;------------------------------- ; Identification routines for various whole-track ; protections and other frivolities. ; ; The main entry point is SkipTrack, which is ; called when the last sector ($0F or $0C) of a ; newly-seeked track is unexpectedly unreadable. ; (All the words in that sentence are important.) ; ; This file also contains low-level subroutines ; that require precise timing. There are ; assemble-time guards around the timing-sensitive ; instructions, which means that changes to this ; file may result in fatal assembler build errors ; because you moved code that can't cross a page ; boundary and now it crosses a page boundary. ;------------------------------- ;------------------------------- ; SkipTrack ; out: C clear if we should skip this track ; C set if we should not skip this track ;------------------------------- SkipTrack ; don't look for whole-track protections on track 0, that's silly lda gTrack sec beq @linknoskip ; ; Electronic Arts protection track? ; jsr IsWideTrack lda #s_widetrack bcc @print ; ; Nibble count track? ; jsr JustTheSameDamnThingOverAndOver lda #s_sync bcc @print ; ; Unexepcted 13-sector track on a 16-sector disk? ; (Micrograms likes to do this) ; jsr Unexpected5And3InBaggingArea lda #s_unexpected5and3 bcc @print ; ; RW18-format track? ; jsr VerifyInfocom18 lda #s_rw18 bcc @print ; ; Unformatted track? ; jsr IsUnformatted @linknoskip bcs @donotskip ; ; $F7F6EFEAAB protection track? ; (initially presents as unformatted, needs separate test because it ; triggers special handling) ; jsr IsF7F6 lda #s_unformat bcs @print lda #s_f7 bit gMode bpl @print bvc @print ; if we're in 'crack' mode, restart the scan to find the protection code bvs SetupF7F6SecondRound ; always branches @print sta + jsr PrintByID + !byte $FD ; SMC ; ; Skipping T22 on a ProDOS disk might indicate the presence of a ; Gamco Industries protection elsewhere on the disk. Different ; Gamco disks present as different types of weirdness on T22 -- ; EEEF, sync, or even unformatted. (The actual protection is just ; a bad block check, so putting the code here will catch all ; possible cases.) ; lda gTrack cmp #$22 clc bne @donotskip lda #TRUE sta gAdventureInternational lda gIsProDOS bne @donotskip sta gPossibleGamco @donotskip rts ;------------------------------- ; IsF7F6 ; check for a specific nibble sequence ; ("F7 F6 EF EE AB") that is used by a ; whole-track protection scheme ; ; in slot 6, drive 1 is on track to test ; out C clear if sequence was found ; C set if sequence was not found ;------------------------------- IsF7F6 lda $C0E9 lda #$00 jsr WAIT tay lda #$19 sta nibcount - jsr ReadNib cmp #$F7 beq + @restart iny bne - dec nibcount bne - sec beq @driveoff + ldx #3 - jsr ReadNib cmp @f7f6_sequence,x bne @restart dex bpl - clc @driveoff lda $C0E8 rts @f7f6_sequence !byte $AB,$EE,$EF,$F6 ;------------------------------- ; SetupF7F6SecondRound ; ; Print that we found the F7F6 protection track, ; then restart the scan so we can search every sector ; for the protection code. ; Never returns. ; Exits via RestartScan. ;------------------------------- SetupF7F6SecondRound ; Mark in the sector map that we should ignore ; this protection track the second time around. lda checksector+1 sta @a+1 lda checksector+2 sta @a+2 ldy gSector lda #kSectorIgnore @a sta $D1D1 ; modifed at runtime ldx @a+1 bne + dec @a+2 + dec @a+1 dey bpl @a jsr PrintByID ; print that we found the protection track !byte s_f7 lda #TRUE sta gIsF7F6 ; set global to activate expensive patcher jmp RestartScan ;------------------------------- ; JustTheSameDamnThingOverAndOver ; check if track has 512 repeated nibbles ; ; in slot 6, drive 1 is on track to test ; out C clear if found ; C set otherwise ;------------------------------- JustTheSameDamnThingOverAndOver lda $C0E9 ; turn on drive motor, but we assume it's already spun up from previous reads so no waiting lda #$60 sta tmp lda #$19 sta unform+1 ldx #$00 ; ; Timing-sensitive code! Cycle counts in margin for worst case path ; @reset clv ; 2 ldy #$00 ; 2 sta @cmp+1 ; 4 @loop lda $C0EC ; 4 bpl @loop ; 2 when not taken !if RELBASE != $2000 { !if >@loop != >* { !serious "branch crosses a page" } } dex ; 2 bne @cmp ; 2 when not taken dec unform+1 ; 5 beq @notfound ; 2 when not taken @cmp cmp #$d1 ; 2 bne @reset ; 2 when not taken iny ; 2 bne @loop ; 2 when not taken (3 when taken) bvs @found ; 2 when not taken bit tmp ; 3 (sets overflow flag) bvs @loop ; 3 (always taken) @found clc !byte $24 @notfound sec lda $C0E8 rts ;------------------------------- ; IsUnformatted ; check if track is unformatted by counting ; the number of valid nibbles in a row ; ; in slot 6, drive 1 is on track to test ; out C clear if track is unformatted ; C set if track is formatted ;------------------------------- IsUnformatted lda $C0E9 ; turn on drive motor, but we assume it's already spun up from previous reads so no waiting lda #$00 sta unform lda #$19 sta unform+1 ; ; Timing-sensitive code! Cycle counts in margin for worst case path ; clc @reset ldy #$00 @loop ldx $C0EC ; 4 bpl @loop ; 2 when not taken !if RELBASE != $2000 { !if >@loop != >* { !serious "branch crosses a page" } } dec unform ; 5 bne + ; 2 when not taken dec unform+1 ; 5 beq @unformatted;2 when not taken + lda gNIBTable,x; 4 bmi @reset ; 2 when not taken iny ; 2 bne @loop ; 3 when taken sec @unformatted lda $C0E8 rts ;------------------------------- ; IsWideTrack ; check if this track claims to be the previous track ; in the case of EA, track 6 reads as track 5 ; in the case of Accolade, track $22 reads as track $21 ; ; in slot 6, drive 1 is on track to test ; out C clear if found wide track ; C set if not found ;------------------------------- IsWideTrack lda $2E clc adc #1 cmp gTrack beq + sec rts + clc rts ;------------------------------- ; ReadNib ; read a single nibble from S6,D1 ; ; in: S6,D1 must be spun up and ready to read ; out: A contains nibble value ;------------------------------- ReadNib .x1 - lda $C0EC bpl - !if RELBASE != $2000 { !if >.x1 != >* { !serious "branch crosses a page" } } rts ;------------------------------- ; Read4x4 ; read a 4-4-encoded value from S6,D1 ; ; in: S6,D1 must be spun up and ready to read ; out: A contains decoded value ; @tmp clobbered ;------------------------------- Read4x4 .x2 - lda $C0EC bpl - !if RELBASE != $2000 { !if >.x2 != >* { !serious "branch crosses a page" } } sec rol sta tmp .x3 - lda $C0EC bpl - !if RELBASE != $2000 { !if >.x3 != >* { !serious "branch crosses a page" } } and tmp rts ;------------------------------- ; Unexpected5And3InBaggingArea ; check if track is unexpectedly full of ; 5-and-3-encoded sectors on a disk where ; we expected 6-and-2 encoded sectors ; ; used by e.g. Micrograms as a weak form ; of copy protection to foil COPYA-style ; copying ; ; in slot 6, drive 1 is on track to test ; out C clear if unexpected track found ; C set if not found ;------------------------------- Unexpected5And3InBaggingArea lda gIs13Sector beq @no ; if ID'd as a 13 sector disk, then this is not unexpected lda $C0E9 lda #$19 sta nibcount ldx #$0C ldy #$00 @restart dey bne + dec nibcount beq @no + - lda $C0EC bpl - @maybeD5 cmp #$D5 bne @restart - lda $C0EC bpl - cmp #$AA bne @maybeD5 - lda $C0EC bpl - cmp #$B5 bne @maybeD5 dex bne @restart clc ; passport-test-suite/Real Math.woz [C=0] matches !byte $A9 @no sec lda $C0E8 rts