Instruction Sequences

# OVERVIEW

The architecture of the SC-CPU uses distributed micro-coded sequencers to execute the machine instructions. Each subsystem in the CPU has a group of controllers that connect to the hardware in that subsystem. Each controller outputs one electric signal which may be a binary or hex or a unique (4-bit) control. This group of controllers is the micro-sequencer for that subsystem.

All the controllers in the micro-sequencer are tied together and slaved to a fast counter that provides common timing for that sequencer. This step counter keeps all the controllers in time with each other. The local command is input to all the controllers simultaneously so they all execute the same command in perfect synchrony. Other controllers that don't directly control hardware include 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 every micro-sequencer 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 micro-sequencers are executed according to the microprogramming in each of the controllers. 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 controller.

It is the programming of all these controllers that is the substance of this article.

# Intro

The entries below are grouped by subsystem/sequencer and illuminates the instructions it executes. These 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 micro-sequencer. This is followed with details of each instruction processed by the micro-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 controllers.

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 controller. I.e., only one controller is used for each hardware input.

??? 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

For the PC description, see the Program Counter article.

### Control Signals

* IP Latch
* IP Input Select (hex)
* IR Latch
* Code ROM control

* Return Stack Pointer Control
* Return Stack RAM Control
* IP+1 to Top of Return Stack [IP+1>TOR]

* Step Counter
* HALT Generator
* GO Generator
* Busy Generator?

Others related - - - ?

* Top of Data Stack to Top of Return Stack [TOS>TOR]
* Top of Return Stack to Top of Data Stack [TOR>TS]

* ? GO\_PC trigger
* ? HALT\_PC trigger
* ? IP>TOS, TOS, IP ???

### Instructions

NOTE:
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)
2. Enable IP\_Latch
3. Clear IP\_In, disable IP\_Latch (wait 1 tic)
4. Send READ to PRAM\_Ctl
5. wait 2 more tics, holding READ
6. wait 1 more tics, holding READ
7. Set IR\_Latch

* Send IDLE to PRAM\_Ctl, Clear IR\_Latch (enter WAIT)

```
           0123456789ABCDEF
IP_In:     110
IP_Latch:  0F0
PRAM_Ctl:  00088880
IR_Latch:  000000F0
State:     123456EEEEEEEEE0
BUSY:      11111110

```

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]

```

```

## Arithmetic, Logic Unit (ALU)

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 control input.

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, etc.)

## 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 (?)

* 8 = TOS
* 9 = NOS
* A = Temp

This will also allow further additions to be made without significant reprogramming.

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
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)

```
TOS_Input:  1000000000000001
SP_Control: 9999000000000009
Latch_TOS:  F000000000000000
R/W_NOS:    0008000000000000
State:      1234EEEEEEEEEEE0
DONE:       0000F00000000000

```

NIP [4] ('delete' NOS and update stack)

Show
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)

```
Dec_SP:   AAAA00000000000A
R/W_NOS:  0008000000000000
State:    1234EEEEEEEEEEE0
DONE:     0000F00000000000

```

SWAP [3] (exchange TOS and NOS)

Show
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
State:       12EEEEEEEEEEEE0
Done:        00F000000000000

```

STORE (Use TOS as address into RAM and copy NOS to that location)

Show
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)

```
TOS_to_Addr:   F00000000000000F
NOS_to_D.Bus:  FFF000000000000F
Latch_Addr:    F000000000000000
RAM_Control:   0004000000000000
State:         123E000000000000
Done:          000F000000000000

```

FETCH (Use TOS as pointer into RAM and copy the data there into TOS)

Show
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)

```
TOS_Addr:     FF0000000000000F
D.Bus_to_TOS: 000000FF00000000
Latch_Addr:   F000000000000000
RAM_Control:  000AAAA000000000
Latch_TOS:    0000000F00000000
State:        1234567EEEEEEEE0
Done:         0000000FFFFFFFF0

```

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
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)

```
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

```

DUP [6] (make another copy of TOS, PUSH to TOS and update stack)

Show
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
State:       12345EEEEEEEEEE0
Done:        00000F0000000000

```

>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

* 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 WAIT state will be entered for at least 1 tic so all outputs will "RTZ".

* 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???

* FETCH A1

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".

* MOVE.R1>R2 RA1 RA2

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.

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.

* MOVE.R1>R1 RA1 RA2

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.

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'.