Update code from upstream repository
https://github.com/lowRISC/opentitan to revision
7aa5c2b890fa5d4e3d0b43e0f5e561cb7743a01d

* [flash] updated flash wrapper md file (Dana Agur)
* [flash / top / ast] functional updates (Timothy Chen)
* [ralgen, dv] Associated changes to ralgen (Srikrishna Iyer)
* [prim_sync_reqack_data] Fix SVA checking DST-to-SRC data stability
  (Pirmin Vogel)
* [dv/keymgr] temp disable alert checking in scb (Cindy Chen)
* [dvsim] Fix a wrong path in print message (Weicai Yang)
* [prim] Teach verilator to recognise a clock gate (Rupert Swarbrick)
* [prim_lc_sync] Add AsyncOn parameter to enable/disable the sync
  flops (Michael Schaffner)
* [clkmgr / top] Add clock divider step down to support lc_ctrl
  transition (Timothy Chen)
* [prim_sync_reqack] Use NRZ protocol internally for increased
  throughput (Pirmin Vogel)
* [prim] correct interface documentation. (Timothy Chen)
* [flash_ctrl] Add tlul configuration interface to prim_flash (Timothy
  Chen)
* [flash_ctrl] Use hamming code for 64b ECC (Timothy Chen)
* [prim/edn] Fix lint error (width mismatch) (Eunchan Kim)

Signed-off-by: Greg Chadwick <gac@lowrisc.org>
This commit is contained in:
Greg Chadwick 2021-01-14 17:18:36 +00:00
parent 698cf93183
commit d717e2385e
20 changed files with 308 additions and 121 deletions

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/lowRISC/opentitan
rev: 7e131447da6d5f3044666a17974e15df44f0328b
rev: 7aa5c2b890fa5d4e3d0b43e0f5e561cb7743a01d
}
}

View file

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

View file

@ -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: <name>
<ip_hjson|top_hjson>: <path-to-hjson-spec>
ip_hjson|top_hjson: <path-to-hjson-spec>
[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

View file

@ -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,
],

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -8,6 +8,7 @@ description: "prim"
filesets:
files_rtl:
depend:
- lowrisc:ip:tlul
- lowrisc:prim:ram_1p
- lowrisc:ip:flash_ctrl_pkg
files:

View file

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

View file

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

View file

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

View file

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

View file

@ -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);