Gidubba/gidubba.asm

1931 lines
47 KiB
NASM
Raw Permalink 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
;***
;Check the RAM size
;Initialise the comparison value
load r0, #1b
;Check a memory location
mchks: store ffef, r0
mchkl: load r1, ffef
breq r0, r1, svlmit
;Decrement the pointer
load r0, mchks + 1
load r2, #fc
cleq r0, r0, sum
store mchks + 1, r0
store mchkl + 1, r0
;Check the next location
breq r0, r0, mchks
;Save the RAM limit
svlmit: load r0, mchks + 1
store limit, r0
;***
;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, 4
;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, 4
;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, 4
;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: load r0, #3f
store ffff, r0
cleq r0, r0, newln
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
;Make room for the line
cleq r0, r0, eofchk
xor r0, r0
brneq r0, r1, cmdp
;Restore the buffer start address
;High byte
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, nextln
;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
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 for an empty 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 strsz, r0
store chsend + 1, r0
;Low byte
load r0, eoflod + 2
store strsz + 1, r0
store chsend + 2, r0
;Check for the save end
chsend: load r0, 0
load r1, #1a
breq r0, r1, cmdp
;Save the buffer address to tmp1 and increment it
;Low byte
load r0, target + 1
store tmp1 + 1, r0
load r2, count
cleq r0, r0, sum
store target + 1, r0
;Add the overflow to the high byte
load r0, target
store tmp1, r0
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 tmp2, r0
;Low byte
load r0, eoflod + 2
store tmp2 + 1, r0
;Negate the first address
;Low byte
load r0, strsz + 1
nand r0, r0
load r2, #1
cleq r0, r0, sum
store strsz + 1, r0
;Reverse and add the overflow to the high byte
load r0, strsz
nand r0, r0
xor r2, r2
xor r2, r1
cleq r0, r0, sum
store strsz, r0
;Get the copy length
;High byte
load r0, tmp2
load r2, strsz
cleq r0, r0, sum
store strsz, r0
;Low byte
load r0, tmp2 + 1
load r2, strsz + 1
cleq r0, r0, sum
store strsz + 1, r0
;Reverse and add the overflow to the high byte
load r0, strsz
xor r2, r2
xor r2, r1
cleq r0, r0, sum
store strsz, 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
store cstor + 1, r3
store cinit + 1, r3
;Low byte
load r0, eoflod + 2
store eofchk + 2, r0
store cmpadr + 1, r0
store cstor + 2, r0
store cinit + 2, r0
;Make room for the copy
cleq r0, r0, eofchk
xor r0, r0
brneq r0, r1, cmdp
;Check for the end of the space
cendsp: load r0, movsto + 1
load r1, cinit + 1
brneq r0, r1, cinist
load r0, movsto + 2
load r1, cinit + 2
brneq r0, r1, cinist
breq r0, r1, relodt
;Initialise a character
cinist: load r0, #0
cinit: store 0, r0
;Increment the source address
;Load the address
incini: load r0, cinit + 1
load r1, cinit + 2
;Increment
cleq r0, r0, incdw
;Store the address
store cinit + 1, r0
store cinit + 2, r1
;Initialise the next character
breq r0, r0, cendsp
;Reload the target from tmp1
relodt: load r0, tmp1
store target, r0
load r0, tmp1 + 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 cload + 1, r3
;Low byte
load r0, eoflod + 2
store cload + 2, r0
;Copy a character
;Load
cload: load r1, 0
;Check for a null
xor r2, r2
breq r1, r2, skip0
;Check for save end
load r2, #1a
breq r1, r2, cmdp
;Save
cstor: store 0, r1
;Check for line end
load r2, #a
brneq r1, r2, cincs
;Decrement the counter
load r0, count
load r2, #ff
cleq r0, r0, sum
store count, r0
;Check the counter
xor r0, r0
load r1, count
breq r0, r1, cmdp
;Increment the source address
;Load the address
cincs: load r0, cload + 1
load r1, cload + 2
;Increment
cleq r0, r0, incdw
;Store the address
store cload + 1, r0
store cload + 2, r1
;Increment the copy address
;Load the address
load r0, cstor + 1
load r1, cstor + 2
;Increment
cleq r0, r0, incdw
;Store the address
store cstor + 1, r0
store cstor + 2, r1
;Load and save the next character
breq r0, r0, cload
;Increment the source address
;Load the address
skip0: load r0, cload + 1
load r1, cload + 2
;Increment
cleq r0, r0, incdw
;Store the address
store cload + 1, r0
store cload + 2, r1
;Load the next character
breq r0, r0, cload
;***
;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
;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
;Check for the RAM limit
load r0, chrsto + 1
load r1, chrsto + 2
chkram: cleq r0, r0, ramchk
xor r2, r2
brneq r1, r2, cmdp
;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, chklf
load r1, #1a
breq r0, r0, chrsto
;Check for a line feed
chklf: load r2, #a
load r3, #0
brneq r1, r2, chrsto
load r1, #d
load r3, #a
;Store a character
chrsto: store buffer + 100, r1
;Check for a newline
;Line feed
load r2, #a
breq r2, r3, readlf
;Carriage return
load r2, #d
breq r1, r2, readcr
;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, chkram
;Read a newline beginning with a carriage return
readcr: cleq r0, r0, readnl
;Check for a line feed
load r2, #a
breq r1, r2, chread
breq r0, r0, chkend
;Read a newline beginning with a line feed
readlf: cleq r0, r0, readnl
;Check for a carriage return
load r2, #d
breq r1, r2, chread
breq r0, r0, chkend
;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
;***
;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, 1
;Check for and store overflow if any
;Check
rol r1, 1
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, 4
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
;Null
load r2, #0
breq r1, r2, inloop
;FF
load r2, #ff
breq r1, r2, inloop
;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
;Ignore the input and print an underscore if at the buffer end
load r2, #5f
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
ret
;Print a newline
eofbr: cleq r0, r0, newln
;Return with End-of-file at r2
ret
;Print a line feed
crbr: load r1, #a
store ffff, r1
breq r0, r0, endnl
;Print a carriage return and a null
lfbr: load r1, #d
store ffff, r1
load r1, #0
store ffff, r1
;Increment and store the string size
endnl: load r2, #2
cleq r0, r0, sum
store strsz + 1, r0
load r0, #0
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
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 r0, eofchk + 1
store movlod + 1, r0
;Low byte
load r3, eofchk + 2
store movlod + 2, r3
;Calculate the new end of the save
;High byte
load r2, strsz
cleq r0, r0, sum
store strsz, r0
;Check for overflow from the high byte
xor r0, r0
brneq r0, r1, lmterr
;Low byte
xor r0, r0
xor r0, r3
load r2, strsz + 1
cleq r0, r0, sum
store strsz + 1, r0
;Add the overflow to the high byte
load r0, strsz
xor r2, r2
xor r2, r1
cleq r0, r0, sum
;Store the new end of the save
store movsto + 1, r0
load r3, strsz + 1
store movsto + 2, r3
;Check for overflow from the high byte
xor r0, r0
brneq r0, r1, lmterr
;Negate the RAM limit
;Low byte
load r0, limit + 1
nand r0, r0
load r2, #1
cleq r0, r0, sum
store tmp2 + 1, r0
;Reverse and add the overflow to the high byte
load r0, limit
nand r0, r0
xor r2, r2
xor r2, r1
cleq r0, r0, sum
store tmp2, r0
;Subtract the RAM limit from the new end of the save
;High byte
load r0, movsto + 1
load r2, tmp2
cleq r0, r0, sum
store tmp2, r0
;Check for overflow from the high byte
xor r0, r0
brneq r0, r1, lmterr
;Low byte
load r0, movsto + 2
load r2, tmp2 + 1
cleq r0, r0, sum
store tmp2 + 1, r0
;Add the overflow to the high byte
load r0, tmp2
xor r2, r2
xor r2, r1
cleq r0, r0, sum
store tmp2, r0
;Check for overflow from the high byte
xor r0, r0
brneq r0, r1, lmterr
;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, roomnd
;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
;Return with a null at r1
roomnd: xor r1, r1
ret
;Print an error and return with an exclamation mark at r1
lmterr: load r0, #21
store ffff, r0
cleq r0, r0, newln
load r1, #21
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
;Print the character
prwrch: store fffe, r1
;Check for the save end
load r2, #1a
breq r1, r2, pwend
;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
;***
;Check for the RAM limit
;Check
ramchk: load r2, limit
load r3, limit + 1
brneq r0, r2, ramend
brneq r1, r3, ramend
;Save an end-of-file at the start address
load r0, #1a
store buffer + 100, r0
;Print an error
load r0, #21
store ffff, r0
cleq r0, r0, newln
;Return with an exclamation mark at r1
load r1, #21
ret
;Return with a null at r1
ramend: load r1, #0
ret
;***
;Read a newline
;Increment the save address
;Load the address
readnl: load r0, chrsto + 1
load r1, chrsto + 2
;Increment
cleq r0, r0, incdw
;Store the address
store chrsto + 1, r0
store lfstor + 1, r0
store chrsto + 2, r1
store lfstor + 2, r1
;Check for the RAM limit
cleq r0, r0, ramchk
xor r2, r2
brneq r1, r2, cmdp
;Store a line feed
load r1, #a
lfstor: store 0, r1
;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
;Check for the RAM limit
cleq r0, r0, ramchk
xor r2, r2
brneq r1, r2, cmdp
;Read a character
load r1, fffd
;Return
ret
;***
;Data
;Variables
ovrflw: data 0
lnnum: data 0
data 0
strsz: data 0
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
tmp1: data 0
data 0
tmp2: data 0
data 0
;Buffer and save
bfstrt: addr buffer
bfsize: data fe
svstrt: addr buffer + 100
limit: data 0
data 0
buffer: