├── .gitattributes ├── .gitignore ├── DOS33L.S ├── DOS33LR.S ├── QBOOT.S └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | -------------------------------------------------------------------------------- /DOS33L.S: -------------------------------------------------------------------------------- 1 | ;qboot DOS 3.3 default launcher support 2 | ;copyright (c) Peter Ferrie 2016 3 | ;assemble using ACME 4 | !cpu 6502 5 | !to "dos33l",plain 6 | ;place on sector 1 7 | *=$BF00 8 | stx sectors 9 | sta address 10 | lda phase 11 | lsr 12 | sta track 13 | - sty index + 1 14 | lda xlatsec, y 15 | sta sector 16 | lda #>iocb 17 | ldy #dct, 0 39 | address !byte $d1 40 | !byte 0, 0, 1, 0, 0, $60, 1 41 | dct !byte 1, $ef, $d8, 0 42 | -------------------------------------------------------------------------------- /DOS33LR.S: -------------------------------------------------------------------------------- 1 | ;qboot DOS 3.3 relocated launcher support 2 | ;copyright (c) Peter Ferrie 2016 3 | ;assemble using ACME 4 | !cpu 6502 5 | !to "dos33l",plain 6 | ;place on sector 1 7 | *=$BF00 8 | firsttrk = $d1 ;user-defined, first track to read 9 | 10 | stx sectors 11 | sta address 12 | - sty index + 1 13 | lda xlatsec, y 14 | sta sector 15 | lda #>iocb 16 | ldy #dct, 0 36 | address !byte $d1 37 | !byte 0, 0, 1, 0, 0, $60, 1 38 | dct !byte 1, $ef, $d8, 0 39 | -------------------------------------------------------------------------------- /QBOOT.S: -------------------------------------------------------------------------------- 1 | ;fast seek/multi-read 2 | ;copyright (c) Peter Ferrie 2015-16 3 | ;assemble using ACME 4 | !cpu 6502 5 | !to "qboot",plain 6 | *=$800 7 | sectors = $d1 ;user-defined 8 | firsttrk = $d1 ;user-defined, first track to read 9 | firstsec = $d1 ;user-defined, first sector to read 10 | address = $d1 ;user-defined 11 | entry = $d1d1 ;user-defined 12 | zpread = 0 ;set to 1 to allow reading into zero page 13 | ;relies on memory wraparound, not supported on IIGS 14 | ;also precludes reading to page $FF 15 | stkread = 0 ;set to 1 to allow reading into stack page 16 | ;but remember about the 6 bytes of stack 17 | seekback = 0 ;set to 1 to enable seek backwards 18 | version = 1 19 | 20 | ;memory usage: 21 | ;256 bytes ($bd00-bdff) static table 22 | grouped = $bd00 23 | ;106 bytes ($xx00-xx69) static table 24 | preshift = code_end 25 | zvalue = $fd ;only during init 26 | znibble = $fe ;only during init 27 | zmask = $ff ;only during init 28 | 29 | !byte 1 ;we'll read the other two ourselves 30 | lsr ;check sector number 31 | 32 | ;the following TAY is a workaround for a CFFA bug 33 | ;the bug is that Y isn't zero on entry 34 | ;the workaround sets it to two instead 35 | ;it's not zero, but it's better than #$10 36 | 37 | tay 38 | adc #$bd 39 | sta $27 ;set or update address as needed 40 | asl 41 | bmi + ;branch if not 3 42 | inc $3d ;increment sector (faster to find) 43 | txa 44 | lsr 45 | lsr 46 | lsr 47 | lsr 48 | ora #$c0 ;slot to PROM base 49 | pha 50 | lda #$5b ;read-1 51 | pha 52 | rts 53 | 54 | + txa 55 | ora #$8c ;slot to Q6L 56 | - iny 57 | ldx patchtbl-3, y 58 | sta code_begin, x ;replace placeholders with Q6L 59 | bne - 60 | and #$f8 ;MOTOROFF 61 | sta slotpatch7+1 62 | eor #8 ;PHASEOFF 63 | sta slotpatch8+1 64 | ldx #$3f 65 | stx zmask 66 | inx 67 | ldy #$7f 68 | bne + ;branch always 69 | *=$839 70 | lda #>(entry-1) 71 | pha 72 | lda #<(entry-1) 73 | pha 74 | jsr preread 75 | jmp $bf00 ;DOS 3.3 launcher entrypoint 76 | 77 | patchtbl 78 | !byte <(slotpatch1+1), <(slotpatch2+1), <(slotpatch3+1), <(slotpatch4+1), <(slotpatch5+1), <(slotpatch6+1) 79 | indextbl ;the 0 also terminates the patchtbl list! 80 | !byte 0, 2, 1, 3 81 | 82 | ;construct denibbilisation table 83 | ;pre-shifted for interleave read 84 | 85 | + 86 | -- sty znibble 87 | tya 88 | asl 89 | bit znibble 90 | beq + 91 | ora znibble 92 | eor #$ff 93 | and #$7e 94 | - bcs + 95 | lsr 96 | bne - 97 | dex 98 | txa 99 | asl 100 | asl 101 | sta preshift-$16, y 102 | + dey 103 | bne -- 104 | 105 | ;construct 2-bit group table 106 | 107 | sty zvalue 108 | -- lsr zmask 109 | lsr zmask 110 | - lda indextbl, x 111 | sta grouped, y 112 | inc zvalue 113 | lda zvalue 114 | and zmask 115 | bne + 116 | inx 117 | txa 118 | and #3 119 | tax 120 | + iny 121 | iny 122 | iny 123 | iny 124 | cpy #3 125 | bcs - 126 | iny 127 | cpy #3 128 | bcc -- 129 | lda #>(entry-1) 130 | pha 131 | lda #<(entry-1) 132 | pha 133 | jsr preread 134 | 135 | !if seekback { ;no room to do this in the routine 136 | sty startsec+1 137 | sta tmpadr+1 138 | stx total+1 139 | } 140 | jmp seekread 141 | 142 | preread 143 | 144 | ;copy post-read if necessary 145 | ;push post-read address here 146 | ; pla 147 | ; tax 148 | ; pla 149 | ; tay 150 | ; lda #>(postread-1) 151 | ; pha 152 | ; lda #<(postread-1) 153 | ; pha 154 | ; tya 155 | ; pha 156 | ; txa 157 | ; pha 158 | 159 | lda #<(firsttrk*2) 160 | sta phase+1 161 | ldx #sectors 162 | lda #address 163 | ldy #firstsec 164 | rts 165 | 166 | *=$8fe 167 | !byte $be, 1 168 | 169 | ;the following lives on sectors $0E and $0D 170 | !pseudopc $be00 { 171 | code_begin 172 | !byte version 173 | 174 | readnib 175 | slotpatch1 176 | - lda $c0d1 177 | bpl - 178 | rts 179 | 180 | ;fill address array for one track 181 | 182 | seekread 183 | !if seekback=0 { 184 | sty startsec+1 185 | sta tmpadr+1 186 | stx total+1 187 | } 188 | 189 | inittrk 190 | sec 191 | lda #$10 192 | sbc startsec+1 193 | cmp total+1 194 | bcs + 195 | tax 196 | + stx partial1 197 | stx partial2 198 | jsr seek 199 | 200 | startsec 201 | ldy #$d1 202 | !if zpread { 203 | inc tmpadr+1 204 | } 205 | tmpadr 206 | - lda #$d1 207 | sta addrtbl, y 208 | !if !zpread { 209 | inc tmpadr+1 210 | } 211 | iny 212 | dec partial1 213 | bne - 214 | 215 | read 216 | -- jsr readnib 217 | - cmp #$d5 218 | bne -- 219 | jsr readnib 220 | cmp #$aa 221 | bne - 222 | tay ;we need Y=#$AA later 223 | jsr readnib 224 | eor #$ad ;zero A if match 225 | beq check_mode 226 | 227 | ;if not #$AD, then #$96 is assumed 228 | 229 | ldy #2 ;volume, track, sector 230 | - jsr readnib 231 | rol ;set carry 232 | sta sector+1 233 | jsr readnib 234 | and sector+1 235 | dey 236 | bpl - 237 | tay 238 | ldx addrtbl, y ;fetch corresponding address 239 | beq read 240 | sta sector+1 ;store index for later 241 | !if zpread { 242 | stx adrpatch9+2 243 | dex 244 | } 245 | stx adrpatch1+2 246 | stx adrpatch8+2 247 | stx adrpatch2+2 248 | stx adrpatch3+2 249 | stx adrpatch5+2 250 | stx adrpatch7+2 251 | !if !zpread { 252 | inx 253 | stx adrpatch9+2 254 | dex 255 | } 256 | dex 257 | stx adrpatch4+2 258 | stx adrpatch6+2 259 | !if stkread { 260 | inx 261 | !if zpread { 262 | inx 263 | } 264 | } 265 | ldy #$fe 266 | adrpatch1 267 | - lda $d102, y 268 | pha 269 | iny 270 | bne - 271 | 272 | branch_read 273 | bcs read ;branch always 274 | check_mode 275 | cpx #0 276 | beq read ;loop if not expecting #$AD 277 | 278 | -- sta tmpval+1 ;zero rolling checksum 279 | slotpatch2 280 | - ldx $c0d1 281 | bpl - 282 | lda preshift-$96, x 283 | adrpatch2 284 | sta $d102, y ;store 2-bit array 285 | 286 | tmpval 287 | eor #$d1 288 | iny 289 | bne -- 290 | ldy #$aa 291 | slotpatch3 292 | - ldx $c0d1 293 | bpl - 294 | eor preshift-$96, x 295 | adrpatch3 296 | ldx $d102, y ;bit2tbl 297 | eor grouped+2, x ;first 86 nibbles use group bits 0-1 298 | adrpatch4 299 | sta $d156, y 300 | iny 301 | bne - 302 | and #$fc 303 | ldy #$aa 304 | slotpatch4 305 | - ldx $c0d1 306 | bpl - 307 | eor preshift-$96, x 308 | adrpatch5 309 | ldx $d102, y ;bit2tbl 310 | eor grouped+1, x ;second 86 nibbles use group bits 2-3 311 | adrpatch6 312 | sta $d1ac, y 313 | iny 314 | bne - 315 | and #$fc 316 | ldx #$ac 317 | slotpatch5 318 | - ldy $c0d1 319 | bpl - 320 | eor preshift-$96, y 321 | adrpatch7 322 | ldy $d100, x ;bit2tbl 323 | eor grouped, y ;last 84 nibbles use group bits 4-5 324 | adrpatch8 325 | sta $d100, x 326 | inx 327 | bne - 328 | and #$fc 329 | slotpatch6 330 | - ldy $c0d1 331 | bpl - 332 | eor preshift-$96, y 333 | cmp #1 ;carry = !zero 334 | ldy #1 335 | - pla 336 | adrpatch9 337 | sta $d100, y 338 | dey 339 | bpl - 340 | branch_read2 341 | bcs branch_read ;branch if checksum failure 342 | sector 343 | ldy #$d1 344 | txa 345 | sta addrtbl, y ;zero corresponding address 346 | dec total+1 347 | dec partial2 ;adjust remaining count (faster than looping over array) 348 | sec 349 | bne branch_read2 ;read all requested sectors in one track 350 | total 351 | ldx #$d1 352 | beq driveoff 353 | inc phase+1 354 | inc phase+1 ;update current track 355 | jmp inittrk 356 | 357 | driveoff 358 | slotpatch7 359 | lda $c0d1 360 | 361 | seekret 362 | rts 363 | 364 | seek 365 | lda #0 366 | sta step+1 367 | copy_cur 368 | curtrk 369 | lda #0 370 | sta tmpval+1 371 | sec 372 | phase 373 | sbc #$d1 374 | beq seekret 375 | !if seekback { 376 | bcs + 377 | } 378 | eor #$ff 379 | inc curtrk+1 380 | !if seekback { 381 | bcc ++ 382 | + adc #$fe 383 | dec curtrk+1 384 | ++ 385 | } 386 | cmp step+1 387 | bcc + 388 | step 389 | lda #$d1 390 | + cmp #8 391 | bcs + 392 | tay 393 | sec 394 | + lda curtrk+1 395 | ldx step1, y 396 | bne + 397 | --- clc 398 | lda tmpval+1 399 | ldx step2, y 400 | + stx sector+1 401 | and #3 402 | rol 403 | tax 404 | slotpatch8 405 | sta $c0d1, x 406 | -- ldx #$13 407 | - dex 408 | bne - 409 | dec sector+1 410 | bne -- 411 | lsr 412 | bcs --- 413 | inc step+1 414 | bne copy_cur 415 | 416 | step1 !byte 1, $30, $28, $24, $20, $1e, $1d, $1c 417 | step2 !byte $70, $2c, $26, $22, $1f, $1e, $1d, $1c 418 | addrtbl !fill 16 419 | partial1 = * 420 | partial2 = partial1+1 421 | code_end=partial2+1 422 | } 423 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | - targets multi-loaders in ProDOS order 2 | - load from any slot 3 | - scatter-reads sectors 4 | - sector-level read, can start and end anywhere in a track 5 | - can perform full-track read in one revolution 6 | - no zpage usage after init, and only 6 bytes of stack 7 | - only 2 bytes overhead per read 8 | - can load up to $bd sectors at a time ($0000-bcff) 9 | (or $c0 sectors if run from banked ROM) 10 | - DOS 3.3 Launcher compatible 11 | - requires only 3 pages in memory 12 | --------------------------------------------------------------------------------