;AM1006 Serial Port Interface Driver for the AM-1006 ; ; ASL-xxxxx-xx ; NOTICE ; ;All rights reserved. This software is the property of Alpha Microsystems ;and the material contained herein is the proprietary property and trade ;secrets of Alpha Microsystems, embodying substantial creative efforts and ;confidential information, ideas and expressions, no part of which may be ;reproduced or transmitted in any form or by any means, electronic, ;mechanical, or otherwise, including photocopying or input into any ;information storage or retrieval system without the express written ;permission of Alpha Microsystems. ; ;CAUTION: Unauthorized distribution or reproduction of this material may ;subject you to legal action. ; ; ;This interface driver supports the 4/8 serial ports contained on the ;AM-1006 CPU board. Unlike the AM-100t ports, they have full modem ;(and therefore printer) control. ; ;Ports are addressed in the TRMDEF statement as 0 thru 7. ; ;Edit History: ; ; modify September 1985 by Tan Nguyen at the House of Reps. to have full ; individual port programable. SEARCH SYS SEARCH SYSSYM SEARCH TRM OBJNAM AM1006.IDV PAGE ;Define Miscellaneous Parameters and Constants ; ;Define 2681 Status Register Bits ST$RDRF = 0 ; 1 = Receive Data Register Full ST$FFUL = 1 ; 1 = FIFO full ST$TRDY = 2 ; 1 = Transmit holding register empty ST$EMT = 3 ; 0 = Transmit shift register empty ST$OVRN = 4 ; 1 = Overrun error ST$PRER = 5 ; 1 = Parity error ST$FRER = 6 ; 1 = Framing error ST$RCBR = 7 ; 1 = Received break ;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$RBCI = 120 ; Reset break change interrupt CM$STBR = 140 ; Start break CM$SPBR = 160 ; Stop break 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$5B = 0 ; 5 bits per character M1$6B = 1 ; 6 bits per character M1$7B = 2 ; 7 bits per character M1$8B = 3 ; 8 bits per character M1$PO = 4 ; Parity Odd M1$PE = 0 ; Parity Enable M1$FP = 10 ; Force parity M1$NP = 20 ; No parity M1$SM = 30 ; Special parity mode M1$IF = 100 ; Interrupt on FIFO full ; 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 M2$RTS = 40 ; Transmitter RTS control M2$AE = 100 ; Auto echo mode M2$LL = 200 ; Local loop mode M2$RL = 300 ; Remote loop mode PAGE ; 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) PAGE ;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 NOP CHROUT: JMP CHROT ;CHROT Output Character Initiation Routine ; ;Enable the 2681 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: A6 CHROT: SAVE A6 MOV T.IHW(A5),A6 ; Get base address of DUART MOVB #CM$RXEN!CM$TXEN,P.CMR(A6); Enable transmitter REST A6 RTN PAGE ;INIT Initialize the AM-1006 Port ; ;This routine is called by TRMDEF each time a port on the AM-1006 is defined. ;The routine must intialize the proper port to the specified configuration, ;or, if the default is specified, it must set the 1006 up for async 19200 baud ;operation. ; ;Inputs: D0 Specified baud rate code. ; A5 Points to terminal definition block. ; ;Outputs: Outputs to 1006 board only. ; ;Modifies: D1, A2, A3, A4; 1006 command register; ; Get baud rate code INIT: LEA A6,BAUDTB ; index the baud rate table ROLB D0,#1 ; Shift to word offset MOVB 0(A6)[D0],D1 ; Get first byte of baud rate code CMPB D1,#-1 ; Is it a valid baud rate ? JEQ BDBAUD ; no - invalid baud rate ; Get port number and base addresses of DUART and channel LEA A3,DUART1 ; get base of DUART address table MOV T.IHM(A5),D2 ; use port # as displacement MOV D2,D3 ; keep a copy ANDB #06,D2 ; Reset bit 0, dont care channl A or B ASL D2,#1 ; double for long word increments MOV 0(A3)[D2],A2 ; Set A2 to base of DUART MOV A2,A4 ; set A4 to base of specific channel BTST #0,D3 ; port # indicates channel A or B BEQ 10$ ; channel A ADD #10,A4 ; channel B ; Set up baud rate 10$: MOVB D1,P.ACR(A2) ; Send table select code INC A6 ; Bump pointer MOVB 0(A6)[D0],D1 ; Get baud rate code ROLB D1,#4 ; Shift to receiver select bits ORB 0(A6)[D0],D1 ; or int transmit clock select bits MOVB D1,P.CLK(A4) ; Send to proper channel ; Reset everything MOVB #CM$RMRP,P.CMR(A4) MOVB #CM$RRCV,P.CMR(A4) MOVB #CM$RTXM,P.CMR(A4) MOVB #CM$REST,P.CMR(A4) MOVB P.SR(A4),D1 ; Look at status reg CMPB D1,#^H0FF ; If not there, should read FF JEQ NOPORT ; If there, should be cleared ;*************************************************************************** ; removed the section below (comments out) (TNN) tannguyen ; MOVB #M1$8B!M1$NP,P.MDR(A4) ; Set up mode register 1 (TNN) ; MOVB #M2$1SB!M2$NM!M2$CET,D1 ; Set up for mode register 2 (TNN) ; CMPB D0,#4 ; Did we want 110 baud (TNN) ; BNE 30$ (TNN) ; MOVB #M2$2SB!M2$NM!M2$CET,D1 ; Set to two stop bits (TNN) ;30$: (TNN) ; MOVB D1,P.MDR(A4) ; Set up mode register 2 (TNN) ;*************************************************************************** ;*************************************************************************** ; added this section below (TNN) ; ;*****************MODIFICATION FOR AM1006 STARTS HERE** (TNN) *************** ; INSERT THIS SECTION AND DELETE THE PREVIOUS SET MODE STATEMENTS ; PLEASE ALSO REFER TO THE PROGRAM ATTACHED ON [100,53] ON AMUS - ; BLKINP.M68 PASWOR.BAS ; ;This gets the mode registers from the tables. all you want to do when ;you assign different mode to any port (e.g, port 0=8bit,none parity ;port 7 7 bit odd parity,etc.) is set the table accordingly ; SETMOD: LEA A6,MR1TAB ;get mode reg. 1 table MOVB 0(A6)[D3],D1 ;get the mode for this port MOVB D1,P.MDR(A4) ;SET IT LEA A6,MR2TAB ;same thing for reg 2 MOVB 0(A6)[D3],D1 ;get mode for this port MOVB D1,P.MDR(A4) ;set it ;done ;******************END OF MOD FOR AM1006 ENDS HERE (TNN)********************** MOVB #CM$RXDI!CM$TXDI,P.CMR(A4) ; Temporarily disable interupts CLR D1 MOVB #IM$TXRD!IM$RXRD,D1 CLR D1 MOVB #IM$TXRD!IM$RXRD,D1 ; Allow interrupts BTST #0,D3 ; channel A ? BEQ 40$ ; yes ROLB D1,#4 ; Shift for channel B 40$: LEA A6,IMASK1 ; Base address of IMR byte table MOV D3,D2 ; Get another copy ASR D2,#1 ; Index OPBIT table ORB D1,0(A6)[D2] ; Set new bit pattern for given DUART MOVB 0(A6)[D2],D1 ; Make sure D1 reflects both channels MOVB D1,P.IMR(A2) ; Send to DUART ; Now enable DTR & RTS MOVB #5,D1 ; Set up for channel A BTST #0,D3 ; See if channel B BEQ 50$ ; Nope MOVB #22,D1 ; Set to channel B 50$: LEA A6,OPBIT1 ; Base address of output byte table ORB D1,0(A6)[D2] ; Set new pattern for given DUART MOVB 0(A6)[D2],D1 ; Make sure D1 reflects both channels MOVB D1,P.SOB(A2) ; Set bits on MOVB #0,P.OCR(A2) ; Send to the DUART ; SET LOCAL MEMORY FLAGS AND POINTERS LEA A0,PORTS ; index port initialization indicator BSET D3,@A0 ; mark this port as initialized ASL D3,#2 ; times 4 to index long words LEA A3,TRMDF0 ; get beginning of TRMDEF table MOV A5,0(A3)[D3] ; store pointer to TRMDEF block in tbl MOV A4,T.IHW(A5) ; Save I/O address in terminal def blk LEA A0,INTRPT ; Get addr of interrupt dispatch MOV A0,INTVEC ; Save in autovector MOVB #CM$RXEN,P.CMR(A4) ; Enable receiver interupts RTN BDBAUD: TYPECR RTN ; just ignore initialization NOPORT: TYPECR RTN PAGE ; INTRPT ; Come here via INTERRUPT vector to process all AM-1006 INTERRUPTs. ; ; Inputs: None ; ; Outputs: None ; ; Modifies: A0,A2,A5,D1 INTRPT: SVLOK ; Lock all interrupts SAVE A0-A6,D0-D7 ; Save all registers MOV #INTADD,A0 ; Index the interrupt port MOVB @A0,D1 ; read INTERRUPT byte BTST #IOINT1,D1 ; Duart 1 I/O (receive/trans) INTERRUPT? BEQ IOSRV1 ; yes, go service it BTST #IOINT2,D1 ; Duart 2 ? BEQ IOSRV2 ; BTST #IOINT3,D1 ; Duart 3 ? JEQ IOSRV3 ; BTST #IOINT4,D1 ; Duart 4 ? JEQ IOSRV4 ; BTST #TIMR1I,D1 ; accidental timer INTERRUPT DUART 1 ? JEQ TIMR1S ; yes, go turn it off BTST #TIMR2I,D1 ; DUART 2 ? JEQ TIMR2S ; BTST #TIMR3I,D1 ; DUART 3 ? JEQ TIMR3S ; BTST #TIMR4I,D1 ; DUART 4 ? JEQ TIMR4S ; BADINT: REST A0-A6,D0-D7 ; Restore registers RTE ; Return from exception IOSRV1: MOVB #PORT01,D1 ; bit pattern indicates ports 0,1 initd ANDB PORTS,D1 ; is either port of this DUART inited? BEQ BADINT ; no, invalid INTERRUPT, ignore it MOV DUART1,A2 ; get base of DUART MOVB P.ISR(A2),D1 ; read INTERRUPT status reg ANDB #IS$TRA!IS$RRA,D1 ; recv or transmit intrt. from ch A? BEQ IOSR1B ; must be channel B MOV TRMDF0,A5 ; get pointer to port 0's TRMDEF block JMP GINTRP ; go to general processing routine IOSR1B: MOV TRMDF1,A5 ; get pointer to port 1's TRMDEF block JMP GINTRP ; go to general processing routine IOSRV2: MOVB #PORT23,D1 ; bit pattern indicates ports 2,3 initd ANDB PORTS,D1 ; is either port of this DUART inited? BEQ BADINT ; no, invalid INTERRUPT, ignore it MOV DUART2,A2 ; get base of DUART MOVB P.ISR(A2),D1 ; read INTERRUPT status reg ANDB #IS$TRA!IS$RRA,D1 ; recv or transmit intrt. from ch A? BEQ IOSR2B ; must be channel B MOV TRMDF2,A5 ; get pointer to port 2's TRMDEF block JMP GINTRP ; go to general processing routine IOSR2B: MOV TRMDF3,A5 ; get pointer to port 3's TRMDEF block JMP GINTRP ; go to general processing routine IOSRV3: MOVB #PORT45,D1 ; bit pattern indicates ports 4,5 initd ANDB PORTS,D1 ; is either port of this DUART inited? BEQ BADINT ; no, invalid INTERRUPT, ignore it MOV DUART3,A2 ; get base of DUART MOVB P.ISR(A2),D1 ; read INTERRUPT status reg ANDB #IS$TRA!IS$RRA,D1 ; recv or transmit intrt. from ch A? BEQ IOSR3B ; must be channel B MOV TRMDF4,A5 ; get pointer to port 4's TRMDEF block BR GINTRP ; go to general processing routine IOSR3B: MOV TRMDF5,A5 ; get pointer to port 5's TRMDEF block BR GINTRP ; go to general processing routine IOSRV4: MOVB #PORT67,D1 ; bit pattern indicates ports 6,7 initd ANDB PORTS,D1 ; is either port of this DUART inited? JEQ BADINT ; no, invalid INTERRUPT, ignore it MOV DUART4,A2 ; get base of DUART MOVB P.ISR(A2),D1 ; read INTERRUPT status reg ANDB #IS$TRA!IS$RRA,D1 ; recv or transmit intrt. from ch A? BEQ IOSR4B ; must be channel B MOV TRMDF6,A5 ; get pointer to port 6's TRMDEF block BR GINTRP ; go to general processing routine IOSR4B: MOV TRMDF7,A5 ; get pointer to port 7's TRMDEF block BR GINTRP ; go to general processing routine TIMR1S: MOVB #PORT01,D1 ; port init mask for this DUART MOV DUART1,A2 ; get base of DUART BR SHUTOF TIMR2S: MOVB #PORT23,D1 ; port init mask for this DUART MOV DUART2,A2 ; get base of DUART BR SHUTOF TIMR3S: MOVB #PORT45,D1 ; port init mask for this DUART MOV DUART3,A2 ; get base of DUART BR SHUTOF TIMR4S: MOVB #PORT67,D1 ; port init mask for this DUART MOV DUART4,A2 ; get base of DUART BR SHUTOF SHUTOF: ANDB PORTS,D1 ; either port on this DUART inited? JEQ BADINT ; no, invalid INTERRUPT ignore it MOVB #^H08,P.ROB(A2) ; shut off timer REST A0-A6,D0-D7 ; restore registers RTE PAGE ;GINTRP General Serial Port Interrupt Processing Routine ; ; Come here to determine which channel (A or B) of given DUART generated the ; INTERRUPT. ; ;Inputs: A5 Terminal definition index ; All registers SAVEd on stack ; ;Outputs: D1 2681 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 P.SR(A4),D1 ; read the 2681 status register BTST #ST$RDRF,D1 ; check receiver data register full flag BNE INPR ; and go process if set BTST #ST$TRDY,D1 ; check transmitter empty flag BNE OUTPR ; and go process if set BR FLSINT ; handle false interrupt PAGE ;INPR Input Character Interrupt Routine ; ;Come here whenever we get a receiver interrupt. Read the character from ;the AM-1006 and pass on to TRMSER. ; ;Inputs: A2 DUART base ; A4 Port register base ; All registers SAVEd on stack ; ;Outputs: None ; ;Modifies: Restores registers INPR: MOVB P.RCV(A4),D1 ; read the data character TRMICP ; go process the character REST A0-A6,D0-D7 ; restore registers RTE PAGE ;OUTPR Transmitter Interrupt Routine ; ;Come here on a transmitter interrupt. If another character is available ;for output, grab it and send it to the 2681. ;Otherwise, clear the OIP flag and dismiss interrupt. ; ;Inputs: D1 2681 Status Register ; A2 DUART base ; A4 I/O register base address ; A5 Terminal definition index ; All registers SAVEd on the stack ; ;Outputs: Only to AM-1006 ; ;Modifies: Registers restored OUTPR: TRMOCP ; get next output character from TRMSER TST D1 ; data available? BPL OUTREG ; yes - ANDW #^C,@A5 ; no - clear the OIP flag MOVB #CM$TXDI,P.CMR(A4) BR OUTRTN ; return ;Send character to transmitter OUTREG: MOVB D1,P.TXM(A4) ; send character to 2681 OUTRTN: REST A0-A6,D0-D7 ; return RTE PAGE ;FLSINT 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 just ;ignore the interrupt. ; ;Inputs: D1 2681 Status Register ; A2 DUART base ; A4 I/O register base address ; All registers SAVEd on stack ; ;Outputs: None ; ;Modifies: Restores registers FLSINT: REST A0-A6,D0-D7 ; restore register RTE ; return PAGE ;Define baud rate table BAUDTB: BYTE 0,0 ; 50 baud BYTE 200,0 ; 75 baud BYTE 0,1 ; 110 baud BYTE 0,2 ; 134.5 baud BYTE 200,3 ; 150 baud BYTE 0,3 ; 200 baud BYTE 0,4 ; 300 baud BYTE 0,5 ; 600 baud BYTE 0,6 ; 1200 baud BYTE 200,12 ; 1800 baud BYTE 200,7 ; 2000 baud BYTE 0,10 ; 2400 baud BYTE -1,-1 ; 3600 baud BYTE 0,11 ; 4800 baud BYTE 0,12 ; 7200 baud BYTE 0,13 ; 9600 baud BYTE 200,14 ; 19200 baud BYTE 0,14 ; 38400 baud EVEN DUART1: LWORD ^H0FFFF10 ; I/O base for DUART 1 ( ports 0&1 ) DUART2: LWORD ^H0FFFF20 ; I/O base for DUART 2 ( ports 2&3 ) DUART3: LWORD ^H0FFFF70 ; I/O base for DUART 3 ( ports 4&5 ) DUART4: LWORD ^H0FFFF90 ; I/O base for DUART 4 ( ports 6&7 ) TRMDF0: LWORD 0 ; pointer to TRMDEF block for port 0 TRMDF1: LWORD 0 ; " " " " " " 1 TRMDF2: LWORD 0 ; " " " " " " 2 TRMDF3: LWORD 0 ; " " " " " " 3 TRMDF4: LWORD 0 ; " " " " " " 4 TRMDF5: LWORD 0 ; " " " " " " 5 TRMDF6: LWORD 0 ; " " " " " " 6 TRMDF7: LWORD 0 ; " " " " " " 7 PORTS: BYTE 0 ; port initialization indicator PORT01 = ^H03 ; bit pattern indcating ports 0,1 initd PORT23 = ^H0C ; bit pattern indcating ports 2,3 initd PORT45 = ^H30 ; bit pattern indcating ports 4,5 initd PORT67 = ^H0C0 ; bit pattern indcating ports 6,7 initd IMASK1: BYTE 0 ; DUART 1 interrupt mask reg byte IMASK2: BYTE 0 ; DUART 2 interrupt mask reg byte IMASK3: BYTE 0 ; DUART 3 interrupt mask reg byte IMASK4: BYTE 0 ; DUART 4 interrupt mask reg byte OPBIT1: BYTE 0 ; DUART 1 output port bits OPBIT2: BYTE 0 ; DUART 2 output port bits OPBIT3: BYTE 0 ; DUART 3 output port bits OPBIT4: BYTE 0 ; DUART 4 output port bits INTADD = ^H0FFFF89 ; Interrupt port address INTVEC = ^H064 ; Address of interrupt vector IOINT1 = 0 ; Duart 1 I/O interrupt bit IOINT2 = 1 ; Duart 2 I/O interrupt bit IOINT3 = 2 ; Duart 3 I/O interrupt bit IOINT4 = 3 ; Duart 4 I/O interrupt bit TIMR1I = 4 ; Duart 1 timer interrupt bit TIMR2I = 5 ; Duart 2 timer interrupt bit TIMR3I = 6 ; Duart 3 timer interrupt bit TIMR4I = 7 ; Duart 4 timer interrupt bit ; ; EACH PORT HAS ITS OWN MODE REGISTER 1 AND 2 VALUE ; this method helps to invidually set up different mode to different ; port. There are two tables: MR1TAB and MR2TAB for mode registers 1 and 2 ; ; mode register 1 table MR1TAB: BYTE M1$7B+M1$PE+M1$PO ;Port 0,7-bits,odd parity(teleray) BYTE M1$7B+M1$PE+M1$PO ;Port 1,7-bits,odd parity(teleray) BYTE M1$7B+M1$PE+M1$PO ;Port 2,7-bits,odd parity(teleray) BYTE M1$8B+M1$NP ;port 3,8-bits,no parity(votestation) BYTE M1$8B+M1$NP ;port 4,8-bits,no parity(votestation) BYTE M1$8B+M1$NP ;port 5,8-bits,no parity(votestation) BYTE M1$8B+M1$NP ;port 6,8-bits,no parity(votestation) BYTE M1$7B+M1$NP ;port 7,8-bits,no parity(XEROX1730) ; mode register 2 table MR2TAB: BYTE M2$1SB+M2$NM+M2$CET ;everybody 1stopbit,rts,normal BYTE M2$1SB+M2$NM+M2$CET ;everybody 1stopbit,rts,normal BYTE M2$1SB+M2$NM+M2$CET ;everybody 1stopbit,rts,normal BYTE M2$1SB+M2$NM+M2$CET ;everybody 1stopbit,rts,normal BYTE M2$1SB+M2$NM+M2$CET ;everybody 1stopbit,rts,normal BYTE M2$1SB+M2$NM+M2$CET ;everybody 1stopbit,rts,normal BYTE M2$1SB+M2$NM+M2$CET ;everybody 1stopbit,rts,normal BYTE M2$1SB+M2$NM+M2$CET ;everybody 1stopbit,rts,normal EVEN END .