Skip to content

§ 2.3. Shifts and Rotations

BarrelShifter8 provides variable-distance shifts and rotations for ALU8. It operates on eight-bit words and reports the last shifted-out bit separately from the result.

Component Description Structural Behavioral
BarrelShifter8 Shifts or rotates an eight-bit word by zero through seven positions and reports the carry/last shifted-out bit Yes Yes

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

The combinational and bit-numbering conventions from 2.1. Arithmetic Components apply here. The simplified C++ example describes binary behavior, not the simulator implementation; it omits propagation delays and X/Z handling.

2.3.1. BarrelShifter8

BarrelShifter8 selects a shift or rotation of A by zero through seven bit positions. The result is produced by a structural multiplexer network, not by a clocked sequence of shifts.

IO pins

Pin Direction Width Description
A Input 8 Word to shift or rotate
B Input 8 Shift distance in bits 2–0; bits 7–3 are ignored
OP Input 3 Local shift/rotation selector
C_IN Input 1 Carry value returned for a valid operation with distance zero
OUT Output 8 Shifted or rotated word
CARRY Output 1 Last shifted-out bit, or C_IN for distance zero

There are no OVERFLOW, ZERO, NEGATIVE, or INVALID_OP pins on this component.

Behavior

The effective distance is

\[ n = B \mathbin{\&} 7, \qquad 0 \leq n \leq 7. \]

Thus B = 0x08 means distance zero, not a shift by eight; B = 0xFF means distance seven.

Local OP Operation Movement and fill Complete ALU8.OP
0b000 SLL Shift left; fill low bits with zero 0x10
0b001 SRL Shift right; fill high bits with zero 0x11
0b010 SRA Shift right; fill high bits with the original A[7] 0x12
0b011 ROL Rotate left; wrap shifted-out high bits into low positions 0x13
0b100 ROR Rotate right; wrap shifted-out low bits into high positions 0x14
0b101–0b111 Reserved OUT = 0, CARRY = 0, regardless of other inputs No corresponding shift operation

The reserved local selections are not a global invalid-opcode table: global codes 0x15–0x17 select comparison operations in the complete ALU. The top-level decoder determines which subunit's output is used.

For every valid operation at n = 0, OUT = A and CARRY = C_IN. For 1 ≤ n ≤ 7, the low eight result bits are

\[ \begin{aligned} \mathrm{SLL}(A,n) &= (A\,2^n) \bmod 256, \\ \mathrm{SRL}(A,n) &= \left\lfloor A/2^n \right\rfloor, \\ \mathrm{SRA}(A,n) &= \left\lfloor s(A)/2^n \right\rfloor \bmod 256. \end{aligned} \]

Here \(s(A)\) is the two's-complement interpretation from 2.1. For negative operands, arithmetic right shift rounds toward negative infinity; it is not C++ signed division's truncation toward zero.

Carry and ignored inputs

Operation CARRY when n > 0
SLL, ROL Original A[8 - n]
SRL, SRA, ROR Original A[n - 1]

C_IN does not supply a fill bit and never enters OUT. For nonzero distance it is ignored, including by the rotations. ROL and ROR rotate eight bits, not a nine-bit word containing carry. These carry rules report the last bit shifted out, not whether any discarded bit was 1.

C++ example

#include <cstdint>

struct Shift8Result {
    std::uint8_t OUT;
    bool CARRY;
};

Shift8Result shift8_ref(
    std::uint8_t a, std::uint8_t b, std::uint8_t op, bool c_in) {
    if (op > 4) return {0, false};
    const unsigned n = unsigned(b) & 7u;
    if (n == 0) return {a, c_in};

    const unsigned x = a;
    unsigned result = 0;
    switch (op) {
    case 0: result = x << n; break;                     // SLL
    case 1: result = x >> n; break;                     // SRL
    case 2:                                           // SRA
        result = (x >> n) | ((x & 0x80u) ? (0xFFu << (8 - n)) : 0u);
        break;
    case 3: result = (x << n) | (x >> (8 - n)); break;  // ROL
    case 4: result = (x >> n) | (x << (8 - n)); break;  // ROR
    }
    const unsigned carry_bit = (op == 0 || op == 3) ? 8 - n : n - 1;
    return {
        static_cast<std::uint8_t>(result & 0xFFu),
        ((x >> carry_bit) & 1u) != 0,
    };
}

The explicit zero-distance branch avoids invalid shift indices. All shifts operate on unsigned integers; sign fill is constructed explicitly. op represents the three-bit local selector; out-of-range integer arguments also return zero result and carry.

Unknown inputs and timing

For known, valid OP and known B[2:0], the unused upper bits of B do not affect either output, even when they contain X or Z. At nonzero distance, unknown C_IN is also isolated. At distance zero, an X or Z carry input yields CARRY = X through the gate network, while known A remains unchanged on OUT.

Unknown data or relevant control bits follow the underlying multiplexer gates. Bits that are known to be zero-filled can still be determined; a Z passing through logic becomes X, not a high-impedance output. Known reserved local selections mask both outputs to zero.

The three structural shift stages are combinational, not three clock cycles. Changes pass through direction selection, shift stages, and output masking before settling. No single structural component latency is declared; use the recorded checkpoints to inspect settled data and carry together.

Implementation

Structural implementation

The network first reverses the bit order for leftward operations, uses a shared rightward shift network, and reverses the result back afterward. Reversal changes bit positions; it does not invert their values.

Internal block Function
A_SPLIT, B_SPLIT Expose operand bits and distance controls
LEFT_SELECT, ROTATE_SELECT, ARITHMETIC_SELECT, VALID_SELECT Derive controls from local OP using Mux8to1 components
INPUT_REVERSE_* Select the original or reversed input order
SHIFT_1_* Optionally shift by 1, controlled by B[0]
SHIFT_2_* Optionally shift by 2, controlled by B[1]
SHIFT_4_* Optionally shift by 4, controlled by B[2]
OUTPUT_REVERSE_* Restore the bit order for leftward operations
VALID_BIT_*, CARRY_VALID Mask reserved selections to zero
OUT_JOIN Assemble the output word

Each enabled stage selects either a shifted word or the preceding word. Its carry multiplexer selects the stage's last shifted-out bit when enabled; otherwise it keeps the preceding carry. The chain starts with C_IN, which survives only when no shift stage is enabled. Fill selection supplies zero, the sign bit, or wrapped data according to the operation.

Behavioral implementation

Behavioral8<BarrelShifter8> calls shift. It evaluates direction reversal, the optional 1-, 2-, and 4-position stages, carry selection, and reserved-opcode masking as operations on arrays of four-state values. It creates no stage components or internal events; the three stages are evaluated within one call.

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 96 recorded rows of BarrelShifter8Test, 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 (396ffca50e2dd8dd). 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 · 3 bit CARRYExpected output · 1 bit OUTExpected output · 8 bit
#0row-019 0x81 0x00 0 0x0 0 0x81
#1row-127 0x81 0x00 1 0x0 1 0x81
#2row-239 0x81 0x01 0 0x0 1 0x02
#3row-341 0x81 0x01 1 0x0 1 0x02
#4row-451 0x81 0x03 0 0x0 0 0x08
#5row-553 0x81 0x03 1 0x0 0 0x08
#6row-661 0x81 0x07 0 0x0 0 0x80
#7row-763 0x81 0x07 1 0x0 0 0x80
#8row-875 0x81 0x08 0 0x0 0 0x81
#9row-983 0x81 0x08 1 0x0 1 0x81
#10row-1095 0x81 0xFF 0 0x0 0 0x80
#11row-1197 0x81 0xFF 1 0x0 0 0x80
#12row-12118 0x81 0x00 0 0x1 0 0x81
#13row-13126 0x81 0x00 1 0x1 1 0x81
#14row-14138 0x81 0x01 0 0x1 1 0x40
#15row-15140 0x81 0x01 1 0x1 1 0x40
#16row-16150 0x81 0x03 0 0x1 0 0x10
#17row-17152 0x81 0x03 1 0x1 0 0x10
#18row-18160 0x81 0x07 0 0x1 0 0x01
#19row-19162 0x81 0x07 1 0x1 0 0x01
#20row-20174 0x81 0x08 0 0x1 0 0x81
#21row-21182 0x81 0x08 1 0x1 1 0x81
#22row-22194 0x81 0xFF 0 0x1 0 0x01
#23row-23196 0x81 0xFF 1 0x1 0 0x01
#24row-24216 0x81 0x00 0 0x2 0 0x81
#25row-25224 0x81 0x00 1 0x2 1 0x81
#26row-26236 0x81 0x01 0 0x2 1 0xC0
#27row-27238 0x81 0x01 1 0x2 1 0xC0
#28row-28247 0x81 0x03 0 0x2 0 0xF0
#29row-29249 0x81 0x03 1 0x2 0 0xF0
#30row-30256 0x81 0x07 0 0x2 0 0xFF
#31row-31258 0x81 0x07 1 0x2 0 0xFF
#32row-32270 0x81 0x08 0 0x2 0 0x81
#33row-33278 0x81 0x08 1 0x2 1 0x81
#34row-34289 0x81 0xFF 0 0x2 0 0xFF
#35row-35291 0x81 0xFF 1 0x2 0 0xFF
#36row-36303 0x81 0x00 0 0x3 0 0x81
#37row-37311 0x81 0x00 1 0x3 1 0x81
#38row-38323 0x81 0x01 0 0x3 1 0x03
#39row-39325 0x81 0x01 1 0x3 1 0x03
#40row-40335 0x81 0x03 0 0x3 0 0x0C
#41row-41337 0x81 0x03 1 0x3 0 0x0C
#42row-42345 0x81 0x07 0 0x3 0 0xC0
#43row-43347 0x81 0x07 1 0x3 0 0xC0
#44row-44359 0x81 0x08 0 0x3 0 0x81
#45row-45367 0x81 0x08 1 0x3 1 0x81
#46row-46381 0x81 0xFF 0 0x3 0 0xC0
#47row-47383 0x81 0xFF 1 0x3 0 0xC0
#48row-48400 0x81 0x00 0 0x4 0 0x81
#49row-49408 0x81 0x00 1 0x4 1 0x81
#50row-50420 0x81 0x01 0 0x4 1 0xC0
#51row-51422 0x81 0x01 1 0x4 1 0xC0
#52row-52432 0x81 0x03 0 0x4 0 0x30
#53row-53434 0x81 0x03 1 0x4 0 0x30
#54row-54442 0x81 0x07 0 0x4 0 0x03
#55row-55444 0x81 0x07 1 0x4 0 0x03
#56row-56456 0x81 0x08 0 0x4 0 0x81
#57row-57464 0x81 0x08 1 0x4 1 0x81
#58row-58478 0x81 0xFF 0 0x4 0 0x03
#59row-59480 0x81 0xFF 1 0x4 0 0x03
#60row-60492 0x81 0x00 0 0x5 0 0x00
#61row-61500 0x81 0x00 1 0x5 0 0x00
#62row-62512 0x81 0x01 0 0x5 0 0x00
#63row-63514 0x81 0x01 1 0x5 0 0x00
#64row-64524 0x81 0x03 0 0x5 0 0x00
#65row-65526 0x81 0x03 1 0x5 0 0x00
#66row-66534 0x81 0x07 0 0x5 0 0x00
#67row-67536 0x81 0x07 1 0x5 0 0x00
#68row-68548 0x81 0x08 0 0x5 0 0x00
#69row-69556 0x81 0x08 1 0x5 0 0x00
#70row-70568 0x81 0xFF 0 0x5 0 0x00
#71row-71570 0x81 0xFF 1 0x5 0 0x00
#72row-72582 0x81 0x00 0 0x6 0 0x00
#73row-73590 0x81 0x00 1 0x6 0 0x00
#74row-74602 0x81 0x01 0 0x6 0 0x00
#75row-75604 0x81 0x01 1 0x6 0 0x00
#76row-76614 0x81 0x03 0 0x6 0 0x00
#77row-77616 0x81 0x03 1 0x6 0 0x00
#78row-78624 0x81 0x07 0 0x6 0 0x00
#79row-79626 0x81 0x07 1 0x6 0 0x00
#80row-80638 0x81 0x08 0 0x6 0 0x00
#81row-81646 0x81 0x08 1 0x6 0 0x00
#82row-82658 0x81 0xFF 0 0x6 0 0x00
#83row-83660 0x81 0xFF 1 0x6 0 0x00
#84row-84672 0x81 0x00 0 0x7 0 0x00
#85row-85680 0x81 0x00 1 0x7 0 0x00
#86row-86692 0x81 0x01 0 0x7 0 0x00
#87row-87694 0x81 0x01 1 0x7 0 0x00
#88row-88704 0x81 0x03 0 0x7 0 0x00
#89row-89706 0x81 0x03 1 0x7 0 0x00
#90row-90714 0x81 0x07 0 0x7 0 0x00
#91row-91716 0x81 0x07 1 0x7 0 0x00
#92row-92728 0x81 0x08 0 0x7 0 0x00
#93row-93736 0x81 0x08 1 0x7 0 0x00
#94row-94748 0x81 0xFF 0 0x7 0 0x00
#95row-95750 0x81 0xFF 1 0x7 0 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.

Embedded simulation

The barrel-shifter8 scenario runs BarrelShifter8Test: 96 recorded cases using A = 0x81, all eight local selections, six B values (0, 1, 3, 7, 8, 255), and both carry inputs. Checkpoints expose the zero-distance carry rule, masked distance, and reserved selections as well as shifts and rotations.

Open BarrelShifter8 in the simulator

Source and tests

Test Coverage
BarrelShifter8Test 96 recorded binary cases: eight local selections × six B values × both carry inputs, with A = 0x81. Checks OUT and CARRY; this is the embedded scenario.
ALU8ContractTest: standalone shifter sweep 20,480 cases: five valid operations × 256 A values × eight effective distances × both carry inputs. Every case drives B[7:3] = 0b11111.
ALU8ContractTest: integrated checks Boundary and seeded random ALU cases, plus targeted X/Z cases for ignored upper distance bits, ignored carry at nonzero distance, and unknown carry at zero distance.

The 20,480-case sweep is exhaustive over valid operations, data words, effective distances, and binary carry inputs, but not over every eight-bit B value, reserved local selection, or four-state pattern. It disables history recording; the embedded simulation contains only the 96 recorded cases.