ALU & Flags
Flags
My ALU has four flags: Zero (Z), Negative (N), Carry (C), and Overflow (O/V).
1. Arithmetic and Logic Operations
Zero (Z) Flag
The Z flag is set when the result of an operation is zero. It’s often used in control flow operations to make decisions based on the zero/non-zero outcome of previous operations.
Example:
0100 (4) - 0100 (4) = 0000 (0)
sets the Z flag because the result is zero.
Negative (N) Flag
The N flag is set when the result of an operation, interpreted in two’s complement, is negative.
Example:
0001 (1) - 0100 (4) = 1111 (-3)
in two’s complement sets the N flag as the result is negative.
Carry (C) Flag
The C flag is affected during unsigned arithmetic to indicate whether there’s a carry out of the most significant bit during addition, or a borrow during subtraction.
Example:
1111 (15) + 0001 (1) = 0000 (0)
in unsigned arithmetic sets the C flag because there’s a carry out of the most significant bit.
Overflow (O/V) Flag
The O (or V) flag is set during signed arithmetic if the signed result falls outside the representable range for the given number of bits. In other words, the flag is set when adding two positive numbers yields a negative value, or vice versa. The Overflow flag is not affected by or concerned with unsigned arithmetic.
Example:
0110 (6) + 0101 (5) = 1011 (-5)
1110 (-6) + 1001 (-1) = **1**0111 (7)
In signed arithmetic these results set the O flag because the result has overflowed the positive representable range.
An overflow is checked by comparing the carry into and out of the MSB. If they’re different, the O flag is set. The ALU internally uses a XOR operation on these two carry signals to set the O flag:
- If both are equal (either both are 0 or both are 1), there is no overflow, and the Overflow flag is not set.
- If they are different (one is 0 and the other is 1), there is an overflow, and the Overflow flag is set.
Examples:
(4) + (5) = (9)
0100 + 0101 = 1001 <-- ("4 + 5 = -7" in two's complements)
Carry 01000
Number A 0100
Number B + 0101
-----
1001
(Carry out (0)) XOR (carry into MSB (1)) = 1 (Overflow flag is set)
(-4) + (-2) = (-6)
1100 + 1110 = 1010 <-- ("-4 - 2 = -6" in two's complements)
Carry 11000
Number A 1100
Number B + 1110
-----
1010
(Carry out (1)) XOR (carry into MSB (1)) = 0 (Overflow flag is not set)
2. Shift Operations
Shift operations also influence the Z, N, and C flags.
Zero (Z) Flag in Shift Operations
- Example: Right shift
0001 (1)
to0000 (0)
sets the Z flag, indicating the result is zero.
Negative (N) Flag in Shift Operations
- Example: Left shift
0100 (4)
to1000 (-8)
in two’s complement sets the N flag because the result is negative.
Carry (C) Flag in Shift Operations
The carry flag can be influenced during shift operations, especially during right shifts where the last bit shifted out is often stored in the carry flag.
Examples:
Right shift
1001 (9)
to0100 (4)
sets the C flag as the last bit shifted out is 1.
Together, the Z, O, N, and C flags provide a detailed post-operation status that can be used for efficient decision-making, error handling, and optimized control flow in various computational tasks.
Implementation
Control lines involved(10):
- |←~ZE Accumulator enable: Outputs accumulator’s content to 8-bit bus.
- |← ZS ALU select: 382 ALU or the Shift register.
- |← ZW Accumulator write
- |← Z0 ALU select_0
- |← Z1 ALU select_1
- |← Z2 ALU select_2
- |← HC_in Shift register’s carry-in: Replaces the shifted bit.
- |←~HC Shift register’s clear
- |←~FE Flags register’s enable: Flag register’s content enable to 8-bit bus
- |←~FW Flags register’s write
- |→ II Interrupt inhibit(Just uses a spare pin of flag register’s transceiver)(Comes from Interrupt logic and is not really related to the flags module)
The 74LS382 is the central chip of my ALU module. For reasons that I ignore, this chip is not available in the HC or HCT family. It performs the following arithmetic and logic operations: Addition, subtraction, OR, exclusive OR, and AND. Additionally it can mirror its content and a null/zero output to the bus. It operates on 4-bit words, so just like the 74HCT173, I use a pair of it to do 8-bit operations.
Pin No | Pin Name | Description |
---|---|---|
3, 1, 19, 17 | A0, A1, A2, A3 | Word A inputs |
4, 2, 18, 16 | B0, B1, B2, B3 | Word B inputs |
5, 6, 7 | S0, S1, S2 | Function Select |
8. 9, 11, 12 | F0, F1, F2, F3 | Output Pins |
10 | GND | Ground |
11, 12, 13, 14 | D3, D4, D5, D6 | Data Input 3, 2, 1, 0 |
20 | VCC | Supply Voltage |
13 | ~G | Generate Carry Output |
14 | ~P | Ripple-Carry Output |
15 | Cn | Carry Input |
Table 1: 74LS382 Pin Configuration
S2 S1 S0 | Operation |
---|---|
0 0 0 | ZERO/NULL |
0 0 1 | B minus A |
0 1 0 | A minus B |
0 1 1 | A plus B |
1 0 0 | A XOR B |
1 0 1 | A OR B (A+B) |
1 1 0 | A AND B (AB) |
1 1 1 | Mirror Input |
Table 2: 74LS382 Functions
To perform shift operations, I use a pair of 74HCT194; a 4-bit bidirectional shift register with parallel and serial data input modes. It enables shifting data left or right and has an asynchronous master reset.
Pin No | Pin Name | Description |
---|---|---|
1 | ~MR D4, D5, D6, D7 | Active Low Asynchronous Master Reset |
2 | Dsr | Serial Data Input Pin (shift right) |
3, 4, 5, 6, | D0, D1, D2, D3, | Parallel Data Inputs |
7 | Dsl | Serial Data Input Pin (shift left) |
8 | GND | Ground Pin |
9, 10 | S0, S1 | Function Select |
11 | CP | Clock Pulse Input |
15, 14, 13, 12 | Q0, Q1, Q2, Q3 | Parallel Output Pin 0, 1, 2, 3 |
16 | VCC | Chip Supply Voltage |
Table 3: 74HCT194 Pin Configuration
For zero-detection, I use a 74HCT688 8-Bit Magnitude Comparator, which provides a cleaner and more efficient solution compared to using two separate ICs(a NOR and an AND IC) to construct my zero detector
Pin No | Pin Name | Description |
---|---|---|
1 | E | Enable input |
2, 4, 6, 8, 11, 13, 15, 17 | P0 to P7 | Word P inputs |
3, 5, 7, 9, 12, 14, 16, 18 | Q0 to Q7 | Word Q inputs |
10 | GND | Ground Pin |
19 | ~(P = Q) | Active Low Equal to output |
20 | VCC | Chip Supply Voltage |
Table 4: 74HCT688 Pin Configuration
Looking at the high level schematic/diagram below:
Let’s call the two 74LS382, the Arithmetic and Logic submodule (382), and the two 74HCT194, the shift submodule (194) or shift register. The accumulator/Z-reg (74HCT574) stores the result of the ALU’s operations.
From the bottom up:
1- Both sub-modules receive their inputs from the data bus, with the 382 getting its second input/operand, from the accumulator. This means that to perform an operation between two operands, A and B; B must first be loaded into the accumulator.
2- The outputs of both sub-modules are directly connected to an 8-bit multiplexer made with two 74HCT257/257 4-bit muxs.
Note: While I use a 74HCT257, a 74HCT157 could also serve the purpose. The only difference between the two is that the 257 has a tri-state output, which I am not using.
The ZS control lines determine which sub-module’s value gets selected by the multiplexer. ZS = 0 selects the Arithmetic and Logic sub-module and ZS = 1 selects the shift sub-module.
3- The output from the sub-modules mux is connected directly to both the accumulator and the zero-detector. The transceiver, positioned between the accumulator’s output and the bus, much like most transceivers in this build, allows the content of the accumulator to be displayed on status LEDs without interfering with the bus content.
The two 74HCT153 multiplexers(flags mux) are used to select the appropriate flag based on the current operation. The output from the flags mux is then fed into a final 74HCT257 before entering the flags register allowing to either overwrite the content of the flag register or use the previous flags.
The two figures below show the full schematic of the ALU module:
Zs | Z2 | Z1 | Z0 | Accumulator’s input | Z flag | O/V flag | N flag | C flag |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0x00 | Z | OVR | D7 | Cn+4 |
0 | 0 | 0 | 1 | B - A | Z | OVR | D7 | Cn+4 |
0 | 0 | 1 | 0 | A - B | Z | OVR | D7 | Cn+4 |
0 | 0 | 1 | 1 | A + B | Z | OVR | D7 | Cn+4 |
0 | 1 | 0 | 0 | A XOR B | Z | OVR | D7 | Cn+4 |
0 | 1 | 0 | 1 | A OR B | Z | OVR | D7 | Cn+4 |
0 | 1 | 1 | 0 | A AND B | Z | OVR | D7 | Cn+4 |
0 | 1 | 1 | 1 | 0XFF | Z | OVR | D7 | Cn+4 |
1 | 0 | 0 | 0 | 194 | Z | OVR | D7 | Cn+4 |
1 | 0 | 0 | 1 | LSL | Z | 0 | D7 | D7 |
1 | 0 | 1 | 0 | LSR | Z | 0 | D7 | D0 |
1 | 0 | 1 | 1 | Bus | D3 | D2 | D1 | D0 |
1 | 1 | 0 | 0 | Reset Carry | Z | O/V | N | 0 |
1 | 1 | 0 | 1 | Set Carry | Z | O/V | N | 1 |
Table 5: ALU’s Truth Table
Important Microcode-Related Notes
Mirroring Bus Content
Note that the 74LS382 does not have a “mirror bus” function; which would have made loading the accumulator with the value on the bus very straightforward. The 74HCT194 on the other hand does have this function; but since it is a sequential component, it requires an extra cycle to be loaded before its output can be loaded into the accumulator.
Flags And Shift Register Control Contention
Writing the bus content to the flags register requires Zs = Z1 = Z0 = 1. This essentially sets the shift register to also get the bus content. In other words; every time the bus content is being written to the flags register, it is also getting written in the shift register. Besides the soft reset instruction, I do not have any instruction that uses both FLG_MIRROR_BUS and a shift operation right now.
ADD and SUB
The ALU’s Carry-in is permanently connected to the carry out from the previous operation, which means that if for example $A
contains 0b11111111
, and $B
contains 0b0
. An ADD $A, 0b1
, will obviously set the C flag. However; if following this first ADD, an ADD $B, 0b1 is performed, the input will have a carry-in added to it, so $B
will contain 0b10 instead of 0b01. In other words, my ADD
and SUB
are actually ADC
and SBC
. I however have a STC
, and CLC
.
So an actual regular ADD $A, 1
, for example, on my CPU is :
CLC
ADD $A, 1
And an actual regular SUB $A, 1
is :
CLC
SUB $A, 1
ICs
2 x 74LS382(Datasheet)
2x 74HCT194 (Digikey, Datasheet)
4x 74HCT257 Quarduple 2:1 mux (Digikey, Datasheet)
2x 74LS153 (Dual 4- to 1-Line Selector/Multiplexer), (Digikey, Datasheet).
1x 74HCT688 8-Bit Magnitude Comparator, (Jameco, Datasheet).
2x 74HCT245, Octal Bus Transceivers With 3-State Outputs, (Digikey, Datasheet).
1x 74HCT173, 4-Bit D-type Registers with tri-state Outputs, (Digikey, Datasheet).
1x 74HCT08 Quadruple 2-Input Positive-AND Gates 74HCT08 (Digikey, Datasheet)
«««««««««« Previous Post: ALU Primer
Next Post: RAM & ROM Primer »»»»»»»»»»
Updated: