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
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ jobs:
run: cabal run gatework -- --netlist fixtures/bus.net --duration 3 --output /tmp/bus.vcd --set a=0101,b=1010
- name: Compare the bus demo with the golden file
run: diff fixtures/bus.golden.vcd /tmp/bus.vcd
- name: Run the four-state vector demo
run: cabal run gatework -- --netlist fixtures/vector4.net --duration 2 --output /tmp/vector4.vcd --set a=0z01,b=01x0,en=1 --at 2 en=0
- name: Compare the vector demo with the golden file
run: diff fixtures/vector4.golden.vcd /tmp/vector4.vcd
- name: Run the shared bus demo
run: cabal run gatework -- --netlist fixtures/shared.net --duration 8 --output /tmp/shared.vcd --set d0=0,e0=0,d1=1,e1=0 --at 2 e0=1 --at 4 e1=1 --at 6 e0=0
- name: Compare the shared bus demo with the golden file
Expand Down
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,26 @@ All notable changes to Gatework appear in this file.
The format follows the Keep a Changelog convention.
This project uses semantic versioning.

## [0.12.0.0] - 2026-08-03

### Added

- Render each bus as one multi-bit vector in the VCD header.
- Group bus values into one line in the VCD timeline.
- Use the standard VCD vector syntax for the values.
- Include unknown and floating values inside vector strings.
- Detect module-internal buses after flattening.
- Add a four-state vector demo fixture and a golden waveform.
- Add deterministic tests and a QuickCheck property for vector output.
- Extend the CI workflow to run the vector demo.

### Changed

- Group all bus bits under one VCD variable and identifier.
- Bump the package version to 0.12.0.0.
- Update the golden VCD files to the new version string.
- Update the bus golden file to the vector format.

## [0.11.0.0] - 2026-08-03

### Added
Expand Down
128 changes: 98 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ You can do these tasks:
- Sample a whole bus into a register on one clock edge.
- Check a single bus bit with an assertion.
- Set a whole bus on the command line with one bit string.
- Read a whole bus as one multi-bit VCD vector.
- See unknown and floating values inside a VCD vector.
- Group module-internal buses into VCD vectors too.

## Architecture

Expand All @@ -56,7 +59,7 @@ The project has five library modules.
| `Gatework.Netlist` | Parses, validates, and flattens circuit files |
| `Gatework.Report` | Renders the waveform as a text table |
| `Gatework.Simulator` | Schedules signal changes |
| `Gatework.VCD` | Renders the waveform text |
| `Gatework.VCD` | Renders waveform text as signals and bus vectors |

The data flow is:

Expand All @@ -81,6 +84,7 @@ An asserted reset forces flip-flop outputs to their initial values.
The recorder keeps the initial value and every later transition.
The assertion checker compares declared expectations with the waveform.
The VCD writer uses stable signal order and stable identifiers.
The VCD writer groups bus bits into multi-bit vectors.
The report writer prints one row per change time.

The repository layout is:
Expand Down Expand Up @@ -504,6 +508,62 @@ The value 0101 means `a[0]=1`, `a[1]=0`, `a[2]=1`, and `a[3]=0`.
Bit 0 is the least-significant bit.
The value 1010 means `b[0]=0`, `b[1]=1`, `b[2]=0`, and `b[3]=1`.

## Multi-bit VCD vectors

Run the four-state vector demo.

```powershell
cabal run gatework -- --netlist fixtures/vector4.net --duration 2 --output vector4.vcd --set a=0z01,b=01x0,en=1 --at 2 en=0
```

The command writes this output:

```text
Wrote vector4.vcd
Signals: 15
Duration: 2 time units
Assertions: 6 passed
```

The VCD header declares each bus as one vector.

```text
$var wire 4 ! a[3:0] $end
$var wire 4 " b[3:0] $end
$var wire 1 # en $end
$var wire 4 $ x[3:0] $end
$var wire 2 % m[1:0] $end
```

The vector name shows the declared width and the bit range.
The timeline lists the whole bus value at each change time.

```text
#0
b0z01!
b01x0"
1#
b0xx1$
bx1%
#2
0#
bzz%
```

A vector value starts with the letter b.
The bit string lists the most-significant bit first.
The value `b0xx1` means x[3]=0, x[2]=x, x[1]=x, and x[0]=1.
Unknown and floating values appear inside the string.

| Time | a[3:0] | b[3:0] | en | x[3:0] | m[1:0] |
| --- | --- | --- | --- | --- | --- |
| 0 | 0z01 | 01x0 | 1 | 0xx1 | x1 |
| 2 | 0z01 | 01x0 | 0 | 0xx1 | zz |

At time 2 the enable goes low.
Both tri-state buffers float, so m reads zz.
The whole vector changes together on one line.

## Sample output

The file `fixtures/counter.golden.vcd` holds the complete counter waveform.
Expand Down Expand Up @@ -617,41 +677,41 @@ x#
```

The file `fixtures/bus.golden.vcd` holds the bus demo waveform.
Its header maps each bus bit to one identifier:
Its header declares each bus as one vector:

```text
$var wire 1 ! a[0] $end
$var wire 1 " a[1] $end
$var wire 1 # a[2] $end
$var wire 1 $ a[3] $end
$var wire 4 ! a[3:0] $end
$var wire 4 " b[3:0] $end
$var wire 4 # x[3:0] $end
$var wire 4 $ n[3:0] $end
$var wire 4 % q[3:0] $end
$var wire 1 & clk $end
$var wire 2 ' hi[1:0] $end
$var wire 1 ( c0 $end
```

Its timeline shows the settled values after the zero-delay transients:
Its timeline shows the settled vector values after the zero-delay transients:

```text
#0
1)
1*
1+
1,
0-
0.
0/
00
18
b0101!
b1010"
b1111#
b0000$
b0000%
0&
b00'
0(
1(
#1
11
12
13
14
15
b1111%
1&
```

Here `)` is `x[0]`, `-` is `n[0]`, and `0` is `n[3]`.
The value `18` means `c0` is high.
The value `00` means `n[3]` is low.
The identifier `1` is `q[0]`.
The register outputs change together on the clock edge.
Here `!` is `a`, `#` is `x`, `$` is `n`, and `%` is `q`.
The value `b0101` means `a[3]=0`, `a[2]=1`, `a[1]=0`, and `a[0]=1`.
The value `b1111` means every bit of `x` is high.
The register output `q` changes together on the clock edge.

## Netlist format

Expand Down Expand Up @@ -909,6 +969,7 @@ Deterministic tests also cover multi-driver resolution, scheduled driver changes
Deterministic tests also cover module library loading, cross-library module references, duplicate module names, and library file validation.
Deterministic tests also cover the report command, its header order, its counter table, and its golden output.
Deterministic tests also cover whole-bus input values, their bit order, their error cases, scheduled whole-bus transitions, and their golden output.
Deterministic tests also cover VCD vectors, their header declarations, their grouped values, four-state vector values, and module-internal bus vectors.
QuickCheck properties cover gate algebra, full adder correctness, scheduled input sampling, reset sampling, register width, and assertion soundness.
QuickCheck properties also compare the hierarchical adder and counter with their flat versions.
QuickCheck properties also cover the four-state model and the tri-state buffer truth table.
Expand All @@ -917,6 +978,7 @@ QuickCheck properties also compare the shared bus with a per-time resolution mod
QuickCheck properties also compare a library adder with its flat version.
QuickCheck properties also compare the counter report with the simulated waveform.
QuickCheck properties also compare whole-bus input values with per-bit reference values.
QuickCheck properties also compare every VCD vector value with the per-bit waveform.

QuickCheck runs one hundred random cases for each property.
The gate properties cover the complete truth table.
Expand All @@ -935,16 +997,18 @@ The bus hierarchy property shows that a bus module matches its flat circuit.
The shared-bus property compares each resolved wire value with a per-time model.
The library adder property compares a library netlist with the flat adder.
The counter report property compares each report cell with the simulated value.
The VCD vector property compares each vector value with the per-bit values at that time.

## Test status

All tests pass on GHC 9.6.7 with Cabal 3.14 in the bundled container.
The CI workflow runs the same checks on Ubuntu with GHC 9.6.6.
Golden tests compare the counter, register, reset, two-bit register, assertion, gate, hierarchical adder, library adder, hierarchical counter, adder, tri-state, undefined-state, bus, and shared-bus VCD text.
Golden tests compare the counter, register, reset, two-bit register, assertion, gate, hierarchical adder, library adder, hierarchical counter, adder, tri-state, undefined-state, bus, shared-bus, and four-state vector VCD text.
The golden report test compares the counter report table with its golden file.
CI runs every demo and compares its output with the golden file.
CI runs the report demo and compares it with the report golden file.
CI runs the bus demo with whole-bus input values.
CI runs the four-state vector demo and compares it with its golden file.
CI confirms that a missing library file stops the run.

## Limitations
Expand All @@ -962,7 +1026,9 @@ All gates use zero delay.
Zero-delay gates can show combinational settling transients at clock edges and at time zero.
Input changes apply only at scheduled times.
They do not react to circuit state.
VCD output uses one module scope and one-bit signals.
VCD output uses one module scope.
A bus renders as one multi-bit vector.
A scalar signal renders as one bit.
An asynchronous reset that releases on a clock edge is a race.
The event order decides the result.
A wide flip-flop uses one shared reset signal.
Expand All @@ -974,7 +1040,8 @@ A library file cannot hold top-level declarations.
The main netlist cannot shadow a library module.
Two library files cannot define the same module.
Modules flatten before simulation, so the VCD stays flat.
A bus expands into single-bit signals, so the VCD stays flat.
A bus expands into single-bit signals internally.
The VCD writer groups the bits into one vector again.
A flip-flop bus output must have a `wire` or `output` declaration.
A reference to a whole bus uses the declared width.
An assertion addresses one bit, not a whole bus.
Expand All @@ -987,6 +1054,7 @@ The report prints every signal in the stable signal order.

## Roadmap

Release 0.12.0.0 completed multi-bit values in the VCD timeline.
Release 0.11.0.0 completed whole-bus input values on the command line.
Release 0.10.0.0 completed the waveform report command.
Release 0.9.0.0 completed module libraries.
Expand All @@ -1000,7 +1068,7 @@ Release 0.2.0.0 completed scheduled input transitions.

Remaining work:

1. Add multi-bit values in the VCD timeline.
1. Add configurable gate delays.

## License

Expand Down
2 changes: 1 addition & 1 deletion fixtures/adder.golden.vcd
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ $date
generated deterministically by gatework
$end
$version
gatework 0.11.0.0
gatework 0.12.0.0
$end
$timescale 1ns $end
$scope module gatework $end
Expand Down
2 changes: 1 addition & 1 deletion fixtures/assert.golden.vcd
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ $date
generated deterministically by gatework
$end
$version
gatework 0.11.0.0
gatework 0.12.0.0
$end
$comment
assert y = 1 at 0
Expand Down
89 changes: 21 additions & 68 deletions fixtures/bus.golden.vcd
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ $date
generated deterministically by gatework
$end
$version
gatework 0.11.0.0
gatework 0.12.0.0
$end
$comment
assert x[0] = 1 at 0
Expand All @@ -15,77 +15,30 @@ $comment
$end
$timescale 1ns $end
$scope module gatework $end
$var wire 1 ! a[0] $end
$var wire 1 " a[1] $end
$var wire 1 # a[2] $end
$var wire 1 $ a[3] $end
$var wire 1 % b[0] $end
$var wire 1 & b[1] $end
$var wire 1 ' b[2] $end
$var wire 1 ( b[3] $end
$var wire 1 ) x[0] $end
$var wire 1 * x[1] $end
$var wire 1 + x[2] $end
$var wire 1 , x[3] $end
$var wire 1 - n[0] $end
$var wire 1 . n[1] $end
$var wire 1 / n[2] $end
$var wire 1 0 n[3] $end
$var wire 1 1 q[0] $end
$var wire 1 2 q[1] $end
$var wire 1 3 q[2] $end
$var wire 1 4 q[3] $end
$var wire 1 5 clk $end
$var wire 1 6 hi[0] $end
$var wire 1 7 hi[1] $end
$var wire 1 8 c0 $end
$var wire 4 ! a[3:0] $end
$var wire 4 " b[3:0] $end
$var wire 4 # x[3:0] $end
$var wire 4 $ n[3:0] $end
$var wire 4 % q[3:0] $end
$var wire 1 & clk $end
$var wire 2 ' hi[1:0] $end
$var wire 1 ( c0 $end
$upscope $end
$enddefinitions $end
#0
1!
0"
1#
0$
0%
1&
0'
b0101!
b1010"
b1111#
b0000$
b0000%
0&
b00'
0(
1(
0)
1)
0*
1*
0+
1+
0,
1,
0-
1-
0-
0.
1.
0.
0/
1/
0/
00
10
00
01
02
03
04
05
06
07
08
18
#1
11
12
13
14
15
b1111%
1&
#2
05
0&
#3
15
1&
Loading
Loading