add handle_trap
[rv32.git] / cpu.py
diff --git a/cpu.py b/cpu.py
index 4fbeafe61938fff05d0a6994e6240b4dd9705966..e0a6881c9248769e328e73ed1498ec4cf0bd49e3 100644 (file)
--- a/cpu.py
+++ b/cpu.py
@@ -80,7 +80,7 @@ class MStatus:
         self.uie = Signal(name="mstatus_uie")
 
         for n in dir(self):
-            if n in ['mpp', 'comb', 'sync'] or n.startswith("_"):
+            if n in ['make', 'mpp', 'comb', 'sync'] or n.startswith("_"):
                 continue
             self.comb += getattr(self, n).eq(0x0)
         self.comb += self.mpp.eq(0b11)
@@ -88,6 +88,18 @@ class MStatus:
         self.sync += self.mie.eq(0)
         self.sync += self.mpie.eq(0)
 
+    def make(self):
+        return Cat(
+                self.uie, self.sie, Constant(0), self.mie,
+                self.upie, self.spie, Constant(0), self.mpie,
+                self.spp, Constant(0, 2), self.mpp,
+                self.fs, self.xs, self.mprv, self._sum,
+                self.mxr, self.tvm, self.tw, self.tsr,
+                Constant(0, 8),
+                (self.xs == Constant(0b11, 2)) | (self.fs == Constant(0b11, 2))
+                )
+
+
 class MIE:
     def __init__(self, comb, sync):
         self.comb = comb
@@ -102,7 +114,7 @@ class MIE:
         self.usie = Signal(name="mie_usie")
 
         for n in dir(self):
-            if n in ['comb', 'sync'] or n.startswith("_"):
+            if n in ['make', 'comb', 'sync'] or n.startswith("_"):
                 continue
             self.comb += getattr(self, n).eq(0x0)
 
@@ -110,6 +122,25 @@ class MIE:
         self.sync += self.mtie.eq(0)
         self.sync += self.msie.eq(0)
 
+class MIP:
+    def __init__(self, comb, sync):
+        self.comb = comb
+        self.sync = sync
+        self.meip = Signal(name="mip_meip") # TODO: implement ext interrupts
+        self.seip = Signal(name="mip_seip")
+        self.ueip = Signal(name="mip_uiep")
+        self.mtip = Signal(name="mip_mtip") # TODO: implement timer interrupts
+        self.stip = Signal(name="mip_stip")
+        self.msip = Signal(name="mip_stip")
+        self.utip = Signal(name="mip_utip")
+        self.ssip = Signal(name="mip_ssip")
+        self.usip = Signal(name="mip_usip")
+
+        for n in dir(self):
+            if n in ['comb', 'sync'] or n.startswith("_"):
+                continue
+            self.comb += getattr(self, n).eq(0x0)
+
 
 class M:
     def __init__(self, comb, sync):
@@ -122,8 +153,8 @@ class M:
         self.sync += self.mepc.eq(0) # 32'hXXXXXXXX;
         self.sync += self.mscratch.eq(0) # 32'hXXXXXXXX;
 
-class Misa:
 
+class Misa:
     def __init__(self, comb, sync):
         self.comb = comb
         self.sync = sync
@@ -137,11 +168,87 @@ class Misa:
         self.comb += self.misa.eq(Cat(cl))
 
 
+class Fetch:
+    def __init__(self, comb, sync):
+        self.comb = comb
+        self.sync = sync
+        self.action = Signal(fetch_action, name="fetch_action")
+        self.target_pc = Signal(32, name="fetch_target_pc")
+        self.output_pc = Signal(32, name="fetch_output_pc")
+        self.output_instruction = Signal(32, name="fetch_ouutput_instruction")
+        self.output_state = Signal(fetch_output_state,name="fetch_output_state")
+
+    def get_fetch_action(self, dc, load_store_misaligned, mi,
+                         branch_taken, misaligned_jump_target,
+                         csr_op_is_valid):
+        c = {}
+        c["default"] = self.action.eq(FA.default) # XXX should be 32'XXXXXXXX?
+        c[FOS.empty] = self.action.eq(FA.default)
+        c[FOS.trap] = self.action.eq(FA.ack_trap)
+
+        # illegal instruction -> error trap
+        i= If((dc.act & DA.trap_illegal_instruction) != 0,
+                 self.action.eq(FA.error_trap)
+              )
+
+        # ecall / ebreak -> noerror trap
+        i = i.Elif((dc.act & DA.trap_ecall_ebreak) != 0,
+                 self.action.eq(FA.noerror_trap))
+
+        # load/store: check alignment, check wait
+        i = i.Elif((dc.act & (DA.load | DA.store)) != 0,
+                If((load_store_misaligned | ~mi.rw_address_valid),
+                    self.action.eq(FA.error_trap) # misaligned or invalid addr
+                ).Elif(mi.rw_wait,
+                    self.action.eq(FA.wait) # wait
+                ).Else(
+                    self.action.eq(FA.default) # ok
+                )
+              )
+
+        # fence
+        i = i.Elif((dc.act & DA.fence) != 0,
+                 self.action.eq(FA.fence))
+
+        # branch -> misaligned=error, otherwise jump
+        i = i.Elif((dc.act & DA.branch) != 0,
+                If(misaligned_jump_target,
+                    self.action.eq(FA.error_trap)
+                ).Else(
+                    self.action.eq(FA.jump)
+                )
+              )
+
+        # jal/jalr -> misaligned=error, otherwise jump
+        i = i.Elif((dc.act & (DA.jal | DA.jalr)) != 0,
+                If(misaligned_jump_target,
+                    self.action.eq(FA.error_trap)
+                ).Else(
+                    self.action.eq(FA.jump)
+                )
+              )
+
+        # csr -> opvalid=ok, else error trap
+        i = i.Elif((dc.act & DA.csr) != 0,
+                If(csr_op_is_valid,
+                    self.action.eq(FA.default)
+                ).Else(
+                    self.action.eq(FA.error_trap)
+                )
+              )
+
+        c[FOS.valid] = i
+
+        return Case(self.output_state, c)
+
+
 class CPU(Module):
     """
     """
 
     def get_ls_misaligned(self, ls, funct3, load_store_address_low_2):
+        """ returns whether a load/store is misaligned
+        """
         return Case(funct3[:2],
                 { F3.sb: ls.eq(Constant(0)),
                   F3.sh: ls.eq(load_store_address_low_2[0] != 0),
@@ -173,6 +280,91 @@ class CPU(Module):
         for f in [F3.csrrc, F3.csrrci]: c[f] = ~written_value & previous_value
         return Case(funct3, c)
 
+    def handle_trap(self, m, ms, ft, dc, load_store_misaligned):
+        s = [ms.mpie.eq(ms.mie),
+             ms.mie.eq(0),
+             m.mepc.eq(Mux(ft.action == FA.noerror_trap,
+                           ft.output_pc + 4,
+                           ft.output_pc))]
+
+        # fetch action ack trap
+        i = If(ft.action == FA.ack_trap,
+                m.mcause.eq(cause_instruction_access_fault)
+              )
+
+        # ecall/ebreak
+        i = i.Elif((dc.act & DA.trap_ecall_ebreak) != 0,
+                m.mcause.eq(Mux(dc.immediate[0],
+                                cause_machine_environment_call,
+                                cause_breakpoint))
+              )
+
+        # load
+        i = i.Elif((dc.act & DA.load) != 0,
+                If(load_store_misaligned,
+                    m.mcause.eq(cause_load_address_misaligned)
+                ).Else(
+                    m.mcause.eq(cause_load_access_fault)
+                )
+              )
+
+        # store
+        i = i.Elif((dc.act & DA.store) != 0,
+                If(load_store_misaligned,
+                    m.mcause.eq(cause_store_amo_address_misaligned)
+                ).Else(
+                    m.mcause.eq(cause_store_amo_access_fault)
+                )
+              )
+
+        # jal/jalr -> misaligned=error, otherwise jump
+        i = i.Elif((dc.act & (DA.jal | DA.jalr | DA.branch)) != 0,
+                m.mcause.eq(cause_instruction_address_misaligned)
+              )
+
+        # defaults to illegal instruction
+        i = i.Else(m.mcause.eq(cause_illegal_instruction))
+
+        s.append(i)
+        return s
+
+    """
+    task handle_trap;
+    begin
+        mstatus_mpie = mstatus_mie;
+        mstatus_mie = 0;
+        mepc = (fetch_action == `fetch_action_noerror_trap) ? fetch_output_pc + 4 : fetch_output_pc;
+        if(fetch_action == `fetch_action_ack_trap) begin
+            mcause = `cause_instruction_access_fault;
+        end
+        else if((decode_action & `decode_action_trap_illegal_instruction) != 0) begin
+            mcause = `cause_illegal_instruction;
+        end
+        else if((decode_action & `decode_action_trap_ecall_ebreak) != 0) begin
+            mcause = decoder_immediate[0] ? `cause_machine_environment_call : `cause_breakpoint;
+        end
+        else if((decode_action & `decode_action_load) != 0) begin
+            if(load_store_misaligned)
+                mcause = `cause_load_address_misaligned;
+            else
+                mcause = `cause_load_access_fault;
+        end
+        else if((decode_action & `decode_action_store) != 0) begin
+            if(load_store_misaligned)
+                mcause = `cause_store_amo_address_misaligned;
+            else
+                mcause = `cause_store_amo_access_fault;
+        end
+        else if((decode_action & (`decode_action_branch | `decode_action_jal | `decode_action_jalr)) != 0) begin
+            mcause = `cause_instruction_address_misaligned;
+        end
+        else begin
+            mcause = `cause_illegal_instruction;
+        end
+    end
+    endtask
+    """
+
     def __init__(self):
         self.clk = ClockSignal()
         self.reset = ResetSignal()
@@ -227,11 +419,7 @@ class CPU(Module):
                   )
         self.specials += mii
 
-        fetch_act = Signal(fetch_action)
-        fetch_target_pc = Signal(32)
-        fetch_output_pc = Signal(32)
-        fetch_output_instruction = Signal(32)
-        fetch_output_st = Signal(fetch_output_state)
+        ft = Fetch(self.comb, self.sync)
 
         fs = Instance("CPUFetchStage", name="fetch_stage",
             i_clk=ClockSignal(),
@@ -239,11 +427,11 @@ class CPU(Module):
             o_memory_interface_fetch_address = mi.fetch_address,
             i_memory_interface_fetch_data = mi.fetch_data,
             i_memory_interface_fetch_valid = mi.fetch_valid,
-            i_fetch_action = fetch_act,
-            i_target_pc = fetch_target_pc,
-            o_output_pc = fetch_output_pc,
-            o_output_instruction = fetch_output_instruction,
-            o_output_state = fetch_output_st,
+            i_fetch_action = ft.action,
+            i_target_pc = ft.target_pc,
+            o_output_pc = ft.output_pc,
+            o_output_instruction = ft.output_instruction,
+            o_output_state = ft.output_state,
             i_reset_vector = reset_vector,
             i_mtvec = mtvec,
         )
@@ -252,7 +440,7 @@ class CPU(Module):
         dc = Decoder()
 
         cd = Instance("CPUDecoder", name="decoder",
-            i_instruction = fetch_output_instruction,
+            i_instruction = ft.output_instruction,
             o_funct7 = dc.funct7,
             o_funct3 = dc.funct3,
             o_rd = dc.rd,
@@ -346,7 +534,7 @@ class CPU(Module):
         self.comb += loaded_value.eq(Cat(b0, b1, b2))
 
         self.comb += mi.rw_active.eq(~self.reset
-                        & (fetch_output_st == fetch_output_state_valid)
+                        & (ft.output_state == FOS.valid)
                         & ~load_store_misaligned
                         & ((dc.act & (DA.load | DA.store)) != 0))
 
@@ -375,15 +563,15 @@ class CPU(Module):
         lui_auipc_result = Signal(32)
         self.comb += lui_auipc_result.eq(Mux(dc.opcode[5],
                                              dc.immediate,
-                                             dc.immediate + fetch_output_pc))
+                                             dc.immediate + ft.output_pc))
 
-        self.comb += fetch_target_pc.eq(Cat(0,
+        self.comb += ft.target_pc.eq(Cat(0,
                     Mux(dc.opcode != OP.jalr,
-                                fetch_output_pc[1:32],
+                                ft.output_pc[1:32],
                                 register_rs1[1:32] + dc.immediate[1:32])))
 
         misaligned_jump_target = Signal()
-        self.comb += misaligned_jump_target.eq(fetch_target_pc[1])
+        self.comb += misaligned_jump_target.eq(ft.target_pc[1])
 
         branch_arg_a = Signal(32)
         branch_arg_b = Signal(32)
@@ -404,8 +592,24 @@ class CPU(Module):
 
         misa = Misa(self.comb, self.sync)
 
-        #self.sync += If(self.reset, self.reset_to_initial(m, mstatus, mie,
-        #                                                  registers))
+        mvendorid = Signal(32)
+        marchid = Signal(32)
+        mimpid = Signal(32)
+        mhartid = Signal(32)
+        self.comb += mvendorid.eq(Constant(0, 32))
+        self.comb += marchid.eq(Constant(0, 32))
+        self.comb += mimpid.eq(Constant(0, 32))
+        self.comb += mhartid.eq(Constant(0, 32))
+
+        mip = MIP(self.comb, self.sync)
+
+        csr_op_is_valid = Signal()
+
+        self.comb += ft.get_fetch_action(dc, load_store_misaligned, mi,
+                                 branch_taken, misaligned_jump_target,
+                                 csr_op_is_valid)
+
+        #self.comb += self.handle_trap(m, mstatus, ft, dc, load_store_misaligned)
 
 if __name__ == "__main__":
     example = CPU()
@@ -422,185 +626,6 @@ if __name__ == "__main__":
 
 """
 
-    parameter mvendorid = 32'b0;
-    parameter marchid = 32'b0;
-    parameter mimpid = 32'b0;
-    parameter mhartid = 32'b0;
-
-    function [31:0] make_mstatus(input mstatus_tsr,
-        input mstatus_tw,
-        input mstatus_tvm,
-        input mstatus_mxr,
-        input mstatus_sum,
-        input mstatus_mprv,
-        input [1:0] mstatus_xs,
-        input [1:0] mstatus_fs,
-        input [1:0] mstatus_mpp,
-        input mstatus_spp,
-        input mstatus_mpie,
-        input mstatus_spie,
-        input mstatus_upie,
-        input mstatus_mie,
-        input mstatus_sie,
-        input mstatus_uie);
-    begin
-        make_mstatus = {(mstatus_xs == 2'b11) | (mstatus_fs == 2'b11),
-            8'b0,
-            mstatus_tsr,
-            mstatus_tw,
-            mstatus_tvm,
-            mstatus_mxr,
-            mstatus_sum,
-            mstatus_mprv,
-            mstatus_xs,
-            mstatus_fs,
-            mstatus_mpp,
-            2'b0,
-            mstatus_spp,
-            mstatus_mpie,
-            1'b0,
-            mstatus_spie,
-            mstatus_upie,
-            mstatus_mie,
-            1'b0,
-            mstatus_sie,
-            mstatus_uie};
-    end
-    endfunction
-
-    wire mip_meip = 0; // TODO: implement external interrupts
-    parameter mip_seip = 0;
-    parameter mip_ueip = 0;
-    wire mip_mtip = 0; // TODO: implement timer interrupts
-    parameter mip_stip = 0;
-    parameter mip_utip = 0;
-    parameter mip_msip = 0;
-    parameter mip_ssip = 0;
-    parameter mip_usip = 0;
-
-    wire csr_op_is_valid;
-
-    function `fetch_action get_fetch_action(
-        input `fetch_output_state fetch_output_state,
-        input `decode_action decode_action,
-        input load_store_misaligned,
-        input memory_interface_rw_address_valid,
-        input memory_interface_rw_wait,
-        input branch_taken,
-        input misaligned_jump_target,
-        input csr_op_is_valid
-        );
-    begin
-        case(fetch_output_state)
-        `fetch_output_state_empty:
-            get_fetch_action = `fetch_action_default;
-        `fetch_output_state_trap:
-            get_fetch_action = `fetch_action_ack_trap;
-        `fetch_output_state_valid: begin
-            if((decode_action & `decode_action_trap_illegal_instruction) != 0) begin
-                get_fetch_action = `fetch_action_error_trap;
-            end
-            else if((decode_action & `decode_action_trap_ecall_ebreak) != 0) begin
-                get_fetch_action = `fetch_action_noerror_trap;
-            end
-            else if((decode_action & (`decode_action_load | `decode_action_store)) != 0) begin
-                if(load_store_misaligned | ~memory_interface_rw_address_valid) begin
-                    get_fetch_action = `fetch_action_error_trap;
-                end
-                else if(memory_interface_rw_wait) begin
-                    get_fetch_action = `fetch_action_wait;
-                end
-                else begin
-                    get_fetch_action = `fetch_action_default;
-                end
-            end
-            else if((decode_action & `decode_action_fence_i) != 0) begin
-                get_fetch_action = `fetch_action_fence;
-            end
-            else if((decode_action & `decode_action_branch) != 0) begin
-                if(branch_taken) begin
-                    if(misaligned_jump_target) begin
-                        get_fetch_action = `fetch_action_error_trap;
-                    end
-                    else begin
-                        get_fetch_action = `fetch_action_jump;
-                    end
-                end
-                else
-                begin
-                    get_fetch_action = `fetch_action_default;
-                end
-            end
-            else if((decode_action & (`decode_action_jal | `decode_action_jalr)) != 0) begin
-                if(misaligned_jump_target) begin
-                    get_fetch_action = `fetch_action_error_trap;
-                end
-                else begin
-                    get_fetch_action = `fetch_action_jump;
-                end
-            end
-            else if((decode_action & `decode_action_csr) != 0) begin
-                if(csr_op_is_valid)
-                    get_fetch_action = `fetch_action_default;
-                else
-                    get_fetch_action = `fetch_action_error_trap;
-            end
-            else begin
-                get_fetch_action = `fetch_action_default;
-            end
-        end
-        default:
-            get_fetch_action = 32'hXXXXXXXX;
-        endcase
-    end
-    endfunction
-
-    assign fetch_action = get_fetch_action(
-        fetch_output_state,
-        decode_action,
-        load_store_misaligned,
-        memory_interface_rw_address_valid,
-        memory_interface_rw_wait,
-        branch_taken,
-        misaligned_jump_target,
-        csr_op_is_valid
-        );
-
-    task handle_trap;
-    begin
-        mstatus_mpie = mstatus_mie;
-        mstatus_mie = 0;
-        mepc = (fetch_action == `fetch_action_noerror_trap) ? fetch_output_pc + 4 : fetch_output_pc;
-        if(fetch_action == `fetch_action_ack_trap) begin
-            mcause = `cause_instruction_access_fault;
-        end
-        else if((decode_action & `decode_action_trap_illegal_instruction) != 0) begin
-            mcause = `cause_illegal_instruction;
-        end
-        else if((decode_action & `decode_action_trap_ecall_ebreak) != 0) begin
-            mcause = decoder_immediate[0] ? `cause_machine_environment_call : `cause_breakpoint;
-        end
-        else if((decode_action & `decode_action_load) != 0) begin
-            if(load_store_misaligned)
-                mcause = `cause_load_address_misaligned;
-            else
-                mcause = `cause_load_access_fault;
-        end
-        else if((decode_action & `decode_action_store) != 0) begin
-            if(load_store_misaligned)
-                mcause = `cause_store_amo_address_misaligned;
-            else
-                mcause = `cause_store_amo_access_fault;
-        end
-        else if((decode_action & (`decode_action_branch | `decode_action_jal | `decode_action_jalr)) != 0) begin
-            mcause = `cause_instruction_address_misaligned;
-        end
-        else begin
-            mcause = `cause_illegal_instruction;
-        end
-    end
-    endtask
-
     wire [11:0] csr_number = decoder_immediate;
     wire [31:0] csr_input_value = decoder_funct3[2] ? decoder_rs1 : register_rs1;
     wire csr_reads = decoder_funct3[1] | (decoder_rd != 0);