mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 21:07:34 -04:00
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:
parent
148604265e
commit
6b0475744d
22 changed files with 2223 additions and 2563 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
742
rtl/ibex_core.sv
742
rtl/ibex_core.sv
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -27,4 +27,4 @@
|
|||
//`define SIMCHECKER
|
||||
`endif
|
||||
|
||||
//`define CHECK_MISALIGNED
|
||||
//`define CHECK_MISALIGNED
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue