OpenCores
URL https://opencores.org/ocsvn/ht_tunnel/ht_tunnel/trunk

Subversion Repositories ht_tunnel

[/] [ht_tunnel/] [trunk/] [rtl/] [systemc/] [flow_control_l2/] [flow_control_l3.cpp] - Rev 19

Compare with Previous | Blame | View Log

//flow_control_l3.cpp
 
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is HyperTransport Tunnel IP Core.
 *
 * The Initial Developer of the Original Code is
 * Ecole Polytechnique de Montreal.
 * Portions created by the Initial Developer are Copyright (C) 2005
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Jean-Francois Belanger
 *   Ami Castonguay <acastong@grm.polymtl.ca>
 *
 * Alternatively, the contents of this file may be used under the terms
 * of the Polytechnique HyperTransport Tunnel IP Core Source Code License 
 * (the  "PHTICSCL License", see the file PHTICSCL.txt), in which case the
 * provisions of PHTICSCL License are applicable instead of those
 * above. If you wish to allow use of your version of this file only
 * under the terms of the PHTICSCL License and not to allow others to use
 * your version of this file under the MPL, indicate your decision by
 * deleting the provisions above and replace them with the notice and
 * other provisions required by the PHTICSCL License. If you do not delete
 * the provisions above, a recipient may use your version of this file
 * under either the MPL or the PHTICSCL License."
 *
 * ***** END LICENSE BLOCK ***** */
 
#include "flow_control_l3.h"
 
flow_control_l3::flow_control_l3(sc_module_name name) : sc_module(name)
{
	/** Processes of the design.  The sensitivity list is in function
		of what theses processes uses.*/
 
	SC_METHOD(fc_fsm_state);
		sensitive_pos << clock;
		sensitive_neg << resetx;
 
	SC_METHOD(fc_fsm);
		sensitive  << curr_state << fifo_user_available 
			<< ro_available_fwd << ro_nop_req_fc << db_nop_req_fc  
			<<  has_nop_buffers_to_send
			<< fc_data_vc_ui 
			<< resetx 
 
			<< fifo_user_packet << fifo_user_available
			<< eh_cmd_data_fc << eh_available_fc
			<< csr_dword_fc << csr_available_fc
			<< ro_packet_fwd << ro_available_fwd
 
			<< data_cnt << has_data << ldtstopx  << chain_current_state
			<< fwd_next_node_buffer_status_ro
			<< nop_next_to_send << lk_consume_fc 
			<< found_next_state 
			<< found_load_fwd_pkt 
			<< found_load_eh_pkt
			<< found_load_csr_pkt 
			<< found_load_user_fifo_pkt 
			<< found_next_chain_current_state
			<< found_fc_ctr_mux
			<< found_fc_nop_sent
			<< found_generate_disconnect_nop
			<< found_next_data_cnt
			<< found_next_has_data
			<< found_current_sent_type
			<< buffered_fwd_vctype_db
			<< found_fwd_vctype_db
			<< buffered_fwd_address_db
			<< found_fwd_address_db
			<< buffered_fc_data_vc_ui
			<< found_fc_data_vc_ui
			<< found_local_packet_issued
			<< found_next_fairness_vc_reserved[0] << found_next_fairness_vc_reserved[1] << found_next_fairness_vc_reserved[2]
 
			<< registered_lk_initiate_retry_disconnect
			<< found_hold_user_fifo_pkt
			<< fc_lctl_lk << fc_hctl_lk
 
#ifdef RETRY_MODE_ENABLED
			<< registered_lk_rx_connected
			<< received_ack
			<< found_new_history_entry_size_m1
			<< found_new_history_entry
			<< new_history_entry_size_m1
			<< retry_disconnect_initiated<< cd_initiate_retry_disconnect
			<< history_playback_done << history_packet 
			<< csr_retry 
 
			<< foundh_fc_ctr_mux << foundh_fc_nop_sent << foundh_next_state
			<< foundh_next_fc_lctl_lk << foundh_next_fc_hctl_lk << foundh_next_calculate_nop_crc
			<< foundh_next_calculate_crc << foundh_next_data_cnt << foundh_next_has_data
			<< foundh_current_sent_type << foundh_consume_history
#endif
			;
 
	SC_METHOD(find_next_state);
	sensitive << ro_nop_req_fc << db_nop_req_fc << nop_next_to_send
		<< ldtstopx
		<< csr_dword_fc 
		<< csr_available_fc
		<< fwd_next_node_buffer_status_ro << eh_cmd_data_fc 
		<< fifo_user_packet << eh_available_fc << fifo_user_available
		<< ro_packet_fwd << ro_available_fwd 
		<< local_priority
		<< fairness_vc_reserved[0] << fairness_vc_reserved[1] << fairness_vc_reserved[2]
		<< fc_data_vc_ui
		<< buffered_fwd_vctype_db << buffered_fwd_address_db
#ifdef RETRY_MODE_ENABLED
		<< csr_retry
		<< room_available_in_history 
		<< cd_initiate_retry_disconnect
		<< retry_disconnect_initiated 
#endif
		;
#ifdef RETRY_MODE_ENABLED
	SC_METHOD(find_next_retry_state);
	sensitive << ro_nop_req_fc << db_nop_req_fc << nop_next_to_send
		<< ldtstopx << fwd_next_node_buffer_status_ro << history_packet
		<< history_playback_done << foundh_generate_disconnect_nop;
 
#endif
}
 
void flow_control_l3::fc_fsm_state( void )
{  
 
	//Upon the reset signal, go to the RESET_STATE and clear any chain state
	if (resetx == false) {
		curr_state.write(NOP_SENT);
		chain_current_state = NO_CHAIN_STATE;
 
		fc_lctl_lk = true;
		fc_hctl_lk = true;
 
#ifdef RETRY_MODE_ENABLED
		received_ack = false;
		fc_disconnect_lk = false;
		registered_lk_rx_connected = false;
		registered_lk_initiate_retry_disconnect = false;
		retry_disconnect_initiated = false;
 
		select_crc_output = false;
		select_nop_crc_output = false;
 
		//We start with a nop, so calculate CRC
		calculate_nop_crc = true;
		calculate_crc = false;
#endif
 
		buffered_fc_data_vc_ui = VC_NONE;
		buffered_fwd_address_db = 0;
		buffered_fwd_vctype_db = VC_NONE;
 
		data_cnt = 0;
		has_data = false;
 
		for(int n = 0; n < 3; n++)
			fairness_vc_reserved[n] = false;
 
	}
	//Otherwise, store the next value
	else {
		curr_state.write(next_state.read());
 
#ifdef RETRY_MODE_ENABLED
		fc_disconnect_lk = next_fc_disconnect_lk;
		registered_lk_rx_connected = lk_rx_connected;
		registered_lk_initiate_retry_disconnect = lk_initiate_retry_disconnect;
#endif
		chain_current_state = next_chain_current_state;
 
		fc_lctl_lk = next_fc_lctl_lk;
		fc_hctl_lk = next_fc_hctl_lk;
 
#ifdef RETRY_MODE_ENABLED
		/**It might not be possible to start a retry a retry sequence
		immediately after we receive a signal to initiate it, so store
		that a retry sequence was initiated and clear it later when we
		take it into account*/
		if(clear_retry_disconnect_initiated){
			retry_disconnect_initiated = false;
		}
		else if(cd_initiate_retry_disconnect.read() ||
				registered_lk_initiate_retry_disconnect.read())
			retry_disconnect_initiated = true;
		else
			retry_disconnect_initiated = retry_disconnect_initiated.read();
 
		/**
			When we are in retry mode, we want to wait until we have received
			at least a single ack that represents the last good packet they
			received, so that we know when to replay the history.  received_ack
			keeps track if we have received that first ack
		*/
		if(lk_rx_connected == false)
			received_ack = false;
		else if(nop_received == true)
			received_ack = true;
		else
			received_ack = received_ack.read();
 
		select_crc_output = next_select_crc_output;
		select_nop_crc_output = next_select_nop_crc_output;
 
		calculate_nop_crc = next_calculate_nop_crc;
		calculate_crc = next_calculate_crc;
 
#endif
 
		buffered_fc_data_vc_ui = fc_data_vc_ui.read();
		buffered_fwd_address_db = fwd_address_db.read();
		buffered_fwd_vctype_db = fwd_vctype_db;
 
		data_cnt = next_data_cnt;
		has_data = next_has_data;
 
		for(int n = 0; n < 3; n++)
			fairness_vc_reserved[n] = next_fairness_vc_reserved[n];
	}
}
 
 
void flow_control_l3::fc_fsm( void ){
	// test to know if a nop request is present
	bool nop_req;
	if (ro_nop_req_fc ==  true || db_nop_req_fc ==  true || nop_next_to_send == true )
		nop_req = true;
	else
		nop_req  = false;
 
	//far_end buffer status
	sc_bv<6> buffer_status_tmp = fwd_next_node_buffer_status_ro;
 
	//variable who contain the status for response. useful to know quickly if a CSR
	//or EH can be send
	sc_bv<2> far_end_resp_stat = (buffer_status_tmp[0],buffer_status_tmp[1]);
 
	//control  of the multiplexer
	fc_ctr_mux = FC_MUX_FEEDBACK;
	//variable indicating that a nop is currently send
	fc_nop_sent = false;
	// variable indicating the amount of data remaining for a sequence
	next_data_cnt = data_cnt;
	// Indicate a data packet consonmmation to the data buffer
	fwd_read_db = false;	
	//Erase a data packet from the buffers
	fwd_erase_db = false;
	// indicate a data packet consonmmation to the user buffer
	fc_consume_data_ui = false;
 
	//acknowledges
	fwd_ack_ro = false;
	consume_user_fifo = false;
	fc_ack_eh = false;
	fc_ack_csr = false;
 
	//Hold the packet so it doesn't change after sending the first dword
	hold_user_fifo = false;
 
#ifdef RETRY_MODE_ENABLED
	//History
	begin_history_playback = false;
	stop_history_playback = false;
	consume_history = false;
	add_to_history = false;
	new_history_entry = false;
	new_history_entry_size_m1 = 0;
 
	//Per-packet crc
	clear_crc = false;
	clear_nop_crc = false;
 
	// ctl signal, in reset it have no meaning
	next_fc_disconnect_lk = false;
 
	//Some other default outputs
	clear_farend_count = false;
 
	next_select_crc_output = false;
	next_select_nop_crc_output = false;
	clear_retry_disconnect_initiated = false;
#endif
 
	//When this is true, the nop framer will produce a disconnect nop
	generate_disconnect_nop = false;
 
 
	//Default, not sending anything
	current_sent_type = "000000";
 
 
	next_chain_current_state = chain_current_state;
 
	//By default, keep sending the same VC on the output
	fc_data_vc_ui = buffered_fc_data_vc_ui.read();
	fwd_vctype_db = buffered_fwd_vctype_db.read();
	fwd_address_db = buffered_fwd_address_db.read();
 
	//For the  fairness algorithm
	local_packet_issued = false;
	for(int n = 0; n < 3; n++)
		next_fairness_vc_reserved[n] = fairness_vc_reserved[n];
 
	next_state = curr_state.read();
 
	next_fc_lctl_lk = true;
	next_fc_hctl_lk = true;
	next_has_data = has_data.read();
 
	//By default, don't calculate any CRC
#ifdef RETRY_MODE_ENABLED
	next_calculate_crc = false;
	next_calculate_nop_crc = false;
#endif
 
	/**
		Select what to do and output in functino of our present state
	*/
	switch (curr_state.read()) {
	//State that sends nop
 
	case FWD_CMD32_SENT:
		{	
#ifdef RETRY_MODE_ENABLED
			add_to_history = lk_consume_fc.read();
#endif
			//If output not consumed, don't modify the output
			if(!lk_consume_fc.read()){
				next_state = FWD_CMD32_SENT;
				next_fc_lctl_lk = true;
				next_fc_hctl_lk = true;
			}
			//If there is data with this packet
			else if (has_data.read()){
				//If a request for nop, interrupt sending the data to send nop
				if (nop_req == true){
					go_NOP_SENT_IN_FWD();
				}
				//Otherwise go send the data
				else{
					go_FWD_DATA_SENT();
				}
			}
#ifdef RETRY_MODE_ENABLED
			//If no data and in retry mode, send the per-packet CRC
			else if(csr_retry.read()){
				go_SEND_CMD_CRC();
			}
#endif
			//No data and no retry mode means packet sent : find next packet to send
			else{
				set_next_state();
			}				 
		}
		break;
 
	case FWD_CMD64_FIRST_SENT:
		{
#ifdef RETRY_MODE_ENABLED
			add_to_history = lk_consume_fc.read();
#endif
 
			//If output not consumed, don't modify the output
			if(!lk_consume_fc.read()){
				next_state = FWD_CMD64_FIRST_SENT;
				next_fc_lctl_lk = true;
				next_fc_hctl_lk = true;
			}
			//Go send the second dword
			else{
				next_state = FWD_CMD64_SECOND_SENT;
				fc_ctr_mux = FC_MUX_FWD_MSB; //32 bits lsb FWD_CMD
				next_fc_lctl_lk = true;
				next_fc_hctl_lk = true;
				fwd_ack_ro = true;
#ifdef RETRY_MODE_ENABLED
				next_calculate_crc = true;
				add_to_history = true;
#endif
			}
		}
		break;
	case FWD_CMD64_SECOND_SENT:
 
#ifdef RETRY_MODE_ENABLED
		add_to_history = lk_consume_fc.read();
#endif
 
		//If output not consumed, don't modify the output
		if(!lk_consume_fc.read()){
			next_state = FWD_CMD64_SECOND_SENT;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = true;
		}
		//If there is data with this packet
		else if (has_data.read()){
			//If a request for nop, interrupt sending the data to send nop
			if (nop_req == true)
				go_NOP_SENT_IN_FWD();
			//Otherwise go send the data
			else{
				go_FWD_DATA_SENT();
			}
		}
#ifdef RETRY_MODE_ENABLED
		//If no data and in retry mode, send the per-packet CRC
		else if(csr_retry.read()){
			go_SEND_CMD_CRC();
		}
#endif
		//No data and no retry mode means packet sent : find next packet to send
		else {
			set_next_state();
		}
		break;
 
	case FWD_DATA_SENT:
		//cout << "entering FWD_DATA_SENT" <<endl;	
 
#ifdef RETRY_MODE_ENABLED
		add_to_history = lk_consume_fc.read();
#endif
 
		//If output not consumed, don't modify the output
		if(!lk_consume_fc.read()){
			next_state = FWD_DATA_SENT;
			next_fc_lctl_lk = false;
			next_fc_hctl_lk = false;
		}
		//If there is data left to send
		else if (has_data.read()){
			//If a request for nop, interrupt sending the data to send nop
			if (nop_req == true)
				go_NOP_SENT_IN_FWD();
			//Otherwise keep sending data
			else
				go_FWD_DATA_SENT();
		}
#ifdef RETRY_MODE_ENABLED
		else if(csr_retry.read()){
			go_SEND_DATA_CRC();
		}
#endif
		//No data and no retry mode means packet sent : find next packet to send
		else {
			set_next_state();
		}
		break;
 
	case NOP_SENT_IN_FWD:
 
		//cout << "entering fc_nop_sent_IN_FWD" <<endl;	
 
 
		if(lk_consume_fc.read()){
#ifdef RETRY_MODE_ENABLED
			//If in retry mode, the nop CRC must be sent
			if(csr_retry.read()){
				go_NOP_CRC_SENT_IN_FWD();
			}
			else
#endif
			{
				//If a nop is requested again, send another
				if (nop_req == true)
					go_NOP_SENT_IN_FWD();
				//Otherwise continue to send data
				else
					go_FWD_DATA_SENT();
			}
		}
		//If output not consumed, don't modify the output
		else{
			next_state = NOP_SENT_IN_FWD;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = true;
		}
 
		break;
 
 
	case USER_CMD32_SENT:
		{	
#ifdef RETRY_MODE_ENABLED
			add_to_history = lk_consume_fc.read();
#endif
 
			//If output not consumed, don't modify the output
			if(!lk_consume_fc.read()){
				next_state = USER_CMD32_SENT;
				next_fc_lctl_lk = true;
				next_fc_hctl_lk = true;
			}
			//If there is data with this packet
			else if (has_data.read()){
				//If a request for nop, interrupt sending the data to send nop
				if (nop_req == true){
					go_NOP_SENT_IN_USER();
				}
				//Otherwise go send the data
				else{
					go_USER_DATA_SENT();
				}
			}
#ifdef RETRY_MODE_ENABLED
			else if(csr_retry.read()){
				go_SEND_CMD_CRC();
			}
#endif
			//No data and no retry mode means packet sent : find next packet to send
			else{
				set_next_state();
			}				 
		}
		break;
 
	case USER_CMD64_FIRST_SENT:
		{
#ifdef RETRY_MODE_ENABLED
			add_to_history = lk_consume_fc.read();
#endif
 
			//If output not consumed, don't modify the output
			if(!lk_consume_fc.read()){
				next_state = USER_CMD64_FIRST_SENT;
				next_fc_lctl_lk = true;
				next_fc_hctl_lk = true;
			}
			else{
				next_state = USER_CMD64_SECOND_SENT;
				fc_ctr_mux = FC_MUX_UI_MSB; //32 bits lsb FWD_CMD
				next_fc_lctl_lk = true;
				next_fc_hctl_lk = true;
				consume_user_fifo = true;
#ifdef RETRY_MODE_ENABLED
				next_calculate_crc = true;
				add_to_history = true;
#endif
			}
		}
		break;
 
	case USER_CMD64_SECOND_SENT:
 
#ifdef RETRY_MODE_ENABLED
		add_to_history = lk_consume_fc.read();
#endif
 
		//If output not consumed, don't modify the output
		if(!lk_consume_fc.read()){
			next_state = USER_CMD64_SECOND_SENT;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = true;
		}
		//If there is data with this packet
		else if (has_data.read()){
			//If a request for nop, interrupt sending the data to send nop
			if (nop_req == true)
				go_NOP_SENT_IN_USER();
			//Otherwise go send the data
			else{
				go_USER_DATA_SENT();
			}
		}
#ifdef RETRY_MODE_ENABLED
		else if(csr_retry.read()){
			go_SEND_CMD_CRC();
		}
#endif
		//No data and no retry mode means packet sent : find next packet to send
		else {
			set_next_state();
		}
		break;
 
	case USER_DATA_SENT:
 
#ifdef RETRY_MODE_ENABLED
		add_to_history = lk_consume_fc.read();
#endif
 
		//If output not consumed, don't modify the output
		if(!lk_consume_fc.read()){
			next_state = USER_DATA_SENT;
			next_fc_lctl_lk = false;
			next_fc_hctl_lk = false;
		}
		//If there is data left to send
		else if (has_data.read()){
			//If a request for nop, interrupt sending the data to send nop
			if (nop_req == true)
				go_NOP_SENT_IN_USER();
			//Otherwise keep sending data
			else
				go_USER_DATA_SENT();
		}
#ifdef RETRY_MODE_ENABLED
		else if(csr_retry.read()){
			go_SEND_DATA_CRC();
		}
#endif
		//No data and no retry mode means packet sent : find next packet to send
		else {
			set_next_state();
		}
 
		break;
 
	case NOP_SENT_IN_USER:
 
		if(lk_consume_fc.read()){
#ifdef RETRY_MODE_ENABLED
			//If in retry mode, nop CRC must be sent
			if(csr_retry.read()){
				fc_nop_sent = false;
				next_state = NOP_CRC_SENT_IN_USER;
				next_fc_lctl_lk = true;
				next_fc_hctl_lk = false;
				next_select_nop_crc_output = true;
			}
			else 
#endif
			{
				//If nop is requestion, send another nop
				if (nop_req == true)
					go_NOP_SENT_IN_USER();
				//Otherwise, keep sending data
				else
					go_USER_DATA_SENT();
			}
		}
		//If output not consumed, don't modify the output
		else{
			next_state = NOP_SENT_IN_USER;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = true;
		}
 
		break;
 
 
	case EH_CMD_SENT:
		{
#ifdef RETRY_MODE_ENABLED
			add_to_history = lk_consume_fc.read();
#endif
 
			//If output not consumed, don't modify the output
			if(!lk_consume_fc.read()){
				next_state = EH_CMD_SENT;
				next_fc_lctl_lk = true;
				next_fc_hctl_lk = true;
			}
			//If there is data with this packet
			else if (has_data.read()){
				//If a request for nop, interrupt sending the data to send nop
				if (nop_req == true){
					go_NOP_SENT_IN_EH();
				}
				//Otherwise go send the data
				else{
					go_ERROR_DATA_SENT();
				}
			}
#ifdef RETRY_MODE_ENABLED
			else if(csr_retry.read()){
				go_SEND_CMD_CRC();
			}
#endif
			//No data and no retry mode means packet sent : find next packet to send
			else{
				set_next_state();
			}				 
		}
		break;
 
	case CSR_CMD_SENT:
		{
 
		//cout << "entering CSR_CMD_SENT" <<endl;
#ifdef RETRY_MODE_ENABLED
			add_to_history = lk_consume_fc.read();
#endif
 
			//If output not consumed, don't modify the output
			if(!lk_consume_fc.read()){
				next_state = CSR_CMD_SENT;
				next_fc_lctl_lk = true;
				next_fc_hctl_lk = true;
			}
			//If there is data with this packet
			else if (has_data.read()){
				//If a request for nop, interrupt sending the data to send nop
				if (nop_req == true){
					go_NOP_SENT_IN_CSR();
				}
				//Otherwise go send the data
				else{
					go_CSR_DATA_SENT();
				}
			}
#ifdef RETRY_MODE_ENABLED
			else if(csr_retry.read()){
				go_SEND_CMD_CRC();
			}
#endif
			//No data and no retry mode means packet sent : find next packet to send
			else{
				set_next_state();
			}				 
		}
		break;
 
 
 
	case ERROR_DATA_SENT:
 
#ifdef RETRY_MODE_ENABLED
		add_to_history = lk_consume_fc.read();
#endif
 
		//If output not consumed, don't modify the output
		if(!lk_consume_fc.read()){
			next_state = ERROR_DATA_SENT;
			next_fc_lctl_lk = false;
			next_fc_hctl_lk = false;
		}
		//If there is data left to send
		else if (has_data.read()){
			//If a request for nop, interrupt sending the data to send nop
			if (nop_req == true)
				go_NOP_SENT_IN_EH();
			//Otherwise keep sending data
			else
				go_ERROR_DATA_SENT();
		}
#ifdef RETRY_MODE_ENABLED
		else if(csr_retry.read()){
			go_SEND_DATA_CRC();
		}
#endif
		//No data and no retry mode means packet sent : find next packet to send
		else {
			set_next_state();
		}
 
		break;
 
	case NOP_SENT_IN_EH:
 
		if(lk_consume_fc.read()){
#ifdef RETRY_MODE_ENABLED
			//If in retry mode, nop CRC must be sent
			if(csr_retry.read()){
				next_select_nop_crc_output = true;
				fc_nop_sent = false;
				next_state = NOP_CRC_SENT_IN_EH;
				next_fc_lctl_lk = true;
				next_fc_hctl_lk = false;
			}
			else
#endif
			{
				//If nop is requestion, send another nop
				if (nop_req == true)
					go_NOP_SENT_IN_EH();
				//Otherwise, keep sending data
				else
					go_ERROR_DATA_SENT();
			}
		}
		//If output not consumed, don't modify the output
		else{
			next_state = NOP_SENT_IN_EH;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = true;
		}
		break;
 
	case CSR_DATA_SENT:
 
#ifdef RETRY_MODE_ENABLED
		add_to_history = lk_consume_fc.read();
#endif
		//If output not consumed, don't modify the output
		if(!lk_consume_fc.read()){
			next_state = CSR_DATA_SENT;
			next_fc_lctl_lk = false;
			next_fc_hctl_lk = false;
		}
		//If there is data left to send
		else if (has_data.read()){
			//If a request for nop, interrupt sending the data to send nop
			if (nop_req == true)
				go_NOP_SENT_IN_CSR();
			//Otherwise keep sending data
			else
				go_CSR_DATA_SENT();
		}
#ifdef RETRY_MODE_ENABLED
		else if(csr_retry.read()){
			go_SEND_DATA_CRC();
		}
#endif
		//No data and no retry mode means packet sent : find next packet to send
		else {
			set_next_state();
		}
 
		break;	        	
 
	case NOP_SENT_IN_CSR:
 
		if(lk_consume_fc.read()){
#ifdef RETRY_MODE_ENABLED
			//If in retry mode, nop CRC must be sent
			if(csr_retry.read()){
				next_select_nop_crc_output = true;
				fc_nop_sent = false;
				next_state = NOP_CRC_SENT_IN_CSR;
				next_fc_lctl_lk = true;
				next_fc_hctl_lk = false;
			}
			else
#endif
			{
				//If nop is requestion, send another nop
				if (nop_req == true)
					go_NOP_SENT_IN_CSR();
				//Otherwise, keep sending data
				else
					go_CSR_DATA_SENT();
			}
		}
		//If output not consumed, don't modify the output
		else{
			next_state = NOP_SENT_IN_CSR;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = true;
		}
		break;
 
	//This outputs nop disconnects.  When ldtstopx is done, then we go back
	//to normal operation.  The link will disconnect on it's own
	case LDTSTOP_DISCONNECT:
		//Disconnect is not activated because the link will start
		//it's deconnect sequence when it reads ldtstopx.  It will
		//take a long delay (minimum 64 dword) before it's deconnected
		//because of the periodic CRC that must be sent
		//
		//fc_disconnect_lk is reserved for RETRY disconnect
		//next_fc_disconnect_lk = true;
 
#ifdef RETRY_MODE_ENABLED
		//Clear CRC so it's clean when we start over
		clear_crc = true;
		clear_nop_crc = true;
#endif
		//While ldtstopx is maintained, stay in ldstopx state
		if(ldtstopx.read() == false){
			go_LDTSTOP_DISCONNECT();
		}
		//Once done, go back to normal operation by starting with a nop
		else{
			go_NOP_SENT();
		}
		break;
 
////////////////////////////////////////////
//				MAIN CRC states
///////////////////////////////////////////
 
#ifdef RETRY_MODE_ENABLED
 
	case NOP_CRC_SENT_IN_CSR:
 
		clear_nop_crc = lk_consume_fc.read();
 
		if(lk_consume_fc.read()){
			go_CSR_DATA_SENT();
		}
		else{
			next_state = NOP_CRC_SENT_IN_CSR;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = false;
			next_select_nop_crc_output = true;
		}
		break;
 
	case NOP_CRC_SENT_IN_FWD:
 
		clear_nop_crc = lk_consume_fc.read();
 
		if(lk_consume_fc.read()){
			go_FWD_DATA_SENT();
		}
		else{
			next_state = NOP_CRC_SENT_IN_FWD;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = false;
			next_select_nop_crc_output = true;
		}
 
		break;
 
	case NOP_CRC_SENT_IN_USER:
 
		clear_nop_crc = lk_consume_fc.read();
 
		if(lk_consume_fc.read()){
			go_USER_DATA_SENT();
		}
		else{
			next_state = NOP_CRC_SENT_IN_USER;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = false;
			next_select_nop_crc_output = true;
		}
		break;
 
	case NOP_CRC_SENT_IN_EH:
 
		clear_nop_crc = lk_consume_fc.read();
 
		if(lk_consume_fc.read()){
			go_ERROR_DATA_SENT();
		}
		else{
			next_state = NOP_CRC_SENT_IN_EH;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = false;
			next_select_nop_crc_output = true;
		}
		break;
 
	case SEND_DATA_CRC:
 
		//cout << "entering SEND_DATA_CRC" <<endl;	
 
		if(!lk_consume_fc.read()){
			next_fc_lctl_lk = false;
			next_fc_hctl_lk = true;
			next_state = SEND_DATA_CRC;
			next_select_crc_output = true;
		}
		else{
			clear_crc = true;		
			set_next_state();
		}
		break;
 
	case SEND_CMD_CRC:
 
		if(!lk_consume_fc.read()){
			next_fc_lctl_lk = true;
			next_fc_hctl_lk =  false;
			next_state = SEND_CMD_CRC;
			next_select_crc_output = true;
		}
		else{
			clear_crc = true;		
			set_next_state();
		}
		break;
 
	case SEND_NOP_CRC:
 
		if(!lk_consume_fc.read()){
			next_fc_lctl_lk = true;
			next_fc_hctl_lk =  false;
			next_state = SEND_NOP_CRC;
			next_select_nop_crc_output = true;
		}
		else{
			clear_nop_crc = true;		
			set_next_state();
		}
		break;
 
	case RETRY_SEND_DISCONNECT:
 
		//If was playing back history, stop it.  If not, this simply does nothing
		stop_history_playback = true;
 
		if(!lk_consume_fc.read()){
			next_fc_lctl_lk = true;
			next_fc_hctl_lk =  true;
			next_state = RETRY_SEND_DISCONNECT;
			next_fc_disconnect_lk = false;
		}
		else{
			next_fc_lctl_lk = true;
			next_fc_hctl_lk =  false;
			next_state = RETRY_SEND_DISCONNECT_CRC;
			next_select_nop_crc_output = true;
			//When the link detects fc_disconnect_lk, it finishes sending the dword currently
			//on it's output and then starts sending warm reset signaling.  fc_disconnect_lk
			//is activated on the next cycle, when the CRC is outputed to the links.  The CRC
			//will be the last dword sent
			next_fc_disconnect_lk = true;
		}
		break;
 
	case RETRY_SEND_DISCONNECT_CRC:
 
		if(!lk_consume_fc.read()){
			next_state = RETRY_SEND_DISCONNECT_CRC;
			next_select_nop_crc_output = true;
		}
		else{
			next_state = RETRY_WAIT_FOR_RX_DISCONNECT;
			clear_nop_crc = true;		
		}
		next_fc_lctl_lk = true;
		next_fc_hctl_lk = false;
 
		next_fc_disconnect_lk = true;
 
	break;
 
	//The TX side of the link is disconnected, but if we initiated the retry
	//attempt, the RX side might still be receiving stuff.  We wait for the RX
	//side to be disconnected
	case RETRY_WAIT_FOR_RX_DISCONNECT:
 
		//cout << "Entered RETRY_WAIT_FOR_RX_DISCONNECT" << endl;
 
		next_fc_lctl_lk = true;
		next_fc_hctl_lk = true;
		clear_crc = true;
		clear_nop_crc = true;
		clear_farend_count = true;
		clear_retry_disconnect_initiated = true;
 
		if(registered_lk_rx_connected.read()){
			next_state = RETRY_WAIT_FOR_RX_DISCONNECT;
			next_fc_disconnect_lk = true;
		}
		else{
			next_state = RETRY_WAIT_FOR_ACK_AND_BUFFER_COUNT_SENT;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = true;
			fc_ctr_mux = FC_MUX_NOP;
			fc_nop_sent = true;
			next_calculate_nop_crc = true;
			next_fc_disconnect_lk = false;
		}
		break;
 
	//To know where to start the resend, we wait for a nop with the last
	//acked packet value.  We also have to finish transmitting all our
	//buffer counts
	case RETRY_WAIT_FOR_ACK_AND_BUFFER_COUNT_SENT:
		begin_history_playback = received_ack.read();
 
		if(!lk_consume_fc.read()){
			next_fc_lctl_lk = true;
			next_fc_hctl_lk =  true;
			next_state = RETRY_WAIT_FOR_ACK_AND_BUFFER_COUNT_SENT;
		}
		else{
			next_state = RETRY_WAIT_FOR_ACK_AND_BUFFER_COUNT_SENT_CRC;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk =  false;
			next_select_nop_crc_output = true;
		}
 
		break;
 
	case RETRY_WAIT_FOR_ACK_AND_BUFFER_COUNT_SENT_CRC:
		begin_history_playback = received_ack.read();
 
		if(!lk_consume_fc.read()){
			next_fc_lctl_lk = true;
			next_fc_hctl_lk =  false;
			next_state = RETRY_WAIT_FOR_ACK_AND_BUFFER_COUNT_SENT_CRC;
			next_select_nop_crc_output = true;
			next_state = RETRY_WAIT_FOR_ACK_AND_BUFFER_COUNT_SENT_CRC;
 
		}
		else{
			fc_ctr_mux = FC_MUX_NOP;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = true;
			fc_nop_sent = true;
			clear_nop_crc = true;
			next_calculate_nop_crc = true;
 
			/*Got ack and finished sending buffer count*/
			if(ldtstopx.read() == false || retry_disconnect_initiated.read()){
				go_RETRY_SEND_DISCONNECT();
			}
			//If this case happens, it means there is no history to play back
			if(history_playback_done.read() && history_playback_ready.read())
				next_state = NOP_SENT;
			//All buffers have been confirmed with nops and playback is ready, start playback
			else if(!has_nop_buffers_to_send.read()&& history_playback_ready.read())
				next_state = RETRY_NOP_SENT;
			else
				next_state = RETRY_WAIT_FOR_ACK_AND_BUFFER_COUNT_SENT;
		}
		break;
 
 
	case RETRY_CMD32_SENT:
		{
		//cout << "entering USER_CMD_SENT" <<endl;
 
			if(!lk_consume_fc.read()){
				next_state = FWD_CMD32_SENT;
				next_fc_lctl_lk = true;
				next_fc_hctl_lk = true;
			}
			else if (has_data.read()){
				if (nop_req == true){
					go_RETRY_NOP_SENT_IN_DATA();
				}
				else{
					go_RETRY_DATA_SENT();
				}
			}
			else{
				go_RETRY_SEND_CMD_CRC();
			}
		}
		break;
 
	case RETRY_CMD64_FIRST_SENT:
		if(!lk_consume_fc.read()){
			next_state = RETRY_CMD64_FIRST_SENT;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = true;
		}
		else{
			next_state = RETRY_CMD64_SECOND_SENT;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = true;
			fc_ctr_mux = FC_MUX_HISTORY; //32 bits lsb FWD_CMD
			consume_history = true;
			next_calculate_crc = true;
		}
		break;
	case RETRY_CMD64_SECOND_SENT:
		if(!lk_consume_fc.read()){
			next_state = RETRY_CMD64_SECOND_SENT;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = true;
		}
		else if (has_data.read()){
			if (nop_req == true){
				go_RETRY_NOP_SENT_IN_DATA();
			}
			else{
				go_RETRY_DATA_SENT();
			}
		}
		else{
			go_RETRY_SEND_CMD_CRC();
		}
		break;
 
	case RETRY_DATA_SENT:
		if(!lk_consume_fc.read()){
			next_state = RETRY_DATA_SENT;
			next_fc_lctl_lk = false;
			next_fc_hctl_lk = false;
		}
		else if (has_data.read()){
			if (nop_req == true){
				go_RETRY_NOP_SENT_IN_DATA();
			}
			else{
				go_RETRY_DATA_SENT();
			}
		}
		else{
			go_RETRY_SEND_CMD_CRC_DATA();
		}
		break;
 
	case RETRY_SEND_CMD_CRC:
		clear_crc = lk_consume_fc.read();
 
		if(!lk_consume_fc.read()){
			next_state = RETRY_SEND_CMD_CRC;
			next_fc_lctl_lk = fc_lctl_lk.read();
			next_fc_hctl_lk = fc_hctl_lk.read();
			next_select_crc_output = true;
		}
		else{
			go_next_retry_state();
		}
		break;
 
	case RETRY_NOP_SENT_IN_DATA:
 
		if(lk_consume_fc.read()){
			next_state = RETRY_NOP_CRC_SENT_IN_DATA;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = false;
			next_select_nop_crc_output = true;
		}
		else{
			next_state = RETRY_NOP_SENT_IN_DATA;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = true;
		}
		break;
 
	case RETRY_NOP_CRC_SENT_IN_DATA:
		clear_nop_crc = lk_consume_fc.read();
 
		if(lk_consume_fc.read()){
			if (nop_req == true)
				go_RETRY_NOP_SENT_IN_DATA();
			else
				go_RETRY_DATA_SENT();
		}
		else{
			next_state = RETRY_NOP_CRC_SENT_IN_DATA;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = false;
			next_select_nop_crc_output = true;
		}
		break;
 
	case RETRY_NOP_SENT:
		//cout << "Entered RETRY_NOP_SENT state" << endl;
		if(lk_consume_fc.read()){
			next_state = RETRY_NOP_CRC_SENT;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = false;
			next_select_nop_crc_output = true;
		}
		else{
			next_state = RETRY_NOP_SENT;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = true;
		}
		break;
	case RETRY_NOP_CRC_SENT:
		clear_nop_crc = lk_consume_fc.read();
 
		if(lk_consume_fc.read()){
			go_next_retry_state();
		}
		else{
			next_state = RETRY_NOP_CRC_SENT;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = false;
			next_select_nop_crc_output = true;
		}
 
		break;
////////////////////////////////////////////
//			End of MAIN CRC states
///////////////////////////////////////////
#endif
 
	//case TRANSMITTER_OFF_STATE:
	default:
	//case NOP_SENT:
		//cout << "entering fc_nop_sent" <<endl;	
		if(lk_consume_fc.read()){
#ifdef RETRY_MODE_ENABLED
			if(csr_retry.read()){
				next_state = SEND_NOP_CRC;
				next_select_nop_crc_output = true;
				next_fc_lctl_lk = true;
				next_fc_hctl_lk = false;
			}
			else
#endif
				set_next_state();
		}
		else{
			next_state = NOP_SENT;
			next_fc_lctl_lk = true;
			next_fc_hctl_lk = true;
		}
	} // end of switch
} // end of fonction
 
 
void flow_control_l3::set_next_state() {
 
	/**
		Basically, this only outputs what's been calculated in
		find_next_state.  The reason for not calling directly call_next_state
		is that there are a lot of calls for this in the MSA and ususually,
		SystemC synthesis tools unroll functions, so the resulting .vhdl output
		is VERY big!  This way, only this small part get unrolled multiple times,
		resulting in a much smaller and faster to compile file.  find_next_state
		is treated a single parallel process.  We're talking 2K lines versus 15K.
	*/
 
	next_state = found_next_state;
 
#ifdef RETRY_MODE_ENABLED
	new_history_entry_size_m1 = found_new_history_entry_size_m1;
	new_history_entry = found_new_history_entry;
	clear_crc = true;
	clear_nop_crc = true;
	next_calculate_crc = found_next_calculate_crc;
	next_calculate_nop_crc = found_next_calculate_nop_crc;
#endif
 
	fwd_ack_ro = found_load_fwd_pkt;
	fc_ack_eh = found_load_eh_pkt;
	fc_ack_csr = found_load_csr_pkt;
	consume_user_fifo = found_load_user_fifo_pkt;
	hold_user_fifo = found_hold_user_fifo_pkt;
	generate_disconnect_nop = found_generate_disconnect_nop;
	fc_nop_sent = found_fc_nop_sent;
	fwd_vctype_db = found_fwd_vctype_db;
	fwd_address_db = found_fwd_address_db;
	next_data_cnt = found_next_data_cnt;
	next_has_data = found_next_has_data;
	fc_data_vc_ui = found_fc_data_vc_ui;
	current_sent_type = found_current_sent_type;
 
	local_packet_issued = found_local_packet_issued;
	for(int n = 0; n < 3; n++)
		next_fairness_vc_reserved[n] = found_next_fairness_vc_reserved[n];
 
	next_chain_current_state = found_next_chain_current_state;
 
	fc_ctr_mux = found_fc_ctr_mux;
	next_fc_lctl_lk = true;
	next_fc_hctl_lk = true;
}
 
 
void flow_control_l3::find_next_state() {
	//Reserving a packet to fairness to make sure not to starve a VC
	bool reserve_fairness = false;
	//If forward has priority but a packet was previously reserved
	bool fairness_override = false;
 
	//By default don't change the fairness reserved bit
	for(int n = 0; n < 3; n++)
		found_next_fairness_vc_reserved[n] = fairness_vc_reserved[n];
 
	//Find if we're requesting a nop
	bool nop_req = ro_nop_req_fc.read() || db_nop_req_fc.read() || nop_next_to_send.read();
 
	bool disconnect = (ldtstopx.read() == false
#ifdef RETRY_MODE_ENABLED
			|| cd_initiate_retry_disconnect.read() || 
			registered_lk_initiate_retry_disconnect.read() ||
			retry_disconnect_initiated.read()		
#endif
			);
	bool send_nop = nop_req || disconnect;
 
	/**
		First, we look if a packet can be sent - needs to be one available and the necessary
		buffers in the other link must be free
    */
	sc_bv<6> csr_cmd_bits;
	csr_cmd_bits = csr_dword_fc.read().range(5,0);
 
	//***********************************************
	//Analyse if the packet from the CSR can be sent
	//***********************************************
	//Some packet analysis
	PacketCommand csr_cmd = getPacketCommand(csr_cmd_bits);
	VirtualChannel csr_vc = VC_RESPONSE;
	bool csr_data_associated = hasDataAssociated(csr_cmd);
	sc_uint<5> csr_size_with_data_m1 =
		getDwordPacketSizeWithDatam1(sc_bv<64>(csr_dword_fc.read()),csr_cmd);
	sc_uint<4> csr_data_count = getDataLengthm1(sc_bv<64>(csr_dword_fc.read()));
	//We know csr can only send responses, check if the next buffer has room for
	//a response packet, and data if there is data associated with that response
	//Also check it there IS a packet!  and if in retry mode, if we have enough room
	//in history
	bool csr_can_be_sent = (csr_available_fc == true) &&
			(fwd_next_node_buffer_status_ro.read()[BUF_STATUS_R_CMD] == true) &&
			(fwd_next_node_buffer_status_ro.read()[BUF_STATUS_R_DATA] == true || !csr_data_associated)
#ifdef RETRY_MODE_ENABLED
			&& (room_available_in_history.read() || !csr_retry.read())
#endif
			;
 
	if(!local_priority.read() && fairness_vc_reserved[csr_vc].read() && csr_can_be_sent)
		fairness_override = true;
	if(csr_available_fc == true && !csr_can_be_sent && 
		local_priority.read() && fairness_vc_reserved[csr_vc].read())
		reserve_fairness = true;
 
	//*********************************************************
	//Analyse if the packet from the Error handler can be sent
	//*********************************************************
	sc_bv<6> eh_cmd_bits;
	eh_cmd_bits = eh_cmd_data_fc.read().range(5,0);
 
	PacketCommand eh_cmd = getPacketCommand(eh_cmd_bits);
	VirtualChannel eh_vc = VC_RESPONSE;
	bool eh_data_associated = hasDataAssociated(eh_cmd);
	sc_uint<5> eh_size_with_data_m1 = getDwordPacketSizeWithDatam1(sc_bv<64>(eh_cmd_data_fc.read()),eh_cmd);
	sc_uint<4> eh_data_count = getDataLengthm1(sc_bv<64>(eh_cmd_data_fc.read()));
	//We know csr can only send responses, check if the next buffer has room for
	//a response packet, and data if there is data associated with that response
	//Also check it there IS a packet!  and if in retry mode, if we have enough room
	//in history
	bool eh_can_be_sent = (eh_available_fc == true) &&
			(fwd_next_node_buffer_status_ro.read()[BUF_STATUS_R_CMD] == true) &&
			(fwd_next_node_buffer_status_ro.read()[BUF_STATUS_R_DATA] == true || !eh_data_associated)
#ifdef RETRY_MODE_ENABLED
			 && (room_available_in_history.read() || !csr_retry.read())
#endif
			;
 
	if(!local_priority.read() && fairness_vc_reserved[eh_vc].read() && eh_can_be_sent)
		fairness_override = true;
	if(eh_available_fc == true && !eh_can_be_sent && 
		local_priority.read() && fairness_vc_reserved[eh_vc].read())
		reserve_fairness = true;
 
 
	//*************************************************************
	//Analyse if the packet from the internal user fifo can be sent
	//*************************************************************
	bool user_can_be_sent = fifo_user_available.read() &&
		verify_buffer_status(fifo_user_packet_vc.read(),fifo_user_packet_data_asociated.read())
#ifdef RETRY_MODE_ENABLED
		 && (room_available_in_history.read() || !csr_retry.read())
#endif
	;
 
#ifdef RETRY_MODE_ENABLED
	sc_uint<5> fifo_user_packet_with_data_m1 = 
		getPacketSizeWithDatam1(fifo_user_packet.read(),fifo_user_packet_command.read());
#endif
 
	if(!local_priority.read() && fairness_vc_reserved[fifo_user_packet_vc.read()].read() && user_can_be_sent)
		fairness_override = true;
 
	/** This way to reserve fairness might stop a eh or csr packet from being sent immediately, but it
		will simply be sent a bit later that's all.  And since the eh and csr traffic is rare, it does
		not cause problem.
	*/
	if(fifo_user_available == true && !user_can_be_sent 
		&& local_priority.read() && !fairness_vc_reserved[fifo_user_packet_vc.read()].read())
		reserve_fairness = true;
 
	/**
		For the fairness algorithm, a packet from csr, user or eh is considered a
		local packet.  We check if a local packet can be sent
	*/
	bool local_req = csr_can_be_sent || eh_can_be_sent || user_can_be_sent;
 
	/**
		If a fairness slot is reserved, it is for a specific VC, choose this VC
	*/
	VirtualChannel reserve_vc;
	if(eh_available_fc.read() || csr_available_fc.read())reserve_vc = VC_RESPONSE;
	else reserve_vc = fifo_user_packet_vc.read();
 
 
	/**
		While we are at it, also check if the forward packet can be sent
	*/
	sc_bv<6> fwd_cmd_bits;
	sc_bv<64> ro_packet_fwd_buf = ro_packet_fwd.read().packet;
	fwd_cmd_bits = ro_packet_fwd_buf.range(5,0);
 
	PacketCommand fwd_cmd = getPacketCommand(fwd_cmd_bits);
	bool fwd_data_associated = hasDataAssociated(fwd_cmd);
	sc_uint<5> fwd_size_with_data_m1 = getPacketSizeWithDatam1(ro_packet_fwd.read().packet,fwd_cmd);
	sc_uint<4> fwd_data_count = getDataLengthm1(sc_bv<64>(ro_packet_fwd.read().packet));
 
 
	/*Also, the error handler shares the line with the fwd, so if the
		error64BitExtension is on, the packet is not for us...*/
	bool fwd_can_be_sent = ro_available_fwd.read() &&
		verify_buffer_status(ro_packet_vc_fwd.read(),fwd_data_associated)  && 
		!ro_packet_fwd.read().error64BitExtension &&
		//If we are currently sending a user chain and the fwd packet is POSTED, we can't send
		!(chain_current_state == USER_CHAIN_STATE && ro_packet_vc_fwd.read() == VC_POSTED) &&
		//Dont send a packet in a VC reserved for local
		!fairness_vc_reserved[ro_packet_vc_fwd.read()].read()
#ifdef RETRY_MODE_ENABLED
		&& (room_available_in_history.read() || !csr_retry.read())
#endif
		;
	bool fwd_chain = isChain(ro_packet_fwd.read().packet);
 
	/** Nop request always has the absolute priority
	*/
 
	//default
#ifdef RETRY_MODE_ENABLED
	found_new_history_entry_size_m1 = 0;
	found_new_history_entry = false;
	found_next_calculate_crc = true;
	found_next_calculate_nop_crc = false;
#endif
	found_load_fwd_pkt = false;
	found_next_chain_current_state = chain_current_state;
	found_load_csr_pkt = false;
	found_load_user_fifo_pkt = false;
	found_hold_user_fifo_pkt = false;
	found_load_eh_pkt = false;
	found_generate_disconnect_nop = false;
	found_fc_nop_sent = false;
	found_fwd_vctype_db =  buffered_fwd_vctype_db.read();
	found_fwd_address_db =  buffered_fwd_address_db.read();
	found_next_data_cnt = 0;
	found_next_has_data = false;
	//send early in which VC data might be read
	found_fc_data_vc_ui = fifo_user_packet_vc.read();
	found_fwd_vctype_db = VC_NONE;
	found_local_packet_issued = false;
	found_current_sent_type = 0;
 
 
	//******************************
	//Select the next state
	//******************************
 
 
	/*  If there is a forward packet to be sent and that either there is no
	local packet to send or it the priority of the forward to send.*/
	if (fwd_can_be_sent && !send_nop &&
		//If local has a packet and has priority, we don't send
		(local_priority.read() == false || local_req == false 
		|| reserve_fairness) && !fairness_override )
	{
 
		//Log the chain state
		if(ro_packet_vc_fwd.read() == VC_POSTED){
			if(fwd_chain) found_next_chain_current_state = FWD_CHAIN_STATE;
			else found_next_chain_current_state = NO_CHAIN_STATE;
		}
 
		//Choose the correct destination state depending 
		//on if the packet is of dword length or not
		if (isDwordPacket(ro_packet_fwd.read().packet,fwd_cmd))  {
			found_next_state = FWD_CMD32_SENT;
			found_load_fwd_pkt = true;
		}
		else{
			found_next_state = FWD_CMD64_FIRST_SENT;
		}
#ifdef RETRY_MODE_ENABLED
		found_new_history_entry_size_m1 = fwd_size_with_data_m1;
		found_new_history_entry = true;
#endif
		found_next_data_cnt = fwd_data_count;
		found_next_has_data = fwd_data_associated;
		found_fwd_vctype_db = ro_packet_vc_fwd.read();
		found_fwd_address_db = ro_packet_fwd.read().data_address;
		found_fc_ctr_mux = FC_MUX_FWD_LSB;
		set_found_sent_type(ro_packet_vc_fwd.read(),fwd_data_associated);
 
		if(reserve_fairness){
			found_local_packet_issued = true;
			found_next_fairness_vc_reserved[reserve_vc] = true;
		}
	}
	/*  Next in priority is the error handler.  It should not generate too much traffic*/
	else if (eh_can_be_sent && !send_nop && 
			(local_priority.read() || fairness_vc_reserved[VC_RESPONSE].read() || !fwd_can_be_sent))
	{
		found_load_eh_pkt = true;
		found_next_state = EH_CMD_SENT;
 
#ifdef RETRY_MODE_ENABLED
		found_new_history_entry_size_m1 = eh_size_with_data_m1;
		found_new_history_entry = true;
#endif
		found_next_data_cnt = eh_data_count;
		found_next_has_data = eh_data_associated;
		found_fc_ctr_mux = FC_MUX_EH;
 
		if(local_priority.read())
			found_local_packet_issued = true;
		else
			found_next_fairness_vc_reserved[VC_RESPONSE] = false;
 
		//EH ALWAYS and ONLY produces responses
		set_found_sent_type(VC_RESPONSE,eh_data_associated);
	}
	/*  Next in priority is the CSR.  It should not generate too much traffic
		after init*/
	else if(csr_can_be_sent && !send_nop && 
			(local_priority.read() || fairness_vc_reserved[VC_RESPONSE].read() || !fwd_can_be_sent))
	{
		found_load_csr_pkt = true;
		found_next_state = CSR_CMD_SENT; 
 
#ifdef RETRY_MODE_ENABLED
		found_new_history_entry_size_m1 = csr_size_with_data_m1;
		found_new_history_entry = true;
#endif
		found_next_data_cnt = csr_data_count;
		found_next_has_data = csr_data_associated;
		found_fc_ctr_mux = FC_MUX_CSR;
 
		if(local_priority.read())
			found_local_packet_issued = true;
		else
			found_next_fairness_vc_reserved[VC_RESPONSE] = false;
 
		//CSR ALWAYS and ONLY produces responses
		set_found_sent_type(VC_RESPONSE,csr_data_associated);
	}
	/*  Next in priority is the packets from the user*/
	else if(user_can_be_sent && !send_nop &&
		!(chain_current_state == FWD_CHAIN_STATE && fifo_user_packet_vc.read() == VC_POSTED) ){
 
		bool isChain = fifo_user_packet_isChain.read();
		//Log the chain state
		if(fifo_user_packet_vc.read() == VC_POSTED){
			if(isChain) found_next_chain_current_state = USER_CHAIN_STATE;
			else found_next_chain_current_state = NO_CHAIN_STATE;
		}
 
		//Choose the correct destination state depending 
		//on if the packet is of dword length or not
		if (fifo_user_packet_dword.read())  {
			found_next_state = USER_CMD32_SENT;
			found_load_user_fifo_pkt = true;
		}
		else{
			found_next_state = USER_CMD64_FIRST_SENT;
			found_hold_user_fifo_pkt = true;
		}
		found_fc_ctr_mux = FC_MUX_UI_LSB;
 
#ifdef RETRY_MODE_ENABLED
		found_new_history_entry_size_m1 = fifo_user_packet_with_data_m1;
		found_new_history_entry = true;
#endif
 
		if(local_priority.read())
			found_local_packet_issued = !isChain;
		else
			found_next_fairness_vc_reserved[fifo_user_packet_vc.read()] = isChain;
 
		found_next_data_cnt = fifo_user_packet_data_count_m1.read();
		found_next_has_data = fifo_user_packet_data_asociated.read();
		set_found_sent_type(fifo_user_packet_vc.read(),fifo_user_packet_data_asociated.read());
	}
	else  {
#ifdef RETRY_MODE_ENABLED
		found_next_calculate_crc = false;
		found_next_calculate_nop_crc = true;
#endif
		found_fc_ctr_mux = FC_MUX_NOP;
		found_fc_nop_sent = !disconnect;
		found_generate_disconnect_nop = disconnect;
 
		//If the link needs to be disconnected
		if(disconnect){
#ifdef RETRY_MODE_ENABLED
			//In retry mode, we initiate a retry sequence
			if(csr_retry.read()){
				found_next_state = RETRY_SEND_DISCONNECT;
			}
			else
#endif
			//Otherwise we just go to standard LDTSTOP disconnect
			{
				found_next_state = LDTSTOP_DISCONNECT;
			}
		}
		//Send nop
		else{
			found_next_state = NOP_SENT;
		}
	}
} 
 
 
#ifdef RETRY_MODE_ENABLED
 
void flow_control_l3::set_foundh_sent_type (VirtualChannel vc , bool data) {
 
	//comment for Reference, do not uncomment
	//or uncomment and define an enum somewhere
	//enum VirtualChannel {VC_POSTED,VC_NON_POSTED,VC_RESPONSE,VC_NONE};
	//   ResponseData;	//bit 0
	// 	 Response;		//bit 1
	// 	 NonPostData;	//bit 2
	// 	 NonPostCmd;	//bit 3
	// 	 PostData;		//bit 4	
	// 	 PostCmd;		//bit 5
 
	switch (vc) {
 
	case VC_POSTED :
		if (data == true)
			foundh_current_sent_type = "110000";
		else
			foundh_current_sent_type = "100000";
		break;
 
	case VC_NON_POSTED :
		if (data == true)
			foundh_current_sent_type = "001100";
		else
			foundh_current_sent_type = "001000";
		break;
 
	case VC_RESPONSE :
		if (data == true)
			foundh_current_sent_type = "000011";
		else
			foundh_current_sent_type = "000010";
		break;
 
	default :
		foundh_current_sent_type = "000000";
		break;
 
	}
 
}
#endif
 
 
void flow_control_l3::set_found_sent_type (VirtualChannel vc , bool data) {
 
	//comment for Reference, do not uncomment
	//or uncomment and define an enum somewhere
	//enum VirtualChannel {VC_POSTED,VC_NON_POSTED,VC_RESPONSE,VC_NONE};
	//   ResponseData;	//bit 0
	// 	 Response;		//bit 1
	// 	 NonPostData;	//bit 2
	// 	 NonPostCmd;	//bit 3
	// 	 PostData;		//bit 4	
	// 	 PostCmd;		//bit 5
 
	switch (vc) {
 
	case VC_POSTED :
		if (data == true)
			found_current_sent_type = "110000";
		else
			found_current_sent_type = "100000";
		break;
 
	case VC_NON_POSTED :
		if (data == true)
			found_current_sent_type = "001100";
		else
			found_current_sent_type = "001000";
		break;
 
	case VC_RESPONSE :
		if (data == true)
			found_current_sent_type = "000011";
		else
			found_current_sent_type = "000010";
		break;
 
	default :
		found_current_sent_type = "000000";
		break;
 
	}
 
}
 
bool flow_control_l3::verify_buffer_status (VirtualChannel vc , bool data ){
 
	//comment for Reference, do not uncomment
	//enum VirtualChannel {VC_POSTED,VC_NON_POSTED,VC_RESPONSE,VC_NONE};
	//   ResponseData;	//bit 0
	// 	 Response;		//bit 1
	// 	 NonPostData;	//bit 2
	// 	 NonPostCmd;	//bit 3
	// 	 PostData;		//bit 4	
	// 	 PostCmd;		//bit 5
 
 
	switch (vc) {
 
	case VC_POSTED :
		if (data == true)
			return  (fwd_next_node_buffer_status_ro.read()[BUF_STATUS_P_DATA] == true &&
			fwd_next_node_buffer_status_ro.read()[BUF_STATUS_P_CMD] == true);
		else
			return  (fwd_next_node_buffer_status_ro.read()[BUF_STATUS_P_CMD] == true);
		break;
 
	case VC_NON_POSTED :
		if (data == true)
			return  (fwd_next_node_buffer_status_ro.read()[BUF_STATUS_NP_DATA] == true &&
			fwd_next_node_buffer_status_ro.read()[BUF_STATUS_NP_CMD] == true);
		else
			return  (fwd_next_node_buffer_status_ro.read()[BUF_STATUS_NP_CMD] == true);
 
		break;
 
	case VC_RESPONSE :
		if (data == true)
			return  (fwd_next_node_buffer_status_ro.read()[BUF_STATUS_R_DATA] == true &&
			fwd_next_node_buffer_status_ro.read()[BUF_STATUS_R_CMD] == true);
		else
			return  (fwd_next_node_buffer_status_ro.read()[BUF_STATUS_R_CMD] == true);
		break;
 
	default :
		return false;
 
 
	}
 
}
 
void flow_control_l3::go_NOP_SENT(){
	fc_ctr_mux = FC_MUX_NOP;
	fc_nop_sent = true;
	next_state = NOP_SENT;
	next_fc_lctl_lk = true;
	next_fc_hctl_lk = true;
#ifdef RETRY_MODE_ENABLED
	next_calculate_nop_crc = true;
#endif
}
 
 
void flow_control_l3::go_NOP_SENT_IN_FWD(){
	fc_ctr_mux = FC_MUX_NOP;
	fc_nop_sent = true;
	next_state = NOP_SENT_IN_FWD;
	next_fc_lctl_lk = true;
	next_fc_hctl_lk = true;
#ifdef RETRY_MODE_ENABLED
	next_calculate_nop_crc = true;
#endif
}
 
void flow_control_l3::go_NOP_SENT_IN_USER(){
	fc_ctr_mux = FC_MUX_NOP;
	fc_nop_sent = true;
	next_state = NOP_SENT_IN_USER;
	next_fc_lctl_lk = true;
	next_fc_hctl_lk = true;
#ifdef RETRY_MODE_ENABLED
	next_calculate_nop_crc = true;
#endif
}
 
void flow_control_l3::go_NOP_SENT_IN_EH(){
	fc_ctr_mux = FC_MUX_NOP;
	fc_nop_sent = true;
	next_state = NOP_SENT_IN_EH;
	next_fc_lctl_lk = true;
	next_fc_hctl_lk = true;
#ifdef RETRY_MODE_ENABLED
	next_calculate_nop_crc = true;
#endif
}
 
void flow_control_l3::go_NOP_SENT_IN_CSR(){
	fc_ctr_mux = FC_MUX_NOP;
	fc_nop_sent = true;
	next_state = NOP_SENT_IN_CSR;
	next_fc_lctl_lk = true;
	next_fc_hctl_lk = true;
#ifdef RETRY_MODE_ENABLED
	next_calculate_nop_crc = true;
#endif
}
 
void flow_control_l3::go_FWD_DATA_SENT(){
	next_fc_lctl_lk = false;
	next_fc_hctl_lk = false;
	fc_ctr_mux = FC_MUX_DB_DATA;
	next_data_cnt = data_cnt.read() - 1;
	next_state = FWD_DATA_SENT;
	next_has_data = data_cnt.read() != 0;
	fwd_erase_db = data_cnt.read() == 0;
 
	fwd_read_db = true;
#ifdef RETRY_MODE_ENABLED
	next_calculate_crc = true;
#endif
}
 
void flow_control_l3::go_USER_DATA_SENT(){
	next_fc_lctl_lk = false;
	next_fc_hctl_lk = false;
	fc_ctr_mux = FC_MUX_UI_DATA;
	next_data_cnt = data_cnt.read() - 1;
	next_state = USER_DATA_SENT;
	next_has_data = data_cnt.read() != 0;
	fc_consume_data_ui = true;
#ifdef RETRY_MODE_ENABLED
	next_calculate_crc = true;
#endif
}
 
void flow_control_l3::go_ERROR_DATA_SENT(){
	next_fc_lctl_lk = false;
	next_fc_hctl_lk = false;
	fc_ctr_mux = FC_MUX_EH;
	next_data_cnt = data_cnt.read() - 1;
	next_state = ERROR_DATA_SENT;
	next_has_data = data_cnt.read() != 0;
	fc_ack_eh = true;
#ifdef RETRY_MODE_ENABLED
	next_calculate_crc = true;
#endif
}
 
void flow_control_l3::go_CSR_DATA_SENT(){
	next_fc_lctl_lk = false;
	next_fc_hctl_lk = false;
	fc_ctr_mux = FC_MUX_CSR;
	next_data_cnt = data_cnt.read() - 1;
	next_state = CSR_DATA_SENT;
	next_has_data = data_cnt.read() != 0;
	fc_ack_csr = true;
#ifdef RETRY_MODE_ENABLED
	next_calculate_crc = true;
#endif
}
 
void flow_control_l3::go_LDTSTOP_DISCONNECT(){
	//next_fc_disconnect_lk = false;
	fc_ctr_mux = FC_MUX_NOP; //32 bits NOP
	next_fc_lctl_lk = true;
	next_fc_hctl_lk = true;
	generate_disconnect_nop = true;
 
	next_state = LDTSTOP_DISCONNECT;
#ifdef RETRY_MODE_ENABLED
	next_calculate_nop_crc = false;
#endif
}
 
 
#ifdef RETRY_MODE_ENABLED
 
void flow_control_l3::go_RETRY_NOP_SENT(){
	fc_ctr_mux = FC_MUX_NOP;
	fc_nop_sent = true;
	next_state = RETRY_NOP_SENT;
	next_fc_lctl_lk = true;
	next_fc_hctl_lk = true;
	next_calculate_nop_crc = true;
}
 
void flow_control_l3::go_RETRY_NOP_SENT_IN_DATA(){
	fc_ctr_mux = FC_MUX_NOP;
	fc_nop_sent = true;
	next_state = RETRY_NOP_SENT_IN_DATA;
	next_fc_lctl_lk = true;
	next_fc_hctl_lk = true;
	next_calculate_nop_crc = true;
}
 
void flow_control_l3::go_NOP_CRC_SENT_IN_FWD(){
	next_select_nop_crc_output = true;
	fc_nop_sent = false;
	next_state = NOP_CRC_SENT_IN_FWD;
	next_fc_lctl_lk = true;
	next_fc_hctl_lk = false;
}
 
void flow_control_l3::go_SEND_CMD_CRC(){
	next_state = SEND_CMD_CRC;
	next_select_crc_output = true;
	next_fc_lctl_lk = true;
	next_fc_hctl_lk = false;
}
 
void flow_control_l3::go_RETRY_SEND_CMD_CRC(){
	next_state = RETRY_SEND_CMD_CRC;
	next_select_crc_output = true;
	next_fc_lctl_lk = true;
	next_fc_hctl_lk = false;
}
 
void flow_control_l3::go_RETRY_SEND_CMD_CRC_DATA(){
	next_state = RETRY_SEND_CMD_CRC;
	next_select_crc_output = true;
	next_fc_lctl_lk = false;
	next_fc_hctl_lk = true;
}
 
 
void flow_control_l3::go_RETRY_DATA_SENT(){
	next_fc_lctl_lk = false;
	next_fc_hctl_lk = false;
	fc_ctr_mux = FC_MUX_HISTORY;
	next_data_cnt = data_cnt.read() - 1;
	next_state = RETRY_DATA_SENT;
	next_has_data = data_cnt.read() != 0;
 
	consume_history = true;
	next_calculate_crc = true;
}
 
void flow_control_l3::go_SEND_DATA_CRC(){
	//fc_ctr_mux = FC_MUX_CRC;
	next_state = SEND_DATA_CRC;
	next_fc_lctl_lk = false;
	next_fc_hctl_lk = true;
	next_select_crc_output = true;
}
 
 
void flow_control_l3::go_RETRY_SEND_DISCONNECT(){
	fc_ctr_mux = FC_MUX_NOP; //32 bits NOP
	next_fc_lctl_lk = true;
	next_fc_hctl_lk = true;
	generate_disconnect_nop = true;
	next_calculate_nop_crc = true;
 
	next_state = RETRY_SEND_DISCONNECT_CRC;
}
 
void flow_control_l3::go_next_retry_state(){
	fc_ctr_mux = foundh_fc_ctr_mux;
	fc_nop_sent = foundh_fc_nop_sent;
	next_state = foundh_next_state;
	next_fc_lctl_lk = foundh_next_fc_lctl_lk;
	next_fc_hctl_lk = foundh_next_fc_hctl_lk;
	next_calculate_nop_crc = foundh_next_calculate_nop_crc;
	next_calculate_crc = foundh_next_calculate_crc;
	next_data_cnt = foundh_next_data_cnt;
	next_has_data = foundh_next_has_data;
	current_sent_type = foundh_current_sent_type;
	consume_history = foundh_consume_history;
}
 
void flow_control_l3::find_next_retry_state(){
 
	//Find if sending a nop has been requested by other modules
	bool nop_req;
	if (ro_nop_req_fc ==  true || db_nop_req_fc ==  true || nop_next_to_send == true )
		nop_req = true;
	else
		nop_req  = false;
 
	sc_bv<6> history_cmd_bits = history_packet.read().range(5,0);
 
	PacketCommand history_cmd = getPacketCommand(history_cmd_bits);
	VirtualChannel history_vc = getVirtualChannel(sc_bv<64>(history_packet.read()),history_cmd);
	bool history_data_associated = hasDataAssociated(history_cmd);
	bool enough_buffers = verify_buffer_status(history_vc,history_data_associated);
	bool dword_packet = isDwordPacket((sc_bv<64>)history_packet.read(),history_cmd);
 
	//Brought before the if/elsif statement to try to accelerate
	//the combinatorial path
	foundh_consume_history = (ldtstopx.read() && !nop_req) && 
		(!history_playback_done.read() && enough_buffers);
 
	foundh_fc_nop_sent = false;
	foundh_next_fc_lctl_lk = true;
	foundh_next_fc_hctl_lk = true;
	foundh_next_calculate_nop_crc = false;
	foundh_next_calculate_crc = false;
	foundh_next_data_cnt = 0;
	foundh_next_has_data = false;
	foundh_current_sent_type = "000000";
	foundh_generate_disconnect_nop = false;
 
	if(ldtstopx.read() == false || retry_disconnect_initiated.read()){
		foundh_next_calculate_nop_crc = true;
		foundh_next_state = RETRY_SEND_DISCONNECT;
		foundh_fc_ctr_mux = FC_MUX_NOP;
		foundh_generate_disconnect_nop = true;
		foundh_next_calculate_nop_crc = true;
	}
	else if(!history_playback_done.read() && enough_buffers && !nop_req){
		set_foundh_sent_type(history_vc,history_data_associated);
		foundh_next_data_cnt = getDataLengthm1(sc_bv<64>(history_packet.read()));
		foundh_next_has_data = history_data_associated;
		foundh_fc_ctr_mux = FC_MUX_HISTORY;
		foundh_next_calculate_crc = true;
 
		//Brought before the if/elsif statement to try to accelerate
		//the combinatorial path
		//foundh_consume_history = dword_packet;
 
		if (dword_packet){
			foundh_next_state = RETRY_CMD32_SENT;
		}
		else{
			foundh_next_state = RETRY_CMD64_FIRST_SENT;
		}
	}
	else{
		if(!history_playback_done.read())
			foundh_next_state = RETRY_NOP_SENT;
		else
			foundh_next_state = NOP_SENT;
 
		foundh_fc_ctr_mux = FC_MUX_NOP;
		foundh_fc_nop_sent = true;
		foundh_next_calculate_nop_crc = true;
	}
}
 
#endif
 
#ifndef SYSTEMC_SIM
 
#include "../core_synth/synth_control_packet.cpp"
 
#endif
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.