avatarKarl Rombauts

Summary

The article details the construction of an 8-bit computer's Arithmetic Logic Unit (ALU) in Logisim, focusing on the implementation and significance of status flags such as Carry, Zero, Negative, and Overflow.

Abstract

In the fourth part of a series on building an 8-bit computer in Logisim, the author delves into the development of the ALU, emphasizing the role of status flags. These flags are crucial for indicating the outcome of arithmetic operations, such as whether there was a carry (C), if the result was zero (Z), whether the result was negative (N), or if an overflow/underflow occurred (V). The article explains how to construct circuits to detect these conditions, using logical operations and gates like NOR, XNOR, and XOR. By the end, the author integrates these flags into the ALU, setting the stage for future operations like comparisons and the addition of multiplication and division circuits.

Opinions

  • The author believes that understanding status flags is essential for building a functional ALU, as they provide critical information about arithmetic operations.
  • The article suggests that the carry flag is particularly relevant for unsigned arithmetic operations, implying that it may be disregarded for logical operations and signed arithmetic.
  • The use of visual aids, such as circuit diagrams and truth tables, indicates the author's opinion that these tools are effective for explaining complex logical operations.
  • The author values efficiency in circuit design, as evidenced by the exploration of different methods to detect overflow conditions, ultimately presenting a simpler XOR-based solution.
  • The recommendation of an AI service at the end of the article implies the author's endorsement of AI tools for educational purposes or as a cost-effective alternative to other AI services.

Building an 8-bit computer in Logisim (Part 4 — Status Flags)

This is the forth article in a series. If you haven’t read the previous parts, you can find them here:

Now that we have our main arithmetic sorted, in this part, we will be looking at how to build the Arithmetic Logic Unit (ALU).

What are status flags?

Status flags are usually a single bit that tells us some information about the last arithmetic operations that we did. So a flag is either set to 1 (true) or 0 (false). Four common flags are:

  • Carry Flag (C)
  • Zero Flag (Z)
  • Negative/Signed Flag (N)
  • Overflow/Underflow Flag (V)

Let’s take a look at each flag in more detail.

Carry Flag (C)

The carry flag is set to 1 (true) if the arithmetic operation results in an output carry bit of 1. An example of this would be if we try and add 255 + 255. In binary 255 is 1111 1111. Notice that we are dealing with an unsigned 8-bit number here. Let’s set both A and B to 1111 1111 on the ALU.

The output of the ALU is 1111 1110 (254 decimal). This is obviously not the right answer. So what happened here? Well, the operation produced an output carry. If you recall from previous parts, the output carry is used so that we can chain multiple full adder circuits together. But if the last full adder in the chain produces an output carry bit, it has nowhere to feed into. As you can see from the image above, that is precisely what happened here. The output carry of the last ALU block is set to 1. This tells us that the actual result of our operation should be 1 1111 1110 (510 decimal).

In a sense, the carry flag, which is just the carry output of the last ALU block, tells us the 8-bit result of the operation is not the whole result. Later, when we end up programming our computer, we can use this information to make conditional jumps. It is important to note that the carry flag is only meaningful if we are dealing with unsigned arithmetic operations. For logical operations like AND and OR, and signed arithmetic operations, we can generally ignore the carry flag.

Zero Flag (Z)

The zero flag is set to 1 (true) if the result from our arithmetic operation is equal to zero. For example 5 − 5 = 0 or 8 × 0 = 0. Let’s take a look at an example using our basic ALU circuit that we built in the previous section.

We will try to use the circuit to calculate 7 − 7. As an 8-bit binary number, 7 is 0000 0111. So we set A and B on the ALU both to 0000 0111. Then to do a subtraction, we Invert B and set the input carry bit to 1 (to flip the sign using twos complement).

The result is 0000 0000 as expected. So we want to set our zero flag to 1 if and only if all of our result bits are 0. This means we need to build a circuit to check if all the bits are zero.

As you might recall an OR gate outputs 1 if at least 1 of its inputs are 1. This is exactly the opposite behaviour that we need, so we can use a NOR gate (an inverted OR gate).

You can also think about this in terms of formal logic. The value of the zero flag should be 1 (true), if and only if all output result bits are 0 (false). We can represent that like so:

Z = ¬R1 ∧ ¬R2 ∧ ¬R3 ∧ ¬R4 ∧ ¬R5 ∧ ¬R6 ∧ ¬R7 ∧ ¬R8

Using De Morgans Law, we get: Z = ¬(R1 ∨ R2 ∨ R3 ∨ R4 ∨ R5 ∨ R6 ∨ R7 ∨ R8)

So that confirms that we can use a NOR gate to check that all the result bits are 0.

3-Bit NOR gate

In this gif, you can see that the NOR gate only outputs 1 if all the inputs are 0. Great, so all we need is an 8-bit NOR gate, and feed all the output bits from the adder circuit into the NOR gate.

Basic ALU Circuit with Z (Zero) Flag

So now when we perform 7 − 7 on our ALU, the zero status flag quickly lets us know that the result is zero. This is useful because we don’t need to check that each result bit is zero.

Negative/Signed Flag (N)

The negative flag Set to 1 if the arithmetic result of an operation is negative. Naturally, this flag is only meaningful if we are dealing with signed operations. As you may recall, when we represent signed numbers in two’s complement form, the most significant bit acts as a sign bit. If the most significant bit is set to 1 then we know the number is negative.

For example, -5 in two’s complement is 1111 1011. The most significant bit (leftmost) is 1, which tells us that the number is negative.

We can use this fact to easily create a signed flag. All we need to do is look at the most significant bit and see if it is 1.

Basic ALU Circuit with N (Negative) Flag

Now that we have a negative flag, we can easily check if the output is less than zero. This will come in very handy for comparison calculations.

Overflow/Underflow Flag (V)

The overflow/underflow flag is set to 1 if an overflow/underflow error occurs when we do a signed arithmetic operation. For example, when we are using two’s complement, the range of numbers we can represent with 8-bits is -128 (1000 0000) — 127 (0111 1111). So what happens when we try to do 127 + 1? We get an overflow error. If we actually try to do this operation on our ALU, the result would be 1000 0000, which is -128 in decimal. This is a result of us exceeding the maximum value we can store in 8 bits.

We can represent this visually like so

All possible signed 4-bit numbers in two’s compliment

The red dotted line represents the boundary between positive and negative numbers. When we add a positive number (addition), we go clockwise around the circle, and when we add a negative number (subtraction), we go anti-clockwise around the circle.

So how can we check if we have an overflow error?

Comparing Inputs and Outputs

One way to calculate the overflow flag is to compare the input to the output of our addition operation. If both inputs are positive (e.g. 127 + 1) and the output is negative (-128), then we know an overflow occurred. Two positive numbers will never add together to produce a negative number. Similarly, if we have two negative inputs (e.g. -128 + -1) and the output is positive (127) then we know an underflow occurred. Two negative numbers never add up to a positive number.

Finally, in the case where we have one positive input and one negative input, we actually can never have an overflow occur. This is because when we add a positive number to a negative one, the output will never be greater than the positive number, and will never be less than the negative number. So this means we can never go out of bounds. For example 12 + (-4) = 8. As you can see, 8 is less than 12 and greater than -4.

If we want to build a circuit that compares the input and output, the first thing we need to check is whether A and B have the same polarity. We can do this by comparing the sign bit of both numbers. So we take the most significant A bit and the most significant B bit and compare them. If they are the same then we know the numbers have the same polarity.

Conveniently the sign bits of the inputs and outputs are all the leftmost bits. This means we only need to concern ourselves with the leftmost 1-bit ALU block.

The leftmost ALU block deals with the sign bits

We will be looking at the internal circuits of this 1-bit ALU which we built in the previous part. First, we want to check that the sign bits (the A and B inputs) are both the same. If the sign bits are the same, we know that the two inputs have the same polarity. To check that two bits have the same value, we can use an XNOR gate. An XNOR gate outputs 0 if its inputs are different and outputs 1 if the inputs are the same.

Using an XNOR gate to check if both A and B have the same polarity

Now we also need to check if the input polarity is different from the output polarity. In this case, we want to check that two bits are different. So instead of an XNOR gate, we can use an XOR gate. We can take the value of the A input and the output of the adder and compare them. We could choose either A or B because we only care about the case where both A and B are the same.

Using an XOR gate to check if the input and output have different polarity

So now we are checking if the two inputs have the same polarity (XNOR gate) and if the output has a different polarity (XOR gate). An overflow will occur if and only if both these gates output a 1. To check this, we can just use an AND gate to finish off the circuit like so:

Final overflow/underflow flag circuit

This is pretty good, but there is a more efficient way to create the overflow flag circuit.

Comparing Carry Bits

Just like the previous method, we only care about the sign bits. Let’s have a look at a truth table for the full adder in the leftmost 1-bit ALU block.

The truth table for the full adder in the leftmost 1-bit ALU block

Here we have all of the possible values for the carry, A, and B inputs. I have highlighted the two results that cause an overflow/underflow. As you can see, in the first highlighted row, both A and B are 1, meaning both inputs are negative. But the sum output is 0, indicating that the output is positive. Similarly, the second row shows that A and B are 0 (positive), and the sum output is 1 (negative).

The other interesting thing is that if we take a look at the carry input and output for these rows, we can see that the input and output is not the same value. This property only happens when we have an overflow/underflow occur. So this means we can quickly check if we have an overflow by checking if the carry input is different from the carry output. We can use an XOR gate to do this.

Simpler overflow/underflow flag using an XOR gate

Putting It All Together

Basic ALU with all four status flags

Now, whenever we do an operation on our ALU, we can quickly check some useful facts about the result by looking at the status flags.

The last thing that is left is only outputting a flag value if one of the operations is selected. If no operation is selected, we should just output nothing.

If we want to check that at least one operation is selected, we can use an OR gate. And we can use the output of that gate to turn on and off the outputs of the status flags. The circuit would look something like this. Each of the flag output has a controlled buffer that we can turn on and off using the output of the OR gate.

Awesome! Our basic ALU circuit is now fully equipt with status flags. In the upcoming sections, we will see how we can make comparisons with these flags, and also add our multiplication and division circuits.

Flags
Alu
Computer Science
Logic
Binary
Recommended from ReadMedium