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 |