Add 3299 protocol support to interface2

This commit is contained in:
Andrew Kay
2021-11-06 13:32:39 -05:00
parent 14fd7485fe
commit cec0ab781a
25 changed files with 1419 additions and 24 deletions

View File

@@ -24,6 +24,7 @@ module coax_buffered_rx (
input read_strobe,
output empty,
output full,
input protocol,
input parity
);
parameter CLOCKS_PER_BIT = 8;
@@ -45,6 +46,7 @@ module coax_buffered_rx (
.error(coax_rx_error),
.data(coax_rx_data),
.strobe(coax_rx_strobe),
.protocol(protocol),
.parity(parity)
);

View File

@@ -25,6 +25,7 @@ module coax_buffered_tx (
output empty,
output full,
output reg ready,
input protocol,
input parity
);
parameter CLOCKS_PER_BIT = 8;
@@ -56,6 +57,7 @@ module coax_buffered_tx (
.data(coax_tx_data),
.strobe(coax_tx_strobe),
.ready(coax_tx_ready),
.protocol(protocol),
.parity(parity)
);

View File

@@ -22,6 +22,7 @@ module coax_rx (
output reg error,
output reg [9:0] data,
output reg strobe = 0,
input protocol,
input parity
);
parameter CLOCKS_PER_BIT = 8;
@@ -95,6 +96,8 @@ module coax_rx (
case (state)
STATE_IDLE:
begin
next_input_data = 10'b0;
if (ss_detector_strobe)
begin
// The start sequence ends with a code violation, so reset
@@ -111,7 +114,7 @@ module coax_rx (
// 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;
next_bit_counter = (protocol == 1 ? 4 : 0);
if (rx != previous_rx && mid_bit_counter > CLOCKS_PER_HALF_BIT)
begin

View File

@@ -22,6 +22,7 @@ module coax_tx (
input [9:0] data,
input strobe,
output ready,
input protocol,
input parity
);
parameter CLOCKS_PER_BIT = 8;
@@ -48,6 +49,8 @@ module coax_tx (
reg next_tx;
reg first_word;
reg next_first_word;
reg end_sequence;
reg next_end_sequence;
@@ -86,6 +89,7 @@ module coax_tx (
next_tx = 0;
next_first_word = first_word;
next_end_sequence = 0;
next_output_data = output_data;
@@ -188,6 +192,7 @@ module coax_tx (
START_SEQUENCE_9:
begin
next_tx = 1;
next_first_word = 1;
if (last_clock)
next_state = SYNC_BIT;
@@ -197,10 +202,21 @@ module coax_tx (
begin
next_tx = first_half ? 0 : 1;
next_bit_counter = 9;
if (last_clock)
begin
// First word is 6 bits in 3299 protocol mode.
if (protocol == 1 && first_word)
begin
next_output_data = { output_data[5:0], 4'b0 };
next_bit_counter = 5;
end
else
begin
next_bit_counter = 9;
end
next_state = DATA_BIT;
end
end
DATA_BIT:
@@ -228,6 +244,8 @@ module coax_tx (
if (last_clock)
begin
next_first_word = 0;
if (output_data_full)
begin
next_state = SYNC_BIT;
@@ -280,6 +298,7 @@ module coax_tx (
active <= (state != IDLE); // TODO: this causes active to remain high one additional clock cycle
tx <= next_tx;
first_word <= next_first_word;
end_sequence <= next_end_sequence;
output_data <= next_output_data;

View File

@@ -36,6 +36,7 @@ module control (
input tx_empty,
input tx_full,
input tx_ready,
output tx_protocol,
output tx_parity,
// RX
@@ -45,6 +46,7 @@ module control (
input [9:0] rx_data,
output reg rx_read_strobe,
input rx_empty,
output rx_protocol,
output rx_parity
);
parameter DEFAULT_CONTROL_REGISTER = 8'b01001000;
@@ -342,6 +344,8 @@ module control (
assign loopback = control_register[0];
assign tx_protocol = control_register[2];
assign tx_parity = control_register[3];
assign rx_protocol = control_register[5];
assign rx_parity = control_register[6];
endmodule

View File

@@ -98,6 +98,7 @@ module top (
wire tx_empty;
wire tx_full;
wire tx_ready;
wire tx_protocol;
wire tx_parity;
coax_buffered_tx #(
@@ -115,6 +116,7 @@ module top (
.empty(tx_empty),
.full(tx_full),
.ready(tx_ready),
.protocol(tx_protocol),
.parity(tx_parity)
);
@@ -125,6 +127,7 @@ module top (
wire [9:0] rx_data;
wire rx_read_strobe;
wire rx_empty;
wire rx_protocol;
wire rx_parity;
coax_buffered_rx #(
@@ -139,6 +142,7 @@ module top (
.data(rx_data),
.read_strobe(rx_read_strobe),
.empty(rx_empty),
.protocol(rx_protocol),
.parity(rx_parity)
);
@@ -184,6 +188,7 @@ module top (
.tx_empty(tx_empty),
.tx_full(tx_full),
.tx_ready(tx_ready),
.tx_protocol(tx_protocol),
.tx_parity(tx_parity),
.rx_reset(rx_reset),
@@ -192,6 +197,7 @@ module top (
.rx_data(rx_data),
.rx_read_strobe(rx_read_strobe),
.rx_empty(rx_empty),
.rx_protocol(rx_protocol),
.rx_parity(rx_parity)
);

View File

@@ -15,6 +15,7 @@ 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
tx_rx_loopback_tb: tx_rx_loopback_tb.v $(RTL)/coax_tx.v $(RTL)/coax_tx_bit_timer.v $(RTL)/coax_rx.v $(RTL)/coax_rx_ss_detector.v
regression_memorex_tb: regression_memorex_tb.v $(RTL)/coax_rx.v $(RTL)/coax_rx_ss_detector.v
test: $(TESTS)

View File

@@ -31,6 +31,7 @@ module coax_buffered_rx_tb;
.reset(reset),
.rx(rx),
.read_strobe(read_strobe),
.protocol(1'b0),
.parity(1'b1)
);

View File

@@ -28,6 +28,7 @@ module coax_buffered_tx_tb;
.data(data),
.load_strobe(load_strobe),
.start_strobe(start_strobe),
.protocol(1'b0),
.parity(1'b1)
);

View File

@@ -28,6 +28,7 @@ module coax_rx_tb;
.clk(clk),
.reset(reset),
.rx(rx),
.protocol(1'b0),
.parity(1'b1)
);

View File

@@ -24,6 +24,7 @@ module coax_tx_tb;
.reset(reset),
.data(data),
.strobe(strobe),
.protocol(1'b0),
.parity(1'b1)
);

View File

@@ -22,6 +22,7 @@ module regression_memorex_tb;
.clk(clk),
.reset(reset),
.rx(rx),
.protocol(1'b0),
.parity(1'b1)
);

View File

@@ -0,0 +1,323 @@
`default_nettype none
`include "assert.v"
module tx_rx_loopback_tb;
reg clk = 0;
initial
begin
forever
begin
#1 clk <= ~clk;
end
end
reg reset = 0;
wire loopback;
wire tx_active;
reg [9:0] tx_data;
reg tx_strobe = 0;
wire tx_ready;
reg tx_protocol = 0;
reg tx_parity = 0;
wire rx_error;
wire [9:0] rx_data;
wire rx_strobe;
reg rx_protocol = 0;
reg rx_parity = 0;
coax_tx #(
.CLOCKS_PER_BIT(8)
) dut_tx (
.clk(clk),
.reset(reset),
.active(tx_active),
.tx(loopback),
.data(tx_data),
.strobe(tx_strobe),
.ready(tx_ready),
.protocol(tx_protocol),
.parity(tx_parity)
);
coax_rx #(
.CLOCKS_PER_BIT(8)
) dut_rx (
.clk(clk),
.reset(reset),
.rx(loopback),
.error(rx_error),
.data(rx_data),
.strobe(rx_strobe),
.protocol(rx_protocol),
.parity(rx_parity)
);
initial
begin
$dumpfile("tx_rx_loopback_tb.vcd");
$dumpvars(0, tx_rx_loopback_tb);
test_3270_protocol;
test_3299_protocol;
test_protocol_mismatch;
test_parity_mismatch;
$finish;
end
task test_3270_protocol;
begin
$display("START: test_3270_protocol");
tx_protocol = 0;
tx_parity = 1;
rx_protocol = 0;
rx_parity = 1;
`assert_equal(dut_tx.state, dut_tx.IDLE, "state should be IDLE");
`assert_equal(dut_rx.state, dut_rx.STATE_IDLE, "state should be IDLE");
fork: test_3270_protocol_tx_rx_fork
begin
tx_data = 10'b0101110101;
#2;
tx_strobe = 1;
#2;
tx_strobe = 0;
@(posedge tx_ready);
tx_data = 10'b1010001010;
#2;
tx_strobe = 1;
#2;
tx_strobe = 0;
end
begin
@(posedge rx_strobe);
`assert_equal(rx_data, 10'b0101110101, "RX data should be equal to TX data");
@(posedge rx_strobe);
`assert_equal(rx_data, 10'b1010001010, "RX data should be equal to TX data");
disable test_3270_protocol_tx_rx_fork;
end
begin
#1000;
$display("[TIMEOUT] %m (%s:%0d)", `__FILE__, `__LINE__);
disable test_3270_protocol_tx_rx_fork;
end
join
#100;
`assert_equal(dut_tx.state, dut_tx.IDLE, "state should be IDLE");
`assert_equal(dut_rx.state, dut_rx.STATE_IDLE, "state should be IDLE");
$display("END: test_3270_protocol");
end
endtask
task test_3299_protocol;
begin
$display("START: test_3299_protocol");
tx_protocol = 1;
tx_parity = 1;
rx_protocol = 1;
rx_parity = 1;
`assert_equal(dut_tx.state, dut_tx.IDLE, "state should be IDLE");
`assert_equal(dut_rx.state, dut_rx.STATE_IDLE, "state should be IDLE");
fork: test_3299_protocol_tx_rx_fork
begin
tx_data = 10'b0000110001;
#2;
tx_strobe = 1;
#2;
tx_strobe = 0;
@(posedge tx_ready);
tx_data = 10'b0101110101;
#2;
tx_strobe = 1;
#2;
tx_strobe = 0;
@(posedge tx_ready);
tx_data = 10'b1010001010;
#2;
tx_strobe = 1;
#2;
tx_strobe = 0;
end
begin
@(posedge rx_strobe);
`assert_equal(rx_data, 10'b0000110001, "RX data should be equal to TX data");
@(posedge rx_strobe);
`assert_equal(rx_data, 10'b0101110101, "RX data should be equal to TX data");
@(posedge rx_strobe);
`assert_equal(rx_data, 10'b1010001010, "RX data should be equal to TX data");
disable test_3299_protocol_tx_rx_fork;
end
begin
#1000;
$display("[TIMEOUT] %m (%s:%0d)", `__FILE__, `__LINE__);
disable test_3299_protocol_tx_rx_fork;
end
join
#100;
`assert_equal(dut_tx.state, dut_tx.IDLE, "state should be IDLE");
`assert_equal(dut_rx.state, dut_rx.STATE_IDLE, "state should be IDLE");
$display("END: test_3299_protocol");
end
endtask
task test_protocol_mismatch;
begin
$display("START: test_protocol_mismatch");
tx_protocol = 1;
tx_parity = 1;
rx_protocol = 0;
rx_parity = 1;
`assert_equal(dut_tx.state, dut_tx.IDLE, "state should be IDLE");
`assert_equal(dut_rx.state, dut_rx.STATE_IDLE, "state should be IDLE");
fork: test_protocol_mismatch_tx_rx_fork
begin
tx_data = 10'b0000110001;
#2;
tx_strobe = 1;
#2;
tx_strobe = 0;
@(posedge tx_ready);
tx_data = 10'b0101110101;
#2;
tx_strobe = 1;
#2;
tx_strobe = 0;
// Wait for TX to complete... we don't want to reset the RX
// to soon as it could be reactivated with the remaining
// transmission.
@(negedge tx_active);
disable test_protocol_mismatch_tx_rx_fork;
end
begin
#1000;
$display("[TIMEOUT] %m (%s:%0d)", `__FILE__, `__LINE__);
disable test_protocol_mismatch_tx_rx_fork;
end
join
// The exact error (parity or loss of mid-bit transition) may depend
// on the length of message and data.
`assert_high(rx_error, "RX error should be HIGH");
`assert_equal(rx_data, dut_rx.ERROR_LOSS_OF_MID_BIT_TRANSITION, "RX data should be ERROR_LOSS_OF_MID_BIT_TRANSITION");
#16;
dut_reset;
#100;
`assert_equal(dut_tx.state, dut_tx.IDLE, "state should be IDLE");
`assert_equal(dut_rx.state, dut_rx.STATE_IDLE, "state should be IDLE");
$display("END: test_protocol_mismatch");
end
endtask
task test_parity_mismatch;
begin
$display("START: test_parity_mismatch");
tx_protocol = 0;
tx_parity = 1;
rx_protocol = 0;
rx_parity = 0;
`assert_equal(dut_tx.state, dut_tx.IDLE, "state should be IDLE");
`assert_equal(dut_rx.state, dut_rx.STATE_IDLE, "state should be IDLE");
fork: test_parity_mismatch_tx_rx_fork
begin
tx_data = 10'b0101110101;
#2;
tx_strobe = 1;
#2;
tx_strobe = 0;
// Wait for TX to complete... we don't want to reset the RX
// to soon as it could be reactivated with the remaining
// transmission.
@(negedge tx_active);
disable test_parity_mismatch_tx_rx_fork;
end
begin
#1000;
$display("[TIMEOUT] %m (%s:%0d)", `__FILE__, `__LINE__);
disable test_parity_mismatch_tx_rx_fork;
end
join
`assert_high(rx_error, "RX error should be HIGH");
`assert_equal(rx_data, dut_rx.ERROR_PARITY, "RX data should be ERROR_PARITY");
#16;
dut_reset;
#100;
`assert_equal(dut_tx.state, dut_tx.IDLE, "state should be IDLE");
`assert_equal(dut_rx.state, dut_rx.STATE_IDLE, "state should be IDLE");
$display("END: test_parity_mismatch");
end
endtask
task dut_reset;
begin
reset = 1;
#2;
reset = 0;
end
endtask
endmodule