More robust coax_rx start sequence detection

This commit is contained in:
Andrew Kay
2021-10-24 16:04:48 -05:00
parent 803a16e93d
commit 55d7a2d784
9 changed files with 489 additions and 534 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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