1
2//
3// Copyright 2013 Ettus Research LLC
4// Copyright 2018 Ettus Research, a National Instruments Company
5//
6// SPDX-License-Identifier: LGPL-3.0-or-later
7//
8
9
10//create a compressed vita based uart data interface
11
12module cvita_uart
13#(
14    parameter SIZE = 0
15)
16(
17    //clocking interface
18    input clk, input rst,
19
20    //uart interface
21    input rxd, output txd,
22
23    //chdr fifo input
24    input [63:0] i_tdata,
25    input i_tlast,
26    input i_tvalid,
27    output i_tready,
28
29    //chdr fifo output
30    output [63:0] o_tdata,
31    output o_tlast,
32    output o_tvalid,
33    input o_tready
34);
35
36    reg [31:0] sid;
37
38    //baud clock divider
39    reg [15:0] clkdiv;
40
41    //hold rx in disable until a tx event
42    reg rxd_enable;
43
44    //==================================================================
45    //== RXD capture and packet generation interface
46    //==================================================================
47    wire [7:0] rx_char;
48    wire fifo_empty;
49    wire fifo_read;
50    reg [11:0] seqnum;
51    wire pgen_trigger;
52    wire pgen_done;
53
54    //rx uart capture
55    simple_uart_rx #(.SIZE(SIZE)) simple_uart_rx
56    (
57        .clk(clk), .rst(rst | ~rxd_enable),
58        .fifo_out(rx_char), .fifo_read(fifo_read), .fifo_level(), .fifo_empty(fifo_empty),
59        .clkdiv(clkdiv), .rx(rxd)
60    );
61
62    //packet generation - holds rx character
63    context_packet_gen context_packet_gen
64    (
65        .clk(clk), .reset(rst), .clear(1'b0),
66        .trigger(pgen_trigger),
67        .seqnum(seqnum),
68        .sid({sid[15:0], sid[31:16]}),
69        .body({56'b0, rx_char}),
70        .vita_time(64'b0),
71
72        .done(pgen_done),
73        .o_tdata(o_tdata), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready)
74    );
75
76    //state machine to manage pgen and rx uart
77    reg [1:0] rxd_state;
78    localparam RXD_STATE_RECV_CHAR = 0;
79    localparam RXD_STATE_PGEN_TRIG = 1;
80    localparam RXD_STATE_WAIT_DONE = 2;
81    localparam RXD_STATE_READ_FIFO = 3;
82
83    always @(posedge clk) begin
84        if (rst) begin
85            seqnum <= 12'b0;
86            rxd_state <= RXD_STATE_RECV_CHAR;
87        end
88        else case (rxd_state)
89
90        RXD_STATE_RECV_CHAR: begin
91            if (!fifo_empty && rxd_enable) rxd_state <= RXD_STATE_PGEN_TRIG;
92        end
93
94        RXD_STATE_PGEN_TRIG: begin
95            rxd_state <= RXD_STATE_WAIT_DONE;
96        end
97
98        RXD_STATE_WAIT_DONE: begin
99            if (pgen_done) rxd_state <= RXD_STATE_READ_FIFO;
100        end
101
102        RXD_STATE_READ_FIFO: begin
103            rxd_state <= RXD_STATE_RECV_CHAR;
104            seqnum <= seqnum + 1'b1;
105        end
106
107        endcase //rxd_state
108    end
109
110    assign fifo_read = (rxd_state == RXD_STATE_READ_FIFO) || (!rxd_enable);
111    assign pgen_trigger = (rxd_state == RXD_STATE_PGEN_TRIG);
112
113    //==================================================================
114    //== TXD generation and packet control interface
115    //==================================================================
116    wire [7:0] tx_char;
117    wire fifo_write;
118    wire fifo_full;
119
120    simple_uart_tx #(.SIZE(SIZE)) simple_uart_tx
121    (
122        .clk(clk), .rst(rst),
123        .fifo_in(tx_char), .fifo_write(fifo_write), .fifo_level(), .fifo_full(fifo_full),
124        .clkdiv(clkdiv), .baudclk(), .tx(txd)
125    );
126
127    //state machine to manage control and tx uart
128    reg [1:0] txd_state;
129    localparam TXD_STATE_RECV_CHDR = 0;
130    localparam TXD_STATE_RECV_TIME = 1;
131    localparam TXD_STATE_RECV_BODY = 2;
132    localparam TXD_STATE_DROP_FIFO = 3;
133
134    always @(posedge clk) begin
135        if (rst) begin;
136            txd_state <= TXD_STATE_RECV_CHDR;
137            rxd_enable <= 1'b0;
138        end
139        if (i_tvalid && i_tready) case (txd_state)
140
141        TXD_STATE_RECV_CHDR: begin
142            txd_state <= (i_tdata[61])? TXD_STATE_RECV_TIME : TXD_STATE_RECV_BODY;
143            sid <= i_tdata[31:0];
144        end
145
146        TXD_STATE_RECV_TIME: begin
147            txd_state <= TXD_STATE_RECV_BODY;
148        end
149
150        TXD_STATE_RECV_BODY: begin
151            txd_state <= (i_tlast)? TXD_STATE_RECV_CHDR : TXD_STATE_DROP_FIFO;
152            clkdiv <= i_tdata[47:32];
153            rxd_enable <= 1'b1;
154        end
155
156        TXD_STATE_DROP_FIFO: begin
157            if (i_tlast) txd_state <= TXD_STATE_RECV_CHDR;
158        end
159
160        endcase //txd_state
161    end
162
163    assign tx_char = i_tdata[7:0];
164    assign fifo_write = (txd_state == TXD_STATE_RECV_BODY) && i_tvalid && i_tready;
165    assign i_tready = !fifo_full;
166
167endmodule // cvita_uart
168