!
! c.s. link handler for kmc11  -  gjb 28/06/78
!
!
! kmc11 program to perform block transfers between pdp-11 and
! c.s. department nine bit link.  buffers are passed, using the
! csrS as follows :-
!    (1) pdp-11 -> kmc11
!        (a) pdp-11 sets csr0.4 (csr request)
!        (b) kmc11 sets csr2.1 (csr grant) after arbitrary delay
!        (c) pdp-11 loads buffer info :
!            csr2.0 = 0 (rx buff), 1 (tx buff)
!            csr2.2/3 = bit 16/17 of address
!            csr3 = length (in words)
!            csr2.7 = extra byte marker
!            csr4/5 = bit 0-15 of address
!        (d) pdp-11 resets csr0.4
!    (2) kmc11 -> pdp-11
!        (a) kmc11 loads buffer info, as above
!        (b) kmc11 sets csr2.4 (data ready)
!
! csr0.0 and csr0.1 enable tx and rx interrupts, respectively
!
! the following error situations can occur :-
!    (1) more than 16 rx or tx buffers sent ahead by pdp-11
!        action : wrap-around, generally non-fatal, but
!                 results in 16 'lost' buffers
!    (2) invalid memory address for buffer
!        action : kmc11 hangs (non-ongoing)
!    (3) tx error
!        action : retry until successful
!
! two versions of link protocol are catered for :
  $def fancy=1;  ! two null bytes precede message, and final byte has bit9
                 ! for pdp 11/34  <->  fep
  $def simple=2; ! no header, eot char terminates
                 ! for pdp 11/40  <->  isys
! selected by :-
  $def lktype=fancy
!
!
$def flag=sp0, highb=sp1, lowb=sp2, rxstate=sp3, txstate=sp4
$def rxcount=sp5, rxhigh=sp6, rxmid=sp7, rxlow=sp8
$def txcount=sp9, txhigh=sp10, txmid=sp11, txlow=sp12
$def temp=sp13, temp1=sp14, link=sp15
$def nprreq=npr.0, nonexmem=misc.0, timeout=misc.4
$def txints=csr0.0, rxints=csr0.1, req11=csr0.4
$def dev=csr2.0, grant=csr2.1, ready=csr2.4, ready1=brg.4
$def bit1617=16_0c, bbit1617=16_8c, rx=0, tx=1
$def crxrdy=16_10, ctxrdy=16_11, cgrant=16_02, cready=16_80
$def rxrdy=adr0.7, txrdy=adr0.7, rxeot=adr1.0, txerr=adr1.7
$def extrabyte=txhigh.7, cextra=16_80
$def normal=0, eot=1
$def idle=0, first=1, second=2, low=3, high=4, term=5, seven=7
$def rtout=16_11, rtin=16_0d, clock=16_10, int=16_80, vector=16_40
$def rthigh=16_0c, rtmid=16_ff
$def rslow=16_68, rdlow=16_6a, tslow=16_6c, tdlow=16_6e
$def bmask=63, eotch=4
!
$data 0;                                           !#rsw must = 0
rsw:0, rx1, rx2, rxlo, rxhi
tsw:0, tx1, tx2, txlo, txhi, txterm
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
!
!
! pop buffer descriptor from queue
$macro pop rt
      temp=rtget
      mar=temp+#rtbase;                         !addr of next buff info
      rthigh=memory,   mar=mar+1;               !load bit 16/17
      rtmid=memory,   mar=mar+1;                !     bit 8-15
      rtlow=memory,   mar=mar+1;                !     bit 0-7
      rtcount=memory;                           !     length
$if rtstate=txstate
         txcount=txcount+1 if extrabyte
$finish
$end
!
!
! set csrS for message to 11, and advance get pointer
$macro ended rt
      temp=rtget
      mar=temp+#rtbase
      temp1=memory, mar=mar+1
      csr5=memory, mar=mar+1
      csr4=memory, mar=mar+1
      $if rtstate=rxstate
      if rxstate=low
         rxcount=rxcount+1
         temp1=temp1!cextra
      finish
      rxlow=memory
      csr3=rxlow-rxcount
      $finish
      csr2=temp1!crtrdy
      temp=temp+4
      temp=temp&bmask
      rtget=temp
      if temp=rtput
         rtstate=idle
      else
         rtstate=first
      finish
$end
!
!
! update put pointer for buffer descriptor queue
$macro accept rt
   rtstate=rtstate+1 if rtstate=idle
   temp=rtput
   temp1=temp+4
   rtput=temp1&bmask
   mar=temp+#rtbase
$if lktype=fancy
   temp=csr2
$finish
$end
!
!
rxstate=0;   txstate=brg;                          !rx and tx in idle state
adr3=brg;   adr2=brg
misc=rthigh
adr7=rtmid;   adr6=rslow
npr=rtout;                                         !zero rx status word
cycle;   repeat if nprreq
adr6=tslow
npr=rtout;                                         !zero tx status word
cycle;   repeat if nprreq
cycle;   repeat if nonexmem;                       !rx or tx gone missing

cycle;                                             !main polling loop
   temp=flag&vector
   misc=temp!clock;                                !start clock

   if grant and req11=0;                  !message from eleven
      link=3
      jump from11
rtn3:
   finish

   if rxstate#idle;                                !read rx status if not idle
      adr5=rtmid;   adr4=rslow
      npr=rtin
   finish
   csr2=cgrant if req11 and grant=0 and ready1=0;  !eleven wants csrS

   cycle;   repeat if nprreq
   if rxstate#idle and rxrdy;                      !rx has data ready
      adr4=rdlow
      npr=rtin;                                    !read it
      mar=rxstate
      cycle;   repeat if nprreq
      jump memory;                                 !switch on rx state
  rx1:pop rx
  rx2:
$if lktype=fancy
      temp=adr0;   temp1=adr1;                     !first two chars
      if temp=0 and temp1=0;                       !null char
         rxstate=rxstate+1
         jump endrx
      finish
$finish
      rxstate=low
 rxlo:lowb=adr0;                                   !low byte received
$if lktype=fancy
      if rxeot=0;                                 !not final byte
         rxstate=rxstate+1
         jump endrx
      finish
$else
      if lowb#eotch;                              !not final byte
         rxstate=rxstate+1
         jump endrx
      finish
$finish
 rxhi:brg=flag&vector;                             !high byte received
      misc=rxhigh!brg
      adr7=rxmid;   adr6=rxlow
      adr3=adr0;   adr2=lowb
      npr=rtout;                                   !write high.low to buffer
      rxcount=rxcount-1
      rxlow=rxlow+2;                               !update buff get ptr
      if c
         rxmid=rxmid+1
         rxhigh=rxhigh+4 if c
      finish
      cycle;   repeat if nprreq
      cycle;   repeat if nonexmem;                 !non-existent buffer
$if lktype=fancy
      if rxeot=0 and rxcount#0;                    !not final byte
         rxstate=low
         jump endrx
      finish
$else
      temp=adr0
      if temp#eotch and rxcount#0;               !not final byte
         rxstate=low
         jump endrx
      finish
$finish
      if grant;                                    !eleven has csrS
         cycle;   repeat if req11;                 !wait for message
         link=2
         jump from11
      finish
      cycle;   repeat if ready;                    !kmc has csrS
 rtn2:
      ended rx
      if rxints;                                   !rx ints on
         misc=int
         flag=0
      else
         flag=2;                                   !mark non-int rx rdy
      finish
endrx:finish
!
!
   if txstate#idle;                                !read tx status if not idle
      adr5=rtmid;   adr4=tslow
      npr=rtin
   finish
   if ready;                                       !check if ready ...
      brg=flag&csr0;                               ! ... and ints reenabled
      if brg.0
         misc=int!vector
         flag=vector
      else if brg.1
         misc=int
         flag=0
      finish
   finish
!
   jump 256 if nprreq=0;                           !jump to page one
   jump .-3
$ctrl 256;                                         !must reside in page 1
   if txstate#idle and txrdy;                      !tx has sent data
      if txerr;                                    !tx error
         adr4=tdlow
         adr2=2
         npr=rtout;                                !retransmit
         cycle;   repeat if nprreq
         jump endtx
      finish
      mar=txstate+#tsw
      jump memory;                                 !switch on tx state
  tx1:pop tx
  tx2:
$if lktype=fancy
      adr2=0;   adr3=brg;                          !first two (null) chars
      txstate=txstate+1
      jump send
$finish
 txlo:adr5=txmid;   adr4=txlow;                    !low byte
$if lktype=fancy
      temp=txhigh&bit1617
      npr=temp+1
$else
      npr=txhigh+1;                                !read word from buffer
$finish
      txcount=txcount-1
      txlow=txlow+2;                               !update buff get ptr
      if c
         txmid=txmid+1
         txhigh=txhigh+4 if c
      finish
      cycle;   repeat if nprreq
      cycle;   repeat if nonexmem;                 !non-existent buffer
      highb=adr1
      adr3=0;   adr2=adr0
$if lktype=fancy
      jump txtst if extrabyte
      txstate=high
$else
      temp=brg
      if temp=eotch
         txstate=term
      else
         txstate=high
      finish
$finish
      jump send
 txhi:adr2=highb;                        !high byte
$if lktype=fancy
txtst:if txcount=0;                                !final byte
         txstate=term
         adr3=eot;                                 !set bit nine
      else
         txstate=txstate!!seven
         adr3=normal
      finish
$else
      if txcount=0 or highb=eotch
         txstate=txstate+1
      else
         txstate=txstate-1
      finish
      adr3=normal
$finish
 send:temp=flag&vector
      misc=temp!rthigh
      adr7=rtmid;   adr6=tdlow
      npr=rtout;                                   !write to tx data word
      cycle;   repeat if nprreq
      jump endtx
txterm:if grant;                                   !done - but eleven has csrS
         cycle;   repeat if req11;                 !wait for message
         link=4
         jump from11
      finish
      cycle;   repeat if ready;                    !kmc has csrS
 rtn4:
      ended tx
      if txints;                                   !tx ints on
         misc=int!vector
         flag=vector
      else
         flag=1;                                   !mark non-int tx rdy
      finish
endtx:
!
   finish
   cycle;   repeat if timeout=0;                   !until 50 microsecs elapsed
repeat
!
!
from11:if dev=rx;                                  !handle eleven's message
   accept rx
$if lktype=fancy
   memory=temp&bit1617,   mar=mar+1
$finish
else
   accept tx
$if lktype=fancy
   memory=temp&bbit1617,   mar=mar+1
$finish
finish
$if lktype=simple
temp=csr2
memory=temp&bit1617,   mar=mar+1;                  !store bit 16/17
$finish
memory=csr5,   mar=mar+1;                          !      bit 8-15
memory=csr4,   mar=mar+1;                          !      bit 0-7
memory=csr3;                                       !      count
csr2=0
jump page1:link+.;                                 !return (ugh !!)
jump rtn2
jump rtn3
jump rtn4