From 372e93db3ac63a09e0c923701697ae4adac562fc Mon Sep 17 00:00:00 2001 From: mjoekhan Date: Tue, 21 Jul 2026 16:25:09 +0500 Subject: [PATCH 1/2] SV: parse ANSI class parameter port lists Allow class C #(type T = int, ...) so parameterized classes with defaults elaborate; add smoke examples and hello_uvm Makefile. --- docs/STATUS.md | 4 ++-- examples/hello_uvm/Makefile | 24 ++++++++++++++++++++++ examples/param_classes/box_default.sv | 29 +++++++++++++++++++++++++++ examples/param_classes/plain_class.sv | 21 +++++++++++++++++++ parse.y | 15 ++++++++++---- pform.h | 3 +++ pform_pclass.cc | 25 +++++++++++++++++++++++ 7 files changed, 115 insertions(+), 6 deletions(-) create mode 100644 examples/hello_uvm/Makefile create mode 100644 examples/param_classes/box_default.sv create mode 100644 examples/param_classes/plain_class.sv diff --git a/docs/STATUS.md b/docs/STATUS.md index 76c81ecb2..4c0c09235 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -12,8 +12,8 @@ Last updated: 2026-07-21 |------|--------| | Icarus Verilog tree | Fork of `steveicarus/iverilog` (`master` @ merge of SV array ordering work) | | [`uvm/`](../uvm/) | Seeded from IVL_UVM (VerifWorks) — messaging, CLP, stub phases, poor-man’s mailbox/semaphore; **not** Accellera-compatible | -| [`examples/hello_uvm`](../examples/hello_uvm) | Smoke TB for the seeded library | -| Parameterized classes | **In progress** on `feat/param-classes` | +| [`examples/hello_uvm`](../examples/hello_uvm) | Smoke TB for the seeded library (`Makefile` included) | +| Parameterized classes | **Partial** on `feat/param-classes`: ANSI `class C #(type T = int, parameter int W = 8);` parses into the class scope and elaborates with **defaults**. Explicit specializations `C#(byte)` / overrides not done yet. See [`examples/param_classes`](../examples/param_classes). | | Associative arrays | Missing | | Virtual interfaces | Missing | | Constraints / randomize | Missing | diff --git a/examples/hello_uvm/Makefile b/examples/hello_uvm/Makefile new file mode 100644 index 000000000..e9450d29c --- /dev/null +++ b/examples/hello_uvm/Makefile @@ -0,0 +1,24 @@ +# Build/run hello_uvm against the seeded uvm/ (IVL_UVM) library. +# Requires a configured install under ../../install (or IVERILOG/VVP on PATH). + +ROOT ?= $(abspath ../..) +IVL_UVM_HOME ?= $(ROOT)/uvm +PREFIX ?= $(ROOT)/install +IVERILOG ?= $(PREFIX)/bin/iverilog +VVP ?= $(PREFIX)/bin/vvp +VVP_MOD ?= $(PREFIX)/lib/ivl + +OUT := hello_uvm.vvp + +.PHONY: all run clean + +all: $(OUT) + +$(OUT): hello_uvm.sv flist.f + IVL_UVM_HOME=$(IVL_UVM_HOME) $(IVERILOG) -g2012 -o $@ -c flist.f + +run: $(OUT) + $(VVP) -M $(VVP_MOD) $(OUT) + +clean: + rm -f $(OUT) diff --git a/examples/param_classes/box_default.sv b/examples/param_classes/box_default.sv new file mode 100644 index 000000000..e74aea470 --- /dev/null +++ b/examples/param_classes/box_default.sv @@ -0,0 +1,29 @@ +// Smoke: ANSI class parameter port list with defaults (no explicit #() override). +class box #(type T = int, parameter int W = 8); + T val; + bit [W-1:0] data; + function new(T v); + val = v; + data = v; + endfunction + function T get(); + return val; + endfunction +endclass + +module top; + box b; + initial begin + b = new(42); + if (b.get() !== 42) begin + $display("FAIL: get=%0d", b.get()); + $finish(1); + end + if (b.data !== 8'h2a) begin + $display("FAIL: data=%0h", b.data); + $finish(1); + end + $display("PASS box_default val=%0d data=%0h", b.val, b.data); + $finish; + end +endmodule diff --git a/examples/param_classes/plain_class.sv b/examples/param_classes/plain_class.sv new file mode 100644 index 000000000..b7bac9d8d --- /dev/null +++ b/examples/param_classes/plain_class.sv @@ -0,0 +1,21 @@ +// Regression: plain (non-parameterized) class still works. +class counter; + int n; + function new(); n = 0; endfunction + function void inc(); n++; endfunction +endclass + +module top; + counter c; + initial begin + c = new; + c.inc(); + c.inc(); + if (c.n !== 2) begin + $display("FAIL n=%0d", c.n); + $finish(1); + end + $display("PASS plain_class n=%0d", c.n); + $finish; + end +endmodule diff --git a/parse.y b/parse.y index 9d4a6b45d..5279d022f 100644 --- a/parse.y +++ b/parse.y @@ -1237,7 +1237,9 @@ assertion_item_label_opt ; class_declaration /* IEEE1800-2005: A.1.2 */ - : K_virtual_opt K_class lifetime_opt identifier_name class_declaration_extends_opt ';' + /* Push the class scope before the optional #(...) parameter port list so + parameters land in the class LexicalScope (same idea as modules). */ + : K_virtual_opt K_class lifetime_opt identifier_name { /* Up to 1800-2017 the grammar in the LRM allowed an optional lifetime * qualifier for class declarations. But the LRM never specified what * this qualifier should do. Starting with 1800-2023 the qualifier has @@ -1253,15 +1255,20 @@ class_declaration /* IEEE1800-2005: A.1.2 */ class_type_t *class_type= new class_type_t(name); FILE_NAME(class_type, @4); pform_set_typedef(@4, name, class_type, nullptr); - pform_start_class_declaration(@2, class_type, $5.type, $5.args, $1); + /* Base class is filled in after parameter_port_list / extends. */ + pform_start_class_declaration(@2, class_type, 0, 0, $1); + } + module_parameter_port_list_opt + class_declaration_extends_opt ';' + { pform_set_class_extends(@7, $7.type, $7.args); } class_items_opt K_endclass { // Process a class. - pform_end_class_declaration(@9); + pform_end_class_declaration(@11); } label_opt { // Wrap up the class. - check_end_label(@11, "class", $4, $11); + check_end_label(@13, "class", $4, $13); delete[] $4; } ; diff --git a/pform.h b/pform.h index 0e0988fc8..b276b52e0 100644 --- a/pform.h +++ b/pform.h @@ -191,6 +191,9 @@ extern void pform_class_property(const struct vlltype&loc, extern void pform_set_this_class(const struct vlltype&loc, PTaskFunc*net); extern void pform_set_constructor_return(PFunction*net); +extern void pform_set_class_extends(const struct vlltype&loc, + data_type_t*base_type, + std::list *base_args); extern void pform_end_class_declaration(const struct vlltype&loc); extern bool pform_in_class(); diff --git a/pform_pclass.cc b/pform_pclass.cc index e9276a49a..307de6106 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -64,6 +64,31 @@ void pform_start_class_declaration(const struct vlltype&loc, } } +void pform_set_class_extends(const struct vlltype&loc, + data_type_t*base_type, + list *base_args) +{ + ivl_assert(loc, pform_cur_class); + class_type_t*type = pform_cur_class->type; + ivl_assert(loc, type); + + if (base_type == 0 && (base_args == 0 || base_args->empty())) { + if (base_args) + delete base_args; + return; + } + + ivl_assert(loc, type->base_type == 0); + type->base_type.reset(base_type); + + ivl_assert(loc, type->base_args.empty()); + if (base_args) { + type->base_args.insert(type->base_args.begin(), base_args->begin(), + base_args->end()); + delete base_args; + } +} + void pform_class_property(const struct vlltype&loc, property_qualifier_t property_qual, data_type_t*data_type, From 9182f4b102dc0d5ca1f0cd942db703782bb89eaf Mon Sep 17 00:00:00 2001 From: mjoekhan Date: Tue, 21 Jul 2026 16:28:32 +0500 Subject: [PATCH 2/2] docs: describe Tier A parameterized classes work Document grammar/pform changes, box_default smoke, and C#(byte) TODO on the iverilog-uvm track only. --- docs/param-classes.md | 52 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/param-classes.md diff --git a/docs/param-classes.md b/docs/param-classes.md new file mode 100644 index 000000000..c3d18fe5f --- /dev/null +++ b/docs/param-classes.md @@ -0,0 +1,52 @@ +# Tier A #1 — Parameterized classes + +Track: **muhammadjawadkhan/iverilog-uvm** only (`feat/param-classes`). Do not open PRs to `steveicarus/iverilog` for this work. + +## Goal + +Support SystemVerilog parameterized classes needed for Accellera-shaped UVM (`uvm_*#(T)`, `config_db`, etc.): + +```systemverilog +class C #(type T = int, parameter int W = 8); + // ... +endclass + +C#(byte) c; // explicit specialization — not done yet +``` + +## What landed (ANSI parameter ports + defaults) + +### Grammar (`parse.y`) + +`class_declaration` now pushes the class scope **before** the optional `#(...)` parameter port list (same idea as modules), then applies `extends`: + +1. `K_virtual_opt K_class lifetime_opt identifier_name` → start class / typedef (`pform_start_class_declaration` with base type deferred). +2. `module_parameter_port_list_opt` — reuse the existing module ANSI parameter-port grammar so `type T = int`, `parameter int W = 8`, etc. land in the class `LexicalScope`. +3. `class_declaration_extends_opt ';'` → `pform_set_class_extends(...)`. +4. class items / `endclass` as before. + +### Pform (`pform_pclass.cc` / `pform.h`) + +- **`pform_set_class_extends`** — fills `base_type` / `base_args` on the current class after the parameter port list (replacing the old path that passed extends into `pform_start_class_declaration` before `#(...)` could exist). +- Related: `pform_start_class_declaration`, `pform_end_class_declaration`, property helpers unchanged in role. + +With defaults present, a bare instance like `box b;` elaborates using those defaults. + +### Smoke example + +[`examples/param_classes/box_default.sv`](../examples/param_classes/box_default.sv) — `class box #(type T = int, parameter int W = 8);` constructed and used without an explicit `#()` override. Companion regression: `plain_class.sv`. + +```bash +iverilog -g2012 -o box_default.vvp examples/param_classes/box_default.sv && vvp box_default.vvp +# expect: PASS box_default ... +``` + +## TODO + +- [ ] Explicit specialization / overrides: `C#(byte)`, `C#(byte, 16)`, named overrides — parse, elaborate a specialized class type, and wire instances to it. +- [ ] Inheritance + parameters interactions as needed by UVM base classes. +- [ ] Broader ivtest coverage beyond the local smoke examples. + +## Status pointer + +See [STATUS.md](STATUS.md) (Parameterized classes row) and [ROADMAP.md](ROADMAP.md) Tier A item 1.