diff --git a/data/disk2.asm b/data/disk2.asm index c210c45..b353e71 100644 --- a/data/disk2.asm +++ b/data/disk2.asm @@ -1,145 +1,245 @@ - GBASL EQU $26 - GBASH EQU $27 - BAS2H EQU $2B - A1L EQU $3C - A1H EQU $3D - A3L EQU $40 - A3H EQU $41 - STACK EQU $0100 - OFFPH0 EQU $C080 - ONPH0 EQU $C081 - TURNON EQU $C089 - SLCTD1 EQU $C08A - READ EQU $C08C - SETRD EQU $C08E - WAIT EQU $FCA8 - IMMRTS EQU $FF58 -00:A2 20 LDX #$20 -02:A0 00 LDY #$00 -04:A2 03 LDX #$03 -06:86 3C SAVTMP STX A1L -08:8A TXA -09:0A ASL A -0A:24 3C BIT A1L -0C:F0 10 BEQ INCX -0E:05 3C ORA A1L -10:49 FF EOR #$FF -12:29 7E AND #$7E -14:B0 08 HASCRY BCS INCX -16:4A LSR A -17:D0 FB BNE HASCRY -19:98 TYA -1A:9D 56 03 STA $0356,X -1D:C8 INY -1E:E8 INCX INX -1F:10 E5 BPL SAVTMP -21:20 58 FF JSR IMMRTS -24:BA TSX -25:BD 00 01 LDA STACK,X -28:0A ASL -29:0A ASL -2A:0A ASL -2B:0A ASL -2C:85 2B STA $2B -2E:AA TAX -2F:BD 8E C0 LDA SETRD,X -32:BD 8C C0 LDA READ,X -35:BD 8A C0 LDA SLCTD1,X -38:BD 89 C0 LDA TURNON,X -3B:A0 50 LDY #$50 -3D:BD 80 C0 LDA OFFPH0,X -40:98 TYA -41:29 03 AND #$03 -43:0A ASL -44:05 2B ORA $2B -46:AA TAX -47:BD 81 C0 LDA ONPH0,X -4A:A9 56 LDA #$56 -4C:20 A8 FC JSR WAIT -4F:88 DEY -50:10 EB BPL [3d] -52:85 26 STA GBASL -54:85 3D STA A1H -56:85 41 STA A3H -58:A9 08 LDA #$08 -5A:85 27 STA GBASH -5C:18 CLC -5D:08 PHP -5E:BD 8C C0 LDA READ,X -61:10 FB BPL [5e] -63:49 D5 EOR #$D5 -65:D0 F7 BNE [5e] -67:BD 8C C0 LDA READ,X -6A:10 FB BPL [67] -6C:C9 AA CMP #$AA -6E:D0 F3 BNE [63] -70:EA NOP -71:BD 8C C0 LDA READ,X -74:10 FB BPL [71] -76:C9 96 CMP #$96 -78:F0 09 BEQ [83] -7A:28 PLP -7B:90 DF BCC [5c] -7D:49 AD EOR #$AD -7F:F0 25 BEQ [a6] -81:D0 D9 BNE [5c] +; disk2.asm +; +; This is the DISASSEMBLED source code for the Disk II controller ROM. +; It adds up to 256 bytes of program code, which is all any peripheral +; card was afforded. +; +; NOTE THAT THIS SOURCE CODE IS NOT ORIGINAL TO APPLE. I translated by +; hand from the machine code in the ROM. Any comments, etc. you see +; here, are from me--NOT APPLE. -83:A0 03 LDY #$03 -85:85 40 STA A3L -87:BD 8C C0 LDA READ,X -8A:10 FB BPL [87] -8C:2A ROL A -8D:85 3C STA A1L -8F:BD 8C C0 LDA READ,X -92:10 FB BPL [8f] -94:25 3C AND A1L -96:88 DEY -97:D0 EC BNE [85] -99:28 PLP -9A:C5 3D CMP A1H -9C:D0 BE BNE [5c] -9E:A5 40 LDA A3L -A0:C5 41 CMP A3H -A2:D0 B8 BNE [5c] -A4:B0 B7 BCS [5d] ;; weird +; Our definitions for this little program + GBASL EQU $26 + GBASH EQU $27 + BAS2H EQU $2B + A1L EQU $3C + A1H EQU $3D + A3L EQU $40 + A3H EQU $41 + STACK EQU $0100 + GCRALT EQU $02D6 + XORSAV EQU $0300 + GCRTAB EQU $0356 + ENTRY EQU $0800 + PHASEOFF EQU $C080 + PHASEON EQU $C081 + TURNON EQU $C089 + SLCTD1 EQU $C08A + READ EQU $C08C + SETRD EQU $C08E + WAIT EQU $FCA8 + FINDSLOT EQU $FF58 -A6:A0 56 LDY #$56 -A8:84 3C STY A1L -AA:BC 8C C0 LDY READ,X -AD:10 FB BPL [aa] -AF:59 D6 02 EOR $02D6,X -B2:A4 3C LDY A1L -B4:88 DEY -B5:99 00 03 STA $0300,Y -B8:D0 EE BNE [a8] -BA:84 3C STY A1L -BC:BC 8C C0 LDY READ,X -BF:10 FB BPL [bc] -C1:59 D6 02 EOR $02D6,X -C4:A4 3C LDY A1L -C6:91 26 STA (GBASL),Y -C8:C8 INY -C9:D0 EF BNE [ba] -CB:BC 8C C0 LDY READ,X -CE:10 FB BPL [cb] -D0:59 D6 02 EOR $02D6,X -D3:D0 87 BNE [5c] -D5:A0 00 LDY #$00 -D7:A2 56 LDX #$56 -D9:CA DEX -DA:30 FB BMI [d7] -DC:B1 26 LDA (GBASL),Y -DE:5E 00 03 LSR $0300,X -E1:2A ROL A -E2:5E 00 03 STA (GBASL),Y -E5:2A ROL A -E6:91 26 STA (GBASL),Y -E8:C8 INY -E9:D0 EE BNE [d9] -EB:E6 27 INC GBASH -ED:E6 3D INC A1H -EF:A5 3D LDA A1H -F1:CD 00 08 CMP $0800 -F4:A6 2B LDX $2B -F6:90 DB BCC [d3] -F8:4C 01 08 JMP $0801 +; This is not needed by the disk controller program itself, but is used +; by the system ROM to determine if there is a valid controller program +; here. (There is!) +00:A2 20 LDX #$20 + +; Here we will write the group coded recording table for our decode +; process, which is in the GCRTAB address. +02:A0 00 LDY #$00 +04:A2 03 LDX #$03 ; our loop begins at $03 +06:86 3C NEXTGCR STX A1L ; A1L tracks the loop counter +08:8A TXA +09:0A ASL A +0A:24 3C BIT A1L ; if X and X<<1 have no bits in common +0C:F0 10 BEQ CONTGCR ; then X will not be written into GCRTAB + +; This sequence of operations will prime A for the VALIDENT check. Any +; valid X register value (from which A is derived) will be one where +; these three operations results in $40; after we loop on VALIDENT and +; shift A to the right a bunch of times, we'll end up with $00 and exit +; the loop without tripping the BCS (because none of the first 6 bits +; were ever high). +0E:05 3C ORA A1L +10:49 FF EOR #$FF +12:29 7E AND #$7E +14:B0 08 VALIDENT BCS CONTGCR +16:4A LSR A +17:D0 FB BNE VALIDENT + +; Only certain X register values will be written via the STA +; instruction; what we do write is an iteration of Y from $00..$3F. +19:98 TYA +1A:9D 56 03 STA GCRTAB,X +1D:C8 INY +1E:E8 CONTGCR INX +1F:10 E5 BPL NEXTGCR + +; All this wrangling is here to make a record of the slot number. +; Because JSR will push the calling address into the stack, we can find +; the MSB of that address with the LDA STACK,X instruction. All of the +; ASLs will essentially push the 7 one hex digit over, so $C7 becomes +; $70. And we store that in BAS2H so we can use it to run operations on +; the peripheral. +21:20 58 FF JSR FINDSLOT +24:BA TSX +25:BD 00 01 LDA STACK,X ; this will load $C7 into A +28:0A ASL +29:0A ASL +2A:0A ASL +2B:0A ASL ; and now we have $70 +2C:85 2B STA BAS2H + +; Ok, with that done, we're going to get everything set up to copy the +; zero track into RAM. NOTE: I'm not entirely sure why we're doing a +; READ from the drive before we know we have drive 1 selected and turned +; on. +2E:AA TAX +2F:BD 8E C0 LDA SETRD,X +32:BD 8C C0 LDA READ,X +35:BD 8A C0 LDA SLCTD1,X +38:BD 89 C0 LDA TURNON,X + +; This loop is going to go through the stepper motor phases, flipping +; them off and on again. To begin with, X is $70, so we're going to work +; with phase 0 at the start. +3B:A0 50 LDY #$50 +3D:BD 80 C0 PHASELOOP LDA PHASEOFF,X +40:98 TYA +41:29 03 AND #$03 ; drop all but the first 2 bits +43:0A ASL ; and shift over +44:05 2B ORA BAS2H ; and add that to $70 +46:AA TAX +47:BD 81 C0 LDA PHASEON,X +4A:A9 56 LDA #$56 +4C:20 A8 FC JSR WAIT ; wait for the motor +4F:88 DEY +50:10 EB BPL PHASELOOP + +; We're setting things up so we can start writing our decoded data into +; the $08 page in memory, which is where we will ultimately jump to once +; we finish going through track zero. +52:85 26 STA GBASL ; A is $00 by this point +54:85 3D STA A1H +56:85 41 STA A3H +58:A9 08 LDA #$08 +5A:85 27 STA GBASH ; so GBASH/L will hold $0800 + +; We're going to check to see if we are at a header marker. +5C:18 CHKHD CLC +5D:08 CHKHDC PHP ; hang onto the status for later + +; Read byte from the disk (BPL is used here because anything that +; doesn't have bit 7 high is bad data in 6-and-2 encoding). +5E:BD 8C C0 READHD1 LDA READ,X +61:10 FB BPL READHD1 +63:49 D5 CHKHD1 EOR #$D5 +65:D0 F7 BNE READHD1 ; try again + +; Look for the second header byte +67:BD 8C C0 READHD2 LDA READ,X +6A:10 FB BPL READHD2 +6C:C9 AA CHKHD2 CMP #$AA +6E:D0 F3 BNE CHKHD1 +70:EA NOP ; I don't know why we NOP here + +; Third header byte +71:BD 8C C0 READHD3 LDA READ,X +74:10 FB BPL READHD3 +76:C9 96 CMP #$96 ; is this the end of a track marker? +78:F0 09 BEQ METADATA ; seems to be! +7A:28 PLP +7B:90 DF BCC CHKHD ; if A < $96, keep seeking for a header byte +7D:49 AD EOR #$AD ; if NOT, then this might be the end of a sector header +7F:F0 25 BEQ DECODE ; so let's get decoding! +81:D0 D9 BNE CHKHD ; Some other byte we didn't expect... + +; The metadata is 4-and-4 encoded, which are two bytes that are read in +; sequence and then AND'd together. The second in the sequence is what +; will stay behind in A3L; we'll read 3 sequences in all. +83:A0 03 METADATA LDY #$03 +85:85 40 AGAIN44 STA A3L +87:BD 8C C0 FIRST44 LDA READ,X ; read a byte +8A:10 FB BPL FIRST44 +8C:2A ROL A +8D:85 3C STA A1L +8F:BD 8C C0 SECOND44 LDA READ,X ; read another byte +92:10 FB BPL SECOND44 +94:25 3C AND A1L ; intersect with the shifted FIRST44 +96:88 DEY +97:D0 EC BNE AGAIN44 + +; This is going to pull from before we began checking for a header +99:28 PLP +9A:C5 3D CMP A1H +9C:D0 BE BNE CHKHD + +; A3H can only be $00, and A3L will have been $96 from the last header +; byte we read; since $96 - $00 will of course not be zero, this will +; force a branch back to CHKHD. Why we have this code here is unclear to +; me. +9E:A5 40 LDA A3L +A0:C5 41 CMP A3H +A2:D0 B8 BNE CHKHD + +; If C is set, we will jump back to read the next header, _but_ we will +; not execute the CLC instruction. +A4:B0 B7 BCS CHKHDC + +; As we decode bytes, we're referencing the GCRTAB entries we built +; earlier but from a slightly different address point (hence GCRALT). +; But make no mistake--we're EORing with GCRTAB data. Note that XORSAV +; is an entry point ($0300) which is conveniently(!) $56 less than +; GCRTAB ($0356). It is, though, really just a place to stash the +; intermediate data. +A6:A0 56 DECODE LDY #$56 ; loop this many times... +A8:84 3C SAV2BITS STY A1L ; save in A1L, because we use Y to read +AA:BC 8C C0 DECBYTE2 LDY READ,X +AD:10 FB BPL DECBYTE +AF:59 D6 02 EOR GCRALT,Y +B2:A4 3C LDY A1L +B4:88 DEY ; decrement the loop counter +B5:99 00 03 STA XORSAV,Y ; hang onto the EOR data +B8:D0 EE BNE SAV2BITS + +; Looping from zero, now, we're going to write all that intermediate +; data into the $0800 page (which is what (GBASL),Y resolves to), +; counting up from $0800..$08FF. +BA:84 3C SAV6BITS STY A1L +BC:BC 8C C0 DECBYTE6 LDY READ,X +BF:10 FB BPL DECBYTE6 +C1:59 D6 02 EOR GCRALT,Y +C4:A4 3C LDY A1L +C6:91 26 STA (GBASL),Y +C8:C8 INY +C9:D0 EF BNE SAV6BITS + +; We read ONE more byte, then determine if we need to check for another +; header again. +CB:BC 8C C0 FINBYTE LDY READ,X +CE:10 FB BPL FINBYTE +D0:59 D6 02 EOR XORTMP,Y + +; We may also get to here because it looks like we didn't write data +; properly into the ENTRY page. +D3:D0 87 BADDATA BNE CHKHD ; another sector? + +; We're using the first 89 ($56) bytes in XORSAV (which, remember, is +; $56 less than the GCRTAB address point); if we go below $00 (rolling +; over to $FF), start over. +; +; The bytes we've already written into the ENTRY page need to have those +; 2 bits we compiled into those 89 bytes pushed back into the data. +D5:A0 00 LDY #$00 +D7:A2 56 BITLOOP LDX #$56 +D9:CA WRITELOOP DEX +DA:30 FB BMI BITLOOP ; start over if we went past $00 +DC:B1 26 LDA (GBASL),Y ; load $0800 + Y +DE:5E 00 03 LSR XORSAV,X ; move bit 0 into carry +E1:2A ROL A ; now load carry into A, plus the orig contents +E2:5E 00 03 LSR XORSAV,X ; shift the former bit 1 (now bit 0) into carry again +E5:2A ROL A ; and again load into A; now we have all 8 bits +E6:91 26 STA (GBASL),Y ; and save it back to $0800 + Y +E8:C8 INY +E9:D0 EE BNE WRITELOOP ; we'll loop here 256 times + +; We're in the home stretch... we're just double-checking if we copied +; things into the ENTRY page properly. +EB:E6 27 INC GBASH ; so now GBASL/H is $0801 +ED:E6 3D INC A1H +EF:A5 3D LDA A1H +F1:CD 00 08 CMP ENTRY ; if A < ENTRY +F4:A6 2B LDX BAS2H +F6:90 DB BCC BADDATA ; then go back and try again +F8:4C 01 08 JMP ENTRY+1 ; otherwise, let's boot the software!