diff --git a/controller.sv b/controller.sv index 7568baf8..9fbead46 100644 --- a/controller.sv +++ b/controller.sv @@ -24,6 +24,7 @@ // comments // // Revision v0.3 - (December 1th 2014) Merged debug unit // // Revision v0.4 - (January 6th 2015) Added vectorial instructions // +// Revision v0.5 - (Sept 15th 2015) Separated controller and decoder // // // // // // // @@ -38,76 +39,56 @@ module controller input logic fetch_enable_i, // Start the decoding output logic core_busy_o, // Core is busy processing instructions - output logic is_decoding_o, + output logic is_decoding_o, // Core is in decoding state + // decoder related signals + output logic deassert_we_o, // deassert write enable for next instruction + input logic illegal_insn_i, // decoder encountered an invalid instruction + input logic trap_insn_i, // decoder encountered a trap instruction + input logic eret_insn_i, // decoder encountered an eret instruction + input logic pipe_flush_i, // decoder wants to do a pipe flush + + input logic rega_used_i, // register A is used + input logic regb_used_i, // register B is used + input logic regc_used_i, // register C is used + + // from IF/ID pipeline input logic [31:0] instr_rdata_i, // Instruction read from instr memory/cache: (sampled in the if stage) - output logic instr_req_o, // Fetch instruction Request: - input logic instr_gnt_i, // grant from icache + + // from prefetcher + output logic instr_req_o, // Start fetching instructions input logic instr_ack_i, // Acknow from instr memory or cache (means that data is available) - output logic [2:0] pc_mux_sel_o, // Selector in the Fetch stage to select the rigth PC (normal, jump ...) + // to prefetcher output logic pc_set_o, // jump to address set by pc_mux_sel + output logic [2:0] pc_mux_sel_o, // Selector in the Fetch stage to select the rigth PC (normal, jump ...) - // ALU signals - output logic [`ALU_OP_WIDTH-1:0] alu_operator_o, // Operator in the Ex stage for the ALU block - output logic [1:0] alu_op_a_mux_sel_o, // Operator a is selected between reg value, PC or immediate - output logic [1:0] alu_op_b_mux_sel_o, // Operator b is selected between reg value or immediate - output logic alu_op_c_mux_sel_o, // Operator c is selected between reg value or PC - output logic [2:0] immediate_mux_sel_o, - - output logic [1:0] vector_mode_o, // selects between 32 bit, 16 bit and 8 bit vectorial modes - output logic scalar_replication_o, // activates scalar_replication for vectorial mode - output logic [1:0] alu_cmp_mode_o, // selects comparison mode for ALU (i.e. full, any, all) - - // Mupliplicator related control signals - output logic mult_en_o, // Multiplication operation is running - output logic [1:0] mult_sel_subword_o, // Select subwords for 16x16 bit of multiplier - output logic [1:0] mult_signed_mode_o, // Multiplication in signed mode - output logic mult_mac_en_o, // Use the accumulator after multiplication - - output logic regfile_we_o, // Write Enable to regfile - output logic regfile_alu_waddr_mux_sel_o, // Select register write address for ALU/MUL operations - - output logic regfile_alu_we_o, // Write Enable to regfile 2nd port - - output logic prepost_useincr_o, // When not active bypass the alu result=op_a + // LSU + input logic data_req_ex_i, // data memory access is currently performed in EX stage input logic data_misaligned_i, - // CSR manipulation - output logic csr_access_o, - output logic [1:0] csr_op_o, - - // LD/ST unit signals - output logic data_we_o, // Write enable to data memory - output logic [1:0] data_type_o, // Data type on data memory: byte, half word or word - output logic data_sign_extension_o, // Sign extension on read data from data memory - output logic [1:0] data_reg_offset_o, // Offset in bytes inside register for stores - output logic data_req_o, // Request for a transaction to data memory - input logic data_req_ex_i, // Delayed copy of the data_req_o - input logic lsu_ready_ex_i, input logic lsu_ready_wb_i, // hwloop signals - output logic [2:0] hwloop_we_o, // write enable for hwloop regs - output logic hwloop_start_mux_sel_o, // selects hwloop start address input - output logic hwloop_end_mux_sel_o, // selects hwloop end address input - output logic hwloop_cnt_mux_sel_o, // selects hwloop counter input - input logic hwloop_jump_i, // modify pc_mux_sel to select the hwloop addr + // jump/branch signals + input logic [1:0] jump_in_ex_i, // jump is being calculated in ALU + input logic [1:0] jump_in_id_i, // jump is being calculated in ALU + input logic [1:0] jump_in_dec_i, // jump is being calculated in ALU + + input logic branch_decision_i, // branch decision is available in EX stage + // Interrupt signals input logic irq_present_i, // there is an IRQ, so if we are sleeping we should wake up now - // Exception Controller Signals input logic exc_pc_sel_i, // exception execution requested - input logic illegal_c_insn_i, // compressed instruction decode failed - output logic illegal_insn_o, // illegal instruction encountered - output logic trap_insn_o, // trap instruction encountered input logic pc_valid_i, // is the next_pc currently valid? - output logic clear_isr_running_o, // an l.rfe instruction was encountered, exit ISR input logic exc_pipe_flush_i, // flush pipeline after exception handling input logic trap_hit_i, // a trap was hit, so we have to flush EX and WB + output logic illegal_insn_o, // illegal instruction encountered + output logic clear_isr_running_o, // an l.rfe instruction was encountered, exit ISR // Debug Unit Signals input logic dbg_stall_i, // Pipeline stall is requested @@ -121,16 +102,13 @@ module controller input logic regfile_we_wb_i, // FW: write enable from WB stage input logic [4:0] regfile_alu_waddr_fw_i, // FW: ALU/MUL write address from EX stage input logic regfile_alu_we_fw_i, // FW: ALU/MUL write enable from EX stage + + // forwarding signals output logic [1:0] operand_a_fw_mux_sel_o, // regfile ra data selector form ID stage output logic [1:0] operand_b_fw_mux_sel_o, // regfile rb data selector form ID stage output logic [1:0] operand_c_fw_mux_sel_o, // regfile rc data selector form ID stage - // Jump target calcuation done decision - output logic [1:0] jump_target_mux_sel_o, // jump target selection - input logic [1:0] jump_in_ex_i, // jump is being calculated in ALU - output logic [1:0] jump_in_id_o, // jump is being calculated in ALU - input logic branch_decision_i, - + // stall signals output logic stall_if_o, // Stall IF stage (deassert requests) output logic stall_id_o, // Stall ID stage (and instr and data memory interface) ( ID_STAGE ) output logic stall_ex_o, // Stall ex stage ( EX_STAGE ) @@ -144,7 +122,8 @@ module controller ); // FSM state encoding - enum logic [3:0] { RESET, BOOT_SET, SLEEP, FIRST_FETCH, DECODE, BRANCH, + enum logic [3:0] { RESET, BOOT_SET, SLEEP, FIRST_FETCH, + DECODE, BRANCH, FLUSH_EX, FLUSH_WB, DBG_FLUSH_EX, DBG_FLUSH_WB, DBG_SIGNAL, DBG_WAIT } ctrl_fsm_cs, ctrl_fsm_ns; @@ -158,24 +137,6 @@ module controller logic reg_d_alu_is_reg_b_id; logic reg_d_alu_is_reg_c_id; - // write enable/request control - logic deassert_we; - logic regfile_we; - logic regfile_alu_we; - logic data_req; - logic data_we; - logic [2:0] hwloop_we; - - logic pipe_flush; - logic trap_insn; - logic eret_insn; - - logic [1:0] jump_in_id; - - // signals to EX stage - logic [`ALU_OP_WIDTH-1:0] alu_operator; - logic mult_en; - logic [1:0] csr_op; logic misalign_stall; logic instr_ack_stall; @@ -183,755 +144,10 @@ module controller logic jr_stall; logic trap_stall; - logic rega_used; - logic regb_used; - logic regc_used; - logic halt_if; logic halt_id; - logic illegal_insn_int; - ///////////////////////////////////////////// - // ____ _ // - // | _ \ ___ ___ ___ __| | ___ _ __ // - // | | | |/ _ \/ __/ _ \ / _` |/ _ \ '__| // - // | |_| | __/ (_| (_) | (_| | __/ | // - // |____/ \___|\___\___/ \__,_|\___|_| // - // // - ///////////////////////////////////////////// - - always_comb - begin - jump_in_id = `BRANCH_NONE; - jump_target_mux_sel_o = `JT_JAL; - - alu_operator = `ALU_NOP; - alu_op_a_mux_sel_o = `OP_A_REGA_OR_FWD; - alu_op_b_mux_sel_o = `OP_B_REGB_OR_FWD; - alu_op_c_mux_sel_o = `OP_C_REGC_OR_FWD; - - immediate_mux_sel_o = `IMM_I; - - vector_mode_o = `VEC_MODE32; - scalar_replication_o = 1'b0; - alu_cmp_mode_o = `ALU_CMP_FULL; - - mult_en = 1'b0; - mult_signed_mode_o = 2'b00; - mult_sel_subword_o = 2'b00; - mult_mac_en_o = 1'b0; - - regfile_we = 1'b0; - regfile_alu_we = 1'b0; - regfile_alu_waddr_mux_sel_o = 1'b1; - - prepost_useincr_o = 1'b1; - - hwloop_we = 3'b0; - hwloop_start_mux_sel_o = 1'b0; - hwloop_end_mux_sel_o = 1'b0; - hwloop_cnt_mux_sel_o = 1'b0; - - csr_access_o = 1'b0; - csr_op = `CSR_OP_NONE; - - data_we = 1'b0; - data_type_o = 2'b00; - data_sign_extension_o = 1'b0; - data_reg_offset_o = 2'b00; - data_req = 1'b0; - - clear_isr_running_o = 1'b0; - - illegal_insn_int = 1'b0; - trap_insn = 1'b0; - eret_insn = 1'b0; - pipe_flush = 1'b0; - - rega_used = 1'b0; - regb_used = 1'b0; - regc_used = 1'b0; - - - unique case (instr_rdata_i[6:0]) - - ////////////////////////////////////// - // _ _ _ __ __ ____ ____ // - // | | | | | \/ | _ \/ ___| // - // _ | | | | | |\/| | |_) \___ \ // - // | |_| | |_| | | | | __/ ___) | // - // \___/ \___/|_| |_|_| |____/ // - // // - ////////////////////////////////////// - - `OPCODE_JAL: begin // Jump and Link - jump_target_mux_sel_o = `JT_JAL; - jump_in_id = `BRANCH_JAL; - // Calculate and store PC+4 - alu_op_a_mux_sel_o = `OP_A_CURRPC; - alu_op_b_mux_sel_o = `OP_B_IMM; - immediate_mux_sel_o = `IMM_PCINCR; - alu_operator = `ALU_ADD; - regfile_alu_we = 1'b1; - // Calculate jump target (= PC + UJ imm) - alu_op_c_mux_sel_o = `OP_C_JT; - end - - `OPCODE_JALR: begin // Jump and Link Register - jump_target_mux_sel_o = `JT_JALR; - jump_in_id = `BRANCH_JALR; - // Calculate and store PC+4 - alu_op_a_mux_sel_o = `OP_A_CURRPC; - alu_op_b_mux_sel_o = `OP_B_IMM; - immediate_mux_sel_o = `IMM_PCINCR; - alu_operator = `ALU_ADD; - regfile_alu_we = 1'b1; - // Calculate jump target (= RS1 + I imm) - rega_used = 1'b1; - alu_op_c_mux_sel_o = `OP_C_JT; - - if (instr_rdata_i[14:12] != 3'b0) begin - jump_in_id = `BRANCH_NONE; - regfile_alu_we = 1'b0; - illegal_insn_int = 1'b0; - end - end - - `OPCODE_BRANCH: begin // Branch - jump_target_mux_sel_o = `JT_COND; - jump_in_id = `BRANCH_COND; - alu_op_c_mux_sel_o = `OP_C_JT; - rega_used = 1'b1; - regb_used = 1'b1; - - unique case (instr_rdata_i[14:12]) - 3'b000: alu_operator = `ALU_EQ; - 3'b001: alu_operator = `ALU_NE; - 3'b100: alu_operator = `ALU_LTS; - 3'b101: alu_operator = `ALU_GES; - 3'b110: alu_operator = `ALU_LTU; - 3'b111: alu_operator = `ALU_GEU; - - default: begin - illegal_insn_int = 1'b1; - end - endcase - end - - - ////////////////////////////////// - // _ ____ ______ _____ // - // | | | _ \ / / ___|_ _| // - // | | | | | |/ /\___ \ | | // - // | |___| |_| / / ___) || | // - // |_____|____/_/ |____/ |_| // - // // - ////////////////////////////////// - - `OPCODE_STORE, - `OPCODE_STORE_POST: begin - data_req = 1'b1; - data_we = 1'b1; - rega_used = 1'b1; - regb_used = 1'b1; - alu_operator = `ALU_ADD; - - // post-increment setup - if (instr_rdata_i[6:0] == `OPCODE_STORE_POST) begin - prepost_useincr_o = 1'b0; - regfile_alu_waddr_mux_sel_o = 1'b0; - regfile_alu_we = 1'b1; - end - - if (instr_rdata_i[14] == 1'b0) begin - // offset from immediate - immediate_mux_sel_o = `IMM_S; - alu_op_b_mux_sel_o = `OP_B_IMM; - end else begin - // offset from register - regc_used = 1'b1; - alu_op_b_mux_sel_o = `OP_B_REGC_OR_FWD; - end - - // store size - unique case (instr_rdata_i[13:12]) - 2'b00: data_type_o = 2'b10; // SB - 2'b01: data_type_o = 2'b01; // SH - 2'b10: data_type_o = 2'b00; // SW - default: begin - data_req = 1'b0; - data_we = 1'b0; - illegal_insn_int = 1'b1; - end - endcase - end - - `OPCODE_LOAD, - `OPCODE_LOAD_POST: begin - data_req = 1'b1; - regfile_we = 1'b1; - rega_used = 1'b1; - data_type_o = 2'b00; - - // offset from immediate - alu_operator = `ALU_ADD; - alu_op_b_mux_sel_o = `OP_B_IMM; - immediate_mux_sel_o = `IMM_I; - - // post-increment setup - if (instr_rdata_i[6:0] == `OPCODE_LOAD_POST) begin - prepost_useincr_o = 1'b0; - regfile_alu_waddr_mux_sel_o = 1'b0; - regfile_alu_we = 1'b1; - end - - // sign/zero extension - data_sign_extension_o = ~instr_rdata_i[14]; - - // load size - unique case (instr_rdata_i[13:12]) - 2'b00: data_type_o = 2'b10; // LB - 2'b01: data_type_o = 2'b01; // LH - 2'b10: data_type_o = 2'b00; // LW - default: data_type_o = 2'b00; // illegal or reg-reg - endcase - - // reg-reg load (different encoding) - if (instr_rdata_i[14:12] == 3'b111) begin - // offset from RS2 - regb_used = 1'b1; - alu_op_b_mux_sel_o = `OP_B_REGB_OR_FWD; - - // sign/zero extension - data_sign_extension_o = ~instr_rdata_i[30]; - - // load size - unique case (instr_rdata_i[31:25]) - 7'b0000_000, - 7'b0100_000: data_type_o = 2'b10; // LB, LBU - 7'b0001_000, - 7'b0101_000: data_type_o = 2'b01; // LH, LHU - 7'b0010_000: data_type_o = 2'b00; // LW - default: begin - data_type_o = 2'b00; - // illegal instruction - data_req = 1'b0; - regfile_we = 1'b0; - regfile_alu_we = 1'b0; - illegal_insn_int = 1'b1; - end - endcase - end - - if (instr_rdata_i[14:12] == 3'b011 || instr_rdata_i[14:12] == 3'b110) - begin - // LD, LWU -> RV64 only - data_req = 1'b0; - regfile_we = 1'b0; - regfile_alu_we = 1'b0; - illegal_insn_int = 1'b1; - end - end - - - ////////////////////////// - // _ _ _ _ // - // / \ | | | | | | // - // / _ \ | | | | | | // - // / ___ \| |__| |_| | // - // /_/ \_\_____\___/ // - // // - ////////////////////////// - - `OPCODE_LUI: begin // Load Upper Immediate - alu_op_a_mux_sel_o = `OP_A_ZERO; - alu_op_b_mux_sel_o = `OP_B_IMM; - immediate_mux_sel_o = `IMM_U; - alu_operator = `ALU_ADD; - regfile_alu_we = 1'b1; - end - - `OPCODE_AUIPC: begin // Add Upper Immediate to PC - alu_op_a_mux_sel_o = `OP_A_CURRPC; - alu_op_b_mux_sel_o = `OP_B_IMM; - immediate_mux_sel_o = `IMM_U; - alu_operator = `ALU_ADD; - regfile_alu_we = 1'b1; - end - - `OPCODE_OPIMM: begin // Reigster-Immediate ALU Operations - alu_op_b_mux_sel_o = `OP_B_IMM; - immediate_mux_sel_o = `IMM_I; - regfile_alu_we = 1'b1; - rega_used = 1'b1; - - unique case (instr_rdata_i[14:12]) - 3'b000: alu_operator = `ALU_ADD; // Add Immediate - 3'b010: alu_operator = `ALU_SLTS; // Set to one if Lower Than Immediate - 3'b011: alu_operator = `ALU_SLTU; // Set to one if Lower Than Immediate Unsigned - 3'b100: alu_operator = `ALU_XOR; // Exclusive Or with Immediate - 3'b110: alu_operator = `ALU_OR; // Or with Immediate - 3'b111: alu_operator = `ALU_AND; // And with Immediate - - 3'b001: begin - alu_operator = `ALU_SLL; // Shift Left Logical by Immediate - if (instr_rdata_i[31:25] != 7'b0) - illegal_insn_int = 1'b1; - end - - 3'b101: begin - if (instr_rdata_i[31:25] == 7'b0) - alu_operator = `ALU_SRL; // Shift Right Logical by Immediate - else if (instr_rdata_i[31:25] == 7'b010_0000) - alu_operator = `ALU_SRA; // Shift Right Arithmetically by Immediate - else - illegal_insn_int = 1'b1; - end - - default: illegal_insn_int = 1'b1; - endcase - end - - `OPCODE_OP: begin // Register-Register ALU operation - regfile_alu_we = 1'b1; - rega_used = 1'b1; - regb_used = 1'b1; - - unique case ({instr_rdata_i[31:25], instr_rdata_i[14:12]}) - {7'b000_0000, 3'b000}: alu_operator = `ALU_ADD; // Add - {7'b010_0000, 3'b000}: alu_operator = `ALU_SUB; // Sub - - {7'b000_0000, 3'b010}: alu_operator = `ALU_SLTS; // Set Lower Than - {7'b000_0000, 3'b011}: alu_operator = `ALU_SLTU; // Set Lower Than Unsigned - - {7'b000_0000, 3'b100}: alu_operator = `ALU_XOR; // Xor - {7'b000_0000, 3'b110}: alu_operator = `ALU_OR; // Or - {7'b000_0000, 3'b111}: alu_operator = `ALU_AND; // And - - {7'b000_0000, 3'b001}: alu_operator = `ALU_SLL; // Shift Left Logical - {7'b000_0000, 3'b101}: alu_operator = `ALU_SRL; // Shift Right Logical - {7'b010_0000, 3'b101}: alu_operator = `ALU_SRA; // Shift Right Arithmetic - - {7'b000_0001, 3'b000}: mult_en = 1'b1; // Multiplication - - default: begin - regfile_alu_we = 1'b0; - illegal_insn_int = 1'b1; - end - endcase - end - - /* - - `OPCODE_ALU: begin // Arithmetic Operation - rega_used = 1'b1; - regb_used = 1'b1; - - case (instr_rdata_i[9:8]) - 2'b00: begin // ALU Operation - regfile_alu_we = 1'b1; - - casex (instr_rdata_i[3:0]) - 4'b110X: begin // l.ext{b,h,w}{s,z} - alu_operator = {3'b010, instr_rdata_i[7:6], instr_rdata_i[0]}; - regb_used = 1'b0; // register b is not used - end - 4'b1111: begin // l.ff1 - alu_operator = `ALU_FF1; - end - endcase // casex (instr_rdata_i[3:2]) - end - - 2'b01: begin // l.fl1, l.clb, l.cnt - regfile_alu_we = 1'b1; - regb_used = 1'b0; - - case (instr_rdata_i[3:0]) - 4'b1101: alu_operator = `ALU_CNT; - 4'b1110: alu_operator = `ALU_CLB; - 4'b1111: alu_operator = `ALU_FL1; - - default: begin - // synopsys translate_off - $display("%t: Illegal ALU instruction received.", $time); - // synopsys translate_on - regfile_alu_we = 1'b0; // disable Write Enable for illegal instruction - illegal_insn_int = 1'b1; - end - endcase //~case(instr_rdata_i[3:0]) - end - - 2'b10: begin // Min, Max, Abs, Avg - regfile_alu_we = 1'b1; - - case (instr_rdata_i[3:0]) - 4'b0000: alu_operator = `ALU_MIN; - 4'b0001: alu_operator = `ALU_MINU; - 4'b0010: alu_operator = `ALU_MAX; - 4'b0011: alu_operator = `ALU_MAXU; - 4'b0100: alu_operator = `ALU_AVG; - 4'b0101: alu_operator = `ALU_AVGU; - - 4'b1000: begin - regb_used = 1'b0; - alu_operator = `ALU_ABS; - end - - default: begin - // synopsys translate_off - $display("%t: Illegal ALU instruction received.", $time); - // synopsys translate_on - regfile_alu_we = 1'b0; // disable Write Enable for illegal instruction - illegal_insn_int = 1'b1; - end - endcase //~case(instr_rdata_i[3:0]) - end - endcase; // case (instr_rdata_i[9:8]) - end - - `OPCODE_MAC: begin // MAC instruction - mult_is_running = 1'b1; - - rega_used = 1'b1; - regb_used = 1'b1; - - regfile_alu_waddr_mux_sel_o = 2'b01; - regfile_alu_we = 1'b1; - - case (instr_rdata_i[6:5]) - 2'b00: begin // MAC - case (instr_rdata_i[3:0]) - 4'b1000: begin // l.mac - mult_mac_en_o = 1'b1; - regc_used = 1'b1; - set_carry = 1'b1; - set_overflow = 1'b1; - end - - 4'b1001: begin // l.mac.c - mult_use_carry_o = 1'b1; - mult_mac_en_o = 1'b1; - regc_used = 1'b1; - set_carry = 1'b1; - set_overflow = 1'b1; - end - - default: begin - // synopsys translate_off - $display("%t: Illegal MAC instruction received.", $time); - // synopsys translate_on - regfile_alu_we = 1'b0; - illegal_insn_int = 1'b1; - end - endcase // case (instr_rdata_i[3:0]) - end - - 2'b01: begin // MAC with subword selection - vector_mode_o = `VEC_MODE216; - mult_mac_en_o = 1'b1; - regc_used = 1'b1; - mult_sel_subword_o = instr_rdata_i[2:1]; - mult_signed_mode_o = instr_rdata_i[4:3]; - mult_use_carry_o = instr_rdata_i[0]; - set_carry = 1'b1; - set_overflow = 1'b1; - end - - 2'b11: begin // mult with subword selection - vector_mode_o = `VEC_MODE216; - mult_sel_subword_o = instr_rdata_i[2:1]; - mult_signed_mode_o = instr_rdata_i[4:3]; - end - - default: begin - // synopsys translate_off - $display("%t: Illegal MAC instruction received.", $time); - // synopsys translate_on - regfile_alu_we = 1'b0; - illegal_insn_int = 1'b1; - end - endcase - end - - `OPCODE_VEC: begin // vectorial alu operations - rega_used = 1'b1; - regfile_alu_we = 1'b1; - - if (instr_rdata_i[0] == 1'b0) // choose vector size - vector_mode_o = `VEC_MODE16; - else - vector_mode_o = `VEC_MODE8; - - if ((instr_rdata_i[7:6] == 2'b01) || (instr_rdata_i[7:6] == 2'b10)) // replicate scalar 2 or 4 times - scalar_replication_o = 1'b1; - - if (instr_rdata_i[7:6] == 2'b10) // use immediate as operand b - begin - alu_op_b_mux_sel_o = `OP_B_IMM; - immediate_mux_sel_o = `IMM_VEC; - end - else - regb_used = 1'b1; - - // now decode the sub opcodes - case (instr_rdata_i[5:1]) - 5'b00000: alu_operator = `ALU_ADD; - 5'b00001: alu_operator = `ALU_SUB; - 5'b00010: alu_operator = `ALU_AVG; - 5'b00011: alu_operator = `ALU_MIN; - 5'b00100: alu_operator = `ALU_MAX; - 5'b00101: alu_operator = `ALU_SRL; - 5'b00110: alu_operator = `ALU_SRA; - 5'b00111: alu_operator = `ALU_SLL; - - 5'b01000: begin // lv32.mul - regfile_alu_waddr_mux_sel_o = 2'b01; - mult_is_running = 1'b1; - end - - 5'b01001: alu_operator = `ALU_OR; - 5'b01010: alu_operator = `ALU_XOR; - 5'b01011: alu_operator = `ALU_AND; - - 5'b01100: begin // lv32.ins - alu_operator = `ALU_INS; - scalar_replication_o = 1'b1; - end - - 5'b10000: begin // lv32.abs - regb_used = 1'b0; // abs does not use operand b - alu_operator = `ALU_ABS; - end - - 5'b10001: begin // lv32.ext - regb_used = 1'b0; - alu_operator = `ALU_EXT; - end - - default: begin // unknown instruction encountered - regfile_alu_we = 1'b0; - illegal_insn_int = 1'b1; - // synopsys translate_off - $display("%t: Unknown vector opcode 0x%h.", $time, instr_rdata_i[5:1]); - // synopsys translate_on - end - endcase // instr_rdata[5:1] - end - - `OPCODE_VCMP: begin // Vectorial comparisons, i.e. lv32.cmp_*, lv32.all_*, lv32.any_* - rega_used = 1'b1; - regfile_alu_we = 1'b1; - - if (instr_rdata_i[0] == 1'b0) // choose vector size - vector_mode_o = `VEC_MODE16; - else - vector_mode_o = `VEC_MODE8; - - if ((instr_rdata_i[7:6] == 2'b01) || (instr_rdata_i[7:6] == 2'b10)) // replicate scalar 2 or 4 times - scalar_replication_o = 1'b1; - - if (instr_rdata_i[7:6] == 2'b10) // use immediate as operand b - begin - alu_op_b_mux_sel_o = `OP_B_IMM; - immediate_mux_sel_o = `IMM_VEC; - end - else - regb_used = 1'b1; - - // now decode the sub opcodes for the ALU - case (instr_rdata_i[3:1]) - 3'b000: alu_operator = `ALU_EQ; - 3'b001: alu_operator = `ALU_NE; - 3'b010: alu_operator = `ALU_GTS; - 3'b011: alu_operator = `ALU_GES; - 3'b100: alu_operator = `ALU_LTS; - 3'b101: alu_operator = `ALU_LES; - - default: begin // unknown instruction encountered - illegal_insn_int = 1'b1; - // synopsys translate_off - $display("%t: Unknown vector opcode 0x%h.", $time, instr_rdata_i[5:1]); - // synopsys translate_on - end - endcase //~case(instr_rdata_i[3:1]) - - alu_cmp_mode_o = instr_rdata_i[5:4]; // which kind of comparison do we have here, i.e. full, any, all - - if((instr_rdata_i[5:4] == `ALU_CMP_ANY) || (instr_rdata_i[5:4] == `ALU_CMP_ALL)) - set_flag = 1'b1; // set the flag for lv32.all_* and lv32.any_* - end - - */ - - - //////////////////////////////////////////////// - // ____ ____ _____ ____ ___ _ _ // - // / ___|| _ \| ____/ ___|_ _| / \ | | // - // \___ \| |_) | _|| | | | / _ \ | | // - // ___) | __/| |__| |___ | | / ___ \| |___ // - // |____/|_| |_____\____|___/_/ \_\_____| // - // // - //////////////////////////////////////////////// - - `OPCODE_SYSTEM: begin - if (instr_rdata_i[14:12] == 3'b000) - begin - // non CSR related SYSTEM instructions - unique case (instr_rdata_i[31:0]) - 32'h00_00_00_73: // ECALL - begin - // environment (system) call - // TODO: Handle in controller - end - - 32'h00_10_00_73: // EBREAK - begin - // debugger trap - trap_insn = 1'b1; - end - - 32'h10_00_00_73: // ERET - begin - eret_insn = 1'b1; - clear_isr_running_o = 1'b1; - end - - 32'h10_20_00_73: // WFI - begin - // flush pipeline - pipe_flush = 1'b1; - end - - default: - begin - illegal_insn_int = 1'b1; - end - endcase - end - else - begin - // instruction to read/modify CSR - csr_access_o = 1'b1; - regfile_alu_we = 1'b1; - alu_op_b_mux_sel_o = `OP_B_IMM; - immediate_mux_sel_o = `IMM_I; // CSR address is encoded in I imm - - if (instr_rdata_i[14] == 1'b1) begin - // rs1 field is used as immediate - alu_op_a_mux_sel_o = `OP_A_ZIMM; - end else begin - rega_used = 1'b1; - alu_op_a_mux_sel_o = `OP_A_REGA_OR_FWD; - end - - unique case (instr_rdata_i[13:12]) - 2'b01: csr_op = `CSR_OP_WRITE; - 2'b10: csr_op = `CSR_OP_SET; - 2'b11: csr_op = `CSR_OP_CLEAR; - default: illegal_insn_int = 1'b1; - endcase - end - - end - - - /////////////////////////////////////////////// - // _ ___ ___ ___ ___ ____ // - // | | | \ \ / / | / _ \ / _ \| _ \ // - // | |_| |\ \ /\ / /| | | | | | | | | |_) | // - // | _ | \ V V / | |__| |_| | |_| | __/ // - // |_| |_| \_/\_/ |_____\___/ \___/|_| // - // // - /////////////////////////////////////////////// - - `OPCODE_HWLOOP: begin - jump_target_mux_sel_o = `JT_HWLP; // get PC + I imm from jump target adder - - unique case (instr_rdata_i[14:12]) - 3'b000: begin - // lp.starti: set start address to PC + I-type immediate - hwloop_we[0] = 1'b1; - hwloop_start_mux_sel_o = 1'b0; - // $display("%t: hwloop start address: %h", $time, instr_rdata_i); - end - 3'b001: begin - // lp.endi: set end address to PC + I-type immediate - hwloop_we[1] = 1'b1; - hwloop_end_mux_sel_o = 1'b0; // jump target - // $display("%t: hwloop end address: %h", $time, instr_rdata_i); - end - 3'b010: begin - // lp.count initialize counter from rs1 - hwloop_we[2] = 1'b1; - hwloop_cnt_mux_sel_o = 1'b1; - rega_used = 1'b1; - // $display("%t: hwloop counter: %h", $time, instr_rdata_i); - end - 3'b011: begin - // lp.counti initialize counter from I-type immediate - hwloop_we[2] = 1'b1; - hwloop_cnt_mux_sel_o = 1'b0; - // $display("%t: hwloop counter imm: %h", $time, instr_rdata_i); - end - 3'b100: begin - // lp.setup: initialize counter from rs1, set start address to - // next instruction and end address to PC + I-type immediate - hwloop_we = 3'b111; - hwloop_start_mux_sel_o = 1'b1; - hwloop_end_mux_sel_o = 1'b0; - hwloop_cnt_mux_sel_o = 1'b1; - rega_used = 1'b1; - // $display("%t: hwloop setup: %h", $time, instr_rdata_i); - end - 3'b101: begin - // lp.setupi: initialize counter from I-type immediate, set start - // address to next instruction and end address to PC + shifted - // z-type immediate - hwloop_we = 3'b111; - hwloop_start_mux_sel_o = 1'b1; - hwloop_end_mux_sel_o = 1'b1; - hwloop_cnt_mux_sel_o = 1'b0; - illegal_insn_int = 1'b1; // TODO: PC + z-imm currently not supported - // $display("%t: hwloop setup imm: %h", $time, instr_rdata_i); - end - default: begin - illegal_insn_int = 1'b1; - end - endcase - end - - default: begin - illegal_insn_int = 1'b1; - end - endcase - - // make sure invalid compressed instruction causes an exception - if (illegal_c_insn_i) begin - illegal_insn_int = 1'b1; - end - - // misaligned access was detected by the LSU - // TODO: this section should eventually be moved out of the decoder - if (data_misaligned_i == 1'b1) - begin - // only part of the pipeline is unstalled, make sure that the - // correct operands are sent to the AGU - alu_op_a_mux_sel_o = `OP_A_REGA_OR_FWD; - alu_op_b_mux_sel_o = `OP_B_IMM; - immediate_mux_sel_o = `IMM_PCINCR; - - // if prepost increments are used, we do not write back the - // second address since the first calculated address was - // the correct one - regfile_alu_we = 1'b0; - - // if post increments are used, we must make sure that for - // the second memory access we do use the adder - prepost_useincr_o = 1'b1; - end - end - `ifndef SYNTHESIS // synopsys translate_off // make sure we are called later so that we do not generate messages for @@ -960,20 +176,21 @@ module controller always_comb begin // Default values - instr_req_o = 1'b1; + instr_req_o = 1'b1; - pc_mux_sel_o = `PC_BOOT; - pc_set_o = 1'b0; + pc_mux_sel_o = `PC_BOOT; + pc_set_o = 1'b0; - ctrl_fsm_ns = ctrl_fsm_cs; + ctrl_fsm_ns = ctrl_fsm_cs; - core_busy_o = 1'b1; - is_decoding_o = 1'b0; + core_busy_o = 1'b1; + is_decoding_o = 1'b0; - halt_if = 1'b0; - halt_id = 1'b0; - dbg_trap_o = 1'b0; - illegal_insn_o = 1'b0; + halt_if = 1'b0; + halt_id = 1'b0; + dbg_trap_o = 1'b0; + illegal_insn_o = 1'b0; + clear_isr_running_o = 1'b0; unique case (ctrl_fsm_cs) // We were just reset, wait for fetch_enable @@ -1031,7 +248,7 @@ module controller is_decoding_o = 1'b1; // handle conditional branches - if (jump_in_id == `BRANCH_COND) begin + if (jump_in_dec_i == `BRANCH_COND) begin // handle branch if decision is available in next cycle if (~stall_id_o) ctrl_fsm_ns = BRANCH; @@ -1039,7 +256,7 @@ module controller // handle unconditional jumps // we can jump directly since we know the address already - if (jump_in_id == `BRANCH_JALR || jump_in_id == `BRANCH_JAL) begin + if (jump_in_dec_i == `BRANCH_JALR || jump_in_dec_i == `BRANCH_JAL) begin pc_mux_sel_o = `PC_JUMP; // we don't have to change our current state here as the prefetch @@ -1053,7 +270,7 @@ module controller end // handle illegal instructions - if (illegal_insn_int) begin + if (illegal_insn_i) begin illegal_insn_o = 1'b1; end @@ -1067,14 +284,15 @@ module controller // exception handler end - if (eret_insn) begin - pc_mux_sel_o = `PC_ERET; - pc_set_o = 1'b1; + if (eret_insn_i) begin + clear_isr_running_o = 1'b1; + pc_mux_sel_o = `PC_ERET; + pc_set_o = 1'b1; end // handle WFI instruction, flush pipeline and (potentially) go to // sleep - if (pipe_flush || exc_pipe_flush_i) + if (pipe_flush_i || exc_pipe_flush_i) begin halt_if = 1'b1; halt_id = 1'b1; @@ -1084,7 +302,7 @@ module controller // take care of debug // branch conditional will be handled in next state - if(trap_hit_i && jump_in_id != `BRANCH_COND) + if(trap_hit_i && jump_in_dec_i != `BRANCH_COND) begin // halt pipeline immediately halt_if = 1'b1; @@ -1235,21 +453,21 @@ module controller begin load_stall = 1'b0; jr_stall = 1'b0; - deassert_we = 1'b0; + deassert_we_o = 1'b0; // deassert WE when the core is not decoding instructions if (ctrl_fsm_cs != DECODE) - deassert_we = 1'b1; + deassert_we_o = 1'b1; // deassert WE in case of illegal instruction - if (illegal_insn_int) - deassert_we = 1'b1; + if (illegal_insn_i) + deassert_we_o = 1'b1; // Stall because of load operation if ((data_req_ex_i == 1'b1) && (regfile_we_ex_i == 1'b1) && ((reg_d_ex_is_reg_a_id == 1'b1) || (reg_d_ex_is_reg_b_id == 1'b1) || (reg_d_ex_is_reg_c_id == 1'b1)) ) begin - deassert_we = 1'b1; + deassert_we_o = 1'b1; load_stall = 1'b1; end @@ -1257,13 +475,13 @@ module controller // - always stall if a result is to be forwarded to the PC // we don't care about in which state the ctrl_fsm is as we deassert_we // anyway when we are not in DECODE - if ((jump_in_id == `BRANCH_JALR) && + if ((jump_in_dec_i == `BRANCH_JALR) && (((regfile_we_wb_i == 1'b1) && (reg_d_wb_is_reg_a_id == 1'b1)) || ((regfile_we_ex_i == 1'b1) && (reg_d_ex_is_reg_a_id == 1'b1)) || ((regfile_alu_we_fw_i == 1'b1) && (reg_d_alu_is_reg_a_id == 1'b1))) ) begin jr_stall = 1'b1; - deassert_we = 1'b1; + deassert_we_o = 1'b1; end end @@ -1272,19 +490,7 @@ module controller assign misalign_stall = data_misaligned_i; - assign trap_stall = trap_insn_o; - - // deassert we signals (in case of stalls) - assign alu_operator_o = (deassert_we) ? `ALU_NOP : alu_operator; - assign mult_en_o = (deassert_we) ? 1'b0 : mult_en; - assign regfile_we_o = (deassert_we) ? 1'b0 : regfile_we; - assign regfile_alu_we_o = (deassert_we) ? 1'b0 : regfile_alu_we; - assign data_we_o = (deassert_we) ? 1'b0 : data_we; - assign data_req_o = (deassert_we) ? 1'b0 : data_req; - assign hwloop_we_o = (deassert_we) ? 3'b0 : hwloop_we; - assign csr_op_o = (deassert_we) ? `CSR_OP_NONE : csr_op; - assign trap_insn_o = (deassert_we) ? 1'b0 : trap_insn; - assign jump_in_id_o = (deassert_we) ? `BRANCH_NONE : jump_in_id; + assign trap_stall = trap_insn_i; //////////////////////////////////////////////////////////////////////////////////////////// @@ -1295,7 +501,7 @@ module controller // we unstall the if_stage if the debug unit wants to set a new // pc, so that the new value gets written into current_pc_if and is // used by the instr_core_interface - stall_if_o = instr_ack_stall | load_stall | jr_stall | (~lsu_ready_ex_i) | (~lsu_ready_wb_i) | misalign_stall | halt_if | (~pc_valid_i) | (jump_in_id_o == `BRANCH_COND); + stall_if_o = instr_ack_stall | load_stall | jr_stall | (~lsu_ready_ex_i) | (~lsu_ready_wb_i) | misalign_stall | halt_if | (~pc_valid_i) | (jump_in_id_i == `BRANCH_COND); stall_id_o = instr_ack_stall | load_stall | jr_stall | (~lsu_ready_ex_i) | (~lsu_ready_wb_i) | misalign_stall | halt_id; stall_ex_o = instr_ack_stall | (~lsu_ready_ex_i) | (~lsu_ready_wb_i) | dbg_stall_i; stall_wb_o = (~lsu_ready_wb_i) | dbg_stall_i; @@ -1307,14 +513,14 @@ module controller // RiscV register encoding: rs1 is [19:15], rs2 is [24:20], rd is [11:7] // // Or10n register encoding: ra is [20:16], rb is [15:11], rd is [25:21] // //////////////////////////////////////////////////////////////////////////////////////////// - assign reg_d_ex_is_reg_a_id = (regfile_waddr_ex_i == instr_rdata_i[`REG_S1]) && (rega_used == 1'b1); - assign reg_d_ex_is_reg_b_id = (regfile_waddr_ex_i == instr_rdata_i[`REG_S2]) && (regb_used == 1'b1); - assign reg_d_ex_is_reg_c_id = (regfile_waddr_ex_i == instr_rdata_i[`REG_D]) && (regc_used == 1'b1); - assign reg_d_wb_is_reg_a_id = (regfile_waddr_wb_i == instr_rdata_i[`REG_S1]) && (rega_used == 1'b1); - assign reg_d_wb_is_reg_b_id = (regfile_waddr_wb_i == instr_rdata_i[`REG_S2]) && (regb_used == 1'b1); - assign reg_d_wb_is_reg_c_id = (regfile_waddr_wb_i == instr_rdata_i[`REG_D]) && (regc_used == 1'b1); - assign reg_d_alu_is_reg_a_id = (regfile_alu_waddr_fw_i == instr_rdata_i[`REG_S1]) && (rega_used == 1'b1); - assign reg_d_alu_is_reg_b_id = (regfile_alu_waddr_fw_i == instr_rdata_i[`REG_S2]) && (regb_used == 1'b1); + assign reg_d_ex_is_reg_a_id = (regfile_waddr_ex_i == instr_rdata_i[`REG_S1]) && (rega_used_i == 1'b1); + assign reg_d_ex_is_reg_b_id = (regfile_waddr_ex_i == instr_rdata_i[`REG_S2]) && (regb_used_i == 1'b1); + assign reg_d_ex_is_reg_c_id = (regfile_waddr_ex_i == instr_rdata_i[`REG_D]) && (regc_used_i == 1'b1); + assign reg_d_wb_is_reg_a_id = (regfile_waddr_wb_i == instr_rdata_i[`REG_S1]) && (rega_used_i == 1'b1); + assign reg_d_wb_is_reg_b_id = (regfile_waddr_wb_i == instr_rdata_i[`REG_S2]) && (regb_used_i == 1'b1); + assign reg_d_wb_is_reg_c_id = (regfile_waddr_wb_i == instr_rdata_i[`REG_D]) && (regc_used_i == 1'b1); + assign reg_d_alu_is_reg_a_id = (regfile_alu_waddr_fw_i == instr_rdata_i[`REG_S1]) && (rega_used_i == 1'b1); + assign reg_d_alu_is_reg_b_id = (regfile_alu_waddr_fw_i == instr_rdata_i[`REG_S2]) && (regb_used_i == 1'b1); //assign reg_d_alu_is_reg_c_id = (regfile_alu_waddr_fw_i == instr_rdata_i[`REG_RD]) && (regc_used == 1'b1); assign reg_d_alu_is_reg_c_id = 1'b0; @@ -1375,8 +581,8 @@ module controller end // Performance Counters - assign perf_jump_o = (jump_in_id_o == `BRANCH_JAL || jump_in_id_o == `BRANCH_JALR); - assign perf_branch_o = (jump_in_id_o == `BRANCH_COND); + assign perf_jump_o = (jump_in_id_i == `BRANCH_JAL || jump_in_id_i == `BRANCH_JALR); + assign perf_branch_o = (jump_in_id_i == `BRANCH_COND); assign perf_jr_stall_o = jr_stall; assign perf_ld_stall_o = load_stall; diff --git a/decoder.sv b/decoder.sv new file mode 100644 index 00000000..17137990 --- /dev/null +++ b/decoder.sv @@ -0,0 +1,867 @@ +//////////////////////////////////////////////////////////////////////////////// +// Company: IIS @ ETHZ - Federal Institute of Technology // +// // +// Engineer Andreas Traber - atraber@iis.ee.ethz.ch // +// // +// Additional contributions by: // +// Matthias Baer - baermatt@student.ethz.ch // +// Igor Loi - igor.loi@unibo.it // +// Sven Stucki - svstucki@student.ethz.ch // +// // +// // +// Create Date: 19/09/2013 // +// Design Name: RISC-V processor core // +// Module Name: decoder.sv // +// Project Name: RI5CY // +// Language: SystemVerilog // +// // +// Description: Decoder // +// // +// // +// Revision: // +// Revision v0.1 - File Created, separated controller and decoder // +// // +// // +// // +//////////////////////////////////////////////////////////////////////////////// + +`include "defines.sv" + +module decoder +( + // singals running to/from controller + input logic deassert_we_i, // deassert we, we are stalled or not active + input logic data_misaligned_i, // misaligned data load/store in progress + + output logic illegal_insn_o, // illegal instruction encountered + output logic trap_insn_o, // trap instruction encountered + output logic eret_insn_o, // trap instruction encountered + output logic pipe_flush_o, // pipeline flush is requested (e.g. WFI instruction) + + output logic rega_used_o, // register A is used by current instruction + output logic regb_used_o, // register B is used by current instruction + output logic regc_used_o, // register C is used by current instruction + + + // from IF/ID pipeline + input logic [31:0] instr_rdata_i, // Instruction read from instr memory/cache: (sampled in the if stage) + input logic illegal_c_insn_i, // compressed instruction decode failed + + // ALU signals + output logic [`ALU_OP_WIDTH-1:0] alu_operator_o, // Operator in the EX stage for the ALU block + output logic [1:0] alu_op_a_mux_sel_o, // Operator a is selected between reg value, PC or immediate + output logic [1:0] alu_op_b_mux_sel_o, // Operator b is selected between reg value or immediate + output logic alu_op_c_mux_sel_o, // Operator c is selected between reg value or PC + output logic [2:0] immediate_mux_sel_o, + + output logic [1:0] vector_mode_o, // selects between 32 bit, 16 bit and 8 bit vectorial modes + output logic scalar_replication_o, // activates scalar_replication for vectorial mode + output logic [1:0] alu_cmp_mode_o, // selects comparison mode for ALU (i.e. full, any, all) + + // MUL related control signals + output logic mult_en_o, // Perform a multiplication operation + output logic [1:0] mult_sel_subword_o, // Select subwords for 16x16 bit of multiplier + output logic [1:0] mult_signed_mode_o, // Multiplication in signed mode + output logic mult_mac_en_o, // Use the accumulator after multiplication + + // register file related signals + output logic regfile_mem_we_o, // Write Enable to regfile + output logic regfile_alu_we_o, // Write Enable to regfile 2nd port + output logic regfile_alu_waddr_sel_o, // Select register write address for ALU/MUL operations + + // CSR manipulation + output logic csr_access_o, // perform an access to CSR + output logic [1:0] csr_op_o, // operation to perform on CSR + + // LD/ST unit signals + output logic data_req_o, // Request for a transaction to data memory + output logic data_we_o, // Write enable to data memory + output logic prepost_useincr_o, // When not active bypass the alu result for address calculation = op_a + output logic [1:0] data_type_o, // Data type on data memory: byte, half word or word + output logic data_sign_extension_o, // Sign extension on read data from data memory + output logic [1:0] data_reg_offset_o, // Offset in bytes inside register for stores + + // hwloop signals + output logic [2:0] hwloop_we_o, // write enable for hwloop regs + output logic hwloop_start_mux_sel_o, // selects hwloop start address input + output logic hwloop_end_mux_sel_o, // selects hwloop end address input + output logic hwloop_cnt_mux_sel_o, // selects hwloop counter input + + // jump/branches + output logic [1:0] jump_in_dec_o, // jump_in_id without deassert + output logic [1:0] jump_in_id_o, // jump is being calculated in ALU + output logic [1:0] jump_target_mux_sel_o // jump target selection +); + + // write enable/request control + logic regfile_mem_we; + logic regfile_alu_we; + logic data_req; + logic data_we; + logic [2:0] hwloop_we; + + logic trap_insn; + logic eret_insn; + logic pipe_flush; + + logic [1:0] jump_in_id; + + logic [`ALU_OP_WIDTH-1:0] alu_operator; + logic mult_en; + logic [1:0] csr_op; + + + ///////////////////////////////////////////// + // ____ _ // + // | _ \ ___ ___ ___ __| | ___ _ __ // + // | | | |/ _ \/ __/ _ \ / _` |/ _ \ '__| // + // | |_| | __/ (_| (_) | (_| | __/ | // + // |____/ \___|\___\___/ \__,_|\___|_| // + // // + ///////////////////////////////////////////// + + always_comb + begin + jump_in_id = `BRANCH_NONE; + jump_target_mux_sel_o = `JT_JAL; + + alu_operator = `ALU_NOP; + alu_op_a_mux_sel_o = `OP_A_REGA_OR_FWD; + alu_op_b_mux_sel_o = `OP_B_REGB_OR_FWD; + alu_op_c_mux_sel_o = `OP_C_REGC_OR_FWD; + + immediate_mux_sel_o = `IMM_I; + + vector_mode_o = `VEC_MODE32; + scalar_replication_o = 1'b0; + alu_cmp_mode_o = `ALU_CMP_FULL; + + mult_en = 1'b0; + mult_signed_mode_o = 2'b00; + mult_sel_subword_o = 2'b00; + mult_mac_en_o = 1'b0; + + regfile_mem_we = 1'b0; + regfile_alu_we = 1'b0; + regfile_alu_waddr_sel_o = 1'b1; + + prepost_useincr_o = 1'b1; + + hwloop_we = 3'b0; + hwloop_start_mux_sel_o = 1'b0; + hwloop_end_mux_sel_o = 1'b0; + hwloop_cnt_mux_sel_o = 1'b0; + + csr_access_o = 1'b0; + csr_op = `CSR_OP_NONE; + + data_we = 1'b0; + data_type_o = 2'b00; + data_sign_extension_o = 1'b0; + data_reg_offset_o = 2'b00; + data_req = 1'b0; + + illegal_insn_o = 1'b0; + trap_insn = 1'b0; + eret_insn = 1'b0; + pipe_flush = 1'b0; + + rega_used_o = 1'b0; + regb_used_o = 1'b0; + regc_used_o = 1'b0; + + + unique case (instr_rdata_i[6:0]) + + ////////////////////////////////////// + // _ _ _ __ __ ____ ____ // + // | | | | | \/ | _ \/ ___| // + // _ | | | | | |\/| | |_) \___ \ // + // | |_| | |_| | | | | __/ ___) | // + // \___/ \___/|_| |_|_| |____/ // + // // + ////////////////////////////////////// + + `OPCODE_JAL: begin // Jump and Link + jump_target_mux_sel_o = `JT_JAL; + jump_in_id = `BRANCH_JAL; + // Calculate and store PC+4 + alu_op_a_mux_sel_o = `OP_A_CURRPC; + alu_op_b_mux_sel_o = `OP_B_IMM; + immediate_mux_sel_o = `IMM_PCINCR; + alu_operator = `ALU_ADD; + regfile_alu_we = 1'b1; + // Calculate jump target (= PC + UJ imm) + alu_op_c_mux_sel_o = `OP_C_JT; + end + + `OPCODE_JALR: begin // Jump and Link Register + jump_target_mux_sel_o = `JT_JALR; + jump_in_id = `BRANCH_JALR; + // Calculate and store PC+4 + alu_op_a_mux_sel_o = `OP_A_CURRPC; + alu_op_b_mux_sel_o = `OP_B_IMM; + immediate_mux_sel_o = `IMM_PCINCR; + alu_operator = `ALU_ADD; + regfile_alu_we = 1'b1; + // Calculate jump target (= RS1 + I imm) + rega_used_o = 1'b1; + alu_op_c_mux_sel_o = `OP_C_JT; + + if (instr_rdata_i[14:12] != 3'b0) begin + jump_in_id = `BRANCH_NONE; + regfile_alu_we = 1'b0; + illegal_insn_o = 1'b0; + end + end + + `OPCODE_BRANCH: begin // Branch + jump_target_mux_sel_o = `JT_COND; + jump_in_id = `BRANCH_COND; + alu_op_c_mux_sel_o = `OP_C_JT; + rega_used_o = 1'b1; + regb_used_o = 1'b1; + + unique case (instr_rdata_i[14:12]) + 3'b000: alu_operator = `ALU_EQ; + 3'b001: alu_operator = `ALU_NE; + 3'b100: alu_operator = `ALU_LTS; + 3'b101: alu_operator = `ALU_GES; + 3'b110: alu_operator = `ALU_LTU; + 3'b111: alu_operator = `ALU_GEU; + + default: begin + illegal_insn_o = 1'b1; + end + endcase + end + + + ////////////////////////////////// + // _ ____ ______ _____ // + // | | | _ \ / / ___|_ _| // + // | | | | | |/ /\___ \ | | // + // | |___| |_| / / ___) || | // + // |_____|____/_/ |____/ |_| // + // // + ////////////////////////////////// + + `OPCODE_STORE, + `OPCODE_STORE_POST: begin + data_req = 1'b1; + data_we = 1'b1; + rega_used_o = 1'b1; + regb_used_o = 1'b1; + alu_operator = `ALU_ADD; + + // post-increment setup + if (instr_rdata_i[6:0] == `OPCODE_STORE_POST) begin + prepost_useincr_o = 1'b0; + regfile_alu_waddr_sel_o = 1'b0; + regfile_alu_we = 1'b1; + end + + if (instr_rdata_i[14] == 1'b0) begin + // offset from immediate + immediate_mux_sel_o = `IMM_S; + alu_op_b_mux_sel_o = `OP_B_IMM; + end else begin + // offset from register + regc_used_o = 1'b1; + alu_op_b_mux_sel_o = `OP_B_REGC_OR_FWD; + end + + // store size + unique case (instr_rdata_i[13:12]) + 2'b00: data_type_o = 2'b10; // SB + 2'b01: data_type_o = 2'b01; // SH + 2'b10: data_type_o = 2'b00; // SW + default: begin + data_req = 1'b0; + data_we = 1'b0; + illegal_insn_o = 1'b1; + end + endcase + end + + `OPCODE_LOAD, + `OPCODE_LOAD_POST: begin + data_req = 1'b1; + regfile_mem_we = 1'b1; + rega_used_o = 1'b1; + data_type_o = 2'b00; + + // offset from immediate + alu_operator = `ALU_ADD; + alu_op_b_mux_sel_o = `OP_B_IMM; + immediate_mux_sel_o = `IMM_I; + + // post-increment setup + if (instr_rdata_i[6:0] == `OPCODE_LOAD_POST) begin + prepost_useincr_o = 1'b0; + regfile_alu_waddr_sel_o = 1'b0; + regfile_alu_we = 1'b1; + end + + // sign/zero extension + data_sign_extension_o = ~instr_rdata_i[14]; + + // load size + unique case (instr_rdata_i[13:12]) + 2'b00: data_type_o = 2'b10; // LB + 2'b01: data_type_o = 2'b01; // LH + 2'b10: data_type_o = 2'b00; // LW + default: data_type_o = 2'b00; // illegal or reg-reg + endcase + + // reg-reg load (different encoding) + if (instr_rdata_i[14:12] == 3'b111) begin + // offset from RS2 + regb_used_o = 1'b1; + alu_op_b_mux_sel_o = `OP_B_REGB_OR_FWD; + + // sign/zero extension + data_sign_extension_o = ~instr_rdata_i[30]; + + // load size + unique case (instr_rdata_i[31:25]) + 7'b0000_000, + 7'b0100_000: data_type_o = 2'b10; // LB, LBU + 7'b0001_000, + 7'b0101_000: data_type_o = 2'b01; // LH, LHU + 7'b0010_000: data_type_o = 2'b00; // LW + default: begin + data_type_o = 2'b00; + // illegal instruction + data_req = 1'b0; + regfile_mem_we = 1'b0; + regfile_alu_we = 1'b0; + illegal_insn_o = 1'b1; + end + endcase + end + + if (instr_rdata_i[14:12] == 3'b011 || instr_rdata_i[14:12] == 3'b110) + begin + // LD, LWU -> RV64 only + data_req = 1'b0; + regfile_mem_we = 1'b0; + regfile_alu_we = 1'b0; + illegal_insn_o = 1'b1; + end + end + + + ////////////////////////// + // _ _ _ _ // + // / \ | | | | | | // + // / _ \ | | | | | | // + // / ___ \| |__| |_| | // + // /_/ \_\_____\___/ // + // // + ////////////////////////// + + `OPCODE_LUI: begin // Load Upper Immediate + alu_op_a_mux_sel_o = `OP_A_ZERO; + alu_op_b_mux_sel_o = `OP_B_IMM; + immediate_mux_sel_o = `IMM_U; + alu_operator = `ALU_ADD; + regfile_alu_we = 1'b1; + end + + `OPCODE_AUIPC: begin // Add Upper Immediate to PC + alu_op_a_mux_sel_o = `OP_A_CURRPC; + alu_op_b_mux_sel_o = `OP_B_IMM; + immediate_mux_sel_o = `IMM_U; + alu_operator = `ALU_ADD; + regfile_alu_we = 1'b1; + end + + `OPCODE_OPIMM: begin // Reigster-Immediate ALU Operations + alu_op_b_mux_sel_o = `OP_B_IMM; + immediate_mux_sel_o = `IMM_I; + regfile_alu_we = 1'b1; + rega_used_o = 1'b1; + + unique case (instr_rdata_i[14:12]) + 3'b000: alu_operator = `ALU_ADD; // Add Immediate + 3'b010: alu_operator = `ALU_SLTS; // Set to one if Lower Than Immediate + 3'b011: alu_operator = `ALU_SLTU; // Set to one if Lower Than Immediate Unsigned + 3'b100: alu_operator = `ALU_XOR; // Exclusive Or with Immediate + 3'b110: alu_operator = `ALU_OR; // Or with Immediate + 3'b111: alu_operator = `ALU_AND; // And with Immediate + + 3'b001: begin + alu_operator = `ALU_SLL; // Shift Left Logical by Immediate + if (instr_rdata_i[31:25] != 7'b0) + illegal_insn_o = 1'b1; + end + + 3'b101: begin + if (instr_rdata_i[31:25] == 7'b0) + alu_operator = `ALU_SRL; // Shift Right Logical by Immediate + else if (instr_rdata_i[31:25] == 7'b010_0000) + alu_operator = `ALU_SRA; // Shift Right Arithmetically by Immediate + else + illegal_insn_o = 1'b1; + end + + default: illegal_insn_o = 1'b1; + endcase + end + + `OPCODE_OP: begin // Register-Register ALU operation + regfile_alu_we = 1'b1; + rega_used_o = 1'b1; + regb_used_o = 1'b1; + + unique case ({instr_rdata_i[31:25], instr_rdata_i[14:12]}) + {7'b000_0000, 3'b000}: alu_operator = `ALU_ADD; // Add + {7'b010_0000, 3'b000}: alu_operator = `ALU_SUB; // Sub + + {7'b000_0000, 3'b010}: alu_operator = `ALU_SLTS; // Set Lower Than + {7'b000_0000, 3'b011}: alu_operator = `ALU_SLTU; // Set Lower Than Unsigned + + {7'b000_0000, 3'b100}: alu_operator = `ALU_XOR; // Xor + {7'b000_0000, 3'b110}: alu_operator = `ALU_OR; // Or + {7'b000_0000, 3'b111}: alu_operator = `ALU_AND; // And + + {7'b000_0000, 3'b001}: alu_operator = `ALU_SLL; // Shift Left Logical + {7'b000_0000, 3'b101}: alu_operator = `ALU_SRL; // Shift Right Logical + {7'b010_0000, 3'b101}: alu_operator = `ALU_SRA; // Shift Right Arithmetic + + {7'b000_0001, 3'b000}: mult_en = 1'b1; // Multiplication + + default: begin + regfile_alu_we = 1'b0; + illegal_insn_o = 1'b1; + end + endcase + end + + /* + + `OPCODE_ALU: begin // Arithmetic Operation + rega_used_o = 1'b1; + regb_used_o = 1'b1; + + case (instr_rdata_i[9:8]) + 2'b00: begin // ALU Operation + regfile_alu_we = 1'b1; + + casex (instr_rdata_i[3:0]) + 4'b110X: begin // l.ext{b,h,w}{s,z} + alu_operator = {3'b010, instr_rdata_i[7:6], instr_rdata_i[0]}; + regb_used_o = 1'b0; // register b is not used + end + 4'b1111: begin // l.ff1 + alu_operator = `ALU_FF1; + end + endcase // casex (instr_rdata_i[3:2]) + end + + 2'b01: begin // l.fl1, l.clb, l.cnt + regfile_alu_we = 1'b1; + regb_used_o = 1'b0; + + case (instr_rdata_i[3:0]) + 4'b1101: alu_operator = `ALU_CNT; + 4'b1110: alu_operator = `ALU_CLB; + 4'b1111: alu_operator = `ALU_FL1; + + default: begin + // synopsys translate_off + $display("%t: Illegal ALU instruction received.", $time); + // synopsys translate_on + regfile_alu_we = 1'b0; // disable Write Enable for illegal instruction + illegal_insn_o = 1'b1; + end + endcase //~case(instr_rdata_i[3:0]) + end + + 2'b10: begin // Min, Max, Abs, Avg + regfile_alu_we = 1'b1; + + case (instr_rdata_i[3:0]) + 4'b0000: alu_operator = `ALU_MIN; + 4'b0001: alu_operator = `ALU_MINU; + 4'b0010: alu_operator = `ALU_MAX; + 4'b0011: alu_operator = `ALU_MAXU; + 4'b0100: alu_operator = `ALU_AVG; + 4'b0101: alu_operator = `ALU_AVGU; + + 4'b1000: begin + regb_used_o = 1'b0; + alu_operator = `ALU_ABS; + end + + default: begin + // synopsys translate_off + $display("%t: Illegal ALU instruction received.", $time); + // synopsys translate_on + regfile_alu_we = 1'b0; // disable Write Enable for illegal instruction + illegal_insn_o = 1'b1; + end + endcase //~case(instr_rdata_i[3:0]) + end + endcase; // case (instr_rdata_i[9:8]) + end + + `OPCODE_MAC: begin // MAC instruction + mult_is_running = 1'b1; + + rega_used_o = 1'b1; + regb_used_o = 1'b1; + + regfile_alu_waddr_sel_o = 2'b01; + regfile_alu_we = 1'b1; + + case (instr_rdata_i[6:5]) + 2'b00: begin // MAC + case (instr_rdata_i[3:0]) + 4'b1000: begin // l.mac + mult_mac_en_o = 1'b1; + regc_used_o = 1'b1; + set_carry = 1'b1; + set_overflow = 1'b1; + end + + 4'b1001: begin // l.mac.c + mult_use_carry_o = 1'b1; + mult_mac_en_o = 1'b1; + regc_used_o = 1'b1; + set_carry = 1'b1; + set_overflow = 1'b1; + end + + default: begin + // synopsys translate_off + $display("%t: Illegal MAC instruction received.", $time); + // synopsys translate_on + regfile_alu_we = 1'b0; + illegal_insn_o = 1'b1; + end + endcase // case (instr_rdata_i[3:0]) + end + + 2'b01: begin // MAC with subword selection + vector_mode_o = `VEC_MODE216; + mult_mac_en_o = 1'b1; + regc_used_o = 1'b1; + mult_sel_subword_o = instr_rdata_i[2:1]; + mult_signed_mode_o = instr_rdata_i[4:3]; + mult_use_carry_o = instr_rdata_i[0]; + set_carry = 1'b1; + set_overflow = 1'b1; + end + + 2'b11: begin // mult with subword selection + vector_mode_o = `VEC_MODE216; + mult_sel_subword_o = instr_rdata_i[2:1]; + mult_signed_mode_o = instr_rdata_i[4:3]; + end + + default: begin + // synopsys translate_off + $display("%t: Illegal MAC instruction received.", $time); + // synopsys translate_on + regfile_alu_we = 1'b0; + illegal_insn_o = 1'b1; + end + endcase + end + + `OPCODE_VEC: begin // vectorial alu operations + rega_used_o = 1'b1; + regfile_alu_we = 1'b1; + + if (instr_rdata_i[0] == 1'b0) // choose vector size + vector_mode_o = `VEC_MODE16; + else + vector_mode_o = `VEC_MODE8; + + if ((instr_rdata_i[7:6] == 2'b01) || (instr_rdata_i[7:6] == 2'b10)) // replicate scalar 2 or 4 times + scalar_replication_o = 1'b1; + + if (instr_rdata_i[7:6] == 2'b10) // use immediate as operand b + begin + alu_op_b_mux_sel_o = `OP_B_IMM; + immediate_mux_sel_o = `IMM_VEC; + end + else + regb_used_o = 1'b1; + + // now decode the sub opcodes + case (instr_rdata_i[5:1]) + 5'b00000: alu_operator = `ALU_ADD; + 5'b00001: alu_operator = `ALU_SUB; + 5'b00010: alu_operator = `ALU_AVG; + 5'b00011: alu_operator = `ALU_MIN; + 5'b00100: alu_operator = `ALU_MAX; + 5'b00101: alu_operator = `ALU_SRL; + 5'b00110: alu_operator = `ALU_SRA; + 5'b00111: alu_operator = `ALU_SLL; + + 5'b01000: begin // lv32.mul + regfile_alu_waddr_sel_o = 2'b01; + mult_is_running = 1'b1; + end + + 5'b01001: alu_operator = `ALU_OR; + 5'b01010: alu_operator = `ALU_XOR; + 5'b01011: alu_operator = `ALU_AND; + + 5'b01100: begin // lv32.ins + alu_operator = `ALU_INS; + scalar_replication_o = 1'b1; + end + + 5'b10000: begin // lv32.abs + regb_used_o = 1'b0; // abs does not use operand b + alu_operator = `ALU_ABS; + end + + 5'b10001: begin // lv32.ext + regb_used_o = 1'b0; + alu_operator = `ALU_EXT; + end + + default: begin // unknown instruction encountered + regfile_alu_we = 1'b0; + illegal_insn_o = 1'b1; + // synopsys translate_off + $display("%t: Unknown vector opcode 0x%h.", $time, instr_rdata_i[5:1]); + // synopsys translate_on + end + endcase // instr_rdata[5:1] + end + + `OPCODE_VCMP: begin // Vectorial comparisons, i.e. lv32.cmp_*, lv32.all_*, lv32.any_* + rega_used_o = 1'b1; + regfile_alu_we = 1'b1; + + if (instr_rdata_i[0] == 1'b0) // choose vector size + vector_mode_o = `VEC_MODE16; + else + vector_mode_o = `VEC_MODE8; + + if ((instr_rdata_i[7:6] == 2'b01) || (instr_rdata_i[7:6] == 2'b10)) // replicate scalar 2 or 4 times + scalar_replication_o = 1'b1; + + if (instr_rdata_i[7:6] == 2'b10) // use immediate as operand b + begin + alu_op_b_mux_sel_o = `OP_B_IMM; + immediate_mux_sel_o = `IMM_VEC; + end + else + regb_used_o = 1'b1; + + // now decode the sub opcodes for the ALU + case (instr_rdata_i[3:1]) + 3'b000: alu_operator = `ALU_EQ; + 3'b001: alu_operator = `ALU_NE; + 3'b010: alu_operator = `ALU_GTS; + 3'b011: alu_operator = `ALU_GES; + 3'b100: alu_operator = `ALU_LTS; + 3'b101: alu_operator = `ALU_LES; + + default: begin // unknown instruction encountered + illegal_insn_o = 1'b1; + // synopsys translate_off + $display("%t: Unknown vector opcode 0x%h.", $time, instr_rdata_i[5:1]); + // synopsys translate_on + end + endcase //~case(instr_rdata_i[3:1]) + + alu_cmp_mode_o = instr_rdata_i[5:4]; // which kind of comparison do we have here, i.e. full, any, all + + if((instr_rdata_i[5:4] == `ALU_CMP_ANY) || (instr_rdata_i[5:4] == `ALU_CMP_ALL)) + set_flag = 1'b1; // set the flag for lv32.all_* and lv32.any_* + end + + */ + + + //////////////////////////////////////////////// + // ____ ____ _____ ____ ___ _ _ // + // / ___|| _ \| ____/ ___|_ _| / \ | | // + // \___ \| |_) | _|| | | | / _ \ | | // + // ___) | __/| |__| |___ | | / ___ \| |___ // + // |____/|_| |_____\____|___/_/ \_\_____| // + // // + //////////////////////////////////////////////// + + `OPCODE_SYSTEM: begin + if (instr_rdata_i[14:12] == 3'b000) + begin + // non CSR related SYSTEM instructions + unique case (instr_rdata_i[31:0]) + 32'h00_00_00_73: // ECALL + begin + // environment (system) call + // TODO: Handle in controller + end + + 32'h00_10_00_73: // EBREAK + begin + // debugger trap + trap_insn = 1'b1; + end + + 32'h10_00_00_73: // ERET + begin + eret_insn = 1'b1; + end + + 32'h10_20_00_73: // WFI + begin + // flush pipeline + pipe_flush = 1'b1; + end + + default: + begin + illegal_insn_o = 1'b1; + end + endcase + end + else + begin + // instruction to read/modify CSR + csr_access_o = 1'b1; + regfile_alu_we = 1'b1; + alu_op_b_mux_sel_o = `OP_B_IMM; + immediate_mux_sel_o = `IMM_I; // CSR address is encoded in I imm + + if (instr_rdata_i[14] == 1'b1) begin + // rs1 field is used as immediate + alu_op_a_mux_sel_o = `OP_A_ZIMM; + end else begin + rega_used_o = 1'b1; + alu_op_a_mux_sel_o = `OP_A_REGA_OR_FWD; + end + + unique case (instr_rdata_i[13:12]) + 2'b01: csr_op = `CSR_OP_WRITE; + 2'b10: csr_op = `CSR_OP_SET; + 2'b11: csr_op = `CSR_OP_CLEAR; + default: illegal_insn_o = 1'b1; + endcase + end + + end + + + /////////////////////////////////////////////// + // _ ___ ___ ___ ___ ____ // + // | | | \ \ / / | / _ \ / _ \| _ \ // + // | |_| |\ \ /\ / /| | | | | | | | | |_) | // + // | _ | \ V V / | |__| |_| | |_| | __/ // + // |_| |_| \_/\_/ |_____\___/ \___/|_| // + // // + /////////////////////////////////////////////// + + `OPCODE_HWLOOP: begin + jump_target_mux_sel_o = `JT_HWLP; // get PC + I imm from jump target adder + + unique case (instr_rdata_i[14:12]) + 3'b000: begin + // lp.starti: set start address to PC + I-type immediate + hwloop_we[0] = 1'b1; + hwloop_start_mux_sel_o = 1'b0; + // $display("%t: hwloop start address: %h", $time, instr_rdata_i); + end + 3'b001: begin + // lp.endi: set end address to PC + I-type immediate + hwloop_we[1] = 1'b1; + hwloop_end_mux_sel_o = 1'b0; // jump target + // $display("%t: hwloop end address: %h", $time, instr_rdata_i); + end + 3'b010: begin + // lp.count initialize counter from rs1 + hwloop_we[2] = 1'b1; + hwloop_cnt_mux_sel_o = 1'b1; + rega_used_o = 1'b1; + // $display("%t: hwloop counter: %h", $time, instr_rdata_i); + end + 3'b011: begin + // lp.counti initialize counter from I-type immediate + hwloop_we[2] = 1'b1; + hwloop_cnt_mux_sel_o = 1'b0; + // $display("%t: hwloop counter imm: %h", $time, instr_rdata_i); + end + 3'b100: begin + // lp.setup: initialize counter from rs1, set start address to + // next instruction and end address to PC + I-type immediate + hwloop_we = 3'b111; + hwloop_start_mux_sel_o = 1'b1; + hwloop_end_mux_sel_o = 1'b0; + hwloop_cnt_mux_sel_o = 1'b1; + rega_used_o = 1'b1; + // $display("%t: hwloop setup: %h", $time, instr_rdata_i); + end + 3'b101: begin + // lp.setupi: initialize counter from I-type immediate, set start + // address to next instruction and end address to PC + shifted + // z-type immediate + hwloop_we = 3'b111; + hwloop_start_mux_sel_o = 1'b1; + hwloop_end_mux_sel_o = 1'b1; + hwloop_cnt_mux_sel_o = 1'b0; + illegal_insn_o = 1'b1; // TODO: PC + z-imm currently not supported + // $display("%t: hwloop setup imm: %h", $time, instr_rdata_i); + end + default: begin + illegal_insn_o = 1'b1; + end + endcase + end + + default: begin + illegal_insn_o = 1'b1; + end + endcase + + // make sure invalid compressed instruction causes an exception + if (illegal_c_insn_i) begin + illegal_insn_o = 1'b1; + end + + // misaligned access was detected by the LSU + // TODO: this section should eventually be moved out of the decoder + if (data_misaligned_i == 1'b1) + begin + // only part of the pipeline is unstalled, make sure that the + // correct operands are sent to the AGU + alu_op_a_mux_sel_o = `OP_A_REGA_OR_FWD; + alu_op_b_mux_sel_o = `OP_B_IMM; + immediate_mux_sel_o = `IMM_PCINCR; + + // if prepost increments are used, we do not write back the + // second address since the first calculated address was + // the correct one + regfile_alu_we = 1'b0; + + // if post increments are used, we must make sure that for + // the second memory access we do use the adder + prepost_useincr_o = 1'b1; + end + end + + // deassert we signals (in case of stalls) + assign regfile_mem_we_o = (deassert_we_i) ? 1'b0 : regfile_mem_we; + assign regfile_alu_we_o = (deassert_we_i) ? 1'b0 : regfile_alu_we; + assign data_req_o = (deassert_we_i) ? 1'b0 : data_req; + assign data_we_o = (deassert_we_i) ? 1'b0 : data_we; // TODO: is this needed? + assign alu_operator_o = (deassert_we_i) ? `ALU_NOP : alu_operator; + assign mult_en_o = (deassert_we_i) ? 1'b0 : mult_en; + assign hwloop_we_o = (deassert_we_i) ? 3'b0 : hwloop_we; + assign csr_op_o = (deassert_we_i) ? `CSR_OP_NONE : csr_op; + assign jump_in_id_o = (deassert_we_i) ? `BRANCH_NONE : jump_in_id; + assign trap_insn_o = (deassert_we_i) ? 1'b0 : trap_insn; + assign eret_insn_o = (deassert_we_i) ? 1'b0 : eret_insn; // TODO: do not deassert? + assign pipe_flush_o = (deassert_we_i) ? 1'b0 : pipe_flush; // TODO: do not deassert? + + assign jump_in_dec_o = jump_in_id; + +endmodule // controller diff --git a/id_stage.sv b/id_stage.sv index c8af19cd..4be7e606 100644 --- a/id_stage.sv +++ b/id_stage.sv @@ -45,7 +45,6 @@ module id_stage // Interface to instruction memory input logic [31:0] instr_rdata_i, // comes from pipeline of IF stage output logic instr_req_o, - input logic instr_gnt_i, input logic instr_ack_i, // Jumps and branches @@ -72,20 +71,10 @@ module id_stage output logic stall_wb_o, // To the Pipeline ID/EX - output logic [31:0] regfile_rb_data_ex_o, - output logic [31:0] alu_operand_a_ex_o, - output logic [31:0] alu_operand_b_ex_o, - output logic [31:0] alu_operand_c_ex_o, - output logic [`ALU_OP_WIDTH-1:0] alu_operator_ex_o, - - output logic [1:0] vector_mode_ex_o, - output logic [1:0] alu_cmp_mode_ex_o, - output logic [1:0] alu_vec_ext_ex_o, - - output logic mult_en_ex_o, - output logic [1:0] mult_sel_subword_ex_o, - output logic [1:0] mult_signed_mode_ex_o, - output logic mult_mac_en_ex_o, + output logic [31:0] regfile_rb_data_ex_o, + output logic [31:0] alu_operand_a_ex_o, + output logic [31:0] alu_operand_b_ex_o, + output logic [31:0] alu_operand_c_ex_o, output logic [4:0] regfile_waddr_ex_o, output logic regfile_we_ex_o, @@ -93,22 +82,37 @@ module id_stage output logic [4:0] regfile_alu_waddr_ex_o, output logic regfile_alu_we_ex_o, - output logic prepost_useincr_ex_o, - input logic data_misaligned_i, + // ALU + output logic [`ALU_OP_WIDTH-1:0] alu_operator_ex_o, - output logic [31:0] hwloop_targ_addr_o, - output logic hwloop_jump_o, + output logic [1:0] vector_mode_ex_o, + output logic [1:0] alu_cmp_mode_ex_o, + output logic [1:0] alu_vec_ext_ex_o, + // MUL + output logic mult_en_ex_o, + output logic [1:0] mult_sel_subword_ex_o, + output logic [1:0] mult_signed_mode_ex_o, + output logic mult_mac_en_ex_o, + + // CSR ID/EX output logic csr_access_ex_o, output logic [1:0] csr_op_ex_o, + // hwloop signals + output logic [31:0] hwloop_targ_addr_o, + output logic hwloop_jump_o, + // Interface to load store unit + output logic data_req_ex_o, output logic data_we_ex_o, output logic [1:0] data_type_ex_o, output logic data_sign_ext_ex_o, output logic [1:0] data_reg_offset_ex_o, output logic data_misaligned_ex_o, - output logic data_req_ex_o, + + output logic prepost_useincr_ex_o, + input logic data_misaligned_i, input logic lsu_ready_ex_i, input logic lsu_ready_wb_i, @@ -149,10 +153,23 @@ module id_stage output logic perf_ld_stall_o // load-use-hazard ); - - // Compressed instruction decoding logic [31:0] instr; + // Decoder/Controller ID stage internal signals + logic deassert_we; + + logic illegal_insn_dec; + logic trap_insn; + logic eret_insn_dec; + logic pipe_flush_dec; + + logic rega_used_dec; + logic regb_used_dec; + logic regc_used_dec; + + logic [1:0] jump_in_dec; + + // Immediate decoding and sign extension logic [31:0] imm_i_type; logic [31:0] imm_s_type; @@ -166,14 +183,11 @@ module id_stage logic [31:0] jump_target; // calculated jump target (-> EX -> IF) logic exc_pc_sel; - logic [2:0] pc_mux_sel_int; // selects next PC in if stage logic irq_present; // Signals running between controller and exception controller logic illegal_insn; - logic illegal_c_insn; - logic trap_insn; logic trap_hit; logic pc_valid; logic clear_isr_running; @@ -264,9 +278,6 @@ module id_stage logic [31:0] operand_c; - assign pc_mux_sel_o = pc_mux_sel_int; - - assign instr = instr_rdata_i; // immediate extraction and sign extension @@ -510,6 +521,83 @@ module id_stage assign dbg_reg_rdata_o = regfile_data_rc_id; + + /////////////////////////////////////////////// + // ____ _____ ____ ___ ____ _____ ____ // + // | _ \| ____/ ___/ _ \| _ \| ____| _ \ // + // | | | | _|| | | | | | | | | _| | |_) | // + // | |_| | |__| |__| |_| | |_| | |___| _ < // + // |____/|_____\____\___/|____/|_____|_| \_\ // + // // + /////////////////////////////////////////////// + + decoder decoder_i + ( + // controller related signals + .deassert_we_i ( deassert_we ), + .data_misaligned_i ( data_misaligned_i ), + + .illegal_insn_o ( illegal_insn_dec ), + .trap_insn_o ( trap_insn ), + .eret_insn_o ( eret_insn_dec ), + .pipe_flush_o ( pipe_flush_dec ), + + .rega_used_o ( rega_used_dec ), + .regb_used_o ( regb_used_dec ), + .regc_used_o ( regc_used_dec ), + + + // from IF/ID pipeline + .instr_rdata_i ( instr ), + .illegal_c_insn_i ( illegal_c_insn_i ), + + // ALU signals + .alu_operator_o ( alu_operator ), + .alu_op_a_mux_sel_o ( alu_op_a_mux_sel ), + .alu_op_b_mux_sel_o ( alu_op_b_mux_sel ), + .alu_op_c_mux_sel_o ( alu_op_c_mux_sel ), + .immediate_mux_sel_o ( immediate_mux_sel ), + + .vector_mode_o ( vector_mode ), + .scalar_replication_o ( scalar_replication ), + .alu_cmp_mode_o ( alu_cmp_mode ), + + // MUL signals + .mult_en_o ( mult_en ), + .mult_sel_subword_o ( mult_sel_subword ), + .mult_signed_mode_o ( mult_signed_mode ), + .mult_mac_en_o ( mult_mac_en ), + + // Register file control signals + .regfile_mem_we_o ( regfile_we_id ), + .regfile_alu_we_o ( regfile_alu_we_id ), + .regfile_alu_waddr_sel_o ( regfile_alu_waddr_mux_sel ), + + // CSR control signals + .csr_access_o ( csr_access ), + .csr_op_o ( csr_op ), + + // Data bus interface + .data_req_o ( data_req_id ), + .data_we_o ( data_we_id ), + .prepost_useincr_o ( prepost_useincr ), + .data_type_o ( data_type_id ), + .data_sign_extension_o ( data_sign_ext_id ), + .data_reg_offset_o ( data_reg_offset_id ), + + // hwloop signals + .hwloop_we_o ( hwloop_we ), + .hwloop_start_mux_sel_o ( hwloop_start_mux_sel ), + .hwloop_end_mux_sel_o ( hwloop_end_mux_sel ), + .hwloop_cnt_mux_sel_o ( hwloop_cnt_mux_sel ), + + // jump/branches + .jump_in_dec_o ( jump_in_dec ), + .jump_in_id_o ( jump_in_id_o ), + .jump_target_mux_sel_o ( jump_target_mux_sel ) + + ); + //////////////////////////////////////////////////////////////////// // ____ ___ _ _ _____ ____ ___ _ _ _____ ____ // // / ___/ _ \| \ | |_ _| _ \ / _ \| | | | | ____| _ \ // @@ -520,122 +608,94 @@ module id_stage //////////////////////////////////////////////////////////////////// controller controller_i ( - .clk ( clk ), - .rst_n ( rst_n ), - .fetch_enable_i ( fetch_enable_i ), - .core_busy_o ( core_busy_o ), - .is_decoding_o ( is_decoding_o ), + .clk ( clk ), + .rst_n ( rst_n ), - // Signal from-to PC pipe (instr rdata) and instr mem system (req and ack) - .instr_rdata_i ( instr ), - .instr_req_o ( instr_req_o ), - .instr_gnt_i ( instr_gnt_i ), - .instr_ack_i ( instr_ack_i ), + .fetch_enable_i ( fetch_enable_i ), + .core_busy_o ( core_busy_o ), + .is_decoding_o ( is_decoding_o ), - .pc_set_o ( pc_set_o ), - .pc_mux_sel_o ( pc_mux_sel_int ), + // decoder related signals + .deassert_we_o ( deassert_we ), + .illegal_insn_i ( illegal_insn_dec ), + .trap_insn_i ( trap_insn ), + .eret_insn_i ( eret_insn_dec ), + .pipe_flush_i ( pipe_flush_dec ), - // Alu signals - .alu_operator_o ( alu_operator ), - .alu_op_a_mux_sel_o ( alu_op_a_mux_sel ), - .alu_op_b_mux_sel_o ( alu_op_b_mux_sel ), - .alu_op_c_mux_sel_o ( alu_op_c_mux_sel ), - .immediate_mux_sel_o ( immediate_mux_sel ), + .rega_used_i ( rega_used_dec ), + .regb_used_i ( regb_used_dec ), + .regc_used_i ( regc_used_dec ), - .scalar_replication_o ( scalar_replication ), - .vector_mode_o ( vector_mode ), - .alu_cmp_mode_o ( alu_cmp_mode ), + // from IF/ID pipeline + .instr_rdata_i ( instr ), - // mult signals - .mult_en_o ( mult_en ), - .mult_sel_subword_o ( mult_sel_subword ), - .mult_signed_mode_o ( mult_signed_mode ), - .mult_mac_en_o ( mult_mac_en ), + // from prefetcher + .instr_req_o ( instr_req_o ), + .instr_ack_i ( instr_ack_i ), - // Register file control signals - .regfile_we_o ( regfile_we_id ), + // to prefetcher + .pc_set_o ( pc_set_o ), + .pc_mux_sel_o ( pc_mux_sel_o ), - .regfile_alu_we_o ( regfile_alu_we_id ), - .regfile_alu_waddr_mux_sel_o ( regfile_alu_waddr_mux_sel ), + // LSU + .data_req_ex_i ( data_req_ex_o ), + .data_misaligned_i ( data_misaligned_i ), - .prepost_useincr_o ( prepost_useincr ), - .data_misaligned_i ( data_misaligned_i ), - - // CSR control signals - .csr_access_o ( csr_access ), - .csr_op_o ( csr_op ), - - // Data bus interface - .data_we_o ( data_we_id ), - .data_type_o ( data_type_id ), - .data_sign_extension_o ( data_sign_ext_id ), - .data_reg_offset_o ( data_reg_offset_id ), - .data_req_o ( data_req_id ), - .data_req_ex_i ( data_req_ex_o ), - - .lsu_ready_ex_i ( lsu_ready_ex_i ), - .lsu_ready_wb_i ( lsu_ready_wb_i ), + .lsu_ready_ex_i ( lsu_ready_ex_i ), + .lsu_ready_wb_i ( lsu_ready_wb_i ), // hwloop signals - .hwloop_we_o ( hwloop_we ), - .hwloop_start_mux_sel_o ( hwloop_start_mux_sel ), - .hwloop_end_mux_sel_o ( hwloop_end_mux_sel ), - .hwloop_cnt_mux_sel_o ( hwloop_cnt_mux_sel ), - .hwloop_jump_i ( hwloop_jump ), + .hwloop_jump_i ( hwloop_jump ), + + // jump/branch control + .jump_in_dec_i ( jump_in_dec ), + .jump_in_id_i ( jump_in_id_o ), + .jump_in_ex_i ( jump_in_ex_o ), + + .branch_decision_i ( branch_decision_i ), // Interrupt signals - .irq_present_i ( irq_present ), + .irq_present_i ( irq_present ), // Exception Controller Signals - .exc_pc_sel_i ( exc_pc_sel ), - .illegal_c_insn_i ( illegal_c_insn_i ), - .illegal_insn_o ( illegal_insn ), - .trap_insn_o ( trap_insn ), - .pc_valid_i ( pc_valid ), - .clear_isr_running_o ( clear_isr_running ), - .trap_hit_i ( trap_hit ), - .exc_pipe_flush_i ( exc_pipe_flush ), + .exc_pc_sel_i ( exc_pc_sel ), + .pc_valid_i ( pc_valid ), + .exc_pipe_flush_i ( exc_pipe_flush ), + .trap_hit_i ( trap_hit ), + .illegal_insn_o ( illegal_insn ), + .clear_isr_running_o ( clear_isr_running ), // Debug Unit Signals - .dbg_stall_i ( dbg_stall_i ), - .dbg_set_npc_i ( dbg_set_npc_i ), - .dbg_trap_o ( dbg_trap_o ), + .dbg_stall_i ( dbg_stall_i ), + .dbg_set_npc_i ( dbg_set_npc_i ), + .dbg_trap_o ( dbg_trap_o ), - // regfile port 1 - .regfile_waddr_ex_i ( regfile_waddr_ex_o ), // Write address for register file from ex-wb- pipeline registers - .regfile_we_ex_i ( regfile_we_ex_o ), - .regfile_waddr_wb_i ( regfile_waddr_wb_i ), // Write address for register file from ex-wb- pipeline registers - .regfile_we_wb_i ( regfile_we_wb_i ), + // Forwarding signals from regfile + .regfile_waddr_ex_i ( regfile_waddr_ex_o ), // Write address for register file from ex-wb- pipeline registers + .regfile_we_ex_i ( regfile_we_ex_o ), + .regfile_waddr_wb_i ( regfile_waddr_wb_i ), // Write address for register file from ex-wb- pipeline registers + .regfile_we_wb_i ( regfile_we_wb_i ), // regfile port 2 - .regfile_alu_waddr_fw_i ( regfile_alu_waddr_fw_i ), - .regfile_alu_we_fw_i ( regfile_alu_we_fw_i ), + .regfile_alu_waddr_fw_i ( regfile_alu_waddr_fw_i ), + .regfile_alu_we_fw_i ( regfile_alu_we_fw_i ), // Forwarding signals - .operand_a_fw_mux_sel_o ( operand_a_fw_mux_sel ), - .operand_b_fw_mux_sel_o ( operand_b_fw_mux_sel ), - .operand_c_fw_mux_sel_o ( operand_c_fw_mux_sel ), - - // To controller (TODO: Remove when control/decode separated and moved) - .jump_target_mux_sel_o ( jump_target_mux_sel ), - .jump_in_ex_i ( jump_in_ex_o ), - - .branch_decision_i ( branch_decision_i ), - - // To exception controller and EX: Jump/Branch indication - .jump_in_id_o ( jump_in_id_o ), + .operand_a_fw_mux_sel_o ( operand_a_fw_mux_sel ), + .operand_b_fw_mux_sel_o ( operand_b_fw_mux_sel ), + .operand_c_fw_mux_sel_o ( operand_c_fw_mux_sel ), // Stall signals - .stall_if_o ( stall_if_o ), - .stall_id_o ( stall_id_o ), - .stall_ex_o ( stall_ex_o ), - .stall_wb_o ( stall_wb_o ), + .stall_if_o ( stall_if_o ), + .stall_id_o ( stall_id_o ), + .stall_ex_o ( stall_ex_o ), + .stall_wb_o ( stall_wb_o ), // Performance Counters - .perf_jump_o ( perf_jump_o ), - .perf_branch_o ( perf_branch_o ), - .perf_jr_stall_o ( perf_jr_stall_o ), - .perf_ld_stall_o ( perf_ld_stall_o ) + .perf_jump_o ( perf_jump_o ), + .perf_branch_o ( perf_branch_o ), + .perf_jr_stall_o ( perf_jr_stall_o ), + .perf_ld_stall_o ( perf_ld_stall_o ) ); diff --git a/riscv_core.sv b/riscv_core.sv index bb1cf278..09e5f07a 100644 --- a/riscv_core.sv +++ b/riscv_core.sv @@ -43,21 +43,21 @@ module riscv_core input logic [4:0] cluster_id_i, // Instruction memory interface - output logic [31:0] instr_addr_o, output logic instr_req_o, - input logic [31:0] instr_rdata_i, - input logic instr_grant_i, + input logic instr_grant_i, // TODO: rename to instr_gnt_i input logic instr_rvalid_i, + output logic [31:0] instr_addr_o, + input logic [31:0] instr_rdata_i, // Data memory interface + output logic data_req_o, + input logic data_gnt_i, + input logic data_r_valid_i, // TODO: rename to data_rvalid_i + output logic data_we_o, + output logic [3:0] data_be_o, output logic [31:0] data_addr_o, output logic [31:0] data_wdata_o, - output logic data_we_o, - output logic data_req_o, - output logic [3:0] data_be_o, input logic [31:0] data_rdata_i, - input logic data_gnt_i, - input logic data_r_valid_i, // Interrupt inputs input logic irq_i, // level-triggered IR line @@ -291,33 +291,31 @@ module riscv_core // Processor Enable .fetch_enable_i ( fetch_enable_i ), - - .jump_in_id_o ( jump_in_id ), - .jump_in_ex_o ( jump_in_ex ), - .branch_decision_i ( branch_decision ), - - .jump_target_o ( jump_target_id ), - .core_busy_o ( core_busy ), .is_decoding_o ( is_decoding ), // Interface to instruction memory .instr_rdata_i ( instr_rdata_id ), .instr_req_o ( instr_req_int ), - .instr_gnt_i ( instr_grant_i ), .instr_ack_i ( instr_ack_int ), + // Jumps and branches + .jump_in_id_o ( jump_in_id ), + .jump_in_ex_o ( jump_in_ex ), + .branch_decision_i ( branch_decision ), + .jump_target_o ( jump_target_id ), + .pc_set_o ( pc_set ), .pc_mux_sel_o ( pc_mux_sel_id ), .exc_pc_mux_o ( exc_pc_mux_id ), - .is_compressed_i ( is_compressed_id ), .illegal_c_insn_i ( illegal_c_insn_id ), + .is_compressed_i ( is_compressed_id ), .current_pc_if_i ( current_pc_if ), .current_pc_id_i ( current_pc_id ), - // STALLS + // Stalls .stall_if_o ( stall_if ), .stall_id_o ( stall_id ), .stall_ex_o ( stall_ex ), @@ -325,20 +323,9 @@ module riscv_core // From the Pipeline ID/EX .regfile_rb_data_ex_o ( regfile_rb_data_ex ), - .alu_operand_a_ex_o ( alu_operand_a_ex ), .alu_operand_b_ex_o ( alu_operand_b_ex ), .alu_operand_c_ex_o ( alu_operand_c_ex ), - .alu_operator_ex_o ( alu_operator_ex ), - - .vector_mode_ex_o ( vector_mode_ex ), // from ID to EX stage - .alu_cmp_mode_ex_o ( alu_cmp_mode_ex ), // from ID to EX stage - .alu_vec_ext_ex_o ( alu_vec_ext_ex ), // from ID to EX stage - - .mult_en_ex_o ( mult_en_ex ), // from ID to EX stage - .mult_sel_subword_ex_o ( mult_sel_subword_ex ), // from ID to EX stage - .mult_signed_mode_ex_o ( mult_signed_mode_ex ), // from ID to EX stage - .mult_mac_en_ex_o ( mult_mac_en_ex ), // from ID to EX stage .regfile_waddr_ex_o ( regfile_waddr_ex ), .regfile_we_ex_o ( regfile_we_ex ), @@ -346,6 +333,19 @@ module riscv_core .regfile_alu_we_ex_o ( regfile_alu_we_ex ), .regfile_alu_waddr_ex_o ( regfile_alu_waddr_ex ), + // ALU + .alu_operator_ex_o ( alu_operator_ex ), + + .vector_mode_ex_o ( vector_mode_ex ), // from ID to EX stage + .alu_cmp_mode_ex_o ( alu_cmp_mode_ex ), // from ID to EX stage + .alu_vec_ext_ex_o ( alu_vec_ext_ex ), // from ID to EX stage + + // MUL + .mult_en_ex_o ( mult_en_ex ), // from ID to EX stage + .mult_sel_subword_ex_o ( mult_sel_subword_ex ), // from ID to EX stage + .mult_signed_mode_ex_o ( mult_signed_mode_ex ), // from ID to EX stage + .mult_mac_en_ex_o ( mult_mac_en_ex ), // from ID to EX stage + // CSR ID/EX .csr_access_ex_o ( csr_access_ex ), .csr_op_ex_o ( csr_op_ex ), @@ -354,16 +354,17 @@ module riscv_core .hwloop_jump_o ( hwloop_jump ), .hwloop_targ_addr_o ( hwloop_target ), - .prepost_useincr_ex_o ( useincr_addr_ex ), - .data_misaligned_i ( data_misaligned ), - + // LSU + .data_req_ex_o ( data_req_ex ), // to load store unit .data_we_ex_o ( data_we_ex ), // to load store unit .data_type_ex_o ( data_type_ex ), // to load store unit .data_sign_ext_ex_o ( data_sign_ext_ex ), // to load store unit .data_reg_offset_ex_o ( data_reg_offset_ex ), // to load store unit - .data_req_ex_o ( data_req_ex ), // to load store unit .data_misaligned_ex_o ( data_misaligned_ex ), // to load store unit + .prepost_useincr_ex_o ( useincr_addr_ex ), + .data_misaligned_i ( data_misaligned ), + .lsu_ready_ex_i ( lsu_ready_ex ), .lsu_ready_wb_i ( lsu_ready_wb ), @@ -388,14 +389,15 @@ module riscv_core .dbg_set_npc_i ( dbg_set_npc ), // Forward Signals - .regfile_alu_waddr_fw_i ( regfile_alu_waddr_fw ), - .regfile_alu_we_fw_i ( regfile_alu_we_fw ), - .regfile_alu_wdata_fw_i ( regfile_alu_wdata_fw ), - .regfile_waddr_wb_i ( regfile_waddr_fw_wb_o), // Write address ex-wb pipeline .regfile_we_wb_i ( regfile_we_wb ), // write enable for the register file .regfile_wdata_wb_i ( regfile_wdata ), // write data to commit in the register file + .regfile_alu_waddr_fw_i ( regfile_alu_waddr_fw ), + .regfile_alu_we_fw_i ( regfile_alu_we_fw ), + .regfile_alu_wdata_fw_i ( regfile_alu_wdata_fw ), + + // Performance Counters .perf_jump_o ( perf_jump ), .perf_branch_o ( perf_branch ), .perf_jr_stall_o ( perf_jr_stall ), @@ -664,7 +666,7 @@ module riscv_core rs2_value = id_stage_i.operand_b_fw_id; // special case for WFI because we don't wait for unstalling there - if ((id_stage_i.stall_ex_o == 1'b0 && is_decoding) || id_stage_i.controller_i.pipe_flush) + if ((id_stage_i.stall_ex_o == 1'b0 && is_decoding) || id_stage_i.controller_i.pipe_flush_i) begin mnemonic = ""; imm = 0;