; ;============================================================================= ; 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"