REM > AP6v13367.src REM Source for Updated PRES AP6 ROM Manager and Utilities REM Can test on Master, but ROM Manager workspace clashes : REM Boilerplate 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%=0:=opt% ELSE z%=P%:=opt%AND-2 DEFFNendif:IFz%:z%=P%-z%:P%=P%-z%:O%=O%-z%:=opt% ELSE =opt% DEFFNelse:IFz%:z%=P%-z%:P%=P%-z%:O%=O%-z%:z%=0:=opt% ELSE z%=P%:=opt%AND-2 : 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 FSCV=&21E : TARGET%=-1:REM Build for 6502Em with no FDC hardware, no real ADFS TARGET%=1 :REM Build for BBC B/B+ TARGET%=3 :REM Build for Master TARGET%=5 :REM Build for Compact TARGET%=0 :REM Build for Electron IF TARGET$<>"":TARGET%=VALTARGET$ : : ver$="1.323":date$="25 Jan 2019" REM Added option *SRPAGE (I). REM *ROMS doesn't wrap over end of line. : ver$="1.324":date$="15 Apr 2020" REM 21-Apr-2020: Removed pre-v1.323 code REM *SRLOAD faults loading over myself : ver$="1.33":date$="02 May 2020" REM *INSERT/*UNPLUG code almost identical, merged REM To do: REM Single code, multiple platform : ver$="1.332":date$="16 Jun 2020" REM Bugfix *SRLOAD/*SRWIPE, if AP6 ROM not in bank 0, always gave 'Not writable' REM Fixed where TubeDisable broken from removing old code : ver$="1.333":date$="16 Jun 2020" REM Artificial bump to get past bodged upload : ver$="1.334":date$="30 Dec 2020" REM *-BREAK ver$="1.335":date$="04 Jan 2021" REM *SRPAGE dosn't lose REM Removed pre-v1.335 code : ver$="1.336" REM Optimised ScanDec routines ver$="1.337" : REM Thoughts: *INSERT/*UNPLUG/*LANG/*TUBE call OSBYTE 162 REM OSBYTE 161/162 pass on to any Configure Module before implementing manuall REM eg set/reset &DF0,X.b6 to pass on : : REM Base addresses REM -------------- IF TARGET%<1 :FDCbase=&FCC4:fdcRES=&20:fdcSIDE=&04:ROMSEL=&FE05:TUBEIO=&FCE0:ROMTABLE=&2A0:FILEBLK=&2E2:REM Electron IF TARGET%=1 OR TARGET%=2 :FDCbase=&FE84:fdcRES=&20:fdcSIDE=&04:ROMSEL=&FE30:TUBEIO=&FEE0:ROMTABLE=&2A1:FILEBLK=&2EE:REM BBC IF TARGET%>2 AND TARGET%<6:FDCbase=&FE28:fdcRES=&04:fdcSIDE=&10:ROMSEL=&FE30:TUBEIO=&FEE0:ROMTABLE=&2A1:FILEBLK=&2ED:REM Master IF TARGET%=0:name$="AP6" ELSE name$="SRAM" : REM Workspace REM --------- LAC=&AC:LAE=&AC:NUM=&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 L0D6C=&0D6C:L0D6D=&0D6D :REM ROM manager settings L0D6E=&0D6E:L0D6F=&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 in b7-b6,b3-b0, b5=TubeDisable, b4=spare 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)+MID$(" BBMEC",TARGET%+1,1) 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, else 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 \ ============ OPT FNif(VALver$<1.336) \\ Scan for short number \\ --------------------- \\ Scans for hex or dec 0-15 or 0-F, or \\ Returns CC, A=number \\ error if empty command line \\ \.ScanDec8 \\ *** TO DO - scan 8-bit decimal \.ScanDec4 \\JSR L8CA5:BCC L8D00 \.errBadNumber \JSR MkError:EQUB 252:EQUS "Bad number":BRK \ \\ Scan for or * \.L8CA0 \LDA (&F2),Y \CMP #ASC"*":BEQ ChkDigitOk :\ EQ+CC='*', EQ+CS=, NE= \: \\ Scan for or "" \\ 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 :\ Return CS=empty line \JSR CheckDigit:BCS errBadNumber :\ Must start with a digit \CMP #1:BNE ChkDigitEnd :\ Not '1', check end of number \LDA (&F2),Y :\ Get next digit \JSR CheckDigit:BCC ChkDigitTen :\ Valid digit, check terminator \LDA #1:BCS ChkDigitEnd :\ Just '1', check terminator .ChkDigitTen \ADC #10 :\ Convert 1x to 10-15 \CMP #16:BCS errBadNumber :\ 16-19, too big .ChkDigitEnd \PHA:LDA (&F2),Y :\ Get following character \CMP #ASC"!":BCC ChkDigitDone :\ Followed by or , return \CMP #ASC",":BNE errBadNumber :\ Followed by non-comma, error .ChkDigitDone \PLA:CMP #&FF :\ Return number, CC=ok, NE=number .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 : OPT FNelse : \ Parse "" * or \ ------------------- .X8CA0 .L8CA0 LDA (&F2),Y CMP #ASC"*":BEQ ChkDigitCC :\ EQ+CC='*' : \ Parse "" or \ ------------------- .X8CA5 .L8CA5 LDA (&F2),Y CMP #13:BEQ ChkDigitCS :\ EQ+CS= : \ Parse 4-bit \ ----------------- .XScanDec4 .ScanDec4 JSR ScanDec8 CMP #&10:BCS XerrBadNumber :\ Too big RTS :\ NE+CC= : \ Parse 8-bit \ ----------------- .ScanDec8 JSR CheckDigit:BCS XerrBadNumber STA NUM :\ Store as current number CMP #10:BCS ScanDecDone :\ Hex number, exit .ScanDecLp JSR ScanDigit:BCS ScanDecDone :\ No more digits PHA :\ Save digit LDA NUM:CMP #26:BCS errBadNumber:\ num>25, num*25>255 ASL A:ASL A:ADC NUM:ASL A :\ num=num*10 STA NUM:PLA:ADC NUM:STA NUM :\ num=num*10+digit BCC ScanDecLp :\ Loop for next digit .XerrBadNumber .errBadNumber JSR MkError:EQUB 252:EQUS "Bad number":BRK .ScanDecDone LDA (&F2),Y CMP #ASC"!":BCS XerrBadNumber :\ Badly terminated number LDA NUM .ChkDigitCS SEC:RTS :\ Return A=number, CS : .CheckDigit LDA (&F2),Y CMP #ASC"A":BCC ScanDigit2 :\ Decimal digit AND #&DF CMP #ASC"F"+1:BCS ChkDigitCS :\ >'F' SBC #6:BNE ScanDigit3 :\ Convert 'A'-'F' .ScanDigit LDA (&F2),Y .ScanDigit2 CMP #ASC"0":BCC ChkDigitCS :\ <'0' CMP #ASC"9"+1:BCS ChkDigitCS :\ >'9' .ScanDigit3 INY:AND #&0F .ChkDigitCC CLC:RTS :\ Return A=digit, CC OPT FNendif \ SERVICE 1 - Do Reset processing \ =============================== .Serv1 TYA:PHA :\ Save current workspace address OPT FNif(TARGET%<3) LDA L0D6D:ASL A:ASL A :\ Get Tube Enable from bit 5 BPL Serv1a :\ bit 5 = 0, not disabled LDA #0:STA &027A :\ Disable Tube LDA &FFB7:STA &A8 :\ Point to default vectors LDA &FFB8:STA &A9 :\ Reset EVENTV and BRKV LDY #&21 :\ Point to EVENTV .Serv1lp LDA (&A8),Y:STA &200,Y CPY #&20:BNE P%+4:LDY #4 :\ EVENTV done, point to BRKV+1 DEY:CPY #1:BNE Serv1lp OPT FNendif .Serv1a LDA &028D CMP #&01:BNE Serv1Done :\ Check last Break type LDY #1:JSR LockUnlockAll :\ If Power on, lock (write protect) all ROMs .Serv1Done PLA:TAY .Serv1Exit PLA:RTS \ SERVICE 7 - Read/Write configuration settings \ ============================================= .Serv7 LDA &EF CMP #&A1:BEQ Serv7go :\ OSBYTE &A1 - Read settings CMP #&A2:BNE Serv1Exit :\ OSBYTE &A2 - Write settings .Serv7go LDX &F0 CPX #15:BEQ Serv7Tube :\ Location 15, Tube On/Off CPX #5:BCC Serv1Exit CPX #8:BCS Serv1Exit \ 5 = b4-b7=LANG \ 6 = b0-b7=unplug bitmap 0-7 \ 7 = b0-b7=unplug bitmap 8-15 \ 15 = b0, 0=NoTube, 1=Tube LSR A:BCC Serv7Write LDA L0D6D-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 :\ A=0000llll EOR L0D6D :\ A=xxTxWWWW AND #&0F :\ A=0000WWWW EOR L0D6D :\ A=xxTxllll EOR #&0F :\ A=xxTxLLLL .Serv7WrOk STA L0D6D-5,X:JMP Serv7Done .Serv7Tube LSR A:BCS Serv7TubeRd :\ Jump with Read .Serv7TubeWr TYA:LSR A :\ Cy=~T LDA L0D6D :\ A=xxTxLLLL AND #&DF :\ A=xx0xLLLL BCS Serv7WrOk :\ Enable Tube ORA #&20:BNE Serv7WrOk :\ Disable Tube .Serv7TubeRd LDA L0D6D :\ A=xxTxLLLL AND #&20:CMP #&20 :\ A=00Tx0000 LDA #&FE:ADC #0 :\ A=1111111T JMP Serv7RdOk :\ EOR FF and return \ SERVICE &10 - Spool/Exec closing \ ================================ \ Insert/Unplug ROMs \ Needs to be done before Serv1, on BBC/Elk Serv10 before Serv01 \ Ctrl-CAPS check needs to be done here to enable ROM before Serv01 \ Check Ctrl-* and jump to *-prompt \ .Serv10 LDA &EF:ORA &F0 ORA &F1:BNE Serv10Exit :\ Not BREAK, skip LDA &028D CMP #&01:BNE X813E :\ Not Power-On, insert/unplug ROMs OPT FNif(TARGET%<3) \ &024B=00xxrrrr - 6502 BASIC ROM \ =01xxrrrr - 6502 BASIC don't relocate \ =10xxrrrr - non-6502 BASIC ROM \ =11xxxxxx - no BASIC LDA &024B :\ Get BASIC ROM number .Serv10SetLang EOR L0D6D:AND #&CF :\ Clear and merge LANG bits EOR L0D6D:STA L0D6D :\ Default language = BASIC OPT FNendif PLA:RTS : .X813E LDX #15:LDA L0D6F :\ Unplug bitmap for ROMs 8-15 .Serv10Lp1 CPX #7:BNE Serv10a LDA L0D6E :\ 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 LDA #&7A:JSR OSBYTE :\ Check keys pressed CPX #&48:BEQ Serv10Enable :\ * CPX #&5B:BEQ Serv10Enable :\ K* CPX #&40:BNE Serv10Exit :\ CAPSLOCK CLC :\ CLC=CAPSLOCK .Serv10Enable PHP:LDA #&78:JSR OSBYTE :\ Clear keypressed info LDA &8006 LDX &F4:STA ROMTABLE,X :\ Re-enable myself PLP:BCC Serv10Exit JSR MkError:EQUB 249:EQUS "Supervisor":BRK .Serv10Exit 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 Serv10Exit :\ 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 LDA cmdBase,X:ASL A:TAX :\ Get command byte, index into addresses 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 cmdAddrs-2+1,X:PHA :\ Get command address LDA cmdAddrs-2+0,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: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 : .HelpDispatch PHA:LDA &F5:PHA :\ Save Y and A again LDY cmdAddrs-2+1,X :\ Offset to help strings LDA cmdAddrs-2+0,X:TAX :\ Offset to command strings BEQ HelpSpecial JSR HelpPrint JMP ServQuit : .HelpLong TYA:PHA LDX #cmdFILE-cmdBase:LDY #hlpFILE-hlpBase:JSR HelpPrint LDX #cmdSRAM-cmdBase:LDY #hlpSRAM-hlpBase: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 :\ Print this command string INX:LDA cmdBase,X :\ Get first byte from next BPL HelpLp1:RTS :\ Loop if not terminator : .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 Support "+LEFT$(ver$,4)+LEFT$(CHR$(96+VALRIGHT$(ver$,1)),LENver$>4) OPT FNelse EQUS "ROM Manager and Utilities "+LEFT$(ver$,4)+LEFT$(CHR$(96+VALRIGHT$(ver$,1)),LENver$>4) 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 EQUS "+1" :EQUB &81 EQUS "SRAM" :EQUB &82 EQUS "UTILS":EQUB &83 EQUB &80 EQUS "SROM" :EQUB &82 EQUB &FF : .cmdFILE .cmdBUILD :EQUS "BUILD" :EQUB &84 .cmdDUMP :EQUS "DUMP" :EQUB &85 .cmdFORMAT :EQUS "FORMAT" :EQUB &86 .cmdLIST :EQUS "LIST" :EQUB &87 .cmdTUBE :EQUS "TUBE" :EQUB &88 .cmdTYPE :EQUS "TYPE" :EQUB &89 .cmdVERIFY :EQUS "VERIFY" :EQUB &8A EQUB &80 : .cmdSRAM .cmdAQRPAGE :EQUS "AQRPAGE" :EQUB &97 .cmdINSERT :EQUS "INSERT" :EQUB &8B .cmdLANG :EQUS "LANG" :EQUB &8C .cmdLROMS :EQUS "LROMS" :EQUB &8D .cmdROMS :EQUS "ROMS" :EQUB &8E .cmdSRLOAD :EQUS "SRLOAD" :EQUB &90 .cmdSRLOCK :EQUS "SRLOCK" :EQUB &91 .cmdSRPAGE :EQUS "SRPAGE" :EQUB &8F .cmdSRSAVE :EQUS "SRSAVE" :EQUB &92 .cmdSRUNLOCK:EQUS "SRUNLOCK":EQUB &93 .cmdSRWIPE :EQUS "SRWIPE" :EQUB &94 .cmdUNPLUG :EQUS "UNPLUG" :EQUB &95 .cmdUROMS :EQUS "UROMS" :EQUB &96 EQUB &80 : .cmdPlus1 .cmdLOADROM :EQUS "LOADROM":EQUB &90 .cmdLOCK :EQUS "LOCK" :EQUB &91 .cmdRLOAD :EQUS "RLOAD" :EQUB &90 .cmdRSAVE :EQUS "RSAVE" :EQUB &92 .cmdSAVEROM :EQUS "SAVEROM":EQUB &92 .cmdUNLOCK :EQUS "UNLOCK" :EQUB &93 .cmdZERO :EQUS "ZERO" :EQUB &94 EQUB &FF ]:A%=P%-cmdBase:IF A%>255:IF (pass%AND3)=0:P."WARNING: Command table ";A%-255;" bytes too long" [OPT opt% : \ Command help strings \ -------------------- .hlpBase .hlpFILE .hlpBUILD :EQUS "":EQUB 13 .hlpDUMP :EQUS "":EQUB 13 .hlpFORMAT :EQUS " (Y)":EQUB 13 .hlpLIST :EQUS "":EQUB 13 .hlpTUBE :EQUS "ON|OFF|":EQUB 13 .hlpTYPE :EQUS "":EQUB 13 .hlpVERIFY :EQUS "":EQUB 13 : .hlpSRAM .hlpAQRPAGE :EQUS "":EQUB 13 .hlpINSERT :EQUS "( (I))":EQUB 13 .hlpLANG :EQUS "()":EQUB 13 .hlpLROMS :EQUS "":EQUB 13 .hlpROMS :EQUS "":EQUB 13 .hlpSRLOAD :EQUS " (U)(L)(I)":EQUB 13 .hlpSRLOCK :EQUS "()":EQUB 13 .hlpSRPAGE :EQUS " (I)":EQUB 13 .hlpSRSAVE :EQUS " ":EQUB 13 .hlpSRUNLOCK:EQUS "()":EQUB 13 .hlpSRWIPE :EQUS " (U)(L)":EQUB 13 .hlpUNPLUG :EQUS "( (U))":EQUB 13 .hlpUROMS :EQUS "":EQUB 13 .hlpHELP :EQUB 13:EQUB 13:EQUB 13 ]:A%=P%-hlpBase:IF A%>255:IF (pass%AND3)=0:P."WARNING: Help table ";A%-255;" bytes too long" [OPT opt% : \ Command dispatch addresses \ -------------------------- .cmdAddrs EQUW 0 :\ +1 &81 EQUB cmdSRAM-cmdBase:EQUB hlpSRAM-hlpBase :\ SRAM &82 EQUB cmdFILE-cmdBase:EQUB hlpFILE-hlpBase :\ UTILS &83 EQUW BUILD-1 :\ &84 EQUW DUMP-1 :\ &85 EQUW AFORMAT-1 :\ &86 EQUW FLIST-1 :\ &87 EQUW TUBE-1 :\ &88 EQUW TYPE-1 :\ &89 EQUW VERIFY-1 :\ &8A EQUW INSERT-1 :\ &8B EQUW LANG-1 :\ &8C EQUW LROMS-1 :\ &8D EQUW ROMS-1 :\ &8E EQUW SRPAGE-1 :\ &8F EQUW SRLOAD-1 :\ &90 EQUW SRLOCK-1 :\ &91 EQUW SRSAVE-1 :\ &92 EQUW SRUNLOCK-1 :\ &93 EQUW SRWIPE-1 :\ &94 EQUW UNPLUG-1 :\ &95 EQUW UROMS-1 :\ &96 EQUW AQRPAGE-1 :\ &97 : \ *Help +1 offsets \ ---------------- .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 hlpSRLOAD -hlpBase EQUB cmdLOCK -cmdBase:EQUB hlpSRLOCK -hlpBase EQUB cmdLROMS -cmdBase:EQUB hlpLROMS -hlpBase EQUB cmdRLOAD -cmdBase:EQUB hlpSRLOAD -hlpBase EQUB cmdRSAVE -cmdBase:EQUB hlpSRSAVE -hlpBase EQUB cmdROMS -cmdBase:EQUB hlpROMS -hlpBase EQUB cmdSAVEROM-cmdBase:EQUB hlpSRSAVE -hlpBase EQUB cmdSRPAGE -cmdBase:EQUB hlpSRPAGE -hlpBase EQUB cmdTUBE -cmdBase:EQUB hlpTUBE -hlpBase EQUB cmdTYPE -cmdBase:EQUB hlpTYPE -hlpBase EQUB cmdUNLOCK -cmdBase:EQUB hlpSRUNLOCK-hlpBase EQUB cmdUNPLUG -cmdBase:EQUB hlpUNPLUG -hlpBase EQUB cmdUROMS -cmdBase:EQUB hlpUROMS -hlpBase EQUB cmdVERIFY -cmdBase:EQUB hlpVERIFY -hlpBase EQUB cmdZERO -cmdBase:EQUB hlpSRWIPE -hlpBase EQUB &00 \ ************* \ FILE COMMANDS \ ************* \ Workspace for UTILS commands \ &A8-&AF = 'MOUNT x' command \ &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 \ *TUBE ON|OFF| \ ================== .TUBE LDA (&F2),Y:AND #&DF :\ Get first character CMP #ASC"O":BNE TubeNum :\ Not *TUBE O, try for number INY LDA (&F2),Y:AND #&DF :\ Get upper case CMP #ASC"N":BEQ TubeOn :\ *TUBE ON CMP #ASC"F":BEQ TubeOff :\ *TUBE OFF DEY :\ Step back to error with non-number .TubeNum JSR ScanDec8 :\ Scan for number OPT FNif(TARGET%<3) STA TUBEIO+6 :\ Select Tube CPU on Electron or BBC OPT FNendif OPT FNif(TARGET%>2) TAX:PHP:SEI:LDA &FE34 :\ Disable IRQs, get current Tube EOR #&10:STA &FE34:STX TUBEIO+6 :\ Swap Tube, select Tube CPU EOR #&10:STA &FE34:STX TUBEIO+6 :\ Swap Tube back, select Tube CPU PLP :\ Restore IRQs OPT FNendif RTS .TubeOn .TubeOff EOR #8:AND #8:ASL A:ASL A :\ Move ON/OFF to bit 5 EOR L0D6D:AND #&20 :\ Clear and merge TUBE bit EOR L0D6D:STA L0D6D :\ Should only do on non-Master RTS \ ******************** \ ROM Manager Commands \ ******************** \ *LROMS (*) \ ========== .LROMS LDA #1 :\ A=1 to lock : \ *UROMS (*) \ ========== .UROMS :\ Entered with A=0 to unlock TAX:TYA:PHA:TXA TAY:JSR LockUnlockAll :\ Lock/unlock all ROMs PLA:TAY :\ Drop through to *ROMS : \ *ROMS (*) \ ========= .ROMS LDA (&F2),Y:CMP #ASC"*" BEQ P%+3:CLC :\ SEC=all ROMs LDX #&0F:STX &F5 :\ Start at ROM 15 .L8C22 PHP LDX &F5:JSR PrRomInfoAll :\ Display info for ROM X BCS L8C2D :\ Skip if nothing displayed LDA #8:JSR OSWRCH :\ Prevent line wrapping JSR OSNEWL .L8C2D PLP:DEC &F5:BPL L8C22 :\ Loop for all ROMs .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 BCC P%+4:LDA #&FF :\ If no , set no default PHA:JMP Serv10SetLang :\ 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 L0D6E:BCC L8D1D :\ Mask with bitmap for 0-7 .L8D1A AND L0D6F :\ 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 \ *SRPAGE (I)(U)(L) \ ============================== \ Lock/Unlock doesn't make sense, as must be ROM anyway \ .SRPAGE JSR ScanDec4:STA &F5 :\ Scan for a short hex number JSR SkipSpaces JSR ScanDec4:PHA :\ Scan for another short hex number JSR srOptionsSpc:PHA :\ Scan for options, returns %ULIQxxxX, corrupts X \ AND #&80 BEQ skip JSR unlock JSR RomTest :\ Y=&00 for ROM, 'R' for RAM, 'E' for EEPROM TYA:BEQ srPage1 .errBankWritable JSR MkError:EQUB 138:EQUS "Bank is not ROM":BRK .srPage1 LDX &F5:LDA #0 STA ROMTABLE,X :\ Remove from ROM table PLA:TAY :\ Y='I' option PLA:CLC:ADC #&96:TAX :\ X=sub-bank select value - confirmed &96 not 96 PHP:SEI :\ Stop IRQs while rebuilding ROM table OPT FNif(TARGET%>2) LDA &FE34:PHA :\ Get current 1MHz bus selection OPT FNendif TYA:PHA :\ Save options JSR RomPage :\ Select sub-bank via stack PLA :\ Get stacked options back \ AND #&40 BEQ skip JSR lock AND #&20 :\ Check 'I' option BNE RebuildROMs :\ Rebuild ROM table BEQ AQRdone \ *AQRPAGE \ =============== .AQRPAGE JSR ScanDec4:TAX :\ Scan for a short hex number PHP:SEI :\ Stop IRQs while rebuilding ROM table OPT FNif(TARGET%>2) LDA &FE34:PHA :\ Get current 1MHz bus selection ORA #&20:STA &FE34 :\ Select cartridge bus OPT FNendif STX &FCFC :\ Set paging register .RebuildROMs 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 the bank in &F5? 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 .AQRdone OPT FNif(TARGET%>2) PLA:STA &FE34 :\ Restore 1MHz bus selection OPT FNendif PLP:RTS :\ Restore IRQs and return \ *INSERT (*)() (I) \ *UNPLUG (*)() (U) \ ====================== \ 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. \ \ On entry, A=0, (F2),Y=>parameters \ .UNPLUG LDA #&FF :\ A=&FF - UNPLUG .INSERT PHA :\ Save JSR L8CA0:PHP :\ Scan for , save / flag STA &F5 :\ Save JSR srOptionsSpc:AND #&A0:\ Look for any options, %UxIxxxxx (corrupts X) PLP:BEQ L8D94 :\ No or *, insert/unplug all ROMs TAX:PLA:TAY:TXA:PHA :\ Y=, SP=>options LDX &F5:JSR InsertUnplugX:\ Insert or Unplug this ROM PLA :\ Get option %ULIQxxxx .InsertOption EOR #&20:BEQ InsertMe :\ %xxIxxxxx - Insert EOR #&A0:BNE InsertDone :\ %Uxxxxxxx - Unplug BEQ UnplugMe :\ Remove me from ROM table .InsertMe JSR ChkRomHeader :\ Check ROM header and get ROMTYPE .UnplugMe LDX &F5:STA ROMTABLE,X :\ Insert or remove from ROM table .InsertDone RTS : \ Insert or unplug ROMs \ -------------------------------- .L8D94 \ On entry, CC=* - silent \ CS= - prompt \ A=options \ SP=>ins/unp TAX:PLA:TAY:TXA:PHA :\ X=options, Y=ins/unp, SP=>options LDX #&0F :\ Start at ROM 15 .InsUnpLoop PHP:TYA:PHA :\ Save silent flag, ins/unp BCC InsUnpSilent :\ Skip prompt if *INSERT/UNPLUG * JSR L9030 :\ Print ROM info and prompt 'Y/N' (A,Y corrupted) BCS InsUnpSkip :\ Skip if 'N' .InsUnpSilent PLA:TAY:PHA :\ Y=Insert/Unplug STX &F5:JSR InsertUnplugX:\ Insert or Unplug this ROM, corrupts A,X,Y TSX:LDA &103,X :\ A=options LDX &F5:JSR InsertOption :\ Deal with (I)(U) options .InsUnpSkip PLA:TAY:PLP :\ Get ins/unp and silent flag back DEX:BPL InsUnpLoop :\ Loop down from 15 to 0 PLA :\ Drop options RTS : \ Insert or Unplug a ROM \ ---------------------- \ A=ROM, Y=&FF, unplug ROM \ A=ROM, Y=&00, insert ROM \ \ Update, do via OSBYTE 162 \ .InsertUnplug TAX .InsertUnplugX JSR XtoBitmap :\ A=2^X, CC=0-7, CS=8-15 INY:BNE InsertThisRom :\ Y was &00, jump to insert BCC P%+3:INY ORA L0D6E,Y:STA L0D6E,Y :\ Store into bitmap RTS .InsertThisRom EOR #&FF:BCS P%+3:DEY AND L0D6E,Y:STA L0D6E,Y :\ Store into bitmap RTS \ *SRLOCK () \ =============== .SRLOCK LDA #1 :\ A=1 to lock : \ *SRUNLOCK () \ ================= .SRUNLOCK :\ Entered with A=0 to unlock PHA:JSR L8CA0 :\ Save lock/unlock flag, scan to A BNE P%+3:SEC :\ No given, lock/unlock all ROMs TAX:PLA:TAY :\ X=, Y=lock/unlock flag BCC LockUnlockROM :\ given, lock/unlock that ROM :\ No given, drop into lock/unlocal all : \ 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 :\ X=offset to lock register OPT FNif(TARGET%>2) LDA &FE34:PHA :\ Get current 1MHz bus selection ORA #&20:STA &FE34 :\ Select cartridge bus OPT FNendif STA &FC00,X :\ write to lock register OPT FNif(TARGET%>2) PLA:STA &FE34 :\ Restore 1MHz bus selection OPT FNendif .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 \ ------------------------------- \ On entry, X=ROM \ On exit, CS='N', CC='Y' \ A,Y corrupted \ X preserved .L9030 TXA:PHA:JSR PrRomInfo :\ Print information on ROM X BCS L9062 :\ ROM is empty 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' .L9062 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 \ \ On exit, CS=nothing displayed, ROM empty, not RAM, not EEPROM \ CC=something displayed, occupied, or RAM, or EEPROM .PrRomInfo CLC .PrRomInfoAll PHP: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 or EEPROM .RomInfoDup PLA:TAX:PLP:BCS RomInfo2 :\ List all ROMs SEC:RTS :\ No ROM header, no SRAM/EEPROM \ stack=> romtype, Cy=ROM header, Y=SRAM .PrRomInfo1 PLA:TAX :\ X=romtype, Cy=header, Y=sram PLA :\ Drop 'all ROMs' flag .RomInfo2 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 LDA L0D6D:AND #&8F CMP &F5: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:BEQ L917C :\ X position=0, finish .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 ScanDec4 :\ Scan OPT FNif(VALver$<1.337) TAX OPT FNendif 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 and trailing spaces OPT FNif(VALver$<1.337) JSR SkipSpaces :\ Now pointing to or .srgetrom JSR ScanDec4: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 OPT FNelse .srgetnum TYA:PHA:DEY :\ Save current parameter .srgetlp1 INY .srgetlp2 JSR CheckDigit:BCC srgetlp2 :\ Step past digits JSR SkipSpaces CMP #ASC"+":BEQ srgetlp1 :\ Step past '+' as well JSR CheckDigit:BCS srgetok :\ Found the PLA:DEY:BCC srgetnum :\ Loop to next param .srgetok PLA:TAY:JSR ScanDec4 :\ Get the OPT FNendif .srWipeRom OPT FNif(VALver$<1.337) TXA OPT FNendif PHA:PHA :\ Stack padding for , stack : \ Now pointing to any trailing options or OPT FNif(VALver$<1.337) DEY:JSR srOptions :\ Scan trailing options OPT FNelse JSR srOptionsSpc :\ Scan trailing options OPT FNendif 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 :\ Get , set &F5= EOR &F4 :\ Compare to myself (preserve Cy) BEQ errRomLocked :\ Can't write to myself PHP:BCC srPrecheck1 :\ No (U)nlock option LDX &F5:LDY #0 :\ X=, Y=unlock JSR LockUnlockROM :\ Unlock this ROM .srPrecheck1 JSR RomTest :\ Check ROM type in bank &F5 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 \ On return, b7 downwards -> ULIQxxxX .srOptionsSpc JSR SkipSpaces .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" :\ b0...b7, b0=no options at all : \ Select sub-bank in ROM in &F5, X=page select \ -------------------------------------------- .RomPage LDA #RomPageEnd-RomPageStart :\ Length of stacked code LDY #(RomPageEnd-RomCopyStart-1)AND255 :\ Offset to end of stacked code BNE StackCopySetupY :\ Jump to stack it and call it : \ 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 LDX #0 .StackCopySetupY STX &AD :\ Entry value for Y 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 &AD: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 .RomStackStart .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 \ to do, this needs to explicitly check if bit 6 is toggling, not check for equality \ a locked EEPROM will toggle, but then return original data, resulting in a fixed loop \ Can return to caller Y=0 for Ok, or Y=63 for failed 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 CMP &AAA2 :\ Wait for floating bus to settle 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 \ Routine copied to stack to select sub-banks \ ------------------------------------------- \ A=old ROM, X=ROM to select, Y=paging value .RomPageStart PHA:JSR &100 :\ Select SRAM/SROM bank STY &AFFF:STY &AFFF:STY &AFFF:\ Select sub-bank PLA:TAX .RomPageSelect STX &F4:LDA #12:STA ROMSEL STX ROMSEL:RTS :\ 26 bytes .RomPageEnd \ ************* \ 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 #&00: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:ORA #ASC"4":PHA :\ Save ASCII floppy drive number for later 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%AND2):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 PLA:PHA :\ 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 ASCII drive number LDX #&A8:LDY #0 :\ Do '*MOUNT' LDA #3:JMP (FSCV) :\ Pass '*MOUNT' to filing system .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 \ 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 : .Hugo EQUS "Hugo" : .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