Code cleanup

Fix errors and warnings reported by lint tools, and clean up the code
according to our coding style. Move all imports into the module.
This commit is contained in:
Scott Johnson 2019-01-30 13:36:25 -08:00 committed by Philipp Wagner
parent 148604265e
commit 6b0475744d
22 changed files with 2223 additions and 2563 deletions

View file

@ -20,42 +20,35 @@
`include "ibex_config.sv"
import ibex_defines::*;
/**
* Arithmetic logic unit
*/
module ibex_alu
(
input logic [ALU_OP_WIDTH-1:0] operator_i,
input logic [31:0] operand_a_i,
input logic [31:0] operand_b_i,
module ibex_alu (
input logic [ibex_defines::ALU_OP_WIDTH-1:0] operator_i,
input logic [31:0] operand_a_i,
input logic [31:0] operand_b_i,
input logic [32:0] multdiv_operand_a_i,
input logic [32:0] multdiv_operand_b_i,
input logic [32:0] multdiv_operand_a_i,
input logic [32:0] multdiv_operand_b_i,
input logic multdiv_en_i,
input logic multdiv_en_i,
output logic [31:0] adder_result_o,
output logic [33:0] adder_result_ext_o,
output logic [31:0] adder_result_o,
output logic [33:0] adder_result_ext_o,
output logic [31:0] result_o,
output logic comparison_result_o,
output logic is_equal_result_o
output logic [31:0] result_o,
output logic comparison_result_o,
output logic is_equal_result_o
);
import ibex_defines::*;
logic [31:0] operand_a_rev;
logic [32:0] operand_b_neg;
// bit reverse operand_a for left shifts and bit counting
generate
genvar k;
for(k = 0; k < 32; k++)
begin : g_revloop
assign operand_a_rev[k] = operand_a_i[31-k];
end
endgenerate
for (genvar k = 0; k < 32; k++) begin : gen_revloop
assign operand_a_rev[k] = operand_a_i[31-k];
end
/////////////////////////////////////
// _ _ _ //
@ -70,8 +63,7 @@ module ibex_alu
logic [32:0] adder_in_a, adder_in_b;
logic [31:0] adder_result;
always_comb
begin
always_comb begin
adder_op_b_negate = 1'b0;
unique case (operator_i)
@ -117,15 +109,13 @@ module ibex_alu
logic shift_left; // should we shift left
logic shift_arithmetic;
logic [31:0] shift_amt; // amount of shift, to the right
logic [4:0] shift_amt; // amount of shift, to the right
logic [31:0] shift_op_a; // input of the shifter
logic [31:0] shift_result;
logic [31:0] shift_right_result;
logic [31:0] shift_left_result;
assign shift_amt = operand_b_i;
assign shift_amt = operand_b_i[4:0];
assign shift_left = (operator_i == ALU_SLL);
@ -137,22 +127,17 @@ module ibex_alu
// right shifts, we let the synthesizer optimize this
logic [32:0] shift_op_a_32;
assign shift_op_a_32 = { shift_arithmetic & shift_op_a[31], shift_op_a};
assign shift_op_a_32 = {shift_arithmetic & shift_op_a[31], shift_op_a};
assign shift_right_result = $signed(shift_op_a_32) >>> shift_amt[4:0];
assign shift_right_result = $unsigned($signed(shift_op_a_32) >>> shift_amt[4:0]);
// bit reverse the shift_right_result for left shifts
genvar j;
generate
for(j = 0; j < 32; j++)
begin : g_resrevloop
assign shift_left_result[j] = shift_right_result[31-j];
end
endgenerate
for (genvar j = 0; j < 32; j++) begin : gen_resrevloop
assign shift_left_result[j] = shift_right_result[31-j];
end
assign shift_result = shift_left ? shift_left_result : shift_right_result;
//////////////////////////////////////////////////////////////////
// ____ ___ __ __ ____ _ ____ ___ ____ ___ _ _ //
// / ___/ _ \| \/ | _ \ / \ | _ \|_ _/ ___| / _ \| \ | | //
@ -166,8 +151,7 @@ module ibex_alu
logic is_greater_equal; // handles both signed and unsigned forms
logic cmp_signed;
always_comb
begin
always_comb begin
cmp_signed = 1'b0;
unique case (operator_i)
@ -189,12 +173,12 @@ module ibex_alu
// Is greater equal
always_comb
begin
if ((operand_a_i[31] ^ operand_b_i[31]) == 0)
is_greater_equal = (adder_result[31] == 0);
else
always_comb begin
if ((operand_a_i[31] ^ operand_b_i[31]) == 1'b0) begin
is_greater_equal = (adder_result[31] == 1'b0);
end else begin
is_greater_equal = operand_a_i[31] ^ (cmp_signed);
end
end
// GTE unsigned:
@ -214,20 +198,19 @@ module ibex_alu
// generate comparison result
logic cmp_result;
always_comb
begin
always_comb begin
cmp_result = is_equal;
unique case (operator_i)
ALU_EQ: cmp_result = is_equal;
ALU_NE: cmp_result = (~is_equal);
ALU_GTS, ALU_GTU: cmp_result = is_greater_equal && (~is_equal);
ALU_EQ: cmp_result = is_equal;
ALU_NE: cmp_result = ~is_equal;
ALU_GTS, ALU_GTU: cmp_result = is_greater_equal & ~is_equal;
ALU_GES, ALU_GEU: cmp_result = is_greater_equal;
ALU_LTS, ALU_SLTS,
ALU_LTU, ALU_SLTU: cmp_result = (~is_greater_equal);
ALU_LTU, ALU_SLTU: cmp_result = ~is_greater_equal;
ALU_SLETS,
ALU_SLETU,
ALU_LES, ALU_LEU: cmp_result = (~is_greater_equal) || is_equal;
ALU_LES, ALU_LEU: cmp_result = ~is_greater_equal | is_equal;
default: ;
endcase
@ -246,8 +229,7 @@ module ibex_alu
// //
////////////////////////////////////////////////////////
always_comb
begin
always_comb begin
result_o = '0;
unique case (operator_i)
@ -270,7 +252,7 @@ module ibex_alu
ALU_GTS, ALU_GES,
ALU_LTS, ALU_LES,
ALU_SLTS, ALU_SLTU,
ALU_SLETS, ALU_SLETU: result_o = cmp_result;
ALU_SLETS, ALU_SLETU: result_o = {31'h0,cmp_result};
default: ; // default case to suppress unique warning
endcase

View file

@ -16,33 +16,30 @@
// //
////////////////////////////////////////////////////////////////////////////////
import ibex_defines::*;
/**
* Compressed instruction decoder
*
* Decodes RISC-V compressed instructions into their RV32 equivalent.
* This module is fully combinatorial.
*/
module ibex_compressed_decoder
(
input logic [31:0] instr_i,
output logic [31:0] instr_o,
output logic is_compressed_o,
output logic illegal_instr_o
module ibex_compressed_decoder (
input logic [31:0] instr_i,
output logic [31:0] instr_o,
output logic is_compressed_o,
output logic illegal_instr_o
);
import ibex_defines::*;
//////////////////////////////////////////////////////////////////////////////////////////////////////
// ____ _ ____ _ //
// / ___|___ _ __ ___ _ __ _ __ ___ ___ ___ ___ __| | | _ \ ___ ___ ___ __| | ___ _ __ //
// | | / _ \| '_ ` _ \| '_ \| '__/ _ \/ __/ __|/ _ \/ _` | | | | |/ _ \/ __/ _ \ / _` |/ _ \ '__| //
// | |__| (_) | | | | | | |_) | | | __/\__ \__ \ __/ (_| | | |_| | __/ (_| (_) | (_| | __/ | //
// \____\___/|_| |_| |_| .__/|_| \___||___/___/\___|\__,_| |____/ \___|\___\___/ \__,_|\___|_| //
// |_| //
//////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// ____ __ _ ____ _ //
// / ___|___ _ __ ___ _ __ _ __ /_/ ___ __| | | _ \ ___ ___ ___ __| | ___ _ __ //
// | | / _ \| '_ ` _ \| '_ \| '__/// / __|/ _` | | | | |/ _ \/ __/ _ \ / _` |/ _ \ '__| //
// | |__| (_) | | | | | | |_) | | \__ \ (_| | | |_| | __/ (_| (_) | (_| | __/ | //
// \____\___/|_| |_| |_| .__/|_| |___/\__,_| |____/ \___|\___\___/ \__,_|\___|_| //
// |_| //
/////////////////////////////////////////////////////////////////////////////////////////////
always_comb
begin
always_comb begin
illegal_instr_o = 1'b0;
instr_o = '0;
@ -52,18 +49,22 @@ module ibex_compressed_decoder
unique case (instr_i[15:13])
3'b000: begin
// c.addi4spn -> addi rd', x2, imm
instr_o = {2'b0, instr_i[10:7], instr_i[12:11], instr_i[5], instr_i[6], 2'b00, 5'h02, 3'b000, 2'b01, instr_i[4:2], OPCODE_OPIMM};
instr_o = {2'b0, instr_i[10:7], instr_i[12:11], instr_i[5],
instr_i[6], 2'b00, 5'h02, 3'b000, 2'b01, instr_i[4:2], OPCODE_OPIMM};
if (instr_i[12:5] == 8'b0) illegal_instr_o = 1'b1;
end
3'b010: begin
// c.lw -> lw rd', imm(rs1')
instr_o = {5'b0, instr_i[5], instr_i[12:10], instr_i[6], 2'b00, 2'b01, instr_i[9:7], 3'b010, 2'b01, instr_i[4:2], OPCODE_LOAD};
instr_o = {5'b0, instr_i[5], instr_i[12:10], instr_i[6],
2'b00, 2'b01, instr_i[9:7], 3'b010, 2'b01, instr_i[4:2], OPCODE_LOAD};
end
3'b110: begin
// c.sw -> sw rs2', imm(rs1')
instr_o = {5'b0, instr_i[5], instr_i[12], 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b010, instr_i[11:10], instr_i[6], 2'b00, OPCODE_STORE};
instr_o = {5'b0, instr_i[5], instr_i[12], 2'b01, instr_i[4:2],
2'b01, instr_i[9:7], 3'b010, instr_i[11:10], instr_i[6],
2'b00, OPCODE_STORE};
end
default: begin
@ -78,18 +79,22 @@ module ibex_compressed_decoder
3'b000: begin
// c.addi -> addi rd, rd, nzimm
// c.nop
instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2], instr_i[11:7], 3'b0, instr_i[11:7], OPCODE_OPIMM};
instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2],
instr_i[11:7], 3'b0, instr_i[11:7], OPCODE_OPIMM};
end
3'b001, 3'b101: begin
// 001: c.jal -> jal x1, imm
// 101: c.j -> jal x0, imm
instr_o = {instr_i[12], instr_i[8], instr_i[10:9], instr_i[6], instr_i[7], instr_i[2], instr_i[11], instr_i[5:3], {9 {instr_i[12]}}, 4'b0, ~instr_i[15], OPCODE_JAL};
instr_o = {instr_i[12], instr_i[8], instr_i[10:9], instr_i[6],
instr_i[7], instr_i[2], instr_i[11], instr_i[5:3],
{9 {instr_i[12]}}, 4'b0, ~instr_i[15], OPCODE_JAL};
end
3'b010: begin
// c.li -> addi rd, x0, nzimm
instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2], 5'b0, 3'b0, instr_i[11:7], OPCODE_OPIMM};
instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2], 5'b0,
3'b0, instr_i[11:7], OPCODE_OPIMM};
if (instr_i[11:7] == 5'b0) illegal_instr_o = 1'b1;
end
@ -99,7 +104,8 @@ module ibex_compressed_decoder
if (instr_i[11:7] == 5'h02) begin
// c.addi16sp -> addi x2, x2, nzimm
instr_o = {{3 {instr_i[12]}}, instr_i[4:3], instr_i[5], instr_i[2], instr_i[6], 4'b0, 5'h02, 3'b000, 5'h02, OPCODE_OPIMM};
instr_o = {{3 {instr_i[12]}}, instr_i[4:3], instr_i[5], instr_i[2],
instr_i[6], 4'b0, 5'h02, 3'b000, 5'h02, OPCODE_OPIMM};
end else if (instr_i[11:7] == 5'b0) begin
illegal_instr_o = 1'b1;
end
@ -113,36 +119,42 @@ module ibex_compressed_decoder
2'b01: begin
// 00: c.srli -> srli rd, rd, shamt
// 01: c.srai -> srai rd, rd, shamt
instr_o = {1'b0, instr_i[10], 5'b0, instr_i[6:2], 2'b01, instr_i[9:7], 3'b101, 2'b01, instr_i[9:7], OPCODE_OPIMM};
instr_o = {1'b0, instr_i[10], 5'b0, instr_i[6:2], 2'b01, instr_i[9:7],
3'b101, 2'b01, instr_i[9:7], OPCODE_OPIMM};
if (instr_i[12] == 1'b1) illegal_instr_o = 1'b1;
if (instr_i[6:2] == 5'b0) illegal_instr_o = 1'b1;
end
2'b10: begin
// c.andi -> andi rd, rd, imm
instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2], 2'b01, instr_i[9:7], 3'b111, 2'b01, instr_i[9:7], OPCODE_OPIMM};
instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2], 2'b01, instr_i[9:7],
3'b111, 2'b01, instr_i[9:7], OPCODE_OPIMM};
end
2'b11: begin
unique case ({instr_i[12], instr_i[6:5]})
3'b000: begin
// c.sub -> sub rd', rd', rs2'
instr_o = {2'b01, 5'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b000, 2'b01, instr_i[9:7], OPCODE_OP};
instr_o = {2'b01, 5'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7],
3'b000, 2'b01, instr_i[9:7], OPCODE_OP};
end
3'b001: begin
// c.xor -> xor rd', rd', rs2'
instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b100, 2'b01, instr_i[9:7], OPCODE_OP};
instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b100,
2'b01, instr_i[9:7], OPCODE_OP};
end
3'b010: begin
// c.or -> or rd', rd', rs2'
instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b110, 2'b01, instr_i[9:7], OPCODE_OP};
instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b110,
2'b01, instr_i[9:7], OPCODE_OP};
end
3'b011: begin
// c.and -> and rd', rd', rs2'
instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b111, 2'b01, instr_i[9:7], OPCODE_OP};
instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b111,
2'b01, instr_i[9:7], OPCODE_OP};
end
3'b100,
@ -161,11 +173,13 @@ module ibex_compressed_decoder
3'b110, 3'b111: begin
// 0: c.beqz -> beq rs1', x0, imm
// 1: c.bnez -> bne rs1', x0, imm
instr_o = {{4 {instr_i[12]}}, instr_i[6:5], instr_i[2], 5'b0, 2'b01, instr_i[9:7], 2'b00, instr_i[13], instr_i[11:10], instr_i[4:3], instr_i[12], OPCODE_BRANCH};
instr_o = {{4 {instr_i[12]}}, instr_i[6:5], instr_i[2], 5'b0, 2'b01,
instr_i[9:7], 2'b00, instr_i[13], instr_i[11:10], instr_i[4:3],
instr_i[12], OPCODE_BRANCH};
end
default: begin
illegal_instr_o = 1'b1;
// illegal_instr_o = 1'b1; // not reachable, dead code, commenting out
end
endcase
end
@ -182,7 +196,8 @@ module ibex_compressed_decoder
3'b010: begin
// c.lwsp -> lw rd, imm(x2)
instr_o = {4'b0, instr_i[3:2], instr_i[12], instr_i[6:4], 2'b00, 5'h02, 3'b010, instr_i[11:7], OPCODE_LOAD};
instr_o = {4'b0, instr_i[3:2], instr_i[12], instr_i[6:4], 2'b00, 5'h02,
3'b010, instr_i[11:7], OPCODE_LOAD};
if (instr_i[11:7] == 5'b0) illegal_instr_o = 1'b1;
end
@ -202,8 +217,7 @@ module ibex_compressed_decoder
if (instr_i[11:7] == 5'b0) begin
// c.ebreak -> ebreak
instr_o = {32'h00_10_00_73};
if (instr_i[6:2] != 5'b0)
illegal_instr_o = 1'b1;
if (instr_i[6:2] != 5'b0) illegal_instr_o = 1'b1;
end else if (instr_i[6:2] == 5'b0) begin
// c.jalr -> jalr x1, rs1, 0
instr_o = {12'b0, instr_i[11:7], 3'b000, 5'b00001, OPCODE_JALR};
@ -213,7 +227,8 @@ module ibex_compressed_decoder
3'b110: begin
// c.swsp -> sw rs2, imm(x2)
instr_o = {4'b0, instr_i[8:7], instr_i[12], instr_i[6:2], 5'h02, 3'b010, instr_i[11:9], 2'b00, OPCODE_STORE};
instr_o = {4'b0, instr_i[8:7], instr_i[12], instr_i[6:2], 5'h02, 3'b010,
instr_i[11:9], 2'b00, OPCODE_STORE};
end
default: begin

View file

@ -22,104 +22,105 @@
`include "ibex_config.sv"
import ibex_defines::*;
/**
* Main CPU controller of the processor
*/
module ibex_controller
#(
parameter REG_ADDR_WIDTH = 5
)
(
input logic clk,
input logic rst_n,
module ibex_controller (
input logic clk,
input logic rst_n,
input logic fetch_enable_i, // Start the decoding
output logic ctrl_busy_o, // Core is busy processing instructions
output logic first_fetch_o, // Core is at the FIRST FETCH stage
output logic is_decoding_o, // Core is in decoding state
input logic fetch_enable_i, // Start the decoding
output logic ctrl_busy_o, // Core is busy processing instructions
output logic first_fetch_o, // Core is at the FIRST FETCH stage
output logic is_decoding_o, // Core is in decoding state
// decoder related signals
output logic deassert_we_o, // deassert write enable for next instruction
// decoder related signals
output logic deassert_we_o, // deassert write enable for next instruction
input logic illegal_insn_i, // decoder encountered an invalid instruction
input logic ecall_insn_i, // ecall encountered an mret instruction
input logic mret_insn_i, // decoder encountered an mret instruction
input logic pipe_flush_i, // decoder wants to do a pipe flush
input logic ebrk_insn_i, // decoder encountered an ebreak instruction
input logic csr_status_i, // decoder encountered an csr status instruction
input logic illegal_insn_i, // decoder encountered an invalid instruction
input logic ecall_insn_i, // ecall encountered an mret instruction
input logic mret_insn_i, // decoder encountered an mret instruction
input logic pipe_flush_i, // decoder wants to do a pipe flush
input logic ebrk_insn_i, // decoder encountered an ebreak instruction
input logic csr_status_i, // decoder encountered an csr status instruction
// from IF/ID pipeline
input logic instr_valid_i, // instruction coming from IF/ID pipeline is valid
// from IF/ID pipeline
input logic instr_valid_i, // instruction coming from IF/ID pipeline is
// valid
// from prefetcher
output logic instr_req_o, // Start fetching instructions
// from prefetcher
output logic instr_req_o, // Start fetching instructions
// to prefetcher
output logic pc_set_o, // jump to address set by pc_mux
output logic [2:0] pc_mux_o, // Selector in the Fetch stage to select the rigth PC (normal, jump ...)
output logic [1:0] exc_pc_mux_o, // Selects target PC for exception
// to prefetcher
output logic pc_set_o, // jump to address set by pc_mux
output logic [2:0] pc_mux_o, // Selector in the Fetch stage to select the
// right PC (normal, jump ...)
output logic [1:0] exc_pc_mux_o, // Selects target PC for exception
// LSU
input logic data_misaligned_i,
// LSU
input logic data_misaligned_i,
// jump/branch signals
input logic branch_in_id_i, // branch in id
input logic branch_taken_ex_i, // branch taken signal
input logic branch_set_i, // branch taken set signal
input logic jump_set_i, // jump taken set signal
// jump/branch signals
input logic branch_in_id_i, // branch in id
input logic branch_taken_ex_i, // branch taken signal
input logic branch_set_i, // branch taken set signal
input logic jump_set_i, // jump taken set signal
input logic instr_multicyle_i, // multicycle instructions active
input logic instr_multicyle_i, // multicycle instructions active
// External Interrupt Req Signals, used to wake up from wfi even if the interrupt is not taken
input logic irq_i,
// Interrupt Controller Signals
input logic irq_req_ctrl_i,
input logic [4:0] irq_id_ctrl_i,
input logic m_IE_i, // interrupt enable bit from CSR (M mode)
// External Interrupt Req Signals, used to wake up from wfi even if the interrupt is not taken
input logic irq_i,
// Interrupt Controller Signals
input logic irq_req_ctrl_i,
input logic [4:0] irq_id_ctrl_i,
input logic m_IE_i, // interrupt enable bit from CSR (M mode)
output logic irq_ack_o,
output logic [4:0] irq_id_o,
output logic irq_ack_o,
output logic [4:0] irq_id_o,
output logic [5:0] exc_cause_o,
output logic exc_ack_o,
output logic exc_kill_o,
output logic [5:0] exc_cause_o,
output logic exc_ack_o,
output logic exc_kill_o,
output logic csr_save_if_o,
output logic csr_save_id_o,
output logic [5:0] csr_cause_o,
output logic csr_restore_mret_id_o,
output logic csr_save_cause_o,
output logic csr_save_if_o,
output logic csr_save_id_o,
output logic [5:0] csr_cause_o,
output logic csr_restore_mret_id_o,
output logic csr_save_cause_o,
// Debug Signals
input logic dbg_req_i, // a trap was hit, so we have to flush EX and WB
output logic dbg_ack_o, // we stopped and give control to debug now
// Debug Signals
input logic dbg_req_i, // a trap was hit, so we have to flush EX and WB
output logic dbg_ack_o, // we stopped and give control to debug now
input logic dbg_stall_i, // Pipeline stall is requested
input logic dbg_jump_req_i, // Change PC to value from debug unit
input logic dbg_stall_i, // Pipeline stall is requested
input logic dbg_jump_req_i, // Change PC to value from debug unit
input logic [DBG_SETS_W-1:0] dbg_settings_i,
output logic dbg_trap_o,
input logic [DBG_SETS_W-1:0] dbg_settings_i,
output logic dbg_trap_o,
// forwarding signals
output logic [1:0] operand_a_fw_mux_sel_o, // regfile ra data selector form ID stage
// forwarding signals
output logic [1:0] operand_a_fw_mux_sel_o, // regfile ra data selector form ID stage
// stall signals
output logic halt_if_o,
output logic halt_id_o,
// stall signals
output logic halt_if_o,
output logic halt_id_o,
input logic id_ready_i, // ID stage is ready
input logic id_ready_i, // ID stage is ready
// Performance Counters
output logic perf_jump_o, // we are executing a jump instruction (j, jr, jal, jalr)
output logic perf_tbranch_o // we are executing a taken branch instruction
// Performance Counters
output logic perf_jump_o, // we are executing a jump instruction
// (j, jr, jal, jalr)
output logic perf_tbranch_o // we are executing a taken branch instruction
);
import ibex_defines::*;
// FSM state encoding
enum logic [3:0] { RESET, BOOT_SET, WAIT_SLEEP, SLEEP, FIRST_FETCH,
DECODE, FLUSH, IRQ_TAKEN,
DBG_SIGNAL, DBG_SIGNAL_SLEEP, DBG_WAIT, DBG_WAIT_BRANCH } ctrl_fsm_cs, ctrl_fsm_ns;
typedef enum logic [3:0] {
RESET, BOOT_SET, WAIT_SLEEP, SLEEP, FIRST_FETCH, DECODE, FLUSH,
IRQ_TAKEN, DBG_SIGNAL, DBG_SIGNAL_SLEEP, DBG_WAIT, DBG_WAIT_BRANCH
} ctrl_fsm_e;
ctrl_fsm_e ctrl_fsm_cs, ctrl_fsm_ns;
logic irq_enable_int;
@ -127,8 +128,7 @@ module ibex_controller
// synopsys translate_off
// make sure we are called later so that we do not generate messages for
// glitches
always_ff @(negedge clk)
begin
always_ff @(negedge clk) begin
// print warning in case of decoding errors
if (is_decoding_o && illegal_insn_i) begin
$display("%t: Illegal instruction (core %0d) at PC 0x%h:", $time, ibex_core.core_id_i,
@ -149,8 +149,7 @@ module ibex_controller
////////////////////////////////////////////////////////////////////////////////////////////
always_comb
begin
always_comb begin
// Default values
instr_req_o = 1'b1;
@ -197,13 +196,12 @@ module ibex_controller
unique case (ctrl_fsm_cs)
// We were just reset, wait for fetch_enable
RESET:
begin
RESET: begin
instr_req_o = 1'b0;
if (fetch_enable_i == 1'b1)
if (fetch_enable_i) begin
ctrl_fsm_ns = BOOT_SET;
else if (dbg_req_i) begin
end else if (dbg_req_i) begin
// just go to debug even when we did not yet get a fetch enable
// this means that the NPC will not be set yet
ctrl_fsm_ns = DBG_SIGNAL;
@ -211,8 +209,7 @@ module ibex_controller
end
// copy boot address to instr fetch address
BOOT_SET:
begin
BOOT_SET: begin
instr_req_o = 1'b1;
pc_mux_o = PC_BOOT;
pc_set_o = 1'b1;
@ -220,8 +217,7 @@ module ibex_controller
ctrl_fsm_ns = FIRST_FETCH;
end
WAIT_SLEEP:
begin
WAIT_SLEEP: begin
ctrl_busy_o = 1'b0;
instr_req_o = 1'b0;
halt_if_o = 1'b1;
@ -230,8 +226,7 @@ module ibex_controller
end
// instruction in if_stage is already valid
SLEEP:
begin
SLEEP: begin
// we begin execution when an
// interrupt has arrived
ctrl_busy_o = 1'b0;
@ -243,28 +238,25 @@ module ibex_controller
if (dbg_req_i) begin
// debug request, now we need to check if we should stay sleeping or
// go to normal processing later
ctrl_fsm_ns = DBG_SIGNAL_SLEEP;
ctrl_fsm_ns = DBG_SIGNAL_SLEEP;
end else begin
// no debug request incoming, normal execution flow
// here transparent interrupts are checked to wake up from wfi
if (irq_i)
begin
if (irq_i) begin
ctrl_fsm_ns = FIRST_FETCH;
end
end
end
FIRST_FETCH:
begin
FIRST_FETCH: begin
first_fetch_o = 1'b1;
// Stall because of IF miss
if ((id_ready_i == 1'b1) && (dbg_stall_i == 1'b0))
begin
if (id_ready_i && !dbg_stall_i) begin
ctrl_fsm_ns = DECODE;
end
if (irq_req_ctrl_i & irq_enable_int) begin
if (irq_req_ctrl_i && irq_enable_int) begin
// This assumes that the pipeline is always flushed before
// going to sleep.
ctrl_fsm_ns = IRQ_TAKEN;
@ -273,82 +265,76 @@ module ibex_controller
end
end
DECODE:
begin
DECODE: begin
is_decoding_o = 1'b0;
// decode and execute instructions only if the current conditional
// branch in the EX stage is either not taken, or there is no
// conditional branch in the EX stage
if (instr_valid_i)
begin // now analyze the current instruction in the ID stage
is_decoding_o = 1'b1;
// decode and execute instructions only if the current conditional
// branch in the EX stage is either not taken, or there is no
// conditional branch in the EX stage
if (instr_valid_i) begin // now analyze the current instruction in the ID stage
is_decoding_o = 1'b1;
if (branch_set_i & ~jump_set_i & ~(mret_insn_i | ecall_insn_i | pipe_flush_i | ebrk_insn_i | illegal_insn_i | csr_status_i))
begin
pc_mux_o = PC_JUMP;
pc_set_o = 1'b1;
perf_tbranch_o = 1'b1;
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
if (dbg_req_i)
ctrl_fsm_ns = DBG_SIGNAL;
end
else if (~branch_set_i & jump_set_i & ~(mret_insn_i | ecall_insn_i | pipe_flush_i | ebrk_insn_i | illegal_insn_i | csr_status_i))
begin
pc_mux_o = PC_JUMP;
pc_set_o = 1'b1;
perf_jump_o = 1'b1;
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
end
else if (~branch_set_i & ~jump_set_i & (mret_insn_i | ecall_insn_i | pipe_flush_i | ebrk_insn_i | illegal_insn_i | csr_status_i))
begin
ctrl_fsm_ns = FLUSH;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end
else
begin
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
if (branch_set_i && !jump_set_i &&
!(mret_insn_i || ecall_insn_i || pipe_flush_i || ebrk_insn_i ||
illegal_insn_i || csr_status_i)) begin
pc_mux_o = PC_JUMP;
pc_set_o = 1'b1;
perf_tbranch_o = 1'b1;
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
if (dbg_req_i) begin
ctrl_fsm_ns = DBG_SIGNAL;
end
end else if (!branch_set_i && jump_set_i &&
!(mret_insn_i || ecall_insn_i || pipe_flush_i ||
ebrk_insn_i || illegal_insn_i || csr_status_i)) begin
pc_mux_o = PC_JUMP;
pc_set_o = 1'b1;
perf_jump_o = 1'b1;
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
end else if (!branch_set_i && !jump_set_i &&
(mret_insn_i || ecall_insn_i || pipe_flush_i ||
ebrk_insn_i || illegal_insn_i || csr_status_i)) begin
ctrl_fsm_ns = FLUSH;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end else begin
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
if ((irq_req_ctrl_i & irq_enable_int & ~instr_multicyle_i & ~branch_in_id_i) & ~(dbg_req_i & ~branch_taken_ex_i))
begin
ctrl_fsm_ns = IRQ_TAKEN;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end
else if (~(irq_req_ctrl_i & irq_enable_int & ~instr_multicyle_i & ~branch_in_id_i) & (dbg_req_i & ~branch_taken_ex_i))
begin
halt_if_o = 1'b1;
if (id_ready_i) begin
ctrl_fsm_ns = DBG_SIGNAL;
end
end
else
exc_kill_o = irq_req_ctrl_i & ~instr_multicyle_i & ~branch_in_id_i ? 1'b1 : 1'b0;
if (irq_req_ctrl_i && irq_enable_int && !instr_multicyle_i && !branch_in_id_i &&
!(dbg_req_i && !branch_taken_ex_i)) begin
ctrl_fsm_ns = IRQ_TAKEN;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end else if (!(irq_req_ctrl_i && irq_enable_int &&
!instr_multicyle_i && !branch_in_id_i) &&
(dbg_req_i && !branch_taken_ex_i)) begin
halt_if_o = 1'b1;
if (id_ready_i) begin
ctrl_fsm_ns = DBG_SIGNAL;
end
end else begin
exc_kill_o = irq_req_ctrl_i & ~instr_multicyle_i & ~branch_in_id_i;
end
end
else //~instr_valid_i
begin
if (irq_req_ctrl_i & irq_enable_int) begin
ctrl_fsm_ns = IRQ_TAKEN;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end
end else begin // !instr_valid_i
if (irq_req_ctrl_i && irq_enable_int) begin
ctrl_fsm_ns = IRQ_TAKEN;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end
end
end
// now we can signal to the debugger that our pipeline is empty and it
// can examine our current state
DBG_SIGNAL:
begin
DBG_SIGNAL: begin
dbg_ack_o = 1'b1;
halt_if_o = 1'b1;
ctrl_fsm_ns = DBG_WAIT;
end
DBG_SIGNAL_SLEEP:
begin
DBG_SIGNAL_SLEEP: begin
dbg_ack_o = 1'b1;
halt_if_o = 1'b1;
@ -357,8 +343,7 @@ module ibex_controller
// The Debugger is active in this state
// we wait until it is done and go back to DECODE
DBG_WAIT:
begin
DBG_WAIT: begin
halt_if_o = 1'b1;
if (dbg_jump_req_i) begin
@ -367,13 +352,12 @@ module ibex_controller
ctrl_fsm_ns = DBG_WAIT;
end
if (dbg_stall_i == 1'b0) begin
if (!dbg_stall_i) begin
ctrl_fsm_ns = DECODE;
end
end
IRQ_TAKEN:
begin
IRQ_TAKEN: begin
pc_mux_o = PC_EXCEPTION;
pc_set_o = 1'b1;
@ -392,8 +376,7 @@ module ibex_controller
end
// flush the pipeline, insert NOP
FLUSH:
begin
FLUSH: begin
halt_if_o = 1'b1;
halt_id_o = 1'b1;
@ -402,57 +385,62 @@ module ibex_controller
unique case(1'b1)
ecall_insn_i: begin
//ecall
pc_mux_o = PC_EXCEPTION;
pc_set_o = 1'b1;
csr_save_id_o = 1'b1;
csr_save_cause_o = 1'b1;
exc_pc_mux_o = EXC_PC_ECALL;
exc_cause_o = EXC_CAUSE_ECALL_MMODE;
csr_cause_o = EXC_CAUSE_ECALL_MMODE;
dbg_trap_o = dbg_settings_i[DBG_SETS_ECALL] | dbg_settings_i[DBG_SETS_SSTE];
//ecall
pc_mux_o = PC_EXCEPTION;
pc_set_o = 1'b1;
csr_save_id_o = 1'b1;
csr_save_cause_o = 1'b1;
exc_pc_mux_o = EXC_PC_ECALL;
exc_cause_o = EXC_CAUSE_ECALL_MMODE;
csr_cause_o = EXC_CAUSE_ECALL_MMODE;
dbg_trap_o = dbg_settings_i[DBG_SETS_ECALL] |
dbg_settings_i[DBG_SETS_SSTE];
end
illegal_insn_i: begin
//exceptions
pc_mux_o = PC_EXCEPTION;
pc_set_o = 1'b1;
csr_save_id_o = 1'b1;
csr_save_cause_o = 1'b1;
exc_pc_mux_o = EXC_PC_ILLINSN;
exc_cause_o = EXC_CAUSE_ILLEGAL_INSN;
csr_cause_o = EXC_CAUSE_ILLEGAL_INSN;
dbg_trap_o = dbg_settings_i[DBG_SETS_EILL] | dbg_settings_i[DBG_SETS_SSTE];
//exceptions
pc_mux_o = PC_EXCEPTION;
pc_set_o = 1'b1;
csr_save_id_o = 1'b1;
csr_save_cause_o = 1'b1;
exc_pc_mux_o = EXC_PC_ILLINSN;
exc_cause_o = EXC_CAUSE_ILLEGAL_INSN;
csr_cause_o = EXC_CAUSE_ILLEGAL_INSN;
dbg_trap_o = dbg_settings_i[DBG_SETS_EILL] |
dbg_settings_i[DBG_SETS_SSTE];
end
mret_insn_i: begin
//mret
pc_mux_o = PC_ERET;
pc_set_o = 1'b1;
csr_restore_mret_id_o = 1'b1;
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
//mret
pc_mux_o = PC_ERET;
pc_set_o = 1'b1;
csr_restore_mret_id_o = 1'b1;
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
end
ebrk_insn_i: begin
dbg_trap_o = 1'b1;//dbg_settings_i[DBG_SETS_EBRK] | dbg_settings_i[DBG_SETS_SSTE];;
exc_cause_o = EXC_CAUSE_BREAKPOINT;
dbg_trap_o = 1'b1; // dbg_settings_i[DBG_SETS_EBRK] |
// dbg_settings_i[DBG_SETS_SSTE];
exc_cause_o = EXC_CAUSE_BREAKPOINT;
end
csr_status_i: begin
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
end
pipe_flush_i: begin
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
end
default:;
endcase
if(~pipe_flush_i) begin
if(dbg_req_i)
if (!pipe_flush_i) begin
if (dbg_req_i) begin
ctrl_fsm_ns = DBG_SIGNAL;
else
end else begin
ctrl_fsm_ns = DECODE;
end
end else begin
if(dbg_req_i)
if (dbg_req_i) begin
ctrl_fsm_ns = DBG_SIGNAL_SLEEP;
else
end else begin
ctrl_fsm_ns = WAIT_SLEEP;
end
end
end
@ -471,33 +459,20 @@ module ibex_controller
// |____/ \__\__,_|_|_| \____\___/|_| |_|\__|_| \___/|_| //
// //
/////////////////////////////////////////////////////////////
always_comb
begin
deassert_we_o = 1'b0;
// deassert WE when the core is not decoding instructions
if (~is_decoding_o)
deassert_we_o = 1'b1;
// deassert WE in case of illegal instruction
if (illegal_insn_i)
deassert_we_o = 1'b1;
end
// deassert WE when the core is not decoding instructions
// or in case of illegal instruction
assign deassert_we_o = ~is_decoding_o | illegal_insn_i;
// Forwarding control unit
assign operand_a_fw_mux_sel_o = data_misaligned_i ? SEL_MISALIGNED : SEL_REGFILE;
// update registers
always_ff @(posedge clk , negedge rst_n)
begin : UPDATE_REGS
if ( rst_n == 1'b0 )
begin
always_ff @(posedge clk, negedge rst_n) begin : UPDATE_REGS
if (!rst_n) begin
ctrl_fsm_cs <= RESET;
//jump_done_q <= 1'b0;
end
else
begin
end else begin
ctrl_fsm_cs <= ctrl_fsm_ns;
// clear when id is valid (no instruction incoming)
//jump_done_q <= jump_done & (~id_ready_i);
@ -510,6 +485,7 @@ module ibex_controller
//----------------------------------------------------------------------------
`ifndef VERILATOR
assert property (
@(posedge clk) (~(dbg_req_i & irq_req_ctrl_i)) ) else $warning("Both dbg_req_i and irq_req_ctrl_i are active");
@(posedge clk) (!(dbg_req_i && irq_req_ctrl_i)) ) else
$warning("Both dbg_req_i and irq_req_ctrl_i are active");
`endif
endmodule // controller

View file

@ -23,74 +23,69 @@
`include "ibex_config.sv"
import ibex_defines::*;
/**
* Top level module of the ibex RISC-V core
*/
module ibex_core
#(
parameter N_EXT_PERF_COUNTERS = 0,
parameter RV32E = 0,
parameter RV32M = 1
)
(
// Clock and Reset
input logic clk_i,
input logic rst_ni,
module ibex_core #(
parameter N_EXT_PERF_COUNTERS = 1,
parameter RV32E = 0,
parameter RV32M = 1
) (
// Clock and Reset
input logic clk_i,
input logic rst_ni,
input logic clock_en_i, // enable clock, otherwise it is gated
input logic test_en_i, // enable all clock gates for testing
input logic clock_en_i, // enable clock, otherwise it is gated
input logic test_en_i, // enable all clock gates for testing
// Core ID, Cluster ID and boot address are considered more or less static
input logic [ 3:0] core_id_i,
input logic [ 5:0] cluster_id_i,
input logic [31:0] boot_addr_i,
// Core ID, Cluster ID and boot address are considered more or less static
input logic [ 3:0] core_id_i,
input logic [ 5:0] cluster_id_i,
input logic [31:0] boot_addr_i,
// Instruction memory interface
output logic instr_req_o,
input logic instr_gnt_i,
input logic instr_rvalid_i,
output logic [31:0] instr_addr_o,
input logic [31:0] instr_rdata_i,
// Instruction memory interface
output logic instr_req_o,
input logic instr_gnt_i,
input logic instr_rvalid_i,
output logic [31:0] instr_addr_o,
input logic [31:0] instr_rdata_i,
// Data memory interface
output logic data_req_o,
input logic data_gnt_i,
input logic data_rvalid_i,
output logic data_we_o,
output logic [3:0] data_be_o,
output logic [31:0] data_addr_o,
output logic [31:0] data_wdata_o,
input logic [31:0] data_rdata_i,
input logic data_err_i,
// Data memory interface
output logic data_req_o,
input logic data_gnt_i,
input logic data_rvalid_i,
output logic data_we_o,
output logic [3:0] data_be_o,
output logic [31:0] data_addr_o,
output logic [31:0] data_wdata_o,
input logic [31:0] data_rdata_i,
input logic data_err_i,
// Interrupt inputs
input logic irq_i, // level sensitive IR lines
input logic [4:0] irq_id_i,
output logic irq_ack_o, // irq ack
output logic [4:0] irq_id_o,
// Interrupt inputs
input logic irq_i, // level sensitive IR lines
input logic [4:0] irq_id_i,
output logic irq_ack_o, // irq ack
output logic [4:0] irq_id_o,
// Debug Interface
input logic debug_req_i,
output logic debug_gnt_o,
output logic debug_rvalid_o,
input logic [14:0] debug_addr_i,
input logic debug_we_i,
input logic [31:0] debug_wdata_i,
output logic [31:0] debug_rdata_o,
output logic debug_halted_o,
input logic debug_halt_i,
input logic debug_resume_i,
// Debug Interface
input logic debug_req_i,
output logic debug_gnt_o,
output logic debug_rvalid_o,
input logic [14:0] debug_addr_i,
input logic debug_we_i,
input logic [31:0] debug_wdata_i,
output logic [31:0] debug_rdata_o,
output logic debug_halted_o,
input logic debug_halt_i,
input logic debug_resume_i,
// CPU Control Signals
input logic fetch_enable_i,
// CPU Control Signals
input logic fetch_enable_i,
input logic [N_EXT_PERF_COUNTERS-1:0] ext_perf_counters_i
input logic [N_EXT_PERF_COUNTERS-1:0] ext_perf_counters_i
);
localparam N_HWLP = 2;
localparam N_HWLP_BITS = $clog2(N_HWLP);
import ibex_defines::*;
// IF/ID signals
logic instr_valid_id;
@ -117,7 +112,6 @@ module ibex_core
// Jump and branch target and decision (EX->IF)
logic [31:0] jump_target_ex;
logic branch_in_ex;
logic branch_decision;
logic ctrl_busy;
@ -161,7 +155,6 @@ module ibex_core
logic [1:0] data_reg_offset_ex;
logic data_req_ex;
logic [31:0] data_wdata_ex;
logic data_misaligned_ex;
logic [31:0] regfile_wdata_lsu;
// stall control
@ -171,9 +164,7 @@ module ibex_core
logic if_valid;
logic id_valid;
logic wb_valid;
logic lsu_ready_ex;
logic data_valid_lsu;
// Signals between instruction core interface and pipe (if and id stages)
@ -188,7 +179,6 @@ module ibex_core
logic csr_save_id;
logic [5:0] csr_cause;
logic csr_restore_mret_id;
logic csr_restore_uret_id;
// Debug Unit
logic [DBG_SETS_W-1:0] dbg_settings;
@ -243,9 +233,8 @@ module ibex_core
// interface to finish loading instructions
assign core_busy_int = if_busy | ctrl_busy | lsu_busy;
always_ff @(posedge clk_i, negedge rst_ni)
begin
if (rst_ni == 1'b0) begin
always_ff @(posedge clk_i, negedge rst_ni) begin
if (!rst_ni) begin
core_busy_q <= 1'b0;
end else begin
core_busy_q <= core_busy_int;
@ -264,12 +253,11 @@ module ibex_core
// main clock gate of the core
// generates all clocks except the one for the debug unit which is
// independent
clock_gating core_clock_gate_i
(
.clk_i ( clk_i ),
.en_i ( clock_en ),
.test_en_i ( test_en_i ),
.clk_o ( clk )
prim_clock_gating core_clock_gate_i (
.clk_i ( clk_i ),
.en_i ( clock_en ),
.test_en_i ( test_en_i ),
.clk_o ( clk )
);
//////////////////////////////////////////////////
@ -280,54 +268,53 @@ module ibex_core
// |___|_| |____/ |_/_/ \_\____|_____| //
// //
//////////////////////////////////////////////////
ibex_if_stage if_stage_i
(
.clk ( clk ),
.rst_n ( rst_ni ),
ibex_if_stage if_stage_i (
.clk ( clk ),
.rst_n ( rst_ni ),
// boot address (trap vector location)
.boot_addr_i ( boot_addr_i ),
// boot address (trap vector location)
.boot_addr_i ( boot_addr_i ),
// instruction request control
.req_i ( instr_req_int ),
// instruction request control
.req_i ( instr_req_int ),
// instruction cache interface
.instr_req_o ( instr_req_o ),
.instr_addr_o ( instr_addr_o ),
.instr_gnt_i ( instr_gnt_i ),
.instr_rvalid_i ( instr_rvalid_i ),
.instr_rdata_i ( instr_rdata_i ),
// instruction cache interface
.instr_req_o ( instr_req_o ),
.instr_addr_o ( instr_addr_o ),
.instr_gnt_i ( instr_gnt_i ),
.instr_rvalid_i ( instr_rvalid_i ),
.instr_rdata_i ( instr_rdata_i ),
// outputs to ID stage
.instr_valid_id_o ( instr_valid_id ),
.instr_rdata_id_o ( instr_rdata_id ),
.is_compressed_id_o ( is_compressed_id ),
.illegal_c_insn_id_o ( illegal_c_insn_id ),
.pc_if_o ( pc_if ),
.pc_id_o ( pc_id ),
// outputs to ID stage
.instr_valid_id_o ( instr_valid_id ),
.instr_rdata_id_o ( instr_rdata_id ),
.is_compressed_id_o ( is_compressed_id ),
.illegal_c_insn_id_o ( illegal_c_insn_id ),
.pc_if_o ( pc_if ),
.pc_id_o ( pc_id ),
// control signals
.clear_instr_valid_i ( clear_instr_valid ),
.pc_set_i ( pc_set ),
.exception_pc_reg_i ( mepc ), // exception return address
.pc_mux_i ( pc_mux_id ), // sel for pc multiplexer
.exc_pc_mux_i ( exc_pc_mux_id ),
.exc_vec_pc_mux_i ( exc_cause[4:0] ),
// control signals
.clear_instr_valid_i ( clear_instr_valid ),
.pc_set_i ( pc_set ),
.exception_pc_reg_i ( mepc ), // exception return address
.pc_mux_i ( pc_mux_id ), // sel for pc multiplexer
.exc_pc_mux_i ( exc_pc_mux_id ),
.exc_vec_pc_mux_i ( exc_cause[4:0] ),
// from debug unit
.dbg_jump_addr_i ( dbg_jump_addr ),
// from debug unit
.dbg_jump_addr_i ( dbg_jump_addr ),
// Jump targets
.jump_target_ex_i ( jump_target_ex ),
// Jump targets
.jump_target_ex_i ( jump_target_ex ),
// pipeline stalls
.halt_if_i ( halt_if ),
.id_ready_i ( id_ready ),
.if_valid_o ( if_valid ),
// pipeline stalls
.halt_if_i ( halt_if ),
.id_ready_i ( id_ready ),
.if_valid_o ( if_valid ),
.if_busy_o ( if_busy ),
.perf_imiss_o ( perf_imiss )
.if_busy_o ( if_busy ),
.perf_imiss_o ( perf_imiss )
);
@ -339,157 +326,150 @@ module ibex_core
// |___|____/ |____/ |_/_/ \_\____|_____| //
// //
/////////////////////////////////////////////////
ibex_id_stage
#(
.RV32E(RV32E),
.RV32M(RV32M)
)
id_stage_i
(
.clk ( clk ),
.rst_n ( rst_ni ),
ibex_id_stage #(
.RV32E(RV32E),
.RV32M(RV32M)
) id_stage_i (
.clk ( clk ),
.rst_n ( rst_ni ),
.test_en_i ( test_en_i ),
.test_en_i ( test_en_i ),
// Processor Enable
.fetch_enable_i ( fetch_enable_i ),
.ctrl_busy_o ( ctrl_busy ),
.core_ctrl_firstfetch_o ( core_ctrl_firstfetch ),
.is_decoding_o ( is_decoding ),
// Processor Enable
.fetch_enable_i ( fetch_enable_i ),
.ctrl_busy_o ( ctrl_busy ),
.core_ctrl_firstfetch_o ( core_ctrl_firstfetch ),
.is_decoding_o ( is_decoding ),
// Interface to instruction memory
.instr_valid_i ( instr_valid_id ),
.instr_rdata_i ( instr_rdata_id ),
.instr_req_o ( instr_req_int ),
// Interface to instruction memory
.instr_valid_i ( instr_valid_id ),
.instr_rdata_i ( instr_rdata_id ),
.instr_req_o ( instr_req_int ),
// Jumps and branches
.branch_in_ex_o ( branch_in_ex ),
.branch_decision_i ( branch_decision ),
// Jumps and branches
.branch_decision_i ( branch_decision ),
// IF and ID control signals
.clear_instr_valid_o ( clear_instr_valid ),
.pc_set_o ( pc_set ),
.pc_mux_o ( pc_mux_id ),
.exc_pc_mux_o ( exc_pc_mux_id ),
.exc_cause_o ( exc_cause ),
// IF and ID control signals
.clear_instr_valid_o ( clear_instr_valid ),
.pc_set_o ( pc_set ),
.pc_mux_o ( pc_mux_id ),
.exc_pc_mux_o ( exc_pc_mux_id ),
.exc_cause_o ( exc_cause ),
.illegal_c_insn_i ( illegal_c_insn_id ),
.is_compressed_i ( is_compressed_id ),
.illegal_c_insn_i ( illegal_c_insn_id ),
.is_compressed_i ( is_compressed_id ),
.pc_id_i ( pc_id ),
.pc_id_i ( pc_id ),
// Stalls
.halt_if_o ( halt_if ),
// Stalls
.halt_if_o ( halt_if ),
.id_ready_o ( id_ready ),
.ex_ready_i ( ex_ready ),
.id_ready_o ( id_ready ),
.ex_ready_i ( ex_ready ),
.id_valid_o ( id_valid ),
.id_valid_o ( id_valid ),
.alu_operator_ex_o ( alu_operator_ex ),
.alu_operand_a_ex_o ( alu_operand_a_ex ),
.alu_operand_b_ex_o ( alu_operand_b_ex ),
.alu_operator_ex_o ( alu_operator_ex ),
.alu_operand_a_ex_o ( alu_operand_a_ex ),
.alu_operand_b_ex_o ( alu_operand_b_ex ),
.mult_en_ex_o ( mult_en_ex ),
.div_en_ex_o ( div_en_ex ),
.multdiv_operator_ex_o ( multdiv_operator_ex ),
.multdiv_signed_mode_ex_o ( multdiv_signed_mode_ex ),
.multdiv_operand_a_ex_o ( multdiv_operand_a_ex ),
.multdiv_operand_b_ex_o ( multdiv_operand_b_ex ),
.mult_en_ex_o ( mult_en_ex ),
.div_en_ex_o ( div_en_ex ),
.multdiv_operator_ex_o ( multdiv_operator_ex ),
.multdiv_signed_mode_ex_o ( multdiv_signed_mode_ex ),
.multdiv_operand_a_ex_o ( multdiv_operand_a_ex ),
.multdiv_operand_b_ex_o ( multdiv_operand_b_ex ),
// CSR ID/EX
.csr_access_ex_o ( csr_access_ex ),
.csr_op_ex_o ( csr_op_ex ),
.csr_cause_o ( csr_cause ),
.csr_save_if_o ( csr_save_if ), // control signal to save pc
.csr_save_id_o ( csr_save_id ), // control signal to save pc
.csr_restore_mret_id_o ( csr_restore_mret_id ), // control signal to restore pc
.csr_save_cause_o ( csr_save_cause ),
// CSR ID/EX
.csr_access_ex_o ( csr_access_ex ),
.csr_op_ex_o ( csr_op_ex ),
.csr_cause_o ( csr_cause ),
.csr_save_if_o ( csr_save_if ), // control signal to save pc
.csr_save_id_o ( csr_save_id ), // control signal to save pc
.csr_restore_mret_id_o ( csr_restore_mret_id ), // control signal to restore pc
.csr_save_cause_o ( csr_save_cause ),
// LSU
.data_req_ex_o ( data_req_ex ), // to load store unit
.data_we_ex_o ( data_we_ex ), // to load store unit
.data_type_ex_o ( data_type_ex ), // to load store unit
.data_sign_ext_ex_o ( data_sign_ext_ex ), // to load store unit
.data_reg_offset_ex_o ( data_reg_offset_ex ), // to load store unit
.data_wdata_ex_o ( data_wdata_ex ), // to load store unit
// LSU
.data_req_ex_o ( data_req_ex ), // to load store unit
.data_we_ex_o ( data_we_ex ), // to load store unit
.data_type_ex_o ( data_type_ex ), // to load store unit
.data_sign_ext_ex_o ( data_sign_ext_ex ), // to load store unit
.data_reg_offset_ex_o ( data_reg_offset_ex ), // to load store unit
.data_wdata_ex_o ( data_wdata_ex ), // to load store unit
.data_misaligned_i ( data_misaligned ),
.misaligned_addr_i ( misaligned_addr ),
.data_misaligned_i ( data_misaligned ),
.misaligned_addr_i ( misaligned_addr ),
// Interrupt Signals
.irq_i ( irq_i ), // incoming interrupts
.irq_id_i ( irq_id_i ),
.m_irq_enable_i ( m_irq_enable ),
.irq_ack_o ( irq_ack_o ),
.irq_id_o ( irq_id_o ),
// Interrupt Signals
.irq_i ( irq_i ), // incoming interrupts
.irq_id_i ( irq_id_i ),
.m_irq_enable_i ( m_irq_enable ),
.irq_ack_o ( irq_ack_o ),
.irq_id_o ( irq_id_o ),
.lsu_load_err_i ( lsu_load_err ),
.lsu_store_err_i ( lsu_store_err ),
.lsu_load_err_i ( lsu_load_err ),
.lsu_store_err_i ( lsu_store_err ),
// Debug Unit Signals
.dbg_settings_i ( dbg_settings ),
.dbg_req_i ( dbg_req ),
.dbg_ack_o ( dbg_ack ),
.dbg_stall_i ( dbg_stall ),
.dbg_trap_o ( dbg_trap ),
// Debug Unit Signals
.dbg_settings_i ( dbg_settings ),
.dbg_req_i ( dbg_req ),
.dbg_ack_o ( dbg_ack ),
.dbg_stall_i ( dbg_stall ),
.dbg_trap_o ( dbg_trap ),
.dbg_reg_rreq_i ( dbg_reg_rreq ),
.dbg_reg_raddr_i ( dbg_reg_raddr ),
.dbg_reg_rdata_o ( dbg_reg_rdata ),
.dbg_reg_rreq_i ( dbg_reg_rreq ),
.dbg_reg_raddr_i ( dbg_reg_raddr ),
.dbg_reg_rdata_o ( dbg_reg_rdata ),
.dbg_reg_wreq_i ( dbg_reg_wreq ),
.dbg_reg_waddr_i ( dbg_reg_waddr ),
.dbg_reg_wdata_i ( dbg_reg_wdata ),
.dbg_reg_wreq_i ( dbg_reg_wreq ),
.dbg_reg_waddr_i ( dbg_reg_waddr ),
.dbg_reg_wdata_i ( dbg_reg_wdata ),
.dbg_jump_req_i ( dbg_jump_req ),
.dbg_jump_req_i ( dbg_jump_req ),
// write data to commit in the register file
.regfile_wdata_lsu_i ( regfile_wdata_lsu ),
.regfile_wdata_ex_i ( regfile_wdata_ex ),
.csr_rdata_i ( csr_rdata ),
// write data to commit in the register file
.regfile_wdata_lsu_i ( regfile_wdata_lsu ),
.regfile_wdata_ex_i ( regfile_wdata_ex ),
.csr_rdata_i ( csr_rdata ),
// Performance Counters
.perf_jump_o ( perf_jump ),
.perf_branch_o ( perf_branch ),
.perf_tbranch_o ( perf_tbranch )
// Performance Counters
.perf_jump_o ( perf_jump ),
.perf_branch_o ( perf_branch ),
.perf_tbranch_o ( perf_tbranch )
);
ibex_ex_block
#(
//change the localparam MULT_TYPE to 0 or 1
//if you want a SLOW or FAST multiplier
.RV32M(RV32M)
)
ex_block_i
(
.clk ( clk ),
.rst_n ( rst_ni ),
// Alu signals from ID stage
//TODO: hot encoding
.alu_operator_i ( alu_operator_ex ),
.multdiv_operator_i ( multdiv_operator_ex ),
.alu_operand_a_i ( alu_operand_a_ex ),
.alu_operand_b_i ( alu_operand_b_ex ),
ibex_ex_block #(
//change the localparam MULT_TYPE to 0 or 1
//if you want a SLOW or FAST multiplier
.RV32M(RV32M)
) ex_block_i (
.clk ( clk ),
.rst_n ( rst_ni ),
// Alu signals from ID stage
//TODO: hot encoding
.alu_operator_i ( alu_operator_ex ),
.multdiv_operator_i ( multdiv_operator_ex ),
.alu_operand_a_i ( alu_operand_a_ex ),
.alu_operand_b_i ( alu_operand_b_ex ),
// Multipler
.mult_en_i ( mult_en_ex ),
.div_en_i ( div_en_ex ),
.multdiv_signed_mode_i ( multdiv_signed_mode_ex),
.multdiv_operand_a_i ( multdiv_operand_a_ex ),
.multdiv_operand_b_i ( multdiv_operand_b_ex ),
.alu_adder_result_ex_o ( alu_adder_result_ex ), // from ALU to LSU
.regfile_wdata_ex_o ( regfile_wdata_ex ),
// Multipler
.mult_en_i ( mult_en_ex ),
.div_en_i ( div_en_ex ),
.multdiv_signed_mode_i ( multdiv_signed_mode_ex),
.multdiv_operand_a_i ( multdiv_operand_a_ex ),
.multdiv_operand_b_i ( multdiv_operand_b_ex ),
.alu_adder_result_ex_o ( alu_adder_result_ex ), // from ALU to LSU
.regfile_wdata_ex_o ( regfile_wdata_ex ),
// To IF: Jump and branch target and decision
.jump_target_o ( jump_target_ex ),
.branch_decision_o ( branch_decision ),
// To IF: Jump and branch target and decision
.jump_target_o ( jump_target_ex ),
.branch_decision_o ( branch_decision ),
.lsu_en_i ( data_req_ex ),
.lsu_ready_ex_i ( data_valid_lsu ),
.ex_ready_o ( ex_ready )
.lsu_en_i ( data_req_ex ),
.lsu_ready_ex_i ( data_valid_lsu ),
.ex_ready_o ( ex_ready )
);
////////////////////////////////////////////////////////////////////////////////////////
@ -501,46 +481,45 @@ module ibex_core
// //
////////////////////////////////////////////////////////////////////////////////////////
ibex_load_store_unit load_store_unit_i
(
.clk ( clk ),
.rst_n ( rst_ni ),
ibex_load_store_unit load_store_unit_i (
.clk ( clk ),
.rst_n ( rst_ni ),
//output to data memory
.data_req_o ( data_req_o ),
.data_gnt_i ( data_gnt_i ),
.data_rvalid_i ( data_rvalid_i ),
.data_err_i ( data_err_i ),
//output to data memory
.data_req_o ( data_req_o ),
.data_gnt_i ( data_gnt_i ),
.data_rvalid_i ( data_rvalid_i ),
.data_err_i ( data_err_i ),
.data_addr_o ( data_addr_o ),
.data_we_o ( data_we_o ),
.data_be_o ( data_be_o ),
.data_wdata_o ( data_wdata_o ),
.data_rdata_i ( data_rdata_i ),
.data_addr_o ( data_addr_o ),
.data_we_o ( data_we_o ),
.data_be_o ( data_be_o ),
.data_wdata_o ( data_wdata_o ),
.data_rdata_i ( data_rdata_i ),
// signal from ex stage
.data_we_ex_i ( data_we_ex ),
.data_type_ex_i ( data_type_ex ),
.data_wdata_ex_i ( data_wdata_ex ),
.data_reg_offset_ex_i ( data_reg_offset_ex ),
.data_sign_ext_ex_i ( data_sign_ext_ex ),
// signal from ex stage
.data_we_ex_i ( data_we_ex ),
.data_type_ex_i ( data_type_ex ),
.data_wdata_ex_i ( data_wdata_ex ),
.data_reg_offset_ex_i ( data_reg_offset_ex ),
.data_sign_ext_ex_i ( data_sign_ext_ex ),
.data_rdata_ex_o ( regfile_wdata_lsu ),
.data_req_ex_i ( data_req_ex ),
.data_rdata_ex_o ( regfile_wdata_lsu ),
.data_req_ex_i ( data_req_ex ),
.adder_result_ex_i ( alu_adder_result_ex),
.adder_result_ex_i ( alu_adder_result_ex),
.data_misaligned_o ( data_misaligned ),
.misaligned_addr_o ( misaligned_addr ),
.data_misaligned_o ( data_misaligned ),
.misaligned_addr_o ( misaligned_addr ),
// exception signals
.load_err_o ( lsu_load_err ),
.store_err_o ( lsu_store_err ),
// exception signals
.load_err_o ( lsu_load_err ),
.store_err_o ( lsu_store_err ),
// control signals
.data_valid_o ( data_valid_lsu ),
.lsu_update_addr_o ( ),
.busy_o ( lsu_busy )
// control signals
.data_valid_o ( data_valid_lsu ),
.lsu_update_addr_o ( ),
.busy_o ( lsu_busy )
);
@ -554,56 +533,53 @@ module ibex_core
// Control and Status Registers //
//////////////////////////////////////
ibex_cs_registers
#(
.N_EXT_CNT ( N_EXT_PERF_COUNTERS )
)
cs_registers_i
(
.clk ( clk ),
.rst_n ( rst_ni ),
ibex_cs_registers #(
.N_EXT_CNT ( N_EXT_PERF_COUNTERS )
) cs_registers_i (
.clk ( clk ),
.rst_n ( rst_ni ),
// Core and Cluster ID from outside
.core_id_i ( core_id_i ),
.cluster_id_i ( cluster_id_i ),
// boot address
.boot_addr_i ( boot_addr_i[31:8] ),
// Interface to CSRs (SRAM like)
.csr_access_i ( csr_access ),
.csr_addr_i ( csr_addr ),
.csr_wdata_i ( csr_wdata ),
.csr_op_i ( csr_op ),
.csr_rdata_o ( csr_rdata ),
// Core and Cluster ID from outside
.core_id_i ( core_id_i ),
.cluster_id_i ( cluster_id_i ),
// boot address
.boot_addr_i ( boot_addr_i[31:8] ),
// Interface to CSRs (SRAM like)
.csr_access_i ( csr_access ),
.csr_addr_i ( csr_addr ),
.csr_wdata_i ( csr_wdata ),
.csr_op_i ( csr_op ),
.csr_rdata_o ( csr_rdata ),
// Interrupt related control signals
.m_irq_enable_o ( m_irq_enable ),
.mepc_o ( mepc ),
// Interrupt related control signals
.m_irq_enable_o ( m_irq_enable ),
.mepc_o ( mepc ),
.pc_if_i ( pc_if ),
.pc_id_i ( pc_id ),
.pc_if_i ( pc_if ),
.pc_id_i ( pc_id ),
.csr_save_if_i ( csr_save_if ),
.csr_save_id_i ( csr_save_id ),
.csr_restore_mret_i ( csr_restore_mret_id ),
.csr_cause_i ( csr_cause ),
.csr_save_cause_i ( csr_save_cause ),
.csr_save_if_i ( csr_save_if ),
.csr_save_id_i ( csr_save_id ),
.csr_restore_mret_i ( csr_restore_mret_id ),
.csr_cause_i ( csr_cause ),
.csr_save_cause_i ( csr_save_cause ),
// performance counter related signals
.if_valid_i ( if_valid ),
.id_valid_i ( id_valid ),
.is_compressed_i ( is_compressed_id ),
.is_decoding_i ( is_decoding ),
// performance counter related signals
.if_valid_i ( if_valid ),
.id_valid_i ( id_valid ),
.is_compressed_i ( is_compressed_id ),
.is_decoding_i ( is_decoding ),
.imiss_i ( perf_imiss ),
.pc_set_i ( pc_set ),
.jump_i ( perf_jump ),
.branch_i ( perf_branch ),
.branch_taken_i ( perf_tbranch ),
.mem_load_i ( data_req_o & data_gnt_i & (~data_we_o) ),
.mem_store_i ( data_req_o & data_gnt_i & data_we_o ),
.imiss_i ( perf_imiss ),
.pc_set_i ( pc_set ),
.jump_i ( perf_jump ),
.branch_i ( perf_branch ),
.branch_taken_i ( perf_tbranch ),
.mem_load_i ( data_req_o & data_gnt_i & (~data_we_o) ),
.mem_store_i ( data_req_o & data_gnt_i & data_we_o ),
.ext_counters_i ( ext_perf_counters_i )
.ext_counters_i ( ext_perf_counters_i )
);
// Mux for CSR access through Debug Unit
@ -625,108 +601,106 @@ module ibex_core
// //
/////////////////////////////////////////////////////////////
ibex_debug_unit debug_unit_i
(
.clk ( clk_i ), // always-running clock for debug
.rst_n ( rst_ni ),
ibex_debug_unit debug_unit_i (
.clk ( clk_i ), // always-running clock for debug
.rst_n ( rst_ni ),
// Debug Interface
.debug_req_i ( debug_req_i ),
.debug_gnt_o ( debug_gnt_o ),
.debug_rvalid_o ( debug_rvalid_o ),
.debug_addr_i ( debug_addr_i ),
.debug_we_i ( debug_we_i ),
.debug_wdata_i ( debug_wdata_i ),
.debug_rdata_o ( debug_rdata_o ),
.debug_halt_i ( debug_halt_i ),
.debug_resume_i ( debug_resume_i ),
.debug_halted_o ( debug_halted_o ),
// Debug Interface
.debug_req_i ( debug_req_i ),
.debug_gnt_o ( debug_gnt_o ),
.debug_rvalid_o ( debug_rvalid_o ),
.debug_addr_i ( debug_addr_i ),
.debug_we_i ( debug_we_i ),
.debug_wdata_i ( debug_wdata_i ),
.debug_rdata_o ( debug_rdata_o ),
.debug_halt_i ( debug_halt_i ),
.debug_resume_i ( debug_resume_i ),
.debug_halted_o ( debug_halted_o ),
// To/From Core
.settings_o ( dbg_settings ),
.trap_i ( dbg_trap ),
.exc_cause_i ( exc_cause ),
.stall_o ( dbg_stall ),
.dbg_req_o ( dbg_req ),
.dbg_ack_i ( dbg_ack ),
// To/From Core
.settings_o ( dbg_settings ),
.trap_i ( dbg_trap ),
.exc_cause_i ( exc_cause ),
.stall_o ( dbg_stall ),
.dbg_req_o ( dbg_req ),
.dbg_ack_i ( dbg_ack ),
// register file read port
.regfile_rreq_o ( dbg_reg_rreq ),
.regfile_raddr_o ( dbg_reg_raddr ),
.regfile_rdata_i ( dbg_reg_rdata ),
// register file read port
.regfile_rreq_o ( dbg_reg_rreq ),
.regfile_raddr_o ( dbg_reg_raddr ),
.regfile_rdata_i ( dbg_reg_rdata ),
// register file write port
.regfile_wreq_o ( dbg_reg_wreq ),
.regfile_waddr_o ( dbg_reg_waddr ),
.regfile_wdata_o ( dbg_reg_wdata ),
// register file write port
.regfile_wreq_o ( dbg_reg_wreq ),
.regfile_waddr_o ( dbg_reg_waddr ),
.regfile_wdata_o ( dbg_reg_wdata ),
// CSR read/write port
.csr_req_o ( dbg_csr_req ),
.csr_addr_o ( dbg_csr_addr ),
.csr_we_o ( dbg_csr_we ),
.csr_wdata_o ( dbg_csr_wdata ),
.csr_rdata_i ( csr_rdata ),
// CSR read/write port
.csr_req_o ( dbg_csr_req ),
.csr_addr_o ( dbg_csr_addr ),
.csr_we_o ( dbg_csr_we ),
.csr_wdata_o ( dbg_csr_wdata ),
.csr_rdata_i ( csr_rdata ),
// signals for PPC and NPC
.pc_if_i ( pc_if ), // from IF stage
.pc_id_i ( pc_id ), // from ID stage
.instr_valid_id_i ( instr_valid_id ),
// signals for PPC and NPC
.pc_if_i ( pc_if ), // from IF stage
.pc_id_i ( pc_id ), // from ID stage
.sleeping_i ( sleeping ),
.sleeping_i ( sleeping ),
.jump_addr_o ( dbg_jump_addr ), // PC from debug unit
.jump_req_o ( dbg_jump_req ) // set PC to new value
.jump_addr_o ( dbg_jump_addr ), // PC from debug unit
.jump_req_o ( dbg_jump_req ) // set PC to new value
);
`ifndef VERILATOR
`ifdef TRACE_EXECUTION
ibex_tracer ibex_tracer_i
(
.clk ( clk_i ), // always-running clock for tracing
.rst_n ( rst_ni ),
ibex_tracer ibex_tracer_i (
.clk ( clk_i ), // always-running clock for tracing
.rst_n ( rst_ni ),
.fetch_enable ( fetch_enable_i ),
.core_id ( core_id_i ),
.cluster_id ( cluster_id_i ),
.fetch_enable ( fetch_enable_i ),
.core_id ( core_id_i ),
.cluster_id ( cluster_id_i ),
.pc ( id_stage_i.pc_id_i ),
.instr ( id_stage_i.instr ),
.compressed ( id_stage_i.is_compressed_i ),
.id_valid ( id_stage_i.id_valid_o ),
.is_decoding ( id_stage_i.is_decoding_o ),
.is_branch ( id_stage_i.branch_in_id ),
.branch_taken ( id_stage_i.branch_set_q ),
.pipe_flush ( id_stage_i.controller_i.pipe_flush_i ),
.mret_insn ( id_stage_i.controller_i.mret_insn_i ),
.ecall_insn ( id_stage_i.controller_i.ecall_insn_i ),
.ebrk_insn ( id_stage_i.controller_i.ebrk_insn_i ),
.csr_status ( id_stage_i.controller_i.csr_status_i ),
.rs1_value ( id_stage_i.operand_a_fw_id ),
.rs2_value ( id_stage_i.operand_b_fw_id ),
.pc ( id_stage_i.pc_id_i ),
.instr ( id_stage_i.instr ),
.compressed ( id_stage_i.is_compressed_i ),
.id_valid ( id_stage_i.id_valid_o ),
.is_decoding ( id_stage_i.is_decoding_o ),
.is_branch ( id_stage_i.branch_in_id ),
.branch_taken ( id_stage_i.branch_set_q ),
.pipe_flush ( id_stage_i.controller_i.pipe_flush_i ),
.mret_insn ( id_stage_i.controller_i.mret_insn_i ),
.ecall_insn ( id_stage_i.controller_i.ecall_insn_i ),
.ebrk_insn ( id_stage_i.controller_i.ebrk_insn_i ),
.csr_status ( id_stage_i.controller_i.csr_status_i ),
.rs1_value ( id_stage_i.operand_a_fw_id ),
.rs2_value ( id_stage_i.operand_b_fw_id ),
.lsu_value ( data_wdata_ex ),
.lsu_value ( data_wdata_ex ),
.ex_reg_addr ( id_stage_i.regfile_waddr_mux ),
.ex_reg_we ( id_stage_i.regfile_we_mux ),
.ex_reg_wdata ( id_stage_i.regfile_wdata_mux ),
.data_valid_lsu ( data_valid_lsu ),
.ex_data_addr ( data_addr_o ),
.ex_data_req ( data_req_o ),
.ex_data_gnt ( data_gnt_i ),
.ex_data_we ( data_we_o ),
.ex_reg_addr ( id_stage_i.regfile_waddr_mux ),
.ex_reg_we ( id_stage_i.regfile_we_mux ),
.ex_reg_wdata ( id_stage_i.regfile_wdata_mux ),
.data_valid_lsu ( data_valid_lsu ),
.ex_data_addr ( data_addr_o ),
.ex_data_req ( data_req_o ),
.ex_data_gnt ( data_gnt_i ),
.ex_data_we ( data_we_o ),
.ex_data_wdata ( data_wdata_o ),
.ex_data_wdata ( data_wdata_o ),
.lsu_reg_wdata ( regfile_wdata_lsu ),
.lsu_reg_wdata ( regfile_wdata_lsu ),
.imm_u_type ( id_stage_i.imm_u_type ),
.imm_uj_type ( id_stage_i.imm_uj_type ),
.imm_i_type ( id_stage_i.imm_i_type ),
.imm_iz_type ( id_stage_i.imm_iz_type[11:0] ),
.imm_z_type ( id_stage_i.imm_z_type ),
.imm_s_type ( id_stage_i.imm_s_type ),
.imm_sb_type ( id_stage_i.imm_sb_type )
.imm_u_type ( id_stage_i.imm_u_type ),
.imm_uj_type ( id_stage_i.imm_uj_type ),
.imm_i_type ( id_stage_i.imm_i_type ),
.imm_iz_type ( id_stage_i.imm_iz_type[11:0] ),
.imm_z_type ( id_stage_i.imm_z_type ),
.imm_s_type ( id_stage_i.imm_s_type ),
.imm_sb_type ( id_stage_i.imm_sb_type )
);
`endif
`endif
endmodule

View file

@ -21,8 +21,6 @@
`include "ibex_config.sv"
import ibex_defines::*;
`ifndef PULP_FPGA_EMUL
`ifdef SYNTHESIS
`define ASIC_SYNTHESIS
@ -35,59 +33,55 @@ import ibex_defines::*;
* Control and Status Registers (CSRs) loosely following the RiscV draft
* priviledged instruction set spec (v1.9)
*/
module ibex_cs_registers
#(
parameter N_EXT_CNT = 0
)
(
// Clock and Reset
input logic clk,
input logic rst_n,
module ibex_cs_registers #(parameter N_EXT_CNT = 0) (
// Clock and Reset
input logic clk,
input logic rst_n,
// Core and Cluster ID
input logic [3:0] core_id_i,
input logic [5:0] cluster_id_i,
// Core and Cluster ID
input logic [3:0] core_id_i,
input logic [5:0] cluster_id_i,
// Used for boot address
input logic [23:0] boot_addr_i,
input logic [31:0] boot_addr_i,
// Interface to registers (SRAM like)
input logic csr_access_i,
input logic [11:0] csr_addr_i,
input logic [31:0] csr_wdata_i,
input logic [1:0] csr_op_i,
output logic [31:0] csr_rdata_o,
// Interface to registers (SRAM like)
input logic csr_access_i,
input logic [11:0] csr_addr_i,
input logic [31:0] csr_wdata_i,
input logic [1:0] csr_op_i,
output logic [31:0] csr_rdata_o,
// Interrupts
output logic m_irq_enable_o,
output logic [31:0] mepc_o,
// Interrupts
output logic m_irq_enable_o,
output logic [31:0] mepc_o,
input logic [31:0] pc_if_i,
input logic [31:0] pc_id_i,
input logic [31:0] pc_if_i,
input logic [31:0] pc_id_i,
input logic csr_save_if_i,
input logic csr_save_id_i,
input logic csr_restore_mret_i,
input logic csr_save_if_i,
input logic csr_save_id_i,
input logic csr_restore_mret_i,
input logic [5:0] csr_cause_i,
input logic csr_save_cause_i,
input logic [5:0] csr_cause_i,
input logic csr_save_cause_i,
// Performance Counters
input logic if_valid_i, // IF stage gives a new instruction
input logic id_valid_i, // ID stage is done
input logic is_compressed_i, // compressed instruction in ID
input logic is_decoding_i, // controller is in DECODE state
// Performance Counters
input logic if_valid_i, // IF stage gives a new instruction
input logic id_valid_i, // ID stage is done
input logic is_compressed_i, // compressed instruction in ID
input logic is_decoding_i, // controller is in DECODE state
input logic imiss_i, // instruction fetch
input logic pc_set_i, // pc was set to a new value
input logic jump_i, // jump instruction seen (j, jr, jal, jalr)
input logic branch_i, // branch instruction seen (bf, bnf)
input logic branch_taken_i, // branch was taken
input logic mem_load_i, // load from memory in this cycle
input logic mem_store_i, // store to memory in this cycle
input logic [N_EXT_CNT-1:0] ext_counters_i
input logic imiss_i, // instruction fetch
input logic pc_set_i, // pc was set to a new value
input logic jump_i, // jump instruction seen (j, jr, jal, jalr)
input logic branch_i, // branch instruction seen (bf, bnf)
input logic branch_taken_i, // branch was taken
input logic mem_load_i, // load from memory in this cycle
input logic mem_store_i, // store to memory in this cycle
input logic [N_EXT_CNT-1:0] ext_counters_i
);
import ibex_defines::*;
localparam N_PERF_COUNTERS = 11 + N_EXT_CNT;
@ -121,12 +115,12 @@ module ibex_cs_registers
} Status_t;
// Performance Counter Signals
logic id_valid_q;
logic [N_PERF_COUNTERS-1:0] PCCR_in; // input signals for each counter category
logic [N_PERF_COUNTERS-1:0] PCCR_inc, PCCR_inc_q; // should the counter be increased?
logic [N_PERF_REGS-1:0] [31:0] PCCR_q, PCCR_n; // performance counters counter register
logic [1:0] PCMR_n, PCMR_q; // mode register, controls saturation and global enable
logic [1:0] PCMR_n, PCMR_q; // mode register, controls saturation and
// global enable
logic [N_PERF_COUNTERS-1:0] PCER_n, PCER_q; // selected counter input
logic [31:0] perf_rdata;
@ -156,9 +150,8 @@ module ibex_cs_registers
////////////////////////////////////////////
// read logic
always_comb
begin
csr_rdata_int = '0;
always_comb begin
csr_rdata_int = '0;
case (csr_addr_i)
// mstatus: always M-mode, contains IE bit
@ -172,7 +165,7 @@ module ibex_cs_registers
3'h0
};
// mtvec: machine trap-handler base address
12'h305: csr_rdata_int = {boot_addr_i, 8'h0};
12'h305: csr_rdata_int = {boot_addr_i[31:8], 8'h0};
// mepc: exception program counter
12'h341: csr_rdata_int = mepc_q;
// mcause: exception cause
@ -181,14 +174,13 @@ module ibex_cs_registers
// mhartid: unique hardware thread id
12'hF14: csr_rdata_int = {21'b0, cluster_id_i[5:0], 1'b0, core_id_i[3:0]};
default: ;
default: ;
endcase
end
// write logic
always_comb
begin
always_comb begin
mepc_n = mepc_q;
mstatus_n = mstatus_q;
mcause_n = mcause_q;
@ -196,7 +188,7 @@ module ibex_cs_registers
case (csr_addr_i)
// mstatus: IE bit
12'h300: if (csr_we_int) begin
mstatus_n = '{
mstatus_n = '{
mie: csr_wdata_int[`MSTATUS_MIE_BITS],
mpie: csr_wdata_int[`MSTATUS_MPIE_BITS],
mpp: PrivLvl_t'(PRIV_LVL_M)
@ -206,7 +198,7 @@ module ibex_cs_registers
12'h341: if (csr_we_int) mepc_n = csr_wdata_int;
// mcause
12'h342: if (csr_we_int) mcause_n = {csr_wdata_int[31], csr_wdata_int[4:0]};
default: ;
default: ;
endcase
// exception controller gets priority over other writes
@ -231,54 +223,37 @@ module ibex_cs_registers
end //csr_restore_mret_i
default:;
endcase
end
// CSR operation logic
always_comb
begin
always_comb begin
csr_wdata_int = csr_wdata_i;
csr_we_int = 1'b1;
unique case (csr_op_i)
CSR_OP_WRITE: csr_wdata_int = csr_wdata_i;
CSR_OP_SET: csr_wdata_int = csr_wdata_i | csr_rdata_o;
CSR_OP_CLEAR: csr_wdata_int = (~csr_wdata_i) & csr_rdata_o;
CSR_OP_WRITE: csr_wdata_int = csr_wdata_i;
CSR_OP_SET: csr_wdata_int = csr_wdata_i | csr_rdata_o;
CSR_OP_CLEAR: csr_wdata_int = ~csr_wdata_i & csr_rdata_o;
CSR_OP_NONE: begin
csr_wdata_int = csr_wdata_i;
csr_we_int = 1'b0;
end
default:;
endcase
end
// output mux
always_comb
begin
csr_rdata_o = csr_rdata_int;
// performance counters
if (is_pccr || is_pcer || is_pcmr)
csr_rdata_o = perf_rdata;
end
// output mux, possibly choose performance counters
assign csr_rdata_o = (is_pccr || is_pcer || is_pcmr) ? perf_rdata : csr_rdata_int;
// directly output some registers
assign m_irq_enable_o = mstatus_q.mie;
assign mepc_o = mepc_q;
// actual registers
always_ff @(posedge clk, negedge rst_n)
begin
if (rst_n == 1'b0)
begin
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
mstatus_q <= '{
mie: 1'b0,
mpie: 1'b0,
@ -286,11 +261,9 @@ module ibex_cs_registers
};
mepc_q <= '0;
mcause_q <= '0;
end
else
begin
end else begin
// update CSRs
mstatus_q <= '{
mstatus_q <= '{
mie: mstatus_n.mie,
mpie: mstatus_n.mpie,
mpp: PRIV_LVL_M
@ -313,26 +286,22 @@ module ibex_cs_registers
assign PCCR_in[1] = if_valid_i; // instruction counter
assign PCCR_in[2] = 1'b0; // Reserved
assign PCCR_in[3] = 1'b0; // Reserved
assign PCCR_in[4] = imiss_i & (~pc_set_i); // cycles waiting for instruction fetches, excluding jumps and branches
assign PCCR_in[4] = imiss_i & (~pc_set_i); // cycles waiting for instruction fetches,
// excluding jumps and branches
assign PCCR_in[5] = mem_load_i; // nr of loads
assign PCCR_in[6] = mem_store_i; // nr of stores
assign PCCR_in[7] = jump_i; // nr of jumps (unconditional)
assign PCCR_in[8] = branch_i; // nr of branches (conditional)
assign PCCR_in[9] = branch_taken_i; // nr of taken branches (conditional)
assign PCCR_in[10] = id_valid_i & is_decoding_i & is_compressed_i; // compressed instruction counter
assign PCCR_in[10] = id_valid_i & is_decoding_i & is_compressed_i; // compressed intr ctr
// assign external performance counters
generate
genvar i;
for (i = 0; i < N_EXT_CNT; i++)
begin : g_extcounters
assign PCCR_in[N_PERF_COUNTERS - N_EXT_CNT + i] = ext_counters_i[i];
end
endgenerate
for (genvar i = 0; i < N_EXT_CNT; i++) begin : gen_extcounters
assign PCCR_in[N_PERF_COUNTERS - N_EXT_CNT + i] = ext_counters_i[i];
end
// address decoder for performance counter registers
always_comb
begin
always_comb begin
is_pccr = 1'b0;
is_pcmr = 1'b0;
is_pcer = 1'b0;
@ -345,7 +314,7 @@ module ibex_cs_registers
unique case (csr_addr_i)
12'h7A0: begin
is_pcer = 1'b1;
perf_rdata[15:0] = PCER_q;
perf_rdata[N_PERF_COUNTERS-1:0] = PCER_q;
end
12'h7A1: begin
is_pcmr = 1'b1;
@ -378,14 +347,14 @@ module ibex_cs_registers
// for synthesis we just have one performance counter register
assign PCCR_inc[0] = (|(PCCR_in & PCER_q)) & PCMR_q[0];
always_comb
begin
always_comb begin
PCCR_n[0] = PCCR_q[0];
if ((PCCR_inc_q[0] == 1'b1) && ((PCCR_q[0] != 32'hFFFFFFFF) || (PCMR_q[1] == 1'b0)))
PCCR_n[0] = PCCR_q[0] + 1;
if ((PCCR_inc_q[0] == 1'b1) && ((PCCR_q[0] != 32'hFFFFFFFF) || (PCMR_q[1] == 1'b0))) begin
PCCR_n[0] = PCCR_q[0] + 32'h1;
end
if (is_pccr == 1'b1) begin
if (is_pccr) begin
unique case (csr_op_i)
CSR_OP_NONE: ;
CSR_OP_WRITE: PCCR_n[0] = csr_wdata_i;
@ -395,23 +364,22 @@ module ibex_cs_registers
end
end
`else
always_comb
begin
for(int i = 0; i < N_PERF_COUNTERS; i++)
begin : PERF_CNT_INC
PCCR_inc[i] = PCCR_in[i] & PCER_q[i] & PCMR_q[0];
always_comb begin
for (int c = 0; c < N_PERF_COUNTERS; c++) begin : PERF_CNT_INC
PCCR_inc[c] = PCCR_in[c] & PCER_q[c] & PCMR_q[0];
PCCR_n[i] = PCCR_q[i];
PCCR_n[c] = PCCR_q[c];
if ((PCCR_inc_q[i] == 1'b1) && ((PCCR_q[i] != 32'hFFFFFFFF) || (PCMR_q[1] == 1'b0)))
PCCR_n[i] = PCCR_q[i] + 1;
if ((PCCR_inc_q[c] == 1'b1) && ((PCCR_q[c] != 32'hFFFFFFFF) || (PCMR_q[1] == 1'b0))) begin
PCCR_n[c] = PCCR_q[c] + 32'h1;
end
if (is_pccr == 1'b1 && (pccr_all_sel == 1'b1 || pccr_index == i)) begin
if (is_pccr && (pccr_all_sel || pccr_index == c)) begin
unique case (csr_op_i)
CSR_OP_NONE: ;
CSR_OP_WRITE: PCCR_n[i] = csr_wdata_i;
CSR_OP_SET: PCCR_n[i] = csr_wdata_i | PCCR_q[i];
CSR_OP_CLEAR: PCCR_n[i] = csr_wdata_i & ~(PCCR_q[i]);
CSR_OP_WRITE: PCCR_n[c] = csr_wdata_i;
CSR_OP_SET: PCCR_n[c] = csr_wdata_i | PCCR_q[c];
CSR_OP_CLEAR: PCCR_n[c] = csr_wdata_i & ~(PCCR_q[c]);
endcase
end
end
@ -419,8 +387,7 @@ module ibex_cs_registers
`endif
// update PCMR and PCER
always_comb
begin
always_comb begin
PCMR_n = PCMR_q;
PCER_n = PCER_q;
@ -444,34 +411,23 @@ module ibex_cs_registers
end
// Performance Counter Registers
always_ff @(posedge clk, negedge rst_n)
begin
if (rst_n == 1'b0)
begin
id_valid_q <= 1'b0;
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
PCER_q <= '0;
PCMR_q <= 2'h3;
for(int i = 0; i < N_PERF_REGS; i++)
begin
PCCR_q[i] <= '0;
PCCR_inc_q[i] <= '0;
for (int r = 0; r < N_PERF_REGS; r++) begin
PCCR_q[r] <= '0;
PCCR_inc_q[r] <= '0;
end
end
else
begin
id_valid_q <= id_valid_i;
end else begin
PCER_q <= PCER_n;
PCMR_q <= PCMR_n;
for(int i = 0; i < N_PERF_REGS; i++)
begin
PCCR_q[i] <= PCCR_n[i];
PCCR_inc_q[i] <= PCCR_inc[i];
for (int r = 0; r < N_PERF_REGS; r++) begin
PCCR_q[r] <= PCCR_n[r];
PCCR_inc_q[r] <= PCCR_inc[r];
end
end
end

View file

@ -19,70 +19,68 @@
`include "ibex_config.sv"
import ibex_defines::*;
module ibex_debug_unit #(parameter REG_ADDR_WIDTH = 5) (
input logic clk,
input logic rst_n,
module ibex_debug_unit
#(
parameter REG_ADDR_WIDTH = 5
)
(
input logic clk,
input logic rst_n,
// Debug Interface
input logic debug_req_i,
output logic debug_gnt_o,
output logic debug_rvalid_o,
input logic [14:0] debug_addr_i,
input logic debug_we_i,
input logic [31:0] debug_wdata_i,
output logic [31:0] debug_rdata_o,
// Debug Interface
input logic debug_req_i,
output logic debug_gnt_o,
output logic debug_rvalid_o,
input logic [14:0] debug_addr_i,
input logic debug_we_i,
input logic [31:0] debug_wdata_i,
output logic [31:0] debug_rdata_o,
output logic debug_halted_o,
input logic debug_halt_i,
input logic debug_resume_i,
output logic debug_halted_o,
input logic debug_halt_i,
input logic debug_resume_i,
// signals to core
output logic [DBG_SETS_W-1:0] settings_o,
// signals to core
output logic [DBG_SETS_W-1:0] settings_o,
input logic trap_i, // trap found, need to stop the core now
input logic [5:0] exc_cause_i, // if it was a trap, then the exception controller knows more
output logic stall_o, // after we got control, we control the stall signal
output logic dbg_req_o,
input logic dbg_ack_i,
input logic trap_i, // trap found, need to stop the core now
input logic [5:0] exc_cause_i, // if it was a trap, then the exception controller knows more
output logic stall_o, // after we got control, we control the stall signal
output logic dbg_req_o,
input logic dbg_ack_i,
// register file read port
output logic regfile_rreq_o,
output logic [REG_ADDR_WIDTH-1:0] regfile_raddr_o,
input logic [31:0] regfile_rdata_i,
// register file read port
output logic regfile_rreq_o,
output logic [(REG_ADDR_WIDTH-1):0] regfile_raddr_o,
input logic [31:0] regfile_rdata_i,
// register file write port
output logic regfile_wreq_o,
output logic [REG_ADDR_WIDTH-1:0] regfile_waddr_o,
output logic [31:0] regfile_wdata_o,
// register file write port
output logic regfile_wreq_o,
output logic [(REG_ADDR_WIDTH-1):0] regfile_waddr_o,
output logic [31:0] regfile_wdata_o,
// CSR read/write port
output logic csr_req_o,
output logic [11:0] csr_addr_o,
output logic csr_we_o,
output logic [31:0] csr_wdata_o,
input logic [31:0] csr_rdata_i,
// CSR read/write port
output logic csr_req_o,
output logic [11:0] csr_addr_o,
output logic csr_we_o,
output logic [31:0] csr_wdata_o,
input logic [31:0] csr_rdata_i,
// Signals for PPC & NPC register
input logic [31:0] pc_if_i,
input logic [31:0] pc_id_i,
// Signals for PPC & NPC register
input logic [31:0] pc_if_i,
input logic [31:0] pc_id_i,
input logic sleeping_i,
input logic instr_valid_id_i,
input logic sleeping_i,
output logic jump_req_o,
output logic [31:0] jump_addr_o
output logic jump_req_o,
output logic [31:0] jump_addr_o
);
enum logic [2:0] {RD_NONE, RD_CSR, RD_GPR, RD_DBGA, RD_DBGS} rdata_sel_q, rdata_sel_n;
import ibex_defines::*;
enum logic [0:0] {FIRST, SECOND} state_q, state_n;
typedef enum logic [2:0] {RD_NONE, RD_CSR, RD_GPR, RD_DBGA, RD_DBGS} rdata_sel_e;
rdata_sel_e rdata_sel_q, rdata_sel_n;
typedef enum logic [0:0] {FIRST, SECOND} dbg_fsm_e;
dbg_fsm_e state_q, state_n;
logic [DBG_SETS_W-1:0] settings_q, settings_n;
@ -96,8 +94,10 @@ module ibex_debug_unit
logic csr_req_q, csr_req_n;
logic regfile_wreq;
typedef enum logic [1:0] {RUNNING, HALT_REQ, HALT} stall_fsm_e;
stall_fsm_e stall_cs, stall_ns;
enum logic [1:0] {RUNNING, HALT_REQ, HALT} stall_cs, stall_ns;
logic [31:0] dbg_rdata;
logic dbg_resume;
logic dbg_halt;
@ -112,8 +112,7 @@ module ibex_debug_unit
// address decoding, write and read controller
always_comb
begin
always_comb begin
rdata_sel_n = RD_NONE;
state_n = FIRST;
@ -162,15 +161,13 @@ module ibex_debug_unit
5'b0_0000: begin // DBG_CTRL
if (debug_wdata_i[16]) begin
// HALT set
if (~debug_halted_o) begin
if (!debug_halted_o) begin
// not halt, so STOP
dbg_halt = 1'b1;
end
end else begin
end else if (debug_halted_o) begin
// RESUME set
if (debug_halted_o) begin
dbg_resume = 1'b1;
end
dbg_resume = 1'b1;
end
settings_n[DBG_SETS_SSTE] = debug_wdata_i[0];
@ -192,10 +189,9 @@ module ibex_debug_unit
debug_gnt_o = 1'b1; // grant it even when invalid access to not block
if (debug_halted_o) begin
unique case (debug_addr_i[6:2])
5'b0_0000: jump_req_n = 1'b1; // DNPC
default:;
endcase
if (debug_addr_i[6:2] == 5'b0_0000) begin
jump_req_n = 1'b1; // DNPC
end
end
end
@ -260,14 +256,14 @@ module ibex_debug_unit
// Since those are combinational, we can do it in the cycle where we set
// rvalid. The address has been latched into addr_q
//----------------------------------------------------------------------------
always_comb
begin
always_comb begin
dbg_rdata = '0;
case (rdata_sel_q)
RD_DBGA: begin
unique case (addr_q[6:2])
5'h00: dbg_rdata[31:0] = {15'b0, debug_halted_o, 15'b0, settings_q[DBG_SETS_SSTE]}; // DBG_CTRL
// DBG_CTRL
5'h00: dbg_rdata[31:0] = {15'b0, debug_halted_o, 15'b0, settings_q[DBG_SETS_SSTE]};
5'h01: dbg_rdata[31:0] = {15'b0, sleeping_i, 15'b0, dbg_ssth_q}; // DBG_HIT
5'h02: begin // DBG_IE
dbg_rdata[31:16] = '0;
@ -310,8 +306,7 @@ module ibex_debug_unit
//----------------------------------------------------------------------------
// read data mux
//----------------------------------------------------------------------------
always_comb
begin
always_comb begin
debug_rdata_o = '0;
case (rdata_sel_q)
@ -319,16 +314,15 @@ module ibex_debug_unit
RD_GPR: debug_rdata_o = regfile_rdata_i;
RD_DBGA: debug_rdata_o = dbg_rdata;
RD_DBGS: debug_rdata_o = dbg_rdata;
default: ;
default: ;
endcase
end
//----------------------------------------------------------------------------
// rvalid generation
//----------------------------------------------------------------------------
always_ff @(posedge clk, negedge rst_n)
begin
if (~rst_n) begin
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
debug_rvalid_o <= 1'b0;
end else begin
debug_rvalid_o <= debug_gnt_o; // always give the rvalid one cycle after gnt
@ -338,8 +332,7 @@ module ibex_debug_unit
//----------------------------------------------------------------------------
// stall control
//----------------------------------------------------------------------------
always_comb
begin
always_comb begin
stall_ns = stall_cs;
dbg_req_o = 1'b0;
stall_o = 1'b0;
@ -347,17 +340,18 @@ module ibex_debug_unit
dbg_cause_n = dbg_cause_q;
dbg_ssth_n = dbg_ssth_q;
case (stall_cs)
unique case (stall_cs)
RUNNING: begin
dbg_ssth_n = 1'b0;
if (dbg_halt | debug_halt_i | trap_i) begin
if (dbg_halt || debug_halt_i || trap_i) begin
dbg_req_o = 1'b1;
stall_ns = HALT_REQ;
if (trap_i) begin
if (settings_q[DBG_SETS_SSTE])
if (settings_q[DBG_SETS_SSTE]) begin
dbg_ssth_n = 1'b1;
end
dbg_cause_n = exc_cause_i;
end else begin
@ -369,31 +363,30 @@ module ibex_debug_unit
HALT_REQ: begin
dbg_req_o = 1'b1;
if (dbg_ack_i)
stall_ns = HALT;
if (dbg_resume | debug_resume_i)
stall_ns = RUNNING;
if (dbg_ack_i) stall_ns = HALT;
if (dbg_resume || debug_resume_i) stall_ns = RUNNING;
end
HALT: begin
stall_o = 1'b1;
debug_halted_o = 1'b1;
if (dbg_resume | debug_resume_i) begin
if (dbg_resume || debug_resume_i) begin
stall_ns = RUNNING;
stall_o = 1'b0;
end
end
default:;
endcase
if (ssth_clear)
if (ssth_clear) begin
dbg_ssth_n = 1'b0;
end
end
always_ff @(posedge clk, negedge rst_n)
begin
if (~rst_n) begin
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
stall_cs <= RUNNING;
dbg_cause_q <= DBG_CAUSE_HALT;
dbg_ssth_q <= 1'b0;
@ -411,10 +404,8 @@ module ibex_debug_unit
assign ppc_int = pc_id_i;
assign npc_int = pc_if_i;
always_ff @(posedge clk, negedge rst_n)
begin
if (~rst_n) begin
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
addr_q <= '0;
wdata_q <= '0;
state_q <= FIRST;
@ -425,7 +416,6 @@ module ibex_debug_unit
settings_q <= 1'b0;
end else begin
// settings
settings_q <= settings_n;
@ -436,7 +426,7 @@ module ibex_debug_unit
state_q <= state_n;
end
if (debug_req_i | debug_rvalid_o) begin
if (debug_req_i || debug_rvalid_o) begin
// wait for either req or rvalid to set those FFs
// This makes sure that they are only triggered once when there is
// only one request, and the FFs can be properly clock gated otherwise

View file

@ -23,64 +23,65 @@
`include "ibex_config.sv"
import ibex_defines::*;
/**
* Instruction decoder
*/
module ibex_decoder
#(
parameter RV32M = 1
)
(
// singals running to/from controller
input logic deassert_we_i, // deassert we, we are stalled or not active
input logic data_misaligned_i, // misaligned data load/store in progress
input logic branch_mux_i,
input logic jump_mux_i,
output logic illegal_insn_o, // illegal instruction encountered
output logic ebrk_insn_o, // trap instruction encountered
output logic mret_insn_o, // return from exception instruction encountered
output logic ecall_insn_o, // environment call (syscall) instruction encountered
output logic pipe_flush_o, // pipeline flush is requested
module ibex_decoder #(
parameter RV32M = 1
) (
// singals running to/from controller
input logic deassert_we_i, // deassert we, we are stalled or not active
input logic data_misaligned_i, // misaligned data load/store in progress
input logic branch_mux_i,
input logic jump_mux_i,
output logic illegal_insn_o, // illegal instruction encountered
output logic ebrk_insn_o, // trap instruction encountered
output logic mret_insn_o, // return from exception instruction encountered
output logic ecall_insn_o, // environment call (syscall)
// instruction encountered
output logic pipe_flush_o, // pipeline flush is requested
// from IF/ID pipeline
input logic [31:0] instr_rdata_i, // instruction read from instr memory/cache
input logic illegal_c_insn_i, // compressed instruction decode failed
// from IF/ID pipeline
input logic [31:0] instr_rdata_i, // instruction read from instr memory/cache
input logic illegal_c_insn_i, // compressed instruction decode failed
// ALU signals
output logic [ALU_OP_WIDTH-1:0] alu_operator_o, // ALU operation selection
output logic [2:0] alu_op_a_mux_sel_o, // operand a selection: reg value, PC, immediate or zero
output logic [2:0] alu_op_b_mux_sel_o, // oNOperand b selection: reg value or immediate
// ALU signals
output logic [ibex_defines::ALU_OP_WIDTH-1:0] alu_operator_o, // ALU operation selection
output logic [2:0] alu_op_a_mux_sel_o, // operand a selection: reg value, PC,
// immediate or zero
output logic [2:0] alu_op_b_mux_sel_o, // operand b selection: reg value or immediate
output logic [0:0] imm_a_mux_sel_o, // immediate selection for operand a
output logic [3:0] imm_b_mux_sel_o, // immediate selection for operand b
output logic [0:0] imm_a_mux_sel_o, // immediate selection for operand a
output logic [3:0] imm_b_mux_sel_o, // immediate selection for operand b
// MUL, DIV related control signals
output logic mult_int_en_o, // perform integer multiplication
output logic div_int_en_o, // perform integer division or reminder
output logic [1:0] multdiv_operator_o,
output logic [1:0] multdiv_signed_mode_o,
// register file related signals
output logic regfile_we_o, // write enable for regfile
// MUL, DIV related control signals
output logic mult_int_en_o, // perform integer multiplication
output logic div_int_en_o, // perform integer division or reminder
output logic [1:0] multdiv_operator_o,
output logic [1:0] multdiv_signed_mode_o,
// register file related signals
output logic regfile_we_o, // write enable for regfile
// CSR manipulation
output logic csr_access_o, // access to CSR
output logic [1:0] csr_op_o, // operation to perform on CSR
output logic csr_status_o, // access to xstatus CSR
// CSR manipulation
output logic csr_access_o, // access to CSR
output logic [1:0] csr_op_o, // operation to perform on CSR
output logic csr_status_o, // access to xstatus CSR
// LD/ST unit signals
output logic data_req_o, // start transaction to data memory
output logic data_we_o, // data memory write enable
output logic [1:0] data_type_o, // data type on data memory: byte, half word or word
output logic data_sign_extension_o, // sign extension on read data from data memory
output logic [1:0] data_reg_offset_o, // offset in byte inside register for stores
// LD/ST unit signals
output logic data_req_o, // start transaction to data memory
output logic data_we_o, // data memory write enable
output logic [1:0] data_type_o, // data type on data memory: byte,
// half word or word
output logic data_sign_extension_o, // sign extension on read data from data memory
output logic [1:0] data_reg_offset_o, // offset in byte inside register for stores
// jump/branches
output logic jump_in_id_o, // jump is being calculated in ALU
output logic branch_in_id_o
// jump/branches
output logic jump_in_id_o, // jump is being calculated in ALU
output logic branch_in_id_o
);
import ibex_defines::*;
// write enable/request control
logic regfile_we;
logic data_req;
@ -102,8 +103,7 @@ module ibex_decoder
// //
/////////////////////////////////////////////
always_comb
begin
always_comb begin
jump_in_id = 1'b0;
branch_in_id = 1'b0;
alu_operator_o = ALU_SLTU;
@ -150,7 +150,7 @@ module ibex_decoder
OPCODE_JAL: begin // Jump and Link
jump_in_id = 1'b1;
if(jump_mux_i) begin
if (jump_mux_i) begin
// Calculate jump target
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
@ -169,7 +169,7 @@ module ibex_decoder
OPCODE_JALR: begin // Jump and Link Register
jump_in_id = 1'b1;
if(jump_mux_i) begin
if (jump_mux_i) begin
// Calculate jump target
alu_op_a_mux_sel_o = OP_A_REGA_OR_FWD;
alu_op_b_mux_sel_o = OP_B_IMM;
@ -189,28 +189,21 @@ module ibex_decoder
regfile_we = 1'b0;
illegal_insn_o = 1'b1;
end
end
OPCODE_BRANCH: begin // Branch
branch_in_id = 1'b1;
if (branch_mux_i)
begin
if (branch_mux_i) begin
unique case (instr_rdata_i[14:12])
3'b000: alu_operator_o = ALU_EQ;
3'b001: alu_operator_o = ALU_NE;
3'b100: alu_operator_o = ALU_LTS;
3'b101: alu_operator_o = ALU_GES;
3'b110: alu_operator_o = ALU_LTU;
3'b111: alu_operator_o = ALU_GEU;
default: begin
illegal_insn_o = 1'b1;
end
3'b000: alu_operator_o = ALU_EQ;
3'b001: alu_operator_o = ALU_NE;
3'b100: alu_operator_o = ALU_LTS;
3'b101: alu_operator_o = ALU_GES;
3'b110: alu_operator_o = ALU_LTU;
3'b111: alu_operator_o = ALU_GEU;
default: illegal_insn_o = 1'b1;
endcase
end
else begin
end else begin
// Calculate jump target in EX
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
@ -218,7 +211,6 @@ module ibex_decoder
alu_operator_o = ALU_ADD;
regfile_we = 1'b0;
end
end
@ -236,13 +228,12 @@ module ibex_decoder
data_we_o = 1'b1;
alu_operator_o = ALU_ADD;
if (instr_rdata_i[14] == 1'b0) begin
if (!instr_rdata_i[14]) begin
// offset from immediate
imm_b_mux_sel_o = IMMB_S;
alu_op_b_mux_sel_o = OP_B_IMM;
end
// Register offset is illegal since no register c available
else begin
end else begin
// Register offset is illegal since no register c available
data_req = 1'b0;
data_we_o = 1'b0;
illegal_insn_o = 1'b1;
@ -271,7 +262,6 @@ module ibex_decoder
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMMB_I;
// sign/zero extension
data_sign_extension_o = ~instr_rdata_i[14];
@ -352,20 +342,21 @@ module ibex_decoder
3'b001: begin
alu_operator_o = ALU_SLL; // Shift Left Logical by Immediate
if (instr_rdata_i[31:25] != 7'b0)
if (instr_rdata_i[31:25] != 7'b0) begin
illegal_insn_o = 1'b1;
end
end
3'b101: begin
if (instr_rdata_i[31:25] == 7'b0)
if (instr_rdata_i[31:25] == 7'b0) begin
alu_operator_o = ALU_SRL; // Shift Right Logical by Immediate
else if (instr_rdata_i[31:25] == 7'b010_0000)
end else if (instr_rdata_i[31:25] == 7'b010_0000) begin
alu_operator_o = ALU_SRA; // Shift Right Arithmetically by Immediate
else
end else begin
illegal_insn_o = 1'b1;
end
end
default: illegal_insn_o = 1'b1;
default:;
endcase
end
@ -374,12 +365,7 @@ module ibex_decoder
if (instr_rdata_i[31]) begin
illegal_insn_o = 1'b1;
end
else
begin // non bit-manipulation instructions
if (~instr_rdata_i[28])
end else if (!instr_rdata_i[28]) begin // non bit-manipulation instructions
unique case ({instr_rdata_i[30:25], instr_rdata_i[14:12]})
// RV32I ALU operations
{6'b00_0000, 3'b000}: alu_operator_o = ALU_ADD; // Add
@ -395,32 +381,32 @@ module ibex_decoder
// supported RV32M instructions
{6'b00_0001, 3'b000}: begin // mul
alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_MULL;
mult_int_en = 1'b1;
multdiv_signed_mode_o = 2'b00;
illegal_insn_o = RV32M ? 1'b0 : 1'b1;
alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_MULL;
mult_int_en = 1'b1;
multdiv_signed_mode_o = 2'b00;
illegal_insn_o = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b001}: begin // mulh
alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_MULH;
mult_int_en = 1'b1;
multdiv_signed_mode_o = 2'b11;
illegal_insn_o = RV32M ? 1'b0 : 1'b1;
alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_MULH;
mult_int_en = 1'b1;
multdiv_signed_mode_o = 2'b11;
illegal_insn_o = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b010}: begin // mulhsu
alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_MULH;
mult_int_en = 1'b1;
multdiv_signed_mode_o = 2'b01;
illegal_insn_o = RV32M ? 1'b0 : 1'b1;
alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_MULH;
mult_int_en = 1'b1;
multdiv_signed_mode_o = 2'b01;
illegal_insn_o = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b011}: begin // mulhu
alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_MULH;
mult_int_en = 1'b1;
multdiv_signed_mode_o = 2'b00;
illegal_insn_o = RV32M ? 1'b0 : 1'b1;
alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_MULH;
mult_int_en = 1'b1;
multdiv_signed_mode_o = 2'b00;
illegal_insn_o = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b100}: begin // div
alu_operator_o = ALU_ADD;
@ -457,9 +443,6 @@ module ibex_decoder
end
end
////////////////////////////////////////////////
// ____ ____ _____ ____ ___ _ _ //
// / ___|| _ \| ____/ ___|_ _| / \ | | //
@ -470,41 +453,28 @@ module ibex_decoder
////////////////////////////////////////////////
OPCODE_SYSTEM: begin
if (instr_rdata_i[14:12] == 3'b000)
begin
if (instr_rdata_i[14:12] == 3'b000) begin
// non CSR related SYSTEM instructions
unique case (instr_rdata_i[31:20])
12'h000: // ECALL
begin
// environment (system) call
ecall_insn_o = 1'b1;
end
12'h001: // ebreak
begin
// debugger trap
ebrk_insn_o = 1'b1;
end
12'h302: // mret
begin
mret_insn_o = 1'b1;
end
12'h105: // wfi
begin
// flush pipeline
pipe_flush_o = 1'b1;
end
default:
begin
illegal_insn_o = 1'b1;
end
endcase
end
else
begin
end else begin
// instruction to read/modify CSR
csr_access_o = 1'b1;
regfile_we = 1'b1;
@ -512,7 +482,7 @@ module ibex_decoder
imm_a_mux_sel_o = IMMA_Z;
imm_b_mux_sel_o = IMMB_I; // CSR address is encoded in I imm
if (instr_rdata_i[14] == 1'b1) begin
if (instr_rdata_i[14]) begin
// rs1 field is used as immediate
alu_op_a_mux_sel_o = OP_A_IMM;
end else begin
@ -526,10 +496,12 @@ module ibex_decoder
default: csr_illegal = 1'b1;
endcase
if(~csr_illegal)
if (instr_rdata_i[31:20] == 12'h300)
if (!csr_illegal) begin
if (instr_rdata_i[31:20] == 12'h300) begin
//access to mstatus
csr_status_o = 1'b1;
end
end
illegal_insn_o = csr_illegal;
@ -548,8 +520,7 @@ module ibex_decoder
// misaligned access was detected by the LSU
// TODO: this section should eventually be moved out of the decoder
if (data_misaligned_i == 1'b1)
begin
if (data_misaligned_i) begin
// only part of the pipeline is unstalled, make sure that the
// correct operands are sent to the AGU
alu_op_a_mux_sel_o = OP_A_REGA_OR_FWD;
@ -560,15 +531,9 @@ module ibex_decoder
// second address since the first calculated address was
// the correct one
regfile_we = 1'b0;
end
end
// deassert we signals (in case of stalls)
assign regfile_we_o = (deassert_we_i) ? 1'b0 : regfile_we;
assign mult_int_en_o = RV32M ? ((deassert_we_i) ? 1'b0 : mult_int_en) : 1'b0;

View file

@ -23,49 +23,46 @@
`include "ibex_config.sv"
import ibex_defines::*;
/**
* Execution stage
*
* Execution block: Hosts ALU and MUL/DIV unit
*/
module ibex_ex_block
#(
parameter RV32M = 1
)
(
module ibex_ex_block #(
parameter RV32M = 1
) (
input logic clk,
input logic rst_n,
input logic clk,
input logic rst_n,
// ALU signals from ID stage
input logic [ibex_defines::ALU_OP_WIDTH-1:0] alu_operator_i,
input logic [1:0] multdiv_operator_i,
input logic mult_en_i,
input logic div_en_i,
// ALU signals from ID stage
input logic [ALU_OP_WIDTH-1:0] alu_operator_i,
input logic [1:0] multdiv_operator_i,
input logic mult_en_i,
input logic div_en_i,
input logic [31:0] alu_operand_a_i,
input logic [31:0] alu_operand_b_i,
input logic [31:0] alu_operand_a_i,
input logic [31:0] alu_operand_b_i,
input logic [1:0] multdiv_signed_mode_i,
input logic [31:0] multdiv_operand_a_i,
input logic [31:0] multdiv_operand_b_i,
input logic [1:0] multdiv_signed_mode_i,
input logic [31:0] multdiv_operand_a_i,
input logic [31:0] multdiv_operand_b_i,
output logic [31:0] alu_adder_result_ex_o,
output logic [31:0] regfile_wdata_ex_o,
output logic [31:0] alu_adder_result_ex_o,
output logic [31:0] regfile_wdata_ex_o,
// To IF: Jump and branch target and decision
output logic [31:0] jump_target_o,
output logic branch_decision_o,
// To IF: Jump and branch target and decision
output logic [31:0] jump_target_o,
output logic branch_decision_o,
input logic lsu_en_i,
input logic lsu_en_i,
// Stall Control
input logic lsu_ready_ex_i, // LSU is done
output logic ex_ready_o // EX stage gets new data
// Stall Control
input logic lsu_ready_ex_i, // LSU is done
output logic ex_ready_o // EX stage gets new data
);
import ibex_defines::*;
localparam MULT_TYPE = 1; //0 is SLOW
logic [31:0] alu_result, multdiv_result;
@ -76,20 +73,18 @@ module ibex_ex_block
logic multdiv_ready, multdiv_en_sel;
logic multdiv_en;
/*
The multdiv_i output is never selected if RV32M=0
At synthesis time, all the combinational and sequential logic
from the multdiv_i module are eliminated
*/
generate
if (RV32M) begin
assign multdiv_en_sel = MULT_TYPE == 0 ? mult_en_i | div_en_i : div_en_i;
assign multdiv_en = mult_en_i | div_en_i;
end else begin
assign multdiv_en_sel = 1'b0;
assign multdiv_en = 1'b0;
end
endgenerate
/*
The multdiv_i output is never selected if RV32M=0
At synthesis time, all the combinational and sequential logic
from the multdiv_i module are eliminated
*/
if (RV32M) begin : gen_multdiv_m
assign multdiv_en_sel = MULT_TYPE ? div_en_i : mult_en_i | div_en_i;
assign multdiv_en = mult_en_i | div_en_i;
end else begin : gen_multdiv_nom
assign multdiv_en_sel = 1'b0;
assign multdiv_en = 1'b0;
end
assign regfile_wdata_ex_o = multdiv_en ? multdiv_result : alu_result;
@ -106,19 +101,18 @@ endgenerate
// //
////////////////////////////
ibex_alu alu_i
(
.operator_i ( alu_operator_i ),
.operand_a_i ( alu_operand_a_i ),
.operand_b_i ( alu_operand_b_i ),
.multdiv_operand_a_i ( multdiv_alu_operand_a ),
.multdiv_operand_b_i ( multdiv_alu_operand_b ),
.multdiv_en_i ( multdiv_en_sel ),
.adder_result_o ( alu_adder_result_ex_o ),
.adder_result_ext_o ( alu_adder_result_ext ),
.result_o ( alu_result ),
.comparison_result_o ( alu_cmp_result ),
.is_equal_result_o ( alu_is_equal_result )
ibex_alu alu_i (
.operator_i ( alu_operator_i ),
.operand_a_i ( alu_operand_a_i ),
.operand_b_i ( alu_operand_b_i ),
.multdiv_operand_a_i ( multdiv_alu_operand_a ),
.multdiv_operand_b_i ( multdiv_alu_operand_b ),
.multdiv_en_i ( multdiv_en_sel ),
.adder_result_o ( alu_adder_result_ex_o ),
.adder_result_ext_o ( alu_adder_result_ext ),
.result_o ( alu_result ),
.comparison_result_o ( alu_cmp_result ),
.is_equal_result_o ( alu_is_equal_result )
);
////////////////////////////////////////////////////////////////
@ -130,59 +124,54 @@ endgenerate
// //
////////////////////////////////////////////////////////////////
generate
if (MULT_TYPE == 0) begin : multdiv_slow
ibex_multdiv_slow multdiv_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.mult_en_i ( mult_en_i ),
.div_en_i ( div_en_i ),
.operator_i ( multdiv_operator_i ),
.signed_mode_i ( multdiv_signed_mode_i ),
.op_a_i ( multdiv_operand_a_i ),
.op_b_i ( multdiv_operand_b_i ),
.alu_adder_ext_i ( alu_adder_result_ext ),
.alu_adder_i ( alu_adder_result_ex_o ),
.equal_to_zero ( alu_is_equal_result ),
.ready_o ( multdiv_ready ),
.alu_operand_a_o ( multdiv_alu_operand_a ),
.alu_operand_b_o ( multdiv_alu_operand_b ),
.multdiv_result_o ( multdiv_result )
if (!MULT_TYPE) begin : gen_multdiv_slow
ibex_multdiv_slow multdiv_i (
.clk ( clk ),
.rst_n ( rst_n ),
.mult_en_i ( mult_en_i ),
.div_en_i ( div_en_i ),
.operator_i ( multdiv_operator_i ),
.signed_mode_i ( multdiv_signed_mode_i ),
.op_a_i ( multdiv_operand_a_i ),
.op_b_i ( multdiv_operand_b_i ),
.alu_adder_ext_i ( alu_adder_result_ext ),
.alu_adder_i ( alu_adder_result_ex_o ),
.equal_to_zero ( alu_is_equal_result ),
.ready_o ( multdiv_ready ),
.alu_operand_a_o ( multdiv_alu_operand_a ),
.alu_operand_b_o ( multdiv_alu_operand_b ),
.multdiv_result_o ( multdiv_result )
);
end else begin: multdiv_fast
ibex_multdiv_fast multdiv_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.mult_en_i ( mult_en_i ),
.div_en_i ( div_en_i ),
.operator_i ( multdiv_operator_i ),
.signed_mode_i ( multdiv_signed_mode_i ),
.op_a_i ( multdiv_operand_a_i ),
.op_b_i ( multdiv_operand_b_i ),
.alu_operand_a_o ( multdiv_alu_operand_a ),
.alu_operand_b_o ( multdiv_alu_operand_b ),
.alu_adder_ext_i ( alu_adder_result_ext ),
.alu_adder_i ( alu_adder_result_ex_o ),
.equal_to_zero ( alu_is_equal_result ),
.ready_o ( multdiv_ready ),
.multdiv_result_o ( multdiv_result )
end else begin: gen_multdiv_fast
ibex_multdiv_fast multdiv_i (
.clk ( clk ),
.rst_n ( rst_n ),
.mult_en_i ( mult_en_i ),
.div_en_i ( div_en_i ),
.operator_i ( multdiv_operator_i ),
.signed_mode_i ( multdiv_signed_mode_i ),
.op_a_i ( multdiv_operand_a_i ),
.op_b_i ( multdiv_operand_b_i ),
.alu_operand_a_o ( multdiv_alu_operand_a ),
.alu_operand_b_o ( multdiv_alu_operand_b ),
.alu_adder_ext_i ( alu_adder_result_ext ),
.alu_adder_i ( alu_adder_result_ex_o ),
.equal_to_zero ( alu_is_equal_result ),
.ready_o ( multdiv_ready ),
.multdiv_result_o ( multdiv_result )
);
end
endgenerate
always_comb
begin
unique case (1'b1)
multdiv_en:
ex_ready_o = multdiv_ready;
lsu_en_i:
ex_ready_o = lsu_ready_ex_i;
default:
//1 Cycle case
ex_ready_o = 1'b1;
endcase
always_comb begin
unique case (1'b1)
multdiv_en:
ex_ready_o = multdiv_ready;
lsu_en_i:
ex_ready_o = lsu_ready_ex_i;
default:
//1 Cycle case
ex_ready_o = 1'b1;
endcase
end
endmodule

View file

@ -22,8 +22,7 @@
* clear_i clears the FIFO for the following cycle. in_addr_i can be sent in
* this cycle already.
*/
module ibex_fetch_fifo
(
module ibex_fetch_fifo (
input logic clk,
input logic rst_n,
@ -43,8 +42,10 @@ module ibex_fetch_fifo
output logic [31:0] out_rdata_o,
output logic [31:0] out_addr_o,
output logic out_valid_stored_o // same as out_valid_o, except that if something is incoming now it is not included. This signal is available immediately as it comes directly out of FFs
);
output logic out_valid_stored_o // same as out_valid_o, except that if something is
// incoming now it is not included. This signal is
// available immediately as it comes directly out of FFs
);
localparam DEPTH = 3; // must be 3 or greater
@ -53,36 +54,35 @@ module ibex_fetch_fifo
logic [DEPTH-1:0] [31:0] rdata_n, rdata_int, rdata_Q;
logic [DEPTH-1:0] valid_n, valid_int, valid_Q;
logic [31:0] addr_next;
logic [31:2] addr_next;
logic [31:0] rdata, rdata_unaligned;
logic valid, valid_unaligned;
logic aligned_is_compressed, unaligned_is_compressed;
logic aligned_is_compressed_st, unaligned_is_compressed_st;
logic unaligned_is_compressed_st;
//////////////////////////////////////////////////////////////////////////////
// output port
//////////////////////////////////////////////////////////////////////////////
assign rdata = (valid_Q[0]) ? rdata_Q[0] : in_rdata_i;
assign valid = valid_Q[0] || in_valid_i;
assign rdata = valid_Q[0] ? rdata_Q[0] : in_rdata_i;
assign valid = valid_Q[0] | in_valid_i;
assign rdata_unaligned = (valid_Q[1]) ? {rdata_Q[1][15:0], rdata[31:16]} : {in_rdata_i[15:0], rdata[31:16]};
assign rdata_unaligned = valid_Q[1] ? {rdata_Q[1][15:0], rdata[31:16]} :
{in_rdata_i[15:0], rdata[31:16]};
// it is implied that rdata_valid_Q[0] is set
assign valid_unaligned = (valid_Q[1] || (valid_Q[0] && in_valid_i));
assign valid_unaligned = valid_Q[1] | (valid_Q[0] & in_valid_i);
assign unaligned_is_compressed = rdata[17:16] != 2'b11;
assign aligned_is_compressed = rdata[1:0] != 2'b11;
assign aligned_is_compressed = rdata[ 1: 0] != 2'b11;
assign unaligned_is_compressed_st = rdata_Q[0][17:16] != 2'b11;
assign aligned_is_compressed_st = rdata_Q[0][1:0] != 2'b11;
//////////////////////////////////////////////////////////////////////////////
// instruction aligner (if unaligned)
//////////////////////////////////////////////////////////////////////////////
always_comb
begin
always_comb begin
// serve the aligned case even though the output address is unaligned when
// the next instruction will be from a hardware loop target
// in this case the current instruction is already prealigned in element 0
@ -90,10 +90,11 @@ module ibex_fetch_fifo
// unaligned case
out_rdata_o = rdata_unaligned;
if (unaligned_is_compressed)
if (unaligned_is_compressed) begin
out_valid_o = valid;
else
end else begin
out_valid_o = valid_unaligned;
end
end else begin
// aligned case
out_rdata_o = rdata;
@ -101,18 +102,18 @@ module ibex_fetch_fifo
end
end
assign out_addr_o = (valid_Q[0]) ? addr_Q[0] : in_addr_i;
assign out_addr_o = valid_Q[0] ? addr_Q[0] : in_addr_i;
// this valid signal must not depend on signals from outside!
always_comb
begin
always_comb begin
out_valid_stored_o = 1'b1;
if (out_addr_o[1]) begin
if (unaligned_is_compressed_st)
if (unaligned_is_compressed_st) begin
out_valid_stored_o = 1'b1;
else
end else begin
out_valid_stored_o = valid_Q[1];
end
end else begin
out_valid_stored_o = valid_Q[0];
end
@ -128,67 +129,53 @@ module ibex_fetch_fifo
// later anyway
assign in_ready_o = ~valid_Q[DEPTH-2];
//////////////////////////////////////////////////////////////////////////////
// FIFO management
//////////////////////////////////////////////////////////////////////////////
always_comb
begin
int j;
addr_int = addr_Q;
always_comb begin
addr_int = addr_Q;
rdata_int = rdata_Q;
valid_int = valid_Q;
if (in_valid_i) begin
for(j = 0; j < DEPTH; j++) begin
if (~valid_Q[j]) begin
for (int j = 0; j < DEPTH; j++) begin
if (!valid_Q[j]) begin
addr_int[j] = in_addr_i;
rdata_int[j] = in_rdata_i;
valid_int[j] = 1'b1;
break;
end
end
end
end
assign addr_next = {addr_int[0][31:2], 2'b00} + 32'h4;
assign addr_next[31:2] = addr_int[0][31:2] + 30'h1;
// move everything by one step
always_comb
begin
always_comb begin
addr_n = addr_int;
rdata_n = rdata_int;
valid_n = valid_int;
if (out_ready_i && out_valid_o) begin
begin
if (addr_int[0][1]) begin
// unaligned case
if (unaligned_is_compressed) begin
addr_n[0] = {addr_next[31:2], 2'b00};
end else begin
addr_n[0] = {addr_next[31:2], 2'b10};
end
rdata_n = {32'b0, rdata_int[DEPTH-1:1]};
valid_n = {1'b0, valid_int[DEPTH-1:1]};
if (addr_int[0][1]) begin
// unaligned case
if (unaligned_is_compressed) begin
addr_n[0] = {addr_next[31:2], 2'b00};
end else begin
if (aligned_is_compressed) begin
// just increase address, do not move to next entry in FIFO
addr_n[0] = {addr_int[0][31:2], 2'b10};
end else begin
// move to next entry in FIFO
addr_n[0] = {addr_next[31:2], 2'b00};
rdata_n = {32'b0, rdata_int[DEPTH-1:1]};
valid_n = {1'b0, valid_int[DEPTH-1:1]};
end
addr_n[0] = {addr_next[31:2], 2'b10};
end
rdata_n = {32'b0, rdata_int[DEPTH-1:1]};
valid_n = {1'b0, valid_int[DEPTH-1:1]};
end else if (aligned_is_compressed) begin
// just increase address, do not move to next entry in FIFO
addr_n[0] = {addr_int[0][31:2], 2'b10};
end else begin
// move to next entry in FIFO
addr_n[0] = {addr_next[31:2], 2'b00};
rdata_n = {32'b0, rdata_int[DEPTH-1:1]};
valid_n = {1'b0, valid_int[DEPTH-1:1]};
end
end
end
@ -197,20 +184,16 @@ module ibex_fetch_fifo
// registers
//////////////////////////////////////////////////////////////////////////////
always_ff @(posedge clk, negedge rst_n)
begin
if(rst_n == 1'b0)
begin
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
addr_Q <= '{default: '0};
rdata_Q <= '{default: '0};
valid_Q <= '0;
end
else
begin
end else begin
// on a clear signal from outside we invalidate the content of the FIFO
// completely and start from an empty state
if (clear_i) begin
valid_Q <= '0;
valid_Q <= '0;
end else begin
addr_Q <= addr_n;
rdata_Q <= rdata_n;
@ -226,4 +209,4 @@ module ibex_fetch_fifo
assert property (
@(posedge clk) (in_valid_i) |-> ((valid_Q[DEPTH-1] == 1'b0) || (clear_i == 1'b1)) );
`endif
endmodule
endmodule

View file

@ -23,9 +23,6 @@
`include "ibex_config.sv"
import ibex_defines::*;
// Source/Destination register instruction index
`define REG_S1 19:15
`define REG_S2 24:20
@ -37,12 +34,10 @@ import ibex_defines::*;
* Decode stage of the core. It decodes the instructions and hosts the register
* file.
*/
module ibex_id_stage
#(
parameter RV32M = 1,
parameter RV32E = 0
)
(
module ibex_id_stage #(
parameter RV32M = 1,
parameter RV32E = 0
) (
input logic clk,
input logic rst_n,
@ -59,7 +54,6 @@ module ibex_id_stage
output logic instr_req_o,
// Jumps and branches
output logic branch_in_ex_o,
input logic branch_decision_i,
// IF and ID stage signals
@ -80,9 +74,9 @@ module ibex_id_stage
output logic id_valid_o, // ID stage is done
// ALU
output logic [ALU_OP_WIDTH-1:0] alu_operator_ex_o,
output logic [31:0] alu_operand_a_ex_o,
output logic [31:0] alu_operand_b_ex_o,
output logic [ibex_defines::ALU_OP_WIDTH-1:0] alu_operator_ex_o,
output logic [31:0] alu_operand_a_ex_o,
output logic [31:0] alu_operand_b_ex_o,
// MUL, DIV
output logic mult_en_ex_o,
@ -151,6 +145,8 @@ module ibex_id_stage
output logic perf_tbranch_o // we are executing a taken branch instruction
);
import ibex_defines::*;
logic [31:0] instr;
// Decoder/Controller ID stage internal signals
@ -181,7 +177,9 @@ module ibex_id_stage
logic halt_id;
//FSM signals to write back multi cycles instructions
logic regfile_we;
enum logic {RF_LSU, RF_EX} select_data_rf;
typedef enum logic {RF_LSU, RF_EX} select_e;
select_e select_data_rf;
// Immediate decoding and sign extension
logic [31:0] imm_i_type;
@ -200,7 +198,6 @@ module ibex_id_stage
logic [31:0] imm_a; // contains the immediate for operand b
logic [31:0] imm_b; // contains the immediate for operand b
// Signals running between controller and exception controller
logic irq_req_ctrl;
logic [4:0] irq_id_ctrl;
@ -284,16 +281,18 @@ module ibex_id_stage
//---------------------------------------------------------------------------
assign regfile_alu_waddr_id = instr[`REG_D];
//if(RV32E)
// assign illegal_reg_rv32e = (regfile_addr_ra_id[4] | regfile_addr_rb_id[4] | regfile_alu_waddr_id[4]);
//else
//if (RV32E)
// assign illegal_reg_rv32e = (regfile_addr_ra_id[4] |
// regfile_addr_rb_id[4] |
// regfile_alu_waddr_id[4]);
//else
assign illegal_reg_rv32e = 1'b0;
// kill instruction in the IF/ID stage by setting the instr_valid_id control
// signal to 0 for instructions that are done
assign clear_instr_valid_o = id_ready_o | halt_id;
assign branch_taken_ex = branch_in_id & branch_decision_i;
assign branch_taken_ex = branch_in_id & branch_decision_i;
////////////////////////////////////////////////////////
// ___ _ _ //
@ -305,34 +304,25 @@ module ibex_id_stage
////////////////////////////////////////////////////////
// ALU_Op_a Mux
always_comb
begin : alu_operand_a_mux
always_comb begin : alu_operand_a_mux
case (alu_op_a_mux_sel)
OP_A_REGA_OR_FWD: alu_operand_a = operand_a_fw_id;
OP_A_CURRPC: alu_operand_a = pc_id_i;
OP_A_IMM: alu_operand_a = imm_a;
default: alu_operand_a = operand_a_fw_id;
endcase; // case (alu_op_a_mux_sel)
endcase // case (alu_op_a_mux_sel)
end
always_comb
begin : immediate_a_mux
unique case (imm_a_mux_sel)
IMMA_Z: imm_a = imm_z_type;
IMMA_ZERO: imm_a = '0;
default: imm_a = '0;
endcase
end
assign imm_a = (imm_a_mux_sel == IMMA_Z) ? imm_z_type : '0;
// Operand a forwarding mux used with LSU instructions
always_comb
begin : operand_a_fw_mux
case (operand_a_fw_mux_sel)
SEL_MISALIGNED: operand_a_fw_id = misaligned_addr_i;
SEL_REGFILE: operand_a_fw_id = regfile_data_ra_id;
default: operand_a_fw_id = regfile_data_ra_id;
endcase; // case (operand_a_fw_mux_sel)
end
// Operand a forwarding mux used with LSU instructions
always_comb begin : operand_a_fw_mux
case (operand_a_fw_mux_sel)
SEL_MISALIGNED: operand_a_fw_id = misaligned_addr_i;
SEL_REGFILE: operand_a_fw_id = regfile_data_ra_id;
default: operand_a_fw_id = regfile_data_ra_id;
endcase // case (operand_a_fw_mux_sel)
end
//////////////////////////////////////////////////////
@ -345,33 +335,31 @@ module ibex_id_stage
//////////////////////////////////////////////////////
// Immediate Mux for operand B
always_comb
begin : immediate_b_mux
unique case (imm_b_mux_sel)
IMMB_I: imm_b = imm_i_type;
IMMB_S: imm_b = imm_s_type;
IMMB_U: imm_b = imm_u_type;
IMMB_PCINCR: imm_b = (is_compressed_i && (~data_misaligned_i)) ? 32'h2 : 32'h4;
IMMB_S2: imm_b = imm_s2_type;
IMMB_BI: imm_b = imm_bi_type;
IMMB_S3: imm_b = imm_s3_type;
IMMB_VS: imm_b = imm_vs_type;
IMMB_VU: imm_b = imm_vu_type;
IMMB_UJ: imm_b = imm_uj_type;
IMMB_SB: imm_b = imm_sb_type;
default: imm_b = imm_i_type;
endcase
end
always_comb begin : immediate_b_mux
unique case (imm_b_mux_sel)
IMMB_I: imm_b = imm_i_type;
IMMB_S: imm_b = imm_s_type;
IMMB_U: imm_b = imm_u_type;
IMMB_PCINCR: imm_b = (is_compressed_i && !data_misaligned_i) ? 32'h2 : 32'h4;
IMMB_S2: imm_b = imm_s2_type;
IMMB_BI: imm_b = imm_bi_type;
IMMB_S3: imm_b = imm_s3_type;
IMMB_VS: imm_b = imm_vs_type;
IMMB_VU: imm_b = imm_vu_type;
IMMB_UJ: imm_b = imm_uj_type;
IMMB_SB: imm_b = imm_sb_type;
default: imm_b = imm_i_type;
endcase
end
// ALU_Op_b Mux
always_comb
begin : alu_operand_b_mux
case (alu_op_b_mux_sel)
OP_B_REGB_OR_FWD: operand_b = regfile_data_rb_id;
OP_B_IMM: operand_b = imm_b;
default: operand_b = regfile_data_rb_id;
endcase // case (alu_op_b_mux_sel)
end
always_comb begin : alu_operand_b_mux
case (alu_op_b_mux_sel)
OP_B_REGB_OR_FWD: operand_b = regfile_data_rb_id;
OP_B_IMM: operand_b = imm_b;
default: operand_b = regfile_data_rb_id;
endcase // case (alu_op_b_mux_sel)
end
assign alu_operand_b = operand_b;
assign operand_b_fw_id = regfile_data_rb_id;
@ -388,48 +376,43 @@ module ibex_id_stage
logic [31:0] regfile_wdata_mux;
logic regfile_we_mux;
logic [4:0] regfile_waddr_mux;
//TODO: add assertion
// Register File mux
always_comb
begin
if(dbg_reg_wreq_i) begin
always_comb begin
if (dbg_reg_wreq_i) begin
regfile_wdata_mux = dbg_reg_wdata_i;
regfile_waddr_mux = dbg_reg_waddr_i;
regfile_we_mux = 1'b1;
end else begin
regfile_we_mux = regfile_we;
regfile_waddr_mux = regfile_alu_waddr_id;
if (select_data_rf == RF_LSU)
if (select_data_rf == RF_LSU) begin
regfile_wdata_mux = regfile_wdata_lsu_i;
else
if (csr_access)
regfile_wdata_mux = csr_rdata_i;
else
regfile_wdata_mux = regfile_wdata_ex_i;
end else if (csr_access) begin
regfile_wdata_mux = csr_rdata_i;
end else begin
regfile_wdata_mux = regfile_wdata_ex_i;
end
end
end
ibex_register_file
#(
.RV32E(RV32E)
)
registers_i
(
.clk ( clk ),
.rst_n ( rst_n ),
ibex_register_file #( .RV32E(RV32E)) registers_i (
.clk ( clk ),
.rst_n ( rst_n ),
.test_en_i ( test_en_i ),
.test_en_i ( test_en_i ),
// Read port a
.raddr_a_i ( regfile_addr_ra_id ),
.rdata_a_o ( regfile_data_ra_id ),
// Read port b
.raddr_b_i ( (dbg_reg_rreq_i == 1'b0) ? regfile_addr_rb_id : dbg_reg_raddr_i ),
.rdata_b_o ( regfile_data_rb_id ),
// write port
.waddr_a_i ( regfile_waddr_mux ),
.wdata_a_i ( regfile_wdata_mux ),
.we_a_i ( regfile_we_mux )
// Read port a
.raddr_a_i ( regfile_addr_ra_id ),
.rdata_a_o ( regfile_data_ra_id ),
// Read port b
.raddr_b_i ( (dbg_reg_rreq_i == 1'b0) ? regfile_addr_rb_id : dbg_reg_raddr_i ),
.rdata_b_o ( regfile_data_rb_id ),
// write port
.waddr_a_i ( regfile_waddr_mux ),
.wdata_a_i ( regfile_wdata_mux ),
.we_a_i ( regfile_we_mux )
);
assign dbg_reg_rdata_o = regfile_data_rb_id;
@ -445,58 +428,53 @@ module ibex_id_stage
// //
///////////////////////////////////////////////
ibex_decoder
#(
.RV32M(RV32M)
)
decoder_i
(
// controller related signals
.deassert_we_i ( deassert_we ),
.data_misaligned_i ( data_misaligned_i ),
.branch_mux_i ( branch_mux_dec ),
.jump_mux_i ( jump_mux_dec ),
ibex_decoder #( .RV32M(RV32M)) decoder_i (
// controller related signals
.deassert_we_i ( deassert_we ),
.data_misaligned_i ( data_misaligned_i ),
.branch_mux_i ( branch_mux_dec ),
.jump_mux_i ( jump_mux_dec ),
.illegal_insn_o ( illegal_insn_dec ),
.ebrk_insn_o ( ebrk_insn ),
.mret_insn_o ( mret_insn_dec ),
.ecall_insn_o ( ecall_insn_dec ),
.pipe_flush_o ( pipe_flush_dec ),
.illegal_insn_o ( illegal_insn_dec ),
.ebrk_insn_o ( ebrk_insn ),
.mret_insn_o ( mret_insn_dec ),
.ecall_insn_o ( ecall_insn_dec ),
.pipe_flush_o ( pipe_flush_dec ),
// from IF/ID pipeline
.instr_rdata_i ( instr ),
.illegal_c_insn_i ( illegal_c_insn_i ),
// from IF/ID pipeline
.instr_rdata_i ( instr ),
.illegal_c_insn_i ( illegal_c_insn_i ),
// ALU signals
.alu_operator_o ( alu_operator ),
.alu_op_a_mux_sel_o ( alu_op_a_mux_sel ),
.alu_op_b_mux_sel_o ( alu_op_b_mux_sel ),
// ALU signals
.alu_operator_o ( alu_operator ),
.alu_op_a_mux_sel_o ( alu_op_a_mux_sel ),
.alu_op_b_mux_sel_o ( alu_op_b_mux_sel ),
.imm_a_mux_sel_o ( imm_a_mux_sel ),
.imm_b_mux_sel_o ( imm_b_mux_sel ),
.imm_a_mux_sel_o ( imm_a_mux_sel ),
.imm_b_mux_sel_o ( imm_b_mux_sel ),
.mult_int_en_o ( mult_int_en ),
.div_int_en_o ( div_int_en ),
.multdiv_operator_o ( multdiv_operator ),
.multdiv_signed_mode_o ( multdiv_signed_mode ),
// Register file control signals
.regfile_we_o ( regfile_we_id ),
.mult_int_en_o ( mult_int_en ),
.div_int_en_o ( div_int_en ),
.multdiv_operator_o ( multdiv_operator ),
.multdiv_signed_mode_o ( multdiv_signed_mode ),
// Register file control signals
.regfile_we_o ( regfile_we_id ),
// CSR control signals
.csr_access_o ( csr_access ),
.csr_op_o ( csr_op ),
.csr_status_o ( csr_status ),
// CSR control signals
.csr_access_o ( csr_access ),
.csr_op_o ( csr_op ),
.csr_status_o ( csr_status ),
// Data bus interface
.data_req_o ( data_req_id ),
.data_we_o ( data_we_id ),
.data_type_o ( data_type_id ),
.data_sign_extension_o ( data_sign_ext_id ),
.data_reg_offset_o ( data_reg_offset_id ),
// Data bus interface
.data_req_o ( data_req_id ),
.data_we_o ( data_we_id ),
.data_type_o ( data_type_id ),
.data_sign_extension_o ( data_sign_ext_id ),
.data_reg_offset_o ( data_reg_offset_id ),
// jump/branches
.jump_in_id_o ( jump_in_id ),
.branch_in_id_o ( branch_in_id )
// jump/branches
.jump_in_id_o ( jump_in_id ),
.branch_in_id_o ( branch_in_id )
);
////////////////////////////////////////////////////////////////////
@ -508,116 +486,114 @@ module ibex_id_stage
// //
////////////////////////////////////////////////////////////////////
ibex_controller controller_i
(
.clk ( clk ),
.rst_n ( rst_n ),
ibex_controller controller_i (
.clk ( clk ),
.rst_n ( rst_n ),
.fetch_enable_i ( fetch_enable_i ),
.ctrl_busy_o ( ctrl_busy_o ),
.first_fetch_o ( core_ctrl_firstfetch_o ),
.is_decoding_o ( is_decoding_o ),
.fetch_enable_i ( fetch_enable_i ),
.ctrl_busy_o ( ctrl_busy_o ),
.first_fetch_o ( core_ctrl_firstfetch_o ),
.is_decoding_o ( is_decoding_o ),
// decoder related signals
.deassert_we_o ( deassert_we ),
.illegal_insn_i ( illegal_insn_dec | illegal_reg_rv32e ),
.ecall_insn_i ( ecall_insn_dec ),
.mret_insn_i ( mret_insn_dec ),
.pipe_flush_i ( pipe_flush_dec ),
.ebrk_insn_i ( ebrk_insn ),
.csr_status_i ( csr_status ),
// decoder related signals
.deassert_we_o ( deassert_we ),
.illegal_insn_i ( illegal_insn_dec | illegal_reg_rv32e ),
.ecall_insn_i ( ecall_insn_dec ),
.mret_insn_i ( mret_insn_dec ),
.pipe_flush_i ( pipe_flush_dec ),
.ebrk_insn_i ( ebrk_insn ),
.csr_status_i ( csr_status ),
// from IF/ID pipeline
.instr_valid_i ( instr_valid_i ),
// from IF/ID pipeline
.instr_valid_i ( instr_valid_i ),
// from prefetcher
.instr_req_o ( instr_req_o ),
// from prefetcher
.instr_req_o ( instr_req_o ),
// to prefetcher
.pc_set_o ( pc_set_o ),
.pc_mux_o ( pc_mux_o ),
.exc_pc_mux_o ( exc_pc_mux_o ),
.exc_cause_o ( exc_cause_o ),
// to prefetcher
.pc_set_o ( pc_set_o ),
.pc_mux_o ( pc_mux_o ),
.exc_pc_mux_o ( exc_pc_mux_o ),
.exc_cause_o ( exc_cause_o ),
// LSU
.data_misaligned_i ( data_misaligned_i ),
// LSU
.data_misaligned_i ( data_misaligned_i ),
// jump/branch control
.branch_in_id_i ( branch_in_id ),
.branch_taken_ex_i ( branch_taken_ex ),
.branch_set_i ( branch_set_q ),
.jump_set_i ( jump_set ),
// jump/branch control
.branch_in_id_i ( branch_in_id ),
.branch_taken_ex_i ( branch_taken_ex ),
.branch_set_i ( branch_set_q ),
.jump_set_i ( jump_set ),
.instr_multicyle_i ( instr_multicyle ),
.instr_multicyle_i ( instr_multicyle ),
.irq_i ( irq_i ),
// Interrupt Controller Signals
.irq_req_ctrl_i ( irq_req_ctrl ),
.irq_id_ctrl_i ( irq_id_ctrl ),
.m_IE_i ( m_irq_enable_i ),
.irq_i ( irq_i ),
// Interrupt Controller Signals
.irq_req_ctrl_i ( irq_req_ctrl ),
.irq_id_ctrl_i ( irq_id_ctrl ),
.m_IE_i ( m_irq_enable_i ),
.irq_ack_o ( irq_ack_o ),
.irq_id_o ( irq_id_o ),
.irq_ack_o ( irq_ack_o ),
.irq_id_o ( irq_id_o ),
.exc_ack_o ( exc_ack ),
.exc_kill_o ( exc_kill ),
.exc_ack_o ( exc_ack ),
.exc_kill_o ( exc_kill ),
// CSR Controller Signals
.csr_save_cause_o ( csr_save_cause_o ),
.csr_cause_o ( csr_cause_o ),
.csr_save_if_o ( csr_save_if_o ),
.csr_save_id_o ( csr_save_id_o ),
.csr_restore_mret_id_o ( csr_restore_mret_id_o ),
// CSR Controller Signals
.csr_save_cause_o ( csr_save_cause_o ),
.csr_cause_o ( csr_cause_o ),
.csr_save_if_o ( csr_save_if_o ),
.csr_save_id_o ( csr_save_id_o ),
.csr_restore_mret_id_o ( csr_restore_mret_id_o ),
// Debug Unit Signals
.dbg_req_i ( dbg_req_i ),
.dbg_ack_o ( dbg_ack_o ),
.dbg_stall_i ( dbg_stall_i ),
.dbg_jump_req_i ( dbg_jump_req_i ),
.dbg_settings_i ( dbg_settings_i ),
.dbg_trap_o ( dbg_trap_o ),
// Debug Unit Signals
.dbg_req_i ( dbg_req_i ),
.dbg_ack_o ( dbg_ack_o ),
.dbg_stall_i ( dbg_stall_i ),
.dbg_jump_req_i ( dbg_jump_req_i ),
.dbg_settings_i ( dbg_settings_i ),
.dbg_trap_o ( dbg_trap_o ),
// Forwarding signals
.operand_a_fw_mux_sel_o ( operand_a_fw_mux_sel ),
// Forwarding signals
.operand_a_fw_mux_sel_o ( operand_a_fw_mux_sel ),
// Stall signals
.halt_if_o ( halt_if_o ),
.halt_id_o ( halt_id ),
// Stall signals
.halt_if_o ( halt_if_o ),
.halt_id_o ( halt_id ),
.id_ready_i ( id_ready_o ),
.id_ready_i ( id_ready_o ),
// Performance Counters
.perf_jump_o ( perf_jump_o ),
.perf_tbranch_o ( perf_tbranch_o )
// Performance Counters
.perf_jump_o ( perf_jump_o ),
.perf_tbranch_o ( perf_tbranch_o )
);
////////////////////////////////////////////////////////////////////////
// _____ _ _____ _ _ _ //
// |_ _| | | / __ \ | | | | | //
// | | _ __ | |_ | / \/ ___ _ __ | |_ _ __ ___ | | | ___ _ __ //
// | || '_ \| __| | | / _ \| '_ \| __| '__/ _ \| | |/ _ \ '__| //
// _| || | | | |_ _ | \__/\ (_) | | | | |_| | | (_) | | | __/ | //
// \___/_| |_|\__(_) \____/\___/|_| |_|\__|_| \___/|_|_|\___|_| //
// //
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// _____ _ _____ _ _ _ //
// |_ _| | | / __ \ | | | | | //
// | | _ __ | |_ | / \/ ___ _ __ | |_ _ __ ___ | | | ___ _ __ //
// | || '_ \| __| | | / _ \| '_ \| __| '__/ _ \| | |/ _ \ '__| //
// _| || | | | |_ _ | \__/\ (_) | | | | |_| | | (_) | | | __/ | //
// \___/_| |_|\__(_) \____/\___/|_| |_|\__|_| \___/|_|_|\___|_| //
// //
////////////////////////////////////////////////////////////////////////
ibex_int_controller int_controller_i
(
.clk ( clk ),
.rst_n ( rst_n ),
ibex_int_controller int_controller_i (
.clk ( clk ),
.rst_n ( rst_n ),
// to controller
.irq_req_ctrl_o ( irq_req_ctrl ),
.irq_id_ctrl_o ( irq_id_ctrl ),
// to controller
.irq_req_ctrl_o ( irq_req_ctrl ),
.irq_id_ctrl_o ( irq_id_ctrl ),
.ctrl_ack_i ( exc_ack ),
.ctrl_kill_i ( exc_kill ),
.ctrl_ack_i ( exc_ack ),
.ctrl_kill_i ( exc_kill ),
// Interrupt signals
.irq_i ( irq_i ),
.irq_id_i ( irq_id_i ),
// Interrupt signals
.irq_i ( irq_i ),
.irq_id_i ( irq_id_i ),
.m_IE_i ( m_irq_enable_i )
.m_IE_i ( m_irq_enable_i )
);
/////////////////////////////////////
@ -643,8 +619,6 @@ module ibex_id_stage
assign csr_access_ex_o = csr_access;
assign csr_op_ex_o = csr_op;
assign branch_in_ex_o = branch_in_id;
assign mult_en_ex_o = mult_int_en;
assign div_en_ex_o = div_int_en;
@ -653,19 +627,17 @@ module ibex_id_stage
assign multdiv_operand_a_ex_o = regfile_data_ra_id;
assign multdiv_operand_b_ex_o = regfile_data_rb_id;
enum logic { IDLE, WAIT_MULTICYCLE } id_wb_fsm_cs, id_wb_fsm_ns;
typedef enum logic { IDLE, WAIT_MULTICYCLE } id_fsm_e;
id_fsm_e id_wb_fsm_cs, id_wb_fsm_ns;
///////////////////////////////////////
// ID-EX/WB Pipeline Register //
///////////////////////////////////////
always_ff @(posedge clk, negedge rst_n)
begin : EX_WB_Pipeline_Register
if (~rst_n)
begin
always_ff @(posedge clk, negedge rst_n) begin : EX_WB_Pipeline_Register
if (!rst_n) begin
id_wb_fsm_cs <= IDLE;
branch_set_q <= 1'b0;
end
else begin
end else begin
id_wb_fsm_cs <= id_wb_fsm_ns;
branch_set_q <= branch_set_n;
end
@ -675,8 +647,7 @@ module ibex_id_stage
// ID-EX/WB FMS //
///////////////////////////////////////
always_comb
begin
always_comb begin
id_wb_fsm_ns = id_wb_fsm_cs;
regfile_we = regfile_we_id;
load_stall = 1'b0;
@ -693,8 +664,7 @@ module ibex_id_stage
unique case (id_wb_fsm_cs)
IDLE:
begin
IDLE: begin
jump_mux_dec = 1'b1;
branch_mux_dec = 1'b1;
unique case (1'b1)
@ -732,9 +702,8 @@ module ibex_id_stage
endcase
end
WAIT_MULTICYCLE:
begin
if(ex_ready_i) begin
WAIT_MULTICYCLE: begin
if (ex_ready_i) begin
regfile_we = regfile_we_id;
id_wb_fsm_ns = IDLE;
load_stall = 1'b0;
@ -758,9 +727,9 @@ module ibex_id_stage
end
// stall control
assign id_ready_o = (~load_stall) & (~branch_stall) & (~jump_stall) & (~multdiv_stall);
assign id_ready_o = ~load_stall & ~branch_stall & ~jump_stall & ~multdiv_stall;
assign id_valid_o = (~halt_id) & id_ready_o;
assign id_valid_o = ~halt_id & id_ready_o;
//----------------------------------------------------------------------------
@ -769,7 +738,8 @@ module ibex_id_stage
`ifndef VERILATOR
// make sure that branch decision is valid when jumping
assert property (
@(posedge clk) (branch_decision_i !== 1'bx || branch_in_id == 1'b0) ) else begin $display("Branch decision is X"); $stop; end
@(posedge clk) (branch_decision_i !== 1'bx || branch_in_id == 1'b0) ) else begin
$display("Branch decision is X"); $stop; end
`ifdef CHECK_MISALIGNED
assert property (
@ -778,11 +748,13 @@ module ibex_id_stage
// the instruction delivered to the ID stage should always be valid
assert property (
@(posedge clk) (instr_valid_i & (~illegal_c_insn_i)) |-> (!$isunknown(instr_rdata_i)) ) else $display("Instruction is valid, but has at least one X");
@(posedge clk) (instr_valid_i & (~illegal_c_insn_i)) |-> (!$isunknown(instr_rdata_i)) ) else
$display("Instruction is valid, but has at least one X");
// make sure multicycles enable signals are unique
assert property (
@(posedge clk) ~(data_req_ex_o & multdiv_int_en )) else $display("Multicycles enable signals are not unique");
@(posedge clk) ~(data_req_ex_o & multdiv_int_en )) else
$display("Multicycles enable signals are not unique");
`endif

View file

@ -22,257 +22,227 @@
`include "ibex_config.sv"
import ibex_defines::*;
/**
* Instruction Fetch Stage
*
* Instruction fetch unit: Selection of the next PC, and buffering (sampling) of
* the read instruction.
*/
module ibex_if_stage
(
input logic clk,
input logic rst_n,
// the boot address is used to calculate the exception offsets
input logic [31:0] boot_addr_i,
// instruction request control
input logic req_i,
// instruction cache interface
output logic instr_req_o,
output logic [31:0] instr_addr_o,
input logic instr_gnt_i,
input logic instr_rvalid_i,
input logic [31:0] instr_rdata_i,
// Output of IF Pipeline stage
output logic instr_valid_id_o, // instruction in IF/ID pipeline is valid
output logic [31:0] instr_rdata_id_o, // read instruction is sampled and sent to ID stage for decoding
output logic is_compressed_id_o, // compressed decoder thinks this is a compressed instruction
output logic illegal_c_insn_id_o, // compressed decoder thinks this is an invalid instruction
output logic [31:0] pc_if_o,
output logic [31:0] pc_id_o,
// Forwarding ports - control signals
input logic clear_instr_valid_i, // clear instruction valid bit in IF/ID pipe
input logic pc_set_i, // set the program counter to a new value
input logic [31:0] exception_pc_reg_i, // address used to restore PC when the interrupt/exception is served
input logic [2:0] pc_mux_i, // sel for pc multiplexer
input logic [1:0] exc_pc_mux_i, // selects ISR address
input logic [4:0] exc_vec_pc_mux_i, // selects ISR address for vectorized interrupt lines
module ibex_if_stage (
input logic clk,
input logic rst_n,
// the boot address is used to calculate the exception offsets
input logic [31:0] boot_addr_i,
// instruction request control
input logic req_i,
// instruction cache interface
output logic instr_req_o,
output logic [31:0] instr_addr_o,
input logic instr_gnt_i,
input logic instr_rvalid_i,
input logic [31:0] instr_rdata_i,
// Output of IF Pipeline stage
output logic instr_valid_id_o, // instruction in IF/ID pipeline is valid
output logic [31:0] instr_rdata_id_o, // read instruction is sampled and sent
// to ID stage for decoding
output logic is_compressed_id_o, // compressed decoder thinks this is a
// compressed instruction
output logic illegal_c_insn_id_o, // compressed decoder thinks this is an
// invalid instruction
output logic [31:0] pc_if_o,
output logic [31:0] pc_id_o,
// Forwarding ports - control signals
input logic clear_instr_valid_i, // clear instruction valid bit in IF/ID pipe
input logic pc_set_i, // set the program counter to a new value
input logic [31:0] exception_pc_reg_i, // address used to restore PC when the
// interrupt/exception is served
input logic [2:0] pc_mux_i, // sel for pc multiplexer
input logic [1:0] exc_pc_mux_i, // selects ISR address
input logic [4:0] exc_vec_pc_mux_i, // selects ISR address for vectorized
// interrupt lines
// jump and branch target and decision
input logic [31:0] jump_target_ex_i, // jump target address
// from debug unit
input logic [31:0] dbg_jump_addr_i,
// pipeline stall
input logic halt_if_i,
input logic id_ready_i,
output logic if_valid_o,
// misc signals
output logic if_busy_o, // is the IF stage busy fetching instructions?
output logic perf_imiss_o // Instruction Fetch Miss
);
// jump and branch target and decision
input logic [31:0] jump_target_ex_i, // jump target address
// from debug unit
input logic [31:0] dbg_jump_addr_i,
// pipeline stall
input logic halt_if_i,
input logic id_ready_i,
output logic if_valid_o,
// misc signals
output logic if_busy_o, // is the IF stage busy fetching instructions?
output logic perf_imiss_o // Instruction Fetch Miss
);
// offset FSM
enum logic[0:0] {WAIT, IDLE } offset_fsm_cs, offset_fsm_ns;
import ibex_defines::*;
logic valid;
logic if_ready;
// prefetch buffer related signals
logic prefetch_busy;
logic branch_req;
logic [31:0] fetch_addr_n;
logic offset_in_init_d, offset_in_init_q;
logic valid;
logic if_ready;
// prefetch buffer related signals
logic prefetch_busy;
logic branch_req;
logic [31:0] fetch_addr_n;
logic fetch_valid;
logic fetch_ready;
logic [31:0] fetch_rdata;
logic [31:0] fetch_addr;
logic fetch_valid;
logic fetch_ready;
logic [31:0] fetch_rdata;
logic [31:0] fetch_addr;
logic [31:0] exc_pc;
logic [31:0] exc_pc;
// exception PC selection mux
always_comb begin : EXC_PC_MUX
exc_pc = '0;
unique case (exc_pc_mux_i)
EXC_PC_ILLINSN: exc_pc = { boot_addr_i[31:8], EXC_OFF_ILLINSN };
EXC_PC_ECALL: exc_pc = { boot_addr_i[31:8], EXC_OFF_ECALL };
EXC_PC_IRQ: exc_pc = { boot_addr_i[31:8], 1'b0, exc_vec_pc_mux_i[4:0], 2'b0 };
// TODO: Add case for EXC_PC_STORE and EXC_PC_LOAD as soon as they are supported
default:;
endcase
end
// fetch address selection
always_comb begin
fetch_addr_n = '0;
unique case (pc_mux_i)
PC_BOOT: fetch_addr_n = {boot_addr_i[31:8], EXC_OFF_RST};
PC_JUMP: fetch_addr_n = jump_target_ex_i;
PC_EXCEPTION: fetch_addr_n = exc_pc; // set PC to exception handler
PC_ERET: fetch_addr_n = exception_pc_reg_i; // PC is restored when returning
// from IRQ/exception
PC_DBG_NPC: fetch_addr_n = dbg_jump_addr_i; // PC is taken from debug unit
default:;
endcase
end
// prefetch buffer, caches a fixed number of instructions
ibex_prefetch_buffer prefetch_buffer_i (
.clk ( clk ),
.rst_n ( rst_n ),
.req_i ( req_i ),
.branch_i ( branch_req ),
.addr_i ( {fetch_addr_n[31:1], 1'b0} ),
.ready_i ( fetch_ready ),
.valid_o ( fetch_valid ),
.rdata_o ( fetch_rdata ),
.addr_o ( fetch_addr ),
// goes to instruction memory / instruction cache
.instr_req_o ( instr_req_o ),
.instr_addr_o ( instr_addr_o ),
.instr_gnt_i ( instr_gnt_i ),
.instr_rvalid_i ( instr_rvalid_i ),
.instr_rdata_i ( instr_rdata_i ),
// Prefetch Buffer Status
.busy_o ( prefetch_busy )
);
// offset initialization state
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
offset_in_init_q <= 1'b1;
end else begin
offset_in_init_q <= offset_in_init_d;
end
end
// exception PC selection mux
always_comb
begin : EXC_PC_MUX
exc_pc = '0;
// offset initialization related transition logic
always_comb begin
offset_in_init_d = offset_in_init_q;
unique case (exc_pc_mux_i)
EXC_PC_ILLINSN: exc_pc = { boot_addr_i[31:8], EXC_OFF_ILLINSN };
EXC_PC_ECALL: exc_pc = { boot_addr_i[31:8], EXC_OFF_ECALL };
EXC_PC_IRQ: exc_pc = { boot_addr_i[31:8], 1'b0, exc_vec_pc_mux_i[4:0], 2'b0 };
// TODO: Add case for EXC_PC_STORE and EXC_PC_LOAD as soon as they are supported
default:;
endcase
fetch_ready = 1'b0;
branch_req = 1'b0;
valid = 1'b0;
if (offset_in_init_q) begin
// no valid instruction data for ID stage, assume aligned
if (req_i) begin
branch_req = 1'b1;
offset_in_init_d = 1'b0;
end
end else begin
if (fetch_valid) begin
valid = 1'b1; // an instruction is ready for ID stage
if (req_i && if_valid_o) begin
fetch_ready = 1'b1;
offset_in_init_d = 1'b0;
end
end
end
// fetch address selection
always_comb
begin
fetch_addr_n = '0;
// take care of jumps and branches
if (pc_set_i) begin
valid = 1'b0;
unique case (pc_mux_i)
PC_BOOT: fetch_addr_n = {boot_addr_i[31:8], EXC_OFF_RST};
PC_JUMP: fetch_addr_n = jump_target_ex_i;
PC_EXCEPTION: fetch_addr_n = exc_pc; // set PC to exception handler
PC_ERET: fetch_addr_n = exception_pc_reg_i; // PC is restored when returning from IRQ/exception
PC_DBG_NPC: fetch_addr_n = dbg_jump_addr_i; // PC is taken from debug unit
// switch to new PC from ID stage
branch_req = 1'b1;
offset_in_init_d = 1'b0;
end
end
default:;
endcase
end
assign pc_if_o = fetch_addr;
assign if_busy_o = prefetch_busy;
assign perf_imiss_o = ~fetch_valid | branch_req;
// prefetch buffer, caches a fixed number of instructions
ibex_prefetch_buffer prefetch_buffer_i
(
.clk ( clk ),
.rst_n ( rst_n ),
// compressed instruction decoding, or more precisely compressed instruction
// expander
//
// since it does not matter where we decompress instructions, we do it here
// to ease timing closure
logic [31:0] instr_decompressed;
logic illegal_c_insn;
logic instr_compressed_int;
.req_i ( req_i ),
ibex_compressed_decoder compressed_decoder_i (
.instr_i ( fetch_rdata ),
.instr_o ( instr_decompressed ),
.is_compressed_o ( instr_compressed_int ),
.illegal_instr_o ( illegal_c_insn )
);
.branch_i ( branch_req ),
.addr_i ( {fetch_addr_n[31:1], 1'b0} ),
// IF-ID pipeline registers, frozen when the ID stage is stalled
always_ff @(posedge clk, negedge rst_n) begin : IF_ID_PIPE_REGISTERS
if (!rst_n) begin
instr_valid_id_o <= 1'b0;
instr_rdata_id_o <= '0;
illegal_c_insn_id_o <= 1'b0;
is_compressed_id_o <= 1'b0;
pc_id_o <= '0;
end else begin
if (if_valid_o) begin
instr_valid_id_o <= 1'b1;
instr_rdata_id_o <= instr_decompressed;
illegal_c_insn_id_o <= illegal_c_insn;
is_compressed_id_o <= instr_compressed_int;
pc_id_o <= pc_if_o;
end else if (clear_instr_valid_i) begin
instr_valid_id_o <= 1'b0;
end
end
end
.ready_i ( fetch_ready ),
.valid_o ( fetch_valid ),
.rdata_o ( fetch_rdata ),
.addr_o ( fetch_addr ),
assign if_ready = valid & id_ready_i;
assign if_valid_o = ~halt_if_i & if_ready;
// goes to instruction memory / instruction cache
.instr_req_o ( instr_req_o ),
.instr_addr_o ( instr_addr_o ),
.instr_gnt_i ( instr_gnt_i ),
.instr_rvalid_i ( instr_rvalid_i ),
.instr_rdata_i ( instr_rdata_i ),
// Prefetch Buffer Status
.busy_o ( prefetch_busy )
);
// offset FSM state
always_ff @(posedge clk, negedge rst_n)
begin
if (rst_n == 1'b0) begin
offset_fsm_cs <= IDLE;
end else begin
offset_fsm_cs <= offset_fsm_ns;
end
end
// offset FSM state transition logic
always_comb
begin
offset_fsm_ns = offset_fsm_cs;
fetch_ready = 1'b0;
branch_req = 1'b0;
valid = 1'b0;
unique case (offset_fsm_cs)
// no valid instruction data for ID stage
// assume aligned
IDLE: begin
if (req_i) begin
branch_req = 1'b1;
offset_fsm_ns = WAIT;
end
end
// serving aligned 32 bit or 16 bit instruction, we don't know yet
WAIT: begin
if (fetch_valid) begin
valid = 1'b1; // an instruction is ready for ID stage
if (req_i && if_valid_o) begin
fetch_ready = 1'b1;
offset_fsm_ns = WAIT;
end
end
end
default: begin
offset_fsm_ns = IDLE;
end
endcase
// take care of jumps and branches
if (pc_set_i) begin
valid = 1'b0;
// switch to new PC from ID stage
branch_req = 1'b1;
offset_fsm_ns = WAIT;
end
end
assign pc_if_o = fetch_addr;
assign if_busy_o = prefetch_busy;
assign perf_imiss_o = (~fetch_valid) | branch_req;
// compressed instruction decoding, or more precisely compressed instruction
// expander
//
// since it does not matter where we decompress instructions, we do it here
// to ease timing closure
logic [31:0] instr_decompressed;
logic illegal_c_insn;
logic instr_compressed_int;
ibex_compressed_decoder compressed_decoder_i
(
.instr_i ( fetch_rdata ),
.instr_o ( instr_decompressed ),
.is_compressed_o ( instr_compressed_int ),
.illegal_instr_o ( illegal_c_insn )
);
// IF-ID pipeline registers, frozen when the ID stage is stalled
always_ff @(posedge clk, negedge rst_n)
begin : IF_ID_PIPE_REGISTERS
if (rst_n == 1'b0)
begin
instr_valid_id_o <= 1'b0;
instr_rdata_id_o <= '0;
illegal_c_insn_id_o <= 1'b0;
is_compressed_id_o <= 1'b0;
pc_id_o <= '0;
end
else
begin
if (if_valid_o)
begin
instr_valid_id_o <= 1'b1;
instr_rdata_id_o <= instr_decompressed;
illegal_c_insn_id_o <= illegal_c_insn;
is_compressed_id_o <= instr_compressed_int;
pc_id_o <= pc_if_o;
end else if (clear_instr_valid_i) begin
instr_valid_id_o <= 1'b0;
end
end
end
assign if_ready = valid & id_ready_i;
assign if_valid_o = (~halt_if_i) & if_ready;
//----------------------------------------------------------------------------
// Assertions
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// Assertions
//----------------------------------------------------------------------------
`ifndef VERILATOR
// there should never be a grant when there is no request
assert property (
@(posedge clk) (instr_gnt_i) |-> (instr_req_o) )
else $warning("There was a grant without a request");
// there should never be a grant when there is no request
assert property (
@(posedge clk) (instr_gnt_i) |-> (instr_req_o) )
else $warning("There was a grant without a request");
`endif
endmodule
endmodule

View file

@ -16,91 +16,76 @@
// //
////////////////////////////////////////////////////////////////////////////////
import ibex_defines::*;
/**
* Interrupt Controller
*/
module ibex_int_controller
(
input logic clk,
input logic rst_n,
module ibex_int_controller (
input logic clk,
input logic rst_n,
// irq_req for controller
output logic irq_req_ctrl_o,
output logic [4:0] irq_id_ctrl_o,
// irq_req for controller
output logic irq_req_ctrl_o,
output logic [4:0] irq_id_ctrl_o,
// handshake signals to controller
input logic ctrl_ack_i,
input logic ctrl_kill_i,
// handshake signals to controller
input logic ctrl_ack_i,
input logic ctrl_kill_i,
// external interrupt lines
input logic irq_i, // level-triggered interrupt inputs
input logic [4:0] irq_id_i, // interrupt id [0,1,....31]
// external interrupt lines
input logic irq_i, // level-triggered interrupt inputs
input logic [4:0] irq_id_i, // interrupt id [0,1,....31]
input logic m_IE_i // interrupt enable bit from CSR (M mode)
input logic m_IE_i // interrupt enable bit from CSR (M mode)
);
enum logic [1:0] { IDLE, IRQ_PENDING, IRQ_DONE} exc_ctrl_cs;
import ibex_defines::*;
typedef enum logic [1:0] { IDLE, IRQ_PENDING, IRQ_DONE} exc_ctrl_e;
exc_ctrl_e exc_ctrl_ns, exc_ctrl_cs;
logic irq_enable_ext;
logic [4:0] irq_id_q;
logic [4:0] irq_id_d, irq_id_q;
assign irq_enable_ext = m_IE_i;
assign irq_req_ctrl_o = exc_ctrl_cs == IRQ_PENDING;
assign irq_id_ctrl_o = irq_id_q;
always_ff @(posedge clk, negedge rst_n)
begin
if (rst_n == 1'b0) begin
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
irq_id_q <= '0;
exc_ctrl_cs <= IDLE;
end else begin
unique case (exc_ctrl_cs)
IDLE:
begin
if(irq_enable_ext & irq_i) begin
exc_ctrl_cs <= IRQ_PENDING;
irq_id_q <= irq_id_i;
end
end
IRQ_PENDING:
begin
unique case(1'b1)
ctrl_ack_i:
exc_ctrl_cs <= IRQ_DONE;
ctrl_kill_i:
exc_ctrl_cs <= IDLE;
default:
exc_ctrl_cs <= IRQ_PENDING;
endcase
end
IRQ_DONE:
begin
exc_ctrl_cs <= IDLE;
end
endcase
irq_id_q <= irq_id_d;
exc_ctrl_cs <= exc_ctrl_ns;
end
end
`ifndef SYNTHESIS
// synopsys translate_off
// evaluate at falling edge to avoid duplicates during glitches
// Removed this message as it pollutes too much the output and makes tests fail
//always_ff @(negedge clk)
//begin
// if (rst_n && exc_ctrl_cs == IRQ_DONE)
// $display("%t: Entering interrupt service routine. [%m]", $time);
//end
// synopsys translate_on
`endif
always_comb begin
irq_id_d = irq_id_q;
exc_ctrl_ns = exc_ctrl_cs;
unique case (exc_ctrl_cs)
IDLE: begin
if (irq_enable_ext && irq_i) begin
exc_ctrl_ns = IRQ_PENDING;
irq_id_d = irq_id_i;
end
end
IRQ_PENDING: begin
unique case(1'b1)
ctrl_ack_i:
exc_ctrl_ns = IRQ_DONE;
ctrl_kill_i:
exc_ctrl_ns = IDLE;
default:
exc_ctrl_ns = IRQ_PENDING;
endcase
end
IRQ_DONE: begin
exc_ctrl_ns = IDLE;
end
endcase
end
endmodule

View file

@ -28,8 +28,7 @@
* Load Store Unit, used to eliminate multiple access during processor stalls,
* and to align bytes and halfwords.
*/
module ibex_load_store_unit
(
module ibex_load_store_unit (
input logic clk,
input logic rst_n,
@ -84,96 +83,88 @@ module ibex_load_store_unit
logic [3:0] data_be;
logic [31:0] data_wdata;
logic misaligned_st; // high if we are currently performing the second part of a misaligned store
logic misaligned_st; // high if we are currently performing the second part
// of a misaligned store
logic data_misaligned, data_misaligned_q;
logic increase_address;
enum logic [2:0] { IDLE, WAIT_GNT_MIS, WAIT_RVALID_MIS, WAIT_GNT, WAIT_RVALID } CS, NS;
typedef enum logic [2:0] {
IDLE, WAIT_GNT_MIS, WAIT_RVALID_MIS, WAIT_GNT, WAIT_RVALID
} ls_fsm_e;
ls_fsm_e CS, NS;
logic [31:0] rdata_q;
///////////////////////////////// BE generation ////////////////////////////////
always_comb
begin
always_comb begin
case (data_type_ex_i) // Data type 00 Word, 01 Half word, 11,10 byte
2'b00:
begin // Writing a word
if (misaligned_st == 1'b0)
begin // non-misaligned case
case (data_addr_int[1:0])
2'b00: begin // Writing a word
if (!misaligned_st) begin // non-misaligned case
unique case (data_addr_int[1:0])
2'b00: data_be = 4'b1111;
2'b01: data_be = 4'b1110;
2'b10: data_be = 4'b1100;
2'b11: data_be = 4'b1000;
endcase; // case (data_addr_int[1:0])
end
else
begin // misaligned case
case (data_addr_int[1:0])
endcase // case (data_addr_int[1:0])
end else begin // misaligned case
unique case (data_addr_int[1:0])
2'b00: data_be = 4'b0000; // this is not used, but included for completeness
2'b01: data_be = 4'b0001;
2'b10: data_be = 4'b0011;
2'b11: data_be = 4'b0111;
endcase; // case (data_addr_int[1:0])
endcase // case (data_addr_int[1:0])
end
end
2'b01:
begin // Writing a half word
if (misaligned_st == 1'b0)
begin // non-misaligned case
case (data_addr_int[1:0])
2'b01: begin // Writing a half word
if (!misaligned_st) begin // non-misaligned case
unique case (data_addr_int[1:0])
2'b00: data_be = 4'b0011;
2'b01: data_be = 4'b0110;
2'b10: data_be = 4'b1100;
2'b11: data_be = 4'b1000;
endcase; // case (data_addr_int[1:0])
end
else
begin // misaligned case
endcase // case (data_addr_int[1:0])
end else begin // misaligned case
data_be = 4'b0001;
end
end
2'b10,
2'b11: begin // Writing a byte
case (data_addr_int[1:0])
unique case (data_addr_int[1:0])
2'b00: data_be = 4'b0001;
2'b01: data_be = 4'b0010;
2'b10: data_be = 4'b0100;
2'b11: data_be = 4'b1000;
endcase; // case (data_addr_int[1:0])
endcase // case (data_addr_int[1:0])
end
endcase; // case (data_type_ex_i)
endcase // case (data_type_ex_i)
end
// prepare data to be written to the memory
// we handle misaligned accesses, half word and byte accesses and
// register offsets here
assign wdata_offset = data_addr_int[1:0] - data_reg_offset_ex_i[1:0];
always_comb
begin
case (wdata_offset)
always_comb begin
unique case (wdata_offset)
2'b00: data_wdata = data_wdata_ex_i[31:0];
2'b01: data_wdata = {data_wdata_ex_i[23:0], data_wdata_ex_i[31:24]};
2'b10: data_wdata = {data_wdata_ex_i[15:0], data_wdata_ex_i[31:16]};
2'b11: data_wdata = {data_wdata_ex_i[ 7:0], data_wdata_ex_i[31: 8]};
endcase; // case (wdata_offset)
endcase // case (wdata_offset)
end
// FF for rdata alignment and sign-extension
always_ff @(posedge clk, negedge rst_n)
begin
if(rst_n == 1'b0)
begin
data_type_q <= '0;
rdata_offset_q <= '0;
data_sign_ext_q <= '0;
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
data_type_q <= 2'h0;
rdata_offset_q <= 2'h0;
data_sign_ext_q <= 1'b0;
data_we_q <= 1'b0;
end
else if (data_gnt_i == 1'b1) // request was granted, we wait for rvalid and can continue to WB
begin
end else if (data_gnt_i) begin
// request was granted, we wait for rvalid and can continue to WB
data_type_q <= data_type_ex_i;
rdata_offset_q <= data_addr_int[1:0];
data_sign_ext_q <= data_sign_ext_ex_i;
@ -181,7 +172,6 @@ module ibex_load_store_unit
end
end
////////////////////////////////////////////////////////////////////////
// ____ _ _____ _ _ //
// / ___|(_) __ _ _ __ | ____|_ _| |_ ___ _ __ ___(_) ___ _ __ //
@ -198,8 +188,7 @@ module ibex_load_store_unit
logic [31:0] rdata_b_ext; // sign extension for bytes
// take care of misaligned words
always_comb
begin
always_comb begin
case (rdata_offset_q)
2'b00: rdata_w_ext = data_rdata_i[31:0];
2'b01: rdata_w_ext = {data_rdata_i[ 7:0], rdata_q[31:8]};
@ -209,83 +198,81 @@ module ibex_load_store_unit
end
// sign extension for half words
always_comb
begin
always_comb begin
case (rdata_offset_q)
2'b00:
begin
if (data_sign_ext_q == 1'b0)
2'b00: begin
if (!data_sign_ext_q) begin
rdata_h_ext = {16'h0000, data_rdata_i[15:0]};
else
end else begin
rdata_h_ext = {{16{data_rdata_i[15]}}, data_rdata_i[15:0]};
end
end
2'b01:
begin
if (data_sign_ext_q == 1'b0)
2'b01: begin
if (!data_sign_ext_q) begin
rdata_h_ext = {16'h0000, data_rdata_i[23:8]};
else
end else begin
rdata_h_ext = {{16{data_rdata_i[23]}}, data_rdata_i[23:8]};
end
end
2'b10:
begin
if (data_sign_ext_q == 1'b0)
2'b10: begin
if (!data_sign_ext_q) begin
rdata_h_ext = {16'h0000, data_rdata_i[31:16]};
else
end else begin
rdata_h_ext = {{16{data_rdata_i[31]}}, data_rdata_i[31:16]};
end
end
2'b11:
begin
if (data_sign_ext_q == 1'b0)
2'b11: begin
if (!data_sign_ext_q) begin
rdata_h_ext = {16'h0000, data_rdata_i[7:0], rdata_q[31:24]};
else
end else begin
rdata_h_ext = {{16{data_rdata_i[7]}}, data_rdata_i[7:0], rdata_q[31:24]};
end
end
endcase // case (rdata_offset_q)
end
// sign extension for bytes
always_comb
begin
always_comb begin
case (rdata_offset_q)
2'b00:
begin
if (data_sign_ext_q == 1'b0)
2'b00: begin
if (!data_sign_ext_q) begin
rdata_b_ext = {24'h00_0000, data_rdata_i[7:0]};
else
end else begin
rdata_b_ext = {{24{data_rdata_i[7]}}, data_rdata_i[7:0]};
end
end
2'b01: begin
if (data_sign_ext_q == 1'b0)
if (!data_sign_ext_q) begin
rdata_b_ext = {24'h00_0000, data_rdata_i[15:8]};
else
end else begin
rdata_b_ext = {{24{data_rdata_i[15]}}, data_rdata_i[15:8]};
end
end
2'b10:
begin
if (data_sign_ext_q == 1'b0)
2'b10: begin
if (!data_sign_ext_q) begin
rdata_b_ext = {24'h00_0000, data_rdata_i[23:16]};
else
end else begin
rdata_b_ext = {{24{data_rdata_i[23]}}, data_rdata_i[23:16]};
end
end
2'b11:
begin
if (data_sign_ext_q == 1'b0)
2'b11: begin
if (!data_sign_ext_q) begin
rdata_b_ext = {24'h00_0000, data_rdata_i[31:24]};
else
end else begin
rdata_b_ext = {{24{data_rdata_i[31]}}, data_rdata_i[31:24]};
end
end
endcase // case (rdata_offset_q)
end
// select word, half word or byte sign extended version
always_comb
begin
always_comb begin
case (data_type_q)
2'b00: data_rdata_ext = rdata_w_ext;
2'b01: data_rdata_ext = rdata_h_ext;
@ -295,42 +282,38 @@ module ibex_load_store_unit
always_ff @(posedge clk, negedge rst_n)
begin
if(rst_n == 1'b0)
begin
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
CS <= IDLE;
rdata_q <= '0;
data_misaligned_q <= '0;
misaligned_addr_o <= 32'b0;
end
else
begin
end else begin
CS <= NS;
if (lsu_update_addr_o) begin
data_misaligned_q <= data_misaligned;
if(increase_address) begin
if (increase_address) begin
misaligned_addr_o <= data_addr_int;
end
end
if (data_rvalid_i && (~data_we_q))
begin
if (data_rvalid_i && !data_we_q) begin
// if we have detected a misaligned access, and we are
// currently doing the first part of this access, then
// store the data coming from memory in rdata_q.
// In all other cases, rdata_q gets the value that we are
// writing to the register file
if ((data_misaligned_q == 1'b1) || (data_misaligned == 1'b1))
if (data_misaligned_q || data_misaligned) begin
rdata_q <= data_rdata_i;
else
end else begin
rdata_q <= data_rdata_ext;
end
end
end
end
// output to register file
assign data_rdata_ex_o = (data_rvalid_i == 1'b1) ? data_rdata_ext : rdata_q;
assign data_rdata_ex_o = data_rvalid_i ? data_rdata_ext : rdata_q;
// output to data interface
assign data_addr_o = data_addr_int;
@ -344,8 +327,7 @@ module ibex_load_store_unit
assign store_err_o = 1'b0;
// FSM
always_comb
begin
always_comb begin
NS = CS;
data_req_o = 1'b0;
@ -358,34 +340,30 @@ module ibex_load_store_unit
case(CS)
// starts from not active and stays in IDLE until request was granted
IDLE:
begin
IDLE: begin
if (data_req_ex_i) begin
data_req_o = data_req_ex_i;
if(data_gnt_i) begin
lsu_update_addr_o = 1'b1;
increase_address = data_misaligned;
NS = data_misaligned ? WAIT_RVALID_MIS : WAIT_RVALID;
end
else begin
NS = data_misaligned ? WAIT_GNT_MIS : WAIT_GNT;
end
data_req_o = data_req_ex_i;
if (data_gnt_i) begin
lsu_update_addr_o = 1'b1;
increase_address = data_misaligned;
NS = data_misaligned ? WAIT_RVALID_MIS : WAIT_RVALID;
end else begin
NS = data_misaligned ? WAIT_GNT_MIS : WAIT_GNT;
end
end
end //~ IDLE
end // IDLE
WAIT_GNT_MIS:
begin
WAIT_GNT_MIS: begin
data_req_o = 1'b1;
if(data_gnt_i) begin
if (data_gnt_i) begin
lsu_update_addr_o = 1'b1;
increase_address = data_misaligned;
NS = WAIT_RVALID_MIS;
end
end //~ WAIT_GNT_MIS
end // WAIT_GNT_MIS
// wait for rvalid in WB stage and send a new request if there is any
WAIT_RVALID_MIS:
begin
WAIT_RVALID_MIS: begin
//increase_address goes down, we already have the proper address
increase_address = 1'b0;
//tell the controller to update the address
@ -393,23 +371,21 @@ module ibex_load_store_unit
data_req_o = 1'b0;
lsu_update_addr_o = data_gnt_i;
if(data_rvalid_i) begin
//if first part rvalid is received
data_req_o = 1'b1;
if(data_gnt_i) begin
//second grant is received
NS = WAIT_RVALID;
//in this stage we already received the first valid but no the second one
//it differes from WAIT_RVALID_MIS because we do not send other requests
end
else begin
//second grant is NOT received, but first rvalid yes
//lsu_update_addr_o is 0 so data_misaligned_q stays high in WAIT_GNT
//increase address stays the same as well
NS = WAIT_GNT; // [1]
end
end
else begin
if (data_rvalid_i) begin
//if first part rvalid is received
data_req_o = 1'b1;
if (data_gnt_i) begin
//second grant is received
NS = WAIT_RVALID;
//in this stage we already received the first valid but no the second one
//it differes from WAIT_RVALID_MIS because we do not send other requests
end else begin
//second grant is NOT received, but first rvalid yes
//lsu_update_addr_o is 0 so data_misaligned_q stays high in WAIT_GNT
//increase address stays the same as well
NS = WAIT_GNT; // [1]
end
end else begin
//if first part rvalid is NOT received
//the second grand is not received either by protocol.
//stay here
@ -417,26 +393,23 @@ module ibex_load_store_unit
end
end
WAIT_GNT:
begin
WAIT_GNT: begin
data_misaligned_o = data_misaligned_q;
//useful in case [1]
data_req_o = 1'b1;
if(data_gnt_i) begin
if (data_gnt_i) begin
lsu_update_addr_o = 1'b1;
NS = WAIT_RVALID;
end
end //~ WAIT_GNT
WAIT_RVALID:
begin
WAIT_RVALID: begin
data_req_o = 1'b0;
if(data_rvalid_i) begin
if (data_rvalid_i) begin
data_valid_o = 1'b1;
NS = IDLE;
end
else begin
end else begin
NS = WAIT_RVALID;
end
end //~ WAIT_RVALID
@ -451,31 +424,29 @@ module ibex_load_store_unit
// check for misaligned accesses that need a second memory access
// If one is detected, this is signaled with data_misaligned_o to
// the controller which selectively stalls the pipeline
always_comb
begin
always_comb begin
data_misaligned = 1'b0;
if((data_req_ex_i == 1'b1) && (data_misaligned_q == 1'b0))
begin
if (data_req_ex_i && !data_misaligned_q) begin
case (data_type_ex_i)
2'b00: // word
begin
if(data_addr_int[1:0] != 2'b00)
2'b00: begin // word
if (data_addr_int[1:0] != 2'b00) begin
data_misaligned = 1'b1;
end
end
2'b01: // half word
begin
if(data_addr_int[1:0] == 2'b11)
2'b01: begin // half word
if (data_addr_int[1:0] == 2'b11) begin
data_misaligned = 1'b1;
end
end
default: ;
default: ;
endcase // case (data_type_ex_i)
end
end
assign data_addr_int = adder_result_ex_i;
assign busy_o = (CS == WAIT_RVALID) || (data_req_o == 1'b1);
assign busy_o = (CS == WAIT_RVALID) | (data_req_o == 1'b1);
//////////////////////////////////////////////////////////////////////////////
// Assertions

View file

@ -15,8 +15,6 @@
// //
////////////////////////////////////////////////////////////////////////////////
import ibex_defines::*;
`define OP_L 15:0
`define OP_H 31:16
@ -25,30 +23,38 @@ import ibex_defines::*;
*
* 16x16 kernel multiplier and Long Division
*/
module ibex_multdiv_fast
(
input logic clk,
input logic rst_n,
input logic mult_en_i,
input logic div_en_i,
input logic [1:0] operator_i,
input logic [1:0] signed_mode_i,
input logic [31:0] op_a_i,
input logic [31:0] op_b_i,
input logic [33:0] alu_adder_ext_i,
input logic [31:0] alu_adder_i,
input logic equal_to_zero,
module ibex_multdiv_fast (
input logic clk,
input logic rst_n,
input logic mult_en_i,
input logic div_en_i,
input logic [1:0] operator_i,
input logic [1:0] signed_mode_i,
input logic [31:0] op_a_i,
input logic [31:0] op_b_i,
input logic [33:0] alu_adder_ext_i,
input logic [31:0] alu_adder_i,
input logic equal_to_zero,
output logic [32:0] alu_operand_a_o,
output logic [32:0] alu_operand_b_o,
output logic [32:0] alu_operand_a_o,
output logic [32:0] alu_operand_b_o,
output logic [31:0] multdiv_result_o,
output logic ready_o
output logic [31:0] multdiv_result_o,
output logic ready_o
);
import ibex_defines::*;
logic [ 4:0] div_counter_q, div_counter_n;
enum logic [1:0] {ALBL, ALBH, AHBL, AHBH } mult_state_q, mult_state_n;
enum logic [2:0] { MD_IDLE, MD_ABS_A, MD_ABS_B, MD_COMP, MD_LAST, MD_CHANGE_SIGN, MD_FINISH } divcurr_state_q, divcurr_state_n;
typedef enum logic [1:0] {
ALBL, ALBH, AHBL, AHBH
} mult_fsm_e;
mult_fsm_e mult_state_q, mult_state_n;
typedef enum logic [2:0] {
MD_IDLE, MD_ABS_A, MD_ABS_B, MD_COMP, MD_LAST, MD_CHANGE_SIGN, MD_FINISH
} div_fsm_e;
div_fsm_e divcurr_state_q, divcurr_state_n;
logic [34:0] mac_res_ext;
logic [33:0] mac_res_q, mac_res_n, mac_res, op_reminder_n;
@ -67,12 +73,13 @@ module ibex_multdiv_fast
logic [31:0] op_denominator_n;
logic [31:0] op_numerator_n;
logic [31:0] op_quotient_n;
logic [32:0] next_reminder, next_quotient;
logic [31:0] next_reminder;
logic [32:0] next_quotient;
logic [32:0] res_adder_h;
logic mult_is_ready;
always_ff @(posedge clk or negedge rst_n) begin : proc_mult_state_q
if(~rst_n) begin
if (!rst_n) begin
mult_state_q <= ALBL;
mac_res_q <= '0;
div_counter_q <= '0;
@ -82,11 +89,11 @@ module ibex_multdiv_fast
op_quotient_q <= '0;
end else begin
if(mult_en_i) begin
if (mult_en_i) begin
mult_state_q <= mult_state_n;
end
if(div_en_i) begin
if (div_en_i) begin
div_counter_q <= div_counter_n;
op_denominator_q <= op_denominator_n ;
op_numerator_q <= op_numerator_n ;
@ -102,7 +109,6 @@ module ibex_multdiv_fast
default:
mac_res_q <= mac_res_q;
endcase
end
end
@ -115,8 +121,9 @@ module ibex_multdiv_fast
assign res_adder_h = alu_adder_ext_i[33:1];
assign next_reminder = is_greater_equal ? res_adder_h : mac_res_q[32:0];
assign next_quotient = is_greater_equal ? op_quotient_q | one_shift : op_quotient_q;
assign next_reminder = is_greater_equal ? res_adder_h[31:0] : mac_res_q[31:0];
assign next_quotient = is_greater_equal ? {1'b0,op_quotient_q} | {1'b0,one_shift} :
{1'b0,op_quotient_q};
assign one_shift = {31'b0, 1'b1} << div_counter_q;
@ -126,12 +133,12 @@ module ibex_multdiv_fast
the next Reminder is Reminder - Divisor contained in res_adder_h and the
*/
always_comb
begin
if ((mac_res_q[31] ^ op_denominator_q[31]) == 0)
is_greater_equal = (res_adder_h[31] == 0);
else
always_comb begin
if ((mac_res_q[31] ^ op_denominator_q[31]) == 1'b0) begin
is_greater_equal = (res_adder_h[31] == 1'b0);
end else begin
is_greater_equal = mac_res_q[31];
end
end
assign div_sign_a = op_a_i[31] & signed_mode_i[0];
@ -140,199 +147,181 @@ module ibex_multdiv_fast
assign rem_change_sign = div_sign_a;
always_comb
begin : div_fsm
div_counter_n = div_counter_q - 1;
op_reminder_n = mac_res_q;
op_quotient_n = op_quotient_q;
divcurr_state_n = divcurr_state_q;
op_numerator_n = op_numerator_q;
op_denominator_n = op_denominator_q;
alu_operand_a_o = {32'h0 , 1'b1};
alu_operand_b_o = {~op_b_i, 1'b1};
always_comb begin : div_fsm
div_counter_n = div_counter_q - 5'h1;
op_reminder_n = mac_res_q;
op_quotient_n = op_quotient_q;
divcurr_state_n = divcurr_state_q;
op_numerator_n = op_numerator_q;
op_denominator_n = op_denominator_q;
alu_operand_a_o = {32'h0 , 1'b1};
alu_operand_b_o = {~op_b_i, 1'b1};
unique case(divcurr_state_q)
MD_IDLE: begin
unique case(operator_i)
MD_OP_DIV: begin
//Check if the Denominator is 0
//quotient for division by 0
op_reminder_n = '1;
divcurr_state_n = equal_to_zero ? MD_FINISH : MD_ABS_A;
end
default: begin
//Check if the Denominator is 0
//reminder for division by 0
op_reminder_n = {2'b0, op_a_i};
divcurr_state_n = equal_to_zero ? MD_FINISH : MD_ABS_A;
end
endcase
//0 - B = 0 iff B == 0
alu_operand_a_o = {32'h0 , 1'b1};
alu_operand_b_o = {~op_b_i, 1'b1};
div_counter_n = 5'd31;
end
MD_ABS_A: begin
//quotient
op_quotient_n = '0;
//A abs value
op_numerator_n = div_sign_a ? alu_adder_i : op_a_i;
divcurr_state_n = MD_ABS_B;
div_counter_n = 5'd31;
//ABS(A) = 0 - A
alu_operand_a_o = {32'h0 , 1'b1};
alu_operand_b_o = {~op_a_i, 1'b1};
end
MD_ABS_B: begin
//reminder
op_reminder_n = { 33'h0, op_numerator_q[31]};
//B abs value
op_denominator_n = div_sign_b ? alu_adder_i : op_b_i;
divcurr_state_n = MD_COMP;
div_counter_n = 5'd31;
//ABS(B) = 0 - B
alu_operand_a_o = {32'h0 , 1'b1};
alu_operand_b_o = {~op_b_i, 1'b1};
end
MD_COMP: begin
op_reminder_n = {1'b0, next_reminder[31:0], op_numerator_q[div_counter_n]};
op_quotient_n = next_quotient;
if(div_counter_q == 5'd1)
divcurr_state_n = MD_LAST;
else
divcurr_state_n = MD_COMP;
//Division
alu_operand_a_o = {mac_res_q[31:0], 1'b1}; //it contains the reminder
alu_operand_b_o = {~op_denominator_q[31:0], 1'b1}; //denominator negated + 1 to do -denominator
end
MD_LAST: begin
unique case(operator_i)
MD_OP_DIV:
//this time we save the quotient in op_reminder_n (i.e. mac_res_q) since we do not need anymore the reminder
op_reminder_n = {1'b0, next_quotient};
default:
//this time we do not save the quotient anymore since we need only the reminder
op_reminder_n = {2'b0, next_reminder[31:0]};
endcase
//Division
alu_operand_a_o = {mac_res_q[31:0], 1'b1}; //it contains the reminder
alu_operand_b_o = {~op_denominator_q[31:0], 1'b1}; //denominator negated + 1 to do -denominator
divcurr_state_n = MD_CHANGE_SIGN;
end
MD_CHANGE_SIGN: begin
divcurr_state_n = MD_FINISH;
unique case(operator_i)
MD_OP_DIV:
op_reminder_n = (div_change_sign) ? alu_adder_i : mac_res_q;
default:
op_reminder_n = (rem_change_sign) ? alu_adder_i : mac_res_q;
endcase
//ABS(Quotient) = 0 - Quotient (or Reminder)
alu_operand_a_o = {32'h0 , 1'b1};
alu_operand_b_o = {~mac_res_q[31:0], 1'b1};
end
MD_FINISH: begin
divcurr_state_n = MD_IDLE;
unique case(divcurr_state_q)
MD_IDLE: begin
if (operator_i == MD_OP_DIV) begin
//Check if the Denominator is 0
//quotient for division by 0
op_reminder_n = '1;
divcurr_state_n = equal_to_zero ? MD_FINISH : MD_ABS_A;
end else begin
//Check if the Denominator is 0
//reminder for division by 0
op_reminder_n = {2'b0, op_a_i};
divcurr_state_n = equal_to_zero ? MD_FINISH : MD_ABS_A;
end
//0 - B = 0 iff B == 0
alu_operand_a_o = {32'h0 , 1'b1};
alu_operand_b_o = {~op_b_i, 1'b1};
div_counter_n = 5'd31;
end
default:;
endcase // divcurr_state_q
MD_ABS_A: begin
//quotient
op_quotient_n = '0;
//A abs value
op_numerator_n = div_sign_a ? alu_adder_i : op_a_i;
divcurr_state_n = MD_ABS_B;
div_counter_n = 5'd31;
//ABS(A) = 0 - A
alu_operand_a_o = {32'h0 , 1'b1};
alu_operand_b_o = {~op_a_i, 1'b1};
end
MD_ABS_B: begin
//reminder
op_reminder_n = { 33'h0, op_numerator_q[31]};
//B abs value
op_denominator_n = div_sign_b ? alu_adder_i : op_b_i;
divcurr_state_n = MD_COMP;
div_counter_n = 5'd31;
//ABS(B) = 0 - B
alu_operand_a_o = {32'h0 , 1'b1};
alu_operand_b_o = {~op_b_i, 1'b1};
end
MD_COMP: begin
op_reminder_n = {1'b0, next_reminder[31:0], op_numerator_q[div_counter_n]};
op_quotient_n = next_quotient[31:0];
divcurr_state_n = (div_counter_q == 5'd1) ? MD_LAST : MD_COMP;
//Division
alu_operand_a_o = {mac_res_q[31:0], 1'b1}; //it contains the reminder
alu_operand_b_o = {~op_denominator_q[31:0], 1'b1}; // -denominator two's compliment
end
MD_LAST: begin
if (operator_i == MD_OP_DIV) begin
// this time we save the quotient in op_reminder_n (i.e. mac_res_q) since
// we do not need anymore the reminder
op_reminder_n = {1'b0, next_quotient};
end else begin
//this time we do not save the quotient anymore since we need only the reminder
op_reminder_n = {2'b0, next_reminder[31:0]};
end
//Division
alu_operand_a_o = {mac_res_q[31:0], 1'b1}; // it contains the reminder
alu_operand_b_o = {~op_denominator_q[31:0], 1'b1}; // -denominator two's compliment
divcurr_state_n = MD_CHANGE_SIGN;
end
MD_CHANGE_SIGN: begin
divcurr_state_n = MD_FINISH;
if (operator_i == MD_OP_DIV) begin
op_reminder_n = (div_change_sign) ? {2'h0,alu_adder_i} : mac_res_q;
end else begin
op_reminder_n = (rem_change_sign) ? {2'h0,alu_adder_i} : mac_res_q;
end
//ABS(Quotient) = 0 - Quotient (or Reminder)
alu_operand_a_o = {32'h0 , 1'b1};
alu_operand_b_o = {~mac_res_q[31:0], 1'b1};
end
MD_FINISH: begin
divcurr_state_n = MD_IDLE;
end
default:;
endcase // divcurr_state_q
end
assign ready_o = mult_is_ready | (divcurr_state_q == MD_FINISH);
always_comb
begin : mult_fsm
mult_op_a = op_a_i[`OP_L];
mult_op_b = op_b_i[`OP_L];
sign_a = 1'b0;
sign_b = 1'b0;
accum = mac_res_q;
mac_res_n = mac_res;
mult_state_n = mult_state_q;
mult_is_ready = 1'b0;
unique case (mult_state_q)
always_comb begin : mult_fsm
mult_op_a = op_a_i[`OP_L];
mult_op_b = op_b_i[`OP_L];
sign_a = 1'b0;
sign_b = 1'b0;
accum = mac_res_q;
mac_res_n = mac_res;
mult_state_n = mult_state_q;
mult_is_ready = 1'b0;
ALBL: begin
//al*bl
mult_op_a = op_a_i[`OP_L];
mult_op_b = op_b_i[`OP_L];
sign_a = 1'b0;
sign_b = 1'b0;
accum = '0;
unique case (mult_state_q)
ALBL: begin
//al*bl
mult_op_a = op_a_i[`OP_L];
mult_op_b = op_b_i[`OP_L];
sign_a = 1'b0;
sign_b = 1'b0;
accum = '0;
mac_res_n = mac_res;
mult_state_n = ALBH;
end
ALBH: begin
//al*bh<<16
mult_op_a = op_a_i[`OP_L];
mult_op_b = op_b_i[`OP_H];
sign_a = 1'b0;
sign_b = signed_mode_i[1] & op_b_i[31];
//result of AL*BL (in mac_res_q) always unsigned with no carry, so carries_q always 00
accum = {18'b0,mac_res_q[31:16]};
if (operator_i == MD_OP_MULL) begin
mac_res_n = {2'b0,mac_res[`OP_L],mac_res_q[`OP_L]};
end else begin
//MD_OP_MULH
mac_res_n = mac_res;
mult_state_n = ALBH;
end
mult_state_n = AHBL;
end
ALBH: begin
//al*bh<<16
mult_op_a = op_a_i[`OP_L];
mult_op_b = op_b_i[`OP_H];
sign_a = 1'b0;
sign_b = signed_mode_i[1] & op_b_i[31];
//result of AL*BL (in mac_res_q) always unsigned with no carry, so carries_q always 00
accum = {18'b0,mac_res_q[31:16]};
unique case(operator_i)
MD_OP_MULL: begin
mac_res_n = {2'b0,mac_res[`OP_L],mac_res_q[`OP_L]};
end
default: begin
//MD_OP_MULH
mac_res_n = mac_res;
end
endcase
mult_state_n = AHBL;
end
AHBL: begin
//ah*bl<<16
mult_op_a = op_a_i[`OP_H];
mult_op_b = op_b_i[`OP_L];
sign_a = signed_mode_i[0] & op_a_i[31];
sign_b = 1'b0;
unique case(operator_i)
MD_OP_MULL: begin
accum = {18'b0,mac_res_q[31:16]};
mac_res_n = {2'b0,mac_res[15:0],mac_res_q[15:0]};
mult_is_ready = 1'b1;
mult_state_n = ALBL;
end
default: begin
accum = mac_res_q;
mac_res_n = mac_res;
mult_state_n = AHBH;
end
endcase
end
AHBH: begin
//only MD_OP_MULH here
//ah*bh
mult_op_a = op_a_i[`OP_H];
mult_op_b = op_b_i[`OP_H];
sign_a = signed_mode_i[0] & op_a_i[31];
sign_b = signed_mode_i[1] & op_b_i[31];
accum[17:0 ] = mac_res_q[33:16];
accum[33:18] = {18{signed_mult & mac_res_q[33]}};
//result of AH*BL is not signed only if signed_mode_i == 2'b00
mac_res_n = mac_res;
mult_state_n = ALBL;
AHBL: begin
//ah*bl<<16
mult_op_a = op_a_i[`OP_H];
mult_op_b = op_b_i[`OP_L];
sign_a = signed_mode_i[0] & op_a_i[31];
sign_b = 1'b0;
if (operator_i == MD_OP_MULL) begin
accum = {18'b0,mac_res_q[31:16]};
mac_res_n = {2'b0,mac_res[15:0],mac_res_q[15:0]};
mult_is_ready = 1'b1;
mult_state_n = ALBL;
end else begin
accum = mac_res_q;
mac_res_n = mac_res;
mult_state_n = AHBH;
end
end
default:;
endcase // mult_state_q
AHBH: begin
//only MD_OP_MULH here
//ah*bh
mult_op_a = op_a_i[`OP_H];
mult_op_b = op_b_i[`OP_H];
sign_a = signed_mode_i[0] & op_a_i[31];
sign_b = signed_mode_i[1] & op_b_i[31];
accum[17: 0] = mac_res_q[33:16];
accum[33:18] = {16{signed_mult & mac_res_q[33]}};
//result of AH*BL is not signed only if signed_mode_i == 2'b00
mac_res_n = mac_res;
mult_state_n = ALBL;
mult_is_ready = 1'b1;
end
default:;
endcase // mult_state_q
end

View file

@ -15,44 +15,46 @@
// //
////////////////////////////////////////////////////////////////////////////////
import ibex_defines::*;
/**
* Slow Multiplier and Division
*
* Baugh-Wooley multiplier and Long Division
*/
module ibex_multdiv_slow
(
input logic clk,
input logic rst_n,
input logic mult_en_i,
input logic div_en_i,
input logic [1:0] operator_i,
input logic [1:0] signed_mode_i,
input logic [31:0] op_a_i,
input logic [31:0] op_b_i,
input logic [33:0] alu_adder_ext_i,
input logic [31:0] alu_adder_i,
input logic equal_to_zero,
module ibex_multdiv_slow (
input logic clk,
input logic rst_n,
input logic mult_en_i,
input logic div_en_i,
input logic [1:0] operator_i,
input logic [1:0] signed_mode_i,
input logic [31:0] op_a_i,
input logic [31:0] op_b_i,
input logic [33:0] alu_adder_ext_i,
input logic [31:0] alu_adder_i,
input logic equal_to_zero,
output logic [32:0] alu_operand_a_o,
output logic [32:0] alu_operand_b_o,
output logic [31:0] multdiv_result_o,
output logic [32:0] alu_operand_a_o,
output logic [32:0] alu_operand_b_o,
output logic [31:0] multdiv_result_o,
output logic ready_o
output logic ready_o
);
logic [ 4:0] multdiv_state_q, multdiv_state_n;
enum logic [2:0] { MD_IDLE, MD_ABS_A, MD_ABS_B, MD_COMP, MD_LAST, MD_CHANGE_SIGN, MD_FINISH } curr_state_q;
import ibex_defines::*;
logic [32:0] accum_window_q;
logic [ 4:0] multdiv_state_q, multdiv_state_d, multdiv_state_m1;
typedef enum logic [2:0] {
MD_IDLE, MD_ABS_A, MD_ABS_B, MD_COMP, MD_LAST, MD_CHANGE_SIGN, MD_FINISH
} div_fsm_e;
div_fsm_e curr_state_q, curr_state_d;
logic [32:0] accum_window_q, accum_window_d;
logic [32:0] res_adder_l;
logic [32:0] res_adder_h;
logic [32:0] op_b_shift_q;
logic [32:0] op_a_shift_q;
logic [32:0] op_b_shift_q, op_b_shift_d;
logic [32:0] op_a_shift_q, op_a_shift_d;
logic [32:0] op_a_ext, op_b_ext;
logic [32:0] one_shift;
logic [32:0] op_a_bw_pp, op_a_bw_last_pp;
@ -60,7 +62,7 @@ module ibex_multdiv_slow
logic sign_a, sign_b;
logic [32:0] next_reminder, next_quotient;
logic [32:0] op_remainder;
logic [31:0] op_numerator_q;
logic [31:0] op_numerator_q, op_numerator_d;
logic is_greater_equal;
logic div_change_sign, rem_change_sign;
@ -70,9 +72,7 @@ module ibex_multdiv_slow
//(accum_window_q + op_a_shift_q)>>1
assign res_adder_h = alu_adder_ext_i[33:1];
always_comb
begin
always_comb begin
alu_operand_a_o = accum_window_q;
multdiv_result_o = div_en_i ? accum_window_q[31:0] : res_adder_l;
@ -83,11 +83,9 @@ module ibex_multdiv_slow
end
MD_OP_MULH: begin
if(curr_state_q == MD_LAST)
alu_operand_b_o = op_a_bw_last_pp;
else
alu_operand_b_o = op_a_bw_pp;
alu_operand_b_o = (curr_state_q == MD_LAST) ? op_a_bw_last_pp : op_a_bw_pp;
end
default: begin
unique case(curr_state_q)
MD_IDLE: begin
@ -113,13 +111,11 @@ module ibex_multdiv_slow
default: begin
//Division
alu_operand_a_o = {accum_window_q[31:0], 1'b1}; //it contains the reminder
alu_operand_b_o = {~op_b_shift_q[31:0], 1'b1}; //denominator negated + 1 to do -denominator
alu_operand_b_o = {~op_b_shift_q[31:0], 1'b1}; //-denominator two's compliment
end
endcase
end
endcase
end
/*
@ -130,13 +126,10 @@ module ibex_multdiv_slow
The
*/
always_comb
begin
if ((accum_window_q[31] ^ op_b_shift_q[31]) == 0)
is_greater_equal = (res_adder_h[31] == 0);
else
is_greater_equal = accum_window_q[31];
end
assign is_greater_equal =
((accum_window_q[31] ^ op_b_shift_q[31]) == 1'b0) ?
(res_adder_h[31] == 1'b0) :
accum_window_q[31];
assign one_shift = {32'b0, 1'b1} << multdiv_state_q;
@ -146,9 +139,8 @@ module ibex_multdiv_slow
assign b_0 = {32{op_b_shift_q[0]}};
//build the partial product
assign op_a_bw_pp = { ~(op_a_shift_q[32] & op_b_shift_q[0]), op_a_shift_q[31:0] & b_0 };
assign op_a_bw_last_pp = { op_a_shift_q[32] & op_b_shift_q[0], ~(op_a_shift_q[31:0] & b_0) };
assign op_a_bw_pp = { ~(op_a_shift_q[32] & op_b_shift_q[0]), (op_a_shift_q[31:0] & b_0) };
assign op_a_bw_last_pp = { (op_a_shift_q[32] & op_b_shift_q[0]), ~(op_a_shift_q[31:0] & b_0) };
assign sign_a = op_a_i[31] & signed_mode_i[0];
assign sign_b = op_b_i[31] & signed_mode_i[1];
@ -159,141 +151,152 @@ module ibex_multdiv_slow
//division
assign op_remainder = accum_window_q[32:0];
assign multdiv_state_n = multdiv_state_q - 1;
assign multdiv_state_m1 = multdiv_state_q - 5'h1;
assign div_change_sign = sign_a ^ sign_b;
assign rem_change_sign = sign_a;
always_ff @(posedge clk or negedge rst_n) begin : proc_multdiv_state_q
if(~rst_n) begin
multdiv_state_q <= '0;
accum_window_q <= '0;
op_b_shift_q <= '0;
op_a_shift_q <= '0;
if (!rst_n) begin
multdiv_state_q <= 5'h0;
accum_window_q <= 33'h0;
op_b_shift_q <= 33'h0;
op_a_shift_q <= 33'h0;
op_numerator_q <= 32'h0;
curr_state_q <= MD_IDLE;
op_numerator_q <= '0;
end else begin
if(mult_en_i | div_en_i) begin
unique case(curr_state_q)
MD_IDLE: begin
unique case(operator_i)
MD_OP_MULL: begin
op_a_shift_q <= op_a_ext << 1;
accum_window_q <= { ~(op_a_ext[32] & op_b_i[0]), op_a_ext[31:0] & {32{op_b_i[0]}} };
op_b_shift_q <= op_b_ext >> 1;
curr_state_q <= MD_COMP;
end
MD_OP_MULH: begin
op_a_shift_q <= op_a_ext;
accum_window_q <= { 1'b1, ~(op_a_ext[32] & op_b_i[0]), op_a_ext[31:1] & {31{op_b_i[0]}} };
op_b_shift_q <= op_b_ext >> 1;
curr_state_q <= MD_COMP;
end
MD_OP_DIV: begin
//Check if the Denominator is 0
//quotient for division by 0
accum_window_q <= '1;
curr_state_q <= equal_to_zero ? MD_FINISH : MD_ABS_A;
end
default: begin
//Check if the Denominator is 0
//reminder for division by 0
accum_window_q <= op_a_ext;
curr_state_q <= equal_to_zero ? MD_FINISH : MD_ABS_A;
end
endcase
multdiv_state_q <= 5'd31;
end
MD_ABS_A: begin
//quotient
op_a_shift_q <= '0;
//A abs value
op_numerator_q <= sign_a ? alu_adder_i : op_a_i;
curr_state_q <= MD_ABS_B;
end
MD_ABS_B: begin
//reminder
accum_window_q <= { 32'h0, op_numerator_q[31]};
//B abs value
op_b_shift_q <= sign_b ? alu_adder_i : op_b_i;
curr_state_q <= MD_COMP;
end
MD_COMP: begin
multdiv_state_q <= multdiv_state_n;
unique case(operator_i)
MD_OP_MULL: begin
accum_window_q <= res_adder_l;
op_a_shift_q <= op_a_shift_q << 1;
op_b_shift_q <= op_b_shift_q >> 1;
end
MD_OP_MULH: begin
accum_window_q <= res_adder_h;
op_a_shift_q <= op_a_shift_q;
op_b_shift_q <= op_b_shift_q >> 1;
end
default: begin
accum_window_q <= {next_reminder[31:0], op_numerator_q[multdiv_state_n]};
op_a_shift_q <= next_quotient;
end
endcase
if(multdiv_state_q == 5'd1)
curr_state_q <= MD_LAST;
else
curr_state_q <= MD_COMP;
end
MD_LAST: begin
unique case(operator_i)
MD_OP_MULL: begin
accum_window_q <= res_adder_l;
curr_state_q <= MD_IDLE;
end
MD_OP_MULH: begin
accum_window_q <= res_adder_l;
curr_state_q <= MD_IDLE;
end
MD_OP_DIV: begin
//this time we save the quotient in accum_window_q since we do not need anymore the reminder
accum_window_q <= next_quotient;
curr_state_q <= MD_CHANGE_SIGN;
end
default: begin
//this time we do not save the quotient anymore since we need only the reminder
accum_window_q <= {1'b0, next_reminder[31:0]};
curr_state_q <= MD_CHANGE_SIGN;
end
endcase
end
MD_CHANGE_SIGN: begin
curr_state_q <= MD_FINISH;
unique case(operator_i)
MD_OP_DIV:
accum_window_q <= (div_change_sign) ? alu_adder_i : accum_window_q;
default:
accum_window_q <= (rem_change_sign) ? alu_adder_i : accum_window_q;
endcase
end
MD_FINISH: begin
curr_state_q <= MD_IDLE;
end
default:;
endcase // curr_state_q
end
multdiv_state_q <= multdiv_state_d;
accum_window_q <= accum_window_d;
op_b_shift_q <= op_b_shift_d;
op_a_shift_q <= op_a_shift_d;
op_numerator_q <= op_numerator_d;
curr_state_q <= curr_state_d;
end
end
always_comb begin
multdiv_state_d = multdiv_state_q;
accum_window_d = accum_window_q;
op_b_shift_d = op_b_shift_q;
op_a_shift_d = op_a_shift_q;
op_numerator_d = op_numerator_q;
curr_state_d = curr_state_q;
if (mult_en_i || div_en_i) begin
unique case(curr_state_q)
MD_IDLE: begin
unique case(operator_i)
MD_OP_MULL: begin
op_a_shift_d = op_a_ext << 1;
accum_window_d = { ~(op_a_ext[32] & op_b_i[0]),
op_a_ext[31:0] & {32{op_b_i[0]}} };
op_b_shift_d = op_b_ext >> 1;
curr_state_d = MD_COMP;
end
MD_OP_MULH: begin
op_a_shift_d = op_a_ext;
accum_window_d = { 1'b1, ~(op_a_ext[32] & op_b_i[0]),
op_a_ext[31:1] & {31{op_b_i[0]}} };
op_b_shift_d = op_b_ext >> 1;
curr_state_d = MD_COMP;
end
MD_OP_DIV: begin
//Check if the Denominator is 0
//quotient for division by 0
accum_window_d = {33{1'b1}};
curr_state_d = equal_to_zero ? MD_FINISH : MD_ABS_A;
end
default: begin
//Check if the Denominator is 0
//reminder for division by 0
accum_window_d = op_a_ext;
curr_state_d = equal_to_zero ? MD_FINISH : MD_ABS_A;
end
endcase
multdiv_state_d = 5'd31;
end
assign ready_o = (curr_state_q == MD_FINISH) | (curr_state_q == MD_LAST & (operator_i == MD_OP_MULL | operator_i == MD_OP_MULH));
MD_ABS_A: begin
//quotient
op_a_shift_d = '0;
//A abs value
op_numerator_d = sign_a ? alu_adder_i : op_a_i;
curr_state_d = MD_ABS_B;
end
MD_ABS_B: begin
//reminder
accum_window_d = { 32'h0, op_numerator_q[31]};
//B abs value
op_b_shift_d = sign_b ? alu_adder_i : op_b_i;
curr_state_d = MD_COMP;
end
MD_COMP: begin
multdiv_state_d = multdiv_state_m1;
unique case(operator_i)
MD_OP_MULL: begin
accum_window_d = res_adder_l;
op_a_shift_d = op_a_shift_q << 1;
op_b_shift_d = op_b_shift_q >> 1;
end
MD_OP_MULH: begin
accum_window_d = res_adder_h;
op_a_shift_d = op_a_shift_q;
op_b_shift_d = op_b_shift_q >> 1;
end
default: begin
accum_window_d = {next_reminder[31:0], op_numerator_q[multdiv_state_m1]};
op_a_shift_d = next_quotient;
end
endcase
curr_state_d = (multdiv_state_q == 5'd1) ? MD_LAST : MD_COMP;
end
MD_LAST: begin
unique case(operator_i)
MD_OP_MULL: begin
accum_window_d = res_adder_l;
curr_state_d = MD_IDLE;
end
MD_OP_MULH: begin
accum_window_d = res_adder_l;
curr_state_d = MD_IDLE;
end
MD_OP_DIV: begin
//this time we save the quotient in accum_window_q since we do not need anymore the reminder
accum_window_d = next_quotient;
curr_state_d = MD_CHANGE_SIGN;
end
default: begin
//this time we do not save the quotient anymore since we need only the reminder
accum_window_d = {1'b0, next_reminder[31:0]};
curr_state_d = MD_CHANGE_SIGN;
end
endcase
end
MD_CHANGE_SIGN: begin
curr_state_d = MD_FINISH;
unique case(operator_i)
MD_OP_DIV:
accum_window_d = (div_change_sign) ? alu_adder_i : accum_window_q;
default:
accum_window_d = (rem_change_sign) ? alu_adder_i : accum_window_q;
endcase
end
MD_FINISH: begin
curr_state_d = MD_IDLE;
end
default:;
endcase // curr_state_q
end
end
assign ready_o = (curr_state_q == MD_FINISH) |
(curr_state_q == MD_LAST &
(operator_i == MD_OP_MULL |
operator_i == MD_OP_MULH));
endmodule // ibex_mult

View file

@ -14,42 +14,44 @@
// long critical paths to the instruction cache //
// //
////////////////////////////////////////////////////////////////////////////////
/**
* Prefetcher Buffer for 32 bit memory interface
*
* Prefetch Buffer that caches instructions. This cuts overly long critical
* paths to the instruction cache.
*/
module ibex_prefetch_buffer
(
input logic clk,
input logic rst_n,
module ibex_prefetch_buffer (
input logic clk,
input logic rst_n,
input logic req_i,
input logic req_i,
input logic branch_i,
input logic [31:0] addr_i,
input logic branch_i,
input logic [31:0] addr_i,
input logic ready_i,
output logic valid_o,
output logic [31:0] rdata_o,
output logic [31:0] addr_o,
input logic ready_i,
output logic valid_o,
output logic [31:0] rdata_o,
output logic [31:0] addr_o,
// goes to instruction memory / instruction cache
output logic instr_req_o,
input logic instr_gnt_i,
output logic [31:0] instr_addr_o,
input logic [31:0] instr_rdata_i,
input logic instr_rvalid_i,
// goes to instruction memory / instruction cache
output logic instr_req_o,
input logic instr_gnt_i,
output logic [31:0] instr_addr_o,
input logic [31:0] instr_rdata_i,
input logic instr_rvalid_i,
// Prefetch Buffer Status
output logic busy_o
// Prefetch Buffer Status
output logic busy_o
);
enum logic [1:0] {IDLE, WAIT_GNT, WAIT_RVALID, WAIT_ABORTED } CS, NS;
typedef enum logic [1:0] {
IDLE, WAIT_GNT, WAIT_RVALID, WAIT_ABORTED
} prefetch_fsm_e;
prefetch_fsm_e CS, NS;
logic [31:0] instr_addr_q, fetch_addr;
logic addr_valid;
@ -58,39 +60,35 @@ module ibex_prefetch_buffer
logic fifo_ready;
logic fifo_clear;
logic valid_stored;
//////////////////////////////////////////////////////////////////////////////
// prefetch buffer status
//////////////////////////////////////////////////////////////////////////////
assign busy_o = (CS != IDLE) || instr_req_o;
assign busy_o = (CS != IDLE) | instr_req_o;
//////////////////////////////////////////////////////////////////////////////
// fetch fifo
// consumes addresses and rdata
//////////////////////////////////////////////////////////////////////////////
ibex_fetch_fifo fifo_i
(
.clk ( clk ),
.rst_n ( rst_n ),
ibex_fetch_fifo fifo_i (
.clk ( clk ),
.rst_n ( rst_n ),
.clear_i ( fifo_clear ),
.clear_i ( fifo_clear ),
.in_addr_i ( instr_addr_q ),
.in_rdata_i ( instr_rdata_i ),
.in_valid_i ( fifo_valid ),
.in_ready_o ( fifo_ready ),
.in_addr_i ( instr_addr_q ),
.in_rdata_i ( instr_rdata_i ),
.in_valid_i ( fifo_valid ),
.in_ready_o ( fifo_ready ),
.out_valid_o ( valid_o ),
.out_ready_i ( ready_i ),
.out_rdata_o ( rdata_o ),
.out_addr_o ( addr_o ),
.out_valid_o ( valid_o ),
.out_ready_i ( ready_i ),
.out_rdata_o ( rdata_o ),
.out_addr_o ( addr_o ),
.out_valid_stored_o ( valid_stored )
.out_valid_stored_o ( )
);
@ -99,19 +97,14 @@ module ibex_prefetch_buffer
//////////////////////////////////////////////////////////////////////////////
assign fetch_addr = {instr_addr_q[31:2], 2'b00} + 32'd4;
always_comb
begin
fifo_clear = branch_i;
end
assign fifo_clear = branch_i;
//////////////////////////////////////////////////////////////////////////////
// instruction fetch FSM
// deals with instruction memory / instruction cache
//////////////////////////////////////////////////////////////////////////////
always_comb
begin
always_comb begin
instr_req_o = 1'b0;
instr_addr_o = fetch_addr;
fifo_valid = 1'b0;
@ -120,30 +113,26 @@ module ibex_prefetch_buffer
unique case(CS)
// default state, not waiting for requested data
IDLE:
begin
IDLE: begin
instr_addr_o = fetch_addr;
instr_req_o = 1'b0;
if (branch_i)
if (branch_i) begin
instr_addr_o = addr_i;
end
if (req_i & (fifo_ready | branch_i )) begin
if (req_i && (fifo_ready || branch_i )) begin
instr_req_o = 1'b1;
addr_valid = 1'b1;
if(instr_gnt_i) //~> granted request
NS = WAIT_RVALID;
else begin //~> got a request but no grant
NS = WAIT_GNT;
end
//~> granted request or not
NS = instr_gnt_i ? WAIT_RVALID : WAIT_GNT;
end
end // case: IDLE
// we sent a request but did not yet get a grant
WAIT_GNT:
begin
WAIT_GNT: begin
instr_addr_o = instr_addr_q;
instr_req_o = 1'b1;
@ -152,21 +141,19 @@ module ibex_prefetch_buffer
addr_valid = 1'b1;
end
if(instr_gnt_i)
NS = WAIT_RVALID;
else
NS = WAIT_GNT;
//~> granted request or not
NS = instr_gnt_i ? WAIT_RVALID : WAIT_GNT;
end // case: WAIT_GNT
// we wait for rvalid, after that we are ready to serve a new request
WAIT_RVALID: begin
instr_addr_o = fetch_addr;
if (branch_i)
if (branch_i) begin
instr_addr_o = addr_i;
end
if (req_i & (fifo_ready | branch_i)) begin
if (req_i && (fifo_ready || branch_i)) begin
// prepare for next request
if (instr_rvalid_i) begin
@ -174,12 +161,8 @@ module ibex_prefetch_buffer
fifo_valid = 1'b1;
addr_valid = 1'b1;
if (instr_gnt_i) begin
NS = WAIT_RVALID;
end else begin
NS = WAIT_GNT;
end
//~> granted request or not
NS = instr_gnt_i ? WAIT_RVALID : WAIT_GNT;
end else begin
// we are requested to abort our current request
// we didn't get an rvalid yet, so wait for it
@ -213,18 +196,14 @@ module ibex_prefetch_buffer
instr_req_o = 1'b1;
// no need to send address, already done in WAIT_RVALID
if (instr_gnt_i) begin
NS = WAIT_RVALID;
end else begin
NS = WAIT_GNT;
end
//~> granted request or not
NS = instr_gnt_i ? WAIT_RVALID : WAIT_GNT;
end
end
default:
begin
NS = IDLE;
instr_req_o = 1'b0;
default: begin
// NS = IDLE; // unreachable, removing dead code
// instr_req_o = 1'b0; // unreachable, removing dead code
end
endcase
end
@ -233,15 +212,11 @@ module ibex_prefetch_buffer
// registers
//////////////////////////////////////////////////////////////////////////////
always_ff @(posedge clk, negedge rst_n)
begin
if(rst_n == 1'b0)
begin
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
CS <= IDLE;
instr_addr_q <= '0;
end
else
begin
end else begin
CS <= NS;
if (addr_valid) begin

View file

@ -29,31 +29,28 @@
* This register file is based on latches and is thus smaller than the flip-flop
* based RF.
*/
module ibex_register_file
#(
parameter RV32E = 0,
parameter DATA_WIDTH = 32
)
(
// Clock and Reset
input logic clk,
input logic rst_n,
module ibex_register_file #(
parameter RV32E = 0,
parameter DATA_WIDTH = 32
) (
// Clock and Reset
input logic clk,
input logic rst_n,
input logic test_en_i,
input logic test_en_i,
//Read port R1
input logic [4:0] raddr_a_i,
output logic [DATA_WIDTH-1:0] rdata_a_o,
//Read port R1
input logic [4:0] raddr_a_i,
output logic [DATA_WIDTH-1:0] rdata_a_o,
//Read port R2
input logic [4:0] raddr_b_i,
output logic [DATA_WIDTH-1:0] rdata_b_o,
//Read port R2
input logic [4:0] raddr_b_i,
output logic [DATA_WIDTH-1:0] rdata_b_o,
// Write port W1
input logic [4:0] waddr_a_i,
input logic [DATA_WIDTH-1:0] wdata_a_i,
input logic we_a_i
// Write port W1
input logic [4:0] waddr_a_i,
input logic [DATA_WIDTH-1:0] wdata_a_i,
input logic we_a_i
);
@ -76,15 +73,8 @@ module ibex_register_file
assign raddr_b_int = raddr_b_i[ADDR_WIDTH-1:0];
assign waddr_a_int = waddr_a_i[ADDR_WIDTH-1:0];
logic clk_int;
int unsigned i;
int unsigned j;
int unsigned k;
genvar x;
//-----------------------------------------------------------------------------
//-- READ : Read address decoder RAD
//-----------------------------------------------------------------------------
@ -95,36 +85,34 @@ module ibex_register_file
// WRITE : SAMPLE INPUT DATA
//---------------------------------------------------------------------------
clock_gating CG_WE_GLOBAL
(
.clk_i ( clk ),
.en_i ( we_a_i ),
.test_en_i ( test_en_i ),
.clk_o ( clk_int )
prim_clock_gating CG_WE_GLOBAL (
.clk_i ( clk ),
.en_i ( we_a_i ),
.test_en_i ( test_en_i ),
.clk_o ( clk_int )
);
// use clk_int here, since otherwise we don't want to write anything anyway
always_ff @(posedge clk_int, negedge rst_n)
begin : sample_waddr
if (~rst_n) begin
wdata_a_q <= '0;
always_ff @(posedge clk_int, negedge rst_n) begin : sample_waddr
if (!rst_n) begin
wdata_a_q <= '0;
end else begin
if(we_a_i)
if (we_a_i) begin
wdata_a_q <= wdata_a_i;
end
end
end
//-----------------------------------------------------------------------------
//-- WRITE : Write Address Decoder (WAD), combinatorial process
//-----------------------------------------------------------------------------
always_comb
begin : p_WADa
for(i = 1; i < NUM_WORDS; i++)
begin : p_WordItera
if ( (we_a_i == 1'b1 ) && (waddr_a_int == i) )
always_comb begin : p_WADa
for (int i = 1; i < NUM_WORDS; i++) begin : p_WordItera
if (we_a_i && (waddr_a_int == i)) begin
waddr_onehot_a[i] = 1'b1;
else
end else begin
waddr_onehot_a[i] = 1'b0;
end
end
end
@ -132,18 +120,14 @@ module ibex_register_file
//-----------------------------------------------------------------------------
//-- WRITE : Clock gating (if integrated clock-gating cells are available)
//-----------------------------------------------------------------------------
generate
for(x = 1; x < NUM_WORDS; x++)
begin : CG_CELL_WORD_ITER
clock_gating CG_Inst
(
.clk_i ( clk_int ),
.en_i ( waddr_onehot_a[x] ),
.test_en_i ( test_en_i ),
.clk_o ( mem_clocks[x] )
);
end
endgenerate
for (genvar x = 1; x < NUM_WORDS; x++) begin : gen_CG_CELL_WORD_ITER
prim_clock_gating CG_Inst (
.clk_i ( clk_int ),
.en_i ( waddr_onehot_a[x] ),
.test_en_i ( test_en_i ),
.clk_o ( mem_clocks[x] )
);
end
//-----------------------------------------------------------------------------
//-- WRITE : Write operation
@ -154,17 +138,15 @@ module ibex_register_file
//-- Use active low, i.e. transparent on low latches as storage elements
//-- Data is sampled on rising clock edge
always_latch
begin : latch_wdata
always_latch begin : latch_wdata
// Note: The assignment has to be done inside this process or Modelsim complains about it
mem[0] = '0;
for(k = 1; k < NUM_WORDS; k++)
begin : w_WordIter
if(mem_clocks[k] == 1'b1)
for (int k = 1; k < NUM_WORDS; k++) begin : w_WordIter
if (mem_clocks[k]) begin
mem[k] = wdata_a_q;
end
end
end
endmodule

View file

@ -27,31 +27,29 @@
* Register file with 31 or 15x 32 bit wide registers. Register 0 is fixed to 0.
* This register file is based on flip flops.
*/
module ibex_register_file
#(
parameter RV32E = 0,
parameter DATA_WIDTH = 32
)
(
// Clock and Reset
input logic clk,
input logic rst_n,
module ibex_register_file #(
parameter RV32E = 0,
parameter DATA_WIDTH = 32
) (
// Clock and Reset
input logic clk,
input logic rst_n,
input logic test_en_i,
input logic test_en_i,
//Read port R1
input logic [4:0] raddr_a_i,
output logic [DATA_WIDTH-1:0] rdata_a_o,
//Read port R1
input logic [4:0] raddr_a_i,
output logic [DATA_WIDTH-1:0] rdata_a_o,
//Read port R2
input logic [4:0] raddr_b_i,
output logic [DATA_WIDTH-1:0] rdata_b_o,
//Read port R2
input logic [4:0] raddr_b_i,
output logic [DATA_WIDTH-1:0] rdata_b_o,
// Write port W1
input logic [4:0] waddr_a_i,
input logic [DATA_WIDTH-1:0] wdata_a_i,
input logic we_a_i
// Write port W1
input logic [4:0] waddr_a_i,
input logic [DATA_WIDTH-1:0] wdata_a_i,
input logic we_a_i
);
@ -59,44 +57,29 @@ module ibex_register_file
localparam NUM_WORDS = 2**ADDR_WIDTH;
logic [NUM_WORDS-1:0][DATA_WIDTH-1:0] rf_reg;
logic [NUM_WORDS-1:0][DATA_WIDTH-1:0] rf_reg_tmp;
logic [NUM_WORDS-1:0] we_a_dec;
logic [NUM_WORDS-1:1][DATA_WIDTH-1:0] rf_reg_tmp;
logic [NUM_WORDS-1:1] we_a_dec;
always_comb
begin : we_a_decoder
for (int i = 0; i < NUM_WORDS; i++) begin
if (waddr_a_i == i)
we_a_dec[i] = we_a_i;
else
we_a_dec[i] = 1'b0;
always_comb begin : we_a_decoder
for (int i = 1; i < NUM_WORDS; i++) begin
we_a_dec[i] = (waddr_a_i == i) ? we_a_i : 1'b0;
end
end
genvar i;
generate
// loop from 1 to NUM_WORDS-1 as R0 is nil
for (i = 1; i < NUM_WORDS; i++)
begin : rf_gen
always_ff @(posedge clk, negedge rst_n)
begin : register_write_behavioral
if (rst_n==1'b0) begin
rf_reg_tmp[i] <= 'b0;
end else begin
if (we_a_dec[i])
rf_reg_tmp[i] <= wdata_a_i;
end
// loop from 1 to NUM_WORDS-1 as R0 is nil
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
rf_reg_tmp <= '{default:'0};
end else begin
for (int r = 1; r < NUM_WORDS; r++) begin
if (we_a_dec[r]) rf_reg_tmp[r] <= wdata_a_i;
end
end
end
// R0 is nil
assign rf_reg[0] = '0;
assign rf_reg[NUM_WORDS-1:1] = rf_reg_tmp[NUM_WORDS-1:1];
endgenerate
// R0 is nil
assign rf_reg[0] = '0;
assign rf_reg[NUM_WORDS-1:1] = rf_reg_tmp[NUM_WORDS-1:1];
assign rdata_a_o = rf_reg[raddr_a_i];
assign rdata_b_o = rf_reg[raddr_b_i];

View file

@ -35,54 +35,52 @@ import ibex_tracer_defines::*;
/**
* Traces the executed instructions
*/
module ibex_tracer
#(
module ibex_tracer #(
parameter REG_ADDR_WIDTH = 5
)
(
// Clock and Reset
input logic clk,
input logic rst_n,
) (
// Clock and Reset
input logic clk,
input logic rst_n,
input logic fetch_enable,
input logic [3:0] core_id,
input logic [5:0] cluster_id,
input logic fetch_enable,
input logic [3:0] core_id,
input logic [5:0] cluster_id,
input logic [31:0] pc,
input logic [31:0] instr,
input logic compressed,
input logic id_valid,
input logic is_decoding,
input logic is_branch,
input logic branch_taken,
input logic pipe_flush,
input logic mret_insn,
input logic ecall_insn,
input logic ebrk_insn,
input logic csr_status,
input logic [31:0] rs1_value,
input logic [31:0] rs2_value,
input logic [31:0] lsu_value,
input logic [31:0] pc,
input logic [31:0] instr,
input logic compressed,
input logic id_valid,
input logic is_decoding,
input logic is_branch,
input logic branch_taken,
input logic pipe_flush,
input logic mret_insn,
input logic ecall_insn,
input logic ebrk_insn,
input logic csr_status,
input logic [31:0] rs1_value,
input logic [31:0] rs2_value,
input logic [31:0] lsu_value,
input logic [(REG_ADDR_WIDTH-1):0] ex_reg_addr,
input logic ex_reg_we,
input logic [31:0] ex_reg_wdata,
input logic data_valid_lsu,
input logic ex_data_req,
input logic ex_data_gnt,
input logic ex_data_we,
input logic [31:0] ex_data_addr,
input logic [31:0] ex_data_wdata,
input logic [(REG_ADDR_WIDTH-1):0] ex_reg_addr,
input logic ex_reg_we,
input logic [31:0] ex_reg_wdata,
input logic data_valid_lsu,
input logic ex_data_req,
input logic ex_data_gnt,
input logic ex_data_we,
input logic [31:0] ex_data_addr,
input logic [31:0] ex_data_wdata,
input logic [31:0] lsu_reg_wdata,
input logic [31:0] lsu_reg_wdata,
input logic [31:0] imm_u_type,
input logic [31:0] imm_uj_type,
input logic [31:0] imm_i_type,
input logic [11:0] imm_iz_type,
input logic [31:0] imm_z_type,
input logic [31:0] imm_s_type,
input logic [31:0] imm_sb_type
input logic [31:0] imm_u_type,
input logic [31:0] imm_uj_type,
input logic [31:0] imm_i_type,
input logic [11:0] imm_iz_type,
input logic [31:0] imm_z_type,
input logic [31:0] imm_s_type,
input logic [31:0] imm_sb_type
);
integer f;
@ -122,10 +120,11 @@ module ibex_tracer
function string regAddrToStr(input logic [(REG_ADDR_WIDTH-1):0] addr);
begin
if (addr < 10)
if (addr < 10) begin
return $sformatf(" x%0d", addr);
else
end else begin
return $sformatf("x%0d", addr);
end
end
endfunction
@ -139,13 +138,15 @@ module ibex_tracer
str);
foreach(regs_write[i]) begin
if (regs_write[i].addr != 0)
if (regs_write[i].addr != 0) begin
$fwrite(f, " %s=%08x", regAddrToStr(regs_write[i].addr), regs_write[i].value);
end
end
foreach(regs_read[i]) begin
if (regs_read[i].addr != 0)
if (regs_read[i].addr != 0) begin
$fwrite(f, " %s:%08x", regAddrToStr(regs_read[i].addr), regs_read[i].value);
end
end
if (mem_access.size() > 0) begin
@ -218,7 +219,7 @@ module ibex_tracer
regs_write.push_back('{rd, 'x});
if (instr[14] == 1'b0) begin
if (!instr[14]) begin
regs_read.push_back('{rs1, rs1_value});
str = $sformatf("%-16s x%0d, x%0d, 0x%h", mnemonic, rd, rs1, csr);
end else begin
@ -233,8 +234,9 @@ module ibex_tracer
begin
// detect reg-reg load and find size
size = instr[14:12];
if (instr[14:12] == 3'b111)
if (instr[14:12] == 3'b111) begin
size = instr[30:28];
end
case (size)
3'b000: mnemonic = "lb";
@ -276,7 +278,7 @@ module ibex_tracer
end
endcase
if (instr[14] == 1'b0) begin
if (!instr[14]) begin
// regular store
regs_read.push_back('{rs2, rs2_value});
regs_read.push_back('{rs1, rs1_value});
@ -293,28 +295,25 @@ module ibex_tracer
mailbox #(instr_trace_t) instr_wb = new ();
// cycle counter
always_ff @(posedge clk, negedge rst_n)
begin
if (rst_n == 1'b0)
always_ff @(posedge clk, negedge rst_n) begin
if (!rst_n) begin
cycles = 0;
else
end else begin
cycles = cycles + 1;
end
end
// open/close output file for writing
initial
begin
initial begin
wait(rst_n == 1'b1);
wait(fetch_enable == 1'b1);
$sformat(fn, "trace_core_%h_%h.log", cluster_id, core_id);
$display("[TRACER] Output filename is: %s", fn);
f = $fopen(fn, "w");
$fwrite(f, " Time Cycles PC Instr Mnemonic\n");
end
final
begin
final begin
$fclose(f);
end
@ -324,13 +323,12 @@ module ibex_tracer
assign rs3 = instr[`REG_S3];
// log execution
always @(negedge clk)
begin
always @(negedge clk) begin
instr_trace_t trace;
mem_acc_t mem_acc;
// special case for WFI because we don't wait for unstalling there
if ( (id_valid || mret_insn || ecall_insn || pipe_flush || ebrk_insn || csr_status || ex_data_req) && is_decoding)
begin
if ( (id_valid || mret_insn || ecall_insn || pipe_flush || ebrk_insn ||
csr_status || ex_data_req) && is_decoding) begin
trace = new ();
trace.simtime = $time;
@ -403,13 +401,14 @@ module ibex_tracer
// replace register written back
foreach(trace.regs_write[i]) begin
if ((trace.regs_write[i].addr == ex_reg_addr) && ex_reg_we)
if ((trace.regs_write[i].addr == ex_reg_addr) && ex_reg_we) begin
trace.regs_write[i].value = ex_reg_wdata;
end
end
// look for data accesses and log them
if (ex_data_req) begin
if(~ex_data_gnt) begin
if (!ex_data_gnt) begin
//we wait until the the gnt comes
do @(negedge clk);
while (!ex_data_gnt);
@ -418,22 +417,23 @@ module ibex_tracer
mem_acc.addr = ex_data_addr;
mem_acc.we = ex_data_we;
if (mem_acc.we)
if (mem_acc.we) begin
mem_acc.wdata = ex_data_wdata;
else
end else begin
mem_acc.wdata = 'x;
end
//we wait until the the data instruction ends
do @(negedge clk);
while (!data_valid_lsu);
while (!data_valid_lsu);
if (~mem_acc.we)
if (!mem_acc.we) begin
//load operations
foreach(trace.regs_write[i])
trace.regs_write[i].value = lsu_reg_wdata;
trace.regs_write[i].value = lsu_reg_wdata;
end
trace.mem_access.push_back(mem_acc);
end
trace.printInstrTrace();
end
end // always @ (posedge clk)

View file

@ -27,4 +27,4 @@
//`define SIMCHECKER
`endif
//`define CHECK_MISALIGNED
//`define CHECK_MISALIGNED

View file

@ -243,8 +243,8 @@ parameter IMMB_VU = 4'b0111;
parameter IMMB_SHUF = 4'b1000;
parameter IMMB_CLIP = 4'b1001;
parameter IMMB_BI = 4'b1011;
parameter IMMB_UJ = 4'b1100;
parameter IMMB_SB = 4'b1101;
parameter IMMB_UJ = 4'b1100;
parameter IMMB_SB = 4'b1101;
// bit mask selection
parameter BMASK_A_ZERO = 1'b0;

View file

@ -66,4 +66,4 @@ parameter INSTR_PMULHSU = { 7'b0000001, 10'b?, 3'b010, 5'b?, OPCODE_OP };
parameter INSTR_PMULHU = { 7'b0000001, 10'b?, 3'b011, 5'b?, OPCODE_OP };
endpackage
endpackage