forked from MirrorRepos/RomWBW
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.
1405 lines
33 KiB
1405 lines
33 KiB
;
|
|
;=============================================================================
|
|
; PPA DISK DRIVER
|
|
;=============================================================================
|
|
;
|
|
; PARALLEL PORT INTERFACE FOR SCSI DISK DEVICES USING A PARALLEL PORT
|
|
; ADAPTER. PRIMARILY TARGETS PARALLEL PORT IOMEGA ZIP 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/23/2023 WBW - INITIAL RELEASE
|
|
; 05/26/3023 WBW - CLEAN UP, LED ACTIVITY
|
|
; 05/27/2023 WBW - ADDED SPP MODE
|
|
; 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:
|
|
;
|
|
; - THIS DRIVER IS FOR THE ZIP DRIVE PPA INTERFACE. IT WILL SIMPLY
|
|
; FAIL TO EVEN RECOGNIZE A ZIP DRIVE WITH THE NEWER IMM INTERFACE.
|
|
; THERE DOES NOT SEEM TO BE A WAY TO VISUALLY DETERMINE IF A ZIP
|
|
; DRIVE IS PPA OR IMM. SIGH.
|
|
;
|
|
; - 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.
|
|
;
|
|
; PPA PORT OFFSETS
|
|
;
|
|
PPA_IODATA .EQU 0 ; PORT A, DATA, OUT
|
|
PPA_IOSTAT .EQU 1 ; PORT B, STATUS, IN
|
|
PPA_IOCTRL .EQU 2 ; PORT C, CTRL, OUT
|
|
PPA_IOSETUP .EQU 3 ; PPI SETUP
|
|
;
|
|
; SCSI UNIT IDS
|
|
;
|
|
PPA_SELF .EQU 7
|
|
PPA_TGT .EQU 6
|
|
;
|
|
; PPA DEVICE STATUS
|
|
;
|
|
PPA_STOK .EQU 0
|
|
PPA_STNOMEDIA .EQU -1
|
|
PPA_STCMDERR .EQU -2
|
|
PPA_STIOERR .EQU -3
|
|
PPA_STTO .EQU -4
|
|
PPA_STNOTSUP .EQU -5
|
|
;
|
|
; PPA DEVICE CONFIGURATION
|
|
;
|
|
PPA_CFGSIZ .EQU 12 ; SIZE OF CFG TBL ENTRIES
|
|
;
|
|
; PER DEVICE DATA OFFSETS IN CONFIG TABLE ENTRIES
|
|
;
|
|
PPA_DEV .EQU 0 ; OFFSET OF DEVICE NUMBER (BYTE)
|
|
PPA_MODE .EQU 1 ; OPERATION MODE: PPA MODE (BYTE)
|
|
PPA_STAT .EQU 2 ; LAST STATUS (BYTE)
|
|
PPA_IOBASE .EQU 3 ; IO BASE ADDRESS (BYTE)
|
|
PPA_MEDCAP .EQU 4 ; MEDIA CAPACITY (DWORD)
|
|
PPA_LBA .EQU 8 ; OFFSET OF LBA (DWORD)
|
|
;
|
|
; MACROS
|
|
;
|
|
#DEFINE PPA_WCTL(VAL) LD A,VAL \ CALL PPA_WRITECTRL
|
|
#DEFINE PPA_WDATA(VAL) LD A,VAL \ CALL PPA_WRITEDATA
|
|
;
|
|
#DEFINE PPA_DPUL(VAL) LD A,VAL \ CALL PPA_DPULSE
|
|
#DEFINE PPA_CPUL(VAL) LD A,VAL \ CALL PPA_CPULSE
|
|
;
|
|
; INCLUDE MG014 NIBBLE MAP FOR MG014 MODE
|
|
;
|
|
#IF (IMMMODE == IMMMODE_MG014)
|
|
#DEFINE MG014_MAP
|
|
#ENDIF
|
|
;
|
|
;=============================================================================
|
|
; INITIALIZATION ENTRY POINT
|
|
;=============================================================================
|
|
;
|
|
PPA_INIT:
|
|
LD IY,PPA_CFG ; POINT TO START OF CONFIG TABLE
|
|
;
|
|
PPA_INIT1:
|
|
LD A,(IY) ; LOAD FIRST BYTE TO CHECK FOR END
|
|
CP $FF ; CHECK FOR END OF TABLE VALUE
|
|
JR NZ,PPA_INIT2 ; IF NOT END OF TABLE, CONTINUE
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET ; AND RETURN
|
|
;
|
|
PPA_INIT2:
|
|
CALL NEWLINE ; FORMATTING
|
|
PRTS("PPA:$") ; DRIVER LABEL
|
|
;
|
|
PRTS(" IO=0x$") ; LABEL FOR IO ADDRESS
|
|
LD A,(IY+PPA_IOBASE) ; GET IO BASE ADDRES
|
|
CALL PRTHEXBYTE ; DISPLAY IT
|
|
;
|
|
PRTS(" MODE=$") ; LABEL FOR MODE
|
|
LD A,(IY+PPA_MODE) ; GET MODE BITS
|
|
|
|
LD HL,PPA_STR_MODE_MAP
|
|
ADD A,A
|
|
CALL ADDHLA
|
|
LD E,(HL)
|
|
INC HL
|
|
LD D,(HL)
|
|
CALL WRITESTR
|
|
;
|
|
; CHECK FOR HARDWARE PRESENCE
|
|
CALL PPA_DETECT ; PROBE FOR INTERFACE
|
|
JR Z,PPA_INIT4 ; IF FOUND, CONTINUE
|
|
CALL PC_SPACE ; FORMATTING
|
|
LD DE,PPA_STR_NOHW ; NO PPA MESSAGE
|
|
CALL WRITESTR ; DISPLAY IT
|
|
JR PPA_INIT6 ; SKIP CFG ENTRY
|
|
;
|
|
PPA_INIT4:
|
|
; UPDATE DRIVER RELATIVE UNIT NUMBER IN CONFIG TABLE
|
|
LD A,(PPA_DEVNUM) ; GET NEXT UNIT NUM TO ASSIGN
|
|
LD (IY+PPA_DEV),A ; UPDATE IT
|
|
INC A ; BUMP TO NEXT UNIT NUM TO ASSIGN
|
|
LD (PPA_DEVNUM),A ; SAVE IT
|
|
;
|
|
; ADD UNIT TO GLOBAL DISK UNIT TABLE
|
|
LD BC,PPA_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 PPA_RESET ; RESET/INIT THE INTERFACE
|
|
#IF (PPATRACE <= 1)
|
|
CALL NZ,PPA_PRTSTAT
|
|
#ENDIF
|
|
JR NZ,PPA_INIT6
|
|
;
|
|
; START PRINTING DEVICE INFO
|
|
CALL PPA_PRTPREFIX ; PRINT DEVICE PREFIX
|
|
;
|
|
PPA_INIT5:
|
|
; PRINT STORAGE CAPACITY (BLOCK COUNT)
|
|
PRTS(" BLOCKS=0x$") ; PRINT FIELD LABEL
|
|
LD A,PPA_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
|
|
;
|
|
PPA_INIT6:
|
|
LD DE,PPA_CFGSIZ ; SIZE OF CFG TABLE ENTRY
|
|
ADD IY,DE ; BUMP POINTER
|
|
JP PPA_INIT1 ; AND LOOP
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; PROBE FOR PPA HARDWARE
|
|
;----------------------------------------------------------------------
|
|
;
|
|
; ON RETURN, ZF SET INDICATES HARDWARE FOUND
|
|
;
|
|
PPA_DETECT:
|
|
#IF (PPATRACE >= 3)
|
|
PRTS("\r\nDETECT:$")
|
|
#ENDIF
|
|
;
|
|
#IF (PPAMODE == PPAMODE_MG014)
|
|
; INITIALIZE 8255
|
|
LD A,(IY+PPA_IOBASE) ; BASE PORT
|
|
ADD A,PPA_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
|
|
;
|
|
PPA_WDATA($AA)
|
|
CALL PPA_DISCONNECT
|
|
CALL PPA_CONNECT
|
|
PPA_WCTL($0E)
|
|
CALL PPA_READSTATUS
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
AND $08
|
|
CP $08
|
|
JR NZ,PPA_DETECT_FAIL
|
|
;
|
|
PPA_WCTL($0C)
|
|
CALL PPA_READSTATUS
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
AND $08
|
|
CP $00
|
|
JR NZ,PPA_DETECT_FAIL
|
|
;
|
|
CALL PPA_DISCONNECT
|
|
;
|
|
PPA_WDATA($AA)
|
|
PPA_WCTL($0C)
|
|
;
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET ; AND RETURN
|
|
;
|
|
PPA_DETECT_FAIL:
|
|
OR $FF ; SIGNAL FAILURE
|
|
RET NZ
|
|
;
|
|
;=============================================================================
|
|
; DRIVER FUNCTION TABLE
|
|
;=============================================================================
|
|
;
|
|
PPA_FNTBL:
|
|
.DW PPA_STATUS
|
|
.DW PPA_RESET
|
|
.DW PPA_SEEK
|
|
.DW PPA_READ
|
|
.DW PPA_WRITE
|
|
.DW PPA_VERIFY
|
|
.DW PPA_FORMAT
|
|
.DW PPA_DEVICE
|
|
.DW PPA_MEDIA
|
|
.DW PPA_DEFMED
|
|
.DW PPA_CAP
|
|
.DW PPA_GEOM
|
|
#IF (($ - PPA_FNTBL) != (DIO_FNCNT * 2))
|
|
.ECHO "*** INVALID PPA FUNCTION TABLE ***\n"
|
|
#ENDIF
|
|
;
|
|
PPA_VERIFY:
|
|
PPA_FORMAT:
|
|
PPA_DEFMED:
|
|
SYSCHKERR(ERR_NOTIMPL) ; NOT IMPLEMENTED
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
PPA_READ:
|
|
CALL HB_DSKREAD ; HOOK DISK READ CONTROLLER
|
|
LD A,SCSI_CMD_READ ; SETUP SCSI READ
|
|
LD (PPA_CMD_RW),A ; AND SAVE IT IN SCSI CMD
|
|
JP PPA_IO ; DO THE I/O
|
|
;
|
|
;
|
|
;
|
|
PPA_WRITE:
|
|
CALL HB_DSKWRITE ; HOOK DISK WRITE CONTROLLER
|
|
LD A,SCSI_CMD_WRITE ; SETUP SCSI WRITE
|
|
LD (PPA_CMD_RW),A ; AND SAVE IT IN SCSI CMD
|
|
JP PPA_IO ; DO THE I/O
|
|
;
|
|
;
|
|
;
|
|
PPA_IO:
|
|
PUSH HL
|
|
CALL PPA_CHKERR ; CHECK FOR ERR STATUS AND RESET IF SO
|
|
POP HL
|
|
JR NZ,PPA_IO3 ; BAIL OUT ON ERROR
|
|
;
|
|
LD (PPA_DSKBUF),HL ; SAVE DISK BUFFER ADDRESS
|
|
;
|
|
#IF (DSKYENABLE)
|
|
#IF (DSKYDSKACT)
|
|
LD A,PPA_LBA
|
|
CALL LDHLIYA
|
|
CALL HB_DSKACT ; SHOW ACTIVITY
|
|
#ENDIF
|
|
#ENDIF
|
|
;
|
|
; SETUP LBA
|
|
; 3 BYTES, LITTLE ENDIAN -> BIG ENDIAN
|
|
LD HL,PPA_CMD_RW+1 ; START OF LBA FIELD IN CDB (MSB)
|
|
LD A,(IY+PPA_LBA+2) ; THIRD BYTE OF LBA FIELD IN CFG (MSB)
|
|
LD (HL),A
|
|
INC HL
|
|
LD A,(IY+PPA_LBA+1)
|
|
LD (HL),A
|
|
INC HL
|
|
LD A,(IY+PPA_LBA+0)
|
|
LD (HL),A
|
|
INC HL
|
|
;
|
|
; DO SCSI IO
|
|
LD DE,(PPA_DSKBUF) ; DISK BUFFER TO DE
|
|
LD A,1 ; BLOCK I/O, ONE SECTOR
|
|
LD HL,PPA_CMD_RW ; POINT TO READ/WRITE CMD TEMPLATE
|
|
CALL PPA_RUNCMD ; RUN THE SCSI ENGINE
|
|
CALL Z,PPA_CHKCMD ; IF EXIT OK, CHECK SCSI RESULTS
|
|
JR NZ,PPA_IO2 ; IF ERROR, SKIP INCREMENT
|
|
; INCREMENT LBA
|
|
LD A,PPA_LBA ; LBA OFFSET
|
|
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
|
|
CALL INC32HL ; INCREMENT THE VALUE
|
|
; INCREMENT DMA
|
|
LD HL,PPA_DSKBUF+1 ; POINT TO MSB OF BUFFER ADR
|
|
INC (HL) ; BUMP DMA BY
|
|
INC (HL) ; ... 512 BYTES
|
|
XOR A ; SIGNAL SUCCESS
|
|
;
|
|
PPA_IO2:
|
|
PPA_IO3:
|
|
LD HL,(PPA_DSKBUF) ; CURRENT DMA TO HL
|
|
OR A ; SET FLAGS BASED ON RETURN CODE
|
|
RET Z ; RETURN IF SUCCESS
|
|
LD A,ERR_IO ; SIGNAL IO ERROR
|
|
OR A ; SET FLAGS
|
|
RET ; AND DONE
|
|
;
|
|
;
|
|
;
|
|
PPA_STATUS:
|
|
; RETURN UNIT STATUS
|
|
LD A,(IY+PPA_STAT) ; GET STATUS OF SELECTED DEVICE
|
|
OR A ; SET FLAGS
|
|
RET ; AND RETURN
|
|
;
|
|
;
|
|
;
|
|
PPA_RESET:
|
|
JP PPA_INITDEV ; JUST (RE)INIT DEVICE
|
|
;
|
|
;
|
|
;
|
|
PPA_DEVICE:
|
|
LD D,DIODEV_PPA ; D := DEVICE TYPE
|
|
LD E,(IY+PPA_DEV) ; E := PHYSICAL DEVICE NUMBER
|
|
LD C,%01111001 ; C := REMOVABLE HARD DISK
|
|
LD H,(IY+PPA_MODE) ; H := MODE
|
|
LD L,(IY+PPA_IOBASE) ; L := BASE I/O ADDRESS
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
; PPA_GETMED
|
|
;
|
|
PPA_MEDIA:
|
|
LD A,E ; GET FLAGS
|
|
OR A ; SET FLAGS
|
|
JR Z,PPA_MEDIA1 ; JUST REPORT CURRENT STATUS AND MEDIA
|
|
;
|
|
CALL PPA_RESET ; RESET INCLUDES MEDIA CHECK
|
|
;
|
|
PPA_MEDIA1:
|
|
LD A,(IY+PPA_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
|
|
;
|
|
;
|
|
;
|
|
PPA_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+PPA_LBA+0),L ; SAVE NEW LBA
|
|
LD (IY+PPA_LBA+1),H ; ...
|
|
LD (IY+PPA_LBA+2),E ; ...
|
|
LD (IY+PPA_LBA+3),D ; ...
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET ; AND RETURN
|
|
;
|
|
;
|
|
;
|
|
PPA_CAP:
|
|
LD A,(IY+PPA_STAT) ; GET STATUS
|
|
PUSH AF ; SAVE IT
|
|
LD A,PPA_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
|
|
;
|
|
;
|
|
;
|
|
PPA_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 PPA_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 PPA_CAP STATUS
|
|
;
|
|
;=============================================================================
|
|
; FUNCTION SUPPORT ROUTINES
|
|
;=============================================================================
|
|
;
|
|
; OUTPUT BYTE IN A TO THE DATA PORT
|
|
;
|
|
PPA_WRITEDATA:
|
|
LD C,(IY+PPA_IOBASE) ; DATA PORT IS AT IOBASE
|
|
OUT (C),A ; WRITE THE BYTE
|
|
;CALL DELAY ; IS THIS NEEDED???
|
|
RET ; DONE
|
|
;
|
|
;
|
|
;
|
|
PPA_WRITECTRL:
|
|
; IBM PC INVERTS ALL BUT C2 ON THE BUS, MG014 DOES NOT.
|
|
; BELOW TRANSLATES FROM IBM -> MG014. IT ALSO INVERTS THE
|
|
; MG014 LED SIMPLY TO MAKE IT EASY TO KEEP LED ON DURING
|
|
; ALL ACTIVITY.
|
|
#IF (PPAMODE == PPAMODE_MG014
|
|
XOR $0B | $80 ; HIGH BIT IS MG014 LED
|
|
#ENDIF
|
|
LD C,(IY+PPA_IOBASE) ; GET BASE IO ADDRESS
|
|
INC C ; BUMP TO CONTROL PORT
|
|
INC C
|
|
OUT (C),A ; WRITE TO CONTROL PORT
|
|
;CALL DELAY ; IS THIS NEEDED?
|
|
RET ; DONE
|
|
;
|
|
; READ THE PARALLEL PORT INPUT LINES (STATUS) AND MAP SIGNALS FROM
|
|
; MG014 TO IBM STANDARD. NOTE POLARITY CHANGE REQUIRED FOR BUSY.
|
|
;
|
|
; MG014 IBM PC
|
|
; -------- --------
|
|
; 0: /ACK 6: /ACK
|
|
; 1: BUSY 7: /BUSY
|
|
; 2: POUT 5: POUT
|
|
; 3: SEL 4: SEL
|
|
; 4: /ERR 3: /ERR
|
|
;
|
|
PPA_READSTATUS:
|
|
LD C,(IY+PPA_IOBASE) ; IOBASE TO C
|
|
INC C ; BUMP TO STATUS PORT
|
|
IN A,(C) ; READ IT
|
|
;
|
|
#IF (PPAMODE == PPAMODE_MG014
|
|
;
|
|
; SHUFFLE BITS ON MG014
|
|
LD C,0 ; INIT RESULT
|
|
BIT 0,A ; 0: /ACK
|
|
JR Z,PPA_READSTATUS1
|
|
SET 6,C ; 6: /ACK
|
|
PPA_READSTATUS1:
|
|
BIT 1,A ; 1: BUSY
|
|
JR NZ,PPA_READSTATUS2 ; POLARITY CHANGE!
|
|
SET 7,C ; 7: /BUSY
|
|
PPA_READSTATUS2:
|
|
BIT 2,A ; 2: POUT
|
|
JR Z,PPA_READSTATUS3
|
|
SET 5,C ; 5: POUT
|
|
PPA_READSTATUS3:
|
|
BIT 3,A ; 3: SEL
|
|
JR Z,PPA_READSTATUS4
|
|
SET 4,C ; 4: SEL
|
|
PPA_READSTATUS4:
|
|
BIT 4,A ; 4: /ERR
|
|
JR Z,PPA_READSTATUS5
|
|
SET 3,C ; 3: /ERR
|
|
PPA_READSTATUS5:
|
|
LD A,C ; RESULT TO A
|
|
;
|
|
#ENDIF
|
|
;
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
PPA_DPULSE:
|
|
CALL PPA_WRITEDATA
|
|
PPA_WCTL($0C)
|
|
PPA_WCTL($0E)
|
|
PPA_WCTL($0C)
|
|
PPA_WCTL($04)
|
|
PPA_WCTL($0C)
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
PPA_CPULSE:
|
|
CALL PPA_WRITEDATA
|
|
PPA_WCTL($04)
|
|
PPA_WCTL($06)
|
|
PPA_WCTL($04)
|
|
PPA_WCTL($0C)
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
PPA_CONNECT:
|
|
PPA_CPUL($00)
|
|
PPA_CPUL($3C)
|
|
PPA_CPUL($20)
|
|
PPA_CPUL($8F)
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
PPA_DISCONNECT:
|
|
PPA_DPUL($00)
|
|
PPA_DPUL($3C)
|
|
PPA_DPUL($20)
|
|
PPA_DPUL($0F)
|
|
;
|
|
; TURNS OFF MG014 LED
|
|
PPA_WCTL($8C)
|
|
;
|
|
RET
|
|
;
|
|
; INITIATE A SCSI BUS RESET.
|
|
;
|
|
PPA_RESETPULSE:
|
|
PPA_WDATA($40)
|
|
PPA_WCTL($08)
|
|
CALL DELAY ; 32 US, IDEALLY 30 US
|
|
PPA_WCTL($0C)
|
|
RET
|
|
;
|
|
; SCSI SELECT PROCESS
|
|
;
|
|
PPA_SELECT:
|
|
#IF (PPATRACE >= 3)
|
|
PRTS("\r\nSELECT: $")
|
|
#ENDIF
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
CALL PPA_READSTATUS
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
LD A,1 << PPA_TGT
|
|
CALL PPA_WRITEDATA
|
|
PPA_WCTL($0E)
|
|
PPA_WCTL($0C)
|
|
LD A,1 << PPA_SELF
|
|
CALL PPA_WRITEDATA
|
|
PPA_WCTL($08)
|
|
;
|
|
LD B,0 ; TIMEOUT COUNTER
|
|
PPA_SELECT1:
|
|
CALL PPA_READSTATUS
|
|
#IF (PPATRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
AND $40
|
|
CP $40
|
|
RET Z
|
|
DJNZ PPA_SELECT1
|
|
JP PPA_CMD_TIMEOUT
|
|
;
|
|
; SEND SCSI CMD BYTE STRING. AT ENTRY, HL POINTS TO START OF
|
|
; COMMAND BYTES. THE LENGTH OF THE COMMAND STRING MUST PRECEED
|
|
; THE COMMAND BYTES (HL - 1).
|
|
;
|
|
; NOTE THAT DATA IS SENT AS BYTE PAIRS! EACH LOOP SENDS 2 BYTES.
|
|
; DATA OUTPOUT IS BURSTED (NO CHECK FOR BUSY). SEEMS TO WORK FINE.
|
|
;
|
|
PPA_SENDCMD:
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
PRTS("\r\nSENDCMD:$")
|
|
#ENDIF
|
|
;
|
|
DEC HL ; BACKUP TO LENGTH BYTE
|
|
LD B,(HL) ; PUT IN B FOR LOOP COUNTER
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
LD A,B
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
PRTS(" BYTES$")
|
|
#ENDIF
|
|
;
|
|
INC HL ; BACK TO FIRST CMD BYTE
|
|
;
|
|
PPA_SENDCMD1:
|
|
;PPA_WCTL($0C)
|
|
LD A,(HL) ; LOAD CMD BYTE
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
CALL PPA_WRITEDATA ; PUT IT ON THE BUS
|
|
INC HL ; BUMP TO NEXT BYTE
|
|
PPA_WCTL($0E)
|
|
PPA_WCTL($0C)
|
|
DJNZ PPA_SENDCMD1 ; LOOP TILL DONE
|
|
;
|
|
RET
|
|
;
|
|
;
|
|
; WAIT FOR SCSI BUS TO BECOME READY WITH A TIMEOUT.
|
|
;
|
|
PPA_WAITLOOP:
|
|
CALL PPA_READSTATUS
|
|
BIT 7,A
|
|
RET NZ ; DONE, STATUS IN A
|
|
DEC HL
|
|
LD A,H
|
|
OR L
|
|
RET Z ; TIMEOUT
|
|
JR PPA_WAITLOOP
|
|
;
|
|
PPA_WAIT:
|
|
LD HL,500 ; GOOD VALUE???
|
|
PPA_WCTL($0C)
|
|
CALL PPA_WAITLOOP
|
|
JP Z,PPA_CMD_TIMEOUT ; HANDLE TIMEOUT
|
|
;PUSH AF
|
|
;IMM_WCTL($04)
|
|
;POP AF
|
|
AND $F0
|
|
RET ; RETURN W/ RESULT IN A
|
|
;
|
|
; MAX OBSERVED WAITLOOP ITERATIONS IS $0116B3 @ 7.372 MHZ ON MG014
|
|
; MAX OBSERVED WAITLOOP ITERATIONS IS $028EFE @ 8.000 MHZ ON MBC SPP
|
|
;
|
|
PPA_LONGWAIT:
|
|
LD A,(CB_CPUMHZ) ; LOAD CPU SPEED IN MHZ
|
|
SRL A ; DIVIDE BY 2, GOOD ENOUGH
|
|
LD B,A ; USE FOR OUTER LOOP COUNT
|
|
PPA_WCTL($0C)
|
|
PPA_LONGWAIT1:
|
|
LD HL,0
|
|
CALL PPA_WAITLOOP
|
|
JR NZ,PPA_LONGWAIT2 ; HANDLE SUCCESS
|
|
DJNZ PPA_LONGWAIT1 ; LOOP TILL COUNTER EXHAUSTED
|
|
JP PPA_CMD_TIMEOUT ; HANDLE TIMEOUT
|
|
;
|
|
PPA_LONGWAIT2:
|
|
;PUSH AF
|
|
;PPA_WCTL($04)
|
|
;
|
|
#IF 0
|
|
PUSH AF
|
|
CALL PC_GT
|
|
LD A,B
|
|
CALL PRTHEXBYTE
|
|
CALL PC_COLON
|
|
CALL PRTHEXWORDHL
|
|
POP AF
|
|
#ENDIF
|
|
;
|
|
;POP AF
|
|
AND $F0
|
|
RET ; RETURN W/ RESULT IN A
|
|
;
|
|
; GET A BYTE OF DATA FROM THE SCSI DEVICE. THIS IS A NIBBLE READ.
|
|
; BYTE RETURNED IN A.
|
|
;
|
|
PPA_GETBYTE:
|
|
CALL PPA_WAIT
|
|
PPA_WCTL($04)
|
|
CALL PPA_READSTATUS
|
|
AND $F0
|
|
PUSH AF
|
|
PPA_WCTL($06)
|
|
CALL PPA_READSTATUS
|
|
AND $F0
|
|
RRCA
|
|
RRCA
|
|
RRCA
|
|
RRCA
|
|
POP HL
|
|
OR H
|
|
PUSH AF
|
|
PPA_WCTL($0C)
|
|
POP AF
|
|
RET
|
|
;
|
|
; GET A CHUNK OF DATA FROM SCSI BUS. THIS IS SPECIFICALLY FOR
|
|
; READ PHASE. IF TRANSFER MODE IS NON-ZERO, THEN A BLOCK (512 BYTES)
|
|
; OF DATA WILL BE READ. OTHERWISE, DATA IS WRITTEN AS
|
|
; LONG AS SCSI DEVICE WANTS TO CONTINUE RECEIVING (NO OVERRUN
|
|
; CHECK IN THIS CASE).
|
|
;
|
|
; THIS IS A NIBBLE READ.
|
|
;
|
|
; DE=BUFFER
|
|
; A=TRANSFER MODE (0=VARIABLE, 1=BLOCK)
|
|
;
|
|
PPA_GETDATA:
|
|
; BRANCH TO CORRECT ROUTINE
|
|
OR A
|
|
JR NZ,PPA_GETBLOCK ; DO BLOCK READ
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
PRTS("\r\nGETDATA:$")
|
|
#ENDIF
|
|
;
|
|
PPA_GETDATA1:
|
|
PUSH HL ; SAVE BYTE COUNTER
|
|
CALL PPA_WAIT ; WAIT FOR BUS READY
|
|
POP HL ; RESTORE BYTE COUNTER
|
|
CP $D0 ; CHECK FOR READ PHASE
|
|
JR NZ,PPA_GETDATA2 ; IF NOT, ASSUME WE ARE DONE
|
|
PPA_WCTL($04)
|
|
CALL PPA_READSTATUS ; GET FIRST NIBBLE
|
|
AND $F0 ; ISOLATE BITS
|
|
PUSH AF ; SAVE WORKING VALUE
|
|
PPA_WCTL($06)
|
|
CALL PPA_READSTATUS ; GET SECOND NIBBLE
|
|
AND $F0 ; ISOLATE BITS
|
|
RRCA ; AND SHIFT TO LOW NIBBLE
|
|
RRCA
|
|
RRCA
|
|
RRCA
|
|
POP BC ; RECOVER LOW NIBBLE
|
|
OR B ; COMBINE
|
|
LD (DE),A ; AND SAVE THE FULL BYTE VALUE
|
|
INC DE ; NEXT BUFFER POS
|
|
INC HL ; INCREMENT BYTES COUNTER
|
|
JR PPA_GETDATA1 ; LOOP TILL DONE
|
|
;
|
|
PPA_GETDATA2:
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXWORDHL
|
|
PRTS(" BYTES$")
|
|
#ENDIF
|
|
;
|
|
PPA_WCTL($0C)
|
|
RET
|
|
;
|
|
PPA_GETBLOCK:
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
PRTS("\r\nGETBLK:$")
|
|
#ENDIF
|
|
LD B,0 ; LOOP COUNTER
|
|
EXX ; SWITCH TO ALT
|
|
EX AF,AF' ; SWITCH TO ALT AF
|
|
; SAVE ALT REGS
|
|
PUSH AF
|
|
PUSH BC
|
|
PUSH DE
|
|
PUSH HL
|
|
; C: PORT C
|
|
LD A,(IY+PPA_IOBASE) ; BASE PORT
|
|
INC A ; STATUS PORT
|
|
LD (PPA_GETBLOCK_A),A ; FILL IN
|
|
LD (PPA_GETBLOCK_B),A ; ... DYNAMIC BITS OF CODE
|
|
INC A ; CONTROL PORT
|
|
LD C,A ; ... TO C
|
|
#IF (PPAMODE == PPAMODE_MG014)
|
|
; DE: CLOCK VALUES
|
|
LD D,$04 ^ ($0B | $80)
|
|
LD E,$06 ^ ($0B | $80)
|
|
; HL: STATMAP
|
|
LD H,MG014_STATMAPLO >> 8
|
|
#ENDIF
|
|
#IF (PPAMODE == PPAMODE_SPP)
|
|
; DE: CLOCK VALUES
|
|
LD D,$04
|
|
LD E,$06
|
|
#ENDIF
|
|
EXX ; SWITCH TO PRI
|
|
CALL PPA_GETBLOCK1 ; LOOP TWICE
|
|
CALL PPA_GETBLOCK1 ; ... FOR 512 BYTES
|
|
; 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
|
|
RET
|
|
;
|
|
;
|
|
PPA_GETBLOCK1:
|
|
EXX ; ALT REGS
|
|
OUT (C),D ; SEND FIRST CLOCK
|
|
PPA_GETBLOCK_A .EQU $+1
|
|
IN A,($FF) ; GET HIGH NIBBLE
|
|
#IF (PPAMODE == PPAMODE_MG014)
|
|
AND $0F ; RELEVANT BITS ONLY
|
|
ADD A,MG014_STATMAPHI & $FF ; HIGH BYTE OF MAP PTR
|
|
LD L,A ; PUT IN L
|
|
LD A,(HL) ; LOOKUP HIGH NIBBLE VALUE
|
|
EX AF,AF' ; SAVE NIBBLE
|
|
#ENDIF
|
|
#IF (PPAMODE == PPAMODE_SPP)
|
|
AND $F0 ; RELEVANT BITS ONLY
|
|
LD L,A ; SAVE NIBBLE IN L
|
|
#ENDIF
|
|
OUT (C),E ; SEND SECOND CLOCK
|
|
PPA_GETBLOCK_B .EQU $+1
|
|
IN A,($FF) ; GET LOW NIBBLE
|
|
#IF (PPAMODE == PPAMODE_MG014)
|
|
AND $0F ; RELEVANT BITS ONLY
|
|
ADD A,MG014_STATMAPLO & $FF ; LOW BYTE OF MAP PTR
|
|
LD L,A ; PUT IN L
|
|
EX AF,AF' ; RECOVER HIGH NIBBLE VALUE
|
|
OR (HL) ; COMBINE WITH LOW NIB VALUE
|
|
#ENDIF
|
|
#IF (PPAMODE == PPAMODE_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
|
|
OR L ; COMBINE WITH HIGH NIB VALUE
|
|
#ENDIF
|
|
EXX ; SWITCH TO PRI
|
|
LD (DE),A ; SAVE BYTE
|
|
INC DE ; BUMP BUF PTR
|
|
DJNZ PPA_GETBLOCK1 ; LOOP
|
|
RET ; DONE
|
|
;
|
|
; PUT A CHUNK OF DATA TO THE SCSI BUS. THIS IS SPECIFICALLY FOR
|
|
; WRITE PHASE. IF TRANSFER MODE IS NON-ZERO, THEN A BLOCK (512 BYTES)
|
|
; OF DATA WILL BE WRITTEN. OTHERWISE, DATA IS WRITTEN AS
|
|
; LONG AS SCSI DEVICE WANTS TO CONTINUE RECEIVING (NO OVERRUN
|
|
; CHECK IN THIS CASE).
|
|
;
|
|
; DE=BUFFER
|
|
; A=TRANSFER MODE (0=VARIABLE, 1=BLOCK)
|
|
;
|
|
PPA_PUTDATA:
|
|
; BRANCH TO CORRECT ROUTINE
|
|
OR A
|
|
JR NZ,PPA_PUTBLOCK ; DO BLOCK WRITE
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
PRTS("\r\nPUTDATA:$")
|
|
#ENDIF
|
|
;
|
|
PPA_PUTDATA1:
|
|
PUSH HL ; SAVE BYTE COUNTER
|
|
CALL PPA_WAIT ; WAIT FOR BUS READY
|
|
POP HL ; RESTORE BYTE COUNTER
|
|
CP $C0 ; CHECK FOR WRITE PHASE
|
|
JR NZ,PPA_PUTDATA2 ; IF NOT, ASSUME WE ARE DONE
|
|
LD A,(DE) ; GET NEXT BYTE TO WRITE (FIRST OF PAIR)
|
|
CALL PPA_WRITEDATA ; PUT ON BUS
|
|
INC DE ; BUMP TO NEXT BUF POS
|
|
INC HL ; INCREMENT COUNTER
|
|
PPA_WCTL($0E)
|
|
PPA_WCTL($0C)
|
|
LD A,(DE) ; GET NEXT BYTE TO WRITE (SECOND OF PAIR)
|
|
JR PPA_PUTDATA1 ; LOOP TILL DONE
|
|
;
|
|
PPA_PUTDATA2:
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXWORDHL
|
|
PRTS(" BYTES$")
|
|
#ENDIF
|
|
;
|
|
RET
|
|
;
|
|
PPA_PUTBLOCK:
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
PRTS("\r\nPUTBLK:$")
|
|
#ENDIF
|
|
;
|
|
LD B,0 ; LOOP COUNTER
|
|
LD A,(IY+PPA_IOBASE) ; GET BASE IO ADR
|
|
LD (PPA_PUTBLOCK_A),A ; FILL IN
|
|
INC A ; STATUS PORT
|
|
INC A ; CONTROL PORT
|
|
LD C,A ; ... TO C
|
|
; HL: CLOCK VALUES
|
|
#IF (PPAMODE == PPAMODE_MG014)
|
|
LD H,$0E ^ ($0B | $80)
|
|
LD L,$0C ^ ($0B | $80)
|
|
#ENDIF
|
|
#IF (PPAMODE == PPAMODE_SPP)
|
|
LD H,$0E
|
|
LD L,$0C
|
|
#ENDIF
|
|
CALL PPA_PUTBLOCK1 ; DO BELOW TWICE
|
|
CALL PPA_PUTBLOCK1 ; ... FOR 512 BYTES
|
|
RET
|
|
;
|
|
PPA_PUTBLOCK1:
|
|
LD A,(DE) ; GET NEXT BYTE
|
|
PPA_PUTBLOCK_A .EQU $+1
|
|
OUT ($FF),A ; PUT ON BUS
|
|
INC DE ; INCREMENT BUF POS
|
|
OUT (C),H ; FIRST CLOCK
|
|
OUT (C),L ; SECOND CLOCK
|
|
DJNZ PPA_PUTBLOCK1 ; LOOP
|
|
RET ; DONE
|
|
;
|
|
; READ SCSI COMMAND STATUS
|
|
;
|
|
PPA_GETSTATUS:
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
PRTS("\r\nSTATUS:$")
|
|
#ENDIF
|
|
;
|
|
CALL PPA_GETBYTE ; GET ONE BYTE
|
|
LD (PPA_CMDSTAT),A ; SAVE AS FIRST STATUS BYTE
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
CALL PPA_WAIT ; CHECK FOR OPTIONAL SECOND BYTE
|
|
CP $F0 ; STILL IN STATUS PHASE?
|
|
RET NZ ; IF NOT, DONE
|
|
CALL PPA_GETBYTE ; ELSE, GET THE SECOND BYTE
|
|
LD (PPA_CMDSTAT+1),A ; AND SAVE IT
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
RET
|
|
;
|
|
; THIS IS THE MAIN SCSI ENGINE. BASICALLY, IT SELECTS THE DEVICE
|
|
; ON THE BUS, SENDS THE COMMAND, THEN PROCESSES THE RESULT.
|
|
;
|
|
; HL: COMMAND BUFFER
|
|
; DE: TRANSFER BUFFER
|
|
; A: TRANSFER MODE (0=VARIABLE, 1=BLOCK)
|
|
;
|
|
PPA_RUNCMD:
|
|
; THERE ARE MANY PLACES NESTED WITHIN THE ROUTINES THAT
|
|
; ARE CALLED HERE. HERE WE SAVE THE STACK SO THAT WE CAN
|
|
; EASILY AND QUICKLY ABORT OUT OF ANY NESTED ROUTINE.
|
|
; SEE PPA_CMD_ERR BELOW.
|
|
LD (PPA_CMDSTK),SP ; FOR ERROR ABORTS
|
|
LD (PPA_DSKBUF),DE ; SAVE BUF PTR
|
|
LD (PPA_XFRMODE),A ; SAVE XFER LEN
|
|
PUSH HL
|
|
CALL PPA_CONNECT ; PARALLEL PORT BUS CONNECT
|
|
CALL PPA_SELECT ; SELECT TARGET DEVICE
|
|
CALL PPA_WAIT ; WAIT TILL READY
|
|
POP HL
|
|
CALL PPA_SENDCMD ; SEND THE COMMAND
|
|
;
|
|
PPA_RUNCMD_PHASE:
|
|
; WAIT FOR THE BUS TO BE READY. WE USE AN EXTRA LONG WAIT
|
|
; TIMEOUT HERE BECAUSE THIS IS WHERE WE WILL WAIT FOR LONG
|
|
; OPERATIONS TO COMPLETE. IT CAN TAKE SOME TIME IF THE
|
|
; DEVICE HAS GONE TO SLEEP BECAUSE IT WILL NEED TO WAKE UP
|
|
; AND SPIN UP BEFORE PROCESSING AN I/O COMMAND.
|
|
CALL PPA_LONGWAIT ; WAIT TILL READY
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
PRTS("\r\nPHASE: $")
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
CP $C0 ; DEVICE WANTS TO RCV DATA
|
|
JR Z,PPA_RUNCMD_WRITE
|
|
CP $D0 ; DEVICE WANTS TO SEND DATA
|
|
JR Z,PPA_RUNCMD_READ
|
|
CP $F0 ; DEVICE WANTS TO BE DONE
|
|
JR Z,PPA_RUNCMD_END
|
|
JR PPA_CMD_IOERR
|
|
;
|
|
PPA_RUNCMD_WRITE:
|
|
LD DE,(PPA_DSKBUF) ; XFER BUFFER
|
|
LD A,(PPA_XFRMODE) ; XFER MODE
|
|
CALL PPA_PUTDATA ; SEND DATA NOW
|
|
JR PPA_RUNCMD_PHASE ; BACK TO DISPATCH
|
|
;
|
|
PPA_RUNCMD_READ:
|
|
LD DE,(PPA_DSKBUF) ; XFER BUFFER
|
|
LD A,(PPA_XFRMODE) ; XFER MODE
|
|
CALL PPA_GETDATA ; GET THE DATA NOW
|
|
JR PPA_RUNCMD_PHASE ; BACK TO DISPATCH
|
|
;
|
|
PPA_RUNCMD_END:
|
|
CALL PPA_GETSTATUS ; READ STATUS BYTES
|
|
CALL PPA_DISCONNECT ; PARALLEL PORT BUS DISCONNECT
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
PPA_CMD_IOERR:
|
|
LD A,PPA_STIOERR ; ERROR VALUE TO A
|
|
JR PPA_CMD_ERR ; CONTINUE
|
|
;
|
|
PPA_CMD_TIMEOUT:
|
|
LD A,PPA_STTO ; ERROR VALUE TO A
|
|
JR PPA_CMD_ERR ; CONTINUE
|
|
;
|
|
PPA_CMD_ERR:
|
|
LD SP,(PPA_CMDSTK) ; UNWIND STACK
|
|
PUSH AF ; SAVE STATUS
|
|
;CALL PPA_RESETPULSE ; CLEAN UP THE MESS???
|
|
LD DE,62 ; DELAY AFTER RESET PULSE
|
|
CALL VDELAY
|
|
CALL PPA_DISCONNECT ; PARALLEL PORT BUS DISCONNECT
|
|
LD DE,62 ; DELAY AFTER DISCONNECT
|
|
CALL VDELAY
|
|
POP AF ; RECOVER STATUS
|
|
JP PPA_ERR ; NOW DO STANDARD ERR PROCESSING
|
|
;
|
|
; ERRORS SHOULD GENERALLY NOT CAUSE SCSI PROCESSING TO FAIL. IF A
|
|
; DEVICE ERROR (I.E., READ ERROR) OCCURS, THEN THE SCSI PROTOCOL WILL
|
|
; PROVIDE ERROR INFORMATION. THE STATUS RESULT OF THE SCSI COMMAND
|
|
; WILL INDICATE IF AN ERROR OCCURRED. ADDITIONALLY, IF THE ERROR IS
|
|
; A CHECK CONDITION ERROR, THEN IT IS MANDATORY TO ISSUE A SENSE
|
|
; REQUEST SCSI COMMAND TO CLEAR THE ERROR AND RETRIEVE DETAILED ERROR
|
|
; INFO.
|
|
;
|
|
PPA_CHKCMD:
|
|
; SCSI COMMAND COMPLETED, CHECK SCSI CMD STATUS
|
|
LD A,(PPA_CMDSTAT) ; GET STATUS BYTE
|
|
OR A ; SET FLAGS
|
|
RET Z ; IF ZERO, ALL GOOD, DONE
|
|
;
|
|
; DO WE HAVE A CHECK CONDITION?
|
|
CP 2 ; CHECK CONDITION RESULT?
|
|
JR Z,PPA_CHKCMD1 ; IF SO, REQUEST SENSE
|
|
JP PPA_IOERR ; ELSE, GENERAL I/O ERROR
|
|
;
|
|
PPA_CHKCMD1:
|
|
; USE REQUEST SENSE CMD TO GET ERROR DETAILS
|
|
LD DE,HB_WRKBUF ; PUT DATA IN WORK BUF
|
|
LD A,0 ; VARIABLE LENGTH READ
|
|
LD HL,PPA_CMD_SENSE ; REQUEST SENSE CMD
|
|
CALL PPA_RUNCMD ; DO IT
|
|
JP NZ,PPA_IOERR ; BAIL IF ERROR IN CMD
|
|
;
|
|
; REQ SENSE CMD COMPLETED
|
|
#IF (PPATRACE >= 3)
|
|
PRTS("\r\nSENSE:$")
|
|
LD A,$19
|
|
LD DE,HB_WRKBUF
|
|
CALL Z,PRTHEXBUF
|
|
#ENDIF
|
|
;
|
|
; CHECK SCSI CMD STATUS
|
|
LD A,(PPA_CMDSTAT) ; GET STATUS BYTE
|
|
OR A ; SET FLAGS
|
|
JP NZ,PPA_IOERR ; IF FAILED, GENERAL I/O ERROR
|
|
;
|
|
; RETURN RESULT BASED ON REQ SENSE DATA
|
|
; TODO: WE NEED TO CHECK THE SENSE KEY FIRST!!!
|
|
LD A,(HB_WRKBUF+12) ; GET ADDITIONAL SENSE CODE
|
|
CP $3A ; NO MEDIA?
|
|
JP Z,PPA_NOMEDIA ; IF SO, RETURN NO MEDIA ERR
|
|
JP PPA_IOERR ; ELSE GENERAL I/O ERR
|
|
;
|
|
; CHECK CURRENT DEVICE FOR ERROR STATUS AND ATTEMPT TO RECOVER
|
|
; VIA RESET IF DEVICE IS IN ERROR.
|
|
;
|
|
PPA_CHKERR:
|
|
LD A,(IY+PPA_STAT) ; GET STATUS
|
|
OR A ; SET FLAGS
|
|
CALL NZ,PPA_RESET ; IF ERROR STATUS, RESET BUS
|
|
RET
|
|
;
|
|
; (RE)INITIALIZE DEVICE
|
|
;
|
|
PPA_INITDEV:
|
|
;
|
|
#IF (PPAMODE == PPAMODE_MG014)
|
|
; INITIALIZE 8255
|
|
LD A,(IY+PPA_IOBASE) ; BASE PORT
|
|
ADD A,PPA_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
|
|
;
|
|
; BUS RESET
|
|
CALL PPA_CONNECT
|
|
CALL PPA_RESETPULSE
|
|
LD DE,62 ; 1000 US
|
|
CALL VDELAY
|
|
CALL PPA_DISCONNECT
|
|
LD DE,62 ; 1000 US
|
|
CALL VDELAY
|
|
;
|
|
; INITIALLY, THE DEVICE MAY REQUIRE MULTIPLE REQUEST SENSE
|
|
; COMMANDS BEFORE IT WILL ACCEPT I/O COMMANDS. THIS IS DUE
|
|
; TO THINGS LIKE BUS RESET NOTIFICATION, MEDIA CHANGE, ETC.
|
|
; HERE, WE RUN A FEW REQUEST SENSE COMMANDS. AS SOON AS ONE
|
|
; INDICATES NO ERRORS, WE CAN CONTINUE.
|
|
LD B,4 ; TRY UP TO 4 TIMES
|
|
PPA_INITDEV1:
|
|
PUSH BC ; SAVE LOOP COUNTER
|
|
;
|
|
; REQUEST SENSE COMMAND
|
|
LD DE,HB_WRKBUF ; BUFFER FOR SENSE DATA
|
|
LD A,0 ; READ WHATEVER IS SENT
|
|
LD HL,PPA_CMD_SENSE ; POINT TO CMD BUFFER
|
|
CALL PPA_RUNCMD ; RUN THE SCSI ENGINE
|
|
JR NZ,PPA_INITDEV2 ; CMD PROC ERROR
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
PRTS("\r\nSENSE:$")
|
|
LD A,$19
|
|
LD DE,HB_WRKBUF
|
|
CALL PRTHEXBUF
|
|
#ENDIF
|
|
;
|
|
; CHECK SENSE KEY
|
|
LD A,(HB_WRKBUF + 2) ; GET SENSE KEY
|
|
OR A ; SET FLAGS
|
|
;
|
|
PPA_INITDEV2:
|
|
POP BC ; RESTORE LOOP COUNTER
|
|
JR Z,PPA_INITDEV3 ; IF NO ERROR, MOVE ON
|
|
DJNZ PPA_INITDEV1 ; TRY UNTIL COUNTER EXHAUSTED
|
|
JP PPA_IOERR ; BAIL OUT WITH ERROR
|
|
;
|
|
PPA_INITDEV3:
|
|
; READ & RECORD DEVICE CAPACITY
|
|
LD DE,HB_WRKBUF ; BUFFER TO CAPACITY RESPONSE
|
|
LD A,0 ; READ WHATEVER IS SENT
|
|
LD HL,PPA_CMD_RDCAP ; POINT TO READ CAPACITY CMD
|
|
CALL PPA_RUNCMD ; RUN THE SCSI ENGINE
|
|
CALL Z,PPA_CHKCMD ; CHECK AND RECORD ANY ERRORS
|
|
RET NZ ; BAIL OUT ON ERROR
|
|
;
|
|
#IF (PPATRACE >= 3)
|
|
PRTS("\r\nRDCAP:$")
|
|
LD A,8
|
|
LD DE,HB_WRKBUF
|
|
CALL PRTHEXBUF
|
|
#ENDIF
|
|
;
|
|
; CAPACITY IS RETURNED IN A 4 BYTE, BIG ENDIAN FIELD AND
|
|
; INDICATES THE LAST LBA VALUE. WE NEED TO CONVERT THIS TO
|
|
; LITTLE ENDIAN AND INCREMENT THE VALUE TO MAKE IT A CAPACITY
|
|
; COUNT INSTEAD OF A LAST LBA VALUE.
|
|
LD A,PPA_MEDCAP ; OFFSET IN CFG FOR CAPACITY
|
|
CALL LDHLIYA ; POINTER TO HL
|
|
PUSH HL ; SAVE IT
|
|
LD HL,HB_WRKBUF ; POINT TO VALUE IN CMD RESULT
|
|
CALL LD32 ; LOAD IT TO DE:HL
|
|
LD A,L ; FLIP BYTES
|
|
LD L,D ; ... BIG ENDIAN
|
|
LD D,A ; ... TO LITTLE ENDIAN
|
|
LD A,H
|
|
LD H,E
|
|
LD E,A
|
|
CALL INC32 ; INCREMENT TO FINAL VALUE
|
|
POP BC ; RECOVER SAVE LOCATION
|
|
CALL ST32 ; STORE VALUE
|
|
;
|
|
XOR A ; SIGNAL SUCCESS
|
|
LD (IY+PPA_STAT),A ; RECORD IT
|
|
RET
|
|
;
|
|
;=============================================================================
|
|
; ERROR HANDLING AND DIAGNOSTICS
|
|
;=============================================================================
|
|
;
|
|
; ERROR HANDLERS
|
|
;
|
|
;
|
|
PPA_NOMEDIA:
|
|
LD A,PPA_STNOMEDIA
|
|
JR PPA_ERR
|
|
;
|
|
PPA_CMDERR:
|
|
LD A,PPA_STCMDERR
|
|
JR PPA_ERR
|
|
;
|
|
PPA_IOERR:
|
|
LD A,PPA_STIOERR
|
|
JR PPA_ERR
|
|
;
|
|
PPA_TO:
|
|
LD A,PPA_STTO
|
|
JR PPA_ERR
|
|
;
|
|
PPA_NOTSUP:
|
|
LD A,PPA_STNOTSUP
|
|
JR PPA_ERR
|
|
;
|
|
PPA_ERR:
|
|
LD (IY+PPA_STAT),A ; SAVE NEW STATUS
|
|
;
|
|
PPA_ERR2:
|
|
#IF (PPATRACE >= 2)
|
|
CALL PPA_PRTSTAT
|
|
#ENDIF
|
|
OR A ; SET FLAGS
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
PPA_PRTERR:
|
|
RET Z ; DONE IF NO ERRORS
|
|
; FALL THRU TO PPA_PRTSTAT
|
|
;
|
|
; PRINT FULL DEVICE STATUS LINE
|
|
;
|
|
PPA_PRTSTAT:
|
|
PUSH AF
|
|
PUSH DE
|
|
PUSH HL
|
|
LD A,(IY+PPA_STAT)
|
|
CALL PPA_PRTPREFIX ; PRINT UNIT PREFIX
|
|
CALL PC_SPACE ; FORMATTING
|
|
CALL PPA_PRTSTATSTR
|
|
POP HL
|
|
POP DE
|
|
POP AF
|
|
RET
|
|
;
|
|
; PRINT STATUS STRING
|
|
;
|
|
PPA_PRTSTATSTR:
|
|
PUSH AF
|
|
PUSH DE
|
|
PUSH HL
|
|
LD A,(IY+PPA_STAT)
|
|
NEG
|
|
LD HL,PPA_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 DIAGNONSTIC PREFIX
|
|
;
|
|
PPA_PRTPREFIX:
|
|
PUSH AF
|
|
CALL NEWLINE
|
|
PRTS("PPA$")
|
|
LD A,(IY+PPA_DEV) ; GET CURRENT DEVICE NUM
|
|
CALL PRTDECB
|
|
CALL PC_COLON
|
|
POP AF
|
|
RET
|
|
;
|
|
;=============================================================================
|
|
; STRING DATA
|
|
;=============================================================================
|
|
;
|
|
PPA_STR_ST_MAP:
|
|
.DW PPA_STR_STOK
|
|
.DW PPA_STR_STNOMEDIA
|
|
.DW PPA_STR_STCMDERR
|
|
.DW PPA_STR_STIOERR
|
|
.DW PPA_STR_STTO
|
|
.DW PPA_STR_STNOTSUP
|
|
;
|
|
PPA_STR_STOK .TEXT "OK$"
|
|
PPA_STR_STNOMEDIA .TEXT "NO MEDIA$"
|
|
PPA_STR_STCMDERR .TEXT "COMMAND ERROR$"
|
|
PPA_STR_STIOERR .TEXT "IO ERROR$"
|
|
PPA_STR_STTO .TEXT "TIMEOUT$"
|
|
PPA_STR_STNOTSUP .TEXT "NOT SUPPORTED$"
|
|
PPA_STR_STUNK .TEXT "UNKNOWN ERROR$"
|
|
;
|
|
PPA_STR_MODE_MAP:
|
|
.DW PPA_STR_MODE_NONE
|
|
.DW PPA_STR_MODE_SPP
|
|
.DW PPA_STR_MODE_MG014
|
|
;
|
|
PPA_STR_MODE_NONE .DB "NONE$"
|
|
PPA_STR_MODE_SPP .DB "SPP$"
|
|
PPA_STR_MODE_MG014 .DB "MG014$"
|
|
;
|
|
PPA_STR_NOHW .TEXT "NOT PRESENT$"
|
|
;
|
|
;=============================================================================
|
|
; DATA STORAGE
|
|
;=============================================================================
|
|
;
|
|
PPA_DEVNUM .DB 0 ; TEMP DEVICE NUM USED DURING INIT
|
|
PPA_CMDSTK .DW 0 ; STACK PTR FOR CMD ABORTING
|
|
PPA_DSKBUF .DW 0 ; WORKING DISK BUFFER POINTER
|
|
PPA_XFRMODE .DB 0 ; 0=VARIABLE, 1=BLOCK (512 BYTES)
|
|
PPA_CMDSTAT .DB 0, 0 ; CMD RESULT STATUS
|
|
;
|
|
; SCSI COMMAND TEMPLATES (LENGTH PREFIXED)
|
|
;
|
|
.DB 6
|
|
PPA_CMD_RW .DB $00, $00, $00, $00, $01, $00 ; READ/WRITE SECTOR
|
|
.DB 6
|
|
PPA_CMD_SENSE .DB $03, $00, $00, $00, $FF, $00 ; REQUEST SENSE DATA
|
|
.DB 10
|
|
PPA_CMD_RDCAP .DB $25, $00, $00, $00, $00, $00, $00, $00, $00, $00 ; READ CAPACITY
|
|
;
|
|
; PPA DEVICE CONFIGURATION TABLE
|
|
;
|
|
PPA_CFG:
|
|
;
|
|
#IF (PPACNT >= 1)
|
|
;
|
|
PPA0_CFG: ; DEVICE 0
|
|
.DB 0 ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
|
|
.DB PPAMODE ; DRIVER DEVICE MODE
|
|
.DB 0 ; DEVICE STATUS
|
|
.DB PPA0BASE ; IO BASE ADDRESS
|
|
.DW 0,0 ; DEVICE CAPACITY
|
|
.DW 0,0 ; CURRENT LBA
|
|
#ENDIF
|
|
;
|
|
#IF (PPACNT >= 2)
|
|
;
|
|
PPA1_CFG: ; DEVICE 1
|
|
.DB 0 ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
|
|
.DB PPAMODE ; DRIVER DEVICE MODE
|
|
.DB 0 ; DEVICE STATUS
|
|
.DB PPA1BASE ; IO BASE ADDRESS
|
|
.DW 0,0 ; DEVICE CAPACITY
|
|
.DW 0,0 ; CURRENT LBA
|
|
#ENDIF
|
|
;
|
|
#IF ($ - PPA_CFG) != (PPACNT * PPA_CFGSIZ)
|
|
.ECHO "*** INVALID PPA CONFIG TABLE ***\n"
|
|
#ENDIF
|
|
;
|
|
.DB $FF ; END MARKER
|
|
|