I was reading something about single-cycle and multi-cycle processors and I have (it seems to be) banal question: how does multi-cycle (that doesn't have pararell pipeline) processor save its state so next instruction isn't executed until currently executed one isn't done? Is it blocking start of first phase somehow?
2 Answers
Indeed, the start of the next instruction is blocked.
The usual way to model multi-state systems is using "finite state machines" - it is a HW logic which switches between numerous states based on:
- The current state
- The inputs
The outputs of a module controlled by FSM is also defined by the FSM's state and the inputs.
What happens in our case? New instruction may only be fetched in the initial state - lets call it IDLE. Once the instruction was fetched, the FSM starts to switch between operational states (for example: IDLE->DECODE->EXECUTE->WRITE-BACK->IDLE). When in a state which is not IDLE, the logic is forbidden from fetching new instructions. Therefore, the new instruction will start to execute only after the previous one ended.
Different processors differ in the designs of their state machines, but in many cases every instruction starts in some state zero (opcode fetch), and the progression of states is set in motion by the opcode which is fetched and any given opcode will always perform the same sequence of operations except that there may be provisions to early-exit instructions in certain cases such as "branch not taken".
On the 6502, state zero, in addition to fetching an opcode, may perform the last steps of the previous instruction if it entails nothing more than computing an ALU result and storing it to a register. The 6502 does not allow deviation from the step sequence for any opcode other than via early exit, but an instruction like "ADC #$1234,X" behaves as follows:
0 -- Finish previous instruction and fetch opcode
1 -- Fetch first byte following opcode [done unconditionally]
2 -- Fetch second byte following opcode into upper-address register
while adding just-fetched byte to X
3 -- Concatenate upper-address register with ALU result and read mem into data register
while feeding upper-address register and 1 into ALU.
If step 2 didn't generate carry, exit.
4 -- Load ALU result into upper half of address register and read mem into data register.
(next cycle)
0 -- Feed newly-fetched value into ALU along with accumulator; store ALU into acc.
It's interesting to note that instructions that read a value from an indexed memory location, operate on it, and put the result in a register can early-exit if there is no carry out of the lower 8 bits of the address, but instructions which need to do more with the fetched result cannot skip any steps. For INC $1234,X
0 -- Finish previous instruction and fetch opcode
1 -- Fetch first byte following opcode [done unconditionally]
2 -- Fetch second byte following opcode into upper-address register
while adding just-fetched byte to X
3 -- Concatenate upper-address register with ALU result and read mem into data register
while feeding upper-address register and 1 into ALU.
4 -- If carry, load ALU result into upper half of address register (otherwise leave alone)
...and read mem into data register.
5 -- Store data register to memory
While feeding data register and 1 into ALU; latch ALU to data register
6 -- Store data register to memory
Note that if the address computation in step 2 doesn't generate a carry, it would be possible to skip from step 4, but the instruction-sequencing logic has no concept of how to any skip part of an instruction other than the tail, and steps 5 and 6 are still needed.
Curiously, although the largest number of cycles required for any documented 6502 opcode is seven (illustrated above), a vintage 6502 that encounters certain undocumented opcodes will execute them in logical fashion as eight-cycle opcodes. The CMP instruction 110xxx01 can accept any of eight addressing modes, two of which take a cycle longer than the indexed absolute addressing mode shown above, but the instruction doesn't have do do anything after computing the address. The documented DEC (110xxx10) only accepts five addressing modes (it does not accept the more complicated ones), but an opcode byte which "ovelaps" those (110xxx11) will combine the effects of DEC and CMP, and will support all the addressing modes that CMP does, even those which end up taking a total of eight cycles. I wonder why the "normal" read-modify-write opcodes can't use those addressing modes, since the circuitry obviously exists to make such addressing modes work correctly with read-modify-write instructions.