diff --git a/Makefile b/Makefile index 449c206..bb4f318 100644 --- a/Makefile +++ b/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 diff --git a/examples/nexys_a7/lut_mem_ether/manta.yaml b/examples/nexys_a7/lut_mem_ether/manta.yaml index f9f4150..3b0a94f 100644 --- a/examples/nexys_a7/lut_mem_ether/manta.yaml +++ b/examples/nexys_a7/lut_mem_ether/manta.yaml @@ -5,4 +5,4 @@ cores: size: 64 ethernet: - interface: "en3" \ No newline at end of file + interface: "en8" \ No newline at end of file diff --git a/examples/nexys_a7/lut_mem_ether/read_write_test.py b/examples/nexys_a7/lut_mem_ether/read_write_test.py index 600cc24..c90535b 100644 --- a/examples/nexys_a7/lut_mem_ether/read_write_test.py +++ b/examples/nexys_a7/lut_mem_ether/read_write_test.py @@ -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}") \ No newline at end of file +# 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') \ No newline at end of file diff --git a/examples/nexys_a7/lut_mem_ether/top_level.sv b/examples/nexys_a7/lut_mem_ether/top_level.sv index 48d9496..e9d1f4c 100644 --- a/examples/nexys_a7/lut_mem_ether/top_level.sv +++ b/examples/nexys_a7/lut_mem_ether/top_level.sv @@ -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 diff --git a/src/manta/ether_iface/__init__.py b/src/manta/ether_iface/__init__.py index acdb9f2..f7cf62b 100644 --- a/src/manta/ether_iface/__init__.py +++ b/src/manta/ether_iface/__init__.py @@ -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", \ diff --git a/src/manta/ether_iface/ethernet_rx.v b/src/manta/ether_iface/ethernet_rx.v index 55eee87..f057709 100644 --- a/src/manta/ether_iface/ethernet_rx.v +++ b/src/manta/ether_iface/ethernet_rx.v @@ -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 diff --git a/src/manta/ether_iface/ethernet_tx.v b/src/manta/ether_iface/ethernet_tx.v index 08e82c7..cce4110 100644 --- a/src/manta/ether_iface/ethernet_tx.v +++ b/src/manta/ether_iface/ethernet_tx.v @@ -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), diff --git a/test/functional_sim/ethernet_tx_tb.sv b/test/functional_sim/ethernet_tx_tb.sv new file mode 100644 index 0000000..6883fd7 --- /dev/null +++ b/test/functional_sim/ethernet_tx_tb.sv @@ -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 \ No newline at end of file