2021-12-02 21:06:35 +00:00
|
|
|
|
NEW
|
|
|
|
|
AUTO 3,1
|
|
|
|
|
.LIST OFF
|
|
|
|
|
.OP 65C02
|
|
|
|
|
.OR $2000
|
|
|
|
|
.TF bin/seq
|
|
|
|
|
*/-------------------------------------
|
|
|
|
|
* # SEQ
|
|
|
|
|
* Prints sequences of numbers.
|
|
|
|
|
*
|
|
|
|
|
* ## Arguments
|
|
|
|
|
* **<first>**
|
|
|
|
|
* Starting number for the sequence of numbers.
|
|
|
|
|
*
|
|
|
|
|
* **<incr>**
|
|
|
|
|
* Count in increments of <incr>. Default is 1 if omitted.
|
|
|
|
|
*
|
|
|
|
|
* **<last>**
|
|
|
|
|
* Last number to count to. If <last> is less than <first>, then the default <incr> is -1.
|
|
|
|
|
*
|
|
|
|
|
* ## Return Value
|
|
|
|
|
* N/A
|
|
|
|
|
*
|
|
|
|
|
* ### Author
|
|
|
|
|
* 2021-11-17, Brian J. Bernstein <brian@dronefone.com>.
|
|
|
|
|
*\-------------------------------------
|
|
|
|
|
.INB inc/macros.i
|
|
|
|
|
.INB inc/a2osx.i
|
|
|
|
|
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
* Defines / Consts
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
DIR_INCREMENT .EQ 1
|
|
|
|
|
DIR_DECREMENT .EQ 0
|
|
|
|
|
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
* Zero Page Segment, up to 32 bytes
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
.DUMMY
|
|
|
|
|
.OR ZPBIN
|
|
|
|
|
ZS.START
|
|
|
|
|
ZPPtr1 .BS 2 ; address pointer (used in arg parsing)
|
|
|
|
|
ArgIndex .BS 1 ; index offset for argument parsing
|
|
|
|
|
NumArgIndex .BS 1 ; used for numerical argument indexing
|
|
|
|
|
Direction .BS 1 ; direction of counting, 0=backwards, 1=forwards
|
|
|
|
|
wFirst .BS 2 ; arg variable - starting count
|
|
|
|
|
wIncr .BS 2 ; arg variable - increment
|
|
|
|
|
wLast .BS 2 ; arg variable - ending count
|
|
|
|
|
bFormat .BS 1 ; flag that the format -f option was specified
|
|
|
|
|
ZPPtrFormat .BS 2 ; pointer to format -f string
|
|
|
|
|
bString .BS 1 ; flag that the string -s option was specified
|
|
|
|
|
ZPPtrString .BS 2 ; pointer to string -s string
|
|
|
|
|
bTerminating .BS 1 ; flag that the terminating -t option was specified
|
|
|
|
|
ZPPtrTerm .BS 2 ; pointer to terminating -t string
|
|
|
|
|
ZS.END .ED
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
* File Header (16 Bytes)
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
CS.START cld
|
|
|
|
|
jmp (.1,x)
|
|
|
|
|
.DA #$61 ; 6502,Level 1 (65c02)
|
|
|
|
|
.DA #1 ; BIN Layout Version 1
|
|
|
|
|
.DA #0 ; Events disabled (enable with S.PS.F.EVENT)
|
|
|
|
|
.DA #0
|
|
|
|
|
.DA CS.END-CS.START ; Code Size (without Constants)
|
|
|
|
|
.DA DS.END-DS.START ; Data SegmentSize
|
|
|
|
|
.DA #32 ; Stack Size
|
|
|
|
|
.DA #ZS.END-ZS.START ; Zero Page Size
|
|
|
|
|
.DA 0
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
* Relocation Table
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
.1 .DA CS.INIT
|
|
|
|
|
.DA CS.RUN
|
|
|
|
|
.DA CS.DOEVENT
|
|
|
|
|
.DA CS.QUIT
|
|
|
|
|
L.MSG.USAGE .DA MSG.USAGE ; msg for usage / help text
|
|
|
|
|
L.MSG.NEWLINE .DA MSG.MSG.NEWLINE
|
|
|
|
|
L.FMT.FORMAT .DA FMT.FORMAT
|
|
|
|
|
L.FMT.STRING .DA FMT.STRING
|
|
|
|
|
L.FMT.TERM .DA FMT.TERM
|
|
|
|
|
.DA 0
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
* Called once at process creation
|
|
|
|
|
* Put code for loading LIB here
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
CS.INIT clc
|
|
|
|
|
|
|
|
|
|
lda L.FMT.FORMAT ; set default format
|
|
|
|
|
sta ZPPtrFormat
|
|
|
|
|
lda L.FMT.FORMAT+1
|
|
|
|
|
sta ZPPtrFormat+1
|
|
|
|
|
|
|
|
|
|
lda L.FMT.STRING ; set default string separator
|
|
|
|
|
sta ZPPtrString
|
|
|
|
|
lda L.FMT.STRING+1
|
|
|
|
|
sta ZPPtrString+1
|
|
|
|
|
|
|
|
|
|
lda L.FMT.TERM ; set default seq terminator string
|
|
|
|
|
sta ZPPtrTerm
|
|
|
|
|
lda L.FMT.TERM+1
|
|
|
|
|
sta ZPPtrTerm+1
|
|
|
|
|
|
|
|
|
|
rts
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
* Called until exit with CS
|
|
|
|
|
* if RUN exits with CC, RUN entered again
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
CS.RUN
|
|
|
|
|
.1 inc ArgIndex ; Check next argument
|
|
|
|
|
lda ArgIndex
|
|
|
|
|
>SYSCALL ArgV ; check for an arg at index in A
|
|
|
|
|
bcc .10 ; if it exists, keep checking
|
|
|
|
|
jmp .8 ; otherwise, we're done with args
|
|
|
|
|
|
|
|
|
|
.10 >STYA ZPPtr1 ; ArgV pointer was in Y,A so stick into ZPPtr1
|
|
|
|
|
lda (ZPPtr1)
|
|
|
|
|
cmp #'-' ; does arg have a hyphen?
|
|
|
|
|
bne .11 ; if not, check for string args
|
|
|
|
|
|
|
|
|
|
jsr CS.RUN.CheckOpt ; if it had a hyphen, check and set arg if recognized
|
|
|
|
|
bcc .1 ; if we recognized the arg, then loop again to check next
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*--- Checking of argument -F ----------
|
|
|
|
|
.11 bit bFormat ; did we just see the -f option?
|
2021-12-02 21:28:26 +00:00
|
|
|
|
bpl .12 ; no, jump to next arg flag
|
2021-12-02 21:06:35 +00:00
|
|
|
|
lda ArgIndex ; yes, then get the pointer to the arg string
|
|
|
|
|
>SYSCALL ArgV ; and set it to the pointer for the -f
|
|
|
|
|
>STYA ZPPtrFormat ; string storage
|
|
|
|
|
lda #0 ; and clear out that we processed the -f
|
|
|
|
|
sta bFormat ; argument so that we don't try it again
|
|
|
|
|
jmp .1 ; and then go process the next arg
|
|
|
|
|
|
|
|
|
|
*--- Checking of argument -S ----------
|
2021-12-02 21:28:26 +00:00
|
|
|
|
.12 bit bString ; did we just see the -s option?
|
|
|
|
|
bpl .13 ; no, jump to next arg flag
|
2021-12-02 21:06:35 +00:00
|
|
|
|
lda ArgIndex ; yes, then get the pointer to the next arg string
|
|
|
|
|
>SYSCALL ArgV ; and set it to the pointer for the -s
|
|
|
|
|
>STYA ZPPtrString ; string storage
|
|
|
|
|
lda #0 ; and clear out that we processed the -s
|
|
|
|
|
sta bString ; argument so that we don't try to do it again
|
|
|
|
|
jmp .1 ; and then go process the next arg
|
|
|
|
|
|
|
|
|
|
*--- Checking of argument -T ----------
|
2021-12-02 21:28:26 +00:00
|
|
|
|
.13 bit bTerminating ; did we just see the -t option?
|
2021-12-02 21:06:35 +00:00
|
|
|
|
bpl .2 ; no, jump to the next arg flag
|
|
|
|
|
lda ArgIndex ; yes, then get the pointer to the arg string
|
|
|
|
|
>SYSCALL ArgV ; and set it to the pointer for the -t
|
|
|
|
|
>STYA ZPPtrTerm ; string storage
|
|
|
|
|
lda #0 ; and clear out that we processed the -t
|
|
|
|
|
sta bTerminating ; argument so that we don't try it again
|
|
|
|
|
jmp .1 ; and then go process the next arg
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*--- Processing numerical args --------
|
|
|
|
|
.2 lda ArgIndex
|
|
|
|
|
>SYSCALL ArgV ; check for an arg at index in A
|
|
|
|
|
|
|
|
|
|
.20 >SYSCALL AToI ; get the next value on the command line
|
|
|
|
|
>STYA wIncr ; temporarily store it as the increment value
|
|
|
|
|
|
|
|
|
|
inc NumArgIndex
|
|
|
|
|
lda NumArgIndex ; check what argument value we were looking at
|
|
|
|
|
cmp #1 ; because if it was the first, then it is probably wFirst
|
|
|
|
|
bne .3
|
|
|
|
|
>LDYA wIncr ; copy the value to wFirst
|
|
|
|
|
>STYA wFirst
|
|
|
|
|
|
|
|
|
|
.3 cmp #2 ; but if we were looking at second value, then
|
|
|
|
|
bne .4 ; we assume it is 'wLast' for the moment
|
|
|
|
|
>LDYA wIncr ; and copy it over
|
|
|
|
|
>STYA wLast
|
|
|
|
|
|
|
|
|
|
.4 cmp #3 ; if we're looking at third value, then we must have had
|
|
|
|
|
bne .5 ; an increment value, so we need to swap what we recorded
|
|
|
|
|
ldx wLast ; as wLast and swap it with the just-read wIncr
|
|
|
|
|
ldy wIncr
|
|
|
|
|
stx wIncr
|
|
|
|
|
sty wLast
|
|
|
|
|
ldx wLast+1 ; as wLast and swap it with the just-read wIncr
|
|
|
|
|
ldy wIncr+1
|
|
|
|
|
stx wIncr+1
|
|
|
|
|
sty wLast+1
|
|
|
|
|
|
|
|
|
|
.5 jmp .1 ; go check for another argument
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*--- Done with args so figure out -----
|
|
|
|
|
*--- what numerical args are for ------
|
|
|
|
|
.8 lda NumArgIndex ; check that we got 1 to 3 numeric arguments.
|
|
|
|
|
cmp #1
|
|
|
|
|
bmi .9 ; otherwise, display help and error out
|
|
|
|
|
cmp #4
|
|
|
|
|
bpl .9
|
|
|
|
|
|
|
|
|
|
cmp #1 ; if we only got one, then it was wLast
|
|
|
|
|
bne .81
|
|
|
|
|
lda wFirst ; copy what we thought was wFirst to wLast
|
|
|
|
|
sta wLast
|
|
|
|
|
lda wFirst+1
|
|
|
|
|
sta wLast+1
|
|
|
|
|
ldy #1 ; set 1 as wFirst
|
|
|
|
|
lda #0
|
|
|
|
|
>STYA wFirst
|
|
|
|
|
>STYA wIncr ; and set 1 as wIncr
|
|
|
|
|
jmp .82
|
|
|
|
|
|
|
|
|
|
.81 cmp #2 ; check to see if we didn't get an increment
|
|
|
|
|
bne .82
|
|
|
|
|
ldy #1 ; if not, then just store +1 as the increment
|
|
|
|
|
lda #0
|
|
|
|
|
>STYA wIncr
|
|
|
|
|
|
|
|
|
|
.82 jsr CS.RUN.Seq ; everything is set, go 'seq' fame and fortune
|
|
|
|
|
jmp .99
|
|
|
|
|
|
|
|
|
|
*--- Display usage and error out ------
|
|
|
|
|
.9
|
|
|
|
|
>PUSHW L.MSG.USAGE ; push address for usage text
|
|
|
|
|
>PUSHBI 0
|
|
|
|
|
>SYSCALL PrintF ; print usage message
|
|
|
|
|
lda #E.SYN ; set OS return code as Syntax Error
|
|
|
|
|
sec ; indicate we don't want CS.RUN called again
|
|
|
|
|
rts ; return to OS
|
|
|
|
|
|
|
|
|
|
*--- Successful exit ------------------
|
|
|
|
|
.99
|
|
|
|
|
lda #0 ; set OS return code to success
|
|
|
|
|
sec ; indicate we don't want CS.RUN called again
|
|
|
|
|
rts ; return to OS
|
|
|
|
|
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
* Called if option S.PS.F.EVENT enabled in Header
|
|
|
|
|
* Timer Event : every 10th seconds
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
CS.DOEVENT sec ; we don't use this since we don't have timer events
|
|
|
|
|
rts
|
|
|
|
|
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
* Called once, when RUN exited with CS
|
|
|
|
|
* Put code for unloading LIB here
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
CS.QUIT clc ; nothing to do on exit except clear carry and return
|
|
|
|
|
rts
|
|
|
|
|
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
* CheckOpt assumes a set ZPPtr1 which is the address of the command line argument being examined.
|
|
|
|
|
* We start at 1 to look past the '-' as position 0 since that was checked by the caller.
|
|
|
|
|
* OptionList is a list of possible options and each character correlates with a memory offset
|
|
|
|
|
* in OptionVars, which are only one byte since they are in ZP but this also allows for us to
|
|
|
|
|
* simply use indexed addressing to reference them easily as well instead of doing 16-bit
|
|
|
|
|
* address juggling.
|
|
|
|
|
* The options are checked in reverse from end-to-start and indexed by X.
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
CS.RUN.CheckOpt ldy #1 ; set up y to look at second character of passed in arg
|
|
|
|
|
lda (ZPPtr1),y ; check second character of passed in argument into A
|
|
|
|
|
ldx #OptionVars-OptionList-1 ; clever way to put size of OptionList into X
|
|
|
|
|
|
|
|
|
|
.2 cmp OptionList,x ; compare the arg we got to the OptionList at X
|
|
|
|
|
beq .3 ; if it is a match, go handle it.
|
|
|
|
|
dex ; if not, decrement so we can check next OptionList
|
|
|
|
|
bpl .2 ; if we haven't reached end of OptionList, go check next
|
|
|
|
|
sec ; set carry if we didn't find a match
|
|
|
|
|
rts ; return to caller
|
|
|
|
|
|
|
|
|
|
.3 ldy OptionVars,x ; since we matched, find ZP addr of matching option into Y
|
|
|
|
|
lda #$ff ; we will set this ZP option to $FF
|
|
|
|
|
sta 0,y ; store A into the ZP address we have in Y
|
|
|
|
|
clc ; clear carry since we found a match
|
|
|
|
|
rts ; return to caller
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
* CS.RUN.Seq - Entry point for when args are handled and we're ready to 'seq'.
|
|
|
|
|
* This is anything we need to do before actually 'seq'encing.
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
CS.RUN.Seq jsr CS.DetermineDir ; determine if we're doing increment or decrement
|
|
|
|
|
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
* CS.DoSeq - the actual 'SEQ' work once everything is set up.
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
CS.DoSeq
|
|
|
|
|
|
|
|
|
|
*--- Print the number in ZPPtrFormat --
|
|
|
|
|
.1 >PUSHW ZPPtrFormat ; set up the format that we're printing sequence with
|
|
|
|
|
>PUSHW wFirst ; current seq value is kept in wFirst
|
|
|
|
|
>PUSHBI 2
|
|
|
|
|
>SYSCALL PrintF ; print the current seq count.
|
|
|
|
|
|
|
|
|
|
*--- Print the string sepators --------
|
|
|
|
|
>PUSHW ZPPtrString
|
|
|
|
|
>PUSHBI 0
|
|
|
|
|
>SYSCALL PrintF ; print string separator
|
|
|
|
|
|
|
|
|
|
lda Direction ; check which direction we're counting
|
|
|
|
|
cmp #DIR_INCREMENT ; going up?
|
|
|
|
|
bne .2 ; nope, go to decrement code
|
|
|
|
|
|
|
|
|
|
*--- Do INCREMENTAL math on the seq ---
|
|
|
|
|
clc ; ADDING wIncr to wFirst
|
|
|
|
|
lda wFirst ; do 16-bit addition of wFirst + wIncr
|
|
|
|
|
adc wIncr
|
|
|
|
|
sta wFirst
|
|
|
|
|
lda wFirst+1
|
|
|
|
|
adc wIncr+1
|
|
|
|
|
sta wFirst+1
|
|
|
|
|
|
|
|
|
|
jsr CS.CmpFirstLast ; is wFirst >= wLast?
|
|
|
|
|
bcs .1 ; no, so keep going
|
|
|
|
|
|
|
|
|
|
lda wFirst ; check to see if wFirst == wLast
|
|
|
|
|
cmp wLast
|
|
|
|
|
bne .9
|
|
|
|
|
lda wFirst+1
|
|
|
|
|
cmp wLast+1
|
|
|
|
|
bne .9
|
|
|
|
|
jmp .1 ; wFirst == wLast, so go around one more time
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*--- Do DECREMENTAL math on the seq ---
|
|
|
|
|
.2 sec ; SUBTRACTING wIncr from wFirst
|
|
|
|
|
lda wFirst
|
|
|
|
|
sbc wIncr
|
|
|
|
|
sta wFirst
|
|
|
|
|
lda wFirst+1
|
|
|
|
|
sbc wIncr+1
|
|
|
|
|
sta wFirst+1
|
|
|
|
|
|
|
|
|
|
jsr CS.CmpFirstLast ; is wFirst still >= wLast?
|
|
|
|
|
bcc .1 ; yes, keep going.
|
|
|
|
|
|
|
|
|
|
lda wFirst ; check to see if wFirst == wLast
|
|
|
|
|
cmp wLast
|
|
|
|
|
bne .9
|
|
|
|
|
lda wFirst+1
|
|
|
|
|
cmp wLast+1
|
|
|
|
|
bne .9
|
|
|
|
|
jmp .1 ; wFirst == wLast, so go around one more time
|
|
|
|
|
|
|
|
|
|
*--- Done with sequence, finish up ----
|
|
|
|
|
.9
|
|
|
|
|
>PUSHW ZPPtrTerm ; set up terminating string
|
|
|
|
|
>PUSHBI 0
|
|
|
|
|
>SYSCALL PrintF ; print terminating string
|
|
|
|
|
rts ; done with SEQ!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* TODO: negatives in incr shouldn't be allowed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
* CS.DetermineDir - checks that increment value in relation +/- to
|
|
|
|
|
* wFirst / wLast, and then sets the Direction flag.
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
CS.DetermineDir jsr CS.CmpFirstLast ; compare first/last values
|
|
|
|
|
bcc .1 ; if first < last, then we're counting forward
|
|
|
|
|
lda #DIR_INCREMENT
|
|
|
|
|
jmp .2
|
|
|
|
|
.1 lda #DIR_DECREMENT
|
|
|
|
|
.2 sta Direction ; set the direction
|
|
|
|
|
rts ; and return to caller.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
* CS.CmpFirstLast - compares wFirst to wLast value and sets carry based on
|
|
|
|
|
* if wFirst greater than or equal to wLast, or clear carry
|
|
|
|
|
* if wFirst is less than wLast.
|
|
|
|
|
*
|
|
|
|
|
* IN: n/a (uses global wFirst/wLast)
|
|
|
|
|
* OUT: carry flag; set if wFirst >= wLast, clear if wFirst < wLast.
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
CS.CmpFirstLast >PUSHW wFirst ; using FPU macro, so push first,
|
|
|
|
|
>PUSHW wLast ; and call the macro
|
|
|
|
|
>FPU iGE
|
|
|
|
|
lda (pStack) ; get result from stack
|
|
|
|
|
bne .1 ; yes, wFirst is >= wLast
|
|
|
|
|
>POP 2 ; wFirst < wLast
|
|
|
|
|
sec ; return to caller with carry set
|
|
|
|
|
rts
|
|
|
|
|
|
|
|
|
|
.1 >POP 2 ; wFirst is >= wLast
|
|
|
|
|
clc ; return to caller with carry clear
|
|
|
|
|
rts
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
CS.END
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
MSG.USAGE .AS "Usage : SEQ [first [incr]] last\r\n"
|
|
|
|
|
.AS " -F numeric format\r\n"
|
|
|
|
|
.AS " -S string separator\r\n"
|
|
|
|
|
.AZ " -T terminating string\r\n"
|
|
|
|
|
MSG.MSG.NEWLINE .AZ "\r\n"
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
FMT.FORMAT .AZ "%I"
|
|
|
|
|
FMT.STRING .AZ "\r\n"
|
|
|
|
|
FMT.TERM .AZ ""
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
OptionList .AS "FfSsTt"
|
|
|
|
|
OptionVars .DA #bFormat,#bFormat,#bString,#bString,#bTerminating,#bTerminating
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
* Per Process DATA segment (0 filled before INIT)
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
.DUMMY
|
|
|
|
|
.OR 0
|
|
|
|
|
DS.START
|
|
|
|
|
DS.END .ED
|
|
|
|
|
*--------------------------------------
|
|
|
|
|
|
|
|
|
|
MAN
|
|
|
|
|
SAVE usr/src/bin/seq.s
|
|
|
|
|
ASM
|