This application note takes FPGA and verification engineers from a fixed counter specification to a reproducible simulation test. The example was developed for EDA Praxis with Codex; its faulty variants are deliberately constructed test cases. They are not a retrospective story about an accidentally observed model error. You receive complete original VHDL files, a self-checking testbench, a local runner and the actual GHDL transcripts. The Aldec procedure is documentation-based; vendor-tool testing is pending.
Prerequisites and test scope
You should understand synchronous logic, VHDL processes and basic arithmetic. The project uses VHDL-2008, ieee.std_logic_1164, ieee.numeric_std and std.env.finish. Reproducing the executed test requires an existing GHDL installation and Python 3 without additional packages. The described Aldec path requires an authorised Active-HDL or Riviera-PRO installation with suitable VHDL support. The download includes no vendor software, licences or model-service credentials.
Testing was performed locally on Windows x64 with GHDL 6.0.0 and the mcode backend. The result report includes the complete version banner. Neither Aldec nor Sigasi was executed for this example. The design has one clock, reset, enable and an unsigned counter output. Its value before the first reset is unspecified. Control inputs are assumed to be binary and synchronous; unknown logic values and crossings between clock domains are outside this specification.
Step 1: Fix requirements before correcting the code
| ID | Requirement | Acceptance |
|---|---|---|
| R1 | Active-high reset at the rising edge, with priority over enable. | Reset with enable 0 and 1, including from a nonzero value. |
| R2 | Increment by one when reset is 0 and enable is 1. | A directed sequence of enabled clock cycles. |
| R3 | Hold when reset is 0 and enable is 0. | Repeated disabled cycles before and after reset. |
| R4 | Wrap modulo 2 to the power of WIDTH. | Two complete wraps, including maximum to zero. |
| R5 | Reset is synchronous. | Asserting reset between edges must not yet change the output. |
WIDTH is a positive parameter. The testbench exercises widths 1, 4 and 8; its reference arithmetic is explicitly limited to 1 through 8. The smallest width is useful because wraparound occurs after only two increments. A larger width checks that the implementation is genuinely parameterised. These selected values do not establish every possible configuration. Requirements and the derived testbench remain unchanged during the correction loop, so a patch cannot silently redefine what counts as success.
Step 2: Prepare the files and agent instruction
ai-counter/
rtl/ai_counter.vhd
tb/tb_ai_counter.vhd
run.py
README.md
LICENSE
results/report.json
results/*.log
Download the complete example and actual GHDL results (ZIP). Extract it into a separate local working folder. Source files and runner use the MIT licence; no vendor files are included. Write your own results into a different output folder to retain the supplied reference results.
A suitable agent instruction names the five requirements, both source files, the RTL file as the only permitted edit target, and the checking procedure. For example: “Check the implementation against R1 through R5. Modify only rtl/ai_counter.vhd. Run the existing runner and report the source change, actual commands, version and exit code. Do not change expected values or assertions. If a tool is missing, a licence fails or the run is incomplete, stop and report the check as failed or not executed, as appropriate.”
Use a separate copy for experiments. The supplied runner constructs its deliberately faulty variants in temporary directories without modifying the supplied RTL file. This keeps the fault demonstration separate from the usable reference implementation. For your own AI-assisted change, also use version control and inspect the diff before execution, particularly any change to test scripts or expected results. The agent’s explanation is useful context, but the files and execution records remain the evidence.
Step 3: Understand the hardware description
The significant order inside the clocked process is reset first, followed by enable. The output receives the internal register value. ieee.numeric_std provides typed unsigned addition; the fixed width implements modular wraparound. Omitting an assignment in the disabled branch preserves the register value in this clocked process. The complete entity and architecture are supplied in rtl/ai_counter.vhd; the excerpt below shows the part that determines the behaviour being checked.
if rising_edge(clk) then
if rst = '1' then
count <= (others => '0');
elsif en = '1' then
count <= count + 1;
end if;
end if;
Project analysis can first expose incorrect identifiers, type errors or missing dependencies. The Sigasi application note describes the documented agent path and its licensing boundaries. For this small project, that is an additional stage to evaluate separately. An accepted analysis report would not automatically confirm R4: a correctly written saturating counter would also be linguistically plausible while violating the required behaviour.
Step 4: Understand the testbench
The testbench checks specified behaviour; it does not use the implementation as its reference. The 1 ns wait belongs to the simulation sequence and is not a physical timing requirement.
The tick procedure drives reset and enable at a falling edge and checks the output one nanosecond after the next rising edge. That wait allows the model’s signal assignments to settle. It is not a physical timing requirement for the eventual circuit. The testbench compares each expected value with q and identifies the associated requirement on failure. Reset between edges has an additional check explicitly performed before the next rising edge.
tick('0', '1', 1, "R2 enabled increment");
tick('0', '0', 1, "R3 disabled hold");
tick('1', '1', 0, "R1 reset priority with enable");
-- The complete file also checks two wraps and synchronous reset.
-- PASS is emitted only after every assertion has succeeded.
Assertions report errors with severity failure. Only after every check does EDA_AI_COUNTER_PASS appear with the current width, followed by finish(0). A watchdog fails after 20 microseconds of simulation time if the test does not complete. The Python runner additionally limits each analysis, elaboration and simulation process to 30 seconds of real execution time. An unfinished simulation and a successful test therefore remain distinct states. GHDL runtime controls are described in the official simulation manual.
Derived from the testbench, WIDTH = 4. Inputs change at the falling edge; each check occurs 1 ns after the next rising edge.
| Check time (ns) | rst | en | Expected q | Behaviour checked |
|---|---|---|---|---|
| 16 | 1 | 0 | 0 | Reset without enable |
| 26 | 0 | 1 | 1 | Increment |
| 36 | 0 | 0 | 1 | Hold |
| 46 | 0 | 0 | 1 | Hold again |
| 56 | 1 | 1 | 0 | Reset has priority |
| 66 | 0 | 1 | 1 | Increment again |
Original schematic, not a new simulator capture or an Aldec test. The complete testbench contains the additional wraparound and reset checks.
Step 5: Simulate with Active-HDL
Open an authorised Active-HDL installation and create a new workspace and design in an empty evaluation folder. Add the two original VHDL files. Select VHDL-2008 in the compiler settings and compile the RTL first, then the testbench, into work. Select tb_ai_counter as the simulation top and start with WIDTH equal to 4. Initialise the simulation and enter set breakassertlevel 2 in the console.
Use Run All. Expect the complete PASS marker for WIDTH=4 and normal completion without assertion errors. Reinitialise and repeat for WIDTH=1 and WIDTH=8. For the negative check, change elsif en = '1' then to else in a scratch copy only. After recompilation and initialisation, R3 must fail and no PASS marker may appear. Restore the original file afterwards. Source for the control setting: Aldec assertion thresholds.
Aldec also documents the shell and batch sequence of library creation, compilation, initialisation and simulation. Confirm the compiler standard, options and process termination against the help shipped with your installed version before building a pipeline from it. The GUI procedure described here is actionable but was not tested locally with Aldec. Source: Active-HDL Batch Mode. Do not continue after errors merely to turn a failed run into an apparently successful completion.
Step 6: Riviera-PRO and automated failure handling
For Riviera-PRO, use the same functional procedure with the original files: a new design, VHDL-2008, RTL before testbench, tb_ai_counter as top, initialisation and a complete run. Its documented assertion control is vhdlassert.break error, a different command from Active-HDL’s setting. Stopping at an assertion does not by itself establish a nonzero operating-system exit code. Before connecting CI, verify that the deliberately faulty version also produces a failed job.
This vendor-tool run remains pending. During your evaluation, record the build number, edition, operating system, commands and behaviour of finish(0). If simulation only pauses, a licence is unavailable or the completion marker is absent, acceptance remains open. The published GHDL runner is not an untested Aldec adapter. It demonstrates a result-checking principle whose implementation must be tested separately for each product. Preserve both the positive and negative transcripts when you establish that integration.
Step 7: The local tests that were actually executed
python run.py --ghdl ghdl --output test-results
Run the runner from the extracted project directory. For one manual run, create the new manual-run subdirectory there and enter it; ../rtl and ../tb then refer to the supplied sources. Use a directory name that does not already exist so that no old work library is reused.
mkdir manual-run
cd manual-run
ghdl -a --std=08 ../rtl/ai_counter.vhd ../tb/tb_ai_counter.vhd
ghdl -e --std=08 tb_ai_counter
ghdl -r --std=08 tb_ai_counter -gWIDTH=4 --assert-level=error
On 19 October 2026, the three positive widths completed with exit code 0 and the matching marker. Four intentional variants compiled successfully and were then rejected by assertions: reset gated by enable, saturation instead of wraparound, ignored enable and asynchronous reset. All four returned exit code 1 without PASS. The runner explicitly refuses to count a compilation failure as successful detection of a behavioural fault. Individual transcripts and report.json are included in the download.
Interpretation, limits and the next step
When a check fails, read the named requirement, the last input combination and the expected value first. An R3 failure, for example, points to unwanted counting while enable is disabled. Inspect the smallest responsible RTL section and repeat the complete unchanged test. Adding a case can strengthen the suite; removing an assertion changes the meaning of the previous result. Keep the fault demonstration distinct from changes you intend to retain.
The result establishes behaviour for the specified stimuli and parameters. It does not establish synthesis support in a particular FPGA tool version, a clock-frequency target, CDC/RDC properties or complete correctness of every possible extension. Source checking, the actual GHDL run and human technical approval are separate states; no human technical sign-off is claimed. For an Aldec/Sigasi evaluation for your project, extend this small example with a representative case from your own design.