URL
https://opencores.org/ocsvn/wbscope/wbscope/trunk
Subversion Repositories wbscope
[/] [wbscope/] [trunk/] [bench/] [cpp/] [wb_tb.h] - Rev 13
Compare with Previous | Blame | View Log
//////////////////////////////////////////////////////////////////////////////// // // Filename: wb_tb.cpp // // Project: WBScope, a wishbone hosted scope // // Purpose: To provide a fairly generic interface wrapper to a wishbone bus, // that can then be used to create a test-bench class. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2015-2017, 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 <stdlib.h> #include <verilated.h> #include <verilated_vcd_c.h> #include "testb.h" #include "devbus.h" const int BOMBCOUNT = 32; template <class VA> class WB_TB : public TESTB<VA>, public DEVBUS { #ifdef WBERR bool m_buserr; #endif #ifdef INTERRUPTWIRE bool m_interrupt; #endif public: typedef uint32_t BUSW; bool m_bomb; WB_TB(void) { m_bomb = false; TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; #ifdef WBERR m_buserr = false; #endif #ifdef INTERRUPTWIRE m_interrupt = false; #endif } virtual void close(void) { TESTB<VA>::closetrace(); } virtual void kill(void) { close(); } #ifdef INTERRUPTWIRE virtual void tick(void) { TESTB<VA>::tick(); if (TESTB<VA>::m_core->INTERRUPTWIRE) m_interrupt = true; } #endif #define TICK this->tick void idle(const unsigned counts = 1) { TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; for(unsigned k=0; k<counts; k++) { this->tick(); assert(!TESTB<VA>::m_core->o_wb_ack); } } BUSW readio(BUSW a) { int errcount = 0; BUSW result; // printf("WB-READM(%08x)\n", a); TESTB<VA>::m_core->i_wb_cyc = 1; TESTB<VA>::m_core->i_wb_stb = 1; TESTB<VA>::m_core->i_wb_we = 0; TESTB<VA>::m_core->i_wb_addr= (a>>2); if (TESTB<VA>::m_core->o_wb_stall) { while((errcount++ < BOMBCOUNT)&&(TESTB<VA>::m_core->o_wb_stall)) { TICK(); #ifdef WBERR if (TESTB<VA>::m_core->WBERR) { m_buserr = true; TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; return -1; } #endif } } TICK(); TESTB<VA>::m_core->i_wb_stb = 0; while((errcount++ < BOMBCOUNT)&&(!TESTB<VA>::m_core->o_wb_ack)) { TICK(); #ifdef WBERR if (TESTB<VA>::m_core->WBERR) { m_buserr = true; TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; return -1; } #endif } result = TESTB<VA>::m_core->o_wb_data; // Release the bus TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; if(errcount >= BOMBCOUNT) { printf("WB/SR-BOMB: NO RESPONSE AFTER %d CLOCKS\n", errcount); m_bomb = true; } else if (!TESTB<VA>::m_core->o_wb_ack) { printf("WB/SR-BOMB: NO ACK, NO TIMEOUT\n"); m_bomb = true; } TICK(); assert(!TESTB<VA>::m_core->o_wb_ack); assert(!TESTB<VA>::m_core->o_wb_stall); return result; } void readv(const BUSW a, int len, BUSW *buf, const int inc=1) { int errcount = 0; int THISBOMBCOUNT = BOMBCOUNT * len; int cnt, rdidx; printf("WB-READM(%08x, %d)\n", a, len); TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; while((errcount++ < BOMBCOUNT)&&(TESTB<VA>::m_core->o_wb_stall)) TICK(); if (errcount >= BOMBCOUNT) { printf("WB-READ(%d): Setting bomb to true (errcount = %d)\n", __LINE__, errcount); m_bomb = true; return; } errcount = 0; TESTB<VA>::m_core->i_wb_cyc = 1; TESTB<VA>::m_core->i_wb_stb = 1; TESTB<VA>::m_core->i_wb_we = 0; TESTB<VA>::m_core->i_wb_addr = (a>>2); rdidx =0; cnt = 0; do { int s; TESTB<VA>::m_core->i_wb_stb = ((rand()&7)!=0) ? 1:0; s = ((TESTB<VA>::m_core->i_wb_stb) &&(TESTB<VA>::m_core->o_wb_stall==0))?0:1; TICK(); TESTB<VA>::m_core->i_wb_addr += (inc&(s^1))?4:0; cnt += (s^1); if (TESTB<VA>::m_core->o_wb_ack) buf[rdidx++] = TESTB<VA>::m_core->o_wb_data; #ifdef WBERR if (TESTB<VA>::m_core->WBERR) { m_buserr = true; TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; return -1; } #endif } while((cnt < len)&&(errcount++ < THISBOMBCOUNT)); TESTB<VA>::m_core->i_wb_stb = 0; while((rdidx < len)&&(errcount++ < THISBOMBCOUNT)) { TICK(); if (TESTB<VA>::m_core->o_wb_ack) buf[rdidx++] = TESTB<VA>::m_core->o_wb_data; #ifdef WBERR if (TESTB<VA>::m_core->WBERR) { m_buserr = true; TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; return -1; } #endif } // Release the bus TESTB<VA>::m_core->i_wb_cyc = 0; if(errcount >= THISBOMBCOUNT) { printf("WB/PR-BOMB: NO RESPONSE AFTER %d CLOCKS\n", errcount); m_bomb = true; } else if (!TESTB<VA>::m_core->o_wb_ack) { printf("WB/PR-BOMB: NO ACK, NO TIMEOUT\n"); m_bomb = true; } TICK(); assert(!TESTB<VA>::m_core->o_wb_ack); } void readi(const BUSW a, const int len, BUSW *buf) { return readv(a, len, buf, 1); } void readz(const BUSW a, const int len, BUSW *buf) { return readv(a, len, buf, 0); } void writeio(const BUSW a, const BUSW v) { int errcount = 0; printf("WB-WRITEM(%08x) <= %08x\n", a, v); TESTB<VA>::m_core->i_wb_cyc = 1; TESTB<VA>::m_core->i_wb_stb = 1; TESTB<VA>::m_core->i_wb_we = 1; TESTB<VA>::m_core->i_wb_addr= (a>>2); TESTB<VA>::m_core->i_wb_data= v; // TESTB<VA>::m_core->i_wb_sel = 0x0f; if (TESTB<VA>::m_core->o_wb_stall) while((errcount++ < BOMBCOUNT)&&(TESTB<VA>::m_core->o_wb_stall)) { printf("Stalled, so waiting, errcount=%d\n", errcount); TICK(); #ifdef WBERR if (m_core->WBERR) { m_buserr = true; TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; return; } #endif } TICK(); #ifdef WBERR if (m_core->WBERR) { m_buserr = true; TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; return; } #endif TESTB<VA>::m_core->i_wb_stb = 0; while((errcount++ < BOMBCOUNT)&&(!TESTB<VA>::m_core->o_wb_ack)) { TICK(); #ifdef WBERR if (m_core->WBERR) { m_buserr = true; TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; return; } #endif } TICK(); // Release the bus? TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; if(errcount >= BOMBCOUNT) { printf("WB/SW-BOMB: NO RESPONSE AFTER %d CLOCKS (LINE=%d)\n",errcount, __LINE__); m_bomb = true; } TICK(); #ifdef WBERR if (m_core->WBERR) { m_buserr = true; TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; return; } #endif assert(!TESTB<VA>::m_core->o_wb_ack); assert(!TESTB<VA>::m_core->o_wb_stall); } void writev(const BUSW a, const int ln, const BUSW *buf, const int inc=1) { unsigned errcount = 0, nacks = 0; printf("WB-WRITEM(%08x, %d, ...)\n", a, ln); TESTB<VA>::m_core->i_wb_cyc = 1; TESTB<VA>::m_core->i_wb_stb = 1; TESTB<VA>::m_core->i_wb_we = 1; TESTB<VA>::m_core->i_wb_addr= (a>>2); // TESTB<VA>::m_core->i_wb_sel = 0x0f; for(unsigned stbcnt=0; stbcnt<ln; stbcnt++) { // m_core->i_wb_addr= a+stbcnt; TESTB<VA>::m_core->i_wb_data= buf[stbcnt]; errcount = 0; while((errcount++ < BOMBCOUNT)&&(TESTB<VA>::m_core->o_wb_stall)) { TICK(); if (TESTB<VA>::m_core->o_wb_ack) nacks++; #ifdef WBERR if (m_core->WBERR) { m_buserr = true; TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; return; } #endif } // Tick, now that we're not stalled. This is the tick // that gets accepted. TICK(); if (TESTB<VA>::m_core->o_wb_ack) nacks++; #ifdef WBERR if (m_core->WBERR) { m_buserr = true; TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; return; } #endif // Now update the address TESTB<VA>::m_core->i_wb_addr += (inc)?4:0; } TESTB<VA>::m_core->i_wb_stb = 0; errcount = 0; while((nacks < ln)&&(errcount++ < BOMBCOUNT)) { TICK(); if (TESTB<VA>::m_core->o_wb_ack) { nacks++; errcount = 0; } #ifdef WBERR if (m_core->WBERR) { m_buserr = true; TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; return; } #endif } // Release the bus TESTB<VA>::m_core->i_wb_cyc = 0; TESTB<VA>::m_core->i_wb_stb = 0; if(errcount >= BOMBCOUNT) { printf("WB/PW-BOMB: NO RESPONSE AFTER %d CLOCKS (LINE=%d)\n",errcount,__LINE__); m_bomb = true; } TICK(); assert(!TESTB<VA>::m_core->o_wb_ack); assert(!TESTB<VA>::m_core->o_wb_stall); } void writei(const BUSW a, const int ln, const BUSW *buf) { writev(a, ln, buf, 1); } void writez(const BUSW a, const int ln, const BUSW *buf) { writev(a, ln, buf, 0); } bool bombed(void) const { return m_bomb; } // bool debug(void) const { return m_debug; } // bool debug(bool nxtv) { return m_debug = nxtv; } bool poll(void) { #ifdef INTERRUPTWIRE return (m_interrupt)||(TESTB<VA>::m_core->INTERRUPTWIRE != 0); #else return false; #endif } bool bus_err(void) const { #ifdef WBERR return m_buserr; #else return false; #endif } void reset_err(void) { #ifdef WBERR m_buserr = false;; #endif } void usleep(unsigned msec) { #ifdef CLKRATEHZ unsigned count = CLKRATEHZ / 1000 * msec; #else // Assume 100MHz if no clockrate is given unsigned count = 1000*100 * msec; #endif while(count-- != 0) #ifdef INTERRUPTWIRE if (poll()) return; else #endif TICK(); } void clear(void) { #ifdef INTERRUPTWIRE m_interrupt = false; #endif } void wait(void) { #ifdef INTERRUPTWIRE while(!poll()) TICK(); #else assert(("No interrupt defined",0)); #endif } };