collapseos/parts/shell.asm
Virgil Dupras 9580cc3994 shell: add "seek" and "peek" dummy commands
This change introduces a command name matching algo.
2019-04-13 22:39:28 -04:00

222 lines
3.5 KiB
NASM

; shell
;
; Runs a shell over an asynchronous communication interface adapter (ACIA).
; for now, this unit is tightly coupled to acia.asm, but it will eventually be
; more general than that.
; Status: incomplete. As it is now, it spits a welcome prompt, wait for input
; and compare the first 4 chars of the input with a command table and call the
; appropriate routine if it's found, an error if it's not.
;
; Commands, for now, are dummy.
;
; See constants below for error codes.
; *** CONSTS ***
CR .equ 0x0d
LF .equ 0x0a
; number of entries in shellCmdTbl
SHELL_CMD_COUNT .equ 2
; The command that was type isn't known to the shell
SHELL_ERR_UNKNOWN_CMD .equ 0x01
; Arguments for the command weren't properly formatted
SHELL_ERR_BAD_ARGS .equ 0x02
; *** CODE ***
shellInit:
; print prompt
ld hl, .prompt
call printstr
call printcrlf
ret
.prompt:
.db "Collapse OS", 0
shellLoop:
call chkbuf
jr shellLoop
; 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 aciaPutC
inc hl
jr .loop
.end:
pop hl
pop af
ret
printcrlf:
ld a, CR
call aciaPutC
ld a, LF
call aciaPutC
ret
; check if the input buffer is full or ends in CR or LF. If it does, prints it
; back and empty it.
chkbuf:
call aciaBufPtr
cp 0
ret z ; BUFIDX is zero? nothing to check.
cp ACIA_BUFSIZE
jr z, .do ; if BUFIDX == BUFSIZE? do!
; our previous char is in BUFIDX - 1. Fetch this
dec hl
ld a, (hl) ; now, that's our char we have in A
inc hl ; put HL back where it was
cp CR
jr z, .do ; char is CR? do!
cp LF
jr z, .do ; char is LF? do!
; nothing matched? don't do anything
ret
.do:
; terminate our string with 0
xor a
ld (hl), a
; reset buffer index
ld (ACIA_BUFIDX), a
; alright, let's go!
ld hl, ACIA_BUF
call shellParse
ret
; Compares strings pointed to by HL and DE up to A count of characters. If
; equal, Z is set. If not equal, Z is reset.
strncmp:
push bc
push hl
push de
ld b, a
.loop:
ld a, (de)
cp (hl)
jr nz, .end ; not equal? break early
inc hl
inc de
djnz .loop
.end:
pop de
pop hl
pop bc
; Because we don't call anything else than CP that modify the Z flag,
; our Z value will be that of the last cp (reset if we broke the loop
; early, set otherwise)
ret
; add the value of A into DE
addDE:
add a, e
jr nc, .end ; no carry? skip inc
inc d
.end:
ld e, a
ret
; jump to the location pointed to by HL. This allows us to call HL instead of
; just jumping it.
jumpHL:
jp hl
ret
; Parse command (null terminated) at HL and calls it
shellParse:
push af
push bc
push de
ld de, shellCmdTbl
ld a, SHELL_CMD_COUNT
ld b, a
.loop:
ld a, 4 ; 4 chars to compare
call strncmp
jr z, .found
ld a, 6
call addDE
djnz .loop
; exhausted loop? not found
ld a, SHELL_ERR_UNKNOWN_CMD
call shellPrintErr
jr .end
.found:
ld a, 4
call addDE
ex hl, de
call jumpHL
ex hl, de
.end:
pop de
pop bc
pop af
ret
; Print the error code set in A (doesn't work for codes > 9 yet...)
shellPrintErr:
push af
push hl
ld hl, .str
call printstr
; ascii for '0' is 0x30
add a, 0x30
call aciaPutC
call printcrlf
pop hl
pop af
ret
.str:
.db "ERR ", 0
; *** COMMANDS ***
shellSeek:
ld hl, .str
call printstr
ret
.str:
.db "seek called", CR, LF, 0
shellPeek:
ld hl, .str
call printstr
ret
.str:
.db "peek called", CR, LF, 0
; Format: 4 bytes name followed by 2 bytes jump. fill names with zeroes
shellCmdTbl:
.db "seek"
jr shellSeek
.db "peek"
jr shellPeek