Pushing the bulk of UHD-3.7.0 code.
Original-commit: ff1546f8137f7f92bb250f685561b0c34cc0e053
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
/a.out
|
||||
/*.vcd
|
||||
simple_gemac_wrapper_tb
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#
|
||||
# Copyright 2010 Ettus Research LLC
|
||||
#
|
||||
|
||||
##################################################
|
||||
# Simple GEMAC Sources
|
||||
##################################################
|
||||
SIMPLE_GEMAC_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/simple_gemac/, \
|
||||
simple_gemac_wrapper.v \
|
||||
simple_gemac.v \
|
||||
simple_gemac_tx.v \
|
||||
simple_gemac_rx.v \
|
||||
crc.v \
|
||||
delay_line.v \
|
||||
flow_ctrl_tx.v \
|
||||
flow_ctrl_rx.v \
|
||||
address_filter.v \
|
||||
address_filter_promisc.v \
|
||||
ll8_to_txmac.v \
|
||||
rxmac_to_ll8.v \
|
||||
ll8_to_axi64.v \
|
||||
axi64_to_ll8.v \
|
||||
mdio.v \
|
||||
))
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
module address_filter
|
||||
(input clk,
|
||||
input reset,
|
||||
input go,
|
||||
input [7:0] data,
|
||||
input [47:0] address,
|
||||
output match,
|
||||
output done);
|
||||
|
||||
reg [2:0] af_state;
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset)
|
||||
af_state <= 0;
|
||||
else
|
||||
if(go)
|
||||
af_state <= (data == address[47:40]) ? 1 : 7;
|
||||
else
|
||||
case(af_state)
|
||||
1 : af_state <= (data == address[39:32]) ? 2 : 7;
|
||||
2 : af_state <= (data == address[31:24]) ? 3 : 7;
|
||||
3 : af_state <= (data == address[23:16]) ? 4 : 7;
|
||||
4 : af_state <= (data == address[15:8]) ? 5 : 7;
|
||||
5 : af_state <= (data == address[7:0]) ? 6 : 7;
|
||||
6, 7 : af_state <= 0;
|
||||
endcase // case (af_state)
|
||||
|
||||
assign match = (af_state==6);
|
||||
assign done = (af_state==6)|(af_state==7);
|
||||
|
||||
endmodule // address_filter
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
module address_filter_promisc
|
||||
(input clk,
|
||||
input reset,
|
||||
input go,
|
||||
input [7:0] data,
|
||||
output match,
|
||||
output done);
|
||||
|
||||
reg [2:0] af_state;
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset)
|
||||
af_state <= 0;
|
||||
else
|
||||
if(go)
|
||||
af_state <= 1;//(data[0] == 1'b0) ? 1 : 7;
|
||||
else
|
||||
case(af_state)
|
||||
1 : af_state <= 2;
|
||||
2 : af_state <= 3;
|
||||
3 : af_state <= 4;
|
||||
4 : af_state <= 5;
|
||||
5 : af_state <= 6;
|
||||
6, 7 : af_state <= 0;
|
||||
endcase // case (af_state)
|
||||
|
||||
assign match = (af_state==6);
|
||||
assign done = (af_state==6)|(af_state==7);
|
||||
|
||||
endmodule // address_filter_promisc
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
|
||||
module axi64_to_ll8
|
||||
#(parameter START_BYTE=6)
|
||||
(input clk, input reset, input clear,
|
||||
input [63:0] axi64_tdata, input axi64_tlast, input [3:0] axi64_tuser, input axi64_tvalid, output axi64_tready,
|
||||
output [7:0] ll_data, output ll_eof, output ll_src_rdy, input ll_dst_rdy);
|
||||
|
||||
reg [7:0] data_int;
|
||||
wire eof_int, valid_int, ready_int;
|
||||
|
||||
reg [2:0] state = START_BYTE;
|
||||
reg eof, done;
|
||||
reg [3:0] occ;
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset | clear)
|
||||
state <= START_BYTE;
|
||||
else
|
||||
if(valid_int & ready_int)
|
||||
if(eof_int)
|
||||
state <= START_BYTE;
|
||||
else
|
||||
state <= state + 3'd1;
|
||||
|
||||
assign valid_int = axi64_tvalid;
|
||||
assign axi64_tready = ready_int & (eof_int | state == 7);
|
||||
assign eof_int = axi64_tlast & (axi64_tuser[2:0] == (state + 3'd1));
|
||||
|
||||
always @*
|
||||
case(state)
|
||||
0 : data_int <= axi64_tdata[63:56];
|
||||
1 : data_int <= axi64_tdata[55:48];
|
||||
2 : data_int <= axi64_tdata[47:40];
|
||||
3 : data_int <= axi64_tdata[39:32];
|
||||
4 : data_int <= axi64_tdata[31:24];
|
||||
5 : data_int <= axi64_tdata[23:16];
|
||||
6 : data_int <= axi64_tdata[15:8];
|
||||
7 : data_int <= axi64_tdata[7:0];
|
||||
default : data_int <= axi64_tdata[7:0];
|
||||
endcase // case (state)
|
||||
|
||||
axi_fifo_short #(.WIDTH(9)) ll8_fifo
|
||||
(.clk(clk), .reset(reset), .clear(0),
|
||||
.i_tdata({eof_int, data_int}), .i_tvalid(valid_int), .i_tready(ready_int),
|
||||
.o_tdata({ll_eof, ll_data}), .o_tvalid(ll_src_rdy), .o_tready(ll_dst_rdy),
|
||||
.space(), .occupied());
|
||||
|
||||
endmodule // axi64_to_ll8
|
||||
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
module crc
|
||||
(input clk,
|
||||
input reset,
|
||||
input clear,
|
||||
input [7:0] data,
|
||||
input calc,
|
||||
output [31:0] crc_out,
|
||||
output match);
|
||||
|
||||
function[31:0] NextCRC;
|
||||
input[7:0] D;
|
||||
input[31:0] C;
|
||||
reg[31:0] NewCRC;
|
||||
begin
|
||||
NewCRC[0] = C[24]^C[30]^D[1]^D[7];
|
||||
NewCRC[1] = C[25]^C[31]^D[0]^D[6]^C[24]^C[30]^D[1]^D[7];
|
||||
NewCRC[2] = C[26]^D[5]^C[25]^C[31]^D[0]^D[6]^C[24]^C[30]^D[1]^D[7];
|
||||
NewCRC[3] = C[27]^D[4]^C[26]^D[5]^C[25]^C[31]^D[0]^D[6];
|
||||
NewCRC[4] = C[28]^D[3]^C[27]^D[4]^C[26]^D[5]^C[24]^C[30]^D[1]^D[7];
|
||||
NewCRC[5] = C[29]^D[2]^C[28]^D[3]^C[27]^D[4]^C[25]^C[31]^D[0]^D[6]^C[24]^C[30]^D[1]^D[7];
|
||||
NewCRC[6] = C[30]^D[1]^C[29]^D[2]^C[28]^D[3]^C[26]^D[5]^C[25]^C[31]^D[0]^D[6];
|
||||
NewCRC[7] = C[31]^D[0]^C[29]^D[2]^C[27]^D[4]^C[26]^D[5]^C[24]^D[7];
|
||||
NewCRC[8] = C[0]^C[28]^D[3]^C[27]^D[4]^C[25]^D[6]^C[24]^D[7];
|
||||
NewCRC[9] = C[1]^C[29]^D[2]^C[28]^D[3]^C[26]^D[5]^C[25]^D[6];
|
||||
NewCRC[10] = C[2]^C[29]^D[2]^C[27]^D[4]^C[26]^D[5]^C[24]^D[7];
|
||||
NewCRC[11] = C[3]^C[28]^D[3]^C[27]^D[4]^C[25]^D[6]^C[24]^D[7];
|
||||
NewCRC[12] = C[4]^C[29]^D[2]^C[28]^D[3]^C[26]^D[5]^C[25]^D[6]^C[24]^C[30]^D[1]^D[7];
|
||||
NewCRC[13] = C[5]^C[30]^D[1]^C[29]^D[2]^C[27]^D[4]^C[26]^D[5]^C[25]^C[31]^D[0]^D[6];
|
||||
NewCRC[14] = C[6]^C[31]^D[0]^C[30]^D[1]^C[28]^D[3]^C[27]^D[4]^C[26]^D[5];
|
||||
NewCRC[15] = C[7]^C[31]^D[0]^C[29]^D[2]^C[28]^D[3]^C[27]^D[4];
|
||||
NewCRC[16] = C[8]^C[29]^D[2]^C[28]^D[3]^C[24]^D[7];
|
||||
NewCRC[17] = C[9]^C[30]^D[1]^C[29]^D[2]^C[25]^D[6];
|
||||
NewCRC[18] = C[10]^C[31]^D[0]^C[30]^D[1]^C[26]^D[5];
|
||||
NewCRC[19] = C[11]^C[31]^D[0]^C[27]^D[4];
|
||||
NewCRC[20] = C[12]^C[28]^D[3];
|
||||
NewCRC[21] = C[13]^C[29]^D[2];
|
||||
NewCRC[22] = C[14]^C[24]^D[7];
|
||||
NewCRC[23] = C[15]^C[25]^D[6]^C[24]^C[30]^D[1]^D[7];
|
||||
NewCRC[24] = C[16]^C[26]^D[5]^C[25]^C[31]^D[0]^D[6];
|
||||
NewCRC[25] = C[17]^C[27]^D[4]^C[26]^D[5];
|
||||
NewCRC[26] = C[18]^C[28]^D[3]^C[27]^D[4]^C[24]^C[30]^D[1]^D[7];
|
||||
NewCRC[27] = C[19]^C[29]^D[2]^C[28]^D[3]^C[25]^C[31]^D[0]^D[6];
|
||||
NewCRC[28] = C[20]^C[30]^D[1]^C[29]^D[2]^C[26]^D[5];
|
||||
NewCRC[29] = C[21]^C[31]^D[0]^C[30]^D[1]^C[27]^D[4];
|
||||
NewCRC[30] = C[22]^C[31]^D[0]^C[28]^D[3];
|
||||
NewCRC[31] = C[23]^C[29]^D[2];
|
||||
NextCRC = NewCRC;
|
||||
end
|
||||
endfunction
|
||||
|
||||
reg [31:0] crc_reg;
|
||||
always @ (posedge clk)
|
||||
if (reset | clear)
|
||||
crc_reg <= 32'hffffffff;
|
||||
else if (calc)
|
||||
crc_reg <= NextCRC(data,crc_reg);
|
||||
|
||||
assign crc_out = ~{crc_reg[24],crc_reg[25],crc_reg[26],crc_reg[27],crc_reg[28],crc_reg[29],crc_reg[30],crc_reg[31],
|
||||
crc_reg[16],crc_reg[17],crc_reg[18],crc_reg[19],crc_reg[20],crc_reg[21],crc_reg[22],crc_reg[23],
|
||||
crc_reg[8],crc_reg[9],crc_reg[10],crc_reg[11],crc_reg[12],crc_reg[13],crc_reg[14],crc_reg[15],
|
||||
crc_reg[0],crc_reg[1],crc_reg[2],crc_reg[3],crc_reg[4],crc_reg[5],crc_reg[6],crc_reg[7] };
|
||||
|
||||
assign match = (crc_reg == 32'hc704_dd7b);
|
||||
|
||||
endmodule // crc
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
module delay_line
|
||||
#(parameter WIDTH=32)
|
||||
(input clk,
|
||||
input [3:0] delay,
|
||||
input [WIDTH-1:0] din,
|
||||
output [WIDTH-1:0] dout);
|
||||
|
||||
genvar i;
|
||||
generate
|
||||
for (i=0;i<WIDTH;i=i+1)
|
||||
begin : gen_delay
|
||||
SRL16E
|
||||
srl16e(.Q(dout[i]),
|
||||
.A0(delay[0]),.A1(delay[1]),.A2(delay[2]),.A3(delay[3]),
|
||||
.CE(1),.CLK(clk),.D(din[i]));
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule // delay_line
|
||||
@@ -0,0 +1,161 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
task SendFlowCtrl;
|
||||
input [15:0] fc_len;
|
||||
begin
|
||||
$display("Sending Flow Control, quanta = %d, time = %d", fc_len,$time);
|
||||
pause_time <= fc_len;
|
||||
@(posedge clk);
|
||||
pause_req <= 1;
|
||||
@(posedge clk);
|
||||
pause_req <= 0;
|
||||
$display("Sent Flow Control");
|
||||
end
|
||||
endtask // SendFlowCtrl
|
||||
|
||||
task SendPacket2MAC;
|
||||
input tx_clk;
|
||||
input [7:0] data_start;
|
||||
input [31:0] data_len;
|
||||
output [7:0] tx_data;
|
||||
output tx_valid;
|
||||
output tx_error;
|
||||
input tx_ack;
|
||||
reg [15:0] count;
|
||||
begin
|
||||
$display("Sending Packet Len=%d, %d", data_len, $time);
|
||||
count <= 1;
|
||||
tx_data <= data_start;
|
||||
tx_error <= 0;
|
||||
tx_valid <= 1;
|
||||
while(~tx_ack)
|
||||
@(posedge tx_clk);
|
||||
$display("Packet Accepted, %d", $time);
|
||||
while(count < data_len)
|
||||
begin
|
||||
tx_data <= tx_data + 1;
|
||||
count <= count + 1;
|
||||
@(posedge clk);
|
||||
end
|
||||
tx_valid <= 0;
|
||||
@(posedge tx_clk);
|
||||
end
|
||||
endtask // SendPacket2MAC
|
||||
|
||||
task SendPacket_to_ll8;
|
||||
input [7:0] data_start;
|
||||
input [15:0] data_len;
|
||||
// output [7:0] tx_data;
|
||||
// output tx_sof;
|
||||
// output tx_eof;
|
||||
// output tx_src_rdy;
|
||||
// input tx_dst_rdy;
|
||||
reg [15:0] count;
|
||||
begin
|
||||
$display("Sending Packet Len=%d, %d", data_len, $time);
|
||||
count <= 2;
|
||||
tx_ll_data2 <= data_start;
|
||||
tx_ll_src_rdy2 <= 1;
|
||||
tx_ll_sof2 <= 1;
|
||||
tx_ll_eof2 <= 0;
|
||||
#1;
|
||||
while(count < data_len)
|
||||
begin
|
||||
while(~tx_ll_dst_rdy2)
|
||||
@(posedge clk);
|
||||
@(posedge clk);
|
||||
tx_ll_data2 = tx_ll_data2 + 1;
|
||||
count = count + 1;
|
||||
tx_ll_sof2 <= 0;
|
||||
end
|
||||
tx_ll_eof2 <= 1;
|
||||
while(~tx_ll_dst_rdy2)
|
||||
@(posedge clk);
|
||||
@(posedge clk);
|
||||
tx_ll_src_rdy2 <= 0;
|
||||
end
|
||||
endtask // SendPacket_to_ll8
|
||||
|
||||
|
||||
task SendPacketFromFile;
|
||||
input clk;
|
||||
input [31:0] data_len;
|
||||
output [7:0] tx_data;
|
||||
output tx_valid;
|
||||
output tx_error;
|
||||
input tx_ack;
|
||||
reg [15:0] count;
|
||||
begin
|
||||
$display("Sending Packet From File Len=%d, %d",data_len,$time);
|
||||
$readmemh("test_packet.mem",pkt_rom );
|
||||
count = 0;
|
||||
tx_data = pkt_rom[count];
|
||||
tx_error = 0;
|
||||
tx_valid = 1;
|
||||
while(~tx_ack)
|
||||
@(posedge clk);
|
||||
$display("Packet Accepted, %d",$time);
|
||||
count = 1;
|
||||
while(count < data_len)
|
||||
begin
|
||||
tx_data = pkt_rom[count];
|
||||
count = count + 1;
|
||||
@(posedge clk);
|
||||
end
|
||||
tx_valid <= 0;
|
||||
@(posedge clk);
|
||||
end
|
||||
endtask // SendPacketFromFile
|
||||
|
||||
task Waiter;
|
||||
input [31:0] wait_length;
|
||||
begin
|
||||
tx_ll_src_rdy2 <= 0;
|
||||
repeat(wait_length)
|
||||
@(posedge clk);
|
||||
tx_ll_src_rdy2 <= 1;
|
||||
end
|
||||
endtask // Waiter
|
||||
|
||||
task SendPacketFromFile_ll8;
|
||||
input [31:0] data_len;
|
||||
input [31:0] wait_length;
|
||||
input [31:0] wait_time;
|
||||
|
||||
integer count;
|
||||
begin
|
||||
$display("Sending Packet From File to LL8 Len=%d, %d",data_len,$time);
|
||||
$readmemh("test_packet.mem",pkt_rom );
|
||||
|
||||
while(~tx_ll_dst_rdy2)
|
||||
@(posedge clk);
|
||||
tx_ll_data2 <= pkt_rom[0];
|
||||
tx_ll_src_rdy2 <= 1;
|
||||
tx_ll_sof2 <= 1;
|
||||
tx_ll_eof2 <= 0;
|
||||
@(posedge clk);
|
||||
|
||||
for(i=1;i<data_len-1;i=i+1)
|
||||
begin
|
||||
while(~tx_ll_dst_rdy2)
|
||||
@(posedge clk);
|
||||
tx_ll_data2 <= pkt_rom[i];
|
||||
tx_ll_sof2 <= 0;
|
||||
@(posedge clk);
|
||||
if(i==wait_time)
|
||||
Waiter(wait_length);
|
||||
end
|
||||
|
||||
while(~tx_ll_dst_rdy2)
|
||||
@(posedge clk);
|
||||
tx_ll_eof2 <= 1;
|
||||
tx_ll_data2 <= pkt_rom[data_len-1];
|
||||
@(posedge clk);
|
||||
tx_ll_src_rdy2 <= 0;
|
||||
end
|
||||
endtask // SendPacketFromFile_ll8
|
||||
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
// RX side of flow control -- when we are running out of RX space, send a PAUSE
|
||||
|
||||
module flow_ctrl_rx
|
||||
(input pause_request_en, input [15:0] pause_time, input [15:0] pause_thresh,
|
||||
input rx_clk, input rx_reset, input [15:0] rx_fifo_space,
|
||||
input tx_clk, input tx_reset, output reg pause_req, output reg [15:0] pause_time_req
|
||||
);
|
||||
|
||||
// ******************************************************************************
|
||||
// Force our TX to send a PAUSE frame because our RX is nearly full
|
||||
// ******************************************************************************
|
||||
|
||||
// RX Clock Domain
|
||||
reg xon, xoff;
|
||||
reg [21:0] countdown;
|
||||
|
||||
wire [15:0] pause_low_thresh = pause_thresh;
|
||||
wire [15:0] pause_hi_thresh = 16'hFFFF;
|
||||
wire [21:0] pq_reduced = {pause_time,6'd0} - 1700;
|
||||
|
||||
always @(posedge rx_clk)
|
||||
if(rx_reset)
|
||||
xoff <= 0;
|
||||
else
|
||||
xoff <= (pause_request_en & (countdown==0) & (rx_fifo_space < pause_low_thresh));
|
||||
|
||||
always @(posedge rx_clk)
|
||||
if(rx_reset)
|
||||
xon <= 0;
|
||||
else
|
||||
xon <= ((countdown!=0) & (rx_fifo_space > pause_hi_thresh));
|
||||
|
||||
always @(posedge rx_clk)
|
||||
if(rx_reset)
|
||||
countdown <= 0;
|
||||
else if(xoff)
|
||||
countdown <= pq_reduced;
|
||||
else if(xon)
|
||||
countdown <= 0;
|
||||
else if(countdown != 0)
|
||||
countdown <= countdown - 1;
|
||||
|
||||
// Cross clock domains
|
||||
wire xon_tx, xoff_tx;
|
||||
oneshot_2clk send_xon (.clk_in(rx_clk), .in(xon), .clk_out(tx_clk), .out(xon_tx));
|
||||
oneshot_2clk send_xoff (.clk_in(rx_clk), .in(xoff), .clk_out(tx_clk), .out(xoff_tx));
|
||||
|
||||
always @(posedge tx_clk)
|
||||
if(xoff_tx)
|
||||
pause_time_req <= pause_time;
|
||||
else if(xon_tx)
|
||||
pause_time_req <= 0;
|
||||
|
||||
always @(posedge tx_clk)
|
||||
if(tx_reset)
|
||||
pause_req <= 0;
|
||||
else
|
||||
pause_req <= xon_tx | xoff_tx;
|
||||
|
||||
endmodule // flow_ctrl_rx
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
// TX side of flow control -- when other side sends PAUSE, we wait
|
||||
|
||||
module flow_ctrl_tx
|
||||
(input rst,
|
||||
input tx_clk,
|
||||
//host processor
|
||||
input tx_pause_en,
|
||||
// From MAC_rx_ctrl
|
||||
input [15:0] pause_quanta,
|
||||
input pause_quanta_val,
|
||||
// MAC_tx_ctrl
|
||||
output pause_apply,
|
||||
input paused);
|
||||
|
||||
// ******************************************************************************
|
||||
// Inhibit our TX from transmitting because they sent us a PAUSE frame
|
||||
// ******************************************************************************
|
||||
|
||||
// Pauses are in units of 512 bit times, or 64 bytes/clock cycles, and can be
|
||||
// as big as 16 bits, so 22 bits are needed for the counter
|
||||
|
||||
reg [15+6:0] pause_quanta_counter;
|
||||
reg pqval_d1, pqval_d2;
|
||||
|
||||
always @(posedge tx_clk) pqval_d1 <= pause_quanta_val;
|
||||
always @(posedge tx_clk) pqval_d2 <= pqval_d1;
|
||||
|
||||
always @ (posedge tx_clk or posedge rst)
|
||||
if (rst)
|
||||
pause_quanta_counter <= 0;
|
||||
else if (pqval_d1 & ~pqval_d2)
|
||||
pause_quanta_counter <= {pause_quanta, 6'b0};
|
||||
else if((pause_quanta_counter!=0) & paused)
|
||||
pause_quanta_counter <= pause_quanta_counter - 1;
|
||||
|
||||
assign pause_apply = tx_pause_en & (pause_quanta_counter != 0);
|
||||
|
||||
endmodule // flow_ctrl
|
||||
@@ -0,0 +1,102 @@
|
||||
|
||||
// Takes 8-bit wide data on a Local-link fifo interface and converts to 64-bit wide axi
|
||||
// Parameter START_BYTE controls which byte of the 8 the first incoming byte goes into
|
||||
// Use START_BYTE=6 with ethernet to nicely align the words for processing of IP packets
|
||||
// Parameter LABEL specifies a value to put in the high word of the very first packet.
|
||||
// This is useful for labeling packets with the port it came from so downstream knows
|
||||
// how to process it. LABEL gets overwritten if START_BYTE = 0
|
||||
|
||||
module ll8_to_axi64
|
||||
#(parameter START_BYTE=6,
|
||||
parameter LABEL=8'h00)
|
||||
(input clk, input reset, input clear,
|
||||
input [7:0] ll_data, input ll_eof, input ll_error, input ll_src_rdy, output ll_dst_rdy,
|
||||
output [63:0] axi64_tdata, output axi64_tlast, output [3:0] axi64_tuser, output axi64_tvalid, input axi64_tready);
|
||||
|
||||
wire error_int, eof_int;
|
||||
wire [7:0] data_int;
|
||||
wire valid_int, ready_int;
|
||||
|
||||
axi_fifo_short #(.WIDTH(10)) ll8_fifo
|
||||
(.clk(clk), .reset(reset), .clear(0),
|
||||
.i_tdata({ll_error, ll_eof, ll_data}), .i_tvalid(ll_src_rdy), .i_tready(ll_dst_rdy),
|
||||
.o_tdata({error_int, eof_int, data_int}), .o_tvalid(valid_int), .o_tready(ready_int),
|
||||
.space(), .occupied());
|
||||
|
||||
wire [7:0] label_wire = LABEL; // Enforces parameter width
|
||||
|
||||
reg [3:0] state = START_BYTE;
|
||||
reg [63:0] holding; // = {label_wire, 56'h0};
|
||||
reg err, eof, done;
|
||||
reg [3:0] occ;
|
||||
|
||||
localparam WAIT = 4'd8;
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset | clear)
|
||||
begin
|
||||
state <= START_BYTE;
|
||||
holding <= {label_wire, 56'h0};
|
||||
err <= 1'b0;
|
||||
eof <= 1'b0;
|
||||
occ <= 3'd0;
|
||||
done <= 1'b0;
|
||||
end
|
||||
else
|
||||
if(state == WAIT)
|
||||
begin
|
||||
state <= START_BYTE;
|
||||
done <= 1'b0;
|
||||
holding <= {label_wire, 56'h0};
|
||||
end
|
||||
else if(valid_int & ready_int)
|
||||
begin
|
||||
case(state)
|
||||
4'd0:
|
||||
begin
|
||||
holding[63:56] <= data_int;
|
||||
holding[55:0] <= 56'h0;
|
||||
end
|
||||
4'd1: holding[55:48] <= data_int;
|
||||
4'd2: holding[47:40] <= data_int;
|
||||
4'd3: holding[39:32] <= data_int;
|
||||
4'd4: holding[31:24] <= data_int;
|
||||
4'd5: holding[23:16] <= data_int;
|
||||
4'd6: holding[15:8] <= data_int;
|
||||
4'd7: holding[7:0] <= data_int;
|
||||
endcase // case (state)
|
||||
|
||||
err <= error_int;
|
||||
eof <= eof_int;
|
||||
if(error_int | eof_int)
|
||||
begin
|
||||
occ <= state+1;
|
||||
done <= 1'b1;
|
||||
state <= WAIT;
|
||||
end
|
||||
else if (state == 4'd7)
|
||||
begin
|
||||
occ <= 3'd0;
|
||||
done <= 1'b1;
|
||||
state <= 4'd0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
occ <= 3'd0;
|
||||
done <= 1'b0;
|
||||
state <= state + 4'd1;
|
||||
end // else: !if(state == 4'd7)
|
||||
|
||||
end // if (valid_int & ready_int)
|
||||
else
|
||||
done <= 1'b0;
|
||||
|
||||
assign axi64_tdata = holding;
|
||||
assign axi64_tlast = eof;
|
||||
assign axi64_tuser[3] = err;
|
||||
assign axi64_tuser[2:0] = occ;
|
||||
|
||||
assign ready_int = axi64_tready & (state != WAIT);
|
||||
assign axi64_tvalid = done;
|
||||
|
||||
endmodule // ll8_to_axi64
|
||||
@@ -0,0 +1,95 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module ll8_to_axi64_tb();
|
||||
|
||||
reg clk = 0;
|
||||
reg reset = 1;
|
||||
|
||||
always #10 clk = ~clk;
|
||||
|
||||
initial $dumpfile("ll8_to_axi64_tb.vcd");
|
||||
initial $dumpvars(0,ll8_to_axi64_tb);
|
||||
|
||||
initial
|
||||
begin
|
||||
#1000 reset = 0;
|
||||
#2000000;
|
||||
$finish;
|
||||
end
|
||||
|
||||
wire [63:0] tdata, tdata_int;
|
||||
wire [3:0] tuser, tuser_int;
|
||||
wire tlast, tlast_int;
|
||||
wire tvalid, tvalid_int, tready, tready_int;
|
||||
|
||||
reg [7:0] ll_data;
|
||||
reg ll_eof, ll_error, ll_src_rdy;
|
||||
wire ll_dst_rdy;
|
||||
|
||||
wire [7:0] ll_data2;
|
||||
wire ll_eof2, ll_src_rdy2, ll_dst_rdy2;
|
||||
|
||||
localparam RPT_COUNT = 12;
|
||||
|
||||
initial
|
||||
begin
|
||||
ll_src_rdy <= 0;
|
||||
|
||||
while(reset)
|
||||
@(posedge clk);
|
||||
|
||||
@(posedge clk);
|
||||
|
||||
{ll_error, ll_eof, ll_data} <= { 1'b0, 1'b0, 8'hA0 };
|
||||
repeat(RPT_COUNT-1)
|
||||
begin
|
||||
ll_src_rdy <= 1;
|
||||
@(posedge clk);
|
||||
ll_data <= ll_data + 1;
|
||||
end
|
||||
ll_eof <= 1;
|
||||
ll_data <= ll_data + 1;
|
||||
@(posedge clk);
|
||||
|
||||
{ll_error, ll_eof, ll_data} <= { 1'b0, 1'b0, 8'hC0 };
|
||||
repeat(RPT_COUNT-1)
|
||||
begin
|
||||
ll_src_rdy <= 1;
|
||||
@(posedge clk);
|
||||
ll_data <= ll_data + 1;
|
||||
end
|
||||
ll_eof <= 1; ll_error <= 1;
|
||||
ll_data <= ll_data + 1;
|
||||
@(posedge clk);
|
||||
ll_src_rdy <= 1'b0;
|
||||
|
||||
end
|
||||
|
||||
ll8_to_axi64 #(.START_BYTE(6), .LABEL(8'h89)) ll8_to_axi64
|
||||
(.clk(clk), .reset(reset), .clear(1'b0),
|
||||
.ll_data(ll_data), .ll_eof(ll_eof), .ll_error(ll_error), .ll_src_rdy(ll_src_rdy), .ll_dst_rdy(ll_dst_rdy),
|
||||
.axi64_tdata(tdata), .axi64_tlast(tlast), .axi64_tuser(tuser), .axi64_tvalid(tvalid), .axi64_tready(tready) );
|
||||
|
||||
axi_fifo_short #(.WIDTH(69)) axi_fifo_short
|
||||
(.clk(clk), .reset(reset), .clear(1'b0),
|
||||
.i_tdata({tlast,tuser,tdata}), .i_tvalid(tvalid), .i_tready(tready),
|
||||
.o_tdata({tlast_int,tuser_int,tdata_int}), .o_tvalid(tvalid_int), .o_tready(tready_int));
|
||||
|
||||
axi64_to_ll8 #(.START_BYTE(6)) axi64_to_ll8
|
||||
(.clk(clk), .reset(reset), .clear(1'b0),
|
||||
.axi64_tdata(tdata_int), .axi64_tlast(tlast_int), .axi64_tuser(tuser_int), .axi64_tvalid(tvalid_int), .axi64_tready(tready_int),
|
||||
.ll_data(ll_data2), .ll_eof(ll_eof2), .ll_src_rdy(ll_src_rdy2), .ll_dst_rdy(ll_dst_rdy2) );
|
||||
|
||||
/*
|
||||
always @(posedge clk)
|
||||
if(ll_src_rdy2 & ll_dst_rdy2)
|
||||
$display("EOF %x\tDATA %x",ll_eof2, ll_data2);
|
||||
|
||||
*/
|
||||
assign ll_dst_rdy2 = 1;
|
||||
|
||||
always @(posedge clk)
|
||||
if(tvalid_int & tready_int)
|
||||
$display("TERR %x\tTUSER %x\tTLAST %x\tTDATA %x",tuser_int[3],tuser_int[2:0], tlast_int, tdata_int);
|
||||
|
||||
endmodule // ll8_to_axi64_tb
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
module ll8_to_txmac
|
||||
(input clk, input reset, input clear,
|
||||
input [7:0] ll_data, input ll_eof, input ll_src_rdy, output ll_dst_rdy,
|
||||
output [7:0] tx_data, output tx_valid, output tx_error, input tx_ack );
|
||||
|
||||
reg [2:0] xfer_state;
|
||||
|
||||
localparam XFER_IDLE = 0;
|
||||
localparam XFER_ACTIVE = 1;
|
||||
localparam XFER_WAIT1 = 2;
|
||||
localparam XFER_UNDERRUN = 3;
|
||||
localparam XFER_DROP = 4;
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset | clear)
|
||||
xfer_state <= XFER_IDLE;
|
||||
else
|
||||
case(xfer_state)
|
||||
XFER_IDLE :
|
||||
if(tx_ack)
|
||||
xfer_state <= XFER_ACTIVE;
|
||||
XFER_ACTIVE :
|
||||
if(~ll_src_rdy)
|
||||
xfer_state <= XFER_UNDERRUN;
|
||||
else if(ll_eof)
|
||||
xfer_state <= XFER_WAIT1;
|
||||
XFER_WAIT1 :
|
||||
xfer_state <= XFER_IDLE;
|
||||
XFER_UNDERRUN :
|
||||
xfer_state <= XFER_DROP;
|
||||
XFER_DROP :
|
||||
if(ll_eof)
|
||||
xfer_state <= XFER_IDLE;
|
||||
endcase // case (xfer_state)
|
||||
|
||||
assign ll_dst_rdy = (xfer_state == XFER_ACTIVE) | tx_ack | (xfer_state == XFER_DROP);
|
||||
assign tx_valid = (ll_src_rdy & (xfer_state == XFER_IDLE))|(xfer_state == XFER_ACTIVE);
|
||||
assign tx_data = ll_data;
|
||||
assign tx_error = (xfer_state == XFER_UNDERRUN);
|
||||
|
||||
endmodule // ll8_to_txmac
|
||||
|
||||
@@ -0,0 +1,847 @@
|
||||
// Define MDIO to add support for clause 22 and clause 45 MDIO interface
|
||||
`define MDIO
|
||||
// If WB clock is 62.5MHz and max MDC spec is 2.5MHz, then divide by 25
|
||||
//`define MDC_HALF_PERIOD 13 // Closest int to 12.5
|
||||
`define MDC_HALF_PERIOD 100
|
||||
|
||||
// Registers
|
||||
`define CPUREG_MDIO_DATA 8'h10
|
||||
`define CPUREG_MDIO_ADDR 8'h14
|
||||
`define CPUREG_MDIO_OP 8'h18
|
||||
`define CPUREG_MDIO_CONTROL 8'h1c
|
||||
`define CPUREG_MDIO_STATUS 8'h1c
|
||||
`define CPUREG_GPIO 8'h20
|
||||
|
||||
|
||||
module mdio
|
||||
(
|
||||
// Wishbone Bus
|
||||
input wb_clk_i,
|
||||
input wb_rst_i,
|
||||
input [7:0] wb_adr_i,
|
||||
input [31:0] wb_dat_i,
|
||||
input wb_we_i,
|
||||
input wb_stb_i,
|
||||
input wb_cyc_i,
|
||||
output reg [31:0] wb_dat_o,
|
||||
output wb_ack_o,
|
||||
output reg wb_int_o,
|
||||
// MDIO
|
||||
output reg mdc,
|
||||
output reg mdio_out,
|
||||
output reg mdio_tri,
|
||||
input mdio_in
|
||||
);
|
||||
|
||||
//
|
||||
// State Declarations
|
||||
//
|
||||
parameter
|
||||
IDLE = 0,
|
||||
PREAMBLE1 = 1,
|
||||
PREAMBLE2 = 2,
|
||||
PREAMBLE3 = 3,
|
||||
PREAMBLE4 = 4,
|
||||
PREAMBLE5 = 5,
|
||||
PREAMBLE6 = 6,
|
||||
PREAMBLE7 = 7,
|
||||
PREAMBLE8 = 8,
|
||||
PREAMBLE9 = 9,
|
||||
PREAMBLE10 = 10,
|
||||
PREAMBLE11 = 11,
|
||||
PREAMBLE12 = 12,
|
||||
PREAMBLE13 = 13,
|
||||
PREAMBLE14 = 14,
|
||||
PREAMBLE15 = 15,
|
||||
PREAMBLE16 = 16,
|
||||
PREAMBLE17 = 17,
|
||||
PREAMBLE18 = 18,
|
||||
PREAMBLE19 = 19,
|
||||
PREAMBLE20 = 20,
|
||||
PREAMBLE21 = 21,
|
||||
PREAMBLE22 = 22,
|
||||
PREAMBLE23 = 23,
|
||||
PREAMBLE24 = 24,
|
||||
PREAMBLE25 = 25,
|
||||
PREAMBLE26 = 26,
|
||||
PREAMBLE27 = 27,
|
||||
PREAMBLE28 = 28,
|
||||
PREAMBLE29 = 29,
|
||||
PREAMBLE30 = 30,
|
||||
PREAMBLE31 = 31,
|
||||
PREAMBLE32 = 32,
|
||||
START1 = 33,
|
||||
C22_START2 = 34,
|
||||
C45_START2 = 35,
|
||||
OP1 = 36,
|
||||
OP2 = 37,
|
||||
PRTAD1 = 38,
|
||||
PRTAD2 = 39,
|
||||
PRTAD3 = 40,
|
||||
PRTAD4 = 41,
|
||||
PRTAD5 = 42,
|
||||
DEVAD1 = 43,
|
||||
DEVAD2 = 44,
|
||||
DEVAD3 = 45,
|
||||
DEVAD4 = 46,
|
||||
DEVAD5 = 47,
|
||||
TA1 = 48,
|
||||
TA2 = 49,
|
||||
TA3 = 50,
|
||||
READ1 = 51,
|
||||
READ2 = 52,
|
||||
READ3 = 53,
|
||||
READ4 = 54,
|
||||
READ5 = 55,
|
||||
READ6 = 56,
|
||||
READ7 = 57,
|
||||
READ8 = 58,
|
||||
READ9 = 59,
|
||||
READ10 = 60,
|
||||
READ11 = 61,
|
||||
READ12 = 62,
|
||||
READ13 = 63,
|
||||
READ14 = 64,
|
||||
READ15 = 65,
|
||||
READ16 = 66,
|
||||
WRITE1 = 67,
|
||||
WRITE2 = 68,
|
||||
WRITE3 = 69,
|
||||
WRITE4 = 70,
|
||||
WRITE5 = 71,
|
||||
WRITE6 = 72,
|
||||
WRITE7 = 73,
|
||||
WRITE8 = 74,
|
||||
WRITE9 = 75,
|
||||
WRITE10 = 76,
|
||||
WRITE11 = 77,
|
||||
WRITE12 = 78,
|
||||
WRITE13 = 79,
|
||||
WRITE14 = 80,
|
||||
WRITE15 = 81,
|
||||
WRITE16 = 82,
|
||||
C45_ADDR1 = 83,
|
||||
C45_ADDR2 = 84,
|
||||
C45_ADDR3 = 85,
|
||||
C45_ADDR4 = 86,
|
||||
C45_ADDR5 = 87,
|
||||
C45_ADDR6 = 88,
|
||||
C45_ADDR7 = 89,
|
||||
C45_ADDR8 = 90,
|
||||
C45_ADDR9 = 91,
|
||||
C45_ADDR10 = 92,
|
||||
C45_ADDR11 = 93,
|
||||
C45_ADDR12 = 94,
|
||||
C45_ADDR13 = 95,
|
||||
C45_ADDR14 = 96,
|
||||
C45_ADDR15 = 97,
|
||||
C45_ADDR16 = 98,
|
||||
PREIDLE = 99;
|
||||
|
||||
reg cpuack;
|
||||
reg [15:0] mdio_read_data;
|
||||
reg [15:0] mdio_write_data;
|
||||
reg [15:0] mdio_address;
|
||||
reg [12:0] mdio_operation;
|
||||
reg mdio_control;
|
||||
reg [7:0] mdc_clk_count;
|
||||
reg mdc_falling_edge;
|
||||
reg mdio_running;
|
||||
reg mdio_done;
|
||||
reg [7:0] state;
|
||||
|
||||
|
||||
assign wb_ack_o = cpuack && wb_stb_i;
|
||||
|
||||
always @(posedge wb_clk_i or posedge wb_rst_i) begin
|
||||
|
||||
if (wb_rst_i == 1'b1) begin
|
||||
wb_dat_o <= 32'b0;
|
||||
wb_int_o <= 1'b0;
|
||||
cpuack <= 1'b0;
|
||||
|
||||
mdio_address <= 0;
|
||||
mdio_operation <= 0;
|
||||
mdio_write_data <= 0;
|
||||
mdio_running <= 0;
|
||||
end
|
||||
else begin
|
||||
|
||||
wb_int_o <= 1'b0;
|
||||
cpuack <= wb_cyc_i && wb_stb_i;
|
||||
// Handshake to MDIO state machine to reset running flag in status.
|
||||
// Wait for falling MDC edge to prevent S/W race condition occuring
|
||||
// where done flag still asserted but running flag now cleared (repeatedly).
|
||||
if (mdio_done && mdc_falling_edge)
|
||||
mdio_running <= 0;
|
||||
|
||||
//
|
||||
// Read access
|
||||
//
|
||||
if (wb_cyc_i && wb_stb_i && !wb_we_i) begin
|
||||
|
||||
case ({wb_adr_i[7:2], 2'b0})
|
||||
|
||||
`CPUREG_MDIO_DATA: begin
|
||||
wb_dat_o <= {16'b0, mdio_read_data};
|
||||
end
|
||||
|
||||
`CPUREG_MDIO_STATUS: begin
|
||||
wb_dat_o <= {31'b0, mdio_running};
|
||||
end
|
||||
|
||||
default: begin
|
||||
end
|
||||
|
||||
endcase
|
||||
end
|
||||
|
||||
//
|
||||
// Write access
|
||||
//
|
||||
if (wb_cyc_i && wb_stb_i && wb_we_i) begin
|
||||
$display("reg write @ addr %x",({wb_adr_i[7:2], 2'b0}));
|
||||
|
||||
case ({wb_adr_i[7:2], 2'b0})
|
||||
|
||||
`CPUREG_MDIO_DATA: begin
|
||||
mdio_write_data <= wb_dat_i[15:0];
|
||||
end
|
||||
|
||||
`CPUREG_MDIO_ADDR: begin
|
||||
mdio_address <= wb_dat_i[15:0];
|
||||
end
|
||||
|
||||
`CPUREG_MDIO_OP: begin
|
||||
mdio_operation <= wb_dat_i[12:0];
|
||||
end
|
||||
|
||||
`CPUREG_MDIO_CONTROL: begin
|
||||
// Trigger mdio operation here. Cleared by state machine at end of bus transaction.
|
||||
if (wb_dat_i[0])
|
||||
mdio_running <= 1;
|
||||
end
|
||||
|
||||
default: begin
|
||||
end
|
||||
|
||||
endcase
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end // always @ (posedge wb_clk_i or posedge wb_rst_i)
|
||||
|
||||
|
||||
//
|
||||
// Produce mdc clock as a signal synchronously from Wishbone clock.
|
||||
//
|
||||
always @(posedge wb_clk_i or posedge wb_rst_i)
|
||||
if (wb_rst_i)
|
||||
begin
|
||||
mdc_clk_count <= 1;
|
||||
mdc <= 0;
|
||||
mdc_falling_edge <= 0;
|
||||
end
|
||||
else if (mdc_clk_count == `MDC_HALF_PERIOD)
|
||||
begin
|
||||
mdc_clk_count <= 1;
|
||||
mdc <= ~mdc;
|
||||
mdc_falling_edge <= mdc;
|
||||
end
|
||||
else
|
||||
begin
|
||||
mdc_clk_count <= mdc_clk_count + 1;
|
||||
mdc_falling_edge <= 0;
|
||||
end
|
||||
|
||||
//
|
||||
// MDIO state machine
|
||||
//
|
||||
always @(posedge wb_clk_i or posedge wb_rst_i)
|
||||
if (wb_rst_i)
|
||||
begin
|
||||
mdio_tri <= 1;
|
||||
mdio_out <= 0;
|
||||
mdio_done <= 0;
|
||||
mdio_read_data <= 0;
|
||||
state <= IDLE;
|
||||
end
|
||||
else if (mdc_falling_edge)
|
||||
//
|
||||
// This is the MDIO bus controller. Use falling edge of MDC.
|
||||
//
|
||||
begin
|
||||
// Defaults
|
||||
mdio_tri <= 1;
|
||||
mdio_out <= 0;
|
||||
mdio_done <= 0;
|
||||
|
||||
|
||||
case(state)
|
||||
// IDLE.
|
||||
// In Clause 22 & 45 the master of the MDIO bus is tristate during idle.
|
||||
//
|
||||
IDLE: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_out <= 0;
|
||||
if (mdio_running)
|
||||
state <= PREAMBLE1;
|
||||
end
|
||||
// Preamble. All MDIO transactions begin witrh 32bits of 1 bits as a preamble.
|
||||
PREAMBLE1: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE2;
|
||||
end
|
||||
PREAMBLE2: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE3;
|
||||
end
|
||||
PREAMBLE3: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE4;
|
||||
end
|
||||
PREAMBLE4: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE5;
|
||||
end
|
||||
PREAMBLE5: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE6;
|
||||
end
|
||||
PREAMBLE6: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE7;
|
||||
end
|
||||
PREAMBLE7: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE8;
|
||||
end
|
||||
PREAMBLE8: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE9;
|
||||
end
|
||||
PREAMBLE9: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE10;
|
||||
end
|
||||
PREAMBLE10: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE11;
|
||||
end
|
||||
PREAMBLE11: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE12;
|
||||
end
|
||||
PREAMBLE12: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE13;
|
||||
end
|
||||
PREAMBLE13: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE14;
|
||||
end
|
||||
PREAMBLE14: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE15;
|
||||
end
|
||||
PREAMBLE15: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE16;
|
||||
end
|
||||
PREAMBLE16: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE17;
|
||||
end
|
||||
PREAMBLE17: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE18;
|
||||
end
|
||||
PREAMBLE18: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE19;
|
||||
end
|
||||
PREAMBLE19: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE20;
|
||||
end
|
||||
PREAMBLE20: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE21;
|
||||
end
|
||||
PREAMBLE21: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE22;
|
||||
end
|
||||
PREAMBLE22: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE23;
|
||||
end
|
||||
PREAMBLE23: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE24;
|
||||
end
|
||||
PREAMBLE24: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE25;
|
||||
end
|
||||
PREAMBLE25: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE26;
|
||||
end
|
||||
PREAMBLE26: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE27;
|
||||
end
|
||||
PREAMBLE27: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE28;
|
||||
end
|
||||
PREAMBLE28: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE29;
|
||||
end
|
||||
PREAMBLE29: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE30;
|
||||
end
|
||||
PREAMBLE30: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE31;
|
||||
end
|
||||
PREAMBLE31: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= PREAMBLE32;
|
||||
end
|
||||
PREAMBLE32: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= START1;
|
||||
end
|
||||
//
|
||||
// Start code for Clause 22 is 01 and Clause 45 is 00
|
||||
//
|
||||
START1: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 0;
|
||||
if (mdio_operation[12])
|
||||
// Clause 45 bit set.
|
||||
state <= C45_START2;
|
||||
else
|
||||
state <= C22_START2;
|
||||
end
|
||||
//
|
||||
// 2nd Clause 22 start bit is a 1
|
||||
//
|
||||
C22_START2: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= OP1;
|
||||
end
|
||||
//
|
||||
// 2nd Clause 45 start bit is a 0
|
||||
//
|
||||
C45_START2: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 0;
|
||||
state <= OP1;
|
||||
end
|
||||
//
|
||||
// Both Clause 22 & 45 use 2 bits for operation and are compatable.
|
||||
// Note we don't screen here for illegal Clause 22 ops.
|
||||
//
|
||||
OP1: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_operation[11];
|
||||
state <= OP2;
|
||||
end
|
||||
OP2: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_operation[10];
|
||||
state <= PRTAD1;
|
||||
end
|
||||
//
|
||||
// Both Clause 22 & 45 use 2 sucsessive 5 bit fields to form a hierarchical address
|
||||
// though it's used slightly different between the 2 standards.
|
||||
//
|
||||
PRTAD1: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_operation[9];
|
||||
state <= PRTAD2;
|
||||
end
|
||||
PRTAD2: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_operation[8];
|
||||
state <= PRTAD3;
|
||||
end
|
||||
PRTAD3: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_operation[7];
|
||||
state <= PRTAD4;
|
||||
end
|
||||
PRTAD4: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_operation[6];
|
||||
state <= PRTAD5;
|
||||
end
|
||||
PRTAD5: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_operation[5];
|
||||
state <= DEVAD1;
|
||||
end
|
||||
DEVAD1: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_operation[4];
|
||||
state <= DEVAD2;
|
||||
end
|
||||
DEVAD2: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_operation[3];
|
||||
state <= DEVAD3;
|
||||
end
|
||||
DEVAD3: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_operation[2];
|
||||
state <= DEVAD4;
|
||||
end
|
||||
DEVAD4: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_operation[1];
|
||||
state <= DEVAD5;
|
||||
end
|
||||
DEVAD5: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_operation[0];
|
||||
state <= TA1;
|
||||
end
|
||||
//
|
||||
// Both Clause 22 & Clause 45 use the same turn around on the bus.
|
||||
// Reads have Z as the first bit and 0 driven by the slave for the 2nd bit.
|
||||
// Note that slaves drive the bus on the rising edge of MDC.
|
||||
// Writes and Address cycles have 10 driven by the master.
|
||||
//
|
||||
TA1: begin
|
||||
// Clause22 write or clause45 write or address go to state TA2
|
||||
if ((mdio_operation[12:11] == 2'b10) || (mdio_operation[12:11] == 2'b01))
|
||||
begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 1;
|
||||
state <= TA2;
|
||||
end
|
||||
else // Read
|
||||
begin
|
||||
mdio_tri <= 1;
|
||||
state <= TA3;
|
||||
end
|
||||
end
|
||||
TA2: begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= 0;
|
||||
if (!mdio_operation[12]) // Clause 22 Write
|
||||
state <= WRITE1;
|
||||
else if (mdio_operation[10]) // Clause 45 Write
|
||||
state <= WRITE1;
|
||||
else // Clause 45 ADDRESS
|
||||
state <= C45_ADDR1;
|
||||
end
|
||||
TA3: begin
|
||||
mdio_tri <= 1;
|
||||
state <= READ1;
|
||||
end
|
||||
//
|
||||
// Clause 22 Reads and both forms of clause 45 Reads have the same bus transaction from here out.
|
||||
//
|
||||
READ1: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_read_data[15] <= mdio_in;
|
||||
state <= READ2;
|
||||
end
|
||||
READ2: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_read_data[14] <= mdio_in;
|
||||
state <= READ3;
|
||||
end
|
||||
READ3: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_read_data[13] <= mdio_in;
|
||||
state <= READ4;
|
||||
end
|
||||
READ4: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_read_data[12] <= mdio_in;
|
||||
state <= READ5;
|
||||
end
|
||||
READ5: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_read_data[11] <= mdio_in;
|
||||
state <= READ6;
|
||||
end
|
||||
READ6: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_read_data[10] <= mdio_in;
|
||||
state <= READ7;
|
||||
end
|
||||
READ7: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_read_data[9] <= mdio_in;
|
||||
state <= READ8;
|
||||
end
|
||||
READ8: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_read_data[8] <= mdio_in;
|
||||
state <= READ9;
|
||||
end
|
||||
READ9: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_read_data[7] <= mdio_in;
|
||||
state <= READ10;
|
||||
end
|
||||
READ10: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_read_data[6] <= mdio_in;
|
||||
state <= READ11;
|
||||
end
|
||||
READ11: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_read_data[5] <= mdio_in;
|
||||
state <= READ12;
|
||||
end
|
||||
READ12: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_read_data[4] <= mdio_in;
|
||||
state <= READ13;
|
||||
end
|
||||
READ13: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_read_data[3] <= mdio_in;
|
||||
state <= READ14;
|
||||
end
|
||||
READ14: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_read_data[2] <= mdio_in;
|
||||
state <= READ15;
|
||||
end
|
||||
READ15: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_read_data[1] <= mdio_in;
|
||||
state <= READ16;
|
||||
end
|
||||
READ16: begin
|
||||
mdio_tri <= 1;
|
||||
mdio_read_data[0] <= mdio_in;
|
||||
state <= PREIDLE;
|
||||
mdio_done <= 1;
|
||||
end
|
||||
//
|
||||
// Write 16bits of data for all types of Write.
|
||||
//
|
||||
WRITE1:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_write_data[15];
|
||||
state <= WRITE2;
|
||||
end
|
||||
WRITE2:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_write_data[14];
|
||||
state <= WRITE3;
|
||||
end
|
||||
WRITE3:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_write_data[13];
|
||||
state <= WRITE4;
|
||||
end
|
||||
WRITE4:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_write_data[12];
|
||||
state <= WRITE5;
|
||||
end
|
||||
WRITE5:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_write_data[11];
|
||||
state <= WRITE6;
|
||||
end
|
||||
WRITE6:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_write_data[10];
|
||||
state <= WRITE7;
|
||||
end
|
||||
WRITE7:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_write_data[9];
|
||||
state <= WRITE8;
|
||||
end
|
||||
WRITE8:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_write_data[8];
|
||||
state <= WRITE9;
|
||||
end
|
||||
WRITE9:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_write_data[7];
|
||||
state <= WRITE10;
|
||||
end
|
||||
WRITE10:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_write_data[6];
|
||||
state <= WRITE11;
|
||||
end
|
||||
WRITE11:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_write_data[5];
|
||||
state <= WRITE12;
|
||||
end
|
||||
WRITE12:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_write_data[4];
|
||||
state <= WRITE13;
|
||||
end
|
||||
WRITE13:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_write_data[3];
|
||||
state <= WRITE14;
|
||||
end
|
||||
WRITE14:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_write_data[2];
|
||||
state <= WRITE15;
|
||||
end
|
||||
WRITE15:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_write_data[1];
|
||||
state <= WRITE16;
|
||||
end
|
||||
WRITE16:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_write_data[0];
|
||||
state <= PREIDLE;
|
||||
mdio_done <= 1;
|
||||
end
|
||||
//
|
||||
// Write 16bits of address for a Clause 45 Address transaction
|
||||
//
|
||||
C45_ADDR1:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_address[15];
|
||||
state <= C45_ADDR2;
|
||||
end
|
||||
C45_ADDR2:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_address[14];
|
||||
state <= C45_ADDR3;
|
||||
end
|
||||
C45_ADDR3:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_address[13];
|
||||
state <= C45_ADDR4;
|
||||
end
|
||||
C45_ADDR4:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_address[12];
|
||||
state <= C45_ADDR5;
|
||||
end
|
||||
C45_ADDR5:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_address[11];
|
||||
state <= C45_ADDR6;
|
||||
end
|
||||
C45_ADDR6:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_address[10];
|
||||
state <= C45_ADDR7;
|
||||
end
|
||||
C45_ADDR7:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_address[9];
|
||||
state <= C45_ADDR8;
|
||||
end
|
||||
C45_ADDR8:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_address[8];
|
||||
state <= C45_ADDR9;
|
||||
end
|
||||
C45_ADDR9:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_address[7];
|
||||
state <= C45_ADDR10;
|
||||
end
|
||||
C45_ADDR10:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_address[6];
|
||||
state <= C45_ADDR11;
|
||||
end
|
||||
C45_ADDR11:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_address[5];
|
||||
state <= C45_ADDR12;
|
||||
end
|
||||
C45_ADDR12:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_address[4];
|
||||
state <= C45_ADDR13;
|
||||
end
|
||||
C45_ADDR13:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_address[3];
|
||||
state <= C45_ADDR14;
|
||||
end
|
||||
C45_ADDR14:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_address[2];
|
||||
state <= C45_ADDR15;
|
||||
end
|
||||
C45_ADDR15:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_address[1];
|
||||
state <= C45_ADDR16;
|
||||
end
|
||||
C45_ADDR16:begin
|
||||
mdio_tri <= 0;
|
||||
mdio_out <= mdio_address[0];
|
||||
state <= PREIDLE;
|
||||
mdio_done <= 1;
|
||||
end
|
||||
//
|
||||
// PREIDLE allows the mdio_running bit to reset.
|
||||
//
|
||||
PREIDLE: begin
|
||||
state <= IDLE;
|
||||
end
|
||||
endcase // case(state)
|
||||
|
||||
end // if (mdc_falling_edge)
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
module rxmac_to_ll8
|
||||
(input clk, input reset, input clear,
|
||||
input [7:0] rx_data, input rx_valid, input rx_error, input rx_ack,
|
||||
output [7:0] ll_data, output ll_sof, output ll_eof, output ll_error, output ll_src_rdy, input ll_dst_rdy );
|
||||
|
||||
reg [2:0] xfer_state;
|
||||
|
||||
localparam XFER_IDLE = 0;
|
||||
localparam XFER_ACTIVE = 1;
|
||||
localparam XFER_ERROR = 2;
|
||||
localparam XFER_ERROR2 = 3;
|
||||
localparam XFER_OVERRUN = 4;
|
||||
localparam XFER_OVERRUN2 = 5;
|
||||
|
||||
assign ll_data = rx_data;
|
||||
assign ll_src_rdy = ((rx_valid & (xfer_state != XFER_OVERRUN2) )
|
||||
| (xfer_state == XFER_ERROR)
|
||||
| (xfer_state == XFER_OVERRUN));
|
||||
assign ll_sof = ((xfer_state==XFER_IDLE)|(xfer_state==XFER_ERROR)|(xfer_state==XFER_OVERRUN));
|
||||
assign ll_eof = (rx_ack | (xfer_state==XFER_ERROR) | (xfer_state==XFER_OVERRUN));
|
||||
assign ll_error = (xfer_state == XFER_ERROR)|(xfer_state==XFER_OVERRUN);
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset | clear)
|
||||
xfer_state <= XFER_IDLE;
|
||||
else
|
||||
case(xfer_state)
|
||||
XFER_IDLE :
|
||||
if(rx_valid)
|
||||
xfer_state <= XFER_ACTIVE;
|
||||
XFER_ACTIVE :
|
||||
if(rx_error)
|
||||
xfer_state <= XFER_ERROR;
|
||||
else if(~rx_valid)
|
||||
xfer_state <= XFER_IDLE;
|
||||
else if(~ll_dst_rdy)
|
||||
xfer_state <= XFER_OVERRUN;
|
||||
XFER_ERROR :
|
||||
if(ll_dst_rdy)
|
||||
xfer_state <= XFER_ERROR2;
|
||||
XFER_ERROR2 :
|
||||
if(~rx_error)
|
||||
xfer_state <= XFER_IDLE;
|
||||
XFER_OVERRUN :
|
||||
if(ll_dst_rdy)
|
||||
xfer_state <= XFER_OVERRUN2;
|
||||
XFER_OVERRUN2 :
|
||||
if(~rx_valid)
|
||||
xfer_state <= XFER_IDLE;
|
||||
endcase // case (xfer_state)
|
||||
|
||||
|
||||
endmodule // rxmac_to_ll8
|
||||
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
module simple_gemac
|
||||
(input clk125, input reset,
|
||||
// GMII
|
||||
output GMII_GTX_CLK, output GMII_TX_EN, output GMII_TX_ER, output [7:0] GMII_TXD,
|
||||
input GMII_RX_CLK, input GMII_RX_DV, input GMII_RX_ER, input [7:0] GMII_RXD,
|
||||
|
||||
// Flow Control Interface
|
||||
input pause_req, input [15:0] pause_time_req, input pause_respect_en,
|
||||
|
||||
// Settings
|
||||
input [47:0] ucast_addr, input [47:0] mcast_addr,
|
||||
input pass_ucast, input pass_mcast, input pass_bcast, input pass_pause, input pass_all,
|
||||
|
||||
// RX Client Interface
|
||||
output rx_clk, output [7:0] rx_data, output rx_valid, output rx_error, output rx_ack,
|
||||
|
||||
// TX Client Interface
|
||||
output tx_clk, input [7:0] tx_data, input tx_valid, input tx_error, output tx_ack,
|
||||
|
||||
output [31:0] debug
|
||||
);
|
||||
|
||||
localparam SGE_IFG = 8'd12; // 12 should be the absolute minimum
|
||||
|
||||
wire rst_rxclk, rst_txclk;
|
||||
reset_sync reset_sync_tx (.clk(tx_clk),.reset_in(reset),.reset_out(rst_txclk));
|
||||
reset_sync reset_sync_rx (.clk(rx_clk),.reset_in(reset),.reset_out(rst_rxclk));
|
||||
|
||||
wire [15:0] pause_quanta_rcvd;
|
||||
wire pause_rcvd, pause_apply, paused;
|
||||
|
||||
simple_gemac_tx simple_gemac_tx
|
||||
(.clk125(clk125),.reset(rst_txclk),
|
||||
.GMII_GTX_CLK(GMII_GTX_CLK), .GMII_TX_EN(GMII_TX_EN),
|
||||
.GMII_TX_ER(GMII_TX_ER), .GMII_TXD(GMII_TXD),
|
||||
.tx_clk(tx_clk), .tx_data(tx_data), .tx_valid(tx_valid), .tx_error(tx_error), .tx_ack(tx_ack),
|
||||
.ifg(SGE_IFG), .mac_addr(ucast_addr),
|
||||
.pause_req(pause_req), .pause_time(pause_time_req), // We request flow control
|
||||
.pause_apply(pause_apply), .paused(paused) // We respect flow control
|
||||
);
|
||||
|
||||
simple_gemac_rx simple_gemac_rx
|
||||
(.reset(rst_rxclk),
|
||||
.GMII_RX_CLK(GMII_RX_CLK), .GMII_RX_DV(GMII_RX_DV),
|
||||
.GMII_RX_ER(GMII_RX_ER), .GMII_RXD(GMII_RXD),
|
||||
.rx_clk(rx_clk), .rx_data(rx_data), .rx_valid(rx_valid), .rx_error(rx_error), .rx_ack(rx_ack),
|
||||
.ucast_addr(ucast_addr), .mcast_addr(mcast_addr),
|
||||
.pass_ucast(pass_ucast), .pass_mcast(pass_mcast), .pass_bcast(pass_bcast),
|
||||
.pass_pause(pass_pause), .pass_all(pass_all),
|
||||
.pause_quanta_rcvd(pause_quanta_rcvd), .pause_rcvd(pause_rcvd),
|
||||
.debug(debug)
|
||||
);
|
||||
|
||||
flow_ctrl_tx flow_ctrl_tx
|
||||
(.rst(rst_txclk), .tx_clk(tx_clk),
|
||||
.tx_pause_en(pause_respect_en),
|
||||
.pause_quanta(pause_quanta_rcvd), // 16 bit value
|
||||
.pause_quanta_val(pause_rcvd),
|
||||
.pause_apply(pause_apply),
|
||||
.paused(paused)
|
||||
);
|
||||
|
||||
endmodule // simple_gemac
|
||||
@@ -0,0 +1,182 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
module simple_gemac_rx
|
||||
(input reset,
|
||||
input GMII_RX_CLK, input GMII_RX_DV, input GMII_RX_ER, input [7:0] GMII_RXD,
|
||||
output rx_clk, output [7:0] rx_data, output reg rx_valid, output rx_error, output reg rx_ack,
|
||||
input [47:0] ucast_addr, input [47:0] mcast_addr,
|
||||
input pass_ucast, input pass_mcast, input pass_bcast, input pass_pause, input pass_all,
|
||||
output reg [15:0] pause_quanta_rcvd, output pause_rcvd,
|
||||
output [31:0] debug );
|
||||
|
||||
localparam RX_IDLE = 0;
|
||||
localparam RX_PREAMBLE = 1;
|
||||
localparam RX_FRAME = 2;
|
||||
localparam RX_GOODFRAME = 3;
|
||||
localparam RX_DO_PAUSE = 4;
|
||||
localparam RX_ERROR = 5;
|
||||
localparam RX_DROP = 6;
|
||||
|
||||
localparam RX_PAUSE = 16;
|
||||
localparam RX_PAUSE_CHK88 = RX_PAUSE + 5;
|
||||
localparam RX_PAUSE_CHK08 = RX_PAUSE_CHK88 + 1;
|
||||
localparam RX_PAUSE_CHK00 = RX_PAUSE_CHK08 + 1;
|
||||
localparam RX_PAUSE_CHK01 = RX_PAUSE_CHK00 + 1;
|
||||
localparam RX_PAUSE_STORE_MSB = RX_PAUSE_CHK01 + 1;
|
||||
localparam RX_PAUSE_STORE_LSB = RX_PAUSE_STORE_MSB + 1;
|
||||
localparam RX_PAUSE_WAIT_CRC = RX_PAUSE_STORE_LSB + 1;
|
||||
|
||||
reg [7:0] rxd_d1;
|
||||
reg rx_dv_d1, rx_er_d1;
|
||||
assign rx_clk = GMII_RX_CLK;
|
||||
|
||||
always @(posedge rx_clk)
|
||||
begin
|
||||
rx_dv_d1 <= GMII_RX_DV;
|
||||
rx_er_d1 <= GMII_RX_ER;
|
||||
rxd_d1 <= GMII_RXD;
|
||||
end
|
||||
|
||||
reg [7:0] rx_state;
|
||||
wire [7:0] rxd_del;
|
||||
wire rx_dv_del, rx_er_del;
|
||||
reg go_filt;
|
||||
|
||||
wire match_crc;
|
||||
wire clear_crc = rx_state == RX_IDLE;
|
||||
wire calc_crc = (rx_state == RX_FRAME) | rx_state[7:4]==4'h1;
|
||||
|
||||
localparam DELAY = 6;
|
||||
delay_line #(.WIDTH(10)) rx_delay
|
||||
(.clk(rx_clk), .delay(DELAY), .din({rx_dv_d1,rx_er_d1,rxd_d1}),.dout({rx_dv_del,rx_er_del,rxd_del}));
|
||||
|
||||
always @(posedge rx_clk)
|
||||
if(reset)
|
||||
rx_ack <= 0;
|
||||
else
|
||||
rx_ack <= (rx_state == RX_GOODFRAME);
|
||||
|
||||
wire is_ucast, is_bcast, is_mcast, is_pause, is_any_ucast;
|
||||
wire keep_packet = (pass_all & is_any_ucast) | (pass_ucast & is_ucast) | (pass_mcast & is_mcast) |
|
||||
(pass_bcast & is_bcast) | (pass_pause & is_pause);
|
||||
|
||||
assign rx_data = rxd_del;
|
||||
assign rx_error = (rx_state == RX_ERROR);
|
||||
|
||||
always @(posedge rx_clk)
|
||||
if(reset)
|
||||
rx_valid <= 0;
|
||||
else if(keep_packet)
|
||||
rx_valid <= 1;
|
||||
else if((rx_state == RX_IDLE)|(rx_state == RX_ERROR))
|
||||
rx_valid <= 0;
|
||||
|
||||
address_filter af_ucast (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
|
||||
.address(ucast_addr), .match(is_ucast), .done());
|
||||
address_filter af_mcast (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
|
||||
.address(mcast_addr), .match(is_mcast), .done());
|
||||
address_filter af_bcast (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
|
||||
.address(48'hFFFF_FFFF_FFFF), .match(is_bcast), .done());
|
||||
address_filter af_pause (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
|
||||
.address(48'h0180_c200_0001), .match(is_pause), .done());
|
||||
address_filter_promisc af_promisc (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
|
||||
.match(is_any_ucast), .done());
|
||||
|
||||
always @(posedge rx_clk)
|
||||
go_filt <= (rx_state==RX_PREAMBLE) & (rxd_d1 == 8'hD5);
|
||||
|
||||
reg [15:0] pkt_len_ctr;
|
||||
always @(posedge rx_clk)
|
||||
if(reset |(rx_state == RX_IDLE))
|
||||
pkt_len_ctr <= 0;
|
||||
else
|
||||
pkt_len_ctr <= pkt_len_ctr + 1;
|
||||
|
||||
localparam MIN_PAUSE_LEN = 71; // 6
|
||||
wire pkt_long_enough = (pkt_len_ctr >= MIN_PAUSE_LEN);
|
||||
always @(posedge rx_clk)
|
||||
if(reset)
|
||||
rx_state <= RX_IDLE;
|
||||
else
|
||||
if(rx_er_d1) // | (~pkt_long_enough & ~rx_dv_d1) & (rx_state != RX_IDLE))
|
||||
rx_state <= RX_ERROR;
|
||||
else
|
||||
case(rx_state)
|
||||
RX_IDLE :
|
||||
if(rx_dv_d1)
|
||||
if(rxd_d1 == 8'h55)
|
||||
rx_state <= RX_PREAMBLE;
|
||||
else
|
||||
rx_state <= RX_ERROR;
|
||||
RX_PREAMBLE :
|
||||
if(~rx_dv_d1)
|
||||
rx_state <= RX_ERROR;
|
||||
else if(rxd_d1 == 8'hD5)
|
||||
rx_state <= RX_FRAME;
|
||||
else if(rxd_d1 != 8'h55)
|
||||
rx_state <= RX_ERROR;
|
||||
RX_FRAME :
|
||||
if(is_pause)
|
||||
rx_state <= RX_PAUSE;
|
||||
else if(~rx_dv_d1)
|
||||
if(match_crc)
|
||||
rx_state <= RX_GOODFRAME;
|
||||
else
|
||||
rx_state <= RX_ERROR;
|
||||
RX_PAUSE_CHK88 :
|
||||
if(rxd_d1 != 8'h88)
|
||||
rx_state <= RX_DROP;
|
||||
else
|
||||
rx_state <= RX_PAUSE_CHK08;
|
||||
RX_PAUSE_CHK08 :
|
||||
if(rxd_d1 != 8'h08)
|
||||
rx_state <= RX_DROP;
|
||||
else
|
||||
rx_state <= RX_PAUSE_CHK00;
|
||||
RX_PAUSE_CHK00 :
|
||||
if(rxd_d1 != 8'h00)
|
||||
rx_state <= RX_DROP;
|
||||
else
|
||||
rx_state <= RX_PAUSE_CHK01;
|
||||
RX_PAUSE_CHK01 :
|
||||
if(rxd_d1 != 8'h01)
|
||||
rx_state <= RX_DROP;
|
||||
else
|
||||
rx_state <= RX_PAUSE_STORE_MSB;
|
||||
RX_PAUSE_WAIT_CRC :
|
||||
if(pkt_long_enough)
|
||||
if(match_crc)
|
||||
rx_state <= RX_DO_PAUSE;
|
||||
else
|
||||
rx_state <= RX_DROP;
|
||||
RX_DO_PAUSE :
|
||||
rx_state <= RX_IDLE;
|
||||
RX_GOODFRAME :
|
||||
rx_state <= RX_IDLE;
|
||||
RX_DROP, RX_ERROR :
|
||||
if(~rx_dv_d1)
|
||||
rx_state <= RX_IDLE;
|
||||
default
|
||||
rx_state <= rx_state + 1;
|
||||
endcase // case (rx_state)
|
||||
|
||||
assign pause_rcvd = (rx_state == RX_DO_PAUSE);
|
||||
crc crc_check(.clk(rx_clk),.reset(reset),.clear(clear_crc),
|
||||
.data(rxd_d1),.calc(calc_crc),.crc_out(),.match(match_crc));
|
||||
|
||||
always @(posedge rx_clk)
|
||||
if(reset)
|
||||
pause_quanta_rcvd <= 0;
|
||||
else if(rx_state == RX_PAUSE_STORE_MSB)
|
||||
pause_quanta_rcvd[15:8] <= rxd_d1;
|
||||
else if(rx_state == RX_PAUSE_STORE_LSB)
|
||||
pause_quanta_rcvd[7:0] <= rxd_d1;
|
||||
|
||||
assign debug = rx_state;
|
||||
|
||||
endmodule // simple_gemac_rx
|
||||
@@ -0,0 +1,205 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
module simple_gemac_tb;
|
||||
`include "eth_tasks.v"
|
||||
|
||||
reg clk = 0;
|
||||
reg reset = 1;
|
||||
|
||||
initial #1000 reset = 0;
|
||||
always #50 clk = ~clk;
|
||||
|
||||
wire GMII_RX_DV, GMII_RX_ER, GMII_TX_EN, GMII_TX_ER, GMII_GTX_CLK;
|
||||
wire [7:0] GMII_RXD, GMII_TXD;
|
||||
|
||||
wire rx_valid, rx_error, rx_ack;
|
||||
wire tx_ack, tx_valid, tx_error;
|
||||
|
||||
wire [7:0] rx_data, tx_data;
|
||||
|
||||
reg [15:0] pause_time;
|
||||
reg pause_req = 0;
|
||||
|
||||
wire GMII_RX_CLK = GMII_GTX_CLK;
|
||||
|
||||
reg [7:0] FORCE_DAT_ERR = 0;
|
||||
reg FORCE_ERR = 0;
|
||||
|
||||
// Loopback
|
||||
assign GMII_RX_DV = GMII_TX_EN;
|
||||
assign GMII_RX_ER = GMII_TX_ER | FORCE_ERR;
|
||||
assign GMII_RXD = GMII_TXD ^ FORCE_DAT_ERR;
|
||||
|
||||
wire [47:0] ucast_addr = 48'hF1F2_F3F4_F5F6;
|
||||
wire [47:0] mcast_addr = 0;
|
||||
wire pass_ucast =1, pass_mcast=0, pass_bcast=1, pass_pause=0, pass_all=0;
|
||||
|
||||
simple_gemac simple_gemac
|
||||
(.clk125(clk), .reset(reset),
|
||||
.GMII_GTX_CLK(GMII_GTX_CLK), .GMII_TX_EN(GMII_TX_EN),
|
||||
.GMII_TX_ER(GMII_TX_ER), .GMII_TXD(GMII_TXD),
|
||||
.GMII_RX_CLK(GMII_RX_CLK), .GMII_RX_DV(GMII_RX_DV),
|
||||
.GMII_RX_ER(GMII_RX_ER), .GMII_RXD(GMII_RXD),
|
||||
.pause_req(pause_req), .pause_time(pause_time), .pause_en(1),
|
||||
.ucast_addr(ucast_addr), .mcast_addr(mcast_addr),
|
||||
.pass_ucast(pass_ucast), .pass_mcast(pass_mcast), .pass_bcast(pass_bcast),
|
||||
.pass_pause(pass_pause), .pass_all(pass_all),
|
||||
.rx_clk(rx_clk), .rx_data(rx_data),
|
||||
.rx_valid(rx_valid), .rx_error(rx_error), .rx_ack(rx_ack),
|
||||
.tx_clk(tx_clk), .tx_data(tx_data),
|
||||
.tx_valid(tx_valid), .tx_error(tx_error), .tx_ack(tx_ack)
|
||||
);
|
||||
|
||||
wire rx_ll_sof, rx_ll_eof, rx_ll_src_rdy, rx_ll_dst_rdy;
|
||||
wire rx_ll_sof2, rx_ll_eof2, rx_ll_src_rdy2;
|
||||
reg rx_ll_dst_rdy2 = 1;
|
||||
wire [7:0] rx_ll_data, rx_ll_data2;
|
||||
wire rx_ll_error, rx_ll_error2;
|
||||
|
||||
rxmac_to_ll8 rx_adapt
|
||||
(.clk(clk), .reset(reset), .clear(0),
|
||||
.rx_data(rx_data), .rx_valid(rx_valid), .rx_error(rx_error), .rx_ack(rx_ack),
|
||||
.ll_data(rx_ll_data), .ll_sof(rx_ll_sof), .ll_eof(rx_ll_eof), .ll_error(rx_ll_error),
|
||||
.ll_src_rdy(rx_ll_src_rdy), .ll_dst_rdy(rx_ll_dst_rdy));
|
||||
|
||||
ll8_shortfifo rx_sfifo
|
||||
(.clk(clk), .reset(reset), .clear(0),
|
||||
.datain(rx_ll_data), .sof_i(rx_ll_sof), .eof_i(rx_ll_eof),
|
||||
.error_i(rx_ll_error), .src_rdy_i(rx_ll_src_rdy), .dst_rdy_o(rx_ll_dst_rdy),
|
||||
.dataout(rx_ll_data2), .sof_o(rx_ll_sof2), .eof_o(rx_ll_eof2),
|
||||
.error_o(rx_ll_error2), .src_rdy_o(rx_ll_src_rdy2), .dst_rdy_i(rx_ll_dst_rdy2));
|
||||
|
||||
wire tx_ll_sof, tx_ll_eof, tx_ll_src_rdy, tx_ll_dst_rdy;
|
||||
reg tx_ll_sof2=0, tx_ll_eof2=0;
|
||||
reg tx_ll_src_rdy2 = 0;
|
||||
wire tx_ll_dst_rdy2;
|
||||
wire [7:0] tx_ll_data;
|
||||
reg [7:0] tx_ll_data2 = 0;
|
||||
wire tx_ll_error;
|
||||
wire tx_ll_error2 = 0;
|
||||
|
||||
ll8_shortfifo tx_sfifo
|
||||
(.clk(clk), .reset(reset), .clear(clear),
|
||||
.datain(tx_ll_data2), .sof_i(tx_ll_sof2), .eof_i(tx_ll_eof2),
|
||||
.error_i(tx_ll_error2), .src_rdy_i(tx_ll_src_rdy2), .dst_rdy_o(tx_ll_dst_rdy2),
|
||||
.dataout(tx_ll_data), .sof_o(tx_ll_sof), .eof_o(tx_ll_eof),
|
||||
.error_o(tx_ll_error), .src_rdy_o(tx_ll_src_rdy), .dst_rdy_i(tx_ll_dst_rdy));
|
||||
|
||||
ll8_to_txmac ll8_to_txmac
|
||||
(.clk(clk), .reset(reset), .clear(clear),
|
||||
.ll_data(tx_ll_data), .ll_sof(tx_ll_sof), .ll_eof(tx_ll_eof),
|
||||
.ll_src_rdy(tx_ll_src_rdy), .ll_dst_rdy(tx_ll_dst_rdy),
|
||||
.tx_data(tx_data), .tx_valid(tx_valid), .tx_error(tx_error), .tx_ack(tx_ack));
|
||||
|
||||
initial $dumpfile("simple_gemac_tb.vcd");
|
||||
initial $dumpvars(0,simple_gemac_tb);
|
||||
|
||||
integer i;
|
||||
reg [7:0] pkt_rom[0:65535];
|
||||
reg [1023:0] ROMFile;
|
||||
|
||||
initial
|
||||
for (i=0;i<65536;i=i+1)
|
||||
pkt_rom[i] <= 8'h0;
|
||||
|
||||
initial
|
||||
begin
|
||||
@(negedge reset);
|
||||
repeat (10)
|
||||
@(posedge clk);
|
||||
SendFlowCtrl(16'h0007); // Send flow control
|
||||
@(posedge clk);
|
||||
#30000;
|
||||
@(posedge clk);
|
||||
SendFlowCtrl(16'h0009); // Increas flow control before it expires
|
||||
#10000;
|
||||
@(posedge clk);
|
||||
SendFlowCtrl(16'h0000); // Cancel flow control before it expires
|
||||
@(posedge clk);
|
||||
|
||||
SendPacket_to_ll8(8'hAA,10); // This packet gets dropped by the filters
|
||||
repeat (10)
|
||||
@(posedge clk);
|
||||
|
||||
SendPacketFromFile_ll8(60,0,0); // The rest are valid packets
|
||||
repeat (10)
|
||||
@(posedge clk);
|
||||
|
||||
SendPacketFromFile_ll8(61,0,0);
|
||||
repeat (10)
|
||||
@(posedge clk);
|
||||
SendPacketFromFile_ll8(62,0,0);
|
||||
repeat (10)
|
||||
@(posedge clk);
|
||||
SendPacketFromFile_ll8(63,0,0);
|
||||
repeat (1)
|
||||
@(posedge clk);
|
||||
SendPacketFromFile_ll8(64,0,0);
|
||||
repeat (10)
|
||||
@(posedge clk);
|
||||
SendPacketFromFile_ll8(59,0,0);
|
||||
repeat (1)
|
||||
@(posedge clk);
|
||||
SendPacketFromFile_ll8(58,0,0);
|
||||
repeat (1)
|
||||
@(posedge clk);
|
||||
SendPacketFromFile_ll8(100,0,0);
|
||||
repeat (1)
|
||||
@(posedge clk);
|
||||
SendPacketFromFile_ll8(200,150,30); // waiting 14 empties the fifo, 15 underruns
|
||||
repeat (1)
|
||||
@(posedge clk);
|
||||
SendPacketFromFile_ll8(100,0,30);
|
||||
#10000 $finish;
|
||||
end
|
||||
|
||||
// Force a CRC error
|
||||
initial
|
||||
begin
|
||||
#90000;
|
||||
@(posedge clk);
|
||||
FORCE_DAT_ERR <= 8'h10;
|
||||
@(posedge clk);
|
||||
FORCE_DAT_ERR <= 8'h00;
|
||||
end
|
||||
|
||||
// Force an RX_ER error (i.e. link loss)
|
||||
initial
|
||||
begin
|
||||
#116000;
|
||||
@(posedge clk);
|
||||
FORCE_ERR <= 1;
|
||||
@(posedge clk);
|
||||
FORCE_ERR <= 0;
|
||||
end
|
||||
|
||||
// Cause receive fifo to fill, causing an RX overrun
|
||||
initial
|
||||
begin
|
||||
#126000;
|
||||
@(posedge clk);
|
||||
rx_ll_dst_rdy2 <= 0;
|
||||
repeat (30) // Repeat of 14 fills the shortfifo, but works. 15 overflows
|
||||
@(posedge clk);
|
||||
rx_ll_dst_rdy2 <= 1;
|
||||
end
|
||||
|
||||
// Tests: Send and recv flow control, send and receive good packets, RX CRC err, RX_ER, RX overrun, TX underrun
|
||||
// Still need to test: CRC errors on Pause Frames
|
||||
|
||||
always @(posedge clk)
|
||||
if(rx_ll_src_rdy2 & rx_ll_dst_rdy2)
|
||||
begin
|
||||
if(rx_ll_sof2 & ~rx_ll_eof2)
|
||||
$display("RX-PKT-START %d",$time);
|
||||
$display("RX-PKT SOF %d EOF %d ERR%d DAT %x",rx_ll_sof2,rx_ll_eof2,rx_ll_error2,rx_ll_data2);
|
||||
if(rx_ll_eof2 & ~rx_ll_sof2)
|
||||
$display("RX-PKT-END %d",$time);
|
||||
end
|
||||
|
||||
endmodule // simple_gemac_tb
|
||||
@@ -0,0 +1,259 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
module simple_gemac_tx
|
||||
(input clk125, input reset,
|
||||
output GMII_GTX_CLK, output reg GMII_TX_EN, output reg GMII_TX_ER, output reg [7:0] GMII_TXD,
|
||||
output tx_clk, input [7:0] tx_data, input tx_valid, input tx_error, output tx_ack,
|
||||
input [7:0] ifg, input [47:0] mac_addr,
|
||||
input pause_req, input [15:0] pause_time,
|
||||
input pause_apply, output reg paused
|
||||
);
|
||||
|
||||
reg tx_en_pre, tx_er_pre;
|
||||
reg [7:0] txd_pre;
|
||||
|
||||
assign GMII_GTX_CLK = clk125;
|
||||
assign tx_clk = clk125;
|
||||
|
||||
reg [7:0] tx_state;
|
||||
reg [7:0] ifg_ctr;
|
||||
reg [15:0] frame_len_ctr;
|
||||
reg [7:0] pause_ctr, pause_dat;
|
||||
|
||||
wire in_ifg = (ifg_ctr != 0);
|
||||
|
||||
wire [31:0] crc_out;
|
||||
|
||||
localparam TX_IDLE = 0;
|
||||
localparam TX_PREAMBLE = 1;
|
||||
localparam TX_SOF_DEL = TX_PREAMBLE + 7;
|
||||
localparam TX_FIRSTBYTE = TX_SOF_DEL + 1;
|
||||
localparam TX_IN_FRAME = TX_FIRSTBYTE + 1;
|
||||
localparam TX_IN_FRAME_2 = TX_IN_FRAME + 1;
|
||||
localparam TX_PAD = TX_IN_FRAME_2 + 1;
|
||||
localparam TX_CRC_0 = 16;
|
||||
localparam TX_CRC_1 = TX_CRC_0 + 1;
|
||||
localparam TX_CRC_2 = TX_CRC_0 + 2;
|
||||
localparam TX_CRC_3 = TX_CRC_0 + 3;
|
||||
localparam TX_ERROR = 32;
|
||||
localparam TX_PAUSE = 55;
|
||||
localparam TX_PAUSE_SOF = TX_PAUSE + 7;
|
||||
localparam TX_PAUSE_FIRST = TX_PAUSE_SOF + 1;
|
||||
localparam TX_PAUSE_END = TX_PAUSE_SOF + 18;
|
||||
|
||||
localparam MIN_FRAME_LEN = 64 + 8 - 4; // Min frame length includes preamble but not CRC
|
||||
localparam MAX_FRAME_LEN = 8192; // How big are the jumbo frames we want to handle?
|
||||
always @(posedge tx_clk)
|
||||
if(reset |(tx_state == TX_IDLE))
|
||||
frame_len_ctr <= 0;
|
||||
else
|
||||
frame_len_ctr <= frame_len_ctr + 1;
|
||||
|
||||
reg send_pause;
|
||||
reg [15:0] pause_time_held;
|
||||
|
||||
always @(posedge tx_clk)
|
||||
if(reset)
|
||||
send_pause <= 0;
|
||||
else if(pause_req)
|
||||
send_pause <= 1;
|
||||
else if(tx_state == TX_PAUSE)
|
||||
send_pause <= 0;
|
||||
|
||||
always @(posedge tx_clk)
|
||||
if(pause_req)
|
||||
pause_time_held <= pause_time;
|
||||
|
||||
always @(posedge tx_clk)
|
||||
if(reset)
|
||||
tx_state <= TX_IDLE;
|
||||
else
|
||||
case(tx_state)
|
||||
TX_IDLE :
|
||||
if(~in_ifg)
|
||||
if(send_pause)
|
||||
tx_state <= TX_PAUSE;
|
||||
else if(tx_valid & ~pause_apply)
|
||||
tx_state <= TX_PREAMBLE;
|
||||
TX_FIRSTBYTE :
|
||||
if(tx_error)
|
||||
tx_state <= TX_ERROR; // underrun
|
||||
else if(~tx_valid)
|
||||
tx_state <= TX_PAD;
|
||||
else
|
||||
tx_state <= TX_IN_FRAME;
|
||||
TX_IN_FRAME :
|
||||
if(tx_error)
|
||||
tx_state <= TX_ERROR; // underrun
|
||||
else if(~tx_valid)
|
||||
tx_state <= TX_PAD;
|
||||
else if(frame_len_ctr == MIN_FRAME_LEN - 1)
|
||||
tx_state <= TX_IN_FRAME_2;
|
||||
TX_IN_FRAME_2 :
|
||||
if(tx_error)
|
||||
tx_state <= TX_ERROR; // underrun
|
||||
else if(~tx_valid)
|
||||
tx_state <= TX_CRC_0;
|
||||
TX_PAD :
|
||||
if(frame_len_ctr == MIN_FRAME_LEN)
|
||||
tx_state <= TX_CRC_0;
|
||||
TX_CRC_3 :
|
||||
tx_state <= TX_IDLE;
|
||||
TX_ERROR :
|
||||
tx_state <= TX_IDLE;
|
||||
TX_PAUSE_END :
|
||||
tx_state <= TX_PAD;
|
||||
default :
|
||||
tx_state <= tx_state + 1;
|
||||
endcase // case (tx_state)
|
||||
|
||||
always @(posedge tx_clk)
|
||||
if(reset)
|
||||
begin
|
||||
tx_en_pre <= 0;
|
||||
tx_er_pre <= 0;
|
||||
txd_pre <= 0;
|
||||
end
|
||||
else
|
||||
casex(tx_state)
|
||||
TX_IDLE :
|
||||
begin
|
||||
tx_en_pre <= 0;
|
||||
tx_er_pre <= 0;
|
||||
txd_pre <= 0;
|
||||
end
|
||||
TX_PREAMBLE, TX_PAUSE :
|
||||
begin
|
||||
txd_pre <= 8'h55;
|
||||
tx_en_pre <= 1;
|
||||
end
|
||||
TX_SOF_DEL, TX_PAUSE_SOF :
|
||||
txd_pre <= 8'hD5;
|
||||
TX_FIRSTBYTE, TX_IN_FRAME, TX_IN_FRAME_2 :
|
||||
txd_pre <= tx_valid ? tx_data : 0;
|
||||
TX_ERROR :
|
||||
begin
|
||||
tx_er_pre <= 1;
|
||||
txd_pre <= 0;
|
||||
end
|
||||
TX_CRC_3 :
|
||||
tx_en_pre <= 0;
|
||||
TX_PAD :
|
||||
txd_pre <= 0;
|
||||
TX_PAUSE_FIRST, 8'b01xx_xxxx : // In Pause Frame
|
||||
txd_pre <= pause_dat;
|
||||
endcase // case (tx_state)
|
||||
|
||||
localparam SGE_FLOW_CTRL_ADDR = 48'h01_80_C2_00_00_01;
|
||||
always @(posedge tx_clk)
|
||||
case(tx_state)
|
||||
TX_PAUSE_SOF :
|
||||
pause_dat <= SGE_FLOW_CTRL_ADDR[47:40]; // Note everything must be 1 cycle early
|
||||
TX_PAUSE_SOF + 1:
|
||||
pause_dat <= SGE_FLOW_CTRL_ADDR[39:32];
|
||||
TX_PAUSE_SOF + 2:
|
||||
pause_dat <= SGE_FLOW_CTRL_ADDR[31:24];
|
||||
TX_PAUSE_SOF + 3:
|
||||
pause_dat <= SGE_FLOW_CTRL_ADDR[23:16];
|
||||
TX_PAUSE_SOF + 4:
|
||||
pause_dat <= SGE_FLOW_CTRL_ADDR[15:8];
|
||||
TX_PAUSE_SOF + 5:
|
||||
pause_dat <= SGE_FLOW_CTRL_ADDR[7:0];
|
||||
TX_PAUSE_SOF + 6:
|
||||
pause_dat <= mac_addr[47:40];
|
||||
TX_PAUSE_SOF + 7:
|
||||
pause_dat <= mac_addr[39:32];
|
||||
TX_PAUSE_SOF + 8:
|
||||
pause_dat <= mac_addr[31:24];
|
||||
TX_PAUSE_SOF + 9:
|
||||
pause_dat <= mac_addr[23:16];
|
||||
TX_PAUSE_SOF + 10:
|
||||
pause_dat <= mac_addr[15:8];
|
||||
TX_PAUSE_SOF + 11:
|
||||
pause_dat <= mac_addr[7:0];
|
||||
TX_PAUSE_SOF + 12:
|
||||
pause_dat <= 8'h88; // Type = 8808 = MAC ctrl frame
|
||||
TX_PAUSE_SOF + 13:
|
||||
pause_dat <= 8'h08;
|
||||
TX_PAUSE_SOF + 14:
|
||||
pause_dat <= 8'h00; // Opcode = 0001 = PAUSE
|
||||
TX_PAUSE_SOF + 15:
|
||||
pause_dat <= 8'h01;
|
||||
TX_PAUSE_SOF + 16:
|
||||
pause_dat <= pause_time_held[15:8];
|
||||
TX_PAUSE_SOF + 17:
|
||||
pause_dat <= pause_time_held[7:0];
|
||||
endcase // case (tx_state)
|
||||
|
||||
wire start_ifg = (tx_state == TX_CRC_3);
|
||||
always @(posedge tx_clk)
|
||||
if(reset)
|
||||
ifg_ctr <= 100;
|
||||
else if(start_ifg)
|
||||
ifg_ctr <= ifg;
|
||||
else if(ifg_ctr != 0)
|
||||
ifg_ctr <= ifg_ctr - 1;
|
||||
|
||||
wire clear_crc = (tx_state == TX_IDLE);
|
||||
|
||||
wire calc_crc =
|
||||
(tx_state==TX_IN_FRAME) |
|
||||
(tx_state==TX_IN_FRAME_2) |
|
||||
(tx_state==TX_PAD) |
|
||||
(tx_state[6]);
|
||||
|
||||
crc crc(.clk(tx_clk), .reset(reset), .clear(clear_crc),
|
||||
.data(txd_pre), .calc(calc_crc), .crc_out(crc_out));
|
||||
|
||||
assign tx_ack = (tx_state == TX_FIRSTBYTE);
|
||||
|
||||
always @(posedge tx_clk)
|
||||
begin
|
||||
GMII_TX_EN <= tx_en_pre;
|
||||
GMII_TX_ER <= tx_er_pre;
|
||||
case(tx_state)
|
||||
TX_CRC_0 :
|
||||
GMII_TXD <= crc_out[31:24];
|
||||
TX_CRC_1 :
|
||||
GMII_TXD <= crc_out[23:16];
|
||||
TX_CRC_2 :
|
||||
GMII_TXD <= crc_out[15:8];
|
||||
TX_CRC_3 :
|
||||
GMII_TXD <= crc_out[7:0];
|
||||
default :
|
||||
GMII_TXD <= txd_pre;
|
||||
endcase // case (tx_state)
|
||||
end
|
||||
|
||||
// report that we are paused only when we get back to IDLE
|
||||
always @(posedge tx_clk)
|
||||
if(reset)
|
||||
paused <= 0;
|
||||
else if(~pause_apply)
|
||||
paused <= 0;
|
||||
else if(tx_state == TX_IDLE)
|
||||
paused <= 1;
|
||||
|
||||
endmodule // simple_gemac_tx
|
||||
|
||||
// Testing code
|
||||
/*
|
||||
reg [7:0] crc_ctr;
|
||||
reg calc_crc_d1;
|
||||
always @(posedge tx_clk)
|
||||
calc_crc_d1 <= calc_crc;
|
||||
|
||||
always @(posedge tx_clk)
|
||||
if(reset)
|
||||
crc_ctr <= 0;
|
||||
else if(calc_crc)
|
||||
crc_ctr <= crc_ctr+1;
|
||||
else if(calc_crc_d1)
|
||||
$display("CRC COUNT = %d",crc_ctr);
|
||||
else
|
||||
crc_ctr <= 0;
|
||||
*/
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
iverilog -Wimplict -Wportbind -y ../fifo/ -y ../models/ -y . -y miim -y ../control -y ../coregen/ -y ../control_lib/ -o simple_gemac_wrapper_tb simple_gemac_wrapper_tb.v
|
||||
@@ -0,0 +1,182 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
module simple_gemac_wrapper
|
||||
#(parameter RX_FLOW_CTRL=0,
|
||||
parameter PORTNUM=8'd0)
|
||||
(input clk125, input reset,
|
||||
// GMII
|
||||
output GMII_GTX_CLK, output GMII_TX_EN, output GMII_TX_ER, output [7:0] GMII_TXD,
|
||||
input GMII_RX_CLK, input GMII_RX_DV, input GMII_RX_ER, input [7:0] GMII_RXD,
|
||||
|
||||
// Client FIFO Interfaces
|
||||
input sys_clk,
|
||||
output [63:0] rx_tdata, output [3:0] rx_tuser, output rx_tlast, output rx_tvalid, input rx_tready,
|
||||
input [63:0] tx_tdata, input [3:0] tx_tuser, input tx_tlast, input tx_tvalid, output tx_tready,
|
||||
|
||||
|
||||
// Wishbone Bus
|
||||
input wb_clk_i,
|
||||
input wb_rst_i,
|
||||
input [7:0] wb_adr_i,
|
||||
input [31:0] wb_dat_i,
|
||||
input wb_we_i,
|
||||
input wb_stb_i,
|
||||
input wb_cyc_i,
|
||||
output [31:0] wb_dat_o,
|
||||
output wb_ack_o,
|
||||
output wb_int_o,
|
||||
|
||||
// MDIO
|
||||
output mdc,
|
||||
input mdio_out,
|
||||
output mdio_tri,
|
||||
output mdio_in,
|
||||
|
||||
// Debug
|
||||
output [31:0] debug_rx,
|
||||
output [31:0] debug_tx
|
||||
);
|
||||
|
||||
wire clear = 0;
|
||||
wire [7:0] rx_data, tx_data;
|
||||
wire tx_clk, tx_valid, tx_error, tx_ack;
|
||||
wire rx_clk, rx_valid, rx_error, rx_ack;
|
||||
|
||||
wire pause_req;
|
||||
wire pause_request_en, pause_respect_en;
|
||||
wire [15:0] pause_time, pause_thresh, pause_time_req, rx_fifo_space;
|
||||
|
||||
wire [31:0] debug_state;
|
||||
|
||||
wire tx_reset, rx_reset;
|
||||
reset_sync reset_sync_tx (.clk(tx_clk),.reset_in(reset),.reset_out(tx_reset));
|
||||
reset_sync reset_sync_rx (.clk(rx_clk),.reset_in(reset),.reset_out(rx_reset));
|
||||
|
||||
simple_gemac simple_gemac
|
||||
(.clk125(clk125), .reset(reset),
|
||||
.GMII_GTX_CLK(GMII_GTX_CLK), .GMII_TX_EN(GMII_TX_EN),
|
||||
.GMII_TX_ER(GMII_TX_ER), .GMII_TXD(GMII_TXD),
|
||||
.GMII_RX_CLK(GMII_RX_CLK), .GMII_RX_DV(GMII_RX_DV),
|
||||
.GMII_RX_ER(GMII_RX_ER), .GMII_RXD(GMII_RXD),
|
||||
.pause_req(RX_FLOW_CTRL ? pause_req : 1'b0), .pause_time_req(RX_FLOW_CTRL ? pause_time_req : 16'd0),
|
||||
.pause_respect_en(pause_respect_en),
|
||||
.ucast_addr(48'h0), .mcast_addr(48'h0),
|
||||
.pass_ucast(1'b0), .pass_mcast(1'b0), .pass_bcast(1'b0),
|
||||
.pass_pause(1'b0), .pass_all(1'b1),
|
||||
.rx_clk(rx_clk), .rx_data(rx_data),
|
||||
.rx_valid(rx_valid), .rx_error(rx_error), .rx_ack(rx_ack),
|
||||
.tx_clk(tx_clk), .tx_data(tx_data),
|
||||
.tx_valid(tx_valid), .tx_error(tx_error), .tx_ack(tx_ack),
|
||||
.debug(debug_state)
|
||||
);
|
||||
|
||||
assign pause_respect_en = 1'b0;
|
||||
assign pause_request_en = 1'b0;
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////////////
|
||||
// RX FIFO Chain
|
||||
wire rx_ll_eof, rx_ll_error, rx_ll_src_rdy, rx_ll_dst_rdy;
|
||||
wire [7:0] rx_ll_data;
|
||||
|
||||
wire [63:0] rx_tdata_int;
|
||||
wire [3:0] rx_tuser_int;
|
||||
wire rx_tlast_int, rx_tvalid_int, rx_tready_int;
|
||||
|
||||
rxmac_to_ll8 rxmac_to_ll8
|
||||
(.clk(rx_clk), .reset(rx_reset), .clear(0),
|
||||
.rx_data(rx_data), .rx_valid(rx_valid), .rx_error(rx_error), .rx_ack(rx_ack),
|
||||
.ll_data(rx_ll_data), .ll_sof(), .ll_eof(rx_ll_eof), .ll_error(rx_ll_error), // ignore sof
|
||||
.ll_src_rdy(rx_ll_src_rdy), .ll_dst_rdy(rx_ll_dst_rdy));
|
||||
|
||||
ll8_to_axi64 #(.START_BYTE(6), .LABEL(PORTNUM)) ll8_to_axi64
|
||||
(.clk(rx_clk), .reset(rx_reset), .clear(0),
|
||||
.ll_data(rx_ll_data), .ll_eof(rx_ll_eof), .ll_error(rx_ll_error), .ll_src_rdy(rx_ll_src_rdy), .ll_dst_rdy(rx_ll_dst_rdy),
|
||||
.axi64_tdata(rx_tdata_int), .axi64_tlast(rx_tlast_int), .axi64_tuser(rx_tuser_int),
|
||||
.axi64_tvalid(rx_tvalid_int), .axi64_tready(rx_tready_int));
|
||||
|
||||
axi64_8k_2clk_fifo rxfifo_2clk
|
||||
(.s_aresetn(~rx_reset),
|
||||
.s_aclk(rx_clk), .s_axis_tvalid(rx_tvalid_int), .s_axis_tready(rx_tready_int),
|
||||
.s_axis_tdata(rx_tdata_int), .s_axis_tlast(rx_tlast_int), .s_axis_tuser(rx_tuser_int),
|
||||
.axis_wr_data_count(),
|
||||
|
||||
.m_aclk(sys_clk), .m_axis_tvalid(rx_tvalid), .m_axis_tready(rx_tready),
|
||||
.m_axis_tdata(rx_tdata), .m_axis_tlast(rx_tlast), .m_axis_tuser(rx_tuser),
|
||||
.axis_rd_data_count() );
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////////////
|
||||
// TX FIFO Chain
|
||||
wire tx_ll_eof, tx_ll_src_rdy, tx_ll_dst_rdy;
|
||||
wire [7:0] tx_ll_data;
|
||||
|
||||
wire [63:0] tx_tdata_int;
|
||||
wire [3:0] tx_tuser_int;
|
||||
wire tx_tlast_int, tx_tvalid_int, tx_tready_int;
|
||||
|
||||
axi64_8k_2clk_fifo txfifo_2clk
|
||||
(.s_aresetn(~tx_reset),
|
||||
.s_aclk(sys_clk), .s_axis_tvalid(tx_tvalid), .s_axis_tready(tx_tready),
|
||||
.s_axis_tdata(tx_tdata), .s_axis_tlast(tx_tlast), .s_axis_tuser(tx_tuser),
|
||||
.axis_wr_data_count(),
|
||||
|
||||
.m_aclk(tx_clk), .m_axis_tvalid(tx_tvalid_int), .m_axis_tready(tx_tready_int),
|
||||
.m_axis_tdata(tx_tdata_int), .m_axis_tlast(tx_tlast_int), .m_axis_tuser(tx_tuser_int),
|
||||
.axis_rd_data_count() );
|
||||
|
||||
axi64_to_ll8 #(.START_BYTE(6)) axi64_to_ll8
|
||||
(.clk(tx_clk), .reset(tx_reset), .clear(0),
|
||||
.axi64_tdata(tx_tdata_int), .axi64_tlast(tx_tlast_int), .axi64_tuser(tx_tuser_int),
|
||||
.axi64_tvalid(tx_tvalid_int), .axi64_tready(tx_tready_int),
|
||||
.ll_data(tx_ll_data), .ll_eof(tx_ll_eof), .ll_src_rdy(tx_ll_src_rdy), .ll_dst_rdy(tx_ll_dst_rdy));
|
||||
|
||||
ll8_to_txmac ll8_to_txmac
|
||||
(.clk(tx_clk), .reset(tx_reset), .clear(clear),
|
||||
.ll_data(tx_ll_data), .ll_eof(tx_ll_eof), .ll_src_rdy(tx_ll_src_rdy), .ll_dst_rdy(tx_ll_dst_rdy),
|
||||
.tx_data(tx_data), .tx_valid(tx_valid), .tx_error(tx_error), .tx_ack(tx_ack));
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////////////
|
||||
// Flow Control
|
||||
generate
|
||||
if(RX_FLOW_CTRL==1)
|
||||
flow_ctrl_rx flow_ctrl_rx
|
||||
(.pause_request_en(pause_request_en), .pause_time(pause_time), .pause_thresh(pause_thresh),
|
||||
.rx_clk(rx_clk), .rx_reset(rx_reset), .rx_fifo_space(rx_fifo_space),
|
||||
.tx_clk(tx_clk), .tx_reset(tx_reset), .pause_req(pause_req), .pause_time_req(pause_time_req));
|
||||
endgenerate
|
||||
|
||||
assign debug_tx = { { tx_ll_data },
|
||||
{ 1'b0, tx_ll_eof, tx_ll_src_rdy, tx_ll_dst_rdy, 4'b0 },
|
||||
{ tx_valid, tx_error, tx_ack, 5'b0},
|
||||
{ tx_data} };
|
||||
assign debug_rx = { { rx_ll_data },
|
||||
{ rx_ll_error, rx_ll_eof, rx_ll_src_rdy, rx_ll_dst_rdy, 4'b0 },
|
||||
{ rx_valid, rx_error, rx_ack, 5'b0},
|
||||
{ rx_data} };
|
||||
|
||||
//
|
||||
// Wishbone MDIO controller
|
||||
//
|
||||
mdio mdio_gige_inst
|
||||
(
|
||||
.wb_clk_i(wb_clk_i),
|
||||
.wb_rst_i(wb_rst_i),
|
||||
.wb_adr_i(wb_adr_i),
|
||||
.wb_dat_i(wb_dat_i),
|
||||
.wb_we_i(wb_we_i),
|
||||
.wb_stb_i(wb_stb_i),
|
||||
.wb_cyc_i(wb_cyc_i),
|
||||
.wb_dat_o(wb_dat_o),
|
||||
.wb_ack_o(wb_ack_o),
|
||||
.wb_int_o(wb_int_o),
|
||||
.mdc(mdc),
|
||||
.mdio_out(mdio_in), // Switch sense of in and out here for master and slave.
|
||||
.mdio_tri(mdio_tri),
|
||||
.mdio_in(mdio_out) // Switch sense of in and out here for master and slave.
|
||||
);
|
||||
|
||||
endmodule // simple_gemac_wrapper
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
module simple_gemac_wrapper_tb;
|
||||
`include "eth_tasks_f36.v"
|
||||
|
||||
reg reset = 1;
|
||||
initial #1000 reset = 0;
|
||||
wire wb_rst = reset;
|
||||
|
||||
reg eth_clk = 0;
|
||||
always #50 eth_clk = ~eth_clk;
|
||||
|
||||
reg wb_clk = 0;
|
||||
always #173 wb_clk = ~wb_clk;
|
||||
|
||||
reg sys_clk = 0;
|
||||
always #77 sys_clk = ~ sys_clk;
|
||||
|
||||
wire GMII_RX_DV, GMII_RX_ER, GMII_TX_EN, GMII_TX_ER, GMII_GTX_CLK;
|
||||
wire [7:0] GMII_RXD, GMII_TXD;
|
||||
|
||||
wire rx_valid, rx_error, rx_ack;
|
||||
wire tx_ack, tx_valid, tx_error;
|
||||
|
||||
wire [7:0] rx_data, tx_data;
|
||||
|
||||
wire GMII_RX_CLK = GMII_GTX_CLK;
|
||||
|
||||
reg [7:0] FORCE_DAT_ERR = 0;
|
||||
reg FORCE_ERR = 0;
|
||||
|
||||
// Loopback
|
||||
assign GMII_RX_DV = GMII_TX_EN;
|
||||
assign GMII_RX_ER = GMII_TX_ER | FORCE_ERR;
|
||||
assign GMII_RXD = GMII_TXD ^ FORCE_DAT_ERR;
|
||||
|
||||
|
||||
wire [31:0] wb_dat_o;
|
||||
reg [31:0] wb_dat_i;
|
||||
reg [7:0] wb_adr;
|
||||
reg wb_stb=0, wb_cyc=0, wb_we=0;
|
||||
wire wb_ack;
|
||||
|
||||
reg [35:0] tx_f36_data=0;
|
||||
reg tx_f36_src_rdy = 0;
|
||||
wire tx_f36_dst_rdy;
|
||||
wire [35:0] rx_f36_data;
|
||||
wire rx_f36_src_rdy;
|
||||
wire rx_f36_dst_rdy = 1;
|
||||
|
||||
simple_gemac_wrapper simple_gemac_wrapper
|
||||
(.clk125(eth_clk), .reset(reset),
|
||||
.GMII_GTX_CLK(GMII_GTX_CLK), .GMII_TX_EN(GMII_TX_EN),
|
||||
.GMII_TX_ER(GMII_TX_ER), .GMII_TXD(GMII_TXD),
|
||||
.GMII_RX_CLK(GMII_RX_CLK), .GMII_RX_DV(GMII_RX_DV),
|
||||
.GMII_RX_ER(GMII_RX_ER), .GMII_RXD(GMII_RXD),
|
||||
|
||||
.sys_clk(sys_clk), .rx_f36_data(rx_f36_data), .rx_f36_src_rdy(rx_f36_src_rdy), .rx_f36_dst_rdy(rx_f36_dst_rdy),
|
||||
.tx_f36_data(tx_f36_data), .tx_f36_src_rdy(tx_f36_src_rdy), .tx_f36_dst_rdy(tx_f36_dst_rdy),
|
||||
|
||||
.wb_clk(wb_clk), .wb_rst(wb_rst), .wb_stb(wb_stb), .wb_cyc(wb_cyc), .wb_ack(wb_ack), .wb_we(wb_we),
|
||||
.wb_adr(wb_adr), .wb_dat_i(wb_dat_i), .wb_dat_o(wb_dat_o),
|
||||
|
||||
.mdio(), .mdc(),
|
||||
.debug() );
|
||||
|
||||
initial $dumpfile("simple_gemac_wrapper_tb.vcd");
|
||||
initial $dumpvars(0,simple_gemac_wrapper_tb);
|
||||
|
||||
integer i;
|
||||
reg [7:0] pkt_rom[0:65535];
|
||||
reg [1023:0] ROMFile;
|
||||
|
||||
initial
|
||||
for (i=0;i<65536;i=i+1)
|
||||
pkt_rom[i] <= 8'h0;
|
||||
|
||||
initial
|
||||
begin
|
||||
@(negedge reset);
|
||||
repeat (10)
|
||||
@(posedge wb_clk);
|
||||
WishboneWR(0,6'b111101);
|
||||
WishboneWR(4,16'hA0B0);
|
||||
WishboneWR(8,32'hC0D0_A1B1);
|
||||
WishboneWR(12,16'h0000);
|
||||
WishboneWR(16,32'h0000_0000);
|
||||
|
||||
@(posedge eth_clk);
|
||||
SendFlowCtrl(16'h0007); // Send flow control
|
||||
@(posedge eth_clk);
|
||||
#30000;
|
||||
@(posedge eth_clk);
|
||||
SendFlowCtrl(16'h0009); // Increase flow control before it expires
|
||||
#10000;
|
||||
@(posedge eth_clk);
|
||||
SendFlowCtrl(16'h0000); // Cancel flow control before it expires
|
||||
@(posedge eth_clk);
|
||||
|
||||
repeat (1000)
|
||||
@(posedge sys_clk);
|
||||
SendPacket_to_fifo36(32'hA0B0C0D0,10); // This packet gets dropped by the filters
|
||||
repeat (1000)
|
||||
@(posedge sys_clk);
|
||||
|
||||
SendPacket_to_fifo36(32'hAABBCCDD,100); // This packet gets dropped by the filters
|
||||
repeat (10)
|
||||
@(posedge sys_clk);
|
||||
/*
|
||||
SendPacketFromFile_f36(60,0,0); // The rest are valid packets
|
||||
repeat (10)
|
||||
@(posedge clk);
|
||||
|
||||
SendPacketFromFile_f36(61,0,0);
|
||||
repeat (10)
|
||||
@(posedge clk);
|
||||
SendPacketFromFile_f36(62,0,0);
|
||||
repeat (10)
|
||||
@(posedge clk);
|
||||
SendPacketFromFile_f36(63,0,0);
|
||||
repeat (1)
|
||||
@(posedge clk);
|
||||
SendPacketFromFile_f36(64,0,0);
|
||||
repeat (10)
|
||||
@(posedge clk);
|
||||
SendPacketFromFile_f36(59,0,0);
|
||||
repeat (1)
|
||||
@(posedge clk);
|
||||
SendPacketFromFile_f36(58,0,0);
|
||||
repeat (1)
|
||||
@(posedge clk);
|
||||
SendPacketFromFile_f36(100,0,0);
|
||||
repeat (1)
|
||||
@(posedge clk);
|
||||
SendPacketFromFile_f36(200,150,30); // waiting 14 empties the fifo, 15 underruns
|
||||
repeat (1)
|
||||
@(posedge clk);
|
||||
SendPacketFromFile_f36(100,0,30);
|
||||
*/
|
||||
#100000 $finish;
|
||||
end
|
||||
|
||||
// Force a CRC error
|
||||
initial
|
||||
begin
|
||||
#90000;
|
||||
@(posedge eth_clk);
|
||||
FORCE_DAT_ERR <= 8'h10;
|
||||
@(posedge eth_clk);
|
||||
FORCE_DAT_ERR <= 8'h00;
|
||||
end
|
||||
|
||||
// Force an RX_ER error (i.e. link loss)
|
||||
initial
|
||||
begin
|
||||
#116000;
|
||||
@(posedge eth_clk);
|
||||
FORCE_ERR <= 1;
|
||||
@(posedge eth_clk);
|
||||
FORCE_ERR <= 0;
|
||||
end
|
||||
/*
|
||||
// Cause receive fifo to fill, causing an RX overrun
|
||||
initial
|
||||
begin
|
||||
#126000;
|
||||
@(posedge clk);
|
||||
rx_ll_dst_rdy2 <= 0;
|
||||
repeat (30) // Repeat of 14 fills the shortfifo, but works. 15 overflows
|
||||
@(posedge clk);
|
||||
rx_ll_dst_rdy2 <= 1;
|
||||
end
|
||||
*/
|
||||
// Tests: Send and recv flow control, send and receive good packets, RX CRC err, RX_ER, RX overrun, TX underrun
|
||||
// Still need to test: CRC errors on Pause Frames, MDIO, wishbone
|
||||
|
||||
task WishboneWR;
|
||||
input [7:0] adr;
|
||||
input [31:0] value;
|
||||
begin
|
||||
wb_adr <= adr;
|
||||
wb_dat_i <= value;
|
||||
wb_stb <= 1;
|
||||
wb_cyc <= 1;
|
||||
wb_we <= 1;
|
||||
while (~wb_ack)
|
||||
@(posedge wb_clk);
|
||||
@(posedge wb_clk);
|
||||
wb_stb <= 0;
|
||||
wb_cyc <= 0;
|
||||
wb_we <= 0;
|
||||
end
|
||||
endtask // WishboneWR
|
||||
/*
|
||||
always @(posedge clk)
|
||||
if(rx_ll_src_rdy2 & rx_ll_dst_rdy2)
|
||||
begin
|
||||
if(rx_ll_sof2 & ~rx_ll_eof2)
|
||||
$display("RX-PKT-START %d",$time);
|
||||
$display("RX-PKT SOF %d EOF %d ERR%d DAT %x",rx_ll_sof2,rx_ll_eof2,rx_ll_error2,rx_ll_data2);
|
||||
if(rx_ll_eof2 & ~rx_ll_sof2)
|
||||
$display("RX-PKT-END %d",$time);
|
||||
end
|
||||
*/
|
||||
endmodule // simple_gemac_wrapper_tb
|
||||
@@ -0,0 +1,66 @@
|
||||
ff
|
||||
ff
|
||||
ff
|
||||
ff
|
||||
ff
|
||||
ff
|
||||
08
|
||||
00
|
||||
07
|
||||
5c
|
||||
2e
|
||||
e4
|
||||
08
|
||||
06
|
||||
00
|
||||
01
|
||||
08
|
||||
04
|
||||
06
|
||||
02
|
||||
00
|
||||
01
|
||||
08
|
||||
00
|
||||
07
|
||||
5c
|
||||
2e
|
||||
e4
|
||||
03
|
||||
64
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
02
|
||||
64
|
||||
00
|
||||
3a
|
||||
f3
|
||||
5c
|
||||
4f
|
||||
12
|
||||
01
|
||||
10
|
||||
00
|
||||
01
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
20
|
||||
41
|
||||
42
|
||||
41
|
||||
08
|
||||
00
|
||||
AA
|
||||
BB
|
||||
CC
|
||||
DD
|
||||
EE
|
||||
FF
|
||||
Reference in New Issue
Block a user