Add SNOOPIE module

This commit is contained in:
Andrew Kay
2022-02-19 10:04:17 -06:00
parent 614f8a5f44
commit 1a6a0e9b80
12 changed files with 461 additions and 2 deletions

View File

@@ -61,6 +61,8 @@ public:
void handleInterrupt();
int snoopie(uint16_t *buffer, size_t bufferSize, uint8_t *writeIndex);
private:
SPICoaxTransceiver &_spiCoaxTransceiver;
CoaxProtocol _txProtocol;
@@ -129,6 +131,8 @@ public:
return readRegister(COAX_REGISTER_STATUS) & COAX_REGISTER_STATUS_RX_ACTIVE;
};
int snoopie(uint16_t *buffer, size_t bufferSize, uint8_t *writeIndex);
private:
void spiTransfer(const uint8_t *transmitBuffer, uint8_t *receiveBuffer, size_t count);
};

View File

@@ -25,6 +25,7 @@
#define COMMAND_INFO 0xf0
#define COMMAND_TEST 0xf1
#define COMMAND_DFU 0xf2
#define COMMAND_SNOOPIE_REPORT 0xf3
#define INFO_SUPPORTED_QUERIES 0x01
#define INFO_HARDWARE_TYPE 0x02
@@ -59,4 +60,7 @@ private:
void handleInfo(uint8_t *buffer, size_t bufferCount);
void handleTest(uint8_t *buffer, size_t bufferCount);
void handleDFU(uint8_t *buffer, size_t bufferCount);
void snoopieTeamAway();
void handleSnoopieReport(uint8_t *buffer, size_t bufferCount);
};

View File

@@ -246,10 +246,16 @@ void Coax::handleInterrupt()
}
}
int Coax::snoopie(uint16_t *buffer, size_t bufferSize, uint8_t *writeIndex)
{
return _spiCoaxTransceiver.snoopie(buffer, bufferSize, writeIndex);
}
#define COAX_COMMAND_READ_REGISTER 0x2
#define COAX_COMMAND_WRITE_REGISTER 0x3
#define COAX_COMMAND_TX 0x4
#define COAX_COMMAND_RX 0x5
#define COAX_COMMAND_SNOOPIE 0x6
#define COAX_COMMAND_RESET 0xff
#define NOP asm volatile("nop\n\t")
@@ -511,6 +517,37 @@ void SPICoaxTransceiver::setRXParity(CoaxParity parity)
writeRegister(COAX_REGISTER_CONTROL, parity == CoaxParity::Even ? COAX_REGISTER_CONTROL_RX_PARITY : 0, COAX_REGISTER_CONTROL_RX_PARITY);
}
int SPICoaxTransceiver::snoopie(uint16_t *buffer, size_t bufferSize, uint8_t *writeIndex)
{
uint8_t transmitBuffer[2] = { COAX_COMMAND_SNOOPIE };
uint8_t receiveBuffer[2];
ATOMIC_BLOCK_START;
LL_GPIO_ResetOutputPin(ICE40_CS_GPIO_Port, ICE40_CS_Pin);
spiTransfer(transmitBuffer, NULL, 1);
transmitBuffer[0] = 0x00;
transmitBuffer[1] = 0x00;
spiTransfer(transmitBuffer, receiveBuffer, 1);
*writeIndex = receiveBuffer[0];
for (size_t index = 0; index < bufferSize; index++) {
spiTransfer(transmitBuffer, receiveBuffer, 2);
uint16_t value = (receiveBuffer[0] << 8) | receiveBuffer[1];
buffer[index] = value;
}
LL_GPIO_SetOutputPin(ICE40_CS_GPIO_Port, ICE40_CS_Pin);
ATOMIC_BLOCK_END;
return 0;
}
void SPICoaxTransceiver::spiTransfer(const uint8_t *transmitBuffer,
uint8_t *receiveBuffer, size_t count)
{

View File

@@ -84,6 +84,8 @@ void Interface::handleMessage(uint8_t *buffer, size_t bufferCount)
handleTest(buffer + 3, count - 1);
} else if (command == COMMAND_DFU) {
handleDFU(buffer + 3, count - 1);
} else if (command == COMMAND_SNOOPIE_REPORT) {
handleSnoopieReport(buffer + 3, count - 1);
} else {
sendErrorMessage(ERROR_UNKNOWN_COMMAND, NULL);
}
@@ -178,6 +180,10 @@ void Interface::handleTransmitReceive(uint8_t *buffer, size_t bufferCount)
if (receiveCount < 0) {
Debug::trap(403, "error = %d", receiveCount);
// vvv
snoopieTeamAway();
// ^^^
_indicators.error();
// Convert the error to legacy interface error for compatability.
@@ -292,3 +298,34 @@ void Interface::handleDFU(uint8_t *buffer, size_t bufferCount)
resetToBootloader();
}
uint16_t snoopieBuffer[256];
uint8_t snoopieWriteIndex;
void Interface::snoopieTeamAway()
{
printf("\r\n\r\nSNOOPIE +++\r\n");
_coax.snoopie((uint16_t *) &snoopieBuffer, 256, &snoopieWriteIndex);
printf("writeIndex = %d\r\n", snoopieWriteIndex);
for (size_t index = 0; index < 256; index++) {
uint16_t counter = (snoopieBuffer[index] & 0xfff0) >> 4;
uint8_t probes = snoopieBuffer[index] & 0x0f;
printf("%d %d\r\n", counter, probes);
}
printf("SNOOPIE ---\r\n");
}
void Interface::handleSnoopieReport(uint8_t *buffer, size_t bufferCount)
{
buffer[0] = 0x01;
buffer[1] = snoopieWriteIndex;
memcpy(buffer + 2, &snoopieBuffer, 256 * sizeof(uint16_t));
MessageSender::send(buffer, 2 + (256 * sizeof(uint16_t)));
}

View File

@@ -19,6 +19,7 @@ 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 -verilog -lib work "snoopie.v"
add_file -constraint -lib work "clocks.sdc"
#implementation: "coax_Implmnt"
impl -add coax_Implmnt -type fpga

View File

@@ -47,7 +47,12 @@ module control (
output reg rx_read_strobe,
input rx_empty,
output rx_protocol,
output rx_parity
output rx_parity,
output reg snoopie_enable,
input [15:0] snoopie_read_data,
output reg snoopie_read_strobe,
input [7:0] snoopie_write_address
);
parameter DEFAULT_CONTROL_REGISTER = 8'b01001000;
@@ -64,6 +69,11 @@ module control (
localparam STATE_RX_3 = 10;
localparam STATE_RX_4 = 11;
localparam STATE_RESET = 12;
localparam STATE_SNOOPIE_1 = 13;
localparam STATE_SNOOPIE_2 = 14;
localparam STATE_SNOOPIE_3 = 15;
localparam STATE_SNOOPIE_4 = 16;
localparam STATE_SNOOPIE_5 = 17;
reg [7:0] state = STATE_IDLE;
reg [7:0] next_state;
@@ -94,6 +104,9 @@ module control (
reg [15:0] rx_buffer;
reg [15:0] next_rx_buffer;
reg next_snoopie_enable;
reg next_snoopie_read_strobe;
reg [1:0] spi_cs_n_d;
always @(posedge clk)
@@ -124,6 +137,9 @@ module control (
next_rx_read_strobe = 0;
next_rx_buffer = rx_buffer;
next_snoopie_enable = 1;
next_snoopie_read_strobe = 0;
case (state)
STATE_IDLE:
begin
@@ -136,6 +152,7 @@ module control (
4'h3: next_state = STATE_WRITE_REGISTER_1;
4'h4: next_state = STATE_TX_1;
4'h5: next_state = STATE_RX_1;
4'h6: next_state = STATE_SNOOPIE_1;
4'hf: next_state = STATE_RESET;
endcase
end
@@ -280,6 +297,57 @@ module control (
next_state = STATE_IDLE;
end
STATE_SNOOPIE_1:
begin
next_snoopie_enable = 0;
next_spi_tx_data = snoopie_write_address;
next_spi_tx_strobe = 1;
next_state = STATE_SNOOPIE_2;
end
STATE_SNOOPIE_2:
begin
next_snoopie_enable = 0;
if (spi_rx_strobe)
next_state = STATE_SNOOPIE_3;
end
STATE_SNOOPIE_3:
begin
next_snoopie_enable = 0;
next_spi_tx_data = snoopie_read_data[15:8];
next_spi_tx_strobe = 1;
next_state = STATE_SNOOPIE_4;
end
STATE_SNOOPIE_4:
begin
next_snoopie_enable = 0;
if (spi_rx_strobe)
begin
next_snoopie_read_strobe = 1;
next_spi_tx_data = snoopie_read_data[7:0];
next_spi_tx_strobe = 1;
next_state = STATE_SNOOPIE_5;
end
end
STATE_SNOOPIE_5:
begin
next_snoopie_enable = 0;
if (spi_rx_strobe)
next_state = STATE_SNOOPIE_3;
end
endcase
if (spi_cs_n_d[1])
@@ -317,6 +385,9 @@ module control (
rx_read_strobe <= next_rx_read_strobe;
rx_buffer <= next_rx_buffer;
snoopie_enable <= next_snoopie_enable;
snoopie_read_strobe <= next_snoopie_read_strobe;
if (reset)
begin
state <= STATE_IDLE;
@@ -337,6 +408,9 @@ module control (
rx_reset <= 0;
rx_read_strobe <= 0;
rx_buffer <= 0;
snoopie_enable <= 1;
snoopie_read_strobe <= 0;
end
previous_tx_active <= tx_active;

View File

@@ -0,0 +1,68 @@
`default_nettype none
module snoopie (
input clk,
input enable,
input [3:0] probes,
output [7:0] xxx_write_address,
output [15:0] read_data,
input read_strobe
);
reg previous_enable = 0;
reg [11:0] counter;
reg [3:0] previous_probes;
reg [7:0] write_address;
reg [15:0] write_data;
reg write_enable;
reg [7:0] read_address;
ram_sdp #(
.AWIDTH(8),
.DWIDTH(16)
) ram (
.clk(clk),
.wr_addr(write_address),
.wr_data(write_data),
.wr_ena(write_enable),
.rd_addr(read_address),
.rd_data(read_data),
.rd_ena(1'b1)
);
always @(posedge clk)
begin
counter <= counter + 1;
// Writer...
if (enable && !previous_enable)
write_address <= 0;
else if (write_enable)
write_address <= write_address + 1;
write_enable <= 0;
if (enable && probes != previous_probes)
begin
write_data <= { counter[11:0], probes[3:0] };
write_enable <= 1;
end
// Reader...
if (enable && !previous_enable)
read_address <= 0;
else if (read_strobe)
read_address <= read_address + 1;
previous_probes <= probes;
previous_enable <= enable;
end
assign xxx_write_address = write_address;
endmodule

View File

@@ -168,6 +168,23 @@ module top (
.rx_debug(rx_debug)
);
wire snoopie_enable;
wire [15:0] snoopie_read_data;
wire snoopie_read_strobe;
wire [7:0] snoopie_write_address;
snoopie snoopie (
.clk(clk),
.enable(snoopie_enable),
.probes({ internal_rx, rx_error, 2'b00 }),
.read_data(snoopie_read_data),
.read_strobe(snoopie_read_strobe),
.xxx_write_address(snoopie_write_address)
);
control control (
.clk(clk),
.reset(reset),
@@ -198,7 +215,12 @@ module top (
.rx_read_strobe(rx_read_strobe),
.rx_empty(rx_empty),
.rx_protocol(rx_protocol),
.rx_parity(rx_parity)
.rx_parity(rx_parity),
.snoopie_enable(snoopie_enable),
.snoopie_read_data(snoopie_read_data),
.snoopie_read_strobe(snoopie_read_strobe),
.snoopie_write_address(snoopie_write_address)
);
assign irq = rx_active || rx_error;

View File

@@ -17,6 +17,7 @@ coax_tx_rx_frontend_tb: coax_tx_rx_frontend_tb.v $(RTL)/coax_tx_rx_frontend.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
regression_johann_tb: regression_johann_tb.v $(RTL)/coax_rx.v $(RTL)/coax_rx_ss_detector.v
test: $(TESTS)
./run_tests.sh

View File

@@ -0,0 +1,169 @@
`default_nettype none
`include "assert.v"
module regression_johann_tb;
reg clk = 0;
initial
begin
forever
begin
#1 clk <= ~clk;
end
end
reg probe_rx = 0;
reg probe_error = 0;
reg reset = 0;
coax_rx #(
.CLOCKS_PER_BIT(16)
) dut (
.clk(clk),
.reset(reset),
.rx(probe_rx),
.protocol(1'b0),
.parity(1'b1)
);
initial
begin
$dumpfile("regression_johann_tb.vcd");
$dumpvars(0, regression_johann_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");
// ... | vcd2v -s 2 -t nnnn probe_rx=top.internal_rx probe_error=top.rx_error
//
// vvv
#200;
probe_rx = 1;
probe_error = 0;
#18;
probe_rx = 0;
probe_error = 0;
#16;
probe_rx = 1;
probe_error = 0;
#16;
probe_rx = 0;
probe_error = 0;
#16;
probe_rx = 1;
probe_error = 0;
#16;
probe_rx = 0;
probe_error = 0;
#16;
probe_rx = 1;
probe_error = 0;
#16;
probe_rx = 0;
probe_error = 0;
#16;
probe_rx = 1;
probe_error = 0;
#16;
probe_rx = 0;
probe_error = 0;
#16;
probe_rx = 1;
probe_error = 0;
#16;
probe_rx = 0;
probe_error = 0;
#48;
probe_rx = 1;
probe_error = 0;
#48;
probe_rx = 0;
probe_error = 0;
#16;
probe_rx = 1;
probe_error = 0;
#32;
probe_rx = 0;
probe_error = 0;
#16;
probe_rx = 1;
probe_error = 0;
#16;
probe_rx = 0;
probe_error = 0;
#16;
probe_rx = 1;
probe_error = 0;
#16;
probe_rx = 0;
probe_error = 0;
#16;
probe_rx = 1;
probe_error = 0;
#16;
probe_rx = 0;
probe_error = 0;
#16;
probe_rx = 1;
probe_error = 0;
#16;
probe_rx = 0;
probe_error = 0;
#16;
probe_rx = 1;
probe_error = 0;
#16;
probe_rx = 0;
probe_error = 0;
#32;
probe_rx = 1;
probe_error = 0;
#32;
probe_rx = 0;
probe_error = 0;
#32;
probe_rx = 1;
probe_error = 0;
#32;
probe_rx = 0;
probe_error = 0;
#32;
probe_rx = 1;
probe_error = 0;
#4;
probe_rx = 1;
probe_error = 1;
#28;
probe_rx = 0;
probe_error = 1;
#16;
probe_rx = 1;
probe_error = 1;
#82;
probe_rx = 0;
probe_error = 1;
#258;
probe_rx = 0;
probe_error = 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

View File

@@ -80,6 +80,42 @@ class SerialInterface(Interface):
if message[0] != 0x01:
raise _convert_error(message)
def snoopie_report(self):
message = bytes([0xf3])
self._write_message(message)
message = self._read_message()
if message[0] != 0x01:
raise Exception('Uh, some sort of problem with the SNOOPIE report')
if len(message) != 1 + 1 + (2 * 256):
raise Exception('Uh, length of SNOOPIE report is not correct')
write_index = message[1]
buffer = message[2:]
print()
print()
print('* ' * 40)
print(f'write_index = {write_index}')
for i in range(256):
x = buffer[i * 2] | (buffer[(i * 2) + 1] << 8)
counter = (x & 0xfff0) >> 4
probes = x & 0x0f
print(f'{counter} {probes}')
print('* ' * 40)
print()
print()
def _get_features(self):
"""Get interface features."""
message = bytes([0xf0, 0x07])
@@ -125,6 +161,10 @@ class SerialInterface(Interface):
if not isinstance(error, (ReceiveError, ReceiveTimeout)):
raise error
# vvv
self.snoopie_report()
# ^^^
response = error
responses.append(response)

View File

@@ -91,6 +91,8 @@ class SerialInterfaceTransmitReceiveTestCase(unittest.TestCase):
self.interface._write_message = Mock(wraps=self.interface._write_message)
self.interface._read_message = Mock()
self.interface.snoopie_report = Mock()
def test_words_frame(self):
# Arrange
self.interface._read_message.return_value=bytes.fromhex('01 00 00')