mirror of
https://github.com/wwarthen/RomWBW.git
synced 2026-02-06 22:43:15 -06:00
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.
1467 lines
35 KiB
NASM
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
|