Initial RiscV core commit; still in an early stage, but ALU instructions work

This commit is contained in:
Sven Stucki 2015-04-01 11:11:07 +02:00
commit a6d67016ac
13 changed files with 5943 additions and 0 deletions

639
alu.sv Normal file
View file

@ -0,0 +1,639 @@
////////////////////////////////////////////////////////////////////////////////
// Company: IIS @ ETHZ - Federal Institute of Technology //
// //
// Engineer: Matthias Baer - baermatt@student.ethz.ch //
// //
// Additional contributions by: //
// Igor Loi - igor.loi@unibo.it //
// Andreas Traber - atraber@student.ethz.ch //
// //
// //
// Create Date: 19/09/2013 //
// Design Name: Pipelined Processor //
// Module Name: alu.sv //
// Project Name: Processor //
// Language: SystemVerilog //
// //
// Description: Arithmetic logic unit of the pipelined processor //
// //
// //
// Revision: //
// Revision v0.1 - File Created //
// Revision v0.2 - (August 6th 2014) Changed port and signal names, addedd //
// comments //
// Revision v0.3 - (December 17 2014) Added vector support //
// //
// //
// //
// //
////////////////////////////////////////////////////////////////////////////////
`include "defines.sv"
module alu
(
// Inputs of the ALU
input logic [`ALU_OP_WIDTH-1:0] operator_i,
input logic [31:0] operand_a_i,
input logic [31:0] operand_b_i,
input logic carry_i,
input logic flag_i,
`ifdef TCDM_ADDR_PRECAL
input logic [31:0] adder_i,
`endif
input logic [1:0] vector_mode_i,
input logic [1:0] cmp_mode_i,
input logic [1:0] vec_ext_i,
output logic [31:0] adder_lsu_o,
output logic [31:0] result_o,
output logic overflow_o,
output logic carry_o,
output logic flag_o
);
`ifdef TCDM_ADDR_PRECAL
assign adder_lsu_o = adder_i;
`else
assign adder_lsu_o = operand_a_i + operand_b_i;
`endif
logic [31:0] operand_a_rev; // bit reversed signal of operand_a_i
// bit reverse operand_a for left shifts
genvar k;
generate
for(k = 0; k < 32; k++)
begin
assign operand_a_rev[k] = operand_a_i[31-k];
end
endgenerate
//////////////////////////////////////////////////////////////////////////////////////////
// ____ _ _ _ _ _ _ _ _ //
// | _ \ __ _ _ __| |_(_) |_(_) ___ _ __ ___ __| | / \ __| | __| | ___ _ __ //
// | |_) / _` | '__| __| | __| |/ _ \| '_ \ / _ \/ _` | / _ \ / _` |/ _` |/ _ \ '__| //
// | __/ (_| | | | |_| | |_| | (_) | | | | __/ (_| | / ___ \ (_| | (_| | __/ | //
// |_| \__,_|_| \__|_|\__|_|\___/|_| |_|\___|\__,_| /_/ \_\__,_|\__,_|\___|_| //
// //
//////////////////////////////////////////////////////////////////////////////////////////
logic [3:0] carry_in;
logic [3:0] carry_out;
logic [31:0] adder_op_a;
logic [31:0] adder_op_b;
logic [31:0] adder_result;
// prepare operand a
assign adder_op_a = (operator_i == `ALU_ABS) ? ~operand_a_i : operand_a_i;
// prepare operand b
assign adder_op_b = (operator_i == `ALU_SUB) ? ~operand_b_i : operand_b_i;
// prepare vector carrys
always_comb
begin
carry_in = {carry_out[2], carry_out[1], carry_out[0], 1'b0};
case (operator_i)
`ALU_ADDC: carry_in[0] = carry_i;
`ALU_SUB, `ALU_ABS:
begin
case (vector_mode_i)
default: // VEC_MODE32
begin
carry_in[0] = 1'b1;
end
`VEC_MODE16:
begin
carry_in[0] = 1'b1;
carry_in[2] = 1'b1;
end
`VEC_MODE8:
begin
carry_in = 4'b1111;
end
endcase
end
default:
begin
case (vector_mode_i)
default: // VEC_MODE32
begin
carry_in[0] = 1'b0;
end
`VEC_MODE16:
begin
carry_in[0] = 1'b0;
carry_in[2] = 1'b0;
end
`VEC_MODE8:
begin
carry_in = 4'b0000;
end
endcase
end
endcase
end
// adder consisting of four slices
assign {carry_out[0], adder_result[ 7: 0]} = adder_op_a[ 7: 0] + adder_op_b[ 7: 0] + carry_in[0];
assign {carry_out[1], adder_result[15: 8]} = adder_op_a[15: 8] + adder_op_b[15: 8] + carry_in[1];
assign {carry_out[2], adder_result[23:16]} = adder_op_a[23:16] + adder_op_b[23:16] + carry_in[2];
assign {carry_out[3], adder_result[31:24]} = adder_op_a[31:24] + adder_op_b[31:24] + carry_in[3];
// averaging by right shifting of one bit
logic [31:0] result_avg;
assign result_avg[ 6: 0] = adder_result[ 7: 1];
assign result_avg[14: 8] = adder_result[15: 9];
assign result_avg[22:16] = adder_result[23:17];
assign result_avg[30:24] = adder_result[31:25];
assign result_avg[ 7] = (vector_mode_i == `VEC_MODE8) ? ((operator_i == `ALU_AVGU) ? 1'b0 : adder_result[ 7]) : adder_result[ 8];
assign result_avg[15] = ((vector_mode_i == `VEC_MODE16) || (vector_mode_i == `VEC_MODE8)) ? ((operator_i == `ALU_AVGU) ? 1'b0 : adder_result[15]) : adder_result[16];
assign result_avg[23] = (vector_mode_i == `VEC_MODE8) ? ((operator_i == `ALU_AVGU) ? 1'b0 : adder_result[23]) : adder_result[24];
assign result_avg[31] = (operator_i == `ALU_AVGU) ? 1'b0 : adder_result[31];
////////////////////////////////////////
// ____ _ _ ___ _____ _____ //
// / ___|| | | |_ _| ___|_ _| //
// \___ \| |_| || || |_ | | //
// ___) | _ || || _| | | //
// |____/|_| |_|___|_| |_| //
// //
////////////////////////////////////////
logic shift_left; // should we shift left?
logic [31:0] shift_amt; // amount of shift
logic [31:0] shift_amt_left; // amount of shift, adapted to vector mode for sll
logic [31:0] shift_amt_int; // amount of shift, adapted to vector mode for sll
logic [31:0] shift_op_a; // input of the shifter
logic [31:0] shift_result;
logic [31:0] shift_left_result;
// by reversing the bits of the input, we also have the reverse the order of shift amounts
always_comb
begin
case(vector_mode_i)
default: // VEC_MODE32
begin
shift_amt_left[31: 0] = shift_amt[31: 0];
end
`VEC_MODE16:
begin
shift_amt_left[15: 0] = shift_amt[31:16];
shift_amt_left[31:16] = shift_amt[15: 0];
end
`VEC_MODE8:
begin
shift_amt_left[ 7: 0] = shift_amt[31:24];
shift_amt_left[15: 8] = shift_amt[23:16];
shift_amt_left[23:16] = shift_amt[15: 8];
shift_amt_left[31:24] = shift_amt[ 7: 0];
end
endcase
end
// choose the bit reversed or the normal input for shift operand a
assign shift_op_a = (shift_left == 1'b1) ? operand_a_rev : operand_a_i;
assign shift_amt_int = (shift_left == 1'b1) ? shift_amt_left : shift_amt;
// right shifts, we let the synthesizer optimize this
always_comb
begin
case(vector_mode_i)
default: // VEC_MODE32
begin
if(operator_i == `ALU_SRA)
shift_result = $unsigned( $signed(shift_op_a) >>> shift_amt_int[4:0] );
else if(operator_i == `ALU_ROR)
shift_result = {shift_op_a, shift_op_a} >> shift_amt_int[4:0];
else
shift_result = shift_op_a >> shift_amt_int[4:0];
end
`VEC_MODE16:
begin
if(operator_i == `ALU_SRA)
begin
shift_result[31:16] = $unsigned( $signed(shift_op_a[31:16]) >>> shift_amt_int[19:16] );
shift_result[15: 0] = $unsigned( $signed(shift_op_a[15: 0]) >>> shift_amt_int[ 3: 0] );
end
else
begin
shift_result[31:16] = shift_op_a[31:16] >> shift_amt_int[19:16];
shift_result[15: 0] = shift_op_a[15: 0] >> shift_amt_int[ 3: 0];
end
end
`VEC_MODE8:
begin
if(operator_i == `ALU_SRA)
begin
shift_result[31:24] = $unsigned( $signed(shift_op_a[31:24]) >>> shift_amt_int[26:24] );
shift_result[23:16] = $unsigned( $signed(shift_op_a[23:16]) >>> shift_amt_int[18:16] );
shift_result[15: 8] = $unsigned( $signed(shift_op_a[15: 8]) >>> shift_amt_int[10: 8] );
shift_result[ 7: 0] = $unsigned( $signed(shift_op_a[ 7: 0]) >>> shift_amt_int[ 2: 0] );
end
else
begin
shift_result[31:24] = shift_op_a[31:24] >> shift_amt_int[26:24];
shift_result[23:16] = shift_op_a[23:16] >> shift_amt_int[18:16];
shift_result[15: 8] = shift_op_a[15: 8] >> shift_amt_int[10: 8];
shift_result[ 7: 0] = shift_op_a[ 7: 0] >> shift_amt_int[ 2: 0];
end
end
endcase; // case (vec_mode_i)
end
// bit reverse the shift_result for left shifts
genvar j;
generate
for(j = 0; j < 32; j++)
begin
assign shift_left_result[j] = shift_result[31-j];
end
endgenerate
//////////////////////////////////////////////////////////////////
// ____ ___ __ __ ____ _ ____ ___ ____ ___ _ _ //
// / ___/ _ \| \/ | _ \ / \ | _ \|_ _/ ___| / _ \| \ | | //
// | | | | | | |\/| | |_) / _ \ | |_) || |\___ \| | | | \| | //
// | |__| |_| | | | | __/ ___ \| _ < | | ___) | |_| | |\ | //
// \____\___/|_| |_|_| /_/ \_\_| \_\___|____/ \___/|_| \_| //
// //
//////////////////////////////////////////////////////////////////
// results
logic [3:0] is_equal;
logic [3:0] is_greater; // handles both signed and unsigned forms
logic [3:0] sel_minmax; // mux control
logic [31:0] result_minmax;
logic [31:0] minmax_b;
logic do_min;
// 8-bit vector comparisons, basic building blocks
logic [3:0] cmp_sign_mode;
logic [3:0] is_equal_vec;
logic [3:0] is_greater_vec;
// generate cmp_sign_mode signal that is used for comparisons below
always_comb
begin
cmp_sign_mode[3:0] = 4'b0000; // unsigned mode
// signed mode
if ((operator_i == `ALU_GTS) ||
(operator_i == `ALU_GES) ||
(operator_i == `ALU_LTS) ||
(operator_i == `ALU_SLTS) ||
(operator_i == `ALU_LES) ||
(operator_i == `ALU_MAX) ||
(operator_i == `ALU_MIN) ||
(operator_i == `ALU_ABS))
begin
case (vector_mode_i)
default: cmp_sign_mode[3:0] = 4'b1000;
`VEC_MODE16: cmp_sign_mode[3:0] = 4'b1010;
`VEC_MODE8: cmp_sign_mode[3:0] = 4'b1111;
endcase
end
end
// generate vector equal and greater than signals, cmp_sign_mode decides if the comparison is done signed or unsigned
genvar i;
generate
for(i = 0; i < 4; i++)
begin
assign is_equal_vec[i] = (operand_a_i[8*i+7:8*i] == operand_b_i[8*i+7:i*8]);
assign is_greater_vec[i] = $signed({operand_a_i[8*i+7] & cmp_sign_mode[i], operand_a_i[8*i+7:8*i]})
>
$signed({operand_b_i[8*i+7] & cmp_sign_mode[i], operand_b_i[8*i+7:i*8]});
end
endgenerate
always_comb
begin
is_equal[3:0] = {4{is_equal_vec[3] & is_equal_vec[2] & is_equal_vec[1] & is_equal_vec[0]}};
is_greater[3:0] = {4{is_greater_vec[3] | (is_equal_vec[3] & (is_greater_vec[2]
| (is_equal_vec[2] & (is_greater_vec[1]
| (is_equal_vec[1] & (is_greater_vec[0]))))))}};
case(vector_mode_i)
default:; // see default assignment
`VEC_MODE16:
begin
is_equal[1:0] = {2{is_equal_vec[0] & is_equal_vec[1]}};
is_equal[3:2] = {2{is_equal_vec[2] & is_equal_vec[3]}};
is_greater[1:0] = {2{is_greater_vec[1] | (is_equal_vec[1] & is_greater_vec[0])}};
is_greater[3:2] = {2{is_greater_vec[3] | (is_equal_vec[3] & is_greater_vec[2])}};
end
`VEC_MODE8:
begin
is_equal[3:0] = is_equal_vec[3:0];
is_greater[3:0] = is_greater_vec[3:0];
end
endcase
end
// generate comparison results
logic [3:0] cmp_result;
logic any_result;
logic all_result;
always_comb
begin
cmp_result = is_equal;
case (operator_i)
`ALU_EQ: cmp_result = is_equal;
`ALU_NE: cmp_result = ~is_equal;
`ALU_GTS, `ALU_GTU: cmp_result = is_greater;
`ALU_GES, `ALU_GEU: cmp_result = is_greater | is_equal;
`ALU_LTS, `ALU_SLTS,
`ALU_LTU, `ALU_SLTU: cmp_result = ~(is_greater | is_equal);
`ALU_LES, `ALU_LEU: cmp_result = ~is_greater;
default:; // nothing to do
endcase //~case(operator_i)
end
assign any_result = |cmp_result;
assign all_result = &cmp_result;
// choose result value for min/max/abs
assign minmax_b = (operator_i == `ALU_ABS) ? adder_result : operand_b_i;
assign do_min = ((operator_i == `ALU_MIN) || (operator_i == `ALU_MINU));
// reuse the minmax mux also for the cmove instruction
// the mux now handles, min, max, abs, cmov, ins
always_comb
begin
sel_minmax[3:0] = is_greater ^ {4{do_min}};
if(operator_i == `ALU_CMOV)
sel_minmax[3:0] = {4{flag_i}};
if(operator_i == `ALU_INS)
begin
if(vector_mode_i == `VEC_MODE16)
begin
sel_minmax[1:0] = {2{vec_ext_i[0]}};
sel_minmax[3:2] = ~{2{vec_ext_i[0]}};
end
else // `VEC_MODE8
begin
sel_minmax[0] = (vec_ext_i != 2'b00);
sel_minmax[1] = (vec_ext_i != 2'b01);
sel_minmax[2] = (vec_ext_i != 2'b10);
sel_minmax[3] = (vec_ext_i != 2'b11);
end
end
end
assign result_minmax[31:24] = (sel_minmax[3] == 1'b1) ? operand_a_i[31:24] : minmax_b[31:24];
assign result_minmax[23:16] = (sel_minmax[2] == 1'b1) ? operand_a_i[23:16] : minmax_b[23:16];
assign result_minmax[15: 8] = (sel_minmax[1] == 1'b1) ? operand_a_i[15: 8] : minmax_b[15: 8];
assign result_minmax[ 7: 0] = (sel_minmax[0] == 1'b1) ? operand_a_i[ 7: 0] : minmax_b[ 7: 0];
//////////////////////////////////////////////////
// _____ _ _ //
// | ____|_ _| |_ ___ _ __ ___(_) ___ _ __ //
// | _| \ \/ / __/ _ \ '_ \/ __| |/ _ \| '_ \ //
// | |___ > <| || __/ | | \__ \ | (_) | | | | //
// |_____/_/\_\\__\___|_| |_|___/_|\___/|_| |_| //
// //
//////////////////////////////////////////////////
logic [7:0] ext_byte;
logic [15:0] ext_word;
logic [31:0] result_ext;
always_comb
begin
ext_byte = operand_a_i[7:0];
if(operator_i == `ALU_EXT)
begin
case(vec_ext_i)
2'b00: ext_byte = operand_a_i[ 7: 0];
2'b01: ext_byte = operand_a_i[15: 8];
2'b10: ext_byte = operand_a_i[23:16];
2'b11: ext_byte = operand_a_i[31:24];
endcase
end
end
assign ext_word = ((vec_ext_i[0] == 1'b1) && (operator_i == `ALU_EXT)) ? operand_a_i[31:16] : operand_a_i[15:0];
always_comb
begin
// zero extend byte
result_ext = {24'b0, ext_byte[7:0]};
// sign extend byte
if((operator_i == `ALU_EXTBS) || ((operator_i == `ALU_EXT) && (vector_mode_i == `VEC_MODE8)))
result_ext = {{24{ext_byte[7]}}, ext_byte[7:0]};
// zero extend word
if(operator_i == `ALU_EXTHZ)
result_ext = {16'b0, ext_word[15:0]};
// sign extend word
if((operator_i == `ALU_EXTHS) || ((operator_i == `ALU_EXT) && (vector_mode_i == `VEC_MODE16)))
result_ext = {{16{ext_word[15]}}, ext_word[15:0]};
end
/////////////////////////////////////////////////////////////////////
// ____ _ _ ____ _ ___ //
// | __ )(_) |_ / ___|___ _ _ _ __ | |_ / _ \ _ __ ___ //
// | _ \| | __| | | / _ \| | | | '_ \| __| | | | | '_ \/ __| //
// | |_) | | |_ | |__| (_) | |_| | | | | |_ | |_| | |_) \__ \_ //
// |____/|_|\__| \____\___/ \__,_|_| |_|\__| \___/| .__/|___(_) //
// |_| //
/////////////////////////////////////////////////////////////////////
logic [31:0] ff_input; // either op_a_i or its bit reversed version
logic [5:0] ff1_result; // holds the index of the first '1'
logic [5:0] fl1_result; // holds the index of the last '1'
logic ff_cmp; // compare value for ff1 and fl1
integer q;
assign ff_input = (operator_i == `ALU_FF1) ? operand_a_i : operand_a_rev;
assign ff_cmp = (operator_i == `ALU_CLB) ? ~operand_a_i[31] : 1'b1;
// search for first bit set to '1'
always_comb
begin
ff1_result = 6'd0;
for(q = 0; q < 32; q++)
begin
if(ff_input[q] == ff_cmp)
begin
ff1_result = q + 6'd1;
break;
end
end
end
// special case if ff1_res is 0 (no 1 found), then we keep the 0
assign fl1_result = (ff1_result == 6'd0) ? 6'd0 : (6'd33 - ff1_result);
// count the number of '1's in a word
logic [5:0] cnt_result; // holds the number of '1's in a word
logic [1:0] cnt_l1[16];
logic [2:0] cnt_l2[8];
logic [3:0] cnt_l3[4];
logic [4:0] cnt_l4[2];
genvar l, m, n, p;
generate for(l = 0; l < 16; l++)
begin
assign cnt_l1[l] = operand_a_i[2*l] + operand_a_i[2*l + 1];
end
endgenerate
generate for(m = 0; m < 8; m++)
begin
assign cnt_l2[m] = cnt_l1[2*m] + cnt_l1[2*m + 1];
end
endgenerate
generate for(n = 0; n < 4; n++)
begin
assign cnt_l3[n] = cnt_l2[2*n] + cnt_l2[2*n + 1];
end
endgenerate
generate for(p = 0; p < 2; p++)
begin
assign cnt_l4[p] = cnt_l3[2*p] + cnt_l3[2*p + 1];
end
endgenerate
assign cnt_result = cnt_l4[0] + cnt_l4[1];
////////////////////////////////////////////////////////
// ____ _ _ __ __ //
// | _ \ ___ ___ _ _| | |_ | \/ |_ ___ __ //
// | |_) / _ \/ __| | | | | __| | |\/| | | | \ \/ / //
// | _ < __/\__ \ |_| | | |_ | | | | |_| |> < //
// |_| \_\___||___/\__,_|_|\__| |_| |_|\__,_/_/\_\ //
// //
////////////////////////////////////////////////////////
always_comb
begin
shift_left = 1'b0;
shift_amt = operand_b_i;
result_o = 'x;
carry_o = 1'b0;
overflow_o = 1'b0;
flag_o = 1'b0;
unique case (operator_i)
// Standard Operations
`ALU_ADD, `ALU_ADDC, `ALU_SUB:
begin // Addition defined above
result_o = adder_result[31:0];
carry_o = carry_out[3];
overflow_o = (adder_op_a[31] ^ adder_result[31]) & (adder_op_b[31] ^ adder_result[31]); // ++ => - and -- => +
end
`ALU_AVG, `ALU_AVGU: result_o = result_avg;
`ALU_AND: result_o = operand_a_i & operand_b_i;
`ALU_OR: result_o = operand_a_i | operand_b_i;
`ALU_XOR: result_o = operand_a_i ^ operand_b_i;
// Shift Operations
`ALU_MOVHI:
begin
shift_left = 1'b1;
shift_amt = 32'd16;
result_o = shift_left_result;
end
`ALU_SLL:
begin
shift_left = 1'b1;
result_o = shift_left_result;
end
`ALU_SRL, `ALU_SRA, `ALU_ROR: result_o = shift_result;
// Extension Operations
`ALU_EXTWZ, `ALU_EXTWS: result_o = operand_a_i;
`ALU_EXTBZ, `ALU_EXTBS, `ALU_EXTHZ, `ALU_EXTHS, `ALU_EXT: result_o = result_ext;
// Min/Max/Abs, CMOV, INS
`ALU_MIN, `ALU_MINU, `ALU_MAX, `ALU_MAXU, `ALU_ABS, `ALU_CMOV, `ALU_INS: result_o = result_minmax;
// Comparison Operations
`ALU_EQ, `ALU_NE, `ALU_GTU, `ALU_GEU, `ALU_LTU, `ALU_LEU, `ALU_GTS, `ALU_GES, `ALU_LTS, `ALU_LES:
begin
result_o[31:24] = {8{cmp_result[3]}};
result_o[23:16] = {8{cmp_result[2]}};
result_o[15: 8] = {8{cmp_result[1]}};
result_o[ 7: 0] = {8{cmp_result[0]}};
case (cmp_mode_i)
`ALU_CMP_ANY:
begin
flag_o = any_result;
end
`ALU_CMP_ALL:
begin
flag_o = all_result;
end
`ALU_CMP_FULL:
begin
flag_o = cmp_result[0];
end
default:;
endcase //~case(cmp_mode_i)
end
// Set Lower Than Operations (result = 1, if a < b)
`ALU_SLTS, `ALU_SLTU: result_o = {30'b0, cmp_result[0]};
`ALU_FF1: result_o = {26'h0, ff1_result};
`ALU_FL1: result_o = {26'h0, fl1_result};
`ALU_CLB: result_o = {26'h0, fl1_result};
`ALU_CNT: result_o = {26'h0, cnt_result};
`ALU_NOP: ; // Do nothing
default:
begin
//synopsys translate_off
//synopsys translate_on
end
endcase //~case(operator_i)
end
endmodule //~module alu

1404
controller.sv Normal file

File diff suppressed because it is too large Load diff

221
debug_unit.sv Normal file
View file

@ -0,0 +1,221 @@
////////////////////////////////////////////////////////////////////////////////
// Company: IIS @ ETHZ - Federal Institute of Technology //
// //
// Engineer: Florian Glaser - glaserf@ethz.ch //
// //
// Additional contributions by: //
// Andreas Traber - atraber@student.ethz.ch //
// //
// //
// Create Date: 11/07/2014 //
// Design Name: Pipelined OpenRISC Processor //
// Module Name: debug_unit.sv //
// Project Name: OR10N //
// Language: SystemVerilog //
// //
// Description: Debug Controller for the pipelined processor //
// //
// //
// Revision: //
// Revision v0.1 - File Created //
// Revision v0.2 - (December 1, 2014) Merge with current OR10N core, //
// changed port and signal names //
// //
// //
// //
// //
// //
////////////////////////////////////////////////////////////////////////////////
`include "defines.sv"
module debug_unit
(
input logic clk,
input logic rst_n,
// signals to Debug Interface
input logic dbginf_stall_i,
output logic dbginf_bp_o,
input logic dbginf_strobe_i,
output logic dbginf_ack_o,
input logic dbginf_we_i,
input logic [15:0] dbginf_addr_i,
input logic [31:0] dbginf_data_i,
output logic [31:0] dbginf_data_o,
// signals to core
output logic dbg_st_en_o, // Single-step trace mode enabled
output logic [1:0] dbg_dsr_o, // debug stop register
output logic stall_core_o,
output logic flush_pipe_o,
input logic pipe_flushed_i,
input logic trap_i,
output logic sp_mux_o,
output logic regfile_mux_o,
output logic regfile_we_o,
output logic [15:0] regfile_addr_o,
output logic [31:0] regfile_wdata_o,
input logic [31:0] regfile_rdata_i
);
// registers for debug control
logic [1:0] DSR_DP, DSR_DN; // Debug Stop Register: IIE, INTE
logic [1:0] DMR1_DP, DMR1_DN; // only single step trace and branch trace bits
logic [2*`N_WP-1:0] DMR2_DP, DMR2_DN; // only BP enable control and BP cause status
// watchpoint status
logic [`N_WP-1:0] WP_Status_D;
// BP control FSM
enum logic [2:0] {Idle, Trap, DebugStall, StallCore} BP_State_SN, BP_State_SP;
// ack to debug interface
assign dbginf_ack_o = (dbginf_strobe_i && (BP_State_SP == StallCore));
always_comb
begin
BP_State_SN = BP_State_SP;
stall_core_o = 1'b0;
dbginf_bp_o = 1'b0;
flush_pipe_o = 1'b0;
case (BP_State_SP)
Idle:
begin
if(trap_i == 1'b1)
BP_State_SN = Trap;
if(dbginf_stall_i)
begin
flush_pipe_o = 1'b1;
BP_State_SN = DebugStall;
end
end
// A trap was encountered, wait for for the pipeline to be
// flushed
Trap:
begin
if(pipe_flushed_i == 1'b1)
begin
dbginf_bp_o = 1'b1;
BP_State_SN = StallCore;
end
end
// A stall from adv dbg was seen, flush the pipeline and wait for unstalling
DebugStall:
begin
flush_pipe_o = 1'b1;
if(pipe_flushed_i == 1'b1)
begin
BP_State_SN = StallCore;
end
end
StallCore:
begin
stall_core_o = 1'b1;
if(~dbginf_stall_i)
BP_State_SN = Idle;
end
default: BP_State_SN = Idle;
endcase // case (BP_State_SP)
end
// data to GPRs and SPRs
assign regfile_wdata_o = dbginf_data_i;
assign dbg_st_en_o = DMR1_DP[0];
assign dbg_dsr_o = DSR_DP;
// address decoding, write and read controller
always_comb
begin
DMR1_DN = DMR1_DP;
DMR2_DN[`N_WP-1:0] = DMR2_DP[`N_WP-1:0];
DSR_DN = DSR_DP;
dbginf_data_o = 32'b0;
regfile_we_o = 1'b0;
regfile_addr_o = 16'b0;
regfile_mux_o = 1'b0;
sp_mux_o = 1'b0;
if(dbginf_strobe_i == 1'b1) begin
// address decoding, first stage: evaluate higher 5 Bits to detect if debug regs are accessed
if(dbginf_addr_i[15:11] == 5'b00110) begin
// second stage: evaluate Bits 10:0 to detect which part of debug registers is accessed
casex(dbginf_addr_i[10:0])
11'd16: begin // SP_DMR1
if(dbginf_we_i == 1'b1)
DMR1_DN = dbginf_data_i[`DMR1_ST+1:`DMR1_ST];
else
dbginf_data_o[`DMR1_ST+1:`DMR1_ST] = DMR1_DP;
end
11'd17: begin // SP_DMR2
if(dbginf_we_i == 1'b1)
DMR2_DN[`N_WP-1:0] = dbginf_data_i[`DMR2_WGB0 + (`N_WP-1):`DMR2_WGB0];
else
dbginf_data_o[`DMR2_WGB0 + (`N_WP-1):`DMR2_WGB0] = DMR2_DP[`N_WP-1:0];
dbginf_data_o[`DMR2_WBS0 + (`N_WP-1):`DMR2_WBS0] = DMR2_DP[2*`N_WP-1:`N_WP];
end
11'd20: begin // SP_DSR
// currently we only handle IIE and INTE
if(dbginf_we_i == 1'b1)
DSR_DN = dbginf_data_i[7:6];
else
dbginf_data_o[7:6] = DSR_DP[1:0];
end
default: ;
endcase // casex [10:0]
end
// check if GPRs are accessed
else if(dbginf_addr_i[15:10] == 6'b000001)
begin
regfile_mux_o = 1'b1;
regfile_addr_o[4:0] = dbginf_addr_i[4:0];
if(dbginf_we_i == 1'b1)
regfile_we_o = 1'b1;
else
dbginf_data_o = regfile_rdata_i;
end
// some other SPR is accessed
else
begin
sp_mux_o = 1'b1;
regfile_addr_o = dbginf_addr_i;
if(dbginf_we_i == 1'b1)
regfile_we_o = 1'b1;
else
dbginf_data_o = regfile_rdata_i;
end
end
end
// normal FF setup
always_ff@(posedge clk or negedge rst_n) begin
if (~rst_n) begin
DMR1_DP <= 2'b0;
DMR2_DP <= 'b0;
DSR_DP <= 'b0;
BP_State_SP <= Idle;
end
else begin
DMR1_DP <= DMR1_DN;
DMR2_DP <= DMR2_DN;
DSR_DP <= DSR_DN;
BP_State_SP <= BP_State_SN;
end
end // always_ff@ (posedge clk or negedge rst_n)
endmodule // debug_unit

270
ex_stage.sv Normal file
View file

@ -0,0 +1,270 @@
////////////////////////////////////////////////////////////////////////////////
// Company: IIS @ ETHZ - Federal Institute of Technology //
// DEI @ UNIBO - University of Bologna //
// //
// Engineer: Renzo Andri - andrire@student.ethz.ch //
// //
// Additional contributions by: //
// Igor Loi - igor.loi@unibo.it //
// //
// //
// Create Date: 01/07/2014 //
// Design Name: Execute stage //
// Module Name: ex_stage.sv //
// Project Name: OR10N //
// Language: SystemVerilog //
// //
// Description: Execution stage: Host Alu and Multiplier //
// ALU: computes additions/subtractions/comparisons //
// (in a pure combinational way) //
// Multiplier: //
// 32bit multiplication: takes two cycles to complete. The //
// Result goes to the register file (only the 32 lsb) //
// 64bit multiplication(l.muld): takes two cycles to complete //
// Result goes to sp register maclo(32lsb) and machi(32msb) //
// //
// //
// Revision: //
// //
// Revision v0.1 - File Created //
// //
// //
// //
////////////////////////////////////////////////////////////////////////////////
// int = internal signals
// wb = writeback
// sp = special registers
`include "defines.sv"
module ex_stage
(
input logic clk,
input logic rst_n,
// ALU signals from ID stage
input logic [`ALU_OP_WIDTH-1:0] alu_operator_i,
input logic [31:0] alu_operand_a_i,
input logic [31:0] alu_operand_b_i,
input logic [31:0] alu_operand_c_i,
input logic alu_carry_i,
input logic alu_flag_i,
input logic [1:0] vector_mode_i,
input logic [1:0] alu_cmp_mode_i,
input logic [1:0] alu_vec_ext_i,
// Multiplier signals
input logic mult_is_running_i,
input logic [1:0] mult_sel_subword_i,
input logic [1:0] mult_signed_mode_i,
input logic mult_use_carry_i,
input logic mult_mac_en_i,
output logic [31:0] data_addr_ex_o,
// input from ID stage
input logic stall_ex_i,
input logic stall_wb_i,
input logic [4:0] regfile_alu_waddr_i,
input logic regfile_alu_we_i,
input logic prepost_useincr_i,
// directly passed through to WB stage, not used in EX
input logic regfile_we_i,
input logic [4:0] regfile_waddr_i,
input logic regfile_wdata_mux_sel_i,
input logic [31:0] regfile_rb_data_i,
input logic hwloop_wb_mux_sel_i,
input logic [31:0] hwloop_pc_plus4_i,
input logic [31:0] hwloop_cnt_i,
input logic set_overflow_i,
input logic set_carry_i,
input logic eoc_i,
input logic sp_we_i,
// Output of EX stage pipeline
//interface with Special registers
output logic alu_flag_o,
output logic carry_o,
output logic overflow_o,
output logic set_overflow_o,
output logic set_carry_o,
output logic [15:0] regfile_wdata_wb_o,
output logic [4:0] regfile_waddr_wb_o,
output logic regfile_wdata_mux_sel_wb_o,
output logic regfile_we_wb_o,
output logic [31:0] regfile_rb_data_wb_o,
output logic [31:0] hwloop_start_data_o,
output logic [31:0] hwloop_end_data_o,
output logic [31:0] hwloop_cnt_data_o,
output logic sp_we_wb_o,
output logic eoc_o,
// Forwarding ports : to ID stage
output logic [4:0] regfile_alu_waddr_fw_o,
output logic regfile_alu_we_fw_o,
output logic [31:0] regfile_alu_wdata_fw_o, // forward to RF and ID/EX pipe, ALU & MUL
output logic [31:0] regfile_alu_wdata_fw_pc_o // forward to PC, no multiplication
`ifdef TCDM_ADDR_PRECAL
,
input logic [31:0] alu_adder_i
`endif
);
// Alu outputs - OVerflow and CarrY
logic alu_overflow_int;
logic alu_carry_int;
// Internal output of the LU
logic [31:0] alu_result;
logic [31:0] alu_adder_lsu_int; // to LS unit
logic [31:0] mult_result;
logic mult_carry_int;
logic mult_overflow_int;
// Result Selection: Select between ALU output signals and MUL
assign carry_o = (mult_is_running_i == 1'b1) ? mult_carry_int : alu_carry_int;
assign overflow_o = (mult_is_running_i == 1'b1) ? mult_overflow_int : alu_overflow_int;
assign regfile_alu_we_fw_o = regfile_alu_we_i;
assign regfile_alu_waddr_fw_o = regfile_alu_waddr_i;
assign regfile_alu_wdata_fw_o = (mult_is_running_i == 1'b0) ? alu_result : mult_result;
assign regfile_alu_wdata_fw_pc_o = alu_result; // forwarding to PC, multiplication not allowed
// generate flags: goes to special purpose register
assign set_overflow_o = (stall_ex_i == 1'b0) ? set_overflow_i : 1'b0;
assign set_carry_o = (stall_ex_i == 1'b0) ? set_carry_i : 1'b0;
//NOTE Igor fix: replaced alu_adder_int with alu_adder_lsu_int --> Now data_addr is calculated with
//NOTE a dedicated adder, no carry is considered , just op_a + op_b from id stage
assign data_addr_ex_o = (prepost_useincr_i == 1'b1) ? alu_adder_lsu_int : alu_operand_a_i;
// hwloop mux. selects the right data to be sent to the hwloop registers (start/end-address and counter)
always_comb
begin : hwloop_start_mux
case (hwloop_wb_mux_sel_i)
1'b0: hwloop_start_data_o = hwloop_pc_plus4_i;
1'b1: hwloop_start_data_o = alu_result;
endcase; // case (hwloop_wb_mux_sel)
end
// assign alu result to hwloop end data
assign hwloop_end_data_o = alu_result;
// assign hwloop mux. selects the right data to be sent to the hwloop registers (start/end-address and counter)
assign hwloop_cnt_data_o = hwloop_cnt_i;
////////////////////////////
// _ _ _ _ //
// / \ | | | | | | //
// / _ \ | | | | | | //
// / ___ \| |__| |_| | //
// /_/ \_\_____\___/ //
// //
////////////////////////////
alu alu_i
(
.operator_i ( alu_operator_i ),
.operand_a_i ( alu_operand_a_i ),
.operand_b_i ( alu_operand_b_i ),
.carry_i ( alu_carry_i ),
.flag_i ( alu_flag_i ),
`ifdef TCDM_ADDR_PRECAL
.adder_i ( alu_adder_i ),
`endif
.vector_mode_i ( vector_mode_i ),
.cmp_mode_i ( alu_cmp_mode_i ),
.vec_ext_i ( alu_vec_ext_i ),
.adder_lsu_o ( alu_adder_lsu_int ),
.result_o ( alu_result ),
.overflow_o ( alu_overflow_int ), // Internal signal
.carry_o ( alu_carry_int ), // Internal signal
.flag_o ( alu_flag_o )
);
////////////////////////////////////////////////////////////////
// __ __ _ _ _ _____ ___ ____ _ ___ _____ ____ //
// | \/ | | | | | |_ _|_ _| _ \| | |_ _| ____| _ \ //
// | |\/| | | | | | | | | || |_) | | | || _| | |_) | //
// | | | | |_| | |___| | | || __/| |___ | || |___| _ < //
// |_| |_|\___/|_____|_| |___|_| |_____|___|_____|_| \_\ //
// //
////////////////////////////////////////////////////////////////
/*
mult mult_i
(
.vector_mode_i ( vector_mode_i ),
.sel_subword_i ( mult_sel_subword_i ),
.signed_mode_i ( mult_signed_mode_i ),
.use_carry_i ( mult_use_carry_i ),
.mac_en_i ( mult_mac_en_i ),
.op_a_i ( alu_operand_a_i ),
.op_b_i ( alu_operand_b_i ),
.mac_i ( alu_operand_c_i ),
.carry_i ( alu_carry_i ),
.result_o ( mult_result ),
.carry_o ( mult_carry_int ),
.overflow_o ( mult_overflow_int )
);
*/
///////////////////////////////////////
// EX/WB Pipeline Register //
///////////////////////////////////////
always_ff @(posedge clk, negedge rst_n)
begin : EX_WB_Pipeline_Register
if (rst_n == 1'b0)
begin
regfile_wdata_wb_o <= 16'h0000;
regfile_waddr_wb_o <= 5'b0_0000;
regfile_wdata_mux_sel_wb_o <= 1'b0;
regfile_we_wb_o <= 1'b0;
regfile_rb_data_wb_o <= 32'h0000_0000;
sp_we_wb_o <= 1'b0;
eoc_o <= 1'b0;
end
else
begin
if (stall_wb_i == 1'b0)
begin
regfile_we_wb_o <= regfile_we_i;
regfile_waddr_wb_o <= regfile_waddr_i;
regfile_wdata_wb_o <= alu_result[15:0]; // this is only used for SPR address
regfile_wdata_mux_sel_wb_o <= regfile_wdata_mux_sel_i;
regfile_rb_data_wb_o <= regfile_rb_data_i;
sp_we_wb_o <= sp_we_i;
eoc_o <= eoc_i;
end
end
end
endmodule

887
id_stage.sv Normal file
View file

@ -0,0 +1,887 @@
////////////////////////////////////////////////////////////////////////////////
// Company: IIS @ ETHZ - Federal Institute of Technology //
// DEI @ UNIBO - University of Bologna //
// //
// Engineer: Renzo Andri - andrire@student.ethz.ch //
// //
// Additional contributions by: //
// Igor Loi - igor.loi@unibo.it //
// Andreas Traber - atraber@student.ethz.ch //
// //
// //
// Create Date: 19/09/2013 //
// Design Name: Decode stage //
// Module Name: id_stage.sv //
// Project Name: OR10N //
// Language: SystemVerilog //
// //
// Description: Decode stage of the OR10N core. It decodes the instructions//
// and hosts the register file and the pipe controller //
// //
// Revision: //
// Revision v0.1 - File Created //
// Revision v0.2 - (July 1st 2014) Pipe splitted in several files //
// Revision v0.3 - (August 7th 2014) Changed port and signal names, added //
// comments //
// Revision v0.4 - (December 1th 2014) Merged debug unit //
// //
// //
// //
// //
////////////////////////////////////////////////////////////////////////////////
`include "defines.sv"
module id_stage
(
input logic clk,
input logic rst_n,
input logic fetch_enable_i,
output logic core_busy_o,
// Interface to instruction memory
input logic [31:0] instr_rdata_i, // comes from pipeline of IF stage
output logic instr_req_o,
input logic instr_gnt_i,
input logic instr_ack_i,
// IF and ID stage signals
output logic [31:0] pc_from_immediate_o,
output logic [2:0] pc_mux_sel_o,
output logic pc_mux_boot_o,
output logic [1:0] exc_pc_mux_o,
output logic force_nop_o,
output logic [31:0] pc_from_regfile_fw_o,
input logic [31:0] current_pc_if_i,
input logic [31:0] current_pc_id_i,
// branch prediction
output logic drop_instruction_o,
`ifdef BRANCH_PREDICTION
output logic wrong_branch_taken_o,
output logic take_branch_o,
`endif
// STALLS
output logic stall_if_o,
output logic stall_id_o,
output logic stall_ex_o,
output logic stall_wb_o,
input logic sr_flag_fw_i,
input logic sr_flag_i,
// To the Pipeline ID/EX
output logic [31:0] regfile_rb_data_ex_o,
output logic [31:0] alu_operand_a_ex_o,
output logic [31:0] alu_operand_b_ex_o,
output logic [31:0] alu_operand_c_ex_o,
output logic [`ALU_OP_WIDTH-1:0] alu_operator_ex_o,
output logic [1:0] vector_mode_ex_o,
output logic [1:0] alu_cmp_mode_ex_o,
output logic [1:0] alu_vec_ext_ex_o,
output logic eoc_ex_o,
output logic mult_is_running_ex_o, // TODO: Rename (-> mult enable ?)
output logic [1:0] mult_sel_subword_ex_o,
output logic [1:0] mult_signed_mode_ex_o,
output logic mult_use_carry_ex_o,
output logic mult_mac_en_ex_o,
output logic [4:0] regfile_waddr_ex_o,
output logic regfile_wdata_mux_sel_ex_o,
output logic regfile_we_ex_o,
output logic [4:0] regfile_alu_waddr_ex_o,
output logic regfile_alu_we_ex_o,
output logic prepost_useincr_ex_o,
input logic data_misaligned_i,
output logic [2:0] hwloop_we_ex_o,
output logic [1:0] hwloop_regid_ex_o,
output logic hwloop_wb_mux_sel_ex_o,
output logic [31:0] hwloop_cnt_o,
output logic [`HWLOOP_REGS-1:0] hwloop_dec_cnt_o,
output logic [31:0] hwloop_targ_addr_o,
output logic sp_we_ex_o,
// Interface to load store unit
output logic data_we_ex_o,
output logic [1:0] data_type_ex_o,
output logic data_sign_ext_ex_o,
output logic [1:0] data_reg_offset_ex_o,
output logic data_misaligned_ex_o,
output logic data_req_ex_o,
input logic data_ack_i, // Grant from data memory
input logic data_rvalid_i,
// SPR signals
output logic set_flag_ex_o,
output logic set_carry_ex_o,
output logic set_overflow_ex_o,
output logic set_dsx_o,
// Interrupt signals
input logic irq_i,
input logic irq_nm_i,
input logic irq_enable_i,
output logic save_pc_if_o,
output logic save_pc_id_o,
output logic save_sr_o,
output logic restore_sr_o,
// from hwloop regs
input logic [`HWLOOP_REGS-1:0] [31:0] hwloop_start_addr_i,
input logic [`HWLOOP_REGS-1:0] [31:0] hwloop_end_addr_i,
input logic [`HWLOOP_REGS-1:0] [31:0] hwloop_counter_i,
// Debug Unit Signals
input logic dbg_flush_pipe_i,
output logic pipe_flushed_o,
input logic dbg_st_en_i,
input logic [1:0] dbg_dsr_i,
input logic dbg_stall_i,
output logic dbg_trap_o,
input logic dbg_reg_mux_i,
input logic dbg_reg_we_i,
input logic [4:0] dbg_reg_addr_i,
input logic [31:0] dbg_reg_wdata_i,
output logic [31:0] dbg_reg_rdata_o,
input logic dbg_set_npc_i,
// Forward Signals
input logic [4:0] regfile_waddr_wb_i,
input logic regfile_we_wb_i,
input logic [31:0] regfile_wdata_wb_i, // From wb_stage: selects data from data memory, ex_stage result and sp rdata
input logic [4:0] regfile_alu_waddr_fw_i,
input logic regfile_alu_we_fw_i,
input logic [31:0] regfile_alu_wdata_fw_i,
input logic [31:0] regfile_alu_wdata_fw_pc_i,
input logic [31:0] wdata_reg_i
`ifdef TCDM_ADDR_PRECAL
,
output logic [31:0] alu_adder_o
`endif
);
// Immediate decoding and sign extension
logic [31:0] imm_i_type;
logic [31:0] imm_s_type;
logic [31:0] imm_sb_type;
logic [31:0] imm_u_type;
logic [31:0] imm_uj_type;
logic [31:0] immediate_b; // contains the immediate for operand b
logic [31:0] current_pc; // PC to be used in ALU (either IF or ID)
logic exc_pc_sel;
logic [2:0] pc_mux_sel_int; // selects next PC in if stage
logic irq_present;
// Signals running between controller and exception controller
logic jump_in_id;
logic jump_in_ex; // registered copy of jump_in_id
logic illegal_insn;
logic trap_insn;
logic pipe_flush;
logic pc_valid;
logic clear_isr_running;
logic [4:0] regfile_addr_ra_id;
logic [4:0] regfile_addr_rb_id;
logic [4:0] regfile_addr_rc_id;
logic [4:0] regfile_waddr_id;
logic [4:0] regfile_alu_waddr_id;
logic regfile_alu_we_id;
logic [31:0] regfile_data_ra_id;
logic [31:0] regfile_data_rb_id;
logic [31:0] regfile_data_rc_id;
logic imm_sign_ext_sel;
// ALU Control
logic [`ALU_OP_WIDTH-1:0] alu_operator;
logic [1:0] alu_op_a_mux_sel;
logic [1:0] alu_op_b_mux_sel;
logic scalar_replication;
logic [1:0] vector_mode;
logic [1:0] alu_cmp_mode;
logic [1:0] alu_vec_ext;
logic alu_pc_mux_sel;
logic [3:0] immediate_mux_sel;
// Multiplier Control
logic mult_is_running; // output of the controller (1 if the opcode is a multiplication)
logic [1:0] mult_sel_subword; // Select a subword when doing multiplications
logic [1:0] mult_signed_mode; // Signed mode multiplication at the output of the controller, and before the pipe registers
logic mult_use_carry; // Enables carry in for the MAC
logic mult_mac_en; // Enables the use of the accumulator
logic eoc; // End of computation generated from the controller
// Register Write Control
logic regfile_wdata_mux_sel;
logic regfile_we_id;
logic [1:0] regfile_alu_waddr_mux_sel; // TODO: FixMe -> 1bit
// Special-Purpose Register Write Control
logic sp_we_id;
// Data Memory Control
logic data_we_id;
logic [1:0] data_type_id;
logic data_sign_ext_id;
logic [1:0] data_reg_offset_id;
logic data_req_id;
// hwloop signals
logic [1:0] hwloop_regid;
logic [2:0] hwloop_we;
logic hwloop_wb_mux_sel;
logic [1:0] hwloop_cnt_mux_sel;
logic [31:0] hwloop_cnt;
logic hwloop_jump;
logic hwloop_enable;
// Supervision Register
logic set_flag;
logic set_carry;
logic set_overflow;
logic prepost_useincr;
// Forwarding
logic [1:0] operand_a_fw_mux_sel;
logic [1:0] operand_b_fw_mux_sel;
logic [1:0] operand_c_fw_mux_sel;
logic [31:0] operand_a_fw_id;
logic [31:0] operand_b_fw_id;
logic [31:0] alu_operand_a;
logic [31:0] alu_operand_b;
logic [31:0] alu_operand_c;
logic [31:0] operand_b; // before going through the scalar replication mux
logic [31:0] operand_b_vec; // scalar replication of operand_b for 8 and 16 bit
// TODO: FIXME temporary assignments while not everything is implemented (e.g. exceptions)
assign exc_pc_sel = 1'b0;
assign pc_valid = 1'b1;
assign pc_mux_sel_o = (exc_pc_sel == 1'b1) ? `PC_EXCEPTION : pc_mux_sel_int;
// Instruction Parts
logic [31:0] instr;
assign instr = instr_rdata_i; // TODO: Remove
assign imm_i_type = { {20 {instr[31]}}, instr[31:20] };
assign imm_s_type = { {20 {instr[31]}}, instr[31:25], instr[11:7] };
assign imm_sb_type = { {20 {instr[31]}}, instr[31], instr[7], instr[30:25], instr[11:8] };
assign imm_u_type = { instr[31:12], {12 {1'b0}} };
assign imm_uj_type = { {20 {instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0 };
// source registers
assign regfile_addr_ra_id = instr[19:15];
assign regfile_addr_rb_id = instr[24:20];
//assign regfile_addr_rc_id = instr_rdata_i[25:21];
//assign alu_vec_ext = instr_rdata_i[9:8];
// destination registers
assign regfile_waddr_id = instr[11:7];
// Second Register Write Adress Selection
// Used for prepost load/store and multiplier
always_comb
begin : alu_waddr_mux
case (regfile_alu_waddr_mux_sel)
default: regfile_alu_waddr_id = regfile_addr_ra_id;
2'b00: regfile_alu_waddr_id = regfile_addr_ra_id;
2'b01: regfile_alu_waddr_id = regfile_waddr_id;
endcase
end
///////////////////////////////////////////////////////////////////////////////////////
// ____ ____ _ //
// | _ \ _ __ ___ __ _ _ __ __ _ _ __ ___ / ___|___ _ _ _ __ | |_ ___ _ __ //
// | |_) | '__/ _ \ / _` | '__/ _` | '_ ` _ \ | | / _ \| | | | '_ \| __/ _ \ '__| //
// | __/| | | (_) | (_| | | | (_| | | | | | | | |__| (_) | |_| | | | | || __/ | //
// |_| |_| \___/ \__, |_| \__,_|_| |_| |_| \____\___/ \__,_|_| |_|\__\___|_| //
// |___/ //
///////////////////////////////////////////////////////////////////////////////////////
// to instruction fetch pc mux
//assign pc_from_immediate_o = immediate26_id;
// PC Mux
always_comb
begin : alu_pc_mux
case (alu_pc_mux_sel)
1'b0: current_pc = current_pc_if_i;
1'b1: current_pc = current_pc_id_i;
endcase; // case (alu_pc_mux_sel)
end
// pc_from_regfile fw Mux, similar to operand_b_fw_mux,
// but not allowed to forward data from load/store unit and from the
// pre/post increment and multiplier
always_comb
begin : pc_from_regfile_fw_mux
case (operand_b_fw_mux_sel)
`SEL_FW_EX: pc_from_regfile_fw_o = regfile_alu_wdata_fw_pc_i;
`SEL_FW_WB: pc_from_regfile_fw_o = wdata_reg_i;
//`SEL_REGFILE: pc_from_regfile_fw_o = regfile_data_rb_id;
//default: pc_from_regfile_fw_o = regfile_data_rb_id;
default: pc_from_regfile_fw_o = regfile_alu_wdata_fw_pc_i;
endcase; // case (operand_b_fw_mux_sel)
end
/*
// hwloop_cnt_mux
always_comb
begin : hwloop_cnt_mux
case (hwloop_cnt_mux_sel)
2'b00: hwloop_cnt = 32'b0;
2'b01: hwloop_cnt = immediate21z_id;
2'b10: hwloop_cnt = immediate13z_id;
2'b11: hwloop_cnt = operand_a_fw_id;
endcase; // case (hwloop_cnt_mux_sel)
end
*/
////////////////////////////////////////////////////////
// ___ _ _ //
// / _ \ _ __ ___ _ __ __ _ _ __ __| | / \ //
// | | | | '_ \ / _ \ '__/ _` | '_ \ / _` | / _ \ //
// | |_| | |_) | __/ | | (_| | | | | (_| | / ___ \ //
// \___/| .__/ \___|_| \__,_|_| |_|\__,_| /_/ \_\ //
// |_| //
////////////////////////////////////////////////////////
// ALU_Op_a Mux
always_comb
begin : alu_operand_a_mux
case (alu_op_a_mux_sel)
default: alu_operand_a = operand_a_fw_id;
`OP_A_REGA_OR_FWD: alu_operand_a = operand_a_fw_id;
`OP_A_CURRPC: alu_operand_a = current_pc;
`OP_A_ZERO: alu_operand_a = 32'b0;
//`OP_A_IMM16: alu_operand_a = immediate16_id;
endcase; // case (alu_op_a_mux_sel)
end
// Operand a forwarding mux
always_comb
begin : operand_a_fw_mux
case (operand_a_fw_mux_sel)
`SEL_FW_EX: operand_a_fw_id = regfile_alu_wdata_fw_i;
`SEL_FW_WB: operand_a_fw_id = regfile_wdata_wb_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
//////////////////////////////////////////////////////
// ___ _ ____ //
// / _ \ _ __ ___ _ __ __ _ _ __ __| | | __ ) //
// | | | | '_ \ / _ \ '__/ _` | '_ \ / _` | | _ \ //
// | |_| | |_) | __/ | | (_| | | | | (_| | | |_) | //
// \___/| .__/ \___|_| \__,_|_| |_|\__,_| |____/ //
// |_| //
//////////////////////////////////////////////////////
// Immediate Mux for operand B
always_comb
begin : immediate_mux
case (immediate_mux_sel)
default: immediate_b = 32'h4;
//`IMM_VEC: immediate_b = immediate_vec_id;
`IMM_I: immediate_b = imm_i_type;
`IMM_S: immediate_b = imm_s_type;
//`IMM_SB: immediate_b = imm_sb_type;
`IMM_U: immediate_b = imm_u_type;
`IMM_UJ: immediate_b = imm_uj_type;
endcase; // case (immediate_mux_sel)
end
// ALU_Op_b Mux
always_comb
begin : alu_operand_b_mux
case (alu_op_b_mux_sel)
default: operand_b = operand_b_fw_id;
`OP_B_REGB_OR_FWD: operand_b = operand_b_fw_id;
//`OP_B_REGC_OR_FWD: operand_b = alu_operand_c;
`OP_B_IMM: operand_b = immediate_b;
endcase // case (alu_op_b_mux_sel)
end
// scalar replication for operand B
//assign operand_b_vec = (vector_mode == `VEC_MODE8) ? {4{operand_b[7:0]}} : {2{operand_b[15:0]}};
// choose normal or scalar replicated version of operand b
assign alu_operand_b = (scalar_replication == 1'b1) ? operand_b_vec : operand_b;
// Operand b forwarding mux
always_comb
begin : operand_b_fw_mux
case (operand_b_fw_mux_sel)
`SEL_FW_EX: operand_b_fw_id = regfile_alu_wdata_fw_i;
`SEL_FW_WB: operand_b_fw_id = regfile_wdata_wb_i;
`SEL_REGFILE: operand_b_fw_id = regfile_data_rb_id;
default: operand_b_fw_id = regfile_data_rb_id;
endcase; // case (operand_b_fw_mux_sel)
end
//////////////////////////////////////////////////////
// ___ _ ____ //
// / _ \ _ __ ___ _ __ __ _ _ __ __| | / ___| //
// | | | | '_ \ / _ \ '__/ _` | '_ \ / _` | | | //
// | |_| | |_) | __/ | | (_| | | | | (_| | | |___ //
// \___/| .__/ \___|_| \__,_|_| |_|\__,_| \____| //
// |_| //
//////////////////////////////////////////////////////
// Operand c forwarding mux
always_comb
begin : operand_c_fw_mux
case (operand_c_fw_mux_sel)
`SEL_FW_EX: alu_operand_c = regfile_alu_wdata_fw_i;
`SEL_FW_WB: alu_operand_c = regfile_wdata_wb_i;
`SEL_REGFILE: alu_operand_c = regfile_data_rc_id;
default: alu_operand_c = regfile_data_rc_id;
endcase; // case (operand_b_fw_mux_sel)
end
/////////////////////////////////////////////////////////
// ____ _____ ____ ___ ____ _____ _____ ____ ____ //
// | _ \| ____/ ___|_ _/ ___|_ _| ____| _ \/ ___| //
// | |_) | _|| | _ | |\___ \ | | | _| | |_) \___ \ //
// | _ <| |__| |_| || | ___) || | | |___| _ < ___) | //
// |_| \_\_____\____|___|____/ |_| |_____|_| \_\____/ //
// //
/////////////////////////////////////////////////////////
riscv_register_file registers_i
(
.clk ( clk ),
.rst_n ( rst_n ),
// Read port a
.raddr_a_i ( (dbg_reg_mux_i == 1'b0) ? regfile_addr_ra_id : dbg_reg_addr_i ),
.rdata_a_o ( regfile_data_ra_id ),
// Read port b
.raddr_b_i ( regfile_addr_rb_id ),
.rdata_b_o ( regfile_data_rb_id ),
// Read port c
.raddr_c_i ( regfile_addr_rc_id ),
.rdata_c_o ( regfile_data_rc_id ),
// Write port a
.waddr_a_i ( regfile_waddr_wb_i ),
.wdata_a_i ( regfile_wdata_wb_i ),
.we_a_i ( regfile_we_wb_i ),
// Write port b
.waddr_b_i ( (dbg_reg_mux_i == 1'b0) ? regfile_alu_waddr_fw_i : dbg_reg_addr_i ),
.wdata_b_i ( (dbg_reg_mux_i == 1'b0) ? regfile_alu_wdata_fw_i : dbg_reg_wdata_i ),
.we_b_i ( (dbg_reg_mux_i == 1'b0) ? regfile_alu_we_fw_i : dbg_reg_we_i )
);
assign dbg_reg_rdata_o = regfile_data_ra_id;
////////////////////////////////////////////////////////////////////
// ____ ___ _ _ _____ ____ ___ _ _ _____ ____ //
// / ___/ _ \| \ | |_ _| _ \ / _ \| | | | | ____| _ \ //
// | | | | | | \| | | | | |_) | | | | | | | | _| | |_) | //
// | |__| |_| | |\ | | | | _ <| |_| | |___| |___| |___| _ < //
// \____\___/|_| \_| |_| |_| \_\\___/|_____|_____|_____|_| \_\ //
// //
////////////////////////////////////////////////////////////////////
controller controller_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.fetch_enable_i ( fetch_enable_i ),
.eoc_o ( eoc ),
.core_busy_o ( core_busy_o ),
// Signal from-to PC pipe (instr rdata) and instr mem system (req and ack)
.instr_rdata_i ( instr_rdata_i ),
.instr_req_o ( instr_req_o ),
.instr_gnt_i ( instr_gnt_i ),
.instr_ack_i ( instr_ack_i ),
.pc_mux_sel_o ( pc_mux_sel_int ),
.pc_mux_boot_o ( pc_mux_boot_o ),
// Alu signals
.alu_operator_o ( alu_operator ),
.extend_immediate_o ( imm_sign_ext_sel ),
.alu_op_a_mux_sel_o ( alu_op_a_mux_sel ),
.alu_op_b_mux_sel_o ( alu_op_b_mux_sel ),
.alu_pc_mux_sel_o ( alu_pc_mux_sel ),
.immediate_mux_sel_o ( immediate_mux_sel ),
.scalar_replication_o ( scalar_replication ),
.vector_mode_o ( vector_mode ),
.alu_cmp_mode_o ( alu_cmp_mode ),
// mult signals
.mult_is_running_o ( mult_is_running ),
.mult_is_running_ex_i ( mult_is_running_ex_o ),
.mult_sel_subword_o ( mult_sel_subword ),
.mult_signed_mode_o ( mult_signed_mode ),
.mult_use_carry_o ( mult_use_carry ),
.mult_mac_en_o ( mult_mac_en ),
// Register file control signals
.regfile_wdata_mux_sel_o ( regfile_wdata_mux_sel ),
.regfile_wdata_mux_sel_ex_i ( regfile_wdata_mux_sel_ex_o ),
.regfile_we_o ( regfile_we_id ),
.regfile_alu_we_o ( regfile_alu_we_id ),
.regfile_alu_waddr_mux_sel_o ( regfile_alu_waddr_mux_sel ),
.prepost_useincr_o ( prepost_useincr ),
.data_misaligned_i ( data_misaligned_i ),
// SP register signals
.sp_we_o ( sp_we_id ),
.sp_we_ex_i ( sp_we_ex_o ),
// Data bus interface
.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_req_o ( data_req_id ),
.data_ack_i ( data_ack_i ),
.data_req_ex_i ( data_req_ex_o ),
.data_rvalid_i ( data_rvalid_i ),
// hwloop signals
.hwloop_we_o ( hwloop_we ),
.hwloop_regid_o ( hwloop_regid ),
.hwloop_wb_mux_sel_o ( hwloop_wb_mux_sel ),
.hwloop_cnt_mux_sel_o ( hwloop_cnt_mux_sel ),
.hwloop_jump_i ( hwloop_jump ),
// Interrupt signals
.irq_present_i ( irq_present ),
// Exception Controller Signals
.jump_in_id_o ( jump_in_id ),
.illegal_insn_o ( illegal_insn ),
.trap_insn_o ( trap_insn ),
.pipe_flush_o ( pipe_flush ),
.pc_valid_i ( pc_valid ),
.clear_isr_running_o ( clear_isr_running ),
.pipe_flushed_i ( pipe_flushed_o ),
// Debug Unit Signals
.dbg_stall_i ( dbg_stall_i ),
.dbg_set_npc_i ( dbg_set_npc_i ),
// SPR Signals
.sr_flag_fw_i ( sr_flag_fw_i ), // Forwarded Branch Signal
.sr_flag_i ( sr_flag_i ),
.set_flag_ex_i ( set_flag_ex_o ),
.set_flag_o ( set_flag ),
.set_overflow_o ( set_overflow ),
.set_carry_o ( set_carry ),
.restore_sr_o ( restore_sr_o ),
// regfile port 1
.regfile_waddr_ex_i ( regfile_waddr_ex_o ), // Write address for register file from ex-wb- pipeline registers
.regfile_we_ex_i ( regfile_we_ex_o ),
.regfile_waddr_wb_i ( regfile_waddr_wb_i ), // Write address for register file from ex-wb- pipeline registers
.regfile_we_wb_i ( regfile_we_wb_i ),
// regfile port 2
.regfile_alu_waddr_fw_i ( regfile_alu_waddr_fw_i ),
.regfile_alu_we_fw_i ( regfile_alu_we_fw_i ),
// Forwarding signals
.operand_a_fw_mux_sel_o ( operand_a_fw_mux_sel ),
.operand_b_fw_mux_sel_o ( operand_b_fw_mux_sel ),
.operand_c_fw_mux_sel_o ( operand_c_fw_mux_sel ),
// branch prediction
.drop_instruction_o ( drop_instruction_o ),
`ifdef BRANCH_PREDICTION
.wrong_branch_taken_o ( wrong_branch_taken_o ),
.take_branch_o ( take_branch_o ),
`endif
// Stall signals
.stall_if_o ( stall_if_o ),
.stall_id_o ( stall_id_o ),
.stall_ex_o ( stall_ex_o ),
.stall_wb_o ( stall_wb_o )
);
///////////////////////////////////////////////////////////////////////
// _____ ____ _ _ _ //
// | ____|_ _____ / ___|___ _ __ | |_ _ __ ___ | | | ___ _ __ //
// | _| \ \/ / __| | | / _ \| '_ \| __| '__/ _ \| | |/ _ \ '__| //
// | |___ > < (__ _ | |__| (_) | | | | |_| | | (_) | | | __/ | //
// |_____/_/\_\___(_) \____\___/|_| |_|\__|_| \___/|_|_|\___|_| //
// //
///////////////////////////////////////////////////////////////////////
assign force_nop_o = 1'b0;
/*
exc_controller exc_controller_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.fetch_enable_i ( fetch_enable_i ),
// to IF stage
.exc_pc_sel_o ( exc_pc_sel ),
.exc_pc_mux_o ( exc_pc_mux_o ),
.force_nop_o ( force_nop_o ),
// hwloop signals
.hwloop_enable_o ( hwloop_enable ),
// Interrupt signals
.irq_i ( irq_i ),
.irq_nm_i ( irq_nm_i ),
.irq_enable_i ( irq_enable_i ),
.irq_present_o ( irq_present ),
// SPR
.save_pc_if_o ( save_pc_if_o ),
.save_pc_id_o ( save_pc_id_o ),
.save_sr_o ( save_sr_o ),
.set_dsx_o ( set_dsx_o ),
// Controller
.core_busy_i ( core_busy_o ),
.jump_in_id_i ( jump_in_id ),
.jump_in_ex_i ( jump_in_ex ),
.stall_id_i ( stall_id_o ),
.illegal_insn_i ( illegal_insn ),
.trap_insn_i ( trap_insn ),
.pipe_flush_i ( pipe_flush ),
.pc_valid_o ( pc_valid ),
.clear_isr_running_i ( clear_isr_running ),
// Debug Unit Signals
.dbg_flush_pipe_i ( dbg_flush_pipe_i ),
.pipe_flushed_o ( pipe_flushed_o ),
.dbg_st_en_i ( dbg_st_en_i ),
.dbg_dsr_i ( dbg_dsr_i ),
.dbg_stall_i ( dbg_stall_i ),
.dbg_set_npc_i ( dbg_set_npc_i ),
.dbg_trap_o ( dbg_trap_o )
);
*/
//////////////////////////////////////////////////////////////////////////
// ____ ___ _ _ _____ ____ ___ _ _ _____ ____ //
// / ___/ _ \| \ | |_ _| _ \ / _ \| | | | | ____| _ \ //
// HWLOOP-| | | | | | \| | | | | |_) | | | | | | | | _| | |_) | //
// | |__| |_| | |\ | | | | _ <| |_| | |___| |___| |___| _ < //
// \____\___/|_| \_| |_| |_| \_\\___/|_____|_____|_____|_| \_\ //
// //
//////////////////////////////////////////////////////////////////////////
/*
hwloop_controller hwloop_controller_i
(
// from ID stage
.enable_i ( hwloop_enable ),
.current_pc_i ( current_pc_if_i ),
// to ID controller
.hwloop_jump_o ( hwloop_jump ),
// to if stage
.hwloop_targ_addr_o ( hwloop_targ_addr_o ),
// from hwloop_regs
.hwloop_start_addr_i ( hwloop_start_addr_i ),
.hwloop_end_addr_i ( hwloop_end_addr_i ),
.hwloop_counter_i ( hwloop_counter_i ),
// to hwloop_regs
.hwloop_dec_cnt_o ( hwloop_dec_cnt_o )
);
*/
/////////////////////////////////////////////////////////////////////////////////
// ___ ____ _______ __ ____ ___ ____ _____ _ ___ _ _ _____ //
// |_ _| _ \ | ____\ \/ / | _ \_ _| _ \| ____| | |_ _| \ | | ____| //
// | || | | |_____| _| \ / | |_) | || |_) | _| | | | || \| | _| //
// | || |_| |_____| |___ / \ | __/| || __/| |___| |___ | || |\ | |___ //
// |___|____/ |_____/_/\_\ |_| |___|_| |_____|_____|___|_| \_|_____| //
// //
/////////////////////////////////////////////////////////////////////////////////
always_ff @(posedge clk, negedge rst_n)
begin : ID_EX_PIPE_REGISTERS
if (rst_n == 1'b0)
begin
regfile_rb_data_ex_o <= 32'h0000_0000;
alu_operator_ex_o <= `ALU_NOP;
alu_operand_a_ex_o <= 32'h0000_0000;
alu_operand_b_ex_o <= 32'h0000_0000;
alu_operand_c_ex_o <= 32'h0000_0000;
vector_mode_ex_o <= `VEC_MODE32;
alu_cmp_mode_ex_o <= `ALU_CMP_FULL;
alu_vec_ext_ex_o <= 2'h0;
mult_is_running_ex_o <= 1'b0;
mult_sel_subword_ex_o <= 2'b0;
mult_signed_mode_ex_o <= 2'b0;
mult_use_carry_ex_o <= 1'b0;
mult_mac_en_ex_o <= 1'b0;
regfile_waddr_ex_o <= 5'b0;
regfile_wdata_mux_sel_ex_o <= 1'b0;
regfile_we_ex_o <= 1'b0;
regfile_alu_waddr_ex_o <= 4'b0;
regfile_alu_we_ex_o <= 1'b0;
prepost_useincr_ex_o <= 1'b0;
sp_we_ex_o <= 1'b0;
data_we_ex_o <= 1'b0;
data_type_ex_o <= 2'b0;
data_sign_ext_ex_o <= 1'b0;
data_reg_offset_ex_o <= 2'b0;
data_req_ex_o <= 1'b0;
data_misaligned_ex_o <= 1'b0;
set_flag_ex_o <= 1'b0;
set_overflow_ex_o <= 1'b0;
set_carry_ex_o <= 1'b0;
hwloop_we_ex_o <= 3'b0;
hwloop_regid_ex_o <= 2'b0;
hwloop_wb_mux_sel_ex_o <= 1'b0;
hwloop_cnt_o <= 32'b0;
jump_in_ex <= 1'b0;
eoc_ex_o <= 1'b0;
`ifdef TCDM_ADDR_PRECAL
alu_adder_o <= '0;
`endif
end
else if ((stall_ex_o == 1'b0) && (data_misaligned_i == 1'b1))
begin // misaligned access case, only unstall alu operands
// if we are using post increments, then we have to use the
// original value of the register for the second memory access
// => keep it stalled
if (prepost_useincr_ex_o == 1'b1)
begin
alu_operand_a_ex_o <= alu_operand_a;
end
alu_operand_b_ex_o <= alu_operand_b;
regfile_alu_we_ex_o <= regfile_alu_we_id;
prepost_useincr_ex_o <= prepost_useincr;
data_misaligned_ex_o <= 1'b1;
end
else if ((stall_ex_o == 1'b0) && (data_misaligned_i == 1'b0))
begin // unstall the whole pipeline
regfile_rb_data_ex_o <= operand_b_fw_id;
alu_operator_ex_o <= alu_operator;
alu_operand_a_ex_o <= alu_operand_a;
alu_operand_b_ex_o <= alu_operand_b;
alu_operand_c_ex_o <= alu_operand_c;
vector_mode_ex_o <= vector_mode;
alu_cmp_mode_ex_o <= alu_cmp_mode;
alu_vec_ext_ex_o <= alu_vec_ext;
mult_is_running_ex_o <= mult_is_running;
mult_sel_subword_ex_o <= mult_sel_subword;
mult_signed_mode_ex_o <= mult_signed_mode;
mult_use_carry_ex_o <= mult_use_carry;
mult_mac_en_ex_o <= mult_mac_en;
regfile_waddr_ex_o <= regfile_waddr_id;
regfile_wdata_mux_sel_ex_o <= regfile_wdata_mux_sel;
regfile_we_ex_o <= regfile_we_id;
regfile_alu_waddr_ex_o <= regfile_alu_waddr_id;
regfile_alu_we_ex_o <= regfile_alu_we_id;
prepost_useincr_ex_o <= prepost_useincr;
sp_we_ex_o <= sp_we_id;
data_we_ex_o <= data_we_id;
data_type_ex_o <= data_type_id;
data_sign_ext_ex_o <= data_sign_ext_id;
data_reg_offset_ex_o <= data_reg_offset_id;
data_req_ex_o <= data_req_id;
data_misaligned_ex_o <= 1'b0;
set_flag_ex_o <= set_flag;
set_overflow_ex_o <= set_overflow;
set_carry_ex_o <= set_carry;
hwloop_we_ex_o <= hwloop_we;
hwloop_regid_ex_o <= hwloop_regid;
hwloop_wb_mux_sel_ex_o <= hwloop_wb_mux_sel;
hwloop_cnt_o <= hwloop_cnt;
jump_in_ex <= jump_in_id;
eoc_ex_o <= eoc;
`ifdef TCDM_ADDR_PRECAL
alu_adder_o <= alu_operand_a + alu_operand_b;
`endif
end
end
endmodule

198
if_stage.sv Normal file
View file

@ -0,0 +1,198 @@
////////////////////////////////////////////////////////////////////////////////
// Company: IIS @ ETHZ - Federal Institute of Technology //
// DEI @ UNIBO - University of Bologna //
// //
// Engineer: Renzo Andri - andrire@student.ethz.ch //
// //
// Additional contributions by: //
// Igor Loi - igor.loi@unibo.it //
// Andreas Traber - atraber@student.ethz.ch //
// //
// //
// Create Date: 01/07/2014 //
// Design Name: Instruction fetch stage //
// Module Name: if_stage.sv //
// Project Name: RiscV //
// Language: SystemVerilog //
// //
// Description: Instruction fetch unit: Selection of the next PC, and //
// buffering (Sampling) of the read instruction //
// Revision: //
// Revision v0.1 - File Created //
// Revision v0.2 - (August 6th 2014) Changed port and signal names, addedd //
// comments //
// Revision v0.3 - (December 1th 2014) Merged debug unit and added more //
// exceptions //
// //
// //
////////////////////////////////////////////////////////////////////////////////
`include "defines.sv"
module 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,
// Output of IF Pipeline stage
output logic [31:0] instr_rdata_id_o, // read instruction is sampled and sent to ID stage for decoding
output logic [31:0] current_pc_if_o, // current pc program counter
output logic [31:0] current_pc_id_o, // current pc program counter
// From to Instr memory
input logic [31:0] instr_rdata_i, // Instruction read from instruction memory /cache
output logic [31:0] instr_addr_o, // address for instruction fetch
// Forwarding ports - control signals
input logic force_nop_i, // insert a NOP in the pipe
input logic [31:0] exception_pc_reg_i, // address used to restore the program counter when the interrupt/exception is served
input logic [31:0] pc_from_regfile_i, // pc from reg file
input logic [31:0] pc_from_immediate_i, // pc from immediate
input logic [31:0] pc_from_hwloop_i, // pc from hwloop start addr
input logic [2:0] pc_mux_sel_i, // sel for pc multiplexer
input logic pc_mux_boot_i, // load boot address as PC
input logic [1:0] exc_pc_mux_i, // select which exception to execute
// from debug unit
input logic [31:0] dbg_pc_from_npc,
input logic dbg_set_npc,
// branch prediction
input logic drop_instruction_i,
`ifdef BRANCH_PREDICTION
input logic wrong_branch_taken_i,
input logic take_branch_i,
`endif
// pipeline stall
input logic stall_if_i,
input logic stall_id_i // Stall in the id stage: here (if_stage) freeze the registers
);
////////////////////////////////////
// Instruction Fetch (IF) signals //
////////////////////////////////////
logic [31:0] next_pc; // Next program counter
logic [31:0] exc_pc; // Exception PC
logic [31:0] instr_rdata_int; // The instruction read from instr memory/cache is forwarded to ID stage, and the controller can force this forwarding to a nop (BUBBLE)
`ifdef BRANCH_PREDICTION
logic [31:0] correct_branch;
`endif
logic [31:0] branch_taken;
logic [31:0] branch_not_taken;
// Address to fetch the instruction
assign instr_addr_o = next_pc;
assign branch_taken = current_pc_id_o + pc_from_immediate_i;
assign branch_not_taken = current_pc_if_o + 32'd4;
// Next PC Selection: pc_mux_sel_i comes from id_stage.controller
always_comb
begin : PC_MUX
case (pc_mux_sel_i)
`INCR_PC: begin next_pc = current_pc_if_o + 32'd4; end // PC is incremented and points the next instruction
`NO_INCR: begin next_pc = current_pc_if_o; end // PC is not incremented
`PC_FROM_REGFILE: begin next_pc = pc_from_regfile_i; end // PC is taken from the regfile
`PC_FROM_IMM: begin next_pc = branch_taken; end // PC is taken from current PC in id + the immediate displacement
`PC_EXCEPTION: begin next_pc = exc_pc; end // PC that points to the exception
`EXC_PC_REG: begin next_pc = exception_pc_reg_i; end // restore the PC when exiting from interr/ecpetions
`HWLOOP_ADDR: begin next_pc = pc_from_hwloop_i; end // PC is taken from hwloop start addr
`ifdef BRANCH_PREDICTION
`PC_BRANCH_PRED: begin next_pc = correct_branch; end // take pc from branch prediction
`endif
default: begin next_pc = current_pc_if_o + 32'd4; end
endcase //~case (pc_mux_sel_i)
end
// Exception PC selection
always_comb
begin : EXC_PC_MUX
case (exc_pc_mux_i)
`EXC_PC_IRQ: begin exc_pc = {boot_addr_i[31:8], `EXC_IRQ }; end
`EXC_PC_IRQ_NM: begin exc_pc = {boot_addr_i[31:8], `EXC_IRQ_NM }; end
`EXC_PC_ILLINSN: begin exc_pc = {boot_addr_i[31:8], `EXC_ILLINSN}; end
`EXC_PC_NO_INCR: begin exc_pc = current_pc_if_o; end
endcase //~case (exc_pc_mux_i)
end
// NOP = addi x0, x0, 0
assign instr_rdata_int = (force_nop_i == 1'b1) ? { {25 {1'b0}}, `OPCODE_OPIMM } : instr_rdata_i;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IF PC register //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
always_ff @(posedge clk, negedge rst_n)
begin : IF_PIPELINE
if (rst_n == 1'b0)
begin : ASSERT_RESET
current_pc_if_o <= 32'h0;
end
else
begin : DEASSERT_RESET
if ( pc_mux_boot_i == 1'b1 )
begin
// set PC to boot address if we were just reset
current_pc_if_o <= boot_addr_i;
end
else if ( dbg_set_npc == 1'b1 )
begin
// debug units sets NPC, PC_MUX_SEL holds this value
current_pc_if_o <= dbg_pc_from_npc;
end
else if ( stall_if_i == 1'b0 )
begin : ENABLED_PIPE
current_pc_if_o <= next_pc;
end
end
end
`ifdef BRANCH_PREDICTION
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Save branch targets in case of a misprediction //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
always_ff @(posedge clk, negedge rst_n)
begin : SAVE_BRANCH_TARGET
if (rst_n == 1'b0)
begin : ASSERT_RESET
correct_branch <= 32'b0;
end
else
begin : DEASSERT_RESET
if (wrong_branch_taken_i)
correct_branch <= (take_branch_i) ? branch_taken : branch_not_taken;
end
end
`endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IF-ID PIPE: Pipeline that is 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 : ASSERT_RESET
instr_rdata_id_o <= '0;
current_pc_id_o <= '0;
end
else
begin : DEASSERT_RESET
if((stall_id_i == 1'b0) & (drop_instruction_i == 1'b0))
begin : ENABLED_PIPE
instr_rdata_id_o <= instr_rdata_int;
current_pc_id_o <= current_pc_if_o;
end
end
end
endmodule

376
include/defines.sv Normal file
View file

@ -0,0 +1,376 @@
////////////////////////////////////////////////////////////////////////////////
// Company: IIS @ ETHZ - Federal Institute of Technology //
// //
// Engineer: Matthias Baer - baermatt@student.ethz.ch //
// //
// Additional contributions by: //
// //
// //
// //
// Create Date: 19/09/2013 //
// Design Name: Pipelined Processor //
// Module Name: defines.sv //
// Project Name: Processor //
// Language: SystemVerilog //
// //
// Description: Defines for the the pipelined processor //
// //
// //
// Revision: //
// Revision v0.1 - File Created //
// //
// //
// //
// //
// //
// //
////////////////////////////////////////////////////////////////////////////////
// BTW: If you want to create more of those fancy ASCII art comments:
// http://patorjk.com/software/taag/#p=display&v=0&f=Standard&t=Fancy%20ASCII%20Art
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////
// ___ ____ _ //
// / _ \ _ __ / ___|___ __| | ___ ___ //
// | | | | '_ \| | / _ \ / _` |/ _ \/ __| //
// | |_| | |_) | |__| (_) | (_| | __/\__ \ //
// \___/| .__/ \____\___/ \__,_|\___||___/ //
// |_| //
////////////////////////////////////////////////
/*
`define OPCODE_J 6'h00
`define OPCODE_JAL 6'h01
`define OPCODE_HWLOOP 6'h02
`define OPCODE_BNF 6'h03
`define OPCODE_BF 6'h04
`define OPCODE_NOP 6'h05
`define OPCODE_MOVHI 6'h06 // also used for l.macrc
`define OPCODE_SYNC 6'h08 // also used for l.trap
`define OPCODE_RFE 6'h09
`define OPCODE_VEC 6'h0a // vectorial instructions
`define OPCODE_VCMP 6'h0b // vectorial compare instructions
`define OPCODE_JR 6'h11
`define OPCODE_JALR 6'h12
`define OPCODE_MACI 6'h13
`define OPCODE_EOC 6'h1c // l.eoc = l.cust1
`define OPCODE_STPOST 6'h14 // ST post-increment
`define OPCODE_STPRE 6'h15 // ST pre-increment
`define OPCODE_LDPOST 6'h16 // LD post-increment
`define OPCODE_LDPRE 6'h17 // LD pre-increment
`define OPCODE_LWZ 6'h21
`define OPCODE_LWS 6'h22
`define OPCODE_LBZ 6'h23
`define OPCODE_LBS 6'h24
`define OPCODE_LHZ 6'h25
`define OPCODE_LHS 6'h26
`define OPCODE_ADDI 6'h27
`define OPCODE_ADDIC 6'h28
`define OPCODE_ANDI 6'h29
`define OPCODE_ORI 6'h2a
`define OPCODE_XORI 6'h2b
`define OPCODE_MULI 6'h2c
`define OPCODE_MFSPR 6'h2d
`define OPCODE_SHIFT 6'h2e
`define OPCODE_SFI 6'h2f
`define OPCODE_MTSPR 6'h30
`define OPCODE_MAC 6'h31
`define OPCODE_SW 6'h35
`define OPCODE_SB 6'h36
`define OPCODE_SH 6'h37
`define OPCODE_ALU 6'h38
`define OPCODE_SF 6'h39
*/
`define OPCODE_SYSTEM 7'h73
`define OPCODE_FENCE 7'h0f
`define OPCODE_OP 7'h33
`define OPCODE_OPIMM 7'h13
`define OPCODE_STORE 7'h23
`define OPCODE_LOAD 7'h03
`define OPCODE_BRANCH 7'h63
`define OPCODE_JALR 7'h67
`define OPCODE_JAL 7'h6f
`define OPCODE_AUIPC 7'h17
`define OPCODE_LUI 7'h37
`define INSTR_LUI { {25 {1'b?}}, `OPCODE_LUI }
`define INSTR_AUIPC { {25 {1'b?}}, `OPCODE_AUIPC }
`define INSTR_JAL { {25 {1'b?}}, `OPCODE_JAL }
`define INSTR_JALR { {17 {1'b?}}, 3'b000, {5 {1'b?}}, `OPCODE_JALR }
// BRANCH
`define INSTR_BEQ { {17 {1'b?}}, 3'b000, {5 {1'b?}}, `OPCODE_BRANCH }
`define INSTR_BNE { {17 {1'b?}}, 3'b001, {5 {1'b?}}, `OPCODE_BRANCH }
`define INSTR_BLT { {17 {1'b?}}, 3'b100, {5 {1'b?}}, `OPCODE_BRANCH }
`define INSTR_BGE { {17 {1'b?}}, 3'b101, {5 {1'b?}}, `OPCODE_BRANCH }
`define INSTR_BLTU { {17 {1'b?}}, 3'b110, {5 {1'b?}}, `OPCODE_BRANCH }
`define INSTR_BGEU { {17 {1'b?}}, 3'b111, {5 {1'b?}}, `OPCODE_BRANCH }
// LOAD
`define INSTR_LB { {17 {1'b?}}, 3'b000, {5 {1'b?}}, `OPCODE_LOAD }
`define INSTR_LH { {17 {1'b?}}, 3'b001, {5 {1'b?}}, `OPCODE_LOAD }
`define INSTR_LW { {17 {1'b?}}, 3'b010, {5 {1'b?}}, `OPCODE_LOAD }
`define INSTR_LBU { {17 {1'b?}}, 3'b100, {5 {1'b?}}, `OPCODE_LOAD }
`define INSTR_LHU { {17 {1'b?}}, 3'b101, {5 {1'b?}}, `OPCODE_LOAD }
// STORE
`define INSTR_SB { {17 {1'b?}}, 3'b000, {5 {1'b?}}, `OPCODE_STORE }
`define INSTR_SH { {17 {1'b?}}, 3'b001, {5 {1'b?}}, `OPCODE_STORE }
`define INSTR_SW { {17 {1'b?}}, 3'b010, {5 {1'b?}}, `OPCODE_STORE }
// OPIMM
`define INSTR_ADDI { {17 {1'b?}}, 3'b000, {5 {1'b?}}, `OPCODE_OPIMM }
`define INSTR_SLTI { {17 {1'b?}}, 3'b010, {5 {1'b?}}, `OPCODE_OPIMM }
`define INSTR_SLTIU { {17 {1'b?}}, 3'b011, {5 {1'b?}}, `OPCODE_OPIMM }
`define INSTR_XORI { {17 {1'b?}}, 3'b100, {5 {1'b?}}, `OPCODE_OPIMM }
`define INSTR_ORI { {17 {1'b?}}, 3'b110, {5 {1'b?}}, `OPCODE_OPIMM }
`define INSTR_ANDI { {17 {1'b?}}, 3'b111, {5 {1'b?}}, `OPCODE_OPIMM }
`define INSTR_SLLI { 7'b0000000, {10 {1'b?}}, 3'b001, {5 {1'b?}}, `OPCODE_OPIMM }
`define INSTR_SRLI { 7'b0000000, {10 {1'b?}}, 3'b101, {5 {1'b?}}, `OPCODE_OPIMM }
`define INSTR_SRAI { 7'b0100000, {10 {1'b?}}, 3'b101, {5 {1'b?}}, `OPCODE_OPIMM }
// OP
`define INSTR_ADD { 7'b0000000, {10 {1'b?}}, 3'b000, {5 {1'b?}}, `OPCODE_OP }
`define INSTR_SUB { 7'b0100000, {10 {1'b?}}, 3'b000, {5 {1'b?}}, `OPCODE_OP }
`define INSTR_SLL { 7'b0000000, {10 {1'b?}}, 3'b001, {5 {1'b?}}, `OPCODE_OP }
`define INSTR_SLT { 7'b0000000, {10 {1'b?}}, 3'b010, {5 {1'b?}}, `OPCODE_OP }
`define INSTR_SLTU { 7'b0000000, {10 {1'b?}}, 3'b011, {5 {1'b?}}, `OPCODE_OP }
`define INSTR_XOR { 7'b0000000, {10 {1'b?}}, 3'b100, {5 {1'b?}}, `OPCODE_OP }
`define INSTR_SRL { 7'b0000000, {10 {1'b?}}, 3'b101, {5 {1'b?}}, `OPCODE_OP }
`define INSTR_SRA { 7'b0100000, {10 {1'b?}}, 3'b101, {5 {1'b?}}, `OPCODE_OP }
`define INSTR_OR { 7'b0000000, {10 {1'b?}}, 3'b110, {5 {1'b?}}, `OPCODE_OP }
`define INSTR_AND { 7'b0000000, {10 {1'b?}}, 3'b111, {5 {1'b?}}, `OPCODE_OP }
// FENCE
`define INSTR_FENCE { 4'b0000, {8 {1'b?}}, {13 {1'b0}}, `OPCODE_FENCE }
`define INSTR_FENCEI { {17 {1'b0}}, 3'b001, {5 {1'b0}}, `OPCODE_FENCE }
// SYSTEM
`define INSTR_SCALL { {11 {1'b0}}, 1'b0, {13 {1'b0}}, `OPCODE_SYSTEM }
`define INSTR_SBREAK { {11 {1'b0}}, 1'b1, {13 {1'b0}}, `OPCODE_SYSTEM }
`define INSTR_RDCYCLE { 5'b11000, {5 {5'b0}}, 2'b00, {5 {1'b0}}, 3'b010, {5 {1'b?}}, `OPCODE_SYSTEM }
`define INSTR_RDCYCLEH { 5'b11001, {5 {5'b0}}, 2'b00, {5 {1'b0}}, 3'b010, {5 {1'b?}}, `OPCODE_SYSTEM }
`define INSTR_RDTIME { 5'b11000, {5 {5'b0}}, 2'b01, {5 {1'b0}}, 3'b010, {5 {1'b?}}, `OPCODE_SYSTEM }
`define INSTR_RDTIMEH { 5'b11001, {5 {5'b0}}, 2'b01, {5 {1'b0}}, 3'b010, {5 {1'b?}}, `OPCODE_SYSTEM }
`define INSTR_RDINSTRET { 5'b11000, {5 {5'b0}}, 2'b10, {5 {1'b0}}, 3'b010, {5 {1'b?}}, `OPCODE_SYSTEM }
`define INSTR_RDINSTRETH { 5'b11001, {5 {5'b0}}, 2'b10, {5 {1'b0}}, 3'b010, {5 {1'b?}}, `OPCODE_SYSTEM }
// RV32M
`define INSTR_MUL { 7'b0000001, {10 {1'b?}}, 3'b000, {5 {1'b?}}, `OPCODE_OP }
`define INSTR_MULH { 7'b0000001, {10 {1'b?}}, 3'b001, {5 {1'b?}}, `OPCODE_OP }
`define INSTR_MULHSU { 7'b0000001, {10 {1'b?}}, 3'b010, {5 {1'b?}}, `OPCODE_OP }
`define INSTR_MULHU { 7'b0000001, {10 {1'b?}}, 3'b011, {5 {1'b?}}, `OPCODE_OP }
/*
`define INSTR_DIV { 7'b0000001, {10 {1'b?}}, 3'b100, {5 {1'b?}}, `OPCODE_OP }
`define INSTR_DIVU { 7'b0000001, {10 {1'b?}}, 3'b101, {5 {1'b?}}, `OPCODE_OP }
`define INSTR_REM { 7'b0000001, {10 {1'b?}}, 3'b110, {5 {1'b?}}, `OPCODE_OP }
`define INSTR_REMU { 7'b0000001, {10 {1'b?}}, 3'b111, {5 {1'b?}}, `OPCODE_OP }
*/
//////////////////////////////////////////////////////////////////////////////
// _ _ _ _ ___ _ _ //
// / \ | | | | | | / _ \ _ __ ___ _ __ __ _| |_(_) ___ _ __ ___ //
// / _ \ | | | | | | | | | | '_ \ / _ \ '__/ _` | __| |/ _ \| '_ \/ __| //
// / ___ \| |__| |_| | | |_| | |_) | __/ | | (_| | |_| | (_) | | | \__ \ //
// /_/ \_\_____\___/ \___/| .__/ \___|_| \__,_|\__|_|\___/|_| |_|___/ //
// |_| //
//////////////////////////////////////////////////////////////////////////////
`define ALU_OP_WIDTH 6
// Movhi Operation
`define ALU_MOVHI 6'b001111
// Standard Operations
`define ALU_ADD 6'b000_000
`define ALU_ADDC 6'b000_001
`define ALU_SUB 6'b000_010
`define ALU_AND 6'b000_011
`define ALU_OR 6'b000_100
`define ALU_XOR 6'b000_101
`define ALU_AVG 6'b000_110
`define ALU_AVGU 6'b000_111
// Shift Operations
`define ALU_SLL 6'b0010_00
`define ALU_SRL 6'b0010_01
`define ALU_SRA 6'b0010_10
`define ALU_ROR 6'b0010_11
// Set Lower Than Operations
`define ALU_SLTS 6'b0011_00
`define ALU_SLTU 6'b0011_01
// CMOV operation
`define ALU_CMOV 6'b0011_10
// Extension Operations
`define ALU_EXTHS 6'b010_000
`define ALU_EXTWS 6'b010_001
`define ALU_EXTBS 6'b010_010
`define ALU_EXTWZ 6'b010_011
`define ALU_EXTHZ 6'b010_100
`define ALU_EXTBZ 6'b010_110
// No Operation
`define ALU_NOP 6'b011111
// Comparison Operations
`define ALU_EQ 6'b10_0000
`define ALU_NE 6'b10_0001
`define ALU_GTU 6'b10_0010
`define ALU_GEU 6'b10_0011
`define ALU_LTU 6'b10_0100
`define ALU_LEU 6'b10_0101
`define ALU_GTS 6'b10_1010
`define ALU_GES 6'b10_1011
`define ALU_LTS 6'b10_1100
`define ALU_LES 6'b10_1101
`define ALU_MIN 6'b10_1110
`define ALU_MINU 6'b11_1110
`define ALU_MAX 6'b10_1111
`define ALU_MAXU 6'b11_1111
`define ALU_ABS 6'b11_1010
`define ALU_INS 6'b11_1101
`define ALU_EXT 6'b11_1100
`define ALU_CNT 6'b11_0000
`define ALU_FF1 6'b11_0010
`define ALU_FL1 6'b11_0011
`define ALU_CLB 6'b11_0001
// Vector Mode
`define VEC_MODE32 2'b00
`define VEC_MODE16 2'b10
`define VEC_MODE8 2'b11
`define VEC_MODE216 2'b01
// ALU comparison mode
`define ALU_CMP_FULL 2'b00
`define ALU_CMP_ANY 2'b01
`define ALU_CMP_ALL 2'b10
////////////////////////////////////////////////////////
// ____ ____ ____ _ _ //
// / ___|| _ \ | _ \ ___ __ _(_)___| |_ ___ _ __ //
// \___ \| |_) | | |_) / _ \/ _` | / __| __/ _ \ '__| //
// ___) | __/ | _ < __/ (_| | \__ \ || __/ | //
// |____/|_| |_| \_\___|\__, |_|___/\__\___|_| //
// |___/ //
////////////////////////////////////////////////////////
// Special-Purpose Register Addresses
// see OpenRISC manual p. 22ff
`define SP_NPC 16'h0010
`define SP_SR 16'h0011
`define SP_MACLO 16'h2801 // TODO: remove
`define SP_MACHI 16'h2802 // TODO: remove
`define SP_EPCR 16'd0032
`define SP_ESR 16'd0064
`define SP_DVR0 16'h3000
`define SP_DCR0 16'h3008
`define SP_DMR1 16'h3010
`define SP_DMR2 16'h3011
// Core and Cluster ID are put into the system control and status
// registers group
`define SP_COREID 16'h0680
`define SP_CLUSTERID 16'h0681
`define SP_DVR_MSB 8'h00
`define SP_DCR_MSB 8'h01
`define SP_DMR_MSB 8'h02
`define SP_DSR_MSB 8'h04
// Supervision Register
`define SR_IEE 5'd2
`define SR_F 5'd9
`define SR_CY 5'd10
`define SR_OV 5'd11
`define SR_DSX 5'd13
//igor addon
`define REG_A 20:16
`define REG_B 15:11
// forwarding operand mux
`define SEL_REGFILE 2'b00
`define SEL_FW_EX 2'b01
`define SEL_FW_WB 2'b10
// operand a selection
`define OP_A_REGA_OR_FWD 2'b00
`define OP_A_CURRPC 2'b10
`define OP_A_IMM16 2'b11
`define OP_A_ZERO 2'b11
// operand b selection
`define OP_B_REGB_OR_FWD 2'b00
`define OP_B_REGC_OR_FWD 2'b01
`define OP_B_IMM 2'b10
// immediate selection
// - `define IMM_5N11 4'b0000
// - `define IMM_21S 4'b0001
// - `define IMM_8Z 4'b0010
// - `define IMM_16Z 4'b0011
// - `define IMM_16 4'b0100
// - `define IMM_11S 4'b0101
// - `define IMM_5N6S 4'b0110
// - `define IMM_VEC 4'b0111
// - `define IMM_HEX4 4'b1000
`define IMM_I 3'b000
`define IMM_S 3'b010
`define IMM_SB 3'b011
`define IMM_U 3'b100
`define IMM_UJ 3'b101
// PC mux selector defines
`define INCR_PC 3'b000
`define NO_INCR 3'b001
`define PC_FROM_REGFILE 3'b010
`define PC_FROM_IMM 3'b011
`define PC_EXCEPTION 3'b100
`define EXC_PC_REG 3'b101
`define HWLOOP_ADDR 3'b110
`define PC_BRANCH_PRED 3'b111
// Exception PC mux selector defines
`define EXC_PC_NO_INCR 2'b00
`define EXC_PC_ILLINSN 2'b01
`define EXC_PC_IRQ 2'b10
`define EXC_PC_IRQ_NM 2'b11
// Exceptions offsets
// It is assumed that the lower 8 bits are enough for all exception
// offsets, so the upper 24 bits of the boot address are used and the
// lower 8 bits of the exception offset
`define EXC_ILLINSN 8'h30
`define EXC_IRQ 8'h38
`define EXC_IRQ_NM 8'h70
// Hardware loops addon
`define HWLOOP_REGS 2
// Debug module
`define N_WP 2 // #Watchpoints
`define DCR_DP 0
`define DCR_CC 3:1
`define DCR_SC 4
`define DCR_CT 7:5
`define DMR1_ST 22
`define DMR2_WGB0 12
`define DMR2_WBS0 22
`define DSR_IIE 0
`define DSR_INTE 1
// TCDM_ADDRES PRE CALCULATION --> Bring part of the alu_adder_o calculation in the ID stage
//`define TCDM_ADDR_PRECAL
//`define BRANCH_PREDICTION

280
instr_core_interface.sv Normal file
View file

@ -0,0 +1,280 @@
////////////////////////////////////////////////////////////////////////////////
// Company: IIS @ ETHZ - Federal Institute of Technology //
// DEI @ UNIBO - University of Bologna //
// //
// Engineer: Igor Loi - igor.loi@unibo.it //
// //
// Additional contributions by: //
// //
// //
// Create Date: 06/08/2014 //
// Design Name: Instruction Fetch interface //
// Module Name: instr_core_interface.sv //
// Project Name: OR10N //
// Language: SystemVerilog //
// //
// Description: Instruction Fetch interface used to properly handle //
// cache stalls //
// //
// Revision: //
// Revision v0.1 - File Created //
// //
// //
// //
// //
// //
////////////////////////////////////////////////////////////////////////////////
module instr_core_interface
(
input logic clk,
input logic rst_n,
input logic req_i,
input logic [31:0] addr_i,
output logic ack_o,
output logic [31:0] rdata_o,
output logic instr_req_o,
output logic [31:0] instr_addr_o,
input logic instr_gnt_i,
input logic instr_r_valid_i,
input logic [31:0] instr_r_rdata_i,
input logic stall_if_i,
input logic drop_request_i
);
enum logic [2:0] {IDLE, PENDING, WAIT_RVALID, WAIT_IF_STALL, WAIT_GNT, ABORT} CS, NS;
logic save_rdata;
logic [31:0] rdata_Q;
logic wait_gnt;
logic [31:0] addr_Q;
always_ff @(posedge clk, negedge rst_n)
begin
if(rst_n == 1'b0)
begin
CS <= IDLE;
rdata_Q <= '0;
addr_Q <= '0;
end
else
begin
CS <= NS;
if(wait_gnt)
addr_Q <= addr_i;
if(save_rdata)
rdata_Q <= instr_r_rdata_i;
end
end
always_comb
begin
instr_req_o = 1'b0;
ack_o = 1'b0;
save_rdata = 1'b0;
rdata_o = instr_r_rdata_i;
instr_addr_o = addr_i;
wait_gnt = 1'b0;
case(CS)
IDLE :
begin
instr_req_o = req_i;
ack_o = 1'b0;
rdata_o = rdata_Q;
if(req_i)
begin
if(instr_gnt_i) //~> granted request
NS = PENDING;
else begin //~> got a request but no grant
NS = WAIT_GNT;
wait_gnt = 1'b1;
end
end //~> if(req_i == 0)
else
begin
NS = IDLE;
end
end // case: IDLE
WAIT_GNT :
begin
instr_addr_o = addr_Q;
instr_req_o = 1'b1;
if(instr_gnt_i)
NS = PENDING;
else
begin
// if (drop_request_i)
// NS = IDLE;
// else
NS = WAIT_GNT;
end
end // case: WAIT_GNT
PENDING :
begin
if(instr_r_valid_i)
begin
save_rdata = 1'b1;
ack_o = 1'b1;
if(stall_if_i)
begin
instr_req_o = 1'b0;
NS = WAIT_IF_STALL;
end
else
begin
instr_req_o = req_i;
if(req_i)
begin
if( instr_gnt_i )
begin
NS = PENDING;
end
else
begin
NS = WAIT_GNT;
wait_gnt = 1'b1;
end
end
else
NS = IDLE;
end
end
else
begin
NS = WAIT_RVALID;
instr_req_o = 1'b0;
ack_o = 1'b0;
end
end // case: PENDING
WAIT_RVALID :
begin
if(instr_r_valid_i)
begin
ack_o = 1'b1;
save_rdata = 1'b1;
if(stall_if_i)
begin
instr_req_o = 1'b0;
NS = WAIT_IF_STALL;
end
else
begin
instr_req_o = req_i;
if(req_i)
if(instr_gnt_i)
NS = PENDING;
else begin
NS = WAIT_GNT;
wait_gnt = 1'b1;
end
else
NS = IDLE;
end
end
else
begin
NS = WAIT_RVALID;
ack_o = 1'b0;
instr_req_o = 1'b0;
end
end // case: WAIT_RVALID
WAIT_IF_STALL :
begin
ack_o = 1'b1;
rdata_o = rdata_Q;
if(stall_if_i)
begin
instr_req_o = 1'b0;
NS = WAIT_IF_STALL;
end
else
begin
instr_req_o = req_i;
if(req_i)
if(instr_gnt_i)
NS = PENDING;
else begin
NS = WAIT_GNT;
wait_gnt = 1'b1;
end
else
NS = IDLE;
end
end // case: WAIT_IF_STALL
ABORT:
begin
ack_o = 1'b1;
instr_req_o = 1'b1;
if(req_i)
begin
if(instr_gnt_i) //~> granted request
NS = PENDING;
else begin //~> got a request but no grant
NS = WAIT_GNT;
wait_gnt = 1'b1;
end
end //~> if(req_i == 0)
else
begin
NS = IDLE;
end
end // case: ABORT
default :
begin
NS = IDLE;
instr_req_o = 1'b0;
end
endcase
end
endmodule

507
load_store_unit.sv Normal file
View file

@ -0,0 +1,507 @@
////////////////////////////////////////////////////////////////////////////////
// Company: IIS @ ETHZ - Federal Institute of Technology //
// DEI @ UNIBO - University of Bologna //
// //
// Engineer: Igor Loi - igor.loi@unibo.it //
// //
// Additional contributions by: //
// //
// //
// Create Date: 01/07/2014 //
// Design Name: Load Store Unit //
// Module Name: load_store_unit.sv //
// Project Name: OR10N //
// Language: SystemVerilog //
// //
// Description: Load Store Unit, used to eliminate multiple access during //
// processor stalls, and to align bytes and halfwords //
// //
// Revision: //
// Revision v0.1 - File Created //
// Revision v0.2 - (August 6th 2014) Added stall stupport when ID stage is //
// stalled //
// //
// //
// //
////////////////////////////////////////////////////////////////////////////////
`include "defines.sv"
module load_store_unit
(
input logic clk,
input logic rst_n,
// signals from ex stage
input logic data_we_ex_i, // write enable -> from ex stage
input logic [1:0] data_type_ex_i, // Data type word, halfword, byte -> from ex stage
input logic [31:0] data_wdata_ex_i, // data to write to memory -> from ex stage
input logic data_sign_ext_ex_i, // sign extension -> from ex stage
input logic [1:0] data_reg_offset_ex_i, // offset inside register for stores -> from ex stage
output logic [31:0] data_rdata_ex_o, // requested data -> to ex stage
output logic [31:0] lsu_data_reg_o, // requested data registered -> to id stage
input logic data_req_ex_i, // data request -> from ex stage
input logic [31:0] data_addr_ex_i, // data address -> from ex stage
output logic data_ack_int_o, // data ack -> to controller
input logic data_misaligned_ex_i, // misaligned access in last ld/st -> from ID/EX pipeline
output logic data_misaligned_o, // misaligned access was detected -> to controller
// output to data memory
output logic data_req_o,
output logic [31:0] data_addr_o,
output logic data_we_o,
output logic [3:0] data_be_o,
output logic [31:0] data_wdata_o,
input logic [31:0] data_rdata_i,
input logic data_rvalid_i,
input logic data_gnt_i,
// stall signal
input logic ex_stall_i
);
// registers for data_rdata alignment and sign extension
logic [1:0] data_type_q;
logic [1:0] rdata_offset_q;
logic data_sign_ext_q;
logic [1:0] wdata_offset; // mux control for data to be written to memory
// signals for tcdm contention
logic [3:0] data_be, data_be_q;
logic [31:0] data_wdata, data_wdata_q;
logic data_we_q;
logic [31:0] data_addr_q;
logic misaligned_st; // high if we are currently performing the second part of a misaligned store
logic misaligned_st_q; // register for misaligned_st
logic request_entered;
enum logic [2:0] { IDLE, WAIT_GNT, PENDING_W_EX_STALL_2, PENDING_W_EX_STALL_1, PENDING_WO_EX_STALL} CS, NS;
logic latch_rdata;
logic [31:0] rdata_q;
///////////////////////////////// BE generation ////////////////////////////////
always_comb
begin
casex (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_ex_i[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_ex_i[1:0])
end
else
begin // misaligned case
case (data_addr_ex_i[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_ex_i[1:0])
end
end
2'b01:
begin // Writing a half word
if (misaligned_st == 1'b0)
begin // non-misaligned case
case (data_addr_ex_i[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_ex_i[1:0])
end
else
begin // misaligned case
data_be = 4'b0001;
end
end
2'b1X: begin // Writing a byte
case (data_addr_ex_i[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_ex_i[1:0])
end
endcase; // casex (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_ex_i[1:0] - data_reg_offset_ex_i[1:0];
always_comb
begin
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)
end
// FF for rdata
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;
end
else if (request_entered == 1'b1) // request entered FSM
begin
data_type_q <= data_type_ex_i;
rdata_offset_q <= data_addr_ex_i[1:0];
data_sign_ext_q <= data_sign_ext_ex_i;
end
end
// pipeline gnt signal
always_ff @(posedge clk, negedge rst_n)
begin
if(rst_n == 1'b0)
begin
data_ack_int_o <= 1'b0;
end
else
begin
data_ack_int_o <= ~((data_req_o == 1'b1) & (data_gnt_i == 1'b0));
end
end
// FF for not accepted requests
always_ff @(posedge clk, negedge rst_n)
begin
if(rst_n == 1'b0)
begin
data_be_q <= '0;
data_addr_q <= '0;
data_we_q <= '0;
data_wdata_q <= '0;
misaligned_st_q <= 1'b0;
end
else if ((data_req_o == 1'b1) & (data_gnt_i == 1'b0)) // request was not granted
begin
data_be_q <= data_be_o;
data_addr_q <= data_addr_o;
data_we_q <= data_we_o;
data_wdata_q <= data_wdata_o;
misaligned_st_q <= misaligned_st;
end
end
////////////////////////////////////////////////////////////////////////
// ____ _ _____ _ _ //
// / ___|(_) __ _ _ __ | ____|_ _| |_ ___ _ __ ___(_) ___ _ __ //
// \___ \| |/ _` | '_ \ | _| \ \/ / __/ _ \ '_ \/ __| |/ _ \| '_ \ //
// ___) | | (_| | | | | | |___ > <| || __/ | | \__ \ | (_) | | | | //
// |____/|_|\__, |_| |_| |_____/_/\_\\__\___|_| |_|___/_|\___/|_| |_| //
// |___/ //
////////////////////////////////////////////////////////////////////////
logic [31:0] data_rdata_ext;
logic [31:0] rdata_w_ext; // sign extension for words, actually only misaligned assembly
logic [31:0] rdata_h_ext; // sign extension for half words
logic [31:0] rdata_b_ext; // sign extension for bytes
// take care of misaligned words
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]};
2'b10: rdata_w_ext = {data_rdata_i[15:0], rdata_q[31:16]};
2'b11: rdata_w_ext = {data_rdata_i[23:0], rdata_q[31:24]};
endcase
end
// sign extension for half words
always_comb
begin
case (rdata_offset_q)
2'b00:
begin
if (data_sign_ext_q == 1'b0)
rdata_h_ext = {16'h0000, data_rdata_i[15:0]};
else
rdata_h_ext = {{16{data_rdata_i[15]}}, data_rdata_i[15:0]};
end
2'b01:
begin
if (data_sign_ext_q == 1'b0)
rdata_h_ext = {16'h0000, data_rdata_i[23:8]};
else
rdata_h_ext = {{16{data_rdata_i[23]}}, data_rdata_i[23:8]};
end
2'b10:
begin
if (data_sign_ext_q == 1'b0)
rdata_h_ext = {16'h0000, data_rdata_i[31:16]};
else
rdata_h_ext = {{16{data_rdata_i[31]}}, data_rdata_i[31:16]};
end
2'b11:
begin
if (data_sign_ext_q == 1'b0)
rdata_h_ext = {16'h0000, data_rdata_i[7:0], rdata_q[31:24]};
else
rdata_h_ext = {{16{data_rdata_i[7]}}, data_rdata_i[7:0], rdata_q[31:24]};
end
endcase // case (rdata_offset_q)
end
// sign extension for bytes
always_comb
begin
case (rdata_offset_q)
2'b00:
begin
if (data_sign_ext_q == 1'b0)
rdata_b_ext = {24'h00_0000, data_rdata_i[7:0]};
else
rdata_b_ext = {{24{data_rdata_i[7]}}, data_rdata_i[7:0]};
end
2'b01: begin
if (data_sign_ext_q == 1'b0)
rdata_b_ext = {24'h00_0000, data_rdata_i[15:8]};
else
rdata_b_ext = {{24{data_rdata_i[15]}}, data_rdata_i[15:8]};
end
2'b10:
begin
if (data_sign_ext_q == 1'b0)
rdata_b_ext = {24'h00_0000, data_rdata_i[23:16]};
else
rdata_b_ext = {{24{data_rdata_i[23]}}, data_rdata_i[23:16]};
end
2'b11:
begin
if (data_sign_ext_q == 1'b0)
rdata_b_ext = {24'h00_0000, data_rdata_i[31:24]};
else
rdata_b_ext = {{24{data_rdata_i[31]}}, data_rdata_i[31:24]};
end
endcase // case (rdata_offset_q)
end
// select word, half word or byte sign extended version
always_comb
begin
case (data_type_q)
2'b00: data_rdata_ext = rdata_w_ext;
2'b01: data_rdata_ext = rdata_h_ext;
2'b10,2'b11: data_rdata_ext = rdata_b_ext;
endcase //~case(rdata_type_q)
end
always_ff @(posedge clk, negedge rst_n)
begin
if(rst_n == 1'b0)
begin
CS <= IDLE;
rdata_q <= '0;
end
else
begin
CS <= NS;
if(latch_rdata)
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_ex_i == 1'b1) || (data_misaligned_o == 1'b1))
rdata_q <= data_rdata_i;
else
rdata_q <= data_rdata_ext;
end
end
end
// output to register file
assign data_rdata_ex_o = (latch_rdata == 1'b1) ? data_rdata_ext : rdata_q;
// registered result of data request
assign lsu_data_reg_o = rdata_q;
// FSM
always_comb
begin
data_req_o = 1'b0;
data_we_o = 1'b0;
data_addr_o = data_addr_ex_i;
data_wdata_o = data_wdata;
data_be_o = data_be;
misaligned_st = data_misaligned_ex_i;
latch_rdata = 1'b0;
request_entered = 1'b0;
case(CS)
IDLE:
begin
data_req_o = data_req_ex_i;
data_we_o = data_we_ex_i;
if(data_req_ex_i)
begin
request_entered = 1'b1;
if(data_gnt_i)
begin
if(ex_stall_i)
NS = PENDING_W_EX_STALL_1;
else
NS = PENDING_WO_EX_STALL;
end
else
begin
if(ex_stall_i)
NS = IDLE;
else
begin
NS = WAIT_GNT;
end
end
end
else
NS = IDLE;
end //~ IDLE
WAIT_GNT:
begin
data_req_o = 1'b1;
data_we_o = data_we_q;
data_addr_o = data_addr_q;
data_be_o = data_be_q;
data_wdata_o = data_wdata_q;
misaligned_st = misaligned_st_q;
if(data_gnt_i)
begin
NS = PENDING_WO_EX_STALL;
end
else
begin
NS = WAIT_GNT;
end
end // case: WAIT_GNT
PENDING_WO_EX_STALL:
begin
latch_rdata = ~data_we_o;
data_req_o = data_req_ex_i;
data_we_o = data_we_ex_i;
if(data_req_ex_i)
begin
request_entered = 1'b1;
if(data_gnt_i)
begin
if(ex_stall_i)
NS = PENDING_W_EX_STALL_1;
else
NS = PENDING_WO_EX_STALL;
end
else
begin
if(ex_stall_i)
NS = IDLE;
else
NS = WAIT_GNT;
end
end
else
NS = IDLE;
end //~PENDING_WO_EX_STALL
PENDING_W_EX_STALL_1 :
begin
data_req_o = 1'b0;
latch_rdata = ~data_we_o;
if(ex_stall_i)
begin
NS = PENDING_W_EX_STALL_2;
end
else
begin
NS = IDLE;
end
end //~ PENDING_W_EX_STALL_1
PENDING_W_EX_STALL_2 :
begin
if(ex_stall_i)
begin
NS = PENDING_W_EX_STALL_2;
end
else
begin
NS = IDLE;
end
end //~ PENDING_W_EX_STALL_2
default :
begin
NS = IDLE;
end
endcase
end
// 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
data_misaligned_o = 1'b0;
if((data_req_ex_i == 1'b1) && (data_misaligned_ex_i == 1'b0))
begin
case (data_type_ex_i)
2'b00: // word
begin
if(data_addr_ex_i[1:0] != 2'b00)
data_misaligned_o = 1'b1;
end
2'b01: // half word
begin
if(data_addr_ex_i[1:0] == 2'b11)
data_misaligned_o = 1'b1;
end
endcase // case (data_type_ex_i)
end
end
endmodule

125
mult.sv Normal file
View file

@ -0,0 +1,125 @@
////////////////////////////////////////////////////////////////////////////////
// Company: IIS @ ETHZ - Federal Institute of Technology //
// //
// Engineer: Matthias Baer - baermatt@student.ethz.ch //
// //
// Additional contributions by: //
// Andreas Traber - atraber@student.ethz.ch //
// //
// //
// Create Date: 19/09/2013 //
// Design Name: Pipelined Processor //
// Module Name: mult.sv //
// Project Name: Processor //
// Language: SystemVerilog //
// //
// Description: Multiplier of the pipelined processor //
// Design ware multiplier requires two cycles to complete. //
// Generic multiplier requires only one cycle. result will be //
// stored in a FF. Best synthesis results are achieved with //
// moving the result register in the multiplier with automatic//
// retiming! //
// //
// Revision: //
// Revision v0.1 - File Created //
// Revision v0.2 - (Oct 30th 2014) Added MAC to the multiplier //
// Revision v0.3 - (Jan 21th 2015) Changed to a 32 bit result for //
// multiplications, added vectorial support and subword //
// selection. There are no flags for multiplications anymore! //
// //
// //
// //
// //
// //
////////////////////////////////////////////////////////////////////////////////
`include "defines.sv"
module mult
(
input logic [1:0] vector_mode_i,
input logic [1:0] sel_subword_i,
input logic [1:0] signed_mode_i,
input logic use_carry_i,
input logic mac_en_i,
input logic [31:0] op_a_i,
input logic [31:0] op_b_i,
input logic [31:0] mac_i,
input logic carry_i,
output logic [31:0] result_o,
output logic carry_o,
output logic overflow_o
);
logic [32:0] result;
logic [31:0] op_a_sel;
logic [31:0] op_b_sel;
logic [32:0] mac_int;
assign mac_int = (mac_en_i == 1'b1) ? mac_i : 32'b0;
// this block performs the subword selection and sign extensions
always_comb
begin
op_a_sel = op_a_i;
op_b_sel = op_b_i;
if(vector_mode_i == `VEC_MODE216)
begin
if(sel_subword_i[1] == 1'b1)
op_a_sel[15:0] = op_a_i[31:16];
else
op_a_sel[15:0] = op_a_i[15:0];
if(sel_subword_i[0] == 1'b1)
op_b_sel[15:0] = op_b_i[31:16];
else
op_b_sel[15:0] = op_b_i[15:0];
op_a_sel[31:16] = {16{signed_mode_i[1] & op_a_sel[15]}};
op_b_sel[31:16] = {16{signed_mode_i[0] & op_b_sel[15]}};
end
end
always_comb
begin
case(vector_mode_i)
default: // VEC_MODE32, VEC_MODE216
begin
result[32: 0] = mac_int + op_a_sel * op_b_sel + (use_carry_i & carry_i);
end
`VEC_MODE16:
begin
result[15: 0] = op_a_sel[15: 0] * op_b_sel[15: 0];
result[31:16] = op_a_sel[31:16] * op_b_sel[31:16];
result[32] = 1'b0;
end
`VEC_MODE8:
begin
result[ 7: 0] = op_a_sel[ 7: 0] * op_b_sel[ 7: 0];
result[15: 8] = op_a_sel[15: 8] * op_b_sel[15: 8];
result[23:16] = op_a_sel[23:16] * op_b_sel[23:16];
result[31:24] = op_a_sel[31:24] * op_b_sel[31:24];
result[32] = 1'b0;
end
endcase; // case (vec_mode_i)
end
assign result_o = result[31:0];
assign carry_o = result[32];
// overflow is only used for MAC
// If the MSB of the input MAC and the result is not the same => overflow occurred
assign overflow_o = mac_i[31] ^ result[31];
endmodule // mult

163
register_file.sv Normal file
View file

@ -0,0 +1,163 @@
module riscv_register_file
#(
parameter ADDR_WIDTH = 5,
parameter DATA_WIDTH = 32
)
(
// Clock and Reset
input logic clk,
input logic rst_n,
//Read port R1
input logic [ADDR_WIDTH-1:0] raddr_a_i,
output logic [DATA_WIDTH-1:0] rdata_a_o,
//Read port R2
input logic [ADDR_WIDTH-1:0] raddr_b_i,
output logic [DATA_WIDTH-1:0] rdata_b_o,
//Read port R3
input logic [ADDR_WIDTH-1:0] raddr_c_i,
output logic [DATA_WIDTH-1:0] rdata_c_o,
// Write port W1
input logic [ADDR_WIDTH-1:0] waddr_a_i,
input logic [DATA_WIDTH-1:0] wdata_a_i,
input logic we_a_i,
// Write port W2
input logic [ADDR_WIDTH-1:0] waddr_b_i,
input logic [DATA_WIDTH-1:0] wdata_b_i,
input logic we_b_i
);
localparam NUM_WORDS = 2**ADDR_WIDTH;
// Read address register, located at the input of the address decoder
logic [ADDR_WIDTH-1:0] RAddrRegxDPa;
logic [ADDR_WIDTH-1:0] RAddrRegxDPb;
logic [ADDR_WIDTH-1:0] RAddrRegxDPc;
logic [NUM_WORDS-1:0] RAddrOneHotxD;
logic [ADDR_WIDTH-1:0] s_raddr_c;
logic [DATA_WIDTH-1:0] MemContentxDP[NUM_WORDS];
logic [NUM_WORDS-1:0] WAddrOneHotxDa;
logic [NUM_WORDS-1:0] WAddrOneHotxDb;
logic [NUM_WORDS-1:0] WAddrOneHotxDb_reg;
logic [NUM_WORDS-1:0] ClocksxC;
logic [DATA_WIDTH-1:0] WDataIntxDa;
logic [DATA_WIDTH-1:0] WDataIntxDb;
logic clk_int;
logic we_int;
int unsigned i;
int unsigned j;
int unsigned k;
int unsigned l;
int unsigned m;
genvar x;
genvar y;
assign we_int = we_a_i | we_b_i;
cluster_clock_gating CG_WE_GLOBAL
(
.clk_o(clk_int),
.en_i(we_int),
.test_en_i(1'b0),
.clk_i(clk)
);
//-----------------------------------------------------------------------------
//-- READ : Read address decoder RAD
//-----------------------------------------------------------------------------
assign rdata_a_o = MemContentxDP[raddr_a_i];
assign rdata_b_o = MemContentxDP[raddr_b_i];
assign rdata_c_o = MemContentxDP[raddr_c_i];
//-----------------------------------------------------------------------------
//-- 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_i == i) )
WAddrOneHotxDa[i] = 1'b1;
else
WAddrOneHotxDa[i] = 1'b0;
end
end
always_comb
begin : p_WADb
for(j=1; j<NUM_WORDS; j++)
begin : p_WordIterb
if ( (we_b_i == 1'b1 ) && (waddr_b_i == j) )
WAddrOneHotxDb[j] = 1'b1;
else
WAddrOneHotxDb[j] = 1'b0;
end
end
always_ff @(posedge clk_int)
begin
if(we_a_i | we_b_i)
WAddrOneHotxDb_reg <= WAddrOneHotxDb;
end
//-----------------------------------------------------------------------------
//-- WRITE : Clock gating (if integrated clock-gating cells are available)
//-----------------------------------------------------------------------------
generate
for(x=1; x<NUM_WORDS; x++)
begin : CG_CELL_WORD_ITER
cluster_clock_gating CG_Inst
(
.clk_o(ClocksxC[x]),
.en_i(WAddrOneHotxDa[x] | WAddrOneHotxDb[x]),
.test_en_i(1'b0),
.clk_i(clk_int)
);
end
endgenerate
//-----------------------------------------------------------------------------
// WRITE : SAMPLE INPUT DATA
//---------------------------------------------------------------------------
always_ff @(posedge clk)
begin : sample_waddr
if(we_a_i)
WDataIntxDa <= wdata_a_i;
if(we_b_i)
WDataIntxDb <= wdata_b_i;
end
//-----------------------------------------------------------------------------
//-- WRITE : Write operation
//-----------------------------------------------------------------------------
//-- Generate M = WORDS sequential processes, each of which describes one
//-- word of the memory. The processes are synchronized with the clocks
//-- ClocksxC(i), i = 0, 1, ..., M-1
//-- Use active low, i.e. transparent on low latches as storage elements
//-- Data is sampled on rising clock edge
always_latch
begin : latch_wdata
// Note: The assignment has to be done inside this process or Modelsim complains about it
MemContentxDP[0] = 32'b0;
for(k=1; k<NUM_WORDS; k++)
begin : w_WordIter
if(ClocksxC[k] == 1'b1)
MemContentxDP[k] = WAddrOneHotxDb_reg[k] ? WDataIntxDb : WDataIntxDa;
end
end
endmodule

791
riscv_core.sv Normal file
View file

@ -0,0 +1,791 @@
////////////////////////////////////////////////////////////////////////////////
// Company: IIS @ ETHZ - Federal Institute of Technology //
// //
// Engineer: Sven Stucki - svstucki@student.ethz.ch //
// //
// Additional contributions by: //
// //
// //
// Create Date: 24/3/2015 //
// Design Name: RiscV Minion //
// Module Name: riscv_core.sv //
// Project Name: RISCV //
// Language: SystemVerilog //
// //
// Description: RiscV core //
// //
// //
// Revision: //
// //
// //
// //
////////////////////////////////////////////////////////////////////////////////
`include "defines.sv"
module riscv_core
(
// Clock and Reset
input logic clk,
input logic rst_n,
// Core ID, Cluster ID and boot address are considered more or less static
input logic [31:0] boot_addr_i,
input logic [4:0] core_id_i,
input logic [4:0] cluster_id_i,
// Instruction memory interface
output logic [31:0] instr_addr_o,
output logic instr_req_o,
input logic [31:0] instr_rdata_i,
input logic instr_grant_i,
input logic instr_rvalid_i,
// Data memory interface
output logic [31:0] data_addr_o,
output logic [31:0] data_wdata_o,
output logic data_we_o,
output logic data_req_o,
output logic [3:0] data_be_o,
input logic [31:0] data_rdata_i,
input logic data_gnt_i,
input logic data_r_valid_i,
// Interrupt inputs
input logic irq_i, // level-triggered IR line
input logic irq_nm_i, // level-triggered IR line for non-maskable IRQ
// Debug Interface
input logic dbginf_stall_i,
output logic dbginf_bp_o,
input logic dbginf_strobe_i,
output logic dbginf_ack_o,
input logic dbginf_we_i,
input logic [15:0] dbginf_addr_i,
input logic [31:0] dbginf_data_i,
output logic [31:0] dbginf_data_o,
// CPU Control Signals
input logic fetch_enable_i,
output logic eoc_o, // End of Computation
output logic core_busy_o
);
// IF/ID signals
logic [31:0] instr_rdata_id; // Instruction sampled nsude the PC stage
logic [31:0] current_pc_if; // Current Program counter
logic [31:0] current_pc_id; // Current Program counter
logic force_nop_id;
logic [2:0] pc_mux_sel_id; // Mux selector for next PC
logic pc_mux_boot; // load boot address as PC
logic [1:0] exc_pc_mux_id; // Mux selector for exception PC
logic useincr_addr_ex; // Active when post increment
logic data_misaligned; // Active when post increment
// Forwarding
logic [31:0] pc_from_immediate_id; //take PC from immediate in case of Jump
// Stalling
logic stall_if; // Stall instruction fetch(deassert request)
logic stall_id; // Stall PC stage and instr memory and data memo
logic stall_ex; // Stall EX Stage
logic stall_wb; // Stall write back stage
// Register Data
logic [31:0] pc_from_regfile_id; // take PC from Register File
logic [31:0] wdata_reg_fw_id; //
logic [31:0] regfile_rb_data_ex; // from id stage to load/store unit and ex stage
logic [31:0] regfile_rb_data_wb; // from ex stage to sp register
// ALU Control
logic [`ALU_OP_WIDTH-1:0] alu_operator_ex;
logic [31:0] alu_operand_a_ex;
logic [31:0] alu_operand_b_ex;
logic [31:0] alu_operand_c_ex;
logic alu_flag_ex;
logic [1:0] vector_mode_ex;
logic [1:0] alu_cmp_mode_ex;
logic [1:0] alu_vec_ext_ex;
// Result Control
logic carry_ex;
logic overflow_ex;
// End of Computation
logic eoc_ex;
logic eoc_wb;
// Multiplier Control
logic mult_is_running_ex;
logic [1:0] mult_sel_subword_ex;
logic [1:0] mult_signed_mode_ex;
logic mult_use_carry_ex;
logic mult_mac_en_ex;
// Register Write Control
logic [4:0] regfile_waddr_ex;
logic regfile_wdata_mux_sel_ex;
logic regfile_we_ex;
logic [4:0] regfile_waddr_fw_wb_o; // From WB to ID
logic regfile_we_wb;
logic [31:0] regfile_wdata;
logic regfile_wdata_mux_sel_wb;
logic [4:0] regfile_alu_waddr_ex;
logic regfile_alu_we_ex;
logic [4:0] regfile_alu_waddr_fw;
logic regfile_alu_we_fw;
logic [31:0] regfile_alu_wdata_fw;
logic [31:0] regfile_alu_wdata_fw_pc;
// Special-Purpose Register Control
logic sp_we_ex; // Output of ID_stage to EX stage
logic sp_we_wb;
logic [31:0] sp_rdata;
logic [15:0] sp_addr;
logic [31:0] sp_wdata;
logic sp_we;
// Data Memory Control: From ID stage (id-ex pipe) <--> load store unit
logic data_we_ex;
logic [1:0] data_type_ex;
logic data_sign_ext_ex;
logic [1:0] data_reg_offset_ex;
logic data_req_ex;
logic [31:0] data_addr_ex;
logic data_misaligned_ex;
logic [31:0] data_rdata_int;
logic [31:0] lsu_data_reg;
logic data_ack_int;
// Supervision Register
logic set_flag_ex;
logic set_carry_ex;
logic set_overflow_ex;
logic set_carry_fw_ex;
logic set_overflow_fw_ex;
logic set_dsx;
// Direct Supervision-Register access
logic sr_flag;
logic sr_flag_fw;
logic carry_sp;
// Calculation Result
logic [15:0] result_wb;
// Signals between instruction core interface and pipe (if and id stages)
logic [31:0] instr_rdata_int; // read instruction from the instruction core interface to if_stage
logic instr_req_int; // Id stage asserts a req to instruction core interface
logic instr_ack_int; // instr core interface acks the request now (read data is available)
logic [31:0] instr_addr_int; // adress sent to the inst core interface from if_Stage
// Interrupts
logic irq_enable;
logic [31:0] epcr;
logic save_pc_if;
logic save_pc_id;
logic save_sr;
logic restore_sr;
// hwloops
logic [31:0] hwloop_cnt_ex; // from id to ex stage (hwloop_regs)
logic [2:0] hwloop_we_ex; // from id to ex stage (hwloop_regs)
logic [1:0] hwloop_regid_ex; // from id to ex stage (hwloop_regs)
logic hwloop_wb_mux_sel_ex; // from id to ex stage (hwloop_regs)
logic [31:0] hwloop_start_data; // hwloop data to write to hwloop_regs
logic [31:0] hwloop_end_data; // hwloop data to write to hwloop_regs
logic [31:0] hwloop_cnt_data; // hwloop data to write to hwloop_regs
logic [`HWLOOP_REGS-1:0] [31:0] hwloop_start_addr; // to hwloop controller
logic [`HWLOOP_REGS-1:0] [31:0] hwloop_end_addr; // to hwloop controller
logic [`HWLOOP_REGS-1:0] [31:0] hwloop_counter; // to hwloop controller
logic [`HWLOOP_REGS-1:0] hwloop_dec_cnt; // from hwloop controller to hwloop regs
logic [31:0] hwloop_targ_addr; // from hwloop controller to if stage
// Debug Unit
logic dbg_stall;
logic dbg_flush_pipe;
logic pipe_flushed;
logic dbg_trap;
logic dbg_st_en; // single-step trace mode enabled
logic [1:0] dbg_dsr; // Debug Stop Register
logic dbg_reg_mux;
logic dbg_sp_mux;
logic dbg_reg_we;
logic [15:0] dbg_reg_addr;
logic [31:0] dbg_reg_wdata;
logic [31:0] dbg_reg_rdata;
logic [31:0] dbg_rdata;
logic [31:0] dbg_npc;
logic dbg_set_npc;
`ifdef BRANCH_PREDICTION
logic wrong_branch_taken;
logic take_branch;
`endif
logic drop_instruction;
`ifdef TCDM_ADDR_PRECAL
logic [31:0] alu_adder_ex;
`endif
//////////////////////////////////////////////////
// ___ _____ ____ _____ _ ____ _____ //
// |_ _| ___| / ___|_ _|/ \ / ___| ____| //
// | || |_ \___ \ | | / _ \| | _| _| //
// | || _| ___) || |/ ___ \ |_| | |___ //
// |___|_| |____/ |_/_/ \_\____|_____| //
// //
//////////////////////////////////////////////////
if_stage if_stage_i
(
// Global signals reset and clock
.clk ( clk ), // Clock
.rst_n ( rst_n ), // active low reset
// Boot address for exception vector offsets
.boot_addr_i ( boot_addr_i ),
// outputs to ID stage
.instr_rdata_id_o ( instr_rdata_id ), // Output of IF Pipeline stage
.current_pc_if_o ( current_pc_if ), // current pc
.current_pc_id_o ( current_pc_id ), // current pc
//Input - OUtput from-to instruction memory
.instr_rdata_i ( instr_rdata_int ), // From Instr memory
.instr_addr_o ( instr_addr_int ), // address for instruction fetch to instr memory/cache
// Forwrding ports - control signals
.force_nop_i ( force_nop_id ), // select incoming instr or NOP
.exception_pc_reg_i ( epcr ), // Exception PC register
.pc_from_regfile_i ( pc_from_regfile_id ), // pc from reg file
.pc_from_immediate_i ( pc_from_immediate_id ), // pc from immediate
.pc_from_hwloop_i ( hwloop_targ_addr ), // pc from hwloop start address
.pc_mux_sel_i ( pc_mux_sel_id ), // sel for pc multiplexer
.pc_mux_boot_i ( pc_mux_boot ), // load boot address as PC
.exc_pc_mux_i ( exc_pc_mux_id ), // selector for exception multiplexer
// from debug unit
.dbg_pc_from_npc ( dbg_npc ),
.dbg_set_npc ( dbg_set_npc ),
// branch prediction
.drop_instruction_i ( drop_instruction ),
`ifdef BRANCH_PREDICTION
.wrong_branch_taken_i( wrong_branch_taken ),
.take_branch_i ( take_branch ),
`endif
// pipeline stalls
.stall_if_i ( stall_if ),
.stall_id_i ( stall_id )
);
///////////////////////////////////////////////////////////////////////////////////
// ___ _ _ ____ _____ ____ ____ ___ ____ _____ ___ _ _ _____ _____ //
// |_ _| \ | / ___|_ _| _ \ / ___/ _ \| _ \| ____| |_ _| \ | |_ _| ___| //
// | || \| \___ \ | | | |_) | | | | | | | |_) | _| | || \| | | | | |_ //
// | || |\ |___) || | | _ < | |__| |_| | _ <| |___ | || |\ | | | | _| //
// |___|_| \_|____/ |_| |_| \_\ \____\___/|_| \_\_____| |___|_| \_| |_| |_| //
// //
///////////////////////////////////////////////////////////////////////////////////
instr_core_interface instr_core_interface_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.stall_if_i ( stall_if ),
.req_i ( instr_req_int ),
.addr_i ( instr_addr_int ),
.ack_o ( instr_ack_int ),
.rdata_o ( instr_rdata_int ),
.instr_req_o ( instr_req_o ),
.instr_addr_o ( instr_addr_o ),
.instr_gnt_i ( instr_grant_i ),
.instr_r_valid_i ( instr_rvalid_i ),
.instr_r_rdata_i ( instr_rdata_i ),
.drop_request_i ( wrong_branch_taken )
);
/////////////////////////////////////////////////
// ___ ____ ____ _____ _ ____ _____ //
// |_ _| _ \ / ___|_ _|/ \ / ___| ____| //
// | || | | | \___ \ | | / _ \| | _| _| //
// | || |_| | ___) || |/ ___ \ |_| | |___ //
// |___|____/ |____/ |_/_/ \_\____|_____| //
// //
/////////////////////////////////////////////////
id_stage id_stage_i
(
.clk ( clk ),
.rst_n ( rst_n ),
// Processor Enable
.fetch_enable_i ( fetch_enable_i ),
.core_busy_o ( core_busy_o ),
// Interface to instruction memory
.instr_rdata_i ( instr_rdata_id ),
.instr_req_o ( instr_req_int ),
.instr_gnt_i ( instr_grant_i ),
.instr_ack_i ( instr_ack_int ),
.pc_mux_sel_o ( pc_mux_sel_id ),
.pc_mux_boot_o ( pc_mux_boot ),
.exc_pc_mux_o ( exc_pc_mux_id ),
.force_nop_o ( force_nop_id ),
.pc_from_regfile_fw_o ( pc_from_regfile_id ),
.current_pc_if_i ( current_pc_if ),
.current_pc_id_i ( current_pc_id ),
.pc_from_immediate_o ( pc_from_immediate_id ),
.sr_flag_fw_i ( sr_flag_fw ),
.sr_flag_i ( sr_flag ),
.drop_instruction_o ( drop_instruction ),
`ifdef BRANCH_PREDICTION
.wrong_branch_taken_o ( wrong_branch_taken ),
.take_branch_o ( take_branch ),
`endif
// STALLS
.stall_if_o ( stall_if ),
.stall_id_o ( stall_id ),
.stall_ex_o ( stall_ex ),
.stall_wb_o ( stall_wb ),
// From the Pipeline ID/EX
.regfile_rb_data_ex_o ( regfile_rb_data_ex ),
.alu_operand_a_ex_o ( alu_operand_a_ex ),
.alu_operand_b_ex_o ( alu_operand_b_ex ),
.alu_operand_c_ex_o ( alu_operand_c_ex ),
.alu_operator_ex_o ( alu_operator_ex ),
.vector_mode_ex_o ( vector_mode_ex ), // from ID to EX stage
.alu_cmp_mode_ex_o ( alu_cmp_mode_ex ), // from ID to EX stage
.alu_vec_ext_ex_o ( alu_vec_ext_ex ), // from ID to EX stage
.eoc_ex_o ( eoc_ex ),
.mult_is_running_ex_o ( mult_is_running_ex ), // from ID to EX stage
.mult_sel_subword_ex_o ( mult_sel_subword_ex ), // from ID to EX stage
.mult_signed_mode_ex_o ( mult_signed_mode_ex ), // from ID to EX stage
.mult_use_carry_ex_o ( mult_use_carry_ex ), // from ID to EX stage
.mult_mac_en_ex_o ( mult_mac_en_ex ), // from ID to EX stage
.regfile_waddr_ex_o ( regfile_waddr_ex ),
.regfile_wdata_mux_sel_ex_o ( regfile_wdata_mux_sel_ex ),
.regfile_we_ex_o ( regfile_we_ex ),
.regfile_alu_we_ex_o ( regfile_alu_we_ex ),
.regfile_alu_waddr_ex_o ( regfile_alu_waddr_ex ),
// hwloop signals
.hwloop_we_ex_o ( hwloop_we_ex ),
.hwloop_regid_ex_o ( hwloop_regid_ex ),
.hwloop_wb_mux_sel_ex_o ( hwloop_wb_mux_sel_ex ),
.hwloop_cnt_o ( hwloop_cnt_ex ),
.hwloop_dec_cnt_o ( hwloop_dec_cnt ),
.hwloop_targ_addr_o ( hwloop_targ_addr ),
.sp_we_ex_o ( sp_we_ex ),
.prepost_useincr_ex_o ( useincr_addr_ex ),
.data_misaligned_i ( data_misaligned ),
.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_req_ex_o ( data_req_ex ), // to load store unit
.data_misaligned_ex_o ( data_misaligned_ex ), // to load store unit
.data_ack_i ( data_ack_int ), // from load store unit
.data_rvalid_i ( data_r_valid_i ),
.set_flag_ex_o ( set_flag_ex ), // to ex_stage
.set_carry_ex_o ( set_carry_ex ), // to ex_stage
.set_overflow_ex_o ( set_overflow_ex ), // to ex_stage
.set_dsx_o ( set_dsx ), // to SPR
// Interrupt Signals
.irq_i ( irq_i ), // incoming interrupts
.irq_nm_i ( irq_nm_i ), // incoming interrupts
.irq_enable_i ( irq_enable ), // global interrupt enable
.save_pc_if_o ( save_pc_if ), // control signal to save pc
.save_pc_id_o ( save_pc_id ), // control signal to save pc
.save_sr_o ( save_sr ), // control signal to save status register
.restore_sr_o ( restore_sr ), // restore status register
// from hwloop regs
.hwloop_start_addr_i ( hwloop_start_addr ),
.hwloop_end_addr_i ( hwloop_end_addr ),
.hwloop_counter_i ( hwloop_counter ),
// Debug Unit Signals
.dbg_flush_pipe_i ( dbg_flush_pipe ),
.pipe_flushed_o ( pipe_flushed ),
.dbg_st_en_i ( dbg_st_en ),
.dbg_dsr_i ( dbg_dsr ),
.dbg_stall_i ( dbg_stall ),
.dbg_trap_o ( dbg_trap ),
.dbg_reg_mux_i ( dbg_reg_mux ),
.dbg_reg_we_i ( dbg_reg_we ),
.dbg_reg_addr_i ( dbg_reg_addr[4:0] ),
.dbg_reg_wdata_i ( dbg_reg_wdata ),
.dbg_reg_rdata_o ( dbg_reg_rdata ),
.dbg_set_npc_i ( dbg_set_npc ),
// Forward Signals
.regfile_alu_waddr_fw_i ( regfile_alu_waddr_fw ),
.regfile_alu_we_fw_i ( regfile_alu_we_fw ),
.regfile_alu_wdata_fw_i ( regfile_alu_wdata_fw ),
.regfile_alu_wdata_fw_pc_i ( regfile_alu_wdata_fw_pc ),
.regfile_waddr_wb_i ( regfile_waddr_fw_wb_o ), // Write address ex-wb pipeline
.regfile_we_wb_i ( regfile_we_wb ), // write enable for the register file
.regfile_wdata_wb_i ( regfile_wdata ), // write data to commit in the register file
.wdata_reg_i ( wdata_reg_fw_id ) // write data to regfile, origin is always a register(not data memory)
`ifdef TCDM_ADDR_PRECAL
,
.alu_adder_o ( alu_adder_ex )
`endif
);
/////////////////////////////////////////////////////
// _______ __ ____ _____ _ ____ _____ //
// | ____\ \/ / / ___|_ _|/ \ / ___| ____| //
// | _| \ / \___ \ | | / _ \| | _| _| //
// | |___ / \ ___) || |/ ___ \ |_| | |___ //
// |_____/_/\_\ |____/ |_/_/ \_\____|_____| //
// //
/////////////////////////////////////////////////////
ex_stage ex_stage_i
(
// Global signals: Clock and active low asynchronous reset
.clk ( clk ),
.rst_n ( rst_n ),
// Alu signals from ID stage
.alu_operator_i ( alu_operator_ex ), // from ID/EX pipe registers
.alu_operand_a_i ( alu_operand_a_ex ), // from ID/EX pipe registers
.alu_operand_b_i ( alu_operand_b_ex ), // from ID/EX pipe registers
.alu_operand_c_i ( alu_operand_c_ex ), // from ID/EX pipe registers
.alu_carry_i ( carry_sp ), // from spr carry
.alu_flag_i ( sr_flag ), // from spr flag
.alu_flag_o ( alu_flag_ex ), // to spr flag
.vector_mode_i ( vector_mode_ex ), // from ID/EX pipe registers
.alu_cmp_mode_i ( alu_cmp_mode_ex ), // from ID/EX pipe registers
.alu_vec_ext_i ( alu_vec_ext_ex ), // from ID/EX pipe registers
// Multipler
.mult_is_running_i ( mult_is_running_ex ),
.mult_sel_subword_i ( mult_sel_subword_ex ),
.mult_signed_mode_i ( mult_signed_mode_ex ),
.mult_use_carry_i ( mult_use_carry_ex ),
.mult_mac_en_i ( mult_mac_en_ex ),
// interface with Special registers
.carry_o ( carry_ex ),
.overflow_o ( overflow_ex ),
.set_overflow_o ( set_overflow_fw_ex ), // to special registers
.set_carry_o ( set_carry_fw_ex ), // to special registers
// input from ID stage
.stall_ex_i ( stall_ex ),
.stall_wb_i ( stall_wb ),
.prepost_useincr_i ( useincr_addr_ex ),
// From ID Stage: Regfile control signals
.regfile_waddr_i ( regfile_waddr_ex ),
.regfile_wdata_mux_sel_i ( regfile_wdata_mux_sel_ex ),
.regfile_we_i ( regfile_we_ex ),
.regfile_alu_we_i ( regfile_alu_we_ex ),
.regfile_alu_waddr_i ( regfile_alu_waddr_ex ),
// From ID stage: hwloop wb reg signals
.hwloop_wb_mux_sel_i ( hwloop_wb_mux_sel_ex ),
.hwloop_pc_plus4_i ( current_pc_id ),
.hwloop_cnt_i ( hwloop_cnt_ex ),
//From ID stage.Controller
.set_overflow_i ( set_overflow_ex ),
.set_carry_i ( set_carry_ex ),
.eoc_i ( eoc_ex ),
.regfile_rb_data_i ( regfile_rb_data_ex ),
.sp_we_i ( sp_we_ex ),
// Output of ex stage pipeline
.regfile_wdata_wb_o ( result_wb ),
.regfile_waddr_wb_o ( regfile_waddr_fw_wb_o ),
.regfile_wdata_mux_sel_wb_o ( regfile_wdata_mux_sel_wb ),
.regfile_we_wb_o ( regfile_we_wb ),
.regfile_rb_data_wb_o ( regfile_rb_data_wb ),
.data_addr_ex_o ( data_addr_ex ),
// To hwloop regs
.hwloop_start_data_o ( hwloop_start_data ),
.hwloop_end_data_o ( hwloop_end_data ),
.hwloop_cnt_data_o ( hwloop_cnt_data ),
.sp_we_wb_o ( sp_we_wb ),
.eoc_o ( eoc_wb ),
// To ID stage: Forwarding signals
.regfile_alu_waddr_fw_o ( regfile_alu_waddr_fw ),
.regfile_alu_we_fw_o ( regfile_alu_we_fw ),
.regfile_alu_wdata_fw_o ( regfile_alu_wdata_fw ),
.regfile_alu_wdata_fw_pc_o ( regfile_alu_wdata_fw_pc )
`ifdef TCDM_ADDR_PRECAL
,
.alu_adder_i ( alu_adder_ex )
`endif
);
/////////////////////////////////////////////////////////
// __ ______ ____ _____ _ ____ _____ //
// \ \ / / __ ) / ___|_ _|/ \ / ___| ____| //
// \ \ /\ / /| _ \ \___ \ | | / _ \| | _| _| //
// \ V V / | |_) | ___) || |/ ___ \ |_| | |___ //
// \_/\_/ |____/ |____/ |_/_/ \_\____|_____| //
// //
/////////////////////////////////////////////////////////
wb_stage wb_stage_i
(
//Mux selector of regfile wdata
.regfile_wdata_mux_sel_i ( regfile_wdata_mux_sel_wb ),
//Mux inputs
.sp_rdata_i ( sp_rdata ),
.data_rdata_i ( data_rdata_int ),
.lsu_data_reg_i ( lsu_data_reg ),
//Mux output
.regfile_wdata_o ( regfile_wdata ),
.wdata_reg_o ( wdata_reg_fw_id ),
.eoc_i ( eoc_wb ),
.eoc_o ( eoc_o )
);
////////////////////////////////////////////////////////////////////////////////////////
// _ ___ _ ____ ____ _____ ___ ____ _____ _ _ _ _ ___ _____ //
// | | / _ \ / \ | _ \ / ___|_ _/ _ \| _ \| ____| | | | | \ | |_ _|_ _| //
// | | | | | |/ _ \ | | | | \___ \ | || | | | |_) | _| | | | | \| || | | | //
// | |__| |_| / ___ \| |_| | ___) || || |_| | _ <| |___ | |_| | |\ || | | | //
// |_____\___/_/ \_\____/ |____/ |_| \___/|_| \_\_____| \___/|_| \_|___| |_| //
// //
////////////////////////////////////////////////////////////////////////////////////////
load_store_unit load_store_unit_i
(
.clk ( clk ),
.rst_n ( rst_n ),
// signal from ex stage
.data_we_ex_i ( data_we_ex ),
.data_type_ex_i ( data_type_ex ),
.data_wdata_ex_i ( regfile_rb_data_ex ),
.data_reg_offset_ex_i ( data_reg_offset_ex ),
.data_sign_ext_ex_i ( data_sign_ext_ex ), // sign extension
.data_rdata_ex_o ( data_rdata_int ),
.lsu_data_reg_o ( lsu_data_reg ),
.data_req_ex_i ( data_req_ex ),
.data_addr_ex_i ( data_addr_ex ),
.data_ack_int_o ( data_ack_int ), // ack used in controller to stall
.data_misaligned_ex_i ( data_misaligned_ex ), // from ID/EX pipeline
.data_misaligned_o ( data_misaligned ),
//output to data memory
.data_be_o ( data_be_o ),
.data_wdata_o ( data_wdata_o ),
.data_rdata_i ( data_rdata_i ),
.data_rvalid_i ( data_r_valid_i ),
.data_addr_o ( data_addr_o ),
.data_we_o ( data_we_o ),
.data_req_o ( data_req_o ),
.data_gnt_i ( data_gnt_i ),
.ex_stall_i ( stall_ex )
);
/*
//////////////////////////////////////////////
// ____ ____ ____ //
// / ___|| _ \ | _ \ ___ __ _ ___ //
// \___ \| |_) | | |_) / _ \/ _` / __| //
// ___) | __/ | _ < __/ (_| \__ \ //
// |____/|_| |_| \_\___|\__, |___/ //
// |___/ //
// Special Purpose REGISTERS //
//////////////////////////////////////////////
sp_registers sp_registers_i
(
.clk ( clk ),
.rst_n ( rst_n ),
// Core and Cluster ID from outside
.core_id_i ( core_id_i ),
.cluster_id_i ( cluster_id_i ),
// Interface to Special register (SRAM LIKE)
.sp_addr_i ( sp_addr ),
.sp_wdata_i ( sp_wdata ),
.sp_we_i ( sp_we ), // from ex-wb pipe regs
.sp_rdata_o ( sp_rdata ), // to write back stage
// Direct interface with MUL-ALU and Controller
// Flag
.flag_i ( alu_flag_ex ), // comparison flag
// Overflow and Carry - From ALU
.carry_i ( carry_ex ),
.overflow_i ( overflow_ex ),
// From the controller
.set_flag_i ( set_flag_ex ), // From EX stage
.set_carry_i ( set_carry_fw_ex ), // From EX stage
.set_overflow_i ( set_overflow_fw_ex ), // From EX stage
.set_dsx_i ( set_dsx ), // from exc controller
// Stall direct write
.enable_direct_write_i ( stall_wb ),
.curr_pc_if_i ( current_pc_if ), // from IF stage
.curr_pc_id_i ( current_pc_id ), // from IF stage
.save_pc_if_i ( save_pc_if ),
.save_pc_id_i ( save_pc_id ),
.save_sr_i ( save_sr ),
.restore_sr_i ( restore_sr ),
.epcr_o ( epcr ),
.irq_enable_o ( irq_enable ),
.npc_o ( dbg_npc ), // PC from debug unit
.set_npc_o ( dbg_set_npc ), // set PC to new value
.flag_fw_o ( sr_flag_fw ),
.flag_o ( sr_flag ),
.carry_o ( carry_sp )
);
// Mux for SPR access through Debug Unit
assign sp_addr = (dbg_sp_mux == 1'b0) ? result_wb : dbg_reg_addr;
assign sp_wdata = (dbg_sp_mux == 1'b0) ? regfile_rb_data_wb : dbg_reg_wdata;
assign sp_we = (dbg_sp_mux == 1'b0) ? sp_we_wb : dbg_reg_we;
assign dbg_rdata = (dbg_sp_mux == 1'b0) ? dbg_reg_rdata : sp_rdata;
//////////////////////////////////////////////
// Hardware Loop Registers //
//////////////////////////////////////////////
hwloop_regs hwloop_regs_i
(
.clk ( clk ),
.rst_n ( rst_n ),
// from ex stage
.hwloop_start_data_i ( hwloop_start_data ),
.hwloop_end_data_i ( hwloop_end_data ),
.hwloop_cnt_data_i ( hwloop_cnt_data ),
.hwloop_we_i ( hwloop_we_ex ),
.hwloop_regid_i ( hwloop_regid_ex ),
// from controller
.stall_id_i ( stall_id ),
// to hwloop controller
.hwloop_start_addr_o ( hwloop_start_addr ),
.hwloop_end_addr_o ( hwloop_end_addr ),
.hwloop_counter_o ( hwloop_counter ),
// from hwloop controller
.hwloop_dec_cnt_i ( hwloop_dec_cnt )
);
*/
/////////////////////////////////////////////////////////////
// ____ _____ ____ _ _ ____ _ _ _ _ ___ _____ //
// | _ \| ____| __ )| | | |/ ___| | | | | \ | |_ _|_ _| //
// | | | | _| | _ \| | | | | _ | | | | \| || | | | //
// | |_| | |___| |_) | |_| | |_| | | |_| | |\ || | | | //
// |____/|_____|____/ \___/ \____| \___/|_| \_|___| |_| //
// //
/////////////////////////////////////////////////////////////
debug_unit debug_unit_i
(
.clk ( clk ),
.rst_n ( rst_n ),
// Debug Interface
.dbginf_stall_i ( dbginf_stall_i ),
.dbginf_bp_o ( dbginf_bp_o ),
.dbginf_strobe_i ( dbginf_strobe_i ),
.dbginf_ack_o ( dbginf_ack_o ),
.dbginf_we_i ( dbginf_we_i ),
.dbginf_addr_i ( dbginf_addr_i ),
.dbginf_data_i ( dbginf_data_i ),
.dbginf_data_o ( dbginf_data_o ),
// To/From Core
.dbg_st_en_o ( dbg_st_en ),
.dbg_dsr_o ( dbg_dsr ),
.stall_core_o ( dbg_stall ),
.flush_pipe_o ( dbg_flush_pipe ),
.pipe_flushed_i ( pipe_flushed ),
.trap_i ( dbg_trap ),
// register file access
.regfile_mux_o ( dbg_reg_mux ),
.sp_mux_o ( dbg_sp_mux ),
.regfile_we_o ( dbg_reg_we ),
.regfile_addr_o ( dbg_reg_addr ),
.regfile_wdata_o ( dbg_reg_wdata ),
.regfile_rdata_i ( dbg_rdata )
);
///////////////////
endmodule // cpu //
///////////////////

82
wb_stage.sv Normal file
View file

@ -0,0 +1,82 @@
////////////////////////////////////////////////////////////////////////////////
// Company: IIS @ ETHZ - Federal Institute of Technology //
// DEI @ UNIBO - University of Bologna //
// //
// Engineer: Renzo Andri - andrire@student.ethz.ch //
// //
// Additional contributions by: //
// Igor Loi - igor.loi@unibo.it //
// //
// //
// Create Date: 01/07/2014 //
// Design Name: Write Back stage //
// Module Name: wb_stage.sv //
// Project Name: OR10N //
// Language: SystemVerilog //
// //
// Description: Execution stage: hosts a Multiplexer that select data to //
// write in the register file (from data interface or SP reg //
// //
// Revision: //
// Revision v0.1 - File Created //
// Revision v0.2 - (August 6th 2014) Changed port and signal names, addedd //
// comments //
// //
// //
// //
////////////////////////////////////////////////////////////////////////////////
// sp = special register
// id = instruction decode
// if = instruction fetch
// ex = execute stage
// wb = write back
// data = from data memory
`include "defines.sv"
module wb_stage
(
// MUX SELECTOR --> Used to select what write in the register file
input logic regfile_wdata_mux_sel_i, // Comes from the controller (thru id-ex and ex-wb pipe)
// MUX INPUTS
input logic [31:0] sp_rdata_i, // From the read port of the special register
input logic [31:0] data_rdata_i, // read Data from data memory system
input logic [31:0] lsu_data_reg_i, // read data registered in LSU
// MUX OUTPUT
output logic [31:0] regfile_wdata_o, // write data for register file
output logic [31:0] wdata_reg_o, // goes to pc_mux, origin is always a register!
input logic eoc_i,
output logic eoc_o
);
assign eoc_o = eoc_i;
// Register Write Data Selection --> Data to write in the regfile
// Select between:
// 00,01: From EX stage (Alu Results)
// 10: From Special Register
// 11: From Data Memory
always_comb
begin : REGFILE_WDATA_MUX
casex (regfile_wdata_mux_sel_i)
1'b0: begin regfile_wdata_o <= sp_rdata_i; end
1'b1: begin regfile_wdata_o <= data_rdata_i; end
endcase; // case (regfile_wdata_mux_sel_i)
end
// wdata_reg_o is very similar to regfile_wdata_o, except that the
// output of the LSU is registered. This signal is then used by the PC
// mux instead of regfile_wdata_o in case forwarding is necessary
always_comb
begin : WDATA_FW_MUX
casex (regfile_wdata_mux_sel_i)
1'b0: begin wdata_reg_o <= sp_rdata_i; end
1'b1: begin wdata_reg_o <= lsu_data_reg_i; end
endcase; // case (regfile_wdata_mux_sel_i)
end
endmodule