mirror of
https://github.com/lowobservable/coax.git
synced 2026-02-27 17:32:39 +00:00
Initial attempt at receiver
This commit is contained in:
@@ -5,7 +5,7 @@ TINYPROG ?= tinyprog
|
||||
|
||||
all: top.bin
|
||||
|
||||
top.json: top.v hello_world.v coax_bit_timer.v coax_tx.v
|
||||
top.json: top.v hello_world.v coax_tx_bit_timer.v coax_tx.v coax_rx_bit_timer.v coax_rx.v
|
||||
|
||||
prog: top.bin
|
||||
$(TINYPROG) -p top.bin
|
||||
|
||||
128
interface2/rtl/coax_rx.v
Normal file
128
interface2/rtl/coax_rx.v
Normal file
@@ -0,0 +1,128 @@
|
||||
`default_nettype none
|
||||
|
||||
module coax_rx (
|
||||
input clk,
|
||||
input rx,
|
||||
output active
|
||||
);
|
||||
parameter CLOCKS_PER_BIT = 8;
|
||||
|
||||
reg rx_0 = 0;
|
||||
reg rx_1 = 0;
|
||||
|
||||
localparam IDLE = 0;
|
||||
localparam LINE_QUIESCE_1 = 1;
|
||||
localparam LINE_QUIESCE_2 = 2;
|
||||
localparam LINE_QUIESCE_3 = 3;
|
||||
localparam LINE_QUIESCE_4 = 4;
|
||||
localparam LINE_QUIESCE_5 = 5;
|
||||
localparam LINE_QUIESCE_6 = 6;
|
||||
localparam CODE_VIOLATION_1A = 7;
|
||||
localparam CODE_VIOLATION_1B = 8;
|
||||
localparam CODE_VIOLATION_2 = 9;
|
||||
localparam CODE_VIOLATION_3A = 10;
|
||||
localparam CODE_VIOLATION_3B = 11;
|
||||
localparam SYNC_BIT = 12;
|
||||
localparam DATA = 13;
|
||||
localparam PARITY_BIT = 14;
|
||||
localparam END_1 = 15;
|
||||
|
||||
reg [4:0] state = IDLE;
|
||||
reg [4:0] next_state;
|
||||
reg [4:0] previous_state = IDLE;
|
||||
|
||||
wire bit_timer_enable;
|
||||
wire bit_timer_sample;
|
||||
|
||||
assign bit_timer_enable = (state != CODE_VIOLATION_1A && state != CODE_VIOLATION_3B);
|
||||
|
||||
coax_rx_bit_timer #(
|
||||
.CLOCKS_PER_BIT(CLOCKS_PER_BIT)
|
||||
) bit_timer (
|
||||
.clk(clk),
|
||||
.rx(rx_1),
|
||||
.enable(bit_timer_enable),
|
||||
.sample(bit_timer_sample)
|
||||
);
|
||||
|
||||
reg [9:0] input_data = 10'b0;
|
||||
reg [4:0] input_data_counter;
|
||||
reg parity_bit;
|
||||
|
||||
always @(*)
|
||||
begin
|
||||
next_state <= state;
|
||||
|
||||
if (state == IDLE)
|
||||
begin
|
||||
if (rx_1)
|
||||
next_state <= LINE_QUIESCE_1;
|
||||
end
|
||||
else if (state == CODE_VIOLATION_1A)
|
||||
begin
|
||||
if (~rx_1)
|
||||
next_state <= CODE_VIOLATION_1B;
|
||||
end
|
||||
else if (state == CODE_VIOLATION_1B)
|
||||
begin
|
||||
if (~rx_1)
|
||||
next_state <= CODE_VIOLATION_2;
|
||||
end
|
||||
else if (state == CODE_VIOLATION_3A)
|
||||
begin
|
||||
if (rx_1)
|
||||
next_state <= CODE_VIOLATION_3B;
|
||||
end
|
||||
else if (state == CODE_VIOLATION_3B)
|
||||
begin
|
||||
if (~rx_1)
|
||||
next_state <= SYNC_BIT;
|
||||
end
|
||||
else if (bit_timer_sample)
|
||||
begin
|
||||
case (state)
|
||||
LINE_QUIESCE_1: next_state <= rx_1 ? LINE_QUIESCE_2 : IDLE;
|
||||
LINE_QUIESCE_2: next_state <= rx_1 ? LINE_QUIESCE_3 : IDLE;
|
||||
LINE_QUIESCE_3: next_state <= rx_1 ? LINE_QUIESCE_4 : IDLE;
|
||||
LINE_QUIESCE_4: next_state <= rx_1 ? LINE_QUIESCE_5 : IDLE;
|
||||
LINE_QUIESCE_5: next_state <= rx_1 ? LINE_QUIESCE_6 : IDLE;
|
||||
LINE_QUIESCE_6: next_state <= rx_1 ? CODE_VIOLATION_1A : IDLE;
|
||||
CODE_VIOLATION_2: next_state <= rx_1 ? CODE_VIOLATION_3A: IDLE;
|
||||
SYNC_BIT: next_state <= rx_1 ? DATA : /* TODO: ERROR */ IDLE;
|
||||
DATA: next_state <= input_data_counter == 9 ? PARITY_BIT : DATA;
|
||||
PARITY_BIT: next_state <= rx_1 == parity_bit ? END_1 : /* TODO: ERROR */ IDLE;
|
||||
END_1: next_state <= rx_1 ? DATA : IDLE; // TODO: END_2
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
rx_0 <= rx;
|
||||
rx_1 <= rx_0;
|
||||
|
||||
if (state == DATA)
|
||||
begin
|
||||
if (state != previous_state)
|
||||
begin
|
||||
input_data <= 10'b0;
|
||||
input_data_counter <= 0;
|
||||
|
||||
parity_bit <= 1; // Even parity includes sync bit
|
||||
end
|
||||
else if (bit_timer_sample)
|
||||
begin
|
||||
input_data <= { input_data[8:0], rx_1 };
|
||||
input_data_counter <= input_data_counter + 1;
|
||||
|
||||
if (rx_1)
|
||||
parity_bit <= ~parity_bit;
|
||||
end
|
||||
end
|
||||
|
||||
state <= next_state;
|
||||
previous_state <= state;
|
||||
end
|
||||
|
||||
assign active = (state >= SYNC_BIT && state <= END_1);
|
||||
endmodule
|
||||
38
interface2/rtl/coax_rx_bit_timer.v
Normal file
38
interface2/rtl/coax_rx_bit_timer.v
Normal file
@@ -0,0 +1,38 @@
|
||||
`default_nettype none
|
||||
|
||||
module coax_rx_bit_timer (
|
||||
input clk,
|
||||
input rx,
|
||||
input enable,
|
||||
output sample
|
||||
);
|
||||
parameter CLOCKS_PER_BIT = 8;
|
||||
|
||||
reg previous_rx;
|
||||
|
||||
reg [$clog2(CLOCKS_PER_BIT/2):0] counter = 0;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (enable)
|
||||
begin
|
||||
if (counter == 0)
|
||||
begin
|
||||
if (rx != previous_rx)
|
||||
counter <= 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
counter <= counter + 1;
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
counter <= 0;
|
||||
end
|
||||
|
||||
previous_rx <= rx;
|
||||
end
|
||||
|
||||
assign sample = (enable && counter == CLOCKS_PER_BIT / 4);
|
||||
endmodule
|
||||
@@ -45,7 +45,7 @@ module coax_tx (
|
||||
wire bit_second_half;
|
||||
wire bit_end_strobe;
|
||||
|
||||
coax_bit_timer #(
|
||||
coax_tx_bit_timer #(
|
||||
.CLOCKS_PER_BIT(CLOCKS_PER_BIT)
|
||||
) bit_timer (
|
||||
.clk(clk),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
`default_nettype none
|
||||
|
||||
module coax_bit_timer (
|
||||
module coax_tx_bit_timer (
|
||||
input clk,
|
||||
input reset,
|
||||
output first_half,
|
||||
@@ -3,6 +3,13 @@ set_io --warn-no-port tx C2
|
||||
set_io --warn-no-port tx_delay C1
|
||||
set_io --warn-no-port tx_inverted D2
|
||||
|
||||
set_io --warn-no-port rx D1
|
||||
set_io --warn-no-port rx_active E2
|
||||
set_io --warn-no-port rx_data_available E1
|
||||
|
||||
set_io --warn-no-port xxx_debug_1 G2
|
||||
set_io --warn-no-port xxx_debug_2 H1
|
||||
|
||||
# 16MHz clock
|
||||
set_io --warn-no-port clk_16mhz B2
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@ module top (
|
||||
output tx,
|
||||
output tx_delay,
|
||||
output tx_inverted,
|
||||
input rx,
|
||||
output rx_active,
|
||||
output xxx_debug_1,
|
||||
output xxx_debug_2,
|
||||
output usb_pu
|
||||
);
|
||||
// 19 MHz
|
||||
@@ -26,12 +30,10 @@ module top (
|
||||
.PLLOUTCORE(clk_19mhz)
|
||||
);
|
||||
|
||||
hello_world hello_world (
|
||||
coax_rx coax_rx (
|
||||
.clk(clk_19mhz),
|
||||
.tx_active(tx_active),
|
||||
.tx(tx),
|
||||
.tx_delay(tx_delay),
|
||||
.tx_inverted(tx_inverted)
|
||||
.rx(rx),
|
||||
.active(rx_active)
|
||||
);
|
||||
|
||||
assign usb_pu = 0;
|
||||
|
||||
@@ -3,11 +3,12 @@ VVP ?= vvp
|
||||
|
||||
RTL = ../rtl
|
||||
|
||||
all: coax_bit_timer_tb.vcd coax_tx_tb.vcd hello_world_tb.vcd
|
||||
all: coax_tx_bit_timer_tb.vcd coax_tx_tb.vcd coax_rx_tb.vcd hello_world_tb.vcd
|
||||
|
||||
coax_bit_timer_tb: coax_bit_timer_tb.v $(RTL)/coax_bit_timer.v
|
||||
coax_tx_tb: coax_tx_tb.v $(RTL)/coax_bit_timer.v $(RTL)/coax_tx.v
|
||||
hello_world_tb: hello_world_tb.v $(RTL)/hello_world.v $(RTL)/coax_bit_timer.v $(RTL)/coax_tx.v
|
||||
coax_tx_bit_timer_tb: coax_tx_bit_timer_tb.v $(RTL)/coax_tx_bit_timer.v
|
||||
coax_tx_tb: coax_tx_tb.v $(RTL)/coax_tx_bit_timer.v $(RTL)/coax_tx.v
|
||||
coax_rx_tb: coax_rx_tb.v $(RTL)/coax_tx_bit_timer.v $(RTL)/coax_tx.v $(RTL)/coax_rx_bit_timer.v $(RTL)/coax_rx.v
|
||||
hello_world_tb: hello_world_tb.v $(RTL)/hello_world.v $(RTL)/coax_tx_bit_timer.v $(RTL)/coax_tx.v
|
||||
|
||||
clean:
|
||||
rm -f *_tb *.vcd
|
||||
|
||||
55
interface2/tests/coax_rx_tb.v
Normal file
55
interface2/tests/coax_rx_tb.v
Normal file
@@ -0,0 +1,55 @@
|
||||
`default_nettype none
|
||||
|
||||
module coax_rx_tb();
|
||||
reg clk = 0;
|
||||
|
||||
initial
|
||||
begin
|
||||
forever
|
||||
begin
|
||||
#1 clk <= ~clk;
|
||||
end
|
||||
end
|
||||
|
||||
reg tx_load = 0;
|
||||
reg [9:0] tx_data;
|
||||
wire tx_tx;
|
||||
|
||||
coax_tx #(
|
||||
.CLOCKS_PER_BIT(8)
|
||||
) tx (
|
||||
.clk(clk),
|
||||
.load(tx_load),
|
||||
.data(tx_data),
|
||||
.tx(tx_tx)
|
||||
);
|
||||
|
||||
coax_rx #(
|
||||
.CLOCKS_PER_BIT(8)
|
||||
) dut (
|
||||
.clk(clk),
|
||||
.rx(tx_tx)
|
||||
);
|
||||
|
||||
initial
|
||||
begin
|
||||
$dumpfile("coax_rx_tb.vcd");
|
||||
$dumpvars(0, coax_rx_tb);
|
||||
|
||||
#8
|
||||
|
||||
tx_data = 10'b0000000101;
|
||||
tx_load = 1;
|
||||
#2 tx_load = 0;
|
||||
|
||||
#32
|
||||
|
||||
tx_data = 10'b1111111111;
|
||||
tx_load = 1;
|
||||
#2 tx_load = 0;
|
||||
|
||||
repeat(1000) @(posedge clk);
|
||||
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -1,6 +1,6 @@
|
||||
`default_nettype none
|
||||
|
||||
module coax_bit_timer_tb();
|
||||
module coax_tx_bit_timer_tb();
|
||||
reg clk = 0;
|
||||
|
||||
initial
|
||||
@@ -16,7 +16,7 @@ module coax_bit_timer_tb();
|
||||
wire second_half;
|
||||
wire end_strobe;
|
||||
|
||||
coax_bit_timer #(
|
||||
coax_tx_bit_timer #(
|
||||
.CLOCKS_PER_BIT(8)
|
||||
) dut (
|
||||
.clk(clk),
|
||||
@@ -28,8 +28,8 @@ module coax_bit_timer_tb();
|
||||
|
||||
initial
|
||||
begin
|
||||
$dumpfile("coax_bit_timer_tb.vcd");
|
||||
$dumpvars(0, coax_bit_timer_tb);
|
||||
$dumpfile("coax_tx_bit_timer_tb.vcd");
|
||||
$dumpvars(0, coax_tx_bit_timer_tb);
|
||||
|
||||
repeat(100) @(posedge clk);
|
||||
|
||||
Reference in New Issue
Block a user