URL
https://opencores.org/ocsvn/altor32/altor32/trunk
Subversion Repositories altor32
[/] [altor32/] [trunk/] [rtl/] [cpu/] [altor32_exec.v] - Rev 36
Go to most recent revision | Compare with Previous | Blame | View Log
//----------------------------------------------------------------- // AltOR32 // Alternative Lightweight OpenRisc // V2.1 // Ultra-Embedded.com // Copyright 2011 - 2014 // // Email: admin@ultra-embedded.com // // License: LGPL //----------------------------------------------------------------- // // Copyright (C) 2011 - 2013 Ultra-Embedded.com // // This source file may be used and distributed without // restriction provided that this copyright statement is not // removed from the file and that any derivative work contains // the original copyright notice and the associated disclaimer. // // This source file is free software; you can redistribute it // and/or modify it under the terms of the GNU Lesser General // Public License as published by the Free Software Foundation; // either version 2.1 of the License, or (at your option) any // later version. // // This source is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the GNU Lesser General Public License for more // details. // // You should have received a copy of the GNU Lesser General // Public License along with this source; if not, write to the // Free Software Foundation, Inc., 59 Temple Place, Suite 330, // Boston, MA 02111-1307 USA //----------------------------------------------------------------- //`define CONF_CORE_DEBUG //`define CONF_CORE_TRACE //----------------------------------------------------------------- // Module - Instruction Execute //----------------------------------------------------------------- module altor32_exec ( // General input clk_i /*verilator public*/, input rst_i /*verilator public*/, // Maskable interrupt input intr_i /*verilator public*/, // Unmaskable interrupt input nmi_i /*verilator public*/, // Fault output reg fault_o /*verilator public*/, // Breakpoint / Trap output reg break_o /*verilator public*/, // Cache control output reg icache_flush_o /*verilator public*/, output reg dcache_flush_o /*verilator public*/, // Branch output branch_o /*verilator public*/, output [31:0] branch_pc_o /*verilator public*/, output stall_o /*verilator public*/, // Opcode & arguments input [31:0] opcode_i /*verilator public*/, input [31:0] opcode_pc_i /*verilator public*/, input opcode_valid_i /*verilator public*/, // Reg A input [4:0] reg_ra_i /*verilator public*/, input [31:0] reg_ra_value_i /*verilator public*/, // Reg B input [4:0] reg_rb_i /*verilator public*/, input [31:0] reg_rb_value_i /*verilator public*/, // Reg D input [4:0] reg_rd_i /*verilator public*/, // Output output [31:0] opcode_o /*verilator public*/, output [4:0] reg_rd_o /*verilator public*/, output [31:0] reg_rd_value_o /*verilator public*/, output mult_o /*verilator public*/, output [31:0] mult_res_o /*verilator public*/, // Register write back bypass input [4:0] wb_rd_i /*verilator public*/, input [31:0] wb_rd_value_i /*verilator public*/, // Memory Interface output reg [31:0] dmem_addr_o /*verilator public*/, output reg [31:0] dmem_data_out_o /*verilator public*/, input [31:0] dmem_data_in_i /*verilator public*/, output reg [3:0] dmem_sel_o /*verilator public*/, output reg dmem_we_o /*verilator public*/, output reg dmem_stb_o /*verilator public*/, output reg dmem_cyc_o /*verilator public*/, input dmem_stall_i /*verilator public*/, input dmem_ack_i /*verilator public*/ ); //----------------------------------------------------------------- // Includes //----------------------------------------------------------------- `include "altor32_defs.v" `include "altor32_funcs.v" //----------------------------------------------------------------- // Params //----------------------------------------------------------------- parameter BOOT_VECTOR = 32'h00000000; parameter ISR_VECTOR = 32'h00000000; //----------------------------------------------------------------- // Registers //----------------------------------------------------------------- // Branch PC reg [31:0] r_pc_branch; reg r_pc_fetch; // Exception saved program counter reg [31:0] r_epc; // Supervisor register reg [31:0] r_sr; // Exception saved supervisor register reg [31:0] r_esr; // Destination register number (post execute stage) reg [4:0] r_e_rd; // Current opcode (PC for debug) reg [31:0] r_e_opcode; reg [31:0] r_e_opcode_pc; // ALU input A reg [31:0] r_e_alu_a; // ALU input B reg [31:0] r_e_alu_b; // ALU output wire [31:0] r_e_result; // Resolved RA/RB register contents wire [31:0] ra_value_resolved; wire [31:0] rb_value_resolved; wire operand_resolved; wire resolve_failed; // ALU Carry wire alu_carry_out; wire alu_carry_update; wire alu_flag_update; // ALU Comparisons wire compare_equal_w; wire compare_gts_w; wire compare_gt_w; wire compare_lts_w; wire compare_lt_w; // ALU operation selection reg [3:0] r_e_alu_func; // Load instruction details reg [4:0] r_load_rd; reg [7:0] r_load_inst; reg [1:0] r_load_offset; // Load forwarding wire load_insn; wire [31:0] load_result; // Memory access? reg r_mem_load; reg r_mem_store; reg r_mem_access; wire load_pending; wire store_pending; wire load_insert; wire load_stall; reg d_mem_load; // Delayed NMI reg r_nmi; // SIM PUTC `ifdef SIM_EXT_PUTC reg [7:0] r_putc; `endif //----------------------------------------------------------------- // Instantiation //----------------------------------------------------------------- // ALU altor32_alu alu ( // ALU operation select .op_i(r_e_alu_func), // Operands .a_i(r_e_alu_a), .b_i(r_e_alu_b), .c_i(r_sr[`OR32_SR_CY]), // Result .p_o(r_e_result), // Carry .c_o(alu_carry_out), .c_update_o(alu_carry_update), // Comparisons .equal_o(compare_equal_w), .greater_than_signed_o(compare_gts_w), .greater_than_o(compare_gt_w), .less_than_signed_o(compare_lts_w), .less_than_o(compare_lt_w), .flag_update_o(alu_flag_update) ); // Load result forwarding altor32_lfu u_lfu ( // Opcode .opcode_i(r_load_inst), // Memory load result .mem_result_i(dmem_data_in_i), .mem_offset_i(r_load_offset), // Result .load_result_o(load_result), .load_insn_o(load_insn) ); // Load / store pending logic altor32_lsu u_lsu ( // Current instruction .opcode_valid_i(opcode_valid_i & ~r_pc_fetch), .opcode_i({2'b00,opcode_i[31:26]}), // Load / Store pending .load_pending_i(r_mem_load), .store_pending_i(r_mem_store), // Load dest register .rd_load_i(r_load_rd), // Load insn in WB stage .load_wb_i(d_mem_load), // Memory status .mem_access_i(r_mem_access), .mem_ack_i(dmem_ack_i), // Load / store still pending .load_pending_o(load_pending), .store_pending_o(store_pending), // Insert load result into pipeline .write_result_o(load_insert), // Stall pipeline due .stall_o(load_stall) ); // Operand forwarding altor32_dfu u_dfu ( // Input registers .ra_i(reg_ra_i), .rb_i(reg_rb_i), // Input register contents .ra_regval_i(reg_ra_value_i), .rb_regval_i(reg_rb_value_i), // Dest register (EXEC stage) .rd_ex_i(r_e_rd), // Dest register (WB stage) .rd_wb_i(wb_rd_i), // Load pending / target .load_pending_i(load_pending), .rd_load_i(r_load_rd), // Multiplier status .mult_lo_ex_i(1'b0), .mult_hi_ex_i(1'b0), .mult_lo_wb_i(1'b0), .mult_hi_wb_i(1'b0), // Multiplier result .result_mult_i(64'b0), // Result (EXEC) .result_ex_i(r_e_result), // Result (WB) .result_wb_i(wb_rd_value_i), // Resolved register values .result_ra_o(ra_value_resolved), .result_rb_o(rb_value_resolved), // Operands required forwarding .resolved_o(operand_resolved), // Stall due to failed resolve .stall_o(resolve_failed) ); //----------------------------------------------------------------- // Opcode decode //----------------------------------------------------------------- reg [7:0] inst_r; reg [7:0] alu_op_r; reg [1:0] shift_op_r; reg [15:0] sfxx_op_r; reg [15:0] uint16_r; reg [31:0] uint32_r; reg [31:0] int32_r; reg [31:0] store_int32_r; reg [15:0] mxspr_uint16_r; reg [31:0] target_int26_r; reg [31:0] reg_ra_r; reg [31:0] reg_rb_r; reg [31:0] shift_rb_r; reg [31:0] shift_imm_r; always @ * begin // Instruction inst_r = {2'b00,opcode_i[31:26]}; // Sub instructions alu_op_r = {opcode_i[9:6],opcode_i[3:0]}; sfxx_op_r = {5'b00,opcode_i[31:21]} & `INST_OR32_SFMASK; shift_op_r = opcode_i[7:6]; // Branch target target_int26_r = sign_extend_imm26(opcode_i[25:0]); // Store immediate store_int32_r = sign_extend_imm16({opcode_i[25:21],opcode_i[10:0]}); // Signed & unsigned imm -> 32-bits uint16_r = opcode_i[15:0]; int32_r = sign_extend_imm16(opcode_i[15:0]); uint32_r = extend_imm16(opcode_i[15:0]); // Register values [ra/rb] reg_ra_r = ra_value_resolved; reg_rb_r = rb_value_resolved; // Shift ammount (from register[rb]) shift_rb_r = {26'b00,rb_value_resolved[5:0]}; // Shift ammount (from immediate) shift_imm_r = {26'b00,opcode_i[5:0]}; // MTSPR/MFSPR operand // NOTE: Use unresolved register value and stall pipeline if required. // This is to improve timing. mxspr_uint16_r = (reg_ra_value_i[15:0] | {5'b00000,opcode_i[10:0]}); end //----------------------------------------------------------------- // Instruction Decode //----------------------------------------------------------------- wire inst_add_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_ADD); // l.add wire inst_addc_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_ADDC); // l.addc wire inst_and_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_AND); // l.and wire inst_or_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_OR); // l.or wire inst_sll_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_SLL); // l.sll wire inst_sra_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_SRA); // l.sra wire inst_srl_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_SRL); // l.srl wire inst_sub_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_SUB); // l.sub wire inst_xor_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_XOR); // l.xor wire inst_mul_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_MUL); // l.mul wire inst_mulu_w = (inst_r == `INST_OR32_ALU) & (alu_op_r == `INST_OR32_MULU); // l.mulu wire inst_addi_w = (inst_r == `INST_OR32_ADDI); // l.addi wire inst_andi_w = (inst_r == `INST_OR32_ANDI); // l.andi wire inst_bf_w = (inst_r == `INST_OR32_BF); // l.bf wire inst_bnf_w = (inst_r == `INST_OR32_BNF); // l.bnf wire inst_j_w = (inst_r == `INST_OR32_J); // l.j wire inst_jal_w = (inst_r == `INST_OR32_JAL); // l.jal wire inst_jalr_w = (inst_r == `INST_OR32_JALR); // l.jalr wire inst_jr_w = (inst_r == `INST_OR32_JR); // l.jr wire inst_lbs_w = (inst_r == `INST_OR32_LBS); // l.lbs wire inst_lhs_w = (inst_r == `INST_OR32_LHS); // l.lhs wire inst_lws_w = (inst_r == `INST_OR32_LWS); // l.lws wire inst_lbz_w = (inst_r == `INST_OR32_LBZ); // l.lbz wire inst_lhz_w = (inst_r == `INST_OR32_LHZ); // l.lhz wire inst_lwz_w = (inst_r == `INST_OR32_LWZ); // l.lwz wire inst_mfspr_w = (inst_r == `INST_OR32_MFSPR); // l.mfspr wire inst_mtspr_w = (inst_r == `INST_OR32_MTSPR); // l.mtspr wire inst_movhi_w = (inst_r == `INST_OR32_MOVHI); // l.movhi wire inst_nop_w = (inst_r == `INST_OR32_NOP); // l.nop wire inst_ori_w = (inst_r == `INST_OR32_ORI); // l.ori wire inst_rfe_w = (inst_r == `INST_OR32_RFE); // l.rfe wire inst_sb_w = (inst_r == `INST_OR32_SB); // l.sb wire inst_sh_w = (inst_r == `INST_OR32_SH); // l.sh wire inst_sw_w = (inst_r == `INST_OR32_SW); // l.sw wire inst_slli_w = (inst_r == `INST_OR32_SHIFTI) & (shift_op_r == `INST_OR32_SLLI); // l.slli wire inst_srai_w = (inst_r == `INST_OR32_SHIFTI) & (shift_op_r == `INST_OR32_SRAI); // l.srai wire inst_srli_w = (inst_r == `INST_OR32_SHIFTI) & (shift_op_r == `INST_OR32_SRLI); // l.srli wire inst_xori_w = (inst_r == `INST_OR32_XORI); // l.xori wire inst_sfxx_w = (inst_r == `INST_OR32_SFXX); wire inst_sfxxi_w = (inst_r == `INST_OR32_SFXXI); wire inst_sfeq_w = (inst_sfxx_w || inst_sfxxi_w) & (sfxx_op_r == `INST_OR32_SFEQ); // l.sfeq wire inst_sfges_w = (inst_sfxx_w || inst_sfxxi_w) & (sfxx_op_r == `INST_OR32_SFGES); // l.sfges wire inst_sfgeu_w = (inst_sfxx_w || inst_sfxxi_w) & (sfxx_op_r == `INST_OR32_SFGEU); // l.sfgeu wire inst_sfgts_w = (inst_sfxx_w || inst_sfxxi_w) & (sfxx_op_r == `INST_OR32_SFGTS); // l.sfgts wire inst_sfgtu_w = (inst_sfxx_w || inst_sfxxi_w) & (sfxx_op_r == `INST_OR32_SFGTU); // l.sfgtu wire inst_sfles_w = (inst_sfxx_w || inst_sfxxi_w) & (sfxx_op_r == `INST_OR32_SFLES); // l.sfles wire inst_sfleu_w = (inst_sfxx_w || inst_sfxxi_w) & (sfxx_op_r == `INST_OR32_SFLEU); // l.sfleu wire inst_sflts_w = (inst_sfxx_w || inst_sfxxi_w) & (sfxx_op_r == `INST_OR32_SFLTS); // l.sflts wire inst_sfltu_w = (inst_sfxx_w || inst_sfxxi_w) & (sfxx_op_r == `INST_OR32_SFLTU); // l.sfltu wire inst_sfne_w = (inst_sfxx_w || inst_sfxxi_w) & (sfxx_op_r == `INST_OR32_SFNE); // l.sfne wire inst_sys_w = (inst_r == `INST_OR32_MISC) & (opcode_i[31:24] == `INST_OR32_SYS); // l.sys wire inst_trap_w = (inst_r == `INST_OR32_MISC) & (opcode_i[31:24] == `INST_OR32_TRAP); // l.trap //----------------------------------------------------------------- // Stall / Execute //----------------------------------------------------------------- reg execute_inst_r; reg stall_inst_r; always @ * begin execute_inst_r = 1'b1; stall_inst_r = 1'b0; // No opcode ready or branch delay slot if (~opcode_valid_i | r_pc_fetch) execute_inst_r = 1'b0; // Valid instruction, but load result / operand not ready else if (resolve_failed | load_stall | (operand_resolved & (inst_mfspr_w | inst_mtspr_w))) stall_inst_r = 1'b1; end //----------------------------------------------------------------- // Next PC //----------------------------------------------------------------- reg [31:0] next_pc_r; always @ * begin // Next expected PC (current PC + 4) next_pc_r = (opcode_pc_i + 4); end //----------------------------------------------------------------- // Next SR //----------------------------------------------------------------- reg [31:0] next_sr_r; reg compare_result_r; always @ * begin next_sr_r = r_sr; // Update SR.F if (alu_flag_update) next_sr_r[`OR32_SR_F] = compare_result_r; // Latch carry if updated if (alu_carry_update) next_sr_r[`OR32_SR_CY] = alu_carry_out; // If valid instruction, check if SR needs updating if (execute_inst_r & ~stall_inst_r) begin case (1'b1) inst_mtspr_w: begin case (mxspr_uint16_r) // SR - Supervision register `SPR_REG_SR: begin next_sr_r = reg_rb_r; // Don't store cache flush requests next_sr_r[`OR32_SR_ICACHE_FLUSH] = 1'b0; next_sr_r[`OR32_SR_DCACHE_FLUSH] = 1'b0; end default: ; endcase end inst_rfe_w: next_sr_r = r_esr; default: ; endcase end end //----------------------------------------------------------------- // Next EPC/ESR //----------------------------------------------------------------- reg [31:0] next_epc_r; reg [31:0] next_esr_r; always @ * begin next_epc_r = r_epc; next_esr_r = r_esr; case (1'b1) inst_mtspr_w: // l.mtspr begin case (mxspr_uint16_r) // EPCR - EPC Exception saved PC `SPR_REG_EPCR: next_epc_r = reg_rb_r; // ESR - Exception saved SR `SPR_REG_ESR: next_esr_r = reg_rb_r; endcase end default: ; endcase end //----------------------------------------------------------------- // ALU inputs //----------------------------------------------------------------- // ALU operation selection reg [3:0] alu_func_r; // ALU operands reg [31:0] alu_input_a_r; reg [31:0] alu_input_b_r; reg write_rd_r; always @ * begin alu_func_r = `ALU_NONE; alu_input_a_r = 32'b0; alu_input_b_r = 32'b0; write_rd_r = 1'b0; case (1'b1) inst_add_w: // l.add begin alu_func_r = `ALU_ADD; alu_input_a_r = reg_ra_r; alu_input_b_r = reg_rb_r; write_rd_r = 1'b1; end inst_addc_w: // l.addc begin alu_func_r = `ALU_ADDC; alu_input_a_r = reg_ra_r; alu_input_b_r = reg_rb_r; write_rd_r = 1'b1; end inst_and_w: // l.and begin alu_func_r = `ALU_AND; alu_input_a_r = reg_ra_r; alu_input_b_r = reg_rb_r; write_rd_r = 1'b1; end inst_or_w: // l.or begin alu_func_r = `ALU_OR; alu_input_a_r = reg_ra_r; alu_input_b_r = reg_rb_r; write_rd_r = 1'b1; end inst_sll_w: // l.sll begin alu_func_r = `ALU_SHIFTL; alu_input_a_r = reg_ra_r; alu_input_b_r = shift_rb_r; write_rd_r = 1'b1; end inst_sra_w: // l.sra begin alu_func_r = `ALU_SHIRTR_ARITH; alu_input_a_r = reg_ra_r; alu_input_b_r = shift_rb_r; write_rd_r = 1'b1; end inst_srl_w: // l.srl begin alu_func_r = `ALU_SHIFTR; alu_input_a_r = reg_ra_r; alu_input_b_r = shift_rb_r; write_rd_r = 1'b1; end inst_sub_w: // l.sub begin alu_func_r = `ALU_SUB; alu_input_a_r = reg_ra_r; alu_input_b_r = reg_rb_r; write_rd_r = 1'b1; end inst_xor_w: // l.xor begin alu_func_r = `ALU_XOR; alu_input_a_r = reg_ra_r; alu_input_b_r = reg_rb_r; write_rd_r = 1'b1; end inst_mul_w, // l.mul inst_mulu_w: // l.mulu begin write_rd_r = 1'b1; end inst_addi_w: // l.addi begin alu_func_r = `ALU_ADD; alu_input_a_r = reg_ra_r; alu_input_b_r = int32_r; write_rd_r = 1'b1; end inst_andi_w: // l.andi begin alu_func_r = `ALU_AND; alu_input_a_r = reg_ra_r; alu_input_b_r = uint32_r; write_rd_r = 1'b1; end inst_jal_w: // l.jal begin alu_input_a_r = next_pc_r; write_rd_r = 1'b1; end inst_jalr_w: // l.jalr begin alu_input_a_r = next_pc_r; write_rd_r = 1'b1; end inst_mfspr_w: // l.mfspr begin case (mxspr_uint16_r) // SR - Supervision register `SPR_REG_SR: begin alu_input_a_r = next_sr_r; write_rd_r = 1'b1; end // EPCR - EPC Exception saved PC `SPR_REG_EPCR: begin alu_input_a_r = r_epc; write_rd_r = 1'b1; end // ESR - Exception saved SR `SPR_REG_ESR: begin alu_input_a_r = r_esr; write_rd_r = 1'b1; end default: ; endcase end inst_movhi_w: // l.movhi begin alu_input_a_r = {uint16_r,16'h0000}; write_rd_r = 1'b1; end inst_ori_w: // l.ori begin alu_func_r = `ALU_OR; alu_input_a_r = reg_ra_r; alu_input_b_r = uint32_r; write_rd_r = 1'b1; end inst_slli_w: // l.slli begin alu_func_r = `ALU_SHIFTL; alu_input_a_r = reg_ra_r; alu_input_b_r = shift_imm_r; write_rd_r = 1'b1; end inst_srai_w: // l.srai begin alu_func_r = `ALU_SHIRTR_ARITH; alu_input_a_r = reg_ra_r; alu_input_b_r = shift_imm_r; write_rd_r = 1'b1; end inst_srli_w: // l.srli begin alu_func_r = `ALU_SHIFTR; alu_input_a_r = reg_ra_r; alu_input_b_r = shift_imm_r; write_rd_r = 1'b1; end // l.lbs l.lhs l.lws l.lbz l.lhz l.lwz inst_lbs_w, inst_lhs_w, inst_lws_w, inst_lbz_w, inst_lhz_w, inst_lwz_w: write_rd_r = 1'b1; // l.sf*i inst_sfxxi_w: begin alu_func_r = `ALU_COMPARE; alu_input_a_r = reg_ra_r; alu_input_b_r = int32_r; end // l.sf* inst_sfxx_w: begin alu_func_r = `ALU_COMPARE; alu_input_a_r = reg_ra_r; alu_input_b_r = reg_rb_r; end inst_xori_w: // l.xori begin alu_func_r = `ALU_XOR; alu_input_a_r = reg_ra_r; alu_input_b_r = int32_r; write_rd_r = 1'b1; end default: ; endcase end //----------------------------------------------------------------- // Comparisons (from ALU outputs) //----------------------------------------------------------------- reg inst_sfges_r; reg inst_sfgeu_r; reg inst_sfgts_r; reg inst_sfgtu_r; reg inst_sfles_r; reg inst_sfleu_r; reg inst_sflts_r; reg inst_sfltu_r; reg inst_sfne_r; reg inst_sfges_q; reg inst_sfgeu_q; reg inst_sfgts_q; reg inst_sfgtu_q; reg inst_sfles_q; reg inst_sfleu_q; reg inst_sflts_q; reg inst_sfltu_q; reg inst_sfne_q; always @ * begin inst_sfges_r = 1'b0; inst_sfgeu_r = 1'b0; inst_sfgts_r = 1'b0; inst_sfgtu_r = 1'b0; inst_sfles_r = 1'b0; inst_sfleu_r = 1'b0; inst_sflts_r = 1'b0; inst_sfltu_r = 1'b0; inst_sfne_r = 1'b0; // Valid instruction if (execute_inst_r && ~stall_inst_r) begin case (1'b1) inst_sfges_w: // l.sfges inst_sfges_r = 1'b1; inst_sfgeu_w: // l.sfgeu inst_sfgeu_r = 1'b1; inst_sfgts_w: // l.sfgts inst_sfgts_r = 1'b1; inst_sfgtu_w: // l.sfgtu inst_sfgtu_r = 1'b1; inst_sfles_w: // l.sfles inst_sfles_r = 1'b1; inst_sfleu_w: // l.sfleu inst_sfleu_r = 1'b1; inst_sflts_w: // l.sflts inst_sflts_r = 1'b1; inst_sfltu_w: // l.sfltu inst_sfltu_r = 1'b1; inst_sfne_w: // l.sfne inst_sfne_r = 1'b1; default: ; endcase end end always @ (posedge clk_i or posedge rst_i) begin if (rst_i == 1'b1) begin inst_sfges_q <= 1'b0; inst_sfgeu_q <= 1'b0; inst_sfgts_q <= 1'b0; inst_sfgtu_q <= 1'b0; inst_sfles_q <= 1'b0; inst_sfleu_q <= 1'b0; inst_sflts_q <= 1'b0; inst_sfltu_q <= 1'b0; inst_sfne_q <= 1'b0; end else begin inst_sfges_q <= inst_sfges_r; inst_sfgeu_q <= inst_sfgeu_r; inst_sfgts_q <= inst_sfgts_r; inst_sfgtu_q <= inst_sfgtu_r; inst_sfles_q <= inst_sfles_r; inst_sfleu_q <= inst_sfleu_r; inst_sflts_q <= inst_sflts_r; inst_sfltu_q <= inst_sfltu_r; inst_sfne_q <= inst_sfne_r; end end always @ * begin case (1'b1) inst_sfges_q: // l.sfges compare_result_r = compare_gts_w | compare_equal_w; inst_sfgeu_q: // l.sfgeu compare_result_r = compare_gt_w | compare_equal_w; inst_sfgts_q: // l.sfgts compare_result_r = compare_gts_w; inst_sfgtu_q: // l.sfgtu compare_result_r = compare_gt_w; inst_sfles_q: // l.sfles compare_result_r = compare_lts_w | compare_equal_w; inst_sfleu_q: // l.sfleu compare_result_r = compare_lt_w | compare_equal_w; inst_sflts_q: // l.sflts compare_result_r = compare_lts_w; inst_sfltu_q: // l.sfltu compare_result_r = compare_lt_w; inst_sfne_q: // l.sfne compare_result_r = ~compare_equal_w; default: // l.sfeq compare_result_r = compare_equal_w; endcase end //----------------------------------------------------------------- // Load/Store operation? //----------------------------------------------------------------- reg load_inst_r; reg store_inst_r; reg [31:0] mem_addr_r; always @ * begin load_inst_r = inst_lbs_w | inst_lhs_w | inst_lws_w | inst_lbz_w | inst_lhz_w | inst_lwz_w; store_inst_r = inst_sb_w | inst_sh_w | inst_sw_w; // Memory address is relative to RA mem_addr_r = reg_ra_r + (store_inst_r ? store_int32_r : int32_r); end //----------------------------------------------------------------- // Branches //----------------------------------------------------------------- reg branch_r; reg branch_link_r; reg [31:0] branch_target_r; reg branch_except_r; always @ * begin branch_r = 1'b0; branch_link_r = 1'b0; branch_except_r = 1'b0; // Default branch target is relative to current PC branch_target_r = (opcode_pc_i + {target_int26_r[29:0],2'b00}); case (1'b1) inst_bf_w: // l.bf branch_r = next_sr_r[`OR32_SR_F]; inst_bnf_w: // l.bnf branch_r = ~next_sr_r[`OR32_SR_F]; inst_j_w: // l.j branch_r = 1'b1; inst_jal_w: // l.jal begin // Write to REG_9_LR branch_link_r = 1'b1; branch_r = 1'b1; end inst_jalr_w: // l.jalr begin // Write to REG_9_LR branch_link_r = 1'b1; branch_r = 1'b1; branch_target_r = reg_rb_r; end inst_jr_w: // l.jr begin branch_r = 1'b1; branch_target_r = reg_rb_r; end inst_rfe_w: // l.rfe begin branch_r = 1'b1; branch_target_r = r_epc; end inst_sys_w: // l.sys begin branch_r = 1'b1; branch_except_r = 1'b1; branch_target_r = ISR_VECTOR + `VECTOR_SYSCALL; end inst_trap_w: // l.trap begin branch_r = 1'b1; branch_except_r = 1'b1; branch_target_r = ISR_VECTOR + `VECTOR_TRAP; end default: ; endcase end //----------------------------------------------------------------- // Invalid instruction //----------------------------------------------------------------- reg invalid_inst_r; always @ * begin case (1'b1) inst_add_w, inst_addc_w, inst_and_w, inst_or_w, inst_sll_w, inst_sra_w, inst_srl_w, inst_sub_w, inst_xor_w, inst_addi_w, inst_andi_w, inst_bf_w, inst_bnf_w, inst_j_w, inst_jal_w, inst_jalr_w, inst_jr_w, inst_lbs_w, inst_lhs_w, inst_lws_w, inst_lbz_w, inst_lhz_w, inst_lwz_w, inst_mfspr_w, inst_mtspr_w, inst_movhi_w, inst_nop_w, inst_ori_w, inst_rfe_w, inst_sb_w, inst_sh_w, inst_sw_w, inst_xori_w, inst_slli_w, inst_srai_w, inst_srli_w, inst_sfeq_w, inst_sfges_w, inst_sfgeu_w, inst_sfgts_w, inst_sfgtu_w, inst_sfles_w, inst_sfleu_w, inst_sflts_w, inst_sfltu_w, inst_sfne_w, inst_sys_w, inst_trap_w: invalid_inst_r = 1'b0; default: invalid_inst_r = 1'b1; endcase end //----------------------------------------------------------------- // Execute: ALU control //----------------------------------------------------------------- always @ (posedge clk_i or posedge rst_i) begin if (rst_i == 1'b1) begin r_e_alu_func <= `ALU_NONE; r_e_alu_a <= 32'h00000000; r_e_alu_b <= 32'h00000000; r_e_rd <= 5'b00000; end else begin //--------------------------------------------------------------- // Instruction not ready //--------------------------------------------------------------- if (~execute_inst_r | stall_inst_r) begin // Insert load result? if (load_insert) begin // Feed load result into pipeline r_e_alu_func <= `ALU_NONE; r_e_alu_a <= load_result; r_e_alu_b <= 32'b0; r_e_rd <= r_load_rd; end else begin // No ALU operation (output == input_a) r_e_alu_func <= `ALU_NONE; r_e_alu_a <= 32'b0; r_e_alu_b <= 32'b0; r_e_rd <= 5'b0; end end //--------------------------------------------------------------- // Valid instruction //--------------------------------------------------------------- else begin // Update ALU input flops r_e_alu_func <= alu_func_r; r_e_alu_a <= alu_input_a_r; r_e_alu_b <= alu_input_b_r; // Branch and link (Rd = LR/R9) if (branch_link_r) r_e_rd <= 5'd9; // Instruction with register writeback else if (write_rd_r) r_e_rd <= reg_rd_i; else r_e_rd <= 5'b0; end end end //----------------------------------------------------------------- // Execute: Update executed PC / opcode //----------------------------------------------------------------- always @ (posedge clk_i or posedge rst_i) begin if (rst_i == 1'b1) begin r_e_opcode <= 32'h00000000; r_e_opcode_pc <= 32'h00000000; end else begin // Instruction not ready if (~execute_inst_r | stall_inst_r) begin // Store bubble opcode r_e_opcode <= `OPCODE_INST_BUBBLE; r_e_opcode_pc <= opcode_pc_i; end // Valid instruction else begin // Store opcode r_e_opcode <= opcode_i; r_e_opcode_pc <= opcode_pc_i; `ifdef CONF_CORE_TRACE $display("%08x: Execute 0x%08x", opcode_pc_i, opcode_i); $display(" rA[%d] = 0x%08x", reg_ra_i, reg_ra_r); $display(" rB[%d] = 0x%08x", reg_rb_i, reg_rb_r); `endif end end end //----------------------------------------------------------------- // Execute: Branch / exceptions //----------------------------------------------------------------- always @ (posedge clk_i or posedge rst_i) begin if (rst_i == 1'b1) begin r_pc_branch <= 32'h00000000; r_pc_fetch <= 1'b0; // Status registers r_epc <= 32'h00000000; r_sr <= 32'h00000000; r_esr <= 32'h00000000; fault_o <= 1'b0; r_nmi <= 1'b0; end else begin // Record NMI in-case it can't be processed this cycle if (nmi_i) r_nmi <= 1'b1; // Reset branch request r_pc_fetch <= 1'b0; // Update SR r_sr <= next_sr_r; // Instruction ready if (execute_inst_r & ~stall_inst_r) begin // Exception: Instruction opcode not valid / supported, invalid PC if (invalid_inst_r || (opcode_pc_i[1:0] != 2'b00)) begin // Save PC of next instruction r_epc <= next_pc_r; r_esr <= next_sr_r; // Disable further interrupts r_sr <= 32'b0; // Set PC to exception vector if (invalid_inst_r) r_pc_branch <= ISR_VECTOR + `VECTOR_ILLEGAL_INST; else r_pc_branch <= ISR_VECTOR + `VECTOR_BUS_ERROR; r_pc_fetch <= 1'b1; fault_o <= 1'b1; end // Exception: Syscall / Break else if (branch_except_r) begin // Save PC of next instruction r_epc <= next_pc_r; r_esr <= next_sr_r; // Disable further interrupts r_sr <= 32'b0; // Set PC to exception vector r_pc_branch <= branch_target_r; r_pc_fetch <= 1'b1; `ifdef CONF_CORE_DEBUG $display(" Exception 0x%08x", branch_target_r); `endif end // Non-maskable interrupt else if (nmi_i | r_nmi) begin r_nmi <= 1'b0; // Save PC of next instruction if (branch_r) r_epc <= branch_target_r; // Next expected PC (current PC + 4) else r_epc <= next_pc_r; r_esr <= next_sr_r; // Disable further interrupts r_sr <= 32'b0; // Set PC to exception vector r_pc_branch <= ISR_VECTOR + `VECTOR_NMI; r_pc_fetch <= 1'b1; `ifdef CONF_CORE_DEBUG $display(" NMI 0x%08x", ISR_VECTOR + `VECTOR_NMI); `endif end // External interrupt else if (intr_i && next_sr_r[`OR32_SR_IEE]) begin // Save PC of next instruction & SR if (branch_r) r_epc <= branch_target_r; // Next expected PC (current PC + 4) else r_epc <= next_pc_r; r_esr <= next_sr_r; // Disable further interrupts r_sr <= 32'b0; // Set PC to external interrupt vector r_pc_branch <= ISR_VECTOR + `VECTOR_EXTINT; r_pc_fetch <= 1'b1; `ifdef CONF_CORE_DEBUG $display(" External Interrupt 0x%08x", ISR_VECTOR + `VECTOR_EXTINT); `endif end // Branch (l.bf, l.bnf, l.j, l.jal, l.jr, l.jalr, l.rfe) else if (branch_r) begin // Perform branch r_pc_branch <= branch_target_r; r_pc_fetch <= 1'b1; `ifdef CONF_CORE_DEBUG $display(" Branch to 0x%08x", branch_target_r); `endif end // Non branch else begin // Update EPC / ESR which may have been updated // by an MTSPR write r_epc <= next_epc_r; r_esr <= next_esr_r; end end end end //----------------------------------------------------------------- // Execute: Memory operations //----------------------------------------------------------------- always @ (posedge clk_i or posedge rst_i) begin if (rst_i == 1'b1) begin // Data memory dmem_addr_o <= 32'h00000000; dmem_data_out_o <= 32'h00000000; dmem_we_o <= 1'b0; dmem_sel_o <= 4'b0000; dmem_stb_o <= 1'b0; dmem_cyc_o <= 1'b0; r_mem_load <= 1'b0; r_mem_store <= 1'b0; r_mem_access <= 1'b0; r_load_rd <= 5'b00000; r_load_inst <= 8'h00; r_load_offset <= 2'b00; d_mem_load <= 1'b0; end else begin // If memory access accepted by slave if (~dmem_stall_i) dmem_stb_o <= 1'b0; if (dmem_ack_i) dmem_cyc_o <= 1'b0; r_mem_access <= 1'b0; d_mem_load <= r_mem_access & r_mem_load; // Pending accesses r_mem_load <= load_pending; r_mem_store <= store_pending; //--------------------------------------------------------------- // Valid instruction //--------------------------------------------------------------- if (execute_inst_r & ~stall_inst_r) begin // Branch and link (Rd = LR/R9) if (branch_link_r) begin // Load outstanding, check if result target is being // overwritten (to avoid WAR hazard) if (r_load_rd == 5'd9) // Ditch load result when it arrives r_load_rd <= 5'b00000; end // Instruction with register writeback else if (write_rd_r) begin // Load outstanding, check if result target is being // overwritten (to avoid WAR hazard) if (reg_rd_i == r_load_rd && ~load_inst_r) // Ditch load result when it arrives r_load_rd <= 5'b00000; end case (1'b1) // l.lbs l.lhs l.lws l.lbz l.lhz l.lwz load_inst_r: begin dmem_addr_o <= mem_addr_r; dmem_data_out_o <= 32'h00000000; dmem_sel_o <= 4'b1111; dmem_we_o <= 1'b0; dmem_stb_o <= 1'b1; dmem_cyc_o <= 1'b1; // Mark load as pending r_mem_load <= 1'b1; r_mem_access <= 1'b1; // Record target register r_load_rd <= reg_rd_i; r_load_inst <= inst_r; r_load_offset <= mem_addr_r[1:0]; `ifdef CONF_CORE_DEBUG $display(" Load from 0x%08x to R%d", mem_addr_r, reg_rd_i); `endif end inst_sb_w: // l.sb begin dmem_addr_o <= mem_addr_r; r_mem_access <= 1'b1; case (mem_addr_r[1:0]) 2'b00 : begin dmem_data_out_o <= {reg_rb_r[7:0],24'h000000}; dmem_sel_o <= 4'b1000; dmem_we_o <= 1'b1; dmem_stb_o <= 1'b1; dmem_cyc_o <= 1'b1; r_mem_store <= 1'b1; end 2'b01 : begin dmem_data_out_o <= {{8'h00,reg_rb_r[7:0]},16'h0000}; dmem_sel_o <= 4'b0100; dmem_we_o <= 1'b1; dmem_stb_o <= 1'b1; dmem_cyc_o <= 1'b1; r_mem_store <= 1'b1; end 2'b10 : begin dmem_data_out_o <= {{16'h0000,reg_rb_r[7:0]},8'h00}; dmem_sel_o <= 4'b0010; dmem_we_o <= 1'b1; dmem_stb_o <= 1'b1; dmem_cyc_o <= 1'b1; r_mem_store <= 1'b1; end 2'b11 : begin dmem_data_out_o <= {24'h000000,reg_rb_r[7:0]}; dmem_sel_o <= 4'b0001; dmem_we_o <= 1'b1; dmem_stb_o <= 1'b1; dmem_cyc_o <= 1'b1; r_mem_store <= 1'b1; end default : ; endcase end inst_sh_w: // l.sh begin dmem_addr_o <= mem_addr_r; r_mem_access <= 1'b1; case (mem_addr_r[1:0]) 2'b00 : begin dmem_data_out_o <= {reg_rb_r[15:0],16'h0000}; dmem_sel_o <= 4'b1100; dmem_we_o <= 1'b1; dmem_stb_o <= 1'b1; dmem_cyc_o <= 1'b1; r_mem_store <= 1'b1; end 2'b10 : begin dmem_data_out_o <= {16'h0000,reg_rb_r[15:0]}; dmem_sel_o <= 4'b0011; dmem_we_o <= 1'b1; dmem_stb_o <= 1'b1; dmem_cyc_o <= 1'b1; r_mem_store <= 1'b1; end default : ; endcase end inst_sw_w: // l.sw begin dmem_addr_o <= mem_addr_r; dmem_data_out_o <= reg_rb_r; dmem_sel_o <= 4'b1111; dmem_we_o <= 1'b1; dmem_stb_o <= 1'b1; dmem_cyc_o <= 1'b1; r_mem_access <= 1'b1; r_mem_store <= 1'b1; `ifdef CONF_CORE_DEBUG $display(" Store R%d to 0x%08x = 0x%08x", reg_rb_i, {mem_addr_r[31:2],2'b00}, reg_rb_r); `endif end default: ; endcase end end end //----------------------------------------------------------------- // Execute: Misc operations //----------------------------------------------------------------- always @ (posedge clk_i or posedge rst_i) begin if (rst_i == 1'b1) begin break_o <= 1'b0; icache_flush_o <= 1'b0; dcache_flush_o <= 1'b0; end else begin break_o <= 1'b0; icache_flush_o <= 1'b0; dcache_flush_o <= 1'b0; //--------------------------------------------------------------- // Valid instruction //--------------------------------------------------------------- if (execute_inst_r & ~stall_inst_r) begin case (1'b1) inst_mtspr_w: // l.mtspr begin case (mxspr_uint16_r) // SR - Supervision register `SPR_REG_SR: begin // Cache flush request? icache_flush_o <= reg_rb_r[`OR32_SR_ICACHE_FLUSH]; dcache_flush_o <= reg_rb_r[`OR32_SR_DCACHE_FLUSH]; end endcase end inst_trap_w: // l.trap break_o <= 1'b1; default: ; endcase end end end //----------------------------------------------------------------- // Execute: NOP (simulation) operations //----------------------------------------------------------------- `ifdef SIMULATION always @ (posedge clk_i or posedge rst_i) begin if (rst_i == 1'b1) begin `ifdef SIM_EXT_PUTC r_putc <= 8'b0; `endif end else begin `ifdef SIM_EXT_PUTC r_putc <= 8'b0; `endif //--------------------------------------------------------------- // Valid instruction //--------------------------------------------------------------- if (execute_inst_r & ~stall_inst_r) begin case (1'b1) inst_nop_w: // l.nop begin case (uint16_r) // NOP_PUTC 16'h0004: begin `ifdef SIM_EXT_PUTC r_putc <= reg_ra_r[7:0]; `else $write("%c", reg_ra_r[7:0]); `endif end // NOP 16'h0000: ; endcase end default: ; endcase end end end `endif //------------------------------------------------------------------- // Assignments //------------------------------------------------------------------- assign branch_pc_o = r_pc_branch; assign branch_o = r_pc_fetch; assign stall_o = stall_inst_r; assign opcode_o = r_e_opcode; assign reg_rd_o = r_e_rd; assign reg_rd_value_o = r_e_result; assign mult_o = 1'b0; assign mult_res_o = 32'b0; //------------------------------------------------------------------- // Hooks for debug //------------------------------------------------------------------- `ifdef verilator function [31:0] get_opcode_ex; // verilator public get_opcode_ex = r_e_opcode; endfunction function [31:0] get_pc_ex; // verilator public get_pc_ex = r_e_opcode_pc; endfunction function [7:0] get_putc; // verilator public `ifdef SIM_EXT_PUTC get_putc = r_putc; `else get_putc = 8'b0; `endif endfunction function [0:0] get_reg_valid; // verilator public get_reg_valid = ~(resolve_failed | load_stall | ~opcode_valid_i); endfunction function [4:0] get_reg_ra; // verilator public get_reg_ra = reg_ra_i; endfunction function [31:0] get_reg_ra_value; // verilator public get_reg_ra_value = ra_value_resolved; endfunction function [4:0] get_reg_rb; // verilator public get_reg_rb = reg_rb_i; endfunction function [31:0] get_reg_rb_value; // verilator public get_reg_rb_value = rb_value_resolved; endfunction `endif endmodule
Go to most recent revision | Compare with Previous | Blame | View Log