dw uart: 0x40000 // ------------------------------------------ // reads up to rg1 bytes into buffer at rg2 // args: buf_size @ bpr+8, buf_addr @ bpr+12 // returns: 0 in bpr+8 on success, 1 on nullptr error buf_read: func push rg0 push rg1 push rg2 push rg3 ldw bpr, rg1, 8 // buf size ldw bpr, rg2, 12 // buf addr jez rg2, _buf_read_err // return err if nullptr _buf_read_loop: jez rg1, _buf_read_end call read_byte ldw bpr, rg3, 8 // read return value from frame stb rg3, rg2 // store into buffer addi rg2, 1, rg2 subi rg1, 1, rg1 jmp _buf_read_loop _buf_read_end: stw zero, bpr, 8 // return 0 (success) pop rg3 pop rg2 pop rg1 pop rg0 return _buf_read_err: lli 1, rg0 stw rg0, bpr, 8 // return 1 (error) pop rg3 pop rg2 pop rg1 pop rg0 return // read_byte: emulator → kernel // reads data from base+0x00, valid flag at base+0x01 read_byte: func push rg0 push rg1 push rg2 ldw uart, rg1 _serial_read_wait: ldb rg1, rg0, 1 // base+0x01 = read valid flag lli 0x01, rg2 ieq rg0, rg2, rg2 jnz rg2, _serial_read_ready hlt jmp _serial_read_wait _serial_read_ready: ldb rg1, rg0, 0 // base+0x00 = data byte stb zero, rg1, 1 // clear read valid flag stb rg0, bpr, 8 // return byte pop rg2 pop rg1 pop rg0 return // _serial_send: kernel → emulator // writes data to base+0x02, valid flag to base+0x03 _serial_send: push rg0 push rg2 push rg3 push rg4 push rg5 ldw uart, rg5 _serial_wait: ldb rg5, rg2, 3 // base+0x03 = write valid flag lli 0x01, rg3 ieq rg2, rg3, rg4 jnz rg4, _serial_wait // wait while emulator hasn't consumed yet stb rg0, rg5, 2 // base+0x02 = data byte lli 0x01, rg2 stb rg2, rg5, 3 // base+0x03 = set valid flag pop rg5 pop rg4 pop rg3 pop rg2 pop rg0 ret // ------------------------------------------ // prints the null-terminated string at addr(arg[0]) print: func push rg0 push rg1 push rg2 ldw bpr, rg0, 8 // load string address from arg _serial_print_loop: ldb rg0, rg1 // load byte ieq rg1, zero, rg2 // null terminator? jnz rg2, _serial_print_end push rg0 // save string pointer mov rg1, rg0 call _serial_send pop rg0 addi rg0, 1, rg0 jmp _serial_print_loop _serial_print_end: pop rg2 pop rg1 pop rg0 jmp _serial_end // ------------------------------------------ // prints the last byte of arg[0] print_byte: func push rg0 ldw bpr, rg0, 8 call _serial_send pop rg0 jmp _serial_end // ------------------------------------------ _serial_end: return