manta/examples/nexys_a7/lut_ram_ether/src/mac_tx.v

248 lines
6.7 KiB
Verilog

`default_nettype none
`timescale 1ns/1ps
module mac_tx (
input wire clk,
// TODO: make this variable width
input wire [15:0] data,
input wire [15:0] ethertype,
input wire start,
output reg txen,
output reg [1:0] txd);
// 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;
// all lengths are in units of dibits, hence all the mulitplies by four
localparam PREAMBLE_LEN = 7 * 4;
localparam SFD_LEN = 1 * 4;
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 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;
reg bitorder_axiov;
bitorder bitorder (
.clk(clk),
.rst(rst),
.axiiv(bitorder_axiiv),
.axiid(bitorder_axiid),
.axiov(bitorder_axiov),
.axiod(bitorder_axiod));
reg crc_rst = 1;
reg crc_axiiv = 0;
reg [31:0] crc_axiod;
crc32 crc (
.clk(clk),
.rst(crc_rst),
.axiiv(crc_axiiv),
.axiid(bitorder_axiod),
// TODO: remove axiov from crc32 module, it's always valid
.axiov(),
.axiod(crc_axiod));
// state machine
reg [8:0] counter = 0;
reg [3:0] state = 0;
localparam IDLE_STATE = 0;
localparam PREAMBLE_STATE = 1;
localparam SFD_STATE = 2;
localparam DST_MAC_STATE = 3;
localparam SRC_MAC_STATE = 4;
localparam ETHERTYPE_STATE = 5;
localparam PAYLOAD_STATE = 6;
localparam ZERO_PAD_STATE = 7;
localparam FCS_STATE = 8;
localparam IPG_STATE = 9;
// sequential logic manages the state machine
always @(posedge clk) begin
counter <= counter + 1;
crc_rst <= 0;
if(state == IDLE_STATE) begin
counter <= 0;
crc_axiiv <= 0;
if(start) state <= PREAMBLE_STATE;
end
else if(state == PREAMBLE_STATE) begin
if(counter == PREAMBLE_LEN - 1) begin
counter <= 0;
state <= SFD_STATE;
end
end
else if(state == SFD_STATE) begin
if(counter == SFD_LEN - 1) begin
counter <= 0;
state <= DST_MAC_STATE;
end
end
else if(state == DST_MAC_STATE) begin
// this is because the crc module lags behind the FSM,
// as it has to go through bitorder first
if(counter == 3) crc_axiiv <= 1;
if(counter == DST_MAC_LEN - 1) begin
counter <= 0;
state <= SRC_MAC_STATE;
end
end
else if(state == SRC_MAC_STATE) begin
if(counter == SRC_MAC_LEN - 1) begin
counter <= 0;
state <= ETHERTYPE_STATE;
end
end
else if(state == ETHERTYPE_STATE) begin
if(counter == ETHERTYPE_LEN - 1) begin
counter <= 0;
state <= PAYLOAD_STATE;
end
end
else if(state == PAYLOAD_STATE) begin
if(counter == PAYLOAD_LEN - 1) begin
counter <= 0;
state <= ZERO_PAD_STATE;
end
end
else if(state == ZERO_PAD_STATE) begin
if(counter == ZERO_PAD_LEN - 1) begin
crc_axiiv <= 0;
counter <= 0;
state <= FCS_STATE;
end
end
else if(state == FCS_STATE) begin
if(counter == FCS_LEN - 1) begin
counter <= 0;
state <= IPG_STATE;
end
end
else if(state == IPG_STATE) begin
if(counter == IPG_LEN - 1) begin
crc_rst <= 1;
counter <= 0;
state <= IDLE_STATE;
end
end
end
// combinational logic handles the pipeline
always @(*) begin
case (state)
IDLE_STATE: begin
bitorder_axiiv = 0;
bitorder_axiid = 0;
txen = 0;
txd = 0;
end
PREAMBLE_STATE: begin
bitorder_axiiv = 1;
bitorder_axiid = PREAMBLE[2*(PREAMBLE_LEN-counter)-1-:2];
txen = bitorder_axiov;
txd = bitorder_axiod;
end
SFD_STATE: begin
bitorder_axiiv = 1;
bitorder_axiid = SFD[2*(SFD_LEN-counter)-1-:2];
txen = bitorder_axiov;
txd = bitorder_axiod;
end
DST_MAC_STATE: begin
bitorder_axiiv = 1;
bitorder_axiid = DST_MAC[2*(DST_MAC_LEN-counter)-1-:2];
txen = bitorder_axiov;
txd = bitorder_axiod;
end
SRC_MAC_STATE: begin
bitorder_axiiv = 1;
bitorder_axiid = SRC_MAC[2*(SRC_MAC_LEN-counter)-1-:2];
txen = bitorder_axiov;
txd = bitorder_axiod;
end
ETHERTYPE_STATE: begin
bitorder_axiiv = 1;
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];
txen = bitorder_axiov;
txd = bitorder_axiod;
end
ZERO_PAD_STATE: begin
bitorder_axiiv = 1;
bitorder_axiid = 0;
txen = bitorder_axiov;
txd = bitorder_axiod;
end
FCS_STATE: begin
bitorder_axiiv = 0;
bitorder_axiid = 0;
txen = 1;
txd = {crc_axiod[2*(FCS_LEN-counter)-2], crc_axiod[2*(FCS_LEN-counter)-1]};
end
IPG_STATE: begin
bitorder_axiiv = 0;
bitorder_axiid = 0;
txen = 0;
txd = 0;
end
default: begin
bitorder_axiiv = 0;
bitorder_axiid = 0;
txen = 0;
txd = 0;
end
endcase
end
endmodule
`default_nettype wire