1. instruction set and architecture
instruction register structure(25b):
[] [][][][] [][][][] [][][][][][][][][][][][][][][][]
|-||------| |---------------------------------------|
addr opcode|------| operands
bit destination(reg)
examples:
0 0111 011 0000100001011001
add r3, 2137
0 0011 100 0000000010001110
xor r4, 0x008e
1 1110 100 0000000000000110
mov r4, r6 - first 13 bits of operand 2 will be ignored because register adresses are 4bit
0 1101 001 1110101000110010
lda r1, 0xea32 - load byte at 0xea32 into r1 register.
first operand is always a register.
addr bit determines wether second operand is a register.
memory is only accessible via lda and str instructions.
instruction set:
mnem. operand(s) value description
nop | none | 0x0 | no operation
or | a, b | 0x1 | or
and | a, b | 0x2 | and
xor | a, b | 0x3 | xor
nor | a, b | 0x4 | nor
nand | a, b | 0x5 | nand
xnor | a, b | 0x6 | xnor
add | a, b | 0x7 | addition (w/ carry)
sub | a, b | 0x8 | substraction (w/ carry)
soi | id, op | 0x9 | single-operand instructions. a is is intruction id, b is operand
mnem operand id description
jz | label | 0x0 | jump if r1 is 0
shr | reg | 0x1 | shift reg 1 bit right (*2)
shl | reg | 0x2 | shift reg 1 bit left (/2)
pop | reg | 0x3 | read from stack
push | a | 0x4 | write constant or register a to stack
int | a | 0x5 | interrupt other program with vector a
ldb | a, addr | 0xa | load byte at memory addres into register a
stb | a, addr | 0xb | store higher byte of register a into memory addres
lda | a, addr | 0xc | load word at memory address into register a
str | a, addr | 0xd | store word from register into memory address
mov | a, b | 0xe | copy b value to register a
hlt | none | 0xf | stop increasing pc (halt cpu)
3. memory, registers and i/o
addressing:
memory addressing always uses bytes
which means that:
0x2137 |0x2138 |0x2139
[][][][][][][][]|[][][][][][][][]|[][][][][][][][]
|========word 0x2137=============|
|==byte 0x2137==|============word 0x2138=========|
its recomended to use even addresses for storing words
registers:
reg addr size description
r0 | 0x0 | | zero register
r1 | 0x1 | 16 |
r2 | 0x2 | 16 |
r3 | 0x3 | 16 |
r4 | 0x4 | 16 |
r5 | 0x5 | 16 |
r6 | 0x6 | 16 |
r7 | 0x7 | 16 |
r8 | 0x8 | 16 |
r9 | 0x9 | 16 |
rA | 0xa | 16 |
rB | 0xb | 16 |
rC | 0xc | 16 |
rD | 0xd | 16 |
rE | 0xe | 16 |
pc | 0xf | 16 | program counter
i/o bus:
---DISCLAIMER!---
no io system is implemented in the js emulator, just use the registers and your schizophernia
i/o is memory mapped, based on uffgbus(similar to unibus). each i/o device is reserved 64 addresses
for its internal memory to communicate with cpu. devices can also write and read main memory.
uffgbus supports maximum of 24 devices
(addreses > 64000 or 0xfa00 are reserved for i/o).
uffgbus structure:
[][][][] [][] [] [] [][][][][][][][][][][][][][][][] [][][][][][][][] (30pin)
| | |gnd | | | | addres [16bit] data [8bit]
| | +5v | | | register request - used with memory read/write if cpu or other device wants to read an internal register
| +10v | | block
| | memory read
+15v memory write
if block is enabled that means that a device higher in hierarchy is using the bus and the current
device cannot use it.
i/o devices have hierarchy, a device lower in hierarchy cannot write nor read when a higher device is working. so for example you cannot use terminal if disk is writing to memory.
example i/o device: terminal
terminal has 3 internal registers: last pressed key(2) and character to output(3), as well as 2kb screen
buffer that is inaccessible from the cpu.
the first register is always a constant storing type of device.
example program writing number of the device to the terminal, assuming device type of terminal is 6:
mov r2, 0xfa01 ; start of the i/o register adresses+1
find:
; find terminal
ldb r3, r2 ; load register 1 of device to r3
cmp r3, 6 ; check if is terminal
je break
add r2, 64 ; skip to the next device
inc r1 ; count how many devices have been checked
jmp find
break:
or r1, 0x0030 ; 0011 is ascii prefix for digits
add r3, 2 ; r3 now points to character register
str r1, r3 ; output the digit
4. fetch cycle and program memory
1. addres from pc (16b) is copied to program memory addres bus
2. dword is being read from program memory into ir and last 7 bits of dword are ignored (instruction is 25bit long)
3. instruction from ir is being decoded by cu
4. cu acceses register stack to get operand data
5. data is being loaded to alu, mab or reg stack
6. output from alu is being written into register
7. pc increases
8. repeat
program memory:
program can be read from:
0x0 - manual input (from control panel) - no instruction limit, can't perform jumps, turing incomplete
0x1 - flash memory (program can't modify it) - max 65535 instuctions
0x2 - main memory (can be modified by program) - max 16383 instructions
to load program from source you have to specify it using stb instruction, for instance:
mov r1, 1 ;flash memory
stb r1, 0xffff
or on control panel:
0 1110 0001 0000 0000 0000 0001
0 1011 0001 1111 1111 1111 1111
5. assembly syntax & programming
assembler uses intel syntax.
label:
mnem target, operand ;comment
syntax sugar:
inc r1 -> add r1, 1
dec r1 -> sub r1, 1
jmp label -> mov pc,
je label -> jz label -> soi 0, label
jne label -> jnz label -> soi 1, label
calling functions:
this architecture doesn't feature call instruction
you can still call functions by using:
mov r1, pc ;copy contents of program counter to r1
add r1, 3
jmp function
mov r2, 0xa1 ;<- r1 points here
;rest of the code here
function:
;instructions here
jmp r1
multiplication/division routines:
multiplication r1*r3
mul:
mov r2, r3
sub r2, 1
add r1, r1
inc r3
push r2
cmp r2, r3 ;r2 is initial value -1
je end
pop r2
jmp mul
end:
hlt
hello world:
mov r1, "he"
str r1, 0x1
mov r1, "ll"
str r1, 0x3
mov r1, "o!"
str r1, 0x5
mov r1, "\n\0"
str r1, 0x7 ;string buffer is now located at 0x1 - 8
mov r2, 1 ;r2 will store start of string for flush
mov r3, pc
add r3, 2 ;call flush function
jmp flush
hlt ; <-- r3 points here!
flush:
ldb r1, r2 ;r4 will store label
jz r2 ;exit function, jz jumps if r1 is zero so no need to use cmp here
out r1, 0x2 ;output character to terminal
add r2, 1 ;increase addres
jmp flush
output (in terminal):
hello!
█
note: this website is best viewed with unix v4 on a pdp-11/45 system