OpenCores
URL https://opencores.org/ocsvn/openarty/openarty/trunk

Subversion Repositories openarty

[/] [openarty/] [trunk/] [rtl/] [enetpackets.v] - Rev 50

Compare with Previous | Blame | View Log

////////////////////////////////////////////////////////////////////////////////
//
// Filename: 	enetpackets.v
//
// Project:	OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose:	To communicate between the Ethernet PHY, and thus to coordinate
//		(and direct/arrange for) the transmission, and receiption, of 
//	packets via the Ethernet interface.
//
//
//	Using this interface requires four registers to be properly configured.
//	These are the receive and transmit control registers, as well as the
//	hardware MAC register(s).
//
//
//	To use the interface, after the system has been alive for a full
//	second, drop the reset line.  Do this by writing to the transmit
//	register a value with zero length, zero command, and the RESET bit as
//	zero.
//
//	This interface is big endian.  Therefore, the most significant byte
//	in each word will be transmitted first.  If the interface references
//	a number of octets less than a multiple of four, the least significant
//	octets in the last word will not be transmitted/were not received.
//
//	To transmit,
//		1. set the source MAC address in the two mac registers.  These
//			are persistent across packets, so once set (whether for
//			transmit or receive) they need not be set again.
//		2. Fill the packet buffer with your packet.  In general, the
//			first 32-bit word must contain the hardware MAC address
//			of your destination, spilling into the 16-bits of the
//			next word.  The bottom 16-bits of that second word
//			must also contain the EtherType (0x0800 for IP,
//			0x0806 for ARP, etc.)  The third word will begin your
//			user data.
//		3. Write a 0x4000 plus the number of bytes in your buffer to
//			the transmit command register.  If your packet is less
//			than 64 bytes, it will automatically be paddedd to 64
//			bytes before being sent.
//		4. Once complete, the controller will raise an interrupt
//			line to note that the interface is idle.
//	OPTIONS:
//		You can turn off the internal insertion of the hardware source
//		MAC by turning the respective bit on in the transmit command
//		register.  If you do this, half of the second word and all the
//		third word must contain the hardware MAC.  The third word must
//		contain the EtherType, both in the top and bottom sixteen bits.
//		The Fourth word will begin user data.
//
//		You can also turn off the automatic insertion of the FCS, or
//		ethernet CRC.  Doing this means that you will need to both 
//		guarantee for yourself that the packet has a minimum of 64
//		bytes in length, and that the last four bytes contain the
//		CRC.
//
//	To Receive: 
//		The receiver is always on.  Receiving is really just a matter
//		of pulling the received packet from the interface, and resetting
//		the interface for the next packet.
//
//		If the VALID bit is set, the receive interface has a valid
//		packet within it.  Write a zero to this bit to reset the
//		interface to accept the next packet.
//
//		If a packet with a CRC error is received, the CRC error bit
//		will be set.  Likewise if a packet has been missed, usually 
//		because the buffer was full when it started, the miss bit
//		will be set.  Finally, if an error occurrs while receiving
//		a packet, the error bit will be set.  These bits may be cleared
//		by writing a one to each of them--something that may be done
//		when clearing the interface for the next packet.
//	OPTIONS:
//		The same options that apply to the transmitter apply to the
//		receiver:
//
//		HWMAC.  If the hardware MAC is turned on, the receiver will
//		only accept packets to either 1) our network address, or 2)
//		a broadcast address.  Further, the first two words will be
//		adjusted to contain the source MAC and the EtherType, so that
//		the user information begins on the third word.  If this feature
//		is turned off, all packets will be received, and the first
//		three words will contain the destination and then source
//		MAC.  The fourth word will contain the EtherType in the lowest,
//		16 bits, meaning user data will begin on the fifth word.
//
//		HWCRC.  If the HWCRC is turned on, the receiver will only
//		detect packets that pass their CRC check.  Further, the packet
//		length (always in octets) will not include the CRC.  However,
//		the CRC will still be left/written to packet memory either way.
//
// Registers:
//	0	Receiver control
//		13'h0	|CRCerr|MISS|ERR|BUSY|VALID |14-bit length (in octets)|
//
//	1	Transmitter control
//		14'h0	|NET_RST|SW-MAC-CHK|SW-CRCn|BUSY/CMD | 14 bit length(in octets)|
//
//	2	// MAC address (high) ??
//	3	// MAC address (low)  ??
//	4	Number of receive packets missed (buffer was full)
//	5	Number of receive packets ending in error
//	6	Number of receive packets with invalid CRCs
//	7	(Number of transmit collisions ??)
//
// Creator:	Dan Gisselquist, Ph.D.
//		Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of  the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program.  (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.)  If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License:	GPL, v3, as defined and found on www.gnu.org,
//		http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
// `define	RX_SYNCHRONOUS_WITH_WB_CLK
`ifdef	RX_SYNCHRONOUS_WITH_WB_CLK
`define	RXCLK	i_wb_clk
`else
`define	RXCLK	i_net_rx_clk
`endif
// `define	TX_SYNCHRONOUS_WITH_WB_CLK
`ifdef	TX_SYNCHRONOUS_WITH_WB_CLK
`define	TXCLK	i_wb_clk
`else
`define	TXCLK	i_net_tx_clk
`endif
module	enetpackets(i_wb_clk, i_reset,
	i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel,
		o_wb_ack, o_wb_stall, o_wb_data,
	//
	o_net_reset_n, 
	i_net_rx_clk, i_net_col, i_net_crs, i_net_dv, i_net_rxd, i_net_rxerr,
	i_net_tx_clk, o_net_tx_en, o_net_txd,
	//
	o_rx_int, o_tx_int,
	//
	o_debug
	);
	parameter	MEMORY_ADDRESS_WIDTH = 12; // Log_2 octet width:11..14
	localparam	MAW =((MEMORY_ADDRESS_WIDTH>14)? 14: // width of words
			((MEMORY_ADDRESS_WIDTH<11)? 11:MEMORY_ADDRESS_WIDTH))-2;
	input			i_wb_clk, i_reset;
	//
	input			i_wb_cyc, i_wb_stb, i_wb_we;
	input	[(MAW+1):0]	i_wb_addr; // 1-bit for ctrl/data, 1 for tx/rx
	input	[31:0]		i_wb_data;
	input	[3:0]		i_wb_sel;
	//
	output	reg		o_wb_ack;
	output	wire		o_wb_stall;
	output	reg	[31:0]	o_wb_data;
	//
	output	reg		o_net_reset_n;
	//
	input			i_net_rx_clk, i_net_col, i_net_crs, i_net_dv;
	input		[3:0]	i_net_rxd;
	input			i_net_rxerr;
	//
	input			i_net_tx_clk;
	output	wire		o_net_tx_en;
	output	wire	[3:0]	o_net_txd;
	//
	output	wire		o_rx_int, o_tx_int;
	//
	output	wire	[31:0]	o_debug;
 
	reg	wr_ctrl;
	reg	[2:0]	wr_addr;
	reg	[31:0]	wr_data;
	reg	[3:0]	wr_sel;
	always @(posedge i_wb_clk)
	begin
		wr_ctrl<=((i_wb_stb)&&(i_wb_we)&&(i_wb_addr[(MAW+1):MAW] == 2'b00));
		wr_addr <= i_wb_addr[2:0];
		wr_data <= i_wb_data;
		wr_sel  <= i_wb_sel;
	end
 
	reg	[31:0]	txmem	[0:((1<<MAW)-1)];
	reg	[31:0]	rxmem	[0:((1<<MAW)-1)];
 
	reg	[(MAW+1):0]	tx_len;
 
`ifdef	RX_SYNCHRONOUS_WITH_WB_CLK
	wire	rx_broadcast;
	wire	[(MAW+1):0]	rx_len;
`else
	(* ASYNC_REG = "TRUE" *) reg	rx_broadcast;
	(* ASYNC_REG = "TRUE" *) reg	[(MAW+1):0]	rx_len;
`endif
 
	reg	tx_cmd, tx_cancel;
`ifdef	TX_SYNCHRONOUS_WITH_WB_CLK
	wire	tx_busy, tx_complete;
`else
	reg	tx_busy, tx_complete;
`endif
	reg	config_hw_crc, config_hw_mac, config_hw_ip_check;
	reg	rx_crcerr, rx_err, rx_miss, rx_clear;
`ifdef	RX_SYNCHRONOUS_WITH_WB_CLK
	wire	rx_valid, rx_busy;
`else
	reg	rx_valid, rx_busy;
`endif
	reg	rx_wb_valid, pre_ack, pre_cmd, tx_nzero_cmd;
	reg	[4:0]	caseaddr;
	reg	[31:0]	rx_wb_data, tx_wb_data;
	reg		rx_err_stb, rx_miss_stb, rx_crc_stb;
 
	reg	[47:0]	hw_mac;
	reg		p_rx_clear;
	reg	[7:0]	clear_pipe;
 
	initial	config_hw_crc = 0;
	initial	config_hw_mac = 0;
	initial	config_hw_ip_check = 0;
	initial	o_net_reset_n = 1'b0;
	initial	tx_cmd    = 1'b0;
	initial	tx_cancel = 1'b0;
	initial	rx_crcerr = 1'b0;
	initial	rx_err    = 1'b0;
	initial	rx_miss   = 1'b0;
	initial	rx_clear  = 1'b0;
	always @(posedge i_wb_clk)
	begin
		// if (i_wb_addr[(MAW+1):MAW] == 2'b10)
			// Writes to rx memory not allowed here
		if ((i_wb_stb)&&(i_wb_we)&&(i_wb_addr[(MAW+1):MAW] == 2'b11)
				&&(i_wb_sel[3]))
			txmem[i_wb_addr[(MAW-1):0]][31:24] <= i_wb_data[31:24];
		if ((i_wb_stb)&&(i_wb_we)&&(i_wb_addr[(MAW+1):MAW] == 2'b11)
				&&(i_wb_sel[2]))
			txmem[i_wb_addr[(MAW-1):0]][23:16] <= i_wb_data[23:16];
		if ((i_wb_stb)&&(i_wb_we)&&(i_wb_addr[(MAW+1):MAW] == 2'b11)
				&&(i_wb_sel[1]))
			txmem[i_wb_addr[(MAW-1):0]][15:8] <= i_wb_data[15:8];
		if ((i_wb_stb)&&(i_wb_we)&&(i_wb_addr[(MAW+1):MAW] == 2'b11)
				&&(i_wb_sel[0]))
			txmem[i_wb_addr[(MAW-1):0]][7:0] <= i_wb_data[7:0];
 
		// Set the err bits on these conditions (filled out below)
		if (rx_err_stb)
			rx_err <= 1'b1;
		if (rx_miss_stb)
			rx_miss <= 1'b1;
		if (rx_crc_stb)
			rx_crcerr <= 1'b1;
 
		if ((wr_ctrl)&&(wr_addr==3'b000))
		begin // RX command register
			rx_crcerr<= (!wr_data[18])&&(!rx_crcerr);
			rx_err   <= (!wr_data[17])&&(!rx_err);
			rx_miss  <= (!wr_data[16])&&(!rx_miss);
			// busy bit cannot be written to
			rx_clear <= rx_clear || (wr_data[14]);
			// Length bits are cleared when invalid
		end else if (!rx_valid)
			rx_clear <= 1'b0;
 
		clear_pipe <= { clear_pipe[6:0], rx_clear };
		p_rx_clear <= |clear_pipe;
 
		if ((tx_busy)||(tx_cancel))
			tx_cmd <= 1'b0;
		if (!tx_busy)
			tx_cancel <= 1'b0;
		pre_cmd <= 1'b0;
		if ((wr_ctrl)&&(wr_addr==3'b001))
		begin // TX command register
 
			// Reset bit must be held down to be valid
			config_hw_ip_check <= (!wr_data[18]);
			o_net_reset_n <= (!wr_data[17]);
			config_hw_mac <= (!wr_data[16]);
			config_hw_crc <= (!wr_data[15]);
			pre_cmd <= (wr_data[14]);
			tx_cancel <= (tx_busy)&&(!wr_data[14]);
//		14'h0	| SW-CRCn |NET-RST|BUSY/CMD | 14 bit length(in octets)|
			tx_len <= wr_data[(MAW+1):0];
		end 
		tx_nzero_cmd <= ((pre_cmd)&&(tx_len != 0));
		if (tx_nzero_cmd)
			tx_cmd <= 1'b1;
		if (!o_net_reset_n)
			tx_cancel <= 1'b1;
		if (!o_net_reset_n)
			tx_cmd <= 1'b0;
 
		if ((wr_ctrl)&&(wr_addr==3'b010))
			hw_mac[47:32] <= wr_data[15:0];
		if ((wr_ctrl)&&(wr_addr==3'b011))
			hw_mac[31:0] <= wr_data[31:0];
	end
 
	wire	[31:0]	w_tx_ctrl;
	wire	[31:0]	w_rx_ctrl;
	wire	[3:0]	w_maw;
 
	assign	w_maw = MAW+2; // Number of bits in the packet length field
	assign	w_rx_ctrl = { 4'h0, w_maw, {(24-20){1'b0}},
			(rx_valid)&&(rx_broadcast)&&(!rx_clear),
			rx_crcerr, rx_err,
			rx_miss, rx_busy, (rx_valid)&&(!rx_clear),
			{(14-MAW-2){1'b0}}, rx_len };
 
	assign	w_tx_ctrl = { 4'h0, w_maw, {(24-19){1'b0}}, 
			!config_hw_ip_check,
			!o_net_reset_n,!config_hw_mac,
			!config_hw_crc, tx_busy,
				{(14-MAW-2){1'b0}}, tx_len };
 
	reg	[31:0]	counter_rx_miss, counter_rx_err, counter_rx_crc;
	initial	counter_rx_miss = 32'h00;
	initial	counter_rx_err  = 32'h00;
	initial	counter_rx_crc  = 32'h00;
 
	// Reads from the bus ... always done, regardless of i_wb_we
	always @(posedge i_wb_clk)
	begin
		rx_wb_data  <= rxmem[i_wb_addr[(MAW-1):0]];
		rx_wb_valid <= (i_wb_addr[(MAW-1):0] <= { rx_len[(MAW+1):2] });
		tx_wb_data  <= txmem[i_wb_addr[(MAW-1):0]];
		pre_ack <= i_wb_stb;
		caseaddr <= {i_wb_addr[(MAW+1):MAW], i_wb_addr[2:0] };
 
		casez(caseaddr)
		5'h00: o_wb_data <= w_rx_ctrl;
		5'h01: o_wb_data <= w_tx_ctrl;
		5'h02: o_wb_data <= {16'h00, hw_mac[47:32] };
		5'h03: o_wb_data <= hw_mac[31:0];
		5'h04: o_wb_data <= counter_rx_miss;
		5'h05: o_wb_data <= counter_rx_err;
		5'h06: o_wb_data <= counter_rx_crc;
		5'h07: o_wb_data <= 32'h00;
		5'b10???: o_wb_data <= (rx_wb_valid)?rx_wb_data:32'h00;
		5'b11???: o_wb_data <= tx_wb_data;
		default: o_wb_data <= 32'h00;
		endcase
		o_wb_ack <= pre_ack;
	end
 
	/////////////////////////////////////
	//
	//
	//
	// Transmitter code
	//
	//
	//
	/////////////////////////////////////
`ifdef	TX_SYNCHRONOUS_WITH_WB_CLK
	reg	[(MAW+1):0]	n_tx_len;
	wire	n_tx_cmd, n_tx_cancel;
	assign	n_tx_cmd = tx_cmd;
	assign	n_tx_cancel = tx_cancel;
`else
	(* ASYNC_REG = "TRUE" *) reg	[(MAW+1):0]	n_tx_len;
	(* ASYNC_REG = "TRUE" *) reg r_tx_cmd, r_tx_cancel;
	reg	n_tx_cmd, n_tx_cancel;
	always @(posedge `TXCLK)
	begin
		r_tx_cmd    <= tx_cmd;
		r_tx_cancel <= tx_cancel;
 
		n_tx_cmd    <= r_tx_cmd;
		n_tx_cancel <= r_tx_cancel;
	end
`endif
 
`ifdef	TX_SYNCHRONOUS_WITH_WB_CLK
	reg	last_tx_clk, tx_clk_stb;
	(* ASYNC_REG = "TRUE" *) reg	r_tx_clk;
	always @(posedge i_wb_clk)
		r_tx_clk <= i_net_tx_clk;
	always @(posedge i_wb_clk)
		last_tx_clk <= r_tx_clk;
	always @(posedge i_wb_clk)
		tx_clk_stb <= (r_tx_clk)&&(!last_tx_clk);
`else
	wire	tx_clk_stb, last_tx_clk;
 
	assign	tx_clk_stb = 1'b1;
	assign	last_tx_clk= 1'b0;
`endif
 
	wire	[(MAW+2):0]	rd_tx_addr;
	assign	rd_tx_addr = (n_tx_addr+8);
 
	reg	[(MAW+2):0]	n_tx_addr;
	reg	[31:0]		n_tx_data, n_next_tx_data;
	reg			n_tx_complete;
`ifdef	TX_SYNCHRONOUSH_WITH_WB
	reg		n_tx_busy, n_tx_config_hw_mac, n_tx_config_hw_crc;
`else
	(* ASYNC_REG = "TRUE" *) reg	n_tx_busy,
					n_tx_config_hw_mac, n_tx_config_hw_crc;
`endif
	(* ASYNC_REG = "TRUE" *) reg r_tx_crs;
	reg	n_tx_crs;
	always @(posedge `TXCLK)
	begin
		r_tx_crs <= i_net_crs;
		n_tx_crs <= r_tx_crs;
	end
 
	wire	[31:0]	n_remap_tx_data;
	assign	n_remap_tx_data[31:28] = n_next_tx_data[27:24];
	assign	n_remap_tx_data[27:24] = n_next_tx_data[31:28];
	assign	n_remap_tx_data[23:20] = n_next_tx_data[19:16];
	assign	n_remap_tx_data[19:16] = n_next_tx_data[23:20];
	assign	n_remap_tx_data[15:12] = n_next_tx_data[11: 8];
	assign	n_remap_tx_data[11: 8] = n_next_tx_data[15:12];
	assign	n_remap_tx_data[ 7: 4] = n_next_tx_data[ 3: 0];
	assign	n_remap_tx_data[ 3: 0] = n_next_tx_data[ 7: 4];
 
	reg		r_txd_en;
	reg	[3:0]	r_txd;
	initial	r_txd_en = 1'b0;
 
	initial	n_tx_busy  = 1'b0;
	initial	n_tx_complete  = 1'b0;
	always @(posedge `TXCLK)
	begin
		if (tx_clk_stb)
		begin
			// While this operation doesn't strictly need to 
			// operate *only* if tx_clk_stb is true, by doing so
			// our code stays compatible with both synchronous
			// to wishbone and synchronous to tx clk options.
			n_next_tx_data  <= txmem[(!n_tx_busy)?0:rd_tx_addr[(MAW+2):3]];
		end
 
 
		if (n_tx_cancel)
			n_tx_busy <= 1'b0;
		else if (!n_tx_busy)
			n_tx_busy <= (n_tx_cmd)&&(!i_net_crs);
		else if (n_tx_addr >= { n_tx_len,1'b0 })
			n_tx_busy     <= 1'b0;
 
		if (!n_tx_busy)
		begin
			n_tx_addr  <= {{(MAW+2){1'b0}},1'b1};
			n_tx_data <= { n_remap_tx_data[27:0], 4'h0 };
			if (n_tx_complete)
				n_tx_complete <= (!n_tx_cmd);
			r_txd_en <= (!n_tx_complete)&&(n_tx_cmd)&&(!i_net_crs);
			r_txd  <= n_remap_tx_data[31:28];
			n_tx_config_hw_mac <= config_hw_mac;
			n_tx_config_hw_crc <= config_hw_crc;
			n_tx_len <= tx_len;
		end else if (!r_txd_en)
			r_txd_en <= (!n_tx_crs);
		else if (tx_clk_stb) begin
			n_tx_addr <= n_tx_addr + 1'b1;
			r_txd <= n_tx_data[31:28];
			if (n_tx_addr[2:0] == 3'h7)
				n_tx_data <= n_remap_tx_data;
			else
				n_tx_data <= { n_tx_data[27:0], 4'h0 };
			if (n_tx_addr >= { n_tx_len,1'b0 })
				n_tx_complete <= 1'b1;
			r_txd_en <= (n_tx_addr < { n_tx_len, 1'b0 });
		end
	end
 
	wire	n_tx_config_hw_preamble;
	assign	n_tx_config_hw_preamble = 1'b1;
 
	wire		w_macen, w_paden, w_txcrcen;
	wire	[3:0]	w_macd,  w_padd,  w_txcrcd;
 
`ifndef	TX_BYPASS_HW_MAC
	addemac	txmaci(`TXCLK, tx_clk_stb, n_tx_config_hw_mac, n_tx_cancel,
				hw_mac, r_txd_en, r_txd, w_macen, w_macd);
`else
	assign	w_macen = r_txd_en;
	assign	w_macd  = r_txd;
`endif
 
`ifndef	TX_BYPASS_PADDING
	addepad	txpadi(`TXCLK, tx_clk_stb, 1'b1, n_tx_cancel,
				w_macen, w_macd, w_paden, w_padd);
`else
	assign	w_paden = w_macen;
	assign	w_padd  = w_macd;
`endif
 
`ifndef	TX_BYPASS_HW_CRC
	addecrc	txcrci(`TXCLK, tx_clk_stb, n_tx_config_hw_crc, n_tx_cancel,
				w_paden, w_padd, w_txcrcen, w_txcrcd);
`else
	assign	w_txcrcen = w_macen;
	assign	w_txcrcd  = w_macd;
`endif
 
	addepreamble txprei(`TXCLK, tx_clk_stb, n_tx_config_hw_preamble, n_tx_cancel,
				w_txcrcen, w_txcrcd, o_net_tx_en, o_net_txd);
 
`ifdef	TX_SYNCRONOUS_WITH_WB_CLK
	assign	tx_busy = n_tx_busy;
	assign	tx_complete = n_tx_complete;
`else
	(* ASYNC_REG = "TRUE" *) reg	r_tx_busy, r_tx_complete;
	always @(posedge i_wb_clk)
	begin
		r_tx_busy <= (n_tx_busy || o_net_tx_en || w_txcrcen || w_macen || w_paden);
		tx_busy <= r_tx_busy;
 
		r_tx_complete <= n_tx_complete;
		tx_busy <= r_tx_busy;
	end
`endif
 
 
 
 
 
	/////////////////////////////////////
	//
	//
	//
	// Receiver code
	//
	//
	//
	/////////////////////////////////////
`ifdef	RX_SYNCHRONOUS_WITH_WB_CLK
	reg	last_rx_clk, rx_clk_stb;
	(* ASYNC_REG="TRUE" *) reg r_rx_clk;
	always @(posedge i_wb_clk)
		r_rx_clk <= i_net_rx_clk;
	always @(posedge i_wb_clk)
		last_rx_clk <= r_rx_clk;
	always @(posedge i_wb_clk)
		rx_clk_stb <= (r_rx_clk)&&(!last_rx_clk);
 
`else
	wire	rx_clk_stb, last_rx_clk;
	assign	rx_clk_stb = 1'b1;
	assign	last_rx_clk = 1'b0;
`endif
 
 
`ifdef	RX_SYNCHRONOUS_WITH_WB_CLK
	wire	n_rx_clear;
	reg	n_rx_config_hw_mac, n_rx_config_hw_crc, n_rx_config_ip_check;
	assign	n_rx_clear = rx_clear;
`else
	(* ASYNC_REG = "TRUE" *) reg n_rx_config_hw_mac, n_rx_config_hw_crc,
			n_rx_config_ip_check;
	(* ASYNC_REG = "TRUE" *) reg r_rx_clear;
	reg	n_rx_clear;
	always @(posedge `RXCLK)
	begin
		r_rx_clear <= (p_rx_clear)||(!o_net_reset_n);
		n_rx_clear <= r_rx_clear;
	end
`endif
 
 
	reg		n_rx_net_err;
	wire		w_npre,  w_rxmin,  w_rxcrc,  w_rxmac;
	wire	[3:0]	w_npred, w_rxmind, w_rxcrcd, w_rxmacd;
	wire		w_minerr, w_rxcrcerr, w_macerr, w_broadcast, w_iperr;
`ifndef	RX_BYPASS_HW_PREAMBLE
	rxepreambl rxprei(`RXCLK, rx_clk_stb, 1'b1, (n_rx_net_err),
			i_net_dv, i_net_rxd, w_npre, w_npred);
`else
	assign	w_npre  = i_net_dv; 
	assign	w_npred = i_net_rxerr; 
`endif
 
`ifdef	RX_BYPASS_HW_MINLENGTH
	// Insist on a minimum of 64-byte packets
	rxemin	rxmini(`RXCLK, rx_clk_stb, 1'b1, (n_rx_net_err),
			w_npre, w_npred, w_minerr);
`else
	assign	w_minerr= 1'b0;
`endif
	assign	w_rxmin = w_npre;
	assign	w_rxmind= w_npred;
 
`ifndef	RX_BYPASS_HW_CRC
	rxecrc	rxcrci(`RXCLK, rx_clk_stb, n_rx_config_hw_crc, (n_rx_net_err),
			w_rxmin, w_rxmind, w_rxcrc, w_rxcrcd, w_rxcrcerr);
`else
	assign	w_rxcrc   = w_rxmin;
	assign	w_rxcrcd  = w_rxmind;
	assign	w_rxcrcerr= 1'b0;
`endif
 
`ifndef	RX_BYPASS_HW_RMMAC
	rxehwmac rxmaci(`RXCLK, rx_clk_stb, n_rx_config_hw_mac, (n_rx_net_err), hw_mac,
			w_rxcrc, w_rxcrcd,
			w_rxmac, w_rxmacd,
			w_macerr, w_broadcast);
`else
	assign	w_rxmac  = w_rxcrc;
	assign	w_rxmacd = w_rxcrcd;
`endif
 
`define	RX_HW_IPCHECK
`ifdef	RX_HW_IPCHECK
	// Check: if this packet is an IP packet, is the IP header checksum
	// valid?
	rxeipchk rxipci(`RXCLK, rx_clk_stb, n_rx_config_ip_check,(n_rx_net_err),
			w_rxcrc, w_rxcrcd, w_iperr);
`else
	assign	w_iperr = 1'b0;
`endif
 
	wire			w_rxwr;
	wire	[(MAW-1):0]	w_rxaddr;
	wire	[31:0]		w_rxdata;
	wire	[(MAW+1):0]	w_rxlen;
 
	rxewrite #(MAW) rxememi(`RXCLK, 1'b1, (n_rx_net_err), w_rxmac, w_rxmacd,
			w_rxwr, w_rxaddr, w_rxdata, w_rxlen);
 
	reg	last_rxwr, n_rx_valid, n_rxmiss, n_eop, n_rx_busy, n_rx_crcerr,
		n_rx_err, n_rx_broadcast, n_rx_miss;
	reg	[(MAW+1):0]	n_rx_len;
 
	initial	n_rx_valid = 1'b0;
	initial	n_rx_clear = 1'b1;
	initial	n_rx_miss  = 1'b0;
	always @(posedge `RXCLK)
	begin
		if ((w_rxwr)&&(!n_rx_valid))
			rxmem[w_rxaddr] <= w_rxdata;
 
		// n_rx_net_err goes true as soon as an error is detected,
		// and stays true as long as valid data is coming in
		n_rx_net_err <= (i_net_dv)&&((i_net_rxerr)||(i_net_col)
				||(w_minerr)||(w_macerr)||(w_rxcrcerr)
				||(w_iperr)
				||(n_rx_net_err)
				||((w_rxwr)&&(n_rx_valid)));
 
		last_rxwr <= w_rxwr;
		n_eop <= (!w_rxwr)&&(last_rxwr)&&(!n_rx_net_err);
 
		n_rx_busy <= (!n_rx_net_err)&&((i_net_dv)||(w_npre)||(w_rxmin)
			||(w_rxcrc)||(w_rxmac)||(w_rxwr));
 
		// Oops ... we missed a packet
		n_rx_miss <= (n_rx_valid)&&(w_rxwr)||
			((n_rx_miss)&&(!n_rx_clear));
 
		n_rx_crcerr <= ((w_rxcrcerr)&&(!n_rx_net_err))
			||((n_rx_crcerr)&&(!n_rx_clear));
 
		n_rx_err <= ((n_rx_err)&&(!n_rx_clear))
			||((i_net_rxerr)||(i_net_col)||(w_minerr));
 
		n_rx_broadcast <= (w_broadcast)||((n_rx_broadcast)&&(!n_rx_clear));
 
		if (n_rx_clear)
		begin
			n_rx_valid <= 1'b0;
			n_rx_len <= 0;
		end else if (n_eop)
		begin
			n_rx_valid <= 1'b1;
			n_rx_len   <= w_rxlen - ((n_rx_config_hw_crc)?{{(MAW-1){1'b0}},3'h4}:0);
		end
		// else n_rx_valid = n_rx_valid;
 
		if ((!i_net_dv)||(n_rx_clear))
		begin
			n_rx_config_hw_mac   <= config_hw_mac;
			n_rx_config_hw_crc   <= config_hw_crc;
			n_rx_config_ip_check <= config_hw_ip_check;
		end
	end
 
`ifdef	RX_SYNCHRONOUS_WITH_WB_CLK
	assign	rx_busy  = n_rx_busy;
	assign	rx_valid = n_rx_valid;
	assign	rx_len   = n_rx_len;
	assign	rx_broadcast = n_rx_broadcast;
`else
	reg	r_rx_busy, r_rx_valid;
	always @(posedge i_wb_clk)
	begin
		r_rx_valid <= n_rx_valid;
		rx_valid <= r_rx_valid;
 
		r_rx_busy <= n_rx_busy;
		rx_busy <= r_rx_busy;
 
		rx_len <= n_rx_len;
		rx_broadcast <= n_rx_broadcast;
	end
 
`endif
 
	reg	[3:0]	rx_err_pipe, rx_miss_pipe, rx_crc_pipe;
	always @(posedge i_wb_clk)
	begin
		rx_err_pipe  <= { rx_err_pipe[ 2:0],(n_rx_err)&&(rx_clk_stb)  };
		rx_miss_pipe <= { rx_miss_pipe[2:0],(n_rx_miss)&&(rx_clk_stb) };
		rx_crc_pipe  <= { rx_crc_pipe[ 2:0],(n_rx_crcerr)&&(rx_clk_stb) };
		rx_err_stb   <= (rx_err_pipe[ 3:2] == 2'b01);
		rx_miss_stb  <= (rx_miss_pipe[3:2] == 2'b01);
		rx_crc_stb   <= (rx_crc_pipe[ 3:2] == 2'b01);
	end
 
	always @(posedge i_wb_clk)
		if (o_net_reset_n)
			counter_rx_miss <= 32'h0;
		else if (rx_miss_stb)
			counter_rx_miss <= counter_rx_miss + 32'h1;
	always @(posedge i_wb_clk)
		if (o_net_reset_n)
			counter_rx_err <= 32'h0;
		else if (rx_err_stb)
			counter_rx_err <= counter_rx_err + 32'h1;
	always @(posedge i_wb_clk)
		if (o_net_reset_n)
			counter_rx_crc <= 32'h0;
		else if (rx_crc_stb)
			counter_rx_crc <= counter_rx_crc + 32'h1;
 
	assign	o_tx_int = !tx_busy;
	assign	o_rx_int = (rx_valid)&&(!rx_clear);
	assign	o_wb_stall = 1'b0;
 
	wire	[31:0]	rxdbg;
	wire	rx_trigger; // reg	rx_trigger;
	/*
	always @(posedge `RXCLK)
	begin
		if ((n_rx_clear)&&(!rx_trigger))
			rx_trigger <= 1'b1;
		else if (!n_rx_clear)
			rx_trigger <= 1'b0;
	end
	*/
	assign	rx_trigger = i_net_dv;
 
	assign	rxdbg = { rx_trigger, n_eop, w_rxwr,
		w_npre, w_npred,
		w_rxcrc, w_rxcrcd,
		w_macerr, w_broadcast, w_rxmac, w_rxmacd,
		n_rx_clear, i_net_rxerr, n_rx_miss, n_rx_net_err,// 4 bits
		n_rx_valid, n_rx_busy, i_net_crs, i_net_dv,	// 4 bits
		i_net_rxd };					// 4 bits
 
 
	wire	[31:0]	txdbg;
	assign	txdbg = { n_tx_cmd, i_net_dv, rx_busy, n_rx_err, i_net_rxd,
			{(24-(MAW+3)-10){1'b0}}, 
			n_tx_addr[(MAW+2):0],
		tx_clk_stb, n_tx_cancel,
		n_tx_cmd, n_tx_complete, n_tx_busy, o_net_tx_en,
		o_net_txd
		};
 
	assign	o_debug = rxdbg;
endmodule
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.