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

Subversion Repositories zipcpu

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

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.
//
// 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 <verilated.h>
#include <verilated_vcd_c.h>
#include "testb.h"
#include "Vzipmmu_tb.h"
 
#define	MMUFLAG_RONW	8 // Read only (not writeable)
#define	MMUFLAG_EXE	4 // Page may be executed
#define	MMUFLAG_CCHE	2 // Cachable
#define	MMUFLAG_ACCS	1 // Accessed
#define	ROFLAG	8	// This page is read-only
#define	EXFLAG	4	// This page is executable
#define	CHFLAG	2	// This page may be cached
#define	AXFLAG	1	// This page has been accessed since loading
 
#define	setup_stb	i_ctrl_cyc_stb
#define	setup_ack	o_rtn_ack
#define	setup_stall	o_rtn_stall
#define	setup_data	o_rtn_data
#define	mem_cyc		v__DOT__mem_cyc
#define	mem_stb		v__DOT__mem_stb
#define	mem_we		v__DOT__mem_we
#define	mem_r_we	v__DOT__mut__DOT__r_we
#define	mem_r_valid	v__DOT__mut__DOT__r_valid
#define	mem_addr	v__DOT__mem_addr
#define	mem_err		v__DOT__mem_err
#define	wr_vtable	v__DOT__mut__DOT__wr_vtable
#define	wr_ptable	v__DOT__mut__DOT__wr_ptable
#define	wr_control	v__DOT__mut__DOT__wr_control
#define	z_context	__PVT__mut__DOT__z_context
#define	context_word	v__DOT__mut__DOT__r_context_word
#define	r_pending	v__DOT__mut__DOT__r_pending
#define	r_we		v__DOT__mut__DOT__r_we
#define	r_valid		v__DOT__mut__DOT__r_valid
#define	r_addr		v__DOT__mut__DOT__r_addr
#define	r_data		v__DOT__mut__DOT__r_data
 
#define	R_CONTROL		0
#define	R_STATUS		4
#define	R_TABLESZ(LGSZ)		(8<<LGSZ)
#define	R_ENTRYSZ(LGSZ,K)	(R_TABLESZ(LGSZ)+(K<<3))
#define	R_TABLE		(8<<LGTBL)
#define	R_VENTRY(K)	((8<<LGTBL)+(K<<3))
#define	R_PENTRY(K)	(R_VENTRY(K)+4)
#define	LOCONTEXT(C)	((C<<4)&((1<<LGPGSZ)-1))
#define	HICONTEXT(C)	(((C>>(LGPGSZ-4))<<4)&((1<<LGPGSZ)-1))
 
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;
	}
 
	void	tick(void) {
 
		TESTB<Vzipmmu_tb>::tick();
 
		bool	writeout = true;
 
		if ((m_debug)&&(writeout)) {
			printf("%08lx-MMU: ", m_tickcount);
			printf("(%s%s%s%s%s%s) %08x (%s%s%s)%08x%s %s %08x/%08x %s%s%s%s",
				(m_core->setup_stb)?"CT":"  ",
				(m_core->i_wbm_cyc)?"CYC":"   ",
				(m_core->i_wbm_stb)?"STB":"   ",
				(m_core->i_wb_we)?"WE":"  ",
				(m_core->i_gie)?"IE":"  ",
				(m_core->i_exe)?"EX":"  ",
				(m_core->i_wb_addr),
				(m_core->mem_cyc)?"CYC":"   ",
				(m_core->mem_stb)?"STB":"   ",
				(m_core->mem_we)?"WE":"  ",
				(m_core->mem_addr),
				(m_core->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->mem_we)?m_core->r_data:m_core->v__DOT__mem_odata,
				(m_core->o_rtn_stall)?"STALL":"     ",
				(m_core->o_rtn_ack )?"ACK":"   ",
				(m_core->o_rtn_miss)?"MISS":"    ",
				(m_core->o_rtn_err )?"ERR":"   ");
 
			printf("[%c]",
				(m_core->wr_control)?'C'
				:(m_core->wr_vtable)?'V'
				:(m_core->wr_ptable)?'P'
				:'-');
			printf("[%c,%04x]",
				(m_core->v__DOT__mut__DOT__kernel_context)?'K'
				:(m_core->v__DOT__mut__DOT__z_context)?'Z':'-',
				m_core->v__DOT__mut__DOT__r_context_word);
			printf(" %s[%s%s@%08x,%08x]",
				(m_core->r_pending)?"R":" ",
				(m_core->r_we)?"W":" ",
				(m_core->r_valid)?"V":" ",
				(m_core->r_addr),
				(m_core->r_data));
			printf("@%2x[%s%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__exe_miss)?"EX":"  ",
				(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%c] = 0x%03x, V=0x%03x, C=0x%04x, CTXT=%04x",
				m_last_tlb_index,
				((m_core->v__DOT__mut__DOT__tlb_valid>>m_last_tlb_index)&1)?'V':'u',
				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_reset    = 1;
		m_core->i_ctrl_cyc_stb = 0;
		m_core->i_gie      = 0;
		m_core->i_exe      = 0;
		m_core->i_wbm_cyc  = 0;
		m_core->i_wbm_stb  = 0;
		tick();
		m_core->i_reset  = 0;
	}
 
	void wb_tick(void) {
		m_core->i_reset  = 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) {
		unsigned	msk = (1<<LGMEMSIZE)-1;
// printf("OP[] Reading from %08x\n", a);
		assert((a&3)==0);
		a = (a>>2)&(msk);
// printf("OP[] ----> %08x\n", a);
		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 = 0;
		m_core->i_wbm_cyc = 0;
		m_core->i_wbm_stb = 0;
		m_core->i_wb_we  = 0;
		m_core->i_wb_addr= a>>2;
 
		if (m_core->i_gie) {
			m_core->i_gie = 0;
			wb_tick();
		}
 
		m_core->i_ctrl_cyc_stb = 1;
 
		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 = 0;
		m_core->i_exe = 0;
		m_core->i_wbm_cyc = 0;
		m_core->i_wbm_stb = 0;
		m_core->i_wb_we  = 1;
		m_core->i_wb_addr= a>>2;
		m_core->i_wb_data= v;
		m_core->i_wb_sel= 15;
 
		if (m_core->i_gie) {
			m_core->i_gie = 0;
			wb_tick();
		}
		m_core->i_ctrl_cyc_stb = 1;
 
 
		if (a & 0x0200)
			m_last_tlb_index = (a>>3)&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>>2;
 
		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>>2;
 
		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>>2;
		m_core->i_wb_data= v;
		m_core->i_wb_sel= 15;
 
		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;
		m_core->i_wb_sel= 15;
		for(unsigned stbcnt=0; stbcnt<ln; stbcnt++) {
			m_core->i_wb_addr= (a>>2)+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(R_CONTROL);
	printf("CONTEXT-REG = %08x\n", c);
	LGTBL  = ((c>>24)&15);
	LGPGSZ= (((c>>20)&15)+10)&31;	// In bytes
	LGCTXT= (((c>>16)&15)+1)&31;
	c &= ((1<<LGCTXT)-1);
	base  = R_ENTRYSZ(LGTBL, idx);
	va &= -(1<<LGPGSZ);
	pa &= -(1<<LGPGSZ);
 
	printf("INSTALL[%2d] %04x:%03x[%04x]%xV -> %03x[%04x]%xP %s%s\n",
		idx, c,
		(va>>LGPGSZ), LOCONTEXT(c)>>4, flags,
		(pa>>LGPGSZ), HICONTEXT(c)>>4, 0,
		(flags&MMUFLAG_RONW)?"RO":"  ",
		(flags&MMUFLAG_CCHE)?"Cachable":"");
	tb->setup_write(base  , va|(LOCONTEXT(c))|flags);
	tb->setup_write(base+4, pa|(HICONTEXT(c)));
	// tb->debug(hdebug);
	tb->tick();
	tb->m_core->i_gie = 1;
}
 
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;
	const unsigned	CONTEXT = 0x0fef7;
 
	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, PAGESZ;
 
	c=tb->setup_read(R_CONTROL);
	printf("CONTROL-REG = %08x\n = %2d\n", c, c);
	sr = tb->setup_read(R_STATUS);
	printf("STATUS-REG  = %08x = %2d\n", sr, sr);
	LGADR = (((c>>28)&15)+17)&31;
	LGTBL = ((c>>24)&15);
	LGPGSZ= (((c>>20)&15)+10)&31;
	PAGESZ= 1ul<<LGPGSZ;
	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);
	printf("PAGESZ      = %08x = %2d\n", PAGESZ, PAGESZ);
 
	// 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(R_CONTROL,CONTEXT);
	c=tb->setup_read(R_CONTROL);
	printf("CONTEXT     = %04x (0x%04x)\n", c &0x0ffff, CONTEXT & 0x0ffff);
	if ((c&0x0ffff) != CONTEXT)
		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 = CONTEXT; // Context: 0xfef7, no flags
		tb->setup_write(R_VENTRY(i), (LOCONTEXT(c))
			|(((1<<LGTBL)-1-i)<<LGPGSZ) | ROFLAG);
		tb->setup_write(R_PENTRY(i), (HICONTEXT(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, c;
 
		c = 0x0fef7;
		v=tb->setup_read(R_VENTRY(i));
		p=tb->setup_read(R_PENTRY(i));
 
		printf("TBL[%2d] = %08x -> %08x", i, v, p);
		printf("\tEXPECTING %08x -> %08x\n",
			(unsigned)((LOCONTEXT(c))|(((1<<LGTBL)-1-i)<<LGPGSZ)|ROFLAG),
			(unsigned)(HICONTEXT(c))|(((1<<LGTBL)-1-i)<<LGPGSZ));
		if (v != (unsigned)((LOCONTEXT(c))|(((1<<LGTBL)-1-i)<<LGPGSZ)|ROFLAG))
			goto test_failure;
		if (p != (unsigned)((HICONTEXT(c))|(((1<<LGTBL)-1-i)<<LGPGSZ)))
			goto test_failure;
	} printf("-- PASS\n\n");
 
	// 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");
	tb->m_core->i_gie = 1;
	tb->tick();
	tberr = false;
	tb->wb_write(0xfffffffc, 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;
	} printf("-- PASS\n\n");
 
	tberr = false;
	install_page(tb, 0, 0xfffffffc, (4<<LGMEMSIZE)+0*PAGESZ,
			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;
	} printf("-- PASS\n\n");
 
	tberr = false;
	printf("\n\nTest: What if we make this into a writeable page?\n");
	install_page(tb, 0, 0xfffffffc, (4<<LGMEMSIZE)+0*PAGESZ, 0);
	tb->m_core->i_gie = 1;
	tb->m_core->i_exe = 0;
	tb->wb_write(0xfffffff8, 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("-- PASS\n\n");
	printf("\n\nTest: Is the next access done w/in a single clock?\n");
	tb->wb_write(0xfffffffc, 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;
	} printf("-- PASS\n\n");
 
 
	tberr = false;
	printf("\n\nTest: What if we make this into a writeable page?\n");
	install_page(tb, 0, 0xffffffff, (4<<LGMEMSIZE)+0*PAGESZ, 0);
	tb->wb_write(0xfffffffc, 0x0fe, &tberr);
	if ((tberr)||((*tb)[0x0ffc]!=0x0fe)) {
		unsigned v;
		v = ((*tb)[0x0ffc]!=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("-- PASS\n\n");
 
	tberr = false;
	printf("\n\nTest: How about a read from the same location?\n");
	{
		unsigned	v;
		v = tb->wb_read(0xfffffffc, &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("-- PASS\n\n");
 
	printf("Test: Burst write, within page (PAGESZ = %04x)\n", PAGESZ);
	tb->setup_write(R_CONTROL, 0x0dad);
#define	TEST_VPAGE	((0x0ffffffffl)&(-(1l<<LGPGSZ)))
	install_page(tb, 0, TEST_VPAGE-2*PAGESZ, (4<<LGMEMSIZE)+0*PAGESZ, 0);
	install_page(tb, 1, TEST_VPAGE-1*PAGESZ, (4<<LGMEMSIZE)+1*PAGESZ, 0);
	install_page(tb, 2, TEST_VPAGE-0*PAGESZ, (4<<LGMEMSIZE)+2*PAGESZ, 0);
 
	tberr = false;
	blen = (1<<(LGPGSZ-2));
	tb->wb_write(TEST_VPAGE-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(R_STATUS));
		goto test_failure;
	} for(unsigned i=0; i<blen; i++) {
		if ((*tb)[i*4] != rdbuf[i]) {
			printf("MEM[%04x] = %08x (!= %08x as expected)\n",
				i, (*tb)[4*i], rdbuf[i]);
			goto test_failure;
		}
	} printf("-- PASS\n\n");
 
	printf("Test: Burst read\n");
	// Try somewhere within that last page
	tberr = false;
	tb->wb_read(TEST_VPAGE-2*(1<<LGPGSZ)+(18*4), 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(R_STATUS));
		goto test_failure;
	} for(unsigned i=0; i<blen; i++) {
		if ((*tb)[(i+18)*4] != rdbuf[i]) {
			printf("MEM[%04x] = %08x (!= %08x as expected)\n",
				i+18, (*tb)[i+18], rdbuf[i]);
			goto test_failure;
		}
	} printf("-- PASS\n\n");
 
 
	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);
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2021 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.