REM > AP6v130.src REM Source for Updated PRES AP6 ROM Manager and Utilities : ON ERROR REPORT:PRINT" at line ";ERL:END IF PAGE>&8000:SYS "OS_GetEnv"TOA$:IFLEFT$(A$,5)<>"B6502":OSCLI"B6502"+MID$(A$,INSTR(A$," ")) A$=MID$(A$,1+INSTR(A$," ",1+INSTR(A$," ",1+INSTR(A$," ")))) TARGET$="":IFLEFT$(A$,7)="TARGET=":TARGET$=MID$(A$,8) DEFFNif(A%):IFA%:z%=-1:=opt% ELSE z%=P%:=opt% DEFFNendif:IFz%=-1:=opt% ELSE z%=P%-z%:P%=P%-z%:O%=O%-z%:=opt% DEFFNelse:IFz%=-1:z%=P%:=opt% ELSE z%=P%-z%:P%=P%-z%:O%=O%-z%:z%=-1:=opt% : name$="AP6" DIM mcode% &3000,L% -1:load%=&8000 OS_CLI=&FFF7:OSBYTE=&FFF4:OSWORD=&FFF1:OSWRCH=&FFEE OSWRCR=&FFEC:OSNEWL=&FFE7:OSASCI=&FFE3:OSRDCH=&FFE0 OSFILE=&FFDD:OSARGS=&FFDA:OSBGET=&FFD7:OSBPUT=&FFD4 OSGBPB=&FFD1:OSFIND=&FFCE:GSINIT=&FFC2:GSREAD=&FFC5 : IF TARGET$<>"":TARGET%=VALTARGET$ IF TARGET$="":TARGET%=-1:REM Build for 6502Em with no FDC hardware, no real ADFS IF TARGET$="":TARGET%=5 :REM Build for Compact IF TARGET$="":TARGET%=1 :REM Build for BBC B/B+ IF TARGET$="":TARGET%=0 :REM Build for Electron : : ver$="1.29":date$="22 Jan 2016" REM 16-Jan-2016: Removed v1.27 code. REM Uses TIME/CountDown to form random number for FORMAT. REM Doesn't respond if not running on an Electron. REM Moved *FORMAT and *VERIFY workspace to FILEBLK. REM Moved *MOUNT workspace. REM Changed *Help FILE to *Help UTILS. REM *SRLOAD/SAVE/WIPE have generalised ULI options. REM *SRSAVE sets file load/exec to ROM addresses. REM Added *UNPLUG (U) option to mirror *INSERT (I) option. REM 20-Jan-2016: Sideways RAM test compatible with EEPROMs. REM 21-Jan-2016: Double read in RomTest to avoid empty ROM socket floating bus problem. REM 22-Jan-2016: Double read replaced by testing bit 6 after EOR. REM *ROMS doesn't print binary version, just version string. : ver$="1.293":date$="10 Feb 2016" REM 30-Jan-2016: *SRLOAD/*SRWIPE checks type. REM 09-Feb-2016: *SRLOAD/*SRWIPE is able to write to EEPROM. REM 10-Feb-2016: Removed v1.28 code. REM v1.29c: *LANG listed by *Help SRAM. *SRLOAD checks type before attempting REM to load file, ensures lock status remains unchanged if load fails. ver$="1.294":date$="12 Feb 2016" REM v1.29d: *SRSAVE doesn't check if is writable. ver$="1.295":date$="29 Feb 2016" REM v1.29e: ROM check has added NOP to work around Turbo floating bus. : ver$="1.301":date$="01 Mar 2016" REM 01-Mar-2016: Update to version 1.30 for full release REM v1.30a: Extra memory access in SRAM test : : REM Base addresses REM -------------- IF TARGET%<1 :FDCbase=&FCC4:fdcRES=&20:fdcSIDE=&04:ROMSEL=&FE05:ROMtable=&2A0:FILEBLK=&2E2:REM Electron IF TARGET%=1 OR TARGET%=2 :FDCbase=&FE84:fdcRES=&20:fdcSIDE=&04:ROMSEL=&FE30:ROMtable=&2A1:FILEBLK=&2EE:REM BBC IF TARGET%>3 AND TARGET%<6:FDCbase=&FE28:fdcRES=&04:fdcSIDE=&10:ROMSEL=&FE30:ROMtable=&2A1:FILEBLK=&2ED:REM Master IF TARGET%=0:name$="AP6" ELSE name$="SRAM" : REM Workspace REM --------- LAC=&AC:LAE=&AC :REM Command workspace L0D70=&0D70 :REM Saved file vectors L0930=&0930 :REM Base of *FORMAT workspace L09D0=FILEBLK+1:L09EC=FILEBLK+12:REM Base of *VERIFY workspace L0D75=&0D6C:L0D72=&0D6D :REM ROM manager settings L0D74=&0D6E:L0D73=&0D6F :REM UNPLUG bitmap : REM *FORMAT workspace REM ----------------- L093B=FILEBLK+0:L0935=FILEBLK+16:L0936=FILEBLK+17 L0938=FILEBLK+1:L093C=FILEBLK+2:L093F=FILEBLK+3:L093E=FILEBLK+4 L0930=FILEBLK+5:L0932=FILEBLK+6:L0931=FILEBLK+7:L0933=&AB L0939=&AE:L093A=&AF : REM *VERIFY workspace REM ----------------- L09ED=L09EC+1:L09EE=L09EC+2:L09EF=L09EC+3 L09D1=L09D0+1:L09D2=L09D0+2:L09D3=L09D0+3:L09D4=L09D0+4:L09D5=L09D0+5 L09D6=L09D0+6:L09D7=L09D0+7:L09D8=L09D0+8:L09D9=L09D0+9:L09DA=L09D0+&A : REM Workspace REM --------- REM &A8-&AF *commands REM &AB =previous NMI owner REM &AC/D=>formatting data REM &AE/F=>main memory workspace, verify buffer REM REM &0D68-&0D6C Plus 1 Support REM &0D6D-&0D6F ROM Manager Support REM &0D70-&0D7F ROM/TAPE intercept REM REM &0D6D If b7=0 - default language ROM REM &0D6E INSERT/UNPLUG bitmap 0-7, b7=7, 0=inserted, 1=unplugged REM &0D6F INSERT/UNPLUG bitmap 8-15, b7=15, 0=inserted, 1=unplugged : : REM I/O addresses REM ------------- FDCstatus =FDCbase+0 FDCcommand=FDCbase+0 FDCtrack =FDCbase+1 FDCsector =FDCbase+2 FDCdata =FDCbase+3 FDCdrive =FDCbase-4 : REM &FCC0-08 Floppy disk controller REM &FCC0 Drive select register REM &FCC4 FDC command/status REM &FCC7 FDC data REM REM &FCD8/&FCD9 lock/unlock register bank 5/6 REM &FCDA/&FCDB lock/unlock register bank 13/15 REM &FCDC/&FCDD lock/unlock register bank 0/2 REM &FCDE/&FCDF lock/unlock register bank 1/3 REM REM &FCFC AQR paging register REM &FCFD unlock AQR REM &FCFE lock AQR : : file$=name$+"v"+LEFT$(ver$,1)+MID$(ver$,3,2) FOR pass%=0 TO 3 opt%=FNsm_pass(pass%) [OPT opt% \ ******************************** \ Updated ROM Management Functions \ ******************************** .ROMStart EQUB &00:EQUW RelocTable JMP ROMMgrServ EQUB &82:EQUB ROMMgrCopy-ROMStart-1 EQUB EVAL("&"+MID$(ver$,3,2)) EQUS "ROM Manager & Utils":EQUB 0 EQUS LEFT$(ver$,4)+" ("+date$+")":EQUB 0 .ROMMgrCopy EQUS "(C)J.G.Harston":EQUB 0 .ROMMgrServ PHA LDA &0DF0,X:BMI ROMMgrExit :\ Disabled, ignore call PLA:PHA CMP #1:BNE P%+5:JMP Serv1 CMP #4:BNE P%+5:JMP Serv4 CMP #7:BNE P%+5:JMP Serv7 CMP #9:BNE P%+5:JMP Serv9 CMP #&10:BNE P%+5:JMP Serv10 .ROMMgrExit PLA:RTS \ Generate inline error \ ===================== .MkError PLA:STA &FD:PLA:STA &FE LDY #0 .MkErrorLp INY:LDA (&FD),Y:STA &100,Y BNE MkErrorLp STA &100:JMP &100 \ Print inline text \ ================= \ Corrupts A,X,Y \ .PrText PLA:STA &F6:PLA:STA &F7:LDY #1 .PrTextLp LDA (&F6),Y:BEQ PrTextEnd JSR OSASCI:INY:BNE PrTextLp .PrTextEnd CLC:TYA:ADC &F6:TAY LDA #0:ADC &F7:PHA TYA:PHA:RTS \ Print character in Y if MI set or space \ --------------------------------------- .PrCharY BPL PrSpace :\ MI not set, print a space TYA:JMP OSWRCH :\ MI set, print the character \ Print spaces \ ============ .Pr2Spaces JSR PrSpace .PrSpace LDA #ASC" ":JMP OSASCI \ Print line number in &A8/9 \ ========================== .PrLineNumSpc JSR PrLineNum:BCC PrSpace .PrLineNum SED:CLC LDA &A8:ADC #&01:STA &A8 :\ Increment &A8/A9 in decimal mode .LBFE4 LDA &A9:ADC #&00:STA &A9 CLD:JSR PrHex :\ Print high byte LDA &A8 :\ Print low byte : \ Print hex number in A \ ===================== .PrHex PHA:LSR A:LSR A:LSR A LSR A:JSR PrNybble:PLA .PrNybble AND #&0F:CMP #&0A BCC PrDigit:ADC #&06 .PrDigit ADC #&30:JMP OSWRCH \ Print validated character \ ========================= .PrChar AND #&7F CMP #&20:BCC X8C71 CMP #&7F:BCC X8C73 .X8C71 LDA #ASC"." .X8C73 JMP OSWRCH \ Skip spaces \ =========== \ Returns A=non-space character \ CS=more parameters \ CC=no parameters, at .SkipSpaces1 INY .SkipSpaces LDA (&F2),Y:CMP #ASC" " BEQ SkipSpaces1:RTS \ Parse number \ ============ \ Scan for short number \ --------------------- \ Scans for hex or dec 0-15 or 0-F, or \ Returns CC, A=number \ error if empty command line \ .L8C9F JSR L8CA5:BCC L8D00 .errBadNumber JSR MkError:EQUB 252:EQUS "Bad number":BRK \ Scan for optional short number \ ------------------------------ \ Scans for hex or dec 0-15 or 0-F, or \ Returns CC, A=number \ CS, empty command line \ .L8CA5 LDA (&F2),Y CMP #&0D:BEQ ChkNotDigit JSR CheckDigit:BCS errBadNumber CMP #1:BNE ChkDigitOk :\ Not '1', return CC, A=digit LDA (&F2),Y :\ See if it's 10-15 CMP #ASC"!":BCC ChkDigitOne :\ '1' followed by spc/cr, return '1' JSR CheckDigit:BCS errBadNumber ADC #10 :\ Convert 1x to 10-15 CMP #16:BCS errBadNumber :\ 16-19, too big .L8D00 RTS : .ChkDigitOne LDA #ASC"1" .CheckDigit CMP #ASC"0":BCC ChkNotDigit :\ CC=not hex digit CMP #ASC"9"+1:BCC ChkDigit :\ CC=digit CMP #ASC"A":BCC ChkNotDigit :\ CC=not hex digit AND #&DF CMP #ASC"F"+1:BCS ChkNotDigit :\ CS=not hex digit SBC #6 .ChkDigit AND #15:INY :\ Step past digit .ChkDigitOk CLC:RTS :\ CC=ok, A=digit .ChkNotDigit SEC:RTS :\ CS=not ok \ SERVICE 1 - Do Reset processing \ =============================== .Serv1 LDA &028D CMP #&01:BNE Serv1Done :\ Check last Break type TYA:PHA LDY #1:JSR LockUnlockAll :\ If Power on, lock (write protect) all ROMs PLA:TAY .Serv1Done PLA:RTS \ SERVICE 7 - Read/Write configuration settings \ ============================================= .Serv7 LDA &EF CMP #&A1:BEQ Serv7go CMP #&A2:BNE Serv1Done .Serv7go LDX &F0 CPX #5:BCC Serv1Done CPX #8:BCS Serv1Done \ 6 = LANG in b4-b7 \ 7 = unplug bitmap 0-7 \ 8 = unplug bitmap 8-15 LSR A:BCC Serv7Write LDA L0D72-5,X :\ Read configuration setting CPX #5:BNE Serv7RdOk :\ Return unplug bitmap ASL A:ASL A:ASL A:ASL A :\ Move LANG to b4-b7 EOR #&FF .Serv7RdOk EOR #&FF:TAY :\ Return in Y .Serv7Done PLA:LDA #0:RTS :\ Claim and return .Serv7Write TYA:EOR #&FF :\ Toggle unplug bitmap CPX #5:BNE Serv7WrOk LSR A:LSR A:LSR A:LSR A :\ Move LANG to b4-b7 EOR #&FF:AND #&0F :\ Toggle back .Serv7WrOk STA L0D72-5,X:JMP Serv7Done \ SERVICE &10 - Spool/Exec closing \ ================================ \ Insert/Unplug ROMs .Serv10 LDA &028D CMP #&01:BNE X813E :\ Not Power-On, insert/unplug ROMs LDA &024B:STA L0D72 :\ Default language = BASIC PLA:RTS : .X813E LDX #15:LDA L0D73 :\ Unplug bitmap for ROMs 8-15 .Serv10Lp1 CPX #7:BNE Serv10a LDA L0D74 :\ Unplug bitmap for ROMs 0-7 .Serv10a ROL A:BCC Serv10Next :\ Leave inserted PHA:LDA #0:STA ROMtable,X:PLA :\ Remove from ROM table .Serv10Next DEX:BPL Serv10Lp1 :\ Loop down to ROM 0 .Serv10Done LDX &F4:PLA:RTS \ SERVICE 4 - *command \ ==================== \ Only ever passed commands starting with a letter .Serv4 LDA (&F2),Y:AND #&DF CMP #ASC"P":BNE Serv4Go :\ Command prefixed by 'P'? INY:JSR Serv4Prefix:DEY :\ Check for prefixed command TAX:BNE Serv10Done :\ Not recognised, return unclaimed PLA:TXA:RTS :\ Recognised, claim and return .Serv4Prefix PHA .Serv4Go LDX #cmdFILE-cmdBase :\ Point to command table .Serv4a TYA:PHA :\ Save start of command line .CmdLookNext PLA:PHA:TAY :\ Get text offset back .CmdLookLp LDA (&F2),Y:CMP #ASC".":BEQ CmdMatchDot CMP cmdBase,X:BEQ CmdLook2 AND #&DF:CMP cmdBase,X:BNE CmdNoMatch .CmdLook2 INX:INY :\ Step to next character LDA cmdBase,X:BPL CmdLookLp :\ Not a full command LDA (&F2),Y :\ Get following character CMP #ASC"A":BCS CmdCheckNext:\ Ensure command ends with non-alpha .CmdFoundSpc JSR SkipSpaces :\ Move past any spaces PLA:STA &F5:PLA :\ Get saved Y and A CMP #9:BEQ HelpDispatch :\ Do *Help JSR CmdDispatch:LDA #0:RTS :\ Call command, claim call .CmdDispatch LDA cmdBase+2,X:PHA :\ Get command address LDA cmdBase+1,X:PHA LDA #0:RTS :\ Jump to routine via stack \ On entry to routines, \ A=0, (&F2),Y=>command line, skipped past any spaces : .CmdMatchDot LDA cmdBase,X :\ Is there still more name to match? BMI CmdCheckNext :\ End of name, the dot is after end of command name INY :\ Step past '.' .CmdMatchDotLp INX:LDA cmdBase,X BPL CmdMatchDotLp :\ Find end of table entry BMI CmdFoundSpc :\ Jump to enter command : .CmdNoMatch INX:LDA cmdBase,X BPL CmdNoMatch :\ Find end of table entry .CmdCheckNext INX:INX:INX LDA cmdBase,X BPL CmdLookNext :\ Loop until table terminator found INX:ASL A:BPL CmdLookNext :\ Not end of final table JMP ServQuit \ SERVICE 9 - *Help \ ================= .Serv9 LDA (&F2),Y:CMP #13:BEQ HelpShort CMP #ASC".":BEQ HelpLong LDX #cmdHELP-cmdBase JMP Serv4a .HelpShort TYA:PHA SEC:JSR PrintHelpTitleLong LDX #cmdHELP-cmdBase LDY #hlpHELP-hlpBase JSR HelpLp1 .ServQuit PLA:TAY:LDX &F4:PLA:RTS : .HelpLong STY &F5:PLA :\ Get A and Y ready for later LDX #(cmdFILEhlp-cmdHELP-1)AND255 :\ Do *Help FILE JSR HelpDispatch LDX #(cmdSRAMhlp-cmdHELP-1)AND255 :\ Do *Help SRAM .HelpDispatch PHA:LDA &F5:PHA :\ Save Y and A again LDY cmdBase+2,X :\ Index to help strings LDA cmdBase+1,X:TAX :\ Index to command strings BEQ HelpSpecial JSR HelpPrint JMP ServQuit : : \ *Help +1 .HelpSpecial SEC:JSR PrintHelpTitleLong LDX #0 .HelpPlus1Lp TXA:PHA LDA idxPlus1+1,X:TAY LDA idxPlus1+0,X:TAX JSR HelpPrCmd PLA:TAX:INX:INX LDA idxPlus1,X BNE HelpPlus1Lp BEQ ServQuit : .HelpPrint JSR PrintHelpTitle JSR OSNEWL .HelpLp1 JSR HelpPrCmd INX:INX:INX LDA cmdBase,X BPL HelpLp1:RTS : .HelpPrCmd JSR Pr2Spaces .HelpPrLp1 LDA cmdBase,X:BMI HelpPrSyntax JSR OSWRCH:INX:BNE HelpPrLp1 .HelpPrSyntax .HelpPrLpSpc JSR PrSpace SEC:LDA &318:SBC &308:SBC #12 BCC HelpPrLpSpc .HelpLp2 LDA hlpBase,Y:JSR OSASCI INY:CMP #13:BNE HelpLp2 RTS : .PrintHelpTitle CLC .PrintHelpTitleLong TYA:PHA:TXA:PHA PHP:JSR PrText:EQUB 13 OPT FNif(TARGET%=0) \EQUS "RetroHardware Plus 1/AP6 "+LEFT$(ver$,4) EQUS "RetroHardware Plus 1 Support "+LEFT$(ver$,4) OPT FNelse EQUS "ROM Manager and Utilities "+LEFT$(ver$,4) OPT FNendif OPT FNif(LENver$>4):EQUB 96+VALRIGHT$(ver$,1):OPT FNendif EQUB 0 PLP:BCC PrHelpTitleDone OPT FNif(TARGET%=0) LDA &30A:SBC &308:SBC #47:BCC PrHelpTitleDone1 JSR PrText EQUS " (ADC/Printer/RS423)" EQUB 0 OPT FNendif .PrHelpTitleDone1 JSR OSNEWL .PrHelpTitleDone PLA:TAX:PLA:TAY RTS : \ Command tables \ *Help lists until bit 7 set \ *command lookup searches until &FF terminator \ So, commands between &80 and &FF are executed but not listed \ .cmdBase .cmdHELP OPT FNif(TARGET%=0) EQUS "+1" :EQUB &80: EQUB 0 :EQUB 0 OPT FNendif EQUS "SRAM" :EQUB &80:.cmdSRAMhlp:EQUB cmdSRAM-cmdBase:EQUB hlpSRAM-hlpBase EQUS "UTILS":EQUB &80:.cmdFILEhlp:EQUB cmdFILE-cmdBase:EQUB hlpFILE-hlpBase EQUB &80 EQUS "SROM" :EQUB &80: EQUB cmdSRAM-cmdBase:EQUB hlpSRAM-hlpBase EQUB &FF : .cmdFILE .cmdBUILD :EQUS "BUILD" :EQUB &80:EQUW BUILD-1 .cmdDUMP :EQUS "DUMP" :EQUB &80:EQUW DUMP-1 .cmdFORMAT :EQUS "FORMAT" :EQUB &80:EQUW AFORMAT-1 .cmdLIST :EQUS "LIST" :EQUB &80:EQUW FLIST-1 .cmdTYPE :EQUS "TYPE" :EQUB &80:EQUW TYPE-1 .cmdVERIFY :EQUS "VERIFY" :EQUB &80:EQUW VERIFY-1 EQUB &80 : .cmdSRAM .cmdINSERT :EQUS "INSERT" :EQUB &80:EQUW INSERT-1 .cmdLANG :EQUS "LANG" :EQUB &80:EQUW LANG-1 OPT FNif(TARGET%=0) .cmdLROMS :EQUS "LROMS" :EQUB &80:EQUW LROMS-1 OPT FNendif .cmdROMS :EQUS "ROMS" :EQUB &80:EQUW ROMS-1 .cmdSRLOAD :EQUS "SRLOAD" :EQUB &80:EQUW SRLOAD-1 OPT FNif(TARGET%=0) .cmdSRLOCK :EQUS "SRLOCK" :EQUB &80:EQUW SRLOCK-1 OPT FNendif .cmdSRSAVE :EQUS "SRSAVE" :EQUB &80:EQUW SRSAVE-1 OPT FNif(TARGET%=0) .cmdSRUNLOCK:EQUS "SRUNLOCK":EQUB &80:EQUW SRUNLOCK-1 OPT FNendif .cmdSRWIPE :EQUS "SRWIPE" :EQUB &80:EQUW SRWIPE-1 .cmdUNPLUG :EQUS "UNPLUG" :EQUB &80:EQUW UNPLUG-1 OPT FNif(TARGET%=0) .cmdUROMS :EQUS "UROMS" :EQUB &80:EQUW UROMS-1 OPT FNendif EQUB &80 : .cmdPlus1 .cmdAQRPAGE :EQUS "AQRPAGE":EQUB &80:EQUW L8D24-1 .cmdLOADROM :EQUS "LOADROM":EQUB &80:EQUW SRLOAD-1 .cmdLOCK :EQUS "LOCK" :EQUB &80:EQUW SRLOCK-1 .cmdRLOAD :EQUS "RLOAD" :EQUB &80:EQUW SRLOAD-1 .cmdRSAVE :EQUS "RSAVE" :EQUB &80:EQUW SRSAVE-1 .cmdSAVEROM :EQUS "SAVEROM":EQUB &80:EQUW SRSAVE-1 .cmdUNLOCK :EQUS "UNLOCK" :EQUB &80:EQUW SRUNLOCK-1 .cmdZERO :EQUS "ZERO" :EQUB &80:EQUW SRWIPE-1 EQUB &FF ]:IF P%-cmdBase>255:P."WARNING: Command table too long" [OPT opt% : .idxPlus1 EQUB cmdAQRPAGE-cmdBase:EQUB hlpAQRPAGE-hlpBase EQUB cmdBUILD -cmdBase:EQUB hlpBUILD -hlpBase EQUB cmdDUMP -cmdBase:EQUB hlpDUMP -hlpBase EQUB cmdFORMAT -cmdBase:EQUB hlpFORMAT -hlpBase EQUB cmdINSERT -cmdBase:EQUB hlpINSERT -hlpBase EQUB cmdLANG -cmdBase:EQUB hlpLANG -hlpBase EQUB cmdLIST -cmdBase:EQUB hlpLIST -hlpBase EQUB cmdLOADROM-cmdBase:EQUB hlpLOADROM-hlpBase EQUB cmdLOCK -cmdBase:EQUB hlpLOCK -hlpBase EQUB cmdLROMS -cmdBase:EQUB hlpLROMS -hlpBase EQUB cmdRLOAD -cmdBase:EQUB hlpRLOAD -hlpBase EQUB cmdRSAVE -cmdBase:EQUB hlpRSAVE -hlpBase EQUB cmdROMS -cmdBase:EQUB hlpROMS -hlpBase EQUB cmdSAVEROM-cmdBase:EQUB hlpSAVEROM-hlpBase EQUB cmdTYPE -cmdBase:EQUB hlpTYPE -hlpBase EQUB cmdUNLOCK -cmdBase:EQUB hlpUNLOCK -hlpBase EQUB cmdUNPLUG -cmdBase:EQUB hlpUNPLUG -hlpBase EQUB cmdUROMS -cmdBase:EQUB hlpUROMS -hlpBase EQUB cmdVERIFY -cmdBase:EQUB hlpVERIFY -hlpBase EQUB cmdZERO -cmdBase:EQUB hlpZERO -hlpBase EQUB &00 : .hlpBase .hlpFILE .hlpBUILD :EQUS "":EQUB 13 .hlpDUMP :EQUS "":EQUB 13 .hlpFORMAT :EQUS " (Y)":EQUB 13 .hlpLIST :EQUS "":EQUB 13 .hlpTYPE :EQUS "":EQUB 13 .hlpVERIFY :EQUS "":EQUB 13 : .hlpSRAM .hlpINSERT :EQUS "( (I))":EQUB 13 .hlpLANG :EQUS "()":EQUB 13 OPT FNif(TARGET%=0) .hlpLROMS :EQUS "":EQUB 13 OPT FNendif .hlpROMS :EQUS "":EQUB 13 .hlpLOADROM .hlpRLOAD OPT FNif(TARGET%=0) .hlpSRLOAD :EQUS " (U)(L)(I)":EQUB 13 OPT FNelse .hlpSRLOAD :EQUS " (I)":EQUB 13 OPT FNendif OPT FNif(TARGET%=0) .hlpLOCK .hlpSRLOCK :EQUS "()":EQUB 13 OPT FNendif .hlpSAVEROM .hlpRSAVE .hlpSRSAVE :EQUS " ":EQUB 13 OPT FNif(TARGET%=0) .hlpUNLOCK .hlpSRUNLOCK:EQUS "()":EQUB 13 OPT FNendif .hlpZERO OPT FNif(TARGET%=0) .hlpSRWIPE :EQUS " (U)(L)":EQUB 13 OPT FNelse .hlpSRWIPE :EQUS "":EQUB 13 OPT FNendif .hlpUNPLUG :EQUS "( (U))":EQUB 13 .hlpKILL OPT FNif(TARGET%=0) .hlpUROMS :EQUS "":EQUB 13 OPT FNendif .hlpHELP :EQUB 13:EQUB 13:EQUB 13 .hlpAQRPAGE :EQUS "":EQUB 13 \ ************* \ FILE COMMANDS \ ************* \ Workspace for UTILS commands \ &A8/9=line number \ &AA =CR/LF flag, BUILD handle \ &AB =type/list flag, dump EOF, OSWORD 0 addr.lo \ &AC = dump count, OSWORD 0 addr.hi \ &AD dump width, OSWORD 0 length \ &AE OSWORD 0 min \ &AF OSWORD 0 max \ \ *LIST \ ============ .FLIST LDA #&FF :\ &FF=LIST \ *TYPE \ ============ .TYPE :\ Entered with &00=TYPE STA &AB:JSR OpeninFile :\ Save list type, open file LDX #0:BEQ type7 :\ Jump into loop : \ Type/List characters from file \ ------------------------------ .type1 CLC:PHP:TAX:JSR OSWRCH:PLP .type2 PHP:JSR OSBGET:BCS typeEOF :\ End of file BIT &FF:BMI LBEED :\ Escape pressed PLP:BCC type3 PHA:JSR PrLineNumSpc:PLA .type3 CMP #10:BEQ type4:CMP #13:BNE type1 .type4 CPX #10:BEQ type5:CPX #13:BNE type6 .type5 STX &AA:CMP &AA:CLC:BNE type2 .type6 TAX:JSR OSNEWL .type7 LDA &AB:LSR A:BPL type2 .typeEOF LDA &318:BEQ type10:JSR OSNEWL .type10 PLP .LBEDA LDA #&00:JMP OSFIND \ *DUMP \ ================ .DUMP JSR OpeninFile LDA &30A:SBC &308 :\ Text window width SBC #4:LSR A:LSR A:AND #&1C CMP #4:BCS P%+4:LDA #3 STA &AD : \ Dump a line from file \ --------------------- .LBEED BIT &FF:BMI LBF56 :\ Escape pressed, tidy up and quit CLC:JSR LBFE4 :\ Print file offset JSR PrSpace :\ Print space TSX:TXA:SEC:SBC &AD:TAX:TXS :\ Claim bytes on stack LDA &AD:STA &AC :\ Number of bytes to dump : \ Dump 8 bytes as hex \ ------------------- .LBF04 JSR OSBGET:BCS LBF16 STA &101,X JSR PrHex:JSR PrSpace :\ Print hex, space INX:DEC &AC:BNE LBF04 CLC:BEQ LBF2C : \ EOF met, pad with '**' \ ---------------------- .LBF16 LDA #ASC"*":JSR OSWRCH JSR OSWRCH:JSR PrSpace LDA #&00:STA &101,X INX:DEC &AC:BNE LBF16 SEC : \ Dump as characters \ ------------------ .LBF2C ROR &AB :\ Save EOF flag in bit 7 LDX &AD:TXA :\ Number of bytes to display CLC:ADC &A8:STA &A8 :\ Update offset BCC LBF30:INC &A9 .LBF30 PLA:JSR PrChar :\ Print printable character DEX:BNE LBF30 JSR OSNEWL ROL &AB :\ Check EOF flag .DumpEOF BCS LBEDA :\ Close and finish TYA:PHA:TAX :\ Save handle, X=handle LDA #127:JSR OSBYTE :\ Read EOF PLA:TAY :\ Get handle back CPX #1:BCC LBEED :\ Not at EOF, loop for more BCS DumpEOF :\ At EOF, close and finish : \ Escape pressed \ -------------- .LBF56 JSR LBEDA :\ Close file .errEscape JSR L97B2 :\ Acknowledge Escape JSR MkError:EQUB 17:EQUS "Escape":BRK \ *BUILD \ ============= .BUILD LDA #&80:JSR OpenFile :\ Open file for output STA &AA : \ Get a line of input \ ------------------- .LBF69 JSR PrLineNumSpc LDA #ASC" ":STA &AE TSX:TXA:SBC #&40:STA &AD LDY #&FF:STY &AF INY:STY &AB INY:STY &AC DEY:TYA:LDX #&AB JSR OSWORD:BCS LBF56 LDX #0:LDY &AA .LBF8E LDA &100,X:JSR OSBPUT INX:CMP #13:BNE LBF8E BEQ LBF69 : .OpeninFile LDA #&40 :\ &40=OPENIN .OpenFile PHA LDA #&00:STA &A8:STA &A9 :\ Line number=0 TYA:CLC:ADC &F2:TAX :\ Convert (&F2),Y to XY LDA &F3:ADC #&00:TAY PLA:JSR OSFIND :\ Open file TAY:BNE OpenFileOk :\ File found .errFileNotFound JSR MkError:EQUB 214:EQUS "File not found":BRK \ ******************** \ ROM Manager Commands \ ******************** \ *LROMS \ ====== .LROMS LDA #1 :\ A=1 to lock : \ *UROMS \ ====== .UROMS :\ Entered with A=0 to unlock TAY:JSR LockUnlockAll :\ Lock/unlock all ROMs :\ Drop through to *ROMS : \ *ROMS \ ===== .ROMS LDX #&0F:STX &F5 :\ Start at ROM 15 .L8C22 LDX &F5:JSR PrRomInfo :\ Display info for ROM X BCS L8C2D:JSR OSNEWL .L8C2D DEC &F5:BPL L8C22 .OpenFileOk RTS \ *LANG () \ ============= \ Updates: \ Doesn't enter selected language, just configures it. \ If no , no default, allows MOS to select default .LANG JSR L8CA5 :\ Scan for ROM number LDX #&FF:BCS L8C97 :\ No , set no default TAX:LDA ROMtable,X :\ Check ROM table ROL A:BMI L8C93 :\ ROM contains a language .L8C80 JSR MkError:EQUB 249:EQUS "Not a language":BRK .L8C93 .L8C97 STX L0D72:RTS :\ Set as default language \ Is ROM X unplugged? \ ------------------- \ On exit, CC=ROM is inserted \ CS=ROM is unplugged .L8D07 JSR XtoBitmap:BCS L8D1A :\ Jump for ROM 8-15 AND L0D74:BCC L8D1D :\ Mask with bitmap for 0-7 .L8D1A AND L0D73 :\ Mask with bitmap for 8-15 .L8D1D CMP #1:RTS :\ CC=inserted, CS=unplugged .XtoBitmap TXA:CMP #8:AND #7:TAX LDA Bitmap,X:RTS .Bitmap EQUB &01:EQUB &02:EQUB &04:EQUB &08 EQUB &10:EQUB &20:EQUB &40:EQUB &80 \ *AQRPAGE \ =============== .L8D24 JSR L8C9F :\ Scan for a short hex number PHP:SEI:STA &FCFC :\ Stop IRQs, set paging register LDX #&0F :\ Rebuild ROM table .AQRlp STX &F5:JSR L8D07 :\ Is it unplugged? .AQRunplugged LDA #0:BCS AQRstore :\ Clear ROM table byte LDX &F5 JSR ChkRomHeader :\ Is there a ROM in this bank? BCS AQRunplugged :\ No header, clear ROM table byte .AQRstore LDX &F5:STA ROMtable,X :\ Store in ROM table DEX:BPL AQRlp :\ Step through all ROMs PLP:RTS :\ Restore IRQs and return \ *INSERT () (I) \ =================== \ Updates: \ It is not an error to INSERT an inserted ROM. \ Only inserts into ROM table if has a ROM header and (I) option. \ Action is silent, no 'Press BREAK' message displayed. \ .INSERT JSR L8CA5:BCS L8D94 :\ No given, insert all ROMs TAX:JSR SkipSpaces:PHA :\ Look for any 'I' option TXA:PHA:JSR InsertRom :\ Insert this ROM PLA:TAX:PLA:AND #&DF :\ X=, A=(I) CMP #ASC"I":BNE InsertDone STX &F5:JSR ChkRomHeader LDX &F5:STA ROMtable,X .InsertDone RTS : \ *INSERT - insert all ROMs \ ------------------------------ .L8D94 LDX #&0F :\ Start at ROM 15 .L8D96 TXA:PHA JSR L8D07:BCC L8DA8 :\ Already inserted, skip PLA:TAX:PHA JSR L9030:BCS L8DA8 :\ Prompt 'Y/N', skip if 'N' JSR InsertRom :\ Insert this ROM .L8DA8 PLA:TAX DEX:BPL L8D96:RTS :\ Loop down from 15 to 0 \ *UNPLUG () (U) \ =================== \ Updates: \ It is not an error to UNPLUG an unplugged ROM. \ It is not an error to UNPLUG an empty ROM. \ It is not an error to UNPLUG the default language. \ It is not an error to UNPLUG the AP6 ROM. \ Does not remove from ROM table (that happens after Break). \ Action is silent, no 'Press BREAK' message displayed. \ .UNPLUG JSR L8CA5 BCS L8E1D :\ No given, unplug all ROMs TAX:JSR SkipSpaces:PHA :\ Look for any 'U' option TXA:PHA LDY #&FF:JSR InsertUnplug :\ Unplug this ROM PLA:TAX:PLA:AND #&DF :\ X=, A=(U) CMP #ASC"U":BNE UnplugDone LDA #0:STA ROMtable,X :\ Remove from ROM table .UnplugDone RTS : \ *UNPLUG - unplug all ROMs \ ------------------------------ .L8E1D LDX #&0F :\ Start at ROM 15 .L8E1F LDA ROMtable,X:BEQ L8E3E :\ If ROM table empty, skip JSR L9030:BCS L8E3E :\ Prompt 'Y/N', skip if 'No' TXA:PHA LDY #&FF:JSR InsertUnplug :\ Add to UNPLUG bitmap PLA:TAX .L8E3E DEX:BPL L8E1F:RTS :\ Loop down from 15 to 0 .InsertRom LDY #0 : \ Insert or Unplug ROM \ -------------------- \ A=ROM, Y=&FF, unplug ROM \ A=ROM, Y=&00, insert ROM \ .InsertUnplug TAX:JSR XtoBitmap :\ A=2^n, CC=0-7, CS=8-15 INY:BNE InsertThisRom :\ Y was &00, jump to insert BCC P%+3:INY ORA L0D74,Y:STA L0D74,Y :\ Store into bitmap RTS .InsertThisRom EOR #&FF:BCS P%+3:DEY AND L0D74,Y:STA L0D74,Y :\ Store into bitmap RTS \ Updates: \ *LOCK/*UNLOCK use the same code \ Full list of lock ports for ROMs 0-15 \ \ *SRLOCK () \ =============== .SRLOCK LDA #1 :\ A=1 to lock : \ *SRUNLOCK () \ ================= .SRUNLOCK :\ Entered with A=0 to unlock PHA:JSR L8CA5:TAX :\ Save lock/unlock flag, scan to X PLA:TAY :\ Y=lock/unlock flag BCC LockUnlockROM :\ given, lock/unlock that ROM : \ Lock/Unlock all ROMs, Y=lock/unlock \ ----------------------------------- .LockUnlockAll LDX #15 .LockUnlockLp TXA:PHA:JSR LockUnlockROM PLA:TAX:DEX:BPL LockUnlockLp RTS \ Lock/Unlock ROM X, Y=0 unlock, Y=1 lock \ --------------------------------------- .LockUnlockROM TYA .LockUnlockROM1 EOR LockAddrs,X :\ Get lock address for this ROM BPL LockUnlockDone :\ <&80=no lock register TAX:STA &FC00,X :\ write to lock register .LockUnlockDone RTS .LockAddrs EQUB &DC:EQUB &DE:EQUB &DC:EQUB &DE :\ 0,1,2,3 EQUB &00:EQUB &D8:EQUB &D8:EQUB &00 :\ 4,5,6,7 EQUB &00:EQUB &00:EQUB &00:EQUB &00 :\ 8,9,10,11 EQUB &00:EQUB &DA:EQUB &00:EQUB &DA :\ 12,13,14,15 \ Print character in A in inverted colours \ ---------------------------------------- .L9002 PHA LDA #&00:JSR L9018 :\ COLOUR 0 LDA #&87:JSR L9018 :\ COLOUR 128+7 PLA:JSR OSWRCH LDA #&07:JSR L9018 :\ COLOUR 7 LDA #&80 :\ COLOUR 128+0 .L9018 PHA LDA #&11:JSR OSWRCH :\ VDU 17 - COLOUR PLA:JMP OSWRCH :\ Colour number \ Display ROM info and Prompt Y/N \ ------------------------------- .L9030 TXA:PHA:JSR PrRomInfo :\ Print information on ROM X LDA #8:JSR OSWRCH PLA:TAX : \ Prompt Y/N \ ---------- .L9035 TXA:PHA JSR PrText:EQUS "? Y/N":EQUB 0 .L903F JSR OSRDCH:BCS X9027 :\ Escape AND #&DF CMP #ASC"Y":BEQ L9056 CMP #ASC"N":BNE L903F .L9056 PHA:JSR PrText:EQUB 127:EQUB 127:EQUB 127:EQUB 0 PLA:PHA JSR OSWRCH:JSR OSNEWL PLA:EOR #1:LSR A :\ CS='N', CC='Y' PLA:TAX:RTS .X9027 JMP errEscape :\ Jump to Escape error \ Print ROM X information \ ======================= \ Updates: \ Doesn't try to display information on empty ROMs \ Displays unplugged ROMs so *INSERT gets all ROMs \ .PrRomInfo STX &F5 JSR ChkRomHeader :\ CLC=Ok, A=type; SEC=empty PHA:PHP :\ stack => romtype, header OPT FNif(TARGET%=0) CMP #&60:BNE RomInfo0 :\ ROM is not BASIC LDX &F5:CPX #10:BNE RomInfo0 :\ Not ROM 10 is not BASIC PLP:BCC RomInfoDup:PHP :\ ROM 10 is BASIC, duplicate of ROM 11 .RomInfo0 OPT FNendif JSR RomTest :\ Y=&00 for ROM, 'R' for RAM, 'E' for EEPROM PLP:BCC PrRomInfo1 :\ CLC, ROM header exists TYA:BNE PrRomInfo1 :\ Y<>0, SRAM .RomInfoDup PLA:SEC:RTS :\ No ROM header, no SRAM \ stack=> romtype, Cy=ROM header, Y=SRAM .PrRomInfo1 PLA:TAX :\ X=romtype, Cy=header, Y=sram PHP :\ stack => header TYA:PHA :\ stack => sram, header TXA:PHA :\ stack => romtype, sram, header : JSR PrText:EQUS "ROM ":EQUB 0 LDX &F5:TXA:JSR PrNybble JSR PrSpace CPX L0D72:BNE RomInfo3 :\ Not default language LDA #ASC"*":JSR L9002 :\ Print inverted '*' BNE RomInfo4 .RomInfo3 LDA #ASC":":JSR OSWRCH .RomInfo4 JSR PrText:EQUS " (":EQUB 0 JSR L8D07:BCC RomInfo5 :\ Not unplugged PLA:LDA #ASC"U":JSR L9002 :\ Print inverted 'U' JSR PrSpace:BNE RomInfo6 .RomInfo5 LDY #ASC"S":PLA:PHA:JSR PrCharY LDY #ASC"L":PLA:ASL A:JSR PrCharY .RomInfo6 PLA:BEQ RomInfo7 :\ ROM JSR L9002:BNE RomInfo8 :\ Print inverted 'R' or 'E' .RomInfo7 JSR PrSpace .RomInfo8 JSR PrText:EQUS ") ":EQUB 0 PLP:BCS L917C :\ No ROM header present : LDA #&08:STA &F6 :\ Point to before ROM title at &8009 LDA #&80:STA &F7 .L914A JSR RdRomNext :\ Read next byte from ROM CMP #&00 BNE P%+4:LDA #ASC" " :\ Convert &00 to space CMP #ASC" ":BCC L914A :\ Control code - skip CMP #ASC"(":BEQ L917C :\ End display at (C) string .L915C LDY &0318:BNE L916D :\ X position>0, skip padding PHA:LDY #13:LDA #ASC" " .L9166 JSR OSWRCH :\ Print 16 spaces DEY:BPL L9166:PLA .L916D JSR OSWRCH :\ Print character .L9170 JMP L914A .L917C CLC:RTS :\ CLC=occupied or empty+sram/eeprom .ChkRomHeader LDA #&05:STA &F6 :\ Point to before ROM type byte &8006 JSR RdRom80:PHA :\ Save ROM type byte JSR RdRomNext :\ Get copyright offset from &8007 STA &F6:JSR RdRom CMP #&00:BNE ChkRomHdrDone JSR RdRomNext CMP #ASC"(":BNE ChkRomHdrDone JSR RdRomNext CMP #ASC"C":BNE ChkRomHdrDone JSR RdRomNext CMP #ASC")":BNE ChkRomHdrDone PLA:CLC:RTS :\ CLC=ok, A=ROM type .ChkRomHdrDone PLA:LDA #0 :\ Fake ROM type to be &00 SEC:RTS :\ SEC=no header .RdRom80 LDA #&80:STA &F7 .RdRomNext INC &F6 .RdRom LDY &F5:JMP &FFB9 \ *************************** \ ROM load/save/wipe commands \ *************************** \ *SAVEROM \ *RSAVE \ *SRSAVE \ *RLOAD (I) (L) (P) (Q) (R) (U) \ *LOADROM (I) (L) (P) (Q) (R) (U) \ *SRLOAD (I) (L) (P) (Q) (R) (U) \ *ZERO (I) (L) (P) (Q) (R) (U) \ *SRWIPE (I) (L) (P) (Q) (R) (U) \ =========================================== \ parameters not implemented \ \ *SRWIPE (U) (L) \ ===================== .SRWIPE LDA #&40:PHA :\ Stack JSR L8C9F:TAX :\ Scan CLC:BCC srWipeRom :\ CLC=write zeros .srSyntax JSR MkError:EQUB 204:EQUS "Bad filename":BRK .errRomLocked JSR MkError:EQUB 135:EQUS "Bank not writable":BRK .SRLOAD LDA #&FF :\ &FF=load .SRSAVE :\ Enters with &00=save PHA:TYA:CLC :\ Save load/save flag ADC &F2:STA FILEBLK+0 :\ Point to filename LDA #0 ADC &F3:STA FILEBLK+1 CLC:JSR GSINIT :\ Use GSREAD to step past filename BEQ srSyntax :\ No parameters .srskip JSR GSREAD:BCC srskip :\ Step past filename JSR SkipSpaces :\ Now pointing to or .srgetrom JSR L8C9F:TAX :\ Scan .srgetplus JSR SkipSpaces JSR CheckDigit DEY:BCC srgetrom :\ Another digit, keep reading as INY:INY:CMP #ASC"+" BEQ srgetplus:DEY :\ Step past '+' as well .srWipeRom TXA:PHA:PHA :\ Stack padding for , stack : \ Now pointing to any trailing options or DEY:JSR srOptions :\ Scan trailing options TSX:STA &102,X :\ Save options on stack \ \ Stack holds , , <&FF=load/&00=save/&40=wipe> \ \ Check if is writable before we change MODE or attempt to load file ASL A :\ Move (U)nlock option to Carry LDA &103,X :\ Get action BEQ srPrecheck3 :\ &00=save, don't check if writable PLA:PHA:STA &F5 :\ Set &F5= PHP:BCC srPrecheck1 :\ No (U)nlock option TAX:LDY #0 :\ X=, Y=unlock JSR LockUnlockROM :\ Unlock this ROM .srPrecheck1 JSR RomTest :\ Check ROM type DEY:BMI errRomLocked:\ Not SRAM or EEPROM PLP:BCC srPrecheck2 :\ Wasn't (U)nlocked, so don't relock LDX &F5:LDA #1 :\ X=, A=lock JSR LockUnlockROM1 :\ Relock this ROM .srPrecheck2 TSX : LDA &103,X :\ Get load/save/wipe action .srPrecheck3 PHA:CMP #&40:BEQ P%+5 :\ Skip if *Wipe JSR CheckMode6 :\ Force to MODE 6 : LDX #&80:LDY #&20 :\ Prepare for copy &8000->&2000 PLA:SEC:BEQ srCopyData :\ Jump forward with &00=save CLC:BPL srWriteRom :\ Jump forward with <&80=wipe JSR srFile:SEC :\ Load , SEC=Copy data \ Note, assume we lose &F5 through external call to OSFILE \ .srWriteRom PLA:TAX:STX &F5 :\ X=ROM, also save in &F5 LDA #0:STA ROMtable,X :\ Remove from ROM table before overwriting TAY:PLA:PHA :\ Y=0, check options BPL srWriteNoUnlock :\ b7=0, don't unlock PHP:JSR LockUnlockROM:PLP :\ Unlock this ROM, preserving Carry .srWriteNoUnlock LDX #&20:LDY #&80 :\ Prepare for copy &2000->&8000 LDA &F5:PHA :\ Get ROM number back .srCopyData PLA:JSR RomCopy :\ Copy data to/from selected \ \ Stack now holds , \ PLA:ASL A:PHA:BPL srNoLock :\ b6=0, don't lock LDX &F5:LDA #1 JSR LockUnlockROM1 :\ Lock this ROM .srNoLock PLA:ASL A:BPL srNoInsert :\ b5=0, don't insert JSR ChkRomHeader:BCS srNoInsert LDX &F5:STA ROMtable,X :\ Store ROM type if valid header .srNoInsert PLA:BEQ srFile :\ A=, if &00, save copied ROM data .srDone RTS : .srFile PHA:LDX #15 .srFileLp LDA srBlock,X:STA FILEBLK+2,X DEX:BPL srFileLp PLA:PHA:BMI srFileGo :\ Jump to do Load LDA #&80:STA FILEBLK+3 :\ Load address=&FFFF8000 LDA &2006 :\ Get ROM type byte ASL A:BPL srFileNoLang :\ No language SEC:LDY #2 :\ Prepare for no reloc address AND #&40:BEQ srsavelp2 :\ No relocation address, use &00008000 LDX &2007 :\ Offset to (C) .srsavelp1 INX:LDA &2000,X:BNE srsavelp1 :\ Step past (C) message CLC:LDY #0 .srsavelp2 BCS P%+5:LDA &2001,X :\ Get Tube address STA FILEBLK+2,Y:STA FILEBLK+6,Y :\ Copy to control block INX:INY:TYA:AND #4:BEQ srsavelp2 .srFileNoLang .srFileGo LDX #FILEBLK AND 255 LDY #FILEBLK DIV 256 PLA:JMP OSFILE .srBlock EQUD &FFFF2000 EQUD &FFFF8000 :\ Low byte=&00 for load to address EQUD &FFFF2000 EQUD &FFFF6000 : \ Scan SRAM command options \ ------------------------- \ (F2),Y=>any trailing options or .srOptions LDA #0:PHA :\ Stack 'no options' LDA (&F2),Y :\ Get first option .OptionLp1 :\ will fall through and set b0 AND #&DF:LDX #7 .OptionLp2 CMP Options,X:BEQ OptionMatch DEX:BNE OptionLp2 .OptionMatch PLA:ORA Bitmap,X:PHA JSR SkipSpaces1 CMP #13:BNE OptionLp1 PLA:RTS :\ Return A= .Options EQUS "....QILU" : \ Test if ROM in &F5 is SRAM \ -------------------------- .RomTest LDA #RomTestEnd-RomTestStart :\ Length of stacked code LDY #(RomTestEnd-RomCopyStart-1)AND255 :\ Offset to end of stacked code BNE StackCopySetup :\ Jump to stack it and call it : \ Copy between main RAM and SROM/SRAM \ ----------------------------------- .RomCopy \ CC=zero data, CS=copy data \ X=source page, Y=dest page, A=rom STA &F5 :\ ROM to copy to/from STX &A9:STY &AB :\ Set source and dest LDA #&40:STA &AC :\ Number of pages to copy LDA #RomCopyEnd-RomCopyStart :\ Length of stacked code LDY #(RomCopyEnd-RomCopyStart-1)AND255 :\ Offset to end of stacked code .StackCopySetup TSX:STX &AA :\ Save old stack pointer TAX :\ X=length of code to stack PHP:SEC:SBC #9:STA &A8:PLP :\ Save offset to RomSelect code .StackCopyLp LDA RomCopyStart,Y:PHA :\ Copy code to stack DEY:DEX:BNE StackCopyLp LDA &AA:PHA :\ Stack old stack pointer TSX :\ X=>entry address on stack PHP:TXA:CLC:ADC &A8:PLP :\ Calculate address of RomSelect code STA &104,X :\ Adjust JSR destination PHP:SEI :\ Stop IRQs from calling while we fiddle with ROMs INX:JSR RomStackDispatch :\ Call the code on the stack PLP:PLA:TAX:TXS :\ Restore IRQs, restore stack RTS : .RomCopyDispatch .RomStackDispatch LDA #&01:PHA :\ Push stack address to jump to TXA:PHA LDY #0:STY &A8:STY &AA :\ Set up entry values LDX &F5:LDA &F4 RTS :\ Jump to code on stack \ Routine copied to stack to copy data \ ------------------------------------ \ CC=zero data, CS=copy data \ A=old ROM, X=ROM to select, Y=0, (&A8)=src, (&AA)=dest, (&AC)=page count .RomCopyStart PHA:JSR &100 :\ Select SRAM/SROM bank TYA :\ Prepare A=0 for wipe .RomCopyLp1 LDX #&40 :\ Write 64 bytes at a time for EEPROM .RomCopyLp2 BCC P%+4:LDA (&A8),Y :\ CC=use zero, CS=fetch byte STA (&AA),Y :\ Store byte INY:DEX:BNE RomCopyLp2 DEY:PHP :\ Save Carry .RomCopyCheck CMP (&AA),Y :\ Check last byte written BNE RomCopyCheck :\ Wait for data to settle PLP :\ Restore Carry INY:BNE RomCopyLp1 :\ Loop for 256 bytes INC &A9:INC &AB :\ Increment addresses DEC &AC:BNE RomCopyLp1 :\ Loop until all done PLA:TAX :\ First 4 bytes and last 13 bytes .RomCopySelect :\ are the same in both routines STX &F4 LDA #&0C:STA ROMSEL STX ROMSEL:RTS :\ 49 bytes .RomCopyEnd \ Routine copied to stack to test for sideways RAM \ ------------------------------------------------ \ A=old ROM, X=ROM to select \ Returns Y=&00, 'R', 'E' .RomTestStart PHA:JSR &100 :\ Select SRAM/SROM bank LDA &8008:EOR #&AA:STA &8008 :\ Modify version byte OPT FNif(VALver$<1.301) NOP :\ Wait for floating bus to settle OPT FNendif OPT FNif(VALver$>=1.301) CMP &AAA2 :\ Wait for floating bus to settle OPT FNendif CMP &8008:PHP :\ EQ=RAM, NE=ROM/EEPROM/empty EOR #&AA:STA &8008 :\ Restore byte .RomTestLp LDA &8008:EOR &8008:BEQ RomTestOk :\ Bytes match \ If empty socket, Cx EOR Cx -> 0x %00xxxxxx \ If EEPROM , Cx EOR 8x -> 4x %x1xxxxxx ASL A:BPL RomTestOk :\ Empty socket, bit 6 not toggling LDY #ASC"E":BNE RomTestLp :\ Toggling, must be EEPROM/empty .RomTestOk PLP:BNE RomTestNotRam :\ NE from earlier, ROM or EEPROM or empty LDY #ASC"R" :\ EQ from earlier, must be RAM .RomTestNotRam PLA:TAX .RomTestSelect STX &F4 LDA #&0C:STA ROMSEL STX ROMSEL:RTS :\ 52 bytes .RomTestEnd \ ************* \ Disk Commands \ ************* \ *FORMAT (Y) \ ========================= .AFORMAT JSR L97E9:PHA :\ Check ADFS, get drive number, A=0/1, X=0-F drive number JSR SkipSpaces:AND #&DF :\ Look for disk size CMP #ASC"S":BEQ Format2 CMP #ASC"M":BEQ Format2 CMP #ASC"L":BEQ Format2 JSR MkError:EQUB 148:EQUS "Bad size":BRK : .Format2 PHA:TXA:PHA :\ stack => physical drive, size, logical drive JSR SkipSpaces1 :\ Look for final optional 'Y' AND #&DF:CMP #ASC"Y" PHP:BEQ Format3 :\ If 'Y', don't prompt for confirmation JSR PrText EQUS "Format drive ":EQUB 0 TXA:JSR PrNybble JSR CheckEnabled : .Format3 \ X=physical drive, stack => (Y), physical drive, size, logical drive JSR NMIClaim :\ *FX143,12,255 - claim NMIs LDA #&00:STA FDCdrive :\ Write &00 RESET to drive control register TAY:TAX .X9A96 DEY:BNE X9A96 :\ Delay for while FDC resets DEX:BNE X9A96 TSX:LDA &104,X :\ Get drive number LDX #0:JSR X93D1 :\ Write to drive register, noRES+SIDE0+DRIVE LDA #&07:JSR X93E0 :\ FDC command 'Restore', seek to Track 0 PLP:BEQ Format11 :\ 'Y' option given, don't prompt to overwrite AND #&10:BNE Format11 :\ Sector Not Found - disk is unformatted JSR NMIRelease :\ Release NMIs JSR PrText EQUS "Already formatted. Format":EQUB 0 JSR CheckEnabled JSR NMIClaim :\ *FX143,12,255 - claim NMIs LDA #&07:JSR X93E0 :\ Spin the disk up again : \ *FORMAT enabled, format existing disk enabled, NMI claimed, all ready to go \ stack => physical drive, size, logical drive .Format11 PLA:STA L0935 :\ Store physical drive number LDX #80:LDY #1 :\ 80 tracks, 1+1 sides PLA:CMP #ASC"L":BEQ Format12 :\ Large =80x2 DEY:CMP #ASC"M":BEQ Format12 :\ Medium=80x1 LDX #40 :\ Small =40x1 .Format12 STX L0932:STY L0931 :\ &932=tracks, &931=sides-1 PLA:STA L0930 :\ &930=logical drive number 0/1 LDA #&00:STA L0938 :\ Set to side 0 : \ Now moved to FILEBLK \ &930=logical drive number \ &931=sides-1 \ &932=tracks \ &933=old NMI owner \ &934= \ &935=physical drive number \ &936=physical drive number as ASCII for *MOUNT, etc \ &937= \ &938=current side \ &939=bottom of memory low byte \ &93A=bottom of memory high byte \ &93B=current track \ &93C=logical sector number \ &93D= \ &93E=modified track number, track+8 if odd track \ &93F=physical sector number : JSR CheckMode JSR L97B4:STX L0939 :\ OSBYTE &83 - read top of user memory TYA:SEC:SBC #&1A:STA L093A :\ Use 6.5K of memory below screen : .Format13 JSR PrText EQUS "Formatting ":EQUB 0 JSR PrPreTrack :\ Print drive,track : .L9338 LDA FDCstatus :\ Read FDC status ROR A:BCS L9338 :\ Loop until FDC not BUSY \ \ Note, FDCstatus in A register is now rotated right \ So, must test for status DIV 2 \ AND #&20:BEQ L935C :\ Not WriteProtected OPT FNif(TARGET%<0) BNE L935C :\ Ignore WriteProtected OPT FNendif JSR NMIRelease JSR MkError:EQUB 201:EQUS "Disk read only":BRK .FormatEscape JSR NMIRelease JMP errEscape \ FDC ready, writable, and disk spinning \ -------------------------------------- .L935C LDA #&00:STA L093B :\ current track=0 .L9360 BIT &FF:BMI FormatEscape :\ Escape pressed JSR X9567 :\ Print track number, build image, write to disk INC L093B:LDA L093B :\ Increment track CMP L0932:BNE L9389 :\ Compare with number of tracks, jump if not done DEC L0931:BMI L939A :\ Decrement number of sides, jump if all done LDA #&00:JSR X93E0 :\ Clear FDC command register INC L0938 :\ Increment side number JSR X93D0 :\ Write to drive control register, select side 1 JMP L9338 :\ Jump back to format from track 0 \ Prepare to do next track \ ------------------------ .L9389 LDA FDCstatus :\ Read FDC status ROR A:BCS L9389 :\ Loop until not BUSY LDA #&53 :\ &53=StepToNext, u=update, h=no spin, v=no verify, speed=3 JSR X93E0 :\ Step to next track JMP L9360 :\ Jump back to write next track \ All done \ -------- .L939A JSR OSNEWL .L93A8 LDA FDCstatus :\ Read FDC status ROR A:BCS L93A8 :\ Loop until not BUSY LDA #&00:JSR X93E0 :\ Clear FDC command register JSR NMIRelease :\ Release NMIs : \ Write padding file if early ADFS version \ ---------------------------------------- LDA L0936:PHA :\ Save ASCII drive number as *SAVE will workspace LDA #&08:STA &F6 :\ Point to version number LDA #&80:STA &F7 LDY &0DBC:JSR &FFB9 :\ Read from current filing system ROM CMP #0:BNE X9A34 :\ Not &00, no need for padding file : JSR PrText EQUS "Writing ADFS 1.00 ZYSysHelp":EQUB 0 ]:cmdLen=1:cmdBuf=&B00:IF(opt%AND3):cmdLen=X9A59-X9A39:cmdBuf=&B00-cmdLen [OPT opt% LDX #cmdLen-1 .X9A0F LDA X9A39,X:STA cmdBuf,X :\ Copy commands to top of page A DEX:BPL X9A0F LDA L0936 :\ Get ASCII drive number STA cmdBuf+&05 :\ Store in '*DIR' STA cmdBuf+&0D :\ Store in '*SAVE' STA cmdBuf+&28 :\ Store in '*ACCESS' LDX #(cmdBuf AND 255)+0 JSR X9980 :\ Do '*DIR' LDX #(cmdBuf AND 255)+7 JSR X9980 :\ Do '*SAVE' LDX #(cmdBuf AND 255)+&20 JSR X9980 :\ Do '*ACCESS' JSR OSNEWL .X9A34 PLA :\ Mount the drive and finish \ Could finish by verifying the drive : \ Mount drive in A \ ---------------- .X9975 TAY:LDX #7 .X9978 LDA X9A59,X:STA &00A8,X :\ Copy command to &A8-&AF DEX:BPL X9978 STY &AE :\ Store drive number LDX #&A8:LDY #0 :\ Do '*MOUNT' JMP OS_CLI .X9980 LDY #&0A:JMP OS_CLI :\ Do command in page &A .X9A39 EQUS "DIR :x":EQUB 13 EQUS "SAVE :x.ZYSysHelp 0+38F0":EQUB 13 EQUS "ACCESS :x.ZYSysHelp L":EQUB 13 .X9A59 EQUS "MOUNT x":EQUB 13 .X9A69 \ Create image of track data in memory, then write to disk \ -------------------------------------------------------- .X9567 LDA L0939:STA LAE+0 :\ LAE/F=>bottom of data buffer LDA L093A:STA LAE+1 LDA #&08 JSR OSWRCH:JSR OSWRCH :\ Print two backspaces LDA L0938:LSR A :\ Side LDA L093B :\ Track BCC P%+4:ADC #79 :\ Add 80 for side 1 JSR PrHex :\ Print track number JSR L9433 :\ Create track image in memory .X9585 LDA FDCstatus :\ Read FDC status ROR A:BCS X9585 :\ Loop until FDC not busy LDA L0939:STA LAC+0 :\ LAC/1=>bottom of memory LDA L093A:STA LAC+1 : \ Write track data \ ---------------- .X99A7 OPT FNif(TARGET%>-1) SEI:LDY #&00 .X99AE LDA FDCstatus:AND #&21 :\ Read FDC Spin+Busy status CMP #&20:BNE X99AE :\ Not spun up, loop until spinning LDA #&F4:STA FDCcommand :\ Write FDC command &F4=Write track, h=spin, e=no delay LDY #&9 .X99EF DEY:BNE X99EF :\ Delay .X99C6 LDA (LAC),Y :\ Get byte from track data CMP #&FF:BEQ X99EC :\ &FF=end of data TAX :\ X=data to write .X99CD LDA FDCstatus AND #&02:BEQ X99CD :\ Loop until DataRequest STX FDCdata :\ Write data INY:BNE X99C6 :\ Loop for 256 bytes INC LAC+1:BNE X99C6 :\ Loop for next 256 bytes .X99EC CLI OPT FNendif : .X959A LDA FDCstatus :\ Read FDC status ROR A:BCS X959A :\ Loop until FDC not busy ROL A:RTS :\ Return result in A \ Write command A to FDC, return result in A \ ------------------------------------------ .X93E0 SEI:STA FDCcommand :\ Write to FDC command register LDY #&09 .X93EB DEY:BNE X93EB :\ Delay for 9 loops CLI:BEQ X959A \ Select drive and side \ --------------------- .X93D0 LDA L0930 :\ Get current drive LDX L0938 :\ Get current side .X93D1 BEQ P%+4:ORA #fdcSIDE :\ If side 1, OR with SIDE CLC:ADC #1 :\ Convert to drive select bitmap ORA #fdcRES :\ OR with noRESET STA FDCdrive:RTS \ Create a track in memory \ ------------------------ .L9433 LDA #&4E:LDX #&3C:JSR X95AF :\ Fill &3C x &4E byte LDX #&00 :\ Start at physical sector 0 .L943C STX L093F:JSR L9459 :\ Create sector X LDX L093F:INX :\ Increment sector CPX #&10:BNE L943C :\ Loop for 16 sectors LDA #&FF :\ Write terminating &FF byte \ Fill memory with track data \ --------------------------- .X95AD LDX #&01 :\ Fill one byte of memory .X95AF LDY #&00 STX L093E :\ Number of bytes to store LDX #&00 .X95B6 STA (LAE),Y:INC LAE+0 BNE X95BE:INC LAE+1 .X95BE INX:CPX L093E:BNE X95B6 RTS \ Fill a sector with fill byte \ ---------------------------- JSR L9452 .L9452 LDA #&4E :\ Fill byte &4E .L9454 LDX #&00:BEQ X95AF :\ Fill with 256 bytes \ Create a single sector image \ ---------------------------- .L9459 LDA #&00:LDX #&0C:JSR X95AF :\ 12 bytes of &00 LDA #&F5:LDX #&03:JSR X95AF :\ 3 bytes of &F5 LDA #&FE:JSR X95AD :\ 1 bytes of &FE - ID start flag LDA L093B:JSR X95AD :\ current track LDA L0938:JSR X95AD :\ current side LDA L093B:ROR A:PHP :\ current track ROL A:PLP:BCC L9483:ADC #&07 :\ track+8 for odd tracks .L9483 STA L093E CLC:LDA L093F:ADC L093E :\ Physical sector+track offset AND #&0F:STA L093C :\ Logical sector number JSR X95AD :\ logical sector LDA #&01:JSR X95AD :\ &01 = sector size=256 LDA #&F7:JSR X95AD :\ &F7 - tell FDC to generate a CRC LDA #&4E:LDX #&16:JSR X95AF :\ 22 bytes of &4E LDA #&00:LDX #&0C:JSR X95AF :\ 12 bytes of &00 LDA #&F5:LDX #&03:JSR X95AF :\ 3 bytes of &F5 LDA #&FB:JSR X95AD :\ 1 byte of &FB - data start flag : LDA L0938:ORA L093B :\ Check track and side BEQ L94C4 :\ If track 0, side 0, fill with root data .L94C1 JMP L9556 :\ Jump to fill with empty sector .Hugo EQUS "Hugo" \ Fill sectors on track 0 with root data \ -------------------------------------- .L94C4 LDA L093C :\ Logical sector number CMP #&07:BCS L94C1 :\ End of track 0, normal blank sector PHA:LDA #&00:JSR L9454 :\ Fill sector with &00 DEC LAE+1 :\ Step back to start of sector PLA :BEQ L950F :\ Sector 0 - FSM starts CMP #&02:BCC L9523 :\ Sector 1 - FSM lengths BEQ L9547 :\ Sector 2 - start of '$' CMP #&06:BCS X94E7 :\ Sector 6 - end of '$' JMP X9732 :\ Sector 3-5 - middle of '$' \ Sector 0 - Free Space Map starts \ -------------------------------- .L950F LDY #&00 LDA #&07:STA (LAE),Y :\ Free space starts at &000007 JSR X9712 :\ Get disk size in sectors to &XXAA LDY #&FC:STA (LAE),Y :\ Store total number of sectors TXA:INY:STA (LAE),Y BNE X9727 :\ Jump forward to calculate checksum \ Sector 1 - Free Space Map lengths \ --------------------------------- .L9523 JSR X9712:LDY #0 :\ Get disk size in sectors to &XXAA SEC:SBC #&07:STA (LAE),Y :\ Free space length = size-7 TXA:SBC #&00 INY:STA (LAE),Y:LDY #&FB LDA &240 :\ Get random-ish value from countdown timer STA (LAE),Y:INY :\ &FB=DiskID LDA &295 :\ Get random-ish value from TIME STA (LAE),Y :\ &FC=DiskID LDA #&03:INY:INY:STA (LAE),Y :\ End of FSM list BNE X9727 :\ Jump forward to calculate checksum \ Sector 2 - start of '$' directory \ --------------------------------- .L9547 LDY #0 .X9549 LDA Hugo,Y:INY:STA (LAE),Y :\ Copy 'Hugo' to start of directory CPY #&04:BNE X9549 BEQ X9732 \ Sector 6 - end of '$' directory \ ------------------------------- .X94E7 LDA #ASC"$" LDY #&CC:STA (LAE),Y :\ Directory name LDY #&D9:STA (LAE),Y :\ Directory title LDA #&0D INY:STA (LAE),Y :\ Terminate with LDY #&CD:STA (LAE),Y :\ Terminate with LDY #&D6 LDA #&02:STA (LAE),Y :\ Parent directory LDY #&FB .X9502 LDA Hugo-&FB,Y:STA (LAE),Y :\ Copy 'Hugo' to end of directory INY:CPY #&FF:BNE X9502 BEQ X9732 \ Calculate FSM checksum \ ---------------------- .X9727 LDA #&FF:LDY #&FE:CLC .X9999 ADC (LAE),Y:DEY:BNE X9999 :\ Add up 254 down to 1 ADC (LAE),Y :\ Add byte 0 DEY:STA (LAE),Y :\ Store at offset 255 : .X9732 INC LAE+1 :\ Point back to end of sector data BNE L955B :\ Jump to add sector footer .L9556 LDA #&6C:JSR L9454 :\ 256 bytes of &6C .L955B LDA #&F7:JSR X95AD :\ &F7 - tell FDC to generate a CRC LDA #&4E:LDX #&2C:JMP X95AF :\ 44 bytes of &4E \ Work out disk size in sectors \ ----------------------------- .X9712 LDX #&0A LDA L0931:BNE X970D :\ If two sides, return X=&0A, A=&00 LDX #&05 LDA L0932 :\ Tracks CMP #80:BEQ X970D :\ If 80 tracks, return X=&05, A=&00 LDX #&02:LDA #&80 :\ Otherwise, 40 tracks, return X=&02, A=&80 RTS .X970D LDA #0:RTS .CheckMode JSR L97A6 :\ Read current screen mode INY:INY:BNE ChkModeChk .CheckMode6 JSR L97A6 :\ Read current screen mode .ChkModeChk CPY #6:BCS ChkModeOk :\ MODE>6 or MODE>4, don't change MODE LDA #22:JSR OSWRCH :\ Need more memory, change to MODE 7 (drops to MODE 6) LDA #7:JMP OSWRCH .ChkModeOk RTS .PrVerifyTrack JSR PrText EQUS "Verifying ":EQUB 0 .PrPreTrack LDA L0935:JSR PrNybble STA L0936 :\ Store ASCII drive number LDA #ASC":":JSR OSWRCH LDA #0:JMP PrHex \ *VERIFY \ ============= .VERIFY JSR L97E9:PHA :\ Check ADFS, get drive number JSR X9975 :\ *MOUNT the drive LDA #0:STA L093B :\ Start with track 0 STA L09D8:STA L09D7 :\ Sector=0 PLA:STA L0935 :\ Store logical drive number ASL A:ASL A:ASL A :\ drive*32 ASL A:ASL A:STA L09D6 :\ Sector=drive*32+000000 LDA #&10:STA L09EF :\ 16 sectors per call JSR CheckMode JSR L97B4:STX LAE+0 :\ OSBYTE &83 - read top of user memory TYA:SEC:SBC #&12:STA LAE+1 :\ Use 5K of memory below screen : \ FBLK+0 &93B=current track \ OSWORD &72 control block \ FBLK+1 &9D0=result \ FBLK+2 &9D1= \ \ FBLK+3 &9D2= \ address \ FBLK+4 &9D3=&FF / \ FBLK+5 &9D4=&FF / \ FBLK+6 &9D5=command \ FBLK+7 &9D6=drive*32+sector \ FBLK+8 &9D7=sector \ FBLK+9 &9D8=sector \ FBLK+10 &9D9=count \ FBLK+11 &9DA=0 \ FBLK+12 &9EF=sectors to do per call \ FBLK+13 &9EC\ \ FBLK+14 &9ED } disk size \ FBLK+15 &9EE/ \ FBLK+16 &935=physical drive number \ FBLK+17 &936=ASCII drive number for *MOUNT \ Verify loop \ ----------- .Verify10 LDA #&86:JSR OSBYTE TXA:BNE Verify11 JSR PrVerifyTrack :\ Print 'Verifying...' .Verify11 BIT &FF:BMI VerifyEscape LDA #&08 JSR OSWRCH:JSR OSWRCH :\ Print two backspaces LDA L093B:JSR PrHex :\ Print track number : LDX #0:STX L09D0 :\ Result STX L09DA :\ Byte 10 LDA LAE+0:STA L09D1 LDA LAE+1:STA L09D2 DEX STX L09D3:STX L09D4 :\ Address high word LDA #8:STA L09D5 :\ Command LDA L09EF:STA L09D9 :\ Count LDX #L09D0 AND 255 :\ Point to control block LDY #L09D0 DIV 256 LDA #&72:JSR OSWORD :\ Read sectors LDX L09D0:BNE Verify12 :\ Report disk error : LDA L093B:BNE Verify13 :\ Not track 0, step to next track LDY #&FC :\ Point to disk size .X9664 LDA (LAE),Y :\ Get disk size STA L09EC-&FC,Y :\ Copy disk size to &9EC/D/E INY:CPY #&FF:BNE X9664 : OPT FNif(TARGET%<0) LDA #&0A:STA L09ED LDA #0:STA L09EC:STA L09EE OPT FNendif BEQ Verify13 :\ Step to next track .VerifyEscape JMP errEscape .Verify12 JSR PrText :\ Report disk error EQUS " disc error ":EQUB 0 TXA:JSR PrHex:JSR OSNEWL : .Verify13 CLC:LDA L09EF :\ Get sectors/track ADC L09D8:STA L09D8 :\ Update sector number low BCC Verify14:INC L09D7 :\ Update sector number mid BNE Verify14:INC L09D6 :\ Update sector number high .Verify14 SEC LDA L09EC:SBC L09EF:STA L09EC :\ Decrement number to do LDA L09ED:SBC #0:STA L09ED LDA L09EE:SBC #0:STA L09EE ORA L09ED:BNE Verify15 :\ >256 to do, loop back LDA L09EC:BEQ VerifyDone :\ Nothing left CMP #&10:BCS Verify15 :\ >15 to do, loop back STA L09EF :\ <16 to do, do remaining amount .Verify15 INC L093B :\ Increment track number JMP Verify10 :\ Loop back for next track .VerifyDone LDA L0936:JSR X9975 :\ *MOUNT the drive JMP OSNEWL :\ Done .NMIClaim LDX #&0C:LDY #&FF JSR X97BB :\ *FX143,12,255 - claim NMIs LDA #&40:STA &D00 :\ Null NMI routine STY L0933:RTS :\ Save old NMI owner .NMIRelease LDX #&0B:LDY L0933 :\ *FX143,11, - release NMIs .X97BB LDA #&8F:BNE L97B8 :\ Service call .L97A6 LDA #&87:BNE L97B8 :\ Read screen mode .L97B2 LDA #&7C:BNE L97B8 :\ Acknowledge Escape .L97B4 LDA #&84 :\ Top of user memory .L97B8 JMP OSBYTE \ Check FS and parse drive number if ADFS \ ======================================= .L97E9 TYA:PHA LDA #0:TAY:JSR OSARGS CMP #8:BEQ L97EC :\ Filing system is ADFS OPT FNif(TARGET%<0) BNE L97EC :\ Ignore current filing system OPT FNendif PLA :\ Drop Y PLA:PLA :\ Drop return address to command PLA:PLA :\ Drop return address to command dispatcher LDY &F5:LDX &F4 :\ Restore to return to MOS LDA #4 .L97EB RTS .L97EC PLA:TAY :\ Get command pointer back :\ Check for valid drive number :\ 0,1,4,5,A,B,E,F :\ Should also allow leading LDA (&F2),Y :\ Get drive character JSR CheckDigit :\ Check if valid character, INY if valid BCS errBadDrive TAX:CMP #8 :\ Keep original drive number in X BCC P%+4:SBC #2 :\ Convert to logical drive number AND #3:CMP #2:BCC L97EB .errBadDrive JSR MkError:EQUB 205:EQUS "Bad drive":BRK : .CheckEnabled JSR L9035:BCC L97EB :\ Prompt Y/N? JSR MkError:EQUB 146:EQUS "Aborted":BRK EQUB &FF : .RelocTable ]NEXT:PROCsm_table OSCLI "*Save "+file$+" "+STR$~(mcode%+mclen%)+" "+STR$~O%+" FFFF0000 FFFBBC00" OSCLI "Stamp "+file$ END : DEFFNsm_pass(pass%) IFpass%=0:mclen%=0 IFpass%=1:mclen%=O%-mcode% P%=&8100-128*(pass%AND2) O%=mcode%+mclen%*(pass%AND2)DIV2 IFpass%=1:IF O%+mclen%*2.125>L%:PRINT"Code overrun":END =VALMID$("4646",pass%+1,1) : DEFPROCsm_table base80%=mcode%+mclen%:base81%=mcode%:byte%=0:count%=0:off%=0:REPEAT byte80%=base80%?off%:byte81%=base81%?off%:IFoff%>=mclen%:byte80%=&80:byte81%=&80 IF((byte81%-byte80%) AND &FE)<>0:PRINT "ERROR: Offset by more than one page at &";~&8000+off% IF(byte80% AND &C0)=&80:byte%=byte%DIV2+128*(byte81%-byte80%):count%=count%+1 IFcount%=8:?O%=byte%:O%=O%+1:byte%=0:count%=0 off%=off%+1:UNTILoff%>=mclen% AND count%=0 ENDPROC