; ==== symbols ====
; _print_hex_nibble        0x00000328  TEXT global
; increment                0x000000ec  TEXT global
; _clear_loop              0x000003ec  TEXT global
; end                      0x000000c0  TEXT global
; reset                    0x000003bc  TEXT global
; _print_end               0x00000288  TEXT global
; decrement                0x000000f4  TEXT global
; open_left                0x000001c8  TEXT global
; open_right               0x0000017c  TEXT global
; expr_end                 0x00000198  TEXT global
; newline                  0x00000378  TEXT global
; input                    0x0000013c  TEXT global
; loop_start               0x00000050  TEXT global
; loop_end                 0x000000e4  TEXT global
; _traverse_right          0x00000158  TEXT global
; dec_ptr                  0x0000010c  TEXT global
; expr_start               0x0000014c  TEXT global
; print_hex_byte           0x000002e4  TEXT global
; print_byte               0x000002b0  TEXT global
; success                  0x000009e8  DATA global
; data                     0x000005e8  DATA global
; error                    0x000005c4  DATA global
; clear                    0x000003d4  TEXT global
; _print_hex_byte          0x00000304  TEXT global
; _bf_reset_clear_data     0x00000208  TEXT global
; bf_reset                 0x000001e4  TEXT global
; _end                     0x00000404  TEXT global
; _traverse_left_start     0x000001a0  TEXT global
; _init                    0x00000000  TEXT global
; counter                  0x000005dc  DATA global
; _print_loop              0x0000026c  TEXT global
; print_whitespace         0x00000354  TEXT global
; inc_ptr                  0x000000fc  TEXT global
; current                  0x000009f8  DATA global
; _traverse_right_start    0x00000154  TEXT global
; print                    0x00000244  TEXT global
; init                     0x00000010  TEXT global
; stack                    0x000005e0  DATA global
; _traverse_left           0x000001a4  TEXT global
; start                    0x0000001c  TEXT global
; close_left               0x000001dc  TEXT global
; input_addr               0x000005e4  DATA global
; close_right              0x00000184  TEXT global
; display                  0x000009f4  DATA global
; _newline_done            0x000003b0  TEXT global
; program                  0x0000041c  DATA global
; _newline_mod             0x000003a0  TEXT global
; _print_hex_nibble_number 0x00000344  TEXT global
; output                   0x0000011c  TEXT global

; ==== data ====
    db "++++++++++++++++++++++++++++++++++++++++++++>++++++++++++++++++++++++++++++++>++++++++++++++++>>+<<[>>>>++++++++++<<[->+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]>[<+>-]>[-]>>>++++++++++<[->-[>+>>]>[+[-<+>]>+>>]<<<<<]>[-]>>[++++++++++++++++++++++++++++++++++++++++++++++++.[-]]<[++++++++++++++++++++++++++++++++++++++++++++++++.[-]]<<<++++++++++++++++++++++++++++++++++++++++++++++++.[-]<<<<<<<.>.>>[>>+<<-]>[>+<<+>-]>[<+>-]<<<-]<<++..."
    db "Invalid Instruction!"
    dw 0x00000000
    dw 0x000000ff
    dw 0x00000000
    dw 0x00000001
    dw 0x00000003
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    dw 0x00000000
    db "Success!"
    dw 0x00000000
    dw 0x00000000
    dw 0x00000002
    dw 0x00000002

; ==== text ====
_init:
    ldw stack, Bpr, 0x0000
    mov Bpr, Spr
init:
    ldw counter, Rg7, 0x0000
start:
    call bf_reset
    lwi program, Rg0
    lwi data, Rg1
    lli Rg8, 0x002b
    lli Rg9, 0x002d
    lli Rga, 0x003e
    lli Rgb, 0x003c
    lli Rgc, 0x002e
    lli Rgd, 0x002c
    lli Rge, 0x005b
    lli Rgf, 0x005d
loop_start:
    ldb Rg0, Rg3, 0x0000
    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
    lwi error, Rg2
    push Rg0
    push Rg1
    push Rg2
    call print
    pop Zero
    pop Rg1
    pop Rg0
end:
    call newline
    lwi success, Rg0
    push Rg0
    call print
    pop Zero
    subi Rg7, Rg7, 0x0001
    jnz Rg7, start
    hlt
loop_end:
    addi Rg0, Rg0, 0x0001
    jmp loop_start
increment:
    addi Rg2, Rg2, 0x0001
    jmp loop_end
decrement:
    subi Rg2, Rg2, 0x0001
    jmp loop_end
inc_ptr:
    stw Rg2, Rg1, 0x0000
    addi Rg1, Rg1, 0x0004
    ldw Rg1, Rg2, 0x0000
    jmp loop_end
dec_ptr:
    stw Rg2, Rg1, 0x0000
    subi Rg1, Rg1, 0x0004
    ldw Rg1, Rg2, 0x0000
    jmp loop_end
output:
    push Rg0
    push Rg1
    push Rg2
    call print_byte
    pop Zero
    pop Rg1
    pop Rg0
    jmp loop_end
input:
    ldw input_addr, Rg2, 0x0000
    jmp loop_end
expr_start:
    ieq Rg2, Zero, Rg4
    jez Rg4, loop_end
_traverse_right_start:
    push Rg8
_traverse_right:
    addi Rg0, Rg0, 0x0001
    ldb Rg0, Rg3, 0x0000
    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
    jmp _traverse_right
close_right:
    pop Rg4
    ieq Rg4, Zero, Rg5
    jnz Rg5, _traverse_right
    addi Rg0, Rg0, 0x0001
    jmp loop_start
expr_end:
    ieq Rg2, Zero, Rg4
    jnz Rg4, loop_end
_traverse_left_start:
    push Rg8
_traverse_left:
    subi Rg0, Rg0, 0x0001
    ldb Rg0, Rg3, 0x0000
    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:
    pop Rg4
    ieq Rg4, Zero, Rg5
    jnz Rg5, _traverse_left
    addi Rg0, Rg0, 0x0001
    jmp loop_start
close_left:
    push Zero
    jmp _traverse_left
bf_reset:
    push Bpr
    mov Spr, Bpr
    push Rg0
    push Rg1
    call clear
    call reset
    lli Rg0, 0x0100
    lwi data, Rg1
_bf_reset_clear_data:
    subi Rg0, Rg0, 0x0001
    stw Zero, Rg1, 0x0000
    addi Rg1, Rg1, 0x0004
    igt Rg0, Zero, Rg4
    jnz Rg4, _bf_reset_clear_data
    pop Rg1
    pop Rg0
    lwi program, Rg0
    lwi data, Rg1
    lli Rg2, 0x0000
    mov Bpr, Spr
    pop Bpr
    ret
print:
    push Bpr
    mov Spr, Bpr
    push Rg0
    push Rg1
    push Rg2
    push Rg3
    ldw Bpr, Rg0, 0x0008
    ldw current, Rg1, 0x0000
_print_loop:
    ldb Rg0, Rg2, 0x0000
    ieq Rg2, Zero, Rg3
    jnz Rg3, _print_end
    stb Rg2, Rg1, 0x0000
    addi Rg0, Rg0, 0x0001
    addi Rg1, Rg1, 0x0001
    jmp _print_loop
_print_end:
    stw current, Rg1, 0x0000
    pop Rg3
    pop Rg2
    pop Rg1
    pop Rg0
    mov Bpr, Spr
    pop Bpr
    ret
print_byte:
    push Bpr
    mov Spr, Bpr
    push Rg0
    push Rg1
    ldw Bpr, Rg0, 0x0008
    ldw current, Rg1, 0x0000
    stb Rg0, Rg1, 0x0000
    addi Rg1, Rg1, 0x0001
    pop Rg1
    pop Rg0
    jmp _end
print_hex_byte:
    push Bpr
    mov Spr, Bpr
    ldw Bpr, Rg0, 0x0008
    ldw current, Rg1, 0x0000
    call _print_hex_byte
    jmp _end
_print_hex_byte:
    lli Rg2, 0x000f
    push Rg0
    shr Rg0, Rg0, Zero, 4
    and Rg0, Rg2, Rg0
    call _print_hex_nibble
    pop Rg0
    and Rg0, Rg2, Rg0
    call _print_hex_nibble
    ret
_print_hex_nibble:
    lli Rg3, 0x000a
    ilt Rg0, Rg3, Rg4
    jnz Rg4, _print_hex_nibble_number
    addi Rg0, Rg0, 0x0037
    stb Rg0, Rg1, 0x0000
    addi Rg1, Rg1, 0x0001
    ret
_print_hex_nibble_number:
    addi Rg0, Rg0, 0x0030
    stb Rg0, Rg1, 0x0000
    addi Rg1, Rg1, 0x0001
    ret
print_whitespace:
    push Bpr
    mov Spr, Bpr
    ldw current, Rg1, 0x0000
    lli Rg0, 0x0020
    stb Rg0, Rg1, 0x0000
    addi Rg1, Rg1, 0x0001
    jmp _end
newline:
    push Bpr
    mov Spr, Bpr
    ldw display, Rg0, 0x0000
    ldw current, Rg1, 0x0000
    sub Rg1, Rg0, Rg2
    lli Rg3, 0x0050
_newline_mod:
    ilt Rg2, Rg3, Rg4
    jnz Rg4, _newline_done
    sub Rg2, Rg3, Rg2
    jmp _newline_mod
_newline_done:
    sub Rg1, Rg2, Rg1
    addi Rg1, Rg1, 0x0050
    jmp _end
reset:
    push Bpr
    mov Spr, Bpr
    ldw display, Rg1, 0x0000
    jmp _end
clear:
    push Bpr
    mov Spr, Bpr
    lli Rg0, 0x01f4
    ldw display, Rg1, 0x0000
_clear_loop:
    subi Rg0, Rg0, 0x0001
    stw Zero, Rg1, 0x0000
    addi Rg1, Rg1, 0x0004
    igt Rg0, Zero, Rg4
    jnz Rg4, _clear_loop
    jmp _end
_end:
    stw current, Rg1, 0x0000
    mov Bpr, Spr
    pop Bpr
    ret
