From 55d7a2d784c5fd687223d412e832f7ab27ebb0a8 Mon Sep 17 00:00:00 2001 From: Andrew Kay Date: Sun, 24 Oct 2021 16:04:48 -0500 Subject: [PATCH] More robust coax_rx start sequence detection --- .github/workflows/interface2_build.yml | 2 +- interface2/fpga/rtl/coax_rx.v | 367 ++++++------------ interface2/fpga/rtl/coax_rx_bit_timer.v | 111 ------ interface2/fpga/rtl/coax_rx_ss_detector.v | 137 +++++++ interface2/fpga/rtl/coax_syn.prj | 2 +- interface2/fpga/tests/Makefile | 6 +- interface2/fpga/tests/coax_rx_bit_timer_tb.v | 75 ---- interface2/fpga/tests/coax_rx_tb.v | 152 ++++---- interface2/fpga/tests/regression_memorex_tb.v | 171 ++++++++ 9 files changed, 489 insertions(+), 534 deletions(-) delete mode 100644 interface2/fpga/rtl/coax_rx_bit_timer.v create mode 100644 interface2/fpga/rtl/coax_rx_ss_detector.v delete mode 100644 interface2/fpga/tests/coax_rx_bit_timer_tb.v create mode 100644 interface2/fpga/tests/regression_memorex_tb.v diff --git a/.github/workflows/interface2_build.yml b/.github/workflows/interface2_build.yml index 205272b..c1e0d58 100644 --- a/.github/workflows/interface2_build.yml +++ b/.github/workflows/interface2_build.yml @@ -49,7 +49,7 @@ jobs: aws-region: us-east-1 - name: Get bitstream source SHA run: | - BITSTREAM_SOURCE_SHA=$(git log -n 1 --format=%H .) + BITSTREAM_SOURCE_SHA=$(git log -n 1 --format=%H rtl) echo Bitstream source SHA is $BITSTREAM_SOURCE_SHA echo "BITSTREAM_SOURCE_SHA=$BITSTREAM_SOURCE_SHA" >> $GITHUB_ENV - name: Check bitstream cache diff --git a/interface2/fpga/rtl/coax_rx.v b/interface2/fpga/rtl/coax_rx.v index 1071a73..7f79e5a 100644 --- a/interface2/fpga/rtl/coax_rx.v +++ b/interface2/fpga/rtl/coax_rx.v @@ -26,36 +26,31 @@ module coax_rx ( ); parameter CLOCKS_PER_BIT = 8; + localparam CLOCKS_PER_HALF_BIT = CLOCKS_PER_BIT / 2; + localparam CLOCKS_PER_2_BIT = CLOCKS_PER_BIT * 2; + localparam CLOCKS_PER_3_BIT = CLOCKS_PER_BIT * 3; + localparam CLOCKS_LOSS_OF_MID_BIT_TRANSITION = CLOCKS_PER_BIT + (CLOCKS_PER_BIT / 2); + localparam ERROR_LOSS_OF_MID_BIT_TRANSITION = 10'b0000000001; localparam ERROR_PARITY = 10'b0000000010; localparam ERROR_INVALID_END_SEQUENCE = 10'b0000000100; localparam STATE_IDLE = 0; - localparam STATE_START_SEQUENCE_1 = 1; - localparam STATE_START_SEQUENCE_2 = 2; - localparam STATE_START_SEQUENCE_3 = 3; - localparam STATE_START_SEQUENCE_4 = 4; - localparam STATE_START_SEQUENCE_5 = 5; - localparam STATE_START_SEQUENCE_6 = 6; - localparam STATE_START_SEQUENCE_7 = 7; - localparam STATE_START_SEQUENCE_8 = 8; - localparam STATE_START_SEQUENCE_9 = 9; - localparam STATE_SYNC_BIT = 10; - localparam STATE_DATA_BIT = 11; - localparam STATE_PARITY_BIT = 12; - localparam STATE_END_SEQUENCE_1 = 13; - localparam STATE_END_SEQUENCE_2 = 14; - localparam STATE_ERROR = 15; + localparam STATE_FIRST_SYNC_BIT = 1; + localparam STATE_SYNC_BIT = 2; + localparam STATE_DATA_BIT = 3; + localparam STATE_PARITY_BIT = 4; + localparam STATE_END_SEQUENCE_1 = 5; + localparam STATE_END_SEQUENCE_2 = 6; + localparam STATE_ERROR = 7; - reg [3:0] state = STATE_IDLE; - reg [3:0] next_state; - reg [7:0] state_counter; - reg [7:0] next_state_counter; + reg [2:0] state = STATE_IDLE; + reg [2:0] next_state; reg previous_rx; - reg bit_timer_reset = 0; - reg next_bit_timer_reset; + reg [$clog2(CLOCKS_PER_3_BIT):0] mid_bit_counter; + reg [$clog2(CLOCKS_PER_3_BIT):0] next_mid_bit_counter; reg [9:0] next_data; reg next_strobe; @@ -70,25 +65,23 @@ module coax_rx ( reg next_active; reg next_error; - wire sample; - wire synchronized; + wire ss_detector_strobe; - coax_rx_bit_timer #( + coax_rx_ss_detector #( .CLOCKS_PER_BIT(CLOCKS_PER_BIT) - ) bit_timer ( + ) ss_detector ( .clk(clk), + .reset(reset), + .enable(state == STATE_IDLE), .rx(rx), - .reset(bit_timer_reset), - .sample(sample), - .synchronized(synchronized) + .strobe(ss_detector_strobe) ); always @(*) begin next_state = state; - next_state_counter = state_counter + 1; - next_bit_timer_reset = 0; + next_mid_bit_counter = mid_bit_counter + 1; next_data = data; next_strobe = 0; @@ -102,288 +95,148 @@ module coax_rx ( case (state) STATE_IDLE: begin - next_bit_timer_reset = 1; - - if (!rx && previous_rx) + if (ss_detector_strobe) begin - next_state = STATE_START_SEQUENCE_1; - next_state_counter = 0; + // The start sequence ends with a code violation, so reset + // the mid bit counter as if the next mid-bit transition + // is half a bit away. + next_mid_bit_counter = CLOCKS_PER_HALF_BIT; + next_state = STATE_FIRST_SYNC_BIT; end end - STATE_START_SEQUENCE_1: + STATE_FIRST_SYNC_BIT: begin - if (sample) + // This is really the first STATE_SYNC_BIT, but we treat it + // differently and consider it part of the start sequence as + // it must be a 1 and we don't consider the receiver active + // until this has been detected. + next_bit_counter = 0; + + if (rx != previous_rx && mid_bit_counter > CLOCKS_PER_HALF_BIT) begin - if (synchronized && rx) - next_state = STATE_START_SEQUENCE_2; + next_mid_bit_counter = 0; + + if (rx) + next_state = STATE_DATA_BIT; else next_state = STATE_IDLE; - - next_state_counter = 0; end - else if (state_counter >= (CLOCKS_PER_BIT * 2)) + else if (mid_bit_counter > CLOCKS_LOSS_OF_MID_BIT_TRANSITION) begin next_state = STATE_IDLE; - next_state_counter = 0; end end - STATE_START_SEQUENCE_2: + STATE_SYNC_BIT: begin - if (sample) + next_active = 1; + next_bit_counter = 0; + + if (rx != previous_rx && mid_bit_counter > CLOCKS_PER_HALF_BIT) begin - if (synchronized && rx) - next_state = STATE_START_SEQUENCE_3; + next_mid_bit_counter = 0; + + if (rx) + next_state = STATE_DATA_BIT; else - next_state = STATE_IDLE; - - next_state_counter = 0; + next_state = STATE_END_SEQUENCE_1; + end + else if (mid_bit_counter > CLOCKS_LOSS_OF_MID_BIT_TRANSITION) + begin + next_data = ERROR_LOSS_OF_MID_BIT_TRANSITION; + next_state = STATE_ERROR; end end - STATE_START_SEQUENCE_3: + STATE_DATA_BIT: begin - if (sample) + next_active = 1; + + if (rx != previous_rx && mid_bit_counter > CLOCKS_PER_HALF_BIT) begin - if (synchronized && rx) - next_state = STATE_START_SEQUENCE_4; + next_mid_bit_counter = 0; + + next_input_data = { input_data[8:0], rx }; + + if (bit_counter < 9) + next_bit_counter = bit_counter + 1; else - next_state = STATE_IDLE; - - next_state_counter = 0; + next_state = STATE_PARITY_BIT; + end + else if (mid_bit_counter > CLOCKS_LOSS_OF_MID_BIT_TRANSITION) + begin + next_data = ERROR_LOSS_OF_MID_BIT_TRANSITION; + next_state = STATE_ERROR; end end - STATE_START_SEQUENCE_4: + STATE_PARITY_BIT: begin - if (sample) + next_active = 1; + + if (rx != previous_rx && mid_bit_counter > CLOCKS_PER_HALF_BIT) begin - if (synchronized && rx) - next_state = STATE_START_SEQUENCE_5; + if (rx == input_data_parity) + begin + next_strobe = 1; + next_data = input_data; + next_state = STATE_SYNC_BIT; + end else - next_state = STATE_IDLE; + begin + next_data = ERROR_PARITY; + next_state = STATE_ERROR; + end - next_state_counter = 0; + next_mid_bit_counter = 0; + end + else if (mid_bit_counter > CLOCKS_LOSS_OF_MID_BIT_TRANSITION) + begin + next_data = ERROR_LOSS_OF_MID_BIT_TRANSITION; + next_state = STATE_ERROR; end end - STATE_START_SEQUENCE_5: - begin - if (sample) - begin - if (synchronized && rx) - next_state = STATE_START_SEQUENCE_6; - else - next_state = STATE_IDLE; - - next_state_counter = 0; - end - end - - STATE_START_SEQUENCE_6: - begin - if (!rx) - begin - next_state = STATE_START_SEQUENCE_7; - next_state_counter = 0; - end - else if (state_counter >= CLOCKS_PER_BIT) - begin - next_state = STATE_IDLE; - next_state_counter = 0; - end - end - - STATE_START_SEQUENCE_7: + STATE_END_SEQUENCE_1: begin if (rx) begin - next_state = STATE_START_SEQUENCE_8; - next_state_counter = 0; + next_state = STATE_END_SEQUENCE_2; + next_mid_bit_counter = 0; end - else if (state_counter >= (CLOCKS_PER_BIT * 2)) + else if (mid_bit_counter > CLOCKS_PER_BIT) begin - next_state = STATE_IDLE; - next_state_counter = 0; + next_data = ERROR_INVALID_END_SEQUENCE; + next_state = STATE_ERROR; end end - STATE_START_SEQUENCE_8: + STATE_END_SEQUENCE_2: begin if (!rx) - begin - next_bit_timer_reset = 1; - next_state = STATE_START_SEQUENCE_9; - next_state_counter = 0; - end - else if (state_counter >= (CLOCKS_PER_BIT * 2)) begin next_state = STATE_IDLE; - next_state_counter = 0; + end + else if (mid_bit_counter > CLOCKS_PER_3_BIT) + begin + // TODO: should this go to ERROR on timeout? + next_state = STATE_IDLE; end end - STATE_START_SEQUENCE_9: + STATE_ERROR: begin - // This is really the first STATE_SYNC_BIT but we treat it - // differently and consider it part of the start - // sequence. - - if (sample && synchronized) - begin - if (rx) - begin - next_bit_counter = 0; - next_state = STATE_DATA_BIT; - end - else - begin - next_state = STATE_IDLE; - end - - next_state_counter = 0; - end - else if (state_counter >= CLOCKS_PER_BIT) - begin - next_state = STATE_IDLE; - next_state_counter = 0; - end - end - - STATE_SYNC_BIT: - begin - next_active = 1; - - if (sample) - begin - if (synchronized) - begin - if (rx) - begin - next_bit_counter = 0; - next_state = STATE_DATA_BIT; - end - else - begin - next_state = STATE_END_SEQUENCE_1; - end - - next_state_counter = 0; - end - else - begin - next_data = ERROR_LOSS_OF_MID_BIT_TRANSITION; - next_state = STATE_ERROR; - next_state_counter = 0; - end - end - end - - STATE_DATA_BIT: - begin - next_active = 1; - - if (sample) - begin - if (synchronized) - begin - next_input_data = { input_data[8:0], rx }; - - if (bit_counter < 9) - begin - next_bit_counter = bit_counter + 1; - end - else - begin - next_state = STATE_PARITY_BIT; - end - - next_state_counter = 0; - end - else - begin - next_data = ERROR_LOSS_OF_MID_BIT_TRANSITION; - next_state = STATE_ERROR; - next_state_counter = 0; - end - end - end - - STATE_PARITY_BIT: - begin - next_active = 1; - - if (sample) - begin - if (synchronized) - begin - if (rx == input_data_parity) - begin - next_strobe = 1; - next_data = input_data; - next_state = STATE_SYNC_BIT; - end - else - begin - next_data = ERROR_PARITY; - next_state = STATE_ERROR; - end - - next_state_counter = 0; - end - else - begin - next_data = ERROR_LOSS_OF_MID_BIT_TRANSITION; - next_state = STATE_ERROR; - next_state_counter = 0; - end - end - end - - STATE_END_SEQUENCE_1: - begin - if (rx) - begin - next_state = STATE_END_SEQUENCE_2; - next_state_counter = 0; - end - else if (state_counter >= CLOCKS_PER_BIT) - begin - next_data = ERROR_INVALID_END_SEQUENCE; - next_state = STATE_ERROR; - next_state_counter = 0; - end - end - - STATE_END_SEQUENCE_2: - begin - // TODO: should this go to ERROR on timeout? - if (!rx) - begin - next_state = STATE_IDLE; - next_state_counter = 0; - end - else if (state_counter >= (CLOCKS_PER_BIT * 2)) - begin - next_state = STATE_IDLE; - next_state_counter = 0; - end - end - - STATE_ERROR: - begin - next_error = 1; - end + next_error = 1; + end endcase end always @(posedge clk) begin state <= next_state; - state_counter <= next_state_counter; - bit_timer_reset <= next_bit_timer_reset; + mid_bit_counter <= next_mid_bit_counter; data <= next_data; strobe <= next_strobe; @@ -400,8 +253,6 @@ module coax_rx ( if (reset) begin - bit_timer_reset <= 1; - state <= STATE_IDLE; strobe <= 0; diff --git a/interface2/fpga/rtl/coax_rx_bit_timer.v b/interface2/fpga/rtl/coax_rx_bit_timer.v deleted file mode 100644 index 2f83e7e..0000000 --- a/interface2/fpga/rtl/coax_rx_bit_timer.v +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2020, 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_bit_timer ( - input clk, - input rx, - input reset, - output reg sample, - output reg synchronized -); - parameter CLOCKS_PER_BIT = 8; - - localparam IDLE = 0; - localparam SYNCHRONIZED = 1; - localparam UNSYNCHRONIZED = 2; - - reg [1:0] state = IDLE; - reg [1:0] next_state; - - reg previous_rx; - - reg [$clog2(CLOCKS_PER_BIT*2):0] transition_counter = 0; - reg [$clog2(CLOCKS_PER_BIT*2):0] next_transition_counter; - reg [$clog2(CLOCKS_PER_BIT):0] bit_counter = 0; - reg [$clog2(CLOCKS_PER_BIT):0] next_bit_counter; - - always @(*) - begin - next_state = state; - - sample = 0; - synchronized = 0; - - next_transition_counter = transition_counter; - next_bit_counter = bit_counter; - - case (state) - IDLE: - begin - if (rx != previous_rx) - begin - next_transition_counter = 0; - next_bit_counter = CLOCKS_PER_BIT / 2; - - next_state = SYNCHRONIZED; - end - end - - SYNCHRONIZED: - begin - if (transition_counter < (CLOCKS_PER_BIT + (CLOCKS_PER_BIT / 4))) - next_transition_counter = transition_counter + 1; - else - next_state = UNSYNCHRONIZED; - - synchronized = 1; - - if (bit_counter < CLOCKS_PER_BIT) - next_bit_counter = bit_counter + 1; - else - next_bit_counter = 0; - - if (rx != previous_rx && transition_counter > (CLOCKS_PER_BIT / 2)) - begin - next_transition_counter = 0; - next_bit_counter = CLOCKS_PER_BIT / 2; - end - - if (bit_counter == ((CLOCKS_PER_BIT / 4) * 3)) - sample = 1; - end - - UNSYNCHRONIZED: - begin - if (bit_counter < CLOCKS_PER_BIT) - next_bit_counter = bit_counter + 1; - else - next_bit_counter = 0; - - if (bit_counter == ((CLOCKS_PER_BIT / 4) * 3)) - sample = 1; - end - endcase - end - - always @(posedge clk) - begin - state <= next_state; - - transition_counter <= next_transition_counter; - bit_counter <= next_bit_counter; - - if (reset) - state <= IDLE; - - previous_rx <= rx; - end -endmodule diff --git a/interface2/fpga/rtl/coax_rx_ss_detector.v b/interface2/fpga/rtl/coax_rx_ss_detector.v new file mode 100644 index 0000000..f966540 --- /dev/null +++ b/interface2/fpga/rtl/coax_rx_ss_detector.v @@ -0,0 +1,137 @@ +// 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_ss_detector ( + input clk, + input reset, + input enable, + input rx, + output reg strobe = 0 +); + parameter CLOCKS_PER_BIT = 8; + + localparam CLOCKS_PER_1_5_BIT = CLOCKS_PER_BIT + (CLOCKS_PER_BIT / 2); + localparam CLOCKS_PER_2_BIT = CLOCKS_PER_BIT * 2; + localparam CLOCKS_PER_2_5_BIT = (CLOCKS_PER_BIT * 2) + (CLOCKS_PER_BIT / 2); + localparam CLOCKS_PER_3_5_BIT = (CLOCKS_PER_BIT * 3) + (CLOCKS_PER_BIT / 2); + + // Number of pulses (or "bits") required before the code violation. + localparam PULSE_COUNT = 5; + + localparam STATE_IDLE = 0; + localparam STATE_PULSE = 1; + localparam STATE_CODE_VIOLATION_FIRST_HALF = 2; + localparam STATE_CODE_VIOLATION_SECOND_HALF = 3; + + reg [1:0] state = STATE_IDLE; + reg [1:0] next_state; + + reg next_strobe; + + reg [$clog2(CLOCKS_PER_3_5_BIT):0] rx_negedge_counter; + reg [$clog2(CLOCKS_PER_3_5_BIT):0] next_rx_negedge_counter; + + reg [$clog2(PULSE_COUNT-1):0] pulse_counter; + reg [$clog2(PULSE_COUNT-1):0] next_pulse_counter; + + reg previous_rx; + + always @(*) + begin + next_state = state; + + next_strobe = 0; + + // Count the clocks since the last negedge. + next_rx_negedge_counter = rx_negedge_counter + 1; + + if (!rx && previous_rx) + next_rx_negedge_counter = 0; + + next_pulse_counter = pulse_counter; + + case (state) + STATE_IDLE: + begin + if (!rx && previous_rx) + next_state = STATE_PULSE; + + // Consider this the first pulse. + next_pulse_counter = 1; + end + + STATE_PULSE: + begin + if (!rx && previous_rx) + begin + if (pulse_counter == (PULSE_COUNT - 1)) + next_state = STATE_CODE_VIOLATION_FIRST_HALF; + else + next_pulse_counter = pulse_counter + 1; + end + else if (rx_negedge_counter > CLOCKS_PER_1_5_BIT) + begin + next_state = STATE_IDLE; + end + end + + STATE_CODE_VIOLATION_FIRST_HALF: + begin + if (rx && !previous_rx && rx_negedge_counter > CLOCKS_PER_BIT) + next_state = STATE_CODE_VIOLATION_SECOND_HALF; + else if (rx_negedge_counter > CLOCKS_PER_2_BIT) + next_state = STATE_IDLE; + end + + STATE_CODE_VIOLATION_SECOND_HALF: + begin + // Although this is a negedge, the negedge_counter will not + // reset until the next clock cycle so this comparison is valid. + if (!rx && rx_negedge_counter > CLOCKS_PER_2_5_BIT) + begin + next_strobe = 1; + next_state = STATE_IDLE; + end + else if (rx_negedge_counter > CLOCKS_PER_3_5_BIT) + begin + next_state = STATE_IDLE; + end + end + endcase + end + + always @(posedge clk) + begin + state <= next_state; + + strobe <= next_strobe; + + rx_negedge_counter <= next_rx_negedge_counter; + pulse_counter <= next_pulse_counter; + + if (reset || !enable) + begin + state <= STATE_IDLE; + + strobe <= 0; + + rx_negedge_counter <= 0; + pulse_counter <= 0; + end + + previous_rx <= rx; + end +endmodule diff --git a/interface2/fpga/rtl/coax_syn.prj b/interface2/fpga/rtl/coax_syn.prj index 38f3c7c..a679398 100644 --- a/interface2/fpga/rtl/coax_syn.prj +++ b/interface2/fpga/rtl/coax_syn.prj @@ -4,7 +4,7 @@ add_file -verilog -lib work "coax_buffered_rx.v" add_file -verilog -lib work "coax_rx.v" -add_file -verilog -lib work "coax_rx_bit_timer.v" +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" diff --git a/interface2/fpga/tests/Makefile b/interface2/fpga/tests/Makefile index 12946c8..ca2e2fe 100644 --- a/interface2/fpga/tests/Makefile +++ b/interface2/fpga/tests/Makefile @@ -6,14 +6,14 @@ TESTS = $(patsubst %.v,%,$(wildcard *_tb.v)) all: test coax_buffer_tb: coax_buffer_tb.v $(RTL)/coax_buffer.v $(RTL)/third_party/*.v -coax_buffered_rx_tb: coax_buffered_rx_tb.v $(RTL)/coax_buffered_rx.v $(RTL)/coax_rx.v $(RTL)/coax_rx_bit_timer.v $(RTL)/coax_buffer.v $(RTL)/third_party/*.v +coax_buffered_rx_tb: coax_buffered_rx_tb.v $(RTL)/coax_buffered_rx.v $(RTL)/coax_rx.v $(RTL)/coax_rx_ss_detector.v $(RTL)/coax_buffer.v $(RTL)/third_party/*.v coax_buffered_tx_tb: coax_buffered_tx_tb.v $(RTL)/coax_buffered_tx.v $(RTL)/coax_tx.v $(RTL)/coax_tx_bit_timer.v $(RTL)/coax_buffer.v $(RTL)/third_party/*.v -coax_rx_bit_timer_tb: coax_rx_bit_timer_tb.v $(RTL)/coax_rx_bit_timer.v -coax_rx_tb: coax_rx_tb.v $(RTL)/coax_rx.v $(RTL)/coax_rx_bit_timer.v +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 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 test: $(TESTS) ./run_tests.sh diff --git a/interface2/fpga/tests/coax_rx_bit_timer_tb.v b/interface2/fpga/tests/coax_rx_bit_timer_tb.v deleted file mode 100644 index 3c68ba6..0000000 --- a/interface2/fpga/tests/coax_rx_bit_timer_tb.v +++ /dev/null @@ -1,75 +0,0 @@ -`default_nettype none - -`include "mock_tx.v" - -module coax_rx_bit_timer_tb; - reg clk = 0; - - initial - begin - forever - begin - #1 clk <= ~clk; - end - end - - wire rx; - - mock_tx mock_tx ( - .tx(rx) - ); - - reg reset = 0; - wire sample; - wire synchronized; - - coax_rx_bit_timer #( - .CLOCKS_PER_BIT(8) - ) dut ( - .clk(clk), - .rx(rx), - .reset(reset), - .sample(sample), - .synchronized(synchronized) - ); - - initial - begin - $dumpfile("coax_rx_bit_timer_tb.vcd"); - $dumpvars(0, coax_rx_bit_timer_tb); - - // Idle - #32; - - // Perfect - mock_tx.tx_bit(1); - mock_tx.tx_bit(0); - mock_tx.tx_bit(1); - - // Delayed - mock_tx.tx_bit_custom(0, 9, 8); - - // Shortened - mock_tx.tx_bit_custom(0, 6, 7); - - // Stuck - mock_tx.tx_bit_custom(1, 24, 8); - - // Reset - dut_reset; - - mock_tx.tx_bit(1); - - #32; - - $finish; - end - - task dut_reset; - begin - reset = 1; - #2; - reset = 0; - end - endtask -endmodule diff --git a/interface2/fpga/tests/coax_rx_tb.v b/interface2/fpga/tests/coax_rx_tb.v index 3542e54..eb68104 100644 --- a/interface2/fpga/tests/coax_rx_tb.v +++ b/interface2/fpga/tests/coax_rx_tb.v @@ -36,29 +36,28 @@ module coax_rx_tb; $dumpfile("coax_rx_tb.vcd"); $dumpvars(0, coax_rx_tb); - test_1; - test_2; - test_3; - test_4; - test_5; - test_6; - test_7; - test_8; - test_9; - test_10; - test_11; - test_12; - test_13; - test_14; - test_15; - test_16; + test_reset; + test_invalid_start_sequence_1_pulse; + test_invalid_start_sequence_2_pulse; + test_invalid_start_sequence_3_pulse; + test_invalid_start_sequence_4_pulse; + test_invalid_start_sequence_code_violation_first_half; + test_invalid_start_sequence_code_violation_second_half; + test_invalid_sync_bit; + test_loss_of_mid_bit_transition_error_data_bit_1; + test_loss_of_mid_bit_transition_error_data_bit_5; + test_loss_of_mid_bit_transition_error_parity_bit; + test_parity_error; + test_loss_of_mid_bit_transition_error_sync_end_bit; + test_invalid_end_sequence; + test_data; $finish; end - task test_1; + task test_reset; begin - $display("START: test_1"); + $display("START: test_reset"); `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); @@ -68,13 +67,13 @@ module coax_rx_tb; `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); - $display("END: test_1"); + $display("END: test_reset"); end endtask - task test_2; + task test_invalid_start_sequence_1_pulse; begin - $display("START: test_2"); + $display("START: test_invalid_start_sequence_1_pulse"); `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); @@ -83,14 +82,15 @@ module coax_rx_tb; #64; `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); + `assert_equal(dut.ss_detector.state, dut.ss_detector.STATE_IDLE, "ss_detector.state should be STATE_IDLE"); - $display("END: test_2"); + $display("END: test_invalid_start_sequence_1_pulse"); end endtask - task test_3; + task test_invalid_start_sequence_2_pulse; begin - $display("START: test_3"); + $display("START: test_invalid_start_sequence_2_pulse"); `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); @@ -103,14 +103,15 @@ module coax_rx_tb; #64; `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); + `assert_equal(dut.ss_detector.state, dut.ss_detector.STATE_IDLE, "ss_detector.state should be STATE_IDLE"); - $display("END: test_3"); + $display("END: test_invalid_start_sequence_2_pulse"); end endtask - task test_4; + task test_invalid_start_sequence_3_pulse; begin - $display("START: test_4"); + $display("START: test_invalid_start_sequence_3_pulse"); `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); @@ -124,14 +125,15 @@ module coax_rx_tb; #64; `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); + `assert_equal(dut.ss_detector.state, dut.ss_detector.STATE_IDLE, "ss_detector.state should be STATE_IDLE"); - $display("END: test_4"); + $display("END: test_invalid_start_sequence_3_pulse"); end endtask - task test_5; + task test_invalid_start_sequence_4_pulse; begin - $display("START: test_5"); + $display("START: test_invalid_start_sequence_4_pulse"); `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); @@ -146,14 +148,15 @@ module coax_rx_tb; #64; `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); + `assert_equal(dut.ss_detector.state, dut.ss_detector.STATE_IDLE, "ss_detector.state should be STATE_IDLE"); - $display("END: test_5"); + $display("END: test_invalid_start_sequence_4_pulse"); end endtask - task test_6; + task test_invalid_start_sequence_code_violation_first_half; begin - $display("START: test_6"); + $display("START: test_invalid_start_sequence_code_violation_first_half"); `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); @@ -169,38 +172,15 @@ module coax_rx_tb; #64; `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); + `assert_equal(dut.ss_detector.state, dut.ss_detector.STATE_IDLE, "ss_detector.state should be STATE_IDLE"); - $display("END: test_6"); + $display("END: test_invalid_start_sequence_code_violation_first_half"); end endtask - task test_7; + task test_invalid_start_sequence_code_violation_second_half; begin - $display("START: test_7"); - - `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); - - mock_tx.tx_set(1); - #16; - mock_tx.tx_set(0); - - mock_tx.tx_bit(1); - mock_tx.tx_bit(1); - mock_tx.tx_bit(1); - mock_tx.tx_bit(1); - mock_tx.tx_bit(1); - - #64; - - `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); - - $display("END: test_7"); - end - endtask - - task test_8; - begin - $display("START: test_8"); + $display("START: test_invalid_start_sequence_code_violation_second_half"); `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); @@ -221,16 +201,17 @@ module coax_rx_tb; #64; `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); + `assert_equal(dut.ss_detector.state, dut.ss_detector.STATE_IDLE, "ss_detector.state should be STATE_IDLE"); mock_tx.tx_set(0); - $display("END: test_8"); + $display("END: test_invalid_start_sequence_code_violation_second_half"); end endtask - task test_9; + task test_invalid_sync_bit; begin - $display("START: test_9"); + $display("START: test_invalid_sync_bit"); `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); @@ -241,14 +222,15 @@ module coax_rx_tb; #64; `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); + `assert_equal(dut.ss_detector.state, dut.ss_detector.STATE_IDLE, "ss_detector.state should be STATE_IDLE"); - $display("END: test_9"); + $display("END: test_invalid_sync_bit"); end endtask - task test_10; + task test_loss_of_mid_bit_transition_error_data_bit_1; begin - $display("START: test_10"); + $display("START: test_loss_of_mid_bit_transition_error_data_bit_1"); `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); @@ -268,13 +250,13 @@ module coax_rx_tb; `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); - $display("END: test_10"); + $display("END: test_loss_of_mid_bit_transition_error_data_bit_1"); end endtask - task test_11; + task test_loss_of_mid_bit_transition_error_data_bit_5; begin - $display("START: test_11"); + $display("START: test_loss_of_mid_bit_transition_error_data_bit_5"); `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); @@ -299,13 +281,13 @@ module coax_rx_tb; `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); - $display("END: test_11"); + $display("END: test_loss_of_mid_bit_transition_error_data_bit_5"); end endtask - task test_12; + task test_loss_of_mid_bit_transition_error_parity_bit; begin - $display("START: test_12"); + $display("START: test_loss_of_mid_bit_transition_error_parity_bit"); `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); @@ -335,13 +317,13 @@ module coax_rx_tb; `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); - $display("END: test_12"); + $display("END: test_loss_of_mid_bit_transition_error_parity_bit"); end endtask - task test_13; + task test_parity_error; begin - $display("START: test_13"); + $display("START: test_parity_error"); `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); @@ -372,13 +354,13 @@ module coax_rx_tb; `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); - $display("END: test_13"); + $display("END: test_parity_error"); end endtask - task test_14; + task test_loss_of_mid_bit_transition_error_sync_end_bit; begin - $display("START: test_14"); + $display("START: test_loss_of_mid_bit_transition_error_sync_end_bit"); `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); @@ -409,13 +391,13 @@ module coax_rx_tb; `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); - $display("END: test_14"); + $display("END: test_loss_of_mid_bit_transition_error_sync_end_bit"); end endtask - task test_15; + task test_invalid_end_sequence; begin - $display("START: test_15"); + $display("START: test_invalid_end_sequence"); `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); @@ -447,13 +429,13 @@ module coax_rx_tb; `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); - $display("END: test_15"); + $display("END: test_invalid_end_sequence"); end endtask - task test_16; + task test_data; begin - $display("START: test_16"); + $display("START: test_data"); `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); @@ -478,7 +460,7 @@ module coax_rx_tb; `assert_equal(dut.data, 10'b0110110011, "data not correct") - $display("END: test_16"); + $display("END: test_data"); end endtask diff --git a/interface2/fpga/tests/regression_memorex_tb.v b/interface2/fpga/tests/regression_memorex_tb.v new file mode 100644 index 0000000..0178506 --- /dev/null +++ b/interface2/fpga/tests/regression_memorex_tb.v @@ -0,0 +1,171 @@ +`default_nettype none + +`include "assert.v" + +module regression_memorex_tb; + reg clk = 0; + + initial + begin + forever + begin + #1 clk <= ~clk; + end + end + + reg rx = 0; + reg reset = 0; + + coax_rx #( + .CLOCKS_PER_BIT(8) + ) dut ( + .clk(clk), + .reset(reset), + .rx(rx), + .parity(1'b1) + ); + + initial + begin + $dumpfile("regression_memorex_tb.vcd"); + $dumpvars(0, regression_memorex_tb); + + test_1; + + $finish; + end + + task test_1; + begin + $display("START: test_1"); + + `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); + + rx = 0; + #20; + rx = 1; + #5; + rx = 0; + #10; + rx = 1; + #10; + rx = 0; + #5; + rx = 1; + #10; + rx = 0; + #10; + rx = 1; + #10; + rx = 0; + #5; + rx = 1; + #10; + rx = 0; + #10; + rx = 1; + #5; + rx = 0; + #10; + rx = 1; + #10; + rx = 0; + #5; + rx = 1; + #10; + rx = 0; + #10; + rx = 1; + #10; + rx = 0; + #5; + rx = 1; + #10; + rx = 0; + #5; + rx = 1; + #10; + rx = 0; + #10; + rx = 1; + #10; + rx = 0; + #5; + rx = 1; + #10; + rx = 0; + #10; + rx = 1; + #10; + rx = 0; + #5; + rx = 1; + #10; + rx = 0; + #5; + rx = 1; + #10; + rx = 0; + #10; + rx = 1; + #10; + rx = 0; + #5; + rx = 1; + #10; + rx = 0; + #25; + rx = 1; + #25; + rx = 0; + #10; + rx = 1; + #15; + rx = 0; + #10; + rx = 1; + #10; + rx = 0; + #5; + rx = 1; + #10; + rx = 0; + #10; + rx = 1; + #5; + rx = 0; + #10; + rx = 1; + #10; + rx = 0; + #5; + rx = 1; + #10; + rx = 0; + #20; + rx = 1; + #15; + rx = 0; + #15; + rx = 1; + #20; + rx = 0; + #15; + rx = 1; + #20; + rx = 0; + #5; + rx = 1; + #35; + rx = 0; + + #64; + + `assert_equal(dut.state, dut.STATE_IDLE, "state should be STATE_IDLE"); + + `assert_equal(dut.data, 10'b0000001010, "data not correct") + + $display("END: test_1"); + end + endtask +endmodule