mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-22 05:07:21 -04:00
Merge 83203c1585
into 733743da0f
This commit is contained in:
commit
78b219e6c4
9 changed files with 1407 additions and 515 deletions
|
@ -198,4 +198,10 @@ ${CVA6_REPO_DIR}/core/cva6_mmu/cva6_ptw.sv
|
|||
${CVA6_REPO_DIR}/core/cva6_mmu/cva6_tlb.sv
|
||||
${CVA6_REPO_DIR}/core/cva6_mmu/cva6_shared_tlb.sv
|
||||
|
||||
//Trace Interface
|
||||
${CVA6_REPO_DIR}/core/cva6_te_connector/include/connector_pkg.sv
|
||||
${CVA6_REPO_DIR}/core/cva6_te_connector/rtl/cva6_te_connector.sv
|
||||
${CVA6_REPO_DIR}/core/cva6_te_connector/rtl/fsm.sv
|
||||
${CVA6_REPO_DIR}/core/cva6_te_connector/rtl/itype_detector.sv
|
||||
|
||||
// end of manifest
|
||||
|
|
|
@ -1774,6 +1774,7 @@ module cva6
|
|||
.exception_t (exception_t),
|
||||
.scoreboard_entry_t (scoreboard_entry_t),
|
||||
.lsu_ctrl_t (lsu_ctrl_t),
|
||||
.bp_resolve_t (bp_resolve_t),
|
||||
.rvfi_probes_instr_t(rvfi_probes_instr_t),
|
||||
.rvfi_probes_csr_t (rvfi_probes_csr_t),
|
||||
.rvfi_probes_t (rvfi_probes_t)
|
||||
|
@ -1809,7 +1810,7 @@ module cva6
|
|||
|
||||
.csr_i(rvfi_csr),
|
||||
.irq_i(irq_i),
|
||||
|
||||
.resolved_branch_i(resolved_branch),
|
||||
.rvfi_probes_o(rvfi_probes_o)
|
||||
|
||||
);
|
||||
|
|
|
@ -16,6 +16,7 @@ module cva6_rvfi_probes
|
|||
parameter type exception_t = logic,
|
||||
parameter type scoreboard_entry_t = logic,
|
||||
parameter type lsu_ctrl_t = logic,
|
||||
parameter type bp_resolve_t = logic,
|
||||
parameter type rvfi_probes_instr_t = logic,
|
||||
parameter type rvfi_probes_csr_t = logic,
|
||||
parameter type rvfi_probes_t = logic
|
||||
|
@ -52,6 +53,7 @@ module cva6_rvfi_probes
|
|||
|
||||
input rvfi_probes_csr_t csr_i,
|
||||
input logic [1:0] irq_i,
|
||||
input bp_resolve_t resolved_branch_i,
|
||||
|
||||
output rvfi_probes_t rvfi_probes_o
|
||||
);
|
||||
|
@ -81,6 +83,11 @@ module cva6_rvfi_probes
|
|||
|
||||
instr.ex_commit_cause = ex_commit_i.cause;
|
||||
instr.ex_commit_valid = ex_commit_i.valid;
|
||||
if (CVA6Cfg.TvalEn) begin
|
||||
instr.tval = ex_commit_i.tval;
|
||||
end else begin
|
||||
instr.tval = '0;
|
||||
end
|
||||
|
||||
instr.priv_lvl = priv_lvl_i;
|
||||
|
||||
|
@ -109,6 +116,9 @@ module cva6_rvfi_probes
|
|||
instr.commit_ack = commit_ack_i;
|
||||
instr.wdata = wdata_i;
|
||||
|
||||
instr.branch_valid = resolved_branch_i.valid;
|
||||
instr.is_taken = resolved_branch_i.is_taken;
|
||||
|
||||
csr = csr_i;
|
||||
csr.mip_q = csr_i.mip_q | ({{CVA6Cfg.XLEN - 1{1'b0}}, CVA6Cfg.RVS && irq_i[1]} << riscv::IRQ_S_EXT);
|
||||
|
||||
|
|
48
core/cva6_te_connector/include/connector_pkg.sv
Executable file
48
core/cva6_te_connector/include/connector_pkg.sv
Executable file
|
@ -0,0 +1,48 @@
|
|||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Author: Umberto Laghi
|
||||
// Contact: umberto.laghi@studio.unibo.it
|
||||
// Github: @ubolakes
|
||||
// Contributors:
|
||||
// Darshak Sheladiya, SYSGO GmbH
|
||||
// Maxime COLSON, Thales
|
||||
|
||||
package connector_pkg;
|
||||
// These parameters could be used in the ENCODER stage
|
||||
localparam CAUSE_LEN = 5; //Size is ecause_width_p in the E-Trace SPEC
|
||||
localparam ITYPE_LEN = 3; //Size is itype_width_p in the E-Trace SPEC (3 or 4)
|
||||
localparam IRETIRE_LEN = 32; //Size is iretire_width_p in the E-Trace SPEC
|
||||
//localparam TIME_LEN = 64; //rvfi_csr used logic [63:0] cycle_q but TIME_LEN could be used in the ENCODER stage
|
||||
|
||||
// struct to save all itypes
|
||||
// refer to page 21 of the spec
|
||||
// The enum could be used in the ENCODER stage
|
||||
typedef enum logic [ITYPE_LEN-1:0] {
|
||||
STD = 0, // none of the other named itype codes
|
||||
EXC = 1, // exception
|
||||
INT = 2, // interrupt
|
||||
ERET = 3, // exception or interrupt return
|
||||
NTB = 4, // nontaken branch
|
||||
TB = 5, // taken branch
|
||||
UIJ = 6, // uninferable jump if ITYPE_LEN == 3, otherwise reserved
|
||||
RES = 7 /*, // reserved
|
||||
UC = 8, // uninferable call
|
||||
IC = 9, // inferable call
|
||||
UIJ = 10, // uninferable jump
|
||||
IJ = 11, // inferable jump
|
||||
CRS = 12, // co-routine swap
|
||||
RET = 13, // return
|
||||
OUIJ = 14, // other uninferable jump
|
||||
OIJ = 15*/ // other inferable jump
|
||||
} itype_t;
|
||||
|
||||
endpackage
|
399
core/cva6_te_connector/rtl/cva6_te_connector.sv
Executable file
399
core/cva6_te_connector/rtl/cva6_te_connector.sv
Executable file
|
@ -0,0 +1,399 @@
|
|||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Author: Umberto Laghi
|
||||
// Contact: umberto.laghi@studio.unibo.it
|
||||
// Github: @ubolakes
|
||||
// Contributors:
|
||||
// Darshak Sheladiya, SYSGO GmbH
|
||||
// Maxime COLSON, Thales
|
||||
|
||||
/* TOP LEVEL MODULE */
|
||||
|
||||
module cva6_te_connector #(
|
||||
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
|
||||
parameter N = 2, // max number of special inst in a cycle
|
||||
parameter FIFO_DEPTH = 16 // number of entries in each FIFO
|
||||
) (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
||||
/* data from the CPU */
|
||||
// inputs
|
||||
input logic [CVA6Cfg.NrCommitPorts-1:0] valid_i, // commit_ack in cva6
|
||||
// necessary inputs from scoreboard_entry_t
|
||||
input logic [CVA6Cfg.NrCommitPorts-1:0][CVA6Cfg.XLEN-1:0] pc_i,
|
||||
input ariane_pkg::fu_op [CVA6Cfg.NrCommitPorts-1:0] op_i,
|
||||
input logic [CVA6Cfg.NrCommitPorts-1:0] is_compressed_i,
|
||||
// necessary inputs from bp_resolve_t
|
||||
input logic branch_valid_i,
|
||||
input logic is_taken_i,
|
||||
// necessary inputs from exception_t
|
||||
input logic ex_valid_i,
|
||||
input logic [CVA6Cfg.XLEN-1:0] tval_i,
|
||||
input logic [CVA6Cfg.XLEN-1:0] cause_i,
|
||||
input riscv::priv_lvl_t priv_lvl_i,
|
||||
//input logic [connector_pkg::CTX_LEN-1:0] context_i, // non mandatory
|
||||
input logic [63:0] time_i, // non mandatory
|
||||
//input logic [connector_pkg::CTYPE_LEN-1:0] ctype_i, // non mandatory
|
||||
//input logic [CVA6Cfg.NrCommitPorts-1:0][connector_pkg::SIJ_LEN-1] sijump_i // non mandatory
|
||||
|
||||
// outputs
|
||||
/* the output of the module goes directly into the trace_encoder module */
|
||||
output logic [N-1:0] valid_o,
|
||||
output logic [N-1:0][connector_pkg::IRETIRE_LEN-1:0] iretire_o,
|
||||
output logic [N-1:0] ilastsize_o,
|
||||
output logic [N-1:0][connector_pkg::ITYPE_LEN-1:0] itype_o,
|
||||
output logic [connector_pkg::CAUSE_LEN-1:0] cause_o,
|
||||
output logic [CVA6Cfg.XLEN-1:0] tval_o,
|
||||
output riscv::priv_lvl_t priv_o,
|
||||
output logic [N-1:0][CVA6Cfg.XLEN-1:0] iaddr_o,
|
||||
//output logic [connector_pkg::CTX_LEN-1:0] context_o, // non mandatory
|
||||
output logic [63:0] time_o // non mandatory
|
||||
//output logic [connector_pkg::CTYPE_LEN-1:0] ctype_o, // non mandatory
|
||||
//output logic [connector_pkg::SIJ_LEN-1] sijump_o // non mandatory
|
||||
);
|
||||
// struct to store data inside the uop FIFO
|
||||
localparam type uop_entry_t = struct packed {
|
||||
logic valid;
|
||||
logic [CVA6Cfg.XLEN-1:0] pc;
|
||||
logic [connector_pkg::ITYPE_LEN-1:0] itype; // determined in itype detector
|
||||
logic compressed;
|
||||
riscv::priv_lvl_t priv;
|
||||
};
|
||||
// entries for the FIFOs
|
||||
uop_entry_t [CVA6Cfg.NrCommitPorts-1:0] uop_entry_i, uop_entry_o;
|
||||
uop_entry_t uop_entry_mux;
|
||||
logic [CVA6Cfg.NrCommitPorts-1:0][connector_pkg::ITYPE_LEN-1:0] itype;
|
||||
// FIFOs management
|
||||
logic pop[CVA6Cfg.NrCommitPorts-1:0]; // signal to pop FIFOs
|
||||
logic empty[CVA6Cfg.NrCommitPorts-1:0]; // signal used to enable counter
|
||||
logic full[CVA6Cfg.NrCommitPorts-1:0];
|
||||
logic push_enable[CVA6Cfg.NrCommitPorts-1:0];
|
||||
// mux arbiter management
|
||||
logic [$clog2(CVA6Cfg.NrCommitPorts-1):0] mux_arb_val;
|
||||
logic clear_mux_arb;
|
||||
logic enable_mux_arb;
|
||||
// demux arbiter management
|
||||
logic [$clog2(N):0] demux_arb_val;
|
||||
logic clear_demux_arb;
|
||||
logic enable_demux_arb;
|
||||
// itype_detector
|
||||
logic is_taken_d, is_taken_q;
|
||||
logic interrupt;
|
||||
// block counter management
|
||||
logic n_blocks_full;
|
||||
logic n_blocks_empty;
|
||||
logic [$clog2(N):0] n_blocks_i, n_blocks_o;
|
||||
logic n_blocks_push;
|
||||
logic n_blocks_pop;
|
||||
// struct to store exc and int infos
|
||||
localparam type exc_info_t = struct packed {
|
||||
logic [connector_pkg::CAUSE_LEN-1:0] cause;
|
||||
logic [CVA6Cfg.XLEN-1:0] tval;
|
||||
};
|
||||
// exception signals
|
||||
exc_info_t exc_info_i, exc_info_o;
|
||||
logic exc_info_full;
|
||||
logic exc_info_empty;
|
||||
logic exc_info_pop;
|
||||
// signals to store blocks
|
||||
logic valid_fsm;
|
||||
logic [ N-1:0][connector_pkg::IRETIRE_LEN-1:0] iretire_q;
|
||||
logic [ N-1:0] ilastsize_q;
|
||||
logic [ N-1:0][ connector_pkg::ITYPE_LEN-1:0] itype_q;
|
||||
logic [ connector_pkg::CAUSE_LEN-1:0] cause_q;
|
||||
logic [ CVA6Cfg.XLEN-1:0] tval_q;
|
||||
logic [ N-1:0][ CVA6Cfg.XLEN-1:0] iaddr_q;
|
||||
|
||||
logic [connector_pkg::IRETIRE_LEN-1:0] iretire_d;
|
||||
logic ilastsize_d;
|
||||
logic [ connector_pkg::ITYPE_LEN-1:0] itype_d;
|
||||
logic [ connector_pkg::CAUSE_LEN-1:0] cause_d;
|
||||
logic [ CVA6Cfg.XLEN-1:0] tval_d;
|
||||
logic [ CVA6Cfg.XLEN-1:0] iaddr_d;
|
||||
|
||||
// assignments
|
||||
assign pop[0] = (mux_arb_val == 0 ||
|
||||
uop_entry_o[0].itype == 1 ||
|
||||
uop_entry_o[0].itype == 2) &&
|
||||
!empty[0];
|
||||
assign pop[1] = (mux_arb_val == 1 ||
|
||||
uop_entry_o[1].itype == 1 ||
|
||||
uop_entry_o[1].itype == 2) &&
|
||||
!empty[1];
|
||||
|
||||
assign clear_mux_arb = (mux_arb_val == CVA6Cfg.NrCommitPorts-1 ||
|
||||
uop_entry_o[0].itype == 1 ||
|
||||
uop_entry_o[0].itype == 2) &&
|
||||
!empty[0];
|
||||
assign enable_mux_arb = !empty[0]; // the counter goes on if FIFOs are not empty
|
||||
assign is_taken_d = is_taken_i;
|
||||
assign n_blocks_push = !n_blocks_full && n_blocks_i > 0;
|
||||
assign clear_demux_arb = n_blocks_pop; // demux_arb_val+1 == n_blocks_o && n_blocks_o > 0 && |valid_o;
|
||||
assign enable_demux_arb = valid_fsm; // && n_blocks_o > 1;
|
||||
assign exc_info_pop = valid_o[0] && (itype_o[0] == 1 || itype_o[0] == 2) && !exc_info_empty;
|
||||
assign exc_info_i.tval = tval_i;
|
||||
assign exc_info_i.cause = cause_i[connector_pkg::CAUSE_LEN-1:0];
|
||||
assign uop_entry_mux = empty[0] ? '0 : uop_entry_o[mux_arb_val];
|
||||
assign interrupt = cause_i[CVA6Cfg.XLEN-1]; // determinated based on the MSB of cause
|
||||
|
||||
/* itype_detectors */
|
||||
for (genvar i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin
|
||||
itype_detector i_itype_detector (
|
||||
.valid_i (valid_i[i]),
|
||||
.exception_i (ex_valid_i),
|
||||
.interrupt_i (interrupt),
|
||||
.op_i (op_i[i]),
|
||||
.branch_taken_i(is_taken_q),
|
||||
.itype_o (itype[i])
|
||||
);
|
||||
end
|
||||
|
||||
/* FIFOs */
|
||||
/* commit ports FIFOs */
|
||||
for (genvar i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin
|
||||
fifo_v3 #(
|
||||
.DEPTH(FIFO_DEPTH),
|
||||
.dtype(uop_entry_t)
|
||||
) i_fifo_uop (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.flush_i ('0),
|
||||
.testmode_i('0),
|
||||
.full_o (full[i]),
|
||||
.empty_o (empty[i]),
|
||||
.usage_o (),
|
||||
.data_i (uop_entry_i[i]),
|
||||
.push_i (push_enable[i] && !full[i]),
|
||||
.data_o (uop_entry_o[i]),
|
||||
.pop_i (pop[i])
|
||||
);
|
||||
end
|
||||
|
||||
// FIFO to store the n_blocks
|
||||
fifo_v3 #(
|
||||
.DEPTH(FIFO_DEPTH),
|
||||
.dtype(exc_info_t)
|
||||
) i_nblock_fifo (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.flush_i ('0),
|
||||
.testmode_i('0),
|
||||
.full_o (exc_info_full),
|
||||
.empty_o (exc_info_empty),
|
||||
.usage_o (),
|
||||
.data_i (exc_info_i),
|
||||
.push_i ((ex_valid_i || interrupt) && !exc_info_full),
|
||||
.data_o (exc_info_o),
|
||||
.pop_i (exc_info_pop)
|
||||
);
|
||||
|
||||
// FIFO to store exc and int info
|
||||
fifo_v3 #(
|
||||
.DEPTH(FIFO_DEPTH),
|
||||
.DATA_WIDTH($clog2(N) + 1)
|
||||
) i_exc_info_fifo (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.flush_i ('0),
|
||||
.testmode_i('0),
|
||||
.full_o (n_blocks_full),
|
||||
.empty_o (n_blocks_empty),
|
||||
.usage_o (),
|
||||
.data_i (n_blocks_i),
|
||||
.push_i (n_blocks_push),
|
||||
.data_o (n_blocks_o),
|
||||
.pop_i (n_blocks_pop)
|
||||
);
|
||||
|
||||
// mux arbiter for serialization
|
||||
counter #(
|
||||
.WIDTH($clog2(CVA6Cfg.NrCommitPorts)),
|
||||
.STICKY_OVERFLOW('0)
|
||||
) i_mux_arbiter ( // change name?
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.clear_i (clear_mux_arb),
|
||||
.en_i (enable_mux_arb),
|
||||
.load_i ('0),
|
||||
.down_i ('0),
|
||||
.d_i ('0),
|
||||
.q_o (mux_arb_val),
|
||||
.overflow_o()
|
||||
);
|
||||
|
||||
// fsm to create blocks instantiation
|
||||
fsm #(
|
||||
.CVA6Cfg(CVA6Cfg),
|
||||
.uop_entry_t(uop_entry_t)
|
||||
) i_fsm (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.uop_entry_i(uop_entry_mux),
|
||||
.cause_i (exc_info_o.cause),
|
||||
.tval_i (exc_info_o.tval),
|
||||
.valid_o (valid_fsm),
|
||||
.iretire_o (iretire_d),
|
||||
.ilastsize_o(ilastsize_d),
|
||||
.itype_o (itype_d),
|
||||
.cause_o (cause_d),
|
||||
.tval_o (tval_d),
|
||||
.priv_o (priv_o),
|
||||
.iaddr_o (iaddr_d)
|
||||
);
|
||||
|
||||
// demux arbiter to choose register
|
||||
counter #(
|
||||
.WIDTH($clog2(N) + 1),
|
||||
.STICKY_OVERFLOW('0)
|
||||
) i_demux_arbiter (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.clear_i (clear_demux_arb),
|
||||
.en_i (enable_demux_arb),
|
||||
.load_i ('0),
|
||||
.down_i ('0),
|
||||
.d_i ('0),
|
||||
.q_o (demux_arb_val),
|
||||
.overflow_o()
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
// init
|
||||
n_blocks_i = '0;
|
||||
n_blocks_pop = '0;
|
||||
for (int i = 0; i < N; i++) begin
|
||||
// output
|
||||
valid_o[i] = '0;
|
||||
iretire_o[i] = '0;
|
||||
ilastsize_o[i] = '0;
|
||||
itype_o[i] = '0;
|
||||
cause_o = '0;
|
||||
tval_o = '0;
|
||||
iaddr_o[i] = '0;
|
||||
// uop_entry
|
||||
uop_entry_i[i].valid = '0;
|
||||
uop_entry_i[i].pc = '0;
|
||||
uop_entry_i[i].itype = '0;
|
||||
uop_entry_i[i].compressed = '0;
|
||||
uop_entry_i[i].priv = riscv::PRIV_LVL_U;
|
||||
end
|
||||
|
||||
|
||||
// populating uop FIFO entries
|
||||
for (int i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin
|
||||
uop_entry_i[i].valid = valid_i[i];
|
||||
uop_entry_i[i].pc = pc_i[i];
|
||||
uop_entry_i[i].itype = itype[i];
|
||||
uop_entry_i[i].compressed = is_compressed_i[i];
|
||||
uop_entry_i[i].priv = priv_lvl_i;
|
||||
push_enable[i] = '0;
|
||||
end
|
||||
|
||||
// enabling push in input FIFOs
|
||||
for (int i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin
|
||||
if ((uop_entry_i[i].itype == 1 || uop_entry_i[i].itype == 2) ||
|
||||
((uop_entry_i[i].itype == 0 || uop_entry_i[i].itype > 2) &&
|
||||
uop_entry_i[i].valid)) begin
|
||||
push_enable[i] = 1;
|
||||
end
|
||||
end
|
||||
|
||||
// counting the blocks to emit in one cycle
|
||||
for (int i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin
|
||||
if ((uop_entry_i[i].itype > 2 && uop_entry_i[i].valid)) begin
|
||||
n_blocks_i += 1;
|
||||
end else if (uop_entry_i[i].itype == 1 || uop_entry_i[i].itype == 2) begin
|
||||
/* since the exc and int signal are connected to all itype detectors,
|
||||
a int would require CVA6Cfg.NrCommitPorts blocks, but it's not true and breaks all
|
||||
the system downstream.
|
||||
That's because it would store CVA6Cfg.NrCommitPorts blocks in the FIFO, but since
|
||||
the MUX allows only one uop_entry with itype == 1, the CVA6Cfg.NrCommitPorts blocks
|
||||
would never be produced, causing a deadlock. */
|
||||
n_blocks_i = 1;
|
||||
end
|
||||
end
|
||||
|
||||
// checking if blocks are ready to output
|
||||
// first case: waiting for one block
|
||||
// when it outputs one block can be exc or int
|
||||
if (n_blocks_o == 1 && valid_fsm && !n_blocks_empty) begin
|
||||
valid_o[0] = '1;
|
||||
iretire_o[0] = iretire_d;
|
||||
ilastsize_o[0] = ilastsize_d;
|
||||
itype_o[0] = itype_d;
|
||||
iaddr_o[0] = iaddr_d;
|
||||
// setting cause and tval for exc or int
|
||||
if (itype_o[0] == 1 || itype_o[0] == 2) begin
|
||||
cause_o = cause_d;
|
||||
tval_o = tval_d;
|
||||
end
|
||||
// popping the nblocks FIFO
|
||||
n_blocks_pop = '1;
|
||||
end
|
||||
|
||||
// second case: waiting for N blocks
|
||||
// when more blocks are output they
|
||||
// are not exc or int, but other disc
|
||||
if (n_blocks_o > 1 && demux_arb_val == n_blocks_o - 1 && valid_fsm && n_blocks_empty) begin
|
||||
// leaving to 0 cause and tval since they are not necessary
|
||||
// setting block specific data
|
||||
for (int i = 0; i < n_blocks_o; i++) begin
|
||||
valid_o[i] = '1;
|
||||
if (i == n_blocks_o - 1) begin
|
||||
iretire_o[i] = iretire_d;
|
||||
ilastsize_o[i] = ilastsize_d;
|
||||
itype_o[i] = itype_d;
|
||||
iaddr_o[i] = iaddr_d;
|
||||
end else begin
|
||||
iretire_o[i] = iretire_q[i];
|
||||
ilastsize_o[i] = ilastsize_q[i];
|
||||
itype_o[i] = itype_q[i];
|
||||
iaddr_o[i] = iaddr_q[i];
|
||||
end
|
||||
end
|
||||
// popping the nblocks FIFO
|
||||
n_blocks_pop = '1;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i, negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
is_taken_q <= '0;
|
||||
for (int i = 0; i < N; i++) begin
|
||||
iretire_q[i] <= '0;
|
||||
ilastsize_q[i] <= '0;
|
||||
itype_q[i] <= '0;
|
||||
cause_q <= '0;
|
||||
tval_q <= '0;
|
||||
iaddr_q[i] <= '0;
|
||||
end
|
||||
end else begin
|
||||
if (branch_valid_i) begin
|
||||
is_taken_q <= is_taken_d;
|
||||
end
|
||||
if (valid_fsm) begin
|
||||
iretire_q[demux_arb_val] <= iretire_d;
|
||||
ilastsize_q[demux_arb_val] <= ilastsize_d;
|
||||
itype_q[demux_arb_val] <= itype_d;
|
||||
cause_q <= cause_d;
|
||||
tval_q <= tval_d;
|
||||
iaddr_q[demux_arb_val] <= iaddr_d;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
assign time_o = time_i;
|
||||
|
||||
|
||||
endmodule
|
253
core/cva6_te_connector/rtl/fsm.sv
Executable file
253
core/cva6_te_connector/rtl/fsm.sv
Executable file
|
@ -0,0 +1,253 @@
|
|||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Author: Umberto Laghi
|
||||
// Contact: umberto.laghi@studio.unibo.it
|
||||
// Github: @ubolakes
|
||||
// Contributors:
|
||||
// Darshak Sheladiya, SYSGO GmbH
|
||||
// Maxime COLSON, Thales
|
||||
|
||||
/* FSM */
|
||||
/*
|
||||
it determines the iaddr, ilastsize, iretire
|
||||
*/
|
||||
|
||||
module fsm #(
|
||||
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
|
||||
parameter type uop_entry_t = logic
|
||||
) (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
||||
input uop_entry_t uop_entry_i,
|
||||
input logic [connector_pkg::CAUSE_LEN-1:0] cause_i,
|
||||
input logic [ CVA6Cfg.XLEN-1:0] tval_i,
|
||||
|
||||
output logic valid_o,
|
||||
output logic [connector_pkg::IRETIRE_LEN-1:0] iretire_o,
|
||||
output logic ilastsize_o,
|
||||
output logic [ connector_pkg::ITYPE_LEN-1:0] itype_o,
|
||||
output logic [ connector_pkg::CAUSE_LEN-1:0] cause_o,
|
||||
output logic [ CVA6Cfg.XLEN-1:0] tval_o,
|
||||
output riscv::priv_lvl_t priv_o,
|
||||
output logic [ CVA6Cfg.XLEN-1:0] iaddr_o
|
||||
);
|
||||
typedef enum logic {
|
||||
IDLE = 0,
|
||||
COUNT = 1
|
||||
} state_t;
|
||||
|
||||
/* internal signals */
|
||||
state_t current_state, next_state;
|
||||
logic [CVA6Cfg.XLEN-1:0] iaddr_d, iaddr_q;
|
||||
logic [CVA6Cfg.XLEN-1:0] iretire_d, iretire_q;
|
||||
logic ilastsize_d, ilastsize_q;
|
||||
logic exception;
|
||||
logic interrupt;
|
||||
logic special_inst;
|
||||
logic one_cycle;
|
||||
logic update_iaddr;
|
||||
logic update_iretire;
|
||||
|
||||
/* assignments */
|
||||
assign exception = uop_entry_i.itype == 1;
|
||||
assign interrupt = uop_entry_i.itype == 2;
|
||||
assign special_inst = uop_entry_i.itype > 2 && uop_entry_i.valid;
|
||||
assign iretire_o = iretire_d;
|
||||
assign iaddr_o = one_cycle ? iaddr_d : iaddr_q;
|
||||
|
||||
// combinatorial logic for state transition
|
||||
always_comb begin
|
||||
// next_state default value
|
||||
next_state = current_state;
|
||||
// init
|
||||
valid_o = '0;
|
||||
iretire_d = '0;
|
||||
ilastsize_d = '0;
|
||||
ilastsize_o = '0;
|
||||
itype_o = '0;
|
||||
cause_o = '0;
|
||||
tval_o = '0;
|
||||
priv_o = riscv::PRIV_LVL_U;
|
||||
iaddr_d = '0;
|
||||
one_cycle = '0;
|
||||
update_iaddr = '0;
|
||||
update_iretire = '0;
|
||||
|
||||
case (current_state)
|
||||
IDLE: begin
|
||||
if (uop_entry_i.itype == 0 && uop_entry_i.valid) begin // standard instr and valid
|
||||
// sets iaddr, increases iretire
|
||||
iaddr_d = uop_entry_i.pc;
|
||||
update_iaddr = '1;
|
||||
iretire_d = uop_entry_i.compressed ? 1 : 2;
|
||||
// saving ilastsize in case next cycle
|
||||
// there is an exc or int w/out retired inst
|
||||
ilastsize_d = !uop_entry_i.compressed;
|
||||
// saving iretire value
|
||||
update_iretire = '1;
|
||||
// goes to COUNT
|
||||
next_state = COUNT;
|
||||
end else if (special_inst) begin // special inst as first inst
|
||||
// set all params for output
|
||||
iaddr_d = uop_entry_i.pc;
|
||||
ilastsize_o = !uop_entry_i.compressed;
|
||||
itype_o = uop_entry_i.itype;
|
||||
// cause and tval not necessary
|
||||
priv_o = uop_entry_i.priv;
|
||||
// output readable
|
||||
valid_o = '1;
|
||||
// read now the output
|
||||
one_cycle = '1;
|
||||
// remains here
|
||||
next_state = IDLE;
|
||||
end else if (interrupt) begin
|
||||
itype_o = uop_entry_i.itype;
|
||||
cause_o = cause_i;
|
||||
// checks if an inst is committed in the same cycle
|
||||
if (uop_entry_i.valid) begin
|
||||
// setting iretire, ilastsize, iaddr
|
||||
iaddr_d = uop_entry_i.pc;
|
||||
iretire_d = uop_entry_i.compressed ? 1 : 2;
|
||||
ilastsize_o = !uop_entry_i.compressed;
|
||||
priv_o = uop_entry_i.priv;
|
||||
end else begin
|
||||
// setting iretire and ilastsize as the values stored
|
||||
iretire_d = iretire_q;
|
||||
ilastsize_o = ilastsize_q;
|
||||
end
|
||||
// output readable
|
||||
valid_o = '1;
|
||||
// read now the output
|
||||
one_cycle = '1;
|
||||
// remains here
|
||||
next_state = IDLE;
|
||||
end else if (exception) begin
|
||||
itype_o = uop_entry_i.itype;
|
||||
cause_o = cause_i;
|
||||
tval_o = tval_i;
|
||||
// checks if an inst is committed in the same cycle
|
||||
if (uop_entry_i.valid) begin
|
||||
// setting iretire, ilastsize, iaddr
|
||||
iaddr_d = uop_entry_i.pc;
|
||||
iretire_d = uop_entry_i.compressed ? 1 : 2;
|
||||
ilastsize_o = !uop_entry_i.compressed;
|
||||
priv_o = uop_entry_i.priv;
|
||||
end else begin
|
||||
// setting iretire and ilastsize as the values stored
|
||||
iretire_d = iretire_q;
|
||||
ilastsize_o = ilastsize_q;
|
||||
end
|
||||
// output readable
|
||||
valid_o = '1;
|
||||
// read now the output
|
||||
one_cycle = '1;
|
||||
// remains here
|
||||
next_state = IDLE;
|
||||
end else begin
|
||||
next_state = IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
COUNT: begin
|
||||
if (uop_entry_i.itype == 0 && uop_entry_i.valid) begin // standard inst
|
||||
// increases iretire
|
||||
iretire_d = uop_entry_i.compressed ? iretire_q + 1 : iretire_q + 2;
|
||||
// saving ilastsize in case next cycle
|
||||
// there is an exc or int w/out retired inst
|
||||
ilastsize_d = !uop_entry_i.compressed;
|
||||
// saving iretire value
|
||||
update_iretire = '1;
|
||||
// remains here
|
||||
next_state = COUNT;
|
||||
end else if (special_inst) begin
|
||||
// set all params for output
|
||||
iretire_d = uop_entry_i.compressed ? iretire_q + 1 : iretire_q + 2;
|
||||
ilastsize_o = !uop_entry_i.compressed;
|
||||
itype_o = uop_entry_i.itype;
|
||||
// cause and tval not necessary
|
||||
priv_o = uop_entry_i.priv;
|
||||
// output readable
|
||||
valid_o = '1;
|
||||
// goes to IDLE
|
||||
next_state = IDLE;
|
||||
end else if (interrupt) begin
|
||||
itype_o = uop_entry_i.itype;
|
||||
cause_o = cause_i;
|
||||
// checks if an inst is committed in the same cycle
|
||||
if (uop_entry_i.valid) begin
|
||||
// setting iretire, ilastsize
|
||||
iretire_d = uop_entry_i.compressed ? iretire_q + 1 : iretire_q + 2;
|
||||
ilastsize_o = !uop_entry_i.compressed;
|
||||
priv_o = uop_entry_i.priv;
|
||||
end else begin
|
||||
// setting iretire and ilastsize as the values stored
|
||||
iretire_d = iretire_q;
|
||||
ilastsize_o = ilastsize_q;
|
||||
end
|
||||
// output readable
|
||||
valid_o = '1;
|
||||
// remains here
|
||||
next_state = IDLE;
|
||||
end else if (exception) begin
|
||||
itype_o = uop_entry_i.itype;
|
||||
cause_o = cause_i;
|
||||
tval_o = tval_i;
|
||||
// checks if an inst is committed in the same cycle
|
||||
if (uop_entry_i.valid) begin
|
||||
// setting iretire, ilastsize
|
||||
iretire_d = uop_entry_i.compressed ? iretire_q + 1 : iretire_q + 2;
|
||||
ilastsize_o = !uop_entry_i.compressed;
|
||||
priv_o = uop_entry_i.priv;
|
||||
end else begin
|
||||
// setting iretire and ilastsize as the values stored
|
||||
iretire_d = iretire_q;
|
||||
ilastsize_o = ilastsize_q;
|
||||
end
|
||||
// output readable
|
||||
valid_o = '1;
|
||||
// remains here
|
||||
next_state = IDLE;
|
||||
end else begin
|
||||
next_state = COUNT;
|
||||
end
|
||||
end
|
||||
|
||||
endcase
|
||||
end
|
||||
|
||||
// sequential logic
|
||||
always_ff @(posedge clk_i, negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
current_state <= IDLE;
|
||||
iaddr_q <= '0;
|
||||
iretire_q <= '0;
|
||||
ilastsize_q <= '0;
|
||||
end else begin
|
||||
if (valid_o) begin
|
||||
iretire_q <= '0;
|
||||
end
|
||||
if (update_iaddr) begin
|
||||
iaddr_q <= iaddr_d;
|
||||
end
|
||||
if (update_iretire) begin
|
||||
iretire_q <= iretire_d;
|
||||
end
|
||||
if (uop_entry_i.valid) begin
|
||||
ilastsize_q <= ilastsize_d;
|
||||
end
|
||||
current_state <= next_state;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
endmodule
|
88
core/cva6_te_connector/rtl/itype_detector.sv
Executable file
88
core/cva6_te_connector/rtl/itype_detector.sv
Executable file
|
@ -0,0 +1,88 @@
|
|||
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
||||
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
||||
// may obtain a copy of the License at
|
||||
|
||||
// https://solderpad.org/licenses/SHL-2.1/
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
||||
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
// either express or implied. See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Author: Umberto Laghi
|
||||
// Contact: umberto.laghi@studio.unibo.it
|
||||
// Github: @ubolakes
|
||||
// Contributors:
|
||||
// Darshak Sheladiya, SYSGO GmbH
|
||||
// Maxime COLSON, Thales
|
||||
|
||||
/* ITYPE DETECTOR */
|
||||
/*
|
||||
it produces the type of the instruction
|
||||
*/
|
||||
|
||||
module itype_detector (
|
||||
input logic valid_i,
|
||||
input logic exception_i,
|
||||
input logic interrupt_i,
|
||||
input ariane_pkg::fu_op op_i,
|
||||
input logic branch_taken_i,
|
||||
output logic [connector_pkg::ITYPE_LEN-1:0] itype_o
|
||||
);
|
||||
|
||||
// internal signals
|
||||
logic exception;
|
||||
logic interrupt;
|
||||
logic eret;
|
||||
logic nontaken_branch;
|
||||
logic taken_branch;
|
||||
logic updiscon;
|
||||
|
||||
// assignments
|
||||
assign exception = exception_i;
|
||||
assign interrupt = interrupt_i; // no need to have an inst committed
|
||||
|
||||
|
||||
|
||||
|
||||
assign eret = (op_i == ariane_pkg::MRET || op_i == ariane_pkg::SRET || op_i == ariane_pkg::DRET);
|
||||
|
||||
assign nontaken_branch = ( op_i == ariane_pkg::EQ ||
|
||||
op_i == ariane_pkg::NE ||
|
||||
op_i == ariane_pkg::LTS ||
|
||||
op_i == ariane_pkg::GES ||
|
||||
op_i == ariane_pkg::LTU ||
|
||||
op_i == ariane_pkg::GEU) &&
|
||||
~branch_taken_i;
|
||||
|
||||
assign taken_branch = ( op_i == ariane_pkg::EQ ||
|
||||
op_i == ariane_pkg::NE ||
|
||||
op_i == ariane_pkg::LTS ||
|
||||
op_i == ariane_pkg::GES ||
|
||||
op_i == ariane_pkg::LTU ||
|
||||
op_i == ariane_pkg::GEU) &&
|
||||
branch_taken_i;
|
||||
|
||||
assign updiscon = op_i == ariane_pkg::JALR;
|
||||
|
||||
// assigning the itype
|
||||
always_comb begin
|
||||
// initialization
|
||||
itype_o = '0;
|
||||
|
||||
if (exception) begin // exception
|
||||
itype_o = 1;
|
||||
end else if (interrupt) begin // interrupt
|
||||
itype_o = 2;
|
||||
end else if (eret && valid_i) begin // exception or interrupt return
|
||||
itype_o = 3;
|
||||
end else if (nontaken_branch && valid_i) begin // nontaken branch
|
||||
itype_o = 4;
|
||||
end else if (taken_branch && valid_i) begin // taken branch
|
||||
itype_o = 5;
|
||||
end else if (connector_pkg::ITYPE_LEN == 3 && updiscon && valid_i) begin // uninferable discontinuity
|
||||
itype_o = 6;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -126,6 +126,9 @@
|
|||
logic [Cfg.PLEN-1:0] mem_paddr; \
|
||||
logic debug_mode; \
|
||||
logic [Cfg.NrCommitPorts-1:0][Cfg.XLEN-1:0] wdata; \
|
||||
logic branch_valid; \
|
||||
logic is_taken; \
|
||||
logic [Cfg.XLEN-1:0] tval; \
|
||||
}
|
||||
|
||||
`define RVFI_PROBES_CSR_T(Cfg) struct packed { \
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue