2019-04-22 22:41:37 -04:00
|
|
|
; stdio
|
|
|
|
;
|
2019-07-13 09:19:01 -04:00
|
|
|
; Allows other modules to print to "standard out", and get data from "standard
|
2019-06-02 10:50:18 -04:00
|
|
|
; in", that is, the console through which the user is connected in a decoupled
|
|
|
|
; manner.
|
2019-04-22 22:41:37 -04:00
|
|
|
;
|
2019-11-04 09:55:12 -05:00
|
|
|
; Those GetC/PutC routines are hooked through defines and have this API:
|
2019-11-03 20:32:27 -05:00
|
|
|
;
|
|
|
|
; GetC: Blocks until a character is read from the device and return that
|
|
|
|
; character in A.
|
|
|
|
;
|
2019-11-04 10:04:09 -05:00
|
|
|
; PutC: Write character specified in A onto the device.
|
2019-11-03 20:32:27 -05:00
|
|
|
;
|
2019-11-04 10:12:17 -05:00
|
|
|
; *** Accepted characters ***
|
|
|
|
;
|
|
|
|
; For now, we're in muddy waters in this regard. We try to stay close to ASCII.
|
|
|
|
; Anything over 0x7f is undefined. Both CR and LF are interpreted as "line end".
|
|
|
|
; Both BS and DEL mean "delete previous character".
|
|
|
|
;
|
|
|
|
; When outputting, newlines are marked by CR and LF. Outputting a character
|
|
|
|
; deletion is made through BS then space then BS.
|
|
|
|
;
|
2019-11-04 09:55:12 -05:00
|
|
|
; *** Defines ***
|
|
|
|
; STDIO_GETC: address of a GetC routine
|
|
|
|
; STDIO_PUTC: address of a PutC routine
|
2019-11-13 20:38:06 -05:00
|
|
|
;
|
2019-07-13 09:19:01 -04:00
|
|
|
; *** Consts ***
|
|
|
|
; Size of the readline buffer. If a typed line reaches this size, the line is
|
|
|
|
; flushed immediately (same as pressing return).
|
|
|
|
.equ STDIO_BUFSIZE 0x20
|
|
|
|
|
|
|
|
; *** Variables ***
|
|
|
|
; Line buffer. We read types chars into this buffer until return is pressed
|
2019-11-03 20:32:27 -05:00
|
|
|
; This buffer is null-terminated.
|
2019-11-15 15:37:49 -05:00
|
|
|
.equ STDIO_BUF STDIO_RAMSTART
|
2019-07-13 09:19:01 -04:00
|
|
|
|
|
|
|
; Index where the next char will go in stdioGetC.
|
2019-11-03 20:32:27 -05:00
|
|
|
.equ STDIO_RAMEND @+STDIO_BUFSIZE
|
2019-05-17 08:14:19 -04:00
|
|
|
|
|
|
|
stdioGetC:
|
2019-11-04 09:55:12 -05:00
|
|
|
jp STDIO_GETC
|
2019-05-17 08:14:19 -04:00
|
|
|
|
|
|
|
stdioPutC:
|
2019-11-04 09:55:12 -05:00
|
|
|
jp STDIO_PUTC
|
2019-04-22 22:41:37 -04:00
|
|
|
|
|
|
|
; print null-terminated string pointed to by HL
|
|
|
|
printstr:
|
|
|
|
push af
|
|
|
|
push hl
|
|
|
|
|
|
|
|
.loop:
|
|
|
|
ld a, (hl) ; load character to send
|
|
|
|
or a ; is it zero?
|
|
|
|
jr z, .end ; if yes, we're finished
|
2019-11-04 09:55:12 -05:00
|
|
|
call STDIO_PUTC
|
2019-04-22 22:41:37 -04:00
|
|
|
inc hl
|
|
|
|
jr .loop
|
|
|
|
|
|
|
|
.end:
|
|
|
|
pop hl
|
|
|
|
pop af
|
|
|
|
ret
|
|
|
|
|
2019-07-13 09:28:35 -04:00
|
|
|
; print B characters from string that HL points to
|
2019-04-22 22:41:37 -04:00
|
|
|
printnstr:
|
|
|
|
push bc
|
|
|
|
push hl
|
|
|
|
.loop:
|
|
|
|
ld a, (hl) ; load character to send
|
2019-11-04 09:55:12 -05:00
|
|
|
call STDIO_PUTC
|
2019-04-22 22:41:37 -04:00
|
|
|
inc hl
|
|
|
|
djnz .loop
|
|
|
|
|
|
|
|
.end:
|
|
|
|
pop hl
|
|
|
|
pop bc
|
|
|
|
ret
|
|
|
|
|
|
|
|
printcrlf:
|
2019-07-13 09:28:35 -04:00
|
|
|
push af
|
2019-11-13 20:38:06 -05:00
|
|
|
ld a, CR
|
2019-11-04 09:55:12 -05:00
|
|
|
call STDIO_PUTC
|
2019-11-13 20:38:06 -05:00
|
|
|
ld a, LF
|
2019-11-04 09:55:12 -05:00
|
|
|
call STDIO_PUTC
|
2019-07-13 09:28:35 -04:00
|
|
|
pop af
|
2019-04-22 22:41:37 -04:00
|
|
|
ret
|
|
|
|
|
2019-11-03 20:32:27 -05:00
|
|
|
; Repeatedly calls stdioGetC until a whole line was read, that is, when CR or
|
|
|
|
; LF is read or if the buffer is full. Sets HL to the beginning of the read
|
|
|
|
; line, which is null-terminated.
|
2019-07-13 09:19:01 -04:00
|
|
|
;
|
|
|
|
; This routine also takes care of echoing received characters back to the TTY.
|
2019-11-03 20:32:27 -05:00
|
|
|
; It also manages backspaces properly.
|
|
|
|
stdioReadLine:
|
|
|
|
push bc
|
|
|
|
ld hl, STDIO_BUF
|
|
|
|
ld b, STDIO_BUFSIZE-1
|
|
|
|
.loop:
|
2019-07-13 09:19:01 -04:00
|
|
|
; Let's wait until something is typed.
|
2019-11-04 09:55:12 -05:00
|
|
|
call STDIO_GETC
|
2019-07-13 09:19:01 -04:00
|
|
|
; got it. Now, is it a CR or LF?
|
2019-11-13 20:38:06 -05:00
|
|
|
cp CR
|
2019-07-13 09:19:01 -04:00
|
|
|
jr z, .complete ; char is CR? buffer complete!
|
2019-11-13 20:38:06 -05:00
|
|
|
cp LF
|
2019-07-13 09:19:01 -04:00
|
|
|
jr z, .complete
|
2019-11-13 20:38:06 -05:00
|
|
|
cp DEL
|
2019-07-13 09:19:01 -04:00
|
|
|
jr z, .delchr
|
2019-11-13 20:38:06 -05:00
|
|
|
cp BS
|
2019-07-13 09:19:01 -04:00
|
|
|
jr z, .delchr
|
|
|
|
|
|
|
|
; Echo the received character right away so that we see what we type
|
2019-11-04 09:55:12 -05:00
|
|
|
call STDIO_PUTC
|
2019-07-13 09:19:01 -04:00
|
|
|
|
|
|
|
; Ok, gotta add it do the buffer
|
2019-07-19 14:24:35 -04:00
|
|
|
ld (hl), a
|
|
|
|
inc hl
|
2019-11-03 20:32:27 -05:00
|
|
|
djnz .loop
|
|
|
|
; buffer overflow, complete line
|
2019-07-13 09:19:01 -04:00
|
|
|
.complete:
|
|
|
|
; The line in our buffer is complete.
|
2019-11-03 20:32:27 -05:00
|
|
|
; Let's null-terminate it and return.
|
|
|
|
xor a
|
|
|
|
ld (hl), a
|
|
|
|
ld hl, STDIO_BUF
|
|
|
|
pop bc
|
2019-07-13 09:19:01 -04:00
|
|
|
ret
|
|
|
|
|
|
|
|
.delchr:
|
2019-11-03 20:32:27 -05:00
|
|
|
; Deleting is a tricky business. We have to decrease HL and increase B
|
|
|
|
; so that everything stays consistent. We also have to make sure that
|
|
|
|
; We don't do buffer underflows.
|
|
|
|
ld a, b
|
|
|
|
cp STDIO_BUFSIZE-1
|
|
|
|
jr z, .loop ; beginning of line, nothing to delete
|
|
|
|
dec hl
|
|
|
|
inc b
|
2019-07-13 09:19:01 -04:00
|
|
|
; Char deleted in buffer, now send BS + space + BS for the terminal
|
|
|
|
; to clear its previous char
|
2019-11-13 20:38:06 -05:00
|
|
|
ld a, BS
|
2019-11-04 09:55:12 -05:00
|
|
|
call STDIO_PUTC
|
2019-07-13 09:19:01 -04:00
|
|
|
ld a, ' '
|
2019-11-04 09:55:12 -05:00
|
|
|
call STDIO_PUTC
|
2019-11-13 20:38:06 -05:00
|
|
|
ld a, BS
|
2019-11-04 09:55:12 -05:00
|
|
|
call STDIO_PUTC
|
2019-11-03 20:32:27 -05:00
|
|
|
jr .loop
|