module: vco_integrator_quantizer
parameters: 
  double per_mm 
  int n_stages 
  double fosc 
  double kv 
  double k2 
  double k3
  double k4
  int mm_seed
inputs:  
  double_interp clk 
  double vctrl
outputs:  
  double freq_out
  double phase_out
static_variables:
  int n 
  int flag
  double delta_phase
  double phase_norm
  double phase_accum
  double phase_current
  double nom_tpd
  double vco_phase
  double count
  double i_nom
  int inv_vec_ptr
  int dummy
  int xor_phase
  int xp
  int xor_out 
  int inv_vec_init_val 
  int dummy_inv
  int xor_vec_init_val
  int dummy_xor_phase
  int ref_state
  int ref_phase
  int inv_phase
  int diff_out
classes:  
  Vco vco("fosc+kv*x+k2*x^2+k3*x^3+k4*x^4","fosc,kv,k2,k3,k4,Ts",fosc,kv,k2,k3,k4,Ts);
  List phase_mm_list()
  List phase_accum_list()
  Rand rand_mm("gauss")
  EdgeDetect clk_edge()
  IntVector inv_vec()
  IntVector ff_vec()
  IntVector ref_vec0()  
  IntVector ref_vec1()
  IntVector ref_vec2()
  IntVector ref_vec3()  
init:
  int i;
  double phase_mm_val = 0.0;
  delta_phase = 2*PI/n_stages/2; //equivalent phase step 
  inv_vec.set_length(n_stages);
  ff_vec.set_length(n_stages);
  ref_vec0.set_length(n_stages);
  ref_vec1.set_length(n_stages);
  ref_vec2.set_length(n_stages);
  ref_vec3.set_length(n_stages);
  inv_vec_init_val = 0;
  dummy_inv = 0;
  dummy_xor_phase = 0;
  if (mm_seed > 0)
  {
     rand_mm.set_seed(mm_seed);
  }
  for (i = 0; i < n_stages; i++)
  {
    //since can't have negative phase steps
    phase_mm_val = delta_phase*(1+per_mm/100*rand_mm.inp());
    phase_mm_val = phase_mm_val > 0.0 ? phase_mm_val : -1*phase_mm_val;
    phase_mm_list.inp(phase_mm_val);
    inv_vec.set_elem(i,dummy_inv);
    if (i <= floor(n_stages/2))
    {   
       ref_vec0.set_elem(i,dummy_xor_phase);
       ref_vec2.set_elem(i,1-dummy_xor_phase);
    }
    else
    {
       ref_vec0.set_elem(i,1-dummy_xor_phase);
       ref_vec2.set_elem(i,dummy_xor_phase);
    }
    ref_vec1.set_elem(i,dummy_xor_phase);
    ref_vec3.set_elem(i,1-dummy_xor_phase);
    dummy_inv = 1-dummy_inv;
    dummy_xor_phase = 1-dummy_xor_phase;
    ref_state = 0;
  }
  phase_norm = 2*PI/(2*n_stages*phase_mm_list.mean());
  phase_accum = 0; 
  for (i = 0; i < 2*n_stages; i++)
  {
    phase_accum_list.inp(phase_accum);
    if (i < (2*n_stages-1))
    {
       phase_accum = phase_accum + phase_norm*phase_mm_list.read();
    }
  }
  phase_current = phase_accum_list.read();   
  count = 0; //initialize pointer of inverter_list to zero
  phase_out = 0;
  inv_vec_ptr = 0;
  flag = 0;
code:  
  if (clk_edge.inp(clk)) 
  {
    freq_out = 0;
    phase_out = 0;
    count = 0;
    for (xp=0;xp<n_stages;xp++)
    {
      switch(ref_state) {
	case 0:
	   ref_phase = ref_vec0.get_elem(xp);
	   break;
	case 1:
           ref_phase = ref_vec1.get_elem(xp);
	   break;
	case 2:
           ref_phase = ref_vec2.get_elem(xp);
	   break;
	case 3:
	   ref_phase = ref_vec3.get_elem(xp);
	   break;
      }
      inv_phase = inv_vec.get_elem(xp);
      xor_out = abs(inv_phase-ref_phase);
      phase_out += xor_out;
      diff_out = abs(inv_phase-ff_vec.get_elem(xp));
      freq_out += diff_out;
      ff_vec.set_elem(xp,inv_phase);
    }
    ref_state += 1;
    ref_state = ref_state%4;
  }
  vco.inp(vctrl);
  vco_phase = vco.phase;
  if (vco.phase > phase_current)
     flag = 1;  
  while(flag)
  {
    if (phase_current == 0)
    {
       if (vco.phase < phase_accum)
       {
          dummy = 1-inv_vec.get_elem(inv_vec_ptr);
          inv_vec.set_elem(inv_vec_ptr,dummy);
          count++;
          phase_current = phase_accum_list.read();
          inv_vec_ptr++;
          if (inv_vec_ptr >= n_stages)
          {
             inv_vec_ptr-=n_stages;
	     inv_vec_ptr=0;
          }
          if (vco.phase < phase_current) flag = 0; 
       }
       else flag = 0;
    }
    else
    {
       dummy = 1-inv_vec.get_elem(inv_vec_ptr);
       inv_vec.set_elem(inv_vec_ptr,dummy);
       count++;
       phase_current = phase_accum_list.read();
       inv_vec_ptr++;
       if (inv_vec_ptr >= n_stages)
       {
	  inv_vec_ptr=0;
       }
       if (vco.phase < phase_current) flag = 0;
    } 
  }
