// mock-up of RX portion of gigabit ethernet MAC
|
// mock-up of RX portion of gigabit ethernet MAC
|
// performs packet reception and creates internal
|
// performs packet reception and creates internal
|
// packet codes, as well as checking CRC on incoming
|
// packet codes, as well as checking CRC on incoming
|
// packets.
|
// packets.
|
|
|
// incoming data is synchronous to "clk", which should
|
// incoming data is synchronous to "clk", which should
|
// be the GMII RX clock. Output data is also synchronous
|
// be the GMII RX clock. Output data is also synchronous
|
// to this clock, so needs to go through a sync FIFO.
|
// to this clock, so needs to go through a sync FIFO.
|
|
|
// If output is not ready while receiving data,
|
// If output is not ready while receiving data,
|
// truncates the packet and makes it an error packet.
|
// truncates the packet and makes it an error packet.
|
|
|
module sd_rx_gigmac
|
module sd_rx_gigmac
|
(
|
(
|
input clk,
|
input clk,
|
input reset,
|
input reset,
|
input gmii_rx_dv,
|
input gmii_rx_dv,
|
input [7:0] gmii_rxd,
|
input [7:0] gmii_rxd,
|
|
|
output rxg_srdy,
|
output rxg_srdy,
|
input rxg_drdy,
|
input rxg_drdy,
|
output [1:0] rxg_code,
|
output [1:0] rxg_code,
|
output [7:0] rxg_data
|
output [7:0] rxg_data
|
);
|
);
|
|
|
reg rxdv1, rxdv2;
|
reg rxdv1, rxdv2;
|
reg [7:0] rxd1, rxd2;
|
reg [7:0] rxd1, rxd2;
|
reg [31:0] calc_crc, nxt_calc_crc;
|
reg [31:0] pkt_crc;
|
reg [31:0] pkt_crc, nxt_pkt_crc;
|
|
reg [3:0] valid_bits, nxt_valid_bits;
|
reg [3:0] valid_bits, nxt_valid_bits;
|
|
reg [31:0] nxt_pkt_crc;
|
|
|
reg [5:0] state, nxt_state;
|
reg [6:0] state, nxt_state;
|
reg ic_srdy;
|
reg ic_srdy;
|
wire ic_drdy;
|
wire ic_drdy;
|
reg [1:0] ic_code;
|
reg [1:0] ic_code;
|
reg [7:0] ic_data;
|
reg [7:0] ic_data;
|
|
wire [31:0] crc;
|
|
|
wire [31:0] crc_comp_a, crc_comp_b;
|
reg crc_valid;
|
|
reg crc_clear;
|
|
|
assign crc_comp_a = { pkt_crc[23:0], rxd2 };
|
mac_crc32 crc_chk
|
assign crc_comp_b = fixup_crc (calc_crc);
|
(
|
localparam CRC32_POLY = 32'h04C11DB7;
|
.clear (crc_clear),
|
|
.data (rxd2),
|
function [31:0] add_crc32;
|
.valid (crc_valid),
|
input [7:0] add_byte;
|
|
input [31:0] prev_crc;
|
/*AUTOINST*/
|
integer b, msb;
|
// Outputs
|
reg [31:0] tmp_crc;
|
.crc (crc[31:0]),
|
begin
|
// Inputs
|
tmp_crc = prev_crc;
|
.clk (clk));
|
for (b = 0; b < 8; b = b + 1)
|
|
begin
|
|
msb = tmp_crc[31];
|
|
tmp_crc = tmp_crc << 1;
|
|
if (msb != add_byte[b])
|
|
begin
|
|
tmp_crc = tmp_crc ^ CRC32_POLY;
|
|
tmp_crc[0] = 1;
|
|
end
|
|
end
|
|
add_crc32 = tmp_crc;
|
|
end
|
|
endfunction // for
|
|
|
|
function [31:0] fixup_crc;
|
|
input [31:0] calc_crc;
|
|
reg [31:0] temp;
|
|
integer b;
|
|
begin
|
|
// Mirror:
|
|
for (b = 0; b < 32; b = b + 1)
|
|
temp[31-b] = calc_crc[b];
|
|
|
|
// Swap and Complement:
|
|
fixup_crc = ~{temp[7:0], temp[15:8], temp[23:16], temp[31:24]};
|
|
end
|
|
endfunction // for
|
|
|
|
|
|
/* -----\/----- EXCLUDED -----\/-----
|
|
// Copied from: http://www.mindspring.com/~tcoonan/gencrc.v
|
|
//
|
|
// Generate a (DOCSIS) CRC32.
|
|
//
|
|
// Uses the GLOBAL variables:
|
|
//
|
|
// Globals referenced:
|
|
// parameter CRC32_POLY = 32'h04C11DB7;
|
|
// reg [ 7:0] crc32_packet[0:255];
|
|
// integer crc32_length;
|
|
//
|
|
// Globals modified:
|
|
// reg [31:0] crc32_result;
|
|
//
|
|
task gencrc32;
|
|
integer byte, bit;
|
|
reg msb;
|
|
reg [7:0] current_byte;
|
|
reg [31:0] temp;
|
|
begin
|
|
crc32_result = 32'hffffffff;
|
|
for (byte = 0; byte < crc32_length; byte = byte + 1) begin
|
|
current_byte = crc32_packet[byte];
|
|
for (bit = 0; bit < 8; bit = bit + 1) begin
|
|
msb = crc32_result[31];
|
|
crc32_result = crc32_result << 1;
|
|
if (msb != current_byte[bit]) begin
|
|
crc32_result = crc32_result ^ CRC32_POLY;
|
|
crc32_result[0] = 1;
|
|
end
|
|
end
|
|
end
|
|
|
|
// Last step is to "mirror" every bit, swap the 4 bytes, and then complement each bit.
|
|
//
|
|
// Mirror:
|
|
for (bit = 0; bit < 32; bit = bit + 1)
|
|
temp[31-bit] = crc32_result[bit];
|
|
|
|
// Swap and Complement:
|
|
crc32_result = ~{temp[7:0], temp[15:8], temp[23:16], temp[31:24]};
|
|
end
|
|
endtask
|
|
-----/\----- EXCLUDED -----/\----- */
|
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
begin
|
begin
|
if (reset)
|
if (reset)
|
begin
|
begin
|
rxd1 <= #1 0;
|
rxd1 <= #1 0;
|
rxdv1 <= #1 0;
|
rxdv1 <= #1 0;
|
rxd2 <= #1 0;
|
rxd2 <= #1 0;
|
rxdv2 <= #1 0;
|
rxdv2 <= #1 0;
|
|
pkt_crc <= #1 0;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
rxd1 <= #1 gmii_rxd;
|
rxd1 <= #1 gmii_rxd;
|
rxdv1 <= #1 gmii_rx_dv;
|
rxdv1 <= #1 gmii_rx_dv;
|
rxd2 <= #1 rxd1;
|
rxd2 <= #1 rxd1;
|
rxdv2 <= #1 rxdv1;
|
rxdv2 <= #1 rxdv1;
|
|
pkt_crc <= #1 nxt_pkt_crc;
|
end
|
end
|
end // always @ (posedge clk)
|
end // always @ (posedge clk)
|
|
|
localparam s_idle = 0, s_preamble = 1, s_sop = 2, s_payload = 3, s_trunc = 4, s_sink = 5;
|
localparam s_idle = 0, s_preamble = 1, s_sop = 2, s_payload = 3, s_trunc = 4, s_sink = 5, s_eop = 6;
|
localparam ns_idle = 1, ns_preamble = 2, ns_sop = 4, ns_payload = 8, ns_trunc = 16, ns_sink = 32;
|
localparam ns_idle = 1, ns_preamble = 2, ns_sop = 4, ns_payload = 8, ns_trunc = 16, ns_sink = 32;
|
|
|
always @*
|
always @*
|
begin
|
begin
|
nxt_calc_crc = calc_crc;
|
|
ic_srdy = 0;
|
ic_srdy = 0;
|
ic_code = `PCC_DATA;
|
ic_code = `PCC_DATA;
|
ic_data = 0;
|
ic_data = 0;
|
nxt_valid_bits = valid_bits;
|
nxt_valid_bits = valid_bits;
|
|
nxt_pkt_crc = pkt_crc;
|
|
crc_valid = 0;
|
|
crc_clear = 0;
|
|
|
case (1'b1)
|
case (1'b1)
|
state[s_idle] :
|
state[s_idle] :
|
begin
|
begin
|
nxt_calc_crc = {32{1'b1}};
|
crc_clear = 1;
|
nxt_pkt_crc = 0;
|
nxt_pkt_crc = 0;
|
nxt_valid_bits = 0;
|
nxt_valid_bits = 0;
|
if (rxdv2 & (rxd2 == `GMII_SFD))
|
if (rxdv2 & (rxd2 == `GMII_SFD))
|
begin
|
begin
|
nxt_state = ns_sop;
|
nxt_state = ns_sop;
|
end
|
end
|
else if (rxdv2)
|
else if (rxdv2)
|
begin
|
begin
|
nxt_state = ns_preamble;
|
nxt_state = ns_preamble;
|
end
|
end
|
end // case: state[s_idle]
|
end // case: state[s_idle]
|
|
|
state[s_preamble]:
|
state[s_preamble]:
|
begin
|
begin
|
if (!rxdv2)
|
if (!rxdv2)
|
nxt_state = ns_idle;
|
nxt_state = ns_idle;
|
else if (rxd2 == `GMII_SFD)
|
else if (rxd2 == `GMII_SFD)
|
nxt_state = ns_sop;
|
nxt_state = ns_sop;
|
end
|
end
|
|
|
state[s_sop] :
|
state[s_sop] :
|
begin
|
begin
|
if (!rxdv2)
|
if (!rxdv2)
|
begin
|
begin
|
nxt_state = ns_idle;
|
nxt_state = ns_idle;
|
end
|
end
|
else if (!ic_drdy)
|
else if (!ic_drdy)
|
nxt_state = ns_sink;
|
nxt_state = ns_sink;
|
else
|
else
|
begin
|
begin
|
ic_srdy = 1;
|
ic_srdy = 1;
|
ic_code = `PCC_SOP;
|
ic_code = `PCC_SOP;
|
ic_data = rxd2;
|
ic_data = rxd2;
|
|
crc_valid = 1;
|
|
nxt_pkt_crc = { rxd2, pkt_crc[31:8] };
|
nxt_state = ns_payload;
|
nxt_state = ns_payload;
|
nxt_pkt_crc = { 24'h0, gmii_rxd };
|
|
nxt_valid_bits = 4'b0001;
|
|
//nxt_calc_crc = add_crc32 (gmii_rxd, calc_crc);
|
|
end
|
end
|
end // case: state[ns_payload]
|
end // case: state[ns_payload]
|
|
|
state[s_payload] :
|
state[s_payload] :
|
begin
|
begin
|
if (!ic_drdy)
|
if (!ic_drdy)
|
nxt_state = ns_trunc;
|
nxt_state = ns_trunc;
|
else if (!rxdv1)
|
else if (!rxdv1)
|
begin
|
begin
|
nxt_state = ns_idle;
|
//nxt_state = ns_idle;
|
ic_srdy = 1;
|
ic_srdy = 0;
|
ic_data = rxd2;
|
ic_data = rxd2;
|
//if ( { pkt_crc[23:0], rxd2 } == add_crc32 (rxd2, calc_crc))
|
crc_valid = 1;
|
`ifdef RX_CHECK_CRC
|
nxt_pkt_crc = { rxd2, pkt_crc[31:8] };
|
if ({ pkt_crc[23:0], rxd2 } == fixup_crc (calc_crc))
|
nxt_state = 1 << s_eop;
|
ic_code = `PCC_EOP;
|
|
else
|
|
ic_code = `PCC_BADEOP;
|
|
`else
|
|
ic_code = `PCC_EOP;
|
|
`endif
|
|
end
|
end
|
else
|
else
|
begin
|
begin
|
ic_srdy = 1;
|
ic_srdy = 1;
|
ic_code = `PCC_DATA;
|
ic_code = `PCC_DATA;
|
ic_data = rxd2;
|
ic_data = rxd2;
|
nxt_pkt_crc = { pkt_crc[23:0], rxd2 };
|
crc_valid = 1;
|
nxt_valid_bits = { valid_bits[2:0], 1'b1 };
|
nxt_pkt_crc = { rxd2, pkt_crc[31:8] };
|
if (valid_bits[2])
|
|
nxt_calc_crc = add_crc32 (pkt_crc[23:16], calc_crc);
|
|
end // else: !if(!rxdv1)
|
end // else: !if(!rxdv1)
|
end // case: state[ns_payload]
|
end // case: state[ns_payload]
|
|
|
|
|
|
state[s_eop] :
|
|
begin
|
|
ic_srdy =1;
|
|
ic_data = pkt_crc[31:24];
|
|
if (pkt_crc == crc)
|
|
begin
|
|
ic_code = `PCC_EOP;
|
|
end
|
|
else
|
|
ic_code = `PCC_BADEOP;
|
|
|
|
if (ic_drdy)
|
|
nxt_state = 1 << s_idle;
|
|
end
|
|
|
state[s_trunc] :
|
state[s_trunc] :
|
begin
|
begin
|
ic_srdy = 1;
|
ic_srdy = 1;
|
ic_code = `PCC_BADEOP;
|
ic_code = `PCC_BADEOP;
|
ic_data = 0;
|
ic_data = 0;
|
if (ic_drdy)
|
if (ic_drdy)
|
nxt_state = ns_sink;
|
nxt_state = ns_sink;
|
end
|
end
|
|
|
state[s_sink] :
|
state[s_sink] :
|
begin
|
begin
|
if (!rxdv2)
|
if (!rxdv2)
|
nxt_state = ns_idle;
|
nxt_state = ns_idle;
|
end
|
end
|
|
|
default : nxt_state = ns_idle;
|
default : nxt_state = ns_idle;
|
endcase // case (1'b1)
|
endcase // case (1'b1)
|
end // always @ *
|
end // always @ *
|
|
|
always @(posedge clk)
|
always @(posedge clk)
|
begin
|
begin
|
if (reset)
|
if (reset)
|
begin
|
begin
|
state <= #1 1;
|
state <= #1 1;
|
/*AUTORESET*/
|
/*AUTORESET*/
|
// Beginning of autoreset for uninitialized flops
|
// Beginning of autoreset for uninitialized flops
|
calc_crc <= 32'h0;
|
|
pkt_crc <= 32'h0;
|
pkt_crc <= 32'h0;
|
valid_bits <= 4'h0;
|
valid_bits <= 4'h0;
|
// End of automatics
|
// End of automatics
|
end
|
end
|
else
|
else
|
begin
|
begin
|
calc_crc <= #1 nxt_calc_crc;
|
|
pkt_crc <= #1 nxt_pkt_crc;
|
pkt_crc <= #1 nxt_pkt_crc;
|
state <= #1 nxt_state;
|
state <= #1 nxt_state;
|
valid_bits <= #1 nxt_valid_bits;
|
valid_bits <= #1 nxt_valid_bits;
|
end // else: !if(reset)
|
end // else: !if(reset)
|
end // always @ (posedge clk)
|
end // always @ (posedge clk)
|
|
|
sd_output #(8+2) out_hold
|
sd_output #(8+2) out_hold
|
(.clk (clk), .reset (reset),
|
(.clk (clk), .reset (reset),
|
.ic_srdy (ic_srdy),
|
.ic_srdy (ic_srdy),
|
.ic_drdy (ic_drdy),
|
.ic_drdy (ic_drdy),
|
.ic_data ({ic_code,ic_data}),
|
.ic_data ({ic_code,ic_data}),
|
.p_srdy (rxg_srdy),
|
.p_srdy (rxg_srdy),
|
.p_drdy (rxg_drdy),
|
.p_drdy (rxg_drdy),
|
.p_data ({rxg_code, rxg_data}));
|
.p_data ({rxg_code, rxg_data}));
|
|
|
endmodule // sd_rx_gigmac
|
endmodule // sd_rx_gigmac
|
|
|