# LMC (Little Man Computer)

pedagogical

http://teaching.idallen.com/dat2343/10f/notes/301_LMC.html

https://en.wikipedia.org/wiki/Little_man_computer

" Instructions Numeric code Mnemonic code Instruction Description 1xx ADD ADD Add the value stored in mailbox xx to whatever value is currently on the accumulator (calculator).

`    Note: the contents of the mailbox are not changed, and the actions of the accumulator (calculator) are not defined for add instructions that cause sums larger than 3 digits.`

2xx SUB SUBTRACT Subtract the value stored in mailbox xx from whatever value is currently on the accumulator (calculator).

`    Note: the contents of the mailbox are not changed, and the actions of the accumulator are not defined for subtract instructions that cause negative results - however, a negative flag will be set so that 8xx (BRP) can be used properly.`

3xx STA STORE Store the contents of the accumulator in mailbox xx (destructive).

`    Note: the contents of the accumulator (calculator) are not changed (non-destructive), but contents of mailbox are replaced regardless of what was in there (destructive)`

5xx LDA LOAD Load the value from mailbox xx (non-destructive) and enter it in the accumulator (destructive). 6xx BRA BRANCH (unconditional) Set the program counter to the given address (value xx). That is, value xx will be the next instruction executed. 7xx BRZ BRANCH IF ZERO (conditional) If the accumulator (calculator) contains the value 000, set the program counter to the value xx. Otherwise, do nothing.

`    Note: since the program is stored in memory, data and program instructions all have the same address/location format.`

8xx BRP BRANCH IF POSITIVE (conditional) If the accumulator (calculator) is 0 or positive, set the program counter to the value xx. Otherwise, do nothing.

`    Note: since the program is stored in memory, data and program instructions all have the same address/location format.`

901 INP INPUT Go to the INBOX, fetch the value from the user, and put it in the accumulator (calculator)

`    Note: this will overwrite whatever value was in the accumulator (destructive)`

902 OUT OUTPUT Copy the value from the accumulator (calculator) to the OUTBOX.

`    Note: the contents of the accumulator are not changed (non-destructive).`

000 HLT/COB HALT/COFFEE BREAK Stop working. DAT DATA This is an assembler instruction which simply loads the value into the next available mailbox. DAT can also be used in conjunction with labels to declare variables. For example, DAT 984 will store the value 984 into a mailbox. "

# CARDIAC

" CARDIAC had a 10 instruction machine language. An instruction consisted of three decimal digits (the sign is ignored). The first digit was the op code (O), the second and third digits comprised an address (A). Addressing was one of accumulator to memory absolute, absolute memory to accumulator, input to absolute memory and absolute memory to output.

`    OAA`

High level languages were never developed for CARDIAC, since they would defeat one of the purposes of the device, to introduce concepts of assembly language programming.

Programs were hand assembled, then written, by pencil into the appropriate memory cells. Instruction Set CARDIAC Instruction Set Opcode Mnemonic Instruction Description 0 INP Input take a number from the input card and put it in a specified memory cell. 1 CLA Clear and add clear the accumulator and add the contents of a memory cell to the accumulator. 2 ADD Add add the contents of a memory cell to the accumulator. 3 TAC Test accumulator contents performs a sign test on the contents of the accumulator; if minus, jump to a specified memory cell. 4 SFT Shift shifts the accumulator x places left, then y places right, where x is the upper address digit and y is the lower. 5 OUT Output take a number from the specified memory cell and write it on the output card. 6 STO Store copy the contents of the accumulator into a specified memory cell. 7 SUB Subtract subtract the contents of a specified memory cell from the accumulator. 8 JMP Jump jump to a specified memory cell. The current cell number is written in cell 99. This allows for one level of subroutines. 9 HRS Halt and reset move bug to the specified cell, then stop program execution. " -- 

# Knuth's MMIX

https://en.wikipedia.org/wiki/MMIX

Knuth's pedagogical language

64-bit addressing, 64-bit words, 256 general-purpose registers, 32 special-purpose registers. Von Neumann architecture (code and data are in the same memory space).

Instructions:

• Loads and stores (LD*, ST*) (64-bit, 32-bit, 16-bit, 8-bit); sign extension or unsigned (zero extension). Load from memory into a register, or store from a register into memory. Also LDHT/STHT, load/store high 32 bits, and STCO, store immediate constant. All have two input registers operands for the address, which are summed together to get the load or store memory location.
• Integer arithmetic: ADD, SUB, MUL, DIV; signed and unsigned; 2ADDU, 4ADDU, 8ADDU, 16ADDU to multiply the first addend by 2,4,8, or 16 before the addition; NEGate, NEGU (negate unsigned; 0 - x mod 2^64) (both negates take an optional second argument which is an immediate constant to replace 0 in the subtraction, eg NEG(x,y=0) is y - x, although the order of operands is actually different than in my formula)
• shifts: SL, SR (shift left, shift right), SLU, SRU (unsigned; SLU is like SL but mod 2^64 instead of potentially overflowing, and SRU zero-extends while SR sign-extends);
• compares: CMP, CMPU; outputs -1, 0, 1 depending on the result of the compare
• conditionals: conditional copy (he says 'conditional set') (if the condition holds, set the destination to a copy of the input), and zero-or-conditional-copy (if the condition holds, set the destination to a copy of the input, otherwise, set the destination to zero); available conditions (tested on a third operand which is neither the input nor the destination): negative, zero, positive, odd, and the negation of each of those four; note that negative means leftmost bit is 1, and odd means rightmost bit is 1.

(tombdo others too, eg MUX, SADD, MOR, MXOR)

# Wirth's RISC

http://www.inf.ethz.ch/personal/wirth/FPGA-relatedWork/RISC-Arch.pdf

Part of the Oberon System.

32-bit words. 16 registers (32-bits each). 32-bit addressing (byte addressing, not word); branch instructions with immediate offsets have 24-bit offsets; load and store memory address offsets are 20 bits; other immediate constants are 16 bits. Note that the largest memory size this has apparently been used for is 'RISC5' which is 1M (20 bit addressing). 32-bit instructions. 5 (4?) instruction encoding formats.

4 ALU condition codes (flag bits): N, Z, C, V (Negative, Zero, Carry, Overflow).

Instructions:

• MOV
• shifts: LSL, ASR, ROR, move and shift left 16 bits
• logical: AND, OR, XOR, ANN (a and not(b))
• arithmetic (both integer and floating point): ADD, SUB, MUL, DIV, unsigned multiplication, ADD with carry, SUB with carry
• conditional branch. Available conditions are: N, Z, C, V, "less or same" (~C
 Z), less than (N != V), less or equal ((N != V) Z), true/always; and the negation of each of these conditions.
• special: load register H (H is where MUL deposits the high 32-bits), load status register (condition codes) into ordinary register,

All instructions have a register direct mode; all except float-point ones have an immediate mode.

Emulators:

# DLX

https://en.wikipedia.org/wiki/DLX

since this is closely related to MIPS, it is discussed in chapter The MIPS and DLX, etc, ISAs

# Mano machine

https://en.wikipedia.org/wiki/Mano_machine

# SIC

https://en.wikipedia.org/wiki/Simplified_Instructional_Computer

# OISCs

There are various "one instruction set computers" (OISCs) ( https://en.wikipedia.org/wiki/One_instruction_set_computer ).

## SUBLEQ

The 'universal instructions' include subleq ("SUbtract and Branch if Less than or EQual to zero"), which requires 3 operands.

## SUBLEQ2

There is also subleq2, which uses an accumulator and requires only 2 operands.

Looking at https://en.wikipedia.org/wiki/One_instruction_set_computer#Synthesized_instructions , we see that at least three 'registers' are needed for simple computations with subleq2. Note however that memory-memory addressing is assumed; if we actually used registers, we'd also need an indirect addressing mode or LOADs and STORES or some other way to reach main memory. The example given for flipping bits also uses an immediate-mode operand of -1 (it would take 2 bits to represent -1,0,1,2).

## SUBNEG

'subneg' ("SUbtract and Branch if NEGative"), with three operands

rssb (Reverse Subtract and Skip if Borrow), which has only one operand but also uses an accumulator.

## Transport triggered architecture

https://en.wikipedia.org/wiki/One_instruction_set_computer also mentions Transport triggered architecture, in which there is only MOV but certain memory locations have magic side effects including arithmetic.

## MOV-only OISC on x86

http://www.cl.cam.ac.uk/~sd601/papers/mov.pdf

# Nock

Nock is a near-minimalistic 'functional assembly language'. See Target languages.

# CPU0

• http://jonathan2251.github.io/lbd/llvmstructure.html (this link is in the middle of an LLVM tutorial that shows how to implement a new backend for LLVM for the CPU0 architecture, but it also contains a good English-language description of the CPU0 architecture)

# TinyVM

https://github.com/jakogut/tinyvm/blob/v1.0/SYNTAX

"9 registers, modeled after x86 registers":

(plus the FLAGS register?)

Instructions

• mov
• push pop
• pushf popf (push and pop the FLAGS register)
• call ret
• add sub mul div inc dec mod rem
• and or not xor
• shl shr
• cmp (result goes into FLAGS register)
• jmp
• je jne jg jge jl jle
• prn (print an integer)

# JSVM

https://github.com/jawb/JSVM

Instructions:

• push pop
• load store (from stack to variable)
• add sub mult div mod
• and or not xor
• ras (Right arithmetic shift) rbs (Right binary shift) ls (left shift)
• lt le
• jmp
• beq bne

Assembler has labels and variable names.

# Gpfault's SVM

A simple stack machine VM written as a personal exercise. 32-bits word size.

Instructions:

• add sub mul div mod neg inc dec
• (bitwise) and or not xor shl shr
• pop dup swp (swap) ovr (over; push a copy of the second item on the stack)
• jmp je jne jg jge jl jle
• nop halt
• rf crf (set or clear the 'rf' flag, which determines whether 'in' and 'out' represent bytes as formatted integers or as raw characters)
• in out (console I/O)

Sample code:

```IN ; read integer "A" from standard input
IN ; read integer "B" from standard input

:GCD ; this is a label
DUP ; if B is 0 then A is the gcd
0 ; (immediate values get pushed on the stack)
@END ; (this is how you put the address of a label onto the stack)
JE ; (this will jump to the address at top of stack if the preceding two values are equal)
SWP ; if B is not 0 then the result is gcd(B, A modulo B)
OVR
MOD
@GCD
JMP ; recursion!

:END
POP ; remove 0 from top of stack
OUT ; now the result is at the top, print it.
```

# IJVM

https://en.wikipedia.org/wiki/IJVM

" Mnemonic Operands Description BIPUSH byte Push a byte onto stack DUP N/A Copy top word on stack and push onto stack ERR N/A Print an error message and halt the simulator GOTO label name Unconditional jump HALT N/A Halt the simulator IADD N/A Pop two words from stack; push their sum IAND N/A Pop two words from stack; push Boolean AND IFEQ label name Pop word from stack and branch if it is zero IFLT label name Pop word from stack and branch if it is less than zero IF_ICMPEQ label name Pop two words from stack and branch if they are equal IINC variable name, byte Add a constant value to a local variable ILOAD variable name Push local variable onto stack IN N/A Reads a character from the keyboard buffer and pushes it onto the stack. If no character is available, 0 is pushed INVOKEVIRTUAL method name Invoke a method, pops object reference and optionally pops arguments from stack. IOR N/A Pop two words from stack; push Boolean OR IRETURN N/A Return from method with integer value ISTORE variable name Pop word from stack and store in local variable ISUB N/A Pop two words from stack; subtract the top word from the second to top word, push the answer; LDC_W constant name Push constant from constant pool onto stack NOP N/A Do nothing OUT N/A Pop word off stack and print it to standard out POP N/A Delete word from top of stack SWAP N/A Swap the two top words on the stack WIDE N/A Prefix instruction; next instruction has a 16-bit index

There's also a set of special ARRAY instructions. Instruction Stack before* Stack after Description NEWARRAY count arrayref Create new array on the heap. The count must be of type int. It is popped off the operand stack. The count represents the number of elements in the array to be created. Based on the Sun JVM-spec. The atype parameter is omitted. IALOAD index. arrayref value Load from int array. The arrayref must be of type reference and must refer to an array whose components are of type int. The index must be of type int. Both arrayref and index are popped from the operand stack. The int value in the component of the array at index is retrieved and pushed onto the operand stack. Part of the Sun JVM Spec. IASTORE value, index, arrayref ... Store into int array. The arrayref must be of type reference and must refer to an array whose components are of type int. Both index and value must be of type int. The arrayref, index, and value are popped from the operand stack. The int value is stored as the component of the array indexed by index. Part of the Sun JVM Spec. W_OUT value ... Pop the value from the stack and write a decimal representation of it to the display. For debugging purposes. Not part of the JVM Spec. "

# SmallVM

https://github.com/andrewrothman/SmallVM

"a small virtual machine with focus on educating others about virtual machines."

instructions (quoted from https://github.com/andrewrothman/SmallVM/blob/master/src/opcodes.h ):

• SET Sets a register to a value or to the contents of another register
• SUB Subtracts two values or register contents
• MULT Multiplies two values or register contents
• DIV Divides two values or register contents
• MOD Mods two values or register contents
• STORE Stores a value into memory
• GET Get a value from memory
• IF Performs the next instruction if the values are equal
• IFN Performs the next instruction if the values are not equal

# Unnamed example simple instruction set in David Jaggar's thesis

From Table 1 on page 10 of 

• SUB: Subtract
• AND: Logical AND
• OR: Logical OR
• EOR: Logical EOR
• NOT: Logical NOT
• LSL: Logical Shift Left
• LSR: Logical Shift Right
• ROT: Rotate
• ASR: Arithmetic Shift Right
• CMP: Compare
• MOV: Move
• MULT: Multiply
• DIV: Divide
• JMP: Jump
• CALL: Procedure Call
• RET: Procedure Return
• Bcc: Conditional Branch

# QFTASM

https://github.com/QuestForTetris/tetris-writeup/blob/master/QFTASM_Cogol.md

"

• No registers. Every address in RAM is treated equally and can be used as any argument for any operation. In a sense, this means all of RAM could be treated like registers. This means that there are no special load/store instructions.
• In a similar vein, memory-mapping. Everything that could be written to or read from shares a unified addressing scheme. This means that the program counter (PC) is address 0, and the only difference between regular instructions and control-flow instructions is that control-flow instructions use address 0.
• Data is serial in transmission, parallel in storage. Due to the "electron"-based nature of our computer, addition and subtraction are significantly easier to implement when the data is transmitted in serial little-endian (least-significant bit first) form. Furthermore, serial data removes the need for cumbersome data buses, which are both really wide and cumbersome to time properly (in order for the data to stay together, all "lanes" of the bus must experience the same travel delay).
• Harvard architecture, meaning a division between program memory (ROM) and data memory (RAM). Although this does reduce the flexibility of the processor, this helps with size optimization: the length of the program is much larger than the amount of RAM we'll need, so we can split the program off into ROM and then focus on compressing the ROM, which is much easier when it is read-only.
• 16-bit data width. This is the smallest power of two that is wider than a standard Tetris board (10 blocks). This gives us a data range of -32768 to +32767 and a maximum program length of 65536 instructions. (2^8=256 instructions is enough for most simple things we might want a toy processor to do, but not Tetris.)
• Asynchronous design. Rather than having a central clock (or, equivalently, several clocks) dictating the timing of the computer, all data is accompanied by a "clock signal" which travels in parallel with the data as it flows around the computer. Certain paths may be shorter than others, and while this would pose difficulties for a centrally-clocked design, an asynchronous design can easily deal with variable-time operations.
• All instructions are of equal size. We felt that an architecture in which each instruction has 1 opcode with 3 operands (value value destination) was the most flexible option. This encompasses binary data operations as well as conditional moves.
• Simple addressing mode system. Having a variety of addressing modes is very useful for supporting things such as arrays or recursion. We managed to implement several important addressing modes with a relatively simple system.

...

• MNZ: Move if Not Zero (note: "a conditional move can both copy data to regular RAM and copy a destination address to the PC")
• MLZ: Move if Less than Zero
• SUB: SUBtraction
• AND: bitwise AND
• OR : bitwise OR
• XOR: bitwise eXclusive OR
• ANT: bitwise And-NoT?
• SL : Shift Left
• SRL: Shift Right Logical
• SRA: Shift Right Arithmetic

...

• Immediate: A hard-coded value. (no RAM reads)

examples:

"

Fibonacci sequence in five lines:

0. MLZ -1 1 1; initial value 1. MLZ -1 A2 3; start loop, shift data 2. MLZ -1 A1 2; shift data 3. MLZ -1 0 0; end loop 4. ADD A2 A3 1; branch delay slot, compute next term

This code computes the Fibonacci sequence, with RAM address 1 containing the current term. It quickly overflows after 28657.

Gray code:

0. MLZ -1 5 1; initial value for RAM address to write to 1. SUB A1 5 2; start loop, determine what binary number to covert to Gray code 2. SRL A2 1 3; shift right by 1 3. XOR A2 A3 A1; XOR and store Gray code in destination address 4. SUB B1 42 4; take the Gray code and subtract 42 (101010) 5. MNZ A4 0 0; if the result is not zero (Gray code != 101010) repeat loop 6. ADD A1 1 1; branch delay slot, increment destination address

This program computes Gray code and stores the code in succesive addresses starting at address 5. This program utilizes several important features such as indirect addressing and a conditional jump. It halts once the resultant Gray code is 101010, which happens for input 51 at address 56. "