Skip to content

Fix/write vhdl conditional in aggregate - #228

Merged
tgingold merged 3 commits into
ghdl:masterfrom
donnie-j:fix/write-vhdl-conditional-in-aggregate
Jun 21, 2026
Merged

Fix/write vhdl conditional in aggregate#228
tgingold merged 3 commits into
ghdl:masterfrom
donnie-j:fix/write-vhdl-conditional-in-aggregate

Conversation

@donnie-j

Copy link
Copy Markdown
Contributor

Closes #227

write_vhdl emitted a conditional expression inside an aggregate element association, which is illegal in VHDL. Affected cell types when Y_WIDTH > 1: $logic_and/or/not, $reduce_*, and all comparison cells.

Fix: introduce an intermediate std_logic signal only when needed, reusing the existing aux_signal_decls mechanism.

Also fixes a $pos type mismatch for Y_WIDTH = 1.

Test cases cover all affected operators at both Y_WIDTH > 1 and Y_WIDTH = 1 (control), including a combined output to verify one intermediate per cell.

donnie-j and others added 3 commits June 21, 2026 18:45
…n-aggregate

write_vhdl emits illegal VHDL-93 when boolean/comparison cells have
output width > 1:

  n0 <= (0 => '1' when COND else '0', others => '0');

VHDL-93 s7.3.2 forbids conditional expressions inside aggregates.
GHDL rejects this with "')' is expected instead of 'when'".

Five test modules, all failing before the fix:

  t_exact:    verbatim reporter case ($logic_and y_width=3)
  t_logic:    $logic_and/or/not at y_width=4 (broken) and y_width=1 (control)
  t_reduce:   $reduce_and/or/xor/xnor at y_width=4 and y_width=1;
              $reduce_xnor has zero prior test coverage at any width
  t_compare:  $eq/$ne/$lt/$eqx at y_width=4 and y_width=1;
              $eqx has zero prior test coverage at any width
  t_combined: three independent boolean cells ($logic_and/or/not) feeding
              one 4-bit output mixed with a plain signal and a constant;
              asserts exactly 3 std_logic intermediates post-fix -- one per
              cell, proving the fix is per-cell not a merged expression

Each module includes y_width=1 control outputs exercising the same cell
types on the already-correct path, confirming the fix does not regress it.

Ref: ghdl#227
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Two related fixes for illegal VHDL-93 output:

1. Conditional-in-aggregate (issue ghdl#227):
   $logic_and, $logic_or, $logic_not, $reduce_and/or/xor/xnor, and
   comparison cells ($lt/le/eq/ne/ge/gt/eqx/nex) with output width > 1
   were emitting:

     n0 <= (0 => '1' when COND else '0', others => '0');

   VHDL-93 s7.3.2 forbids conditional expressions inside aggregates.
   GHDL rejects this with "')' is expected instead of 'when'".

   Fix: introduce a std_logic intermediate signal via aux_signal_decls
   and emit two legal concurrent statements:

     n_bool <= '1' when COND else '0';
     n0     <= (0 => n_bool, others => '0');

   The intermediate is allocated only when Y_WIDTH > 1; the common
   1-bit path is unchanged.

2. $pos Y_WIDTH==1 type mismatch:
   When $pos extends/truncates to width 1, the backend was emitting:

     Y <= std_logic_vector(resize(unsigned(A), 1));

   which has type std_logic_vector(0 downto 0), not std_logic.
   Fix: use arith_open/arith_close as every other arithmetic cell does,
   producing resize(unsigned(A), 1)(0) -- a std_logic value.

Implementation: a new dump_bool_assign() helper encapsulates the
Y_WIDTH dispatch and the intermediate-signal pattern, eliminating
repetition across all five affected cell handlers.

Also rename ff_signal_decls -> aux_signal_decls to reflect its broader
use: FF internals, split-Y temporaries, and now bool-to-vector
intermediates.

Fixes: ghdl#227
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Add t_vhdl.vhd exercising three paths used extensively in production:

  - Signed/unsigned arithmetic: GHDL normalizes signed/unsigned to
    std_logic_vector before emitting RTLIL; write_vhdl must emit valid
    VHDL-93 for the resulting $add cells.

  - Single-bit sub-range slices: bus8(2) and bus8(5) must produce
    std_logic output ports, not std_logic_vector(0 downto 0).

  - Boolean flag OR'd into vector: the issue ghdl#227 pattern exercised
    end-to-end via the GHDL import path.

Note: fixed_pkg is intentionally not used.  fixed_pkg injects overflow
$assert cells whose 'if '1' = '1'' condition is ambiguous under both
--std=93 and --std=08 when std_logic_1164 is in scope.  That is a
pre-existing limitation of the $assert handler, separate from this fix.

Only VHDL-2008 syntax is checked (ghdl -s --std=08); simulation-level
correctness is deferred to a future test.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
@tgingold
tgingold merged commit bb7f96f into ghdl:master Jun 21, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

write_vhdl produces vhdl not passing syntax check: when conditional assignment in positional assignment

2 participants