<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://preservation64.de/index.php?action=history&amp;feed=atom&amp;title=Eagles_GMA87</id>
	<title>Eagles GMA87 - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://preservation64.de/index.php?action=history&amp;feed=atom&amp;title=Eagles_GMA87"/>
	<link rel="alternate" type="text/html" href="https://preservation64.de/index.php?title=Eagles_GMA87&amp;action=history"/>
	<updated>2026-08-28T15:14:08Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.34.0-alpha</generator>
	<entry>
		<id>https://preservation64.de/index.php?title=Eagles_GMA87&amp;diff=75696&amp;oldid=prev</id>
		<title>Enigma at 22:00, 24 August 2026</title>
		<link rel="alternate" type="text/html" href="https://preservation64.de/index.php?title=Eagles_GMA87&amp;diff=75696&amp;oldid=prev"/>
		<updated>2026-08-24T22:00:01Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table class=&quot;diff diff-contentalign-left&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #222; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #222; text-align: center;&quot;&gt;Revision as of 22:00, 24 August 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l2&quot; &gt;Line 2:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 2:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;This article documents, in full technical detail, the copy protection scheme&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;This article documents, in full technical detail, the copy protection scheme&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;−&lt;/td&gt;&lt;td style=&quot;color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;used by the Commodore 64 release of '''Eagles''' &lt;del class=&quot;diffchange diffchange-inline&quot;&gt;(Hewson/Graeme Ashton,&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;used by the Commodore 64 release of '''Eagles''', as distributed on the ''Beau Jolly Big Box 2'' compilation disk&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;−&lt;/td&gt;&lt;td style=&quot;color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del class=&quot;diffchange diffchange-inline&quot;&gt;1987)&lt;/del&gt;, as distributed on the ''Beau Jolly Big Box 2'' compilation disk&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot;&gt; &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;(&amp;lt;code&amp;gt;BeauJolly_BigBox2_Disk6_s0.g64&amp;lt;/code&amp;gt;). Eagles carries a&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;(&amp;lt;code&amp;gt;BeauJolly_BigBox2_Disk6_s0.g64&amp;lt;/code&amp;gt;). Eagles carries a&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;code&amp;gt;GMA87&amp;lt;/code&amp;gt; disk label — the same protection family used by&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;code&amp;gt;GMA87&amp;lt;/code&amp;gt; disk label — the same protection family used by&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Enigma</name></author>
		
	</entry>
	<entry>
		<id>https://preservation64.de/index.php?title=Eagles_GMA87&amp;diff=75695&amp;oldid=prev</id>
		<title>Enigma: Created page with &quot;= Eagles (C64) — GMA87 copy protection, full technical write-up =  This article documents, in full technical detail, the copy protection scheme used by the Commodore 64 rele...&quot;</title>
		<link rel="alternate" type="text/html" href="https://preservation64.de/index.php?title=Eagles_GMA87&amp;diff=75695&amp;oldid=prev"/>
		<updated>2026-08-24T21:44:12Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;= Eagles (C64) — GMA87 copy protection, full technical write-up =  This article documents, in full technical detail, the copy protection scheme used by the Commodore 64 rele...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;= Eagles (C64) — GMA87 copy protection, full technical write-up =&lt;br /&gt;
&lt;br /&gt;
This article documents, in full technical detail, the copy protection scheme&lt;br /&gt;
used by the Commodore 64 release of '''Eagles''' (Hewson/Graeme Ashton,&lt;br /&gt;
1987), as distributed on the ''Beau Jolly Big Box 2'' compilation disk&lt;br /&gt;
(&amp;lt;code&amp;gt;BeauJolly_BigBox2_Disk6_s0.g64&amp;lt;/code&amp;gt;). Eagles carries a&lt;br /&gt;
&amp;lt;code&amp;gt;GMA87&amp;lt;/code&amp;gt; disk label — the same protection family used by&lt;br /&gt;
[[Cholo]], [[Triaxos]], and roughly twenty other titles linking to the&lt;br /&gt;
[https://preservation64.de/index.php?title=GMA87 GMA87] wiki page — but,&lt;br /&gt;
uniquely among all of them, moves the actual decryption step off the C64 and&lt;br /&gt;
onto the '''1541 disk drive's own 6502 CPU'''. This makes Eagles a title where the C64 never sees ciphertext for the protected&lt;br /&gt;
game data at all.&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
* The disk directory is deliberately hidden from naive tools by a non-standard&lt;br /&gt;
  (&amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;$A0&amp;lt;/code&amp;gt;) filename padding.&lt;br /&gt;
* The only loadable file, &amp;lt;code&amp;gt;BOOT&amp;lt;/code&amp;gt;, is deliberately loaded at&lt;br /&gt;
  &amp;lt;code&amp;gt;$02A7&amp;lt;/code&amp;gt; so that it overlaps and hijacks the C64's own KERNAL&lt;br /&gt;
  page-2/3 RAM vector table — a standard auto-start trick.&lt;br /&gt;
* From there, a self-decrypting bootstrap streams in a much larger program&lt;br /&gt;
  live from the drive, byte by byte, XORing each byte against its own&lt;br /&gt;
  destination address (a descramble, not a secret key).&lt;br /&gt;
* That program contains a hardware-handshake primitive&lt;br /&gt;
  (&amp;lt;code&amp;gt;$05EB&amp;lt;/code&amp;gt;) that talks to the drive over CIA2's &amp;lt;code&amp;gt;$DD00&amp;lt;/code&amp;gt;&lt;br /&gt;
  port with cycle-accurate raster-line synchronization. It is used for&lt;br /&gt;
  ''every'' byte of a further custom byte-transfer protocol.&lt;br /&gt;
* The drive, on command, seeks to track 39 containing a&lt;br /&gt;
  deliberately malformed sync region, and measures a **physically&lt;br /&gt;
  unclonable, disk-specific signature byte** from sync length variation —&lt;br /&gt;
  structurally the same measurement Cholo/Triaxos perform on track 38.&lt;br /&gt;
  Measured value for this disk capture: &amp;lt;code&amp;gt;$95&amp;lt;/code&amp;gt; (149 decimal).&lt;br /&gt;
* Unlike Cholo/Triaxos (which send this byte to the C64 and decrypt a large&lt;br /&gt;
  static block there in one pass), Eagles uploads a '''fresh drive-side&lt;br /&gt;
  program''' to drive RAM (&amp;lt;code&amp;gt;$0300&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;$03DF&amp;lt;/code&amp;gt;) via&lt;br /&gt;
  standard 1541 &amp;lt;code&amp;gt;M-W&amp;lt;/code&amp;gt; (memory-write) commands, and bakes the&lt;br /&gt;
  measured signature byte directly into that program's own machine code —&lt;br /&gt;
  as the literal operand of an &amp;lt;code&amp;gt;EOR #$95&amp;lt;/code&amp;gt; instruction at drive&lt;br /&gt;
  address &amp;lt;code&amp;gt;$035D&amp;lt;/code&amp;gt;.&lt;br /&gt;
* From that point on, the '''drive's own 6502''' decrypts every byte of&lt;br /&gt;
  every subsequent game-data sector, one block at a time, and streams&lt;br /&gt;
  already-plaintext bytes to the C64 over the bit-banged serial link. The&lt;br /&gt;
  C64 never receives, stores, or applies the key itself.&lt;br /&gt;
* Both halves of the scheme fail ''silently'' on a bad copy — a hang, not an&lt;br /&gt;
  error message or a crash on load. A disk that reproduces the sync-mark&lt;br /&gt;
  layout but not the exact sync length pattern sails through every check on&lt;br /&gt;
  both sides and decrypts to garbage far downstream&lt;br /&gt;
&lt;br /&gt;
== Disk structure and directory obfuscation ==&lt;br /&gt;
&lt;br /&gt;
=== Non-standard filename padding ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;BOOT&amp;lt;/code&amp;gt; directory entry (logical track 18, sector 1, slot 0)&lt;br /&gt;
is the four bytes &amp;lt;code&amp;gt;42 4F 4F 54&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;&amp;quot;BOOT&amp;quot;&amp;lt;/code&amp;gt;) followed by&lt;br /&gt;
'''twelve &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; bytes''', not the standard CBM DOS&lt;br /&gt;
&amp;lt;code&amp;gt;$A0&amp;lt;/code&amp;gt; (shifted-space) padding. Two confirmed consequences:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;LIST&amp;lt;/code&amp;gt;ing the directory truncates right after &amp;lt;code&amp;gt;BOOT&amp;lt;/code&amp;gt;&lt;br /&gt;
  with no closing quote or &amp;lt;code&amp;gt;PRG&amp;lt;/code&amp;gt; shown — BASIC's line printer&lt;br /&gt;
  reads the &amp;lt;code&amp;gt;$00&amp;lt;/code&amp;gt; mid-string as a premature line terminator.&lt;br /&gt;
* &amp;lt;code&amp;gt;LOAD&amp;quot;BOOT&amp;quot;,8,1&amp;lt;/code&amp;gt; (exact name) returns &amp;lt;code&amp;gt;FILE NOT FOUND&amp;lt;/code&amp;gt;&lt;br /&gt;
  — the real KERNAL's name-matching does not tolerate the non-standard&lt;br /&gt;
  padding either. Only &amp;lt;code&amp;gt;LOAD&amp;quot;*&amp;quot;,8,1&amp;lt;/code&amp;gt; (wildcard match on the&lt;br /&gt;
  first directory entry) works.&lt;br /&gt;
&lt;br /&gt;
1306 bytes, load address &amp;lt;code&amp;gt;$02A7&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Boot mechanism: overlapping the KERNAL's own RAM vector table ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;$02A7&amp;lt;/code&amp;gt; deliberately overlaps &amp;lt;code&amp;gt;$0300&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;$0333&amp;lt;/code&amp;gt;,&lt;br /&gt;
the C64's page-2/3 KERNAL RAM vector table (&amp;lt;code&amp;gt;IERROR&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;IMAIN&amp;lt;/code&amp;gt;, ..., &amp;lt;code&amp;gt;CINV&amp;lt;/code&amp;gt;, ..., &amp;lt;code&amp;gt;IGETIN&amp;lt;/code&amp;gt;, ...).&lt;br /&gt;
Simply ''loading'' the file overwrites these vectors with whatever bytes&lt;br /&gt;
land at those file offsets — no explicit install instruction is needed.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;IMAIN&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0302&amp;lt;/code&amp;gt;, the address BASIC jumps through&lt;br /&gt;
  every time it returns to its input loop) → becomes &amp;lt;code&amp;gt;$0334&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;ISTOP&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;$0328&amp;lt;/code&amp;gt;, checked periodically during&lt;br /&gt;
  KERNAL I/O, including during &amp;lt;code&amp;gt;LOAD&amp;lt;/code&amp;gt; itself) → becomes&lt;br /&gt;
  &amp;lt;code&amp;gt;$02ED&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
It means the &amp;quot;program&amp;quot; starts running the&lt;br /&gt;
moment &amp;lt;code&amp;gt;LOAD&amp;lt;/code&amp;gt; returns control to BASIC, with no &amp;lt;code&amp;gt;RUN&amp;lt;/code&amp;gt;&lt;br /&gt;
needed. The execution entry is at &amp;lt;code&amp;gt;$02ED&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ISTOP&amp;lt;/code&amp;gt;), not&lt;br /&gt;
byte 0 of the file.&lt;br /&gt;
&lt;br /&gt;
== Bootstrap: a self-decrypting live stream, not a static file ==&lt;br /&gt;
&lt;br /&gt;
Tracing forward from &amp;lt;code&amp;gt;$02ED&amp;lt;/code&amp;gt; '''live''' (the static file content&lt;br /&gt;
at these addresses is misleading — see why below):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$02ED&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;$0301&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;JSR $FFC3&amp;lt;/code&amp;gt;&lt;br /&gt;
  (&amp;lt;code&amp;gt;CLOSE&amp;lt;/code&amp;gt;), set pointer &amp;lt;code&amp;gt;$AE&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;$AF&amp;lt;/code&amp;gt; =&lt;br /&gt;
  &amp;lt;code&amp;gt;$0334&amp;lt;/code&amp;gt;, disable the display (&amp;lt;code&amp;gt;$D011&amp;lt;/code&amp;gt;), then&lt;br /&gt;
  &amp;lt;code&amp;gt;JSR $FFC6&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;CHKIN&amp;lt;/code&amp;gt; — itself hijacked, see next),&lt;br /&gt;
  then &amp;lt;code&amp;gt;JSR $0334&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The hijacked &amp;lt;code&amp;gt;ICHKIN&amp;lt;/code&amp;gt; vector (&amp;lt;code&amp;gt;$031E&amp;lt;/code&amp;gt; →&lt;br /&gt;
  &amp;lt;code&amp;gt;$02CB&amp;lt;/code&amp;gt;) actually points at a small relocator that copies 9&lt;br /&gt;
  bytes from &amp;lt;code&amp;gt;$0304&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;$8000&amp;lt;/code&amp;gt;, then&lt;br /&gt;
  &amp;lt;code&amp;gt;JMP $02A7&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;$02A7&amp;lt;/code&amp;gt;: a tight loop —&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$02A7  JSR $FFA5        ; ACPTR - read one byte from the IEC bus&lt;br /&gt;
$02AA  EOR $AE          ; XOR against the destination pointer's OWN low byte&lt;br /&gt;
                         ;   (a self-referential descramble, not a secret&lt;br /&gt;
                         ;   key - fully determined by address alone)&lt;br /&gt;
$02AC  STA ($AE),Y&lt;br /&gt;
$02AE  ...               ; increment pointer, loop&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  ...continuing until the pointer reaches &amp;lt;code&amp;gt;$075D&amp;lt;/code&amp;gt;. This is why a&lt;br /&gt;
  ''static'' disassembly of &amp;lt;code&amp;gt;$0334&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;$075D&amp;lt;/code&amp;gt; looks like&lt;br /&gt;
  noise: those bytes are overwritten live, streamed byte-by-byte from the&lt;br /&gt;
  drive, before they are ever executed.&lt;br /&gt;
&lt;br /&gt;
Once populated, &amp;lt;code&amp;gt;$0334&amp;lt;/code&amp;gt; onward contains a real, coherent program&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;$05EB&amp;lt;/code&amp;gt; primitive: the real protection gate ==&lt;br /&gt;
&lt;br /&gt;
Deep inside the newly-populated block sits &amp;lt;code&amp;gt;$05EB&amp;lt;/code&amp;gt;, the key&lt;br /&gt;
routine used for every byte of the custom transfer protocol that follows —&lt;br /&gt;
including the destination address the payload gets written through.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$05EB  A9 0A       LDA #$0A            ; border/background = orange (visual cue)&lt;br /&gt;
$05ED  8D 20 D0    STA $D020&lt;br /&gt;
$05F0  8D 21 D0    STA $D021&lt;br /&gt;
$05F3  A5 17       LDA $17&lt;br /&gt;
$05F5  8D 00 DD    STA $DD00           ; write to CIA2 port A (drive-facing)&lt;br /&gt;
$05F8  EE 18 D4    INC $D418           ; SID volume flicker, cosmetic&lt;br /&gt;
$05FB  AD 00 DD    LDA $DD00&lt;br /&gt;
$05FE  10 F8       BPL $05FB           ; wait for bit 7 - a response from the drive&lt;br /&gt;
$0600  AD 12 D0    LDA $D012           ; raster line&lt;br /&gt;
$0603  C9 31       CMP #$31&lt;br /&gt;
$0605  90 06       BCC $060D&lt;br /&gt;
$0607  29 06       AND #$06&lt;br /&gt;
$0609  C9 02       CMP #$02&lt;br /&gt;
$060B  F0 F3       BEQ $0600           ; cycle-accurate raster-synced wait&lt;br /&gt;
$060D  A9 02       LDA #$02&lt;br /&gt;
$060F  8D 20 D0    STA $D020           ; border = red&lt;br /&gt;
$0612  8D 21 D0    STA $D021&lt;br /&gt;
$0615  A5 18       LDA $18&lt;br /&gt;
$0617  8D 00 DD    STA $DD00&lt;br /&gt;
$061A  EA (x9)     NOP                 ; fixed-length timing pad&lt;br /&gt;
$0624  AE 00 DD    LDX $DD00           ; read the port value...&lt;br /&gt;
$0627  BD 00 01    LDA $0100,X         ; ...as an INDEX into a lookup table&lt;br /&gt;
$062A  AE 00 DD    LDX $DD00&lt;br /&gt;
$062D  1D 08 01    ORA $0108,X         ; three more reads, three more tables, OR'd together&lt;br /&gt;
$0630  AE 00 DD    LDX $DD00&lt;br /&gt;
$0633  1D 10 01    ORA $0110,X&lt;br /&gt;
$0636  AE 00 DD    LDX $DD00&lt;br /&gt;
$0639  1D 18 01    ORA $0118,X&lt;br /&gt;
$063C  60          RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This reads CIA2's &amp;lt;code&amp;gt;$DD00&amp;lt;/code&amp;gt; port with cycle-accurate raster-line&lt;br /&gt;
synchronization — structurally the same &amp;quot;cycle-accurate &amp;lt;code&amp;gt;$DD00&amp;lt;/code&amp;gt;&amp;quot;&lt;br /&gt;
handshake mechanism the Cholo/Triaxos track-38 check uses — and decodes the&lt;br /&gt;
drive's response into a byte using four 256-entry lookup tables as a&lt;br /&gt;
nibble/bit decoder.&lt;br /&gt;
&lt;br /&gt;
The four lookup tables at &amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;$0108&amp;lt;/code&amp;gt;/&lt;br /&gt;
&amp;lt;code&amp;gt;$0110&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;$0118&amp;lt;/code&amp;gt; are '''fixed, not disk-derived''': a&lt;br /&gt;
store-watchpoint on that range caught the first write coming from a plain,&lt;br /&gt;
unconditional copy loop (&amp;lt;code&amp;gt;$0725&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;$073F&amp;lt;/code&amp;gt;) that tiles a&lt;br /&gt;
'''fixed''' 28-byte source at &amp;lt;code&amp;gt;$0740&amp;lt;/code&amp;gt;, eight repeats each, into&lt;br /&gt;
&amp;lt;code&amp;gt;$0100&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;$01FF&amp;lt;/code&amp;gt;. They only gate ''whether''&lt;br /&gt;
&amp;lt;code&amp;gt;$05EB&amp;lt;/code&amp;gt; can complete at all; they don't encode a disk-specific&lt;br /&gt;
value.&lt;br /&gt;
&lt;br /&gt;
The transfer this primitive serves uses a &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt;-byte&lt;br /&gt;
escape/terminator framing: a lone &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt; signals end-of-data,&lt;br /&gt;
&amp;lt;code&amp;gt;$01 $01&amp;lt;/code&amp;gt; is an escaped literal &amp;lt;code&amp;gt;$01&amp;lt;/code&amp;gt;, anything else&lt;br /&gt;
is stored directly via &amp;lt;code&amp;gt;STA ($AE),Y&amp;lt;/code&amp;gt; with '''no further&lt;br /&gt;
transformation'''.&lt;br /&gt;
&lt;br /&gt;
=== Verification: a plain D64 hangs, it does not decrypt to garbage ===&lt;br /&gt;
&lt;br /&gt;
Attaching a plain sector-image conversion of this disk (no raw GCR&lt;br /&gt;
track-39 signature present) and running the identical&lt;br /&gt;
&amp;lt;code&amp;gt;LOAD&amp;quot;*&amp;quot;,8,1&amp;lt;/code&amp;gt; sequence, execution reaches &amp;lt;code&amp;gt;$02A7&amp;lt;/code&amp;gt;,&lt;br /&gt;
runs '''identically''' up to this exact point, and then '''hangs&lt;br /&gt;
permanently''' at &amp;lt;code&amp;gt;$05FB&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;$05FE&amp;lt;/code&amp;gt;&lt;br /&gt;
(&amp;lt;code&amp;gt;LDA $DD00&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;BPL $05FB&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
== The signature track: track 39 ==&lt;br /&gt;
&lt;br /&gt;
The signature region is '''not''' at logical track 38 the way it is for&lt;br /&gt;
Cholo/Triaxos. Converting the G64 to text and inspecting it shows physical&lt;br /&gt;
tracks 36–38 are entirely empty (no &amp;lt;code&amp;gt;track N&amp;lt;/code&amp;gt; section at all —&lt;br /&gt;
a real gap), while '''track 39''' has a section with two&lt;br /&gt;
unmistakable markers: its first decoded bytes start with&lt;br /&gt;
&amp;lt;code&amp;gt;69 59 59 A7 A7...&amp;lt;/code&amp;gt; (matching the &amp;lt;code&amp;gt;69 XX XX XX A9&amp;lt;/code&amp;gt;-style&lt;br /&gt;
signature prefix used by every other GMA87 game), and its &amp;lt;code&amp;gt;sync N&amp;lt;/code&amp;gt;&lt;br /&gt;
entries are wildly non-uniform (&amp;lt;code&amp;gt;41, 40, 40, 40, 87, 136, 40, 40&amp;lt;/code&amp;gt;)&lt;br /&gt;
versus a normal track's uniform sync-mark length throughout.&lt;br /&gt;
&lt;br /&gt;
=== Track-seek mechanism: entirely standard DOS ROM code ===&lt;br /&gt;
&lt;br /&gt;
The drive's own &amp;lt;code&amp;gt;DRVTRK&amp;lt;/code&amp;gt; variable (&amp;lt;code&amp;gt;$0022&amp;lt;/code&amp;gt;) was traced&lt;br /&gt;
live across a full load. '''The &amp;lt;code&amp;gt;DRVTRK=39&amp;lt;/code&amp;gt; transition is&lt;br /&gt;
reached via completely standard, unmodified DOS-ROM job-dispatch code.&lt;br /&gt;
&lt;br /&gt;
* The custom drive code's only involvement is submitting an ordinary job&lt;br /&gt;
  (code &amp;lt;code&amp;gt;$E0&amp;lt;/code&amp;gt;, EXECUTE) into the standard job queue with a&lt;br /&gt;
  header-table track value of '''39''' — a value the ROM never validates&lt;br /&gt;
  against the normal 1–35 range.&lt;br /&gt;
* The store into &amp;lt;code&amp;gt;DRVTRK&amp;lt;/code&amp;gt; happens at &amp;lt;code&amp;gt;$F31B&amp;lt;/code&amp;gt;&lt;br /&gt;
  (&amp;lt;code&amp;gt;LDA ($32),Y&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;STA $22&amp;lt;/code&amp;gt;), inside the stock job&lt;br /&gt;
  dispatcher's buffer-scan/mismatch-handling loop — 100% ROM code, reading&lt;br /&gt;
  the out-of-range track value straight out of the job's own header-table&lt;br /&gt;
  entry.&lt;br /&gt;
&lt;br /&gt;
== Stage 1: the track-39 signature-measurement program ==&lt;br /&gt;
&lt;br /&gt;
It turns out to be '''structurally identical to the Cholo/Triaxos&lt;br /&gt;
track-38 algorithm''', just retargeted to Eagles' own signature track (39):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
; ---- sync-marker search, 90-attempt retry budget ----&lt;br /&gt;
$0300  AD 00 1C    LDA $1C00&lt;br /&gt;
$0303  29 9F       AND #$9F&lt;br /&gt;
$0305  8D 00 1C    STA $1C00&lt;br /&gt;
$0308  A0 5A       LDY #$5A            ; Y = 90 - sync-retry budget&lt;br /&gt;
$030A  88          DEY                 ; &amp;lt;-- retry entry point&lt;br /&gt;
$030B  D0 05       BNE $0312&lt;br /&gt;
$030D  A9 02       LDA #$02            ; error $02 = HEADER NOT FOUND&lt;br /&gt;
$030F  4C 69 F9    JMP $F969           ; ERRR - retries exhausted, report failure&lt;br /&gt;
$0312  2C 00 1C    BIT $1C00&lt;br /&gt;
$0315  30 FB       BMI $0312           ; sync-wait poll&lt;br /&gt;
$0317  AD 01 1C    LDA $1C01           ; discard first raw byte after sync&lt;br /&gt;
$031A  B8          CLV&lt;br /&gt;
$031B  A2 04       LDX #$04&lt;br /&gt;
$031D  50 FE       BVC $031D           ; CLV/BVC byte-ready wait (classic 1541 trick)&lt;br /&gt;
$031F  B8          CLV&lt;br /&gt;
$0320  AD 01 1C    LDA $1C01           ; read raw GCR byte&lt;br /&gt;
$0323  9D 00 05    STA $0500,X         ; store into $0500-$0504 (5 bytes)&lt;br /&gt;
$0326  CA          DEX&lt;br /&gt;
$0327  10 F4       BPL $031D&lt;br /&gt;
$0329  C9 A9       CMP #$A9            ; last byte read must be $A9&lt;br /&gt;
$032B  D0 DD       BNE $030A           ; mismatch -&amp;gt; retry&lt;br /&gt;
$032D  AD 04 05    LDA $0504           ; first byte read (2nd overall)&lt;br /&gt;
$0330  C9 69       CMP #$69            ; must be $69&lt;br /&gt;
$0332  D0 D6       BNE $030A           ; mismatch -&amp;gt; retry&lt;br /&gt;
                                        ; signature &amp;quot;69 xx xx xx A9&amp;quot; confirmed&lt;br /&gt;
&lt;br /&gt;
; ---- 10-sample raw pulse-width (flux-jitter) measurement ----&lt;br /&gt;
$0334  A0 00       LDY #$00&lt;br /&gt;
$0336  2C 00 1C    BIT $1C00&lt;br /&gt;
$0339  30 FB       BMI $0336           ; wait for next sync&lt;br /&gt;
$033B  A2 00       LDX #$00&lt;br /&gt;
$033D  E8          INX                 ; &amp;lt;-- pulse-width measurement loop&lt;br /&gt;
$033E  2C 00 1C    BIT $1C00&lt;br /&gt;
$0341  10 FA       BPL $033D           ; count iterations (X) while bit7=0&lt;br /&gt;
$0343  8A          TXA&lt;br /&gt;
$0344  99 00 05    STA $0500,Y         ; store sample[Y]&lt;br /&gt;
$0347  C8          INY&lt;br /&gt;
$0348  C0 0A       CPY #$0A            ; 10 samples total&lt;br /&gt;
$034A  D0 EA       BNE $0336&lt;br /&gt;
&lt;br /&gt;
; ---- fold 10 samples into an 8-bit result via CMP/ROL ----&lt;br /&gt;
$034C  A2 02       LDX #$02            ; sample[0] discarded, sample[1] = reference&lt;br /&gt;
$034E  BD 00 05    LDA $0500,X&lt;br /&gt;
$0351  CD 01 05    CMP $0501           ; compare sample[X] to reference&lt;br /&gt;
$0354  2E 0A 05    ROL $050A           ; roll carry (&amp;gt;=ref-&amp;gt;1, &amp;lt;ref-&amp;gt;0) into result byte&lt;br /&gt;
$0357  E8          INX&lt;br /&gt;
$0358  E0 0A       CPX #$0A            ; samples[2..9], 8 comparisons -&amp;gt; 8-bit result&lt;br /&gt;
$035A  D0 F2       BNE $034E&lt;br /&gt;
$035C  AE 0A 05    LDX $050A           ; X = computed 8-bit result: $95 for this disk&lt;br /&gt;
&lt;br /&gt;
; ---- send the result byte to the C64 via VIA1 $1800, nibble-out ----&lt;br /&gt;
$035F  2C 00 18    BIT $1800&lt;br /&gt;
$0362  10 FB       BPL $035F           ; wait for IEC bus ready&lt;br /&gt;
$0364  A9 10       LDA #$10&lt;br /&gt;
$0366  8D 00 18    STA $1800&lt;br /&gt;
$0369  2C 00 18    BIT $1800&lt;br /&gt;
$036C  30 FB       BMI $0369&lt;br /&gt;
$036E  8A          TXA                 ; A = result byte&lt;br /&gt;
$036F  4A          LSR A               ; \  send high nibble&lt;br /&gt;
$0370  4A          LSR A               ;  |&lt;br /&gt;
$0371  4A          LSR A               ;  |&lt;br /&gt;
$0372  4A          LSR A               ; /&lt;br /&gt;
$0373  8D 00 18    STA $1800&lt;br /&gt;
$0376  0A          ASL A&lt;br /&gt;
$0377  29 0F       AND #$0F&lt;br /&gt;
$0379  8D 00 18    STA $1800&lt;br /&gt;
$037C  8A          TXA&lt;br /&gt;
$037D  29 0F       AND #$0F            ; \  send low nibble&lt;br /&gt;
$037F  8D 00 18    STA $1800           ;  |&lt;br /&gt;
$0382  0A          ASL A               ;  |&lt;br /&gt;
$0383  29 0F       AND #$0F            ;  |&lt;br /&gt;
$0385  8D 00 18    STA $1800           ; /&lt;br /&gt;
$0388  A9 0F       LDA #$0F&lt;br /&gt;
$038A  EA          NOP&lt;br /&gt;
$038B  8D 00 18    STA $1800           ; final bus state&lt;br /&gt;
$038E  A9 01       LDA #$01            ; status $01 = SUCCESS&lt;br /&gt;
$0390  4C 69 F9    JMP $F969           ; ERRR (used generically as &amp;quot;set status, return&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
; ---- self-relocation/patch helper (install-time only, not per-visit) ----&lt;br /&gt;
$0393  38          SEC&lt;br /&gt;
$0394  AD 39 03    LDA $0339&lt;br /&gt;
$0397  E9 E1       SBC #$E1&lt;br /&gt;
$0399  85 FB       STA $FB&lt;br /&gt;
$039B  AD 3A 03    LDA $033A&lt;br /&gt;
$039E  E9 10       SBC #$10&lt;br /&gt;
$03A0  85 FC       STA $FC&lt;br /&gt;
$03A2  A9 8D       LDA #$8D            ; $8D = STA opcode - patches code in place&lt;br /&gt;
$03A4  A0 00       LDY #$00&lt;br /&gt;
$03A6  91 FB       STA ($FB),Y&lt;br /&gt;
$03A8  C8          INY&lt;br /&gt;
$03A9  38          SEC&lt;br /&gt;
$03AA  AD 35 03    LDA $0335&lt;br /&gt;
$03AD  E9 D2       SBC #$D2&lt;br /&gt;
$03AF  91 FB       STA ($FB),Y&lt;br /&gt;
$03B1  C8          INY&lt;br /&gt;
$03B2  AD 36 03    LDA $0336&lt;br /&gt;
$03B5  E9 04       SBC #$04&lt;br /&gt;
$03B7  91 FB       STA ($FB),Y&lt;br /&gt;
$03B9  60          RTS&lt;br /&gt;
&lt;br /&gt;
; ---- self-decrypt the $0300-$0392 block against 3 fixed ROM bytes (anti-static-disasm) ----&lt;br /&gt;
$03BA  A2 00       LDX #$00&lt;br /&gt;
$03BC  BD 00 03    LDA $0300,X&lt;br /&gt;
$03BF  4D 10 F5    EOR $F510&lt;br /&gt;
$03C2  4D 56 F5    EOR $F556&lt;br /&gt;
$03C5  4D 18 C1    EOR $C118&lt;br /&gt;
$03C8  9D 00 03    STA $0300,X&lt;br /&gt;
$03CB  E8          INX&lt;br /&gt;
$03CC  E0 93       CPX #$93            ; $93 = 147 bytes&lt;br /&gt;
$03CE  D0 EC       BNE $03BC&lt;br /&gt;
&lt;br /&gt;
; ---- job setup: target track 39, submit EXECUTE job, check result ----&lt;br /&gt;
$03D0  A9 27       LDA #$27            ; $27 = 39 decimal - THE TARGET TRACK&lt;br /&gt;
$03D2  85 06       STA $06&lt;br /&gt;
$03D4  A9 01       LDA #$01&lt;br /&gt;
$03D6  85 07       STA $07&lt;br /&gt;
$03D8  20 18 C1    JSR $C118           ; (ROM call)&lt;br /&gt;
$03DB  A9 E0       LDA #$E0&lt;br /&gt;
$03DD  85 00       STA $00             ; submit EXECUTE job (buffer 0)&lt;br /&gt;
$03DF  A5 00       LDA $00&lt;br /&gt;
$03E1  30 FC       BMI $03DF           ; wait for job completion&lt;br /&gt;
$03E3  C9 02       CMP #$02&lt;br /&gt;
$03E5  90 06       BCC $03ED           ; status &amp;lt; 2 (success) -&amp;gt; RTS normally&lt;br /&gt;
$03E7  4C E7 03    JMP $03E7           ; status &amp;gt;= 2 (FAILURE) -&amp;gt; INFINITE SELF-LOOP&lt;br /&gt;
$03EA  20 2C C1    JSR $C12C           ; (unreached in the traced path)&lt;br /&gt;
$03ED  60          RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Both failure modes are deliberate, permanent hangs, never wrong output:'''&lt;br /&gt;
if the 5-byte marker doesn't match, the routine retries the sync search up&lt;br /&gt;
to 90 times before giving up with error &amp;lt;code&amp;gt;$02&amp;lt;/code&amp;gt; (&amp;quot;header not&lt;br /&gt;
found&amp;quot;). If the job's returned status is failure, execution at&lt;br /&gt;
&amp;lt;code&amp;gt;$03E7&amp;lt;/code&amp;gt; falls into an infinite self-loop&lt;br /&gt;
(&amp;lt;code&amp;gt;JMP $03E7&amp;lt;/code&amp;gt;) — the drive-side counterpart to the C64-side hangs&lt;br /&gt;
at &amp;lt;code&amp;gt;$05FB&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;$05FE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Measured result byte for this disk capture: &amp;lt;code&amp;gt;$95&amp;lt;/code&amp;gt; (149&lt;br /&gt;
decimal).''' Raw sample buffer at &amp;lt;code&amp;gt;$0500&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;$0509&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;code&amp;gt;12 27 3C 11 12 3D 12 3D 12 3D&amp;lt;/code&amp;gt; (sample[0]=&amp;lt;code&amp;gt;$12&amp;lt;/code&amp;gt;&lt;br /&gt;
discarded, sample[1]=&amp;lt;code&amp;gt;$27&amp;lt;/code&amp;gt; the reference). Hand-verifying the&lt;br /&gt;
&amp;lt;code&amp;gt;CMP&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;ROL&amp;lt;/code&amp;gt; algorithm against these samples&lt;br /&gt;
independently reproduces &amp;lt;code&amp;gt;$95&amp;lt;/code&amp;gt; exactly.&lt;br /&gt;
&lt;br /&gt;
== Stage 1 → C64: &amp;lt;code&amp;gt;$05EB&amp;lt;/code&amp;gt; receives &amp;lt;code&amp;gt;$95&amp;lt;/code&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
The C64 receives the drive's track-39 result via the same&lt;br /&gt;
&amp;lt;code&amp;gt;$05EB&amp;lt;/code&amp;gt; routine documented above (raster-synced &amp;lt;code&amp;gt;$DD00&amp;lt;/code&amp;gt;&lt;br /&gt;
poll, then the 4-lookup-table decode, &amp;lt;code&amp;gt;RTS&amp;lt;/code&amp;gt; at &amp;lt;code&amp;gt;$063C&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The consumer is a separate, small wrapper elsewhere in the&lt;br /&gt;
same code block:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$071F  78          SEI&lt;br /&gt;
$0720  20 EB 05    JSR $05EB&lt;br /&gt;
$0723  58          CLI&lt;br /&gt;
$0724  60          RTS ; A=$95, SP=$FB&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This returns to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$03B9  8D 6E 05    STA $056E      ; A=$95 (unchanged), SP=$FF&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The &amp;lt;code&amp;gt;M-W&amp;lt;/code&amp;gt; upload: staging a fresh drive-side program ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;$056E&amp;lt;/code&amp;gt; is not a destination in its own right — it is offset&lt;br /&gt;
&amp;lt;code&amp;gt;$5D&amp;lt;/code&amp;gt; (93 decimal) inside a larger, 224-byte C64-RAM buffer&lt;br /&gt;
based at &amp;lt;code&amp;gt;$0511&amp;lt;/code&amp;gt;. That buffer gets uploaded to the drive, 32&lt;br /&gt;
bytes at a time, via a sequence of standard 1541 DOS '''&amp;lt;code&amp;gt;M-W&amp;lt;/code&amp;gt;&lt;br /&gt;
(memory-write)''' command-channel commands:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
; ---- open the drive's command channel (LFN=15, dev=8, SA=15) ----&lt;br /&gt;
$06D4  20 BD FF    JSR $FFBD          ; SETNAM&lt;br /&gt;
$06D7  A9 0F       LDA #$0F           ; A = 15&lt;br /&gt;
$06D9  A8          TAY                ; Y = 15 (secondary address = command channel)&lt;br /&gt;
$06DA  A2 08       LDX #$08           ; X = 8 (device 8)&lt;br /&gt;
$06DC  20 BA FF    JSR $FFBA          ; SETLFS(LFN=15, dev=8, SA=15)&lt;br /&gt;
$06DF  20 C0 FF    JSR $FFC0          ; OPEN&lt;br /&gt;
$06E2  A2 0F       LDX #$0F&lt;br /&gt;
$06E4  20 C9 FF    JSR $FFC9          ; CHKOUT(15)&lt;br /&gt;
$06E7  A9 4D       LDA #$4D / JSR $FFD2   ; CHROUT 'M'&lt;br /&gt;
$06EC  A9 2D       LDA #$2D / JSR $FFD2   ; CHROUT '-'&lt;br /&gt;
$06F1  60          RTS                ; &amp;quot;M-&amp;quot; sent so far&lt;br /&gt;
&lt;br /&gt;
; ---- complete the M-W command header and send one 32-byte chunk ----&lt;br /&gt;
$0644  20 D2 06    JSR $06D2          ; (the &amp;quot;M-&amp;quot; open routine above)&lt;br /&gt;
$0647  A9 57       LDA #$57 / JSR $EDDD   ; 'W'  -&amp;gt; command so far: &amp;quot;M-W&amp;quot;&lt;br /&gt;
$064C  A5 17       LDA $17 / JSR $EDDD    ; address LOW byte  (running offset:&lt;br /&gt;
                                           ;   $00,$20,$40,$60,$80,$A0,$C0)&lt;br /&gt;
$0651  A9 03       LDA #$03 / JSR $EDDD   ; address HIGH byte (fixed: page $03)&lt;br /&gt;
$0656  A9 20       LDA #$20 / JSR $EDDD   ; count = $20 (32 bytes), fixed&lt;br /&gt;
$065B  A4 17       LDY $17&lt;br /&gt;
$065D  18          CLC&lt;br /&gt;
$065E  A5 17       LDA $17&lt;br /&gt;
$0660  69 20       ADC #$20           ; running offset += $20 for next pass&lt;br /&gt;
$0662  85 17       STA $17&lt;br /&gt;
$0664  B9 11 05    LDA $0511,Y        ; &amp;lt;-- payload byte Y of the upload buffer&lt;br /&gt;
$0667  20 DD ED    JSR $EDDD          ; send it&lt;br /&gt;
$066A  C8          INY&lt;br /&gt;
$066B  C4 17       CPY $17&lt;br /&gt;
$066D  D0 F5       BNE $0664          ; loop for all 32 bytes of this chunk&lt;br /&gt;
$066F  20 CC FF    JSR $FFCC          ; CLRCHN&lt;br /&gt;
$0672  A5 17       LDA $17&lt;br /&gt;
$0674  C9 DA       CMP #$DA           ; $DA = 218 decimal&lt;br /&gt;
$0676  90 CC       BCC $0644          ; more chunks needed -&amp;gt; loop&lt;br /&gt;
$0678  ...                            ; upload complete (7 chunks, 224 bytes)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each pass sends one complete &amp;lt;code&amp;gt;M-W $03xx $20 &amp;amp;lt;32 bytes&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
command. Seven passes, at running offsets&lt;br /&gt;
&amp;lt;code&amp;gt;$00,$20,$40,$60,$80,$A0,$C0&amp;lt;/code&amp;gt;, upload &amp;lt;code&amp;gt;$E0&amp;lt;/code&amp;gt; (224)&lt;br /&gt;
bytes total, covering drive RAM &amp;lt;code&amp;gt;$0300&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;$03DF&amp;lt;/code&amp;gt;.&lt;br /&gt;
'''The &amp;lt;code&amp;gt;$0511&amp;lt;/code&amp;gt; buffer is a full replacement copy of the next&lt;br /&gt;
drive-side job program, staged in C64 RAM and pushed to the drive one&lt;br /&gt;
&amp;lt;code&amp;gt;M-W&amp;lt;/code&amp;gt; chunk at a time.'''&lt;br /&gt;
&lt;br /&gt;
Since &amp;lt;code&amp;gt;$056E&amp;lt;/code&amp;gt; sits at buffer offset &amp;lt;code&amp;gt;$5D&amp;lt;/code&amp;gt;, inside the&lt;br /&gt;
'''third''' 32-byte chunk (offsets &amp;lt;code&amp;gt;$40&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;$5F&amp;lt;/code&amp;gt;,&lt;br /&gt;
destined for drive addresses &amp;lt;code&amp;gt;$0340&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;$035F&amp;lt;/code&amp;gt;), the&lt;br /&gt;
measured signature byte lands at drive address&lt;br /&gt;
&amp;lt;code&amp;gt;$0300 + $5D = $035D&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Stage 2: the uploaded drive-side program, with &amp;lt;code&amp;gt;$95&amp;lt;/code&amp;gt; marked ==&lt;br /&gt;
&lt;br /&gt;
Uploaded specifically to decrypt and stream the actual game&lt;br /&gt;
data:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
; ---- read a full GCR-encoded sector from the VIA into a 256-byte buffer ----&lt;br /&gt;
$0300  A9 06       LDA #$06&lt;br /&gt;
$0302  85 31       STA $31&lt;br /&gt;
$0304  20 0A F5    JSR $F50A          ; seek/prep (1541 KERNAL DSTRT)&lt;br /&gt;
$0307  50 FE       BVC $0307          ; wait for VIA SR byte-ready&lt;br /&gt;
$0309  B8          CLV&lt;br /&gt;
$030A  AD 01 1C    LDA $1C01          ; read GCR byte from VIA2&lt;br /&gt;
$030D  99 00 06    STA $0600,Y&lt;br /&gt;
$0310  C8          INY&lt;br /&gt;
$0311  D0 F4       BNE $0307          ; fill $0600-$06FF (256 bytes)&lt;br /&gt;
&lt;br /&gt;
$0313  A0 BA       LDY #$BA&lt;br /&gt;
$0315  50 FE       BVC $0315&lt;br /&gt;
$0317  B8          CLV&lt;br /&gt;
$0318  AD 01 1C    LDA $1C01&lt;br /&gt;
$031B  99 00 01    STA $0100,Y&lt;br /&gt;
$031E  C8          INY&lt;br /&gt;
$031F  D0 F4       BNE $0315          ; fill $01BA-$01FF (70 bytes, stack page)&lt;br /&gt;
&lt;br /&gt;
; ---- decode GCR, verify header track and checksum (standard DOS ROM calls) ----&lt;br /&gt;
$0321  20 E0 F8    JSR $F8E0          ; GCRBIN&lt;br /&gt;
$0324  A5 38       LDA $38&lt;br /&gt;
$0326  C5 47       CMP $47            ; header track check&lt;br /&gt;
$0328  F0 04       BEQ $032E&lt;br /&gt;
$032A  A9 04       LDA #$04&lt;br /&gt;
$032C  D0 4E       BNE $037C          ; -&amp;gt; error, status $04&lt;br /&gt;
&lt;br /&gt;
$032E  20 E9 F5    JSR $F5E9          ; CHKBLK&lt;br /&gt;
$0331  C5 3A       CMP $3A            ; checksum check&lt;br /&gt;
$0333  F0 04       BEQ $0339&lt;br /&gt;
$0335  A9 05       LDA #$05&lt;br /&gt;
$0337  D0 43       BNE $037C          ; -&amp;gt; error, status $05&lt;br /&gt;
&lt;br /&gt;
; ---- header fields decrypted with FIXED, disk-independent ROM constants ----&lt;br /&gt;
$0339  AD 01 06    LDA $0601&lt;br /&gt;
$033C  4D 77 F5    EOR $F577          ; byte-count field&lt;br /&gt;
$033F  8D 01 06    STA $0601&lt;br /&gt;
$0342  85 07       STA $07&lt;br /&gt;
$0344  A0 02       LDY #$02&lt;br /&gt;
$0346  A2 FF       LDX #$FF&lt;br /&gt;
$0348  AD 00 06    LDA $0600&lt;br /&gt;
$034B  4D 76 F5    EOR $F576          ; status/type byte&lt;br /&gt;
$034E  8D 00 06    STA $0600&lt;br /&gt;
$0351  F0 03       BEQ $0356&lt;br /&gt;
$0353  8E 01 06    STX $0601&lt;br /&gt;
$0356  EE 01 06    INC $0601&lt;br /&gt;
&lt;br /&gt;
; ---- ****** THE PER-BYTE DATA DECRYPTION LOOP ****** ----&lt;br /&gt;
$0359  B9 00 06    LDA $0600,Y&lt;br /&gt;
$035C  49 95       EOR #$95           ; &amp;lt;====== HERE. The measured&lt;br /&gt;
                                       ;   flux-jitter signature byte, INJECTED&lt;br /&gt;
                                       ;   by the M-W upload above, sits as the&lt;br /&gt;
                                       ;   immediate operand of this EOR at&lt;br /&gt;
                                       ;   drive address $035D. Every data byte&lt;br /&gt;
                                       ;   of every subsequent sector is&lt;br /&gt;
                                       ;   decrypted with THIS key, on the&lt;br /&gt;
                                       ;   drive's own 6502, before ever being&lt;br /&gt;
                                       ;   sent to the C64.&lt;br /&gt;
$035E  AA          TAX&lt;br /&gt;
$035F  E0 01       CPX #$01&lt;br /&gt;
$0361  D0 03       BNE $0366&lt;br /&gt;
$0363  20 91 03    JSR $0391          ; send nibble (bit-bang $1800)&lt;br /&gt;
$0366  20 91 03    JSR $0391          ; send nibble&lt;br /&gt;
$0369  C8          INY&lt;br /&gt;
$036A  CC 01 06    CPY $0601&lt;br /&gt;
$036D  D0 EA       BNE $0359          ; loop over the whole decrypted data block&lt;br /&gt;
&lt;br /&gt;
; ---- end-of-block housekeeping / next-sector dispatch ----&lt;br /&gt;
$036F  AD 00 06    LDA $0600&lt;br /&gt;
$0372  F0 0E       BEQ $0382&lt;br /&gt;
$0374  C5 06       CMP $06&lt;br /&gt;
$0376  85 06       STA $06&lt;br /&gt;
$0378  F0 05       BEQ $037F&lt;br /&gt;
$037A  A9 01       LDA #$01&lt;br /&gt;
$037C  4C 69 F9    JMP $F969          ; job dispatcher / error exit&lt;br /&gt;
$037F  4C 04 03    JMP $0304          ; loop back for next GCR block&lt;br /&gt;
&lt;br /&gt;
$0382  A2 01       LDX #$01&lt;br /&gt;
$0384  20 91 03    JSR $0391&lt;br /&gt;
$0387  A2 02       LDX #$02&lt;br /&gt;
$0389  20 91 03    JSR $0391&lt;br /&gt;
$038C  A9 7F       LDA #$7F&lt;br /&gt;
$038E  4C 69 F9    JMP $F969          ; job status $7F = done/OK&lt;br /&gt;
&lt;br /&gt;
; ---- $0391: the same $1800 bit-bang nibble-send routine used by Stage 1 ----&lt;br /&gt;
$0391  2C 00 18    BIT $1800&lt;br /&gt;
$0394  10 FB       BPL $0391&lt;br /&gt;
$0396  A9 10       LDA #$10&lt;br /&gt;
$0398  8D 00 18    STA $1800&lt;br /&gt;
$039B  2C 00 18    BIT $1800&lt;br /&gt;
$039E  30 FB       BMI $039B&lt;br /&gt;
$03A0  8A          TXA&lt;br /&gt;
$03A1  4A          LSR A&lt;br /&gt;
$03A2  4A          LSR A&lt;br /&gt;
$03A3  4A          LSR A&lt;br /&gt;
$03A4  4A          LSR A&lt;br /&gt;
$03A5  8D 00 18    STA $1800&lt;br /&gt;
$03A8  0A          ASL A&lt;br /&gt;
$03A9  29 0F       AND #$0F&lt;br /&gt;
$03AB  8D 00 18    STA $1800&lt;br /&gt;
$03AE  8A          TXA&lt;br /&gt;
$03AF  29 0F       AND #$0F&lt;br /&gt;
$03B1  8D 00 18    STA $1800&lt;br /&gt;
$03B4  0A          ASL A&lt;br /&gt;
$03B5  29 0F       AND #$0F&lt;br /&gt;
$03B7  8D 00 18    STA $1800&lt;br /&gt;
$03BA  A9 0F       LDA #$0F&lt;br /&gt;
$03BD  8D 00 18    STA $1800&lt;br /&gt;
$03C0  60          RTS&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''This is the actual decryption mechanism for the game's data payload.'''&lt;br /&gt;
The block's own header fields (byte count, status/type byte) are&lt;br /&gt;
&amp;quot;decrypted&amp;quot; with '''fixed, disk-independent''' constants pulled straight&lt;br /&gt;
from the drive's own ROM (&amp;lt;code&amp;gt;$F576&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;$F577&amp;lt;/code&amp;gt;) — plain&lt;br /&gt;
obfuscation, not keyed to this disk at all. Every actual '''data''' byte,&lt;br /&gt;
by contrast, is decrypted with &amp;lt;code&amp;gt;$95&amp;lt;/code&amp;gt; — the disk-specific,&lt;br /&gt;
sync length variation signature — inside the loop at&lt;br /&gt;
&amp;lt;code&amp;gt;$0359&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;$036D&amp;lt;/code&amp;gt;, entirely on the drive, before the&lt;br /&gt;
byte is ever placed on the serial bus. The C64 receives only&lt;br /&gt;
already-decrypted plaintext through the same &amp;lt;code&amp;gt;$0391&amp;lt;/code&amp;gt; nibble-out&lt;br /&gt;
routine documented for Stage 1.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[GMA87]]&lt;/div&gt;</summary>
		<author><name>Enigma</name></author>
		
	</entry>
</feed>