在设计和验证 FPGA 设计时,硬件描述语言 (HDL) 的使用正成为越来越重要的因素。行为级描述的使用不仅提高了设计生产力,而且在设计验证中提供了独特的优势。当今最主要的 HDL 称为 Verilog 和 VHDL。本应用说明 Verilog 在数字 UART(通用异步接收器和发送器)的设计和验证中的使用。
UART 由两个独立的 HDL 模块组成。一个模块实现发送器,而另一个模块实现接收器。发射器和接收器模块可以在设计的顶层进行组合,以实现所需的发射器和接收器通道的任意组合。数据可写入发送器并从接收器读出,全部通过单个 8 位双向 CPU 接口完成。发送器和接收器通道的地址映射可以轻松构建到设计顶层的接口中。两个模块共享一个名为 mclkx16 的公共主时钟。在每个模块内,mclkx16 被划分为独立的波特率时钟。
以下为相关Verilog代码
rxcver.v文件
/*******************************************************************
*
* DESCRIPTION: UART receiver module.
*
*******************************************************************/
module rxcver (mclkx16, read, rx, reset, rxrdy, parityerr, framingerr, overrun, data);
input mclkx16; // Input clock, 16 x baudrate clock used for synchronisation.
input read; // Read strobe.
input rx; // Receive input line.
input reset; // Global Reset.
// receive status & error signals
output rxrdy; // Received data ready to be read.
output parityerr; reg parityerr; // Receiver parity error detected.
output framingerr; reg framingerr; // Receiver framing error detected.
output overrun; reg overrun; // Receiver overrun error detected.
// 8 bit latched output data bus.
output [7:0] data; reg [7:0]data; // 8 bit output data bus
// Internal control signals.
reg [3:0] rxcnt; // Count of clock cycles
reg rx1, read1, read2, idle1, hunt; // Delayed versions of rx, read, idle, and last hunting for start bit flag.
// Receive shift register bits
reg [7:0] rhr; // Receive hold register
reg [7:0] rsr; // Receive seriel -> parallel shift register
reg rxparity; // Parity bit of received data
reg paritygen; // Generated parity of received data
reg rxstop; // Stop bit of received data
// wire paritymode = 1'b1; // Initializing to 1 = odd parity, 0 = even parity.
// Receive clock and control signals.
reg rxclk; // Receive data shift clock
reg idle; // 1'b1 when receiver is idling
reg rxdatardy; // 1'b1 when data is ready to be read
// Idle requires async preset since it is clocked by rxclk, and it's
// value determines whether rxclk gets generated or not.
// Idle goes low when shifting in data. This is ensured because all bits
// of rsr are preset to all 1's when idle is high. Idle goes high again
// when rsr[0] = 0, i.e. when the low "rxstop" bit reach rsr[0].
// Next rising edge of rxclk preset idle to high again, and generation of
// rxclk is disabled.
always @(posedge rxclk or posedge reset)
begin
if (reset)
idle <= 1'b1;
else
idle <= !idle && !rsr[0];
end
// Synchronizing rxclk to the centerpoint of low leading startbit.
always @(posedge mclkx16)
begin
// A start bit is eight clock times with rx=0 after a falling edge of rx.
if (reset)
hunt <= 1'b0;
else if (idle && !rx && rx1 )
hunt <= 1'b1; // Start hunting when idle and falling edge of rx is found.
else if (!idle || rx )
hunt <= 1'b0; // Stop hunting when shifting in data, or a 1 is found on rx.
if (!idle || hunt)
rxcnt <= rxcnt + 1; // Count clocks when not idle, or hunting for start bit.
else
rxcnt <= 4'b0001; // hold at 1, when idle and waiting for falling edge of rx.
rx1 <= rx; // delay rx one cycle of mclkx16, used for edge detection.
rxclk <= rxcnt[3]; // rxclk = mclkx16 divided by 16. First rising edge of rxclk occures
// always at the centerpoint of the low leading startbit.
end
// This task reset internal bit of receiver, when no data are received.
task idle_reset;
begin
rsr <= 8'b11111111; // All 1's ensure that idle stays low during data shifting.
rxparity <= 1'b1; // Preset to high to ensure idle = 0 during data shifting.
// paritygen <= paritymode; // Preset paritygen to parity mode.
paritygen <= 1'b1; // Preset to 1 => odd parity mode, 0 => even parity mode.
rxstop <= 1'b0; // Forces idle = 1, when rsr[0] gets rxstop bit.
end
endtask
// This task executes sampling & shifting of data, and generates parity result.
task shift_data;
begin
rsr <= rsr >> 1; // Right shift receive shift register.
rsr[7] <= rxparity; // Load rsr[7] with rxparity.
rxparity <= rxstop; // Load rxparity with rxstop.
rxstop <= rx; // Load rxstop with rx. At 1'st shift rxstop gets low "start bit".
paritygen <= paritygen ^ rxstop; // Generate parity as data are shifted.
end
endtask
// When not idling, sample data at the rx input, and generate parity.
always @(posedge rxclk or posedge reset)
if (reset)
idle_reset; // Reset internal bits.
else
begin
if (idle)
idle_reset; // Reset internal bits.
else
shift_data; // Shift data and generate parity.
end
// Generate status & error flags.
always @(posedge mclkx16 or posedge reset)
if (reset)
begin
rhr <= 8'h00;
rxdatardy <= 1'b0;
overrun <= 1'b0;
parityerr <= 1'b0;
framingerr <= 1'b0;
idle1 <= 1'b1;
read2 <= 1'b1;
read1 <= 1'b1;
end
else
begin
if (idle && !idle1) // Look for rising edge of idle and update output registers.
begin
if (rxdatardy)
overrun <= 1'b1; // Overrun error, if previous data still in holding register.
else
begin
overrun <= 1'b0; // No overrun error, since holding register is empty.
rhr <= rsr; // Update holding register with contens of shift register.
parityerr <= paritygen; // paritygen = 1, if parity error.
framingerr <= !rxstop; // Framingerror, if stop bit is not 1.
rxdatardy <= 1'b1; // Data is ready for reading flag.
end
end
if (!read2 && read1)
begin // Clear error and data registers when data is read.
rxdatardy <= 1'b0;
parityerr <= 1'b0;
framingerr <= 1'b0;
overrun <= 1'b0;
end
idle1 <= idle; // idle delayed 1 cycle for edge detect.
read2 <= read1; // 2 cycle delayed version of read, used for edge detection.
read1 <= read; // 1 cycle delayed version of read, used for edge detection.
end
assign rxrdy = rxdatardy; // Receive data ready output signal
always @(read or rhr) //Latch data output when read goes low.
if (~read)
data = rhr;
endmodule
txmit.v文件
/*******************************************************************
*
* DESCRIPTION: UART transmitter module.
*
*******************************************************************/
module txmit (mclkx16, write, reset, tx, txrdy, data);
input mclkx16; // Input clock, 16 x baudrate clock used for synchronization.
input write; // Transmit write strobe.
input reset; // Global reset.
output tx; reg tx; // Transmit data output.
output txrdy; // Transmitter ready to recieve next byte to be send
input [7:0] data; // 8 bit input data bus
reg write1, write2; // write signal delayed 1 and 2 cycles.
reg txdone1; // txdone signal delayed one cycle.
// Transmit shift register bits
reg [7:0] thr; // Transmit hold register
reg [7:0] tsr; // Transmit shift register, used for shifting out data to tx.
reg tag1, tag2; // Tag bits for used for detecting, when the tsr are empty.
wire paritymode = 1'b1; // Initializing to 1 = odd parity, 0 = even parity.
reg txparity; // Parity generation register.
// Transmit clock and other control signals
reg txclk; // Transmit clock, i.e. baudrate clock = 1/16'th of mclkx16.
wire txdone; // Set to high, when shifting of byte is done.
wire paritycycle; // Set to high, one cycle next to last shift cycle.
reg txdatardy; // Set to hign, when data is ready in transmit hold register.
reg [2:0] cnt; // Counter used for generating the internal baud rate clock.
// Paritycycle = 1 on next to last cycle, this means when tsr[1] gets tag2.
assign paritycycle = tsr[1] && !(tag2 || tag1 || tsr[7] || tsr[6] || tsr[5] || tsr[4] || tsr[3] || tsr[2]);
// txdone = 1 when done shifting, this means when tx gets tag2.
assign txdone = !(tag2 || tag1 || tsr[7] || tsr[6] || tsr[5] || tsr[4] || tsr[3] || tsr[2] || tsr[1] || tsr[0]);
// Ready for new date to be written, when no data is in transmit hold register.
assign txrdy = !txdatardy;
// Latch data[7:0] into the transmit hold register at posedge of write.
always @(write or data)
if (~write)
thr = data;
// Toggle txclk every 8 counts, which divides the clock by 16, to generate the baud clock
always @(posedge mclkx16 or posedge reset)
if (reset)
begin
txclk <= 1'b0;
cnt <= 3'b000;
end
else
begin
if (cnt == 3'b000)
txclk <= !txclk;
cnt <= cnt + 1;
end
task idle_reset;
begin // Apply pseudo Idle state, equal to end of transmission.
tsr <= 8'h00; // Reset transmit shift register.
tag2 <= 1'b0; // Reset tag bit.
tag1 <= 1'b0; // Reset tag bit.
// txparity <= paritymode; // Set parity mode for even or odd parity.
txparity <= 1'b0; // Reset txparty bit.
tx <= 1'b1; // At pseudo idle set Start bit high.
end
endtask
task load_data;
begin // Initialize registers and load next byte of data.
tsr <= thr; // Load tsr from thr.
tag2 <= 1'b1; // Set tag bits for detecting when shifting is done.
tag1 <= 1'b1; // Set tag bits for detecting when shifting is done.
txparity <= paritymode; // Set parity mode bit, 0 = even parity, 1 = odd parity
tx <= 1'b0; // Set start bit low.
end
endtask
task shift_data;
begin
tsr <= tsr >> 1; // Right shift tsr by one.
tsr[7] <= tag1; // Set tsr[7] = tag1.
tag1 <= tag2; // Set tag1 = tag2.
tag2 <= 1'b0; // Set tag2 = 0.
txparity <= txparity ^ tsr[0]; // Generate parity.
end
endtask
// Shifting out data to tx.
always @(posedge txclk or posedge reset)
if (reset)
idle_reset; // Reset internal bits of transmitter.
else
begin
if (txdone && txdatardy)
load_data; // Load new data to tsr.
else
begin
shift_data; // Shift contents of tsr to tx output.
// Shift out data or parity bit or stop/idle bit.
if (txdone )
tx <= 1'b1; // Output stop/idle bit.
else if (paritycycle)
tx <= txparity; // Output parity bit.
else
tx <= tsr[0]; //Shift out data bit.
end
end
always @(posedge mclkx16 or posedge reset)
if (reset)
begin
txdatardy <= 1'b0;
write2 <= 1'b1;
write1 <= 1'b1;
txdone1 <= 1'b1; // Set equal to txdone at reset.
end
else
begin
if (write1 && !write2)
txdatardy <= 1'b1; // At risign edge of write, new data are latched in thr, and txdatardy are set.
else if (!txdone && txdone1)
txdatardy <= 1'b0; // At falling edge of txdone, the thr has been loaded into tsr, so txdatardy are reset.
// Generate delayed versions of write and txdone signals for edge detection.
write2 <= write1;
write1 <= write;
txdone1 <= txdone;
end
endmodule
uart.v文件
/*******************************************************************
*
* DESCRIPTION: UART top level module implements full duplex UART function.
*
*******************************************************************/
//Includes Verilog HDL sources for Transmitter & receiver modules
`include "txmit.v"
`include "rxcver.v"
module uart (mclkx16, reset, read, write, data, rx, tx, rxrdy, txrdy, parityerr, framingerr, overrun);
input mclkx16; // Input clock, 16 x baud rate clock used for synchronisation.
input read; // read strobe input.
input write; // write strobe input.
input reset; // Master reset input.
inout [7:0] data; // Bidirectional data bus for writing to transmitter & reading from receiver.
// Receiver input signal, error and status flags.
input rx; // Receive data line input
output rxrdy; wire rxrdy; // Data ready to be read.
output parityerr; wire parityerr; // Parity error flag.
output framingerr; wire framingerr; // Framing error flag.
output overrun; wire overrun; // Overrun error flag.
wire [7:0] rxdata; // Intermediate output signals from receiver.
// Transmitter output signal and status flag.
output tx; wire tx; // Transmit data line output
output txrdy; wire txrdy; // Transmitter ready for next byte.
//Instantiation of the transmitter module.
txmit tx_1 (mclkx16, write, reset, tx, txrdy, data);
// Instantiation of the receiver module.
rxcver rx_1 (mclkx16, read, rx, reset, rxrdy, parityerr, framingerr, overrun, rxdata);
//Drives the databus during data read, otherwise tri-state the data bus.
assign data = !read ? rxdata : 8'bzzzzzzzz;
endmodule
更多回帖