X-Git-Url: https://git.libre-soc.org/?p=rv32.git;a=blobdiff_plain;f=cpu_decoder.py;h=c92fb8898daea15443b74c506b45efc328ed603e;hp=9aebc4cf84dca9a50acca4ab3c6bbc4d975bd991;hb=HEAD;hpb=9f4eb932a96e88ed7bf05afc5c487b19169390e4 diff --git a/cpu_decoder.py b/cpu_decoder.py index 9aebc4c..c92fb88 100644 --- a/cpu_decoder.py +++ b/cpu_decoder.py @@ -29,68 +29,12 @@ 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): + """ 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) @@ -103,201 +47,220 @@ class CPUDecoder(Module): self.opcode = Signal(7) self.decode_action = Signal(decode_action) + # decode bits of instruction 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.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) + # add combinatorial decode opcode case statements for immed and action + self.comb += self.calculate_immediate() + self.comb += self.calculate_action() -""" - - 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 -""" + def calculate_immediate(self): + """ calculate immediate + """ + ci = {} + no_imm = Constant(0x0, 32) + + # R-type: no immediate + for op in [OP.amo, OP.op, OP.op_32, OP.op_fp]: + ci[op] = self.immediate.eq(no_imm) + + # I-type: sign-extended bits 20-31 + im = Cat(self.instruction[20:], Replicate(self.instruction[31], 20)) + 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 [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 [OP.branch, ]: + ci[op] = self.immediate.eq(im) + + # U-type + im = Cat(Constant(0, 1), self.instruction[12:], ) + for op in [OP.auipc, OP.lui]: + ci[op] = self.immediate.eq(im) + + # J-type + im = Cat(Constant(0, 1), + self.instruction[21:25], self.instruction[25:31], + self.instruction[20], self.instruction[12:20], + Replicate(self.instruction[31], 12)) + for op in [OP.jal, ]: + ci[op] = self.immediate.eq(im) + + # R4-type: no immediate + for op in [OP.madd, OP.msub, OP.nmsub, OP.nmadd]: + ci[op] = self.immediate.eq(no_imm) + + # unknown + 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 + for op in [ "default", ]: + ci[op] = self.immediate.eq(no_imm) + + return Case(self.opcode, ci) + + def _decode_funct3(self, action, options): + """ decode by list of cases + """ + c = {} + # load opcode + for op in options: + c[op] = self.decode_action.eq(action) + # default + 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(DA.store, [F3.sb, F3.sh, F3.sw, ]) + + def calculate_load_action(self): + """ decode load action + """ + 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(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(DA.jalr, [F3.jalr, ]) + + def calculate_op_action(self): + """ decode op action: the arith ops, and, or, add, xor, sr/sl etc. + """ + c = {} + immz = Constant(0, 12) + regz = Constant(0, 5) + # slli + c[F3.slli] = \ + If((self.funct7 == Constant(0, 7)), + 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(DA.op_op_imm) + ).Else( + self.decode_action.eq(DA.trap_illegal_instruction)) + # default + c["default"] = self.decode_action.eq(DA.op_op_imm) + + return Case(self.funct3, c) + + def calculate_misc_action(self): + """ decode misc mem action: fence and fence_i + """ + c = {} + immz = Constant(0, 12) + regz = Constant(0, 5) + # fence + c[F3.fence] = \ + If((self.immediate[8:12] == immz) & (self.rs1 == regz) & \ + (self.rd == regz), + self.decode_action.eq(DA.fence) + ).Else( + self.decode_action.eq(DA.trap_illegal_instruction)) + # fence.i + c[F3.fence_i] = \ + If((self.immediate[0:12] == immz) & (self.rs1 == regz) & \ + (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(DA.trap_illegal_instruction) + + return Case(self.funct3, c) + + def calculate_system_action(self): + """ decode opcode system: ebreak and csrs + """ + c = {} + 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.funct3, c) + + def calculate_action(self): + """ calculate action based on opcode. + + 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() print(verilog.convert(example, - { + { example.instruction, example.funct7, example.funct3,