diff --git a/doc/ethernet.md b/doc/ethernet.md new file mode 100644 index 0000000..72b327f --- /dev/null +++ b/doc/ethernet.md @@ -0,0 +1,37 @@ +ok so the way the new packets work is: + +- everything uses the same ethertype - that's configured once, in manta.yaml, and is set as a parameter in each of the rx and tx stacks + +- we do [addr] [data] for incoming write messages, and [addr] for incoming read messages. +- we do [data] for outgoing read responses. this means that: + - we need to detect packet length on mac_rx + - packets coming out of the FPGA are fixed-width, mac_tx will always send out 2 bytes of data + - packets going into the FPGA are guarunteed to be longer than packets coming out of the FPGA + +- actually this doesn't make a lot of sense - we're going to be padding anyway, so this really just introduces extra complexity for us. let's just do + something like [rw] [addr] [data] + - since we know that we're _always_ going to get in at least 60 bytes of content and each message only contains like + - we could say that in the future since we're using a fixed ethertype and can detect the paket length based on the crsdv line, we could concevably + stack a bunch of [rw] [addr] [data] things together in the same packet - and creep right up to the ethernet MTU. but we'll file that along the 'other stuff' + and go from there. for now let's just pull 1 + 2 + 2 = 5 bytes = 40 bits into aggregate and see what happens. + + - ok so then updated mac_rx is: + - ether, with the reset removed from it + - bitorder, with the reset removed from it + - firewall, but checks the destination MAC of the packet in addition to the ethertype + - transaction, which turns the packets coming in into rw/addr/data triplets. this is then outputted to the top level of mac_rx + + - and the updated mac_tx is: + - just the same, except we just put the busficiation logic inside it. so then instead of having start we do the logic with rw_i and valid_i ourselves, + and buffer thee data ourselves + + - so then we just have mac_tx and mac_rx in the manta core chain. which feels good. + + +previous ideas: + - how to do variable length detection? right now our current stack is not well suited for that + - keeping in line with the existing stack, we want to progressively take out chunks as time goes on. + - i think we should modify firewall to check ethertype in addition to mac address also get rid of the reset while we're at it + - because it's jaycode, probably going to be easier to rewrite from scratch to preserve style and sanity. i don't have anything to prove + - we can use the 205 checkers for this, ironcially enough + - i think we should modify aggregate to get both the payload and length. the payload is clocked in dibit-by-dibit, so we'll want to grab the \ No newline at end of file diff --git a/examples/nexys_a7/lut_ram_ether/send_packet.py b/examples/nexys_a7/lut_ram_ether/send_packet.py index 11be180..39bb472 100644 --- a/examples/nexys_a7/lut_ram_ether/send_packet.py +++ b/examples/nexys_a7/lut_ram_ether/send_packet.py @@ -21,7 +21,7 @@ def read_register(addr): sniffer.start() from time import sleep time.sleep(0.1) - sendp(pkt, iface=ifc) + sendp(pkt, iface=ifc, verbose = 0) results = sniffer.stop() assert len(results) == 1, "Received more packets than expected!" @@ -44,7 +44,7 @@ def write_register(addr, data): pkt = pkt / msg pkt.load = msg - sendp(pkt, iface=ifc) + sendp(pkt, iface=ifc, verbose = 0) def read_batch(addrs): pkts = [] @@ -67,7 +67,7 @@ def read_batch(addrs): from time import sleep time.sleep(0.1) - sendp(pkts, iface=ifc) + sendp(pkts, iface=ifc, verbose = 0) sniffer.join() results = sniffer.results @@ -100,26 +100,25 @@ def write_batch(addrs, data): pkt = pkt / msg pkt.load = msg - sendp(pkts, iface=ifc) + sendp(pkts, iface=ifc, verbose = 0) from time import sleep if __name__ == "__main__": - # for addr in range(64): - # data = addr - # write_register(addr, data) + for addr in range(64): + data = addr + write_register(addr, data) + retval = read_register(addr) + if retval != addr: + print(f"ERROR: sent {data} got {retval}") - # retval = read_register(addr) - # if retval != addr: - # print("oops") + else: + print(f"SUCCESS: sent {data} got {retval}") - # else: - # print(f"yay addr: {addr} worked!") - - addrs = [i for i in range(64)] - datas = addrs - write_batch(addrs, datas) - print("done") - retvals = read_batch(addrs) - print(retvals) + # addrs = [i for i in range(64)] + # datas = addrs + # write_batch(addrs, datas) + # print("done") + # retvals = read_batch(addrs) + # print(retvals) diff --git a/examples/nexys_a7/lut_ram_ether/src/manta.v b/examples/nexys_a7/lut_ram_ether/src/manta.v index 27329a4..8b7ce7c 100644 --- a/examples/nexys_a7/lut_ram_ether/src/manta.v +++ b/examples/nexys_a7/lut_ram_ether/src/manta.v @@ -27,7 +27,10 @@ module manta( output reg txen, output reg [1:0] txd); - ethernet_rx erx ( + ethernet_rx # ( + .FPGA_MAC(48'h69_69_5A_06_54_91), + .ETHERTYPE(16'h88_B5) + ) erx ( .clk(clk), .crsdv(crsdv), @@ -64,7 +67,11 @@ module manta( reg my_lut_ram_btx_rw; reg my_lut_ram_btx_valid; - ethernet_tx etx ( + ethernet_tx #( + .FPGA_MAC(48'h69_69_5A_06_54_91), + .HOST_MAC(48'h00_E0_4C_68_1E_0C), + .ETHERTYPE(16'h88_B5) + ) etx ( .clk(clk), .txen(txen), diff --git a/src/manta/aggregate.v b/src/manta/aggregate.v index e2e7772..31334a5 100644 --- a/src/manta/aggregate.v +++ b/src/manta/aggregate.v @@ -7,54 +7,36 @@ * first 32 bits on an AXI bus for a single cycle. * If the packet is not at least 64 bits long, * nothing happens - * - * This value can then be fed into the seven - * segment display to verify proper operation - * of your module! */ `define AGR_MAX 48 `define AGR_SHOW 64 -module aggregate(clk, rst, axiid, axiiv, axiod, axiov); +module aggregate ( + input wire clk, + input wire [1:0] axiid, + input wire axiiv, - /* batteries */ - input logic clk, rst; - - /* AXI input valid, and AXI input data from the - * Ethernet pipeline. Comprises only data, i.e. - * source/destination/ethertype are omitted via - * previous stages in the pipeline. Also technically - * comprises the FCS, but we assume that the actual - * data in the ethernet frame is >= 32 bits long - * so we'll lose the FCS in this stage by design - */ - input logic[1:0] axiid; - input logic axiiv; - - /* AXI output valid, and AXI output data. Comprises - * just the first 32 bits of the incoming transmission, - * asserted for a single cycle - */ - output logic[47:0] axiod; - output logic axiov; + output reg [47:0] axiod, + output reg axiov); /* A quick and dirty counter. As long as this is below * 32, we'll dump packets into the AXI output data buffer. * Once the counter gets to AGR_MAX, we'll assert AXI valid. * Then we'll hang until axiiv drops */ - logic[31:0] counter; + + reg [31:0] counter; assign axiov = counter == `AGR_SHOW; - always_ff @(posedge clk) begin: COUNTER - if (rst || !axiiv) counter <= 32'b0; + always @(posedge clk) begin: COUNTER + if (!axiiv) counter <= 32'b0; else counter <= counter + 2; end - always_ff @(posedge clk) begin: AXIOD - if (rst || !axiiv) axiod <= 32'b0; + always @(posedge clk) begin: AXIOD + if (!axiiv) axiod <= 32'b0; else if (counter < `AGR_MAX && axiiv) axiod[`AGR_MAX - counter - 2 +: 2] <= axiid; end diff --git a/src/manta/bitorder.v b/src/manta/bitorder.v index 0de0c15..5a5ad46 100644 --- a/src/manta/bitorder.v +++ b/src/manta/bitorder.v @@ -1,39 +1,19 @@ `default_nettype none `timescale 1ns / 1ps -/* Ethernet sends packets in least significant - * bit order, most significant byte order. This - * module is responsible for changing that to - * make things legible - in particular, we convert - * from LSb/MSB to MSb/MSB. - */ - `define BO_SENDA 2'b00 `define BO_SENDB 2'b01 `define BO_EMPTYA 2'b10 `define BO_EMPTYB 2'b11 -module bitorder(clk, rst, axiiv, axiid, axiod, axiov); +module bitorder ( + input wire clk, - /* batteries */ - input logic clk, rst; + input wire axiiv, + input wire [1:0] axiid, - /* AXI input valid and AXI input data - * from the module upstream from us in the - * pipeline - that being the physical layer - * This will transport bits from off the wire - * in least significant bit first order - */ - input logic[1:0] axiid; - input logic axiiv; - - /* AXI output valid and AXI output data - * Transports the correctly bit-ordered Ethernet - * data (most significant bit first) up the pipeline - * for further processing... - */ - output logic[1:0] axiod; - output logic axiov; + output reg [1:0] axiod, + output reg axiov); /* Two registers to hold data coming in off the wire, * byte by byte. This is where we'll buffer until @@ -42,97 +22,91 @@ module bitorder(clk, rst, axiiv, axiid, axiod, axiov); * order using one register. Meanwhile, we'll start * receiving into the other register - dual buffers. */ - logic[7:0] bufa, bufb; + reg [7:0] bufa = 8'b0; + reg [7:0] bufb = 8'b0; /* A counter. This indicates what 'stage' we're in, * and always refers to the index we're reading into * in the receiving buffer or sending out of in the * sending buffer */ - logic[2:0] countera, counterb; + reg [2:0] countera = 3'b0; + reg [2:0] counterb = 3'b0; /* Which state we're in - should we be using buffer * A to send, buffer B to send, or neither because * we've just come out of reset? */ - logic[1:0] state; + reg [1:0] state = `BO_EMPTYB; - always_comb begin: AXIOV + always @(*) begin: AXIOV if (state == `BO_SENDA || state == `BO_SENDB) axiov = 1'b1; else axiov = 1'b0; end - always_comb begin: AXIOD + always @(*) begin: AXIOD if (state == `BO_SENDA) axiod = bufa[countera +: 2]; else if (state == `BO_SENDB) axiod = bufb[counterb +: 2]; else axiod = 1'b0; end - always_ff @(posedge clk) begin: BUFFERIN - if (rst) begin - bufa <= 8'b0; - bufb <= 8'b0; - end else if (axiiv) begin + always @(posedge clk) begin: BUFFERIN + if (axiiv) begin case (state) `BO_EMPTYB, `BO_SENDB: bufa[countera +: 2] <= axiid; `BO_EMPTYA, `BO_SENDA: bufb[counterb +: 2] <= axiid; endcase - end else if (state == `BO_EMPTYB || state == `BO_EMPTYA) begin + end + + else if (state == `BO_EMPTYB || state == `BO_EMPTYA) begin bufa <= 8'b0; bufb <= 8'b0; end end - always_ff @(posedge clk) begin: STATES - if (rst) begin - state <= `BO_EMPTYB; - countera <= 3'b0; - counterb <= 3'b0; - end else begin - case (state) - `BO_EMPTYB: begin - if (axiiv) begin - if (countera == 3'h6) - state <= `BO_SENDA; - else countera <= countera + 2; - end else countera <= 3'b0; - end + always @(posedge clk) begin: STATES + case (state) + `BO_EMPTYB: begin + if (axiiv) begin + if (countera == 3'h6) + state <= `BO_SENDA; + else countera <= countera + 2; + end else countera <= 3'b0; + end - `BO_EMPTYA: begin - if (axiiv) begin - if (counterb == 3'h6) - state <= `BO_SENDB; - else counterb <= counterb + 2; - end else counterb <= 3'b0; - end + `BO_EMPTYA: begin + if (axiiv) begin + if (counterb == 3'h6) + state <= `BO_SENDB; + else counterb <= counterb + 2; + end else counterb <= 3'b0; + end - `BO_SENDB: begin - if (counterb == 3'h0) state <= `BO_EMPTYB; - else counterb <= counterb - 2; + `BO_SENDB: begin + if (counterb == 3'h0) state <= `BO_EMPTYB; + else counterb <= counterb - 2; - if (axiiv) begin - if (countera == 3'h6) - state <= `BO_SENDA; - else countera <= countera + 2; - end - end + if (axiiv) begin + if (countera == 3'h6) + state <= `BO_SENDA; + else countera <= countera + 2; + end + end - `BO_SENDA: begin - if (countera == 3'h0) state <= `BO_EMPTYA; - else countera <= countera - 2; + `BO_SENDA: begin + if (countera == 3'h0) state <= `BO_EMPTYA; + else countera <= countera - 2; - if (axiiv) begin - if (counterb == 3'h6) - state <= `BO_SENDB; - else counterb <= counterb + 2; - end - end - endcase - end + if (axiiv) begin + if (counterb == 3'h6) + state <= `BO_SENDB; + else counterb <= counterb + 2; + end + end + endcase end - endmodule `default_nettype wire diff --git a/src/manta/cksum.v b/src/manta/cksum.v index 59dcfaa..3cf8b80 100644 --- a/src/manta/cksum.v +++ b/src/manta/cksum.v @@ -19,52 +19,37 @@ `define CK_FRESH 2'b00 `define CK_COMPUTING 2'b01 `define CK_DONE 2'b10 - + `define MAGIC_CHECK 32'h38_fb_22_84 -module cksum(clk, rst, axiid, axiiv, done, kill); +module cksum ( + input wire clk, + input wire [1:0] axiid, + input wire axiiv, - /* batteries */ - input logic clk, rst; + output reg done, + output reg kill); - /* AXI input valid, and AXI input data from the - * physical layer. Comprises unmodified data directly - * from the wire, in Ethernet bit order, to be fed - * directly into the CRC32 module you wrote for the - * pset - */ - input logic[1:0] axiid; - input logic axiiv; - - /* Done and kill, as described in the module synopsis */ - output logic done, kill; - - /* CRC32 AXI output data bus, which is the 32-bit - * checksum calculated so far via the checksum module - * you implemented in one of the last psets (CRC32-BZIP2) - */ - logic[31:0] crcd; - logic crcv; + reg [31:0] crcd; + reg crcv; /* Decoupled logic to reset the CRC module independently * Used to compute multiple CRCs back to back */ - logic crcrst; + reg crcrst; - /* Our finite state machine - bonus points if you can identify - * whether this is a Moore or Mealy FSM! - */ - logic[1:0] state; + reg [1:0] state = `CK_FRESH; - crc32 cksum(.clk(clk), - .rst(crcrst | rst), - .axiiv(axiiv), - .axiid(axiid), - .axiov(crcv), - .axiod(crcd)); + crc32 cksum( + .clk(clk), + .rst(crcrst), + .axiiv(axiiv), + .axiid(axiid), + .axiov(crcv), + .axiod(crcd)); - always_ff @(posedge clk) begin: OUTPUTS - if (rst || axiiv) begin + always @(posedge clk) begin: OUTPUTS + if (axiiv) begin done <= 1'b0; kill <= 1'b0; crcrst <= 1'b0; @@ -72,22 +57,19 @@ module cksum(clk, rst, axiid, axiiv, done, kill); if (state == `CK_COMPUTING && !axiiv) begin done <= 1'b1; crcrst <= 1'b1; + kill <= (crcd != `MAGIC_CHECK); + end - if (crcd == `MAGIC_CHECK) kill <= 1'b0; - else kill <= 1'b1; - end else crcrst <= 1'b0; + else crcrst <= 1'b0; end end - always_ff @(posedge clk) begin: FSM - if (rst) state <= `CK_FRESH; - else begin - case (state) + always @(posedge clk) begin: FSM + case (state) `CK_FRESH: if (axiiv) state <= `CK_COMPUTING; `CK_COMPUTING: if (!axiiv) state <= `CK_DONE; `CK_DONE: if (axiiv) state <= `CK_COMPUTING; - endcase - end + endcase end endmodule diff --git a/src/manta/ether.v b/src/manta/ether.v index 9e84886..56ad986 100644 --- a/src/manta/ether.v +++ b/src/manta/ether.v @@ -1,27 +1,6 @@ `default_nettype none `timescale 1ns / 1ps -/* This module receives packets from the RJ45 (Ethernet) port on your - * FPGA from the _physical layer_, i.e. the electronic (or optical!) - * connection between devices running through an Ethernet cable. - * - * Ethernet is very diverse set of specifications, with all sorts of - * different physical layers (which we abbreviate 'the medium' or - * 'media' in plural). Ethernet media have transfer speeds ranging - * from 1 Mbps to 400 gigabits per second in modern data centers! - * For this implementation, we will implement "Fast Ethernet", which - * (not fast by today's standards) utilizes a physical layer capable - * of 100 Mbps communication. Most modern cables are backwards - * compatible with this standard. - */ - -/* Note: this file uses tabs instead of spaces for indentation. - * More modern editors should pick this up automatically, but if yours - * doesn't that might explain trouble getting things to line up. You - * can probably configure this (e.g. in vim, type ":set noexpandtab" - * in normal mode and then type ":set tabstop=8") - */ - `define EF_IDLE 3'b000 `define EF_PREAM 3'b001 `define EF_DATA 3'b011 @@ -35,60 +14,19 @@ `define PREAM_LAST 2'b11 `define PREAM_BAD 2'b10 -module ether(clk, rst, rxd, crsdv, axiov, axiod); +module ether ( + input wire clk, + input wire [1:0] rxd, + input wire crsdv, - input logic clk, rst; + output reg axiov, + output reg [1:0] axiod); - /* Carrier Sense (CRS) / Data Valid (DV): indicates - * whether there is a valid signal currently being - * transmitted over the Ethernet medium by another - * sender. - * - * In the past, >2 computers were connected - * to the same Ethernet cable, so this helped - * distinguish if one machine was trying to talk over - * another. Nowadays, usually Ethernet connections are - * point to point (have you ever seen an Ethernet cable - * with three ports on it? no? that's what i thought), - * and shared media isn't even supported in the 100 Mbps - * spec. - * - * So just use this input to determine whether valid - * data is on the line coming in. - */ - input logic crsdv; + reg [4:0] count; + reg [2:0] state; - /* Receive Data (RXD): If crsdv is high, receives - * two bits off the wire. Otherwise, undefined - * (let's say 2'bXX) - * - * According to the IEEE 802.3 Fast Ethernet - * specification, with the exception of the FCS, - * bytes in Ethernet world are sent least significant - * bit first, most significant byte first. Confusing! - * Basically, if you have a two byte (16 bit) message, - * the bits will come in over RXD as: - * - * 7:6 -> 5:4 -> 3:2 -> 1:0 -> 15:14 -> ... -> 9:8 - * - * For now, this idiosyncracy won't matter to you. - * Later, it will. - */ - input logic[1:0] rxd; - - /* 2-bit AXI output: forward whatever we receive - * on to the outside world for further processing - */ - output logic axiov; - output logic[1:0] axiod; - - /* END OF STARTER CODE */ - - logic[4:0] count; - logic[2:0] state; - - logic[1:0] preamex; - logic preamok, start; + reg [1:0] preamex; + reg preamok, start; always @(*) begin: PREAM if (count == `PREAM_SIZE - 1) preamex = `PREAM_LAST; @@ -105,34 +43,34 @@ module ether(clk, rst, rxd, crsdv, axiov, axiod); else count <= 0; end + initial begin + axiod = 2'b0; + axiov = 1'b0; + state = 3'b0; + end + always @(posedge clk) begin: FSM - if (rst) begin - axiod <= 2'b0; - axiov <= 1'b0; - state <= 3'b0; - end else begin - case (state) - `EF_BAD: if (!crsdv) state <= `EF_IDLE; - `EF_IDLE: if (start) state <= `EF_PREAM; + case (state) + `EF_BAD: if (!crsdv) state <= `EF_IDLE; + `EF_IDLE: if (start) state <= `EF_PREAM; - `EF_PREAM: begin - if (!preamok || !crsdv) state <= `EF_BAD; - else if (count == `PREAM_SIZE - 1) - state <= `EF_DATA; - end + `EF_PREAM: begin + if (!preamok || !crsdv) state <= `EF_BAD; + else if (count == `PREAM_SIZE - 1) + state <= `EF_DATA; + end - `EF_DATA: begin - if (crsdv) begin - axiov <= 1'b1; - axiod <= rxd; - end else begin - axiov <= 1'b0; - axiod <= 2'b0; - state <= `EF_IDLE; - end - end - endcase - end + `EF_DATA: begin + if (crsdv) begin + axiov <= 1'b1; + axiod <= rxd; + end else begin + axiov <= 1'b0; + axiod <= 2'b0; + state <= `EF_IDLE; + end + end + endcase end endmodule diff --git a/src/manta/ethernet_rx.v b/src/manta/ethernet_rx.v index 02676f9..7cd1f71 100644 --- a/src/manta/ethernet_rx.v +++ b/src/manta/ethernet_rx.v @@ -13,27 +13,29 @@ module ethernet_rx ( output reg valid_o ); - // we know if the packet is a read or write - // based on the ethertype. + parameter FPGA_MAC = 0; + parameter ETHERTYPE = 0; - reg [15:0] ethertype; reg [31:0] data; reg valid; - mac_rx mrx ( + mac_rx #( + .DST_MAC(48'h69_69_5A_06_54_91), + .ETHERTYPE(16'h88_B5) + ) mrx ( .clk(clk), .crsdv(crsdv), .rxd(rxd), - .ethertype(ethertype), - .data(data), + .payload(payload), + .length(length) .valid(valid)); - assign addr_o = data[31:16]; - assign wdata_o = data[15:0]; - assign rw_o = (ethertype == 4); - assign valid_o = valid && ((ethertype == 4) || (ethertype == 2)); + assign addr_o = payload[31:16]; + assign wdata_o = payload[15:0]; + assign rw_o = (length == 4); + assign valid_o = valid && ((length == 4) || (length == 2)); endmodule diff --git a/src/manta/ethernet_tx.v b/src/manta/ethernet_tx.v index b1f9725..e0e0982 100644 --- a/src/manta/ethernet_tx.v +++ b/src/manta/ethernet_tx.v @@ -1,25 +1,35 @@ `default_nettype none `timescale 1ns/1ps -module ethernet_tx( +module ethernet_tx ( input wire clk, - output reg txen, - output reg [1:0] txd, - input wire [15:0] rdata_i, input wire rw_i, - input wire valid_i + input wire valid_i, + + output reg txen, + output reg [1:0] txd ); - reg [15:0] data_buf = 0; - always @(posedge clk) if(~rw_i && valid_i) data_buf <= rdata_i; + parameter FPGA_MAC = 0; + parameter HOST_MAC = 0; + parameter ETHERTYPE = 0; - mac_tx mtx ( + reg [15:0] rdata_buf = 0; + + always @(posedge clk) + if(~rw_i && valid_i) rdata_buf <= rdata_i; + + mac_tx #( + .SRC_MAC(FPGA_MAC), + .DST_MAC(HOST_MAC), + .ETHERTYPE(ETHERTYPE), + .PAYLOAD_LENGTH_BYTES(2) + ) mtx ( .clk(clk), - .data(data_buf), - .ethertype(16'h2), + .payload(rdata_buf), .start(~rw_i && valid_i), .txen(txen), diff --git a/src/manta/firewall.v b/src/manta/firewall.v index af4c2a3..8da52ab 100644 --- a/src/manta/firewall.v +++ b/src/manta/firewall.v @@ -1,62 +1,21 @@ `default_nettype none `timescale 1ns / 1ps -/* Sometimes we might receive packets not - * intended for us on the wire. This is especially - * true if we're operating in old school mode, where - * Ethernet used to have many devices on the same - * medium. Alternatively, several virtual NICs may - * exist in software on a given machine, or a machine - * may support MAC address randomization. - * - * All of this means we need to make sure inbound - * packets are actually intended for us, and not - * for some other NIC. That's what this module is - * for. In addition, this module will also strip - * the MAC address pair (and Ethertype) off of the - * Ethernet header, leaving only data and the FCS. - * We'll clean up the FCS later... - */ - -/* "Intended for us" means the following: - * - has the destination MAC "`FW_ME" as defined below. Make this - * your own MAC of your choice - get creative! - * - has the destination MAC of all 1s, i.e. a 'broadcast' packet - * - * If these conditions are not met on a given input stream, data - * from the packet is dropped / not forwarded on through the - * pipeline - */ - -`define FW_ME 48'h69_69_5A_06_54_91 `define FW_DESTSTART 0 `define FW_DESTEND (`FW_DESTSTART + 48) `define FW_DATASTART (48 + 48) -module firewall(clk, rst, axiiv, axiid, axiov, axiod); +module firewall ( + input wire clk, + input wire axiiv, + input wire [1:0] axiid, - /* batteries */ - input logic clk, rst; + output reg axiov, + output reg [1:0] axiod); - /* AXI input valid, and AXI input data from the bit order - * flip module. So this will transport MSb/MSB first data - * coming off the wire - allowing you to compare with src/dst - * MAC addresses a bit more easily - */ - input logic[1:0] axiid; - input logic axiiv; - - /* AXI output valid, and AXI output data. If and only if - * the packet is intended for our device as described above, - * this line will stream out the _data_ and _fcs_ (NOT the MAC - * addresses in the header, nor the ethertype - we're ignoring - * the latter this time around) we're receiving off the wire. - * If a kill-worthy condition is detected, these lines are - * deasserted for the duration of the incoming packet - */ - output logic[1:0] axiod; - output logic axiov; + parameter ETHERTYPE = 0; + parameter FPGA_MAC = 0; /* Buffers to hold our MAC address in the reverse order, * to make comparison easier than it otherwise would be @@ -79,9 +38,9 @@ module firewall(clk, rst, axiiv, axiid, axiov, axiod); */ logic matchme, matchbcast; - assign me = `FW_ME; + assign me = FPGA_MAC; - always_ff @(posedge clk) begin: MATCH + always @(posedge clk) begin: MATCH if (counter == 32'b0) begin matchme <= 1'b1; matchbcast <= 1'b1; @@ -101,7 +60,7 @@ module firewall(clk, rst, axiiv, axiid, axiov, axiod); end end - always_comb begin: AXIOUT + always @(*) begin: AXIOUT if (counter >= `FW_DATASTART && (matchme | matchbcast)) begin axiod = axiid; axiov = axiiv; @@ -111,7 +70,7 @@ module firewall(clk, rst, axiiv, axiid, axiov, axiod); end end - always_ff @(posedge clk) begin: COUNTER + always @(posedge clk) begin: COUNTER if (axiiv) counter <= counter + 2; else counter <= 32'b0; end diff --git a/src/manta/mac_rx.v b/src/manta/mac_rx.v index 843dbee..6b404a1 100644 --- a/src/manta/mac_rx.v +++ b/src/manta/mac_rx.v @@ -7,69 +7,60 @@ module mac_rx ( input wire crsdv, input wire [1:0] rxd, - output reg [15:0] ethertype, - output reg [31:0] data, + output reg [39:0] payload, output reg valid); - // TODO: rewrite modules to not need external reset - reg rst = 1; - always @(posedge clk) rst <= 0; + parameter FPGA_MAC = 0; + parameter ETHERTYPE = 0; - /* ether -> { cksum, bitorder } */ - reg[1:0] ether_axiod; + reg [1:0] ether_axiod; reg ether_axiov; - ether e( + ether e ( .clk(clk), - .rst(rst), .rxd(rxd), .crsdv(crsdv), .axiov(ether_axiov), .axiod(ether_axiod)); - /* bitorder -> firewall */ - reg[1:0] bitorder_axiod; + reg [1:0] bitorder_axiod; reg bitorder_axiov; - bitorder b( + bitorder b ( .clk(clk), - .rst(rst), .axiiv(ether_axiov), .axiid(ether_axiod), .axiov(bitorder_axiov), .axiod(bitorder_axiod)); - /* firewall -> aggregate */ - reg[1:0] firewall_axiod; + reg [1:0] firewall_axiod; reg firewall_axiov; - firewall f( + firewall #( + .FPGA_MAC(FPGA_MAC), + .ETHERTYPE(ETHERTYPE) + ) f ( .clk(clk), - .rst(rst), .axiiv(bitorder_axiov), .axiid(bitorder_axiod), .axiov(firewall_axiov), .axiod(firewall_axiod)); - /* aggregate output */ - reg[47:0] aggregate_axiod; + reg [47:0] aggregate_axiod; reg aggregate_axiov; - aggregate a( + aggregate a ( .clk(clk), - .rst(rst), .axiiv(firewall_axiov), .axiid(firewall_axiod), .axiov(aggregate_axiov), .axiod(aggregate_axiod)); - /* cksum -> top_level */ reg cksum_done; reg cksum_kill; - cksum c( + cksum c ( .clk(clk), - .rst(rst), .axiiv(ether_axiov), .axiid(ether_axiod), .done(cksum_done), @@ -83,7 +74,7 @@ module mac_rx ( reg [1:0] state = IDLE; initial valid = 0; - initial data = 0; + initial payload = 0; always @(posedge clk) begin valid <= 0; @@ -95,12 +86,11 @@ module mac_rx ( else if(state == WAIT_FOR_DATA) begin if(aggregate_axiov) begin state <= WAIT_FOR_FCS; - ethertype <= aggregate_axiod[47:32]; - data <= aggregate_axiod[31:0]; - + payload <= aggregate_axiod[31:0]; end - // if aggregate never gives us data, go back to idle when the packet ends + // if aggregate never gives us data, + // go back to idle when the packet ends else if(cksum_done) state <= IDLE; end diff --git a/src/manta/mac_tx.v b/src/manta/mac_tx.v index f7b39f0..812c078 100644 --- a/src/manta/mac_tx.v +++ b/src/manta/mac_tx.v @@ -4,9 +4,7 @@ module mac_tx ( input wire clk, - // TODO: make this variable width - input wire [15:0] data, - input wire [15:0] ethertype, + input wire [(8 * PAYLOAD_LENGTH_BYTES)-1:0] payload, input wire start, output reg txen, @@ -15,8 +13,10 @@ module mac_tx ( // packet magic numbers localparam PREAMBLE = {7{8'b01010101}}; localparam SFD = 8'b11010101; - parameter SRC_MAC = 48'h69_69_69_69_69_69; - parameter DST_MAC = 48'hFF_FF_FF_FF_FF_FF; + parameter [47:0] SRC_MAC = 0; + parameter [47:0] DST_MAC = 0; + parameter [15:0] ETHERTYPE = 0; + parameter PAYLOAD_LENGTH_BYTES = 0; // all lengths are in units of dibits, hence all the mulitplies by four localparam PREAMBLE_LEN = 7 * 4; @@ -24,16 +24,11 @@ module mac_tx ( localparam SRC_MAC_LEN = 6 * 4; localparam DST_MAC_LEN = 6 * 4; localparam ETHERTYPE_LEN = 2 * 4; - localparam PAYLOAD_LEN = 2 * 4; - // localparam ZERO_PAD_LEN = (46 * 4) - PAYLOAD_LEN ; // minimum payload size is 46 bytes + localparam PAYLOAD_LEN = PAYLOAD_LENGTH_BYTES * 4; localparam ZERO_PAD_LEN = (46 * 4) - PAYLOAD_LEN + 4; // minimum payload size is 46 bytes localparam FCS_LEN = 4 * 4; localparam IPG_LEN = 96 / 2; - // TODO: make crc and bitorder modules not need reset - reg rst = 1; - always @(posedge clk) rst <= 0; - reg [1:0] bitorder_axiid; reg [1:0] bitorder_axiod; reg bitorder_axiiv; @@ -41,7 +36,6 @@ module mac_tx ( bitorder bitorder ( .clk(clk), - .rst(rst), .axiiv(bitorder_axiiv), .axiid(bitorder_axiid), @@ -202,14 +196,14 @@ module mac_tx ( ETHERTYPE_STATE: begin bitorder_axiiv = 1; - bitorder_axiid = ethertype[2*(ETHERTYPE_LEN-counter)-1-:2]; + bitorder_axiid = ETHERTYPE[2*(ETHERTYPE_LEN-counter)-1-:2]; txen = bitorder_axiov; txd = bitorder_axiod; end PAYLOAD_STATE: begin bitorder_axiiv = 1; - bitorder_axiid = data[2*(PAYLOAD_LEN-counter)-1-:2]; + bitorder_axiid = payload[2*(PAYLOAD_LEN-counter)-1-:2]; txen = bitorder_axiov; txd = bitorder_axiod; end diff --git a/test/functional_sim/mac_tb.sv b/test/functional_sim/mac_tb.sv index 9517d05..9e867de 100644 --- a/test/functional_sim/mac_tb.sv +++ b/test/functional_sim/mac_tb.sv @@ -1,6 +1,11 @@ `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 + + module mac_tb(); logic clk; @@ -15,19 +20,24 @@ module mac_tb(); logic txen; logic [1:0] txd; - logic [15:0] mtx_data; - logic [15:0] mtx_ethertype; + // this testbench makes sure that our rx pipeline is good, + // so we'll have mtx simulate the host machine and blast + // 5 bytes (plus padding) onto our fake RMII + logic [39:0] mtx_payload; logic mtx_start; - logic [15:0] mrx_data; - logic [15:0] mrx_ethertype; + logic [39:0] mrx_payload; logic mrx_valid; - mac_tx mtx ( + mac_tx #( + .SRC_MAC(`HOST_MAC), + .DST_MAC(`FPGA_MAC), + .ETHERTYPE(`ETHERTYPE), + .PAYLOAD_LENGTH_BYTES(5) + ) mtx ( .clk(clk), - .data(mtx_data), - .ethertype(mtx_ethertype), + .payload(mtx_payload), .start(mtx_start), .txen(txen), @@ -36,28 +46,28 @@ module mac_tb(); assign rxd = txd; assign crsdv = txen; - mac_rx mrx ( + mac_rx #( + .FPGA_MAC(`FPGA_MAC), + .ETHERTYPE(`ETHERTYPE) + ) mrx ( .clk(clk), .crsdv(crsdv), .rxd(rxd), - .data(mrx_data), - .ethertype(mrx_ethertype), + .payload(mrx_payload), .valid(mrx_valid)); initial begin $dumpfile("mac_tb.vcd"); $dumpvars(0, mac_tb); clk = 0; - mtx_ethertype = 0; - mtx_data = 0; + mtx_payload = 0; mtx_start = 0; #10; - for (int i=0; i<128; i=i+1) begin - mtx_data = i; - mtx_ethertype = i; + for (int i=0; i<32; i=i+1) begin + mtx_payload = i; mtx_start = 0; #10; mtx_start = 1; @@ -67,7 +77,7 @@ module mac_tb(); #1000; - assert(mrx_data == i) else $error("data mismatch!"); + assert(mrx_payload == i) else $error("data mismatch!"); end $finish(); end