mirror of
https://github.com/wwarthen/RomWBW.git
synced 2026-02-06 14:11:48 -06:00
Use a global flag to indicate if interrupts have been enabled during the boot process. Drivers that operate in the pre-interrupt phase can use this to manage interrupt disable bracketing. This allows restoring the location of interrupt enable in the boot process to it's proper location.
366 lines
9.0 KiB
NASM
366 lines
9.0 KiB
NASM
;
|
|
;==================================================================================================
|
|
; PIO DRIVER (PARALLEL PORT)
|
|
;==================================================================================================
|
|
;
|
|
; SETUP PARAMETER WORD:
|
|
; +-------+---+-------------------+ +---+---+-----------+---+-------+
|
|
; | |RTS| ENCODED BAUD RATE | |DTR|XON| PARITY |STP| 8/7/6 |
|
|
; +-------+---+---+---------------+ ----+---+-----------+---+-------+
|
|
; F E D C B A 9 8 7 6 5 4 3 2 1 0
|
|
; -- MSB (D REGISTER) -- -- LSB (E REGISTER) --
|
|
;
|
|
; THIS DRIVER IS JUST A STUB TO DETECT AND INITIALIZE PIO HARDWARE
|
|
; IF IT EXISTS. FOR NOW, IT DOES NOT REGISTER ANY OF THE PIO CHANNELS
|
|
; AS CHARACTER DEVICE UNITS.
|
|
;
|
|
PIO_NONE .EQU 0
|
|
PIO_PIO .EQU 1
|
|
;
|
|
PIO0A_CTL .EQU PIO0BASE + $02
|
|
PIO0A_DAT .EQU PIO0BASE + $00
|
|
PIO0B_CTL .EQU PIO0BASE + $03
|
|
PIO0B_DAT .EQU PIO0BASE + $01
|
|
;
|
|
#IF (PIOCNT >= 2)
|
|
;
|
|
PIO1A_CTL .EQU PIO1BASE + $02
|
|
PIO1A_DAT .EQU PIO1BASE + $00
|
|
PIO1B_CTL .EQU PIO1BASE + $03
|
|
PIO1B_DAT .EQU PIO1BASE + $01
|
|
;
|
|
#ENDIF
|
|
;
|
|
PIO_PREINIT:
|
|
;
|
|
; SETUP THE DISPATCH TABLE ENTRIES
|
|
; NOTE: INTS WILL BE DISABLED WHEN PREINIT IS CALLED AND THEY MUST REMAIN
|
|
; DISABLED.
|
|
;
|
|
CALL PIO_PROBE ; PROBE FOR CHIPS
|
|
;
|
|
LD B,PIO_CFGCNT ; LOOP CONTROL
|
|
XOR A ; ZERO TO ACCUM
|
|
LD (PIO_DEV),A ; CURRENT DEVICE NUMBER
|
|
LD IY,PIO_CFG ; POINT TO START OF CFG TABLE
|
|
PIO_PREINIT0:
|
|
PUSH BC ; SAVE LOOP CONTROL
|
|
CALL PIO_INITUNIT ; HAND OFF TO GENERIC INIT CODE
|
|
POP BC ; RESTORE LOOP CONTROL
|
|
;
|
|
LD A,(IY+1) ; GET THE PIO TYPE DETECTED
|
|
OR A ; SET FLAGS
|
|
JR Z,PIO_PREINIT2 ; SKIP IT IF NOTHING FOUND
|
|
;
|
|
PUSH BC ; SAVE LOOP CONTROL
|
|
PUSH IY ; CFG ENTRY ADDRESS
|
|
POP DE ; ... TO DE
|
|
LD BC,PIO_FNTBL ; BC := FUNCTION TABLE ADDRESS
|
|
; REGISTRATION OF CHARACTER UNIT IN HBIOS IS BYPASSED
|
|
; FOR NOW. NOT SURE WHAT TO DO WITH THIS HARDWARE YET.
|
|
;CALL NZ,CIO_ADDENT ; ADD ENTRY IF PIO FOUND, BC:DE
|
|
POP BC ; RESTORE LOOP CONTROL
|
|
;
|
|
PIO_PREINIT2:
|
|
LD DE,PIO_CFGSIZ ; SIZE OF CFG ENTRY
|
|
ADD IY,DE ; BUMP IY TO NEXT ENTRY
|
|
DJNZ PIO_PREINIT0 ; LOOP UNTIL DONE
|
|
;
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET ; AND RETURN
|
|
;
|
|
; PIO INITIALIZATION ROUTINE
|
|
;
|
|
PIO_INITUNIT:
|
|
CALL PIO_DETECT ; DETERMINE PIO TYPE
|
|
LD (IY+1),A ; SAVE IN CONFIG TABLE
|
|
OR A ; SET FLAGS
|
|
RET Z ; ABORT IF NOTHING THERE
|
|
;
|
|
; UPDATE WORKING PIO DEVICE NUM
|
|
LD HL,PIO_DEV ; POINT TO CURRENT UART DEVICE NUM
|
|
LD A,(HL) ; PUT IN ACCUM
|
|
INC (HL) ; INCREMENT IT (FOR NEXT LOOP)
|
|
LD (IY),A ; UPDATE UNIT NUM
|
|
;
|
|
; SET DEFAULT CONFIG
|
|
LD DE,-1 ; LEAVE CONFIG ALONE
|
|
JP PIO_INITDEV ; IMPLEMENT IT AND RETURN
|
|
;
|
|
;
|
|
;
|
|
PIO_INIT:
|
|
LD B,PIO_CFGCNT ; COUNT OF POSSIBLE PIO UNITS
|
|
LD IY,PIO_CFG ; POINT TO START OF CFG TABLE
|
|
PIO_INIT1:
|
|
PUSH BC ; SAVE LOOP CONTROL
|
|
LD A,(IY+1) ; GET PIO TYPE
|
|
OR A ; SET FLAGS
|
|
CALL NZ,PIO_PRTCFG ; PRINT IF NOT ZERO
|
|
POP BC ; RESTORE LOOP CONTROL
|
|
LD DE,PIO_CFGSIZ ; SIZE OF CFG ENTRY
|
|
ADD IY,DE ; BUMP IY TO NEXT ENTRY
|
|
DJNZ PIO_INIT1 ; LOOP TILL DONE
|
|
;
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET ; DONE
|
|
;
|
|
; DRIVER FUNCTION TABLE
|
|
;
|
|
PIO_FNTBL:
|
|
.DW PIO_IN
|
|
.DW PIO_OUT
|
|
.DW PIO_IST
|
|
.DW PIO_OST
|
|
.DW PIO_INITDEV
|
|
.DW PIO_QUERY
|
|
.DW PIO_DEVICE
|
|
#IF (($ - PIO_FNTBL) != (CIO_FNCNT * 2))
|
|
.ECHO "*** INVALID PIO FUNCTION TABLE ***\n"
|
|
#ENDIF
|
|
;
|
|
;
|
|
;
|
|
PIO_IN:
|
|
LD E,0 ; DUMMY VALUE
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
PIO_OUT:
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
PIO_IST:
|
|
XOR A ; NO CHARS WAITING
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
PIO_OST:
|
|
XOR A ; NO BUFFER SPACE AVAIL
|
|
RET
|
|
;
|
|
PIO_INITDEV:
|
|
; INITDEV CAN BE CALLED PRIOR TO INTERRUPTS BEING ENABLED. WE
|
|
; NEED TO LEAVE INTERRUPTS ALONE IN THIS SCENARIO
|
|
LD A,(INTSENAB) ; INTS ENABLED?
|
|
OR A ; TEST VALUE
|
|
JR Z,PIO_INITDEV0 ; BYPASS DI/EI IF NOT ENABLED
|
|
;
|
|
; INTERRUPTS DISABLED DURING INIT
|
|
; ??? IS THIS NEEDED?
|
|
HB_DI ; DISABLE INTS
|
|
CALL PIO_INITDEV0 ; DO THE WORK
|
|
HB_EI ; INTS BACK ON
|
|
RET ; DONE
|
|
;
|
|
PIO_INITDEV0:
|
|
;
|
|
; THIS ENTRY POINT BYPASSES DISABLING/ENABLING INTS WHICH IS REQUIRED BY
|
|
; PREINIT ABOVE. PREINIT IS NOT ALLOWED TO ENABLE INTS!
|
|
;
|
|
LD C,(IY+3) ; CONTROL PORT
|
|
LD A,%00010111 ; CLEAR INTERRUPT CTL WORD
|
|
OUT (C),A
|
|
LD A,%11111111 ; CLEAR MASK
|
|
OUT (C),A
|
|
LD A,%00000000 ; CLEAR INTERRUPT VECTOR
|
|
OUT (C),A
|
|
LD A,%01001111 ; SET MODE 1 (INPUT)
|
|
OUT (C),A
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
PIO_QUERY:
|
|
LD E,(IY+5) ; FIRST CONFIG BYTE TO E
|
|
LD D,(IY+6) ; SECOND CONFIG BYTE TO D
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET ; DONE
|
|
;
|
|
;
|
|
;
|
|
PIO_DEVICE:
|
|
LD D,CIODEV_PIO ; D := DEVICE TYPE
|
|
LD E,(IY) ; E := PHYSICAL UNIT
|
|
LD C,$40 ; C := DEVICE TYPE, 0x40 IS PIO
|
|
LD H,(IY+1) ; H := MODE
|
|
LD L,(IY+3) ; L := BASE I/O ADDRESS
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
; PIO CHIP PROBE
|
|
; CHECK FOR PRESENCE OF PIO CHIPS AND POPULATE THE
|
|
; PIO_MAP BITMAP (ONE BIT PER CHIP). THIS DETECTS
|
|
; CHIPS, NOT CHANNELS. EACH CHIP HAS 2 CHANNELS.
|
|
; MAX OF TWO CHIPS CURRENTLY. INT VEC VALUE IS TRASHED!
|
|
;
|
|
PIO_PROBE:
|
|
; CLEAR THE PRESENCE BITMAP
|
|
LD HL,PIO_MAP ; HL POINTS TO BITMAP
|
|
XOR A ; ZERO
|
|
LD (PIO_MAP),A ; CLEAR CHIP PRESENT BITMAP
|
|
;
|
|
; FIRST POSSIBLE CHIP
|
|
LD C,PIO0A_CTL ; FIRST CHIP CMD/STAT PORT
|
|
CALL PIO_PROBECHIP ; PROBE IT
|
|
JR NZ,PIO_PROBE1 ; IF NOT ZERO, NOT FOUND
|
|
SET 0,(HL) ; SET BIT FOR FIRST CARD
|
|
PIO_PROBE1:
|
|
;
|
|
#IF (PIOCNT >= 2)
|
|
LD C,PIO1A_CTL ; SECOND CHIP CMD/STAT PORT
|
|
CALL PIO_PROBECHIP ; PROBE IT
|
|
JR NZ,PIO_PROBE2 ; IF NOT ZERO, NOT FOUND
|
|
SET 1,(HL) ; SET BIT FOR SECOND CARD
|
|
PIO_PROBE2:
|
|
#ENDIF
|
|
;
|
|
RET
|
|
;
|
|
PIO_PROBECHIP:
|
|
; PIO IS HARD TO DETECT DEFINITIVELY. BEST I CAN THINK
|
|
; OF IS TO CHECK THE VALUE READ FROM THE CONTROL PORT.
|
|
; IT APPEARS TO BE ZERO CONSISTENTLY IF CHIP EXISTS.
|
|
IN A,(C) ; GET VALUE
|
|
OR A ; COMPARE TO ZERO
|
|
RET
|
|
;
|
|
; PIO DETECTION ROUTINE
|
|
; THERE IS ONLY ONE VARIATION OF PIO CHIP, SO HERE WE JUST CHECK THE
|
|
; CHIP PRESENCE BITMAP TO SET THE CHIP TYPE OF EITHER NONE OR PIO.
|
|
;
|
|
PIO_DETECT:
|
|
LD B,(IY+2) ; GET CHIP/CHANNEL
|
|
SRL B ; SHIFT AWAY THE CHANNEL BIT
|
|
INC B ; NUMBER OF TIMES TO ROTATE BITS
|
|
LD A,(PIO_MAP) ; BIT MAP IN A
|
|
PIO_DETECT1:
|
|
; ROTATE DESIRED CHIP BIT INTO CF
|
|
RRA ; ROTATE NEXT BIT INTO CF
|
|
DJNZ PIO_DETECT1 ; DO THIS UNTIL WE HAVE DESIRED BIT
|
|
; RETURN CHIP TYPE
|
|
LD A,PIO_NONE ; ASSUME NOTHING HERE
|
|
RET NC ; IF CF NOT SET, RETURN
|
|
LD A,PIO_PIO ; CHIP TYPE IS PIO
|
|
RET ; DONE
|
|
;
|
|
;
|
|
;
|
|
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
|
|
;
|
|
XOR A
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
PIO_TYPE_MAP:
|
|
.DW PIO_STR_NONE
|
|
.DW PIO_STR_PIO
|
|
|
|
PIO_STR_NONE .DB "<NOT PRESENT>$"
|
|
PIO_STR_PIO .DB "PIO$"
|
|
;
|
|
; WORKING VARIABLES
|
|
;
|
|
PIO_DEV .DB 0 ; DEVICE NUM USED DURING INIT
|
|
PIO_MAP .DB 0 ; CHIP PRESENCE BITMAP
|
|
;
|
|
PIO0A_RCVBUF .EQU 0
|
|
PIO0B_RCVBUF .EQU 0
|
|
;
|
|
#IF (PIOCNT >= 2)
|
|
PIO1A_RCVBUF .EQU 0
|
|
PIO1B_RCVBUF .EQU 0
|
|
#ENDIF
|
|
;
|
|
; PIO PORT TABLE
|
|
;
|
|
PIO_CFG:
|
|
; PIO0 CHANNEL A
|
|
PIO0A_CFG:
|
|
.DB 0 ; DEVICE NUMBER (SET DURING INIT)
|
|
.DB 0 ; PIO TYPE (SET DURING INIT)
|
|
.DB $00 ; CHIP 0 / CHANNEL A (LOW BIT IS CHANNEL)
|
|
.DB PIO0A_CTL ; CMD/STATUS PORT
|
|
.DB PIO0A_DAT ; DATA PORT
|
|
.DW DEFSERCFG ; LINE CONFIGURATION
|
|
.DW PIO0A_RCVBUF ; POINTER TO RCV BUFFER STRUCT
|
|
;
|
|
DEVECHO "PIO: IO="
|
|
DEVECHO PIO0BASE
|
|
DEVECHO ", CHANNEL A\n"
|
|
;
|
|
PIO_CFGSIZ .EQU $ - PIO_CFG ; SIZE OF ONE CFG TABLE ENTRY
|
|
;
|
|
; PIO0 CHANNEL B
|
|
PIO0B_CFG:
|
|
.DB 0 ; DEVICE NUMBER (SET DURING INIT)
|
|
.DB 0 ; PIO TYPE (SET DURING INIT)
|
|
.DB $01 ; CHIP 0 / CHANNEL B (LOW BIT IS CHANNEL)
|
|
.DB PIO0B_CTL ; CMD/STATUS PORT
|
|
.DB PIO0B_DAT ; DATA PORT
|
|
.DW DEFSERCFG ; LINE CONFIGURATION
|
|
.DW PIO0B_RCVBUF ; POINTER TO RCV BUFFER STRUCT
|
|
;
|
|
DEVECHO "PIO: IO="
|
|
DEVECHO PIO0BASE
|
|
DEVECHO ", CHANNEL B\n"
|
|
;
|
|
#IF (PIOCNT >= 2)
|
|
;
|
|
; PIO1 CHANNEL A
|
|
PIO1A_CFG:
|
|
.DB 0 ; DEVICE NUMBER (SET DURING INIT)
|
|
.DB 0 ; PIO TYPE (SET DURING INIT)
|
|
.DB $02 ; CHIP 1 / CHANNEL A (LOW BIT IS CHANNEL)
|
|
.DB PIO1A_CTL ; CMD/STATUS PORT
|
|
.DB PIO1A_DAT ; DATA PORT
|
|
.DW DEFSERCFG ; LINE CONFIGURATION
|
|
.DW PIO1A_RCVBUF ; POINTER TO RCV BUFFER STRUCT
|
|
;
|
|
DEVECHO "PIO: IO="
|
|
DEVECHO PIO1BASE
|
|
DEVECHO ", CHANNEL A\n"
|
|
;
|
|
; PIO1 CHANNEL B
|
|
PIO1B_CFG:
|
|
.DB 0 ; DEVICE NUMBER (SET DURING INIT)
|
|
.DB 0 ; PIO TYPE (SET DURING INIT)
|
|
.DB $03 ; CHIP 1 / CHANNEL B (LOW BIT IS CHANNEL)
|
|
.DB PIO1B_CTL ; CMD/STATUS PORT
|
|
.DB PIO1B_DAT ; DATA PORT
|
|
.DW DEFSERCFG ; LINE CONFIGURATION
|
|
.DW PIO1B_RCVBUF ; POINTER TO RCV BUFFER STRUCT
|
|
;
|
|
DEVECHO "PIO: IO="
|
|
DEVECHO PIO1BASE
|
|
DEVECHO ", CHANNEL B\n"
|
|
;
|
|
#ENDIF
|
|
;
|
|
PIO_CFGCNT .EQU ($ - PIO_CFG) / PIO_CFGSIZ
|