add ethernet_tx_tb
This commit is contained in:
parent
2c461ed08d
commit
15aa5f469f
8
Makefile
8
Makefile
|
|
@ -11,6 +11,9 @@ lint:
|
|||
serve_docs:
|
||||
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:
|
||||
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_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:
|
||||
iverilog -g2012 -o sim.out -y src/manta/ether_iface test/functional_sim/ethernet_rx_tb.sv
|
||||
vvp sim.out
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ cores:
|
|||
size: 64
|
||||
|
||||
ethernet:
|
||||
interface: "en3"
|
||||
interface: "en8"
|
||||
|
|
@ -1,17 +1,7 @@
|
|||
from manta import Manta
|
||||
from random import randint
|
||||
|
||||
m = Manta('manta.yaml')
|
||||
|
||||
from manta import Manta
|
||||
from time import sleep
|
||||
|
||||
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):
|
||||
# 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)
|
||||
# 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;
|
||||
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 (
|
||||
.clk(clk_50mhz),
|
||||
|
|
@ -44,6 +36,25 @@ module top_level (
|
|||
.txen(eth_txen),
|
||||
.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
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
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:
|
||||
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
|
||||
for option in config:
|
||||
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!"
|
||||
|
||||
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')
|
||||
|
||||
def write_register(self, addr, data):
|
||||
|
|
@ -99,61 +100,69 @@ class EthernetInterface:
|
|||
pkt.load = msg
|
||||
self.send_packet(pkt, iface=self.iface, verbose = self.verbose)
|
||||
|
||||
# def read_batch(addrs):
|
||||
# pkts = []
|
||||
# for addr in addrs:
|
||||
# pkt = Ether()
|
||||
# pkt.src = src_mac
|
||||
# pkt.dst = dst_mac
|
||||
# pkt.type = 0x0002
|
||||
def read_batch(self, addrs):
|
||||
# Prepare packets to read from addresses
|
||||
pkts = []
|
||||
for addr in addrs:
|
||||
pkt = Ether()
|
||||
pkt.src = self.host_mac
|
||||
pkt.dst = self.fpga_mac
|
||||
pkt.type = self.ethertype
|
||||
|
||||
# # two bytes of address, and 44 of padding
|
||||
# # makes the 46 byte minimum length
|
||||
# msg = addr.to_bytes(2, 'big') + 44*b'\x00'
|
||||
# one byte of rw, two bytes of address, and 44 of padding
|
||||
# makes the 46 byte minimum length
|
||||
msg = b'\x00' + addr.to_bytes(2, 'big') + 43*b'\x00'
|
||||
|
||||
# pkt = pkt / msg
|
||||
# pkt.load = msg
|
||||
# pkts.append(pkt)
|
||||
pkt = pkt / msg
|
||||
pkt.load = msg
|
||||
pkts.append(pkt)
|
||||
|
||||
# sniffer = AsyncSniffer(iface = iface, count = len(addrs), filter="ether src 69:69:5a:06:54:91")
|
||||
# sniffer.start()
|
||||
# from time import sleep
|
||||
# time.sleep(0.1)
|
||||
# Start sniffer in another thread, send packets, grab responses
|
||||
sniffer = AsyncSniffer(iface = self.iface, count = len(addrs), filter=f"ether src {self.fpga_mac}")
|
||||
sniffer.start()
|
||||
sleep(0.1)
|
||||
sendp(pkts, iface=self.iface, verbose = 0, inter = 0.05)
|
||||
sniffer.join()
|
||||
results = sniffer.results
|
||||
|
||||
# sendp(pkts, iface=iface, verbose = 0)
|
||||
# sniffer.join()
|
||||
# results = sniffer.results
|
||||
assert len(results) == len(addrs), "Received more packets than expected!"
|
||||
|
||||
# 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 = []
|
||||
# for packet in results:
|
||||
# raw_response_bytes = bytes(packet.payload)[0:2]
|
||||
# data = int.from_bytes(raw_response_bytes, 'big')
|
||||
# datas.append(data)
|
||||
# Parse packets
|
||||
datas = []
|
||||
for packet in results:
|
||||
raw_response_bytes = bytes(packet.payload)[3:5]
|
||||
data = int.from_bytes(raw_response_bytes, 'big')
|
||||
datas.append(data)
|
||||
|
||||
# return datas
|
||||
return datas
|
||||
|
||||
# def write_batch(addrs, data):
|
||||
# pkts = []
|
||||
# for i in range(len(addrs)):
|
||||
# pkt = Ether()
|
||||
# pkt.src = src_mac
|
||||
# pkt.dst = dst_mac
|
||||
# pkt.type = 0x0002
|
||||
def write_batch(self, addrs, datas):
|
||||
assert len(addrs) == len(datas), \
|
||||
"Number of addresses provided is unequal to number of data provided!"
|
||||
|
||||
# addr = addrs[i]
|
||||
# data = datas[i]
|
||||
pkts = []
|
||||
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
|
||||
# # data, and 42 of padding makes the 46 byte
|
||||
# # minimum length
|
||||
# msg = addr.to_bytes(2, 'big') + data.to_bytes(2, 'big') + 42*b'\x00'
|
||||
# one byte of rw, two bytes of address, two bytes of data, and 41
|
||||
# bytes of paddding make the 46 byte limit.
|
||||
msg = b'\x01' + addr.to_bytes(2, 'big') + data.to_bytes(2, 'big') + 41*b'\x00'
|
||||
|
||||
# pkt = pkt / msg
|
||||
# pkt.load = msg
|
||||
pkt = pkt / 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):
|
||||
return ["input wire crsdv", \
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ module ethernet_rx (
|
|||
assign rw_o = (payload[39:32] == 8'd1);
|
||||
assign addr_o = payload[31:16];
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ module ethernet_tx (
|
|||
) mtx (
|
||||
.clk(clk),
|
||||
|
||||
.payload(rdata_buf),
|
||||
.payload({24'd0, rdata_buf}),
|
||||
.start(~rw_i && valid_i),
|
||||
|
||||
.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