Merge pull request #6 from muhammadjawadkhan/feat/param-classes
SV: ANSI class parameter port lists (defaults)
This commit is contained in:
commit
39e757e975
|
|
@ -12,8 +12,8 @@ Last updated: 2026-07-21
|
||||||
|------|--------|
|
|------|--------|
|
||||||
| Icarus Verilog tree | Fork of `steveicarus/iverilog` (`master` @ merge of SV array ordering work) |
|
| 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 |
|
| [`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 |
|
| [`examples/hello_uvm`](../examples/hello_uvm) | Smoke TB for the seeded library (`Makefile` included) |
|
||||||
| Parameterized classes | **In progress** on `feat/param-classes` |
|
| 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 |
|
| Associative arrays | Missing |
|
||||||
| Virtual interfaces | Missing |
|
| Virtual interfaces | Missing |
|
||||||
| Constraints / randomize | Missing |
|
| Constraints / randomize | Missing |
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
15
parse.y
15
parse.y
|
|
@ -1237,7 +1237,9 @@ assertion_item_label_opt
|
||||||
;
|
;
|
||||||
|
|
||||||
class_declaration /* IEEE1800-2005: A.1.2 */
|
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
|
{ /* Up to 1800-2017 the grammar in the LRM allowed an optional lifetime
|
||||||
* qualifier for class declarations. But the LRM never specified what
|
* qualifier for class declarations. But the LRM never specified what
|
||||||
* this qualifier should do. Starting with 1800-2023 the qualifier has
|
* 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);
|
class_type_t *class_type= new class_type_t(name);
|
||||||
FILE_NAME(class_type, @4);
|
FILE_NAME(class_type, @4);
|
||||||
pform_set_typedef(@4, name, class_type, nullptr);
|
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
|
class_items_opt K_endclass
|
||||||
{ // Process a class.
|
{ // Process a class.
|
||||||
pform_end_class_declaration(@9);
|
pform_end_class_declaration(@11);
|
||||||
}
|
}
|
||||||
label_opt
|
label_opt
|
||||||
{ // Wrap up the class.
|
{ // Wrap up the class.
|
||||||
check_end_label(@11, "class", $4, $11);
|
check_end_label(@13, "class", $4, $13);
|
||||||
delete[] $4;
|
delete[] $4;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
|
||||||
3
pform.h
3
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_this_class(const struct vlltype&loc, PTaskFunc*net);
|
||||||
extern void pform_set_constructor_return(PFunction*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<named_pexpr_t> *base_args);
|
||||||
extern void pform_end_class_declaration(const struct vlltype&loc);
|
extern void pform_end_class_declaration(const struct vlltype&loc);
|
||||||
extern bool pform_in_class();
|
extern bool pform_in_class();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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<named_pexpr_t> *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,
|
void pform_class_property(const struct vlltype&loc,
|
||||||
property_qualifier_t property_qual,
|
property_qualifier_t property_qual,
|
||||||
data_type_t*data_type,
|
data_type_t*data_type,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue