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

Subversion Repositories wbuart32

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /wbuart32/trunk/bench
    from Rev 4 to Rev 5
    Reverse comparison

Rev 4 → Rev 5

/README.md
0,0 → 1,?rev2len?
There are two bench testing directories, one for Verilator sources, and one for C++ simulation sources that will work with Verilator. The Verilog sources may or may not be used with Verilator. Indeed, they would work nicely as stand--alone top--level files that may be used to test whether or not the UART on a given board works.
/cpp/Makefile
4,8 → 4,43
##
## Project: wbuart32, a full featured UART with simulator
##
## Purpose:
## Purpose: To test a group of Verilator modules: txuart (UART transmitter),
## rxuart (UART receiver/sink) and wbuart (UART module, containing
## both receiver and transmitter, with FIFOs, controlled via wishbone).
##
##
## Targets:
## test
## Perform both tests. The end result should be either a PASS
## or a FAIL.
##
## helloworld
## A non-automated, and less interactive test than the others. In
## this test, the UART simply produces a Hello World message to the
## screen over and over again.
##
## linetest
## An automated test of both txuart and rxuart. The test works
## by sending a message through the rxuart, and receiving the
## message via the txuart. This depends upon a Verilog test
## infrastructure, linetest.v.
##
## This test may be ran in an interactive mode. In this mode,
## characters written to the UART will be reflected back upon
## the entrance of a return character.
##
## speechtest
## An automated test of the wbuart, txuart, and fifo. In this
## case, the test RTL produces a copy of the Gettysburg address,
## filling the FIFO at 12/16 at a time. In automated mode, the
## speechtest will compare the output against against a text copy
## of the speech, and report upon any success or failure.
##
## In interactive mode, the test will repeatedly print out the
## Gettysburg address until stopped. (It may take a significant
## amount of time between copies of the Gettysburg address ...)
##
##
## Creator: Dan Gisselquist, Ph.D.
## Gisselquist Technology, LLC
##
39,14 → 74,26
FLAGS := -Wall -Og -g
OBJDIR := obj-pc
RTLD := ../verilog
VERILATOR_ROOT ?= $(shell bash -c 'verilator -V|grep VERILATOR_ROOT | head -1 | sed -e " s/^.*=\s*//"')
VROOT := $(VERILATOR_ROOT)
INCS := -I$(RTLD)/obj_dir/ -I/usr/share/verilator/include
SOURCES := linetest.cpp
SOURCES := helloworld.cpp linetest.cpp uartsim.cpp uartsim.h
VOBJDR := $(RTLD)/obj_dir
VLIB := /usr/share/verilator/include/verilated.cpp
SIMSRCS := linetest.cpp uartsim.cpp
SIMOBJ := $(subst .cpp,.o,$(SIMSRCS))
SIMOBJS:= $(addprefix $(OBJDIR)/,$(SIMOBJ))
all: $(OBJDIR)/ linetest
SYSVDR := /usr/share/verilator/include
VLIB := $(SYSVDR)/verilated.cpp $(SYSVDR)/verilated_vcd_c.cpp
# Sources necessary to build the linetest program (rxuart-txuart test)
LINSRCS := linetest.cpp uartsim.cpp
LINOBJ := $(subst .cpp,.o,$(LINSRCS))
LINOBJS:= $(addprefix $(OBJDIR)/,$(LINOBJ))
# Sources necessary to build the helloworld test (txuart test)
HLOSRCS := helloworld.cpp uartsim.cpp
HLOOBJ := $(subst .cpp,.o,$(HLOSRCS))
HLOOBJS:= $(addprefix $(OBJDIR)/,$(HLOOBJ))
# Sources necessary to build the speech test (wbuart test)
SPCHSRCS:= speechtest.cpp uartsim.cpp
SPCHOBJ := $(subst .cpp,.o,$(SPCHSRCS))
SPCHOBJS:= $(addprefix $(OBJDIR)/,$(SPCHOBJ))
all: $(OBJDIR)/ linetest helloworld speechtest test
 
$(OBJDIR)/:
@bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi"
56,11 → 103,42
$(OBJDIR)/%.o: %.cpp
$(CXX) $(FLAGS) $(INCS) -c $< -o $@
 
linetest: $(OBJDIR)/linetest.o $(OBJDIR)/uartsim.o $(VOBJDR)/Vlinetest__ALL.a
linetest: $(LINOBJS) $(VOBJDR)/Vlinetest__ALL.a
$(CXX) $(FLAGS) $(INCS) $^ $(VLIB) -o $@
 
helloworld: $(HLOOBJS) $(VOBJDR)/Vhelloworld__ALL.a
$(CXX) $(FLAGS) $(INCS) $^ $(VLIB) -o $@
 
#
# The speech test program depends upon a copy of the Gettysburg Address,
# turned into a hex file format which will be read by the Verilog/RTL
# $readmemh function. However, we need to create that hex file that will
# written. That's the purpose of mkspeech--to make a file that can be read
# by $readmemh.
#
mkspeech: mkspeech.cpp
$(CXX) mkspeech.cpp -o $@
 
# Now that mkspeech is available, use it to produce a speech.hex file from
# the speech.txt file. Be careful if you adjust this speech: the speechfifo.v
# verilog file depends upon the exact number of characters--its not a portable
# dependency, but ... it is what it is.
speech.hex: mkspeech speech.txt
./mkspeech speech.txt
 
# Now, if the speech.hex file is available, then we can perform our final build.
# Actually, we could've done this without the speech file being available, but
# this works.
speechtest: speech.hex $(SPCHOBJS) $(VOBJDR)/Vspeechfifo__ALL.a
$(CXX) $(FLAGS) $(INCS) $(SPCHOBJS) $(VOBJDR)/Vspeechfifo__ALL.a $(VLIB) -o $@
 
test: linetest speechtest
./linetest
./speechtest
 
.PHONY: clean
clean:
rm -f ./linetest
rm -f ./linetest ./helloworld ./speechtest
rm -f ./mkspeech ./speech.hex
rm -rf $(OBJDIR)/
 
/cpp/README.md
0,0 → 1,21
+ C++ source files
 
Items within this directory include:
 
- uartsim defines a C++ class that can be used for simulating a UART within
Verilator. This class can be used both to generate valid UART signaling,
to determine if your configuration can receive it properly, as well as to decode
valid UART signaling to determine if your configuration is properly setting the
UART signaling wire.
 
- speech.txt, and the associated speech.hex file, is the text that speechfifo
will transmit. It is currently set to the Gettysburg Address. While you are welcome to change this, the length of this file is hard coded within the verilog file that references it.
 
- mkspeech, a Verilog hex file generator--although it also converts newlines to
carriage-return newline pairs
 
- Demonstration projects using these:
-- helloworld, exercises and tests the helloworld.v test bench
-- linetest, exercises and tests the linetest.v test bench. This also creates a .VCD file which can be viewed via GTKwave
-- speechtest, exercises and tests the speechfifo test bench. When run with the -i option, speechtest will also generate a .VCD file for use with GTKwave.
 
/cpp/helloworld.cpp
0,0 → 1,72
////////////////////////////////////////////////////////////////////////////////
//
// Filename: helloworld.cpp
//
// Project: wbuart32, a full featured UART with simulator
//
// Purpose: To demonstrate a useful Verilog file which could be used as a
// toplevel program later, to demo the transmit UART.
//
// 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 <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <signal.h>
#include "verilated.h"
#include "Vhelloworld.h"
#include "uartsim.h"
 
int main(int argc, char **argv) {
Verilated::commandArgs(argc, argv);
Vhelloworld tb;
UARTSIM *uart;
int port = 0;
unsigned setup = 25, testcount = 0;
 
tb.i_setup = setup;
uart = new UARTSIM(port);
uart->setup(tb.i_setup);
 
while(testcount++ < 0x7f000000) {
 
tb.i_clk = 1;
tb.eval();
tb.i_clk = 0;
tb.eval();
 
(*uart)(tb.o_uart_tx);
}
 
printf("\n\nSimulation complete\n");
}
/cpp/linetest.cpp
8,7 → 8,7
// which can be exercised/proven via Verilator.
//
// If you run this program with no arguments, it will run an automatic
// test, returning "SUCCESS" on success, or "FAIL" on failure as a last
// test, returning "PASS" on success, or "FAIL" on failure as a last
// output line--hence it should support automated testing.
//
// If you run with a '-i' argument, the program will run interactively.
50,9 → 50,11
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include "verilated.h"
#include "Vlinetest.h"
#include "verilated_vcd_c.h"
#include "uartsim.h"
 
int main(int argc, char **argv) {
62,6 → 64,7
bool run_interactively = false;
int port = 0;
unsigned setup = 25;
char string[] = "This is a UART testing string\r\n";
 
for(int argn=1; argn<argc; argn++) {
if (argv[argn][0] == '-') for(int j=1; (j<1000)&&(argv[argn][j]); j++)
83,7 → 86,8
}
 
tb.i_setup = setup;
tb.i_uart = 1;
int baudclocks = setup & 0x0ffffff;
tb.i_uart_rx = 1;
if (run_interactively) {
uart = new UARTSIM(port);
uart->setup(tb.i_setup);
95,7 → 99,7
tb.i_clk = 0;
tb.eval();
 
tb.i_uart = (*uart)(tb.o_uart);
tb.i_uart_rx = (*uart)(tb.o_uart_tx);
}
 
} else {
108,9 → 112,9
exit(EXIT_FAILURE);
}
 
pid_t pid = fork();
pid_t childs_pid = fork();
 
if (pid < 0) {
if (childs_pid < 0) {
fprintf(stderr, "ERR setting up child process\n");
perror("O/S ERR");
printf("TEST FAILURE\n");
117,7 → 121,7
exit(EXIT_FAILURE);
}
 
if (pid) {
if (childs_pid) {
int nr=-2, nw;
 
// We are the parent
124,7 → 128,6
close(childs_stdin[ 0]); // Close the read end
close(childs_stdout[1]); // Close the write end
 
char string[] = "This is a UART testing string\r\n";
char test[256];
 
nw = write(childs_stdin[1], string, strlen(string));
142,14 → 145,37
printf("Successfully read %d characters: %s\n", nr, test);
}
 
// We are done, kill our child if not already dead
kill(pid, SIGTERM);
int status = 0, rv = -1;
 
// Give the child the oppoortunity to take another
// 60 seconds to finish closing itself
for(int waitcount=0; waitcount < 60; waitcount++) {
rv = waitpid(-1, &status, WNOHANG);
if (rv == childs_pid)
break;
else if (rv < 0)
break;
else // rv == 0
sleep(1);
}
 
if (rv != childs_pid) {
kill(childs_pid, SIGTERM);
printf("WARNING: Child/simulator did not terminate normally\n");
}
 
if (WEXITSTATUS(status) != EXIT_SUCCESS) {
printf("WARNING: Child/simulator exit status does not indicate success\n");
}
 
if ((nr == nw)&&(nw == (int)strlen(string))
&&(strcmp(test, string) == 0))
printf("SUCCESS!\n");
else
&&(strcmp(test, string) == 0)) {
printf("PASS!\n");
exit(EXIT_SUCCESS);
} else {
printf("TEST FAILED\n");
exit(EXIT_FAILURE);
}
} else {
close(childs_stdin[ 1]);
close(childs_stdout[0]);
173,9 → 199,25
// Make sure we don't run longer than 4 seconds ...
time_t start = time(NULL);
int iterations_before_check = 2048;
unsigned clocks = 0;
bool done = false;
 
for(int i=0; i<200000; i++) {
#define VCDTRACE
#ifdef VCDTRACE
Verilated::traceEverOn(true);
VerilatedVcdC* tfp = new VerilatedVcdC;
tb.trace(tfp, 99);
tfp->open("linetest.vcd");
#define TRACE_POSEDGE tfp->dump(10*clocks)
#define TRACE_NEGEDGE tfp->dump(10*clocks+5)
#define TRACE_CLOSE tfp->close()
#else
#define TRACE_POSEDGE while(0)
#define TRACE_NEGEDGE while(0)
#define TRACE_CLOSE while(0)
#endif
 
for(int i=0; i<(baudclocks*24); i++) {
// Clear any initial break condition
tb.i_clk = 1;
tb.eval();
182,18 → 224,22
tb.i_clk = 0;
tb.eval();
 
tb.i_uart = 1;
tb.i_uart_rx = 1;
}
 
while(!done) {
while(clocks < 2*(baudclocks*16)*strlen(string)) {
tb.i_clk = 1;
tb.eval();
TRACE_POSEDGE;
tb.i_clk = 0;
tb.eval();
TRACE_NEGEDGE;
clocks++;
 
tb.i_uart = (*uart)(tb.o_uart);
tb.i_uart_rx = (*uart)(tb.o_uart_tx);
 
if (false) {
/*
static long counts = 0;
static int lasti = 1, lasto = 1;
bool writeout = false;
220,7 → 266,7
tb.v__DOT__transmitter__DOT__state,
tb.v__DOT__transmitter__DOT__zero_baud_counter,
tb.v__DOT__transmitter__DOT__baud_counter);
}
} */
}
 
if (iterations_before_check-- <= 0) {
230,6 → 276,10
fprintf(stderr, "CHILD-TIMEOUT\n");
}
}
}
 
TRACE_CLOSE;
 
exit(EXIT_SUCCESS);
}
}
}
/cpp/mkspeech.cpp
0,0 → 1,98
////////////////////////////////////////////////////////////////////////////////
//
// Filename: mkspeech.cpp
//
// Project: wbuart32, a full featured UART with simulator
//
// Purpose: To turn a text file (i.e. the Gettysburg address) into a
// hex file that can be included via readmemh.
//
// 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 <stdlib.h>
#include <unistd.h>
#include <string.h>
 
int main(int argc, char **argv) {
FILE *fp, *fout;
 
if (argc != 2) {
fprintf(stderr, "Err: USAGE is mkspeech <filename>.txt\n");
exit(EXIT_FAILURE);
} else if ((!argv[1])||(strlen(argv[1])<5)
||(strcmp(&argv[1][strlen(argv[1])-4], ".txt")!=0)) {
fprintf(stderr, "Err: %s is an invalid text file name\n", argv[1]);
exit(EXIT_FAILURE);
} else if (access(argv[1], F_OK)!=0) {
fprintf(stderr, "Err: %s is not a file\n", argv[1]);
exit(EXIT_FAILURE);
} else if (access(argv[1], R_OK)!=0) {
fprintf(stderr, "Err: Cannot read %s\n", argv[1]);
exit(EXIT_FAILURE);
}
 
fp = fopen(argv[1], "r");
if (fp == NULL) {
fprintf(stderr, "Err: Cannot read %s\n", argv[1]);
exit(EXIT_FAILURE);
}
 
fout = fopen("speech.hex", "w");
if (fout == NULL) {
fprintf(stderr, "Err: Cannot write %s\n", "speech.hex");
exit(EXIT_FAILURE);
}
 
int linelen = 0;
int ch, addr = 0;
 
fprintf(fout, "@%08x ", addr); linelen += 4+6;
while((ch = fgetc(fp))!=EOF) {
if (ch == '\n') {
fprintf(fout, "%02x ", '\r' & 0x0ff); linelen += 3; addr++;
if (linelen >= 77) {
fprintf(fout, "\n");
linelen = 0;
fprintf(fout, "@%08x ", addr); linelen += 4+6;
}
}
fprintf(fout, "%02x ", ch & 0x0ff); linelen += 3; addr++;
 
if (linelen >= 77) {
fprintf(fout, "\n");
linelen = 0;
fprintf(fout, "@%08x ", addr); linelen += 4+6;
}
} fprintf(fout, "\n");
 
fclose(fp);
fclose(fout);
}
/cpp/speech.txt
0,0 → 1,24
Four score and seven years ago our fathers brought forth on this continent, a
new nation, conceived in Liberty, and dedicated to the proposition that all men
are created equal.
 
Now we are engaged in a great civil war, testing whether that nation, or any
nation so conceived and so dedicated, can long endure. We are met on a great
battle-field of that war. We have come to dedicate a portion of that field, as
a final resting place for those who here gave their lives that that nation
might live. It is altogether fitting and proper that we should do this.
 
But, in a larger sense, we can not dedicate-we can not consecrate-we can not
hallow-this ground. The brave men, living and dead, who struggled here, have
consecrated it, far above our poor power to add or detract. The world will
little note, nor long remember what we say here, but it can never forget what
they did here. It is for us the living, rather, to be dedicated here to the
unfinished work which they who fought here have thus far so nobly advanced. It
is rather for us to be here dedicated to the great task remaining before
us-that from these honored dead we take increased devotion to that cause for
which they gave the last full measure of devotion-that we here highly resolve
that these dead shall not have died in vain-that this nation, under God, shall
have a new birth of freedom-and that government of the people, by the people,
for the people, shall not perish from the earth.
 
 
/cpp/speechtest.cpp
0,0 → 1,397
////////////////////////////////////////////////////////////////////////////////
//
// Filename: speechtest.cpp
//
// Project: wbuart32, a full featured UART with simulator
//
// Purpose: To demonstrate a useful Verilog file which could be used as a
// toplevel program later, to demo the transmit UART as it might
// be commanded from a WB bus, and having a FIFO.
//
// If all goes well, the program will write out the words of the Gettysburg
// address in interactive mode. In non-interactive mode, the program will
// read its own output and report on whether or not it worked well.
//
// 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 <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <signal.h>
#include <ctype.h>
#include "verilated.h"
#include "Vspeechfifo.h"
#include "uartsim.h"
#include "verilated_vcd_c.h"
 
void usage(void) {
fprintf(stderr, "USAGE: speechtest [-i] [<matchfile>.txt]\n");
fprintf(stderr, "\n"
"\tWhere ... \n"
"\t-i\tis an optional argument, instructing speechtest to run\n"
"\t\tinteractively. This mode offers no checkin against any possible\n"
"\t\ttruth or match file.\n"
"\n"
"\t<matchfile.txt>\t is the name of a file which will be compared against\n"
"\t\tthe output of the simulation. If the output matches the match\n"
"\t\tfile, the simulation will exit with success. Only the number of\n"
"\t\tcharacters in the match file will be tested.\n\n");
};
 
int main(int argc, char **argv) {
Verilated::commandArgs(argc, argv);
Vspeechfifo tb;
UARTSIM *uart;
int port = 0;
unsigned setup = 25, testcount = 0, baudclocks;
const char *matchfile = "speech.txt";
bool run_interactively = false;
 
for(int argn=1; argn<argc; argn++) {
if (argv[argn][0]=='-') for(int j=1; (j<1000)&&(argv[argn][j]); j++)
switch(argv[argn][j]) {
case 'i': run_interactively = true;
break;
default:
printf("Undefined option, -%c\n", argv[argn][j]);
usage();
exit(EXIT_FAILURE);
} else {
matchfile = argv[argn];
}
}
 
tb.i_setup = setup;
baudclocks = setup & 0x0ffffff;
 
if (run_interactively) {
//
// The difference between the non-interactive mode and the
// interactive mode is that in the interactive mode we don't
// get to observe the speech being output to stdout. Thus,
// we blindly run for a period of clocks, and then stop.
//
// The cool part of the interactive mode is that we can
// output internals from the simulation, for the purpose of
// debug by printf. We can also dump things to a VCD file,
// should you wish to run GTKwave.
//
uart = new UARTSIM(port);
uart->setup(tb.i_setup);
 
Verilated::traceEverOn(true);
VerilatedVcdC* tfp = new VerilatedVcdC;
tb.trace(tfp, 99);
tfp->open("speechtrace.vcd");
 
testcount = 0;
while(testcount < baudclocks * 16 * 2048) {
// Run one tick of the clock.
 
tb.i_clk = 1; // Positive edge
tb.eval();
tfp->dump(5*(2*testcount));
tb.i_clk = 0; // Negative edge
tb.eval();
 
// Now, evaluate the UART, throwing away the received
// value since the SpeechTest doesnt use it.
(*uart)(tb.o_uart_tx);
 
tfp->dump(5*(2*testcount+1));
testcount++;
 
// #define DEBUG
#ifdef DEBUG
//
// Here are my notes from my last attempt at debug by printf.
printf("%08x ",
tb.v__DOT__restart_counter);
printf("%s %s@%d<-%08x[%c/%4d] (%s%s,%08x,%2d,%2d,%2d,%c,%s) %s,%02x >%d\n",
(tb.v__DOT__restart)?"RST":" ",
(tb.v__DOT__wb_stb)?"STB":" ",
(tb.v__DOT__wb_addr),
(tb.v__DOT__wb_data),
isgraph(tb.v__DOT__wb_data&0x0ff)?
(tb.v__DOT__wb_data&0x0ff) : '.',
(tb.v__DOT__msg_index),
(tb.v__DOT__wbuarti__DOT____Vcellinp__txfifo____pinNumber2)?"RST":" ",
(tb.v__DOT__wbuarti__DOT__txf_wb_write)?"WR":" ",
(tb.v__DOT__wbuarti__DOT__txfifo__DOT__r_fill),
(tb.v__DOT__wbuarti__DOT__txfifo__DOT__r_first),
(tb.v__DOT__wbuarti__DOT__txfifo__DOT__w_first_plus_one),
(tb.v__DOT__wbuarti__DOT__txfifo__DOT__r_last),
isgraph(tb.v__DOT__wbuarti__DOT__tx_data&0x0ff)?
(tb.v__DOT__wbuarti__DOT__tx_data&0x0ff) : '.',
(tb.v__DOT__wbuarti__DOT____Vcellinp__txfifo____pinNumber5)?"RD":" ",
(tb.v__DOT__wbuarti__DOT__tx_empty_n)?"TXI":"EMP",
(tb.v__DOT__wbuarti__DOT__tx_data),
(tb.o_uart_tx));
#endif
}
 
tfp->close();
 
//
// *IF* we ever get here, then at least explain to the user
// why we stopped.
//
printf("\n\nSimulation complete\n");
} else {
//
// Non-interactive mode is more difficult. In this case, we
// must figure out how to determine if the test was successful
// or not. Since uartsim dumps the UART output to standard
// out, we then need to do a bit of work to capture that.
//
// In particular, we are going to fork ourselves and set up our
// child process so that we can read from its standard out
// (and write to its standard in--although we don't).
int childs_stdin[2], childs_stdout[2];
FILE *fp = fopen(matchfile, "r");
long flen = 0;
 
//
// Before forking (and getting complicated), let's read the
// file describing the data we are supposed to read. Our goal
// will basically be to do an strncmp with the data in this
// file, and then to check for zero (equality).
//
if (fp == NULL) {
fprintf(stderr, "ERR - could not open %s\n", matchfile);
perror("O/S Err:");
printf("FAIL\n");
exit(EXIT_FAILURE);
}
 
// Quick, look up how long this file is.
fseek(fp, 0l, SEEK_END);
flen = ftell(fp);
fseek(fp, 0l, SEEK_SET);
 
if (flen <= 0) {
if (flen == 0)
fprintf(stderr, "ERR - zero length match file!\n");
else {
fprintf(stderr, "ERR - getting file length\n");
perror("O/S Err:");
}
printf("FAIL\n");
exit(EXIT_FAILURE);
}
 
 
// We are ready to do our forking magic. So, let's allocate
// pipes for the childs standard input and output streams.
if ((pipe(childs_stdin)!=0)||(pipe(childs_stdout) != 0)) {
fprintf(stderr, "ERR setting up child pipes\n");
perror("O/S Err:");
printf("FAIL\n");
exit(EXIT_FAILURE);
}
 
//
// FORK !!!!!
//
// After this line, there are two threads running--a parent and
// a child. The childs child_pid will be zero, the parents
// child_pid will be the pid of the child.
pid_t child_pid = fork();
 
// Make sure the fork worked ...
if (child_pid < 0) {
fprintf(stderr, "ERR setting up child process fork\n");
perror("O/S Err:");
printf("FAIL\n");
exit(EXIT_FAILURE);
}
 
if (child_pid) {
int nr = -2, rd, fail;
 
// We are the parent
// Adjust our pipe file descriptors so that they are
// useful.
close(childs_stdin[ 0]); // Close the read end
close(childs_stdout[1]); // Close the write end
 
// Let's allocate some buffers to contain both our
// match file (string), and what we read from the
// UART. Nominally, we would only need flen+1
// characters, but this number doesn't quite work--since
// mkspeech turned all of the the LFs into CR/LF pairs.
// In the worst case, this would double the number of
// characters we would need. Hence, we read allocate
// enough for the worst case.
char *string = (char *)malloc((size_t)(2*flen+2)),
*rdbuf = (char *)malloc((size_t)(2*flen+2));
 
// If this doesn't work, admit to a failure
if ((string == NULL)||(rdbuf == NULL)) {
fprintf(stderr, "ERR Malloc failure --- cannot allocate space to read match file\n");
perror("O/S Err:");
printf("FAIL\n");
exit(EXIT_FAILURE);
}
 
// Read the string we are going to match against from
// the matchfile. Expand NLs into CR,NL pairs. Also
// keep track of the resulting length (in flen), and
// terminate the string with a null character.
//
{
// Read string, and expand newlines into
// CR LF pairs
char *dp = string;
int ch;
while((ch =fgetc(fp))!=EOF) {
if (ch == '\n')
*dp++ = '\r';
*dp++ = ch;
}
*dp++ = '\0';
flen = strlen(string);
}
 
//
// Enough setup, let's do our work: Read a character
// from the pipe and compare it against what we are
// expecting. Break out on any comparison failure.
//
nr = 0;
rd = 0;
fail = -1;
while((nr<flen)
&&((rd = read(childs_stdout[0],
&rdbuf[nr], 1))>0)) {
for(int i=0; i<rd; i++)
if (rdbuf[nr+i] != string[nr+i]) {
fail = nr+i;
break;
}
if (fail>=0)
break;
rdbuf[rd+nr] = 0;
nr += rd;
}
 
// Tell the user how many (of how many) characters we
// compared (that matched), for debugging purposes.
//
printf("MATCH COMPLETE, nr = %d (/ %ld)\n", nr, flen);
fflush(stdout);
 
kill(child_pid, SIGKILL);
 
free(string);
free(rdbuf);
 
// Report on the results, either PASS or FAIL
if (nr == flen) {
printf("PASS\n");
exit(EXIT_SUCCESS);
} else {
printf("%s\n\nDoes not match. MISMATCH: ch[%d]=%c != %c (%02x)\nFAIL\n", rdbuf, fail, rdbuf[fail], string[fail], string[fail]);
exit(EXIT_FAILURE);
}
//
// At this point, the parent is complete, and can
// exit.
} else {
//
// If childs_pid == 0, then we are the child
//
// The child reports the uart result via stdout, so
// let's make certain it points to STDOUT_FILENO.
//
close(childs_stdin[ 1]); // Close the write end
close(childs_stdout[0]); // Close the read end
 
// Now, adjust our stdin/stdout file numbers
// Stdin first. (Yes, I know we arent use stdin, this
// is more for form than anything else.)
close(STDIN_FILENO);
if (dup(childs_stdin[0]) != STDIN_FILENO) {
fprintf(stderr, "Could not create childs stdin\n");
perror("O/S ERR");
exit(EXIT_FAILURE);
}
 
// Set up the standard out file descriptor so that it
// points to our pipe
close(STDOUT_FILENO);
if (dup(childs_stdout[1]) != STDOUT_FILENO) {
fprintf(stderr, "Could not create childs stdout\n");
perror("O/S ERR");
exit(EXIT_FAILURE);
}
 
// Set the UARTSIM up to producing an output to the
// STDOUT, rather than a TCP/IP port
uart = new UARTSIM(0);
// Set up our baud rate, stop bits, parity, etc.
// properly
uart->setup(tb.i_setup);
 
//
// Now ... we're finally ready to run our simulation.
//
// while(testcount < baudclocks * 16 * 2048)
while(testcount++ < 0x7f000000) {
// Rising edge of the clock
tb.i_clk = 1;
tb.eval();
// Negative edge of the clock
tb.i_clk = 0;
tb.eval();
 
// Advance the UART based upon the output
// o_uart_tx value
(*uart)(tb.o_uart_tx);
}
 
// We will never get here. If all goes well, we will be
// killed as soon as we produce the speech.txt file
// output--many clocks before this.
//
// If we do get here, something is terribly wrong.
//
fprintf(stderr, "Child was never killed, did it produce any output?\n");
fprintf(stderr, "FAIL\n");
exit(EXIT_FAILURE);
}
}
}
 
/verilog/Makefile
8,9 → 8,38
## bench test. The result is C++ code (built by Verilator), that
## is then built (herein) into a library.
##
## Targets: The default target, all, builds the target test, which includes
## the linetest Verilator library necessary for testing.
## ALTERNATE_PURPOSE:
## All of the Verilog files within this directory may be made top level
## files in their own right for the purpose of testing the UART capability
## of your board. Should you wish to test these as toplevel files, you
## will need to remove the i_setup from the input, and set it to something
## like:
## wire [29:0] i_setup;
##
## // If we have a 100MHz clock, then we can set up for a 115,200
## // baud clock by setting i_setup to (100MHz / 115200) ~= 868.
## // The upper bits of this number also set the protocol to
## // one stop bit, no parity, and 8 data bits.
## assign i_setup = 30'd868; // 115,200 Baud 8N1
##
## Using this purpose, the UART ports of a new piece of hardware may be
## proven. To do this,
## 1. get BLINKY working first--to prove that the clock works like
## you think it does. Then, once BLINKY is running,
## 2. get helloworld working. This requires only the clock and
## the output UART pin to work.
## (Aside) 3. Once helloworld works, you should be able to get
## speechfifo to work with no further hassles.
## 4. After helloworld works, switch to getting linetest running on
## your hardware. This will prove that you have not only
## the clock and output UART pin working, but that you also
## have the input UART pin working as well.
##
## Targets: The default target of this makefile, all, builds the target
## test, which includes the linetest Verilator library, the
## helloworld Verilator library, and the speechfifo Verilator library--all
## necessary for bench testing using the C++ files in bench/cpp.
##
## Creator: Dan Gisselquist, Ph.D.
## Gisselquist Technology, LLC
##
46,8 → 75,11
VDIRFB:= $(FBDIR)/obj_dir
RTLDR := ../../rtl
 
.PHONY: test
test: $(VDIRFB)/Vlinetest__ALL.a
.PHONY: test testline testhello speechfifo
test: testline testhello speechfifo
testline: $(VDIRFB)/Vlinetest__ALL.a
testhello: $(VDIRFB)/Vhelloworld__ALL.a
speechfifo: $(VDIRFB)/Vspeechfifo__ALL.a
 
$(VDIRFB)/Vlinetest__ALL.a: $(VDIRFB)/Vlinetest.h $(VDIRFB)/Vlinetest.cpp
$(VDIRFB)/Vlinetest__ALL.a: $(VDIRFB)/Vlinetest.mk
54,8 → 86,19
$(VDIRFB)/Vlinetest.h $(VDIRFB)/Vlinetest.cpp $(VDIRFB)/Vlinetest.mk: linetest.v
$(VDIRFB)/Vlinetest.h $(VDIRFB)/Vlinetest.cpp $(VDIRFB)/Vlinetest.mk: $(RTLDR)/rxuart.v $(RTLDR)/txuart.v
 
$(VDIRFB)/Vhelloworld__ALL.a: $(VDIRFB)/Vhelloworld.h $(VDIRFB)/Vhelloworld.cpp
$(VDIRFB)/Vhelloworld__ALL.a: $(VDIRFB)/Vhelloworld.mk
$(VDIRFB)/Vhelloworld.h $(VDIRFB)/Vhelloworld.cpp $(VDIRFB)/Vhelloworld.mk: helloworld.v
$(VDIRFB)/Vhelloworld.h $(VDIRFB)/Vhelloworld.cpp $(VDIRFB)/Vhelloworld.mk: $(RTLDR)/rxuart.v $(RTLDR)/txuart.v
 
SPEECHSRCS := $(addprefix $(RTLDR)/,rxuart.v txuart.v ufifo.v wbuart.v)
SPEECHVFILES:= $(addprefix $(VDIRFB)/,Vspeechfifo.h Vspeechfifo.cpp Vspeechfifo.mk)
$(VDIRFB)/Vspeechfifo__ALL.a: $(VDIRFB)/Vspeechfifo.h $(VDIRFB)/Vspeechfifo.cpp
$(VDIRFB)/Vspeechfifo__ALL.a: $(VDIRFB)/Vspeechfifo.mk
$(SPEECHVFILES): speechfifo.v $(SPEECHSRCS)
 
$(VDIRFB)/V%.cpp $(VDIRFB)/V%.h $(VDIRFB)/V%.mk: $(FBDIR)/%.v
verilator -cc -y ../../rtl $*.v
verilator --trace -cc -y ../../rtl $*.v
 
$(VDIRFB)/V%__ALL.a: $(VDIRFB)/V%.mk
cd $(VDIRFB); make -f V$*.mk
/verilog/README.md
0,0 → 1,14
This directory contains three basic configurations for testing your UART
and proving that it works:
- helloworld: Displays the familiar "Hello, World!" message over and over. Tests the transmit UART port.
- linetest: Reads a line of text, then parrots it back. Tests both receive and transmit UART.
- speechfifo: Recites the Gettysburg address over and over again. This can be used to test the transmit UART port, and particularly to test receivers to see if they can receive 1400+ characters at full speed without any problems.
 
Each of these configurations has a commented line defining OPT_STANDALONE within
it. If you uncomment this line, the configurations may be run as stand alone
configurations. (You will probably want to adjust the baud clock divider, to
be specific to the baud rate you wish to generate as well as the clock rate
you will be generating this from.)
 
If you leave OPT_STANDALONE commented, these demo programs should work quite
nicely with a Verilator based simulation.
/verilog/helloworld.v
0,0 → 1,127
////////////////////////////////////////////////////////////////////////////////
//
// Filename: helloworld.v
//
// Project: wbuart32, a full featured UART with simulator
//
// Purpose: To create a *very* simple UART test program, which can be used
// as the top level design file of any FPGA program.
//
// With some modifications (discussed below), this RTL should be able to
// run as a top-level testing file, requiring only the UART and clock pin
// to work.
//
// 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
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
// Uncomment the next line if you want this program to work as a standalone
// (not verilated) RTL "program" to test your UART. You'll also need to set
// your setup condition properly, though. I recommend setting it to the
// ratio of your onboard clock to your desired baud rate. For more information
// about how to set this, please see the specification.
//
//`define OPT_STANDALONE
//
module helloworld(i_clk,
`ifndef OPT_STANDALONE
i_setup,
`endif
o_uart_tx);
//
input i_clk;
output wire o_uart_tx;
`ifndef OPT_STANDALONE
input [29:0] i_setup;
`endif
 
// If i_setup isnt set up as an input parameter, it needs to be set.
// We do so here, to a setting appropriate to create a 115200 Baud
// comms system from a 100MHz clock. This also sets us to an 8-bit
// data word, 1-stop bit, and no parity.
`ifdef OPT_STANDALONE
wire [29:0] i_setup;
assign i_setup = 30'd868; // 115200 Baud, if clk @ 100MHz
`endif
 
reg pwr_reset;
initial pwr_reset = 1'b1;
always @(posedge i_clk)
pwr_reset <= 1'b0;
 
reg [7:0] message [0:15];
initial begin
message[ 0] = "H";
message[ 1] = "e";
message[ 2] = "l";
message[ 3] = "l";
message[ 4] = "o";
message[ 5] = ",";
message[ 6] = " ";
message[ 7] = "W";
message[ 8] = "o";
message[ 9] = "r";
message[10] = "l";
message[11] = "d";
message[12] = "!";
message[13] = " ";
message[14] = "\r";
message[15] = "\n";
end
 
reg [27:0] counter;
initial counter = 28'hffffff0;
always @(posedge i_clk)
counter <= counter + 1'b1;
 
wire tx_break, tx_busy;
reg tx_stb;
reg [3:0] tx_index;
reg [7:0] tx_data;
 
assign tx_break = 1'b0;
 
initial tx_index = 4'h0;
always @(posedge i_clk)
if ((tx_stb)&&(!tx_busy))
tx_index <= tx_index + 1'b1;
always @(posedge i_clk)
tx_data <= message[tx_index];
 
initial tx_stb = 1'b0;
always @(posedge i_clk)
if (&counter)
tx_stb <= 1'b1;
else if ((tx_stb)&&(!tx_busy)&&(tx_index==4'hf))
tx_stb <= 1'b0;
 
txuart transmitter(i_clk, pwr_reset, i_setup, tx_break,
tx_stb, tx_data, o_uart_tx, tx_busy);
 
endmodule
/verilog/linetest.v
8,6 → 8,10
// buffering one line's worth of input, and then piping that line
// to the transmitter while (possibly) receiving a new line.
//
// With some modifications (discussed below), this RTL should be able to
// run as a top-level testing file, requiring only the transmit and receive
// UART pins and the clock to work.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
37,31 → 41,85
////////////////////////////////////////////////////////////////////////////////
//
//
module linetest(i_clk, i_setup, i_uart, o_uart);
// Uncomment the next line if you want this program to work as a standalone
// (not verilated) RTL "program" to test your UART. You'll also need to set
// your setup condition properly, though. I recommend setting it to the
// ratio of your onboard clock to your desired baud rate. For more information
// about how to set this, please see the specification.
//
// `define OPT_STANDALONE
//
module linetest(i_clk,
`ifndef OPT_STANDALONE
i_setup,
`endif
i_uart_rx, o_uart_tx);
input i_clk;
`ifndef OPT_STANDALONE
input [29:0] i_setup;
input i_uart;
output wire o_uart;
`endif
input i_uart_rx;
output wire o_uart_tx;
 
// If i_setup isnt set up as an input parameter, it needs to be set.
// We do so here, to a setting appropriate to create a 115200 Baud
// comms system from a 100MHz clock. This also sets us to an 8-bit
// data word, 1-stop bit, and no parity.
`ifdef OPT_STANDALONE
wire [29:0] i_setup;
assign i_setup = 30'd868; // 115200 Baud, if clk @ 100MHz
`endif
 
reg [7:0] buffer [0:255];
reg [7:0] head, tail;
 
// Create a reset line that will always be true on a power on reset
reg pwr_reset;
initial pwr_reset = 1'b1;
always @(posedge i_clk)
pwr_reset = 1'b0;
 
 
 
// The UART Receiver
//
// This is where everything begins, by reading data from the UART.
//
// Data (rx_data) is present when rx_stb is true. Any parity or
// frame errors will also be valid at that time. Finally, we'll ignore
// errors, and even the clocked uart input distributed from here.
wire rx_stb, rx_break, rx_perr, rx_ferr, rx_ignored;
wire [7:0] rx_data;
 
rxuart receiver(i_clk, pwr_reset, i_setup, i_uart, rx_stb, rx_data,
rxuart receiver(i_clk, pwr_reset, i_setup, i_uart_rx, rx_stb, rx_data,
rx_break, rx_perr, rx_ferr, rx_ignored);
 
 
// The next step in this process is to dump everything we read into a
// FIFO. First step: writing into the FIFO. Always write into FIFO
// memory. (The next step will step the memory address if rx_stb was
// true ...)
wire [7:0] nxt_head;
assign nxt_head = head + 8'h01;
always @(posedge i_clk)
buffer[head] <= rx_data;
 
// Select where in our FIFO memory to write. On reset, we clear the
// memory. In all other cases/respects, we step the memory forward.
//
// However ... we won't step it forward IF ...
// rx_break - we are in a BREAK condition on the line
// (i.e. ... it's disconnected)
// rx_perr - We've seen a parity error
// rx_ferr - Same thing for a frame error
// nxt_head != tail - If the FIFO is already full, we'll just drop
// this new value, rather than dumping random garbage
// from the FIFO until we go round again ... i.e., we
// don't write on potential overflow.
//
// Adjusting this address will make certain that the next write to the
// FIFO goes to the next address--since we've already written the FIFO
// memory at this address.
initial head= 8'h00;
always @(posedge i_clk)
if (pwr_reset)
73,8 → 131,19
reg [7:0] lineend;
reg run_tx;
 
// How much of the FIFO is in use? head - tail. What if they wrap
// around? Still: head-tail, but this time truncated to the number of
// bits of interest. It can never be negative ... so ... we're good,
// this just measures that number.
assign nused = head-tail;
 
// Here's the guts of the algorithm--setting run_tx. Once set, the
// buffer will flush. Here, we set it on one of two conditions: 1)
// a newline is received, or 2) the line is now longer than 80
// characters.
//
// Once the line has ben transmitted (separate from emptying the buffer)
// we stop transmitting.
initial run_tx = 0;
initial lineend = 0;
always @(posedge i_clk)
82,27 → 151,43
begin
run_tx <= 1'b0;
lineend <= 8'h00;
end else if ((rx_data == 8'h0a)&&(rx_stb))
end else if(((rx_data == 8'h0a)||(rx_data == 8'hd))&&(rx_stb))
begin
// Start transmitting once we get to either a newline
// or a carriage return character
lineend <= head+8'h1;
run_tx <= 1'b1;
end else if ((!run_tx)&&(nused>8'd80)&&(head != tail))
end else if ((!run_tx)&&(nused>8'd80))
begin
// Start transmitting once we get to 80 chars
lineend <= head;
run_tx <= 1'b1;
end else if (tail == lineend)
// Line buffer has been emptied
run_tx <= 1'b0;
 
// Now ... let's deal with the transmitter
wire tx_break, tx_busy;
assign tx_break = 1'b0;
reg [7:0] tx_data;
reg tx_stb;
 
always @(posedge i_clk)
tx_data <= buffer[tail];
// When do we wish to transmit?
//
// Any time run_tx is true--but we'll give it an extra clock.
initial tx_stb = 1'b0;
always @(posedge i_clk)
tx_stb <= run_tx;
 
// We'll transmit the data from our FIFO from ... wherever our tail
// is pointed.
always @(posedge i_clk)
tx_data <= buffer[tail];
 
// We increment the pointer to where we read from any time 1) we are
// requesting to transmit a character, and 2) the transmitter was not
// busy and thus accepted our request. At that time, increment the
// pointer, and we'll be ready for another round.
initial tail = 8'h00;
always @(posedge i_clk)
if(pwr_reset)
111,6 → 196,6
tail <= tail + 8'h01;
txuart transmitter(i_clk, pwr_reset, i_setup, tx_break,
tx_stb, tx_data, o_uart, tx_busy);
tx_stb, tx_data, o_uart_tx, tx_busy);
 
endmodule
/verilog/speechfifo.v
0,0 → 1,211
////////////////////////////////////////////////////////////////////////////////
//
// Filename: speechfifo.v
//
// Project: wbuart32, a full featured UART with simulator
//
// Purpose: To test/demonstrate/prove the wishbone access to the FIFO'd
// UART via sending more information than the FIFO can hold,
// and then verifying that this was the value received.
//
// To do this, we "borrow" a copy of Abraham Lincolns Gettysburg address,
// make that the FIFO isn't large enough to hold it, and then try
// to send this address every couple of minutes.
//
// With some minor modifications (discussed below), this RTL should be
// able to be run as a top-level testing file, requiring only that the
// clock and the transmit UART pins be working.
//
// 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
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
// Uncomment the next line if you want this program to work as a standalone
// (not verilated) RTL "program" to test your UART. You'll also need to set
// your i_setup condition properly, though (below). I recommend setting it to
// the ratio of your onboard clock to your desired baud rate. For more
// information about how to set this, please see the specification.
//
//`define OPT_STANDALONE
//
module speechfifo(i_clk,
`ifndef OPT_STANDALONE
i_setup,
`endif
o_uart_tx);
input i_clk;
output wire o_uart_tx;
 
// The i_setup wires are input when run under Verilator, but need to
// be set internally if this is going to run as a standalone top level
// test configuration.
`ifdef OPT_STANDALONE
wire [29:0] i_setup;
 
// Here we set i_setup to something appropriate to create a 115200 Baud
// UART system from a 100MHz clock. This also sets us to an 8-bit data
// word, 1-stop bit, and no parity.
assign i_setup = 30'd868;
`else
input [29:0] i_setup;
`endif
 
reg wb_stb;
reg [1:0] wb_addr;
reg [31:0] wb_data;
 
wire uart_stall, uart_ack;
wire [31:0] uart_data;
 
wire tx_int, txfifo_int;
 
// The next four lines create a strobe signal that is true on the first
// clock, but never after. This makes for a decent power-on reset
// signal.
reg pwr_reset;
initial pwr_reset = 1'b1;
always @(posedge i_clk)
pwr_reset <= 1'b0;
 
// The message we wish to transmit is kept in "message". It needs to be
// set initially. Do so here.
//
// Since the message has fewer than 2048 elements in it, we preset every
// element to a space so that if (for some reason) we broadcast past the
// end of our message, we'll at least be sending something useful.
integer i;
reg [7:0] message [0:2047];
initial begin
for(i=0; i<2048; i=i+1)
message[i] = 8'h20;
$readmemh("speech.hex",message);
end
 
// Let's keep track of time, and send our message over and over again.
// To do this, we'll keep track of a restart counter. When this counter
// rolls over, we restart our message.
reg [30:0] restart_counter;
// Since we want to start our message just a couple clocks after power
// up, we'll set the reset counter just a couple clocks shy of a roll
// over.
initial restart_counter = -31'd16;
always @(posedge i_clk)
restart_counter <= restart_counter+1'b1;
 
// Ok, now that we have a counter that tells us when to start over,
// let's build a set of signals that we can use to get things started
// again. This will be the restart signal. On this signal, we just
// restart everything.
reg restart;
initial restart = 0;
always @(posedge i_clk)
begin
restart <= (restart_counter == 0);
end
 
// Our message index. This is the address of the character we wish to
// transmit next. Note, there's a clock delay between setting this
// index and when the wb_data is valid. Hence, we set the index on
// restart[0] to zero.
reg [10:0] msg_index;
initial msg_index = 11'd2040;
always @(posedge i_clk)
begin
if (restart)
msg_index <= 0;
else if ((wb_stb)&&(!uart_stall))
// We only advance the index if a port operation on the
// wbuart has taken place. That's what the
// (wb_stb)&&(!uart_stall) is about. (wb_stb) is the
// request for a transaction on the bus, uart_stall
// tells us to wait 'cause the peripheral isn't ready.
// In our case, it's always ready, uart_stall == 0, but
// we keep/maintain this logic for good form.
//
// Note also, we only advance when restart[0] is zero.
// This keeps us from advancing prior to the setup
// word.
msg_index <= msg_index + 1'b1;
end
 
// What data will we be sending to the port?
always @(posedge i_clk)
if (restart)
// The first thing we do is set the baud rate, and
// serial port configuration parameters. Ideally,
// we'd only set this once. But rather than complicate
// the logic, we set it everytime we start over.
wb_data <= { 2'b00, i_setup };
else if ((wb_stb)&&(!uart_stall))
// Then, if the last thing was received over the bus,
// we move to the next data item.
wb_data <= { 24'h00, message[msg_index] };
 
// We send our first value to the SETUP address (all zeros), all other
// values we send to the transmitters address. We should really be
// double checking that stall remains low, but its not required here.
always @(posedge i_clk)
if (restart)
wb_addr <= 2'b00;
else // if (!uart_stall)??
wb_addr <= 2'b11;
 
// The wb_stb signal indicates that we wish to write, using the wishbone
// to our peripheral. We have two separate types of writes. First,
// we wish to write our setup. Then we want to drop STB and write
// our data. Once we've filled half of the FIFO, we wait for the FIFO
// to empty before issuing a STB again and then fill up half the FIFO
// again.
initial wb_stb = 1'b0;
always @(posedge i_clk)
if (restart)
wb_stb <= 1'b1;
else if (msg_index >= 1481)
wb_stb <= 1'b0;
else if (tx_int)
wb_stb <= 1'b1;
else if (txfifo_int)
wb_stb <= wb_stb;
else
wb_stb <= 1'b0;
 
// We aren't using the receive interrupts, so we'll just mark them
// here as ignored.
wire ignored_rx_int, ignored_rxfifo_int;
 
// Finally--the unit under test--now that we've set up all the wires
// to run/test it.
wbuart #(30'h868)
wbuarti(i_clk, pwr_reset,
wb_stb, wb_stb, 1'b1, wb_addr, wb_data,
uart_stall, uart_ack, uart_data,
1'b1, o_uart_tx,
ignored_rx_int, tx_int,
ignored_rxfifo_int, txfifo_int);
 
endmodule

powered by: WebSVN 2.1.0

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