Merge remote-tracking branch 'origin/master' into exc_ctrl

This commit is contained in:
Andreas Traber 2015-11-17 10:36:15 +01:00
commit c7cec664ac
11 changed files with 432 additions and 301 deletions

4
alu.sv
View file

@ -327,11 +327,11 @@ module riscv_alu
`ALU_XOR: result_o = operand_a_i ^ operand_b_i;
// Shift Operations
`ALU_SLL: result_o = shift_left_result;
`ALU_SLL: result_o = shift_left_result;
`ALU_SRL,
`ALU_SRA,
`ALU_ROR: result_o = shift_result;
`ALU_ROR: result_o = shift_result;
// Extension Operations
`ALU_EXTBZ,

View file

@ -44,7 +44,7 @@ module riscv_compressed_decoder
always_comb
begin
illegal_instr_o = 1'b0;
instr_o = 'X;
instr_o = 'x;
unique case (instr_i[1:0])
// C0
@ -126,30 +126,34 @@ module riscv_compressed_decoder
2'b11: begin
unique case ({instr_i[12], instr_i[6:5]})
3'b001,
3'b000: begin
// c.sub -> sub rd', rd', rs2'
instr_o = {2'b01, 5'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b000, 2'b01, instr_i[9:7], `OPCODE_OP};
end
3'b001: begin
// c.xor -> xor rd', rd', rs2'
instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b100, 2'b01, instr_i[9:7], `OPCODE_OP};
end
3'b010: begin
// c.or -> or rd', rd', rs2'
instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b110, 2'b01, instr_i[9:7], `OPCODE_OP};
end
3'b011: begin
// c.and -> and rd', rd', rs2'
instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b111, 2'b01, instr_i[9:7], `OPCODE_OP};
end
3'b100,
3'b101,
3'b110,
3'b111: begin
// 001: c.sll -> sll rd', rd', rs2'
// 100: c.xor -> xor rd', rd', rs2'
// 101: c.srl -> srl rd', rd', rs2'
// 110: c.or -> or rd', rd', rs2'
// 111: c.and -> and rd', rd', rs2'
instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], instr_i[12], instr_i[6:5], 2'b01, instr_i[9:7], `OPCODE_OP};
end
3'b000,
3'b010: begin
// 000: c.addw
// 010: c.subw
// 100: c.subw
// 101: c.addw
illegal_instr_o = 1'b1;
end
3'b011: begin
// c.sub -> sub rd', rd', rs2'
instr_o = {2'b01, 5'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b000, 2'b01, instr_i[9:7], `OPCODE_OP};
end
endcase
end
endcase

View file

@ -127,7 +127,7 @@ module riscv_controller
enum logic [3:0] { RESET, BOOT_SET, SLEEP, FIRST_FETCH,
DECODE, BRANCH_DELAY,
FLUSH_EX, FLUSH_WB,
DBG_SIGNAL, DBG_WAIT } ctrl_fsm_cs, ctrl_fsm_ns;
DBG_WAIT_BRANCH, DBG_SIGNAL, DBG_WAIT } ctrl_fsm_cs, ctrl_fsm_ns;
logic reg_d_ex_is_reg_a_id;
logic reg_d_ex_is_reg_b_id;
@ -319,17 +319,19 @@ module riscv_controller
// take care of debug
// branch conditional will be handled in next state
if(trap_hit_i && jump_in_dec_i != `BRANCH_COND)
if (trap_hit_i)
begin
// halt pipeline immediately
halt_if_o = 1'b1;
halt_id_o = 1'b1;
// TODO: take a second look at this
// make sure the current instruction has been executed
// before changing state to non-decode
//if (~stall_ex_o)
ctrl_fsm_ns = DBG_SIGNAL;
if (id_valid_i) begin
if (jump_in_id_i == `BRANCH_COND)
ctrl_fsm_ns = DBG_WAIT_BRANCH;
else
ctrl_fsm_ns = DBG_SIGNAL;
end
end
end
else
@ -367,13 +369,26 @@ module riscv_controller
ctrl_fsm_ns = DECODE;
end
// a branch was in ID when a debug trap is hit
DBG_WAIT_BRANCH:
begin
halt_if_o = 1'b1;
if (branch_decision_i) begin
// there is a branch in the EX stage that is taken
pc_mux_sel_o = `PC_BRANCH;
pc_set_o = 1'b1;
end
ctrl_fsm_ns = DBG_SIGNAL;
end
// now we can signal to the debugger that our pipeline is empty and it
// can examine our current state
DBG_SIGNAL:
begin
dbg_trap_o = 1'b1;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
ctrl_fsm_ns = DBG_WAIT;
end
@ -383,19 +398,15 @@ module riscv_controller
DBG_WAIT:
begin
halt_if_o = 1'b1;
halt_id_o = 1'b1;
if(dbg_set_npc_i == 1'b1) begin
halt_id_o = 1'b0;
pc_mux_sel_o = `PC_DBG_NPC;
pc_set_o = 1'b1;
ctrl_fsm_ns = DBG_WAIT;
end
if(dbg_stall_i == 1'b0) begin
halt_if_o = 1'b0;
halt_id_o = 1'b0;
ctrl_fsm_ns = DECODE;
ctrl_fsm_ns = BRANCH_DELAY;
end
end
@ -403,7 +414,6 @@ module riscv_controller
FLUSH_EX:
begin
halt_if_o = 1'b1;
halt_id_o = 1'b1;
if(ex_valid_i)
ctrl_fsm_ns = FLUSH_WB;
@ -413,7 +423,6 @@ module riscv_controller
FLUSH_WB:
begin
halt_if_o = 1'b1;
halt_id_o = 1'b1;
if (~fetch_enable_i) begin
// we are requested to go to sleep
@ -422,7 +431,6 @@ module riscv_controller
end else begin
// unstall pipeline and continue operation
halt_if_o = 1'b0;
halt_id_o = 1'b0;
if (id_valid_i)
ctrl_fsm_ns = DECODE;

View file

@ -31,17 +31,18 @@ module riscv_cs_registers
)
(
// Clock and Reset
input logic clk,
input logic rst_n,
input logic clk,
input logic rst_n,
// Core and Cluster ID
input logic [4:0] core_id_i,
input logic [4:0] cluster_id_i,
input logic [4:0] core_id_i,
input logic [4:0] cluster_id_i,
// Interface to registers (SRAM like)
input logic [11:0] csr_addr_i,
input logic [31:0] csr_wdata_i,
input logic [1:0] csr_op_i,
input logic csr_access_i,
input logic [11:0] csr_addr_i,
input logic [31:0] csr_wdata_i,
input logic [1:0] csr_op_i,
output logic [31:0] csr_rdata_o,
// Interrupts
@ -270,29 +271,32 @@ module riscv_cs_registers
pccr_index = '0;
perf_rdata = '0;
unique case (csr_addr_i)
12'h7A0: begin
is_pcer = 1'b1;
perf_rdata[N_PERF_COUNTERS-1:0] = PCER_q;
end
12'h7A1: begin
is_pcmr = 1'b1;
perf_rdata[1:0] = PCMR_q;
end
12'h79F: begin
is_pccr = 1'b1;
pccr_all_sel = 1'b1;
end
default:;
endcase
// only perform csr access if we actually care about the read data
if (csr_access_i) begin
unique case (csr_addr_i)
12'h7A0: begin
is_pcer = 1'b1;
perf_rdata[N_PERF_COUNTERS-1:0] = PCER_q;
end
12'h7A1: begin
is_pcmr = 1'b1;
perf_rdata[1:0] = PCMR_q;
end
12'h79F: begin
is_pccr = 1'b1;
pccr_all_sel = 1'b1;
end
default:;
endcase
// look for 780 to 79F, Performance Counter Counter Registers
if (csr_addr_i[11:5] == 7'b0111100) begin
is_pccr = 1'b1;
// look for 780 to 79F, Performance Counter Counter Registers
if (csr_addr_i[11:5] == 7'b0111100) begin
is_pccr = 1'b1;
pccr_index = csr_addr_i[4:0];
pccr_index = csr_addr_i[4:0];
perf_rdata = PCCR_q[csr_addr_i[4:0]];
perf_rdata = PCCR_q[csr_addr_i[4:0]];
end
end
end

View file

@ -5,15 +5,16 @@
// //
// Additional contributions by: //
// Andreas Traber - atraber@student.ethz.ch //
// Sven Stucki - svstucki@student.ethz.ch //
// //
// //
// Create Date: 11/07/2014 //
// Design Name: Pipelined OpenRISC Processor //
// Design Name: RISC-V processor core //
// Module Name: debug_unit.sv //
// Project Name: OR10N //
// Project Name: RI5CY //
// Language: SystemVerilog //
// //
// Description: Debug Controller for the pipelined processor //
// Description: Debug controller //
// //
// //
// Revision: //
@ -22,9 +23,6 @@
// changed port and signal names //
// //
// //
// //
// //
// //
////////////////////////////////////////////////////////////////////////////////
@ -32,59 +30,68 @@
module riscv_debug_unit
(
input logic clk,
input logic rst_n,
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,
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 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 trap_i,
output logic stall_core_o,
output logic flush_pipe_o,
input logic trap_i,
output logic sp_mux_o,
output logic regfile_mux_o,
output logic regfile_we_o,
output logic [11:0] regfile_addr_o,
output logic [31:0] regfile_wdata_o,
input logic [31:0] regfile_rdata_i,
output logic sp_mux_o,
output logic regfile_mux_o,
output logic regfile_we_o,
output logic [11:0] regfile_addr_o,
output logic [31:0] regfile_wdata_o,
input logic [31:0] regfile_rdata_i,
// Signals for PPC & NPC register
input logic [31:0] curr_pc_if_i,
input logic [31:0] curr_pc_id_i,
input logic [31:0] curr_pc_if_i,
input logic [31:0] curr_pc_id_i,
input logic [31:0] branch_pc_i,
input logic [1:0] jump_in_ex_i,
input logic branch_taken_i,
output logic [31:0] npc_o,
output logic set_npc_o
);
);
// 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 [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
// BP control FSM
enum logic [2:0] {Idle, Trap, DebugStall, StallCore} BP_State_SN, BP_State_SP;
enum logic [2:0] {Idle, Trap, DebugStall, StallCore} BP_State_SN, BP_State_SP;
// ppc/npc tracking
enum logic [1:0] {IFID, IFEX, IDEX} pc_tracking_fsm_cs, pc_tracking_fsm_ns;
logic [31:0] ppc_int, npc_int;
// ack to debug interface
assign dbginf_ack_o = dbginf_strobe_i && ((BP_State_SP == StallCore) || (dbginf_addr_i[15:11] == 5'b00110));
always_comb
begin
BP_State_SN = BP_State_SP;
stall_core_o = 1'b0;
dbginf_bp_o = 1'b0;
flush_pipe_o = 1'b0;
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:
@ -152,15 +159,15 @@ module riscv_debug_unit
// 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])
case (dbginf_addr_i[10:0])
11'd0: begin // NPC
set_npc_o = dbginf_we_i;
dbginf_data_o = curr_pc_if_i;
dbginf_data_o = npc_int;
end
11'd1: begin // PPC
dbginf_data_o = curr_pc_id_i;
dbginf_data_o = ppc_int;
end
11'd16: begin // SP_DMR1
@ -169,6 +176,7 @@ module riscv_debug_unit
else
dbginf_data_o[`DMR1_ST+1:`DMR1_ST] = DMR1_DP;
end
11'd20: begin // SP_DSR
// currently we only handle IIE and INTE
if(dbginf_we_i == 1'b1)
@ -176,8 +184,9 @@ module riscv_debug_unit
else
dbginf_data_o[7:6] = DSR_DP[1:0];
end
default: ;
endcase // casex [10:0]
endcase
end
// check if internal registers (GPR or SPR) are accessed
else if(BP_State_SP == StallCore)
@ -196,8 +205,8 @@ module riscv_debug_unit
// some other SPR is accessed
else
begin
sp_mux_o = 1'b1;
regfile_addr_o = dbginf_addr_i[11:0];
sp_mux_o = 1'b1;
regfile_addr_o = dbginf_addr_i[11:0];
if(dbginf_we_i == 1'b1)
regfile_we_o = 1'b1;
@ -208,18 +217,67 @@ module riscv_debug_unit
end
end
// normal FF setup
always_ff@(posedge clk or negedge rst_n) begin
if (~rst_n) begin
DMR1_DP <= 2'b0;
DSR_DP <= 'b0;
BP_State_SP <= Idle;
always_comb
begin
pc_tracking_fsm_ns = pc_tracking_fsm_cs;
ppc_int = curr_pc_id_i;
npc_int = curr_pc_if_i;
// PPC/NPC mux
unique case (pc_tracking_fsm_cs)
IFID: begin
ppc_int = curr_pc_id_i;
npc_int = curr_pc_if_i;
end
IFEX: begin
ppc_int = branch_pc_i;
npc_int = curr_pc_if_i;
end
IDEX: begin
ppc_int = branch_pc_i;
npc_int = curr_pc_id_i;
if (set_npc_o)
pc_tracking_fsm_ns = IFEX;
end
default: begin
pc_tracking_fsm_ns = IFID;
end
endcase
// set state if trap is encountered
if (stall_core_o && (BP_State_SP != StallCore)) begin
pc_tracking_fsm_ns = IFID;
if (jump_in_ex_i == `BRANCH_COND) begin
if (branch_taken_i)
pc_tracking_fsm_ns = IFEX;
else
pc_tracking_fsm_ns = IDEX;
end
end
end
always_ff@(posedge clk, negedge rst_n)
begin
if (rst_n == 1'b0) begin
DMR1_DP <= 2'b0;
DSR_DP <= 'b0;
BP_State_SP <= Idle;
pc_tracking_fsm_cs <= IFID;
end
else begin
DMR1_DP <= DMR1_DN;
DSR_DP <= DSR_DN;
BP_State_SP <= BP_State_SN;
DMR1_DP <= DMR1_DN;
DSR_DP <= DSR_DN;
BP_State_SP <= BP_State_SN;
pc_tracking_fsm_cs <= pc_tracking_fsm_ns;
end
end // always_ff@ (posedge clk or negedge rst_n)
end
endmodule // debug_unit

View file

@ -81,8 +81,8 @@ module riscv_decoder
// hwloop signals
output logic [2:0] hwloop_we_o, // write enable for hwloop regs
output logic hwloop_target_mux_sel_o, // selects immediate for hwloop target
output logic hwloop_start_mux_sel_o, // selects hwloop start address input
output logic hwloop_end_mux_sel_o, // selects hwloop end address input
output logic hwloop_cnt_mux_sel_o, // selects hwloop counter input
// jump/branches
@ -144,8 +144,8 @@ module riscv_decoder
prepost_useincr_o = 1'b1;
hwloop_we = 3'b0;
hwloop_target_mux_sel_o = 1'b0;
hwloop_start_mux_sel_o = 1'b0;
hwloop_end_mux_sel_o = 1'b0;
hwloop_cnt_mux_sel_o = 1'b0;
csr_access_o = 1'b0;
@ -577,7 +577,7 @@ module riscv_decoder
///////////////////////////////////////////////
`OPCODE_HWLOOP: begin
jump_target_mux_sel_o = `JT_HWLP; // get PC + I imm from jump target adder
hwloop_target_mux_sel_o = 1'b0;
unique case (instr_rdata_i[14:12])
3'b000: begin
@ -585,31 +585,44 @@ module riscv_decoder
hwloop_we[0] = 1'b1;
hwloop_start_mux_sel_o = 1'b0;
end
3'b001: begin
// lp.endi: set end address to PC + I-type immediate
hwloop_we[1] = 1'b1;
hwloop_end_mux_sel_o = 1'b0; // jump target
end
3'b010: begin
// lp.count: initialize counter from rs1
hwloop_we[2] = 1'b1;
hwloop_cnt_mux_sel_o = 1'b1;
rega_used_o = 1'b1;
end
3'b011: begin
// lp.counti: initialize counter from I-type immediate
hwloop_we[2] = 1'b1;
hwloop_cnt_mux_sel_o = 1'b0;
end
3'b100: begin
// lp.setup: initialize counter from rs1, set start address to
// next instruction and end address to PC + I-type immediate
hwloop_we = 3'b111;
hwloop_start_mux_sel_o = 1'b1;
hwloop_end_mux_sel_o = 1'b0;
hwloop_cnt_mux_sel_o = 1'b1;
rega_used_o = 1'b1;
end
3'b101: begin
// lp.setupi: initialize counter from rs1, set start address to
// next instruction and end address to PC + I-type immediate
hwloop_we = 3'b111;
hwloop_target_mux_sel_o = 1'b1;
hwloop_start_mux_sel_o = 1'b1;
hwloop_cnt_mux_sel_o = 1'b1;
rega_used_o = 1'b1;
end
default: begin
illegal_insn_o = 1'b1;
end

View file

@ -38,7 +38,9 @@ module riscv_id_stage
input logic clk,
input logic rst_n,
input logic fetch_enable_i,
input logic test_en_i,
input logic fetch_enable_i,
output logic core_busy_o,
output logic is_decoding_o,
@ -81,7 +83,9 @@ module riscv_id_stage
input logic ex_valid_i, // EX stage is done
input logic wb_valid_i, // WB stage is done
// To the Pipeline ID/EX
// Pipeline ID/EX
output logic [31:0] branch_pc_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,
@ -253,10 +257,11 @@ module riscv_id_stage
logic [1:0] hwloop_regid;
logic [2:0] hwloop_we;
logic hwloop_jump;
logic hwloop_target_mux_sel;
logic hwloop_start_mux_sel;
logic hwloop_end_mux_sel;
logic hwloop_cnt_mux_sel;
logic [31:0] hwloop_target;
logic [31:0] hwloop_start;
logic [31:0] hwloop_end;
logic [31:0] hwloop_cnt;
@ -332,23 +337,26 @@ module riscv_id_stage
// hwloop register id
assign hwloop_regid = instr[8:7]; // rd contains hwloop register id
// hwloop target mux
always_comb
begin
unique case (hwloop_target_mux_sel)
1'b0: hwloop_target = current_pc_id_i + imm_i_type;
1'b1: hwloop_target = current_pc_id_i + {imm_z_type[30:0], 1'b0};
endcase
end
// hwloop start mux
always_comb
begin
unique case (hwloop_start_mux_sel)
1'b0: hwloop_start = jump_target; // for PC + I imm
1'b0: hwloop_start = hwloop_target; // for PC + I imm
1'b1: hwloop_start = current_pc_if_i; // for next PC
endcase
end
// hwloop end mux
always_comb
begin
unique case (hwloop_end_mux_sel)
1'b0: hwloop_end = jump_target; // for PC + I imm
1'b1: hwloop_end = jump_target; // TODO: PC + (Z imm << 1) for lp.setupi
endcase
end
assign hwloop_end = hwloop_target;
// hwloop cnt mux
always_comb
@ -373,9 +381,11 @@ module riscv_id_stage
begin : jump_target_mux
unique case (jump_target_mux_sel)
`JT_JAL: jump_target = current_pc_id_i + imm_uj_type;
`JT_JALR: jump_target = regfile_data_ra_id + imm_i_type; // cannot forward rs1 as path is too long
`JT_COND: jump_target = current_pc_id_i + imm_sb_type;
`JT_HWLP: jump_target = current_pc_id_i + imm_i_type;
// JALR: Cannot forward RS1, since the path is too long
`JT_JALR: jump_target = regfile_data_ra_id + imm_i_type;
default: jump_target = regfile_data_ra_id + imm_i_type;
endcase
end
@ -503,6 +513,8 @@ module riscv_id_stage
.clk ( clk ),
.rst_n ( rst_n ),
.test_en_i ( test_en_i ),
// Read port a
.raddr_a_i ( regfile_addr_ra_id ),
.rdata_a_o ( regfile_data_ra_id ),
@ -592,8 +604,8 @@ module riscv_id_stage
// hwloop signals
.hwloop_we_o ( hwloop_we ),
.hwloop_target_mux_sel_o ( hwloop_target_mux_sel ),
.hwloop_start_mux_sel_o ( hwloop_start_mux_sel ),
.hwloop_end_mux_sel_o ( hwloop_end_mux_sel ),
.hwloop_cnt_mux_sel_o ( hwloop_cnt_mux_sel ),
// jump/branches
@ -804,6 +816,18 @@ module riscv_id_stage
// |___|____/ |_____/_/\_\ |_| |___|_| |_____|_____|___|_| \_|_____| //
// //
/////////////////////////////////////////////////////////////////////////////////
always_ff @(posedge clk, negedge rst_n)
begin
if (rst_n == 1'b0)
begin
branch_pc_ex_o <= '0;
end
else begin
if (jump_in_id_o == `BRANCH_COND && id_valid_o)
branch_pc_ex_o <= current_pc_id_i;
end
end
always_ff @(posedge clk, negedge rst_n)
begin : ID_EX_PIPE_REGISTERS
if (rst_n == 1'b0)

View file

@ -85,6 +85,7 @@ module riscv_if_stage
// from debug unit
input logic [31:0] dbg_npc_i,
input logic dbg_set_npc_i,
// pipeline stall
input logic halt_if_i,
@ -353,7 +354,7 @@ module riscv_if_stage
// take care of jumps and branches
// only send one branch request per jump/branch
if (branch_req_Q == 1'b0) begin
if (dbg_set_npc_i || (branch_req_Q == 1'b0)) begin
if (pc_set_i) begin
valid = 1'b0;

View file

@ -56,10 +56,10 @@
`define OPCODE_CUST1 7'h2b
// PULP custom
`define OPCODE_STORE_POST 7'h27
`define OPCODE_LOAD_POST 7'h07
`define OPCODE_HWLOOP 7'h6b
`define OPCODE_PULP_OP 7'h57
`define OPCODE_LOAD_POST 7'h0b
`define OPCODE_STORE_POST 7'h2b
`define OPCODE_PULP_OP 7'h5b
`define OPCODE_HWLOOP 7'h7b
// instruction masks (for tracer)
@ -280,7 +280,6 @@
`define BRANCH_COND 2'b11 // conditional branches
// jump target mux
`define JT_HWLP 2'b00
`define JT_JAL 2'b01
`define JT_JALR 2'b10
`define JT_COND 2'b11

View file

@ -1,154 +1,156 @@
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;
logic [DATA_WIDTH-1:0] MemContentxDP[NUM_WORDS];
logic [NUM_WORDS-1:1] WAddrOneHotxDa;
logic [NUM_WORDS-1:1] WAddrOneHotxDb;
logic [NUM_WORDS-1:1] WAddrOneHotxDb_reg;
logic [NUM_WORDS-1:1] 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;
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
module riscv_register_file
#(
parameter ADDR_WIDTH = 5,
parameter DATA_WIDTH = 32
)
(
// Clock and Reset
input logic clk,
input logic rst_n,
input logic test_en_i,
//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;
logic [DATA_WIDTH-1:0] MemContentxDP[NUM_WORDS];
logic [NUM_WORDS-1:1] WAddrOneHotxDa;
logic [NUM_WORDS-1:1] WAddrOneHotxDb;
logic [NUM_WORDS-1:1] WAddrOneHotxDb_reg;
logic [NUM_WORDS-1:1] 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;
genvar x;
genvar y;
assign we_int = we_a_i | we_b_i;
cluster_clock_gating CG_WE_GLOBAL
(
.clk_i ( clk ),
.en_i ( we_int ),
.test_en_i ( test_en_i ),
.clk_o ( clk_int )
);
//-----------------------------------------------------------------------------
//-- 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_i ( clk_int ),
.en_i ( WAddrOneHotxDa[x] | WAddrOneHotxDb[x] ),
.test_en_i ( test_en_i ),
.clk_o ( ClocksxC[x] )
);
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

View file

@ -38,6 +38,8 @@ module riscv_core
input logic clk,
input logic rst_n,
input logic test_en_i, // enable all clock gates for testing
// Core ID, Cluster ID and boot address are considered more or less static
input logic [31:0] boot_addr_i,
input logic [4:0] core_id_i,
@ -117,6 +119,8 @@ module riscv_core
logic if_busy;
logic [31:0] branch_pc_ex; // PC of last executed branch
// ALU Control
logic [`ALU_OP_WIDTH-1:0] alu_operator_ex;
logic [31:0] alu_operand_a_ex;
@ -148,6 +152,7 @@ module riscv_core
logic csr_access_ex;
logic [1:0] csr_op_ex;
logic csr_access;
logic [1:0] csr_op;
logic [11:0] csr_addr;
logic [31:0] csr_rdata;
@ -276,6 +281,7 @@ module riscv_core
// from debug unit
.dbg_npc_i ( dbg_npc ),
.dbg_set_npc_i ( dbg_set_npc ),
// Jump and branch target and decision
.jump_in_id_i ( jump_in_id ),
@ -308,6 +314,8 @@ module riscv_core
.clk ( clk ),
.rst_n ( rst_n ),
.test_en_i ( test_en_i ),
// Processor Enable
.fetch_enable_i ( fetch_enable_i ),
.core_busy_o ( core_busy ),
@ -353,6 +361,7 @@ module riscv_core
.wb_valid_i ( wb_valid ),
// From the Pipeline ID/EX
.branch_pc_ex_o ( branch_pc_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 ),
@ -573,6 +582,7 @@ module riscv_core
.cluster_id_i ( cluster_id_i ),
// Interface to CSRs (SRAM like)
.csr_access_i ( csr_access_ex ),
.csr_addr_i ( csr_addr ),
.csr_wdata_i ( csr_wdata ),
.csr_op_i ( csr_op ),
@ -608,11 +618,13 @@ module riscv_core
);
// Mux for CSR access through Debug Unit
assign csr_addr = (dbg_sp_mux == 1'b0) ? alu_operand_b_ex[11:0] : dbg_reg_addr;
assign csr_wdata = (dbg_sp_mux == 1'b0) ? alu_operand_a_ex : dbg_reg_wdata;
assign csr_op = (dbg_sp_mux == 1'b0) ? csr_op_ex
: (dbg_reg_we == 1'b1 ? `CSR_OP_WRITE : `CSR_OP_NONE);
assign dbg_rdata = (dbg_sp_mux == 1'b0) ? dbg_reg_rdata : csr_rdata;
assign csr_access = (dbg_sp_mux == 1'b0) ? csr_access_ex : 1'b1;
assign csr_addr = (dbg_sp_mux == 1'b0) ? alu_operand_b_ex[11:0] : dbg_reg_addr;
assign csr_wdata = (dbg_sp_mux == 1'b0) ? alu_operand_a_ex : dbg_reg_wdata;
assign csr_op = (dbg_sp_mux == 1'b0) ? csr_op_ex
: (dbg_reg_we == 1'b1 ? `CSR_OP_WRITE
: `CSR_OP_NONE );
assign dbg_rdata = (dbg_sp_mux == 1'b0) ? dbg_reg_rdata : csr_rdata;
/////////////////////////////////////////////////////////////
@ -642,13 +654,14 @@ module riscv_core
// 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 ),
.trap_i ( dbg_trap ),
// register file access
.regfile_mux_o ( dbg_reg_mux ),
.sp_mux_o ( dbg_sp_mux ),
.regfile_mux_o ( dbg_reg_mux ),
.regfile_we_o ( dbg_reg_we ),
.regfile_addr_o ( dbg_reg_addr ),
.regfile_wdata_o ( dbg_reg_wdata ),
@ -657,6 +670,11 @@ module riscv_core
// signals for PPC and NPC
.curr_pc_if_i ( current_pc_if ), // from IF stage
.curr_pc_id_i ( current_pc_id ), // from IF stage
.branch_pc_i ( branch_pc_ex ), // PC of last executed branch (in EX stage)
.jump_in_ex_i ( jump_in_ex ),
.branch_taken_i ( branch_decision ),
.npc_o ( dbg_npc ), // PC from debug unit
.set_npc_o ( dbg_set_npc ) // set PC to new value
);