add cpu_decoder.py
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 23 Nov 2018 12:21:52 +0000 (12:21 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 23 Nov 2018 12:21:52 +0000 (12:21 +0000)
cpu_decoder.py [new file with mode: 0644]

diff --git a/cpu_decoder.py b/cpu_decoder.py
new file mode 100644 (file)
index 0000000..9aebc4c
--- /dev/null
@@ -0,0 +1,310 @@
+"""
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`timescale 1ns / 100ps
+"""
+from migen import *
+from migen.fhdl import verilog
+
+from riscvdefs import *
+from cpudefs import *
+
+def calculate_immediate(instruction, immediate):
+    """ calculate immediate
+    """
+    ci = {}
+    no_imm = 0x0
+
+    # R-type: no immediate
+    for op in [opcode_amo, opcode_op, opcode_op_32, opcode_op_fp]:
+        ci[op] = immediate.eq(no_imm)
+
+    # I-type
+    im = Cat(instruction[20:], Replicate(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]:
+        ci[op] = immediate.eq(im)
+
+    # S-type
+    im = Cat(instruction[7:12], instruction[25:31],
+             Replicate(instruction[31], 21))
+    for op in [opcode_store, opcode_store_fp]:
+        ci[op] = immediate.eq(im)
+        
+    # B-type
+    im = Cat(Constant(0, 1),
+             instruction[8:12], instruction[25:31],
+             instruction[7], Replicate(instruction[31], 20))
+    for op in [opcode_branch, ]:
+        ci[op] = immediate.eq(im)
+
+    # U-type
+    im = Cat(Constant(0, 1), instruction[12:], )
+    for op in [opcode_auipc, opcode_lui]:
+        ci[op] = immediate.eq(im)
+
+    # J-type
+    im = Cat(Constant(0, 1),
+             instruction[21:25], instruction[25:31],
+             instruction[20], instruction[12:20],
+             Replicate(instruction[31], 12))
+    for op in [opcode_jal, ]:
+        ci[op] = immediate.eq(im)
+
+    # R4-type: no immediate
+    for op in [opcode_madd, opcode_msub, opcode_nmsub, opcode_nmadd]:
+        ci[op] = 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]:
+        ci[op] = immediate.eq(no_imm)
+
+    # default
+    for op in [ "default", ]:
+        ci[op] = immediate.eq(no_imm)
+
+    return ci
+
+
+class CPUDecoder(Module):
+
+    def __init__(self):
+        self.instruction = Signal(32)
+        self.funct7 = Signal(7)
+        self.funct3 = Signal(3)
+        self.rd = Signal(5)
+        self.rs1 = Signal(5)
+        self.rs2 = Signal(5)
+        self.immediate = Signal(32)
+        self.opcode = Signal(7)
+        self.decode_action = Signal(decode_action)
+
+        self.comb += self.funct7.eq(self.instruction[25:32])
+        self.comb += self.funct3.eq(self.instruction[12:15])
+        self.comb += self.rd.eq(self.instruction[7:12])
+        self.comb += self.rs1.eq(self.instruction[15:20])
+        self.comb += self.rs2.eq(self.instruction[20:25])
+        self.comb += self.opcode.eq(self.instruction[0:7])
+
+        # add combinatorial decode opcode case statement
+        ci = calculate_immediate(self.instruction, self.immediate)
+        self.comb += Case(self.opcode, ci)
+
+"""
+        
+        function [31:0] calculate_immediate(input [31:0] instruction, input [6:0] opcode);
+        begin
+            case(opcode)
+
+            `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:
+                // unknown
+                calculate_immediate = 32'hXXXXXXXX;
+            default:
+                calculate_immediate = 32'hXXXXXXXX;
+            endcase
+        end
+        endfunction
+        
+        assign immediate = calculate_immediate(instruction, 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_load: begin
+                case(funct3)
+                `funct3_lb,
+                `funct3_lbu,
+                `funct3_lh,
+                `funct3_lhu,
+                `funct3_lw:
+                    calculate_action = `decode_action_load;
+                default:
+                    calculate_action = `decode_action_trap_illegal_instruction;
+                endcase
+            end
+            `opcode_misc_mem: begin
+                if(funct3 == `funct3_fence) begin
+                    if((immediate[11:8] == 0) & (rs1 == 0) & (rd == 0))
+                        calculate_action = `decode_action_fence;
+                    else
+                        calculate_action = `decode_action_trap_illegal_instruction;
+                end
+                else if(funct3 == `funct3_fence_i) begin
+                    if((immediate[11:0] == 0) & (rs1 == 0) & (rd == 0))
+                        calculate_action = `decode_action_fence_i;
+                    else
+                        calculate_action = `decode_action_trap_illegal_instruction;
+                end
+                else
+                begin
+                    calculate_action = `decode_action_trap_illegal_instruction;
+                end
+            end
+            `opcode_op_imm,
+            `opcode_op: begin
+                if(funct3 == `funct3_slli) begin
+                    if(funct7 == 0)
+                        calculate_action = `decode_action_op_op_imm;
+                    else
+                        calculate_action = `decode_action_trap_illegal_instruction;
+                end
+                else if(funct3 == `funct3_srli_srai) begin
+                    if(funct7 == 0 || funct7 == 7'h20)
+                        calculate_action = `decode_action_op_op_imm;
+                    else
+                        calculate_action = `decode_action_trap_illegal_instruction;
+                end
+                else begin
+                    calculate_action = `decode_action_op_op_imm;
+                end
+            end
+            `opcode_lui,
+            `opcode_auipc: begin
+                calculate_action = `decode_action_lui_auipc;
+            end
+            `opcode_store: begin
+                case(funct3)
+                `funct3_sb,
+                `funct3_sh,
+                `funct3_sw:
+                    calculate_action = `decode_action_store;
+                default:
+                    calculate_action = `decode_action_trap_illegal_instruction;
+                endcase
+            end
+            `opcode_branch: begin
+                case(funct3)
+                `funct3_beq,
+                `funct3_bne,
+                `funct3_blt,
+                `funct3_bge,
+                `funct3_bltu,
+                `funct3_bgeu:
+                    calculate_action = `decode_action_branch;
+                default:
+                    calculate_action = `decode_action_trap_illegal_instruction;
+                endcase
+            end
+            `opcode_jalr: begin
+                if(funct3 == `funct3_jalr)
+                    calculate_action = `decode_action_jalr;
+                else
+                    calculate_action = `decode_action_trap_illegal_instruction;
+            end
+            `opcode_jal: begin
+                calculate_action = `decode_action_jal;
+            end
+            `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
+"""
+
+
+if __name__ == "__main__":
+    example = CPUDecoder()
+    print(verilog.convert(example,
+         { 
+           example.instruction,
+           example.funct7,
+           example.funct3,
+           example.rd,
+           example.rs1,
+           example.rs2,
+           example.immediate,
+           example.opcode,
+           example.decode_action,
+           }))