! file 'ring9s'  - with monitoring back in

!********************************
!*    emas-2900   ring interface *
!*                    handler     *
!*      file: ring8s              *
!*   date:04.feb.82               *
!*********************************
!new version to handle version 2 of TSBSP (Nov 82)

! prep options are:
!  t trace buffer
!  s stats gathering
!  f fault generation to test higher level recovery
!  k kent (if not kent assumed to be ERCC)
!  g gateway version - different service no
!  b monitor blipping (unselected with pkt count # 0)
!
!nb location k'140016 is used to hold the checksum so that it may
!be accessed from code


include  "deimosperm"
constrecord  (*) name  nil == 0




begin 

#if k
conststring (17) vsn = "ring:vsn012 (k) "
#else
conststring (13) vsn = "ring:vsn011a "
#fi
#datestring

ownintegername  no of big buff == k'060112'; ! 3 seg position
ownintegername  big buff pt    == k'060104'; !     ditto

constintegername  no of big 2 seg == k'100112'; ! for 2 seg buff man
constintegername  big buff pt 2 seg== k'100104'

constintegername  ps == k'017776';       ! processor status in seg 0






recordformat  mef(record (mef) name  link, byteinteger  len,type, integer  address, integerarray  a(0:100))

recordformat  pe(byteinteger  ser,reply,fn,port,(record (mef) name  mes, byteinteger  len,s1 orinteger  lport,hport))


!!           ring interface registers

!-----------------------------


recordformat  ringf(integer  rdata,source,sourceselect,status,tdata,dest,spare,intstat)

constrecord  (ringf) name  ring==k'004040'; ! in seg 0



!           ring command/status register bits

constinteger   busy=1
constinteger   unselected=2
constinteger   accepted=4
constinteger   ignored=8
constinteger   badpacket=16
constinteger   packet rejected=64


!ring interface status bits

constinteger   receive=1
constinteger   transmit=2
constinteger   onoff=16
constinteger   rintoff=k'40'
constinteger   rinton=k'100'
constinteger   tready=k'200'
constinteger   tintoff=k'400'
constinteger   tinton=k'1000'
constinteger   iproff=k'2000'
constinteger   ipron=k'4000'
constinteger   iptoff=k'10000'
constinteger   ipton=k'20000'
constinteger   repa=k'100000'




!byte stream command codes

constinteger   rdy=x'3000'
constinteger   notrdy=x'5000'
constinteger   reset=x'6300'
constinteger   close=x'6600'
constinteger   data=x'a000'
constinteger   nodata=x'c000'
constinteger   exp ack = x'6900'
constinteger  exp ack2 = x'6902';        !with sequence number
constinteger  exp data = x'6D00'
constinteger  exp data2 = x'6d02';       !with sequence number


!transport service command codes


constinteger   open=x'6a00'
constinteger   openack=x'6500'
constinteger   longblock=x'9000'
constinteger   longblockch=x'9000'
constinteger   longblockcs0=x'9400'
constinteger   singleshot=x'9800'



!                      incoming function codes
!                      -------------------------


!he following values may be added to the output codes

constinteger  release flag=x'80';        !release buffer at end of output
constinteger  tell flag=x'40';           !notify at end of transfer
constinteger  cs0flag=x'20'


constinteger  command mask=x'1f';        !to get command code

constinteger  enable port=0
constinteger  xdata=1
constinteger  ssout=2;                   !single shot output
constinteger  xrdy=3
constinteger  xnotrdy=4
constinteger  xnodata=5
constinteger  xclose=6
constinteger  xreset=7
constinteger  xclosereq=8
constinteger  xexprdy=9
constinteger  x disc response=10
constinteger  x reset response=11
constinteger  x disc ok=12
constinteger  x null data=13
constinteger  disable port=15
constinteger  output trace=16;           !force output of trace buffer
constinteger  xexpack=17;                !keep these in this order, all the xexp s
constinteger  xexpdata=18
constinteger  xexpack2=19
constinteger  xexpdata2=20


!                              outgoing function codes
!                                 -----------------------

constinteger  output done=0
constinteger  transfer error=1
constinteger  r input done=2
constinteger  input error=3



constinteger   timeout=2;                !number of alarm calls


!time is incremented on every alarm call, on overflow to
!zero it is set to 1 as time 0 implies time-not-set



owninteger  ntimes=0
owninteger  time


owninteger  me=0;                        !ring address

integer  t,i









!**************************************************************

!*         buffer manager calls   (from and to)               *

!**************************************************************

constinteger  buffer here = 0
!********** to buffer manager ***********

constinteger  request buffer = 0
constinteger  release buffer = 1
!****************************************************************

!********** various service numbers *************

#if k
#if g
constinteger  ring ser = 7
#else
constinteger  ring ser = 10
#fi
#else
constinteger  ring ser = 13
#fi
constinteger  buffer manager = 17
constinteger  time int = 0
constbyteinteger  tx int = -6; 
constbyteinteger  rx int = -7; 

constinteger  t3 ser = 21
!************************************************************



record (pe) p;                           !input pon record
record (pe) op;                          !output pon record

owninteger  x, no buffc;                 ! no of 'no buff'


#if s
ownintegerarray  rhist(0:6); 
owninteger  rcount; 
owninteger  ip,opkts,ints; 
owninteger  im, om, timec
#fi


#if f
owninteger  eflag = 0; 
owninteger  ecount = 0; 
#fi


owninteger  mon = 0

owninteger  intloop = 10

#if t
constinteger  tracelim = 1023; 
recordformat  tracef(byteinteger  type, integer  data); 
ownrecord (tracef) array  trace(0:tracelim); 
owninteger  tracep = 0; 
owninteger  tsent=0; 
#fi

!%ownrecord (pe) %array ptrace(0:300)
!%owninteger ptp=0

owninteger  state=0
!values of state
constinteger  closed=0;                  !before first entry
constinteger  on=1;                      !normal state
constinteger  off=2;                     !ring offline

owninteger  dstate=0;                    !dynamic state (see bits below)

!values for dstate
constinteger  idle=0
constinteger  inputting=1
constinteger  outputting=256


!data used during an input transfer
!----------------------------------

ownrecord (mef) name  inbuf
owninteger  port,csflag
constinteger  maxlen=125;                !250 bytes of data max



!data accessed in code therefore in fixed location the gla

constintegername  ics==k'140016';        !checksum
constintegername  ocs==k'140014';        ! output block checksum

!data used during output transfer
!---------------------------------

ownrecord (pe) outp
ownintegerarrayname  obuf
owninteger  dest, o pktcount, o pktlen, i tout, o tout,
          outcs, d, oretry, func;        !outcs#0 => checksum reqd

constinteger  maxretries=500;            !max number of retries of
!a single packet

!data used for input transfer

ownintegerarrayname  i buf
owninteger  i pktcount, i pktlen



!data used for port-pairs list
!-----------------------------

!each record contains a port range (low, high) and the id
!of the task that will handle input on a port in this range

recordformat  ppf(integer  lport,hport, byteinteger  reply)

constinteger  nppmax=8
ownrecord (ppf) array  ppa(1:nppmax)
owninteger  npp=0
ownrecord (ppf) name  pp



!data used for output pon queue
!------------------------------

!all the pq records are on a cyclic list, pqfirst and pqlast point
!to the head and tail of the q, npq tells how many items are on the q.



recordformat  pqf(record (pqf) name  link, record (pe) p)

constinteger  maxnpq=32
ownrecord (pqf) array  pq(1:maxnpq)
ownrecord (pqf) name  pqfirst, pqlast
owninteger  npq=0



!data defining canned commands (rdy, nodata etc.)

!data defining 'canned' byte stream commands rdy etc. the command is
!put into the array ccbuf, ccbuf(0) is the port number, ccbuf(1) is
!the receiver command set from the reccom array, and ccbuf(2) is the
!transmitter command set from trancom array. the array sindex gives the position
!in ccbuf of the sequence number if reqd.

ownintegerarray  ccbuf(0:3)

constintegerarray  reccom(xrdy:xexpdata2)=rdy,
   notrdy, 0, close, reset, 0, 0, close, reset, close, 0,
   0, 0, 0, expack, expdata, expack2, expdata2

constintegerarray  trancom(xrdy:xexpdata2)=0,
   0, nodata, x'a042', x'a042', data+6, 0, 0, 0, x'8000', data,
   0, 0, 0, 0, 0, 0, 0

constbyteintegerarray  sindex(xrdy:xexpdata2)=1,1,2,0,0,2,2,0,0,0,2,
   0,0,0,0,3,0,3

!%routinespec pont(%record (pe) %name p)
routinespec  do clock int
routinespec  end op transfer
routinespec  end ip transfer
routinespec  start input transfer
routinespec  start output transfer
#if f
routinespec  do forced error(integer  type); !$s
#fi
routinespec  do timeout(integer  type)
routinespec  freebuffer(record (mef) name  mes)
record  (mef) mapspec  getbuffer
routinespec  initialize
routinespec  input done(integer  function)
routinespec  disports
#if t
routinespec  puttrace; 
#fi

!**********************************************

!*      initialisation                        *

!**********************************************


map hwr(0);                              ! map top seg to seg 0
!     set prio(2);     !run at priority 2
i = map virt(buffer manager,4,3)
if  i=0 start ;                          ! buf man only has 2 segs
   no of big buff == no of big 2 seg
   big buff pt == big buff pt 2 seg
finish 
i = map virt(buffer manager,5,4);        ! map to my seg 4
i = map virt(buffer manager,6,5);        !and to seg 5
linkin(ring ser)
linkin(tx int); ; linkin(rx int)

change out zero = t3 ser

printstring(vsn)
#if t
printstring(" trace")
#fi
printstring(datestring); newline

initialize;                              !initialise data structures

alarm(20)

cycle 
   p_ser = 0; poff(p)
   
   if  p_ser=own id start ; 
      if  p_reply=0 start ;              !clock call
         alarm(20)
         do clock int
         
      finishelsestart ;                  !from buffer manager
!                   pont(p)
         printstring("RING:illegal message from:")
         write(p_reply,1); newline
         continue 
         
         
      finish 
      continue 
   finishelsestart 
      
      if  p_ser=ring ser start 
!                   pont(p)
         !decode 'normal' pon message
         if  p_fn=enable port start 
            if  npp>=nppmax start 
               printstring("RING:too many ports")
               newline
            finishelsestart 
               !add port pair to list
               npp = npp+1
               pp == ppa(npp)
               pp_lport = p_lport
               pp_hport = p_hport
               pp_reply = p_reply
               if  state=closed start 
                  !if this is the first entry, setup
                  !state according to the inverse of onoff
                  !so that the state change is recognised
                  
                  if  ring_intstat&onoff=0 then  state = on else  state = off
               finish 
            finish 
         finishelsestart 
            if  p_fn=disable port then  dis ports andcontinue 
            if  p_fn=output trace start 
#if t
               if  tsent=0 then  puttrace; 
               tsent = 1; 
#fi
            finishelsestart 
               !assume output request
               if  state=off start 
rel:              if  p_fn&x'7f'<xrdy start ; ! block included
                     if  p_fn&release flag#0 then  free buffer(p_mes)
                  finish 
                  continue ;             ! ignore the request
               finish 
               
               if  npq<maxnpq start ;    !put on output queue
                  pqlast == pqlast_link
                  pqlast_p = p
                  npq = npq+1
               finishelsestart 
                  printstring("RING:queue full")
                  newline
                  ->rel
               finish 
            finish 
         finish 
      finish 
   finish 
   
   
   
#if s
   if  p_ser&x'80'#0 then  ints = ints+1
#fi
   
!now cycle round a few times looking at ready bits on the ring interface
! dstate contains the dynamic state either idle, inputting or outputting
!
   i = intloop-1
!turn off all interrupts - do all io using ready bits
   
   ring_intstat = ring_intstat!(tint off+ipt off+rint off+ipr off)
   
   
   while  i<intloop cycle 
      i = i+1
      ring_intstat = ring_intstat!(tint off+ipt off+rint off+ipr off)
      
      if  dstate&outputting#0 start 
         !output packet
         !-------------
         
         if  ring_intstat&tready#0 start ; !transmitter ready
            if  ring_status&accepted#0 start ; !last transmission failed
#if b
               if  ring_status&unselected=0 and  opktcount#0 start ;  !blipped
                  printstring("ring:blip from"); write(dest,3); newline
                  do timeout(1)
                  continue 
               finish 
#fi
               if  oretry>maxretries start 
                  do timeout(1)
#if s
                  timec = timec+1
#fi
                  continue 
               finish 
               ring_intstat = ring_intstat!transmit; !send it again
               oretry = oretry+1
               i = 0
            finishelsestart 
               
#if s
               if  oretry<6 start ; 
                  rhist(oretry) = rhist(oretry)+1; 
               finishelsestart ; 
                  rhist(6) = rhist(6)+1; 
               finish ; 
               rcount = rcount+oretry; 
#fi
               
               if  o pktcount<o pktlen start 
                  
                  d = o buf(o pktcount)
                  
putout:           
#if s
                  opkts = opkts+1; 
#fi
                  o cs = o cs+d
                  *=k'005537'; *=k'140014'; !adc cs
#if t
                  trace(tracep)_type = 'o'; 
                  trace(tracep)_data = d; 
                  tracep = (tracep+1)&tracelim; 
#fi
#if f
                  if  eflag#0 then  do forced error('e'); 
#fi
                  
                  ring_tdata = d
                  
                  i = 0
                  oretry = 0
                  o pktcount = o pktcount+1
               finishelsestart 
                  if  o pktcount=o pktlen and  outcs#0 start 
                     d = o cs
                     if  outp_fn&cs0flag#0 then  d = 0
                     ->putout
                  finish 
                  !end of output transfer
                  !----------------------
end output:       
                  end op transfer
                  exitif  dstate=0;      ! force an interupt (input buffs)
               finish 
            finish 
         finish 
      finishelsestart 
         if (ring_intstat&tready#0) or (ring_intstat&onoff=0) start 
            !start up output transfer (if any)
            !----------------------------------
            if  npq#0 then  start output transfer
         finish 
      finish 
      if  dstate&inputting#0 start 
         if  ring_intstat&repa=0 thencontinue 
         
         d = ring_rdata
         
#if t
         if  inbuf_address#me start 
            trace(tracep)_type = 'i'; 
            trace(tracep)_data = d; 
            tracep = (tracep+1)&tracelim; 
         finish 
#fi
#if s
         ip = ip+1; 
#fi
         
!look to see if port field looks like a header and if so start transfer
!from here
         
!               %if i pktcount=0 %and d&x'f800'=longblock %then !                  -> start inp
         
#if f
         if  eflag#0 then  do forced error('f'); 
#fi
         
         i = 0
         if  i pktcount<i pktlen start 
            i cs = i cs+d
            *=k'005537'; *=k'140016';    ! adc cs
            ring_intstat = ring_intstat!receive
            i buf(i pktcount) = d
            i pktcount = i pktcount+1
         finishelsestart 
            !end of input transfer
            !-----------------------
            end ip transfer
            exitif  dstate=0;            ! force it to do a poff (input buffers)
         finish 
      finishelsestart ;                  ! dstate=idle
         if  ring_intstat&repa#0 start 
            !start input transfer
!                                  !--------------------
start inp:  
            start input transfer
            i = 0
         finish 
      finish 
   repeat 
   
   !need to switch interrupts back on
   ring_intstat = ring_intstat!rinton
 
!now look to see if in middle of an output transfer - this implies
!we haven't seen the mini-packet come back. Either intloop is too small
!or the ring has gone down
   if  dstate&outputting#0 start 
      if  ring_intstat & onoff = 0 start 
         do timeout(1);     !abort the output transfer
      else 
         ring_intstat = ring_intstat!tinton; !enable output interrupts
         intloop=intloop+4;      !increase intloop so it shouldn't happen again
         printstring("Ring:reschedule during output transfer")
         printstring(" intloop now=");   write(intloop,1); newline
      finish 
   finish 
   
repeat 





routine  input done(integer  function)
!-------------------
   
!find out who wants input to this port
   
   
   integer  port,i,xx
   record (ppf) name  pp
   
   
   xx = 0;                               ! compiler bug forces this !
   port = i buf(xx)
   cycle  i = npp,-1,1
      pp == ppa(i)
      if  pp_lport<=port<=pp_hport start 
         op_ser = pp_reply
         op_reply = ring ser
         op_fn = function
         if  function=r input done start 
            op_mes == inbuf
!             pont(op)
            pon(op)
            inbuf == nil
         finishelsestart 
!            pont(op)
            pon(op)
         finish 
         return 
      finish 
      
   repeat 
!nobody wants the input
   printstring("RING:input rejected ")
   write(port,3); write(inbuf_address,3)
   newline
   
end 



routine  do clock int
!--------------------
   integer  i
   time = time+1
   if  time=0 then  time = 1;            !time=0 => time not set
   
   
   
   if  ring_intstat&onoff=0 start 
      
      if  dstate&outputting#0 then  do timeout(1)
      if  dstate&inputting#0 then  do timeout(0)
      if  state=on start 
         printstring("****************** ring switched off")
         newline
         state = off
      finish 
   finishelsestart 
      if  state=off start 
         !calculate my ring address
         !turn off all interrupts
         
         ring_intstat = ring_intstat!(tint off+ipt off+rint off+ipr off)
         while  me=0 cycle 
            cycle  i = 1,1,254
               ring_sourceselect = i
               ring_intstat = ring_intstat!receive
               ring_dest = i
               ring_tdata = x'f0f0'
               while  ring_intstat&tready=0 cycle 
                  if  ring_intstat&onoff=0 then  ->out
               repeat 
               if  ring_intstat#0 and  ring_rdata=x'f0f0' then  me = i andexit 
            repeat 
         repeat 
         printstring("ring online")
         write(me,3)
         newline
         for  i = 1,1,3 cycle ;          !send 3 pkts to invalid
            ring_dest = 1; ring_tdata = 16_f0f0
            while  ring_intstat&tready=0 cycle ; repeat 
         repeat 
         !now count how long it takes
         i = 0
         ring_tdata = 16_f0f0
         while  ring_intstat&tready=0 cycle 
            i = i+1
         repeat 
!the loop takes 16usecs so the ring cycle time is equal to i*16/18 usecs
         printstring("Ring cycle=")
         write(i*16//18,3); printstring(" microsecs"); newline
         state = on
         
         !initialize ring interface
         ring_intstat = ring_intstat!(receive+iproff+iptoff+rinton)
         ring_sourceselect = -1
      finish 
   finish 
   
out:
   
   if  'M'<=int<='P' start 
      mon = int-'O'; int = 0
   finish 
   if  int='?' start 
      int = 0
      printstring("o/p queued ="); write(npq,1); newline
   finish 
   
   
   x = x+1; 
   if  x>=150 start ; !every minute with alarm(20) set
      x=0;
      if  no buffc#0 start 
         printstring("RING: No buffer count =")
         write(no buffc,1); newline
         no buffc = 0
      finish 
      
#if s
      if  mon>0 start ; 
         select output(1)
         printstring("RING:"); 
         write(rcount,5); 
         cycle  i = 0,1,6; 
            write(rhist(i),4); 
         repeat ; 
         write(ip,4); 
         write(opkts,4); 
         write(ints,4); 
         write(im,5); 
         write(om,1); 
         write(timec,1); 
         newline; 
         select output(0);               !$s
      finish ; 
      im = 0; 
      om = 0; 
      rcount = 0; 
      x = 0; 
      ip = 0; 
      opkts = 0; 
      ints = 0; 
      cycle  i = 0,1,6; 
         rhist(i) = 0; 
      repeat ; 
#fi
   finish ; 
   
#if f
   if  int='E' start ; 
      eflag = (eflag+1)&1; 
      printstring("eflag="); 
      write(eflag,1); 
      newline; 
      int = 0; 
   finish ; 
#fi
   
   
#if t
   if  int='H' start 
      intloop = (intloop+1)//2
      printstring("intloop="); write(intloop,1); newline
      int = 0
   finish 
   if  int='D' start 
      intloop = intloop*2
      printstring("intloop="); write(intloop,1); newline
      int = 0
   finish 
   if  int='T' start ; 
      puttrace; 
      int = 0; 
   finish ; 
#fi
   
#if t
   !                trace(tracep)_type='s';
   !                trace(tracep)_data=time;
   !                 tracep=(tracep+1) & tracelim;
#fi
   
   
   if  i tout#0 and  time-i tout>timeout then  do timeout(0)
   if  o tout#0 and  time-o tout>timeout then  do timeout(1)
end 

routine  end op transfer
!-----------------------
   dstate = dstate&(¬outputting)
   o tout = 0
   if  outp_fn&release flag#0 then  freebuffer(outp_mes)
   if  outp_fn&tell flag#0 start 
      op_ser = outp_reply
      op_reply = ring ser
      op_fn = output done
      pon(op)
   finish 
end 

routine  end ip transfer
!-----------------------
   ring_sourceselect = -1
   ring_intstat = ring_intstat!receive
   if  csflag#0 then  i cs = 0;          !zero checksum reqd.
   if  d=i cs start 
      input done(r input done)
   finishelsestart 
      printstring("RING:checksum fail from ")
      write(inbuf_address,3)
      write(d,3); write(i cs,3); newline
   finish 
   i tout = 0
   dstate = dstate&(¬inputting)
end 

routine  start input transfer
!----------------------------
   d = ring_rdata
#if t
   if  ring_source#me start 
      trace(tracep)_type = 'i'; 
      trace(tracep)_data = d; 
      tracep = (tracep+1)&tracelim; 
   finish 
#fi
   if  d&x'f800'=longblock start 
      csflag = d&x'400'
      i pktlen = d&x'3ff'+2
      if  i pktlen>maxlen start 
         printstring("Ring: block too long (")
         write(i pktlen,-1); printstring(") from ")
         write(ring_source,-1); newline
         -> skip
      finish 
      i pktcount = 0
      if  inbuf==nil start ;             !$e - kent fault
         inbuf == get buffer;            ! grab a buffer from buf man
         if  inbuf==nil start 
            no buffc = no buffc+1
skip:       
            ring_intstat = ring_intstat!receive
            return 
         finish 
#if s
         im = im+1
#fi
      finish 
      inbuf_len = i pktlen-2
      i buf == inbuf_a
      inbuf_address = ring_source
      ring_sourceselect = ring_source
      ring_intstat = ring_intstat!receive
      dstate = dstate!inputting
      i cs = d
      i tout = time
      return 
   finish 
   ->skip
end 

routine  start output transfer
!-----------------------------
   outp = pqfirst_p
   pqfirst == pqfirst_link;              !remove record
   npq = npq-1;                          !from output q
   func = outp_fn&command mask
#if s
   om = om+1; 
#fi
   if  func=ssout start ;                !single shot block
      dest = outp_mes_address
      o pktcount = 1
      o buf == outp_mes_a
      o pktlen = outp_mes_len
      if  o pktlen=0 start 
         end op transfer
         return 
      finish 
      
      o cs = o buf(0);                   !first packet
      outcs = 0;                         !no checksum
   finishelsestart 
      if  func<xrdy start 
         !output given buffer
         !-------------------
         dest = outp_mes_address
         o buf == outp_mes_a
         o pktlen = outp_mes_len+2
      finishelsestart 
         !output byte stream command
         !----------------------------
         dest = outp_len
         o pktlen = 3
         ccbuf(0) = outp_lport
         ccbuf(1) = reccom(func)
         ccbuf(2) = trancom(func)
         o buf == ccbuf
         !see if sequence number reqd
         i = sindex(func)
         if  i=3 then  ccbuf(3) = 0 and  opktlen = 4; !exp data
         if  i#0 then  ccbuf(i) = ccbuf(i)+(outp_s1<<8); !add in sequence
         
      finish 
      o cs = longblockch+o pktlen-2
      if  outp_fn&cs0flag#0 then  o cs = o cs!longblockcs0
      outcs = 1;                         !checksum reqd
      o pktcount = 0
   finish 
   ring_dest = dest
   
   
   ring_tdata = o cs
#if t
   trace(tracep)_type = 'o'; 
   trace(tracep)_data = o cs; 
   tracep = (tracep+1)&tracelim; 
#fi
   oretry = 0
   o tout = time
   dstate = dstate!outputting
   i = 0
end 

#if f
routine  do forced error(integer  type); !$s
!---------------------------------------
   ecount = ecount+1; 
   if  ecount>1000 start ; 
      d = d+1; 
      ecount = 0; 
#if t
      trace(tracep)_type = type; 
      trace(tracep)_data = 0; 
      tracep = (tracep+1)&tracelim; 
#fi
   finish ; 
end 
#fi

routine  do timeout(integer  type)
!----------------
   
   
   
   if  type=1 start ;                    ! outputting timeout
      o tout = 0
#if s
      timec = timec+1
#fi
      if  mon<0 start 
         printstring("RING:output timeout to")
         write(dest,3); newline
      finish 
      op_ser = outp_reply
      op_reply = ring ser
      op_fn = transfer error
      op_port = outp_port
!       pont(op)
      pon(op)
      if  outp_fn&release flag#0 then  freebuffer(outp_mes)
      dstate = dstate&(¬outputting)
   finishelsestart 
      ! must be input timeout
      !send message if port number has been input
      i tout = 0
      if  i pktcount>0 then  inputdone(input error)
      
!return the input buffer
      unless  inbuf==nil start 
         printstring("RING:Input Timeout from")
         write(inbuf_address,3); newline
      finish 
      
      ring_intstat = ring_intstat!receive
      ring_sourceselect = -1
      dstate = dstate&(¬inputting)
   finish 
   
#if t
   trace(tracep)_type = 'x'; 
   trace(tracep)_data = 0; 
   tracep = (tracep+1)&tracelim; 
#fi
   
   
end 


routine  initialize
!------------------
   integer  i
   
!initialise pon q as cyclic list
   pqfirst == pq(1)
   pqlast == pq(maxnpq)
   cycle  i = 1,1,maxnpq-1
      pq(i)_link == pq(i+1)
   repeat 
   pq(maxnpq)_link == pq(1)
   npq = 0
   
end 



routine  freebuffer(record (mef) name  mes)
!-----------------------------------------------
   
   
   record  (pe) p
   integer  x
   if  mes_type # 0 start ;              !small buffer
      p_ser = buffer manager
      p_reply = own id
      p_fn = release buffer
      p_mes == mes
      pon(p)
      return 
   finish 
!big buffer connected directly back into buff mans free chain
   mes_type = mes_type ! 1;              !buffer free flag
   ps = ps!k'340';                       ! put processor status = 7
   no of big buff = no of big buff+1
   x = addr(mes)+k'20000';               ! addr wrt buffer manager vm
   integer(addr(mes)) = big buff pt;     ! copy in top of chain
   big buff pt = x;                      ! and remake 1st entry
   ps = ps&(¬k'340');                    ! and allow ints again
end 


record  (mef) map  getbuffer
!-----------------

integer  x
record  (mef) name  mes
ps = ps!k'340';                          ! stop processor interrupts
if  no of big buff>5 start ;             ! leave some (no queuing done)
   no of big buff = no of big buff-1
   x = big buff pt;                      ! get buffer managers free pointer
   x = x-k'20000';                       ! make it my vm (my seg 3 = bm seg 4)
   big buff pt = integer(x);             ! copy rest of free queue
   ps = ps&(¬k'340');                    ! allow ints again
   mes == record(x)
   mes_type = mes_type & (8_376);        !remove 'free' buffer bit
   result  == record(x);                 ! and pass back result
finish 
ps = ps&(¬k'340')
result  == null

end 




routine  disports;                       !disable port by removing
!-----------------                        !from port pairs list

integer  i,j

cycle  i = 1,1,npp
   pp == ppa(i)
   if  pp_lport=p_lport and  pp_hport=p_hport and  pp_reply=p_reply start 
      cycle  j = i,1,npp-1
         ppa(j) = ppa(j+1)
      repeat 
      npp = npp-1
      return 
   finish 
repeat 
end 




#if t
routine  addvchar(string  (*) name  s, integer  c)
!-------------------------------------------------
   if  c<32 or  c>126 then  c=' '
   length(s)=length(s)+1
   charno(s, length(s))=c
end 

routine  puthex(integer  d, string  (*) name  vstr)
!-------------------------------------------------

integer  i; 
byteinteger  s; 

printsymbol(' '); 
cycle  i = 12,-4,0; 
   s = (d>>i)&x'f'; 
   if  s>9 then  s = s-'0'+'a'-10; 
   printsymbol(s+'0'); 
repeat ; 
addvchar(vstr, d>>8)
addvchar(vstr, d & 16_ff)
end ; 





routine  put visi chars(string  (*) name  s, integer  c)
!-------------------------------------------------------
   if  c=0 then  return 
   spaces( (16-c)*5+2 )
   printstring(s);  newline
end 

routine  puttrace; 
!----------------;

integer  tplast,tp,tc; 
string  (32) vstr;                       !visible char form
integer  ty,type; 

tc = 0; 
vstr = ""
tp = (tracep+1)&tracelim; 
selectoutput(1); 
type = 0; 
cycle ; 
   ty = trace(tp)_type; 
   if  ty#0 start ; 
      trace(tp)_type = 0; 
      if  ty#type start ; 
         put visi chars(vstr, tc)
         printstring("******** "); 
         printsymbol(ty); 
         tc = 2; 
         vstr="    "
         type = ty; 
      finish ; 
      if  tc>=16 start 
         put visi chars(vstr, tc)
         vstr=""
         tc = 0
      finish 
      puthex(trace(tp)_data, vstr);     !save visible chars in vstr
      tc = tc+1; 
   finish ; 
   tp = (tp+1)&x'3ff'; 
repeatuntil  tp=tracep; 
newline; 
printstring("end of trace"); 
newline; 

closeoutput
selectoutput(0); 
printstring("done"); 
newline; 

end ; 
#fi
!%routine pont(%record (pe) %name p)
!   ptrace(ptp)=p
!   ptp=ptp+1
!   %if ptp>300 %then ptp=0
!%end
endofprogram