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

1091 lines
22 KiB
NASM
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
PAGE
STTL "--- 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?
BEQ BOOTS2 ; YES, DO STUFF (X)
CMP #$0A ; 3RD SECTOR GOES UP >(X)
BNE BOOTS0 ; NO, CONTINUE
; CALC ADDRESS OF ROM SECTOR READ ROUTINE
LDA #$D0
STA BADDR+HI
BNE BOOTS0 ; JMP (X)
BOOTS2: 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=<$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=<$0F IN MAIN BANK 2
; $10=<$1F IN AUX BANK 2
; $20=<$4F IN AUX BANK 1
RMDBNK: DB 00 ;REMEMBER 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 >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
; MONITOR CALLS ARE TO ROM SO MUST BE FROM MAIN 48K OF MEMORY
; ALL CALLS IN XZIP ARE UNCHANGED FROM EZIP BUT ARE DIVERTED NOW
; THROUGH THESE RTNS WHICH SWITCH IN ROM TO READ FROM, CALL THE
; MONITOR ROUTINE THEN SWITCH BACK TO RAM FOR EVERYTHING AND RETURN
; EACH CALL SHOULD BE SEPARATE SO AS TO PRESERVE REGISTERS ON CALL
BASCAL: PHA
LDA RDROM ; SET TO READ FROM ROM
LDA RDROM
PLA
JSR MBASCAL ; CALL MONITOR RTN
JMP MOUT
BELL: PHA
LDA RDROM
LDA RDROM
PLA
JSR MBELL
JMP MOUT
CLEOL: PHA
LDA RDROM
LDA RDROM
PLA
JSR MCLEOL
JMP MOUT
CLEOS: PHA
LDA RDROM
LDA RDROM
PLA
JSR MCLEOS
JMP MOUT
HOME: PHA
LDA RDROM
LDA RDROM
PLA
JSR MHOME
JMP MOUT
MCOUT: PHA
LDA RDROM
LDA RDROM
PLA
JSR MMCOUT
JMP MOUT
COUT1: PHA
LDA RDROM
LDA RDROM
PLA
JSR MCOUT1
JMP MOUT
RDKEY: PHA
LDA RDROM
LDA RDROM
PLA
JSR MRDKEY
JMP MOUT
GETLN1: PHA
LDA RDROM
LDA RDROM
PLA
JSR MGETLN1
JMP MOUT
MWAIT: PHA
LDA RDROM
LDA RDROM
PLA
JSR MMWAIT
; FALL THRU ON LAST ONE
MOUT: PHA ; SAVE [A] AS MAY HAVE INFORMATION
LDA BNK1SET ; RESET TO READ FROM RAM
LDA BNK1SET
PLA
RTS
; TO CHECK IF HAVE ENOUGH MEMORY, MUST HAVE 128K OF MEMORY (X)
CHKSIZ: LDA RDROM ; FLAGS IN ROM, MUST GET THEM
LDA RDROM
LDA $FBB3 ; CHECK ID BYTE
CMP #$06 ; IS IT A IIE OR IIC?
BEQ CHKS0 ; YES
LDA BNK1SET ; RESET TO RAM
LDA BNK1SET
SEC ; NO, IT'S NOT 128K (EZIP)
RTS
CHKS0: LDA $FBC0 ; IS IT A IIE OR! A IIC
LDX BNK1SET ; RESET TO RAM
LDX BNK1SET
STA SIG ; 0 = IIC
CLC ; SAY OK,
RTS ; FINISH UP IN COLD
CALL80: LDA RDROM ; SET TO READ ROM
LDA RDROM ; SO CAN TURN 80 COL DISPLAY ON
JSR $C300 ; THIS NEEDS ROM
LDA BNK1SET ; RESET TO RAM
LDA BNK1SET
RTS
; MARK END OF SECTOR
PAGE
; 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 >A< AT CALL TO IDOS
; [DCBERR] IDOS ERROR CODE
; [DCBBFL] DISK BUFFER ADDRESS (LSB) [BOOT = IOBUFF]
; [DCBBFM] DISK BUFFER ADDRESS (MSB) [BOOT = IOBUFF]
; >A<=1 WRITES DISK BUFFER
; >A<=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 ; AL<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 ; >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 >A<
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/M] TO [IOBUFF]
STA DCBBFM
LDA #<IOBUFF
STA DCBBFL
LDA #1
STA DCBDRV ; SET DRIVE = 1
STA DCBPDR
RTS
END