collapseos/kernel/stdio.asm

217 lines
4.6 KiB
NASM
Raw Normal View History

2019-04-23 12:41:37 +10:00
; stdio
;
; Allows other modules to print to "standard out", and get data from "standard
; in", that is, the console through which the user is connected in a decoupled
; manner.
2019-04-23 12:41:37 +10: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 ***
2019-04-23 12:41:37 +10:00
; Used to store formatted hex values just before printing it.
2019-05-18 05:43:44 +10:00
.equ STDIO_HEX_FMT STDIO_RAMSTART
.equ STDIO_GETC STDIO_HEX_FMT+2
.equ STDIO_PUTC STDIO_GETC+2
; Line buffer. We read types chars into this buffer until return is pressed
; This buffer is null-terminated and we don't keep an index around: we look
; for the null-termination every time we write to it. Simpler that way.
.equ STDIO_BUF STDIO_PUTC+2
; Index where the next char will go in stdioGetC.
.equ STDIO_BUFIDX STDIO_BUF+STDIO_BUFSIZE
.equ STDIO_RAMEND STDIO_BUFIDX+1
2019-05-17 22:14:19 +10:00
; Sets GetC to the routine where HL points to and PutC to DE.
2019-05-17 22:14:19 +10:00
stdioInit:
ld (STDIO_GETC), hl
ld (STDIO_PUTC), de
xor a
ld (STDIO_BUF), a
ld (STDIO_BUFIDX), a
2019-05-17 22:14:19 +10:00
ret
stdioGetC:
ld ix, (STDIO_GETC)
jp (ix)
stdioPutC:
ld ix, (STDIO_PUTC)
jp (ix)
2019-04-23 12:41:37 +10: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-05-17 22:14:19 +10:00
call stdioPutC
2019-04-23 12:41:37 +10:00
inc hl
jr .loop
.end:
pop hl
pop af
ret
2019-07-13 23:28:35 +10:00
; print B characters from string that HL points to
2019-04-23 12:41:37 +10:00
printnstr:
push bc
push hl
.loop:
ld a, (hl) ; load character to send
2019-05-17 22:14:19 +10:00
call stdioPutC
2019-04-23 12:41:37 +10:00
inc hl
djnz .loop
.end:
pop hl
pop bc
ret
printcrlf:
2019-07-13 23:28:35 +10:00
push af
2019-04-23 12:41:37 +10:00
ld a, ASCII_CR
2019-05-17 22:14:19 +10:00
call stdioPutC
2019-04-23 12:41:37 +10:00
ld a, ASCII_LF
2019-05-17 22:14:19 +10:00
call stdioPutC
2019-07-13 23:28:35 +10:00
pop af
2019-04-23 12:41:37 +10:00
ret
; Print the hex char in A
printHex:
2019-07-13 23:28:35 +10:00
push bc
2019-04-23 12:41:37 +10:00
push hl
ld hl, STDIO_HEX_FMT
call fmtHexPair
2019-07-13 23:28:35 +10:00
ld b, 2
2019-04-23 12:41:37 +10:00
call printnstr
pop hl
2019-07-13 23:28:35 +10:00
pop bc
2019-04-23 12:41:37 +10:00
ret
2019-04-24 03:29:16 +10:00
; Print the hex pair in HL
printHexPair:
push af
ld a, h
call printHex
ld a, l
call printHex
pop af
ret
; Call stdioGetC and put the result in the buffer. Sets Z according to whether
; the buffer is "complete", that is, whether CR or LF have been pressed or if
; the the buffer is full. Z is set if the line is "complete", unset if not.
; The next call to stdioReadC after a completed line will start a new line.
;
; This routine also takes care of echoing received characters back to the TTY.
;
; This routine doesn't wait after a typed char. If nothing is typed, we return
; immediately with Z flag unset.
;
; Note that this routine doesn't bother returning the typed character.
stdioReadC:
; Let's wait until something is typed.
call stdioGetC
ret nz ; nothing typed? nothing to do
; got it. Now, is it a CR or LF?
cp ASCII_CR
jr z, .complete ; char is CR? buffer complete!
cp ASCII_LF
jr z, .complete
cp ASCII_DEL
jr z, .delchr
cp ASCII_BS
jr z, .delchr
; Echo the received character right away so that we see what we type
call stdioPutC
; Ok, gotta add it do the buffer
; save char for later
ex af, af'
ld a, (STDIO_BUFIDX)
push hl ; --> lvl 1
ld hl, STDIO_BUF
; make HL point to dest spot
call addHL
; Write our char down
ex af, af'
ld (hl), a
; follow up with a null char
inc hl
xor a
ld (hl), a
pop hl ; <-- lvl 1
; inc idx, which still is in AF'
ex af, af'
inc a
cp STDIO_BUFSIZE-1 ; -1 is because we always want to keep our
; last char at zero.
jr z, .complete ; end of buffer reached? buffer is full.
; not complete. save idx back
ld (STDIO_BUFIDX), a
; Z already unset
ret
.complete:
; The line in our buffer is complete.
; But before we do that, let's take care of a special case: the empty
; line. If we didn't add any character since the last "complete", then
; our buffer's content is the content from the last time. Let's set this
; to an empty string.
ld a, (STDIO_BUFIDX)
or a
jr nz, .completeSkip
ld (STDIO_BUF), a
.completeSkip:
xor a ; sets Z
ld (STDIO_BUFIDX), a
ret
.delchr:
ld a, (STDIO_BUFIDX)
or a
jp z, unsetZ ; buf empty? nothing to do
; buffer not empty, let's go back one char and set a null char there.
dec a
ld (STDIO_BUFIDX), a
push hl ;<|
ld hl, STDIO_BUF ; |
; make HL point to dest spot |
call addHL ; |
xor a ; |
ld (hl), a ; |
pop hl ;<|
; Char deleted in buffer, now send BS + space + BS for the terminal
; to clear its previous char
ld a, ASCII_BS
call stdioPutC
ld a, ' '
call stdioPutC
ld a, ASCII_BS
call stdioPutC
jp unsetZ
; Make HL point to the line buffer. It is always null terminated.
stdioGetLine:
ld hl, STDIO_BUF
ret
2019-07-15 07:29:00 +10:00
; Repeatedly call stdioReadC until Z is set, then make HL point to the read
; buffer.
stdioReadLine:
call stdioReadC
jr nz, stdioReadLine
ld hl, STDIO_BUF
ret