Instruction Sequences

The architecture of the SC-CPU uses distributed microcoded sequencers to execute the machine instructions. Each subsystem in the CPU has a group of microsequencers that control the hardware in that subsystem. Each microsequencer controls one electric signal, which may be a binary, or hex or a unique control. This group of microsequencers is the sequencer for that subsystem.

All the micro sequencers in the subsystem are tied together to a fast counter that provides common timing for that sequencer. Every sequencer also includes two microsequencers not explicitly used for controlling the hardware. The first is the local "state address" generator which does the fast counting for the sequencer and the second is the 'BUSY' signal generator, used to indicate when the subsystem is executing a command. See the sequencer details article for more information.

Each (machine) instruction is decoded by each subsystem that needs to do something in response to it. The decoded instructions are called "commands" in this system, to distinguish them from the original "instruction". Commands input to the sequencers are executed according to the microprogramming in the microsequencers. When a new command is entered, it initiates the fast-step counter which counts to a certain number for each command then goes into a wait state. As each step is counted, the other microsequencers turn on or off etc all the signals to the hardware under its control, according to the timing in each microsequencer. It is the programming of all these microsequencers that is the substance of this article.

Intro
The entries below are grouped by subsystem/sequencer and the instructions it executes. The basic functional blocks include the Data Stack and ALU (data processing), the Return Stack and Program Controller (program control), the Main Memory and addressable registers (data movement). System I/O includes the human interface and is usually included in data movement as it often uses dedicated registers or even instructions. It is YTBD if this system will keep with this philosophy or consider I\O as a separate subsystem.

The subsystems descriptions below first list all the control signals used by the sequencer. This is followed with details of each instruction processed by the sequencer. Each instruction entry includes a brief description of its function in the title line. The sequence is detailed step-by-step in 'Techish' below it, each clock 'tic' represented by a single line. This is followed by the actual 'program' for each hardware control signal. These may be used to program the Memory Banks that make up the microsequencers.

The program 'images' become a single line in the data inside a Memory Bank and represents the execution of a single command. All the commands in each subsystem that affect a single hardware signal are compiled into a single microsequencer.

??? Also note that sequences begin in state 'F' instead of state '0' as detailed here. This may not continue to be the case...

Program Counter
The PC is the heart of the CPU. It fetches and holds the new instruction then notifies the rest of the system it is ready. The PC waits for the OK signal from the processor subsystems and then presents the next instruction to be executed.

The compnents in the PC which the sequencer controls are the return stack, the +1 counter and the program memory control. It may also interface with the data stack for transferring to/from the stack. (?)

Control Signals

 * Seq_Step count
 * BUSY rtz


 * GO_PC trigger
 * HALT_PC trigger


 * IP_In Control (1-4)
 * IP Latch
 * PRAM Control (read) Enable
 * IR Latch


 * IP+1>TOR Enable
 * R-Stack RAM Control
 * R-Stack Pointer Control

??? IP>TOS, TOS, IP ???
 * TOR>TOS Enable
 * TOS>TOR Enable

Instructions
The basic fetch cycle increments the value in the IP, latches it into the IP and sends it to the PRAM along with the signal to read. Then it waits for the instruction from that location, latches that into the IR then notifies the system that it is ready. It then waits for the 'done' signal from the decoder, which starts this process again. Latching the IP starts the process to compute IP+1 which is complete before the PRAM is ready.

There are several ways the next instruction adddress (pointer) can be generated in this system. The 'ready' signal is latched from the IR_latch. (The latch is reset by the 'done' signal from the execution circuitry. This reset also initiates the STEP process.)

The following ROM images are 0-based NOT F-based!!! STEP  [1]   (normal execution sequence) Show
 * 1) Set IP_In to '1' (IP+1)
 * (wait 1 tic)
 * 1) Enable IP_Latch
 * 2) Clear IP_In, disable IP_Latch (wait 1 tic)
 * 3) Send READ to PRAM_Ctl
 * 4) wait 2 more tics, holding READ
 * 5) wait 1 tic
 * 6) Set IR_Latch
 * Send IDLE to PRAM_Ctl, Clear IR_Latch (enter WAIT)

0123456789ABCDEF IP_In:    110 IP_Latch: 0F0 PRAM_Ctl: 000088880 IR_Latch: 0000000F0 State:    1234567EEEEEEEE0 BUSY:     111111110

START  [2]   (begin executing the instruction at the current address and start the exec loop) Show
 * 1) Send READ to PRAM_Ctl, Set GO_PC toggle
 * 2) Clear GO_PC toggle, wait 2 more tics
 * 3) wait 1 tic
 * 4) Set IR_Latch
 * enter WAIT (Send IDLE to PRAM_Ctl, Clear IR_Latch)

0123456789ABCDEF PRAM_Ctl: 88880 IR_Latch: 000F0 State:    1234EEEEEEEEEEE0 BUSY:     22220

JUMP  [3]   (begin execution at the address in the instruction) Show
 * 1) SetI IP_In to '2' (IR)
 * 2) Enable IP_Latch
 * 3) wait 1 tic, clear IP_In, disable IP_Latch
 * 4) Send READ to PRAM_Ctl
 * 5) wait 3 tics
 * 6) wait 2 tics
 * 7) wait 1 tic
 * 8) Set IR_Latch, Send IDLE to PRAM_Ctl, Send IR_Rdy to decoder, enter WAIT

0123456789ABCDEF IP_In:    220 IP_Latch: 0F0 PRAM_Ctl: 000088880 IR_Latch: 0000000F0 State:    1234567EEEEEEEE0 BUSY:     333333330

HALT  [7]   (Stops the exec loop, reset the IP to '0') Show
 * 1) Set STOP_PC toggle, Set IP_Latch, Set IR_Latch
 * enter WAIT (Clear STOP_PC toggle, Clear IP_Latch, Clear IR_Latch

0123456789ABCDEF IP_Latch: F0 IR_Latch:  F0 State:     EEEEEEEEEEEEEEE0 BUSY:     70

JSUB  []   (save IP+1 to the R-Stack and begin execution at the address in the instruction) Show
 * 1) Execute a PUSH to R-Stack
 * 2) Execute JUMP

RETN  []   (pop the R-Stack and begin execution at the address specified there) Show

BRAN  []   (if the specified bits in the CC are set, begin execution at the address in the instruction) Show

HALT  []   (stops execution with the current instruction - sets the HALT bit) Show

RUN  []   (resumes normal execution - resets the HALT bit ) Show

>R  []   (take the value on the data bus and push it onto the return stack) Show

R>  []   (pop the top of the return stack onto the data bus) Show

ALU Instructions
Because the Design Model specifies a 0-Operand design, the TOS is effectively the accumulator register while NOS is input B for the ALU or low cell for doubles output by the ALU. The ALU inputs a single Hex control line to select its function, which is a matter of selecting the proper output enable. The sequencer simply sends out this function call and latches the TOS and the ALU's Condition Code bits at the appropriate time. There is a maximum of 15 functions possible in the ALU machine code Hex.

The ALU instruction may be paralleled with other instructions to minimize execution time.

1-Operand Instructions

 * Increment
 * Decrement
 * Invert
 * Negate
 * L/Shift
 * R/Shift
 * L/AShift
 * R/AShift

2-Operand Instructions

 * AND
 * OR
 * XOR
 * ADD
 * SUB
 * MUL

General Sequence

 * The functions INC, DEC, ADD, SUB need 7 tics to complete.
 * The MUL function takes 18? tics to complete.
 * Others need just one before the output may be latched.


 * 1) Send 'function code' to ALU_Control.
 * 2) Wait (X) tics for the ALU's output to be ready.
 * 3) Enable Latch_TOS, enable Latch_CCA_bits
 * depending on instruction, Enable Latch_NOS
 * 1) WAIT (disable Latch_TOS, disable Latch_NOS, disable Latch_CCA_bits)

Data Transfer Sequences
There are 4 'types' of memory used for data in this system - the main memory (64K cells), the 2 stacks, the register bank (16 cells) and the various dedicated registers (or latches) (<=16 cells). Many of these sources may also be used as an index into the main memory. References in this article are such: Main memory references use 'Mx', register bank references use 'Rx' and dedicated registers will use 'Lx'. Not all dedicated registers allow the same functionality and some will get a specific reference as development progresses and their unique requirements are met.

The data transfer instructions are divided into 3 categories -
 * Stack Manipulation - data is moved around within or between the stacks.
 * Register Manipulation - data is only moved around from one register file (GP, DEDicated registers or the stacks to another.
 * RAM Manipulation - any access requiring use of the data RAM (or the CODE ROM, too).

Stack Manipulation
The TOS and NOS outputs are tied to the ALU inputs at all times. The various inputs to the TOS are enabled individually and they include the NOS and local TEMP registers as well as the ALU output and general data bus. Since all enables are built using M.Banks, any aribtrary value may be used. For simplicity, the values will be the same for all enables (in either direction) and are assigned as follows:
 * 0 = ALU
 * 1 = D-bus
 * 2 = 'Addr' register direct (?)

This will also allow further additions to be made without significant reprogramming.
 * 8 = TOS
 * 9 = NOS
 * A = Temp

There may be some confusion when for example the connection is to be made between TOS and NOS. However, careful attention to proper flow and enables programming will avoid contention issues. For the example NOS>TOS, the input is critical so the code for NOS as source is used and sent to all input enables feeding TOS. This will ensure that only NOS is connected to TOS. It greatly helps that all registers and memory is dual-ported and inputs are generally DONT-CARE unless a write is being performed. -

DROP  [2]   ('delete' TOS and update stack)   Show TOS_Input: 1000000000000001 SP_Control: 9999000000000009 Latch_TOS: F000000000000000 R/W_NOS:   0008000000000000 State:     1234EEEEEEEEEEE0 DONE:      0000F00000000000
 * 1) Send 'NOS' to TOS_Input (takes 1 tic), send 'Dec' to SP_Control (3t)
 * 2) Enable Latch_TOS
 * 3) Disable Latch_TOS, send 'ALU' to TOS_Input
 * 4) ? Wait 1 more for "Dec_SP"
 * 5) Send 'Read' to R/W_NOS (update output)
 * 6) WAIT (Send 'Idle' to R/W_NOS, send 'Idle' to SP_Control)

NIP  [4]   ('delete' NOS and update stack)   Show Dec_SP:  AAAA00000000000A R/W_NOS: 0008000000000000 State:   1234EEEEEEEEEEE0 DONE:    0000F00000000000
 * 1) Send 'Dec' to SP_Control
 * 2) Wait for 'Dec'
 * 3) Wait for 'Dec'
 * 4) Wait for 'Dec'
 * 5) Send 'Read' to R/W_NOS  (update output)
 * 6) WAIT (Idle NOS, Idle SP_Control)

SWAP  [3]   (exchange TOS and NOS)   Show State:      12EEEEEEEEEEEE0 Done:       00F000000000000
 * 1) Enable TOS_to_NOS, enable NOS_to_TOS
 * 2) Enable Latch_TOS, send Write to R/W_NOS
 * 3) Disable Latch_TOS, disable R/W_NOS, disable NOS_to_TOS, disable TOS_to_NOS
 * 4) Read to R/W_NOS (update output)
 * 5) WAIT (Disable R/W_NOS)
 * TOS_to_NOS: F0000000000000F
 * NOS_to_TOS: F0000000000000F
 * Latch_TOS: F00000000000000
 * R/W_NOS:   408000000000000

STORE  (Use TOS as address into RAM and copy NOS to that location)   Show TOS_to_Addr:  F00000000000000F NOS_to_D.Bus: FFF000000000000F Latch_Addr:   F000000000000000 RAM_Control:  0004000000000000 State:        123E000000000000 Done:         000F000000000000
 * 1) Enable TOS_to_Addr, enable NOS_to_D.Bus
 * 2) Send Latch_Addr (to RAM controller)
 * 3) Send 'Idle' to Latch_Addr, disable TOS_to_Addr
 * 4) wait for RAM address decoder
 * 5) Send 'Write' to RAM_Control, disable NOS_to_Bus
 * 6) WAIT (Send 'Idle' to RAM_Control)

FETCH  (Use TOS as pointer into RAM and copy the data there into TOS)   Show TOS_Addr:    FF0000000000000F D.Bus_to_TOS: 000000FF00000000 Latch_Addr:  F000000000000000 RAM_Control: 000AAAA000000000 Latch_TOS:   0000000F00000000 State:       1234567EEEEEEEE0 Done:        0000000FFFFFFFF0
 * 1) Enable TOS_to_Addr
 * 2) Enable Latch_Addr (to RAM controller)
 * 3) wait for RAM address decoder, disable Latch_Addr, disable TOS_to_Addr
 * 4) wait for RAM address decoder
 * 5) Send 'Read+Output' to RAM_Control
 * 6) wait for read
 * 7) wait for read
 * 8) wait for read!, enable D.Bus_to_TOS
 * 9) Enable Latch_TOS, send 'Idle' to RAM_Control, disable TOS_to_Addr
 * 10) WAIT (disable Latch_TOS, disable RAM_to_D.Bus, disable D.Bus_to_TOS)

PUSH  [1]   (add data [from bus?] to TOS and update stack)   Show
 * 1) Send Inc_SP, Enable TOS_to_NOS, enable bus (?)_to_TOS (disables ALU_to_TOS)
 * 2) ? Wait 1 more for "Dec_SP"
 * 3) ? Wait 1 more for "Dec_SP"
 * 4) ? Wait 1 more for "Dec_SP"
 * 5) Enable Write_NOS (TOS in NOS), Send Idle_SP?
 * 6) Disable Write_NOS, disable TOS_to_NOS
 * 7) Enable Read_NOS (update output), enable Latch_TOS (new value in TOS)
 * 8) WAIT (Disable Read_NOS (TOS is now in NOS), disable Latch_TOS, disable bus_to_TOS)

OVER  [5]   (take NOS and PUSH a copy to TOS and update stack)   Show NOS_to_Temp: F0000000000000F Latch_Temp: F00000000000000 SP_Control: 999900000000000 TOS_to_NOS: 000FF0000000000 R/W_NOS:    000040800000000 Temp_to_TOS: 000FF0000000000 Latch_TOS:  0000F0000000000 State:      123456EEEEEEEE0 Done:       000000F00000000
 * 1) Enable NOS_to_Temp
 * 2) Enable Latch_Temp (NOS into Temp), send Inc to SP_Control
 * 3) Disable Latch_Temp, disable NOS_to_Temp
 * 4) Wait for "Dec"
 * 5) Enable TOS_to_NOS, enable Temp_to_TOS (disables ALU_to_TOS)
 * 6) Send Write to NOS_Control, enable Latch_TOS (TOS>NOS, Temp>TOS), send Idle to SP_Control
 * 7) Send Idle to NOS_Control, disable Latch_TOS, disable TOS_to_NOS
 * 8) Send Read to NOS_Control (update output)
 * 9) WAIT (Send Idle to NOS_Control)

DUP  [6]   (make another copy of TOS, PUSH to TOS and update stack)   Show State:      12345EEEEEEEEEE0 Done:       00000F0000000000
 * 1) Send Inc to SP_Control
 * 2) Wait for "Inc"
 * 3) Wait for "Inc"
 * 4) Enable TOS_to_NOS, (Wait for "Inc")
 * 5) Enable Write_NOS, send Idle to SP_Control
 * 6) Disable Write_NOS
 * 7) Enable Read_NOS (update output)
 * 8) WAIT (Disable Read_NOS, disable TOS_to_NOS)
 * SP_Control: 9990000000000009
 * TOS_to_NOS: 00FFFF0000000000
 * R/W_NOS:   0004080000000000

>R  (copy TOS to TOR, delete TOS and update stack)

R>  (update stack and copy TOR to TOS)

>A  (copy TOS to RAM_address, delete TOS and update stack)   ???

A>  (update stack and copy RAM_address to TOS)   ???

>rN  (copy TOS to Register#, delete TOS and update stack)   ???

rN>  (update stack and copy data in Register# to TOS)   ???

PICK  (use TOS as index into stack and copy the proper cell# to TOS)   ???

Register Manipulation
The WAIT state will be entered for at least 1 tic so all outputs will "RTZ".
 * R1->R2  (from one register to another in the same bank)
 * 1) Enable READ (address is already present) {This will latch the M.Bank output only}, select direct data input
 * 2) Disable READ (RTZ), Switch address_select to "TargetRegister"
 * 3) Enable WRITE (assuming 1 tic for above)
 * 4) jump to WAIT, activate DONE output.
 * The address input is set to "SourceRegister".
 * The memory control (CLOCK) is '0'
 * The data input is set to the data bus.
 * The output enable is disabled.

RAM Manipulation

 * M[R1]->R2  (R1 is a pointer into Main memory and is used to fetch data which is then stored in R2. Transfer is over the data bus.)
 * 1) Enable READ to register bank (address is already present) {This will latch the M.Bank output only},
 * 2) Enable output to bus, send IDLE to register bank
 * 3) (contents of R1 is now on bus) Latch the data memory address register. (???)
 * 4) Disable register output to bus, select TargetRegister as register bank address input
 * 5) NOOP for main memory decoding. (?)
 * 6) Send READ to Main memory
 * 7) Send IDLE to Main memory (data is now on the bus), send WRITE to register bank (data input is 'bus' as default)
 * 8) jump to WAIT, activate DONE output.
 * Resets register bank controls as noted previously


 * R1->M(R2)  (R2 is a pointer into main memory and is used to store the data in R1. Transfer uses bus.)
 * 1) Set register bank address input to "TargetRegister"
 * 2) Send READ to register bank
 * 3) (address is now on bus) Latch the data memory address register. (takes 2? tics)
 * 4) Set register bank address input to "SourceRegister" (1 tic), enable main memory output to bus
 * 5) Send READ to main memory
 * 6) (data is now on bus) Send WRITE to register bank
 * 7) jump to WAIT, activate DONE output.
 * Disables main memory output to bus in addition to resetting register bank controls


 * M[R1]->M[R2]  (Both R1 and R2 hold addresses into main memory. Transfers data from memory -to- memory, using bus.)
 * Such a transfer will require the data to be temporarily stored (the address transfer uses the bus). Because of this a separate instruction is not necessary. Either a memory-to-register or memory-to-latch pair must be used.

OR? Should I add another internal bus for address transfers only???

Reads the data at the address in the instruction and leaves it in "T".
 * FETCH A1

Reads the data at the address in the instruction and uses that to form the final address of the data to read. Leaves the data in "T".
 * FETCH> A1

Takes the value in Register bank 1 at the location defined by RA1 and stores it in Register bank 2 at the location defined by RA2. The original data location is untouched. The data previously in RA2 is lost. Does not need the "T" register.
 * MOVE.R1>R2 RA1 RA2

RA1 and RA2 are hex digits. - State-1 enables RA1 to go to the register bank-1. The address will be present at the bank's input for the next tic. RA2 is also enabled to go to the bank-2.

State-2 sets the control line for bank-1 to READ. (Both inputs may be set during the same tic and the output will be available on the next tic.) The data will be at the output for the next tic.

In state-3 the output enable of the register bank is enabled. This output will be presented to the bus by the next tic. RA1 is disconnected from bank-1. Register bank-1's control line is set to idle (the Memory Bank only responds to the rising edge of this signal).

In state-4 the data is already on the bus and RA2 is present at bank-2. Bank-2's control line is now set to WRITE and the data on the bus is written within this tic. Bank-1's output enable is also deactivated, which will take effect on the next tic.

In state-5 bank-2's control line set to idle and the RA2 is removed from bank-2. The control line "I'm waiting" is activated (now or sooner) which calls for another instruction. The sequencer is put into the WAIT mode.

Takes the value in Register bank 1 at the location defined by RA1 and stores it in Register bank 1 at the location defined by RA2. The original data location is untouched. The data previously in RA2 is lost. Uses the "T" register and destroys any data previously in it.
 * MOVE.R1>R1 RA1 RA2

RA1 and RA2 are hex digits. -

State-1 enables the address of the source register to go to the register bank 1. This is accomplished via an AND gate so there's a tic delay through that gate before the bank sees the address.

State-2 sets the control line for this bank to READ. (Both inputs may be set during the same tic and the output will be available on the next tic.)

In state-3 the output enable of the register bank is enabled. This output will be presented to the bus by the next tic. The address connection made in state 1 is disabled and the destination address is enabled. The register bank's control line is set to idle (the bank only responds to the rising edge of this signal).

In state-4 the "T" register is latched since the data will be on the bus at the start of this tic. The register bank's output enable is deactivated (which will take effect at the next tic).

In state-5 the bus is clear and the needed data has been latched into the "T" register so its latch control is now deactivated. The output enable of the "T" register is activated and the data will be placed on the bus at the next tic.

At the start of state-6, the data in the "T" register is present on the bus and the destination address within the register bank has been set. The bank's control line is now set to WRITE and the data on the bus is written within this tic. The "T" register's output enable is also deactivated, which will take effect on the next tic.

In state-7 the register bank's control line set to idle and the destination address is removed from the register bank. The control line "I'm waiting" is activated (now or sooner) which calls for another instruction. The sequencer is put into the WAIT mode. This WAIT will begin on the next tic. (???)

Ramblings...
More than one sequencer may operate on the current instruction at one time. Synchronization is only varied by how the seqencer decodes the instruction. I don't see any reason this decoding should be more than a single tic.

The system includes a 'handshake' - a common 'busy' line for simple communication between sequencers and the Program Counter circuit. The '0' state of this signal is detected by a hardware circuit which initiates the STEP instruction in the Program Counter's sequencer, beginning the execution cycle. The STEP instruction is the basic instruction fetch and excute loop of the CPU. When it starts, it raises the busy flag. The STEP instruction ends when it signals the CPU that the instruction is ready to decode. After a few wait cycles, STEP will release the busy line. Every other sequencer also has acces to and control of this busy line and when a sequencer is decoding an instruction, it raises this line itself. So, only when no sequencer is claiming use of the instruction and the line can go to '0', the hardware detects this state and sends the STEP instruction to the P.C. and the cycle is begun.

The SC electrics has the 4-bit hex as its basis so as much circuitry uses that as possible. This means the top 8 bits of the instruction code can be decoded easily in a single tic by a memory bank and 8 bits is sufficient for the basic level of instruction decoding. Where instructions can direct the hardware directly, those connections are easy too.

The move instructions that use a register require the use of 20 bits for data and thus must be decoded withing the very 'top' instruction bits. For most of the remaining instructions, all 8 bits may be used to select the proper sequencer(s) for the instruction.


 * Verify the delay to the WAIT state and make sure no 'glitches'.