Commentary: Changes update
This commit is contained in:
parent
087cabcf35
commit
7b2277f584
1
Changes
1
Changes
|
|
@ -33,6 +33,7 @@ Verilator 5.047 devel
|
|||
* Support dist and solve...before inside foreach constraints (#7245) (#7253). [Yilou Wang]
|
||||
* Support array and struct info metadata in FST traces (#7255). [Geza Lore, Testorrent USA, Inc.]
|
||||
* Support dynamic array .size in inline randomize() with constraints (#7258) (#7266). [Yilou Wang]
|
||||
* Support modport export/import task prototypes and out-of-block definitions (#7277). [Yilou Wang]
|
||||
* Add VPI callback support to --main (#7145).
|
||||
* Add V3LiftExpr pass to lower impure expressions and calls (#7141) (#7164). [Geza Lore, Testorrent USA, Inc.]
|
||||
* Add --func-recursion-depth CLI option (#7175) (#7179).
|
||||
|
|
|
|||
|
|
@ -594,16 +594,15 @@ object.
|
|||
This class manages processes that await events (triggers). There is one
|
||||
such object per each trigger awaited by coroutines. Coroutines ``co_await``
|
||||
this object's ``trigger`` function. They are stored in three stages -
|
||||
`awaiting`, `fired` and `toResume`. First, they land in the `awaiting` stage, and
|
||||
cannot be resumed. The ``ready`` function moves all coroutines from the
|
||||
`awaiting` stage into the `fired` stage. The ``moveToResumeQueue`` function moves
|
||||
`fired` coroutines into `toResume`. Finally, function `resume` resumes
|
||||
all coroutines from the `toResume` stage.
|
||||
`awaiting`, `fired` and `toResume`. First, they land in the `awaiting`
|
||||
stage, and cannot be resumed. The ``ready`` function moves all coroutines
|
||||
from the `awaiting` stage into the `fired` stage. The ``moveToResumeQueue``
|
||||
function moves `fired` coroutines into `toResume`. Finally, function
|
||||
`resume` resumes all coroutines from the `toResume` stage.
|
||||
|
||||
This split is done to avoid self-triggering, triggering coroutines
|
||||
multiple times and triggering coroutines in the same iteration
|
||||
they were suspended. See the `Scheduling with timing` section
|
||||
for details on how this is used.
|
||||
This split is done to avoid self-triggering, triggering coroutines multiple
|
||||
times and triggering coroutines in the same iteration they were suspended.
|
||||
See the `Scheduling with timing` section for details on how this is used.
|
||||
|
||||
``VlDynamicTriggerScheduler``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -1844,33 +1843,25 @@ algorithmic stage. An example:
|
|||
The following summarizes the above example dump, with more detail on each
|
||||
field in the section below.
|
||||
|
||||
+---------------+--------------------------------------------------------+
|
||||
| ``1:2:`` | The hierarchy of the ``VAR`` is the ``op2p`` |
|
||||
| | pointer under the ``MODULE``, which in turn is the |
|
||||
| | ``op1p`` pointer under the ``NETLIST``. |
|
||||
+---------------+--------------------------------------------------------+
|
||||
| ``VAR`` | The AstNodeType (e.g. ``AstVar``). |
|
||||
+---------------+--------------------------------------------------------+
|
||||
| ``0x91a780`` | Address of this node. |
|
||||
+---------------+--------------------------------------------------------+
|
||||
| ``<e74>`` | The 74th edit to the netlist was the last |
|
||||
| | modification to this node. |
|
||||
+---------------+--------------------------------------------------------+
|
||||
| ``{a22ah}`` | This node is related to the source filename |
|
||||
| | "a", where "a" is the first file read, "z" the 26th, |
|
||||
| | and "aa" the 27th. Then line 22 in that file, then |
|
||||
| | column 8 (aa=0, az=25, ba=26, ...). |
|
||||
+---------------+--------------------------------------------------------+
|
||||
| ``@dt=0x...`` | The address of the data type this node references. |
|
||||
+---------------+--------------------------------------------------------+
|
||||
| ``w32`` | The data-type width() is 32 bits. |
|
||||
+---------------+--------------------------------------------------------+
|
||||
| ``out_wide`` | The name() of the node, in this case, the name of the |
|
||||
| | variable. |
|
||||
+---------------+--------------------------------------------------------+
|
||||
| ``[O]`` | Flags which vary with the type of node, in this |
|
||||
| | case of a VAR, it means the variable is an output. |
|
||||
+---------------+--------------------------------------------------------+
|
||||
============= =============================================================
|
||||
``1:2:`` The hierarchy of the ``VAR`` is the ``op2p`` pointer under
|
||||
the ``MODULE``, which in turn is the ``op1p`` pointer under
|
||||
the ``NETLIST``.
|
||||
``VAR`` The AstNodeType (e.g. ``AstVar``).
|
||||
``0x91a780`` Address of this node.
|
||||
``<e74>`` The 74th edit to the netlist was the last modification to
|
||||
this node.
|
||||
``{a22ah}`` This node is related to the source filename "a", where "a" is
|
||||
the first file read, "z" the 26th, and "aa" the 27th. Then
|
||||
line 22 in that file, then column 8 (aa=0, az=25, ba=26,
|
||||
...).
|
||||
``@dt=0x...`` The address of the data type this node references.
|
||||
``w32`` The data-type width() is 32 bits.
|
||||
``out_wide`` The name() of the node, in this case, the name of the
|
||||
variable.
|
||||
``[O]`` Flags which vary with the type of node, in this case of a
|
||||
VAR, it means the variable is an output.
|
||||
============= =============================================================
|
||||
|
||||
In more detail, the following fields are dumped common to all nodes. They
|
||||
are produced by the ``AstNode::dump()`` method:
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ module t;
|
|||
arr4 = '{10, 20, 30, 40};
|
||||
if (arr4 == '{10, 20, 30, 40}) begin
|
||||
// expected
|
||||
end else begin
|
||||
end
|
||||
else begin
|
||||
$display("FAIL: arr4 == pattern");
|
||||
$stop;
|
||||
end
|
||||
|
|
@ -44,7 +45,8 @@ module t;
|
|||
// 2. Fixed-size array: NEQ with assignment pattern
|
||||
if (arr4 != '{10, 20, 30, 99}) begin
|
||||
// expected
|
||||
end else begin
|
||||
end
|
||||
else begin
|
||||
$display("FAIL: arr4 != pattern");
|
||||
$stop;
|
||||
end
|
||||
|
|
@ -52,7 +54,8 @@ module t;
|
|||
// 3. Pattern on LHS of comparison
|
||||
if ('{10, 20, 30, 40} == arr4) begin
|
||||
// expected
|
||||
end else begin
|
||||
end
|
||||
else begin
|
||||
$display("FAIL: pattern == arr4 (LHS)");
|
||||
$stop;
|
||||
end
|
||||
|
|
@ -60,7 +63,8 @@ module t;
|
|||
// 4. Pattern on LHS of NEQ
|
||||
if ('{10, 20, 30, 99} != arr4) begin
|
||||
// expected
|
||||
end else begin
|
||||
end
|
||||
else begin
|
||||
$display("FAIL: pattern != arr4 (LHS NEQ)");
|
||||
$stop;
|
||||
end
|
||||
|
|
@ -72,7 +76,8 @@ module t;
|
|||
sub = q[1:3];
|
||||
if (sub == '{20, 30, 40}) begin
|
||||
// expected
|
||||
end else begin
|
||||
end
|
||||
else begin
|
||||
$display("FAIL: queue slice == pattern");
|
||||
$stop;
|
||||
end
|
||||
|
|
@ -80,7 +85,8 @@ module t;
|
|||
// 6. Queue: NEQ with assignment pattern
|
||||
if (sub != '{20, 30, 99}) begin
|
||||
// expected
|
||||
end else begin
|
||||
end
|
||||
else begin
|
||||
$display("FAIL: queue slice != pattern");
|
||||
$stop;
|
||||
end
|
||||
|
|
@ -91,7 +97,8 @@ module t;
|
|||
p1 = '{a: 8'hAA, b: 8'h55};
|
||||
if (p1 == '{a: 8'hAA, b: 8'h55}) begin
|
||||
// expected
|
||||
end else begin
|
||||
end
|
||||
else begin
|
||||
$display("FAIL: struct == pattern");
|
||||
$stop;
|
||||
end
|
||||
|
|
@ -99,7 +106,8 @@ module t;
|
|||
// 8. Struct: NEQ with assignment pattern
|
||||
if (p1 != '{a: 8'hAA, b: 8'hFF}) begin
|
||||
// expected
|
||||
end else begin
|
||||
end
|
||||
else begin
|
||||
$display("FAIL: struct != pattern");
|
||||
$stop;
|
||||
end
|
||||
|
|
@ -111,7 +119,8 @@ module t;
|
|||
parr[1] = '{a: 8'h03, b: 8'h04};
|
||||
if (parr == '{'{a: 8'h01, b: 8'h02}, '{a: 8'h03, b: 8'h04}}) begin
|
||||
// expected
|
||||
end else begin
|
||||
end
|
||||
else begin
|
||||
$display("FAIL: array of structs == nested pattern");
|
||||
$stop;
|
||||
end
|
||||
|
|
@ -122,7 +131,8 @@ module t;
|
|||
wide_arr = '{32'hDEAD_BEEF, 32'hCAFE_BABE, 32'h1234_5678};
|
||||
if (wide_arr == '{32'hDEAD_BEEF, 32'hCAFE_BABE, 32'h1234_5678}) begin
|
||||
// expected
|
||||
end else begin
|
||||
end
|
||||
else begin
|
||||
$display("FAIL: wide array == pattern");
|
||||
$stop;
|
||||
end
|
||||
|
|
@ -130,7 +140,8 @@ module t;
|
|||
byte_arr = '{8'hAB, 8'hCD};
|
||||
if (byte_arr == '{8'hAB, 8'hCD}) begin
|
||||
// expected
|
||||
end else begin
|
||||
end
|
||||
else begin
|
||||
$display("FAIL: byte array == pattern");
|
||||
$stop;
|
||||
end
|
||||
|
|
@ -148,14 +159,16 @@ module t;
|
|||
// -------------------------------------------------------
|
||||
if (arr4_t'{10, 20, 30, 40} == arr4_t'{10, 20, 30, 40}) begin
|
||||
// expected
|
||||
end else begin
|
||||
end
|
||||
else begin
|
||||
$display("FAIL: typed pattern == typed pattern");
|
||||
$stop;
|
||||
end
|
||||
|
||||
if (arr4_t'{10, 20, 30, 40} != arr4_t'{10, 20, 30, 99}) begin
|
||||
// expected
|
||||
end else begin
|
||||
end
|
||||
else begin
|
||||
$display("FAIL: typed pattern != typed pattern");
|
||||
$stop;
|
||||
end
|
||||
|
|
|
|||
|
|
@ -14,21 +14,21 @@ module t;
|
|||
CROSS_NEG2 = -2,
|
||||
CROSS_NEG1, // -1
|
||||
CROSS_ZERO, // 0
|
||||
CROSS_POS1 // 1
|
||||
CROSS_POS1 // 1
|
||||
} cross_zero_e;
|
||||
|
||||
// Case 2: signed enum starting at zero
|
||||
typedef enum int {
|
||||
START_ZERO = 0,
|
||||
START_ONE, // 1
|
||||
START_TWO // 2
|
||||
START_ONE, // 1
|
||||
START_TWO // 2
|
||||
} start_zero_e;
|
||||
|
||||
// Case 3: signed enum all negative
|
||||
typedef enum int {
|
||||
ALL_NEG3 = -3,
|
||||
ALL_NEG2, // -2
|
||||
ALL_NEG1 // -1
|
||||
ALL_NEG1 // -1
|
||||
} all_neg_e;
|
||||
|
||||
// Case 4: signed enum starting at large negative, crossing zero
|
||||
|
|
@ -38,19 +38,17 @@ module t;
|
|||
WIDE_NEG1, // -1
|
||||
WIDE_ZERO, // 0
|
||||
WIDE_POS1, // 1
|
||||
WIDE_POS2 // 2
|
||||
WIDE_POS2 // 2
|
||||
} wide_cross_e;
|
||||
|
||||
// Case 5: signed enum single value at zero
|
||||
typedef enum int {
|
||||
SINGLE_ZERO = 0
|
||||
} single_zero_e;
|
||||
typedef enum int {SINGLE_ZERO = 0} single_zero_e;
|
||||
|
||||
// Case 6: signed enum starting at -1, crossing zero
|
||||
typedef enum int {
|
||||
FROM_NEG1 = -1,
|
||||
FROM_ZERO, // 0
|
||||
FROM_POS1 // 1
|
||||
FROM_POS1 // 1
|
||||
} from_neg1_e;
|
||||
|
||||
initial begin
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ endpackage
|
|||
// Inner types interface (mirrors xyz_types_if).
|
||||
// Provides types derived from cfg that the outer interface imports.
|
||||
interface inner_types_if #(
|
||||
parameter cfg3_pkg::cfg_t cfg = '0
|
||||
parameter cfg3_pkg::cfg_t cfg = '0
|
||||
) ();
|
||||
typedef logic [$clog2(cfg.NumIds)-1:0] trans_id_t;
|
||||
typedef logic [$clog2(cfg.NumThreads)-1:0] tl_index_t;
|
||||
|
|
@ -30,13 +30,13 @@ endinterface
|
|||
// Instantiates inner_types_if, imports types from it, and builds
|
||||
// compound struct typedefs that include those imported types.
|
||||
interface outer_types_if #(
|
||||
parameter cfg3_pkg::cfg_t cfg = '0
|
||||
parameter cfg3_pkg::cfg_t cfg = '0
|
||||
) ();
|
||||
localparam int NUM_ROWS = (cfg.Capacity / cfg.Slices) / 8;
|
||||
typedef logic [$clog2(NUM_ROWS)-1:0] row_addr_t;
|
||||
|
||||
// Nested interface - this is the trigger.
|
||||
inner_types_if #(cfg) inner_types();
|
||||
inner_types_if #(cfg) inner_types ();
|
||||
typedef inner_types.trans_id_t trans_id_t;
|
||||
typedef inner_types.tl_index_t tl_index_t;
|
||||
|
||||
|
|
@ -57,39 +57,39 @@ interface outer_types_if #(
|
|||
} addr_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic en;
|
||||
trans_id_t tag;
|
||||
tl_index_t tl;
|
||||
logic is_read;
|
||||
logic needs_resp;
|
||||
logic en;
|
||||
trans_id_t tag;
|
||||
tl_index_t tl;
|
||||
logic is_read;
|
||||
logic needs_resp;
|
||||
} meta_t;
|
||||
|
||||
typedef struct packed {
|
||||
meta_t meta;
|
||||
addr_t addr;
|
||||
meta_t meta;
|
||||
addr_t addr;
|
||||
logic [63:0] data;
|
||||
} rq_t;
|
||||
|
||||
// Compound packet type (mirrors iq_pkt_t)
|
||||
typedef struct packed {
|
||||
pkt_hdr_t hdr;
|
||||
rq_t payload;
|
||||
rq_t payload;
|
||||
} pkt_t;
|
||||
endinterface
|
||||
|
||||
// Width-parameterized FIFO (mirrors ring_fifo).
|
||||
module fifo3 #(
|
||||
parameter int p_width = 1,
|
||||
parameter int p_depth = 2
|
||||
parameter int p_width = 1,
|
||||
parameter int p_depth = 2
|
||||
) (
|
||||
input logic clk,
|
||||
input logic rst_n,
|
||||
input logic [p_width-1:0] push_dat_i,
|
||||
input logic push_vld_i,
|
||||
output logic [p_width-1:0] front_dat_o,
|
||||
output logic not_empty_o
|
||||
input logic clk,
|
||||
input logic rst_n,
|
||||
input logic [p_width-1:0] push_dat_i,
|
||||
input logic push_vld_i,
|
||||
output logic [p_width-1:0] front_dat_o,
|
||||
output logic not_empty_o
|
||||
);
|
||||
logic [p_width-1:0] mem [p_depth];
|
||||
logic [p_width-1:0] mem[p_depth];
|
||||
logic [$clog2(p_depth)-1:0] wptr, rptr;
|
||||
logic [p_depth:0] count;
|
||||
assign not_empty_o = (count != 0);
|
||||
|
|
@ -99,7 +99,8 @@ module fifo3 #(
|
|||
wptr <= '0;
|
||||
rptr <= '0;
|
||||
count <= '0;
|
||||
end else if (push_vld_i) begin
|
||||
end
|
||||
else if (push_vld_i) begin
|
||||
mem[wptr] <= push_dat_i;
|
||||
wptr <= wptr + 1;
|
||||
count <= count + 1;
|
||||
|
|
@ -114,19 +115,19 @@ endmodule
|
|||
// cell (in wrapper3's cell loop), before outer_types_if__Az1's nested
|
||||
// inner_types_if is deparameterized.
|
||||
module slice3 #(
|
||||
parameter cfg3_pkg::cfg_t cfg = '0,
|
||||
parameter int SLICE_IDX = 0,
|
||||
parameter type iq_pkt_t = logic,
|
||||
parameter type oq_pkt_t = logic
|
||||
parameter cfg3_pkg::cfg_t cfg = '0,
|
||||
parameter int SLICE_IDX = 0,
|
||||
parameter type iq_pkt_t = logic,
|
||||
parameter type oq_pkt_t = logic
|
||||
) (
|
||||
input logic clk,
|
||||
input logic rst_n,
|
||||
input logic in_vld,
|
||||
output logic out_vld,
|
||||
output iq_pkt_t fe_ot_pkt_o
|
||||
input logic clk,
|
||||
input logic rst_n,
|
||||
input logic in_vld,
|
||||
output logic out_vld,
|
||||
output iq_pkt_t fe_ot_pkt_o
|
||||
);
|
||||
// Local outer_types_if for other local types
|
||||
outer_types_if #(cfg) types();
|
||||
outer_types_if #(cfg) types ();
|
||||
typedef types.pkt_nid_t pkt_nid_t;
|
||||
|
||||
iq_pkt_t rqq_in, rqq_ot;
|
||||
|
|
@ -149,15 +150,15 @@ module slice3 #(
|
|||
// the nested inner_types_if inside outer_types_if__Az1 hasn't
|
||||
// been deparameterized, so trans_id_t/tl_index_t have wrong widths.
|
||||
fifo3 #(
|
||||
.p_width($bits(iq_pkt_t)),
|
||||
.p_depth(4)
|
||||
.p_width($bits(iq_pkt_t)),
|
||||
.p_depth(4)
|
||||
) rqq (
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
.push_dat_i(rqq_in),
|
||||
.push_vld_i(in_vld),
|
||||
.front_dat_o(rqq_ot),
|
||||
.not_empty_o(rqq_ot_vld)
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
.push_dat_i(rqq_in),
|
||||
.push_vld_i(in_vld),
|
||||
.front_dat_o(rqq_ot),
|
||||
.not_empty_o(rqq_ot_vld)
|
||||
);
|
||||
|
||||
assign fe_ot_pkt_o = rqq_ot;
|
||||
|
|
@ -168,14 +169,14 @@ endmodule
|
|||
// Creates outer_types_if, imports pkt_t, and passes it as a type
|
||||
// parameter to slice3 instances in a generate loop.
|
||||
module wrapper3 #(
|
||||
parameter cfg3_pkg::cfg_t cfg = '0
|
||||
parameter cfg3_pkg::cfg_t cfg = '0
|
||||
) (
|
||||
input logic clk,
|
||||
input logic rst_n
|
||||
input logic clk,
|
||||
input logic rst_n
|
||||
);
|
||||
outer_types_if #(cfg) types();
|
||||
outer_types_if #(cfg) types ();
|
||||
typedef types.pkt_t iq_pkt_t;
|
||||
typedef types.rq_t oq_pkt_t;
|
||||
typedef types.rq_t oq_pkt_t;
|
||||
|
||||
// Capture $bits of the type parameter for external checking.
|
||||
// If the nested inner_types_if hasn't been deparameterized before
|
||||
|
|
@ -188,16 +189,16 @@ module wrapper3 #(
|
|||
for (genvar i = 0; i < cfg.NumThreads; i++) begin : gen_slices
|
||||
iq_pkt_t fe_pkt;
|
||||
slice3 #(
|
||||
.cfg(cfg),
|
||||
.SLICE_IDX(i),
|
||||
.iq_pkt_t(iq_pkt_t),
|
||||
.oq_pkt_t(oq_pkt_t)
|
||||
.cfg(cfg),
|
||||
.SLICE_IDX(i),
|
||||
.iq_pkt_t(iq_pkt_t),
|
||||
.oq_pkt_t(oq_pkt_t)
|
||||
) u_slice (
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
.in_vld(1'b1),
|
||||
.out_vld(out_vld[i]),
|
||||
.fe_ot_pkt_o(fe_pkt)
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
.in_vld(1'b1),
|
||||
.out_vld(out_vld[i]),
|
||||
.fe_ot_pkt_o(fe_pkt)
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
|
|
@ -210,12 +211,7 @@ module t;
|
|||
|
||||
int cyc = 0;
|
||||
|
||||
localparam cfg3_pkg::cfg_t MY_CFG = '{
|
||||
Capacity: 8192,
|
||||
Slices: 8,
|
||||
NumThreads: 4,
|
||||
NumIds: 16
|
||||
};
|
||||
localparam cfg3_pkg::cfg_t MY_CFG = '{Capacity: 8192, Slices: 8, NumThreads: 4, NumIds: 16};
|
||||
// Expected widths:
|
||||
// trans_id_t = $clog2(16) = 4 bits
|
||||
// tl_index_t = $clog2(4) = 2 bits
|
||||
|
|
@ -231,19 +227,21 @@ module t;
|
|||
// These computations happen in the testbench module context where
|
||||
// the cfg parameter values are known constants, not through the
|
||||
// nested interface PARAMTYPEDTYPE chain.
|
||||
localparam int EXP_TRANS_ID_W = $clog2(MY_CFG.NumIds); // 4
|
||||
localparam int EXP_TL_INDEX_W = $clog2(MY_CFG.NumThreads); // 2
|
||||
localparam int EXP_ROW_ADDR_W = $clog2((MY_CFG.Capacity / MY_CFG.Slices) / 8); // 7
|
||||
localparam int EXP_PKT_NID_W = $clog2(MY_CFG.NumThreads); // 2
|
||||
localparam int EXP_PKT_HDR_W = 2 * EXP_PKT_NID_W; // 4
|
||||
localparam int EXP_ADDR_W = EXP_ROW_ADDR_W + EXP_TL_INDEX_W + 6; // 15
|
||||
localparam int EXP_META_W = 1 + EXP_TRANS_ID_W + EXP_TL_INDEX_W + 1 + 1; // 9
|
||||
localparam int EXP_RQ_W = EXP_META_W + EXP_ADDR_W + 64; // 88
|
||||
localparam int EXP_PKT_W = EXP_PKT_HDR_W + EXP_RQ_W; // 92
|
||||
localparam int EXP_TRANS_ID_W = $clog2(MY_CFG.NumIds); // 4
|
||||
localparam int EXP_TL_INDEX_W = $clog2(MY_CFG.NumThreads); // 2
|
||||
localparam int EXP_ROW_ADDR_W = $clog2((MY_CFG.Capacity / MY_CFG.Slices) / 8); // 7
|
||||
localparam int EXP_PKT_NID_W = $clog2(MY_CFG.NumThreads); // 2
|
||||
localparam int EXP_PKT_HDR_W = 2 * EXP_PKT_NID_W; // 4
|
||||
localparam int EXP_ADDR_W = EXP_ROW_ADDR_W + EXP_TL_INDEX_W + 6; // 15
|
||||
localparam int EXP_META_W = 1 + EXP_TRANS_ID_W + EXP_TL_INDEX_W + 1 + 1; // 9
|
||||
localparam int EXP_RQ_W = EXP_META_W + EXP_ADDR_W + 64; // 88
|
||||
localparam int EXP_PKT_W = EXP_PKT_HDR_W + EXP_RQ_W; // 92
|
||||
|
||||
wrapper3 #(.cfg(MY_CFG)) u_wrapper (
|
||||
.clk(clk),
|
||||
.rst_n(rst_n)
|
||||
wrapper3 #(
|
||||
.cfg(MY_CFG)
|
||||
) u_wrapper (
|
||||
.clk(clk),
|
||||
.rst_n(rst_n)
|
||||
);
|
||||
|
||||
// Self-check: verify that $bits(pkt_t) as seen through the nested
|
||||
|
|
@ -253,7 +251,8 @@ module t;
|
|||
// cfg.NumIds=0 instead of the actual value 16.
|
||||
initial begin
|
||||
if (u_wrapper.PKT_WIDTH != EXP_PKT_W) begin
|
||||
$display("%%Error: t_iface_nested_width3.v: $bits(pkt_t) = %0d, expected %0d", u_wrapper.PKT_WIDTH, EXP_PKT_W);
|
||||
$display("%%Error: t_iface_nested_width3.v: $bits(pkt_t) = %0d, expected %0d",
|
||||
u_wrapper.PKT_WIDTH, EXP_PKT_W);
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
18 | task clk.send(input logic [7:0] val);
|
||||
| ^~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: t/t_modport_export_bad.v:25:8: Interface port not found for out-of-block definition: 'nonexistent' (IEEE 1800-2023 25.7)
|
||||
25 | task nonexistent.send(input logic [7:0] val);
|
||||
%Error: t/t_modport_export_bad.v:27:8: Interface port not found for out-of-block definition: 'nonexistent' (IEEE 1800-2023 25.7)
|
||||
27 | task nonexistent.send(input logic [7:0] val);
|
||||
| ^~~~~~~~~~~
|
||||
%Error: t/t_modport_export_bad.v:40:8: No matching export prototype found in interface bus_if_noexport for task 'send' (IEEE 1800-2023 25.7)
|
||||
40 | task port.send(input logic [7:0] val);
|
||||
%Error: t/t_modport_export_bad.v:42:8: No matching export prototype found in interface bus_if_noexport for task 'send' (IEEE 1800-2023 25.7)
|
||||
42 | task port.send(input logic [7:0] val);
|
||||
| ^~~~
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -7,21 +7,23 @@
|
|||
interface bus_if;
|
||||
logic [7:0] data;
|
||||
|
||||
modport provider(
|
||||
output data,
|
||||
export task send(input logic [7:0] val)
|
||||
);
|
||||
modport provider(output data, export task send(input logic [7:0] val));
|
||||
endinterface
|
||||
|
||||
// Error 1: 'clk' is a plain wire port, not an interface port
|
||||
module driver1(bus_if.provider port, input logic clk);
|
||||
module driver1 (
|
||||
bus_if.provider port,
|
||||
input logic clk
|
||||
);
|
||||
task clk.send(input logic [7:0] val); // lint_off: UNUSED
|
||||
port.data = val;
|
||||
endtask
|
||||
endmodule
|
||||
|
||||
// Error 2: 'nonexistent' is not a port on this module
|
||||
module driver2(bus_if.provider port);
|
||||
module driver2 (
|
||||
bus_if.provider port
|
||||
);
|
||||
task nonexistent.send(input logic [7:0] val);
|
||||
port.data = val;
|
||||
endtask
|
||||
|
|
@ -30,23 +32,26 @@ endmodule
|
|||
interface bus_if_noexport;
|
||||
logic [7:0] data;
|
||||
|
||||
modport provider(
|
||||
output data
|
||||
);
|
||||
modport provider(output data);
|
||||
endinterface
|
||||
|
||||
// Error 3: no export prototype for 'send' in interface
|
||||
module driver3(bus_if_noexport.provider port);
|
||||
module driver3 (
|
||||
bus_if_noexport.provider port
|
||||
);
|
||||
task port.send(input logic [7:0] val);
|
||||
port.data = val;
|
||||
endtask
|
||||
endmodule
|
||||
|
||||
module t;
|
||||
bus_if bif();
|
||||
bus_if bif ();
|
||||
logic clk;
|
||||
driver1 drv1(.port(bif.provider), .clk(clk));
|
||||
driver2 drv2(.port(bif.provider));
|
||||
bus_if_noexport bif2();
|
||||
driver3 drv3(.port(bif2.provider));
|
||||
driver1 drv1 (
|
||||
.port(bif.provider),
|
||||
.clk(clk)
|
||||
);
|
||||
driver2 drv2 (.port(bif.provider));
|
||||
bus_if_noexport bif2 ();
|
||||
driver3 drv3 (.port(bif2.provider));
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -4,28 +4,32 @@
|
|||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0)
|
||||
// verilog_format: on
|
||||
|
||||
interface bus_if;
|
||||
logic [7:0] data;
|
||||
logic [7:0] result;
|
||||
|
||||
modport provider(
|
||||
output data,
|
||||
output result,
|
||||
export task send(input logic [7:0] val),
|
||||
export task accumulate(input logic [7:0] a, input logic [7:0] b)
|
||||
output data,
|
||||
output result,
|
||||
export task send(input logic [7:0] val),
|
||||
export task accumulate(input logic [7:0] a, input logic [7:0] b)
|
||||
);
|
||||
|
||||
modport consumer(
|
||||
input data,
|
||||
input result,
|
||||
import task send(input logic [7:0] val),
|
||||
import task accumulate(input logic [7:0] a, input logic [7:0] b)
|
||||
input data,
|
||||
input result,
|
||||
import task send(input logic [7:0] val),
|
||||
import task accumulate(input logic [7:0] a, input logic [7:0] b)
|
||||
);
|
||||
endinterface
|
||||
|
||||
module driver(bus_if.provider port);
|
||||
module driver (
|
||||
bus_if.provider port
|
||||
);
|
||||
task port.send(input logic [7:0] val);
|
||||
port.data = val;
|
||||
port.result = val + 8'h01;
|
||||
|
|
@ -38,8 +42,8 @@ module driver(bus_if.provider port);
|
|||
endmodule
|
||||
|
||||
module t;
|
||||
bus_if bif();
|
||||
driver drv(.port(bif.provider));
|
||||
bus_if bif ();
|
||||
driver drv (.port(bif.provider));
|
||||
|
||||
initial begin
|
||||
// Test 1: send -- multiple statements in task body
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@
|
|||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
|
|
|
|||
Loading…
Reference in New Issue