! ! Ring handler for KMC11 ! DATE 23.nov.81 ! ! $list 1 $def flag=sp0, rstatl=sp1, rstath=sp2, rxstate=sp3, txstate=sp4 $def itim = sp5, rxhigh=sp6, rxmid=sp7, rxlow=sp8 $def otim = sp9, txhigh=sp10, txmid=sp11, txlow=sp12 $def temp=sp13, temp1=sp14, time = sp15 ! sp5, sp9 & sp15 are spare ! $def idatal = adr0, idatah = adr1, odatal = adr2, odatah = adr3 $def ibusl = adr4, ibush = adr5, obusl = adr6, obush = adr7 ! $def nprreq=npr.0, nonexmem=misc.0, timeout=misc.4, settime = 16_10 $def bits1617 = 16_0c $def intson=csr0.0, rxints=csr0.1, reqi11 = csr0.4, oack = csr0.7 $def rfn = csr2.0, kmcreq = csr3.4, gobit = csr2.7 $def rxreply = 16_10; ! kmcreq+fn=0 $def txreply = 16_11; ! kmcreq+fn=1 $DEF rtin=16_0d, rtout = 16_11, npri = 1 ! $def rdata = 16_20, source = 16_22, ssel = 16_24, status = 16_26 $def tdata = 16_28, dest = 16_2a, intsta = 16_2e, topseg = 16_e8 $def bmask = 63, maxret = 254 ! ring status bits $def accepted = 4 ! ring interface status bits $def receive = 1, transmit = 2, onoff = 16, tready = rstatl.7, repa = rstath.7 ! packet header definitions $def lblch = 16_90; ! long block with checksum $def lblnch = 16_94; ! long block - no checksum ! ! states $def idle = 0, starting = 1, going = 2, ending = 3, end2 = 4, waiting = 5, signal = 6 ! $data 0 retries: 0; ! no of retries on output opktl: 0; ! output packet - actual length opktc: 0; ! output packet - words gone so far ocsl: 0; ! output checksum - low byte ocsh: 0; ! - high byte txflag: 0; ! ok/failed flag, 0 = ok csifl: 0; ! input checksum flag ipktl: 0; ! input packet - actual len ipktc: 0; ! inpu packet - data so far icsl: 0; ! checksum - low byte iclh: 0; ! - high byte rxflag: 0; ! ok/failed flag failvl: 0; ! low byte of failed word failvh: 0; ! high byte failcl: 0; ! no of 'no buffer' - low byte failch: 0; ! - high byte rxget:0; !rx buffer q get ptr rxput:0; !rx buffer q put ptr txget:0; !tx buffer q get ptr txput:0; !tx buffer q put ptr rxbase:0; !rx buffer desc area $data @+bmask txbase:0; !tx buffer desc area $data @+bmask ! ! now the macros ! p o p ! this macro copies the top request into the scratch pad registers ! it does not delete the request, which is held for reply to pdp11 $macro pop xx temp=xxget mar=temp+#xxbase; !addr of next buff info xxhigh=memory, mar=mar+1; !load bit 16/17 xxmid=memory, mar=mar+1; ! bit 8-15 xxlow=memory; ! bit 0-7 xxlow = xxlow+2; ! step pointer on to "len" in buffer xxmid = xxmid+2 if c; ! allow for partial overflow xxstate = starting; ! buffer now ready for use $end ! ! ! set csrS for message to 11, and advance get pointer ! memory contains:- bits 17&18, 8-15, 0-7 and a dummy $macro ended xx temp=xxget mar=temp+#xxbase; ! point at mid/low address (eventually) temp1 = xxreply, mar = mar+1; ! fn type & kmc req set (mar->mid) csr6=memory, mar=mar+1; ! put address back in kmc 'out' address csr7=memory, mar=mar+1 csr3 = temp1!xxflag; ! add in flag temp=temp+4 temp=temp&bmask xxget=temp xxstate = signal; ! wait for pdp11 to respond $end ! ! ! update put pointer for buffer descriptor queue ! and empty csr request into queue $macro use xx temp = xxput mar = temp+#xxbase; ! point mar at next 'hole' temp1 = csr2; ! only want ext bits memory = temp1&16_06, mar = mar+1; ! get extension bits memory = csr5, mar = mar+1; ! get xxmid memory = csr4, mar = mar+1; ! get xxlow memory = 0; ! dummy just now temp1=temp+4 xxput=temp1&bmask $end ! ! $macro waitnpr cycle; repeat if nprreq $end ! g e t 1 1 w - get the next word out of a pdp11 buffer $macro get11w adr5 = txmid adr4 = txlow; ! move in buffer address npr = txhigh!npri; ! bits 17&18 + go txlow = txlow+2; ! step buffer pointer if c; ! allow for overflows txmid = txmid+2 txhigh = txhigh+4 if c finish waitnpr $end ! p u t 11 w ! - put a word into a pdp11 buffer $macro put11w obusl = rxlow; obush = rxmid; ! transfer from ring -> pdp11 misc = flag!rxhigh; ! now bits 16&17 npr = rtout; ! start the transfer rxlow = rxlow+2; ! step the address if c rxmid = rxmid+1; ! do overflows rxhigh = rxhigh+4 if c; ! including bits 16&17 finish waitnpr $end ! r e a d param ! - read a unibus location $macro read xxx adr4 = xxx; adr5 = topseg npr = rtin; ! do the npr transfer cycle; repeat if nprreq $end ! w r i t e param ! - write into a unibus location $macro write xxx adr7 = topseg adr6 = xxx misc = flag!bits1617 npr = rtout cycle; repeat if nprreq $end $macro openring brg = 16_ff obusl = brg; obush = brg; ! set + -1 write ssel $end ! brg = 0 flag = brg; ! initial state of misc rxstate = brg; txstate = brg csr0 = brg; csr2 = brg; csr3 = brg read intstat ! check ring is on the bus cycle; repeat if nonexmem; ! loops here if isn't ! cycle top: if reqi11; ! 11 is requesting service if rfn = 0; ! is read function use rx else use tx ! otherwise is output buffer finish csr2 = 0; ! clear csr2 to indicate done cycle; repeat if reqi11; ! wait for pdp11 to clear request finish if kmcreq; ! kmc is waiting for 11 to take info if oack; ! 11 has acked csr3 = 0; ! clear kmcreq cycle; repeat if oack; ! wait for 11 to see req dropped if rxstate = signal; ! was an rx request rxstate = idle; ! so idle it jump sigtx if txstate = waiting ! do next one immediately if available else; ! must have been tx txstate = idle jump sigrx if rxstate = waiting finish finish finish ! check for state = idle and a request pending if txstate = idle; ! ready to go temp = txget, mar = mar+1; ! if txget # txput if temp # memory pop tx finish finish if rxstate = idle; ! receive ready to go temp = rxget, mar = mar+1; ! if rxget # rxput if temp # memory ! openring pop rx finish finish jump top if timeout = 0; ! only check the ring once every 50msecs ! end of bit fiddling in the interface, now check the ring read intstat rstatl = idatal; rstath = idatah; ! hold ring intstatus jump doinput if txstate = idle or txstate > waiting; ! nothing to do (executes >=) ! tx is active - check if can proceed if tready; ! ready bit up ? jump start if txstate = starting read status temp = idatal temp = temp&4 if temp = 4; ! (really not accepted) temp1 = retries; ! loads mar automatically jump txfail if temp1 > maxret memory = temp1+1; ! add 1 to retry count adr2 = rstatl!transmit; ! send it again odatah = rstath; ! and high byte write intstat jump doinput finish if txstate = end2; ! had to wait for cksm gone ack txstate = txstate+1; ! state = ending jump doinput; ! nothing actually to go finish ! send the next word now start: mar = #retries; ! all of them need access to varbs memory = 0, mar = mar+1; ! clear retriesand point mar at opktl get11w ! the the next word from the pdp11 buffer ! nb: when 1st setting up buffer addrs, +2 must ! be added to txlow, to point at len if txstate = starting temp1 = adr0; ! save len for 1st ring pkt temp = temp1+2; ! actual len of packet (words) memory = temp, mar = mar+1; ! save in opktl memory = 0, mar = mar+1; ! zero opktc memory = 0, mar = mar+1; ! checksum - low byte memory = 0, mar = mar+1 ! - high byte memory = 0; ! and flag get11w ! get dest csr6 = idatal; ! for diagnostics only odatal = idatal; odatah = idatah; ! copy to out npr write dest ! write out ring_dest txstate = txstate+1; ! txstate = going adr2 = temp1; adr3 = lblnch; ! length+long block flag - no checksum else if txstate = going; ! adr0 & 2 contain next word to go temp = memory, mar = mar+1; ! pick up opktl temp1 = memory; ! pick up opktc temp1 = temp1+1 memory = temp1; ! put back new opktc txstate = txstate+1 if temp=temp1; ! state=ending if c=l !! add o cs adr2 = adr0; adr3 = adr1; ! move 11 word to out npr else; ! state must be ending mar = #ocsl; ! state must be ending adr2 = memory, mar = mar+1 adr3 = memory otim = txstate; ! temp for testing txstate = txstate+1; ! state = waiting finish ! now write out the ring word write tdata finish doinput: ! now look to see if anything to be done on the input side ! rstat l&h contain intstatus if repa; ! get status & see if packet present if rxstate=idle or rxstate>waiting; ! executes >= temp = failcl; ! get fail count memory = temp+1, mar = mar+1; ! put it back if c temp = memory; ! get high byte memory = temp+1; ! overflow finish jump recnext; ! simply ignore if in the wrong state finish read rdata ! get the ring packet (all need it) if rxstate = starting; ! 1st packet temp = adr1; ! check type of block temp1 = temp&16_f8 jump rxfail if temp1 # lblch; ! not a normal block csifl = temp&4, mar = mar+1; ! remember checksum type temp1 = temp&3; ! pickup the top bits of length jump rxfail if temp1 # 0; ! length too big brg = adr0; ! pickup low byte odatal = brg; temp = brg; ! and put in o npr and temp odatah = 0 put11w ! put the length into the buffer temp = temp+2; ! actual length of packet jump recnext if temp > 125; ! >maxlen of packet memory = temp, mar = mar+1; ! store in ipktl memory = 0, mar = mar+1; ! no actual data so far memory = 0, mar = mar+1; ! low byte of checksum (till checksum used !!!) memory = 0, mar = mar+1; ! high byte of checksum memory = 0; ! success flag read source odatal = idatal; odatah = idatah; ! move source to o npr write ssel put11w ! put source into sourceselect and pdp11 buf rxstate = rxstate+1 else if rxstate = going temp = ipktl, mar = mar+1; ! pickup packet len (mar then to c) temp1 = memory; ! temp1 = ipktc temp1 = temp1+1 memory = temp1, mar = mar+1; ! ipktc = ipktc+1 rxstate = rxstate+1 if temp1 = temp; ! state=ending if ipktc=ipktl ! should add checksum here !!!!!!!!!!!!!!! odatal = idatal; odatah = idatah; ! move the input ring word.... put11w ! and write it to pdp11 buffer else; ! (ending) deal with the checksum ! check the checksum here ! rxstate = rxstate+2; ! state = waiting finish recnext: adr3 = rstath adr2 = rstatl!receive; ! _intstat = _intstat!receive write intstat finish; ! if repa = 0 ! now check to see if kmc->11 channel is busy and..... ! if not, if either rx or tx is 'waiting' to use it chkkmc: if kmcreq = 0; ! ready to be used if rxstate = waiting; ! more priority to rx sigrx: ended rx jump doint else if txstate = waiting; ! cant do both together sigtx: ended tx doint: if intson; ! sigal int to 11 if ints enabled misc = 16_80; ! nb: only one int used finish finish finish time = time+1; ! keep a 8 bit count of time time = time+1 if c; ! do not use time=0 misc = flag!settime; ! start timer again repeat rxfail: rxflag = 16_80, mar = mar+1; ! set fail flag memory = idatal, mar = mar+1; ! hold word for debugging memory = idatah rxstate = waiting jump chkkmc txfail: txflag = 16_80; ! mark failed txstate = waiting jump chkkmc