mirror of
https://github.com/lowobservable/coax.git
synced 2026-01-27 20:57:26 +00:00
Add interface2
This commit is contained in:
10
interface2/fpga/rtl/.gitignore
vendored
Normal file
10
interface2/fpga/rtl/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
*.json
|
||||
*.asc
|
||||
*.bin
|
||||
|
||||
# iCEcube2
|
||||
.mac_address
|
||||
coax_Implmnt
|
||||
synlog.tcl
|
||||
*.log
|
||||
*.log.bak
|
||||
1
interface2/fpga/rtl/Makefile
Normal file
1
interface2/fpga/rtl/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
include icecube2.mk
|
||||
2
interface2/fpga/rtl/clocks.sdc
Normal file
2
interface2/fpga/rtl/clocks.sdc
Normal file
@@ -0,0 +1,2 @@
|
||||
create_clock -period 25.00 -name {clk} [get_ports {clk}]
|
||||
create_clock -period 100.00 -name {spi_sck} [get_ports {spi_sck}]
|
||||
94
interface2/fpga/rtl/coax_buffer.v
Normal file
94
interface2/fpga/rtl/coax_buffer.v
Normal file
@@ -0,0 +1,94 @@
|
||||
// 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_buffer (
|
||||
input clk,
|
||||
input reset,
|
||||
input [9:0] write_data,
|
||||
input write_strobe,
|
||||
output [9:0] read_data,
|
||||
input read_strobe,
|
||||
output empty,
|
||||
output full,
|
||||
output reg almost_empty,
|
||||
output reg almost_full
|
||||
);
|
||||
parameter DEPTH = 256;
|
||||
parameter ALMOST_EMPTY_THRESHOLD = 64;
|
||||
parameter ALMOST_FULL_THRESHOLD = 192;
|
||||
|
||||
fifo_sync_ram #(
|
||||
.DEPTH(DEPTH),
|
||||
.WIDTH(10)
|
||||
) fifo (
|
||||
.wr_data(write_data),
|
||||
.wr_ena(write_strobe),
|
||||
.wr_full(full),
|
||||
.rd_data(read_data),
|
||||
.rd_ena(read_strobe),
|
||||
.rd_empty(empty),
|
||||
.clk(clk),
|
||||
.rst(reset)
|
||||
);
|
||||
|
||||
reg write_strobe_only;
|
||||
reg read_strobe_only;
|
||||
reg not_empty;
|
||||
reg not_full;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
write_strobe_only <= (write_strobe && !read_strobe);
|
||||
read_strobe_only <= (read_strobe && !write_strobe);
|
||||
|
||||
not_empty <= !empty;
|
||||
not_full <= !full;
|
||||
end
|
||||
|
||||
reg increment_level;
|
||||
reg decrement_level;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
increment_level <= (write_strobe_only && not_full);
|
||||
decrement_level <= (read_strobe_only && not_empty);
|
||||
|
||||
if (reset)
|
||||
begin
|
||||
increment_level <= 0;
|
||||
decrement_level <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
reg [$clog2(DEPTH):0] level;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (increment_level)
|
||||
level <= level + 1;
|
||||
else if (decrement_level)
|
||||
level <= level - 1;
|
||||
|
||||
if (reset)
|
||||
level <= 0;
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
almost_empty <= (level <= ALMOST_EMPTY_THRESHOLD);
|
||||
almost_full <= (level >= ALMOST_FULL_THRESHOLD);
|
||||
end
|
||||
endmodule
|
||||
85
interface2/fpga/rtl/coax_buffered_rx.v
Normal file
85
interface2/fpga/rtl/coax_buffered_rx.v
Normal file
@@ -0,0 +1,85 @@
|
||||
// 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_buffered_rx (
|
||||
input clk,
|
||||
input reset,
|
||||
input rx,
|
||||
output active,
|
||||
output error,
|
||||
output [9:0] data,
|
||||
input read_strobe,
|
||||
output empty,
|
||||
output full,
|
||||
input parity
|
||||
);
|
||||
parameter CLOCKS_PER_BIT = 8;
|
||||
parameter DEPTH = 256;
|
||||
|
||||
localparam ERROR_OVERFLOW = 10'b0000001000;
|
||||
|
||||
wire coax_rx_error;
|
||||
wire [9:0] coax_rx_data;
|
||||
wire coax_rx_strobe;
|
||||
|
||||
coax_rx #(
|
||||
.CLOCKS_PER_BIT(CLOCKS_PER_BIT)
|
||||
) coax_rx (
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
.rx(rx),
|
||||
.active(active),
|
||||
.error(coax_rx_error),
|
||||
.data(coax_rx_data),
|
||||
.strobe(coax_rx_strobe),
|
||||
.parity(parity)
|
||||
);
|
||||
|
||||
wire [9:0] coax_buffer_data;
|
||||
|
||||
coax_buffer #(
|
||||
.DEPTH(DEPTH)
|
||||
) coax_buffer (
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
.write_data(coax_rx_data),
|
||||
.write_strobe(coax_rx_strobe),
|
||||
.read_data(coax_buffer_data),
|
||||
.read_strobe(read_strobe && !error),
|
||||
.empty(empty),
|
||||
.full(full)
|
||||
);
|
||||
|
||||
wire overflow;
|
||||
|
||||
assign overflow = ((active && !previous_active && !empty) || (coax_rx_strobe && full));
|
||||
|
||||
reg overflowed = 0;
|
||||
reg previous_active;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (reset)
|
||||
overflowed <= 0;
|
||||
else if (overflow)
|
||||
overflowed <= 1;
|
||||
|
||||
previous_active <= active;
|
||||
end
|
||||
|
||||
assign error = overflow || overflowed || coax_rx_error;
|
||||
assign data = (overflow || overflowed) ? ERROR_OVERFLOW : (coax_rx_error ? coax_rx_data : (empty ? 10'b0 : coax_buffer_data));
|
||||
endmodule
|
||||
151
interface2/fpga/rtl/coax_buffered_tx.v
Normal file
151
interface2/fpga/rtl/coax_buffered_tx.v
Normal file
@@ -0,0 +1,151 @@
|
||||
// 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_buffered_tx (
|
||||
input clk,
|
||||
input reset,
|
||||
output active,
|
||||
output tx,
|
||||
input [9:0] data,
|
||||
input load_strobe,
|
||||
input start_strobe,
|
||||
output empty,
|
||||
output full,
|
||||
output reg ready,
|
||||
input parity
|
||||
);
|
||||
parameter CLOCKS_PER_BIT = 8;
|
||||
parameter DEPTH = 256;
|
||||
parameter START_DEPTH = DEPTH * 0.75;
|
||||
|
||||
localparam STATE_IDLE = 0;
|
||||
localparam STATE_TRANSMITTING_1 = 1;
|
||||
localparam STATE_TRANSMITTING_2 = 2;
|
||||
localparam STATE_TRANSMITTING_3 = 3;
|
||||
|
||||
reg [1:0] state = STATE_IDLE;
|
||||
reg [1:0] next_state;
|
||||
|
||||
reg next_ready;
|
||||
|
||||
wire [9:0] coax_tx_data;
|
||||
reg coax_tx_strobe = 0;
|
||||
reg next_coax_tx_strobe;
|
||||
wire coax_tx_ready;
|
||||
|
||||
coax_tx #(
|
||||
.CLOCKS_PER_BIT(CLOCKS_PER_BIT)
|
||||
) coax_tx (
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
.active(active),
|
||||
.tx(tx),
|
||||
.data(coax_tx_data),
|
||||
.strobe(coax_tx_strobe),
|
||||
.ready(coax_tx_ready),
|
||||
.parity(parity)
|
||||
);
|
||||
|
||||
reg coax_buffer_read_strobe = 0;
|
||||
reg next_coax_buffer_read_strobe;
|
||||
wire coax_buffer_almost_full;
|
||||
|
||||
coax_buffer #(
|
||||
.DEPTH(DEPTH),
|
||||
.ALMOST_FULL_THRESHOLD(START_DEPTH)
|
||||
) coax_buffer (
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
.write_data(data),
|
||||
.write_strobe(load_strobe),
|
||||
.read_data(coax_tx_data),
|
||||
.read_strobe(coax_buffer_read_strobe),
|
||||
.empty(empty),
|
||||
.almost_full(coax_buffer_almost_full),
|
||||
.full(full)
|
||||
);
|
||||
|
||||
always @(*)
|
||||
begin
|
||||
next_state = state;
|
||||
|
||||
next_coax_tx_strobe = 0;
|
||||
next_coax_buffer_read_strobe = 0;
|
||||
|
||||
next_ready = 1;
|
||||
|
||||
case (state)
|
||||
STATE_IDLE:
|
||||
begin
|
||||
// NOTE: Redundant check of almost full AND not empty is in
|
||||
// order to protect against bugs with the almost full logic.
|
||||
if ((start_strobe || coax_buffer_almost_full) && !empty)
|
||||
next_state = STATE_TRANSMITTING_1;
|
||||
end
|
||||
|
||||
STATE_TRANSMITTING_1:
|
||||
begin
|
||||
if (coax_tx_ready)
|
||||
begin
|
||||
if (!empty)
|
||||
begin
|
||||
next_coax_tx_strobe = 1;
|
||||
next_state = STATE_TRANSMITTING_2;
|
||||
end
|
||||
else
|
||||
begin
|
||||
next_ready = 0;
|
||||
next_state = STATE_TRANSMITTING_3;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
STATE_TRANSMITTING_2:
|
||||
begin
|
||||
next_coax_buffer_read_strobe = 1;
|
||||
next_state = STATE_TRANSMITTING_1;
|
||||
end
|
||||
|
||||
STATE_TRANSMITTING_3:
|
||||
begin
|
||||
next_ready = 0;
|
||||
|
||||
if (!active)
|
||||
next_state = STATE_IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
state <= next_state;
|
||||
|
||||
coax_tx_strobe <= next_coax_tx_strobe;
|
||||
coax_buffer_read_strobe <= next_coax_buffer_read_strobe;
|
||||
|
||||
ready <= next_ready;
|
||||
|
||||
if (reset)
|
||||
begin
|
||||
state <= STATE_IDLE;
|
||||
|
||||
coax_tx_strobe <= 0;
|
||||
coax_buffer_read_strobe <= 0;
|
||||
|
||||
ready <= 1;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
415
interface2/fpga/rtl/coax_rx.v
Normal file
415
interface2/fpga/rtl/coax_rx.v
Normal file
@@ -0,0 +1,415 @@
|
||||
// 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 (
|
||||
input clk,
|
||||
input reset,
|
||||
input rx,
|
||||
output reg active,
|
||||
output reg error,
|
||||
output reg [9:0] data,
|
||||
output reg strobe = 0,
|
||||
input parity
|
||||
);
|
||||
parameter CLOCKS_PER_BIT = 8;
|
||||
|
||||
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;
|
||||
|
||||
reg [3:0] state = STATE_IDLE;
|
||||
reg [3:0] next_state;
|
||||
reg [7:0] state_counter;
|
||||
reg [7:0] next_state_counter;
|
||||
|
||||
reg previous_rx;
|
||||
|
||||
reg bit_timer_reset = 0;
|
||||
reg next_bit_timer_reset;
|
||||
|
||||
reg [9:0] next_data;
|
||||
reg next_strobe;
|
||||
|
||||
reg [9:0] input_data;
|
||||
reg [9:0] next_input_data;
|
||||
reg input_data_parity;
|
||||
|
||||
reg [3:0] bit_counter = 0;
|
||||
reg [3:0] next_bit_counter;
|
||||
|
||||
reg next_active;
|
||||
reg next_error;
|
||||
|
||||
wire sample;
|
||||
wire synchronized;
|
||||
|
||||
coax_rx_bit_timer #(
|
||||
.CLOCKS_PER_BIT(CLOCKS_PER_BIT)
|
||||
) bit_timer (
|
||||
.clk(clk),
|
||||
.rx(rx),
|
||||
.reset(bit_timer_reset),
|
||||
.sample(sample),
|
||||
.synchronized(synchronized)
|
||||
);
|
||||
|
||||
always @(*)
|
||||
begin
|
||||
next_state = state;
|
||||
next_state_counter = state_counter + 1;
|
||||
|
||||
next_bit_timer_reset = 0;
|
||||
|
||||
next_data = data;
|
||||
next_strobe = 0;
|
||||
|
||||
next_input_data = input_data;
|
||||
next_bit_counter = bit_counter;
|
||||
|
||||
next_active = 0;
|
||||
next_error = 0;
|
||||
|
||||
case (state)
|
||||
STATE_IDLE:
|
||||
begin
|
||||
next_bit_timer_reset = 1;
|
||||
|
||||
if (!rx && previous_rx)
|
||||
begin
|
||||
next_state = STATE_START_SEQUENCE_1;
|
||||
next_state_counter = 0;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_START_SEQUENCE_1:
|
||||
begin
|
||||
if (sample)
|
||||
begin
|
||||
if (synchronized && rx)
|
||||
next_state = STATE_START_SEQUENCE_2;
|
||||
else
|
||||
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_START_SEQUENCE_2:
|
||||
begin
|
||||
if (sample)
|
||||
begin
|
||||
if (synchronized && rx)
|
||||
next_state = STATE_START_SEQUENCE_3;
|
||||
else
|
||||
next_state = STATE_IDLE;
|
||||
|
||||
next_state_counter = 0;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_START_SEQUENCE_3:
|
||||
begin
|
||||
if (sample)
|
||||
begin
|
||||
if (synchronized && rx)
|
||||
next_state = STATE_START_SEQUENCE_4;
|
||||
else
|
||||
next_state = STATE_IDLE;
|
||||
|
||||
next_state_counter = 0;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_START_SEQUENCE_4:
|
||||
begin
|
||||
if (sample)
|
||||
begin
|
||||
if (synchronized && rx)
|
||||
next_state = STATE_START_SEQUENCE_5;
|
||||
else
|
||||
next_state = STATE_IDLE;
|
||||
|
||||
next_state_counter = 0;
|
||||
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:
|
||||
begin
|
||||
if (rx)
|
||||
begin
|
||||
next_state = STATE_START_SEQUENCE_8;
|
||||
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_START_SEQUENCE_8:
|
||||
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
|
||||
end
|
||||
|
||||
STATE_START_SEQUENCE_9:
|
||||
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
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
state <= next_state;
|
||||
state_counter <= next_state_counter;
|
||||
|
||||
bit_timer_reset <= next_bit_timer_reset;
|
||||
|
||||
data <= next_data;
|
||||
strobe <= next_strobe;
|
||||
|
||||
input_data <= next_input_data;
|
||||
|
||||
// Parity includes the sync bit.
|
||||
input_data_parity <= (parity == 1 ? ^{ 1'b1, input_data } : ~^{ 1'b1, input_data });
|
||||
|
||||
bit_counter <= next_bit_counter;
|
||||
|
||||
active <= next_active;
|
||||
error <= next_error;
|
||||
|
||||
if (reset)
|
||||
begin
|
||||
bit_timer_reset <= 1;
|
||||
|
||||
state <= STATE_IDLE;
|
||||
|
||||
strobe <= 0;
|
||||
|
||||
active <= 0;
|
||||
error <= 0;
|
||||
end
|
||||
|
||||
previous_rx <= rx;
|
||||
end
|
||||
endmodule
|
||||
111
interface2/fpga/rtl/coax_rx_bit_timer.v
Normal file
111
interface2/fpga/rtl/coax_rx_bit_timer.v
Normal file
@@ -0,0 +1,111 @@
|
||||
// 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
|
||||
71
interface2/fpga/rtl/coax_syn.prj
Normal file
71
interface2/fpga/rtl/coax_syn.prj
Normal file
@@ -0,0 +1,71 @@
|
||||
#-- Synopsys, Inc.
|
||||
#-- Project file /home/andrew/lattice_coax/coax/coax_syn.prj
|
||||
#project files
|
||||
|
||||
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_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 "control.v"
|
||||
add_file -verilog -lib work "spi_device.v"
|
||||
add_file -verilog -lib work "coax_buffered_tx.v"
|
||||
add_file -verilog -lib work "coax_buffer.v"
|
||||
add_file -verilog -lib work "third_party/fifo_sync_ram.v"
|
||||
add_file -verilog -lib work "third_party/ram_sdp.v"
|
||||
add_file -verilog -lib work "strobe_cdc.v"
|
||||
add_file -verilog -lib work "top.v"
|
||||
add_file -verilog -lib work "dual_clock_spi_device.v"
|
||||
add_file -constraint -lib work "clocks.sdc"
|
||||
#implementation: "coax_Implmnt"
|
||||
impl -add coax_Implmnt -type fpga
|
||||
|
||||
#implementation attributes
|
||||
set_option -vlog_std v2001
|
||||
set_option -project_relative_includes 1
|
||||
|
||||
#device options
|
||||
set_option -technology SBTiCE40UP
|
||||
set_option -part iCE40UP5K
|
||||
set_option -package SG48
|
||||
set_option -speed_grade
|
||||
set_option -part_companion ""
|
||||
|
||||
#compilation/mapping options
|
||||
|
||||
# mapper_options
|
||||
set_option -frequency auto
|
||||
set_option -write_verilog 0
|
||||
set_option -write_vhdl 0
|
||||
|
||||
# Silicon Blue iCE40UP
|
||||
set_option -maxfan 10000
|
||||
set_option -disable_io_insertion 0
|
||||
set_option -pipe 1
|
||||
set_option -retiming 0
|
||||
set_option -update_models_cp 0
|
||||
set_option -fixgatedclocks 2
|
||||
set_option -fixgeneratedclocks 0
|
||||
|
||||
# NFilter
|
||||
set_option -popfeed 0
|
||||
set_option -constprop 0
|
||||
set_option -createhierarchy 0
|
||||
|
||||
# sequential_optimization_options
|
||||
set_option -symbolic_fsm_compiler 1
|
||||
|
||||
# Compiler Options
|
||||
set_option -compiler_compatible 0
|
||||
set_option -resource_sharing 1
|
||||
|
||||
#automatic place and route (vendor) options
|
||||
set_option -write_apr_constraint 1
|
||||
|
||||
#set result format/file last
|
||||
project -result_format "edif"
|
||||
project -result_file ./coax_Implmnt/coax.edf
|
||||
project -log_file "./coax_Implmnt/coax.srr"
|
||||
impl -active coax_Implmnt
|
||||
project -run synthesis -clean
|
||||
308
interface2/fpga/rtl/coax_tx.v
Normal file
308
interface2/fpga/rtl/coax_tx.v
Normal file
@@ -0,0 +1,308 @@
|
||||
// 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_tx (
|
||||
input clk,
|
||||
input reset,
|
||||
output reg active,
|
||||
output reg tx,
|
||||
input [9:0] data,
|
||||
input strobe,
|
||||
output ready,
|
||||
input parity
|
||||
);
|
||||
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 START_SEQUENCE_9 = 9;
|
||||
localparam SYNC_BIT = 10;
|
||||
localparam DATA_BIT = 11;
|
||||
localparam PARITY_BIT = 12;
|
||||
localparam END_SEQUENCE_1 = 13;
|
||||
localparam END_SEQUENCE_2 = 14;
|
||||
localparam END_SEQUENCE_3 = 15;
|
||||
|
||||
reg [3:0] state = IDLE;
|
||||
reg [3:0] next_state;
|
||||
|
||||
reg next_tx;
|
||||
|
||||
reg end_sequence;
|
||||
reg next_end_sequence;
|
||||
|
||||
reg [9:0] output_data;
|
||||
reg [9:0] next_output_data;
|
||||
reg output_data_full = 0;
|
||||
reg next_output_data_full;
|
||||
reg parity_bit;
|
||||
reg next_parity_bit;
|
||||
reg output_parity_bit;
|
||||
reg next_output_parity_bit;
|
||||
|
||||
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_end_sequence = 0;
|
||||
|
||||
next_output_data = output_data;
|
||||
next_output_data_full = output_data_full;
|
||||
next_parity_bit = parity_bit;
|
||||
next_output_parity_bit = output_parity_bit;
|
||||
|
||||
if (strobe && ready)
|
||||
begin
|
||||
next_output_data = data;
|
||||
next_output_data_full = 1;
|
||||
|
||||
// Parity includes the sync bit.
|
||||
next_parity_bit = (parity == 1 ? ^{ 1'b1, data } : ~^{ 1'b1, data });
|
||||
end
|
||||
|
||||
next_bit_counter = bit_counter;
|
||||
|
||||
next_bit_timer_reset = 0;
|
||||
|
||||
case (state)
|
||||
IDLE:
|
||||
begin
|
||||
next_bit_timer_reset = 1;
|
||||
|
||||
if (output_data_full)
|
||||
begin
|
||||
next_state = START_SEQUENCE_1;
|
||||
end
|
||||
end
|
||||
|
||||
START_SEQUENCE_1:
|
||||
begin
|
||||
next_tx = 1;
|
||||
|
||||
// TODO... off by 1
|
||||
if (second_half)
|
||||
begin
|
||||
next_bit_timer_reset = 1;
|
||||
next_state = START_SEQUENCE_2;
|
||||
end
|
||||
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 = first_half ? 0 : 1;
|
||||
|
||||
if (last_clock)
|
||||
next_state = START_SEQUENCE_7;
|
||||
end
|
||||
|
||||
START_SEQUENCE_7:
|
||||
begin
|
||||
next_tx = 0;
|
||||
|
||||
if (last_clock)
|
||||
next_state = START_SEQUENCE_8;
|
||||
end
|
||||
|
||||
START_SEQUENCE_8:
|
||||
begin
|
||||
next_tx = first_half ? 0 : 1;
|
||||
|
||||
if (last_clock)
|
||||
next_state = START_SEQUENCE_9;
|
||||
end
|
||||
|
||||
START_SEQUENCE_9:
|
||||
begin
|
||||
next_tx = 1;
|
||||
|
||||
if (last_clock)
|
||||
next_state = SYNC_BIT;
|
||||
end
|
||||
|
||||
SYNC_BIT:
|
||||
begin
|
||||
next_tx = first_half ? 0 : 1;
|
||||
|
||||
next_bit_counter = 9;
|
||||
|
||||
if (last_clock)
|
||||
next_state = DATA_BIT;
|
||||
end
|
||||
|
||||
DATA_BIT:
|
||||
begin
|
||||
next_tx = first_half ? ~output_data[9] : output_data[9];
|
||||
|
||||
if (last_clock)
|
||||
begin
|
||||
next_output_data = { output_data[8:0], output_data[9] };
|
||||
next_bit_counter = bit_counter - 1;
|
||||
|
||||
if (bit_counter == 0)
|
||||
begin
|
||||
next_output_data_full = 0;
|
||||
next_output_parity_bit = parity_bit;
|
||||
|
||||
next_state = PARITY_BIT;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
PARITY_BIT:
|
||||
begin
|
||||
next_tx = first_half ? ~output_parity_bit : output_parity_bit;
|
||||
|
||||
if (last_clock)
|
||||
begin
|
||||
if (output_data_full)
|
||||
begin
|
||||
next_state = SYNC_BIT;
|
||||
end
|
||||
else
|
||||
begin
|
||||
next_end_sequence = 1;
|
||||
next_state = END_SEQUENCE_1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
END_SEQUENCE_1:
|
||||
begin
|
||||
next_tx = first_half ? 1 : 0;
|
||||
next_end_sequence = 1;
|
||||
|
||||
if (last_clock)
|
||||
next_state = END_SEQUENCE_2;
|
||||
end
|
||||
|
||||
END_SEQUENCE_2:
|
||||
begin
|
||||
next_tx = 1;
|
||||
next_end_sequence = 1;
|
||||
|
||||
if (last_clock)
|
||||
next_state = END_SEQUENCE_3;
|
||||
end
|
||||
|
||||
END_SEQUENCE_3:
|
||||
begin
|
||||
next_tx = 1;
|
||||
next_end_sequence = 1;
|
||||
|
||||
if (last_clock)
|
||||
begin
|
||||
next_tx = 0;
|
||||
next_end_sequence = 0;
|
||||
next_state = IDLE;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
state <= next_state;
|
||||
|
||||
active <= (state != IDLE); // TODO: this causes active to remain high one additional clock cycle
|
||||
tx <= next_tx;
|
||||
|
||||
end_sequence <= next_end_sequence;
|
||||
|
||||
output_data <= next_output_data;
|
||||
output_data_full <= next_output_data_full;
|
||||
parity_bit <= next_parity_bit;
|
||||
output_parity_bit <= next_output_parity_bit;
|
||||
|
||||
bit_counter <= next_bit_counter;
|
||||
|
||||
bit_timer_reset <= next_bit_timer_reset;
|
||||
|
||||
if (reset)
|
||||
begin
|
||||
state <= IDLE;
|
||||
|
||||
active <= 0;
|
||||
tx <= 0;
|
||||
|
||||
end_sequence <= 0;
|
||||
|
||||
output_data_full <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
assign ready = (!output_data_full && !end_sequence);
|
||||
endmodule
|
||||
46
interface2/fpga/rtl/coax_tx_bit_timer.v
Normal file
46
interface2/fpga/rtl/coax_tx_bit_timer.v
Normal file
@@ -0,0 +1,46 @@
|
||||
// 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_tx_bit_timer (
|
||||
input clk,
|
||||
input reset,
|
||||
output first_half,
|
||||
output second_half,
|
||||
output last_clock
|
||||
);
|
||||
parameter CLOCKS_PER_BIT = 8;
|
||||
|
||||
reg [$clog2(CLOCKS_PER_BIT):0] counter = 0;
|
||||
reg [$clog2(CLOCKS_PER_BIT):0] next_counter;
|
||||
|
||||
always @(*)
|
||||
begin
|
||||
next_counter = last_clock ? 0 : counter + 1;
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
counter <= next_counter;
|
||||
|
||||
if (reset)
|
||||
counter <= 0;
|
||||
end
|
||||
|
||||
assign first_half = (counter < CLOCKS_PER_BIT / 2);
|
||||
assign second_half = ~first_half;
|
||||
|
||||
assign last_clock = (counter == CLOCKS_PER_BIT - 1);
|
||||
endmodule
|
||||
53
interface2/fpga/rtl/coax_tx_distorter.v
Normal file
53
interface2/fpga/rtl/coax_tx_distorter.v
Normal file
@@ -0,0 +1,53 @@
|
||||
// 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_tx_distorter (
|
||||
input clk,
|
||||
input active_input,
|
||||
input tx_input,
|
||||
output reg active_output,
|
||||
output reg tx_output,
|
||||
output reg tx_delay,
|
||||
output reg tx_n
|
||||
);
|
||||
parameter CLOCKS_PER_BIT = 8;
|
||||
|
||||
localparam DELAY_CLOCKS = CLOCKS_PER_BIT / 4;
|
||||
|
||||
reg [DELAY_CLOCKS-1:0] tx_d = { (DELAY_CLOCKS){1'b1} };
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (active_input)
|
||||
begin
|
||||
tx_d <= { tx_d[DELAY_CLOCKS-2:0], tx_input };
|
||||
|
||||
active_output <= 1;
|
||||
tx_output <= tx_input;
|
||||
tx_delay <= tx_d[DELAY_CLOCKS-1];
|
||||
tx_n <= ~tx_input;
|
||||
end
|
||||
else
|
||||
begin
|
||||
tx_d <= { (DELAY_CLOCKS){1'b1} };
|
||||
|
||||
active_output <= 0;
|
||||
tx_output <= 0;
|
||||
tx_delay <= 0;
|
||||
tx_n <= 0;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
347
interface2/fpga/rtl/control.v
Normal file
347
interface2/fpga/rtl/control.v
Normal file
@@ -0,0 +1,347 @@
|
||||
// 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 control (
|
||||
input clk,
|
||||
input reset,
|
||||
|
||||
// SPI
|
||||
input spi_cs_n,
|
||||
input [7:0] spi_rx_data,
|
||||
input spi_rx_strobe,
|
||||
output reg [7:0] spi_tx_data,
|
||||
output reg spi_tx_strobe,
|
||||
|
||||
output loopback,
|
||||
|
||||
// TX
|
||||
output reg tx_reset,
|
||||
input tx_active,
|
||||
output reg [9:0] tx_data,
|
||||
output reg tx_load_strobe,
|
||||
output reg tx_start_strobe,
|
||||
input tx_empty,
|
||||
input tx_full,
|
||||
input tx_ready,
|
||||
output tx_parity,
|
||||
|
||||
// RX
|
||||
output reg rx_reset,
|
||||
input rx_active,
|
||||
input rx_error,
|
||||
input [9:0] rx_data,
|
||||
output reg rx_read_strobe,
|
||||
input rx_empty,
|
||||
output rx_parity
|
||||
);
|
||||
parameter DEFAULT_CONTROL_REGISTER = 8'b01001000;
|
||||
|
||||
localparam STATE_IDLE = 0;
|
||||
localparam STATE_READ_REGISTER_1 = 1;
|
||||
localparam STATE_READ_REGISTER_2 = 2;
|
||||
localparam STATE_WRITE_REGISTER_1 = 3;
|
||||
localparam STATE_WRITE_REGISTER_2 = 4;
|
||||
localparam STATE_TX_1 = 5;
|
||||
localparam STATE_TX_2 = 6;
|
||||
localparam STATE_TX_3 = 7;
|
||||
localparam STATE_RX_1 = 8;
|
||||
localparam STATE_RX_2 = 9;
|
||||
localparam STATE_RX_3 = 10;
|
||||
localparam STATE_RX_4 = 11;
|
||||
localparam STATE_RESET = 12;
|
||||
|
||||
reg [7:0] state = STATE_IDLE;
|
||||
reg [7:0] next_state;
|
||||
|
||||
reg [7:0] control_register = DEFAULT_CONTROL_REGISTER;
|
||||
reg [7:0] next_control_register;
|
||||
reg [7:0] register_mask;
|
||||
reg [7:0] next_register_mask;
|
||||
|
||||
reg [7:0] command;
|
||||
reg [7:0] next_command;
|
||||
|
||||
reg [7:0] next_spi_tx_data;
|
||||
reg next_spi_tx_strobe;
|
||||
|
||||
reg next_tx_reset;
|
||||
reg previous_tx_active;
|
||||
reg [9:0] next_tx_data;
|
||||
reg tx_data_valid = 0;
|
||||
reg next_tx_data_valid;
|
||||
reg next_tx_load_strobe;
|
||||
reg next_tx_start_strobe;
|
||||
reg tx_complete = 0;
|
||||
reg next_tx_complete;
|
||||
|
||||
reg next_rx_reset;
|
||||
reg next_rx_read_strobe;
|
||||
reg [15:0] rx_buffer;
|
||||
reg [15:0] next_rx_buffer;
|
||||
|
||||
reg [1:0] spi_cs_n_d;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
spi_cs_n_d <= { spi_cs_n_d[0], spi_cs_n };
|
||||
end
|
||||
|
||||
always @(*)
|
||||
begin
|
||||
next_state = state;
|
||||
|
||||
next_control_register = control_register;
|
||||
next_register_mask = register_mask;
|
||||
|
||||
next_command = command;
|
||||
|
||||
next_spi_tx_data = spi_tx_data;
|
||||
next_spi_tx_strobe = 0;
|
||||
|
||||
next_tx_reset = 0;
|
||||
next_tx_data = tx_data;
|
||||
next_tx_data_valid = tx_data_valid;
|
||||
next_tx_load_strobe = 0;
|
||||
next_tx_start_strobe = 0;
|
||||
next_tx_complete = tx_complete;
|
||||
|
||||
next_rx_reset = 0;
|
||||
next_rx_read_strobe = 0;
|
||||
next_rx_buffer = rx_buffer;
|
||||
|
||||
case (state)
|
||||
STATE_IDLE:
|
||||
begin
|
||||
if (spi_rx_strobe)
|
||||
begin
|
||||
next_command = spi_rx_data;
|
||||
|
||||
case (spi_rx_data[3:0])
|
||||
4'h2: next_state = STATE_READ_REGISTER_1;
|
||||
4'h3: next_state = STATE_WRITE_REGISTER_1;
|
||||
4'h4: next_state = STATE_TX_1;
|
||||
4'h5: next_state = STATE_RX_1;
|
||||
4'hf: next_state = STATE_RESET;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
STATE_READ_REGISTER_1:
|
||||
begin
|
||||
next_spi_tx_data = 0;
|
||||
|
||||
case (command[7:4])
|
||||
4'h1: next_spi_tx_data = { 1'b0, rx_error, rx_active, 1'b0, tx_complete, tx_active, 2'b0 };
|
||||
4'h2: next_spi_tx_data = control_register;
|
||||
4'hf: next_spi_tx_data = 8'ha5;
|
||||
endcase
|
||||
|
||||
next_spi_tx_strobe = 1;
|
||||
|
||||
next_state = STATE_READ_REGISTER_2;
|
||||
end
|
||||
|
||||
STATE_READ_REGISTER_2:
|
||||
begin
|
||||
if (spi_rx_strobe)
|
||||
next_state = STATE_READ_REGISTER_1;
|
||||
end
|
||||
|
||||
STATE_WRITE_REGISTER_1:
|
||||
begin
|
||||
if (spi_rx_strobe)
|
||||
begin
|
||||
next_register_mask = spi_rx_data;
|
||||
|
||||
next_state = STATE_WRITE_REGISTER_2;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_WRITE_REGISTER_2:
|
||||
begin
|
||||
if (spi_rx_strobe)
|
||||
begin
|
||||
case (command[7:4])
|
||||
4'h2: next_control_register = (control_register & ~register_mask) | (spi_rx_data & register_mask);
|
||||
endcase
|
||||
|
||||
next_state = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_TX_1:
|
||||
begin
|
||||
next_tx_complete = 0;
|
||||
next_state = STATE_TX_2;
|
||||
end
|
||||
|
||||
STATE_TX_2:
|
||||
begin
|
||||
if (spi_rx_strobe)
|
||||
begin
|
||||
next_tx_data_valid = 0;
|
||||
|
||||
if (tx_full)
|
||||
begin
|
||||
next_spi_tx_data = 8'b10000001; // Overflow
|
||||
next_spi_tx_strobe = 1;
|
||||
end
|
||||
else if (!tx_ready)
|
||||
begin
|
||||
next_spi_tx_data = 8'b10000010; // Underflow
|
||||
next_spi_tx_strobe = 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
next_tx_data = { spi_rx_data[1:0], 8'b00000000 };
|
||||
next_tx_data_valid = 1;
|
||||
|
||||
next_spi_tx_data = 8'h00;
|
||||
next_spi_tx_strobe = 1;
|
||||
end
|
||||
|
||||
next_state = STATE_TX_3;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_TX_3:
|
||||
begin
|
||||
if (spi_rx_strobe)
|
||||
begin
|
||||
next_tx_data = { tx_data[9:8], spi_rx_data };
|
||||
next_tx_load_strobe = tx_data_valid;
|
||||
|
||||
next_state = STATE_TX_2;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_RX_1:
|
||||
begin
|
||||
next_rx_buffer = { rx_error, rx_empty, 4'b0000, rx_data };
|
||||
|
||||
next_state = STATE_RX_2;
|
||||
end
|
||||
|
||||
STATE_RX_2:
|
||||
begin
|
||||
next_spi_tx_data = rx_buffer[15:8];
|
||||
next_spi_tx_strobe = 1;
|
||||
|
||||
next_state = STATE_RX_3;
|
||||
end
|
||||
|
||||
STATE_RX_3:
|
||||
begin
|
||||
if (spi_rx_strobe)
|
||||
begin
|
||||
next_spi_tx_data = rx_buffer[7:0];
|
||||
next_spi_tx_strobe = 1;
|
||||
|
||||
// Reset on error and only dequeue if not empty.
|
||||
if (rx_buffer[15])
|
||||
next_rx_reset = 1; // TODO: should this be more explicit?
|
||||
else if (!rx_buffer[14])
|
||||
next_rx_read_strobe = 1;
|
||||
|
||||
next_state = STATE_RX_4;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_RX_4:
|
||||
begin
|
||||
if (spi_rx_strobe)
|
||||
next_state = STATE_RX_1;
|
||||
end
|
||||
|
||||
STATE_RESET:
|
||||
begin
|
||||
// TODO: should this also reset the control register flags
|
||||
// like loopback?
|
||||
|
||||
next_tx_reset = 1;
|
||||
next_tx_complete = 0;
|
||||
|
||||
next_rx_reset = 1;
|
||||
|
||||
next_state = STATE_IDLE;
|
||||
end
|
||||
endcase
|
||||
|
||||
if (spi_cs_n_d[1])
|
||||
begin
|
||||
if (!tx_empty && !tx_active)
|
||||
next_tx_start_strobe = 1; // TODO: this can last for multiple clock cycles, but that is okay...
|
||||
|
||||
next_state = STATE_IDLE;
|
||||
end
|
||||
|
||||
if (!tx_active && previous_tx_active)
|
||||
next_tx_complete = 1;
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
state <= next_state;
|
||||
|
||||
control_register <= next_control_register;
|
||||
register_mask <= next_register_mask;
|
||||
|
||||
command <= next_command;
|
||||
|
||||
spi_tx_data <= next_spi_tx_data;
|
||||
spi_tx_strobe <= next_spi_tx_strobe;
|
||||
|
||||
tx_reset <= next_tx_reset;
|
||||
tx_data <= next_tx_data;
|
||||
tx_data_valid <= next_tx_data_valid;
|
||||
tx_load_strobe <= next_tx_load_strobe;
|
||||
tx_start_strobe <= next_tx_start_strobe;
|
||||
tx_complete <= next_tx_complete;
|
||||
|
||||
rx_reset <= next_rx_reset;
|
||||
rx_read_strobe <= next_rx_read_strobe;
|
||||
rx_buffer <= next_rx_buffer;
|
||||
|
||||
if (reset)
|
||||
begin
|
||||
state <= STATE_IDLE;
|
||||
|
||||
control_register <= DEFAULT_CONTROL_REGISTER;
|
||||
|
||||
command <= 0;
|
||||
|
||||
spi_tx_data <= 0;
|
||||
spi_tx_strobe <= 0;
|
||||
|
||||
tx_reset <= 0;
|
||||
tx_data <= 0;
|
||||
tx_load_strobe <= 0;
|
||||
tx_start_strobe <= 0;
|
||||
tx_complete <= 0;
|
||||
|
||||
rx_reset <= 0;
|
||||
rx_read_strobe <= 0;
|
||||
rx_buffer <= 0;
|
||||
end
|
||||
|
||||
previous_tx_active <= tx_active;
|
||||
end
|
||||
|
||||
assign loopback = control_register[0];
|
||||
|
||||
assign tx_parity = control_register[3];
|
||||
assign rx_parity = control_register[6];
|
||||
endmodule
|
||||
75
interface2/fpga/rtl/dual_clock_spi_device.v
Normal file
75
interface2/fpga/rtl/dual_clock_spi_device.v
Normal file
@@ -0,0 +1,75 @@
|
||||
// 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 dual_clock_spi_device (
|
||||
input clk_slow,
|
||||
input clk_fast,
|
||||
input spi_sck,
|
||||
input spi_cs_n,
|
||||
input spi_sdi,
|
||||
output spi_sdo,
|
||||
output reg [7:0] rx_data,
|
||||
output reg rx_strobe,
|
||||
input [7:0] tx_data,
|
||||
input tx_strobe
|
||||
);
|
||||
wire [7:0] rx_data_fast;
|
||||
wire rx_strobe_fast;
|
||||
reg [7:0] tx_data_fast;
|
||||
wire tx_strobe_fast;
|
||||
|
||||
spi_device spi (
|
||||
.clk(clk_fast),
|
||||
.spi_sck(spi_sck),
|
||||
.spi_cs_n(spi_cs_n),
|
||||
.spi_sdi(spi_sdi),
|
||||
.spi_sdo(spi_sdo),
|
||||
.rx_data(rx_data_fast),
|
||||
.rx_strobe(rx_strobe_fast),
|
||||
.tx_data(tx_data_fast),
|
||||
.tx_strobe(tx_strobe_fast)
|
||||
);
|
||||
|
||||
wire rx_strobe_slow;
|
||||
|
||||
strobe_cdc rx_strobe_cdc (
|
||||
.clk_in(clk_fast),
|
||||
.strobe_in(rx_strobe_fast),
|
||||
.clk_out(clk_slow),
|
||||
.strobe_out(rx_strobe_slow)
|
||||
);
|
||||
|
||||
strobe_cdc tx_strobe_cdc (
|
||||
.clk_in(clk_slow),
|
||||
.strobe_in(tx_strobe),
|
||||
.clk_out(clk_fast),
|
||||
.strobe_out(tx_strobe_fast)
|
||||
);
|
||||
|
||||
always @(posedge clk_slow)
|
||||
begin
|
||||
if (tx_strobe)
|
||||
tx_data_fast <= tx_data;
|
||||
|
||||
rx_strobe <= 0;
|
||||
|
||||
if (rx_strobe_slow)
|
||||
begin
|
||||
rx_data <= rx_data_fast;
|
||||
rx_strobe <= 1;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
20
interface2/fpga/rtl/icecube2.mk
Normal file
20
interface2/fpga/rtl/icecube2.mk
Normal file
@@ -0,0 +1,20 @@
|
||||
# See https://github.com/halfmanhalftaco/fpga-docker/tree/master/Lattice_iCEcube2
|
||||
ICECUBE2_WRAPPER = docker run -it --rm --volume $(RTL):/data --workdir /data --mac-address=$(shell cat .mac_address) icecube2:latest ./icecube2_env.sh
|
||||
|
||||
RTL = $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
|
||||
IMPLMNT = coax_Implmnt
|
||||
|
||||
all: top.bin
|
||||
|
||||
$(IMPLMNT)/coax.edf: coax_syn.prj *.v third_party/*.v clocks.sdc
|
||||
$(ICECUBE2_WRAPPER) synpwrap -prj coax_syn.prj
|
||||
|
||||
top.bin: $(IMPLMNT)/coax.edf pins.pcf
|
||||
rm -f top.bin
|
||||
$(ICECUBE2_WRAPPER) ./icecube2_flow.tcl
|
||||
cp $(IMPLMNT)/sbt/outputs/bitmap/top_bitmap.bin top.bin
|
||||
|
||||
clean:
|
||||
rm -rf $(IMPLMNT) synlog.tcl *.bin *.log *.log.bak
|
||||
|
||||
.PHONY: all clean
|
||||
15
interface2/fpga/rtl/icecube2_env.sh
Executable file
15
interface2/fpga/rtl/icecube2_env.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
export ICECUBE_DIR="/opt/icecube2"
|
||||
export SBT_DIR="$ICECUBE_DIR/sbt_backend"
|
||||
|
||||
export FOUNDRY="$ICECUBE_DIR/LSE"
|
||||
export SYNPLIFY_PATH="$ICECUBE_DIR/synpbase"
|
||||
export LM_LICENSE_FILE="$ICECUBE_DIR/license.dat"
|
||||
|
||||
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH${LD_LIBRARY_PATH:+:}$SBT_DIR/bin/linux/opt:$SBT_DIR/bin/linux/opt/synpwrap:$SBT_DIR/lib/linux/opt:$FOUNDRY/bin/lin64"
|
||||
|
||||
# Give precedence to iCEcube2 tools.
|
||||
export PATH="$SBT_DIR/bin/linux/opt:$SBT_DIR/bin/linux/opt/synpwrap${PATH:+:}$PATH"
|
||||
|
||||
$*
|
||||
6
interface2/fpga/rtl/icecube2_flow.tcl
Executable file
6
interface2/fpga/rtl/icecube2_flow.tcl
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/tclsh8.5
|
||||
|
||||
# Place and route, bitmap generation and timing
|
||||
source [file join $::env(SBT_DIR) "tcl/sbt_backend_synpl.tcl"]
|
||||
|
||||
run_sbt_backend_auto iCE40UP5K-SG48 top [pwd] coax_Implmnt ":edifparser -y pins.pcf" coax
|
||||
25
interface2/fpga/rtl/pins.pcf
Normal file
25
interface2/fpga/rtl/pins.pcf
Normal file
@@ -0,0 +1,25 @@
|
||||
set_io clk 37
|
||||
|
||||
set_io reset_n 20
|
||||
|
||||
# SPI
|
||||
set_io spi_sck 15
|
||||
|
||||
set_io spi_cs_n 16
|
||||
set_io spi_sdi 17
|
||||
set_io spi_sdo 14
|
||||
|
||||
# TX
|
||||
set_io tx_active 35
|
||||
set_io tx_n 36
|
||||
set_io tx_delay 34
|
||||
|
||||
# RX
|
||||
set_io rx 26
|
||||
|
||||
set_io irq 13
|
||||
|
||||
set_io gpio0 46
|
||||
set_io gpio1 47
|
||||
set_io gpio2 48
|
||||
set_io gpio3 6
|
||||
79
interface2/fpga/rtl/spi_device.v
Normal file
79
interface2/fpga/rtl/spi_device.v
Normal file
@@ -0,0 +1,79 @@
|
||||
// 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 spi_device (
|
||||
input clk,
|
||||
input spi_sck,
|
||||
input spi_cs_n,
|
||||
input spi_sdi,
|
||||
output spi_sdo,
|
||||
output reg [7:0] rx_data,
|
||||
output reg rx_strobe,
|
||||
input [7:0] tx_data,
|
||||
input tx_strobe
|
||||
);
|
||||
reg [1:0] cs_n_d;
|
||||
reg [2:0] sck_d;
|
||||
reg [2:0] sdi_d;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
cs_n_d <= { cs_n_d[0], spi_cs_n };
|
||||
|
||||
sck_d <= { sck_d[1:0], spi_sck };
|
||||
sdi_d <= { sdi_d[1:0], spi_sdi };
|
||||
end
|
||||
|
||||
reg [3:0] counter;
|
||||
reg [7:0] input_data;
|
||||
reg [7:0] output_data;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
rx_strobe <= 0;
|
||||
|
||||
if (tx_strobe)
|
||||
output_data <= tx_data;
|
||||
|
||||
if (cs_n_d[1])
|
||||
begin
|
||||
counter <= 0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (!sck_d[2] && sck_d[1])
|
||||
begin
|
||||
input_data <= { input_data[6:0], sdi_d[2] };
|
||||
counter <= counter + 1;
|
||||
end
|
||||
|
||||
if (sck_d[2] && !sck_d[1])
|
||||
begin
|
||||
output_data <= { output_data[6:0], 1'b0 };
|
||||
|
||||
if (counter == 8)
|
||||
begin
|
||||
rx_data <= input_data;
|
||||
rx_strobe <= 1;
|
||||
|
||||
counter <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign spi_sdo = output_data[7];
|
||||
endmodule
|
||||
42
interface2/fpga/rtl/strobe_cdc.v
Normal file
42
interface2/fpga/rtl/strobe_cdc.v
Normal file
@@ -0,0 +1,42 @@
|
||||
// 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 strobe_cdc (
|
||||
input clk_in,
|
||||
input strobe_in,
|
||||
input clk_out,
|
||||
output reg strobe_out
|
||||
);
|
||||
reg toggle_in;
|
||||
|
||||
always @(posedge clk_in)
|
||||
begin
|
||||
if (strobe_in)
|
||||
toggle_in <= ~toggle_in;
|
||||
end
|
||||
|
||||
reg [2:0] toggle_out;
|
||||
|
||||
always @(posedge clk_out)
|
||||
begin
|
||||
toggle_out <= { toggle_out[1:0], toggle_in };
|
||||
|
||||
strobe_out <= 0;
|
||||
|
||||
if (toggle_out[2] != toggle_out[1])
|
||||
strobe_out <= 1;
|
||||
end
|
||||
endmodule
|
||||
161
interface2/fpga/rtl/third_party/fifo_sync_ram.v
vendored
Normal file
161
interface2/fpga/rtl/third_party/fifo_sync_ram.v
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
// https://raw.githubusercontent.com/smunaut/ice40-playground/68ac87f6c458712a41d5b8e305d222849233ff00/cores/misc/rtl/fifo_sync_ram.v
|
||||
|
||||
/*
|
||||
* fifo_sync_ram.v
|
||||
*
|
||||
* vim: ts=4 sw=4
|
||||
*
|
||||
* Copyright (C) 2019 Sylvain Munaut <tnt@246tNt.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* BSD 3-clause, see LICENSE.bsd
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the <organization> nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module fifo_sync_ram #(
|
||||
parameter integer DEPTH = 256,
|
||||
parameter integer WIDTH = 16
|
||||
)(
|
||||
input wire [WIDTH-1:0] wr_data,
|
||||
input wire wr_ena,
|
||||
output wire wr_full,
|
||||
|
||||
output wire [WIDTH-1:0] rd_data,
|
||||
input wire rd_ena,
|
||||
output wire rd_empty,
|
||||
|
||||
input wire clk,
|
||||
input wire rst
|
||||
);
|
||||
|
||||
localparam AWIDTH = $clog2(DEPTH);
|
||||
|
||||
|
||||
// Signals
|
||||
// -------
|
||||
|
||||
// RAM
|
||||
reg [AWIDTH-1:0] ram_wr_addr;
|
||||
wire [ WIDTH-1:0] ram_wr_data;
|
||||
wire ram_wr_ena;
|
||||
|
||||
reg [AWIDTH-1:0] ram_rd_addr;
|
||||
wire [ WIDTH-1:0] ram_rd_data;
|
||||
wire ram_rd_ena;
|
||||
|
||||
// Fill-level
|
||||
reg [AWIDTH:0] level;
|
||||
(* keep="true" *) wire lvl_dec;
|
||||
(* keep="true" *) wire lvl_mov;
|
||||
wire lvl_empty;
|
||||
|
||||
// Full
|
||||
wire full_nxt;
|
||||
reg full;
|
||||
|
||||
// Read logic
|
||||
reg rd_valid;
|
||||
|
||||
|
||||
// Fill level counter
|
||||
// ------------------
|
||||
// (counts the number of used words - 1)
|
||||
|
||||
always @(posedge clk or posedge rst)
|
||||
if (rst)
|
||||
level <= {(AWIDTH+1){1'b1}};
|
||||
else
|
||||
level <= level + { {AWIDTH{lvl_dec}}, lvl_mov };
|
||||
|
||||
assign lvl_dec = ram_rd_ena & ~ram_wr_ena;
|
||||
assign lvl_mov = ram_rd_ena ^ ram_wr_ena;
|
||||
assign lvl_empty = level[AWIDTH];
|
||||
|
||||
|
||||
// Full flag generation
|
||||
// --------------------
|
||||
|
||||
assign full_nxt = level == { 1'b0, {(AWIDTH-2){1'b1}}, 2'b01 };
|
||||
|
||||
always @(posedge clk or posedge rst)
|
||||
if (rst)
|
||||
full <= 1'b0;
|
||||
else
|
||||
full <= (full | (wr_ena & ~rd_ena & full_nxt)) & ~(rd_ena & ~wr_ena);
|
||||
|
||||
assign wr_full = full;
|
||||
|
||||
|
||||
// Write
|
||||
// -----
|
||||
|
||||
always @(posedge clk or posedge rst)
|
||||
if (rst)
|
||||
ram_wr_addr <= 0;
|
||||
else if (ram_wr_ena)
|
||||
ram_wr_addr <= ram_wr_addr + 1;
|
||||
|
||||
assign ram_wr_data = wr_data;
|
||||
assign ram_wr_ena = wr_ena;
|
||||
|
||||
|
||||
// Read
|
||||
// ----
|
||||
|
||||
always @(posedge clk or posedge rst)
|
||||
if (rst)
|
||||
ram_rd_addr <= 0;
|
||||
else if (ram_rd_ena)
|
||||
ram_rd_addr <= ram_rd_addr + 1;
|
||||
|
||||
assign ram_rd_ena = (rd_ena | ~rd_valid) & ~lvl_empty;
|
||||
|
||||
always @(posedge clk or posedge rst)
|
||||
if (rst)
|
||||
rd_valid <= 1'b0;
|
||||
else if (rd_ena | ~rd_valid)
|
||||
rd_valid <= ~lvl_empty;
|
||||
|
||||
assign rd_data = ram_rd_data;
|
||||
assign rd_empty = ~rd_valid;
|
||||
|
||||
|
||||
// RAM
|
||||
// ---
|
||||
|
||||
ram_sdp #(
|
||||
.AWIDTH(AWIDTH),
|
||||
.DWIDTH(WIDTH)
|
||||
) ram_I (
|
||||
.wr_addr(ram_wr_addr),
|
||||
.wr_data(ram_wr_data),
|
||||
.wr_ena(ram_wr_ena),
|
||||
.rd_addr(ram_rd_addr),
|
||||
.rd_data(ram_rd_data),
|
||||
.rd_ena(ram_rd_ena),
|
||||
.clk(clk)
|
||||
);
|
||||
endmodule // fifo_sync_ram
|
||||
73
interface2/fpga/rtl/third_party/ram_sdp.v
vendored
Normal file
73
interface2/fpga/rtl/third_party/ram_sdp.v
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
// https://raw.githubusercontent.com/smunaut/ice40-playground/68ac87f6c458712a41d5b8e305d222849233ff00/cores/misc/rtl/ram_sdp.v
|
||||
|
||||
/*
|
||||
* ram_sdp.v
|
||||
*
|
||||
* vim: ts=4 sw=4
|
||||
*
|
||||
* Copyright (C) 2019 Sylvain Munaut <tnt@246tNt.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* BSD 3-clause, see LICENSE.bsd
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the <organization> nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module ram_sdp #(
|
||||
parameter integer AWIDTH = 9,
|
||||
parameter integer DWIDTH = 8
|
||||
)(
|
||||
input wire [AWIDTH-1:0] wr_addr,
|
||||
input wire [DWIDTH-1:0] wr_data,
|
||||
input wire wr_ena,
|
||||
|
||||
input wire [AWIDTH-1:0] rd_addr,
|
||||
output reg [DWIDTH-1:0] rd_data,
|
||||
input wire rd_ena,
|
||||
|
||||
input wire clk
|
||||
);
|
||||
// Signals
|
||||
reg [DWIDTH-1:0] ram [(1<<AWIDTH)-1:0];
|
||||
|
||||
`ifdef SIM
|
||||
integer i;
|
||||
initial
|
||||
for (i=0; i<(1<<AWIDTH); i=i+1)
|
||||
ram[i] = 0;
|
||||
`endif
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
// Read
|
||||
if (rd_ena)
|
||||
rd_data <= ram[rd_addr];
|
||||
|
||||
// Write
|
||||
if (wr_ena)
|
||||
ram[wr_addr] <= wr_data;
|
||||
end
|
||||
|
||||
endmodule // ram_sdp
|
||||
201
interface2/fpga/rtl/top.v
Normal file
201
interface2/fpga/rtl/top.v
Normal file
@@ -0,0 +1,201 @@
|
||||
// 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 top (
|
||||
input clk,
|
||||
|
||||
input reset_n,
|
||||
|
||||
// SPI
|
||||
input spi_sck,
|
||||
input spi_cs_n,
|
||||
input spi_sdi,
|
||||
output spi_sdo,
|
||||
|
||||
// TX
|
||||
output tx_active,
|
||||
output tx_n,
|
||||
output tx_delay,
|
||||
|
||||
// RX
|
||||
input rx,
|
||||
|
||||
output irq,
|
||||
|
||||
output gpio0,
|
||||
output gpio1,
|
||||
output gpio2,
|
||||
output gpio3
|
||||
);
|
||||
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;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
reset <= !reset_n_d[1];
|
||||
end
|
||||
|
||||
wire clk_fast;
|
||||
|
||||
SB_PLL40_CORE #(
|
||||
.FEEDBACK_PATH("SIMPLE"),
|
||||
.DIVR(4'b0000),
|
||||
.DIVF(7'b0010000),
|
||||
.DIVQ(3'b011),
|
||||
.FILTER_RANGE(3'b011)
|
||||
) clk_fast_pll (
|
||||
.RESETB(1'b1),
|
||||
.BYPASS(1'b0),
|
||||
.REFERENCECLK(clk),
|
||||
.PLLOUTCORE(clk_fast)
|
||||
);
|
||||
|
||||
wire [7:0] spi_rx_data;
|
||||
wire spi_rx_strobe;
|
||||
wire [7:0] spi_tx_data;
|
||||
wire spi_tx_strobe;
|
||||
|
||||
dual_clock_spi_device spi (
|
||||
.clk_slow(clk),
|
||||
.clk_fast(clk_fast),
|
||||
.spi_sck(spi_sck),
|
||||
.spi_cs_n(spi_cs_n),
|
||||
.spi_sdi(spi_sdi),
|
||||
.spi_sdo(spi_sdo),
|
||||
.rx_data(spi_rx_data),
|
||||
.rx_strobe(spi_rx_strobe),
|
||||
.tx_data(spi_tx_data),
|
||||
.tx_strobe(spi_tx_strobe)
|
||||
);
|
||||
|
||||
wire loopback;
|
||||
|
||||
wire tx_reset;
|
||||
wire internal_tx_active;
|
||||
wire internal_tx;
|
||||
wire [9:0] tx_data;
|
||||
wire tx_load_strobe;
|
||||
wire tx_start_strobe;
|
||||
wire tx_empty;
|
||||
wire tx_full;
|
||||
wire tx_ready;
|
||||
wire tx_parity;
|
||||
|
||||
coax_buffered_tx #(
|
||||
.CLOCKS_PER_BIT(16),
|
||||
.DEPTH(2048),
|
||||
.START_DEPTH(1536)
|
||||
) coax_buffered_tx (
|
||||
.clk(clk),
|
||||
.reset(reset || tx_reset),
|
||||
.active(internal_tx_active),
|
||||
.tx(internal_tx),
|
||||
.data(tx_data),
|
||||
.load_strobe(tx_load_strobe),
|
||||
.start_strobe(tx_start_strobe),
|
||||
.empty(tx_empty),
|
||||
.full(tx_full),
|
||||
.ready(tx_ready),
|
||||
.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 rx_active;
|
||||
wire rx_error;
|
||||
wire [9:0] rx_data;
|
||||
wire rx_read_strobe;
|
||||
wire rx_empty;
|
||||
wire rx_parity;
|
||||
|
||||
coax_buffered_rx #(
|
||||
.CLOCKS_PER_BIT(16),
|
||||
.DEPTH(2048)
|
||||
) coax_buffered_rx (
|
||||
.clk(clk),
|
||||
.reset(reset || rx_reset),
|
||||
.rx(internal_rx),
|
||||
.active(rx_active),
|
||||
.error(rx_error),
|
||||
.data(rx_data),
|
||||
.read_strobe(rx_read_strobe),
|
||||
.empty(rx_empty),
|
||||
.parity(rx_parity)
|
||||
);
|
||||
|
||||
control control (
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
|
||||
.spi_cs_n(spi_cs_n),
|
||||
.spi_rx_data(spi_rx_data),
|
||||
.spi_rx_strobe(spi_rx_strobe),
|
||||
.spi_tx_data(spi_tx_data),
|
||||
.spi_tx_strobe(spi_tx_strobe),
|
||||
|
||||
.loopback(loopback),
|
||||
|
||||
.tx_reset(tx_reset),
|
||||
.tx_active(internal_tx_active),
|
||||
.tx_data(tx_data),
|
||||
.tx_load_strobe(tx_load_strobe),
|
||||
.tx_start_strobe(tx_start_strobe),
|
||||
.tx_empty(tx_empty),
|
||||
.tx_full(tx_full),
|
||||
.tx_ready(tx_ready),
|
||||
.tx_parity(tx_parity),
|
||||
|
||||
.rx_reset(rx_reset),
|
||||
.rx_active(rx_active),
|
||||
.rx_error(rx_error),
|
||||
.rx_data(rx_data),
|
||||
.rx_read_strobe(rx_read_strobe),
|
||||
.rx_empty(rx_empty),
|
||||
.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 gpio1 = tx_active;
|
||||
assign gpio2 = rx_active;
|
||||
assign gpio3 = 0;
|
||||
endmodule
|
||||
Reference in New Issue
Block a user