Commit 8cb95d13 authored by Koen Martens's avatar Koen Martens

uart: implement receive logic in top-level module

parent 54273110
task simulate_sin(
input [TB_DATA_WIDTH-1:0] data,
input string message = "",
input integer clk_divider = 2,
input stop_bit = 1'b1,
input integer stop_clk_count = clk_divider*16
);
integer bit_index;
string formatted;
begin
tb_sin = 1'b0; // start bit
repeat(clk_divider*16) @(posedge clk);
bit_index = 0;
repeat(TB_DATA_WIDTH) begin
tb_sin = data[bit_index];
repeat(clk_divider*16) @(posedge clk);
bit_index += 1;
end
tb_sin = stop_bit; // stop bit
repeat(stop_clk_count) @(posedge clk);
end
endtask
......@@ -90,6 +90,7 @@ module receive #(
end else begin
framing_error_o = 1'b1;
state <= STATE_DATA;
data_bit <= 1;
end
end
end else begin
......
......@@ -50,29 +50,7 @@ module receive_tb();
`include "common/testbench_tasks/tb_assert.v"
task simulate_sin(
input [TB_DATA_WIDTH-1:0] data,
input string message = "",
input stop_bit = 1'b1,
input integer stop_clk_count = 32
);
integer bit_index;
string formatted;
begin
tb_sin = 1'b0; // start bit
repeat(32) @(posedge clk);
bit_index = 0;
repeat(TB_DATA_WIDTH) begin
tb_sin = data[bit_index];
repeat(32) @(posedge clk);
bit_index += 1;
end
tb_sin = stop_bit; // stop bit
repeat(stop_clk_count) @(posedge clk);
end
endtask
`include "common/testbench_tasks/simulate_sin.v"
integer counter;
......@@ -103,7 +81,7 @@ module receive_tb();
repeat(32) @(posedge clk);
simulate_sin(8'b01001011, "framing error", 1'b0, 16);
simulate_sin(8'b01001011, "framing error", 2, 1'b0, 16);
tb_assert(tb_framing_error_o===1'b1, "framing_error_o asserted after framing error");
repeat(16) begin
......
`include "wishbone/uart/transmit.v"
`include "wishbone/uart/receive.v"
module uart #(
parameter DATA_WIDTH = 8,
......@@ -57,44 +58,80 @@ module uart #(
.data_ready_i(~LSR_THRE)
);
wire [DATA_WIDTH-1:0] receiver_data;
reg receiver_data_latched;
wire receiver_data_ready;
wire receiver_framing_error;
receive #(
.DATA_WIDTH(DATA_WIDTH),
.DIVISOR_WIDTH(16)
) receiver (
.clk_i(clk_i),
.rst_i(rst_i),
.data_o(receiver_data),
.clk_divisor_i({DLM, DLL}),
.sin(sin),
.data_latched_i(receiver_data_latched),
.data_ready_o(receiver_data_ready),
.framing_error_o(receiver_framing_error)
);
always @(posedge clk_i) begin
if(rst_i) begin
RBR <= 'b0; THR <= 'b0; DLL <= 'b0; DLM <= 'b0;
THR <= 'b0; LCR <= 'b0;
LSR_OE = 1'b0; LSR_PE = 1'b0; LSR_FE = 1'b0; LSR_BI = 1'b0;
LSR_THRE = 1'b1; LSR_FIFO_ERROR = 1'b0; LSR_DR = 1'b0;
dat_o = {DATA_WIDTH{1'b0}}; ack_o = 1'b0;
LSR_OE <= 1'b0; LSR_PE <= 1'b0; LSR_FE <= 1'b0; LSR_BI <= 1'b0;
LSR_THRE <= 1'b1; LSR_FIFO_ERROR <= 1'b0; LSR_DR <= 1'b0;
dat_o <= {DATA_WIDTH{1'b0}}; ack_o <= 1'b0;
receiver_data_latched <= 1'b0;
end else begin
if(tsr_latched) LSR_THRE = 1'b1;
if(tsr_latched) LSR_THRE <= 1'b1;
if(receiver_framing_error) LSR_FE <= 1'b1;
if(receiver_data_latched) receiver_data_latched <= 1'b0;
if(receiver_data_ready & ~receiver_data_latched) begin
RBR <= receiver_data;
receiver_data_latched <= 1'b1;
LSR_DR <= 1'b1;
if(LSR_DR) LSR_OE <= 1'b1;
end
if (cyc_i & stb_i & ~ack_o) begin
if (we_i) begin
case(adr_i)
3'b000: // THR / DLL
if(LCR_DLAB) begin
DLL = dat_i;
DLL <= dat_i;
end else begin
THR = dat_i;
LSR_THRE = 1'b0;
THR <= dat_i;
LSR_THRE <= 1'b0;
end
3'b011: // LCR
LCR = dat_i;
LCR <= dat_i;
endcase
end
case(adr_i)
3'b000: dat_o = LCR_DLAB?DLL:RBR;
3'b011: dat_o = LCR;
3'b000:
begin
dat_o <= LCR_DLAB?DLL:RBR;
if(~LCR_DLAB) LSR_DR <= 1'b0;
end
3'b011: dat_o <= LCR;
3'b101:
begin
dat_o = LSR;
LSR_OE = 1'b0; LSR_PE = 1'b0; LSR_FE = 1'b0; LSR_BI = 1'b0;
dat_o <= LSR;
LSR_OE <= 1'b0; LSR_PE <= 1'b0; LSR_FE <= 1'b0; LSR_BI <= 1'b0;
end
default: dat_o = 'b0;
default: dat_o <= 'b0;
endcase
ack_o = 1'b1;
ack_o <= 1'b1;
end else begin
ack_o = 1'b0;
ack_o <= 1'b0;
end
end
end
......
......@@ -97,6 +97,8 @@ module uart_tb();
end
endtask
`include "common/testbench_tasks/simulate_sin.v"
reg [TB_DATA_WIDTH-1:0] read_data;
integer retry_count;
......@@ -105,7 +107,7 @@ module uart_tb();
$dumpvars(0, uart_tb);
tb_rst_i = 1'b1; tb_cyc_i = 1'b0; tb_stb_i = 1'b0; tb_we_i = 1'b0; tb_adr_i = 'b0; tb_dat_i = 'b0;
tb_sin = 'b0;
tb_sin = 'b1;
@(posedge clk);
@(negedge clk);
......@@ -174,6 +176,61 @@ module uart_tb();
tb_assert(tb_sout===1'b1, "sout 1 when idling");
end
repeat(12) @(posedge clk);
simulate_sin(8'b01001011, "K", TB_DIVIDER);
wb_read(5, read_data); // LSR
tb_assert(read_data[0]===1'b1, "DR asserted after rx byte 1");
tb_assert(read_data[1]===1'b0, "OE deasserted after rx byte 1");
tb_assert(read_data[3]===1'b0, "FE deasserted after rx byte 1");
wb_read(5, read_data); // LSR
tb_assert(read_data[0]===1'b1, "DR asserted after rx byte 1, 2nd");
tb_assert(read_data[1]===1'b0, "OE deasserted after rx byte 1, 2nd");
tb_assert(read_data[3]===1'b0, "FE deasserted after rx byte 1, 2nd");
wb_read(0, read_data); // RBR
tb_assert(read_data===8'b01001011);
wb_read(5, read_data); // LSR
tb_assert(read_data[0]===1'b0, "DR deasserted after rx byte 1 read RBR");
tb_assert(read_data[1]===1'b0, "OE deasserted after rx byte 1 read RBR");
tb_assert(read_data[3]===1'b0, "FE deasserted after rx byte 1 read RBR");
simulate_sin(8'b01001011, "K", TB_DIVIDER);
simulate_sin(8'b01000111, "G", TB_DIVIDER);
wb_read(5, read_data); // LSR
tb_assert(read_data[0]===1'b1, "DR asserted after rx byte 2&3");
tb_assert(read_data[1]===1'b1, "OE asserted after rx byte 2&3");
tb_assert(read_data[3]===1'b0, "FE deasserted after rx byte 2&3");
wb_read(5, read_data); // LSR
tb_assert(read_data[0]===1'b1, "DR asserted after rx byte 2&3, 2nd");
tb_assert(read_data[1]===1'b0, "OE deasserted after rx byte 2&3, 2nd");
tb_assert(read_data[3]===1'b0, "FE deasserted after rx byte 2&3, 2nd");
wb_read(0, read_data); // RBR
tb_assert(read_data===8'b01000111);
wb_read(5, read_data); // LSR
tb_assert(read_data[0]===1'b0, "DR deasserted after rx byte 3 read RBR");
tb_assert(read_data[1]===1'b0, "OE deasserted after rx byte 3 read RBR");
tb_assert(read_data[3]===1'b0, "FE deasserted after rx byte 3 read RBR");
simulate_sin(8'b01001011, "K", TB_DIVIDER, 1'b0);
wb_read(5, read_data); // LSR
tb_assert(read_data[0]===1'b0, "DR deasserted after rx byte 4");
tb_assert(read_data[1]===1'b0, "OE deasserted after rx byte 4");
tb_assert(read_data[3]===1'b1, "FE asserted after rx byte 4");
wb_read(5, read_data); // LSR
tb_assert(read_data[0]===1'b0, "DR deasserted after rx byte 4, 2nd");
tb_assert(read_data[1]===1'b0, "OE deasserted after rx byte 4, 2nd");
tb_assert(read_data[3]===1'b0, "FE deasserted after rx byte 4, 2nd");
$display("passed");
$finish;
end
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment