diff options
Diffstat (limited to 'hdl')
-rw-r--r-- | hdl/core.py | 184 |
1 files changed, 143 insertions, 41 deletions
diff --git a/hdl/core.py b/hdl/core.py index 655af68..c1e38cc 100644 --- a/hdl/core.py +++ b/hdl/core.py @@ -1,4 +1,6 @@ +from curses.ascii import SI from multiprocessing import dummy +from tkinter import S from amaranth import * from amaranth.sim import Simulator, Settle, Delay from enum import Enum, unique @@ -6,49 +8,145 @@ from enum import Enum, unique from utils import cmd -# class Reg(Elaboratable): -# def __init__(self): -# self.rd_addr = Signal(4) -# self.rs1_addr = Signal(4) -# self.rs2_addr = Signal(4) - -# self.rd = Signal(32) -# self.rs1 = Signal(32) -# self.rs2 = Signal(32) - -# self.zx = Signal(32) -# self.ax = Signal(32) -# self.bx = Signal(32) -# self.bx = Signal(32) -# self.cx = Signal(32) -# self.dx = Signal(32) -# self.ex = Signal(32) -# self.fx = Signal(32) -# self.gx = Signal(32) -# self.hx = Signal(32) -# self.hi = Signal(32) -# self.lo = Signal(32) -# self.fg = Signal(32) -# self.cr = Signal(32) -# self.ip = Signal(32) -# self.sp = Signal(32) -# self.ja = Signal(32) - -# self.reg_ar = Array([self.zx, self.ax, self.bx, self.cx, self.dx, self.ex, self.fx, self.gx, self.hx, self.hi, self.lo, self.fg, self.cr, self.ip, self.sp, self.ja]) - -# # TODO: add support for storing multiplication result -# self.ports = [self.rd_addr, self.rs1_addr, self.rs2_addr, self.rd, self.rs1, self.rs2, self.ip] +class Reg(Elaboratable): + def __init__(self): + # enable write + self.wr_en = Signal(1) -# def elaborate(self, platform=None): -# m = Module() + # input and output addresses + self.rd_addr = Signal(4) + self.rs1_addr = Signal(4) + self.rs2_addr = Signal(4) -# with m.If(self.rd_addr != 0): -# m.d.sync += self.reg_ar[self.rd_addr].eq(self.rd) + # input and output signals + self.rd = Signal(32) + self.rs1 = Signal(32) + self.rs2 = Signal(32) -# m.d.comb += self.rs1.eq(self.reg_ar[self.rs1_addr]) -# m.d.comb += self.rs2.eq(self.reg_ar[self.rs2_addr]) + # alu status signals + self.alu_flgs = Signal(5) -# return m + self.stack_instr = Signal(1) + self.stack_down_up = Signal(1) + + ################################################################## + + # activated when interupt is triggered + self.interupt = Signal(1) + # return from interrupt special + self.iret = Signal(1) + # jump signal to jump and link (swap ip and cs0) + self.jump = Signal(1) + + ################################################################# + # None of the 3 signals above should ever be set at the same time + ################################################################# + + + # internal signals + self._user_mode = Signal(1) + self._interupt = Signal(1) + self._sp_write = Signal(1) + + self.zx = Signal(32) #0 + self.ax = Signal(32) #1 + self.bx = Signal(32) #2 + self.bx = Signal(32) #3 + self.cx = Signal(32) #4 + self.dx = Signal(32) #5 + self.ex = Signal(32) #6 + self.fx = Signal(32) #7 + self.gx = Signal(32) #8 + self.hx = Signal(32) #9 + self.ip = Signal(32) #10 + self.sp = Signal(32) #11 + self.flg = Signal(32) #12 + self.cs0 = Signal(32) #13 + self.cs1 = Signal(32) #14 + self.cs2 = Signal(32) #15 + self.pda = Signal(32) #16 + + # for sake of modularity, make bit locations easily configurable + setattr(self.flg, 'c', self.flg[0]) + setattr(self.flg, 'ov', self.flg[1]) + setattr(self.flg, 'z', self.flg[2]) + setattr(self.flg, 'n', self.flg[3]) + setattr(self.flg, 'od', self.flg[4]) + setattr(self.flg, 'int', self.flg[16]) + setattr(self.flg, 'user_mode', self.flg[17]) + setattr(self.flg, 'page_en', self.flg[18]) + + + reg_list = [self.zx, self.ax, self.bx, self.cx, self.dx, self.ex, self.fx, self.gx, self.hx, self.ip, self.sp, self.flg, self.cs0, self.cs1, self.cs2, self.pda] + for idx, reg in enumerate(reg_list): + setattr(reg, 'idx', idx) # set idx attribute to each register + + self.reg_arr = Array(reg_list) + self.ports = [self.wr_en, self.alu_flgs, self.jump, self.interupt, self.iret, self.stack_instr, self.stack_down_up, self.rd_addr, self.rs1_addr, self.rs2_addr, self.rd, self.rs1, self.rs2, self.ip] + + def elaborate(self, platform=None): + m = Module() + + # user mode override + m.d.comb += self._interupt.eq(self.flg.int & self.interupt) # if the sw guy don't want to be interupted, don't + m.d.comb += self._user_mode.eq(self.flg.user_mode & ~self._interupt) + + # toggle ip and cs0 + with m.If(self.jump | self._interupt | self.iret): + m.d.sync += self.cs0.eq(self.ip) + m.d.sync += self.ip.eq(self.cs0) + with m.Else(): + m.d.sync += self.ip.eq(self.ip + 1) # increment ip only on normal operation + + with m.If(self._interupt): + m.d.sync += self.cs1.eq(self.sp) + m.d.sync += self.cs2.eq(self.flg) + m.d.sync += self.flg.user_mode.eq(0) # set to system mode or iret cannot be used + m.d.sync += self.flg.int.eq(0) # clear int flag, essential because another interrupt can be triggered without this + with m.Elif(self.iret): + m.d.sync += self.sp.eq(self.cs1) + m.d.sync += self.flg.eq(self.cs2) + + m.d.comb += self._sp_write.eq(0) + + # writeback setup + with m.If(self.wr_en): + with m.Switch(self.rd_addr): + with m.Case(self.zx.idx): # do not write to zero register + pass + with m.Case(self.ip.idx): #do not directly write to ip register + pass + with m.Case(self.flg.idx): + # mask top half of register to prevent writing to flags in user mode + m.d.sync += self.flg.eq(self.rd & Cat(Const(0xFFFF, 16), Repl(~self._user_mode, 16))) + with m.Case(self.sp.idx): + m.d.comb += self._sp_write.eq(1) + m.d.sync += self.sp.eq(self.rd) + with m.Case(): + m.d.sync += self.flg.eq(Cat(self.alu_flgs, self.flg[len(self.alu_flgs):])) # update flags if register is not being written to + m.d.sync += self.reg_arr[self.rd_addr].eq(self.rd) + + with m.If(~self._sp_write & self.stack_instr): + with m.If(self.stack_down_up): + m.d.sync += self.sp.eq(self.sp - 1) + with m.Else(): + m.d.sync += self.sp.eq(self.sp + 1) + + + ### Combination signal outputs ### + with m.Switch(self.rs1_addr): + with m.Case(self.flg.idx): + m.d.comb += self.rs1.eq(self.flg & Cat(Const(0xFFFF, 16), Repl(~self._user_mode, 16))) + with m.Case(): + m.d.comb += self.rs1.eq(self.reg_arr[self.rs1_addr]) + + with m.Switch(self.rs2_addr): + with m.Case(self.flg.idx): + m.d.comb += self.rs2.eq(self.flg & Cat(Const(0xFFFF, 16), Repl(~self._user_mode, 16))) + with m.Case(): + m.d.comb += self.rs2.eq(self.reg_arr[self.rs2_addr]) + + return m # class ASAP32Core(Elaboratable): @@ -323,6 +421,10 @@ def test_alu(filename="alu.vcd"): sim.run() + if __name__ == '__main__': - hdl = ALU() - cmd(hdl, test_alu) + reg = Reg() + cmd(reg, None) + + # hdl = ALU() + # cmd(hdl, test_alu) |