// lib:
// print.dsa

// usage:
//
// include print "<relative path>""
//
// usage for print:
//      push (register containing address of string)
//      push pcx
//      jmp print::print
//
// usage for reset:
//      push pcx
//      jmp print::reset
//
// usage for clear:
//      push pcx
//      jmp print::clear
//
// usage for print_byte:
//      push (register containing byte)
//      push pcx
//      jmp print::print_byte
//
// usage for print_word:
//      push (register containing word)
//      push pcx
//      jmp print::print_word
//

include maths "../maths/core.dsa"

dw display: 0x20000
dw current: 0x20000

// ------------------------------------------
// prints the string at addr(arg[0]) to the screen.
print:
    push bpr
    mov spr, bpr

    ldw bpr, rg0, 8
    ldw current, rg1

_print_loop:
	ldb rg0, acc
	stb acc, rg1

	addi rg0, 1
	addi rg1, 1

    cmp acc, zero
	jne _print_loop
    jmp _end

// ------------------------------------------
// prints the value of arg[0] to the screen.
print_word:
    // initialise
    push bpr
    mov spr, bpr

    // load byte into acc
    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:
    push bpr
    mov spr, bpr

    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:
    push bpr
    mov spr, bpr

    ldw bpr, rg0, 8
    ldw current, rg1

    call _print_hex_byte
    jmp _end

// function body
_print_hex_byte:
    // mask to get lower nibble
    lli 0xF, rg2
    // save rg0 state
    push rg0

    shr rg0, 4
    and rg0, rg2, rg0
    call _print_hex_nibble
    pop rg0

    and rg0, rg2, rg0
    call _print_hex_nibble
    return

// print a hex digit
_print_hex_nibble:
    lli 10, rg3
    cmp rg0, rg3
    jlt _print_hex_nibble_number
    addi rg0, 0x37, rg0
    stb rg0, rg1
    addi rg1, 1
    return

// helper function.
_print_hex_nibble_number:
    addi rg0, 0x30, rg0
    stb rg0, rg1
    addi rg1, 1
    return

// ------------------------------------------
// print whitespace
print_whitespace:
    push bpr
    mov spr, bpr

    ldw current, rg1
    lli 0x20, rg0
    stb rg0, rg1
    addi rg1, 1
    jmp _end

// ------------------------------------------
// print newline
print_newline:
    push bpr
    mov spr, bpr

    // load variables into registers
    ldw display, rg0
    ldw current, rg1

    // get the offset from the display base
    sub rg1, rg0, rg0

    lwi 80, rg2
    pusha 3
    push rg0
    push rg2
    call maths::divmod
    pop zero  // result
    pop rg3 // remainder
    popa 3

    sub rg1, rg3, rg2
    addi rg2, 80, rg1

    // _end saves the display state
    jmp _end

// ------------------------------------------
// resets the cursor position on the screen to 0x20000. (0,0)
reset:
    push bpr
    mov spr, bpr
    ldw display, rg1
    jmp _end

// ------------------------------------------
// clears the screen
clear:
    push bpr
    mov spr, bpr
    // display size = 2000 bytes / 500 words
    lli 500 rg0
    ldw display, rg1

_clear_loop:
    dec rg0
    stw zero, rg1
    addi rg1, 4
    cmp rg0, zero
    jgt _clear_loop
    jmp _end

// ------------------------------------------
// return
_end:
    stw rg1, current

    mov bpr, spr
    pop bpr
    return
