Rework ARP datapath modules to separate output register

This commit is contained in:
Alex Forencich 2014-10-28 01:55:36 -07:00
parent 4474181549
commit 0f62d31fef
4 changed files with 335 additions and 266 deletions

View File

@ -92,9 +92,9 @@ ARP Frame
THA Target MAC 6 octets
TPA Target IP 4 octets
This module receives an Ethernet frame with decoded fields and decodes
the ARP packet format. If the Ethertype does not match, the packet is
discarded.
This module receives an Ethernet frame with header fields in parallel and
payload on an AXI stream interface, decodes the ARP packet fields, and
produces the frame fields in parallel.
*/
@ -138,8 +138,8 @@ reg store_arp_tpa_3;
reg [7:0] frame_ptr_reg = 0, frame_ptr_next;
reg input_eth_hdr_ready_reg = 0;
reg input_eth_payload_tready_reg = 0;
reg input_eth_hdr_ready_reg = 0, input_eth_hdr_ready_next;
reg input_eth_payload_tready_reg = 0, input_eth_payload_tready_next;
reg output_frame_valid_reg = 0, output_frame_valid_next;
reg [47:0] output_eth_dest_mac_reg = 0;
@ -183,6 +183,9 @@ assign error_invalid_header = error_invalid_header_reg;
always @* begin
state_next = 2'bz;
input_eth_hdr_ready_next = 0;
input_eth_payload_tready_next = 0;
store_eth_hdr = 0;
store_arp_htype_0 = 0;
store_arp_htype_1 = 0;
@ -224,9 +227,11 @@ always @* begin
STATE_IDLE: begin
// idle state - wait for data
frame_ptr_next = 0;
input_eth_hdr_ready_next = ~output_frame_valid_reg;
if (input_eth_hdr_ready & input_eth_hdr_valid) begin
frame_ptr_next = 0;
input_eth_hdr_ready_next = 0;
input_eth_payload_tready_next = 1;
store_eth_hdr = 1;
state_next = STATE_READ_HEADER;
end else begin
@ -235,6 +240,8 @@ always @* begin
end
STATE_READ_HEADER: begin
// read header state
input_eth_payload_tready_next = 1;
if (input_eth_payload_tvalid) begin
// word transfer in - store it
frame_ptr_next = frame_ptr_reg+1;
@ -274,7 +281,6 @@ always @* begin
endcase
if (input_eth_payload_tlast) begin
// end of frame
state_next = STATE_IDLE;
if (frame_ptr_reg != 8'h1B) begin
// don't have the whole header
error_header_early_termination_next = 1;
@ -285,6 +291,9 @@ always @* begin
// otherwise, transfer tuser
output_frame_valid_next = ~input_eth_payload_tuser;
end
input_eth_hdr_ready_next = ~output_frame_valid_reg;
input_eth_payload_tready_next = 0;
state_next = STATE_IDLE;
end
end else begin
state_next = STATE_READ_HEADER;
@ -292,6 +301,8 @@ always @* begin
end
STATE_WAIT_LAST: begin
// wait for end of frame; read and discard
input_eth_payload_tready_next = 1;
if (input_eth_payload_tvalid) begin
if (input_eth_payload_tlast) begin
if (output_arp_hlen != 6 || output_arp_plen != 4) begin
@ -301,11 +312,14 @@ always @* begin
// otherwise, transfer tuser
output_frame_valid_next = ~input_eth_payload_tuser;
end
input_eth_hdr_ready_next = ~output_frame_valid_reg;
input_eth_payload_tready_next = 0;
state_next = STATE_IDLE;
end else begin
state_next = STATE_WAIT_LAST;
end
end else begin
// wait for end of frame; read and discard
state_next = STATE_WAIT_LAST;
end
end
@ -327,6 +341,9 @@ always @(posedge clk or posedge rst) begin
end else begin
state_reg <= state_next;
input_eth_hdr_ready_reg <= input_eth_hdr_ready_next;
input_eth_payload_tready_reg <= input_eth_payload_tready_next;
frame_ptr_reg <= frame_ptr_next;
output_frame_valid_reg <= output_frame_valid_next;
@ -336,25 +353,6 @@ always @(posedge clk or posedge rst) begin
busy_reg <= state_next != STATE_IDLE;
// generate valid outputs
case (state_next)
STATE_IDLE: begin
// idle; accept new data
input_eth_hdr_ready_reg <= ~output_frame_valid;
input_eth_payload_tready_reg <= 0;
end
STATE_READ_HEADER: begin
// read header; accept new data
input_eth_hdr_ready_reg <= 0;
input_eth_payload_tready_reg <= 1;
end
STATE_WAIT_LAST: begin
// wait for end of frame; read and discard
input_eth_hdr_ready_reg <= 0;
input_eth_payload_tready_reg <= 1;
end
endcase
// datapath
if (store_eth_hdr) begin
output_eth_dest_mac_reg <= input_eth_dest_mac;

View File

@ -93,9 +93,9 @@ ARP Frame
THA Target MAC 6 octets
TPA Target IP 4 octets
This module receives an Ethernet frame with decoded fields and decodes
the ARP packet format. If the Ethertype does not match, the packet is
discarded.
This module receives an Ethernet frame with header fields in parallel and
payload on an AXI stream interface, decodes the ARP packet fields, and
produces the frame fields in parallel.
*/
@ -115,8 +115,8 @@ reg store_arp_hdr_word_3;
reg [7:0] frame_ptr_reg = 0, frame_ptr_next;
reg input_eth_hdr_ready_reg = 0;
reg input_eth_payload_tready_reg = 0;
reg input_eth_hdr_ready_reg = 0, input_eth_hdr_ready_next;
reg input_eth_payload_tready_reg = 0, input_eth_payload_tready_next;
reg output_frame_valid_reg = 0, output_frame_valid_next;
reg [47:0] output_eth_dest_mac_reg = 0;
@ -160,6 +160,9 @@ assign error_invalid_header = error_invalid_header_reg;
always @* begin
state_next = 2'bz;
input_eth_hdr_ready_next = 0;
input_eth_payload_tready_next = 0;
store_eth_hdr = 0;
store_arp_hdr_word_0 = 0;
store_arp_hdr_word_1 = 0;
@ -177,9 +180,11 @@ always @* begin
STATE_IDLE: begin
// idle state - wait for data
frame_ptr_next = 0;
input_eth_hdr_ready_next = ~output_frame_valid_reg;
if (input_eth_hdr_ready & input_eth_hdr_valid) begin
frame_ptr_next = 0;
input_eth_hdr_ready_next = 0;
input_eth_payload_tready_next = 1;
store_eth_hdr = 1;
state_next = STATE_READ_HEADER;
end else begin
@ -188,6 +193,8 @@ always @* begin
end
STATE_READ_HEADER: begin
// read header state
input_eth_payload_tready_next = 1;
if (input_eth_payload_tvalid) begin
// word transfer in - store it
frame_ptr_next = frame_ptr_reg+1;
@ -202,7 +209,6 @@ always @* begin
end
endcase
if (input_eth_payload_tlast) begin
state_next = STATE_IDLE;
if (frame_ptr_reg != 8'h03 | (input_eth_payload_tkeep & 8'h0F) != 8'h0F) begin
error_header_early_termination_next = 1;
end else if (output_arp_hlen != 6 || output_arp_plen != 4) begin
@ -210,21 +216,29 @@ always @* begin
end else begin
output_frame_valid_next = ~input_eth_payload_tuser;
end
input_eth_hdr_ready_next = ~output_frame_valid_reg;
input_eth_payload_tready_next = 0;
state_next = STATE_IDLE;
end
end else begin
state_next = STATE_READ_HEADER;
end
end
STATE_WAIT_LAST: begin
// read last payload word; data in output register; do not accept new data
// wait for end of frame; read and discard
input_eth_payload_tready_next = 1;
if (input_eth_payload_tvalid) begin
// word transfer out - done
if (input_eth_payload_tlast) begin
if (output_arp_hlen != 6 || output_arp_plen != 4) begin
// lengths not valid
error_invalid_header_next = 1;
end else begin
// otherwise, transfer tuser
output_frame_valid_next = ~input_eth_payload_tuser;
end
input_eth_hdr_ready_next = ~output_frame_valid_reg;
input_eth_payload_tready_next = 0;
state_next = STATE_IDLE;
end else begin
state_next = STATE_WAIT_LAST;
@ -252,6 +266,9 @@ always @(posedge clk or posedge rst) begin
end else begin
state_reg <= state_next;
input_eth_hdr_ready_reg <= input_eth_hdr_ready_next;
input_eth_payload_tready_reg <= input_eth_payload_tready_next;
frame_ptr_reg <= frame_ptr_next;
output_frame_valid_reg <= output_frame_valid_next;
@ -261,25 +278,6 @@ always @(posedge clk or posedge rst) begin
busy_reg <= state_next != STATE_IDLE;
// generate valid outputs
case (state_next)
STATE_IDLE: begin
// idle; accept new data
input_eth_hdr_ready_reg <= ~output_frame_valid;
input_eth_payload_tready_reg <= 0;
end
STATE_READ_HEADER: begin
// read header; accept new data
input_eth_hdr_ready_reg <= 0;
input_eth_payload_tready_reg <= 1;
end
STATE_WAIT_LAST: begin
// wait for end of frame; read and discard
input_eth_hdr_ready_reg <= 0;
input_eth_payload_tready_reg <= 1;
end
endcase
// datapath
if (store_eth_hdr) begin
output_eth_dest_mac_reg <= input_eth_dest_mac;

View File

@ -88,31 +88,22 @@ ARP Frame
THA Target MAC 6 octets
TPA Target IP 4 octets
This module receives an Ethernet frame with decoded fields and decodes
the ARP packet format. If the Ethertype does not match, the packet is
discarded.
This module receives an ARP frame with header fields in parallel and
transmits the complete Ethernet payload on an AXI interface.
*/
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_WRITE_HEADER = 3'd1,
STATE_WRITE_HEADER_LAST = 3'd2;
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_WRITE_HEADER = 2'd1;
reg [2:0] state_reg = STATE_IDLE, state_next;
reg [1:0] state_reg = STATE_IDLE, state_next;
// datapath control signals
reg store_frame;
reg [7:0] write_hdr_data;
reg write_hdr_last;
reg write_hdr_out;
reg [7:0] frame_ptr_reg = 0, frame_ptr_next;
reg [47:0] output_eth_dest_mac_reg = 0;
reg [47:0] output_eth_src_mac_reg = 0;
reg [15:0] output_eth_type_reg = 0;
reg [15:0] arp_htype_reg = 0;
reg [15:0] arp_ptype_reg = 0;
reg [15:0] arp_oper_reg = 0;
@ -121,53 +112,63 @@ reg [31:0] arp_spa_reg = 0;
reg [47:0] arp_tha_reg = 0;
reg [31:0] arp_tpa_reg = 0;
reg input_frame_ready_reg = 0;
reg input_frame_ready_reg = 0, input_frame_ready_next;
reg output_eth_hdr_valid_reg = 0, output_eth_hdr_valid_next;
reg [7:0] output_eth_payload_tdata_reg = 0;
reg output_eth_payload_tvalid_reg = 0;
reg output_eth_payload_tlast_reg = 0;
reg output_eth_payload_tuser_reg = 0;
reg [47:0] output_eth_dest_mac_reg = 0;
reg [47:0] output_eth_src_mac_reg = 0;
reg [15:0] output_eth_type_reg = 0;
reg busy_reg = 0;
// internal datapath
reg [7:0] output_eth_payload_tdata_int;
reg output_eth_payload_tvalid_int;
reg output_eth_payload_tready_int = 0;
reg output_eth_payload_tlast_int;
reg output_eth_payload_tuser_int;
wire output_eth_payload_tready_int_early;
assign input_frame_ready = input_frame_ready_reg;
assign output_eth_hdr_valid = output_eth_hdr_valid_reg;
assign output_eth_dest_mac = output_eth_dest_mac_reg;
assign output_eth_src_mac = output_eth_src_mac_reg;
assign output_eth_type = output_eth_type_reg;
assign output_eth_payload_tdata = output_eth_payload_tdata_reg;
assign output_eth_payload_tvalid = output_eth_payload_tvalid_reg;
assign output_eth_payload_tlast = output_eth_payload_tlast_reg;
assign output_eth_payload_tuser = output_eth_payload_tuser_reg;
assign busy = busy_reg;
always @* begin
state_next = 2'bz;
store_frame = 0;
input_frame_ready_next = 0;
write_hdr_data = 0;
write_hdr_last = 0;
write_hdr_out = 0;
store_frame = 0;
frame_ptr_next = frame_ptr_reg;
output_eth_hdr_valid_next = output_eth_hdr_valid_reg & ~output_eth_hdr_ready;
output_eth_payload_tdata_int = 0;
output_eth_payload_tvalid_int = 0;
output_eth_payload_tlast_int = 0;
output_eth_payload_tuser_int = 0;
case (state_reg)
STATE_IDLE: begin
// idle state - wait for data
frame_ptr_next = 0;
input_frame_ready_next = ~output_eth_hdr_valid_reg;
if (input_frame_valid) begin
if (input_frame_ready & input_frame_valid) begin
store_frame = 1;
write_hdr_out = 1;
write_hdr_data = input_arp_htype[15: 8];
input_frame_ready_next = 0;
output_eth_hdr_valid_next = 1;
frame_ptr_next = 1;
if (output_eth_payload_tready_int) begin
output_eth_payload_tvalid_int = 1;
output_eth_payload_tdata_int = input_arp_htype[15: 8];
frame_ptr_next = 1;
end
state_next = STATE_WRITE_HEADER;
end else begin
state_next = STATE_IDLE;
@ -175,57 +176,49 @@ always @* begin
end
STATE_WRITE_HEADER: begin
// read header state
if (output_eth_payload_tready) begin
if (output_eth_payload_tready_int) begin
// word transfer out
frame_ptr_next = frame_ptr_reg+1;
output_eth_payload_tvalid_int = 1;
state_next = STATE_WRITE_HEADER;
write_hdr_out = 1;
case (frame_ptr_reg)
8'h01: write_hdr_data = arp_htype_reg[ 7: 0];
8'h02: write_hdr_data = arp_ptype_reg[15: 8];
8'h03: write_hdr_data = arp_ptype_reg[ 7: 0];
8'h04: write_hdr_data = 6; // hlen
8'h05: write_hdr_data = 4; // plen
8'h06: write_hdr_data = arp_oper_reg[15: 8];
8'h07: write_hdr_data = arp_oper_reg[ 7: 0];
8'h08: write_hdr_data = arp_sha_reg[47:40];
8'h09: write_hdr_data = arp_sha_reg[39:32];
8'h0A: write_hdr_data = arp_sha_reg[31:24];
8'h0B: write_hdr_data = arp_sha_reg[23:16];
8'h0C: write_hdr_data = arp_sha_reg[15: 8];
8'h0D: write_hdr_data = arp_sha_reg[ 7: 0];
8'h0E: write_hdr_data = arp_spa_reg[31:24];
8'h0F: write_hdr_data = arp_spa_reg[23:16];
8'h10: write_hdr_data = arp_spa_reg[15: 8];
8'h11: write_hdr_data = arp_spa_reg[ 7: 0];
8'h12: write_hdr_data = arp_tha_reg[47:40];
8'h13: write_hdr_data = arp_tha_reg[39:32];
8'h14: write_hdr_data = arp_tha_reg[31:24];
8'h15: write_hdr_data = arp_tha_reg[23:16];
8'h16: write_hdr_data = arp_tha_reg[15: 8];
8'h17: write_hdr_data = arp_tha_reg[ 7: 0];
8'h18: write_hdr_data = arp_tpa_reg[31:24];
8'h19: write_hdr_data = arp_tpa_reg[23:16];
8'h1A: write_hdr_data = arp_tpa_reg[15: 8];
8'h01: output_eth_payload_tdata_int = arp_htype_reg[ 7: 0];
8'h02: output_eth_payload_tdata_int = arp_ptype_reg[15: 8];
8'h03: output_eth_payload_tdata_int = arp_ptype_reg[ 7: 0];
8'h04: output_eth_payload_tdata_int = 6; // hlen
8'h05: output_eth_payload_tdata_int = 4; // plen
8'h06: output_eth_payload_tdata_int = arp_oper_reg[15: 8];
8'h07: output_eth_payload_tdata_int = arp_oper_reg[ 7: 0];
8'h08: output_eth_payload_tdata_int = arp_sha_reg[47:40];
8'h09: output_eth_payload_tdata_int = arp_sha_reg[39:32];
8'h0A: output_eth_payload_tdata_int = arp_sha_reg[31:24];
8'h0B: output_eth_payload_tdata_int = arp_sha_reg[23:16];
8'h0C: output_eth_payload_tdata_int = arp_sha_reg[15: 8];
8'h0D: output_eth_payload_tdata_int = arp_sha_reg[ 7: 0];
8'h0E: output_eth_payload_tdata_int = arp_spa_reg[31:24];
8'h0F: output_eth_payload_tdata_int = arp_spa_reg[23:16];
8'h10: output_eth_payload_tdata_int = arp_spa_reg[15: 8];
8'h11: output_eth_payload_tdata_int = arp_spa_reg[ 7: 0];
8'h12: output_eth_payload_tdata_int = arp_tha_reg[47:40];
8'h13: output_eth_payload_tdata_int = arp_tha_reg[39:32];
8'h14: output_eth_payload_tdata_int = arp_tha_reg[31:24];
8'h15: output_eth_payload_tdata_int = arp_tha_reg[23:16];
8'h16: output_eth_payload_tdata_int = arp_tha_reg[15: 8];
8'h17: output_eth_payload_tdata_int = arp_tha_reg[ 7: 0];
8'h18: output_eth_payload_tdata_int = arp_tpa_reg[31:24];
8'h19: output_eth_payload_tdata_int = arp_tpa_reg[23:16];
8'h1A: output_eth_payload_tdata_int = arp_tpa_reg[15: 8];
8'h1B: begin
write_hdr_data = arp_tpa_reg[ 7: 0];
write_hdr_last = 1;
state_next = STATE_WRITE_HEADER_LAST;
output_eth_payload_tdata_int = arp_tpa_reg[ 7: 0];
output_eth_payload_tlast_int = 1;
input_frame_ready_next = ~output_eth_hdr_valid_reg;
state_next = STATE_IDLE;
end
endcase
end else begin
state_next = STATE_WRITE_HEADER;
end
end
STATE_WRITE_HEADER_LAST: begin
// write last header word; data in output register
if (output_eth_payload_tready) begin
// word transfer out - done
state_next = STATE_IDLE;
end else begin
state_next = STATE_WRITE_HEADER_LAST;
end
end
endcase
end
@ -244,39 +237,18 @@ always @(posedge clk or posedge rst) begin
arp_spa_reg <= 0;
arp_tha_reg <= 0;
arp_tpa_reg <= 0;
output_eth_payload_tdata_reg <= 0;
output_eth_payload_tvalid_reg <= 0;
output_eth_payload_tlast_reg <= 0;
output_eth_payload_tuser_reg <= 0;
busy_reg <= 0;
end else begin
state_reg <= state_next;
frame_ptr_reg <= frame_ptr_next;
input_frame_ready_reg <= input_frame_ready_next;
output_eth_hdr_valid_reg <= output_eth_hdr_valid_next;
busy_reg <= state_next != STATE_IDLE;
// generate valid outputs
case (state_next)
STATE_IDLE: begin
// idle; accept new data
input_frame_ready_reg <= ~output_eth_hdr_valid;
output_eth_payload_tvalid_reg <= 0;
end
STATE_WRITE_HEADER: begin
// write header
input_frame_ready_reg <= 0;
output_eth_payload_tvalid_reg <= 1;
end
STATE_WRITE_HEADER_LAST: begin
// write last header word; data in output register
input_frame_ready_reg <= 0;
output_eth_payload_tvalid_reg <= 1;
end
endcase
if (store_frame) begin
output_eth_dest_mac_reg <= input_eth_dest_mac;
output_eth_src_mac_reg <= input_eth_src_mac;
@ -289,11 +261,68 @@ always @(posedge clk or posedge rst) begin
arp_tha_reg <= input_arp_tha;
arp_tpa_reg <= input_arp_tpa;
end
end
end
if (write_hdr_out) begin
output_eth_payload_tdata_reg <= write_hdr_data;
output_eth_payload_tlast_reg <= write_hdr_last;
output_eth_payload_tuser_reg <= 0;
// output datapath logic
reg [7:0] output_eth_payload_tdata_reg = 0;
reg output_eth_payload_tvalid_reg = 0;
reg output_eth_payload_tlast_reg = 0;
reg output_eth_payload_tuser_reg = 0;
reg [7:0] temp_axis_tdata_reg = 0;
reg temp_axis_tvalid_reg = 0;
reg temp_axis_tlast_reg = 0;
reg temp_axis_tuser_reg = 0;
assign output_eth_payload_tdata = output_eth_payload_tdata_reg;
assign output_eth_payload_tvalid = output_eth_payload_tvalid_reg;
assign output_eth_payload_tlast = output_eth_payload_tlast_reg;
assign output_eth_payload_tuser = output_eth_payload_tuser_reg;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle
assign output_eth_payload_tready_int_early = output_eth_payload_tready | (~temp_axis_tvalid_reg & ~output_eth_payload_tvalid_reg) | (~temp_axis_tvalid_reg & ~output_eth_payload_tvalid_int);
always @(posedge clk or posedge rst) begin
if (rst) begin
output_eth_payload_tdata_reg <= 0;
output_eth_payload_tvalid_reg <= 0;
output_eth_payload_tlast_reg <= 0;
output_eth_payload_tuser_reg <= 0;
output_eth_payload_tready_int <= 0;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end else begin
// transfer sink ready state to source
output_eth_payload_tready_int <= output_eth_payload_tready_int_early;
if (output_eth_payload_tready_int) begin
// input is ready
if (output_eth_payload_tready | ~output_eth_payload_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_eth_payload_tdata_reg <= output_eth_payload_tdata_int;
output_eth_payload_tvalid_reg <= output_eth_payload_tvalid_int;
output_eth_payload_tlast_reg <= output_eth_payload_tlast_int;
output_eth_payload_tuser_reg <= output_eth_payload_tuser_int;
end else begin
// output is not ready and currently valid, store input in temp
temp_axis_tdata_reg <= output_eth_payload_tdata_int;
temp_axis_tvalid_reg <= output_eth_payload_tvalid_int;
temp_axis_tlast_reg <= output_eth_payload_tlast_int;
temp_axis_tuser_reg <= output_eth_payload_tuser_int;
end
end else if (output_eth_payload_tready) begin
// input is not ready, but output is ready
output_eth_payload_tdata_reg <= temp_axis_tdata_reg;
output_eth_payload_tvalid_reg <= temp_axis_tvalid_reg;
output_eth_payload_tlast_reg <= temp_axis_tlast_reg;
output_eth_payload_tuser_reg <= temp_axis_tuser_reg;
temp_axis_tdata_reg <= 0;
temp_axis_tvalid_reg <= 0;
temp_axis_tlast_reg <= 0;
temp_axis_tuser_reg <= 0;
end
end
end

View File

@ -89,32 +89,22 @@ ARP Frame
THA Target MAC 6 octets
TPA Target IP 4 octets
This module receives an Ethernet frame with decoded fields and decodes
the ARP packet format. If the Ethertype does not match, the packet is
discarded.
This module receives an ARP frame with header fields in parallel and
transmits the complete Ethernet payload on an AXI interface.
*/
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_WRITE_HEADER = 3'd1,
STATE_WRITE_HEADER_LAST = 3'd2;
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_WRITE_HEADER = 2'd1;
reg [2:0] state_reg = STATE_IDLE, state_next;
reg [1:0] state_reg = STATE_IDLE, state_next;
// datapath control signals
reg store_frame;
reg [63:0] write_hdr_data;
reg [7:0] write_hdr_keep;
reg write_hdr_last;
reg write_hdr_out;
reg [7:0] frame_ptr_reg = 0, frame_ptr_next;
reg [47:0] output_eth_dest_mac_reg = 0;
reg [47:0] output_eth_src_mac_reg = 0;
reg [15:0] output_eth_type_reg = 0;
reg [15:0] arp_htype_reg = 0;
reg [15:0] arp_ptype_reg = 0;
reg [15:0] arp_oper_reg = 0;
@ -123,64 +113,72 @@ reg [31:0] arp_spa_reg = 0;
reg [47:0] arp_tha_reg = 0;
reg [31:0] arp_tpa_reg = 0;
reg input_frame_ready_reg = 0;
reg input_frame_ready_reg = 0, input_frame_ready_next;
reg output_eth_hdr_valid_reg = 0, output_eth_hdr_valid_next;
reg [63:0] output_eth_payload_tdata_reg = 0;
reg [7:0] output_eth_payload_tkeep_reg = 0;
reg output_eth_payload_tvalid_reg = 0;
reg output_eth_payload_tlast_reg = 0;
reg output_eth_payload_tuser_reg = 0;
reg [47:0] output_eth_dest_mac_reg = 0;
reg [47:0] output_eth_src_mac_reg = 0;
reg [15:0] output_eth_type_reg = 0;
reg busy_reg = 0;
// internal datapath
reg [63:0] output_eth_payload_tdata_int;
reg [7:0] output_eth_payload_tkeep_int;
reg output_eth_payload_tvalid_int;
reg output_eth_payload_tready_int = 0;
reg output_eth_payload_tlast_int;
reg output_eth_payload_tuser_int;
wire output_eth_payload_tready_int_early;
assign input_frame_ready = input_frame_ready_reg;
assign output_eth_hdr_valid = output_eth_hdr_valid_reg;
assign output_eth_dest_mac = output_eth_dest_mac_reg;
assign output_eth_src_mac = output_eth_src_mac_reg;
assign output_eth_type = output_eth_type_reg;
assign output_eth_payload_tdata = output_eth_payload_tdata_reg;
assign output_eth_payload_tkeep = output_eth_payload_tkeep_reg;
assign output_eth_payload_tvalid = output_eth_payload_tvalid_reg;
assign output_eth_payload_tlast = output_eth_payload_tlast_reg;
assign output_eth_payload_tuser = output_eth_payload_tuser_reg;
assign busy = busy_reg;
always @* begin
state_next = 2'bz;
store_frame = 0;
input_frame_ready_next = 0;
write_hdr_data = 0;
write_hdr_keep = 0;
write_hdr_last = 0;
write_hdr_out = 0;
store_frame = 0;
frame_ptr_next = frame_ptr_reg;
output_eth_hdr_valid_next = output_eth_hdr_valid_reg & ~output_eth_hdr_ready;
output_eth_payload_tdata_int = 0;
output_eth_payload_tvalid_int = 0;
output_eth_payload_tlast_int = 0;
output_eth_payload_tuser_int = 0;
case (state_reg)
STATE_IDLE: begin
// idle state - wait for data
frame_ptr_next = 0;
input_frame_ready_next = ~output_eth_hdr_valid_reg;
if (input_frame_valid) begin
if (input_frame_ready & input_frame_valid) begin
store_frame = 1;
write_hdr_out = 1;
write_hdr_data[ 7: 0] = input_arp_htype[15: 8];
write_hdr_data[15: 8] = input_arp_htype[ 7: 0];
write_hdr_data[23:16] = input_arp_ptype[15: 8];
write_hdr_data[31:24] = input_arp_ptype[ 7: 0];
write_hdr_data[39:32] = 6; // hlen
write_hdr_data[47:40] = 4; // plen
write_hdr_data[55:48] = input_arp_oper[15: 8];
write_hdr_data[63:56] = input_arp_oper[ 7: 0];
write_hdr_keep = 8'hff;
frame_ptr_next = 8;
input_frame_ready_next = 0;
output_eth_hdr_valid_next = 1;
if (output_eth_payload_tready_int) begin
output_eth_payload_tvalid_int = 1;
output_eth_payload_tdata_int[ 7: 0] = input_arp_htype[15: 8];
output_eth_payload_tdata_int[15: 8] = input_arp_htype[ 7: 0];
output_eth_payload_tdata_int[23:16] = input_arp_ptype[15: 8];
output_eth_payload_tdata_int[31:24] = input_arp_ptype[ 7: 0];
output_eth_payload_tdata_int[39:32] = 6; // hlen
output_eth_payload_tdata_int[47:40] = 4; // plen
output_eth_payload_tdata_int[55:48] = input_arp_oper[15: 8];
output_eth_payload_tdata_int[63:56] = input_arp_oper[ 7: 0];
output_eth_payload_tkeep_int = 8'hff;
frame_ptr_next = 8;
end
state_next = STATE_WRITE_HEADER;
end else begin
state_next = STATE_IDLE;
@ -188,61 +186,64 @@ always @* begin
end
STATE_WRITE_HEADER: begin
// read header state
if (output_eth_payload_tready) begin
if (output_eth_payload_tready_int) begin
// word transfer out
frame_ptr_next = frame_ptr_reg+8;
output_eth_payload_tvalid_int = 1;
state_next = STATE_WRITE_HEADER;
write_hdr_out = 1;
case (frame_ptr_reg)
8'h00: begin
output_eth_payload_tdata_int[ 7: 0] = input_arp_htype[15: 8];
output_eth_payload_tdata_int[15: 8] = input_arp_htype[ 7: 0];
output_eth_payload_tdata_int[23:16] = input_arp_ptype[15: 8];
output_eth_payload_tdata_int[31:24] = input_arp_ptype[ 7: 0];
output_eth_payload_tdata_int[39:32] = 6; // hlen
output_eth_payload_tdata_int[47:40] = 4; // plen
output_eth_payload_tdata_int[55:48] = input_arp_oper[15: 8];
output_eth_payload_tdata_int[63:56] = input_arp_oper[ 7: 0];
output_eth_payload_tkeep_int = 8'hff;
end
8'h08: begin
write_hdr_data[ 7: 0] = arp_sha_reg[47:40];
write_hdr_data[15: 8] = arp_sha_reg[39:32];
write_hdr_data[23:16] = arp_sha_reg[31:24];
write_hdr_data[31:24] = arp_sha_reg[23:16];
write_hdr_data[39:32] = arp_sha_reg[15: 8];
write_hdr_data[47:40] = arp_sha_reg[ 7: 0];
write_hdr_data[55:48] = arp_spa_reg[31:24];
write_hdr_data[63:56] = arp_spa_reg[23:16];
write_hdr_keep = 8'hff;
output_eth_payload_tdata_int[ 7: 0] = arp_sha_reg[47:40];
output_eth_payload_tdata_int[15: 8] = arp_sha_reg[39:32];
output_eth_payload_tdata_int[23:16] = arp_sha_reg[31:24];
output_eth_payload_tdata_int[31:24] = arp_sha_reg[23:16];
output_eth_payload_tdata_int[39:32] = arp_sha_reg[15: 8];
output_eth_payload_tdata_int[47:40] = arp_sha_reg[ 7: 0];
output_eth_payload_tdata_int[55:48] = arp_spa_reg[31:24];
output_eth_payload_tdata_int[63:56] = arp_spa_reg[23:16];
output_eth_payload_tkeep_int = 8'hff;
end
8'h10: begin
write_hdr_data[ 7: 0] = arp_spa_reg[15: 8];
write_hdr_data[15: 8] = arp_spa_reg[ 7: 0];
write_hdr_data[23:16] = arp_tha_reg[47:40];
write_hdr_data[31:24] = arp_tha_reg[39:32];
write_hdr_data[39:32] = arp_tha_reg[31:24];
write_hdr_data[47:40] = arp_tha_reg[23:16];
write_hdr_data[55:48] = arp_tha_reg[15: 8];
write_hdr_data[63:56] = arp_tha_reg[ 7: 0];
write_hdr_keep = 8'hff;
output_eth_payload_tdata_int[ 7: 0] = arp_spa_reg[15: 8];
output_eth_payload_tdata_int[15: 8] = arp_spa_reg[ 7: 0];
output_eth_payload_tdata_int[23:16] = arp_tha_reg[47:40];
output_eth_payload_tdata_int[31:24] = arp_tha_reg[39:32];
output_eth_payload_tdata_int[39:32] = arp_tha_reg[31:24];
output_eth_payload_tdata_int[47:40] = arp_tha_reg[23:16];
output_eth_payload_tdata_int[55:48] = arp_tha_reg[15: 8];
output_eth_payload_tdata_int[63:56] = arp_tha_reg[ 7: 0];
output_eth_payload_tkeep_int = 8'hff;
end
8'h18: begin
write_hdr_data[ 7: 0] = arp_tpa_reg[31:24];
write_hdr_data[15: 8] = arp_tpa_reg[23:16];
write_hdr_data[23:16] = arp_tpa_reg[15: 8];
write_hdr_data[31:24] = arp_tpa_reg[ 7: 0];
write_hdr_data[39:32] = 0;
write_hdr_data[47:40] = 0;
write_hdr_data[55:48] = 0;
write_hdr_data[63:56] = 0;
write_hdr_keep = 8'h0f;
write_hdr_last = 1;
state_next = STATE_WRITE_HEADER_LAST;
output_eth_payload_tdata_int[ 7: 0] = arp_tpa_reg[31:24];
output_eth_payload_tdata_int[15: 8] = arp_tpa_reg[23:16];
output_eth_payload_tdata_int[23:16] = arp_tpa_reg[15: 8];
output_eth_payload_tdata_int[31:24] = arp_tpa_reg[ 7: 0];
output_eth_payload_tdata_int[39:32] = 0;
output_eth_payload_tdata_int[47:40] = 0;
output_eth_payload_tdata_int[55:48] = 0;
output_eth_payload_tdata_int[63:56] = 0;
output_eth_payload_tkeep_int = 8'h0f;
output_eth_payload_tlast_int = 1;
input_frame_ready_next = ~output_eth_hdr_valid_reg;
state_next = STATE_IDLE;
end
endcase
end else begin
state_next = STATE_WRITE_HEADER;
end
end
STATE_WRITE_HEADER_LAST: begin
// write last header word; data in output register
if (output_eth_payload_tready) begin
// word transfer out - done
state_next = STATE_IDLE;
end else begin
state_next = STATE_WRITE_HEADER_LAST;
end
end
endcase
end
@ -261,40 +262,18 @@ always @(posedge clk or posedge rst) begin
arp_spa_reg <= 0;
arp_tha_reg <= 0;
arp_tpa_reg <= 0;
output_eth_payload_tdata_reg <= 0;
output_eth_payload_tkeep_reg <= 0;
output_eth_payload_tvalid_reg <= 0;
output_eth_payload_tlast_reg <= 0;
output_eth_payload_tuser_reg <= 0;
busy_reg <= 0;
end else begin
state_reg <= state_next;
frame_ptr_reg <= frame_ptr_next;
input_frame_ready_reg <= input_frame_ready_next;
output_eth_hdr_valid_reg <= output_eth_hdr_valid_next;
busy_reg <= state_next != STATE_IDLE;
// generate valid outputs
case (state_next)
STATE_IDLE: begin
// idle; accept new data
input_frame_ready_reg <= ~output_eth_hdr_valid;
output_eth_payload_tvalid_reg <= 0;
end
STATE_WRITE_HEADER: begin
// write header
input_frame_ready_reg <= 0;
output_eth_payload_tvalid_reg <= 1;
end
STATE_WRITE_HEADER_LAST: begin
// write last header word; data in output register
input_frame_ready_reg <= 0;
output_eth_payload_tvalid_reg <= 1;
end
endcase
if (store_frame) begin
output_eth_dest_mac_reg <= input_eth_dest_mac;
output_eth_src_mac_reg <= input_eth_src_mac;
@ -307,12 +286,77 @@ always @(posedge clk or posedge rst) begin
arp_tha_reg <= input_arp_tha;
arp_tpa_reg <= input_arp_tpa;
end
end
end
if (write_hdr_out) begin
output_eth_payload_tdata_reg <= write_hdr_data;
output_eth_payload_tkeep_reg <= write_hdr_keep;
output_eth_payload_tlast_reg <= write_hdr_last;
output_eth_payload_tuser_reg <= 0;
// output datapath logic
reg [63:0] output_eth_payload_tdata_reg = 0;
reg [7:0] output_eth_payload_tkeep_reg = 0;
reg output_eth_payload_tvalid_reg = 0;
reg output_eth_payload_tlast_reg = 0;
reg output_eth_payload_tuser_reg = 0;
reg [63:0] temp_eth_payload_tdata_reg = 0;
reg [7:0] temp_eth_payload_tkeep_reg = 0;
reg temp_eth_payload_tvalid_reg = 0;
reg temp_eth_payload_tlast_reg = 0;
reg temp_eth_payload_tuser_reg = 0;
// enable ready input next cycle if output is ready or if there is space in both output registers or if there is space in the temp register that will not be filled next cycle
assign output_eth_payload_tready_int_early = output_eth_payload_tready | (~temp_eth_payload_tvalid_reg & ~output_eth_payload_tvalid_reg) | (~temp_eth_payload_tvalid_reg & ~output_eth_payload_tvalid_int);
assign output_eth_payload_tdata = output_eth_payload_tdata_reg;
assign output_eth_payload_tkeep = output_eth_payload_tkeep_reg;
assign output_eth_payload_tvalid = output_eth_payload_tvalid_reg;
assign output_eth_payload_tlast = output_eth_payload_tlast_reg;
assign output_eth_payload_tuser = output_eth_payload_tuser_reg;
always @(posedge clk or posedge rst) begin
if (rst) begin
output_eth_payload_tdata_reg <= 0;
output_eth_payload_tkeep_reg <= 0;
output_eth_payload_tvalid_reg <= 0;
output_eth_payload_tlast_reg <= 0;
output_eth_payload_tuser_reg <= 0;
output_eth_payload_tready_int <= 0;
temp_eth_payload_tdata_reg <= 0;
temp_eth_payload_tkeep_reg <= 0;
temp_eth_payload_tvalid_reg <= 0;
temp_eth_payload_tlast_reg <= 0;
temp_eth_payload_tuser_reg <= 0;
end else begin
// transfer sink ready state to source
output_eth_payload_tready_int <= output_eth_payload_tready_int_early;
if (output_eth_payload_tready_int) begin
// input is ready
if (output_eth_payload_tready | ~output_eth_payload_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
output_eth_payload_tdata_reg <= output_eth_payload_tdata_int;
output_eth_payload_tkeep_reg <= output_eth_payload_tkeep_int;
output_eth_payload_tvalid_reg <= output_eth_payload_tvalid_int;
output_eth_payload_tlast_reg <= output_eth_payload_tlast_int;
output_eth_payload_tuser_reg <= output_eth_payload_tuser_int;
end else begin
// output is not ready and currently valid, store input in temp
temp_eth_payload_tdata_reg <= output_eth_payload_tdata_int;
temp_eth_payload_tkeep_reg <= output_eth_payload_tkeep_int;
temp_eth_payload_tvalid_reg <= output_eth_payload_tvalid_int;
temp_eth_payload_tlast_reg <= output_eth_payload_tlast_int;
temp_eth_payload_tuser_reg <= output_eth_payload_tuser_int;
end
end else if (output_eth_payload_tready) begin
// input is not ready, but output is ready
output_eth_payload_tdata_reg <= temp_eth_payload_tdata_reg;
output_eth_payload_tkeep_reg <= temp_eth_payload_tkeep_reg;
output_eth_payload_tvalid_reg <= temp_eth_payload_tvalid_reg;
output_eth_payload_tlast_reg <= temp_eth_payload_tlast_reg;
output_eth_payload_tuser_reg <= temp_eth_payload_tuser_reg;
temp_eth_payload_tdata_reg <= 0;
temp_eth_payload_tkeep_reg <= 0;
temp_eth_payload_tvalid_reg <= 0;
temp_eth_payload_tlast_reg <= 0;
temp_eth_payload_tuser_reg <= 0;
end
end
end