.lif z %defin .title Versatec (V80) support .sbttl Versatec (V80) support: Definitions, Macros and Code v80vrs==%fnam2 ;;; Plotter will be refered to as MATRIX (because printer and ;;; plotter both begin with "p" .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 ;;; prefixes used in this module ;;; ;;; V8. Hardware interface offsets and bits ;;; ;;; $VS Versated scan line structure offsets ;;; ;;; $VH Hardware device object offsets ;;; ;;; VA V80 hardware routines ;;; ;;; V80 V80 support routines (random things) ;;; ;;; V8S V80 scan line routines ;;; ;;; V8% V80 scan line commands ;;; ;;; V8N V80 network routines ;;; ;;; V8C V80 constants ;;; ;;; V8V V80 variables ;;; ;;; V8T V80 tables ;;; ;;; V8$ V80 strings ;;; ;;; typical register usage: ;;; ;;; r0/ chaos connection ;;; ;;; r1/ chaos packet ;;; ;;; r2/ V80 hardware/interface object (v80 connection?) ;;; ;;; r3/ V80 scan line (V80 packet?) ;;; ;;; r5/ device base address = $vaadr(r2) ;; V80 definitions ;; offsets to the device registers (relative to printer status) v8.mbc==00 ;matrix byte count v8.ext==02 ;dma data buffer address extension bits v8.pbc==04 ;printer byte count v8.dma==06 ;dma data buffer address v8.mcs==10 ;matrix control and status v8.mdb==12 ;matrix data buffer v8.pcs==14 ;printer control and status v8.pdb==16 ;printer data buffer ;;; Control and Status Register bits v8.err==bit.15 ;error v8.dtc==bit.14 ;data transmission complete interrupt enable v8.bsy==bit.13 ;DMA busy v8.swp==bit.09 ;swap bytes on DMA transfer v8.ers==bit.08 ;DMA erase after read v8.rdy==bit.07 ;ready v8.ien==bit.06 ;interrupt enable v8.lnt==bit.05 ;remote line terminate v8.frm==bit.04 ;remote form feed v8.eot==bit.03 ;remote end of transmission v8.clb==bit.02 ;clear buffer v8.rst==bit.01 ;remote reset v8.spp==bit.00 ;enable SPP .endc p1 .sbttl -- Macros v8cnv8==0 ;start with no V80s .macro v8 pvec,mvec,csr,nos,chwin .if p2 %%==. .=v8tpvc+<2*v8cnv8> .word pvec .=v8tmvc+<2*v8cnv8> .word mvec .=v8tcsr+<2*v8cnv8> .word csr .=%% .endc p2 v8cnos==nos v8cchw==chwin v8cnv8==v8cnv8+1 .endm chnsrv ^"VERSATEC",cxversatec ;define the new server .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 .sbttl VA.... Interface definitions and tables ;; ;;;;;; a V80 hardware object ;; dsect < ;;interface/hardware object $vasta:: .blkw 1 ;device available flag %vsava==100000 ;available flag (must be high bit) %vsprn==000001 ;state is printing %vsplt==000002 ;state is plotting $vaadd:: .blkw 1 ;address of this interface $vaxqu:: .blkw 1 ;transmission queue $vaxqe:: .blkw 1 ;pointer to end of transmission queue $vanvs:: .blkw 1 ;number of items on transmission queue $vanos:: .blkw 1 ;number of output slots on queue $vapks:: .blkw 1 ;chaos packets (print) that should be freed $vacur:: .blkw 1 ;current scan line being worked on $vaprv:: .blkw 1 ;previous scan line (for XORing) $vaeof:: .blkw 1 ;consecutive CHAOS EOF count $vawid:: .blkw 1 ;width of usable line in bytes $varem:: .blkw 1 ;number of bytes remaning in line $valft:: .blkw 1 ;offset to left of scan line $vaxor:: .blkw 1 ;xor flag $vacon:: .blkw 1 ;current command continuation (0 for top level) $vacom:: .blkw 1 ;last command (in case continuation needs it) $vanar:: .blkw 1 ;number of args needed for current command $vaarp:: .blkw 1 ;pointer to place to deposit next arg $vaarg:: .blkb 64. ;max of 64 bytes of args (plot n) ;; if you add things, be sure to update VAINI and V80DWN >,l$vaobj ;; ;;;;;; Tables ;; .wvector v8tobj,v8cnv8 ;table of the objects v8tpvc: .blkw v8cnv8 ;print vector v8tmvc: .blkw v8cnv8 ;matrix vector v8tcsr: .blkw v8cnv8 ;control and status register ;; ;;;;;; Interrupt vectors point here ;; v8tbrk: .rept v8cnv8 .lif z .rpcnt v8tpbr:: jsr r2,@#vaintp .word v8tobj+<2*.rpcnt> .lif z .rpcnt v8tmbr:: jsr r2,@#vaintm .word v8tobj+<2*.rpcnt> .endr lv8tbrk==<.-v8tbrk>/v8cnv8 v8tvap: ;vector address, print .rept v8cnv8 .word v8tpbr+<.rpcnt*lv8tbrk> .endr v8tvam: ;vector address, matrix .rept v8cnv8 .word v8tmbr+<.rpcnt*lv8tbrk> .endr ;;; Init the Versatec hardware(s) v8ini: vaini: clr r0 ;start at v80 index 0 loop < call 100$ ;really init the beast add #2,r0 cmp r0,#v8cnv8*2 rptl lo > call v8sini ;init the scan line routines return 100$: ;do the work mov v8tcsr(r0),r3 call nxmcat ;catch bad interface vanxm mov #v8.clb,v8.pcs(r3) ;clear buffer (to print CSR) mov #v8.clb,v8.mcs(r3) ;clear buffer (to matrix CSR) clr v8.dma(r3) ;clear DMA address clr v8.ext(r3) ;and DMA address extension bits call nxmclr ;safe, interface is alive mov v8tpvc(r0),r2 ;get print vector mov v8tvap(r0),(r2)+ ;set vector address mov #pr5,(r2)+ ;and priority mov v8tmvc(r0),r2 ;get matrix vector mov v8tvam(r0),(r2)+ ;set vector address mov #pr5,(r2)+ ;and priority push #l$vaobj call fsmall call fsmclr pop r2 if eq, ;oops, out of memory at initialization mov r2,v8tobj(r0) mov #%vsava,$vasta(r2) ;device is available mov r3,$vaadd(r2) ;set it's CSR address jcall v80dwn ;shut down this versatec vanxm: clr v8tobj(r0) ;declare no hardware object return v80dwn: tst sysup ;is the system up yet if ne,< ;yup push r1,r3 mov $vaxqu(r2),r3 ;get the Xmit queue if ne, ;free it if exists mov $vacur(r2),r3 ;get current scan line if ne, ;free it if exists mov $vaprv(r2),r3 ;get previous scan line if ne, ;free it if exists mov $vapks(r2),r1 ;get list of chaos packets to free if ne, ;free them if exists call v8sfls ;flush all scan lines pop r3,r1 > push r2 add #$vaxqu,r2 ;want to auto-inc clr (r2)+ ;nothing on the Xmit queue mov r2,(r2) ;set up end pointer sub #2,(r2)+ ;... clr (r2)+ ;no scan lines on the Xmit list mov #v8cnos,(r2)+ ;all output slots available clr (r2)+ ;no chaos packets to free clr (r2)+ ;no current scan line clr (r2)+ ;no previous scan line clr (r2)+ ;no chaos eofs clr (r2)+ ;no width clr (r2)+ ;no bytes remaining clr (r2)+ ;no left margin info yet clr (r2)+ ;don't do XOR clr (r2)+ ;no current command continuation add #3*2,r2 ;last command, # needed args, arg ptr have ;no meaning without command continuation pop r2 return vaintp: ;printer support mov @(r2),r2 ;get the hardware object push r1,r5 mov $vaadd(r2),r5 ;get device address loop < mov $vaxqu(r2),r1 ;get a packet off the list if eq,< bic #v8.ien,v8.pcs(r5) ;turn off interrupts mov r2,$vaxqe(r2) ;set up end pointer add #$vaxqu,$vaxqe(r2) ;... exitl > tst $cpknb(r1) ;did we already use it? if mi,< ;yup mov (r1),$vaxqu(r2) ;unlink it dec $vanvs(r2) ;one less scan line inc $vanos(r2) ;one more output slot mov $vapks(r2),(r1) ;link the chaos packets into this one mov r1,$vapks(r2) ;and make this one the list rptl ;and try again > push r1 add #$cpkdt,(sp) ;point to the data region pop v8.dma(r5) ;put it in the DMA register push $cpknb(r1) ;number of bytes neg (sp) ;V80 wants 2's complement pop v8.pbc(r5) ;this is the printer byte count bis #bit.15,$cpknb(r1) ;flag this packet as printed > pop r5,r1,r2 ;pop all regs rti vaintm: mov @(r2),r2 ;get the hardware object push r3,r5 ;for scan line and device address mov $vaadd(r2),r5 ;get the address of the interface loop < ;loop over the transmission queue mov $vaxqu(r2),r3 ;get the scan line on the front if eq,< bic #v8.ien,v8.mcs(r5) ;turn off interrupts mov r2,$vaxqe(r2) ;set up the end of the queue add #$vaxqu,$vaxqe(r2) ;... exitl > tst $vsskb(r3) ;skip before? if ne,< ;yup dec $vsskb(r3) bis #v8.lnt,v8.mcs(r5) ;terminate line exitl > tst $vsnum(r3) ;print this line? if ne,< ;yup dec $vsnum(r3) push r3 add #$vsdat,(sp) ;point to data pop v8.dma(r5) ;set the DMA address mov #-%vsnby,v8.mbc(r5) ;neg byte count exitl > tst $vsska(r3) ;skip after? if ne,< ;yup dec $vsska(r3) bis #v8.lnt,v8.mcs(r5) ;terminate line exitl > tst $vsflg(r3) if ne,< bis #v8.frm,v8.mcs(r5) ;remote form feed clr $vsflg(r3) exitl > mov $vslnk(r3),$vaxqu(r2) ;unlink this scan line dec $vanvs(r2) ;one less scan line inc $vanos(r2) ;another output slot mov #-1,$vslnk(r3) ;no longer on a transmit list cmp r3,$vaprv(r2) ;is this the previous packet if ne, ;free the scan line rptl ;and try again > pop r5,r3,r2 rti .sbttl V80... V80 random support routines v80wto: ;wait for an output slot loop < tst $vanos(r2) exitl gt push r0,r1,r2 add #$vanos,r2 .regs #hng.ne,#zero .hang pop r2,r1,r0 rptl > return v80frc: loop < tst $vanvs(r2) exitl eq push r0,r1,r2 add #$vanvs,r2 .regs #hng.eq,#zero .hang pop r2,r1,r0 > return v80vso: call v80wto lock 5 clr (r3) mov r3,@$vaxqe(r2) mov r3,$vaxqe(r2) inc $vanvs(r2) dec $vanos(r2) add $vaadd(r2),r5 bis #v8.ien,(r5) unlock return .sbttl V8S... V80 scan line (de)allocation routines ;;; Versatec scan line structure %vsnby==2112./8. ;number of bytes in a scan line dsect < $vslnk:: .blkw 1 ;transmit link, for packet linking $vsskb:: .blkw 1 ;scan lines to skip before this line $vsnum:: .blkw 1 ;number of times to do this scan line $vsska:: .blkw 1 ;scan lines to skip after this line $vsflg:: .blkw 1 ;flags ;; be sure to update v8sall if you change this $vsdat:: .blkb %vsnby ;actual scan data .even >,l$vs .wscalar v8vfrl ;free scan line list .wscalar v8vnfr ;number on the freelist v8sini: ;initialize scan lines clr v8vfrl ;clear the head of the list clr v8vnfr ;and nothing on it return ;;; Free the scan line in r3 v8sfre: cmp v8vnfr,#v8cnos+2 ;should we free it? if ge,< push r3 ;give it back to free storage call fsmfre ;must be CALLED inc r3 ;cause error on word reference return> lock 5 ;no interrupts from versatec mov v8vfrl,(r3) ;shove the freelist into the scan mov r3,v8vfrl ;and make it the freelist inc v8vnfr ;one more scan line on the freelist unlock inc r3 ;cuase error on word reference return v8sfrl: push r5 ;to hold the list mov r3,r5 ;put the list in r5 loop < mov r5,r3 ;get the scan line exitl eq ;finished if no packet mov (r3),r5 ;cdr on down call v8sfre ;free the one scan line rptl ;and loop around > pop r5 return ;;; Flush the current list of available packets v8sfls: lock 5 mov v8vfrl,r5 clr v8vfrl clr v8vnfr unlock loop < push r5 exitl eq mov (r5),r5 call fsmfre rptl > pop * return ;;; Allocate a scan line. Return in r3 (or 0 if none) v8sall: lock 5 ;don't allow versatec to confuse the freelist mov v8vfrl,r3 ;get the top of the freelist if ne,< mov (r3),v8vfrl ;unlink it dec v8vnfr ;one less on the freelist unlock> else < unlock ;it is indeed safe push #l$vs ;length of a scan line structure call fsmall pop r3> push r3 if ne,< mov #-1,(r3)+ ;not linked on any list clr (r3)+ ;0 skip before count clr (r3)+ ;0 times to print this one clr (r3)+ ;0 skip after count clr (r3)+ ;no flags > pop r3 ;set Z flag in the process if zero return .sbttl V8%... Chaos packet discombobulating %v8eop==0 %v8rpt==000 %v8skp==100 %v8plt==200 %v8eol==300 %v8rpl==300 %v8xor==337 %v8mar==340 %v8ma1==350 ;;; Conventions: ;;; r0: Number of bytes left in CHAOS packet ;;; r1: Byte pointer into CHAOS packet ;;; r2: Hardware object ;;; r3: byte pointer into current scan line ;;; r4: available ;;; r5: available ;;; push ;;; call va%gar ;;; looks like it returns when all args accumulated ;;; must save r4 and r5 if you want to keep them. Do not save them on ;;; the stack va%gar: pop $vacon(r2) ;save return address as continuation pop $vanar(r2) ;number of args we need mov r2,$vaarp(r2) ;setup pointer to place ... add #$vaarg,$vaarp(r2) ;... to deposit next args va%ga2: ;;; packet processor reenters here mov $vanar(r2),r4 ;number of args still needed tst r4 if ne,< tst r0 if ne,< cmp r0,r4 if lt, ;take min with chaos bytes sub r4,r0 ;number of packet bytes when finished sub r4,$vanar(r2) ;discount it from number we need mov $vaarp(r2),r5 ;get pointer to next place for args loop < movb (r1)+,(r5)+ sorl r4 > mov r5,$vaarp(r2) ;save new value > > tst $vanar(r2) ;test possible new value if ne, ;need more, return to packet processor push $vacon(r2) ;restore return address clr $vacon(r2) ;no continuation for next time return ;and return to command processor v8%eop: call v8%lfn ;finish current line mov $vacur(r2),r3 mov #-1,$vsflg(r3) v8%out: lock 5 mov $vaprv(r2),r3 ;get previous if ne,< cmp (r3),#-1 ;is it on a transmit list? if eq, ;free it if not > mov $vacur(r2),r3 ;get current mov r3,$vaprv(r2) ;new previous unlock mov #v8.mcs,r5 ;address offset call v80vso v8%new: loop < call v8sall ;get a new one exitl ne push r0,r1 .regs #1,#0 .sleep pop r1,r0 rptl > mov r3,$vacur(r2) add $valft(r2),r3 mov $vawid(r2),$varem(r2) jcall v8%clr ;clear the scan line v8%rpt: mov r5,$vacom(r2) ;save command push #1 ;one arg call va%gar ;get it mov $vacom(r2),r5 ;get command back bic #mask6,r5 inc r5 sub r5,$varem(r2) movb $vaarg(r2),r4 ;get the arg loop < movb r4,(r3)+ sorl r5 > return v8%skp: mov r5,$vacom(r2) ;save command push #1 ;one arg call va%gar ;get it mov $vacom(r2),r5 ;get command back bic #mask6,r5 inc r5 sub r5,$varem(r2) add r5,r3 movb $vaarg(r2),(r3)+ ;set the byte dec $varem(r2) return v8%plt: bic #mask6,r5 inc r5 mov r5,$vacom(r2) ;save nbytes as command push r5 ;number of args needed call va%gar mov $vacom(r2),r5 ;get number of bytes back sub r5,$varem(r2) mov r2,r4 add #$vaarg,r4 ;get pointer to args loop < movb (r4)+,(r3)+ sorl r5 > return v8%eol: jcall v8%lad v8%rpl: bic #mask5,r5 push r5 call v8%lfn pop r5 push r3 mov $vaprv(r2),r3 lock 5 add r5,$vsnum(r3) cmp (r3),#-1 ;is it on a transmit list if eq,< mov #v8.mcs,r5 ;address offset call v80vso> ;if not, put it back on unlock pop r3 return v8%xor: call v8%lfn mov #-1,$vaxor(r2) return v8%mar: mov r5,$vacom(r2) ;save command push #3 ;need 3 args call va%gar ;get them mov $vacom(r2),r5 ;get command back bic #mask3,r5 movb $vaarg+0(r2),r4 bic #mask8,r4 ash #3,r4 add r5,r4 dec r4 ;convert one based to zero based mov $vacur(r2),r5 ;get current scan line mov r4,$vsskb(r5) ;tell it to skip before the top margin ;before printing pushb $vaarg+1(r2) ;get second arg bic #mask8,(sp) movb $vaarg+2(r2),r4 ;get third arg bic #mask8,r4 v8%ma.: sub (sp),r4 inc r4 mov r4,$vawid(r2) mov r4,$varem(r2) mov #$vsdat-1,r3 ;point to data with conversion from one ;based to zero based. add (sp)+,r3 mov r3,$valft(r2) add $vacur(r2),r3 return v8%ma1: push #4 call va%gar ;get 4 args push $vaarg+0(r2) ;get first 2 swab (sp) ;PDP-10 to PDP-11 style push $vaarg+2(r2) ;get second 2 swab (sp) ;pdp-10 to pdp-11 style pop r4 br v8%ma. v8%lfn: cmp $varem(r2),$vawid(r2) if eq, loop < tst $vaxor(r2) if ne,< call v8%dxr clr $vaxor(r2)> exitl v8%lad: cmp $varem(r2),$vawid(r2) rptl ne > mov $vacur(r2),r3 mov #1,$vsnum(r3) jcall v8%out v8%clr: mov $vacur(r2),r4 add #$vsdat,r4 mov #<%vsnby+1>/2,r5 loop < clr (r4)+ sorl r5 > return v8%dxr: mov $vacur(r2),r5 mov $vaprv(r2),r4 add #$vsdat,r5 add #$vsdat,r4 push r2,r3 mov #<%vsnby+1>/2,r3 loop < mov (r4)+,r2 xor r2,(r5)+ sorl r3 > pop r3,r2 return .sbttl V8N... Versatec network handler cxversatec:: v8nchaos: cx$srv v8nopn,40,240_8,<> v8nopn: call cpkpki ;get the RFC if cs,< 110$: call ccnfre .logout > mov #v8cnv8,r5 ;number of V80 configured mov #v8tobj,r4 ;pointer to devices loop < mov (r4)+,r2 ;set the hardware object if ne,< ;if there is something there tst $vasta(r2) ;is it available? exitl mi ;yup, so use it > sorl r5 ;else try for the next mov (pc)+,r2 .string 120$: clr $cpknb(r1) call cpkaz1 ;stuff message into one packet movb #%cocls,$cpkop(r1) ;make it a close packet call cpkpko ;output it br 110$ > clr $vasta(r2) ;no longer available, no status mov $vaadd(r2),r5 mov #v8.clb,v8.pcs(r5) ;clear buffer command mov #v8cchw,$cpkpn(r1) ;window size movb #%coopn,$cpkop(r1) ;open packet call cpkpko ;output packet call v80dwn ;shut it down for good measure clr $vaeof(r2) ;no eof packets seen yet. loop < lock 5 mov $vapks(r2),r1 ;get packets that may need freeing if eq, else < clr $vapks(r2) unlock call cpkfrl > call cpkpki ;get a packet if cs,< 200$: call v80frc ;force all scans out call v80dwn ;shut down the versatec mov $vaadd(r2),r3 bis #v8.frm,v8.pcs(r3) ;issue form feed mov #%vsava,$vasta(r2) ;make it available br 110$ > if eq,< call cpkwti ;wait for an input packet rptl > tstb $cpkop(r1) ;is it data? if pl,< pushb $cpkop(r1) call cpkfre cmpb (sp)+,#%coeof if eq,< inc $vaeof(r2) cmp $vaeof(r2),#2 bge 200$ > > else ;go process the packet rptl > ;;; Process the packet v8npkt: bitb #1,$cpkop(r1) ;print or plot if eq,< ;print cmpb $vasta(r2),#%vsprn ;already in print? if ne, ;finish current set of commands movb #%vsprn,$vasta(r2) mov r1,r3 mov #v8.pcs,r5 jcall v80vso ;output the "scan line" > cmpb $vasta(r2),#%vsplt ;else plot packet if ne, movb #%vsplt,$vasta(r2) push r0,r1 tst $vacur(r2) ;is there already a scan line? if eq, ;try and get a new scan line mov $cpknb(r1),r0 ;get byte count add #$cpkdt,r1 ;point to data loop < ;real loop tst r0 ;any more packet data? exitl le ;get out if not loop < ;exit mechanism tst $vacon(r2) ;is there a continuation? if ne,< ;yup call va%ga2 ;continue argument collection exitl ;maybe finish command > dec r0 ;going to grab a byte from packet movb (r1)+,r5 if eq, if pl, call v8%skp exitl> bit #100,r5 if eq, cmpb r5,#%v8eol if eq, cmpb r5,#%v8xor if lo, if eq, cmpb r5,#%v8ma1 if lo, if eq, > tst $varem(r2) if le, rptl > pop r1,r0 jcall cpkfre **** .endc %defin .iif nz %defin, .list ;start listing as usual ;; local modes: ;; mode:midas ;; auto fill mode: ;; fill column:75 ;; comment column:32 ;; compile command: :xfile dcp;\swit compil M ;; end: