add ethernet_tx_tb
This commit is contained in:
parent
2c461ed08d
commit
15aa5f469f
8
Makefile
8
Makefile
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,4 @@ cores:
|
||||||
size: 64
|
size: 64
|
||||||
|
|
||||||
ethernet:
|
ethernet:
|
||||||
interface: "en3"
|
interface: "en8"
|
||||||
|
|
@ -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')
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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", \
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
Loading…
Reference in New Issue