-
Notifications
You must be signed in to change notification settings - Fork 1
/
character_recovery.v
142 lines (131 loc) · 2.89 KB
/
character_recovery.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
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
`default_nettype none
module character_recovery
#(
parameter OVERSAMPLING = 16,
parameter DATA_BITS = 8,
parameter PARITY = 0
)
(
input rst_i,
input clk_i,
input rx_i,
output reg [DATA_BITS-1:0] char_o,
output reg valid_o,
output reg frame_error_o,
output reg parity_error_o
);
localparam COUNTSIZE = $clog2(OVERSAMPLING);
reg [COUNTSIZE-1:0] counter;
localparam DATASIZE = $clog2(DATA_BITS);
reg [DATASIZE-1:0] index;
reg [1:0] state;
localparam IDLE = 2'b00;
localparam STARTING = 2'b01;
localparam STARTED = 2'b10;
localparam CAPTURED = 2'b11;
wire counter_empty;
assign counter_empty = counter == {COUNTSIZE{1'b0}};
reg past_rx;
wire start_bit_edge;
assign start_bit_edge = (past_rx) && (~rx_i);
// parity calculation
wire parity_error;
wire data_finished;
reg parity_bit;
generate if (PARITY > 0) begin
reg parity;
always @(posedge clk_i) begin
if (rst_i) begin
parity <= 1'b0;
parity_bit <= 1'b0;
end
else begin
case (state)
IDLE: begin
parity <= 1'b0;
parity_bit <= 1'b0;
end
STARTED: begin
if (counter_empty) begin
parity <= parity ^ rx_i;
if (index == DATA_BITS-1) begin
parity_bit <= 1'b1;
end
end
end
default: begin
;
end
endcase
end
end
assign parity_error = parity != PARITY[0];
assign data_finished = parity_bit;
end
endgenerate
generate if (PARITY == 0) begin
assign parity_error = 1'b0;
assign data_finished = (index == DATA_BITS-1);
always @(*) begin
parity_bit = 1'b0;
end
end
endgenerate
always @(posedge clk_i) begin
if (rst_i) begin
valid_o <= 1'b0;
frame_error_o <= 1'b0;
state <= IDLE;
past_rx <= 1'b1;
counter <= {COUNTSIZE{1'b0}};
parity_error_o <= 1'b0;
// No need to reset char_o
end
else begin
past_rx <= rx_i;
case (state)
IDLE: begin
valid_o <= 1'b0;
frame_error_o <= 1'b0;
parity_error_o <= 1'b0;
if (counter_empty && start_bit_edge) begin
state <= STARTING;
index <= {DATASIZE{1'b0}};
counter <= (OVERSAMPLING >> 1) - 1'b1;
end
end
STARTING: begin
counter <= counter - 1'b1;
if (counter_empty) begin
state <= (~rx_i) ? STARTED : IDLE;
counter <= OVERSAMPLING-1;
end
end
STARTED: begin
counter <= counter - 1'b1;
if (counter_empty) begin
if (~parity_bit) begin
char_o[index] <= rx_i;
index <= index + 1'b1;
end
if (data_finished) state <= CAPTURED;
counter <= OVERSAMPLING-1;
end
end
CAPTURED: begin
counter <= counter - 1'b1;
if (counter_empty) begin
// stop bit must be opposite of start bit
// can't assert valid if there's a parity error
valid_o <= (rx_i & ~parity_error);
frame_error_o <= (~rx_i);
parity_error_o <= parity_error;
state <= IDLE;
// wait out the rest of the bit period before restart
counter <= (OVERSAMPLING >> 1) - 1'b1 + (OVERSAMPLING & 1'b1);
end
end
endcase
end
end
endmodule