68K inner workings
Posted: Fri Jan 04, 2019 8:46 pm
Hi, I just wanted to share some of my notes I made a while back. This is based on Galibert's schematic, so in these notes the chip is assumed to be oriented such that the A13 pin is on the upper left. A lot of this is probably well known already, but I thought it'd be nice to have it all in one place.
On the left side of the chip we find the registers and their associated data processing circuitry. It is divided into three sections that can be connected together, each containing two separate lanes for transferring data. This means that the chip can execute up to 6 general purpose data transfers per cycle.
In addition to the architecturally visible registers, there are seven general purpose registers for use by the microcode, which I have given the names A through G.
- Register A is a 32-bit register that can be used as a memory address, and can be copied into PC. It can be loaded with the sum of two registers, or one register plus or minus a constant, which can be 4, 2 or the size specified by the current instruction.
- Register B is a 32-bit register that can retrieve the last accessed memory address (LAST).
- Register C is a 16-bit register that can retrieve an ALU result and be written to memory.
- Register D is a 16-bit register that can be loaded from memory.
- Register E is a 16-bit register that can be the second operand of an ALU operation.
- Register F is a 16-bit register that can be loaded with the immediate field of an instruction (IMM), the requested interrupt level (IPL), the status register (SR), the current instruction (IR), the current function code (FC), or an exception vector (Vec). It can also be copied into the status register (SR or CCR).
- Register G is a 16-bit shift register.
- There is also a 32-bit register that holds an immediate value.
From the top, we have:
(High section)
- high D0-D7, A0-A6, USP, SSP, immediate register, memory address register, A, PC.
- high adder
- high B
(Low section)
- low adder
- low A, PC, memory address register
- MOVEM register list (List)
- next bit in register list
- F
- low immediate register, SSP, USP, A6-A0
(Data section)
- low B, D7-D0
- Bit selection register (BIT#)
- Selected bit (BIT)
- D
- Output register
- G, C
- ALU flag output: carry 16, overflow 16, sign, carry 8, overflow 8, carry 4
- ALU
- ALU operands
- E
The vertical section in the center of the chip takes the current instruction as an input, and determines such things as instruction operands and exception vectors. This also extracts fields such as shift counts or the target of a branch instruction. The slightly wider section at the bottom selects which ALU functions to perform. Below this is the ALU control logic, with the CCR at the upper left.
At the bottom of the chip is the instruction decoder, which outputs a 10-bit microcode starting address. The left side determines whether an instruction is word or long sized. Instructions can consist of up to three stages, so above this is another instruction decoder. The left side recognizes invalid instructions, and the right side outputs addresses for the second and third stage of the instruction.
Above the invalid instructions we have the condition code evaluator. This produces two bits that form part of the next microcode address for a branching microcode instruction.
The large ROM on the right side of the chip contains the microcode. It is divided into two sections, each with their own address decoding. The left section produces a 68-bit output which specifies the operations to perform. The right section produces a 17-bit output which contains the next microcode address and a few other control bits. Some addresses may map to the same column in one or both sections, thus allowing operation words to be reused. You'll see some redundant operations throughout the code because of this.
To the right of the microcode, at the very top, is the 8-bit bus state machine. At the bottom is a circuit that determines which exception to raise, and the microcode address to jump to, based on which conditions are present at certain points during execution. At the very bottom right is the logic that handles the bus during 16-bit operation. I haven't deciphered how this one works yet.
On the VPA pin you'll notice a funny little circuit. Somehow, using the VPA pin, perhaps with a voltage outside the normal operational range, you can activate a test mode which outputs the 68-bit operation word on the address pins. Presumably, the instruction is input with the data pins, while selecting one of the three stages with IPL0 and DTACK. BR and BGACK control which branch to take for a branching instruction. IPL1 and IPL2 select which part of the operation word to output.
Let's look at some microcode. In the following, each step will appear on one line, with a list of operations performed during the step.
"x<=y" indicates that the previous value of y is copied into x, with sign extension where appropriate. "x.H" and "x.L" indicate the high or low part of a register. "x:y" indicates the 32-bit value formed by concatenating x with y. "[s:x]" indicates memory location x in address space s, where s is either DATA, PROGRAM or ACK. If an address is suffixed with ".B", it is accessed in byte mode if the current instruction is a byte instruction. Multiple registers may be given as a transfer destination, separated with commas. If an address appears alone, the address is prefetched. Math1, Math2 and Math3 invokes the ALU to perform an operation which differs depending on the instruction. Am/Dm/Rm refer to the register selected by the register field of an instruction, or the immediate register in the case of addq, subq, dbcc, trapcc, scc or an immediate ALU instruction. An/Dn/Rn refer to the register in the EA field, or the immediate register if an immediate or absolute addressing mode is used. Xn refers to the index register of an indexed addressing mode.
Other words that may appear on a line are:
FETCH - load next instruction word from prefetch buffer
PREFETCH[x] - prefetch instruction word from x
UPPER, LOWER - transfer upper or lower byte only
NEXT - get the next register of a MOVEM instruction
INT - load IPL, set S, clear T, no trace
FAULT - set S, clear T, no trace
TRAP - set S, clear T
RESET - assert the reset signal
HALT - assert the halt signal
CHECK - check for exception conditions
NEXTI - check interrupts, trace, illegal instruction etc.
End - end the current instruction
Stage2 - go to stage 2
Stage3 - go to stage 3
I'll start with the code that deals with various exceptional conditons.
As you can see, at the start of an instruction, the PC register points two bytes ahead of the current instruction, and the A register points four bytes ahead. The second word is in the prefetch queue and is also loaded into the D register, and F is loaded with the immediate field of the current instruction, if any. It is noteworthy that the reset routine fetches the initial SSP and PC from program memory rather than data memory like the other vectors. There is also an undocumented behaviour that occurs if a bus error occurs during reset processing, where the HALT signal will continuously toggle on and off.
Here are some examples of actual instructions.
I have made a program which dumps all the instructions, but the output for complex instructions with a lot of branching needs to be polished a bit. More is to come. In the meantime, if someone needs to know how something works, feel free to ask.
On the left side of the chip we find the registers and their associated data processing circuitry. It is divided into three sections that can be connected together, each containing two separate lanes for transferring data. This means that the chip can execute up to 6 general purpose data transfers per cycle.
In addition to the architecturally visible registers, there are seven general purpose registers for use by the microcode, which I have given the names A through G.
- Register A is a 32-bit register that can be used as a memory address, and can be copied into PC. It can be loaded with the sum of two registers, or one register plus or minus a constant, which can be 4, 2 or the size specified by the current instruction.
- Register B is a 32-bit register that can retrieve the last accessed memory address (LAST).
- Register C is a 16-bit register that can retrieve an ALU result and be written to memory.
- Register D is a 16-bit register that can be loaded from memory.
- Register E is a 16-bit register that can be the second operand of an ALU operation.
- Register F is a 16-bit register that can be loaded with the immediate field of an instruction (IMM), the requested interrupt level (IPL), the status register (SR), the current instruction (IR), the current function code (FC), or an exception vector (Vec). It can also be copied into the status register (SR or CCR).
- Register G is a 16-bit shift register.
- There is also a 32-bit register that holds an immediate value.
From the top, we have:
(High section)
- high D0-D7, A0-A6, USP, SSP, immediate register, memory address register, A, PC.
- high adder
- high B
(Low section)
- low adder
- low A, PC, memory address register
- MOVEM register list (List)
- next bit in register list
- F
- low immediate register, SSP, USP, A6-A0
(Data section)
- low B, D7-D0
- Bit selection register (BIT#)
- Selected bit (BIT)
- D
- Output register
- G, C
- ALU flag output: carry 16, overflow 16, sign, carry 8, overflow 8, carry 4
- ALU
- ALU operands
- E
The vertical section in the center of the chip takes the current instruction as an input, and determines such things as instruction operands and exception vectors. This also extracts fields such as shift counts or the target of a branch instruction. The slightly wider section at the bottom selects which ALU functions to perform. Below this is the ALU control logic, with the CCR at the upper left.
At the bottom of the chip is the instruction decoder, which outputs a 10-bit microcode starting address. The left side determines whether an instruction is word or long sized. Instructions can consist of up to three stages, so above this is another instruction decoder. The left side recognizes invalid instructions, and the right side outputs addresses for the second and third stage of the instruction.
Above the invalid instructions we have the condition code evaluator. This produces two bits that form part of the next microcode address for a branching microcode instruction.
The large ROM on the right side of the chip contains the microcode. It is divided into two sections, each with their own address decoding. The left section produces a 68-bit output which specifies the operations to perform. The right section produces a 17-bit output which contains the next microcode address and a few other control bits. Some addresses may map to the same column in one or both sections, thus allowing operation words to be reused. You'll see some redundant operations throughout the code because of this.
To the right of the microcode, at the very top, is the 8-bit bus state machine. At the bottom is a circuit that determines which exception to raise, and the microcode address to jump to, based on which conditions are present at certain points during execution. At the very bottom right is the logic that handles the bus during 16-bit operation. I haven't deciphered how this one works yet.
On the VPA pin you'll notice a funny little circuit. Somehow, using the VPA pin, perhaps with a voltage outside the normal operational range, you can activate a test mode which outputs the 68-bit operation word on the address pins. Presumably, the instruction is input with the data pins, while selecting one of the three stages with IPL0 and DTACK. BR and BGACK control which branch to take for a branching instruction. IPL1 and IPL2 select which part of the operation word to output.
Let's look at some microcode. In the following, each step will appear on one line, with a list of operations performed during the step.
"x<=y" indicates that the previous value of y is copied into x, with sign extension where appropriate. "x.H" and "x.L" indicate the high or low part of a register. "x:y" indicates the 32-bit value formed by concatenating x with y. "[s:x]" indicates memory location x in address space s, where s is either DATA, PROGRAM or ACK. If an address is suffixed with ".B", it is accessed in byte mode if the current instruction is a byte instruction. Multiple registers may be given as a transfer destination, separated with commas. If an address appears alone, the address is prefetched. Math1, Math2 and Math3 invokes the ALU to perform an operation which differs depending on the instruction. Am/Dm/Rm refer to the register selected by the register field of an instruction, or the immediate register in the case of addq, subq, dbcc, trapcc, scc or an immediate ALU instruction. An/Dn/Rn refer to the register in the EA field, or the immediate register if an immediate or absolute addressing mode is used. Xn refers to the index register of an indexed addressing mode.
Other words that may appear on a line are:
FETCH - load next instruction word from prefetch buffer
PREFETCH[x] - prefetch instruction word from x
UPPER, LOWER - transfer upper or lower byte only
NEXT - get the next register of a MOVEM instruction
INT - load IPL, set S, clear T, no trace
FAULT - set S, clear T, no trace
TRAP - set S, clear T
RESET - assert the reset signal
HALT - assert the halt signal
CHECK - check for exception conditions
NEXTI - check interrupts, trace, illegal instruction etc.
End - end the current instruction
Stage2 - go to stage 2
Stage3 - go to stage 3
I'll start with the code that deals with various exceptional conditons.
Code: Select all
Exceptions:
(1) F<=SR A<=PC-2
(2) PC<=A C<=A.L FAULT A<=SSP-2
(3) C<=F [DATA:A]<=C A<=A-4
(4) SSP<=A C<=PC.H [DATA:A]<=C F<=Vec A<=A+2
(5) B<=F C<=E [DATA:A]<=C A<=A-4
(6) PC<=B D<=[DATA:B] A<=B+2
(7) B.H<=D D<=[DATA:A] A<=A+2
(8) PREFETCH[PROGRAM:B.H:D] A<=B.H:D+2
(9)
(10) PC<=A A<=A+2 CHECK [PROGRAM:A]
(11) D<=[LAST] PREFETCH[LAST] FETCH F<=IMM
End
Interrupt:
(1) F<=SR A<=PC-2
(2) PC<=A E<=F C<=A.L INT
(3) F<=IPL A<=SSP-2
(4) B<=F C<=E [DATA:A]<=C A<=A-4
(5) PREFETCH[ACK:B]
(6) CHECK
(7) FETCH F<=IMM
(8) SSP<=A C<=PC.H [DATA:A]<=C F<=Vec A<=A+2
(9) B<=F C<=E [DATA:A]<=C A<=A-4
(10) PC<=B D<=[DATA:B] A<=B+2
(11) B.H<=D D<=[DATA:A] A<=A+2
(12) PREFETCH[PROGRAM:B.H:D] A<=B.H:D+2
(13)
(14) PC<=A A<=A+2 CHECK [PROGRAM:A]
(15) D<=[LAST] PREFETCH[LAST] FETCH F<=IMM
End
Bus error:
(1) B<=LAST F<=SR A<=PC
(2) PC<=A C<=A.L FAULT A<=SSP-2
(3) C<=F [DATA:A]<=C A<=A-4
(4) C<=PC.H [DATA:A]<=C F<=IR A<=A+2
(5) C<=F [DATA:A]<=C A<=A-4
(6) PC<=B C<=B.L [DATA:A]<=C FETCH F<=FC A<=A-2
(7) C<=F [DATA:A]<=C A<=A-4
(8) SSP<=A C<=PC.H [DATA:A]<=C F<=Vec A<=A+2
(9) B<=F C<=E [DATA:A]<=C A<=A-4
(10) PC<=B D<=[DATA:B] A<=B+2
(11) B.H<=D D<=[DATA:A] A<=A+2
(12) PREFETCH[PROGRAM:B.H:D] A<=B.H:D+2
(13)
(14) PC<=A A<=A+2 CHECK [PROGRAM:A]
(15) D<=[LAST] PREFETCH[LAST] FETCH F<=IMM
End
Reset:
(1)
(2) FETCH F<=IMM
(3) F<=Vec
(4) INT A<=F
(5) SSP<=D D<=[PROGRAM:A] A<=A+2
(6) SSP<=D D<=[PROGRAM:A] A<=A+2
(7) SSP<=D D<=[PROGRAM:A] FAULT A<=A+2
(8) B.H<=D D<=[PROGRAM:A] A<=A+2
(9) PREFETCH[PROGRAM:B.H:D] A<=B.H:D+2
(10)
(11) PC<=A A<=A+2 CHECK [PROGRAM:A]
(12) D<=[LAST] PREFETCH[LAST] FETCH F<=IMM
End
Double fault:
(1) HALT
Go to (1)
Reset+fault:
(1) HALT
(2) F<=SR A<=PC-2
Go to (1)
Here are some examples of actual instructions.
Code: Select all
bclr Dm,Dn and the second phase of bclr #imm,Dn:
(1) B<=Rm BIT#<=Rm.L PC<=A A<=Rn CHECK [PROGRAM:A]
(2) E<=Rn.L C<=Math1(BIT,Rn.L) D<=[LAST] PREFETCH[LAST] A<=PC+2 NEXTI
High word:
(3) E<=Rn.H C<=Math1(BIT,Rn.H)
(4) C<=Math3(BIT,C)
(5) Rn.H<=C C<=BIT&E CCR<=Flags.L FETCH F<=IMM
End
Low word:
(6) C<=Math3(BIT,C)
(7) Rn.L<=C C<=BIT&E CCR<=Flags.L FETCH F<=IMM
End
Same for btst:
(1) B<=Rm BIT#<=Rm.L PC<=A A<=Rn CHECK [PROGRAM:A]
(2) E<=Rn.L C<=Rn.L D<=[LAST] PREFETCH[LAST] A<=PC+2 NEXTI
High word:
(3) C<=BIT&Rn.H CCR<=Flags.L FETCH F<=IMM
End
Low word:
(4) Rn.L<=C C<=BIT&E CCR<=Flags.L FETCH F<=IMM
End
scc Dn:
(1) PC<=A C<=0 NEXTI [PROGRAM:A]
Condition false:
(2) Rn.L<=C D<=[LAST] PREFETCH[LAST] FETCH F<=IMM A<=PC+2 W
End
Condition true:
(3) C<=Math1(-1,C) D<=[LAST] PREFETCH[LAST] A<=B
(4) Dn.L<=C FETCH F<=IMM A<=PC+2 W
End
jsr.l:
(1) B.H<=D D<=[PROGRAM:A] A<=A+2
(2) B.L<=D PREFETCH[PROGRAM:B.H:D] PC<=A A<=Am-4
(3) [DATA:A]<=PC.H Rm<=A A<=A+2
(4) [DATA:A]<=PC.L A<=B+2 CHECK
(5) PC<=A A<=A+2 CHECK [PROGRAM:A]
(6) D<=[LAST] PREFETCH[LAST] FETCH F<=IMM
End