diff --git a/interface2/rtl/Makefile b/interface2/rtl/Makefile index 59411a5..0804ace 100644 --- a/interface2/rtl/Makefile +++ b/interface2/rtl/Makefile @@ -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 diff --git a/interface2/rtl/coax_rx.v b/interface2/rtl/coax_rx.v new file mode 100644 index 0000000..cf12f8a --- /dev/null +++ b/interface2/rtl/coax_rx.v @@ -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 diff --git a/interface2/rtl/coax_rx_bit_timer.v b/interface2/rtl/coax_rx_bit_timer.v new file mode 100644 index 0000000..9502e50 --- /dev/null +++ b/interface2/rtl/coax_rx_bit_timer.v @@ -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 diff --git a/interface2/rtl/coax_tx.v b/interface2/rtl/coax_tx.v index 5191e30..e1e06c5 100644 --- a/interface2/rtl/coax_tx.v +++ b/interface2/rtl/coax_tx.v @@ -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), diff --git a/interface2/rtl/coax_bit_timer.v b/interface2/rtl/coax_tx_bit_timer.v similarity index 96% rename from interface2/rtl/coax_bit_timer.v rename to interface2/rtl/coax_tx_bit_timer.v index 008918e..7082d9b 100644 --- a/interface2/rtl/coax_bit_timer.v +++ b/interface2/rtl/coax_tx_bit_timer.v @@ -1,6 +1,6 @@ `default_nettype none -module coax_bit_timer ( +module coax_tx_bit_timer ( input clk, input reset, output first_half, diff --git a/interface2/rtl/pins.pcf b/interface2/rtl/pins.pcf index 22790a8..155d45b 100644 --- a/interface2/rtl/pins.pcf +++ b/interface2/rtl/pins.pcf @@ -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 diff --git a/interface2/rtl/top.v b/interface2/rtl/top.v index 045c9e1..3eb4e41 100644 --- a/interface2/rtl/top.v +++ b/interface2/rtl/top.v @@ -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; diff --git a/interface2/tests/Makefile b/interface2/tests/Makefile index 3ea2e43..ecbd6da 100644 --- a/interface2/tests/Makefile +++ b/interface2/tests/Makefile @@ -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 diff --git a/interface2/tests/coax_rx_tb.v b/interface2/tests/coax_rx_tb.v new file mode 100644 index 0000000..6436e80 --- /dev/null +++ b/interface2/tests/coax_rx_tb.v @@ -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 diff --git a/interface2/tests/coax_bit_timer_tb.v b/interface2/tests/coax_tx_bit_timer_tb.v similarity index 80% rename from interface2/tests/coax_bit_timer_tb.v rename to interface2/tests/coax_tx_bit_timer_tb.v index 7141da9..3d5ce6b 100644 --- a/interface2/tests/coax_bit_timer_tb.v +++ b/interface2/tests/coax_tx_bit_timer_tb.v @@ -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);