1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
// UART transmitter module.
// Transmits a frame: start bit (0), 8 data bits (LSB first), stop bit (1)
// at a baud rate determined by CLKS_PER_BIT (here: 10417 for 100MHz/9600)
module uart_tx (
input clk, // system clock: 100 MHz
input rst, // synchronous reset (active high)
input start, // one-cycle pulse to start transmission
input [7:0] data, // data byte to send
output reg tx, // serial output
output reg busy // high while transmitting the byte
);
// 100e6/9600 ≈ 10417 cycles per bit.
parameter CLKS_PER_BIT = 10417;
reg [13:0] clk_count; // counter for baud tick (14 bits is enough)
reg [ 3:0] bit_index; // counts from 0 to 9 (10 bits total: start, 8 data, stop)
reg [ 9:0] tx_frame; // complete frame: {stop bit, data[7:0], start bit}
always @(posedge clk) begin
if (rst) begin
busy <= 1'b0;
tx <= 1'b1; // idle state is high
clk_count <= 0;
bit_index <= 0;
end else begin
if (!busy) begin
if (start) begin
// Load frame: start bit (0), 8 data bits (LSB first), stop bit (1)
tx_frame <= {1'b1, data, 1'b0};
busy <= 1'b1;
clk_count <= 0;
bit_index <= 0;
tx <= 1'b0; // send start bit immediately
end else begin
tx <= 1'b1; // remain idle
end
end else begin
// When busy, count clocks for each bit period.
if (clk_count < CLKS_PER_BIT - 1) clk_count <= clk_count + 1;
else begin
clk_count <= 0;
bit_index <= bit_index + 1;
if (bit_index < 9) tx <= tx_frame[bit_index+1];
else begin
busy <= 1'b0;
tx <= 1'b1; // return to idle
end
end
end
end
end
endmodule
// Top-level module for the iCE40 HX8K FPGA.
// This module instantiates the UART transmitter and sends the bytes for
// "Hello" and a newline character, then stops.
module top (
input SYSCLK, // 100 MHz system clock
input SERIAL_RX, // Unused in this design; available as a pin
output SERIAL_TX // UART transmit output
);
// Create a simple synchronous reset signal.
// Here, we use a counter that holds reset high for a few hundred cycles.
reg [7:0] reset_cnt;
reg sys_rst;
always @(posedge SYSCLK) begin
if (reset_cnt != 8'd255) begin
reset_cnt <= reset_cnt + 1;
sys_rst <= 1'b1;
end else begin
sys_rst <= 1'b0;
end
end
// ROM for the message "Hello\n" (6 bytes)
reg [7:0] message[0:5];
initial begin
message[0] = "H"; // ASCII 72
message[1] = "e"; // ASCII 101
message[2] = "l"; // ASCII 108
message[3] = "l"; // ASCII 108
message[4] = "o"; // ASCII 111
message[5] = "\n"; // ASCII 10 (newline)
end
// Pointer to index through the message.
reg [2:0] index;
// One-cycle pulse to trigger transmission.
reg start_tx;
// Data byte to be transmitted.
reg [7:0] data_to_send;
// Busy flag from the transmitter.
wire tx_busy;
// State machine states.
localparam IDLE = 2'd0, WAIT_BUSY = 2'd1, WAIT_IDLE = 2'd2, DONE = 2'd3;
reg [1:0] state;
// Synchronous state machine with reset.
always @(posedge SYSCLK) begin
if (sys_rst) begin
// Initialize on reset.
state <= IDLE;
index <= 0;
start_tx <= 1'b0;
data_to_send <= 8'd0;
end else begin
case (state)
IDLE: begin
start_tx <= 1'b0;
if (index < 3'd6) begin
if (!tx_busy) begin
data_to_send <= message[index];
start_tx <= 1'b1; // trigger transmission
state <= WAIT_BUSY;
end
end else begin
state <= DONE;
end
end
// After issuing the start pulse, wait for tx_busy to go high.
WAIT_BUSY: begin
start_tx <= 1'b0; // ensure pulse is only one cycle.
if (tx_busy) state <= WAIT_IDLE;
end
// Wait for the transmitter to finish sending the byte.
WAIT_IDLE: begin
if (!tx_busy) begin
index <= index + 1; // move to next byte
state <= IDLE;
end
end
DONE: begin
start_tx <= 1'b0;
// Remain in DONE state; no further transmissions.
end
default: state <= IDLE;
endcase
end
end
// Instantiate the UART transmitter.
uart_tx uart_inst (
.clk (SYSCLK),
.rst (sys_rst), // Use our synchronous reset signal.
.start(start_tx), // One-cycle pulse to start transmission.
.data (data_to_send),
.tx (SERIAL_TX),
.busy (tx_busy)
);
endmodule
|