; ADITIO.M68 - interface software for MAcrotech Adit card.
; Disclaimer
; Macrotech makes no representations or warranties with respect to the
; contents hereof and specifically disclaims any implied warranties of
; merchantibility or fitness for any purpose, useful or otherwise.
;
;
;
;This interface driver supports an Adit serial i/o board upto 16 channels.
;All ports have full modem (and therefore printer) control.
;
;Ports are addressed in the TRMDEF statement as 0 through 17 octal.
; Beta-test prerelease version 0.1 01JUN84 - not for distribution
; This driver is not DMA driven. This driver supports only one ADIT
; upto 16 channels. Tested with AMOS 1.1A(68). Future release will
; incorporate DMA features, extended driver entry
; routines for advanced features (ie: high speed block i/o through
; DMA), etc.
; last update 01JUN84
; base port = 0E0h
; interrupt level = 7
ADITP=^H0FFFFE0
SEARCH SYS
SEARCH SYSSYM
SEARCH TRM
objnam 0,0,[IDV]
; i/o port register map
AIC=0 ; command register
AIR1=1 ; data register
AIR2=2 ; for setup
AIR3=3 ; ditto
SEMA=4 ; semaphore, busy when bit 0 is high
ACK=5 ; read acks interrupt & gets status
; status register defines
STS.IN=0 ; input is available
STS.OT=1 ; space for output data
STS.BS=2 ; channel is busy
STS.DC=4 ; data carrier detect
STS.BR=5 ; break detected
STS.PA=6 ; UART parity error
STS.FR=7 ; framing error
CHROUT:
SAVE A0-A6, D0-D7
MOV T.IHM(A5), D7 ; get unit number
MOV T.IHW(A5),A3 ; and hardware address
AND #17, D7 ; D7 gets channel number
LEA A6,COMAND+2
MOVB D7, @A6
MOVB #^H70, D0 ; interrupt on buffer ready
NOTBSY
CALL COMAND
REST A0-A6, D0-D7
RTN
; init sets up interrupt structure ,modem block parms and initializes modem
; board.
INIT: SUPVR
SVLOK ; lock cpu for init
MOV #ADITP,A3 ; index baord
LEA A6,INITA ; INDEX INIT FLAG
TSTB @A6 ; ADIT given full reset yet ?
BNE 10$ ; yes-once is enuf.
SETB @A6 ; flag we did reset it
NOTBSY ; wait for it
MOVB #^H0C0,D0 ; reset board command
CALL COMAND ; reset it
CLR D7
MOVW INTLVL, D7 ; get interrupt level
LSL D7, #2 ; make it lword offset
MOVW #434, A6 ; index int vector table
SUB D7, A6 ; A6 points to table entry
LEA A1, IROUT
MOV A1, @A6
10$: MOVL T.IHM(A5), D7 ; D7 gets unit #
MOV D7, D6 ; copy it
DIV D7, #16. ; get board unit number
ASL D7, #3. ; multiply by eight for offset
ADDW D7, A3 ; A3 gets board's base address
MOV A3, T.IHW(A5) ; save it for later
MOV #ADITP,A3 ; get base adress again
ASL D6, #2. ; make offset longword/channel
LEA A6, TTABL
ADD D6, A6 ; A6 index interrupt TRMDEF table
MOV A5, @A6 ; set TRMDEF refererence
NOTBSY ; wait for not busy
; When set up for single buffer, the ADIT hangs up on output
MOVB #304, AIR1(A3) ; set 8 data, 1 stop, no parity or XON/XOFF
; So for now, use multiple output buffers
;;; MOVB #344, AIR1(A3) ; set 8 data, 1 stop, no parity or XON/XOFF
; set up baud rate
MOVW T.BAU(A5), D7 ; get system rate
LEA A6, BTABLE-2 ; index baud rate table -4
40$: ADDW #2, A6 ; pre-increment
MOVB (A6)+, D6 ; compare to possible
BEQ 100$ ; end of list
CMPW D6, D7 ; match ?
BNE 40$ ; no-try next
MOVB (A6)+, AIR2(A3) ; set AIR2
MOVB (A6)+, AIR3(A3) ; set AIR3
LEA A6, COMAND+2
MOV T.IHM(A5), D7
AND #17, D7
MOVB D7, @A6 ; set channel number
MOV #^H30, D0 ; init channel command
CALL COMAND ; wait for ADIT, give command
MOV #^H50, D0
NOTBSY
CALL COMAND ; enable receive interrupts
LSTS #0 ; return to user mode, unlock CPU.
RTN
100$: LSTS #0
TYPECR <?Invalid baud rate for ADIT>
RTN
; interrupt routine for reading characters
IROUT: SVLOK
SAVE A0-A6, D0-D7
MOV #ADITP, A3 ; A3 indexs hardware
20$: MOVB ACK(A3), D0 ; acknowledge interrupt & get channel
MOV D0,D2
; use imbedded channel number to do table lookup.
AND #17, D0 ; strip to channel only
;; This is NASTY, SELF MODIFYING CODE, used for economy & speed.
LEA A6,COMAND+2
MOVB D0,@A6 ; save channel number
; This stores the current channel number in the OR #???,D0 op code in the
; COMAND subroutine, so we do not have to keep generating the channel number
; prior to each COMAND call.
ASL D0, #2. ; x 4
LEA A6, TTABL
MOV 0(A6)[D0], D7 ; D7 gets TRMDEF pointer
JEQ SPUR ; if zero its spurious
MOV D7, A5 ; else point A5 to TRMDEF
AND #^H0F0,D2 ; strip out channel from interrupt poll
CMPB D2,#^H050 ; is it input ?
BEQ RECV ; no-check for input
; send output data to ADIT as long as it is not busy and data is available.
; limit transfer to 64 bytes for now.
XMIT: MOV #10.,D3 ; set maximum transfer count to 11.
10$: PUSH D3
TRMOCP
POP D3
TST D1
BMI DISARM ; disable transmitter
NOTBSY
MOVB D1, AIR2(A3) ; yes-set data output byte
MOV #^H60, D0 ; set single out command
CALL COMAND ; do it
NOTBSY
MOVB AIR1(A3), D2 ; D2 gets ADIT status
BTST #STS.OT, D2 ; more output space ?
BEQ 20$ ; no
DBF D3,10$ ; yes-loop if max count no te exceeded.
; end output process
20$: MOV #^H70, D0 ; enable xmit interrupts for next time
CALL COMAND
BR DONE
; no more data to output - clear OIP bit in status word
DISARM: BCLR #7, @A5 ; clear OIP
BR DONE
; receive all characters buffered.
RECV: MOV #^H40, D0 ; make it read single data
NOTBSY
CALL COMAND ; send the command
NOTBSY
MOVB AIR2(A3), D1 ; get the byte
SAVE A3,A5
TRMICP ; pass it to TRMSER
REST A3,A5
MOVB AIR1(A3), D2 ; check status
BTST #STS.IN, D2 ; got more data ?
BNE RECV ; yes-loop til gone
MOV #^H50, D0 ; no-rearm input interrupt
CALL COMAND ; send the command
BR DONE
; COMAND adds the channel bias (stored in the immediate field of the first op)
; and sends the command to the ADIT card. Then, it waits for the ADIT to become
; ready for another command.
COMAND: ORB #0, D0 ; add channel bias to command
MOVB D0, AIC(A3) ; give to ADIT
RTN
EVEN
INITA: WORD 0 ; board inted flag
TTABL: BLKL 32. ; map of 32 possible TRMDEFs