add Makefile for verilog compilation
[rv32.git] / cpu_decoder.py
index 93dbe634f961d8e4a5395684021e2bf3a22e2df0..c92fb8898daea15443b74c506b45efc328ed603e 100644 (file)
@@ -30,6 +30,11 @@ from riscvdefs import *
 from cpudefs import *
 
 class CPUDecoder(Module):
+    """ decodes a 32-bit instruction into an immediate and other constituent
+        parts, including the opcode and funct3 and funct7, followed by
+        a further (hierarchical) breakdown of the action required to be taken.
+        unidentified actions are decoded as an illegal instruction trap.
+    """
 
     def __init__(self):
         self.instruction = Signal(32)
@@ -58,35 +63,35 @@ class CPUDecoder(Module):
         """ calculate immediate
         """
         ci = {}
-        no_imm = 0x0
+        no_imm = Constant(0x0, 32)
 
         # R-type: no immediate
-        for op in [opcode_amo, opcode_op, opcode_op_32, opcode_op_fp]:
+        for op in [OP.amo, OP.op, OP.op_32, OP.op_fp]:
             ci[op] = self.immediate.eq(no_imm)
 
-        # I-type
+        # I-type: sign-extended bits 20-31
         im = Cat(self.instruction[20:], Replicate(self.instruction[31], 20))
-        for op in [opcode_load, opcode_load_fp, opcode_misc_mem,
-                   opcode_op_imm, opcode_op_imm_32, opcode_jalr,
-                   opcode_system]:
+        for op in [OP.load, OP.load_fp, OP.misc_mem,
+                   OP.op_imm, OP.op_imm_32, OP.jalr,
+                   OP.system]:
             ci[op] = self.immediate.eq(im)
 
         # S-type
         im = Cat(self.instruction[7:12], self.instruction[25:31],
                  Replicate(self.instruction[31], 21))
-        for op in [opcode_store, opcode_store_fp]:
+        for op in [OP.store, OP.store_fp]:
             ci[op] = self.immediate.eq(im)
 
         # B-type
         im = Cat(Constant(0, 1),
                  self.instruction[8:12], self.instruction[25:31],
                  self.instruction[7], Replicate(self.instruction[31], 20))
-        for op in [opcode_branch, ]:
+        for op in [OP.branch, ]:
             ci[op] = self.immediate.eq(im)
 
         # U-type
         im = Cat(Constant(0, 1), self.instruction[12:], )
-        for op in [opcode_auipc, opcode_lui]:
+        for op in [OP.auipc, OP.lui]:
             ci[op] = self.immediate.eq(im)
 
         # J-type
@@ -94,18 +99,18 @@ class CPUDecoder(Module):
                  self.instruction[21:25], self.instruction[25:31],
                  self.instruction[20], self.instruction[12:20],
                  Replicate(self.instruction[31], 12))
-        for op in [opcode_jal, ]:
+        for op in [OP.jal, ]:
             ci[op] = self.immediate.eq(im)
 
         # R4-type: no immediate
-        for op in [opcode_madd, opcode_msub, opcode_nmsub, opcode_nmadd]:
+        for op in [OP.madd, OP.msub, OP.nmsub, OP.nmadd]:
             ci[op] = self.immediate.eq(no_imm)
 
         # unknown
-        for op in [ opcode_custom_0, opcode_48b_escape_0, opcode_custom_1,
-                    opcode_64b_escape, opcode_reserved_10101, opcode_rv128_0,
-                    opcode_48b_escape_1, opcode_reserved_11010,
-                    opcode_reserved_11101, opcode_rv128_1, opcode_80b_escape]:
+        for op in [ OP.custom_0, OP.op_48b_escape_0, OP.custom_1,
+                    OP.op_64b_escape, OP.reserved_10101, OP.rv128_0,
+                    OP.op_48b_escape_1, OP.reserved_11010,
+                    OP.reserved_11101, OP.rv128_1, OP.op_80b_escape]:
             ci[op] = self.immediate.eq(no_imm)
 
         # default
@@ -114,7 +119,7 @@ class CPUDecoder(Module):
 
         return Case(self.opcode, ci)
 
-    def _decode_funct3(self, options, action):
+    def _decode_funct3(self, action, options):
         """ decode by list of cases
         """
         c = {}
@@ -122,176 +127,135 @@ class CPUDecoder(Module):
         for op in options:
             c[op] = self.decode_action.eq(action)
         # default
-        c["default"] = \
-            self.decode_action.eq(decode_action_trap_illegal_instruction)
+        c["default"] = self.decode_action.eq(DA.trap_illegal_instruction)
 
         return Case(self.funct3, c)
 
     def calculate_store_action(self):
         """ decode store action
         """
-        return self._decode_funct3([ funct3_sb, funct3_sh, funct3_sw, ],
-                                    decode_action_store)
+        return self._decode_funct3(DA.store, [F3.sb, F3.sh, F3.sw, ])
 
     def calculate_load_action(self):
         """ decode load action
         """
-        return self._decode_funct3([ funct3_lb, funct3_lbu, funct3_lh,
-                                     funct3_lhu, funct3_lw, ],
-                                    decode_action_load)
+        return self._decode_funct3(DA.load, [F3.lb, F3.lbu, F3.lh,
+                                             F3.lhu, F3.lw, ])
 
     def calculate_branch_action(self):
         """ decode branch action
         """
-        return self._decode_funct3([ funct3_beq, funct3_bne, funct3_blt,
-                                     funct3_bge, funct3_bltu, funct3_bgeu ],
-                                    decode_action_branch)
+        return self._decode_funct3(DA.branch, [F3.beq, F3.bne, F3.blt,
+                                               F3.bge, F3.bltu, F3.bgeu ])
 
     def calculate_jalr_action(self):
         """ decode jalr action
         """
-        return self._decode_funct3([ funct3_jalr, ],
-                                    decode_action_jalr)
+        return self._decode_funct3(DA.jalr, [F3.jalr, ])
 
     def calculate_op_action(self):
-        """ decode op action
+        """ decode op action: the arith ops, and, or, add, xor, sr/sl etc.
         """
         c = {}
         immz = Constant(0, 12)
         regz = Constant(0, 5)
-        # fence
-        c[funct3_slli] = \
+        # slli
+        c[F3.slli] = \
             If((self.funct7 == Constant(0, 7)),
-                self.decode_action.eq(decode_action_op_op_imm)).\
-            Else(
-                self.decode_action.eq(decode_action_trap_illegal_instruction))
-        # fence.i
-        c[funct3_srli_srai] = \
+                self.decode_action.eq(DA.op_op_imm)
+            ).Else(
+                self.decode_action.eq(DA.trap_illegal_instruction))
+        # srli/srai
+        c[F3.srli_srai] = \
             If((self.funct7 == Constant(0, 7) | \
                (self.funct7 == Constant(0x20, 7))),
-                self.decode_action.eq(decode_action_op_op_imm)).\
-            Else(
-                self.decode_action.eq(decode_action_trap_illegal_instruction))
+                self.decode_action.eq(DA.op_op_imm)
+            ).Else(
+                self.decode_action.eq(DA.trap_illegal_instruction))
         # default
-        c["default"] = \
-            self.decode_action.eq(decode_action_op_op_imm)
+        c["default"] = self.decode_action.eq(DA.op_op_imm)
 
         return Case(self.funct3, c)
 
     def calculate_misc_action(self):
-        """ decode misc mem action
+        """ decode misc mem action: fence and fence_i
         """
         c = {}
         immz = Constant(0, 12)
         regz = Constant(0, 5)
         # fence
-        c[funct3_fence] = \
+        c[F3.fence] = \
             If((self.immediate[8:12] == immz) & (self.rs1 == regz) & \
-                                                   (self.rd == regz),
-                self.decode_action.eq(decode_action_fence)).\
-            Else(
-                self.decode_action.eq(decode_action_trap_illegal_instruction))
+                                                (self.rd == regz),
+                self.decode_action.eq(DA.fence)
+            ).Else(
+                self.decode_action.eq(DA.trap_illegal_instruction))
         # fence.i
-        c[funct3_fence_i] = \
+        c[F3.fence_i] = \
             If((self.immediate[0:12] == immz) & (self.rs1 == regz) & \
-                                                    (self.rd == regz),
-                self.decode_action.eq(decode_action_fence_i)).\
-            Else(
-                self.decode_action.eq(decode_action_trap_illegal_instruction))
+                                                (self.rd == regz),
+                self.decode_action.eq(DA.fence_i)
+            ).Else(
+                self.decode_action.eq(DA.trap_illegal_instruction))
         # default
-        c["default"] = \
-            self.decode_action.eq(decode_action_trap_illegal_instruction)
+        c["default"] = self.decode_action.eq(DA.trap_illegal_instruction)
 
         return Case(self.funct3, c)
 
-    def calculate_action(self):
-        """ calculate action
+    def calculate_system_action(self):
+        """ decode opcode system: ebreak and csrs
         """
         c = {}
-        # load opcode
-        c[opcode_load] = self.calculate_load_action()
-        c[opcode_misc_mem] = self.calculate_misc_action()
-        c[opcode_op_imm] = self.calculate_op_action()
-        c[opcode_op] = self.calculate_op_action()
-        c[opcode_lui] = self.decode_action.eq(decode_action_lui_auipc)
-        c[opcode_auipc] = self.decode_action.eq(decode_action_lui_auipc)
-        c[opcode_store] = self.calculate_store_action()
-        c[opcode_branch] = self.calculate_branch_action()
-        c[opcode_jalr] = self.calculate_jalr_action()
-        c[opcode_jal] = self.decode_action.eq(decode_action_jal)
+        b1 = Constant(1, 32)
+        regz = Constant(0, 5)
+        # ebreak
+        c[F3.ecall_ebreak] = \
+            If((self.immediate == ~b1) & (self.rs1 == regz) & \
+                                         (self.rd == regz),
+                self.decode_action.eq(DA.trap_ecall_ebreak)
+            ).Else(
+                self.decode_action.eq(DA.trap_illegal_instruction))
+        # csrs
+        for op in [ F3.csrrw, F3.csrrs, F3.csrrc,
+                    F3.csrrwi, F3.csrrsi, F3.csrrci]:
+            c[op] = self.decode_action.eq(DA.csr)
+        # default
+        c["default"] = self.decode_action.eq(DA.trap_illegal_instruction)
 
-        return Case(self.opcode, c)
+        return Case(self.funct3, c)
 
-"""
+    def calculate_action(self):
+        """ calculate action based on opcode.
 
-        function `decode_action calculate_action(
-            input [6:0] funct7,
-            input [2:0] funct3,
-            input [4:0] rd,
-            input [4:0] rs1,
-            input [4:0] rs2,
-            input [31:0] immediate,
-            input [6:0] opcode);
-        begin
-            case(opcode)
-            `opcode_system: begin
-                case(funct3)
-                `funct3_ecall_ebreak:
-                    if((rs1 != 0) | (rd != 0) | ((immediate & ~32'b1) != 0))
-                        calculate_action = `decode_action_trap_illegal_instruction;
-                    else
-                        calculate_action = `decode_action_trap_ecall_ebreak;
-                `funct3_csrrw,
-                `funct3_csrrs,
-                `funct3_csrrc,
-                `funct3_csrrwi,
-                `funct3_csrrsi,
-                `funct3_csrrci:
-                    calculate_action = `decode_action_csr;
-                default:
-                    calculate_action = `decode_action_trap_illegal_instruction;
-                endcase
-            end
-            `opcode_load_fp,
-            `opcode_custom_0,
-            `opcode_op_imm_32,
-            `opcode_48b_escape_0,
-            `opcode_store_fp,
-            `opcode_custom_1,
-            `opcode_amo,
-            `opcode_op_32,
-            `opcode_64b_escape,
-            `opcode_madd,
-            `opcode_msub,
-            `opcode_nmsub,
-            `opcode_nmadd,
-            `opcode_op_fp,
-            `opcode_reserved_10101,
-            `opcode_rv128_0,
-            `opcode_48b_escape_1,
-            `opcode_reserved_11010,
-            `opcode_reserved_11101,
-            `opcode_rv128_1,
-            `opcode_80b_escape: begin
-                calculate_action = `decode_action_trap_illegal_instruction;
-            end
-            default:
-                calculate_action = `decode_action_trap_illegal_instruction;
-            endcase
-        end
-        endfunction
-
-        assign decode_action = calculate_action(funct7,
-                                                funct3,
-                                                rd,
-                                                rs1,
-                                                rs2,
-                                                immediate,
-                                                opcode);
-
-    endmodule
-"""
+            this is a first level case statement that calls down to 2nd
+            level case (and in some cases if logic) mostly using funct3
+            (funct7 in the case of arith ops).
+        """
+        c = {}
+        c[OP.load    ] = self.calculate_load_action()
+        c[OP.misc_mem] = self.calculate_misc_action()
+        c[OP.op_imm  ] = self.calculate_op_action()
+        c[OP.op      ] = self.calculate_op_action()
+        c[OP.lui     ] = self.decode_action.eq(DA.lui_auipc)
+        c[OP.auipc   ] = self.decode_action.eq(DA.lui_auipc)
+        c[OP.store   ] = self.calculate_store_action()
+        c[OP.branch  ] = self.calculate_branch_action()
+        c[OP.jalr    ] = self.calculate_jalr_action()
+        c[OP.jal     ] = self.decode_action.eq(DA.jal)
+        c[OP.system  ] = self.calculate_system_action()
+
+        # big batch of unrecognised opcodes: throw trap.
+        for o in [ OP.load_fp, OP.custom_0, OP.op_imm_32,
+                    OP.op_48b_escape_0, OP.store_fp, OP.custom_1,
+                    OP.amo, OP.op_32, OP.op_64b_escape,
+                    OP.madd, OP.msub, OP.nmsub,
+                    OP.nmadd, OP.op_fp, OP.reserved_10101,
+                    OP.rv128_0, OP.op_48b_escape_1, OP.reserved_11010,
+                    OP.reserved_11101, OP.rv128_1, OP.op_80b_escape,
+                    "default", ]:
+            c[o] = self.decode_action.eq(DA.trap_illegal_instruction)
 
+        return Case(self.opcode, c)
 
 if __name__ == "__main__":
     example = CPUDecoder()