mirror of
https://github.com/corundum/corundum.git
synced 2025-01-30 08:32:52 +08:00
Rework ARP subsystem
This commit is contained in:
parent
25d1b373cc
commit
5b7646ccda
255
rtl/arp.v
255
rtl/arp.v
@ -30,7 +30,7 @@ THE SOFTWARE.
|
||||
* ARP block for IPv4, ethernet frame interface
|
||||
*/
|
||||
module arp #(
|
||||
parameter CACHE_ADDR_WIDTH = 2,
|
||||
parameter CACHE_ADDR_WIDTH = 9,
|
||||
parameter REQUEST_RETRY_COUNT = 4,
|
||||
parameter REQUEST_RETRY_INTERVAL = 125000000*2,
|
||||
parameter REQUEST_TIMEOUT = 125000000*30
|
||||
@ -71,8 +71,10 @@ module arp #(
|
||||
* ARP requests
|
||||
*/
|
||||
input wire arp_request_valid,
|
||||
output wire arp_request_ready,
|
||||
input wire [31:0] arp_request_ip,
|
||||
output wire arp_response_valid,
|
||||
input wire arp_response_ready,
|
||||
output wire arp_response_error,
|
||||
output wire [47:0] arp_response_mac,
|
||||
|
||||
@ -93,7 +95,7 @@ localparam [15:0]
|
||||
ARP_OPER_INARP_REPLY = 16'h0009;
|
||||
|
||||
wire incoming_frame_valid;
|
||||
wire incoming_frame_ready;
|
||||
reg incoming_frame_ready;
|
||||
wire [47:0] incoming_eth_dest_mac;
|
||||
wire [47:0] incoming_eth_src_mac;
|
||||
wire [15:0] incoming_eth_type;
|
||||
@ -107,19 +109,6 @@ wire [31:0] incoming_arp_spa;
|
||||
wire [47:0] incoming_arp_tha;
|
||||
wire [31:0] incoming_arp_tpa;
|
||||
|
||||
reg outgoing_frame_valid_reg = 1'b0, outgoing_frame_valid_next;
|
||||
wire outgoing_frame_ready;
|
||||
reg [47:0] outgoing_eth_dest_mac_reg = 48'd0, outgoing_eth_dest_mac_next;
|
||||
reg [15:0] outgoing_arp_oper_reg = 16'd0, outgoing_arp_oper_next;
|
||||
reg [47:0] outgoing_arp_tha_reg = 48'd0, outgoing_arp_tha_next;
|
||||
reg [31:0] outgoing_arp_tpa_reg = 32'd0, outgoing_arp_tpa_next;
|
||||
|
||||
// drop frame
|
||||
reg drop_incoming_frame_reg = 1'b0, drop_incoming_frame_next;
|
||||
|
||||
// wait on incoming frames until we can reply
|
||||
assign incoming_frame_ready = outgoing_frame_ready | drop_incoming_frame_reg;
|
||||
|
||||
/*
|
||||
* ARP frame processing
|
||||
*/
|
||||
@ -159,6 +148,13 @@ arp_eth_rx_inst (
|
||||
.error_invalid_header()
|
||||
);
|
||||
|
||||
reg outgoing_frame_valid_reg = 1'b0, outgoing_frame_valid_next;
|
||||
wire outgoing_frame_ready;
|
||||
reg [47:0] outgoing_eth_dest_mac_reg = 48'd0, outgoing_eth_dest_mac_next;
|
||||
reg [15:0] outgoing_arp_oper_reg = 16'd0, outgoing_arp_oper_next;
|
||||
reg [47:0] outgoing_arp_tha_reg = 48'd0, outgoing_arp_tha_next;
|
||||
reg [31:0] outgoing_arp_tpa_reg = 32'd0, outgoing_arp_tpa_next;
|
||||
|
||||
arp_eth_tx
|
||||
arp_eth_tx_inst (
|
||||
.clk(clk),
|
||||
@ -191,27 +187,8 @@ arp_eth_tx_inst (
|
||||
.busy()
|
||||
);
|
||||
|
||||
wire incoming_eth_type_valid = (incoming_eth_type == 16'h0806);
|
||||
wire incoming_arp_htype_valid = (incoming_arp_htype == 16'h0001);
|
||||
wire incoming_arp_ptype_valid = (incoming_arp_ptype == 16'h0800);
|
||||
|
||||
wire incoming_arp_oper_arp_request = (incoming_arp_oper == ARP_OPER_ARP_REQUEST);
|
||||
wire incoming_arp_oper_arp_reply = (incoming_arp_oper == ARP_OPER_ARP_REPLY);
|
||||
wire incoming_arp_oper_inarp_request = (incoming_arp_oper == ARP_OPER_INARP_REQUEST);
|
||||
wire incoming_arp_oper_inarp_reply = (incoming_arp_oper == ARP_OPER_INARP_REPLY);
|
||||
|
||||
wire filtered_incoming_frame_valid = incoming_frame_valid &
|
||||
incoming_eth_type_valid &
|
||||
incoming_arp_htype_valid &
|
||||
incoming_arp_ptype_valid;
|
||||
|
||||
wire filtered_incoming_arp_oper_arp_request = filtered_incoming_frame_valid & incoming_arp_oper_arp_request;
|
||||
wire filtered_incoming_arp_oper_arp_reply = filtered_incoming_frame_valid & incoming_arp_oper_arp_reply;
|
||||
wire filtered_incoming_arp_oper_inarp_request = filtered_incoming_frame_valid & incoming_arp_oper_inarp_request;
|
||||
wire filtered_incoming_arp_oper_inarp_reply = filtered_incoming_frame_valid & incoming_arp_oper_inarp_reply;
|
||||
|
||||
wire cache_query_request_valid;
|
||||
wire [31:0] cache_query_request_ip;
|
||||
reg cache_query_request_valid_reg = 1'b0, cache_query_request_valid_next;
|
||||
reg [31:0] cache_query_request_ip_reg = 32'd0, cache_query_request_ip_next;
|
||||
wire cache_query_response_valid;
|
||||
wire cache_query_response_error;
|
||||
wire [47:0] cache_query_response_mac;
|
||||
@ -219,8 +196,6 @@ wire [47:0] cache_query_response_mac;
|
||||
reg cache_write_request_valid_reg = 1'b0, cache_write_request_valid_next;
|
||||
reg [31:0] cache_write_request_ip_reg = 32'd0, cache_write_request_ip_next;
|
||||
reg [47:0] cache_write_request_mac_reg = 48'd0, cache_write_request_mac_next;
|
||||
wire cache_write_in_progress;
|
||||
wire cache_write_complete;
|
||||
|
||||
/*
|
||||
* ARP cache
|
||||
@ -232,134 +207,109 @@ arp_cache_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
// Query cache
|
||||
.query_request_valid(cache_query_request_valid),
|
||||
.query_request_ip(cache_query_request_ip),
|
||||
.query_request_valid(cache_query_request_valid_reg),
|
||||
.query_request_ready(),
|
||||
.query_request_ip(cache_query_request_ip_reg),
|
||||
.query_response_valid(cache_query_response_valid),
|
||||
.query_response_ready(1'b1),
|
||||
.query_response_error(cache_query_response_error),
|
||||
.query_response_mac(cache_query_response_mac),
|
||||
// Write cache
|
||||
.write_request_valid(cache_write_request_valid_reg),
|
||||
.write_request_ready(),
|
||||
.write_request_ip(cache_write_request_ip_reg),
|
||||
.write_request_mac(cache_write_request_mac_reg),
|
||||
.write_in_progress(cache_write_in_progress),
|
||||
.write_complete(cache_write_complete),
|
||||
// Configuration
|
||||
.clear_cache(clear_cache)
|
||||
);
|
||||
|
||||
reg arp_request_operation_reg = 1'b0, arp_request_operation_next;
|
||||
|
||||
reg arp_request_valid_reg = 1'b0, arp_request_valid_next;
|
||||
reg arp_request_ready_reg = 1'b0, arp_request_ready_next;
|
||||
reg [31:0] arp_request_ip_reg = 32'd0, arp_request_ip_next;
|
||||
|
||||
reg arp_response_valid_reg = 1'b0, arp_response_valid_next;
|
||||
reg arp_response_error_reg = 1'b0, arp_response_error_next;
|
||||
reg arp_response_broadcast_reg = 1'b0, arp_response_broadcast_next;
|
||||
reg [47:0] arp_response_mac_reg = 48'd0, arp_response_mac_next;
|
||||
|
||||
reg [5:0] arp_request_retry_cnt_reg = 6'd0, arp_request_retry_cnt_next;
|
||||
reg [35:0] arp_request_timer_reg = 36'd0, arp_request_timer_next;
|
||||
|
||||
assign cache_query_request_valid = ~arp_request_operation_reg ? arp_request_valid_reg : 1'b1;
|
||||
assign cache_query_request_ip = arp_request_ip_reg;
|
||||
assign arp_request_ready = arp_request_ready_reg;
|
||||
|
||||
assign arp_response_valid = arp_response_error_reg | (cache_query_response_valid & ~cache_query_response_error & ~arp_request_operation_reg) | arp_response_broadcast_reg;
|
||||
assign arp_response_valid = arp_response_valid_reg;
|
||||
assign arp_response_error = arp_response_error_reg;
|
||||
assign arp_response_mac = arp_response_broadcast_reg ? 48'hffffffffffff : cache_query_response_mac;
|
||||
assign arp_response_mac = arp_response_mac_reg;
|
||||
|
||||
always @* begin
|
||||
incoming_frame_ready = 1'b0;
|
||||
|
||||
outgoing_frame_valid_next = outgoing_frame_valid_reg & ~outgoing_frame_ready;
|
||||
outgoing_eth_dest_mac_next = outgoing_eth_dest_mac_reg;
|
||||
outgoing_arp_oper_next = outgoing_arp_oper_reg;
|
||||
outgoing_arp_tha_next = outgoing_arp_tha_reg;
|
||||
outgoing_arp_tpa_next = outgoing_arp_tpa_reg;
|
||||
|
||||
cache_write_request_valid_next = 1'b0;
|
||||
cache_write_request_mac_next = 48'd0;
|
||||
cache_write_request_ip_next = 32'd0;
|
||||
cache_query_request_valid_next = 1'b0;
|
||||
cache_query_request_ip_next = cache_query_request_ip_reg;
|
||||
|
||||
arp_request_valid_next = 1'b0;
|
||||
cache_write_request_valid_next = 1'b0;
|
||||
cache_write_request_mac_next = cache_write_request_mac_reg;
|
||||
cache_write_request_ip_next = cache_write_request_ip_reg;
|
||||
|
||||
arp_request_ready_next = 1'b0;
|
||||
arp_request_ip_next = arp_request_ip_reg;
|
||||
arp_request_operation_next = arp_request_operation_reg;
|
||||
arp_request_retry_cnt_next = arp_request_retry_cnt_reg;
|
||||
arp_request_timer_next = arp_request_timer_reg;
|
||||
arp_response_valid_next = arp_response_valid_reg & ~arp_response_ready;
|
||||
arp_response_error_next = 1'b0;
|
||||
arp_response_broadcast_next = 1'b0;
|
||||
|
||||
drop_incoming_frame_next = 1'b0;
|
||||
arp_response_mac_next = 48'd0;
|
||||
|
||||
// manage incoming frames
|
||||
if (filtered_incoming_frame_valid & ~(outgoing_frame_valid_reg & ~outgoing_frame_ready)) begin
|
||||
// store sender addresses in cache
|
||||
cache_write_request_valid_next = 1'b1;
|
||||
cache_write_request_ip_next = incoming_arp_spa;
|
||||
cache_write_request_mac_next = incoming_arp_sha;
|
||||
if (incoming_arp_oper_arp_request) begin
|
||||
if (incoming_arp_tpa == local_ip) begin
|
||||
// send reply frame to valid incoming request
|
||||
outgoing_frame_valid_next = 1'b1;
|
||||
outgoing_eth_dest_mac_next = incoming_eth_src_mac;
|
||||
outgoing_arp_oper_next = ARP_OPER_ARP_REPLY;
|
||||
outgoing_arp_tha_next = incoming_arp_sha;
|
||||
outgoing_arp_tpa_next = incoming_arp_spa;
|
||||
end else begin
|
||||
// does not match -> drop it
|
||||
drop_incoming_frame_next = 1'b1;
|
||||
incoming_frame_ready = outgoing_frame_ready;
|
||||
if (incoming_frame_valid & incoming_frame_ready) begin
|
||||
if (incoming_eth_type == 16'h0806 && incoming_arp_htype == 16'h0001 && incoming_arp_ptype == 16'h0800) begin
|
||||
// store sender addresses in cache
|
||||
cache_write_request_valid_next = 1'b1;
|
||||
cache_write_request_ip_next = incoming_arp_spa;
|
||||
cache_write_request_mac_next = incoming_arp_sha;
|
||||
if (incoming_arp_oper == ARP_OPER_ARP_REQUEST) begin
|
||||
// ARP request
|
||||
if (incoming_arp_tpa == local_ip) begin
|
||||
// send reply frame to valid incoming request
|
||||
outgoing_frame_valid_next = 1'b1;
|
||||
outgoing_eth_dest_mac_next = incoming_eth_src_mac;
|
||||
outgoing_arp_oper_next = ARP_OPER_ARP_REPLY;
|
||||
outgoing_arp_tha_next = incoming_arp_sha;
|
||||
outgoing_arp_tpa_next = incoming_arp_spa;
|
||||
end
|
||||
end else if (incoming_arp_oper == ARP_OPER_INARP_REPLY) begin
|
||||
// INARP request
|
||||
if (incoming_arp_tha == local_mac) begin
|
||||
// send reply frame to valid incoming request
|
||||
outgoing_frame_valid_next = 1'b1;
|
||||
outgoing_eth_dest_mac_next = incoming_eth_src_mac;
|
||||
outgoing_arp_oper_next = ARP_OPER_INARP_REPLY;
|
||||
outgoing_arp_tha_next = incoming_arp_sha;
|
||||
outgoing_arp_tpa_next = incoming_arp_spa;
|
||||
end
|
||||
end
|
||||
end else if (incoming_arp_oper_inarp_request) begin
|
||||
if (incoming_arp_tha == local_mac) begin
|
||||
// send reply frame to valid incoming request
|
||||
outgoing_frame_valid_next = 1'b1;
|
||||
outgoing_eth_dest_mac_next = incoming_eth_src_mac;
|
||||
outgoing_arp_oper_next = ARP_OPER_INARP_REPLY;
|
||||
outgoing_arp_tha_next = incoming_arp_sha;
|
||||
outgoing_arp_tpa_next = incoming_arp_spa;
|
||||
end else begin
|
||||
// does not match -> drop it
|
||||
drop_incoming_frame_next = 1'b1;
|
||||
end
|
||||
end else begin
|
||||
// does not match -> drop it
|
||||
drop_incoming_frame_next = 1'b1;
|
||||
end
|
||||
end else if (incoming_frame_valid & ~filtered_incoming_frame_valid) begin
|
||||
// incoming invalid frame -> drop it
|
||||
drop_incoming_frame_next = 1'b1;
|
||||
end
|
||||
|
||||
// manage ARP lookup requests
|
||||
if (~arp_request_operation_reg & ~arp_response_valid) begin
|
||||
if (arp_request_valid) begin
|
||||
if (~(arp_request_ip | subnet_mask) == 0) begin
|
||||
// broadcast address
|
||||
// (all bits in request IP set where subnet mask is clear)
|
||||
arp_request_valid_next = 1'b0;
|
||||
arp_response_broadcast_next = 1'b1;
|
||||
end else if (((arp_request_ip ^ gateway_ip) & subnet_mask) == 0) begin
|
||||
// within subnet, look up IP directly
|
||||
// (no bits differ between request IP and gateway IP where subnet mask is set)
|
||||
arp_request_valid_next = 1'b1;
|
||||
arp_request_ip_next = arp_request_ip;
|
||||
end else begin
|
||||
// outside of subnet, so look up gateway address
|
||||
arp_request_valid_next = 1'b1;
|
||||
arp_request_ip_next = gateway_ip;
|
||||
end
|
||||
end
|
||||
if (cache_query_response_error & ~arp_response_error) begin
|
||||
arp_request_operation_next = 1'b1;
|
||||
// send ARP request frame
|
||||
outgoing_frame_valid_next = 1'b1;
|
||||
outgoing_eth_dest_mac_next = 48'hFF_FF_FF_FF_FF_FF;
|
||||
outgoing_arp_oper_next = ARP_OPER_ARP_REQUEST;
|
||||
outgoing_arp_tha_next = 48'h00_00_00_00_00_00;
|
||||
outgoing_arp_tpa_next = arp_request_ip_reg;
|
||||
arp_request_retry_cnt_next = REQUEST_RETRY_COUNT-1;
|
||||
arp_request_timer_next = REQUEST_RETRY_INTERVAL;
|
||||
end
|
||||
end else if (arp_request_operation_reg) begin
|
||||
if (arp_request_operation_reg) begin
|
||||
arp_request_ready_next = 1'b0;
|
||||
cache_query_request_valid_next = 1'b1;
|
||||
arp_request_timer_next = arp_request_timer_reg - 1;
|
||||
// if we got a response, it will go in the cache, so when the query succeds, we're done
|
||||
if (cache_query_response_valid & ~cache_query_response_error) begin
|
||||
if (cache_query_response_valid & ~cache_query_response_error) begin
|
||||
arp_request_operation_next = 1'b0;
|
||||
cache_query_request_valid_next = 1'b0;
|
||||
arp_response_valid_next = 1'b1;
|
||||
arp_response_error_next = 1'b0;
|
||||
arp_response_mac_next = cache_query_response_mac;
|
||||
end
|
||||
// timer timeout
|
||||
if (arp_request_timer_reg == 0) begin
|
||||
@ -367,9 +317,9 @@ always @* begin
|
||||
// have more retries
|
||||
// send ARP request frame
|
||||
outgoing_frame_valid_next = 1'b1;
|
||||
outgoing_eth_dest_mac_next = 48'hFF_FF_FF_FF_FF_FF;
|
||||
outgoing_eth_dest_mac_next = 48'hffffffffffff;
|
||||
outgoing_arp_oper_next = ARP_OPER_ARP_REQUEST;
|
||||
outgoing_arp_tha_next = 48'h00_00_00_00_00_00;
|
||||
outgoing_arp_tha_next = 48'h000000000000;
|
||||
outgoing_arp_tpa_next = arp_request_ip_reg;
|
||||
arp_request_retry_cnt_next = arp_request_retry_cnt_reg - 1;
|
||||
if (arp_request_retry_cnt_reg > 1) begin
|
||||
@ -380,7 +330,51 @@ always @* begin
|
||||
end else begin
|
||||
// out of retries
|
||||
arp_request_operation_next = 1'b0;
|
||||
arp_response_valid_next = 1'b1;
|
||||
arp_response_error_next = 1'b1;
|
||||
cache_query_request_valid_next = 1'b0;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
arp_request_ready_next = ~arp_response_valid_next;
|
||||
if (cache_query_request_valid_reg) begin
|
||||
cache_query_request_valid_next = 1'b1;
|
||||
if (cache_query_response_valid) begin
|
||||
if (cache_query_response_error) begin
|
||||
arp_request_operation_next = 1'b1;
|
||||
// send ARP request frame
|
||||
outgoing_frame_valid_next = 1'b1;
|
||||
outgoing_eth_dest_mac_next = 48'hffffffffffff;
|
||||
outgoing_arp_oper_next = ARP_OPER_ARP_REQUEST;
|
||||
outgoing_arp_tha_next = 48'h000000000000;
|
||||
outgoing_arp_tpa_next = arp_request_ip_reg;
|
||||
arp_request_retry_cnt_next = REQUEST_RETRY_COUNT-1;
|
||||
arp_request_timer_next = REQUEST_RETRY_INTERVAL;
|
||||
end else begin
|
||||
cache_query_request_valid_next = 1'b0;
|
||||
arp_response_valid_next = 1'b1;
|
||||
arp_response_error_next = 1'b0;
|
||||
arp_response_mac_next = cache_query_response_mac;
|
||||
end
|
||||
end
|
||||
end else if (arp_request_valid & arp_request_ready) begin
|
||||
if (~(arp_request_ip | subnet_mask) == 0) begin
|
||||
// broadcast address
|
||||
// (all bits in request IP set where subnet mask is clear)
|
||||
arp_response_valid_next = 1'b1;
|
||||
arp_response_error_next = 1'b0;
|
||||
arp_response_mac_next = 48'hffffffffffff;
|
||||
end else if (((arp_request_ip ^ gateway_ip) & subnet_mask) == 0) begin
|
||||
// within subnet, look up IP directly
|
||||
// (no bits differ between request IP and gateway IP where subnet mask is set)
|
||||
cache_query_request_valid_next = 1'b1;
|
||||
cache_query_request_ip_next = arp_request_ip;
|
||||
arp_request_ip_next = arp_request_ip;
|
||||
end else begin
|
||||
// outside of subnet, so look up gateway address
|
||||
cache_query_request_valid_next = 1'b1;
|
||||
cache_query_request_ip_next = gateway_ip;
|
||||
arp_request_ip_next = gateway_ip;
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -389,26 +383,25 @@ end
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
outgoing_frame_valid_reg <= 1'b0;
|
||||
cache_query_request_valid_reg <= 1'b0;
|
||||
cache_write_request_valid_reg <= 1'b0;
|
||||
arp_request_valid_reg <= 1'b0;
|
||||
arp_request_ready_reg <= 1'b0;
|
||||
arp_request_operation_reg <= 1'b0;
|
||||
arp_request_retry_cnt_reg <= 6'd0;
|
||||
arp_request_timer_reg <= 36'd0;
|
||||
arp_response_error_reg <= 1'b0;
|
||||
arp_response_broadcast_reg <= 1'b0;
|
||||
drop_incoming_frame_reg <= 1'b0;
|
||||
arp_response_valid_reg <= 1'b0;
|
||||
end else begin
|
||||
outgoing_frame_valid_reg <= outgoing_frame_valid_next;
|
||||
cache_query_request_valid_reg <= cache_query_request_valid_next;
|
||||
cache_write_request_valid_reg <= cache_write_request_valid_next;
|
||||
arp_request_valid_reg <= arp_request_valid_next;
|
||||
arp_request_ready_reg <= arp_request_ready_next;
|
||||
arp_request_operation_reg <= arp_request_operation_next;
|
||||
arp_request_retry_cnt_reg <= arp_request_retry_cnt_next;
|
||||
arp_request_timer_reg <= arp_request_timer_next;
|
||||
arp_response_error_reg <= arp_response_error_next;
|
||||
arp_response_broadcast_reg <= arp_response_broadcast_next;
|
||||
drop_incoming_frame_reg <= drop_incoming_frame_next;
|
||||
arp_response_valid_reg <= arp_response_valid_next;
|
||||
end
|
||||
|
||||
cache_query_request_ip_reg <= cache_query_request_ip_next;
|
||||
outgoing_eth_dest_mac_reg <= outgoing_eth_dest_mac_next;
|
||||
outgoing_arp_oper_reg <= outgoing_arp_oper_next;
|
||||
outgoing_arp_tha_reg <= outgoing_arp_tha_next;
|
||||
@ -416,6 +409,8 @@ always @(posedge clk) begin
|
||||
cache_write_request_mac_reg <= cache_write_request_mac_next;
|
||||
cache_write_request_ip_reg <= cache_write_request_ip_next;
|
||||
arp_request_ip_reg <= arp_request_ip_next;
|
||||
arp_response_error_reg <= arp_response_error_next;
|
||||
arp_response_mac_reg <= arp_response_mac_next;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
259
rtl/arp_64.v
259
rtl/arp_64.v
@ -30,10 +30,10 @@ THE SOFTWARE.
|
||||
* ARP block for IPv4, ethernet frame interface (64 bit datapath)
|
||||
*/
|
||||
module arp_64 #(
|
||||
parameter CACHE_ADDR_WIDTH = 2,
|
||||
parameter CACHE_ADDR_WIDTH = 9,
|
||||
parameter REQUEST_RETRY_COUNT = 4,
|
||||
parameter REQUEST_RETRY_INTERVAL = 125000000*2,
|
||||
parameter REQUEST_TIMEOUT = 125000000*30
|
||||
parameter REQUEST_RETRY_INTERVAL = 156250000*2,
|
||||
parameter REQUEST_TIMEOUT = 156250000*30
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
@ -73,8 +73,10 @@ module arp_64 #(
|
||||
* ARP requests
|
||||
*/
|
||||
input wire arp_request_valid,
|
||||
output wire arp_request_ready,
|
||||
input wire [31:0] arp_request_ip,
|
||||
output wire arp_response_valid,
|
||||
input wire arp_response_ready,
|
||||
output wire arp_response_error,
|
||||
output wire [47:0] arp_response_mac,
|
||||
|
||||
@ -95,7 +97,7 @@ localparam [15:0]
|
||||
ARP_OPER_INARP_REPLY = 16'h0009;
|
||||
|
||||
wire incoming_frame_valid;
|
||||
wire incoming_frame_ready;
|
||||
reg incoming_frame_ready;
|
||||
wire [47:0] incoming_eth_dest_mac;
|
||||
wire [47:0] incoming_eth_src_mac;
|
||||
wire [15:0] incoming_eth_type;
|
||||
@ -109,19 +111,6 @@ wire [31:0] incoming_arp_spa;
|
||||
wire [47:0] incoming_arp_tha;
|
||||
wire [31:0] incoming_arp_tpa;
|
||||
|
||||
reg outgoing_frame_valid_reg = 1'b0, outgoing_frame_valid_next;
|
||||
wire outgoing_frame_ready;
|
||||
reg [47:0] outgoing_eth_dest_mac_reg = 48'd0, outgoing_eth_dest_mac_next;
|
||||
reg [15:0] outgoing_arp_oper_reg = 16'd0, outgoing_arp_oper_next;
|
||||
reg [47:0] outgoing_arp_tha_reg = 48'd0, outgoing_arp_tha_next;
|
||||
reg [31:0] outgoing_arp_tpa_reg = 32'd0, outgoing_arp_tpa_next;
|
||||
|
||||
// drop frame
|
||||
reg drop_incoming_frame_reg = 1'b0, drop_incoming_frame_next;
|
||||
|
||||
// wait on incoming frames until we can reply
|
||||
assign incoming_frame_ready = outgoing_frame_ready | drop_incoming_frame_reg;
|
||||
|
||||
/*
|
||||
* ARP frame processing
|
||||
*/
|
||||
@ -162,6 +151,13 @@ arp_eth_rx_inst (
|
||||
.error_invalid_header()
|
||||
);
|
||||
|
||||
reg outgoing_frame_valid_reg = 1'b0, outgoing_frame_valid_next;
|
||||
wire outgoing_frame_ready;
|
||||
reg [47:0] outgoing_eth_dest_mac_reg = 48'd0, outgoing_eth_dest_mac_next;
|
||||
reg [15:0] outgoing_arp_oper_reg = 16'd0, outgoing_arp_oper_next;
|
||||
reg [47:0] outgoing_arp_tha_reg = 48'd0, outgoing_arp_tha_next;
|
||||
reg [31:0] outgoing_arp_tpa_reg = 32'd0, outgoing_arp_tpa_next;
|
||||
|
||||
arp_eth_tx_64
|
||||
arp_eth_tx_inst (
|
||||
.clk(clk),
|
||||
@ -195,27 +191,8 @@ arp_eth_tx_inst (
|
||||
.busy()
|
||||
);
|
||||
|
||||
wire incoming_eth_type_valid = (incoming_eth_type == 16'h0806);
|
||||
wire incoming_arp_htype_valid = (incoming_arp_htype == 16'h0001);
|
||||
wire incoming_arp_ptype_valid = (incoming_arp_ptype == 16'h0800);
|
||||
|
||||
wire incoming_arp_oper_arp_request = (incoming_arp_oper == ARP_OPER_ARP_REQUEST);
|
||||
wire incoming_arp_oper_arp_reply = (incoming_arp_oper == ARP_OPER_ARP_REPLY);
|
||||
wire incoming_arp_oper_inarp_request = (incoming_arp_oper == ARP_OPER_INARP_REQUEST);
|
||||
wire incoming_arp_oper_inarp_reply = (incoming_arp_oper == ARP_OPER_INARP_REPLY);
|
||||
|
||||
wire filtered_incoming_frame_valid = incoming_frame_valid &
|
||||
incoming_eth_type_valid &
|
||||
incoming_arp_htype_valid &
|
||||
incoming_arp_ptype_valid;
|
||||
|
||||
wire filtered_incoming_arp_oper_arp_request = filtered_incoming_frame_valid & incoming_arp_oper_arp_request;
|
||||
wire filtered_incoming_arp_oper_arp_reply = filtered_incoming_frame_valid & incoming_arp_oper_arp_reply;
|
||||
wire filtered_incoming_arp_oper_inarp_request = filtered_incoming_frame_valid & incoming_arp_oper_inarp_request;
|
||||
wire filtered_incoming_arp_oper_inarp_reply = filtered_incoming_frame_valid & incoming_arp_oper_inarp_reply;
|
||||
|
||||
wire cache_query_request_valid;
|
||||
wire [31:0] cache_query_request_ip;
|
||||
reg cache_query_request_valid_reg = 1'b0, cache_query_request_valid_next;
|
||||
reg [31:0] cache_query_request_ip_reg = 32'd0, cache_query_request_ip_next;
|
||||
wire cache_query_response_valid;
|
||||
wire cache_query_response_error;
|
||||
wire [47:0] cache_query_response_mac;
|
||||
@ -223,8 +200,6 @@ wire [47:0] cache_query_response_mac;
|
||||
reg cache_write_request_valid_reg = 1'b0, cache_write_request_valid_next;
|
||||
reg [31:0] cache_write_request_ip_reg = 32'd0, cache_write_request_ip_next;
|
||||
reg [47:0] cache_write_request_mac_reg = 48'd0, cache_write_request_mac_next;
|
||||
wire cache_write_in_progress;
|
||||
wire cache_write_complete;
|
||||
|
||||
/*
|
||||
* ARP cache
|
||||
@ -236,134 +211,109 @@ arp_cache_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
// Query cache
|
||||
.query_request_valid(cache_query_request_valid),
|
||||
.query_request_ip(cache_query_request_ip),
|
||||
.query_request_valid(cache_query_request_valid_reg),
|
||||
.query_request_ready(),
|
||||
.query_request_ip(cache_query_request_ip_reg),
|
||||
.query_response_valid(cache_query_response_valid),
|
||||
.query_response_ready(1'b1),
|
||||
.query_response_error(cache_query_response_error),
|
||||
.query_response_mac(cache_query_response_mac),
|
||||
// Write cache
|
||||
.write_request_valid(cache_write_request_valid_reg),
|
||||
.write_request_ready(),
|
||||
.write_request_ip(cache_write_request_ip_reg),
|
||||
.write_request_mac(cache_write_request_mac_reg),
|
||||
.write_in_progress(cache_write_in_progress),
|
||||
.write_complete(cache_write_complete),
|
||||
// Configuration
|
||||
.clear_cache(clear_cache)
|
||||
);
|
||||
|
||||
reg arp_request_operation_reg = 1'b0, arp_request_operation_next;
|
||||
|
||||
reg arp_request_valid_reg = 1'b0, arp_request_valid_next;
|
||||
reg arp_request_ready_reg = 1'b0, arp_request_ready_next;
|
||||
reg [31:0] arp_request_ip_reg = 32'd0, arp_request_ip_next;
|
||||
|
||||
reg arp_response_valid_reg = 1'b0, arp_response_valid_next;
|
||||
reg arp_response_error_reg = 1'b0, arp_response_error_next;
|
||||
reg arp_response_broadcast_reg = 1'b0, arp_response_broadcast_next;
|
||||
reg [47:0] arp_response_mac_reg = 48'd0, arp_response_mac_next;
|
||||
|
||||
reg [5:0] arp_request_retry_cnt_reg = 6'd0, arp_request_retry_cnt_next;
|
||||
reg [35:0] arp_request_timer_reg = 36'd0, arp_request_timer_next;
|
||||
|
||||
assign cache_query_request_valid = ~arp_request_operation_reg ? arp_request_valid_reg : 1'b1;
|
||||
assign cache_query_request_ip = arp_request_ip_reg;
|
||||
assign arp_request_ready = arp_request_ready_reg;
|
||||
|
||||
assign arp_response_valid = arp_response_error_reg | (cache_query_response_valid & ~cache_query_response_error & ~arp_request_operation_reg) | arp_response_broadcast_reg;
|
||||
assign arp_response_valid = arp_response_valid_reg;
|
||||
assign arp_response_error = arp_response_error_reg;
|
||||
assign arp_response_mac = arp_response_broadcast_reg ? 48'hffffffffffff : cache_query_response_mac;
|
||||
assign arp_response_mac = arp_response_mac_reg;
|
||||
|
||||
always @* begin
|
||||
incoming_frame_ready = 1'b0;
|
||||
|
||||
outgoing_frame_valid_next = outgoing_frame_valid_reg & ~outgoing_frame_ready;
|
||||
outgoing_eth_dest_mac_next = outgoing_eth_dest_mac_reg;
|
||||
outgoing_arp_oper_next = outgoing_arp_oper_reg;
|
||||
outgoing_arp_tha_next = outgoing_arp_tha_reg;
|
||||
outgoing_arp_tpa_next = outgoing_arp_tpa_reg;
|
||||
|
||||
cache_write_request_valid_next = 1'b0;
|
||||
cache_write_request_mac_next = 48'd0;
|
||||
cache_write_request_ip_next = 32'd0;
|
||||
cache_query_request_valid_next = 1'b0;
|
||||
cache_query_request_ip_next = cache_query_request_ip_reg;
|
||||
|
||||
arp_request_valid_next = 1'b0;
|
||||
cache_write_request_valid_next = 1'b0;
|
||||
cache_write_request_mac_next = cache_write_request_mac_reg;
|
||||
cache_write_request_ip_next = cache_write_request_ip_reg;
|
||||
|
||||
arp_request_ready_next = 1'b0;
|
||||
arp_request_ip_next = arp_request_ip_reg;
|
||||
arp_request_operation_next = arp_request_operation_reg;
|
||||
arp_request_retry_cnt_next = arp_request_retry_cnt_reg;
|
||||
arp_request_timer_next = arp_request_timer_reg;
|
||||
arp_response_valid_next = arp_response_valid_reg & ~arp_response_ready;
|
||||
arp_response_error_next = 1'b0;
|
||||
arp_response_broadcast_next = 1'b0;
|
||||
|
||||
drop_incoming_frame_next = 1'b0;
|
||||
arp_response_mac_next = 48'd0;
|
||||
|
||||
// manage incoming frames
|
||||
if (filtered_incoming_frame_valid & ~(outgoing_frame_valid_reg & ~outgoing_frame_ready)) begin
|
||||
// store sender addresses in cache
|
||||
cache_write_request_valid_next = 1'b1;
|
||||
cache_write_request_ip_next = incoming_arp_spa;
|
||||
cache_write_request_mac_next = incoming_arp_sha;
|
||||
if (incoming_arp_oper_arp_request) begin
|
||||
if (incoming_arp_tpa == local_ip) begin
|
||||
// send reply frame to valid incoming request
|
||||
outgoing_frame_valid_next = 1'b1;
|
||||
outgoing_eth_dest_mac_next = incoming_eth_src_mac;
|
||||
outgoing_arp_oper_next = ARP_OPER_ARP_REPLY;
|
||||
outgoing_arp_tha_next = incoming_arp_sha;
|
||||
outgoing_arp_tpa_next = incoming_arp_spa;
|
||||
end else begin
|
||||
// does not match -> drop it
|
||||
drop_incoming_frame_next = 1'b1;
|
||||
incoming_frame_ready = outgoing_frame_ready;
|
||||
if (incoming_frame_valid & incoming_frame_ready) begin
|
||||
if (incoming_eth_type == 16'h0806 && incoming_arp_htype == 16'h0001 && incoming_arp_ptype == 16'h0800) begin
|
||||
// store sender addresses in cache
|
||||
cache_write_request_valid_next = 1'b1;
|
||||
cache_write_request_ip_next = incoming_arp_spa;
|
||||
cache_write_request_mac_next = incoming_arp_sha;
|
||||
if (incoming_arp_oper == ARP_OPER_ARP_REQUEST) begin
|
||||
// ARP request
|
||||
if (incoming_arp_tpa == local_ip) begin
|
||||
// send reply frame to valid incoming request
|
||||
outgoing_frame_valid_next = 1'b1;
|
||||
outgoing_eth_dest_mac_next = incoming_eth_src_mac;
|
||||
outgoing_arp_oper_next = ARP_OPER_ARP_REPLY;
|
||||
outgoing_arp_tha_next = incoming_arp_sha;
|
||||
outgoing_arp_tpa_next = incoming_arp_spa;
|
||||
end
|
||||
end else if (incoming_arp_oper == ARP_OPER_INARP_REPLY) begin
|
||||
// INARP request
|
||||
if (incoming_arp_tha == local_mac) begin
|
||||
// send reply frame to valid incoming request
|
||||
outgoing_frame_valid_next = 1'b1;
|
||||
outgoing_eth_dest_mac_next = incoming_eth_src_mac;
|
||||
outgoing_arp_oper_next = ARP_OPER_INARP_REPLY;
|
||||
outgoing_arp_tha_next = incoming_arp_sha;
|
||||
outgoing_arp_tpa_next = incoming_arp_spa;
|
||||
end
|
||||
end
|
||||
end else if (incoming_arp_oper_inarp_request) begin
|
||||
if (incoming_arp_tha == local_mac) begin
|
||||
// send reply frame to valid incoming request
|
||||
outgoing_frame_valid_next = 1'b1;
|
||||
outgoing_eth_dest_mac_next = incoming_eth_src_mac;
|
||||
outgoing_arp_oper_next = ARP_OPER_INARP_REPLY;
|
||||
outgoing_arp_tha_next = incoming_arp_sha;
|
||||
outgoing_arp_tpa_next = incoming_arp_spa;
|
||||
end else begin
|
||||
// does not match -> drop it
|
||||
drop_incoming_frame_next = 1'b1;
|
||||
end
|
||||
end else begin
|
||||
// does not match -> drop it
|
||||
drop_incoming_frame_next = 1'b1;
|
||||
end
|
||||
end else if (incoming_frame_valid & ~filtered_incoming_frame_valid) begin
|
||||
// incoming invalid frame -> drop it
|
||||
drop_incoming_frame_next = 1'b1;
|
||||
end
|
||||
|
||||
// manage ARP lookup requests
|
||||
if (~arp_request_operation_reg & ~arp_response_valid) begin
|
||||
if (arp_request_valid) begin
|
||||
if (~(arp_request_ip | subnet_mask) == 0) begin
|
||||
// broadcast address
|
||||
// (all bits in request IP set where subnet mask is clear)
|
||||
arp_request_valid_next = 1'b0;
|
||||
arp_response_broadcast_next = 1'b1;
|
||||
end else if (((arp_request_ip ^ gateway_ip) & subnet_mask) == 0) begin
|
||||
// within subnet, look up IP directly
|
||||
// (no bits differ between request IP and gateway IP where subnet mask is set)
|
||||
arp_request_valid_next = 1'b1;
|
||||
arp_request_ip_next = arp_request_ip;
|
||||
end else begin
|
||||
// outside of subnet, so look up gateway address
|
||||
arp_request_valid_next = 1'b1;
|
||||
arp_request_ip_next = gateway_ip;
|
||||
end
|
||||
end
|
||||
if (cache_query_response_error & ~arp_response_error) begin
|
||||
arp_request_operation_next = 1'b1;
|
||||
// send ARP request frame
|
||||
outgoing_frame_valid_next = 1'b1;
|
||||
outgoing_eth_dest_mac_next = 48'hFF_FF_FF_FF_FF_FF;
|
||||
outgoing_arp_oper_next = ARP_OPER_ARP_REQUEST;
|
||||
outgoing_arp_tha_next = 48'h00_00_00_00_00_00;
|
||||
outgoing_arp_tpa_next = arp_request_ip_reg;
|
||||
arp_request_retry_cnt_next = REQUEST_RETRY_COUNT-1;
|
||||
arp_request_timer_next = REQUEST_RETRY_INTERVAL;
|
||||
end
|
||||
end else if (arp_request_operation_reg) begin
|
||||
if (arp_request_operation_reg) begin
|
||||
arp_request_ready_next = 1'b0;
|
||||
cache_query_request_valid_next = 1'b1;
|
||||
arp_request_timer_next = arp_request_timer_reg - 1;
|
||||
// if we got a response, it will go in the cache, so when the query succeds, we're done
|
||||
if (cache_query_response_valid & ~cache_query_response_error) begin
|
||||
if (cache_query_response_valid & ~cache_query_response_error) begin
|
||||
arp_request_operation_next = 1'b0;
|
||||
cache_query_request_valid_next = 1'b0;
|
||||
arp_response_valid_next = 1'b1;
|
||||
arp_response_error_next = 1'b0;
|
||||
arp_response_mac_next = cache_query_response_mac;
|
||||
end
|
||||
// timer timeout
|
||||
if (arp_request_timer_reg == 0) begin
|
||||
@ -371,9 +321,9 @@ always @* begin
|
||||
// have more retries
|
||||
// send ARP request frame
|
||||
outgoing_frame_valid_next = 1'b1;
|
||||
outgoing_eth_dest_mac_next = 48'hFF_FF_FF_FF_FF_FF;
|
||||
outgoing_eth_dest_mac_next = 48'hffffffffffff;
|
||||
outgoing_arp_oper_next = ARP_OPER_ARP_REQUEST;
|
||||
outgoing_arp_tha_next = 48'h00_00_00_00_00_00;
|
||||
outgoing_arp_tha_next = 48'h000000000000;
|
||||
outgoing_arp_tpa_next = arp_request_ip_reg;
|
||||
arp_request_retry_cnt_next = arp_request_retry_cnt_reg - 1;
|
||||
if (arp_request_retry_cnt_reg > 1) begin
|
||||
@ -384,7 +334,51 @@ always @* begin
|
||||
end else begin
|
||||
// out of retries
|
||||
arp_request_operation_next = 1'b0;
|
||||
arp_response_valid_next = 1'b1;
|
||||
arp_response_error_next = 1'b1;
|
||||
cache_query_request_valid_next = 1'b0;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
arp_request_ready_next = ~arp_response_valid_next;
|
||||
if (cache_query_request_valid_reg) begin
|
||||
cache_query_request_valid_next = 1'b1;
|
||||
if (cache_query_response_valid) begin
|
||||
if (cache_query_response_error) begin
|
||||
arp_request_operation_next = 1'b1;
|
||||
// send ARP request frame
|
||||
outgoing_frame_valid_next = 1'b1;
|
||||
outgoing_eth_dest_mac_next = 48'hffffffffffff;
|
||||
outgoing_arp_oper_next = ARP_OPER_ARP_REQUEST;
|
||||
outgoing_arp_tha_next = 48'h000000000000;
|
||||
outgoing_arp_tpa_next = arp_request_ip_reg;
|
||||
arp_request_retry_cnt_next = REQUEST_RETRY_COUNT-1;
|
||||
arp_request_timer_next = REQUEST_RETRY_INTERVAL;
|
||||
end else begin
|
||||
cache_query_request_valid_next = 1'b0;
|
||||
arp_response_valid_next = 1'b1;
|
||||
arp_response_error_next = 1'b0;
|
||||
arp_response_mac_next = cache_query_response_mac;
|
||||
end
|
||||
end
|
||||
end else if (arp_request_valid & arp_request_ready) begin
|
||||
if (~(arp_request_ip | subnet_mask) == 0) begin
|
||||
// broadcast address
|
||||
// (all bits in request IP set where subnet mask is clear)
|
||||
arp_response_valid_next = 1'b1;
|
||||
arp_response_error_next = 1'b0;
|
||||
arp_response_mac_next = 48'hffffffffffff;
|
||||
end else if (((arp_request_ip ^ gateway_ip) & subnet_mask) == 0) begin
|
||||
// within subnet, look up IP directly
|
||||
// (no bits differ between request IP and gateway IP where subnet mask is set)
|
||||
cache_query_request_valid_next = 1'b1;
|
||||
cache_query_request_ip_next = arp_request_ip;
|
||||
arp_request_ip_next = arp_request_ip;
|
||||
end else begin
|
||||
// outside of subnet, so look up gateway address
|
||||
cache_query_request_valid_next = 1'b1;
|
||||
cache_query_request_ip_next = gateway_ip;
|
||||
arp_request_ip_next = gateway_ip;
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -393,26 +387,25 @@ end
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
outgoing_frame_valid_reg <= 1'b0;
|
||||
cache_query_request_valid_reg <= 1'b0;
|
||||
cache_write_request_valid_reg <= 1'b0;
|
||||
arp_request_valid_reg <= 1'b0;
|
||||
arp_request_ready_reg <= 1'b0;
|
||||
arp_request_operation_reg <= 1'b0;
|
||||
arp_request_retry_cnt_reg <= 6'd0;
|
||||
arp_request_timer_reg <= 36'd0;
|
||||
arp_response_error_reg <= 1'b0;
|
||||
arp_response_broadcast_reg <= 1'b0;
|
||||
drop_incoming_frame_reg <= 1'b0;
|
||||
arp_response_valid_reg <= 1'b0;
|
||||
end else begin
|
||||
outgoing_frame_valid_reg <= outgoing_frame_valid_next;
|
||||
cache_query_request_valid_reg <= cache_query_request_valid_next;
|
||||
cache_write_request_valid_reg <= cache_write_request_valid_next;
|
||||
arp_request_valid_reg <= arp_request_valid_next;
|
||||
arp_request_ready_reg <= arp_request_ready_next;
|
||||
arp_request_operation_reg <= arp_request_operation_next;
|
||||
arp_request_retry_cnt_reg <= arp_request_retry_cnt_next;
|
||||
arp_request_timer_reg <= arp_request_timer_next;
|
||||
arp_response_error_reg <= arp_response_error_next;
|
||||
arp_response_broadcast_reg <= arp_response_broadcast_next;
|
||||
drop_incoming_frame_reg <= drop_incoming_frame_next;
|
||||
arp_response_valid_reg <= arp_response_valid_next;
|
||||
end
|
||||
|
||||
cache_query_request_ip_reg <= cache_query_request_ip_next;
|
||||
outgoing_eth_dest_mac_reg <= outgoing_eth_dest_mac_next;
|
||||
outgoing_arp_oper_reg <= outgoing_arp_oper_next;
|
||||
outgoing_arp_tha_reg <= outgoing_arp_tha_next;
|
||||
@ -420,6 +413,8 @@ always @(posedge clk) begin
|
||||
cache_write_request_mac_reg <= cache_write_request_mac_next;
|
||||
cache_write_request_ip_reg <= cache_write_request_ip_next;
|
||||
arp_request_ip_reg <= arp_request_ip_next;
|
||||
arp_response_error_reg <= arp_response_error_next;
|
||||
arp_response_mac_reg <= arp_response_mac_next;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
236
rtl/arp_cache.v
236
rtl/arp_cache.v
@ -27,32 +27,34 @@ THE SOFTWARE.
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* ARP cache block
|
||||
* ARP cache
|
||||
*/
|
||||
module arp_cache #(
|
||||
parameter CACHE_ADDR_WIDTH = 2
|
||||
parameter CACHE_ADDR_WIDTH = 9
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* Query cache
|
||||
* Cache query
|
||||
*/
|
||||
input wire query_request_valid,
|
||||
output wire query_request_ready,
|
||||
input wire [31:0] query_request_ip,
|
||||
|
||||
output wire query_response_valid,
|
||||
input wire query_response_ready,
|
||||
output wire query_response_error,
|
||||
output wire [47:0] query_response_mac,
|
||||
|
||||
/*
|
||||
* Write cache
|
||||
* Cache write
|
||||
*/
|
||||
input wire write_request_valid,
|
||||
output wire write_request_ready,
|
||||
input wire [31:0] write_request_ip,
|
||||
input wire [47:0] write_request_mac,
|
||||
output wire write_in_progress,
|
||||
output wire write_complete,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
@ -60,118 +62,156 @@ module arp_cache #(
|
||||
input wire clear_cache
|
||||
);
|
||||
|
||||
// bit LRU cache
|
||||
reg mem_write = 0;
|
||||
reg store_query = 0;
|
||||
reg store_write = 0;
|
||||
|
||||
reg [31:0] ip_addr_mem[(2**CACHE_ADDR_WIDTH)-1:0];
|
||||
reg [47:0] mac_addr_mem[(2**CACHE_ADDR_WIDTH)-1:0];
|
||||
reg [(2**CACHE_ADDR_WIDTH)-1:0] lru_bit = 0;
|
||||
|
||||
reg query_response_valid_reg = 0;
|
||||
reg query_response_error_reg = 0;
|
||||
reg [47:0] query_response_mac_reg = 0;
|
||||
|
||||
reg write_complete_reg = 0;
|
||||
|
||||
localparam [2:0]
|
||||
WRITE_STATE_IDLE = 0,
|
||||
WRITE_STATE_SEARCH = 1,
|
||||
WRITE_STATE_NOTFOUND = 2;
|
||||
|
||||
reg [2:0] write_state = WRITE_STATE_IDLE;
|
||||
reg query_ip_valid_reg = 0, query_ip_valid_next;
|
||||
reg [31:0] query_ip_reg = 0;
|
||||
reg write_ip_valid_reg = 0, write_ip_valid_next;
|
||||
reg [31:0] write_ip_reg = 0;
|
||||
reg [47:0] write_mac_reg = 0;
|
||||
reg [CACHE_ADDR_WIDTH-1:0] write_addr = 0;
|
||||
reg [CACHE_ADDR_WIDTH-1:0] write_ptr = 0;
|
||||
|
||||
wire write_state_idle = (write_state == WRITE_STATE_IDLE);
|
||||
wire write_state_search = (write_state == WRITE_STATE_SEARCH);
|
||||
wire write_state_notfound = (write_state == WRITE_STATE_NOTFOUND);
|
||||
reg [CACHE_ADDR_WIDTH-1:0] wr_ptr_reg = {CACHE_ADDR_WIDTH{1'b0}}, wr_ptr_next;
|
||||
reg [CACHE_ADDR_WIDTH-1:0] rd_ptr_reg = {CACHE_ADDR_WIDTH{1'b0}}, rd_ptr_next;
|
||||
|
||||
reg clear_cache_operation = 0;
|
||||
reg valid_mem[(2**CACHE_ADDR_WIDTH)-1:0];
|
||||
reg [31:0] ip_addr_mem[(2**CACHE_ADDR_WIDTH)-1:0];
|
||||
reg [47:0] mac_addr_mem[(2**CACHE_ADDR_WIDTH)-1:0];
|
||||
|
||||
reg query_request_ready_reg = 0, query_request_ready_next;
|
||||
|
||||
reg query_response_valid_reg = 0, query_response_valid_next;
|
||||
reg query_response_error_reg = 0, query_response_error_next;
|
||||
reg [47:0] query_response_mac_reg = 0;
|
||||
|
||||
reg write_request_ready_reg = 0, write_request_ready_next;
|
||||
|
||||
wire [31:0] query_request_hash;
|
||||
wire [31:0] write_request_hash;
|
||||
|
||||
assign query_request_ready = query_request_ready_reg;
|
||||
|
||||
assign query_response_valid = query_response_valid_reg;
|
||||
assign query_response_error = query_response_error_reg;
|
||||
assign query_response_mac = query_response_mac_reg;
|
||||
|
||||
assign write_in_progress = ~write_state_idle;
|
||||
assign write_complete = write_complete_reg;
|
||||
assign write_request_ready = write_request_ready_reg;
|
||||
|
||||
wire lru_full = &lru_bit;
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(32),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
rd_hash (
|
||||
.data_in(query_request_ip),
|
||||
.state_in(32'hffffffff),
|
||||
.data_out(),
|
||||
.state_out(query_request_hash)
|
||||
);
|
||||
|
||||
integer i;
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(32),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
wr_hash (
|
||||
.data_in(write_request_ip),
|
||||
.state_in(32'hffffffff),
|
||||
.data_out(),
|
||||
.state_out(write_request_hash)
|
||||
);
|
||||
|
||||
always @* begin
|
||||
mem_write = 1'b0;
|
||||
store_query = 1'b0;
|
||||
store_write = 1'b0;
|
||||
|
||||
wr_ptr_next = wr_ptr_reg;
|
||||
rd_ptr_next = rd_ptr_reg;
|
||||
|
||||
query_ip_valid_next = query_ip_valid_reg;
|
||||
|
||||
query_request_ready_next = ~query_ip_valid_reg || ~query_request_valid || query_response_ready;
|
||||
|
||||
query_response_valid_next = query_response_valid_reg & ~query_response_ready;
|
||||
query_response_error_next = query_response_error_reg;
|
||||
|
||||
if (query_ip_valid_reg && (~query_request_valid || query_response_ready)) begin
|
||||
query_response_valid_next = 1;
|
||||
query_ip_valid_next = 0;
|
||||
if (valid_mem[rd_ptr_reg] && ip_addr_mem[rd_ptr_reg] == query_ip_reg) begin
|
||||
query_response_error_next = 0;
|
||||
end else begin
|
||||
query_response_error_next = 1;
|
||||
end
|
||||
end
|
||||
|
||||
if (query_request_valid && query_request_ready && (~query_ip_valid_reg || ~query_request_valid || query_response_ready)) begin
|
||||
store_query = 1;
|
||||
query_ip_valid_next = 1;
|
||||
rd_ptr_next = query_request_hash[CACHE_ADDR_WIDTH-1:0];
|
||||
end
|
||||
|
||||
write_ip_valid_next = write_ip_valid_reg;
|
||||
|
||||
write_request_ready_next = 1'b1;
|
||||
|
||||
if (write_ip_valid_reg) begin
|
||||
write_ip_valid_next = 0;
|
||||
mem_write = 1;
|
||||
end
|
||||
|
||||
if (write_request_valid && write_request_ready) begin
|
||||
store_write = 1;
|
||||
write_ip_valid_next = 1;
|
||||
wr_ptr_next = write_request_hash[CACHE_ADDR_WIDTH-1:0];
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
query_response_valid_reg <= 0;
|
||||
query_response_error_reg <= 0;
|
||||
write_complete_reg <= 0;
|
||||
write_state <= WRITE_STATE_IDLE;
|
||||
write_addr <= 0;
|
||||
write_ptr <= 0;
|
||||
clear_cache_operation <= 1;
|
||||
lru_bit <= 0;
|
||||
query_ip_valid_reg <= 1'b0;
|
||||
query_request_ready_reg <= 1'b0;
|
||||
query_response_valid_reg <= 1'b0;
|
||||
write_ip_valid_reg <= 1'b0;
|
||||
write_request_ready_reg <= 1'b0;
|
||||
end else begin
|
||||
write_complete_reg <= 0;
|
||||
query_response_valid_reg <= 0;
|
||||
query_response_error_reg <= 0;
|
||||
query_ip_valid_reg <= query_ip_valid_next;
|
||||
query_request_ready_reg <= query_request_ready_next;
|
||||
query_response_valid_reg <= query_response_valid_next;
|
||||
write_ip_valid_reg <= write_ip_valid_next;
|
||||
write_request_ready_reg <= write_request_ready_next;
|
||||
end
|
||||
|
||||
// clear LRU bits when full
|
||||
if (lru_full) begin
|
||||
lru_bit <= 0;
|
||||
end
|
||||
query_response_error_reg <= query_response_error_next;
|
||||
|
||||
// fast IP match and readout
|
||||
if (query_request_valid) begin
|
||||
query_response_valid_reg <= 1;
|
||||
query_response_error_reg <= 1;
|
||||
for (i = 0; i < 2**CACHE_ADDR_WIDTH; i = i + 1) begin
|
||||
if (ip_addr_mem[i] == query_request_ip) begin
|
||||
query_response_error_reg <= 0;
|
||||
query_response_mac_reg <= mac_addr_mem[i];
|
||||
lru_bit[i] <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
if (store_query) begin
|
||||
query_ip_reg <= query_request_ip;
|
||||
end
|
||||
|
||||
// manage writes
|
||||
if (write_state_idle) begin
|
||||
if (write_request_valid) begin
|
||||
write_state <= WRITE_STATE_SEARCH;
|
||||
write_ip_reg <= write_request_ip;
|
||||
write_mac_reg <= write_request_mac;
|
||||
end
|
||||
write_addr <= 0;
|
||||
end else if (write_state_search) begin
|
||||
write_addr <= write_addr + 1;
|
||||
if (&write_addr) begin
|
||||
write_state <= WRITE_STATE_NOTFOUND;
|
||||
end
|
||||
if (ip_addr_mem[write_addr] == write_ip_reg) begin
|
||||
write_state <= WRITE_STATE_IDLE;
|
||||
mac_addr_mem[write_addr] <= write_mac_reg;
|
||||
write_complete_reg <= 1;
|
||||
end
|
||||
end else if (write_state_notfound) begin
|
||||
write_ptr <= write_ptr + 1;
|
||||
if (~lru_bit[write_ptr]) begin
|
||||
ip_addr_mem[write_ptr] <= write_ip_reg;
|
||||
mac_addr_mem[write_ptr] <= write_mac_reg;
|
||||
write_state <= WRITE_STATE_IDLE;
|
||||
write_complete_reg <= 1;
|
||||
end
|
||||
end
|
||||
if (store_write) begin
|
||||
write_ip_reg <= write_request_ip;
|
||||
write_mac_reg <= write_request_mac;
|
||||
end
|
||||
|
||||
// clear cache
|
||||
if (clear_cache & ~clear_cache_operation) begin
|
||||
clear_cache_operation <= 1;
|
||||
write_addr <= 0;
|
||||
end
|
||||
if (clear_cache_operation) begin
|
||||
write_addr <= write_addr + 1;
|
||||
ip_addr_mem[write_addr] <= 0;
|
||||
mac_addr_mem[write_addr] <= 0;
|
||||
clear_cache_operation <= ~&write_addr;
|
||||
end
|
||||
wr_ptr_reg <= wr_ptr_next;
|
||||
rd_ptr_reg <= rd_ptr_next;
|
||||
|
||||
query_response_mac_reg <= mac_addr_mem[rd_ptr_reg];
|
||||
|
||||
if (mem_write) begin
|
||||
valid_mem[wr_ptr_reg] <= 1'b1;
|
||||
ip_addr_mem[wr_ptr_reg] <= write_ip_reg;
|
||||
mac_addr_mem[wr_ptr_reg] <= write_mac_reg;
|
||||
end
|
||||
end
|
||||
|
||||
|
17
rtl/ip.v
17
rtl/ip.v
@ -66,8 +66,10 @@ module ip
|
||||
* ARP requests
|
||||
*/
|
||||
output wire arp_request_valid,
|
||||
input wire arp_request_ready,
|
||||
output wire [31:0] arp_request_ip,
|
||||
input wire arp_response_valid,
|
||||
output wire arp_response_ready,
|
||||
input wire arp_response_error,
|
||||
input wire [47:0] arp_response_mac,
|
||||
|
||||
@ -242,20 +244,24 @@ reg input_ip_hdr_ready_reg = 1'b0, input_ip_hdr_ready_next;
|
||||
|
||||
reg arp_request_valid_reg = 1'b0, arp_request_valid_next;
|
||||
|
||||
reg arp_response_ready_reg = 1'b0, arp_response_ready_next;
|
||||
|
||||
reg drop_packet_reg = 1'b0, drop_packet_next;
|
||||
|
||||
assign input_ip_hdr_ready = input_ip_hdr_ready_reg;
|
||||
assign input_ip_payload_tready = outgoing_ip_payload_tready | drop_packet_reg;
|
||||
|
||||
assign arp_request_valid = arp_request_valid_reg | (input_ip_hdr_valid & ~input_ip_hdr_ready_reg);
|
||||
assign arp_request_valid = arp_request_valid_reg;
|
||||
assign arp_request_ip = input_ip_dest_ip;
|
||||
assign arp_response_ready = arp_response_ready_reg;
|
||||
|
||||
assign tx_error_arp_failed = arp_response_error;
|
||||
|
||||
always @* begin
|
||||
state_next = STATE_IDLE;
|
||||
|
||||
arp_request_valid_next = 1'b0;
|
||||
arp_request_valid_next = arp_request_valid_reg & ~arp_request_ready;
|
||||
arp_response_ready_next = 1'b0;
|
||||
drop_packet_next = 1'b0;
|
||||
|
||||
input_ip_hdr_ready_next = 1'b0;
|
||||
@ -269,26 +275,25 @@ always @* begin
|
||||
if (input_ip_hdr_valid) begin
|
||||
// initiate ARP request
|
||||
arp_request_valid_next = 1'b1;
|
||||
arp_response_ready_next = 1'b1;
|
||||
state_next = STATE_ARP_QUERY;
|
||||
end else begin
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
STATE_ARP_QUERY: begin
|
||||
arp_request_valid_next = 1;
|
||||
arp_response_ready_next = 1'b1;
|
||||
|
||||
if (arp_response_valid) begin
|
||||
// wait for ARP reponse
|
||||
if (arp_response_error) begin
|
||||
// did not get MAC address; drop packet
|
||||
input_ip_hdr_ready_next = 1'b1;
|
||||
arp_request_valid_next = 1'b0;
|
||||
drop_packet_next = 1'b1;
|
||||
state_next = STATE_WAIT_PACKET;
|
||||
end else begin
|
||||
// got MAC address; send packet
|
||||
input_ip_hdr_ready_next = 1'b1;
|
||||
arp_request_valid_next = 1'b0;
|
||||
outgoing_ip_hdr_valid_next = 1'b1;
|
||||
outgoing_eth_dest_mac_next = arp_response_mac;
|
||||
state_next = STATE_WAIT_PACKET;
|
||||
@ -314,6 +319,7 @@ always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
state_reg <= STATE_IDLE;
|
||||
arp_request_valid_reg <= 1'b0;
|
||||
arp_response_ready_reg <= 1'b0;
|
||||
drop_packet_reg <= 1'b0;
|
||||
input_ip_hdr_ready_reg <= 1'b0;
|
||||
outgoing_ip_hdr_valid_reg <= 1'b0;
|
||||
@ -321,6 +327,7 @@ always @(posedge clk) begin
|
||||
state_reg <= state_next;
|
||||
|
||||
arp_request_valid_reg <= arp_request_valid_next;
|
||||
arp_response_ready_reg <= arp_response_ready_next;
|
||||
drop_packet_reg <= drop_packet_next;
|
||||
|
||||
input_ip_hdr_ready_reg <= input_ip_hdr_ready_next;
|
||||
|
18
rtl/ip_64.v
18
rtl/ip_64.v
@ -68,8 +68,10 @@ module ip_64
|
||||
* ARP requests
|
||||
*/
|
||||
output wire arp_request_valid,
|
||||
input wire arp_request_ready,
|
||||
output wire [31:0] arp_request_ip,
|
||||
input wire arp_response_valid,
|
||||
output wire arp_response_ready,
|
||||
input wire arp_response_error,
|
||||
input wire [47:0] arp_response_mac,
|
||||
|
||||
@ -246,25 +248,28 @@ ip_eth_tx_64_inst (
|
||||
.error_payload_early_termination(tx_error_payload_early_termination)
|
||||
);
|
||||
|
||||
|
||||
reg input_ip_hdr_ready_reg = 1'b0, input_ip_hdr_ready_next;
|
||||
|
||||
reg arp_request_valid_reg = 1'b0, arp_request_valid_next;
|
||||
|
||||
reg arp_response_ready_reg = 1'b0, arp_response_ready_next;
|
||||
|
||||
reg drop_packet_reg = 1'b0, drop_packet_next;
|
||||
|
||||
assign input_ip_hdr_ready = input_ip_hdr_ready_reg;
|
||||
assign input_ip_payload_tready = outgoing_ip_payload_tready | drop_packet_reg;
|
||||
|
||||
assign arp_request_valid = arp_request_valid_reg | (input_ip_hdr_valid & ~input_ip_hdr_ready_reg);
|
||||
assign arp_request_valid = arp_request_valid_reg;
|
||||
assign arp_request_ip = input_ip_dest_ip;
|
||||
assign arp_response_ready = arp_response_ready_reg;
|
||||
|
||||
assign tx_error_arp_failed = arp_response_error;
|
||||
|
||||
always @* begin
|
||||
state_next = STATE_IDLE;
|
||||
|
||||
arp_request_valid_next = 1'b0;
|
||||
arp_request_valid_next = arp_request_valid_reg & ~arp_request_ready;
|
||||
arp_response_ready_next = 1'b0;
|
||||
drop_packet_next = 1'b0;
|
||||
|
||||
input_ip_hdr_ready_next = 1'b0;
|
||||
@ -278,26 +283,25 @@ always @* begin
|
||||
if (input_ip_hdr_valid) begin
|
||||
// initiate ARP request
|
||||
arp_request_valid_next = 1'b1;
|
||||
arp_response_ready_next = 1'b1;
|
||||
state_next = STATE_ARP_QUERY;
|
||||
end else begin
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
STATE_ARP_QUERY: begin
|
||||
arp_request_valid_next = 1'b1;
|
||||
arp_response_ready_next = 1'b1;
|
||||
|
||||
if (arp_response_valid) begin
|
||||
// wait for ARP reponse
|
||||
if (arp_response_error) begin
|
||||
// did not get MAC address; drop packet
|
||||
input_ip_hdr_ready_next = 1'b1;
|
||||
arp_request_valid_next = 1'b0;
|
||||
drop_packet_next = 1'b1;
|
||||
state_next = STATE_WAIT_PACKET;
|
||||
end else begin
|
||||
// got MAC address; send packet
|
||||
input_ip_hdr_ready_next = 1'b1;
|
||||
arp_request_valid_next = 1'b0;
|
||||
outgoing_ip_hdr_valid_next = 1'b1;
|
||||
outgoing_eth_dest_mac_next = arp_response_mac;
|
||||
state_next = STATE_WAIT_PACKET;
|
||||
@ -323,6 +327,7 @@ always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
state_reg <= STATE_IDLE;
|
||||
arp_request_valid_reg <= 1'b0;
|
||||
arp_response_ready_reg <= 1'b0;
|
||||
drop_packet_reg <= 1'b0;
|
||||
input_ip_hdr_ready_reg <= 1'b0;
|
||||
outgoing_ip_hdr_valid_reg <= 1'b0;
|
||||
@ -330,6 +335,7 @@ always @(posedge clk) begin
|
||||
state_reg <= state_next;
|
||||
|
||||
arp_request_valid_reg <= arp_request_valid_next;
|
||||
arp_response_ready_reg <= arp_response_ready_next;
|
||||
drop_packet_reg <= drop_packet_next;
|
||||
|
||||
input_ip_hdr_ready_reg <= input_ip_hdr_ready_next;
|
||||
|
@ -30,7 +30,7 @@ THE SOFTWARE.
|
||||
* IPv4 and ARP block, ethernet frame interface
|
||||
*/
|
||||
module ip_complete #(
|
||||
parameter ARP_CACHE_ADDR_WIDTH = 2,
|
||||
parameter ARP_CACHE_ADDR_WIDTH = 9,
|
||||
parameter ARP_REQUEST_RETRY_COUNT = 4,
|
||||
parameter ARP_REQUEST_RETRY_INTERVAL = 125000000*2,
|
||||
parameter ARP_REQUEST_TIMEOUT = 125000000*30
|
||||
@ -141,8 +141,10 @@ This module integrates the IP and ARP modules for a complete IP stack
|
||||
*/
|
||||
|
||||
wire arp_request_valid;
|
||||
wire arp_request_ready;
|
||||
wire [31:0] arp_request_ip;
|
||||
wire arp_response_valid;
|
||||
wire arp_response_ready;
|
||||
wire arp_response_error;
|
||||
wire [47:0] arp_response_mac;
|
||||
|
||||
@ -361,8 +363,10 @@ ip_inst (
|
||||
.input_ip_payload_tuser(input_ip_payload_tuser),
|
||||
// ARP requests
|
||||
.arp_request_valid(arp_request_valid),
|
||||
.arp_request_ready(arp_request_ready),
|
||||
.arp_request_ip(arp_request_ip),
|
||||
.arp_response_valid(arp_response_valid),
|
||||
.arp_response_ready(arp_response_ready),
|
||||
.arp_response_error(arp_response_error),
|
||||
.arp_response_mac(arp_response_mac),
|
||||
// Status
|
||||
@ -415,8 +419,10 @@ arp_inst (
|
||||
.output_eth_payload_tuser(arp_tx_eth_payload_tuser),
|
||||
// ARP requests
|
||||
.arp_request_valid(arp_request_valid),
|
||||
.arp_request_ready(arp_request_ready),
|
||||
.arp_request_ip(arp_request_ip),
|
||||
.arp_response_valid(arp_response_valid),
|
||||
.arp_response_ready(arp_response_ready),
|
||||
.arp_response_error(arp_response_error),
|
||||
.arp_response_mac(arp_response_mac),
|
||||
// Configuration
|
||||
|
@ -30,7 +30,7 @@ THE SOFTWARE.
|
||||
* IPv4 and ARP block, ethernet frame interface (64 bit datapath)
|
||||
*/
|
||||
module ip_complete_64 #(
|
||||
parameter ARP_CACHE_ADDR_WIDTH = 2,
|
||||
parameter ARP_CACHE_ADDR_WIDTH = 9,
|
||||
parameter ARP_REQUEST_RETRY_COUNT = 4,
|
||||
parameter ARP_REQUEST_RETRY_INTERVAL = 156250000*2,
|
||||
parameter ARP_REQUEST_TIMEOUT = 156250000*30
|
||||
@ -145,8 +145,10 @@ This module integrates the IP and ARP modules for a complete IP stack
|
||||
*/
|
||||
|
||||
wire arp_request_valid;
|
||||
wire arp_request_ready;
|
||||
wire [31:0] arp_request_ip;
|
||||
wire arp_response_valid;
|
||||
wire arp_response_ready;
|
||||
wire arp_response_error;
|
||||
wire [47:0] arp_response_mac;
|
||||
|
||||
@ -378,8 +380,10 @@ ip_inst (
|
||||
.input_ip_payload_tuser(input_ip_payload_tuser),
|
||||
// ARP requests
|
||||
.arp_request_valid(arp_request_valid),
|
||||
.arp_request_ready(arp_request_ready),
|
||||
.arp_request_ip(arp_request_ip),
|
||||
.arp_response_valid(arp_response_valid),
|
||||
.arp_response_ready(arp_response_ready),
|
||||
.arp_response_error(arp_response_error),
|
||||
.arp_response_mac(arp_response_mac),
|
||||
// Status
|
||||
@ -434,8 +438,10 @@ arp_inst (
|
||||
.output_eth_payload_tuser(arp_tx_eth_payload_tuser),
|
||||
// ARP requests
|
||||
.arp_request_valid(arp_request_valid),
|
||||
.arp_request_ready(arp_request_ready),
|
||||
.arp_request_ip(arp_request_ip),
|
||||
.arp_response_valid(arp_response_valid),
|
||||
.arp_response_ready(arp_response_ready),
|
||||
.arp_response_error(arp_response_error),
|
||||
.arp_response_mac(arp_response_mac),
|
||||
// Configuration
|
||||
|
@ -30,7 +30,7 @@ THE SOFTWARE.
|
||||
* IPv4 and ARP block with UDP support, ethernet frame interface
|
||||
*/
|
||||
module udp_complete #(
|
||||
parameter ARP_CACHE_ADDR_WIDTH = 2,
|
||||
parameter ARP_CACHE_ADDR_WIDTH = 9,
|
||||
parameter ARP_REQUEST_RETRY_COUNT = 4,
|
||||
parameter ARP_REQUEST_RETRY_INTERVAL = 125000000*2,
|
||||
parameter ARP_REQUEST_TIMEOUT = 125000000*30,
|
||||
|
@ -30,7 +30,7 @@ THE SOFTWARE.
|
||||
* IPv4 and ARP block with UDP support, ethernet frame interface (64 bit datapath)
|
||||
*/
|
||||
module udp_complete_64 #(
|
||||
parameter ARP_CACHE_ADDR_WIDTH = 2,
|
||||
parameter ARP_CACHE_ADDR_WIDTH = 9,
|
||||
parameter ARP_REQUEST_RETRY_COUNT = 4,
|
||||
parameter ARP_REQUEST_RETRY_INTERVAL = 125000000*2,
|
||||
parameter ARP_REQUEST_TIMEOUT = 125000000*30,
|
||||
|
175
tb/test_arp.py
175
tb/test_arp.py
@ -26,6 +26,7 @@ THE SOFTWARE.
|
||||
from myhdl import *
|
||||
import os
|
||||
|
||||
import axis_ep
|
||||
import eth_ep
|
||||
import arp_ep
|
||||
|
||||
@ -35,6 +36,7 @@ testbench = 'test_%s' % module
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("../rtl/lfsr.v")
|
||||
srcs.append("../rtl/arp_cache.v")
|
||||
srcs.append("../rtl/arp_eth_rx.v")
|
||||
srcs.append("../rtl/arp_eth_tx.v")
|
||||
@ -65,6 +67,7 @@ def bench():
|
||||
|
||||
arp_request_valid = Signal(bool(0))
|
||||
arp_request_ip = Signal(intbv(0)[32:])
|
||||
arp_response_ready = Signal(bool(0))
|
||||
|
||||
local_mac = Signal(intbv(0)[48:])
|
||||
local_ip = Signal(intbv(0)[32:])
|
||||
@ -85,17 +88,18 @@ def bench():
|
||||
output_eth_payload_tlast = Signal(bool(0))
|
||||
output_eth_payload_tuser = Signal(bool(0))
|
||||
|
||||
arp_request_ready = Signal(bool(0))
|
||||
arp_response_valid = Signal(bool(0))
|
||||
arp_response_error = Signal(bool(0))
|
||||
arp_response_mac = Signal(intbv(0)[48:])
|
||||
|
||||
# sources and sinks
|
||||
source_pause = Signal(bool(0))
|
||||
sink_pause = Signal(bool(0))
|
||||
eth_source_pause = Signal(bool(0))
|
||||
eth_sink_pause = Signal(bool(0))
|
||||
|
||||
source = eth_ep.EthFrameSource()
|
||||
eth_source = eth_ep.EthFrameSource()
|
||||
|
||||
source_logic = source.create_logic(
|
||||
eth_source_logic = eth_source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
eth_hdr_ready=input_eth_hdr_ready,
|
||||
@ -108,13 +112,13 @@ def bench():
|
||||
eth_payload_tready=input_eth_payload_tready,
|
||||
eth_payload_tlast=input_eth_payload_tlast,
|
||||
eth_payload_tuser=input_eth_payload_tuser,
|
||||
pause=source_pause,
|
||||
name='source'
|
||||
pause=eth_source_pause,
|
||||
name='eth_source'
|
||||
)
|
||||
|
||||
sink = eth_ep.EthFrameSink()
|
||||
eth_sink = eth_ep.EthFrameSink()
|
||||
|
||||
sink_logic = sink.create_logic(
|
||||
eth_sink_logic = eth_sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
eth_hdr_ready=output_eth_hdr_ready,
|
||||
@ -127,8 +131,30 @@ def bench():
|
||||
eth_payload_tready=output_eth_payload_tready,
|
||||
eth_payload_tlast=output_eth_payload_tlast,
|
||||
eth_payload_tuser=output_eth_payload_tuser,
|
||||
pause=sink_pause,
|
||||
name='sink'
|
||||
pause=eth_sink_pause,
|
||||
name='eth_sink'
|
||||
)
|
||||
|
||||
arp_request_source = axis_ep.AXIStreamSource()
|
||||
|
||||
arp_request_source_logic = arp_request_source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(arp_request_ip,),
|
||||
tvalid=arp_request_valid,
|
||||
tready=arp_request_ready,
|
||||
name='arp_request_source'
|
||||
)
|
||||
|
||||
arp_response_sink = axis_ep.AXIStreamSink()
|
||||
|
||||
arp_response_sink_logic = arp_response_sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(arp_response_error, arp_response_mac),
|
||||
tvalid=arp_response_valid,
|
||||
tready=arp_response_ready,
|
||||
name='arp_response_sink'
|
||||
)
|
||||
|
||||
# DUT
|
||||
@ -164,8 +190,10 @@ def bench():
|
||||
output_eth_payload_tuser=output_eth_payload_tuser,
|
||||
|
||||
arp_request_valid=arp_request_valid,
|
||||
arp_request_ready=arp_request_ready,
|
||||
arp_request_ip=arp_request_ip,
|
||||
arp_response_valid=arp_response_valid,
|
||||
arp_response_ready=arp_response_ready,
|
||||
arp_response_error=arp_response_error,
|
||||
arp_response_mac=arp_response_mac,
|
||||
|
||||
@ -214,14 +242,13 @@ def bench():
|
||||
test_frame.arp_spa = 0xc0a80164
|
||||
test_frame.arp_tha = 0x000000000000
|
||||
test_frame.arp_tpa = 0xc0a80165
|
||||
source.send(test_frame.build_eth())
|
||||
eth_source.send(test_frame.build_eth())
|
||||
yield clk.posedge
|
||||
|
||||
yield output_eth_payload_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
while eth_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = sink.recv()
|
||||
rx_frame = eth_sink.recv()
|
||||
check_frame = arp_ep.ARPFrame()
|
||||
check_frame.parse_eth(rx_frame)
|
||||
|
||||
@ -244,15 +271,15 @@ def bench():
|
||||
print("test 2: Cached read")
|
||||
current_test.next = 2
|
||||
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = True
|
||||
arp_request_ip.next = 0xc0a80164
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = False
|
||||
arp_request_source.send([(0xc0a80164,)])
|
||||
|
||||
yield arp_response_valid.posedge
|
||||
assert not bool(arp_response_error)
|
||||
assert int(arp_response_mac) == 0x5A5152535455
|
||||
while arp_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
err, mac = arp_response_sink.recv().data[0]
|
||||
|
||||
assert not err
|
||||
assert mac == 0x5A5152535455
|
||||
|
||||
yield delay(100)
|
||||
|
||||
@ -260,18 +287,13 @@ def bench():
|
||||
print("test 3: Unached read")
|
||||
current_test.next = 3
|
||||
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = True
|
||||
arp_request_ip.next = 0xc0a80166
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = False
|
||||
arp_request_source.send([(0xc0a80166,)])
|
||||
|
||||
# wait for ARP request packet
|
||||
yield output_eth_payload_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
while eth_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = sink.recv()
|
||||
rx_frame = eth_sink.recv()
|
||||
check_frame = arp_ep.ARPFrame()
|
||||
check_frame.parse_eth(rx_frame)
|
||||
|
||||
@ -302,13 +324,17 @@ def bench():
|
||||
test_frame.arp_spa = 0xc0a80166
|
||||
test_frame.arp_tha = 0xDAD1D2D3D4D5
|
||||
test_frame.arp_tpa = 0xc0a80165
|
||||
source.send(test_frame.build_eth())
|
||||
eth_source.send(test_frame.build_eth())
|
||||
yield clk.posedge
|
||||
|
||||
# wait for lookup
|
||||
yield arp_response_valid.posedge
|
||||
assert not bool(arp_response_error)
|
||||
assert int(arp_response_mac) == 0x6A6162636465
|
||||
while arp_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
err, mac = arp_response_sink.recv().data[0]
|
||||
|
||||
assert not err
|
||||
assert mac == 0x6A6162636465
|
||||
|
||||
yield delay(100)
|
||||
|
||||
@ -316,18 +342,13 @@ def bench():
|
||||
print("test 4: Unached read, outside of subnet")
|
||||
current_test.next = 4
|
||||
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = True
|
||||
arp_request_ip.next = 0x08080808
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = False
|
||||
arp_request_source.send([(0x08080808,)])
|
||||
|
||||
# wait for ARP request packet
|
||||
yield output_eth_payload_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
while eth_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = sink.recv()
|
||||
rx_frame = eth_sink.recv()
|
||||
check_frame = arp_ep.ARPFrame()
|
||||
check_frame.parse_eth(rx_frame)
|
||||
|
||||
@ -358,13 +379,17 @@ def bench():
|
||||
test_frame.arp_spa = 0xc0a80101
|
||||
test_frame.arp_tha = 0xDAD1D2D3D4D5
|
||||
test_frame.arp_tpa = 0xc0a80165
|
||||
source.send(test_frame.build_eth())
|
||||
eth_source.send(test_frame.build_eth())
|
||||
yield clk.posedge
|
||||
|
||||
# wait for lookup
|
||||
yield arp_response_valid.posedge
|
||||
assert not bool(arp_response_error)
|
||||
assert int(arp_response_mac) == 0xAABBCCDDEEFF
|
||||
while arp_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
err, mac = arp_response_sink.recv().data[0]
|
||||
|
||||
assert not err
|
||||
assert mac == 0xAABBCCDDEEFF
|
||||
|
||||
yield delay(100)
|
||||
|
||||
@ -372,20 +397,20 @@ def bench():
|
||||
print("test 5: Unached read, timeout")
|
||||
current_test.next = 5
|
||||
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = True
|
||||
arp_request_ip.next = 0xc0a80167
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = False
|
||||
arp_request_source.send([(0xc0a80167,)])
|
||||
|
||||
yield arp_response_valid.posedge
|
||||
assert bool(arp_response_error)
|
||||
while arp_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
err, mac = arp_response_sink.recv().data[0]
|
||||
|
||||
assert err
|
||||
|
||||
# check for 4 ARP requests
|
||||
assert sink.count() == 4
|
||||
assert eth_sink.count() == 4
|
||||
|
||||
while not sink.empty():
|
||||
rx_frame = sink.recv()
|
||||
while not eth_sink.empty():
|
||||
rx_frame = eth_sink.recv()
|
||||
|
||||
check_frame = arp_ep.ARPFrame()
|
||||
check_frame.parse_eth(rx_frame)
|
||||
@ -410,26 +435,26 @@ def bench():
|
||||
current_test.next = 6
|
||||
|
||||
# subnet broadcast
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = True
|
||||
arp_request_ip.next = 0xc0a801FF
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = False
|
||||
arp_request_source.send([(0xc0a801ff,)])
|
||||
|
||||
yield arp_response_valid.posedge
|
||||
assert not bool(arp_response_error)
|
||||
assert int(arp_response_mac) == 0xFFFFFFFFFFFF
|
||||
while arp_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
err, mac = arp_response_sink.recv().data[0]
|
||||
|
||||
assert not err
|
||||
assert mac == 0xffffffffffff
|
||||
|
||||
# general broadcast
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = True
|
||||
arp_request_ip.next = 0xFFFFFFFF
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = False
|
||||
arp_request_source.send([(0xffffffff,)])
|
||||
|
||||
yield arp_response_valid.posedge
|
||||
assert not bool(arp_response_error)
|
||||
assert int(arp_response_mac) == 0xFFFFFFFFFFFF
|
||||
while arp_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
err, mac = arp_response_sink.recv().data[0]
|
||||
|
||||
assert not err
|
||||
assert mac == 0xffffffffffff
|
||||
|
||||
yield delay(100)
|
||||
|
||||
|
@ -50,6 +50,7 @@ reg output_eth_payload_tready = 0;
|
||||
|
||||
reg arp_request_valid = 0;
|
||||
reg [31:0] arp_request_ip = 0;
|
||||
reg arp_response_ready = 0;
|
||||
|
||||
reg [47:0] local_mac = 0;
|
||||
reg [31:0] local_ip = 0;
|
||||
@ -70,6 +71,7 @@ wire output_eth_payload_tvalid;
|
||||
wire output_eth_payload_tlast;
|
||||
wire output_eth_payload_tuser;
|
||||
|
||||
wire arp_request_ready;
|
||||
wire arp_response_valid;
|
||||
wire arp_response_error;
|
||||
wire [47:0] arp_response_mac;
|
||||
@ -92,6 +94,7 @@ initial begin
|
||||
output_eth_payload_tready,
|
||||
arp_request_valid,
|
||||
arp_request_ip,
|
||||
arp_response_ready,
|
||||
local_mac,
|
||||
local_ip,
|
||||
gateway_ip,
|
||||
@ -109,6 +112,7 @@ initial begin
|
||||
output_eth_payload_tvalid,
|
||||
output_eth_payload_tlast,
|
||||
output_eth_payload_tuser,
|
||||
arp_request_ready,
|
||||
arp_response_valid,
|
||||
arp_response_error,
|
||||
arp_response_mac
|
||||
@ -152,8 +156,10 @@ UUT (
|
||||
.output_eth_payload_tuser(output_eth_payload_tuser),
|
||||
// ARP requests
|
||||
.arp_request_valid(arp_request_valid),
|
||||
.arp_request_ready(arp_request_ready),
|
||||
.arp_request_ip(arp_request_ip),
|
||||
.arp_response_valid(arp_response_valid),
|
||||
.arp_response_ready(arp_response_ready),
|
||||
.arp_response_error(arp_response_error),
|
||||
.arp_response_mac(arp_response_mac),
|
||||
// Configuration
|
||||
|
@ -26,6 +26,7 @@ THE SOFTWARE.
|
||||
from myhdl import *
|
||||
import os
|
||||
|
||||
import axis_ep
|
||||
import eth_ep
|
||||
import arp_ep
|
||||
|
||||
@ -35,6 +36,7 @@ testbench = 'test_%s' % module
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("../rtl/lfsr.v")
|
||||
srcs.append("../rtl/arp_cache.v")
|
||||
srcs.append("../rtl/arp_eth_rx_64.v")
|
||||
srcs.append("../rtl/arp_eth_tx_64.v")
|
||||
@ -66,6 +68,7 @@ def bench():
|
||||
|
||||
arp_request_valid = Signal(bool(0))
|
||||
arp_request_ip = Signal(intbv(0)[32:])
|
||||
arp_response_ready = Signal(bool(0))
|
||||
|
||||
local_mac = Signal(intbv(0)[48:])
|
||||
local_ip = Signal(intbv(0)[32:])
|
||||
@ -87,17 +90,18 @@ def bench():
|
||||
output_eth_payload_tlast = Signal(bool(0))
|
||||
output_eth_payload_tuser = Signal(bool(0))
|
||||
|
||||
arp_request_ready = Signal(bool(0))
|
||||
arp_response_valid = Signal(bool(0))
|
||||
arp_response_error = Signal(bool(0))
|
||||
arp_response_mac = Signal(intbv(0)[48:])
|
||||
|
||||
# sources and sinks
|
||||
source_pause = Signal(bool(0))
|
||||
sink_pause = Signal(bool(0))
|
||||
eth_source_pause = Signal(bool(0))
|
||||
eth_sink_pause = Signal(bool(0))
|
||||
|
||||
source = eth_ep.EthFrameSource()
|
||||
eth_source = eth_ep.EthFrameSource()
|
||||
|
||||
source_logic = source.create_logic(
|
||||
eth_source_logic = eth_source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
eth_hdr_ready=input_eth_hdr_ready,
|
||||
@ -111,13 +115,13 @@ def bench():
|
||||
eth_payload_tready=input_eth_payload_tready,
|
||||
eth_payload_tlast=input_eth_payload_tlast,
|
||||
eth_payload_tuser=input_eth_payload_tuser,
|
||||
pause=source_pause,
|
||||
name='source'
|
||||
pause=eth_source_pause,
|
||||
name='eth_source'
|
||||
)
|
||||
|
||||
sink = eth_ep.EthFrameSink()
|
||||
eth_sink = eth_ep.EthFrameSink()
|
||||
|
||||
sink_logic = sink.create_logic(
|
||||
eth_sink_logic = eth_sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
eth_hdr_ready=output_eth_hdr_ready,
|
||||
@ -131,8 +135,30 @@ def bench():
|
||||
eth_payload_tready=output_eth_payload_tready,
|
||||
eth_payload_tlast=output_eth_payload_tlast,
|
||||
eth_payload_tuser=output_eth_payload_tuser,
|
||||
pause=sink_pause,
|
||||
name='sink'
|
||||
pause=eth_sink_pause,
|
||||
name='eth_sink'
|
||||
)
|
||||
|
||||
arp_request_source = axis_ep.AXIStreamSource()
|
||||
|
||||
arp_request_source_logic = arp_request_source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(arp_request_ip,),
|
||||
tvalid=arp_request_valid,
|
||||
tready=arp_request_ready,
|
||||
name='arp_request_source'
|
||||
)
|
||||
|
||||
arp_response_sink = axis_ep.AXIStreamSink()
|
||||
|
||||
arp_response_sink_logic = arp_response_sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(arp_response_error, arp_response_mac),
|
||||
tvalid=arp_response_valid,
|
||||
tready=arp_response_ready,
|
||||
name='arp_response_sink'
|
||||
)
|
||||
|
||||
# DUT
|
||||
@ -170,8 +196,10 @@ def bench():
|
||||
output_eth_payload_tuser=output_eth_payload_tuser,
|
||||
|
||||
arp_request_valid=arp_request_valid,
|
||||
arp_request_ready=arp_request_ready,
|
||||
arp_request_ip=arp_request_ip,
|
||||
arp_response_valid=arp_response_valid,
|
||||
arp_response_ready=arp_response_ready,
|
||||
arp_response_error=arp_response_error,
|
||||
arp_response_mac=arp_response_mac,
|
||||
|
||||
@ -220,14 +248,13 @@ def bench():
|
||||
test_frame.arp_spa = 0xc0a80164
|
||||
test_frame.arp_tha = 0x000000000000
|
||||
test_frame.arp_tpa = 0xc0a80165
|
||||
source.send(test_frame.build_eth())
|
||||
eth_source.send(test_frame.build_eth())
|
||||
yield clk.posedge
|
||||
|
||||
yield output_eth_payload_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
while eth_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = sink.recv()
|
||||
rx_frame = eth_sink.recv()
|
||||
check_frame = arp_ep.ARPFrame()
|
||||
check_frame.parse_eth(rx_frame)
|
||||
|
||||
@ -250,15 +277,15 @@ def bench():
|
||||
print("test 2: Cached read")
|
||||
current_test.next = 2
|
||||
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = True
|
||||
arp_request_ip.next = 0xc0a80164
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = False
|
||||
arp_request_source.send([(0xc0a80164,)])
|
||||
|
||||
yield arp_response_valid.posedge
|
||||
assert not bool(arp_response_error)
|
||||
assert int(arp_response_mac) == 0x5A5152535455
|
||||
while arp_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
err, mac = arp_response_sink.recv().data[0]
|
||||
|
||||
assert not err
|
||||
assert mac == 0x5A5152535455
|
||||
|
||||
yield delay(100)
|
||||
|
||||
@ -266,18 +293,13 @@ def bench():
|
||||
print("test 3: Unached read")
|
||||
current_test.next = 3
|
||||
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = True
|
||||
arp_request_ip.next = 0xc0a80166
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = False
|
||||
arp_request_source.send([(0xc0a80166,)])
|
||||
|
||||
# wait for ARP request packet
|
||||
yield output_eth_payload_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
while eth_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = sink.recv()
|
||||
rx_frame = eth_sink.recv()
|
||||
check_frame = arp_ep.ARPFrame()
|
||||
check_frame.parse_eth(rx_frame)
|
||||
|
||||
@ -308,13 +330,17 @@ def bench():
|
||||
test_frame.arp_spa = 0xc0a80166
|
||||
test_frame.arp_tha = 0xDAD1D2D3D4D5
|
||||
test_frame.arp_tpa = 0xc0a80165
|
||||
source.send(test_frame.build_eth())
|
||||
eth_source.send(test_frame.build_eth())
|
||||
yield clk.posedge
|
||||
|
||||
# wait for lookup
|
||||
yield arp_response_valid.posedge
|
||||
assert not bool(arp_response_error)
|
||||
assert int(arp_response_mac) == 0x6A6162636465
|
||||
while arp_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
err, mac = arp_response_sink.recv().data[0]
|
||||
|
||||
assert not err
|
||||
assert mac == 0x6A6162636465
|
||||
|
||||
yield delay(100)
|
||||
|
||||
@ -322,18 +348,13 @@ def bench():
|
||||
print("test 4: Unached read, outside of subnet")
|
||||
current_test.next = 4
|
||||
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = True
|
||||
arp_request_ip.next = 0x08080808
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = False
|
||||
arp_request_source.send([(0x08080808,)])
|
||||
|
||||
# wait for ARP request packet
|
||||
yield output_eth_payload_tlast.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
while eth_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
rx_frame = sink.recv()
|
||||
rx_frame = eth_sink.recv()
|
||||
check_frame = arp_ep.ARPFrame()
|
||||
check_frame.parse_eth(rx_frame)
|
||||
|
||||
@ -364,13 +385,17 @@ def bench():
|
||||
test_frame.arp_spa = 0xc0a80101
|
||||
test_frame.arp_tha = 0xDAD1D2D3D4D5
|
||||
test_frame.arp_tpa = 0xc0a80165
|
||||
source.send(test_frame.build_eth())
|
||||
eth_source.send(test_frame.build_eth())
|
||||
yield clk.posedge
|
||||
|
||||
# wait for lookup
|
||||
yield arp_response_valid.posedge
|
||||
assert not bool(arp_response_error)
|
||||
assert int(arp_response_mac) == 0xAABBCCDDEEFF
|
||||
while arp_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
err, mac = arp_response_sink.recv().data[0]
|
||||
|
||||
assert not err
|
||||
assert mac == 0xAABBCCDDEEFF
|
||||
|
||||
yield delay(100)
|
||||
|
||||
@ -378,20 +403,20 @@ def bench():
|
||||
print("test 5: Unached read, timeout")
|
||||
current_test.next = 5
|
||||
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = True
|
||||
arp_request_ip.next = 0xc0a80167
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = False
|
||||
arp_request_source.send([(0xc0a80167,)])
|
||||
|
||||
yield arp_response_valid.posedge
|
||||
assert bool(arp_response_error)
|
||||
while arp_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
err, mac = arp_response_sink.recv().data[0]
|
||||
|
||||
assert err
|
||||
|
||||
# check for 4 ARP requests
|
||||
assert sink.count() == 4
|
||||
assert eth_sink.count() == 4
|
||||
|
||||
while not sink.empty():
|
||||
rx_frame = sink.recv()
|
||||
while not eth_sink.empty():
|
||||
rx_frame = eth_sink.recv()
|
||||
|
||||
check_frame = arp_ep.ARPFrame()
|
||||
check_frame.parse_eth(rx_frame)
|
||||
@ -416,26 +441,26 @@ def bench():
|
||||
current_test.next = 6
|
||||
|
||||
# subnet broadcast
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = True
|
||||
arp_request_ip.next = 0xc0a801FF
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = False
|
||||
arp_request_source.send([(0xc0a801ff,)])
|
||||
|
||||
yield arp_response_valid.posedge
|
||||
assert not bool(arp_response_error)
|
||||
assert int(arp_response_mac) == 0xFFFFFFFFFFFF
|
||||
while arp_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
err, mac = arp_response_sink.recv().data[0]
|
||||
|
||||
assert not err
|
||||
assert mac == 0xffffffffffff
|
||||
|
||||
# general broadcast
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = True
|
||||
arp_request_ip.next = 0xFFFFFFFF
|
||||
yield clk.posedge
|
||||
arp_request_valid.next = False
|
||||
arp_request_source.send([(0xffffffff,)])
|
||||
|
||||
yield arp_response_valid.posedge
|
||||
assert not bool(arp_response_error)
|
||||
assert int(arp_response_mac) == 0xFFFFFFFFFFFF
|
||||
while arp_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
err, mac = arp_response_sink.recv().data[0]
|
||||
|
||||
assert not err
|
||||
assert mac == 0xffffffffffff
|
||||
|
||||
yield delay(100)
|
||||
|
||||
|
@ -51,6 +51,7 @@ reg output_eth_payload_tready = 0;
|
||||
|
||||
reg arp_request_valid = 0;
|
||||
reg [31:0] arp_request_ip = 0;
|
||||
reg arp_response_ready = 0;
|
||||
|
||||
reg [47:0] local_mac = 0;
|
||||
reg [31:0] local_ip = 0;
|
||||
@ -72,6 +73,7 @@ wire output_eth_payload_tvalid;
|
||||
wire output_eth_payload_tlast;
|
||||
wire output_eth_payload_tuser;
|
||||
|
||||
wire arp_request_ready;
|
||||
wire arp_response_valid;
|
||||
wire arp_response_error;
|
||||
wire [47:0] arp_response_mac;
|
||||
@ -95,6 +97,7 @@ initial begin
|
||||
output_eth_payload_tready,
|
||||
arp_request_valid,
|
||||
arp_request_ip,
|
||||
arp_response_ready,
|
||||
local_mac,
|
||||
local_ip,
|
||||
gateway_ip,
|
||||
@ -113,6 +116,7 @@ initial begin
|
||||
output_eth_payload_tvalid,
|
||||
output_eth_payload_tlast,
|
||||
output_eth_payload_tuser,
|
||||
arp_request_ready,
|
||||
arp_response_valid,
|
||||
arp_response_error,
|
||||
arp_response_mac
|
||||
@ -158,8 +162,10 @@ UUT (
|
||||
.output_eth_payload_tuser(output_eth_payload_tuser),
|
||||
// ARP requests
|
||||
.arp_request_valid(arp_request_valid),
|
||||
.arp_request_ready(arp_request_ready),
|
||||
.arp_request_ip(arp_request_ip),
|
||||
.arp_response_valid(arp_response_valid),
|
||||
.arp_response_ready(arp_response_ready),
|
||||
.arp_response_error(arp_response_error),
|
||||
.arp_response_mac(arp_response_mac),
|
||||
// Configuration
|
||||
|
@ -26,12 +26,15 @@ THE SOFTWARE.
|
||||
from myhdl import *
|
||||
import os
|
||||
|
||||
import axis_ep
|
||||
|
||||
module = 'arp_cache'
|
||||
testbench = 'test_%s' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("../rtl/lfsr.v")
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
@ -48,6 +51,8 @@ def bench():
|
||||
query_request_valid = Signal(bool(0))
|
||||
query_request_ip = Signal(intbv(0)[32:])
|
||||
|
||||
query_response_ready = Signal(bool(0))
|
||||
|
||||
write_request_valid = Signal(bool(0))
|
||||
write_request_ip = Signal(intbv(0)[32:])
|
||||
write_request_mac = Signal(intbv(0)[48:])
|
||||
@ -55,12 +60,55 @@ def bench():
|
||||
clear_cache = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
query_request_ready = Signal(bool(0))
|
||||
|
||||
query_response_valid = Signal(bool(0))
|
||||
query_response_error = Signal(bool(0))
|
||||
query_response_mac = Signal(intbv(0)[48:])
|
||||
|
||||
write_in_progress = Signal(bool(0))
|
||||
write_complete = Signal(bool(0))
|
||||
write_request_ready = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
query_request_source_pause = Signal(bool(0))
|
||||
query_response_sink_pause = Signal(bool(0))
|
||||
write_request_source_pause = Signal(bool(0))
|
||||
|
||||
query_request_source = axis_ep.AXIStreamSource()
|
||||
|
||||
query_request_source_logic = query_request_source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(query_request_ip,),
|
||||
tvalid=query_request_valid,
|
||||
tready=query_request_ready,
|
||||
pause=query_request_source_pause,
|
||||
name='query_request_source'
|
||||
)
|
||||
|
||||
query_response_sink = axis_ep.AXIStreamSink()
|
||||
|
||||
query_response_sink_logic = query_response_sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(query_response_mac,),
|
||||
tvalid=query_response_valid,
|
||||
tready=query_response_ready,
|
||||
tuser=query_response_error,
|
||||
pause=query_response_sink_pause,
|
||||
name='query_response_sink'
|
||||
)
|
||||
|
||||
write_request_source = axis_ep.AXIStreamSource()
|
||||
|
||||
write_request_source_logic = write_request_source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(write_request_ip, write_request_mac),
|
||||
tvalid=write_request_valid,
|
||||
tready=write_request_ready,
|
||||
pause=write_request_source_pause,
|
||||
name='write_request_source'
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
@ -73,16 +121,18 @@ def bench():
|
||||
current_test=current_test,
|
||||
|
||||
query_request_valid=query_request_valid,
|
||||
query_request_ready=query_request_ready,
|
||||
query_request_ip=query_request_ip,
|
||||
|
||||
query_response_valid=query_response_valid,
|
||||
query_response_ready=query_response_ready,
|
||||
query_response_error=query_response_error,
|
||||
query_response_mac=query_response_mac,
|
||||
|
||||
write_request_valid=write_request_valid,
|
||||
write_request_ready=write_request_ready,
|
||||
write_request_ip=write_request_ip,
|
||||
write_request_mac=write_request_mac,
|
||||
write_in_progress=write_in_progress,
|
||||
write_complete=write_complete,
|
||||
|
||||
clear_cache=clear_cache
|
||||
)
|
||||
@ -107,24 +157,13 @@ def bench():
|
||||
current_test.next = 1
|
||||
|
||||
yield clk.posedge
|
||||
write_request_valid.next = True
|
||||
write_request_ip.next = 0xc0a80111
|
||||
write_request_mac.next = 0x0000c0a80111
|
||||
yield clk.posedge
|
||||
write_request_valid.next = False
|
||||
write_request_source.send([(0xc0a80111, 0x0000c0a80111)])
|
||||
write_request_source.send([(0xc0a80112, 0x0000c0a80112)])
|
||||
|
||||
yield write_complete.posedge
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
write_request_valid.next = True
|
||||
write_request_ip.next = 0xc0a80112
|
||||
write_request_mac.next = 0x0000c0a80112
|
||||
yield clk.posedge
|
||||
write_request_valid.next = False
|
||||
|
||||
yield write_complete.posedge
|
||||
yield clk.posedge
|
||||
while not write_request_source.empty():
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(100)
|
||||
|
||||
@ -133,71 +172,47 @@ def bench():
|
||||
current_test.next = 2
|
||||
|
||||
yield clk.posedge
|
||||
query_request_valid.next = True
|
||||
query_request_ip.next = 0xc0a80111
|
||||
yield clk.posedge
|
||||
query_request_valid.next = False
|
||||
query_request_source.send([(0xc0a80111, )])
|
||||
query_request_source.send([(0xc0a80112, )])
|
||||
query_request_source.send([(0xc0a80113, )])
|
||||
|
||||
yield query_response_valid.posedge
|
||||
assert not bool(query_response_error)
|
||||
assert int(query_response_mac) == 0x0000c0a80111
|
||||
while query_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
query_request_valid.next = True
|
||||
query_request_ip.next = 0xc0a80112
|
||||
yield clk.posedge
|
||||
query_request_valid.next = False
|
||||
resp = query_response_sink.recv()
|
||||
assert resp.data[0][0] == 0x0000c0a80111
|
||||
assert not resp.user[0]
|
||||
|
||||
yield query_response_valid.posedge
|
||||
assert not bool(query_response_error)
|
||||
assert int(query_response_mac) == 0x0000c0a80112
|
||||
while query_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
resp = query_response_sink.recv()
|
||||
assert resp.data[0][0] == 0x0000c0a80112
|
||||
assert not resp.user[0]
|
||||
|
||||
# not in cache; was not written
|
||||
yield clk.posedge
|
||||
query_request_valid.next = True
|
||||
query_request_ip.next = 0xc0a80113
|
||||
yield clk.posedge
|
||||
query_request_valid.next = False
|
||||
while query_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
yield query_response_valid.posedge
|
||||
assert bool(query_response_error)
|
||||
resp = query_response_sink.recv()
|
||||
assert resp.user[0]
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: write more")
|
||||
current_test.next = 3
|
||||
|
||||
yield clk.posedge
|
||||
write_request_valid.next = True
|
||||
write_request_ip.next = 0xc0a80121
|
||||
write_request_mac.next = 0x0000c0a80121
|
||||
yield clk.posedge
|
||||
write_request_valid.next = False
|
||||
|
||||
yield write_complete.posedge
|
||||
yield clk.posedge
|
||||
|
||||
yield clk.posedge
|
||||
write_request_valid.next = True
|
||||
write_request_ip.next = 0xc0a80122
|
||||
write_request_mac.next = 0x0000c0a80122
|
||||
yield clk.posedge
|
||||
write_request_valid.next = False
|
||||
|
||||
yield write_complete.posedge
|
||||
yield clk.posedge
|
||||
|
||||
write_request_source.send([(0xc0a80121, 0x0000c0a80121)])
|
||||
write_request_source.send([(0xc0a80122, 0x0000c0a80122)])
|
||||
# overwrites 0xc0a80121 due to LRU
|
||||
yield clk.posedge
|
||||
write_request_valid.next = True
|
||||
write_request_ip.next = 0xc0a80123
|
||||
write_request_mac.next = 0x0000c0a80123
|
||||
yield clk.posedge
|
||||
write_request_valid.next = False
|
||||
write_request_source.send([(0xc0a80123, 0x0000c0a80123)])
|
||||
|
||||
yield write_complete.posedge
|
||||
yield clk.posedge
|
||||
while not write_request_source.empty():
|
||||
yield clk.posedge
|
||||
|
||||
yield delay(100)
|
||||
|
||||
@ -206,59 +221,61 @@ def bench():
|
||||
current_test.next = 4
|
||||
|
||||
yield clk.posedge
|
||||
query_request_valid.next = True
|
||||
query_request_ip.next = 0xc0a80111
|
||||
yield clk.posedge
|
||||
query_request_valid.next = False
|
||||
query_request_source.send([(0xc0a80111, )])
|
||||
|
||||
yield query_response_valid.posedge
|
||||
assert not bool(query_response_error)
|
||||
assert int(query_response_mac) == 0x0000c0a80111
|
||||
while query_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
resp = query_response_sink.recv()
|
||||
assert resp.data[0][0] == 0x0000c0a80111
|
||||
assert not resp.user[0]
|
||||
|
||||
yield clk.posedge
|
||||
query_request_valid.next = True
|
||||
query_request_ip.next = 0xc0a80112
|
||||
yield clk.posedge
|
||||
query_request_valid.next = False
|
||||
query_request_source.send([(0xc0a80112, )])
|
||||
|
||||
yield query_response_valid.posedge
|
||||
assert not bool(query_response_error)
|
||||
assert int(query_response_mac) == 0x0000c0a80112
|
||||
while query_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
resp = query_response_sink.recv()
|
||||
assert resp.data[0][0] == 0x0000c0a80112
|
||||
assert not resp.user[0]
|
||||
|
||||
# not in cache; was overwritten
|
||||
yield clk.posedge
|
||||
query_request_valid.next = True
|
||||
query_request_ip.next = 0xc0a80121
|
||||
yield clk.posedge
|
||||
query_request_valid.next = False
|
||||
query_request_source.send([(0xc0a80121, )])
|
||||
|
||||
yield query_response_valid.posedge
|
||||
assert bool(query_response_error)
|
||||
while query_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
resp = query_response_sink.recv()
|
||||
assert resp.user[0]
|
||||
|
||||
yield clk.posedge
|
||||
query_request_valid.next = True
|
||||
query_request_ip.next = 0xc0a80122
|
||||
yield clk.posedge
|
||||
query_request_valid.next = False
|
||||
query_request_source.send([(0xc0a80122, )])
|
||||
|
||||
yield query_response_valid.posedge
|
||||
assert not bool(query_response_error)
|
||||
assert int(query_response_mac) == 0x0000c0a80122
|
||||
while query_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
resp = query_response_sink.recv()
|
||||
assert resp.data[0][0] == 0x0000c0a80122
|
||||
assert not resp.user[0]
|
||||
|
||||
yield clk.posedge
|
||||
query_request_valid.next = True
|
||||
query_request_ip.next = 0xc0a80123
|
||||
yield clk.posedge
|
||||
query_request_valid.next = False
|
||||
query_request_source.send([(0xc0a80123, )])
|
||||
|
||||
yield query_response_valid.posedge
|
||||
assert not bool(query_response_error)
|
||||
assert int(query_response_mac) == 0x0000c0a80123
|
||||
while query_response_sink.empty():
|
||||
yield clk.posedge
|
||||
|
||||
resp = query_response_sink.recv()
|
||||
assert resp.data[0][0] == 0x0000c0a80123
|
||||
assert not resp.user[0]
|
||||
|
||||
# LRU reset by previous operation
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
yield clk.posedge
|
||||
print("test 5: LRU test")
|
||||
current_test.next = 5
|
||||
|
@ -39,6 +39,8 @@ reg [7:0] current_test = 0;
|
||||
reg query_request_valid = 0;
|
||||
reg [31:0] query_request_ip = 0;
|
||||
|
||||
reg query_response_ready = 0;
|
||||
|
||||
reg write_request_valid = 0;
|
||||
reg [31:0] write_request_ip = 0;
|
||||
reg [47:0] write_request_mac = 0;
|
||||
@ -46,12 +48,13 @@ reg [47:0] write_request_mac = 0;
|
||||
reg clear_cache = 0;
|
||||
|
||||
// Outputs
|
||||
wire query_request_ready;
|
||||
|
||||
wire query_response_valid;
|
||||
wire query_response_error;
|
||||
wire [47:0] query_response_mac;
|
||||
|
||||
wire write_in_progress;
|
||||
wire write_complete;
|
||||
wire write_request_ready;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
@ -61,17 +64,18 @@ initial begin
|
||||
current_test,
|
||||
query_request_valid,
|
||||
query_request_ip,
|
||||
query_response_ready,
|
||||
write_request_valid,
|
||||
write_request_ip,
|
||||
write_request_mac,
|
||||
clear_cache
|
||||
);
|
||||
$to_myhdl(
|
||||
query_request_ready,
|
||||
query_response_valid,
|
||||
query_response_error,
|
||||
query_response_mac,
|
||||
write_in_progress,
|
||||
write_complete
|
||||
write_request_ready
|
||||
);
|
||||
|
||||
// dump file
|
||||
@ -87,16 +91,17 @@ UUT (
|
||||
.rst(rst),
|
||||
// Query cache
|
||||
.query_request_valid(query_request_valid),
|
||||
.query_request_ready(query_request_ready),
|
||||
.query_request_ip(query_request_ip),
|
||||
.query_response_valid(query_response_valid),
|
||||
.query_response_ready(query_response_ready),
|
||||
.query_response_error(query_response_error),
|
||||
.query_response_mac(query_response_mac),
|
||||
// Write cache
|
||||
.write_request_valid(write_request_valid),
|
||||
.write_request_ready(write_request_ready),
|
||||
.write_request_ip(write_request_ip),
|
||||
.write_request_mac(write_request_mac),
|
||||
.write_in_progress(write_in_progress),
|
||||
.write_complete(write_complete),
|
||||
// Configuration
|
||||
.clear_cache(clear_cache)
|
||||
);
|
||||
|
@ -26,6 +26,7 @@ THE SOFTWARE.
|
||||
from myhdl import *
|
||||
import os
|
||||
|
||||
import axis_ep
|
||||
import eth_ep
|
||||
import ip_ep
|
||||
|
||||
@ -58,6 +59,7 @@ def bench():
|
||||
input_eth_payload_tvalid = Signal(bool(0))
|
||||
input_eth_payload_tlast = Signal(bool(0))
|
||||
input_eth_payload_tuser = Signal(bool(0))
|
||||
arp_request_ready = Signal(bool(0))
|
||||
arp_response_valid = Signal(bool(0))
|
||||
arp_response_error = Signal(bool(0))
|
||||
arp_response_mac = Signal(intbv(0)[48:])
|
||||
@ -93,6 +95,7 @@ def bench():
|
||||
output_eth_payload_tuser = Signal(bool(0))
|
||||
arp_request_valid = Signal(bool(0))
|
||||
arp_request_ip = Signal(intbv(0)[32:])
|
||||
arp_response_ready = Signal(bool(0))
|
||||
output_ip_hdr_valid = Signal(bool(0))
|
||||
output_ip_eth_dest_mac = Signal(intbv(0)[48:])
|
||||
output_ip_eth_src_mac = Signal(intbv(0)[48:])
|
||||
@ -224,6 +227,28 @@ def bench():
|
||||
name='ip_sink'
|
||||
)
|
||||
|
||||
arp_request_sink = axis_ep.AXIStreamSink()
|
||||
|
||||
arp_request_sink_logic = arp_request_sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(arp_request_ip,),
|
||||
tvalid=arp_request_valid,
|
||||
tready=arp_request_ready,
|
||||
name='arp_request_sink'
|
||||
)
|
||||
|
||||
arp_response_source = axis_ep.AXIStreamSource()
|
||||
|
||||
arp_response_source_logic = arp_response_source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(arp_response_error, arp_response_mac),
|
||||
tvalid=arp_response_valid,
|
||||
tready=arp_response_ready,
|
||||
name='arp_response_source'
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
@ -257,8 +282,10 @@ def bench():
|
||||
output_eth_payload_tuser=output_eth_payload_tuser,
|
||||
|
||||
arp_request_valid=arp_request_valid,
|
||||
arp_request_ready=arp_request_ready,
|
||||
arp_request_ip=arp_request_ip,
|
||||
arp_response_valid=arp_response_valid,
|
||||
arp_response_ready=arp_response_ready,
|
||||
arp_response_error=arp_response_error,
|
||||
arp_response_mac=arp_response_mac,
|
||||
|
||||
@ -325,17 +352,13 @@ def bench():
|
||||
while True:
|
||||
yield clk.posedge
|
||||
|
||||
arp_response_valid.next = 0
|
||||
arp_response_error.next = 0
|
||||
arp_response_mac.next = 0
|
||||
if not arp_request_sink.empty():
|
||||
req_ip = arp_request_sink.recv().data[0][0]
|
||||
|
||||
if arp_request_valid:
|
||||
if int(arp_request_ip) in arp_table:
|
||||
arp_response_valid.next = 1
|
||||
arp_response_mac.next = arp_table[int(arp_request_ip)]
|
||||
if req_ip in arp_table:
|
||||
arp_response_source.send([(0, arp_table[req_ip])])
|
||||
else:
|
||||
arp_response_valid.next = 1
|
||||
arp_response_error.next = 1
|
||||
arp_response_source.send([(1, 0)])
|
||||
|
||||
rx_error_header_early_termination_asserted = Signal(bool(0))
|
||||
rx_error_payload_early_termination_asserted = Signal(bool(0))
|
||||
|
@ -44,6 +44,7 @@ reg [7:0] input_eth_payload_tdata = 0;
|
||||
reg input_eth_payload_tvalid = 0;
|
||||
reg input_eth_payload_tlast = 0;
|
||||
reg input_eth_payload_tuser = 0;
|
||||
reg arp_request_ready = 0;
|
||||
reg arp_response_valid = 0;
|
||||
reg arp_response_error = 0;
|
||||
reg [47:0] arp_response_mac = 0;
|
||||
@ -81,6 +82,7 @@ wire output_eth_payload_tlast;
|
||||
wire output_eth_payload_tuser;
|
||||
wire arp_request_valid;
|
||||
wire [31:0] arp_request_ip;
|
||||
wire arp_response_ready;
|
||||
wire output_ip_hdr_valid;
|
||||
wire [47:0] output_ip_eth_dest_mac;
|
||||
wire [47:0] output_ip_eth_src_mac;
|
||||
@ -125,6 +127,7 @@ initial begin
|
||||
input_eth_payload_tvalid,
|
||||
input_eth_payload_tlast,
|
||||
input_eth_payload_tuser,
|
||||
arp_request_ready,
|
||||
arp_response_valid,
|
||||
arp_response_error,
|
||||
arp_response_mac,
|
||||
@ -162,6 +165,7 @@ initial begin
|
||||
output_eth_payload_tuser,
|
||||
arp_request_valid,
|
||||
arp_request_ip,
|
||||
arp_response_ready,
|
||||
output_ip_hdr_valid,
|
||||
output_ip_eth_dest_mac,
|
||||
output_ip_eth_src_mac,
|
||||
@ -226,8 +230,10 @@ UUT (
|
||||
.output_eth_payload_tuser(output_eth_payload_tuser),
|
||||
// ARP requests
|
||||
.arp_request_valid(arp_request_valid),
|
||||
.arp_request_ready(arp_request_ready),
|
||||
.arp_request_ip(arp_request_ip),
|
||||
.arp_response_valid(arp_response_valid),
|
||||
.arp_response_ready(arp_response_ready),
|
||||
.arp_response_error(arp_response_error),
|
||||
.arp_response_mac(arp_response_mac),
|
||||
// IP frame input
|
||||
|
@ -26,6 +26,7 @@ THE SOFTWARE.
|
||||
from myhdl import *
|
||||
import os
|
||||
|
||||
import axis_ep
|
||||
import eth_ep
|
||||
import ip_ep
|
||||
|
||||
@ -59,6 +60,7 @@ def bench():
|
||||
input_eth_payload_tvalid = Signal(bool(0))
|
||||
input_eth_payload_tlast = Signal(bool(0))
|
||||
input_eth_payload_tuser = Signal(bool(0))
|
||||
arp_request_ready = Signal(bool(0))
|
||||
arp_response_valid = Signal(bool(0))
|
||||
arp_response_error = Signal(bool(0))
|
||||
arp_response_mac = Signal(intbv(0)[48:])
|
||||
@ -96,6 +98,7 @@ def bench():
|
||||
output_eth_payload_tuser = Signal(bool(0))
|
||||
arp_request_valid = Signal(bool(0))
|
||||
arp_request_ip = Signal(intbv(0)[32:])
|
||||
arp_response_ready = Signal(bool(0))
|
||||
output_ip_hdr_valid = Signal(bool(0))
|
||||
output_ip_eth_dest_mac = Signal(intbv(0)[48:])
|
||||
output_ip_eth_src_mac = Signal(intbv(0)[48:])
|
||||
@ -232,6 +235,28 @@ def bench():
|
||||
name='ip_sink'
|
||||
)
|
||||
|
||||
arp_request_sink = axis_ep.AXIStreamSink()
|
||||
|
||||
arp_request_sink_logic = arp_request_sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(arp_request_ip,),
|
||||
tvalid=arp_request_valid,
|
||||
tready=arp_request_ready,
|
||||
name='arp_request_sink'
|
||||
)
|
||||
|
||||
arp_response_source = axis_ep.AXIStreamSource()
|
||||
|
||||
arp_response_source_logic = arp_response_source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=(arp_response_error, arp_response_mac),
|
||||
tvalid=arp_response_valid,
|
||||
tready=arp_response_ready,
|
||||
name='arp_response_source'
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
@ -267,8 +292,10 @@ def bench():
|
||||
output_eth_payload_tuser=output_eth_payload_tuser,
|
||||
|
||||
arp_request_valid=arp_request_valid,
|
||||
arp_request_ready=arp_request_ready,
|
||||
arp_request_ip=arp_request_ip,
|
||||
arp_response_valid=arp_response_valid,
|
||||
arp_response_ready=arp_response_ready,
|
||||
arp_response_error=arp_response_error,
|
||||
arp_response_mac=arp_response_mac,
|
||||
|
||||
@ -337,17 +364,13 @@ def bench():
|
||||
while True:
|
||||
yield clk.posedge
|
||||
|
||||
arp_response_valid.next = 0
|
||||
arp_response_error.next = 0
|
||||
arp_response_mac.next = 0
|
||||
if not arp_request_sink.empty():
|
||||
req_ip = arp_request_sink.recv().data[0][0]
|
||||
|
||||
if arp_request_valid:
|
||||
if int(arp_request_ip) in arp_table:
|
||||
arp_response_valid.next = 1
|
||||
arp_response_mac.next = arp_table[int(arp_request_ip)]
|
||||
if req_ip in arp_table:
|
||||
arp_response_source.send([(0, arp_table[req_ip])])
|
||||
else:
|
||||
arp_response_valid.next = 1
|
||||
arp_response_error.next = 1
|
||||
arp_response_source.send([(1, 0)])
|
||||
|
||||
rx_error_header_early_termination_asserted = Signal(bool(0))
|
||||
rx_error_payload_early_termination_asserted = Signal(bool(0))
|
||||
|
@ -44,6 +44,7 @@ reg [7:0] input_eth_payload_tkeep = 0;
|
||||
reg input_eth_payload_tvalid = 0;
|
||||
reg input_eth_payload_tlast = 0;
|
||||
reg input_eth_payload_tuser = 0;
|
||||
reg arp_request_ready = 0;
|
||||
reg arp_response_valid = 0;
|
||||
reg arp_response_error = 0;
|
||||
reg [47:0] arp_response_mac = 0;
|
||||
@ -83,6 +84,7 @@ wire output_eth_payload_tlast;
|
||||
wire output_eth_payload_tuser;
|
||||
wire arp_request_valid;
|
||||
wire [31:0] arp_request_ip;
|
||||
wire arp_response_ready;
|
||||
wire output_ip_hdr_valid;
|
||||
wire [47:0] output_ip_eth_dest_mac;
|
||||
wire [47:0] output_ip_eth_src_mac;
|
||||
@ -129,6 +131,7 @@ initial begin
|
||||
input_eth_payload_tvalid,
|
||||
input_eth_payload_tlast,
|
||||
input_eth_payload_tuser,
|
||||
arp_request_ready,
|
||||
arp_response_valid,
|
||||
arp_response_error,
|
||||
arp_response_mac,
|
||||
@ -168,6 +171,7 @@ initial begin
|
||||
output_eth_payload_tuser,
|
||||
arp_request_valid,
|
||||
arp_request_ip,
|
||||
arp_response_ready,
|
||||
output_ip_hdr_valid,
|
||||
output_ip_eth_dest_mac,
|
||||
output_ip_eth_src_mac,
|
||||
@ -235,8 +239,10 @@ UUT (
|
||||
.output_eth_payload_tuser(output_eth_payload_tuser),
|
||||
// ARP requests
|
||||
.arp_request_valid(arp_request_valid),
|
||||
.arp_request_ready(arp_request_ready),
|
||||
.arp_request_ip(arp_request_ip),
|
||||
.arp_response_valid(arp_response_valid),
|
||||
.arp_response_ready(arp_response_ready),
|
||||
.arp_response_error(arp_response_error),
|
||||
.arp_response_mac(arp_response_mac),
|
||||
// IP frame input
|
||||
|
@ -45,6 +45,7 @@ srcs.append("../rtl/arp_eth_rx.v")
|
||||
srcs.append("../rtl/arp_eth_tx.v")
|
||||
srcs.append("../rtl/eth_arb_mux_2.v")
|
||||
srcs.append("../rtl/eth_mux_2.v")
|
||||
srcs.append("../rtl/lfsr.v")
|
||||
srcs.append("../lib/axis/rtl/arbiter.v")
|
||||
srcs.append("../lib/axis/rtl/priority_encoder.v")
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
@ -45,6 +45,7 @@ srcs.append("../rtl/arp_eth_rx_64.v")
|
||||
srcs.append("../rtl/arp_eth_tx_64.v")
|
||||
srcs.append("../rtl/eth_arb_mux_64_2.v")
|
||||
srcs.append("../rtl/eth_mux_64_2.v")
|
||||
srcs.append("../rtl/lfsr.v")
|
||||
srcs.append("../lib/axis/rtl/arbiter.v")
|
||||
srcs.append("../lib/axis/rtl/priority_encoder.v")
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
@ -53,6 +53,7 @@ srcs.append("../rtl/arp_eth_rx.v")
|
||||
srcs.append("../rtl/arp_eth_tx.v")
|
||||
srcs.append("../rtl/eth_arb_mux_2.v")
|
||||
srcs.append("../rtl/eth_mux_2.v")
|
||||
srcs.append("../rtl/lfsr.v")
|
||||
srcs.append("../lib/axis/rtl/arbiter.v")
|
||||
srcs.append("../lib/axis/rtl/priority_encoder.v")
|
||||
srcs.append("../lib/axis/rtl/axis_fifo.v")
|
||||
@ -525,13 +526,13 @@ def bench():
|
||||
udp_tx_error_payload_early_termination_asserted.next = 1
|
||||
|
||||
def wait_normal():
|
||||
i = 16
|
||||
i = 20
|
||||
while i > 0:
|
||||
i = max(0, i-1)
|
||||
if (input_eth_payload_tvalid or input_ip_payload_tvalid or input_udp_payload_tvalid or
|
||||
output_eth_payload_tvalid or output_ip_payload_tvalid or output_udp_payload_tvalid or
|
||||
input_eth_hdr_valid or input_ip_hdr_valid or input_udp_hdr_valid):
|
||||
i = 16
|
||||
i = 20
|
||||
yield clk.posedge
|
||||
|
||||
@instance
|
||||
|
@ -53,6 +53,7 @@ srcs.append("../rtl/arp_eth_rx_64.v")
|
||||
srcs.append("../rtl/arp_eth_tx_64.v")
|
||||
srcs.append("../rtl/eth_arb_mux_64_2.v")
|
||||
srcs.append("../rtl/eth_mux_64_2.v")
|
||||
srcs.append("../rtl/lfsr.v")
|
||||
srcs.append("../lib/axis/rtl/arbiter.v")
|
||||
srcs.append("../lib/axis/rtl/priority_encoder.v")
|
||||
srcs.append("../lib/axis/rtl/axis_fifo.v")
|
||||
@ -543,13 +544,13 @@ def bench():
|
||||
udp_tx_error_payload_early_termination_asserted.next = 1
|
||||
|
||||
def wait_normal():
|
||||
i = 16
|
||||
i = 20
|
||||
while i > 0:
|
||||
i = max(0, i-1)
|
||||
if (input_eth_payload_tvalid or input_ip_payload_tvalid or input_udp_payload_tvalid or
|
||||
output_eth_payload_tvalid or output_ip_payload_tvalid or output_udp_payload_tvalid or
|
||||
input_eth_hdr_valid or input_ip_hdr_valid or input_udp_hdr_valid):
|
||||
i = 16
|
||||
i = 20
|
||||
yield clk.posedge
|
||||
|
||||
@instance
|
||||
|
Loading…
x
Reference in New Issue
Block a user