collapseos/kernel/stdio.asm
Virgil Dupras 019d05f64c Make the shell a userspace app
That's my mega-commit you've all been waiting for.

The code for the shell share more routines with userspace apps than with kernel
units, because, well, its behavior is that of a userspace app, not a device
driver.

This created a weird situation with libraries and jump tables. Some routine
belonging to the `kernel/` directory felt weird there.

And then comes `apps/basic`, which will likely share even more code with the
shell. I was seeing myself creating huge jump tables to reuse code from the
shell. It didn't feel right.

Moreover, we'll probably want basic-like apps to optionnally replace the shell.

So here I am with this huge change in the project structure. I didn't test all
recipes on hardware yet, I will do later. I might have broken some...

But now, the structure feels better and the line between what belongs to
`kernel` and what belongs to `apps` feels clearer.
2019-11-15 15:37:49 -05:00

146 lines
3.2 KiB
NASM

; 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.
;
; Those GetC/PutC routines are hooked through defines and have this API:
;
; GetC: Blocks until a character is read from the device and return that
; character in A.
;
; PutC: Write character specified in A onto the device.
;
; *** 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.
;
; *** Defines ***
; STDIO_GETC: address of a GetC routine
; STDIO_PUTC: address of a PutC routine
;
; *** 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
; This buffer is null-terminated.
.equ STDIO_BUF STDIO_RAMSTART
; Index where the next char will go in stdioGetC.
.equ STDIO_RAMEND @+STDIO_BUFSIZE
stdioGetC:
jp STDIO_GETC
stdioPutC:
jp STDIO_PUTC
; 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
call STDIO_PUTC
inc hl
jr .loop
.end:
pop hl
pop af
ret
; print B characters from string that HL points to
printnstr:
push bc
push hl
.loop:
ld a, (hl) ; load character to send
call STDIO_PUTC
inc hl
djnz .loop
.end:
pop hl
pop bc
ret
printcrlf:
push af
ld a, CR
call STDIO_PUTC
ld a, LF
call STDIO_PUTC
pop af
ret
; 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.
;
; This routine also takes care of echoing received characters back to the TTY.
; It also manages backspaces properly.
stdioReadLine:
push bc
ld hl, STDIO_BUF
ld b, STDIO_BUFSIZE-1
.loop:
; Let's wait until something is typed.
call STDIO_GETC
; got it. Now, is it a CR or LF?
cp CR
jr z, .complete ; char is CR? buffer complete!
cp LF
jr z, .complete
cp DEL
jr z, .delchr
cp BS
jr z, .delchr
; Echo the received character right away so that we see what we type
call STDIO_PUTC
; Ok, gotta add it do the buffer
ld (hl), a
inc hl
djnz .loop
; buffer overflow, complete line
.complete:
; The line in our buffer is complete.
; Let's null-terminate it and return.
xor a
ld (hl), a
ld hl, STDIO_BUF
pop bc
ret
.delchr:
; 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
; Char deleted in buffer, now send BS + space + BS for the terminal
; to clear its previous char
ld a, BS
call STDIO_PUTC
ld a, ' '
call STDIO_PUTC
ld a, BS
call STDIO_PUTC
jr .loop