blob: 888a313d88f1325ca90df2752428216517cd3ab4 [file] [log] [blame]
//////////////////////////////////////////////////////////////////////////////
// SPDX-FileCopyrightText: Syntacore LLC © 2016-2021
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// 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.
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileContributor: Syntacore LLC
// //////////////////////////////////////////////////////////////////////////
/// @file <scr1_pipe_tdu.sv>
/// @brief Trigger Debug Unit (TDU)
///
//------------------------------------------------------------------------------
//
// Functionality:
// - Provides read/write interface for TDU CSRs
// - Provides triggers functionality:
// - Supports triggers either in both Debug and M modes or in Debug mode only
// - Supports virtual address matching (load, store, exec) triggers
// - Supports instruction count triggers
// - Supports the following actions on trigger firing:
// - Breakpoint exception raising
// - Debug Mode entering
// - Supports triggers chaining
//
// Structure:
// - CSR read/write i/f
// - TDU CSRs:
// - TSELECT
// - TDATA1/MCONTROL/ICOUNT
// - TDATA2
// - TINFO
// - TDU <-> EXU i/f
// - TDU <-> LSU i/f
// - TDU <-> HDU i/f
//------------------------------------------------------------------------------
`include "scr1_arch_description.svh"
`ifdef SCR1_TDU_EN
`include "scr1_riscv_isa_decoding.svh"
`include "scr1_tdu.svh"
module scr1_pipe_tdu (
// Common signals
input logic rst_n, // TDU reset
input logic clk, // TDU clock
input logic clk_en, // TDU clock enable
input logic tdu_dsbl_i, // TDU Disable
// TDU <-> CSR interface
input logic csr2tdu_req_i, // CSR-TDU i/f request
input type_scr1_csr_cmd_sel_e csr2tdu_cmd_i, // CSR-TDU i/f command
input logic [SCR1_CSR_ADDR_TDU_OFFS_W-1:0] csr2tdu_addr_i, // CSR-TDU i/f address
input logic [SCR1_TDU_DATA_W-1:0] csr2tdu_wdata_i, // CSR-TDU i/f write data
output logic [SCR1_TDU_DATA_W-1:0] tdu2csr_rdata_o, // CSR-TDU i/f read data
output type_scr1_csr_resp_e tdu2csr_resp_o, // CSR-TDU i/f response
// TDU <-> EXU interface
input type_scr1_brkm_instr_mon_s exu2tdu_imon_i, // Instruction stream monitoring
output logic [SCR1_TDU_ALLTRIG_NUM-1 : 0] tdu2exu_ibrkpt_match_o, // Instruction BP match
output logic tdu2exu_ibrkpt_exc_req_o, // Instruction BP exception request
input logic [SCR1_TDU_ALLTRIG_NUM-1 : 0] exu2tdu_bp_retire_i, // Map of BPs being retired
// TDU <-> LSU interface
`ifndef SCR1_TDU_EN
output logic tdu2lsu_brk_en_o, // TDU-LSU Breakpoint enable
`endif // SCR1_TDU_EN
output logic tdu2lsu_ibrkpt_exc_req_o, // TDU-LSU Instruction BP exception request
input type_scr1_brkm_lsu_mon_s lsu2tdu_dmon_i, // TDU-LSU Data address stream monitoring
output logic [SCR1_TDU_MTRIG_NUM-1 : 0] tdu2lsu_dbrkpt_match_o, // TDU-LSU Data BP match
output logic tdu2lsu_dbrkpt_exc_req_o, // TDU-LSU Data BP exception request
// TDU <-> HDU interface
output logic tdu2hdu_dmode_req_o // Debug Mode redirection request
);
//------------------------------------------------------------------------------
// Local parameters declaration
//------------------------------------------------------------------------------
localparam int unsigned MTRIG_NUM = SCR1_TDU_MTRIG_NUM;
localparam int unsigned ALLTRIG_NUM = SCR1_TDU_ALLTRIG_NUM;
localparam int unsigned ALLTRIG_W = $clog2(ALLTRIG_NUM+1);
//------------------------------------------------------------------------------
// Local signals declaration
//------------------------------------------------------------------------------
// TDU CSRs read/write i/f signals
//------------------------------------------------------------------------------
// Write signals
logic csr_wr_req;
logic [SCR1_TDU_DATA_W-1:0] csr_wr_data;
// Register select
logic csr_addr_tselect;
logic [MTRIG_NUM-1:0] csr_addr_mcontrol;
logic [MTRIG_NUM-1:0] csr_addr_tdata2;
`ifdef SCR1_TDU_ICOUNT_EN
logic csr_addr_icount;
`endif // SCR1_TDU_ICOUNT_EN
// TDU CSRs
//------------------------------------------------------------------------------
// TSELECT register
logic csr_tselect_upd;
logic [ALLTRIG_W-1:0] csr_tselect_ff;
// MCONTROL register
logic [MTRIG_NUM-1:0] csr_mcontrol_wr_req;
logic [MTRIG_NUM-1:0] csr_mcontrol_clk_en;
logic [MTRIG_NUM-1:0] csr_mcontrol_upd;
logic [MTRIG_NUM-1:0] csr_mcontrol_dmode_ff;
logic [MTRIG_NUM-1:0] csr_mcontrol_dmode_next;
logic [MTRIG_NUM-1:0] csr_mcontrol_m_ff;
logic [MTRIG_NUM-1:0] csr_mcontrol_m_next;
logic [MTRIG_NUM-1:0] csr_mcontrol_exec_ff;
logic [MTRIG_NUM-1:0] csr_mcontrol_exec_next;
logic [MTRIG_NUM-1:0] csr_mcontrol_load_ff;
logic [MTRIG_NUM-1:0] csr_mcontrol_load_next;
logic [MTRIG_NUM-1:0] csr_mcontrol_store_ff;
logic [MTRIG_NUM-1:0] csr_mcontrol_store_next;
logic [MTRIG_NUM-1:0] csr_mcontrol_action_ff;
logic [MTRIG_NUM-1:0] csr_mcontrol_action_next;
logic [MTRIG_NUM-1:0] csr_mcontrol_hit_ff;
logic [MTRIG_NUM-1:0] csr_mcontrol_hit_next;
logic [MTRIG_NUM-1:0] csr_mcontrol_exec_hit;
logic [MTRIG_NUM-1:0] csr_mcontrol_ldst_hit;
// ICOUNT register
`ifdef SCR1_TDU_ICOUNT_EN
logic csr_icount_wr_req;
logic csr_icount_clk_en;
logic csr_icount_upd;
logic csr_icount_dmode_ff;
logic csr_icount_dmode_next;
logic csr_icount_m_ff;
logic csr_icount_m_next;
logic csr_icount_action_ff;
logic csr_icount_action_next;
logic csr_icount_hit_ff;
logic csr_icount_hit_next;
logic [SCR1_TDU_ICOUNT_COUNT_HI-SCR1_TDU_ICOUNT_COUNT_LO:0]
csr_icount_count_ff;
logic [SCR1_TDU_ICOUNT_COUNT_HI-SCR1_TDU_ICOUNT_COUNT_LO:0]
csr_icount_count_next;
logic csr_icount_skip_ff;
logic csr_icount_skip_next;
logic csr_icount_decr_en;
logic csr_icount_count_decr;
logic csr_icount_skip_dsbl;
logic csr_icount_hit;
`endif // SCR1_TDU_ICOUNT_EN
// TDATA2 register
logic [MTRIG_NUM-1:0] csr_tdata2_upd;
logic [MTRIG_NUM-1:0] csr_tdata2_ff [SCR1_TDU_DATA_W-1:0];
//------------------------------------------------------------------------------
// CSR read/write interface
//------------------------------------------------------------------------------
// Read logic
//------------------------------------------------------------------------------
assign tdu2csr_resp_o = csr2tdu_req_i ? SCR1_CSR_RESP_OK : SCR1_CSR_RESP_ER;
integer i;
always_comb begin
i = 0; // yosys latch warning fix
tdu2csr_rdata_o = '0;
if (csr2tdu_req_i) begin
case (csr2tdu_addr_i)
SCR1_CSR_ADDR_TDU_OFFS_TSELECT: begin
tdu2csr_rdata_o = {'0, csr_tselect_ff};
end
SCR1_CSR_ADDR_TDU_OFFS_TDATA2 : begin
for(i = 0; i < MTRIG_NUM; i=i+1) begin // cp.4
if(csr_tselect_ff == ALLTRIG_W'(i)) begin
tdu2csr_rdata_o = csr_tdata2_ff[i];
end
end
end
SCR1_CSR_ADDR_TDU_OFFS_TDATA1 : begin
for(i = 0; i < MTRIG_NUM; i=i+1) begin // cp.4
if(csr_tselect_ff == ALLTRIG_W'(i)) begin
tdu2csr_rdata_o[SCR1_TDU_TDATA1_TYPE_HI:
SCR1_TDU_TDATA1_TYPE_LO] = SCR1_TDU_MCONTROL_TYPE_VAL;
tdu2csr_rdata_o[SCR1_TDU_TDATA1_DMODE] = csr_mcontrol_dmode_ff[i];
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_MASKMAX_HI:
SCR1_TDU_MCONTROL_MASKMAX_LO] = SCR1_TDU_MCONTROL_MASKMAX_VAL;
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_HIT] = csr_mcontrol_hit_ff[i];
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_SELECT] = SCR1_TDU_MCONTROL_SELECT_VAL;
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_TIMING] = SCR1_TDU_MCONTROL_TIMING_VAL;
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_ACTION_HI:
SCR1_TDU_MCONTROL_ACTION_LO] = {5'b0, csr_mcontrol_action_ff[i]};
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_CHAIN] = 1'b0;
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_MATCH_HI:
SCR1_TDU_MCONTROL_MATCH_LO] = 4'b0;
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_M] = csr_mcontrol_m_ff[i];
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_RESERVEDA] = SCR1_TDU_MCONTROL_RESERVEDA_VAL;
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_S] = 1'b0;
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_U] = 1'b0;
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_EXECUTE] = csr_mcontrol_exec_ff [i];
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_STORE] = csr_mcontrol_store_ff[i];
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_LOAD] = csr_mcontrol_load_ff [i];
end
end
`ifdef SCR1_TDU_ICOUNT_EN
if(csr_tselect_ff == ALLTRIG_W'(SCR1_TDU_ALLTRIG_NUM - 1'b1)) begin
tdu2csr_rdata_o[SCR1_TDU_TDATA1_TYPE_HI:
SCR1_TDU_TDATA1_TYPE_LO] = SCR1_TDU_ICOUNT_TYPE_VAL;
tdu2csr_rdata_o[SCR1_TDU_TDATA1_DMODE] = csr_icount_dmode_ff;
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_HIT] = csr_icount_hit_ff;
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_COUNT_HI:
SCR1_TDU_ICOUNT_COUNT_LO] = csr_icount_count_ff;
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_U] = 1'b0;
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_S] = 1'b0;
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_M] = csr_icount_m_ff;
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_ACTION_HI:
SCR1_TDU_ICOUNT_ACTION_LO] = {5'b0, csr_icount_action_ff};
end
`endif // SCR1_TDU_ICOUNT_EN
end
SCR1_CSR_ADDR_TDU_OFFS_TINFO : begin
for(i = 0; i < MTRIG_NUM; i=i+1) begin // cp.4
if(csr_tselect_ff == ALLTRIG_W'(i)) begin
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_TYPE_VAL] = 1'b1;
end
end
`ifdef SCR1_TDU_ICOUNT_EN
if(csr_tselect_ff == ALLTRIG_W'(SCR1_TDU_ALLTRIG_NUM - 1'b1)) begin
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_TYPE_VAL] = 1'b1;
end
`endif // SCR1_TDU_ICOUNT_EN
end
default : begin
end
endcase
end
end
// Write logic
//------------------------------------------------------------------------------
always_comb begin
csr_wr_req = 1'b0;
csr_wr_data = '0;
case (csr2tdu_cmd_i)
SCR1_CSR_CMD_WRITE: begin
csr_wr_req = 1'b1;
csr_wr_data = csr2tdu_wdata_i;
end
SCR1_CSR_CMD_SET : begin
csr_wr_req = |csr2tdu_wdata_i;
csr_wr_data = tdu2csr_rdata_o | csr2tdu_wdata_i;
end
SCR1_CSR_CMD_CLEAR: begin
csr_wr_req = |csr2tdu_wdata_i;
csr_wr_data = tdu2csr_rdata_o & ~csr2tdu_wdata_i;
end
default : begin
end
endcase
end
// Register selection
//------------------------------------------------------------------------------
integer k;
always_comb begin
k = 0; // yosys latch warning fix
csr_addr_tselect = 1'b0;
csr_addr_tdata2 = '0;
csr_addr_mcontrol = '0;
`ifdef SCR1_TDU_ICOUNT_EN
csr_addr_icount = '0;
`endif // SCR1_TDU_ICOUNT_EN
if (csr2tdu_req_i) begin
case (csr2tdu_addr_i)
SCR1_CSR_ADDR_TDU_OFFS_TSELECT: begin
csr_addr_tselect = 1'b1;
end
SCR1_CSR_ADDR_TDU_OFFS_TDATA1 : begin
for(k = 0; k < MTRIG_NUM; k=k+1) begin
if(csr_tselect_ff == ALLTRIG_W'(k)) begin
csr_addr_mcontrol[k] = 1'b1;
end
end
`ifdef SCR1_TDU_ICOUNT_EN
if(csr_tselect_ff == ALLTRIG_W'(SCR1_TDU_ALLTRIG_NUM - 1'b1)) begin
csr_addr_icount = 1'b1;
end
`endif // SCR1_TDU_ICOUNT_EN
end
SCR1_CSR_ADDR_TDU_OFFS_TDATA2 : begin
for(k = 0; k < MTRIG_NUM; k=k+1) begin // cp.4
if(csr_tselect_ff == ALLTRIG_W'(k) ) begin
csr_addr_tdata2[k] = 1'b1;
end
end
end
default : begin
end
endcase
end
end
//------------------------------------------------------------------------------
// TDU CSRs
//------------------------------------------------------------------------------
//
// TDU CSRs consist of the following registers:
// - TSELECT
// - TDATA1/MCONTROL/ICOUNT (depending on the type field value)
// - TDATA2
//
// TSELECT register
//------------------------------------------------------------------------------
// Determines which trigger is accessible through the other trigger registers
assign csr_tselect_upd = clk_en & csr_addr_tselect & csr_wr_req
& (csr_wr_data[ALLTRIG_W-1:0] < ALLTRIG_W'(ALLTRIG_NUM));
always_ff @(negedge rst_n, posedge clk) begin
if(~rst_n) begin
csr_tselect_ff <= '0;
end else if(csr_tselect_upd) begin
csr_tselect_ff <= csr_wr_data[ALLTRIG_W-1:0];
end
end
`ifdef SCR1_TDU_ICOUNT_EN
// ICOUNT register
//------------------------------------------------------------------------------
// Provides a trigger that fires when the certain number of instructions has retired
// Is intended to be used as a single step trigger (in this case count must be 1)
assign csr_icount_wr_req = csr_addr_icount & csr_wr_req;
assign csr_icount_clk_en = clk_en & (csr_icount_wr_req | csr_icount_m_ff);
assign csr_icount_upd = ~csr_icount_dmode_ff
? csr_icount_wr_req
: tdu_dsbl_i & csr_icount_wr_req;
always_ff @(negedge rst_n, posedge clk) begin
if(~rst_n) begin
csr_icount_dmode_ff <= 1'b0;
csr_icount_m_ff <= 1'b0;
csr_icount_action_ff <= 1'b0;
csr_icount_hit_ff <= 1'b0;
csr_icount_count_ff <= '0;
csr_icount_skip_ff <= 1'b0;
end else if (csr_icount_clk_en) begin
csr_icount_dmode_ff <= csr_icount_dmode_next;
csr_icount_m_ff <= csr_icount_m_next;
csr_icount_action_ff <= csr_icount_action_next;
csr_icount_hit_ff <= csr_icount_hit_next;
csr_icount_count_ff <= csr_icount_count_next;
csr_icount_skip_ff <= csr_icount_skip_next;
end
end
assign csr_icount_decr_en = (~tdu_dsbl_i & csr_icount_m_ff)
? exu2tdu_imon_i.vd & (csr_icount_count_ff != 14'b0)
: 1'b0;
assign csr_icount_count_decr = exu2tdu_imon_i.req & csr_icount_decr_en & ~csr_icount_skip_ff;
assign csr_icount_skip_dsbl = exu2tdu_imon_i.req & csr_icount_decr_en & csr_icount_skip_ff;
always_comb begin
if (csr_icount_upd) begin
csr_icount_dmode_next = csr_wr_data[SCR1_TDU_TDATA1_DMODE];
csr_icount_m_next = csr_wr_data[SCR1_TDU_ICOUNT_M];
csr_icount_action_next = (csr_wr_data[SCR1_TDU_ICOUNT_ACTION_HI
:SCR1_TDU_ICOUNT_ACTION_LO] == 'b1);
csr_icount_hit_next = csr_wr_data[SCR1_TDU_ICOUNT_HIT];
csr_icount_count_next = csr_wr_data[SCR1_TDU_ICOUNT_COUNT_HI:SCR1_TDU_ICOUNT_COUNT_LO];
end else begin
csr_icount_dmode_next = csr_icount_dmode_ff;
csr_icount_m_next = csr_icount_m_ff;
csr_icount_action_next = csr_icount_action_ff;
csr_icount_hit_next = exu2tdu_bp_retire_i[ALLTRIG_NUM - 1'b1]
? 1'b1
: csr_icount_hit_ff;
csr_icount_count_next = csr_icount_count_decr
? csr_icount_count_ff - 1'b1
: csr_icount_count_ff;
end
end
assign csr_icount_skip_next = csr_icount_wr_req ? csr_wr_data[SCR1_TDU_ICOUNT_M]
: csr_icount_skip_dsbl ? 1'b0
: csr_icount_skip_ff;
`endif // SCR1_TDU_ICOUNT_EN
// MCONTROL registers
//------------------------------------------------------------------------------
// Provides a trigger that fires on the virtual address (stored in TDATA2) match
// (load, store, exec options supported). Triggers chaining supported
genvar trig;
generate
for (trig = 0; $unsigned(trig) < MTRIG_NUM; trig=trig+1) begin : gblock_mtrig
assign csr_mcontrol_wr_req[trig] = csr_addr_mcontrol[trig] & csr_wr_req;
assign csr_mcontrol_clk_en[trig] = clk_en
& (csr_mcontrol_wr_req[trig] | csr_mcontrol_m_ff[trig]);
assign csr_mcontrol_upd [trig] = ~csr_mcontrol_dmode_ff[trig]
? csr_mcontrol_wr_req[trig]
: tdu_dsbl_i & csr_mcontrol_wr_req[trig];
always_ff @(negedge rst_n, posedge clk) begin
if(~rst_n) begin
csr_mcontrol_dmode_ff [trig] <= 1'b0;
csr_mcontrol_m_ff [trig] <= 1'b0;
csr_mcontrol_exec_ff [trig] <= 1'b0;
csr_mcontrol_load_ff [trig] <= 1'b0;
csr_mcontrol_store_ff [trig] <= 1'b0;
csr_mcontrol_action_ff[trig] <= 1'b0;
csr_mcontrol_hit_ff [trig] <= 1'b0;
end else if(csr_mcontrol_clk_en[trig]) begin
csr_mcontrol_dmode_ff [trig] <= csr_mcontrol_dmode_next[trig];
csr_mcontrol_m_ff [trig] <= csr_mcontrol_m_next[trig];
csr_mcontrol_exec_ff [trig] <= csr_mcontrol_exec_next[trig];
csr_mcontrol_load_ff [trig] <= csr_mcontrol_load_next[trig];
csr_mcontrol_store_ff [trig] <= csr_mcontrol_store_next[trig];
csr_mcontrol_action_ff[trig] <= csr_mcontrol_action_next[trig];
csr_mcontrol_hit_ff [trig] <= csr_mcontrol_hit_next[trig];
end
end
always_comb begin
if (csr_mcontrol_upd[trig]) begin
csr_mcontrol_dmode_next [trig] = csr_wr_data[SCR1_TDU_TDATA1_DMODE];
csr_mcontrol_m_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_M];
csr_mcontrol_exec_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_EXECUTE];
csr_mcontrol_load_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_LOAD];
csr_mcontrol_store_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_STORE];
csr_mcontrol_action_next[trig] = (csr_wr_data[SCR1_TDU_MCONTROL_ACTION_HI
:SCR1_TDU_MCONTROL_ACTION_LO] == 'b1);
csr_mcontrol_hit_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_HIT];
end else begin
csr_mcontrol_dmode_next [trig] = csr_mcontrol_dmode_ff [trig];
csr_mcontrol_m_next [trig] = csr_mcontrol_m_ff [trig];
csr_mcontrol_exec_next [trig] = csr_mcontrol_exec_ff [trig];
csr_mcontrol_load_next [trig] = csr_mcontrol_load_ff [trig];
csr_mcontrol_store_next [trig] = csr_mcontrol_store_ff [trig];
csr_mcontrol_action_next[trig] = csr_mcontrol_action_ff[trig];
csr_mcontrol_hit_next [trig] = exu2tdu_bp_retire_i[trig]
? 1'b1
: csr_mcontrol_hit_ff[trig];
end
end
// TDATA2 register
//------------------------------------------------------------------------------
assign csr_tdata2_upd[trig] = ~csr_mcontrol_dmode_ff[trig]
? clk_en & csr_addr_tdata2[trig] & csr_wr_req
: clk_en & csr_addr_tdata2[trig] & csr_wr_req & tdu_dsbl_i;
always_ff @(posedge clk) begin
if (csr_tdata2_upd[trig]) begin
csr_tdata2_ff[trig] <= csr_wr_data;
end
end
end
endgenerate // gblock_mtrig
//------------------------------------------------------------------------------
// TDU <-> EXU interface
//------------------------------------------------------------------------------
assign csr_icount_hit = ~tdu_dsbl_i & csr_icount_m_ff
? exu2tdu_imon_i.vd & (csr_icount_count_ff == 14'b1) & ~csr_icount_skip_ff
: 1'b0;
`ifndef SCR1_TDU_ICOUNT_EN
assign tdu2exu_ibrkpt_match_o = csr_mcontrol_exec_hit;
assign tdu2exu_ibrkpt_exc_req_o = |csr_mcontrol_exec_hit;
`else
assign tdu2exu_ibrkpt_match_o = {csr_icount_hit, csr_mcontrol_exec_hit};
assign tdu2exu_ibrkpt_exc_req_o = |csr_mcontrol_exec_hit | csr_icount_hit;
`endif // SCR1_TDU_ICOUNT_EN
//------------------------------------------------------------------------------
// TDU <-> LSU interface
//------------------------------------------------------------------------------
// Breakpoint logic
//------------------------------------------------------------------------------
generate
for (trig = 0; $unsigned(trig) < MTRIG_NUM; trig=trig+1) begin : gblock_break_trig
assign csr_mcontrol_exec_hit[trig] = ~tdu_dsbl_i
& csr_mcontrol_m_ff[trig]
& csr_mcontrol_exec_ff[trig]
& exu2tdu_imon_i.vd
& exu2tdu_imon_i.addr == csr_tdata2_ff[trig];
end
endgenerate
`ifndef SCR1_TDU_ICOUNT_EN
assign tdu2lsu_ibrkpt_exc_req_o = |csr_mcontrol_exec_hit;
`else
assign tdu2lsu_ibrkpt_exc_req_o = |csr_mcontrol_exec_hit | csr_icount_hit;
`endif // SCR1_TDU_ICOUNT_EN
// Watchpoint logic
//------------------------------------------------------------------------------
generate
for( trig = 0; $unsigned(trig) < MTRIG_NUM; trig=trig+1 ) begin : gblock_watch_trig
assign csr_mcontrol_ldst_hit[trig] = ~tdu_dsbl_i
& csr_mcontrol_m_ff[trig]
& lsu2tdu_dmon_i.vd
& ( (csr_mcontrol_load_ff [trig] & lsu2tdu_dmon_i.load)
| (csr_mcontrol_store_ff[trig] & lsu2tdu_dmon_i.store))
& lsu2tdu_dmon_i.addr == csr_tdata2_ff[trig];
end
endgenerate
assign tdu2lsu_dbrkpt_match_o = csr_mcontrol_ldst_hit;
assign tdu2lsu_dbrkpt_exc_req_o = |csr_mcontrol_ldst_hit;
`ifndef SCR1_TDU_EN
assign tdu2lsu_brk_en_o = |csr_mcontrol_m_ff | csr_icount_m_ff;
`endif // SCR1_TDU_EN
//------------------------------------------------------------------------------
// TDU <-> HDU interface
//------------------------------------------------------------------------------
integer j;
always_comb begin
tdu2hdu_dmode_req_o = 1'b0;
for(j = 0; j < MTRIG_NUM; j=j+1) begin
tdu2hdu_dmode_req_o |= (csr_mcontrol_action_ff[j] & exu2tdu_bp_retire_i[j]);
end
`ifdef SCR1_TDU_ICOUNT_EN
tdu2hdu_dmode_req_o |= (csr_icount_action_ff & exu2tdu_bp_retire_i[ALLTRIG_NUM-1]);
`endif // SCR1_TDU_ICOUNT_EN
end
`ifdef SCR1_TRGT_SIMULATION
//------------------------------------------------------------------------------
// Assertion
//------------------------------------------------------------------------------
SVA_TDU_X_CONTROL : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown({clk_en, tdu_dsbl_i, csr2tdu_req_i,
exu2tdu_imon_i.vd, lsu2tdu_dmon_i.vd, exu2tdu_bp_retire_i})
) else $error("TDU Error: control signals is X - %0b", {clk_en,
tdu_dsbl_i, csr2tdu_req_i, exu2tdu_imon_i.vd, lsu2tdu_dmon_i.vd, exu2tdu_bp_retire_i});
SVA_DM_X_CLK_EN : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown(clk_en)
) else $error("TDU Error: clk_en control signals is X");
SVA_DM_X_DSBL : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown(tdu_dsbl_i)
) else $error("TDU Error: tdu_dsbl_i control signals is X");
SVA_DM_X_CSR2TDU_REQ : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown(csr2tdu_req_i)
) else $error("TDU Error: csr2tdu_req_i control signals is X");
SVA_DM_X_I_MON_VD : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown(exu2tdu_imon_i.vd)
) else $error("TDU Error: exu2tdu_imon_i.vd control signals is X");
SVA_DM_X_D_MON_VD : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown(lsu2tdu_dmon_i.vd)
) else $error("TDU Error: lsu2tdu_dmon_i.vd control signals is X");
SVA_DM_X_BP_RETIRE : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown(exu2tdu_bp_retire_i)
) else $error("TDU Error: exu2tdu_bp_retire_i control signals is X");
SVA_TDU_X_CSR : assert property (
@(negedge clk) disable iff (~rst_n)
csr2tdu_req_i |-> !$isunknown({csr2tdu_cmd_i,csr2tdu_addr_i})
) else $error("TDU Error: csr is X");
SVA_TDU_XW_CSR : assert property (
@(negedge clk) disable iff (~rst_n)
(csr2tdu_req_i & csr_wr_req) |-> !$isunknown(csr2tdu_wdata_i)
) else $error("TDU Error: csr wdata is X ");
SVA_TDU_X_IMON : assert property (
@(negedge clk) disable iff (~rst_n)
exu2tdu_imon_i.vd |-> !$isunknown({exu2tdu_imon_i.req,exu2tdu_imon_i.addr})
) else $error("TDU Error: imonitor is X");
SVA_TDU_X_DMON : assert property (
@(negedge clk) disable iff (~rst_n)
lsu2tdu_dmon_i.vd |-> !$isunknown({lsu2tdu_dmon_i})
) else $error("TDU Error: dmonitor is X");
`endif // SCR1_TRGT_SIMULATION
endmodule : scr1_pipe_tdu
`endif // SCR1_TDU_EN