Machine Definition & Programming Guide

This page presents a machine definition and programming guide for Simon. The aspects of the machine definition left unspecified in the articles, as distinguished from the resolutions for them used here, are elaborated on the Gaps & Alterations page.

Much of the material presented here is new (2006), including the programming model diagram, assembly format definition and sample programs. Such material was not presented in the original articles.

Contents (this page):

 Programming Model

Figure 1. Programming Model of Simon
Figure 1 presents the programming model of Simon.

Program instructions and data are input via a 5-level paper tape reader (5 bits or holes wide). (5-level paper tape was standard for use with teletypes before the advent of ASCII). Data may also be input manually via the front-panel switches during program execution.

Various registers are provided, some for general data storage, others for targetted purposes. The registers and busses are a mixture of 2- and 4-bits wide. The input register can be viewed as one 4-bit register (referred to as IR) or two 2-bit registers (IR1 and IR2). IR1 refers to the 2 lower-order bits of IR, IR2 to the 2 higher-order bits. Register CR4, which indicates the function to be performed by the ALU, is 4 bits wide. There is a 1-bit carry register (CRY) accessible only by the ALU. All other registers are 2 bits wide.

Note that IR and CR5 can not be loaded from the main bus. IR is only loaded from the tape or front panel, CR5 is restricted to registering the output from the ALU.

The ALU is also 2-bits wide. The functions which it performs are listed further below.

Output is via the 5 lamps connected to the Output Registers.

Comment: The mixture of 2 and 4 bit registers and busses makes for an awkward design. Presumably the designers made this choice for reasons of economy, particularly in reducing the size of the ALU. Nonetheless, I suspect a more fully 4-bit design where the existing 2-bit registers are simply combined into 4-bit registers and the ALU extended to 4 bits, would not require many more relays.

Program execution

To program Simon one prepares a paper tape with the machine instructions and data. The paper tape is the program memory: Simon executes the program instructions as it reads the tape, it does not 'load' the program.

The tape reader reads in one direction only. All instructions on the tape are executed in sequence, there is no opportunity to skip instructions or branch. Some degree of conditional operation is provided for by the selective assignment function of the ALU. There is one opportunity to create a loop by forming the entire program tape into a loop.

A program may include programmed halts. Program execution stops, and the machine waits for manual indication before resuming execution. The output lamps can be observed at this point and/or a data value can be input from the front panel.

 Instruction Encoding and Execution

Figure 2. Instruction Encoding
Each instruction on the program tape is composed of a triplet of 5-bit elements (characters) as defined in Figure 2. The register codes are shown in Table 1.

At the tape level there is really only one type of instruction. In executing each tape instruction the machine performs the following sequence of actions:

  1. Clear IR if c=1.
  2. Bitwise-OR the input data from the tape (iiii), or from the front-panel switches, into IR.
  3. Copy the data in the source register (ssss) to the destination register (dddd).

This sequence obviously and directly provides the operation of moving data between registers. Other operations - specifically those involving the ALU - are accomplished by loading CR4 with an appropriate function code from Table 2. Loading CR4 results in CR5 and CRY being loaded with the function results from the ALU. This is detailed further in the programming examples below.

In the event of a programmed halt (h=1), reading of the tape stops immediately at the 2nd element of the tape triplet. At this point, IR can be manually loaded with data from the front panel and execution resumed.

Table 1. Register Codes
Register Code
IR / IR1 0
IR2 1
SR1 2
SR2 3
SR3 4
SR4 5
SR5 6
SR6 7
CR1 8
CR2 9
CR3 10
CR4 11
CR5 12
OR1 13
OR2 14
OR3 15
Table 2. ALU Function Codes
Symbol Code Function Description
ADD 0 CR5 = r = CR1+CR2, CRY = r>3 Add, no carry-in
NEG 1 CR5 = r = 3-CR1+1, CRY = r<0 Negate (twos-complement), no borrow-in
GT 2 CR5 = if CR2>CR1 then 1 else 0 Greater than
SEL 3 CR5 = if CR3(LSB) then CR2 else CR1 Select based on LSB of CR3
AND 4 CR5 = CR1 AND CR2 Bitwise AND
NOT 5 CR5 = 3-CR1 Bitwise ones-complement
OR 6 CR5 = CR1 OR CR2 Bitwise OR
- 7 - not defined
ADC 8 CR5 = r = CR1+CR2+CRY, CRY = r>3 Add, with carry-in
NGC 9 CR5 = r = 3-CR1-CRY+1, CRY = r<0 Negate (twos-complement), with borrow-in
- 10 - not defined
- 11 - not defined
- 12 - not defined
- 13 - not defined
- 14 - not defined
- 15 - not defined

Miscellaneous and Side-Effects:

 Assembly Format

Figure 3. Assembly Instruction Nomenclature
asmInstr    = rawInstr [/comment]
            | niceInstr [/comment]


rawInstr    = dstReg srcReg [data][*][^]

dstReg      = register

srcReg      = register

register    = IR, IR1, IR2, CR1..CR5, SR1..SR6, OR1..OR3
            | number

data        = number
            | function

function    = ADD, NEG, GT, SEL, AND, NOT, OR, ADC, NGC

number      = 0..31


niceInstr   = dstReg=number   --> dstReg IR1 number  / get low bits of number
            | dstReg=*         --> dstReg IR1 *       / halt, get low bits
            | dstReg=^         --> dstReg IR2 ^       / get previous high bits
            | dstReg=srcReg    --> dstReg srcReg
            | function         --> CR4 IR function
            | HLT              --> IR IR *^
            | NOP              --> IR IR
To introduce some new nomenclature, Figure 3 defines an assembly instruction. Two syntaxes for specifying an instruction are provided: a raw syntax which permits the construction of any arbitrary tape pattern, and a nice syntax which provides for greater clarity and convenience.

Raw Syntax

For clarity the operands have been reordered from their sequence in a tape triplet, so information movement is now consistently right to left.

It is possible to specify an instruction entirely in numeric form. To this end, numeric values may be in the range 0 to 31 to permit the direct setting of the 5th bit in a tape element. In practice, only values in the range 0 to 15 are typically used, with the 5th bit being handled by other specifications in the assembly instruction.

Specifying "IR" for register is equivalent to specifying "IR1", and is provided simply for clarity when performing a 4-bit transfer to CR4. Symbolic values for the ALU function codes may be used for clarity.

Specifying a third argument results in c=1 on the tape, to clear IR in preparation for receipt of the new value, unless "^" is present, which forces c=0. Specifying "^" is typically done to get the second set of 2 bits from a previously loaded value.

Figure 4. Assembly Instruction Examples
             Tape (hex)  Assembly                                      
             ----------  ----------------------------------------------

raw numeric:  12.0D.00   2   0   13   / load IR with 13 and SR1 with 1
raw symbolic: 12.0D.00   SR1 IR1 13   / same as above
nice:         12.0D.00   SR1=13       / same as above

              12.1D.00   SR1 IR1 13*  / force h=1
              02.0D.00   SR1 IR1 13^  / suppress IR clear, c=0
              02.1D.00   SR1 IR1 13*^

raw symbolic: 0E.00.0C   OR2 CR5      / load OR2 with contents of CR5
nice:         0E.00.0C   OR2=CR5      / same as above

raw symbolic: 1B.01.00   CR4 IR  NEG  / load CR4 with NEG function code
nice:         1B.01.00   NEG          / same as above

              00.10.00   HLT

              00.00.00   NOP
If data is not specified a data value of 0 is implied.

Specifying "*" introduces a programmed halt (h=1).

Nice Syntax

The nice syntax eliminates the need for repeated specification of inherent aspects of instructions. While for the most part a program can be written entirely using this syntax, there are some limitations as to what can be expressed with it. Particularly, note that the nice syntax for data input implies the use of specific halves of the IR register.

HLT can be used to indicate a pause in a program when there is no interest in the data from the front panel, but note IR may be affected if the front panel switches are not all 0.

Figure 4 presents some examples of assembly instructions, showing the tape codes they produce and the equivalency between the different assembly syntaxes.

 Programming Examples

Following are several programs which exemplify some programming techniques for Simon.

Data Input Operations

Program 1. Loading 4-bit Values
Ref  Tape      Assembly
---  --------  --------------------------------------------------
000: 1D.0D.00  OR1 IR1 13   / load IR with 13, lower bits to OR1
001: 0E.00.01  OR2 IR2 ^    / higher bits to OR2

002: 1D.10.00  OR1=*        / wait for data from front panel
003: 0E.00.01  OR2=^                 
As the main data bus is only 2-bits wide, loading the 4 bits of input data from the tape or front panel into 2-bit machine registers actually requires two tape instructions.

By example, lines 0 and 1 of Program 1 load the value 13 (binary 1101) from tape into registers OR1 and OR2. The first instruction (line 0) specifies IR to be cleared, loads IR with the 4 bits from the tape and transfers two bits to OR1. The second instruction (line 1) refrains from clearing the previous data from IR and transfers the other 2 bits to OR2. OR1 will receive binary 01, OR2 will receive binary 11.

The same procedure applies for loading data from the front panel during a programmed halt as shown in lines 2 and 3. The instructions are expressed in nice syntax this time, with IR1 versus IR2 implied by the use of "=*" versus "=^".

Operations with the ALU

Program 2. 4-bit Addition
Ref  Tape      Assembly
---  --------  --------------------------------------------------
000: 18.0D.00  CR1=13       / load first operand
001: 02.00.01  SR1=^        / save high bits as well

002: 19.05.00  CR2=5        / load second operand
003: 03.00.01  SR2=^        / save high bits as well

004: 1B.00.00  ADD          / add low bits, no carry-in
005: 1D.00.0C  OR1=CR5      / display low bits

006: 18.00.02  CR1=SR1      / retrieve upper bits
007: 19.00.03  CR2=SR2      /  of both operands
008: 1B.08.00  ADC          / add upper bits, with carry-in
009: 1E.00.0C  OR2=CR5      / display high bits

010: 18.00.00  CR1=0        / clear CR1
011: 19.00.00  CR2=0        / clear CR2
012: 1B.08.00  ADC          / add 0+0+carry
013: 1F.00.0C  OR3=CR5      / display 5th bit of result
As is apparent from Figure 1, performing an arithmetic or logical function requires registers CR1, CR2, CR3, and CR4 to be loaded appropriately. Table 2 lists the functions performed and the code for CR4 which invokes them.

The order in which the loads occur is of consequence. CR5 and CRY will receive the result of the function but do not do so until CR4 is loaded. This means CR4 must be loaded for every function operation - even if CR4 already contains the desired function code - and the load performed after loading the desired operands into CR1, CR2 and/or CR3.

As an example, Program 2 adds two 4-bit values (13 and 5) and displays the 5-bit result in the output lamps.

Conditional Operation

Program 3. Maximum of Two 4-bit Values
Ref  Tape      Assembly
---  --------  --------------------------------------------------
000: 12.10.00  SR1=*        / wait for first value (A)
001: 03.00.01  SR2=^        / save high bits as well

002: 14.10.00  SR3=*        / wait for second value (B)
003: 05.00.01  SR4=^  

004: 08.00.04  CR1=SR3      / negate B
005: 1B.01.00  NEG          /   and save in SR5 & 6
006: 06.00.0C  SR5=CR5    
007: 08.00.05  CR1=SR4    
008: 1B.09.00  NGC
009: 07.00.0C  SR6=CR5    

010: 18.00.00  CR1=0        / save carry (5th bit) in CR3
011: 19.00.00  CR2=0  
012: 1B.08.00  ADC
013: 0A.00.0C  CR3=CR5    

014: 08.00.02  CR1=SR1      / subtract: A + -B
015: 09.00.06  CR2=SR5    
016: 1B.00.00  ADD
017: 08.00.03  CR1=SR2    
018: 09.00.07  CR2=SR6    
019: 1B.08.00  ADC
020: 08.00.0A  CR1=CR3    
021: 19.00.00  CR2=0  
022: 1B.08.00  ADC          / result = B>A
023: 0A.00.0C  CR3=CR5      / move result to CR3

024: 08.00.02  CR1=SR1      / select lower bits
025: 09.00.04  CR2=SR3      /   for display
026: 1B.03.00  SEL
027: 0D.00.0C  OR1=CR5    

028: 08.00.03  CR1=SR2      / select upper bits
029: 09.00.05  CR2=SR4      /   for display
030: 1B.03.00  SEL
031: 0E.00.0C  OR2=CR5
As mentioned previously, no branch or skip instructions are provided; however a conditional assignment function (SEL) is provided by the ALU.

Program 3 directs Simon to receive two manually-input 4-bit values and select the greater of the two for display. During execution one value is subtracted from the other. The difference result is ignored, but the carry register holds the borrow result of the subtraction. The value in the carry register is moved to CR3 where it is used twice by SEL instructions to choose the value for display.

 Miscellaneous Issues

As instructions occupy 3 elements on the tape, when loading a tape onto Simon one must be careful to position the tape precisely at the first element of the program, to ensure that execution does not begin in the middle of an instruction. Starting execution at an arbitrary point in a blank leader is not acceptable. A suggested policy is to begin a tape with several instructions of the form "IR2 IR1 0" which results in a tape pattern of "10001 00000 00000". These are effectively NOPs, while the 'holes - no holes - no holes' pattern provides easy visual indication for positioning the tape correctly.

Blank portions of tape are effectively NOPs, so blank trailers are acceptable. The absence of tape presents an instruction with a programmed halt to the machine, so the end of tape will result in the machine halting.

  Machine Definition | Relay Implementation | Programs | Simulation | Alterations
2006 Sep