// Verilog HDL for "RSFQ.lib", "and_gate" "_functional"

// Module AND gate
module and_gate (a, b, clk, out);

input
	a, b, clk;

output
	out;
reg 
	out;

parameter
	t_hold	= 12,
	t_setup	=  1,
	delay	= 25,

// multichannel description of a warning file
	warning_file=2,  
// multichannel description of a delay file
	delay_file = warning_file<<1;

reg
	a_internal, b_internal, clk_internal,
	a_state, b_state,          // internal state at inputs a and b
	a_set, b_set;		   // signals determining the moment when
				   // the state of the a,b inputs changes to "1"
integer
	data_delay, 	// delay between a (b) and a_internal (b_internal)
	clk_delay, 	// delay between clk and clk_internal
	out_delay, 	// delay between clk_internal and out
	out_value,	// output value in a given clock cycle
	last_clk_time,	// time when the last clock pulse appeared
	vt_hold,	// variable hold
	vt_setup,	// variable setup
	vdelay;		// variable delay


`include "INIT"

`ifdef RANDOM_DELAYS
 `include "RANDOM_GATE"
`endif


initial 
	begin
		vt_hold = t_hold;
		vt_setup = t_setup;
		vdelay = delay;

`ifdef RANDOM_DELAYS
		delay_dev = and_gate_variation*delay;
		vdelay = $dist_normal(and_gate_seed, delay, delay_dev);
		vt_hold = $dist_normal(and_gate_seed, t_hold, and_hs_dev);
		vt_setup = t_setup + (t_hold - vt_hold);
`endif

		#0 $fdisplay(delay_file, "module=%m, nom_delay=%0d, delay=%0d", delay, vdelay);
		#0 $fdisplay(delay_file, "module=%m, nom_hold=%0d, hold=%0d", t_hold, vt_hold);
		#0 $fdisplay(delay_file, "module=%m, nom_setup=%0d, setup=%0d", t_setup, vt_setup);


// define delays between inputs & outputs and the corresponding
//  internal auxiliary registers
	  	if(vt_hold<0)
		  begin
	    		data_delay = -vt_hold;
	    	  	clk_delay = 0;
		  	out_delay = vdelay;
		  end
	  	else
		  begin
	    	  	data_delay = 0;
	    	  	clk_delay = vt_hold;
		  	out_delay=vdelay-vt_hold;
		  end

// clear internal registers and the output signal
		a_internal = 0;
		b_internal = 0;
		clk_internal = 0;
		last_clk_time = 0;
		a_state = 0;
		b_state = 0;
		a_set = 0;
		b_set = 0;
		out = 0;
	end

always @(posedge a) 	// Execute at positive edge of a
	  a_internal <= #(data_delay) a;

always @(posedge b) 	// Execute at positive edge of b
	  b_internal <= #(data_delay) b;

always @(posedge clk) 	// Execute at positive edge of clk
	  clk_internal <= #(clk_delay) clk;

always @(posedge a_internal)
	begin
// setting an internal state at the input a
                a_state <= a_state | 1'bx;
		if (a_internal === 1)
		  a_set <= #(vt_hold+vt_setup) 1;

		a_internal <= 0;
	end

always @(posedge b_internal)
	begin
// setting an internal state at the input a
                b_state <= b_state | 1'bx;
		if (b_internal === 1)
		  b_set <= #(vt_hold+vt_setup) 1;

		b_internal <= 0;
	end

always @(posedge a_set)
	begin
		if ($stime - last_clk_time >= vt_hold+vt_setup)
			a_state = 1;
		else
		  begin
			a_state = 1'bx;

		  // generating a warning
		  	$fwrite(warning_file, 
			 "Violation of hold/setup time in module %m.\n");
			$fwrite(warning_file,
			"Input A pulse at %0d,",
			 $stime-data_delay-vt_hold-vt_setup);
			$fwrite(warning_file,
			"\tClock pulse at %0d.\n", last_clk_time-clk_delay);
		  end

		a_set <= 0;
	end

always @(posedge b_set)
	begin
		if ($stime - last_clk_time >= vt_hold+vt_setup)
			b_state = 1;
		else
		  begin
			b_state = 1'bx;

		  // generating a warning
		  	$fwrite(warning_file, 
			 "Violation of hold/setup time in module %m.\n");
			$fwrite(warning_file,
			"Input B pulse at %0d,",
			 $stime-data_delay-vt_hold-vt_setup);
			$fwrite(warning_file,
			"\tClock pulse at %0d.\n", last_clk_time-clk_delay);
		  end

		b_set <= 0;
	end


always @(posedge clk_internal)	
	begin
// computing the output
		if (clk_internal === 1'bx)
		  out_value = 1'bx;
		else
		  out_value = a_state & b_state;

// transfering the result to the output
		out <= #(out_delay) out_value;
		out <= #(out_delay+2) 0;

// clearing the internal state of A and B inputs
		a_state  <= 0;
		b_state  <= 0;

		clk_internal <= 0;
		last_clk_time = $stime;

	end

endmodule


[ [ ['module', 'and_gate', '(', [['a'], ['b'], ['clk'], ['out']], ')', ';'],
    [ ['input', 'a', 'b', 'clk', ';'],
      ['output', 'out', ';'],
      ['reg', ['out'], ';'],
      [ 'parameter',
        ['t_hold', '=', '12'],
        ['t_setup', '=', '1'],
        ['delay', '=', '25'],
        ['warning_file', '=', '2'],
        ['delay_file', '=', ['warning_file'], '<<', '1'],
        ';'],
      [ 'reg',
        ['a_internal'],
        ['b_internal'],
        ['clk_internal'],
        ['a_state'],
        ['b_state'],
        ['a_set'],
        ['b_set'],
        ';'],
      [ 'integer',
        ['data_delay'],
        ['clk_delay'],
        ['out_delay'],
        ['out_value'],
        ['last_clk_time'],
        ['vt_hold'],
        ['vt_setup'],
        ['vdelay'],
        ';'],
      [ 'initial',
        [ 'begin',
          [ [[['vt_hold'], '=', ['t_hold']], ';'],
            [[['vt_setup'], '=', ['t_setup']], ';'],
            [[['vdelay'], '=', ['delay']], ';'],
            [[['delay_dev'], '=', ['and_gate_variation'], '*', ['delay']], ';'],
            [ [ ['vdelay'],
                '=',
                [ '$dist_normal',
                  '(',
                  ['and_gate_seed'],
                  ['delay'],
                  ['delay_dev'],
                  ')']],
              ';'],
            [ [ ['vt_hold'],
                '=',
                [ '$dist_normal',
                  '(',
                  ['and_gate_seed'],
                  ['t_hold'],
                  ['and_hs_dev'],
                  ')']],
              ';'],
            [ [ ['vt_setup'],
                '=',
                ['t_setup'],
                '+',
                '(',
                [['t_hold'], '-', ['vt_hold']],
                ')'],
              ';'],
            [ ['#', '0'],
              [ '$fdisplay',
                '(',
                ['delay_file'],
                '"module=%m, nom_delay=%0d, delay=%0d"',
                ['delay'],
                ['vdelay'],
                ')',
                ';']],
            [ ['#', '0'],
              [ '$fdisplay',
                '(',
                ['delay_file'],
                '"module=%m, nom_hold=%0d, hold=%0d"',
                ['t_hold'],
                ['vt_hold'],
                ')',
                ';']],
            [ ['#', '0'],
              [ '$fdisplay',
                '(',
                ['delay_file'],
                '"module=%m, nom_setup=%0d, setup=%0d"',
                ['t_setup'],
                ['vt_setup'],
                ')',
                ';']],
            [ 'if',
              ['(', ['vt_hold'], '<', '0', ')'],
              [ 'begin',
                [ [[['data_delay'], '=', '-', ['vt_hold']], ';'],
                  [[['clk_delay'], '=', '0'], ';'],
                  [[['out_delay'], '=', ['vdelay']], ';']],
                'end'],
              'else',
              [ 'begin',
                [ [[['data_delay'], '=', '0'], ';'],
                  [[['clk_delay'], '=', ['vt_hold']], ';'],
                  [[['out_delay'], '=', ['vdelay'], '-', ['vt_hold']], ';']],
                'end']],
            [[['a_internal'], '=', '0'], ';'],
            [[['b_internal'], '=', '0'], ';'],
            [[['clk_internal'], '=', '0'], ';'],
            [[['last_clk_time'], '=', '0'], ';'],
            [[['a_state'], '=', '0'], ';'],
            [[['b_state'], '=', '0'], ';'],
            [[['a_set'], '=', '0'], ';'],
            [[['b_set'], '=', '0'], ';'],
            [[['out'], '=', '0'], ';']],
          'end']],
      [ 'always',
        ['@', '(', ['posedge', ['a']], ')'],
        [ [['a_internal'], '<=', ['#', '(', [['data_delay']], ')'], ['a']],
          ';']],
      [ 'always',
        ['@', '(', ['posedge', ['b']], ')'],
        [ [['b_internal'], '<=', ['#', '(', [['data_delay']], ')'], ['b']],
          ';']],
      [ 'always',
        ['@', '(', ['posedge', ['clk']], ')'],
        [ [['clk_internal'], '<=', ['#', '(', [['clk_delay']], ')'], ['clk']],
          ';']],
      [ 'always',
        ['@', '(', ['posedge', ['a_internal']], ')'],
        [ 'begin',
          [ [[['a_state'], '<=', ['a_state'], '|', "1 'b x"], ';'],
            [ 'if',
              ['(', ['a_internal'], '===', '1', ')'],
              [ [ ['a_set'],
                  '<=',
                  ['#', '(', [['vt_hold'], '+', ['vt_setup']], ')'],
                  '1'],
                ';']],
            [[['a_internal'], '<=', '0'], ';']],
          'end']],
      [ 'always',
        ['@', '(', ['posedge', ['b_internal']], ')'],
        [ 'begin',
          [ [[['b_state'], '<=', ['b_state'], '|', "1 'b x"], ';'],
            [ 'if',
              ['(', ['b_internal'], '===', '1', ')'],
              [ [ ['b_set'],
                  '<=',
                  ['#', '(', [['vt_hold'], '+', ['vt_setup']], ')'],
                  '1'],
                ';']],
            [[['b_internal'], '<=', '0'], ';']],
          'end']],
      [ 'always',
        ['@', '(', ['posedge', ['a_set']], ')'],
        [ 'begin',
          [ [ 'if',
              [ '(',
                ['$stime'],
                '-',
                ['last_clk_time'],
                '>=',
                ['vt_hold'],
                '+',
                ['vt_setup'],
                ')'],
              [[['a_state'], '=', '1'], ';'],
              'else',
              [ 'begin',
                [ [[['a_state'], '=', "1 'b x"], ';'],
                  [ '$fwrite',
                    '(',
                    ['warning_file'],
                    '"Violation of hold/setup time in module %m.\\n"',
                    ')',
                    ';'],
                  [ '$fwrite',
                    '(',
                    ['warning_file'],
                    '"Input A pulse at %0d,"',
                    ['$stime'],
                    '-',
                    ['data_delay'],
                    '-',
                    ['vt_hold'],
                    '-',
                    ['vt_setup'],
                    ')',
                    ';'],
                  [ '$fwrite',
                    '(',
                    ['warning_file'],
                    '"\\tClock pulse at %0d.\\n"',
                    ['last_clk_time'],
                    '-',
                    ['clk_delay'],
                    ')',
                    ';']],
                'end']],
            [[['a_set'], '<=', '0'], ';']],
          'end']],
      [ 'always',
        ['@', '(', ['posedge', ['b_set']], ')'],
        [ 'begin',
          [ [ 'if',
              [ '(',
                ['$stime'],
                '-',
                ['last_clk_time'],
                '>=',
                ['vt_hold'],
                '+',
                ['vt_setup'],
                ')'],
              [[['b_state'], '=', '1'], ';'],
              'else',
              [ 'begin',
                [ [[['b_state'], '=', "1 'b x"], ';'],
                  [ '$fwrite',
                    '(',
                    ['warning_file'],
                    '"Violation of hold/setup time in module %m.\\n"',
                    ')',
                    ';'],
                  [ '$fwrite',
                    '(',
                    ['warning_file'],
                    '"Input B pulse at %0d,"',
                    ['$stime'],
                    '-',
                    ['data_delay'],
                    '-',
                    ['vt_hold'],
                    '-',
                    ['vt_setup'],
                    ')',
                    ';'],
                  [ '$fwrite',
                    '(',
                    ['warning_file'],
                    '"\\tClock pulse at %0d.\\n"',
                    ['last_clk_time'],
                    '-',
                    ['clk_delay'],
                    ')',
                    ';']],
                'end']],
            [[['b_set'], '<=', '0'], ';']],
          'end']],
      [ 'always',
        ['@', '(', ['posedge', ['clk_internal']], ')'],
        [ 'begin',
          [ [ 'if',
              ['(', ['clk_internal'], '===', "1 'b x", ')'],
              [[['out_value'], '=', "1 'b x"], ';'],
              'else',
              [[['out_value'], '=', ['a_state'], '&', ['b_state']], ';']],
            [ [['out'], '<=', ['#', '(', [['out_delay']], ')'], ['out_value']],
              ';'],
            [ [['out'], '<=', ['#', '(', [['out_delay'], '+', '2'], ')'], '0'],
              ';'],
            [[['a_state'], '<=', '0'], ';'],
            [[['b_state'], '<=', '0'], ';'],
            [[['clk_internal'], '<=', '0'], ';'],
            [[['last_clk_time'], '=', ['$stime']], ';']],
          'end']]],
    'endmodule']]
