OS SERIES 9 GEOFF COX ************************************************************************* * * * OSBYTE 140 *TAPE * * selects TAPE filing system * * * * OSBYTE 141 *ROM * * selects ROM filing system * * * ************************************************************************* F135 EOR #&8C ;if it's *TAPE A=0 *ROM A=1 F137 ASL ;double it F138 STA &0247 ;store it in filing system flag store F13B CPX #&03 ;if X>=3 C set X=3 Z set F13D JMP &F14B ; ******** set cassette options ******************************************* ;called after BREAK etc ;lower nybble sets sequential access ;upper sets load and save options ;0000 Ignore errors, no messages ;0001 Abort if error, no messages ;0010 Retry after error, no messages ;1000 Ignore error short messages ;1001 Abort if error short messages ;1010 Retry after error short messages ;1100 Ignore error long messages ;1101 Abort if error long messages ;1110 Retry after error long messages F140 PHP ;save flags F141 LDA #&A1 ;set sequential access abort if error, no messages F143 STA &E3 ;set load/save retry if error, short messages F145 LDA #&19 ;set interblock gap F147 STA &03D1 ;and store it F14A PLP ;get back flags F14B PHP ;push flags F14C LDA #&06 ;'filing system taking over' call to FSCV F14E JSR &E031 ;call OSFSC F151 LDX #&06 ; F153 PLP ;get back flags F154 BEQ &F157 ;if Z set earlier F156 DEX ;do not decrement X F157 STX &C6 ;set current baud rate X=5 300 baud X=6 1200 baud ********* CFS/RFS claim FILEV,ARGSV,BGETV,BPUTV,GBPBV,FINDV,FSCV ********** ********** set to F27D, F18E, F4C9, F529, FFA6, F3CA, F1B1 **************** F159 LDX #&0E ;CLAIM FILING SYSTEM VECTORS F15B LDA &D951,X ; F15E STA &0211,X ; F161 DEX ; F162 BNE &F15B ; F164 STX &C2 ;&C2=&00 set progress flag = idle F166 LDX #&0F ;set X to make ROM service call &0F, vectors changed ************************************************************************* * * * OSBYTE 143 * * Pass service commands to sideways ROMs * * * ************************************************************************* ; On entry X = service call number ; Y = any additional parameter ; On exit X=0 if claimed, or preserved if unclaimed ; Y = any returned parameter ; When called internally, EQ set if call claimed F168 LDA &F4 ; Get current ROM number F16A PHA ; Save it F16B TXA ; Pass service call number to A F16C LDX #&0F ; Start at ROM 15 ; Loop through all 16 ROMs F16E INC &02A1,X ; Read bit 7 on ROM type table F171 DEC &02A1,X ; F174 BPL &F183 ; If not set (+ve result), step to next ROM down F176 STX &F4 ; Otherwise, select this ROM, &F4 RAM copy F178 STX &FE30 ; Page in selected ROM F17B JSR &8003 ; Call the ROM's service entry ; X and P do not need to be preserved by the ROM F17E TAX ; On exit pass A to X to chech if claimed F17F BEQ &F186 ; If 0, service call claimed, reselect ROM and exit F181 LDX &F4 ; Otherwise, get current ROM back F183 DEX ; Step to next ROM down F184 BPL &F16E ; Loop until done ROM 0 F186 PLA ; Get back original ROM number F187 STA &F4 ; Set ROM number RAM copy F189 STA &FE30 ; Page in the original ROM F18C TXA ; Pass X back to A to set zero flag F18D RTS ; And return ************************************************************************* * * * CFS OSARGS entry point * * * ************************************************************************* F18E ORA #&00 ;is A=00 F190 BNE &F1A2 ;if not return F192 CPY #&00 ;is Y=0 F194 BNE &F1A2 ;if not return F196 LDA &C6 ;else get current baud rate and zero bit 2 F198 AND #&FB ;C6=5 becomes 1, 6 becomes 2 F19A ORA &0247 ;if cassette selected A=0 else A=2 F19D ASL ;multiply by 2 F19E ORA &0247 ;Or it again F1A1 LSR ;divide by 2 F1A2 RTS ;return cassette =0 ************************************************************************* * * * CFS/RFS FSC DISPATCH TABLE * * * ************************************************************************* F1A3 DB 4C,F5 ; 0 *OPT (F54C) F1A5 DB 1D,F6 ; 1 check EOF (F61D) F1A7 DB 04,F3 ; 2 */ (F304) F1A9 DB 0F,E3 ; 3 unknown command (E30F) F1AB DB 04,F3 ; 4 *RUN (F304) F1AD DB 2A,F3 ; 5 *CAT (F32A) F1AF DB 74,E2 ; 6 New filing system (E274) ************************************************************************* * Filing System control entry OSFSC * * Entry via 021E FSCV * * A = FSC function * ************************************************************************* ;on entry A is reason code ;A=0 A *OPT command has been used X & Y are the 2 parameters ;A=1 EOF is being checked, on entry X=File handle on Exit X<>&00 = EOF exists, X=&00 = not at EOF ;A=2 A */ command has been used *RUN the file ;A=3 An unrecognised OS command has ben used X,Y point at command ;A=4 A *RUN command has been used X,Y point at filename ;A=5 A *CAT cammand has been issued X,Y point to rest of command ;A=6 New filing system about to take over, close SPOOL & EXEC files ;A=7 Return in X and Y lowest and highest file handle used ;A=8 OS about to process *command F1B1 CMP #&07 ;if A>6 F1B3 BCS &F1A2 ;goto F1A2 (RTS) F1B5 STX &BC ;else save X F1B7 ASL ;A=A*2 F1B8 TAX ;X=A to get offset F1B9 LDA &F1A4,X ;get hi byte of address-1 F1BC PHA ;push it F1BD LDA &F1A3,X ;get lo byte of address-1 F1C0 PHA ;push it F1C1 LDX &BC ;get back X F1C3 RTS ;this now jumps to the address got from the table +1 ************************************************************************* * * * LOAD FILE * * * ************************************************************************* F1C4 PHP ;save flags on stack, allows sibroutines to turn off IRQs F1C5 PHA ;save load/run action F1C6 JSR &FB27 ; Set &BB to load/save options, set &C7=6 for load/save block gap ;claim serial system for cassette F1C9 LDA &03C2 ;execution address LO F1CC PHA ;save A on stack F1CD JSR &F631 ;search for file F1D0 PLA ;get back A F1D1 BEQ &F1ED ;if A=0, RUN, use file's own load address, go to F1ED F1D3 LDX #&03 ;else X=3 F1D5 LDA #&FF ;A=&FF F1D7 PHA ;save A on stack F1D8 LDA &03BE,X ;get load address F1DB STA &B0,X ;store it as current load address F1DD PLA ;get back A F1DE AND &B0,X ;test for &FFFFFFFF load address F1E0 DEX ;X=X-1 F1E1 BPL &F1D7 ;until all 4 bytes copied F1E3 CMP #&FF ;if all bytes contain don't contain &FF F1E5 BNE &F1ED ;continue F1E7 JSR &FAE8 ;else sound bell, reset ACIA & motor off F1EA JMP &E267 ;'Bad Address' error F1ED LDA &03CA ; Get block flag F1F0 LSR ; Set carry from Locked flag in bit 0 F1F1 PLA ; Get action back F1F2 BEQ &F202 ; If A=0, *RUN, jump to F202 to test Locked flag F1F4 BCC &F209 ; A<>0, *LOAD, if unlocked, jump to load *************** LOCKED FILE ROUTINE ************************************* F1F6 JSR &FAF2 ; Release Tube and reset serial system F1F9 BRK ; F1FA DB &E5 ;error number F1FC 'Locked' ; F201 BRK ; F202 BCC &F209 ; Carry clear, unlocked, jump to F209 to load file F204 LDA #&03 ; else A=3 F206 STA &0258 ; store to cause ESCAPE disable and memory clear on break F209 LDA #&30 ; F20B AND &BB ; Get current error OPTions F20D BEQ &F213 ; If all errors ignored, skip checking checksum F20F LDA &C1 ; Else get checksum result F211 BNE &F21D ; If checksum not ok, jump to F21D to... F213 TYA ; A=Y F214 PHA ; Save Y on stack F215 JSR &FBBB ; Claim Tube, start Host->Tube transfer F218 PLA ; F219 TAY ; Get Y back F21A JSR &F7D5 ; Set block offset=0, status='load data block' F21D JSR &F9B4 ; Load data block F220 BNE &F255 ; If not found return to search F222 JSR &FB69 ; Increment current block number F225 BIT &03CA ; Test block flag F228 BMI &F232 ; If bit 7=1 then this is last block so jump to F232 F22A JSR &F96A ; Else increment current load address F22D JSR &F77B ; Read next block header F230 BNE &F209 ; And loop back to F209 ******** store data in OSFILE parameter block *************************** \ BUG! &C8/9 only set when called from OSFILE, will not be set by *RUN \ BUG! &CD/E only updated when *OPT 1,2 has been used F232 LDY #&0A ; Y=>length in control block F234 LDA &CC ; File length counter low F236 STA (&C8),Y ; Store in OSFILE parameter block F238 INY ; Y=Y+1 F239 LDA &CD ; File length counter high F23B STA (&C8),Y ; Store in OSFILE parameter block F23D LDA #&00 ; Always return 16-bit length ; &CE/&CF is unused, could just use 4-byte loop F23F INY ; Y=Y+1 F240 STA (&C8),Y ; Store in OSFILE parameter block F242 INY ; Y=Y+1 F243 STA (&C8),Y ; Store in OSFILE parameter block F245 PLP ; Get flags back F246 JSR &FAE8 ; Ring bell, reset ACIA & motor F249 BIT &BA ; Test if error reported, set in current block flag F24B BMI &F254 ; If bit 7 set, already reported an error, skip F24D PHP ; Save flags on stack F24E JSR &FA46 ; Print message following call (in this case NEWLINE!) F251 DB &0D,&00 ; could be replaced by single JSR OSNEWL call F253 PLP ; Restore flags F254 RTS ; And return ************RETRY AFTER A FAILURE ROUTINE ******************************* F255 JSR &F637 ;search for a specified block F258 BNE &F209 ; loop back to F209 *********** Read Filename using General String Readerr ****************** ;filename pointed to by X and Y F25A STX &F2 ;OS filename/command line pointer lo F25C STY &F3 ;OS filename/command line pointer hi F25E LDY #&00 ;Y=0 F260 JSR &EA1D ;initialise GS string reading F263 LDX #&00 ;X=0 F265 JSR &EA2F ;call GSREAD F268 BCS &F277 ;if end of character string F277 F26A BEQ &F274 ;if CHR$0 jump to error as &00 used as a terminator F26C STA &03D2,X ;store character in CFS filename area F26F INX ;increment character count F270 CPX #&0B ;if X<>11 F272 BNE &F265 ;loop for up to ten characters F274 JMP &EA8F ;else Bad String error ************* terminate Filename **************************************** F277 LDA #&00 ;terminate filename with 0 F279 STA &03D2,X ; F27C RTS ;return ************************************************************************* * * * OSFILE ENTRY * * * * on entry A determines action * * A=0 save block of memory as a file * * A=1 write catalogue info for existing file * * A=2 write load address only for existing file * * A=3 write execution address only for existing file * * A=4 write attributes only for existing file * * A=5 Read catalogue info, return file type in A * * A=6 Delete named file * * A=&FF load the named file if lo byte of Exec address=0 use * * address in parameter block else files own load address * * X,Y point to parameter block * * bytes 0,1 filename address, 2-5 load,6-9 exec,A-D length or * * start of data for save, 0E End address /attributes * ************************************************************************* ;parameter block located by XY ;0/1 Address of Filename terminated by &0D ;2/4 Load Address of File ;6/9 Execution Address of File ;A/D Start address of data for write operations or length of file ; for read operations ;E/11 End address of Data; i.e. byte AFTER last byte to be written ; or file attributes ; ;On Entry action is determined by value in A ; ;A=0 Save section of memory as named file, write catalogue information ;A=1 Write catalogue information for named file ;A=2 Write the LOAD address (only) for the named File ;A=3 Write the EXECUTION address (only) for the named File ;A=4 Write the ATTRIBUTES for the named File ;A=5 Read the named files catalogue information Place file type in A ;A=6 Delete the named file ;A=&FF Load the named file and read its catalogue information F27D PHA ;save A on stack F27E STX &C8 ;osfile block pointer lo F280 STY &C9 ;osfile block pointer hi F282 LDY #&00 ;Y=0 F284 LDA (&C8),Y ;OSFILE parameter block F286 TAX ;X=A F287 INY ;Y=Y+1 F288 LDA (&C8),Y ;OSFILE parameter block F28A TAY ;Y=A F28B JSR &F25A ;get filename from BUFFER F28E LDY #&02 ;Y=2 F290 LDA (&C8),Y ;copy parameters to Cassette block at 3BE/C5 F292 STA &03BC,Y ;from LOAD and EXEC address F295 STA &00AE,Y ;make second copy at B0-B8 F298 INY ;Y=Y+1 F299 CPY #&0A ;until Y=10 F29B BNE &F290 ; F29D PLA ;get back A F29E BEQ &F2A7 ;if A=0, jump to do SAVE F2A0 CMP #&FF ;else if A<>&FF F2A2 BNE &F254 ;RETURN as cassette has no other options F2A4 JMP &F1C4 ;if A=&FF, jump to do LOAD ************** Save a file ********************************************** F2A7 STA &03C6 ; Zero block number low F2AA STA &03C7 ; Zero block number high F2AD LDA (&C8),Y ; Copy start/end from control block F2AF STA &00A6,Y ; Store to zero page copy (&B0 to &B7) F2B2 INY ; Data start and data end address F2B3 CPY #&12 ; Loop until Y=18 F2B5 BNE &F2AD ; F2B7 TXA ; A=X F2B8 BEQ &F274 ; If X=0 no filename found so jump to 'Bad string' error F2BA JSR &FB27 ; Set load/save cassette options into &BB, set C7=6 ; Claim serial system for cassette F2BD JSR &F934 ; Prompt to start recording, generate error if ROMFS F2C0 LDA #&00 ; A=0 F2C2 JSR &FBBD ; Claim Tube for Tube->Host transfers F2C5 JSR &FBE2 ; Set up CFS for write operation ; Loop to save blocks F2C8 SEC ; Set carry flag F2C9 LDX #&FD ; X=&FD F2CB LDA &FFB7,X ; Calculate 24-bit end-start F2CE SBC &FFB3,X ; F2D1 STA &02CB,X ; Store remaining length in block header F2D4 INX ; Overlaps into block flag to allow &10000 F2D5 BNE &F2CB ; F2D7 TAY ; Check length b16-b23 F2D8 BNE &F2E8 ; Jump if length>&FFFF F2DA CPX &03C8 ; Check length b0-b7, CC if len<>&xx00, CS if len=&xx00 F2DD LDA #&01 ; A=1 F2DF SBC &03C9 ; Subtract block length high, A=number of blocks to save F2E2 BCC &F2E8 ; If carry clear, 256 or more bytes, jump to save F2E4 LDX #&80 ; If length<257, X=&80, b7=last block F2E6 BNE &F2F0 ; Jump F2F0 F2E8 LDA #&01 ; Set block length=256 F2EA STA &03C9 ; block length high F2ED STX &03C8 ; block length F2F0 STX &03CA ; block flag, flags=&00 not last block, or &80 last block F2F3 JSR &F7EC ; Write block to Tape F2F6 BMI &F341 ; If negative, all done, return F2F8 JSR &F96A ; Increment current start address F2FB INC &03C6 ; Increment block number low F2FE BNE &F2C8 ; If not 0, loop back to save next block F300 INC &03C7 ; Increment block number high F303 BNE &F2C8 ; And loop back ************************************************************************* * * * *RUN ENTRY * * * ************************************************************************* F305 JSR &F25A ;get filename from BUFFER F308 LDX #&FF ;X=&FF F30A STX &03C2 ;execution address F30D JSR &F1C4 ;load file F310 BIT &027A ; &FF if tube present F313 BPL &F31F ; No Tube present, enter at I/O address F315 LDA &03C4 ; Get execution address b16-b23 F318 AND &03C5 ; AND with execution address b24-b31 F31B CMP #&FF ; If exec is not &FFFFxxxx, jump to I/O address F31D BNE &F322 ; If exec<>&FFFFxxxx, call Tube F31F JMP (&03C2) ; Call file in I/O via exec address F322 LDX #&C2 ; Point XY to exec address at &03C2 F324 LDY #&03 ; F326 LDA #&04 ; Tube call 4=Execute code F328 JMP &FBC7 ; And issue to Tube to run file ************************************************************************* * * * *CAT ENTRY * * * ************************************************************************* ;CASSETTE OPTIONS in &E2 ;bit 0 input file open ;bit 1 output file open ;bit 2,4,5 not used ;bit 3 current CATalogue status ;bit 6 EOF reached ;bit 7 EOF warning given F32B LDA #&08 ;A=8 F32D JSR &F344 ;set status bits from A F330 JSR &FB27 ;Set cassette options into (BB),set C7=6 ;claim serial system for cassette F333 LDA #&00 ;A=0 F335 JSR &F348 ;search for a header F338 JSR &FAFC ;perform read F33B LDA #&F7 ;A=&F7 F33D AND &E2 ;clear bit 3 of CFS status bit, not cataloging F33F STA &E2 ; F341 RTS ;return F342 LDA #&40 ;set bit 6 of E2 cassette options, EOF met F344 ORA &E2 ; F346 BNE &F33F ;and Jump F33F ********** search routine *********************************************** F348 PHA ;save A on stack, A=0 for CAT, A<>0 for LOAD F349 LDA &0247 ;filing system flag 0=CFS 2=RFS F34C BEQ &F359 ;if CFS, jump to read header F34E JSR &EE13 ;set current ROM/PHROM to &EF F351 JSR &EE18 ;get byte from ROM/PHROM, CC=byte returned, CS=no response F354 BCC &F359 ;if carry clear, jump to read header F356 CLV ;clear overflow flag F357 BVC &F39A ;jump to return with VC, CS *********** CFS/RFS read header ******************************************** F359 JSR &F77B ;read block header F35C LDA &03C6 ;block number F35F STA &B4 ;current block no. lo F361 LDA &03C7 ;block number hi F364 STA &B5 ;current block no. hi F366 LDX #&FF ;X=&FF F368 STX &03DF ;set copy of last read block flag to &FF F36B INX ;X=X+1 F36C STX &BA ;set current block flag to &00 F36E BEQ &F376 ;jump to F376 F370 JSR &FB69 ;inc. current block no. F373 JSR &F77B ;read block header F376 LDA &0247 ;get filing system flag 0=CFS 2=RFS F379 BEQ &F37D ;if CFS F37D F37B BVC &F39A ;if V clear F39A F37D PLA ;get back A F37E PHA ;save A on stack F37F BEQ &F3AE ;if A=0, CAT, skip checking filename match F381 JSR &FA72 ;else check filename header block matches searched filename F384 BNE &F39C ;filename doesn't match, jump to keep searching F386 LDA #&30 ;else A=&30 to read bits 4/5 of current OPTions F388 AND &BB ;current error OPTions F38A BEQ &F39A ;if ignore all errors, don't check block number F38C LDA &03C6 ;block number F38F CMP &B6 ;compare with expected block no. lo F391 BNE &F39C ;wrong block F393 LDA &03C7 ;loaded block number hi F396 CMP &B7 ;compare with expected block no. hi F398 BNE &F39C ;wrong block F39A PLA ;get back A F39B RTS ;matching file header found, return ; F39C LDA &0247 ;filing system flag 0=CFS 2=RFS F39F BEQ &F3AE ;if tape, jump to go back to searching F3A1 JSR &EEAD ;ROMFS, use ROM displacement address F3A4 LDA #&FF ;set block number to &FFFF F3A6 STA &03C6 ;block number lo F3A9 STA &03C7 ;block number hi F3AC BNE &F370 ;jump F370 F3AE BVC &F3B5 ;if overflow clear F3B5 F3B0 LDA #&FF ;A=&FF F3B2 JSR &F7D7 ;set flags F3B5 LDX #&00 ;X=0 F3B7 JSR &F9D9 ;report 'DATA?' F3BA LDA &0247 ;filing system flag 0=CFS 2=RFS F3BD BEQ &F3C3 ; F3BF BIT &BB ;current OPTions F3C1 BVC &F3A1 ;long messages not required if BIT 6 =0 F3C3 BIT &03CA ;block flag F3C6 BMI &F3A4 ;if -ve F3A4 F3C8 BPL &F370 ;else loop back and do it again