progress: new assembler works, instruction set fully implemented with call/ret and push/pop, bf.dsa works which means the dsa assembly language works reliably. still a few bugs to fix. might be able to squeeze out a tiny bit more performance

This commit is contained in:
2026-03-09 03:24:20 +00:00
parent fc972b9b7b
commit e01a9f2808
63 changed files with 4975 additions and 1579 deletions
+19
View File
@@ -0,0 +1,19 @@
include print: "./print.dsa"
db msg: "hello world"
dw stack: 0x1000
_init:
ldw stack, bpr
mov bpr, spr
lwi 1000000, rg5
_loop:
call print::reset
lwi msg, rg0
push rg0
call print::print
pop zero
subi rg5, 1, rg5
igt rg5, zero, rg4
jnz rg4, _loop
hlt
+227
View File
@@ -0,0 +1,227 @@
// a simple brainf##k interpreter,
// because I already wrote a compiler lol.
include print "./print.dsa"
// "print hello world"
db program: "++++++++++++++++++++++++++++++++++++++++++++
>++++++++++++++++++++++++++++++++
>++++++++++++++++
>
>+
<<
[
>>
>
>++++++++++
<<
[->+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]
>[<+>-]
>[-]
>>
>++++++++++
<
[->-[>+>>]>[+[-<+>]>+>>]<<<<<]
>[-]
>>[++++++++++++++++++++++++++++++++++++++++++++++++.[-]]
<[++++++++++++++++++++++++++++++++++++++++++++++++.[-]]
<<<++++++++++++++++++++++++++++++++++++++++++++++++.[-]
<<<<<<<.>.
>>[>>+<<-]
>[>+<<+>-]
>[<+>-]
<<<-
]
<<++..."
db error: "Invalid Instruction!"
dw stack: 0x10000
dw input: 0x30000
resb data: 1024
// set up a stack so we can call functions
_init_stack:
ldw stack, bpr
mov bpr, spr
start:
// load the start of the program into rg0
lwi program, rg0
lwi data, rg1
// rg0 is our instruction pointer
// rg1 is our data pointer
// rg2 is the value at the data pointer
// rg3 stores the current instruction
// rg4 is the expression nesting level.
lli 43, rg8 // + = 43 increment
lli 45, rg9 // - = 45 decrement
lli 62, rga // > = 62 increment pointer
lli 60, rgb // < = 60 decrement pointer
lli 46, rgc // . = 46 output
lli 44, rgd // , = 44 input
lli 91, rge // [ = 91 loop start
lli 93, rgf // ] = 93 loop end
loop_start:
// load the current instruction into rg3
ldb rg0, rg3
// switch on the instruction
ieq rg3, rg8, rg4
jnz rg4, increment
ieq rg3, rg9, rg4
jnz rg4, decrement
ieq rg3, rga, rg4
jnz rg4, inc_ptr
ieq rg3, rgb, rg4
jnz rg4, dec_ptr
ieq rg3, rgc, rg4
jnz rg4, output
ieq rg3, rgd, rg4
jnz rg4, input
ieq rg3, rge, rg4
jnz rg4, expr_start
ieq rg3, rgf, rg4
jnz rg4, expr_end
ieq rg3, zero, rg4
jnz rg4, end
// if we get here, we don't know what the instruction is
lwi error, rg2
push rg0
push rg1
push rg2
call print::print
pop zero
pop rg1
pop rg0
end:
hlt
loop_end:
addi rg0, 1, rg0
jmp loop_start
// ------------------------------------------
// increment the current cell
increment:
addi rg2, 1, rg2
jmp loop_end
// ------------------------------------------
// decrement the current cell
decrement:
subi rg2, 1, rg2
jmp loop_end
// ------------------------------------------
// increment the pointer
inc_ptr:
stw rg2, rg1
addi rg1, 4
ldw rg1, rg2
jmp loop_end
// ------------------------------------------
// decrement the pointer
dec_ptr:
stw rg2, rg1
subi rg1, 4
ldw rg1, rg2
jmp loop_end
// ------------------------------------------
// print the byte in the current cell
output:
push rg0
push rg1
push rg2
call print::print_byte
pop zero
pop rg1
pop rg0
jmp loop_end
// ------------------------------------------
// read a byte into the current cell
input:
ldw input, rg2
jmp loop_end
// ------------------------------------------
// handle an open bracket instruction
expr_start:
ieq rg2, zero, rg4
jez rg4, loop_end
_traverse_right_start:
// push a register that definitely has a nonzero value
// when we pop this value from the stack
// we know we've finished traversing.
push rg8
_traverse_right:
addi rg0, 1, rg0
ldb rg0, rg3
ieq rg3, rge, rg4
jnz rg4, open_right
ieq rg3, rgf, rg4
jnz rg4, close_right
ieq rg3, zero, rg4
jnz rg4, end
jmp _traverse_right
open_right:
// push zero to the stack
push zero
jmp _traverse_right
close_right:
// check if we've reached the bottom of the stack
pop rg4
ieq rg4, zero, rg5
jnz rg5, _traverse_right
// go to next instruction after closing bracket
addi rg0, 1, rg0
jmp loop_start
// ------------------------------------------
// handle the close bracket instruction
expr_end:
ieq rg2, zero, rg4
jnz rg4, loop_end
_traverse_left_start:
push rg8
_traverse_left:
subi rg0, 1, rg0
ldb rg0, rg3
ieq rg3, rge, rg4
jnz rg4, open_left
ieq rg3, rgf, rg4
jnz rg4, close_left
ieq rg3, zero, rg4
jnz rg4, end
jmp _traverse_left
open_left:
// check if we've reached the bottom of the stack
pop rg4
ieq rg4, zero, rg5
jnz rg5, _traverse_left
// go to next instruction after open bracket
addi rg0, 1, rg0
jmp loop_start
close_left:
// push zero to the stack
push zero
jmp _traverse_left
Binary file not shown.
+292
View File
@@ -0,0 +1,292 @@
// lib:
// print.dsa
// usage:
//
// include print "<relative path>"
//
// usage for print:
// push (register containing address of string)
// call print::print
//
// usage for reset:
// call print::reset
//
// usage for clear:
// call print::clear
//
// usage for print_byte:
// push (register containing byte)
// call print::print_byte
//
// usage for print_word:
// push (register containing word)
// call print::print_word
//
// usage for print_num:
// push (register containing number to print in decimal)
// call print::print_num
//
dw display: 0x20000
dw current: 0x20000
// ------------------------------------------
// prints the string at addr(arg[0]) to the screen.
print: func
ldw bpr, rg0, 8
ldw current, rg1
_print_loop:
ldb rg0, rg2
ieq rg2, zero, rg4
jnz rg4, _end
stb rg2, rg1
addi rg0, 1
addi rg1, 1
jmp _print_loop
// ------------------------------------------
// println:
// push bpr
// mov spr, bpr
// ldw bpr, rg0, 8
// ldw current, rg1
// _println_loop:
// ldb rg0, acc
// ieq acc, zero, rg4
// jnz rg4, _println_end
// stb acc, rg1
// addi rg0, 1
// addi rg1, 1
// jmp _println_loop
// _println_end:
// call print_newline
// jmp _end
// ------------------------------------------
// prints the value of arg[0] to the screen.
// print_word:
// push bpr
// mov spr, bpr
// ldw bpr, rg0, 8
// ldw current, rg1
// addi rg1, 3
// stb rg0, rg1
// subi rg1, 1
// shr rg0, 8
// stb rg0, rg1
// subi rg1, 1
// shr rg0, 8
// stb rg0, rg1
// subi rg1, 1
// shr rg0, 8
// stb rg0, rg1
// addi rg1, 4
// jmp _end
// ------------------------------------------
// prints the last byte of arg[0] to the screen.
print_byte: func
ldw bpr, rg0, 8
ldw current, rg1
stb rg0, rg1
addi rg1, 1
jmp _end
// ------------------------------------------
// prints the value of arg[0] to the screen in hex.
// print_hex_word:
// push bpr
// mov spr, bpr
// ldw current, rg1
// ldb bpr, rg0, 8
// push rg0
// call _print_hex_byte
// addi spr, 4
// ldb bpr, rg0, 9
// push rg0
// call _print_hex_byte
// addi spr, 4
// ldb bpr, rg0, 10
// push rg0
// call _print_hex_byte
// addi spr, 4
// ldb bpr, rg0, 11
// push rg0
// call _print_hex_byte
// addi spr, 4
// jmp _end
// ------------------------------------------
// prints the last byte of arg[0] to the screen in hex.
print_hex_byte: func
ldw bpr, rg0, 8
ldw current, rg1
call _print_hex_byte
jmp _end
// function body
_print_hex_byte:
lli 0xF, rg2
push rg0
shr rg0, 4
and rg0, rg2, rg0
call _print_hex_nibble
pop rg0
and rg0, rg2, rg0
call _print_hex_nibble
ret
// print a hex digit
_print_hex_nibble:
lli 10, rg3
ilt rg0, rg3, rg4
jnz rg4, _print_hex_nibble_number
addi rg0, 0x37, rg0
stb rg0, rg1
addi rg1, 1
ret
// helper function.
_print_hex_nibble_number:
addi rg0, 0x30, rg0
stb rg0, rg1
addi rg1, 1
ret
// ------------------------------------------
// print whitespace
print_whitespace: func
ldw current, rg1
lli 0x20, rg0
stb rg0, rg1
addi rg1, 1
jmp _end
// // ------------------------------------------
// // print newline
// print_newline:
// push bpr
// mov spr, bpr
// ldw display, rg0
// ldw current, rg1
// sub rg1, rg0, rg0
// lwi 80, rg2
// push rg0
// push rg1
// push rg2
// push rg0
// push rg2
// call maths::divmod
// pop zero // result
// pop rg3 // remainder
// pop rg0
// pop rg1
// pop rg2
// sub rg1, rg3, rg2
// addi rg2, 80, rg1
// jmp _end
// ------------------------------------------
// prints arg[0] as a decimal number to the screen.
// print_num:
// push bpr
// mov spr, bpr
// ldw bpr, rg0, 8
// lli 0, rg5
// ieq rg0, zero, rg4
// jez rg4, _print_num_extract_digits
// lli 0x30, rg6
// push rg6
// lli 1, rg5
// jmp _print_num_output
// _print_num_extract_digits:
// ieq rg0, zero, rg4
// jnz rg4, _print_num_output
// push rg0
// lli 10, rg1
// push rg1
// call maths::divmod
// pop rg0 // quotient
// pop rg1 // remainder
// addi rg1, 0x30, rg6
// push rg6
// inc rg5
// jmp _print_num_extract_digits
// _print_num_output:
// ldw current, rg1
// _print_num_output_loop:
// ieq rg5, zero, rg4
// jnz rg4, _print_num_done
// pop rg6
// stb rg6, rg1
// addi rg1, 1
// dec rg5
// jmp _print_num_output_loop
// _print_num_done:
// jmp _end
// ------------------------------------------
// resets the cursor position to 0x20000 (0,0)
reset: func
ldw display, rg1
jmp _end
// ------------------------------------------
// clears the screen
clear: func
lli 500, rg0
ldw display, rg1
_clear_loop:
subi rg0, 1, rg0
stw zero, rg1
addi rg1, 4
igt rg0, zero, rg4
jnz rg4, _clear_loop
jmp _end
// ------------------------------------------
// return — saves current, restores frame, returns
_end:
stw rg1, current
return