.lif z %defin .title DH11 (Able DH/DM) support .sbttl DH11 support: Definitions, Macros and Code ;;; some qbus DHs look like unibus DHs (Emulex). Some don't (Canadian). .iif z qbus, dhubus==-1 .iif nz qbus, .iif ndf dhubus, dhubus==0 ;qbus default to qbus (Canadian) ;;; ;;; General info: ;;; ;;; DH11 16 line DMA output async terminal driver. Also works for the ;;; ;;; qbus DHK-11 ;;; ;;; Usage: ;;; ;;; defdev dh,dh11,< ;;; ;;; ;;; dh vec,csr , ;;; ;;; ;;; dhl typ,baud.,P,stp,nbts,where ;;; ;;; dh 340,160020,< ;;; ;;; dhl v52,9600.,n,002,8, ;;; ;;; > ;;; ;;; > ;;; ;;; Known bugs: ;;; ;;; Ignores all tty info, except typ and location. Assumes 9600. baud, ;;; ;;; no parity, 2 stop bits, 8 bits per character. ;;; ;;; Misfeatures: ;;; ;;; No modem control. .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 ;; DH11 definitions ;; offsets to device registers dh.scr==0 ;(MIX W/B) System Control Register dh.nxt==2 ;(R/ Wrd) Next Received Character Register dh.lpr==4 ;(R/W Wrd) Line Parameter Register (Group) dh.car==6 ;(R/W Wrd) Current Address Register dh.bcr==10 ;(R/W Wrd) Byte Count Register (Group) dh.bar==12 ;(R/W Wrd) Buffer Active Register dh.brk==14 ;(R/W Wrd) Break Control Register dh.ssr==16 ;(MIX W/B) Silo Status Register ;; System Control Register bits (dh.scr) [Mixed, Word/byte] dh.xin==bit.15 ;(r/w) Transmitter Interrupt dh.sin==bit.14 ;(r/ ) Storage Interrupt dh.xie==bit.13 ;(r/w) Transmit and NXM Interrupt Enable dh.sie==bit.12 ;(r/w) Storage Interrupt Enable dh.mcl==bit.11 ;(r/w) Master Clear dh.nin==bit.10 ;(r/ ) NXM Interrupt dh.mnt==bit.09 ;(r/w) Maintenance dh.cni==bit.08 ;( /w) Clear NXM Interrupt dh.rin==bit.07 ;(r/ ) Receiver Interrupt dh.rie==bit.06 ;(r/w) Receiver Interrupt Enable dh.lin==mask4 ;(r/w) Line selection for setting LPR,CAR,BCR ;; Next Received Character Register bits (dh.nxt) [read only, word only] dh.vdp==bit.15 ;Valid Data Present dh.dov==bit.14 ;Data Overrun dh.frm==bit.13 ;Framing Error dh.par==bit.12 ;Parity Error dh.rln==mask4 ;Line Number mask after SWAB'ing dh.rch==mask8 ;Character Data Byte ;; Line Parameter Register bits (dh.lpr) [read/write, word only] dh.aee==bit.15 ;Auto-Echo-Enable dh.fdx==bit.14 ;(cleared =) Full Duplex dh.tsp==10. ;ash for transmitter speed dh.rsp==06. ;ash for receiver speed dh.odd==bit.05 ;odd parity dh.pen==bit.04 ;parity enable dh.tsb==bit.02 ;two stop bits dh.5bt==0 ;5 bits dh.6bt==1 ;6 bits dh.7bt==2 ;7 bits dh.8bt==3 ;8 bits ;; Silo Status Register bits (dh.ssr) dh.smn==bit.15 ;Silo Maintenence dh.sfl==mask13&mask8 ;Silo Fill Level dh.rxm==mask7&mask6 ;Read Extended Memory (A17 and A16) dh.sal==mask5 ;Silo Alarm Level .sbttl -- Macros **** .macro dh vec,csr,dmvec,dmcsr,lines ndhl==0 lines .if p2 %%==. .=dh$vec+<2*ndh> .word vec .=dh$csr+<2*ndh> .word csr .=dm$csr+<2*ndh> .word dmcsr .=dh$tty+<2*ndh> .word 2* .=dh$nlines+<2*ndh> .word ndhl .=%% .endc ndh==ndh+1 .endm .macro dhl 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 ndhl==ndhl+1 .endm .endc p1 ndh==0 ;no DHs to start with .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 DH11 receiver structure .blkb l$tti ;basically an input tty with.... >,l$dhr dsect < ;;; a DH11 transmitter structure .blkb l$tto ;basically an output tty with... $dhxnum:: .blkw 1 ;a DH device index $dhsel:: .blkw 1 ;select value to put in dh.scr (with int enables) $dhbit:: .blkw 1 ;enable bit (lsh 1 line_number) $dhqnb:: .blkw 1 ;number of bytes in last xmit >,l$dhx ;;; DH11s are PDP11 interfaces to 16 serial lines. Each line is supported ;;; by one source object, and the transmitter by one destination object. dh$vec: .blkw ndh ;interrupt vector location dh$csr: .blkw ndh ;csr device register base address dm$csr: .blkw ndh ;one DM per DH dh$tty: .blkw ndh ;base tty number of this dh dh$nli: .blkw ndh ;number of lines on the DHs .wvector dh$oac,ndh ;old active control register dh%bit: .rept 16. .word 1_.rpcnt .endr dh$brk: .rept ndh .lif z .rpcnt dh$rbk:: jsr r0,@#dhrint .rpcnt*2 .lif z .rpcnt dh$xbk:: jsr r0,@#dhxint .rpcnt*2 .endr ldh$brk==<.-dh$brk>/ndh dh$var: ;vector address, receive .rept ndh .word dh$rbk+<.rpcnt*ldh$brk> .endr dh$vax: ;vector address, xmit .rept ndh .word dh$xbk+<.rpcnt*ldh$brk> .endr ;;; DH11 receiver interrupt handler. Interrupt vector points in DH$BRK, which ;;; contains a JSR R0,@#DHRINT. This saves r0 on the stack, and the DH index ;;; can be picked up with MOV (R0),R0. ;;; r0: device index ;;; r1: character ;;; r4: tty device ;;; r5: csr dhrint: mov (r0),r0 ;get DH index push r1,r4,r5 ;save some more regs mov dh$csr(r0),r5 ;get the csr loop < mov dh.nxt(r5),r1 ;get the next character exitl pl ;nothing there, so exit mov r1,r4 swab r4 bic #dh.rln,r4 ;get line number cmp r4,dh$nlines(r0) ;make sure it is known if lt,< asl r4 ;indexable add dh$tty(r0),r4 ;tty index mov ttyrdv(r4),r4 ;get the receive device bic #dh.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 rti ;;; DH11 Transmitter interrupt handler. Interrupt vector points in DH$BRK, ;;; which contains a JSR R0,@#DHXINT. this saves r0 on the stack and the DH ;;; index can be picked up with MOV (R0),R0. ;;; r0: DH index ;;; r3: Scratch ;;; r4: TTY output device ;;; r5: DH CSR dhxint: mov (r0),r0 ;get index push r5,r4,r3 ;save some more regs mov dh$csr(r0),r5 bit #dh.nin,dh.scr(r5) ;NXM interrupt? if ne, ;GARP bic #dh.xin,dh.scr(r5) ;turn interrupts back on (kludge...) push dh$oac(r0) ;get old DH.BAR bic dh.bar(r5),(sp) ;now has bits that went inactive bic (sp),dh$oac(r0) clr r3 ;start at DH line 0 loop < mov r3,r4 ;get line number asl r4 ;index add dh$tty(r0),r4 ;now tty index mov ttyxdv(r4),r4 ;get the tty xmit device bit $dhbit(r4),(sp) ;was it active if ne,< ;yup, but isn't now add $dhqnb(r4),$dvfpt(r4) ;up the pointer cmp $dvfpt(r4),$dvlim(r4) ;hit the top? if his, ;chop it down sub $dhqnb(r4),$dvhmn(r4) ;discount number of characters in ;last xmit if eq, ;allow more user transmission else ;start output to tty if still more > inc r3 ;go on to the next one cmp r3,dh$nlines(r0) ;at the end yet rptl lo > pop *,r3,r4,r5,r0 rti ;;; Start DH output ;;; r0: dh index ;;; r4: tty output device ;;; r5: dh csr dhsout: bic $dhbit(r4),dh.bar(r5) ;make sure it isn't transmitting mov $dhsel(r4),dh.scr(r5) ;select the line mov $dvfpt(r4),dh.car(r5) ;current address register push $dvlim(r4) ;upper limit of ring buffer sub $dvfpt(r4),(sp) ;max number we should transmit cmp $dvhmn(r4),(sp) ;does it wrap? if lt, ;output the min mov (sp),$dhqnb(r4) ;save queued nbytes for later updating neg (sp) ;hardware wants neg count pop dh.bcr(r5) ;byte count register bis $dhbit(r4),dh.bar(r5) ;start it transmitting in hardware bis $dhbit(r4),dh$oac(r0) ;and software return ;;; Power-up and Initialization code dhpwu:: dhini: clr r0 loop < call dhinit ;initialize this DH11 (16 lines) add #2,r0 cmp r0,#2*ndh ;done all yet?? rptl lt > return ;;; Initialize a 16-line DH11. Called with R0 as DH11 index. dhinit: push r5,r4 ;save regs mov dh$csr(r0),r5 ;get the CSR for this DH11 call nxmcat ;is it really there?? dhnxm mov #dh.mcl,dh.scr(r5) ;do a master clear clr dh.brk(r5) ;nobody doing breaks clr dh.ssr(r5) ;zero limit, zero alarm limit for silo mov #dh.xie+dh.rie,dh.scr(r5) ;enable interrupts call nxmclr ;looks good, clear nxm catch clr dh$oac(r0) ;no old active lines mov dh$vec(r0),r4 ;interrupt vector mov dh$var(r0),(r4)+ ;setup receive interrupt routine mov #pr5,(r4)+ ;and priority mov dh$vax(r0),(r4)+ ;setup xmit interrupt routine mov #pr5,(r4)+ ;and priority push r2,r1 mov dh$csr(r0),r5 ;get CSR back mov dh$nlines(r0),r4 ;number of lines loop < mov dh$nlines(r0),r1 sub r4,r1 ;which line mov r1,dh.scr(r5) ;select the line mov r1,r3 ;set speed asl r3 add dh$tty(r0),r3 ;tty index mov ttyisp(r3),r3 ;get speed mov #dhstbl,r2 ;get speed table loop < tst (r2) if eq, cmp (r2)+,r3 exitl eq tst (r2)+ rptl > mov (r2),r2 ;get the speed bits bis #dh.8bt,r2 ;turn on 8bit mode mov r2,dh.lpr(r5) .if z qbus mov dm$csr(r0),r2 if ne,< call nxmcat .word 10$ mov r1,(r2) ;set the line number mov #2,2(r2) ;turn on DTR call nxmclr 10$: > .endc push r1 asl (sp) add dh$tty(r0),(sp) ;tty index push #l$dhr,#l$dhx ;size of xmit and recv devices call ttygood if cs, pop r2 ;get xmit device mov #dhpput,$dvppt(r2) ;set physical put mov r0,$dhxnum(r2) mov r1,$dhsel(r2) bis #dh.xie+dh.rie,$dhsel(r2) ;select is line with enable bits asl r1 ;don't use r1 below here mov dh%bit(r1),$dhbit(r2) ;enable bit clr $dhqnb(r2) pop r2 ;get receive device mov #dhpget,$dvpgt(r2) ;set physical get routine pop * ;punt tty index dec r4 rptl ne ;too far for SOB > mov #dh.xie+dh.rie,dh.scr(r5) ;enable interrupts pop r1,r2 pop r4,r5 return .macro ..dhs speed,ubusval,qbusval .if nz dhubus .if ge ubusval .word speed,ubusval*<<1_dh.tsp>+<1_dh.rsp>> .endc .iff .if ge qbusval .word speed,qbusval*<<1_dh.tsp>+<1_dh.rsp>> .endc .endc .endm dhstbl: ;dh speed table ..dhs 19200.,16,17 ..dhs 9600.,15,16 ..dhs 7200.,-1,15 ;only on qbus version ..dhs 4800.,14,14 ..dhs 3600.,-1,13 ..dhs 2400.,13,12 ..dhs 2000.,-1,11 ..dhs 1800.,12,10 ..dhs 1200.,11,07 ..dhs 600.,10,06 ..dhs 300.,07,05 .word 0 dhnxm: push r0 mov dh$nlines(r0),r5 mov dh$tty(r0),r0 loop < call ttybad tst (r0)+ sorl r5 > pop r0,r4,r5 return dhpput: lock 6 call chnput if cc,< push r0 mov $dhxnum(r4),r0 ;get DH index bit $dhbit(r4),dh$oac(r0) ;was it idle if eq,< push r5 mov dh$csr(r0),r5 call dhsout pop r5 > pop r0 > unlock return dhpget: ;physical get lock 6 call chnget unlock 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: