; FILE NAME: P3.M68 ; DATE: 2/9/87 ; MODIFIED: ; 32 PORT DRIVER ON 1200 3 PORT SEARCH SYS SEARCH SYSSYM SEARCH TRM OBJNAM .IDV PORT0 = ^H0FFFFFE20 ; I/O base for port 0 PORT1 = ^H0FFFFFE24 ; I/O base for port 1 PORT2 = ^H0FFFFFE30 ; I/O base for port 2 PORTB = ^H0FFFFFE28 ; Baud rate generator port INTVCT = ^H06C ; Interrupt vector for port 1 and 2 FTDEBUG=0 ; set to 1 for debug features DEFINE DEBUG ARG IF NE, FTDEBUG MOVB #^H0'ARG,^H0FFFFFE00 ; ENDC ENDM ;Define Miscellaneous Parameters and Constants ;Define 6850 Status Register Bits STRDRF = 0 ; 1 = Receive Data Register Full STTDRE = 1 ; 1 = Transmit Data Register Empty STDCD = 2 ; 1 = DCD bar has gone high (no carrier) STCTS = 3 ; 0 = CTS bar is low (OK to transmit) STFE = 4 ; 1 = Framing Error STOVRN = 5 ; 1 = Overrun Error STPE = 6 ; 1 = Parity Error STIRQ = 7 ; 1 = Interrupt has been requested ;Define 6850 Command Register Bits CMRESET = 3 ; Master Reset for ACIA CM16 = 1 ; Clock is divide by 16 CM7EP2 = 00 ; 7 data bits, 2 stop bit, even parity CM7OP2 = 04 ; 7 data bits, 2 stop bits, odd parity CM7EP1 = 10 ; 7 data bits, 1 stop bit, even parity CM7OP1 = 14 ; 7 data bits, 1 stop bit, odd parity CM8NP2 = 20 ; 8 data bits, 2 stop bits, no parity CM8NP1 = 24 ; 8 data bits, 1 stop bit, no parity CM8EP1 = 30 ; 8 data bits, 1 stop bit, even parity CM8OP1 = 34 ; 8 data bits, 1 stop bit, odd parity CMTXD = 0 ; RTS bar low, transmitter disabled CMTXE = 40 ; RTS bar low, transmitter enabled CMDRTS = 100 ; RTS bar high, transmitter disabled CMBREAK = 140 ; Force break CMRCE = 200 ; Receiver Enabled CLRRTS = ^C140 ; Bit pattern to clear RTS control bits ;Define I/O Port Offsets ;These are defined as offset to the base of the serial port block (i.e., base ;of the board + 4). P.SR = 0 ; Status Register (Input) P.CMD = 0 ; Command Register (Output) P.RCV = 2 ; Receiver Holding Register (Input) P.TXM = 2 ; Tranmitter Holding Register (Output) ; RS232 pin equates RS.PGD = ^H01 ; protective ground RS.TXD = ^H02 ; transmit data RS.RXD = ^H03 ; receive data RS.RTS = ^H04 ; request to send RS.CTS = ^H05 ; clear to send RS.DSR = ^H06 ; data set ready RS.SGD = ^H07 ; signal ground RS.DCD = ^H08 ; receive line signal or data carrier detect RS.009 = ^H09 ; ?? RS.010 = ^H0A ; ?? RS.011 = ^H0B ; ?? RS.SRL = ^H0C ; secondary receive line signal RS.SCT = ^H0D ; secondary clear to send RS.STX = ^H0E ; secondary transmit data RS.TSC = ^H0F ; transmitter signal element timing (DCE) RS.SRX = ^H10 ; secondary receive data RS.RSC = ^H11 ; receiver signal element timing (DCE) RS.018 = ^H12 ; ?? RS.SRT = ^H13 ; secondary request to send RS.DTR = ^H14 ; data terminal ready RS.SQD = ^H15 ; signal quality detector RS.RGI = ^H16 ; ring indicator RS.DSS = ^H17 ; data signal rate selector (DCE/DTE) RS.TST = ^H18 ; transmitter signal element timing (DTE) RS.025 = ^H19 ; ?? ;Driver Commumnications Area ;This is the standard branch table used by TRMDEF and TRMSER. Only TRMDEF ;is allowed to call the initialization routine. AM1: BR CHROUT ; character output routine BR INIT ; initialization routine BR 20$ ; BR 40$ ; 20$: JMP GETPIN ; get status and available pins 40$: JMP SETPIN ; toggle available pins ;CHROUT Output Character Initiation Routine ;Enable the 6850 transmitter which generates an initial interrupt which ;will be dispatched to the transmitter routine, starting the output ;process. This routine is called by clock routine set up by TRMSER. ;Inputs: A5 Pointer to terminal definition block ;Outputs: None ;Modifies: None ; Modified to use the control bits from the INIT routine setup. CHROUT: LEA A6,CBITS0 ; assume port 0, point at control bits MOV T.IHM(A5),D7 ; is it really port 0 ? BEQ 20$ ; yes LEA A6,CBITS1 ; no assume port 1 CMP D7,#1 ; is it really port 1 ? BEQ 20$ ; yes LEA A6,CBITS2 ; no, it's really port 2 ;-- 16 PORT CMP D7,#2 BEQ 20$ JMP CHR16 ; 16 PORT CHROUT ;-------------------------------- 20$: CLR D7 MOVB @A6,D7 ; get the control bits ORB #CMTXE,D7 ; or in transmitter enable bit MOV T.IHW(A5),A6 ; get base address of I/O port MOVB D7,@A6 ; enable the transmitter RTN ;INIT Initialize the AM-100/L Port ;This routine is called by TRMDEF each time a port on the AM-100/L is defined. ;The routine must intialize the proper port to the specified configuration, ;or, if the default is specified, it must set the 100/L up for async 19200 baud ;operation. ;Inputs: D0 Specified baud rate code. ; A5 Points to terminal definition block. ;Outputs: Outputs to 1200 board only. ;Modifies: D1, A3, A4; 1200 command register; ; If D0 is set to a -1 then a routine is calling INIT with the ; following parameters specified at the base of A6. ; word - baud rate, based on BAUDTB ; word - data bits, 5,6,7,8 - 0,1,2,3 ; word - stop bits, 1,1.5,2 - 0,1,2 ; word - parity, none,even,odd - 0,1,3 ; lword - interrupt on specific pin drop INIT: SAVE A0-A6,D0-D7 MOV D0,D1 ; get baud rate index (assume TRMDEF) LEA A4,BAUDTB ; index the baud rate table TST D0 ; called by TRMDEF ? BPL INIT1 ; yes CLR D1 MOVW @A6,D1 ; get baud rate index from parm block MOVW D1,T.BAU(A5) ; save it in TCB INIT1: MOVB 0(A4)[D1],D1 ; is it valid? JMI BDBAUD ; no - invalid baud rate TST T.IHM(A5) ; are we selecting port 0? BEQ 10$ ; yes - ;Set up port 1 baud rate load, I/O port, and interrupt vector MOVB #40,D2 ; no - select port 1 baud rate load MOV #PORT1,A4 ; and I/O port LEA A3,TRMDF1 ; storage for port 1 TCB pointer CMP T.IHM(A5),#1 ; is it port 1? BEQ 20$ ; yes MOVB #300,D2 ; no - select port 2 baud rate load MOV #PORT2,A4 ; and I/O port LEA A3,TRMDF2 ; storage for port 2 TCB pointer ;---------- 16 PORT CMP T.IHM(A5),#2 ; PORT 2 BEQ 20$ JMP INIT16 ; MUST BE 16 PORT ;;; BR 20$ ;----------------------------------- ;Set up port 0 baud rate load, I/O port, and interrupt vector 10$: MOVB #20,D2 ; get port 0 select bit MOV #PORT0,A4 ; index port 0 LEA A3,TRMDF0 ; storage for port 1 TDB pointer 20$: MOV A5,(A3)+ ; save TDB pointer and bump LEA A0,INTRPT ; index port 0 interrupt routine MOV A0,INTVCT ; store it ;Send baud rate code to baud rate generator and reset ACIA ORB D1,D2 ; combine selector code with baud rate MOVB D2,PORTB ; send to baud rate generator MOV A4,T.IHW(A5) ; store I/O addr terminal definition blk MOVB #CMRESET,@A4 ; reset the 6850 ACIA chip ;Set up the ACIA for 16X clock, correct # of stop bits, transmitter disabled, ; and receiver enabled TST D0 ; called by TRMDEF ? BMI 25$ ; no, require special treatment MOVB #CM16!CM8NP1!CMTXD!CMRCE,@A3 CMPB D0,#2 ; did we want 110 baud? JNE 150$ ; no - MOVB #CM16!CM8NP2!CMTXD!CMRCE,@A3 BR 150$ 25$: MOVB #CM16!CMTXD!CMRCE,@A3 ; set default bits MOVW 2(A6),D0 ; read # of data bits from parm block CMPB D0,#2 ; 7 data bits ? BNE 70$ ; no, must be 8 MOVW 4(A6),D0 ; read # of stop bits from parm block BNE 40$ ; must be 2 stop bits MOVW 6(A6),D0 ; read parity bit info BTST #1,D0 ; even parity ? BNE 30$ ; yes ORB #CM7OP1,@A3 ; specify 7 data, odd parity, 1 stop BR 100$ 30$: ORB #CM7EP1,@A3 ; specify 7 data, even parity, 1 stop BR 100$ 40$: MOVW 6(A6),D0 ; read parity bit info BTST #1,D0 ; even parity ? BNE 50$ ; yes ORB #CM7OP2,@A3 ; specify 7 data, odd parity, 2 stop BR 100$ 50$: ORB #CM7EP2,@A3 ; specify 7 data, even parity, 2 stop BR 100$ 70$: MOVW 4(A6),D0 ; read # of stop bits from parm block BNE 90$ ; must be 2 stop bits MOVW 6(A6),D0 ; read parity bit info BTST #0,D0 ; parity ? BNE 80$ ; yes ORB #CM8NP1,@A3 ; specify 8 data, no parity, 1 stop BR 100$ 80$: BTST #1,D0 ; even parity ? BNE 85$ ; yes ORB #CM8OP1,@A3 ; specify 8 data, odd parity, 1 stop BR 100$ 85$: ORB #CM8EP1,@A3 ; specify 8 data, even parity, 1 stop BR 100$ 90$: ORB #CM8NP2,@A3 ; has to be 8 data, no parity, 2 stop 100$: MOV 10(A6),D0 ; interrupt on DCD drop requested ? BTST #RS.DCD,D0 BEQ 150$ ; no MOVB #STDCD,1(A3) ; yes, set it as an interrupt condition 150$: MOVB @A3,@A4 ; set up ACIA INTXIT: REST A0-A6,D0-D7 RTN ; Storage used for external routine setups TRMDF0: LWORD 0 ; storage for port 0 TCB pointer CBITS0: BYTE 0 ; storage for port 0 control reg bits INTCN0: BYTE 0 ; storage for port 0 interrupt contdtn TRMDF1: LWORD 0 ; storage for port 1 TCB pointer CBITS1: BYTE 0 ; storage for port 1 control reg bits INTCN1: BYTE 0 ; storage for port 1 interrupt condtn TRMDF2: LWORD 0 ; storage for port 2 TCB pointer CBITS2: BYTE 0 ; storage for port 2 control reg bits INTCN2: BYTE 0 ; storage for port 2 interrupt condtn ; GETPIN return RS-232 pin status and available ; in : A5 points to terminal definition block ; out : D6 status on pins ; D7 available pins GETPIN: ;------- 16 PORT CMP T.IHM(A5),#2 ; PORT 0,1,2 BLOS 116$ CALL GETP16 RTN ;---------------------------- 116$: PUSH A4 CLR D6 ; clear the port status bits MOV T.IHW(A5),A4 ; get port address MOVB @A4,D7 ; read port status BTST #2,D7 ; DCD present ? BNE 10$ ; no, lost it BSET #RS.DCD,D6 ; say we have DCD 10$: BTST #3,D7 ; do we have CTS ? BNE 20$ ; no BSET #RS.CTS,D6 ; say we have CTS 20$: CLR D7 BSET #RS.CTS, D7 ; obtain status BSET #RS.DCD, D7 ; obtain status BSET #RS.RTS, D7 ; set pin POP A4 RTN ; SETPIN toggle pins based on the RS-232 pin setup ; we can only toggle RTS ; in : D0 pins to toggle ; A5 points to terminal definition block ; out : nothing SETPIN: ;------- 16 PORT CMP T.IHM(A5),#2 ; PORT 0,1,2 BLOS 116$ CALL SETP16 RTN ;---------------------------- 116$: PUSH A4 LEA A6,CBITS0 ; assume port 0 MOV T.IHM(A5),D7 ; is it really port 0 ? BEQ 10$ ; yes LEA A6,CBITS1 ; no assume port 1 CMP D7,#1 ; is it really port 1 ? BEQ 10$ ; yes LEA A6,CBITS2 ; no, it's really port 2 10$: MOV T.IHW(A5),A4 ; get address of port ANDB #CLRRTS,@A6 ; clear RTS control bits BTST #RS.RTS,D0 ; drop or raise RTS ? BNE 20$ ; raise it, bits are already cleared ORB #CMDRTS,@A6 ; drop it 20$: MOVB @A6,@A4 ; send new bit pattern to control reg POP A4 RTN ;INTRn Define Serial Port Routines ;These routines contain code that is modified by the initialization routine. ;Called at interrupt level. ;Inputs: None ;Outputs: A5 Terminal definition block index ;Modifies: A5 ; Modified to test for external routines to call for sending/ ; receiving data, or for testing line drop. INTRPT: SVLOK ; turn off interrupts SAVE A3-A6,D1,D6-D7 ; save registers MOV TRMDF0, A5 ; set channel 1 terminal definition index BTST #STIRQ,PORT0 ; is it really port 1 ? BNE GINTRP ; yes MOV TRMDF1, A5 ; set channel 1 terminal definition index BTST #STIRQ,PORT1 ; is it really port 1 ? BNE GINTRP ; yes MOV TRMDF2, A5 ; set channel 2 terminal definition index ;--- 16 PORT BTST #STIRQ,PORT2 ; PORT 2 BNE GINTRP JMP INT16 ; 16 PORT INT ;-------------------------------- ;GINTRP Handle Serial Port Interrupt ;Come here whenever we get a serial port interrupt. Determine what type it ;is and dispatch to appropriate routine. Called at interrupt level. ;Inputs: A5 Terminal definition index ; All registers SAVEd on stack ;Outputs: D1 6850 Status Register ; A4 Pointer to base of I/O ports ;Modifies: D1, A4 GINTRP: MOV T.IHW(A5),A4 ; get I/O register base into A4 MOVB @A4,D1 ; read the 6850 status register BTST #STRDRF,D1 ; check receiver data register full flag BNE INPR ; and go process if set BTST #STDCD,D1 ; was interrupt caused by DCD drop ? BNE INFI ; yes, go clear interrupt. We don't care ; must be a transmit data reg empty BTST #STTDRE,D1 ; interrupt. Make sure it is empty BNE OUTPR ; yes, it is go get a char to send BR INFI1 ; must be a spurious interrupt, fall ; through to false interrupt routine. ;INFI False Interrupt Routine ;Come here when interrupt was caused by neither transmitter or receiver. ;The interrupt is either DCD change or spurious. In either case, we read ;recieve data register to clear interrupt. ;Inputs: D1 6850 Status Register ; A4 I/O register base address ; All registers SAVEd on stack ;Outputs: None ;Modifies: Restores registers INFI: MOV T.EXC(A5),D7 ; is there an alternate exception routine BEQ INFI1 ; no, just clear interrupt and return MOV D7,A6 ; yes, transfer to an address reg LEA A3,INTCN0 ; no it's port 1, point at intr condtn MOV T.IHM(A5),D7 ; is it really port 0 ? BEQ 10$ ; yes LEA A3,INTCN1 ; no assume port 1 CMP D7,#1 ; is it really port 1 ? BEQ 10$ ; yes LEA A3,INTCN2 ; no, it's really port 2 10$: ANDB @A3,D1 ; any of our interrupt contditions met? BEQ INFI1 ; no, just clear interrupt and return CALL @A6 ; call the alternate routine INFI1: MOVB P.RCV(A4),D1 ; clear 6850 interrupt REST A3-A6,D1,D6-D7 ; restore registers RTE ; return ;INPR Input Character Interrupt Routine ;Come here whenever we get a receiver interrupt. Read the character from ;the AM-100/L and pass on to TRMSER. ;Inputs: A4 I/O register base ; All registers SAVEd on stack ;Outputs: None ;Modifies: Restores registers INPR: MOVB P.RCV(A4),D1 ; read the data character MOV T.INC(A5),D7 ; is there an alternate input routine BEQ 10$ ; no, use TRMICP MOV D7,A6 ; yes, transfer address to address reg CALL @A6 ; call the alternate routine BR INTX 10$: TRMICP ; go process the character INTX: REST A3-A6,D1,D6-D7 ; restore registers RTE ;OUTPR Transmitter Interrupt Routine ;Come here on a transmitter interrupt. If another character is available ;for output, grab it and send it to the 6850. ;Otherwise, clear the OIP flag and dismiss interrupt. ;Inputs: D1 6850 Status Register ; A4 I/O register base address ; A5 Terminal definition index ; All registers SAVEd on the stack ;Outputs: Only to AM-100/L ;Modifies: Registers restored OUTPR: MOV T.OTC(A5),D7 ; is there an alternate output routine BEQ 5$ ; no use TRMOCP MOV D7,A6 ; yes, transfer address to address reg CALL @A6 ; call the alternate routine BR 7$ 5$: TRMOCP ; get next output character from TRMSER 7$: TST D1 ; data available? BPL OPRG ; yes - ANDW #^C,@A5 ; no - clear the OIP flag LEA A6,CBITS0 ; assume port 0 MOV T.IHM(A5),D7 ; is it really port 0 ? BEQ 8$ ; yes LEA A6,CBITS1 ; no assume port 1 CMP D7,#1 ; is it really port 1 ? BEQ 8$ ; yes LEA A6,CBITS2 ; no, it's really port 2 8$: MOVB @A6,@A4 ; get the control bits OPRD: BR INTX ; return ;Send character to transmitter OPRG: MOVB D1,P.TXM(A4) ; send character to 6850 BR INTX ; return ;Come here if an invalid baud rate was specified BDBAUD: TYPECR RTN ; just ignore initialization ;Define baud rate table BAUDTB: BYTE 0 ; 50 baud BYTE 1 ; 75 baud BYTE 2 ; 110 baud BYTE 3 ; 134.5 baud BYTE 4 ; 150 baud BYTE -1 ; 200 baud (not valid on 1941-05) BYTE 5 ; 300 baud BYTE 6 ; 600 baud BYTE 7 ; 1200 baud BYTE 10 ; 1800 baud BYTE 11 ; 2000 baud BYTE 12 ; 2400 baud BYTE 13 ; 3600 baud BYTE 14 ; 4800 baud BYTE 15 ; 7200 baud BYTE 16 ; 9600 baud BYTE 17 ; 19200 baud EVEN ;------------------ 16PORT ---------------- ; 16 PORT DRIVER FOR 1200 IOPRT0 = ^H0FFFFE0 ; FIRST 16 PORTS IOPRT1 = ^H0FFFFC0 ; 2ND 16 PORTS INTP0 = ^H0FFFFE4 INTP1 = ^H0FFFFC4 ;Define 2681 Command Register Bits CM$RMRP = 20 ; Reset mode register pointer CM$RRCV = 40 ; Reset receiver CM$RTXM = 60 ; Reset transmitter CM$REST = 100 ; Reset error status CM$RXEN = 1 ; Receiver enable CM$RXDI = 2 ; Receiver disable CM$TXEN = 4 ; Transmitter enable CM$TXDI = 10 ; Transmitter disable ; Define 2681 Mode Register 1 bits M1$8B = 3 ; 8 bits per character M1$NP = 20 ; No parity ; Define 2681 Mode Register 2 bits M2$1SB = 7 ; 1 stop bit M2$2SB = 17 ; 2 stop bits M2$NM = 0 ; Normal channel mode M2$CET = 20 ; CTS enables transmitter ; Define 2681 Interrupt Mask Register bits IM$TXRD = 1 ; Interrupt on transmitter ready IM$RXRD = 2 ; Interrupt on receiver ready ; Define 2681 Interrupt Status Register bits IS$TRA = 1 ; Transmitter ready A IS$RRA = 2 ; Receiver ready A IS$TRB = 20 ; Transmitter ready B IS$RRB = 40 ; Receiver ready B ;Define I/O Port Offsets ;These are defined as offset to the base of the serial port block. P.MDR = 0 ; Mode Register (Input & Output) P.SR = 1 ; Status Register (Input) P.CLK = 1 ; Clock Select Register (Output) P.CMR = 2 ; Command Register (Output) P.RCV = 3 ; Receiver Holding Register (Input) P.TXM = 3 ; Tranmitter Holding Register (Output) P.ACR = 4 ; Auxiliary Control Register (Output) P.ISR = 5 ; Interrupt Status Register (Input) P.IMR = 5 ; Interrupt Mask Register (Output) P.OCR = 15 ; Output port configuration register(Output) P.SOB = 16 ; Set output port bits register(Output) P.ROB = 17 ; Reset output port bits register(Output) ;This is the standard branch table used by TRMDEF and TRMSER. Only TRMDEF ;is allowed to call the initialization routine. ;Output Character Initiation Routine ;ENTER WITH A5->TERMINAL DEFINITION BLOCK CHR16: SAVE D0-D1 MOV T.IHM(A5),D0 ; GET PORT NUM SUB #3,D0 ; 0,1,2 FOR 1200 PORTS LEA A6,P0MASK ; PORT INITED INDICATOR BTST #4,D0 ; 1ST OR 2ND BANK BEQ CHRB0 LEA A6,P1MASK CHRB0: ANDB #^H0F,D0 MOVW @A6,D1 ; GET PREVIOUS INITED PORTS BTST D0,D1 ; HAS CHANNEL BEEN INITED JEQ IGNXIT ; NOPE CALL WZ80 ; WAIT FOR Z80 INT TO BE SERVICED JEQ IGNXIT ; NOT READY, T/O MOV T.IHM(A5),D0 ; GET PORT NUM SUB #3,D0 MOV #IOPRT0,A6 ; DATA PORT NUM BTST #4,D0 ; 2ND BANK? BEQ BNK0 MOV #IOPRT1,A6 BNK0: ANDB #^H0F,D0 ORW #^H0FF00,D0 ; XMIT & RCV ENABLE = FF,,PORT NUM MOVW D0,@A6 IGNXIT: REST D0-D1 RTN ;--------- WAIT FOR Z80 INT TO BE SERVICED ------ WZ80: SAVE D1,D7 MOVW #^H100,D7 ; DONT WAIT FOREVER SW0: MOV #INTP0,A6 ; WAIT FOR INT ON Z80 TO BE SERVICED MOVW @A6,D1 ; MUST BE WORD MOVE BTST #0,D1 ; 0->INT ACTIVE BEQ SW0 SW1: MOV #INTP1,A6 MOVW @A6,D1 BTST #0,D1 BEQ SW1 ;;; DBNE D7,SWAIT REST D1,D7 RTN ; RET ZF=1 IF T/O ;Initialize the PI-1016 Port ; ENTER WITH D0 = BAUD RATE INDICATOR ; A5 -> terminal definition block. ; ENTER WITH A0-A6,D0-D6 ON STACK INIT16: CMP D0,#18. JHIS BAUDER ; RATES SUPPORTED = 0..17 LEA A0,INTRPT ; index port 0 interrupt routine MOV A0,INTVCT ; store it LEA A0,AMALIV ; IF FIRST CALL, THEN INIT ALL PORTS TSTB @A0 BNE NOTFST MOVB #-1,@A0 MOV #^H0FFFFE6,A0 ININXT: MOVB #0,@A0 ; RESET Z80 MOVW #-2,D1 10$: DBF D1,10$ 20$: DBF D1,20$ MOVB #-1,@A0 ; RELEASE Z80 30$: DBF D1,30$ 40$: DBF D1,40$ CMP A0,#^H0FFFFE6 BNE NOTFST MOV #^H0FFFFC6,A0 BR ININXT NOTFST: LEA A0,P0MASK ; PORT INITED INDICATOR MOV T.IHM(A5),D1 ; GET PORT NUMBER SUB #3,D1 BTST #4,D1 ; 2ND BANK? BEQ IB0 LEA A0,P1MASK IB0: MOVW @A0,D2 ; GET PREVIOUS INITED PORTS ANDB #^H0F,D1 XORB #1,D1 ; GET OTHER CHANNEL BTST D1,D2 ; HAS OTHER CHANNEL BEEN INITED JEQ NEWINI ; NOPE MOV T.IHM(A5),D1 ; GET PORT NUMBER SUBB #3,D1 XORB #1,D1 LEA A0,BVAL ; GET BAUD VALUE USED ON OTHER PORT CLR D3 MOVB 0(A0)[D1],D3 BTST #7.,D3 ; ACR=1? JEQ TRYB0 TRYB1: LEA A0,BAUD1 ; index the baud rate table ACR=1 MOVB 0(A0)[D0],D4 ; Is it a valid baud rate ? CMPB D4,#-1 BEQ CHGB0 ; no - invalid baud rate BCLR #7,D3 MOVB 0(A0)[D3],D4 ; OTHER CHANNEL ALSO SUPPORTED CMPB D4,#-1 BEQ CHGB0 BSET #7.,D0 ; USE ACR=1 JMP SBAUD CHGB0: ; TRY TO CHANGE TO ACR=0 LEA A0,BAUD0 MOVB 0(A0)[D0],D4 ; BOTH BAUD RATES DEFNED CMPB D4,#-1 JEQ BAUDER BCLR #7,D3 MOVB 0(A0)[D3],D4 CMPB D4,#-1 JEQ BAUDER SAVE D0,A5 ; RESET BAUD RATE ON OTHER CHANEL MOV D3,D0 ; OLD BAUD RATE LEA A0,TCB0 MOV T.IHM(A5),D1 ; GET PORT NUMBER SUBB #3,D1 XORB #1,D1 LSL D1,#2 ; PORT NUM * 4 FOR LWORD OFFSET MOV 0(A0)[D1],A5 ; PNTR TO OTHER CHAN TRM DEF BLK BCLR #7.,D0 ; USE ACR=0 CALL PINIT ; INIT OTHER CHANNEL REST D0,A5 JMP SBAUD TRYB0: LEA A0,BAUD0 ; INDEX BAUD RATE TABLE ACR=0 MOVB 0(A0)[D0],D4 CMPB D4,#-1 BEQ CHGB1 BCLR #7,D3 MOVB 0(A0)[D3],D4 CMPB D4,#-1 JNE SBAUD ; SET BAUD RATE TO ACR=0 CHGB1: ; TRY TO CHANGE TO ACR=1 LEA A0,BAUD1 MOVB 0(A0)[D0],D4 ; BOTH BAUD RATES DEFNED CMPB D4,#-1 JEQ BAUDER BCLR #7,D3 MOVB 0(A0)[D3],D4 CMPB D4,#-1 JEQ BAUDER SAVE D0,A5 ; RESET BAUD RATE ON OTHER CHANEL MOV D3,D0 ; OLD BAUD RATE BSET #7.,D0 ; INDICATE THAT PORT HAS ACR=1 LEA A0,TCB0 MOV T.IHM(A5),D1 ; GET PORT NUMBER SUBB #3,D1 XORB #1,D1 LSL D1,#2 ; PORT NUM * 4 FOR LWORD OFFSET MOV 0(A0)[D1],A5 ; PNTR TO OTHER CHAN TRM DEF BLK CALL PINIT ; INIT OTHER CHANNEL REST D0,A5 BSET #7.,D0 ; USE ACR=1 ON NEW PORT JMP SBAUD BAUDER: TYPECR ERRXIT: REST A0-A6,D0-D7 RTN NEWINI: LEA A0,BAUD1 ; index the baud rate table ACR=1 MOVB 0(A0)[D0],D4 ; Is it a valid baud rate ? CMPB D4,#-1 JEQ NOTB0 BSET #7.,D0 ; SET ACR=1 JMP SBAUD NOTB0: LEA A0,BAUD0 ; INDEX BAUD RATE TABLE ACR=0 MOVB 0(A0)[D0],D4 CMPB D4,#-1 JEQ BAUDER ;--- ENTER WITH D0 BITS 0..6=BAUD RATE CODE, D0 B7 = ACR ; A5 -> TRMDEF BLK SBAUD: ; Get port number and base addresses of DUART and channel PINIT: LEA A0,BAUD0 MOV D0,D3 CLR D6 BCLR #7.,D0 ; BAUD1? BEQ ACR0 LEA A0,BAUD1 MOVB #^H80,D6 ; ACR VALUE ACR0: ADD D0,A0 ; OFFSET TO BAUD RATE INIT VALUE MOV T.IHM(A5),D2 ; use port # as displacement SUB #3,D2 LEA A1,BVAL ; SAVE BAUD RATE VALUE ON CURR PORT MOVB D3,0(A1)[D2] MOV D2,D4 ; keep a copy CLR D3 BCLR #0,D2 ; EVEN OR ODD PORT BEQ EADDR MOV #8.,D3 ; BASE ADDR OF CHANNEL EADDR: ANDB #^H0F,D2 LSL D2,#3 ; BASE ADDR OF UART = 8*PORT NUM ORB #^H80,D2 ADD D2,D3 ; Set D2 to base of DUART ; set D3 to base of specific channel LSL D2,#8. ; PUT ADDR IN HI BYTE LSL D3,#8. ; Set up baud rate MOV #IOPRT0,A2 ; DATA/STATUS PORT BTST #4,D4 BEQ LOWBNK MOV #IOPRT1,A2 LOWBNK: MOVW D2,D5 ADDW #,D5 MOVB D6,D5 ; TABLE SELECT CODE MOVW D5,@A2 ; Send table select code CALL WZ80 JEQ Z80ERR MOVB @A0,D1 ; Get baud rate code ROLB D1,#4 ; Shift to receiver select bits ORB @A0,D1 ; or int transmit clock select bits MOVW D3,D5 ADDW #,D5 MOVB D1,D5 MOVW D5,@A2 ; Send to proper channel CALL WZ80 JEQ Z80ERR ; Reset everything MOVW D3,D5 ADD #,D5 MOVB #CM$RMRP,D5 MOVW D5,@A2 CALL WZ80 JEQ Z80ERR MOVB #CM$RRCV,D5 MOVW D5,@A2 CALL WZ80 JEQ Z80ERR MOVB #CM$RTXM,D5 MOVW D5,@A2 CALL WZ80 JEQ Z80ERR MOVB #CM$REST,D5 MOVW D5,@A2 CALL WZ80 JEQ Z80ERR MOVW D3,D5 ADDW #,D5 MOVB #M1$8B!M1$NP,D5 ; Set up mode register 1 MOVW D5,@A2 CALL WZ80 JEQ Z80ERR ; MOVB #M2$1SB!M2$NM,D5 ; Set up for mode register 2 ; CMPB D0,#4 ; Did we want 110 baud ; BNE 30$ MOVB #M2$2SB!M2$NM,D5 ; Set to two stop bits 30$: MOVW D5,@A2 ; Set up mode register 2 CALL WZ80 JEQ Z80ERR MOVW D3,D5 ADDW #,D5 MOVB #CM$RXDI!CM$TXDI,D5 ; Temporarily disable RCV AND XMIT MOVW D5,@A2 CALL WZ80 JEQ Z80ERR MOVW D2,D5 ADDW #,D5 CLRB D5 ; NO INTS ENABLED ON UART BTST #11.,D3 ; CHANNEL A ? BEQ 40$ ; GO IF TRUE ROLB D5,#4 ; SHIFT UP FOR CHANNEL B 40$: LEA A0,IMSK0 ; BASE ADDRESS OF IMR BYTE TABLE MOV D4,D0 ; SAVE CHANNEL NUM LSR D4,#1 ; INDEX CORRECT MASK REGISTER ADD D4,A0 ORB D5,@A0 ; ADD TO EXISTING MASK VALUE MOVB @A0,D5 ; D1 REFLECTS BOTH CHANNELS MOVW D5,@A2 ; PROGRAM DUART CALL WZ80 JEQ Z80ERR ; Now enable DTR & RTS MOVW D2,D5 ADDW #,D5 MOVB #5,D5 ; SET UP CHANNEL A BTST #11.,D3 ; TEST IF CHANNEL B BEQ 50$ MOVB #22,D5 ; SET UP CHANNEL B 50$: LEA A0,OBIT0 ; BASE ADDRESS OF OUTPUT BYTE TABLE ADD D4,A0 ORB D5,@A0 ; ADD TO EXISTING BIT PATTERN MOVB @A0,D5 ; D1 REFLECTS BOTH CHANNELS MOVW D5,@A2 ; SET BITS ON CALL WZ80 JEQ Z80ERR MOVW D2,D5 ADDW #,D5 MOVW D5,@A2 ; SET UP OPR CALL WZ80 JEQ Z80ERR ; SET LOCAL MEMORY FLAGS AND POINTERS LEA A0,P0MASK ; PORT INITED INDICATOR BTST #3,D4 ; PORT/2 BEQ 10$ LEA A0,P1MASK 10$: MOVW @A0,D2 ; GET PROVIOUS INITED PORTS MOVB D0,D4 ANDB #^H0F,D0 BSET D0,D2 ; MARK CURRENT PORT AS INITED MOVW D2,@A0 ; SAVE INDICATOR LSL D4,#2 ; INDEX LONG WORDS LEA A0,TCB0 ADD D4,A0 MOV A5,@A0 ; SAVE TRMDEF BLOCK ADDRESS MOV D3,T.IHW(A5) ; SAVE DUART ADDRESS IN TRMDEF BLOCK MOVW D3,D5 ADDW #,D5 MOVB #CM$RXEN!CM$TXEN,D5 MOVW D5,@A2 ; ENABLE RECEIVER AND XMITTER CALL WZ80 JEQ Z80ERR ; MOV T.IHM(A5),D0 ; GET PORT NUM ; SUB #3,D0 ; ANDW #^H0F,D0 ; ORW #^H0FF10,D0 ; ENABLE RCV DISABLE XMIT ; MOVW D0,@A2 ; CALL WZ80 Z80ERR: ; CAN'T TALK TO Z80 REST A0-A6,D0-D7 RTN ; GETPIN return RS-232 pin status and available ; ; in : A5 points to terminal definition block ; ; out : D6 status on pins ; D7 available pins GETP16: CLR D6 ; clear the port status bits BSET #RS.DCD,D6 ; say we have DCD BSET #RS.CTS,D6 ; say we have CTS CLR D7 BSET #RS.CTS, D7 ; obtain status BSET #RS.DCD, D7 ; obtain status BSET #RS.RTS, D7 ; set pin RTN ; SETPIN toggle pins based on the RS-232 pin setup ; we can only toggle RTS ; ; in : D0 pins to toggle ; A5 points to terminal definition block ; out : nothing SETP16: RTN ;--------- INTERRUPT SERVICE ROUTINE ------- ; INTRPT ; Come here via INTERRUPT vector to process all PM-1016 INTERRUPTs. INT16: ; SAVE A3-A6,D1,D6-D7 ; save registers MOV #INTP0,A4 MOVW @A4,D1 ; IS INT ACTIVE ON BANK 0 LEA A3,P0MASK MOV #IOPRT0,A4 ; INPUT PORT BTST #1,D1 BNE DP0 MOV #INTP1,A4 ; IS INT ACTIVE ON BANK 1 MOVW @A4,D1 LEA A3,P1MASK MOV #IOPRT1,A4 ; INPUT PORT BTST #1,D1 JEQ FLSINT DP0: CLR D1 MOVW @A4,D1 MOV D1,D6 ; SAVE DATA BYTE LSR D6,#8. ; MOVE PORT NUM TO LOW BYTE CMPB D6,#^H0FF ; XMIT INT? JNE NOXMIT CLR D7 AND #^H0FF,D1 BSET D1,D7 CMP A4,#IOPRT1 ; SERVICING BANK1 BNE SERVB0 ADD #^H10,D1 ; 2ND BANK SERVB0: LEA A5,TCB0 LSL D1,#2 ; LONG WORD OFFSET MOV 0(A5)[D1],D1 ; TCB PNTR, USE D0 TO SET FLAGS MOV D1,A5 JEQ FLSINT ANDW @A3,D7 JEQ FLSINT TRMOCP ; get next output character from TRMSER MOV T.IHM(A5),D7 SUB #3,D7 TST D1 ; data available? BPL OPRG7 ; yes - ANDW #^C,@A5 ; no - clear the OIP flag CALL WZ80 ANDW #^H0F,D7 ; PORT NUM ORW #^H0FC00,D7 ; DISABLE XMIT MOVW D7,@A4 ; DISABLE XMIT INT JMP INT16 ; RETRY ;Send character to transmitter OPRG7: AND #^H0F,D7 ; CLEAR PORT NUM LSL D7,#8. ; PORT NUM INTO HI BYTE OF LOW WRD MOVB D1,D7 ; SET PORT NUM IN WORD TO XMIT CALL WZ80 ; MAKE SURE Z80 NOT IN INT ROUTINE MOVW D7,@A4 ; send character to 16 PORT JMP INT16 ;--------- RECEIVE FROM TERMINAL ------ NOXMIT: CLR D7 AND #^H0FF,D6 ; GET PORT NUM BSET D6,D7 CMP A4,#IOPRT1 ; SERVICING BANK1 BNE READB0 ADD #^H10,D6 ; 2ND BANK READB0: LEA A5,TCB0 LSL D6,#2 ; LONG WORD OFFSET MOV 0(A5)[D6],D6 ; TCB PNTR, USE D0 TO SET FLAGS MOV D6,A5 BEQ FLSINT ANDW @A3,D7 BEQ FLSINT ;Input Character Interrupt Routine ; ;Come here whenever we get a receiver interrupt. Read the character from ;the PM-1016 and pass on to TRMSER. ; ;ENTER WITH D1 = INPUT BYTE ; A5 TRMDEF BLOCK PNTR ; All registers SAVEd on stack TRMICP ; go process the character JMP INT16 ; REST A3-A6,D1,D6-D7 ; RTE FLSINT: ;-------------------------------- ; MOV #PORT1,A4 ; get I/O register base into A4 ; MOVB @A4,D1 ; read the 6850 status register ; BTST #STTDRE,D1 ; interrupt. Make sure it is empty ; BEQ FLSINT ; yes, it is go get a char to send ; MOV #IOPRT0,A3 ; MOVW @A3,D1 ; CMPB D1,#^H0FF ; BNE NOTFF ; LSR D1,#8. ;NOTFF: ; MOVB D1,P.TXM(A4) ; send character to 6850 ; ;--------------------------- REST A3-A6,D1,D6,D7 ; restore registers RTE ; BAUD RATE TABLE BAUD1: ; ACR BIT 7 = 1 BYTE -1 ; 50 baud BYTE 0 ; 75 baud BYTE 1 ; 110 baud BYTE 2 ; 134.5 baud BYTE 3 ; 150 baud BYTE -1 ; 200 baud BYTE 4 ; 300 baud BYTE 5 ; 600 baud BYTE 6 ; 1200 baud BYTE 12 ; 1800 baud BYTE 7 ; 2000 baud BYTE 10 ; 2400 baud BYTE -1 ; 3600 baud BYTE 11 ; 4800 baud BYTE -1 ; 7200 baud BYTE 13 ; 9600 baud BYTE 14 ; 19200 baud BYTE -1 ; 38400 baud BYTE 0 BAUD0: ; ACR = 0 BYTE 0 ; 0 = 50 baud BYTE -1 ; 1 = 75 baud BYTE 1 ; 2 = 110 baud BYTE 2 ; 3 = 134.5 baud BYTE -1 ; 4 = 150 baud BYTE 3 ; 5 = 200 baud BYTE 4 ; 6 = 300 baud BYTE 5 ; 7 = 600 baud BYTE 6 ; 8 = 1200 baud BYTE -1 ; 9 = 1800 baud BYTE -1 ; 10 = 2000 baud BYTE 10 ; 11 = 2400 baud BYTE -1 ; 12 = 3600 baud BYTE 11 ; 13 = 4800 baud BYTE 12 ; 14 = 7200 baud BYTE 13 ; 15 = 9600 baud BYTE -1 ; 16 = 19200 baud BYTE 14 ; 17 = 38400 baud BYTE 0 ; 18 USED FOR UN-INITED PORTS EVEN TCB0: LWORD 0 ; POINTER TO TRMDEF BLOCKS TCB1: LWORD 0 TCB2: LWORD 0 TCB3: LWORD 0 TCB4: LWORD 0 TCB5: LWORD 0 TCB6: LWORD 0 TCB7: LWORD 0 TCB8: LWORD 0 TCB9: LWORD 0 TCBA: LWORD 0 TCBB: LWORD 0 TCBC: LWORD 0 TCBD: LWORD 0 TCBE: LWORD 0 TCBF: LWORD 0 TCB10: LWORD 0 ; POINTER TO TRMDEF BLOCKS TCB11: LWORD 0 TCB12: LWORD 0 TCB13: LWORD 0 TCB14: LWORD 0 TCB15: LWORD 0 TCB16: LWORD 0 TCB17: LWORD 0 TCB18: LWORD 0 TCB19: LWORD 0 TCB1A: LWORD 0 TCB1B: LWORD 0 TCB1C: LWORD 0 TCB1D: LWORD 0 TCB1E: LWORD 0 TCB1F: LWORD 0 P0MASK: WORD 0 ; PORT INITIALIZATION INDICATOR P1MASK: WORD 0 IMSK0: BYTE 0 IMSK1: BYTE 0 ; INTERRUPT MASK REGISTERS IMSK2: BYTE 0 IMSK3: BYTE 0 IMSK4: BYTE 0 IMSK5: BYTE 0 IMSK6: BYTE 0 IMSK7: BYTE 0 IMSK8: BYTE 0 IMSK9: BYTE 0 IMSKA: BYTE 0 IMSKB: BYTE 0 IMSKC: BYTE 0 IMSKD: BYTE 0 IMSKE: BYTE 0 IMSKF: BYTE 0 IMSK10: BYTE 0 IMSK11: BYTE 0 ; INTERRUPT MASK REGISTERS IMSK12: BYTE 0 IMSK13: BYTE 0 IMSK14: BYTE 0 IMSK15: BYTE 0 IMSK16: BYTE 0 IMSK17: BYTE 0 IMSK18: BYTE 0 IMSK19: BYTE 0 IMSK1A: BYTE 0 IMSK1B: BYTE 0 IMSK1C: BYTE 0 IMSK1D: BYTE 0 IMSK1E: BYTE 0 IMSK1F: BYTE 0 OBIT0: BYTE 0 OBIT1: BYTE 0 ; OUTPUT PORT BITS OBIT2: BYTE 0 OBIT3: BYTE 0 OBIT4: BYTE 0 OBIT5: BYTE 0 OBIT6: BYTE 0 OBIT7: BYTE 0 OBIT8: BYTE 0 OBIT9: BYTE 0 OBITA: BYTE 0 OBITB: BYTE 0 OBITC: BYTE 0 OBITD: BYTE 0 OBITE: BYTE 0 OBITF: BYTE 0 OBIT10: BYTE 0 OBIT11: BYTE 0 ; OUTPUT PORT BITS OBIT12: BYTE 0 OBIT13: BYTE 0 OBIT14: BYTE 0 OBIT15: BYTE 0 OBIT16: BYTE 0 OBIT17: BYTE 0 OBIT18: BYTE 0 OBIT19: BYTE 0 OBIT1A: BYTE 0 OBIT1B: BYTE 0 OBIT1C: BYTE 0 OBIT1D: BYTE 0 OBIT1E: BYTE 0 OBIT1F: BYTE 0 BVAL: BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 AMALIV: BYTE 0 EVEN END .