| 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 |