
- •Contents
- •Preface
- •List of Figures
- •List of Tables
- •Acknowledgments
- •1.1.2 The Instruction
- •1 Problems
- •2 Programming Microcomputers
- •3 Bus Hardware and Signals
- •3.3 Conclusions
- •3 Problems
- •5 Interrupts and Alternatives
- •5.4.1 Direct Memory Access
- •7.1.3 Other Transducers
- •7.2 Basic Analog Processing Components
- •7.2.1 Transistors and Silicon Controlled Rectifiers
- •8 Counters and Timers
- •9. Communications Systems
- •9.3.3 The ACIA
- •9.4.4 The Small Computer System Interface (SCSI)
- •9.5 Conclusions
- •10.1.2 A 6812 SPI Display
6 |
Chapter 1 Microcomputer Architecture |
Before going on, we point out a feature of the von Neumann computer that is easy to overlook, but is at once von Neumann's greatest contribution to computer architecture and yet a major problem in computing. Because instructions and data both are stored in the primary memory, there is no way to distinguish one from the other except by which hand (program counter or effective address) is used to get the data. We can conveniently use memory not needed to store instructions - if few are to be stored - to store more data, and vice versa. It is possible to modify an instruction as if it were data, just before it is fetched, although a good computer scientist would shudder at the thought. However, through an error (bug) in the program, it is possible to start fetching data words as if they were instructions, which produces strange results fast.
A program sequence is a sequence of instructions fetched from consecutive locations one after another. To increment the word at location $100, we can load it into the accumulator using the LDAA instruction, increment it there using the INCA instruction, and then put it back using the STAA instruction. (A better way will be shown in the next section, but we do it in three instructions here to illustrate a point.) This program sequence is written in consecutive lines as follows
LDAA ALPHA
INCA
STAA ALPHA
Unless something is done to change the left hand (program counter), a sequence of words in contiguously numbered boxes will be fetched and executed as a program sequence. For example, a sequence of load and store instructions can be fetched and executed to copy a collection of words from one place in the mailbox to another place. However, when the controller reads the instruction, it may direct the left hand to move to a new location (load a new number in the program counter). Such an instruction is called a jump, which is an example of a control instruction. Such instructions will be discussed further in §1.2.3, where concrete examples using the 6812 instruction set are described. To facilitate the memory access functions, the effective address can be computed in a number of ways, called addressing modes. The 6812 addressing modes will be explained in §1.2.1.
1.1.2 The Instruction
In this section the concept of an instruction is described from different points of view. The instruction is discussed first with respect to the cycle of fetching, decoding, and sequencing of microinstructions. Then the instruction is discussed in relation to hardware-software trade-offs. Some concepts used in choosing the best instruction set are also discussed.
The controller fetches a word or a couple of words from primary memory and sends commands to all the modules to execute the instruction. An instruction, then, is essentially a complex command carried out under the direction of a single word or a couple of words fetched as an inseparable group from memory.



















1.2 The 6812 Instruction Set
The displacement used in the branch instruction, the last instruction in the program, is shown as xx. It can be determined as follows. When the branch is executed, the program counter has the value $20D, and we want to jump back to location $202. The difference, $20D - $202, is $OB, so the displacement should be -$OB. A safe way to calculate the displacement is to convert to binary, negate, and then convert to hexadecimal. $OB is 00001011, so the 2's complement negative is 11110101. In hexadecimal, this is SF5. That is not hard to see, but binary arithmetic gets rather tedious. A faster way takes the 16's complement of the hexadecimal number. Just subtract each digit from $F (15), digit by digit, then add 1 to the whole thing. -$OB is then ($F - 0),($F - B) + 1 or $F4 + 1, which is $F5. That's pretty easy, isn't it!
A branch instruction may direct the person in the analogy to branch, for instance, only if the number in the adder is positive. If that number is not positive, the next instruction is fetched and executed because the left hand is not moved. This is a conditional branch. The 6812 has only conditional branch instructions, rather than conditional jumps or conditional subroutine calls and conditional subroutine returns (as does the 8080). The conditional branch tests one or more condition codes, then branches to another location specified by the displacement if the condition is true, using relative addressing. For each conditional branch, which uses an 8-bit offset, there is also a conditional long branch, which uses a 16-bit offset. The instruction
BCC L
branches to location L if the carry bit is cleared, otherwise the instruction does nothing. A set of simple branches test any one of the condition codes, branching if the bit is
set or clear. For example, BCC L will branch to location L if the carry bit is clear, while BCS L will branch there if the carry bit is set. Other sets test combinations of condition codes (the Z, N, and V bits) that indicate 2's complement inequalities. The last set tests combinations of the Z and C bits that indicate unsigned number inequalities. Column 2 of Table 1.6 tests each condition code separately. The BMIand BPLinstructions check the sign bit and should be used after LDAA, STAA, and TST (or equivalent) to check the sign of a 2's complement number that was moved. The BCC and BCSinstructions test the carry bit, which indicates an overflow after adding unsigned numbers, or the bit shifted out after a shift instruction. The BVS and BVCinstruction set tests the V condition code, set if an overflow occurs on adding 2's complement numbers. The Z bit is also tested easily, but since we often compare two numbers to set the Z bit if the two numbers are equal, the instruction is called BEQand the complementary instruction is BNE. BEQ and BNE are also used in the 2's complement and unsigned number branches discussed next.
A 2's complement overflow will occur if the two numbers being added have the same sign and the result has a different sign. Have you ever added two positive numbers and gotten a negative number? That's an overflow. Or if you add two negative numbers and get a positive number, that too is an overflow. But if you add two numbers of different signs, an overflow cannot occur. In using these condition codes in branch instructions, we must be careful to test the carry bit, not the overflow bit, after an unsigned binary add, since the carry bit is set if an unsigned overflow occurs; and we must remember to test the overflow bit V after a 2's complement add, because it is set if the result is erroneous as a 2's complement number. The branches listed in the middle





30 |
Chapter 1 |
Microcomputer Architecture |
I/O registers |
in memory and locations in other programs |
to jump or branch to. In an |
EQU'S expression, the asterisk (*) is often used to indicate the current location counter. The ORG, DS . B, and EQUdirectives determine where areas of data are to be put but
do not fill those areas with initial values. The following directives not only provide room for variables but also initialize them with constants when the program is loaded.
The define constant (byte) directive DC. B will put a byte in memory for each operand of the directive. The value of an operand is put into memory when the location counter specifies the address and the location counter is incremented for each operand. DC. B 10 will put $0A in a word in memory. The directive
L: DC.B 1 , 2,3
will initialize 3 bytes in memory to be
01
02
03
and will tell the assembler that L is the symbolic address of the first word, whose initial value is $01. The location counter is incremented three times. ASCII characters can be inserted as DC.B arguments by putting them between matching quotes. Define constant (word) DC.Wwill initialize two consecutive 16-bit words for each argument. The value of each operand is put in two consecutive words and the location counter is incremented by two for each operand. For example, the directive
L: DC.W 1 , 2,3
will initialize six consecutive bytes in memory, as follows
00
01
00
02
00
03
and will tell the assembler that L is the address of the first word in this area, whose value is $00. The location counter is incremented six times. The DC .Wdirective is especially useful in putting addresses in memory so that they can be used in indirect addressing or picked up into an index register. If ALPHA is $100 because an EQUdirective set it to that value or because it is a label of an instruction or directive like DC. B that begins at location $100, then the directive
DC.W ALPHA
will generate the following 2 bytes in memory:
01
00






