blob: c89f36409d0f7d53544187393331396a88c96b6e [file] [log] [blame]
From 85e5139d1cb07b2dd16a5698aff758b06a17c851 Mon Sep 17 00:00:00 2001
From: Michael Schaffner <msf@google.com>
Date: Tue, 25 Oct 2022 18:27:27 -0700
Subject: [PATCH 4/4] Use lowrisc instead of PULP primitives
Signed-off-by: Michael Schaffner <msf@google.com>
diff --git a/src/dm_csrs.sv b/src/dm_csrs.sv
index 581c3f7..ee13a50 100644
--- a/src/dm_csrs.sv
+++ b/src/dm_csrs.sv
@@ -79,6 +79,7 @@ module dm_csrs #(
input logic sberror_valid_i, // bus error occurred
input logic [2:0] sberror_i // bus error occurred
);
+
// the amount of bits we need to represent all harts
localparam int unsigned HartSelLen = (NrHarts == 1) ? 1 : $clog2(NrHarts);
localparam int unsigned NrHartsAligned = 2**HartSelLen;
@@ -86,10 +87,6 @@ module dm_csrs #(
dm::dtm_op_e dtm_op;
assign dtm_op = dm::dtm_op_e'(dmi_req_i.op);
- logic resp_queue_full;
- logic resp_queue_empty;
- logic resp_queue_push;
- logic resp_queue_pop;
localparam dm::dm_csr_e DataEnd = dm::dm_csr_e'(dm::Data0 + {4'h0, dm::DataCount} - 8'h1);
localparam dm::dm_csr_e ProgBufEnd = dm::dm_csr_e'(dm::ProgBuf0 + {4'h0, dm::ProgBufSize} - 8'h1);
@@ -180,9 +177,6 @@ module dm_csrs #(
dm::dmi_resp_t resp_queue_inp;
- assign dmi_resp_valid_o = ~resp_queue_empty;
- assign dmi_req_ready_o = ~resp_queue_full;
- assign resp_queue_push = dmi_req_valid_i & dmi_req_ready_o;
// SBA
assign sbautoincrement_o = sbcs_q.sbautoincrement;
assign sbreadonaddr_o = sbcs_q.sbreadonaddr;
@@ -579,28 +573,29 @@ module dm_csrs #(
assign progbuf_o = progbuf_q;
assign data_o = data_q;
- assign resp_queue_pop = dmi_resp_ready_i & ~resp_queue_empty;
-
assign ndmreset_o = dmcontrol_q.ndmreset;
+ logic unused_testmode;
+ assign unused_testmode = testmode_i;
+
// response FIFO
- fifo_v2 #(
- .dtype ( logic [$bits(dmi_resp_o)-1:0] ),
- .DEPTH ( 2 )
+ prim_fifo_sync #(
+ .Width ($bits(dmi_resp_o)),
+ .Pass (1'b0),
+ .Depth (2)
) i_fifo (
- .clk_i,
- .rst_ni,
- .flush_i ( ~dmi_rst_ni ), // Flush the queue if the DTM is
- // reset
- .testmode_i ( testmode_i ),
- .full_o ( resp_queue_full ),
- .empty_o ( resp_queue_empty ),
- .alm_full_o ( ),
- .alm_empty_o ( ),
- .data_i ( resp_queue_inp ),
- .push_i ( resp_queue_push ),
- .data_o ( dmi_resp_o ),
- .pop_i ( resp_queue_pop )
+ .clk_i ( clk_i ),
+ .rst_ni ( dmi_rst_ni ), // reset only when system is re-set
+ .clr_i ( 1'b0 ),
+ .wdata_i ( resp_queue_inp ),
+ .wvalid_i( dmi_req_valid_i ),
+ .wready_o( dmi_req_ready_o ),
+ .rdata_o ( dmi_resp_o ),
+ .rvalid_o( dmi_resp_valid_o ),
+ .rready_i( dmi_resp_ready_i ),
+ .full_o ( ), // Unused
+ .depth_o ( ), // Unused
+ .err_o ( ) // Unused
);
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
diff --git a/src/dmi_cdc.sv b/src/dmi_cdc.sv
index f9d66fd..ec7a755 100644
--- a/src/dmi_cdc.sv
+++ b/src/dmi_cdc.sv
@@ -17,6 +17,10 @@
* This is mainly a wrapper around the existing CDCs.
*/
module dmi_cdc (
+ // Test controls
+ input logic testmode_i,
+ input logic test_rst_ni,
+
// JTAG side (master side)
input logic tck_i,
input logic trst_ni,
@@ -45,70 +49,76 @@ module dmi_cdc (
input logic core_dmi_valid_i
);
- logic core_clear_pending;
- cdc_2phase_clearable #(.T(dm::dmi_req_t)) i_cdc_req (
- .src_rst_ni ( trst_ni ),
- .src_clear_i ( jtag_dmi_cdc_clear_i ),
- .src_clk_i ( tck_i ),
- .src_clear_pending_o(), // Not used
- .src_data_i ( jtag_dmi_req_i ),
- .src_valid_i ( jtag_dmi_valid_i ),
- .src_ready_o ( jtag_dmi_ready_o ),
+ // TODO: Make it clean for synthesis.
+ logic jtag_combined_rstn;
+ always_ff @(posedge tck_i or negedge trst_ni) begin
+ if (!trst_ni) begin
+ jtag_combined_rstn <= '0;
+ end else if (jtag_dmi_cdc_clear_i) begin
+ jtag_combined_rstn <= '0;
+ end else begin
+ jtag_combined_rstn <= 1'b1;
+ end
+ end
- .dst_rst_ni ( rst_ni ),
- .dst_clear_i ( 1'b0 ), // No functional reset from core side
- // used (only async).
- .dst_clear_pending_o( core_clear_pending ), // use the clear pending signal
- // to synchronously clear the
- // response FIFO in the dm_top
- // csrs
- .dst_clk_i ( clk_i ),
- .dst_data_o ( core_dmi_req_o ),
- .dst_valid_o ( core_dmi_valid_o ),
- .dst_ready_i ( core_dmi_ready_i )
+ logic combined_rstn_premux;
+ prim_flop_2sync #(
+ .Width(1),
+ .ResetValue(0)
+ ) u_combined_rstn_sync (
+ .clk_i,
+ .rst_ni(rst_ni & jtag_combined_rstn),
+ .d_i(1'b1),
+ .q_o(combined_rstn_premux)
);
- cdc_2phase_clearable #(.T(dm::dmi_resp_t)) i_cdc_resp (
- .src_rst_ni ( rst_ni ),
- .src_clear_i ( 1'b0 ), // No functional reset from core side
- // used (only async ).
- .src_clear_pending_o(), // Not used
- .src_clk_i ( clk_i ),
- .src_data_i ( core_dmi_resp_i ),
- .src_valid_i ( core_dmi_valid_i ),
- .src_ready_o ( core_dmi_ready_o ),
-
- .dst_rst_ni ( trst_ni ),
- .dst_clear_i ( jtag_dmi_cdc_clear_i ),
- .dst_clear_pending_o(), //Not used
- .dst_clk_i ( tck_i ),
- .dst_data_o ( jtag_dmi_resp_o ),
- .dst_valid_o ( jtag_dmi_valid_o ),
- .dst_ready_i ( jtag_dmi_ready_i )
+ logic combined_rstn;
+ prim_clock_mux2 #(
+ .NoFpgaBufG(1'b1)
+ ) u_rst_mux (
+ .clk0_i(combined_rstn_premux),
+ .clk1_i(test_rst_ni),
+ .sel_i(testmode_i),
+ .clk_o(combined_rstn)
);
- // We need to flush the DMI response FIFO in DM top using the core clock
- // synchronous clear signal core_dmi_rst_no. We repurpose the clear
- // pending signal in the core clock domain by generating a 1 cycle pulse from
- // it.
-
- logic core_clear_pending_q;
- logic core_dmi_rst_nq;
- logic clear_pending_rise_edge_detect;
-
- assign clear_pending_rise_edge_detect = !core_clear_pending_q && core_clear_pending;
+ prim_fifo_async_simple #(
+ .Width($bits(dm::dmi_req_t)),
+ // Use the RZ protocol so that the two sides can be reset independently without getting
+ // out of sync due to EVEN/ODD states.
+ .EnRzHs(1)
+ ) i_cdc_req (
+ .clk_wr_i (tck_i),
+ .rst_wr_ni(trst_ni),
+ .wvalid_i (jtag_dmi_valid_i),
+ .wready_o (jtag_dmi_ready_o),
+ .wdata_i (jtag_dmi_req_i),
+ .clk_rd_i (clk_i),
+ .rst_rd_ni(combined_rstn),
+ .rvalid_o (core_dmi_valid_o),
+ .rready_i (core_dmi_ready_i),
+ .rdata_o (core_dmi_req_o)
+ );
- always_ff @(posedge clk_i, negedge rst_ni) begin
- if (!rst_ni) begin
- core_dmi_rst_nq <= 1'b1;
- core_clear_pending_q <= 1'b0;
- end else begin
- core_dmi_rst_nq <= ~clear_pending_rise_edge_detect; // active-low!
- core_clear_pending_q <= core_clear_pending;
- end
- end
+ prim_fifo_async_simple #(
+ .Width($bits(dm::dmi_resp_t)),
+ // Use the RZ protocol so that the two sides can be reset independently without getting
+ // out of sync due to EVEN/ODD states.
+ .EnRzHs(1)
+ ) i_cdc_resp (
+ .clk_wr_i (clk_i),
+ .rst_wr_ni(combined_rstn),
+ .wvalid_i (core_dmi_valid_i),
+ .wready_o (core_dmi_ready_o),
+ .wdata_i (core_dmi_resp_i),
+ .clk_rd_i (tck_i),
+ .rst_rd_ni(trst_ni),
+ .rvalid_o (jtag_dmi_valid_o),
+ .rready_i (jtag_dmi_ready_i),
+ .rdata_o (jtag_dmi_resp_o)
+ );
- assign core_dmi_rst_no = core_dmi_rst_nq;
+ assign core_dmi_rst_no = combined_rstn;
endmodule : dmi_cdc
diff --git a/src/dmi_jtag.sv b/src/dmi_jtag.sv
index 6be89a6..a7e5bff 100644
--- a/src/dmi_jtag.sv
+++ b/src/dmi_jtag.sv
@@ -22,9 +22,10 @@ module dmi_jtag #(
input logic clk_i, // DMI Clock
input logic rst_ni, // Asynchronous reset active low
input logic testmode_i,
+ input logic test_rst_ni,
- // active-low glitch free reset signal. Is asserted for one dmi clock cycle
- // (clk_i) whenever the dmi_jtag is reset (POR or functional reset).
+ // active-low glitch free reset signal. Is asserted
+ // (clk_i) whenever the dmi_jtag is reset.
output logic dmi_rst_no,
output dm::dmi_req_t dmi_req_o,
output logic dmi_req_valid_o,
@@ -327,6 +328,9 @@ module dmi_jtag #(
// CDC
// ---------
dmi_cdc i_dmi_cdc (
+ // Test controls
+ .testmode_i,
+ .test_rst_ni,
// JTAG side (master side)
.tck_i ( tck ),
.trst_ni ( trst_ni ),
diff --git a/src/dmi_jtag_tap.sv b/src/dmi_jtag_tap.sv
index 53f0fa9..3f91356 100644
--- a/src/dmi_jtag_tap.sv
+++ b/src/dmi_jtag_tap.sv
@@ -185,18 +185,15 @@ module dmi_jtag_tap #(
// ----------------
// DFT
// ----------------
- logic tck_n, tck_ni;
-
- tc_clk_inverter i_tck_inv (
- .clk_i ( tck_i ),
- .clk_o ( tck_ni )
- );
-
- tc_clk_mux2 i_dft_tck_mux (
- .clk0_i ( tck_ni ),
- .clk1_i ( tck_i ), // bypass the inverted clock for testing
- .clk_sel_i ( testmode_i ),
- .clk_o ( tck_n )
+ logic tck_n;
+
+ prim_clock_inv #(
+ .HasScanMode(1'b1),
+ .NoFpgaBufG(1'b1)
+ ) i_tck_inv (
+ .clk_i ( tck_i ),
+ .clk_no ( tck_n ),
+ .scanmode_i ( testmode_i )
);
// TDO changes state at negative edge of TCK