"================================================================================================
#TITLE    'Atlas C&C PLD2: Clock Synchronisation';
#ENGINEER 'Martin Postranecky / Dominic A Hayes';
#COMPANY  'University College London';
#COMMENT  'fits to M5-512/120';
"================================================================================================
"              Receives: 
"                          BC_RESET  SOFT RESET  TRIGGER  CALIBRATE  SLOWCOM
"                             "A"        "B"        "C"       "D"      "E"
"              and synchronises them with CLK2
"Modified:
"29JUN98 added OR gate to end1c in prodedure busy (BUSY -1-).
" 1JUL98 added extra FF before outc2 in procedure g.
"18SEP98 added stop_clk when reg08 write accessed.
" 2OCT98 replaced node Z AND gate (procedure sync_trigger) with flip-flop.
" 9OCT98 burst_busy trigger disable included.  REMOVED 12OCT98 and pin 143 NO_CONNECT.
"        prbs generator (procedure prbs) for triggers included.
"14OCT98 ??
"16OCT98 incorporated function calibrate_gates into procedure calibrate.
"         added vburst mod to proc calibrate.
"19OCT98 removed intin_c1 i/p, now use o/p of prbs as random trigger intin_c1.
"         modified random trigger generation from 9OCT98 including today's mod.
"         function trigger_gates incorporated into proc triggers.
"20OCT98 created proc sync_slowcom for out_e logic (coupled with nclre mod on pld3).
"22OCT98 proc prbs: sr preset by /noa_rst.
"23OCT98 pin 38 no_connect.
"29OCT98 increased prbs to 39 bits.  out_ch and out_c1 made outputs.
"  MOD BELOW (12DEC98) NOT ON CLOAC (as of 02AUG99) [ADDED VIA CLOAC2 CODE 13SEP99]
"12DEC98 83uSec delay (12bit counter rep_count) added to rep_cal signal generated 
"           from nx output of pld3.
"16JUL99 added AND gate to /clear input of qZ FF added on 2/10/98.
"03AUG99 sync FFs added to busyout (BUSY -2-).  (requested by Gareth Moorhead)
"
"        *** CLOAC/CLOAC2 use common src and pi files from now on. ***
"23AUG99 03AUG99 mode removed, replaced by:
"        In BUSY -1- nbusyc input to busy AND gate replaced by nenc.
"
"------------------------------------------------------------------------------------------------

"-----------------------------------------------------------------------
FUNCTION level_to_pulse
"Converts input level into a single pulse approx 2tPD long.
"called by main body and D.

  (INPUT  level, reset);
   NODE   pulse CLOCKED_BY level RESET_BY clr NO_REDUCE;
   NODE   clr;
   RETURN pulse;
   
   clr =  pulse
       +  /reset;
    
   pulse = 1;
   
END level_to_pulse;
"-----------------------------------------------------------------------

"-----------------------------------------------------------------------
FUNCTION and3or     "A"              "B"
"Input gates for "BC_RESET" and "SOFT_RESET".
"called by procedure sync_input.

  (INPUT  extin, enext, vin, enint, intin, noa_busy);
   NODE   clk1;
   RETURN clk1;
   
   clk1 =  extin * enext * noa_busy
        +  vin * noa_busy
        +  enint * intin * noa_busy;

END and3or;
"-----------------------------------------------------------------------

"------------------------------------------------------------------------------------------------
PROCEDURE shift144
"called by procedure sync_trigger.
"operates as a 128 + 16 shift register with selectable output.

  (INPUT  serial_in,           "serial data from sync'd trigger.
          select[7..0],        "8bit selection from trig delay register.
          clk,                 "clock from delay line 3.
          out_d,               "shift register ff reset.
          noa_rst;             "main board reset.
   OUTPUT shift_out_a, shift_out_b);
   NODE   shift_a[128],
          shift_b[16]
            CLOCKED_BY clk
            RESET_BY reset;
   NODE   reset,
          selected_bit_a,
          selected_bit_b, 
          shift_out;
   
   reset = out_d + /noa_rst;   
   shift_a = [shift_a[126..0],serial_in];

   CASE select[7..4]
      WHEN 0 => selected_bit_a = serial_in;
      WHEN 1 => selected_bit_a = shift_a[15];   
      WHEN 2 => selected_bit_a = shift_a[31];
      WHEN 3 => selected_bit_a = shift_a[47];
      WHEN 4 => selected_bit_a = shift_a[63];
      WHEN 5 => selected_bit_a = shift_a[79];   
      WHEN 6 => selected_bit_a = shift_a[95];   
      WHEN 7 => selected_bit_a = shift_a[111];      
      WHEN 8 => selected_bit_a = shift_a[127];
   END CASE;

   shift_b = [shift_b[14..0], selected_bit_a];

   CASE select[3..0]
      WHEN 0  => selected_bit_b = selected_bit_a;
      WHEN 1  => selected_bit_b = shift_b[0];
      WHEN 2  => selected_bit_b = shift_b[1];
      WHEN 3  => selected_bit_b = shift_b[2];
      WHEN 4  => selected_bit_b = shift_b[3];
      WHEN 5  => selected_bit_b = shift_b[4];
      WHEN 6  => selected_bit_b = shift_b[5];
      WHEN 7  => selected_bit_b = shift_b[6];
      WHEN 8  => selected_bit_b = shift_b[7];
      WHEN 9  => selected_bit_b = shift_b[8];
      WHEN 10 => selected_bit_b = shift_b[9];
      WHEN 11 => selected_bit_b = shift_b[10];
      WHEN 12 => selected_bit_b = shift_b[11];
      WHEN 13 => selected_bit_b = shift_b[12];
      WHEN 14 => selected_bit_b = shift_b[13];
      WHEN 15 => selected_bit_b = shift_b[14];
   END CASE; 
   
   shift_out_a = selected_bit_a;
   shift_out_b = selected_bit_b;
 
END shift144;
"------------------------------------------------------------------------------------------------

"------------------------------------------------------------------------------------------------
PROCEDURE sync
"The set of 4 flip-flops used to synchronise the input clock signals.
"Used by A,B,C and D clocks.
"Called by procedures sync_input, sync_trigger, and sync_calibrate.

  (INPUT  clk1, clk2, end1, nclr; 
   OUTPUT nbusy, out, en, nen);
   NODE   q1 CLOCKED_BY clk1 RESET_BY /nclr;
   NODE   q2 CLOCKED_BY clk2 RESET_BY /nclr;
   NODE   q3 CLOCKED_BY clk2 RESET_BY /nclr;
   NODE   q5 CLOCKED_BY clk2 RESET_BY /nclr;

   q1 = end1;
   q2 = q1;
   q3 = q2 * /q5;
   q5 = q2;
   nbusy = /q1;
   out = q3;
   en = q5;
   nen = /q5;
   
END sync;
"------------------------------------------------------------------------------------------------

"------------------------------------------------------------------------------------------------
PROCEDURE sync_input                   "A"            "B"
"Main procedure for synchronising "BC_RESET" and "SOFT_RESET" clock.
"Called by Main Body twice.

  (INPUT  extin,enext,vin,enint,intin,noa_busy,nclr,end1,clk2; 
   OUTPUT nbusy,out,en,nen);
   NODE   clk1;

   clk1 = and3or(extin, enext, vin, enint, intin, noa_busy);

   sync
      (clk1,clk2,end1,nclr,   "TO
       nbusy,out,en,nen);     "FROM
       
END sync_input;
"------------------------------------------------------------------------------------------------

"------------------------------------------------------------------------------------------------
PROCEDURE prbs
"pseudo-random binary sequence generator, kicks in when repeat trigger selected.
"Called by Main Body.

  (INPUT  intin_c2,enint_c1,noa_rst;
   OUTPUT intin_c1);
   NODE   sr_in, prbs_clk;
   NODE   sr[1..39] CLOCKED_BY prbs_clk PRESET_BY /noa_rst;

   prbs_clk = intin_c2 * enint_c1;   "similar to "sr[.] CLOCK_ENABLED_BY enint_c1" which no fit
   intin_c1 = sr[39];
   sr_in    = sr[39] (+) sr[35];
   sr       = [sr_in,sr[1..38]];

END prbs;
"------------------------------------------------------------------------------------------------

"------------------------------------------------------------------------------------------------
PROCEDURE g
"Addition to "SYNC C = TRIGGER" Circuit
"modified 1/7/98 to add extra FF before outc2.
"called from procedure sync_trigger.

  (INPUT  out_c1, nbusy_a, nbusy_b, nbusy_c, nbusy_d, noa_rst, clk2, nclrc;
   OUTPUT out_c2);
   NODE   out_c1h;
   NODE   q1 CLOCKED_BY (/nbusy_d) RESET_BY /(noa_rst * nbusy_c);
   NODE   q2 CLOCKED_BY clk2 RESET_BY /noa_rst;

   q1 = 1;
   out_c1h = out_c1 * /q1 * nbusy_a * nbusy_b;
 
   q2 = out_c1h;
   out_c2 = q2;     
 
END g;    
"------------------------------------------------------------------------------------------------

"------------------------------------------------------------------------------------------------
PROCEDURE sync_trigger          "C"
"Procedure for synchronising "TRIGGER" clock.
"Called from Main Body.

  (INPUT  test_sw,trig_win,extin,enext,vin,y,en_d,enint_1,intin_1,enint_2,intin_2,
          noa_busy,nbusy_2,nclrc,end1c,clk2,entrig_win,
          select[8],clk3,out_d,
          nbusy_a,nbusy_b,nbusy_d,noa_rst; 
   OUTPUT nbusy_c,out_c,out_ch,out_c1,out_c2,en_c,nen_c);
   NODE   clk1,Z_clk,Z_clr;
   NODE   qZ CLOCKED_BY Z_clk RESET_BY /Z_clr;

   qZ    = 1;
   Z_clk = extin * enext * noa_busy;
   Z_clr = (trig_win OR /entrig_win) AND noa_rst AND nbusy_c;


   clk1 = qZ                        "used to be function trigger_gates.
        + nbusy_2 * test_sw    
        + nbusy_2 * vin
        + y * en_d
        + nbusy_2 * enint_1 * intin_1
        + nbusy_2 * enint_2 * intin_2 * /enint_1;

   sync                             "calls sync procedure.
      (clk1,clk2,end1c,nclrc,       "TO
       nbusy_c,out_c,en_c,nen_c);   "FROM

   shift144                                     "calls the 144 shift register procedure.
     (out_c,select,clk3,out_d,noa_rst,          "TO
      out_ch,out_c1);                           "FROM
      
   g
     (out_c1,nbusy_a,nbusy_b,nbusy_c,nbusy_d,noa_rst,clk2,nclrc,
      out_c2);       

END sync_trigger;
"------------------------------------------------------------------------------------------------

"------------------------------------------------------------------------------------------------
PROCEDURE sync_calibrate         "D"
"Procedure for synchronising "CALIBRATE" clock.
"Called from Main Body.

  (INPUT  extin,enext,vin,noa_busy,nclrd,end1d,clk2,encal_burst,noa_rst; 
   OUTPUT nbusy_d,out_d,en_d,nen_d);
   NODE   q0 CLOCKED_BY en_d RESET_BY (nclrd_pulse + /noa_rst);
   NODE   clk1, rep_cal, nclrd_pulse;
   NODE   en_count_rst, del_rep_cal DEFAULT_TO 0;
   NODE   en_count CLOCKED_BY rep_cal RESET_BY (/noa_rst + en_count_rst);   
   NODE   rep_count[12]CLOCKED_BY clk2 CLOCK_ENABLED_BY en_count RESET_BY (/noa_rst + /en_count);   

   q0   = 1;

   nclrd_pulse = level_to_pulse(nclrd, noa_rst);
   rep_cal = nclrd_pulse * encal_burst * q0; 

      en_count = 1;                 "FF clocked via nx input from pld3
      rep_count = rep_count .+. 1;     
                                   
      IF rep_count = 3321 THEN          
         en_count_rst = 1;          "reset counter enable FF
      ELSIF rep_count = 3320 THEN               
         del_rep_cal = 1;           "delayed y from counter.
      END IF;                       

   clk1 =  extin * enext * noa_busy
        +  vin * noa_busy
        +  del_rep_cal;             "vburst mod to include CAL pulses.

   sync
     (clk1,clk2,end1d,nclrd,        "TO
      nbusy_d,out_d,en_d,nen_d);    "FROM
      
END sync_calibrate;
"------------------------------------------------------------------------------------------------

"------------------------------------------------------------------------------------------------
PROCEDURE sync_slowcom            "E"
"Procedure for synchronising "SLOW COMMAND", sends out_e to pld3 .
"Called by Main Body.

  (INPUT  vin_e,noa_busy,nclr_e,end1_e,nclrc_e,clk2;
   OUTPUT nbusy_e,out_e,en_e,nen_e);
   NODE   clk1; 

   clk1 = vin_e * noa_busy;

   sync
      (clk1,clk2,end1_e,nclr_e,       "TO
       nbusy_e,out_e,en_e,nen_e);     "FROM
   
END sync_slowcom;
"------------------------------------------------------------------------------------------------

"------------------------------------------------------------------------------------------------
PROCEDURE count
"Called by Procedure busy (BUSY -1-).  Generates "NCOUNT_A", "NCOUNT_B", and "NCOUNT_C"  

  (INPUT  clk6,nen6,nclr6;
   OUTPUT ncount_a, ncount_b, ncount_c);
   NODE   ncount2,ncount3,ncount4,ncount5,ncount6,ncount7 DEFAULT_TO 1;
   NODE   count[3] CLOCKED_BY clk6 
                   CLOCK_ENABLED_BY /nen6 
                   RESET_BY /nclr6;

   count = count .+. 1;

   CASE count
      WHEN 2 => ncount2 = 0;
      WHEN 3 => ncount3 = 0;     
      WHEN 4 => ncount4 = 0;
      WHEN 5 => ncount5 = 0;     
      WHEN 6 => ncount6 = 0;
      WHEN 7 => ncount7 = 0;
    END CASE;
           
   ncount_a = ncount6;
   ncount_b = ncount6;
   ncount_c = ncount2;

END count;   
"------------------------------------------------------------------------------------------------

"------------------------------------------------------------------------------------------------
PROCEDURE busy
"Includes "BUSY -1-", "BUSY -2-", and "CLOCK INPUTS"
"Called from Main Body.

  (INPUT  noa_rst,clk2,nen_a,nen_b,nen_c,nen_d,en_d,nbusy_a,nbusy_b,nbusy_c,nbusy_d,nbusy_e,
          nclrc_e,nx,
          sreset,voarst,enint_busy,enext_busy1,enext_busy2,enext_busy3,enext_busy4,
          extbusy1,extbusy2,extbusy3,extbusy4,vbusy,
          nimext_clk,eclext_clk,enext_clk,enint_clk,int_clk,stop_clk;
   OUTPUT oa_reset,noa_reset,noa_busy,intbusy,extbusy,busyout,nbusy_c2,clkin,
          nclr_a,nclr_b,nclr_c,nclr_d,nclr_e,end1_a,end1_b,end1_c,end1_d,end1_e);
   NODE   z,ncount_a, ncount_b, ncount_c, nen6, nclr6, svreset, count9;
   NODE   q0 CLOCKED_BY svreset RESET_BY count9;
   NODE   count[4] CLOCKED_BY int_clk CLOCK_ENABLED_BY q0 RESET_BY /svreset;     "eclext/int swap
   NODE   clk_in;
   NODE   q1, en_clkin CLOCKED_BY /clk_in;
   
"BUSY -1-
"--------
   nen6     = nen_a * nen_b * nen_c;                                    "enable input to count
   nclr6    = /(nbusy_a * nbusy_b * nbusy_c) * noa_rst;                 "clr input to count
   count                                                                "calls procedure count
      (clk2,nen6,nclr6,                "TO
       ncount_a,ncount_b,ncount_c);    "FROM
   noa_busy = nbusy_a * nbusy_b * nen_c * nbusy_d * nbusy_e * noa_rst;  "gated busys.
                                                                        "23AUG99 mod: nbusy_c replaced by nen_c

   nclr_a   = ncount_a * noa_rst;
   nclr_b   = ncount_b * nbusy_a *     noa_rst;
   nclr_c   = ncount_c * nbusy_a *     nbusy_b      *   noa_rst;
   nclr_d   = nbusy_a  * nbusy_b * (nbusy_c + en_d) * (nx + nen_d) * noa_rst;
   nclr_e   = nbusy_a  * nbusy_b *      nbusy_c     *   nbusy_d    * nclrc_e * noa_rst;
   
   
   end1_a   = noa_busy;
   end1_b   = noa_busy;
   end1_c   = noa_busy + en_d;
   end1_d   = noa_busy;
   end1_e   = noa_busy;
   
"BUSY -2-                        " NB noa_reset is output to mono-stab, which is then input
"--------                        "     to this chip as noa_rst.
   q0 = 1;                       "data input of oa_reset ff
   oa_reset    = q0;
   noa_reset   = /q0;
   svreset = /sreset * /voarst;
   
   count = count .+. 1;    "set up counter
    
   IF count = 9 THEN       "used to reset q
     count9 = 1;           "oa_reset 9x25ns duration
   ELSE
     count9 = 0;
   END IF;     

   intbusy     = /noa_busy;                      
   extbusy     = extbusy1 * enext_busy1
                  + extbusy2 * enext_busy2 
                  + extbusy3 * enext_busy3 
                  + extbusy4 * enext_busy4;

   z           = extbusy                            "intermediate NODE
                  + vbusy;
   nbusy_c2    = /noa_busy
                  /+ z;       "NOR

   busyout     = /noa_busy * enint_busy 
               + z;
                                                   
"CLOCK INPUTS            
"------------ 
   q1       = stop_clk;                            " stop clock from pld1 when write reg08.
   en_clkin = q1;
  
   clk_in   = (nimext_clk + eclext_clk) * enext_clk * /enint_clk  "main clock generator from
            + enint_clk * int_clk;                                "  gated clock signals

   clkin    = clk_in * en_clkin; 

END busy;
"------------------------------------------------------------------------------------------------


"================================================================================================
"------------------------------------------------------------------------------------------------
"       SIGNAL DECLARATIONS for main body
" (INPUT/OUTPUT are chip I/O, NODEs are internal signals) 
"------------------------------------------------------------------------------------------------
INPUT  extina,   enext_a,  vina,       enint_a,    intina,  
       extinb,   enext_b,  vinb,       enint_b,    intinb, 
       extinc,   enext_c,  vinc,       enint_c1,   enint_c2,   intinc2, 
       extind,   enext_d,  vind,
       vine,     nclrc_e,
       clk2,     clk3,     nimext_clk, eclext_clk, enext_clk,   enint_clk,  int_clk, stop_clk,     
       noa_rst,  sreset,   voa_rst,    encal_burst,
       extbusy1, extbusy2, extbusy3,   extbusy4,   enint_busy,  vbusy,
       enext_busy1,    enext_busy2,    enext_busy3,    enext_busy4,
       nx,       y,        test_sw,    entrig_win, trig_win,    select[8];

NODE   extin_a,  vin_a,  intin_a,  
       extin_b,  vin_b,  intin_b, 
       extin_c,  vin_c,  intin_c1, intin_c2,
       extin_d,  vin_d,
       vin_e,
       voa_reset,
       nen_a,    nen_b,  nen_c,  nen_d,   nen_e,    
       nclr_a,   nclr_b, nclr_c, nclr_d,  nclr_e,
       nbusy_a,  en_a,   end1_a,
       nbusy_b,  en_b,   end1_b,
       nbusy_c,  en_c,   end1_c,
       nbusy_c2,
       nbusy_d,  en_d,   end1_d,
       nbusy_e,  en_e,   end1_e;
           
OUTPUT intbusy, extbusy, busyout, clkin,  noa_busy, oa_reset, noa_reset,
       out_a,   out_b,   out_c,out_ch,out_c1,out_c2,  out_d,  out_e;
                  
"------------------------------------------------------------------------------------------------
"        CODE for main body
"------------------------------------------------------------------------------------------------

"LEVEL_TO_PULSE conversions
"--------------------------
extin_a  = level_to_pulse(extina, noa_rst);     "converts input levels to pulses
intin_a  = level_to_pulse(intina, noa_rst);     " for certain inputs.
vin_a    = level_to_pulse(vina, noa_rst);       "

extin_b  = level_to_pulse(extinb, noa_rst);     "
intin_b  = level_to_pulse(intinb, noa_rst);     "
vin_b    = level_to_pulse(vinb, noa_rst);       "

extin_c  = level_to_pulse(extinc, noa_rst);     "
intin_c2 = level_to_pulse(intinc2, noa_rst);    "
vin_c    = level_to_pulse(vinc, noa_rst);       "

extin_d  = level_to_pulse(extind, noa_rst);     "
vin_d    = level_to_pulse(vind, noa_rst);       "

vin_e    = level_to_pulse(vine, noa_rst);       "

voa_reset = level_to_pulse(voa_rst, noa_rst);   "


"A - BC_RESET
"------------
sync_input
  (extin_a,enext_a,vin_a,enint_a,intin_a,noa_busy,nclr_a,end1_a,clk2, "TO

   nbusy_a,out_a,en_a,nen_a);                                         "FROM 


"B - SOFT_RESET
"--------------
sync_input
  (extin_b,enext_b,vin_b,enint_b,intin_b,noa_busy,nclr_b,end1_b,clk2, "TO

   nbusy_b,out_b,en_b,nen_b);                                         "FROM


"PRBS - RANDOM TRIGGER
"---------------------
prbs
  (intin_c2,enint_c1,noa_rst,          "TO

   intin_c1);                          "FROM


"C - TRIGGER
"-----------
sync_trigger   
  (test_sw,trig_win,extin_c,enext_c,vin_c,y,en_d,enint_c1,intin_c1,enint_c2,intin_c2,  "TO             
     noa_busy,nbusy_c2,nclr_c,end1_c,clk2,entrig_win,                                  "TO             
     select,clk3,out_d,                                                                "TO             
     nbusy_a,nbusy_b,nbusy_d,noa_rst,                                                  "TO
             
   nbusy_c,out_c,out_ch,out_c1,out_c2,en_c,nen_c);                                     "FROM           


"D - CALIBRATE
"-------------
sync_calibrate
  (extin_d,enext_d,vin_d,noa_busy,nclr_d,end1_d,clk2,encal_burst,noa_rst, "TO

   nbusy_d,out_d,en_d,nen_d);                                             "FROM 


"E - SLOW COMMAND
"----------------
sync_slowcom
  (vin_e,noa_busy,nclr_e,end1_e,nclrc_e,clk2,   "TO

   nbusy_e,out_e,en_e,nen_e);                   "FROM
   
"BUSY & CLKIN
"------------
busy
  (noa_rst,clk2,nen_a,nen_b,nen_c,nen_d,en_d,nbusy_a,nbusy_b,nbusy_c,nbusy_d,nbusy_e,"TO BUSY1
     nclrc_e,nx,                                                                     "TO BUSY1
     sreset,voa_reset,enint_busy,enext_busy1,enext_busy2,enext_busy3,enext_busy4,    "TO BUSY2
     extbusy1,extbusy2,extbusy3,extbusy4,vbusy,                                      "TO BUSY2
     nimext_clk,eclext_clk,enext_clk,enint_clk,int_clk,stop_clk,                   "TO CLOCK INPUTS

   oa_reset,noa_reset,noa_busy,intbusy,extbusy,busyout,nbusy_c2,clkin,               "FROM
     nclr_a,nclr_b,nclr_c,nclr_d,nclr_e,end1_a,end1_b,end1_c,end1_d,end1_e);         "FROM
      
"================================================================================================
