diff --git a/NOW.md b/NOW.md index 10ffeca94..02f62978c 100644 --- a/NOW.md +++ b/NOW.md @@ -2,6 +2,13 @@ Last updated: 2026-08-08 +## gen-verilog: hex/bin literals in array-literal text normalized; more SV keywords (Refs #1948) + +- The array-literal concat path works on raw source TEXT (not AST), so `0x38`/`0b..` element literals reached Verilog verbatim -- illegal (`8'(0x38)`). A text-level normalizer converts them to decimal +- SystemVerilog keyword list extended (context, local, new, null, inside, foreach, ...) -- a spec param named `context` emitted `input [31:0] context;` +- tri-net corpus: icarus 85 -> 88 (api_documenter, multipath_router, olsr_routing); link_quality_monitor advances from compile-error to a signed-i8 runtime divergence +- FROZEN_HASH resealed + ## gen-verilog: const-name array sizes resolved; packed array-literal locals; keyword-safe local names (Refs #1948) - `[u32; HISTORY_SIZE]` (const-name size) silently fell back to a 32-bit scalar input while `[u32; 16]` (literal) packed to 512 bits -- packed callers desynced from packed locals. All type strings now resolve const array sizes to numerics up front diff --git a/bootstrap/src/compiler.rs b/bootstrap/src/compiler.rs index cec7ffdad..e3bb9019a 100644 --- a/bootstrap/src/compiler.rs +++ b/bootstrap/src/compiler.rs @@ -4791,6 +4791,11 @@ impl VerilogCodegen { "program", "property", "protected", "pure", "rand", "randc", "ref", "return", "sequence", "shortint", "shortreal", "static", "string", "struct", "super", "this", "type", "typedef", "union", "unique", "var", "virtual", "void", + "context", "constraint", "covergroup", "coverpoint", "cross", "dist", + "expect", "foreach", "forkjoin", "iff", "inside", "join_any", + "join_none", "local", "matches", "modport", "new", "null", "solve", + "tagged", "throughout", "timeprecision", "timeunit", "wait_order", + "wildcard", "with", ] } @@ -4798,6 +4803,31 @@ impl VerilogCodegen { /// escaped form \\name when the name is a keyword, otherwise the /// original name. The trailing space is part of the escaped identifier /// syntax and must be preserved wherever the identifier is emitted. + /// Normalize Rust/t27 integer literals embedded in element TEXT (the + /// array-literal concat path works on raw source text, not AST nodes) to + /// plain Verilog decimal: `0x20`/`0b1010` and `_` separators are illegal + /// Verilog (t27#1948). Non-literal text (calls, idents) passes through. + fn verilog_normalize_literal_text(txt: &str) -> String { + let t = txt.trim(); + let clean: String = t.chars().filter(|&c| c != '_').collect(); + if let Some(hex) = clean.strip_prefix("0x").or_else(|| clean.strip_prefix("0X")) { + if !hex.is_empty() && hex.chars().all(|c| c.is_ascii_hexdigit()) { + if let Ok(n) = u128::from_str_radix(hex, 16) { + return n.to_string(); + } + } + } else if let Some(bin) = clean.strip_prefix("0b").or_else(|| clean.strip_prefix("0B")) { + if !bin.is_empty() && bin.chars().all(|c| c == '0' || c == '1') { + if let Ok(n) = u128::from_str_radix(bin, 2) { + return n.to_string(); + } + } + } else if !clean.is_empty() && clean.chars().all(|c| c.is_ascii_digit()) { + return clean; + } + t.to_string() + } + fn verilog_safe_identifier(name: &str) -> String { if Self::verilog_keywords().contains(&name) { format!("\\{} ", name) @@ -6163,7 +6193,7 @@ impl VerilogCodegen { if let Some((val, count)) = txt.rsplit_once(';') { if let Ok(n) = count.trim().parse::() { for _ in 0..n.min(current_dim) { - parts.push(format!("{}'({})", elem_w, val.trim())); + parts.push(format!("{}'({})", elem_w, Self::verilog_normalize_literal_text(val))); } } } else { @@ -6191,7 +6221,7 @@ impl VerilogCodegen { elems_txt.push(cur.trim().to_string()); } for e in elems_txt.iter().take(current_dim) { - parts.push(format!("{}'({})", elem_w, e)); + parts.push(format!("{}'({})", elem_w, Self::verilog_normalize_literal_text(e))); } } } diff --git a/bootstrap/stage0/FROZEN_HASH b/bootstrap/stage0/FROZEN_HASH index 48a4c9b1c..aa2d08387 100644 --- a/bootstrap/stage0/FROZEN_HASH +++ b/bootstrap/stage0/FROZEN_HASH @@ -1 +1 @@ -74e705b146049ff7648d2cf69a3fc43c53dc74fae10280cff21030b94bddebf5 +1cb67e85167378d36862a7f1294e1798f9bb8b432e77cec5a30584bc6ad3bbf3 diff --git a/docs/NOW.md b/docs/NOW.md index 08e9f92d2..2637faca2 100644 --- a/docs/NOW.md +++ b/docs/NOW.md @@ -2,6 +2,13 @@ Last updated: 2026-08-08 +## gen-verilog: hex/bin literals in array-literal text normalized; more SV keywords (Refs #1948) + +- The array-literal concat path works on raw source TEXT (not AST), so `0x38`/`0b..` element literals reached Verilog verbatim -- illegal (`8'(0x38)`). A text-level normalizer converts them to decimal +- SystemVerilog keyword list extended (context, local, new, null, inside, foreach, ...) -- a spec param named `context` emitted `input [31:0] context;` +- tri-net corpus: icarus 85 -> 88 (api_documenter, multipath_router, olsr_routing); link_quality_monitor advances from compile-error to a signed-i8 runtime divergence +- FROZEN_HASH resealed + ## gen-verilog: const-name array sizes resolved; packed array-literal locals; keyword-safe local names (Refs #1948) - `[u32; HISTORY_SIZE]` (const-name size) silently fell back to a 32-bit scalar input while `[u32; 16]` (literal) packed to 512 bits -- packed callers desynced from packed locals. All type strings now resolve const array sizes to numerics up front