Separate shell and acia input buffers
They serve a different purpose. The goal of the ACIA buffer is to ensure that we don't miss an input. The goal of the shell buffer is to wait until the user presses return. The ACIA buffer has been moved to shell and replaced with a circular buffer, a more appropriate data structure for this kind of purpose. Also, introduce `aciaGetC`.
This commit is contained in:
parent
902c6a5dd3
commit
8ccddbcb0e
@ -14,23 +14,29 @@
|
||||
; RAM.
|
||||
|
||||
; *** CONSTS ***
|
||||
; size of the input buffer. If our input goes over this size, we echo
|
||||
; immediately.
|
||||
; size of the input buffer. If our input goes over this size, we start losing
|
||||
; data.
|
||||
ACIA_BUFSIZE .equ 0x20
|
||||
|
||||
; *** VARIABLES ***
|
||||
; Our input buffer starts there
|
||||
; Our input buffer starts there. This is a circular buffer.
|
||||
ACIA_BUF .equ ACIA_RAMSTART
|
||||
|
||||
; index, in the buffer, where our next character will go. 0 when the buffer is
|
||||
; empty, BUFSIZE-1 when it's almost full.
|
||||
ACIA_BUFIDX .equ ACIA_BUF+ACIA_BUFSIZE
|
||||
ACIA_RAMEND .equ ACIA_BUFIDX+1
|
||||
; The "read" index of the circular buffer. It points to where the next char
|
||||
; should be read. If rd == wr, the buffer is empty. Not touched by the
|
||||
; interrupt.
|
||||
ACIA_BUFRDIDX .equ ACIA_BUF+ACIA_BUFSIZE
|
||||
; The "write" index of the circular buffer. Points to where the next char
|
||||
; should be written. Should only be touched by the interrupt. if wr == rd-1,
|
||||
; the interrupt will *not* write in the buffer until some space has been freed.
|
||||
ACIA_BUFWRIDX .equ ACIA_BUFRDIDX+1
|
||||
ACIA_RAMEND .equ ACIA_BUFWRIDX+1
|
||||
|
||||
aciaInit:
|
||||
; initialize variables
|
||||
xor a
|
||||
ld (ACIA_BUFIDX), a ; starts at 0
|
||||
ld (ACIA_BUFRDIDX), a ; starts at 0
|
||||
ld (ACIA_BUFWRIDX), a
|
||||
|
||||
; setup ACIA
|
||||
; CR7 (1) - Receive Interrupt enabled
|
||||
@ -41,6 +47,16 @@ aciaInit:
|
||||
out (ACIA_CTL), a
|
||||
ret
|
||||
|
||||
; Increase the circular buffer index in A, properly considering overflow.
|
||||
; returns value in A.
|
||||
aciaIncIndex:
|
||||
inc a
|
||||
cp ACIA_BUFSIZE
|
||||
ret nz ; not equal? nothing to do
|
||||
; equal? reset
|
||||
xor a
|
||||
ret
|
||||
|
||||
; read char in the ACIA and put it in the read buffer
|
||||
aciaInt:
|
||||
push af
|
||||
@ -51,18 +67,27 @@ aciaInt:
|
||||
bit 0, a ; is our ACIA rcv buffer full?
|
||||
jr z, .end ; no? a interrupt was triggered for nothing.
|
||||
|
||||
call aciaBufPtr ; HL set, A set
|
||||
; is our input buffer full? If yes, we don't read anything. Something
|
||||
; is wrong: we don't process data fast enough.
|
||||
cp ACIA_BUFSIZE
|
||||
jr z, .end ; if BUFIDX == BUFSIZE, our buffer is full.
|
||||
; Load both read and write indexes so we can compare them. To do so, we
|
||||
; perform a "fake" read increase and see if it brings it to the same
|
||||
; value as the write index.
|
||||
ld a, (ACIA_BUFRDIDX)
|
||||
call aciaIncIndex
|
||||
ld l, a
|
||||
ld a, (ACIA_BUFWRIDX)
|
||||
cp l
|
||||
jr z, .end ; Equal? buffer is full
|
||||
|
||||
; Alrighty, buffer not full. let's write.
|
||||
ld de, ACIA_BUF
|
||||
; A already contains our write index, add it to DE
|
||||
call addDE
|
||||
; increase our buf ptr while we still have it in A
|
||||
inc a
|
||||
ld (ACIA_BUFIDX), a
|
||||
call aciaIncIndex
|
||||
ld (ACIA_BUFWRIDX), a
|
||||
|
||||
; And finially, fetch the value and write it.
|
||||
in a, (ACIA_IO)
|
||||
ld (hl), a
|
||||
ld (de), a
|
||||
|
||||
.end:
|
||||
pop hl
|
||||
@ -70,18 +95,30 @@ aciaInt:
|
||||
ei
|
||||
reti
|
||||
|
||||
; Set current buffer pointer in HL. The buffer pointer is where our *next* char
|
||||
; will be written. A is set to the value of (BUFIDX)
|
||||
aciaBufPtr:
|
||||
push bc
|
||||
; Read a character from the input buffer. If the buffer is empty, loop until
|
||||
; there something to fetch. Returns value in A.
|
||||
aciaGetC:
|
||||
push de
|
||||
|
||||
ld a, (ACIA_BUFIDX)
|
||||
ld hl, ACIA_BUF
|
||||
xor b
|
||||
ld c, a
|
||||
add hl, bc ; hl now points to INPTBUF + BUFIDX
|
||||
.loop:
|
||||
ld a, (ACIA_BUFWRIDX)
|
||||
ld e, a
|
||||
ld a, (ACIA_BUFRDIDX)
|
||||
cp e
|
||||
jr z, .loop ; equal? buffer empty, wait.
|
||||
|
||||
pop bc
|
||||
; Alrighty, buffer not empty. let's read.
|
||||
ld de, ACIA_BUF
|
||||
; A already contains our read index, add it to DE
|
||||
call addDE
|
||||
; increase our buf ptr while we still have it in A
|
||||
call aciaIncIndex
|
||||
ld (ACIA_BUFRDIDX), a
|
||||
|
||||
; And finially, fetch the value.
|
||||
ld a, (de)
|
||||
|
||||
pop de
|
||||
ret
|
||||
|
||||
; spits character in A in port SER_OUT
|
||||
|
@ -18,6 +18,26 @@ addDE:
|
||||
ld e, a
|
||||
ret
|
||||
|
||||
; Increase HL until the memory address it points to is null for a maximum of
|
||||
; 0xff bytes. Returns the new HL value as well as the number of bytes iterated
|
||||
; in A.
|
||||
findnull:
|
||||
push bc
|
||||
ld a, 0xff
|
||||
ld b, a
|
||||
|
||||
.loop: ld a, (hl)
|
||||
cp 0
|
||||
jr z, .end
|
||||
inc hl
|
||||
djnz .loop
|
||||
.end:
|
||||
; We ran 0xff-B loops. That's the result that goes in A.
|
||||
ld a, 0xff
|
||||
sub a, b
|
||||
pop bc
|
||||
ret
|
||||
|
||||
; Format the lower nibble of A into a hex char and stores the result in A.
|
||||
fmtHex:
|
||||
and a, 0xf
|
||||
@ -191,3 +211,4 @@ upcase:
|
||||
; 'a' - 'A' == 0x20
|
||||
sub 0x20
|
||||
ret
|
||||
|
||||
|
@ -26,18 +26,29 @@ SHELL_ERR_UNKNOWN_CMD .equ 0x01
|
||||
; Arguments for the command weren't properly formatted
|
||||
SHELL_ERR_BAD_ARGS .equ 0x02
|
||||
|
||||
; Size of the shell command buffer. If a typed command reaches this size, the
|
||||
; command is flushed immediately (same as pressing return).
|
||||
SHELL_BUFSIZE .equ 0x20
|
||||
|
||||
; *** VARIABLES ***
|
||||
; Memory address that the shell is currently "pointing at" for peek and deek
|
||||
; operations. Set with seek.
|
||||
SHELL_MEM_PTR .equ SHELL_RAMSTART
|
||||
; Used to store formatted hex values just before printing it.
|
||||
SHELL_HEX_FMT .equ SHELL_MEM_PTR+2
|
||||
SHELL_RAMEND .equ SHELL_HEX_FMT+2
|
||||
|
||||
; Command 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.
|
||||
SHELL_BUF .equ SHELL_HEX_FMT+2
|
||||
|
||||
SHELL_RAMEND .equ SHELL_BUF+SHELL_BUFSIZE
|
||||
|
||||
; *** CODE ***
|
||||
shellInit:
|
||||
xor a
|
||||
ld (SHELL_MEM_PTR), a
|
||||
ld (SHELL_BUF), a
|
||||
|
||||
; print prompt
|
||||
ld hl, .prompt
|
||||
@ -49,37 +60,42 @@ shellInit:
|
||||
.db "Collapse OS", 0
|
||||
|
||||
shellLoop:
|
||||
; check if the input buffer is full or ends in CR or LF. If it does,
|
||||
; prints it back and empty it.
|
||||
call aciaBufPtr
|
||||
cp 0
|
||||
jr z, shellLoop ; 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
|
||||
|
||||
; First, let's wait until something is typed.
|
||||
call aciaGetC
|
||||
; got it. Now, is it a CR or LF?
|
||||
cp ASCII_CR
|
||||
jr z, .do ; char is CR? do!
|
||||
cp ASCII_LF
|
||||
jr z, .do ; char is LF? do!
|
||||
|
||||
; nothing matched? don't do anything
|
||||
jr shellLoop
|
||||
.do:
|
||||
; terminate our string with 0
|
||||
; Ok, gotta add it do the buffer
|
||||
; save char for later
|
||||
ex af, af'
|
||||
ld hl, SHELL_BUF
|
||||
call findnull ; HL points to where we need to write
|
||||
; A is the number of chars in the buf
|
||||
cp SHELL_BUFSIZE
|
||||
jr z, .do ; A == bufsize? then our buffer is full. do!
|
||||
|
||||
; bring the char back in A
|
||||
ex af, af'
|
||||
; Buffer not full, not CR or LF. Let's put that char in our buffer and
|
||||
; read again.
|
||||
ld (hl), a
|
||||
; Now, write a zero to the next byte to properly terminate our string.
|
||||
inc hl
|
||||
xor a
|
||||
ld (hl), a
|
||||
; reset buffer index
|
||||
ld (ACIA_BUFIDX), a
|
||||
|
||||
; alright, let's go!
|
||||
ld hl, ACIA_BUF
|
||||
jr shellLoop
|
||||
|
||||
.do:
|
||||
ld hl, SHELL_BUF
|
||||
call shellParse
|
||||
; empty our buffer by writing a zero to its first char
|
||||
xor a
|
||||
ld (hl), a
|
||||
|
||||
jr shellLoop
|
||||
|
||||
printcrlf:
|
||||
|
Loading…
Reference in New Issue
Block a user