diff options
-rw-r--r-- | doc/ASAP32-ISA.md | 14 | ||||
-rw-r--r-- | hdl/core.py | 184 |
2 files changed, 150 insertions, 48 deletions
diff --git a/doc/ASAP32-ISA.md b/doc/ASAP32-ISA.md index c6a0d54..111dec9 100644 --- a/doc/ASAP32-ISA.md +++ b/doc/ASAP32-ISA.md @@ -49,19 +49,18 @@ I propose a different name: EX GP-4 FX GP-5 GX GP-6 - FX GP-7 - FLG Processor Flags + HX GP-7 IP Instruction Pointer SP Stack Pointer + FLG Processor Flags CS0 Control status 0 (saves IP) CS1 Control status 1 (saves SP) CS2 Control status 2 (saves FLG) - RS0 RESERVED + PDA Page Directory Address ### FLG Flag Register Bitfield - These registers are Read/Write - They are automaticaly written to by the CPU - Top-half registers are supervisor only + The lower half is read/write + The upper half can be read or written to in supervisor mode only FLG[0] Carry FLG[1] Overflow @@ -150,10 +149,11 @@ I propose a different name: PUSHR RS SP+=1 ;*SP = RS POPR RS RS = *SP ;SP-=1 PUSHI IMM SP+=1 ;*SP = IMM - INVP IMM Invalidate entry in TLB + INVP IMM Invalidate entry in TLB* JMP IMM Jump to address IMM CALL LABEL CS0=IP; IP=LABEL INT IMM CS0=IP; CS1=SP; CS2=FLG; IP=IDT[IMM]* + SCALL Same as call but is used to make calls to the kernel (fixed IDT address) IRET IP=CS0; SP=CS1; FLG=CS2* RET IP = CS0 SIF Set interrupt flag* 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) |