mirror of
https://github.com/lowobservable/coax.git
synced 2026-02-27 01:19:52 +00:00
Add initial coax_tx
This commit is contained in:
295
interface2/rtl/coax_tx.v
Normal file
295
interface2/rtl/coax_tx.v
Normal file
@@ -0,0 +1,295 @@
|
||||
`default_nettype none
|
||||
|
||||
module coax_tx (
|
||||
input clk,
|
||||
input reset,
|
||||
output reg active,
|
||||
output reg tx,
|
||||
input [9:0] data,
|
||||
input load,
|
||||
output full
|
||||
);
|
||||
parameter CLOCKS_PER_BIT = 8;
|
||||
|
||||
localparam IDLE = 0;
|
||||
localparam START_SEQUENCE_1 = 1;
|
||||
localparam START_SEQUENCE_2 = 2;
|
||||
localparam START_SEQUENCE_3 = 3;
|
||||
localparam START_SEQUENCE_4 = 4;
|
||||
localparam START_SEQUENCE_5 = 5;
|
||||
localparam START_SEQUENCE_6 = 6;
|
||||
localparam START_SEQUENCE_7 = 7;
|
||||
localparam START_SEQUENCE_8 = 8;
|
||||
localparam SYNC_BIT = 9;
|
||||
localparam DATA_BIT = 10;
|
||||
localparam PARITY_BIT = 11;
|
||||
localparam END_SEQUENCE_1 = 12;
|
||||
localparam END_SEQUENCE_2 = 13;
|
||||
localparam END_SEQUENCE_3 = 14;
|
||||
|
||||
reg [3:0] state = IDLE;
|
||||
reg [3:0] next_state;
|
||||
|
||||
reg next_active;
|
||||
reg next_tx;
|
||||
|
||||
reg previous_load;
|
||||
|
||||
reg [9:0] holding_data;
|
||||
reg [9:0] next_holding_data;
|
||||
reg holding_data_full = 0;
|
||||
reg next_holding_data_full;
|
||||
|
||||
reg [9:0] output_data;
|
||||
reg [9:0] next_output_data;
|
||||
reg output_data_full = 0;
|
||||
reg next_output_data_full;
|
||||
|
||||
reg [3:0] bit_counter = 0;
|
||||
reg [3:0] next_bit_counter;
|
||||
|
||||
reg bit_timer_reset = 0;
|
||||
reg next_bit_timer_reset;
|
||||
|
||||
wire first_half;
|
||||
wire second_half;
|
||||
wire last_clock;
|
||||
|
||||
coax_tx_bit_timer #(
|
||||
.CLOCKS_PER_BIT(CLOCKS_PER_BIT)
|
||||
) bit_timer (
|
||||
.clk(clk),
|
||||
.reset(bit_timer_reset),
|
||||
.first_half(first_half),
|
||||
.second_half(second_half),
|
||||
.last_clock(last_clock)
|
||||
);
|
||||
|
||||
always @(*)
|
||||
begin
|
||||
next_state = state;
|
||||
|
||||
next_tx = 0;
|
||||
|
||||
next_holding_data = holding_data;
|
||||
next_holding_data_full = holding_data_full;
|
||||
next_output_data = output_data;
|
||||
next_output_data_full = output_data_full;
|
||||
|
||||
if (!load && previous_load)
|
||||
begin
|
||||
if (!holding_data_full && !output_data_full)
|
||||
begin
|
||||
next_output_data = data;
|
||||
next_output_data_full = 1;
|
||||
end
|
||||
else if (!holding_data_full)
|
||||
begin
|
||||
next_holding_data = data;
|
||||
next_holding_data_full = 1;
|
||||
end
|
||||
end
|
||||
|
||||
next_bit_counter = bit_counter;
|
||||
|
||||
next_bit_timer_reset = 0;
|
||||
|
||||
case (state)
|
||||
IDLE:
|
||||
begin
|
||||
if (output_data_full)
|
||||
begin
|
||||
next_bit_timer_reset = 1;
|
||||
next_state = START_SEQUENCE_1;
|
||||
end
|
||||
end
|
||||
|
||||
START_SEQUENCE_1:
|
||||
begin
|
||||
next_tx = first_half ? 0 : 1;
|
||||
|
||||
if (last_clock)
|
||||
next_state = START_SEQUENCE_2;
|
||||
end
|
||||
|
||||
START_SEQUENCE_2:
|
||||
begin
|
||||
next_tx = first_half ? 0 : 1;
|
||||
|
||||
if (last_clock)
|
||||
next_state = START_SEQUENCE_3;
|
||||
end
|
||||
|
||||
START_SEQUENCE_3:
|
||||
begin
|
||||
next_tx = first_half ? 0 : 1;
|
||||
|
||||
if (last_clock)
|
||||
next_state = START_SEQUENCE_4;
|
||||
end
|
||||
|
||||
START_SEQUENCE_4:
|
||||
begin
|
||||
next_tx = first_half ? 0 : 1;
|
||||
|
||||
if (last_clock)
|
||||
next_state = START_SEQUENCE_5;
|
||||
end
|
||||
|
||||
START_SEQUENCE_5:
|
||||
begin
|
||||
next_tx = first_half ? 0 : 1;
|
||||
|
||||
if (last_clock)
|
||||
next_state = START_SEQUENCE_6;
|
||||
end
|
||||
|
||||
START_SEQUENCE_6:
|
||||
begin
|
||||
next_tx = 0;
|
||||
|
||||
if (last_clock)
|
||||
next_state = START_SEQUENCE_7;
|
||||
end
|
||||
|
||||
START_SEQUENCE_7:
|
||||
begin
|
||||
next_tx = first_half ? 0 : 1;
|
||||
|
||||
if (last_clock)
|
||||
next_state = START_SEQUENCE_8;
|
||||
end
|
||||
|
||||
START_SEQUENCE_8:
|
||||
begin
|
||||
next_tx = 1;
|
||||
|
||||
if (last_clock)
|
||||
next_state = SYNC_BIT;
|
||||
end
|
||||
|
||||
SYNC_BIT:
|
||||
begin
|
||||
next_tx = first_half ? 0 : 1;
|
||||
|
||||
if (last_clock)
|
||||
begin
|
||||
next_bit_counter = 9;
|
||||
next_state = DATA_BIT;
|
||||
end
|
||||
end
|
||||
|
||||
DATA_BIT:
|
||||
begin
|
||||
next_tx = first_half ? ~output_data[9] : output_data[9];
|
||||
|
||||
if (last_clock)
|
||||
begin
|
||||
if (bit_counter == 0)
|
||||
begin
|
||||
next_state = PARITY_BIT;
|
||||
end
|
||||
else
|
||||
begin
|
||||
next_output_data = { output_data[8:0], output_data[9] };
|
||||
next_bit_counter = bit_counter - 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
PARITY_BIT:
|
||||
begin
|
||||
// Even parity includes the sync bit.
|
||||
next_tx = first_half ? ~^{ 1'b1, output_data } : ^{ 1'b1, output_data };
|
||||
|
||||
if (last_clock)
|
||||
begin
|
||||
next_output_data_full = 0;
|
||||
|
||||
if (holding_data_full)
|
||||
begin
|
||||
next_output_data = holding_data;
|
||||
next_output_data_full = 1;
|
||||
next_holding_data_full = 0;
|
||||
|
||||
next_state = SYNC_BIT;
|
||||
end
|
||||
else
|
||||
begin
|
||||
next_state = END_SEQUENCE_1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
END_SEQUENCE_1:
|
||||
begin
|
||||
next_tx = first_half ? 1 : 0;
|
||||
|
||||
if (last_clock)
|
||||
next_state = END_SEQUENCE_2;
|
||||
end
|
||||
|
||||
END_SEQUENCE_2:
|
||||
begin
|
||||
next_tx = 1;
|
||||
|
||||
if (last_clock)
|
||||
next_state = END_SEQUENCE_3;
|
||||
end
|
||||
|
||||
END_SEQUENCE_3:
|
||||
begin
|
||||
next_tx = 1;
|
||||
|
||||
if (last_clock)
|
||||
begin
|
||||
next_tx = 0;
|
||||
next_state = IDLE;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(*)
|
||||
begin
|
||||
next_active = (next_state != IDLE);
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
state <= next_state;
|
||||
|
||||
active <= next_active;
|
||||
tx <= next_tx;
|
||||
|
||||
holding_data <= next_holding_data;
|
||||
holding_data_full <= next_holding_data_full;
|
||||
output_data <= next_output_data;
|
||||
output_data_full <= next_output_data_full;
|
||||
|
||||
bit_counter <= next_bit_counter;
|
||||
|
||||
bit_timer_reset <= next_bit_timer_reset;
|
||||
|
||||
if (reset)
|
||||
begin
|
||||
state <= IDLE;
|
||||
|
||||
active <= 0;
|
||||
tx <= 0;
|
||||
|
||||
holding_data <= 10'b0000000000;
|
||||
holding_data_full <= 0;
|
||||
output_data <= 10'b0000000000;
|
||||
output_data_full <= 0;
|
||||
|
||||
bit_counter <= 0;
|
||||
|
||||
bit_timer_reset <= 0;
|
||||
end
|
||||
|
||||
previous_load <= load;
|
||||
end
|
||||
|
||||
assign full = holding_data_full;
|
||||
endmodule
|
||||
@@ -3,9 +3,10 @@ VVP ?= vvp
|
||||
|
||||
RTL = ../rtl
|
||||
|
||||
all: coax_tx_bit_timer_tb.vcd coax_rx_bit_timer_tb.vcd coax_rx_tb.vcd
|
||||
all: coax_tx_bit_timer_tb.vcd coax_tx_tb.vcd coax_rx_bit_timer_tb.vcd coax_rx_tb.vcd
|
||||
|
||||
coax_tx_bit_timer_tb: coax_tx_bit_timer_tb.v $(RTL)/coax_tx_bit_timer.v
|
||||
coax_tx_tb: coax_tx_tb.v $(RTL)/coax_tx.v $(RTL)/coax_tx_bit_timer.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
|
||||
|
||||
|
||||
112
interface2/tests/coax_tx_tb.v
Normal file
112
interface2/tests/coax_tx_tb.v
Normal file
@@ -0,0 +1,112 @@
|
||||
`default_nettype none
|
||||
|
||||
`include "assert.v"
|
||||
|
||||
module coax_tx_tb;
|
||||
reg clk = 0;
|
||||
|
||||
initial
|
||||
begin
|
||||
forever
|
||||
begin
|
||||
#1 clk <= ~clk;
|
||||
end
|
||||
end
|
||||
|
||||
reg reset = 0;
|
||||
reg [9:0] data;
|
||||
reg load = 0;
|
||||
|
||||
coax_tx #(
|
||||
.CLOCKS_PER_BIT(8)
|
||||
) dut (
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
.data(data),
|
||||
.load(load)
|
||||
);
|
||||
|
||||
initial
|
||||
begin
|
||||
$dumpfile("coax_tx_tb.vcd");
|
||||
$dumpvars(0, coax_tx_tb);
|
||||
|
||||
test_1;
|
||||
test_2;
|
||||
test_3;
|
||||
|
||||
$finish;
|
||||
end
|
||||
|
||||
task test_1;
|
||||
begin
|
||||
$display("START: test_1");
|
||||
|
||||
`assert_equal(dut.state, dut.IDLE, "state should be IDLE");
|
||||
|
||||
dut_reset;
|
||||
|
||||
#8;
|
||||
|
||||
`assert_equal(dut.state, dut.IDLE, "state should be IDLE");
|
||||
|
||||
$display("END: test_1");
|
||||
end
|
||||
endtask
|
||||
|
||||
task test_2;
|
||||
begin
|
||||
$display("START: test_2");
|
||||
|
||||
`assert_equal(dut.state, dut.IDLE, "state should be IDLE");
|
||||
|
||||
data = 10'b0101110101;
|
||||
|
||||
load = 1;
|
||||
#2;
|
||||
load = 0;
|
||||
|
||||
#400;
|
||||
|
||||
`assert_equal(dut.state, dut.IDLE, "state should be IDLE");
|
||||
|
||||
$display("END: test_2");
|
||||
end
|
||||
endtask
|
||||
|
||||
task test_3;
|
||||
begin
|
||||
$display("START: test_3");
|
||||
|
||||
`assert_equal(dut.state, dut.IDLE, "state should be IDLE");
|
||||
|
||||
data = 10'b0101110101;
|
||||
|
||||
load = 1;
|
||||
#2;
|
||||
load = 0;
|
||||
|
||||
#32;
|
||||
|
||||
data = 10'b1010001110;
|
||||
|
||||
load = 1;
|
||||
#2;
|
||||
load = 0;
|
||||
|
||||
#600;
|
||||
|
||||
`assert_equal(dut.state, dut.IDLE, "state should be IDLE");
|
||||
|
||||
$display("END: test_3");
|
||||
end
|
||||
endtask
|
||||
|
||||
task dut_reset;
|
||||
begin
|
||||
reset = 1;
|
||||
#2;
|
||||
reset = 0;
|
||||
end
|
||||
endtask
|
||||
endmodule
|
||||
Reference in New Issue
Block a user