/* simple_core */
// Author Andrew Laffely
// Last modified: 12 Feb 03

module adder_core (reset, hold, in_ready, out_ready, data_in, data_out, read, write, in_addr, out_addr);
input reset, hold;                // External control signals
input [2:0] in_ready, out_ready;  // Input and Output port ready registers
input [31:0] data_in;             // Input data

output read, write;               // Read and Write signals
output [31:0] data_out;
output [1:0] in_addr, out_addr;   // Port addresses.
reg read, write; 
reg [31:0] data_out;
reg [1:0] in_addr, out_addr;   

reg [31:0] opA, opB;
reg [31:0] res;
reg ops_ready, res_ready; //Internal flow conrol
reg stall, go;
  
reg lclock;
initial
begin
	#3 lclock = 1'b0;
	forever #47 lclock = ~lclock;  // Use 10 or 20 or 40 or 80 etc.
end

/*********************** READ DATA *****************************/
always @ (posedge lclock)
  begin
	#1 if(((!ops_ready)||(!stall))&&(!hold)&&(!reset))  
	// Do not read anymore if full and stalled
		if(in_ready[in_addr])  // check port
			read = 1;
  end

always @ (negedge lclock)
  begin
	read = 0;
  end

always @ (negedge read)
  begin
    if (!reset)
      begin
	if ((in_addr[0])&&(!hold))
	  begin
		opB=data_in;
		ops_ready=1;
	  end
	else
	  begin
		opA=data_in;
	  end
	$display("In Core=%h addr=%b ops_ready=%b",data_in, in_addr, ops_ready);
	#1 in_addr[0]=~in_addr[0];   // next data	
      end
  end
/********************* End READ DATA ***************************/

/*********************** Write DATA ****************************/
always @ (posedge lclock)
  begin
	if((res_ready)&&(!hold)&&(!reset)) // wait until the pipe is full
		if(out_ready[out_addr])  // check port
			write = 1;
  end

always @ (negedge lclock)
  begin
	write = 0;
  end

always @ (negedge write)
  begin
	if(!reset)
	  begin
		data_out=res;
		$display("Out Core=%h out_addr=%b ops_ready=%b",data_out, out_addr, ops_ready);
	res_ready=0;
	  end
  end
/******************** End Write DATA ***************************/

/************************ Reset ********************************/
always @ (reset)
  begin
	read=0;
	write=0;
	in_addr=0;
	out_addr=0;
	ops_ready=0;
	res_ready=0;
	stall = 0;
  end
/*********************** End Reset *****************************/

/******************* Core flow Control *************************/
// stall tells the pipeline to stop adding and stop taking in data
always @ (posedge lclock)
  begin
	if(!out_ready[out_addr])
		stall = 1;
  end

always @ (posedge out_ready[out_addr])
  begin
	stall=0;
  end
/******************* End flow Control *************************/

/************************ Proccessing *************************/
always @ (posedge lclock)
  begin
	if((ops_ready)&&(!stall)&&(!hold))
	  begin
		res=opA+opB;  //Wow this 32 bit adder is fast
		res_ready=1;
		ops_ready=0;
		
	  end
  end
/********************* End Proccessing *************************/
endmodule


[ [ [ 'module',
      'adder_core',
      '(',
      [ ['reset'],
        ['hold'],
        ['in_ready'],
        ['out_ready'],
        ['data_in'],
        ['data_out'],
        ['read'],
        ['write'],
        ['in_addr'],
        ['out_addr']],
      ')',
      ';'],
    [ ['input', 'reset', 'hold', ';'],
      ['input', '[', '2', ':', '0', ']', 'in_ready', 'out_ready', ';'],
      ['input', '[', '31', ':', '0', ']', 'data_in', ';'],
      ['output', 'read', 'write', ';'],
      ['output', '[', '31', ':', '0', ']', 'data_out', ';'],
      ['output', '[', '1', ':', '0', ']', 'in_addr', 'out_addr', ';'],
      ['reg', ['read'], ['write'], ';'],
      ['reg', '[', '31', ':', '0', ']', ['data_out'], ';'],
      ['reg', '[', '1', ':', '0', ']', ['in_addr'], ['out_addr'], ';'],
      ['reg', '[', '31', ':', '0', ']', ['opA'], ['opB'], ';'],
      ['reg', '[', '31', ':', '0', ']', ['res'], ';'],
      ['reg', ['ops_ready'], ['res_ready'], ';'],
      ['reg', ['stall'], ['go'], ';'],
      ['reg', ['lclock'], ';'],
      [ 'initial',
        [ 'begin',
          [ [['#', '3'], [[['lclock'], '=', "1 'b 0"], ';']],
            [ 'forever',
              [['#', '47'], [[['lclock'], '=', '~', ['lclock']], ';']]]],
          'end']],
      [ 'always',
        ['@', '(', ['posedge', ['lclock']], ')'],
        [ 'begin',
          [ [ ['#', '1'],
              [ 'if',
                [ '(',
                  '(',
                  [ '(',
                    ['!', ['ops_ready']],
                    ')',
                    '||',
                    '(',
                    ['!', ['stall']],
                    ')'],
                  ')',
                  '&&',
                  '(',
                  ['!', ['hold']],
                  ')',
                  '&&',
                  '(',
                  ['!', ['reset']],
                  ')',
                  ')'],
                [ 'if',
                  ['(', ['in_ready', ['[', ['in_addr'], ']']], ')'],
                  [[['read'], '=', '1'], ';']]]]],
          'end']],
      [ 'always',
        ['@', '(', ['negedge', ['lclock']], ')'],
        ['begin', [[[['read'], '=', '0'], ';']], 'end']],
      [ 'always',
        ['@', '(', ['negedge', ['read']], ')'],
        [ 'begin',
          [ [ 'if',
              ['(', '!', ['reset'], ')'],
              [ 'begin',
                [ [ 'if',
                    [ '(',
                      '(',
                      [['in_addr', ['[', '0', ']']]],
                      ')',
                      '&&',
                      '(',
                      ['!', ['hold']],
                      ')',
                      ')'],
                    [ 'begin',
                      [ [[['opB'], '=', ['data_in']], ';'],
                        [[['ops_ready'], '=', '1'], ';']],
                      'end'],
                    'else',
                    ['begin', [[[['opA'], '=', ['data_in']], ';']], 'end']],
                  [ '$display',
                    '(',
                    '"In Core=%h addr=%b ops_ready=%b"',
                    ['data_in'],
                    ['in_addr'],
                    ['ops_ready'],
                    ')',
                    ';'],
                  [ ['#', '1'],
                    [ [ ['in_addr', ['[', '0', ']']],
                        '=',
                        '~',
                        ['in_addr', ['[', '0', ']']]],
                      ';']]],
                'end']]],
          'end']],
      [ 'always',
        ['@', '(', ['posedge', ['lclock']], ')'],
        [ 'begin',
          [ [ 'if',
              [ '(',
                '(',
                [['res_ready']],
                ')',
                '&&',
                '(',
                ['!', ['hold']],
                ')',
                '&&',
                '(',
                ['!', ['reset']],
                ')',
                ')'],
              [ 'if',
                ['(', ['out_ready', ['[', ['out_addr'], ']']], ')'],
                [[['write'], '=', '1'], ';']]]],
          'end']],
      [ 'always',
        ['@', '(', ['negedge', ['lclock']], ')'],
        ['begin', [[[['write'], '=', '0'], ';']], 'end']],
      [ 'always',
        ['@', '(', ['negedge', ['write']], ')'],
        [ 'begin',
          [ [ 'if',
              ['(', '!', ['reset'], ')'],
              [ 'begin',
                [ [[['data_out'], '=', ['res']], ';'],
                  [ '$display',
                    '(',
                    '"Out Core=%h out_addr=%b ops_ready=%b"',
                    ['data_out'],
                    ['out_addr'],
                    ['ops_ready'],
                    ')',
                    ';'],
                  [[['res_ready'], '=', '0'], ';']],
                'end']]],
          'end']],
      [ 'always',
        ['@', '(', [['reset']], ')'],
        [ 'begin',
          [ [[['read'], '=', '0'], ';'],
            [[['write'], '=', '0'], ';'],
            [[['in_addr'], '=', '0'], ';'],
            [[['out_addr'], '=', '0'], ';'],
            [[['ops_ready'], '=', '0'], ';'],
            [[['res_ready'], '=', '0'], ';'],
            [[['stall'], '=', '0'], ';']],
          'end']],
      [ 'always',
        ['@', '(', ['posedge', ['lclock']], ')'],
        [ 'begin',
          [ [ 'if',
              ['(', '!', ['out_ready', ['[', ['out_addr'], ']']], ')'],
              [[['stall'], '=', '1'], ';']]],
          'end']],
      [ 'always',
        ['@', '(', ['posedge', ['out_ready', ['[', ['out_addr'], ']']]], ')'],
        ['begin', [[[['stall'], '=', '0'], ';']], 'end']],
      [ 'always',
        ['@', '(', ['posedge', ['lclock']], ')'],
        [ 'begin',
          [ [ 'if',
              [ '(',
                '(',
                [['ops_ready']],
                ')',
                '&&',
                '(',
                ['!', ['stall']],
                ')',
                '&&',
                '(',
                ['!', ['hold']],
                ')',
                ')'],
              [ 'begin',
                [ [[['res'], '=', ['opA'], '+', ['opB']], ';'],
                  [[['res_ready'], '=', '1'], ';'],
                  [[['ops_ready'], '=', '0'], ';']],
                'end']]],
          'end']]],
    'endmodule']]
