viewing: uffg.txt.html     use J/K or arrows to scroll, SEMICOLON to change theme




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