diff --git a/vendor/lowrisc_ip.lock.hjson b/vendor/lowrisc_ip.lock.hjson index 37290316..6ba1c0a1 100644 --- a/vendor/lowrisc_ip.lock.hjson +++ b/vendor/lowrisc_ip.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/lowRISC/opentitan - rev: 7e131447da6d5f3044666a17974e15df44f0328b + rev: 7aa5c2b890fa5d4e3d0b43e0f5e561cb7743a01d } } diff --git a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh index 638a0c42..4386f135 100644 --- a/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh +++ b/vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh @@ -539,4 +539,23 @@ end `endif +// Creates a SVA cover that can be used in a covergroup. +// +// This macro creates an unnamed SVA cover from the expression `__sva` and an event with the name +// `__ev_name`. When the SVA cover is hit, the event is triggered. A coverpoint can cover the +// `triggered` property of the event. +`ifndef DV_FCOV_SVA +`define DV_FCOV_SVA(__ev_name, __sva, __clk = clk_i, __rst = rst_ni) \ + event __ev_name; \ + cover property (@(posedge __clk) disable iff (__rst == 0) (__sva)) begin \ + -> __ev_name; \ + end +`endif + +// Creates a coverpoint for an expression where only the expression true case is of interest for +// coverage (e.g. where the expression indicates an event has occured). +`ifndef DV_FCOV_EXPR_SEEN +`define DV_FCOV_EXPR_SEEN(__cp_name, __expr) __cp_name: coverpoint __expr { bins seen = {1}; } +`endif + `endif // __DV_MACROS_SVH__ diff --git a/vendor/lowrisc_ip/dv/tools/ralgen/README.md b/vendor/lowrisc_ip/dv/tools/ralgen/README.md index 9e494498..3ae83ec2 100644 --- a/vendor/lowrisc_ip/dv/tools/ralgen/README.md +++ b/vendor/lowrisc_ip/dv/tools/ralgen/README.md @@ -15,6 +15,10 @@ The adjoining `ralgen.core` file registers the `ralgen` generator. The FuseSoC core file that 'calls' the generator adds it as a dependency. When calling the generator, the following parameters are set: * **name (mandatory)**: Name of the RAL package (typically, same is the IP). +* **dv_base_prefix (optional)**: The prefix added to the base classes from + which the register classes are derived. Set this option to derive the register + classes not from the default `dv_base_reg`, but from user defined custom + class definitions. * **ip_hjson**: Path to the hjson specification written for an IP which includes the register descriptions. This needs to be a valid input for `reggen`. * **top_hjson**: Path to the hjson specification for a top level design. This @@ -30,7 +34,9 @@ generate: generator: ralgen parameters: name: - : + ip_hjson|top_hjson: + [dv_base_prefix: my_base] + targets: default: @@ -63,11 +69,15 @@ the `name` parameter to derive the [VLNV](https://fusesoc.readthedocs.io/en/master/user/overview.html#core-naming-rules) name for the generated core file. -The generated core file adds **`lowrisc:dv:dv_lib`** as a dependency for the -generated RAL package. This is required because our DV register block, register -and field models are derived from the +The generated core file adds **`lowrisc:dv:dv_base_reg`** as a dependency for +the generated RAL package. This is required because our DV register block, +register and field models are derived from the [DV library]({{< relref "hw/dv/sv/dv_lib/README.md" >}}) of classes. This -ensures the right compilation order is maintained. +ensures the right compilation order is maintained. If the `dv_base_prefix` +argument is set, then it adds **`lowrisc:dv:my_base_reg`** as an extra +dependency, where `my_base` is the value of the argument as shown in the +example above. This core file and the associated sources are assumed to be +available in the provided FuseSoC search paths. ## Limitations diff --git a/vendor/lowrisc_ip/dv/tools/ralgen/ralgen.py b/vendor/lowrisc_ip/dv/tools/ralgen/ralgen.py index 8e42656a..3750c593 100755 --- a/vendor/lowrisc_ip/dv/tools/ralgen/ralgen.py +++ b/vendor/lowrisc_ip/dv/tools/ralgen/ralgen.py @@ -49,6 +49,7 @@ def main(): name = gapi['parameters'].get('name') ip_hjson = gapi['parameters'].get('ip_hjson') top_hjson = gapi['parameters'].get('top_hjson') + dv_base_prefix = gapi['parameters'].get('dv_base_prefix') if not name or (bool(ip_hjson) == bool(top_hjson)): print("Error: ralgen requires the \"name\" and exactly one of " "{\"ip_hjson\" and \"top_hjson\"} parameters to be set.") @@ -65,6 +66,11 @@ def main(): cmd = os.path.join(util_path, "topgen.py") args = [cmd, "-r", "-o", ".", "-t", ral_spec] + depends = ["lowrisc:dv:dv_base_reg"] + if dv_base_prefix and dv_base_prefix != "dv_base": + args.extend(["--dv-base-prefix", dv_base_prefix]) + depends.append("lowrisc:dv:{}_reg".format(dv_base_prefix)) + try: subprocess.run(args, check=True) except subprocess.CalledProcessError as e: @@ -77,9 +83,7 @@ def main(): 'name': "lowrisc:dv:{}_ral_pkg".format(name), 'filesets': { 'files_dv': { - 'depend': [ - "lowrisc:dv:dv_base_reg", - ], + 'depend': depends, 'files': [ ral_pkg_file, ], diff --git a/vendor/lowrisc_ip/ip/prim/doc/prim_flash.md b/vendor/lowrisc_ip/ip/prim/doc/prim_flash.md index cee5bda3..52381f67 100644 --- a/vendor/lowrisc_ip/ip/prim/doc/prim_flash.md +++ b/vendor/lowrisc_ip/ip/prim/doc/prim_flash.md @@ -38,14 +38,21 @@ tck_i | input | jtag tck tdi_i | input | jtag tdi tms_i | input | jtag tms tdo_o | output | jtag tdo +bist_enable_i | input | lc_ctrl_pkg :: On for bist_enable input scanmode_i | input | dft scanmode input +scan_en_i | input | dft scan shift input scan_rst_n_i | input | dft scanmode reset -flash_power_ready_h_io | inout | flash power is ready (high voltage connection) -flash_power_down_h_io | inout | flash wrapper is powering down (high voltage connection) -flash_test_mode_a_io | inout | flash test mode values (analog connection) -flash_test_voltage_h_io | inout | flash test mode voltage (high voltage connection) - - +flash_power_ready_h_i | input | flash power is ready (high voltage connection) +flash_power_down_h_i | input | flash wrapper is powering down (high voltage connection) +flash_test_mode_a_i | input | flash test mode values (analog connection) +flash_test_voltage_h_i | input | flash test mode voltage (high voltage connection) +flash_err_o | output | flash level error interrupt indication, cleared on write 1 to status register +flash_alert_po | output | flash positive detector alert +flash_alert_no | output | flash negative detector alert +flash_alert_ack | input | single pulse ack +flash_alert_trig | input | alert force trig by SW +tl_i | input | TL_UL interface for rd/wr registers access +tl_o | output | TL_UL interface for rd/wr registers access ### Flash Request/Response Signals Name | In/Out | Description @@ -60,12 +67,12 @@ erase_suspend | input | erase suspend request addr | input | requested transaction address part | input | requested transaction partition info_sel | input | if requested transaction is information partition, the type of information partition accessed -he | output | high endurance enable for requested address +he | input | high endurance enable for requested address prog_data | input | program data ack | output | transction acknowledge rd_data | output | transaction read data done | output | transaction done -erase_suspend_done | output | erase suspend done + # Theory of Operations @@ -81,18 +88,18 @@ Depending on the type of transaction, there may be a significant gap between `ac For example, a read may have only 1 or 2 cycles between transaction acknowledgement and transaction complete. Whereas a program or erase may have a gap extending up to uS or even mS. -It is the flash wrapper's decision on how many outstanding transaction to accept. +It is the flash wrapper decision on how many outstanding transaction to accept. The following are examples for read, program and erase transactions. ### Read {{< wavejson >}} {signal: [ - {name: 'clk_i', wave: 'p................'}, - {name: 'rd_i', wave: '011..0.1..0......'}, - {name: 'addr_i', wave: 'x22..x.2..x......'}, - {name: 'ack_o', wave: '1.0.10...10......'}, - {name: 'done_o', wave: '0...10...10....10'}, - {name: 'rd_data_o', wave: 'x...2x...2x....2x'}, + {name: 'clk_i', wave: 'p.................'}, + {name: 'rd_i', wave: '011..0.1..0.......'}, + {name: 'addr_i', wave: 'x22..x.2..x.......'}, + {name: 'ack_o', wave: '010.10...10.......'}, + {name: 'done_o', wave: '0....10...10....10'}, + {name: 'rd_data_o', wave: 'x....2x...2x....2x'}, ]} {{< /wavejson >}} @@ -141,17 +148,22 @@ A program type not supported by the wrapper, indicated through `prog_type_avail` ## Erase Suspend Since erase operations can take a significant amount of time, sometimes it is necessary for software or other components to suspend the operation. -The suspend operation follows a similar request (`erase_suspend_req` and done (`erase_suspend_done`) interface. +The suspend operation input request starts with `erase_suspend_req` assertion. Flash wrapper circuit acks when wrapper starts suspend. When the erase suspend completes, the flash wrapper circuitry also asserts `done` for the ongoing erase transaction to ensure all hardware gracefully completes. The following is an example diagram {{< wavejson >}} {signal: [ {name: 'clk_i', wave: 'p................'}, - {name: 'pg_erase_i', wave: '01............0..'}, - {name: 'ack_o', wave: '1.0..............'}, - {name: 'erase_suspend_i', wave: '0.....1.......0..'}, + {name: 'pg_erase_i', wave: '01.0..............'}, + {name: 'ack_o', wave: '0.10...10........'}, + {name: 'erase_suspend_i', wave: '0.....1.0........'}, {name: 'done_o', wave: '0............10..'}, - {name: 'erase_suspend_done_o', wave: '0............10..'}, -]} + ] + } {{< /wavejson >}} + +## Error Interrupt +The `flash_err_o` is a level interrupt indication, that is asserted whenever an error event occurs in one of the Flash banks. +An Error status register is used to hold the error source of both banks, and it is cleared on writing 1 to the relevant bit. +Clearing the status register trigs deassertion of the interrupt. diff --git a/vendor/lowrisc_ip/ip/prim/lint/prim_clock_div.waiver b/vendor/lowrisc_ip/ip/prim/lint/prim_clock_div.waiver index bd70fff8..c9b4a732 100644 --- a/vendor/lowrisc_ip/ip/prim/lint/prim_clock_div.waiver +++ b/vendor/lowrisc_ip/ip/prim/lint/prim_clock_div.waiver @@ -3,3 +3,6 @@ # SPDX-License-Identifier: Apache-2.0 # # waiver file for prim_clock_div + +waive -rules DUAL_EDGE_CLOCK -location {prim_clock_div.sv} -regexp {.*} \ + -comment "The clock switch signal is synchronized on negative edge to ensure it is away from any transition" diff --git a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_sync_reqack/rtl/prim_sync_reqack_tb.sv b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_sync_reqack/rtl/prim_sync_reqack_tb.sv index f1d44ae8..354e6483 100644 --- a/vendor/lowrisc_ip/ip/prim/pre_dv/prim_sync_reqack/rtl/prim_sync_reqack_tb.sv +++ b/vendor/lowrisc_ip/ip/prim/pre_dv/prim_sync_reqack/rtl/prim_sync_reqack_tb.sv @@ -57,7 +57,8 @@ module prim_sync_reqack_tb #( logic rst_done; // Instantiate DUT - logic [WidthTrans-1:0] out_data, unused_out_data; + logic [WidthTrans-1:0] in_data, out_data, unused_out_data; + assign in_data = DataSrc2Dst ? src_count_q : dst_count_q; prim_sync_reqack_data #( .Width ( WidthTrans ), .DataSrc2Dst ( DataSrc2Dst ), @@ -73,7 +74,7 @@ module prim_sync_reqack_tb #( .dst_req_o (dst_req), .dst_ack_i (dst_ack), - .data_i (dst_count_q), + .data_i (in_data), .data_o (out_data) ); assign unused_out_data = out_data; diff --git a/vendor/lowrisc_ip/ip/prim/prim_clock_div.core b/vendor/lowrisc_ip/ip/prim/prim_clock_div.core index 7bd9bfbf..ab031d75 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_clock_div.core +++ b/vendor/lowrisc_ip/ip/prim/prim_clock_div.core @@ -16,7 +16,16 @@ filesets: - rtl/prim_clock_div.sv file_type: systemVerilogSource + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/prim_clock_div.waiver + file_type: waiver + targets: default: filesets: + - tool_ascentlint ? (files_ascentlint_waiver) - files_rtl diff --git a/vendor/lowrisc_ip/ip/prim/prim_secded.core b/vendor/lowrisc_ip/ip/prim/prim_secded.core index ed82bf4f..abcad6c4 100644 --- a/vendor/lowrisc_ip/ip/prim/prim_secded.core +++ b/vendor/lowrisc_ip/ip/prim/prim_secded.core @@ -16,6 +16,8 @@ filesets: - rtl/prim_secded_39_32_enc.sv - rtl/prim_secded_72_64_dec.sv - rtl/prim_secded_72_64_enc.sv + - rtl/prim_secded_hamming_72_64_dec.sv + - rtl/prim_secded_hamming_72_64_enc.sv file_type: systemVerilogSource targets: diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_div.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_div.sv index 35dbbba7..838d146e 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_div.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_clock_div.sv @@ -10,11 +10,17 @@ module prim_clock_div #( ) ( input clk_i, input rst_ni, + input step_down_req_i, // step down divisor by 2x + output logic step_down_ack_o, // step down acknowledge input test_en_i, output logic clk_o ); + // Only even divide is supported at the moment + // For odd divide we need to introduce more parameters to control duty cycle + `ASSERT_INIT(DivEven_A, (Divisor % 2) == 0) + logic clk_int; if (Divisor == 2) begin : gen_div2 @@ -38,28 +44,56 @@ module prim_clock_div #( .clk_no(q_n) ); - assign clk_int = q_p; + logic step_down_nq; + always_ff @(negedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + step_down_nq <= 1'b0; + end else begin + step_down_nq <= step_down_req_i; + end + end + + // make sure selection point is away from both edges + prim_clock_mux2 #( + .NoFpgaBufG(1'b1) + ) u_step_down_mux ( + .clk0_i(q_p), + .clk1_i(clk_i), + .sel_i(step_down_nq), + .clk_o(clk_int) + ); + + assign step_down_ack_o = step_down_nq; end else begin : gen_div - // Only even divide is supported at the moment - // For odd divide we need to introduce more parameters to control duty cycle - `ASSERT_INIT(DivEven_A, (Divisor % 2) == 0) localparam int ToggleCnt = Divisor / 2; localparam int CntWidth = $clog2(ToggleCnt); logic [CntWidth-1:0] cnt; + logic [CntWidth-1:0] limit; + + assign limit = !step_down_req_i ? ToggleCnt - 1 : + (ToggleCnt / 2) == 2 ? '0 : (ToggleCnt / 2) - 1; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin cnt <= '0; clk_int <= ResetValue; - end else if (cnt == ToggleCnt-1) begin + end else if (cnt >= limit) begin cnt <= '0; clk_int <= ~clk_o; end else begin cnt <= cnt + 1'b1; end end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + step_down_ack_o <= 1'b0; + end else begin + step_down_ack_o <= step_down_req_i; + end + end end // when in scanmode, bypass the dividers completely diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_edn_req.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_edn_req.sv index 75cae9d0..e76fefd5 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_edn_req.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_edn_req.sv @@ -38,8 +38,9 @@ module prim_edn_req logic [edn_pkg::ENDPOINT_BUS_WIDTH-1:0] word_data; logic word_fips; + localparam int SyncWidth = $bits({edn_i.edn_fips, edn_i.edn_bus}); prim_sync_reqack_data #( - .Width(edn_pkg::ENDPOINT_BUS_WIDTH), + .Width(SyncWidth), .DataSrc2Dst(1'b0), .DataReg(1'b0) ) u_prim_sync_reqack_data ( diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv index 951a130f..a5593a35 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv @@ -15,7 +15,11 @@ module prim_lc_sync #( // The buffer cells have a don't touch constraint // on them such that synthesis tools won't collapse // all copies into one signal. - parameter int NumCopies = 1 + parameter int NumCopies = 1, + // This instantiates the synchronizer flops if set to 1. + // In special cases where the receiver is in the same clock domain as the sender, + // this can be set to 0. However, it is recommended to leave this at 1. + parameter bit AsyncOn = 1 ) ( input clk_i, input rst_ni, @@ -26,15 +30,19 @@ module prim_lc_sync #( `ASSERT_INIT(NumCopiesMustBeGreaterZero_A, NumCopies > 0) logic [lc_ctrl_pkg::TxWidth-1:0] lc_en; - prim_flop_2sync #( - .Width(lc_ctrl_pkg::TxWidth), - .ResetValue(lc_ctrl_pkg::TxWidth'(lc_ctrl_pkg::Off)) - ) u_prim_flop_2sync ( - .clk_i, - .rst_ni, - .d_i(lc_en_i), - .q_o(lc_en) - ); + if (AsyncOn) begin : gen_flops + prim_flop_2sync #( + .Width(lc_ctrl_pkg::TxWidth), + .ResetValue(lc_ctrl_pkg::TxWidth'(lc_ctrl_pkg::Off)) + ) u_prim_flop_2sync ( + .clk_i, + .rst_ni, + .d_i(lc_en_i), + .q_o(lc_en) + ); + end else begin : gen_no_flops + assign lc_en = lc_en_i; + end for (genvar j = 0; j < NumCopies; j++) begin : gen_buffs logic [lc_ctrl_pkg::TxWidth-1:0] lc_en_out; diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv index 808630b4..e8e7d473 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv @@ -8,19 +8,18 @@ // Both domains will see a handshake with the duration of one clock cycle. // // Notes: -// - Once asserted, the source domain is not allowed to de-assert REQ without ACK. -// - The destination domain is not allowed to send an ACK without a REQ. +// - Once asserted, the source (SRC) domain is not allowed to de-assert REQ without ACK. +// - The destination (DST) domain is not allowed to send an ACK without a REQ. // - This module works both when syncing from a faster to a slower clock domain and vice versa. -// - Internally, this module uses a return-to-zero, four-phase handshake protocol. Assuming the -// destination side responds with an ACK immediately, the latency from asserting the REQ on the -// source side is: -// - 1 source + 2 destination clock cycles until the handshake is performed on the -// destination side, +// - Internally, this module uses a non-return-to-zero, two-phase handshake protocol. Assuming the +// DST domain responds with an ACK immediately, the latency from asserting the REQ in the +// SRC domain is: +// - 1 source + 2 destination clock cycles until the handshake is performed in the DST domain, // - 1 source + 2 destination + 1 destination + 2 source clock cycles until the handshake is -// performed on the source side. -// - It takes another round trip (3 source + 3 destination clock cycles) before the next -// REQ is starting to be propagated to the destination side. The module is thus not suitable -// for high-bandwidth communication. +// performed in the SRC domain. +// +// For further information, see Section 8.2.4 in H. Kaeslin, "Top-Down Digital VLSI Design: From +// Architecture to Gate-Level Circuits and FPGAs", 2015. `include "prim_assert.sv" @@ -38,7 +37,7 @@ module prim_sync_reqack ( // Types typedef enum logic { - HANDSHAKE, SYNC + EVEN, ODD } sync_reqack_fsm_e; // Signals @@ -46,8 +45,12 @@ module prim_sync_reqack ( sync_reqack_fsm_e dst_fsm_ns, dst_fsm_cs; logic src_req_d, src_req_q, src_ack; logic dst_ack_d, dst_ack_q, dst_req; + logic src_handshake, dst_handshake; - // Move REQ over to ACK side. + assign src_handshake = src_req_i & src_ack_o; + assign dst_handshake = dst_req_o & dst_ack_i; + + // Move REQ over to DST domain. prim_flop_2sync #( .Width(1) ) req_sync ( @@ -57,7 +60,7 @@ module prim_sync_reqack ( .q_o (dst_req) ); - // Move ACK over to REQ side. + // Move ACK over to SRC domain. prim_flop_2sync #( .Width(1) ) ack_sync ( @@ -67,31 +70,36 @@ module prim_sync_reqack ( .q_o (src_ack) ); - // REQ-side FSM (source domain) + // REQ-side FSM (SRC domain) always_comb begin : src_fsm src_fsm_ns = src_fsm_cs; - // By default, we forward the REQ and ACK. - src_req_d = src_req_i; - src_ack_o = src_ack; + // By default, we keep the internal REQ value and don't ACK. + src_req_d = src_req_q; + src_ack_o = 1'b0; unique case (src_fsm_cs) - HANDSHAKE: begin - // The handshake on the REQ side is done for exactly 1 clock cycle. - if (src_req_i && src_ack) begin - src_fsm_ns = SYNC; - // Tell ACK side that we are done. - src_req_d = 1'b0; + EVEN: begin + // Simply forward REQ and ACK. + src_req_d = src_req_i; + src_ack_o = src_ack; + + // The handshake is done for exactly 1 clock cycle. + if (src_handshake) begin + src_fsm_ns = ODD; end end - SYNC: begin - // Make sure ACK side knows that we are done. - src_req_d = 1'b0; - src_ack_o = 1'b0; - if (!src_ack) begin - src_fsm_ns = HANDSHAKE; + ODD: begin + // Internal REQ and ACK have inverted meaning now. If src_req_i is high again, this signals + // a new transaction. + src_req_d = ~src_req_i; + src_ack_o = ~src_ack; + + // The handshake is done for exactly 1 clock cycle. + if (src_handshake) begin + src_fsm_ns = EVEN; end end @@ -99,29 +107,36 @@ module prim_sync_reqack ( endcase end - // ACK-side FSM (destination domain) + // ACK-side FSM (DST domain) always_comb begin : dst_fsm dst_fsm_ns = dst_fsm_cs; - // By default, we forward the REQ and ACK. - dst_req_o = dst_req; - dst_ack_d = dst_ack_i; + // By default, we don't REQ and keep the internal ACK. + dst_req_o = 1'b0; + dst_ack_d = dst_ack_q; unique case (dst_fsm_cs) - HANDSHAKE: begin - // The handshake on the ACK side is done for exactly 1 clock cycle. - if (dst_req && dst_ack_i) begin - dst_fsm_ns = SYNC; + EVEN: begin + // Simply forward REQ and ACK. + dst_req_o = dst_req; + dst_ack_d = dst_ack_i; + + // The handshake is done for exactly 1 clock cycle. + if (dst_handshake) begin + dst_fsm_ns = ODD; end end - SYNC: begin - // Don't forward REQ, hold ACK, wait for REQ side. - dst_req_o = 1'b0; - dst_ack_d = 1'b1; - if (!dst_req) begin - dst_fsm_ns = HANDSHAKE; + ODD: begin + // Internal REQ and ACK have inverted meaning now. If dst_req goes low, this signals a new + // transaction. + dst_req_o = ~dst_req; + dst_ack_d = ~dst_ack_i; + + // The handshake is done for exactly 1 clock cycle. + if (dst_handshake) begin + dst_fsm_ns = EVEN; end end @@ -132,7 +147,7 @@ module prim_sync_reqack ( // Registers always_ff @(posedge clk_src_i or negedge rst_src_ni) begin if (!rst_src_ni) begin - src_fsm_cs <= HANDSHAKE; + src_fsm_cs <= EVEN; src_req_q <= 1'b0; end else begin src_fsm_cs <= src_fsm_ns; @@ -141,7 +156,7 @@ module prim_sync_reqack ( end always_ff @(posedge clk_dst_i or negedge rst_dst_ni) begin if (!rst_dst_ni) begin - dst_fsm_cs <= HANDSHAKE; + dst_fsm_cs <= EVEN; dst_ack_q <= 1'b0; end else begin dst_fsm_cs <= dst_fsm_ns; @@ -149,10 +164,10 @@ module prim_sync_reqack ( end end - // Source domain cannot de-assert REQ while waiting for ACK. - `ASSERT(ReqAckSyncHoldReq, $fell(src_req_i) |-> (src_fsm_cs != HANDSHAKE), clk_src_i, !rst_src_ni) + // SRC domain can only de-assert REQ after receiving ACK. + `ASSERT(SyncReqAckHoldReq, $fell(src_req_i) |-> $fell(src_ack_o), clk_src_i, !rst_src_ni) - // Destination domain cannot assert ACK without REQ. - `ASSERT(ReqAckSyncAckNeedsReq, dst_ack_i |-> dst_req_o, clk_dst_i, !rst_dst_ni) + // DST domain cannot assert ACK without REQ. + `ASSERT(SyncReqAckAckNeedsReq, dst_ack_i |-> dst_req_o, clk_dst_i, !rst_dst_ni) endmodule diff --git a/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack_data.sv b/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack_data.sv index 9919d519..542fb43e 100644 --- a/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack_data.sv +++ b/vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack_data.sv @@ -7,8 +7,8 @@ // This module synchronizes a REQ/ACK handshake with associated data across a clock domain // crossing (CDC). Both domains will see a handshake with the duration of one clock cycle. By // default, the data itself is not registered. The main purpose of feeding the data through this -// module to have an anchor point for waiving CDC violations. If the data is configured to -// flow from the destination (DST) to the source (SRC) domain, an additional register stage can be +// module to have an anchor point for waiving CDC violations. If the data is configured to flow +// from the destination (DST) to the source (SRC) domain, an additional register stage can be // inserted for data buffering. // // Under the hood, this module uses a prim_sync_reqack primitive for synchronizing the @@ -86,18 +86,21 @@ module prim_sync_reqack_data #( //////////////// if (DataSrc2Dst == 1'b1) begin : gen_assert_data_src2dst // SRC domain cannot change data while waiting for ACK. - `ASSERT(ReqAckSyncDataHoldSrc2Dst, !$stable(data_i) |-> - !(src_req_i == 1'b1 && u_prim_sync_reqack.src_fsm_cs == u_prim_sync_reqack.HANDSHAKE), + `ASSERT(SyncReqAckDataHoldSrc2Dst, !$stable(data_i) |-> + (!src_req_i || (src_req_i && src_ack_o)), clk_src_i, !rst_src_ni) // Register stage cannot be used. - `ASSERT_INIT(ReqAckSyncDataReg, DataSrc2Dst && !DataReg) + `ASSERT_INIT(SyncReqAckDataReg, DataSrc2Dst && !DataReg) end else if (DataSrc2Dst == 1'b0 && DataReg == 1'b0) begin : gen_assert_data_dst2src - // DST domain cannot change data while waiting for SRC domain to receive the ACK. - `ASSERT(ReqAckSyncDataHoldDst2Src, !$stable(data_i) |-> - (u_prim_sync_reqack.dst_fsm_cs != u_prim_sync_reqack.SYNC), - clk_dst_i, !rst_dst_ni) + // DST domain shall not change data while waiting for SRC domain to latch it (together with + // receiving ACK). It takes 2 SRC cycles for ACK to cross over from DST to SRC, and 1 SRC cycle + // for the next REQ to cross over from SRC to DST. Assert that the data is stable during that + // window, i.e. [-2,+1] SRC cycles around the SRC handshake. + `ASSERT(SyncReqAckDataHoldDst2Src, + src_req_i && src_ack_o |-> $past(data_o,2) == data_o && $stable(data_o) [*2], + clk_src_i, !rst_src_ni) end endmodule diff --git a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flash.core b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flash.core index b37299f8..5dbbeabb 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flash.core +++ b/vendor/lowrisc_ip/ip/prim_generic/prim_generic_flash.core @@ -8,6 +8,7 @@ description: "prim" filesets: files_rtl: depend: + - lowrisc:ip:tlul - lowrisc:prim:ram_1p - lowrisc:ip:flash_ctrl_pkg files: diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_gating.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_gating.sv index 1cc05e68..4ae0f906 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_gating.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_clock_gating.sv @@ -3,6 +3,9 @@ // SPDX-License-Identifier: Apache-2.0 // // Common Library: Clock Gating cell +// +// The logic assumes that en_i is synchronized (so the instantiation site might need to put a +// synchronizer before en_i). module prim_generic_clock_gating #( parameter bit NoFpgaGate = 1'b0 // this parameter has no function in generic @@ -13,8 +16,7 @@ module prim_generic_clock_gating #( output logic clk_o ); - // Assume en_i synchronized, if not put synchronizer prior to en_i - logic en_latch; + logic en_latch /* verilator clock_enable */; always_latch begin if (!clk_i) begin en_latch = en_i | test_en_i; diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv index ee5c65ca..12d21a6c 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash.sv @@ -21,20 +21,29 @@ module prim_generic_flash #( input flash_phy_pkg::flash_phy_prim_flash_req_t [NumBanks-1:0] flash_req_i, output flash_phy_pkg::flash_phy_prim_flash_rsp_t [NumBanks-1:0] flash_rsp_o, output logic [flash_phy_pkg::ProgTypes-1:0] prog_type_avail_o, - input init_i, output init_busy_o, input tck_i, input tdi_i, input tms_i, output logic tdo_o, + input bist_enable_i, input scanmode_i, input scan_rst_ni, input flash_power_ready_h_i, input flash_power_down_h_i, input [TestModeWidth-1:0] flash_test_mode_a_i, - input flash_test_voltage_h_i + input flash_test_voltage_h_i, + input tlul_pkg::tl_h2d_t tl_i, + output tlul_pkg::tl_d2h_t tl_o ); + localparam int CfgRegs = 21; + localparam int CfgAddrWidth = $clog2(CfgRegs); + + // convert this into a tlul write later + logic init; + assign init = 1'b1; + logic [NumBanks-1:0] init_busy; assign init_busy_o = |init_busy; @@ -73,9 +82,8 @@ module prim_generic_flash #( .ack_o(flash_rsp_o[bank].ack), .done_o(flash_rsp_o[bank].done), .rd_data_o(flash_rsp_o[bank].rdata), - .init_i, + .init_i(init), .init_busy_o(init_busy[bank]), - .erase_suspend_done_o(flash_rsp_o[bank].erase_suspend_done), .flash_power_ready_h_i, .flash_power_down_h_i ); @@ -98,4 +106,57 @@ module prim_generic_flash #( assign unused_tms = tms_i; assign tdo_o = '0; + // fake memory used to emulate configuration + logic cfg_req; + logic cfg_we; + logic [CfgAddrWidth-1:0] cfg_addr; + logic [31:0] cfg_wdata; + logic cfg_rvalid; + logic [31:0] cfg_rdata; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + cfg_rvalid <= 1'b0; + end else begin + cfg_rvalid <= cfg_req & !cfg_we; + end + end + + tlul_adapter_sram #( + .SramAw(CfgAddrWidth), + .SramDw(32), + .Outstanding(2), + .ErrOnWrite(1) + ) u_cfg ( + .clk_i, + .rst_ni, + .tl_i, + .tl_o, + .req_o(cfg_req), + .gnt_i(1'b1), + .we_o(cfg_we), + .addr_o(cfg_addr), + .wdata_o(cfg_wdata), + .wmask_o(), + .rdata_i(cfg_rdata), + .rvalid_i(cfg_rvalid), + .rerror_i('0) + ); + + prim_ram_1p #( + .Width(32), + .Depth(CfgRegs) + ) u_cfg_ram ( + .clk_i, + .req_i(cfg_req), + .write_i(cfg_we), + .addr_i(cfg_addr), + .wdata_i(cfg_wdata), + .wmask_i({32{1'b1}}), + .rdata_o(cfg_rdata) + ); + + logic unused_bist_enable; + assign unused_bist_enable = bist_enable_i; + endmodule // prim_generic_flash diff --git a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash_bank.sv b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash_bank.sv index 600e4b7e..4f7ae452 100644 --- a/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash_bank.sv +++ b/vendor/lowrisc_ip/ip/prim_generic/rtl/prim_generic_flash_bank.sv @@ -36,7 +36,6 @@ module prim_generic_flash_bank #( input [DataWidth-1:0] prog_data_i, output logic ack_o, output logic done_o, - output logic erase_suspend_done_o, output logic [DataWidth-1:0] rd_data_o, input init_i, output logic init_busy_o, @@ -244,7 +243,6 @@ module prim_generic_flash_bank #( init_busy_o = '0; pop_cmd = '0; done_o = '0; - erase_suspend_done_o = '0; unique case (st_q) StReset: begin @@ -334,7 +332,6 @@ module prim_generic_flash_bank #( st_d = StIdle; pop_cmd = 1'b1; done_o = 1'b1; - erase_suspend_done_o = 1'b1; time_cnt_clr = 1'b1; index_cnt_clr = 1'b1; end else if (index_cnt < index_limit_q || time_cnt < time_limit_q) begin diff --git a/vendor/lowrisc_ip/util/dvsim/Modes.py b/vendor/lowrisc_ip/util/dvsim/Modes.py index 5babbf38..92886a64 100644 --- a/vendor/lowrisc_ip/util/dvsim/Modes.py +++ b/vendor/lowrisc_ip/util/dvsim/Modes.py @@ -118,9 +118,10 @@ class Modes(): if type(self_attr_val) != type(mode_attr_val): log.error( "Mode %s cannot be merged into %s due to a conflict " - "(type mismatch): %s: {%s(%s), %s(%s)}", name, self.name, - attr, str(self_attr_val), str(type(self_attr_val)), - str(mode_attr_val), str(type(mode_attr_val))) + "(type mismatch): %s: {%s(%s), %s(%s)}", mode.name, + self.name, attr, str(self_attr_val), + str(type(self_attr_val)), str(mode_attr_val), + str(type(mode_attr_val))) sys.exit(1) # Check if they are different non-default values. @@ -128,8 +129,8 @@ class Modes(): log.error( "Mode %s cannot be merged into %s due to a conflict " "(unable to pick one from different values): " - "%s: {%s, %s}", name, self.name, attr, str(self_attr_val), - str(mode_attr_val)) + "%s: {%s, %s}", mode.name, self.name, attr, + str(self_attr_val), str(mode_attr_val)) sys.exit(1) # Check newly appended sub_modes, remove 'self' and duplicates diff --git a/vendor/lowrisc_ip/util/uvmdvgen/scoreboard.sv.tpl b/vendor/lowrisc_ip/util/uvmdvgen/scoreboard.sv.tpl index f3cdf5cd..0fe4a987 100644 --- a/vendor/lowrisc_ip/util/uvmdvgen/scoreboard.sv.tpl +++ b/vendor/lowrisc_ip/util/uvmdvgen/scoreboard.sv.tpl @@ -34,6 +34,10 @@ class ${name}_scoreboard extends dv_base_scoreboard #( % for agent in env_agents: ${agent}_fifo = new("${agent}_fifo", this); % endfor +% if has_alerts: + // TODO: remove once support alert checking + do_alert_check = 0; +% endif endfunction function void connect_phase(uvm_phase phase);