OpenCores
URL https://opencores.org/ocsvn/altor32/altor32/trunk

Subversion Repositories altor32

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /altor32/trunk
    from Rev 30 to Rev 31
    Reverse comparison

Rev 30 → Rev 31

/rtl/cpu/altor32_defs.v
104,8 → 104,8
//-----------------------------------------------------------------
// Set Flag Instructions
//-----------------------------------------------------------------
`define INST_OR32_SFXX 8'h2F
`define INST_OR32_SFXXI 8'h39
`define INST_OR32_SFXX 8'h39
`define INST_OR32_SFXXI 8'h2F
`define INST_OR32_SFEQ 16'h0720
`define INST_OR32_SFEQI 16'h05E0
`define INST_OR32_SFGES 16'h072B
/rtl/cpu/altor32_exec.v
188,6 → 188,11
// Delayed NMI
reg r_nmi;
 
// SIM PUTC
`ifdef SIM_EXT_PUTC
reg [7:0] r_putc;
`endif
 
//-----------------------------------------------------------------
// Instantiation
//-----------------------------------------------------------------
305,1043 → 310,1277
.stall_o(resolve_failed)
);
 
//-------------------------------------------------------------------
// Execute: Execute opcode
//-------------------------------------------------------------------
//-----------------------------------------------------------------
// 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;
 
// Execute stage blocking assignment vars
reg [7:0] v_inst;
reg [4:0] v_rd;
reg [7:0] v_alu_op;
reg [1:0] v_shift_op;
reg [15:0] v_sfxx_op;
reg [15:0] v_imm;
reg [31:0] v_imm_uint32;
reg [31:0] v_imm_int32;
reg [31:0] v_store_imm;
reg [15:0] v_mxspr_imm;
reg [31:0] v_target;
reg [31:0] v_reg_ra;
reg [31:0] v_reg_rb;
reg [31:0] v_pc;
reg [31:0] v_offset;
reg [31:0] v_shift_val;
reg [31:0] v_shift_imm;
reg [31:0] v_vector;
reg [31:0] v_sr;
reg [31:0] v_mem_addr;
reg [31:0] v_mem_data_in;
reg v_exception;
reg v_branch;
reg v_jmp;
reg v_write_rd;
reg v_store_pending;
reg v_load_pending;
reg v_inst_load;
reg v_inst_store;
reg v_stall;
reg v_no_intr;
reg v_opcode_valid;
reg v_check_load_rd;
 
always @ (posedge clk_i or posedge rst_i)
always @ *
begin
if (rst_i == 1'b1)
begin
r_pc_branch <= 32'h00000000;
r_pc_fetch <= 1'b0;
r_stall <= 1'b0;
// Instruction
inst_r = {2'b00,opcode_i[31:26]};
 
// Status registers
r_epc <= 32'h00000000;
r_sr <= 32'h00000000;
r_esr <= 32'h00000000;
r_e_rd <= 5'b00000;
// Sub instructions
alu_op_r = {opcode_i[9:6],opcode_i[3:0]};
sfxx_op_r = {5'b00,opcode_i[31:21]};
shift_op_r = opcode_i[7:6];
 
// Default to no ALU operation
r_e_alu_func <= `ALU_NONE;
r_e_alu_a <= 32'h00000000;
r_e_alu_b <= 32'h00000000;
r_e_opcode <= 32'h00000000;
r_e_opcode_pc <= 32'h00000000;
// Branch target
target_int26_r = sign_extend_imm26(opcode_i[25:0]);
 
// Data memory
dmem_addr_o <= 32'h00000000;
dmem_data_out_o <= 32'h00000000;
dmem_rd_o <= 1'b0;
dmem_wr_o <= 4'b0000;
// Store immediate
store_int32_r = sign_extend_imm16({opcode_i[25:21],opcode_i[10:0]});
 
fault_o <= 1'b0;
break_o <= 1'b0;
// 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]);
 
r_nmi <= 1'b0;
icache_flush_o <= 1'b0;
dcache_flush_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;
// Register values [ra/rb]
reg_ra_r = ra_value_resolved;
reg_rb_r = rb_value_resolved;
 
d_mem_load <= 1'b0;
end
else
begin
// Shift ammount (from register[rb])
shift_rb_r = {26'b00,rb_value_resolved[5:0]};
 
// If memory access accepted by slave
if (dmem_accept_i)
begin
dmem_rd_o <= 1'b0;
dmem_wr_o <= 4'b0000;
end
r_mem_access <= 1'b0;
break_o <= 1'b0;
icache_flush_o <= 1'b0;
dcache_flush_o <= 1'b0;
// Shift ammount (from immediate)
shift_imm_r = {26'b00,opcode_i[5:0]};
 
// 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;
// MTSPR/MFSPR operand
mxspr_uint16_r = (ra_value_resolved[15:0] | {5'b00000,opcode_i[10:0]});
end
 
v_exception = 1'b0;
v_vector = 32'h00000000;
v_branch = 1'b0;
v_jmp = 1'b0;
v_write_rd = 1'b0;
v_sr = r_sr;
v_stall = 1'b0;
v_no_intr = 1'b0;
//-----------------------------------------------------------------
// 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
 
d_mem_load <= r_mem_access & r_mem_load;
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
 
//---------------------------------------------------------------
// Opcode
//---------------------------------------------------------------
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
 
// Instruction not ready
if (!opcode_valid_i)
begin
v_opcode_valid = 1'b0;
`ifdef CONF_CORE_DEBUG_BUBBLE
$display("%08x: Execute - Instruction not ready", opcode_pc_i);
`endif
end
// Branch request, always drop the next instruction
else if (r_pc_fetch)
begin
v_opcode_valid = 1'b0;
`ifdef CONF_CORE_DEBUG
$display("%08x: Exec - Branch pending, skip instruction (%x)", opcode_pc_i, opcode_i);
`endif
end
// Valid instruction ready
else
begin
v_mem_data_in = opcode_i;
v_opcode_valid = 1'b1;
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
 
`ifdef CONF_CORE_FAULT_ON_OPCODE0
// This is a valid opcode (branch to same instruction),
// but rare and useful for catching pipeline errors
if (v_mem_data_in == 32'h00000000)
fault_o <= 1'b1;
`endif
end
wire inst_xori_w = (inst_r == `INST_OR32_XORI); // l.xori
 
//---------------------------------------------------------------
// Decode opcode
//---------------------------------------------------------------
v_alu_op = {v_mem_data_in[9:6],v_mem_data_in[3:0]};
v_sfxx_op = {5'b00,v_mem_data_in[31:21]};
v_shift_op = v_mem_data_in[7:6];
v_target = sign_extend_imm26(v_mem_data_in[25:0]);
v_store_imm = sign_extend_imm16({v_mem_data_in[25:21],v_mem_data_in[10:0]});
wire inst_sfxx_w = (inst_r == `INST_OR32_SFXX);
wire inst_sfxxi_w = (inst_r == `INST_OR32_SFXXI);
 
// Signed & unsigned imm -> 32-bits
v_imm = v_mem_data_in[15:0];
v_imm_int32 = sign_extend_imm16(v_imm);
v_imm_uint32 = extend_imm16(v_imm);
wire inst_sfeq_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFEQ); // l.sfeq
wire inst_sfges_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFGES); // l.sfges
 
// Load register[ra]
v_reg_ra = ra_value_resolved;
wire inst_sfgeu_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFGEU); // l.sfgeu
wire inst_sfgts_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFGTS); // l.sfgts
wire inst_sfgtu_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFGTU); // l.sfgtu
wire inst_sfles_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFLES); // l.sfles
wire inst_sfleu_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFLEU); // l.sfleu
wire inst_sflts_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFLTS); // l.sflts
wire inst_sfltu_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFLTU); // l.sfltu
wire inst_sfne_w = (inst_r == `INST_OR32_SFXX) & (sfxx_op_r == `INST_OR32_SFNE); // l.sfne
 
// Load register[rb]
v_reg_rb = rb_value_resolved;
// Default to no ALU operation (output == input_a)
r_e_alu_func <= `ALU_NONE;
r_e_alu_a <= 32'h00000000;
// Default target is R[d]
v_rd = reg_rd_i;
//---------------------------------------------------------------
// Outstanding memory access
//---------------------------------------------------------------
wire inst_sfeqi_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFEQI); // l.sfeqi
wire inst_sfgesi_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFGESI); // l.sfgesi
wire inst_sfgeui_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFGEUI); // l.sfgeui
wire inst_sfgtsi_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFGTSI); // l.sfgtsi
wire inst_sfgtui_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFGTUI); // l.sfgtui
wire inst_sflesi_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFLESI); // l.sflesi
 
// Pending accesses
v_load_pending = load_pending;
v_store_pending = store_pending;
v_check_load_rd = 1'b1;
// Stall pipeline due to load / store
if (v_opcode_valid & load_stall)
begin
v_stall = 1'b1;
v_opcode_valid = 1'b0;
end
wire inst_sfleui_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFLEUI); // l.sfleui
wire inst_sfltsi_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFLTSI); // l.sfltsi
wire inst_sfltui_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFLTUI); // l.sfltui
wire inst_sfnei_w = (inst_r == `INST_OR32_SFXXI) & (sfxx_op_r == `INST_OR32_SFNEI); // l.sfnei
 
// Insert load result into pipeline?
if (load_insert)
begin
// Feed load result into pipeline
r_e_alu_func <= `ALU_NONE;
r_e_alu_a <= load_result;
v_rd = r_load_rd;
v_write_rd = 1'b1;
end
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
 
//---------------------------------------------------------------
// Invalid PC detection
//---------------------------------------------------------------
// Detect incorrect program counter and cause FAULT
if (opcode_valid_i && (opcode_pc_i[1:0] != 2'b00))
begin
fault_o <= 1'b1;
v_opcode_valid = 1'b0;
v_exception = 1'b1;
v_vector = ISR_VECTOR + `VECTOR_BUS_ERROR;
end
//---------------------------------------------------------------
// Failed operand resolve?
//---------------------------------------------------------------
if (opcode_valid_i & resolve_failed)
begin
`ifdef CONF_CORE_DEBUG
$display("%08x: Operand resolve failed RA=%d, RB=%d", opcode_pc_i, reg_ra_i, reg_rb_i);
`endif
// Stall!
v_opcode_valid = 1'b0;
v_stall = 1'b1;
end
//---------------------------------------------------------------
// Final instruction decoding
//---------------------------------------------------------------
// Insert bubble into the pipeline?
if (!v_opcode_valid)
begin
v_mem_data_in = `OPCODE_INST_BUBBLE;
v_check_load_rd = 1'b0;
end
//-----------------------------------------------------------------
// Stall / Execute
//-----------------------------------------------------------------
reg execute_inst_r;
reg stall_inst_r;
 
// Store opcode (after possible bubble generation)
r_e_opcode <= v_mem_data_in;
r_e_opcode_pc <= opcode_pc_i;
always @ *
begin
execute_inst_r = 1'b1;
stall_inst_r = 1'b0;
 
// Decode instruction
v_inst = {2'b00,v_mem_data_in[31:26]};
// 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)
stall_inst_r = 1'b1;
end
 
// Shift ammount (from register[rb])
v_shift_val = {26'b00,v_reg_rb[5:0]};
//-----------------------------------------------------------------
// Next PC
//-----------------------------------------------------------------
reg [31:0] next_pc_r;
 
// Shift ammount (from immediate)
v_shift_imm = {26'b00,v_imm[5:0]};
always @ *
begin
// Next expected PC (current PC + 4)
next_pc_r = (opcode_pc_i + 4);
end
 
// MTSPR/MFSPR operand
v_mxspr_imm = (v_reg_ra[15:0] | {5'b00000,v_mem_data_in[10:0]});
//-----------------------------------------------------------------
// Next SR
//-----------------------------------------------------------------
reg [31:0] next_sr_r;
reg compare_result_r;
always @ *
begin
next_sr_r = r_sr;
 
// Next expected PC (current PC + 4)
v_pc = (opcode_pc_i + 4);
// Latch carry if updated
if (alu_carry_update)
v_sr[`OR32_SR_CY] = alu_carry_out;
// Latch carry if updated
if (alu_carry_update)
next_sr_r[`OR32_SR_CY] = alu_carry_out;
 
`ifdef CONF_CORE_TRACE
if (v_opcode_valid)
begin
$display("%08x: Execute 0x%08x", opcode_pc_i, v_mem_data_in);
$display(" rA[%d] = 0x%08x", reg_ra_i, v_reg_ra);
$display(" rB[%d] = 0x%08x", reg_rb_i, v_reg_rb);
end
`endif
// 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;
 
//---------------------------------------------------------------
// Execute instruction
//---------------------------------------------------------------
case (v_inst)
`INST_OR32_BUBBLE :
begin
// Do not allow external interrupts whilst executing a bubble
// as this will result in pipeline issues.
v_no_intr = 1'b1;
end
`INST_OR32_ALU :
begin
case (v_alu_op)
`INST_OR32_ADD: // l.add
begin
r_e_alu_func <= `ALU_ADD;
r_e_alu_a <= v_reg_ra;
r_e_alu_b <= v_reg_rb;
v_write_rd = 1'b1;
end
`INST_OR32_ADDC: // l.addc
begin
r_e_alu_func <= `ALU_ADDC;
r_e_alu_a <= v_reg_ra;
r_e_alu_b <= v_reg_rb;
v_write_rd = 1'b1;
end
// 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;
inst_sfxx_w,
inst_sfxxi_w:
next_sr_r[`OR32_SR_F] = compare_result_r;
default:
;
endcase
end
end
 
`INST_OR32_AND: // l.and
begin
r_e_alu_func <= `ALU_AND;
r_e_alu_a <= v_reg_ra;
r_e_alu_b <= v_reg_rb;
v_write_rd = 1'b1;
end
//-----------------------------------------------------------------
// Next EPC/ESR
//-----------------------------------------------------------------
reg [31:0] next_epc_r;
reg [31:0] next_esr_r;
 
`INST_OR32_OR: // l.or
begin
r_e_alu_func <= `ALU_OR;
r_e_alu_a <= v_reg_ra;
r_e_alu_b <= v_reg_rb;
v_write_rd = 1'b1;
end
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;
 
`INST_OR32_SLL: // l.sll
begin
r_e_alu_func <= `ALU_SHIFTL;
r_e_alu_a <= v_reg_ra;
r_e_alu_b <= v_shift_val;
v_write_rd = 1'b1;
end
// ESR - Exception saved SR
`SPR_REG_ESR: next_esr_r = reg_rb_r;
endcase
end
default:
;
endcase
end
 
`INST_OR32_SRA: // l.sra
begin
r_e_alu_func <= `ALU_SHIRTR_ARITH;
r_e_alu_a <= v_reg_ra;
r_e_alu_b <= v_shift_val;
v_write_rd = 1'b1;
end
//-----------------------------------------------------------------
// ALU inputs
//-----------------------------------------------------------------
 
`INST_OR32_SRL: // l.srl
begin
r_e_alu_func <= `ALU_SHIFTR;
r_e_alu_a <= v_reg_ra;
r_e_alu_b <= v_shift_val;
v_write_rd = 1'b1;
end
// ALU operation selection
reg [3:0] alu_func_r;
 
`INST_OR32_SUB: // l.sub
begin
r_e_alu_func <= `ALU_SUB;
r_e_alu_a <= v_reg_ra;
r_e_alu_b <= v_reg_rb;
v_write_rd = 1'b1;
end
// ALU operands
reg [31:0] alu_input_a_r;
reg [31:0] alu_input_b_r;
reg write_rd_r;
 
`INST_OR32_XOR: // l.xor
begin
r_e_alu_func <= `ALU_XOR;
r_e_alu_a <= v_reg_ra;
r_e_alu_b <= v_reg_rb;
v_write_rd = 1'b1;
end
always @ *
begin
alu_func_r = `ALU_NONE;
alu_input_a_r = 32'b0;
alu_input_b_r = 32'b0;
write_rd_r = 1'b0;
 
default:
begin
fault_o <= 1'b1;
v_exception = 1'b1;
v_vector = ISR_VECTOR + `VECTOR_ILLEGAL_INST;
end
endcase
end
case (1'b1)
 
`INST_OR32_ADDI: // l.addi
begin
r_e_alu_func <= `ALU_ADD;
r_e_alu_a <= v_reg_ra;
r_e_alu_b <= v_imm_int32;
v_write_rd = 1'b1;
end
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_OR32_ANDI: // l.andi
begin
r_e_alu_func <= `ALU_AND;
r_e_alu_a <= v_reg_ra;
r_e_alu_b <= v_imm_uint32;
v_write_rd = 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_OR32_BF: // l.bf
begin
if (v_sr[`OR32_SR_F] == 1'b1)
v_branch = 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_OR32_BNF: // l.bnf
begin
if (v_sr[`OR32_SR_F] == 1'b0)
v_branch = 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_OR32_J: // l.j
begin
v_branch = 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_OR32_JAL: // l.jal
begin
r_e_alu_a <= v_pc;
v_write_rd = 1'b1;
v_rd = 5'b01001; // Write to REG_9_LR
`ifdef CONF_CORE_DEBUG
$display(" Save 0x%x to LR", v_pc);
`endif
v_branch = 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_OR32_JALR: // l.jalr
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_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
r_e_alu_a <= v_pc;
v_write_rd = 1'b1;
v_rd = 5'b01001; // Write to REG_9_LR
`ifdef CONF_CORE_DEBUG
$display(" Save 0x%x to LR", v_pc);
`endif
v_pc = v_reg_rb;
v_jmp = 1;
alu_input_a_r = next_sr_r;
write_rd_r = 1'b1;
end
 
`INST_OR32_JR: // l.jr
// EPCR - EPC Exception saved PC
`SPR_REG_EPCR:
begin
v_pc = v_reg_rb;
v_jmp = 1;
alu_input_a_r = r_epc;
write_rd_r = 1'b1;
end
 
// l.lbs l.lhs l.lws l.lbz l.lhz l.lwz
`INST_OR32_LBS, `INST_OR32_LHS, `INST_OR32_LWS, `INST_OR32_LBZ, `INST_OR32_LHZ, `INST_OR32_LWZ :
// ESR - Exception saved SR
`SPR_REG_ESR:
begin
v_mem_addr = (v_reg_ra + v_imm_int32);
dmem_addr_o <= v_mem_addr;
dmem_data_out_o <= 32'h00000000;
dmem_rd_o <= 1'b1;
// Writeback if load result ready
v_write_rd = 1'b1;
v_check_load_rd = 1'b0;
// Mark load as pending
v_load_pending = 1'b1;
r_mem_access <= 1'b1;
// Record target register
r_load_rd <= reg_rd_i;
r_load_inst <= v_inst;
r_load_offset<= v_mem_addr[1:0];
`ifdef CONF_CORE_DEBUG
$display(" Load from 0x%08x to R%d", v_mem_addr, reg_rd_i);
`endif
// Detect bad load address & fault (ignore bit 31)
if (v_mem_addr[30:28] != 3'h1)
begin
v_load_pending = 1'b0;
dmem_rd_o <= 1'b0;
r_mem_access <= 1'b0;
fault_o <= 1'b1;
v_exception = 1'b1;
v_vector = ISR_VECTOR + `VECTOR_BUS_ERROR;
end
alu_input_a_r = r_esr;
write_rd_r = 1'b1;
end
default:
;
endcase
end
 
`INST_OR32_MFSPR: // l.mfspr
begin
case (v_mxspr_imm)
// SR - Supervision register
`SPR_REG_SR:
begin
r_e_alu_a <= v_sr;
v_write_rd = 1'b1;
end
inst_movhi_w: // l.movhi
begin
alu_input_a_r = {uint16_r,16'h0000};
write_rd_r = 1'b1;
end
 
// EPCR - EPC Exception saved PC
`SPR_REG_EPCR:
begin
r_e_alu_a <= r_epc;
v_write_rd = 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
 
// ESR - Exception saved SR
`SPR_REG_ESR:
begin
r_e_alu_a <= r_esr;
v_write_rd = 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
 
default:
begin
fault_o <= 1'b1;
v_exception = 1'b1;
v_vector = ISR_VECTOR + `VECTOR_ILLEGAL_INST;
end
endcase
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_OR32_MTSPR: // l.mtspr
begin
case (v_mxspr_imm)
// SR - Supervision register
`SPR_REG_SR:
begin
v_sr = v_reg_rb;
// Cache flush request?
icache_flush_o <= v_reg_rb[`OR32_SR_ICACHE_FLUSH];
dcache_flush_o <= v_reg_rb[`OR32_SR_DCACHE_FLUSH];
// Don't store cache flush requests
v_sr[`OR32_SR_ICACHE_FLUSH] = 1'b0;
v_sr[`OR32_SR_DCACHE_FLUSH] = 1'b0;
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
 
// EPCR - EPC Exception saved PC
`SPR_REG_EPCR:
begin
r_epc <= v_reg_rb;
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;
 
// ESR - Exception saved SR
`SPR_REG_ESR:
begin
r_esr <= v_reg_rb;
end
default:
begin
fault_o <= 1'b1;
v_exception = 1'b1;
v_vector = ISR_VECTOR + `VECTOR_ILLEGAL_INST;
end
endcase
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
 
`INST_OR32_MOVHI: // l.movhi
begin
r_e_alu_a <= {v_imm,16'h0000};
v_write_rd = 1'b1;
end
//-----------------------------------------------------------------
// Comparisons
//-----------------------------------------------------------------
always @ *
begin
compare_result_r = 1'b0;
 
`INST_OR32_NOP: // l.nop
begin
`ifdef SIMULATION
case (v_imm)
// NOP_PUTC
16'h0004: $write("%c", v_reg_ra[7:0]);
// NOP
16'h0000: ;
endcase
`endif
end
case (1'b1)
inst_sfeq_w: // l.sfeq
begin
if (reg_ra_r == reg_rb_r)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_ORI: // l.ori
begin
r_e_alu_func <= `ALU_OR;
r_e_alu_a <= v_reg_ra;
r_e_alu_b <= v_imm_uint32;
v_write_rd = 1'b1;
end
inst_sfeqi_w: // l.sfeqi
begin
if (reg_ra_r == int32_r)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_RFE: // l.rfe
begin
v_pc = r_epc;
v_sr = r_esr;
v_jmp = 1;
end
inst_sfges_w: // l.sfges
begin
if (greater_than_equal_signed(reg_ra_r, reg_rb_r) == 1'b1)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_SHIFTI :
begin
case (v_shift_op)
`INST_OR32_SLLI: // l.slli
begin
r_e_alu_func <= `ALU_SHIFTL;
r_e_alu_a <= v_reg_ra;
r_e_alu_b <= v_shift_imm;
v_write_rd = 1'b1;
end
inst_sfgesi_w: // l.sfgesi
begin
if (greater_than_equal_signed(reg_ra_r, int32_r) == 1'b1)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_SRAI: // l.srai
begin
r_e_alu_func <= `ALU_SHIRTR_ARITH;
r_e_alu_a <= v_reg_ra;
r_e_alu_b <= v_shift_imm;
v_write_rd = 1'b1;
end
inst_sfgeu_w: // l.sfgeu
begin
if (reg_ra_r >= reg_rb_r)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_SRLI: // l.srli
begin
r_e_alu_func <= `ALU_SHIFTR;
r_e_alu_a <= v_reg_ra;
r_e_alu_b <= v_shift_imm;
v_write_rd = 1'b1;
end
inst_sfgeui_w: // l.sfgeui
begin
if (reg_ra_r >= int32_r)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
default:
begin
fault_o <= 1'b1;
v_exception = 1'b1;
v_vector = ISR_VECTOR + `VECTOR_ILLEGAL_INST;
end
endcase
end
inst_sfgts_w: // l.sfgts
begin
if (greater_than_signed(reg_ra_r, reg_rb_r) == 1'b1)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_SB:
begin
v_mem_addr = (v_reg_ra + v_store_imm);
dmem_addr_o <= v_mem_addr;
r_mem_access <= 1'b1;
case (v_mem_addr[1:0])
2'b00 :
begin
dmem_data_out_o <= {v_reg_rb[7:0],24'h000000};
dmem_wr_o <= 4'b1000;
v_store_pending = 1'b1;
end
2'b01 :
begin
dmem_data_out_o <= {{8'h00,v_reg_rb[7:0]},16'h0000};
dmem_wr_o <= 4'b0100;
v_store_pending = 1'b1;
end
2'b10 :
begin
dmem_data_out_o <= {{16'h0000,v_reg_rb[7:0]},8'h00};
dmem_wr_o <= 4'b0010;
v_store_pending = 1'b1;
end
2'b11 :
begin
dmem_data_out_o <= {24'h000000,v_reg_rb[7:0]};
dmem_wr_o <= 4'b0001;
v_store_pending = 1'b1;
end
default :
begin
dmem_data_out_o <= 32'h00000000;
dmem_wr_o <= 4'b0000;
end
endcase
end
inst_sfgtsi_w: // l.sfgtsi
begin
if (greater_than_signed(reg_ra_r, int32_r) == 1'b1)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_SFXX, `INST_OR32_SFXXI:
begin
case (v_sfxx_op)
`INST_OR32_SFEQ: // l.sfeq
begin
if (v_reg_ra == v_reg_rb)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
inst_sfgtu_w: // l.sfgtu
begin
if (reg_ra_r > reg_rb_r)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_SFEQI: // l.sfeqi
begin
if (v_reg_ra == v_imm_int32)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
inst_sfgtui_w: // l.sfgtui
begin
if (reg_ra_r > int32_r)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_SFGES: // l.sfges
begin
if (greater_than_equal_signed(v_reg_ra, v_reg_rb) == 1'b1)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
inst_sfles_w: // l.sfles
begin
if (less_than_equal_signed(reg_ra_r, reg_rb_r) == 1'b1)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_SFGESI: // l.sfgesi
begin
if (greater_than_equal_signed(v_reg_ra, v_imm_int32) == 1'b1)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
inst_sflesi_w: // l.sflesi
begin
if (less_than_equal_signed(reg_ra_r, int32_r) == 1'b1)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_SFGEU: // l.sfgeu
begin
if (v_reg_ra >= v_reg_rb)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
inst_sfleu_w: // l.sfleu
begin
if (reg_ra_r <= reg_rb_r)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_SFGEUI: // l.sfgeui
begin
if (v_reg_ra >= v_imm_int32)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
inst_sfleui_w: // l.sfleui
begin
if (reg_ra_r <= int32_r)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_SFGTS: // l.sfgts
begin
if (greater_than_signed(v_reg_ra, v_reg_rb) == 1'b1)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
inst_sflts_w: // l.sflts
begin
if (less_than_signed(reg_ra_r, reg_rb_r) == 1'b1)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_SFGTSI: // l.sfgtsi
begin
if (greater_than_signed(v_reg_ra, v_imm_int32) == 1'b1)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
inst_sfltsi_w: // l.sfltsi
begin
if (less_than_signed(reg_ra_r, int32_r) == 1'b1)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_SFGTU: // l.sfgtu
begin
if (v_reg_ra > v_reg_rb)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
inst_sfltu_w: // l.sfltu
begin
if (reg_ra_r < reg_rb_r)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_SFGTUI: // l.sfgtui
begin
if (v_reg_ra > v_imm_int32)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
inst_sfltui_w: // l.sfltui
begin
if (reg_ra_r < int32_r)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_SFLES: // l.sfles
begin
if (less_than_equal_signed(v_reg_ra, v_reg_rb) == 1'b1)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
inst_sfne_w: // l.sfne
begin
if (reg_ra_r != reg_rb_r)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
 
`INST_OR32_SFLESI: // l.sflesi
begin
if (less_than_equal_signed(v_reg_ra, v_imm_int32) == 1'b1)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
inst_sfnei_w: // l.sfnei
begin
if (reg_ra_r != int32_r)
compare_result_r = 1'b1;
else
compare_result_r = 1'b0;
end
default:
;
endcase
end
 
`INST_OR32_SFLEU: // l.sfleu
begin
if (v_reg_ra <= v_reg_rb)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
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;
 
`INST_OR32_SFLEUI: // l.sfleui
begin
if (v_reg_ra <= v_imm_int32)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
// Memory address is relative to RA
mem_addr_r = reg_ra_r + (store_inst_r ? store_int32_r : int32_r);
end
 
`INST_OR32_SFLTS: // l.sflts
begin
if (less_than_signed(v_reg_ra, v_reg_rb) == 1'b1)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
//-----------------------------------------------------------------
// Branches
//-----------------------------------------------------------------
reg branch_r;
reg branch_link_r;
reg [31:0] branch_target_r;
reg branch_except_r;
 
`INST_OR32_SFLTSI: // l.sfltsi
begin
if (less_than_signed(v_reg_ra, v_imm_int32) == 1'b1)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
always @ *
begin
 
`INST_OR32_SFLTU: // l.sfltu
begin
if (v_reg_ra < v_reg_rb)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
branch_r = 1'b0;
branch_link_r = 1'b0;
branch_except_r = 1'b0;
 
`INST_OR32_SFLTUI: // l.sfltui
begin
if (v_reg_ra < v_imm_int32)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
// Default branch target is relative to current PC
branch_target_r = (opcode_pc_i + {target_int26_r[29:0],2'b00});
 
`INST_OR32_SFNE: // l.sfne
begin
if (v_reg_ra != v_reg_rb)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
case (1'b1)
inst_bf_w: // l.bf
branch_r = r_sr[`OR32_SR_F];
 
`INST_OR32_SFNEI: // l.sfnei
begin
if (v_reg_ra != v_imm_int32)
v_sr[`OR32_SR_F] = 1'b1;
else
v_sr[`OR32_SR_F] = 1'b0;
end
inst_bnf_w: // l.bnf
branch_r = ~r_sr[`OR32_SR_F];
 
default:
begin
fault_o <= 1'b1;
v_exception = 1'b1;
v_vector = ISR_VECTOR + `VECTOR_ILLEGAL_INST;
end
endcase
end
inst_j_w: // l.j
branch_r = 1'b1;
 
`INST_OR32_SH: // l.sh
begin
v_mem_addr = (v_reg_ra + v_store_imm);
dmem_addr_o <= v_mem_addr;
r_mem_access <= 1'b1;
case (v_mem_addr[1:0])
2'b00 :
begin
dmem_data_out_o <= {v_reg_rb[15:0],16'h0000};
dmem_wr_o <= 4'b1100;
v_store_pending = 1'b1;
end
2'b10 :
begin
dmem_data_out_o <= {16'h0000,v_reg_rb[15:0]};
dmem_wr_o <= 4'b0011;
v_store_pending = 1'b1;
end
default :
begin
dmem_data_out_o <= 32'h00000000;
dmem_wr_o <= 4'b0000;
end
endcase
end
inst_jal_w: // l.jal
begin
// Write to REG_9_LR
branch_link_r = 1'b1;
branch_r = 1'b1;
end
 
`INST_OR32_SW: // l.sw
begin
v_mem_addr = (v_reg_ra + v_store_imm);
dmem_addr_o <= v_mem_addr;
dmem_data_out_o <= v_reg_rb;
dmem_wr_o <= 4'b1111;
r_mem_access <= 1'b1;
v_store_pending = 1'b1;
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
 
`ifdef CONF_CORE_DEBUG
$display(" Store R%d to 0x%08x = 0x%08x", reg_rb_i, {v_mem_addr[31:2],2'b00}, v_reg_rb);
`endif
end
inst_jr_w: // l.jr
begin
branch_r = 1'b1;
branch_target_r = reg_rb_r;
end
 
`INST_OR32_MISC:
begin
case (v_mem_data_in[31:24])
`INST_OR32_SYS: // l.sys
begin
v_exception = 1'b1;
v_vector = ISR_VECTOR + `VECTOR_SYSCALL;
end
inst_rfe_w: // l.rfe
begin
branch_r = 1'b1;
branch_target_r = r_epc;
end
 
`INST_OR32_TRAP: // l.trap
begin
v_exception = 1'b1;
v_vector = ISR_VECTOR + `VECTOR_TRAP;
break_o <= 1'b1;
end
inst_sys_w: // l.sys
begin
branch_r = 1'b1;
branch_except_r = 1'b1;
branch_target_r = ISR_VECTOR + `VECTOR_SYSCALL;
end
 
default :
begin
fault_o <= 1'b1;
v_exception = 1'b1;
v_vector = ISR_VECTOR + `VECTOR_ILLEGAL_INST;
end
endcase
end
inst_trap_w: // l.trap
begin
branch_r = 1'b1;
branch_except_r = 1'b1;
branch_target_r = ISR_VECTOR + `VECTOR_TRAP;
end
 
`INST_OR32_XORI: // l.xori
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_sfeqi_w,
inst_sfges_w,
inst_sfgesi_w,
inst_sfgeu_w,
inst_sfgeui_w,
inst_sfgts_w,
inst_sfgtsi_w,
inst_sfgtu_w,
inst_sfgtui_w,
inst_sfles_w,
inst_sflesi_w,
inst_sfleu_w,
inst_sfleui_w,
inst_sflts_w,
inst_sfltsi_w,
inst_sfltu_w,
inst_sfltui_w,
inst_sfne_w,
inst_sfnei_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
r_e_alu_func <= `ALU_XOR;
r_e_alu_a <= v_reg_ra;
r_e_alu_b <= v_imm_int32;
v_write_rd = 1'b1;
// 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
 
default :
else
begin
fault_o <= 1'b1;
v_exception = 1'b1;
v_vector = ISR_VECTOR + `VECTOR_ILLEGAL_INST;
// 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
endcase
 
end
//---------------------------------------------------------------
// Branch logic
// Valid instruction
//---------------------------------------------------------------
else if (~invalid_inst_r)
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;
 
// If relative branch, calculate target before possible interrupt/exception
if (v_branch == 1'b1)
begin
v_offset = {v_target[29:0],2'b00};
v_pc = (opcode_pc_i + v_offset);
// 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
// Pipeline stall due to load result not ready
if (v_stall == 1'b1)
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;
 
r_stall <= 1'b0;
end
else
begin
r_stall <= stall_inst_r;
 
// Instruction not ready
if (~execute_inst_r | stall_inst_r)
begin
// No exceptions whilst stalled
end
// Exception (Fault/Syscall/Break)
else if (v_exception == 1'b1)
// Store bubble opcode
r_e_opcode <= `OPCODE_INST_BUBBLE;
r_e_opcode_pc <= opcode_pc_i;
end
// Valid instruction
else if (~invalid_inst_r)
begin
// Save PC of next instruction
r_epc <= v_pc;
// Store opcode
r_e_opcode <= opcode_i;
r_e_opcode_pc <= opcode_pc_i;
 
// Disable further interrupts
r_esr <= v_sr;
v_sr = 0;
 
// Set PC to exception vector
v_pc = v_vector;
r_pc_branch <= v_pc;
r_pc_fetch <= 1'b1;
`ifdef CONF_CORE_DEBUG
$display(" Exception 0x%08x", v_vector);
`endif
`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
// Non-maskable interrupt
else if (nmi_i | r_nmi)
begin
r_nmi <= 1'b0;
end
end
 
// Save PC of next instruction
r_epc <= v_pc;
//-----------------------------------------------------------------
// 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;
 
// Disable further interrupts
r_esr <= v_sr;
v_sr = 0;
// Status registers
r_epc <= 32'h00000000;
r_sr <= 32'h00000000;
r_esr <= 32'h00000000;
 
// Set PC to exception vector
v_pc = ISR_VECTOR + `VECTOR_NMI;
r_pc_branch <= v_pc;
r_pc_fetch <= 1'b1;
`ifdef CONF_CORE_DEBUG
$display(" NMI 0x%08x", v_pc);
`endif
end
// External interrupt
else if (v_no_intr == 1'b0 &&
((intr_i && v_sr[`OR32_SR_IEE])))
begin
// Save PC of next instruction & SR
r_epc <= v_pc;
fault_o <= 1'b0;
 
// Disable further interrupts
r_esr <= v_sr;
v_sr = 0;
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;
 
// Set PC to external interrupt vector
v_pc = ISR_VECTOR + `VECTOR_EXTINT;
// Reset branch request
r_pc_fetch <= 1'b0;
 
r_pc_branch <= v_pc;
r_pc_fetch <= 1'b1;
`ifdef CONF_CORE_DEBUG
$display(" External Interrupt 0x%08x", v_pc);
`endif
end
// Handle relative branches (l.bf, l.bnf, l.j, l.jal)
else if (v_branch == 1'b1)
// Update SR
r_sr <= next_sr_r;
 
// Instruction ready
if (execute_inst_r & ~stall_inst_r)
begin
// Perform branch (already in v_pc)
r_pc_branch <= v_pc;
r_pc_fetch <= 1'b1;
`ifdef CONF_CORE_DEBUG
$display(" Branch to 0x%08x", v_pc);
`endif
end
// Handle absolute jumps (l.jr, l.jalr, l.rfe)
else if (v_jmp == 1'b1)
begin
// Perform branch
r_pc_branch <= v_pc;
r_pc_fetch <= 1'b1;
`ifdef CONF_CORE_DEBUG
$display(" Jump to 0x%08x", v_pc);
`endif
end
// 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;
 
// Update other registers with variable values
r_stall <= v_stall;
r_sr <= v_sr;
// 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;
 
// Memory access?
r_mem_load <= v_load_pending;
r_mem_store<= v_store_pending;
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_rd_o <= 1'b0;
dmem_wr_o <= 4'b0000;
// No writeback required?
if (v_write_rd == 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_accept_i)
begin
// Target register is R0 which is read-only
r_e_rd <= 5'b00000;
dmem_rd_o <= 1'b0;
dmem_wr_o <= 4'b0000;
end
// Writeback required
else
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 & ~invalid_inst_r)
begin
// Load outstanding, check if result target is being
// overwritten (to avoid WAR hazard)
if (v_check_load_rd && v_rd == r_load_rd)
// 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_rd_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_wr_o <= 4'b1000;
r_mem_store <= 1'b1;
end
2'b01 :
begin
dmem_data_out_o <= {{8'h00,reg_rb_r[7:0]},16'h0000};
dmem_wr_o <= 4'b0100;
r_mem_store <= 1'b1;
end
2'b10 :
begin
dmem_data_out_o <= {{16'h0000,reg_rb_r[7:0]},8'h00};
dmem_wr_o <= 4'b0010;
r_mem_store <= 1'b1;
end
2'b11 :
begin
dmem_data_out_o <= {24'h000000,reg_rb_r[7:0]};
dmem_wr_o <= 4'b0001;
r_mem_store <= 1'b1;
end
default :
begin
dmem_data_out_o <= 32'h00000000;
dmem_wr_o <= 4'b0000;
end
endcase
end
 
inst_sh_w: // l.sh
begin
`ifdef CONF_CORE_DEBUG
if (v_rd != 5'b0)
$display("%08x: Load target overwrite, clear target (R%d)", opcode_pc_i, r_load_rd);
`endif
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_wr_o <= 4'b1100;
r_mem_store <= 1'b1;
end
2'b10 :
begin
dmem_data_out_o <= {16'h0000,reg_rb_r[15:0]};
dmem_wr_o <= 4'b0011;
r_mem_store <= 1'b1;
end
default :
begin
dmem_data_out_o <= 32'h00000000;
dmem_wr_o <= 4'b0000;
end
endcase
end
 
// Ditch load result when it arrives
r_load_rd <= 5'b00000;
inst_sw_w: // l.sw
begin
dmem_addr_o <= mem_addr_r;
dmem_data_out_o <= reg_rb_r;
dmem_wr_o <= 4'b1111;
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
 
// Target Rd
r_e_rd <= v_rd;
//-----------------------------------------------------------------
// 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 & ~invalid_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 & ~invalid_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
//-------------------------------------------------------------------
1372,6 → 1611,14
// 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
`endif
 
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.