Files
RomWBW/Source/HBIOS/syq.asm
Wayne Warthen f8c800e527 Create DSKY Driver Framework
Added a new driver category for DSKY (Display/Keypad) devices.  Existing DSKY devices were converted into drivers ICM and PKD.  These devices were previously DSKY and DSKYNG.

This removes substantial code duplication and recovers significant space in romldr and dbgmon.
2023-06-28 15:06:53 -07:00

1467 lines
35 KiB
NASM

;
;=============================================================================
; SYQ DISK DRIVER
;=============================================================================
;
; PARALLEL PORT INTERFACE FOR ATA DISK DEVICES USING A PARALLEL PORT
; ADAPTER. PRIMARILY TARGETS PARALLEL PORT SYQUEST DRIVES.
;
; INTENDED TO CO-EXIST WITH LPT DRIVER.
;
; CREATED BY WAYNE WARTHEN FOR ROMWBW HBIOS.
; MUCH OF THE CODE IS DERIVED FROM LINUX AND FUZIX (ALAN COX).
; - https://github.com/EtchedPixels/FUZIX
; - https://github.com/torvalds/linux
;
; 05/29/2023 WBW - INITIAL RELEASE
; 06/06/2023 WBW - OPTIMIZE BLOCK READ AND WRITE
;
;=============================================================================
;
; IBM PC STANDARD PARALLEL PORT (SPP):
; - NHYODYNE PRINT MODULE
;
; PORT 0 (OUTPUT):
;
; D7 D6 D5 D4 D3 D2 D1 D0
; +-------+-------+-------+-------+-------+-------+-------+-------+
; | PD7 | PD6 | PD5 | PD4 | PD3 | PD2 | PD1 | PD0 |
; +-------+-------+-------+-------+-------+-------+-------+-------+
;
; PORT 1 (INPUT):
;
; D7 D6 D5 D4 D3 D2 D1 D0
; +-------+-------+-------+-------+-------+-------+-------+-------+
; | /BUSY | /ACK | POUT | SEL | /ERR | 0 | 0 | 0 |
; +-------+-------+-------+-------+-------+-------+-------+-------+
;
; PORT 2 (OUTPUT):
;
; D7 D6 D5 D4 D3 D2 D1 D0
; +-------+-------+-------+-------+-------+-------+-------+-------+
; | STAT1 | STAT0 | ENBL | PINT | SEL | RES | LF | STB |
; +-------+-------+-------+-------+-------+-------+-------+-------+
;
;=============================================================================
;
; MG014 STYLE INTERFACE:
; - RCBUS MG014 MODULE
;
; PORT 0 (OUTPUT):
;
; D7 D6 D5 D4 D3 D2 D1 D0
; +-------+-------+-------+-------+-------+-------+-------+-------+
; | PD7 | PD6 | PD5 | PD4 | PD3 | PD2 | PD1 | PD0 |
; +-------+-------+-------+-------+-------+-------+-------+-------+
;
; PORT 1 (INPUT):
;
; D7 D6 D5 D4 D3 D2 D1 D0
; +-------+-------+-------+-------+-------+-------+-------+-------+
; | | | | /ERR | SEL | POUT | BUSY | /ACK |
; +-------+-------+-------+-------+-------+-------+-------+-------+
;
; PORT 2 (OUTPUT):
;
; D7 D6 D5 D4 D3 D2 D1 D0
; +-------+-------+-------+-------+-------+-------+-------+-------+
; | LED | | | | /SEL | /RES | /LF | /STB |
; +-------+-------+-------+-------+-------+-------+-------+-------+
;
;=============================================================================
;
; TODO:
;
; NOTES:
;
; - TESTED ON THE SYQUEST SPARQ ONLY.
;
; - 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
; THE STANDARD IBM PARALLEL PORT WHICH NECESSITATES A BUNCH OF EXTRA
; BIT FIDDLING ON EVERY READ.
;
; - SOME OF THE DATA TRANSFERS HAVE NO BUFFER OVERRUN CHECKS. IT IS
; ASSUMED SCSI DEVICES WILL SEND/REQUEST THE EXPECTED NUMBER OF BYTES.
;
; SYQ PORT OFFSETS
;
SYQ_IODATA .EQU 0 ; PORT A, DATA, OUT
SYQ_IOSTAT .EQU 1 ; PORT B, STATUS, IN
SYQ_IOCTRL .EQU 2 ; PORT C, CTRL, OUT
SYQ_IOSETUP .EQU 3 ; PPI SETUP
;
; THIS INTERFACE TRANSLATES BETWEEN PPI AND ATA. THE ATA REGSITERS
; CAN BE ACCESSED THROUGH THE INTERFACE. THE INTERFACE ALSO HAS
; REGISTERS OF ITS OWN.
;
SYQ_REG_NAT .EQU 0 ; START OF NATIVE INTERFACE REGISTERS
SYQ_REG_PRI .EQU $18 ; START OF PRIMARY ATA REGISTERS
SYQ_REG_ALT .EQU $10 ; START OF ALTERNATE ATA REGISTERS
;
SYQ_REG_DATA .EQU SYQ_REG_PRI + $00 ; DATA /OUTPUT (R/W)
SYQ_REG_ERR .EQU SYQ_REG_PRI + $01 ; ERROR REGISTER (R)
SYQ_REG_FEAT .EQU SYQ_REG_PRI + $01 ; FEATURES REGISTER (W)
SYQ_REG_COUNT .EQU SYQ_REG_PRI + $02 ; SECTOR COUNT REGISTER (R/W)
SYQ_REG_SECT .EQU SYQ_REG_PRI + $03 ; SECTOR NUMBER REGISTER (R/W)
SYQ_REG_CYLLO .EQU SYQ_REG_PRI + $04 ; CYLINDER NUM REGISTER (LSB) (R/W)
SYQ_REG_CYLHI .EQU SYQ_REG_PRI + $05 ; CYLINDER NUM REGISTER (MSB) (R/W)
SYQ_REG_DRVHD .EQU SYQ_REG_PRI + $06 ; DRIVE/HEAD REGISTER (R/W)
SYQ_REG_LBA0 .EQU SYQ_REG_PRI + $03 ; LBA BYTE 0 (BITS 0-7) (R/W)
SYQ_REG_LBA1 .EQU SYQ_REG_PRI + $04 ; LBA BYTE 1 (BITS 8-15) (R/W)
SYQ_REG_LBA2 .EQU SYQ_REG_PRI + $05 ; LBA BYTE 2 (BITS 16-23) (R/W)
SYQ_REG_LBA3 .EQU SYQ_REG_PRI + $06 ; LBA BYTE 3 (BITS 24-27) (R/W)
SYQ_REG_STAT .EQU SYQ_REG_PRI + $07 ; STATUS REGISTER (R)
SYQ_REG_CMD .EQU SYQ_REG_PRI + $07 ; COMMAND REGISTER (EXECUTE) (W)
SYQ_REG_XAR .EQU SYQ_REG_ALT + $00 ; ECB DIDE EXTERNAL ADDRESS REGISTER (W)
SYQ_REG_ALTSTAT .EQU SYQ_REG_ALT + $06 ; ALTERNATE STATUS REGISTER (R)
SYQ_REG_CTRL .EQU SYQ_REG_ALT + $06 ; DEVICE CONTROL REGISTER (W)
SYQ_REG_DRVADR .EQU SYQ_REG_ALT + $07 ; DRIVE ADDRESS REGISTER (R)
;
; ATA COMMAND BYTES
;
SYQ_CMD_NOP .EQU $00
SYQ_CMD_DEVRES .EQU $08
SYQ_CMD_RECAL .EQU $10
SYQ_CMD_READ .EQU $20
SYQ_CMD_WRITE .EQU $30
SYQ_CMD_DEVDIAG .EQU $90
SYQ_CMD_IDPKTDEV .EQU $A1
SYQ_CMD_MEDIASTATUS .EQU $DA
SYQ_CMD_IDDEV .EQU $EC
SYQ_CMD_SETFEAT .EQU $EF
;
; POST-COMMAND DATA TRANSFER OPTIONS
;
SYQ_XFR_NONE .EQU 0 ; NO DATA TRANSFER FOR CMD
SYQ_XFR_READ .EQU 1 ; CMD IS A READ OPERATION
SYQ_XFR_WRITE .EQU 2 ; CMD IS A WRITE OPERATION
;
; SYQ DEVICE STATUS
;
SYQ_STOK .EQU 0
SYQ_STNOMEDIA .EQU -1
SYQ_STCMDERR .EQU -2
SYQ_STIOERR .EQU -3
SYQ_STTO .EQU -4
SYQ_STNOTSUP .EQU -5
;
; SYQ DEVICE CONFIGURATION
;
SYQ_CFGSIZ .EQU 12 ; SIZE OF CFG TBL ENTRIES
;
; PER DEVICE DATA OFFSETS IN CONFIG TABLE ENTRIES
;
SYQ_DEV .EQU 0 ; OFFSET OF DEVICE NUMBER (BYTE)
SYQ_MODE .EQU 1 ; OPERATION MODE: SYQ MODE (BYTE)
SYQ_STAT .EQU 2 ; LAST STATUS (BYTE)
SYQ_IOBASE .EQU 3 ; IO BASE ADDRESS (BYTE)
SYQ_MEDCAP .EQU 4 ; MEDIA CAPACITY (DWORD)
SYQ_LBA .EQU 8 ; OFFSET OF LBA (DWORD)
;
; THE SYQ_WAITXXX FUNCTIONS ARE BUILT TO TIMEOUT AS NEEDED SO DRIVER WILL
; NOT HANG IF DEVICE IS UNRESPONSIVE. DIFFERENT TIMEOUTS ARE USED DEPENDING
; ON THE SITUATION. THE SLOW TIMEOUT IS USED TO WAIT FOR A DEVICE TO
; BECOME READY AFTER A HARD RESET (SPIN UP, ETC.). THE NORMAL TIMEOUT
; IS USED DURING NORMAL OPERATION FOR ALL I/O OPERATIONS WHICH SHOULD
; 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.
;
SYQ_TOSLOW .EQU 120 ; SLOW TIMEOUT IS 30 SECS (30 / .25)
SYQ_TONORM .EQU 4 ; NORMAL TIMEOUT IS 1 SEC (1 / .25)
;
; MACROS
;
#DEFINE SYQ_W0(VAL) LD A,VAL \ CALL SYQ_WRITEDATA
#DEFINE SYQ_R1 CALL SYQ_READSTATUS
#DEFINE SYQ_W2(VAL) LD A,VAL \ CALL SYQ_WRITECTRL
;
#DEFINE SYQ_WR(REG,VAL) LD C,REG \ LD A,VAL \ CALL SYQ_WRITEREG
#DEFINE SYQ_RR(REG) LD C,REG \ CALL SYQ_READREG
;
; INCLUDE MG014 NIBBLE MAP FOR MG014 MODE
;
#IF (SYQMODE == SYQMODE_MG014)
#DEFINE MG014_MAP
#ENDIF
;
;=============================================================================
; INITIALIZATION ENTRY POINT
;=============================================================================
;
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:
LD A,(IY) ; LOAD FIRST BYTE TO CHECK FOR END
CP $FF ; CHECK FOR END OF TABLE VALUE
JR NZ,SYQ_INIT2 ; IF NOT END OF TABLE, CONTINUE
XOR A ; SIGNAL SUCCESS
RET ; AND RETURN
;
SYQ_INIT2:
CALL NEWLINE ; FORMATTING
PRTS("SYQ:$") ; DRIVER LABEL
;
PRTS(" IO=0x$") ; LABEL FOR IO ADDRESS
LD A,(IY+SYQ_IOBASE) ; GET IO BASE ADDRES
CALL PRTHEXBYTE ; DISPLAY IT
;
PRTS(" MODE=$") ; LABEL FOR MODE
LD A,(IY+SYQ_MODE) ; GET MODE BITS
LD HL,SYQ_STR_MODE_MAP
ADD A,A
CALL ADDHLA
LD E,(HL)
INC HL
LD D,(HL)
CALL WRITESTR
;
; CHECK FOR HARDWARE PRESENCE
CALL SYQ_DETECT ; PROBE FOR INTERFACE
JR Z,SYQ_INIT4 ; IF FOUND, CONTINUE
CALL PC_SPACE ; FORMATTING
LD DE,SYQ_STR_NOHW ; NO SYQ MESSAGE
CALL WRITESTR ; DISPLAY IT
JR SYQ_INIT6 ; SKIP CFG ENTRY
;
SYQ_INIT4:
; UPDATE DRIVER RELATIVE UNIT NUMBER IN CONFIG TABLE
LD A,(SYQ_DEVNUM) ; GET NEXT UNIT NUM TO ASSIGN
LD (IY+SYQ_DEV),A ; UPDATE IT
INC A ; BUMP TO NEXT UNIT NUM TO ASSIGN
LD (SYQ_DEVNUM),A ; SAVE IT
;
; ADD UNIT TO GLOBAL DISK UNIT TABLE
LD BC,SYQ_FNTBL ; BC := FUNC TABLE ADR
PUSH IY ; CFG ENTRY POINTER
POP DE ; COPY TO DE
CALL DIO_ADDENT ; ADD ENTRY TO GLOBAL DISK DEV TABLE
;
CALL SYQ_RESET ; RESET/INIT THE INTERFACE
#IF (SYQTRACE <= 1)
CALL NZ,SYQ_PRTSTAT
#ENDIF
JR NZ,SYQ_INIT6
;
; START PRINTING DEVICE INFO
CALL SYQ_PRTPREFIX ; PRINT DEVICE PREFIX
;
SYQ_INIT5:
; PRINT STORAGE CAPACITY (BLOCK COUNT)
PRTS(" BLOCKS=0x$") ; PRINT FIELD LABEL
LD A,SYQ_MEDCAP ; OFFSET TO CAPACITY FIELD
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
CALL LD32 ; GET THE CAPACITY VALUE
CALL PRTHEX32 ; PRINT HEX VALUE
;
; PRINT STORAGE SIZE IN MB
PRTS(" SIZE=$") ; PRINT FIELD LABEL
LD B,11 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB
CALL SRL32 ; RIGHT SHIFT
CALL PRTDEC32 ; PRINT DWORD IN DECIMAL
PRTS("MB$") ; PRINT SUFFIX
;
SYQ_INIT6:
LD DE,SYQ_CFGSIZ ; SIZE OF CFG TABLE ENTRY
ADD IY,DE ; BUMP POINTER
JP SYQ_INIT1 ; AND LOOP
;
;----------------------------------------------------------------------
; PROBE FOR SYQ HARDWARE
;----------------------------------------------------------------------
;
; ON RETURN, ZF SET INDICATES HARDWARE FOUND
;
SYQ_DETECT:
;
#IF (SYQTRACE >= 3)
PRTS("\r\nDETECT:$")
#ENDIF
;
#IF (SYQMODE == SYQMODE_MG014)
; INITIALIZE 8255
LD A,(IY+SYQ_IOBASE) ; BASE PORT
ADD A,SYQ_IOSETUP ; BUMP TO SETUP PORT
LD C,A ; MOVE TO C FOR I/O
LD A,$82 ; CONFIG A OUT, B IN, C OUT
OUT (C),A ; DO IT
CALL DELAY ; BRIEF DELAY FOR GOOD MEASURE
#ENDIF
;
; WE USE THIS SEQUENCE TO DETECT AN ACTUAL SYQ DEVICE ON THE
; PARALLEL PORT. THE VALUES RECORDED IN THE FINAL CALL TO
; SYQ_DISCONNECT ARE USED TO CONFIRM DEVICE PRESENCE.
; NO ACTUAL ATA COMMANDS ARE USED.
CALL SYQ_DISCONNECT
CALL SYQ_CONNECT
CALL SYQ_DISCONNECT
;
; THE SYQ_SN VALUES ARE RECORDED IN THE CPP ROUTINE USED BY
; SYQ_CONNECT/DISCONNECT.
; EXPECTING S1=$B8, S2=$18, S3=$38
LD A,(SYQ_S1)
CP $B8
RET NZ
LD A,(SYQ_S2)
CP $18
RET NZ
LD A,(SYQ_S3)
CP $38
RET NZ
;
; PRESENCE CHECK
CALL SYQ_CONNECT
;
#IF (SYQTRACE >= 3)
PRTS(" CHK:$")
#ENDIF
;
SYQ_WR($18+2,$AA)
SYQ_WR($18+3,$55)
SYQ_RR($18+2)
#IF (SYQTRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
LD H,A
SYQ_RR($18+3)
#IF (SYQTRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
LD L,A
CALL SYQ_DISCONNECT
;
LD A,H
CP $AA
RET NZ
LD A,L
CP $55
RET
;
;=============================================================================
; DRIVER FUNCTION TABLE
;=============================================================================
;
SYQ_FNTBL:
.DW SYQ_STATUS
.DW SYQ_RESET
.DW SYQ_SEEK
.DW SYQ_READ
.DW SYQ_WRITE
.DW SYQ_VERIFY
.DW SYQ_FORMAT
.DW SYQ_DEVICE
.DW SYQ_MEDIA
.DW SYQ_DEFMED
.DW SYQ_CAP
.DW SYQ_GEOM
#IF (($ - SYQ_FNTBL) != (DIO_FNCNT * 2))
.ECHO "*** INVALID SYQ FUNCTION TABLE ***\n"
#ENDIF
;
SYQ_VERIFY:
SYQ_FORMAT:
SYQ_DEFMED:
SYSCHKERR(ERR_NOTIMPL) ; NOT IMPLEMENTED
RET
;
;
;
SYQ_READ:
CALL HB_DSKREAD ; HOOK DISK READ CONTROLLER
LD B,SYQ_XFR_READ ; READ TRANSFER MODE
LD C,SYQ_CMD_READ ; READ COMMAND BYTE
JP SYQ_IO ; DO THE I/O
;
;
;
SYQ_WRITE:
CALL HB_DSKWRITE ; HOOK DISK WRITE CONTROLLER
LD B,SYQ_XFR_WRITE ; WRITE TRANSFER MODE
LD C,SYQ_CMD_WRITE ; WRITE COMMAND BYTE
JP SYQ_IO ; DO THE I/O
;
;
;
SYQ_IO:
;
PUSH BC ; SAVE MODE/COMMAND
PUSH HL ; SAVE DISK BUF PTR
CALL SYQ_CHKERR ; CHECK FOR ERR STATUS AND RESET IF SO
POP HL ; RECOVER DISK BUF PTR
POP BC ; RECOVER MODE/COMMAND
JR NZ,SYQ_IO1 ; BAIL OUT ON ERROR
;
LD A,B ; XFR MODE TO ACCUM
LD (SYQ_XFRMODE),A ; AND SAVE IT FOR CMD
LD (SYQ_DSKBUF),HL ; SAVE DISK BUFFER ADDRESS
LD A,SYQ_LBA ; LBA OFFSET IN CONFIG
CALL LDHLIYA ; POINT TO LBA DWORD
#IF (DSKYENABLE)
#IF (DSKYDSKACT)
CALL HB_DSKACT ; SHOW ACTIVITY
#ENDIF
#ENDIF
CALL LD32 ; SET DE:HL TO LBA
;
CALL SYQ_CMDSETUP ; SETUP ATA COMMAND BUF
CALL SYQ_RUNCMD ; RUN COMMAND
JR NZ,SYQ_IO1 ; IF ERR, SKIP INCREMENT
;
; INCREMENT LBA
LD A,SYQ_LBA ; LBA OFFSET
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
CALL INC32HL ; INCREMENT THE VALUE
;
; INCREMENT DMA
LD HL,SYQ_DSKBUF+1 ; POINT TO MSB OF BUFFER ADR
INC (HL) ; BUMP DMA BY
INC (HL) ; ... 512 BYTES
;
XOR A ; SIGNAL SUCCESS
;
SYQ_IO1:
LD HL,(SYQ_DSKBUF) ; CURRENT DMA TO HL
OR A ; SET FLAGS
RET ; AND DONE
;
;
;
SYQ_STATUS:
; RETURN UNIT STATUS
LD A,(IY+SYQ_STAT) ; GET STATUS OF SELECTED DEVICE
OR A ; SET FLAGS
RET ; AND RETURN
;
;
;
SYQ_RESET:
JP SYQ_INITDEV ; JUST (RE)INIT DEVICE
;
;
;
SYQ_DEVICE:
LD D,DIODEV_SYQ ; D := DEVICE TYPE
LD E,(IY+SYQ_DEV) ; E := PHYSICAL DEVICE NUMBER
LD C,%01111001 ; C := REMOVABLE HARD DISK
LD H,(IY+SYQ_MODE) ; H := MODE
LD L,(IY+SYQ_IOBASE) ; L := BASE I/O ADDRESS
XOR A ; SIGNAL SUCCESS
RET
;
; SYQ_GETMED
;
SYQ_MEDIA:
LD A,E ; GET FLAGS
OR A ; SET FLAGS
JR Z,SYQ_MEDIA1 ; JUST REPORT CURRENT STATUS AND MEDIA
;
CALL SYQ_RESET ; RESET INCLUDES MEDIA CHECK
;
SYQ_MEDIA1:
LD A,(IY+SYQ_STAT) ; GET STATUS
OR A ; SET FLAGS
LD D,0 ; NO MEDIA CHANGE DETECTED
LD E,MID_HD ; ASSUME WE ARE OK
RET Z ; RETURN IF GOOD INIT
LD E,MID_NONE ; SIGNAL NO MEDIA
LD A,ERR_NOMEDIA ; NO MEDIA ERROR
OR A ; SET FLAGS
RET ; AND RETURN
;
;
;
SYQ_SEEK:
BIT 7,D ; CHECK FOR LBA FLAG
CALL Z,HB_CHS2LBA ; CLEAR MEANS CHS, CONVERT TO LBA
RES 7,D ; CLEAR FLAG REGARDLESS (DOES NO HARM IF ALREADY LBA)
LD (IY+SYQ_LBA+0),L ; SAVE NEW LBA
LD (IY+SYQ_LBA+1),H ; ...
LD (IY+SYQ_LBA+2),E ; ...
LD (IY+SYQ_LBA+3),D ; ...
XOR A ; SIGNAL SUCCESS
RET ; AND RETURN
;
;
;
SYQ_CAP:
LD A,(IY+SYQ_STAT) ; GET STATUS
PUSH AF ; SAVE IT
LD A,SYQ_MEDCAP ; OFFSET TO CAPACITY FIELD
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
CALL LD32 ; GET THE CURRENT CAPACITY INTO DE:HL
LD BC,512 ; 512 BYTES PER BLOCK
POP AF ; RECOVER STATUS
OR A ; SET FLAGS
RET
;
;
;
SYQ_GEOM:
; FOR LBA, WE SIMULATE CHS ACCESS USING 16 HEADS AND 16 SECTORS
; RETURN HS:CC -> DE:HL, SET HIGH BIT OF D TO INDICATE LBA CAPABLE
CALL SYQ_CAP ; GET TOTAL BLOCKS IN DE:HL, BLOCK SIZE TO BC
LD L,H ; DIVIDE BY 256 FOR # TRACKS
LD H,E ; ... HIGH BYTE DISCARDED, RESULT IN HL
LD D,16 | $80 ; HEADS / CYL = 16, SET LBA CAPABILITY BIT
LD E,16 ; SECTORS / TRACK = 16
RET ; DONE, A STILL HAS SYQ_CAP STATUS
;
;=============================================================================
; FUNCTION SUPPORT ROUTINES
;=============================================================================
;
;
;
SYQ_IDENTIFY:
#IF (SYQTRACE >= 3)
CALL SYQ_PRTPREFIX
PRTS(" IDDEV$")
#ENDIF
;
LD C,SYQ_CMD_IDDEV
LD DE,0
LD HL,0
CALL SYQ_CMDSETUP
;
LD HL,HB_WRKBUF
LD (SYQ_DSKBUF),HL
LD A,SYQ_XFR_READ
LD (SYQ_XFRMODE),A
;
JP SYQ_RUNCMD
;
;
;
SYQ_MEDIASTATUS:
#IF (SYQTRACE >= 3)
CALL SYQ_PRTPREFIX
PRTS(" MEDIASTATUS$")
#ENDIF
;
LD C,SYQ_CMD_MEDIASTATUS
LD DE,0
LD HL,0
CALL SYQ_CMDSETUP
;
LD HL,0
LD (SYQ_DSKBUF),HL
LD A,SYQ_XFR_NONE
LD (SYQ_XFRMODE),A
;
JP SYQ_RUNCMD
;
; DE:HL LBA
; C: COMMAND
;
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
;
;=============================================================================
; COMMAND PROCESSING
;=============================================================================
;
; 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
;
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,(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_W2(1)
SYQ_W2(3)
SYQ_W0($FF)
LD B,0 ; LOOP COUNTER
LD DE,(SYQ_DSKBUF) ; INIT BUFFER PTR
EXX ; SWITCH TO ALT REGS
EX AF,AF' ; SWITCH TO ALT AF
; SAVE ALT REGS
PUSH AF
PUSH BC
PUSH DE
PUSH HL
; C: PORT C
LD A,(IY+SYQ_IOBASE) ; BASE PORT
INC A ; STATUS PORT
LD (SYQ_GETBUF_A),A ; FILL IN
LD (SYQ_GETBUF_B),A ; ... DYNAMIC BITS OF CODE
LD (SYQ_GETBUF_C),A ;
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
; RESTORE ALT REGS
EXX ; SWITCH TO ALT REGS
EX AF,AF' ; SWITCH TO ALT AF
POP HL
POP DE
POP BC
POP AF
EXX ; SWITCH TO PRI REGS
EX AF,AF' ; SWITCH TO PRI AF
SYQ_W0(0)
SYQ_W2(4)
;
XOR A ; SIGNAL SUCCESS
RET
;
SYQ_GETBUF1:
;
; FIRST BYTE
EXX ; ALT REGS
;
; DE: CLOCK VALUES FOR FIRST BYTE
#IF (SYQMODE == SYQMODE_MG014)
LD D,$06 ^ ($0B | $80)
LD E,$04 ^ ($0B | $80)
#ENDIF
#IF (SYQMODE == SYQMODE_SPP)
LD D,$06
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)
AND $0F ; RELEVANT BITS ONLY
ADD A,MG014_STATMAPLO & $FF ; LOW BYTE OF MAP PTR
LD L,A ; PUT IN L
LD A,(HL) ; LOOKUP LOW NIBBLE VALUE
EX AF,AF' ; ALT AF, SAVE NIBBLE
#ENDIF
#IF (SYQMODE == SYQMODE_SPP)
AND $F0 ; RELEVANT BITS ONLY
RLCA ; MOVE TO LOW NIBBLE
RLCA ; MOVE TO LOW NIBBLE
RLCA ; MOVE TO LOW NIBBLE
RLCA ; MOVE TO LOW NIBBLE
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)
AND $0F ; RELEVANT BITS ONLY
ADD A,MG014_STATMAPHI & $FF ; HIGH BYTE OF MAP PTR
LD L,A ; PUT IN L
EX AF,AF' ; PRI AF, RECOVER LOW NIBBLE VALUE
OR (HL) ; COMBINE WITH HIGH NIB VALUE
#ENDIF
#IF (SYQMODE == SYQMODE_SPP)
AND $F0 ; RELEVANT BITS ONLY
OR L ; COMBINE WITH HIGH NIB VALUE
#ENDIF
EXX ; SWITCH TO PRI REGS
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
;
; DE: CLOCK VALUES FOR SECOND BYTE
#IF (SYQMODE == SYQMODE_MG014)
LD D,$07 ^ ($0B | $80)
LD E,$05 ^ ($0B | $80)
#ENDIF
#IF (SYQMODE == SYQMODE_SPP)
LD D,$07
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)
AND $0F ; RELEVANT BITS ONLY
ADD A,MG014_STATMAPLO & $FF ; LOW BYTE OF MAP PTR
LD L,A ; PUT IN L
LD A,(HL) ; LOOKUP LOW NIBBLE VALUE
EX AF,AF' ; ALT AF, SAVE NIBBLE
#ENDIF
#IF (SYQMODE == SYQMODE_SPP)
AND $F0 ; RELEVANT BITS ONLY
RLCA ; MOVE TO LOW NIBBLE
RLCA ; MOVE TO LOW NIBBLE
RLCA ; MOVE TO LOW NIBBLE
RLCA ; MOVE TO LOW NIBBLE
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)
AND $0F ; RELEVANT BITS ONLY
ADD A,MG014_STATMAPHI & $FF ; HIGH BYTE OF MAP PTR
LD L,A ; PUT IN L
EX AF,AF' ; PRI AF, RECOVER LOW NIBBLE VALUE
OR (HL) ; COMBINE WITH HIGH NIB VALUE
#ENDIF
#IF (SYQMODE == SYQMODE_SPP)
AND $F0 ; RELEVANT BITS ONLY
OR L ; COMBINE WITH HIGH NIB VALUE
#ENDIF
EXX ; SWITCH TO PRI REGS
LD (DE),A ; SAVE BYTE
INC DE ; BUMP BUF PTR
;
DJNZ SYQ_GETBUF1 ; LOOP
RET ; DONE
;
;
;
SYQ_PUTBUF:
SYQ_W0($67)
SYQ_W2(1)
SYQ_W2(5)
;
LD DE,(SYQ_DSKBUF) ; INIT BUFFER PTR
LD B,0 ; READ 256 WORDS
LD A,(IY+SYQ_IOBASE) ; GET BASE IO ADR
LD (SYQ_PUTBUF_A),A ; FILL IN
LD (SYQ_PUTBUF_B),A ; ... DYNAMIC BITS OF CODE
INC A ; STATUS PORT
INC A ; CONTROL PORT
LD C,A ; ... TO C
; HL: CLOCK VALUES
#IF (SYQMODE == SYQMODE_MG014)
LD H,$04 ^ ($0B | $80)
LD L,$05 ^ ($0B | $80)
#ENDIF
#IF (SYQMODE == SYQMODE_SPP)
LD H,$04
LD L,$05
#ENDIF
CALL SYQ_PUTBUF1 ; ONE LOOP CUZ BYTE PAIRS
SYQ_W2(7)
SYQ_W2(4)
;
XOR A
RET
;
SYQ_PUTBUF1:
LD A,(DE) ; GET NEXT BYTE
SYQ_PUTBUF_A .EQU $+1
OUT ($FF),A ; PUT ON BUS
INC DE ; INCREMENT BUF POS
OUT (C),H ; FIRST CLOCK
LD A,(DE) ; GET NEXT BYTE
SYQ_PUTBUF_B .EQU $+1
OUT ($FF),A ; PUT ON BUS
INC DE ; INCREMENT BUF POS
OUT (C),L ; SECOND CLOCK
DJNZ SYQ_PUTBUF1 ; LOOP
RET ; DONE
;
; (RE)INITIALIZE DEVICE
;
SYQ_INITDEV:
;
#IF (SYQTRACE >= 3)
PRTS("\r\nINITDEV:$")
#ENDIF
;
#IF (SYQMODE == SYQMODE_MG014)
; INITIALIZE 8255
LD A,(IY+SYQ_IOBASE) ; BASE PORT
ADD A,SYQ_IOSETUP ; BUMP TO SETUP PORT
LD C,A ; MOVE TO C FOR I/O
LD A,$82 ; CONFIG A OUT, B IN, C OUT
OUT (C),A ; DO IT
CALL DELAY ; SHORT DELAY FOR BUS SETTLE
#ENDIF
;
CALL SYQ_CONNECT ; NOW CONNECT TO BUS
CALL SYQ_DISCONNECT ; DISCONNECT FIRST JUST IN CASE
CALL SYQ_CONNECT ; NOW CONNECT TO BUS
;
; ATA SOFT RESET
LD C,SYQ_REG_CTRL
LD A,%00001010
CALL SYQ_WRITEREG
CALL DELAY
LD C,SYQ_REG_CTRL
LD A,%00001110
CALL SYQ_WRITEREG
CALL DELAY
LD C,SYQ_REG_CTRL
LD A,%00001010
CALL SYQ_WRITEREG
CALL DELAY
#IF (SYQTRACE >= 3)
; SELECT PRIMARY IDE DRIVE
LD C,SYQ_REG_DRVHD
LD A,$A0
CALL SYQ_WRITEREG
;
PRTS(" ATA REGS:$")
CALL SYQ_REGDUMP ; DUMP ATA PRIMARY REGISTERS
#ENDIF
;
CALL SYQ_DISCONNECT
;
; ISSUE DEVICE IDENTIFY COMMAND TO READ AND RECORD
; DEVICE CAPACITY.
CALL SYQ_IDENTIFY ; RUN IDENTIFY COMMAND
RET NZ ; BAIL OUT ON ERROR
;
LD DE,HB_WRKBUF ; POINT TO BUFFER
#IF (SYQTRACE >= 4)
CALL DUMP_BUFFER ; DUMP IT IF DEBUGGING
#ENDIF
;
; GET DEVICE CAPACITY AND SAVE IT
LD A,SYQ_MEDCAP ; OFFSET TO CAPACITY FIELD
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
PUSH HL ; SAVE POINTER
LD HL,HB_WRKBUF ; POINT TO BUFFER START
LD A,120 ; OFFSET OF SECTOR COUNT
CALL ADDHLA ; POINT TO ADDRESS OF SECTOR COUNT
CALL LD32 ; LOAD IT TO DE:HL
POP BC ; RECOVER POINTER TO CAPACITY ENTRY
CALL ST32 ; SAVE CAPACITY
;
; ISSUE MEDIA STATUS A FEW TIMES TO CLEAR ANY PENDING ERRORS
; (LIKE MEDIA CHANGE) AND DETERMINE IF MEDIA IS LOADED. IF
; AN ERROR IS STILL OCCURRING AFTER MULTIPLE ATTEMPTS, WE
; ASSUME MEDIA IS NOT LOADED IN DEVICE.
LD B,4 ; 4 TRIES
SYQ_INITDEV1:
PUSH BC
CALL SYQ_MEDIASTATUS
POP BC
JR Z,SYQ_INITDEV2 ; MOVE ON IF NO ERROR
DJNZ SYQ_INITDEV1 ; LOOP AS NEEDED
JP SYQ_NOMEDIA ; EXIT W/ NO MEDIA STATUS
;
SYQ_INITDEV2:
;
; RECORD STATUS OK
XOR A ; A := 0 (STATUS = OK)
LD (IY+SYQ_STAT),A ; SAVE IT
;
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:
;
#IF (SYQTRACE >= 3)
PRTS(" CONNECT:$")
#ENDIF
;
LD A,$00 ; INITIALIZE THE CHIP
CALL SYQ_CPP
;
LD A,$E0 ; CONNECT TO THE CHIP
CALL SYQ_CPP
;
SYQ_W0(0)
SYQ_W2(1)
SYQ_W2(4)
;
SYQ_WR($08,$10)
SYQ_WR($0C,$14)
SYQ_WR($0A,$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:
;
#IF (SYQTRACE >= 3)
PRTS(" DISCON:$")
#ENDIF
;
LD A,$30 ; DISCONNECT FROM THE CHIP
CALL SYQ_CPP
;
; TURNS OFF MG014 LED
SYQ_W2($8C)
;
RET
;
; WRITE VALUE IN A TO ATA REGISTER IN C
;
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
;=============================================================================
;
; ERROR HANDLERS
;
SYQ_NOMEDIA:
LD A,SYQ_STNOMEDIA
JR SYQ_ERR
;
SYQ_CMDERR:
LD A,SYQ_STCMDERR
JR SYQ_ERR
;
SYQ_IOERR:
LD A,SYQ_STIOERR
JR SYQ_ERR
;
SYQ_TO:
LD A,SYQ_STTO
JR SYQ_ERR
;
SYQ_NOTSUP:
LD A,SYQ_STNOTSUP
JR SYQ_ERR
;
SYQ_ERR:
LD (IY+SYQ_STAT),A ; SAVE NEW STATUS
;
SYQ_ERR2:
#IF (SYQTRACE >= 2)
CALL SYQ_PRTSTAT
#ENDIF
OR A ; SET FLAGS
RET
;
;
;
SYQ_PRTERR:
RET Z ; DONE IF NO ERRORS
; FALL THRU TO SYQ_PRTSTAT
;
; PRINT FULL DEVICE STATUS LINE
;
SYQ_PRTSTAT:
PUSH AF
PUSH DE
PUSH HL
LD A,(IY+SYQ_STAT)
CALL SYQ_PRTPREFIX ; PRINT UNIT PREFIX
CALL PC_SPACE ; FORMATTING
CALL SYQ_PRTSTATSTR
POP HL
POP DE
POP AF
RET
;
; PRINT STATUS STRING
;
SYQ_PRTSTATSTR:
PUSH AF
PUSH DE
PUSH HL
LD A,(IY+SYQ_STAT)
NEG
LD HL,SYQ_STR_ST_MAP
ADD A,A
CALL ADDHLA
LD E,(HL)
INC HL
LD D,(HL)
CALL WRITESTR
POP HL
POP DE
POP AF
RET
;
; PRINT ALL REGISTERS DIRECTLY FROM DEVICE
; DEVICE MUST BE CONNECTED AND SELECTED PRIOR TO CALL
;
SYQ_REGDUMP:
PUSH AF
PUSH BC
CALL PC_SPACE
CALL PC_LBKT
LD B,8
LD C,SYQ_REG_PRI
SYQ_REGDUMP1:
PUSH BC
CALL SYQ_READREG
POP BC
CALL PRTHEXBYTE
INC C
DEC B
CALL NZ,PC_SPACE
JR NZ,SYQ_REGDUMP1
CALL PC_RBKT
POP BC
POP AF
RET
;
; PRINT DEVICE/UNIT PREFIX
;
SYQ_PRTPREFIX:
PUSH AF
CALL NEWLINE
PRTS("SYQ$")
LD A,(IY+SYQ_DEV) ; GET CURRENT DEVICE NUM
CALL PRTDECB
CALL PC_COLON
POP AF
RET
;
;=============================================================================
; STRING DATA
;=============================================================================
;
SYQ_STR_ST_MAP:
.DW SYQ_STR_ST_OK
.DW SYQ_STR_ST_NOMEDIA
.DW SYQ_STR_ST_CMDERR
.DW SYQ_STR_ST_IOERR
.DW SYQ_STR_ST_TO
.DW SYQ_STR_ST_NOTSUP
;
SYQ_STR_ST_OK .TEXT "OK$"
SYQ_STR_ST_NOMEDIA .TEXT "NO MEDIA$"
SYQ_STR_ST_CMDERR .TEXT "COMMAND ERROR$"
SYQ_STR_ST_IOERR .TEXT "IO ERROR$"
SYQ_STR_ST_TO .TEXT "TIMEOUT$"
SYQ_STR_ST_NOTSUP .TEXT "NOT SUPPORTED$"
SYQ_STR_ST_UNK .TEXT "UNKNOWN ERROR$"
;
SYQ_STR_MODE_MAP:
.DW SYQ_STR_MODE_NONE
.DW SYQ_STR_MODE_SPP
.DW SYQ_STR_MODE_MG014
;
SYQ_STR_MODE_NONE .TEXT "NONE$"
SYQ_STR_MODE_SPP .TEXT "SPP$"
SYQ_STR_MODE_MG014 .TEXT "MG014$"
;
SYQ_STR_NOHW .TEXT "NOT PRESENT$"
;
;=============================================================================
; DATA STORAGE
;=============================================================================
;
SYQ_DEVNUM .DB 0 ; TEMP DEVICE NUM USED DURING INIT
SYQ_CMDSTK .DW 0 ; STACK PTR FOR CMD ABORTING
SYQ_DSKBUF .DW 0 ; WORKING DISK BUFFER POINTER
SYQ_XFRLEN .DW 0 ; WORKING TRANSFER LENGTH
SYQ_CMD .DB 0 ; CURRENT ATA COMMAND
SYQ_XFRMODE .DB 0 ; COMMAND DATA TRANSFER MODE
SYQ_CMD_STKSAV .DW 0 ; STACK FOR CMD ERROR EXIT
;
SYQ_CMDBUF:
SYQ_CMD_DATA .DB 0
SYQ_CMD_FEAT .DB 0
SYQ_CMD_COUNT .DB 0
SYQ_CMD_LBA0 .DB 0
SYQ_CMD_LBA1 .DB 0
SYQ_CMD_LBA2 .DB 0
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 * 511 ; WAIT FUNCS SCALER FOR CPU SPEED
;
; SYQ DEVICE CONFIGURATION TABLE
;
SYQ_CFG:
;
#IF (SYQCNT >= 1)
;
SYQ0_CFG: ; DEVICE 0
.DB 0 ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
.DB SYQMODE ; DRIVER DEVICE MODE
.DB 0 ; DEVICE STATUS
.DB SYQ0BASE ; IO BASE ADDRESS
.DW 0,0 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
#ENDIF
;
#IF (SYQCNT >= 2)
;
SYQ1_CFG: ; DEVICE 1
.DB 0 ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
.DB SYQMODE ; DRIVER DEVICE MODE
.DB 0 ; DEVICE STATUS
.DB SYQ1BASE ; IO BASE ADDRESS
.DW 0,0 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
#ENDIF
;
#IF ($ - SYQ_CFG) != (SYQCNT * SYQ_CFGSIZ)
.ECHO "*** INVALID SYQ CONFIG TABLE ***\n"
#ENDIF
;
.DB $FF ; END MARKER