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

Subversion Repositories ht_tunnel

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

Compare with Previous | Blame | View Log

//ht_errorHandler.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):
 *   Martin Corriveau
 *   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 "errorhandler_l2.h"
 
errorhandler_l2::errorhandler_l2( sc_module_name name) :sc_module(name)
{
	//This is combinatory to it's sensitive to all the variables read by the process
	SC_METHOD(stateMachine);
	sensitive << csr_end_of_chain << csr_initcomplete << csr_drop_uninit_link << csr_unit_id <<
		ro_available_fwd << ro_packet_fwd << 
		fc_ack_eh << inputRegister << eh_cmd_data_fc << eh_available_fc << dataLeftToSendm1 << state;
 
	//This represents registers, so it's only sensitive to clk and reset
	SC_METHOD(clockAndReset);
	sensitive_neg << resetx;
	sensitive_pos << clk;
 
}
 
 
void errorhandler_l2::clockAndReset(){
 
	if(resetx.read() == false){
		//We have no data to send
		dataLeftToSendm1 = 0;
		//Go back to idle state
		state = IdleState;
 
		eh_cmd_data_fc = 0;
		eh_available_fc = false;
 
		syn_ControlPacketComplete defaultPkt;
		initialize_syn_ControlPacketComplete(defaultPkt);
		inputRegister = defaultPkt;
	}
	else{
		eh_available_fc = next_outputReq;
		dataLeftToSendm1 = next_dataLeftToSendm1;
		state = next_state;
		eh_cmd_data_fc = next_outputData;
		inputRegister = next_inputRegister;
	}
}
 
bool errorhandler_l2::checkEOCError() const
{
	/**
		End of chain can happen for two reasons :
		   - csr_end_of_chain is asserted, either because we truly are
		     the last element of the chain or because it is set by
			 software
		   - The link is not initialized yet and csr_drop_uninit_link is
		     set.
	*/
	if( csr_end_of_chain.read() == true ||
		( csr_initcomplete.read() == false &&
		  csr_drop_uninit_link.read() == true ) )
	{
		return true;
	}
	return false;
}
 
 
 
#ifdef SYSTEMC_SIM
/// Trace external function
void 
sc_trace(	sc_trace_file *tf, const errorhandler_l2& v,
			const sc_string& NAME )
{
	sc_trace(tf,v.clk, NAME + ".clk");
	sc_trace(tf,v.ro_packet_fwd, NAME + ".ro_packet_fwd");
	sc_trace(tf,v.ro_available_fwd, NAME + ".ro_available_fwd");
	sc_trace(tf,v.eh_ack_ro, NAME + ".eh_ack_ro");
	sc_trace(tf,v.fc_ack_eh, NAME + ".fc_ack_eh");
	sc_trace(tf,v.eh_cmd_data_fc, NAME + ".eh_cmd_data_fc");
	sc_trace(tf,v.eh_available_fc, NAME + ".eh_available_fc");
	sc_trace(tf,v.eh_address_db, NAME + ".eh_address_db");
	sc_trace(tf,v.eh_erase_db, NAME + ".eh_erase_db");
	sc_trace(tf,v.eh_vctype_db, NAME + ".eh_vctype_db");
	sc_trace(tf,v.csr_end_of_chain, NAME + ".csr_end_of_chain");
	sc_trace(tf,v.csr_initcomplete, NAME + ".csr_initcomplete");
	sc_trace(tf,v.csr_drop_uninit_link, NAME + ".csr_drop_uninit_link");
	sc_trace(tf,v.resetx, NAME + ".resetx");	
	sc_trace(tf,v.dataLeftToSendm1, NAME + ".dataLeftToSendm1");
 
}
#endif
 
void errorhandler_l2::stateMachine(){
 
	///////////////////////////////////////////////
	// Default outputs
	///////////////////////////////////////////////
	eh_ack_ro = false;
	next_dataLeftToSendm1 = 0;
	//All 1's because response packets for end of chain errors must only contain 1's
	next_outputData = "11111111111111111111111111111111";
	next_outputReq = false;
	next_state = IdleState;
	next_inputRegister = ro_packet_fwd.read();
	eh_address_db.write( 0 );
	eh_vctype_db.write( VC_NONE );
	eh_erase_db = false;
	//No need for this, reading the packet at the input is a signal that we
	//received a eoc packet, so no need for an extra signal.
	//eh_received_eoc_error_csr = false;
 
	//General variables that can be used in multiple states
	sc_bv<64> input_register_pkt = inputRegister.read().packet;
	PacketCommand input_register_cmd = getPacketCommand(input_register_pkt.range(5,0));
	VirtualChannel input_register_vc = getVirtualChannel(input_register_pkt,input_register_cmd);
	bool dataAssociated = hasDataAssociated(input_register_cmd);
 
	switch(state){
 
	///////////////////////////////////////////////
	// IDLE STATE
	///////////////////////////////////////////////
	case IdleState :
		/**If there is a packet and it is a an end of chain error
		   The same packets "signal" goes to both the flow control and
		   the error handler.  What dicates who consumes that packet
		   is if we are currently in a end of chain states
		*/
		if((checkEOCError() || ro_packet_fwd.read().error64BitExtension) 
				&& ro_available_fwd == true){
			next_state = AnalyzePacketStateOutputFree;
			eh_ack_ro = true;
		}
		break;
 
 
	///////////////////////////////////////////////
	// AnalyzePacketStateOutputLoaded STATE
	///////////////////////////////////////////////
	/** This state means that we have a new packet to analyze in the
		input buffer but that there is also data in the output buffer
		waiting to be sent
	*/
	case AnalyzePacketStateOutputLoaded :
		next_outputReq = true;
		next_outputData = eh_cmd_data_fc.read();
		next_state = AnalyzePacketStateOutputLoaded;
 
		//This state does roughly he same thing as the next state, but can only
		//update the output buffers if the FC acks what in the output buffer
		//If there is no ack, we stop right here and wait for the ack.
		if(fc_ack_eh.read() == false) break;
 
	/** This state means that we have a new packet to analyze in the
		input buffer and that we can output data to the flow control
		immediately.
	*/
	///////////////////////////////////////////////
	// AnalyzePacketStateOutputFree STATE
	///////////////////////////////////////////////
	case AnalyzePacketStateOutputFree :
 
		//When we reveice non posted packets, we generate a response with
		//the MASTER_ABORT bit on
		if(input_register_vc == VC_NON_POSTED ){
 
			// Construct Response Packet and activate the sending process
			bool passPW = getPassPW(input_register_pkt);
			sc_uint<5> dataLengthm1 = getDataLengthm1(input_register_pkt);
			//sc_uint<5> dataLength = dataLengthm1 + 1;
			sc_bv<5> reqUID = getUnitID(input_register_pkt);
			sc_bv<5> srcTag = request_getSrcTag(input_register_pkt);
 
			switch( input_register_cmd ){
 
			case READ:
			case ATOMIC:
				{
					/**
						In the case we received READ or ATOMIC request, we must
						reply with a response that has the right amount of data
						requested.
					*/
					sc_bv<32> readResponse = generateReadResponse( csr_unit_id.read(),
						srcTag,
						reqUID.range(1,0),
						dataLengthm1,
						false,
						RE_MASTER_ABORT,
						passPW,
						false);
 
					next_outputData = readResponse;
					next_outputReq = true;
					next_dataLeftToSendm1 = dataLengthm1;
					next_state = SendingDataStateInputFree;
				}
				break;
			//case WRITE:
			default:
				{
					/**
						In the case of a WRITE, we simply respond with a
						TargetDone
					*/
					next_outputData = generateTargetDone( csr_unit_id.read(),
						srcTag,
						reqUID.range(1,0),
						false,
						RE_MASTER_ABORT,
						passPW,
						false);
					next_outputReq = true;
					next_state = InputFreeOutputLoaded;
				}
				break;
 
			}
		}
		//In the case of POSTED and RESPONSE vc's, we can't response
		//We simply flag a bit in the CSR saying that we received an error.
		else if(input_register_cmd != BROADCAST){
			//eh_received_eoc_error_csr = true;
		}
 
		/** If the received packet contained data, we drop it */
		if(dataAssociated){
			eh_address_db.write( inputRegister.read().data_address );
			eh_vctype_db.write( input_register_vc);
			eh_erase_db = true;
		}
 
		break;
 
 
	///////////////////////////////////////////////
	// SendingDataStateInputFree STATE
	///////////////////////////////////////////////
	case SendingDataStateInputFree :
		next_outputReq = true;
 
		next_dataLeftToSendm1 = dataLeftToSendm1;
		next_state = SendingDataStateInputFree;
 
		//If there is a new packet at the input
		if((checkEOCError() || ro_packet_fwd.read().error64BitExtension) 
				&& ro_available_fwd == true){
			//If we only have one more data to send and the current data
			//is being read, load the last data and analyze the new packet
			if(dataLeftToSendm1.read() == 0 && fc_ack_eh.read() == true) {
				next_state = AnalyzePacketStateOutputLoaded;
			}
			//If we only have one more data to send and the current data
			//is not being read, we stay
			else if(dataLeftToSendm1.read() == 0){
				next_state = SendingDataStateInputLoaded;
				next_outputData = eh_cmd_data_fc.read();
			}
			else {
				next_state = SendingDataStateInputLoaded;
				if(fc_ack_eh.read() == true){
					next_dataLeftToSendm1 = dataLeftToSendm1.read() - 1;
				}
				else{
					next_outputData = eh_cmd_data_fc.read();
				}
			}
			eh_ack_ro = true;
		}
		else if(fc_ack_eh.read() == true){
			if(dataLeftToSendm1.read() == 0){
				next_state = InputFreeOutputLoaded;
			}
			else{
				next_dataLeftToSendm1 = dataLeftToSendm1.read() - 1;
			}
		}
		else{
			next_outputData = eh_cmd_data_fc.read();
		}
 
		break;
 
	///////////////////////////////////////////////
	// SendingDataStateInputLoaded STATE
	///////////////////////////////////////////////
	case SendingDataStateInputLoaded :
		next_outputReq = true;
		next_dataLeftToSendm1 = dataLeftToSendm1;
		next_state = SendingDataStateInputLoaded;
		next_inputRegister = inputRegister;
 
		if(fc_ack_eh.read() == true){
			if(dataLeftToSendm1.read() == 0) next_state = AnalyzePacketStateOutputLoaded;
			else next_dataLeftToSendm1 = dataLeftToSendm1.read() - 1;
		}
		else{
			next_outputData = eh_cmd_data_fc.read();
		}
		break;
 
	///////////////////////////////////////////////
	// InputFreeOutputLoaded STATE
	///////////////////////////////////////////////
	case InputFreeOutputLoaded :
		next_outputData = eh_cmd_data_fc.read();
		next_outputReq = true;
 
		if((checkEOCError() || ro_packet_fwd.read().error64BitExtension) 
				&& ro_available_fwd == true){
			if(fc_ack_eh.read() == true){
				next_state = AnalyzePacketStateOutputFree;
				next_outputReq = false;
			}
			else{
				next_state = AnalyzePacketStateOutputLoaded;
				next_outputData = eh_cmd_data_fc.read();
			}
		}
		else if(fc_ack_eh.read() == true){
			next_state = IdleState;
			next_outputReq = false;
		}
		else{
			next_state = InputFreeOutputLoaded;
			next_outputData = eh_cmd_data_fc.read();
		}
		break;
 
	}
}
 
#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.