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

View File

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

View File

@ -88,31 +88,22 @@ ARP Frame
THA Target MAC 6 octets THA Target MAC 6 octets
TPA Target IP 4 octets TPA Target IP 4 octets
This module receives an Ethernet frame with decoded fields and decodes This module receives an ARP frame with header fields in parallel and
the ARP packet format. If the Ethertype does not match, the packet is transmits the complete Ethernet payload on an AXI interface.
discarded.
*/ */
localparam [2:0] localparam [1:0]
STATE_IDLE = 3'd0, STATE_IDLE = 2'd0,
STATE_WRITE_HEADER = 3'd1, STATE_WRITE_HEADER = 2'd1;
STATE_WRITE_HEADER_LAST = 3'd2;
reg [2:0] state_reg = STATE_IDLE, state_next; reg [1:0] state_reg = STATE_IDLE, state_next;
// datapath control signals // datapath control signals
reg store_frame; 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 [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_htype_reg = 0;
reg [15:0] arp_ptype_reg = 0; reg [15:0] arp_ptype_reg = 0;
reg [15:0] arp_oper_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 [47:0] arp_tha_reg = 0;
reg [31:0] arp_tpa_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 output_eth_hdr_valid_reg = 0, output_eth_hdr_valid_next;
reg [7:0] output_eth_payload_tdata_reg = 0; reg [47:0] output_eth_dest_mac_reg = 0;
reg output_eth_payload_tvalid_reg = 0; reg [47:0] output_eth_src_mac_reg = 0;
reg output_eth_payload_tlast_reg = 0; reg [15:0] output_eth_type_reg = 0;
reg output_eth_payload_tuser_reg = 0;
reg busy_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 input_frame_ready = input_frame_ready_reg;
assign output_eth_hdr_valid = output_eth_hdr_valid_reg; assign output_eth_hdr_valid = output_eth_hdr_valid_reg;
assign output_eth_dest_mac = output_eth_dest_mac_reg; assign output_eth_dest_mac = output_eth_dest_mac_reg;
assign output_eth_src_mac = output_eth_src_mac_reg; assign output_eth_src_mac = output_eth_src_mac_reg;
assign output_eth_type = output_eth_type_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; assign busy = busy_reg;
always @* begin always @* begin
state_next = 2'bz; state_next = 2'bz;
store_frame = 0; input_frame_ready_next = 0;
write_hdr_data = 0; store_frame = 0;
write_hdr_last = 0;
write_hdr_out = 0;
frame_ptr_next = frame_ptr_reg; frame_ptr_next = frame_ptr_reg;
output_eth_hdr_valid_next = output_eth_hdr_valid_reg & ~output_eth_hdr_ready; 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) case (state_reg)
STATE_IDLE: begin STATE_IDLE: begin
// idle state - wait for data // idle state - wait for data
frame_ptr_next = 0; 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; store_frame = 1;
write_hdr_out = 1; input_frame_ready_next = 0;
write_hdr_data = input_arp_htype[15: 8];
output_eth_hdr_valid_next = 1; 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; state_next = STATE_WRITE_HEADER;
end else begin end else begin
state_next = STATE_IDLE; state_next = STATE_IDLE;
@ -175,57 +176,49 @@ always @* begin
end end
STATE_WRITE_HEADER: begin STATE_WRITE_HEADER: begin
// read header state // read header state
if (output_eth_payload_tready) begin if (output_eth_payload_tready_int) begin
// word transfer out // word transfer out
frame_ptr_next = frame_ptr_reg+1; frame_ptr_next = frame_ptr_reg+1;
output_eth_payload_tvalid_int = 1;
state_next = STATE_WRITE_HEADER; state_next = STATE_WRITE_HEADER;
write_hdr_out = 1;
case (frame_ptr_reg) case (frame_ptr_reg)
8'h01: write_hdr_data = arp_htype_reg[ 7: 0]; 8'h01: output_eth_payload_tdata_int = arp_htype_reg[ 7: 0];
8'h02: write_hdr_data = arp_ptype_reg[15: 8]; 8'h02: output_eth_payload_tdata_int = arp_ptype_reg[15: 8];
8'h03: write_hdr_data = arp_ptype_reg[ 7: 0]; 8'h03: output_eth_payload_tdata_int = arp_ptype_reg[ 7: 0];
8'h04: write_hdr_data = 6; // hlen 8'h04: output_eth_payload_tdata_int = 6; // hlen
8'h05: write_hdr_data = 4; // plen 8'h05: output_eth_payload_tdata_int = 4; // plen
8'h06: write_hdr_data = arp_oper_reg[15: 8]; 8'h06: output_eth_payload_tdata_int = arp_oper_reg[15: 8];
8'h07: write_hdr_data = arp_oper_reg[ 7: 0]; 8'h07: output_eth_payload_tdata_int = arp_oper_reg[ 7: 0];
8'h08: write_hdr_data = arp_sha_reg[47:40]; 8'h08: output_eth_payload_tdata_int = arp_sha_reg[47:40];
8'h09: write_hdr_data = arp_sha_reg[39:32]; 8'h09: output_eth_payload_tdata_int = arp_sha_reg[39:32];
8'h0A: write_hdr_data = arp_sha_reg[31:24]; 8'h0A: output_eth_payload_tdata_int = arp_sha_reg[31:24];
8'h0B: write_hdr_data = arp_sha_reg[23:16]; 8'h0B: output_eth_payload_tdata_int = arp_sha_reg[23:16];
8'h0C: write_hdr_data = arp_sha_reg[15: 8]; 8'h0C: output_eth_payload_tdata_int = arp_sha_reg[15: 8];
8'h0D: write_hdr_data = arp_sha_reg[ 7: 0]; 8'h0D: output_eth_payload_tdata_int = arp_sha_reg[ 7: 0];
8'h0E: write_hdr_data = arp_spa_reg[31:24]; 8'h0E: output_eth_payload_tdata_int = arp_spa_reg[31:24];
8'h0F: write_hdr_data = arp_spa_reg[23:16]; 8'h0F: output_eth_payload_tdata_int = arp_spa_reg[23:16];
8'h10: write_hdr_data = arp_spa_reg[15: 8]; 8'h10: output_eth_payload_tdata_int = arp_spa_reg[15: 8];
8'h11: write_hdr_data = arp_spa_reg[ 7: 0]; 8'h11: output_eth_payload_tdata_int = arp_spa_reg[ 7: 0];
8'h12: write_hdr_data = arp_tha_reg[47:40]; 8'h12: output_eth_payload_tdata_int = arp_tha_reg[47:40];
8'h13: write_hdr_data = arp_tha_reg[39:32]; 8'h13: output_eth_payload_tdata_int = arp_tha_reg[39:32];
8'h14: write_hdr_data = arp_tha_reg[31:24]; 8'h14: output_eth_payload_tdata_int = arp_tha_reg[31:24];
8'h15: write_hdr_data = arp_tha_reg[23:16]; 8'h15: output_eth_payload_tdata_int = arp_tha_reg[23:16];
8'h16: write_hdr_data = arp_tha_reg[15: 8]; 8'h16: output_eth_payload_tdata_int = arp_tha_reg[15: 8];
8'h17: write_hdr_data = arp_tha_reg[ 7: 0]; 8'h17: output_eth_payload_tdata_int = arp_tha_reg[ 7: 0];
8'h18: write_hdr_data = arp_tpa_reg[31:24]; 8'h18: output_eth_payload_tdata_int = arp_tpa_reg[31:24];
8'h19: write_hdr_data = arp_tpa_reg[23:16]; 8'h19: output_eth_payload_tdata_int = arp_tpa_reg[23:16];
8'h1A: write_hdr_data = arp_tpa_reg[15: 8]; 8'h1A: output_eth_payload_tdata_int = arp_tpa_reg[15: 8];
8'h1B: begin 8'h1B: begin
write_hdr_data = arp_tpa_reg[ 7: 0]; output_eth_payload_tdata_int = arp_tpa_reg[ 7: 0];
write_hdr_last = 1; output_eth_payload_tlast_int = 1;
state_next = STATE_WRITE_HEADER_LAST; input_frame_ready_next = ~output_eth_hdr_valid_reg;
state_next = STATE_IDLE;
end end
endcase endcase
end else begin end else begin
state_next = STATE_WRITE_HEADER; state_next = STATE_WRITE_HEADER;
end end
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 endcase
end end
@ -244,39 +237,18 @@ always @(posedge clk or posedge rst) begin
arp_spa_reg <= 0; arp_spa_reg <= 0;
arp_tha_reg <= 0; arp_tha_reg <= 0;
arp_tpa_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; busy_reg <= 0;
end else begin end else begin
state_reg <= state_next; state_reg <= state_next;
frame_ptr_reg <= frame_ptr_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; output_eth_hdr_valid_reg <= output_eth_hdr_valid_next;
busy_reg <= state_next != STATE_IDLE; 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 if (store_frame) begin
output_eth_dest_mac_reg <= input_eth_dest_mac; output_eth_dest_mac_reg <= input_eth_dest_mac;
output_eth_src_mac_reg <= input_eth_src_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_tha_reg <= input_arp_tha;
arp_tpa_reg <= input_arp_tpa; arp_tpa_reg <= input_arp_tpa;
end end
end
end
if (write_hdr_out) begin // output datapath logic
output_eth_payload_tdata_reg <= write_hdr_data; reg [7:0] output_eth_payload_tdata_reg = 0;
output_eth_payload_tlast_reg <= write_hdr_last; reg output_eth_payload_tvalid_reg = 0;
output_eth_payload_tuser_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 end
end end

View File

@ -89,32 +89,22 @@ ARP Frame
THA Target MAC 6 octets THA Target MAC 6 octets
TPA Target IP 4 octets TPA Target IP 4 octets
This module receives an Ethernet frame with decoded fields and decodes This module receives an ARP frame with header fields in parallel and
the ARP packet format. If the Ethertype does not match, the packet is transmits the complete Ethernet payload on an AXI interface.
discarded.
*/ */
localparam [2:0] localparam [1:0]
STATE_IDLE = 3'd0, STATE_IDLE = 2'd0,
STATE_WRITE_HEADER = 3'd1, STATE_WRITE_HEADER = 2'd1;
STATE_WRITE_HEADER_LAST = 3'd2;
reg [2:0] state_reg = STATE_IDLE, state_next; reg [1:0] state_reg = STATE_IDLE, state_next;
// datapath control signals // datapath control signals
reg store_frame; 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 [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_htype_reg = 0;
reg [15:0] arp_ptype_reg = 0; reg [15:0] arp_ptype_reg = 0;
reg [15:0] arp_oper_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 [47:0] arp_tha_reg = 0;
reg [31:0] arp_tpa_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 output_eth_hdr_valid_reg = 0, output_eth_hdr_valid_next;
reg [63:0] output_eth_payload_tdata_reg = 0; reg [47:0] output_eth_dest_mac_reg = 0;
reg [7:0] output_eth_payload_tkeep_reg = 0; reg [47:0] output_eth_src_mac_reg = 0;
reg output_eth_payload_tvalid_reg = 0; reg [15:0] output_eth_type_reg = 0;
reg output_eth_payload_tlast_reg = 0;
reg output_eth_payload_tuser_reg = 0;
reg busy_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 input_frame_ready = input_frame_ready_reg;
assign output_eth_hdr_valid = output_eth_hdr_valid_reg; assign output_eth_hdr_valid = output_eth_hdr_valid_reg;
assign output_eth_dest_mac = output_eth_dest_mac_reg; assign output_eth_dest_mac = output_eth_dest_mac_reg;
assign output_eth_src_mac = output_eth_src_mac_reg; assign output_eth_src_mac = output_eth_src_mac_reg;
assign output_eth_type = output_eth_type_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; assign busy = busy_reg;
always @* begin always @* begin
state_next = 2'bz; state_next = 2'bz;
store_frame = 0; input_frame_ready_next = 0;
write_hdr_data = 0; store_frame = 0;
write_hdr_keep = 0;
write_hdr_last = 0;
write_hdr_out = 0;
frame_ptr_next = frame_ptr_reg; frame_ptr_next = frame_ptr_reg;
output_eth_hdr_valid_next = output_eth_hdr_valid_reg & ~output_eth_hdr_ready; 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) case (state_reg)
STATE_IDLE: begin STATE_IDLE: begin
// idle state - wait for data // idle state - wait for data
frame_ptr_next = 0; 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; store_frame = 1;
write_hdr_out = 1; input_frame_ready_next = 0;
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;
output_eth_hdr_valid_next = 1; 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; state_next = STATE_WRITE_HEADER;
end else begin end else begin
state_next = STATE_IDLE; state_next = STATE_IDLE;
@ -188,61 +186,64 @@ always @* begin
end end
STATE_WRITE_HEADER: begin STATE_WRITE_HEADER: begin
// read header state // read header state
if (output_eth_payload_tready) begin if (output_eth_payload_tready_int) begin
// word transfer out // word transfer out
frame_ptr_next = frame_ptr_reg+8; frame_ptr_next = frame_ptr_reg+8;
output_eth_payload_tvalid_int = 1;
state_next = STATE_WRITE_HEADER; state_next = STATE_WRITE_HEADER;
write_hdr_out = 1;
case (frame_ptr_reg) 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 8'h08: begin
write_hdr_data[ 7: 0] = arp_sha_reg[47:40]; output_eth_payload_tdata_int[ 7: 0] = arp_sha_reg[47:40];
write_hdr_data[15: 8] = arp_sha_reg[39:32]; output_eth_payload_tdata_int[15: 8] = arp_sha_reg[39:32];
write_hdr_data[23:16] = arp_sha_reg[31:24]; output_eth_payload_tdata_int[23:16] = arp_sha_reg[31:24];
write_hdr_data[31:24] = arp_sha_reg[23:16]; output_eth_payload_tdata_int[31:24] = arp_sha_reg[23:16];
write_hdr_data[39:32] = arp_sha_reg[15: 8]; output_eth_payload_tdata_int[39:32] = arp_sha_reg[15: 8];
write_hdr_data[47:40] = arp_sha_reg[ 7: 0]; output_eth_payload_tdata_int[47:40] = arp_sha_reg[ 7: 0];
write_hdr_data[55:48] = arp_spa_reg[31:24]; output_eth_payload_tdata_int[55:48] = arp_spa_reg[31:24];
write_hdr_data[63:56] = arp_spa_reg[23:16]; output_eth_payload_tdata_int[63:56] = arp_spa_reg[23:16];
write_hdr_keep = 8'hff; output_eth_payload_tkeep_int = 8'hff;
end end
8'h10: begin 8'h10: begin
write_hdr_data[ 7: 0] = arp_spa_reg[15: 8]; output_eth_payload_tdata_int[ 7: 0] = arp_spa_reg[15: 8];
write_hdr_data[15: 8] = arp_spa_reg[ 7: 0]; output_eth_payload_tdata_int[15: 8] = arp_spa_reg[ 7: 0];
write_hdr_data[23:16] = arp_tha_reg[47:40]; output_eth_payload_tdata_int[23:16] = arp_tha_reg[47:40];
write_hdr_data[31:24] = arp_tha_reg[39:32]; output_eth_payload_tdata_int[31:24] = arp_tha_reg[39:32];
write_hdr_data[39:32] = arp_tha_reg[31:24]; output_eth_payload_tdata_int[39:32] = arp_tha_reg[31:24];
write_hdr_data[47:40] = arp_tha_reg[23:16]; output_eth_payload_tdata_int[47:40] = arp_tha_reg[23:16];
write_hdr_data[55:48] = arp_tha_reg[15: 8]; output_eth_payload_tdata_int[55:48] = arp_tha_reg[15: 8];
write_hdr_data[63:56] = arp_tha_reg[ 7: 0]; output_eth_payload_tdata_int[63:56] = arp_tha_reg[ 7: 0];
write_hdr_keep = 8'hff; output_eth_payload_tkeep_int = 8'hff;
end end
8'h18: begin 8'h18: begin
write_hdr_data[ 7: 0] = arp_tpa_reg[31:24]; output_eth_payload_tdata_int[ 7: 0] = arp_tpa_reg[31:24];
write_hdr_data[15: 8] = arp_tpa_reg[23:16]; output_eth_payload_tdata_int[15: 8] = arp_tpa_reg[23:16];
write_hdr_data[23:16] = arp_tpa_reg[15: 8]; output_eth_payload_tdata_int[23:16] = arp_tpa_reg[15: 8];
write_hdr_data[31:24] = arp_tpa_reg[ 7: 0]; output_eth_payload_tdata_int[31:24] = arp_tpa_reg[ 7: 0];
write_hdr_data[39:32] = 0; output_eth_payload_tdata_int[39:32] = 0;
write_hdr_data[47:40] = 0; output_eth_payload_tdata_int[47:40] = 0;
write_hdr_data[55:48] = 0; output_eth_payload_tdata_int[55:48] = 0;
write_hdr_data[63:56] = 0; output_eth_payload_tdata_int[63:56] = 0;
write_hdr_keep = 8'h0f; output_eth_payload_tkeep_int = 8'h0f;
write_hdr_last = 1; output_eth_payload_tlast_int = 1;
state_next = STATE_WRITE_HEADER_LAST; input_frame_ready_next = ~output_eth_hdr_valid_reg;
state_next = STATE_IDLE;
end end
endcase endcase
end else begin end else begin
state_next = STATE_WRITE_HEADER; state_next = STATE_WRITE_HEADER;
end end
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 endcase
end end
@ -261,40 +262,18 @@ always @(posedge clk or posedge rst) begin
arp_spa_reg <= 0; arp_spa_reg <= 0;
arp_tha_reg <= 0; arp_tha_reg <= 0;
arp_tpa_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; busy_reg <= 0;
end else begin end else begin
state_reg <= state_next; state_reg <= state_next;
frame_ptr_reg <= frame_ptr_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; output_eth_hdr_valid_reg <= output_eth_hdr_valid_next;
busy_reg <= state_next != STATE_IDLE; 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 if (store_frame) begin
output_eth_dest_mac_reg <= input_eth_dest_mac; output_eth_dest_mac_reg <= input_eth_dest_mac;
output_eth_src_mac_reg <= input_eth_src_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_tha_reg <= input_arp_tha;
arp_tpa_reg <= input_arp_tpa; arp_tpa_reg <= input_arp_tpa;
end end
end
end
if (write_hdr_out) begin // output datapath logic
output_eth_payload_tdata_reg <= write_hdr_data; reg [63:0] output_eth_payload_tdata_reg = 0;
output_eth_payload_tkeep_reg <= write_hdr_keep; reg [7:0] output_eth_payload_tkeep_reg = 0;
output_eth_payload_tlast_reg <= write_hdr_last; reg output_eth_payload_tvalid_reg = 0;
output_eth_payload_tuser_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 end
end end