From 14fd7485fef020e362c91bff536c889479d2a3dc Mon Sep 17 00:00:00 2001 From: Andrew Kay Date: Fri, 29 Oct 2021 19:12:21 -0500 Subject: [PATCH] New coax_tx_rx_frontend and coax_rx_blanker modules --- interface2/fpga/rtl/coax_rx_blanker.v | 56 +++++++++ interface2/fpga/rtl/coax_syn.prj | 2 + interface2/fpga/rtl/coax_tx_distorter.v | 12 +- interface2/fpga/rtl/coax_tx_rx_frontend.v | 71 +++++++++++ interface2/fpga/rtl/top.v | 53 ++++---- interface2/fpga/tests/Makefile | 2 + interface2/fpga/tests/coax_rx_blanker_tb.v | 117 ++++++++++++++++++ .../fpga/tests/coax_tx_rx_frontend_tb.v | 88 +++++++++++++ 8 files changed, 370 insertions(+), 31 deletions(-) create mode 100644 interface2/fpga/rtl/coax_rx_blanker.v create mode 100644 interface2/fpga/rtl/coax_tx_rx_frontend.v create mode 100644 interface2/fpga/tests/coax_rx_blanker_tb.v create mode 100644 interface2/fpga/tests/coax_tx_rx_frontend_tb.v diff --git a/interface2/fpga/rtl/coax_rx_blanker.v b/interface2/fpga/rtl/coax_rx_blanker.v new file mode 100644 index 0000000..5354c47 --- /dev/null +++ b/interface2/fpga/rtl/coax_rx_blanker.v @@ -0,0 +1,56 @@ +// Copyright (c) 2021, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +`default_nettype none + +module coax_rx_blanker ( + input clk, + input reset, + input enable, + + input rx_input, + input tx_active, + + output reg rx_output +); + parameter DELAY_CLOCKS = 2; + + reg rx_input_d0; + + always @(posedge clk) + begin + rx_input_d0 <= rx_input; + end + + reg [DELAY_CLOCKS-1:0] blank; + + always @(posedge clk) + begin + if (reset) + blank <= { (DELAY_CLOCKS){1'b0} }; + else if (tx_active) + blank <= { (DELAY_CLOCKS){1'b1} }; + else + blank <= { blank[DELAY_CLOCKS-2:0], 1'b0 }; + end + + always @(posedge clk) + begin + // TODO: should enable be delayed 1 clock to match input? + if (!enable || !blank[DELAY_CLOCKS-1]) + rx_output <= rx_input_d0; + else + rx_output <= 1'b0; + end +endmodule diff --git a/interface2/fpga/rtl/coax_syn.prj b/interface2/fpga/rtl/coax_syn.prj index a679398..3fc1a3e 100644 --- a/interface2/fpga/rtl/coax_syn.prj +++ b/interface2/fpga/rtl/coax_syn.prj @@ -8,6 +8,8 @@ add_file -verilog -lib work "coax_rx_ss_detector.v" add_file -verilog -lib work "coax_tx.v" add_file -verilog -lib work "coax_tx_bit_timer.v" add_file -verilog -lib work "coax_tx_distorter.v" +add_file -verilog -lib work "coax_rx_blanker.v" +add_file -verilog -lib work "coax_tx_rx_frontend.v" add_file -verilog -lib work "control.v" add_file -verilog -lib work "spi_device.v" add_file -verilog -lib work "coax_buffered_tx.v" diff --git a/interface2/fpga/rtl/coax_tx_distorter.v b/interface2/fpga/rtl/coax_tx_distorter.v index c64804c..f9fdc67 100644 --- a/interface2/fpga/rtl/coax_tx_distorter.v +++ b/interface2/fpga/rtl/coax_tx_distorter.v @@ -20,8 +20,8 @@ module coax_tx_distorter ( input tx_input, output reg active_output, output reg tx_output, - output reg tx_delay, - output reg tx_n + output reg tx_delay_output, + output reg tx_n_output ); parameter CLOCKS_PER_BIT = 8; @@ -37,8 +37,8 @@ module coax_tx_distorter ( active_output <= 1; tx_output <= tx_input; - tx_delay <= tx_d[DELAY_CLOCKS-1]; - tx_n <= ~tx_input; + tx_delay_output <= tx_d[DELAY_CLOCKS-1]; + tx_n_output <= ~tx_input; end else begin @@ -46,8 +46,8 @@ module coax_tx_distorter ( active_output <= 0; tx_output <= 0; - tx_delay <= 0; - tx_n <= 0; + tx_delay_output <= 0; + tx_n_output <= 0; end end endmodule diff --git a/interface2/fpga/rtl/coax_tx_rx_frontend.v b/interface2/fpga/rtl/coax_tx_rx_frontend.v new file mode 100644 index 0000000..1c2f940 --- /dev/null +++ b/interface2/fpga/rtl/coax_tx_rx_frontend.v @@ -0,0 +1,71 @@ +// Copyright (c) 2021, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +`default_nettype none + +module coax_tx_rx_frontend ( + input clk, + input reset, + + input loopback, + input tx_active_input, + input tx_input, + output rx_output, + + // The outside world... + output tx_active_output, + output tx_output, + output tx_n_output, + output tx_delay_output, + input rx_input, + + output rx_debug +); + parameter CLOCKS_PER_BIT = 8; + + coax_tx_distorter #( + .CLOCKS_PER_BIT(CLOCKS_PER_BIT) + ) coax_tx_distorter ( + .clk(clk), + .active_input(!loopback && tx_active_input), + .tx_input(tx_input), + .active_output(tx_active_output), + .tx_output(tx_output), + .tx_delay_output(tx_delay_output), + .tx_n_output(tx_n_output) + ); + + reg [1:0] rx_input_d; + reg internal_rx; + + always @(posedge clk) + begin + rx_input_d <= { rx_input_d[0], rx_input }; + + internal_rx <= loopback ? tx_input : rx_input_d[1]; + end + + coax_rx_blanker #( + .DELAY_CLOCKS(2 + 4) // To account for the RX input 2FF synchronizer and more + ) coax_rx_blanker ( + .clk(clk), + .reset(reset), + .enable(!loopback), + .rx_input(internal_rx), + .tx_active(tx_active_output), + .rx_output(rx_output) + ); + + assign rx_debug = internal_rx; +endmodule diff --git a/interface2/fpga/rtl/top.v b/interface2/fpga/rtl/top.v index 9345e02..d9bbd8a 100644 --- a/interface2/fpga/rtl/top.v +++ b/interface2/fpga/rtl/top.v @@ -40,13 +40,13 @@ module top ( output gpio2, output gpio3 ); + localparam CLOCKS_PER_BIT = 16; + reg [1:0] reset_n_d; - reg [1:0] rx_d; always @(posedge clk) begin reset_n_d <= { reset_n_d[0], reset_n }; - rx_d <= { rx_d[0], rx }; end reg reset; @@ -89,8 +89,6 @@ module top ( .tx_strobe(spi_tx_strobe) ); - wire loopback; - wire tx_reset; wire internal_tx_active; wire internal_tx; @@ -103,7 +101,7 @@ module top ( wire tx_parity; coax_buffered_tx #( - .CLOCKS_PER_BIT(16), + .CLOCKS_PER_BIT(CLOCKS_PER_BIT), .DEPTH(2048), .START_DEPTH(1536) ) coax_buffered_tx ( @@ -120,14 +118,8 @@ module top ( .parity(tx_parity) ); - reg internal_rx; - - always @(posedge clk) - begin - internal_rx <= loopback ? internal_tx : (!internal_tx_active ? rx_d[1] : 0); - end - wire rx_reset; + wire internal_rx; wire rx_active; wire rx_error; wire [9:0] rx_data; @@ -136,7 +128,7 @@ module top ( wire rx_parity; coax_buffered_rx #( - .CLOCKS_PER_BIT(16), + .CLOCKS_PER_BIT(CLOCKS_PER_BIT), .DEPTH(2048) ) coax_buffered_rx ( .clk(clk), @@ -150,6 +142,28 @@ module top ( .parity(rx_parity) ); + wire loopback; + wire rx_debug; + + coax_tx_rx_frontend #( + .CLOCKS_PER_BIT(CLOCKS_PER_BIT) + ) coax_tx_rx_frontend ( + .clk(clk), + .reset(reset), + + .loopback(loopback), + .tx_active_input(internal_tx_active), + .tx_input(internal_tx), + .rx_output(internal_rx), + + .tx_active_output(tx_active), + .tx_n_output(tx_n), + .tx_delay_output(tx_delay), + .rx_input(rx), + + .rx_debug(rx_debug) + ); + control control ( .clk(clk), .reset(reset), @@ -181,20 +195,9 @@ module top ( .rx_parity(rx_parity) ); - coax_tx_distorter #( - .CLOCKS_PER_BIT(16) - ) coax_tx_distorter ( - .clk(clk), - .active_input(!loopback && internal_tx_active), - .tx_input(internal_tx), - .active_output(tx_active), - .tx_delay(tx_delay), - .tx_n(tx_n) - ); - assign irq = rx_active || rx_error; - assign gpio0 = rx_d[1]; + assign gpio0 = rx_debug; assign gpio1 = tx_active; assign gpio2 = rx_active; assign gpio3 = 0; diff --git a/interface2/fpga/tests/Makefile b/interface2/fpga/tests/Makefile index ca2e2fe..9fea3c4 100644 --- a/interface2/fpga/tests/Makefile +++ b/interface2/fpga/tests/Makefile @@ -12,6 +12,8 @@ coax_rx_tb: coax_rx_tb.v $(RTL)/coax_rx.v $(RTL)/coax_rx_ss_detector.v coax_tx_bit_timer_tb: coax_tx_bit_timer_tb.v $(RTL)/coax_tx_bit_timer.v coax_tx_distorter_tb: coax_tx_distorter_tb.v $(RTL)/coax_tx_distorter.v coax_tx_tb: coax_tx_tb.v $(RTL)/coax_tx.v $(RTL)/coax_tx_bit_timer.v +coax_rx_blanker_tb: coax_rx_blanker_tb.v $(RTL)/coax_rx_blanker.v +coax_tx_rx_frontend_tb: coax_tx_rx_frontend_tb.v $(RTL)/coax_tx_rx_frontend.v $(RTL)/coax_tx_distorter.v $(RTL)/coax_rx_blanker.v control_tb: control_tb.v $(RTL)/control.v $(RTL)/coax_buffered_tx.v $(RTL)/coax_tx.v $(RTL)/coax_tx_bit_timer.v $(RTL)/coax_buffer.v $(RTL)/third_party/*.v regression_memorex_tb: regression_memorex_tb.v $(RTL)/coax_rx.v $(RTL)/coax_rx_ss_detector.v diff --git a/interface2/fpga/tests/coax_rx_blanker_tb.v b/interface2/fpga/tests/coax_rx_blanker_tb.v new file mode 100644 index 0000000..51f1a0e --- /dev/null +++ b/interface2/fpga/tests/coax_rx_blanker_tb.v @@ -0,0 +1,117 @@ +`default_nettype none + +`include "assert.v" + +module coax_rx_blanker_tb; + reg clk = 0; + + initial + begin + forever + begin + #1 clk <= ~clk; + end + end + + reg reset = 0; + reg enable = 0; + reg rx_input = 0; + reg tx_active = 0; + + coax_rx_blanker #( + .DELAY_CLOCKS(6) + ) dut ( + .clk(clk), + .reset(reset), + .enable(enable), + .rx_input(rx_input), + .tx_active(tx_active) + ); + + initial + begin + $dumpfile("coax_rx_blanker_tb.vcd"); + $dumpvars(0, coax_rx_blanker_tb); + + test_not_enabled; + test_enabled_tx_not_active; + test_enabled_tx_active; + + $finish; + end + + task test_not_enabled; + begin + $display("START: test_not_enabled"); + + enable = 0; + rx_input = 1; + + #4; + + `assert_high(dut.rx_output, "rx_output should be HIGH"); + + rx_input = 0; + + #4; + + `assert_low(dut.rx_output, "rx_output should be LOW"); + + #16; + + $display("END: test_not_enabled"); + end + endtask + + task test_enabled_tx_not_active; + begin + $display("START: test_enabled_tx_not_active"); + + enable = 1; + rx_input = 1; + tx_active = 0; + + #4; + + `assert_high(dut.rx_output, "rx_output should be HIGH"); + + rx_input = 0; + + #4; + + `assert_low(dut.rx_output, "rx_output should be LOW"); + + #16; + + $display("END: test_enabled_tx_not_active"); + end + endtask + + task test_enabled_tx_active; + begin + $display("START: test_enabled_tx_active"); + + enable = 1; + rx_input = 1; + tx_active = 1; + + #4; + + `assert_low(dut.rx_output, "rx_output should be LOW"); + + tx_active = 0; + + #4; + + `assert_low(dut.rx_output, "rx_output should be LOW"); + + #12; + + `assert_high(dut.rx_output, "rx_output should be HIGH"); + + #16; + + $display("END: test_enabled_tx_active"); + end + endtask +endmodule diff --git a/interface2/fpga/tests/coax_tx_rx_frontend_tb.v b/interface2/fpga/tests/coax_tx_rx_frontend_tb.v new file mode 100644 index 0000000..976da01 --- /dev/null +++ b/interface2/fpga/tests/coax_tx_rx_frontend_tb.v @@ -0,0 +1,88 @@ +`default_nettype none + +`include "assert.v" + +module coax_tx_rx_frontend_tb; + reg clk = 0; + + initial + begin + forever + begin + #1 clk <= ~clk; + end + end + + reg reset = 0; + reg loopback = 0; + reg tx_active_input = 0; + reg tx_input = 0; + reg rx_input = 0; + + coax_tx_rx_frontend #( + .CLOCKS_PER_BIT(8) + ) dut ( + .clk(clk), + .reset(reset), + .loopback(loopback), + .tx_active_input(tx_active_input), + .tx_input(tx_input), + .rx_input(rx_input) + ); + + initial + begin + $dumpfile("coax_tx_rx_frontend_tb.vcd"); + $dumpvars(0, coax_tx_rx_frontend_tb); + + test_loopback; + test_not_loopback; + + $finish; + end + + task test_loopback; + begin + $display("START: test_loopback"); + + loopback = 1; + tx_active_input = 1; + tx_input = 1; + rx_input = 0; + + #16; + + tx_active_input = 0; + tx_input = 0; + + #8; + + loopback = 0; + + #16; + + $display("END: test_loopback"); + end + endtask + + task test_not_loopback; + begin + $display("START: test_not_loopback"); + + loopback = 0; + tx_active_input = 1; + tx_input = 1; + rx_input = 1; + + #16; + + tx_active_input = 0; + tx_input = 0; + rx_input = 0; + + #16; + + $display("END: test_not_loopback"); + end + endtask +endmodule