Last active
February 12, 2020 19:44
-
-
Save moonheart08/1f852ab8a5f3e9853e940fe073e6883c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#bankdef "bootrom" { | |
#addr 0x0 | |
#size 0x1000 | |
#outp 0x0 | |
} | |
#bankdef "ram" { | |
#addr 0x1000 | |
#size 0x8000 | |
} | |
#cpudef | |
{ | |
#bits 8 | |
#tokendef Locals { | |
A = 0, | |
B = 1, | |
C = 2, | |
D = 3, | |
E = 4, | |
F = 5, | |
SP = 6, ; Stack pointer | |
RSP = 7, ; Return stack pointer | |
} | |
pushloc {l: Locals} -> 0x0 @ l[3:0] | |
poploc {l: Locals} -> 0x0 @ (8 + l)[3:0] | |
dup -> 0x10 ; A -> A, A | |
drop -> 0x11 ; A -> () | |
swap -> 0x12 ; A, B -> B, A | |
pick -> 0x13 ; A -> SP[A]; | |
pick.i {i} -> { | |
0b10 @ i[5:0] @ 0x13 | |
} | |
pull -> 0x14 ; A -> SP[A]; pop SP[A] | |
pull.i {i} -> { | |
0x5 @ i[3:0] @ 0x27 | |
} | |
insert -> 0x15 ; A, B -> SP[A] = B | |
load -> 0x16 ; A -> A[0] | |
store -> 0x17 ; A, B -> A[0] = B | |
; literally just add/sub related instrs | |
add -> 0x18 ; A, B -> A + B | |
sub -> 0x19 ; A, B -> A - B | |
addc -> 0x1A ; A, B, (Carry Flag) -> A addc B | |
subb -> 0x1B ; A, B, (Carry Flag) -> A addc B | |
pushc -> 0x1C ; () -> (Carry Flag) | |
pusho -> 0x1D ; () -> (Overflow Flag) | |
popc -> 0x1E ; A -> (Carry Flag) = A | |
popo -> 0x1F ; A -> (Overflow Flag) = A | |
; bitwise | |
and -> 0x20 ; A, B -> A & B | |
or -> 0x21 ; A, B -> A | B | |
xor -> 0x22 ; A, B -> A ^ B | |
not -> 0x23 ; A -> !A | |
shl -> 0x24 ; A, B -> A >> B | |
shr -> 0x25 ; A, B -> A << B | |
shra -> 0x26 ; A, B -> A <<< B | |
; ERRATA BEHAVIOR: | |
; If prefixed with offs {n} for any offset | |
; besides zero, it will function similarly to | |
; the pull instruction, with a constant source | |
nop -> 0x27 ; A -> A | |
; extended arithmetic | |
inc -> 0x28 ; A -> A + 1 | |
dec -> 0x29 ; A -> A - 1 | |
inc2 -> 0x2A ; A -> A + 2 | |
dec2 -> 0x2B ; A -> A - 2 | |
; IO operations | |
loadio -> 0x2C ; A -> IO[A] | |
storeio -> 0x2D ; A, B -> IO[A] = B | |
; Control register | |
loadcr -> 0x2E ; () -> CR | |
storecr -> 0x2F ; A -> CR = A | |
; Jumps/call/ret | |
call -> 0x30 ; A -> pushrsp PC; jump A | |
ret -> 0x31 ; () -> A = poprsp; jump A | |
pushrsp -> 0x32 ; () -> pushrsp | |
poprsp -> 0x33 ; A -> poprsp A | |
jump -> 0x34 ; A -> jump A | |
; Why this set of jumps and not some other jump design? | |
; coz. | |
jc -> 0x35 ; A -> if (Carry Flag) then jump A | |
jo -> 0x36 ; A -> if (Overflow Flag) then jump A | |
jz -> 0x37 ; A -> if (Zero Flag) then jump A | |
jnc -> 0x38 ; A -> if not (Carry Flag) then jump A | |
jno -> 0x39 ; A -> if not (Overflow Flag) then jump A | |
jnz -> 0x3A ; A -> if not (Zero Flag) then jump A | |
jmpr {addr} -> { | |
reladdr = addr - pc | |
assert(reladdr <= 0x7f) | |
assert(reladdr >= !0x7f) | |
0x3B @ reladdr[7:0] | |
} | |
jcr {addr} -> { | |
reladdr = addr - pc | |
assert(reladdr <= 0x7f) | |
assert(reladdr >= !0x7f) | |
0x3C @ reladdr[7:0] | |
} | |
jor {addr} -> { | |
reladdr = addr - pc | |
assert(reladdr <= 0x7f) | |
assert(reladdr >= !0x7f) | |
0x3D @ reladdr[7:0] | |
} | |
jzr {addr} -> { | |
reladdr = addr - pc | |
assert(reladdr <= 0x7f) | |
assert(reladdr >= !0x7f) | |
0x3E @ reladdr[7:0] | |
} | |
jncr {addr} -> { | |
reladdr = addr - pc | |
assert(reladdr <= 0x7f) | |
assert(reladdr >= !0x7f) | |
0x40 @ reladdr[7:0] | |
} | |
jnor {addr} -> { | |
reladdr = addr - pc | |
assert(reladdr <= 0x7f) | |
assert(reladdr >= !0x7f) | |
0x41 @ reladdr[7:0] | |
} | |
jnzr {addr} -> { | |
reladdr = addr - pc | |
assert(reladdr <= 0x7f) | |
assert(reladdr >= !0x7f) | |
0x42 @ reladdr[7:0] | |
} | |
nc -> 0x48 ; This is a prefix. if applied, the next | |
; instruction does not consume it's arguments. | |
; Magic! | |
rel -> 0x49 ; Makes a value on the stack relative to PC | |
; A -> PC + (signed byte)A | |
snip -> 0x4A ; A, B -> B; shorthand for offs 1 drop | |
offs {n} -> 0x5 @ n[3:0] | |
; Offset the next instruction's interaction | |
; with the stack by n | |
imm.6 {i} -> { | |
0b10 @ i[5:0] | |
} | |
imm.13 {i} -> { | |
0b110 @ i[12:0] | |
} | |
imm.16 {i} -> { | |
0b11100000 @ i[15:0] | |
} | |
} | |
#bank "bootrom" | |
boot: | |
imm.13 retstack | |
poploc rsp | |
imm.13 stack | |
poploc sp | |
imm.13 reset_alloc | |
call | |
jmpr pc | |
reset_alloc: | |
imm.13 200 ;X | |
imm.13 alloc_usage_buf ;X Y | |
imm.6 0 | |
imm.13 memset | |
jump ; tail call optimization | |
; call | |
; ret | |
memset: | |
; X Y FILL | |
poploc a | |
.lp: | |
inc | |
dup ; X Y Y | |
pushloc a ; X Y Y A | |
store ; X Y | |
offs 1 | |
dec | |
jnzr .lp | |
drop ; X | |
drop ; () | |
ret | |
; May want a microcoded memcpy | |
; OR, could spend time optimizing this | |
; but juggling stack is hard | |
memcpy: | |
; L = length | |
; X = source | |
; Y = dest | |
; L X Y | |
.lp: | |
nc | |
load ; L X Y [Y] | |
pick.i 2 ; L X Y [Y] X | |
store ; L X Y | [X] = [Y] | |
offs 2 | |
dec ; X Y L-1 | |
jzr .escape | |
offs 2 | |
inc ; Y L-1 X+1 | |
offs 2 | |
inc ; L-1 X+1 Y+1 | |
jmpr .lp | |
.escape: | |
ret | |
#bank "ram" | |
retstack: | |
; 32 entries | |
#res 0x0040 | |
stack: | |
; 1024 entries | |
#res 0x0800 | |
alloc_data: | |
alloc_usage_buf: | |
#res 200 ; 1600 bits, to mark 32-byte segments as in use. | |
memory: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment