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

Subversion Repositories zipcpu

[/] [zipcpu/] [trunk/] [sim/] [verilator/] [zipmmu_tb.cpp] - Rev 204

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

////////////////////////////////////////////////////////////////////////////////
//
// Filename:	zipmmu_tb.cpp
//
// Project:	Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose:	A quick test bench to determine if the zipmmu module works.
//		This test bench does nothing to determine whether or not it
//	is connected properly, but only tests whether or not the zipmmu works
//	as it is supposed to.
//
//
// Creator:	Dan Gisselquist, Ph.D.
//		Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, 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.
//
// License:	GPL, v3, as defined and found on www.gnu.org,
//		http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#include <stdio.h>
 
#include <verilated.h>
#include <verilated_vcd_c.h>
#include "testb.h"
#include "Vzipmmu_tb.h"
 
#define	MMUFLAG_RONW	8 // Read only (not writeable)
#define	MMUFLAG_ACCS	4 // Accessed
#define	MMUFLAG_CCHE	2 // Cachable
#define	MMUFLAG_THSP	1 // Page has this context
 
const int	BOMBCOUNT = 32,
		LGMEMSIZE = 15;
 
class	ZIPMMU_TB : public TESTB<Vzipmmu_tb> {
	long		m_tickcount;
	bool		m_bomb, m_miss, m_err, m_debug;
	int		m_last_tlb_index;
public:
 
	ZIPMMU_TB(void) {
		m_debug = true;
		m_last_tlb_index = 0;
	}
 
#define	v__DOT__mem_stb	v__DOT__mut__DOT__r_valid
	void	tick(void) {
 
		TESTB<Vzipmmu_tb>::tick();
 
		bool	writeout = true;
 
		if ((m_debug)&&(writeout)) {
			printf("%08lx-MMU: ", m_tickcount);
			printf("(%s%s%s%s) %08x (%s%s%s)%08x%s %s %08x/%08x %s%s%s%s%s",
				(m_core->i_ctrl_cyc_stb)?"CT":"  ",
				(m_core->i_wbm_cyc)?"CYC":"   ",
				(m_core->i_wbm_stb)?"STB":"   ",
				(m_core->i_wb_we)?"WE":"  ",
				(m_core->i_wb_addr),
				(m_core->v__DOT__mem_cyc)?"CYC":"   ",
				(m_core->v__DOT__mem_stb)?"STB":"   ",
#define	v__DOT__mem_we	v__DOT__mut__DOT__r_we
				(m_core->v__DOT__mem_we)?"WE":"  ",
				(m_core->v__DOT__mem_addr),
				(m_core->v__DOT__mem_err)?"ER":"  ",
				(m_core->i_wb_we)?"<-":"->",
				(m_core->i_wb_we)?m_core->i_wb_data:m_core->o_rtn_data,
				(m_core->v__DOT__mem_we)?m_core->v__DOT__mut__DOT__r_data:m_core->v__DOT__mem_odata,
				(m_core->o_rtn_stall)?"STALL":"     ",
				(m_core->v__DOT__mut__DOT__setup_ack)?"S":" ",
				(m_core->o_rtn_ack )?"ACK":"   ",
				(m_core->o_rtn_miss)?"MISS":"    ",
				(m_core->o_rtn_err )?"ERR":"   ");
 
			printf("[%d,%d]",
				m_core->v__DOT__mut__DOT__wr_vtable,
				m_core->v__DOT__mut__DOT__wr_ptable);
			printf("[%d,%d,%04x]",
				m_core->v__DOT__mut__DOT__wr_control,
				m_core->v__DOT__mut__DOT__z_context,
				m_core->v__DOT__mut__DOT__r_context_word);
			/*
			printf("[%08x,%08x-%08x]", 
				m_core->v__DOT__mut__DOT__w_vtable_reg,
				m_core->v__DOT__mut__DOT__w_ptable_reg,
				m_core->v__DOT__mut__DOT__setup_data);
			*/
			printf(" %s[%s%s@%08x,%08x]",
				(m_core->v__DOT__mut__DOT__r_pending)?"R":" ",
				(m_core->v__DOT__mut__DOT__r_we)?"W":" ",
				(m_core->v__DOT__mut__DOT__r_valid)?"V":" ",
				(m_core->v__DOT__mut__DOT__r_addr),
				(m_core->v__DOT__mut__DOT__r_data));
			printf("@%2x[%s%s%s][%s%s%s%s]",
				(m_core->v__DOT__mut__DOT__s_tlb_addr),
				(m_core->v__DOT__mut__DOT__s_pending)?"P":" ",
				(m_core->v__DOT__mut__DOT__s_tlb_hit)?"HT":"  ",
				(m_core->v__DOT__mut__DOT__s_tlb_miss)?"MS":"  ",
				(m_core->v__DOT__mut__DOT__ro_flag)?"RO":"  ",
				(m_core->v__DOT__mut__DOT__simple_miss)?"SM":"  ",
				(m_core->v__DOT__mut__DOT__ro_miss)?"RM":"  ",
				(m_core->v__DOT__mut__DOT__table_err)?"TE":"  ");
				//(m_core->v__DOT__mut__DOT__cachable)?"CH":"  ");
			/*
			printf(" M[%016lx]",
				m_core->v__DOT__mut__DOT__r_tlb_match);
			printf(" P[%3d] = 0x%08x, V=0x%08x, C=0x%08x, CTXT=%04x",
				m_last_tlb_index,
				m_core->v__DOT__mut__DOT__tlb_pdata[m_last_tlb_index],
				m_core->v__DOT__mut__DOT__tlb_vdata[m_last_tlb_index],
				m_core->v__DOT__mut__DOT__tlb_cdata[m_last_tlb_index],
				m_core->v__DOT__mut__DOT__r_context_word);
			*/
			printf("\n");
		}
	}
 
	void reset(void) {
		m_core->i_rst    = 1;
		m_core->i_ctrl_cyc_stb = 0;
		m_core->i_wbm_cyc  = 0;
		m_core->i_wbm_stb  = 0;
		tick();
		m_core->i_rst  = 0;
	}
 
	void wb_tick(void) {
		m_core->i_rst  = 0;
		m_core->i_ctrl_cyc_stb = 0;
		m_core->i_wbm_cyc  = 0;
		m_core->i_wbm_stb  = 0;
		tick();
		assert(!m_core->o_rtn_ack);
		assert(!m_core->o_rtn_err);
	}
 
	unsigned operator[](unsigned a) {
		a &= ((1<<LGMEMSIZE)-1);
		return m_core->v__DOT__ram__DOT__mem[a];
	}
 
	unsigned setup_read(unsigned a) {
		int		errcount = 0;
		unsigned	result;
		m_miss = false; m_err = false;
 
		printf("WB-READS(%08x)\n", a);
 
		m_core->i_ctrl_cyc_stb = 1;
		m_core->i_wbm_cyc = 0;
		m_core->i_wbm_stb = 0;
		m_core->i_wb_we  = 0;
		m_core->i_wb_addr= a;
 
		if (m_core->o_rtn_stall) {
			while((errcount++ < BOMBCOUNT)&&(m_core->o_rtn_stall))
				tick();
		} tick();
 
		m_core->i_ctrl_cyc_stb = 0;
 
		while((errcount++ <  BOMBCOUNT)&&(!m_core->o_rtn_ack)) {
			tick();
		}
 
 
		result = m_core->o_rtn_data;
		assert(!m_core->o_rtn_err);
		assert(!m_core->o_rtn_miss);
 
		if(errcount >= BOMBCOUNT) {
			printf("SETTING ERR TO TRUE!!!!! (BOMB)\n");
			m_bomb = true;
		} else if (!m_core->o_rtn_ack) {
			printf("SETTING ERR TO TRUE--NO ACK, NO TIMEOUT\n");
			m_bomb = true;
		}
		tick();
 
		assert(!m_core->o_rtn_ack);
		assert(!m_core->o_rtn_miss);
		assert(!m_core->o_rtn_err);
		assert(!m_core->o_rtn_stall);
 
		return result;
	}
 
	void setup_write(unsigned a, unsigned v) {
		int		errcount = 0;
		m_miss = false; m_err = false;
 
		printf("WB-WRITES(%08x,%08x)\n", a,v);
 
		m_core->i_ctrl_cyc_stb = 1;
		m_core->i_wbm_cyc = 0;
		m_core->i_wbm_stb = 0;
		m_core->i_wb_we  = 1;
		m_core->i_wb_addr= a;
		m_core->i_wb_data= v;
 
		if (a & 0x080)
			m_last_tlb_index = (a>>1)&0x3f;
 
		if (m_core->o_rtn_stall) {
			while((errcount++ < BOMBCOUNT)&&(m_core->o_rtn_stall))
				tick();
		} tick();
 
		m_core->i_ctrl_cyc_stb = 0;
 
		while((errcount++ <  BOMBCOUNT)&&(!m_core->o_rtn_ack)) {
			tick();
		}
 
 
		assert(!m_core->o_rtn_err);
		assert(!m_core->o_rtn_miss);
 
		if(errcount >= BOMBCOUNT) {
			printf("SETTING ERR TO TRUE!!!!! (BOMB)\n");
			m_bomb = true;
		} else if (!m_core->o_rtn_ack) {
			printf("SETTING ERR TO TRUE--NO ACK, NO TIMEOUT\n");
			m_bomb = true;
		}
		tick();
 
		assert(!m_core->o_rtn_ack);
		assert(!m_core->o_rtn_miss);
		assert(!m_core->o_rtn_err);
		assert(!m_core->o_rtn_stall);
	}
 
	unsigned wb_read(unsigned a, bool *err) {
		int		errcount = 0;
		unsigned	result;
		if (err)	*err = false;
 
		printf("WB-READM(%08x)\n", a);
 
		m_core->i_ctrl_cyc_stb = 0;
		m_core->i_wbm_cyc = 1;
		m_core->i_wbm_stb = 1;
		m_core->i_wb_we  = 0;
		m_core->i_wb_addr= a;
 
		if (m_core->o_rtn_stall) {
			while((errcount++ < BOMBCOUNT)&&(m_core->o_rtn_stall)) {
				tick();
				if ((err)&&((m_core->o_rtn_err)||(m_core->o_rtn_miss))) {
					if (!*err) {
						m_miss = (m_core->o_rtn_miss);
						m_err  = (m_core->o_rtn_err);
					} *err = true;
					m_core->i_ctrl_cyc_stb = 0;
					m_core->i_wbm_cyc = 0;
					m_core->i_wbm_stb = 0;
					tick();
					return 0;
				}
			}
		} tick();
 
		m_core->i_wbm_stb = 0;
 
		while((errcount++ <  BOMBCOUNT)&&(!m_core->o_rtn_ack)) {
			tick();
			if ((err)&&((m_core->o_rtn_err)||(m_core->o_rtn_miss))) {
				if (!*err) {
					m_miss = (m_core->o_rtn_miss);
					m_err  = (m_core->o_rtn_err);
				} *err = true;
				m_core->i_ctrl_cyc_stb = 0;
				m_core->i_wbm_cyc = 0;
					m_core->i_wbm_stb = 0;
				tick();
				return 0;
			}
		}
 
 
		result = m_core->o_rtn_data;
		assert(!m_core->o_rtn_err);
		assert(!m_core->o_rtn_miss);
 
		// Release the bus?
		m_core->i_wbm_cyc = 0;
		m_core->i_wbm_stb = 0;
 
		if(errcount >= BOMBCOUNT) {
			printf("SETTING ERR TO TRUE!!!!! (BOMB)\n");
			m_bomb = true;
		} else if (!m_core->o_rtn_ack) {
			printf("SETTING ERR TO TRUE--NO ACK, NO TIMEOUT\n");
			m_bomb = true;
		}
		tick();
 
		assert(!m_core->o_rtn_ack);
		assert(!m_core->o_rtn_miss);
		assert(!m_core->o_rtn_err);
		assert(!m_core->o_rtn_stall);
 
		return result;
	}
 
	void	wb_read(unsigned a, int len, unsigned *buf, bool *err) {
		int		errcount = 0;
		int		THISBOMBCOUNT = BOMBCOUNT * len;
		int		cnt, rdidx, inc;
 
		if (err)	*err = false;
		printf("WB-READM(%08x, %d)\n", a, len);
 
		while((errcount++ < BOMBCOUNT)&&(m_core->o_rtn_stall))
			wb_tick();
 
		if (errcount >= BOMBCOUNT) {
			printf("WB-READ(%d): Setting bomb to true (errcount = %d)\n", __LINE__, errcount);
			m_bomb = true;
			return;
		}
 
		errcount = 0;
 
		m_core->i_ctrl_cyc_stb = 0;
		m_core->i_wbm_cyc = 1;
		m_core->i_wbm_stb = 1;
		m_core->i_wb_we   = 0;
		m_core->i_wb_addr = a;
 
		rdidx =0; cnt = 0;
		inc = 1;
 
		do {
			int	s;
			s = (m_core->o_rtn_stall==0)?0:1;
			tick();
			if (!s)
				m_core->i_wb_addr += inc;
			cnt += (s==0)?1:0;
			if (m_core->o_rtn_ack)
				buf[rdidx++] = m_core->o_rtn_data;
			if ((err)&&((m_core->o_rtn_err)||(m_core->o_rtn_miss))) {
				if (!*err) {
					m_miss = (m_core->o_rtn_miss);
					m_err  = (m_core->o_rtn_err);
				} *err = true;
				m_core->i_ctrl_cyc_stb = 0;
				m_core->i_wbm_cyc = 0;
					m_core->i_wbm_stb = 0;
				tick();
				return;
			}
		} while((cnt < len)&&(errcount++ < THISBOMBCOUNT));
 
		m_core->i_wbm_stb = 0;
 
		while((rdidx < len)&&(errcount++ < THISBOMBCOUNT)) {
			tick();
			if ((err)&&((m_core->o_rtn_err)||(m_core->o_rtn_miss))) {
				if (!*err) {
					m_miss = (m_core->o_rtn_miss);
					m_err  = (m_core->o_rtn_err);
				} *err = true;
				m_core->i_ctrl_cyc_stb = 0;
				m_core->i_wbm_cyc = 0;
					m_core->i_wbm_stb = 0;
				tick();
				return;
			}
			if (m_core->o_rtn_ack)
				buf[rdidx++] = m_core->o_rtn_data;
		}
 
		// Release the bus?
		m_core->i_wbm_cyc = 0;
 
		if(errcount >= THISBOMBCOUNT) {
			printf("SETTING ERR TO TRUE!!!!! (errcount=%08x, THISBOMBCOUNT=%08x)\n", errcount, THISBOMBCOUNT);
			m_bomb = true;
		} else if (!m_core->o_rtn_ack) {
			printf("SETTING ERR TO TRUE--NO ACK, NO TIMEOUT\n");
			m_bomb = true;
		}
		tick();
		assert(!m_core->o_rtn_ack);
		assert(!m_core->o_rtn_miss);
		assert(!m_core->o_rtn_err);
		assert(!m_core->o_rtn_stall);
	}
 
	void	wb_write(unsigned a, unsigned v, bool *err) {
		int errcount = 0;
 
		if (err)	*err = false;
		printf("WB-WRITEM(%08x) <= %08x\n", a, v);
		m_core->i_ctrl_cyc_stb = 0;
		m_core->i_wbm_cyc = 1;
		m_core->i_wbm_stb = 1;
		m_core->i_wb_we  = 1;
		m_core->i_wb_addr= a;
		m_core->i_wb_data= v;
 
		if (m_core->o_rtn_stall)
			while((errcount++ < BOMBCOUNT)&&(m_core->o_rtn_stall)) {
				printf("Stalled, so waiting, errcount=%d\n", errcount);
				tick();
				if ((err)&&((m_core->o_rtn_miss)||(m_core->o_rtn_err))) {
					if (!*err) {
						m_miss = (m_core->o_rtn_miss);
						m_err  = (m_core->o_rtn_err);
					} *err = true;
					m_core->i_wbm_cyc = 0;
					m_core->i_wbm_stb = 0;
					tick();
					return;
				}
			}
		tick();
		if ((err)&&((m_core->o_rtn_miss)||(m_core->o_rtn_err))) {
			if (!*err) {
				m_miss = (m_core->o_rtn_miss);
				m_err  = (m_core->o_rtn_err);
			} *err = true;
			m_core->i_wbm_cyc = 0;
			m_core->i_wbm_stb = 0;
			tick();
			return;
		}
 
		m_core->i_wbm_stb = 0;
 
		while((errcount++ <  BOMBCOUNT)&&(!m_core->o_rtn_ack)) {
			tick();
			if ((err)&&((m_core->o_rtn_miss)||(m_core->o_rtn_err))) {
				if (!*err) {
					m_miss = (m_core->o_rtn_miss);
					m_err  = (m_core->o_rtn_err);
				} *err = true;
				m_core->i_wbm_cyc = 0;
				m_core->i_wbm_stb = 0;
				tick();
				return;
			}
		} tick();
		if ((err)&&((m_core->o_rtn_miss)||(m_core->o_rtn_err))) {
			if (!*err) {
				m_miss = (m_core->o_rtn_miss);
				m_err  = (m_core->o_rtn_err);
			} *err = true;
			m_core->i_wbm_cyc = 0;
			m_core->i_wbm_stb = 0;
			tick();
			return;
		}
 
		// Release the bus?
		m_core->i_ctrl_cyc_stb = 0;
		m_core->i_wbm_cyc = 0;
		m_core->i_wbm_stb = 0;
 
		if(errcount >= BOMBCOUNT) {
			printf("SETTING ERR TO TRUE!!!!! (BOMB) (LINE=%d, count=%d)\n",__LINE__, errcount);
			m_bomb = true;
		} tick();
		assert(!m_core->o_rtn_ack);
		assert(!m_core->o_rtn_miss);
		assert(!m_core->o_rtn_err);
		assert(!m_core->o_rtn_stall);
	}
 
	void	wb_write(unsigned a, unsigned int ln, unsigned *buf, bool *err) {
		unsigned errcount = 0, nacks = 0;
		if (err)	*err = false;
 
		printf("WB-WRITEM(%08x, %d, ...)\n", a, ln);
		m_core->i_ctrl_cyc_stb = 0;
		m_core->i_wbm_cyc = 1;
		m_core->i_wbm_stb = 1;
		m_core->i_wb_we  = 1;
		for(unsigned stbcnt=0; stbcnt<ln; stbcnt++) {
			m_core->i_wb_addr= a+stbcnt;
			m_core->i_wb_data= buf[stbcnt];
			errcount = 0;
 
			while((errcount++ < BOMBCOUNT)&&(m_core->o_rtn_stall)) {
				tick();
				if ((err)&&((m_core->o_rtn_miss)||(m_core->o_rtn_err))) {
					if (!*err) {
						m_miss = (m_core->o_rtn_miss);
						m_err  = (m_core->o_rtn_err);
					} *err = true;
					m_core->i_wbm_cyc = 0;
					m_core->i_wbm_stb = 0;
					tick();
					return;
				}
				if (m_core->o_rtn_ack) nacks++;
			}
			// Tick, now that we're not stalled.  This is the tick
			// that gets accepted.
			tick(); if (m_core->o_rtn_ack) nacks++;
			if ((err)&&((m_core->o_rtn_miss)||(m_core->o_rtn_err))) {
				if (!*err) {
					m_miss = (m_core->o_rtn_miss);
					m_err  = (m_core->o_rtn_err);
				} *err = true;
				m_core->i_wbm_cyc = 0;
				m_core->i_wbm_stb = 0;
				tick();
				return;
			}
		}
 
		m_core->i_wbm_stb = 0;
 
		errcount = 0;
		while((nacks < ln)&&(errcount++ < BOMBCOUNT)) {
			tick();
			if (m_core->o_rtn_ack) {
				nacks++;
				errcount = 0;
			}
			if ((err)&&((m_core->o_rtn_miss)||(m_core->o_rtn_err))) {
				if (!*err) {
					m_miss = (m_core->o_rtn_miss);
					m_err  = (m_core->o_rtn_err);
				} *err = true;
				m_core->i_wbm_cyc = 0;
				m_core->i_wbm_stb = 0;
				tick();
				return;
			}
		}
 
		// Release the bus
		m_core->i_wbm_cyc = 0;
		m_core->i_wbm_stb = 0;
 
		if(errcount >= BOMBCOUNT) {
			printf("SETTING ERR TO TRUE!!!!! (BOMB)\n");
			m_bomb = true;
		} tick();
		assert(!m_core->o_rtn_ack);
		assert(!m_core->o_rtn_miss);
		assert(!m_core->o_rtn_err);
		assert(!m_core->o_rtn_stall);
	}
 
	bool	miss(void) {
		return m_miss;
	} bool	err(void) {
		return m_err;
	}
 
	bool	bombed(void) const { return m_bomb; }
 
	bool	debug(void) const { return m_debug; }
	bool	debug(bool nxtv) { return m_debug = nxtv; }
};
 
void	uload(unsigned len, unsigned *buf) {
	FILE	*fp = fopen("/dev/urandom", "r");
 
	if ((NULL == fp)||(len != fread(buf, sizeof(unsigned), len, fp))) {
		for(int i=0; i<(int)len; i++)
			buf[i] = ((unsigned)rand());
	} if (NULL == fp)
		fclose(fp);
}
 
void	install_page(ZIPMMU_TB *tb, int idx, unsigned va, unsigned pa, int flags) {
	int	LGTBL, LGPGSZ, LGCTXT;
	int	c;
	unsigned base;
	bool	hdebug = tb->debug();
 
	tb->debug(false);
	c=tb->setup_read(0);
	printf("CONTEXT-REG = %08x\n", c);
	LGTBL  = ((c>>24)&15);
	LGPGSZ= (((c>>20)&15)+8)&31;
	LGCTXT= (((c>>16)&15)+1)&31;
	c &= ((1<<LGCTXT)-1);
	base  = (2<<LGTBL)+(idx<<1);
	va &= -(1<<LGPGSZ);
	pa &= -(1<<LGPGSZ);
 
	printf("INSTALL[%2d] %04x:%08xV -> %08xP %s%s\n",
		idx, c, va, pa,
		(flags&MMUFLAG_RONW)?"RO":"  ",
		(flags&MMUFLAG_CCHE)?"Cachable":"");
	tb->setup_write(base  , va|(( c    &0x0ff)<<4)|flags);
	tb->setup_write(base+1, pa|(((c>>8)&0x0ff)<<4)|flags);
	tb->debug(hdebug);
}
 
int main(int  argc, char **argv) {
	Verilated::commandArgs(argc, argv);
	ZIPMMU_TB	*tb = new ZIPMMU_TB;
	unsigned 	*rdbuf; // *mbuf;
	unsigned	mlen = (1<<LGMEMSIZE), c, blen;
 
	tb->opentrace("zipmmu_tb.vcd");
	printf("Giving the core 2 cycles to start up\n");
	// Before testing, let's give the unit time enough to warm up
	tb->reset();
	for(int i=0; i<2; i++)
		tb->wb_tick();
 
	mlen = 1<<16;
 
	printf("Getting some memory ...\n");
	rdbuf = new unsigned[mlen];
	// mbuf  = new unsigned[mlen]; // Match buffer
	printf("Charging my memory with random values\n");
	uload(mlen, rdbuf);
 
 
	int	LGADR, LGTBL, LGPGSZ, LGCTXT, sr;
 
	c=tb->setup_read(0);
	printf("CONTROL-REG = %08x\n = %2d\n", c, c);
	sr = tb->setup_read(1);
	printf("STATUS-REG  = %08x = %2d\n", sr, sr);
	LGADR = (((c>>28)&15)+17)&31;
	LGTBL = ((c>>24)&15);
	LGPGSZ= (((c>>20)&15)+8)&31;
	LGCTXT= (((c>>16)&15)+1)&31;
	printf("LGADR       = %08x = %2d\n", LGADR, LGADR);
	printf("LGTBL       = %08x = %2d\n", LGTBL, LGTBL);
	printf("LGPGSZ      = %08x = %2d\n", LGPGSZ, LGPGSZ);
	printf("LGCTXT      = %08x = %2d\n", LGCTXT, LGCTXT);
 
	// First, let's make sure we can read/write the context
	printf("\n\nTest: Can we read/write the context register?\n");
	tb->setup_write(0,0x01fec);
	c=tb->setup_read(0);
	printf("CONTEXT     = %08x (0x1fec?)\n", c&0x0ffff);
	if ((c&0x0ffff) != 0x01fec)
		goto test_failure;
 
	// Load the table with TLB misses
	printf("\n\nTest: Can we load the table with TLB misses? (%d entries)\n", (1<<LGTBL));
	for(int i=0; i<(1<<LGTBL); i++) {
		c = 0x0f70; // Context: 0xfef7
		tb->setup_write((2<<LGTBL)+(i<<1)  , c+(((1<<LGTBL)-1-i)<<LGPGSZ));
		c = 0x0fe2; // CCHE flag only
		tb->setup_write((2<<LGTBL)+(i<<1)+1, c+(((1<<LGTBL)-1-i)<<LGPGSZ));
	}
 
	// Dump the table, make sure we got it right
	for(int i=0; i<(1<<LGTBL); i++) {
		unsigned v, p;
		v=tb->setup_read((2<<LGTBL)+(i<<1)  );
		p=tb->setup_read((2<<LGTBL)+(i<<1)+1);
 
		printf("TBL[%2d] = %08x -> %08x\n", i, v, p);
		if (v != (unsigned)(0x00f72+(((1<<LGTBL)-1-i)<<LGPGSZ)))
			goto test_failure;
		if (p != (unsigned)(0x00fe2+(((1<<LGTBL)-1-i)<<LGPGSZ)))
			goto test_failure;
	}
 
	// Now, let's create a fictitious process, context 1, with no pages.
	// See what happens when we try to access his stack at 0xffffffff
	bool	tberr;
	printf("\n\nTest: Do we get a TLB miss when attempting to find a non-existent page?\n");
	tberr = false;
	tb->wb_write(0xffffffff, 0x0fe, &tberr);
	if ((!tberr)||(!tb->miss())||(tb->err())) {
		printf("TBERR = %s\nMISS  = %s\nERR   = %s\n",
			(tberr)?"true":"false", (tb->miss())?"true":"false",
			(tb->err())?"true":"false");
		goto test_failure;
	}
 
	tberr = false;
	install_page(tb, 0, 0x0ffffffff, (1<<LGMEMSIZE)+0*(1<<LGPGSZ),
			MMUFLAG_RONW);
	printf("\n\nTest: Do we get a TLB miss when attempting to write a RO page?\n");
	tb->wb_write(0xffffffff, 0x0fe, &tberr);
	if ((!tberr)||(!tb->miss())||(tb->err())) {
		printf("TBERR = %s\nMISS  = %s\nERR   = %s\n",
			(tberr)?"true":"false", (tb->miss())?"true":"false",
			(tb->err())?"true":"false");
		goto test_failure;
	}
 
	tberr = false;
	printf("\n\nTest: What if we make this into a writeable page?\n");
	install_page(tb, 0, 0xffffffff, (1<<LGMEMSIZE)+0*(1<<LGPGSZ), 0);
	tb->wb_write(0xffffffff, 0x0fe, &tberr);
	if (tberr) {
		printf("TBERR = %s\nMISS  = %s\nERR   = %s\n",
			(tberr)?"true":"false", (tb->miss())?"true":"false",
			(tb->err())?"true":"false");
		goto test_failure;
	}
	printf("\n\nTest: Is the next access done w/in a single clock?\n");
	tb->wb_write(0xfffffff7, 0xdeadbeef, &tberr);
	if (tberr) {
		printf("TBERR = %s\nMISS  = %s\nERR   = %s\n",
			(tberr)?"true":"false", (tb->miss())?"true":"false",
			(tb->err())?"true":"false");
		goto test_failure;
	}
 
 
	tberr = false;
	printf("\n\nTest: What if we make this into a writeable page?\n");
	install_page(tb, 0, 0xffffffff, (1<<LGMEMSIZE)+0*(1<<LGPGSZ), 0);
	tb->wb_write(0xffffffff, 0x0fe, &tberr);
	if ((tberr)||((*tb)[0x0fff]!=0x0fe)) {
		unsigned v;
		v = ((*tb)[0x0fff]!=0x0fe);
		printf("V     = 0x%08x (!= 0x0fe?)\nTBERR = %s\nMISS  = %s\nERR   = %s\n",
			v, (tberr)?"true":"false", (tb->miss())?"true":"false",
			(tb->err())?"true":"false");
		goto test_failure;
	}
 
	tberr = false;
	printf("\n\nTest: How about a read from the same location?\n");
	{
		unsigned	v;
		v = tb->wb_read(0xffffffff, &tberr);
		if ((tberr)||(v != 0x0fe)) {
			printf("V     = 0x%08x (!= 0x0fe?)\nTBERR = %s\nMISS  = %s\nERR   = %s\n",
				v,
				(tberr)?"true":"false", (tb->miss())?"true":"false",
				(tb->err())?"true":"false");
			goto test_failure;
		}
	}
 
	printf("Test: Burst write, within page\n");
	tb->setup_write(0, 0x0dad);
	install_page(tb, 0, ((0x0ffffffffl)&(-(1l<<LGPGSZ)))-2*(1<<LGPGSZ), (1<<LGMEMSIZE)+0*(1<<LGPGSZ), 0);
	install_page(tb, 1, ((0x0ffffffffl)&(-(1l<<LGPGSZ)))-1*(1<<LGPGSZ), (1<<LGMEMSIZE)+1*(1<<LGPGSZ), 0);
	install_page(tb, 2, ((0x0ffffffffl)&(-(1l<<LGPGSZ)))+0*(1<<LGPGSZ), (1<<LGMEMSIZE)+2*(1<<LGPGSZ), 0);
 
	tberr = false;
	blen = (1<<(LGPGSZ-2));
	tb->wb_write(((0xffffffff)&(-(1l<<LGPGSZ)))-2*(1<<LGPGSZ), blen, rdbuf, &tberr);
	if (tberr) {
		printf("TBERR = %s\nMISS  = %s\nERR   = %s\n",
			(tberr)?"true":"false", (tb->miss())?"true":"false",
			(tb->err())?"true":"false");
		printf("STATUS= %08x\n", tb->setup_read(1));
		goto test_failure;
	} for(unsigned i=0; i<blen; i++) {
		if ((*tb)[i] != rdbuf[i]) {
			printf("MEM[%04x] = %08x (!= %08x as expected)\n",
				i, (*tb)[i], rdbuf[i]);
			goto test_failure;
		}
	}
 
	printf("Test: Burst read\n");
	// Try somewhere within that last page
	tberr = false;
	tb->wb_read(((0xffffffff)&(-(1<<LGPGSZ)))-2*(1<<LGPGSZ)+18, blen, rdbuf, &tberr);
	if (tberr) {
		printf("TBERR = %s\nMISS  = %s\nERR   = %s\n",
			(tberr)?"true":"false", (tb->miss())?"true":"false",
			(tb->err())?"true":"false");
		printf("STATUS= %08x\n", tb->setup_read(1));
		goto test_failure;
	} for(unsigned i=0; i<blen; i++) {
		if ((*tb)[i+18] != rdbuf[i]) {
			printf("MEM[%04x] = %08x (!= %08x as expected)\n",
				i+18, (*tb)[i+18], rdbuf[i]);
			goto test_failure;
		}
	}
 
 
	printf("Tests not (yet) implemented\n");
	printf("Test: Burst read crossing pages, second page valid\n");
	printf("Test: Burst read crossing pages, second page invalid\n");
 
	printf("SUCCESS!!\n");
	exit(0);
test_failure:
	printf("FAIL-HERE\n");
	for(int i=0; i<4; i++)
		tb->tick();
	printf("TEST FAILED\n");
	exit(-1);
}
 

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.