Difference between revisions of "Prism Leisure Protection"

From Software Archive
Jump to navigation Jump to search
 
(5 intermediate revisions by the same user not shown)
Line 1: Line 1:
−
Checks data duplication on track 41. ($AC signature)
+
= Prism Leisure Protection =
 +
 
 +
'''Prism Leisure Protection''' is a Commodore 64 disk protection that checks
 +
for a '''data duplication track''': a track outside the normal 35-track range
 +
that consists of one byte value, <code>$AC</code>, repeated around the whole
 +
track. Most releases use '''track 41'''; some variants use track 40 or track 36
 +
(see [[#Variants|Variants]]). A disk copied with a normal 35-track copier lacks
 +
this track, and the check fails.
  
 
Disk title in directory is modified to show in green color.
 
Disk title in directory is modified to show in green color.
  
 
Used by Electric Dreams, Software Studios, Mirrorsoft Ltd., Thalamus
 
Used by Electric Dreams, Software Studios, Mirrorsoft Ltd., Thalamus
 +
 +
== The signature track ==
 +
 +
* The signature track has no sectors, headers or checksums. It contains the byte <code>$AC</code> repeated about 7,140 times per revolution.
 +
* In GCR bits <code>$AC</code> is <code>10101100</code>. On the disk this appears as a repeating flux interval pattern of 2-2-1-3 bit cells.
 +
* The track is written at the bit rate of speed zone 2 (3.50&nbsp;µs per cell). This is not the zone the 1541 DOS would use for that track.
 +
* No sync mark was found in the flux of any analyzed disk. The pattern simply runs once around the track.
 +
 +
<pre>
 +
Track  1 ─────────────────────────────── 35  ordinary CBM DOS layout
 +
Track 36 ─ 40                                  unused (standard variant)
 +
Track 41  $AC $AC $AC $AC ... (whole track, about 7,140 bytes, zone 2)
 +
</pre>
 +
 +
== The check ==
 +
 +
The loader uploads drive code. The drive code runs as an
 +
'''EXECUTE job (<code>$E0</code>) in buffer 3''', so the DOS job loop first
 +
moves the head to the signature track. Buffer 3 then starts with
 +
<code>JMP $0530</code>.
 +
 +
Standard variant, captured from drive RAM at the moment the head is stepped to
 +
track 41:
 +
 +
<pre>
 +
; ---- job setup, called once for track 41 and once for track 18 ----
 +
$0580  A9 29      LDA #$29          ; track 41 ($28 = track 40 in the track 40 variant)
 +
$0582  8D FD 05    STA $05FD
 +
$0585  A9 30      LDA #$30          ; job code entry -> $0530 (the check)
 +
$0587  8D 1C 05    STA $051C
 +
$058A  20 03 05    JSR $0503
 +
$058D  A9 12      LDA #$12          ; afterwards: track 18
 +
$058F  8D FD 05    STA $05FD
 +
$0592  A9 7A      LDA #$7A          ; job code entry -> $057A (no check,
 +
$0594  8D 1C 05    STA $051C        ;  just puts the head back on 18)
 +
$0597  20 03 05    JSR $0503
 +
$059A  60          RTS
 +
 +
$0503  20 00 C1    JSR $C100        ; LED on
 +
...
 +
$050A  AD FD 05    LDA $05FD
 +
$050D  85 80      STA $80          ; current track
 +
$050F  85 51      STA $51
 +
...
 +
$0516  A9 4C      LDA #$4C          ; buffer 3: JMP $05xx
 +
$0518  8D 00 06    STA $0600
 +
$051B  A9 30      LDA #$30          ; (operand patched to $30 / $7A above)
 +
$051D  8D 01 06    STA $0601
 +
$0520  A9 05      LDA #$05
 +
$0522  8D 02 06    STA $0602
 +
$0525  A5 7F      LDA $7F
 +
$0527  09 E0      ORA #$E0          ; EXECUTE job for buffer 3
 +
$0529  85 03      STA $03
 +
$052B  A5 03      LDA $03
 +
$052D  30 FC      BMI $052B        ; wait for the job to finish
 +
$052F  60          RTS
 +
 +
; ---- the check (runs on the signature track) ----
 +
$0530  AD 0C 1C    LDA $1C0C
 +
$0533  09 E0      ORA #$E0          ; head to read mode
 +
$0535  8D 0C 1C    STA $1C0C
 +
$0538  A9 00      LDA #$00
 +
$053A  8D 03 1C    STA $1C03        ; data port = input
 +
$053D  A9 FF      LDA #$FF
 +
$053F  8D FE 05    STA $05FE        ; search budget: 255 x 256 bytes
 +
$0542  A0 00      LDY #$00
 +
$0544  50 FE      BVC $0544        ; wait for byte ready
 +
$0546  B8          CLV
 +
$0547  AD 01 1C    LDA $1C01
 +
$054A  C9 AC      CMP #$AC          ; search for the first $AC
 +
$054C  F0 10      BEQ $055E
 +
$054E  88          DEY
 +
$054F  D0 F3      BNE $0544
 +
$0551  CE FE 05    DEC $05FE
 +
$0554  D0 EC      BNE $0542
 +
$0556  A9 00      LDA #$00          ; FAILED: result $00
 +
$0558  8D FF 05    STA $05FF
 +
$055B  4C 96 FD    JMP $FD96
 +
 +
$055E  A2 00      LDX #$00          ; found: now 256 more bytes ...
 +
$0560  50 FE      BVC $0560
 +
$0562  B8          CLV
 +
$0563  AD 01 1C    LDA $1C01
 +
$0566  C9 AC      CMP #$AC          ; ... must all be $AC
 +
$0568  D0 E4      BNE $054E        ; any other byte -> keep searching
 +
$056A  88          DEY
 +
$056B  D0 05      BNE $0572
 +
$056D  CE FE 05    DEC $05FE
 +
$0570  F0 E4      BEQ $0556        ; budget used up -> FAILED
 +
$0572  CA          DEX
 +
$0573  D0 EB      BNE $0560
 +
$0575  A9 C2      LDA #$C2          ; PASSED: result $C2
 +
$0577  8D FF 05    STA $05FF
 +
$057A  4C 96 FD    JMP $FD96
 +
</pre>
 +
 +
In short:
 +
 +
* The drive reads raw bytes from the signature track without looking for a sync or a header.
 +
* It searches up to 255&nbsp;×&nbsp;256 bytes (about nine revolutions) for an <code>$AC</code>.
 +
* After that, 256 bytes in a row must be <code>$AC</code>.
 +
* The result goes to drive address <code>$05FF</code>: <code>$C2</code> means passed, <code>$00</code> means failed.
 +
* A second job returns the head to track 18.
 +
* In most releases checked, the check runs about 10.5&nbsp;s after loading starts (up to about 15&nbsp;s in some).
 +
 +
== The C64 side ==
 +
 +
The C64 part is in a directory entry with an empty name, loaded to
 +
<code>$F000</code> (1,280 bytes). It is copied to <code>$C000</code> and
 +
entered with <code>JMP $C0E0</code> (from <code>$C475</code>):
 +
 +
<pre>
 +
$C0E0  20 03 C0    JSR $C003        ; upload the drive code
 +
$C0E3  20 B8 C0    JSR $C0B8        ; start it: "M-E" $0500
 +
$C0E6  20 70 C0    JSR $C070        ; read the result: "M-R" $05FF -> $C0FF
 +
$C0E9  A9 A6      LDA #$A6          ; build the expected value without
 +
$C0EB  49 17      EOR #$17          ;  ever writing it as a constant:
 +
$C0ED  49 98      EOR #$98          ;  $A6^$17^$98^$B6^$AD^$F0 = $C2
 +
$C0EF  49 B6      EOR #$B6
 +
$C0F1  49 AD      EOR #$AD
 +
$C0F3  49 F0      EOR #$F0
 +
$C0F5  CD FF C0    CMP $C0FF        ; compare with the byte read from the drive
 +
$C0F8  F0 03      BEQ $C0FD
 +
$C0FA  6C FC FF    JMP ($FFFC)      ; FAILED: reset the C64
 +
$C0FD  4C 00 00    JMP $xx00        ; the high byte of this JMP IS $C0FF
 +
</pre>
 +
 +
* '''Upload (<code>$C003</code>):''' the drive code is stored in C64 memory at <code>$C100</code>–<code>$C1FF</code>, XOR-encrypted with <code>$05</code>. That's the high byte of its drive address, which the upload loop uses as the key. It is sent with <code>M-W</code> in 32-byte chunks to drive <code>$0500</code>–<code>$05FF</code> and decrypted on the fly.
 +
* '''Read-back (<code>$C070</code>):''' the C64 opens the command channel, sends <code>M-R</code> <code>$FF $05</code>, and stores the single byte it gets back at <code>$C0FF</code>.
 +
* '''Decision:''' if the byte is not <code>$C2</code>, the loader jumps through the reset vector, and the machine restarts. This is the reset seen when the check fails.
 +
 +
The result byte is used three times, so patching only the
 +
<code>BEQ</code> or the reset jump doesn't crack the protection:
 +
 +
# as the comparison value at <code>$C0F5</code>;
 +
# as the high byte of the jump target. <code>$C0FF</code> is also the operand of <code>JMP $xx00</code> at <code>$C0FD</code>, so only the correct value <code>$C2</code> continues at <code>$C200</code>;
 +
# as the decryption key. The code at <code>$C200</code> XORs page <code>$C300</code> with <code>$C0FF</code> and then jumps to <code>$C300</code>:
 +
 +
<pre>
 +
$C200  78          SEI
 +
$C201  A2 00      LDX #$00
 +
$C203  BD 00 C3    LDA $C300,X
 +
$C206  4D FF C0    EOR $C0FF        ; key = result byte ($C2)
 +
$C209  9D 00 C3    STA $C300,X
 +
$C20C  CA          DEX
 +
$C20D  D0 F4      BNE $C203
 +
$C20F  58          CLI
 +
$C210  4C 00 C3    JMP $C300
 +
</pre>
 +
 +
== Variants ==
 +
 +
{| class="wikitable"
 +
! Variant !! Signature track !! Difference to the standard routine !! Releases
 +
|-
 +
| Standard || 41 || — || most releases, e.g. [[Power-Pack]], [[Grand Prix Selection]], [[Enduro Racer]], [[International Karate +]], [[Football Manager 2]]
 +
|-
 +
| Track 40 || 40 || Same routine, only the track number differs (<code>LDA #$28</code>). || [[Metaplex]], [[Speedball]], [[Phobia]]
 +
|-
 +
| Old || 41 || Needs only 255 <code>$AC</code> in a row, has no search budget, and stores <code>$FF</code> for passed. || [[Firetrack]]
 +
|-
 +
| New || 36 || Waits for a sync and accepts <code>$AC</code> in all 8 bit rotations. Result at <code>$05B7</code>. || [[Tanium]]
 +
|}
 +
 +
=== Track 40 variant ===
 +
 +
The drive and C64 code are the same as in the standard variant; only the track
 +
number in the job setup is <code>$28</code> (track 40). Some images of these
 +
releases carry the <code>$AC</code> track on both track 40 and track 41, but
 +
only track 40 is read. Some images of [[Metaplex]] have only track 40.
 +
 +
=== Old variant (Firetrack) ===
 +
 +
<pre>
 +
$0538  A9 00      LDA #$00
 +
$053A  8D FF 05    STA $05FF        ; result preset: $00
 +
...
 +
$054D  A2 FF      LDX #$FF          ; 255 bytes in a row ...
 +
$054F  50 FE      BVC $054F
 +
$0551  B8          CLV
 +
$0552  AD 01 1C    LDA $1C01
 +
$0555  C9 AC      CMP #$AC
 +
$0557  D0 F4      BNE $054D        ; any other byte: start counting again
 +
$0559  CA          DEX
 +
$055A  D0 F3      BNE $054F
 +
$055C  A9 FF      LDA #$FF          ; PASSED: result $FF
 +
$055E  8D FF 05    STA $05FF
 +
$0561  4C 96 FD    JMP $FD96
 +
</pre>
 +
 +
There is no search budget and no failure exit. On a disk without the signature
 +
track the drive keeps searching forever, so a copy hangs instead of failing.
 +
 +
=== New variant (Tanium) ===
 +
 +
<pre>
 +
$0500  A9 24      LDA #$24          ; track 36
 +
...
 +
$0556  2C 00 1C    BIT $1C00        ; wait for a sync, then for its end
 +
$0559  30 FB      BMI $0556
 +
...
 +
$0565  A2 00      LDX #$00          ; search budget: 256 bytes
 +
$0567  20 89 05    JSR $0589        ; byte is a rotation of $AC?
 +
$056A  F0 0B      BEQ $0577
 +
$056C  CA          DEX
 +
$056D  D0 F8      BNE $0567
 +
$056F  A9 00      LDA #$00          ; FAILED: result $00
 +
$0571  8D B7 05    STA $05B7
 +
$0574  4C 96 FD    JMP $FD96
 +
$0577  A0 00      LDY #$00          ; then 256 bytes in a row
 +
$0579  20 89 05    JSR $0589
 +
$057C  D0 E9      BNE $0567
 +
$057E  88          DEY
 +
$057F  D0 F8      BNE $0579
 +
$0581  A9 C2      LDA #$C2          ; PASSED: result $C2
 +
$0583  8D B7 05    STA $05B7
 +
$0586  4C 96 FD    JMP $FD96
 +
 +
$0589  50 FE      BVC $0589
 +
$058B  B8          CLV
 +
$058C  AD 01 1C    LDA $1C01
 +
$058F  C9 AC      CMP #$AC          ; accepts $AC, $56, $2B, $95, $CA, $65,
 +
...                                  ;  $B2 and $59: all 8 bit rotations
 +
</pre>
 +
 +
Because every bit rotation of <code>$AC</code> is accepted, this variant no
 +
longer depends on where the drive's byte boundaries fall on the track (see
 +
below).
 +
 +
== Copying and imaging ==
 +
 +
* A 35-track copy or a D64 image loses the signature track, and the check fails.
 +
* A signature track that decodes as "almost <code>$AC</code>" fails too. The check needs 256 correct bytes in a row, so a single shifted or lost bit in every few bytes is enough to break it.
 +
* '''Byte framing.''' The standard routine reads without a sync, so the drive's byte boundaries fall wherever the head happens to start reading. On a clean signature track this does not matter. On an image with interrupted <code>$AC</code> runs, the result can depend on the start timing: one image of [[Football Manager 2]] (source 2, "(!)") passed the check in only 2 of 7 VICE runs with different start delays, while the other images of the same release passed every time. The new variant (Tanium) avoids this problem.
 +
* '''Back sides (flippy sides) need care when imaging:'''
 +
** '''Recording direction.''' In a double-sided KryoFlux capture, head 1 reads the back side in reverse time order. This applies to the signature track as well as to tracks 1–35. Read without reversal, the <code>$AC</code> pattern looks like 3-1-2-2 instead of 2-2-1-3.
 +
** '''Signal distortion.''' The signature track signal on back sides can be heavily peak-shifted. On [[Power-Pack]] source 7, Disk 1 back side, the measured intervals were 1.30 / 1.88 / 2.18 / 2.60 cells instead of 1 / 2 / 2 / 3. It then decodes cleanly only at exactly 3.50&nbsp;µs per cell.
  
 
==== Pages that refer to this protection ====
 
==== Pages that refer to this protection ====
  
 
{{Special:Whatlinkshere/Prism Leisure Protection}}
 
{{Special:Whatlinkshere/Prism Leisure Protection}}

Latest revision as of 11:26, 10 October 2026

Prism Leisure Protection

Prism Leisure Protection is a Commodore 64 disk protection that checks for a data duplication track: a track outside the normal 35-track range that consists of one byte value, $AC, repeated around the whole track. Most releases use track 41; some variants use track 40 or track 36 (see Variants). A disk copied with a normal 35-track copier lacks this track, and the check fails.

Disk title in directory is modified to show in green color.

Used by Electric Dreams, Software Studios, Mirrorsoft Ltd., Thalamus

The signature track

  • The signature track has no sectors, headers or checksums. It contains the byte $AC repeated about 7,140 times per revolution.
  • In GCR bits $AC is 10101100. On the disk this appears as a repeating flux interval pattern of 2-2-1-3 bit cells.
  • The track is written at the bit rate of speed zone 2 (3.50 µs per cell). This is not the zone the 1541 DOS would use for that track.
  • No sync mark was found in the flux of any analyzed disk. The pattern simply runs once around the track.
 Track  1 ─────────────────────────────── 35   ordinary CBM DOS layout
 Track 36 ─ 40                                  unused (standard variant)
 Track 41   $AC $AC $AC $AC ... (whole track, about 7,140 bytes, zone 2)

The check

The loader uploads drive code. The drive code runs as an EXECUTE job ($E0) in buffer 3, so the DOS job loop first moves the head to the signature track. Buffer 3 then starts with JMP $0530.

Standard variant, captured from drive RAM at the moment the head is stepped to track 41:

; ---- job setup, called once for track 41 and once for track 18 ----
$0580  A9 29       LDA #$29          ; track 41 ($28 = track 40 in the track 40 variant)
$0582  8D FD 05    STA $05FD
$0585  A9 30       LDA #$30          ; job code entry -> $0530 (the check)
$0587  8D 1C 05    STA $051C
$058A  20 03 05    JSR $0503
$058D  A9 12       LDA #$12          ; afterwards: track 18
$058F  8D FD 05    STA $05FD
$0592  A9 7A       LDA #$7A          ; job code entry -> $057A (no check,
$0594  8D 1C 05    STA $051C         ;   just puts the head back on 18)
$0597  20 03 05    JSR $0503
$059A  60          RTS

$0503  20 00 C1    JSR $C100         ; LED on
...
$050A  AD FD 05    LDA $05FD
$050D  85 80       STA $80           ; current track
$050F  85 51       STA $51
...
$0516  A9 4C       LDA #$4C          ; buffer 3: JMP $05xx
$0518  8D 00 06    STA $0600
$051B  A9 30       LDA #$30          ; (operand patched to $30 / $7A above)
$051D  8D 01 06    STA $0601
$0520  A9 05       LDA #$05
$0522  8D 02 06    STA $0602
$0525  A5 7F       LDA $7F
$0527  09 E0       ORA #$E0          ; EXECUTE job for buffer 3
$0529  85 03       STA $03
$052B  A5 03       LDA $03
$052D  30 FC       BMI $052B         ; wait for the job to finish
$052F  60          RTS

; ---- the check (runs on the signature track) ----
$0530  AD 0C 1C    LDA $1C0C
$0533  09 E0       ORA #$E0          ; head to read mode
$0535  8D 0C 1C    STA $1C0C
$0538  A9 00       LDA #$00
$053A  8D 03 1C    STA $1C03         ; data port = input
$053D  A9 FF       LDA #$FF
$053F  8D FE 05    STA $05FE         ; search budget: 255 x 256 bytes
$0542  A0 00       LDY #$00
$0544  50 FE       BVC $0544         ; wait for byte ready
$0546  B8          CLV
$0547  AD 01 1C    LDA $1C01
$054A  C9 AC       CMP #$AC          ; search for the first $AC
$054C  F0 10       BEQ $055E
$054E  88          DEY
$054F  D0 F3       BNE $0544
$0551  CE FE 05    DEC $05FE
$0554  D0 EC       BNE $0542
$0556  A9 00       LDA #$00          ; FAILED: result $00
$0558  8D FF 05    STA $05FF
$055B  4C 96 FD    JMP $FD96

$055E  A2 00       LDX #$00          ; found: now 256 more bytes ...
$0560  50 FE       BVC $0560
$0562  B8          CLV
$0563  AD 01 1C    LDA $1C01
$0566  C9 AC       CMP #$AC          ; ... must all be $AC
$0568  D0 E4       BNE $054E         ; any other byte -> keep searching
$056A  88          DEY
$056B  D0 05       BNE $0572
$056D  CE FE 05    DEC $05FE
$0570  F0 E4       BEQ $0556         ; budget used up -> FAILED
$0572  CA          DEX
$0573  D0 EB       BNE $0560
$0575  A9 C2       LDA #$C2          ; PASSED: result $C2
$0577  8D FF 05    STA $05FF
$057A  4C 96 FD    JMP $FD96

In short:

  • The drive reads raw bytes from the signature track without looking for a sync or a header.
  • It searches up to 255 × 256 bytes (about nine revolutions) for an $AC.
  • After that, 256 bytes in a row must be $AC.
  • The result goes to drive address $05FF: $C2 means passed, $00 means failed.
  • A second job returns the head to track 18.
  • In most releases checked, the check runs about 10.5 s after loading starts (up to about 15 s in some).

The C64 side

The C64 part is in a directory entry with an empty name, loaded to $F000 (1,280 bytes). It is copied to $C000 and entered with JMP $C0E0 (from $C475):

$C0E0  20 03 C0    JSR $C003         ; upload the drive code
$C0E3  20 B8 C0    JSR $C0B8         ; start it: "M-E" $0500
$C0E6  20 70 C0    JSR $C070         ; read the result: "M-R" $05FF -> $C0FF
$C0E9  A9 A6       LDA #$A6          ; build the expected value without
$C0EB  49 17       EOR #$17          ;   ever writing it as a constant:
$C0ED  49 98       EOR #$98          ;   $A6^$17^$98^$B6^$AD^$F0 = $C2
$C0EF  49 B6       EOR #$B6
$C0F1  49 AD       EOR #$AD
$C0F3  49 F0       EOR #$F0
$C0F5  CD FF C0    CMP $C0FF         ; compare with the byte read from the drive
$C0F8  F0 03       BEQ $C0FD
$C0FA  6C FC FF    JMP ($FFFC)       ; FAILED: reset the C64
$C0FD  4C 00 00    JMP $xx00         ; the high byte of this JMP IS $C0FF
  • Upload ($C003): the drive code is stored in C64 memory at $C100–$C1FF, XOR-encrypted with $05. That's the high byte of its drive address, which the upload loop uses as the key. It is sent with M-W in 32-byte chunks to drive $0500–$05FF and decrypted on the fly.
  • Read-back ($C070): the C64 opens the command channel, sends M-R $FF $05, and stores the single byte it gets back at $C0FF.
  • Decision: if the byte is not $C2, the loader jumps through the reset vector, and the machine restarts. This is the reset seen when the check fails.

The result byte is used three times, so patching only the BEQ or the reset jump doesn't crack the protection:

  1. as the comparison value at $C0F5;
  2. as the high byte of the jump target. $C0FF is also the operand of JMP $xx00 at $C0FD, so only the correct value $C2 continues at $C200;
  3. as the decryption key. The code at $C200 XORs page $C300 with $C0FF and then jumps to $C300:
$C200  78          SEI
$C201  A2 00       LDX #$00
$C203  BD 00 C3    LDA $C300,X
$C206  4D FF C0    EOR $C0FF         ; key = result byte ($C2)
$C209  9D 00 C3    STA $C300,X
$C20C  CA          DEX
$C20D  D0 F4       BNE $C203
$C20F  58          CLI
$C210  4C 00 C3    JMP $C300

Variants

Variant Signature track Difference to the standard routine Releases
Standard 41 — most releases, e.g. Power-Pack, Grand Prix Selection, Enduro Racer, International Karate +, Football Manager 2
Track 40 40 Same routine, only the track number differs (LDA #$28). Metaplex, Speedball, Phobia
Old 41 Needs only 255 $AC in a row, has no search budget, and stores $FF for passed. Firetrack
New 36 Waits for a sync and accepts $AC in all 8 bit rotations. Result at $05B7. Tanium

Track 40 variant

The drive and C64 code are the same as in the standard variant; only the track number in the job setup is $28 (track 40). Some images of these releases carry the $AC track on both track 40 and track 41, but only track 40 is read. Some images of Metaplex have only track 40.

Old variant (Firetrack)

$0538  A9 00       LDA #$00
$053A  8D FF 05    STA $05FF         ; result preset: $00
...
$054D  A2 FF       LDX #$FF          ; 255 bytes in a row ...
$054F  50 FE       BVC $054F
$0551  B8          CLV
$0552  AD 01 1C    LDA $1C01
$0555  C9 AC       CMP #$AC
$0557  D0 F4       BNE $054D         ; any other byte: start counting again
$0559  CA          DEX
$055A  D0 F3       BNE $054F
$055C  A9 FF       LDA #$FF          ; PASSED: result $FF
$055E  8D FF 05    STA $05FF
$0561  4C 96 FD    JMP $FD96

There is no search budget and no failure exit. On a disk without the signature track the drive keeps searching forever, so a copy hangs instead of failing.

New variant (Tanium)

$0500  A9 24       LDA #$24          ; track 36
...
$0556  2C 00 1C    BIT $1C00         ; wait for a sync, then for its end
$0559  30 FB       BMI $0556
...
$0565  A2 00       LDX #$00          ; search budget: 256 bytes
$0567  20 89 05    JSR $0589         ; byte is a rotation of $AC?
$056A  F0 0B       BEQ $0577
$056C  CA          DEX
$056D  D0 F8       BNE $0567
$056F  A9 00       LDA #$00          ; FAILED: result $00
$0571  8D B7 05    STA $05B7
$0574  4C 96 FD    JMP $FD96
$0577  A0 00       LDY #$00          ; then 256 bytes in a row
$0579  20 89 05    JSR $0589
$057C  D0 E9       BNE $0567
$057E  88          DEY
$057F  D0 F8       BNE $0579
$0581  A9 C2       LDA #$C2          ; PASSED: result $C2
$0583  8D B7 05    STA $05B7
$0586  4C 96 FD    JMP $FD96

$0589  50 FE       BVC $0589
$058B  B8          CLV
$058C  AD 01 1C    LDA $1C01
$058F  C9 AC       CMP #$AC          ; accepts $AC, $56, $2B, $95, $CA, $65,
...                                  ;   $B2 and $59: all 8 bit rotations

Because every bit rotation of $AC is accepted, this variant no longer depends on where the drive's byte boundaries fall on the track (see below).

Copying and imaging

  • A 35-track copy or a D64 image loses the signature track, and the check fails.
  • A signature track that decodes as "almost $AC" fails too. The check needs 256 correct bytes in a row, so a single shifted or lost bit in every few bytes is enough to break it.
  • Byte framing. The standard routine reads without a sync, so the drive's byte boundaries fall wherever the head happens to start reading. On a clean signature track this does not matter. On an image with interrupted $AC runs, the result can depend on the start timing: one image of Football Manager 2 (source 2, "(!)") passed the check in only 2 of 7 VICE runs with different start delays, while the other images of the same release passed every time. The new variant (Tanium) avoids this problem.
  • Back sides (flippy sides) need care when imaging:
    • Recording direction. In a double-sided KryoFlux capture, head 1 reads the back side in reverse time order. This applies to the signature track as well as to tracks 1–35. Read without reversal, the $AC pattern looks like 3-1-2-2 instead of 2-2-1-3.
    • Signal distortion. The signature track signal on back sides can be heavily peak-shifted. On Power-Pack source 7, Disk 1 back side, the measured intervals were 1.30 / 1.88 / 2.18 / 2.60 cells instead of 1 / 2 / 2 / 3. It then decodes cleanly only at exactly 3.50 µs per cell.

Pages that refer to this protection