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: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ jobs:
run: cabal run gatework -- --netlist fixtures/unknown.net --duration 8 --output /tmp/unknown.vcd --set d=1 --at 4 d=0
- name: Compare the undefined demo with the golden file
run: diff fixtures/unknown.golden.vcd /tmp/unknown.vcd
- name: Run the bus demo
run: cabal run gatework -- --netlist fixtures/bus.net --duration 3 --output /tmp/bus.vcd --set 'a[0]=1,a[2]=1,b[1]=1,b[3]=1'
- name: Run the bus demo with whole-bus values
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 shared bus demo
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@ All notable changes to Gatework appear in this file.
The format follows the Keep a Changelog convention.
This project uses semantic versioning.

## [0.11.0.0] - 2026-08-03

### Added

- Set a whole input bus on the command line with one bit string.
- Accept whole-bus bit strings in the --set and --at options.
- The bit string lists the most-significant bit first.
- The value may use 0, 1, x, and z.
- Reject a value that does not match the bus width.
- Add deterministic tests and a QuickCheck property for whole-bus values.
- Run the bus demo with whole-bus values in the CI workflow.

### Changed

- Bump the package version to 0.11.0.0.

## [0.10.0.0] - 2026-08-03

### Added
Expand Down
34 changes: 29 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ You can do these tasks:
- Pass a bus through a module port.
- 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.

## Architecture

Expand Down Expand Up @@ -469,7 +470,7 @@ The `NOT` gate shows the unknown until the flip-flop samples data.
Run four-bit bus operations with gates and a register.

```powershell
cabal run gatework -- --netlist fixtures/bus.net --duration 3 --output bus.vcd --set 'a[0]=1,a[2]=1,b[1]=1,b[3]=1'
cabal run gatework -- --netlist fixtures/bus.net --duration 3 --output bus.vcd --set a=0101,b=1010
```

The command writes this output:
Expand All @@ -481,6 +482,11 @@ Duration: 3 time units
Assertions: 7 passed
```

The value `a=0101` sets the whole input bus `a`.
The string lists bits from the most-significant bit down.
So `a[3]=0`, `a[2]=1`, `a[1]=0`, and `a[0]=1`.
This command gives the same waveform as per-bit assignments.

The inputs `a` and `b` are four-bit buses.
The gate `XOR combine` applies bitwise across both buses.
The module `invert_bus` passes the bus `x` through a four-bit port.
Expand Down Expand Up @@ -799,6 +805,23 @@ assert s[0] = 1 at 0
assert s[2] = 0 at 4
```

### Whole-bus input values

The command line sets one bit or a whole bus.

```text
--set a[0]=1
--set a=0101
--at 2 b=1010
```

A bit assignment names one signal.
The value must be 0, 1, x, or z.
A bus assignment names the bus without brackets.
The value must match the bus width.
The bit string lists the most-significant bit first.
The value may use 0, 1, x, and z.

### Modules and instances

A module is a reusable subcircuit.
Expand Down Expand Up @@ -885,13 +908,15 @@ Deterministic tests also cover bus declarations, bitwise gates, bit references,
Deterministic tests also cover multi-driver resolution, scheduled driver changes, flip-flop output exclusivity, the shared-bus fixture, and its golden output.
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.
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.
QuickCheck properties also compare a bus circuit with a bitwise reference model.
QuickCheck properties also compare the shared bus with a per-time resolution model.
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 runs one hundred random cases for each property.
The gate properties cover the complete truth table.
Expand Down Expand Up @@ -919,6 +944,7 @@ Golden tests compare the counter, register, reset, two-bit register, assertion,
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 confirms that a missing library file stops the run.

## Limitations
Expand Down Expand Up @@ -952,8 +978,6 @@ A bus expands into single-bit signals, so the VCD stays flat.
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.
Input assignments on the command line address one bit.
The CLI does not accept whole-bus values.
One module declaration cannot live inside another.
An instance output must connect to a declared signal.
The dotted instance names are part of the VCD signal names.
Expand All @@ -963,6 +987,7 @@ The report prints every signal in the stable signal order.

## Roadmap

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.
Release 0.8.0.0 completed multi-driver wire resolution.
Expand All @@ -975,8 +1000,7 @@ Release 0.2.0.0 completed scheduled input transitions.

Remaining work:

1. Add whole-bus input values on the command line.
2. Add multi-bit values in the VCD timeline.
1. Add multi-bit values in the VCD timeline.

## License

Expand Down
62 changes: 41 additions & 21 deletions app/Main.hs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
module Main (main) where

import Data.List (intercalate)
import Gatework.Logic (Logic, logicChar, parseLogic)
import Gatework.Netlist (netlistSignals, parseNetlistFileWithLibraries)
import Gatework.Logic (Logic, logicChar)
import Gatework.Netlist
( Netlist
, netlistSignals
, parseNetlistFileWithLibraries
, resolveInputAssignments
)
import Gatework.Report (renderReport)
import Gatework.Simulator
( AssertionFailure (..)
Expand All @@ -23,8 +28,8 @@ data Options = Options
, optionDuration :: Integer
, optionOutput :: FilePath
, optionOutputExplicit :: Bool
, optionInputs :: [(String, Logic)]
, optionScheduled :: [(Time, String, Logic)]
, optionInputs :: [(String, String)]
, optionScheduled :: [(Time, String, String)]
, optionLibraries :: [FilePath]
}

Expand Down Expand Up @@ -55,17 +60,23 @@ run command = do
case parsed of
Left message -> failWith message
Right netlist ->
case simulateWithScheduledInputs netlist (optionInputs options) (optionScheduled options) (optionDuration options) of
case resolveInputAssignments netlist (optionInputs options) of
Left message -> failWith message
Right simulation -> do
wroteFile <- emit command simulation
let summaryHandle = if wroteFile then stdout else stderr
if wroteFile
then putStrLn ("Wrote " ++ optionOutput options)
else pure ()
hPutStrLn summaryHandle ("Signals: " ++ show (length (netlistSignals netlist)))
hPutStrLn summaryHandle ("Duration: " ++ show (optionDuration options) ++ " time units")
reportAssertions summaryHandle simulation
Right inputOverrides ->
case resolveScheduledAssignments netlist (optionScheduled options) of
Left message -> failWith message
Right scheduled ->
case simulateWithScheduledInputs netlist inputOverrides scheduled (optionDuration options) of
Left message -> failWith message
Right simulation -> do
wroteFile <- emit command simulation
let summaryHandle = if wroteFile then stdout else stderr
if wroteFile
then putStrLn ("Wrote " ++ optionOutput options)
else pure ()
hPutStrLn summaryHandle ("Signals: " ++ show (length (netlistSignals netlist)))
hPutStrLn summaryHandle ("Duration: " ++ show (optionDuration options) ++ " time units")
reportAssertions summaryHandle simulation

commandOptions :: Command -> Options
commandOptions (CommandRun options) = options
Expand Down Expand Up @@ -129,14 +140,21 @@ parseOptions arguments = parseMore defaultOptions arguments
parseMore options {optionScheduled = optionScheduled options ++ [(time, name, logic) | (name, logic) <- values]} rest
option : _ -> Left ("unknown option: " ++ option)

parseAssignments :: String -> Either String [(String, Logic)]
parseAssignments :: String -> Either String [(String, String)]
parseAssignments value = mapM parseAssignment (splitOn ',' value)
where
parseAssignment assignment = case break (== '=') assignment of
(name, '=' : rawLogic) | not (null name) -> case parseLogic rawLogic of
Just logic -> Right (name, logic)
Nothing -> Left ("input value must be 0, 1, x, or z: " ++ assignment)
_ -> Left ("input assignment must use signal=0, signal=1, signal=x, or signal=z: " ++ assignment)
(name, '=' : rawValue) | not (null name) && not (null rawValue) ->
Right (name, rawValue)
_ -> Left ("input assignment must use signal=value: " ++ assignment)

resolveScheduledAssignments :: Netlist -> [(Time, String, String)]
-> Either String [(Time, String, Logic)]
resolveScheduledAssignments netlist = fmap concat . mapM step
where
step (time, name, value) = do
resolved <- resolveInputAssignments netlist [(name, value)]
pure [(time, signal, logic) | (signal, logic) <- resolved]

splitOn :: Char -> String -> [String]
splitOn delimiter value = case break (== delimiter) value of
Expand All @@ -151,14 +169,16 @@ failWith message = do

usage :: String
usage = intercalate "\n"
[ "gatework [report] --netlist FILE [--library FILE] [--duration N] [--output FILE] [--set signal=0,signal=1,signal=x,signal=z] [--at TIME signal=0,signal=1,signal=x,signal=z]"
[ "gatework [report] --netlist FILE [--library FILE] [--duration N] [--output FILE] [--set signal=value] [--at TIME signal=value]"
, ""
, "Simulate a netlist and write a VCD waveform."
, "Run 'gatework report' to write a text waveform table instead."
, "Without --output, the report prints to standard output."
, "Use --library to load reusable module definitions from another file."
, "Repeat --library to load more than one module file."
, "Use --at to change input signals at a fixed time during the run."
, "Use x for an unknown value and z for a floating value."
, "A signal value is 0, 1, x, or z."
, "Set a whole bus with a bit string, for example --set a=0101."
, "The bit string lists the most-significant bit first."
, "Check assert declarations in the netlist against the waveform."
]
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.10.0.0
gatework 0.11.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.10.0.0
gatework 0.11.0.0
$end
$comment
assert y = 1 at 0
Expand Down
2 changes: 1 addition & 1 deletion 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.10.0.0
gatework 0.11.0.0
$end
$comment
assert x[0] = 1 at 0
Expand Down
2 changes: 1 addition & 1 deletion fixtures/counter.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.10.0.0
gatework 0.11.0.0
$end
$timescale 1ns $end
$scope module gatework $end
Expand Down
2 changes: 1 addition & 1 deletion fixtures/gates.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.10.0.0
gatework 0.11.0.0
$end
$comment
assert nand_out = 1 at 0
Expand Down
2 changes: 1 addition & 1 deletion fixtures/haddader.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.10.0.0
gatework 0.11.0.0
$end
$timescale 1ns $end
$scope module gatework $end
Expand Down
2 changes: 1 addition & 1 deletion fixtures/hcounter.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.10.0.0
gatework 0.11.0.0
$end
$timescale 1ns $end
$scope module gatework $end
Expand Down
2 changes: 1 addition & 1 deletion fixtures/libadder.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.10.0.0
gatework 0.11.0.0
$end
$timescale 1ns $end
$scope module gatework $end
Expand Down
2 changes: 1 addition & 1 deletion fixtures/reg2.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.10.0.0
gatework 0.11.0.0
$end
$timescale 1ns $end
$scope module gatework $end
Expand Down
2 changes: 1 addition & 1 deletion fixtures/register.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.10.0.0
gatework 0.11.0.0
$end
$timescale 1ns $end
$scope module gatework $end
Expand Down
2 changes: 1 addition & 1 deletion fixtures/reset.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.10.0.0
gatework 0.11.0.0
$end
$timescale 1ns $end
$scope module gatework $end
Expand Down
2 changes: 1 addition & 1 deletion fixtures/shared.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.10.0.0
gatework 0.11.0.0
$end
$comment
assert y = z at 0
Expand Down
2 changes: 1 addition & 1 deletion fixtures/tristate.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.10.0.0
gatework 0.11.0.0
$end
$comment
assert y = z at 0
Expand Down
2 changes: 1 addition & 1 deletion fixtures/unknown.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.10.0.0
gatework 0.11.0.0
$end
$comment
assert q = x at 0
Expand Down
3 changes: 2 additions & 1 deletion gatework.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 3.0
name: gatework
version: 0.10.0.0
version: 0.11.0.0
synopsis: Event-driven digital logic simulation in Haskell
description:
Gatework parses typed netlists, runs combinational gates and D
Expand All @@ -13,6 +13,7 @@ description:
circuits. A module library file stores reusable module definitions.
The command-line tool loads libraries with the --library option.
A waveform report command prints the signal values as a text table.
The command-line tool also sets a whole bus with one bit string.
GTKWave and other waveform viewers can open the output.
homepage: https://github.com/DanielCuevas1208/gatework
bug-reports: https://github.com/DanielCuevas1208/gatework/issues
Expand Down
Loading
Loading