-
Notifications
You must be signed in to change notification settings - Fork 0
/
serial_rx.v
94 lines (84 loc) · 2.4 KB
/
serial_rx.v
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
module serial_rx #(
parameter CLK_PER_BIT = 50
)(
input clk,
input rst,
input rx,
output [7:0] data,
output new_data
);
// clog2 is 'ceiling of log base 2' which gives you the number of bits needed to store a value
parameter CTR_SIZE = $clog2(CLK_PER_BIT);
localparam STATE_SIZE = 2;
localparam IDLE = 2'd0,
WAIT_HALF = 2'd1,
WAIT_FULL = 2'd2,
WAIT_HIGH = 2'd3;
reg [CTR_SIZE-1:0] ctr_d, ctr_q;
reg [2:0] bit_ctr_d, bit_ctr_q;
reg [7:0] data_d, data_q;
reg new_data_d, new_data_q;
reg [STATE_SIZE-1:0] state_d, state_q = IDLE;
reg rx_d, rx_q;
assign new_data = new_data_q;
assign data = data_q;
always @(*) begin
rx_d = rx;
state_d = state_q;
ctr_d = ctr_q;
bit_ctr_d = bit_ctr_q;
data_d = data_q;
new_data_d = 1'b0;
case (state_q)
IDLE: begin
bit_ctr_d = 3'b0;
ctr_d = 1'b0;
if (rx_q == 1'b0) begin
state_d = WAIT_HALF;
end
end
WAIT_HALF: begin
ctr_d = ctr_q + 1'b1;
if (ctr_q == (CLK_PER_BIT >> 1)) begin
ctr_d = 1'b0;
state_d = WAIT_FULL;
end
end
WAIT_FULL: begin
ctr_d = ctr_q + 1'b1;
if (ctr_q == CLK_PER_BIT - 1) begin
data_d = {rx_q, data_q[7:1]};
bit_ctr_d = bit_ctr_q + 1'b1;
ctr_d = 1'b0;
if (bit_ctr_q == 3'd7) begin
state_d = WAIT_HIGH;
new_data_d = 1'b1;
end
end
end
WAIT_HIGH: begin
if (rx_q == 1'b1) begin
state_d = IDLE;
end
end
default: begin
state_d = IDLE;
end
endcase
end
always @(posedge clk) begin
if (rst) begin
ctr_q <= 1'b0;
bit_ctr_q <= 3'b0;
new_data_q <= 1'b0;
state_q <= IDLE;
end else begin
ctr_q <= ctr_d;
bit_ctr_q <= bit_ctr_d;
new_data_q <= new_data_d;
state_q <= state_d;
end
rx_q <= rx_d;
data_q <= data_d;
end
endmodule