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.
 
 
 
 
 
 

1002 lines
25 KiB

; PIO driver sets up the parallel port as a subtype of Serial/Char device.
;
;
; HBIOS initializes driver by:
;
; 1) Calling Pre-initialization
;
; This involves setting up all the data structures describing the devices.
; If possible, do a hardware test to verify it is available for adding to available devices.
;
; 2) Calling device initialization.
;
; Hardware initialization.
; Configure to initial state or to a new state.
;
; Implementation limitations:
;
; The fully functionality of the Z80 PIO can only be realized by using Z80 interrupt mode 2.
; Registers cannot be interrogated for interrupts status and the originating interrupt
; device cannot be determine.
;
; Full implementation of IM2 functionality for an ECB-ZP and ECB-4P board would require the
; allocation of an interrupt handler for each chip channel. Thus, 12 interrupt handlers
; would be required to support this configuration. As the HBIOS only has an allocation of
; 16, a full implmentation is impractical.
;
; The compromise solution is to allow 4 interrupts for the PIO driver.; All remaining PIO's
; are limited to Bit mode or blind read and writed to the input/output ports.
;
; Zilog PIO reset state:
;
; Both port mask registers are reset to inhibit All port data bits.
; Port data bus lines are set to a high-impedance state and the Ready "handshake"
; Mode 1 (output) is automatically selected.
; The vector address registers are not reset.
; Both port interrupt enable flip-flops are reset.
; Both port output registers are reset.
;
; Register addressing for ECB-ZP and ECB-4P assuming base address 90h and 88h respectively.
;
; PIO ----ZP---- ----4P----
; 0 DATA 0 90h DATA 0 B8h
; 0 DATA 1 91h DATA 1 B9h
; 0 CMD 0 92h CMD 0 BAh
; 0 CMD 1 93h CMD 1 BBh
; 1 DATA 0 94h DATA 0 BCh
; 1 DATA 1 95h DATA 1 BDh
; 1 CMD 0 96h CMD 0 BEh
; 1 CMD 1 97h CMD 1 BFh
; 2 DATA 0 C0h
; 2 DATA 1 C1h
; 2 CMD 0 C2h
; 2 CMD 1 C3h
; 3 DATA 0 C4h
; 3 DATA 1 C5h
; 3 CMD 0 C6h
; 3 CMD 1 C7h
;
PIODEBUG .EQU 1
;
M_Output .EQU $00 << 6
M_Input .EQU $01 << 6
M_Bidir .EQU $02 << 6
M_BitCtrl .EQU $03 << 6
M_BitAllIn .EQU $FF
M_BitAllOut .EQU $00
;
PIO_NONE .EQU 0
PIO_ZPIO .EQU 1
PIO_8255 .EQU 2
PIO_PORT .EQU 3
; SET MAXIMUM NUMBER OF INTERRUPTS AVAILABLE FOR ALL
; ENSURE INTERRUPTS ARE NOT TURNED ON IF IM2 IS NOT SET.
INT_ALLOC .DB 0
INT_N .EQU 00000000B
#IF (INTMODE == 2)
INT_Y .EQU 00000100B
INT_ALLOW .EQU 4
#ELSE
INT_Y .EQU INT_N
INT_ALLOW .EQU 0
#ENDIF
;
INT0 .EQU 00000000B
INT1 .EQU 00000001B
INT2 .EQU 00000010B
INT3 .EQU 00000011B
;
; SETUP THE DISPATCH TABLE ENTRIES
;
; PIO_CNT HOLDS THE NUMBER OF DEVICED CALCULATED FROM THE NUMBER OF DEFPIO MACROS
; PIO_CNT SHOULD INCREASE BY 2 FOR EVERY PIO CHIP ADDED.
;
; PIO_PREINIT WILL READ THROUGH ALL PIOCFG TABLES AND CONFIGURE EACH TABLE.
; IT WITH THEN CALL PIO_INITUNIT TO INITIALIZE EACH DEVICE TO ITS DEFAULT STATE
;
; EXPECTS NOTHING ON ENTRY
;
PIO_PREINIT:
CALL NEWLINE ;D
LD B,PIO_CNT ; LOOP CONTROL
LD C,0 ; PHYSICAL UNIT INDEX
XOR A ; ZERO TO ACCUM
; LD (PIO_DEV),A ; CURRENT DEVICE NUMBER
LD (INT_ALLOC),A ; START WITH NO INTERRUPTS ALLOCATED
PIO_PREINIT0:
PUSH BC ; SAVE LOOP CONTROL
; LD A,C ; INITIALIZE THE UNIT
; PUSH AF ;D
; LD A,'u' ;D
; CALL COUT ;D
; POP AF ;D
; CALL PRTHEXBYTE ;D UNIT
; CALL PC_SPACE ;D
; RLCA ; MULTIPLY BY CFG TABLE ENTRY SIZE (32 BYTES)
; RLCA ; ...
; RLCA ; ... TO GET OFFSET INTO CFG TABLE
; RLCA
;; RLCA
; LD HL,PIO_CFG ; POINT TO START OF CFG TABLE
; PUSH AF
; CALL ADDHLA ; HL := ENTRY ADDRESS
; POP AF
; CALL ADDHLA ; HL := ENTRY ADDRESS
; PUSH HL ; SAVE IT
; POP IY ; ... TO IY
CALL IDXCFG
LD (HL),C
PUSH AF ;D
LD A,'c' ;D
CALL COUT ;D
POP AF ;D
PUSH BC ;D
PUSH HL ;D
POP BC ;D
CALL PRTHEXWORD ;D CONFIG TABLE
CALL PC_SPACE ;D
POP BC ;D
LD A,(IY+1) ; GET THE PIO TYPE DETECTED
CP PIO_PORT ; SET FLAGS
PUSH AF ;D
LD A,'t' ;D
CALL COUT ;D
POP AF ;D
CALL PRTHEXBYTE ;D TYPE
CALL PC_SPACE ;D
; JR Z,BADINIT
; PUSH BC ; SAVE LOOP CONTROL
; LD BC,PIO_FNTBL ; BC := FUNCTION TABLE ADDRESS
; DEC A
; JR Z,TYPFND ; SKIP IT IF NOTHING FOUND
; LD BC,PPI_FNTBL ; BC := FUNCTION TABLE ADDRESS
; DEC A
; JR Z,TYPFND ; ADD ENTRY IF PIO FOUND, BC:DE
; LD BC,PRT_FNTBL
; DEC A
; JR Z,TYPFND
; POP BC
; JR BADINIT
PUSH HL
LD DE,-1 ; INITIALIZE THIS DEVICE WITH
CALL PIO_INITDEV ; DEFAULT VALUES
POP HL
; JR NZ,SKPINIT
; AT THIS POINT WE KNOW WE
; HAVE A VALID DEVICE SO ADD IT
LD A,8 ; CALCULATE THE FUNCTION TABLE
CALL ADDHLA ; POSITION WHICH FOLLOWS THE
PUSH HL ; CONFIGURATION TABLE OF EACH
POP BC ; DEVICE
TYPFND: PUSH AF ;D
LD A,'f' ;D
CALL COUT ;D
POP AF ;D
PUSH BC ;D
CALL PRTHEXWORD ;D FUNCTION TABLE
POP BC ;D
CALL NEWLINE ;D
PUSH IY ; ADD ENTRY IF PIO FOUND, BC:DE
POP DE ; BC: DRIVER FUNCTION TABLE
CALL CIO_ADDENT ; DE: ADDRESS OF UNIT INSTANCE DATA
BADINIT:POP BC ; RESTORE LOOP CONTROL
INC C ; NEXT PHYSICAL UNIT
SKPINIT:DJNZ PIO_PREINIT0 ; LOOP UNTIL DONE
PUSH AF ;D
PRTS("INTS=$") ;D
LD A,(INT_ALLOC) ;D
CALL PRTHEXBYTE ;D
POP AF ;D
PUSH DE ;D
LD DE,CIO_TBL-3 ;D
CALL DUMP_BUFFER ;D
POP DE ;D
XOR A ; SIGNAL SUCCESS
RET ; AND RETURN
;
; X24
;
;
CFG_SIZ .EQU 24
;
IDXCFG: LD A,C
RLCA ; X 2
RLCA ; X 4
RLCA ; X 8
LD H,0
LD L,A ; HL = X 8
PUSH HL
ADD HL,HL ; HL = X 16
POP DE
ADD HL,DE ; HL = X 24
LD DE,PIO_CFG
ADD HL,DE
PUSH HL ; COPY CFG DATA PTR
POP IY ; ... TO IY
RET
; PIO_INITDEV - INITIALIZE DEVICE
;
; IF DE = FFFF THEN THE SETUP PARAMETER WORD WILL BE READ FROM THE DEVICE CONFIGURATION
; TABLE POINTED TO BY IY AND THE PIO PORT WILL BE PROGRAMMED BASED ON THAT CONFIGURATION.
;
; OTHERWISE THE PIO PORT WILL BE PROGRAMMED BY THE SETUP PARAMETER WORD IN DE AND THIS
; WILL BE SAVED IN THE DEVICE CONFIGURATION TABLE POINTED TO BY IY.
;
; ALL OTHER CONFIGURATION OF THE DEVICE CONFIGURATION TABLE IS DONE UPSTEAM BY PIO_PREINIT
PIO_INITDEV:
; TEST FOR -1 (FFFF) WHICH MEANS USE CURRENT CONFIG (JUST REINIT)
LD A,D ; TEST DE FOR
AND E ; ... VALUE OF -1
INC A ; ... SO Z SET IF -1
JR NZ,PIO_INITDEV1 ; IF DE == -1, REINIT CURRENT CONFIG
PIO_INITDEV0:
; LOAD EXISTING CONFIG (DCW) TO REINIT
LD E,(IY+4) ; LOW BYTE
LD D,(IY+5) ; HIGH BYTE
;
PIO_INITDEV1: ; WHICH DEVICE TYPE?
LD A,(IY+1)
CP PIO_ZPIO
JR Z,SETPIO0
CP PIO_8255
JP Z,SET_8255
CP PIO_PORT
JP Z,SET_PORT
BAD_SET:OR $FF ; UNKNOWN DEVICE
RET
SETPIO0:LD A,E ; GET MODE
AND 11000000B ; BITS (B7B6)
CP 10000000B ; IS IT BIDIR?
JR NZ,SETPIO1
LD A,(IY+2) ; GET CHANNEL
OR A
JR NZ,BAD_SET ; CAN'T DO ON CH1
; VALIDATE INTERRUPT REQUEST
; GRANT INTERRUPT IF THERE IS A FREE INTERRUPT
; GRANT INTERRUPT IF AN INTERRUPT IS ALREADY ALLOCATED TO THIS UNIT
SETPIO1:PUSH AF ;D
LD A,'[' ;D
CALL COUT ;D
LD A,(IY) ;D
CALL PRTHEXBYTE ;D
LD A,']' ;D
CALL COUT ;D
POP AF ;D
BIT 2,E ; SKIP IF WE ARE NOT REQUESTING
JP Z,SETPIO2 ; AN INTERRUPT
PRTS("[INTREQ]$") ;D
; LD A,(IY+4) ; GET CURRENT INTERRUPT SETTING
; BIT 2,A ; SKIP IF IT IS ALREADY
; JP NZ,SETPIO2 ; ALLOCATED TO THIS UNIT
LD A,(INT_ALLOC) ; WE NEED TO ALLOCATE AN
CP INT_ALLOW ; INTERRUPT. DO WE HAVE
JR NC,BAD_SET ; ONE FREE?
PRTS("[ALLOCINT]$") ;D
; WHICH INTERRUPT IS FREE ?
; SCAN THROUGH THE CFG TABLES
; AND FIND A FREE ONE
PUSH AF ; NESTED LOOP
LD DE,CFG_SIZ ; OUTSIDE LOOP IS INTERRUPT
LD B,INT_ALLOW ; INSIDE LOOP IS DEVICE
SETPIOP: LD C,B
DEC C
PUSH BC
LD B,PIO_CNT
LD HL,PIO_CFG+4
SETPIOX: LD A,(HL)
BIT 2,A ; JUMP TO NEXT DEVICE
JR Z,SETPIOY ; IF NO INTERRUPT ON
AND 00000011B ; THIS DEVICE
CP C ; IF WE MATCH AN INTERRUPT HERE THEN IT IS NOT FREE.
JR NZ,SETPIOY ; SO EXIT INSIDE LOOP AND TRY NEXT INTERRUPT
XOR A ; WE MATCH INT 0 - IF WE ARE CHECKING FOR IT THEN
OR C ; WE REGARD IS AS FREE.
JR NZ,SETPIOZ
SETPIOY: ADD HL,DE
DJNZ SETPIOX
JR SETPIOQ ; WE GET HERE IF THE CURRENT INTERRUPT
; WAS NOT MATCHED SO IT IS FREE
SETPIOZ: POP BC
DJNZ SETPIOP
POP AF
PRTS("[NONEFREE]$")
RET
SETPIOQ:PUSH AF ; AVAILABLE INTERRUPT IS IN C
PRTS("[FREE]=$")
LD A,C
CALL PRTHEXBYTE
POP AF
POP AF
POP AF
SETPIOR:LD HL,INT_ALLOC ; INCREASE THE COUNT
INC (HL) ; OF USED INTERRUPTS
LD A,(HL)
; LD A,(IY) ; IS THIS UNIT
; INC A ; UNITIALIZED?
; JR Z,SETPIO6
LD A,(IY+4) ; IT IS UNITIALIZED SO
OR C ; SAVE THE ALLOCATES
LD (IY+4),A ; INTERRUPT
;
; FOR THIS DEVICE AND INTERRUPT, UPDATE THE CONFIG TABLE FOR THIS DEVICE.
; PIO_IN, PIO_OUT, PIO_IST, PIO_OST ENTRIES NEED TO BE REDIRECTED.
; INTERRUPT VECTOR NEEDS TO BE UPDATED
;
LD A,(IY+0)
LD HL,0
; SETUP PIO INTERRUPT VECTOR IN IVT
LD HL,HBX_IV09+1
; CALL SPK_BEEP
;
SETPIO6:RET
; EXIT WITH FREE INTERRUPT IN C
LD A,C
LD (INT_ALLOC),A
LD A,E
AND 11000000B
OR 00000100B
OR C
LD E,A
LD (IY+5),A
;
; TODO: DEALLOCATE AN INTERRUPT
;
; LD A,(INT_ALLOC)
; DEC A
; LD (INT_ALLOC),A
;
SETPIO2:
; DE CONTAINS THE MODE IF INTERRUPT ROUTINE SKIPPED
PRTS("[NOINTREQ]$") ;D
; LD A,(IY+4)
LD A,E ; GET MODE AND CREATE COMMAND
AND 11000000B ; $B0
OR 00001111B ; $0F
LD C,(IY+3) ; GET DATA PORT
INC C ; POINT TO CMD
INC C ; PORT
OUT (C),A ; SET MODE
CP (M_BitCtrl | $0F) ; IF MODE 3
JR NZ,SETPIO3
LD A,(IY+5) ; SET I/O DIRECTION
OUT (C),A ; FOR MODE 3
SETPIO3:; INTERUPT HANDLING
JP SETPIO4
; SETUP THE INTERRUPT VECTOR
LD A,E
AND 00000011B
; DEC A ; INDEX INTO THE
ADD A,A ; THE VECTOR TABLE
ADD A,A ;
LD C,A
LD B,0
LD HL,HBX_IV09+1
ADD HL,BC ; GET THE ADDRESS OF
PUSH DE
LD D,(HL) ; THAT INTERRUPT
INC HL ; HANDLER
LD E,(HL)
LD HL,0 ;HBX_IVT+IVT_PIO0 ; POPULATE THE
LD A,L ; GET LOW BYTE OF IVT ADDRESS
ADD HL,BC ; INTERRUPT TABLE
LD (HL),D ; WITH THE INTERRUPT
INC HL ; HANDLER ADDRESS FOR
LD (HL),E ; THIS UNIT
POP DE
LD HL,INT_ALLOC
LD C,(HL)
LD B,0
LD HL,PRTTAB-1 ; SAVE THE DATA
ADD HL,BC ; PORT FOR EACH INTERRUPT
LD C,(IY+3)
LD (HL),C
INC C ; POINT TO CMD PORT
INC C
DI ; SET THE VECTOR ADDRESS
OUT (C),A
; LD A,10000011B ; ENABLE INTERRUPTS ON
OUT (C),A ; THIS UNIT
EI
; JR GUD_SET
;
SETPIO4:LD A,00000111B ; $07
OUT (C),A ; NO INTERRUPTS
;
; SUCCESSFULL SO SAVE DEVICE CONFIGURATION WORD (DCW)
;
GUD_SET:LD (IY+4),E ; LOW BYTE
LD (IY+5),D ; HIGH BYTE
;
; UPDATE THE DEVICE TABLE WITH THE ADDRESSES FOR THE CORRECT ROUTINE.
;
LD A,E
AND 00000111B
LD HL,INTMATRIX ; POINT TO EITHER THE INTERRUPT
JR NZ, USEIM
LD HL,POLMATRIX ; MATRIX OR THE POLLED MATRIX
USEIM: PUSH HL
PUSH IY ; CALCULATE THE DESTINATION
POP HL ; ADDRESS IN THE PIO_CFG TABLE
LD BC,8 ; FOR THE FOUR ADDESSES TO BE
ADD HL,BC ; COPIED TO
; LD B,0 ; 00000000 CALCULATE THE SOURCE ADDRESS
LD C,E ; XX?????? FROM THE MATRIX. EACH ENTRY
SRL C ; 0XX????? IN THE MATRIX IS 8 BYTES SO
SRL C ; 00XX???? SOURCE = MATRIX BASE + (8 * MODE)
SRL C ; 000XX???
POP DE ; LOAD THE MATRIX BASE
; LD DE,POLMATRIX
EX DE,HL
ADD HL,BC ; HL = SOURCE
LD C,8 ; COPY 8 BYTES
LDIR
; PUSH IY
; POP DE
; CALL DUMP_BUFFER
XOR A
RET
PRTTAB: .DB 0
.DB 0
.DB 0
.DB 0
;
;-----------------------------------------------------------------------------
;
; INPUT INTERRUPT VECTOR MACRO AND DEFINITION FOR FOUR PORTS
;
#DEFINE PIOMIVT(PIOIN,PIOIST,PIOPRT) \
#DEFCONT ;\
#DEFCONT ; RETURN WITH ERROR IF THERE IS \
#DEFCONT ; ALREADY A CHARACTER IN BUFFER \
#DEFCONT ;\
#DEFCONT ; OTHERWISE CHANGE THE STATUS TO \
#DEFCONT ; SHOW THERE IS ONE CHARACTER IN \
#DEFCONT ; THE BUFFER AND READ IT IN AND \
#DEFCONT ; AND STORE IT.RETURN GOOD STATUS.\
#DEFCONT ;\
#DEFCONT \ LD A,(_CIST)
#DEFCONT \ OR A
#DEFCONT \ JR NZ,_OVFL
#DEFCONT \ LD A,(PIOPRT)
#DEFCONT \ LD C,A
#DEFCONT \ LD A,1
#DEFCONT \ LD (_CIST),A
#DEFCONT \ IN A,(C)
#DEFCONT \ LD (_CICH),A
#DEFCONT \ OR $FF
#DEFCONT \ RET
#DEFCONT \_OVFL:XOR A
#DEFCONT \ RET
#DEFCONT ;\
#DEFCONT ;\
#DEFCONT ;\
#DEFCONT ;\
#DEFCONT ;\
#DEFCONT ;\
#DEFCONT \PIOIN:CALL PIOIST
#DEFCONT \ JR Z,PIOIN
#DEFCONT \ LD A,(_CICH)
#DEFCONT \ LD E,A
#DEFCONT \ XOR A
#DEFCONT \ LD (_CIST),A
#DEFCONT \ RET
#DEFCONT ;\
#DEFCONT ; If THERE A CHARACTER \
#DEFCONT ; AVAILABLE? RETURN NUMBER \
#DEFCONT ; IN A - 0 OR 1 \
#DEFCONT ;\
#DEFCONT \PIOIST:LD A,(_CIST)
#DEFCONT \ AND 00000001B
#DEFCONT \ RET
#DEFCONT ;\
#DEFCONT ; CIST : 01 = CHARACTER READY ELSE NOT READY \
#DEFCONT ; CISH : CHARACTER STORED BY INTERRUPT \
#DEFCONT ;\
#DEFCONT \_CIST .DB 00
#DEFCONT \_CICH .DB 00
;
PIOIVT0:.MODULE PIOIVT0
PIOMIVT(PIO0IN,PI0_IST,PRTTAB+0)
PIOIVT1:.MODULE PIOIVT1
PIOMIVT(PIO1IN,PI1_IST,PRTTAB+1)
PIOIVT2:.MODULE PIOIVT2
PIOMIVT(PIO2IN,PI2_IST,PRTTAB+2)
PIOIVT3:.MODULE PIOIVT3
PIOMIVT(PIO3IN,PI3_IST,PRTTAB+3)
;
;-----------------------------------------------------------------------------
;
; OUTPUT INTERRUPT VECTOR MACRO AND DEFINITION FOR FOUR PORTS
;
; AN INTERRUPT IS GENERATED WHEN THE RECEIVING DEVICE CAN ACCEPT A CHARACTER
;
#DEFINE PIOMOVT(PIOOUT,PIOOST,PIOPRT) \
#DEFCONT ;\
#DEFCONT ; RETURN IF WE ARE WAITING FOR A \
#DEFCONT ; CHARACTER (COST = 00) \
#DEFCONT ;\
#DEFCONT ; IF ZERO CHARACTERS READY
#DEFCONT ; (COST = 01) CHANGE STATUS TO \
#DEFCONT ; WAITING FOR CHARACTER (COST 00) \
#DEFCONT ;\
#DEFCONT ; IF A CHARACTER IS READY THEN \
#DEFCONT ; OUTPUT AND CHANGE STATUS TO \
#DEFCONT ; ZERO CHARACTERS READY \
#DEFCONT ;\
#DEFCONT \ LD A,(_COST)
#DEFCONT \ DEC A
#DEFCONT \ RET M
#DEFCONT \ JR Z,_WFC
#DEFCONT \ LD A,(_COCH)
#DEFCONT \ LD E,A
#DEFCONT \_ONOW:LD A,(PIOPRT)
#DEFCONT \ LD C,A
#DEFCONT \ OUT (C),E
#DEFCONT \ LD A,1
#DEFCONT \_WFC: LD (_COST),A
#DEFCONT \ RET
#DEFCONT ;\
#DEFCONT ; WAIT FOR SPACE FOR THE CHARACTER\
#DEFCONT ; IF WE ARE WAITING FOR A \
#DEFCONT ; CHARACTRE THEN OUTPUT IT NOW \
#DEFCONT ; OTHERWISE STORE IT UNTIL THE \
#DEFCONT ; INTERRUPT CALLS FOR IT \
#DEFCONT ;\
#DEFCONT \PIOOUT:LD A,(_COST)
#DEFCONT \ CP 2
#DEFCONT \ JR C,_ONOW
#DEFCONT \ LD A,E
#DEFCONT \ LD (_COCH),A
#DEFCONT \ LD A,2
#DEFCONT \ LD (_COST),A
#DEFCONT \ JR PIOOUT
#DEFCONT ;\
#DEFCONT ; RETURN WITH NUMBER OF \
#DEFCONT ; CHARACTERS AVAILABLE 0 or 1 \
#DEFCONT ;\
#DEFCONT \PIOOST:LD A,(_COST)
#DEFCONT \ DEC A
#DEFCONT \ DEC A
#DEFCONT \ RET Z
#DEFCONT \ LD A,1
#DEFCONT \ RET
#DEFCONT ;\
#DEFCONT ; COST : 00 WAITING FOR CHARACTER\
#DEFCONT ; 01 ZERO CHARACTERS READY\
#DEFCONT ; 02 ONE CHARACTER READY \
#DEFCONT ; COCH : CHARACTER TO OUTPUT \
#DEFCONT ;\
#DEFCONT \_COST .DB 01
#DEFCONT \_COCH .DB 00
;
PIOOVT0:.MODULE PIOOVT0
PIOMOVT(PIO0OUT,PI0_OST,PRTTAB+0)
PIOOVT1:.MODULE PIOOVT1
PIOMOVT(PIO1OUT,PI1_OST,PRTTAB+1)
PIOOVT2:.MODULE PIOOVT2
PIOMOVT(PIO2OUT,PI2_OST,PRTTAB+2)
PIOOVT3:.MODULE PIOOVT3
PIOMOVT(PIO3OUT,PI3_OST,PRTTAB+3)
;
;-----------------------------------------------------------------------------
;
; NON INTERRUPT OUTPUT ROUTINE - SHARED
;
; INPUT WILL ALWAYS RETURN ERROR, CHARACTER RETURNED IS UNDEFINED.
; OUTPUT WILL ALWAYS RETURN SUCCESS
; INPUT-STATUS WILL ALWAYS RETURN 0 CHARACTERS IN BUFFER.
; OUTPUT-STATUS WILL ALWAYS RETURN 1 CHARACTER SPACE IN BUFFER.
PIOSHO_IN:
LD A,1
RET
;
PIOSHO_OUT:
LD C,(IY+3)
OUT (C),E
XOR A
RET
;
PIOSHO_IST: XOR A
RET
;
PIOSH_OST:
LD A,1
RET
;
;-----------------------------------------------------------------------------
;
; NON INTERRUPT INPUT ROUTINE - SHARED
;
; INPUT WILL ALWAYS A CHARACTER AND SUCCESS.
; OUTPUT WILL ALWAYS RETURN FAILURE
; INPUT STATUS WILL ALWAYS RETURN 1 CHARACTER IN BUFFER.
;OUTPUT-STATUS WILL ALWAYS RETURN 0 CHARACTER SPACE IN BUFFER.
;
PIOSHI_IN:
LD C,(IY+3)
IN A,(C)
LD E,A
XOR A
RET
;
PIOSHI_OUT:
LD A,1
RET
;
PIOSH_IST:
LD A,1
RET
;
PIOSHI_OST:
XOR A
RET
;
;-----------------------------------------------------------------------------
;
; ON ENTRY IY POINTS TO THE DEVICE RECORD. GET AND RETURN THE CONFIGURATION WORD IN DE
;
PIO_QUERY:
PPI_QUERY:
LD E,(IY+4) ; FIRST CONFIG BYTE TO E
LD D,(IY+5) ; SECOND CONFIG BYTE TO D
XOR A ; SIGNAL SUCCESS
RET
;
;-----------------------------------------------------------------------------
;
; ON ENTRY IY POINTS TO THE DEVICE RECORD. FOR CHARACTER DEVICES BIT 6 OF ATTRIBUTE
; INDICATES PARALLEL PORT IF 1 SO WE SET IT. COMMON TO ALL PORTS
;
PIO_DEVICE:
PPI_DEVICE:
LD D,CIODEV_PIO ; D := DEVICE TYPE
LD E,(IY) ; E := PHYSICAL UNIT
LD C,$40 ; C := ATTRIBUTE
XOR A ; SIGNAL SUCCESS
RET
;
INTMATRIX:
.DW PIO0IN, PIO0OUT, PI0_IST, PI0_OST
.DW PIO1IN, PIO1OUT, PI1_IST, PI1_OST
.DW PIO2IN, PIO2OUT, PI2_IST, PI2_OST
.DW PIO3IN, PIO3OUT, PI3_IST, PI3_OST
POLMATRIX:
.DW PIOSHO_IN, PIOSHO_OUT, PIOSHO_IST, PIOSH_OST ; OUTPUT
.DW PIOSHI_IN, PIOSHI_OUT, PIOSH_IST, PIOSHI_OST ; INPUT
.DW 0,0,0,0 ; BIDIR
.DW 0,0,0,0 ; BIT MODE
SET_8255:
RET
;
SET_BYE:
XOR A ; SIGNAL SUCCESS
RET
;
; ------------------------------------
; i8255 FUNCTION TABLE ROUTINES
;-------------------------------------
PPI_IN:
XOR A ; SIGNAL SUCCESS
RET
;
PPI_OUT:
XOR A ; SIGNAL SUCCESS
RET
;
PPI_IST:
RET
;
PPI_OST:
RET
;
; PIO_INITDEV - Configure device.
; If DE = FFFF then extract the configuratio information from the table of devices and program the device using those settings.
; Otherwise use the configuration information in DE to program those settings and save them in the device table
PPI_INITDEV:
XOR A ; SIGNAL SUCCESS
RET
PPI_INT:OR $FF ; NZ SET TO INDICATE INT HANDLED
RET
;
PIO_PRTCFG:
; ANNOUNCE PORT
CALL NEWLINE ; FORMATTING
PRTS("PIO$") ; FORMATTING
LD A,(IY) ; DEVICE NUM
CALL PRTDECB ; PRINT DEVICE NUM
PRTS(": IO=0x$") ; FORMATTING
LD A,(IY+3) ; GET BASE PORT
CALL PRTHEXBYTE ; PRINT BASE PORT
;
; PRINT THE PIO TYPE
CALL PC_SPACE ; FORMATTING
LD A,(IY+1) ; GET PIO TYPE BYTE
RLCA ; MAKE IT A WORD OFFSET
LD HL,PIO_TYPE_MAP ; POINT HL TO TYPE MAP TABLE
CALL ADDHLA ; HL := ENTRY
LD E,(HL) ; DEREFERENCE
INC HL ; ...
LD D,(HL) ; ... TO GET STRING POINTER
CALL WRITESTR ; PRINT IT
;
; ALL DONE IF NO PIO WAS DETECTED
LD A,(IY+1) ; GET PIO TYPE BYTE
OR A ; SET FLAGS
RET Z ; IF ZERO, NOT PRESENT
;
PRTS(" MODE=$") ; FORMATTING
LD E,(IY+4) ; LOAD CONFIG
LD D,(IY+5) ; ... WORD TO DE
CALL PS_PRTPC0 ; PRINT CONFIG
;
LD A,(IY+4) ; PRINT
BIT 2,A ; ALLOCATED
JR Z,NOINT ; INTERRUPT
PRTS("/i$")
LD A,(IY+4)
AND 00000011B
CALL PRTDECB
NOINT: XOR A
RET
;
; WORKING VARIABLES
;
PIO_DEV .DB 0 ; DEVICE NUM USED DURING INIT
;
; DESCRIPTION OF DIFFERENT PORT TYPES
;
PIO_TYPE_MAP:
.DW PIO_STR_NONE
.DW PIO_STR_PIO
.DW PIO_STR_8255
.DW PIO_STR_PORT
PIO_STR_NONE .DB "<NOT PRESENT>$"
PIO_STR_PIO .DB "Zilog PIO$"
PIO_STR_8255 .DB "i8255 PPI$"
PIO_STR_PORT .DB "IO Port$"
;
; Z80 PIO PORT TABLE - EACH ENTRY IS FOR 1 CHIP I.E. TWO PORTS
;
; 32 BYTE DATA STRUCTURE FOR EACH PORT
;
; .DB 0 ; IY+0 CIO DEVICE NUMBER (SET DURING PRE-INIT, THEN FIXED)
; .DB 0 ; IY+1 PIO TYPE (SET AT ASSEMBLY, FIXED)
; .DB 0 ; IY+2 PIO CHANNEL (SET AT ASSEMBLY, FIXED)
; .DB PIOBASE+2 ; IY+3 BASE DATA PORT (SET AT ASSEMBLY, FIXED)
; .DB 0 ; IY+4 SPW - MODE 3 I/O DIRECTION BYTE (SET AT ASSEMBLE, SET WITH INIT)
; .DB 0 ; IY+5 SPW - MODE, INTERRUPT (SET AT ASSEMBLY, SET WITH INIT)
; .DW 0 ; IY+6/7 FUNCTION TABLE (SET AT ASSEMBLY, SET DURING PRE-INIT AND AT INIT)
; .DW PIO_IN ; IY+8 ADDR FOR DEVICE INPUT (SET WITH INIT)
; .DW PIO_OUT ; IY+10 ADDR FOR DEVICE OUTPUT (SET WITH INIT)
; .DW PIO_IST ; IY+12 ADDR FOR DEVICE INPUT STATUS (SET WITH INIT)
; .DW PIO_OST ; IY+14 ADDR FOR DEVICE OUTPUT STATUS (SET WITH INIT)
; .DW PIO_INITDEV ; IY+16 ADDR FOR INITIALIZE DEVICE ROUTINE (SET AT ASSEMBLY, FIXED)
; .DW PIO_QUERY ; IY+18 ADDR FOR QUERY DEVICE RECORD ROUTINE (SET AT ASSEMBLY, FIXED)
; .DW PIO_DEVICE ; IY+20 ADDR FOR DEVICE TYPE ROUTINE (SET AT ASSEMBLY, FIXED)
; .FILL 10
;
; SETUP PARAMETER WORD:
;
; +-------------------------------+ +-------+-----------+---+-------+
; | BIT CONTROL | | MODE | | A | INT |
; +-------------------------------+ --------------------+-----------+
; F E D C B A 9 8 7 6 5 4 3 2 1 0
; -- MSB (D REGISTER) -- -- LSB (E REGISTER) --
;
;
; MSB = BIT CONTROL MAP USE IN MODE 3
;
; MODE B7 B6 = 00 Mode 0 Output
; 01 Mode 1 Input
; 10 Mode 2 Bidir
; 11 Mode 3 Bit Mode
;
; INTERRUPT ALLOCATED B2 = 0 NOT ALLOCATED
; = 1 IS ALLOCATED
;
; WHICH IVT IS ALLOCATES B1 B0 00 IVT_PIO0
; 01 IVT_PIO1
; 10 IVT_PIO2
; 11 IVT_PIO3
;
#DEFINE DEFPIO(MPIOBASE,MPIOCH0,MPIOCH1,MPIOCH0X,MPIOCH1X,MPIOIN0,MPIOIN1) \
#DEFCONT \ .DB 0
#DEFCONT \ .DB PIO_ZPIO
#DEFCONT \ .DB 0
#DEFCONT \ .DB MPIOBASE
#DEFCONT \ .DB (MPIOCH0|MPIOIN0)
#DEFCONT \ .DB MPIOCH0X
#DEFCONT \ .DW 0
#DEFCONT \ .DW 0,0,0,0, PIO_INITDEV,PIO_QUERY,PIO_DEVICE
#DEFCONT \ .FILL 2
#DEFCONT \ .DB 0
#DEFCONT \ .DB PIO_ZPIO
#DEFCONT \ .DB 1
#DEFCONT \ .DB MPIOBASE+1
#DEFCONT \ .DB (MPIOCH1|MPIOIN1)
#DEFCONT \ .DB MPIOCH1X
#DEFCONT \ .DW 0
#DEFCONT \ .DW 0,0,0,0, PIO_INITDEV,PIO_QUERY,PIO_DEVICE
#DEFCONT \ .FILL 2
;
; i8255 PORT TABLE - EACH ENTRY IS FOR 1 CHIP I.E. THREE PORTS
;
#DEFINE DEFPPI(MPPIBASE,MPPICH1,MPPICH2,MPPICH3,MPPICH1X,MPPICH2X,MPPICH3X) \
#DEFCONT \ .DB 0
#DEFCONT \ .DB PIO_8255
#DEFCONT \ .DB 0
#DEFCONT \ .DB MPPIBASE
#DEFCONT \ .DB (MPPICH1|00001000B)
#DEFCONT \ .DB MPPICH1X
#DEFCONT \ .DW 0
#DEFCONT \ .DW PPI_IN,PPI_OUT,PPI_IST,PPI_OST,PPI_INITDEV,PPI_QUERY,PPI_DEVICE
#DEFCONT \ .FILL 2
#DEFCONT \ .DB 0
#DEFCONT \ .DB PIO_8255
#DEFCONT \ .DB 1
#DEFCONT \ .DB MPPIBASE+2
#DEFCONT \ .DB (MPPICH2|00010000B)
#DEFCONT \ .DB MPPICH2X
#DEFCONT \ .DW 0
#DEFCONT \ .DW PPI_IN,PPI_OUT,PPI_IST,PPI_OST,PPI_INITDEV,PPI_QUERY,PPI_DEVICE
#DEFCONT \ .FILL 2
#DEFCONT \ .DB 0
#DEFCONT \ .DB PIO_8255
#DEFCONT \ .DB 2
#DEFCONT \ .DB MPPIBASE+4
#DEFCONT \ .DB (MPPICH3|00100000B)
#DEFCONT \ .DB MPPICH3X
#DEFCONT \ .DW 0
#DEFCONT \ .DW PPI_IN,PPI_OUT,PPI_IST,PPI_OST,PPI_INITDEV,PPI_QUERY,PPI_DEVICE
#DEFCONT \ .FILL 2
;
; HERE WE ACTUALLY DEFINE THE HARDWARE THAT THE HBIOS CAN ACCESS
; THE INIT ROUTINES READ AND SET THE INITIAL MODES FROM THIS INFO
;
PIO_CFG:
;
#IF PIO_4P
DEFPIO(PIO4BASE+0,M_Output,M_Input,M_BitAllOut,M_BitAllOut,INT_N,INT_N)
DEFPIO(PIO4BASE+4,M_Input,M_Input,M_BitAllOut,M_BitAllOut,INT_N,INT_N)
DEFPIO(PIO4BASE+8,M_Output,M_Output,M_BitAllOut,M_BitAllOut,INT_N,INT_N)
DEFPIO(PIO4BASE+12,M_Output,M_Output,M_BitAllOut,M_Output,INT_N,INT_N)
#ENDIF
#IF PIO_ZP
DEFPIO(PIOZBASE+0,M_Input,M_Input,M_BitAllOut,M_BitAllOut,INT_N,INT_N)
DEFPIO(PIOZBASE+4,M_Output,M_Output,M_BitAllOut,M_BitAllOut,INT_N,INT_N)
#ENDIF
; PPI_SBC & (PLATFORM == PLT_SBC) & (PPIDEMODE != PPIDEMODE_SBC))
#IF PPI_SBC
DEFPPI(PPIBASE,M_Output,M_Output,M_Output,M_BitAllOut,M_BitAllOut,M_BitAllOut)
#ENDIF
;
PIO_CNT .EQU ($ - PIO_CFG) / CFG_SIZ
;
;-------------------------------------------------------------------
; WHEN WE GET HERE IY POINTS TO THE PIO_CFG TABLE WE ARE WORKING ON.
; C IS THE UNIT NUMBER
;-------------------------------------------------------------------
;
;PIO_INITUNIT:
; LD A,C ; SET THE UNIT NUMBER
; LD (IY),A
;
; LD DE,-1 ; LEAVE CONFIG ALONE
; CALL PIO_INITDEV ; IMPLEMENT IT AND RETURN
; XOR A ; SIGNAL SUCCESS
; RET ; AND RETURN
;
PIO_INIT:
; CALL SPK_BEEP
LD B,PIO_CNT ; COUNT OF POSSIBLE PIO UNITS
LD C,0 ; INDEX INTO PIO CONFIG TABLE
PIO_INIT1:
PUSH BC ; SAVE LOOP CONTROL
; LD A,C ; PHYSICAL UNIT TO A
; RLCA ; MULTIPLY BY CFG TABLE ENTRY SIZE (32 BYTES)
; RLCA ; ...
; RLCA ; ... TO GET OFFSET INTO CFG TABLE
; RLCA
;; RLCA
; LD HL,PIO_CFG ; POINT TO START OF CFG TABLE
; PUSH AF
; CALL ADDHLA ; HL := ENTRY ADDRESS
; POP AF
; CALL ADDHLA ; HL := ENTRY ADDRESS
; PUSH HL ; COPY CFG DATA PTR
; POP IY ; ... TO IY
CALL IDXCFG
LD A,(IY+1) ; GET PIO TYPE
OR A ; SET FLAGS
CALL NZ,PIO_PRTCFG ; PRINT IF NOT ZERO
; PUSH DE
; LD DE,$FFFF ; INITIALIZE DEVICE/CHANNEL
; CALL PIO_INITDEV ; BASED ON DPW
; POP DE
POP BC ; RESTORE LOOP CONTROL
INC C ; NEXT UNIT
DJNZ PIO_INIT1 ; LOOP TILL DONE
;
XOR A ; SIGNAL SUCCESS
RET ; DONE
;
SET_PORT:
; DEVICE TYPE IS I/O PORT SO JUST WRITE $00 TO IT
LD C,(IY+3)
OUT (C),A
XOR A
RET