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

Subversion Repositories ht_tunnel

[/] [ht_tunnel/] [tags/] [START/] [bench/] [link_l2/] [link_l2_tb/] [link_l2_tb.cpp] - Rev 21

Go to most recent revision | Compare with Previous | Blame | View Log

//link_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 "link_l2_tb.h"
#include <cstdlib>
#include <iostream>
 
#include "../link_frame_rx_l3_tb/link_rx_transmitter.h"
#include "../link_frame_tx_l3_tb/link_tx_validator.h"
#include "../../core/require.h"
 
/**
	Note : this is far from being a full testbench.  The goal of this
	is to verify the basic fonctionnality.  Extensive testing of all
	possibilities is not yet a priority...  
 
	 The goals of this testbench are to check :
 
	-basic sequence without error (verify the correctness of sent CRC's)
	-basic with error on rx side (verify the correctness of sent CRC's)
	-ldtstop sequence
	-sync error
 
	-basic with error in CRC and retry mode enabled (should be ignored)
	-basic with error in CTL transition and retry mode
*/
 
 
link_l2_tb::link_l2_tb(sc_module_name name) : sc_module(name){
	SC_THREAD(manage_rx_transmission);
	sensitive_pos(clk);
 
	SC_THREAD(validate_rx_reception);
	sensitive_pos(clk);
 
	SC_THREAD(stimulus);
	sensitive_pos(clk);
 
	transmitter = new link_rx_transmitter("link_rx_transmitter");
	transmitter->clk(clk);
	transmitter->phy_ctl_lk(phy_ctl_lk);
	for(int n = 0; n < CAD_IN_WIDTH; n++){
		transmitter->phy_cad_lk[n](phy_cad_lk[n]);
	}
	transmitter->phy_available_lk(phy_available_lk);
 
#ifndef INTERNAL_SHIFTER_ALIGNMENT
	transmitter->lk_deser_stall_phy(lk_deser_stall_phy);
	transmitter->lk_deser_stall_cycles_phy(lk_deser_stall_cycles_phy);
#endif
 
	validator = new link_tx_validator("link_tx_validator");
	validator->clk(clk);
 
	validator->lk_ctl_phy(lk_ctl_phy);
	for(int n = 0; n < CAD_IN_WIDTH; n++){
		validator->lk_cad_phy[n](lk_cad_phy[n]);
	}
	validator->tx_consume_data(lk_consume_fc);
 
	validator->phy_consume_lk(phy_consume_lk);
	validator->cad_to_frame(fc_dword_lk);
	validator->lctl_to_frame(fc_lctl_lk);
	validator->hctl_to_frame(fc_hctl_lk);
 
	//A random seed value
	srand(23524);
	reset_rx_connection = false;
	check_rx_dword_reception = true;
	rx_number = 0;
	expecting_rx_crc_error = 0;
 
	rx_crc = 0xFFFFFFFF;
	tx_crc = 0xFFFFFFFF;
}
 
link_l2_tb::~link_l2_tb(){
	delete transmitter;
	delete validator;
}
 
void link_l2_tb::stimulus(){
	init();
 
	link_tx_validator::LinkTransmission_TX tx_crc_transmission;
	tx_crc_transmission.lctl = true;
	tx_crc_transmission.hctl = true;
 
	LinkTransmission rx_crc_transmission;
	rx_crc_transmission.error = false;
	rx_crc_transmission.lctl = true;
	rx_crc_transmission.hctl = true;
 
	//////////////////////////////////////
	// First test, valid and nonvalid CRC
	//////////////////////////////////////
 
	init_fill_queues(272,false);
	tx_crc_transmission.dword = ~last_tx_crc;
	validator->expected_transmission.push(tx_crc_transmission);
	//cout << "Expected TX CRC : " << tx_crc_transmission.dword.to_string(SC_HEX) << endl;
 
	//rx_crc_transmission.dword = ~last_rx_crc;
	//Generate error!
	rx_crc_transmission.dword = 0x01234567;
	transmit_rx_queue.push(rx_crc_transmission);
	expecting_rx_crc_error++;
 
	fill_rx_qeues(16, true);
	fill_tx_qeues(16, true);
 
	link_tx_validator::LinkTransmission_TX nop_transmit;
	nop_transmit.dword = 0;
	nop_transmit.lctl = true;
	nop_transmit.hctl = true;
 
	validator->expect_tx_consume_data = 600;
 
	while(!(expected_rx_queue.empty() && validator->expected_transmission.empty())){
		if(validator->to_transmit.size() < 2){
			validator->to_transmit.push(nop_transmit);
			validator->checking_errors = false;
		}
 
		if(lk_crc_error_csr.read()){
			if(!expecting_rx_crc_error)
				cout << "CRC mismatch on reception" << endl;
			else
				expecting_rx_crc_error--;
		}
		wait();
	}
 
	cout << "Done basic sequence without CTL error " << endl;
	resetx = false;
 
	if(expecting_rx_crc_error){
		cout << "Some CRC transmission errors were not detected!" << endl;
	}
 
	//////////////////////////////////////
	// Test : LDTSTOP sequence
	//////////////////////////////////////
	cout << endl << "Start LDTSTOP test" << endl;
	empty_tx_queues(true);
	empty_rx_queues(true);
	init();
	cout << "LDTSTOP init done" << endl;
	init_fill_queues(272,true);
	validator->expect_tx_consume_data = 600;
 
	//Send part of the data
	while(validator->expected_transmission.size() > 114){
		if(lk_crc_error_csr.read()){
			if(!expecting_rx_crc_error)
				cout << "CRC mismatch on reception" << endl;
			else
				expecting_rx_crc_error--;
		}
		wait();
	}
 
	cout << "starting LDTSTOP sequence" << endl;
 
	//Start ldtstop sequence
	ldtstopx = false;
	cd_initiate_nonretry_disconnect_lk = true;
 
	while(validator->expected_transmission.size() > 0){
		if(lk_crc_error_csr.read()){
			if(!expecting_rx_crc_error)
				cout << "CRC mismatch on reception" << endl;
			else
				expecting_rx_crc_error--;
		}
		wait();
	}
 
	cout << "Sending disconnect nops" << endl;
 
	//Disconnect NOPs!
	link_tx_validator::LinkTransmission_TX t_tx;
	t_tx.dword = sc_uint<32>(0x00000020); t_tx.hctl = true; t_tx.lctl = true;
	for(int n = 0; n < 20; n++)
		validator->expected_transmission.push(t_tx);
 
	while(validator->expected_transmission.size() > 10){
		if(lk_crc_error_csr.read()){
			if(!expecting_rx_crc_error)
				cout << "CRC mismatch on reception" << endl;
			else
				expecting_rx_crc_error--;
		}
		wait();
	}
 
	cout << "Done LDTSTOP sequence test" << endl;
 
	//////////////////////////////////////
	// Test : SYNC sequence
	//////////////////////////////////////
	cout << endl << "Start SYNC test" << endl;
	empty_tx_queues(true);
	empty_rx_queues(true);
	init();
	init_fill_queues(400,true);
	validator->expect_tx_consume_data = 600;
 
	cout << "Start sending data" << endl;
	//Send part of the data
	while(validator->expected_transmission.size() > 1 || !phy_consume_lk.read()){
		if(lk_crc_error_csr.read()){
			if(!expecting_rx_crc_error)
				cout << "CRC mismatch on reception" << endl;
			else
				expecting_rx_crc_error--;
		}
		wait();
	}
 
	cout << "starting SYNC sequence" << endl;
 
	//Start sync sequence
	csr_sync = true;
 
	//Empty all expected packets
	for(int n = expected_rx_queue.size(); n != 0 ;n--)
		expected_rx_queue.pop();
 
	//Expect disconnect NOPs!
	t_tx.dword = sc_uint<32>(0xFFFFFFFF); t_tx.hctl = true; t_tx.lctl = true;
	for(int n = 0; n < 150; n++)
		validator->expected_transmission.push(t_tx);
 
	while(validator->expected_transmission.size() > 10){
		if(lk_crc_error_csr.read()){
			cout << "CRC mismatch on reception" << endl;
		}
		wait();
	}
 
	csr_sync = false;
	cout << "Done SYNC sequence test" << endl;
 
	//////////////////////////////////////
	// Test : CRC Error in retry mode (should be ignored)
	//////////////////////////////////////
	cout << endl << "Start Retry CRC error test" << endl;
	empty_tx_queues(true);
	empty_rx_queues(true);
	init();
	init_fill_queues(272,false);
	validator->checking_errors = false;
 
	//rx_crc_transmission.dword = ~last_rx_crc;
	//Generate error!
	transmit_rx_queue.push(rx_crc_transmission);
 
	fill_rx_qeues(16, true);
	fill_tx_qeues(16, true);
 
	validator->expect_tx_consume_data = 600;
 
	csr_retry = true;
 
	while(!(expected_rx_queue.empty() && validator->expected_transmission.empty())){
		if(validator->to_transmit.size() < 2){
			validator->to_transmit.push(nop_transmit);
		}
 
		if(lk_crc_error_csr.read())
			cout << "ERROR : CRC mismatch signaled in retry mode" << endl;
		if(lk_initiate_retry_disconnect.read())
			cout << "Error, retry sequence started incorrectly!" << endl;
		wait();
	}
 
	cout << "Done retry sequence with periodic CRC error " << endl;
	resetx = false;
	csr_retry = false;
	//validator->checking_errors = true;
 
 
	//////////////////////////////////////
	// Test : CTL transition error in retry mode
	//////////////////////////////////////
	cout << endl << "Start Retry CTL error test" << endl;
	empty_tx_queues(true);
	empty_rx_queues(true);
	init();
	init_fill_queues(50,false);
	csr_retry = true;
	validator->checking_errors = false;
 
	LinkTransmission rx_ctl_error_t;
	rx_ctl_error_t.error = true;
	rx_ctl_error_t.lctl = true;
	rx_ctl_error_t.hctl = true;
	rx_ctl_error_t.dword = 0x01234567;
 
	transmit_rx_queue.push(rx_ctl_error_t);
 
	fill_rx_qeues(16, true);
	fill_tx_qeues(16, true);
 
	validator->expect_tx_consume_data = 600;
 
	csr_retry = true;
 
	while(!expected_rx_queue.empty() && !lk_initiate_retry_disconnect.read())
		wait();
 
	if(!lk_initiate_retry_disconnect.read())
		cout << "Error, retry sequence not started correctly!" << endl;
 
	csr_retry = false;
	cout << "Done retry sequence CTL error " << endl;
 
	//////////////////////////////////////
	// Test : initiate an external retry sequence
	//////////////////////////////////////
 
	/*cout << "Start initiate Retry test" << endl;
	empty_tx_queues(true);
	empty_rx_queues(true);
	init();
	init_fill_queues(50,false);
	csr_retry = true;
 
	while(validator->expected_transmission.size() > 10)
		wait();*/
 
	resetx = false;
	validator->checking_errors = false;
	validator->reset();
 
	//Inifinite loop
	while(true) wait();
}
 
void link_l2_tb::init(){
	cout << "TB: Init" << endl;
 
	/**
		Start reset and initialist internal variables and signals sent
		to the link
	*/
	resetx = false;
	pwrok = false;
	ldtstopx = false;
 
	csr_rx_link_width_lk = "000";
	csr_tx_link_width_lk = "000";
	csr_sync = false;
	csr_end_of_chain = false;
 
	csr_crc_force_error_lk = false;
	csr_transmitter_off_lk = false;
	csr_extented_ctl_lk = false;
	csr_extended_ctl_timeout_lk = false;
	csr_ldtstop_tristate_enable_lk = false;
 
#ifdef RETRY_MODE_ENABLED
	cd_initiate_retry_disconnect = false;
	fc_disconnect_lk = false;
	csr_retry = false;
#endif
	cd_initiate_nonretry_disconnect_lk = false;
 
	//Reset validator to initial state
	validator->reset();
	//Wait some cycles for reset to have effect
	for(int n = 0; n < 5; n++) wait();
	validator->reset();//Not sure this call is necessary...
 
	//Stop cold reset and make sure no in ldtstop sequence
	pwrok = true;
	ldtstopx = true;
	transmitter->send_initial_value(5);
 
	for(int n = 0; n < 5; n++) wait();
 
	//stop reset
	resetx = true;
	//Reset the rx connection (it will reconnect automatically)
	reset_rx_connection = true;
}
 
void link_l2_tb::init_fill_queues(const unsigned quantity,bool insertLastCrc){
	//First, push a maximum of 128 in
	int q_max128 = quantity > 128 ? 128 : quantity;
	fill_rx_qeues(q_max128, true);
	fill_tx_qeues(q_max128, true);
 
	//Check how many are to add
	int quantity_remaining = quantity - q_max128;
 
	//if none, we're done
	if(!quantity_remaining) return;
 
	//128 is the first window 
	last_rx_crc = rx_crc;
	last_tx_crc = tx_crc;
	rx_crc = 0xFFFFFFFF;
	tx_crc = 0xFFFFFFFF;
 
	//Transmission object that will hold tx CRC
	link_tx_validator::LinkTransmission_TX tx_crc_transmission;
	tx_crc_transmission.lctl = true;
	tx_crc_transmission.hctl = true;
 
	//Transmission object that will hold rx CRC
	LinkTransmission rx_crc_transmission;
	rx_crc_transmission.error = false;
	rx_crc_transmission.lctl = true;
	rx_crc_transmission.hctl = true;
	while(true){
		//Send a max of 16 dwords
		int q_max16 = quantity_remaining > 16 ? 16 : quantity_remaining;
		//substract the number sent to the quantity remaining
		quantity_remaining -= q_max16;
 
		//Fill the queues
		fill_rx_qeues(q_max16, true);
		fill_tx_qeues(q_max16, true);
 
		//Break if done
		//If less than 16 were pushed in, we reached our quantity
		//If 16 were pushed and none left, we're done if we don't want
		//to add the last CRC
		if(!quantity_remaining && !insertLastCrc || q_max16 != 16) break;
 
		//Insert the CRC
		tx_crc_transmission.dword = ~last_tx_crc;
		rx_crc_transmission.dword = ~last_rx_crc;
		validator->expected_transmission.push(tx_crc_transmission);
		transmit_rx_queue.push(rx_crc_transmission);
		//cout << "TX CRC inserted : " << tx_crc_transmission.dword.to_string(SC_HEX)
		//	<< " Size now : " << validator->expected_transmission.size() << endl;
 
		if(!quantity_remaining) break;
 
		//Insert the next 112 dwords of the window
		int q_max112 = quantity_remaining > 112 ? 112 : quantity_remaining;
		quantity_remaining -= q_max112;
 
		fill_rx_qeues(q_max112, true);
		fill_tx_qeues(q_max112, true);
 
 
		last_rx_crc = rx_crc;
		last_tx_crc = tx_crc;
		rx_crc = 0xFFFFFFFF;
		tx_crc = 0xFFFFFFFF;	
 
		if(!quantity_remaining) break;
	}
}
 
 
void link_l2_tb::fill_tx_qeues(const unsigned quantity, bool updateCRC){
	LinkTransmission t;
	link_tx_validator::LinkTransmission_TX t_tx;
 
	//Add the requested number of transmissions
	for(unsigned n = 0; n < quantity; n++){
		//Generate a transmission
		generate_random_transmission(t);
		//Simply copy it into a TX transmission
		t_tx.dword = t.dword; t_tx.hctl = t.hctl; t_tx.lctl = t.lctl;
 
		//Put it in the expected and to_transmit queues
		validator->expected_transmission.push(t_tx);
		validator->to_transmit.push(t_tx);
		if(updateCRC) {
			update_crc(tx_crc,t.dword,t.lctl,t.hctl);
			//cout << "CRC after " << n << " : " << tx_crc << "Hex " << sc_uint<32>(tx_crc).to_string(SC_HEX) << endl;
		}
	}
}
 
void link_l2_tb::empty_tx_queues(bool reset_crc){
	for(int n = validator->expected_transmission.size(); n > 0; n--)
		validator->expected_transmission.pop();
	for(int n = validator->to_transmit.size(); n > 0; n--)
		validator->to_transmit.pop();
	if(reset_crc){
		last_tx_crc = 0;
		tx_crc = 0xFFFFFFFF;
	}
}
 
void link_l2_tb::fill_rx_qeues(const unsigned quantity, bool updateCRC){
	LinkTransmission t;
	t.error = false;
	for(int n = quantity; n != 0; n--){
		generate_random_transmission(t);
		transmit_rx_queue.push(t);
		expected_rx_queue.push(t);
		if(updateCRC) 
			update_crc(rx_crc,t.dword,t.lctl,t.hctl);
	}
}
 
void link_l2_tb::empty_rx_queues(bool reset_crc){
	for(int n = transmit_rx_queue.size();n>0;n--)
		transmit_rx_queue.pop();
	for(int n = expected_rx_queue.size();n>0;n--)
		expected_rx_queue.pop();
	if(reset_crc){
		last_rx_crc = 0;
		rx_crc = 0xFFFFFFFF;
	}
}
 
void link_l2_tb::generate_random_transmission(LinkTransmission & t){
	//15 bit used for rand because some implementations of rand
	//have a max of 32K
	sc_uint<15> r = rand();
	t.dword.range(31,24) = r.range(7,0);
	r = rand();
	t.dword.range(23,16) = r.range(7,0);
	r = rand();
	t.dword.range(15,8) = r.range(7,0);
	r = rand();
	t.dword.range(7,0) = r.range(7,0);
 
	t.lctl = (rand() << 1) / (RAND_MAX);
	t.hctl = (rand() << 1) / (RAND_MAX);
}
 
void link_l2_tb::update_crc(int & crc,const sc_bv<32> &dword, bool lctl, bool hctl){
	//There is a total of 36 bits to throw in CRC.  Since it's higher
	//than 32 bits, do it in two passes of 18 bits
	unsigned dword_int = (unsigned)sc_uint<32>(dword);
 
	//Put data in integers
	int data[2] = {
		(dword_int & 0xFF) | ((dword_int & 0xFF00) << 1),
		((dword_int & 0xFF0000) >> 16) | ((dword_int & 0xFF000000) >> 15)
	};
 
	//Add the lctl values to the CRC
	if(lctl) data[0] |= 0x20100;
	if(hctl) data[1] |= 0x20100;
 
	sc_uint<18> d0 = data[0];
	sc_uint<18> d1 = data[1];
 
	sc_bv<36> complete_data;
	complete_data.range(17,0) = data[0];
	complete_data.range(35,18) = data[1];
 
	//cout << "TB CRC DATA " << complete_data.to_string(SC_HEX) << endl;
 
	//Do the two passes 
	for(int n = 0; n < 2; n++){
		//- taken exactly from the HT spec (10.1.1)
		for(int i = 0; i < 18; i++){
			int tmp = crc >> 31; /* store highest bit */
			crc = (crc << 1) | ((data[n] >> i) & 1); /* shift message in */
			crc = (tmp) ? crc ^ poly : crc; /* substract poly if greater */
		}
	}
}
 
 
void link_l2_tb::manage_rx_transmission(){
	while(true){
		if(reset_rx_connection){
			transmitter->send_initial_value(5);
			transmitter->send_init_sequence(0,0);
			reset_rx_connection = false;
		}
		if(!transmit_rx_queue.empty()){
			transmitter->send_dword_link(
				transmit_rx_queue.front().dword,
				transmit_rx_queue.front().lctl,
				transmit_rx_queue.front().hctl,
				transmit_rx_queue.front().error);
			transmit_rx_queue.pop();
		}
		else
			wait();
	}
}
 
 
void link_l2_tb::validate_rx_reception(){
	while(true){
		wait();
		//Test reception of data
		if(lk_available_cd.read() && check_rx_dword_reception){
			verify(!(expected_rx_queue.empty()),
				"RX : Unexpected data reception");
			if(!expected_rx_queue.empty()){
				LinkTransmission t = expected_rx_queue.front();
 
				/*cout << "RX Data in front : L=" << t.lctl << " H=" <<
					t.hctl << " D=" << t.dword.to_string(SC_HEX) << "  Number: " << rx_number++ << endl;
				cout << "RX Data received : L=" << lk_lctl_cd.read() << " H=" <<
					lk_hctl_cd.read() << " D=" << lk_dword_cd.read().to_string(SC_HEX) << endl;*/
 
				expected_rx_queue.pop();
 
				verify((t.dword == lk_dword_cd.read() &&
						t.lctl == lk_lctl_cd.read() &&
						t.hctl == lk_hctl_cd.read()),
					"RX Invalid data received");
			}
		}
	}
 
}
 

Go to most recent revision | 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.