94 lines
2.4 KiB
Verilog
94 lines
2.4 KiB
Verilog
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 |