Category : Assembly Language Source Code
Archive   : CUG292.ZIP
Filename : MOND09.ASM

 
Output of file : MOND09.ASM contained in archive : CUG292.ZIP

.title MONDEB - 09

; *********************************************************
; * *
; * MONDEB - 09 - a monitor/debugger *
; * for the 6809 microprocessor *
; * *
; *********************************************************
;
; author: Don Peters (6800 version)
; date: April 1977
;
; modified for the 6809
; by: Alan R. Baldwin
; date: Nov 1988
;
; This 6809 monitor/debugger does not use the
; direct page addressing mode. Thus the user
; program has complete control of the page
; assignment and may use the monitor routines
; without concern for variable locations.
;
; To add user functions to MONDEB - 09
;
; 1) add your commands to the end of command list #1
; 2) add the command entry points to the jump table
; 3) append any local command lists after MONDEB's
; 4) provide an external initialization routine to
; set up the console (and/or alternate)
; ports and any other start up processing.
; MONDEB will call 'userinit' if inituser = 1.
;

.module mond09

standalone = 0 ; standalone flag indicating the
; vectors and associated code are
; to be included during assembly

inituser = 0 ; call 'userinit' flag indicating
; a user startup routine will be
; called during intialization

.page
.sbttl MONDEB - 09 working variables

.radix d

.if standalone

.area WORKPG (REL,CON)

.else

.area WORKPG (ABS,OVR)

.endif

.setdp 0

workpg: .blkb 256-(endpg-mstack)
; main stack storage
mstack: .blkb 12 ; stack storage for rti instruction

ttybuf: .blkb 72 ; start of input line buffer
ttyend: .blkb 1 ; end of input line buffer
bufbeg: .blkb 2 ; input line start of buffer
bufend: .blkb 2 ; input line end of buffer

comadr: .blkb 2 ; address of beginning of command lists
synptr: .blkb 2 ; input line character pointer for good syntax
linptr: .blkb 2 ; input line character pointer (content =>
; content of synptr)
bolflg: .blkb 1 ; "beginning of line flg"
delim: .blkb 1 ; characters permitted as valid command/modifier
; delimiter
ibcode: .blkb 1 ; input base (1=hex, 2=dec, 3=oct)
dbcode: .blkb 1 ; display base (1=hex, 2=dec, 3=oct, 4=bin)
dbnbr: .blkb 1 ; display base number (e.g., 16,10,8, or 2)
nbrhi: .blkb 1 ; most significant byte of scanned number
nbrlo: .blkb 1 ; least significant byte of scanned number
ranglo: .blkb 2 ; range lower limit picked up by gtrang
ranghi: .blkb 2 ; range upper limit picked up by gtrang
verfrm: .blkb 2 ; beginning address of range to verify
verto: .blkb 2 ; ending address of range to checksum verify
chksum: .blkb 1 ; checksum of range given in the verify command
brkadr: .blkb 2 ; address of inserted breakpoint
brkins: .blkb 1 ; instruction which should be there normally
inpflg: .blkb 1 ; alternate input flag
outflg: .blkb 1 ; alternate output flag
outadr: .blkb 2 ; alternate address that the output chars go to
hdxflg: .blkb 1 ; half-duplex terminal flag (if non-zero, no echo)
cplcnt: .blkb 1 ; "characters per line" count
cplmax: .blkb 1 ; "characters per line" maximum

; temporary (locally used) variables

temp1: .blkb 2 ; in: main
temp2: .blkb 2 ; in: main
temp3: .blkb 2 ; in: main
temp4: .blkb 2 ; in: main
temp5: .blkb 2 ; in: main
temp6: .blkb 2 ; in: main

nummat: .blkb 1 ; used in command
lisnum: .blkb 1 ; used in command
comnum: .blkb 1 ; used in command
lisptr: .blkb 2 ; used in command
decdig: .blkb 1 ; decimal digit being built
numbhi: .blkb 1 ; used by outnum
numblo: .blkb 1 ; used by outnum
nbr2x: .blkb 2 ; used by number
timcon: .blkb 2 ; delay time constant
bytect: .blkb 1 ; record byte count used in load command
cksm: .blkb 1 ; record checksum used in load command

conin: .blkb 2 ; address of console input routine
conout: .blkb 2 ; address of console output routine
altin: .blkb 2 ; address of alternate input routine
altout: .blkb 2 ; address of alternate output routine

.rsrvd: .blkb 2 ; reserved vector
.swi3: .blkb 2 ; swi3 vector
.swi2: .blkb 2 ; swi2 vector
.firq: .blkb 2 ; firq vector
.irq: .blkb 2 ; irq vector
.swi: .blkb 2 ; swi vector
.nmi: .blkb 2 ; nmi vector
spsave: .blkb 2 ; saved stack pointer
endpg:

; convenient equivalences for local variables

memadr = temp1 ; display, set, search, test
strnum = temp2 ; fndstr
eoschr = temp2+1 ; fndstr

; for "search" command

bytptr = temp2
nbytes = temp3
nbrmat = temp3+1
bytstr = temp4

; other constants

cr = 13 ; carriage return
lf = 10 ; line feed


.page
.sbttl MOND09 Startup

.if standalone

.area MONDEB (REL,CON)

reset: lds #mstack+12 ; load stack pointer
bsr mond09 ; stack pc and start mondeb
bra reset
.else

.area MONDEB (ABS,OVR)

.endif

mond09: pshs u,y,x,dp,b,a,cc ; pseudo swi
sts spsave ; save the pointer
orcc #0b01010000 ; hold irq and firq interrupts
lds #mstack ; initialize the stack pointer
jsr inital ; initialize variables
jsr docrlf ; advance to a clean line
ldx #msghed ; get address of header
jsr outstr ; type it
ldx #ttybuf-1 ; get address of terminal input buffer
stx bufbeg ; save it
ldx #ttyend ; define end of input buffer
stx bufend ; 72 char capacity, incl cr
lda #3 ; delimiter class definition
sta delim ; space or comma (code 3)
bra promp1

; prepare to get a new command

prompt: jsr docrlf ; type cr-lf
inc bolflg ; set 'beginning of line' flag
ldx synptr ; point to current character
lda ,x ; get it
cmpa #'; ; semicolon?
beq getcmd ; continue scan if it is,
; skipping the prompt
promp1: ldx #msgprm ; type prompt
jsr outstr
jsr getlin ; get line of input
cmpb #3 ; abort line on a control-c
beq prompt

ldx bufbeg ; set syntax scanning pointer
stx synptr ; to beginning of buffer/line
lda 1,x ; get first char
jsr tsteol ; reprompt on an empty line
beq prompt ; (first char = cr,lf,or 😉

.page
.sbttl Get Command

getcmd: lda #1 ; use list 1 when matching
jsr comand ; now go for a match
beq prompt ; reprompt if just a cr was typed
bgt jmpcmd ; good command if positive

badsyn: ldx bufbeg ; get start of line

1$: cpx linptr ; space over to the error in syntax
beq 2$ ; at error ?
jsr outsp ; output a space
inx ; no, move on
bra 1$

; the 'extra' char '1' is compensated for by the prompt
; char on the preceeding line

2$: lda #'^ ; at error - get an up-arrow
jsr outchr ; print it
jsr docrlf
bra promp1 ; ignore any succeeding packed
; commands

; *******
; *there should be no more characters on the input line
; (except delimiters)

nomore: jsr skpdlm
bcs prompt ; if carry bit set, end of line
; (normal)
bra badsyn ; there is something there but shouldn't be

.page
.sbttl Command Dispatcher

; ******
; execute a computed 'goto' to the proper command

jmpcmd: asla ; multiply command by 2
ldx #1$-2
jmp [a,x] ; jump to designated command

1$: .word break
.word contin
.word compar
.word copy
.word displa
.word dbase
.word delay
.word dump
.word goto
.word help
.word ibase
.word load
.word reg
.word set
.word search
.word test
.word verify
.word cli
.word clf
.word sei
.word sef
.word xirq
.word xfirq
.word xnmi
.word xrsrvd
.word xswi
.word xswi2
.word xswi3

.page
.sbttl REG - display registers

reg: ; print stack stored swi data
disreg: ldx spsave ; get saved stack pointer
clr comnum ; start at beginning of the
; register name list
bsr 1$ ; type condition codes
bsr 1$ ; type acca
bsr 1$ ; type accb
bsr 1$ ; type dp
jsr docrlf ; advance to a clean line
bsr 2$ ; type index reg x
bsr 2$ ; type index reg y
bsr 2$ ; type index reg u
jsr docrlf ; advance to a clean line
leax -9,x ; back to d
bsr 2$ ; type d
leax 7,x ; back to pc
bsr 2$ ; type program counter

; type the stack pointer location

bsr 3$ ; type stack pointer id
ldx #spsave
jsr out2by ; type the value
jmp nomore

; output content of a 1 byte register

1$: bsr 3$
jsr out1by
inx
rts

; output content of a 2 byte register

2$: bsr 3$
jsr out2by
leax 2,x ; skip to next word in stack
rts

; misc setup for register display

3$: jsr outsp ; output a space
inc comnum ; skip to next register name
lda #5 ; register name is in list 5
jsr typcmd ; type it
jsr outeq ; type an '='
rts

.page
.sbttl Software Interrupt Entry Point

typswi: sts spsave
ldx #msgswi
jsr outstr

; decrement pc so it points to 'swi' instruction

ldx spsave
ldd 10,x
subd #1
cmpd brkadr ; a break point ?
bne disreg ; no - allow to pass
std 10,x ; backup PC
bra disreg ; go display registers

.sbttl GOTO - Go To Memory Address

goto: jsr mnumber ; get destination
beq contin ; if none, just continue
ldd nbrhi
lds spsave ; place new PC
std 10,s ; fall through to Continue

.sbttl Continue - Continue From a 'SWI'

contin: lds spsave ; in case sp was modified via set
rti ; command

.sbttl SEI - Set Interrupt Mask

sei: orcc #0b00010000
jmp nomore

.sbttl CLI - Clear Interrupt Mask

cli: andcc #~0b00010000
jmp nomore

.sbttl SEF - Set Fast Interrupt Mask

sef: orcc #0b01000000
jmp nomore

.sbttl CLF - Clear Fast Interrupt Mask

clf: andcc #~0b01000000
jmp nomore

.page
.sbttl COPY - Copy From One Location To Another

copy: jsr gtrang ; get source range into ranglo &
; ranghi
lble badsyn ; error if no source
jsr mnumber ; get destination
lble badsyn ; error if no destination
ldx ranglo ; get source address pointer
ldu nbrhi ; get destination address pointer
lda ,x ; get byte from source
1$: sta ,u+ ; save byte in destination
cpx ranghi ; compare to end of input range
lbeq nomore ; done if equal
lda ,x+ ; get byte from source
bra 1$ ; loop for next byte

.page
.sbttl BREAK - Set Breakpoint at Specified Address

break: jsr mnumber ; get breakpoint location
bmi 3$ ; if not numeric, look for '?'
beq 2$ ; if no modifier, remove old breakpoint
ldx brkadr ; get current break address
lda ,x ; and the char there
cmpa #0x3f ; compare to 'swi'
bne 1$ ; equal?

lda brkins ; yes, restore the old instruction
sta ,x ; restore it

1$: ldx nbrhi ; get new breakpoint
stx brkadr ; save it
lda ,x ; get instruction stored there
sta brkins ; save it
lda #0x3f ; get code for software interrupt
sta ,x ; put it at breakpoint
bra 5$ ; all done

2$: ldx brkadr ; get address of break
lda ,x ; get inst. there
cmpa #0x3f ; swi?
bne 5$ ; if not, return & prompt
lda brkins ; was a swi - get previous inst.
sta ,x ; & restore it
bra 5$

3$: lda #4
jsr comand ; scan for it
lble badsyn ; bad syntax if not '?'
ldx brkadr ; it is, get break address
lda ,x ; get instruction there
cmpa #0x3f ; is it a 'swi'?
beq 4$ ; if yes, say so
ldx #msgnbr ; get that message
jsr outstr ; say it
bra 5$

4$: ldx #msgbat ; get that message
jsr outstr ; say it
ldx #brkadr ; get break address
jsr out2by ; type it
5$: jmp nomore

.page
.sbttl IBASE - Set Input Base

ibase: lda #3 ; look for hex,dec,or oct in list #3
jsr comand
bmi 2$ ; unrecognizable base, try'?'
bgt 1$
lda #1 ; no base given - default to hex
1$: sta ibcode ; save base code
jmp nomore

2$: lda ibcode ; get ib code in case its needed
pshs a ; save it on stack temporarily
bra ibdbq

.sbttl DBASE - Set Display Base

dbase: lda #3 ; look for hex,dec,oct, or bin in list #3
jsr comand
bmi 3$ ; unrecognizable base, try '?'
bgt 1$
lda #1 ; no base given - default to hex
1$: sta dbcode
ldx #2$-1 ; get numeric base from table
lda a,x
sta dbnbr ; save it
jmp nomore ; done

2$: .byte 16 ; display base table
.byte 10
.byte 8
.byte 2

3$: lda dbcode ; get db code in case its needed
pshs a ; save it on stack temporarily

ibdbq: lda #4 ; look for '?' in list #4
jsr comand
puls b ; retrieve input base/display base code
lble badsyn ; error if the 'something' was not a '?'
lda #3 ; base code is in list 3
stb comnum ; store base code
jsr typcmd ; type out base
jmp nomore

.page
.sbttl Display - Display Memory Data

displa: jsr gtrang ; get memory display range
lble badsyn ; address is required
ldx ranglo ; initialize address pointer
stx memadr

lda #6 ; search list 6 for
jsr comand ; display modifiers 'data' or 'used'
lbmi badsyn ; any other modifier is illegal
deca ; adj display modifier code so that:
sta comnum ; -1=addr & data, 0=data, 1=used
clrb ; init 'data values per line' counter
incb
1$: ldx #memadr
tst comnum ; which display option?
bmi 6$ ; if 'address & data', go there
decb ; count data values per line
bne 2$ ; if count not up, skip address output
jsr docrlf ; get to line beginning
jsr out2by ; output address
jsr outsp ; and a space
ldb dbnbr ; reset line counter

2$: ldx memadr ; point to data at that address
tst comnum ; want 'data' option?
bgt 3$ ; if not, go to 'used' code

jsr outsp ; output preceedng space
bra 7$

3$: lda ,x ; get the data
bne 4$
lda #'. ; its zero, get a '.'
bra 5$

4$: lda #'+ ; its non-zero, get a '+'
5$: jsr outchr ; output the '.' or '+'
bra 8$

6$: jsr outsp ; output a preceeding space
jsr out2by ; type address
jsr outeq ; type '='
ldx ,x ; get content
7$: jsr out1by ; type it
8$: cpx ranghi ; are we done
lbeq nomore ; if yes, back to prompt
inx ; no, inc memory address
stx memadr ; save it
bra 1$

.page
.sbttl SET - Set Memory Locations

set: jsr gtrang ; get memory location/range
bmi 5$ ; if not an address, look for a
; register name
lbeq badsyn ; an address modifier is required

; range of address specified?

ldx ranglo
cpx ranghi
beq 2$ ; if single address, set up
; addresses individually

; set a range of addresses to a single value

jsr mnumber ; get that value
lble badsyn ; its required
lda nbrlo ; put it in acca
1$: sta ,x ; store it in destination
cpx ranghi ; end of range hit?
lbeq nomore ; if yes, all done
inx ; no, on to next address in range
bra 1$ ; loop to see it

; set addresses up individually

2$: stx memadr ; save memory loc
3$: jsr mnumber ; get data to put there
beq 4$ ; end of line?
lblt badsyn ; abort if bad syntax
lda nbrlo ; load data byte
ldx memadr ; load address
sta ,x+ ; store data
bra 2$

4$: ldx synptr ; point to end of line
lda ,x ; get char there
cmpa #lf ; line feed?
lbne nomore ; if not,back to prompt
ldx #memadr ; yes, get next address to be set
jsr out2by ; type it
jsr outsp ; and a space
jsr getlin ; get a new line
ldx bufbeg ; get buffer beginning
stx synptr ; equate it to syntax scan pointer
bra 3$ ; go pick up data

; look for (register name, register value) pairs

5$: lda #5
jsr comand ; pick up a register name
lbmi badsyn ; error if unrecognizable
lbeq nomore ; done if end of line
pshs a ; save register name(number)
jsr mnumber ; get new register value
puls a ; restore register name(number)
lble badsyn ; got good register value?
deca
ldu #6$
lda a,u
leau a,u
ldx spsave ; yes, point to top of stack
ldd nbrhi ; get register value
jsr ,u ; go to function
bra 5$ ; and loop

6$: .byte 7$-6$
.byte 8$-6$
.byte 9$-6$
.byte 10$-6$
.byte 11$-6$
.byte 12$-6$
.byte 13$-6$
.byte 14$-6$
.byte 15$-6$
.byte 16$-6$

7$: stb ,x ; condition codes
rts

8$: stb 1,x ; acca
rts

9$: stb 2,x ; accb
rts

10$: stb 3,x ; dp
rts

11$: std 4,x ; ix
rts

12$: std 6,x ; iy
rts

13$: std 8,x ; iu
rts

14$: std 1,x ; d
rts

15$: std 10,x ; pc
rts

16$: std spsave ; sp
rts

.page
.sbttl Checksum Verify a Block of Memory

verify: jsr gtrang ; get a number range
beq 1$ ; no modifier means check what we have
lbmi badsyn ; anything else is illegal

ldx ranglo ; good range given,
stx verfrm ; transfer it to checksum addresses
ldx ranghi
stx verto

bsr cksum ; compute checksum
sta chksum ; save it
ldx #chksum ; type the checksum
jsr out1by
bra 3$

1$: bsr cksum ; compute checksum
cmpa chksum ; same as stored checksum?
bne 2$

ldx #msgver ; they verify - say so
jsr outstr
bra 3$

2$: ldx #msgnve ; they don't - say so
jsr outstr
3$: jmp nomore

; compute the checksum from addresses verfrm to verto
; return the checksum in acca

cksum: clra ; init checksum to zero
ldx verfrm ; get first address
dex ; init to one less
1$: inx ; start of checksum loop
adda ,x ; update checksum in acca with
; byte pointed to
cpx verto ; hit end of range?
bne 1$ ; if not, loop back
coma ; complement the sum
rts ; return with it


.page
.sbttl Search Memory for Byte String

; global variables used
; linptr - input line character pointer
; lisptr - command list character pointer
; ranglo - 'search from' address
; ranghi - 'search to' address
;
; local variables used
; memadr - starting memory address where a match
; occurred
; bytptr - address pointer used to fill bytstr and
; substr buffers
; nbytes - number of bytes in byte string
; nbrmat - number of chars that match so far in the
; matching process
; bytstr - starting address of 6 character byte sring
; buffer
;
; the search string occupies temp4, temp5, & temp6
; (6 bytes max)

search: jsr gtrang ; get search range
lble badsyn ; abort if no pair
ldx #bytstr ; get start of byte string
; to search for
stx bytptr ; set pointer to it
clr nbytes ; zero # of bytes in byte string

1$: jsr mnumber ; get a byte string
beq 2$ ; begin search if eol
lblt badsyn
; good byte, add it to string
inc nbytes ; count this byte
lda nbytes ; don't accept over 6 bytes
cmpa #6
lbgt badsyn
lda nbrlo ; get (low order) byte
ldx bytptr ; get byte pointer
sta ,x+ ; save byte, bump pointer
stx bytptr ; save it
bra 1$

2$: tst nbytes ; is # of bytes to look for >0
lbeq badsyn ; if not,bad syntax
ldx ranglo ; initialize memory pointer
dex
stx linptr

3$: ldx #bytstr-1 ; initialize byte pointer
stx lisptr
clr nbrmat ; set 'number of bytes that
; matched' to zero
jsr getlst ; get byte from byte string

4$: jsr mgetchr ; get byte from memory range
cba ; compare memory & byte string
; characters
beq 5$ ; if no match, test for range end
cpx ranghi ; have we reached the range
; search upper limit?
lbeq nomore ; yes, go prompt for next command
bra 4$

5$: stx memadr ; match achieved - save address of match
6$: inc nbrmat ; bump number matched
lda nbrmat
cmpa nbytes ; have all characters matched?
beq 8$ ; if so, match achieved

jsr getlst ; haven't matched all yet, go get next pair
jsr mgetchr ; even if past 'search to' address
cba
beq 6$

7$: ldx memadr ; mismatch on some byte past the first one

cpx ranghi ; this test handles special case
lbeq nomore ; of a match on range end
stx linptr
bra 3$ ; go reset the byte string pointer


8$: ldx #memadr ; match on byte string achieved,
jsr out2by ; type out memory address
jsr outsp ; and a space
bra 7$

.page
.sbttl Test Ram

test: jsr gtrang ; get an address range
lble badsyn ; abort if no pair
ldu ranglo ; ranglo holds starting address of range
; ranghi holds ending address of range
1$: lda ,u ; get byte stored at test location
pshs a ; save it
clr ,u ; zero the location
tst ,u ; test it
beq 2$ ; ok if = zero
ldx #msgccl ; can't clear location
bra 4$

2$: dec ,u ; set location to $ff
lda #0xff
cmpa ,u ; did it get set to $ff?
beq 3$
ldx #msgcso ; can't set location to one's
bra 4$

3$: puls a
sta ,u ; restore previous content
cmpu ranghi ; hit end of test range?
lbeq nomore ; yes, all done
leau 1,u ; no, move to test next location
bra 1$

4$: stx temp3 ; save error message temporarily
ldx #temp4
stu ,x
jsr out2by ; type out bad address
jsr outeq ; and equal sign
ldx temp4
jsr out1by ; its content
jsr outsp ; a space
ldx temp3
jsr outstr ; and the type of error
jsr docrlf
bra 3$

.page
.sbttl vector settup commands

; rsrvd - set up rsvd pointer

xrsrvd: jsr numinx ; get pointer in ix
stx .rsrvd ; save it
jmp nomore

; swi3 - set up swi3 pointer

xswi3: jsr numinx ; get pointer in ix
stx .swi3 ; save it
jmp nomore

; swi2 - set up swi2 pointer

xswi2: jsr numinx ; get pointer in ix
stx .swi2 ; save it
jmp nomore

; firq - set up interrupt pointer

xfirq: jsr numinx ; get pointer in ix
stx .firq ; save it
jmp nomore

; irq - set up interrupt pointer

xirq: jsr numinx ; get pointer in ix
stx .irq ; save it
jmp nomore

; swi - set up swi pointer

xswi: jsr numinx ; get pointer in ix
stx .swi ; save it
jmp nomore

; nmi - set up non-maskable interrupt pointer

xnmi: jsr numinx ; get ponter in ix
stx .nmi ; save it
jmp nomore

.page
.sbttl compare numbers

; compare - output sum & difference of two input numbers

compar: jsr numinx ; get first number
stx ranglo ; put it in ranglo
jsr numinx ; get second number
stx nbrhi ; save it in nbrhi

; compute and output the sum

jsr sumnum ; compute sum
ldx #msgsis ;get its title
bsr 1$ ; output title & sum

jsr difnum ; compute difference

ldx #msgdis ; get its title
bsr 1$ ; output title & diff

jmp nomore

; compute and output the result

1$: jsr outstr ; output it
ldx #ranghi ; get result
jsr out2by ; display result
rts

.page
.sbttl dump memory in S1-S9 format

; *****
; dump - dump portion of memory in S1-S9 format
;
; get address range: start in ranglo (2 bytes), end in
; ranghi (2bytes)
; if no address range is given, use whatever is n
; ranlo & ranghi

dump: jsr gtrang
clr temp5 ; initialize to dump to terminal

1$: lda #2 ; look for a 'TO' modifier
jsr comand
beq 2$
lble badsyn ; error if bad syntax
cmpa #1 ; TO ?
bne 1$ ; go look for another modifier

jsr numinx ; get 'TO' address
stx outadr ; save it
inc temp5 ; remember this
bra 1$ ; go look for another modifier

2$: tst temp5
beq 3$
inc outflg ; set flag for proper output device

3$: ldd ranghi ; compute # of bytes to output
subd ranglo ; subtract lo bytes
cmpd #16 ; diff 0-15.
bcs 5$
4$: ldb #15

; to get frame count, add 1
; (diff of 0 implies 1 output) + # of data bytes
; + 2 addr bytes + 1 checksum byte

5$: addb #4
stb temp3 ; temp3 is the frame count
subb #3
stb temp4 ; temp4 is the record byte count

ldx #msgs1 ; output a 'S1' header data record
jsr outstr
clrb ; zero checksum

ldx #temp3 ; punch frame count
bsr 7$

ldx #ranglo ; punch address
bsr 7$
bsr 7$

ldx ranglo ; load memory pointer
6$: bsr 7$ ; output data byte
dec temp4 ; dec byte count
bne 6$
stx ranglo ; save memory pointer

comb ; complement checksum
pshs b ; put it on stack
tfr s,x ; let ix point to it
bsr 7$ ; output checksum
puls b ; pull it off stack
ldx ranglo ; restore memory pointer
dex
cpx ranghi ; hit end of range?
bne 3$

ldx #msgs9 ; yes, output an 'S9' record
jsr outstr
clr outflg ; set to terminal output
jmp nomore

7$: jsr out1by ; output a byte pointed to by ix as
addb ,x+ ; 2 hex characters, update checksum
rts


.page
.sbttl Load S1-S9 format Data

load: jsr inpchr ; get a char
cmpa #'S ; is it an S ?
bne load

jsr inpchr ; got an 'S', examine next character
cmpa #'9 ; done if its a '9'
beq 3$

cmpa #'1 ; is it a '1'?
bne load ; if not, look for next 'S'

clr cksm ; clear checksum

jsr 5$ ; read record byte count
suba #2
sta bytect ; save count minus 2 address bytes

bsr 4$ ; build address

1$: bsr 5$ ; read a data byte into acca
dec bytect ; count it
beq 2$ ; if done with record, check checksum
sta ,x+ ; not done, store byte in memory
bra 1$ ; on to next memory address

2$: inc cksm ; test checksum by adding 1
beq load ; if ok, result should be zero

ldx #msgnve ; record checksum error
jsr outstr
ldx #temp1 ; get record address of it
jsr out2by ; type it too
3$: clr inpflg ; reset flag to normal terminal input
jmp nomore

4$: bsr 5$ ; build address
sta temp1
bsr 5$
sta temp1+1
ldx temp1
rts

5$: bsr 6$ ; get left hex digit
asla ; move to hi 4 bits
asla
asla

asla
tab ; save it in acca
bsr 6$ ; get right hex digit
aba ; combine then in acca
tab ; update the checksum
addb cksm
stb cksm
rts

6$: jsr inpchr ; input a hex char & convert to internal form
suba #'0
bmi 8$ ; not hex if below ascii '1'
cmpa #'9-'0
ble 7$ ; ok if ascii '9' or less
cmpa #'A-'0 ; below ascii 'A'?
bmi 8$ ; error if it is
cmpa #'F-'0 ; over ascii 'F'?
bgt 8$ ; error if it is
suba #7 ; conv ascii A-F to hex A-F
7$: rts

8$: ldx #msgcnh ; error - char not hex, say so
jsr outstr
rts

.page
.sbttl Delay Function

; *****
; delay - delay specified # of milliseconds

delay: jsr numinx ; get delay time
bsr timdel
jmp nomore

; *****
; time delay subroutine
; ix is input as the # of milliseconds to delay
; adj timcon so (7*timcon*cycle time=1 ms)

timdel: pshs d
1$: ldd timcon

2$: subd #1 ; a 7 cycle loop
bne 2$

dex ; decrement millisecond counter
bne 1$
puls d,pc

.page
.sbttl Help List

help: jsr docrlf ; next line
ldx #comlst ; command list

1$: ldb #4 ; commands per line
stb temp1

2$: ldb #12 ; positions per command
; must be larger than longest command
3$: lda ,x+ ; get character
cmpa #cr ; is end of command
beq 4$
jsr outchr ; print command character
decb
bne 3$

4$: lda ,x ; get character
cmpa #lf ; is end of list
beq 6$ ; finished
dec temp1 ; per line done ?
bne 5$ ; no - skip

jsr docrlf ; next line
bra 1$

5$: lda #' ; space
jsr outchr
decb
bne 5$
bra 2$

6$: jsr docrlf ; next line
jmp nomore

.page
.sbttl Command Lists

;================================================
;
; c o m m a n d l i s t s c a n n i n g
; r o u t i n e
;
; this routine seeks a match of the characters pointed
; at by the input line scanning pointer to one of the
; commands in a list specified by acca.
; the result of the scan for a match is returned in
; acca as follows:
;
; acca=-1: the match was unsuccessful. the syntax
; pointer (synptr) was not updated
; (advanced).
;
; acca= 0: the match was unsuccessful since there
; were
; no more characters, i.e., the end of
; the
; line was reached.
;
; acca=+n: successful match. the syntax pointer
; was updated
; to the first character following the
; command
; delimiter. acca holds the number of
; the
; command matched.
; global variables for external communication
; synptr - good syntax input line char pointer
; linptr - input line character pointer
; delim - class of permissible command delimiters
;
; temporary 2 byte internal variables
; lisptr - command list character pointer
;
; temporary 1 byte internal variables
; nummat - number of characters that successfully match
; lisnum - # of list within which a match will be sought
; comnum - command number matched
;
; constants used
; cr - carriage return
; lf - line feed
;
; a, b & ix are not preserved

comand: sta lisnum ; save list # to match within
jsr skpdlm ; test if we are at the end of the line
bcc 1$
clra
rts

; initialize the command list pointer to one less than
; the beginning of the command lists

1$: ldx comadr ; entry point

; move to the beginning of the desired command list

lda lisnum ; search for 'string' # lisnum
ldb #lf ; use lf as a 'string' terminator
bsr fndstr
stx lisptr

; the list pointer, lisptr, now points to one less than
; the first character
; of the first command in the desired list

clr comnum

; reset input line pointer to: 1) beginning of line, or
; to 2) point where last successful scan terminated

2$: inc comnum ; initialize the command # to 1
ldx synptr
stx linptr
clr nummat ; clear number of characters
; matched
3$: jsr mgetchr ; get input line char in accb
jsr tstdlm ; test for a delimiter
bne 4$ ; success (found delimiter)
jsr getlst ; get command list char in acca
cmpa #lf ; has end of command list been reached ?
beq 5$ ; if so, potential match failure
cmpa #cr ; has end of command been reached ?
beq 5$ ; if so, potential match failure
cba ; compare the two characters
bne 6$ ; match not possible on this command
inc nummat ; they match, compare the succeeding characters
bra 3$ ; inc number of characters matched

4$: ldx linptr ; successful match
stx synptr ; update good syntax pointer
lda comnum ; return command number
rts

; no match

5$: tst nummat ; did at least one match?
beq 6$ ; to next command if none matched
jsr tstdlm ; at least one matched - test for delimiter
bne 4$ ; if a delimiter, match has been achieved
lda ,x ; retrieve last character

; illegal delimiter
; move to next command within list

6$: cmpa #lf ; end of this list?
beq 7$ ; if so, nothing on list matched
cmpa #cr ; is it a cr?
beq 2$ ; yes, next command
jsr getlst ; get next command list character
bra 6$ ; no, get to end of command

7$: clra ; match failure
deca ; no match possible within this list
rts

.page
.sbttl Typeout Command

;====================================
; this routine types out command number "comnum"
; the list is specified in acca
; accb & ix are preserved

typcmd: pshs b,x
ldx #comlst-1 ; move to head of command lists
ldb #lf ; and list terminator
bsr fndstr ; go to head of desired list
lda comnum ; get command number
ldb #cr ; get command terminator
bsr fndstr ; go to head of desired command

1$: inx ; move to next character
lda ,x ; get a command character
cmpa #cr ; is it a command terminator?
beq 2$ ; if so, return
jsr outchr ; no, type it
bra 1$

2$: puls b,x,pc

.page
.sbttl Find string

;======================================
; move to beginning of desired string number (in acca)
; each string is terminated by an end of string
; character (in accb)
; the index register is assumed initialized pointing to
; one less than the first character of the first string
; acca, accb & ix are not preserved
; local variables
; strnum - string # to find
; eoschr - "end of string" character

fndstr: sta strnum ; save string number
stb eoschr ; save terminator
clrb
1$: incb ; string 1 is the first string
cmpb strnum ; is this the right string?
beq 3$ ; if so, done

; no, swallow up characters until an end of string char is hit

2$: inx ; bump pointer to next one
lda ,x ; get char pointed at
cmpa eoschr ; end of string hit?
beq 1$ ; if it is, bump the string counter
bra 2$ ; no, move on to next char
3$: rts ; ix set properly, return

.page
.sbttl Skip Leading Delimiters

;=================================================
; skip leading delimiters
; this routine should be called prior to scanning for
; any information
; on the input line
; the current character is ignored if the scannng
; pointer is at the beginning of a line. if not, the
; scanning pointer skips over spaces and commas
; until an end of line or non-delimiter is found.
; the carry bit is set if and end of line is encountered.

; acca, accb, & ix are not preserved

skpdlm: clc
tst bolflg ; at beginning of line?
bgt 2$

; look at current input character

1$: ldx synptr ; get pointer to it
lda ,x ; get char
bsr tsteol ; test for end of line
bne 2$
sec ; yes, end hit, set carry
rts

; "peek" at next char in line

2$: ldb 1,x ; get it
bsr tstdlm ; see if its a delimiter
bne 3$
rts ; if not, return

; next char is a delimiter

3$: jsr mgetchr ; move to next char in input line
stx synptr ; update syntax pointer
bra 1$ ; go test for end of line


.page
.sbttl Test for End-of-Line Character

;============================================
; test for end-of-line character
; z bit of cc reg set if char in acca is a terminator
; acca, accb, & ix are preserved

tsteol: cmpa #cr ; carriage return?
beq 1$
cmpa #lf ; line feed? (continued lines)
beq 1$
cmpa #'; ; for several commands on one line
1$: rts

.sbttl Test for Delimeter

;===============================================
; check the character n accb aganst the delimiter(s)
; specified by variable delim
; accb & ix are preserved
; acca is set to 0 if accb is not a delimiter, to 1
; if it is
; if delim=1, space s delimiter
; if delim=2, comma is delimiter
; if delim=3, space or comma is delimiter
; if delim=4, any non-alphanumeric is a delimiter
; test for end-of-line (logical or physical)

tstdlm: pshs b
tba
bsr tsteol
puls b
beq 5$

lda delim
cmpa #1
bne 1$
cmpb #' ; want a space - is it?
bne 6$
bra 5$

1$: cmpa #2
bne 3$
2$: cmpb #', ; want a comma - is it?
bne 6$
bra 5$
3$: cmpa #3
bne 4$
cmpb #' ; want either, is it a space?
beq 5$
bra 2$ ; or a comma?

4$: cmpa #4
bne 7$ ; error if delm not 1-4
cmpb #'0 ; test if char is 0-9 inclusive
blt 5$
cmpb #'9
ble 6$

cmpb #'A ; test if char is A to Z inclusive
blt 5$
cmpb #'Z
ble 6$ ; over Z - its a delimiter

5$: lda #1 ; char in accb is a delimiter
rts

6$: clra ; char in accb is not a delimiter
rts
; error in specifying delimiter class
7$: swi ; have monitor type out pertinent
; statistics

.page
.sbttl Sum Two Numbers

;================================================
; add the 2 byte number stored in (ranglo,ranglo+1) to
; the number stored in (nbrhi,nbrlo) and put the result
; in (ranghi,ranghi+1)

sumnum: pshs d ; add lo order bytes
ldd ranglo
addd nbrhi
std ranghi
puls d,pc

.sbttl Subtract Two Numbers

;====================================================
; subtract the 2 byte number stored in (nbrhi,nbrlo)
; from the two byte number stored in (ranglo,ranglo+1)
; and put the result in (ranghi,ranghi+1)
; accb & ix are preserved
; acca is altered

difnum: pshs d ; subtract lo order bytes
ldd ranglo
subd nbrhi
std ranghi
puls d,pc

.page
.sbttl Get Range

;===================================================
; this routine scans the input line for a pair of numbers
; representing an address range. a colon separating the
; pair implies "thru", while an "!" implies "thru the
; following"
; e.g., 100:105 is equivalent to 100!5
; a single number implies a range of 1
; on return (ranglo,ranglo+1) holds the range start, and
; (ranghi,ranghi+1) holds the range end
; acca, accb, & ix are not preserved

gtrang: bsr mnumber ; pick up first number
bgt 1$
blt 2$
rts ; nothing more on input line


1$: ldx nbrhi ; good single number
stx ranglo ; transfer it to ranglo
bra 3$ ; and to ranghi

; bad number, but is it bad due to a ":" or "!" delimiter?
; get the terminator for the first number

2$: ldx linptr
lda ,x
cmpa #': ; was it a colon?
bne 4$ ; if not, go test for "!"
bsr 8$ ; was ":", process first number &
; get next one
ble 5$ ; illegal if end of line or non-numeric

3$: ldx nbrhi ; transfer second number to ranghi
stx ranghi
bra 7$

4$: cmpa #'! ; was delimiter a "!"?
beq 6$ ; if yes, get 2nd number
clra ; illegal delimiter, return
deca
5$: rts

6$: bsr 8$ ; was "!", process first number &
; get next one
ble 5$
bsr sumnum ; compute range end, put into ranghi

7$: lda #1 ; successful exit
rts

; update syntax pointer, move first number to ranglo,
; & get 2nd number

8$: stx synptr ; update syntax pointer
ldx nbrhi ; get first number of the pair
stx ranglo ; save it in "low range" value
bsr mnumber ; pick up the second number of the pair
rts

.page
.sbttl Get number in IX

;====================================================
; get a 2 byte number & return it in the index register

numinx: bsr mnumber
bgt 1$
jmp badsyn
1$: ldx nbrhi
rts

.page
.sbttl Scan For a Number

;==================================================
; scan for a number
; return the most significant byte in nbrhi
; and the least significant byte in nbrlo
; the result of the scan for a number is returned in
; acca as follows:
;
; acca=-1: the match was unsuccessful. the syntax
; pointer (synptr) was not updated.
;
; acca= 0: the scan was unsuccessful since there
; were no more characters. (i.e., the end
; of the line was encountered.)
;
; acca=+1: the scan was successful. the syntax
; pointer was updated to the first character
; following the command.
;
; ix is preserved
; global variables for external communication
; nbrhi - number hi byte
; nbrlo - number lo byte
; ibcode - input base code
; dbcode - display base code
;
; local variables
; nbr2x - used in decimal conversion
; initialize both bytes to zero

mnumber:pshs x ; save ix
clr nbrhi
clr nbrlo
ldx synptr ; initialize the line scanning pointer
stx linptr
jsr skpdlm ; are we at end of line?
bcc 1$
clra ; yes, zero acca
puls x,pc

1$: jsr mgetchr ; get a character from the input
; line into accb
jsr tstdlm ; test for a delimiter
bne 6$ ; good delimiter if acca is non-zero
subb #'0 ; subtract ascii 0
bmi 8$ ; error if less

lda ibcode ; determine input base & go to right routine
cmpa #1 ; hex code ?
beq 2$

cmpa #2 ; decimal code ?
beq 4$

cmpa #3 ; octal code ?
beq 5$

; hex input processing

2$: cmpb #'9-'0 ; default an illegal input base to hex
ble 3$ ; if 9 or less
cmpb #'A-'0
bmi 8$ ; not hex if < A
cmpb #'F-'0
bgt 8$ ; not hex if > F
subb #7 ; move A-F above 0-9

3$: bsr 9$ ; shift lo & hi bytes left 4 bits
bsr 9$
orb nbrlo
stb nbrlo
bra 1$

; decimal input

4$: cmpb #9
bgt 8$ ; not decimal if > 9

; multiply saved value by 10 & add in new digit

bsr 10$ ; multiply current number by 2 to get 2x value
ldx nbrhi ; save this *2 number temporarily
stx nbr2x
bsr 9$ ; multiply this # by 4 to get 8x value
clra ; new digit
addd nbr2x ; note that 10x=2x+8x
bcs 8$ ; carry out of ms byte is an error
addd nbrhi
bcs 8$ ; carry out of ms byte is an error
std nbrhi ; save result
bra 1$

; octal input

5$: cmpb #7
bgt 8$ ; not octal if > 7
bsr 9$ ; shift hi & lo bytes 3 places left
bsr 10$ ; carry out of hibyte is illegal
orb nbrlo ; add in new digit
stb nbrlo
bra 1$

6$: ldx linptr ; good number - scan was successful
stx synptr ; update good syntax line pointer
lda #1 ; set "good scan" flag
puls x,pc

7$: leas 2,s
8$: clra ; conversion error - scan was unsuccessful
deca
puls x,pc

9$: asl nbrlo ; shift a two byte number left one position
rol nbrhi
bcs 7$
10$: asl nbrlo ; shift a two byte number left one position
rol nbrhi
bcs 7$
rts

.page
.sbttl General Output Routines

;===========================================
; output a space

outsp: lda #'
jsr outchr
rts

;===========================================
; output an "=" sign

outeq: lda #'=
jsr outchr
rts

;==========================================
; output a 1 byte number

out1by: pshs d
ldb #1
bsr outnum
puls d,pc

;==========================================
; output a 2 byte number

out2by: pshs d
ldb #2
bsr outnum
puls d,pc

;==========================================
; display the number pointed at by the address in the
; index register and output it according to the base
; specified in "dbcode"
; leading zeros are included
; acca & ix are preserved
; accb is input as the number of bytes comprising the
; number.
; global variables for external communication
; ibcode - input base code
; dbcode - display base code
;
; local variables
; decdig - decimal digit being built
; numbhi - hi byte of number being output
; numblo - lo byte of number being output

outnum: pshs d,x ; save these
ldx ,x ; get the two bytes at that address
stx numbhi ; put them in a scratch area for processing
lda dbcode ; get display base

cmpa #1
beq 1$
cmpa #2
beq 4$
cmpa #3
beq 11$
cmpa #4
beq 14$

; output a hex number

1$: aslb ; 1 byte=2 chars, 2 bytes=4 chars
2$: bsr 16$ ; get next 4 bits
bsr 16$

anda #0x0f ; extract 4 bits
cmpa #9
ble 3$
adda #7 ; convert 10:15 to A-F

3$: bsr 18$
decb
bne 2$
puls d,x,pc ; restore registers & return

; output a decimal number

4$: decb ; test # of bytes to output
beq 5$
ldx #9$ ; initialize for output of a 2 byte number
ldd numbhi
bra 6$

5$: ldx #10$ ; initialize for output of a 1 byte number
clra
ldb numbhi
6$: clr decdig ; clear the digit to output
7$: subd ,x ; subtract the power of 10 conversion constant
bcs 8$ ; test for borrow (carry)
inc decdig ; no borrow yet - nc digit being built
bra 7$ ; repeat loop

; building of digit to output is complete - print it

8$: pshs a ; save lo byte of number being output
lda decdig ; get digit
bsr 18$ ; print it
puls a ; restore lo byte

addd ,x++ ; borrow generated - cancel last subtraction
cpx #9$+10 ; are we thru with units conversion?
bne 6$ ; if not, back to get next digit
puls d,x,pc ; if yes, restore registers & return

; decimal output conversion constants

9$: .word 10000
.word 1000
10$: .word 100
.word 10
.word 1

; output an octal number

11$: aslb ; first approximation of # of
clra ; digits to output
cmpb #2
bgt 12$
bsr 16$ ; 1 byte - get first 2 bits
bsr 18$
bra 13$ ; go output last 2 digits

12$: bsr 17$ ; two byte # - output hi order bit/digit
bsr 18$
incb ; 5 more digits to go

13$: bsr 16$ ; get next 3 bits
bsr 17$
anda #7 ; extract 3 bits
bsr 18$
decb ; count this digit
bne 13$ ; are we done?
puls d,x,pc ; if yes, restore registers & return

14$: aslb ; output a binary number
aslb
aslb
15$: bsr 17$ ; get next bit
anda #1 ; extract the bit
bsr 18$ ; output it
decb ; count it
bne 15$ ; are we done?
puls d,x,pc ; if yes, restore registers & return

16$: bsr 17$ ; left shift 2 bits

17$: asl numblo ; left shift the 3 byte number 1 bit
rol numbhi
rola
rts

18$: adda #'0 ; convert to a numeric ascii digit & output it
jsr outchr
rts

.page
.sbttl Get Character Routines

;=================================================
; this routine gets the next character from the input
; line buffer
; acca is preserved
; accb is loaded with the character
; ix is incremented and left pointing to the character
; returned

mgetchr:
ldx linptr
inx
ldb ,x
stx linptr
clr bolflg ; set flag to not at "beginning of line"
rts

;==================================================
; this routine gets the next character in the command
; lists
; acca is the character retrieved
; accb is preserved
; ix is incremented & left pointing to the character returned

getlst: ldx lisptr ; get current list pointer
inx ; move pointer to next character
lda ,x ; get character pointed at
stx lisptr ; save pointer
rts ; and return

.page
.sbttl Command Lists

;=====================================================
; command lists
; a carriage return signifies end-of-command
; a line feed signifies end-of-command-list
; list 1 - major commands

comlst: .ascii /BREAK/ ; set breakpoint (swi code)
.byte cr
.ascii /CONTINUE/ ; continue from "swi"
.byte cr
.ascii /COMPARE/ ; print sum & difference of 2 numbers
.byte cr
.ascii /COPY/ ; copy from one location to another
.byte cr
.ascii /DISPLAY/ ; display memory data
.byte cr
.ascii /DBASE/ ; set display base
.byte cr
.ascii /DELAY/ ; delay specified # of bytes
.byte cr
.ascii /DUMP/ ; dump memory in mikbug or image format
.byte cr
.ascii /GOTO/ ; go to memory address
.byte cr
.ascii /HELP/ ; help listing
.byte cr
.ascii /IBASE/ ; set input base
.byte cr
.ascii /LOAD/ ; load mikbug tape
.byte cr
.ascii /REG/ ; display registers
.byte cr
.ascii /SET/ ; set memory data
.byte cr
.ascii /SEARCH/ ; search memory for a byte string
.byte cr
.ascii /TEST/ ; test a range of memory
.byte cr
.ascii /VERIFY/ ; verify that memory content is unchanged
.byte cr
.ascii /CLI/ ; clear interrupt mask
.byte cr
.ascii /CLF/ ; clear fast interrupt mask
.byte cr
.ascii /SEI/ ; set interrupt mask
.byte cr
.ascii /SEF/ ; set fast interrupt mask
.byte cr
.ascii /IRQ/ ; set interrupt pointer
.byte cr
.ascii /FIRQ/ ; set fast interrupt pointer
.byte cr
.ascii /NMI/ ; set non-maskable interrupt pointer
.byte cr
.ascii /RSRVD/ ; set reserved interrupt pointer
.byte cr
.ascii /SWI/ ; set software interrupt pointer
.byte cr
.ascii /SWI2/ ; set swi2 interrupt pointer
.byte cr
.ascii /SWI3/ ; set swi3 interrupt pointer
.byte cr
.byte lf ; end of list 1

; list 2 - modifier to dump

.ascii /TO/ ; destination
.byte cr
.byte lf ; end of list 2

; list 3 - number base specifiers

.ascii /HEX/ ; base 16
.byte cr
.ascii /DEC/ ; base 10
.byte cr
.ascii /OCT/ ; base 8
.byte cr
.ascii /BIN/ ; base 2
.byte cr
.byte lf ; end of list 3

; list 4 - information request

.ascii /?/
.byte cr
.byte lf ; end of list 4

; list 5 - register names

.ascii /.CC/
.byte cr
.ascii /.A/
.byte cr
.ascii /.B/
.byte cr
.ascii /.DP/
.byte cr
.ascii /.IX/
.byte cr
.ascii /.IY/
.byte cr

.ascii /.IU/
.byte cr
.ascii /.AB/
.byte cr
.ascii /.PC/
.byte cr
.ascii /.SP/
.byte cr
.byte lf ; end of list 5

; list 6 - modifiers to "display"

.ascii /DATA/
.byte cr
.ascii /USED/
.byte cr
.byte lf ; end of list 6

; list 7 - modifier to "load"

.ascii /FROM/ ; source
.byte cr
.byte lf ; end of list 7


.page
.sbttl Get a line

;=======================================================
;
; this routine constructs a line of input by getting all
; input characters up to and including a carriage return
; (which then designates "end of line").
; typing rubout will delete the previous character
; typing control-c will abort the line
; typing control-z will use the previous line
; the input line is stored beginning at the address
; stored in bufbeg and ending at the address stored
; in bufend
; acca, accb, & ix are not preserved
;
; global variables
; bufbeg - input line start of buffer
; bufend - input line end of buffer
;
; local constants

getlin: ldx bufbeg ; set pointer to one less than
; the beginning of the line buffer
clrb ; accb holds last input char
1$: cpx bufend ; check current line end against buffer end
bne 2$

; line too long - abort it as if a control-c had been typed

ldx #msgltl ; get message
jsr outstr ; output it
ldb #3 ; put ctl-c in accb
rts

2$: jsr inpchr ; get a character (returned in acca)
anda #0x7f ; drop parity bit

; control-z copies from present position to previous end of line

cmpa #26 ; is char a control-z?
bne 3$
jsr docrlf ; yes, type cr-lf
rts

3$: cmpa #13 ; is char a cr?
beq 4$
cmpa #10 ; or a lf?
bne 6$
4$: inx
sta ,x ; yes, store the terminator
tst hdxflg ; test for half-duplex terminal
bne 5$
jsr docrlf ; type cr-lf
5$: rts ; now return

6$: cmpa #3 ; is char a control-c?
bne 7$ ; no
tab ; return ctl-c in accb
lda #'^ ; echo an up-arrow
jsr outchr
rts

7$: cmpa #127 ; no, is it delete?
beq 10$ ; yes - delete character
inx ; not a delete, so advance to next char
sta ,x ; store it in inplin
tab ; last character in b
tst hdxflg ; check half duplex
bne 9$ ; yes - skip
jsr outchr ; echo character
9$: bra 1$ ; get another

; current character is a delete
; test line length - if its zero, ignore this delete
; since we can't delete prior to first char in input line

10$: cpx bufbeg
beq 1$
pshs x
ldx #11$ ; delete character on screen
bsr outstr
puls x
ldb ,-x ; last character
bra 1$

11$: .byte 8,32,8,4 ; BS, SPACE, BS, EOT


;====================================================
; initialization routine

inital: lda #1
sta ibcode ; set input base to hex
sta dbcode ; set display base to hex

; set up display base number

lda #16
sta dbnbr

; max # of characters per line

lda #72
sta cplmax
clr inpflg ; default input from terminal
clr outflg ; default output to terminal
clr hdxflg ; clear half-duplex flag

; set up swi interrupt address pointer

ldx #typswi ; type "swi" & do "reg" command
stx .swi

; clear breakpoint address

ldd #0xfffe ; normal systems have rom here
std brkadr

; initialize to mondeb's command lists

ldx #comlst-1
stx comadr

; time constant for a .5 microsecond clock

ldd #285
std timcon

.if inituser
jmp userinit ; user returns via rts
.else
rts
.endif

;===================================================
; output a character string which begins at the address
; in the index register
; acca & accb are preserved
; ix is left pointing to the string terminator

outstr: pshs a
1$: lda ,x ; get char pointed to
cmpa #4 ; is it a string terminator?
beq 2$ ; done if it is
bsr outchr ; isn't, output it
inx ; on to next char
bra 1$
2$: puls a,pc

;=====================================================
; input a character

inpchr: tst inpflg ; console ?
bne 2$

1$: jsr [conin] ; tst for a character
bcc 1$ ; none - loop until there is
rts

2$: jsr [altin] ; tst for a character
bcc 2$ ; none - loop until there is
rts

;======================================================
; output the character in acca to the desired output
; device/location
; if outflg = 0, output is to terminal
; if outflg # 0, output is to address in outadr
; & this address is then incremented

outchr: pshs d,x ; save d and x
ldb outflg ; test output destination flag
decb
ble 1$ ; skip this code if terminal output

; output to something other than terminal

ldx outadr ; get output char destination addr
sta ,x+ ; save char in memory
stx outadr ; update output address
puls d,x,pc

1$: cmpa #lf ; ignore line feeds
bne 2$
puls d,x,pc

2$: cmpa #cr ; test for carriage return
bne 3$
bsr docrlf
puls d,x,pc

3$: ldb cplcnt ; get "chars per line" count
cmpb cplmax
bge 4$ ; send cr-lf if greater

; less than max, but also send cr-lf if 10 from end and
; printing a space

addb #10
cmpb cplmax
blt 5$
cmpa #' ; near end, test if about to print a space
bne 5$

; terminal line full or nearly full - interject a cr-lf

4$: bsr docrlf
5$: inc cplcnt ; bump counter
bsr chrout ; send it to acia1
puls d,x,pc

;======================================================
; send a carriage return-line feed to the terminal

docrlf: pshs d
lda #cr
bsr chrout
lda #lf
bsr chrout
clr cplcnt ; zero "chars/line" count
puls d,pc

;======================================================
; send char in acca

chrout: tst outflg ; check destination
bne 1$
jmp [conout] ; output a character
1$: jmp [altout]

;======================================================
; misc text

msghed: .ascii /MONDEB-09 1.00/
.byte cr,4
msgprm: .byte '*,4
msgswi: .byte cr,lf
.ascii /swi:/
.byte cr,lf,4
msgltl: .ascii /too long/
.byte 4
msgnbr: .ascii /not set/
.byte 4
msgbat: .ascii /set @ /
.byte 4
msgver: .ascii /ok/
.byte 4
msgnve: .ascii /checksum error /
.byte 4
msgccl: .ascii /can't clear/
.byte 4
msgcso: .ascii /can't set to ones/
.byte 4
msgsis: .ascii /sum is /
.byte 4
msgdis: .ascii /, dif is /
.byte 4
msgs1: .byte cr,lf,0,0,'S,'1,4
msgs9: .byte cr,lf,0
.ascii /S9030000FC/
.byte cr,lf,4
msgcnh: .ascii /char not hex/
.byte cr,4


;****************************************************
;* default interrupt transfers *
;****************************************************

.if standalone
rsrvd: jmp [.rsrvd] ; reserved vector
swi3: jmp [.swi3] ; swi3 vector
swi2: jmp [.swi2] ; swi2 vector
firq: jmp [.firq] ; firq vector
irq: jmp [.irq] ; irq vector
swi: jmp [.swi] ; swi vector
nmi: jmp [.nmi] ; nmi vector
.endif

.page
.sbttl dispatch table

.if standalone

.area DISPAT (REL,CON)

.word timdel ; time delay for # of ms specified by ix
.word cksum ; return checksum of an address range in acca
.word mgetchr ; return (in accb) char pointed to by linptr
.word getlst ; return (in acca) char pointed to by lisptr
.word gtrang ; pick up an address range in ranglo & ranghi
.word mnumber ; pick up a number & return it in nbrhi & nbrlo
.word skpdlm ; skip over input line delimiters
.word tstdlm ; test char in accb for a delimiter
.word tsteol ; test char in acca for end-of-line
.word comand ; search specified command list for a command
.word typcmd ; types out command number "comnum" in list acca
.word out1by ; display the 1 byte number pointed at by ix
.word out2by ; display the 2 byte number pointed at by ix
.word getlin ; get a line of input into the tty buffer
.word outstr ; output char string ix points to
.word docrlf ; send cr-lf with delay & zero line count
.word outchr ; like chrout, but with folding, cr delay, & lf
.word chrout ; send acca to console
.word inpchr ; get a char, return it in acca
.word prompt ; to prompt for new command
.word mond09 ; start of mondeb
.endif

.page
.sbttl Hardware Interrupt Tables

;********************************************************
;* MONDEB-09 hardware vector table
;*
;* this table is used if the MONDEB-09 rom addresses
;* the mc6809 hardware vectors.
;********************************************************

.if standalone

.area INTVEC (ABS,OVR)

. = 0xFFF0 ; vector position

.word rsrvd ; reserved slot
.word swi3 ; software interrupt 3
.word swi2 ; software interrupt 2
.word firq ; fast interrupt request
.word irq ; interrupt request
.word swi ; software interrupt
.word nmi ; non-maskable interrupt
.word reset ; restart
.endif