Modified NSC driver for use with Ultrawarp

This commit is contained in:
Bobbi Webber-Manners 2021-05-29 20:54:07 -04:00
parent b0e77c2f7c
commit b4a0031f9d
6 changed files with 846 additions and 9 deletions

40
No_Slot_Clock/README.md Normal file
View File

@ -0,0 +1,40 @@
#`NS.CLOCK.SYSTEM`
##No Slot Clock Driver for ProDOS
`nsc.s` is the original No Slot Clock driver written by SMT, which has been
disassembled and commented by Github user mgcaret. I took it from [here]
(https://gist.github.com/mgcaret/ae2860c754fd029d2640107c4fe0bffd).
The RM Ultrawarp Apple II accelerator card has some sort of bug in the
banking of ROMs. As a result of this problem, the original `NS.CLOCK.SYSTEM`
does not work on a system with Ultrawarp, unless the accelerator card is
completely disabled. The symptom is that the NSC is detected and the ProDOS
driver is installed, but the time returned is all zeroes. It does not appear
to be a problem related to the 13MHz clock speed of the Ultrawarp accelerator
because it also manifests if the Ultrawarp is active but with 1MHz clock.
`nsc_ultrawarp.s` is a modified version of nsc.s which includes a workaround
for this problem. It has the following differences compared to `nsc.s`:
- The original code searches for an NSC installed under peripheral card
ROMs in each of the Apple II slots, and only then searches for a NSC
installed in the normal place, which is underneath the CE or CX ROM on
an Apple //e, or the Monitor ROM on an original Apple II or plus. I
removed the search through the slots, and now only look for an NSC
installed under the CE/CX ROM or Monitor ROM.
- In the original code, the driver code itself is modified in place to
work with the NSC in the location where it was detected. This is no
longer required, so I removed the self-modifying code. This makes the
code easier to read, and also makes the clock driver a few bytes shorter,
which is critical, as there was no space to add any additional code.
- Added an additional instruction `LDA $C00B` at the beginning of the clock
driver. This causes the driver to work properly with the Ultrawarp
active, either at full speed (13MHz) or 1MHz. The reason adding this one
read fixes the erroneous behaviour is not well understood. It seems that
the additional instruction causes the CE/CX ROM to be banked in. Without
this extra instruction, it seems the ROM was not banked in when running
with the Ultrawarp. This appears to be a hardware bug in the Ultrawarp.
Bobbi
May 29, 2021

5
No_Slot_Clock/build_nsc Executable file
View File

@ -0,0 +1,5 @@
ca65 nsc_ultrawarp.s
ld65 nsc_ultrawarp.o -t none -o ns.clock.system\#ff0000
cadius createvolume nsc_ultrawarp.po NSC.UW 140KB
cadius addfile nsc_ultrawarp.po /NSC.UW ns.clock.system\#ff0000
scp nsc_ultrawarp.po pi@pi-eth:~/virtual-1.po

View File

@ -565,6 +565,7 @@ MyName: .byte $0F,"NS.CLOCK.SYSTEM" ; overwritten in the usual case
ClockDrv:
php
sei
lda $C00B ; Workaround for Ultrawarp bug
lda C8OFF
CDRdSwL = * - 2 ; may modify to read INTCXROM state
CDRdSwH = * - 1
@ -597,27 +598,28 @@ CDUnlck = * - 1 ; may be patched to a different
bne ubytlp
ldx #$08 ; loop counter to read 8 bytes of clock data
rbytlp: ldy #$08 ; loop counter to read 8 bits of clock data
rbitlp: lda SLOT3ROM+$04 ; get data bit (NSC clocks reads off of A2)
rbitlp: pha
lda SLOT3ROM+$04 ; get data bit (NSC clocks reads off of A2)
CDRdClk = * - 1 ; may be patched for different loc
ror a ; put into carry
ror INBUF-1,x ; and then rotate into relative input buffer loc
pla
ror a ; then rotate into relative i/p buffer loc
dey
bne rbitlp ; next bit
lda INBUF-1,x ; now BCD->Binary
pha ; now BCD->Binary
lsr a
lsr a
lsr a
lsr a
tay
beq notens ; no tens digit
lda INBUF-1,x
pla
and #$0F
clc ; repeated addition for tens
: adc #$0A
dey
: dey
bmi notens ; no tens digit
adc #$0A
bne :-
sta INBUF-1,X ; update value to binary equiv
notens: dex
notens: sta INBUF-1,X ; update value to binary equiv
bne rbytlp ; next byte
; put values into ProDOS time locations
lda INBUF+4

Binary file not shown.

View File

@ -0,0 +1,790 @@
; Fully disassembled and analyzed source to SMT
; NS.CLOCK.SYSTEM by M.G. - 04/20/2017
; Assembles to a binary match for SMT code if
; IncludeJunk is set, see the .if IncludeJunk for details.
; other notes:
; * uses direct block access to read volume directory,
; so won't launch from an AppleShare volume.
; Build instructions:
; ca65 ns.clock.system.s -l ns.clock.system.lst
; ld65 -t none -o ns.clock.system ns.clock.system.o
; put ns.clock.system as a SYS file on a ProDOS disk.
.setcpu "6502"
IncludeJunk = 0 ; original file had a bunch of garbage
; setting this to 1 includes it
; ----------------------------------------------------------------------------
; Zero page
POINTER := $A5 ; generic pointer used everywhere
ENTNUM := $A7 ; current file entry # in block (zero-based)
LENGTH := $A8 ; generic length byte used everywhere
; entry points
PRODOS := $BF00
INIT := $FB2F
HOME := $FC58
CROUT := $FD8E
PRBYTE := $FDDA
COUT := $FDED
SETNORM := $FE84
SETKBD := $FE89
SETVID := $FE93
; buffers & other spaces
INBUF := $0200 ; input buffer
PATHBUF := $0280 ; path buffer
RELOCT := $1000 ; relocation target
BLOCKBUF := $1800 ; block & I/O buffer
SYSEXEC := $2000 ; location of SYS executables
SOFTEV := $03F2 ; RESET vector
; global Page entries
CLKENTRY := $BF06 ; clock routine entry point
DEVNUM := $BF30 ; most recent accessed device
MEMTABL := $BF58 ; system bitmap
DATELO := $BF90
DATEHI := $BF91
TIMELO := $BF92
TIMEHI := $BF93
MACHID := $BF98 ; machine ID
; I/O and hardware
ROMIn2 := $C082 ; access to read ROM/no write LC RAM
LCBank1 := $C08B ; Access twice to write LC bank 1
KBD := $C000 ; keyboard
INTCXROMOFF := $C006 ; Disable internal $C100-$CFFF ROM
INTCXROMON := $C007 ; Enable interal $C100-$CFFF ROM
KBDSTR := $C010 ; keyboard strobe
INTCXROM := $C015 ; Read state of $C100-$CFFF soft switch
CLR80VID := $C00C ; Turn off 80-column mode
CLRALTCHAR := $C00E ; Turn off alt charset
SLOT3ROM := $C300 ; SLOT 3 ROM
C8OFF := $CFFF ; C8xx Slot ROM off
; Misc
CLKCODEMAX := $7D
; Macro to define ASCII string with high bit set.
.macro hasc Arg
.repeat .strlen(Arg), I
.byte .strat(Arg, I) | $80
.endrep
.endmacro
; ----------------------------------------------------------------------------
; relocate ourself from SYSEXEC to RELOCT
; note that we .org the whole thing, including this routine, at the target
; address and jump to it after the first page is relocated.
.org RELOCT ; note code initially runs at SYSEXEC
.proc Relocate
sec
bcs :+ ; skip version info
.byte $05, $29, $21 ; version date in BCD (May 29 2021)
: ldx #$05 ; page counter, do $0500 bytes
ldy #$00 ; byte counter
from: lda SYSEXEC,y ; start location
to: sta RELOCT,y ; end location
iny ; next byte offset
bne from ; if not zero, copy byte
inc from+2 ; otherwise increment source address high byte
inc to+2 ; and destination address high byte
dex ; dec page counter
beq Main ; when done start main code
jmp from ; live jump... into relocated code after first page loop
.endproc
; ----------------------------------------------------------------------------
.proc Main
; figure out length of our name and stick in LENGTH
lda #$00
sta LENGTH ; zero length
ldx PATHBUF ; length pf path
beq Main1 ; skip if length = 0 (no path)
: inc LENGTH ; length += 1 for each non-/
dex ; previous char in path
beq CopyNm ; nothing left? Copy our name.
lda PATHBUF,x ; get character
; check for /... kinda wtf, as cmp #$2f would work...
eor #$2F ; roundabout check for '/'
asl a ; upper/lower case
bne :- ; keep examining if not '/'
; now save our name (assuming we weren't lied to)
CopyNm: ldy #$00 ; init destination offset
: iny ; increment destination offset
inx ; inc source offset
lda PATHBUF,x ; get source char
sta MyName,y ; write to save location
cpy LENGTH ; got it all?
bcc :- ; nope, copy more
sty MyName ; save length
; done moving stuff
Main1: cld
bit ROMIn2 ; make sure ROM enabled
; letter of the law with RESET vector
lda #<Main1
sta SOFTEV
lda #>Main1
sta SOFTEV+1
eor #$A5
sta SOFTEV+2
lda #$95 ; control code
jsr COUT ; to quit 80-column firmware
ldx #$FF ; reset
txs ; stack pointer
; get video & keyboard I/O to known state
sta CLR80VID
sta CLRALTCHAR
jsr SETVID
jsr SETKBD
jsr SETNORM
jsr INIT
; initialize memory map
ldx #$17 ; there are $18 bytes total
lda #$01 ; last byte gets $01 (protect global page)
: sta MEMTABL,x
lda #$00 ; all but first byte get $00 (no protection)
dex
bne :-
lda #$CF ; first byte protect ZP, stack, text page 1
sta MEMTABL
lda MACHID
and #$88 ; mask in bits indicating machine with lower case
bne :+ ; has lower case, skip over next few instructions
lda #$DF ; mask value
sta CaseCv ; to make print routine convert to upper case
: lda MACHID
and #$01 ; mask in clock bit
beq FindClock ; no clock yet, proceed
jsr HOME
jsr iprint
.byte $8D ; CR
hasc "Previous Clock Installed!"
.byte $87,$8D,$00 ; BELL, CR, done
jmp NextSys
.endproc
; go hunting for clock
.proc FindClock
ldy #$03 ; save old date and time
: lda DATELO,y ; because we are going to overwrite
sta DTSave,y ; during our probes
dey
bpl :-
jmp InstallDriver
.endproc
.proc NoClock
ldy #$03 ; restore old date/time because
: lda DTSave,y ; we didn't find clock anywhere
sta DATELO,y
dey
bpl :-
jsr HOME
jsr iprint
.byte $8D
hasc "No-Slot Clock Not Found." ; typo in original fixed
.byte $8D, $8D
hasc "Clock Not Installed!"
.byte $87, $8D, $00
; launch next .system file
jmp NextSys
.endproc
DTSave: .byte $00,$00,$00,$00 ; Saved ProDOS Date/Time values
; install driver, this does it the right way and looks at the vector
; and puts the driver there
.proc InstallDriver
; this code corrects reference to DS121x unlock sequence
lda CLKENTRY+1
sta POINTER
clc
adc #(DSUnlk-ClockDrv)
sta CDULSqL
lda CLKENTRY+2
sta POINTER+1
adc #$00
sta CDULSqH
; done correcting
lda LCBank1 ; make LC RAM writable
lda LCBank1
ldy #DrvSize ; copy driver
: lda ClockDrv,y
sta (POINTER),y
dey
bpl :-
lda MACHID ; current MACHID
ora #$01 ; set clock installed bit
sta MACHID ; and put back
lda #$4C ; JMP
sta CLKENTRY ; into clock driver entry point
jsr CLKENTRY ; may as well give it a whirl
bit ROMIn2 ; LC write protect
jsr HOME
jsr iprint
.byte $8d
hasc "No-Slot Clock Installed "
.byte $00
; print today's date
lda DATEHI
ror a
pha
lda DATELO
pha
rol a
rol a
rol a
rol a
and #$0F
jsr PrDec
lda #$AF
jsr COUT
pla
and #$1F
jsr PrDec
lda #$AF
jsr COUT
pla
jsr PrDec
jsr CROUT
.endproc
; This starts the process of finding & launching next system file
; unfortunately it also uses block reads and can't be run from an AppleShare
; volume.
.proc NextSys
; set reset vector to DoQUit
lda #<DoQuit
sta SOFTEV
lda #>DoQuit
sta SOFTEV+1
eor #$A5
sta SOFTEV+2
lda DEVNUM ; last unit number accessed
sta PL_READ_BLOCK+1 ; put in parameter list
jsr GetBlock ; get first volume directory block
lda BLOCKBUF+$23 ; get entry_length
sta SMENTL ; modify code
lda BLOCKBUF+$24 ; get entries_per_block
sta SMEPB ; modify code
lda #$01 ;
sta ENTNUM ; init current entry number as second (from 0)
lda #<(BLOCKBUF+$2B) ; set pointer to that entry
sta POINTER ; making assumptions as we go
lda #>(BLOCKBUF+$2B)
sta POINTER+1
; loop to examine file entries...
FEntLp: ldy #$10 ; offset of file_type
lda (POINTER),y
cmp #$FF ; SYS?
bne NxtEnt ; nope..
ldy #$00 ; offset of storage_type & name_length
lda (POINTER),y
and #$30 ; mask interesting bits of storage_type
beq NxtEnt ; if not 1-3 (standard file organizations)
lda (POINTER),y ; get storage_type and name_length again
and #$0F ; mask in name_length
sta LENGTH ; save for later
tay ; and use as index for comparison
; comparison loop
ldx #$06 ; counter for size of ".SYSTEM"
: lda (POINTER),y ; get file name byte
cmp system,x ; compare to ".SYSTEM"
bne NxtEnt ; no match
dey
dex
bpl :-
; if we got here, have ".SYSTEM" file
ldy MyName ; length of our own file name
cpy LENGTH ; matches?
bne CkExec ; nope, see if we should exec
; loop to check if this is our own name
: lda (POINTER),y
cmp MyName,y
bne CkExec ; no match, see if we should exec
dey
bne :-
; if we got here, we have found our own self
sec
ror FdSelf ; flag it
; go to next entry
NxtEnt: lda POINTER ; low byte of entry pointer
clc ; ready for addition
adc #$27 ; add entry length that is
SMENTL = * - 1 ; self-modifed
sta POINTER ; save it
bcc :+ ; no need to do high byte if no carry
inc POINTER+1 ; only increment if carry
: inc ENTNUM ; next entry number
lda ENTNUM ; and get it
cmp #$0D ; check against number of entries that is
SMEPB = * - 1 ; self-modified
bcc FEntLp ; back to main search if not done with this block
lda BLOCKBUF+$02 ; update PL_BLOCK_READ for next directory block
sta PL_READ_BLOCK+4
lda BLOCKBUF+$03
sta PL_READ_BLOCK+5
ora PL_READ_BLOCK+4 ; see if pointer is $00
beq NoSys ; error if we hit the end and found nothing..
jsr GetBlock ; get next volume directory block
lda #$00
sta ENTNUM ; update current entry number
lda #<(BLOCKBUF+$04) ; and reset pointer
sta POINTER
lda #>(BLOCKBUF+$04)
sta POINTER+1
jmp FEntLp ; go back to main loop
CkExec: bit FdSelf ; did we find our own name yet?
bpl NxtEnt ; nope... go to next entry
ldx PATHBUF ; get length of path in path buffer
beq CpyNam ; skip looking for / if zero
: dex ;
beq CpyNam ; done if zero
lda PATHBUF,x ;
eor #$2F ; is '/'?
asl a ; in roundabout way
bne :- ; no slash
; copy file name onto path, x already has position
CpyNam: ldy #$00
: iny ; next source byte offset
inx ; next dest byte offset
lda (POINTER),y ; get filename char
sta PATHBUF,x ; put in path
cpy LENGTH ; copied all the chars?
bcc :- ; nope
stx PATHBUF ; update length of path
jmp LaunchSys ; try to launch it!
NoSys: jsr iprint
.byte $8D, $8D, $8D
hasc "* Unable to find next '.SYSTEM' file *"
.byte $8D, $00
; wait for keyboard then quit to ProDOS
bit KBDSTR
: lda KBD
bpl :-
bit KBDSTR
jmp DoQuit
.endproc
; ----------------------------------------------------------------------------
; inline print routine
; print chars after JSR until $00 encountered
; converts case via CaseCv ($FF = no conversion, $DF = to upper)
.proc iprint
pla
sta POINTER
pla
sta POINTER+1
bne next
: cmp #$E1
bcc noconv
and CaseCv
noconv: jsr COUT
next: inc POINTER
bne nohi
inc POINTER+1
nohi: ldy #$00
lda (POINTER),y
bne :-
lda POINTER+1
pha
lda POINTER
pha
rts
.endproc
; ----------------------------------------------------------------------------
; print one or two decimal digits
.proc PrDec
ldx #$B0 ; tens digit
cmp #$0A
bcc onedig
: sbc #$0A ; repeated subtraction, carry is already set
inx
cmp #$0A ; less than 10 yet?
bcs :- ; nope
onedig: pha
cpx #$B0
beq nozero ; skip printing leading zero
txa
jsr COUT
nozero: pla
ora #$B0
jsr COUT
rts
.endproc
CaseCv: .byte $FF ; default case conversion byte = none
; ----------------------------------------------------------------------------
.proc DoQuit
jsr PRODOS
.byte $65 ; MLI QUIT
.word PL_QUIT
brk ; crash into monitor if QUIT fails
rts ; (!) if that doesn't work, go back to caller
PL_QUIT:
.byte $04 ; param count
.byte $00 ; quit type - $00 is only type
.word $0000 ; reserved
.byte $00 ; reserved
.word $0000 ; reserved
.endproc
.proc GetBlock
jsr PRODOS
.byte $80 ; READ_BLOCK
.word PL_READ_BLOCK
bcs LaunchFail
rts
.endproc
PL_READ_BLOCK:
.byte $03
.byte $60 ; unit number
.word BLOCKBUF
.word $0002 ; first volume directory block
; ----------------------------------------------------------------------------
; launch next .SYSTEM file
.proc LaunchSys
jsr PRODOS
.byte $C8 ; OPEN
.word PL_OPEN
bcs LaunchFail
lda PL_OPEN+$05 ; copy ref number
sta PL_READ+$01 ; into READ parameter list
jsr PRODOS
.byte $CA ; READ
.word PL_READ
bcs LaunchFail
; bug the first: Close should be done every time the OPEN call is successful
; but only done when the READ succeeds
; bug the second: Others may not consider this a bug, but we close all open
; files, even if we didn't open them. That's not very polite.
jsr PRODOS
.byte $CC ; CLOSE
.word PL_CLOSE
bcs LaunchFail
jmp SYSEXEC
.endproc
; ----------------------------------------------------------------------------
; failed to launch next .SYSTEM file
.proc LaunchFail
pha
jsr iprint
.byte $8D, $8D, $8D
hasc "** Disk Error $"
.byte $00
pla
jsr PRBYTE
jsr iprint
hasc " **"
.byte $8D, $00
; wait for keyboard, then quit to ProDOS
bit KBDSTR
: lda KBD
bpl :-
bit KBDSTR
jmp DoQuit
.endproc
; ----------------------------------------------------------------------------
PL_OPEN:
.byte $03
.word PATHBUF
.word BLOCKBUF
.byte $01 ; ref num (default 1 wtf?)
PL_READ:
.byte $04
.byte $01 ; ref num
.word SYSEXEC ; data buffer
.word $FFFF ; request count
.word $0000 ; transfer count
PL_CLOSE:
.byte $01
.byte $00 ; ref num $00 = all files
; ----------------------------------------------------------------------------
FdSelf: .byte $00 ; bit 7 set if we found our name in volume dir
system: .byte ".SYSTEM"
MyName: .byte $0F,"NS.CLOCK.SYSTEM" ; overwritten in the usual case
; actual clock driver follows
ClockDrv:
php
sei
lda $C00B ; Workaround for Ultrawarp bug - Bobbi
lda $CFFF
pha
sta $C300
lda $C304
ldx #$08
ubytlp: lda DSUnlk,X
CDULSqL = * - 2 ; to be patched later when relocated into ProDOS
CDULSqH = * - 1
sec ; bit 7 of a is going to be set
ror a ; first bit in byte of unlock seq in carry & b7 = 1
ubitlp: pha ; remaining bits are in a, so save it
lda #$00
rol a ; move unlock bit into low bit
tay ; put into y
lda $C300,Y ; NSC looks for unlock on A0 line
pla ; restore unlock seq in progress
lsr a ; next bit into cary
bne ubitlp ; do again until that 1 bit we set above rolls off
dex ; next byte of unlock sequence
bne ubytlp
ldx #$08 ; loop counter to read 8 bytes of clock data
rbytlp: ldy #$08 ; loop counter to read 8 bits of clock data
rbitlp: lda $C304 ; get data bit (NSC clocks reads off of A2)
ror a ; put into carry
ror INBUF-1,x ; and then rotate into relative input buffer loc
dey
bne rbitlp ; next bit
lda INBUF-1,x ; now BCD->Binary
lsr a
lsr a
lsr a
lsr a
tay
beq notens ; no tens digit
lda INBUF-1,x
and #$0F
clc ; repeated addition for tens
: adc #$0A
dey
bne :-
sta INBUF-1,X ; update value to binary equiv
notens: dex
bne rbytlp ; next byte
; put values into ProDOS time locations
lda INBUF+4
sta TIMEHI
lda INBUF+5
sta TIMELO
lda INBUF+1
asl a
asl a
asl a
asl a
asl a
ora INBUF+2
sta DATELO
lda INBUF
rol a
sta DATEHI
pla
;;bmi :+
;;sta INTCXROMOFF
: plp
rts
; Dallas unlock sequence
DSUnlk = * - 1
.byte $5C, $A3, $3A, $C5, $5C, $A3, $3A, $C5
DrvSize = * - ClockDrv
.assert DrvSize < CLKCODEMAX, error, "NS CLOCK driver too big"
; ----------------------------------------------------------------------------
; the rest of this looks like junk that was accidentally saved with the file
; there are no references from the previous code. Didn't feel like disassembling.
.if IncludeJunk
.setcpu "6502"
BASWARM := $D43F ; warm start BASIC
FNDLIN := $D61A ; BASIC search for line
SETPTRS := $D665
L008D := $008D
L0EA1 := $0EA1
L161F := $161F
L2020 := $2020
L434F := $434F
L522F := $522F
L9A17 := $9A17
LAC08 := $AC08
LAC0D := $AC0D
LAC1F := $AC1F
LAC6B := $AC6B
LAD50 := $AD50
LAFD3 := $AFD3
LAFD7 := $AFD7
LB1D3 := $B1D3
LB531 := $B531
LBE70 := $BE70
LFFFF := $FFFF
.byte $00
stz $F5,x ; 147C 74 F5 t.
.byte $D3 ; 147E D3 .
adc $8DB3 ; 147F 6D B3 8D m..
lsr $BE,x ; 1482 56 BE V.
jmp L2020 ; 1484 4C 20 20 L
; ----------------------------------------------------------------------------
bbr2 $43,L14DE ; 1487 2F 43 54 /CT
rol $2031 ; 148A 2E 31 20 .1
sta $AE00 ; 148D 8D 00 AE ...
lda $CABB,x ; 1490 BD BB CA ...
stx $74 ; 1493 86 74 .t
jsr LAC0D ; 1495 20 0D AC ..
ldx $20A9 ; 1498 AE A9 20 ..
bbr2 $48,L14DF ; 149B 2F 48 41 /HA
eor ($44) ; 149E 52 44 RD
and ($20),y ; 14A0 31 20 1
sta $A400 ; 14A2 8D 00 A4 ...
lda #$00 ; 14A5 A9 00 ..
beq L14BE ; 14A7 F0 15 ..
lda #$00 ; 14A9 A9 00 ..
sta $BE44 ; 14AB 8D 44 BE .D.
jsr L522F ; 14AE 20 2F 52 /R
eor ($4D,x) ; 14B1 41 4D AM
jsr L008D ; 14B3 20 8D 00 ..
jsr LAC08 ; 14B6 20 08 AC ..
bcs L150B ; 14B9 B0 50 .P
jsr SETPTRS ; 14BB 20 65 D6 e.
L14BE: sta $D8 ; 14BE 85 D8 ..
jsr L0EA1 ; 14C0 20 A1 0E ..
bbr2 $4E,L1515 ; 14C3 2F 4E 4F /NO
rol $4C53 ; 14C6 2E 53 4C .SL
bbr4 $54,L14FA ; 14C9 4F 54 2E OT.
.byte $43 ; 14CC 43 C
jmp L434F ; 14CD 4C 4F 43 LOC
; ----------------------------------------------------------------------------
.byte $4B ; 14D0 4B K
jsr L008D ; 14D1 20 8D 00 ..
lda #$FF ; 14D4 A9 FF ..
jsr L522F ; 14D6 20 2F 52 /R
eor ($4D,x) ; 14D9 41 4D AM
jsr L008D ; 14DB 20 8D 00 ..
L14DE: .byte $76 ; 14DE 76 v
L14DF: bbs1 $4C,L1525 ; 14DF 9F 4C 43 .LC
tay ; 14E2 A8 .
jsr LAC08 ; 14E3 20 08 AC ..
bcs L150B ; 14E6 B0 23 .#
jsr SETPTRS ; 14E8 20 65 D6 e.
jsr L9A17 ; 14EB 20 17 9A ..
lda #$00 ; 14EE A9 00 ..
sta $24 ; 14F0 85 24 .$
jmp BASWARM ; 14F2 4C 3F D4 L?.
; ----------------------------------------------------------------------------
jsr LB531 ; 14F5 20 31 B5 1.
bcs L150B ; 14F8 B0 11 ..
L14FA: jsr LAC1F ; 14FA 20 1F AC ..
bcs L150B ; 14FD B0 0C ..
sty $6B ; 14FF 84 6B .k
sty $69 ; 1501 84 69 .i
sty $6D ; 1503 84 6D .m
stx $6C ; 1505 86 6C .l
stx $6A ; 1507 86 6A .j
stx $6E ; 1509 86 6E .n
L150B: rts ; 150B 60 `
; ----------------------------------------------------------------------------
lda #$01 ; 150C A9 01 ..
ldx #$FC ; 150E A2 FC ..
jsr LB1D3 ; 1510 20 D3 B1 ..
bcs L150B ; 1513 B0 F6 ..
L1515: lda #$D1 ; 1515 A9 D1 ..
jsr LBE70 ; 1517 20 70 BE p.
bcs L150B ; 151A B0 EF ..
lda $67 ; 151C A5 67 .g
sta $BED7 ; 151E 8D D7 BE ...
adc $BEC8 ; 1521 6D C8 BE m..
.byte $8D ; 1524 8D .
L1525: cli ; 1525 58 X
ldx $68A5,y ; 1526 BE A5 68 ..h
sta $BED8 ; 1529 8D D8 BE ...
adc $BEC9 ; 152C 6D C9 BE m..
sta $BE59 ; 152F 8D 59 BE .Y.
bcs L1536 ; 1532 B0 02 ..
cmp $74 ; 1534 C5 74 .t
L1536: lda #$0E ; 1536 A9 0E ..
bcs L150B ; 1538 B0 D1 ..
ldx $BEC8 ; 153A AE C8 BE ...
ldy $BEC9 ; 153D AC C9 BE ...
jsr LAFD7 ; 1540 20 D7 AF ..
bcs L150B ; 1543 B0 C6 ..
jsr LAFD3 ; 1545 20 D3 AF ..
bcs L150B ; 1548 B0 C1 ..
jsr LAC6B ; 154A 20 6B AC k.
ldx $BE59 ; 154D AE 59 BE .Y.
ldy $BE58 ; 1550 AC 58 BE .X.
stx $B0 ; 1553 86 B0 ..
sty $AF ; 1555 84 AF ..
rts ; 1557 60 `
; ----------------------------------------------------------------------------
sec ; 1558 38 8
lda $67 ; 1559 A5 67 .g
sbc $BEB9 ; 155B ED B9 BE ...
sta $3C ; 155E 85 3C .<
lda $68 ; 1560 A5 68 .h
sbc $BEBA ; 1562 ED BA BE ...
sta $3D ; 1565 85 3D .=
ora $3C ; 1567 05 3C .<
clc ; 1569 18 .
beq L15B1 ; 156A F0 45 .E
ldx $67 ; 156C A6 67 .g
lda $68 ; 156E A5 68 .h
L1570: stx $3A ; 1570 86 3A .:
sta $3B ; 1572 85 3B .;
ldy #$01 ; 1574 A0 01 ..
lda ($3A),y ; 1576 B1 3A .:
dey ; 1578 88 .
ora ($3A),y ; 1579 11 3A .:
beq L15B1 ; 157B F0 34 .4
lda ($3A),y ; 157D B1 3A .:
adc $3C ; 157F 65 3C e<
tax ; 1581 AA .
sta ($3A),y ; 1582 91 3A .:
iny ; 1584 C8 .
lda ($3A),y ; 1585 B1 3A .:
adc $3D ; 1587 65 3D e=
sta ($3A),y ; 1589 91 3A .:
clc ; 158B 18 .
bcc L1570 ; 158C 90 E2 ..
lda $BE57 ; 158E AD 57 BE .W.
and #$08 ; 1591 29 08 ).
clc ; 1593 18 .
beq L15B1 ; 1594 F0 1B ..
lda $BE68 ; 1596 AD 68 BE .h.
sta $50 ; 1599 85 50 .P
lda $BE69 ; 159B AD 69 BE .i.
sta $51 ; 159E 85 51 .Q
jsr FNDLIN ; 15A0 20 1A D6 ..
clc ; 15A3 18 .
lda $9B ; 15A4 A5 9B ..
adc #$FF ; 15A6 69 FF i.
sta $B8 ; 15A8 85 B8 ..
lda $9C ; 15AA A5 9C ..
adc #$FF ; 15AC 69 FF i.
sta $B9 ; 15AE 85 B9 ..
clc ; 15B0 18 .
L15B1: rts ; 15B1 60 `
; ----------------------------------------------------------------------------
bcc L15D6 ; 15B2 90 22 ."
lda #$FC ; 15B4 A9 FC ..
sta $BE6A ; 15B6 8D 6A BE .j.
sta $BEB8 ; 15B9 8D B8 BE ...
lda #$C3 ; 15BC A9 C3 ..
sta $BEB7 ; 15BE 8D B7 BE ...
lda $67 ; 15C1 A5 67 .g
sta $BEA5 ; 15C3 8D A5 BE ...
sta $BEB9 ; 15C6 8D B9 BE ...
lda $68 ; 15C9 A5 68 .h
sta $BEA6 ; 15CB 8D A6 BE ...
sta $BEBA ; 15CE 8D BA BE ...
jsr LAD50 ; 15D1 20 50 AD P.
bcs L161F ; 15D4 B0 49 .I
L15D6: lda #$02 ; 15D6 A9 02 ..
ldx #$FC ; 15D8 A2 FC ..
jsr LB1D3 ; 15DA 20 D3 B1 ..
bcs L161F ; 15DD B0 40 .@
lda $AF ; 15DF A5 AF ..
sec ; 15E1 38 8
sbc $67 ; 15E2 E5 67 .g
tax ; 15E4 AA .
sta $BEC8 ; 15E5 8D C8 BE ...
lda $B0 ; 15E8 A5 B0 ..
sbc $68 ; 15EA E5 68 .h
tay ; 15EC A8 .
sta $BEC9 ; 15ED 8D C9 BE ...
lda #$00 ; 15F0 A9 00 ..
sta $BECA ; 15F2 8D CA BE ...
lda $67 ; 15F5 A5 67 .g
sta $BED7 ; 15F7 8D D7 BE ...
lda $68 ; 15FA A5 68 .h
sta $BED8 ; 15FC 8D D8 BE ...
.byte $20 ; 15FF 20
.endif

Binary file not shown.