You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1516 lines
36 KiB

;
;=============================================================================
; 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
;
;--------------------------------------------------------------------------------------------------
; HBIOS MODULE HEADER
;--------------------------------------------------------------------------------------------------
;
ORG_SYQ .EQU $
;
.DW SIZ_SYQ ; MODULE SIZE
.DW SYQ_INITPHASE ; ADR OF INIT PHASE HANDLER
;
SYQ_INITPHASE:
; INIT PHASE HANDLER, A=PHASE
;CP HB_PHASE_PREINIT ; PREINIT PHASE?
;JP Z,SYQ_PREINIT ; DO PREINIT
CP HB_PHASE_INIT ; INIT PHASE?
JP Z,SYQ_INIT ; DO INIT
RET ; DONE
;
;=============================================================================
; 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
;
DEVECHO "SYQ: MODE="
#IF (SYQMODE == SYQMODE_SPP)
DEVECHO "SPP"
#ENDIF
#IF (SYQMODE == SYQMODE_MG014)
DEVECHO "MG014"
#ENDIF
DEVECHO ", IO="
DEVECHO SYQ0BASE
DEVECHO "\n"
#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
;
DEVECHO "SYQ: MODE="
#IF (SYQMODE == SYQMODE_SPP)
DEVECHO "SPP"
#ENDIF
#IF (SYQMODE == SYQMODE_MG014)
DEVECHO "MG014"
#ENDIF
DEVECHO ", IO="
DEVECHO SYQ1BASE
DEVECHO "\n"
#ENDIF
;
#IF ($ - SYQ_CFG) != (SYQCNT * SYQ_CFGSIZ)
.ECHO "*** INVALID SYQ CONFIG TABLE ***\n"
#ENDIF
;
.DB $FF ; END MARKER
;
;--------------------------------------------------------------------------------------------------
; HBIOS MODULE TRAILER
;--------------------------------------------------------------------------------------------------
;
END_SYQ .EQU $
SIZ_SYQ .EQU END_SYQ - ORG_SYQ
;
MEMECHO "SYQ occupies "
MEMECHO SIZ_SYQ
MEMECHO " bytes.\n"