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
28 changes: 28 additions & 0 deletions .trinity/seals/conformance_T27bConformanceVerilogPinAttrs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"built_by": "t27c-bootstrap@0.5.2+a86b691b1",
"closure": [],
"config": "gen=c,rust,verilog,zig;tests=zig",
"gen_hash_c": "sha256:3c5e7789036c884c6db63087b6826ba7d0fceebf565a1117366e444297f96403",
"gen_hash_rust": "sha256:23a28b4b1a5f4f7a0f0f9a90d5da3153a8d378767d7ea29ad47c2bd85fa234d8",
"gen_hash_verilog": "sha256:f769e899129496c1fde0c54f94000d19299033e3554f86c0c8073cc3f7bda02c",
"gen_hash_zig": "sha256:7313bb5a528c122c2a2b8d745cbb7c41c64b72b3585e6d92a7e748de4e359202",
"module": "T27bConformanceVerilogPinAttrs",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-18T04:19:01Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:4319dbdf900eafa8d0bfc95fe7aaf87c0455152f7d92d4db5661143be11da83e",
"spec_path": "specs/tri/t27b/conformance/verilog_pin_attrs.t27",
"tests": {
"failed": 0,
"failing": [],
"forced": false,
"passed": 3,
"total": 3,
"vacuous": 0
},
"toolchain": {
"test_runner": "sha256:1982ae948e24d00c5d221ccec12dfce1eb01204b53e37b0f857f93b16d64629d",
"zig": "0.16.0"
}
}
18 changes: 9 additions & 9 deletions .trinity/seals/t27b_T27bVerilogEmit.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,27 @@
},
{
"spec": "specs/tri/t27b/verilog_plan.t27",
"spec_hash": "sha256:e83cfc469873ff2317ab1ec4afcf775e576028e572adc232052dbfc46ee26507"
"spec_hash": "sha256:c71ad7c23e4e17dc1289fad6c6e11b118d85bcff6002d5165263774200ea6bb0"
}
],
"config": "gen=c,rust,verilog,zig;tests=zig",
"gen_hash_c": "sha256:3b1d0af3d223ece81d76f46e7a17a4b7be4870207c15fb7b8fa0e277a8735f82",
"gen_hash_rust": "sha256:1fe1d2a06eef20f16e92c0d521185806db1cbb60e5779335e0f37eb6a6689f7f",
"gen_hash_verilog": "sha256:587cc7d8f59751c39692c49ffe252663cfe9a204f24725325f92d628cf1aed3b",
"gen_hash_zig": "sha256:09c7cbba8fe1c04837f3561924bffefff20a77e1d1ee03a36fe900da1d52f3ff",
"gen_hash_c": "sha256:584f47df1d6ade6798722fa33b3df656a95667420215ebe815ddb7421ca66444",
"gen_hash_rust": "sha256:49081e7dffcef5342fc40c42c2760db4a29e86a6b88badcccd5dad66fdfba811",
"gen_hash_verilog": "sha256:1a385b65b99093e2addc4adf6f382d110186574b7ad1fcf83a0c41e7e13d304e",
"gen_hash_zig": "sha256:404bcae3892f3be78ba2755b203d92d0b582de42653dc9bec5d90399c763704d",
"module": "T27bVerilogEmit",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-18T03:40:42Z",
"sealed_at": "2026-10-18T04:19:01Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:4fadad47612defd88ad1e3e3160aac802ac5f9e0a122fc33f058105923a0c903",
"spec_hash": "sha256:c34cd680a2f832cf513fb55a3b19956d16649604e605b1f01eaa3cf4294380df",
"spec_path": "specs/tri/t27b/verilog_emit.t27",
"tests": {
"failed": 0,
"failing": [],
"forced": false,
"passed": 9,
"total": 9,
"passed": 10,
"total": 10,
"vacuous": 0
},
"toolchain": {
Expand Down
16 changes: 8 additions & 8 deletions .trinity/seals/t27b_T27bVerilogPlan.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@
}
],
"config": "gen=c,rust,verilog,zig;tests=zig",
"gen_hash_c": "sha256:5a6a8b00e27811871acf66e81b547b3ba1e7a81b2388f0faae2487575c151f01",
"gen_hash_rust": "sha256:828a636e0d7dd3c1814667902d86436433ab6cc6e58e4ed163ee1b4a431b4c37",
"gen_hash_verilog": "sha256:b053716c93b085c72fbefadead49d3371ec4c11f3fa8cc9affc711770ad6174f",
"gen_hash_zig": "sha256:29602f8d57a5df9a641adb65e9b96f119bf74b018f97d57e1d621e6f68ec1c14",
"gen_hash_c": "sha256:f8813a08094b5fc36dc1fd089229cad13108eaf2b515a010ec213dd554052bed",
"gen_hash_rust": "sha256:e4860aa2da6eb2159bc505ac625c4880fba5fdb25ffe8953f2280c23be67d135",
"gen_hash_verilog": "sha256:71f948e58983e4e5390acbef7144e44371a76bd7b9cd55294df1d99865d92e7a",
"gen_hash_zig": "sha256:c59ac64c3064eaf401315d43ece71253b0917172f8337efbf01fd59a4f6ddacf",
"module": "T27bVerilogPlan",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-18T03:40:41Z",
"sealed_at": "2026-10-18T04:18:58Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:e83cfc469873ff2317ab1ec4afcf775e576028e572adc232052dbfc46ee26507",
"spec_hash": "sha256:c71ad7c23e4e17dc1289fad6c6e11b118d85bcff6002d5165263774200ea6bb0",
"spec_path": "specs/tri/t27b/verilog_plan.t27",
"tests": {
"failed": 0,
"failing": [],
"forced": false,
"passed": 17,
"total": 17,
"passed": 18,
"total": 18,
"vacuous": 0
},
"toolchain": {
Expand Down
1 change: 1 addition & 0 deletions docs/reports/t27b_expectations.json
Original file line number Diff line number Diff line change
Expand Up @@ -1635,6 +1635,7 @@
{"path": "specs/tri/t27b/conformance/value_params.t27", "t27b": "pass"},
{"path": "specs/tri/t27b/conformance/verilog_lib.t27", "t27b": "pass"},
{"path": "specs/tri/t27b/conformance/verilog_odd_cast.t27", "t27b": "pass"},
{"path": "specs/tri/t27b/conformance/verilog_pin_attrs.t27", "t27b": "pass"},
{"path": "specs/tri/t27b/conformance/verilog_prim.t27", "t27b": "pass"},
{"path": "specs/tri/t27b/conformance/verilog_use.t27", "t27b": "pass"},
{"path": "specs/tri/t27b/conformance/verilog_wide_inout.t27", "t27b": "pass"},
Expand Down
159 changes: 150 additions & 9 deletions gen/rust/tri/t27b/verilog_emit.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Generated from .t27 spec
// DO NOT EDIT — generated by t27c
// NOT LOWERED BY THIS BACKEND: 9 test(s), 0 invariant(s), 0 function(s) with no body.
// NOT LOWERED BY THIS BACKEND: 10 test(s), 0 invariant(s), 0 function(s) with no body.
// This backend emits declarations only. The spec's checks live in
// the Zig and Verilog outputs; do not read this file as verified.

Expand Down Expand Up @@ -382,6 +382,88 @@ pub fn is_const_expr(nodes: &[u8], text: &[u8], meta: &[u8], ptext: &[u8], item:
return fold_ok(nodes, text, meta, ptext, item, i, 0);
}

pub fn is_str_const(nodes: &[u8], text: &[u8], meta: &[u8], d: usize) -> bool {
if (((kind(nodes, d) != K_CONST_DECL) || is_mut(meta, d)) || ((d + 1) >= end(nodes, d))) {
return false;
}
return ((kind(nodes, (d + 1)) == K_EXPR_LITERAL) && field_eq(nodes, text, (d + 1), F_KIND, "string"));
}

pub fn pin_decl(nodes: &[u8], text: &[u8], meta: &[u8], k: usize, port: &[u8]) -> i64 {
let mut d: usize = 1;
while (d < end(nodes, 0)) {
if (is_str_const(nodes, text, meta, d) && declares_pin(text, lo(nodes, d, F_NAME), hi(nodes, d, F_NAME), k, port)) {
let di: i64 = (d as _);
return di;
}
d = end(nodes, d);
}
return NO_NODE;
}

pub fn put_pins(out: &mut [u8], at: usize, nodes: &[u8], text: &[u8], meta: &[u8], port: &[u8]) -> usize {
let mut q: usize = put_text(out, at, "\n ");
let mut k: usize = 0;
while (k < PIN_KEYS) {
let d: i64 = pin_decl(nodes, text, meta, k, port);
if (d != NO_NODE) {
let du: usize = (d as _);
q = put_text(out, q, "(* ");
q = put_text(out, q, pin_key(k));
q = put_text(out, q, " = \"");
q = put_bytes(out, q, text, lo(nodes, (du + 1), F_VALUE), hi(nodes, (du + 1), F_VALUE));
q = put_text(out, q, "\" *) ");
}
k = (k + 1);
}
return q;
}

pub fn is_port(nodes: &[u8], text: &[u8], meta: &[u8], ptext: &[u8], oc: i64, name: &[u8]) -> bool {
if (oc != NO_NODE) {
if same(name, "clk") {
return !(has_net(nodes, text, meta, ptext, "clk"));
}
if same(name, "rst_n") {
return !(has_net(nodes, text, meta, ptext, "rst_n"));
}
if same(name, "en") {
return !(has_net(nodes, text, meta, ptext, "en"));
}
let oci: usize = (oc as _);
let np: usize = param_count(ptext, params_lo(meta, oci), params_hi(meta, oci));
let mut kx: usize = 0;
while (kx < np) {
let pa: usize = param_name_lo(meta, ptext, oci, kx);
let pb: usize = param_name_hi(meta, ptext, oci, kx);
if ((((pb - pa) == name.len()) && has_at(ptext, pa, pb, name)) && (bound_instance(nodes, text, meta, ptext, pa, pb) == NO_NODE)) {
return true;
}
kx = (kx + 1);
}
}
let dp: bool = declares_ports(nodes, text, meta, ptext);
let mut c: usize = 1;
while (c < end(nodes, 0)) {
if (((kind(nodes, c) == K_CONST_DECL) && ((hi(nodes, c, F_NAME) - lo(nodes, c, F_NAME)) == name.len())) && has_at(text, lo(nodes, c, F_NAME), hi(nodes, c, F_NAME), name)) {
let cl: u8 = item_class(nodes, text, meta, ptext, c);
if ((cl == C_INPUT) || (cl == C_INOUT)) {
return true;
}
return is_output(nodes, text, meta, ptext, c, dp);
}
c = end(nodes, c);
}
return false;
}

pub fn pin_named(nodes: &[u8], text: &[u8], meta: &[u8], ptext: &[u8], oc: i64, d: usize) -> bool {
let ca: usize = lo(nodes, d, F_NAME);
let cb: usize = hi(nodes, d, F_NAME);
let key: &'static str = pin_key(pin_kind(text, ca, cb));
return is_port(nodes, text, meta, ptext, oc, &text[(ca) as usize..(((cb - key.len()) - 1)) as usize]);
}

pub fn item_class(nodes: &[u8], text: &[u8], meta: &[u8], ptext: &[u8], c: usize) -> u8 {
let k: u8 = kind(nodes, c);
if (k == K_FN_DECL) {
Expand Down Expand Up @@ -1699,21 +1781,24 @@ pub fn ports(out: &mut [u8], at: usize, nodes: &[u8], text: &[u8], meta: &[u8],
let mut first: bool = true;
if (oc != NO_NODE) {
if !(has_net(nodes, text, meta, ptext, "clk")) {
q = put_text(out, q, "\n input wire clk");
q = put_pins(out, q, nodes, text, meta, b"clk");
q = put_text(out, q, "input wire clk");
first = false;
}
if !(has_net(nodes, text, meta, ptext, "rst_n")) {
if !(first) {
q = put_text(out, q, ",");
}
q = put_text(out, q, "\n input wire rst_n");
q = put_pins(out, q, nodes, text, meta, b"rst_n");
q = put_text(out, q, "input wire rst_n");
first = false;
}
if !(has_net(nodes, text, meta, ptext, "en")) {
if !(first) {
q = put_text(out, q, ",");
}
q = put_text(out, q, "\n input wire en");
q = put_pins(out, q, nodes, text, meta, b"en");
q = put_text(out, q, "input wire en");
first = false;
}
let oci: usize = (oc as _);
Expand All @@ -1730,7 +1815,8 @@ pub fn ports(out: &mut [u8], at: usize, nodes: &[u8], text: &[u8], meta: &[u8],
if !(first) {
q = put_text(out, q, ",");
}
q = put_text(out, q, "\n input wire ");
q = put_pins(out, q, nodes, text, meta, &ptext[(pa) as usize..(pb) as usize]);
q = put_text(out, q, "input wire ");
q = put_range(out, q, pt);
q = put_name(out, q, ptext, pa, pb);
first = false;
Expand All @@ -1748,7 +1834,8 @@ pub fn ports(out: &mut [u8], at: usize, nodes: &[u8], text: &[u8], meta: &[u8],
if !(first) {
q = put_text(out, q, ",");
}
q = put_text(out, q, "\n input wire ");
q = put_pins(out, q, nodes, text, meta, &text[(lo(nodes, ci, F_NAME)) as usize..(hi(nodes, ci, F_NAME)) as usize]);
q = put_text(out, q, "input wire ");
q = put_range(out, q, it);
q = put_name(out, q, text, lo(nodes, ci, F_NAME), hi(nodes, ci, F_NAME));
first = false;
Expand All @@ -1765,7 +1852,8 @@ pub fn ports(out: &mut [u8], at: usize, nodes: &[u8], text: &[u8], meta: &[u8],
if !(first) {
q = put_text(out, q, ",");
}
q = put_text(out, q, "\n inout wire ");
q = put_pins(out, q, nodes, text, meta, &text[(lo(nodes, co, F_NAME)) as usize..(hi(nodes, co, F_NAME)) as usize]);
q = put_text(out, q, "inout wire ");
q = put_range(out, q, iot);
q = put_name(out, q, text, lo(nodes, co, F_NAME), hi(nodes, co, F_NAME));
first = false;
Expand All @@ -1783,10 +1871,11 @@ pub fn ports(out: &mut [u8], at: usize, nodes: &[u8], text: &[u8], meta: &[u8],
if !(first) {
q = put_text(out, q, ",");
}
q = put_pins(out, q, nodes, text, meta, &text[(lo(nodes, c, F_NAME)) as usize..(hi(nodes, c, F_NAME)) as usize]);
if (item_class(nodes, text, meta, ptext, c) == C_VAR) {
q = put_text(out, q, "\n output reg ");
q = put_text(out, q, "output reg ");
} else {
q = put_text(out, q, "\n output wire ");
q = put_text(out, q, "output wire ");
}
q = put_range(out, q, t);
q = put_name(out, q, text, lo(nodes, c, F_NAME), hi(nodes, c, F_NAME));
Expand Down Expand Up @@ -2120,6 +2209,9 @@ pub fn module_text(out: &mut [u8], at: usize, nodes: &[u8], text: &[u8], meta: &
if (((cl == C_CONST) && is_period_name(text, lo(nodes, c, F_NAME), hi(nodes, c, F_NAME))) && !(period_named(nodes, text, meta, ptext, c))) {
return fail(out, nodes, meta, text, c, "clock period declared for no instance output", lo(nodes, c, F_NAME), hi(nodes, c, F_NAME));
}
if ((is_str_const(nodes, text, meta, c) && (pin_kind(text, lo(nodes, c, F_NAME), hi(nodes, c, F_NAME)) != PIN_KEYS)) && !(pin_named(nodes, text, meta, ptext, oc, c))) {
return fail(out, nodes, meta, text, c, "pin attribute for no port of the module", lo(nodes, c, F_NAME), hi(nodes, c, F_NAME));
}
if (cl == C_VAR) {
let t: i64 = sym_type(nodes, text, meta, ptext, 0, sym_of(SYM_TOP, c), 0);
if !(ty_scalar(t)) {
Expand Down Expand Up @@ -3122,6 +3214,8 @@ pub const OP_SHIFT: u8 = 2;

pub const PERIOD_SUFFIX: &'static str = "_PERIOD_PS";

pub const PIN_KEYS: usize = 4;

pub const ROLE_ATTR: u8 = 3;

pub const ROLE_BAD: u8 = 0;
Expand Down Expand Up @@ -3196,6 +3290,17 @@ pub fn declares_period(text: &[u8], ca: usize, cb: usize, ia: usize, ib: usize,
return binds(text, ca, (cb - PERIOD_SUFFIX.len()), text, ia, ib, fa, fb);
}

pub fn declares_pin(text: &[u8], ca: usize, cb: usize, k: usize, port: &[u8]) -> bool {
if !(is_pin_name(text, ca, cb, k)) {
return false;
}
let key: &'static str = pin_key(k);
if ((cb - ca) != ((port.len() + 1) + key.len())) {
return false;
}
return has_at(text, ca, cb, port);
}

pub fn digit_of(c: u8) -> u64 {
if ((c >= 48) && (c <= 57)) {
return ((c - 48) as u64);
Expand Down Expand Up @@ -3389,6 +3494,18 @@ pub fn is_period_name(text: &[u8], ca: usize, cb: usize) -> bool {
return same(&text[((cb - s)) as usize..(cb) as usize], PERIOD_SUFFIX);
}

pub fn is_pin_name(text: &[u8], ca: usize, cb: usize, k: usize) -> bool {
let key: &'static str = pin_key(k);
let s: usize = key.len();
if (cb < ((ca + s) + 2)) {
return false;
}
if (text[(((cb - s) - 1)) as usize] != 95) {
return false;
}
return same(&text[((cb - s)) as usize..(cb) as usize], key);
}

pub fn is_pub(meta: &[u8], i: usize) -> bool {
return ((meta_word(meta, i, 0) & FLAG_PUB) == FLAG_PUB);
}
Expand Down Expand Up @@ -3656,6 +3773,30 @@ pub fn peer(a: i64, b: i64) -> i64 {
return TY_BAD;
}

pub fn pin_key(k: usize) -> &'static str {
if (k == 0) {
return "LOC";
}
if (k == 1) {
return "IOSTANDARD";
}
if (k == 2) {
return "SLEW";
}
return "IN_TERM";
}

pub fn pin_kind(text: &[u8], ca: usize, cb: usize) -> usize {
let mut k: usize = 0;
while (k < PIN_KEYS) {
if is_pin_name(text, ca, cb, k) {
return k;
}
k = (k + 1);
}
return PIN_KEYS;
}

pub fn port_name_end(ps: &[u8], a: usize, b: usize) -> usize {
if ((b > (a + 1)) && (ps[((b - 1)) as usize] == 95)) {
return (b - 1);
Expand Down
Loading
Loading