;Disassembly of Opus EDOS 0.4 ;Greg Cook, 21 August 2023 ;Hints on Tube host code (all attributed): ;(NAUG) M. Holmes and A. Dickens, The new advanced user guide for ; the BBC Microcomputer (Cambridge: Adder, 1987) ;(SB) Steven Bass's comments on Opus EDOS 0.4, ; http://regregex.bbcmicro.net/edos04.asm.txt ;(JGH) J. G. Harston's disassembly of the Tube host code, ; http://mdfs.net/Software/Tube/BBC/Host.lst ;Comments beginning with capital letters are entry points ;Unused code does not label the used code ;_UNUSED Assemble unused code and data ;Symbol: _UNUSED ;Source: http://wouter.bbcmicro.net/bbc/bestanden/roms-2009.01.28.zip ;Path: roms/kopie_van_disk/Opus/Opus_EDOS__0.4 ;Banner version: 0.4 ;Code length: &3531 (=&3F28-&09F7) ;Acorn CRC: &5523 ;PKZIP CRC: &1D8A3860 ;XFER CRC: &EA30334D ;Cksum: 1245836096 ;This is a commented disassembly of the original release from 1984. ;A patched edition is available which fixes most of the faults and ;shortcomings of the original, and provides some improvements: ; http://regregex.bbcmicro.net/#prog.edospat ;Summary ; ;A filing system written by Alan Williams in 1984, running on the ;7-chip WD2791 interface board. It fully implements both the single ;density Acorn DFS disc format and the double density Opus DDOS format. ;Its interface is compatible with these filing systems but presents ;significant differences to both programs and users: the command syntax ;resembles Challenger rather than DDOS, there is no *TAPEDISK facility ;and the ROM does away with the full screen displays of DDOS. PAGE is ;slightly lower than normal at &1700. ; ;EDOS maintains a default filename: if a filename passed to EDOS for ;resolution has an empty leaf name, EDOS substitutes the previous leaf ;name passed to it. The default drive, volume and directory, however, ;come from the most recent arguments to *DRIVE, *VOL and/or *DIR. The ;combined default filename is displayed in the *CAT catalogue header. ;SAVE "", for example, overwrites this file, which is not necessarily ;the file most recently accessed; *INFO displays details of the default ;file. ; ;Leaf names consisting of one to seven spaces (thus non-empty) are valid ;and equivalent. As always, EDOS pads a leaf name with spaces to seven ;characters to store it in its workspaces and the catalogue. While such ;a name is the last one mentioned, $., F. etc. and the empty string ;refer to files whose leaf names are all spaces. This state persists ;until a leaf name containing non-space characters is accessed. ; ;On hard reset the default filename is initialised to ":0A.$. " [sic]. ; ;A further refinement over DDOS is a modification of the catalogue ;format to allow a file, and thus a volume, to fill the data area of a ;double density disc surface: 355 KiB physically, 511 KiB logically. ;Only random access calls can handle the largest files, in this version ;of the code; the original use case of this feature is unclear. ; ;The firmware is stable (at version 0.4) and assembled in modules, but ;lacks some aspects of Acorn DFS behaviour which can cause compatibility ;problems. A third-party patch has since been produced which brings the ;API up to Acorn DFS standards. ; ;EDOS, in its near-finished form, is likely to have been a prototype for ;a DDOS-compatible filing system using one page of main workspace, with ;a view either to accompanying the new WD 1770 controller board or to ;forming the basis of firmware for the upcoming Challenger unit. It ;probably did circulate albeit in a very small quantity. Although the ;Challenger had plenty of RAM on board, keeping the workspace on one ;page would have reduced the amount of paging required, making it easier ;to code its internal operations. EDOS is also greatly simplified with ;2.5 KiB less code than either DDOS or Challenger, although its API ;shortcomings and the lack of RAM disc support account for some of the ;reduction. ; ;Williams probably developed EDOS, from scratch, between the earliest ;completion of DDOS and the end of 1984. DDOS was announced in December ;1983 and is first dated to 27 March 1984; its retargeting to the ;Challenger unit took place between June and October 1985. A lost early ;edition of DDOS is thought to be the source of the specification, via ;an imperfect reverse-engineering process; this conjectured prototype in ;turn bears minor API differences from its parent, Acorn DFS, besides ;those relating to double density operation. However the *LOCK and ;*UNLOCK commands, and the curious 'modal PTR' behaviour emulate those ;features in Acorn System DOS whose housekeeping memory, as with EDOS, ;occupies a single page. EDOS may be the only filing system on the BBC ;Micro to implement its pointers this way (at the cost of compatibility ;with tricky programs) and is certainly one of the exceptional DFS- ;compatible filing systems not to derive from the Acorn codebase. ; ;Assembly of the extant ROM image began on a DDOS-equipped testbed ;machine, and continued under an intermediate EDOS ROM once all basic ;functions were in place. That DDOS is the disc interface board's ;original firmware is proved by the layout of the control latch for its ;convenience, whereas EDOS has to translate its internal variables to ;the appropriate latch value. The ROM title and copyright message imply ;that the ROM is a commission by Opus Supplies, in such form as Williams ;delivered it. ; ;In the end the Challenger ROM was based on DDOS code, with user ;interface and logic changes imported from EDOS, showing that the author ;of DDOS had received and incorporated EDOS concepts. ;Assembly ; ;To assemble EDOS, Williams first generated a 16 KiB master file on disc ;filled, for convenience, with byte values &80 to &BF in groups of 256. ;A *SAVE command saving the address space of an empty paged ROM socket ;to disc yields a file with these contents, although as the data bus is ;undriven while it is read, glitches may appear. ;If this was the case here then an Opus DDOS ROM most likely performed ;the save, as it provides for switching in another paged ROM bank during ;disc operations - Acorn DFS would have copied out its own code. From ;this it appears that EDOS was developed from start to finish on its ;WD 2791-equipped testbed, with an early version of DDOS installed until ;a preliminary EDOS ROM took over. ; ;Next, Williams inserted entries in the volume catalogue (hardlinks) ;creating files that overlapped the master file. The starting LBA of ;each hardlink was offset from that of the master file by an amount ;corresponding to the high byte of the base address of the module it ;would contain. Reading a byte or two from the hardlink, and comparing ;the byte value from the underlying master file with the high byte of ;the base address would show that the LBA was correct. ; ;He then developed from scratch for each module an assembly source file, ;likely a BBC BASIC program with embedded assembly language as described ;in the BBC Microcomputer User Guide. Every module begins with a table ;of global entry points whose addresses are fixed and shared with all ;source files; internal symbols are held in memory only while the module ;is assembled. This keeps memory requirements and development costs low ;but forces the global tables to be included in the ROM, the free space ;fragmented and the module locations planned in advance. ; ;Each source file being independent, Williams was able to reassemble ;modules individually as he made improvements. The assembly programs ;wrote their object code into the respective hardlink using OSBPUT ;calls, since saving the image with OSFILE would move the hardlink to an ;unoccupied part of the disc. Assembling each module thus rewrote ;certain sectors of the master file, linking the module automatically. ;In the process, arbitrary data migrated between sectors - and sometimes ;between modules - as the final sector of each module would be written ;out from the random access sector buffer, containing a remnant of data ;from the last sector visited. ;Most sources opened their hardlink using OPENOUT, overwriting its ;previous contents. The Tube service code assembler, on the other hand, ;altered a persistent 1 KiB module file initially prepared with padding ;zeroes and ending with version 1.10 of Acorn's Tube host code. This ;afforded Williams the use of OPENUP and BPUT# to inject his Tube ;service code at the start of the file without disturbing or seeking ;past the object code. ; ;Eventually, the developing EDOS became a viable filing system and was ;installed on the development machine. Later assemblies can be ;distinguished as EDOS clears the sector buffer when a random access ;file extends into a new sector. ;Williams continued to assemble modules until version 0.4 was complete; ;then the extant EPROM was programmed from the master file some time ;after its manufacturing date in mid-May 1984 (date code 8420). ;Layout ; ;The modules of EDOS are laid out as follows:- ;No Addresses Description Unused space ; 1 &8000..&80CE Paged ROM header and service Blank ; 2 &8100..&83A5 Keyword recognition and help Blank ; 3 &8400..&8599 Utilities Copy of previous page ; 4 &8600..&899E 'Light' DFS commands Copy of previous page ; 5 &8A00..&8F4D 'Medium' DFS commands Blank ; 6 &9000..&91C8 Console output subsystem Blank ; 7 &9200..&92B9 Macro functions and misc. Old version module 16 ; 8 &9300..&954C Parsing and validation Blank ; 9 &9600..&974B EDOS setup Blank ;10 &9800..&9A72 Channel operations Blank ;11 &9B00..&9DDE Disc operations Blank ; - &9E00..&9FFF - Master file ;12 &A000..&A3FF Tube hosting - ;13 &A400..&A4B6 EDOS console output Blank ;14 &A500..&A5EC File selection Old version module 11 ;15 &A600..&A8BE Catalogue operations Blank ;16 &A900..&AEBF 'Heavy' DFS commands Blank ; - &AF00..&AFFF - Older version module 16 ;17 &B000..&B394 EDOS API, part 1 Blank ;18 &B400..&B6FF EDOS API, part 2 - ;19 &B700..&B92A Monitor Copy of previous page ;20 &BA00..&BF27 EDOS API, part 3 Blank ; ;The majority of modules have their slack space cleared, and it is ;conceivable that they are the least recent ones built and that a non- ;blanking filing system inserted the rest later. However the sources of ;all transclusions, modules 11 and 16, are both assembled blanked; it ;would imply that Williams had built newer versions of these modules, ;without replacing them in the master file, before assembling modules 7 ;and 14; and the cleared module 16 mostly overwrites a longer, unblanked ;assembly in a way that this hypothesis cannot explain. The CLC at ;&ADE6 is a correction added versus the code in page &AF, and so its ;disappearance in reverse time cannot be construed as an optimisation. ; ;As the blanked modules are therefore unlikely to represent a total ;rebuild late in the history of the project, Williams appears to have ;worked on this ROM image incrementally, installing an intermediate ;version of it before the final assembly of most of the modules. ; ;An odd feature of the *command and *HELP keyword tables is that the ;byte terminating each keyword - which always has bit 7 set - is the ;offset of a syntax string and not the high byte of the action address, ;as usual. The action addresses are then allowed to point into main ;memory, suggesting that the EDOS build was once tested on a machine ;without sideways RAM fitted, but the gradual construction of EDOS 0.4 ;rules out testing in main memory during the observable history of the ;master file. ; ;The clever yet unwieldy build process shows signs of entrenching the ;module layout: unused pages are left in the middle of the image, and ;the page freed by condensing the 'heavy' DFS commands module is not ;reclaimed to expand part 2 of the API, shoehorned into three pages. ;It may even have led to the demise of this firmware, despite its ;potential: porting the source code from the presumed BBC BASIC/assembly ;hybrid to a professional assembly language was a tedious and ;unjustified task when Opus already had access to an adequate codebase ;in ASM format which was easier to repurpose. This was a shame as a ;flexible EDOS codebase would have readily yielded an API-complete, ;double density FS in 14 kilobytes with 2 KiB workspace required and 2 ;KiB empty at the end of the sideways ROM slot. ;The implication is obvious. Opus, already shipping sideways RAM ;boards, was closer than it realised to offering its own main-memory- ;freeing "E00 DFS" on an inboard, combined ROM+RAM circuit at a much ;lower price point than the external Challenger unit. ;Paged ROM header 8000 4C A6 80 JMP P0A6 ;Language entry (RTS) 8003 4C 2E 80 JMP P02E ;Service entry 8006 EQUB &82 ;rom type: service only 8007 EQUB &16 ;Copyright offset pointer 8008 EQUB &01 ;Version No. 8009 EQUS "OPUS EDOS" ;title 8012 EQUB &00 ;terminator byte 8013 EQUS "0.4" ;version string 8016 EQUB &00 ;terminator byte 8017 EQUS "(C) Alan Williams 1984";copyright pointer validated by MOS 802D EQUB &00 ;terminator byte ;Paged ROM service .P02E ;ROM service. 802E 20 03 B7 JSR S703 ;call monitor 8031 C9 01 CMP #&01 ;request absolute workspace 8033 F0 29 BEQ P05E 8035 C9 02 CMP #&02 ;request private workspace 8037 F0 2C BEQ P065 8039 C9 03 CMP #&03 ;boot 803B F0 45 BEQ P082 803D C9 04 CMP #&04 ;unrecognised OSCLI 803F F0 47 BEQ P088 8041 C9 08 CMP #&08 ;unrecognised OSWORD 8043 F0 49 BEQ P08E 8045 C9 09 CMP #&09 ;*HELP 8047 F0 4B BEQ P094 8049 C9 0A CMP #&0A ;claim absolute workspace 804B F0 4D BEQ P09A 804D C9 0F CMP #&0F ;vectors claimed 804F F0 49 BEQ P09A 8051 C9 12 CMP #&12 ;initialise filing system 8053 F0 48 BEQ P09D 8055 C9 FE CMP #&FE ;tube post initialisation 8057 F0 4E BEQ P0A7 8059 C9 FF CMP #&FF ;tube main initialisation 805B F0 54 BEQ P0B1 805D 60 RTS .P05E ;request absolute workspace 805E C0 16 CPY #&16 8060 B0 02 BCS P064 8062 A0 16 LDY #&16 ;we need 8 pages 0E..15 incl .P064 8064 60 RTS ; SVCE CALL 2 - CLAIM PRIVATE WORK SPACE ; A = SVCE CALL No., X = ROM No., Y = value of first free page. .P065 ;request private workspace 8065 48 PHA ;save on stack 8066 98 TYA ;save our page number in the 8067 9D F0 0D STA &0DF0,X ;OS ROM table 806A 85 A9 STA &A9 ;and in high byte of pointer 806C 18 CLC ;claim one page 806D 69 01 ADC #&01 806F A8 TAY 8070 68 PLA ;restore ROM call number 8071 20 00 92 JSR Q200 ;save AXY 8074 AD 8D 02 LDA &028D ;get last reset type 8077 F0 08 BEQ P081 ;if not 0 soft break 8079 A0 00 LDY #&00 ;then low byte of pointer =0 807B 84 A8 STY &A8 ;clear workspace flag in 807D A0 0D LDY #&0D ;byte &D of private page 807F 91 A8 STA (&A8),Y ;marking it uninitialised. .P081 8081 60 RTS .P082 8082 20 B7 80 JSR P0B7 ;test boot key 8085 B0 1A BCS P0A1 ;if okay boot the disc 8087 60 RTS ; SVCE CALL 4 - UNRECOGNISED * COMMAND ; On entry &F2 and &F3 point to the start of the string .P088 ;Unrecognised OSCLI 8088 20 03 81 JSR P103 ;scan it 808B B0 17 BCS P0A4 ;if we ran it break out 808D 60 RTS .P08E ;unrecognised OSWORD 808E 20 00 BA JSR SA00 ;compare OSWORD 8091 B0 11 BCS P0A4 ;with our codes && break out 8093 60 RTS .P094 ;*HELP 8094 20 06 81 JSR P106 ;search our topics 8097 B0 0B BCS P0A4 ;if specific to us break out 8099 60 RTS .P09A ;claim absolute workspace 809A 4C 06 96 JMP Q606 ;Wksp claim/vectors changed. .P09D ;Initialise FS 809D C0 04 CPY #&04 ;our FS ID = 4 809F D0 05 BNE P0A6 .P0A1 80A1 20 03 96 JSR Q603 .P0A4 ;Break out of ROM call chain 80A4 A9 00 LDA #&00 .P0A6 80A6 60 RTS .P0A7 ;Post-initialise Tube 80A7 C0 00 CPY #&00 80A9 F0 FB BEQ P0A6 ;edos ignores if Y=0 80AB 20 03 A0 JSR R003 ;otherwise it does post-init 80AE A9 00 LDA #&00 ;and consumes the call. 80B0 60 RTS .P0B1 ;Tube main init 80B1 20 00 A0 JSR R000 80B4 A9 00 LDA #&00 ;edos consumes this call 80B6 60 RTS .P0B7 ;Test boot key 80B7 20 00 92 JSR Q200 ;Save AXY 80BA A9 7A LDA #&7A 80BC 20 F4 FF JSR &FFF4 ;scan keyboard from code &10 80BF 8A TXA 80C0 30 09 BMI P0CB ;if no keypress C=1, allow boot 80C2 C9 32 CMP #&32 ;if key is not "D" disallow boot 80C4 D0 07 BNE P0CD ;return C=0 disallow boot 80C6 A9 78 LDA #&78 ;else 80C8 20 F4 FF JSR &FFF4 ;register keypress for 2KR .P0CB 80CB 38 SEC ;return C=1 allow boot 80CC 60 RTS .P0CD 80CD 18 CLC ;return C=0 disallow boot 80CE 60 RTS ;unused space from &80CF ;unused space ends at &8100 ;Keyword recognition and help subsystem .P100 8100 4C 0C 81 JMP P10C ;OSFSC 3 .P103 8103 4C 1A 81 JMP P11A ;OSCLI .P106 8106 4C 13 81 JMP P113 ;*HELP .P109 8109 4C 70 81 JMP P170 ;Print syntax for command .P10C ;OSFSC 3 810C 20 00 92 JSR Q200 ;save AXY 810F A2 2C LDX #&2C ;X=table offset=&2C 8111 D0 0C BNE P11F ;scan DFS commands .P113 ;*HELP 8113 20 00 92 JSR Q200 ;save AXY 8116 A2 E0 LDX #&E0 ;X=table offset=&E0 8118 D0 05 BNE P11F ;scan help keywords .P11A ;OSCLI 811A 20 00 92 JSR Q200 ;scans UTILS commands. save AXY 811D A2 00 LDX #&00 ;X=table offset=&00 .P11F ;Scan keyword table 811F 20 C2 FF JSR &FFC2 ;call GSINIT on keyword .P122 8122 8A TXA ;X = table offset 8123 48 PHA ;save table offset 8124 98 TYA ;Y = GSINIT offset 8125 48 PHA ;save GSINIT offset .P126 8126 BD 1B 82 LDA &821B,X ;get character from table 8129 F0 41 BEQ P16C ;if NUL then exit C=0 812B 30 1F BMI P14C ;if terminator test completeness 812D 51 F2 EOR (&F2),Y ;else compare with command char 812F 29 DF AND #&DF ;make test case insensitive 8131 D0 04 BNE P137 ;if unequal test if abbreviated 8133 E8 INX ;else increment table offset 8134 C8 INY ;increment command offset 8135 D0 EF BNE P126 ;and loop. .P137 8137 E8 INX 8138 BD 1B 82 LDA &821B,X ;search tbl for next terminator 813B 10 FA BPL P137 813D B1 F2 LDA (&F2),Y ;get char where search stopped 813F C8 INY ;increment command offset 8140 C9 2E CMP #&2E ;was it a dot? 8142 F0 14 BEQ P158 ;if so accept the abbreviation .P144 8144 68 PLA ;else restore command offset 8145 A8 TAY ;to start 8146 68 PLA ;discard old table offset 8147 E8 INX ;increment table offset by 3 to 8148 E8 INX ;skip syntax and action address 8149 E8 INX 814A D0 D6 BNE P122 ;and compare with next keyword. .P14C 814C B1 F2 LDA (&F2),Y ;get character after command 814E 29 DF AND #&DF ;convert to uppercase 8150 C9 41 CMP #&41 ;is it less than "A"? 8152 90 04 BCC P158 ;then accept the command 8154 C9 5B CMP #&5B ;is it less than "Z"? 8156 90 EC BCC P144 ;then table entry was too short! .P158 8158 BD 1C 82 LDA &821C,X ;else accept command. 815B 85 A8 STA &A8 ;get action address 815D BD 1D 82 LDA &821D,X ;store in temp pointer 8160 85 A9 STA &A9 8162 18 CLC 8163 20 C2 FF JSR &FFC2 ;call GSINIT with C=0 8166 68 PLA ;discard old GSINIT offset 8167 68 PLA ;get tbl offset of this command 8168 AA TAX ;place in X 8169 6C A8 00 JMP (&00A8) ;and jump to the action address. .P16C 816C 68 PLA ;command not found. 816D 68 PLA ;discard offsets 816E 18 CLC ;offer command to lower ROMs 816F 60 RTS ;exit .P170 ;Print syntax for command 8170 20 18 90 JSR Q018 ;Print Syntax: 8173 EQUB &08 ;X=offset to help entry 8174 EQUB &DC ;error 220, "Syntax" 8175 EQUS "Syntax:" 817C EQUB &00 ;terminator byte 817D 20 F1 81 JSR P1F1 ;print help entry 8180 20 09 90 JSR Q009 ;display error (never returns) .P183 8183 A9 02 LDA #&02 ;*HELP 8185 A2 EA LDX #&EA ;one column.point to keywd table 8187 20 94 81 JSR P194 ;print help keywords 818A 18 CLC ;pass call to lower ROMs 818B 60 RTS ;exit .P18C 818C A2 2C LDX #&2C ;*HELP DFS.offset to point to DFS table 818E D0 02 BNE P192 .P190 8190 A2 00 LDX #&00 ;*HELP UTILS.point to UTILS table .P192 8192 A9 01 LDA #&01 ;Print help table, two columns: .P194 8194 85 AA STA &AA ;Print help table. 8196 20 00 96 JSR Q600 ;print EDOS banner .P199 8199 20 F1 81 JSR P1F1 ;print help entry 819C E8 INX ;skip syntax and action address 819D E8 INX .P19E 819E E8 INX 819F BD 18 82 LDA &8218,X ;search keyword just printed 81A2 10 FA BPL P19E ;until terminator found 81A4 BD 1B 82 LDA &821B,X ;test first char of next keyword 81A7 F0 16 BEQ P1BF ;if NUL print newline and exit 81A9 A5 AA LDA &AA ;else toggle b0 of column flag 81AB 49 01 EOR #&01 ;00000001 81AD 85 AA STA &AA 81AF F0 06 BEQ P1B7 ;if any bit is set 81B1 20 09 90 JSR Q009 ;print newline 81B4 4C 99 81 JMP P199 ;and loop .P1B7 81B7 A9 28 LDA #&28 ;else 81B9 20 06 90 JSR Q006 ;Tab to column 41 81BC 4C 99 81 JMP P199 ;and loop. .P1BF ;end of *HELP or syntax 81BF 20 09 90 JSR Q009 ;print newline 81C2 38 SEC ;break out of ROM call 81C3 60 RTS ;exit 81C4 20 18 90 JSR Q018 ;*HELP HELP 81C7 EQUB &01 ;newline before string 81C8 EQUS "I need somebody," 81D8 EQUB &00 81D9 20 18 90 JSR Q018 81DC EQUB &02 ;newline after string 81DD EQUS " not just anybody" 81EE EQUB &00 81EF 38 SEC 81F0 60 RTS .P1F1 ;Print help entry, X=offset. 81F1 20 00 92 JSR Q200 ;Save AXY 81F4 A9 02 LDA #&02 ;tab to column 2 or more 81F6 20 06 90 JSR Q006 ;returning current POS in A 81F9 48 PHA ;save POS .P1FA 81FA BD 1B 82 LDA &821B,X 81FD 30 06 BMI P205 ;if not the terminator 81FF 20 00 90 JSR Q000 ;print the character in A 8202 E8 INX ;advance offset 8203 D0 F5 BNE P1FA ;and loop .P205 8205 29 7F AND #&7F ;else mask terminator 8207 AA TAX ;to get offset of syntax 8208 68 PLA ;get back POS 8209 18 CLC 820A 69 09 ADC #&09 ;add 9 820C 20 06 90 JSR Q006 ;tab to 9 places after command .P20F 820F BD 14 83 LDA &8314,X 8212 F0 06 BEQ P21A ;if NUL then exit 8214 20 00 90 JSR Q000 ;else print the character in A 8217 E8 INX ;advance offset 8218 D0 F5 BNE P20F ;and loop. .P21A 821A 60 RTS 821B EQUS "BUILD" ;*BUILD fsp P400 8220 EQUB &BA ;Syntax fsp (b7 set) 8221 EQUW &00,&84 ;Action address &8400 8223 EQUS "DISC" ;*DISC I, P403 8227 EQUB &B8 ;Syntax I (b7 set) 8228 EQUW &03,&84 ;Action address &8403 822A EQUS "DISK" ;*DISK I, P403 822E EQUB &B8 ;Syntax I (b7 set) 822F EQUW &03,&84 ;Action address &8403 8231 EQUS "DUMP" ;*DUMP fsp, P406 8235 EQUB &BA ;Syntax fsp (b7 set) 8236 EQUW &06,&84 ;Action address &8406 8238 EQUS "LIST" ;*LIST fsp, P409 823C EQUB &BA ;Syntax fsp (b7 set) 823D EQUW &09,&84 ;Action address &8409 823F EQUS "TYPE" ;*TYPE fsp, P40C 8243 EQUB &BA ;Syntax fsp (b7 set) 8244 EQUW &0C,&84 ;Action address &840C 8246 EQUB &00 8247 EQUS "ACCESS" ;*ACCESS fsp L, P600 824D EQUB &80 ;Syntax fsp L 824E EQUW &00,&86 ;Action address &8600 8250 EQUS "BACKUP" ;*BACKUP drv drv, PA00 8256 EQUB &88 ;Syntax drv drv 8257 EQUW &00,&8A ;Action address &8A00 8259 EQUS "CATGEN" ;*CATGEN vol ..., R903 825F EQUB &E1 ;Syntax vol ... 8260 EQUW &03,&A9 ;Action address &A903 8262 EQUS "COMPACT" ;*COMPACT vol, PA03 8269 EQUB &9B ;Syntax vol 826A EQUW &03,&8A ;Action address &8A03 826C EQUS "COPY" ;*COPY vol vol afsp, PA06 8270 EQUB &9F ;Syntax vol vol afsp 8271 EQUW &06,&8A ;Action address &8A06 8273 EQUS "DELETE" ;*DELETE fsp, P606 8279 EQUB &BA ;Syntax fsp (b7 set) 827A EQUW &06,&86 ;Action address &8606 827C EQUS "DESTROY" ;*DESTROY afsp, P609 8283 EQUB &B3 ;Syntax afsp 8284 EQUW &09,&86 ;Action address &8609 8286 EQUS "DIR" ;*DIR dir, P60C 8289 EQUB &BE ;Syntax dir 828A EQUW &0C,&86 ;Action address &860C 828C EQUS "DRIVE" ;*DRIVE drv, P60F 8291 EQUB &F1 ;Syntav drv 8292 EQUW &0F,&86 ;Action address &860F 8294 EQUS "ENABLE" ;*ENABLE, PA09 829A EQUB &B7 ;Syntax 829B EQUW &09,&8A ;Action address &8A09 829D EQUS "FCOPY" ;*FCOPY fsp name, PA12 82A2 EQUB &C2 ;Syntax fsp name 82A3 EQUW &12,&8A ;Action address &8A12 82A5 EQUS "FORMAT" ;*FORMAT drv ..., R900 82AB EQUB &F5 ;Syntax drv ... 82AC EQUW &00,&A9 ;Action address &A900 82AE EQUS "INFO" ;*INFO afsp, P612 82B2 EQUB &B3 ;Syntax afsp 82B3 EQUW &12,&86 ;Action address &8612 82B5 EQUS "LIB" ;*LIB dir, P615 82B8 EQUB &BE ;Syntax dir 82B9 EQUW &15,&86 ;Action address &8615 82BB EQUS "LOCK" ;*LOCK afsp, P621 82BF EQUB &B3 ;Syntax afsp 82C0 EQUW &21,&86 ;Action address &8621 82C2 EQUS "RENAME" ;*RENAME fsp name, P618 82C8 EQUB &C2 ;Syntax fsp name 82C9 EQUW &18,&86 ;Action address &8618 82CB EQUS "SCOPY" ;*SCOPY vol vol afsp, PA0F 82D0 EQUB &9F ;Syntax vol vol afsp 82D1 EQUW &0F,&8A ;Action address &8A0F 82D3 EQUS "TITLE" ;*TITLE title, P61B 82D8 EQUB &DB ;Syntax title 82D9 EQUW &1B,&86 ;Action address &861B 82DB EQUS "UNLOCK" ;*UNLOCK afsp, P624 82E1 EQUB &B3 ;Syntax afsp 82E2 EQUW &24,&86 ;Action address &8624 82E4 EQUS "VERIFY" ;*VERIFY drv, R906 82EA EQUB &F1 ;Syntax drv 82EB EQUW &06,&A9 ;Action address &A906 82ED EQUS "VOL" ;*VOL vol, P627 82F0 EQUB &9B ;Syntax vol 82F1 EQUW &27,&86 ;Action address &8627 82F3 EQUS "WIPE" ;*WIPE afsp, P61E 82F7 EQUB &B3 ;Syntax afsp 82F8 EQUW &1E,&86 ;Action address &861E 82FA EQUB &00 ;terminator byte 82FB EQUB &B7 ;*HELP, P183 82FC EQUW &83,&81 ;action address &8183 82FE EQUS "HELP" ;*HELP HELP, &81C4 8302 EQUB &B7 ;Syntax 8303 EQUW &C4,&81 ;Action address &81C4 8305 EQUS "DFS" ;*HELP DFS, P18C 8308 EQUB &B7 ;Syntax 8309 EQUW &8C,&81 ;Action address &818C 830B EQUS "UTILS" ;*HELP UTILS, P190 8310 EQUB &B7 ;Syntax 8311 EQUW &90,&81 ;Action address &8190 8313 EQUB &00 ;terminator byte 8314 EQUS "afsp L" 831B EQUB &00 ;terminator byte 831C EQUS "src drv dest drv" 832E EQUB &00 ;terminator byte 832F EQUS "vol" 8332 EQUB &00 ;terminator byte 8333 EQUS "src vol dest vol afsp" 834B EQUB &00 ;terminator byte 834C EQUS "I" 834D EQUB &00 ;terminator byte 834E EQUS "fsp" 8351 EQUB &00 ;terminator byte 8352 EQUS "dir" 8355 EQUB &00 ;terminator byte 8356 EQUS "old fsp new entry name" 836E EQUB &00 ;terminator byte 836F EQUS "title" 8374 EQUB &00 ;terminator byte 8375 EQUS "drv vol specs" 8384 EQUB &00 ;terminator byte 8385 EQUS "drv" 8388 EQUB &00 ;terminator byte 8389 EQUS "drv S D 40 80 40-80 Oo" 83A5 EQUB &00 ;terminator byte ;unused space from &83A6 ;unused space ends at &8400 ;Utilities .P400 8400 4C 0F 84 JMP P40F ;*BUILD fsp .P403 8403 4C 71 84 JMP P471 ;*DISC, *DISK .P406 8406 4C 82 84 JMP P482 ;*DUMP .P409 8409 4C F4 84 JMP P4F4 ;*LIST .P40C 840C 4C 1F 85 JMP P51F ;*TYPE .P40F ;*BUILD 840F A9 80 LDA #&80 8411 20 3B 85 JSR P53B ;open file for writing 8414 20 67 84 JSR P467 ;flush all open files .P417 8417 20 73 85 JSR P573 ;increment line number 841A 20 8B 85 JSR P58B ;print line number 841D 20 44 84 JSR P444 ;input line .P420 8420 A6 AA LDX &AA ;get low byte of pointer 8422 E4 AF CPX &AF ;compare with line length 8424 F0 0B BEQ P431 ;if equal input next line 8426 A2 00 LDX #&00 ;else get char at pointer 8428 A1 AA LDA (&AA,X) 842A 20 D4 FF JSR &FFD4 ;call OSBPUT 842D E6 AA INC &AA ;advance pointer 842F D0 EF BNE P420 ;loop until end of buffer .P431 8431 24 FF BIT &FF ;test escape flag 8433 10 E2 BPL P417 ;if clear input next line 8435 98 TYA ;else save file handle 8436 48 PHA 8437 A9 7E LDA #&7E ;acknowledge Escape 8439 20 F4 FF JSR &FFF4 ;call OSBYTE 843C 68 PLA ;restore file handle 843D A8 TAY 843E 20 E7 FF JSR &FFE7 ;call OSNEWL 8441 4C 6C 85 JMP P56C ;close file and exit. .P444 ;Input line 8444 20 00 92 JSR Q200 ;save AXY 8447 88 DEY ;y=handle, point to previous 8448 C0 11 CPY #&11 ;buffer. If buffer was &11 844A B0 02 BCS P44E ;or less, point to next 844C C8 INY ;buffer. 844D C8 INY .P44E 844E 84 AB STY &AB ;store high byte of pointer 8450 A0 FF LDY #&FF 8452 84 AC STY &AC ;maximum line length = 255 8454 84 AE STY &AE ;maximum ASCII value = 255 8456 C8 INY ;set Y=0 8457 84 AA STY &AA ;clear low byte of pointer 8459 84 AD STY &AD ;minimum ASCII value = 0 845B 98 TYA ;set A=0 845C A2 AA LDX #&AA ;point XY to parameter block 845E 20 F1 FF JSR &FFF1 ;call OSWORD to input line 8461 B0 01 BCS P464 ;if user did not Escape 8463 C8 INY ;add 1 for the CR character .P464 8464 84 AF STY &AF ;return length of line in &AF 8466 60 RTS .P467 8467 20 00 92 JSR Q200 ;Flush all open files.save AXY 846A A9 FF LDA #&FF 846C A0 00 LDY #&00 846E 4C DA FF JMP &FFDA ;call OSARGS and exit .P471 ;*DISC, *DISK 8471 20 C5 FF JSR &FFC5 ;call GSREAD for character 8474 A0 01 LDY #&01 8476 B0 05 BCS P47D ;if EOS init EDOS, Y=1 no boot 8478 C9 49 CMP #&49 ;else is character "I"? 847A D0 01 BNE P47D ;if not init EDOS, Y=1 no boot 847C 88 DEY ;else Y=0 to boot default drive .P47D 847D 20 03 96 JSR Q603 ;initialise EDOS 8480 38 SEC ;c=1, exit and break ROM call 8481 60 RTS .P482 ;*DUMP 8482 20 39 85 JSR P539 ;open file for reading 8485 AE 55 03 LDX &0355 ;open file, get current MODE 8488 BD EC 84 LDA &84EC,X ;get ASCII column tab for MODE 848B 85 AA STA &AA ;store in temp 848D BD E4 84 LDA &84E4,X ;get bytes per row for MODE 8490 85 AF STA &AF ;store in temp .P492 8492 20 93 85 JSR P593 ;BGET byte 8495 B0 27 BCS P4BE ;if EOF close file 8497 20 8A 85 JSR P58A ;else print file offset+space 849A 20 79 85 JSR P579 ;add bytes/row to file offset 849D A6 AF LDX &AF ;X=bytes per row .P49F 849F 24 AA BIT &AA ;if b7 of tab clear 84A1 30 03 BMI P4A6 84A3 20 03 90 JSR Q003 ;then print space. .P4A6 84A6 38 SEC ;permit leading zero 84A7 20 0F 90 JSR Q00F ;print hex byte 84AA 9D 00 01 STA &0100,X ;store byte for ASCII column 84AD CA DEX ;decrement column counter 84AE D0 06 BNE P4B6 ;if no more columns 84B0 20 C1 84 JSR P4C1 ;print ASCII column 84B3 4C 92 84 JMP P492 ;and loop for next row. .P4B6 84B6 20 93 85 JSR P593 ;else BGET next byte 84B9 90 E4 BCC P49F ;if no EOF print it and loop 84BB 20 C1 84 JSR P4C1 ;else flush ASCII column .P4BE 84BE 4C 6C 85 JMP P56C ;close file and exit. .P4C1 84C1 20 00 92 JSR Q200 ;Print ASCII column.save AXY 84C4 A5 AA LDA &AA ;x=no.chars not to print 84C6 29 7F AND #&7F ;mask print-space bit off tab 84C8 20 06 90 JSR Q006 ;tab to screen column 84CB A4 AF LDY &AF ;y=bytes per row .P4CD 84CD B9 00 01 LDA &0100,Y ;get byte from stack page 84D0 30 04 BMI P4D6 ;if >=&80 print a dot 84D2 C9 20 CMP #&20 ;else if >=&20 print character 84D4 B0 02 BCS P4D8 .P4D6 84D6 A9 2E LDA #&2E ;else print a dot .P4D8 84D8 20 00 90 JSR Q000 ;Print character in A 84DB 88 DEY ;decrement byte pointer 84DC E8 INX ;increment bytes not to print 84DD E4 AF CPX &AF ;if result <> bytes per column 84DF D0 EC BNE P4CD ;then loop for next character 84E1 4C E7 FF JMP &FFE7 ;else print newline and exit. 84E4 EQUB &10,&08,&04,&10 ;*DUMP bytes/row in MODES [0..7] 84E8 EQUB &08,&04,&08,&08 84EC EQUB &37,&1F,&8E,&37 ;*DUMP ASCII tab in MODEs [0..7] 84F0 EQUB &1F,&8E,&1F,&1F .P4F4 ;*LIST 84F4 20 39 85 JSR P539 ;Open file for reading .P4F7 84F7 20 93 85 JSR P593 ;open file, BGET char 84FA B0 70 BCS P56C ;if EOF close file 84FC 20 73 85 JSR P573 ;else increment line number 84FF 20 8B 85 JSR P58B ;print line number .P502 8502 20 E3 FF JSR &FFE3 ;call OSASCI to print char .P505 8505 C9 0D CMP #&0D ;was it CR? 8507 F0 EE BEQ P4F7 ;if so start next line 8509 C9 0A CMP #&0A ;else, was it LF? 850B F0 07 BEQ P514 ;if so BGET+OSWRCH next char 850D 20 93 85 JSR P593 ;else BGET next character 8510 B0 5A BCS P56C ;if EOF close file 8512 90 EE BCC P502 ;else print char and loop. .P514 8514 20 93 85 JSR P593 ;test Escape and BGET char 8517 B0 53 BCS P56C ;if EOF close file 8519 20 EE FF JSR &FFEE ;else call OSWRCH to print 851C 4C 05 85 JMP P505 ;interpret char and loop. .P51F ;*TYPE 851F 20 39 85 JSR P539 ;Open file for reading .P522 8522 20 93 85 JSR P593 ;open file, BGET char 8525 B0 45 BCS P56C ;if EOF close file 8527 20 E3 FF JSR &FFE3 ;else print char with OSASCI .P52A 852A C9 0A CMP #&0A ;was it LF? 852C D0 F4 BNE P522 ;if not loop for next char 852E 20 93 85 JSR P593 ;else BGET next char 8531 B0 39 BCS P56C ;if EOF close file 8533 20 EE FF JSR &FFEE ;else call OSWRCH to print 8536 4C 2A 85 JMP P52A ;interpret char and loop. .P539 8539 A9 40 LDA #&40 ;Open file for reading .P53B ;Open file 853B 20 00 92 JSR Q200 ;save AXY 853E 48 PHA ;save A 853F 98 TYA ;GSREAD pointer (&F2),Y 8540 18 CLC ;points to filename. 8541 65 F2 ADC &F2 ;calculate XY = &F2,3 + Y 8543 AA TAX ;X = Y + &F2 8544 A9 00 LDA #&00 ;A = 0 8546 85 A8 STA &A8 ;as side effect line no.=0 8548 85 A9 STA &A9 ;Y = 0 + &F3 + carry 854A 65 F3 ADC &F3 854C A8 TAY 854D 68 PLA ;restore A file open mode 854E 20 CE FF JSR &FFCE ;call OSFIND to open file 8551 BA TSX ;return handle in Y 8552 9D 03 01 STA &0103,X 8555 AA TAX ;if handle = 0 8556 D0 1A BNE P572 8558 20 18 90 JSR Q018 ;Print "File not found" error. 855B EQUB &0A ;LF 855C EQUB &D6 855D EQUS "File not found" 856B EQUB &00 ;terminator byte .P56C ;Close file 856C A9 00 LDA #&00 856E 20 CE FF JSR &FFCE .P571 8571 38 SEC ;break unrecognised OSCLI .P572 8572 60 RTS ;ROM call and exit .P573 8573 48 PHA 8574 F8 SED 8575 A9 01 LDA #&01 ;Increment line number 8577 D0 03 BNE P57C .P579 8579 48 PHA ;Add bytes/row to file offset 857A A5 AF LDA &AF .P57C 857C 18 CLC 857D 65 A8 ADC &A8 857F 85 A8 STA &A8 8581 A9 00 LDA #&00 8583 65 A9 ADC &A9 8585 85 A9 STA &A9 8587 D8 CLD 8588 68 PLA 8589 60 RTS .P58A 858A 38 SEC ;Print offset w/leading zeroes .P58B 858B 20 15 90 JSR Q015 ;Print BCD line no at &00A8 858E EQUW &A8,&00 8590 4C 03 90 JMP Q003 ;print space and exit .P593 8593 24 FF BIT &FF ;Test Escape and BGET 8595 30 DA BMI P571 8597 4C D7 FF JMP &FFD7 ;unused space from &859A #ifdef _UNUSED ;aligned, verbatim copy of *DUMP code from &849A..FF 859A 20 79 85 JSR P579 859D A6 AF LDX &AF .P59F 859F 24 AA BIT &AA 85A1 30 03 BMI P5A6 85A3 20 03 90 JSR Q003 .P5A6 85A6 38 SEC 85A7 20 0F 90 JSR Q00F 85AA 9D 00 01 STA &0100,X 85AD CA DEX 85AE D0 06 BNE P5B6 85B0 20 C1 84 JSR P4C1 85B3 4C 92 84 JMP P492 .P5B6 85B6 20 93 85 JSR P593 85B9 90 E4 BCC P59F 85BB 20 C1 84 JSR P4C1 85BE 4C 6C 85 JMP P56C 85C1 20 00 92 JSR Q200 85C4 A5 AA LDA &AA 85C6 29 7F AND #&7F 85C8 20 06 90 JSR Q006 85CB A4 AF LDY &AF .P5CD 85CD B9 00 01 LDA &0100,Y 85D0 30 04 BMI P5D6 85D2 C9 20 CMP #&20 85D4 B0 02 BCS P5D8 .P5D6 85D6 A9 2E LDA #&2E .P5D8 85D8 20 00 90 JSR Q000 85DB 88 DEY 85DC E8 INX 85DD E4 AF CPX &AF 85DF D0 EC BNE P5CD 85E1 4C E7 FF JMP &FFE7 85E4 EQUB &10,&08,&04,&10 85E8 EQUB &08,&04,&08,&08 85EC EQUB &37,&1F,&8E,&37 85F0 EQUB &1F,&8E,&1F,&1F 85F4 20 39 85 JSR P539 85F7 20 93 85 JSR P593 85FA B0 70 BCS P66C 85FC 20 73 85 JSR P573 85FF EQUB &20 #endif /* _UNUSED */ ;unused space ends at &8600 ;'Light' DFS commands .P600 8600 4C 2A 86 JMP P62A ;*ACCESS .P603 8603 4C 74 86 JMP P674 ;*CAT .P606 8606 4C BC 87 JMP P7BC ;*DELETE .P609 8609 4C CD 87 JMP P7CD ;*DESTROY .P60C 860C 4C 0E 88 JMP P80E ;*DIR .P60F 860F 4C 28 88 JMP P828 ;*DRIVE .P612 8612 4C 42 88 JMP P842 ;*INFO .P615 8615 4C 35 88 JMP P835 ;*LIB .P618 8618 4C 54 88 JMP P854 ;*RENAME .P61B 861B 4C 91 88 JMP P891 ;*TITLE .P61E 861E 4C B9 88 JMP P8B9 ;*WIPE .P621 8621 4C 3E 86 JMP P63E ;*LOCK .P624 8624 4C 4C 86 JMP P64C ;*UNLOCK .P627 8627 4C 1B 88 JMP P81B ;*VOL .P62A ;*ACCESS 862A 20 15 93 JSR Q315 ;get ambiguous file spec 862D 20 C5 FF JSR &FFC5 ;call GSREAD 8630 B0 1D BCS P64F ;if end of string unlock file 8632 C9 4C CMP #&4C ;else is character "L"? 8634 D0 05 BNE P63B ;if not print syntax and exit 8636 20 C5 FF JSR &FFC5 ;call GSREAD for next char 8639 B0 06 BCS P641 ;if end of string lock file .P63B 863B 4C 09 81 JMP P109 ;else print syntax and exit .P63E ;*LOCK 863E 20 15 93 JSR Q315 ;get ambiguous file spec .P641 8641 20 6A 86 JSR P66A ;select file, dir in A .P644 8644 09 80 ORA #&80 ;set attribute bit 8646 20 5A 86 JSR P65A ;update file, select next 8649 90 F9 BCC P644 ;loop until no more files 864B 60 RTS .P64C ;*UNLOCK 864C 20 15 93 JSR Q315 ;get ambiguous file spec .P64F 864F 20 6A 86 JSR P66A ;select file, dir in A .P652 8652 29 7F AND #&7F ;clear attribute bit 8654 20 5A 86 JSR P65A ;update file, select next 8657 90 F9 BCC P652 ;loop until no more files 8659 60 RTS .P65A ;Update file entry 865A 8D 47 10 STA &1047 ;store dir 865D 20 06 A6 JSR R606 ;pack catalogue entry 8660 20 0F A5 JSR R50F ;find next match of afsp 8663 90 08 BCC P66D ;if more matches select next 8665 20 03 9B JSR QB03 ;else write catalogue 8668 38 SEC ;set carry 8669 60 RTS ;and exit .P66A ;Select file from afsp 866A 20 83 89 JSR P983 ;check file exists in catalogue .P66D 866D 20 03 A6 JSR R603 ;unpack catalogue entry 8670 AD 47 10 LDA &1047 ;return directory and attribute 8673 60 RTS .P674 ;*CAT 8674 20 06 93 JSR Q306 ;get ambiguous volume spec 8677 20 0C 9B JSR QB0C ;softmount disc 867A 20 6E 89 JSR P96E ;reset column COUNT = 0 867D 20 18 90 JSR Q018 ;Print "Defs" 8680 EQUB &00 8681 EQUS "Defs" 8685 EQUB &00 ;terminator byte 8686 A2 00 LDX #&00 ;x=0 for default path 8688 20 E9 88 JSR P8E9 ;print " :"+path 868B A9 2E LDA #&2E ;start with a dot .P68D 868D 20 00 90 JSR Q000 ;print character in A 8690 BD 00 10 LDA &1000,X ;get character of def filename 8693 E8 INX ;increment index 8694 E0 08 CPX #&08 ;have we loaded 7 characters? 8696 D0 F5 BNE P68D ;if not then loop 8698 20 73 89 JSR P973 ;else tab to next 20-column 869B 20 18 90 JSR Q018 ;print "Lib" 869E EQUB &00 869F EQUS "Lib" 86A2 EQUB &00 ;terminator byte 86A3 A2 03 LDX #&03 ;X = 3 for library path 86A5 20 E9 88 JSR P8E9 ;print " :"+path 86A8 20 73 89 JSR P973 ;tab to next 20-column 86AB A5 C9 LDA &C9 ;get immediate (*CAT) drive, A = current drive 86AD 20 18 90 JSR Q018 ;print "Drive "+number 86B0 EQUB &C0 86B1 EQUS "Drive " 86B7 EQUB &00 ;terminator byte 86B8 AA TAX ;drive number to X register 86B9 BD F8 0F LDA &0FF8,X ;get track stepping status 86BC D0 09 BNE P6C7 ;if enabled skip forward 86BE BD F4 0F LDA &0FF4,X ;else get no. tracks 86C1 20 04 89 JSR P904 ;"Print "n tracks" 86C4 4C D3 86 JMP P6D3 ;skip forward. .P6C7 86C7 20 18 90 JSR Q018 ;Print " 40-80" 86CA EQUB &00 86CB EQUS " 40-80" 86D2 EQUB &00 ;terminator byte .P6D3 86D3 20 73 89 JSR P973 ;tab to next 20-column 86D6 BD F0 0F LDA &0FF0,X ;get density flag 86D9 4A LSR A 86DA 4A LSR A 86DB 4A LSR A ;divide by 8 (SD=1 DD=2) 86DC 20 18 90 JSR Q018 ;Print "Density " 86DF EQUB &80 86E0 EQUS "Density " 86E8 EQUB &00 ;terminator byte 86E9 BD FC 0F LDA &0FFC,X ;get number of volumes 86EC F0 32 BEQ P720 ;if DFS skip volume list 86EE 20 03 90 JSR Q003 ;else print a space 86F1 A0 41 LDY #&41 ;start with "A" .P6F3 86F3 B9 EF 0F LDA &0FEF,Y ;get no. tracks in 1030..7 86F6 F0 04 BEQ P6FC ;if none volume not present 86F8 98 TYA ;else print volume letter 86F9 20 00 90 JSR Q000 ;print character in A .P6FC 86FC C8 INY ;increment volume letter 86FD C0 49 CPY #&49 ;is it before "I"? 86FF D0 F2 BNE P6F3 ;if so loop. 8701 A4 C8 LDY &C8 ;get immediate (*CAT) volume, Y = Immediate volume 8703 D0 18 BNE P71D ;if undefined then 8705 20 6B 89 JSR P96B ;cat all vols: print newline 8708 A0 41 LDY #&41 ;set immediate volume = "A" .P70A 870A 84 C8 STY &C8 ;Y -> &00C8 = Immediate volume 870C B9 EF 0F LDA &0FEF,Y ;get no. tracks in volume 870F F0 06 BEQ P717 ;if volume is present 8711 20 00 9B JSR QB00 ;then read volume catalogue 8714 20 23 87 JSR P723 ;and list its contents. .P717 ;increment volume letter 8717 C8 INY ;if now less than "I" 8718 C0 49 CPY #&49 ;then loop over volumes 871A D0 EE BNE P70A ;else exit. 871C 60 RTS .P71D 871D 20 09 9B JSR QB09 ;load volume catalogue .P720 8720 20 6B 89 JSR P96B ;print newline, reset count .P723 8723 20 00 92 JSR Q200 ;save AXY 8726 20 6B 89 JSR P96B ;print newline, reset count 8729 A2 00 LDX #&00 ;print first 8 characters .P72B 872B BD 00 0E LDA &0E00,X ;of title in sector 0 872E 20 00 90 JSR Q000 ;print character in A 8731 E8 INX 8732 E0 08 CPX #&08 8734 D0 F5 BNE P72B 8736 A2 00 LDX #&00 ;print last 4 characters .P738 8738 BD 00 0F LDA &0F00,X ;of title in sector 1 873B 20 00 90 JSR Q000 ;print character in A 873E E8 INX 873F E0 04 CPX #&04 8741 D0 F5 BNE P738 8743 AD 04 0F LDA &0F04 ;get cycle number 8746 20 18 90 JSR Q018 ;print " ("+hex byte 8749 EQUB &40 874A EQUS " (" 874C EQUB &00 874D A9 29 LDA #&29 874F 20 00 90 JSR Q000 ;print ")" 8752 A6 C9 LDX &C9 ;X = current drive 8754 BD FC 0F LDA &0FFC,X ;X=*CAT drive number 8757 F0 18 BEQ P771 ;get number of volumes 8759 20 73 89 JSR P973 ;if not a DFS disc 875C 20 73 89 JSR P973 ;then tab to next 20-column 875F A4 C8 LDY &C8 ;and again, Y = Immediate volume 8761 98 TYA ;get *CAT volume letter 8762 20 18 90 JSR Q018 ;print "Vol " +letter 8765 EQUB &C0 8766 EQUS "Vol " 876A EQUB &00 ;terminator byte 876B B9 EF 0F LDA &0FEF,Y ;get number of tracks in volume 876E 20 04 89 JSR P904 ;print "n tracks" .P771 8771 20 73 89 JSR P973 ;tab to next 20-field 8774 20 1B A6 JSR R61B ;get free space on volume 8777 20 09 A4 JSR R409 ;print decimal word 877A 20 18 90 JSR Q018 ;Print "free/" 877D EQUB &00 877E EQUS "free/" 8783 EQUB &00 ;terminator byte 8784 AD 06 0F LDA &0F06 ;get MSB sectors on volume 8787 29 07 AND #&07 ;mask all but low 3 bits 8789 8D 61 10 STA &1061 ;store in accumulator high 878C AD 07 0F LDA &0F07 ;get sectors on volume low 878F 8D 60 10 STA &1060 ;store accumulator low 8792 20 09 A4 JSR R409 ;print decimal word 8795 20 03 90 JSR Q003 ;print space 8798 20 09 96 JSR Q609 ;get boot option, X=offset 879B A9 20 LDA #&20 ;start with a space .P79D ;get char of boot opt string 879D 20 00 90 JSR Q000 ;Print character in A 87A0 BD 0C 96 LDA &960C,X 87A3 E8 INX ;increment X "OFF LOAD RUN EXEC " 87A4 C9 20 CMP #&20 ;was the character space? 87A6 D0 F5 BNE P79D ;if not then loop 87A8 20 6B 89 JSR P96B ;else print newline 87AB AD 07 10 LDA &1007 ;get default directory 87AE 85 C7 STA &C7 ;store immediate directory 87B0 A9 00 LDA #&00 ;set A=0 Immediate dir'y, A -> &00C7 87B2 20 18 89 JSR P918 ;list files in immed dir 87B5 A9 80 LDA #&80 ;set A=&80 87B7 20 18 89 JSR P918 ;list files in all (other) dirs 87BA 38 SEC ;breakout ROM call and exit 87BB 60 RTS .P7BC ;*DELETE 87BC 20 12 93 JSR Q312 ;get file spec 87BF 20 83 89 JSR P983 ;check file exists in catalogue 87C2 20 21 A5 JSR R521 ;check file not locked 87C5 20 00 A6 JSR R600 ;delete catalogue entry 87C8 20 03 9B JSR QB03 ;write catalogue 87CB 38 SEC ;breakout ROM call 87CC 60 RTS ;and exit. .P7CD ;*DESTROY 87CD 20 15 93 JSR Q315 ;get afsp 87D0 20 00 9B JSR QB00 ;load catalogue 87D3 20 12 A5 JSR R512 ;find unlocked file in cat 87D6 B0 34 BCS P80C ;if not found exit silently 87D8 20 6E 89 JSR P96E ;else reset column count .P7DB 87DB 20 03 A6 JSR R603 ;unpack fields from catalogue 87DE 20 03 A4 JSR R403 ;print directory and filename 87E1 20 00 A6 JSR R600 ;delete catalogue entry 87E4 20 18 A5 JSR R518 ;find next unlocked match 87E7 B0 06 BCS P7EF ;if found 87E9 20 73 89 JSR P973 ;then tab to next 20-column 87EC 4C DB 87 JMP P7DB ;and loop .P7EF ;else ask 87EF 20 18 90 JSR Q018 ;"Destroy these files?" (even if *ENABLEd) 87F2 EQUB &11 87F3 EQUS "Destroy these files" 8806 EQUB &00 ;terminator byte 8807 D0 03 BNE P80C ;if user answers yes 8809 20 03 9B JSR QB03 ;then write catalogue. .P80C 880C 38 SEC 880D 60 RTS ;breakout ROM call and exit. .P80E ;*DIR 880E 20 09 93 JSR Q309 ;get path spec 8811 20 06 92 JSR Q206 ;copy memory absolute 8814 EQUW &C7,&00 ;from immediate path 8816 EQUW &07,&10 ;to default path 8818 EQUB &03 ;(dir, volume and drive) 8819 38 SEC 881A 60 RTS ;breakout ROM call and exit. .P81B ;*VOL 881B 20 03 93 JSR Q303 ;get volume spec (no colon) 881E 20 06 92 JSR Q206 ;copy memory absolute 8821 EQUW &C8,&00 ;from vol+drive 8823 EQUW &08,&10 ;to default path 8825 EQUB &02 ;vol+drive 8826 38 SEC 8827 60 RTS ;breakout ROM call and exit. .P828 ;Was *DRIVE 8828 20 00 93 JSR Q300 ;get drive number 882B 20 06 92 JSR Q206 ;copy memory absolute 882E EQUW &C9,&00 ;from immediate drive 8830 EQUW &09,&10 ;to default path 8832 EQUB &01 ;drive 8833 38 SEC 8834 60 RTS ;breakout ROM call and exit. .P835 ;*LIB 8835 20 09 93 JSR Q309 ;get path spec 8838 20 06 92 JSR Q206 ;copy memory absolute 883B EQUW &C7,&00 ;from immediate path, &00C7 883D EQUW &0A,&10 ;to library path, &100A 883F EQUB &03 8840 38 SEC 8841 60 RTS ;breakout ROM call and exit. .P842 ;*INFO 8842 20 80 89 JSR P980 ;get afsp, check it exists .P845 8845 20 03 A6 JSR R603 ;unpack cat 8848 20 06 A4 JSR R406 ;print *INFO line 884B 20 09 90 JSR Q009 ;print newline 884E 20 0F A5 JSR R50F ;find next match of afsp 8851 90 F2 BCC P845 ;loop if found 8853 60 RTS ;else breakout ROM call and exit. .P854 ;*RENAME 8854 98 TYA ;save command line pointer 8855 48 PHA 8856 20 12 93 JSR Q312 ;get file spec 8859 20 0F 93 JSR Q30F ;get entry name 885C 68 PLA ;(to check syntax) 885D A8 TAY ;restore command line pointer 885E 20 12 93 JSR Q312 ;get file spec 8861 20 83 89 JSR P983 ;check file exists in catalogue 8864 20 21 A5 JSR R521 ;check file not locked 8867 A5 CC LDA &CC ;get pointer to cat entry 8869 48 PHA ;save it 886A 20 0F 93 JSR Q30F ;get new entry name 886D 20 09 A5 JSR R509 ;try to find it in cat 8870 B0 11 BCS P883 ;if present 8872 20 18 90 JSR Q018 ;then "File exists" error 8875 EQUB &0A 8876 EQUB &C4 8877 EQUS "File exists" 8882 EQUB &00 ;terminator byte .P883 8883 68 PLA ;else restore cat pointer 8884 AA TAX 8885 20 09 92 JSR Q209 ;copy immediate filename 8888 EQUW &C0,&00 ;into catalogue at index X+8 888A EQUW &08,&0E 888C EQUB &08,&02 888E 4C B4 88 JMP P8B4 ;jump to write cat and exit. .P891 ;*TITLE 8891 20 06 92 JSR Q206 ;copy default path to immed 8894 EQUW &00,&10 ;FROM address &1000 8896 EQUW &C0,&00 ;TO address &00C0 8898 EQUB &0A ;count 8899 20 00 9B JSR QB00 ;load catalogue 889C A2 00 LDX #&00 ;clear index register .P89E 889E 20 1E 93 JSR Q31E ;get character of string 88A1 9D 00 0E STA &0E00,X ;store in first part of title 88A4 E8 INX ;increment index register 88A5 E0 08 CPX #&08 ;is it now 8 or more? 88A7 D0 F5 BNE P89E ;if not loop .P8A9 88A9 20 1E 93 JSR Q31E ;else get character of string 88AC 9D F8 0E STA &0EF8,X ;store in last part of title 88AF E8 INX ;increment index register 88B0 E0 0C CPX #&0C ;is it 12 or more? 88B2 D0 F5 BNE P8A9 ;if not loop .P8B4 88B4 20 03 9B JSR QB03 ;else write catalogue 88B7 38 SEC ;breakout ROM call 88B8 60 RTS ;and exit. .P8B9 ;*WIPE 88B9 20 80 89 JSR P980 ;get afsp, check it exists .P8BC 88BC 20 03 A6 JSR R603 ;unpack cat 88BF 20 03 A4 JSR R403 ;print directory and filename 88C2 AD 47 10 LDA &1047 ;get attribute bit 88C5 10 06 BPL P8CD ;if locked 88C7 20 09 90 JSR Q009 ;then print newline 88CA 4C E3 88 JMP P8E3 ;and loop to next file .P8CD 88CD 20 18 90 JSR Q018 ;ask " : delete?" 88D0 EQUB &10 88D1 EQUS " : delete" 88DA EQUB &00 ;terminator byte 88DB D0 06 BNE P8E3 ;if user answers no then loop 88DD 20 00 A6 JSR R600 ;else delete entry 88E0 20 03 9B JSR QB03 ;and write catalogue. .P8E3 88E3 20 0F A5 JSR R50F ;find next match of afsp 88E6 90 D4 BCC P8BC ;and loop else 88E8 60 RTS ;breakout +exit. .P8E9 ;Print " :"+path 88E9 BD 09 10 LDA &1009,X ;get drive, X = 3 library path, X = 0 default path 88EC 20 18 90 JSR Q018 ;print " :"+drive 88EF EQUB &C0 88F0 EQUS " :" 88F2 EQUB &00 ;terminator byte 88F3 BD 08 10 LDA &1008,X ;get volume letter 88F6 20 00 90 JSR Q000 ;print character in A 88F9 A9 2E LDA #&2E ;set A=dot 88FB 20 00 90 JSR Q000 ;print character in A 88FE BD 07 10 LDA &1007,X ;get directory character 8901 4C 00 90 JMP Q000 ;print character in A .P904 ;Print "n tracks" 8904 20 18 90 JSR Q018 ;print " " +decimal no. in A 8907 EQUB &80 8908 EQUS " " 890A EQUB &00 ;terminator byte 890B 20 18 90 JSR Q018 ;print " tracks" 890E EQUB &00 890F EQUS " tracks" 8916 EQUB &00 ;terminator byte 8917 60 RTS ;and exit. .P918 ;List files in cat section 8918 85 A8 STA &A8 ;A=0 immed dir, A=&80 all dirs 891A 20 89 89 JSR P989 ;select first file in cat section 891D B0 60 BCS P97F ;if none then exit 891F 20 6B 89 JSR P96B ;else print newline .P922 8922 A6 CC LDX &CC ;set X = catalogue pointer 8924 86 A9 STX &A9 ;store in temp 8926 20 09 92 JSR Q209 ;copy catalogue entry 8929 EQUW &08,&0E ;to immediate name and directory 892B EQUW &C0,&00 892D EQUB &08,&20 .P92F 892F 20 8F 89 JSR P98F ;select next file in cat section 8932 B0 07 BCS P93B ;if no more files then break out 8934 20 1B A5 JSR R51B ;else compare immed - cat entry 8937 90 F6 BCC P92F ;if cat entry > immed then loop 8939 B0 E7 BCS P922 ;else loop to set new 'minimum'. .P93B 893B 20 06 92 JSR Q206 ;copy memory absolute 893E EQUW &C0,&00 ;FROM immediate filename and dir &00C0 8940 EQUW &40,&10 ;TO catalogue workspace &1040 8942 EQUB &08 ;count 8943 20 03 90 JSR Q003 ;print space 8946 24 A8 BIT &A8 ;test directory flag 8948 30 0C BMI P956 ;if current dir only 894A 20 03 90 JSR Q003 ;then print two spaces 894D 20 03 90 JSR Q003 ;to replace directory and dot 8950 20 00 A4 JSR R400 ;print filename 8953 4C 59 89 JMP P959 ;and jump forward .P956 8956 20 03 A4 JSR R403 ;else print dir and filename. .P959 8959 A6 A9 LDX &A9 ;get temp value 895B 86 CC STX &CC ;restore to catalogue pointer 895D 20 00 A6 JSR R600 ;delete catalogue entry 8960 20 89 89 JSR P989 ;select first file in cat section 8963 B0 06 BCS P96B ;if no more print nl and exit 8965 20 73 89 JSR P973 ;else tab to next 20-column 8968 4C 22 89 JMP P922 ;&loopfor next file in cat section. .P96B ;Print newline +reset: 896B 20 09 90 JSR Q009 .P96E ;Reset column COUNT = 0 896E 48 PHA 896F A9 00 LDA #&00 8971 F0 09 BEQ P97C .P973 ;Tab to next 20-column 8973 48 PHA 8974 A5 AA LDA &AA 8976 18 CLC 8977 69 14 ADC #&14 8979 20 06 90 JSR Q006 ;tab to column in A .P97C 897C 85 AA STA &AA ;save new cursor position 897E 68 PLA .P97F 897F 60 RTS .P980 ;Get afsp, check it exists 8980 20 15 93 JSR Q315 ;get ambiguous file spec: .P983 ;Check file exists in catalogue 8983 20 00 9B JSR QB00 ;load catalogue 8986 4C 0C A5 JMP R50C ;and check file exists. .P989 8989 20 00 A5 JSR R500 ;Select first file in cat section 898C 4C 92 89 JMP P992 ;select 1st file and jump .P98F 898F 20 06 A5 JSR R506 ;Select next file in cat section .P992 8992 B0 0A BCS P99E ;if no more files then exit C=1 8994 24 A8 BIT &A8 ;else test directory flag 8996 30 05 BMI P99D ;if b7=1 then exit C=0 8998 20 1E A5 JSR R51E ;else compare directory letters 899B D0 F2 BNE P98F ;if mismatch then loop .P99D 899D 18 CLC ;else exit C=0 .P99E 899E 60 RTS ;unused space from &899F #ifdef _UNUSED ;aligned, verbatim copy of *TITLE code from &889F..FF 899F EQUB &1E,&93 89A1 9D 00 0E STA &0E00,X 89A4 E8 INX 89A5 E0 08 CPX #&08 89A7 D0 F5 BNE P99E .P9A9 89A9 20 1E 93 JSR Q31E 89AC 9D F8 0E STA &0EF8,X 89AF E8 INX 89B0 E0 0C CPX #&0C 89B2 D0 F5 BNE P9A9 89B4 20 03 9B JSR QB03 89B7 38 SEC 89B8 60 RTS 89B9 20 80 89 JSR P980 .P9BC 89BC 20 03 A6 JSR R603 89BF 20 03 A4 JSR R403 89C2 AD 47 10 LDA &1047 89C5 10 06 BPL P9CD 89C7 20 09 90 JSR Q009 89CA 4C E3 88 JMP P8E3 .P9CD 89CD 20 18 90 JSR Q018 89D0 EQUB &10 89D1 EQUS " : delete" 89DA EQUB &00 89DB D0 06 BNE P9E3 89DD 20 00 A6 JSR R600 89E0 20 03 9B JSR QB03 .P9E3 89E3 20 0F A5 JSR R50F 89E6 90 D4 BCC P9BC 89E8 60 RTS 89E9 BD 09 10 LDA &1009,X 89EC 20 18 90 JSR Q018 89EF EQUB &C0 89F0 EQUS " :" 89F2 EQUB &00 89F3 BD 08 10 LDA &1008,X 89F6 20 00 90 JSR Q000 89F9 A9 2E LDA #&2E 89FB 20 00 90 JSR Q000 89FE EQUB &BD,&07 #endif /* _UNUSED */ ;unused space ends at &8A00 ;'Medium' DFS commands .PA00 8A00 4C 15 8A JMP PA15 ;*BACKUP .PA03 8A03 4C D3 8A JMP PAD3 ;*COMPACT .PA06 8A06 4C 64 8B JMP PB64 ;*COPY .PA09 8A09 4C E7 8B JMP PBE7 ;*ENABLE .PA0C 8A0C 4C FA 8C JMP PCFA ;Ask user for confirmation .PA0F 8A0F 4C 77 8B JMP PB77 ;*SCOPY .PA12 8A12 4C A5 8B JMP PBA5 ;*FCOPY .PA15 ;*BACKUP 8A15 20 00 93 JSR Q300 ;get drive spec 8A18 A5 C9 LDA &C9 ;A = current drive 8A1A 8D 70 10 STA &1070 ;store source drive in workspace 8A1D 20 00 93 JSR Q300 ;get drive spec 8A20 A5 C9 LDA &C9 ;A = current drive 8A22 8D 71 10 STA &1071 ;store dest drive in workspace 8A25 A9 00 LDA #&00 8A27 8D 72 10 STA &1072 ;clear source volume 8A2A 8D 73 10 STA &1073 ;and target volume 8A2D AD 70 10 LDA &1070 ;A = source drive 8A30 20 18 90 JSR Q018 ;print "Copying from drive " +source drive 8A33 EQUB &C0 8A34 EQUS "Copying from drive " 8A47 EQUB &00 ;terminator byte 8A48 AD 71 10 LDA &1071 8A4B 20 18 90 JSR Q018 ;print " to drive "+target+nl 8A4E EQUB &C2 8A4F EQUS " to drive " 8A59 EQUB &00 ;terminator byte ;compare drive geometries: 8A5A 20 77 8D JSR PD77 ;initialise and load source disc 8A5D 20 FF 8B JSR PBFF ;set up prompt flag 8A60 AE 70 10 LDX &1070 ;get source drive for use later 8A63 BD F4 0F LDA &0FF4,X ;get no. tracks on source drive 8A66 8D 81 10 STA &1081 ;store temp 8A69 BD F0 0F LDA &0FF0,X ;get density of source drive 8A6C 48 PHA ;push density 8A6D 20 B7 8D JSR PDB7 ;swap source and target discs 8A70 20 91 8D JSR PD91 ;ensure catalogue loaded 8A73 AE 71 10 LDX &1071 ;get target drive for use later 8A76 68 PLA ;pop source density 8A77 DD F0 0F CMP &0FF0,X ;compare with target density 8A7A D0 3F BNE PABB ;if unequal "Incompatible discs" 8A7C AD 81 10 LDA &1081 ;else get source tracks 8A7F DD F4 0F CMP &0FF4,X ;compare with target tracks 8A82 D0 37 BNE PABB ;if unequal "Incompatible discs" 8A84 A9 00 LDA #&00 ;else clear src sectors-to-go 8A86 8D 76 10 STA &1076 8A89 8D 78 10 STA &1078 8A8C 8D 79 10 STA &1079 ;and high byte of target stg. .PA8F 8A8F BD F0 0F LDA &0FF0,X ;get target sectors per track 8A92 18 CLC 8A93 6D 76 10 ADC &1076 ;increase stg counts by this 8A96 8D 76 10 STA &1076 8A99 8D 77 10 STA &1077 8A9C 90 06 BCC PAA4 ;carry out to high bytes 8A9E EE 78 10 INC &1078 8AA1 EE 79 10 INC &1079 .PAA4 8AA4 CE 81 10 DEC &1081 8AA7 D0 E6 BNE PA8F ;loop until all tracks done. 8AA9 AD 71 10 LDA &1071 ;get target drive 8AAC 09 80 ORA #&80 ;set top bit 8AAE 20 0C 8A JSR PA0C ;confirm wipe of disc and memory 8AB1 90 06 BCC PAB9 ;if No then exit 8AB3 20 58 8E JSR PE58 ;else copy the disc 8AB6 20 58 8E JSR PE58 ;and make sure it is all done. .PAB9 8AB9 38 SEC ;break out of ROM call 8ABA 60 RTS ;and exit .PABB 8ABB 20 18 90 JSR Q018 ;Error "Incompatible discs" 8ABE EQUB &0A ;LF 8ABF EQUB &D3 8AC0 EQUS "Incompatible discs" 8AD2 EQUB &00 ;terminator byte .PAD3 ;*COMPACT 8AD3 20 EE 8B JSR PBEE ;get and store volume spec 8AD6 20 F3 8B JSR PBF3 ;store it as 'target' volume too 8AD9 20 77 8D JSR PD77 ;initialise & load source disc 8ADC A9 80 LDA #&80 8ADE 8D 80 10 STA &1080 ;set flag for single disc oper'n 8AE1 A2 00 LDX #&00 ;set &106B,C = &0001 8AE3 8E 6C 10 STX &106C ;to search for one free sector 8AE6 E8 INX 8AE7 8E 6B 10 STX &106B 8AEA 20 0C A6 JSR R60C ;find a free space in volume 8AED B0 5B BCS PB4A ;(not at end!) if not found quit 8AEF 20 06 A5 JSR R506 ;else select next (a) file 8AF2 B0 56 BCS PB4A ;if no file found finish 8AF4 AD 70 10 LDA &1070 ;else get source drive 8AF7 20 18 90 JSR Q018 ;print "Compacting vol "+n 8AFA EQUB &C0 8AFB EQUS "Compacting vol " 8B0A EQUB &00 ;terminator byte 8B0B AD 72 10 LDA &1072 ;get source volume letter 8B0E 20 00 90 JSR Q000 ;print it in A 8B11 20 09 90 JSR Q009 ;print newline 8B14 A9 80 LDA #&80 ;this routine wipes memory only 8B16 20 0C 8A JSR PA0C ;ask user for confirmation 8B19 90 2F BCC PB4A ;if not given then finish .PB1B 8B1B 20 03 A6 JSR R603 ;else unpack fields from cat 8B1E 20 CE 8E JSR PECE ;copy entry from cat 1 to 2 8B21 20 00 A6 JSR R600 ;delete catalogue entry .PB24 8B24 20 2A 8F JSR PF2A ;set copy range = entry range .PB27 8B27 20 5B 8E JSR PE5B ;copy file 8B2A 98 TYA ;if a write is now due 8B2B D0 0D BNE PB3A ;then flush buffer &test if done 8B2D A6 CC LDX &CC ;else get catalogue pointer 8B2F 20 06 A5 JSR R506 ;select next 'source' file 8B32 90 E7 BCC PB1B ;and loop if one is found 8B34 20 B7 8D JSR PDB7 ;else 'swap discs' 8B37 4C 27 8B JMP PB27 ;and loop back to tidy up. .PB3A 8B3A E4 AB CPX &AB ;if all files have been saved 8B3C F0 09 BEQ PB47 ;then finish 8B3E 20 F0 8E JSR PEF0 ;else unpack cat 2 entry 8B41 20 45 8F JSR PF45 ;create catalogue entry +*INFO 8B44 4C 24 8B JMP PB24 ;& loop back to save this file. .PB47 ;Finish *COMPACT 8B47 20 03 9B JSR QB03 ;write catalogue .PB4A 8B4A 20 1B A6 JSR R61B ;get free space on volume 8B4D 20 09 A4 JSR R409 ;print decimal word 8B50 20 18 90 JSR Q018 ;print " free sectors"+newline 8B53 EQUB &02 8B54 EQUS " free sectors" 8B61 EQUB &00 ;terminator byte 8B62 38 SEC 8B63 60 RTS ;and exit C=1. .PB64 ;*COPY 8B64 20 DC 8C JSR PCDC ;process args 8B67 90 3A BCC PBA3 ;if user declines, then exit .PB69 8B69 20 03 A6 JSR R603 ;else unpack fields 8B6C 20 49 8C JSR PC49 ;copy cat 1 to 2 and copy file 8B6F 20 0F A5 JSR R50F ;find next match of afsp 8B72 90 F5 BCC PB69 ;and loop if one is found 8B74 4C 5B 8C JMP PC5B ;else flush copy buffer &exit. .PB77 ;*SCOPY 8B77 20 DC 8C JSR PCDC ;process args, if user declines 8B7A 90 27 BCC PBA3 ;then exit .PB7C 8B7C 20 03 A6 JSR R603 ;else unpack fields 8B7F 20 03 A4 JSR R403 ;print directory and filename*SCOPY 8B82 20 18 90 JSR Q018 ;ask " : copy?" 8B85 EQUB &10 8B86 EQUS " : copy" 8B8D EQUB &00 ;terminator byte 8B8E D0 0E BNE PB9E ;if user answers yes, then: 8B90 20 49 8C JSR PC49 ;copy cat 1 to 2 and copy file 8B93 20 5B 8C JSR PC5B ;flush copy buffer 8B96 20 B7 8D JSR PDB7 ;swap discs (to reselect source) 8B99 20 91 8D JSR PD91 ;ensure catalogue loaded 8B9C 86 CC STX &CC ;save catalogue pointer .PB9E 8B9E 20 0F A5 JSR R50F ;find next match of afsp 8BA1 90 D9 BCC PB7C ;and loop if one is found .PBA3 8BA3 38 SEC 8BA4 60 RTS ;else exit C=1. .PBA5 ;*FCOPY 8BA5 20 12 93 JSR Q312 ;get file spec 8BA8 A2 00 LDX #&00 ;clear X 8BAA 20 F3 8B JSR PBF3 ;store source vol for copier 8BAD 20 06 92 JSR Q206 ;copy memory absolute 8BB0 EQUW &C0,&00 ;FROM immediate filename+dir, &00C0 8BB2 EQUW &40,&10 ;TO catalogue block 1, &1040 8BB4 EQUB &08 ;count 8BB5 20 12 93 JSR Q312 ;get file spec 8BB8 20 F3 8B JSR PBF3 ;store target vol for copier 8BBB 20 06 92 JSR Q206 ;copy memory absolute 8BBE EQUW &C0,&00 ;FROM immediate filename+dir, &00C0 8BC0 EQUW &58,&10 ;TO catalogue block 2, &1058 8BC2 EQUB &08 ;count 8BC3 20 06 92 JSR Q206 ;copy memory absolute 8BC6 EQUW &40,&10 ;FROM catalogue block 1, &1040 8BC8 EQUW &C0,&00 ;back TO immediate filename+dir, &00C0 8BCA EQUB &08 ;count 8BCB 20 98 8C JSR PC98 ;init copy, find source file 8BCE 20 F8 8C JSR PCF8 ;ask to overwrite memory 8BD1 90 D0 BCC PBA3 ;if refused exit C=1 8BD3 20 03 A6 JSR R603 ;else unpack fields from cat 8BD6 A6 CC LDX &CC ;get catalogue pointer in X 8BD8 20 09 92 JSR Q209 ;copy target filename+dir 8BDB EQUW &58,&10 ;to catalogue entry 8BDD EQUW &08,&0E ;temporarily renaming the file 8BDF EQUB &08,&02 8BE1 20 49 8C JSR PC49 ;copy cat to cat2 and copy file 8BE4 4C 5B 8C JMP PC5B ;flush copy buffer &exit. .PBE7 ;*ENABLE 8BE7 A9 02 LDA #&02 ;set enabled flag b1=1 8BE9 8D 0F 10 STA &100F 8BEC 38 SEC ;break out of ROM call 8BED 60 RTS ;and exit .PBEE 8BEE A2 00 LDX #&00 ;Get and store source vol spec: .PBF0 8BF0 20 03 93 JSR Q303 ;Get and store dest vol spec .PBF3 8BF3 A5 C8 LDA &C8 ;get volume letter of spec, A = Immediate volume 8BF5 9D 72 10 STA &1072,X ;store it in source/dest info 8BF8 A5 C9 LDA &C9 ;get drive letter of spec, A = current drive 8BFA 9D 70 10 STA &1070,X ;store it in source/dest info 8BFD E8 INX ;move pointer from src to dest. 8BFE 60 RTS ;and exit .PBFF 8BFF AD 72 10 LDA &1072 ;Set up prompt flag 8C02 CD 73 10 CMP &1073 ;compare src and target volumes 8C05 D0 08 BNE PC0F ;if equal, then: 8C07 AD 70 10 LDA &1070 ;compare src and target drives 8C0A CD 71 10 CMP &1071 ;if equal,discs must be distinct 8C0D F0 34 BEQ PC43 ;so jump to set prompt bit .PC0F 8C0F AD 70 10 LDA &1070 ;else get source drive 8C12 4D 71 10 EOR &1071 ;XOR target drive 8C15 29 01 AND #&01 ;A=1 iff different units 8C17 D0 2F BNE PC48 ;if so then exit 8C19 20 18 90 JSR Q018 ;else ask, "Are source and target the same disc?" 8C1C EQUB &10 8C1D EQUS "Are source and target the same disc" 8C40 EQUB &00 ;terminator byte 8C41 F0 05 BEQ PC48 ;if Yes then exit .PC43 8C43 A9 40 LDA #&40 ;else, A = &40 8C45 8D 80 10 STA &1080 ;set prompt flag. .PC48 8C48 60 RTS ;exit .PC49 8C49 20 CE 8E JSR PECE ;copy entry from cat 1 to 2: ;Copy file. Fulfils the entry now in catalogue block 2. ;The pointer to the current file in the source catalogue is fetched ;by PECE and passed in X. It is saved at &107E while writing to the ;destination disc, then restored to &CC on exit (at &8C58, below). ;On entry if Y=0 then the file's contents are read from the source ;disc into the data buffer. ;If Y=1 then the file's contents are written from the data buffer ;on to the target disc, and the rest of the copy buffer is flushed. .PC4C ;Copy file 8C4C 20 2A 8F JSR PF2A ;set copy range = entry range 8C4F 20 5B 8E JSR PE5B ;read/write range to buffer 8C52 98 TYA 8C53 D0 09 BNE PC5E ;if write now due, flush else: 8C55 20 91 8D JSR PD91 ;ensure catalogue loaded 8C58 86 CC STX &CC ;save catalogue ptr 8C5A 60 RTS ;and exit. .PC5B 8C5B 20 58 8E JSR PE58 ;write(?) range, then: .PC5E 8C5E E4 AB CPX &AB ;Flush copy buffer. if empty 8C60 F0 31 BEQ PC93 ;then flush cat 1 and exit C=1 8C62 20 F0 8E JSR PEF0 ;else unpack cat 2 entry 8C65 20 91 8D JSR PD91 ;ensure catalogue loaded 8C68 20 06 92 JSR Q206 ;copy memory absolute 8C6B EQUW &C0,&00 ;FROM immediate filename+dir &00C0 8C6D EQUW &40,&10 ;TO catalogue block 1, &1040 (save filename being read) 8C6F EQUB &08 ;count 8C70 20 06 92 JSR Q206 ;copy memory absolute 8C73 EQUW &58,&10 ;FROM catalogue block 2, &1058 8C75 EQUW &C0,&00 ;TO immediate filename+dir, &00C0 (target file name) 8C77 EQUB &08 ;count 8C78 20 09 A5 JSR R509 ;find file in catalogue 8C7B B0 06 BCS PC83 ;if not found skip, else: 8C7D 20 21 A5 JSR R521 ;check file not locked 8C80 20 00 A6 JSR R600 ;delete catalogue entry .PC83 8C83 20 06 92 JSR Q206 ;copy memory absolute 8C86 EQUW &40,&10 ;FROM catalogue block 1, &1040 8C88 EQUW &C0,&00 ;TO immediate filename+dir, &00C0 (restore filename being read) 8C8A EQUB &08 ;count 8C8B 20 45 8F JSR PF45 ;create cat entry +*INFO 8C8E E6 A8 INC &A8 ;mark catalogue page as dirty 8C90 4C 4C 8C JMP PC4C ;and go back to Copy file! .PC93 8C93 20 A7 8D JSR PDA7 ;Flush catalogue, 8C96 38 SEC 8C97 60 RTS ;exit C=1 .PC98 ;Initialise copy 8C98 20 77 8D JSR PD77 ;initialise & load source disc 8C9B 20 0C A5 JSR R50C ;check file exists 8C9E AD 06 0F LDA &0F06 ;get top 3 bits of disc size 8CA1 8D 81 10 STA &1081 ;(+boot option), store 1081 8CA4 AD 70 10 LDA &1070 ;get source drive 8CA7 20 18 90 JSR Q018 ;print "Copying from vol "+n 8CAA EQUB &C0 8CAB EQUS "Copying from vol " 8CBC EQUB &00 ;terminator byte 8CBD AD 72 10 LDA &1072 ;get source vol letter 8CC0 20 00 90 JSR Q000 ;print it (print character in A) 8CC3 AD 71 10 LDA &1071 ;get target drive 8CC6 20 18 90 JSR Q018 ;print " to vol "+n 8CC9 EQUB &C0 8CCA EQUS " to vol " 8CD2 EQUB &00 ;terminator byte 8CD3 AD 73 10 LDA &1073 ;get target volume 8CD6 20 00 90 JSR Q000 ;print it (print character in A) 8CD9 4C 09 90 JMP Q009 ;print newline and exit. .PCDC 8CDC 20 EE 8B JSR PBEE ;Process *COPY, *SCOPY arguments 8CDF 20 F0 8B JSR PBF0 ;get &store src & dest vol specs 8CE2 20 15 93 JSR Q315 ;get ambiguous file spec 8CE5 20 98 8C JSR PC98 ;initialise copy 8CE8 20 FF 8B JSR PBFF ;set up prompt flag 8CEB 2C 80 10 BIT &1080 8CEE 50 08 BVC PCF8 8CF0 A9 01 LDA #&01 8CF2 0D 80 10 ORA &1080 8CF5 8D 80 10 STA &1080 ;copy prompt bit of flag to b0 .PCF8 ;Ask to overwrite memory only: 8CF8 A9 80 LDA #&80 .PCFA ;Ask user for confirmation 8CFA 0A ASL A 8CFB 90 1A BCC PD17 ;if b0=1 caller will wipe memory 8CFD 2C 7A 02 BIT &027A ;so test Tube presence 8D00 30 15 BMI PD17 ;if present caller won't wipe I/O 8D02 20 53 8D JSR PD53 ;else ensure *ENABLEd or warn 8D05 B0 4A BCS PD51 ;if *ENABLED exit C=1 8D07 20 18 90 JSR Q018 ;complete warning of memory loss 8D0A EQUB &02 8D0B EQUS "user memory" 8D16 EQUB &00 ;terminator byte .PD17 8D17 4A LSR A ;if b1=1 caller will wipe disc 8D18 F0 18 BEQ PD32 ;drive number in b2..3, now b0..1 8D1A 20 53 8D JSR PD53 ;ensure *ENABLED or warn 8D1D B0 32 BCS PD51 ;if *ENABLED exit C=1 8D1F 20 18 90 JSR Q018 ;complete warning of disc erasure 8D22 EQUB &C2 8D23 EQUS "disc in drive " 8D31 EQUB &00 ;terminator byte .PD32 8D32 20 18 90 JSR Q018 ;Ask if user wants to proceed 8D35 EQUB &15 8D36 EQUS "Do you want to proceed" 8D4C EQUB &00 ;terminator byte 8D4D F0 02 BEQ PD51 ;Z=yes, if so exit C=1 8D4F 18 CLC ;else 8D50 60 RTS ;exit C=0. .PD51 8D51 38 SEC 8D52 60 RTS ;exit C=1 .PD53 8D53 4E 0F 10 LSR &100F ;Print warning 8D56 B0 1E BCS PD76 ;return C=*ENABLEd 8D58 20 18 90 JSR Q018 ;if not *ENABLEd 8D5B EQUB &01 ;begin warning message. 8D5C EQUS "WARNING: will overwrite " 8D74 EQUB &00 ;terminator byte 8D75 18 CLC .PD76 8D76 60 RTS .PD77 ;Initialise and load source disc 8D77 A9 00 LDA #&00 8D79 A8 TAY ;clear A,Y 8D7A 85 AB STA &AB ;and &AB 8D7C A2 0B LDX #&0B .PD7E 8D7E 9D 76 10 STA &1076,X ;and &1076..81 8D81 CA DEX 8D82 10 FA BPL PD7E 8D84 A9 13 LDA #&13 ;A = 8271 read cmd for source drive 8D86 8D 74 10 STA &1074 8D89 A9 0B LDA #&0B ;A = 8271 write command for target 8D8B 8D 75 10 STA &1075 8D8E 20 C7 8D JSR PDC7 ;ask for disc, then: .PD91 8D91 48 PHA ;Ensure catalogue loaded 8D92 A5 A8 LDA &A8 ;get catalogue flag 8D94 D0 0F BNE PDA5 ;if catalogue empty 8D96 A5 C8 LDA &C8 ;then get immediate volume 8D98 F0 06 BEQ PDA0 ;if <>NUL, then 8D9A 20 00 9B JSR QB00 ;softmount and catalogue drive 8D9D 4C A3 8D JMP PDA3 .PDA0 8DA0 20 0C 9B JSR QB0C ;else softmount disc. .PDA3 8DA3 E6 A8 INC &A8 ;flag = 1, catalogue clean .PDA5 8DA5 68 PLA 8DA6 60 RTS ;restore A and exit. .PDA7 8DA7 48 PHA 8DA8 A5 A8 LDA &A8 ;Flush catalogue 8DAA C9 02 CMP #&02 ;save A, get page flag 8DAC 90 07 BCC PDB5 ;if page is empty or clean,then exit 8DAE 20 03 9B JSR QB03 ;else write catalogue 8DB1 A9 01 LDA #&01 8DB3 85 A8 STA &A8 ;and mark page as clean. .PDB5 8DB5 68 PLA 8DB6 60 RTS ;restore A and exit. .PDB7 8DB7 20 A7 8D JSR PDA7 ;Swap source and target discs 8DBA 48 PHA ;flush catalogue, save A 8DBB 8A TXA 8DBC 99 7E 10 STA &107E,Y ;store src cat pointer/garbage in temp 8DBF 98 TYA 8DC0 49 01 EOR #&01 ;toggle source/target drive 8DC2 A8 TAY 8DC3 BE 7E 10 LDX &107E,Y ;load garbage/src cat pointer into X 8DC6 68 PLA ;restore A, then: .PDC7 ;Ask for disc 8DC7 20 00 92 JSR Q200 ;save AXY 8DCA 2C 80 10 BIT &1080 ;test flag 8DCD 50 3C BVC PE0B ;if prompt bit clear then skip .PDCF 8DCF C0 00 CPY #&00 ;else test Y,if Y<>0 then ask for target 8DD1 D0 11 BNE PDE4 ;else ask for source 8DD3 20 18 90 JSR Q018 ;print "Is source" 8DD6 EQUB &00 8DD7 EQUS "Is source" 8DE0 EQUB &00 ;terminator byte 8DE1 4C F2 8D JMP PDF2 ;and jump. .PDE4 8DE4 20 18 90 JSR Q018 ;print "Is target" 8DE7 EQUB &00 8DE8 EQUS "Is target" 8DF1 EQUB &00 ;terminator byte .PDF2 8DF2 B9 70 10 LDA &1070,Y ;get source or target drv no. 8DF5 20 18 90 JSR Q018 ;ask " disc in drive "+n+"?" 8DF8 EQUB &D0 8DF9 EQUS " disc in drive " 8E08 EQUB &00 ;terminator byte 8E09 D0 C4 BNE PDCF ;if No then loop and ask again! .PE0B 8E0B 2C 80 10 BIT &1080 ;else test flag 8E0E 30 04 BMI PE14 ;if b7 clear 8E10 A2 00 LDX #&00 ;then mark catalogue empty. 8E12 86 A8 STX &A8 .PE14 8E14 B9 72 10 LDA &1072,Y ;get source/target volume 8E17 85 C8 STA &C8 ;A -> &00C8 = Immediate volume 8E19 B9 70 10 LDA &1070,Y ;get source/target drive 8E1C 85 C9 STA &C9 ;A = current drive/store immediate drive 8E1E A9 83 LDA #&83 ;call OSBYTE 8E20 20 F4 FF JSR &FFF4 ;to get OSHWM (High Water Mark) 8E23 86 A9 STX &A9 ;store in &A9,&AA 8E25 84 AA STY &AA ;pointer to catalogue 8E27 C8 INY 8E28 C8 INY ;increase by two pages 8E29 84 AC STY &AC ;store in &AC, &AB(=00) 8E2B A9 84 LDA #&84 ;pointer to buffer. 8E2D 20 F4 FF JSR &FFF4 ;call OSBYTE to get HIMEM 8E30 98 TYA 8E31 38 SEC 8E32 E5 AC SBC &AC ;subtract start of buffer 8E34 90 0E BCC PE44 ;if HIMEM <= buffer 8E36 F0 0C BEQ PE44 ;then error "No free memory" 8E38 85 AD STA &AD ;else store buffer size 8E3A AD 80 10 LDA &1080 ;test flag 8E3D 4A LSR A ;if bit 1 set 8E3E 90 03 BCC PE43 8E40 20 91 8D JSR PD91 ;then ensure catalogue loaded .PE43 8E43 60 RTS ;and exit. .PE44 8E44 20 18 90 JSR Q018 ;error "No free memory" 8E47 EQUB &0A ;LF 8E48 EQUB &D4 8E49 EQUS "No free memory" 8E57 EQUB &00 ;terminator byte .PE58 ;Copy data between discs 8E58 20 B7 8D JSR PDB7 ;swap discs &flsh cat: .PE5B 8E5B B9 76 10 LDA &1076,Y ;test src stg count 8E5E 19 78 10 ORA &1078,Y ;OR low & high bytes 8E61 D0 01 BNE PE64 ;if =0 8E63 60 RTS ;then exit .PE64 8E64 A5 AC LDA &AC ;else set O7F address 8E66 8D 12 10 STA &1012 ;to address of data buffer 8E69 A9 00 LDA #&00 8E6B 8D 11 10 STA &1011 8E6E A9 FF LDA #&FF 8E70 8D 13 10 STA &1013 8E73 8D 14 10 STA &1014 8E76 B9 74 10 LDA &1074,Y ;set command = Read for src disc 8E79 8D 16 10 STA &1016 ;or Write for target disc 8E7C A5 AD LDA &AD ;if buffer size = 0 8E7E F0 D8 BEQ PE58 ;then swap discs and start again 8E80 20 86 8E JSR PE86 ;else do disc transfer <= bufsiz 8E83 4C 5B 8E JMP PE5B ;and start again. .PE86 8E86 20 00 92 JSR Q200 ;Do disc transfer.A=sector count 8E89 BE 78 10 LDX &1078,Y ;save AXY. if source stg <256 8E8C D0 08 BNE PE96 8E8E D9 76 10 CMP &1076,Y 8E91 90 03 BCC PE96 8E93 B9 76 10 LDA &1076,Y ;then A = max(A, source stg). .PE96 8E96 85 AE STA &AE ;save sector count 8E98 84 AF STY &AF ;save source/target in temp 8E9A BE 7A 10 LDX &107A,Y ;get low byte of start sector 8E9D B9 7C 10 LDA &107C,Y ;get high byte 8EA0 A8 TAY ;set XY = start sector 8EA1 A5 AE LDA &AE ;get sector count in A 8EA3 20 06 9B JSR QB06 ;do LBA transfer 8EA6 98 TYA ;XY = last+1 sector 8EA7 A4 AF LDY &AF ;restore Y=source or target 8EA9 99 7C 10 STA &107C,Y ;store high byte 8EAC 8A TXA ;store low byte 8EAD 99 7A 10 STA &107A,Y 8EB0 B9 76 10 LDA &1076,Y ;subtract sector count from 8EB3 38 SEC ;source sectors-to-go 8EB4 E5 AE SBC &AE ;first low byte 8EB6 99 76 10 STA &1076,Y 8EB9 B9 78 10 LDA &1078,Y ;then borrow from high byte 8EBC E9 00 SBC #&00 8EBE 99 78 10 STA &1078,Y 8EC1 AD 12 10 LDA &1012 ;number of last+1 page 8EC4 85 AC STA &AC ;store start of data buffer 8EC6 A5 AD LDA &AD 8EC8 38 SEC 8EC9 E5 AE SBC &AE ;subtract sector count 8ECB 85 AD STA &AD ;from buffer size 8ECD 60 RTS ;exit. .PECE 8ECE A6 CC LDX &CC ;Copy entry from cat 1 to 2 8ED0 20 00 92 JSR Q200 ;cat ptr to X then save AXY 8ED3 A4 AB LDY &AB ;?&AB = offset in cat 2 8ED5 98 TYA ;put into A and Y 8ED6 18 CLC 8ED7 69 08 ADC #&08 ;add 8 to A 8ED9 85 AB STA &AB ;store as loop limit .PEDB 8EDB BD 08 0E LDA &0E08,X ;copy name part of cat entry 8EDE 91 A9 STA (&A9),Y ;to catalogue buffer 8EE0 E6 AA INC &AA ;point to next page up 8EE2 BD 08 0F LDA &0F08,X ;copy attributes of cat entry 8EE5 91 A9 STA (&A9),Y ;to catalogue buffer 8EE7 C6 AA DEC &AA ;point to original page 8EE9 E8 INX ;increment offsets 8EEA C8 INY 8EEB C4 AB CPY &AB ;compare with loop limit 8EED D0 EC BNE PEDB ;if equal exit else loop. 8EEF 60 RTS .PEF0 ;Unpack catalogue 2 entry 8EF0 20 00 92 JSR Q200 ;save AXY 8EF3 8A TXA ;X = offset in catalogue 2 8EF4 A8 TAY ;copy it to Y 8EF5 A2 00 LDX #&00 ;then set X = 0 .PEF7 8EF7 B1 A9 LDA (&A9),Y ;copy cat entry in buffer 2 8EF9 9D 40 10 STA &1040,X ;to packed area in cat block 1 8EFC E6 AA INC &AA 8EFE B1 A9 LDA (&A9),Y 8F00 9D 48 10 STA &1048,X 8F03 C6 AA DEC &AA 8F05 E8 INX 8F06 C8 INY 8F07 E0 08 CPX #&08 8F09 D0 EC BNE PEF7 8F0B AD 06 0F LDA &0F06 ;get cat 1 volume size high bits 8F0E 48 PHA ;save 8F0F AD 81 10 LDA &1081 ;put cat 2's size in its place 8F12 8D 06 0F STA &0F06 ;(to select 18/19 bit fields): 8F15 20 12 A6 JSR R612 ;unpack cat fields from wkspace 8F18 68 PLA ;and restore cat 1's size. 8F19 8D 06 0F STA &0F06 8F1C 20 06 92 JSR Q206 ;copy memory absolute 8F1F EQUW &40,&10 ;FROM cat block 1, &1040 8F21 EQUW &58,&10 ;TO block 2, &1058 8F23 EQUB &18 ;count 8F24 BA TSX ;return new offset in X 8F25 98 TYA ;Y -> A = 8F26 9D 04 01 STA &0104,X 8F29 60 RTS ;and exit. .PF2A ;Set copy range = entry range 8F2A 48 PHA 8F2B AD 53 10 LDA &1053 ;get sector count low byte 8F2E 99 76 10 STA &1076,Y ;store sectors-to-go low byte 8F31 AD 54 10 LDA &1054 ;same with high byte 8F34 99 78 10 STA &1078,Y 8F37 AD 51 10 LDA &1051 ;Y=0 selects source Y=1 target 8F3A 99 7A 10 STA &107A,Y ;absolute start sector low 8F3D AD 52 10 LDA &1052 ;(LBA) 8F40 99 7C 10 STA &107C,Y ;absolute start sector high 8F43 68 PLA 8F44 60 RTS ;restore A and exit. .PF45 8F45 20 09 A6 JSR R609 ;Create catalogue entry 8F48 20 06 A4 JSR R406 ;print *INFO line 8F4B 4C 09 90 JMP Q009 ;print newline and exit ;unused space from &8F4E ;unused space ends at &9000 ;Console output subsystem .Q000 9000 4C 1B 90 JMP Q01B ;Print character in A .Q003 9003 4C 54 90 JMP Q054 ;Print space .Q006 9006 4C 5C 90 JMP Q05C ;Tab to column in A .Q009 9009 4C 7E 90 JMP Q07E ;Display error message/newline .Q00C 900C 4C D7 90 JMP Q0D7 ;Print hex nibble .Q00F 900F 4C CC 90 JMP Q0CC ;Print hex byte .Q012 9012 4C F0 90 JMP Q0F0 ;Print decimal byte .Q015 9015 4C B1 90 JMP Q0B1 ;Print hex word absolute .Q018 9018 4C 19 91 JMP Q119 ;Print string immediate .Q01B ;Print character in A 901B 20 00 92 JSR Q200 ;save AXY 901E A4 F4 LDY &F4 ;get ROM type byte from ROM Select Register 9020 B9 A1 02 LDA &02A1,Y ;if b3=1 then error message 9023 29 08 AND #&08 ;so add the character to it 9025 D0 1E BNE Q045 ;else get *FX3 setting 9027 AD 7C 02 LDA &027C ;is *SPOOL output disabled? 902A 29 10 AND #&10 ;00010000 902C D0 10 BNE Q03E ;if so print the character 902E AD 7C 02 LDA &027C ;else disable *SPOOL output 9031 09 10 ORA #&10 9033 8D 7C 02 STA &027C 9036 B9 A1 02 LDA &02A1,Y ;and set b2=1 in ROM type byte 9039 09 04 ORA #&04 ;indicating it had been enabled. 903B 99 A1 02 STA &02A1,Y .Q03E 903E BA TSX 903F BD 05 01 LDA &0105,X ;get value in A on entry 9042 4C EE FF JMP &FFEE ;print it with OSWRCH and exit. .Q045 9045 BA TSX 9046 BD 05 01 LDA &0105,X ;add character to error message: 9049 AC 00 01 LDY &0100 ;get value of A on entry 904C 99 00 01 STA &0100,Y ;get offset to end of error 904F C8 INY ;store character at end 9050 8C 00 01 STY &0100 ;increment offset 9053 60 RTS ;store it and exit. .Q054 ;Print space 9054 48 PHA 9055 A9 20 LDA #&20 9057 20 1B 90 JSR Q01B ;Print character in A 905A 68 PLA 905B 60 RTS .Q05C ;Tab to column in A 905C 20 00 92 JSR Q200 ;Save AXY 905F A4 F4 LDY &F4 ;get ROM type byte 9061 B9 A1 02 LDA &02A1,Y 9064 29 08 AND #&08 ;test bit 3 9066 30 EC BMI Q054 ;if set print one space and exit .Q068 9068 20 54 90 JSR Q054 ;else print a space 906B A9 86 LDA #&86 906D 20 F4 FF JSR &FFF4 9070 8A TXA ;if cursor in column 0 9071 F0 06 BEQ Q079 ;then return A=0 9073 BA TSX ;else compare column number 9074 DD 05 01 CMP &0105,X ;with value of A on entry 9077 90 EF BCC Q068 ;if less print more spaces .Q079 9079 BA TSX ;return A=X coordinate 907A 9D 05 01 STA &0105,X ;of cursor 907D 60 RTS .Q07E ;Display error message/newline 907E 20 00 92 JSR Q200 ;save AXY 9081 A4 F4 LDY &F4 ;get ROM type byte 9083 B9 A1 02 LDA &02A1,Y ;clear b2..3 9086 48 PHA 9087 29 F3 AND #&F3 ;(mask bits 2-3) 9089 99 A1 02 STA &02A1,Y 908C 68 PLA ;if b3 was 1 908D 48 PHA 908E 29 08 AND #&08 ;(mask bits 0-2 and 4-7) 9090 D0 11 BNE Q0A3 ;do a BRK error message in stack 9092 20 E7 FF JSR &FFE7 ;else print a newline 9095 68 PLA 9096 29 04 AND #&04 ;if b2 was 1 enable *SPOOL 9098 F0 08 BEQ Q0A2 909A AD 7C 02 LDA &027C 909D 29 EF AND #&EF ;(mask bit 4) 909F 8D 7C 02 STA &027C .Q0A2 90A2 60 RTS ;and exit. .Q0A3 90A3 AC 00 01 LDY &0100 ;error message. get length of err 90A6 A9 00 LDA #&00 ;set NUL error message terminator 90A8 99 00 01 STA &0100,Y 90AB 8D 00 01 STA &0100 ;and BRK instruction over length 90AE 4C 00 01 JMP &0100 ;call BRK. .Q0B1 ;Print hex word absolute 90B1 20 00 92 JSR Q200 ;save AXY 90B4 20 03 92 JSR Q203 ;address follows caller's JSR 90B7 85 B2 STA &B2 ;store address in pointer 90B9 20 03 92 JSR Q203 ;Get byte immediate 90BC 85 B3 STA &B3 90BE BA TSX ;get status register on entry 90BF BD 06 01 LDA &0106,X 90C2 48 PHA ;C=print leading zeroes 90C3 28 PLP 90C4 A0 01 LDY #&01 ;offset to top byte of word 90C6 20 CA 90 JSR Q0CA ;fetch high byte and print 90C9 88 DEY ;point to bottom byte .Q0CA 90CA B1 B2 LDA (&B2),Y ;fetch it and fall through: .Q0CC ;Print hex byte 90CC 48 PHA 90CD 08 PHP ;upper nibble first 90CE 4A LSR A 90CF 4A LSR A 90D0 4A LSR A 90D1 4A LSR A 90D2 28 PLP 90D3 20 D7 90 JSR Q0D7 ;Print hex nibble 90D6 68 PLA ;then lower. Fall through: .Q0D7 ;Print hex nibble 90D7 48 PHA 90D8 29 0F AND #&0F ;on entry C=print leading zeroes 90DA F0 01 BEQ Q0DD ;on exit C=a nonzero was printed 90DC 38 SEC .Q0DD 90DD 08 PHP 90DE 09 20 ORA #&20 90E0 90 08 BCC Q0EA 90E2 09 30 ORA #&30 90E4 C9 3A CMP #&3A 90E6 90 02 BCC Q0EA 90E8 69 06 ADC #&06 .Q0EA 90EA 20 1B 90 JSR Q01B ;Print character in A 90ED 28 PLP 90EE 68 PLA 90EF 60 RTS .Q0F0 ;Print decimal byte 90F0 20 00 92 JSR Q200 ;save AXY 90F3 18 CLC ;C=0, suppress leading zeroes 90F4 A0 02 LDY #&02 ;start with the hundreds .Q0F6 90F6 08 PHP ;digit loop, save C 90F7 A2 00 LDX #&00 ;set dividend = 0 .Q0F9 90F9 D9 16 91 CMP &9116,Y ;subtract loop 90FC 90 07 BCC Q105 ;if A>=placevalue 90FE E8 INX ;then increment dividend 90FF 38 SEC ;and subtract placevalue 9100 F9 16 91 SBC &9116,Y ;from A 9103 D0 F4 BNE Q0F9 ;if A>0 subtract again .Q105 9105 28 PLP ;else restore C 9106 48 PHA ;save remnant 9107 8A TXA 9108 D0 02 BNE Q10C ;if dividend>0 then print it 910A 90 03 BCC Q10F ;if a leading zero skip it .Q10C 910C 20 D7 90 JSR Q0D7 ;else print it .Q10F 910F 68 PLA ;restore remnant 9110 88 DEY ;point to lower placevalue 9111 D0 E3 BNE Q0F6 ;if not units then loop 9113 38 SEC ;else units. set carry 9114 4C D7 90 JMP Q0D7 ;to print unit even if 0. exit. 9117 EQUB &0A ;placevalue 10 9118 EQUB &64 ;placevalue 100 ;Print string immediate ;The JSR instruction calling this routine is followed by: ;1 byte microcode (see below), 1 byte error number (if applicable), ;string terminated by NUL. ;The microcode byte is made up as follows: ;&01 .......1 Print newline before string ;&02 ......1. Print newline after string ;&04 .....1.. Beep at end of string ;&08 ...01... Error message, issue it if b1=1 or on JSR &9009 ;&10 ...10... Ask question, get yes/no answer, return Z=1, C=1 if yes ;&40 01...... Print hex value in A after string ;&80 10...... Print decimal value in A after string ;&C0 11...... Print character in A after string .Q119 ;Print string immediate 9119 20 00 92 JSR Q200 ;save AXY 911C 20 03 92 JSR Q203 ;get byte immediate 911F 48 PHA ;save it 9120 29 08 AND #&08 ;00001000 = mask bits 0-2 and 4-7 9122 F0 0F BEQ Q133 ;if b3=1 9124 A9 01 LDA #&01 ;then bottom of stack page =1 9126 8D 00 01 STA &0100 9129 A4 F4 LDY &F4 ;get our ROM socket number 912B B9 A1 02 LDA &02A1,Y ;get ROM type byte +flags 912E 09 08 ORA #&08 ;set b3=1 9130 99 A1 02 STA &02A1,Y ;store it back. .Q133 9133 68 PLA ;restore microcode byte 9134 A8 TAY ;copy to Y 9135 4A LSR A ;shift b0 into carry 9136 90 0A BCC Q142 ;if b0=1 9138 A9 0A LDA #&0A ;A = 913A 20 1B 90 JSR Q01B ;print character in A 913D A9 0D LDA #&0D ;A = 913F 20 1B 90 JSR Q01B ;print character in A .Q142 9142 20 03 92 JSR Q203 ;get byte immediate 9145 F0 06 BEQ Q14D ;if =NUL break out of loop 9147 20 1B 90 JSR Q01B ;else print the character in A 914A 4C 42 91 JMP Q142 ;and loop. .Q14D 914D BA TSX 914E BD 05 01 LDA &0105,X 9151 C0 80 CPY #&80 ;10000000 9153 90 10 BCC Q165 ;if microcode b7=1 9155 C0 C0 CPY #&C0 ;11000000 9157 90 06 BCC Q15F ;then if b6=1 9159 20 1B 90 JSR Q01B ;then 11.. Print character in A 915C 4C 6C 91 JMP Q16C .Q15F 915F 20 F0 90 JSR Q0F0 ;else 10.. Print decimal byte 9162 4C 6C 91 JMP Q16C .Q165 9165 C0 40 CPY #&40 ;01000000 9167 90 03 BCC Q16C ;else if b6=1 9169 20 CC 90 JSR Q0CC ;Print hex byte .Q16C 916C 98 TYA ;then 01.. print hex in A. 916D 29 02 AND #&02 ;mask bits 2-7 = restore microcode byte 916F F0 03 BEQ Q174 ;if b1=1 9171 20 7E 90 JSR Q07E ;Display error message/newline .Q174 9174 98 TYA ;restore microcode byte 9175 29 04 AND #&04 ;mask bits 0-1 and 3-4 9177 F0 05 BEQ Q17E ;if b2=1 9179 A9 07 LDA #&07 ;then A = 7 917B 20 1B 90 JSR Q01B ;Print character in A = send BEL to make a beep. .Q17E 917E 98 TYA ;restore microcode byte 917F 29 10 AND #&10 ;mask bits 0-3 and 5-7 9181 F0 45 BEQ Q1C8 ;if b4=1, then re-enter! 9183 20 18 90 JSR Q018 ;print "? " 9186 EQUB &00 9187 EQUS "? " 9189 EQUB &00 ;terminator byte 918A A2 00 LDX #&00 918C A9 15 LDA #&15 ;call *FX 15,1 918E 20 F4 FF JSR &FFF4 ;to clear input buffer .Q191 9191 20 E0 FF JSR &FFE0 ;call OSRDCH to GET character 9194 90 0C BCC Q1A2 ;if ESCAPE pressed, then re-enter 9196 20 18 90 JSR Q018 ;to print "Escape" error 9199 EQUB &0A 919A EQUB &11 919B EQUS "Escape" 91A1 EQUB &00 ;terminator byte .Q1A2 91A2 C9 59 CMP #&59 ;is it "Y"? 91A4 F0 16 BEQ Q1BC ;then register Yes 91A6 C9 79 CMP #&79 ;is it "y"? 91A8 F0 12 BEQ Q1BC ;then register Yes 91AA C9 4E CMP #&4E ;is it "N"? 91AC F0 04 BEQ Q1B2 ;then register No 91AE C9 6E CMP #&6E ;is it "n"? 91B0 D0 DF BNE Q191 ;if not get another keypress. .Q1B2 91B2 20 18 90 JSR Q018 ;else print "no" 91B5 EQUB &02 91B6 EQUS "no" 91B8 EQUB &00 ;terminator byte 91B9 C9 FF CMP #&FF ;return Z=0, C=0. 91BB 60 RTS .Q1BC 91BC 20 18 90 JSR Q018 ;print "yes" 91BF EQUB &02 91C0 EQUS "yes" 91C3 EQUB &00 ;terminator byte 91C4 A9 00 LDA #&00 91C6 C9 00 CMP #&00 .Q1C8 91C8 60 RTS ;return Z=1, C=1. ;unused space from &91C9 ;unused space ends at &9200 ;Macro functions and miscellaneous .Q200 9200 4C 12 92 JMP Q212 ;Save AXY .Q203 9203 4C 47 92 JMP Q247 ;Get byte immediate .Q206 9206 4C 68 92 JMP Q268 ;Copy memory absolute .Q209 9209 4C 6F 92 JMP Q26F ;Copy memory absolute indexed .Q20C 920C 6C 1E 02 JMP (&021E) ;Issue Filing System Call .Q20F 920F 4C 0F 92 JMP Q20F ;Halt ;Save AXY, to be restored when the calling routine exits. ;At that point the status register will be passed back to the ;superroutine as in a normal RTS. ;On return to the caller the stack will contain (right to left): ;&2E, &92, Y, X, A, P, return address(-1) low, return address(-1) high, ;superroutine address(-1) low, superroutine address(-1) high ;i.e. &0101,S = &2E; &0105,S = A. .Q212 ;Save AXY, etc 9212 08 PHP ;to be restored 9213 48 PHA ;when the calling routine 9214 8A TXA ;exits. At that point P 9215 48 PHA ;will be passed back to 9216 98 TYA ;the superroutine as in a 9217 48 PHA ;normal RTS. 9218 A9 92 LDA #&92 ;Within the call the stack 921A 48 PHA ;contains (right to left): 921B A9 2E LDA #&2E ;&2E,&92,Y,X,A,P,rl,rh 921D 48 PHA ;i.e. &0101,S = &A7 921E A0 06 LDY #&06 ;counter .Q220 9220 BA TSX ;get current stack pointer 9221 BD 08 01 LDA &0108,X ;peek at the 8th value down 9224 48 PHA ;push it on top, and loop x6. 9225 88 DEY ;(duplicates return address 9226 D0 F8 BNE Q220 ;and PAXY) 9228 68 PLA 9229 A8 TAY 922A 68 PLA 922B AA TAX 922C 68 PLA ;pop Y, X, A 922D 28 PLP ;pop P 922E 60 RTS ;and return to caller. ;Restore AXY. Invoked by the caller of "Save AXY" when it reaches ;an RTS. ;During the TSX at &9230 the stack contains (right to left): ;new P, old Y, X, A, P, return address(-1) low, return address(-1) high, ;superroutine address(-1) low, superroutine address(-1) high ;i.e. &0101,S = new P. 922F 08 PHP ;push status register on entry 9230 BA TSX 9231 BD 01 01 LDA &0101,X ;peek its value into A 9234 9D 05 01 STA &0105,X ;overwrite old status 9237 9D 06 01 STA &0106,X ;and "Save AXY" return address 923A 9D 07 01 STA &0107,X 923D 68 PLA ;discard address to restore AXY 923E 68 PLA ;pop A 923F A8 TAY 9240 68 PLA ;pop Y 9241 AA TAX 9242 68 PLA ;pop X 9243 28 PLP 9244 28 PLP 9245 28 PLP ;pop three copies of status 9246 60 RTS ;and return to superroutine ;Get byte immediate. The caller has already called "Save AXY", ;and before that the superroutine called the caller with JSR. ;After this JSR instruction is a number of bytes for the subroutine ;to process. This routine fetches the next byte for the subroutine ;and advances the return address back to the superroutine. ;During the TSX at &924A the stack contains (right to left): ;&2E, &92, caller Y, X, A, P, ;&49, &92, caller return address(-1) low, high, ;&2E, &92, superroutine Y, X, A, P, ;caller "save AXY" return address(-1) low, high, ;superroutine return address(-1) low, high ;therefore &0113..4,S = address of the immediate operand, less one. .Q247 ;Get byte immediate 9247 20 00 92 JSR Q200 ;save caller's AXY 924A BA TSX ;get stack pointer 924B 18 CLC 924C BD 13 01 LDA &0113,X 924F 69 01 ADC #&01 ;add 1 to superroutine return address 9251 9D 13 01 STA &0113,X ;save result back on stack 9254 85 B0 STA &B0 ;and as a pointer 9256 BD 14 01 LDA &0114,X 9259 69 00 ADC #&00 ;complete the addition on the high byte 925B 9D 14 01 STA &0114,X ;save back on stack 925E 85 B1 STA &B1 ;store high byte of pointer 9260 A0 00 LDY #&00 ;clear Y 9262 B1 B0 LDA (&B0),Y ;clear index register 9264 9D 05 01 STA &0105,X ;get byte at new pointer 9267 60 RTS ;return in A on exit. ;Copy memory absolute ;The JSR instruction calling this routine is followed by: ;2 bytes From address, 2 bytes To address, 1 byte length. ;Copying proceeds upwards in memory. .Q268 ;Copy memory absolute 9268 20 00 92 JSR Q200 ;Save AXY 926B A0 05 LDY #&05 ;5 argument bytes 926D D0 05 BNE Q274 ;and jump always ;Copy memory absolute indexed ;Arguments as for "Copy memory absolute", except there is a sixth byte: ;bits 4 to 7 of this byte control indexing of the From address, ;bits 0 and 1 control indexing of the To address. ;When the field is all zeroes the relevant address is used as is; ;otherwise one of the following values is added to the given address ;to form an effective address where the transfer will start. ;Bits Value to be added ;0000 or 00 Zero ;0001 or 01 Y on entry ;0010 or 10 X on entry ;0011 or 11 A on entry ;0100 P on entry ;0101 &71 ;0110 &92 ;0111 caller return address(-1) low byte ;1000 caller return address(-1) high byte ;1xxx undefined .Q26F ;Copy memory absolute indexed 926F 20 00 92 JSR Q200 ;Save AXY 9272 A0 06 LDY #&06 ;6 argument bytes .Q274 9274 A2 00 LDX #&00 ;clear offset 9276 86 B7 STX &B7 ;default to no indexing .Q278 9278 20 03 92 JSR Q203 ;fetch operand byte 927B 95 B2 STA &B2,X ;store in workspace 927D E8 INX ;increment offset 927E 88 DEY ;decrement counter 927F D0 F7 BNE Q278 ;loop while more argument bytes 9281 A5 B7 LDA &B7 ;get indexing argument 9283 4A LSR A 9284 4A LSR A 9285 4A LSR A 9286 4A LSR A ;move bits 7..4 to 3..0 9287 20 AD 92 JSR Q2AD ;fetch relevant index value/Interpret index bits 928A 65 B2 ADC &B2 ;add to From address 928C 85 B2 STA &B2 ;store back in workspace 928E 90 02 BCC Q292 ;if carry out occurs 9290 E6 B3 INC &B3 ;then increment high byte. .Q292 9292 A5 B7 LDA &B7 ;get indexing argument 9294 29 03 AND #&03 ;mask off From bits 9296 20 AD 92 JSR Q2AD ;mask bits 0-2 and 4-7/interpret To bits 9299 65 B4 ADC &B4 ;add relevant index to To address/interpret index bits 929B 85 B4 STA &B4 ;store back in workspace 929D 90 02 BCC Q2A1 ;if carry out occurs 929F E6 B5 INC &B5 ;then increment high byte. .Q2A1 92A1 A0 00 LDY #&00 ;clear offset .Q2A3 92A3 B1 B2 LDA (&B2),Y ;fetch byte from From area 92A5 91 B4 STA (&B4),Y ;store in To area 92A7 C8 INY ;increment offset 92A8 C4 B6 CPY &B6 ;have we copied all bytes? 92AA 90 F7 BCC Q2A3 ;if not then loop 92AC 60 RTS ;else exit. .Q2AD 92AD A8 TAY ;Interpret index bits. 92AE F0 08 BEQ Q2B8 ;if none set then return zero 92B0 BA TSX ;else put stack pointer in X .Q2B1 92B1 E8 INX ;add Y to X without using memory 92B2 88 DEY 92B3 D0 FC BNE Q2B1 ;Interpret index bits 92B5 BD 04 01 LDA &0104,X ;peek one of the saved registers .Q2B8 92B8 18 CLC 92B9 60 RTS ;clear carry for add and exit. ;unused space from &92BA #ifdef _UNUSED ;see comments at &AEC0 ;verbatim copy of *VERIFY code from &AEA8..BF; used code is 18 bytes tighter 92BA EQUB &82 92BB EQUS "track " 92C1 EQUB &00 92C2 60 RTS 92C3 20 18 90 JSR Q018 92C6 EQUB &02 92C7 EQUS "complete" 92CF EQUB &00 92D0 38 SEC 92D1 60 RTS ;verbatim copy of *CATGEN code from &ADC0..ED; used code is 18 bytes tighter 92D2 EQUB &60,&10 92D4 4E 61 10 LSR &1061 92D7 6E 60 10 ROR &1060 92DA 08 PHP 92DB 20 09 A4 JSR R409 92DE 28 PLP 92DF 90 07 BCC Q2E8 92E1 20 18 90 JSR Q018 92E4 EQUB &00 92E5 EQUS ".5" 92E7 EQUB &00 .Q2E8 92E8 20 09 90 JSR Q009 92EB 68 PLA 92EC 60 RTS 92ED 20 00 92 JSR Q200 92F0 A9 00 LDA #&00 92F2 8D 61 10 STA &1061 92F5 AE 70 10 LDX &1070 92F8 18 CLC 92F9 6D 74 10 ADC &1074 92FC 90 03 BCC Q301 92FE EQUB &EE,&61 #endif /* _UNUSED */ ;unused space ends at &9300 ;Parsing and validation .Q300 9300 4C 21 93 JMP Q321 ;Get drive spec .Q303 9303 4C 4A 93 JMP Q34A ;Get volume spec .Q306 9306 4C 34 93 JMP Q334 ;Get ambiguous volume spec .Q309 9309 4C 5B 93 JMP Q35B ;Get path spec 930C 4C 53 93 JMP Q353 ;Get ambiguous path spec .Q30F 930F 4C 77 93 JMP Q377 ;Get entry (dir+file) name .Q312 9312 4C 96 93 JMP Q396 ;Get file spec .Q315 9315 4C 8E 93 JMP Q38E ;Get ambiguous file spec .Q318 9318 4C 2B 94 JMP Q42B ;Get multiple drive spec .Q31B 931B 4C 53 94 JMP Q453 ;X=6, check volume letter .Q31E 931E 4C 5E 94 JMP Q45E ;Get space padded string char .Q321 ;Get drive spec 9321 20 00 92 JSR Q200 ;save AXY 9324 20 06 92 JSR Q206 ;copy memory absolute 9327 EQUW &09,&10 ;FROM default drive, &1009 9329 EQUW &C9,&00 ;TO immediate drive, &00C9 (current drive) 932B EQUB &01 ;count 932C A2 00 LDX #&00 ;as it's a "drive" spec 932E 20 6F 94 JSR Q46F ;parse drive spec 9331 4C CF 93 JMP Q3CF ;and finish. .Q334 ;Get ambiguous volume spec 9334 20 00 92 JSR Q200 ;save AXY / 0, :2, :1A, 3H, 1* etc. 9337 20 98 94 JSR Q498 ;get volume spec without error 933A B0 0B BCS Q347 ;if argument ends then finish 933C C9 2A CMP #&2A ;else is next character "*"? 933E D0 07 BNE Q347 ;if not then finish [BUG] "+" etc. OK 9340 A9 00 LDA #&00 ;else immed vol = NUL ambiguous 9342 85 C8 STA &C8 ;A -> &00C8 = Immediate volume 9344 20 C5 FF JSR &FFC5 ;call GSREAD .Q347 9347 4C CF 93 JMP Q3CF ;and finish. .Q34A ;Get volume spec 934A 20 00 92 JSR Q200 ;save AXY / 0A,:2B etc. 934D 20 98 94 JSR Q498 ;get volume spec without error 9350 4C CF 93 JMP Q3CF ;and finish .Q353 ;Get ambiguous path spec 9353 20 00 92 JSR Q200 ;save AXY 9356 A9 01 LDA #&01 ;*, :0.*, :3A.*, etc. & as below 9358 4C 60 93 JMP Q360 .Q35B ;Get path spec 935B 20 00 92 JSR Q200 ;save AXY 935E A9 00 LDA #&00 ;$, D, :0, :3.M, :2B.$, :1A etc. .Q360 9360 85 CE STA &CE ;A -> &00CE = ambiguous spec flag 9362 20 06 92 JSR Q206 ;copy memory absolute 9365 EQUW &07,&10 ;FROM default path, &1007 9367 EQUW &C7,&00 ;TO immediate path, &00C7 = Immediate dir 9369 EQUB &03 ;count 936A A2 0D LDX #&0D ;this is a "directory" spec 936C 20 AB 94 JSR Q4AB ;get volume part of path spec 936F B0 03 BCS Q374 ;if end-of-word then exit C=1. 9371 20 F0 94 JSR Q4F0 ;else get directory letter .Q374 9374 4C CF 93 JMP Q3CF ;and finish. .Q377 ;Get entry (dir+file) name/PROG, $.!BOOT, M.DTX 9377 20 00 92 JSR Q200 ;save AXY 937A A9 00 LDA #&00 ;clear A 937C 85 CE STA &CE ;A -> &00CE = ambiguous spec flag 937E 20 06 92 JSR Q206 ;copy memory absolute 9381 EQUW &00,&10 ;FROM default filename + directory, &1000 9383 EQUW &C0,&00 ;TO immediate filename + directory, &00C0 9385 EQUB &08 ;count 9386 A2 17 LDX #&17 ;this is an "entry" spec 9388 20 47 95 JSR Q547 ;set up and jump into file spec 938B 4C AA 93 JMP Q3AA .Q38E ;Get ambiguous file spec 938E 20 00 92 JSR Q200 ;save AXY 9391 A9 01 LDA #&01 ;INTRO, #####P, :2A.*.*, 9393 4C 9B 93 JMP Q39B ;(nothing) .Q396 ;Get file spec 9396 20 00 92 JSR Q200 ;save AXY 9399 A9 00 LDA #&00 ;KEYBD, B.DOTTY, :3.!BOOT, :2.$.LUNARLA, :A.DEBUG, :A.M.DEMO, :1G.DATA12, :0A.$.MENU, (nothing) .Q39B 939B 85 CE STA &CE ;A -> &00CE = ambiguous spec flag 939D 20 06 92 JSR Q206 ;copy memory absolute 93A0 EQUW &00,&10 ;FROM default filename and full path, &1000 93A2 EQUW &C0,&00 ;TO immediate filename and full path, &00C0 93A4 EQUB &0A ;count 93A5 A2 1D LDX #&1D ;this is a "file" spec 93A7 20 AB 94 JSR Q4AB ;get volume part of path spec .Q3AA 93AA B0 23 BCS Q3CF ;if end-of-word then exit C=1 93AC 20 1B 95 JSR Q51B ;else peek next char (AY presvd) 93AF D0 0C BNE Q3BD ;if it was <>".", get filename 93B1 20 F0 94 JSR Q4F0 ;else get directory letter 93B4 C9 2E CMP #&2E ;compare current char with "." 93B6 D0 1F BNE Q3D7 ;if unequal then "Bad spec" err 93B8 20 C5 FF JSR &FFC5 ;else call GSREAD 93BB B0 12 BCS Q3CF ;if end-of-word then finish .Q3BD 93BD 20 FA 94 JSR Q4FA ;else get filename proper 93C0 90 0D BCC Q3CF ;if invalid then finish, else: 93C2 A5 CE LDA &CE ;a = ambiguous spec flag 93C4 30 08 BMI Q3CE ;accept filename if this spec is unambiguous 93C6 20 06 92 JSR Q206 ;else, Copy memory absolute 93C9 EQUW &C0,&00 ;FROM immediate filename, &00C0 93CB EQUW &00,&10 ;TO default filename, &1000 93CD EQUB &07 ;count .Q3CE 93CE 38 SEC ;C=1 for success, fall through: .Q3CF ;Finish parsing. 93CF 90 06 BCC Q3D7 ;if C=0 then give bad spec error .Q3D1 ;Return Y to caller 93D1 BA TSX 93D2 98 TYA 93D3 9D 03 01 STA &0103,X ;A -> stack 93D6 60 RTS ;and exit .Q3D7 93D7 20 18 90 JSR Q018 ;Give bad spec error 93DA EQUB &08 93DB EQUB &CC 93DC EQUS "Bad " 93E0 EQUB &00 ;terminator byte 93E1 A5 CE LDA &CE ;A = ambiguous spec flag 93E3 F0 0F BEQ Q3F4 ;if unambiguous spec then skip 93E5 20 18 90 JSR Q018 ;else, Print character in A = ambiguous 93E8 EQUB &00 93E9 EQUS "ambiguous " 93F3 EQUB &00 ;terminator byte .Q3F4 93F4 BD 09 94 LDA &9409,X ;append type of spec 93F7 F0 06 BEQ Q3FF ;to error. if NUL, finish 93F9 20 00 90 JSR Q000 ;else 'print' character 93FC E8 INX ;increment offset and loop. 93FD D0 F5 BNE Q3F4 .Q3FF 93FF 20 18 90 JSR Q018 ;finish error with " spec". 9402 EQUB &02 9403 EQUS " spec" 9408 EQUB &00 ;terminator byte 9409 EQUS "drive" 940E EQUB &00 ;terminator byte 940F EQUS "volume" 9415 EQUB &00 ;terminator byte 9416 EQUS "directory" 941F EQUB &00 ;terminator byte 9420 EQUS "entry" 9425 EQUB &00 ;terminator byte 9426 EQUS "file" 942A EQUB &00 ;terminator byte .Q42B ;Get multiple drive spec 942B 20 00 92 JSR Q200 ;save AXY 942E A2 00 LDX #&00 ;(nothing), 0, :2, :1 2, 1 :3 .Q430 9430 20 47 95 JSR Q547 ;call GSINIT C=0 then GSREAD 9433 B0 1B BCS Q450 ;if end-of-word then finish 9435 C9 3A CMP #&3A ;else compare this char with ":" 9437 D0 06 BNE Q43F ;if unequal try it as drive no. 9439 20 7C 94 JSR Q47C ;else get drive character 943C 4C 47 94 JMP Q447 ;and loop if EOW else bad spec. .Q43F 943F 20 8A 94 JSR Q48A ;validate and store drive number 9442 90 08 BCC Q44C ;if invalid return in A 9444 20 C5 FF JSR &FFC5 ;else call GSREAD .Q447 9447 B0 E7 BCS Q430 ;if end-of-word then loop 9449 4C D7 93 JMP Q3D7 ;else give "Bad spec" error. .Q44C ;Return A and Y to caller 944C BA TSX 944D 9D 05 01 STA &0105,X .Q450 9450 4C D1 93 JMP Q3D1 .Q453 ;X=6, check volume letter 9453 20 00 92 JSR Q200 ;save AXY 9456 A2 06 LDX #&06 ;this is a "volume" spec 9458 20 D8 94 JSR Q4D8 ;Validate volume letter 945B 4C CF 93 JMP Q3CF ;or error if invalid. .Q45E ;Get space padded string char 945E 24 E4 BIT &E4 ;if b6=1, this routine reached EOS 9460 70 09 BVS Q46B ;(or C=1 to GSINIT!) so return space 9462 20 C5 FF JSR &FFC5 ;else GSREAD 9465 90 07 BCC Q46E ;if not EOS return A=character, C=0 9467 66 E4 ROR &E4 9469 66 E4 ROR &E4 ;else set b6=1, signal EOS to self .Q46B 946B A9 20 LDA #&20 ;return a space 946D 38 SEC .Q46E 946E 60 RTS ;and exit C=1 (end-of-string) .Q46F ;Parse drive spec 946F A9 00 LDA #&00 ;A = 0 = ambiguous spec not allowed 9471 85 CE STA &CE ;0 -> &00CE = ambiguous spec flag 9473 20 47 95 JSR Q547 ;call GSINIT C=0 then GSREAD 9476 B0 11 BCS Q489 ;if end-of-word then exit C=1 9478 C9 3A CMP #&3A ;else compare with ":" 947A D0 05 BNE Q481 ;if unequal try as drive number .Q47C 947C 20 C5 FF JSR &FFC5 ;else call GSREAD 947F B0 08 BCS Q489 ;if end-of-word exit C=1, else: .Q481 9481 20 8A 94 JSR Q48A ;Get drive character 9484 90 03 BCC Q489 ;test&store, if invalid exit C= 0 9486 20 C5 FF JSR &FFC5 ;else call GSREAD .Q489 9489 60 RTS ;and exit. .Q48A ;Validate and store drive number 948A C9 30 CMP #&30 ;if less than ASCII "0" 948C 90 08 BCC Q496 948E C9 34 CMP #&34 ;or greater than "3" 9490 B0 04 BCS Q496 ;then exit C=0 9492 85 C9 STA &C9 ;else store immediate drive/A -> current drive 9494 38 SEC 9495 60 RTS ;and exit C = 1. .Q496 9496 18 CLC 9497 60 RTS ;exit C = 0 .Q498 ;Get volume spec without error 9498 20 06 92 JSR Q206 ;copy memory absolute 949B EQUW &08,&10 ;FROM default volume letter and drive number, &1008 949D EQUW &C8,&00 ;TO immediate volume letter and drive number, &00C8 949F EQUB &02 ;count 94A0 A2 06 LDX #&06 ;this is a "volume" spec 94A2 20 6F 94 JSR Q46F ;parse drive spec 94A5 B0 03 BCS Q4AA ;if end-of-word exit C=1 94A7 20 CF 94 JSR Q4CF ;else get volume letter & exit. .Q4AA 94AA 60 RTS ;exit .Q4AB ;Get volume part of path spec 94AB 20 47 95 JSR Q547 ;call GSINIT C=0 then GSREAD 94AE B0 1E BCS Q4CE ;if EOW exit C=1 else compare 94B0 C9 3A CMP #&3A ;if this char <> ":" 94B2 D0 19 BNE Q4CD ;then exit C=0 94B4 20 C5 FF JSR &FFC5 ;else call GSREAD 94B7 B0 15 BCS Q4CE ;if end-of-word exit C=1 94B9 20 81 94 JSR Q481 ;else get drive character 94BC B0 10 BCS Q4CE ;if end-of-word exit C=1 94BE 20 CF 94 JSR Q4CF ;else get volume letter 94C1 B0 0B BCS Q4CE ;if end-of-word exit C=1 94C3 C9 2E CMP #&2E ;else compare this char to "." 94C5 F0 03 BEQ Q4CA ;if equal call GSREAD and exit .Q4C7 94C7 4C D7 93 JMP Q3D7 ;else give "Bad spec" error. .Q4CA 94CA 4C C5 FF JMP &FFC5 ;call GSREAD and exit. .Q4CD 94CD 18 CLC ;C=0 .Q4CE 94CE 60 RTS ;exit. .Q4CF 94CF 20 D8 94 JSR Q4D8 ;Get volume letter 94D2 90 03 BCC Q4D7 ;test&store, if invalid exit C=0 94D4 20 C5 FF JSR &FFC5 ;else call GSREAD and exit. .Q4D7 94D7 60 RTS ;exit. .Q4D8 ;Validate volume letter 94D8 C9 41 CMP #&41 ;is it < ASCII 'A'? 94DA 90 12 BCC Q4EE ;if less than "A" exit C=0 94DC C9 49 CMP #&49 ;is it >= ASCII 'I'? 94DE 90 0A BCC Q4EA ;then store and exit C=1 94E0 C9 61 CMP #&61 ;is it < ASCII 'a'? 94E2 90 0A BCC Q4EE ;then exit C=0 94E4 C9 69 CMP #&69 ;is it >= ASCII 'i'? 94E6 B0 06 BCS Q4EE ;then exit C=0 94E8 29 DF AND #&DF ;convert to uppercase .Q4EA 94EA 85 C8 STA &C8 ;A -> &00C8 = Immediate volume 94EC 38 SEC 94ED 60 RTS ;and exit C=1 .Q4EE 94EE 18 CLC 94EF 60 RTS .Q4F0 94F0 20 24 95 JSR Q524 ;Get directory letter 94F3 90 D2 BCC Q4C7 ;test spec char, error if bad 94F5 85 C7 STA &C7 ;else store immediate directoryImmediate dir'y -> &00C7 94F7 4C C5 FF JMP &FFC5 ;call GSREAD and exit. .Q4FA ;Get filename proper 94FA 20 00 92 JSR Q200 ;save AXY 94FD A2 00 LDX #&00 ;X is now just an offset .Q4FF 94FF 20 24 95 JSR Q524 ;test spec character 9502 90 14 BCC Q518 ;if invalid return Y, exit C=0 9504 95 C0 STA &C0,X ;else store immediate filename 9506 E8 INX ;increment offset 9507 E0 07 CPX #&07 ;have we taken 7 characters? 9509 F0 0A BEQ Q515 ;if so get pad char and finish 950B C9 2A CMP #&2A ;else compare this char with "*" 950D F0 03 BEQ Q512 ;if unequal, then: 950F 20 1E 93 JSR Q31E ;get space padded character. .Q512 9512 4C FF 94 JMP Q4FF ;now loop for more characters. .Q515 9515 20 1E 93 JSR Q31E ;get space padded character .Q518 9518 4C D1 93 JMP Q3D1 ;return Y to caller and exit. .Q51B 951B 20 00 92 JSR Q200 ;save AXY 951E 20 1E 93 JSR Q31E ;Peek next char and compare "." 9521 C9 2E CMP #&2E ;get padded char 9523 60 RTS ;and return Z=1 if equals "." .Q524 9524 C9 3A CMP #&3A ;is it ASCII ':'?/Test spec character 9526 F0 19 BEQ Q541 ;if so exit C=0 9528 C9 2E CMP #&2E ;else, is it ASCII '.'? 952A F0 15 BEQ Q541 ;if so exit C=0 952C C9 2A CMP #&2A ;else, is it ASCII '*'? 952E F0 04 BEQ Q534 ;if so go flag ambiguous 9530 C9 23 CMP #&23 ;else, is it ASCII '#'? 9532 D0 0A BNE Q53E ;if anything else exit C=1 .Q534 9534 48 PHA ;else save character 9535 A5 CE LDA &CE ;A = ambiguous file spec flag 9537 F0 07 BEQ Q540 ;if ambiguous file specs not allowed then exit C=0 9539 A9 FF LDA #&FF ;else flag = &FF 953B 85 CE STA &CE ;as this spec is ambiguous/A -> &00CE = ambiguous file spec flag 953D 68 PLA ;retrieve character .Q53E 953E 38 SEC 953F 60 RTS ;and exit C=1. .Q540 9540 68 PLA ;retrieve character .Q541 9541 18 CLC 9542 60 RTS ;exit C=0 .Q543 9543 18 CLC 9544 4C C2 FF JMP &FFC2 ;Call GSINIT with C=0. .Q547 ;Call GSINIT C=0 then GSREAD 9547 20 43 95 JSR Q543 954A 4C C5 FF JMP &FFC5 ;unused space from &954D ;unused space ends at &9600 ;EDOS setup .Q600 9600 4C 1E 96 JMP Q61E ;Print EDOS banner .Q603 9603 4C 3C 96 JMP Q63C ;Initialise EDOS .Q606 9606 4C 12 97 JMP Q712 ;Save workspace to private page .Q609 9609 4C 2A 97 JMP Q72A ;Get boot option 960C EQUS "OFF LOAD RUN EXEC " ;boot commands/descriptions 0..3 .Q61E ;Print EDOS banner 961E 20 00 92 JSR Q200 ;save AXY 9621 A2 00 LDX #&00 ;set character offset=0 (to be 1) 9623 20 2F 96 JSR Q62F ;print "OPUS EDOS" 9626 20 03 90 JSR Q003 ;print a space 9629 20 2F 96 JSR Q62F ;print version string 962C 4C 09 90 JMP Q009 ;print newline and exit. .Q62F ;Print title string. inc offset 962F E8 INX 9630 BD 08 80 LDA &8008,X ;get character from ROM title 9633 F0 06 BEQ Q63B ;if zero then exit 9635 20 00 90 JSR Q000 ;else print character in A 9638 4C 2F 96 JMP Q62F ;and repeat .Q63B 963B 60 RTS .Q63C ;Initialise EDOS 963C 20 00 92 JSR Q200 ;save AXY 963F A9 06 LDA #&06 ;issue OSFSC 6 to notify current 9641 20 0C 92 JSR Q20C ;FS. 9644 AD 38 02 LDA &0238 ;set up pointer in zero page 9647 85 AA STA &AA ;to point to extended 9649 AD 39 02 LDA &0239 ;vector table 964C 85 AB STA &AB 964E A2 00 LDX #&00 ;set X=0 offset in preset table 9650 A0 1B LDY #&1B ;set Y=&1B offset in EVT .Q652 9652 20 DA 96 JSR Q6DA 9655 20 DA 96 JSR Q6DA ;copy two bytes from ROM to EVT 9658 A5 F4 LDA &F4 ;add our ROM number to the table 965A 91 AA STA (&AA),Y 965C C8 INY 965D E0 0E CPX #&0E ;have we copied 7 vectors? 965F D0 F1 BNE Q652 ;if not loop 9661 A2 0F LDX #&0F ;issue ROM service call &F, 9663 A9 8F LDA #&8F ;vectors have been changed 9665 20 F4 FF JSR &FFF4 9668 A2 0A LDX #&0A ;issue ROM service call &A, 966A A9 8F LDA #&8F ;claiming absolute workspace 966C 20 F4 FF JSR &FFF4 966F 20 3A 97 JSR Q73A ;test flag in private page 9672 C9 EF CMP #&EF ;=&EF workspace stowed? 9674 F0 13 BEQ Q689 ;if so go and unstow 9676 20 00 96 JSR Q600 ;else print EDOS banner 9679 A0 00 LDY #&00 ;clear y for use as offset: .Q67B 967B B9 04 97 LDA &9704,Y ;get meta-default path and lib 967E C0 0E CPY #&0E ;if we've copied it all then 9680 90 02 BCC Q684 9682 A9 00 LDA #&00 ;a=0 to clear rest of page .Q684 9684 91 A8 STA (&A8),Y 9686 C8 INY 9687 D0 F2 BNE Q67B .Q689 9689 A0 0D LDY #&0D ;store &BE, workspace unstowed 968B A9 BE LDA #&BE ;in flag in private page 968D 91 A8 STA (&A8),Y 968F A0 00 LDY #&00 ;copy private page to absolute .Q691 9691 B1 A8 LDA (&A8),Y ;workspace 9693 99 00 10 STA &1000,Y 9696 C8 INY 9697 D0 F8 BNE Q691 9699 20 06 92 JSR Q206 ;copy default path to zero page 969C EQUW &00,&10 ;FROM boot command, &1000 969E EQUW &C0,&00 ;TO string workspace &00C0 96A0 EQUB &0A ;count 96A1 A9 36 LDA #&36 ;&36 = EDOS pseudo-command 96A3 8D 16 10 STA &1016 ;2791 Force Interrupt 96A6 20 12 9B JSR QB12 ;issue plain OSWORD &7F 96A9 BA TSX ;get value of Y on entry 96AA BD 03 01 LDA &0103,X 96AD D0 20 BNE Q6CF ;if Y=0 exit with C=1, break out 96AF 20 00 9B JSR QB00 ;else softmount & load cat 96B2 20 09 96 JSR Q609 ;get boot option 96B5 F0 18 BEQ Q6CF ;if boot is OFF, exit C=1 96B7 20 09 92 JSR Q209 ;else copy boot command 96BA EQUW &0C,&96 ;from &960C 96BC EQUW &58,&10 ;to string workspace at &1058 96BE EQUB &04,&20 ;4 bytes, X indexed source 96C0 20 06 92 JSR Q206 ;copy 96C3 EQUW &D1,&96 ;FROM filename " $.!boot"+cr, Q6D1 96C5 EQUW &5C,&10 ;TO address &105C 96C7 EQUB &09 ;count 9 bytes 96C8 A2 58 LDX #&58 ;call OSCLI on command string 96CA A0 10 LDY #&10 96CC 20 F7 FF JSR &FFF7 .Q6CF 96CF 38 SEC ;set C=1 to break out of ROM call 96D0 60 RTS ;and exit .Q6D1 96D1 EQUS " $.!boot" ;"$.!boot" name of boot file 96D9 EQUB &0D ;CR .Q6DA 96DA BD E8 96 LDA &96E8,X ;get preset vector 96DD 9D 12 02 STA &0212,X ;store in vector tbl 96E0 BD F6 96 LDA &96F6,X ;get extended vector preset 96E3 91 AA STA (&AA),Y ;store in extended vector table 96E5 E8 INX ;increment pair offset 96E6 C8 INY ;increment triplet offset 96E7 60 RTS ;exit ;Vectors to extended vector handlers, 7 pairs [0..13] 96E8 EQUW &1B,&FF ;&FF1B 96EA EQUW &1E,&FF ;&FF1E 96EC EQUW &21,&FF ;&FF21 96EE EQUW &24,&FF ;&FF24 96F0 EQUW &27,&FF ;&FF27 96F2 EQUW &2A,&FF ;&FF2A 96F4 EQUW &2D,&FF ;&FF2D 96F6 EQUW &00,&B0 ;S000, FILEV for OSFILE 96F8 EQUW &03,&B0 ;S003, ARGSV for OSARGS 96FA EQUW &00,&B4 ;S400, BGETV for OSBGET 96FC EQUW &03,&B4 ;S403, BPUTV for OSBPUT 96FE EQUW &06,&B4 ;S406, GBPBV for OSGBPB 9700 EQUW &06,&B0 ;S006, FINDV for OSFIND 9702 EQUW &09,&B0 ;S009, FSCV for OSFSC 9704 EQUS " " ;Meta-default filename and path 970B EQUS "$A0" ;directory, volume and drive 970E EQUS "$A0" ;default library 9711 EQUB &BE ;flag BE = we own absolute wksp .Q712 ;Save workspace to private page 9712 20 00 92 JSR Q200 ;save AXY 9715 20 3A 97 JSR Q73A ;if flag in private page+&D <> &BE 9718 D0 0F BNE Q729 ;then exit 971A A9 EF LDA #&EF ;else set absolute page flag = &EF 971C 8D 0D 10 STA &100D ;meaning workspace stowed 971F A0 00 LDY #&00 ;and copy workspace to private pg. .Q721 9721 B9 00 10 LDA &1000,Y ;load one byte from abs page 9724 91 A8 STA (&A8),Y ;store in private page 9726 C8 INY ;increment offset 9727 D0 F8 BNE Q721 ;loop until whole page done .Q729 9729 60 RTS ;exit .Q72A ;Get boot option 972A AD 06 0F LDA &0F06 972D 29 30 AND #&30 ;extract boot option 972F 4A LSR A ;shift right twice 9730 4A LSR A ;A=0,4,8 or 12 9731 AA TAX ;copy to X 9732 E0 08 CPX #&08 ;if X>=8, increment X 9734 90 01 BCC Q737 9736 E8 INX ;now X=0,4,9 or 13 .Q737 9737 4A LSR A ;shift A right twice more 9738 4A LSR A ;return A=0 to 3, X=string ptr 9739 60 RTS .Q73A ;Test if private page available 973A A4 F4 LDY &F4 973C B9 F0 0D LDA &0DF0,Y ;get private page no. for our rom 973F 85 A9 STA &A9 ;set high byte of pointer 9741 A9 00 LDA #&00 ;clear low byte of pointer 9743 85 A8 STA &A8 9745 A0 0D LDY #&0D ;load byte &D of private page 9747 B1 A8 LDA (&A8),Y ;through the pointer 9749 C9 BE CMP #&BE ;compare with value &BE 974B 60 RTS ;return Z=page available ;unused space from &974C ;unused space ends at &9800 ;Channel operations .Q800 9800 4C 24 98 JMP Q824 ;Initialise for open file .Q803 9803 4C 4E 98 JMP Q84E ;Init & check file open .Q806 9806 4C AC 98 JMP Q8AC ;Check file not open (mutex) .Q809 9809 4C 73 98 JMP Q873 ;Get unused file handle .Q80C 980C 4C 9E 98 JMP Q89E ;Check file open & return pointer .Q80F 980F 4C 0C 99 JMP Q90C ;Flush open file .Q812 9812 4C 20 99 JMP Q920 ;Transfer file buffer to LBA .Q815 9815 4C 49 99 JMP Q949 ;Close open file .Q818 9818 4C 6B 99 JMP Q96B ;Close all files .Q81B 981B 4C 84 99 JMP Q984 ;Check volume not changed .Q81E 981E 4C C7 99 JMP Q9C7 ;Open a file .Q821 9821 4C 2E 9A JMP QA2E ;Print disc/volume error message .Q824 ;Initialise for open file 9824 86 CB STX &CB ;set pointer to buffer 9826 A0 00 LDY #&00 ;clear Y 9828 84 CA STY &CA ;clear &00CA 982A E0 11 CPX #&11 ;validate file handle 982C 90 10 BCC Q83E ;if less than &11, branch 982E E0 16 CPX #&16 ;else is X > 22? 9830 B0 0C BCS Q83E ;if greater than &16, branch 9832 BC 28 98 LDY &9828,X ;else, point Y to file workspace 9835 B9 88 10 LDA &1088,Y ;put file flag byte in A .Q838 9838 60 RTS 9839 EQUB &00 ;indexed by X above 983A EQUB &18 ;table to start of workspace 983B EQUB &30 ;for channels &11..15 983C EQUB &48 983D EQUB &60 .Q83E 983E 20 64 98 JSR Q864 ;print "Channel n" 9841 20 18 90 JSR Q018 ;print " invalid" 9844 EQUB &02 9845 EQUS " invalid" 984D EQUB &00 ;terminator byte .Q84E ;Init & check file open 984E 20 00 98 JSR Q800 ;Initialise for open file 9851 D0 E5 BNE Q838 ;if file closed 9853 20 64 98 JSR Q864 ;print "Channel n" 9856 20 18 90 JSR Q018 ;print " not open" 9859 EQUB &02 985A EQUS " not open" 9863 EQUB &00 ;terminator byte .Q864 9864 8A TXA 9865 20 18 90 JSR Q018 9868 EQUB &88 9869 EQUB &DE 986A EQUS "Channel " 9872 EQUB &00 ;terminator byte .Q873 ;Get unused file handle 9873 48 PHA 9874 A2 11 LDX #&11 ;start with lowest handle &11 .Q876 9876 20 00 98 JSR Q800 ;initialise for this handle 9879 F0 21 BEQ Q89C ;if handle unused exit 987B E8 INX ;else increment handle number 987C E0 16 CPX #&16 ;have we run out of handles? 987E D0 F6 BNE Q876 ;if not try next handle 9880 20 18 90 JSR Q018 ;else give error 9883 EQUB &0A ;LF 9884 EQUB &C0 9885 EQUS "Too many open channels" 989B EQUB &00 ;terminator byte .Q89C 989C 68 PLA ;return unused handle in X 989D 60 RTS .Q89E ;Check file open & return pointer 989E 20 00 92 JSR Q200 ;save AXY 98A1 98 TYA ;copy handle to X 98A2 AA TAX 98A3 20 03 98 JSR Q803 ;initialise & check file open 98A6 BA TSX ;return workspace pointer in Y 98A7 98 TYA 98A8 9D 03 01 STA &0103,X ;save on stack 98AB 60 RTS .Q8AC ;Check file not open (mutex) 98AC 20 00 92 JSR Q200 ;save AXY 98AF A2 11 LDX #&11 ;start with lowest handle &11 .Q8B1 98B1 20 00 98 JSR Q800 ;initialise for this handle 98B4 F0 41 BEQ Q8F7 ;no match if handle is unused 98B6 BA TSX ;get A on entry. b7=we want to 98B7 1D 05 01 ORA &0105,X ;open for writing. if request and 98BA 10 3B BPL Q8F7 ;handle both read only, no match. 98BC A2 08 LDX #&08 ;else 8 characters to compare 98BE 86 B9 STX &B9 ;store a counter 98C0 A6 CC LDX &CC ;point X to filename in catalogue .Q8C2 98C2 BD 08 0E LDA &0E08,X ;get character of file/dir name 98C5 20 FF 98 JSR Q8FF ;convert to upper case 98C8 85 B8 STA &B8 ;store in temp location 98CA B9 8A 10 LDA &108A,Y ;get filename char fr this handle 98CD 20 FF 98 JSR Q8FF ;convert to upper case 98D0 C5 B8 CMP &B8 ;compare with catalogue char 98D2 D0 23 BNE Q8F7 ;no match if unequal 98D4 E8 INX ;else increment catalogue ptr 98D5 C8 INY ;and handle pointer 98D6 C6 B9 DEC &B9 ;one less char to compare 98D8 D0 E8 BNE Q8C2 ;loop if more characters 98DA A5 C8 LDA &C8 ;else get volume of subject file, A = Immediate volume 98DC D9 8A 10 CMP &108A,Y ;compare with volume of handle 98DF D0 16 BNE Q8F7 ;no match if unequal 98E1 A5 C9 LDA &C9 ;else get drive of subject file, A = current drive 98E3 D9 8B 10 CMP &108B,Y ;compare with drive of handle 98E6 D0 0F BNE Q8F7 ;no match if unequal 98E8 20 18 90 JSR Q018 ;else a match, "File open" error. 98EB EQUB &0A ;LF 98EC EQUB &C2 98ED EQUS "File open" 98F6 EQUB &00 ;terminator byte .Q8F7 ;put handle number back in X 98F7 A6 CB LDX &CB ;set pointer to buffer 98F9 E8 INX ;increment handle number 98FA E0 16 CPX #&16 ;have we run out of handles? 98FC D0 B3 BNE Q8B1 ;if not try next handle 98FE 60 RTS ;if so then file not open, exit .Q8FF ;Convert to uppercase 98FF 29 7F AND #&7F ;mask b7 9901 C9 61 CMP #&61 ;less than "a"? 9903 90 06 BCC Q90B ;if so return 9905 C9 7B CMP #&7B ;more than "z"? 9907 B0 02 BCS Q90B ;if so return 9909 29 DF AND #&DF ;else return ASCII value A-Z .Q90B 990B 60 RTS .Q90C ;Flush file buffer 990C 20 00 92 JSR Q200 ;save AXY 990F B9 89 10 LDA &1089,Y ;test if page is dirty 9912 C9 02 CMP #&02 9914 A9 00 LDA #&00 9916 99 89 10 STA &1089,Y ;mark it empty 9919 90 F0 BCC Q90B 991B A9 4B LDA #&4B ;if it was dirty, write it out. 991D 4C 23 99 JMP Q923 .Q920 ;Transfer file buffer to LBA 9920 20 00 92 JSR Q200 ;save AXY .Q923 9923 8D 16 10 STA &1016 ;A=command, store it 9926 B9 93 10 LDA &1093,Y ;get drive the file is on 9929 85 C9 STA &C9 ;current drive -> &00C9 992B A5 CA LDA &CA ;give address of buffer 992D 8D 11 10 STA &1011 9930 A5 CB LDA &CB 9932 8D 12 10 STA &1012 9935 A9 FF LDA #&FF ;in I/O processor 9937 8D 13 10 STA &1013 993A 8D 14 10 STA &1014 993D BE 96 10 LDX &1096,Y ;and desired absolute sector 9940 B9 97 10 LDA &1097,Y 9943 A8 TAY 9944 A9 01 LDA #&01 ;one sector to transfer 9946 4C 06 9B JMP QB06 ;do it .Q949 ;Close open file 9949 20 0F 98 JSR Q80F ;flush buffer 994C 24 CD BIT &CD ;if &CD b7=1 994E 30 33 BMI Q983 ;then exit 9950 48 PHA ;else clear channel flags 9951 A9 00 LDA #&00 9953 99 88 10 STA &1088,Y 9956 68 PLA ;if bit 7 of A clear then exit 9957 10 2A BPL Q983 9959 20 1B 98 JSR Q81B ;else check volume not changed 995C 20 09 92 JSR Q209 ;copy EXT to file length in cat 995F EQUW &9A,&10 9961 EQUW &4E,&10 9963 EQUB &03,&10 9965 20 06 A6 JSR R606 ;pack catalogue fields 9968 4C 03 9B JMP QB03 ;write catalogue and exit. .Q96B ;Close all files 996B A5 CD LDA &CD 996D 30 05 BMI Q974 ;if &CD b7=0 996F A9 77 LDA #&77 ;then close *SPOOL/*EXEC files. 9971 20 F4 FF JSR &FFF4 .Q974 9974 A2 11 LDX #&11 ;set file handle=&11 .Q976 9976 20 00 98 JSR Q800 ;initialise for handle 9979 F0 03 BEQ Q97E ;if handle in use 997B 20 15 98 JSR Q815 ;close open file .Q97E 997E E8 INX ;increment handle 997F E0 16 CPX #&16 ;repeat for all handles and exit 9981 D0 F3 BNE Q976 .Q983 9983 60 RTS .Q984 ;Check volume not changed 9984 20 09 92 JSR Q209 ;copy memory absolute indexed 9987 EQUW &8A,&10 ;from path of open file at &108A 9989 EQUW &C0,&00 ;to immediate path at &100A 998B EQUB &0A,&10 998D 20 00 9B JSR QB00 ;softmount and catalogue drive 9990 20 09 A5 JSR R509 ;find file in catalogue 9993 B0 26 BCS Q9BB ;if not found "Volume changed" 9995 20 03 A6 JSR R603 ;unpack fields from catalogue 9998 AD 51 10 LDA &1051 ;compare start sector 999B D9 94 10 CMP &1094,Y ;with one in file workspace 999E D0 1B BNE Q9BB ;"Volume changed" if different 99A0 AD 52 10 LDA &1052 99A3 D9 95 10 CMP &1095,Y 99A6 D0 13 BNE Q9BB 99A8 AD 53 10 LDA &1053 ;compare allocated length 99AB D9 98 10 CMP &1098,Y ;with one in file workspace 99AE D0 0B BNE Q9BB ;"Volume changed" if different 99B0 AD 54 10 LDA &1054 99B3 D9 99 10 CMP &1099,Y 99B6 D0 03 BNE Q9BB 99B8 4C 21 A5 JMP R521 ;else check file unlocked & exit .Q9BB 99BB 20 21 98 JSR Q821 ;print disc/volume error message 99BE EQUB &C8 99BF EQUS "changed" 99C6 EQUB &00 ;terminator byte .Q9C7 ;Open a file 99C7 20 09 98 JSR Q809 ;check free handle available 99CA 20 06 92 JSR Q206 ;if so copy 99CD EQUW &1E,&9A ;FROM addresses and desired length, &9A1E 99CF EQUW &60,&10 ;TO file workspace, &1060 99D1 EQUB &10 99D2 A2 00 LDX #&00 99D4 20 18 A6 JSR R618 ;check perms/create file 99D7 B0 44 BCS QA1D ;if failed exit C=1 99D9 20 09 98 JSR Q809 ;else, get unused file handle 99DC 99 88 10 STA &1088,Y ;store read/write flags from A 99DF A9 00 LDA #&00 99E1 99 89 10 STA &1089,Y ;mark file buffer empty 99E4 99 9A 10 STA &109A,Y ;clear low byte of EXT 99E7 20 09 92 JSR Q209 ;copy zero to clear EXT & PTR 99EA EQUW &9A,&10 99EC EQUW &9B,&10 99EE EQUB &05,&11 99F0 20 09 92 JSR Q209 ;copy immediate name and path 99F3 EQUW &C0,&00 ;to name and path of open file 99F5 EQUW &8A,&10 99F7 EQUB &0A,&01 99F9 20 09 92 JSR Q209 ;copy absolute start sector 99FC EQUW &51,&10 ;to file workspace 99FE EQUW &94,&10 9A00 EQUB &02,&01 9A02 20 09 92 JSR Q209 ;copy number of sectors used 9A05 EQUW &53,&10 ;to allocated length 9A07 EQUW &98,&10 9A09 EQUB &02,&01 9A0B B9 88 10 LDA &1088,Y ;get channel flag 9A0E 2A ROL A 9A0F 10 09 BPL QA1A ;if open for reading/update 9A11 20 09 92 JSR Q209 ;then copy file length to EXT 9A14 EQUW &4E,&10 9A16 EQUW &9A,&10 9A18 EQUB &03,&01 .QA1A 9A1A B9 88 10 LDA &1088,Y ;get channel flag .QA1D 9A1D 60 RTS ;exit 9A1E EQUB &00,&00,&00,&00 ;table [0..15] of parameters 9A22 EQUB &00,&00,&00,&40 ;for new open files 9A26 EQUB &00,&00,&00,&40 ;desired sector allocation &40 9A2A EQUB &00,&00,&00,&00 ;to open 5 files on a 100K disc .QA2E ;Print disc/volume error message 9A2E 20 00 92 JSR Q200 ;save AXY 9A31 20 18 90 JSR Q018 ;set up error message 9A34 EQUB &08 9A35 EQUB &00 ;terminator byte 9A36 20 03 92 JSR Q203 ;get error number\Get byte immediate 9A39 20 00 90 JSR Q000 ;"print" it - Print character in A 9A3C A5 C9 LDA &C9 ;A = current drive 9A3E AA TAX ;X = offset by drive No. 9A3F BC FC 0F LDY &0FFC,X ;does drive have multiple volums? 9A42 D0 0D BNE QA51 ;if not 9A44 20 18 90 JSR Q018 ;print "Disc "+number 9A47 EQUB &C0 9A48 EQUS "Disc " 9A4D EQUB &00 ;terminator byte 9A4E 4C 62 9A JMP QA62 ;print space and string .QA51 9A51 20 18 90 JSR Q018 ;else print "Volume "+number 9A54 EQUB &C0 9A55 EQUS "Volume " 9A5C EQUB &00 ;terminator byte 9A5D A5 C8 LDA &C8 ;A = Immediate volume letter 9A5F 20 00 90 JSR Q000 ;print it - Print character in A .QA62 9A62 20 03 90 JSR Q003 ;print space .QA65 9A65 20 03 92 JSR Q203 ;print error string immediate: 9A68 F0 06 BEQ QA70 ;get immediate byte, if not 0 9A6A 20 00 90 JSR Q000 ;then print it - Print character in A 9A6D 4C 65 9A JMP QA65 ;and loop .QA70 9A70 4C 09 90 JMP Q009 ;else display error/newline ;unused space from &9A73 ;unused space ends at &9B00 ;Disc operations .QB00 9B00 4C 4A 9B JMP QB4A ;Softmount & load current cat .QB03 9B03 4C E1 9B JMP QBE1 ;Write current catalogue .QB06 9B06 4C 1B 9B JMP QB1B ;Do LBA transfer .QB09 9B09 4C 50 9B JMP QB50 ;Load volume catalogue .QB0C 9B0C 4C 88 9B JMP QB88 ;Softmount disc .QB0F 9B0F 4C 02 9C JMP QC02 ;Call OSWORD &7F, report errors .QB12 9B12 4C FD 9C JMP QCFD ;Call OSWORD &7F .QB15 9B15 4C FF 9B JMP QBFF ;Call OSWORD &7F r/w w/errors .QB18 9B18 4C FA 9C JMP QCFA ;Call OSWORD &7F read/write ;Do LBA transfer. On entry A=no. of sectors, XY=absolute start sector, ;?&C9=drive, !&1011=address, ?&1016=8271 command. ;On exit XY=absolute end sector (last accessed+1), value used at &8EA3. ;Transfers the first track and tail-recurses until done. .QB1B ;Do LBA transfer 9B1B 48 PHA 9B1C 20 BD 9D JSR QDBD ;convert LBA to cylinder/sector 9B1F CD 19 10 CMP &1019 ;compare request - dist to EOT 9B22 B0 03 BCS QB27 ;if >0 then transfer to EOT 9B24 8D 19 10 STA &1019 ;else set O7F length = request .QB27 9B27 20 15 9B JSR QB15 ;call OSWORD &7F r/w w/errors 9B2A AD 19 10 LDA &1019 ;get OSWORD &7F transfer length 9B2D 29 DF AND #&DF ;mask off sector size field 9B2F 8D 19 10 STA &1019 ;put back in OSWORD &7F block 9B32 18 CLC ;and add to O7F address (*256) 9B33 6D 12 10 ADC &1012 9B36 8D 12 10 STA &1012 9B39 8A TXA ;put LBA low byte in A 9B3A 18 CLC ;add OSWORD &7F transfer length 9B3B 6D 19 10 ADC &1019 9B3E AA TAX ;put result back in X 9B3F 90 01 BCC QB42 ;and carry out to Y 9B41 C8 INY .QB42 9B42 68 PLA ;restore LBA request length 9B43 38 SEC 9B44 ED 19 10 SBC &1019 ;subtract O7F transfer length 9B47 D0 D2 BNE QB1B ;and loop if result <>0 9B49 60 RTS ;else, exit .QB4A 9B4A 20 0C 9B JSR QB0C ;Softmount disc 9B4D D0 BA BNE QB09 ;if multi-volume load vol cat 9B4F 60 RTS .QB50 ;Load volume catalogue 9B50 20 00 92 JSR Q200 ;save AXY 9B53 20 AA 9D JSR QDAA ;calculate sector offset 9B56 8A TXA ;divide by 2 again 9B57 4A LSR A 9B58 A8 TAY 9B59 B9 30 10 LDA &1030,Y ;does the volume exist? 9B5C F0 19 BEQ QB77 ;if not give error 9B5E A9 00 LDA #&00 ;page E contains disc cat 9B60 AC 03 0E LDY &0E03 ;get sectors per track .QB63 9B63 18 CLC 9B64 7D 08 0E ADC &0E08,X ;accum cur vol start track 9B67 90 03 BCC QB6C ;we're multiplying to get 9B69 EE 39 10 INC &1039 ;absolute sector offset .QB6C 9B6C 88 DEY ;to start of volume 9B6D D0 F4 BNE QB63 ;store in 1038..9 9B6F 8D 38 10 STA &1038 ;rollout read cat block, 9B72 A9 93 LDA #&93 ;prepare O7F r/w, calculate 9B74 4C F1 9B JMP QBF1 ;vol offset, read vol cat .QB77 9B77 20 21 98 JSR Q821 ;print disc/volume error message 9B7A EQUB &D1 9B7B EQUS "non-existent" 9B87 EQUB &00 ;terminator byte .QB88 ;Softmount disc 9B88 20 00 92 JSR Q200 ;save AXY 9B8B A9 00 LDA #&00 9B8D 8D 38 10 STA &1038 ;clear volume offset 9B90 8D 39 10 STA &1039 9B93 A6 C9 LDX &C9 ;X = current drive 9B95 9D F4 0F STA &0FF4,X ;clear number of tracks 9B98 9D F8 0F STA &0FF8,X ;clear track stepping flag 9B9B 20 06 92 JSR Q206 ;copy memory absolute 9B9E EQUW &E6,&9C ;FROM read catalogue command, QCE6 9BA0 EQUW &11,&10 ;TO OSWORD 7F block, &1011 9BA2 EQUB &09 ;count 9BA3 AD 84 10 LDA &1084 ;Get *OPT 6 density 9BA6 D0 14 BNE QBBC ;Not 0? you asked for it 9BA8 BD F0 0F LDA &0FF0,X ;0=autodetect. 9BAB C9 0A CMP #&0A ;Validate current density 9BAD F0 06 BEQ QBB5 ;is it SD? if so branch to QBB5 9BAF C9 12 CMP #&12 ;else, is it DD? 9BB1 F0 02 BEQ QBB5 ;if so branch to QBB5 9BB3 A9 0A LDA #&0A ;else, set it to SD .QBB5 9BB5 20 17 9D JSR QD17 ;try to load catalogue 9BB8 F0 0A BEQ QBC4 ;Z=success 9BBA 49 18 EOR #&18 ;if failed swap &0A<->&12: .QBBC 9BBC 20 17 9D JSR QD17 ;Attempt at specified density 9BBF F0 03 BEQ QBC4 ;if failed to load catalogue 9BC1 4C 08 9C JMP QC08 ;then interpret disc error .QBC4 9BC4 AD 86 10 LDA &1086 ;else get *OPT 8 tracks 9BC7 F0 14 BEQ QBDD ;0 means 1:1 stepping 9BC9 10 0F BPL QBDA ;1..127 means skip track(s) 9BCB A9 1F LDA #&1F ;>127 means autodetect. 9BCD 8D 16 10 STA &1016 ;Prepare OSWORD &7F command 9BD0 A9 02 LDA #&02 ;to verify track 2 9BD2 8D 17 10 STA &1017 ;2 -> track number 9BD5 20 18 9B JSR QB18 ;call OSWORD &7F (with 1:1) 9BD8 F0 03 BEQ QBDD ;if failed .QBDA 9BDA 9D F8 0F STA &0FF8,X ;set stepping for current drive .QBDD 9BDD BD FC 0F LDA &0FFC,X ;return Z=single volume disc 9BE0 60 RTS .QBE1 ;Write catalogue 9BE1 20 00 92 JSR Q200 ;save AXY 9BE4 F8 SED ;Increment catalogue cycle no. 9BE5 18 CLC 9BE6 AD 04 0F LDA &0F04 9BE9 69 01 ADC #&01 9BEB 8D 04 0F STA &0F04 9BEE D8 CLD 9BEF A9 0B LDA #&0B ;A = 8271 command = &0B = write. Fall through: .QBF1 9BF1 20 06 92 JSR Q206 ;Read/write volume catalogue. 9BF4 EQUW &E6,&9C ;FROM address = OSWORD &7F block = QCE6 9BF6 EQUW &11,&10 ;store it in the TO address = &1011 9BF8 EQUB &09 ;count 9BF9 8D 16 10 STA &1016 ;set 8271 command 9BFC 20 AA 9D JSR QDAA ;calculate volume offset .QBFF ;Call OSWORD &7F r/w w/errors 9BFF 20 9A 9D JSR QD9A ;Prepare O7F block .QC02 ;Call OSWORD &7F, report errors 9C02 20 12 9B JSR QB12 9C05 D0 01 BNE QC08 ;if failed print error 9C07 60 RTS .QC08 ;Decode errors 9C08 AE 15 10 LDX &1015 ;X = number of parameters 9C0B BD 17 10 LDA &1017,X ;A = OSWORD &7F (8271) status 9C0E C9 12 CMP #&12 ;if status = &12 9C10 D0 16 BNE QC28 9C12 20 18 90 JSR Q018 ;start "Write protect" error 9C15 EQUB &08 9C16 EQUB &C7 9C17 EQUS "Write protect" 9C24 EQUB &00 ;terminator byte 9C25 4C B8 9C JMP QCB8 ;add disc address to error .QC28 9C28 C9 20 CMP #&20 ;else if status = &20 9C2A D0 1A BNE QC46 9C2C 20 18 90 JSR Q018 ;start "Deleted data read" error 9C2F EQUB &08 9C30 EQUB &C7 9C31 EQUS "Deleted data read" 9C42 EQUB &00 ;terminator byte 9C43 4C B8 9C JMP QCB8 ;add disc address to error .QC46 9C46 C9 0C CMP #&0C ;else if status = &0C 9C48 D0 15 BNE QC5F 9C4A 20 18 90 JSR Q018 ;start "ID CRC error" 9C4D EQUB &08 9C4E EQUB &C7 9C4F EQUS "ID CRC error" 9C5B EQUB &00 ;terminator byte 9C5C 4C B8 9C JMP QCB8 ;add disc address to error .QC5F 9C5F C9 18 CMP #&18 ;else if status = &18 9C61 D0 13 BNE QC76 9C63 20 18 90 JSR Q018 ;start "Seek error" error 9C66 EQUB &08 9C67 EQUB &C7 9C68 EQUS "Seek error" 9C72 EQUB &00 ;terminator byte 9C73 4C B8 9C JMP QCB8 ;add disc address to error .QC76 9C76 C9 0E CMP #&0E ;else if status = &0E 9C78 D0 17 BNE QC91 9C7A 20 18 90 JSR Q018 ;start "Data CRC error" error 9C7D EQUB &08 9C7E EQUB &C7 9C7F EQUS "Data CRC error" 9C8D EQUB &00 ;terminator byte 9C8E 4C B8 9C JMP QCB8 ;add disc address to error .QC91 9C91 C9 0A CMP #&0A ;else if status = &0A 9C93 D0 12 BNE QCA7 9C95 20 18 90 JSR Q018 ;start "Lost data" error 9C98 EQUB &08 9C99 EQUB &C7 9C9A EQUS "Lost data" 9CA3 EQUB &00 ;terminator byte 9CA4 4C B8 9C JMP QCB8 ;add disc address to error .QCA7 9CA7 20 18 90 JSR Q018 ;otherwise generic "Disc Fault" 9CAA EQUB &48 9CAB EQUB &C7 9CAC EQUS "Disc Fault " 9CB7 EQUB &00 ;terminator byte .QCB8 9CB8 A5 C9 LDA &C9 ;A = current drive 9CBA 20 18 90 JSR Q018 ;Print " on drive " 9CBD EQUB &C0 9CBE EQUS " on drive " 9CC8 EQUB &00 ;terminator byte 9CC9 AD 17 10 LDA &1017 ;A = track number 9CCC 20 18 90 JSR Q018 9CCF EQUB &80 9CD0 EQUS "." 9CD1 EQUB &00 ;terminator byte 9CD2 20 06 92 JSR Q206 ;copy memory absolute 9CD5 EQUW &EF,&9C ;FROM command to read special register 05 (sector number) at QCEF 9CD7 EQUW &15,&10 ;TO OSWORD &7F block at &1015 9CD9 EQUB &03 ;count 9CDA 20 12 9B JSR QB12 ;call plain OSWORD &7F 9CDD AD 18 10 LDA &1018 ;load sector number 9CE0 20 18 90 JSR Q018 ;error msg "."+sector no 9CE3 EQUB &82 9CE4 EQUS "." 9CE5 EQUB &00 ;terminator byte .QCE6 9CE6 EQUD &00,&0E,&FF,&FF ;load catalogue 9CEA EQUB &03 ;No. of parameters 9CEB EQUB &93 ;command = read sector 9CEC EQUB &00 9CED EQUB &00 9CEE EQUB &22 .QCEF 9CEF EQUB &01 ;1 parameter byte, command &3D 9CF0 EQUB &3D ;read special register &05 9CF1 EQUB &05 ;(sector number) .QCF2 ;Read DFS/disc catalogue 9CF2 9D FC 0F STA &0FFC,X ;store volume count for current drive 9CF5 0A ASL A 9CF6 8D 18 10 STA &1018 ;store sector offset 9CF9 98 TYA ;a=density of current attempt, returned .QCFA ;Call OSWORD &7F read/write 9CFA 20 9A 9D JSR QD9A ;prepare O7F block .QCFD ;Call OSWORD &7F 9CFD 20 00 92 JSR Q200 ;save AXY 9D00 A5 C9 LDA &C9 ;A = current drive 9D02 29 03 AND #&03 ;mask bits 2-7, bits 0-1 = drive 9D04 8D 10 10 STA &1010 ;store in OSWORD &7F block 9D07 A9 7F LDA #&7F ;osword command 9D09 A2 10 LDX #&10 ;LSB of parameter block 9D0B A0 10 LDY #&10 ;MSB of parameter block 9D0D 20 F1 FF JSR &FFF1 ;call OSWORD &7F 9D10 AE 15 10 LDX &1015 9D13 BD 17 10 LDA &1017,X ;return Z=success 9D16 60 RTS .QD17 ;Softmount part 2 9D17 20 00 92 JSR Q200 ;save AXY 9D1A 9D F0 0F STA &0FF0,X ;set density of current drive 9D1D A8 TAY 9D1E AD 85 10 LDA &1085 ;get *OPT 7 volumes 9D21 30 08 BMI QD2B ;if >=128 then treat as SD 9D23 D0 24 BNE QD49 ;not 0? Load disc cat, YAFI 9D25 A9 08 LDA #&08 ;0=autodetect: default 8 vols. 9D27 C0 12 CPY #&12 ;if disc is double density 9D29 F0 1E BEQ QD49 ;load disc catalogue .QD2B 9D2B A9 00 LDA #&00 ;treat as single volume disc 9D2D 20 F2 9C JSR QCF2 ;read DFS catalogue 9D30 D0 4A BNE QD7C ;if read failed then exit 9D32 AD 06 0F LDA &0F06 ;get sector count in AY 9D35 29 07 AND #&07 9D37 A8 TAY 9D38 AD 07 0F LDA &0F07 .QD3B 9D3B 38 SEC ;Subtract one track's worth 9D3C FD F0 0F SBC &0FF0,X 9D3F B0 03 BCS QD44 9D41 88 DEY 9D42 30 36 BMI QD7A ;If sectors run out exit .QD44 9D44 FE F4 0F INC &0FF4,X ;Calculate track count 9D47 D0 F2 BNE QD3B ;lucky it was zeroed first! .QD49 9D49 20 F2 9C JSR QCF2 ;read disc catalogue 9D4C D0 2E BNE QD7C ;if read failed then exit 9D4E CC 03 0E CPY &0E03 ;have we got density right? 9D51 D0 2A BNE QD7D ;if bad complain bad layout 9D53 AD 04 0E LDA &0E04 ;get track count from disc 9D56 9D F4 0F STA &0FF4,X ;store it for current drive 9D59 A2 08 LDX #&08 ;calculate number of tracks 9D5B A0 10 LDY #&10 ;in each volume and store .QD5D 9D5D 88 DEY ;in &1030,X 9D5E 88 DEY 9D5F CA DEX 9D60 30 18 BMI QD7A ;when done exit 9D62 48 PHA ;save ceiling track number 9D63 B9 08 0E LDA &0E08,Y ;get start track no. 9D66 9D 30 10 STA &1030,X ;store in &1030,X in case it's 0 9D69 C9 01 CMP #&01 ;set C=1 if start track >0 9D6B 68 PLA ;restore ceiling track number 9D6C 90 EF BCC QD5D ;if volume absent then loop 9D6E F9 08 0E SBC &0E08,Y ;else ceiling - start track 9D71 9D 30 10 STA &1030,X ;=volume size. store in 1030,X 9D74 B9 08 0E LDA &0E08,Y ;get new ceiling 9D77 4C 5D 9D JMP QD5D ;and loop. .QD7A 9D7A A9 00 LDA #&00 ;0=success .QD7C 9D7C 60 RTS .QD7D 9D7D 20 18 90 JSR Q018 ;Give error "Bad multi-volume layout" 9D80 EQUB &0A ;LF 9D81 EQUB &D0 9D82 EQUS "Bad multi-volume layout" 9D99 EQUB &00 ;terminator byte .QD9A ;Prepare OSWORD &7F block 9D9A 48 PHA 9D9B A9 03 LDA #&03 ;for a read or write 9D9D 8D 15 10 STA &1015 ;three parameters 9DA0 AD 19 10 LDA &1019 9DA3 09 20 ORA #&20 ;256 byte sectors 9DA5 8D 19 10 STA &1019 9DA8 68 PLA 9DA9 60 RTS .QDAA ;calculate sector offset 9DAA A6 C9 LDX &C9 ;A = current drive 9DAC BD FC 0F LDA &0FFC,X ;for volume catalogue 9DAF F0 07 BEQ QDB8 ;if disc has volumes 9DB1 A6 C8 LDX &C8 ;A = Immediate volume 9DB3 CA DEX ;convert to binary 9DB4 8A TXA 9DB5 29 0F AND #&0F ;mask bits 4-7 9DB7 0A ASL A ;and multiply by 2 .QDB8 9DB8 AA TAX ;store it in Osword block 9DB9 8E 18 10 STX &1018 ;return in A and X 9DBC 60 RTS ;Convert logical block address (LBA) to cylinder/sector address. ;On entry XY contains an absolute logical block address and ?&C9 ;contains the drive number. On exit ?&1017 contains the corresponding ;cylinder (track) number, ?&1018 contains the sector number (zero based) ;and ?&1019 contains the number of sectors until the end of the track ;(i.e. ?&1018 + ?&1019 = sectors per track). All taking into account ;the geometry of the drive identified by ?&C9. .QDBD ;Convert LBA to CS 9DBD 20 00 92 JSR Q200 ;save AXY 9DC0 A9 FF LDA #&FF ;preset track number = -1 9DC2 8D 17 10 STA &1017 9DC5 8A TXA ;LBA low byte to A 9DC6 A6 C9 LDX &C9 ;X = drive number .QDC8 9DC8 EE 17 10 INC &1017 ;increment track number 9DCB 8D 18 10 STA &1018 ;save LBA low byte as abs sector 9DCE 38 SEC 9DCF FD F0 0F SBC &0FF0,X ;subtract spt of drive from it 9DD2 B0 F4 BCS QDC8 ;if no borrow-in then loop 9DD4 88 DEY ;else borrow from LBA high byte 9DD5 10 F1 BPL QDC8 ;if LBA - spt >=0 then loop 9DD7 49 FF EOR #&FF ;else invert result 9DD9 AA TAX ;add 1 to make 2's complement 9DDA E8 INX ;(positive difference) in X 9DDB 8E 19 10 STX &1019 ;=distance to end of track. 9DDE 60 RTS ;exit ;unused space from &9DDF #ifdef _UNUSED 9E00 EQUB &9E,&9E,&9E,&9E 9E04 EQUB &9E,&9E,&9E,&9E 9E08 EQUB &9E,&9E,&9E,&9E 9E0C EQUB &9E,&9E,&9E,&9E 9E10 EQUB &9E,&9E,&9E,&9E 9E14 EQUB &9E,&9E,&9E,&9E 9E18 EQUB &9E,&9E,&9E,&9E 9E1C EQUB &9E,&9E,&9E,&9E 9E20 EQUB &9E,&9E,&9E,&9E 9E24 EQUB &9E,&9E,&9E,&9E 9E28 EQUB &9E,&9E,&9E,&9E 9E2C EQUB &9E,&9E,&9E,&9E 9E30 EQUB &9E,&9E,&9E,&9E 9E34 EQUB &9E,&9E,&9E,&9E 9E38 EQUB &9E,&9E,&9E,&9E 9E3C EQUB &9E,&9E,&9E,&9E 9E40 EQUB &9E,&9E,&9E,&9E 9E44 EQUB &9E,&9E,&9E,&9E 9E48 EQUB &9E,&9E,&9E,&9E 9E4C EQUB &9E,&9E,&9E,&9E 9E50 EQUB &9E,&9E,&9E,&9E 9E54 EQUB &9E,&9E,&9E,&9E 9E58 EQUB &9E,&9E,&9E,&9E 9E5C EQUB &9E,&9E,&9E,&9E 9E60 EQUB &9E,&9E,&9E,&9E 9E64 EQUB &9E,&9E,&9E,&9E 9E68 EQUB &9E,&9E,&9E,&9E 9E6C EQUB &9E,&9E,&9E,&9E 9E70 EQUB &9E,&9E,&9E,&9E 9E74 EQUB &9E,&9E,&9E,&9E 9E78 EQUB &9E,&9E,&9E,&9E 9E7C EQUB &9E,&9E,&9E,&9E 9E80 EQUB &9E,&9E,&9E,&9E 9E84 EQUB &9E,&9E,&9E,&9E 9E88 EQUB &9E,&9E,&9E,&9E 9E8C EQUB &9E,&9E,&9E,&9E 9E90 EQUB &9E,&9E,&9E,&9E 9E94 EQUB &9E,&9E,&9E,&9E 9E98 EQUB &9E,&9E,&9E,&9E 9E9C EQUB &9E,&9E,&9E,&9E 9EA0 EQUB &9E,&9E,&9E,&9E 9EA4 EQUB &9E,&9E,&9E,&9E 9EA8 EQUB &9E,&9E,&9E,&9E 9EAC EQUB &9E,&9E,&9E,&9E 9EB0 EQUB &9E,&9E,&9E,&9E 9EB4 EQUB &9E,&9E,&9E,&9E 9EB8 EQUB &9E,&9E,&9E,&9E 9EBC EQUB &9E,&9E,&9E,&9E 9EC0 EQUB &9E,&9E,&9E,&9E 9EC4 EQUB &9E,&9E,&9E,&9E 9EC8 EQUB &9E,&9E,&9E,&9E 9ECC EQUB &9E,&9E,&9E,&9E 9ED0 EQUB &9E,&9E,&9E,&9E 9ED4 EQUB &9E,&9E,&9E,&9E 9ED8 EQUB &9E,&9E,&9E,&9E 9EDC EQUB &9E,&9E,&9E,&9E 9EE0 EQUB &9E,&9E,&9E,&9E 9EE4 EQUB &9E,&9E,&9E,&9E 9EE8 EQUB &9E,&9E,&9E,&9E 9EEC EQUB &9E,&9E,&9E,&9E 9EF0 EQUB &9E,&9E,&9E,&9E 9EF4 EQUB &9E,&9E,&9E,&9E 9EF8 EQUB &9E,&9E,&9E,&9E 9EFC EQUB &9E,&9E,&9E,&9E 9F00 EQUB &9F,&9F,&9F,&9F 9F04 EQUB &9F,&9F,&9F,&9F 9F08 EQUB &9F,&9F,&9F,&9F 9F0C EQUB &9F,&9F,&9F,&9F 9F10 EQUB &9F,&9F,&9F,&9F 9F14 EQUB &9F,&9F,&9F,&9F 9F18 EQUB &9F,&9F,&9F,&9F 9F1C EQUB &9F,&9F,&9F,&9F 9F20 EQUB &9F,&9F,&9F,&9F 9F24 EQUB &9F,&9F,&9F,&9F 9F28 EQUB &9F,&9F,&9F,&9F 9F2C EQUB &9F,&9F,&9F,&9F 9F30 EQUB &9F,&9F,&9F,&9F 9F34 EQUB &9F,&9F,&9F,&9F 9F38 EQUB &9F,&9F,&9F,&9F 9F3C EQUB &9F,&9F,&9F,&9F 9F40 EQUB &9F,&9F,&9F,&9F 9F44 EQUB &9F,&9F,&9F,&9F 9F48 EQUB &9F,&9F,&9F,&9F 9F4C EQUB &9F,&9F,&9F,&9F 9F50 EQUB &9F,&9F,&9F,&9F 9F54 EQUB &9F,&9F,&9F,&9F 9F58 EQUB &9F,&9F,&9F,&9F 9F5C EQUB &9F,&9F,&9F,&9F 9F60 EQUB &9F,&9F,&9F,&9F 9F64 EQUB &9F,&9F,&9F,&9F 9F68 EQUB &9F,&9F,&9F,&9F 9F6C EQUB &9F,&9F,&9F,&9F 9F70 EQUB &9F,&9F,&9F,&9F 9F74 EQUB &9F,&9F,&9F,&9F 9F78 EQUB &9F,&9F,&9F,&9F 9F7C EQUB &9F,&9F,&9F,&9F 9F80 EQUB &9F,&9F,&9F,&9F 9F84 EQUB &9F,&9F,&9F,&9F 9F88 EQUB &9F,&9F,&9F,&9F 9F8C EQUB &9F,&9F,&9F,&9F 9F90 EQUB &9F,&9F,&9F,&9F 9F94 EQUB &9F,&9F,&9F,&9F 9F98 EQUB &9F,&9F,&9F,&9F 9F9C EQUB &9F,&9F,&9F,&9F 9FA0 EQUB &9F,&9F,&9F,&9F 9FA4 EQUB &9F,&9F,&9F,&9F 9FA8 EQUB &9F,&9F,&9F,&9F 9FAC EQUB &9F,&9F,&9F,&9F 9FB0 EQUB &9F,&9F,&9F,&9F 9FB4 EQUB &9F,&9F,&9F,&9F 9FB8 EQUB &9F,&9F,&9F,&9F 9FBC EQUB &9F,&9F,&9F,&9F 9FC0 EQUB &9F,&9F,&9F,&9F 9FC4 EQUB &9F,&9F,&9F,&9F 9FC8 EQUB &9F,&9F,&9F,&9F 9FCC EQUB &9F,&9F,&9F,&9F 9FD0 EQUB &9F,&9F,&9F,&9F 9FD4 EQUB &9F,&9F,&9F,&9F 9FD8 EQUB &9F,&9F,&9F,&9F 9FDC EQUB &9F,&9F,&9F,&9F 9FE0 EQUB &9F,&9F,&9F,&9F 9FE4 EQUB &9F,&9F,&9F,&9F 9FE8 EQUB &9F,&9F,&9F,&9F 9FEC EQUB &9F,&9F,&9F,&9F 9FF0 EQUB &9F,&9F,&9F,&9F 9FF4 EQUB &9F,&9F,&9F,&9F 9FF8 EQUB &9F,&9F,&9F,&9F 9FFC EQUB &9F,&9F,&9F,&9F #endif /* _UNUSED */ ;unused space ends at &A000 ; Tube hosting .R000 A000 4C 12 A0 JMP R012 ;Initialise Tube .R003 A003 4C 53 A0 JMP R053 ;Tube post init .R006 A006 4C 6D A0 JMP R06D ;*GO / open Tube channel 3? .R009 A009 4C 87 A0 JMP R087 ;Transfer byte to/from Tube .R00C A00C 4C 9B A0 JMP R09B ;Close Tube channel 3 A00F 4C A8 A0 JMP R0A8 ;Call code in Tube processor .R012 ;Initialise Tube A012 20 00 92 JSR Q200 ;save AXY A015 A9 8E LDA #&8E ;set Tube status (NAUG p.329) A017 8D E0 FE STA &FEE0 ;enable NMI on R3, IRQ on R1,R4 A01A 20 06 92 JSR Q206 ;install BRK handler on BRKV &41 bytes A01D EQUW &F1,&A0 ;FROM address, R0F1 A01F EQUW &16,&00 ;TO address, &0016 A021 EQUB &41 A022 A9 16 LDA #&16 A024 8D 02 02 STA &0202 A027 A9 00 LDA #&00 A029 8D 03 02 STA &0203 ;brk vector = &0016 A02C 20 06 92 JSR Q206 ;copy Tube host code to &0400 A02F EQUW &32,&A1 ;FROM address R132 A031 EQUW &00,&04 ;TO address &0400 A033 EQUB &FF ;count A034 20 06 92 JSR Q206 ;copy Tube host code to &04FF A037 EQUW &31,&A2 ;FROM address R132+&FF A039 EQUW &FF,&04 ;TO address &04FF A03B EQUB &FF ;count A03C 20 06 92 JSR Q206 ;copy memory absolute A03F EQUW &30,&A3 ;FROM address = R132+&1FE A041 EQUW &FE,&05 ;TO address &05FE A043 EQUB &D0 ;count A044 A9 AD LDA #&AD A046 8D 20 02 STA &0220 A049 A9 06 LDA #&06 A04B 8D 21 02 STA &0221 ;event vector = &06AD A04E 20 21 04 JSR &0421 ;mark Tube unclaimed .R051 A051 38 SEC ;claim ROM call and exit A052 60 RTS .R053 ;Tube post init A053 20 00 92 JSR Q200 ;save AXY A056 A2 06 LDX #&06 A058 A9 14 LDA #&14 ;OSBYTE &14 A05A 20 F4 FF JSR &FFF4 ;FONT EXPLOSION/DEFINITION .R05D A05D AD E0 FE LDA &FEE0 ;print Tube coprocessor banner: A060 10 FB BPL R05D ;poll until character in R1DATA A062 AD E1 FE LDA &FEE1 ;then read R1DATA A065 F0 EA BEQ R051 ;if =NUL then exit C=1 A067 20 EE FF JSR &FFEE ;else print the character & loop A06A 4C 5D A0 JMP R05D .R06D ;*GO / open Tube channel 3? A06D 20 00 92 JSR Q200 ;save AXY A070 20 76 A0 JSR R076 ;claim Tube A073 4C 06 04 JMP &0406 ;call tube .R076 ;Claim Tube A076 20 00 92 JSR Q200 ;save AXY A079 38 SEC ;set up Tube flag A07A 6A ROR A ;b6=1, Tube in use A07B 6A ROR A ;b7=1 if writing to coprocessor A07C 8D 3A 10 STA &103A .R07F A07F A9 C1 LDA #&C1 ;poll Tube entry point w/A=&C1 A081 20 06 04 JSR &0406 ;to claim Tube for DFS (%000001) A084 90 F9 BCC R07F ;until C=1 returned, then exit. A086 60 RTS .R087 ;Transfer byte to/from Tube A087 20 00 92 JSR Q200 ;save AXY A08A 2C 3A 10 BIT &103A ;103A: b6=Tube, b7=write to Tube A08D 30 08 BMI R097 A08F AD E5 FE LDA &FEE5 A092 BA TSX A093 9D 05 01 STA &0105,X A096 60 RTS .R097 A097 8D E5 FE STA &FEE5 A09A 60 RTS .R09B ;Close Tube channel 3 A09B 20 00 92 JSR Q200 ;save AXY A09E A9 00 LDA #&00 ;clear Tube flag A0A0 8D 3A 10 STA &103A ;set A=&81,DFS is releasing Tube A0A3 A9 81 LDA #&81 A0A5 4C 06 04 JMP &0406 ;call tube .R0A8 A0A8 A9 04 LDA #&04 ;Call code in Tube coprocessor A0AA 4C 06 04 JMP &0406 ;call tube ;unused space from &A0AD ;unused space ends at &A0F1 .R0F1 ;Tube BRK handler, &0016..51 A0F1 A9 FF LDA #&FF ;set A=&FF to interrupt coprocessor (JGH) A0F3 20 9E 06 JSR &069E ;write A to R4DATA A0F6 AD E3 FE LDA &FEE3 ;empty inward R2DATA and discard byte A0F9 A9 00 LDA #&00 ;set A=0 to specify error (JGH) A0FB 20 95 06 JSR &0695 ;write A to R2DATA A0FE A8 TAY ;set Y=0 offset into error message A0FF B1 FD LDA (&FD),Y ;get error number at MOS error pointer A101 20 95 06 JSR &0695 ;write A to R2DATA .R104 A104 C8 INY ;increment offset A105 B1 FD LDA (&FD),Y ;get character of error message A107 20 95 06 JSR &0695 ;write A to R2DATA A10A AA TAX ;test last character written A10B D0 F7 BNE R104 ;loop until it is NUL A10D A2 FF LDX #&FF ;reset stack pointer A10F 9A TXS A110 58 CLI ;enable interrupts: .R111 ;0036 Idle loop A111 2C E0 FE BIT &FEE0 ;test R1STAT A114 10 06 BPL R11C ;if b7=1, data available .R116 A116 AD E1 FE LDA &FEE1 ;then read R1DATA to A A119 20 EE FF JSR &FFEE ;call OSWRCH. .R11C A11C 2C E2 FE BIT &FEE2 ;test R2STAT A11F 10 F0 BPL R111 ;if b7=0, data not available then test R1 A121 2C E0 FE BIT &FEE0 ;else Tube call waiting. test R1STAT A124 30 F0 BMI R116 ;first print waiting bytes to OSWRCH (if any) A126 AE E3 FE LDX &FEE3 ;then read R2DATA to X =call number A129 86 51 STX &51 ;modify LSB indirect address of next inst. A12B 6C 00 05 JMP (&0500) ;0050 handle Tube call via jump table A12E EQUD &00,&80,&00,&00 ;Default Tube entry address = &00008000 .R132 ;0400 Copy language to coprocessor (NAUG) A132 4C 84 04 JMP &0484 ;0403 Copy ESCAPE flag to coprocessor (NAUG) A135 4C A7 06 JMP &06A7 ;0406 Tube service entry A138 C9 80 CMP #&80 ;if A = &00..7F A13A 90 2B BCC R167 ;then set up data transfer A13C C9 C0 CMP #&C0 ;else if A = &C0..FF A13E B0 1A BCS R15A ;then handle Tube claim A140 09 40 ORA #&40 ;else A=&80..BF release Tube A142 C5 15 CMP &15 ;set b6=1 to compare with claimant ID A144 D0 20 BNE R166 ;if releaser is not claimant then ignore else: ;0414 Release Tube A146 08 PHP ;save interrupt state A147 78 SEI ;disable interrupts A148 A9 05 LDA #&05 ;type byte=5 No transfer (FS release) A14A 20 9E 06 JSR &069E ;write A to R4DATA A14D A5 15 LDA &15 ;set A=claimant ID A14F 20 9E 06 JSR &069E ;write A to R4DATA A152 28 PLP ;restore interrupt state: A153 A9 80 LDA #&80 ;0421 Mark Tube unclaimed A155 85 15 STA &15 ;not in range &C0..FF =no claimant A157 85 14 STA &14 ;&80=Tube unclaimed A159 60 RTS .R15A ;0428 Claim Tube A15A 06 14 ASL &14 ;&00=Tube claimed A15C B0 06 BCS R164 ;if it was unclaimed then set claimant A15E C5 15 CMP &15 ;else compare caller's ID - current claimant A160 F0 04 BEQ R166 ;if same claimant reclaims then return C=1 A162 18 CLC ;else reject claim, return C=0 A163 60 RTS .R164 A164 85 15 STA &15 ;set current claimant, C=1 claim granted .R166 A166 60 RTS .R167 ;0435 Set up data transfer A167 08 PHP ;save interrupt state A168 78 SEI ;disable interrupts A169 84 13 STY &13 ;set control block pointer from XY A16B 86 12 STX &12 ;a=type byte/reason code A16D 20 9E 06 JSR &069E ;write A to R4DATA A170 AA TAX ;hold type byte in X A171 A0 03 LDY #&03 ;1+4 bytes to write A173 A5 15 LDA &15 ;set A=claimant ID A175 20 9E 06 JSR &069E ;write A to R4DATA: .R178 A178 B1 12 LDA (&12),Y ;get byte of transfer address, MSB to LSB A17A 20 9E 06 JSR &069E ;write A to R4DATA A17D 88 DEY ;in descending/big-endian order A17E 10 F8 BPL R178 ;loop until claimant+4 address bytes written A180 A0 18 LDY #&18 ;set Tube status (NAUG p.329) A182 8C E0 FE STY &FEE0 ;set V,M=0 disable NMI and word mode on R3 A185 BD 18 05 LDA &0518,X ;get status setting for transfer type in X A188 8D E0 FE STA &FEE0 ;write to R1STAT A18B 4A LSR A ;test I in bit 1 = modify interrupts on R1 A18C 4A LSR A ;(if I was modified, then I was set) A18D 90 06 BCC R195 ;if interrupts were enabled on R1 A18F 2C E5 FE BIT &FEE5 ;then transferring to host (C=1, used later) A192 2C E5 FE BIT &FEE5 ;discard word in R3 to empty it .R195 A195 20 9E 06 JSR &069E ;write A to R4DATA = synchronising byte .R198 A198 2C E6 FE BIT &FEE6 ;wait for it to be taken; test R4STAT A19B 50 FB BVC R198 ;loop until b6=1, not full A19D B0 0D BCS R1AC ;if transferring to host then branch A19F E0 04 CPX #&04 ;else if type<>4 address only A1A1 D0 11 BNE R1B4 ;then return without handshake, else: .R1A3 ;0471 Release Tube with handshake A1A3 20 14 04 JSR &0414 ;release Tube A1A6 20 95 06 JSR &0695 ;write A to R2DATA =&80 =transfer complete A1A9 4C 32 00 JMP &0032 ;go to idle loop .R1AC A1AC 4A LSR A ;test J in bit 2 = modify interrupts on R4 A1AD 90 05 BCC R1B4 ;if J=1, types 0 or 2, bytes/words to host A1AF A0 88 LDY #&88 A1B1 8C E0 FE STY &FEE0 ;then set M=1 enable NMIs on R3 .R1B4 A1B4 28 PLP ;restore interrupt state A1B5 60 RTS ;0484 Copy language to coprocessor (NAUG) A1B6 58 CLI ;enable interrupts A1B7 B0 11 BCS R1CA ;if C=1, entry from *FX142 (JGH) then copy A1B9 D0 03 BNE R1BE ;else if A>0 then enter language (JGH) A1BB 4C 9C 05 JMP &059C ;else A=0 no language, signal completion .R1BE A1BE A2 00 LDX #&00 ;set X=&00 do not alter A1C0 A0 FF LDY #&FF ;set Y=&FF do not update A1C2 A9 FD LDA #&FD ;OSBYTE &FD = read/write type of last reset A1C4 20 F4 FF JSR &FFF4 ;call OSBYTE A1C7 8A TXA ;if type = 0 soft BREAK A1C8 F0 D9 BEQ R1A3 ;then release Tube and write &80 to R2DATA .R1CA A1CA A9 FF LDA #&FF ;&FF = claim Tube with claimant ID = &3F A1CC 20 06 04 JSR &0406 ;call Tube service A1CF 90 F9 BCC R1CA ;loop until claim granted A1D1 20 D2 04 JSR &04D2 ;set up Tube destination address .R1D4 A1D4 A9 07 LDA #&07 ;type byte = 7, 256 byte transfer to host A1D6 20 CB 04 JSR &04CB ;set up Tube data transfer A1D9 A0 00 LDY #&00 ;clear page offset A1DB 84 00 STY &00 ;align ROM pointer to page boundary .R1DD A1DD B1 00 LDA (&00),Y ;get byte from ROM A1DF 8D E5 FE STA &FEE5 ;write A to R3DATA A1E2 EA NOP ;wait 3 microseconds A1E3 EA NOP A1E4 EA NOP A1E5 C8 INY ;increment offset A1E6 D0 F5 BNE R1DD ;loop until page boundary reached (10us/byte) A1E8 E6 54 INC &54 ;then add 256 to Tube transfer address A1EA D0 06 BNE R1F2 ;carry out to 2MSB A1EC E6 55 INC &55 A1EE D0 02 BNE R1F2 ;and MSB A1F0 E6 56 INC &56 .R1F2 A1F2 E6 01 INC &01 ;increment MSB of ROM pointer A1F4 24 01 BIT &01 ;test b14 of ROM pointer A1F6 50 DC BVC R1D4 ;loop until b14=1, when it has reached &C000 A1F8 20 D2 04 JSR &04D2 ;set up Tube destination address A1FB A9 04 LDA #&04 ;type byte = 4 no transfer, execute 2P code: ;04CB set up Tube data transfer A1FD A0 00 LDY #&00 ;point XY at Tube transfer address at &0053 A1FF A2 53 LDX #&53 A201 4C 06 04 JMP &0406 ;jump into Tube service. ;04D2 Set up Tube destination address A204 A9 80 LDA #&80 A206 85 54 STA &54 ;set 3MSB of Tube transfer address = &80 A208 85 01 STA &01 ;set MSB of ROM pointer = &80 A20A A9 20 LDA #&20 ;set b5=1 to test custom address flag A20C 2D 06 80 AND &8006 ;AND with ROM type byte A20F A8 TAY ;place result in AY for MSB, 2MSB of addr A210 84 53 STY &53 ;store as LSB (on the assumption that it's 0) A212 F0 19 BEQ R22D ;if b5=0 then no custom addr, set &00008000 A214 AE 07 80 LDX &8007 ;else get offset of copyright string .R217 A217 E8 INX ;skip leading NUL, increment offset A218 BD 00 80 LDA &8000,X ;test character of copyright string A21B D0 FA BNE R217 ;loop until terminating NUL reached A21D BD 01 80 LDA &8001,X ;store next byte as LSB of Tube address A220 85 53 STA &53 A222 BD 02 80 LDA &8002,X ;store byte after that as 3MSB A225 85 54 STA &54 A227 BC 03 80 LDY &8003,X ;get next byte as 2MSB A22A BD 04 80 LDA &8004,X ;get byte after that as MSB: .R22D A22D 85 56 STA &56 ;store MSB of Tube transfer address A22F 84 55 STY &55 ;store 2MSB of Tube transfer address A231 60 RTS ;0500 Tube call handler jump table (SB) A232 EQUW &37,&05 ;R2 was &00 - jump osrdch_call A234 EQUW &96,&05 ;R2 was &02 - jump oscli_call A236 EQUW &F2,&05 ;R2 was &04 - jump short_osbyte A238 EQUW &07,&06 ;R2 was &06 - jump long_osbyte A23A EQUW &27,&06 ;R2 was &08 - jump osword_call A23C EQUW &68,&06 ;R2 was &0A - jump osword0_call A23E EQUW &5E,&05 ;R2 was &0C - jump osargs_call A240 EQUW &2D,&05 ;R2 was &0E - jump osbget_call A242 EQUW &20,&05 ;R2 was &10 - jump osbput_call A244 EQUW &42,&05 ;R2 was &12 - jump osfind_call A246 EQUW &A9,&05 ;R2 was &14 - jump osfile_call A248 EQUW &D1,&05 ;R2 was &16 - jump osgbpb_call ;0518 Tube status settings for transfer types 0..7 A24A EQUB &86 ;0=bytes to host J,I=1 enable IRQ on R4,R1 A24B EQUB &88 ;1=bytes from host M=1 enable NMI on R3 A24C EQUB &96 ;2=words to host V,J,I=1 enable IRQ on R4,R1 A24D EQUB &98 ;3=words from host V,M=1 enable NMI on R3 A24E EQUB &18 ;4=address only V,M=0 disable NMI on R3 A24F EQUB &18 ;5=(reserved) V,M=0 disable NMI on R3 A250 EQUB &82 ;6=page to host I=1 enable IRQ on R1 A251 EQUB &18 ;7=page from host V,M=0 disable NMI on R3 ;osbput_call A252 20 C5 06 JSR &06C5 ;read R2DATA to A A255 A8 TAY ;set Y=channel A256 20 C5 06 JSR &06C5 ;read R2DATA to A =byte to write A259 20 D4 FF JSR &FFD4 ;call OSBPUT A25C 4C 9C 05 JMP &059C ;signal completion ;osbget_call A25F 20 C5 06 JSR &06C5 ;read R2DATA to A A262 A8 TAY ;set Y=channel A263 20 D7 FF JSR &FFD7 ;call OSBGET A266 4C 3A 05 JMP &053A ;send C, A to R2DATA and idle ;osrdch_call A269 20 E0 FF JSR &FFE0 ;call OSRDCH ;053A send C, A to R2DATA and idle A26C 6A ROR A ;rotate C into A b7, save A b0 in C A26D 20 95 06 JSR &0695 ;write A to R2DATA A270 2A ROL A ;restore A on entry A271 4C 9E 05 JMP &059E ;write to R2DATA and idle ;osfind_call A274 20 C5 06 JSR &06C5 ;read R2DATA to A A277 F0 0B BEQ R284 ;if A=0 then close file A279 48 PHA ;else save A=call no. = open mode A27A 20 82 05 JSR &0582 ;read string to buffer A27D 68 PLA ;restore A A27E 20 CE FF JSR &FFCE ;call OSFIND A281 4C 9E 05 JMP &059E ;write to R2DATA and idle .R284 A284 20 C5 06 JSR &06C5 ;read R2DATA to A A287 A8 TAY ;set Y=file handle A288 A9 00 LDA #&00 ;restore A=0 call no. = close file A28A 20 CE FF JSR &FFCE ;call OSFIND A28D 4C 9C 05 JMP &059C ;signal completion ;osargs_call A290 20 C5 06 JSR &06C5 ;read R2DATA to A A293 A8 TAY ;set Y=channel A294 A2 04 LDX #&04 ;4 bytes to read: .R296 A296 20 C5 06 JSR &06C5 ;read R2DATA to A A299 95 FF STA &FF,X ;save in locations 3..0 A29B CA DEX ;in descending order A29C D0 F8 BNE R296 ;loop until X bytes read A29E 20 C5 06 JSR &06C5 ;read R2DATA to A =call number A2A1 20 DA FF JSR &FFDA ;call OSARGS A2A4 20 95 06 JSR &0695 ;write A to R2DATA =return value A2A7 A2 03 LDX #&03 ;4 bytes to write: .R2A9 A2A9 B5 00 LDA &00,X ;get locations 3..0 A2AB 20 95 06 JSR &0695 ;write A to R2DATA A2AE CA DEX ;in descending order A2AF 10 F8 BPL R2A9 ;loop until X+1 bytes written A2B1 4C 36 00 JMP &0036 ;go to idle loop ;0582 read string to buffer A2B4 A2 00 LDX #&00 ;set X=0 LSB of buffer address A2B6 A0 00 LDY #&00 ;set Y=0 buffer offset .R2B8 A2B8 20 C5 06 JSR &06C5 ;read R2DATA to A A2BB 99 00 07 STA &0700,Y ;save in string buffer A2BE C8 INY ;in ascending order, increment offset A2BF F0 04 BEQ R2C5 ;if end of buffer reached then stop A2C1 C9 0D CMP #&0D ;else test character read A2C3 D0 F3 BNE R2B8 ;if =CR then string terminated else loop .R2C5 A2C5 A0 07 LDY #&07 ;set Y=&07 MSB of buffer address A2C7 60 RTS ;oscli_call A2C8 20 82 05 JSR &0582 ;read string to buffer A2CB 20 F7 FF JSR &FFF7 ;call OSCLI ;059C Signal completion A2CE A9 7F LDA #&7F .R2D0 ;059E Write to R2DATA and idle A2D0 2C E2 FE BIT &FEE2 ;test R2STAT A2D3 50 FB BVC R2D0 ;loop until b6=1, not full A2D5 8D E3 FE STA &FEE3 ;write A to R2DATA .R2D8 A2D8 4C 36 00 JMP &0036 ;go to idle loop ;osfile_call A2DB A2 10 LDX #&10 ;16 bytes to read: .R2DD A2DD 20 C5 06 JSR &06C5 ;read R2DATA to A A2E0 95 01 STA &01,X ;save to locations 17..2 A2E2 CA DEX ;in descending order A2E3 D0 F8 BNE R2DD ;loop until X bytes read A2E5 20 82 05 JSR &0582 ;read string to buffer A2E8 86 00 STX &00 ;save buffer address at 0,1 A2EA 84 01 STY &01 ;=&0700 A2EC A0 00 LDY #&00 ;set Y=0; X=0 from 0582 A2EE 20 C5 06 JSR &06C5 ;read R2DATA to A =call number A2F1 20 DD FF JSR &FFDD ;call OSFILE A2F4 20 95 06 JSR &0695 ;write A to R2DATA =return value A2F7 A2 10 LDX #&10 ;16 bytes to write: .R2F9 A2F9 B5 01 LDA &01,X ;get locations 17..2 A2FB 20 95 06 JSR &0695 ;write A to R2DATA A2FE CA DEX ;in descending order A2FF D0 F8 BNE R2F9 ;loop until X bytes written A301 F0 D5 BEQ R2D8 ;then go to idle loop ;osgbpb_call A303 A2 0D LDX #&0D ;13 bytes to read: .R305 A305 20 C5 06 JSR &06C5 ;read R2DATA to A A308 95 FF STA &FF,X ;save to locations 12..0 A30A CA DEX ;in descending order A30B D0 F8 BNE R305 ;loop until X bytes read A30D 20 C5 06 JSR &06C5 ;read R2DATA to A A310 A0 00 LDY #&00 ;set Y=0; X=0 from loop A312 20 D1 FF JSR &FFD1 ;call OSGBPB A315 48 PHA ;save return value A316 A2 0C LDX #&0C ;13 bytes to write: .R318 A318 B5 00 LDA &00,X ;get locations 12..0 A31A 20 95 06 JSR &0695 ;write A to R2DATA A31D CA DEX ;in descending order A31E 10 F8 BPL R318 ;loop until X bytes written A320 68 PLA ;restore A=return value A321 4C 3A 05 JMP &053A ;send C, A to R2DATA and idle ;short_osbyte A324 20 C5 06 JSR &06C5 ;read R2DATA to A A327 AA TAX ;save X=first parameter A328 20 C5 06 JSR &06C5 ;read R2DATA to A =call number A32B 20 F4 FF JSR &FFF4 ;call OSBYTE .R32E A32E 2C E2 FE BIT &FEE2 ;test R2STAT A331 50 FB BVC R32E ;loop until b6=1, not full A333 8E E3 FE STX &FEE3 ;write X to R2DATA =result .R336 A336 4C 36 00 JMP &0036 ;go to idle loop ;long_osbyte A339 20 C5 06 JSR &06C5 ;read R2DATA to A A33C AA TAX ;set X=first parameter A33D 20 C5 06 JSR &06C5 ;read R2DATA to A A340 A8 TAY ;set Y=second parameter A341 20 C5 06 JSR &06C5 ;read R2DATA to A =call number A344 20 F4 FF JSR &FFF4 ;call OSBYTE A347 49 9D EOR #&9D ;if A=&9D fast Tube BPUT A349 F0 EB BEQ R336 ;then end call without handshake A34B 6A ROR A ;else rotate C into A b7 A34C 20 95 06 JSR &0695 ;write A to R2DATA .R34F A34F 2C E2 FE BIT &FEE2 ;test R2STAT A352 50 FB BVC R34F ;loop until b6=1, not full A354 8C E3 FE STY &FEE3 ;write Y to R2DATA =second result A357 70 D5 BVS R32E ;write X to R2DATA and idle (always) ;osword_call A359 20 C5 06 JSR &06C5 ;read R2DATA to A =call number A35C A8 TAY ;hold in Y .R35D A35D 2C E2 FE BIT &FEE2 ;test R2STAT A360 10 FB BPL R35D ;loop until b7=1, data available A362 AE E3 FE LDX &FEE3 ;read R2DATA to X =control block size A365 CA DEX ;decrement X A366 30 0F BMI R377 ;if X was not in range 1..128 then no bytes .R368 A368 2C E2 FE BIT &FEE2 ;else test R2STAT A36B 10 FB BPL R368 ;loop until b7=1, data available A36D AD E3 FE LDA &FEE3 ;read R2DATA to A A370 9D 28 01 STA &0128,X ;save to locations &0128+(X-1..0) A373 CA DEX ;in descending order A374 10 F2 BPL R368 ;loop until X bytes written A376 98 TYA ;restore A=call number .R377 A377 A2 28 LDX #&28 ;point XY to OSWORD control block at &0128 A379 A0 01 LDY #&01 A37B 20 F1 FF JSR &FFF1 ;call OSWORD .R37E A37E 2C E2 FE BIT &FEE2 ;test R2STAT A381 10 FB BPL R37E ;loop until b7=1, data available A383 AE E3 FE LDX &FEE3 ;read R2DATA to X =control block size A386 CA DEX ;decrement X A387 30 0E BMI R397 ;if X was not in range 1..128 then no bytes .R389 A389 BC 28 01 LDY &0128,X ;else get byte of control block at ..&0128 .R38C A38C 2C E2 FE BIT &FEE2 ;test R2STAT A38F 50 FB BVC R38C ;loop until b6=1, not full A391 8C E3 FE STY &FEE3 ;write Y to R2DATA A394 CA DEX ;in descending order A395 10 F2 BPL R389 ;loop until X bytes written .R397 A397 4C 36 00 JMP &0036 ;go to idle loop ;osword0_call A39A A2 04 LDX #&04 ;5 bytes to read: .R39C A39C 20 C5 06 JSR &06C5 ;read R2DATA to A A39F 95 00 STA &00,X ;save to locations 4..0 A3A1 CA DEX ;in descending order A3A2 10 F8 BPL R39C ;loop until X+1 bytes read A3A4 E8 INX ;set X=0 A3A5 A0 00 LDY #&00 ;set Y=0; point XY to OSWORD control block A3A7 8A TXA ;set A=0 read line from input stream A3A8 20 F1 FF JSR &FFF1 ;call OSWORD A3AB 90 05 BCC R3B2 ;if user pressed ESCAPE A3AD A9 FF LDA #&FF ;then A=&FF carry set/error condition A3AF 4C 9E 05 JMP &059E ;write to R2DATA and idle .R3B2 A3B2 A2 00 LDX #&00 ;else X=0 offset into string buffer A3B4 A9 7F LDA #&7F ;set A=&7F carry clear/no error A3B6 20 95 06 JSR &0695 ;write A to R2DATA .R3B9 A3B9 BD 00 07 LDA &0700,X ;get character from string buffer A3BC 20 95 06 JSR &0695 ;write A to R2DATA A3BF E8 INX ;increment offset A3C0 C9 0D CMP #&0D ;test character just written A3C2 D0 F5 BNE R3B9 ;if =CR then string terminated else loop A3C4 4C 36 00 JMP &0036 ;go to idle loop .R3C7 ;0695 Write A to R2DATA A3C7 2C E2 FE BIT &FEE2 ;test R2STAT A3CA 50 FB BVC R3C7 ;loop until b6=1, not full A3CC 8D E3 FE STA &FEE3 ;write A to R2DATA A3CF 60 RTS .R3D0 ;069E Write A to R4DATA A3D0 2C E6 FE BIT &FEE6 ;test R4STAT A3D3 50 FB BVC R3D0 ;loop until b6=1, not full A3D5 8D E7 FE STA &FEE7 ;write A to R4DATA A3D8 60 RTS ;06A7 Copy ESCAPE flag to coprocessor (NAUG) A3D9 A5 FF LDA &FF ;get MOS ESCAPE flag A3DB 38 SEC ;rotate 1 into bit 7, ESCAPE flag in bit 6 A3DC 6A ROR A ;A >= &80 indicating ESCAPE flag update A3DD 30 0F BMI R3EE ;write A to R1DATA (always) ;06AD Event handler A3DF 48 PHA ;save event type A3E0 A9 00 LDA #&00 ;set A=&00 to indicate event A3E2 20 BC 06 JSR &06BC ;write A to R1DATA A3E5 98 TYA ;transfer Y=second event parameter to A A3E6 20 BC 06 JSR &06BC ;write A to R1DATA A3E9 8A TXA ;transfer X=first event parameter to A A3EA 20 BC 06 JSR &06BC ;write A to R1DATA A3ED 68 PLA ;restore event type to A: .R3EE ;06BC Write A to R1DATA A3EE 2C E0 FE BIT &FEE0 ;test R1STAT A3F1 50 FB BVC R3EE ;loop until b6=1, not full A3F3 8D E1 FE STA &FEE1 ;write A to R1DATA A3F6 60 RTS .R3F7 ;06C5 Read R2DATA to A A3F7 2C E2 FE BIT &FEE2 ;test R2STAT A3FA 10 FB BPL R3F7 ;loop until b7=1, data available A3FC AD E3 FE LDA &FEE3 ;read R2DATA to A and return A3FF 60 RTS ;EDOS console output .R400 A400 4C 1F A4 JMP R41F ;Print filename .R403 A403 4C 0C A4 JMP R40C ;Print directory and filename .R406 A406 4C 3D A4 JMP R43D ;Print *INFO line .R409 A409 4C 6D A4 JMP R46D ;Print decimal word .R40C ;Print directory and filename A40C 20 00 92 JSR Q200 ;save AXY .R40F ;print directory and filename A40F AD 47 10 LDA &1047 A412 29 7F AND #&7F ;remove Locked bit A414 20 00 90 JSR Q000 ;print directory letter in A A417 A9 2E LDA #&2E ;print "." A419 20 00 90 JSR Q000 ;Print character in A, fall through: A41C 4C 22 A4 JMP R422 .R41F ;Print filename A41F 20 00 92 JSR Q200 ;save AXY .R422 A422 A0 00 LDY #&00 ;set offset = 0 .R424 A424 B9 40 10 LDA &1040,Y ;get character from cat wksp A427 20 00 90 JSR Q000 ;print the character in A A42A C8 INY ;increment offset A42B C0 07 CPY #&07 ;reached end of name proper? A42D D0 F5 BNE R424 ;if not then loop. A42F AD 47 10 LDA &1047 ;get directory and attribute A432 10 08 BPL R43C ;if Locked A434 20 18 90 JSR Q018 ;then print " L". A437 EQUB &00 A438 EQUS " L" A43B EQUB &00 .R43C A43C 60 RTS ;exit .R43D ;Print *INFO line A43D 20 00 92 JSR Q200 ;save AXY A440 20 0F A4 JSR R40F ;print directory and filename A443 A9 0E LDA #&0E ;tab to column 14 A445 20 06 90 JSR Q006 ;Tab to column in A A448 A2 00 LDX #&00 ;catalogue field offset = 0 A44A 20 64 A4 JSR R464 ;print load address A44D 20 64 A4 JSR R464 ;print execution address A450 20 64 A4 JSR R464 ;print file length A453 CA DEX ;pretend startsec is 3byte field: .R454 A454 18 CLC ;Print top word w/o leading 0s A455 BD 4A 10 LDA &104A,X ;load top byte A458 20 5E A4 JSR R45E ;print hex byte, allow zeroes A45B BD 48 10 LDA &1048,X ;load middle byte .R45E A45E 20 0F 90 JSR Q00F ;print hex byte A461 38 SEC ;allow zeroes A462 E8 INX ;increment offset A463 60 RTS ;exit. .R464 A464 20 54 A4 JSR R454 ;Print 3byte field from cat A467 BD 46 10 LDA &1046,X ;print top word w/o leading 0s A46A 4C 5E A4 JMP R45E ;0s allowed, print bottom byte. .R46D ;Print decimal word A46D 20 00 92 JSR Q200 ;save AXY A470 18 CLC ;similar algorithm to A471 A0 04 LDY #&04 ;print-decimal-byte (Q012) .R473 A473 08 PHP A474 A2 00 LDX #&00 .R476 A476 AD 61 10 LDA &1061 A479 D9 B2 A4 CMP &A4B2,Y A47C D0 06 BNE R484 A47E AD 60 10 LDA &1060 A481 D9 AE A4 CMP &A4AE,Y .R484 A484 90 16 BCC R49C A486 E8 INX A487 AD 60 10 LDA &1060 A48A F9 AE A4 SBC &A4AE,Y A48D 8D 60 10 STA &1060 A490 AD 61 10 LDA &1061 A493 F9 B2 A4 SBC &A4B2,Y A496 8D 61 10 STA &1061 A499 4C 76 A4 JMP R476 .R49C A49C 28 PLP A49D 8A TXA A49E D0 02 BNE R4A2 A4A0 90 03 BCC R4A5 .R4A2 A4A2 20 0C 90 JSR Q00C ;print hex nibble .R4A5 A4A5 88 DEY A4A6 D0 CB BNE R473 A4A8 AD 60 10 LDA &1060 A4AB 38 SEC A4AC 4C 0C 90 JMP Q00C ;print hex nibble A4AF EQUB &0A,&64,&E8,&10 ;low bytes [0..3] A4B3 EQUB &00,&00,&03,&27 ;high bytes [0..3] ;unused space from &A4B7 ;unused space ends at &A500 ;File selection .R500 A500 4C 2A A5 JMP R52A ;Select first file in catalogue A503 4C 24 A5 JMP R524 ;Select and ensure first file .R506 A506 4C 31 A5 JMP R531 ;Select next file in catalogue .R509 A509 4C 47 A5 JMP R547 ;Find file in catalogue .R50C A50C 4C 41 A5 JMP R541 ;Check file exists .R50F A50F 4C 51 A5 JMP R551 ;Find next match of afsp .R512 A512 4C 70 A5 JMP R570 ;Find unlocked file in cat A515 4C 57 A5 JMP R557 ;Check unlocked file exists .R518 A518 4C 7A A5 JMP R57A ;Find next unlocked match .R51B A51B 4C 80 A5 JMP R580 ;Compare filenames .R51E A51E 4C 99 A5 JMP R599 ;Compare directory letters .R521 A521 4C CE A5 JMP R5CE ;Check file not locked .R524 ;Select and ensure first file A524 20 00 A5 JSR R500 ;select first file in catalogue A527 4C 5A A5 JMP R55A ;give error if catalogue empty. .R52A ;Select first file in catalogue A52A 48 PHA A52B AD 05 0F LDA &0F05 ;get file count from catalogue A52E 4C 34 A5 JMP R534 ;set ptr = count - 8 and exit. .R531 ;Select next file in catalogue A531 48 PHA A532 A5 CC LDA &CC ;get catalogue pointer .R534 A534 38 SEC A535 E9 08 SBC #&08 ;Subtract 8 to pt to next entry A537 90 05 BCC R53E ;if borrow then exit C=1 A539 85 CC STA &CC ;else store catalogue pointer A53B 68 PLA ;restore A and .R53C A53C 18 CLC A53D 60 RTS ;exit C=0 .R53E A53E 68 PLA ;restore A .R53F A53F 38 SEC A540 60 RTS ;exit C=1 .R541 ;Check file exists A541 20 09 A5 JSR R509 ;find file in catalogue A544 4C 5A A5 JMP R55A ;return C=0 or "File not found" .R547 ;Find file in catalogue A547 20 00 A5 JSR R500 ;select first file in catalogue A54A B0 F3 BCS R53F ;return C=1 if no files, else: .R54C A54C 20 1B A5 JSR R51B ;compare filenames A54F F0 EB BEQ R53C ;return C=0 if matched, else: .R551 ;Find next match of afsp A551 20 06 A5 JSR R506 ;select next file in catalogue A554 90 F6 BCC R54C ;loop if found else return C=1 A556 60 RTS .R557 ;Check unlocked file exists A557 20 12 A5 JSR R512 ;find unlocked file in cat .R55A A55A 90 E0 BCC R53C ;return C=0 if found, else: A55C 20 18 90 JSR Q018 ;Raise "File not found" error. A55F EQUB &0A A560 EQUB &D6 A561 EQUS "File not found" A56F EQUB &00 .R570 ;Find unlocked file in cat A570 20 09 A5 JSR R509 ;find file in catalogue A573 B0 CA BCS R53F ;return C=1 if no files, else: .R575 A575 20 E4 A5 JSR R5E4 ;read directory and attribute A578 10 C2 BPL R53C ;return C=0 if unlocked, else: .R57A ;Find next unlocked match A57A 20 0F A5 JSR R50F ;find next match of afsp A57D 90 F6 BCC R575 ;loop if found else return C=1 A57F 60 RTS .R580 ;Compare filenames A580 20 00 92 JSR Q200 ;save AXY A583 20 9C A5 JSR R59C ;compare directory letters A586 D0 10 BNE R598 ;if mismatch then exit Z=0 A588 A0 00 LDY #&00 ;else clear Y index register .R58A A58A BD 08 0E LDA &0E08,X ;get character of entry name A58D 20 AD A5 JSR R5AD ;compare to immediate filename A590 D0 06 BNE R598 ;if mismatch then exit Z=0 A592 E8 INX ;else increment copy of cat ptr A593 C8 INY ;and immediate filename offset A594 C0 07 CPY #&07 ;have we compared 7 characters? A596 D0 F2 BNE R58A ;return Z=1 if so else loop. .R598 A598 60 RTS .R599 ;Compare directory letters A599 20 00 92 JSR Q200 ;save AXY .R59C A59C 20 E7 A5 JSR R5E7 ;read directory and attribute A59F 29 7F AND #&7F ;mask off bit 7 (attribute bit) A5A1 20 C3 A5 JSR R5C3 ;convert to upper case A5A4 85 B8 STA &B8 ;store in temp A5A6 A5 C7 LDA &C7 ;A = Immediate dir'y A5A8 29 7F AND #&7F ;mask bit 7 (attribute bit) A5AA 4C B5 A5 JMP R5B5 ;and jump forward .R5AD ;Compare to immediate filename A5AD 20 C3 A5 JSR R5C3 ;convert to upper case A5B0 85 B8 STA &B8 ;store in temp A5B2 B9 C0 00 LDA &00C0,Y ;get char of immediate filename .R5B5 A5B5 C9 2A CMP #&2A ;is search character ASCII '*'? A5B7 F0 09 BEQ R5C2 ;if it is, exit Z=1 A5B9 C9 23 CMP #&23 ;else, is it ASCII '#'? A5BB F0 05 BEQ R5C2 ;if it is, exit Z=1 A5BD 20 C3 A5 JSR R5C3 ;else convert to upper case A5C0 C5 B8 CMP &B8 ;and compare w/temp (Z=match) .R5C2 A5C2 60 RTS ;exit .R5C3 ;Convert to upper case A5C3 C9 61 CMP #&61 ;is it < ASCII 'a'? A5C5 90 06 BCC R5CD ;if so, not lower case, exit A5C7 C9 7B CMP #&7B ;else, is it > 'z'? A5C9 B0 02 BCS R5CD ;if so, not alpha, exit A5CB 29 DF AND #&DF ;else, convert to upper case .R5CD A5CD 60 RTS ;exit .R5CE ;Check file not locked A5CE 20 E4 A5 JSR R5E4 ;read directory and attribute A5D1 10 FA BPL R5CD ;return N=0 if unlocked A5D3 20 18 90 JSR Q018 ;else "File locked" error. A5D6 EQUB &0A A5D7 EQUB &C3 A5D8 EQUS "File locked" A5E3 EQUB &00 .R5E4 ;Read directory and attribute A5E4 20 00 92 JSR Q200 ;save AXY .R5E7 A5E7 A6 CC LDX &CC ;at catalogue pointer A5E9 BD 0F 0E LDA &0E0F,X ;return directory character A5EC 60 RTS ;b7=1, N=1 if file locked ;unused space from &A5ED #ifdef _UNUSED ;copy of read DFS/disc catalogue code at &9CEC..FE ; used code is 1 byte tighter A5ED EQUB &00 A5EE EQUB &00 A5EF EQUB &22 A5F0 EQUB &01 A5F1 EQUB &3D A5F2 EQUB &05 A5F3 9D FC 0F STA &0FFC,X A5F6 0A ASL A A5F7 8D 18 10 STA &1018 A5FA 98 TYA A5FB 20 93 9D JSR QD93 ;9CFA=JSR QD9A; perhaps $&9D83 was "Bad disc layout"? A5FE EQUB &20,&00 #endif /* _UNUSED */ ;unused space ends at &A600 ;Catalogue operations .R600 A600 4C 21 A6 JMP R621 ;Delete catalogue entry .R603 A603 4C 44 A6 JMP R644 ;Unpack fields from catalogue .R606 A606 4C 93 A7 JMP R793 ;Pack fields into catalogue .R609 A609 4C 22 A7 JMP R722 ;Create catalogue entry .R60C A60C 4C 07 A8 JMP R807 ;Find a free space in volume .R60F A60F 4C 4C A8 JMP R84C ;Calculate absolute end of file .R612 A612 4C 5E A6 JMP R65E ;Unpack cat fields from wkspace .R615 A615 4C 62 A8 JMP R862 ;Determine if room to extend .R618 A618 4C E9 A6 JMP R6E9 ;Check parms/create file .R61B A61B 4C 25 A8 JMP R825 ;Get free space on volume .R61E A61E 4C 7B A8 JMP R87B ;Get ceiling over cat entry .R621 ;Delete catalogue entry A621 20 00 92 JSR Q200 ;save AXY A624 AD 05 0F LDA &0F05 ;pointed to by &CC A627 38 SEC ;by moving valid entries A628 E9 08 SBC #&08 ;over it A62A 8D 05 0F STA &0F05 A62D A6 CC LDX &CC ;x = Pointer to file entry in catalogue .R62F A62F EC 05 0F CPX &0F05 ;if new end of catalogue reached A632 B0 0F BCS R643 ;then exit A634 BD 10 0E LDA &0E10,X ;else copy next entry A637 9D 08 0E STA &0E08,X ;to current entry A63A BD 10 0F LDA &0F10,X A63D 9D 08 0F STA &0F08,X A640 E8 INX ;increment offset A641 D0 EC BNE R62F ;and loop (always) .R643 A643 60 RTS .R644 ;Unpack fields from catalogue A644 20 00 92 JSR Q200 ;save AXY A647 A6 CC LDX &CC ;x = Pointer to file entry in catalogue A649 20 09 92 JSR Q209 ;copy memory absolute indexed A64C EQUW &08,&0E ;FROM catalogue entry, &0E08,X A64E EQUW &40,&10 ;TO workspace, &1040 A650 EQUB &08,&20 ;8 bytes, from X A652 20 09 92 JSR Q209 ;copy memory absolute indexed A655 EQUW &08,&0F ;FROM catalogue entry, &0F08,X A657 EQUW &48,&10 ;TO workspace, &1048 A659 EQUB &08,&20 ;8 bytes, from X A65B 4C 61 A6 JMP R661 ;fall through: .R65E ;Unpack cat fields from wkspace A65E 20 00 92 JSR Q200 ;save AXY .R661 A661 A2 07 LDX #&07 ;point X to &104F LSB start sector A663 A0 0A LDY #&0A ;point Y to &1052 MSB start sector A665 AD 06 0F LDA &0F06 ;Is volume >= 256 KB? A668 29 04 AND #&04 ;00000100;mask bit 2 A66A D0 1F BNE R68B ;if not A66C AD 4E 10 LDA &104E ;then get top bits exec/length/load/start A66F 48 PHA A670 20 D6 A6 JSR R6D6 ;copy start sector to &1051..52 A673 C8 INY ;point Y to &1050 MSB file length A674 68 PLA ;restore top bits A675 4A LSR A ;push 00eelldd A676 4A LSR A A677 48 PHA A678 4A LSR A ;push 0000eell A679 4A LSR A A67A 48 PHA A67B 20 D6 A6 JSR R6D6 ;copy length to &104E..50 A67E 68 PLA A67F 4A LSR A A680 4A LSR A A681 20 D6 A6 JSR R6D6 ;copy exec to 104B..4D A684 68 PLA A685 20 D6 A6 JSR R6D6 ;copy load to 1048..4A A688 4C A7 A6 JMP R6A7 ;chip up and exit .R68B A68B AD 4E 10 LDA &104E ;else same as above A68E 48 PHA ;for volumes >=256 KB A68F 20 D8 A6 JSR R6D8 A692 C8 INY A693 68 PLA A694 4A LSR A A695 4A LSR A A696 48 PHA A697 4A LSR A A698 4A LSR A A699 48 PHA A69A 20 D8 A6 JSR R6D8 A69D 68 PLA A69E 4A LSR A A69F 4A LSR A A6A0 20 D0 A6 JSR R6D0 A6A3 68 PLA A6A4 20 D0 A6 JSR R6D0 .R6A7 ;Chip up catalogue fields A6A7 18 CLC A6A8 AD 51 10 LDA &1051 ;add volume offset A6AB 6D 38 10 ADC &1038 ;to start sector to make A6AE 8D 51 10 STA &1051 ;absolute offset A6B1 AD 52 10 LDA &1052 ;store in &1051..52 A6B4 6D 39 10 ADC &1039 A6B7 8D 52 10 STA &1052 A6BA AD 4E 10 LDA &104E ;store number of sectors used A6BD C9 01 CMP #&01 ;in &1053..54 A6BF AD 4F 10 LDA &104F A6C2 69 00 ADC #&00 A6C4 8D 53 10 STA &1053 A6C7 AD 50 10 LDA &1050 A6CA 69 00 ADC #&00 A6CC 8D 54 10 STA &1054 A6CF 60 RTS .R6D0 A6D0 29 02 AND #&02 ;Extend 17 bit to 18 bit - mask bit 1 A6D2 F0 02 BEQ R6D6 ;clear bit 0; if bit 1 set A6D4 09 03 ORA #&03 ;00000011 then copy it to bit 0 .R6D6 A6D6 29 03 AND #&03 ;00000011 ;Unpack 18 bit field .R6D8 A6D8 29 07 AND #&07 ;00000111 ;Unpack 19 bit field A6DA 20 E4 A6 JSR R6E4 ;store MSB A6DD 20 E0 A6 JSR R6E0 ;copy 2MSB, fall through for LSB: .R6E0 A6E0 BD 48 10 LDA &1048,X ;get byte from packed catalogue A6E3 CA DEX ;decrement offset .R6E4 A6E4 99 48 10 STA &1048,Y ;store byte in unpacked catalogue A6E7 88 DEY ;decrement offset A6E8 60 RTS .R6E9 ;Check parms/create file A6E9 20 00 9B JSR QB00 ;softmount and catalogue driv A6EC 20 09 A5 JSR R509 ;A=desired mode (OSFIND) A6EF 90 0A BCC R6FB ;read catalogue, find file A6F1 C9 80 CMP #&80 ;if not found, then: A6F3 F0 1A BEQ R70F ;if OPENOUT A6F5 C9 A0 CMP #&A0 ;or if called from OSFILE A6F7 F0 16 BEQ R70F ;then create catalogue entry A6F9 38 SEC ;else OPENIN/UP not found, A6FA 60 RTS ;exit C=1. .R6FB A6FB C9 40 CMP #&40 ;else file found. if OPENIN A6FD F0 03 BEQ R702 ;then don't check lock A6FF 20 21 A5 JSR R521 ;else check file not locked .R702 A702 20 06 98 JSR Q806 ;check file not open (mutex) A705 20 03 A6 JSR R603 ;unpack fields from catalogue A708 C9 A0 CMP #&A0 ;if not called from OSFILE A70A D0 11 BNE R71D ;then monitor and exit C=0 A70C 20 00 A6 JSR R600 ;else delete catalogue entry .R70F A70F 20 06 92 JSR Q206 ;copy memory absolute A712 EQUW &C0,&00 ;FROM immediate dir+filename, &00C0 A714 EQUW &58,&10 ;TO catalogue block 2, &1058 A716 EQUB &08 ;8-bytes A717 20 09 A6 JSR R609 ;create catalogue entry A71A 20 03 9B JSR QB03 ;write catalogue .R71D A71D 20 1B B7 JSR S71B ;call file access monitor A720 18 CLC ;and A721 60 RTS ;exit C=0. .R722 ;Create catalogue entry A722 20 00 92 JSR Q200 ;save AXY A725 AD 05 0F LDA &0F05 ;get number of files A728 C9 F8 CMP #&F8 ;11111000, if =31 A72A 90 13 BCC R73F ;then give volume error A72C 20 21 98 JSR Q821 ;print disc/volume error message A72F EQUB &BE A730 EQUS "catalogue full" A73E EQUB &00 .R73F A73F 20 0A A8 JSR R80A ;else find a free space in vol A742 90 31 BCC R775 ;if C=0 then success, do insert A744 20 1B A6 JSR R61B ;else get amount of free space on volume A747 AD 60 10 LDA &1060 ;16 bit compare: A74A CD 6B 10 CMP &106B ;free space - desired allocation A74D D0 06 BNE R755 A74F AD 61 10 LDA &1061 A752 CD 6C 10 CMP &106C .R755 A755 90 15 BCC R76C ;if <0 then "disc full" A757 20 21 98 JSR Q821 ;else raise "needs compacting" error A75A EQUB &C6 A75B EQUS "needs compacting" A76B EQUB &00 .R76C A76C 20 21 98 JSR Q821 ;Raise "Disc full" error A76F EQUB &C6 A770 EQUS "full" A774 EQUB &00 .R775 ;Do insert at slot &CC points to A775 AD 05 0F LDA &0F05 ;LDA &0F05 get file pointer A778 AA TAX ;copy to X (assert X<=&F0) A779 18 CLC ;add 8 to pointer A77A 69 08 ADC #&08 ;(assert 0<=?&CC<=&F0) A77C 8D 05 0F STA &0F05 ;and store back in catalogue. .R77F A77F E4 CC CPX &CC ;if catalogue slot at ?&CC free A781 F0 13 BEQ R796 ;then pack it (assert X>=?&CC) A783 CA DEX ;else bubble entries A784 BD 08 0E LDA &0E08,X ;into the next slot up A787 9D 10 0E STA &0E10,X ;going from end to start A78A BD 08 0F LDA &0F08,X ;and A78D 9D 10 0F STA &0F10,X A790 4C 7F A7 JMP R77F ;loop back to the test. .R793 ;Pack fields into catalogue A793 20 00 92 JSR Q200 ;save AXY .R796 A796 A6 CC LDX &CC ;as pointed to by &CC A798 20 09 92 JSR Q209 ;copy name and directory A79B EQUW &40,&10 A79D EQUW &08,&0E A79F EQUB &08,&02 A7A1 A0 00 LDY #&00 A7A3 20 D2 A7 JSR R7D2 ;copy low bytes load address A7A6 20 D2 A7 JSR R7D2 ;copy low bytes exec address A7A9 0A ASL A ;A = %00ee0000 or %00e00000 A7AA 0A ASL A A7AB 0A ASL A A7AC 0A ASL A A7AD 05 B8 ORA &B8 ;A = %00ee00dd or %00e000d0 A7AF 0A ASL A ;A = %ee00dd00 or %e000d000 A7B0 0A ASL A A7B1 20 EC A7 JSR R7EC ;copy low bytes length A7B4 0A ASL A ;A = %00ll0000 or %0lll0000 A7B5 0A ASL A A7B6 0A ASL A A7B7 0A ASL A A7B8 05 B8 ORA &B8 ;A = %eelldd00 or %ellld000 A7BA 85 B8 STA &B8 ;save A A7BC 38 SEC A7BD AD 51 10 LDA &1051 ;subtract absolute start sector A7C0 ED 38 10 SBC &1038 ;from start of volume A7C3 9D 09 0F STA &0F09,X ;store relative start sector A7C6 AD 52 10 LDA &1052 ;calculate high bits A7C9 ED 39 10 SBC &1039 ;A = %000000ss or %00000sss A7CC 05 B8 ORA &B8 ;A = %eellddss or %ellldsss A7CE 9D 08 0F STA &0F08,X ;store packed byte A7D1 60 RTS .R7D2 A7D2 20 EC A7 JSR R7EC ;save A in temp, copy 2 bytes A7D5 29 03 AND #&03 ;save b17..16 A7D7 48 PHA A7D8 AD 06 0F LDA &0F06 ;test volume size A7DB 29 04 AND #&04 ;if 256 KiB or more A7DD D0 02 BNE R7E1 ;then return single bit A7DF 68 PLA ;else return b17..16 A7E0 60 RTS .R7E1 A7E1 68 PLA ;restore b17..16 A7E2 C9 03 CMP #&03 ;if either is clear A7E4 D0 03 BNE R7E9 ;then return 0 A7E6 A9 02 LDA #&02 ;else return b1=1 A7E8 60 RTS .R7E9 A7E9 A9 00 LDA #&00 A7EB 60 RTS .R7EC A7EC 85 B8 STA &B8 ;Save A in temp, copy 2 bytes, A7EE 20 FA A7 JSR R7FA ;load third from fields, A7F1 20 FA A7 JSR R7FA ;return low 3 bits A7F4 20 02 A8 JSR R802 A7F7 29 07 AND #&07 ;00000111 A7F9 60 RTS .R7FA A7FA 20 02 A8 JSR R802 ;Copy byte from fields to high A7FD 9D 08 0F STA &0F08,X ;catalogue, increment X and Y A800 E8 INX A801 60 RTS .R802 ;Get byte from fields A802 B9 48 10 LDA &1048,Y A805 C8 INY ;increment Y A806 60 RTS .R807 ;Find a free space in volume A807 20 00 92 JSR Q200 ;save AXY .R80A A80A 20 95 A8 JSR R895 ;initialise for zeroth file .R80D A80D 20 06 92 JSR Q206 ;copy memory absolute A810 EQUW &58,&10 ;from catalogue block 2 at &1058 A812 EQUW &40,&10 ;to catalogue block 1 at &1040 A814 EQUB &18 ;(block 2 contains prospective file) A815 20 0F A6 JSR R60F ;Calculate absolute end of file A818 20 68 A8 JSR R868 ;determine if room to extend A81B B0 06 BCS R823 ;if so exit C=0 A81D 20 B3 A8 JSR R8B3 ;else unpack next file in cat A820 90 EB BCC R80D ;if more files then loop A822 60 RTS ;else exit C=1. .R823 A823 18 CLC A824 60 RTS .R825 ;Get free space on volume A825 20 00 92 JSR Q200 ;save AXY A828 A9 00 LDA #&00 ;set accumulator = 0 A82A 8D 60 10 STA &1060 A82D 8D 61 10 STA &1061 A830 20 95 A8 JSR R895 ;initialise for zeroth file .R833 A833 20 68 A8 JSR R868 ;get free space *before* file A836 90 13 BCC R84B ;if overlap then exit A838 18 CLC A839 6D 60 10 ADC &1060 ;else add AX to accumulator A83C 8D 60 10 STA &1060 A83F 8A TXA A840 6D 61 10 ADC &1061 A843 8D 61 10 STA &1061 A846 20 B3 A8 JSR R8B3 ;select next file in catalogue A849 90 E8 BCC R833 ;inc.imaginary end of volume file .R84B A84B 60 RTS ;and loop until no more files. .R84C ;Calculate absolute end of file A84C 48 PHA ;(last used sector +1) A84D 18 CLC A84E AD 53 10 LDA &1053 A851 6D 51 10 ADC &1051 A854 8D 69 10 STA &1069 A857 AD 54 10 LDA &1054 A85A 6D 52 10 ADC &1052 A85D 8D 6A 10 STA &106A A860 68 PLA A861 60 RTS .R862 ;Determine if room to extend A862 20 00 92 JSR Q200 ;save AXY A865 20 0F A6 JSR R60F ;calculate absolute last sec+1 .R868 A868 20 1E A6 JSR R61E ;get ceiling over file A86B 38 SEC ;subtract absolute end of file A86C ED 69 10 SBC &1069 A86F 48 PHA A870 8A TXA A871 ED 6A 10 SBC &106A A874 AA TAX A875 68 PLA A876 D0 02 BNE R87A A878 E8 INX ;return in AX A879 CA DEX ;Z=no free sectors .R87A A87A 60 RTS .R87B ;Get ceiling over catalogue entry A87B A6 CC LDX &CC ;get catalogue pointer A87D 18 CLC A87E BD 07 0F LDA &0F07,X ;get LSB volume relative start sector A881 6D 38 10 ADC &1038 ;add LSB start sector of volume A884 48 PHA ;save LSB absolute start sector A885 AD 06 0F LDA &0F06 ;get MSB sectors on volume A888 29 04 AND #&04 ;mask bit 2 A88A 09 03 ORA #&03 ;make mask for 256 or 512 KiB range A88C 3D 06 0F AND &0F06,X ;mask MSB relative start sector A88F 6D 39 10 ADC &1039 ;add MSB start sector of volume A892 AA TAX ;return MSB in X, LSB in A A893 68 PLA A894 60 RTS .R895 A895 48 PHA ;Initialise for zeroth file A896 AD 38 10 LDA &1038 ;copy offset to start of volume A899 8D 69 10 STA &1069 ;to absolute end of file A89C AD 39 10 LDA &1039 ;representing end of imaginary A89F 8D 6A 10 STA &106A ;zeroth file A8A2 0D 38 10 ORA &1038 ;if offset = 0 A8A5 D0 05 BNE R8AC A8A7 A9 02 LDA #&02 ;then set offset = 2 A8A9 8D 69 10 STA &1069 ;reserving 2 sectors for DFS cat .R8AC A8AC AD 05 0F LDA &0F05 ;set catalogue pointer A8AF 85 CC STA &CC ;to number of entries in cat. A8B1 68 PLA A8B2 60 RTS .R8B3 A8B3 20 06 A5 JSR R506 ;select next file in catalogue A8B6 B0 06 BCS R8BE ;if no more files then exit A8B8 20 03 A6 JSR R603 ;else unpack fields from cat A8BB 20 0F A6 JSR R60F ;calculate absolute end of file .R8BE A8BE 60 RTS ;exit ;unused space from &A8BF ;unused space ends at &A900 ;'Heavy' DFS commands .R900 A900 4C 09 A9 JMP R909 ;*FORMAT .R903 A903 4C C9 AB JMP RBC9 ;*CATGEN .R906 A906 4C 8E AB JMP RB8E ;*VERIFY .R909 ;*FORMAT A909 A9 FF LDA #&FF A90B 8D 70 10 STA &1070 ;set &1070..75 = &FF A90E 20 06 92 JSR Q206 ;copy memory absolute A911 EQUW &70,&10 ;FROM address &1070 A913 EQUW &71,&10 ;TO address &1071 A915 EQUB &05 ;5-bytes A916 20 04 AE JSR RE04 ;set default drive/clear params .R919 A919 20 18 93 JSR Q318 ;get optional drive spec A91C 90 03 BCC R921 ;if no more arguments A91E 4C 9C A9 JMP R99C ;then proceed with format, else test first nonspace char .R921 A921 C9 34 CMP #&34 ;Is it "4"? A923 D0 21 BNE R946 ;if not try others A925 A9 28 LDA #&28 ;else set no. tracks = 40 A927 8D 71 10 STA &1071 A92A 20 88 A9 JSR R988 ;do GSREAD, syntax error if EOW A92D C9 30 CMP #&30 ;is next character "0"? A92F D0 54 BNE R985 ;syntax error if not A931 20 C5 FF JSR &FFC5 ;call GSREAD A934 B0 E3 BCS R919 ;if end of arg, scan for another A936 8D 72 10 STA &1072 ;else store char A939 C9 2D CMP #&2D ;is it "-"? A93B D0 48 BNE R985 ;syntax error if not A93D 20 88 A9 JSR R988 ;else GSREAD, syntax err if EOW A940 C9 38 CMP #&38 ;is character "8"? A942 D0 41 BNE R985 ;syntax error if not A944 F0 09 BEQ R94F ;else ensure "0" follows. .R946 A946 C9 38 CMP #&38 ;does argument begin "8"? A948 D0 0F BNE R959 ;if not try other characters A94A A9 50 LDA #&50 ;else set no. tracks = 80 A94C 8D 71 10 STA &1071 .R94F A94F 20 88 A9 JSR R988 ;do GSREAD, syntax error if EOW A952 C9 30 CMP #&30 ;is character "0"? A954 D0 2F BNE R985 ;syntax error if not A956 4C 7D A9 JMP R97D ;else skip " ", scan next arg. .R959 A959 29 5F AND #&5F ;convert lowercase to uppercase A95B C9 53 CMP #&53 ;is it ASCII 'S'? A95D D0 08 BNE R967 ;if not try "D" or "O" A95F A9 0A LDA #&0A ;else A961 8D 70 10 STA &1070 ;set density = single A964 4C 7D A9 JMP R97D ;skip space, scan next arg. .R967 A967 C9 44 CMP #&44 ;is it ASCII 'D'? A969 D0 08 BNE R973 ;if not try "O" A96B A9 12 LDA #&12 ;else A96D 8D 70 10 STA &1070 ;set density = double A970 4C 7D A9 JMP R97D ;skip space, scan next arg. .R973 A973 C9 4F CMP #&4F ;is it ASCII 'O'? A975 D0 0E BNE R985 ;syntax error if not A977 20 8E A9 JSR R98E ;else get outstep value A97A 8D 74 10 STA &1074 ;and save it .R97D A97D 20 C5 FF JSR &FFC5 ;call GSREAD to skip space A980 90 03 BCC R985 ;syntax error if another char A982 4C 19 A9 JMP R919 ;else scan next argument. .R985 A985 4C 09 81 JMP P109 ;print syntax and quit .R988 A988 20 C5 FF JSR &FFC5 ;call GSREAD A98B B0 F8 BCS R985 ;syntax error if end of word A98D 60 RTS ;else return. .R98E A98E 20 88 A9 JSR R988 ;do GSREAD, syntax error if EOW A991 C9 30 CMP #&30 ;is character less than "0"? A993 90 F0 BCC R985 ;syntax error if so A995 C9 39 CMP #&39 ;is character "9" or greater? A997 B0 EC BCS R985 ;syntax error if so A999 29 0F AND #&0F ;else mask bits 0-3 A99B 60 RTS ;return value 0..9. .R99C A99C 20 09 90 JSR Q009 ;print newline A99F 20 70 AE JSR RE70 ;print "Formatting " A9A2 20 93 AE JSR RE93 ;print "drive n" A9A5 AD 70 10 LDA &1070 ;if density given on cmd line A9A8 10 0C BPL R9B6 ;then use that density A9AA AD 84 10 LDA &1084 ;else get *OPT 6 density A9AD D0 07 BNE R9B6 ;if manual, use that setting A9AF BD F0 0F LDA &0FF0,X ;else use density of curr drive A9B2 D0 02 BNE R9B6 ;if no disc has been used in it A9B4 A9 12 LDA #&12 ;then default density = double! .R9B6 A9B6 8D 70 10 STA &1070 ;set density A9B9 0A ASL A A9BA 0A ASL A ;multiply by 4 A9BB 8D 76 10 STA &1076 ;= number of CHRN bytes A9BE 2C 76 10 BIT &1076 ;if fewer than 16 sectors A9C1 70 0D BVS R9D0 A9C3 20 18 90 JSR Q018 ;then print " Sing" A9C6 EQUB &00 A9C7 EQUS " Sing" A9CC EQUB &00 A9CD 4C DA A9 JMP R9DA .R9D0 A9D0 20 18 90 JSR Q018 ;else print " Doub" A9D3 EQUB &00 A9D4 EQUS " Doub" A9D9 EQUB &00 .R9DA A9DA 20 18 90 JSR Q018 ;print "le Density"+newline A9DD EQUB &02 A9DE EQUS "le Density" A9E8 EQUB &00 A9E9 AD 71 10 LDA &1071 ;if no. tracks given A9EC 10 07 BPL R9F5 ;then validate that number A9EE BD F4 0F LDA &0FF4,X ;else get tracks on curr drive A9F1 D0 02 BNE R9F5 ;if no disc has been used in it A9F3 A9 50 LDA #&50 ;then default tracks = 80! .R9F5 A9F5 C9 50 CMP #&50 ;allow 80 tracks maximum A9F7 90 02 BCC R9FB ;(can save 2 bytes here) A9F9 A9 50 LDA #&50 ;set number of tracks .R9FB A9FB 8D 71 10 STA &1071 A9FE 20 18 90 JSR Q018 ;print " Tracks = "+n AA01 EQUB &80 AA02 EQUS " Tracks = " AA0C EQUB &00 AA0D AD 72 10 LDA &1072 ;if 40-80 mode specified AA10 10 0C BPL RA1E ;then set 2:1 stepping AA12 A9 00 LDA #&00 ;else default to 1:1 AA14 AC 71 10 LDY &1071 ;check number of tracks = 40 AA17 C0 28 CPY #&28 AA19 D0 03 BNE RA1E ;if not then keep 1:1 stepping AA1B AD 86 10 LDA &1086 ;else use *OPT 8 tracks setting .RA1E AA1E 8D 72 10 STA &1072 ;save stepping parameter AA21 A8 TAY AA22 F0 08 BEQ RA2C ;if not 1:1 stepping AA24 20 18 90 JSR Q018 ;then print "-80". AA27 EQUB &00 AA28 EQUS "-80" AA2B EQUB &00 .RA2C AA2C 20 09 90 JSR Q009 ;print newline AA2F AD 85 10 LDA &1085 ;get *OPT 7 volumes AA32 30 09 BMI RA3D ;if cheeseburger, volumes = 0 AA34 D0 09 BNE RA3F ;if manual, use that setting AA36 A9 08 LDA #&08 ;else volumes = 8 in double den AA38 2C 76 10 BIT &1076 ;test bit 6 AA3B 70 02 BVS RA3F ;if double density, branch .RA3D AA3D A9 00 LDA #&00 ;else, volumes = 0. .RA3F AA3F 8D 73 10 STA &1073 ;set number of volumes AA42 2C 76 10 BIT &1076 ;if not the default for this density AA45 70 06 BVS RA4D AA47 C9 00 CMP #&00 ;i.e. 0 volumes in single density AA49 F0 16 BEQ RA61 AA4B D0 04 BNE RA51 .RA4D AA4D C9 08 CMP #&08 ;or 8 volumes in double density AA4F F0 10 BEQ RA61 .RA51 AA51 20 18 90 JSR Q018 ;then print " Volumes = "+n+nl AA54 EQUB &82 AA55 EQUS " Volumes = " AA60 EQUB &00 .RA61 AA61 AD 74 10 LDA &1074 ;if outstep specified AA64 10 0F BPL RA75 ;then print its value AA66 A9 05 LDA #&05 ;else outstep = 5 in dbl dens AA68 2C 76 10 BIT &1076 ;if single density AA6B 70 02 BVS RA6F AA6D A9 03 LDA #&03 ;then outstep = 3. .RA6F AA6F 8D 74 10 STA &1074 ;set default outstep AA72 4C 85 AA JMP RA85 ;and skip printing it. .RA75 AA75 20 18 90 JSR Q018 ;print " Outstep = "+n+nl AA78 EQUB &82 AA79 EQUS " Outstep = " AA84 EQUB &00 .RA85 AA85 AD 70 10 LDA &1070 ;calculate density - outstep AA88 38 SEC ;to obtain logical outstep. AA89 ED 74 10 SBC &1074 ;sector nos on the next track AA8C 8D 74 10 STA &1074 ;are higher by this amount. AA8F 8A TXA ;put drive number in A AA90 20 0C 8A JSR PA0C ;and confirm overwrite AA93 B0 02 BCS RA97 ;if refused AA95 38 SEC AA96 60 RTS ;exit C=1, else: .RA97 ;Do *FORMAT AA97 AD 70 10 LDA &1070 AA9A 9D F0 0F STA &0FF0,X ;Configure target drive AA9D AD 71 10 LDA &1071 AAA0 9D F4 0F STA &0FF4,X AAA3 AD 72 10 LDA &1072 AAA6 9D F8 0F STA &0FF8,X AAA9 AD 73 10 LDA &1073 AAAC 9D FC 0F STA &0FFC,X AAAF A9 00 LDA #&00 ;Point O7F block to CHRN table AAB1 38 SEC ;at end of page &0E AAB2 ED 76 10 SBC &1076 ;and set a pointer to fill it AAB5 85 A8 STA &A8 AAB7 8D 11 10 STA &1011 AABA A9 0F LDA #&0F AABC E9 00 SBC #&00 AABE 85 A9 STA &A9 AAC0 8D 12 10 STA &1012 AAC3 A9 FF LDA #&FF AAC5 8D 13 10 STA &1013 AAC8 8D 14 10 STA &1014 AACB A9 00 LDA #&00 AACD 8D 17 10 STA &1017 ;Track no. = 0 AAD0 8D 77 10 STA &1077 ;Sector no. = 0 AAD3 8D 1A 10 STA &101A ;Gap 5 size = 0 (mini floppy) AAD6 A9 05 LDA #&05 ;5 parameters AAD8 8D 15 10 STA &1015 AADB A9 23 LDA #&23 ;&23 = 8271 Format command AADD 8D 16 10 STA &1016 AAE0 AD 70 10 LDA &1070 ;No. sectors to format = spt AAE3 09 20 ORA #&20 ;00100000, 256 byte sectors AAE5 8D 19 10 STA &1019 AAE8 A9 12 LDA #&12 ;if single density AAEA 8D 18 10 STA &1018 ;then gap3 = 18 AAED 8D 1B 10 STA &101B ;and gap1 = 18 AAF0 2C 76 10 BIT &1076 ;test density flag AAF3 50 0A BVC RAFF ;if double density AAF5 A9 1B LDA #&1B AAF7 8D 18 10 STA &1018 ;then gap3 = 27 AAFA A9 24 LDA #&24 AAFC 8D 1B 10 STA &101B ;and gap1 = 36 .RAFF AAFF 20 09 90 JSR Q009 ;print newline .RB02 AB02 20 70 AE JSR RE70 ;print "Formatting " AB05 20 A2 AE JSR REA2 ;print "track n" AB08 AE 70 10 LDX &1070 ;fill out CHRN block: AB0B A0 00 LDY #&00 .RB0D AB0D AD 17 10 LDA &1017 ;set cylinder (track) AB10 91 A8 STA (&A8),Y AB12 C8 INY AB13 AD 10 10 LDA &1010 ;get OSWORD &7F drive number AB16 29 02 AND #&02 ;extract bit 1 = side select AB18 4A LSR A ;H=0 drvs 0/2, H=1 drvs 1/3 AB19 91 A8 STA (&A8),Y ;set head number AB1B C8 INY AB1C AD 77 10 LDA &1077 ;set record (sector) AB1F 91 A8 STA (&A8),Y AB21 C8 INY AB22 A9 01 LDA #&01 ;set record length = 256 bytes AB24 91 A8 STA (&A8),Y AB26 C8 INY AB27 20 F6 AD JSR RDF6 ;add 1 to sector iter, mod spt. AB2A CA DEX ;loop until all sectors done AB2B D0 E0 BNE RB0D AB2D 20 0F 9B JSR QB0F ;call OSWORD &7F, report errors AB30 AD 74 10 LDA &1074 ;get track skew AB33 20 F6 AD JSR RDF6 ;add to sector iterator AB36 EE 17 10 INC &1017 ;increment track number AB39 AD 17 10 LDA &1017 ;have we formatted all tracks? AB3C CD 71 10 CMP &1071 AB3F D0 C1 BNE RB02 ;loop until all tracks done AB41 20 70 AE JSR RE70 ;print "Formatting " AB44 20 18 90 JSR Q018 ;print "catalog " AB47 EQUB &02 AB48 EQUS "catalog " AB50 EQUB &00 AB51 AD 73 10 LDA &1073 ;get no. volumes AB54 D0 0C BNE RB62 ;if =0 AB56 AD 71 10 LDA &1071 ;then get tracks on disc AB59 8D 78 10 STA &1078 ;set as tracks in volume AB5C 20 18 AE JSR RE18 ;create volume catalogues AB5F 4C 85 AB JMP RB85 ;then go to verify .RB62 AB62 A9 2E LDA #&2E ;set volume A = 46 tracks AB64 8D 78 10 STA &1078 AB67 A9 21 LDA #&21 ;set volume B = 33 tracks AB69 8D 79 10 STA &1079 AB6C AD 71 10 LDA &1071 AB6F C9 50 CMP #&50 ;is it an 80 track disc? AB71 F0 06 BEQ RB79 ;if not AB73 4E 78 10 LSR &1078 ;then AB76 4E 79 10 LSR &1079 ;halve those two values. .RB79 AB79 20 91 AC JSR RC91 ;validate volume allocation AB7C 20 03 AD JSR RD03 ;adjust volumes to fill disc AB7F 20 4E AC JSR RC4E ;create volume and disc cats AB82 20 09 90 JSR Q009 ;print newline .RB85 AB85 20 70 AE JSR RE70 ;print "Formatting " AB88 20 B1 AE JSR REB1 ;print "complete" AB8B 4C 99 AB JMP RB99 ;verify disc and exit .RB8E ;*VERIFY AB8E 20 04 AE JSR RE04 ;set default drive/clear params AB91 20 18 93 JSR Q318 ;parse arguments AB94 B0 03 BCS RB99 ;if incorrectly formed AB96 4C 09 81 JMP P109 ;print syntax and quit. .RB99 AB99 20 09 90 JSR Q009 ;else print newline AB9C 20 82 AE JSR RE82 ;print "Verifying " AB9F 20 93 AE JSR RE93 ;Print "drive n" ABA2 20 0C 9B JSR QB0C ;Softmount disc .RBA5 ABA5 20 53 AE JSR RE53 ;verify track ABA8 24 FF BIT &FF ;test Escape flag ABAA 10 0C BPL RBB8 ;if clear then continue ABAC 20 18 90 JSR Q018 ;else "Escape" error ABAF EQUB &0A ABB0 EQUB &11 ABB1 EQUS "Escape" ABB7 EQUB &00 .RBB8 ABB8 EE 17 10 INC &1017 ;increment track number ABBB AD 17 10 LDA &1017 ;fetch it ABBE DD F4 0F CMP &0FF4,X ;compare with tracks on disc ABC1 D0 E2 BNE RBA5 ;loop until all tracks done. ABC3 20 82 AE JSR RE82 ;print "Verifying " ABC6 4C B1 AE JMP REB1 ;print "complete" .RBC9 ;*CATGEN ABC9 8E 72 10 STX &1072 ;save command table pointer ABCC 20 04 AE JSR RE04 ;set default drive/clear params .RBCF ABCF 20 18 93 JSR Q318 ;get multiple drive spec ABD2 B0 27 BCS RBFB ;if no more arguments then proceed ABD4 20 1B 93 JSR Q31B ;else X=6, check volume letter ABD7 A5 C8 LDA &C8 ;if we return then letter valid ABD9 29 0F AND #&0F ;convert it to binary 1..8 ABDB AA TAX ABDC CA DEX ;subtract 1 ABDD A9 00 LDA #&00 ;clear this vol's track count ABDF 9D 78 10 STA &1078,X ;store .RBE2 ABE2 20 C5 FF JSR &FFC5 ;call GSREAD ABE5 B0 E8 BCS RBCF ;if EOW scan next argument ABE7 C9 30 CMP #&30 ;else is character "0"? ABE9 90 0A BCC RBF5 ;syntax error if less ABEB C9 3A CMP #&3A ;is it more than "9"? ABED B0 06 BCS RBF5 ;syntax error if more. ABEF 20 EF AC JSR RCEF ;add digit to track count ABF2 4C E2 AB JMP RBE2 ;loop to process more digits .RBF5 ABF5 AE 72 10 LDX &1072 ;restore command table pointer ABF8 4C 09 81 JMP P109 ;print syntax and quit .RBFB ABFB 20 0C 9B JSR QB0C ;softmount disc ABFE A6 C9 LDX &C9 ;x = current drive AC00 8A TXA ;x -> A = current drive AC01 20 18 90 JSR Q018 ;print "Drive "+n AC04 EQUB &C0 AC05 EQUS "Drive " AC0B EQUB &00 AC0C BD FC 0F LDA &0FFC,X ;get no. volumes on drive AC0F 8D 73 10 STA &1073 ;store in temp AC12 D0 1B BNE RC2F ;if =0 AC14 20 18 90 JSR Q018 ;then print ": single volume disc"+nl AC17 EQUB &02 AC18 EQUS ": single volume disc" AC2C EQUB &00 AC2D 38 SEC AC2E 60 RTS ;and exit C=1 .RC2F AC2F 20 91 AC JSR RC91 ;else validate vol allocation AC32 AD 81 10 LDA &1081 ;get total number of tracks AC35 D0 0D BNE RC44 ;if =0, then user wants a volume cat AC37 20 06 92 JSR Q206 ;copy memory absolute AC3A EQUW &30,&10 ;FROM actual vol allocations at &1030 AC3C EQUW &78,&10 ;TO command line workspace at &1078 AC3E EQUB &08 ;count AC3F 20 4A AD JSR RD4A ;print *CATGEN heading AC42 38 SEC AC43 60 RTS ;and exit C=1 .RC44 AC44 20 03 AD JSR RD03 ;else adjust volumes to fill AC47 A5 C9 LDA &C9 ;A = current drive AC49 20 0C 8A JSR PA0C ;ask user for confirmation AC4C 90 41 BCC RC8F ;if refused exit C=1, else: .RC4E AC4E 20 18 AE JSR RE18 ;Create volume and disc catalogues AC51 A9 00 LDA #&00 ;create volume catalogues AC53 AC 70 10 LDY &1070 ;get density (=sec/trk) AC56 8C 03 0E STY &0E03 ;store in disc catalogue .RC59 AC59 18 CLC AC5A 6D 71 10 ADC &1071 ;add number of tracks AC5D 90 03 BCC RC62 ;carry out to disc cat AC5F EE 02 0E INC &0E02 .RC62 AC62 88 DEY ;decrement sectors AC63 D0 F4 BNE RC59 ;and loop while more to go. AC65 8D 01 0E STA &0E01 ;store no. of sectors on disc AC68 AD 71 10 LDA &1071 ;get number of tracks AC6B 8D 04 0E STA &0E04 ;store in disc catalogue AC6E A9 01 LDA #&01 ;start volumes on track 1 AC70 A2 00 LDX #&00 ;clear X and Y offsets AC72 A0 00 LDY #&00 ;to start at first volume: .RC74 AC74 99 08 0E STA &0E08,Y ;store start track number AC77 18 CLC AC78 7D 78 10 ADC &1078,X ;add no. tracks in volume AC7B 48 PHA AC7C BD 78 10 LDA &1078,X AC7F D0 03 BNE RC84 ;if volume is absent AC81 99 08 0E STA &0E08,Y ;then delete start track no. .RC84 AC84 68 PLA AC85 C8 INY AC86 C8 INY ;increase disc cat offset by 2 AC87 E8 INX ;increment volume cat offset AC88 E0 08 CPX #&08 AC8A D0 E8 BNE RC74 ;and loop for all 8 volumes. AC8C 20 03 9B JSR QB03 ;write disc catalogue .RC8F AC8F 38 SEC AC90 60 RTS ;and exit C=1. .RC91 ;Validate volume allocation AC91 20 00 92 JSR Q200 ;save AXY AC94 A6 C9 LDX &C9 ;x = current drive AC96 BD F4 0F LDA &0FF4,X ;get no. tracks on this drive AC99 8D 71 10 STA &1071 ;store in cmd line parameter AC9C 8D 80 10 STA &1080 ;and store volume size limit AC9F BC F0 0F LDY &0FF0,X ;get density of this drive ACA2 8C 70 10 STY &1070 ;store in cmd line parameter ACA5 A2 00 LDX #&00 ;clear total number of tracks ACA7 8E 81 10 STX &1081 ;X = volume offset = 0 (A) .RCAA ACAA BD 78 10 LDA &1078,X ;get no. tracks in this volume ACAD F0 17 BEQ RCC6 ;if nonexistent vol then skip ACAF EC 73 10 CPX &1073 ;else if >= no.volumes ACB2 B0 18 BCS RCCC ;error "vol nn unavailable" ACB4 CD 80 10 CMP &1080 ;else if >= tracks on disc ACB7 B0 23 BCS RCDC ;error "vol nn spec too large" ACB9 6D 81 10 ADC &1081 ;else add to total tracks ACBC B0 72 BCS RD30 ;if >255 ACBE CD 71 10 CMP &1071 ;or if >= tracks on disc ACC1 B0 6D BCS RD30 ;error "total tracks too many" ACC3 8D 81 10 STA &1081 ;else store new total. .RCC6 ACC6 E8 INX ;increment volume pointer ACC7 E0 08 CPX #&08 ;and loop for all 8 volumes ACC9 D0 DF BNE RCAA ACCB 60 RTS ;then exit .RCCC ACCC 20 21 98 JSR Q821 ;print disc/volume error message ACCF EQUB &D2 ACD0 EQUS "unavailable" ACDB EQUB &00 .RCDC ACDC 20 21 98 JSR Q821 ;print disc/volume error message ACDF EQUB &D2 ACE0 EQUS "spec too large" ACEE EQUB &00 .RCEF ;Add digit to track count ACEF 20 00 92 JSR Q200 ;save AXY ACF2 29 0F AND #&0F ;convert ASCII num to binary ACF4 A0 0A LDY #&0A ;set counter = 10 ACF6 18 CLC .RCF7 ACF7 7D 78 10 ADC &1078,X ;add former units digit ACFA B0 E0 BCS RCDC ;give error if carry out ACFC 88 DEY ;else loop to multiply x10. ACFD D0 F8 BNE RCF7 ACFF 9D 78 10 STA &1078,X ;store tens plus new unit. AD02 60 RTS .RD03 ;Adjust volumes to fill disc AD03 20 00 92 JSR Q200 ;save AXY AD06 AD 71 10 LDA &1071 ;get no. tracks on disc AD09 18 CLC ;clear carry AD0A ED 81 10 SBC &1081 ;sub (tracks in volumes + 1) AD0D F0 3E BEQ RD4D ;if zero result go and print AD0F AE 73 10 LDX &1073 ;else get no. volumes .RD12 AD12 18 CLC ;clear carry AD13 7D 77 10 ADC &1077,X ;add track slack to last vol AD16 9D 77 10 STA &1077,X ;and store AD19 CD 80 10 CMP &1080 ;compare new size - disc size AD1C 90 2F BCC RD4D ;if <0 go and print AD1E 48 PHA ;else volume overflows. AD1F AD 80 10 LDA &1080 ;get total tracks AD22 38 SEC ;set carry AD23 E9 01 SBC #&01 ;reduce by 1 AD25 9D 77 10 STA &1077,X ;store as volume size AD28 68 PLA ;restore calculated size AD29 38 SEC ;subtract (total - 1) AD2A FD 77 10 SBC &1077,X ;= slack remaining AD2D CA DEX ;try again with next volume AD2E D0 E2 BNE RD12 ;if no more volumes then: .RD30 AD30 20 21 98 JSR Q821 ;print disc/volume error message AD33 EQUB &D2 AD34 EQUS "total tracks too many" AD49 EQUB &00 .RD4A ;Print *CATGEN heading AD4A 20 00 92 JSR Q200 ;save AXY .RD4D ;Print *CATGEN heading AD4D 20 18 90 JSR Q018 ;print heading on its own line .... AD50 EQUB &03 AD51 EQUS "Volume Tracks Sectors K bytes" AD71 EQUB &00 AD72 A9 01 LDA #&01 ;A=1, cats take one track AD74 20 18 90 JSR Q018 ;print nl+" Cat" AD77 EQUB &01 AD78 EQUS " Cat" AD7C EQUB &00 AD7D 20 9B AD JSR RD9B ;print volume listing line AD80 A0 41 LDY #&41 ;Y="A" .RD82 AD82 B9 37 10 LDA &1037,Y ;get size from 1078..F AD85 F0 0E BEQ RD95 ;if =0 then skip volume AD87 48 PHA ;else save no. tracks AD88 98 TYA ;A=volume letter AD89 20 18 90 JSR Q018 ;print 3 spaces + letter AD8C EQUB &C0 AD8D EQUS " " AD90 EQUB &00 AD91 68 PLA ;restore no. tracks AD92 20 9B AD JSR RD9B ;print volume listing line .RD95 AD95 C8 INY ;increment volume letter AD96 C0 49 CPY #&49 ;have we gone past "H"? AD98 D0 E8 BNE RD82 ;if not loop AD9A 60 RTS ;else exit C=1 .RD9B AD9B 48 PHA ;Print volume listing line AD9C A9 0A LDA #&0A ;save no. tracks in A AD9E 20 06 90 JSR Q006 ;Tab to column in A ADA1 68 PLA ;peek no. tracks ADA2 48 PHA ADA3 20 12 90 JSR Q012 ;print decimal byte ADA6 8D 74 10 STA &1074 ;store in temp ADA9 A9 12 LDA #&12 ;A=18 ADAB 20 06 90 JSR Q006 ;Tab to column in A ADAE 20 DB AD JSR RDDB ;multiply to get sectors ADB1 20 09 A4 JSR R409 ;print decimal word ADB4 A9 1B LDA #&1B ;A=27 ADB6 20 06 90 JSR Q006 ;Tab to column in A ADB9 20 DB AD JSR RDDB ;regenerate no. sectors ADBC 4E 61 10 LSR &1061 ;shift right twice ADBF 6E 60 10 ROR &1060 ;to divide by 4 ADC2 4E 61 10 LSR &1061 ;and get kilobytes. ADC5 6E 60 10 ROR &1060 ;C=1 if we get half a K ADC8 08 PHP ;save carry flag ADC9 20 09 A4 JSR R409 ;print decimal word ADCC 28 PLP ;restore carry flag ADCD 90 07 BCC RDD6 ;if set ADCF 20 18 90 JSR Q018 ;then print ".5" ADD2 EQUB &00 ADD3 EQUS ".5" ADD5 EQUB &00 .RDD6 ADD6 20 09 90 JSR Q009 ;print newline ADD9 68 PLA ;restore no. tracks ADDA 60 RTS ;and exit .RDDB ;Multiply tracks by spt ADDB 20 00 92 JSR Q200 ;save AXY ADDE A9 00 LDA #&00 ;and result word high byte. ADE0 8D 61 10 STA &1061 ;get density (=sectors/track) ADE3 AE 70 10 LDX &1070 ;into X. .RDE6 ADE6 18 CLC ;clear carry ADE7 6D 74 10 ADC &1074 ;add track count to total ADEA 90 03 BCC RDEF ;if carry out occurs ADEC EE 61 10 INC &1061 ;increment result high byte .RDEF ADEF CA DEX ;decrement sectors remaining ADF0 D0 F4 BNE RDE6 ;loop if more to go ADF2 8D 60 10 STA &1060 ;else store low byte and exit ADF5 60 RTS .RDF6 ;Add A to sector iterator ADF6 18 CLC ;clear carry ADF7 6D 77 10 ADC &1077 ;add A to sector iterator ADFA 38 SEC ;set carry .RDFB ADFB 8D 77 10 STA &1077 ;repeatedly subtract sectors/trk ADFE ED 70 10 SBC &1070 ;to obtain remainder AE01 B0 F8 BCS RDFB ;leave ?&1070 in range 0..spt-1 AE03 60 RTS .RE04 ;Set default drive/clear params AE04 20 00 92 JSR Q200 ;save AXY AE07 AD 09 10 LDA &1009 ;zero *command argument space AE0A 85 C9 STA &C9 ;A = current drive AE0C A2 00 LDX #&00 AE0E 8A TXA .RE0F AE0F 9D 78 10 STA &1078,X AE12 E8 INX AE13 E0 08 CPX #&08 AE15 D0 F8 BNE RE0F AE17 60 RTS .RE18 ;Create volume catalogues AE18 20 00 92 JSR Q200 ;save AXY AE1B A9 41 LDA #&41 ;Set immediate volume = A AE1D 85 C8 STA &C8 ;A -> &00C8 = Immediate volume AE1F A9 00 LDA #&00 ;Zero catalogue pages AE21 AA TAX .RE22 AE22 9D 00 0E STA &0E00,X AE25 9D 00 0F STA &0F00,X AE28 E8 INX AE29 D0 F7 BNE RE22 .RE2B AE2B A9 99 LDA #&99 ;cat version no, will => &00 AE2D 8D 04 0F STA &0F04 AE30 A9 00 LDA #&00 AE32 8D 06 0F STA &0F06 AE35 AC 70 10 LDY &1070 ;multiply spt by tracks in vol .RE38 AE38 18 CLC AE39 7D 78 10 ADC &1078,X AE3C 90 03 BCC RE41 AE3E EE 06 0F INC &0F06 .RE41 AE41 88 DEY AE42 D0 F4 BNE RE38 AE44 8D 07 0F STA &0F07 ;store in size field of cat AE47 20 03 9B JSR QB03 ;write current catalogue AE4A E6 C8 INC &C8 ;increment volume letter AE4C E8 INX AE4D EC 73 10 CPX &1073 ;have we created all volumes? AE50 90 D9 BCC RE2B ;loop until done AE52 60 RTS ;then exit .RE53 AE53 48 PHA AE54 20 82 AE JSR RE82 ;print "Verifying" AE57 20 A2 AE JSR REA2 ;print "track n" AE5A A9 1F LDA #&1F ;a = 8271 verify command AE5C 8D 16 10 STA &1016 ;set OSWORD &7F command AE5F A9 00 LDA #&00 AE61 8D 18 10 STA &1018 ;start verifying at sector 0 AE64 A6 C9 LDX &C9 ;x = current drive AE66 BD F0 0F LDA &0FF0,X ;get no. sectors per track AE69 8D 19 10 STA &1019 ;set no. sectors to verify AE6C 68 PLA AE6D 4C 15 9B JMP QB15 ;call OSWORD &7F r/w w/errors. .RE70 AE70 20 18 90 JSR Q018 ;Print "Formatting " AE73 EQUB &00 AE74 EQUB &0B AE75 EQUS "Formatting " AE80 EQUB &00 AE81 60 RTS .RE82 AE82 20 18 90 JSR Q018 ;Print "Verifying " AE85 EQUB &00 AE86 EQUB &0B AE87 EQUS "Verifying " AE91 EQUB &00 AE92 60 RTS .RE93 ;Print "drive n" AE93 A6 C9 LDX &C9 ;X = current drive AE95 8A TXA ;X -> A = current drive AE96 20 18 90 JSR Q018 ;Print "drive n" AE99 EQUB &C2 AE9A EQUS "drive " AEA0 EQUB &00 AEA1 60 RTS .REA2 ;Print "track n" AEA2 AD 17 10 LDA &1017 ;A = track number AEA5 20 18 90 JSR Q018 AEA8 EQUB &82 AEA9 EQUS "track " AEAF EQUB &00 AEB0 60 RTS .REB1 AEB1 20 18 90 JSR Q018 ;Print "complete" AEB4 EQUB &02 AEB5 EQUS "complete" AEBD EQUB &00 AEBE 38 SEC ;set CF = 1 and exit AEBF 60 RTS ;unused space from &AEC0 #ifdef _UNUSED ;possible sequence of events: ;1. 'Heavy' DFS commands are assembled at &A900..&AF0B ; (Buffer not cleared, bytes &AE0C..FF are repeated at &AF0C..FF) ;2. Code at &AE82..9E (29 bytes) deleted from source, last byte =&AEEE ;3. CLC inserted at &AE16, last byte =&AEEF ;4. 30 bytes before &ADEF (=ROR &1060) deleted, last byte =&AED1 ;5. 'Heavy' DFS commands are reassembled at &A900..&AED1 ; (Buffer not cleared, bytes &ADD2..FF repeated at &AED2..FF, now erased) ;6. Macro functions are assembled at &9200..B9 ; (Buffer not cleared, 'Heavy' bytes &AEBA..D1 repeated at &92BA..D1; ; 'Heavy' bytes &ADD2..FF repeated at &92D2..FF) ;7. 18 bytes before &ADD1 deleted, last byte =&AEBF ;8. Meanwhile, random access code updated to clear buffer on file extension ;9. Intermediate EDOS installed, replacing previous FS ;10.'Heavy' DFS commands are reassembled at &A900..&AEBF. ;verbatim copy of *VERIFY code at &AEB4..BF; used code is 76 bytes tighter AF00 EQUB &02 AF01 EQUS "complete" AF09 EQUB &00 AF0A 38 SEC AF0B 60 RTS ;copy of *CATGEN code at &ADDC..&AE52; used code is 48 bytes tighter AF0C EQUB &00,&92 AF0E A9 00 LDA #&00 AF10 8D 61 10 STA &1061 AF13 AE 70 10 LDX &1070 .RF16 ;omits ADE6=CLC AF16 6D 74 10 ADC &1074 AF19 90 03 BCC RF1E AF1B EE 61 10 INC &1061 .RF1E AF1E CA DEX AF1F D0 F5 BNE RF16 AF21 8D 60 10 STA &1060 AF24 60 RTS AF25 18 CLC AF26 6D 77 10 ADC &1077 AF29 38 SEC .RF2A AF2A 8D 77 10 STA &1077 AF2D ED 70 10 SBC &1070 AF30 B0 F8 BCS RF2A AF32 60 RTS AF33 20 00 92 JSR Q200 AF36 AD 09 10 LDA &1009 AF39 85 C9 STA &C9 AF3B A2 00 LDX #&00 AF3D 8A TXA .RF3E AF3E 9D 78 10 STA &1078,X AF41 E8 INX AF42 E0 08 CPX #&08 AF44 D0 F8 BNE RF3E AF46 60 RTS AF47 20 00 92 JSR Q200 AF4A A9 41 LDA #&41 AF4C 85 C8 STA &C8 AF4E A9 00 LDA #&00 AF50 AA TAX .RF51 AF51 9D 00 0E STA &0E00,X AF54 9D 00 0F STA &0F00,X AF57 E8 INX AF58 D0 F7 BNE RF51 .RF5A AF5A A9 99 LDA #&99 AF5C 8D 04 0F STA &0F04 AF5F A9 00 LDA #&00 AF61 8D 06 0F STA &0F06 AF64 AC 70 10 LDY &1070 .RF67 AF67 18 CLC AF68 7D 78 10 ADC &1078,X AF6B 90 03 BCC RF70 AF6D EE 06 0F INC &0F06 .RF70 AF70 88 DEY AF71 D0 F4 BNE RF67 AF73 8D 07 0F STA &0F07 AF76 20 03 9B JSR QB03 AF79 E6 C8 INC &C8 AF7B E8 INX AF7C EC 73 10 CPX &1073 AF7F 90 D9 BCC RF5A AF81 60 RTS ;highly modified version of code at &943F..49, &9473..97 .RF82 AF82 18 CLC AF83 20 C2 FF JSR &FFC2 AF86 20 C5 FF JSR &FFC5 AF89 B0 13 BCS RF9E AF8B C9 30 CMP #&30 AF8D 90 0E BCC RF9D AF8F C9 34 CMP #&34 AF91 B0 0A BCS RF9D AF93 85 C9 STA &C9 AF95 20 C5 FF JSR &FFC5 AF98 B0 E8 BCS RF82 AF9A 4C 09 81 JMP P109 .RF9D AF9D 18 CLC .RF9E AF9E 60 RTS ;copy of *FORMAT code at &AE53..B3, used code is 76 bytes tighter AF9F 48 PHA AFA0 20 CE AE JSR RECE ;AE54=JSR RE82 AFA3 20 EE AE JSR REEE ;AE56=JSR REA2 AFA6 A9 1F LDA #&1F AFA8 8D 16 10 STA &1016 AFAB A9 00 LDA #&00 AFAD 8D 18 10 STA &1018 AFB0 A6 C9 LDX &C9 AFB2 BD F0 0F LDA &0FF0,X AFB5 8D 19 10 STA &1019 AFB8 68 PLA AFB9 4C 15 9B JMP QB15 AFBC 20 18 90 JSR Q018 AFBF EQUB &00 AFC0 EQUB &0B AFC1 EQUS "Formatting " AFCC EQUB &00 AFCD 60 RTS AFCE 20 18 90 JSR Q018 AFD1 EQUB &00 AFD2 EQUB &0B AFD3 EQUS "Verifying " AFDD EQUB &00 AFDE 60 RTS AFDF A6 C9 LDX &C9 AFE1 8A TXA AFE2 20 18 90 JSR Q018 AFE5 EQUB &C2 AFE6 EQUS "drive " AFEC EQUB &00 AFED 60 RTS AFEE AD 17 10 LDA &1017 AFF1 20 18 90 JSR Q018 AFF4 EQUB &82 AFF5 EQUS "track " AFFB EQUB &00 AFFC 60 RTS AFFD 20 18 90 JSR &9018 #endif /* _UNUSED */ ;unused space ends at &B000 ;EDOS API, part 1 B000 4C 0C B0 JMP S00C ;OSFILE B003 4C 1A B1 JMP S11A ;OSARGS B006 4C 7C B1 JMP S17C ;OSFIND B009 4C A9 B1 JMP S1A9 ;OSFSC .S00C ;OSFILE B00C 20 00 92 JSR Q200 ;save AXY B00F 20 06 B7 JSR S706 ;call monitor B012 20 09 B4 JSR S409 ;copy user's OSFILE/GBPB block B015 AA TAX ;transfer reason code to X B016 E8 INX ;add 1 B017 E0 08 CPX #&08 ;does A equal 0..6 or &FF? B019 90 01 BCC S01C ;if so continue B01B 60 RTS ;else exit C=1. .S01C B01C BD 12 B1 LDA &B112,X ;get microcode byte from B112..9 B01F 85 CD STA &CD ;store in shift register B021 BA TSX ;have A=1 returned on exit B022 A9 01 LDA #&01 ;as no hierarchical directories B024 9D 05 01 STA &0105,X ;and err given if file not found B027 AE 70 10 LDX &1070 ;put address of filename in XY B02A AC 71 10 LDY &1071 B02D 20 33 B3 JSR S333 ;set up GSINIT B030 20 12 93 JSR Q312 ;and get file spec from the string B033 46 CD LSR &CD ;sample first bit of microcode B035 90 43 BCC S07A B037 A2 72 LDX #&72 ;......1 Save file B039 A0 60 LDY #&60 ;OSFILE load addr to cat block 2 B03B 20 51 B3 JSR S351 ;do 32 to 18 bit copy B03E A2 76 LDX #&76 ;OSFILE exec addr to cat block 2 B040 A0 63 LDY #&63 B042 20 51 B3 JSR S351 ;do 32 to 18 bit copy B045 38 SEC B046 AD 7E 10 LDA &107E ;subtract OSFILE end address B049 ED 7A 10 SBC &107A ;from start address B04C 8D 66 10 STA &1066 ;to get length B04F AD 7F 10 LDA &107F ;(note 16 bit so file 64K max) B052 ED 7B 10 SBC &107B B055 8D 67 10 STA &1067 B058 AE 66 10 LDX &1066 ;is low byte of length zero? B05B E0 01 CPX #&01 ;if not set carry flag B05D 69 00 ADC #&00 ;and increment high byte B05F 8D 6B 10 STA &106B ;to make the sector count B062 A9 00 LDA #&00 ;clear high byte B064 8D 6C 10 STA &106C ;of sector count B067 8A TXA ;low byte to A and discard B068 A9 A0 LDA #&A0 ;&A0 = OSFILE reason code B06A 20 18 A6 JSR R618 ;check perms/create file B06D 20 06 92 JSR Q206 ;copy start address B070 EQUW &7A,&10 ;FROM start address at &107A B072 EQUW &11,&10 ;TO OSWORD &7F block at &1011 B074 EQUB &04 ;count B075 A9 0B LDA #&0B ;a = 8271 write command B077 4C 42 B3 JMP S342 ;save data to disc and exit .S07A B07A 20 00 9B JSR QB00 ;......0 load catalogue B07D 20 0C A5 JSR R50C ;check file exists B080 20 03 A6 JSR R603 ;unpack fields from catalogue B083 46 CD LSR &CD B085 90 13 BCC S09A B087 20 06 92 JSR Q206 ;.....10 Load file. Copy memory B08A EQUW &72,&10 ;FROM OSFILE load address at &1072 B08C EQUW &11,&10 ;TO OSWORD &7F block at &1011 B08E EQUB &04 ;count B08F AD 76 10 LDA &1076 ;test low byte of exec address B092 F0 03 BEQ S097 ;if =0 then skip, else: B094 20 70 B3 JSR S370 ;copy load addr from cat to O7F .S097 B097 20 40 B3 JSR S340 ;load data from disc .S09A B09A 46 CD LSR &CD B09C 90 38 BCC S0D6 B09E A2 48 LDX #&48 ;....1x0 Get file info B0A0 A0 72 LDY #&72 ;load addr from cat to OSFILE B0A2 20 74 B3 JSR S374 ;do 18 to 32 bit copy B0A5 A2 4B LDX #&4B ;exec addr from cat to OSFILE B0A7 A0 76 LDY #&76 B0A9 20 74 B3 JSR S374 ;do 18 to 32 bit copy B0AC 20 06 92 JSR Q206 ;copy memory absolute B0AF EQUW &4E,&10 ;FROM length from cat at &104E B0B1 EQUW &7A,&10 ;TO OSFILE at &107A B0B3 EQUB &03 ;count B0B4 A9 00 LDA #&00 ;clear top byte of length B0B6 AA TAX ;and attribute word .S0B7 B0B7 9D 7D 10 STA &107D,X B0BA E8 INX B0BB E0 05 CPX #&05 B0BD D0 F8 BNE S0B7 B0BF 2C 47 10 BIT &1047 ;test lock bit of cat entry B0C2 10 05 BPL S0C9 ;if clear then skip, else: B0C4 A9 0A LDA #&0A ;set low attribute byte = &0A B0C6 8D 7E 10 STA &107E ;as user can't write or delete .S0C9 B0C9 A0 00 LDY #&00 ;copy OSFILE block back .S0CB B0CB B9 70 10 LDA &1070,Y ;to user's area B0CE 91 BE STA (&BE),Y B0D0 C8 INY B0D1 C0 12 CPY #&12 B0D3 D0 F6 BNE S0CB B0D5 60 RTS ;and exit .S0D6 B0D6 20 21 A5 JSR R521 ;check file not locked B0D9 46 CD LSR &CD ;microcode shift register in OSGBPB etc B0DB 90 06 BCC S0E3 B0DD 20 00 A6 JSR R600 ;...10x0 Delete file B0E0 4C 03 9B JMP QB03 ;write catalogue .S0E3 B0E3 46 CD LSR &CD ;microcode shift register in OSGBPB etc B0E5 90 07 BCC S0EE B0E7 A2 72 LDX #&72 ;..100x0 Set load address B0E9 A0 48 LDY #&48 ;load address to cat block 1 B0EB 20 51 B3 JSR S351 ;do 32 to 18 bit copy. .S0EE B0EE 46 CD LSR &CD ;microcode shift register in OSGBPB etc B0F0 90 07 BCC S0F9 B0F2 A2 76 LDX #&76 ;.1x00x0 Set exec address B0F4 A0 4B LDY #&4B ;exec address to cat block 1 B0F6 20 51 B3 JSR S351 ;to 32 to 18 bit copy .S0F9 B0F9 46 CD LSR &CD ;microcode shift register in OSGBPB etc B0FB 90 0F BCC S10C B0FD AD 7E 10 LDA &107E ;1xx00x0 Set attributes B100 29 0A AND #&0A ;mask bits 0,2,4-7 of attributes B102 F0 02 BEQ S106 ;if b2=1 and/or b0=1 B104 A9 80 LDA #&80 ;then set L bit of catalogue entry .S106 B106 0D 47 10 ORA &1047 ;else leave L bit unchanged B109 8D 47 10 STA &1047 .S10C B10C 20 06 A6 JSR R606 ;xxx00x0 Not save delete or info pack fields B10F 4C 03 9B JMP QB03 ;write catalogue and exit B112 EQUB &06,&01,&70,&10 ;8 microcode bytes for OSFILE B116 EQUB &20,&40,&04,&08 ;&FF and 0 to 6 .S11A B11A 20 09 B7 JSR S709 ;call OSARGS monitor B11D 85 CD STA &CD ;when A=&FF flush routine flushes B11F C0 00 CPY #&00 B121 D0 25 BNE S148 B123 C9 00 CMP #&00 B125 D0 03 BNE S12A ;a=0, y=0: return FS number B127 A9 04 LDA #&04 B129 60 RTS .S12A B12A 20 00 92 JSR Q200 ;save AXY B12D C9 01 CMP #&01 B12F D0 10 BNE S141 B131 20 09 92 JSR Q209 ;copy memory absolute indexed B134 EQUW &82,&10 ;from workspace B136 EQUW &00,&00 ;to bottom of user's block B138 EQUB &02,&02 ;2 bytes, X indexed destination B13A A9 FF LDA #&FF ;set top word to &FFFF B13C 95 02 STA &02,X ;indicating I/O memory B13E 95 03 STA &03,X .S140 B140 60 RTS ;and exit. .S141 B141 C9 FF CMP #&FF ;a=&FF, y=0: flush all files B143 D0 FB BNE S140 B145 4C 18 98 JMP Q818 .S148 B148 20 00 92 JSR Q200 ;save AXY B14B 20 0C 98 JSR Q80C ;check file open & return pointer B14E C9 00 CMP #&00 ;y>0: file handle given B150 D0 11 BNE S163 ;ensure file is open B152 C8 INY ;a=0, y>0: return PTR B153 C8 INY ;increment channel pointer B154 C8 INY ;to point to PTR not EXT: .S155 ;a=2, y>0: return EXT B155 20 09 92 JSR Q209 ;copy memory absolute indexed B158 EQUW &9A,&10 ;from workspace B15A EQUW &00,&00 ;to bottom of user's block B15C EQUB &03,&12 ;3 bytes, from Y to X B15E A9 00 LDA #&00 ;clear top byte of PTR B160 95 03 STA &03,X B162 60 RTS ;and exit. .S163 B163 C9 01 CMP #&01 ;a=1, y>0: write PTR B165 D0 0A BNE S171 B167 20 09 92 JSR Q209 ;copy memory absolute indexed B16A EQUW &00,&00 ;from user's block B16C EQUW &9D,&10 ;to workspace B16E EQUB &03,&21 ;nothing happens to file until next write! .S170 B170 60 RTS ;exit .S171 B171 C9 02 CMP #&02 B173 F0 E0 BEQ S155 B175 C9 FF CMP #&FF B177 D0 F7 BNE S170 ;a=&FF, y>0: flush file B179 4C 0F 98 JMP Q80F .S17C ;OSFIND B17C 20 00 92 JSR Q200 ;save AXY B17F 20 15 B7 JSR S715 ;call OSFIND Monitor B182 C9 00 CMP #&00 ;is it a CLOSE# ? B184 F0 03 BEQ S189 ;if so, B186 4C 98 B1 JMP S198 ;then: .S189 B189 85 CD STA &CD ;b7=0 so flush routine closes B18B 98 TYA B18C AA TAX ;channel number to X B18D D0 03 BNE S192 ;if channel number =0 B18F 4C 18 98 JMP Q818 ;then close all channels &exit .S192 B192 20 03 98 JSR Q803 ;else set up for channel X B195 4C 15 98 JMP Q815 ;close channel and exit. .S198 B198 48 PHA ;save file open mode B199 20 33 B3 JSR S333 ;GSINIT string in XY B19C 20 12 93 JSR Q312 ;get file spec B19F 68 PLA ;restore mode B1A0 20 1E 98 JSR Q81E ;open a file B1A3 8A TXA ;return channel in A B1A4 BA TSX ;SP -> X B1A5 9D 05 01 STA &0105,X ;save on stack B1A8 60 RTS ;and exit. .S1A9 ;OSFSC B1A9 20 18 B7 JSR S718 ;filing system call monitor B1AC C9 00 CMP #&00 ;if A=0 then *OPT B1AE F0 03 BEQ S1B3 B1B0 4C 90 B2 JMP S290 .S1B3 ;*OPT B1B3 E0 01 CPX #&01 B1B5 F0 0E BEQ S1C5 B1B7 B0 10 BCS S1C9 B1B9 A9 00 LDA #&00 ;*OPT 0 B1BB A2 06 LDX #&06 ;Clear options 6..9 .S1BD B1BD 9D 7E 10 STA &107E,X B1C0 E8 INX B1C1 E0 0A CPX #&0A B1C3 D0 F8 BNE S1BD ;then fall through: .S1C5 B1C5 8C 0E 10 STY &100E ;*OPT 1 monitor B1C8 60 RTS .S1C9 B1C9 E0 04 CPX #&04 ;bad options 2 or 3 B1CB 90 25 BCC S1F2 B1CD D0 33 BNE S202 B1CF 20 06 92 JSR Q206 ;copy memory absolute *OPT 4 B1D2 EQUW &07,&10 ;set boot option B1D4 EQUW &C7,&00 ;copy default dir/vol/drive B1D6 EQUB &03 ;to immediate path B1D7 20 00 9B JSR QB00 ;softmount and read catalogue B1DA AD 06 0F LDA &0F06 ;clear boot option bits B1DD 29 CF AND #&CF ;11001111 B1DF 8D 06 0F STA &0F06 B1E2 98 TYA ;replace them with bits from Y B1E3 29 03 AND #&03 ;00000011 B1E5 0A ASL A B1E6 0A ASL A B1E7 0A ASL A B1E8 0A ASL A B1E9 0D 06 0F ORA &0F06 B1EC 8D 06 0F STA &0F06 B1EF 4C 03 9B JMP QB03 ;write catalogue and exit .S1F2 B1F2 20 18 90 JSR Q018 ;Print "Bad option" B1F5 EQUB &0A B1F6 EQUB &CB B1F7 EQUS "Bad option" B201 EQUB &00 .S202 B202 E0 05 CPX #&05 ;*OPT 5 display options B204 D0 7E BNE S284 B206 AD 0E 10 LDA &100E ;get option 1 B209 20 18 90 JSR Q018 ;print "*opt 1 monitor = "+n B20C EQUB &82 B20D EQUS "*opt 1 monitor = " B21E EQUB &00 B21F AD 84 10 LDA &1084 ;get option 6 B222 20 18 90 JSR Q018 ;print "*opt 6 density = "+n B225 EQUB &82 B226 EQUS "*opt 6 density = " B237 EQUB &00 B238 AD 85 10 LDA &1085 ;get option 7 B23B 20 18 90 JSR Q018 ;print "*opt 7 volumes = "+n B23E EQUB &82 B23F EQUS "*opt 7 volumes = " B250 EQUB &00 B251 AD 86 10 LDA &1086 ;get option 8 B254 20 18 90 JSR Q018 ;print "*opt 8 tracks = "+n B257 EQUB &82 B258 EQUS "*opt 8 tracks = " B269 EQUB &00 B26A AD 87 10 LDA &1087 ;get option 9 B26D 20 18 90 JSR Q018 ;print "*opt 9 saverom = "+n B270 EQUB &82 B271 EQUS "*opt 9 saverom = " B282 EQUB &00 B283 60 RTS .S284 B284 E0 0A CPX #&0A ;reject options >=10 B286 90 03 BCC S28B B288 4C F2 B1 JMP S1F2 .S28B B28B 98 TYA ;*OPT 6..9 B28C 9D 7E 10 STA &107E,X ;set EDOS options B28F 60 RTS .S290 B290 C9 02 CMP #&02 B292 F0 1E BEQ S2B2 B294 B0 0D BCS S2A3 B296 20 03 98 JSR Q803 ;OSFSC 1 B299 20 0C B4 JSR S40C ;Test EOF (don't set warning flag) B29C A2 00 LDX #&00 B29E 90 02 BCC S2A2 B2A0 A2 FF LDX #&FF ;c=1, X=&FF if EOF .S2A2 B2A2 60 RTS .S2A3 B2A3 C9 04 CMP #&04 B2A5 F0 0B BEQ S2B2 B2A7 B0 6A BCS S313 B2A9 20 33 B3 JSR S333 ;OSFSC 3. Initialise string B2AC 20 00 81 JSR P100 ;Unknown OSCLI offered to current FS. B2AF 90 04 BCC S2B5 ;If not built in to EDOS try to *RUN it. B2B1 60 RTS .S2B2 ;OSFSC 2 & 4. *RUN, */ B2B2 20 33 B3 JSR S333 ;String init .S2B5 B2B5 20 12 93 JSR Q312 ;expand path at XY, get file spec B2B8 20 00 9B JSR QB00 ;softmount & load catalogue B2BB 20 09 A5 JSR R509 ;find file B2BE 90 21 BCC S2E1 ;if not found B2C0 20 06 92 JSR Q206 ;replace path with library's B2C3 EQUW &0A,&10 ;FROM address &101A B2C5 EQUW &C7,&00 ;TO address &00C7 = Immediate dir'y B2C7 EQUB &03 ;count B2C8 20 00 9B JSR QB00 ;load library catalogue B2CB 20 09 A5 JSR R509 ;find file B2CE 90 11 BCC S2E1 ;if not found: B2D0 20 18 90 JSR Q018 ;Print "Bad Command" error B2D3 EQUB &0A B2D4 EQUB &FE B2D5 EQUS "Bad command" B2E0 EQUB &00 .S2E1 B2E1 98 TYA ;else store pointer B2E2 18 CLC ;to arguments B2E3 65 F2 ADC &F2 B2E5 8D 82 10 STA &1082 B2E8 A5 F3 LDA &F3 B2EA 69 00 ADC #&00 B2EC 8D 83 10 STA &1083 B2EF 20 03 A6 JSR R603 ;unpack fields from catalogue B2F2 20 3D B3 JSR S33D ;load file B2F5 AD 4D 10 LDA &104D ;if execution address B2F8 49 03 EOR #&03 ;00000011;has high bits clear B2FA 2D 7A 02 AND &027A ;and Tube is present B2FD D0 0B BNE S30A ;then call address over Tube B2FF 20 06 92 JSR Q206 ;else copy exec to zero page B302 EQUW &4B,&10 ;FROM address &104B B304 EQUW &BE,&00 ;TO address &00BE B306 EQUB &02 ;count B307 6C BE 00 JMP (&00BE) ;and call it (can save 8 bytes here) .S30A B30A A2 4B LDX #&4B ;Do a *GO to the exec address B30C A0 10 LDY #&10 B30E A9 04 LDA #&04 B310 4C 06 A0 JMP R006 .S313 B313 C9 06 CMP #&06 B315 F0 08 BEQ S31F B317 B0 0B BCS S324 B319 20 33 B3 JSR S333 ;OSFSC 5 *CAT. string init. B31C 4C 03 86 JMP P603 ;*CAT .S31F B31F A9 77 LDA #&77 ;OSFSC 6 FS about to change. B321 4C F4 FF JMP &FFF4 ;close *SPOOL and *EXEC files .S324 B324 C9 08 CMP #&08 B326 F0 07 BEQ S32F B328 B0 08 BCS S332 B32A A2 11 LDX #&11 ;OSFSC 7 Return semi-incl. B32C A0 16 LDY #&16 ;range of file handles B32E 60 RTS .S32F B32F 4E 0F 10 LSR &100F ;OSFSC 8 *command issued .S332 B332 60 RTS ;clear *ENABLE status .S333 ;String init B333 86 F2 STX &F2 B335 84 F3 STY &F3 ;store XY in GS pointer B337 A0 00 LDY #&00 B339 18 CLC B33A 4C C2 FF JMP &FFC2 ;call GSINIT with C=0 .S33D ;Load file. B33D 20 70 B3 JSR S370 ;copy addr to O7F .S340 B340 A9 13 LDA #&13 ;store read command in block .S342 B342 8D 16 10 STA &1016 B345 AE 51 10 LDX &1051 ;absolute start sector in XY B348 AC 52 10 LDY &1052 B34B AD 53 10 LDA &1053 ;sector length (mod 256) in A B34E 4C 06 9B JMP QB06 ;do LBA transfer and exit .S351 ;Copy 32 bit to 18 bit addr B351 48 PHA B352 20 09 92 JSR Q209 ;Copy memory B355 EQUW &00,&10 ;from 1000,X B357 EQUW &00,&10 ;to 1000,Y B359 EQUB &02,&21 B35B BD 02 10 LDA &1002,X ;AND high bytes of source B35E 3D 03 10 AND &1003,X ;together B361 C9 FF CMP #&FF B363 F0 04 BEQ S369 B365 A9 00 LDA #&00 ;If not clear high bits B367 F0 02 BEQ S36B .S369 B369 A9 03 LDA #&03 ;else set high bits .S36B B36B 99 02 10 STA &1002,Y ;and store with address B36E 68 PLA B36F 60 RTS .S370 B370 A2 48 LDX #&48 ;Copy load address B372 A0 11 LDY #&11 ;to OSWORD &7F block: .S374 B374 48 PHA ;Copy 18 bit to 32 bit address B375 20 09 92 JSR Q209 ;from 1000,X to 1000,Y B378 EQUW &00,&10 B37A EQUW &00,&10 B37C EQUB &02,&21 B37E BD 02 10 LDA &1002,X ;are b17 and b16 both set? B381 29 03 AND #&03 B383 C9 03 CMP #&03 B385 F0 04 BEQ S38B B387 A9 00 LDA #&00 ;If not high bytes = 0000 B389 F0 02 BEQ S38D .S38B B38B A9 FF LDA #&FF ;else high bytes = FFFF .S38D B38D 99 02 10 STA &1002,Y B390 99 03 10 STA &1003,Y B393 68 PLA B394 60 RTS ;unused space from &B395 ;unused space ends at &B400 ;EDOS API, part 2: random access I/O B400 4C 0F B4 JMP S40F ;OSBGET B403 4C 1D B4 JMP S41D ;OSBPUT B406 4C 2B B4 JMP S42B ;OSGBPB .S409 B409 4C 71 B5 JMP S571 ;Copy user's OSFILE/GBPB block .S40C B40C 4C 82 B5 JMP S582 ;Test EOF (warned flag not set) .S40F ;OSBGET B40F 20 00 92 JSR Q200 ;save AXY B412 20 0C B7 JSR S70C ;call monitor B415 98 TYA B416 AA TAX B417 20 03 98 JSR Q803 ;init for file handle B41A 4C 24 B6 JMP S624 ;get byte and exit .S41D ;OSBPUT B41D 20 00 92 JSR Q200 ;save AXY B420 20 0F B7 JSR S70F ;call monitor B423 98 TYA B424 AA TAX B425 20 AF B6 JSR S6AF ;check file is writeable B428 4C 4E B6 JMP S64E ;put byte and exit .S42B ;OSGBPB B42B 20 00 92 JSR Q200 ;save AXY B42E 20 12 B7 JSR S712 ;call OSGBPB monitor B431 20 09 B4 JSR S409 ;copy user's OSFILE/GBPB block B434 AA TAX ;validate call number B435 CA DEX B436 E0 08 CPX #&08 B438 90 01 BCC S43B ;if invalid exit with C=1 B43A 60 RTS ;how convenient .S43B B43B BD 69 B5 LDA &B569,X B43E 85 CD STA &CD B440 20 06 92 JSR Q206 ;copy memory absolute B443 EQUW &71,&10 ;FROM address &1071 B445 EQUW &BC,&00 ;TO address &00BC B447 EQUB &02 ;count B448 A9 80 LDA #&80 ;set A b7 = 1, b6..0 = 0 B44A E0 02 CPX #&02 ;if call number = 1 or 2 B44C B0 02 BCS S450 ;(set PTR and write, write) B44E A9 00 LDA #&00 ;then b7 = 0 write mem to disc .S450 B450 8D 3A 10 STA &103A ;tube flag b7=read b6=0 host tx B453 AD 73 10 LDA &1073 ;test high word of address B456 2D 74 10 AND &1074 B459 49 FF EOR #&FF ;A=0 if in I/O space, invert B45B 2D 7A 02 AND &027A ;A=0 if Tube absent too B45E F0 0D BEQ S46D ;in which case skip forward B460 AD 3A 10 LDA &103A ;else a Tube transfer. B463 18 CLC ;set A=0 if writing to disc, B464 2A ROL A ;A=1 if reading from disc B465 2A ROL A B466 A2 71 LDX #&71 ;point XY to the full address B468 A0 10 LDY #&10 B46A 20 06 A0 JSR R006 ;open Tube channel 3. .S46D ;now sample microcode B46D 46 CD LSR &CD ;to select actions: B46F 90 72 BCC S4E3 ;.....1 Get title / get cat B471 20 06 92 JSR Q206 ;copy default to immediate path B474 EQUW &07,&10 ;FROM address &1007 B476 EQUW &C7,&00 ;TO address &00C7 = Immediate dir'y B478 EQUB &03 ;count B479 20 00 9B JSR QB00 ;softmount and load catalogue. B47C 46 CD LSR &CD B47E 90 27 BCC S4A7 B480 A0 00 LDY #&00 ;....11 Get title B482 A9 0C LDA #&0C ;clear offset; length byte = 12 .S484 B484 20 E5 B6 JSR S6E5 ;send byte in A to user B487 C8 INY ;send first 8 bytes of sector 0 B488 B9 FF 0D LDA &0DFF,Y ;(with Y = 1 to 8) B48B C0 09 CPY #&09 B48D D0 F5 BNE S484 .S48F B48F B9 F7 0E LDA &0EF7,Y ;send first 4 bytes of sector 1 B492 20 E5 B6 JSR S6E5 ;(with Y = 9 to 12) B495 C8 INY B496 C0 0D CPY #&0D B498 D0 F5 BNE S48F B49A AD 06 0F LDA &0F06 ;get boot option B49D 4A LSR A ;place in bits 3..0 B49E 4A LSR A B49F 4A LSR A B4A0 4A LSR A B4A1 20 E5 B6 JSR S6E5 ;send it B4A4 4C 60 B5 JMP S560 ;close Tube channel and exit. .S4A7 B4A7 AD 04 0F LDA &0F04 ;....01 Get catalogue B4AA 8D 70 10 STA &1070 ;get catalogue cycle number B4AD AD 05 0F LDA &0F05 ;store in file handle byte of B4B0 38 SEC ;OSGBPB block. B4B1 ED 79 10 SBC &1079 ;files * 8 - OSGBPB pointer B4B4 85 CC STA &CC ;=starting catalogue pointer .S4B6 B4B6 20 06 A5 JSR R506 ;select next file in catalogue B4B9 B0 1C BCS S4D7 ;if no more files then finish B4BB 20 1E A5 JSR R51E ;else compare directory letters B4BE D0 F6 BNE S4B6 ;if unequal skip to next file B4C0 20 03 A6 JSR R603 ;else unpack fields from cat B4C3 A0 00 LDY #&00 ;clear offset B4C5 A9 07 LDA #&07 ;set length byte = 7 .S4C7 B4C7 20 E5 B6 JSR S6E5 ;send byte in A to user B4CA B9 40 10 LDA &1040,Y ;send 7 bytes of filename proper B4CD C8 INY ;(with Y = 1 to 7) B4CE C0 08 CPY #&08 B4D0 D0 F5 BNE S4C7 B4D2 20 C8 B6 JSR S6C8 ;decrement number of entries B4D5 D0 DF BNE S4B6 ;remaining to be transferred .S4D7 ;if more then loop B4D7 AD 05 0F LDA &0F05 ;else files * 8 - final cat ptr B4DA 38 SEC ;=new OSGBPB pointer B4DB E5 CC SBC &CC ;store in OSGBPB block & finish. B4DD 8D 79 10 STA &1079 B4E0 4C 4C B5 JMP S54C .S4E3 B4E3 46 CD LSR &CD ;.....0 B4E5 90 1D BCC S504 B4E7 A0 00 LDY #&00 ;....10 Get default/get library B4E9 46 CD LSR &CD ;Y=0 to point to default path B4EB 90 02 BCC S4EF B4ED A0 03 LDY #&03 ;...110 Get library. Y=3 .S4EF ;...x10 Get default/get library B4EF 20 E3 B6 JSR S6E3 ;send binary 1 B4F2 B9 09 10 LDA &1009,Y ;get drive number B4F5 20 E5 B6 JSR S6E5 ;send it B4F8 20 E3 B6 JSR S6E3 ;send binary 1 B4FB B9 07 10 LDA &1007,Y ;get directory letter B4FE 20 E5 B6 JSR S6E5 ;send it B501 4C 60 B5 JMP S560 ;close Tube channel and exit .S504 B504 AE 70 10 LDX &1070 ;....00 Read/write. get file handle B507 46 CD LSR &CD B509 90 03 BCC S50E B50B 20 AF B6 JSR S6AF ;...100 Write. check writeable .S50E B50E 46 CD LSR &CD B510 90 03 BCC S515 B512 20 03 98 JSR Q803 ;..1x00 Read. check file is open .S515 B515 46 CD LSR &CD ;..xx00 Read/write B517 90 09 BCC S522 B519 20 09 92 JSR Q209 ;.1xx00 Set PTR B51C EQUW &79,&10 ;copy FROM OSGBPB block, &1079 B51E EQUW &9D,&10 ;TO PTR, &109D,Y B520 EQUB &03,&01 ;3 bytes, Y indexed TO .S522 B522 20 D6 B6 JSR S6D6 ;.xxx00 Read/write. compare L=0 B525 F0 1C BEQ S543 ;if no bytes to transfer, finish B527 46 CD LSR &CD B529 90 0D BCC S538 .S52B B52B 20 E5 B6 JSR S6E5 ;1xxx00 OSGBPB write loop B52E 20 4B B6 JSR S64B ;get from memory, put to file B531 20 C8 B6 JSR S6C8 ;decrement bytes to transfer B534 D0 F5 BNE S52B ;repeat if more bytes B536 F0 0B BEQ S543 .S538 B538 20 21 B6 JSR S621 ;0xxx00 GBPB read loop B53B 20 E5 B6 JSR S6E5 ;get from file, put to memory B53E 20 C8 B6 JSR S6C8 ;decrement bytes to transfer B541 D0 F5 BNE S538 ;repeat if more bytes .S543 ;Read/write finished B543 20 09 92 JSR Q209 ;copy PTR to OSGBPB block B546 EQUW &9D,&10 ;FROM PTR, &109D,Y B548 EQUW &79,&10 ;TO OSGBPB block, &1079 B54A EQUB &03,&10 .S54C B54C 20 06 92 JSR Q206 ;copy address to OSGBPB block B54F EQUW &BC,&00 ;FROM address &00BC B551 EQUW &71,&10 ;TO address &1071 B553 EQUB &02 ;count B554 A0 00 LDY #&00 .S556 B556 B9 70 10 LDA &1070,Y ;copy OSGBPB block to user's block B559 91 BE STA (&BE),Y ;from &1070 to (&BE), 13 bytes B55B C8 INY B55C C0 0D CPY #&0D B55E D0 F6 BNE S556 .S560 B560 2C 3A 10 BIT &103A ;test Tube channel flag B563 50 03 BVC S568 ;if b6 = 1, Tube channel in use B565 20 0C A0 JSR R00C ;then close Tube channel .S568 B568 60 RTS ;exit. B569 EQUB &34,&24,&18,&08 ;OSGBPB microcode table 1..8 B56D EQUB &03,&02,&06,&01 .S571 ;Copy user's OSFILE/GBPB block B571 48 PHA ;to workspace at &1070..81 B572 86 BE STX &BE B574 84 BF STY &BF B576 A0 11 LDY #&11 .S578 B578 B1 BE LDA (&BE),Y B57A 99 70 10 STA &1070,Y B57D 88 DEY B57E 10 F8 BPL S578 B580 68 PLA B581 60 RTS .S582 ;Test EOF (warned flag not set) B582 B9 9D 10 LDA &109D,Y .S585 B585 38 SEC ;compare PTR - EXT, channel in Y B586 F9 9A 10 SBC &109A,Y ;return C=1 if EOF B589 B9 9E 10 LDA &109E,Y B58C F9 9B 10 SBC &109B,Y B58F B9 9F 10 LDA &109F,Y B592 F9 9C 10 SBC &109C,Y B595 60 RTS .S596 B596 B9 88 10 LDA &1088,Y ;Increment PTR. B599 29 FE AND #&FE ;11111110;invoked by BGET/BPUT/GBPB. B59B 99 88 10 STA &1088,Y ;note AXY not saved! B59E 18 CLC ;clear warning-given flag B59F B9 94 10 LDA &1094,Y ;get start sector of file B5A2 79 9E 10 ADC &109E,Y ;add middle & high bytes PTR B5A5 85 BA STA &BA ;store &BA,&BB: target page B5A7 B9 95 10 LDA &1095,Y B5AA 79 9F 10 ADC &109F,Y B5AD 85 BB STA &BB B5AF B9 89 10 LDA &1089,Y ;is page empty? B5B2 F0 11 BEQ S5C5 ;if so go to set target B5B4 A5 BA LDA &BA ;else get target page B5B6 D9 96 10 CMP &1096,Y ;compare with current page B5B9 D0 07 BNE S5C2 B5BB A5 BB LDA &BB B5BD D9 97 10 CMP &1097,Y B5C0 F0 24 BEQ S5E6 ;if same don't touch page/flag .S5C2 B5C2 20 0F 98 JSR Q80F ;if different flush page .S5C5 B5C5 A5 BA LDA &BA ;set target as current page B5C7 99 96 10 STA &1096,Y B5CA A5 BB LDA &BB B5CC 99 97 10 STA &1097,Y B5CF 38 SEC B5D0 A9 00 LDA #&00 ;supposing LSB of PTR = 0, B5D2 20 85 B5 JSR S585 ;would we be at end-of-file? B5D5 B0 0C BCS S5E3 B5D7 A9 13 LDA #&13 ;if not read current page B5D9 20 12 98 JSR Q812 ;Transfer file buffer to LBA B5DC A9 01 LDA #&01 ;mark as clean B5DE 99 89 10 STA &1089,Y B5E1 D0 03 BNE S5E6 .S5E3 B5E3 20 15 B6 JSR S615 ;else definite EOF, clear page .S5E6 B5E6 B9 9D 10 LDA &109D,Y ;get PTR low byte B5E9 48 PHA ;push it B5EA 20 0C B4 JSR S40C ;are we really at EOF? B5ED 08 PHP ;remember for later B5EE 18 CLC B5EF B9 9D 10 LDA &109D,Y ;increment PTR nevertheless B5F2 69 01 ADC #&01 B5F4 99 9D 10 STA &109D,Y B5F7 B9 9E 10 LDA &109E,Y B5FA 69 00 ADC #&00 B5FC 99 9E 10 STA &109E,Y B5FF B9 9F 10 LDA &109F,Y B602 69 00 ADC #&00 B604 99 9F 10 STA &109F,Y B607 28 PLP B608 90 09 BCC S613 ;if we weren't at EOF then exit B60A 20 09 92 JSR Q209 ;else extend file B60D EQUW &9D,&10 ;by copying PTR to EXT B60F EQUW &9A,&10 ;(we're still at EOF) B611 EQUB &03,&11 .S613 B613 68 PLA ;return A=offset of byte in buf B614 60 RTS .S615 ;Clear page &CA,CB points to B615 20 00 92 JSR Q200 ;Save AXY B618 A9 00 LDA #&00 B61A A8 TAY .S61B B61B 91 CA STA (&CA),Y B61D C8 INY B61E D0 FB BNE S61B B620 60 RTS .S621 ;Get byte B621 20 00 92 JSR Q200 ;Save AXY .S624 B624 20 0C B4 JSR S40C ;test for end-of-file B627 B0 0C BCS S635 ;if so set warned and exit C=1 B629 20 96 B5 JSR S596 ;else increment PTR B62C A8 TAY B62D BA TSX B62E B1 CA LDA (&CA),Y ;get byte that PTR had PTd to B630 9D 05 01 STA &0105,X ;return it in A B633 18 CLC ;exit C=0 B634 60 RTS .S635 B635 B9 88 10 LDA &1088,Y ;we've read past end-of-file. B638 6A ROR A ;test warning-given flag B639 B0 07 BCS S642 ;if set give EOF error B63B 38 SEC ;else set warning-given B63C 2A ROL A ;flag and return C=1 B63D 99 88 10 STA &1088,Y B640 38 SEC B641 60 RTS .S642 B642 20 18 90 JSR Q018 ;raise "EOF" error B645 EQUB &0A ;error message, LF after B646 EQUB &DF ;error number &DF B647 EQUS "EOF" ;message string "EOF" B64A EQUB &00 ;terminator byte .S64B ;Put byte to file B64B 20 00 92 JSR Q200 ;save AXY .S64E B64E 38 SEC B64F B9 9E 10 LDA &109E,Y ;compare PTR high bytes B652 F9 98 10 SBC &1098,Y ; - allocated length B655 B9 9F 10 LDA &109F,Y B658 F9 99 10 SBC &1099,Y B65B 90 40 BCC S69D ;if PTR=&80 BA07 B0 04 BCS SA0D ;then return BA09 C9 7D CMP #&7D ;if less than &7D then return BA0B B0 01 BCS SA0E ;(C=0; passed to lower ROMs) .SA0D BA0D 60 RTS .SA0E BA0E 58 CLI BA0F C9 7F CMP #&7F ;if not &7F BA11 F0 03 BEQ SA16 BA13 4C FC BA JMP SAFC ;then jump to RTS .SA16 BA16 A0 06 LDY #&06 ;else &7F disc op. BA18 B1 F0 LDA (&F0),Y ;get command byte BA1A 29 3F AND #&3F ;00111111 mask it BA1C A2 00 LDX #&00 ;search for it in table .SA1E BA1E DD FD BA CMP &BAFD,X ;OSWORD &7F 8271 command lookup table BA21 F0 0E BEQ SA31 ;if found carry on BA23 48 PHA ;else go to next row BA24 8A TXA ;8 bytes in each row BA25 18 CLC BA26 69 08 ADC #&08 BA28 AA TAX BA29 68 PLA BA2A E0 70 CPX #&70 ;have we reached end of table? BA2C D0 F0 BNE SA1E ;if so unrecognised command BA2E 4C FC BA JMP SAFC ;so quit C=1 (hook) .SA31 BA31 BD FE BA LDA &BAFE,X ;get microcode BA34 29 10 AND #&10 ;if b4 set BA36 F0 13 BEQ SA4B BA38 A0 07 LDY #&07 ;then get first 8271 parameter BA3A B1 F0 LDA (&F0),Y ;(special register number) BA3C C9 05 CMP #&05 ;if none of these values BA3E F0 0B BEQ SA4B ;&05 = WD2791 sector register BA40 C9 12 CMP #&12 ;&12 = unit 0 current track BA42 F0 07 BEQ SA4B BA44 C9 1A CMP #&1A ;&1A = unit 1 current track BA46 F0 03 BEQ SA4B ;then quit. BA48 4C FC BA JMP SAFC .SA4B BA4B 20 00 B7 JSR S700 ;call OSWORD monitor BA4E A0 00 LDY #&00 ;get O7F drive number BA50 B1 F0 LDA (&F0),Y ;A = OSWORD X register value BA52 10 01 BPL SA55 ;if top bit clear, branch BA54 C8 INY ;else, copy it to workspace. .SA55 BA55 B1 F0 LDA (&F0),Y ;copy rest of block to worksp. BA57 99 10 10 STA &1010,Y ;OSWORD &7F block BA5A C8 INY BA5B C0 0C CPY #&0C BA5D D0 F6 BNE SA55 BA5F 20 06 92 JSR Q206 ;copy BA62 EQUW &F0,&00 ;FROM user O7F block address &00F0 BA64 EQUW &1C,&10 ;TO workspace at &101C BA66 EQUB &02 ;count BA67 EA NOP BA68 EA NOP BA69 EA NOP BA6A BD FE BA LDA &BAFE,X ;get microcode BA6D 29 60 AND #&60 ;01100000 ;if b5 and b6 clear BA6F F0 1A BEQ SA8B ;then start O7F command BA71 AD 17 10 LDA &1017 ;else get track number BA74 20 40 BE JSR SE40 ;test if drive double-stepped BA77 90 01 BCC SA7A ;if so BA79 0A ASL A ;then double track number. .SA7A BA7A 20 CF BB JSR SBCF ;seek that track BA7D C9 FF CMP #&FF ;if Escape pressed during seek BA7F D0 03 BNE SA84 BA81 4C 9A BB JMP SB9A ;save status and ack. error. .SA84 BA84 29 99 AND #&99 ;if { NotReady RecordNotFound BA86 F0 03 BEQ SA8B ;CRCError Busy } any are set BA88 4C 6D BB JMP SB6D ;then finish O7F, else: .SA8B BA8B BD FE BA LDA &BAFE,X ;Start O7F command. BA8E 29 20 AND #&20 ;00100000 ;test b5 of microcode BA90 F0 08 BEQ SA9A ;if set BA92 20 43 BC JSR SC43 ;prepare for read/write BA95 D0 03 BNE SA9A ;if no. sectors to transfer =0 BA97 4C 6D BB JMP SB6D ;then finish O7F, else: .SA9A BA9A 20 06 92 JSR Q206 ;Save original transfer address in z.p. BA9D EQUW &11,&10 ;FROM address &1011 BA9F EQUW &A2,&00 ;TO address &00A2 BAA1 EQUB &02 ;count BAA2 A9 00 LDA #&00 BAA4 8D 65 0D STA &0D65 BAA7 AD 13 10 LDA &1013 ;part of OSWORD &7F block BAAA 2D 14 10 AND &1014 ;test high bits of address BAAD 49 FF EOR #&FF ;invert - if any are clear BAAF 2D 7A 02 AND &027A ;and Tube is present, then: BAB2 F0 1E BEQ SAD2 BAB4 BD FE BA LDA &BAFE,X ;get microcode BAB7 29 03 AND #&03 ;00000011 ;test two low bits BAB9 F0 06 BEQ SAC1 ;if either one is set BABB 20 5B BC JSR SC5B ;open channel 3 for data BABE 8D 64 0D STA &0D64 ;set Tube flag >0 .SAC1 BAC1 BC 01 BB LDY &BB01,X ;get offset of NMI code BAC4 F0 28 BEQ SAEE ;if zero there's no NMI handler BAC6 20 09 92 JSR Q209 ;Copy NMI handler BAC9 EQUW &9D,&BE ;from &BE9D BACB EQUW &00,&0D ;to &0D00 BACD EQUB &20,&10 ;32 bytes, Y indexed source BACF 4C EE BA JMP SAEE ;get command and execute .SAD2 BAD2 BC FF BA LDY &BAFF,X ;an I/O transfer. Get NMI BAD5 F0 17 BEQ SAEE ;offset, no handler if zero. BAD7 20 09 92 JSR Q209 ;Copy NMI handler BADA EQUW &9D,&BE ;from &BEA4 BADC EQUW &00,&0D ;to &0D00 BADE EQUB &20,&10 ;&20 bytes, from Y BAE0 BC 00 BB LDY &BB00,X ;does NMI take an address? BAE3 F0 09 BEQ SAEE ;0=no address / fixed address BAE5 20 09 92 JSR Q209 ;if so copy bytes BAE8 EQUW &11,&10 ;from O7F address low at &1011 BAEA EQUW &FF,&0C ;to NMI handler at &0CFF(the address of an LDA/STA.) BAEC EQUB &02,&01 ;2 bytes, to Y .SAEE BAEE BD 02 BB LDA &BB02,X ;get 2793 command BAF1 49 FF EOR #&FF ;invert for 2791 BAF3 A8 TAY BAF4 BD 04 BB LDA &BB04,X ;get jump-table address BAF7 48 PHA ;A -> (SP) = MSB BAF8 BD 03 BB LDA &BB03,X ;for command routine (minus 1 for RTS) BAFB 48 PHA ;A -> (SP) = LSB .SAFC BAFC 60 RTS ;and jump to the routine. ;The microcode byte at &BAFE,X is made up as follows: ;&01 ......01 PIO write to disc, source address required ;&02 ......10 PIO read from disc, target address required ;&10 ...1.... Read/write 8271 special registers ;&40 .1...... Motor operation (seek required) ;&60 .11..... Sector operation (scans or reads sector IDs) ;&80 1....... Not used; set if operation accesses or overwrites ; sector data area (i.e. read/write sectors, and format) BAFD EQUB &0B ;&0B Write data = 8271 command BAFE EQUB &E1 ;microcode byte BAFF EQUB &01 ;1 + offset of I/O ISR BB00 EQUB &04 ;1 + offset of address within ISR BB01 EQUB &16 ;1 + offset of Tube ISR BB02 EQUB &A0 ;equivalent 2793 command BB03 EQUW &65,&BC ;&BC65+1=&BC66 = Write data command BB05 EQUB &0F ;&0F Write deleted data BB06 EQUB &E1,&01,&04,&16,&A1 BB0B EQUW &65,&BC ;&BC65+1=&BC66 = Write data command BB0D EQUB &13 ;&13 Read data BB0E EQUB &E2,&23,&09,&38,&80 BB13 EQUW &69,&BC ;&BC69+1=&BC6A = Read data command BB15 EQUB &17 ;&17 Read data & deleted data BB16 EQUB &E2,&23,&09,&38,&80 BB1B EQUW &65,&BC ;&BC65+1=&BC66 = Write data command BB1D EQUB &1B ;&1B Read ID BB1E EQUB &62,&45,&0D,&5E,&C4 BB23 EQUW &AD,&BC ;&BCAD+1=&BCAE = Read ID command BB25 EQUB &1F ;&1F Verify data BB26 EQUB &E0,&6F,&00,&6F,&80 BB2B EQUW &65,&BC ;&BC65+1=&BC66 = Write data command BB2D EQUB &23 ;&23 Format track BB2E EQUB &C1,&73,&00,&73,&F4 BB33 EQUW &CF,&BC ;&BCCF+1=&BCD0 = Format command BB35 EQUB &24 ;&24 (Write track) BB36 EQUB &41,&01,&04,&16,&F4 BB3B EQUW &A5,&BD ;&BDA5+1=&BDA6 = Do disc op and finish O7F BB3D EQUB &25 ;&25 (Read track) BB3E EQUB &42,&23,&09,&38,&E4 BB43 EQUW &A5,&BD ;&BDA5+1=&BDA6 = Do disc op and finish O7F BB45 EQUB &29 ;&29 Seek BB46 EQUB &40,&00,&00,&00,&00 BB4B EQUW &BE,&BC ;&BCBE+1=&BCBF = Seek command BB4D EQUB &2C ;&2C Read drive status BB4E EQUB &00,&00,&00,&00,&00 BB53 EQUW &AB,&BD ;&BDAB+1=&BDAC = Read drive status BB55 EQUB &36 ;&36 Force interrupt BB56 EQUB &00,&00,&00,&00,&D0 BB5B EQUW &4E,&BE ;&BE4E+1=&BE4F = send Force Interrupt BB5D EQUB &3A ;&3A Write special registers BB5E EQUB &10,&00,&00,&00,&00 BB63 EQUW &E9,&BD ;&BDE9+1=&BDEA = Write special registers BB65 EQUB &3D ;&3D Read special registers BB66 EQUB &10,&00,&00,&00,&00 BB6B EQUW &11,&BE ;&BE11+1=&BE12 = Read special registers .SB6D BB6D C9 FF CMP #&FF ;Finish OSWORD &7F. BB6F F0 15 BEQ SB86 ;Bogus status? else 2791 result BB71 29 7C AND #&7C ;01111100 ;mask off { NotReady Track BB73 F0 11 BEQ SB86 ;Index } if other bits then BB75 A2 05 LDX #&05 ;error. search in table .SB77 BB77 DD C3 BB CMP &BBC3,X BB7A F0 07 BEQ SB83 ;found. BB7C CA DEX BB7D D0 F8 BNE SB77 BB7F 09 01 ORA #&01 ;00000001 ;not found. BB81 D0 03 BNE SB86 .SB83 BB83 BD C9 BB LDA &BBC9,X ;if found get 8271 equivalent .SB86 BB86 48 PHA BB87 AD 64 0D LDA &0D64 ;was it a Tube transfer? BB8A F0 03 BEQ SB8F ;if so BB8C 20 0C A0 JSR R00C ;close Tube channel 3. .SB8F BB8F A2 0B LDX #&0B ;issue Rom Call &0B, BB91 AC 61 0D LDY &0D61 ;release NMI. give previous BB94 A9 8F LDA #&8F ;owner ID as parameter BB96 20 F4 FF JSR &FFF4 BB99 68 PLA .SB9A BB9A 20 06 92 JSR Q206 ;copy user's O7F block address to zero page BB9D EQUW &1C,&10 ;FROM address &101C BB9F EQUW &A0,&00 ;TO address &00A0 BBA1 EQUB &02 ;count BBA2 48 PHA BBA3 A0 05 LDY #&05 ;get no. parameters to command BBA5 B1 A0 LDA (&A0),Y BBA7 18 CLC ;point to byte after parameters BBA8 69 07 ADC #&07 BBAA A8 TAY BBAB 68 PLA ;store O7F result there BBAC 91 A0 STA (&A0),Y BBAE EA NOP BBAF EA NOP BBB0 EA NOP BBB1 C9 FF CMP #&FF ;if bogus status returned BBB3 D0 0C BNE SBC1 BBB5 20 18 90 JSR Q018 ;give Escape error BBB8 EQUB &0A ;linefeed BBB9 EQUB &11 BBBA EQUS "Escape" BBC0 EQUB &00 .SBC1 BBC1 38 SEC ;else end OSWORD & break ROM BBC2 60 RTS ;call chain. BBC3 EQUB &04,&08,&10 ;2793 error table 0..5 BBC6 EQUB &18,&20,&40 BBC9 EQUB &0A,&0E,&18 ;8271 equivalent errors BBCC EQUB &0C,&20,&12 .SBCF ;Seek logical track BBCF 20 00 92 JSR Q200 ;save AXY BBD2 48 PHA BBD3 A2 0C LDX #&0C ;X = reason code = claim NMI BBD5 A0 FF LDY #&FF ;Y = parameter passed = &FF ;Y preset to &FF so that Y=&FF ;on exit indicates that no ROM ;claims previous ownership of ;the NMI resource. BBD7 A9 8F LDA #&8F ;A = call No. BBD9 20 F4 FF JSR &FFF4 ;call OSBYTE &8F = Paged ROM Service Request BBDC 8C 61 0D STY &0D61 ;Y = previous owner BBDF 20 06 92 JSR Q206 ;copy memory absolute BBE2 EQUW &66,&BE ;from disc op code at &BE66 BBE4 EQUW &20,&0D ;to &0D20 BBE6 EQUB &38 ;No. of bytes = &38, &0D20..57 BBE7 A9 40 LDA #&40 ;= RTI instruction BBE9 8D 00 0D STA &0D00 ;store it at NMI entry point BBEC A9 10 LDA #&10 ;set retry counter = 16 BBEE 8D 62 0D STA &0D62 BBF1 A9 00 LDA #&00 BBF3 8D 64 0D STA &0D64 ;set Tube flag = 0 BBF6 AD 10 10 LDA &1010 ;A = OSWORD &7F block = drive BBF9 29 03 AND #&03 ;00000011 mask bits 2-7, bits 0-1 = drive number BBFB A8 TAY ;A -> Y = drive number BBFC BE 20 10 LDX &1020,Y ;get DEN for drive in X, 0FF0,X Density of drives 0..3 0A=SD 12=DD BBFF E0 12 CPX #&12 ;if =18 sectors/track BC01 D0 02 BNE SC05 ;set MFM latch bit BC03 09 40 ORA #&40 ;01000000, set bit 6 (DEN) .SC05 BC05 8D 84 FE STA &FE84 BC08 20 36 BE JSR SE36 ;get track no. under head BC0B 49 FF EOR #&FF BC0D 8D 81 FE STA &FE81 ;write to track register BC10 A0 08 LDY #&08 ;=Restore command BC12 68 PLA ;recover logical track number BC13 F0 07 BEQ SC1C ;if >0 BC15 49 FF EOR #&FF BC17 8D 83 FE STA &FE83 ;store data register BC1A A0 18 LDY #&18 ;=Seek command .SC1C BC1C 8C 63 0D STY &0D63 ;Temp. 2791 command BC1F AD 8F 02 LDA &028F ;get MOS option byte BC22 4A LSR A ;b4..b5 = stepping rate BC23 4A LSR A ;default = 11 = slowest BC24 4A LSR A BC25 4A LSR A BC26 29 03 AND #&03 ;00000011 mask bits 2-7, bits 0-1 = stepping BC28 0D 63 0D ORA &0D63 ;merge into 2791 command BC2B 49 FF EOR #&FF ;invert for 2791 BC2D A8 TAY BC2E 20 5B BE JSR SE5B ;do disc operation BC31 48 PHA ;save result status BC32 20 36 BE JSR SE36 ;get track no. under head/set X to actuator number BC35 AD 81 FE LDA &FE81 ;load track register BC38 49 FF EOR #&FF BC3A 9D 1E 10 STA &101E,X ;set new track no. under head BC3D 68 PLA BC3E BA TSX BC3F 9D 05 01 STA &0105,X ;return status in A BC42 60 RTS .SC43 ;Prepare for read/write. BC43 AD 17 10 LDA &1017 ;A = track number BC46 49 FF EOR #&FF BC48 8D 81 FE STA &FE81 ;write to track register BC4B AD 18 10 LDA &1018 ;get O7F sector no. BC4E 49 FF EOR #&FF BC50 8D 82 FE STA &FE82 ;write to sector register .SC53 BC53 AD 19 10 LDA &1019 ;Get no. sectors BC56 29 1F AND #&1F ;00011111 ;mask off sector size bits BC58 85 A4 STA &A4 ;store in counter for later BC5A 60 RTS .SC5B ;Open Tube channel to O7F addr BC5B 20 00 92 JSR Q200 ;save AXY BC5E 4A LSR A BC5F A2 11 LDX #&11 BC61 A0 10 LDY #&10 BC63 4C 06 A0 JMP R006 ;called from jump table at &BB13 etc BC66 A9 00 LDA #&00 ;Write data command BC68 F0 02 BEQ SC6C ;called from jump table at &BB0B BC6A A9 FF LDA #&FF ;Read data command .SC6C BC6C 8D 66 0D STA &0D66 .SC6F BC6F 20 5B BE JSR SE5B ;do disc op, return status BC72 C9 20 CMP #&20 ;if { Ready DeletedData } BC74 F0 08 BEQ SC7E ;then scrub last sector BC76 E6 A3 INC &A3 BC78 29 DF AND #&DF ;11011111 ;else mask off { HeadLoaded } BC7A D0 2F BNE SCAB ;other bits? finish O7F BC7C F0 23 BEQ SCA1 ;no other bits? do next sector .SC7E BC7E 8D 65 0D STA &0D65 ;Scrub sector. save status BC81 AD 66 0D LDA &0D66 ;if Write Data command BC84 F0 1B BEQ SCA1 ;then we requested it, carry on BC86 AD 64 0D LDA &0D64 ;else is Read. if I/O transfer BC89 D0 06 BNE SC91 BC8B CE 09 0D DEC &0D09 ;then decrement fetch page BC8E 4C A1 BC JMP SCA1 ;and do next sector .SC91 BC91 20 0C A0 JSR R00C ;else close TUBE channel BC94 20 06 92 JSR Q206 ;and copy address to O7F block BC97 EQUW &A2,&00 ;FROM address &00A2 to &1011 BC99 EQUW &11,&10 ;scrubbing all sectors in track. BC9B EQUB &02 ;i/o only scrubs the deleted one BC9C A9 02 LDA #&02 BC9E 20 5B BC JSR SC5B ;and open Tube channel .SCA1 BCA1 CE 82 FE DEC &FE82 ;increment sector register BCA4 C6 A4 DEC &A4 ;decrement sector count BCA6 D0 C7 BNE SC6F ;loop if more sectors BCA8 AD 65 0D LDA &0D65 ;else retrieve status .SCAB BCAB 4C 6D BB JMP SB6D ;post disc op .SCAE ;called from jump table at &BB3B BCAE A9 04 LDA #&04 ;Read ID command. 4 bytes to get BCB0 85 A1 STA &A1 ;save in counter BCB2 20 5B BE JSR SE5B ;do disc op BCB5 D0 0D BNE SCC4 ;if status = zero BCB7 98 TYA ;then clear b2 of command BCB8 09 04 ORA #&04 ;00000100 ;{ SettlingDelay } BCBA A8 TAY BCBB C6 A4 DEC &A4 ;decrement sector counter BCBD D0 EF BNE SCAE ;repeat command if more. BCBF A9 00 LDA #&00 ;else finish with zero status. .SCC1 BCC1 4C 6D BB JMP SB6D .SCC4 BCC4 C9 08 CMP #&08 ;was there a { CRCError } ? BCC6 D0 F9 BNE SCC1 ;if not then finish. BCC8 CE 62 0D DEC &0D62 ;decrement retry counter BCCB F0 F4 BEQ SCC1 ;exit if run out BCCD 4C 8B BA JMP SA8B ;else restart command. ;Format command ;called from jump table at &BB43 BCD0 8C 63 0D STY &0D63 BCD3 A0 00 LDY #&00 ;zero RLE table index BCD5 84 A1 STY &A1 ;store index at &00A1 BCD7 20 53 BC JSR SC53 ;set &A4 = no. sectors BCDA AD 19 10 LDA &1019 ;get no. sectors BCDD 0A ASL A BCDE 0A ASL A BCDF 0A ASL A ;multiply by 8 BCE0 85 A0 STA &A0 ;save in temp. BCE2 AD 10 10 LDA &1010 ;A = OSWORD &7F block = drive number 0..3 BCE5 29 03 AND #&03 ;00000011 mask bits 2-7, bits 0-1 = drive number BCE7 24 A0 BIT &A0 ;if no. sectors >=16 BCE9 10 02 BPL SCED BCEB 09 40 ORA #&40 ;01000000, then set double density bit. .SCED BCED 8D 84 FE STA &FE84 ;setup drive control register BCF0 AE 1B 10 LDX &101B ;get gap1 length .SCF3 BCF3 A9 FE LDA #&FE ;do gap (&FE emits IDAM) BCF5 20 41 BD JSR SD41 BCF8 24 A0 BIT &A0 ;if SD BCFA 30 09 BMI SD05 BCFC 20 66 BD JSR SD66 ;then fetch C byte BCFF 20 66 BD JSR SD66 ;fetch H byte BD02 4C 0F BD JMP SD0F .SD05 BD05 A2 02 LDX #&02 ;else fetch C byte, BD07 20 68 BD JSR SD68 ;to be sent twice (C and H) BD0A 20 66 BD JSR SD66 ;fetch H byte BD0D C6 A1 DEC &A1 ;and discard. .SD0F BD0F 20 66 BD JSR SD66 ;fetch R byte BD12 20 66 BD JSR SD66 ;fetch N byte BD15 20 79 BD JSR SD79 ;place CRC here BD18 A2 0B LDX #&0B ;gap2 = 11 if SD, BD1A 24 A0 BIT &A0 BD1C 10 02 BPL SD20 BD1E A2 16 LDX #&16 ;or 22 if DD. .SD20 BD20 A9 FB LDA #&FB ;append gap (&FB emits DAM) BD22 20 41 BD JSR SD41 BD25 A9 E5 LDA #&E5 ;append sector BD27 A2 00 LDX #&00 ;256 x &E5 BD29 20 88 BD JSR SD88 BD2C 20 79 BD JSR SD79 ;append CRC BD2F AE 18 10 LDX &1018 ;get gap3 length specified in BD32 C6 A4 DEC &A4 ;O7F param 2. Dec sector count BD34 D0 BD BNE SCF3 ;loop if more sectors BD36 A2 00 LDX #&00 ;else append gap4 BD38 20 80 BD JSR SD80 BD3B AC 63 0D LDY &0D63 ;get command BD3E 4C A6 BD JMP SDA6 ;do it and finish. .SD41 BD41 20 00 92 JSR Q200 ;Append gap to byte stream.save AXY BD44 20 80 BD JSR SD80 ;Write initial part (X=length) BD47 A9 00 LDA #&00 ;if SD BD49 A2 06 LDX #&06 ;then append 6 x &00 BD4B 24 A0 BIT &A0 BD4D 10 0B BPL SD5A BD4F A9 00 LDA #&00 ;else append 12 x &00 BD51 A2 0C LDX #&0C BD53 20 88 BD JSR SD88 BD56 A9 F5 LDA #&F5 ;then 3 x &F5 sync tokens BD58 A2 03 LDX #&03 .SD5A BD5A 20 88 BD JSR SD88 BD5D BA TSX ;retrieve A on entry BD5E BD 05 01 LDA &0105,X BD61 A2 01 LDX #&01 ;add address mark and exit BD63 4C 88 BD JMP SD88 .SD66 BD66 A2 01 LDX #&01 ;Fetch 1xbyte from I/O/Tube: .SD68 BD68 AD 64 0D LDA &0D64 ;Fetch byte from I/O/Tube BD6B F0 06 BEQ SD73 ;to be repeated X times. BD6D AD E5 FE LDA &FEE5 ;if Tube, read R3DATA BD70 4C 76 BD JMP SD76 .SD73 BD73 B1 A2 LDA (&A2),Y ;else read from (XY+1) BD75 C8 INY ;and increment pointer .SD76 BD76 4C 88 BD JMP SD88 ;add to RLE table and exit .SD79 BD79 A9 F7 LDA #&F7 ;Add CRC token to table. BD7B A2 01 LDX #&01 BD7D 4C 88 BD JMP SD88 .SD80 BD80 A9 FF LDA #&FF ;Add first part of gap. BD82 24 A0 BIT &A0 ;if SD then value = &FF BD84 10 02 BPL SD88 BD86 A9 4E LDA #&4E ;else value = &4E. .SD88 BD88 20 00 92 JSR Q200 ;Add (byte,runlen) to table.save AXY BD8B A4 A1 LDY &A1 ;get RLE table pointer BD8D 99 00 0E STA &0E00,Y ;store byte value BD90 8A TXA BD91 99 00 0F STA &0F00,Y ;store run length BD94 E6 A1 INC &A1 ;increment table pointer BD96 F0 01 BEQ SD99 ;"Bad spt" error if overrun BD98 60 RTS ;else exit. .SD99 BD99 20 18 90 JSR Q018 BD9C EQUB &0A BD9D EQUB &D0 BD9E EQUS "Bad spt" BDA5 EQUB &00 .SDA6 ;called from jump table at &BB4B/&BB53 BDA6 20 5B BE JSR SE5B ;Do disc op and finish O7F. BDA9 4C 6D BB JMP SB6D ;called from jump table at &BB5B BDAC 20 36 BE JSR SE36 ;get track no. under head BDAF 20 CF BB JSR SBCF ;seek that track BDB2 48 PHA ;Read drive status. BDB3 A0 81 LDY #&81 ;Preset b7 = unused, BDB5 68 PLA ;b0 = "CNT/OP1" BDB6 48 PHA ;if { Ready } BDB7 30 10 BMI SDC9 BDB9 AD 10 10 LDA &1010 ;A = OSWORD &7F block, BDBC 4A LSR A ;then set relevant RDYn bit according to O7F drive; BDBD 90 06 BCC SDC5 BDBF 98 TYA BDC0 09 40 ORA #&40 ;01000000 = set b6 = RDY1 BDC2 A8 TAY BDC3 D0 04 BNE SDC9 .SDC5 BDC5 98 TYA BDC6 09 04 ORA #&04 ;00000100 = set b2 = RDY0 BDC8 A8 TAY .SDC9 BDC9 68 PLA BDCA 48 PHA BDCB 29 40 AND #&40 ;01000000 ;if { WriteProtect } BDCD F0 04 BEQ SDD3 BDCF 98 TYA BDD0 09 08 ORA #&08 ;00001000 then set b3 = WRPROT BDD2 A8 TAY .SDD3 BDD3 68 PLA BDD4 48 PHA BDD5 29 04 AND #&04 ;00000100 ;if { Track00 } BDD7 F0 04 BEQ SDDD BDD9 98 TYA BDDA 09 02 ORA #&02 ;00000010 ;then set b1 = TRACK0 BDDC A8 TAY .SDDD BDDD 68 PLA BDDE 29 02 AND #&02 ;00000010 ;if { Index } BDE0 F0 04 BEQ SDE6 BDE2 98 TYA BDE3 09 10 ORA #&10 ;00010000 ;then set b4 = INDEX BDE5 A8 TAY .SDE6 BDE6 98 TYA BDE7 4C 9A BB JMP SB9A ;store result and exit ;Write special registers ;called from jump table at &BB63 BDEA AD 17 10 LDA &1017 ;A = track number BDED C9 05 CMP #&05 BDEF F0 14 BEQ SE05 ;if not register 5 BDF1 20 2D BE JSR SE2D ;then set X b0 = parm b3 BDF4 AD 18 10 LDA &1018 ;get track no. to write BDF7 20 40 BE JSR SE40 ;if drive is double-stepped BDFA 90 01 BCC SDFD BDFC 0A ASL A ;double the track number. .SDFD BDFD 9D 1E 10 STA &101E,X ;store in workspace BE00 A9 00 LDA #&00 ;return zero status. BE02 4C 9A BB JMP SB9A .SE05 BE05 AD 18 10 LDA &1018 ;&05 (Current sector) BE08 49 FF EOR #&FF BE0A 8D 82 FE STA &FE82 ;write to sector register BE0D A9 00 LDA #&00 ;return zero status BE0F 4C 9A BB JMP SB9A ;Read special registers ;called from jump table at &BB6B BE12 AD 17 10 LDA &1017 ;A = track number BE15 C9 05 CMP #&05 BE17 F0 0C BEQ SE25 ;if not register 5 BE19 20 2D BE JSR SE2D ;then set X b0 = parm b3 BE1C 20 40 BE JSR SE40 ;test if drive is double-stepped BE1F 90 01 BCC SE22 BE21 4A LSR A ;then halve the track number .SE22 BE22 4C 9A BB JMP SB9A ;return value as result .SE25 BE25 AD 82 FE LDA &FE82 ;read sector register BE28 49 FF EOR #&FF BE2A 4C 9A BB JMP SB9A ;return value as result .SE2D BE2D AD 17 10 LDA &1017 ;A = track number/&12, &1A (Current track) BE30 4A LSR A ;returns track under head of BE31 4A LSR A ;drives 0 and 1 BE32 4A LSR A BE33 4C 39 BE JMP SE39 ;fall through: .SE36 BE36 AD 10 10 LDA &1010 ;A = OSWORD &7F block = track no. under head .SE39 BE39 29 01 AND #&01 ;00000001 = mask bit 1-7, bit 0 = drive number BE3B AA TAX ;A -> X = drive specified in the OSWORD &7F command BE3C BD 1E 10 LDA &101E,X ;A = Track no. under heads on drives 0&2, 1&3 BE3F 60 RTS .SE40 ;Test if drive is double-stepped BE40 20 00 92 JSR Q200 ;save AXY BE43 AD 10 10 LDA &1010 ;A = OSWORD &7F block = drive number BE46 29 03 AND #&03 ;00000011, mask bits 2-7, bis 0-1 = drive number BE48 A8 TAY BE49 B9 28 10 LDA &1028,Y ;get track stepping for drive BE4C C9 01 CMP #&01 ;return C=1 if enabled. BE4E 60 RTS ;called from jump table at &BB03 BE4F A9 D0 LDA #&D0 ;A = Force interrupt, 11010000 BE51 49 FF EOR #&FF BE53 8D 80 FE STA &FE80 ;send Force Interrupt to command register BE56 A9 00 LDA #&00 ;return zero result BE58 4C 9A BB JMP SB9A .SE5B ;Do disc op. BE5B A5 F4 LDA &F4 ;save EDOS socket BE5D 8D 60 0D STA &0D60 ;number in NMI area BE60 AD 87 10 LDA &1087 ;get *OPT 9 saverom BE63 4C 20 0D JMP &0D20 ;jump to disc operation busywait BE66 85 F4 STA &F4 ;Disc ancillary loop BE68 8D 30 FE STA &FE30 ;copied to &0D20 BE6B 8C 80 FE STY &FE80 ;set ROM bank to *OPT 9 saverom BE6E A9 14 LDA #&14 ;issue FDC command .SE70 BE70 E9 01 SBC #&01 ;allow status register BE72 D0 FC BNE SE70 ;to settle (50 us) .SE74 BE74 AD 80 FE LDA &FE80 ;convert status to WD2793 form BE77 49 FF EOR #&FF ;if S7 Not Ready is clear BE79 10 14 BPL SE8F ;then test S0 Busy BE7B 2C 16 10 BIT &1016 ;else if command bit 7 is clear BE7E 10 F4 BPL SE74 ;then op uninterruptible; loop BE80 24 FF BIT &FF ;else test MOS Escape flag BE82 10 F0 BPL SE74 ;if Escape not pressed then loop BE84 A9 00 LDA #&00 ;else command = Restore BE86 49 FF EOR #&FF ;convert to WD2791 form BE88 8D 80 FE STA &FE80 ;write to command register BE8B A9 FF LDA #&FF ;return bogus status &FF BE8D D0 04 BNE SE93 ;branch (always) .SE8F BE8F 6A ROR A ;test S0 Busy BE90 B0 E2 BCS SE74 ;if set then test S7 Not Ready BE92 2A ROL A ;else reform status, S0 = 0 .SE93 BE93 48 PHA ;save status register BE94 AD 60 0D LDA &0D60 ;load slot number of EDOS ROM BE97 85 F4 STA &F4 ;page EDOS ROM back in BE99 8D 30 FE STA &FE30 BE9C 68 PLA ;present last status in A BE9D 60 RTS BE9E 85 A0 STA &A0 ;NMI read I/O BEA0 AD 00 0D LDA &0D00 ;all NMIs copied to &0D00 BEA3 49 FF EOR #&FF ;read memory, invert for WD2791 BEA5 8D 83 FE STA &FE83 ;store in Data Register BEA8 EE 03 0D INC &0D03 ;modify read instruction BEAB D0 03 BNE SEB0 ;incrementing the address BEAD EE 04 0D INC &0D04 .SEB0 BEB0 A5 A0 LDA &A0 ;restore accumulator and exit BEB2 40 RTI BEB3 85 A0 STA &A0 ;NMI read Tube BEB5 AD E5 FE LDA &FEE5 BEB8 49 FF EOR #&FF BEBA 8D 83 FE STA &FE83 BEBD A5 A0 LDA &A0 BEBF 40 RTI BEC0 85 A0 STA &A0 ;NMI write I/O BEC2 AD 83 FE LDA &FE83 BEC5 49 FF EOR #&FF BEC7 8D 00 0D STA &0D00 BECA EE 08 0D INC &0D08 BECD D0 03 BNE SED2 BECF EE 09 0D INC &0D09 .SED2 BED2 A5 A0 LDA &A0 BED4 40 RTI BED5 85 A0 STA &A0 ;NMI write Tube BED7 AD 83 FE LDA &FE83 BEDA 49 FF EOR #&FF BEDC 8D E5 FE STA &FEE5 BEDF A5 A0 LDA &A0 BEE1 40 RTI BEE2 85 A0 STA &A0 ;NMI read ID I/O BEE4 AD 83 FE LDA &FE83 BEE7 49 FF EOR #&FF BEE9 C6 A1 DEC &A1 BEEB 30 0B BMI SEF8 BEED 8D 00 0D STA &0D00 BEF0 EE 0C 0D INC &0D0C BEF3 D0 03 BNE SEF8 BEF5 EE 0D 0D INC &0D0D .SEF8 BEF8 A5 A0 LDA &A0 BEFA 40 RTI BEFB 85 A0 STA &A0 ;NMI read ID Tube BEFD AD 83 FE LDA &FE83 BF00 49 FF EOR #&FF BF02 C6 A1 DEC &A1 BF04 30 03 BMI SF09 BF06 8D E5 FE STA &FEE5 .SF09 BF09 A5 A0 LDA &A0 BF0B 40 RTI BF0C 2C 83 FE BIT &FE83 ;NMI verify BF0F 40 RTI BF10 85 A0 STA &A0 ;NMI format BF12 AD 00 0E LDA &0E00 BF15 49 FF EOR #&FF BF17 8D 83 FE STA &FE83 BF1A CE 00 0F DEC &0F00 BF1D D0 06 BNE SF25 BF1F EE 03 0D INC &0D03 BF22 EE 0B 0D INC &0D0B .SF25 BF25 A5 A0 LDA &A0 BF27 40 RTI ;unused space from &BF28 BFFF EQUB &00 ;make 16 KiB ROM image ;Variables ;00A0..A1 Pointer to user's OSWORD &7F block ;00A0 Temporary for A in NMI service routines ;00A1 No. bytes to fetch in Read ID NMI service routine ;00A2..A3 CHRN block address from O7F 1..2 for Format command ;00A4 No. sectors to read ;00A8 Catalogue flag in medium *commands 0=empty 1=clean >1=dirty ;00A8..A9 Pointer to CHRN table in *FORMAT ;00A8..A9 Pointer to private page when stowing/restoring workspace ;00A9..AA Pointer to backup/copy second catalogue buffer ;00AA..AB Pointer to extended vector table while setting up FS ;00AB Pointer to first free entry in catalogue 2 ;00AC High byte of data buffer address, low byte = 0 ;00AD Data buffer size in pages ;00AE Sector count in *BACKUP, *COPY ;00AF Temporary for Y in *BACKUP, *COPY: 0=source 1=target ;00B0..B1 Pointer to parameter byte in get byte immediate ;00B2..B3 Pointer to hex word in print-absolute ;00B2..B3 Pointer to source in copy memory absolute ;00B4..B5 Pointer to target in copy memory absolute ;00B6 No. bytes to copy in copy memory absolute ;00B7 Indexing argument in copy memory absolute ;00B8 Temp for high bits when packing catalogue entry ;00B8 Uppercased character to compare with names of open handles ;00B9 Counter to compare filename with names of open handles ;00BA..BB Target absolute sector when advancing PTR ;00BC..BD Pointer to user memory in OSGBPB ;00BE..BF Pointer to user's OSGBPB block ;00C0..C6 Immediate file name ;00C7..C9 Immediate dir, volume, drive (ASCII) ;00CA..CB Pointer to buffer of open file (CB=file handle) ;00CC Pointer to file entry in catalogue ;00CD Microcode shift register in OSGBPB, OSFIND/OSARGS, OSFILE, ; OSWORD &7F ; (in Q815) b7=0 Close file b7=1 Flush file only ;00CE 0=ambiguous spec not allowed 1=ambiguous spec allowed, ; current spec is specific &FF=current spec is ambiguous ;0100 Offset of next character of error message (from &0100); >=1 ;0100 BRK instruction followed by error message ;0101 Error number ;0102..24 Error message string terminated by NUL ; (longest error may be "Deleted data read on drive 0.79.17") ;0120..23 Trampoline to fetch byte of control block for monitor print ;02A1,Y ROM type byte (Y=?&F4) ; b3=Error message is being prepared ; b2=*SPOOL output was enabled before printing EDOS message ; NB Illegal usage; b3..0 reserved as CPU type field ;0D60 Socket number of EDOS ROM during disc operation ;0D61 ID of previous NMI owner during disc operation ;0D62 Retry counter in Read ID command ;0D63 Temp. 2791 command (may not be the exact one issued) ;0D64 >0 = Disc op is transferring to Tube ;0D65 Temporary for status after disc operation ;0D66 0 = Write to disc, &FF = Read from disc ;0D66 0 = accept deleted data, &FF = scrub deleted data ;0DF0,X High byte of address of private page (X=?&F4) ;1000..06 Default file name ;1007..09 Default directory, volume, drive (ASCII) ;100A..0C Library directory, volume, drive (ASCII) ;100D In absolute workspace: &BE=workspace in absolute page, ; other=absolute page not initialised. ; Private page+&D: &BE=workspace in absolute page, ; &EF=workspace in private page, other=private page ; not initialised. ;100E *OPT 1 monitor ;100F b1=1 if *ENABLEd ;1010..1B OSWORD &7F block ;101C..1D Address of user's OSWORD &7F block ;101E..1F Track no. under heads on drives 0&2, 1&3 ;1020..23 0FF0,X Density of drives 0..3 0A=SD 12=DD ;1024..27 0FF4,X No. tracks on drives 0..3 ;1028..2B 0FF8,X Track stepping on drives 0..3 >0=step ;102C..2F 0FFC,X No. volumes on disc, offset of disc cat /2 ;1030..37 No. tracks in volumes A..H ;1038..39 Offset to start of volume in sectors ;103A b6=Tube transfer, b7=write to Tube or I/O memory ; (when transferring bytes to/from open files) ;1040..57 Catalogue block 1 ;1040..46 Filename (used by *INFO) ;1047 Directory letter (used by *INFO) ;1048..4F Load/exec/length/start sector in catalogue format ;1048..4A Load address from catalogue (18 bit) ;104B..4D Execution address from catalogue (18 bit) ;104E..50 File length from catalogue ;1051..52 Absolute start sector ;1053..54 Number of sectors used ;1058..6F Catalogue block 2, for creating catalogue entries ;1058..64 OSCLI boot command string ;1060..61 Result from 'calculate free space on volume' routine ;1060..61 Input to 'print decimal word' routine ;1060..6F Table from &9A1E..2D for newly created files ;1060..62 cf. 1048..4A Load address of new file (18 bit) ;1063..65 cf. 104B..4D Execution address of new file (18 bit) ;1066..68 cf. 104E..50 Initial file length ;1069..6A cf. 1051..52 Absolute end sector (last used +1) ;106B..6C cf. 1053..54 Desired sector allocation ;1070..81 OSFILE/OSGBPB block ;1070..81 Workspace used by *BACKUP and *COPY ;1070 Source drive ;1071 Target drive ;1072 Source volume ;1073 Target volume ;1074..75 =&13,&0B 8271 read/write commands for source, target ;1076..77 Low byte of sectors-to-go for source, target ;1078..79 High byte of sectors-to-go for source, target ;107A..7B Low byte of start sector for source, target ;107C..7D High byte of start sector for source, target ;1080 b7 = Single disc operation (*COMPACT) ; b6 = Prompt to change discs b0 = b6? ;1081 High byte of volume size of source disc ; (to select 18/19 bit fields in catalogue 2) ;1070..81 Workspace used by *FORMAT, *CATGEN ;1070..73 Density,tracks,track stepping,volumes ;1072 Pointer to *command table entry in *CATGEN ;1074 Outstep (track skew) ;1076 4 * sector count (density) ;1077 Sector iterator ;1078..7F No. tracks in each volume of disc to format ;1080 1 + Maximum number of tracks per volume ;1081 Total number of tracks allocated to volumes ;1082..83 Pointer to arguments of *RUN, */ command ;1084..87 *OPT 6..9 density, volumes, tracks, saverom ;1088,Y Channel flags b0=EOF warning given b6=open for reading ; b7=open for writing ;1089,Y Current buffer 0=empty 1=clean 2=dirty ;108A..0,Y Name of open file ;1091,Y Directory of open file ;1092,Y Volume containing open file ;1093,Y Drive containing open file ;1094..5,Y Absolute start LBA of open file ;1096..7,Y Absolute LBA of sector currently in buffer ;1098..9,Y Allocated file length (!== EXT) ;109A..C,Y EXT file length ;109D..F,Y PTR file pointer ;This Perl script recreates the binary from this listing. ;Copy the text between the cut lines. ;Paste it into a new file, asm2bin.pl, and remove the column of ; ;Then call it with ; perl asm2bin.pl -D_UNUSED -b 8000 -o edos04 edos04.asm.txt ;-------->8--- ;#!/usr/bin/perl ; ;#Usage: perl asm2bin.pl ;# {-D SYMBOL[=VALUE]} [-E|-d] [-b BASE] ;# -o OUTFILE [FILE...] ; ;use Getopt::Std; ;use IO::Seekable qw(SEEK_SET SEEK_CUR SEEK_END); ; ;@x=(2); $t[6]=2; $t[7]=4; ; ;for($i=0;$i<@ARGV && ($arg = $ARGV[$i]) ne '--'; ++$i) { ; if(substr($arg,0,2) eq '-D') { ; if(($dfn=substr($arg,2)) eq '') { ; $dfn = $ARGV[++$i]; ; } ; if(($x=index($dfn,'=')) > 0) { ; $symbol{substr($dfn,0,$x)} = substr($dfn,$x+1); ; } elsif($dfn ne '') { ; $symbol{$dfn} = 1; ; } ; } ;} ; ;getopts("D:Eb:do:"); ;die "No output file specified" if $opt_o eq ''; ;$opt_b = hex($opt_b); ; ;open(BIN,"+>$opt_o") or die; ;binmode(BIN) unless $opt_E; ;while(<>) { ; y/\n\r//d; ; unless(/^\s*#/) { ; while(($key, $value) = each %symbol) { ; $x=0; ; while(($x = index($_,$key,$x)) >= 0) { ; substr($_,$x,length($key),$value); ; $x+=length($value); ; } ; } ; } ; if(/^\s*#\s*()ifdef\s+(\S*)$/ ; || /^\s*#\s*((?:el)?)if\s+defined\s*\(\s*(\S*)\s*\)/ ; || /^\s*#\s*((?:el)?)if\s+defined\s*(\S*)/) { ; unshift@x,4 if$1 eq''; ; $x[0]=$t[$x[0]|$x[1]&2|!exists($symbol{$2})];$_=''; ; }elsif(/^\s*#\s*()ifndef\s+(\S*)$/ ; || /^\s*#\s*((?:el)?)if\s+\!\s*defined\s*\(\s*(\S*)\s*\)/ ; || /^\s*#\s*((?:el)?)if\s+\!\s*defined\s*(\S*)/) { ; unshift@x,4 if$1 eq''; ; $x[0]=$t[$x[0]|$x[1]&2|exists($symbol{$2})];$_=''; ; }elsif(/^\s*#\s*((?:el)?)if\s+\!\s*(\S*)\s*$/) { ; unshift@x,4 if$1 eq''; ; $x[0]=$t[$x[0]|$x[1]&2|($2 !=0)];$_=''; ; }elsif(/^\s*#\s*((?:el)?)if\s+(\S*)\s*$/) { ; unshift@x,4 if$1 eq''; ; $x[0]=$t[$x[0]|$x[1]&2|($2 ==0)];$_=''; ; }elsif(/^\s*#\s*else(?!\S)/) { ; $x[0]=$t[$x[0]|$x[1]&2];$_=''; ; }elsif(/^\s*#\s*endif(?!\S)/) { ; shift@x;@x=(2)unless@x;$_=''; ; }elsif($x[0] & 2 && /^\s*#\s*define\s+(\S+)\s*(.*)$/) { ; $symbol{$1}=$2;$_=''; ; }elsif($x[0] & 2 && /^\s*#\s*undef\s+(\S+)/) { ; delete $symbol{$1};$_=''; ; } ; if($opt_E) { ; print BIN ($x[0] & 2 ? $_ : ''), "\n"; next; ; }elsif(($x[0] & 2)==0) { ; next; ; } ; if(/^ {0,2}([0-9A-F]{4})/) { ; print STDERR "seek $1\n" if $opt_d; ; seek(BIN,hex($1)-$opt_b,SEEK_SET); ; } ; if(/^ {0,2}[^;\\]{4}((?: {0,2}[0-9A-F]{2}){1,3})/) { ; ($a=$1)=~y/ //d; ; print STDERR " write $a\n" if $opt_d; ; print BIN pack("H*",$a); ; } ; if(/^ {0,2}[^;\\]{4} {0,2}EQUS ((?:"[^"]*")*)/) { ; ($a=substr($1,1,length($1)-2))=~s/""/"/g; ; print STDERR " write $a\n" if $opt_d; ; print BIN $a; ; } ; if(/^ {0,2}[^;\\]{4} {0,2}EQU[^S] (&[0-9A-F]{2}(?:,&[0-9A-F]{2})*)/){ ; ($a=$1)=~y/,&//d; ; print STDERR " write $a\n" if $opt_d; ; print BIN pack("H*",$a); ; } ;} ;close(BIN); ;-------->8--- ;End of edos04.asm.txt