mirror of
https://github.com/wwarthen/RomWBW.git
synced 2026-02-06 14:11:48 -06:00
IMM Driver has rational timeouts now. It also lights the MG014 LED during activity. The PPA skeleton just attempts to determine if the PPA interface is present. It does not attempt any I/O.
1553 lines
36 KiB
NASM
1553 lines
36 KiB
NASM
;
|
|
;=============================================================================
|
|
; IMM DISK DRIVER
|
|
;=============================================================================
|
|
;
|
|
; PARALLEL PORT INTERFACE FOR SCSI DISK DEVICES USING A PARALLEL PORT
|
|
; ADAPTER. PRIMARILY TARGETS PARALLEL PORT IOMEGA ZIP DRIVES.
|
|
;
|
|
; CURRENTLY CODED SPECIFICALLY FOR RCBUS MG014 PARALLEL PORT HARDWARE.
|
|
; INTENDED TO CO-EXIST WITH LPT DRIVER.
|
|
;
|
|
; CREATED BY WAYNE WARTHEN FOR ROMWBW HBIOS.
|
|
; MUCH OF THE CODE IS DERIVED FROM FUZIX (ALAN COX).
|
|
;
|
|
; 5/23/2023 WBW - INITIAL RELEASE
|
|
; 5/26/3023 WBW - CLEAN UP, LED ACTIVITY
|
|
;
|
|
;=============================================================================
|
|
;
|
|
; MG014 STYLE INTERFACE (USED BY RCBUS MG014 MODULE):
|
|
;
|
|
; PORT 0 (INPUT/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 (INPUT/OUTPUT):
|
|
;
|
|
; D7 D6 D5 D4 D3 D2 D1 D0
|
|
; +-------+-------+-------+-------+-------+-------+-------+-------+
|
|
; | LED | | | | /SEL | /RES | /LF | /STB |
|
|
; +-------+-------+-------+-------+-------+-------+-------+-------+
|
|
;
|
|
;=============================================================================
|
|
;
|
|
; TODO:
|
|
;
|
|
; - CLEAN UP WAIT LOOP STUFF
|
|
;
|
|
; - OPTIMIZE READ/WRITE LOOPS
|
|
;
|
|
; NOTES:
|
|
;
|
|
; - THIS DRIVER IS FOR THE ZIP DRIVE IMM INTERFACE. IT WILL SIMPLY
|
|
; FAIL TO EVEN RECOGNIZE A ZIP DRIVE WITH THE OLDER PPA INTERFACE.
|
|
; THERE DOES NOT SEEM TO BE A WAY TO VISUALLY DETERMINE IF A ZIP
|
|
; DRIVE IS IMM OR PPA. SIGH.
|
|
;
|
|
; - THERE ARE SOME HARD CODED TIMEOUT LOOPS IN THE CODE. THEY ARE
|
|
; WORKING OK ON A 7 MHZ Z80. THEY ARE LIKELY TO NEED TWEAKING ON
|
|
; FASTER CPUS.
|
|
;
|
|
; - THIS DRIVER OPERATES PURELY IN NIBBLE MODE. I SUSPECT IT IS
|
|
; POSSIBLE TO USE 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.
|
|
;
|
|
; IMM PORT OFFSETS
|
|
;
|
|
IMM_IODATA .EQU 0 ; PORT A, DATA, OUT
|
|
IMM_IOSTAT .EQU 1 ; PORT B, STATUS, IN
|
|
IMM_IOCTRL .EQU 2 ; PORT C, CTRL, OUT
|
|
IMM_IOSETUP .EQU 3 ; PPI SETUP
|
|
;
|
|
; SCSI UNIT IDS
|
|
;
|
|
IMM_SELF .EQU 7
|
|
IMM_TGT .EQU 6
|
|
;
|
|
; IMM DEVICE STATUS
|
|
;
|
|
IMM_STOK .EQU 0
|
|
IMM_STINVUNIT .EQU -1
|
|
IMM_STNOMEDIA .EQU -2
|
|
IMM_STCMDERR .EQU -3
|
|
IMM_STIOERR .EQU -4
|
|
IMM_STTO .EQU -5
|
|
IMM_STNOTSUP .EQU -6
|
|
;
|
|
; IMM DEVICE CONFIGURATION
|
|
;
|
|
IMM_CFGSIZ .EQU 12 ; SIZE OF CFG TBL ENTRIES
|
|
;
|
|
; PER DEVICE DATA OFFSETS IN CONFIG TABLE ENTRIES
|
|
;
|
|
IMM_DEV .EQU 0 ; OFFSET OF DEVICE NUMBER (BYTE)
|
|
IMM_MODE .EQU 1 ; OPERATION MODE: IMM MODE (BYTE)
|
|
IMM_STAT .EQU 2 ; LAST STATUS (BYTE)
|
|
IMM_IOBASE .EQU 3 ; IO BASE ADDRESS (BYTE)
|
|
IMM_MEDCAP .EQU 4 ; MEDIA CAPACITY (DWORD)
|
|
IMM_LBA .EQU 8 ; OFFSET OF LBA (DWORD)
|
|
;
|
|
;=============================================================================
|
|
; INITIALIZATION ENTRY POINT
|
|
;=============================================================================
|
|
;
|
|
IMM_INIT:
|
|
LD IY,IMM_CFG ; POINT TO START OF CONFIG TABLE
|
|
;
|
|
IMM_INIT1:
|
|
LD A,(IY) ; LOAD FIRST BYTE TO CHECK FOR END
|
|
CP $FF ; CHECK FOR END OF TABLE VALUE
|
|
JR NZ,IMM_INIT2 ; IF NOT END OF TABLE, CONTINUE
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET ; AND RETURN
|
|
;
|
|
IMM_INIT2:
|
|
CALL NEWLINE ; FORMATTING
|
|
PRTS("IMM:$") ; DRIVER LABEL
|
|
;
|
|
PRTS(" IO=0x$") ; LABEL FOR IO ADDRESS
|
|
LD A,(IY+IMM_IOBASE) ; GET IO BASE ADDRES
|
|
CALL PRTHEXBYTE ; DISPLAY IT
|
|
;
|
|
PRTS(" MODE=$") ; LABEL FOR MODE
|
|
LD A,(IY+IMM_MODE) ; GET MODE BITS
|
|
LD DE,IMM_STR_MODE_NONE ; MODE LABEL
|
|
CP IMMMODE_NONE ; TEST FOR MODE
|
|
JR Z,IMM_INIT3 ; IF SO, DISPLAY IT
|
|
LD DE,IMM_STR_MODE_MG014 ; MODE LABEL
|
|
CP IMMMODE_MG014 ; TEST FOR MODE
|
|
JR Z,IMM_INIT3 ; IF SO, DISPLAY IT
|
|
LD DE,IMM_STR_MODE_UNK ; MODE LABEL
|
|
IMM_INIT3:
|
|
CALL WRITESTR ; DISPLAY MODE
|
|
;
|
|
; CHECK FOR HARDWARE PRESENCE
|
|
CALL IMM_DETECT ; PROBE FOR INTERFACE
|
|
JR Z,IMM_INIT4 ; IF FOUND, CONTINUE
|
|
CALL PC_SPACE ; FORMATTING
|
|
LD DE,IMM_STR_NOHW ; NO IMM MESSAGE
|
|
CALL WRITESTR ; DISPLAY IT
|
|
JR IMM_INIT6 ; SKIP CFG ENTRY
|
|
;
|
|
IMM_INIT4:
|
|
; UPDATE DRIVER RELATIVE UNIT NUMBER IN CONFIG TABLE
|
|
LD A,(IMM_DEVNUM) ; GET NEXT UNIT NUM TO ASSIGN
|
|
LD (IY+IMM_DEV),A ; UPDATE IT
|
|
INC A ; BUMP TO NEXT UNIT NUM TO ASSIGN
|
|
LD (IMM_DEVNUM),A ; SAVE IT
|
|
;
|
|
; ADD UNIT TO GLOBAL DISK UNIT TABLE
|
|
LD BC,IMM_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 IMM_RESET ; RESET/INIT THE INTERFACE
|
|
;
|
|
; START PRINTING DEVICE INFO
|
|
CALL IMM_PRTPREFIX ; PRINT DEVICE PREFIX
|
|
;
|
|
; CHECK FOR BAD STATUS
|
|
LD A,(IY+IMM_STAT) ; GET STATUS
|
|
OR A ; SET FLAGS
|
|
JP Z,IMM_INIT5 ; CONTINUE
|
|
CALL PC_SPACE ; FORMATTING
|
|
CALL IMM_PRTSTATSTR ; PRINT STATUS STRING
|
|
JR IMM_INIT6 ; LOOP TILL DONE
|
|
;
|
|
IMM_INIT5:
|
|
; PRINT STORAGE CAPACITY (BLOCK COUNT)
|
|
PRTS(" BLOCKS=0x$") ; PRINT FIELD LABEL
|
|
LD A,IMM_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
|
|
;
|
|
IMM_INIT6:
|
|
LD DE,IMM_CFGSIZ ; SIZE OF CFG TABLE ENTRY
|
|
ADD IY,DE ; BUMP POINTER
|
|
JP IMM_INIT1 ; AND LOOP
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; PROBE FOR IMM HARDWARE
|
|
;----------------------------------------------------------------------
|
|
;
|
|
; ON RETURN, ZF SET INDICATES HARDWARE FOUND
|
|
;
|
|
IMM_DETECT:
|
|
; INITIALIZE 8255
|
|
LD A,(IY+IMM_IOBASE) ; BASE PORT
|
|
ADD A,IMM_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
|
|
;
|
|
; WE USE THIS SEQUENCE TO DETECT AN ACTUAL IMM DEVICE ON THE
|
|
; PARALLEL PORT. THE VALUES RECORDED IN THE FINAL CALL TO
|
|
; IMM_DISCONNECT ARE USED TO CONFIRM DEVICE PRESENCE.
|
|
; NO ACTUAL SCSI COMMANDS ARE USED.
|
|
CALL IMM_DISCONNECT
|
|
CALL IMM_CONNECT
|
|
CALL IMM_DISCONNECT
|
|
;
|
|
; THE IMM_SN VALUES ARE RECORDED IN THE CPP ROUTINE USED BY
|
|
; IMM_CONNECT/DISCONNECT.
|
|
; EXPECTING S1=$B8, S2=$18, S3=$38
|
|
LD A,(IMM_S1)
|
|
CP $B8
|
|
RET NZ
|
|
LD A,(IMM_S2)
|
|
CP $18
|
|
RET NZ
|
|
LD A,(IMM_S3)
|
|
CP $38
|
|
RET NZ
|
|
;
|
|
XOR A
|
|
RET
|
|
;
|
|
;=============================================================================
|
|
; DRIVER FUNCTION TABLE
|
|
;=============================================================================
|
|
;
|
|
IMM_FNTBL:
|
|
.DW IMM_STATUS
|
|
.DW IMM_RESET
|
|
.DW IMM_SEEK
|
|
.DW IMM_READ
|
|
.DW IMM_WRITE
|
|
.DW IMM_VERIFY
|
|
.DW IMM_FORMAT
|
|
.DW IMM_DEVICE
|
|
.DW IMM_MEDIA
|
|
.DW IMM_DEFMED
|
|
.DW IMM_CAP
|
|
.DW IMM_GEOM
|
|
#IF (($ - IMM_FNTBL) != (DIO_FNCNT * 2))
|
|
.ECHO "*** INVALID IMM FUNCTION TABLE ***\n"
|
|
#ENDIF
|
|
;
|
|
IMM_VERIFY:
|
|
IMM_FORMAT:
|
|
IMM_DEFMED:
|
|
SYSCHKERR(ERR_NOTIMPL) ; NOT IMPLEMENTED
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IMM_READ:
|
|
CALL HB_DSKREAD ; HOOK DISK READ CONTROLLER
|
|
LD A,SCSI_CMD_READ ; SETUP SCSI READ
|
|
LD (IMM_CMD_RW),A ; AND SAVE IT IN SCSI CMD
|
|
JP IMM_IO ; DO THE I/O
|
|
;
|
|
;
|
|
;
|
|
IMM_WRITE:
|
|
CALL HB_DSKREAD ; HOOK DISK WRITE CONTROLLER
|
|
LD A,SCSI_CMD_WRITE ; SETUP SCSI WRITE
|
|
LD (IMM_CMD_RW),A ; AND SAVE IT IN SCSI CMD
|
|
JP IMM_IO ; DO THE I/O
|
|
;
|
|
;
|
|
;
|
|
IMM_IO:
|
|
LD (IMM_DSKBUF),HL ; SAVE DISK BUFFER ADDRESS
|
|
CALL IMM_CHKERR ; CHECK FOR ERR STATUS AND RESET IF SO
|
|
JR NZ,IMM_IO3 ; BAIL OUT ON ERROR
|
|
;
|
|
; SETUP LBA
|
|
; 3 BYTES, LITTLE ENDIAN -> BIG ENDIAN
|
|
LD HL,IMM_CMD_RW+1 ; START OF LBA FIELD IN CDB (MSB)
|
|
LD A,(IY+IMM_LBA+2) ; THIRD BYTE OF LBA FIELD IN CFG (MSB)
|
|
LD (HL),A
|
|
INC HL
|
|
LD A,(IY+IMM_LBA+1)
|
|
LD (HL),A
|
|
INC HL
|
|
LD A,(IY+IMM_LBA+0)
|
|
LD (HL),A
|
|
INC HL
|
|
;
|
|
; DO SCSI IO
|
|
LD DE,(IMM_DSKBUF) ; DISK BUFFER TO DE
|
|
LD BC,512 ; ONE SECTOR, 512 BYTES
|
|
LD HL,IMM_CMD_RW ; POINT TO READ/WRITE CMD TEMPLATE
|
|
CALL IMM_RUNCMD ; RUN THE SCSI ENGINE
|
|
CALL Z,IMM_CHKCMD ; IF EXIT OK, CHECK SCSI RESULTS
|
|
JR NZ,IMM_IO2 ; IF ERROR, SKIP INCREMENT
|
|
; INCREMENT LBA
|
|
LD A,IMM_LBA ; LBA OFFSET
|
|
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
|
|
CALL INC32HL ; INCREMENT THE VALUE
|
|
; INCREMENT DMA
|
|
LD HL,IDE_DSKBUF+1 ; POINT TO MSB OF BUFFER ADR
|
|
INC (HL) ; BUMP DMA BY
|
|
INC (HL) ; ... 512 BYTES
|
|
XOR A ; SIGNAL SUCCESS
|
|
;
|
|
IMM_IO2:
|
|
IMM_IO3:
|
|
LD HL,(IMM_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
|
|
;
|
|
;
|
|
;
|
|
IMM_STATUS:
|
|
; RETURN UNIT STATUS
|
|
LD A,(IY+IMM_STAT) ; GET STATUS OF SELECTED DEVICE
|
|
OR A ; SET FLAGS
|
|
RET ; AND RETURN
|
|
;
|
|
;
|
|
;
|
|
IMM_RESET:
|
|
JP IMM_INITDEV ; JUST (RE)INIT DEVICE
|
|
;
|
|
;
|
|
;
|
|
IMM_DEVICE:
|
|
LD D,DIODEV_IMM ; D := DEVICE TYPE
|
|
LD E,(IY+IMM_DEV) ; E := PHYSICAL DEVICE NUMBER
|
|
LD C,%01000000 ; C := REMOVABLE HARD DISK
|
|
LD H,(IY+IMM_MODE) ; H := MODE
|
|
LD L,(IY+IMM_IOBASE) ; L := BASE I/O ADDRESS
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
; IMM_GETMED
|
|
;
|
|
IMM_MEDIA:
|
|
LD A,E ; GET FLAGS
|
|
OR A ; SET FLAGS
|
|
JR Z,IMM_MEDIA1 ; JUST REPORT CURRENT STATUS AND MEDIA
|
|
;
|
|
CALL IMM_RESET ; RESET INCLUDES MEDIA CHECK
|
|
;
|
|
IMM_MEDIA1:
|
|
LD A,(IY+IMM_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
|
|
;
|
|
;
|
|
;
|
|
IMM_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+IMM_LBA+0),L ; SAVE NEW LBA
|
|
LD (IY+IMM_LBA+1),H ; ...
|
|
LD (IY+IMM_LBA+2),E ; ...
|
|
LD (IY+IMM_LBA+3),D ; ...
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET ; AND RETURN
|
|
;
|
|
;
|
|
;
|
|
IMM_CAP:
|
|
LD A,(IY+IMM_STAT) ; GET STATUS
|
|
PUSH AF ; SAVE IT
|
|
LD A,IMM_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
|
|
;
|
|
;
|
|
;
|
|
IMM_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 IMM_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 IMM_CAP STATUS
|
|
;
|
|
;=============================================================================
|
|
; FUNCTION SUPPORT ROUTINES
|
|
;=============================================================================
|
|
;
|
|
; OUTPUT BYTE IN A TO THE DATA PORT
|
|
;
|
|
IMM_WRITEDATA:
|
|
LD C,(IY+IMM_IOBASE) ; DATA PORT IS AT IOBASE
|
|
OUT (C),A ; WRITE THE BYTE
|
|
;CALL DELAY ; IS THIS NEEDED???
|
|
RET ; DONE
|
|
;
|
|
;
|
|
;
|
|
IMM_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.
|
|
XOR $0B | $80 ; HIGH BIT IS MG014 LED
|
|
LD C,(IY+IMM_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
|
|
;
|
|
IMM_READSTATUS:
|
|
LD C,(IY+IMM_IOBASE) ; IOBASE TO C
|
|
INC C ; BUMP TO STATUS PORT
|
|
IN A,(C) ; READ IT
|
|
LD C,0 ; INIT RESULT
|
|
;
|
|
; SHUFFLE BITS
|
|
BIT 0,A ; 0: /ACK
|
|
JR Z,IMM_READSTATUS1
|
|
SET 6,C ; 6: /ACK
|
|
;
|
|
IMM_READSTATUS1:
|
|
;
|
|
BIT 1,A ; 1: BUSY
|
|
JR NZ,IMM_READSTATUS2 ; POLARITY CHANGE!
|
|
SET 7,C ; 7: /BUSY
|
|
;
|
|
IMM_READSTATUS2:
|
|
;
|
|
BIT 2,A ; 2: POUT
|
|
JR Z,IMM_READSTATUS3
|
|
SET 5,C ; 5: POUT
|
|
;
|
|
IMM_READSTATUS3:
|
|
;
|
|
BIT 3,A ; 3: SEL
|
|
JR Z,IMM_READSTATUS4
|
|
SET 4,C ; 4: SEL
|
|
;
|
|
IMM_READSTATUS4:
|
|
;
|
|
BIT 4,A ; 4: /ERR
|
|
JR Z,IMM_READSTATUS5
|
|
SET 3,C ; 3: /ERR
|
|
;
|
|
IMM_READSTATUS5:
|
|
LD A,C ; RESULT TO A
|
|
RET
|
|
;
|
|
; SIGNAL SEQUENCE TO CONNECT/DISCONNECT
|
|
; VALUE IN A IS WRITTEN TO DATA PORT DURING SEQUENCE
|
|
;
|
|
IMM_CPP:
|
|
PUSH AF
|
|
LD A,$0C
|
|
CALL IMM_WRITECTRL
|
|
LD A,$AA
|
|
CALL IMM_WRITEDATA
|
|
LD A,$55
|
|
CALL IMM_WRITEDATA
|
|
LD A,$00
|
|
CALL IMM_WRITEDATA
|
|
LD A,$FF
|
|
CALL IMM_WRITEDATA
|
|
CALL IMM_READSTATUS
|
|
AND $B8
|
|
LD (IMM_S1),A
|
|
LD A,$87
|
|
CALL IMM_WRITEDATA
|
|
CALL IMM_READSTATUS
|
|
AND $B8
|
|
LD (IMM_S2),A
|
|
LD A,$78
|
|
CALL IMM_WRITEDATA
|
|
CALL IMM_READSTATUS
|
|
AND $38
|
|
LD (IMM_S3),A
|
|
POP AF
|
|
CALL IMM_WRITEDATA
|
|
LD A,$0C
|
|
CALL IMM_WRITECTRL
|
|
LD A,$0D
|
|
CALL IMM_WRITECTRL
|
|
LD A,$0C
|
|
CALL IMM_WRITECTRL
|
|
LD A,$FF
|
|
CALL IMM_WRITEDATA
|
|
;
|
|
; CONNECT: S1=$B8 S2=$18 S3=$30
|
|
; DISCONNECT: S1=$B8 S2=$18 S3=$38
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
PRTS("\r\nCPP: S1=$")
|
|
LD A,(IMM_S1)
|
|
CALL PRTHEXBYTE
|
|
PRTS(" S2=$")
|
|
LD A,(IMM_S2)
|
|
CALL PRTHEXBYTE
|
|
PRTS(" S3=$")
|
|
LD A,(IMM_S3)
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
XOR A ; ASSUME SUCCESS FOR NOW
|
|
RET
|
|
;
|
|
IMM_S1 .DB 0
|
|
IMM_S2 .DB 0
|
|
IMM_S3 .DB 0
|
|
;
|
|
; SEQUENCE TO CONNECT TO DEVICE ON PARALLEL PORT BUS.
|
|
;
|
|
IMM_CONNECT:
|
|
LD A,$E0
|
|
CALL IMM_CPP
|
|
LD A,$30
|
|
CALL IMM_CPP
|
|
LD A,$E0
|
|
CALL IMM_CPP
|
|
RET
|
|
;
|
|
; SEQUENCE TO DISCONNECT FROM DEVICE ON PARALLEL PORT BUS.
|
|
; THE FINAL IMM_WRITECTRL IS ONLY TO TURN OFF THE MG014 STATUS LED.
|
|
;
|
|
IMM_DISCONNECT:
|
|
LD A,$30
|
|
CALL IMM_CPP
|
|
;
|
|
; TURNS OFF MG014 LED
|
|
LD A,$8C
|
|
CALL IMM_WRITECTRL
|
|
;
|
|
RET
|
|
;
|
|
; INITIATE A SCSI BUS RESET.
|
|
;
|
|
IMM_RESETPULSE:
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
LD A,$40
|
|
CALL IMM_WRITEDATA
|
|
CALL DELAY ; 16 US, IDEALLY, 1 US
|
|
LD A,$0C
|
|
CALL IMM_WRITECTRL
|
|
LD A,$0D
|
|
CALL IMM_WRITECTRL
|
|
CALL DELAY ; 48 US, IDEALLY, 50 US
|
|
CALL DELAY
|
|
CALL DELAY
|
|
LD A,$0C
|
|
CALL IMM_WRITECTRL
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
RET
|
|
;
|
|
; SCSI SELECT PROCESS
|
|
;
|
|
IMM_SELECT:
|
|
#IF (IMMTRACE >= 3)
|
|
PRTS("\r\nSELECT: $")
|
|
#ENDIF
|
|
LD A,$0C
|
|
CALL IMM_WRITECTRL
|
|
;
|
|
LD HL,500 ; TIMEOUT COUNTER
|
|
;
|
|
IMM_SELECT1:
|
|
CALL IMM_READSTATUS
|
|
AND $08
|
|
JR Z,IMM_SELECT2 ; IF CLEAR, MOVE ON
|
|
DEC HL
|
|
LD A,H
|
|
OR L
|
|
JP Z,IMM_CMD_TIMEOUT ; TIMEOUT
|
|
JR IMM_SELECT1
|
|
;
|
|
IMM_SELECT2:
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
; PLACE HOST AND TARGET BIT ON DATA BUS
|
|
LD A,$80 | (1 << IMM_TGT)
|
|
CALL IMM_WRITEDATA
|
|
CALL DELAY ; CONFIRM DELAY TIME?
|
|
LD A,$0C
|
|
CALL IMM_WRITECTRL
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
CALL IMM_READSTATUS
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
LD A,$0D
|
|
CALL IMM_WRITECTRL
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
CALL IMM_READSTATUS
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
LD HL,500 ; TIMEOUT COUNTER
|
|
;
|
|
IMM_SELECT3:
|
|
CALL IMM_READSTATUS
|
|
#IF (IMMTRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
AND $08
|
|
JR NZ,IMM_SELECT4 ; IF SET, MOVE ON
|
|
DEC HL
|
|
LD A,H
|
|
OR L
|
|
JP Z,IMM_CMD_TIMEOUT ; TIMEOUT
|
|
JR IMM_SELECT3
|
|
;
|
|
IMM_SELECT4:
|
|
LD A,$0C
|
|
CALL IMM_WRITECTRL
|
|
;
|
|
XOR A
|
|
RET
|
|
;
|
|
; 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.
|
|
;
|
|
IMM_SENDCMD:
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
PRTS("\r\nSENDCMD:$")
|
|
#ENDIF
|
|
;
|
|
DEC HL ; BACKUP TO LENGTH BYTE
|
|
LD B,(HL) ; PUT IN B FOR LOOP COUNTER
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
LD A,B
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
PRTS(" BYTES$")
|
|
#ENDIF
|
|
;
|
|
INC HL ; BACK TO FIRST CMD BYTE
|
|
IMM_SENDCMD1:
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
LD A,(HL) ; LOAD CMD BYTE
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
CALL IMM_WRITEDATA ; PUT IT ON THE BUS
|
|
INC HL ; BUMP TO NEXT BYTE
|
|
DEC B ; DEC LOOP COUNTER
|
|
LD A,$05
|
|
CALL IMM_WRITECTRL
|
|
LD A,(HL) ; LOAD CMD BYTE
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
CALL IMM_WRITEDATA ; PUT IT ON THE BUS
|
|
INC HL ; BUMP TO NEXT BYTE
|
|
LD A,$00
|
|
CALL IMM_WRITECTRL
|
|
DJNZ IMM_SENDCMD1 ; LOOP TILL DONE
|
|
;
|
|
IMM_SENDCMD2:
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
;
|
|
RET
|
|
;
|
|
; WAIT FOR SCSI BUS TO BECOME READY WITH A TIMEOUT.
|
|
;
|
|
IMM_WAITLOOP:
|
|
CALL IMM_READSTATUS
|
|
BIT 7,A
|
|
RET NZ ; DONE, STATUS IN A
|
|
DEC HL
|
|
LD A,H
|
|
OR L
|
|
RET Z ; TIMEOUT
|
|
JR IMM_WAITLOOP
|
|
;
|
|
IMM_WAIT:
|
|
LD HL,500 ; GOOD VALUE???
|
|
LD A,$0C
|
|
CALL IMM_WRITECTRL
|
|
CALL IMM_WAITLOOP
|
|
JP Z,IMM_CMD_TIMEOUT ; HANDLE TIMEOUT
|
|
PUSH AF
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
POP AF
|
|
AND $B8
|
|
RET ; RETURN W/ RESULT IN A
|
|
;
|
|
; MAX OBSERVED IMM_WAITLOOP ITERATIONS IS $0116B3
|
|
;
|
|
IMM_LONGWAIT:
|
|
LD B,3 ; VALUE???
|
|
LD A,$0C
|
|
CALL IMM_WRITECTRL
|
|
IMM_LONGWAIT1:
|
|
LD HL,0
|
|
CALL IMM_WAITLOOP
|
|
JR NZ,IMM_LONGWAIT2 ; HANDLE SUCCESS
|
|
DJNZ IMM_LONGWAIT1 ; LOOP TILL COUNTER EXHAUSTED
|
|
JP IMM_CMD_TIMEOUT ; HANDLE TIMEOUT
|
|
;
|
|
IMM_LONGWAIT2:
|
|
PUSH AF
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
;
|
|
#IF 0
|
|
CALL PC_GT
|
|
LD A,B
|
|
CALL PRTHEXBYTE
|
|
CALL PC_COLON
|
|
CALL PRTHEXWORDHL
|
|
#ENDIF
|
|
;
|
|
POP AF
|
|
AND $B8
|
|
RET ; RETURN W/ RESULT IN A
|
|
;
|
|
; PEROFRM SCSI BUS NEGOTIATION. REQURIED PRIOR TO DATA READS.
|
|
;
|
|
IMM_NEGOTIATE:
|
|
#IF (IMMTRACE >= 3)
|
|
PRTS("\r\nNEGO: $")
|
|
#ENDIF
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
CALL DELAY ; 16 US, IDEALLY 5 US
|
|
LD A,$00
|
|
CALL IMM_WRITEDATA
|
|
LD DE,7 ; 112 US, IDEALLY 100 US
|
|
CALL VDELAY
|
|
LD A,$06
|
|
CALL IMM_WRITECTRL
|
|
CALL DELAY ; 16 US, IDEALLY 5 US
|
|
CALL IMM_READSTATUS
|
|
PUSH AF ; SAVE RESULT
|
|
CALL DELAY ; 16 US, IDEALLY 5 US
|
|
LD A,$07
|
|
CALL IMM_WRITECTRL
|
|
CALL DELAY ; 16 US, IDEALLY 5 US
|
|
LD A,$06
|
|
CALL IMM_WRITECTRL
|
|
;
|
|
POP AF
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
AND $20
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PC_GT
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
CP $20 ; $20 MEANS DATA READY
|
|
JP NZ,IMM_CMD_IOERR
|
|
RET
|
|
;
|
|
; GET A BYTE OF DATA FROM THE SCSI DEVICE. THIS IS A NIBBLE READ.
|
|
; BYTE RETURNED IN A.
|
|
;
|
|
IMM_GETBYTE:
|
|
CALL IMM_WAIT
|
|
LD A,$06
|
|
CALL IMM_WRITECTRL
|
|
CALL IMM_READSTATUS
|
|
AND $F0
|
|
RRCA
|
|
RRCA
|
|
RRCA
|
|
RRCA
|
|
PUSH AF
|
|
LD A,$05
|
|
CALL IMM_WRITECTRL
|
|
CALL IMM_READSTATUS
|
|
AND $F0
|
|
POP HL
|
|
OR H
|
|
PUSH AF
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
POP AF
|
|
RET
|
|
;
|
|
; GET A CHUNK OF DATA FROM SCSI BUS. THIS IS SPECIFICALLY FOR
|
|
; READ PHASE. IF A LENGTH IS SPECIFIED (NON-ZERO HL), THEN THE
|
|
; DATA IS BURST READ. IF NO LENGTH SPECIFIED, DATA IS READ AS
|
|
; LONG AS SCSI DEVICE WANTS TO CONTINUE SENDING (NO OVERRUN
|
|
; CHECK IN THIS CASE).
|
|
;
|
|
; THIS IS A NIBBLE READ.
|
|
;
|
|
; DE=BUFFER
|
|
; HL=LENGTH (0 FOR VARIABLE)
|
|
;
|
|
IMM_GETDATA:
|
|
; BRANCH TO CORRECT ROUTINE
|
|
LD A,H
|
|
OR L ; IF ZERO
|
|
JR NZ,IMM_GETDATALEN ; DO BURST READ
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
PRTS("\r\nGETDATA:$")
|
|
#ENDIF
|
|
;
|
|
IMM_GETDATA1:
|
|
PUSH HL ; SAVE BYTE COUNTER
|
|
CALL IMM_WAIT ; WAIT FOR BUS READY
|
|
POP HL ; RESTORE BYTE COUNTER
|
|
CP $98 ; CHECK FOR READ PHASE
|
|
JR NZ,IMM_GETDATA2 ; IF NOT, ASSUME WE ARE DONE
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
LD A,$06
|
|
CALL IMM_WRITECTRL
|
|
CALL IMM_READSTATUS ; GET FIRST NIBBLE
|
|
AND $F0 ; ISOLATE BITS
|
|
RRCA ; AND SHIFT TO LOW NIBBLE
|
|
RRCA
|
|
RRCA
|
|
RRCA
|
|
PUSH AF ; SAVE WORKING VALUE
|
|
LD A,$05
|
|
CALL IMM_WRITECTRL
|
|
CALL IMM_READSTATUS ; GET SECOND NIBBLE
|
|
AND $F0 ; ISOLATE BITS
|
|
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
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
LD A,$0C
|
|
CALL IMM_WRITECTRL
|
|
JR IMM_GETDATA1 ; LOOP TILL DONE
|
|
;
|
|
IMM_GETDATA2:
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXWORDHL
|
|
PRTS(" BYTES$")
|
|
#ENDIF
|
|
;
|
|
RET
|
|
;
|
|
IMM_GETDATALEN:
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
PRTS("\r\nGETDLEN:$")
|
|
CALL PC_SPACE
|
|
CALL PRTHEXWORDHL
|
|
PRTS(" BYTES$")
|
|
#ENDIF
|
|
;
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
IMM_GETDATALEN1:
|
|
LD A,$06
|
|
CALL IMM_WRITECTRL
|
|
CALL IMM_READSTATUS ; GET FIRST NIBBLE
|
|
AND $F0 ; ISOLATE BITS
|
|
RRCA ; MOVE TO LOW NIBBLE
|
|
RRCA
|
|
RRCA
|
|
RRCA
|
|
PUSH AF ; SAVE WORKING VALUE
|
|
LD A,$05
|
|
CALL IMM_WRITECTRL
|
|
CALL IMM_READSTATUS ; GET SECOND NIBBLE
|
|
AND $F0 ; ISOLATE BITS
|
|
POP BC ; RECOVER FIRST NIBBLE
|
|
OR B ; COMBINE
|
|
LD (DE),A ; SAVE FINAL BYTE VALUE
|
|
INC DE ; NEXT BUFFER POS
|
|
DEC HL ; DEC LOOP COUNTER
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
LD A,H ; CHECK LOOP COUNTER
|
|
OR L
|
|
JR NZ,IMM_GETDATALEN1 ; LOOP IF NOT DONE
|
|
LD A,$0C
|
|
CALL IMM_WRITECTRL
|
|
RET
|
|
;
|
|
; PUT A CHUNK OF DATA TO THE SCSI BUS. THIS IS SPECIFICALLY FOR
|
|
; WRITE PHASE. IF A LENGTH IS SPECIFIED (NON-ZERO HL), THEN THE
|
|
; DATA IS BURST WRITTEN. IF NO LENGTH SPECIFIED, DATA IS WRITTEN AS
|
|
; LONG AS SCSI DEVICE WANTS TO CONTINUE RECEIVING (NO OVERRUN
|
|
; CHECK IN THIS CASE).
|
|
;
|
|
; READS ARE DONE AS BYTE PAIRS. EACH LOOP READS 2 BYTES.
|
|
;
|
|
; DE=BUFFER
|
|
; HL=LENGTH (0 FOR VARIABLE)
|
|
;
|
|
IMM_PUTDATA:
|
|
LD A,H
|
|
OR L
|
|
JR NZ,IMM_PUTDATALEN
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
PRTS("\r\nPUTDATA:$")
|
|
#ENDIF
|
|
;
|
|
IMM_PUTDATA1:
|
|
PUSH HL ; SAVE BYTE COUNTER
|
|
CALL IMM_WAIT ; WAIT FOR BUS READY
|
|
POP HL ; RESTORE BYTE COUNTER
|
|
CP $88 ; CHECK FOR WRITE PHASE
|
|
JR NZ,IMM_PUTDATA2 ; IF NOT, ASSUME WE ARE DONE
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
LD A,(DE) ; GET NEXT BYTE TO WRITE (FIRST OF PAIR)
|
|
CALL IMM_WRITEDATA ; PUT ON BUS
|
|
INC DE ; BUMP TO NEXT BUF POS
|
|
INC HL ; INCREMENT COUNTER
|
|
LD A,$05
|
|
CALL IMM_WRITECTRL
|
|
LD A,(DE) ; GET NEXT BYTE TO WRITE (SECOND OF PAIR)
|
|
CALL IMM_WRITEDATA ; PUT ON BUS
|
|
INC DE ; BUMP TO NEXT BUF POS
|
|
INC HL ; INCREMENT COUNTER
|
|
LD A,$00
|
|
CALL IMM_WRITECTRL
|
|
JR IMM_PUTDATA1 ; LOOP TILL DONE
|
|
;
|
|
IMM_PUTDATA2:
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXWORDHL
|
|
PRTS(" BYTES$")
|
|
#ENDIF
|
|
;
|
|
RET
|
|
;
|
|
IMM_PUTDATALEN:
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
PRTS("\r\nPUTDLEN:$")
|
|
CALL PC_SPACE
|
|
CALL PRTHEXWORDHL
|
|
PRTS(" BYTES$")
|
|
#ENDIF
|
|
;
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
IMM_PUTDATALEN1:
|
|
LD A,(DE) ; GET NEXT BYTE (FIRST OF PAIR)
|
|
CALL IMM_WRITEDATA ; PUT ON BUS
|
|
INC DE ; INCREMENT BUF POS
|
|
DEC HL ; DEC LOOP COUNTER
|
|
LD A,$05
|
|
CALL IMM_WRITECTRL
|
|
LD A,(DE) ; GET NEXT BYTE (SECOND OF PAIR)
|
|
CALL IMM_WRITEDATA ; PUT ON BUS
|
|
INC DE ; INCREMENT BUF POS
|
|
DEC HL ; DEC LOOP COUNTER
|
|
LD A,$00
|
|
CALL IMM_WRITECTRL
|
|
LD A,H ; CHECK LOOP COUNTER
|
|
OR L
|
|
JR NZ,IMM_PUTDATALEN1 ; LOOP TILL DONE
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
RET
|
|
;
|
|
; READ SCSI COMMAND STATUS
|
|
;
|
|
IMM_GETSTATUS:
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
PRTS("\r\nSTATUS:$")
|
|
#ENDIF
|
|
;
|
|
CALL IMM_GETBYTE ; GET ONE BYTE
|
|
LD (IMM_CMDSTAT),A ; SAVE AS FIRST STATUS BYTE
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
CALL IMM_WAIT ; CHECK FOR OPTIONAL SECOND BYTE
|
|
CP $B8 ; STILL IN STATUS PHASE?
|
|
RET NZ ; IF NOT, DONE
|
|
CALL IMM_GETBYTE ; ELSE, GET THE SECOND BYTE
|
|
LD (IMM_CMDSTAT+1),A ; AND SAVE IT
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
RET
|
|
;
|
|
; TERMINATE A BULD READ OPERATION
|
|
;
|
|
IMM_ENDREAD:
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
LD A,$0C
|
|
CALL IMM_WRITECTRL
|
|
LD A,$0E
|
|
CALL IMM_WRITECTRL
|
|
LD A,$04
|
|
CALL IMM_WRITECTRL
|
|
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
|
|
; BC: TRANSFER LENGTH (0=VARIABLE)
|
|
;
|
|
IMM_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 IMM_CMD_ERR BELOW.
|
|
LD (IMM_CMDSTK),SP ; FOR ERROR ABORTS
|
|
LD (IMM_DSKBUF),DE ; SAVE BUF PTR
|
|
LD (IMM_XFRLEN),BC ; SAVE XFER LEN
|
|
PUSH HL
|
|
CALL IMM_CONNECT ; PARALLEL PORT BUS CONNECT
|
|
CALL IMM_SELECT ; SELECT TARGET DEVICE
|
|
CALL IMM_WAIT ; WAIT TILL READY
|
|
POP HL
|
|
CALL IMM_SENDCMD ; SEND THE COMMAND
|
|
;
|
|
IMM_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 IMM_LONGWAIT ; WAIT TILL READY
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
PRTS("\r\nPHASE: $")
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
CP $88 ; DEVICE WANTS TO RCV DATA
|
|
JR Z,IMM_RUNCMD_WRITE
|
|
CP $98 ; DEVICE WANTS TO SEND DATA
|
|
JR Z,IMM_RUNCMD_READ
|
|
CP $B8 ; DEVICE WANTS TO BE DONE
|
|
JR Z,IMM_RUNCMD_END
|
|
JR IMM_CMD_IOERR
|
|
;
|
|
IMM_RUNCMD_WRITE:
|
|
LD DE,(IMM_DSKBUF) ; XFER BUFFER
|
|
LD HL,(IMM_XFRLEN) ; XFER LENGTH
|
|
CALL IMM_PUTDATA ; SEND DATA NOW
|
|
JR IMM_RUNCMD_PHASE ; BACK TO DISPATCH
|
|
;
|
|
IMM_RUNCMD_READ:
|
|
CALL IMM_NEGOTIATE ; NEGOTIATE FOR READ
|
|
CALL IMM_WAIT ; WAIT TILL READY
|
|
; CHECK FOR STATUS $98???
|
|
LD DE,(IMM_DSKBUF) ; XFER BUFFER
|
|
LD HL,(IMM_XFRLEN) ; XFER LENGTH
|
|
CALL IMM_GETDATA ; GET THE DATA NOW
|
|
CALL IMM_ENDREAD ; TERMINATE THE READ
|
|
JR IMM_RUNCMD_PHASE ; BACK TO DISPATCH
|
|
;
|
|
IMM_RUNCMD_END:
|
|
CALL IMM_NEGOTIATE ; NEGOTIATE FOR READ (STATUS)
|
|
CALL IMM_WAIT ; WAIT TILL READY
|
|
; CHECK FOR STATUS $B8???
|
|
CALL IMM_GETSTATUS ; READ STATUS BYTES
|
|
CALL IMM_ENDREAD ; TERMINATE THE READ
|
|
CALL IMM_DISCONNECT ; PARALLEL PORT BUS DISCONNECT
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
IMM_CMD_IOERR:
|
|
LD A,IMM_STIOERR ; ERROR VALUE TO A
|
|
JR IMM_CMD_ERR ; CONTINUE
|
|
;
|
|
IMM_CMD_TIMEOUT:
|
|
LD A,IMM_STTO ; ERROR VALUE TO A
|
|
JR IMM_CMD_ERR ; CONTINUE
|
|
;
|
|
IMM_CMD_ERR:
|
|
LD SP,(IMM_CMDSTK) ; UNWIND STACK
|
|
PUSH AF ; SAVE STATUS
|
|
;CALL IMM_RESETPULSE ; CLEAN UP THE MESS???
|
|
LD DE,62 ; DELAY AFTER RESET PULSE
|
|
CALL VDELAY
|
|
CALL IMM_DISCONNECT ; PARALLEL PORT BUS DISCONNECT
|
|
LD DE,62 ; DELAY AFTER DISCONNECT
|
|
CALL VDELAY
|
|
POP AF ; RECOVER STATUS
|
|
JP IMM_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.
|
|
;
|
|
IMM_CHKCMD:
|
|
; SCSI COMMAND COMPLETED, CHECK SCSI CMD STATUS
|
|
LD A,(IMM_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,IMM_CHKCMD1 ; IF SO, REQUEST SENSE
|
|
JP IMM_IOERR ; ELSE, GENERAL I/O ERROR
|
|
;
|
|
IMM_CHKCMD1:
|
|
; USE REQUEST SENSE CMD TO GET ERROR DETAILS
|
|
LD DE,HB_WRKBUF ; PUT DATA IN WORK BUF
|
|
LD BC,0 ; VARIABLE LENGTH REQUEST
|
|
LD HL,IMM_CMD_SENSE ; REQUEST SENSE CMD
|
|
CALL IMM_RUNCMD ; DO IT
|
|
JP NZ,IMM_IOERR ; BAIL IF ERROR IN CMD
|
|
;
|
|
; REQ SENSE CMD COMPLETED
|
|
#IF (IMMTRACE >= 3)
|
|
LD A,16
|
|
LD DE,HB_WRKBUF
|
|
CALL Z,PRTHEXBUF
|
|
#ENDIF
|
|
;
|
|
; CHECK SCSI CMD STATUS
|
|
LD A,(IMM_CMDSTAT) ; GET STATUS BYTE
|
|
OR A ; SET FLAGS
|
|
JP NZ,IMM_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,IMM_NOMEDIA ; IF SO, RETURN NO MEDIA ERR
|
|
JP IMM_IOERR ; ELSE GENERAL I/O ERR
|
|
;
|
|
; CHECK CURRENT DEVICE FOR ERROR STATUS AND ATTEMPT TO RECOVER
|
|
; VIA RESET IF DEVICE IS IN ERROR.
|
|
;
|
|
IMM_CHKERR:
|
|
LD A,(IY+IMM_STAT) ; GET STATUS
|
|
OR A ; SET FLAGS
|
|
CALL NZ,IMM_RESET ; IF ERROR STATUS, RESET BUS
|
|
RET
|
|
;
|
|
; (RE)INITIALIZE DEVICE
|
|
;
|
|
IMM_INITDEV:
|
|
; INITIALIZE 8255
|
|
LD A,(IY+IMM_IOBASE) ; BASE PORT
|
|
ADD A,IMM_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
|
|
;
|
|
CALL IMM_DISCONNECT ; DISCONNECT FIRST JUST IN CASE
|
|
CALL IMM_CONNECT ; NOW CONNECT TO BUS
|
|
CALL IMM_RESETPULSE ; ISSUE A SCSI BUS RESET
|
|
LD DE,62 ; WAIT A BIT
|
|
CALL VDELAY
|
|
CALL IMM_DISCONNECT ; AND DISCONNECT FROM BUS
|
|
LD DE,62 ; WAIT A BIT MORE
|
|
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
|
|
IMM_INITDEV1:
|
|
PUSH BC ; SAVE LOOP COUNTER
|
|
;
|
|
; REQUEST SENSE COMMAND
|
|
LD DE,HB_WRKBUF ; BUFFER FOR SENSE DATA
|
|
LD BC,0 ; READ WHATEVER IS SENT
|
|
LD HL,IMM_CMD_SENSE ; POINT TO CMD BUFFER
|
|
CALL IMM_RUNCMD ; RUN THE SCSI ENGINE
|
|
JR NZ,IMM_INITDEV2 ; CMD PROC ERROR
|
|
;
|
|
; CHECK CMD STATUS
|
|
LD A,(IMM_CMDSTAT) ; GET STATUS BYTE
|
|
OR A ; SET FLAGS
|
|
JR NZ,IMM_INITDEV2 ; IF ERROR, LOOP
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
LD A,16
|
|
LD DE,HB_WRKBUF
|
|
CALL PRTHEXBUF
|
|
#ENDIF
|
|
;
|
|
; CHECK SENSE KEY
|
|
LD A,(HB_WRKBUF + 2) ; GET SENSE KEY
|
|
OR A ; SET FLAGS
|
|
;
|
|
IMM_INITDEV2:
|
|
POP BC ; RESTORE LOOP COUNTER
|
|
JR Z,IMM_INITDEV3 ; IF NO ERROR, MOVE ON
|
|
DJNZ IMM_INITDEV1 ; TRY UNTIL COUNTER EXHAUSTED
|
|
JP IMM_IOERR ; BAIL OUT WITH ERROR
|
|
;
|
|
IMM_INITDEV3:
|
|
; READ & RECORD DEVICE CAPACITY
|
|
LD DE,HB_WRKBUF ; BUFFER TO CAPACITY RESPONSE
|
|
LD BC,0 ; READ WHATEVER IS SENT
|
|
LD HL,IMM_CMD_RDCAP ; POINT TO READ CAPACITY CMD
|
|
CALL IMM_RUNCMD ; RUN THE SCSI ENGINE
|
|
CALL Z,IMM_CHKCMD ; CHECK AND RECORD AND ERRORS
|
|
RET NZ ; BAIL ON ON ERROR
|
|
;
|
|
#IF (IMMTRACE >= 3)
|
|
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,IMM_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+IMM_STAT),A ; RECORD IT
|
|
RET
|
|
;;;;
|
|
;;;; *** DEBUG ***
|
|
;;;;
|
|
;;; LD DE,HB_WRKBUF
|
|
;;; LD BC,512
|
|
;;; LD HL,IMM_CMD_READ
|
|
;;; CALL IMM_RUNCMD
|
|
;;; CALL Z,IMM_CHKCMD
|
|
;;; LD DE,HB_WRKBUF
|
|
;;; CALL Z,DUMP_BUFFER
|
|
;;;;
|
|
;;; LD DE,HB_WRKBUF
|
|
;;; LD BC,512
|
|
;;; LD HL,IMM_CMD_READ
|
|
;;; CALL IMM_RUNCMD
|
|
;;; CALL Z,IMM_CHKCMD
|
|
;;; LD DE,HB_WRKBUF
|
|
;;; CALL Z,DUMP_BUFFER
|
|
;;;;
|
|
;;; LD DE,HB_WRKBUF
|
|
;;; LD BC,0
|
|
;;; LD HL,IMM_CMD_INQ
|
|
;;; CALL IMM_RUNCMD
|
|
;;; CALL Z,IMM_CHKCMD
|
|
;;; LD DE,HB_WRKBUF
|
|
;;; CALL Z,DUMP_BUFFER
|
|
;;;;
|
|
;;; LD DE,HB_WRKBUF
|
|
;;; LD BC,512
|
|
;;; LD HL,IMM_CMD_WRITE
|
|
;;; CALL IMM_RUNCMD
|
|
;;; CALL Z,IMM_CHKCMD
|
|
;;;;
|
|
;;; LD DE,HB_WRKBUF
|
|
;;; LD BC,512
|
|
;;; LD HL,IMM_CMD_READ2
|
|
;;; CALL IMM_RUNCMD
|
|
;;; CALL Z,IMM_CHKCMD
|
|
;;; LD DE,HB_WRKBUF
|
|
;;; CALL Z,DUMP_BUFFER
|
|
;;;;
|
|
;;; RET
|
|
;;;;
|
|
;;;IMM_CMD .DB $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 ; TEMPLATE
|
|
;;;IMM_CMD_READ .DB $08, $00, $00, $00, $01, $00 ; READ SECTOR $0000
|
|
;;;IMM_CMD_INQ .DB $12, $00, $00, $00, $FF, $00 ; INQUIRY
|
|
;;;IMM_CMD_TEST .DB $00, $00, $00, $00, $00, $00 ; TEST UNIT READY
|
|
;;;IMM_CMD_START .DB $1B, $00, $00, $00, $01, $00 ; START UNIT
|
|
;;;IMM_CMD_WRITE .DB $0A, $00, $F0, $00, $01, $00 ; READ SECTOR $F000
|
|
;;;IMM_CMD_READ2 .DB $08, $00, $F0, $00, $01, $00 ; READ SECTOR $F000
|
|
;
|
|
;=============================================================================
|
|
; ERROR HANDLING AND DIAGNOSTICS
|
|
;=============================================================================
|
|
;
|
|
; ERROR HANDLERS
|
|
;
|
|
IMM_INVUNIT:
|
|
LD A,IMM_STINVUNIT
|
|
JR IMM_ERR2 ; SPECIAL CASE FOR INVALID UNIT
|
|
;
|
|
IMM_NOMEDIA:
|
|
LD A,IMM_STNOMEDIA
|
|
JR IMM_ERR
|
|
;
|
|
IMM_CMDERR:
|
|
LD A,IMM_STCMDERR
|
|
JR IMM_ERR
|
|
;
|
|
IMM_IOERR:
|
|
LD A,IMM_STIOERR
|
|
JR IMM_ERR
|
|
;
|
|
IMM_TO:
|
|
LD A,IMM_STTO
|
|
JR IMM_ERR
|
|
;
|
|
IMM_NOTSUP:
|
|
LD A,IMM_STNOTSUP
|
|
JR IMM_ERR
|
|
;
|
|
IMM_ERR:
|
|
LD (IY+IMM_STAT),A ; SAVE NEW STATUS
|
|
;
|
|
IMM_ERR2:
|
|
#IF (IMMTRACE >= 2)
|
|
CALL IMM_PRTSTAT
|
|
#ENDIF
|
|
OR A ; SET FLAGS
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IMM_PRTERR:
|
|
RET Z ; DONE IF NO ERRORS
|
|
; FALL THRU TO IMM_PRTSTAT
|
|
;
|
|
; PRINT FULL DEVICE STATUS LINE
|
|
;
|
|
IMM_PRTSTAT:
|
|
PUSH AF
|
|
PUSH DE
|
|
PUSH HL
|
|
LD A,(IY+IMM_STAT)
|
|
CP IMM_STINVUNIT
|
|
JR Z,IMM_PRTSTAT2 ; INVALID UNIT IS SPECIAL CASE
|
|
CALL IMM_PRTPREFIX ; PRINT UNIT PREFIX
|
|
JR IMM_PRTSTAT3
|
|
IMM_PRTSTAT2:
|
|
CALL NEWLINE
|
|
PRTS("IMM:$") ; NO UNIT NUM IN PREFIX FOR INVALID UNIT
|
|
IMM_PRTSTAT3:
|
|
CALL PC_SPACE ; FORMATTING
|
|
CALL IMM_PRTSTATSTR
|
|
POP HL
|
|
POP DE
|
|
POP AF
|
|
RET
|
|
;
|
|
; PRINT STATUS STRING
|
|
;
|
|
IMM_PRTSTATSTR:
|
|
PUSH AF
|
|
PUSH DE
|
|
LD A,(IY+IMM_STAT)
|
|
OR A
|
|
LD DE,IMM_STR_STOK
|
|
JR Z,IMM_PRTSTATSTR1
|
|
INC A
|
|
LD DE,IMM_STR_STINVUNIT
|
|
JR Z,IMM_PRTSTATSTR1
|
|
INC A
|
|
LD DE,IMM_STR_STNOMEDIA
|
|
JR Z,IMM_PRTSTATSTR1
|
|
INC A
|
|
LD DE,IMM_STR_STCMDERR
|
|
JR Z,IMM_PRTSTATSTR1
|
|
INC A
|
|
LD DE,IMM_STR_STIOERR
|
|
JR Z,IMM_PRTSTATSTR1
|
|
INC A
|
|
LD DE,IMM_STR_STTO
|
|
JR Z,IMM_PRTSTATSTR1
|
|
INC A
|
|
LD DE,IMM_STR_STNOTSUP
|
|
JR Z,IMM_PRTSTATSTR1
|
|
LD DE,IMM_STR_STUNK
|
|
IMM_PRTSTATSTR1:
|
|
CALL WRITESTR
|
|
POP DE
|
|
POP AF
|
|
RET
|
|
;
|
|
; PRINT DIAGNONSTIC PREFIX
|
|
;
|
|
IMM_PRTPREFIX:
|
|
PUSH AF
|
|
CALL NEWLINE
|
|
PRTS("IMM$")
|
|
LD A,(IY+IMM_DEV) ; GET CURRENT DEVICE NUM
|
|
CP $FE ; NOT YET ASSIGNED?
|
|
JR Z,IMM_PRTPREFIX1 ; SKIP DEV NUM IF SO
|
|
CALL PRTDECB
|
|
IMM_PRTPREFIX1:
|
|
CALL PC_COLON
|
|
POP AF
|
|
RET
|
|
;
|
|
;=============================================================================
|
|
; STRING DATA
|
|
;=============================================================================
|
|
;
|
|
IMM_STR_STOK .TEXT "OK$"
|
|
IMM_STR_STINVUNIT .TEXT "INVALID UNIT$"
|
|
IMM_STR_STNOMEDIA .TEXT "NO MEDIA$"
|
|
IMM_STR_STCMDERR .TEXT "COMMAND ERROR$"
|
|
IMM_STR_STIOERR .TEXT "IO ERROR$"
|
|
IMM_STR_STTO .TEXT "TIMEOUT$"
|
|
IMM_STR_STNOTSUP .TEXT "NOT SUPPORTED$"
|
|
IMM_STR_STUNK .TEXT "UNKNOWN ERROR$"
|
|
;
|
|
IMM_STR_NOHW .TEXT "NOT PRESENT$"
|
|
;
|
|
IMM_STR_MODE_NONE .TEXT "NONE$"
|
|
IMM_STR_MODE_MG014 .TEXT "MG014$"
|
|
IMM_STR_MODE_UNK .TEXT "???$"
|
|
;
|
|
;=============================================================================
|
|
; DATA STORAGE
|
|
;=============================================================================
|
|
;
|
|
IMM_DEVNUM .DB 0 ; TEMP DEVICE NUM USED DURING INIT
|
|
IMM_CMDSTK .DW 0 ; STACK PTR FOR CMD ABORTING
|
|
IMM_DSKBUF .DW 0 ; WORKING DISK BUFFER POINTER
|
|
IMM_XFRLEN .DW 0 ; WORKING TRANSFER LENGTH
|
|
IMM_CMDSTAT .DB 0, 0 ; CMD RESULT STATUS
|
|
;
|
|
IMM_TYPE_MAP:
|
|
.DW IMM_STR_NONE
|
|
.DW IMM_STR_MG014
|
|
;
|
|
IMM_STR_NONE .DB "<NOT PRESENT>$"
|
|
IMM_STR_MG014 .DB "MG014$"
|
|
;
|
|
; SCSI COMMAND TEMPLATES (LENGTH PREFIXED)
|
|
;
|
|
.DB 6
|
|
IMM_CMD_RW .DB $00, $00, $00, $00, $01, $00 ; READ/WRITE SECTOR
|
|
.DB 6
|
|
IMM_CMD_SENSE .DB $03, $00, $00, $00, $FF, $00 ; REQUEST SENSE DATA
|
|
.DB 10
|
|
IMM_CMD_RDCAP .DB $25, $00, $00, $00, $00, $00, $00, $00, $00, $00 ; READ CAPACITY
|
|
;
|
|
; IMM DEVICE CONFIGURATION TABLE
|
|
;
|
|
IMM_CFG:
|
|
;
|
|
#IF (IMMCNT >= 1)
|
|
;
|
|
IMM0_CFG: ; DEVICE 0
|
|
.DB 0 ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
|
|
.DB IMM0MODE ; DRIVER DEVICE MODE
|
|
.DB 0 ; DEVICE STATUS
|
|
.DB IMM0BASE ; IO BASE ADDRESS
|
|
.DW 0,0 ; DEVICE CAPACITY
|
|
.DW 0,0 ; CURRENT LBA
|
|
#ENDIF
|
|
;
|
|
#IF (IMMCNT >= 2)
|
|
;
|
|
IMM1_CFG: ; DEVICE 1
|
|
.DB 0 ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
|
|
.DB IMM1MODE ; DRIVER DEVICE MODE
|
|
.DB 0 ; DEVICE STATUS
|
|
.DB IMM1BASE ; IO BASE ADDRESS
|
|
.DW 0,0 ; DEVICE CAPACITY
|
|
.DW 0,0 ; CURRENT LBA
|
|
#ENDIF
|
|
;
|
|
#IF ($ - IMM_CFG) != (IMMCNT * IMM_CFGSIZ)
|
|
.ECHO "*** INVALID IMM CONFIG TABLE ***\n"
|
|
#ENDIF
|
|
;
|
|
.DB $FF ; END MARKER
|