mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-22 13:07:46 -04:00
Update lowrisc_ip to lowRISC/opentitan@7aa5c2b89
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:
parent
698cf93183
commit
d717e2385e
20 changed files with 308 additions and 121 deletions
2
vendor/lowrisc_ip.lock.hjson
vendored
2
vendor/lowrisc_ip.lock.hjson
vendored
|
@ -9,6 +9,6 @@
|
|||
upstream:
|
||||
{
|
||||
url: https://github.com/lowRISC/opentitan
|
||||
rev: 7e131447da6d5f3044666a17974e15df44f0328b
|
||||
rev: 7aa5c2b890fa5d4e3d0b43e0f5e561cb7743a01d
|
||||
}
|
||||
}
|
||||
|
|
19
vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh
vendored
19
vendor/lowrisc_ip/dv/sv/dv_utils/dv_macros.svh
vendored
|
@ -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__
|
||||
|
|
20
vendor/lowrisc_ip/dv/tools/ralgen/README.md
vendored
20
vendor/lowrisc_ip/dv/tools/ralgen/README.md
vendored
|
@ -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
|
||||
|
||||
|
|
10
vendor/lowrisc_ip/dv/tools/ralgen/ralgen.py
vendored
10
vendor/lowrisc_ip/dv/tools/ralgen/ralgen.py
vendored
|
@ -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,
|
||||
],
|
||||
|
|
54
vendor/lowrisc_ip/ip/prim/doc/prim_flash.md
vendored
54
vendor/lowrisc_ip/ip/prim/doc/prim_flash.md
vendored
|
@ -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.
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
2
vendor/lowrisc_ip/ip/prim/prim_secded.core
vendored
2
vendor/lowrisc_ip/ip/prim/prim_secded.core
vendored
|
@ -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:
|
||||
|
|
44
vendor/lowrisc_ip/ip/prim/rtl/prim_clock_div.sv
vendored
44
vendor/lowrisc_ip/ip/prim/rtl/prim_clock_div.sv
vendored
|
@ -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
|
||||
|
|
|
@ -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 (
|
||||
|
|
28
vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv
vendored
28
vendor/lowrisc_ip/ip/prim/rtl/prim_lc_sync.sv
vendored
|
@ -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;
|
||||
|
|
115
vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv
vendored
115
vendor/lowrisc_ip/ip/prim/rtl/prim_sync_reqack.sv
vendored
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -8,6 +8,7 @@ description: "prim"
|
|||
filesets:
|
||||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:ip:tlul
|
||||
- lowrisc:prim:ram_1p
|
||||
- lowrisc:ip:flash_ctrl_pkg
|
||||
files:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
11
vendor/lowrisc_ip/util/dvsim/Modes.py
vendored
11
vendor/lowrisc_ip/util/dvsim/Modes.py
vendored
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue