!***********************************************************************
!*                                                                     *
!*                Ethernet Diagnostic Monitor                          *
!*  Originally W.I.Walker M.Sc project 1984, heavily modded by JHB     *
!*                                                                     *
!*                    Version 1.1  6 Aug 1986                          *
!*                                                                     *
!***********************************************************************

%include "inc:util.imp"
%include "inc:fs.imp"
!**
{%include "ie:terminal.inc"}
%external %routine %spec Set Terminal Characteristics %alias "IE_TT_STC"
%external %routine %spec reset terminal  %alias "IE_RESET_TERMINAL"
%external %integer %function %spec Default Terminal %alias "IE_DEF_TER"
%external %byte %spec Terminal Model %alias "IE_TT_MODEL"
%external %routine %spec Clear Screen %alias "IE_TT_CS"
%external %routine %spec Reverse On %alias "IE_TT_REVERSE"
%external %routine %spec Normal  %alias "IE_TT_NORMAL"
%external %routine %spec Cursor %alias "IE_TT_CURSOR" (%integer X, Y)
%external %routine %spec Forward Scroll %alias "IE_TT_FS" (%integer Top, Bottom)
!**

%begin

%option "-low"
@16_1070 %integer EV
@16_1078 %integer CV
%option "-nolow"

%constinteger nl=10,esc=27,str=1,stp=2,tic=3,stx=16_20,infobytes=4,
              buffsiz=16_40000,screenwidth=80,screenlength=22,
              maxdatbytperline = screenwidth//3

%conststring(255) monfirm="fastmonf.bin"   {diagmonf.bin}
%string (255) s1, s2, s3

%owninteger stp seg=0,strt seg=0,op mode=0,sel dis=0,stp rec md=0,str pb md=0,
            stp pb md=0,bytes=0,maxblcksiz=534,maxsegnum=0,segsiz=0,
            fifo of cnt=0,dma or cnt=0,coll cnt=0,crce cnt=0,rece cnt=0,
            empty cnt=0,buff of cnt=0,intrprt level=0,timing cnt=0,gap cnt=0,
            tick=0,tracestrt=0,traceend=0,buffbot=0,bufftop=0,packs=0,blcks=0,
            disblcks=0,buff full=0,delay=0,temp=0,original CV=0,original EV=0,
            maxpacks=0,firmstart=0,firmlen=0,i=0,j=0,maxpershort=5,maxperline=10

%recordformat bd(%integer put,%integerarray get(0:1))
%ownrecord(bd) buffdet 
%ownintegerarray disvals(0:15) = 0(*)

%bytearray buffer(0:buffsiz-1)

%ownbyte rcvmode=0,stat1=0,port1=0,stat2=0,port2=0,monstat=0
%short lastseg
%recordformat segf(%short segno, len, %byte status, time, %c
                   %bytearray dest, srce(0:5), %byte type, seq,
                   %bytearray data(0:533))
%record (segf) %name curseg

%routine wait(%integer msec)
   msec = cputime + msec
   %while cputime <= msec %cycle;   %repeat
%end


%routine %spec reset apm


%on %event 0,1,2,4,8 %start            
  printstring("Event "); phex2(event_event); space; phex2(event_sub)
  space; write(event_line, 4); space; phex(event_extra); newline
  printline(event_message)
  %if monstat & 1 # 0 %then reset apm  {this event is signalled by <ctrl y>
  %stop                                {leave program under control
%finish

%routine prhex(%integer i)
  %if i<=9 %then write(i,-1) %else printstring("16_") %and phex4(i)
%end

%routine prline(%string (255) s)
  newline; printline(s); newline
%end


!---- Special Input Routines ----------------------------------------------------------

%routine wait for return
    %cycle; %repeatuntil testsymbol < 0
    printstring("Type <return> to continue")
    %cycle; %repeatuntil testsymbol = 10
    newline
%end


%predicate user said yes
   %integer answer

   prompt("Y or N ? ")
   %cycle
     readsymbol(answer)
     %if 'a'<=answer<='z' %then answer=answer-32
   %repeat %until answer='Y' %or answer='N'
   %true %if answer = 'Y'
   %false
%end

%routine readinteger(%string (255) prstrg,%integername num, %integer base,low,hi)
  !this function takes input and returns an integer value.
  !the input may be in any base.

  %byte sym,neg
 
  %if hi<low %then hi=2147483647
  prompt(prstrg)
  %cycle
     neg=0;num=0
     readsymbol(sym) %until sym#' '
     %if sym='+' %start
       readsymbol(sym)
     %elseif sym='-'
       neg=1
       readsymbol(sym)
     %finish
     %if sym=nl %then ->inputerr
     %while '0'<=sym<='9' %or 'a'<=sym<='z' %or 'A'<= sym<='Z' %cycle
       %if 'a'<=sym<='z' %start
         sym=sym-' '-7
       %elseif 'A'<=sym<='Z'
         sym=sym-7 
       %finish
       sym=sym-'0'
       %if sym>=base %then ->inputerr
       num=num*base+sym
       readsymbol(sym)
     %repeat
     %if sym#nl %start
   inputerr:
       readsymbol(sym) %while sym#nl
       neg=0; num=low-1
     %finish
     %if neg=1 %then num=-num
   %repeatuntil low <= num <= hi
%end


!---- Monitor Set Up Routines --------------------------------------------------------

%routine load(%integer start, len)
  !this routine loads the binary file of the firmware into the station
  %byte sym
  %integer ad

  sym=0; ETHS=sym                     {disable station interrupts
  ETHC=16_03                          {following data to be loaded into
  %for ad=start, 1, start+len-1 %cycle
    twait
    ETHD=byteinteger(ad)              {pass data to station through data
  %repeat
  twait
  ETHC=16_0B                          {end of data,return to normal procedures
%end                                     {for handling data arriving at station


%routine fillblock(%integer bytes,from,filler)
!  %returnif bytes<=0
%label x,y
   *tst.l d0
   *ble y
   *move.l d1,a1
   *sub.l #1,d0
x: *move.b d2,(a1)+
   *dbra d0,x
   *bra y
y:
%end

%routine buffer initialisation
  !this routine sets up the segmented,circular buffer
  %integer i
  fillblock(buffsiz, addr(buffer(0)), 0)

  segsiz=maxblcksiz + 2 + rem(maxblcksiz+2,2)
  maxsegnum=buffsiz//segsiz - 1

  %for i=0, 1, maxsegnum %cycle   {init. segment number fields
    shortinteger(addr(buffer(i*segsiz)))=i
  %repeat

  bufftop=addr(buffer(0)) 
  buffbot=bufftop + segsiz*(maxsegnum + 1)
  buffdet_put=bufftop
  buffdet_get(0)=bufftop
  buffdet_get(1)=bufftop
  trace strt=0
  trace end=0
  buff full=0
%end



%routine  reset apm

!this routine resets the ether station for normal use

  ETHS=16_40                            {reset hardware
  wait(2)
  CV=original CV                        {replace original interrupt
  EV=original EV                        {vectors
  ETHS=6                                {reenable station interrupts
  wait(10)
  etheropen(lsap,rdte<<8+rsap)          {reconnect to file store
  forward scroll(1, 24)
  prline("APM has been reset for normal use.")
  reset terminal
%end



!---- Stop Mechanism -------------------------------------------------

%predicate stop condition occurred(%integer stop mode)
  !this predicate is used to check whether the current operation
  !should be stopped as requested by the user.
  !there are 4 stop modes.

  %predicate user stopped manually
    !Check for input from the keyboard indicating a manual stop

    %false %if testsymbol<0
    %cycle;  %repeat %until testsymbol<0
    %true
  %end

  !stop if user hit key or packets received >= packets specified by user
  !or user has reached specified segment (playback)

  %true %if user stopped manually %or (stop mode=2 %and packs>=maxpacks) %or %c
  (stop mode=3 %and shortinteger(buffdet_get(1)) = stp seg+1)

  %false
%end



!---- Interpretation Module ----------------------------------------------------

%routine interpret (%integer intrprt mode,user fn) 
  !this routine presents a single block,in the requested format onto the VDU.
  !this routine is called by both record and playback modules.

  %routine interpret addr(%bytearrayname add(0:5))
    phex2(add(0));  printsymbol(':');  phex2(add(1))
    %if add(2)#0 %or add(3)#0 %or add(4)#0 %or add(5)#0 %start 
      !if error in address field then print the lot
      printsymbol(':')
      phex2(add(2)); phex2(add(3)); phex(add(4)); phex2(add(5))
    %finish
  %end

  %routine present pckt hdr
   %integer i
   !this routine presents a packet header as a stream of bytes.

    %for i=0,1,5 %cycle; phex2(curseg_dest(i)); %repeat; space
    %for i=0,1,5 %cycle; phex2(curseg_srce(i)); %repeat; space
    phex2(curseg_type); space; phex2(curseg_seq)
  %end


  %routine present pckt data(%bytearrayname data(0:533), %integer bytes)
    !this routine presents packet data as a stream of bytes.
    %integer full lines,act lines,rem bytes,n,m,p

    newline %and %return %if bytes=0
    %if bytes<=maxpershort %then spaces(4) %else newline
    full lines=bytes//maxperline
    %if full lines <=2 %or user fn#1 %then act lines = full lines %else act lines = 2
    rem bytes=rem(bytes,maxperline)
    %if actlines # 0 %start
       %for n=0,1,act lines-1 %cycle
         %for m=0,1,maxperline-1 %cycle
            p = n * maxperline + m
            %if intrprt mode >2 %start
               %if 32<=data(p)<=126 %then printsymbol(data(p)) %else printsymbol('_')
            %finishelse phex2(data(p)) %and space
         %repeat
         newline
       %repeat
    %finish
    printline("...") %if act lines # full lines
    %if rem bytes > 0 %start
      %for n=0,1,rem bytes-1 %cycle
         p = full lines * maxperline + n
         %if intrprt mode >2 %start
            %if 32<=data(p)<=126 %then printsymbol(data(p)) %else printsymbol('_')
         %finishelse phex2(data(p)) %and space
      %repeat
      newline
    %finish
  %end


  %routine interpret blck hdr
    !This routine presents any significant information in the block header.

    %if curseg_time#0 %start
      tick=tick + curseg_time
      printsymbol('['); write(tick,-1); printsymbol(']')
      newline
    %finish

    reverse on; phex4(curseg_segno); normal
    %if curseg_status & 128 # 0 %start    {empty block
      %if curseg_status !! 128 = 0 %start {end of trace marker
        reverse on; printline("** End of trace **"); normal
      %elseif curseg_status & 1 # 0  {check fifo overflow bit
        reverse on; printline("** FIFO overflow **"); normal
      %finish
    %else                                {block contains packet
      %if curseg_status & 64 # 0 %start   {check buff overflow bit
        reverse on; printline("** Buffer overflow **"); normal
      %finish
      printstring(" L="); phex4(curseg_len); space
                                         {check other status bits
      %if curseg_status & 16_1E#0 %start
         %if curseg_status & 8 # 0 %then printstring(" CRCE")
         %if curseg_status & 4 # 0 %then printstring(" COLL")
         %if curseg_status & 2 # 0 %then printstring(" LONG")
         %if curseg_status & 16# 0 %then printstring(" RECE")
         printline(" *")
      %finish
    %finish
  %end
      

  %routine interpret pckt hdr
    !this routine presents a packet header in symbolic form.

    interpret addr(curseg_srce)
    printstring(" -> ")
    interpret addr(curseg_dest)
    %if curseg_type=1 %start
       printstring(" data")
    %elseif curseg_type=129
       printstring("  ack")
    %else                         {if error in type field display it
      spaces(3); phex2(curseg_type)
    %finish
    printsymbol('('); phex2(curseg_seq); printsymbol(')')
  %end

  curseg == record(buffdet_get(user fn-1))

  interpret blck hdr

  %if curseg_len >=14+infobytes %start    {block contains a packet
    %if intrprt mode>=2 %then interpret pckt hdr %else present pckt hdr
    present pckt data(curseg_data, curseg_len - 18)
  %finish

  newline
                                        {move get to beginning of next segment
  buffdet_get(user fn-1)=buffdet_get(user fn-1) + segsiz
  %if buffdet_get(user fn-1)>=buffbot %then buffdet_get(user fn-1)=bufftop

%end


!---- Recording Module -----------------------------------------------------------

%routine recording(%integer display on)
  !this routine provides control of the recording operation.

  %routine recording status review
    !this routine presents the recording operation statistics onto the VDU

    %integer x,y

    %constintegerarray disx (0:8) = 15,22,31,40,49,58,68,19,47
    %constintegerarray disy (0:8) = 3, 3, 3, 3, 3, 3, 3, 0, 0
    %constintegerarray disposns(0:8) = 6, 8, 8, 8, 8, 9, 8, 6, 6

    %routine update(%integer field, val)
       %if val # disvals(field) %start
          y=disy(field)
          cursor(disx(field), y) %if x # disx(field)
          write(val, disposns(field))
          x=disx(field) + disposns(field) + 1
          disvals(field) = val
       %finish
    %end

    x=-1; y=-1
->chop
    update(7, packs)
    x=-1
    update(8, timing cnt//10)
    x=-1
    update(0, fifo of cnt)
    update(1, dma or cnt)
    update(2, coll cnt)
    update(3, crce cnt)
    update(4, rece cnt)
    update(5, buff of cnt)
    update(6, empty cnt)
chop:
    cursor(0, screenlength-2) %if y>=0
  %end


  %routine start recording

  !this routine sends a ctrl char to the ether 
  !station which activates the station
    %integer i

    !a 2 window arrangement is used in recording mode

    clearscreen
    printstring("Packets Recorded=                 Time (sec)=              Stations ")
    %if stat1 > 127 %then printstring("All") %else phex2(stat1)
    printstring(" <-> ")
    %if stat2 > 127 %then printstring("All") %else phex2(stat2)
    newlines(2)
    printline("Status Bits:  fifo o/f  dma o/r     coll     crce     rece  buff o/f    empty")
    printline("Count")
    printline("--------------------------------------------------------------------------------")
    forward scroll(6, screenlength-1)
  
    !initialise recording vars

    %if intrprt level<=2 %then maxpershort=10 %and maxperline=maxdatbytperline %else %c
    maxpershort=30 %and maxperline=screenwidth

    fifo of cnt=0;  dma or cnt=0;     coll cnt=0;     crce cnt=0
    rece cnt=0;     timing cnt=0;     buff of cnt=0;  empty cnt=0
    packs=0;        blcks=0;          disblcks=0;     tick=0
    %for i=0,1,8 %cycle; disvals(i)=-1; %repeat
    buffdet_get(0)=buffdet_put         {get and put start at same segment
    trace strt=buffdet_get(0)

    twait
    ETHC=str
    %cycle                              {wait for signal that recording
    %repeat %until monstat & 2 # 0      {has started
    prline("Recording Started")
%end


  %routine stop recording(%string (255) why, %integer extra)

    !this routine sends a ctrl char to the ether station which disables
    !the station until start recording is called again

    twait
    ETHC=stp
    %cycle                                {wait for signal that recording
    %repeat %until monstat & 2 =0         {has stopped
    newline
    printstring("Recording Stopped - ".why)
    space %and phex(extra) %if extra # 0
    newline
  
    recording status review

    !wind up recording operation

    trace end=buffdet_put
    curseg == record(buffdet_put)
    curseg_len=infobytes      {create an empty block to
    curseg_status=128         {mark end of trace.
    curseg_time  =0
    buffdet_put=buffdet_put + segsiz         {move put to next segment
    %if buffdet_put>=buffbot %start 
      buffdet_put=bufftop
      buff full=1
    %finish

{t} %if buffdet_put<0 %start
{t}    phex(bufftop); space; phex(buffbot); space; phex(trace strt); space
{t}    phex(trace end); newline
{t}    phex(buffdet_put); space; phex(buffdet_get(0)); space; phex(buffdet_get(1))
{t}    space; phex(maxsegnum); space; phex(segsiz)
{t}    newline
{t} %finish

    ! if trace filled buffer then find earliest block in trace
    %if blcks>maxsegnum %then trace strt=buffdet_put
    printstring("Trace Occupies Segments ");  write(shortinteger(trace strt),-1)
    printstring(" to ")
    %if trace end=bufftop %then write(maxsegnum,-1) %else %c
    write(shortinteger(trace end - segsiz), -1)
    newline

    wait for return

  %end
  

  %routine record only

    !this routine stops recorded as requested and presents recording stats.

    %on 0 %start
       %if event_sub=1 %then stop recording("User abort",0) %else %c
       stop recording("Unspecified event 0/".itos(event_sub,-1), event_extra)
       %return
    %finish

    start recording %if monstat & 2 = 0      {if recording not started
{t}prline("Pointers corrupt 2") %if buffdet_put<0

    %cycle
       recording status review
    %repeatuntil stop condition occurred(stp rec md) %or %c
    buffdet_put <0
{t} prline("pointers corrupt 5") %if buffdet_put <0

    stop recording("Specified stop occurred",0)
  %end
  

  %routine record and display

    !this routine displays recorded data while recording

    %on 0 %start
       %if event_sub=1 %then stop recording("User abort",0) %else %c
       stop recording("Unspecified event 0/".itos(event_sub,-1), event_extra)
       %return
    %finish

    start recording
    %cycle
      %cycle
        %if stop condition occurred(stp rec md) %start   
          stop recording("Specified stop occurred",0)
          %return
        %finish

      %repeat %until buffdet_get(0)#buffdet_put %or buffdet_put & 16_ff000000 # 0
      %if blcks-disblcks>maxsegnum %start  {check if recording has
        prline("Display Stopped: recording overtaken display")

        record only                              {continue recording
        %return
      %finish
      interpret (intrprt level,op mode)
      disblcks=disblcks+1
      recording status review
    %repeat
  %end
  

  %if display on>0 %then record and display %else record only
%end


!---- Dump profile -------------------------------------------------------------

%routine dump profile
   printstring("Blocksize    "); write(maxblcksiz, 5); spaces(5)
   printstring("Rx mode      "); write(rcvmode, 5); newline
   printstring("Stn/Port 1    "); phex2(stat1); space; phex2(port1); spaces(5)
   printstring("Stn/Port 2    "); phex2(stat2); space; phex2(port2); newline
   printstring("Op mode      "); write(op mode, 5); spaces(5)
   printstring("Stop Rx mode "); write(stp rec md, 5); newline
   printstring("Int level    "); write(intrprt level, 5); spaces(5)
   printstring("Start Pb mode"); write(str pb md, 5); newline
   printstring("Start Pb seg "); write(strt seg, 5); spaces(5)
   printstring("Stop pb mode "); write(stp pb md, 5); newline
   printstring("Stop pb seg  "); write(stp seg, 5); newline
%end


!---- Playback Module -----------------------------------------------------------

%routine playback
 
!this routine presents data already recorded and provides
!control over which data is presented.


  %routine playback status update
    !this routine checks the status field of the next
    !block to be displayed and updates the playback
    !operation statistics

    blcks=blcks + 1
    curseg == record(buffdet_get(1))
    %if curseg_status & 128 > 0 %start     {empty block
      %if curseg_status !! 128 = 0 %then gap cnt=gap cnt + 1  %c
      %else %if curseg_status & 1 > 0 %then fifo of cnt=fifo of cnt + 1
    %else                                      {block contains a packet
      packs=packs +1 
      %if curseg_status & 64# 0 %then buff of cnt=buff of cnt + 1
      %if curseg_status & 8 # 0 %then crce cnt=crce cnt + 1
      %if curseg_status & 4 # 0 %then coll cnt=coll cnt + 1
      %if curseg_status & 2 # 0 %then dma or cnt=dma or cnt + 1
      %if curseg_status & 16# 0 %then rece cnt=rece cnt + 1
    %finish
  %end


  %routine playback status review
  
  !this routine presents the playback operation statistics
  !onto the VDU

    cursor(32, 0);     write(blcks,6)
    cursor(62, 0);     write(packs,6)

    cursor(11, 2)  {???}

    write(gap cnt,6);    write(fifo of cnt,9);    write(buff of cnt,9)
    write(crce cnt,9);   write(coll cnt,9);       write(dma or cnt,9)
    write(rece cnt,9)

    cursor(0, screenlength-2)
  %end
  

    !Set up a 2 window arrangement for use in playback mode

    clearscreen
    printline("Strt Seg No.=           Blcks=                 Packet Count= ")
    printline("Events:        end      fifo      buff      crce      coll      long      rece")
    printline("Count")
    printline("--------------------------------------------------------------------------------")
    forward scroll(4, screenlength-1)

    !initialise playback vars

    %if str pb md=3 %start
      buffdet_get(1) = trace strt
    %elseif str pb md=2 
      buffdet_get(1)=bufftop + strt seg*segsiz
    %elseif stp pb md=4
      %if trace end=bufftop %then stp seg=maxsegnum %c
      %else stp seg=shortinteger(trace end - segsiz)
      stp pb md=3
    %finish

    %if intrprt level<=2 %then maxpershort=10 %and maxperline=maxdatbytperline %else %c
    maxpershort=30 %and maxperline=screenwidth

    tick=0;          packs=0;         blcks=0;      gap cnt=0
    fifo of cnt=0;   buff of cnt=0;   crce cnt=0;   coll cnt=0
    dma or cnt=0;    rece cnt=0;      delay=0

    ! indicate at which segment playback is starting
    cursor(15,0); prhex(shortinteger(buffdet_get(1)))
    cursor(0, screenlength-2)

  %cycle
    wait(500)
    %if stop condition occurred(stp pb md) %start
      playback status review
      prline("Playback Complete")
      wait for return
      %return
    %finish
                       {check if an unused segment has been reached
    %if buff full=0 %and buffdet_get(1)>=buffdet_put %start
      playback status review
      prline("Playback Stopped: End of trace")
      wait for return
      %return
    %finish
    playback status update
    interpret (intrprt level,op mode)
    playback status review
  %repeat
%end
  
%integerfn stoh(%string (255) s)
   %integer i, l, c, no
   l=length(s); no=0
   %if l#0 %start
     %for i=1,1,l %cycle
        c=charno(s, i)
        %if '0'<=c<='9' %start
           no=no*16+(c-'0')
        %elseif 'A'<=c<='F'
           no=no*16+(c-'A'+10)
        %elseif 'a'<=c<='f'
           no=no*16+(c-'a'+10)
        %elseif c=' '
        %finishelseresult=-1
      %repeat
   %finish
   %result=no
%end

%integerfn munge stnport(%string (255) s, %bytename stn, port)
   !Expects a stn.port of form stn <or> stn.port <or> stn.0
   %string (255) p
   %integer rc

   rc=1
   rc=0 %and p="" %unless s -> s.(".").p ;!Separate into stn and port

   stn = stoh(s)
   %result=-1 %unless 0<=stn<=255
   port = stoh(p)
   %result=-1 %unless 0<=port<=31
   %result=rc
%end

%option "-nodiag -nostack -low"
%routine prime monitor

  %routine clock tick

  !the first part of this routine changes the address in the clock
  !interrupt vector and loads the jmp instr in the new ISR with the old 
  !address.
  !the 2nd part of the routine is the clock interrupt service routine.
  !when a clock interrupt occurs ETHC is loaded to cause an interrupt
  !to the z80 and then the service routine jumps to the start of the
  !original service routine.

    %label clock,newclck

    *lea clock,a0                       {load jmp instr with original
    *move.l CV,2(a0)                    {address in CV
    *lea newclck,a0                     {load CV with new address
    *move.l a0,CV                      
    *rts

  newclck:
    *btst #3,ETHS                       {wait til tbe is set
    *beq newclck                       
    *move.b #tic,ETHC                   {causes interrupt to z80
    *addq.l #1,delay                    {increment pb delay counter
  clock:
    *jmp 16_12345678                    {jmp to original service routine

  %end

  %routine ether interrupt handler(%record(*)%name r)

  !the 1st part of this routine changes the address in the ether interrupt
  !vector and loads the address of the location r points to into the 
  !1st lea instr of the new service routine.
  !the 2nd part of the routine is the new ether interrupt service routine.

    %label intaddr,ccstr,ccstp,ccstx,erwait,loop,blck done
    %label notctrl,newput,intretn
    %label bit1,bit2,bit3,bit4,bit6,bit7

    *lea intaddr,a1                     {load EV with new address
    *move.l a1,EV                       {
    *move.l a0,6(a1)                    {load 1st movea with addr 
    *rts                                {that r points to

  intaddr:
    *movem.l d0-d7/a0-a7,-(sp)
    *movea.l #16_12345678,a0
    *btst #1,ETHS                     {if intrpt not from ctrl reg then
    *beq notctrl                      {do nothing and jmp to notctrl

    *move.b ETHC,d1                   {read ctrl char
    *cmpi.b #stx,d1                   {jump to piece of code handling
    *beq ccstx                        {the response to ctrl char
    *cmpi.b #str,d1                   
    *beq ccstr                        
    *cmpi.b #stp,d1                     
    *beq ccstp                        
    *bra intretn                      
  
  ccstr:                              {station fully operational for recording
    *bset #1,monstat                  {indicates that firmware is recording
    *bra intretn

  ccstp:                              {station no longer passing on received
                                      {packets
    *bclr #1,monstat                  {indicates that firmware is not recording
    *bra intretn                      

  ccstx:
    *movea.l (a0),a1                  {load buffdet_put int a1
    *addq.l #2,a1                     {move past seg. no
    *bsr erwait                        {wait until next char arrives
    *move.b ETHD,d1                    {load contents of ETHD into buffer

    *moveq #0,d2
    *bsr erwait                       {wait for next char
    *move.b ETHD,d2                   {load high byte of blcklen into buffer
    *move.b d2,(a1)+                  {and into 2nd byte of d2
    *lsl #8,d2                        {
    *move.b d1,(a1)+                  {load low byte of blcklen into buffer
    *move.b d1,d2                     {and into 1st byte of d2
    *move.l d2,d3                     {d2 now contains the length of the block

    *bsr erwait                       
    *move.b ETHD,d1                   {load status field into d1
    *move.b d1,(a1)+

    *moveq #0,d0
    *bsr erwait
    *move.b ETHD,d0                   {load time field into d0
    *move.b d0,(a1)+
    *subi.l #infobytes+1,d2           {subtract 5 as d2 will act as counter.

    *add.l d0,timing cnt              {update timing cnt
                                       
    *btst #0,d1                       {update status bit cnts
    *beq bit1
    *addq.l #1,fifo of cnt
  bit1:
    *btst #1,d1
    *beq bit2
    *addq.l #1,dma or cnt
  bit2:
    *btst #2,d1
    *beq bit3
    *addq.l #1,coll cnt
  bit3:
    *btst #3,d1
    *beq bit4
    *addq.l #1,crce cnt
  bit4:
    *btst #4,d1
    *beq bit6
    *addq.l #1,rece cnt
  bit6:
    *btst #6,d1
    *beq bit7
    *addq.l #1,buff of cnt
  bit7:
    *btst #7,d1
    *beq loop
    *addq.l #1,empty cnt                {if set then no more data to
    *bra blck done                      {receive

  loop:
    *bsr erwait                         {wait for next char
    *move.b ETHD,(a1)+                  {loaded remainder of block into buffer
    *dbra d2,loop                       {
    *addq.l #1,packs                    {update packs cnt

  blck done:
    *addq.l #1,blcks                    {update blcks cnt
    *move.l segsiz,d4                   {find start point of next block
    *movea.l (a0),a1                    {to be recorded = buffdet_put+segsiz
    *adda.l d4,a1                       {

    *cmp.l buffbot,a1                   {if a1 (next value of put) is greater
    *blt newput                         {buffbot
    *movea.l bufftop,a1                 {tput becomes bufftop and
    *move.l #1,buff full

  newput:
    *move.l a1,(a0)                     {update buffdet_put

  intretn:
    *movem.l (sp)+,d0-d7/a0-a7
    *rte

  notctrl:
    *move.b ETHD,d0                     {read ETHD to clear interrupt
    *bra intretn

  erwait:                               {wait for next char to arrive
    *btst #2,ETHS
    *beq erwait
    *rts

  %end

  original CV=CV
  original EV=EV
  monstat=1                           {indicates that apm should be
                                      {considered to be conrolled by
!!  clock tick                          {turn clock off for just now
  ether interrupt handler(buffdet)
  ETHS=6                                {enable normal interrupts
%end
%option "-diag -stack -nolow"




!---- Program Body - User Interface ------------------------------------------------------------------

begin:
  monstat=0
  Terminal Model = Default Terminal
  set terminal mode(8)
  set terminal characteristics
  clearscreen

  readinteger("Max user data bytes/packet recorded (0-534):",bytes, 10, 0, 534)
  maxblcksiz=bytes+infobytes+14

prompt("Targets - Generic form: stn.port,stn.port: ")
readline(s1)
prompt("")
stat1=128; stat2=128; port1=0; port2=0
%if s1="" %start
   !All packets
   rcvmode=0

%elseif s1 -> s2.(",").s3
   !Point-point
   rcvmode=20
   i=munge stnport(s2, stat1, port1)
   %if i>0 %then rcvmode = rcvmode + i
   i=munge stnport(s3, stat2, port2)
   %if i>0 %then rcvmode = rcvmode + i

%else
   !Fan in/out
   rcvmode=10
   i=munge stnport(s1, stat1, port1)
   %if i>0 %then rcvmode = rcvmode + i

%finish

printstring("Mode:"); write(rcvmode, 2); space
%if rcvmode=0 %then printstring("All") %else %start
   space
   phex2(stat1); printsymbol('.')
   %if rcvmode & 3 # 0 %then phex2(port1) %else printstring("*")
   printstring(" <-> ")
   %if rcvmode<20 %then printstring("All") %elsestart
      phex2(stat2); printsymbol('.')
      %if rcvmode & 3 # 0 %then phex2(port2) %else printstring("*")
   %finish
%finish
newline

%cycle
  
  prline("1: Record     2: Playback     3: Initialise     4: Quit")

readmode:
  readinteger("Command:",op mode, 10, 1,4)

  %if op mode= 1 %start
    buffer initialisation
    write(maxsegnum,-1); printstring(" segments available"); newline
    prline("Stop after <n> packets, n=0 means never")

    readinteger("<n>:",maxpacks, 10, 0,65535)
    %if maxpacks<=0 %then stp rec md = 1 %else stp rec md = 2

    prline("Display data during recording?")

    %if user said yes %start
      sel dis=1
      prline("Block Interpretation...
     0: none    1: interpret header   2: dump data   3: interpret L2 data")

      readinteger("Level:",intrprt level, 10, 0,3)
    %finishelse sel dis=0
    newline

    dump profile

    connectfile(monfirm,0,firmstart,firmlen)
      
    !Place initial values of variables into locations in the binary file of the firmware.
    byteinteger(firmstart+3)<-maxblcksiz
    byteinteger(firmstart+4)<-maxblcksiz>>8
    byteinteger(firmstart+5)=rcvmode
    byteinteger(firmstart+6)=stat1
    byteinteger(firmstart+7)=port1
    byteinteger(firmstart+8)=stat2
    byteinteger(firmstart+9)=port2
    
    load(firmstart,firmlen)
    prline("APM now in monitor mode")
    heapput(firmstart)
    {set up APM
    prompt("")
    wait for return
    prime monitor

{t} prline("Starting to record")
    recording(sel dis)
    reset apm
  %else

    %if op mode=2 %start
      %if trace strt=0 %start
        printline("Trace Empty.")
        ->readmode
      %finish

      prline("1: Continue playback     2: Playback from segment <n>    3: Restart playback")

      readinteger("Mode:",str pb md, 10, 1,3)

      %if str pb md=2 %start
        %if bufffull=1 %then lastseg=maxsegnum %else lastseg=shortinteger(trace end)
        newline
        printstring("<n> (hex, 0 to "); prhex(lastseg)
        printstring(")..."); newline

        %cycle
           readinteger("Segment:",strt seg, 16, 0, 65535)
           %exit %if 0<=strt seg<=lastseg
           printline("out of range")
        %repeat
      %finish

      prline("Stop Playback when key is hit and ...
     1:  end of trace     2:  after <n> packets     3:  at segment <n>")

      readinteger("Mode:",stp pb md, 10, 1,3)

      %if stp pb md=2 %start
        prline("Specify <n>")

        readinteger("Packets:",maxpacks, 10, 0,65535)
      %else

        %if stp pb md=3 %start
          %if buff full=1 %then lastseg=maxsegnum %else %c
            lastseg=shortinteger(trace end)
          newline
          printstring("<n> (hex, 0 to "); prhex(lastseg)
          printstring(")..."); newline

          %cycle
            readinteger("Segment:",stp seg, 16, 0,65535)
            %exit %if 0<=stp seg<=lastseg
            printline("out of range")
          %repeat
        %finish
      %finish

      prline("Block Interpretation...
     0: none    1: interpret header   2: dump data  3: interpret data")

      readinteger("Level:",intrprt level, 10, 0,3)

      newline
      prompt("")
      wait for return
      playback

    %else             {op mode= 3 or 4
      reset apm
      %if op mode=4 %then %return 
      -> begin
    %finish
  %finish

  clearscreen
%repeat

%endofprogram

!t! newline
!t! %for i=0,1,22 %cycle
!t!   %for j=0,1,segsiz-1 %cycle
!t!     phex2(buffer(i*segsiz+j)); space
!t!   %repeat
!t!   newline
!t! %repeat

