mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-27 12:18:07 +11:00
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.
|
; RAM.
|
||||||
|
|
||||||
; *** CONSTS ***
|
; *** CONSTS ***
|
||||||
; size of the input buffer. If our input goes over this size, we echo
|
; size of the input buffer. If our input goes over this size, we start losing
|
||||||
; immediately.
|
; data.
|
||||||
ACIA_BUFSIZE .equ 0x20
|
ACIA_BUFSIZE .equ 0x20
|
||||||
|
|
||||||
; *** VARIABLES ***
|
; *** VARIABLES ***
|
||||||
; Our input buffer starts there
|
; Our input buffer starts there. This is a circular buffer.
|
||||||
ACIA_BUF .equ ACIA_RAMSTART
|
ACIA_BUF .equ ACIA_RAMSTART
|
||||||
|
|
||||||
; index, in the buffer, where our next character will go. 0 when the buffer is
|
; The "read" index of the circular buffer. It points to where the next char
|
||||||
; empty, BUFSIZE-1 when it's almost full.
|
; should be read. If rd == wr, the buffer is empty. Not touched by the
|
||||||
ACIA_BUFIDX .equ ACIA_BUF+ACIA_BUFSIZE
|
; interrupt.
|
||||||
ACIA_RAMEND .equ ACIA_BUFIDX+1
|
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:
|
aciaInit:
|
||||||
; initialize variables
|
; initialize variables
|
||||||
xor a
|
xor a
|
||||||
ld (ACIA_BUFIDX), a ; starts at 0
|
ld (ACIA_BUFRDIDX), a ; starts at 0
|
||||||
|
ld (ACIA_BUFWRIDX), a
|
||||||
|
|
||||||
; setup ACIA
|
; setup ACIA
|
||||||
; CR7 (1) - Receive Interrupt enabled
|
; CR7 (1) - Receive Interrupt enabled
|
||||||
@ -41,6 +47,16 @@ aciaInit:
|
|||||||
out (ACIA_CTL), a
|
out (ACIA_CTL), a
|
||||||
ret
|
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
|
; read char in the ACIA and put it in the read buffer
|
||||||
aciaInt:
|
aciaInt:
|
||||||
push af
|
push af
|
||||||
@ -51,18 +67,27 @@ aciaInt:
|
|||||||
bit 0, a ; is our ACIA rcv buffer full?
|
bit 0, a ; is our ACIA rcv buffer full?
|
||||||
jr z, .end ; no? a interrupt was triggered for nothing.
|
jr z, .end ; no? a interrupt was triggered for nothing.
|
||||||
|
|
||||||
call aciaBufPtr ; HL set, A set
|
; Load both read and write indexes so we can compare them. To do so, we
|
||||||
; is our input buffer full? If yes, we don't read anything. Something
|
; perform a "fake" read increase and see if it brings it to the same
|
||||||
; is wrong: we don't process data fast enough.
|
; value as the write index.
|
||||||
cp ACIA_BUFSIZE
|
ld a, (ACIA_BUFRDIDX)
|
||||||
jr z, .end ; if BUFIDX == BUFSIZE, our buffer is full.
|
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
|
; increase our buf ptr while we still have it in A
|
||||||
inc a
|
call aciaIncIndex
|
||||||
ld (ACIA_BUFIDX), a
|
ld (ACIA_BUFWRIDX), a
|
||||||
|
|
||||||
|
; And finially, fetch the value and write it.
|
||||||
in a, (ACIA_IO)
|
in a, (ACIA_IO)
|
||||||
ld (hl), a
|
ld (de), a
|
||||||
|
|
||||||
.end:
|
.end:
|
||||||
pop hl
|
pop hl
|
||||||
@ -70,18 +95,30 @@ aciaInt:
|
|||||||
ei
|
ei
|
||||||
reti
|
reti
|
||||||
|
|
||||||
; Set current buffer pointer in HL. The buffer pointer is where our *next* char
|
; Read a character from the input buffer. If the buffer is empty, loop until
|
||||||
; will be written. A is set to the value of (BUFIDX)
|
; there something to fetch. Returns value in A.
|
||||||
aciaBufPtr:
|
aciaGetC:
|
||||||
push bc
|
push de
|
||||||
|
|
||||||
ld a, (ACIA_BUFIDX)
|
.loop:
|
||||||
ld hl, ACIA_BUF
|
ld a, (ACIA_BUFWRIDX)
|
||||||
xor b
|
ld e, a
|
||||||
ld c, a
|
ld a, (ACIA_BUFRDIDX)
|
||||||
add hl, bc ; hl now points to INPTBUF + BUFIDX
|
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
|
ret
|
||||||
|
|
||||||
; spits character in A in port SER_OUT
|
; spits character in A in port SER_OUT
|
||||||
|
@ -18,6 +18,26 @@ addDE:
|
|||||||
ld e, a
|
ld e, a
|
||||||
ret
|
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.
|
; Format the lower nibble of A into a hex char and stores the result in A.
|
||||||
fmtHex:
|
fmtHex:
|
||||||
and a, 0xf
|
and a, 0xf
|
||||||
@ -191,3 +211,4 @@ upcase:
|
|||||||
; 'a' - 'A' == 0x20
|
; 'a' - 'A' == 0x20
|
||||||
sub 0x20
|
sub 0x20
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
@ -26,18 +26,29 @@ SHELL_ERR_UNKNOWN_CMD .equ 0x01
|
|||||||
; Arguments for the command weren't properly formatted
|
; Arguments for the command weren't properly formatted
|
||||||
SHELL_ERR_BAD_ARGS .equ 0x02
|
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 ***
|
; *** VARIABLES ***
|
||||||
; Memory address that the shell is currently "pointing at" for peek and deek
|
; Memory address that the shell is currently "pointing at" for peek and deek
|
||||||
; operations. Set with seek.
|
; operations. Set with seek.
|
||||||
SHELL_MEM_PTR .equ SHELL_RAMSTART
|
SHELL_MEM_PTR .equ SHELL_RAMSTART
|
||||||
; Used to store formatted hex values just before printing it.
|
; Used to store formatted hex values just before printing it.
|
||||||
SHELL_HEX_FMT .equ SHELL_MEM_PTR+2
|
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 ***
|
; *** CODE ***
|
||||||
shellInit:
|
shellInit:
|
||||||
xor a
|
xor a
|
||||||
ld (SHELL_MEM_PTR), a
|
ld (SHELL_MEM_PTR), a
|
||||||
|
ld (SHELL_BUF), a
|
||||||
|
|
||||||
; print prompt
|
; print prompt
|
||||||
ld hl, .prompt
|
ld hl, .prompt
|
||||||
@ -49,37 +60,42 @@ shellInit:
|
|||||||
.db "Collapse OS", 0
|
.db "Collapse OS", 0
|
||||||
|
|
||||||
shellLoop:
|
shellLoop:
|
||||||
; check if the input buffer is full or ends in CR or LF. If it does,
|
; First, let's wait until something is typed.
|
||||||
; prints it back and empty it.
|
call aciaGetC
|
||||||
call aciaBufPtr
|
; got it. Now, is it a CR or LF?
|
||||||
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
|
|
||||||
|
|
||||||
cp ASCII_CR
|
cp ASCII_CR
|
||||||
jr z, .do ; char is CR? do!
|
jr z, .do ; char is CR? do!
|
||||||
cp ASCII_LF
|
cp ASCII_LF
|
||||||
jr z, .do ; char is LF? do!
|
jr z, .do ; char is LF? do!
|
||||||
|
|
||||||
; nothing matched? don't do anything
|
; Ok, gotta add it do the buffer
|
||||||
jr shellLoop
|
; save char for later
|
||||||
.do:
|
ex af, af'
|
||||||
; terminate our string with 0
|
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
|
xor a
|
||||||
ld (hl), a
|
ld (hl), a
|
||||||
; reset buffer index
|
|
||||||
ld (ACIA_BUFIDX), a
|
|
||||||
|
|
||||||
; alright, let's go!
|
jr shellLoop
|
||||||
ld hl, ACIA_BUF
|
|
||||||
|
.do:
|
||||||
|
ld hl, SHELL_BUF
|
||||||
call shellParse
|
call shellParse
|
||||||
|
; empty our buffer by writing a zero to its first char
|
||||||
|
xor a
|
||||||
|
ld (hl), a
|
||||||
|
|
||||||
jr shellLoop
|
jr shellLoop
|
||||||
|
|
||||||
printcrlf:
|
printcrlf:
|
||||||
|
Loading…
Reference in New Issue
Block a user