Skip to content

Instantly share code, notes, and snippets.

@nickelpro
Created June 6, 2023 14:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nickelpro/3435df24c7ce8b236e4ddcc892ca15f8 to your computer and use it in GitHub Desktop.
Save nickelpro/3435df24c7ce8b236e4ddcc892ca15f8 to your computer and use it in GitHub Desktop.
module EdgeSync (
input clk,
input nReset,
input in,
output rise,
output fall,
output logic out
);
logic sync, cmp;
assign rise = out & ~cmp;
assign fall = ~out & cmp;
always_ff @(posedge clk, negedge nReset) begin
if (!nReset) begin
cmp <= 0;
out <= 0;
sync <= 0;
end else begin
cmp <= out;
out <= sync;
sync <= in;
end
end
endmodule
module UartRx #(
int Oversample = 16
) (
input clk,
input nReset,
input in,
output logic [7:0] data,
output logic done,
output logic err
);
localparam sampleWidth = $clog2(Oversample);
localparam fullSampleCount = sampleWidth'(Oversample - 1);
localparam halfSampleCount = sampleWidth'((Oversample / 2) - 1);
// verilog_format: off
enum {
IDLE,
START,
DATA_A,
DATA_B,
STOP,
ERROR
} curState, nextState;
// verilog_format: on
logic rise, fall, syncOut;
EdgeSync es (
.*,
.out(syncOut)
);
logic edgeDetect = fall || rise;
logic [sampleWidth-1:0] sampleCount;
logic [7:0] readBuf;
logic [2:0] readCount;
logic edgeCmp;
logic badSync = edgeDetect && edgeCmp && (sampleCount >= halfSampleCount);
logic reSync = edgeDetect && (sampleCount < halfSampleCount);
logic advance = reSync || (sampleCount == 0);
always_ff @(posedge clk, negedge nReset) begin
if (!nReset) begin
sampleCount <= fullSampleCount;
edgeCmp <= 0;
curState <= IDLE;
end else begin
curState <= nextState;
if (curState != nextState) begin
edgeCmp <= 0;
sampleCount <= fullSampleCount;
end else begin
edgeCmp <= edgeDetect ? 1 : edgeCmp;
sampleCount <= sampleCount - 1;
end
end
end
always_ff @(posedge clk, negedge nReset) begin
if (!nReset) begin
readCount <= 7;
done <= 0;
end else begin
if (readCount == 0) begin
data <= readBuf;
done <= 1;
end else begin
done <= 0;
end
if (nextState != DATA_A && nextState != DATA_B) begin
readCount <= 7;
end else if (sampleCount == halfSampleCount) begin
readCount <= readCount - 1;
readBuf <= {readBuf[7:1], syncOut};
end
end
end
always_ff @(posedge clk, negedge nReset) begin
if (!nReset || nextState != ERROR) begin
err <= 0;
end else begin
err <= 1;
end
end
always_comb begin
case (curState)
IDLE:
if (fall) begin
nextState = START;
end else begin
nextState = curState;
end
START:
if (rise && (sampleCount >= halfSampleCount)) begin
nextState = ERROR;
end else if (advance) begin
nextState = DATA_A;
end
DATA_A:
if (badSync) begin
nextState = ERROR;
end else if (advance && (readCount > 0)) begin
nextState = DATA_B;
end else begin
nextState = STOP;
end
DATA_B:
if (badSync) begin
nextState = ERROR;
end else if (advance && (readCount > 0)) begin
nextState = DATA_A;
end else begin
nextState = STOP;
end
STOP:
if (badSync || (fall && (sampleCount >= halfSampleCount))) begin
nextState = ERROR;
end else if (fall) begin
nextState = START;
end else begin
nextState = IDLE;
end
ERROR: nextState = IDLE;
endcase
end
endmodule
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment