I'm reading Chapter 17 of Charles Petzold book Code (which is excellent) and in it he's describing an automated adder which he's adding different Operation Codes or Instruction Codes.

In the diagram, he has an output for an 8 bit latch which says "Code", but it doesn't connect to anything else.

I'm just wondering how does the Op code instruct/tell the adder what to do (add/subtract/jump/halt/etc).

I'm guessing that it must change the control signals for different parts of the adder, but how does it recognize each Op Code?

Is it a lot of AND gates and Inverters? that connect to the control signal inputs of the other parts?

Thanks and by the way, I'm a newbie trying to understand and haven't even got to transistors or chips or anything else yet, so may not understand anything above a layman's explanation! And sorry if this question is a bit basic.


I don't have this book.

The "decoder" transforms opcodes into signals for driving the various execution units (alu, branch, ...) and selecting the registers.

Tranditional RISC CPUs have relatively simple encodings where there are almost fixed fields for selecting the operations. This is far less true in CPUs like x86.

(Example, some MIPS instructions : http://www-inst.eecs.berkeley.edu/~cs150/sp11/checkpoint_1/images/MIPS150ISA.png)

Then, for the arithmetic/logic part, there is not separate adder, subtractor, and, or... blocks selected with multiplexers. Many operation are combined in multipurpose circuits, for example adder/subtractor/negate.


I don't have the Charles Petzold 'Code' book.

Reading your question, it doesn't seem tht the book has communicated the basic concept of an Arithmetic Logic Unit (aka ALU).

If you search the web for Arithmetic Logic Unit, or ALU, you will find many usable explanations, for example wikipedia Arithmetic_logic_unit

All Central Processing Units (CPUs) have one or more ALU's. The ALU operates on multi-bit binary values, for example 8-bit (bytes), 16 or 32 bit words. The ALU implements the 'data processing' operations like add, subtract, negate, etc., using the multi-bit values to represent binary numbers. The ALU implements bit-wise Boolean operations like and, or, not (bit-complement), using the multi-bit values as groups of bits. The ALU can shift the multi-bit value left of right (usually through some internal bit); shift is important for multiply and divide operations, among other uses. The ALU is also used to test multi-bit values for zero or negative values, or compare two multi-bit values for equality, less than, greater than etc.

The CPU decodes the instructions to select the appropriate function of the ALU. You might think of his as dynamic configuration of the ALUs capabilities. The ALU is capable of applying a range of Boolean logic combinations to its input data (operands). The ALU operates on one or two multi-bit values, plus a few internal bits of state representing previous operations (these bits are held in the status register. The CPU can use those state bits, for example to control conditional branching.

The CPUs decoder is using some of the bits of the instruction to create a set of signals (the ALU's control signal 'bit pattern') which will cause the ALU to apply the right logic function to its data (operands).

You might look at a datasheet for Texas Instruments 4-bit wide SN74181 ALU for the to see how this works. That is a very old chip, designed to be used to make a CPU, before the advent of microprocessors. For example, Table 1 shows all of the functions the ALU can apply to its operands, along with its control signals.


Well, I DO have the book :)

If you take a look at the instructions covered in Chapter 17, and list out the opcodes in binary form, they go like this:

I I I I   I I I I
7 6 5 4   3 2 1 0

0 0 0 1   0 0 0 0  LOD         !I7 !I6 !I5  I4  !I3 !I2 !I1 !I0
0 0 0 1   0 0 0 1  STO         !I7 !I6 !I5  I4  !I3 !I2 !I1  I0

0 0 1 0   0 0 0 0  ADD         !I7 !I6  I5 !I4  !I3 !I2 !I1 !I0
0 0 1 0   0 0 0 1  SUB         !I7 !I6  I5 !I4  !I3 !I2 !I1  I0
0 0 1 0   0 0 1 0  ADC         !I7 !I6  I5 !I4  !I3 !I2  I1 !I0
0 0 1 0   0 0 1 1  SBB         !I7 !I6  I5 !I4  !I3 !I2  I1  I0

0 0 1 0   0 1 x x  future ALU  !I7 !I6  I5 !I4  !I3  I2   x   x
0 0 1 0   1 0 x x  future ALU  !I7 !I6  I5 !I4   I3 !I2   x   x
0 0 1 0   1 1 x x  future ALU  !I7 !I6  I5 !I4   I3  I2   x   x

0 0 1 1   0 0 0 0  JMP         !I7 !I6  I5  I4  !I3 !I2 !I1 !I0
0 0 1 1   0 0 0 1  JZ          !I7 !I6  I5  I4  !I3 !I2 !I1  I0
0 0 1 1   0 0 1 0  JC          !I7 !I6  I5  I4  !I3 !I2  I1 !I0  
0 0 1 1   0 0 1 1  JNZ         !I7 !I6  I5  I4  !I3 !I2  I1  I0

1 1 1 1   1 1 1 1  HLT          I7  I6  I5  I4   I3  I2  I1  I0

In the instruction byte, the leftmost 4 bits (I7 thru I4) determine the main instruction type (1xh for load/store, 2xh for add/subtract, 3xh for jumps, and FFh for halt) and the rightmost four bits (I3 thru I0) serve as modifiers. (Ix stands for bit x of the instruction byte.) I'm using the books convention of a 'h' suffix for hex, rather than a 0x prefix as used in C and other languages.

In the diagram in the book, the output of the 8-bit latches (labeled "Code") for the high 8 bits of the 24-bit instruction should have been shown going into a decoder circuit. And you're right, in simplest form its just a bunch of AND gates and inverters (so both senses of each bit are available).

As shown on the right for each opcode, the instruction byte can be decoded using 8-input AND's, along with inverters as needed. !I7 is the same as \$\small \overline{\text{I7}}\$, but I found I can't use overbars in tables like this.

But if you had a line going into the ALU that said do an add or subtract, you would probably want to decode just the leftmost 6 bits:

0 0 1 0   0 0 x 0  any ADD/SUB !I7 !I6  I5 !I4  !I3 !I2   x  x

and use that to signal the ALU to do add/subtract operation; then run I0 into the ALU lead that tells it whether to do an add (0) or subtract (1); and run I1 into the ALU lead that says whether to use carry/borrow (1) or not (0).

Likewise, you would also partially decode the left 6 bits for a jump:

0 0 1 1   0 0 x x  any JMP     !I7 !I6  I5  I4  !I3 !I2   x   x

and then let the rightmost two bits (I0 and I1) determine the type using a 2 to 4 decoder. So you don't need to always decode all 8 bits of the instruction byte separately for each opcode.

Notice I decoded bits I3 and I2 as 0 for the add and subtract opcodes, even though they're not necessary at this time; this leaves 12 more possible opcodes (total of 16) for the instruction group 2xh, marked "future" in the table above. These would likely be used for additional operations on the ALU such as logic operations (AND, OR, XOR, NOT) and shifts. The same could be done for the jump group (3xh).

If you look at another of my answers here, where I discuss the circuitry for a 1-bit slice of the ALU for the 8085, you'll see that there are no specific lines for operations such as AND, OR, XOR or even ADD and SUB inside the ALU. Instead, there are a number of special control lines with names like select_op1 and force_ncarry_1 that determine how the ALU processes the inputs and produces a result. Various combinations of these special lines are enabled as needed by each opcode being executed (see the table in the linked answer).

Another way of extending the class 2xh instructions is to add an immediate mode. Petzold doesn't go into this in his book, but an immediate addressing mode simply means to use the value of the operand from the instruction directly (in this case, the lower 16-bits), instead of using the operand as a 16-bit address into RAM.

Comparing the two:

ADD A, [4000h]         adds the contents of memory location 4000h to the accumulator A

ADD A, #4000h          adds the value 4000h to the accumulator A

To handle this second mode of addressing, we can (as an example) use the I3 bit to indiocate immediate addressing: I3=0, memory address, I3=1, immediate addressing. So now the ALU instructions look like this:

0 0 1 0   0 0 0 0  ADD         !I7 !I6  I5 !I4  !I3 !I2 !I1 !I0
0 0 1 0   0 0 0 1  SUB         !I7 !I6  I5 !I4  !I3 !I2 !I1  I0
0 0 1 0   0 0 1 0  ADC         !I7 !I6  I5 !I4  !I3 !I2  I1 !I0
0 0 1 0   0 0 1 1  SBB         !I7 !I6  I5 !I4  !I3 !I2  I1  I0

0 0 1 0   0 1 x x  future ALU  !I7 !I6  I5 !I4  !I3  I2   x   x

0 0 1 0   1 0 0 0  ADD#        !I7 !I6  I5 !I4  !I3 !I2 !I1 !I0
0 0 1 0   1 0 0 1  SUB#        !I7 !I6  I5 !I4  !I3 !I2 !I1  I0
0 0 1 0   1 0 1 0  ADC#        !I7 !I6  I5 !I4  !I3 !I2  I1 !I0
0 0 1 0   1 0 1 1  SBB#        !I7 !I6  I5 !I4  !I3 !I2  I1  I0

0 0 1 0   1 1 x x  future ALU# !I7 !I6  I5 !I4   I3  I2   x   x

I have marked the new instructions with a # after the mnemonic.

This reduces the maximum number of unique ALU opcodes in the 2xh group from 16 down to 8, but this still leaves room for AND, OR and XOR, including their immediate counterparts. NOT (which only works on the accumulator) has no operands and thus no immediate version.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.