Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
581 lines (400 sloc) 11.6 KB
;7 3 0$nandi ; Should be -4
;4 12 0$andi ; Should be 4
;0 0$noti ; Should be -1 (all ones)
;8 4 0$ori ; Should be 12
;8 12 0$xori ; Should be 4
;255 0$lshiftilone ; Should be 510
;9 128 0$addi ; Should be 137
;37 12 0$subi ; Should be 25
;2 2 2 42 3 0$seti
;1 2 0$lshiftil ; Should be 4
;6 0$rshiftilone
;12 1 0$rshiftil
;3 4 0$iseqi ; Should be 0
;42 0$pushbytetoheapi ; The value "42" should be on the heap
;"hello" 1 0$stackstrlen ; Should return 5
;10 "Hello, world!" 2 15 0$print
;10 2 1 0$print
;10 "Blarb." 2 8 0$print
;10 'a' 2 2 0$print ; Should print "a\n"
;"Hello, Blarb!" 0$printline
;"hello" 1 0$pushstringtoheap
;"test.txt" 0 0 0$openwithname
;0$closedescriptor
;0 0$readchar ; Reads a single character from stdin
;5 0$brki
;1284 3487 0$multiplyi
;40 2 0$isgei
0 0$exit
; ANDs the two immediate values
; Circuit: (A NAND B) NAND (A NAND B)
#andi
4 3 ! ; A NAND B
4 4 !
2 0 ~ 2^ ; Pop the stack frame
; NANDs the two immediate values
#nandi
4 3 ! ; Nand it up
2 1 ~ 2^ 1$ ; Get rid of extra argument
2 0 ~ 1^ ; return
; NOTs the immediate value
; Circuit: A NAND A
#noti
3 3 ! ; NAND the arg with itself
2 0 ~ 1^
; ORs the two immediate values
; Circuit: (A NAND A) NAND (B NAND B)
#ori
4 4 !
3 3 !
4 3 !
2 0 ~ 2^
; XORs the two immediate values
; Circuit: (A NAND B) AND (A OR B)
#xori
4 1 ~ 1$ ; Copy A
2 4 ! ; A NAND B
1$ 5 2 ~ 2$ ; Copy A and B
3 3 ! 2 2 ! 3 2 ! 1^ ; A OR B
3 2 ! 3 3 ! 1^ ; AND the two values on the stack
2 1 ~ 3 0 ~ 4^ 1$ ; Return the stored result
; Pushes a null-terminated bitmask list to the stack
#pushincreasingbitmasklist
2 0 ~ 1^ 0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152 4194304 8388608 16777216 33554432 67108864 134217728 268435456 536870912 1073741824 2147483648 4294967296 8589934592 17179869184 34359738368 68719476736 137438953472 274877906944 549755813888 1099511627776 2199023255552 4398046511104 8796093022208 17592186044416 35184372088832 70368744177664 140737488355328 281474976710656 562949953421312 1125899906842624 2251799813685248 4503599627370496 9007199254740992 18014398509481984 36028797018963968 72057594037927936 144115188075855872 288230376151711744 576460752303423488 1152921504606846976 2305843009213693952 4611686018427387904 9223372036854775808
#rshiftilone
0$pushincreasingbitmasklist
68 1 ~ 1$ ; Copy of the param
0 ; Accumulator
#rshiftiloneloop
4? rshiftilonerun
6 0 ~ 2 1 ~ 6^ 1$; Return the accumulator
#rshiftilonerun
; Check if the bit is set (a new boolean will be on the stack)
4 1 ~ 1$
4 1 ~ 1$
0$andi
4 1 ~ 3 2 ~ 2 3 ~ 4^ 1$ 2$ 3$ ; Remove the top-most list elements
1? 1^ rshiftiloneaddtoaccumulator
1^ rshiftiloneloop
#rshiftiloneaddtoaccumulator
4 1 ~ 1$ 0$ori ; Add next bit to the accumulator
rshiftiloneloop
; A B rshiftil -> A shifted right by B bits
#rshiftil
4 1 ~ 1$ ; Parameter A (the value to shift)
4 1 ~ 1$ ; Decrementor B
#rshiftilloop
1? rshiftilrun
4 0 ~ 3 1 ~ 5^ 1$ ; Return the value when the decrementor hits 0
#rshiftilrun
1 0$subi ; Decrement
; Perform the shift
3 1 ~ 1$ 0$rshiftilone
2 1 ~ 3 2 ~ 3^ 1$ 2$
rshiftilloop
#lshiftilone
0$pushincreasingbitmasklist
0
69 1 ~ 1$ ; Copy of the param
#lshiftiloneloop
3? lshiftilonerun
; At this point, there will just be 0,1,<returnvalue> on the stack
2 1 ~
5 0 ~ 5^ 1$
#lshiftilonerun
; Check if the bit is set (a new boolean will be on the stack)
2 1 ~ 1$
5 1 ~ 1$
0$andi
; Copy the mutating return value
3 1 ~ 1$
6 1 ~ 1$ 0$noti ; Invert the next single bit mask
0$andi ; unset the next bit
; Set the next bit if the above boolean is true
2? 5 1 ~ 1$ 0$ori
; Pop n drop!
2 1 ~ 4^ 1$
lshiftiloneloop
; A B lshiftil -> A shifted right by B bits
#lshiftil
4 1 ~ 1$ ; Parameter A (the value to shift)
4 1 ~ 1$ ; Decrementor B
#lshiftilloop
1? lshiftilrun
4 0 ~ 3 1 ~ 5^ 1$ ; Return the value when the decrementor hits 0
#lshiftilrun
1 0$subi ; Decrement
; Perform the shift
3 1 ~ 1$ 0$lshiftilone
2 1 ~ 3 2 ~ 3^ 1$ 2$
lshiftilloop
; Recursive adder
#addi
2? add_continue
; Base case: If the param B is 0, return param A by itself.
4 1 ~ 2 0 ~ 3^ 1$
#add_continue
4 1 ~ 1$ ; Copy A and B
4 1 ~ 1$
0$xori ; "sum" bit's, excluding carries.
5 1 ~ 1$ ; Copy A and B again
5 1 ~ 1$
0$andi ; Carry bits
0$lshiftilone ; Shift the carry bits before recursing
0$addi ; Recurse, with only the carry bits.
2 1 ~
3 0 ~ 4^ 1$
; Subtract: A B subi -> A - B
#subi
; Two's compliment of B
3 1 ~ 1 $ 0$noti
1 0$addi
5 1 ~ 1$ ; A
0$addi ; A - B
2 1 ~
3 0 ~ 4^ 1$
; Multiple two immediate values together
; Note: This "does not care" about negative numbers
; This algorithm is trivial.
; It will add the first number to itself, while decrementing the second number.
; If the second number starts out at 0, this returns 0, as expected.
#multiplyi
; A B ReturnAddress
0 ; Accumulator (start at 0)
3 0$copy ; Decrementor (Copy of second parameter)
#multiplyicheckfor0
1? multiplyiloop
; Return the result if the second parameter reaches 0
3 1 ~ 4 0 ~ 5^ 1$
#multiplyiloop
1 0$subi ; Subtract from the decrementor.
5 0$copy ; First param
3 0$copy ; Accumulator
0$addi ; Add them
3 0$seti ; Set the accumulator to the result
multiplyicheckfor0
; Usage: index copy
; Copies the word on the stack at "index" to the top of the stack
#copy
3 1 ~ 1$ 3 0$addi ; index
1 ~ 2 0 ~ 2^ 1$
; Usage: I1 I2 swap
; Swaps the contents of the two given stack indices (I1 and I2)
#swap
; Get first element
3 0$copy
2 0$addi
0$copy
; Get second element
3 0$copy
3 0$addi
0$copy
; Set first element
5 0$copy
4 0$addi
0$seti
; Set second element
3 0$copy
3 0$addi
0$seti
2 0 ~ 3^
; Usage: value index seti
; Set's a word on the stack (at "index") to "value"
#seti
3 0$copy ; value
3 0$copy ; index
5 0$addi
1 0$copy
0 ! ; Set the value at the given index to all 1s
1 0$copy
3 ! ; At this point, the stack var is the inverse of what it should be
1 0$subi
1 0$copy
!
3 0 ~ 4^
; A jumpi -> jump by A lines
#jumpi
0$addi
2 0 ~ 1^
; Checks if two numbers are equal
; Returns 1 if they are equal, 0 if not.
#iseqi
3 0$copy
3 0$copy
0$xori
1? 3 0 ~ 4^ 0
3 0 ~ 4^ 1
; Checks if A >= B
#isgei
3 0$copy
3 0$copy
0$subi
; Check if the highest bit is set (if the result is negative)
9223372036854775808 0$andi
1? 3 0 ~ 4^ 0 ; Return 0
3 0 ~ 4^ 1 ; Return 1
#tobooli
2? 2 0 ~ 2^ 1
2 0 ~ 2^ 0
; B brki; new brk endpoint B (or 0)
#brki
3 1 ~
0 0 0 0 0 1$ 12 % ; brk it up
3 0 ~ 2 1 ~ 3^ 1$
; Usage: B pushbytetoheapi
; Pushes byte B to the heap
#pushbytetoheapi
; Extend the breakpoint
0 0$brki
1 0$addi
0$brki
1 0$subi
4 2 = ; Set the heap value to the byte parameter
3 0 ~ 3^
; B stackstrlen Push the length of the string at stack index B
#stackstrlen
2 0$copy ; Starting stack index
3 0$addi ; Offset from the return address
#stackstrlenloop
; If the value at the pointer is null, return!
1 0$copy
0$copy
1? 1^ stackstrlenrun
1^
; Difference between initial string pointer and the end
3 0$copy
3 0$addi
0$subi
2 1 ~
3 0 ~ 3^ 1$
#stackstrlenrun
; Increment the string pointer
1 0$addi
stackstrlenloop
; I L pushbytearraytoheap
; Copy array of length L at index I to the heap
; Returns the initial array index breakpoint
#pushbytearraytoheap
0 0$brki
3 0$copy ; The length of the array (L)
0$addi
0$brki ; Allocate memory for the byte array
1^
; New initial breakpoint (it may have changed address)
0 0$brki
3 0$copy
0$subi
1 0$copy ; A following pointer (for byte copying)
#pushbytearraytoheaploop
; On the stack at this point, just the initial breakpoint.
; If L is non-zero, copy the next pointer byte and loop again
4? pushbytearraytoheaprun
; If L is 0, terminate and return the initial breakpoint.
3 1 ~
4 0 ~ 5^ 1$
#pushbytearraytoheaprun
5 0$copy ; I
4 0$addi ; Stack offset from this function
0$copy ; Copy so we don't destroy stack content
2 3 = ; Swap the byte to the heap
1^
1 0$addi ; Increment the pointer
; Increment I
5 0$copy
1 0$addi
6 0$seti
; Decrement L
4 0$copy
1 0$subi
5 0$seti
pushbytearraytoheaploop
; Pushes the string at the given stack index to the heap (no null byte)
; Returns the heap memory address
#pushstringtoheap
2 0$copy
2 0$addi ; Offset the index because of the local vars
0$stackstrlen
; The index, again
3 0$copy
3 0$addi
; Swap the stack vars, since the stack index is on the top now
2 1 ~ 3 2 ~ 2^ 1$ 2$
; At this point, INDEX and SIZE should be on the stack
0$pushbytearraytoheap
; Now it's just the heap address - so we return that
1 2 ~
3 0 ~ 3^ 1$
; FIXME this is broken
; Takes a single argument: The file descriptor to read from.
#readchar
0 0$brki ; Get the current heap address
1 0$addi
0$brki ; Extend it by one byte
1 0$subi
2 1 ~
4 2 ~; File descriptor argument
; Read syscall is 0
0 0 0 1 1$ 2$ 0 %
1^ ; Pop the return status (ignore it for now)
0 2 3 =; Swap the heap byte out with a 0, so it's on the stack now
2 0$copy
0$brki ; Deallocate the buffer
3 1 ~
5 0 ~ 5^ 1$
; Prints the array at the given index
; A B print - Prints the array at index A of length B
#print
3 0$copy ; Index
3 0$addi
3 0$copy ; Length
0$pushbytearraytoheap ; Replaces index and length with a heap pointer
3 0$copy
; Length in reg 1 and pointer in reg 2
2 1 ~ 3 2 ~
; Print from the heap
0 0 0 1$ 2$ 1 1 %
3 0$copy ; Pointer to the beginning of the string (on the heap)
0$brki ; Deallocate the string, now that we are done printing.
6 0 ~ 7^
; Shortcut to print a line (with a newline) and pop the string
; "str" printline - Prints the null terminated <str>
#printline
2 0$stackstrlen
4
2 0$copy
0$print
; Print a newline
10 2 1 0$print
1^
; Pop the length of the string, plus stack vars, plus null byte
3 0$addi
2 1 ~
3 0 ~ 1$ ^
; Open a file and return a descriptor number
; e.g. "test.txt" FLAGS MODE openwithname
; mode 0 is read only (see Linux "open" syscall docs)
#openwithname
4 0$pushstringtoheap
0 0$pushbytetoheapi ; the open syscall needs a null termination
2 1 ~ ; name
5 2 ~ ; flags
4 3 ~ ; mode
; Now we have a pointer to that string on the stack
0 0 0 3$ 2$ 1$ 2 %
2 0$copy ; Pointer to the beginning of the string (on the heap)
0$brki ; Deallocate the string, now that we are done printing.
; Figure out the string length and pop em' all!
7 0$stackstrlen
7 0$addi
4 2 ~ ; Store the file descriptor value, so we can return it
6 0 ~ ^ 2$
; Close the give descriptor
; Returns nothing (but really... we should return a status)
#closedescriptor
3 1 ~ ; Store the descriptor number for sanity
0 0 0 0 0 1$ 3 %
; Note: The syscall operater returns a status - we assume it works :)
3 0 ~ 3^
#exit
3 1~
0 0 0 0 0 1$ 60 % 3^