Gidubba/gidubba.asm

1745 lines
42 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;Gidubba: A simple line editor
;***
;Save an end-of-file at the start address
load r0, #1a
store buffer + 100, r0
;***
;Command prompt
cmdp: load r0, #3e
store ffff, r0
load r0, #20
store ffff, r0
;Input the command
cmdin: cleq r0, r0, input
;Check for control characters
;Escape
load r0, #1b
breq r0, r2, cmdesc
;End-of-file
load r0, #1a
breq r0, r2, end
;Initialise the command and argument
xor r0, r0
store cmd, r0
store argf1, r0
store argf2, r0
load r0, #30
store arg1, r0
store arg1 + 1, r0
store arg1 + 2, r0
store arg1 + 3, r0
store arg2, r0
store arg2 + 1, r0
;Parse the command and its first argument
;Command
load r0, buffer
store cmd, r0
;Load carriage return and hash
load r1, #d
load r2, #23
;Check for no command
breq r0, r1, cmdp
;First digit
load r0, buffer + 1
breq r0, r1, chkcmd
load r3, #1
store argf1, r3
breq r0, r2, hsharg
load r3, arg1d2 + 1
store arg2d1 + 1, r3
load r3, arg1d2 + 2
store arg2d1 + 2, r3
load r3, #2c
breq r0, r3, 2ndarg
store arg1 + 3, r0
;Second digit
arg1d2: load r0, buffer + 2
breq r0, r1, getarg
load r3, arg1d3 + 1
store arg2d1 + 1, r3
load r3, arg1d3 + 2
store arg2d1 + 2, r3
load r3, #2c
breq r0, r3, 2ndarg
load r2, arg1 + 3
store arg1 + 2, r2
store arg1 + 3, r0
;Third digit
arg1d3: load r0, buffer + 3
breq r0, r1, getarg
load r3, arg1d4 + 1
store arg2d1 + 1, r3
load r3, arg1d4 + 2
store arg2d1 + 2, r3
load r3, #2c
breq r0, r3, 2ndarg
load r2, arg1 + 2
store arg1 + 1, r2
load r2, arg1 + 3
store arg1 + 2, r2
store arg1 + 3, r0
;Fourth digit
arg1d4: load r0, buffer + 4
breq r0, r1, getarg
load r3, arg1d5 + 1
store arg2d1 + 1, r3
load r3, arg1d5 + 2
store arg2d1 + 2, r3
load r3, #2c
breq r0, r3, 2ndarg
load r2, arg1 + 1
store arg1, r2
load r2, arg1 + 2
store arg1 + 1, r2
load r2, arg1 + 3
store arg1 + 2, r2
store arg1 + 3, r0
;Check for command end
load r0, arg1d5 + 1
load r1, arg1d5 + 2
cleq r0, r0, incdw
store arg2d1 + 1, r0
store arg2d1 + 2, r1
load r1, #d
arg1d5: load r0, buffer + 5
breq r0, r1, getarg
load r3, #2c
breq r0, r3, 2ndarg
breq r0, r0, cmderr
;Parse the second argument
;Set the addresses
2ndarg: load r0, arg2d1 + 1
load r1, arg2d1 + 2
cleq r0, r0, incdw
store arg2d2 + 1, r0
store arg2d2 + 2, r1
cleq r0, r0, incdw
store arg2d3 + 1, r0
store arg2d3 + 2, r1
;Load carriage return
load r1, #d
;First digit
arg2d1: load r0, 0
breq r0, r1, chkcmd
load r3, #1
store argf2, r3
store arg2 + 1, r0
;Second digit
arg2d2: load r0, 0
breq r0, r1, getarg
load r2, arg2 + 1
store arg2, r2
store arg2 + 1, r0
;Check for command end
arg2d3: load r0, 0
breq r0, r1, getarg
breq r0, r0, cmderr
;Hash is a shortcut for FFFF
;Check for command end
hsharg: load r0, buffer + 2
brneq r0, r1, cmderr
;Save FFFF
xor r0, r0
nand r0, r0
store target, r0
store target + 1, r0
breq r0, r0, chkcmd
;Get the value of the first argument
;First digit
getarg: load r0, arg1
cleq r0, r0, hex2n
load r1, #3f
breq r0, r1, cmderr
xor r2, r2
xor r2, r0
shl r2
shl r2
shl r2
shl r2
;Second digit
load r0, arg1 + 1
cleq r0, r0, hex2n
load r1, #3f
breq r0, r1, cmderr
;Combine and store the first and second digits
or r0, r2
store target, r0
;Third digit
load r0, arg1 + 2
cleq r0, r0, hex2n
load r1, #3f
breq r0, r1, cmderr
xor r2, r2
xor r2, r0
shl r2
shl r2
shl r2
shl r2
;Fourth digit
load r0, arg1 + 3
cleq r0, r0, hex2n
load r1, #3f
breq r0, r1, cmderr
;Combine and store the third and fourth digits
or r0, r2
store target + 1, r0
;Get the value of the second argument
;First digit
load r0, arg2
cleq r0, r0, hex2n
load r1, #3f
breq r0, r1, cmderr
xor r2, r2
xor r2, r0
shl r2
shl r2
shl r2
shl r2
;Second digit
load r0, arg2 + 1
cleq r0, r0, hex2n
load r1, #3f
breq r0, r1, cmderr
;Combine and store the first and second digits
or r0, r2
store count, r0
;Check for commands
;Load the command
chkcmd: load r0, cmd
;Check for no argument
load r2, argf1
xor r3, r3
breq r2, r3, cnarg
;Check for single argument
load r2, argf2
xor r3, r3
breq r2, r3, onearg
;Copy to mark
load r1, #43
breq r0, r1, copy
load r1, #63
breq r0, r1, copy
;Delete
load r1, #44
breq r0, r1, delete
load r1, #64
breq r0, r1, delete
;List
load r1, #4c
breq r0, r1, list
load r1, #6c
breq r0, r1, list
;Branch to error
breq r0, r0, cmderr
;Insert
onearg: load r1, #49
breq r0, r1, insln
load r1, #69
breq r0, r1, insln
;Set a mark
load r1, #4d
breq r0, r1, setmrk
load r1, #6d
breq r0, r1, setmrk
;Branch to error
breq r0, r0, cmderr
;Print
cnarg: load r1, #50
breq r0, r1, print
load r1, #70
breq r0, r1, print
;Write to tape
load r1, #57
breq r0, r1, write
load r1, #77
breq r0, r1, write
;Read from tape
load r1, #52
breq r0, r1, read
load r1, #72
breq r0, r1, read
;Print an error and return to the command prompt
cmderr: cleq r0, r0, error
breq r0, r0, cmdp
cmdesc: load r0, #20
store ffff, r0
store ffff, r0
breq r0, r0, cmdin
;***
;Insert a line
;Reset the line number
insln: xor r0, r0
store lnnum, r0
store lnnum + 1, r0
;Get the save start address
;High byte
load r0, svstrt
store eoflod + 1, r0
;Low byte
load r0, svstrt + 1
store eoflod + 2, r0
;Find the argument line in the save and store its number
nextln: cleq r0, r0, fend
;Print a line number prompt
instrt: cleq r0, r0, prnln
;Input the line
inline: cleq r0, r0, input
;Check for control characters
;Escape
load r0, #1b
breq r0, r2, inesc
;End-of-file
load r0, #1a
breq r0, r2, cmdp
;Increment the line number
;Load the number
load r0, lnnum
load r1, lnnum + 1
;Increment
cleq r0, r0, incdw
;Store the number
store target, r0
store target + 1, r1
;Store the save address
;High byte
load r3, eoflod + 1
store eofchk + 1, r3
store cmpadr, r3
;Low byte
load r0, eoflod + 2
store eofchk + 2, r0
store cmpadr + 1, r0
;Save the line
cleq r0, r0, eofchk
;Insert the next line
breq r0, r0, nextln
inesc: load r0, #20
store ffff, r0
store ffff, r0
store ffff, r0
store ffff, r0
store ffff, r0
store ffff, r0
breq r0, r0, inline
;***
;Set a mark for copying
setmrk: load r0, target
store mark, r0
load r0, target + 1
store mark + 1, r0
breq r0, r0, cmdp
;***
;Copy to mark
;Check the counter
copy: xor r0, r0
load r1, count
breq r0, r1, cmdp
;Reset the line number
xor r0, r0
store lnnum, r0
store lnnum + 1, r0
;Get the save start address
;High byte
load r0, svstrt
store eoflod + 1, r0
;Low byte
load r0, svstrt + 1
store eoflod + 2, r0
;Find the argument line in the save and store its number
cleq r0, r0, fend
;Get the save address of the line
;High byte
load r0, eoflod + 1
store readch + 1, r0
store chsend + 1, r0
;Low byte
load r0, eoflod + 2
store readch + 2, r0
store chsend + 2, r0
;Check for the save end
chsend: load r0, 0
load r1, #1a
breq r0, r1, cmdp
;Restore the buffer start address
;High byte
load r0, bfstrt
store stoch + 1, r0
;Low byte
load r0, bfstrt + 1
store stoch + 2, r0
;Initialise the character counter
xor r0, r0
;Read a character
readch: load r1, 0
;Check for save and buffer ends
;Save end
load r2, #1a
breq r1, r2, feol
;Buffer end
load r2, bfsize
breq r0, r2, feol
;Store the character in the buffer
stoch: store 0, r1
;Check for line and save ends
;Line end
load r2, #a
breq r1, r2, incsz
;Increment the character counter and store it in r3
;Increment
load r2, #1
cleq r0, r0, sum
;Store
xor r3, r3
xor r3, r0
;Increment the save address
;Low byte
load r0, readch + 2
load r2, #1
cleq r0, r0, sum
store readch + 2, r0
;Add the overflow to the high byte
load r0, readch + 1
xor r2, r2
xor r2, r1
cleq r0, r0, sum
store readch + 1, r0
;Increment the buffer address
;Low byte
load r0, stoch + 2
load r2, #1
cleq r0, r0, sum
store stoch + 2, r0
;Add the overflow to the high byte
load r0, stoch + 1
xor r2, r2
xor r2, r1
cleq r0, r0, sum
store stoch + 1, r0
;Reload the character counter to r0
xor r0, r0
xor r0, r3
;Read the next character
breq r0, r0, readch
;Increment and store the string size
feol: load r2, #2
cleq r0, r0, sum
store strsz, r0
;Force line end
load r1, stoch + 1
store stocr + 1 ,r1
load r1, stoch + 2
store stocr + 2 ,r1
;Store the CR of a newline in the buffer
load r0, #d
stocr: store 0, r0
;Increment the buffer address
;Load the address
load r0, stoch + 1
load r1, stoch + 2
;Increment
cleq r0, r0, incdw
;Store the address
store stolf + 1, r0
store stolf + 2, r1
;Store the LF of a newline in the buffer
load r0, #a
stolf: store 0, r0
;Jump to saving
breq r0, r0, svtarg
;Increment and store the string size
incsz: load r2, #1
cleq r0, r0, sum
store strsz, r0
;Save the target at tmp
svtarg: load r0, target
store tmp, r0
load r0, target + 1
store tmp + 1, r0
;Load the mark to target
load r0, mark
store target, r0
load r0, mark + 1
store target + 1, r0
;Reset the line number
xor r0, r0
store lnnum, r0
store lnnum + 1, r0
;Get the save start address
;High byte
load r0, svstrt
store eoflod + 1, r0
;Low byte
load r0, svstrt + 1
store eoflod + 2, r0
;Find the marked line in the save and store its number
cleq r0, r0, fend
;Store the save address
;High byte
load r3, eoflod + 1
store eofchk + 1, r3
store cmpadr, r3
;Low byte
load r0, eoflod + 2
store eofchk + 2, r0
store cmpadr + 1, r0
;Save the marked line
cleq r0, r0, eofchk
;Loop
;Decrement the counter
load r0, count
load r2, #ff
cleq r0, r0, sum
store count, r0
;Check if the mark is a hash
load r2, #ff
load r0, target
brneq r0, r2, incmrk
load r1, target + 1
breq r1, r2, incln
;Increment the mark
incmrk: load r1, target + 1
cleq r0, r0, incdw
store mark, r0
store mark + 1, r1
;Increment the line number
incln: load r0, tmp
load r1, tmp + 1
cleq r0, r0, incdw
store target, r0
store target + 1, r1
;Check if the mark is less than the line number
;Negate the mark and store in tmp
load r0, mark
nand r0, r0
load r1, mark + 1
nand r1, r1
cleq r0, r0, incdw
store tmp, r0
store tmp + 1, r1
;Add the high bytes
load r0, target
load r2, tmp
cleq r0, r0, sum
store tmp, r0
;Store the overflow in r3
xor r3, r3
xor r3, r1
;Add the low bytes
load r0, target + 1
load r2, tmp + 1
cleq r0, r0, sum
;Add the overflow to the high byte
load r0, tmp
xor r2, r2
xor r2, r1
cleq r0, r0, sum
;Check
xor r1, r3
xor r3, r3
breq r1, r3, cpend
;Re-increment the mark
load r0, target
load r1, target + 1
cleq r0, r0, incdw
store target, r0
store target + 1, r1
;Loop
cpend: breq r0, r0, copy
;***
;Delete a line
;Check for an empty counter
delete: xor r0, r0
load r1, count
breq r0, r1, cmdp
;Reset the line number
xor r0, r0
store lnnum, r0
store lnnum + 1, r0
;Get the save start address
;High byte
load r0, svstrt
store eoflod + 1, r0
;Low byte
load r0, svstrt + 1
store eoflod + 2, r0
;Find the argument line in the save and store its number
cleq r0, r0, fend
;Get the save address of the line
;High byte
load r0, eoflod + 1
store stomov + 1, r0
store dchend + 1, r0
;Low byte
load r0, eoflod + 2
store stomov + 2, r0
store dchend + 2, r0
;Check for the save end
dchend: load r0, 0
load r1, #1a
breq r0, r1, cmdp
;Increment the buffer address
;Low byte
load r0, target + 1
load r2, count
cleq r0, r0, sum
store target + 1, r0
;Add the overflow to the high byte
load r0, target
xor r2, r2
xor r2, r1
cleq r0, r0, sum
store target, r0
;Find the next line in the save and store its number
cleq r0, r0, fend
;Get the save address of the line
;High byte
load r0, eoflod + 1
store lodmov + 1, r0
;Low byte
load r0, eoflod + 2
store lodmov + 2, r0
;Move the remainder of the text back
lodmov: load r0, 0
stomov: store 0, r0
;Check for the save end
load r1, #1a
breq r0, r1, delend
;Increment the first save address
;Load the address
load r0, stomov + 1
load r1, stomov + 2
;Increment
cleq r0, r0, incdw
;Store the address
store stomov + 1, r0
store stomov + 2, r1
;Increment the second save address
;Load the address
load r0, lodmov + 1
load r1, lodmov + 2
;Increment
cleq r0, r0, incdw
;Store the address
store lodmov + 1, r0
store lodmov + 2, r1
;Move the next character
breq r0, r0, lodmov
;Return to the command prompt
delend: breq r0, r0, cmdp
;***
;List a line
;Reset the line number
list: xor r0, r0
store lnnum, r0
store lnnum + 1, r0
;Get the save start address
;High byte
load r0, svstrt
store eoflod + 1, r0
;Low byte
load r0, svstrt + 1
store eoflod + 2, r0
;Check the counter
lcount: xor r0, r0
load r1, count
breq r0, r1, cmdp
;Find the argument line in the save and store its number
cleq r0, r0, fend
;Get the save address of the line
;High byte
load r0, eoflod + 1
store chlist + 1, r0
store lchend + 1, r0
;Low byte
load r0, eoflod + 2
store chlist + 2, r0
store lchend + 2, r0
;Check for the save end
lchend: load r0, 0
load r1, #1a
breq r0, r1, cmdp
;Print a line number prompt
cleq r0, r0, prnln
;Load a character from the save
chlist: load r1, 0
;Check for the save end
load r2, #1a
breq r1, r2, prnwln
;Print the character
store ffff, r1
;Check for the line end
load r2, #a
breq r1, r2, lstend
;Increment the save address
;Load the address
load r0, chlist + 1
load r1, chlist + 2
;Increment
cleq r0, r0, incdw
;Store the address
store chlist + 1, r0
store chlist + 2, r1
;Print the next character
breq r0, r0, chlist
;Print a newline
prnwln: cleq r0, r0, newln
;Loop
;Decrement the counter
lstend: load r0, count
load r2, #ff
cleq r0, r0, sum
store count, r0
;Increment the line number
load r0, target
load r1, target + 1
cleq r0, r0, incdw
store target, r0
store target + 1, r1
;Loop
breq r0, r0, lcount
;***
;Print the text
;Get the printer address
;High byte
print: load r0, #ff
store prwrch + 1, r0
;Low byte
load r0, #fe
store prwrch + 2, r0
;Print
cleq r0, r0, prwr
;Return to the command prompt
breq r0, r0, cmdp
;***
;Write the text to the tape punch
;Get the tape punch address
;High byte
write: load r0, #ff
store prwrch + 1, r0
;Low byte
load r0, #fd
store prwrch + 2, r0
;Write
cleq r0, r0, prwr
;Write an end-of-file
load r0, #1a
store fffd, r0
;Return to the command prompt
breq r0, r0, cmdp
;***
;Read the text from the tape reader
;Get the save start address
;High byte
read: load r0, svstrt
store chrsto + 1, r0
;Low byte
load r0, svstrt + 1
store chrsto + 2, r0
;Ignore the leader
iglead: load r1, fffd
xor r2, r2
breq r1, r2, iglead
breq r0, r0, chkend
;Read a character
chread: load r1, fffd
;Check for trailer or empty tape reader
;Trailer
chkend: xor r2, r2
brneq r1, r2, chkntp
load r1, #1a
breq r0, r0, chrsto
;Empty tape reader
chkntp: nand r2, r2
brneq r1, r2, chrsto
load r1, #1a
;Store a character
chrsto: store buffer + 100, r1
;Check for the save end
load r2, #1a
breq r1, r2, redend
;Increment the save address
;Load the address
load r0, chrsto + 1
load r1, chrsto + 2
;Increment
cleq r0, r0, incdw
;Store the address
store chrsto + 1, r0
store chrsto + 2, r1
;Read the next character
breq r0, r0, chread
;Return to the command prompt
redend: breq r0, r0, cmdp
;***
;Halt
end: halt
;***
;Print a newline
newln: load r0, #d
store ffff, r0
load r0, #a
store ffff, r0
ret
;***
;Print an error
error: load r0, #3f
store ffff, r0
cleq r0, r0, newln
;***
;Add r2 to r0 with the overflow stored in r1
;Reset overflow
sum: xor r1, r1
store ovrflw, r1
;Copy the first argument to r1
sumlop: xor r1, r1
xor r1, r0
;Calculate the sum and carry and copy the pre-shift carry to r1
;Sum
xor r0, r2
;Carry
and r2, r1
;Copy the pre-shift carry
xor r1, r1
xor r1, r2
;Shift the carry
shl r2
;Check for and store overflow if any
;Check
rol r1
breq r1, r2, nvrflw
;Store
load r1, #1
store ovrflw, r1
;Check for no carry
nvrflw: xor r1, r1
breq r1, r2, sumend
;Loop
breq r0, r0, sumlop
;Load overflow and return
sumend: load r1, ovrflw
ret
;***
;Increment a value stored in r0 and r1
;Store the high byte in r3
incdw: xor r3, r3
xor r3, r0
;Load the low byte to r0
xor r0, r0
xor r0, r1
;Increment the low byte
load r2, #1
cleq r0, r0, sum
;Load the high byte to r0 and store the low byte in r3
;Move the high byte to r2
xor r2, r2
xor r2, r3
;Store the low byte to r3
xor r3, r3
xor r3, r0
;Load the high byte to r0
xor r0, r0
xor r0, r2
;Add the overflow to the high byte
xor r2, r2
xor r2, r1
cleq r0, r0, sum
;Load the low byte in r1
xor r1, r1
xor r1, r3
;Return
ret
;***
;Decrement a value stored in r0 and r1
;Store the low byte in r3
decdw: xor r3, r3
xor r3, r1
;Decrement the high byte
load r2, #ff
cleq r0, r0, sum
;Load the low byte to r0 and store the high byte in r3
;Move the low byte to r2
xor r2, r2
xor r2, r3
;Store the high byte to r3
xor r3, r3
xor r3, r0
;Load the low byte to r0
xor r0, r0
xor r0, r2
;Decrement the low byte
load r2, #ff
cleq r0, r0, sum
;Load the high byte to r0 and store the low byte in r3
;Move the high byte to r2
xor r2, r2
xor r2, r3
;Store the low byte to r3
xor r3, r3
xor r3, r0
;Load the high byte to r0
xor r0, r0
xor r0, r2
;Add the overflow to the high byte
xor r2, r2
xor r2, r1
cleq r0, r0, sum
;Load the low byte in r1
xor r1, r1
xor r1, r3
;Return
ret
;***
;Get the hexadecimal digit of a nibble
;Extract the low nibble
n2hex: load r1, #f
and r0, r1
;Get the nibble value
load r1, #0
breq r0, r1, dgt0
load r1, #1
breq r0, r1, dgt1
load r1, #2
breq r0, r1, dgt2
load r1, #3
breq r0, r1, dgt3
load r1, #4
breq r0, r1, dgt4
load r1, #5
breq r0, r1, dgt5
load r1, #6
breq r0, r1, dgt6
load r1, #7
breq r0, r1, dgt7
load r1, #8
breq r0, r1, dgt8
load r1, #9
breq r0, r1, dgt9
load r1, #a
breq r0, r1, dgta
load r1, #b
breq r0, r1, dgtb
load r1, #c
breq r0, r1, dgtc
load r1, #d
breq r0, r1, dgtd
load r1, #e
breq r0, r1, dgte
load r1, #f
breq r0, r1, dgtf
;Load the hexadecimal digit of the nibble
dgt0: load r0, #30
breq r0, r0, n2hend
dgt1: load r0, #31
breq r0, r0, n2hend
dgt2: load r0, #32
breq r0, r0, n2hend
dgt3: load r0, #33
breq r0, r0, n2hend
dgt4: load r0, #34
breq r0, r0, n2hend
dgt5: load r0, #35
breq r0, r0, n2hend
dgt6: load r0, #36
breq r0, r0, n2hend
dgt7: load r0, #37
breq r0, r0, n2hend
dgt8: load r0, #38
breq r0, r0, n2hend
dgt9: load r0, #39
breq r0, r0, n2hend
dgta: load r0, #41
breq r0, r0, n2hend
dgtb: load r0, #42
breq r0, r0, n2hend
dgtc: load r0, #43
breq r0, r0, n2hend
dgtd: load r0, #44
breq r0, r0, n2hend
dgte: load r0, #45
breq r0, r0, n2hend
dgtf: load r0, #46
breq r0, r0, n2hend
;Return
n2hend: ret
;***
;Get the nibble of a hexadecimal digit
;Get the nibble value
;Numeric digits
hex2n: load r1, #30
breq r0, r1, nbl0
load r1, #31
breq r0, r1, nbl1
load r1, #32
breq r0, r1, nbl2
load r1, #33
breq r0, r1, nbl3
load r1, #34
breq r0, r1, nbl4
load r1, #35
breq r0, r1, nbl5
load r1, #36
breq r0, r1, nbl6
load r1, #37
breq r0, r1, nbl7
load r1, #38
breq r0, r1, nbl8
load r1, #39
breq r0, r1, nbl9
;Uppercase letter digits
load r1, #41
breq r0, r1, nbla
load r1, #42
breq r0, r1, nblb
load r1, #43
breq r0, r1, nblc
load r1, #44
breq r0, r1, nbld
load r1, #45
breq r0, r1, nble
load r1, #46
breq r0, r1, nblf
;Lowercase letter digits
load r1, #61
breq r0, r1, nbla
load r1, #62
breq r0, r1, nblb
load r1, #63
breq r0, r1, nblc
load r1, #64
breq r0, r1, nbld
load r1, #65
breq r0, r1, nble
load r1, #66
breq r0, r1, nblf
;Load a question mark if the character is not a digit
load r0, #3f
breq r0, r0, h2nend
;Load the hexadecimal digit of the nibble
nbl0: load r0, #0
breq r0, r0, h2nend
nbl1: load r0, #1
breq r0, r0, h2nend
nbl2: load r0, #2
breq r0, r0, h2nend
nbl3: load r0, #3
breq r0, r0, h2nend
nbl4: load r0, #4
breq r0, r0, h2nend
nbl5: load r0, #5
breq r0, r0, h2nend
nbl6: load r0, #6
breq r0, r0, h2nend
nbl7: load r0, #7
breq r0, r0, h2nend
nbl8: load r0, #8
breq r0, r0, h2nend
nbl9: load r0, #9
breq r0, r0, h2nend
nbla: load r0, #a
breq r0, r0, h2nend
nblb: load r0, #b
breq r0, r0, h2nend
nblc: load r0, #c
breq r0, r0, h2nend
nbld: load r0, #d
breq r0, r0, h2nend
nble: load r0, #e
breq r0, r0, h2nend
nblf: load r0, #f
breq r0, r0, h2nend
;Return
h2nend: ret
;***
;Get the hexadecimal digits of a byte
;Load the byte to to r2
bt2hex: xor r2, r2
xor r2, r0
;Convert the low nibble to a digit and store it in r2
;Convert
cleq r0, r0, n2hex
;Store
xor r1, r1
xor r1, r0
;Re-load the byte to r0
xor r0, r0
xor r0, r2
;Store the low nibble in r2
xor r2, r2
xor r2, r1
;Convert the high nibble to a digit
ror r0
ror r0
ror r0
ror r0
cleq r0, r0, n2hex
;Load the digit of the low nibble to r1
xor r1, r1
xor r1, r2
;Return
ret
;***
;Input a character
;Restore the buffer start address
;High byte
input: load r0, bfstrt
store chstor + 1, r0
;Low byte
load r0, bfstrt + 1
store chstor + 2, r0
;Initialise the character counter
xor r0, r0
;Read a character
inloop: load r1, ffff
;Check for control characters and the buffer end
;Delete
load r2, #7f
breq r1, r2, delbr
;Escape
load r2, #1b
breq r1, r2, escbr
;End-of-file
load r2, #1a
breq r1, r2, eofbr
;Carriage return
load r2, #d
breq r1, r2, crbr
;Line feed
load r2, #a
breq r1, r2, lfbr
;Buffer end
load r2, bfsize
brneq r0, r2, chstor
;Backtrack if at the buffer end
load r2, #8
store ffff, r2
breq r0, r0, inloop
;Store the character in the buffer
chstor: store buffer, r1
;Increment the character counter and store it in r3
;Increment
load r2, #1
cleq r0, r0, sum
;Store
xor r3, r3
xor r3, r0
;Increment the buffer address
;Low byte
load r0, chstor + 2
load r2, #1
cleq r0, r0, sum
store chstor + 2, r0
;Add the overflow to the high byte
load r0, chstor + 1
xor r2, r2
xor r2, r1
cleq r0, r0, sum
store chstor + 1, r0
;Reload the character counter to r0
xor r0, r0
xor r0, r3
;Read the next character
breq r0, r0, inloop
;Print an underscore
delbr: load r2, #5f
store ffff, r2
;Check for buffer start
xor r2, r2
breq r0, r2, inloop
;Decrement the character counter and store it in r3
;Decrement
load r2, #ff
cleq r0, r0, sum
;Store
xor r3, r3
xor r3, r0
;Decrement the buffer address
;High byte
load r0, chstor + 1
load r2, #ff
cleq r0, r0, sum
store chstor + 1, r0
;Low byte
load r0, chstor + 2
load r2, #ff
cleq r0, r0, sum
store chstor + 2, r0
;Add the overflow to the high byte
load r0, chstor + 1
xor r2, r2
xor r2, r1
cleq r0, r0, sum
store chstor + 1, r0
;Reload the character counter to r0
xor r0, r0
xor r0, r3
;Read the next character
breq r0, r0, inloop
;Print a backslash and a newline
;Backslash
escbr: load r0, #20
store ffff, r0
load r0, #5c
store ffff, r0
;Newline
cleq r0, r0, newln
;Return with escape in r2
breq r0, r0, inend
;Print a newline
eofbr: cleq r0, r0, newln
;Return with End-of-file at r2
breq r0, r0, inend
;Print a line feed
crbr: load r1, #a
store ffff, r1
breq r0, r0, endnl
;Print a carriage return
lfbr: load r1, #d
store ffff, r1
;Increment and store the string size
endnl: load r2, #2
cleq r0, r0, sum
store strsz, r0
;Get the buffer address
load r1, chstor + 1
store endcr + 1, r1
load r1, chstor + 2
store endcr + 2, r1
;Store the CR of a newline in the buffer
load r0, #d
endcr: store 0, r0
;Increment the buffer address
;Load the address
load r0, chstor + 1
load r1, chstor + 2
;Increment
cleq r0, r0, incdw
;Store the address
store endlf + 1, r0
store endlf + 2, r1
;Store the LF of a newline in the buffer
load r0, #a
endlf: store 0, r0
;Return
inend: ret
;***
;Make room for the line
;Find the end of the save address
;Check for an end-of-file
eofchk: load r0, 0
load r1, #1a
breq r0, r1, endfnd
;Load the address
load r0, eofchk + 1
load r1, eofchk + 2
;Increment
cleq r0, r0, incdw
;Store the address
store eofchk + 1, r0
store eofchk + 2, r1
;Check the next character
breq r0, r0, eofchk
;Store the end of the save address
;High byte
endfnd: load r3, eofchk + 1
store movlod + 1, r3
;Low byte
load r0, eofchk + 2
store movlod + 2, r0
;Calculate the new end of the save
;Increment the low byte
load r2, strsz
cleq r0, r0, sum
;Move the high byte to r2
xor r2, r2
xor r2, r3
;Store the low byte to r3
xor r3, r3
xor r3, r0
;Load the high byte to r0
xor r0, r0
xor r0, r2
;Add the overflow to the high byte
xor r2, r2
xor r2, r1
cleq r0, r0, sum
;Store the new end of the save
store movsto + 1, r0
store movsto + 2, r3
;Move the End-of-file
movlod: load r0, 0
movsto: store 0, r0
;Check for the address of the new line
load r0, cmpadr
load r1, movlod + 1
brneq r0, r1, decsav
load r0, cmpadr + 1
load r1, movlod + 2
brneq r0, r1, decsav
breq r0, r1, save
;Decrement the old save address
;load the address
decsav: load r0, movlod + 1
load r1, movlod + 2
;Decrement
cleq r0, r0, decdw
;Store the address
store movlod + 1, r0
store movlod + 2, r1
;Decrement the new save address
;load the address
load r0, movsto + 1
load r1, movsto + 2
;Decrement
cleq r0, r0, decdw
;Store the address
store movsto + 1, r0
store movsto + 2, r1
;Move the next character
breq r0, r0, movlod
;***
;Save the line
;Restore the buffer start address
;High byte
save: load r0, bfstrt
store chload + 1, r0
;Low byte
load r0, bfstrt + 1
store chload + 2, r0
;Store the save address
;High byte
load r0, eoflod + 1
store chsave + 1, r0
;Low byte
load r0, eoflod + 2
store chsave + 2, r0
;Load and save a character from the buffer
;Load
chload: load r1, buffer
;Save
chsave: store buffer + 100, r1
;Check for line end
load r2, #a
breq r1, r2, savend
;Increment the buffer address
;Load the address
load r0, chload + 1
load r1, chload + 2
;Increment
cleq r0, r0, incdw
;Store the address
store chload + 1, r0
store chload + 2, r1
;Increment the save address
;Load the address
load r0, chsave + 1
load r1, chsave + 2
;Increment
cleq r0, r0, incdw
;Store the address
store chsave + 1, r0
store chsave + 2, r1
;Load and save the next character
breq r0, r0, chload
;Return
savend: ret
;***
;Find the argument line in the save and store its number
;Check for the argument
fend: load r0, target
load r1, lnnum
brneq r0, r1, feof
load r0, target + 1
load r1, lnnum + 1
breq r0, r1, fendnd
;Check for control characters
;End-of-file
feof: load r0, #1a
eoflod: load r1, 0
breq r0, r1, fendnd
;Line feed
load r2, #a
brneq r1, r2, incsav
;Increment the line number
;Load the number
load r0, lnnum
load r1, lnnum + 1
;Increment
cleq r0, r0, incdw
;Store the number
store lnnum, r0
store lnnum + 1, r1
;Increment the save address
;Load the address
incsav: load r0, eoflod + 1
load r1, eoflod + 2
;Increment
cleq r0, r0, incdw
;Store the address
store eoflod + 1, r0
store eoflod + 2, r1
;Check the next character
breq r0, r0, fend
;Return
fendnd: ret
;***
;Print a line number prompt
;Print the high byte
;Get the byte
prnln: load r0, lnnum
;Convert
cleq r0, r0, bt2hex
;Print
load r2, #30
breq r0, r2, lead0
store ffff, r0
nlead0: store ffff, r1
load r3, #1
breq r0, r0, lbtln
lead0: load r0, #20
store ffff, r0
brneq r1, r2, nlead0
load r1, #20
store ffff, r1
xor r3, r3
;Print the low byte
;Get the byte
lbtln: load r0, lnnum + 1
;Convert
cleq r0, r0, bt2hex
;Check for preceding leading zeroes
xor r2, r2
brneq r2, r3, nled0s
;Print
load r2, #30
brneq r0, r2, nled0s
load r0, #20
store ffff, r0
store ffff, r1
breq r0, r0, prcln
nled0s: store ffff, r0
store ffff, r1
;Print a colon
prcln: load r0, #3a
store ffff, r0
load r0, #20
store ffff, r0
;Return
ret
;***
;Print or write to tape
;Get the save start address
;High byte
prwr: load r0, svstrt
store chprwr + 1, r0
;Low byte
load r0, svstrt + 1
store chprwr + 2, r0
;Load a character from the save
chprwr: load r1, buffer + 100
;Check for the save end
load r2, #1a
breq r1, r2, pwend
;Print the character
prwrch: store fffe, r1
;Increment the save address
;Load the address
load r0, chprwr + 1
load r1, chprwr + 2
;Increment
cleq r0, r0, incdw
;Store the address
store chprwr + 1, r0
store chprwr + 2, r1
;Print the next character
breq r0, r0, chprwr
;Return
pwend: ret
;***
;Data
;Variables
ovrflw: data 0
lnnum: data 0
data 0
strsz: data 0
dgtcnt: data 0
dgtadr: addr buffer + 2
cmd: data 0
arg1: data 30
data 30
data 30
data 30
argf1: data 0
arg2: data 30
data 30
argf2: data 0
target: data 0
data 0
count: data 0
mark: data 0
data 0
mrkadr: data 0
data 0
cmpadr: data 0
data 0
tmp: data 0
data 0
;Buffer and save
bfstrt: addr buffer
bfsize: data fe
svstrt: addr buffer + 100
buffer: