Files
Andrew Plotkin b642da811e Initial commit.
2023-11-16 18:19:54 -05:00

993 lines
20 KiB
NASM

PAGE
SBTTL "--- BOOT CODE & RWTS: APPLE II ---"
; ---------
; BOOT CODE
; ---------
; LOADS ALL OF TRACK 0 INTO RAM AT $800 TO $1800,
; THEN JUMPS THROUGH [COLD]
ORG BORG ; (EZIP)
DB 01 ; MAGICAL MYSTERY BYTE
; BOOT BEGINS HERE
BOOT: ;THIS LABLE NEVER USED BUT MUST BE HERE
LDA BADDR+HI ; CHECK MSB OF BOOT ADDRESS
CMP #$09 ; 1ST ENTRY INTO BOOT?
BNE BOOTS0 ; NO, CONTINUE
; CALC ADDRESS OF ROM SECTOR READ ROUTINE
LDA #$D0
STA BADDR+HI
;MOVMON
LDA $C089 ;SET TO READ ROM WRITE RAM
LDA $C089 ; MUST READ TWICE TO TURN SWITCH ON
LDY #0 ; COPY MONITOR RTNS TO RAM
LDA #$F8 ; SO DON'T NEED TO ACCESS ROM
STA I+HI
LDA #0
STA I+LO
BOOTLP: LDA (I),Y ; READ FROM ROM
STA (I),Y ; WRITE TO RAM
INY
BNE BOOTLP ; 256 COUNT
INC I+HI ; THROUGH PG $FF
BNE BOOTLP
LDA $C08B ; SET TO R/W RAM, BANK 1
LDA $C08B ; MUST READ 2CE
LDA BSLOT ; GET SLOT ID * 16
STA DCBSLT ; MAKE IT THE DEFAULT TARGET
STA DCBPSL ; AND THE "OLD" SLOT
LSR A ; DIVIDE BY 16
LSR A
LSR A
LSR A
ORA #%11000000 ; MAKE IT $C0nn
STA I+HI ; USE AS MSB OF ADDRESS
LDA #$5C ; LSB IS ALWAYS $5C
STA I+LO
LDA #1
STA DCBSEC
BOOTS0: LDX DCBSEC
INC DCBSEC
CPX #$10
BCS BOOTS1
LDA ILEAVE,X
STA BSECT
LDX BSLOT
JMP (I)
BOOTS1: JSR INIT
JMP COLD ; LOAD REMAINDER OF ZIP
; ---------------------
; SECTOR INTERLEAVE MAP
; ---------------------
; USED BY "BOOT" (AND "RWTS" (NOT THIS W/ EZIP))
; MUST BE IN 1ST PAGE!
ILEAVE: DB $00,$04,$08,$0C,$01,$05,$09,$0D
DB $02,$06,$0A,$0E,$03,$07,$0B,$0F
;
;
; RAMDSK
; THIS CODE IS DESIGNED TO RESIDE
; IN MAIN 48K *ABOVE PAGE 2*
;
; ON ENTRY IT ASSUMES THAT MAIN
; BANK 1 IS ENABLED
; A = SECTOR - $00=LOW $4F
; Y = PAGE TO READ/WRITE
; TO/FROM
; X = ON ENTRY 1=WRITE
; 0=READ
; RMDBNK - 48K BANK TO READ TO
; AUX OR MAIN
; THE RAMDISK CAN ONLY WRITE FROM
; MAIN MEMORY (ACTUALLY FROM THE BANK THIS CODE IS IN)
; SECTOR MAP
; $00=LOW $0F IN MAIN BANK 2
; $10=LOW $1F IN AUX BANK 2
; $20=LOW $4F IN AUX BANK 1
RMDBNK: DB 00 ;RREMEMBER WHAT BANK THIS IS IN WHEN YOU SET IT
RAMDSK: STY WRTBNK+MAIN ;WRITE TO MAIN 48K BANK (WHERE THIS CODE IS)
STY WRDADD+1+HI ;SAVE HIGH ADDRESS FOR EITHER
STY RAMLOOP+1+HI ;READ OR WRITE
CMP #$10
BCS RAM1
LDY BNK2SET ;IN MAIN BANK 2
LDY BNK2SET ;ENABLE BANK 2 WITH TWO READS
ADC #$D0 ;C=0 , ALIGN SECTOR INTO RAM
BNE RAMDO
RAM1: STA ALTZP+AUX ;IT IS IN AUX RAM
CMP #$20 ;BANK 1 OR 2 ???
BCS RAM2
LDY BNK2SET ;IN AUX BANK 2
LDY BNK2SET ;ENABLE BANK 2
ADC #$C0 ;ALIGN
BNE RAMDO
RAM2: ADC #$AF ;C=1 ; IN AUX BANK 1
RAMDO: DEX ; SEE IF X WAS A 1
BNE RAMREAD ;NO IT WAS A ZERO
STA WRDADD+1+HI ;WRITE
BEQ RAMDO1
RAMREAD: STA RAMLOOP+1+HI ;READ
LDY RMDBNK ;THIS MUST BE GOTTEN FROM A SAFE PLACE
STA WRTBNK,Y ;SET TO READ TO RMDBNK
RAMDO1: LDY #00
RAMLOOP: LDA $FF00,Y
WRDADD: STA $FF00,Y
INY
BNE RAMLOOP
; LEAVE WITH MAIN BANK1 ENABLED
; AND MAIN 48K SELECTED FOR WRITE
LDA BNK1SET
LDA BNK1SET
STA WRTBNK+MAIN
STA ALTZP+MAIN
RTS
; FILL TO PAGE BOUNDRY WITH 00
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0
; INFOCOM'S VERSION OF APPLE RWTS (READ/WRITE TRACK/SECTOR)
; HACKED BY ANDREW KALUZNIACKI
; FROM THE DOS RWTS ON APPLE DOS 3.3
ORG $D000
; -------------------------------
; MAIN ENTRY INTO INFO-DOS (IDOS)
; -------------------------------
; [DCBSEC] SECTOR (0-15), SET BY CALLER
; [DCBTRK] TRACK (0-34), SET BY CALLER
; [DCBDRV] DRIVE (1 OR 2), SET BY CALLER [BOOT DEFAULT]
; [DCBSLT] SLOT*16, SET BY CALLER [BOOT DEFAULT]
; [DCBPSL] SLOT*16 OF LAST USED SLOT, SET BY BOOT
; [DCBPDR] LAST DRIVE USED (1 OR 2), SET BY BOOT
; [DCBCMD] STORAGE FOR COMMAND SENT IN HIGH ALOW AT CALL TO IDOS
; [DCBERR] IDOS ERROR CODE
; [DCBBFL] DISK BUFFER ADDRESS (LSB) [BOOT = IOBUFF]
; [DCBBFM] DISK BUFFER ADDRESS (MSB) [BOOT = IOBUFF]
; HIGH ALOW =1 WRITES DISK BUFFER
; HIGH ALOW =0 READS DISK BUFFER
; [IOBUFF] = 256-BYTE BUFFER FOR DISK I/O
; (OPTIONAL IF [DCBBFL/DCBBFM] ARE SET)
; [BUFFA] ONE PAGE BUFFER
; [BUFFB] $56 BYTE BUFFER
; CARRY CLEAR ON RETURN IF NO ERROR
; IF CARRY SET, ERROR CODE IS IN [DERR]:
; $10 = WRITE PROTECTED
; $40 = DRIVE ERROR
; $80 = READ ERROR
; *** WARNING ***
; IDOS MUST START ON A PAGE BOUNDARY.
; CHANGE ANY CODE BETWEEN [IDOS] AND [INIT] AT YOUR OWN RISK.
; YOU HAVE BEEN WARNED.
DOS: NOP
NOP
NOP ; DON'T ASK, AND DON'T CHANGE
PHP ; SAVE STATUS OF [I]
SEI ; DISABLE INTERUPTS
JSR DOSENT ; DO IT (GO TO MAIN ROUTINE)
BCS DSERR ; ERROR OCCURED IF C=1
PLP ; RESTORE [I]
CLC ; SET "NO ERROR"
RTS ; RETURN FROM CALL
DSERR: PLP ; RESTORE [I]
SEC ; INDICATE ERROR
RTS ; EXIT
; PRE-NIBBLIZE [IOBUFF] BEFORE WRITING
PRENIB: LDX #0
LDY #2
PRELP1: DEY
LDA (DCBBFL),Y
LSR A
ROL BUFFB,X
LSR A
ROL BUFFB,X
STA BUFFA,Y
INX
CPX #$56
BCC PRELP1
LDX #0
TYA
BNE PRELP1
LDX #$55 ; CLEAR BITS 7 AND 6
PRELP2: LDA BUFFB,X ; OF TOP NIBBLE BUFFER
AND #%00111111
STA BUFFB,X
DEX
BPL PRELP2
RTS
; ------------
; WRITE SECTOR
; ------------
; WRITES PRENIBBLIZED DATA AT [BUFFA/BUFFB] TO DISK
; ENTRY: SLOT*16 IN [X]
; EXIT: CARRY SET IF ERROR
WRTDTA: STX DTMP4 ; SAVE SLOT ID HERE
STX SLTMP2
SEC ; SET CARRY FOR POSSIBLE ERROR
LDA Q6H,X ; CHECK FOR WRITE-PROTECT
LDA Q7L,X
BMI WRTEXI ; EXIT W/CARRY SET IF PROTECTED
LDA BUFFB ; SAVE 1ST BYTE OF 2NDARY BUFFER
STA DTMP3 ; FOR LATER
LDA #$FF ; ESTABLISH AUTOSYNC BYTE
STA Q7H,X ; SET DRIVE TO WRITE MODE
ORA Q6L,X ; WAIT FOR HARDWARE TO SETTLE
PHA
PLA
NOP
LDY #4 ; WRITE 5 AUTOSYNC BYTES
WRTLP1: PHA
PLA
JSR WRBYT2 ; USING 40 uS DELAY
DEY
BNE WRTLP1
LDA #$D5 ; WRITE DATA FIELD PROLOGUE:
JSR WRBYT1 ; $D5-$AA-$AD
LDA #$AA
JSR WRBYT1
LDA #$AD
JSR WRBYT1
TYA ; A BRIEF DELAY
LDY #$56 ; INIT LOOP INDEX
BNE WRTSK1 ; BRANCH ALWAYS
; WRITE [BUFFB] TO DISK
WRTLP2: LDA BUFFB,Y ; GET A BYTE FROM [BUFFB]
WRTSK1: EOR BUFFB-1,Y
TAX ; USE IT AS AN INDEX
LDA WRTTBL,X ; INTO THE TRANSLATE TABLE
LDX DTMP4 ; RESTORE SLOT ID
STA Q6H,X ; AND WRITE THE TRANSLATED BYTE
LDA Q6L,X
DEY ; LOOP TILL
BNE WRTLP2 ; EMPTY
; WRITE [BUFFA] TO DISK
LDA DTMP3 ; RESTORE "LOST" [BUFFB] BYTE
NOP ; WAIT JUST A MOMENT ...
WRTLP3: EOR BUFFA,Y ; GET A BYTE FROM [BUFFA]
TAX ; USE IT AS AN INDEX
LDA WRTTBL,X ; INTO THE TRANSLATE TABLE
LDX SLTMP2 ; RESTORE SLOT ID
STA Q6H,X ; AND WRITE THE TRANSLATED BYTE
LDA Q6L,X
LDA BUFFA,Y ; GET NEXT BYTE FROM BUFFER
INY ; AND LOOP TILL
BNE WRTLP3 ; ALL OF [BUFFA] IS WRITTEN
TAX
LDA WRTTBL,X
LDX DTMP4 ; RESTORE SLOT ID
JSR WRBYT3 ; AND WRITE THE LAST [BUFFA] BYTE
LDA #$DE ; WRITE DATA FIELD EPILOGUE:
JSR WRBYT1 ; $DE-$AA-$EB
LDA #$AA
JSR WRBYT1
LDA #$EB
JSR WRBYT1
LDA #$FF ; WRITE GAP 3
JSR WRBYT1
LDA Q7L,X ; SET DRIVE TO READ MODE
WRTEXI: LDA Q6L,X
RTS
; ----------------------------
; WRITE A BYTE (TIME-CRITICAL)
; ----------------------------
; ENTRY: BYTE TO WRITE IN [A]
; SLOT*16 IN [X]
WRBYT1: CLC ; PROLOGUE, EPILOGUE AND GAP 3 TIMING
WRBYT2: PHA ; ENTRY FOR GAP 2 TIMING
PLA
WRBYT3: STA Q6H,X
ORA Q6L,X
RTS
; CONVERT RAW DATA TO BINARY IN [IOBUFF]
POSTNB: LDY #0
PSTSK1: LDX #$56
PSTLP1: DEX
BMI PSTSK1
LDA BUFFA,Y
LSR BUFFB,X
ROL A
LSR BUFFB,X
ROL A
STA (DCBBFL),Y
INY
CPY DTMP3
BNE PSTLP1
RTS
; -----------
; READ SECTOR
; -----------
; READ RAW SECTOR DATA TO [BUFFA/BUFFB]
; ENTRY: SLOT*16 IN [X]
; EXIT: CARRY SET IF ERROR, ELSE 342 RAW BYTES IN [BUFFA/BUFFB]
RDSECT: LDY #$20
RDLP1: DEY ; RETURN AN ERROR IF
BEQ RDBAD ; NO $D5 FOUND AFTER 32 TRIES
; FETCH & VALIDATE PROLOGUE ($D5-$AA-$AD)
RD1: LDA Q6L,X ; GET A BYTE
BPL RD1
RDSK1: EOR #$D5 ; WAS IT $D5?
BNE RDLP1 ; NO, KEEP LOOKING
NOP ; ELSE WAIT A MOMENT ...
RD2: LDA Q6L,X ; GET ANOTHER BYTE
BPL RD2
CMP #$AA ; WAS IT $AA?
BNE RDSK1 ; CHECK FOR $D5 AGAIN IF NOT
LDY #$56 ; ELSE INIT DATA-READ INDEX
RD3: LDA Q6L,X ; GET A BYTE
BPL RD3
CMP #$AD ; WAS IT $AD?
BNE RDSK1 ; CHECK FOR $D5 IF NOT
; READ RAW DATA INTO [BUFFB]
LDA #0 ; CLEAR [A], DELAY ...
RDLP2: DEY
STY DTMP3 ; SAVE INDEX HERE
RD4: LDY Q6L,X ; GET A DATA BYTE
BPL RD4
EOR RDTBL-$96,Y ; TRANSLATE IT
LDY DTMP3 ; RESTORE INDEX
STA BUFFB,Y ; STORE BYTE IN [BUFFB]
BNE RDLP2 ; CONTINUE TILL [BUFFB] FULL
; READ RAW DATA INTO [BUFFA]
RDLP3: STY DTMP3 ; RE-INIT INDEX TO ZERO
RD5: LDY Q6L,X ; GET A DATA BYTE
BPL RD5
EOR RDTBL-$96,Y ; TRANSLATE IT
LDY DTMP3 ; RESTORE INDEX
STA BUFFA,Y ; SAVE BYTE IN [BUFFA]
INY
BNE RDLP3 ; LOOP TILL [BUFFA] IS FULL
; FETCH & VALIDATE CHECKSUM
RD6: LDY Q6L,X ; GET THE NEXT BYTE
BPL RD6
CMP RDTBL-$96,Y ; TRANSLATE IT
BNE RDBAD ; ERROR IF CHECKSUM BAD
; FETCH & VALIDATE EPILOGUE ($DE-$AA-$EB)
RD7: LDA Q6L,X ; GET A BYTE
BPL RD7
CMP #$DE ; IS IT $DE?
BNE RDBAD ; ERROR IF NOT
NOP ; WAIT ...
RD8: LDA Q6L,X ; GET ANOTHER BYTE
BPL RD8
CMP #$AA ; IS IT $AA?
BEQ RDOK ; DATA OKAY IF SO
RDBAD: SEC ; ELSE SET CARRY FOR ERROR
RTS ; AND SCRAM
; ---------------------
; READ AN ADDRESS FIELD
; ---------------------
; ENTRY: SLOT*16 IN [X]
; EXIT: CARRY SET IF ERROR
RDADDR: LDY #$FC ; INIT TIMEOUT COUNTER
STY DTMP3
ADDLP1: INY
BNE ADD1
INC DTMP3 ; ERROR IF
BEQ RDBAD ; CAN'T FIND ADDRESS HEADER
; FETCH THE ADDRESS FIELD PROLOGUE ($D5-$AA-$96)
ADD1: LDA Q6L,X ; GRAB A BYTE
BPL ADD1
ADDLP2: CMP #$D5 ; WAS IT $D5?
BNE ADDLP1 ; NO, KEEP SEARCHING
NOP ; ELSE WAIT A FEW MICROSECONDS ...
ADD2: LDA Q6L,X ; GET ANOTHER BYTE
BPL ADD2
CMP #$AA ; WAS IT $AA?
BNE ADDLP2 ; NO, CHECK IF $D5
LDY #3 ; ELSE INIT DATA-FETCH INDEX
ADD3: LDA Q6L,X ; GET A BYTE
BPL ADD3
CMP #$96 ; WAS IT $96?
BNE ADDLP2 ; NO, CHECK FOR $D5
; FETCH THE 4 BYTES OF ADDRESS DATA
LDA #0 ; INIT CHECKSUM BYTE
ADDLP3: STA DTMP4 ; UPDATE CHECKSUM
ADD4: LDA Q6L,X ; GET A BYTE
BPL ADD4
ROL A ; SHIFT IT
STA DTMP3 ; AND SAVE 1ST PART HERE
ADD5: LDA Q6L,X ; GET ANOTHER BYTE
BPL ADD5
AND DTMP3 ; SUPER 1ST PART OF BYTE
STA HDRCHK,Y ; STORE IN RESULT TABLE
EOR DTMP4 ; COMPUTE CHECKSUM
DEY ; GOT 4 BYTES YET?
BPL ADDLP3 ; NO, LOOP BACK
TAY ; LOOK AT CHECKSUM BYTE
BNE RDBAD ; ERROR IF NON-ZERO
; FETCH & VALIDATE EPILOGUE ($DE-$AA, IGNORE $EB)
ADD6: LDA Q6L,X ; GET A BYTE
BPL ADD6
CMP #$DE ; WAS IT $DE?
BNE RDBAD ; ERROR IF NOT
NOP ; ELSE WAIT A MOMENT ...
ADD7: LDA Q6L,X ; GET ONE MORE BYTE
BPL ADD7
CMP #$AA ; WAS IT $AA
BNE RDBAD ; ERROR IF NOT
RDOK: CLC ; ELSE CLEAR CARRY FOR SUCCESS
RTS ; AND RETURN
; ---------------------
; MOVE ARM TO TRACK [A]
; ---------------------
; ENTRY: SLOT*16 IN [X]
; TARGET TRACK IN [A]
; CURRENT TRACK IN [CTRACK]
SEEK: STX SLTMP3 ; SAVE SLOT ID
STA TTRK ; AND TARGET TRACK
CMP CTRACK ; TARGET SAME AS CURRENT?
BEQ SEEEXI ; EXIT NOW IF SO
LDA #0 ; INIT
STA DTMP3 ; INDEX
SEESK1: LDA CTRACK ; GET CURRENT TRACK
STA DTMP4 ; SAVE IT HERE
SEC
SBC TTRK ; GET TRACK DIFFERENCE
BEQ SEESK6
BCS SEESK2
EOR #%11111111
INC CTRACK
BCC SEESK3
SEESK2: ADC #$FE
DEC CTRACK
SEESK3: CMP DTMP3
BCC SEESK4
LDA DTMP3
SEESK4: CMP #$0C
BCS SEESK5
TAY
SEESK5: SEC
JSR SEEK0
LDA DELTB1,Y
JSR ARMDEL
LDA DTMP4
CLC
JSR SEEK1
LDA DELTB2,Y
JSR ARMDEL
INC DTMP3
BNE SEESK1
SEESK6: JSR ARMDEL
CLC
SEEK0: LDA CTRACK
SEEK1: AND #%00000011
ROL A
ORA SLTMP3
TAX
LDA PH0OFF,X ; MOVE THE ARM
LDX SLTMP3
SEEEXI: RTS
; ------------------
; ARM MOVEMENT DELAY
; ------------------
; NOTE: THIS ROUTINE MUST BEGIN ON A PAGE BOUNDARY!
; ENTRY: 100uS DELAY INTERVAL IN [A]
; MOTOR TIME COUNT IN [MTIME]
ARMDEL: LDX #$11
ARMLP1: DEX
BNE ARMLP1
INC DCNT
BNE ARMLP2
INC DTMP2
ARMLP2: SEC
SBC #1
BNE ARMDEL
RTS
; -------------------------
; ARM MOVEMENT DELAY TABLES
; -------------------------
DELTB1: DB $01,$30,$28,$24,$20,$1E,$1D,$1C
DB $1C,$1C,$1C,$1C
DELTB2: DB $70,$2C,$26,$22,$1F,$1E,$1D,$1C
DB $1C,$1C,$1C,$1C
; ---------------------
; WRITE TRANSLATE TABLE
; ---------------------
WRTTBL: DB $96,$97,$9A,$9B,$9D,$9E,$9F,$A6
DB $A7,$AB,$AC,$AD,$AE,$AF,$B2,$B3
DB $B4,$B5,$B6,$B7,$B9,$BA,$BB,$BC
DB $BD,$BE,$BF,$CB,$CD,$CE,$CF,$D3
DB $D6,$D7,$D9,$DA,$DB,$DC,$DD,$DE
DB $DF,$E5,$E6,$E7,$E9,$EA,$EB,$EC
DB $ED,$EE,$EF,$F2,$F3,$F4,$F5,$F6
DB $F7,$F9,$FA,$FB,$FC,$FD,$FE,$FF
; --------------------
; READ TRANSLATE TABLE
; --------------------
RDTBL: DB $00,$01,$98,$99,$02,$03,$9C,$04
DB $05,$06,$A0,$A1,$A2,$A3,$A4,$A5
DB $07,$08,$A8,$A9,$AA,$09,$0A,$0B
DB $0C,$0D,$B0,$B1,$0E,$0F,$10,$11
DB $12,$13,$B8,$14,$15,$16,$17,$18
DB $19,$1A,$C0,$C1,$C2,$C3,$C4,$C5
DB $C6,$C7,$C8,$C9,$CA,$1B,$CC,$1C
DB $1D,$1E,$D0,$D1,$D2,$1F,$D4,$D5
DB $20,$21,$D8,$22,$23,$24,$25,$26
DB $27,$28,$E0,$E1,$E2,$E3,$E4,$29
DB $2A,$2B,$E8,$2C,$2D,$2E,$2F,$30
DB $31,$32,$F0,$F1,$33,$34,$35,$36
DB $37,$38,$F8,$39,$3A,$3B,$3C,$3D
DB $3E,$3F
; ---------------
; MAIN RWTS ENTRY
; ---------------
; ENTRY: [A]=0 FOR READ, [A]=1 FOR WRITE
; [SLOT] = TARGET SLOT
; [DRIVE] = TARGET DRIVE
; [TRACK] = TARGET TRACK
; [SECTOR] = TARGET SECTOR
; EXIT: CARRY CLEAR IF OKAY
; COMMENTS - LINDE
; ACTUAL VARIABLES ARE:
; [DCBSLT] = SLOT
; [DCBTRK] = TRACK
; [DCBSEC] = SECTOR
; [[DCBDRV] = DRIVE
; FOR TRK, SEC, DRV 1 = 1 (DRIVE 1, SET DCBDRV TO 1)
; FOR SLT - MULTIPLY SLOT BY 16 (SLOT 6, SET DCBSLT TO $60)
DOSENT: STA DCBCMD ; SAVE COMMAND
LDA #2 ; ALLOW 2
STA NRECAL ; RECALS
ASL A ; AND 4
STA NSEEK ; SEEKS
LDX DCBSLT ; GET REQUESTED SLOT ID
CPX DCBPSL ; SAME AS LAST SLOT?
BEQ DOSS1 ; YES, CONTINUE
LDX DCBPSL
; WAIT FOR OLD DRIVE TO TURN OFF, UPDATE SLOT ID
LDA Q7L,X ; SET OLD SLOT TO READ MODE
DOSL1: LDY #8 ; INIT COUNTER
LDA Q6L,X
DOSL2: CMP Q6L,X
BNE DOSL1
DEY
BNE DOSL2
LDX DCBSLT ; GET NEW SLOT ID INTO [X]
STX DCBPSL ; MAKE IT THE "OLD" SLOT
; CURRENT SLOT ID IN [X]
DOSS1: LDA Q7L,X ; GET DRIVE INTO READ MODE
LDA Q6L,X ; READ WITH DELAYS
LDY #8 ; TO SEE IF DRIVE IS SPINNING
DOSL3: LDA Q6L,X
PHA
PLA
PHA
PLA
STX SLTMP1 ; SAVE SLOT HERE
CMP Q6L,X
BNE DOSS2
DEY
BNE DOSL3
DOSS2: PHP ; SAVE TEST RESULT ON STACK
LDA DRVON,X ; TURN ON MOTOR
LDA #$D8 ; REFRESH
STA DTMP2 ; MOTOR TIME CONSTANT
; CHECK DRIVE ID
LDA DCBDRV
CMP DCBPDR ; HAS DRIVE CHANGED?
BEQ DOSS3 ; NO, CONTINUE
STA DCBPDR ; ELSE MAKE NEW DRIVE "OLD"
PLP ; SET ZERO FLAG
LDY #0 ; OF TEST RESULT
PHP ; AND PUSH IT BACK ON STACK
DOSS3: ROR A ; CHECK DRIVE ID
BCC DOSS4 ; CARRY WILL BE CLEAR IF DRIVE = 2
LDA DRV0EN,X ; ELSE SELECT DRIVE #1
BCS DOSS5 ; BRANCH ALWAYS
DOSS4: LDA DRV1EN,X ; SELECT DRIVE #2
DOSS5: ROR DRVFLG ; HIGH BIT = 1 FOR DRIVE 1, 0 FOR 2
PLP ; CHECK TEST RESULTS
PHP
BNE DOSS6 ; BRANCH IF DRIVE WAS ON
LDY #7 ; WAIT FOR CAP DISCHARGE
DOSL4: JSR ARMDEL
DEY
BNE DOSL4
LDX SLTMP1 ; RESTORE SLOT ID
; SEEK THE TARGET TRACK
DOSS6: LDA DCBTRK ; GET TARGET TRACK
JSR MYSEEK
PLP ; WAS DRIVE ON?
BNE DOSS7 ; YES, CONTINUE
; WAIT FOR DRIVE TO COME UP TO SPEED
LDY DTMP2
BPL DOSS7
DOSL5: LDY #$12 ; WAIT FOR DRIVE TO
DOSL6: DEY ; COME UP TO SPEED
BNE DOSL6
INC DCNT
BNE DOSL5
INC DTMP2
BNE DOSL5
; DECODE DISK COMMAND
DOSS7: LDA DCBCMD ; GET COMMAND
ROR A ; CARRY = 0 IF "READ"
PHP ; SAVE READ/WRITE STATUS
; AND MAINTAIN STACK
BCC GETADR ; BRANCH IF "READ"
JSR PRENIB
; FETCH AN ADDRESS FIELD
GETADR: LDA #48
STA DTMP1 ; INIT RETRY COUNT
GTA0: LDX SLTMP1 ; RESTORE SLOT ID
LDA DCBCMD
BPL DOSS8
STA DTMP6 ; TELL RDFADD TO GET HEADER ONLY
JSR RDFSEC ; #$84 = READ FUNNY FORMAT
BCC RRGHT ; READ IT
BCS GTA1 ; OOPS
DOSS8: JSR RDADDR ; GET AN ADDRESS FIELD
BCC RRGHT ; CONTINUE IF SUCCESSFUL
GTA1: DEC DTMP1 ; ELSE UPDATE RETRY COUNT
BPL GTA0 ; AND TRY AGAIN
; RECALIBRATE THE ARM
GTA2: LDA CTRACK ; SAVE THE
PHA ; CURRENT TRACK ID
LDA #$60
JSR SETTRK
DEC NRECAL ; UPDATE RECAL COUNT
BEQ DOSERR ; ERROR IF EMPTY
LDA #4 ; RESET
STA NSEEK ; SEEK COUNT
LDA #0 ; CALIBRATE THE ARM
JSR MYSEEK ; TO TRACK #0
PLA ; RESTORE CURRENT TRACK
GTA3: JSR MYSEEK ; GO TO IT
JMP GETADR ; AND TRY AGAIN
; ADDRESS FIELD FOUND
RRGHT: LDY HDRTRK
CPY CTRACK ; ON THE RIGHT TRACK?
BEQ RTTRAK ; YES, CONTINUE
LDA CTRACK
PHA
TYA
JSR SETTRK
PLA
DEC NSEEK
BNE GTA3
BEQ GTA2 ; ELSE RECALIBRATE
; HANDLE A DRIVE ERROR
DOSERR PLA ; CLEAN UP STACK
LDA #$40 ; $40 = DRIVE ERROR
PLP ; CLEAN UP STATUS REGISTER
JMP DOSERR2
; CHECK FOR PROPER SECTOR (VOLUME CHECK OMITTED)
RTTRAK: LDA DCBCMD
BMI DOSS9 ; NO INTERLEAVE
LDY DCBSEC
LDA INTLVE,Y ; GET INTERLEAVE BYTE
CMP HDRSEC ; MATCHED FOUND SECTOR?
BNE GTA1 ; NO, TRY AGAIN
; SECTOR FOUND!
DOSS9: PLP ; WILL THIS BE READ OR WRITE?
BCS DOSWRT ; DO "WRITE" IF CARRY SET
; READ A SECTOR
LDA DCBCMD
BPL DOSS10
LDY DCBSEC ; FUNNY FORMAT
STY DTMP6
JSR RDFSEC
BCC DOSS11
SEC
BCS DOSS11
DOSS10: JSR RDSECT ; DO THE READ
DOSS11: BCC GTA3A ; OK
CLC ; RESET FOR NEXT TIME THRU
PHP ; PUSH FOR NEXT TIME THRU
BCC GTA1 ; JMP, ERROR OCCURRED
GTA3A: LDX #$00
STX DTMP3
JSR POSTNB
LDX SLTMP1 ; RESTORE SLOT ID
DOSFIN: LDA #0 ; 0 = NO ERRORS
CLC ; CARRY CLEAR FOR SUCCESS
BCC DOSEXI
; ERROR EXIT
DOSERR2: SEC ; CARRY SET FOR ERROR
; GENERAL EXIT
DOSEXI: STA DCBERR ; SAVE ERROR CODE HERE
LDA DRVOFF,X ; STOP THE DRIVE
RTS ; BYE!
; WRITE A SECTOR
DOSWRT: JSR WRTDTA
BCC DOSFIN ; ALL'S WELL IF CARRY CLEAR
LDA #$10 ; ELSE GET ERROR CODE INTO [A]
BNE DOSERR2 ; AND DO AN ERROR EXIT
; ---------------------
; SET UP FOR TRACK SEEK
; ---------------------
MYSEEK: ASL A ; TRACK*2 (PHASE OF DISK CARE)
JSR DOSEEK
LSR CTRACK ; CURRENT TRACK/2
RTS
; --------------
; EXECUTE A SEEK
; --------------
; PAGE BOUNDARY SHOULD BEGIN HERE!
DOSEEK: STA TTRK
JSR XTOY
LDA DR1TBL,Y
BIT DRVFLG
BMI EEK1
LDA DR2TBL,Y
EEK1: STA CTRACK
LDA TTRK
BIT DRVFLG
BMI EEK2
STA DR2TBL,Y
BPL EEK3
EEK2: STA DR1TBL,Y
EEK3: JMP SEEK
; --------------------
; GET SLOT ID INTO [Y]
; --------------------
XTOY: TXA
LSR A
LSR A
LSR A
LSR A
TAY
RTS
; ------------
; SET TRACK ID
; ------------
SETTRK: PHA
LDA DCBDRV
ROR A
ROR DRVFLG
JSR XTOY
PLA
ASL A
BIT DRVFLG
BMI SETT1
STA DR2TBL,Y
BPL SETT2
SETT1: STA DR1TBL,Y
SETT2: RTS
; -----------
; IDOS TABLES
; -----------
DR1TBL: DB 00,00,00,00 ; (8 BYTES)
DB 00,00,00,00
CTRACK EQU DR1TBL ; CURRENT TRACK
DR2TBL: DB 00,00,00,00 ; (8 BYTES)
DB 00,00,00,00
NSEEK: DB 00 ; SEEK COUNT
DTMP1: DB 00 ; RETRY COUNT
SLTMP1: DB 00 ; SLOT ID
SLTMP2: DB 00
NRECAL: DB 00 ; RECALIBRATE COUNT
;DUPLICATE INTERLEAVE TBL FOR USE AFTER BOOT
INTLVE: DB $00,$04,$08,$0C,$01,$05,$09,$0D
DB $02,$06,$0A,$0E,$03,$07,$0B,$0F
; ------------------
; READ SECTOR FROM BIG TRACK
; ------------------
; READ ADDRESS FIELD TO CHECK TRACK
; FIND HEADER $D5:$AA:$AD
RDFSEC: LDA #$20
STA HTEMP
TAY
RDFL1: LDA #$84 ; IN CASE ERROR OCCURS
DEC HTEMP
BEQ RDFBAD2
RDFL2: DEY
BEQ RDFL2
NOP
NOP
LDA Q6L,X
BPL RDFL2
CMP #$D5
BNE RDFL2
RDF1: LDA Q6L,X
BPL RDF1
CMP #$AA
BNE RDFL1
RDF2: LDA Q6L,X
BPL RDF2
CMP #$AD
BNE RDFL1
; HEADER FOUND - GET TRACK ID 4+4
SEC
RDF3: LDA Q6L,X
BPL RDF3
ROL A
STA TEMP
RDF4: LDA Q6L,X
BPL RDF4
AND TEMP
STA HDRTRK
LDA DTMP6
BMI RDFOK ; ONLY LOOKING FOR TRACK NUMBER AND ?
RDFNEXT: LDY #$56 ; SET INDEX (AND TIMING)
; SKIP UNUSED SECTORS
LDA #$00 ; ZERO HIGH ALOW
RDFL3: DEY ; NEXT
STY DTMP3 ; SAVE INDEX
RDF5: LDY Q6L,X ; GET A BYTE
BPL RDF5 ; WAIT VALID
EOR RDTBL-$96,Y ; CHECK SUM AND DECODE
LDY DTMP3 ; GET INDEX
STA BUFFB,Y ; SAVE DATRA
BNE RDFL3 ; LOOP TILL DONE
RDFL4: STY DTMP3 ; SAVE INDEX
RDF6: LDY Q6L,X ; GET A BYTE
BPL RDF6 ; WAIT VALID
EOR RDTBL-$96,Y ; DECODE AND CHECK SUM
LDY DTMP3 ; GET INDEX
STA BUFFA,Y ; SAVE DATA
INY ; NEXT
BNE RDFL4 ; LOOP TIL DONE
RDF7: LDY Q6L,X ; GET A BYTE
BPL RDF7 ; WAIT VALID
DEC DTMP6
BPL RDFNEXT
CMP RDTBL-$96,Y ; CHECK SUM VALID?
BNE RDFBAD ; NO, EXIT ERROR
RDFOK: CLC
RTS
RDFBAD: LDA #$85
RDFBAD2: STA DCBERR
SEC
RTS
; ----------------------
; MACHINE INITIALIZATION
; ----------------------
INIT: LDA TXTSET ; SET TEXT MODE
LDA MIXCLR ; SET NO MIX
LDA LOWSCR ; SET PAGE 1
LDA #>IOBUFF ; POINT [DCBBFL/H] TO [IOBUFF]
STA DCBBFM
LDA #<IOBUFF
STA DCBBFL
LDA #1
STA DCBDRV ; SET DRIVE = 1
STA DCBPDR
RTS
END