Skip to content

§ 2.6. Complete ALU8

ALU8 combines the arithmetic, logic, shift/rotate, comparison/select, and flag components into one eight-bit combinational unit. It supports 29 operations, a five-bit opcode, and an explicit carry input. Multiplication and division are not included.

Component Description Structural Behavioral
ALU8ControlDecoder Decodes the five-bit opcode into local operation selectors, result-source enables, and an invalid-opcode flag Yes Yes
ALU8ResultSelector Combines six enabled result sources into the final eight-bit result Yes Yes
ALU8 Integrates the operation units, control decoder, result selector, and flags behind one input/output interface Yes Yes

These columns indicate registered simulator implementations; the simplified C++ examples below are not counted.

The simplified C++ examples describe binary behavior, not the simulator implementation; they omit propagation delays and X/Z handling. The complete ALU example uses the functions from §§2.1–2.5.

2.6.1. ALU8ControlDecoder

This block translates the complete ALU opcode into local selectors and result/flag enables. It does not compute operand data.

IO pins

Pin Direction Width Description
OP Input 5 Complete ALU opcode
LOCAL_OP Output 3 OP[2:0], used by logic and shift units
ARITH_OP Output 3 Arithmetic selector; forced to local SUB = 2 during comparisons
COMPARE_OP Output 3 Comparison selector, 0–6 for global opcodes 21–27; otherwise 0
ARITHMETIC_ENABLE, LOGIC_ENABLE, SHIFT_ENABLE, COMPARE_ENABLE Output 1 each Enable the corresponding result source
PASS_A_ENABLE, PASS_B_ENABLE Output 1 each Enable operand pass-through
INVALID_OP Output 1 Reserved opcode indication

Behavior

For binary OP, arithmetic is enabled for 0–6, logic for 8–14, shifts for 16–20, comparisons for 21–27, and operand pass-through for 28 or 29. At most one result enable is high. CLEAR = 30 and reserved encodings 7, 15, 31 disable every result source; only the reserved encodings set INVALID_OP.

During comparisons, ARITH_OP = 2 requests the shared subtraction, but ARITHMETIC_ENABLE = 0: its intermediate result and flags must not be exposed as the final ALU result and flags. Outside comparisons, ARITH_OP = OP[2:0]. Unused local selectors are not forced to zero except COMPARE_OP.

C++ example

#include <cstdint>
#include <stdexcept>

struct ALU8Control {
    std::uint8_t LOCAL_OP, ARITH_OP, COMPARE_OP;
    bool ARITHMETIC_ENABLE, LOGIC_ENABLE, SHIFT_ENABLE, COMPARE_ENABLE;
    bool PASS_A_ENABLE, PASS_B_ENABLE, INVALID_OP;
};

ALU8Control alu8_control_ref(std::uint8_t op) {
    if (op > 31) throw std::invalid_argument("OP must fit five bits");
    const bool compare = op >= 21 && op <= 27;
    return {
        static_cast<std::uint8_t>(op & 7),
        static_cast<std::uint8_t>(compare ? 2 : op & 7),
        static_cast<std::uint8_t>(compare ? op - 21 : 0),
        op <= 6, op >= 8 && op <= 14, op >= 16 && op <= 20, compare,
        op == 28, op == 29, op == 7 || op == 15 || op == 31
    };
}

Unknown inputs and timing

Unknown opcode bits follow the decoder and gates. INVALID_OP does not indicate whether all input bits are binary. The block has no clock or stored state; control outputs can change at different propagation times.

Implementation

Structural implementation

OPERATION_DECODER is a Decoder5to32 with its enable tied high. OR networks combine decoded lines into group enables and the invalid flag. A splitter/joiner forwards the low three bits; three Mux2to1 gates override the arithmetic selector during comparisons. OR networks remap comparison opcodes to local selectors.

Behavioral implementation

Behavioral8<ALU8ControlDecoder> calls control. It evaluates all 32 opcode matches with four-state logic, combines them into group enables and INVALID_OP, and constructs the local selectors. LOCAL_OP directly copies OP[2:0], preserving Z as wiring does; the other outputs pass through logic expressions.

The evaluator is defined in ALU8Behavioral.cpp; its value functions are in ALU8ValueModel.hpp. It retains the public pins without functional circuit children. Catalog construction supplies a delay table characterized from the gates; where a delay twin is available and agrees with the computed value, publication can follow the current inputs’ gate-level settling time within that bound, subject to older pending results. The compact evaluator does not reproduce transient gate glitches.

The recorded scenario runs against both implementations in CTest. ALU8FidelityContractTest checks binary/X/Z settled-output equivalence against the structural circuit. The example table uses the default structural run; its checkpoint times need not match the behavioral run.

Examples

All 32 recorded rows of ALU8ControlDecoderTest, in checkpoint order. Outputs are test expectations verified against the simulation. Time is the absolute settled checkpoint time in simulator units, not milliseconds or CPU cycles.

Default scenario profile: canonical-default-preview / structural (b9bfd586b0cd37b5). Changing fidelity or the circuit can change these times.

Checkpointzero-based number · timeline label Timesimulator units OPInput · 5 bit ARITHMETIC_ENABLEExpected output · 1 bit ARITH_OPExpected output · 3 bit COMPARE_ENABLEExpected output · 1 bit COMPARE_OPExpected output · 3 bit INVALID_OPExpected output · 1 bit LOCAL_OPExpected output · 3 bit LOGIC_ENABLEExpected output · 1 bit PASS_A_ENABLEExpected output · 1 bit PASS_B_ENABLEExpected output · 1 bit SHIFT_ENABLEExpected output · 1 bit
#0row-012 0x00 1 0x0 0 0x0 0 0x0 0 0 0 0
#1row-119 0x01 1 0x1 0 0x0 0 0x1 0 0 0 0
#2row-226 0x02 1 0x2 0 0x0 0 0x2 0 0 0 0
#3row-334 0x03 1 0x3 0 0x0 0 0x3 0 0 0 0
#4row-445 0x04 1 0x4 0 0x0 0 0x4 0 0 0 0
#5row-553 0x05 1 0x5 0 0x0 0 0x5 0 0 0 0
#6row-660 0x06 1 0x6 0 0x0 0 0x6 0 0 0 0
#7row-767 0x07 0 0x7 0 0x0 1 0x7 0 0 0 0
#8row-880 0x08 0 0x0 0 0x0 0 0x0 1 0 0 0
#9row-987 0x09 0 0x1 0 0x0 0 0x1 1 0 0 0
#10row-1094 0x0A 0 0x2 0 0x0 0 0x2 1 0 0 0
#11row-11102 0x0B 0 0x3 0 0x0 0 0x3 1 0 0 0
#12row-12113 0x0C 0 0x4 0 0x0 0 0x4 1 0 0 0
#13row-13121 0x0D 0 0x5 0 0x0 0 0x5 1 0 0 0
#14row-14128 0x0E 0 0x6 0 0x0 0 0x6 1 0 0 0
#15row-15135 0x0F 0 0x7 0 0x0 1 0x7 0 0 0 0
#16row-16146 0x10 0 0x0 0 0x0 0 0x0 0 0 0 1
#17row-17153 0x11 0 0x1 0 0x0 0 0x1 0 0 0 1
#18row-18160 0x12 0 0x2 0 0x0 0 0x2 0 0 0 1
#19row-19168 0x13 0 0x3 0 0x0 0 0x3 0 0 0 1
#20row-20179 0x14 0 0x4 0 0x0 0 0x4 0 0 0 1
#21row-21193 0x15 0 0x2 1 0x0 0 0x5 0 0 0 0
#22row-22208 0x16 0 0x2 1 0x1 0 0x6 0 0 0 0
#23row-23216 0x17 0 0x2 1 0x2 0 0x7 0 0 0 0
#24row-24229 0x18 0 0x2 1 0x3 0 0x0 0 0 0 0
#25row-25237 0x19 0 0x2 1 0x4 0 0x1 0 0 0 0
#26row-26245 0x1A 0 0x2 1 0x5 0 0x2 0 0 0 0
#27row-27253 0x1B 0 0x2 1 0x6 0 0x3 0 0 0 0
#28row-28267 0x1C 0 0x4 0 0x0 0 0x4 0 1 0 0
#29row-29273 0x1D 0 0x5 0 0x0 0 0x5 0 0 1 0
#30row-30279 0x1E 0 0x6 0 0x0 0 0x6 0 0 0 0
#31row-31285 0x1F 0 0x7 0 0x0 1 0x7 0 0 0 0

Scroll within the table for all rows and pins. Buses use hexadecimal; values containing X/Z use MSB-first binary. Inputs show the declared values in effect at each checkpoint, including retained inputs. Sequential tests also replay preparation changes between checkpoints, such as lowering the clock. Use the matching checkpoint label in the simulation below.

Embedded simulation

All 32 binary opcodes are recorded, checking every output pin.

Open ALU8ControlDecoder in the simulator

Source and tests

2.6.2. ALU8ResultSelector

This block combines six enabled data sources into one result bus. Its enable pins are independent; it is not a priority selector.

IO pins

Pin Direction Width Description
ARITHMETIC_RESULT, LOGIC_RESULT, SHIFT_RESULT, COMPARE_RESULT Input 8 each Results from the operation units
A, B Input 8 each Operand pass-through sources
ARITHMETIC_ENABLE, LOGIC_ENABLE, SHIFT_ENABLE, COMPARE_ENABLE Input 1 each Enable the corresponding unit result
PASS_A_ENABLE, PASS_B_ENABLE Input 1 each Enable operand pass-through
OUT Output 8 Bitwise OR of the enabled sources

Behavior

Each source is AND-masked by its enable, then the six masked words are OR-combined. With one enable high, OUT is that source. With all enables low, OUT = 0. Multiple enables produce the bitwise OR of those sources, not an error or a priority choice. The integrated decoder only generates zero-hot or one-hot enables for binary opcodes.

C++ example

The arrays use this order: arithmetic, logic, shift, comparison, A, B.

#include <array>
#include <cstdint>

std::uint8_t alu8_result_selector_ref(
    const std::array<std::uint8_t, 6>& sources,
    const std::array<bool, 6>& enables) {
    std::uint8_t out = 0;
    for (unsigned i = 0; i < sources.size(); ++i)
        if (enables[i]) out |= sources[i];
    return out;
}

Unknown inputs and timing

A low enable masks X/Z data. Active unknown data follows AND/OR gate rules; high impedance is not forwarded as high impedance through these gates. Unknown enables also follow gate rules rather than selecting an arbitrary input. There is no stored state or fixed cycle latency.

Implementation

Structural implementation

Six eight-bit splitters feed 48 AND gates, followed by 40 OR gates and one output joiner. No operation unit is clock-gated or stopped by these enables.

Behavioral implementation

Behavioral8<ALU8ResultSelector> calls select. For each output bit, it AND-masks each of the six source bits with its enable and OR-combines the contributions using four-state logic. Multiple enabled sources are combined, not prioritized; disabled unknown data is masked to zero.

The evaluator is defined in ALU8Behavioral.cpp; its value functions are in ALU8ValueModel.hpp. It retains the public pins without functional circuit children. Catalog construction supplies a delay table characterized from the gates; where a delay twin is available and agrees with the computed value, publication can follow the current inputs’ gate-level settling time within that bound, subject to older pending results. The compact evaluator does not reproduce transient gate glitches.

The recorded scenario runs against both implementations in CTest. ALU8FidelityContractTest checks binary/X/Z settled-output equivalence against the structural circuit. The example table uses the default structural run; its checkpoint times need not match the behavioral run.

Examples

All 66 recorded rows of ALU8ResultSelectorTest, in checkpoint order. Outputs are test expectations verified against the simulation. Time is the absolute settled checkpoint time in simulator units, not milliseconds or CPU cycles.

Default scenario profile: canonical-default-preview / structural (860d91a948498bdb). Changing fidelity or the circuit can change these times.

Checkpointzero-based number · timeline label Timesimulator units AInput · 8 bit ARITHMETIC_ENABLEInput · 1 bit ARITHMETIC_RESULTInput · 8 bit BInput · 8 bit COMPARE_ENABLEInput · 1 bit COMPARE_RESULTInput · 8 bit LOGIC_ENABLEInput · 1 bit LOGIC_RESULTInput · 8 bit PASS_A_ENABLEInput · 1 bit PASS_B_ENABLEInput · 1 bit SHIFT_ENABLEInput · 1 bit SHIFT_RESULTInput · 8 bit OUTExpected output · 8 bit
#0row-04 0x55 0 0x81 0xAA 0 0x18 0 0x42 0 0 0 0x24 0x00
#1row-19 0x55 1 0x81 0xAA 0 0x18 0 0x42 0 0 0 0x24 0x81
#2row-214 0x55 0 0x81 0xAA 0 0x18 1 0x42 0 0 0 0x24 0x42
#3row-319 0x55 1 0x81 0xAA 0 0x18 1 0x42 0 0 0 0x24 0xC3
#4row-424 0x55 0 0x81 0xAA 0 0x18 0 0x42 0 0 1 0x24 0x24
#5row-529 0x55 1 0x81 0xAA 0 0x18 0 0x42 0 0 1 0x24 0xA5
#6row-634 0x55 0 0x81 0xAA 0 0x18 1 0x42 0 0 1 0x24 0x66
#7row-739 0x55 1 0x81 0xAA 0 0x18 1 0x42 0 0 1 0x24 0xE7
#8row-844 0x55 0 0x81 0xAA 1 0x18 0 0x42 0 0 0 0x24 0x18
#9row-949 0x55 1 0x81 0xAA 1 0x18 0 0x42 0 0 0 0x24 0x99
#10row-1054 0x55 0 0x81 0xAA 1 0x18 1 0x42 0 0 0 0x24 0x5A
#11row-1159 0x55 1 0x81 0xAA 1 0x18 1 0x42 0 0 0 0x24 0xDB
#12row-1264 0x55 0 0x81 0xAA 1 0x18 0 0x42 0 0 1 0x24 0x3C
#13row-1369 0x55 1 0x81 0xAA 1 0x18 0 0x42 0 0 1 0x24 0xBD
#14row-1474 0x55 0 0x81 0xAA 1 0x18 1 0x42 0 0 1 0x24 0x7E
#15row-1579 0x55 1 0x81 0xAA 1 0x18 1 0x42 0 0 1 0x24 0xFF
#16row-1684 0x55 0 0x81 0xAA 0 0x18 0 0x42 1 0 0 0x24 0x55
#17row-1789 0x55 1 0x81 0xAA 0 0x18 0 0x42 1 0 0 0x24 0xD5
#18row-1894 0x55 0 0x81 0xAA 0 0x18 1 0x42 1 0 0 0x24 0x57
#19row-1999 0x55 1 0x81 0xAA 0 0x18 1 0x42 1 0 0 0x24 0xD7
#20row-20104 0x55 0 0x81 0xAA 0 0x18 0 0x42 1 0 1 0x24 0x75
#21row-21109 0x55 1 0x81 0xAA 0 0x18 0 0x42 1 0 1 0x24 0xF5
#22row-22114 0x55 0 0x81 0xAA 0 0x18 1 0x42 1 0 1 0x24 0x77
#23row-23119 0x55 1 0x81 0xAA 0 0x18 1 0x42 1 0 1 0x24 0xF7
#24row-24124 0x55 0 0x81 0xAA 1 0x18 0 0x42 1 0 0 0x24 0x5D
#25row-25129 0x55 1 0x81 0xAA 1 0x18 0 0x42 1 0 0 0x24 0xDD
#26row-26134 0x55 0 0x81 0xAA 1 0x18 1 0x42 1 0 0 0x24 0x5F
#27row-27139 0x55 1 0x81 0xAA 1 0x18 1 0x42 1 0 0 0x24 0xDF
#28row-28144 0x55 0 0x81 0xAA 1 0x18 0 0x42 1 0 1 0x24 0x7D
#29row-29149 0x55 1 0x81 0xAA 1 0x18 0 0x42 1 0 1 0x24 0xFD
#30row-30154 0x55 0 0x81 0xAA 1 0x18 1 0x42 1 0 1 0x24 0x7F
#31row-31159 0x55 1 0x81 0xAA 1 0x18 1 0x42 1 0 1 0x24 0xFF
#32row-32164 0x55 0 0x81 0xAA 0 0x18 0 0x42 0 1 0 0x24 0xAA
#33row-33169 0x55 1 0x81 0xAA 0 0x18 0 0x42 0 1 0 0x24 0xAB
#34row-34174 0x55 0 0x81 0xAA 0 0x18 1 0x42 0 1 0 0x24 0xEA
#35row-35179 0x55 1 0x81 0xAA 0 0x18 1 0x42 0 1 0 0x24 0xEB
#36row-36184 0x55 0 0x81 0xAA 0 0x18 0 0x42 0 1 1 0x24 0xAE
#37row-37189 0x55 1 0x81 0xAA 0 0x18 0 0x42 0 1 1 0x24 0xAF
#38row-38194 0x55 0 0x81 0xAA 0 0x18 1 0x42 0 1 1 0x24 0xEE
#39row-39199 0x55 1 0x81 0xAA 0 0x18 1 0x42 0 1 1 0x24 0xEF
#40row-40204 0x55 0 0x81 0xAA 1 0x18 0 0x42 0 1 0 0x24 0xBA
#41row-41209 0x55 1 0x81 0xAA 1 0x18 0 0x42 0 1 0 0x24 0xBB
#42row-42214 0x55 0 0x81 0xAA 1 0x18 1 0x42 0 1 0 0x24 0xFA
#43row-43219 0x55 1 0x81 0xAA 1 0x18 1 0x42 0 1 0 0x24 0xFB
#44row-44224 0x55 0 0x81 0xAA 1 0x18 0 0x42 0 1 1 0x24 0xBE
#45row-45229 0x55 1 0x81 0xAA 1 0x18 0 0x42 0 1 1 0x24 0xBF
#46row-46234 0x55 0 0x81 0xAA 1 0x18 1 0x42 0 1 1 0x24 0xFE
#47row-47239 0x55 1 0x81 0xAA 1 0x18 1 0x42 0 1 1 0x24 0xFF
#48row-48244 0x55 0 0x81 0xAA 0 0x18 0 0x42 1 1 0 0x24 0xFF
#49row-49249 0x55 1 0x81 0xAA 0 0x18 0 0x42 1 1 0 0x24 0xFF
#50row-50254 0x55 0 0x81 0xAA 0 0x18 1 0x42 1 1 0 0x24 0xFF
#51row-51259 0x55 1 0x81 0xAA 0 0x18 1 0x42 1 1 0 0x24 0xFF
#52row-52264 0x55 0 0x81 0xAA 0 0x18 0 0x42 1 1 1 0x24 0xFF
#53row-53269 0x55 1 0x81 0xAA 0 0x18 0 0x42 1 1 1 0x24 0xFF
#54row-54274 0x55 0 0x81 0xAA 0 0x18 1 0x42 1 1 1 0x24 0xFF
#55row-55279 0x55 1 0x81 0xAA 0 0x18 1 0x42 1 1 1 0x24 0xFF
#56row-56284 0x55 0 0x81 0xAA 1 0x18 0 0x42 1 1 0 0x24 0xFF
#57row-57289 0x55 1 0x81 0xAA 1 0x18 0 0x42 1 1 0 0x24 0xFF
#58row-58294 0x55 0 0x81 0xAA 1 0x18 1 0x42 1 1 0 0x24 0xFF
#59row-59299 0x55 1 0x81 0xAA 1 0x18 1 0x42 1 1 0 0x24 0xFF
#60row-60304 0x55 0 0x81 0xAA 1 0x18 0 0x42 1 1 1 0x24 0xFF
#61row-61309 0x55 1 0x81 0xAA 1 0x18 0 0x42 1 1 1 0x24 0xFF
#62row-62314 0x55 0 0x81 0xAA 1 0x18 1 0x42 1 1 1 0x24 0xFF
#63row-63319 0x55 1 0x81 0xAA 1 0x18 1 0x42 1 1 1 0x24 0xFF
#64row-64324 0bXXXXXXXX 0 0bXXXXXXXX 0bXXXXXXXX 0 0bXXXXXXXX 0 0bXXXXXXXX 0 0 0 0bXXXXXXXX 0x00
#65row-65327 0bZZZZZZZZ 0 0bZZZZZZZZ 0bZZZZZZZZ 0 0bZZZZZZZZ 0 0bZZZZZZZZ 0 0 0 0bZZZZZZZZ 0x00

Scroll within the table for all rows and pins. Buses use hexadecimal; values containing X/Z use MSB-first binary. Inputs show the declared values in effect at each checkpoint, including retained inputs. Sequential tests also replay preparation changes between checkpoints, such as lowering the clock. Use the matching checkpoint label in the simulation below.

The binary source words are 81, 42, 24, 18, 55, AA (hex), in the source-array order above; the final two rows use X/Z source words.

Embedded simulation

The scenario records all 64 enable combinations with these source words, then two all-disabled cases with every source set to X or Z. It contains 66 rows, not an exhaustive sweep over the six data buses.

Open ALU8ResultSelector in the simulator

Source and tests

2.6.3. ALU8

The caller supplies operands, an operation, and carry input. Opcode decoding, shared subtraction for comparisons, result selection, and flag selection are internal.

IO pins

Pin Direction Width Description
A Input 8 First operand
B Input 8 Second operand or shift/rotate distance
OP Input 5 Complete ALU opcode
C_IN Input 1 Carry/no-borrow input for ADC/SBC; carry source for zero-distance shifts/rotates
OUT Output 8 Selected result
ZERO Output 1 1 when OUT is zero
NEGATIVE Output 1 Bit 7 of a binary OUT
CARRY Output 1 Arithmetic carry/no-borrow or shift/rotate carry; otherwise 0
OVERFLOW Output 1 Signed arithmetic overflow; otherwise 0
INVALID_OP Output 1 A reserved opcode is selected

There is no clock, start, busy, valid/ready handshake, or stored status register. DIFF, CARRY_IN, and OVERFLOW_IN from CompareSelect8 are not external ALU pins.

Behavior

Operands and OUT are eight-bit patterns. Arithmetic wraps modulo 256; signed operations interpret a pattern as two's complement in −128–127. Let \(s(x)\) denote that signed interpretation and \(n=B\mathbin{\&}7\) the effective shift distance.

Opcode map

OP Operation OUT
0x00 ADD A + B
0x01 ADC A + B + C_IN
0x02 SUB A - B
0x03 SBC A - B - (1 - C_IN)
0x04 INC A + 1
0x05 DEC A - 1
0x06 NEG 0 - A
0x07 Reserved 0x00; INVALID_OP = 1
0x08 AND A AND B, bitwise
0x09 OR A OR B, bitwise
0x0A XOR A XOR B, bitwise
0x0B NOT Bitwise complement of A
0x0C NAND Bitwise complement of A AND B
0x0D NOR Bitwise complement of A OR B
0x0E XNOR Bitwise complement of A XOR B
0x0F Reserved 0x00; INVALID_OP = 1
0x10 SLL Shift A left by n, zero fill
0x11 SRL Shift A right by n, zero fill
0x12 SRA Shift A right by n, sign fill
0x13 ROL Rotate A left by n
0x14 ROR Rotate A right by n
0x15 EQ 0x01 if A == B, otherwise 0x00
0x16 SLTU 0x01 if unsigned A < B, otherwise 0x00
0x17 SLT 0x01 if s(A) < s(B), otherwise 0x00
0x18 MINU Smaller unsigned operand
0x19 MAXU Larger unsigned operand
0x1A MINS Operand with smaller signed value
0x1B MAXS Operand with larger signed value
0x1C PASS_A A
0x1D PASS_B B
0x1E CLEAR 0x00; INVALID_OP = 0
0x1F Reserved 0x00; INVALID_OP = 1

Min/max operations return the original operand pattern, not a predicate or magnitude. Rotations operate on eight bits, not on a nine-bit word containing carry. The full operation details are in arithmetic, logic, shifts and rotations, and comparison and selection.

Flags and ignored inputs

ZERO = [OUT == 0] and NEGATIVE = OUT[7] for every binary result, including predicates and reserved operations. A false comparison therefore sets ZERO = 1; a true comparison returns 0x01 and sets ZERO = 0.

Operation group CARRY OVERFLOW
Arithmetic (0x00–0x06) Carry-out for addition; 1 means no borrow for subtraction Signed result before wrapping is outside −128–127
Shift/rotate (0x10–0x14), n > 0 Last bit shifted/rotated out 0
Shift/rotate (0x10–0x14), n = 0 C_IN 0
Logic, comparison, min/max, pass, clear, reserved 0 0

The arithmetic flag rules for INC, DEC, and NEG are specified in 2.1. In particular, NEG sets carry only for A = 0; this ALU uses the no-borrow convention consistently.

For known opcodes, ignored inputs are isolated from the settled outputs:

  • B is ignored by INC, DEC, NEG, NOT, and PASS_A.
  • A is ignored by PASS_B; both operands are ignored by CLEAR and reserved operations.
  • Shifts and rotations ignore B[7:3], even when those bits are unknown.
  • C_IN is used only by ADC, SBC, and zero-distance shifts/rotates. In particular, ordinary subtraction and all comparisons ignore it.

Reserved opcodes produce OUT = 0, ZERO = 1, NEGATIVE = CARRY = OVERFLOW = 0, and INVALID_OP = 1. CLEAR produces the same result and flags except INVALID_OP = 0. For a supported, known opcode, INVALID_OP = 0 even when an operand is unknown or arithmetic overflows.

C++ example

This example composes the functions from 2.1, 2.2, 2.3, 2.4, and 2.5. Compile those C++ examples first, in chapter order.

struct ALU8Result {
    std::uint8_t OUT;
    bool ZERO;
    bool NEGATIVE;
    bool CARRY;
    bool OVERFLOW;
    bool INVALID_OP;
};

ALU8Result alu8_ref(
    std::uint8_t a, std::uint8_t b, std::uint8_t op, bool c_in) {
    const bool arithmetic = op <= 0x06;
    const bool logic = op >= 0x08 && op <= 0x0E;
    const bool shift = op >= 0x10 && op <= 0x14;
    const bool comparison = op >= 0x15 && op <= 0x1B;
    const bool transfer = op >= 0x1C && op <= 0x1E;
    const bool invalid = !(arithmetic || logic || shift || comparison || transfer);

    std::uint8_t out = 0;
    bool arith_carry = false, arith_overflow = false, shift_carry = false;
    if (arithmetic || comparison) {
        const auto local_op = static_cast<std::uint8_t>(comparison ? 2 : op);
        const auto r = arithmetic8_ref(a, b, local_op, c_in);
        arith_carry = r.CARRY;
        arith_overflow = r.OVERFLOW;
        out = comparison
            ? compare_select8_ref(a, b, r.OUT, r.CARRY, r.OVERFLOW,
                                  static_cast<std::uint8_t>(op - 0x15))
            : r.OUT;
    } else if (logic) {
        out = logic8_ref(a, b, static_cast<std::uint8_t>(op - 0x08));
    } else if (shift) {
        const auto r = shift8_ref(a, b, static_cast<std::uint8_t>(op - 0x10), c_in);
        out = r.OUT;
        shift_carry = r.CARRY;
    } else if (op == 0x1C) {
        out = a;
    } else if (op == 0x1D) {
        out = b;
    }
    const auto f = flags8_ref(out, arithmetic, shift,
                              arith_carry, arith_overflow, shift_carry);
    return {out, f.ZERO, f.NEGATIVE, f.CARRY, f.OVERFLOW, invalid};
}

op represents a five-bit binary pin. Out-of-range integer arguments also return the invalid-operation result; they are not masked into an unrelated valid opcode. The example skips inactive computations for clarity, whereas the structural circuit can evaluate them and masks their outputs.

Unknown inputs and timing

The structural gates determine four-state behavior; the C++ example does not. Known operation selection masks inactive result paths, so unknown data in an unused path does not automatically make OUT unknown. For example, CLEAR and reserved opcodes still produce their defined zero result with unknown data and carry inputs, and AND with an all-zero operand produces zero despite unknown bits in the other operand.

An X/Z bit that affects the selected computation follows its gates' propagation rules. ZERO can be unknown for a partially unknown result with no known 1. A high-impedance operand bit passing through logic is treated as unknown, not preserved as a high-impedance output.

An opcode containing X or Z is not automatically a reserved encoding. Decoder and selection gates determine the outputs; INVALID_OP is not an input-validity checker. The contract test specifically checks that an entirely unknown/high-impedance opcode produces INVALID_OP = X, without asserting a complete output word for that case.

In structural fidelity, all operation paths are combinational and may change while gates settle. There is no fixed instruction-cycle count, atomic result/flag update, or declared worst-case structural ALU8 latency. Recorded checkpoints inspect settled results; intermediate timeline positions can show propagation through the decoder, carry chain, result selector, and flags. Catalog-selected behavioral fidelity uses delays characterized from the gate network. Its delay twin can time the current operation and operands, while the proven per-path table bounds publication when the twin cannot answer. It does not reproduce intermediate gate glitches.

Implementation

Structural implementation

Internal component or network Responsibility
CONTROL (ALU8ControlDecoder) Decode the opcode into local selectors, enables, and the invalid flag
ARITHMETIC (ArithmeticUnit8) Seven arithmetic operations and shared subtraction for comparisons
LOGIC (LogicUnit8) Seven bitwise operations
SHIFTER (BarrelShifter8) Three shifts and two rotations
COMPARE_SELECT (CompareSelect8) Interpret subtraction data/flags and select predicates or operands
RESULT_SELECT (ALU8ResultSelector) Select and assemble the final eight-bit word
FLAGS (ALU8FlagUnit) Derive zero/sign and select carry/overflow

In the default structural profile there is exactly one AddSub8, containing one Adder8 and eight FullAdder components, in the complete ALU hierarchy. Each of the seven operation units can independently switch between structural and behavioral fidelity. Nested AddSub8, Adder8, and ZeroDetect8 units are also selectable. A structural root with all seven units set to behavioral has eight components; a behavioral root has one. Structural8Builder is only a construction/wiring helper.

The five-bit opcode is translated to each unit's three-bit local selector:

Selected group Local operation Result source
Arithmetic OP[2:0] ARITHMETIC.OUT
Logic OP[2:0] LOGIC.OUT
Shift/rotate OP[2:0] SHIFTER.OUT
Comparison/min/max Arithmetic forced to local SUB = 2; comparison remapped to OP - 0x15 COMPARE_SELECT.OUT
PASS_A, PASS_B No unit result selected External A or B
CLEAR, reserved No result source enabled Zero from the masked result network

For comparison operations, the same A and B drive both units. ARITHMETIC.OUT, CARRY, and OVERFLOW connect to COMPARE_SELECT.DIFF, CARRY_IN, and OVERFLOW_IN. This makes the comparison inputs consistent without requiring the caller to calculate them or adding a second subtractor. The arithmetic result/flag enable remains low during comparisons, even though the arithmetic unit is computing their intermediate subtraction.

The result network has six sources: arithmetic, logic, shift, comparison, A, and B. For each output bit, six AND gates mask these sources with decoded enables and five OR gates combine them. These enables select outputs; they do not stop inactive units from evaluating. The selected result feeds both OUT and FLAGS.RESULT. The top-level invalid flag comes from its own five-bit decoder, not from the arithmetic unit's local INVALID_OP.

Behavioral implementation

Behavioral8<ALU8> calls alu, which composes the four-state control, arithmetic, logic, shift, comparison, result-selection, and flag functions. Comparison inputs come from the same computed subtraction result and flags. Unlike the simplified C++ example, this evaluator computes the operation paths and masks their outputs, preserving the gate expressions' treatment of inactive and unknown inputs.

The evaluator is defined in ALU8Behavioral.cpp; its value functions are in ALU8ValueModel.hpp. It retains the public pins without functional circuit children. Catalog construction supplies a delay table characterized from the gates; where a delay twin is available and agrees with the computed value, publication can follow the current inputs’ gate-level settling time within that bound, subject to older pending results. The compact evaluator does not reproduce transient gate glitches.

The recorded scenario runs against both implementations in CTest. ALU8FidelityContractTest checks binary/X/Z settled-output equivalence against the structural circuit. The example table uses the default structural run; its checkpoint times need not match the behavioral run.

Examples

All 70 recorded rows of ALU8Test, in checkpoint order. Outputs are test expectations verified against the simulation. Time is the absolute settled checkpoint time in simulator units, not milliseconds or CPU cycles.

Default scenario profile: canonical-default-preview / structural (e35085b4ea551693). Changing fidelity or the circuit can change these times.

Checkpointzero-based number · timeline label Timesimulator units AInput · 8 bit BInput · 8 bit C_INInput · 1 bit OPInput · 5 bit CARRYExpected output · 1 bit INVALID_OPExpected output · 1 bit NEGATIVEExpected output · 1 bit OUTExpected output · 8 bit OVERFLOWExpected output · 1 bit ZEROExpected output · 1 bit
#0row-038 0x81 0x03 0 0x00 0 0 1 0x84 0 0
#1row-178 0x7F 0x01 1 0x00 0 0 1 0x80 1 0
#2row-2104 0x81 0x03 0 0x01 0 0 1 0x84 0 0
#3row-3140 0x7F 0x01 1 0x01 0 0 1 0x81 1 0
#4row-4180 0x81 0x03 0 0x02 1 0 0 0x7E 1 0
#5row-5203 0x7F 0x01 1 0x02 1 0 0 0x7E 0 0
#6row-6239 0x81 0x03 0 0x03 1 0 0 0x7D 1 0
#7row-7262 0x7F 0x01 1 0x03 1 0 0 0x7E 0 0
#8row-8291 0x81 0x03 0 0x04 0 0 1 0x82 0 0
#9row-9329 0x7F 0x01 1 0x04 0 0 1 0x80 1 0
#10row-10374 0x81 0x03 0 0x05 1 0 1 0x80 0 0
#11row-11396 0x7F 0x01 1 0x05 1 0 0 0x7E 0 0
#12row-12438 0x81 0x03 0 0x06 0 0 0 0x7F 0 0
#13row-13461 0x7F 0x01 1 0x06 0 0 1 0x81 0 0
#14row-14487 0x81 0x03 0 0x07 0 1 0 0x00 0 1
#15row-15500 0x7F 0x01 1 0x07 0 1 0 0x00 0 1
#16row-16526 0x81 0x03 0 0x08 0 0 0 0x01 0 0
#17row-17566 0x7F 0x01 1 0x08 0 0 0 0x01 0 0
#18row-18590 0x81 0x03 0 0x09 0 0 1 0x83 0 0
#19row-19626 0x7F 0x01 1 0x09 0 0 0 0x7F 0 0
#20row-20666 0x81 0x03 0 0x0A 0 0 1 0x82 0 0
#21row-21689 0x7F 0x01 1 0x0A 0 0 0 0x7E 0 0
#22row-22725 0x81 0x03 0 0x0B 0 0 0 0x7E 0 0
#23row-23748 0x7F 0x01 1 0x0B 0 0 1 0x80 0 0
#24row-24773 0x81 0x03 0 0x0C 0 0 1 0xFE 0 0
#25row-25811 0x7F 0x01 1 0x0C 0 0 1 0xFE 0 0
#26row-26856 0x81 0x03 0 0x0D 0 0 0 0x7C 0 0
#27row-27878 0x7F 0x01 1 0x0D 0 0 1 0x80 0 0
#28row-28920 0x81 0x03 0 0x0E 0 0 0 0x7D 0 0
#29row-29943 0x7F 0x01 1 0x0E 0 0 1 0x81 0 0
#30row-30969 0x81 0x03 0 0x0F 0 1 0 0x00 0 1
#31row-31982 0x7F 0x01 1 0x0F 0 1 0 0x00 0 1
#32row-321011 0x81 0x03 0 0x10 0 0 0 0x08 0 0
#33row-331051 0x7F 0x01 1 0x10 0 0 1 0xFE 0 0
#34row-341083 0x81 0x03 0 0x11 0 0 0 0x10 0 0
#35row-351119 0x7F 0x01 1 0x11 1 0 0 0x3F 0 0
#36row-361159 0x81 0x03 0 0x12 0 0 1 0xF0 0 0
#37row-371182 0x7F 0x01 1 0x12 1 0 0 0x3F 0 0
#38row-381218 0x81 0x03 0 0x13 0 0 0 0x0C 0 0
#39row-391241 0x7F 0x01 1 0x13 0 0 1 0xFE 0 0
#40row-401269 0x81 0x03 0 0x14 0 0 0 0x30 0 0
#41row-411307 0x7F 0x01 1 0x14 1 0 1 0xBF 0 0
#42row-421357 0x81 0x03 0 0x15 0 0 0 0x00 0 1
#43row-431380 0x7F 0x01 1 0x15 0 0 0 0x00 0 1
#44row-441429 0x81 0x03 0 0x16 0 0 0 0x00 0 1
#45row-451460 0x7F 0x01 1 0x16 0 0 0 0x00 0 1
#46row-461506 0x81 0x03 0 0x17 0 0 0 0x01 0 0
#47row-471538 0x7F 0x01 1 0x17 0 0 0 0x00 0 1
#48row-481584 0x81 0x03 0 0x18 0 0 0 0x03 0 0
#49row-491618 0x7F 0x01 1 0x18 0 0 0 0x01 0 0
#50row-501654 0x81 0x03 0 0x19 0 0 1 0x81 0 0
#51row-511688 0x7F 0x01 1 0x19 0 0 0 0x7F 0 0
#52row-521736 0x81 0x03 0 0x1A 0 0 1 0x81 0 0
#53row-531771 0x7F 0x01 1 0x1A 0 0 0 0x01 0 0
#54row-541819 0x81 0x03 0 0x1B 0 0 0 0x03 0 0
#55row-551854 0x7F 0x01 1 0x1B 0 0 0 0x7F 0 0
#56row-561887 0x81 0x03 0 0x1C 0 0 1 0x81 0 0
#57row-571925 0x7F 0x01 1 0x1C 0 0 0 0x7F 0 0
#58row-581970 0x81 0x03 0 0x1D 0 0 0 0x03 0 0
#59row-591992 0x7F 0x01 1 0x1D 0 0 0 0x01 0 0
#60row-602034 0x81 0x03 0 0x1E 0 0 0 0x00 0 1
#61row-612057 0x7F 0x01 1 0x1E 0 0 0 0x00 0 1
#62row-622083 0x81 0x03 0 0x1F 0 1 0 0x00 0 1
#63row-632096 0x7F 0x01 1 0x1F 0 1 0 0x00 0 1
#64row-642141 0xFF 0x01 0 0x00 1 0 0 0x00 0 1
#65row-652181 0x00 0x00 0 0x06 1 0 0 0x00 0 1
#66row-662209 0x80 0x00 0 0x06 0 0 1 0x80 1 0
#67row-672245 0xFF 0xFF 0 0x03 0 0 1 0xFF 0 0
#68row-682275 0x81 0x00 1 0x10 1 0 1 0x81 0 0
#69row-692303 0x81 0x08 1 0x14 1 0 1 0x81 0 0

Scroll within the table for all rows and pins. Buses use hexadecimal; values containing X/Z use MSB-first binary. Inputs show the declared values in effect at each checkpoint, including retained inputs. Sequential tests also replay preparation changes between checkpoints, such as lowering the clock. Use the matching checkpoint label in the simulation below.

The signed comparison and signed-minimum examples return different kinds of data: SLT returns a positive predicate word, while MINS returns the negative operand's original bits. Their NEGATIVE flags follow those output words, not the internal subtraction.

Embedded simulation

The alu8 scenario runs ALU8Test: two operand/carry sets for each of the 32 opcodes, followed by six targeted arithmetic and zero-distance shift/rotate cases, for 70 recorded rows. The top level contains exactly seven named blocks. Open the explorer to inspect CONTROL, ARITHMETIC, LOGIC, SHIFTER, COMPARE_SELECT, RESULT_SELECT, or FLAGS; their gates remain expandable and the timeline includes their actual propagation.

Open ALU8 in the simulator

Source and tests

Test Coverage
ALUHierarchyTest Checks the seven named top-level blocks in both ALUs and a single eight-/32-bit full-adder chain. Grouping does not reduce the number of gates.
ALU8FidelityContractTest 84,100 settled-output comparisons across all 11 Chapter 2 families, including every four-state zero-detector input, every four-state opcode, and every result-selector enable combination with sampled data. Also checks 13 mixed-fidelity profiles × 256 integrated inputs. These are not exhaustive over the full ALU's four-state input space.
ALU8Test 70 recorded binary rows; checks OUT and all five single-bit outputs. This is the embedded scenario.
ALU8ContractTest: integrated binary checks 5,184 boundary cases: 32 opcodes × nine A values × nine B values × both carry inputs, plus 2,048 seeded random cases. Checks all outputs against an independent integer oracle.
ALU8ContractTest: structure and four-state checks Checks five-bit OP and exactly one AddSub8, one Adder8, and eight FullAdder instances. Adds 28 targeted X/Z cases for ignored inputs, masked results, partial unknown results, shifts, and unknown opcode indication. The two entirely unknown-opcode cases check only INVALID_OP.
ALU8ContractTest: standalone sweeps 262,144 AddSub8 cases and 20,480 valid BarrelShifter8 cases; these are separate lower-level circuits, not that many full-ALU rows.
ALU8WasmParityTest.mjs Compares native and WASM portable topology, timestamps/checkpoint metadata, initial/final states, and expanded ALU topology for the recorded scenarios. This is not an independent arithmetic oracle or an every-timestamp state comparison.
VisualizerWasmBrowserTest.py Checks the chapter embeds, scenario/type/row counts, accessible compact controls, and focus framing in an actual browser.

The integrated contract sweep contains 7,260 cases, not an exhaustive sweep of all 4,194,304 binary A/B/OP/C_IN combinations. It disables history recording; the embedded simulation contains only the 70 recorded rows.

The component catalog identifies this interface as alu.width8, contract version 2. Its inputs include five-bit OP and C_IN; no four-bit-opcode compatibility mode is part of this contract. The ALU32 and RV32I ALU interfaces are separate contracts.