@ -72,23 +72,15 @@
;
; TODO:
;
; - STRAIGHTEN OUT TIMEOUTS
;
; - REVIEW/ADD CODE COMMENTS
;
; - CODE NEEDS TO BE REORGANIZED
;
; NOTES:
;
; - TESTED ON THE SYQUEST SPARQ ONLY.
;
; - THERE ARE SOME HARD CODED TIMEOUT LOOPS IN THE CODE. THEY ARE
; WORKING OK ON A 7 MHZ Z80. THEY ARE LIKELY TO NEED TWEAKING ON
; FASTER CPUS.
;
; - THIS DRIVER OPERATES PURELY IN NIBBLE MODE. I SUSPECT IT IS
; POSSIBLE TO USE FULL BYTE MODE (PS2 STYLE), BUT I HAVE NOT
; ATTEMPTED IT.
; - THIS DRIVER OPERATES USES NIBBLE READ MODE. ALTHOUGH THE 8255
; (MG014) CAN READ OR WRITE TO PORT A (DATA), IT "GLITCHES" WHEN
; THE MODE IS CHANGED CAUSING THE CONTROL LINES TO CHANGE AND
; BREAKS THE PROTOCOL. I SUSPECT THE MBC SPP CAN SUPPORT FULL BYTE
; MODE, (PS2 STYLE), BUT I HAVE NOT ATTEMPTED IT.
;
; - RELATIVE TO ABOVE, THIS BEAST IS SLOW. IN ADDITION TO THE
; NIBBLE MODE READS, THE MG014 ASSIGNS SIGNALS DIFFERENTLY THAN
@ -181,12 +173,9 @@ SYQ_LBA .EQU 8 ; OFFSET OF LBA (DWORD)
; OCCUR PRETTY FAST. NOTE THAT THE ATA SPEC ALLOWS UP TO 30 SECONDS
; FOR DEVICES TO RESPOND. WE ARE USING MUCH MORE AGGRESSIVE VALUES
; BASED ON REAL WORLD EXPERIENCE.
; THE PICO TIMEOUT (TOPICO) IS A SPECIAL TIMEOUT FOR THE RC2014 SD
; PICO TO WAIT FOR THE PICO DEVICE TO INITIALIZE.
;
SYQ_TOSLOW .EQU 200 ; SLOW TIMEOUT IS 20 SECS
SYQ_TONORM .EQU 5 ; NORMAL TIMEOUT IS 0.55 SECS
SYQ_TOPICO .EQU 50 ; RC2014 SD PICO (5 SECONDS)
SYQ_TOSLOW .EQU 120 ; SLOW TIMEOUT IS 30 SECS (30 / .25)
SYQ_TONORM .EQU 4 ; NORMAL TIMEOUT IS 1 SEC (1 / .25)
;
; MACROS
;
@ -208,6 +197,17 @@ SYQ_TOPICO .EQU 50 ; RC2014 SD PICO (5 SECONDS)
;=============================================================================
;
SYQ_INIT:
; COMPUTE CPU SPEED COMPENSATED TIMEOUT SCALER
; ONE INTERNAL LOOP IN WAITBSY IS 489TS. ON A 1 MHZ CPU, 1 TS
; TAKES 1NS. SO 1/4 SECOND IS 250000 TS ON A 1 MHZ CPU.
; SINCE 1 INTERNAL LOOP IS 489 TS, IT TAKES 250000 / 489 = 511
; INTERNAL LOOPS FOR 1/10 SECOND. SO, WE WANT TO USE
; 511 * CPU MHZ FOR INTERNAL LOOP COUNT.
LD DE , 511 ; LOAD SCALER FOR 1MHZ
LD A ,( CB_CPUMHZ ) ; LOAD CPU SPEED IN MHZ
CALL MULT8X16 ; HL := DE * A
LD ( SYQ_TOSCALER ), HL ; SAVE IT
;
LD IY , SYQ_CFG ; POINT TO START OF CONFIG TABLE
;
SYQ_INIT1:
@ -417,6 +417,9 @@ SYQ_IO:
LD ( SYQ_DSKBUF ), HL ; SAVE DISK BUFFER ADDRESS
LD A , SYQ_LBA ; LBA OFFSET IN CONFIG
CALL LDHLIYA ; POINT TO LBA DWORD
# IF ( DS KYENABLE )
CALL HB_DSKACT ; SHOW ACTIVITY
# ENDIF
CALL LD32 ; SET DE:HL TO LBA
;
CALL SYQ_CMDSETUP ; SETUP ATA COMMAND BUF
@ -526,364 +529,168 @@ SYQ_GEOM:
; FUNCTION SUPPORT ROUTINES
;=============================================================================
;
; OUTPUT BYTE IN A TO THE DATA PORT
;
SYQ_WRITEDATA:
LD C ,( IY + SYQ_IOBASE ) ; DATA PORT IS AT IOBASE
OUT ( C ), A ; WRITE THE BYTE
;CALL DELAY ; IS THIS NEEDED???
RET ; DONE
;
;
;
SYQ_WRITECTRL:
; IBM PC INVERTS ALL BUT C2 ON THE BUS, MG014 DOES NOT.
; BELOW TRANSLATES FROM IBM -> MG014. IT ALSO INVERTS THE
; MG014 LED SIMPLY TO MAKE IT EASY TO KEEP LED ON DURING
; ALL ACTIVITY.
;
# IF ( SYQMODE = = SYQMODE_MG014
XOR $ 0B | $ 80 ; HIGH BIT IS MG014 LED
SYQ_IDENTIFY:
# IF ( SYQTRACE > = 3 )
CALL SYQ_PRTPREFIX
PRTS ( " IDDEV$" )
# ENDIF
LD C ,( IY + SYQ_IOBASE ) ; GET BASE IO ADDRESS
INC C ; BUMP TO CONTROL PORT
INC C
OUT ( C ), A ; WRITE TO CONTROL PORT
;CALL DELAY ; IS THIS NEEDED?
RET ; DONE
;
; READ THE PARALLEL PORT INPUT LINES (STATUS) AND MAP SIGNALS FROM
; MG014 TO IBM STANDARD. NOTE POLARITY CHANGE REQUIRED FOR BUSY.
LD C , SYQ_CMD_IDDEV
LD DE , 0
LD HL , 0
CALL SYQ_CMDSETUP
;
; MG014 IBM PC (SPP)
; -------- --------
; 0: /ACK 6: /ACK
; 1: BUSY 7: /BUSY
; 2: POUT 5: POUT
; 3: SEL 4: SEL
; 4: /ERR 3: /ERR
LD HL , HB_WRKBUF
LD ( SYQ_DSKBUF ), HL
LD A , SYQ_XFR_READ
LD ( SYQ_XFRMODE ), A
;
SYQ_READSTATUS:
LD C ,( IY + SYQ_IOBASE ) ; IOBASE TO C
INC C ; BUMP TO STATUS PORT
IN A ,( C ) ; READ IT
JP SYQ_RUNCMD
;
# IF ( SYQMODE = = SYQMODE_MG014
;
; SHUFFLE BITS ON MG014
LD C , 0 ; INIT RESULT
BIT 0 , A ; 0: /ACK
JR Z , SYQ_READSTATUS1
SET 6 , C ; 6: /ACK
SYQ_READSTATUS1:
BIT 1 , A ; 1: BUSY
JR NZ , SYQ_READSTATUS2 ; POLARITY CHANGE!
SET 7 , C ; 7: /BUSY
SYQ_READSTATUS2:
BIT 2 , A ; 2: POUT
JR Z , SYQ_READSTATUS3
SET 5 , C ; 5: POUT
SYQ_READSTATUS3:
BIT 3 , A ; 3: SEL
JR Z , SYQ_READSTATUS4
SET 4 , C ; 4: SEL
SYQ_READSTATUS4:
BIT 4 , A ; 4: /ERR
JR Z , SYQ_READSTATUS5
SET 3 , C ; 3: /ERR
SYQ_READSTATUS5:
LD A , C ; RESULT TO A
;
SYQ_MEDIASTATUS:
# IF ( SYQTRACE > = 3 )
CALL SYQ_PRTPREFIX
PRTS ( " MEDIASTATUS$" )
# ENDIF
;
RET
;
; SIGNAL SEQUENCE TO CONNECT/DISCONNECT
; VALUE IN A IS WRITTEN TO DATA PORT DURING SEQUENCE
LD C , SYQ_CMD_MEDIASTATUS
LD DE , 0
LD HL , 0
CALL SYQ_CMDSETUP
;
SYQ_CPP:
PUSH AF
SYQ_W2 ( 4 )
SYQ_W0 ( $ 22 )
SYQ_W0 ( $ AA )
SYQ_W0 ( $ 55 )
SYQ_W0 ( 0 )
SYQ_W0 ( $ FF )
LD HL , 0
LD ( SYQ_DSKBUF ), HL
LD A , SYQ_XFR_NONE
LD ( SYQ_XFRMODE ), A
;
CALL SYQ_READSTATUS
AND $ B8
LD ( SYQ_S1 ), A
JP SYQ_RUNCMD
;
SYQ_W0 ( $ 87 )
; DE:HL LBA
; C: COMMAND
;
CALL SYQ_READSTATUS
AND $ B8
LD ( SYQ_S2 ), A
SYQ_CMDSETUP:
XOR A
LD ( SYQ_CMD_FEAT ), A
INC A
LD ( SYQ_CMD_COUNT ), A
LD ( SYQ_CMD_LBA0 ), HL
LD ( SYQ_CMD_LBA2 ), DE
LD A , $ E0
LD ( SYQ_CMD_DRV ), A
LD A , C
LD ( SYQ_CMD_OP ), A
RET
;
SYQ_W0 ( $ 78 )
;=============================================================================
; COMMAND PROCESSING
;=============================================================================
;
CALL SYQ_READSTATUS
AND $ 38
LD ( SYQ_S3 ), A
; RUN AN ATA COMMAND USING CMD BUFFER IN SYQ_CMDBUF.
; DATA TRANSFER MODE IN SYQ_XFRMODE: SYQ_XFR_[NONE|READ|WRITE]
; DATA TRANSFER BUFFER PTR IN SYQ_DSKBUF.
;
POP AF
CALL SYQ_WRITEDATA
SYQ_W2 ( 4 )
SYQ_W2 ( 5 )
SYQ_W2 ( 4 )
SYQ_W0 ( $ FF )
SYQ_RUNCMD:
;
; CONNECT: S1=$B8 S2=$18 S3=$30
; DISCONNECT: S1=$B8 S2=$18 S3=$38
# IF ( SYQTRACE > = 4 )
PRTS ( " CPP: S1=$" )
LD A ,( SYQ_S1 )
CALL PRTHEXBYTE
PRTS ( " S2=$" )
LD A ,( SYQ_S2 )
CALL PRTHEXBYTE
PRTS ( " S3=$" )
LD A ,( SYQ_S3 )
CALL PRTHEXBYTE
# IF ( SYQTRACE > = 3 )
PRTS ( " RUNCMD:$" )
# ENDIF
;
XOR A ; ASSUME SUCCESS FOR NOW
RET
;
SYQ_S1 .DB 0
SYQ_S2 .DB 0
SYQ_S3 .DB 0
CALL SYQ_CONNECT ; CONNECT TO DEVICE
;
; SEQUENCE TO CONNECT TO DEVICE ON PARALLEL PORT BUS.
LD ( SYQ_CMD_STKSAV ), SP ; SAVE STACK FOR ERR EXITS
LD HL , SYQ_CMD_EXIT ; SETUP NORMAL RETURN VIA
PUSH HL ; ... SYQ_CMDEXIT
CALL SYQ_WAITRDY ; WAIT FOR DRIVE READY
;
SYQ_CONNECT:
LD B , 7
LD C , SYQ_REG_PRI + 1
LD HL , SYQ_CMDBUF + 1
SYQ_RUNCMD1:
LD A ,( HL )
# IF ( SYQTRACE > = 3 )
CALL PC_SPACE
CALL PRTHEXBYTE
# ENDIF
PUSH BC
CALL SYQ_WRITEREG
POP BC
INC HL
INC C
DJNZ SYQ_RUNCMD1
;
# IF ( SYQTRACE > = 3 )
PRTS ( " CONNECT:$" )
PRTS ( " --> $" )
# ENDIF
;
LD A , $ 00 ; INITIALIZE THE CHIP
CALL SYQ_CPP
LD A , SYQ_TOSLOW
LD ( SYQ_TIMEOUT ), A
LD A ,( SYQ_TIMEOUT )
PUSH AF
LD A , SYQ_TOSLOW
CALL SYQ_WAITBSY ; WAIT FOR DRIVE READY (COMMAND DONE)
POP AF
LD ( SYQ_TIMEOUT ), A
CALL SYQ_GETRES
;
LD A , $ E0 ; CONNECT TO THE CHIP
CALL SYQ_CPP
LD A ,( SYQ_XFRMODE ) ; DATA TRANSFER?
OR A ; SET FLAGS
JR Z , SYQ_CMD_EXIT ; IF NONE, EXIT, A IS ZERO
CP SYQ_XFR_READ ; READ?
JP Z , SYQ_GETBUF ; READ DATA TO BUFFER
CP SYQ_XFR_WRITE ; WRITE?
JP Z , SYQ_PUTBUF ; WRITE DATA FROM BUFFER
JR SYQ_CMD_CMDERR ; INVALID VALUE FOR XFR
;
SYQ_W0 ( 0 )
SYQ_W2 ( 1 )
SYQ_W2 ( 4 )
SYQ_CMD_CMDERR:
LD A , SYQ_STCMDERR ; SIGNAL COMMAND ERROR
JR SYQ_CMD_EXIT ; AND EXIT
;
SYQ_WR ( $ 08 , $ 10 )
SYQ_WR ( $ 0 C , $ 14 )
SYQ_WR ( $ 0 A , $ 38 )
SYQ_WR ( $ 12 , $ 10 )
SYQ_CMD_IOERR:
LD A , SYQ_STIOERR ; SIGNAL IO ERROR
JR SYQ_CMD_EXIT ; AND EXIT
;
RET
SYQ_CMD_TIMEOUT:
LD A , SYQ_STTO ; SIGNAL TIMEOUT ERROR
JR SYQ_CMD_EXIT ; AND EXIT
;
; SEQUENCE TO DISCONNECT FROM DEVICE ON PARALLEL PORT BUS.
; THE FINAL SYQ_WRITECTRL IS ONLY TO TURN OFF THE MG014 STATUS LED.
SYQ_CMD_EXIT:
LD SP ,( SYQ_CMD_STKSAV ) ; UNWIND STACK
PUSH AF ; SAVE RESULT
CALL SYQ_DISCONNECT ; DISCONNECT
POP AF ; RESTORE RESULT
OR A ; ERROR?
JP NZ , SYQ_ERR ; IF SO, HANDLE IT
RET ; NORMAL RETURN
;
SYQ_DISCONNECT:
;
;
SYQ_GETRES:
SYQ_RR ( SYQ_REG_STAT )
# IF ( SYQTRACE > = 3 )
PRTS ( " DISCON:$" )
CALL PC_SPACE
CALL PRTHEXBYTE
# ENDIF
AND % 00000001 ; ERROR BIT SET?
RET Z ; NOPE, RETURN WITH ZF
;
LD A , $ 30 ; DISCONNECT FROM THE CHIP
CALL SYQ_CPP
;
; TURNS OFF MG014 LED
SYQ_W2 ( $ 8 C )
;
RET
;
; WRITE VALUE IN A TO ATA REGISTER IN C
SYQ_RR ( SYQ_REG_ERR )
# IF ( SYQTRACE > = 3 )
CALL PC_SPACE
CALL PRTHEXBYTE
# ENDIF
JP SYQ_CMD_CMDERR
;
SYQ_WRITEREG:
PUSH AF
LD A , $ 60
ADD A , C
CALL SYQ_WRITEDATA
SYQ_W2 ( 1 )
POP AF
CALL SYQ_WRITEDATA
SYQ_W2 ( 4 )
RET
;
; READ VALUE FROM ATA REGISTER IN C
;
SYQ_READREG:
LD A , C
CALL SYQ_WRITEDATA
SYQ_W2 ( 1 )
SYQ_W2 ( 3 )
CALL SYQ_READSTATUS
AND $ F0
RRCA
RRCA
RRCA
RRCA
LD C , A
PUSH BC
SYQ_W2 ( 4 )
CALL SYQ_READSTATUS
AND $ F0
POP BC
OR C
RET
;
;
;
SYQ_WAITRDY:
LD A ,( SYQ_TIMEOUT ) ; GET TIMEOUT IN 0.05 SECS
LD B , A ; PUT IN OUTER LOOP VAR
SYQ_WAITRDY1:
LD A , B
LD DE ,( SYQ_TOSCALER ) ; CPU SPPED SCALER TO INNER LOOP VAR
SYQ_WAITRDY2:
SYQ_RR ( SYQ_REG_STAT )
LD C , A ; SAVE IT???
AND % 11000000 ; ISOLATE BUSY AND RDY BITS
XOR % 01000000 ; WE WANT BUSY(7) TO BE 0 AND RDY(6) TO BE 1
RET Z ; ALL SET, RETURN WITH Z SET
DEC DE
LD A , D
OR E
JR NZ , SYQ_WAITRDY2 ; INNER LOOP RETURN
DJNZ SYQ_WAITRDY1 ; OUTER LOOP RETURN
JP SYQ_CMD_TIMEOUT ; EXIT WITH RDYTO ERR
;
;
;
SYQ_WAITDRQ:
LD A ,( SYQ_TIMEOUT ) ; GET TIMEOUT IN 0.1 SECS
LD B , A ; PUT IN OUTER LOOP VAR
SYQ_WAITDRQ1:
LD DE ,( SYQ_TOSCALER ) ; CPU SPPED SCALER TO INNER LOOP VAR
SYQ_WAITDRQ2:
SYQ_RR ( SYQ_REG_STAT )
LD C , A ; SAVE IT???
AND % 10001000 ; TO FILL (OR READY TO FILL)
XOR % 00001000
RET Z
DEC DE
LD A , D
OR E
JR NZ , SYQ_WAITDRQ2
DJNZ SYQ_WAITDRQ1
JP SYQ_CMD_TIMEOUT ; EXIT WITH BUFTO ERR
;
;
;
SYQ_WAITBSY:
LD A ,( SYQ_TIMEOUT ) ; GET TIMEOUT IN 0.1 SECS
LD B , A ; PUT IN OUTER LOOP VAR
SYQ_WAITBSY1:
LD DE ,( SYQ_TOSCALER ) ; CPU SPPED SCALER TO INNER LOOP VAR
SYQ_WAITBSY2:
SYQ_RR ( SYQ_REG_STAT )
LD C , A ; SAVE IT??? ; 4TS
AND % 10000000 ; TO FILL (OR READY TO FILL) ; 7TS
RET Z ; 5TS
DEC DE ; 6TS
LD A , D ; 4TS
OR E ; 4TS
JR NZ , SYQ_WAITBSY2 ; 12TS
DJNZ SYQ_WAITBSY1 ; -----
JP SYQ_CMD_TIMEOUT ; EXIT WITH BSYTO ERR ; 180
;
; RUN AN ATA COMMAND USING CMD BUFFER IN SYQ_CMDBUF.
; DATA TRANSFER MODE IN SYQ_XFRMODE: SYQ_XFR_[NONE|READ|WRITE]
; DATA TRANSFER BUFFER PTR IN SYQ_DSKBUF.
;
SYQ_RUNCMD:
;
# IF ( SYQTRACE > = 3 )
PRTS ( " RUNCMD:$" )
# ENDIF
;
CALL SYQ_CONNECT ; CONNECT TO DEVICE
;
LD ( SYQ_CMD_STKSAV ), SP ; SAVE STACK FOR ERR EXITS
LD HL , SYQ_CMD_EXIT ; SETUP NORMAL RETURN VIA
PUSH HL ; ... SYQ_CMDEXIT
CALL SYQ_WAITRDY ; WAIT FOR DRIVE READY
;
LD B , 7
LD C , SYQ_REG_PRI + 1
LD HL , SYQ_CMDBUF + 1
SYQ_RUNCMD1:
LD A ,( HL )
# IF ( SYQTRACE > = 3 )
CALL PC_SPACE
CALL PRTHEXBYTE
# ENDIF
PUSH BC
CALL SYQ_WRITEREG
POP BC
INC HL
INC C
DJNZ SYQ_RUNCMD1
;
# IF ( SYQTRACE > = 3 )
PRTS ( " -->$" )
# ENDIF
;
CALL SYQ_WAITBSY ; WAIT FOR DRIVE READY (COMMAND DONE)
CALL SYQ_GETRES
;
LD A ,( SYQ_XFRMODE ) ; DATA TRANSFER?
OR A ; SET FLAGS
JR Z , SYQ_CMD_EXIT ; IF NONE, EXIT, A IS ZERO
CP SYQ_XFR_READ ; READ?
JP Z , SYQ_GETBUF ; READ DATA TO BUFFER
CP SYQ_XFR_WRITE ; WRITE?
JP Z , SYQ_PUTBUF ; WRITE DATA FROM BUFFER
JR SYQ_CMD_CMDERR ; INVALID VALUE FOR XFR
;
SYQ_CMD_CMDERR:
LD A , SYQ_STCMDERR ; SIGNAL COMMAND ERROR
JR SYQ_CMD_EXIT ; AND EXIT
;
SYQ_CMD_IOERR:
LD A , SYQ_STIOERR ; SIGNAL IO ERROR
JR SYQ_CMD_EXIT ; AND EXIT
;
SYQ_CMD_TIMEOUT:
LD A , SYQ_STTO ; SIGNAL TIMEOUT ERROR
JR SYQ_CMD_EXIT ; AND EXIT
;
SYQ_CMD_EXIT:
LD SP ,( SYQ_CMD_STKSAV ) ; UNWIND STACK
PUSH AF ; SAVE RESULT
CALL SYQ_DISCONNECT ; DISCONNECT
POP AF ; RESTORE RESULT
OR A ; ERROR?
JP NZ , SYQ_ERR ; IF SO, HANDLE IT
RET ; NORMAL RETURN
;
;
;
SYQ_GETRES:
SYQ_RR ( SYQ_REG_STAT )
# IF ( SYQTRACE > = 3 )
CALL PC_SPACE
CALL PRTHEXBYTE
# ENDIF
AND % 00000001 ; ERROR BIT SET?
RET Z ; NOPE, RETURN WITH ZF
;
SYQ_RR ( SYQ_REG_ERR )
# IF ( SYQTRACE > = 3 )
CALL PC_SPACE
CALL PRTHEXBYTE
# ENDIF
JP SYQ_CMD_CMDERR
;
;
;
SYQ_GETBUF:
SYQ_W0 ( 7 )
SYQ_GETBUF:
SYQ_W0 ( 7 )
SYQ_W2 ( 1 )
SYQ_W2 ( 3 )
SYQ_W0 ( $ FF )
@ -906,8 +713,10 @@ SYQ_GETBUF:
LD ( SYQ_GETBUF_D ), A ;
INC A ; CONTROL PORT
LD C , A ; ... TO C
# IF ( SYQMODE = = SYQMODE_MG014 )
; HL: STATMAP
LD H , MG014_STATMAPLO >> 8
# ENDIF
EXX ; SWITCH TO PRI REGS
EX AF , AF ' ; SWITCH TO PRI AF
CALL SYQ_GETBUF1 ; 256 WORDS
@ -941,6 +750,7 @@ SYQ_GETBUF1:
LD E , $ 04
# ENDIF
OUT ( C ), D ; FIRST CLOCK
NOP ; SMALL DELAY SEEMS TO BE NEEDED
SYQ_GETBUF_A .EQU $ + 1
IN A ,( $ FF ) ; GET LOW NIBBLE
# IF ( SYQMODE = = SYQMODE_MG014 )
@ -959,6 +769,7 @@ SYQ_GETBUF_A .EQU $+1
LD L , A ; SAVE NIBBLE IN L
# ENDIF
OUT ( C ), E ; SECOND CLOCK
NOP ; SMALL DELAY SEEMS TO BE NEEDED
SYQ_GETBUF_B .EQU $ + 1
IN A ,( $ FF ) ; GET HIGH NIBBLE
# IF ( SYQMODE = = SYQMODE_MG014 )
@ -976,6 +787,14 @@ SYQ_GETBUF_B .EQU $+1
LD ( DE ), A ; SAVE BYTE
INC DE ; BUMP BUF PTR
;
; SPECIAL HANDLING FOR LAST BYTE
LD A , B ; GET ITERATION COUNTER
DEC A ; SET ZF IF ON LAST ITERATION
JR NZ , SYQ_GETBUF2 ; IF NOT SET, SKIP OVER
LD A , $ FF ; VALUE TO WRITE
CALL SYQ_WRITEDATA ; PUT VALUE ON DATA BUS
;
SYQ_GETBUF2:
; SECOND BYTE
EXX ; ALT REGS
;
@ -989,6 +808,7 @@ SYQ_GETBUF_B .EQU $+1
LD E , $ 05
# ENDIF
OUT ( C ), D ; FIRST CLOCK
NOP ; SMALL DELAY SEEMS TO BE NEEDED
SYQ_GETBUF_C .EQU $ + 1
IN A ,( $ FF ) ; GET LOW NIBBLE
# IF ( SYQMODE = = SYQMODE_MG014 )
@ -1007,6 +827,7 @@ SYQ_GETBUF_C .EQU $+1
LD L , A ; SAVE NIBBLE IN L
# ENDIF
OUT ( C ), E ; SECOND CLOCK
NOP ; SMALL DELAY SEEMS TO BE NEEDED
SYQ_GETBUF_D .EQU $ + 1
IN A ,( $ FF ) ; GET HIGH NIBBLE
# IF ( SYQMODE = = SYQMODE_MG014 )
@ -1072,15 +893,6 @@ SYQ_PUTBUF_B .EQU $+1
DJNZ SYQ_PUTBUF1 ; LOOP
RET ; DONE
;
; CHECK CURRENT DEVICE FOR ERROR STATUS AND ATTEMPT TO RECOVER
; VIA RESET IF DEVICE IS IN ERROR.
;
SYQ_CHKERR:
LD A ,( IY + SYQ_STAT ) ; GET STATUS
OR A ; SET FLAGS
CALL NZ , SYQ_RESET ; IF ERROR STATUS, RESET BUS
RET
;
; (RE)INITIALIZE DEVICE
;
SYQ_INITDEV:
@ -1171,62 +983,285 @@ SYQ_INITDEV2:
;
RET ; RETURN, A=0, Z SET
;
;=============================================================================
; INTERFACE SUPPORT ROUTINES
;=============================================================================
;
; OUTPUT BYTE IN A TO THE DATA PORT
;
SYQ_WRITEDATA: ; 17 (CALL)
LD C ,( IY + SYQ_IOBASE ) ; DATA PORT IS AT IOBASE ; 19
OUT ( C ), A ; WRITE THE BYTE ; 12
;CALL DELAY ; IS THIS NEEDED???
RET ; DONE ; 10
; ; --> 58
;
;
SYQ_WRITECTRL: ; 17 (CALL)
; IBM PC INVERTS ALL BUT C2 ON THE BUS, MG014 DOES NOT.
; BELOW TRANSLATES FROM IBM -> MG014. IT ALSO INVERTS THE
; MG014 LED SIMPLY TO MAKE IT EASY TO KEEP LED ON DURING
; ALL ACTIVITY.
;
# IF ( SYQMODE = = SYQMODE_MG014
XOR $ 0B | $ 80 ; HIGH BIT IS MG014 LED
# ENDIF
LD C ,( IY + SYQ_IOBASE ) ; GET BASE IO ADDRESS ; 19
INC C ; BUMP TO CONTROL PORT ; 4
INC C ; 4
OUT ( C ), A ; WRITE TO CONTROL PORT ; 12
;CALL DELAY ; IS THIS NEEDED?
RET ; DONE ; 10
; ; --> 49
; READ THE PARALLEL PORT INPUT LINES (STATUS) AND MAP SIGNALS FROM
; MG014 TO IBM STANDARD. NOTE POLARITY CHANGE REQUIRED FOR BUSY.
;
; MG014 IBM PC (SPP)
; -------- --------
; 0: /ACK 6: /ACK
; 1: BUSY 7: /BUSY
; 2: POUT 5: POUT
; 3: SEL 4: SEL
; 4: /ERR 3: /ERR
;
SYQ_READSTATUS: ; 17 (CALL)
LD C ,( IY + SYQ_IOBASE ) ; IOBASE TO C ; 19
INC C ; BUMP TO STATUS PORT ; 4
IN A ,( C ) ; READ IT ; 12
;
# IF ( SYQMODE = = SYQMODE_MG014
;
; SHUFFLE BITS ON MG014
LD C , 0 ; INIT RESULT
BIT 0 , A ; 0: /ACK
JR Z , SYQ_READSTATUS1
SET 6 , C ; 6: /ACK
SYQ_READSTATUS1:
BIT 1 , A ; 1: BUSY
JR NZ , SYQ_READSTATUS2 ; POLARITY CHANGE!
SET 7 , C ; 7: /BUSY
SYQ_READSTATUS2:
BIT 2 , A ; 2: POUT
JR Z , SYQ_READSTATUS3
SET 5 , C ; 5: POUT
SYQ_READSTATUS3:
BIT 3 , A ; 3: SEL
JR Z , SYQ_READSTATUS4
SET 4 , C ; 4: SEL
SYQ_READSTATUS4:
BIT 4 , A ; 4: /ERR
JR Z , SYQ_READSTATUS5
SET 3 , C ; 3: /ERR
SYQ_READSTATUS5:
LD A , C ; RESULT TO A
;
# ENDIF
;
RET ; 10
; ; --> 62
; SIGNAL SEQUENCE TO CONNECT/DISCONNECT
; VALUE IN A IS WRITTEN TO DATA PORT DURING SEQUENCE
;
SYQ_CPP:
PUSH AF
SYQ_W2 ( 4 )
SYQ_W0 ( $ 22 )
SYQ_W0 ( $ AA )
SYQ_W0 ( $ 55 )
SYQ_W0 ( 0 )
SYQ_W0 ( $ FF )
;
CALL SYQ_READSTATUS
AND $ B8
LD ( SYQ_S1 ), A
;
SYQ_W0 ( $ 87 )
;
CALL SYQ_READSTATUS
AND $ B8
LD ( SYQ_S2 ), A
;
SYQ_W0 ( $ 78 )
;
CALL SYQ_READSTATUS
AND $ 38
LD ( SYQ_S3 ), A
;
POP AF
CALL SYQ_WRITEDATA
SYQ_W2 ( 4 )
SYQ_W2 ( 5 )
SYQ_W2 ( 4 )
SYQ_W0 ( $ FF )
;
; CONNECT: S1=$B8 S2=$18 S3=$30
; DISCONNECT: S1=$B8 S2=$18 S3=$38
# IF ( SYQTRACE > = 4 )
PRTS ( " CPP: S1=$" )
LD A ,( SYQ_S1 )
CALL PRTHEXBYTE
PRTS ( " S2=$" )
LD A ,( SYQ_S2 )
CALL PRTHEXBYTE
PRTS ( " S3=$" )
LD A ,( SYQ_S3 )
CALL PRTHEXBYTE
# ENDIF
;
XOR A ; ASSUME SUCCESS FOR NOW
RET
;
SYQ_S1 .DB 0
SYQ_S2 .DB 0
SYQ_S3 .DB 0
;
; SEQUENCE TO CONNECT TO DEVICE ON PARALLEL PORT BUS.
;
SYQ_CONNECT:
;
SYQ_IDENTIFY:
# IF ( SYQTRACE > = 3 )
CALL SYQ_PRTPREFIX
PRTS ( " IDDEV$" )
PRTS ( " CONNECT:$" )
# ENDIF
;
LD C , SYQ_CMD_IDDEV
LD DE , 0
LD HL , 0
CALL SYQ_CMDSETUP
LD A , $ 00 ; INITIALIZE THE CHIP
CALL SYQ_CPP
;
LD HL , HB_WRKBUF
LD ( SYQ_DSKBUF ), HL
LD A , SYQ_XFR_READ
LD ( SYQ_XFRMODE ), A
LD A , $ E0 ; CONNECT TO THE CHIP
CALL SYQ_CPP
;
JP SYQ_RUNCMD
SYQ_W0 ( 0 )
SYQ_W2 ( 1 )
SYQ_W2 ( 4 )
;
SYQ_WR ( $ 08 , $ 10 )
SYQ_WR ( $ 0 C , $ 14 )
SYQ_WR ( $ 0 A , $ 38 )
SYQ_WR ( $ 12 , $ 10 )
;
RET
;
; SEQUENCE TO DISCONNECT FROM DEVICE ON PARALLEL PORT BUS.
; THE FINAL SYQ_WRITECTRL IS ONLY TO TURN OFF THE MG014 STATUS LED.
;
SYQ_DISCONNECT:
;
SYQ_MEDIASTATUS:
# IF ( SYQTRACE > = 3 )
CALL SYQ_PRTPREFIX
PRTS ( " MEDIASTATUS$" )
PRTS ( " DISCON:$" )
# ENDIF
;
LD C , SYQ_CMD_MEDIASTATUS
LD DE , 0
LD HL , 0
CALL SYQ_CMDSETUP
LD A , $ 30 ; DISCONNECT FROM THE CHIP
CALL SYQ_CPP
;
LD HL , 0
LD ( SYQ_DSKBUF ), HL
LD A , SYQ_XFR_NONE
LD ( SYQ_XFRMODE ), A
; TURNS OFF MG014 LED
SYQ_W2 ( $ 8 C )
;
JP SYQ_RUNCMD
RET
;
; DE:HL LBA
; C: COMMAND
; WRITE VALUE IN A TO ATA REGISTER IN C
;
SYQ_CMDSETUP:
XOR A
LD ( SYQ_CMD_FEAT ), A
INC A
LD ( SYQ_CMD_COUNT ), A
LD ( SYQ_CMD_LBA0 ), HL
LD ( SYQ_CMD_LBA2 ), DE
LD A , $ E0
LD ( SYQ_CMD_DRV ), A
LD A , C
LD ( SYQ_CMD_OP ), A
SYQ_WRITEREG:
PUSH AF
LD A , $ 60
ADD A , C
CALL SYQ_WRITEDATA
SYQ_W2 ( 1 )
POP AF
CALL SYQ_WRITEDATA
SYQ_W2 ( 4 )
RET
;
; READ VALUE FROM ATA REGISTER IN C
;
SYQ_READREG: ; 17 (CALL)
LD A , C ; 4
CALL SYQ_WRITEDATA ; 58
SYQ_W2 ( 1 ) ; 49 + 7
SYQ_W2 ( 3 ) ; 49 + 7
CALL SYQ_READSTATUS ; 62
AND $ F0 ; 7
RRCA ; 4
RRCA ; 4
RRCA ; 4
RRCA ; 4
LD C , A ; 4
PUSH BC ; 11
SYQ_W2 ( 4 ) ; 49 + 7
CALL SYQ_READSTATUS ; 62
AND $ F0 ; 7
POP BC ; 10
OR C ; 4
RET ; 10
; ; --> 440
; CHECK CURRENT DEVICE FOR ERROR STATUS AND ATTEMPT TO RECOVER
; VIA RESET IF DEVICE IS IN ERROR.
;
SYQ_CHKERR:
LD A ,( IY + SYQ_STAT ) ; GET STATUS
OR A ; SET FLAGS
CALL NZ , SYQ_RESET ; IF ERROR STATUS, RESET BUS
RET
;
;
;
SYQ_WAITRDY:
LD A ,( SYQ_TIMEOUT ) ; GET TIMEOUT IN 0.05 SECS
LD B , A ; PUT IN OUTER LOOP VAR
SYQ_WAITRDY1:
LD A , B
LD DE ,( SYQ_TOSCALER ) ; CPU SPPED SCALER TO INNER LOOP VAR
SYQ_WAITRDY2:
SYQ_RR ( SYQ_REG_STAT )
LD C , A ; SAVE IT???
AND % 11000000 ; ISOLATE BUSY AND RDY BITS
XOR % 01000000 ; WE WANT BUSY(7) TO BE 0 AND RDY(6) TO BE 1
RET Z ; ALL SET, RETURN WITH Z SET
DEC DE
LD A , D
OR E
JR NZ , SYQ_WAITRDY2 ; INNER LOOP RETURN
DJNZ SYQ_WAITRDY1 ; OUTER LOOP RETURN
JP SYQ_CMD_TIMEOUT ; EXIT WITH RDYTO ERR
;
;
;
SYQ_WAITDRQ:
LD A ,( SYQ_TIMEOUT ) ; GET TIMEOUT IN 0.1 SECS
LD B , A ; PUT IN OUTER LOOP VAR
SYQ_WAITDRQ1:
LD DE ,( SYQ_TOSCALER ) ; CPU SPPED SCALER TO INNER LOOP VAR
SYQ_WAITDRQ2:
SYQ_RR ( SYQ_REG_STAT )
LD C , A ; SAVE IT???
AND % 10001000 ; TO FILL (OR READY TO FILL)
XOR % 00001000
RET Z
DEC DE
LD A , D
OR E
JR NZ , SYQ_WAITDRQ2
DJNZ SYQ_WAITDRQ1
JP SYQ_CMD_TIMEOUT ; EXIT WITH BUFTO ERR
;
;
;
SYQ_WAITBSY:
LD A ,( SYQ_TIMEOUT ) ; GET TIMEOUT IN 0.1 SECS
LD B , A ; PUT IN OUTER LOOP VAR
SYQ_WAITBSY1:
LD DE ,( SYQ_TOSCALER ) ; CPU SPPED SCALER TO INNER LOOP VAR
SYQ_WAITBSY2:
SYQ_RR ( SYQ_REG_STAT ) ; 440 + 7
LD C , A ; SAVE IT??? ; 4TS
AND % 10000000 ; TO FILL (OR READY TO FILL) ; 7TS
RET Z ; 5TS
DEC DE ; 6TS
LD A , D ; 4TS
OR E ; 4TS
JR NZ , SYQ_WAITBSY2 ; 12TS
DJNZ SYQ_WAITBSY1 ; -----
JP SYQ_CMD_TIMEOUT ; EXIT WITH BSYTO ERR ; 489
;
;=============================================================================
; ERROR HANDLING AND DIAGNOSTICS
;=============================================================================
@ -1394,7 +1429,7 @@ SYQ_CMD_DRV .DB 0
SYQ_CMD_OP .DB 0
;
SYQ_TIMEOUT .DB SYQ_TONORM ; WAIT FUNCS TIMEOUT IN TENTHS OF SEC
SYQ_TOSCALER .DW CPUMHZ * 556 ; WAIT FUNCS SCALER FOR CPU SPEED
SYQ_TOSCALER .DW CPUMHZ * 511 ; WAIT FUNCS SCALER FOR CPU SPEED
;
; SYQ DEVICE CONFIGURATION TABLE
;