Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions src/intercard_link.sv
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,22 @@ module intercard_link #(
// Width-contract sanity: INTERCARD_LANES * INTERCARD_LANE_WIDTH must
// equal 128 (INTERCARD_BUS_WIDTH per the MAST #14 contract). Any
// override that breaks this contract will fail elaboration.
//
// NOTE on placement: $error sits directly in the generate body (NOT
// wrapped in `initial begin ... end`). Verilator `--lint-only` parses
// and elaborates the design but does NOT run `initial` blocks, so
// wrapping $error in `initial` would mask a contract violation under
// lint-only (issue #12). Generate-body $error is an IEEE 1800-2012
// elaboration-time construct and is enforced by Verilator at lint time.
// ------------------------------------------------------------------
localparam int INTERCARD_BUS_WIDTH = INTERCARD_LANES * INTERCARD_LANE_WIDTH;

initial begin
if (INTERCARD_BUS_WIDTH != 128) begin
generate
if (INTERCARD_BUS_WIDTH != 128) begin : g_width_contract_broken
$error("intercard_link: INTERCARD_LANES (%0d) * INTERCARD_LANE_WIDTH (%0d) = %0d, expected 128 (MAST #14 contract).",
INTERCARD_LANES, INTERCARD_LANE_WIDTH, INTERCARD_BUS_WIDTH);
end
end
endgenerate

// ------------------------------------------------------------------
// Stub body: tie outputs to safe defaults so synthesis/elab does not
Expand Down
15 changes: 11 additions & 4 deletions verif/intercard_link/test_widths.sv
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,19 @@ module test_widths;
localparam int ACTUAL_BUS_WIDTH = 4 /* INTERCARD_LANES */ *
32 /* INTERCARD_LANE_WIDTH */;

// $error sits DIRECTLY in the generate body (no `initial` wrapper).
// Lint-only mode does NOT run `initial` blocks, so wrapping would
// mask contract violations under lint-only (issue #12). The bare
// $error form is an IEEE 1800-2012 elaboration-time construct and
// is enforced at lint time.
//
// The "OK" branch retains `initial $display` because that path is
// observational, not a gate — when the contract holds, lint-only
// exits 0 and the display is a no-op (only meaningful under --binary).
generate
if (ACTUAL_BUS_WIDTH != EXPECT_BUS_WIDTH) begin : g_width_mismatch
// This $error fires at elaboration. Verilator surfaces it as
// an elaboration-time error and exits non-zero.
initial $error("intercard_link width contract broken: actual=%0d expected=%0d",
ACTUAL_BUS_WIDTH, EXPECT_BUS_WIDTH);
$error("intercard_link width contract broken: actual=%0d expected=%0d",
ACTUAL_BUS_WIDTH, EXPECT_BUS_WIDTH);
end else begin : g_width_ok
initial $display("[test_widths] INTERCARD_BUS_WIDTH = %0d (matches MAST #14 contract)",
ACTUAL_BUS_WIDTH);
Expand Down
Loading