New coax_tx_rx_frontend and coax_rx_blanker modules

This commit is contained in:
Andrew Kay
2021-10-29 19:12:21 -05:00
parent 55d7a2d784
commit 14fd7485fe
8 changed files with 370 additions and 31 deletions

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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