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

Subversion Repositories ht_tunnel

[/] [ht_tunnel/] [trunk/] [bench/] [decoder_l2/] [decoder_l2_tb.cpp] - Rev 19

Compare with Previous | Blame | View Log

//decoder_l2_tb.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):
 *   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 "decoder_l2_tb.h"
#include <iostream>
#include <string>
#include <sstream>
 
using namespace std;
 
decoder_l2_tb::decoder_l2_tb(sc_module_name name) : sc_module(name){
	SC_THREAD(stimulate_input);
	sensitive_pos(clk);
	SC_THREAD(nop_info_validation);
	sensitive_pos(clk);
	SC_THREAD(databuffer_validation);
	sensitive_pos(clk);
	SC_THREAD(disconnect_retry_validation);
	sensitive_pos(clk);
	SC_THREAD(reordering_validation);
	sensitive_pos(clk);
 
	//Seed random generator with any number
	srand(4052);
	error = false;
	crc1 = 0xFFFFFFFF;
	crc2 = 0xFFFFFFFF;
}
 
void decoder_l2_tb::stimulate_input(){
	resetx = false;
	for(int n = 0; n < 3; n++){
		wait();
	}
	resetx = true;
 
	//Non-retry tests, normal operation
	send_nop();
	if(error) return;
	send_tgtdone();
	if(error) return;
	send_read();
	if(error) return;
	send_write();
	if(error) return;
	send_ext();
	if(error) return;
	send_ext_fc();
	if(error) return;
	send_ext_fc64();
	if(error) return;
	send_tgtdone_in_data();
	if(error) return;
	send_discon_nop();
 
	//initiated retry mode
	resetx = false;
	csr_retry = true;
	for(int n =0; n < 3; n++)
		wait();
	resetx = true;
 
	//Retry mode, normal operation
	send_nop();
	if(error) return;
	send_tgtdone();
	if(error) return;
	send_read();
	if(error) return;
	send_write();
	if(error) return;
	send_ext();
	if(error) return;
	send_ext_fc();
	if(error) return;
	send_ext_fc64();
	if(error) return;
	send_tgtdone_in_data();
	if(error) return;
	send_fc_in_data();
	if(error) return;
	send_fc64_in_data();
	if(error) return;
	send_nop_in_data();
	if(error) return;
	send_discon_nop();
	if(error) return;
	cout << endl << endl << "*** TEST SUCCESSFUL! ***" << endl << endl;
 
	expect_cd_initiate_retry_disconnect = 99999;
	//Retry mode, create errors & stomped packets
	//not done yet
}
 
void decoder_l2_tb::send_dword(sc_bv<32> dword,bool lctl, bool hctl){
	bool send;
	do{
		//Don't always make the dword available
		send = rand() %10 < 8;
		if(send){
			lk_available_cd = true;
			lk_dword_cd = dword;
			lk_hctl_cd = hctl;
			lk_lctl_cd = lctl;
		}
		wait();
		lk_available_cd = false;
	}while(!send);
}
 
void decoder_l2_tb::send_nop(){
	//Nop is mostly zeroes
	sc_bv<32> dword = 0;
 
	//Create a random nop entry
	NopEntry entry;
	entry.cd_nopinfo_fc = sc_uint<12>(rand());
	entry.cd_nop_ack_value_fc = rand();
 
	//Fill the nop bits with the values from entry
	dword.range(19,8) = entry.cd_nopinfo_fc;
	dword.range(31,24) = entry.cd_nop_ack_value_fc;
 
	//Send then generated nop
	nop_queue.push_back(entry);
	send_dword(dword,true,true);
	if(csr_retry.read()){
		calculate_crc1(dword,true,true);
		send_dword(~crc1,true,false);
		crc1 = 0xFFFFFFFF;
	}
}
 
void decoder_l2_tb::send_tgtdone(){
	//Generate a target done packet
	sc_bv<32> dword;
	getRandomVector(dword);
	sc_bv<6> command = "110011";
	dword.range(5,0) = command;
 
	//Send the packet
	send_dword(dword,true,true);
	if(csr_retry.read()){
		calculate_crc1(dword,true,true);
		send_dword(~crc1,true,false);
		crc1 = 0xFFFFFFFF;
	}
	//Add to expected entry
	addReorderingEntry(dword,false);
}
 
void decoder_l2_tb::send_read(){
	//Generate first dword of read packet
	sc_bv<32> dword;
	sc_bv<32> dword2;
	getRandomVector(dword);
	sc_bv<2> command = "01";
	dword.range(5,4) = command;
 
	//Send it
	send_dword(dword,true,true);
	if(csr_retry.read()){
		calculate_crc1(dword,true,true);
	}
 
	//Repeat for second dword
	getRandomVector(dword2);
	send_dword(dword2,true,true);
	if(csr_retry.read()){
		calculate_crc1(dword2,true,true);
		send_dword(~crc1,true,false);
		crc1 = 0xFFFFFFFF;
	}
 
	//Add to expected entry
	sc_bv<64> qword;
	qword.range(31,0) = dword;
	qword.range(63,32) = dword2;
	addReorderingEntry(qword,false);
 
}
 
void decoder_l2_tb::send_write(){
	//Random amount of data following it
	int data_length = rand() % 16;
 
	///Create and store the data
	DataBufferEntry entry = generate_data_packet(data_length,VC_POSTED);
	databuffer_queue.push_back(entry);
 
	//Send the write command packet (randomly generated)
	send_write_header(data_length);
	//Then send the data that follows it
	send_data_packet(entry,0,data_length);
 
	//Then send CRC if in retry mode
	if(csr_retry.read()){
		send_dword(~crc2,false,true);
		crc2 = 0xFFFFFFFF;
	}
}
 
 
void decoder_l2_tb::send_write_header(int datalength_m1){
	sc_bv<32> dword;
	sc_bv<64> qword = 0;
 
 
	getRandomVector(dword);
	sc_bv<3> command = "101";
	dword.range(5,3) = command;
	dword.range(25,22) = sc_uint<4>(datalength_m1);
	qword.range(31,0) = dword;
	send_dword(dword,true,true);
	if(csr_retry.read()){
		calculate_crc2(dword,true,true);
	}
	getRandomVector(dword);
	qword.range(63,32) = dword;
	addReorderingEntry(qword,false);
 
	send_dword(dword,true,true);
	if(csr_retry.read()){
		calculate_crc2(dword,true,true);
	}
}
 
decoder_l2_tb::DataBufferEntry decoder_l2_tb::generate_data_packet(int datalength_m1,
													VirtualChannel vc){
	DataBufferEntry entry;
	entry.size = datalength_m1;
	entry.vc = vc;
	entry.address_requested = false;
	entry.badcrc = false;
 
	for(int n = 0; n <= datalength_m1; n++){
		entry.data[n] = rand() & 0xFFF |
			rand() & 0xFFF << 12 |
			rand() & 0xFF << 24;
	}
 
	return entry;
}
 
void decoder_l2_tb::send_data_packet(DataBufferEntry &entry,
									 int offset,
									 int last){
	for(int n = offset; n <= last; n++){
		send_dword(sc_uint<32>(entry.data[n]),false,false);
		if(csr_retry.read()){
			calculate_crc2(sc_uint<32>(entry.data[n]),false,false);
		}
	}
}
 
void decoder_l2_tb::send_ext(){
	//Send the 64 bit extension
	sc_bv<32> dword;
	getRandomVector(dword);
	sc_bv<6> command = "111110";
	dword.range(5,0) = command;
	send_dword(dword,true,true);
	if(csr_retry.read()){
		calculate_crc1(dword,true,true);
	}
 
	//Send a standard read packet
	send_read();
 
	/** The send_read() function pushed an expected request
		in the queue.  Modify it so that a 64b error is
		expected */
	reordering_queue.back().pkt.error64BitExtension = true;
 
}
 
void decoder_l2_tb::send_ext_fc(){
	sc_bv<32> dword;
	getRandomVector(dword);
	sc_bv<7> command = "0110111";
	dword.range(6,0) = command;
	send_dword(dword,true,true);
	if(csr_retry.read()){
		calculate_crc1(dword,true,true);
		send_dword(~crc1,true,false);
		crc1 = 0xFFFFFFFF;
	}
}
 
void decoder_l2_tb::send_ext_fc64(){
	sc_bv<32> dword;
	getRandomVector(dword);
	sc_bv<7> command = "1110111";
	dword.range(6,0) = command;
	send_dword(dword,true,true);
	if(csr_retry.read()){
		calculate_crc1(dword,true,true);
	}
	getRandomVector(dword);
	send_dword(dword,true,true);
	if(csr_retry.read()){
		calculate_crc1(dword,true,true);
		send_dword(~crc1,true,false);
		crc1 = 0xFFFFFFFF;
	}
}
 
void decoder_l2_tb::send_tgtdone_in_data(){
	int data_length = rand() % 12 + 4;
	DataBufferEntry entry = generate_data_packet(data_length,VC_POSTED);
	databuffer_queue.push_back(entry);
	send_write_header(data_length);
 
	send_data_packet(entry,0,1);
	send_tgtdone();
 
	//Swap packets in retry mode
	if(csr_retry.read()){
		ReorderingEntry tmp = reordering_queue.back();
		reordering_queue.back() = *(reordering_queue.end()-2);
		*(reordering_queue.end()-2) = tmp;
	}
 
	send_data_packet(entry,2,data_length);
 
	if(csr_retry.read()){
		send_dword(~crc2,false,true);
		crc2 = 0xFFFFFFFF;
	}
}
 
void decoder_l2_tb::send_fc_in_data(){
	int data_length = rand() % 12 + 4;
	DataBufferEntry entry = generate_data_packet(data_length,VC_POSTED);
	databuffer_queue.push_back(entry);
	send_write_header(data_length);
 
	send_data_packet(entry,0,1);
	send_ext_fc();
	send_data_packet(entry,2,data_length);
 
	if(csr_retry.read()){
		send_dword(~crc2,false,true);
		crc2 = 0xFFFFFFFF;
	}
}
 
void decoder_l2_tb::send_fc64_in_data(){
	int data_length = rand() % 12 + 4;
	DataBufferEntry entry = generate_data_packet(data_length,VC_POSTED);
	databuffer_queue.push_back(entry);
	send_write_header(data_length);
 
	send_data_packet(entry,0,1);
	send_ext_fc64();
	send_data_packet(entry,2,data_length);
 
	if(csr_retry.read()){
		send_dword(~crc2,false,true);
		crc2 = 0xFFFFFFFF;
	}
}
 
void decoder_l2_tb::send_nop_in_data(){
	int data_length = rand() % 12 + 4;
	DataBufferEntry entry = generate_data_packet(data_length,VC_POSTED);
	databuffer_queue.push_back(entry);
	send_write_header(data_length);
 
	send_data_packet(entry,0,1);
	send_nop();
	send_data_packet(entry,2,data_length);
 
	if(csr_retry.read()){
		send_dword(~crc2,false,true);
		crc2 = 0xFFFFFFFF;
	}
}
 
void decoder_l2_tb::send_discon_nop(){
	sc_bv<32> dword = 0;
	dword[6] = true;
 
	NopEntry entry;
	entry.cd_nopinfo_fc = sc_uint<12>(rand());
	entry.cd_nop_ack_value_fc = rand();
	dword.range(19,8) = entry.cd_nopinfo_fc;
	dword.range(31,24) = entry.cd_nop_ack_value_fc;
 
	/** After a disconnect nop, the decoder is expected to initiate\
		a disconnect sequence
	*/
	if(csr_retry.read())
		expect_cd_initiate_retry_disconnect = 4;
	else
		expect_cd_initiate_nonretry_disconnect_lk = 4;
	send_dword(dword,true,true);
	if(csr_retry.read()){
		calculate_crc1(dword,true,true);
		send_dword(~crc1,true,false);
		crc1 = 0xFFFFFFFF;
	}
}
 
void decoder_l2_tb::nop_info_validation(){
	while(!error){
		//Start by checking the standard nop information
 
		//Check that entries in the queue are not simply being accumulated without
		//ever being used
		if(nop_queue.size() > 4){
			displayError("ERROR: Nop data not sent"); continue;
		}
 
		//When the command decoder says that nop is received, check the validity of the information
		if(cd_nop_received_fc.read()){
			if(nop_queue.empty()){
				displayError("ERROR: Nop data was not sent"); continue;
			}
			if(cd_nopinfo_fc.read() != nop_queue.front().cd_nopinfo_fc ||
				cd_nop_ack_value_fc.read() != nop_queue.front().cd_nop_ack_value_fc)
			{
				displayError("ERROR: Invalid nop data content"); continue;
			}
			nop_queue.pop_front();
		}
 
		//Check the next packet to ack value
		if(cd_rx_next_pkt_to_ack_fc.size() > 4){
			displayError("ERROR: next_pkt_to_ack value not udpated correctly"); continue;
		}
		if(!ack_value.empty()){
			if(ack_value.front() == cd_nop_ack_value_fc.read()){
				ack_value.pop_front();
			}
			else if(ack_value.front() != (cd_nop_ack_value_fc.read() + 1)){
				displayError("ERROR: Invalid next_pkt_to_ack value"); continue;
			}
		}
 
		wait();
	}
}
 
void decoder_l2_tb::databuffer_validation(){
	//Some default values
	last_databuffer_address = 0;
	db_address_cd = rand();
	int pos_in_entry = 0;
	delayed_start_writing_data = false;
	delayed_start_writing_data2 = false;
	delayed_start_writing_data3 = false;
	writing_data = false;
 
	while(!error){
		//Store cd_getaddr_db with different degrees of delay.  It will be used to verify
		//the data pending signal later on
		delayed_start_writing_data = cd_getaddr_db.read();
		delayed_start_writing_data2 = delayed_start_writing_data;
		delayed_start_writing_data3 = delayed_start_writing_data2;
 
		//Check that entries in the queue are not simply being accumulated without
		//ever being used
		if(databuffer_queue.size() > 2){
			displayError("ERROR: Data not sent to databuffer"); continue;
		}
 
		//When the command decoder starts writing a data packet to the databuffer
		if(cd_getaddr_db.read()){
			/** Check that this is a correct behavior
			*/
			if(writing_data.read()){
				displayError("ERROR: Last data entry not finished"); continue;
			}
			if(databuffer_queue.empty()){
				displayError("ERROR: Data entry requested"); continue;
			}
			if(databuffer_queue.front().address_requested){
				displayError("ERROR: Data address already requested"); continue;
			}
			if(databuffer_queue.front().vc != cd_vctype_db.read()){
				displayError("ERROR: Wrong VC requested in databuffer"); continue;
			}
			if(databuffer_queue.front().size != cd_datalen_db.read()){
				displayError("ERROR: Wrong data length requested"); continue;
			}
			//modify the entry in the queue so that we know that an address has been requested
			databuffer_queue.front().address_requested = true;
			last_databuffer_address = db_address_cd.read();
			db_address_cd = rand();
			writing_data = true;
			pos_in_entry = 0;
		}
 
		//When command decoder writing to databuffer, check that correct data is written
		if(cd_write_db.read()){
			if(!writing_data.read()){
				displayError("ERROR: Unexpected data write"); continue;
			}
			if(sc_uint<32>(databuffer_queue.front().data[pos_in_entry++]) !=
				cd_data_db.read())
			{
				displayError("ERROR: Wrong data received"); continue;
			}
			if(pos_in_entry > databuffer_queue.front().size){
				databuffer_queue.pop_front();
				writing_data = false;
			}
		}
 
		wait();
	}
}
 
void decoder_l2_tb::disconnect_retry_validation(){
	expect_cd_initiate_retry_disconnect = 0;
	expect_cd_received_stomped_csr = 0;
	expect_cd_initiate_nonretry_disconnect_lk = 0;
 
	while(!error){
		//Check if cd_initiate_retry_disconnect is expected to be asserted
		if(expect_cd_initiate_retry_disconnect > 0){
			//Reduce the count of cycles left before it must be asserted
			expect_cd_initiate_retry_disconnect--;
 
			//Remove the expected flag if it becomes asserted
			if(cd_initiate_retry_disconnect.read()){
				expect_cd_initiate_retry_disconnect = 0;
			}
			//If the count goes down to 0, give an error (timeout)
			else if(!expect_cd_initiate_retry_disconnect){
				displayError("ERROR: cd_initiate_retry_disconnect not asserted"); continue;				
			}
		}
		//If it is unexpectedly asserted, display error
		else if(cd_initiate_retry_disconnect.read()){
			displayError("ERROR: cd_initiate_retry_disconnect asserted"); continue;
		}
 
		//Check if cd_received_stomped_csr is expected to be asserted
		if(expect_cd_received_stomped_csr > 0){
			//Reduce the count of cycles left before it must be asserted
			expect_cd_received_stomped_csr--;
 
			//Remove the expected flag if it becomes asserted
			if(cd_received_stomped_csr.read()){
				expect_cd_received_stomped_csr = 0;
			}
			//If the count goes down to 0, give an error (timeout)
			else if(!expect_cd_received_stomped_csr){
				displayError("ERROR: cd_received_stomped_csr not asserted"); continue;				
			}
		}
		//If it is unexpectedly asserted, display error
		else if(cd_received_stomped_csr.read()){
			displayError("ERROR: cd_received_stomped_csr asserted"); continue;
		}
 
		//Check if cd_initiate_nonretry_disconnect_lk is expected to be asserted
		if(expect_cd_initiate_nonretry_disconnect_lk > 0){
			//Reduce the count of cycles left before it must be asserted
			expect_cd_initiate_nonretry_disconnect_lk--;
 
			//Remove the expected flag if it becomes asserted
			if(cd_initiate_nonretry_disconnect_lk.read()){
				expect_cd_initiate_nonretry_disconnect_lk = 0;
			}
			//If the count goes down to 0, give an error (timeout)
			else if(!expect_cd_initiate_nonretry_disconnect_lk){
				displayError("ERROR: cd_initiate_nonretry_disconnect_lk not asserted"); continue;				
			}
		}
		//If it is unexpectedly asserted, display error
		else if(cd_initiate_nonretry_disconnect_lk.read()){
			displayError("ERROR: cd_initiate_nonretry_disconnect_lk asserted"); continue;
		}
 
		wait();
	}
 
}
 
void decoder_l2_tb::reordering_validation(){
	//There is no data pending at the beggining
	sc_uint<BUFFERS_ADDRESS_WIDTH> pending_data_address;
	bool data_pending = false;
 
	while(!error){
		//Check that entries in the queue are not simply being accumulated without
		//ever being used
		if(reordering_queue.size() > 4){
			displayError("ERROR: Packets not sent to reordering"); continue;
		}
 
		//If packet is sent to reordering
		if(cd_available_ro.read()){
			//Check that there is a packet in the queue to avoid reading from an empty
			//queue if the decoder is not working correctly
			if(reordering_queue.empty()){
				ostringstream o;
				o << "ERROR: Unexpected command packet received: " << 
					cd_packet_ro.read().packet.to_string(SC_HEX);
				displayError(o.str().c_str()); continue;
			}
 
			//Check that the packet matches the entry in the front of the queue
			if(reordering_queue.front().pkt.packet != cd_packet_ro.read().packet ||
				reordering_queue.front().pkt.error64BitExtension != cd_packet_ro.read().error64BitExtension)
			{
				displayError("ERROR: Invalid command packet received"); continue;
			}
 
			//Check that the address of the data is correct (if apliccable)
			if(reordering_queue.front().has_data &&
				cd_packet_ro.read().data_address != last_databuffer_address)
			{
				displayError("ERROR: Invalid data address in packet sent to command buffers"); continue;
			}
 
			//Store what should be the pending data address for this packet
			pending_data_address = last_databuffer_address;
			//Remove it from the queue
			reordering_queue.pop_front();
		}
 
		if(cd_data_pending_ro.read() != data_pending)
		{
			displayError("ERROR: cd_data_pending_ro has wrong value"); continue;
		}
 
		/**
			Calculate if the decoder should advertise data pending.
				Rules : 
				 -No data pending when retry mode is active (csr_retry)
				 -It starts after a delay of getting address from
				  databuffer (delayed_start_writing_data2)
				 -It stays pending (data_pending) until a next command
				  packet is received (CTL available from link)
		*/
		data_pending = (data_pending && 
			!(lk_lctl_cd.read() && lk_available_cd.read() && !writing_data.read())
			|| (delayed_start_writing_data2.read())) && !csr_retry.read();
 
		if(cd_data_pending_ro.read() && 
			pending_data_address != cd_data_pending_addr_ro.read())
		{
			displayError("ERROR: invalid pending data address value"); continue;
		}
		wait();
	}
}
 
void decoder_l2_tb::displayError(const char * error_message){
	cout << error_message << endl;
	error = true;
	resetx = false;
}
 
void decoder_l2_tb::getRandomVector(sc_bv<32> &vector){
	vector.range(14,0) = sc_uint<15>(rand());
	vector.range(29,15) = sc_uint<15>(rand());
	vector.range(31,30) = sc_uint<2>(rand());
}
 
void decoder_l2_tb::getRandomVector(sc_bv<64> &vector){
	for(int n = 0; n < 4; n++)
		vector.range(15*(n+1) - 1,15*n) = sc_uint<15>(rand());
	vector.range(63,60) = sc_uint<4>(rand());
}
 
void decoder_l2_tb::addReorderingEntry(sc_bv<32> &vector,bool hasData){
	sc_bv<64> qword = 0;
	qword.range(31,0) = vector;
	addReorderingEntry(qword,hasData);
}
 
void decoder_l2_tb::addReorderingEntry(sc_bv<64> &vector,bool hasData){
	ReorderingEntry entry;
	entry.pkt.error64BitExtension = false;
	entry.pkt.packet = vector;
	entry.has_data = hasData;
	reordering_queue.push_back(entry);
}
 
void decoder_l2_tb::calculate_crc1(sc_bv<32> dword,bool lctl, bool hctl){
	sc_bv<34> data;
	data[33] = hctl;
	data.range(32,17) = dword.range(31,16);
	data[16] = lctl;
	data.range(15,0) = dword.range(15,0);
	calculate_crc(crc1,data);
}
 
void decoder_l2_tb::calculate_crc2(sc_bv<32> dword,bool lctl, bool hctl){
	sc_bv<34> data;
	data[33] = hctl;
	data.range(32,17) = dword.range(31,16);
	data[16] = lctl;
	data.range(15,0) = dword.range(15,0);
	calculate_crc(crc2,data);
}
 
void decoder_l2_tb::calculate_crc(unsigned &crc,sc_bv<34> &data){
	static unsigned poly = 0x04C11DB7;
 
	for(int i = 0; i < 34; i++){
		/* xor highest bit w/ message: */
		unsigned tmp = ((crc >> 31) & 1) ^ ( ((sc_bit)data[i]) ? 1 : 0);
 
		/* substract poly if greater: */
		crc = (tmp) ? (crc << 1) ^ poly : ((crc << 1) | tmp);
	}
}
 

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.