.lif z %defin .title DZ11 support .sbttl DZ11 support: Definitions, Macros and Code ;;; ;;; General info: ;;; ;;; DZ11 8 line async tty driver. Can probably also be used for qbus ;;; ;;; version. ;;; ;;; Usage: ;;; ;;; defdev dz,dz11,< ;;; ;;; ;;; dz vec,csr , ;;; ;;; ;;; dzl typ,baud.,P,stp,nbts,where ;;; ;;; dz 300,160100,< ;;; ;;; dzl v52,9600.,n,002,8, ;;; ;;; > ;;; ;;; > ;;; ;;; Known bugs: ;;; ;;; sometimes the buffer wraps, and characters keep coming (probably ;;; ;;; 65K of them). I don't know why this happens, but it is probably my ;;; ;;; misunderstanding of what a DZ wants to see for output. ;;; ;;; More bugs: ;;; ;;; Ignores all terminal info (except type, baud, and location). Assumes ;;; ;;; no parity, 2 stop bits, 8 bits per character. .iif z %defin, .nlist ;don't list definitions and macros if not ;defining them .if nz %defin ;only define symbols when we are supposed to .if p1 .sbttl -- Definitions ;; dz11 definitions ;; offsets to device registers dz.csr==0 ;(R/W) csr dz.rbf==2 ;(R/ ) receiver buffer dz.lpr==2 ;( /W) line parameter register dz.xcr==4 ;(R/W) transmitter control register dz.msr==6 ;(R/ ) modem status dz.xdr==6 ;( /W) transmitter data dz.xbr==7 ;( /W) transmitter break data ;; Control and Status Register bits (dz.csr) [read/write] dz.xrd==bit.15 ;transmitter ready dz.xie==bit.14 ;transmitter interrupt enable dz.sa==bit.13 ;silo alarm (notification) dz.sae==bit.12 ;silo alarm enable dz.xln==mask3 ;xmit line number mask (after SWAB) dz.rdn==bit.07 ;receiver done dz.rie==bit.06 ;receiver interrupt enable dz.mse==bit.05 ;master scan enable dz.mcl==bit.04 ;master clear dz.mnt==bit.03 ;maintenance ;; Receiver Buffer bits (dz.rbf) [read only, word only] dz.vdp==bit.15 ;Valid Data Present dz.dov==bit.14 ;Data Overrun dz.frm==bit.13 ;framing error (break was hit) dz.par==bit.12 ;parity error dz.rln==mask3 ;rcvr line number mask (after SWAB) dz.rch==mask8 ;the received character ;; Line paramter register bits (dz.lpr) [write only, word only] dz.rcv==bit.12 ;receiver on dz.spd==08. ;ash for speed select dz.paN==0_6 ;no parity dz.paE==1_6 ;even parity dz.paO==3_6 ;odd parity dz.tsb==bit.05 ;two stop bits dz.5bt==0_3 ;5 bit characters dz.6bt==1_3 ;6 bit characters dz.7bt==2_3 ;7 bit characters dz.8bt==3_3 ;8 bit characters dz.lln==mask3 ;line number .sbttl -- Macros .macro dz vec,csr,lines ndzl==0 lines .if p2 %%==. .=dz$vec+<2*ndz> .word vec .=dz$csr+<2*ndz> .word csr .=dz$tty+<2*ndz> .word 2* .=dz$nlines+<2*ndz> .word ndzl .=%% .endc ndz==ndz+1 .endm .macro dzl ttytyp,baud,par,nstop,nbits,where .if p1 %%==. .=0 .string .=%% .iff %%==. .=ttyityp+<2*ntty> .word t.'ttytyp .=ttyispd+<2*ntty> .word baud .=ttyilo+<2*ntty> .string .=%% .endc ntty==ntty+1 ndzl==ndzl+1 .endm .endc p1 ndz==0 .endc %defin .iif z %defin, .list ;start listing again .iif nz %defin, .nlist ;don't list code if only doing definitions .if z %defin ;only do code if not defining symbols .sbttl -- Code dsect < ;;; a DZ11 receiver structure .blkb l$tti ;basically an input tty with.... >,l$dzr dsect < ;;; a DZ11 transmitter structure .blkb l$tto ;basically an output tty with... $dzbit:: .blkw 1 ;enable bit (lsh 1 line_number) $dzint:: .blkw 1 ;place to put the bit to interrupt do XMIT $dzbct:: .blkw 1 ;how many we've done >,l$dzx ;;; DZ11s are PDP11 interfaces to 8 serial lines. Each line is supported ;;; by one source object, and the transmitter by one destination object. dz$vec: .blkw ndz ;interrupt vector location dz$csr: .blkw ndz ;csr device register base address dz$tty: .blkw ndz ;base tty number of this dz dz$nli: .blkw ndz ;number of lines on the DZs dz$bkc: .blkw ndz ;break bits dz%bit: .rept 8. .word 1_.rpcnt .endr dz$brk: .rept ndz .lif z .rpcnt dz$rbk:: jsr r0,@#dzrint .rpcnt*2 .lif z .rpcnt dz$xbk:: jsr r0,@#dzxint .rpcnt*2 .endr ldz$brk==<.-dz$brk>/ndz ;;; DZ11 receiver interrupt handler. Interrupt vector points in DZ$BRK, which ;;; contains a JSR R0,@#DZRINT. This saves r0 on the stack, and the DZ index ;;; can be picked up with MOV (R0),R0 ;;; r0: device index ;;; r1: character ;;; r4: tty device ;;; r5: csr dzrint: mov (r0),r0 ;get the DZ index push r1,r4,r5 ;save some more regs mov dz$csr(r0),r5 ;get the CSR loop < mov dz.rbf(r5),r1 ;get the receiver buffer exitl pl ;nothing there, so exit mov r1,r4 swab r4 bic #dz.rln,r4 ;get line number cmp r4,dz$nlines(r0) ;make sure it is known if lt,< asl r4 add dz$tty(r0),r4 ;tty index mov ttyrdv(r4),r4 ;get the receive device bit #dz.frm,r1 ;BREAK? if ne,< movb #%acom,r1 ;send COM-B call @$dvlpt(r4) ;put the character in the device movb #'B,r1 > else < bic #dz.rch,r1 ;get character bits only > call @$dvlpt(r4) ;put the character in the device > rptl ;try for more characters > pop r5,r4,r1,r0 ;restore all regs rti ;;; DZ11 Transmitter interrupt handler. Interrupt vector points in DZ$BRK ;;; which contains a JSR R0,@#DZXINT. This saves r0 on the stack and the DZ ;;; index can be picked up with MOV (R0),R0. ;;; r0: dz index ;;; r1: temp for character ;;; r4: tty output device ;;; r5: dz csr dzxint: mov (r0),r0 push r1,r3,r4,r5 ;save some more regs mov dz$csr(r0),r5 loop < mov dz.csr(r5),r3 ;read CSR exitl pl ;no more lines ready swab r3 bic #dz.xln,r3 ;get line number asl r3 ;indexable add dz$tty(r0),r3 ;tty index mov ttyxdv(r3),r4 ;get tty output object tst $dzbct(r4) ;in break? if ne,< if gt,< bisb $dzbit(r4),dz$bkc(r0) movb dz$bkc(r0),dz.xbr(r5) > cmp $dzbct(r4),ttyispd(r3) if gt,< bicb $dzbit(r4),dz$bkc(r0) movb dz$bkc(r0),dz.xbr(r5) clr $dzbct(r4) br 10$ > clrb dz.xdr(r5) ;send a NUL add #50.,$dzbct(r4) ;done yet? rptl > 10$: tst $dvhmn(r4) if gt,< call chnfgt movb r1,dz.xdr(r5) ;put character in xmit data register > else ;clear interrupt bit rptl > pop r5,r4,r3,r1,r0 rti dzpwu:: dzini: clr r0 loop < call dzinit ;initial this DZ11 add #2,r0 cmp r0,#2*ndz ;done all of them yet? rptl lt > return dzinit: push r5,r4 mov dz$csr(r0),r5 call nxmcat dznxm mov #dz.mcl,dz.csr(r5) ;request a master clear call nxmclr ;it's probably there loop < bit #dz.mcl,dz.csr(r5) rptl ne ;wait for master clear to finish > mov dz$vec(r0),r4 ;get vector mov r0,r5 ;get index mul #ldz$brk/2,r5 ;convert to offset into dz$brk (table) add #dz$rbk,r5 ;point to receiver interrupt routine mov r5,(r4)+ ;setup receiver interrupt routine mov #pr5,(r4)+ ;and priority sub #dz$rbk-dz$xbk,r5 ;now has pointer to xmit routine mov r5,(r4)+ ;setup xmit interrupt routine mov #pr5,(r4)+ ;and priority mov dz$csr(r0),r5 ;get csr back push r2,r1 clr r4 ;start at line zero loop < ;;get the speed part of the LPR mov r4,r1 asl r1 add dz$tty(r0),r1 ;now is tty index mov #dzstbl,r2 loop < tst (r2) if eq, cmp (r2)+,ttyisp(r1) exitl eq tst (r2)+ rptl > mov (r2),r1 ;get speed part bis r4,r1 ;or in the line line bis #dz.rcv+dz.paN+dz.8bt,r1 mov r1,dz.lpr(r5) ;setup the line parameter register mov r4,r1 asl r1 push r1 add dz$tty(r0),(sp) ;tty index push #l$dzr,#l$dzx ;size of xmit and recv devices call ttygood if cs, pop r2 ;get xmit device mov #dzpput,$dvppt(r2) ;set physical put mov #dzpio,$dvlio(r2) ;and I/O control mov dz%bit(r1),$dzbit(r2) mov r5,$dzint(r2) add #dz.xcr,$dzint(r2) pop r2 ;get receive devices mov #dzpget,$dvpgt(r2) ;set physical get routine pop * ;punt tty index inc r4 cmp r4,dz$nlines(r0) rptl lo > pop r1,r2 mov #dz.xie+dz.rie+dz.mse,dz.csr(r5) ;enable the world pop r4,r5 return .macro ..dzs speed,ubusval,qbusval .if z qbus .if ge ubusval .word speed,ubusval'_dz.spd .endc .iff .if ge qbusval .word speed,qbusval'_dz.spd .endc .endc .endm dzstbl: ;dz speed table (unibus version may not be ;correct. Assumed same as qbus.) ..dzs 19200.,17,17 ..dzs 9600.,16,16 ..dzs 7200.,15,15 ;only on qbus version ..dzs 4800.,14,14 ..dzs 3600.,13,13 ..dzs 2400.,12,12 ..dzs 2000.,11,11 ..dzs 1800.,10,10 ..dzs 1200.,07,07 ..dzs 600.,06,06 ..dzs 300.,05,05 .word 0 dzpio: .word $open,dzpopn ;I/O control .word $close,dzpcls .word ttybrk,dzpbrk .word 0 dznxm: push r0 mov dz$nlines(r0),r5 mov dz$tty(r0),r0 loop < call ttybad tst (r0)+ sorl r5 > pop r0,r4,r5 return dzpput: lock 6 call chnput if cc, unlock return dzpget: lock 6 call chnget unlock return dzpopn: push $dzbit(r4) ;set DTR swab (sp) bis (sp)+,@$dzint(r4) return dzpcls: push $dzbit(r4) ;reset DTR swab (sp) bic (sp)+,@$dzint(r4) return dzpbrk: mov #-1,$dzbct(r4) ;start breaking bisb $dzbit(r4),@$dzint(r4) return .endc %defin .iif nz %defin, .list ;start listing as usual ;; local modes: ;; mode:midas ;; auto fill mode: ;; fill column:75 ;; comment column:32 ;; end: