8ccddbcb0e
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`.
215 lines
3.8 KiB
NASM
215 lines
3.8 KiB
NASM
; core
|
|
;
|
|
; Routines used by pretty much all parts. You will want to include it first
|
|
; in your glue file.
|
|
|
|
; *** CONSTS ***
|
|
ASCII_CR .equ 0x0d
|
|
ASCII_LF .equ 0x0a
|
|
|
|
; *** CODE ***
|
|
|
|
; 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
|
|
|
|
; 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
|
|
cp 10
|
|
jr nc, .alpha ; if >= 10, we have alpha
|
|
add a, '0'
|
|
ret
|
|
.alpha:
|
|
add a, 'A'-10
|
|
ret
|
|
|
|
; Formats value in A into a string hex pair. Stores it in the memory location
|
|
; that HL points to. Does *not* add a null char at the end.
|
|
fmtHexPair:
|
|
push af
|
|
|
|
; let's start with the rightmost char
|
|
inc hl
|
|
call fmtHex
|
|
ld (hl), a
|
|
|
|
; and now with the leftmost
|
|
dec hl
|
|
pop af
|
|
push af
|
|
and a, 0xf0
|
|
rra \ rra \ rra \ rra
|
|
call fmtHex
|
|
ld (hl), a
|
|
|
|
pop af
|
|
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 the hex char at A and extract it's 0-15 numerical value. Put the result
|
|
; in A.
|
|
;
|
|
; On success, the carry flag is reset. On error, it is set.
|
|
parseHex:
|
|
; First, let's see if we have an easy 0-9 case
|
|
cp '0'
|
|
jr c, .error ; if < '0', we have a problem
|
|
cp '9'+1
|
|
jr nc, .alpha ; if >= '9'+1, we might have alpha
|
|
; We are in the 0-9 range
|
|
sub a, '0' ; C is clear
|
|
ret
|
|
|
|
.alpha:
|
|
call upcase
|
|
cp 'A'
|
|
jr c, .error ; if < 'A', we have a problem
|
|
cp 'F'+1
|
|
jr nc, .error ; if >= 'F', we have a problem
|
|
; We have alpha.
|
|
sub a, 'A'-10 ; C is clear
|
|
ret
|
|
|
|
.error:
|
|
scf
|
|
ret
|
|
|
|
; Parses 2 characters of the string pointed to by HL and returns the numerical
|
|
; value in A. If the second character is a "special" character (<0x21) we don't
|
|
; error out: the result will be the one from the first char only.
|
|
;
|
|
; On success, the carry flag is reset. On error, it is set.
|
|
parseHexPair:
|
|
push bc
|
|
push hl
|
|
|
|
ld a, (hl)
|
|
call parseHex
|
|
jr c, .end ; error? goto end, keeping the C flag on
|
|
rla \ rla \ rla \ rla ; let's push this in MSB
|
|
ld b, a
|
|
inc hl
|
|
ld a, (hl)
|
|
cp 0x21
|
|
jr c, .single ; special char? single digit
|
|
call parseHex
|
|
jr c, .end ; error?
|
|
or b ; join left-shifted + new. we're done!
|
|
; C flag was set on parseHex and is necessarily clear at this point
|
|
jr .end
|
|
|
|
.single:
|
|
; If we have a single digit, our result is already stored in B, but
|
|
; we have to right-shift it back.
|
|
ld a, b
|
|
and a, 0xf0
|
|
rra \ rra \ rra \ rra
|
|
|
|
.end:
|
|
pop hl
|
|
pop bc
|
|
ret
|
|
|
|
; 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
|
|
|
|
; print A characters from string that HL points to
|
|
printnstr:
|
|
push bc
|
|
push hl
|
|
|
|
ld b, a
|
|
.loop:
|
|
ld a, (hl) ; load character to send
|
|
call aciaPutC
|
|
inc hl
|
|
djnz .loop
|
|
|
|
.end:
|
|
pop hl
|
|
pop bc
|
|
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
|
|
|
|
; Transforms the character in A, if it's in the a-z range, into its upcase
|
|
; version.
|
|
upcase:
|
|
cp 'a'
|
|
ret c ; A < 'a'. nothing to do
|
|
cp 'z'+1
|
|
ret nc ; A >= 'z'+1. nothing to do
|
|
; 'a' - 'A' == 0x20
|
|
sub 0x20
|
|
ret
|
|
|