!Virtual memory support for visual ECCE
!A.D. Culloch.  March 1981
!Large byte address space mapped over a large
!temporary DA file.

%const %integer CR = 13
%const %integer maxname=127;         !max file name length
%recordformat file(%string(maxname) name, %integer chan,
                    %integer top,lim,vmtop,vmlim,flag)


%include "Sysinc:Command.INC"
%include "sysinc:DA.inc"

   %own %integer maxVM = 400 {blocks}
   %ownintegerarray bitmap(0:50) = 0(*)

   %routine set bit (%integer index)
      %integer j = index>>5, k = index&31
      bitmap(j) = bitmap(j) ! 1<<k
   %end

   %predicate bit set {?} (%integer index)
      %integer j = index>>5, k=index&31
      %true %if bitmap(j) & 1<<k # 0
      %false
   %end

   %routine clear bit (%integer index)
      %integer j = index>>5, k = index&31
      bitmap(j) = bitmap(j) & (\(1<<k))
   %end


   %record %format blockfm (%byte %array B(0:511))

   %record %format buffm(%integer from,to,  {block maps these V.addrs}
                         %integer chan,     {paged in from here}
                         %integer block,    {block in paging file}
                         %record(buffm)%name link,   {circular list}
                         %record(blockfm) blk)

   %const %integer max con = 3;          !max files in VM: IN,OUT,SEC
   %const %integer sec chan = 3
   %own %integer %array base(1:max con) = 512,0(*);!base V.addr of file (j)
   %own %integer connected = 1;          !no of files currently mapped
   %const %integer paging file = {channel} 1
   %own %string(31) page file name;      !tmp file in current directory
   %external %integer %spec buffers
   %external %record(buffm) %array %name %spec buffer
   %external %record(buf fm)%name %spec buf
   %own %integer free VM = 512;          !bytes of VM connected (must be >0)

   %string(4) %function Unique Extension
      %record(parm fm) P
      P_dact = 25;  SVC (20,P);          !Director call for unique ext
      P_p4 = P_p4&x'FFFF'
      SVC (18,P);                        !Unpack filename -> ".EXT"
      %result = string(addr(P_sact))
   %end
   

   %external %byte %map byte integer (%integer index);!into notional VM in DA file
      %integer block = index>>9, offset = index&511, chan
      %record(buffm)%name prev, p
      p == buf_link;                     !hd of circ. list
      %cycle;                            !id BLOCK in buffer chain?
         %if p_from <= index <= p_to %start
            !promote this buffer to hd of list
            !(most recently used)
            %if p == buf %start;         !tl becomes hd
               buf == prev
            %else %if p ## buf_link;     !already hd?
               prev_link == p_link
               p_link == buf_link
               buf_link == p
            %finish
            %result == p_blk_B(offset)
         %finish
         %exit %if p == buf
         prev == p
         p == p_link
      %repeat
      !block not in store.. replace last page in list
      %if buf_block >= 0 %and buf_chan # sec chan %start
         write DA (paging file, buf_block, buf_blk)
      %finish
      !promote last buffer
      buf == prev
      chan = paging file
      %if %not bit set (block-1) %start;   !not in paging file - which chan?
         chan = chan + 1 %until chan={last}connected %or index < base(chan+1)
      %finish
      p_from = 512*block
      p_to   = p_from + 512 - 1
      p_chan = chan
      read DA (chan,(p_from - base(chan))>>9,p_blk)
      p_block = block - 1 {offset for initial free VM=512}
      set bit (p_block);  !used
      %result == p_blk_B(offset)
   %end
   %external %routine connect input (%record(file)%name f)
      %own %integer first {call} = 1 {nonzero: true}
      %integer j,k, size
      %const %integer to Director = 20,
                      pack filename = 17,
                      get status = 18;  !magic nos for svcs
      %recordformat parmfm ( %c
            %short dsno,dact, %short ssno, sact, %integer p1,p2,p3,p4,p5,p6 %or
               %integer frig, %short ssno2,sact2,%string(23) text         %or   
               %integer frig2,%short ssno3,%string(25) fname)
      %record(parm fm) Q
      %if f_top # 0 %start;              !previous secondary input file
         %for j = 1,1,buffers %cycle;    !free any buffers in use
            buffer(j)_to = -1 %if buffer(j)_from >= f_top
         %repeat
         close DA (f_chan)
         connected = connected - 1
      %finish
      !get size of file (blocks) from Director
      %if f_name = "" %then size = 0 %else %start
         Q_fname = f_name
         SVC (pack filename,Q)
         Q_text = "illegal filename" %and ->fail %if Q_p1 < 0 %or Q_p2 < 0
         Q_dact = get status
         SVC (to Director,Q)
         %if Q_p6 # 0 %start
fail:       print symbol (CR);  print symbol (NL);         !cr/lf
            print string ("*Edit " . f_name . " fails -- " . Q_text)
            %stop
         %finish
         size = Q_p2;                       !blocks
      %finish
      %record(buffm) %name p
      %if first # 0 %start
         first = 0
         %for j = 1,1,buffers %cycle
            p == buffer(j)
            p_from = 0;  p_to = -1; p_chan = -1; p_block = -1
            %if j = buffers %then p_link == buffer(1) %c
                            %else p_link == buffer(j+1)
            p_blk_B(k) = '@' %for k = 0,1,511;   !warning of problems
         %repeat
         page file name = "$ECCE" . unique extension
         create file (page file name, max VM, max VM)
Write(Max VM, 1);  Printstring(" blocks created");  Newline
         open DA (paging file, read write, page file name)
      %finish
      f_flag = -1 %and %return %if size < 0
      connected = connected + 1
      f_chan = connected
      open DA (f_chan,read only,f_name) %if f_name # ""
      %monitor %if f_chan > max con
      base(f_chan) = free VM;  f_top = free VM
      f_lim = free VM + 512*size
      free VM = free VM + 512*(size + f_flag)
      %if f_flag # 0 %start;              !mark extra pages as 'in file'
         set bit (j-1) %for j = f_top>>9 + size, 1, free VM>>9 - 1
      %finish
      f_flag = 0
      f_VM top = f_top;  f_VM lim = free VM - 1;  !VAX
      f_lim = f_lim - 1 %while f_lim # f_top %and byte integer (f_lim-1) # NL
   %end
   %external %routine move (%integer length, from, to)
      %return %if from = to
      %if to <= from %start
         %while length > 0 %cycle
            byte integer (to) = byte integer (from)
            from = from + 1
            to = to + 1
            length = length - 1
         %repeat
      %else
         from = from + length;            !move from back to front
         to   = to   + length
         %while length > 0 %cycle
            from = from - 1
            to   = to   - 1
            byte integer (to) = byte integer (from)
            length = length - 1
         %repeat
      %finish
   %end
   %external %routine close off
      %external %record(file) %spec in, out, sec
      %integer flim = out_lim, size
      %record(buffm)%name this
      %integer k
      %integer j = flim - out_top;   !out size
      %const %integer eot = 4
!      Dump last couple of blocks on the console
!      k = flim - 1024;  k = 512 %if k < 512
!      %while k # flim %cycle
!         print symbol (byteinteger(k))
!         k = k + 1
!      %repeat
       %while j&511 # 0 %cycle;     !fill last block
         j = j + 1
         byte integer (flim) = EOT
         flim = flim + 1
       %repeat
       size = j>>9 {blocks}
       !fill paging file
       %for j = 512,512,512*size %cycle
         %unless bit set (j>>9-1) %start;   !block not used yet
            k = byte integer (j);           !access it
         %finish
       %repeat
       %for j = 1,1,buffers %cycle;        !flush buffers
         this == buffer(j)
         write DA (paging file,this_block,this_blk) %if this_block >= 0
       %repeat
       extend DA (paging file,size - max VM,size);   !truncate
       close DA (j) %for j = 1,1,max con
       delete file (out_name) %if out_name # "" %and exists (out_name)
       rename file (page file name,out_name)
       write (size,0);  print string (" block")
       print symbol ('s') %if size # 1;  print symbol (':');  space
   %end
%end %of %file
