URL
https://opencores.org/ocsvn/wbscope/wbscope/trunk
Subversion Repositories wbscope
Compare Revisions
- This comparison shows the changes necessary to convert path
/wbscope/trunk/bench
- from Rev 12 to Rev 13
- ↔ Reverse comparison
Rev 12 → Rev 13
/cpp/Makefile
1,11 → 1,30
################################################################################ |
## |
## Filename: |
## Filename: bench/cpp/Makefile |
## |
## Project: WBScope, a wishbone hosted scope |
## |
## Purpose: |
## Purpose: This file directs the build of a Verilator-based test bench to |
## prove that the wbscope and wbscopc work. This build must be |
## called after building in bench/rtl, since it depends upon the products |
## of that build. |
## |
## Targets: |
## |
## all: Builds both wbscope_tb and wbscopc_tb |
## |
## clean: Cleans up all of the build products, together with the .vcd |
## files, so you can start over from scratch. |
## |
## wbscope_tb: A test bench for the basic wishbone scope. |
## Prints success or failure on the last line. |
## |
## wbscopc_tb: A test bench for the compressed wishbone scope. |
## Prints success or failure on the last line. |
## |
## test: Runs both testbenches, printing success if both succeed, or |
## failure if one of the two does not. |
## |
## Creator: Dan Gisselquist, Ph.D. |
## Gisselquist Technology, LLC |
## |
31,19 → 50,30
## License: GPL, v3, as defined and found on www.gnu.org, |
## http://www.gnu.org/licenses/gpl.html |
## |
## |
################################################################################ |
## |
## |
all: wbscope_tb |
all: wbscope_tb wbscopc_tb |
CXX := g++ |
RTLD := ../rtl |
ROBJD:= $(RTLD)/obj_dir |
VROOT:= /usr/share/verilator |
VINCS:= -I$(VROOT) |
VERILATOR_ROOT ?= $(shell bash -c 'verilator -V|grep VERILATOR_ROOT| head -1|sed -e " s/^.*=\s*//"') |
VROOT:= $(VERILATOR_ROOT) |
INCS := -I$(VROOT)/include -I$(ROBJD) |
VSRCS:= $(VROOT)/include/verilated.cpp $(VROOT)/include/verilated_vcd_c.cpp |
TBOBJ:= $(ROBJD)/Vwbscope_tb__ALL.a |
TCOBJ:= $(ROBJD)/Vwbscopc_tb__ALL.a |
|
wbscope_tb: wbscope_tb.cpp $(ROBJD)/Vwbscope_tb__ALL.a $(ROBJD)/Vwbscope_tb.h |
wbscope_tb: wbscope_tb.cpp $(TBOBJ) $(ROBJD)/Vwbscope_tb.h wb_tb.h testb.h |
$(CXX) $(INCS) wbscope_tb.cpp $(VSRCS) $(TBOBJ) -o $@ |
|
wbscopc_tb: wbscopc_tb.cpp $(TCOBJ) $(ROBJD)/Vwbscopc_tb.h wb_tb.h testb.h |
$(CXX) $(INCS) wbscopc_tb.cpp $(VSRCS) $(TCOBJ) -o $@ |
|
test: wbscope_tb wbscopc_tb |
./wbscope_tb |
./wbscopc_tb |
|
clean: |
rm -f wbscope_tb wbscopc_tb |
rm -f wbscope_tb.vcd wbscopc_tb.vcd |
/cpp/devbus.h
0,0 → 1,148
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: devbus.h |
// |
// Project: WBScope, a wishbone hosted scope |
// |
// Purpose: The purpose of this file is to document an interface which |
// any device with a bus, whether it be implemented over a UART, |
// an ethernet, or a PCI express bus, must implement. This describes |
// only an interface, and not how that interface is to be accomplished. |
// |
// The neat part of this interface is that, if programs are designed to |
// work with it, than the implementation details may be changed later |
// and any program that once worked with the interface should be able |
// to continue to do so. (i.e., switch from a UART controlled bus to a |
// PCI express controlled bus, with minimal change to the software of |
// interest.) |
// |
// |
// 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 |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#ifndef DEVBUS_H |
#define DEVBUS_H |
|
#include <stdio.h> |
#include <unistd.h> |
|
typedef unsigned int uint32; |
|
class BUSERR { |
public: |
uint32 addr; |
BUSERR(const uint32 a) : addr(a) {}; |
}; |
|
class DEVBUS { |
public: |
typedef uint32 BUSW; |
|
virtual void kill(void) = 0; |
virtual void close(void) = 0; |
|
// Write a single value to a single address |
// a is the address of the value to be read as it exists on the |
// wishbone bus within the FPGA. |
// v is the singular value to write to this address |
virtual void writeio(const BUSW a, const BUSW v) = 0; |
|
// Read a single value to a single address |
// a is the address of the value to be read as it exists on the |
// wishbone bus within the FPGA. |
// This function returns the value read from the device wishbone |
// at address a. |
virtual BUSW readio(const BUSW a) = 0; |
|
// Read a series of values from values from a block of memory |
// a is the address of the value to be read as it exists on the |
// wishbone bus within the FPGA. |
// len is the number of words to read |
// buf is a pointer to a place to store the words once read. |
// This is equivalent to: |
// for(int i=0; i<len; i++) |
// buf[i] = readio(a+i); |
// only it's faster in our implementation. |
virtual void readi(const BUSW a, const int len, BUSW *buf) = 0; |
|
// Read a series of values from the same address in memory. This |
// call is identical to readi, save that the address is not incremented |
// from one read to the next. It is equivalent to: |
// for(int i=0; i<len; i++) |
// buf[i] = readio(a); |
// only it's faster in our implementation. |
// |
virtual void readz(const BUSW a, const int len, BUSW *buf) = 0; |
|
// Write a series of values into a block of memory on the FPGA |
// a is the address of the value to be written as it exists on the |
// wishbone bus within the FPGA. |
// len is the number of words to write |
// buf is a pointer to a place to from whence to grab the data |
// to be written. |
// This is equivalent to: |
// for(int i=0; i<len; i++) |
// writeio(a+i, buf[i]); |
// only it's faster in our implementation. |
virtual void writei(const BUSW a, const int len, const BUSW *buf) = 0; |
// Write a series of values into the same address on the FPGA bus. This |
// call is identical to writei, save that the address is not incremented |
// from one write to the next. It is equivalent to: |
// for(int i=0; i<len; i++) |
// writeio(a, buf[i]); |
// only it's faster in our implementation. |
// |
virtual void writez(const BUSW a, const int len, const BUSW *buf) = 0; |
|
// Query whether or not an interrupt has taken place |
virtual bool poll(void) = 0; |
|
// Sleep until interrupt, but sleep no longer than msec milliseconds |
virtual void usleep(unsigned msec) = 0; |
|
// Sleep until an interrupt, no matter how long it takes for that |
// interrupt to take place |
virtual void wait(void) = 0; |
|
// Query whether or not a bus error has taken place. This is somewhat |
// of a misnomer, as my current bus error detection code exits any |
// interface, but ... it is what it is. |
virtual bool bus_err(void) const = 0; |
|
// Clear any bus error condition. |
virtual void reset_err(void) = 0; |
|
// Clear any interrupt condition that has already been noticed by |
// the interface, does not check for further interrupt |
virtual void clear(void) = 0; |
|
virtual ~DEVBUS(void) { }; |
}; |
|
#endif |
/cpp/testb.h
2,7 → 2,7
// |
// Filename: testb.h |
// |
// Project: Zip CPU -- a small, lightweight, RISC CPU core |
// Project: WBScope, a wishbone hosted scope |
// |
// Purpose: A wrapper for a common interface to a clocked FPGA core |
// begin exercised in Verilator. |
25,7 → 25,7
// 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 |
// 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. |
// |
34,6 → 34,8
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#ifndef TESTB_H |
#define TESTB_H |
|
41,6 → 43,8
#include <stdint.h> |
#include <verilated_vcd_c.h> |
|
#define TBASSERT(TB,A) do { if (!(A)) { (TB).closetrace(); } assert(A); } while(0); |
|
template <class VA> class TESTB { |
public: |
VA *m_core; |
50,22 → 54,27
TESTB(void) : m_trace(NULL), m_tickcount(0l) { |
m_core = new VA; |
Verilated::traceEverOn(true); |
m_core->i_clk = 0; |
eval(); // Get our initial values set properly. |
} |
virtual ~TESTB(void) { |
if (m_trace) m_trace->close(); |
closetrace(); |
delete m_core; |
m_core = NULL; |
} |
|
virtual void opentrace(const char *vcdname) { |
m_trace = new VerilatedVcdC; |
m_core->trace(m_trace, 99); |
m_trace->open(vcdname); |
if (!m_trace) { |
m_trace = new VerilatedVcdC; |
m_core->trace(m_trace, 99); |
m_trace->open(vcdname); |
} |
} |
|
virtual void closetrace(void) { |
if (m_trace) { |
m_trace->close(); |
delete m_trace; |
m_trace = NULL; |
} |
} |
77,16 → 86,22
virtual void tick(void) { |
m_tickcount++; |
|
//if((m_trace)&&(m_tickcount)) m_trace->dump(10*m_tickcount-4); |
// Make sure we have our evaluations straight before the top |
// of the clock. This is necessary since some of the |
// connection modules may have made changes, for which some |
// logic depends. This forces that logic to be recalculated |
// before the top of the clock. |
eval(); |
if ((m_trace)&&(m_tickcount)) m_trace->dump(10*m_tickcount-2); |
if (m_trace) m_trace->dump(10*m_tickcount-2); |
m_core->i_clk = 1; |
eval(); |
if (m_trace) m_trace->dump(10*m_tickcount); |
m_core->i_clk = 0; |
eval(); |
if (m_trace) m_trace->dump(10*m_tickcount+5); |
|
if (m_trace) { |
m_trace->dump(10*m_tickcount+5); |
m_trace->flush(); |
} |
} |
|
virtual void reset(void) { |
/cpp/wb_tb.h
0,0 → 1,455
//////////////////////////////////////////////////////////////////////////////// |
// |
// 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 |
} |
}; |
|
/cpp/wbscopc_tb.cpp
0,0 → 1,195
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: wbscopc_tb.cpp |
// |
// Project: WBScope, a wishbone hosted scope |
// |
// Purpose: A quick test bench to determine if the run-length encoded |
// wbscopc module works. |
// |
// 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 <verilated.h> |
#include <verilated_vcd_c.h> |
#include "Vwbscopc_tb.h" |
#include "testb.h" |
#include "devbus.h" |
#define INTERRUPTWIRE o_interrupt |
#include "wb_tb.h" |
|
const int LGMEMSIZE = 15; |
|
class WBSCOPC_TB : public WB_TB<Vwbscopc_tb> { |
bool m_debug; |
public: |
|
WBSCOPC_TB(void) { |
m_debug = true; |
} |
|
void tick(void) { |
|
WB_TB<Vwbscopc_tb>::tick(); |
|
bool writeout = true; |
if ((m_debug)&&(writeout)) {} |
} |
|
void reset(void) { |
m_core->i_rst = 1; |
m_core->i_wb_cyc = 0; |
m_core->i_wb_stb = 0; |
tick(); |
m_core->i_rst = 0; |
} |
|
unsigned trigger(void) { |
m_core->i_trigger = 1; |
idle(); |
m_core->i_trigger = 0; |
printf("TRIGGERED AT %08x\n", m_core->o_data); |
return m_core->o_data; |
} |
|
bool debug(void) const { return m_debug; } |
bool debug(bool nxtv) { return m_debug = nxtv; } |
}; |
|
int main(int argc, char **argv) { |
Verilated::commandArgs(argc, argv); |
WBSCOPC_TB *tb = new WBSCOPC_TB; |
unsigned v, addr, trigger_addr; |
unsigned *buf; |
int trigpt; |
|
tb->opentrace("wbscopc_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(); |
tb->idle(2); |
|
#define WBSCOPE_STATUS 0 |
#define WBSCOPE_DATA 4 |
#define WBSCOPE_NORESET 0x80000000 |
#define WBSCOPE_TRIGGER (WBSCOPE_NO_RESET|0x08000000) |
#define WBSCOPE_MANUAL (WBSCOPE_TRIGGER) |
#define WBSCOPE_PRIMED 0x10000000 |
#define WBSCOPE_TRIGGERED 0x20000000 |
#define WBSCOPE_STOPPED 0x40000000 |
#define WBSCOPE_DISABLED 0x04000000 |
#define WBSCOPE_LGLEN(A) ((A>>20)&0x01f) |
#define WBSCOPE_LENGTH(A) (1<<(LGLEN(A))) |
|
// First test ... read the status register |
v = tb->readio(WBSCOPE_STATUS); |
int ln = WBSCOPE_LGLEN(v); |
printf("V = %08x\n", v); |
printf("LN = %d, or %d entries\n", ln, (1<<ln)); |
printf("DLY = %d\n", (v&0xfffff)); |
if (((1<<ln) < tb->m_tickcount)&&(v&0x10000000)) { |
printf("SCOPE is already triggered! ??\n"); |
goto test_failure; |
} |
buf = new unsigned[(1<<ln)]; |
|
tb->idle((1<<(12+4)) + (1<<ln) +240); |
|
v = tb->readio(WBSCOPE_STATUS); |
if ((v&WBSCOPE_PRIMED)==0) { |
printf("v = %08x\n", v); |
printf("SCOPE hasn\'t primed! ??\n"); |
goto test_failure; |
} |
|
tb->trigger(); |
v = tb->readio(WBSCOPE_STATUS); |
if ((v&WBSCOPE_TRIGGERED)==0) { |
printf("v = %08x\n", v); |
printf("SCOPE hasn\'t triggered! ??\n"); |
goto test_failure; |
} |
|
while((v & WBSCOPE_STOPPED)==0) |
v = tb->readio(WBSCOPE_STATUS); |
printf("SCOPE has stopped, reading data\n"); |
|
tb->readz(WBSCOPE_DATA, (1<<ln), buf); |
addr = 0; |
trigger_addr = 0xffffffff; |
for(int i=0; i<(1<<ln); i++) { |
if (buf[i] & 0x80000000) |
addr += (buf[i]&0x7fffffff) + 1; |
else { |
if ((i > 0)&&(buf[i-1]&0x80000000)) |
printf(" [*****]:\n"); |
printf("%5d[%5d]: %08x", addr, i, buf[i]); |
if (buf[i] & 0x40000000) { |
printf(" <<--- TRIGGER!"); |
trigger_addr = addr; |
} printf("\n"); |
|
addr++; |
} |
} if ((buf[(1<<ln)-1]&0x80000000)) |
printf(" [*****]:\n"); |
|
if (buf[(1<<ln)-1] & 0x80000000) { |
printf("ERR: LAST VALUE IS A RUN, 0x%08x\n", buf[(1<<ln)-1]); |
goto test_failure; |
} |
|
if (trigger_addr == 0xffffffff) { |
printf("ERR: TRIGGER NOT FOUND IN THE DATA!\n"); |
goto test_failure; |
} |
|
|
printf("TRIGGER ADDRESS = %08x (%5d)\n", trigger_addr, trigger_addr); |
printf("V = %08x\n", v & 0x0fffff); |
printf("Difference = %08x (%5d)\n", addr - trigger_addr, |
addr - trigger_addr); |
if (addr - 1 - trigger_addr != (v & 0x0fffff)) { |
printf("TRIGGER AT THE WRONG LOCATION!\n"); |
goto test_failure; |
} |
|
printf("SUCCESS!!\n"); |
delete tb; |
exit(0); |
test_failure: |
printf("FAIL-HERE\n"); |
for(int i=0; i<4; i++) |
tb->tick(); |
printf("TEST FAILED\n"); |
delete tb; |
exit(-1); |
} |
/cpp/wbscope_tb.cpp
39,30 → 39,24
|
#include <verilated.h> |
#include <verilated_vcd_c.h> |
#include "Vwbscope_tb.h" |
#include "testb.h" |
#include "Vwbscope_tb.h" |
#define INTERRUPTWIRE o_interrupt |
#include "wb_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 LGMEMSIZE = 15; |
|
const int BOMBCOUNT = 32, |
LGMEMSIZE = 15; |
|
class WBSCOPE_TB : public TESTB<Vwbscope_tb> { |
bool m_bomb, m_miss, m_err, m_debug; |
int m_last_tlb_index; |
class WBSCOPE_TB : public WB_TB<Vwbscope_tb> { |
bool m_bomb, m_debug; |
public: |
|
WBSCOPE_TB(void) { |
m_debug = true; |
m_last_tlb_index = 0; |
} |
|
void tick(void) { |
|
TESTB<Vwbscope_tb>::tick(); |
WB_TB<Vwbscope_tb>::tick(); |
|
bool writeout = true; |
if ((m_debug)&&(writeout)) {} |
76,113 → 70,10
m_core->i_rst = 0; |
} |
|
void wb_tick(void) { |
m_core->i_wb_cyc = 0; |
m_core->i_wb_stb = 0; |
tick(); |
assert(!m_core->o_wb_ack); |
} |
|
unsigned wb_read(unsigned a) { |
unsigned result; |
|
printf("WB-READM(%08x)\n", a); |
|
m_core->i_wb_cyc = 1; |
m_core->i_wb_stb = 1; |
m_core->i_wb_we = 0; |
m_core->i_wb_addr= (a>>2)&1; |
|
// Dont need to check for stalls, since the wbscope never stalls |
tick(); |
|
m_core->i_wb_stb = 0; |
|
while(!m_core->o_wb_ack) |
tick(); |
|
result = m_core->o_wb_data; |
|
// Release the bus? |
m_core->i_wb_cyc = 0; |
m_core->i_wb_stb = 0; |
|
// Let the bus idle for one cycle |
tick(); |
|
return result; |
} |
|
void wb_read(unsigned a, int len, unsigned *buf) { |
int cnt, rdidx; |
|
printf("WB-READM(%08x, %d)\n", a, len); |
|
m_core->i_wb_cyc = 1; |
m_core->i_wb_stb = 1; |
m_core->i_wb_we = 0; |
m_core->i_wb_addr = (a>>2)&1; |
|
rdidx =0; cnt = 0; |
|
do { |
tick(); |
// Normally, we'd increment the address here. For the |
// scope, multiple reads only make sense if they are |
// from the same address, hence we don't increment the |
// address here |
// m_core->i_wb_addr += inc; |
cnt += 1; |
if (m_core->o_wb_ack) |
buf[rdidx++] = m_core->o_wb_data; |
} while(cnt < len); |
|
m_core->i_wb_stb = 0; |
|
while(rdidx < len) { |
tick(); |
if (m_core->o_wb_ack) |
buf[rdidx++] = m_core->o_wb_data; |
} |
|
// Release the bus? |
m_core->i_wb_cyc = 0; |
|
tick(); |
assert(!m_core->o_wb_ack); |
} |
|
void wb_write(unsigned a, unsigned v) { |
int errcount = 0; |
|
printf("WB-WRITEM(%08x) <= %08x\n", a, v); |
m_core->i_wb_cyc = 1; |
m_core->i_wb_stb = 1; |
m_core->i_wb_we = 1; |
m_core->i_wb_addr= (a>>2)&1; |
m_core->i_wb_data= v; |
|
tick(); |
m_core->i_wb_stb = 0; |
|
while(!m_core->o_wb_ack) { |
tick(); |
} |
|
tick(); |
|
// Release the bus? |
m_core->i_wb_cyc = 0; |
m_core->i_wb_stb = 0; |
|
assert(!m_core->o_wb_ack); |
} |
|
unsigned trigger(void) { |
m_core->i_trigger = 1; |
wb_tick(); |
idle(); |
m_core->i_trigger = 0; |
printf("TRIGGERED AT %08x\n", m_core->o_data); |
return m_core->o_data; |
} |
|
196,13 → 87,13
unsigned v; |
unsigned *buf; |
int trigpt; |
unsigned trigger_time, expected_first_value; |
|
tb->opentrace("wbscope_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(); |
tb->idle(2); |
|
#define WBSCOPE_STATUS 0 |
#define WBSCOPE_DATA 4 |
217,7 → 108,7
#define WBSCOPE_LENGTH(A) (1<<(LGLEN(A))) |
|
// First test ... read the status register |
v = tb->wb_read(WBSCOPE_STATUS); |
v = tb->readio(WBSCOPE_STATUS); |
int ln = WBSCOPE_LGLEN(v); |
printf("V = %08x\n", v); |
printf("LN = %d, or %d entries\n", ln, (1<<ln)); |
228,10 → 119,9
} |
buf = new unsigned[(1<<ln)]; |
|
for(int i=0; i<(1<<ln); i++) |
tb->wb_tick(); |
tb->idle(1<<ln); |
|
v = tb->wb_read(WBSCOPE_STATUS); |
v = tb->readio(WBSCOPE_STATUS); |
if ((v&WBSCOPE_PRIMED)==0) { |
printf("v = %08x\n", v); |
printf("SCOPE hasn\'t primed! ??\n"); |
238,8 → 128,10
goto test_failure; |
} |
|
tb->trigger(); |
v = tb->wb_read(WBSCOPE_STATUS); |
trigger_time = tb->trigger() & 0x7fffffff; |
printf("TRIGGERED AT %08x\n", trigger_time); |
|
v = tb->readio(WBSCOPE_STATUS); |
if ((v&WBSCOPE_TRIGGERED)==0) { |
printf("v = %08x\n", v); |
printf("SCOPE hasn\'t triggered! ??\n"); |
247,17 → 139,21
} |
|
while((v & WBSCOPE_STOPPED)==0) |
v = tb->wb_read(WBSCOPE_STATUS); |
v = tb->readio(WBSCOPE_STATUS); |
printf("SCOPE has stopped, reading data\n"); |
|
tb->wb_read(WBSCOPE_DATA, (1<<ln), buf); |
tb->readz(WBSCOPE_DATA, (1<<ln), buf); |
for(int i=0; i<(1<<ln); i++) { |
printf("%4d: %08x\n", i, buf[i]); |
if ((i>0)&&(((buf[i]&0x7fffffff)-(buf[i-1]&0x7fffffff))!=1)) |
printf("%4d: %08x%s\n", i, buf[i], |
(i== (1<<ln)-1-(v&0x0fffff)) ? " <<--- TRIGGER!":""); |
if ((i>0)&&(((buf[i]&0x7fffffff)-(buf[i-1]&0x7fffffff))!=1)) { |
printf("ERR: Scope data doesn't increment!\n"); |
printf("\tIn other words--its not matching the test signal\n"); |
goto test_failure; |
} |
} |
|
trigpt = (1<<ln)-v&(0x0fffff); |
trigpt = (1<<ln)-v&(0x0fffff)-1; |
if ((trigpt >= 0)&&(trigpt < (1<<ln))) { |
printf("Trigger value = %08x\n", buf[trigpt]); |
if (((0x80000000 & buf[trigpt])==0)&&(trigpt>0)) { |
269,6 → 165,14
} |
} |
|
expected_first_value = trigger_time + (v&0x0fffff) - (1<<ln); |
if (buf[0] != expected_first_value) { |
printf("Initial value = %08x\n", buf[0]); |
printf("Expected: %08x\n", expected_first_value); |
printf("ERR: WRONG STARTING-VALUE\n"); |
goto test_failure; |
} |
|
printf("SUCCESS!!\n"); |
delete tb; |
exit(0); |
/rtl/Makefile
1,15 → 1,14
################################################################################ |
# |
# Filename: Makefile |
# |
# Project: WBScope, a wishbone hosted scope |
# |
# Purpose: This makefile builds a verilator simulation of the rtl |
# testbenches necessary to test certain components of the |
# wishbone scope using Verilator. It does not make the system within |
## Icarus, Vivado or Quartus. |
## |
## Filename: Makefile |
## |
## Project: WBScope, a wishbone hosted scope |
## |
## Purpose: This makefile builds a verilator simulation of the rtl |
## testbenches necessary to test certain components of both the |
## wishbone scope and its RLE compressed brother using Verilator. |
## |
## |
## Creator: Dan Gisselquist, Ph.D. |
## Gisselquist Technology, LLC |
## |
40,13 → 39,18
## |
## |
.PHONY: all |
all: wbscope_tb |
all: wbscope_tb wbscopc_tb |
|
RTLD := ../../rtl |
VOBJ := obj_dir |
|
# |
# |
# Building the wbscope test bench |
# |
# |
$(VOBJ)/Vwbscope_tb.cpp: $(RTLD)/wbscope.v wbscope_tb.v |
verilator -trace -cc -y $(RTLD) wbscope_tb.v |
verilator -Wall -O3 -trace -cc -y $(RTLD) wbscope_tb.v |
$(VOBJ)/Vwbscope_tb.h: $(VOBJ)/Vwbscope_tb.cpp |
|
$(VOBJ)/Vwbscope_tb__ALL.a: $(VOBJ)/Vwbscope_tb.cpp $(VOBJ)/Vwbscope_tb.h |
55,6 → 59,21
.PHONY: wbscope_tb |
wbscope_tb: $(VOBJ)/Vwbscope_tb__ALL.a |
|
# |
# |
# Building the wbscopc test bench, for the compressed wbscope |
# |
# |
$(VOBJ)/Vwbscopc_tb.cpp: $(RTLD)/wbscopc.v wbscopc_tb.v |
verilator -Wall -O3 -trace -cc -y $(RTLD) wbscopc_tb.v |
$(VOBJ)/Vwbscopc_tb.h: $(VOBJ)/Vwbscopc_tb.cpp |
|
$(VOBJ)/Vwbscopc_tb__ALL.a: $(VOBJ)/Vwbscopc_tb.cpp $(VOBJ)/Vwbscopc_tb.h |
make --no-print-directory --directory=$(VOBJ) -f Vwbscopc_tb.mk |
|
.PHONY: wbscopc_tb |
wbscopc_tb: $(VOBJ)/Vwbscopc_tb__ALL.a |
|
# $(VOBJ)/Vaxiscope_tb.cpp: $(RTLD)/axiscope.v axiscope.v |
# verilator -trace -cc -y $(RTLD) wbscope_tb.v |
# $(VOBJ)/Vaxiscope_tb.h: $(VOBJ)/Vwbscope_tb.cpp |
/rtl/wbscopc_tb.v
0,0 → 1,92
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: wbscopc_tb.v |
// |
// Project: WBScope, a wishbone hosted scope |
// |
// Purpose: This file is a test bench wrapper around the compressed |
// wishbone scope, designed to create a "signal" which can then |
// be scoped and proven. Unlike the case of the normal wishbone scope, |
// this scope needs a test signal that has lots of idle time surrounded |
// my sudden changes. We'll handle our sudden changes via a counter. |
// |
// 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 |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
module wbscope_tb(i_clk, |
// i_rst is required by our test infrastructure, yet unused here |
i_rst, |
// The test data. o_data is internally generated here from |
// o_counter, i_trigger is given externally |
i_trigger, o_data, o_counter, |
// Wishbone bus interaction |
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, |
// wishbone bus outputs |
o_wb_ack, o_wb_stall, o_wb_data, |
// And our output interrupt |
o_interrupt); |
input i_clk, i_rst, i_trigger; |
output wire [30:0] o_data; |
output wire [29:0] o_counter; |
// |
input i_wb_cyc, i_wb_stb, i_wb_we; |
input i_wb_addr; |
input [31:0] i_wb_data; |
// |
output wire o_wb_ack; |
output wire [31:0] o_wb_data; |
output wire o_wb_stall; |
// |
output o_interrupt; |
|
reg [29:0] counter; |
initial counter = 0; |
always @(posedge i_clk) |
counter <= counter + 1'b1; |
always @(posedge i_clk) |
if (counter[11:8] == 4'h0) |
o_data <= { i_trigger, counter }; |
else if ((counter[10])&&(counter[1])) |
o_data <= { i_trigger, counter }; |
else |
o_data <= { i_trigger, counter[29:12], 12'h0 }; |
|
wire wb_stall_ignored; |
|
wbscopc #(.LGMEM(5'd14), .BUSW(32), .SYNCHRONOUS(1), .MAX_STEP(768), |
.DEFAULT_HOLDOFF(36)) |
scope(i_clk, 1'b1, i_trigger, o_data, |
i_clk, i_wb_cyc, i_wb_stb, i_wb_we, |
i_wb_addr, i_wb_data, |
o_wb_ack, wb_stall_ignored, o_wb_data, |
o_interrupt); |
|
assign o_wb_stall = 1'b0; |
|
endmodule |
/rtl/wbscope_tb.v
4,7 → 4,12
// |
// Project: WBScope, a wishbone hosted scope |
// |
// Purpose: |
// Purpose: This file is a test bench wrapper around the wishbone scope, |
// designed to create a "signal" which can then be scoped and |
// proven. In our case here, the "signal" is a counter. When we test |
// the scope within our bench/cpp Verilator testbench, we'll know if our |
// test was "correct" if the counter 1) only ever counts by 1, and 2) if |
// the trigger lands on thte right data sample. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
35,9 → 40,18
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
module wbscope_tb(i_clk, i_rst, i_trigger, o_data, |
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, |
o_wb_ack, o_wb_data, o_interrupt); |
module wbscope_tb(i_clk, |
// i_rst is required by our test infrastructure, yet unused here |
i_rst, |
// The test data. o_data is internally generated here from a |
// counter, i_trigger is given externally |
i_trigger, o_data, |
// Wishbone bus interaction |
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, |
// wishbone bus outputs |
o_wb_ack, o_wb_stall, o_wb_data, |
// And our output interrupt |
o_interrupt); |
input i_clk, i_rst, i_trigger; |
output wire [31:0] o_data; |
// |
46,6 → 60,7
input [31:0] i_wb_data; |
// |
output wire o_wb_ack; |
output wire o_wb_stall; |
output wire [31:0] o_wb_data; |
// |
output o_interrupt; |
59,7 → 74,8
|
wire wb_stall_ignored; |
|
wbscope #(5'd6, 32, 1) |
wbscope #(.LGMEM(5'd6), .BUSW(32), .SYNCHRONOUS(1), |
.DEFAULT_HOLDOFF(1)) |
scope(i_clk, 1'b1, i_trigger, o_data, |
i_clk, i_wb_cyc, i_wb_stb, i_wb_we, |
i_wb_addr, i_wb_data, |
66,4 → 82,10
o_wb_ack, wb_stall_ignored, o_wb_data, |
o_interrupt); |
|
assign o_wb_stall = 1'b0; |
|
// verilator lint_off UNUSED |
wire [1:0] unused; |
assign unused = { i_rst, wb_stall_ignored }; |
// verilator lint_on UNUSED |
endmodule |