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

Subversion Repositories dblclockfft

[/] [dblclockfft/] [trunk/] [bench/] [cpp/] [laststage_tb.cpp] - Rev 36

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

////////////////////////////////////////////////////////////////////////////
//
// Filename: 	laststage_tb.cpp
//
// Project:	A Doubletime Pipelined FFT
//
// Purpose:	A test-bench for the laststage.v subfile of the general purpose
//		pipelined FFT.  This file may be run autonomously.  If so,
//	the last line output will either read "SUCCESS" on success, or some
//	other failure message otherwise.
//
//	This file depends upon verilator to both compile, run, and therefore
//	test laststage.v
//
// Creator:	Dan Gisselquist, Ph.D.
//		Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015,2018 Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of  the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program.  (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.)  If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License:	GPL, v3, as defined and found on www.gnu.org,
//		http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdint.h>
 
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "Vlaststage.h"
#include "twoc.h"
 
#define	IWIDTH	16
#define	OWIDTH	(IWIDTH+1)
#define	SHIFT	0
#define	ROUND	1
 
#define	ASIZ	32
#define	AMSK	(ASIZ-1)
 
class	LASTSTAGE_TB {
public:
	Vlaststage	*m_last;
	VerilatedVcdC	*m_trace;
#ifdef	DBLCLKFFT
	unsigned long	m_left[ASIZ], m_right[ASIZ];
#else
	unsigned long	m_data[ASIZ];
#endif
	bool		m_syncd;
	int		m_addr, m_offset;
	unsigned long	m_tickcount;
 
	LASTSTAGE_TB(void) {
		Verilated::traceEverOn(true);
		m_last = new Vlaststage;
		m_tickcount = 0;
		m_syncd = false; m_addr = 0, m_offset = 0;
	}
 
	void	opentrace(const char *vcdname) {
		if (!m_trace) {
			m_trace = new VerilatedVcdC;
			m_last->trace(m_trace, 99);
			m_trace->open(vcdname);
		}
	}
 
	void	closetrace(void) {
		if (m_trace) {
			m_trace->close();
			delete m_trace;
			m_trace = NULL;
		}
	}
 
	void	tick(void) {
		m_tickcount++;
 
		m_last->i_clk = 0;
		m_last->eval();
		if (m_trace) m_trace->dump((uint64_t)(10ul * m_tickcount - 2));
		m_last->i_clk = 1;
		m_last->eval();
		if (m_trace) m_trace->dump((uint64_t)(10ul * m_tickcount));
		m_last->i_clk = 0;
		m_last->eval();
		if (m_trace) {
			m_trace->dump((uint64_t)(10ul * m_tickcount + 5));
			m_trace->flush();
		}
		m_last->i_reset  = 0;
		m_last->i_sync = 0;
	}
 
	void	cetick(void) {
		int	nkce;
 
		tick();
		nkce = (rand()&1);
#ifdef	FFT_CKPCE
		nkce += FFT_CKPCE;
#endif
		if ((m_last->i_ce)&&(nkce > 0)) {
			m_last->i_ce = 0;
			for(int kce = 1; kce < nkce; kce++)
				tick();
			m_last->i_ce = 1;
		}
	}
 
	void	reset(void) {
		m_last->i_reset = 1;
		tick();
 
		m_syncd = false; m_addr = 0, m_offset = 0;
	}
 
	void	check_results(void) {
		bool	failed = false;
 
		if ((!m_syncd)&&(m_last->o_sync)) {
			m_syncd = true;
			m_offset = m_addr;
			printf("SYNCD at %d\n", m_addr);
		}
 
#ifdef	DBLCLKFFT
		int	ir0, ir1, ii0, ii1, or0, oi0, or1, oi1;
 
		ir0 = sbits(m_left[ (m_addr-m_offset)&AMSK]>>IWIDTH, IWIDTH);
		ir1 = sbits(m_right[(m_addr-m_offset)&AMSK]>>IWIDTH, IWIDTH);
		ii0 = sbits(m_left[ (m_addr-m_offset)&AMSK], IWIDTH);
		ii1 = sbits(m_right[(m_addr-m_offset)&AMSK], IWIDTH);
 
 
		or0 = sbits(m_last->o_left  >> OWIDTH, OWIDTH);
		oi0 = sbits(m_last->o_left           , OWIDTH);
		or1 = sbits(m_last->o_right >> OWIDTH, OWIDTH);
		oi1 = sbits(m_last->o_right          , OWIDTH);
 
 
		// Sign extensions
		printf("k=%3d: IN = %08x:%08x, OUT =%09lx:%09lx, S=%d\n",
			m_addr, m_last->i_left, m_last->i_right,
			m_last->o_left, m_last->o_right,
			m_last->o_sync);
 
		/*
		printf("\tI0 = { %x : %x }, I1 = { %x : %x }, O0 = { %x : %x }, O1 = { %x : %x }\n",
			ir0, ii0, ir1, ii1, or0, oi0, or1, oi1);
		*/
 
		if (m_syncd) {
			if (or0 != (ir0 + ir1))	{
				printf("FAIL 1: or0 != (ir0+ir1), or %x(exp) != %x(sut)\n", (ir0+ir1), or0);
				failed=true;}
			if (oi0 != (ii0 + ii1))	{printf("FAIL 2\n"); failed=true;}
			if (or1 != (ir0 - ir1))	{printf("FAIL 3\n"); failed=true;}
			if (oi1 != (ii0 - ii1))	{printf("FAIL 4\n"); failed=true;}
		} else if (m_addr > 20) {
			printf("NO SYNC!\n");
			failed = true;
		}
#else
		int	or0, oi0;
		int	sumr, sumi, difr, difi;
		int	ir0, ii0, ir1, ii1, ir2, ii2, ir3, ii3, irn, iin;
 
		irn = sbits(m_data[(m_addr-m_offset+2)&AMSK]>>IWIDTH, IWIDTH);
		iin = sbits(m_data[(m_addr-m_offset+2)&AMSK], IWIDTH);
		ir0 = sbits(m_data[(m_addr-m_offset+1)&AMSK]>>IWIDTH, IWIDTH);
		ii0 = sbits(m_data[(m_addr-m_offset+1)&AMSK], IWIDTH);
		ir1 = sbits(m_data[(m_addr-m_offset  )&AMSK]>>IWIDTH, IWIDTH);
		ii1 = sbits(m_data[(m_addr-m_offset  )&AMSK], IWIDTH);
		ir2 = sbits(m_data[(m_addr-m_offset-1)&AMSK]>>IWIDTH, IWIDTH);
		ii2 = sbits(m_data[(m_addr-m_offset-1)&AMSK], IWIDTH);
		ir3 = sbits(m_data[(m_addr-m_offset-2)&AMSK]>>IWIDTH, IWIDTH);
		ii3 = sbits(m_data[(m_addr-m_offset-2)&AMSK], IWIDTH);
 
		sumr = ir1 + ir0;
		sumi = ii1 + ii0;
 
		difr = ir2 - ir1;
		difi = ii2 - ii1;
 
		or0 = sbits(m_last->o_val  >> OWIDTH, OWIDTH);
		oi0 = sbits(m_last->o_val           , OWIDTH);
 
		printf("IR0 = %08x, IR1 = %08x, IR2 = %08x, ",
				ir0, ir1, ir2);
		printf("II0 = %08x, II1 = %08x, II2 = %08x, ",
				ii0, ii1, ii2);
		// Sign extensions
		printf("k=%3d: IN = %08x, %c, OUT =%09lx, S=%d\n",
			m_addr, m_last->i_val,
			m_last->i_sync ? 'S':' ',
			m_last->o_val, m_last->o_sync);
 
 
		if ((m_syncd)&&(0 == ((m_addr-m_offset)&1))) {
			if (or0 != sumr)	{
				printf("FAIL 1: or0 != (ir0+ir1), or %x(exp) != %x(sut)\n", sumr, or0);
				failed=true;
			} if (oi0 != sumi)	{
				printf("FAIL 2\n");
				failed=true;
			}
		} else if ((m_syncd)&&(1 == ((m_addr-m_offset)&1))) {
			if (or0 != difr) {
				printf("FAIL 3: or0 != (ir1-ir0), or %x(exp) != %x(sut)\n", difr, or0);
				failed=true;
			} if (oi0 != difi) {
				printf("FAIL 4: oi0 != (ii1-ii0), or %x(exp) != %x(sut)\n", difi, oi0);
				failed=true;
			}
		} else if (m_addr > 20) {
			printf("NO SYNC!\n");
			failed = true;
		}
#endif
		if (failed)
			exit(-2);
	}
 
	void	sync(void) {
		m_last->i_sync = 1;
	}
 
	void	test(unsigned long left, unsigned long right) {
		m_last->i_ce    = 1;
		if (m_last->i_sync)
			m_addr = 0;
#ifdef	DBLCLKFFT
		m_last->i_left  = left;
		m_last->i_right = right;
 
		m_left[ m_addr&AMSK] = m_last->i_left;
		m_right[m_addr&AMSK] = m_last->i_right;
		m_addr++;
 
		cetick();
#else
		m_last->i_val = left;
		m_data[ m_addr&AMSK] = m_last->i_val;
		m_addr = (m_addr+1);
		cetick();
 
		check_results();
 
		m_last->i_val = right;
		m_data[m_addr&AMSK] = m_last->i_val;
		m_addr = (m_addr+1)&AMSK;
		cetick();
#endif
 
		check_results();
	}
 
	void	test(int ir0, int ii0, int ir1, int ii1) {
		unsigned long	left, right, mask = (1<<IWIDTH)-1;
 
		left  = ((ir0&mask) << IWIDTH) | (ii0 & mask);
		right = ((ir1&mask) << IWIDTH) | (ii1 & mask);
		test(left, right);
	}
};
 
int	main(int argc, char **argv, char **envp) {
	Verilated::commandArgs(argc, argv);
	LASTSTAGE_TB	*tb = new LASTSTAGE_TB;
 
	tb->opentrace("laststage.vcd");
	tb->reset();
 
	tb->sync();
 
	tb->test( 1, 0,0,0);
	tb->test( 0, 2,0,0);
	tb->test( 0, 0,4,0);
	tb->test( 0, 0,0,8);
 
	tb->test( 0, 0,0,0);
 
	tb->test(16,16,0,0);
	tb->test(0,0,16,16);
	tb->test(16,-16,0,0);
	tb->test(0,0,16,-16);
	tb->test(16,16,0,0);
	tb->test(0,0,16,16);
 
	for(int k=0; k<64; k++) {
		int16_t	ir0, ii0, ir1, ii1;
 
		// Let's pick some random values, ...
		ir0 = rand(); if (ir0&4) ir0 = -ir0;
		ii0 = rand(); if (ii0&2) ii0 = -ii0;
		ir1 = rand(); if (ir1&1) ir1 = -ir1;
		ii1 = rand(); if (ii1&8) ii1 = -ii1;
 
		tb->test(ir0, ii0, ir1, ii1);
 
	}
 
	delete	tb;
 
	printf("SUCCESS!\n");
	exit(0);
}
 
 
 
 
 
 
 

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.