aboutsummaryrefslogtreecommitdiff
path: root/docs/j1/verilog/uart.v
diff options
context:
space:
mode:
Diffstat (limited to 'docs/j1/verilog/uart.v')
-rw-r--r--docs/j1/verilog/uart.v180
1 files changed, 180 insertions, 0 deletions
diff --git a/docs/j1/verilog/uart.v b/docs/j1/verilog/uart.v
new file mode 100644
index 0000000..4daac0f
--- /dev/null
+++ b/docs/j1/verilog/uart.v
@@ -0,0 +1,180 @@
+`default_nettype none
+
+module baudgen(
+ input wire clk,
+ input wire resetq,
+ input wire [31:0] baud,
+ input wire restart,
+ output wire ser_clk);
+ parameter CLKFREQ = 1000000;
+
+ wire [38:0] aclkfreq = CLKFREQ;
+ reg [38:0] d;
+ wire [38:0] dInc = d[38] ? ({4'd0, baud}) : (({4'd0, baud}) - aclkfreq);
+ wire [38:0] dN = restart ? 0 : (d + dInc);
+ wire fastclk = ~d[38];
+ assign ser_clk = fastclk;
+
+ always @(negedge resetq or posedge clk)
+ begin
+ if (!resetq) begin
+ d <= 0;
+ end else begin
+ d <= dN;
+ end
+ end
+endmodule
+
+/*
+
+-----+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+----
+ | | | | | | | | | | | |
+ |start| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |stop1|stop2|
+ | | | | | | | | | | | ? |
+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+ +
+
+*/
+
+module uart(
+ input wire clk, // System clock
+ input wire resetq,
+
+ // Outputs
+ output wire uart_busy, // High means UART is transmitting
+ output reg uart_tx, // UART transmit wire
+ // Inputs
+ input wire [31:0] baud,
+ input wire uart_wr_i, // Raise to transmit byte
+ input wire [7:0] uart_dat_i // 8-bit data
+);
+ parameter CLKFREQ = 1000000;
+
+ reg [3:0] bitcount;
+ reg [8:0] shifter;
+
+ assign uart_busy = |bitcount;
+ wire sending = |bitcount;
+
+ wire ser_clk;
+
+ wire starting = uart_wr_i & ~uart_busy;
+ baudgen #(.CLKFREQ(CLKFREQ)) _baudgen(
+ .clk(clk),
+ .resetq(resetq),
+ .baud(baud),
+ .restart(1'b0),
+ .ser_clk(ser_clk));
+
+ always @(negedge resetq or posedge clk)
+ begin
+ if (!resetq) begin
+ uart_tx <= 1;
+ bitcount <= 0;
+ shifter <= 0;
+ end else begin
+ if (starting) begin
+ shifter <= { uart_dat_i[7:0], 1'b0 };
+ bitcount <= 1 + 8 + 1;
+ end
+
+ if (sending & ser_clk) begin
+ { shifter, uart_tx } <= { 1'b1, shifter };
+ bitcount <= bitcount - 4'd1;
+ end
+ end
+ end
+
+endmodule
+
+module rxuart(
+ input wire clk,
+ input wire resetq,
+ input wire [31:0] baud,
+ input wire uart_rx, // UART recv wire
+ input wire rd, // read strobe
+ output wire valid, // has data
+ output wire [7:0] data); // data
+ parameter CLKFREQ = 1000000;
+
+ reg [4:0] bitcount;
+ reg [7:0] shifter;
+
+ // On starting edge, wait 3 half-bits then sample, and sample every 2 bits thereafter
+
+ wire idle = &bitcount;
+ wire sample;
+ reg [2:0] hh = 3'b111;
+ wire [2:0] hhN = {hh[1:0], uart_rx};
+ wire startbit = idle & (hhN[2:1] == 2'b10);
+ wire [7:0] shifterN = sample ? {hh[1], shifter[7:1]} : shifter;
+
+ wire ser_clk;
+ baudgen #(.CLKFREQ(CLKFREQ)) _baudgen(
+ .clk(clk),
+ .baud({baud[30:0], 1'b0}),
+ .resetq(resetq),
+ .restart(startbit),
+ .ser_clk(ser_clk));
+
+ assign valid = (bitcount == 18);
+ reg [4:0] bitcountN;
+ always @*
+ if (startbit)
+ bitcountN = 0;
+ else if (!idle & !valid & ser_clk)
+ bitcountN = bitcount + 5'd1;
+ else if (valid & rd)
+ bitcountN = 5'b11111;
+ else
+ bitcountN = bitcount;
+
+ // 3,5,7,9,11,13,15,17
+ assign sample = (bitcount > 2) & bitcount[0] & !valid & ser_clk;
+ assign data = shifter;
+
+ always @(negedge resetq or posedge clk)
+ begin
+ if (!resetq) begin
+ hh <= 3'b111;
+ bitcount <= 5'b11111;
+ shifter <= 0;
+ end else begin
+ hh <= hhN;
+ bitcount <= bitcountN;
+ shifter <= shifterN;
+ end
+ end
+endmodule
+
+module buart(
+ input wire clk,
+ input wire resetq,
+ input wire [31:0] baud,
+ input wire rx, // recv wire
+ output wire tx, // xmit wire
+ input wire rd, // read strobe
+ input wire wr, // write strobe
+ output wire valid, // has recv data
+ output wire busy, // is transmitting
+ input wire [7:0] tx_data,
+ output wire [7:0] rx_data // data
+);
+ parameter CLKFREQ = 1000000;
+
+ rxuart #(.CLKFREQ(CLKFREQ)) _rx (
+ .clk(clk),
+ .resetq(resetq),
+ .baud(baud),
+ .uart_rx(rx),
+ .rd(rd),
+ .valid(valid),
+ .data(rx_data));
+ uart #(.CLKFREQ(CLKFREQ)) _tx (
+ .clk(clk),
+ .resetq(resetq),
+ .baud(baud),
+ .uart_busy(busy),
+ .uart_tx(tx),
+ .uart_wr_i(wr),
+ .uart_dat_i(tx_data));
+endmodule