add ethernet_tx_tb

This commit is contained in:
Fischer Moseley 2023-04-27 23:13:51 -04:00
parent 2c461ed08d
commit 15aa5f469f
8 changed files with 250 additions and 74 deletions

View File

@ -11,6 +11,9 @@ lint:
serve_docs: serve_docs:
mkdocs serve mkdocs serve
src_loc:
find src -type f \( -iname \*.sv -o -iname \*.v -o -iname \*.py -o -iname \*.yaml -o -iname \*.md \) | sed 's/.*/"&"/' | xargs wc -l
total_loc: total_loc:
find . -type f \( -iname \*.sv -o -iname \*.v -o -iname \*.py -o -iname \*.yaml -o -iname \*.yml -o -iname \*.md \) | sed 's/.*/"&"/' | xargs wc -l find . -type f \( -iname \*.sv -o -iname \*.v -o -iname \*.py -o -iname \*.yaml -o -iname \*.yml -o -iname \*.md \) | sed 's/.*/"&"/' | xargs wc -l
@ -31,6 +34,11 @@ auto_gen:
# Functional Simulation # Functional Simulation
functional_sim: io_core_tb logic_analyzer_tb bit_fifo_tb bridge_rx_tb bridge_tx_tb lut_mem_tb functional_sim: io_core_tb logic_analyzer_tb bit_fifo_tb bridge_rx_tb bridge_tx_tb lut_mem_tb
ethernet_tx_tb:
iverilog -g2012 -o sim.out -y src/manta/ether_iface test/functional_sim/ethernet_tx_tb.sv
vvp sim.out
rm sim.out
ethernet_rx_tb: ethernet_rx_tb:
iverilog -g2012 -o sim.out -y src/manta/ether_iface test/functional_sim/ethernet_rx_tb.sv iverilog -g2012 -o sim.out -y src/manta/ether_iface test/functional_sim/ethernet_rx_tb.sv
vvp sim.out vvp sim.out

View File

@ -5,4 +5,4 @@ cores:
size: 64 size: 64
ethernet: ethernet:
interface: "en3" interface: "en8"

View File

@ -1,17 +1,7 @@
from manta import Manta from manta import Manta
from random import randint from random import randint
m = Manta('manta.yaml')
from manta import Manta
from time import sleep
m = Manta("manta.yaml") m = Manta("manta.yaml")
print(m.my_lut_mem.read(0))
m.my_lut_mem.write(0, 5)
print(m.my_lut_mem.read(0))
# for addr in range(m.my_lut_mem.size): # for addr in range(m.my_lut_mem.size):
# write_data = randint(0, (2**16)-1) # write_data = randint(0, (2**16)-1)
@ -19,4 +9,41 @@ print(m.my_lut_mem.read(0))
# read_data = m.my_lut_mem.read(addr) # read_data = m.my_lut_mem.read(addr)
# print(f"test addr: {addr} with data: {write_data}") # print(f"test addr: {addr} with data: {write_data}")
# print(f" -> correct data received on readback?: {write_data == read_data}") # print(f" -> correct data received on readback?: {write_data == read_data}")
# addrs = list(range(m.my_lut_mem.size))
# datas = addrs
# print(m.my_lut_mem.interface.read_batch(addrs))
# internal rage intensifies
# try writing a single register at a time which is known good,
# and then read them back all at once
# m.my_lut_mem.write(39, 42069)
# m.my_lut_mem.write(40, 42070)
# print(m.my_lut_mem.read(39))
# print(m.my_lut_mem.read(40))
# print(m.my_lut_mem.interface.read_batch([39,40]))
# exit()
# ok so i think i kind of understand the issue
# so basically what's happening here is that whatever is in the
# 16's place of the write data at the last write persists in all the reads, meaning
#addrs = list(range(48))
addrs = list(range(m.my_lut_mem.size))
print(addrs)
print('\n')
from time import sleep
for addr in addrs:
m.my_lut_mem.write(addr, addr)
sleep(0.1)
print([m.my_lut_mem.read(addr) for addr in addrs])
print('\n')

View File

@ -26,15 +26,7 @@ module top_level (
assign eth_refclk = clk_50mhz; assign eth_refclk = clk_50mhz;
divider d (.clk(clk), .ethclk(clk_50mhz)); divider d (.clk(clk), .ethclk(clk_50mhz));
assign led = manta_inst.brx_my_lut_mem_addr;
assign led16_r = manta_inst.brx_my_lut_mem_rw;
assign led17_r = manta_inst.brx_my_lut_mem_valid;
ssd ssd (
.clk(clk_50mhz),
.val( {manta_inst.my_lut_mem_btx_rdata, manta_inst.brx_my_lut_mem_wdata} ),
.cat({cg,cf,ce,cd,cc,cb,ca}),
.an(an));
manta manta_inst ( manta manta_inst (
.clk(clk_50mhz), .clk(clk_50mhz),
@ -44,6 +36,25 @@ module top_level (
.txen(eth_txen), .txen(eth_txen),
.txd(eth_txd)); .txd(eth_txd));
// debugging!
initial led17_r = 0;
reg [31:0] val = 0;
always @(posedge clk_50mhz) begin
if(manta_inst.my_lut_mem.valid_o) begin
led <= manta_inst.my_lut_mem.addr_o;
led16_r <= manta_inst.my_lut_mem.rw_o;
led17_r <= !led17_r;
val <= {manta_inst.my_lut_mem.rdata_o, manta_inst.my_lut_mem.wdata_o};
end
end
ssd ssd (
.clk(clk_50mhz),
.val(val),
.cat({cg,cf,ce,cd,cc,cb,ca}),
.an(an));
endmodule endmodule

View File

@ -1,15 +1,16 @@
from ..hdl_utils import * from ..hdl_utils import *
# Lazy and selective imports for quick builds!
from scapy.interfaces import get_if_list
from scapy.arch import get_if_hwaddr
from scapy.layers.l2 import Ether
from scapy.sendrecv import AsyncSniffer, sendp, sendpfast
from time import sleep
from scapy.all import *
class EthernetInterface: class EthernetInterface:
def __init__(self, config): def __init__(self, config):
# Lazy and selective imports for quick builds!
from scapy.interfaces import get_if_list
from scapy.arch import get_if_hwaddr
from scapy.layers.l2 import Ether
from scapy.sendrecv import AsyncSniffer, sendp, sendpfast
from time import sleep
# Warn if unrecognized options have been given # Warn if unrecognized options have been given
for option in config: for option in config:
if option not in ["interface", "host_mac", "fpga_mac", "ethertype", "tcpreplay", "verbose"]: if option not in ["interface", "host_mac", "fpga_mac", "ethertype", "tcpreplay", "verbose"]:
@ -81,7 +82,7 @@ class EthernetInterface:
assert len(results) == 1, "Received more packets than expected!" assert len(results) == 1, "Received more packets than expected!"
raw_response_bytes = bytes(results[0].payload)[0:2] raw_response_bytes = bytes(results[0].payload)[3:5]
return int.from_bytes(raw_response_bytes, 'big') return int.from_bytes(raw_response_bytes, 'big')
def write_register(self, addr, data): def write_register(self, addr, data):
@ -99,61 +100,69 @@ class EthernetInterface:
pkt.load = msg pkt.load = msg
self.send_packet(pkt, iface=self.iface, verbose = self.verbose) self.send_packet(pkt, iface=self.iface, verbose = self.verbose)
# def read_batch(addrs): def read_batch(self, addrs):
# pkts = [] # Prepare packets to read from addresses
# for addr in addrs: pkts = []
# pkt = Ether() for addr in addrs:
# pkt.src = src_mac pkt = Ether()
# pkt.dst = dst_mac pkt.src = self.host_mac
# pkt.type = 0x0002 pkt.dst = self.fpga_mac
pkt.type = self.ethertype
# # two bytes of address, and 44 of padding # one byte of rw, two bytes of address, and 44 of padding
# # makes the 46 byte minimum length # makes the 46 byte minimum length
# msg = addr.to_bytes(2, 'big') + 44*b'\x00' msg = b'\x00' + addr.to_bytes(2, 'big') + 43*b'\x00'
# pkt = pkt / msg pkt = pkt / msg
# pkt.load = msg pkt.load = msg
# pkts.append(pkt) pkts.append(pkt)
# sniffer = AsyncSniffer(iface = iface, count = len(addrs), filter="ether src 69:69:5a:06:54:91") # Start sniffer in another thread, send packets, grab responses
# sniffer.start() sniffer = AsyncSniffer(iface = self.iface, count = len(addrs), filter=f"ether src {self.fpga_mac}")
# from time import sleep sniffer.start()
# time.sleep(0.1) sleep(0.1)
sendp(pkts, iface=self.iface, verbose = 0, inter = 0.05)
sniffer.join()
results = sniffer.results
# sendp(pkts, iface=iface, verbose = 0) assert len(results) == len(addrs), "Received more packets than expected!"
# sniffer.join()
# results = sniffer.results
# assert len(results) == len(addrs), "Received more packets than expected!" # #print(raw(results[1]))
# for packet in results:
# hexdump(packet)
# print( [i for i in bytes(packet.payload)] )
# print( [i for i in raw(packet)] )
# print("\n")
# datas = [] # Parse packets
# for packet in results: datas = []
# raw_response_bytes = bytes(packet.payload)[0:2] for packet in results:
# data = int.from_bytes(raw_response_bytes, 'big') raw_response_bytes = bytes(packet.payload)[3:5]
# datas.append(data) data = int.from_bytes(raw_response_bytes, 'big')
datas.append(data)
# return datas return datas
# def write_batch(addrs, data): def write_batch(self, addrs, datas):
# pkts = [] assert len(addrs) == len(datas), \
# for i in range(len(addrs)): "Number of addresses provided is unequal to number of data provided!"
# pkt = Ether()
# pkt.src = src_mac
# pkt.dst = dst_mac
# pkt.type = 0x0002
# addr = addrs[i] pkts = []
# data = datas[i] for addr, data in zip(addrs, datas):
pkt = Ether()
pkt.src = self.host_mac
pkt.dst = self.fpga_mac
pkt.type = self.ethertype
# # two bytes of address, two bytes of # one byte of rw, two bytes of address, two bytes of data, and 41
# # data, and 42 of padding makes the 46 byte # bytes of paddding make the 46 byte limit.
# # minimum length msg = b'\x01' + addr.to_bytes(2, 'big') + data.to_bytes(2, 'big') + 41*b'\x00'
# msg = addr.to_bytes(2, 'big') + data.to_bytes(2, 'big') + 42*b'\x00'
# pkt = pkt / msg pkt = pkt / msg
# pkt.load = msg pkt.load = msg
pkts.append(pkt)
# sendp(pkts, iface=iface, verbose = 0) self.send_packet(pkts, iface=self.iface, verbose = 0)
def hdl_top_level_ports(self): def hdl_top_level_ports(self):
return ["input wire crsdv", \ return ["input wire crsdv", \

View File

@ -34,7 +34,7 @@ module ethernet_rx (
assign rw_o = (payload[39:32] == 8'd1); assign rw_o = (payload[39:32] == 8'd1);
assign addr_o = payload[31:16]; assign addr_o = payload[31:16];
assign wdata_o = payload[15:0]; assign wdata_o = payload[15:0];
assign valid_o = valid && ( payload[39:32] == 8'd0 || payload[39:32] == 8'd1); assign valid_o = valid && ( payload[39:32] == 8'd0 || payload[39:32] == 8'd1) && (payload[55:40] == 16'h88B5);
endmodule endmodule

View File

@ -29,7 +29,7 @@ module ethernet_tx (
) mtx ( ) mtx (
.clk(clk), .clk(clk),
.payload(rdata_buf), .payload({24'd0, rdata_buf}),
.start(~rw_i && valid_i), .start(~rw_i && valid_i),
.txen(txen), .txen(txen),

View File

@ -0,0 +1,121 @@
`default_nettype none
//`timescale 1ns/1ps
`define FPGA_MAC 48'h69_69_5A_06_54_91
`define HOST_MAC 48'h00_E0_4C_68_1E_0C
`define ETHERTYPE 16'h88_B5
task send_on_etx_receive_on_mrx (
input [15:0] data
);
ethernet_tx_tb.etx_rdata = data;
ethernet_tx_tb.etx_rw = 0;
ethernet_tx_tb.etx_valid = 0;
#10;
ethernet_tx_tb.etx_valid = 1;
#10;
ethernet_tx_tb.etx_valid = 0;
while(!ethernet_tx_tb.mrx_valid) #10;
$display(ethernet_tx_tb.mrx_payload);
endtask
module ethernet_tx_tb();
// https://www.youtube.com/watch?v=K35qOTQLNpA
logic clk;
always begin
#5;
clk = !clk;
end
logic txen;
logic [1:0] txd;
// ethernet tx
reg [15:0] etx_rdata;
reg etx_rw;
reg etx_valid;
ethernet_tx #(
.FPGA_MAC(`FPGA_MAC),
.HOST_MAC(`HOST_MAC),
.ETHERTYPE(`ETHERTYPE)
) etx (
.clk(clk),
.rdata_i(etx_rdata),
.rw_i(etx_rw),
.valid_i(etx_valid),
.txen(txen),
.txd(txd));
// mac_rx, for decoding
logic crsdv;
logic [1:0] rxd;
reg [55:0] mrx_payload;
reg mrx_valid;
mac_rx #(
// this is the host mac since we're using mac_rx to impersonate
// the host computer, to which packets are currently addressed.
.FPGA_MAC(`HOST_MAC),
.ETHERTYPE(`ETHERTYPE)
) mrx (
.clk(clk),
.crsdv(crsdv),
.rxd(rxd),
.payload(mrx_payload),
.valid(mrx_valid));
logic [15:0] where_ethertype_should_be;
logic [7:0] where_rw_should_be;
logic [15:0] where_addr_should_be;
logic [15:0] where_data_should_be;
assign {where_ethertype_should_be, where_rw_should_be, where_addr_should_be, where_data_should_be} = mrx_payload;
assign rxd = txd;
assign crsdv = txen;
initial begin
$dumpfile("ethernet_tx_tb.vcd");
$dumpvars(0, ethernet_tx_tb);
clk = 0;
etx_rdata = 16'h6970;
etx_rw = 0;
etx_valid = 0;
#50;
send_on_etx_receive_on_mrx(16'h6970);
#10000;
// for (int i=0; i<32; i=i+1) begin
// mtx_payload = i;
// mtx_start = 0;
// #10;
// mtx_start = 1;
// #10;
// mtx_start = 0;
// while(!mrx_valid) #10;
// #1000;
// assert(mrx_payload == i) else $error("data mismatch!");
// end
$finish();
end
endmodule
`default_nettype wire