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

Subversion Repositories wbuart32

Compare Revisions

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

Rev 5 → Rev 6

/trunk/bench/cpp/helloworld.cpp
44,6 → 44,7
#include <sys/types.h>
#include <signal.h>
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "Vhelloworld.h"
#include "uartsim.h"
 
52,21 → 53,42
Vhelloworld tb;
UARTSIM *uart;
int port = 0;
unsigned setup = 25, testcount = 0;
unsigned setup = 868, clocks = 0, baudclocks;
 
tb.i_setup = setup;
uart = new UARTSIM(port);
uart->setup(tb.i_setup);
baudclocks = tb.i_setup & 0xfffffff;
 
while(testcount++ < 0x7f000000) {
#define VCDTRACE
#ifdef VCDTRACE
Verilated::traceEverOn(true);
VerilatedVcdC* tfp = new VerilatedVcdC;
tb.trace(tfp, 99);
tfp->open("helloworld.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
#define TRACE_NEGEDGE
#define TRACE_CLOSE
#endif
 
clocks = 0;
while(clocks < 16*32*baudclocks) {
 
tb.i_clk = 1;
tb.eval();
TRACE_POSEDGE;
tb.i_clk = 0;
tb.eval();
TRACE_NEGEDGE;
 
(*uart)(tb.o_uart_tx);
clocks++;
}
 
TRACE_CLOSE;
printf("\n\nSimulation complete\n");
}
/trunk/bench/verilog/echotest.v
0,0 → 1,138
////////////////////////////////////////////////////////////////////////////////
//
// Filename: echotest.v
//
// Project: wbuart32, a full featured UART with simulator
//
// Purpose: To test that the txuart and rxuart modules work properly, by
// echoing the input directly to the output.
//
// This module may be run as either a DUMBECHO, simply forwarding the input
// wire to the output with a touch of clock in between, or it can run as
// a smarter echo routine that decodes text before returning it. The
// difference depends upon whether or not OPT_DUMBECHO is defined, as
// discussed below.
//
// 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.
//
// DON'T FORGET TO TURN OFF HARDWARE FLOW CONTROL! ... or this'll never
// work. If you want to run with hardware flow control on, add another
// wire to this module in order to set o_cts to 1'b1.
//
//
// 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 defining OPT_DUMBECHO in order to test the wires
// and external functionality of any UART, independent of the UART protocol.
//
`define OPT_DUMBECHO
//
//
// 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 echotest(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;
`endif
input i_uart_rx;
output wire o_uart_tx;
 
`ifdef OPT_DUMBECHO
reg r_uart_tx;
 
initial r_uart_tx = 1'b1;
always @(posedge i_clk)
r_uart_tx <= i_uart_rx;
assign o_uart_tx = r_uart_tx;
`else
// This is the "smart" echo verion--one that decodes, and then
// re-encodes, values over the UART. There is a risk, though, doing
// things in this manner that the receive UART might run *just* a touch
// faster than the transmitter, and hence drop a bit every now and
// then. Hence, it works nicely for hand-testing, but not as nicely
// for high-speed UART testing.
 
 
 
// 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.
//
// This code only applies if OPT_DUMBECHO is not defined.
`ifdef OPT_STANDALONE
wire [29:0] i_setup;
assign i_setup = 30'd868; // 115200 Baud, if clk @ 100MHz
`endif
 
// 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.
//
// This code only applies if OPT_DUMBECHO is not defined.
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, rx_stb, rx_data,
rx_break, rx_perr, rx_ferr, rx_ignored);
 
wire tx_busy;
txuart transmitter(i_clk, pwr_reset, i_setup, rx_break,
rx_stb, rx_data, o_uart_tx, tx_busy);
 
`endif
 
endmodule
 
/trunk/bench/verilog/speechfifo.v
61,20 → 61,23
input i_clk;
output wire o_uart_tx;
 
// 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. This will be overwritten by
// i_setup, but at least it gives us something to start with/from.
parameter INITIAL_UART_SETUP = 30'd868;
 
// 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;
assign i_setup = INITIAL_UART_SETUP;
`else
input [29:0] i_setup;
`endif
 
reg restart;
reg wb_stb;
reg [1:0] wb_addr;
reg [31:0] wb_data;
101,9 → 104,9
integer i;
reg [7:0] message [0:2047];
initial begin
for(i=0; i<2048; i=i+1)
$readmemh("speech.hex",message);
for(i=1481; 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.
121,12 → 124,9
// 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
175,6 → 175,21
else // if (!uart_stall)??
wb_addr <= 2'b11;
 
// Knowing when to stop sending the speech is important, but depends
// upon an 11 bit comparison. Since FPGA logic is best measured by the
// number of inputs to an always block, we pull those 11-bits out of
// the always block for wb_stb, and place them here on the clock prior.
// If end_of_message is true, then we need to stop transmitting, and
// wait for the next (restart) to get us started again. We set that
// flag hee.
reg end_of_message;
initial end_of_message = 1'b1;
always @(posedge i_clk)
if (restart)
end_of_message <= 1'b0;
else
end_of_message <= (msg_index >= 1481);
 
// 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
184,14 → 199,26
initial wb_stb = 1'b0;
always @(posedge i_clk)
if (restart)
// Start sending to the UART on a reset. The first
// thing we'll send will be the configuration, but
// that's done elsewhere. This just starts up the
// writes to the peripheral wbuart.
wb_stb <= 1'b1;
else if (msg_index >= 1481)
else if (end_of_message)
// Stop transmitting when we get to the end of our
// message.
wb_stb <= 1'b0;
else if (tx_int)
// If we aren't at the end of the message, and tx_int
// tells us the FIFO is empty, then start writing into
// the FIFO>
wb_stb <= 1'b1;
else if (txfifo_int)
// If we are writing into the FIFO, and it's less than
// half full (i.e. txfifo_int is true) then keep going.
wb_stb <= wb_stb;
else
// But once the FIFO gets to half full, stop.
wb_stb <= 1'b0;
 
// We aren't using the receive interrupts, so we'll just mark them
200,7 → 227,7
 
// Finally--the unit under test--now that we've set up all the wires
// to run/test it.
wbuart #(30'h868)
wbuart #(INITIAL_UART_SETUP)
wbuarti(i_clk, pwr_reset,
wb_stb, wb_stb, 1'b1, wb_addr, wb_data,
uart_stall, uart_ack, uart_data,
/trunk/doc/spec.pdf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
/trunk/doc/src/spec.tex
210,7 → 210,8
 
Finally, there are a series of example files found in the bench/verilog
directory. {\tt helloworld.v} presents an example of a simple UART transmitter
sending the ``Hello, World \\r\\n'' message over and over again. This example
sending the ``Hello, World {\textbackslash}r{\textbackslash}n'' message over
and over again. This example
uses only the {\tt txuart.v} module, and can be simulated in Verilator.
A second test file, {\tt linetest.v}, works by waiting for a line of data to be
received, after which it parrots that line back to the terminal. This tests
351,6 → 352,19
\end{tabular}\caption{Parity setup}\label{tbl:parity}
\end{center}\end{table}
 
The final portion of this register is the baud {\tt CLKS}. This is the number
of ticks of your ssytem clock per baud interval,
\begin{eqnarray*}
{\tt CLKS} &=& \frac{f_{\mbox{\tiny SYS}}}{f_{\mbox{\tiny BAUD}}}.
\end{eqnarray*}
Rounding to the nearest integer is recommended. Hence, if you have a system
clock of 100~MHz and wish to achieve 115,200~Baud, you would set {\tt CLKS} to
\begin{eqnarray*}
{\tt CLKS}_{\tiny{\tt Example}} &=& \frac{100 \cdot 10^6}{115200}
\frac{\mbox{Clocks per Second}}{\mbox{Baud Intervals per Second}}
\approx 868 \mbox{ Clocks per Baud Interval}
\end{eqnarray*}
 
Changes to this setup register will take place in the transmitter as soon as
the transmitter is idle and ready to accept another byte.
 
/trunk/rtl/txuart.v
116,7 → 116,8
 
wire [27:0] clocks_per_baud, break_condition;
wire [1:0] data_bits;
wire use_parity, parity_even, dblstop, fixd_parity;
wire use_parity, parity_even, dblstop, fixd_parity,
fixdp_value;
reg [29:0] r_setup;
assign clocks_per_baud = { 4'h0, r_setup[23:0] };
assign break_condition = { r_setup[23:0], 4'h0 };
125,6 → 126,7
assign use_parity = r_setup[26];
assign fixd_parity = r_setup[25];
assign parity_even = r_setup[24];
assign fixdp_value = r_setup[24];
 
reg [27:0] baud_counter;
reg [3:0] state;
131,7 → 133,6
reg [7:0] lcl_data;
reg calc_parity, r_busy, zero_baud_counter;
 
initial r_setup = INITIAL_SETUP;
initial o_uart_tx = 1'b1;
initial r_busy = 1'b1;
initial state = `TXU_IDLE;
142,18 → 143,13
begin
if (i_reset)
begin
o_uart_tx <= 1'b1;
r_busy <= 1'b1;
state <= `TXU_IDLE;
lcl_data <= 8'h0;
calc_parity <= 1'b0;
end else if (i_break)
begin
o_uart_tx <= 1'b0;
state <= `TXU_BREAK;
calc_parity <= 1'b0;
r_busy <= 1'b1;
end else if (~zero_baud_counter)
end else if (!zero_baud_counter)
begin // r_busy needs to be set coming into here
r_busy <= 1'b1;
end else if (state == `TXU_BREAK)
160,16 → 156,10
begin
state <= `TXU_IDLE;
r_busy <= 1'b1;
o_uart_tx <= 1'b1;
calc_parity <= 1'b0;
end else if (state == `TXU_IDLE) // STATE_IDLE
begin
// baud_counter <= 0;
r_setup <= i_setup;
calc_parity <= 1'b0;
if ((i_wr)&&(~r_busy))
if ((i_wr)&&(!r_busy))
begin // Immediately start us off with a start bit
o_uart_tx <= 1'b0;
r_busy <= 1'b1;
case(data_bits)
2'b00: state <= `TXU_BIT_ZERO;
177,13 → 167,8
2'b10: state <= `TXU_BIT_TWO;
2'b11: state <= `TXU_BIT_THREE;
endcase
lcl_data <= i_data;
// baud_counter <= clocks_per_baud-28'h01;
end else begin // Stay in idle
o_uart_tx <= 1'b1;
r_busy <= 0;
// lcl_data is irrelevant
// state <= state;
end
end else begin
// One clock tick in each of these states ...
191,32 → 176,22
r_busy <= 1'b1;
if (state[3] == 0) // First 8 bits
begin
o_uart_tx <= lcl_data[0];
calc_parity <= calc_parity ^ lcl_data[0];
if (state == `TXU_BIT_SEVEN)
state <= (use_parity)?`TXU_PARITY:`TXU_STOP;
else
state <= state + 1;
lcl_data <= { 1'b0, lcl_data[7:1] };
end else if (state == `TXU_PARITY)
begin
state <= `TXU_STOP;
if (fixd_parity)
o_uart_tx <= parity_even;
else
o_uart_tx <= calc_parity^((parity_even)? 1'b1:1'b0);
end else if (state == `TXU_STOP)
begin // two stop bit(s)
o_uart_tx <= 1'b1;
if (dblstop)
state <= `TXU_SECOND_STOP;
else
state <= `TXU_IDLE;
calc_parity <= 1'b0;
end else // `TXU_SECOND_STOP and default:
begin
state <= `TXU_IDLE; // Go back to idle
o_uart_tx <= 1'b1;
// Still r_busy, since we need to wait
// for the baud clock to finish counting
// out this last bit.
224,9 → 199,129
end
end
 
// o_busy
//
// This is a wire, designed to be true is we are ever busy above.
// originally, this was going to be true if we were ever not in the
// idle state. The logic has since become more complex, hence we have
// a register dedicated to this and just copy out that registers value.
assign o_busy = (r_busy);
 
 
// r_setup
//
// Our setup register. Accept changes between any pair of transmitted
// words. The register itself has many fields to it. These are
// broken out up top, and indicate what 1) our baud rate is, 2) our
// number of stop bits, 3) what type of parity we are using, and 4)
// the size of our data word.
initial r_setup = INITIAL_SETUP;
always @(posedge i_clk)
if (state == `TXU_IDLE)
r_setup <= i_setup;
 
// lcl_data
//
// This is our working copy of the i_data register which we use
// when transmitting. It is only of interest during transmit, and is
// allowed to be whatever at any other time. Hence, if r_busy isn't
// true, we can always set it. On the one clock where r_busy isn't
// true and i_wr is, we set it and r_busy is true thereafter.
// Then, on any zero_baud_counter (i.e. change between baud intervals)
// we simple logically shift the register right to grab the next bit.
always @(posedge i_clk)
if (!r_busy)
lcl_data <= i_data;
else if (zero_baud_counter)
lcl_data <= { 1'b0, lcl_data[7:1] };
 
// o_uart_tx
//
// This is the final result/output desired of this core. It's all
// centered about o_uart_tx. This is what finally needs to follow
// the UART protocol.
//
// Ok, that said, our rules are:
// 1'b0 on any break condition
// 1'b0 on a start bit (IDLE, write, and not busy)
// lcl_data[0] during any data transfer, but only at the baud
// change
// PARITY -- During the parity bit. This depends upon whether or
// not the parity bit is fixed, then what it's fixed to,
// or changing, and hence what it's calculated value is.
// 1'b1 at all other times (stop bits, idle, etc)
always @(posedge i_clk)
if (i_reset)
o_uart_tx <= 1'b1;
else if ((i_break)||((i_wr)&&(!r_busy)))
o_uart_tx <= 1'b0;
else if (zero_baud_counter)
casez(state)
4'b0???: o_uart_tx <= lcl_data[0];
`TXU_PARITY: o_uart_tx <= calc_parity;
default: o_uart_tx <= 1'b1;
endcase
 
 
// calc_parity
//
// Calculate the parity to be placed into the parity bit. If the
// parity is fixed, then the parity bit is given by the fixed parity
// value (r_setup[24]). Otherwise the parity is given by the GF2
// sum of all the data bits (plus one for even parity).
always @(posedge i_clk)
if (fixd_parity)
calc_parity <= fixdp_value;
else if (zero_baud_counter)
begin
if (state[3] == 0) // First 8 bits of msg
calc_parity <= calc_parity ^ lcl_data[0];
else
calc_parity <= parity_even;
end else if (!r_busy)
calc_parity <= parity_even;
 
 
// All of the above logic is driven by the baud counter. Bits must last
// clocks_per_baud in length, and this baud counter is what we use to
// make certain of that.
//
// The basic logic is this: at the beginning of a bit interval, start
// the baud counter and set it to count clocks_per_baud. When it gets
// to zero, restart it.
//
// However, comparing a 28'bit number to zero can be rather complex--
// especially if we wish to do anything else on that same clock. For
// that reason, we create "zero_baud_counter". zero_baud_counter is
// nothing more than a flag that is true anytime baud_counter is zero.
// It's true when the logic (above) needs to step to the next bit.
// Simple enough?
//
// I wish we could stop there, but there are some other (ugly)
// conditions to deal with that offer exceptions to this basic logic.
//
// 1. When the user has commanded a BREAK across the line, we need to
// wait several baud intervals following the break before we start
// transmitting, to give any receiver a chance to recognize that we are
// out of the break condition, and to know that the next bit will be
// a stop bit.
//
// 2. A reset is similar to a break condition--on both we wait several
// baud intervals before allowing a start bit.
//
// 3. In the idle state, we stop our counter--so that upon a request
// to transmit when idle we can start transmitting immediately, rather
// than waiting for the end of the next (fictitious and arbitrary) baud
// interval.
//
// When (i_wr)&&(!r_busy)&&(state == `TXU_IDLE) then we're not only in
// the idle state, but we also just accepted a command to start writing
// the next word. At this point, the baud counter needs to be reset
// to the number of clocks per baud, and zero_baud_counter set to zero.
//
// The logic is a bit twisted here, in that it will only check for the
// above condition when zero_baud_counter is false--so as to make
// certain the STOP bit is complete.
initial zero_baud_counter = 1'b0;
initial baud_counter = 28'h05;
always @(posedge i_clk)
237,17 → 332,21
// Give ourselves 16 bauds before being ready
baud_counter <= break_condition;
zero_baud_counter <= 1'b0;
end else if (~zero_baud_counter)
end else if (!zero_baud_counter)
baud_counter <= baud_counter - 28'h01;
else if (state == `TXU_BREAK)
// Give us two stop bits before becoming available
// Give us four idle baud intervals before becoming
// available
baud_counter <= clocks_per_baud<<2;
else if (state == `TXU_IDLE)
begin
if((i_wr)&&(~r_busy))
baud_counter <= 28'h0;
zero_baud_counter <= 1'b1;
if ((i_wr)&&(!r_busy))
begin
baud_counter <= clocks_per_baud - 28'h01;
else
zero_baud_counter <= 1'b1;
zero_baud_counter <= 1'b0;
end
end else
baud_counter <= clocks_per_baud - 28'h01;
end
/trunk/rtl/ufifo.v
51,13 → 51,13
localparam FLEN=(1<<LGFLEN);
 
reg [(BW-1):0] fifo[0:(FLEN-1)];
reg [(LGFLEN-1):0] r_first, r_last;
reg [(LGFLEN-1):0] r_first, r_last, r_next;
 
wire [(LGFLEN-1):0] w_first_plus_one, w_first_plus_two,
w_last_plus_one;
assign w_first_plus_two = r_first + {{(LGFLEN-2){1'b0}},2'b10};
assign w_first_plus_one = r_first + {{(LGFLEN-1){1'b0}},1'b1};
assign w_last_plus_one = r_last + {{(LGFLEN-1){1'b0}},1'b1};
assign w_last_plus_one = r_next; // r_last + 1'b1;
 
reg will_overflow;
initial will_overflow = 1'b0;
120,17 → 120,20
always @(posedge i_clk)
if (i_rst)
begin
r_last <= { (LGFLEN){1'b0} };
r_last <= 0;
r_next <= { {(LGFLEN-1){1'b0}}, 1'b1 };
r_unfl <= 1'b0;
end else if (i_rd)
begin
if ((i_wr)||(!will_underflow)) // (r_first != r_last)
r_last <= w_last_plus_one;
begin
r_last <= r_next;
r_next <= r_last +{{(LGFLEN-2){1'b0}},2'b10};
// Last chases first
// Need to be prepared for a possible two
// reads in quick succession
// o_data <= fifo[r_last+1];
else
end else
r_unfl <= 1'b1;
end
 
138,7 → 141,7
always @(posedge i_clk)
fifo_here <= fifo[r_last];
always @(posedge i_clk)
fifo_next <= fifo[r_last+{{(LGFLEN-1){1'b0}},1'b1}];
fifo_next <= fifo[r_next];
always @(posedge i_clk)
r_data <= i_data;
 
173,7 → 176,7
if (i_rst)
r_fill <= 0;
else if ((i_rd)&&(!i_wr))
r_fill <= r_first - r_last - 1'b1;
r_fill <= r_first - r_next;
else if ((!i_rd)&&(i_wr))
r_fill <= r_first - r_last + 1'b1;
else
/trunk/rtl/wbuart.v
243,7 → 243,7
txf_wb_write, txf_wb_data,
(~tx_busy)&&(tx_empty_n), tx_data,
tx_empty_n, txf_half_full, txf_status, txf_err);
// Let's grab two interrupts from the FIFO for the CPU.
// Let's create two transmit based interrupts from the FIFO for the CPU.
// The first will be true any time the FIFO is empty.
assign o_uart_tx_int = !tx_empty_n;
// The second will be true any time the FIFO is less than half

powered by: WebSVN 2.1.0

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