erc-c/data/disk2.asm

264 lines
12 KiB
NASM

; 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.
;
; For details on the assembly instructions--what they mean and do--this
; is a good resource:
; http://www.e-tradition.net/bytes/6502/6502_instruction_set.html
;
; Any number that has a $ in front of it means it's a hex number, vs.
; decimal.
; Our definitions for this little program. The EQU symbol is not a
; formal instruction understood by the 6502 CPU; it's a notation that
; simply means "equals"; e.g. GBASL equals $26.
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
; 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
; In at least one implementation (notably WinApple), the opcode below is
; rewritten as `A9 00 EA`, which is equivalent to:
; LDA #$00
; NOP
; This would essentially remove the WAIT call. The WAIT subroutine will,
; in the course of its operation, leave $00 in A, which explains the LDA
; #$00 opcode sequence. The NOP is there to replace the third byte
; (which was part of the JSR address in its original form).
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 $0900
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!