Difference between revisions of "Prism Leisure Protection"
| (One intermediate revision by the same user not shown) | |||
| Line 2: | Line 2: | ||
'''Prism Leisure Protection''' is a Commodore 64 disk protection that checks | '''Prism Leisure Protection''' is a Commodore 64 disk protection that checks | ||
| − | for a '''data duplication track | + | for a '''data duplication track''': a track outside the normal 35-track range |
| − | 35-track range that consists of one byte value, <code>$AC</code>, repeated | + | that consists of one byte value, <code>$AC</code>, repeated around the whole |
| − | around the whole track. A disk copied with a normal 35-track copier lacks | + | 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. | this track, and the check fails. | ||
| Line 13: | Line 14: | ||
== The signature track == | == 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. | * 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 µs per cell). This is not the zone the 1541 DOS would use for track | + | * 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. | * No sync mark was found in the flux of any analyzed disk. The pattern simply runs once around the track. | ||
<pre> | <pre> | ||
Track 1 ─────────────────────────────── 35 ordinary CBM DOS layout | Track 1 ─────────────────────────────── 35 ordinary CBM DOS layout | ||
| − | Track 36 ─ 40 unused | + | Track 36 ─ 40 unused (standard variant) |
Track 41 $AC $AC $AC $AC ... (whole track, about 7,140 bytes, zone 2) | Track 41 $AC $AC $AC $AC ... (whole track, about 7,140 bytes, zone 2) | ||
</pre> | </pre> | ||
| Line 28: | Line 29: | ||
The loader uploads drive code. The drive code runs as an | 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 | '''EXECUTE job (<code>$E0</code>) in buffer 3''', so the DOS job loop first | ||
| − | moves the head to track | + | moves the head to the signature track. Buffer 3 then starts with |
<code>JMP $0530</code>. | <code>JMP $0530</code>. | ||
| − | + | Standard variant, captured from drive RAM at the moment the head is stepped to | |
| + | track 41: | ||
<pre> | <pre> | ||
; ---- job setup, called once for track 41 and once for track 18 ---- | ; ---- job setup, called once for track 41 and once for track 18 ---- | ||
| − | $0580 A9 29 LDA #$29 ; track 41 | + | $0580 A9 29 LDA #$29 ; track 41 ($28 = track 40 in the track 40 variant) |
$0582 8D FD 05 STA $05FD | $0582 8D FD 05 STA $05FD | ||
$0585 A9 30 LDA #$30 ; job code entry -> $0530 (the check) | $0585 A9 30 LDA #$30 ; job code entry -> $0530 (the check) | ||
| Line 66: | Line 68: | ||
$052F 60 RTS | $052F 60 RTS | ||
| − | ; ---- the check (runs on track | + | ; ---- the check (runs on the signature track) ---- |
$0530 AD 0C 1C LDA $1C0C | $0530 AD 0C 1C LDA $1C0C | ||
$0533 09 E0 ORA #$E0 ; head to read mode | $0533 09 E0 ORA #$E0 ; head to read mode | ||
| Line 107: | Line 109: | ||
In short: | In short: | ||
| − | * The drive reads raw bytes from track | + | * 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 <code>$AC</code>. | * It searches up to 255 × 256 bytes (about nine revolutions) for an <code>$AC</code>. | ||
* After that, 256 bytes in a row must be <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. | * 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. | * 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 side == | ||
| Line 157: | Line 160: | ||
$C210 4C 00 C3 JMP $C300 | $C210 4C 00 C3 JMP $C300 | ||
</pre> | </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 == | == Copying and imaging == | ||
| − | * A 35-track copy or a D64 image loses track | + | * A 35-track copy or a D64 image loses the signature track, and the check fails. |
| − | * A track | + | * 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:''' | * '''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 track | + | ** '''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 track | + | ** '''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 ==== | ==== 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
Contents
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
$ACrepeated about 7,140 times per revolution. - In GCR bits
$ACis10101100. 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:$C2means passed,$00means 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 withM-Win 32-byte chunks to drive$0500–$05FFand decrypted on the fly. - Read-back (
$C070): the C64 opens the command channel, sendsM-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:
- as the comparison value at
$C0F5; - as the high byte of the jump target.
$C0FFis also the operand ofJMP $xx00at$C0FD, so only the correct value$C2continues at$C200; - as the decryption key. The code at
$C200XORs page$C300with$C0FFand 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
$ACruns, 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
$ACpattern 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.
- 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
Pages that refer to this protection
- Descriptions of old disk copy protections (← links)
- Grand Prix Selection (← links)
- Speedball (← links)
- Tetris (← links)
- Foxx Fights Back (← links)
- Metaplex (← links)
- Hunter's Moon (← links)
- Quedex (← links)
- Football Manager 2 (← links)
- Power-Pack (← links)
- Enduro Racer (← links)
- Big Trouble in Little China (← links)
- Firetrack (← links)
- Future Games 64 (← links)
- Soccer Mania (← links)
- Quartet (← links)
- Pack of Aces (← links)
- International Karate + (← links)
- Football Manager: World Cup Edition 1990 (← links)
- Fun Collection Vol.1 (← links)
- Andy Capp (← links)
- Karnov (← links)
- Predator (← links)
- Super Sprint (← links)
- Championship Sprint (← links)
- Phobia (← links)
- Super Hang-On (← links)
- Mean Streak (← links)
- Tanium (← links)
- Zig-Zag (← links)