/* Output port */
// Author Andrew Laffely
// Last modified: 12 Feb 03
// !!!!!!!!!!!!!!! DO NOT CHANGE THIS FILE !!!!!!!!!!!!!!!!!!!!!!!!!
module out_port (gclock, reset, i_addr, c_data, c_addr, c_write, valid_next, data_out, ready);

input gclock, reset;
input [1:0] i_addr;     // buffer address requested by ccm
input [1:0] c_addr;     // buffer address requested by core
input [31:0] c_data;    // the data sent from the core
input valid_next;       // flow control bit sent from upstream block
input c_write;	        // write singal from core

output [32:0] data_out; // the data to be sent to interface
output [2:0] ready;     // flow control, port "ready" signal, sent to core
reg [32:0] data_out;
reg [2:0] ready;        // Port ready signal

reg [6:0] valid;        // contains the valid bits of the data in the port
reg [31:0] data [6:0];  // the data in the cdm
reg [2:0] i_addr_hold;  // hold the buf addr while evaluating  
reg [2:0] c_addr_hold;  // hold the buf addr while evaluating
reg [2:0] i_buf_state, c_buf_state; // first or second buf in each port

reg faketiming;         // Makes level sensitive transitions work properly
initial
begin
	faketiming = 1'b0;
	forever #1 faketiming = ~faketiming;
end

// *********************** INTERCONNECT *********************** //
always @ (posedge gclock)  //interconnect side
  begin
    if(!reset)
      begin
	//update valid from last transfer
	if(!(i_addr_hold[2:1] == 2'b11))  
	  begin
	    if(!(valid_next)&&data_out[32])
	      begin
		i_buf_state[i_addr_hold[2:1]]=~i_buf_state[i_addr_hold[2:1]];
		valid[i_addr_hold]=0;
	      end
	  end

	#1 i_addr_hold = {i_addr,i_buf_state[i_addr]};

	//send data
	if(!(i_addr == 2'b11))  //default no data
		#1 data_out={valid[i_addr_hold], data[i_addr_hold]};
	else
		#1 data_out[32]=0;
	end
end
// ******************** END INTERCONNECT *********************** //

// *************************** CORE **************************** //
always @ (posedge c_write)
  begin
	c_addr_hold = {c_addr, c_buf_state[c_addr]};
  end

always @ (negedge c_write) //Core
  begin
	if(!reset)
	  begin
		c_buf_state[c_addr_hold[2:1]]=~c_buf_state[c_addr_hold[2:1]];
		valid[c_addr_hold]=1;  //glitch reset
	  end
  end
// ************************** END CORE ************************* //

always @ (faketiming)
  begin
    if (reset)
      begin
	valid = 4'b0000;
	i_addr_hold = 3'b111;
	i_buf_state=3'b000;
	c_buf_state=3'b000;
      end
   else
      begin
	ready[0]=~valid[c_buf_state[0]];
	ready[1]=~valid[c_buf_state[1]];
	ready[2]=~valid[c_buf_state[2]];

	// *************************** CORE ************************ //
	if (c_write)
	  begin
		data[c_addr_hold]=c_data[31:0];
	  end
	// ************************ END CORE ********************** //
  end
end
endmodule

