PAGE 60 TITLE The Systems Group I/O module ; ; SGIO.MAC ; The Systems Group ; Physical I/O drivers for CP/M 2.2 ; ; Drivers for CPD2800 or CPC-2810 board (SIO and PIO) ; and for INO288 board (additional Physical drivers) ; ; Edit history: ; 9/10/81 jl - Updated CTC divisor constant for CPC-2810 Rev B. ; ; This source is written for MACRO-80 (Microsoft's Z80 assembler) .Z80 TRUE EQU -1 ; define true FALSE EQU 0 ; define false ; CONDITIONAL EQUATES ARE LOCATED IN FOLLOWING FILE INCLUDE SYSTEM.EQU IOBYTE EQU 3 ; location of I/O byte COMVEC EQU 30H ; communication vector ETX EQU 'C'-40H ; end of text char ACK EQU 'F'-40H ; acknoledge char IF1 ; on pass one IF CPD280 .PRINTX "CPD-2800 I/O drivers" ENDIF IF CPC281 .PRINTX "CPC-2810 I/O drivers" ENDIF IF INO288 .PRINTX "Additional INO-2880 I/O drivers" ENDIF IF INTDC .PRINTX "Receiver Interrupts for CRT: driver" ENDIF IF DIABLO .PRINTX "Diablo ETX/ACK protocal for TTY: driver" ENDIF ENDIF ; These are the entry points used by the BIOS GLOBAL CONST ; console status GLOBAL CONIN ; console input GLOBAL CONOT ; console output GLOBAL LIST ; list device GLOBAL PUNCH ; punch device GLOBAL READER ; reader device GLOBAL LISTST ; list device status GLOBAL INITIO ; I/O initialization ; Physical device per I/O byte bit definitions TTY EQU 00B ; SIO channel B CRT EQU 01B ; SIO channel A UC1 EQU 11B ; Uart-0 on INO288 board LPT EQU 10B ; PIO channels in Centronics mode UL1 EQU 11B ; Uart-1 on INO288 board ; Default I/O assignment: ; Set the next two equates to the prefered default Console and List devices. CON EQU CRT ; the console default LST EQU TTY ; the list device default ; I/O definitions for SIO and PIO devices on CPD280 or CPC281 ; IF CPD280 ; Universal Interrupt controller ports UICD EQU CPUB+12 UICC EQU CPUB+13 ENDIF ; ; SIO ports SIOAD EQU CPUB+0 ; channel A data SIOAC EQU CPUB+1 ; channel A status/control SIOBD EQU CPUB+2 ; channel B data SIOBC EQU CPUB+3 ; channel B status/control ; SIO baud rates SIOABR EQU 9600 ; channel A baud rate IF DIABLO ; if diablo on TTY: device SIOBBR EQU 1200 ; channel B baud rate ELSE SIOBBR EQU 9600 ; low speed printer ENDIF ; ; SIO status bits SRDA EQU 0 ; read data availible bit STBE EQU 2 ; transmitter buffer empty SDCD EQU 3 ; data carrier detect input bit CTS EQU 1 SHL STBE + 1 SHL SDCD ; mask for hardware handshaking ; PIO ports PIOAD EQU CPUB+4 ; channel A data PIOAC EQU CPUB+5 ; channel A status/control PIOBD EQU CPUB+6 ; channel B data PIOBC EQU CPUB+7 ; channel B status/control ; PIO status bits PBSY EQU 0 ; parallel device ready IF CPD280 ; TIMER ports (8253) used as baud rate generators and RTC CTR0 EQU CPUB+8 ; counter 0 (SIOA clock) CTR1 EQU CPUB+9 ; counter 1 (SIOB clock) CTR2 EQU CPUB+10 ; counter 2 (RTC counter) CTRM EQU CPUB+11 ; set counter mode port ; TIMER baud rate divisors (based on 1.2288 mhz clock) CDIV0 EQU 7680/(SIOABR/10) CDIV1 EQU 7680/(SIOBBR/10) ENDIF ; CPD280 IF CPC281 ; Additional SIO equates (presence optional). SIOCD EQU CPUB+8 ; channel C data SIOCC EQU CPUB+9 ; status/control SIODD EQU CPUB+10 ; channel D data SIODC EQU CPUB+11 ; status/control ; ; PROM on/off control PROM EQU CPUB+16 ; PROM control port ROMENA EQU 1 ; value to enable PROM ROMDIS EQU 0 ; value to disable PROM ; ; Z80-CTC used for baud rate generators and RTC CTCA EQU CPUB+12 ; counter A CTCB EQU CPUB+13 ; counter B CTCC EQU CPUB+14 ; counter C CTCD EQU CPUB+15 ; counter D ; IF SIOABR GE 600 CTMODA EQU 045H ; no pre-scaler, load constant CTDIVA EQU 3840/(SIOABR/10) ; constant ELSE CTMODA EQU 005H ; pre-scale = 16, load constant CTDIVA EQU 15625/SIOABR ; constant ENDIF IF SIOBBR GE 600 CTMODB EQU 045H ; see CTMODA CTDIVB EQU 3840/(SIOBBR/10) ELSE CTMODB EQU 005H CTDIVB EQU 15625/SIOBBR ENDIF ENDIF ; CPC281 ; I/O definitions for Uart-0 and Uart-1 on INO288 board ; ; Uart-0&1 ports (8251) INOU0D EQU INOB+0 ; Uart-0 data INOU0C EQU INOB+1 ; Uart-0 status/control INOU1D EQU INOB+2 ; Uart-1 data INOU1C EQU INOB+3 ; Uart-1 status/control ; ; 9519 UIC port addresses UICD1 EQU INOB+24 ; UIC 1 data port UICC1 EQU INOB+25 ; UIC 1 status/command port UICD2 EQU INOB+26 ; UIC 2 data port UICC2 EQU INOB+27 ; UIC 2 status/command port ; ; 8251 status bits IRDA EQU 1 ; read data availible bit ITBE EQU 0 ; transmitter buffer empty bit ; ; Baud rate port BRSW01 EQU INOB+16 ; for Uart-0&1 ; Device initialization INITIO: LD A,LST SHL 6+CON ; build the default I/O byte LD (IOBYTE),A ; and initialize it in page 0 IF CPD280 ; ***** 9519 UIC INITIALIZATION ***** ; ; The main initialization for the AMD 9519 UNIVERSAL INTERRUPT ; CONTROLLER located on the CPD-2800 CPU board is performed first. ; XOR A OUT (UICC),A ; reset UIC device ; ; IREQ lines active LOW, GROUP INTERRUPT active LOW, ; Set for rotating priority, individual vector, Interrupt mode. ; (see page 4 of AM9519 data sheet) ; LD A,81H OUT (UICC),A ; ; set "M7" ("CHIP ARMED BIT"). ; LD A,0A9H OUT (UICC),A ; ; enable the "AUTO-CLEAR" bits for all IREQ lines. ; LD A,0C0H ; pre-select auto clear OUT (UICC),A LD A,0FFH ; load auto clear register OUT (UICD),A ; ; Clear the interrupt request and Interrupt service registers. ; LD A,40H OUT (UICC),A ; clear INT REQUEST reg. LD A,70H OUT (UICC),A ; clear INT SERV reg. ENDIF IF INO288 XOR A OUT (UICC1),A ; reset 9519 UIC on INO-288 OUT (UICC2),A ; reset second 9519 ENDIF IF INTDC LD HL,COMISR LD (COMVEC),HL ; XOR A LD I,A IM 2 ENDIF ; INTDC IF CPD280 ; set SIO baud rates using 8253 counter LD A,036H ; 16-bit counter 0 load OUT (CTRM),A LD A,CDIV0 AND 0FFH OUT (CTR0),A ; load LSB LD A,CDIV0 SHR 8 OUT (CTR0),A ; load MSB LD A,076H ; 16-bit counter 1 load OUT (CTRM),A LD A,CDIV1 AND 0FFH OUT (CTR1),A ; load LSB LD A,CDIV1 SHR 8 OUT (CTR1),A ; load MSB ENDIF IF CPC281 ; set SIO baud rates using CTC counter LD A,CTMODA OUT (CTCA),A ; send mode LD A,CTDIVA OUT (CTCA),A ; and constant LD A,CTMODB OUT (CTCB),A ; send mode LD A,CTDIVB OUT (CTCB),A ; and constant ENDIF ; Set up SIO channels LD HL,ISIOA ; point to SIO init table LD BC,ISIOAL*256+SIOAC ; length in B & port in C OTIR ; mass programming LD HL,ISIOB ; repeat for channel B LD BC,ISIOBL*256+SIOBC OTIR ; Set up PIO for Centronics protocal LD A,00FH OUT (PIOAC),A ; channel A output LD A,0CFH OUT (PIOBC),A ; channel B bit control LD A,1 OUT (PIOBC),A ; bit 0 = busy LD A,80H OUT (PIOBD),A ; enable centronics bit IF CPC281 ; Reset second SIO on CPU board (presence optional) LD A,018H ; SIO reset OUT (SIOCC),A OUT (SIODC),A ENDIF IF INO288 ; Set up INO288 board IN A,(BRSW01) ; read baud rate switch OUT (BRSW01),A ; program baud rate LD HL,I8251 ; point to 8251 init table LD BC,I8251L*256+INOU0C ; length in B & port in C OTIR ; mass output LD HL,I8251 ; point to 8251 init table LD BC,I8251L*256+INOU1C ; length in B & port in C OTIR ; mass output ENDIF ; INO288 RET ; done IF INO288 ; Initialization sequence for 8251 I8251: DB 0AAH ; dummy command for re-initialization DB 040H ; reset device DB 04EH ; 1 stop bit,8-bit char,X16 clock DB 037H ; RTS,DTR,err reset,enable trans&rec I8251L EQU $-I8251 ; length of sequence ENDIF ; ****** INITIALIZATION TABLES FOR SIO DEVICES ****** ; ; CHANNEL A ISIOA: DB 018H ; channel reset DB 004H ; write reg 4 DB 044H ; X16 clock, 1 stop bit DB 003H ; write reg 3 DB 0C1H ; Rx 8-bit char, Rx enable DB 005H ; write reg 5 DB 0EAH ; DTR, Tx 8-bit char, Tx enable, RTS ; IF INTDC DB 001H ; write register 1 DB 018H ; INT on all Rx chars ENDIF ; DB 000H ; read reg 0 ISIOAL EQU $-ISIOA ; length of sequence ; ; CHANNEL B ISIOB: DB 018H ; channel reset DB 004H ; write reg 4 DB 044H ; X16 clock, 1 stop bit DB 003H ; write reg 3 DB 0C1H ; Rx 8-bit char, Rx enable DB 005H ; write reg 5 DB 0EAH ; DTR, Tx 8-bit char, Tx enable, RTS ; IF INTDC DB 002H ; write register 2 DB COMVEC AND 0FFH ; mode 2 vector for channel A ENDIF ; DB 000H ; read reg 0 ISIOBL EQU $-ISIOB ; length of sequence ; Logical Console Status entry: ; On exit: ACC=0 if no char waiting or ACC=FF if char waiting CONST: CALL DISPAT ; Dispatch to Physical driver DB 1 ; shift left once DW TTYST ; device table DW CRTST DW BATST DW UC1ST ; Logical Console Input entry: ; On exit: ACC=char CONIN: CALL DISPAT ; Dispatch to Physical driver DB 1 ; shift left once DW TTYIN ; device table DW CRTIN DW BATIN DW UC1IN ; Logical Console Output entry: ; On entry: C=char CONOT: CALL DISPAT ; Dispatch to Physical driver DB 1 ; shift left once DW TTYOT DW CRTOT DW BATOT DW UC1OT READER: XOR A PUNCH: RET ; *** NOT IMPLEMENTED *** ; Logical List Status entry: ; on exit: ACC=0 if transmitter busy, ACC=FF if transmit ready LISTST: CALL DISPAT ; Dispatch to Physical driver DB 3 ; shift left 3 times DW TTYOST DW CRTOST DW LPTOST DW UL1OST ; Logical List Device output entry: ; on entry: ACC=char LIST: CALL DISPAT ; Dispatch to Physical driver DB 3 ; shift left 3 times DW TTYOT DW CRTOT DW LPTOT DW UL1OT ; TTY Device Physical drivers: SIO channel B ; TTY receive status: TTYST: IN A,(SIOBC) ; get status BIT SRDA,A ; test receive data availible LD A,0 RET Z ; if no char waiting CPL ; set ACC=FF RET ; done ; TTY character input: TTYIN: IN A,(SIOBC) ; get status BIT SRDA,A ; test receive data availible JR Z,TTYIN ; loop for char IN A,(SIOBD) AND 07FH ; mask RET ; done ; TTY transmit status: TTYOST: IF SERCTS ; if hardware handshaking LD A,10H ; reset EXT status command OUT (SIOBC),A ; send to SIO IN A,(SIOBC) ; get status AND CTS ; mask TBE and DCD CP CTS ; test for both true LD A,0 RET NZ ; if not ready CPL ; set ACC=FF RET ; done ELSE IN A,(SIOBC) ; get status BIT STBE,A ; test transmitter LD A,0 RET Z ; if not ready CPL ; set ACC=FF RET ; done ENDIF ; TTY character output: TTYOT: CALL TTYOST ; call status routine OR A ; set flags JR Z,TTYOT ; loop if busy LD A,C ; get char OUT (SIOBD),A ; and send it IF DIABLO ; if diablo TTY: device CP "L"-40H ; check form feed JR Z,ASCFF CP "J"-40H ; check line feed RET NZ ; done of not ASCFF: PUSH BC LD C,ETX ; get EXT char CALL TTYOT ; send it WTACK: CALL TTYIN ; wait for ACK CP ACK JR NZ,WTACK POP BC LD A,C ; restore registers ENDIF RET ; done ; CRT Device Physical Drivers: SIO channel A ; CRT receive status: IF INTDC CRTST: EI PUSH DE PUSH HL LD HL,(COTPT) LD DE,(CINPT) OR A SBC HL,DE POP HL POP DE LD A,0 RET Z CPL RET ELSE ; NOT INTDC CRTST: IN A,(SIOAC) ; get status byte BIT SRDA,A ; test receive data availible LD A,0 RET Z ; if no char waiting CPL ; set A=FF RET ENDIF ; INTDC ; CRT character input: IF INTDC CRTIN: PUSH DE PUSH HL ; CRTIN1: EI LD HL,(CINPT) LD DE,(COTPT) OR A SBC HL,DE JR Z,CRTIN1 INC DE LD HL,CBEND OR A SBC HL,DE JR NZ,CRTIN2 LD DE,CBUF CRTIN2: LD (COTPT),DE LD A,(DE) POP HL POP DE AND 7FH RET ELSE ; NOT INTDC CRTIN: IN A,(SIOAC) ; get status byte BIT SRDA,A ; test receive data availible JR Z,CRTIN ; and loop till ready IN A,(SIOAD) ; get data AND 7FH ; ascii mask RET ENDIF ; INTDC ; CRT transmit status CRTOST: IN A,(SIOAC) ; get status BIT STBE,A ; test transmitter LD A,0 RET Z ; if busy CPL ; ACC=FF RET ; done ; CRT character output: CRTOT: IN A,(SIOAC) ; get status byte BIT STBE,A ; test transmitter buffer empty JR Z,CRTOT ; and loop till ready LD A,C ; get character OUT (SIOAD),A ; and send it RET IF INO288 ; UC1 Device Physical drivers: Uart-0 on INO288 board ; UC1 receive status: UC1ST: IN A,(INOU0C) ; get status BIT IRDA,A ; test receiver LD A,0 RET Z ; if no char CPL ; ACC=FF RET ; done ; UC1 character input: UC1IN: IN A,(INOU0C) ; get status BIT IRDA,A ; test receiver JR Z,UC1IN ; loop if no char IN A,(INOU0D) ; get char AND 07FH ; mask RET ; done ; UC1 character output: UC1OT: IN A,(INOU0C) ; get status BIT ITBE,A ; test transmitter JR Z,UC1OT ; loop if not ready LD A,C ; get char OUT (INOU0D),A ; and send it RET ; done ELSE ; INO288 ; The User defined console in not supported (UC1:=CRT:). UC1ST EQU CRTST UC1OST EQU CRTOST UC1IN EQU CRTIN UC1OT EQU CRTOT ENDIF ; INO288 ; LPT Device Physical drivers: PIO channels in Centronic mode ; LPT transmit status: LPTOST: IN A,(PIOBD) ; get status BIT PBSY,A ; test busy bit LD A,0 RET NZ ; if busy CPL ; ACC=FF RET ; if not busy ; LPT character output: LPTOT: IN A,(PIOBD) ; get status BIT PBSY,A ; test busy bit JR NZ,LPTOT ; loop if busy LD A,C ; get char OUT (PIOAD),A ; and send it RET ; done IF INO288 ; UL1 Device Physical drivers: Uart-1 on INO288 board ; UL1 transmit status: UL1OST: IN A,(INOU1C) ; get status BIT ITBE,A ; test transmitter LD A,0 RET Z ; if not ready CPL ; ACC=FF RET ; done ; UL1 character output: UL1OT: IN A,(INOU1C) ; get status BIT ITBE,A ; test transmitter JR Z,UL1OT ; if not ready LD A,C ; get char OUT (INOU1D),A ; and send it RET ; done ELSE ; INO288 ; The user defined List device is not supported (UL1:=TTY:). UL1OST EQU TTYOST UL1OT EQU TTYOT ENDIF ; INO288 ; The batch device is not supported (BAT:=CON:). BATST EQU CRTST BATIN EQU CRTIN BATOT EQU CRTOT IF INTDC ; Console interrupt service routine COMISR: LD (OLDSP),SP ; store callers stack pointer LD SP,COMSTK ; point to local stack PUSH AF PUSH BC PUSH DE PUSH HL ; save all regs ; LD DE,(CINPT) INC DE LD HL,CBEND OR A SBC HL,DE JR NZ,CISR1 LD DE,CBUF CISR1: LD (CINPT),DE IN A,(SIOAD) ; get character LD (DE),A ; POP HL POP DE POP BC POP AF ; restore all regs LD SP,(OLDSP) ; restore callers stack pointer EI RETI OLDSP: DW 0 ; old stack pointer DS 16 ; stack area COMSTK: ; top of communication stack ENDIF ; INTDC ; I/O Dispatch Routine: ; On entry: (SP)-> Physical driver addr table, 1st byte = IOBYT shift factor ; routine exits to Physical driver routine. DISPAT: EX (SP),HL ; get table address PUSH BC ; save regs LD B,(HL) ; get shift factor INC HL LD A,(IOBYTE) ; get the IOBYTE DISP0: RLCA ; shift DJNZ DISP0 ; per shift factor AND 0110B ; mask bits 1&2 LD C,A ; prep for double add ADD HL,BC ; find table entry LD A,(HL) ; get LSB in ACC INC HL LD H,(HL) ; get MSB in H LD L,A ; complete address POP BC ; restore regs EX (SP),HL ; restore HL and put addr on stack RET ; execute driver IF INTDC CINPT: DW CBUF ; input pointer COTPT: DW CBUF ; output pointer CBUF: DS 32 ; character buffer CBEND EQU $ ; end of buffer ENDIF END