--- /dev/null
+"""
+/*
+ * 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,
+ }))