Archive-name: fpga_l3_fade
Version: 0.1b
Submitted-by:
wz...@ise.pw.edu.pl
Last-modified: 2012-05-03 +00:00
Copyright-Notice: Free software (partly GPL, partly BSD, partly public domain)
It seems, that my previous post, containing complete sources was too big,
and was rejected by the serwer.
Therefore I send now reduced version (without the 10_100_1000 Mbps tri-mode
ethernet MAC , which is available from:
http://opencores.org/project,ethernet_tri_mode )
This archive implements the simple and light protocol for transmission
of data from low resources FPGA connected to the Ethernet MAC
and an embedded system running Linux OS.
The main goal was to assure the reliable transmission over unreliable
Ethernet link without need to buffer significant amount of data
in the FPGA. This created a need to obtain possibly early
acknowledgment of received packets from the embedded system,
and therefore the protocol had to be implemented in layer 3.
Archive contains both FPGA sources and Linux driver and application
sources.
See file desc.txt for details.
Wojciech M. Zabolotny
wz...@ise.pw.edu.pl
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.11).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `#!/bin/sh' line above, then type `sh FILE'.
#
lock_dir=_sh18720
# Made on 2012-05-03 23:35 CEST by <wzab@WZLap>.
# Source directory was `/tmp/files2'.
#
# Existing files will *not* be overwritten, unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 6897 -rw-r--r-- FPGA_sources/eth_sender.vhd
# 3668 -rwxr--r-- FPGA_sources/ack_fifo/rec_to_pkg.py
# 264 -rw-r--r-- FPGA_sources/ack_fifo/ack.rec
# 1075 -rw-r--r-- FPGA_sources/ack_fifo/pkt_ack_pkg.vhd
# 7892 -rw-r--r-- FPGA_sources/eth_receiver.vhd
# 6020 -rw-r--r-- FPGA_sources/dcm1.xco
# 1665 -rw-r--r-- FPGA_sources/dpram_inf.vhd
# 2715 -rw-r--r-- FPGA_sources/ack_fifo.xco
# 4827 -rw-r--r-- FPGA_sources/sp601_eth.ucf
# 1358 -rw-r--r-- FPGA_sources/sp601_eth.prj
# 22288 -rw-r--r-- FPGA_sources/sp601_eth_top.vhd
# 20479 -rw-r--r-- FPGA_sources/desc_manager_simple.vhd
# 2196 -rw-r--rw- linux_driver_and_application/receiver2.c
# 2075 -rw-r--r-- linux_driver_and_application/fpga_l3_fade.h
# 31482 -rw-r--r-- linux_driver_and_application/fpga_l3_fade.c
# 219 -rw-r--r-- linux_driver_and_application/Makefile
# 9345 -rw-r--r-- desc.txt
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
if test "X$1" = "X-c"
then keep_file=''
else keep_file=true
fi
echo=echo
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=
locale_dir=
set_echo=false
for dir in $PATH
do
if test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir
set_echo=true
break ;;
esac
fi
done
if ${set_echo}
then
set_echo=false
for dir in $PATH
do
if test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
set_echo=true
break
fi
done
if ${set_echo}
then
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
fi
IFS="$save_IFS"
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
then shar_n= shar_c='
'
else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901
if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
test ! -f ${st1} && test -f ${f}; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
test ! -f ${st3} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$2 "$8"'
else
shar_touch=:
echo
${echo} 'WARNING: not restoring timestamps. Consider getting and
installing GNU `touch'\'', distributed in GNU coreutils...'
echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir} ; then :
else ${echo} "lock directory ${lock_dir} exists"
exit 1
fi
if mkdir ${lock_dir}
then ${echo} "x - created lock directory ${lock_dir}."
else ${echo} "x - failed to create lock directory ${lock_dir}."
exit 1
fi
# ============= FPGA_sources/eth_sender.vhd ==============
if test ! -d 'FPGA_sources'; then
mkdir 'FPGA_sources'
if test $? -eq 0
then ${echo} "x - created directory FPGA_sources."
else ${echo} "x - failed to create directory FPGA_sources."
exit 1
fi
fi
if test -n "${keep_file}" && test -f 'FPGA_sources/eth_sender.vhd'
then
${echo} "x - SKIPPING FPGA_sources/eth_sender.vhd (file already exists)"
else
${echo} "x - extracting FPGA_sources/eth_sender.vhd (text)"
sed 's/^X//' << 'SHAR_EOF' > 'FPGA_sources/eth_sender.vhd' &&
-------------------------------------------------------------------------------
-- Title : FPGA Ethernet interface - block sending packets via Ethernet MAC
-- Project :
-------------------------------------------------------------------------------
-- File : desc_manager.vhd
-- Author : Wojciech M. Zabolotny (
wz...@ise.pw.edu.pl)
-- License : BSD License
-- Company :
-- Created : 2012-03-30
-- Last update: 2012-05-03
-- Platform :
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: This file implements the state machine, which manages the
-- table of packet descriptors, used to resend only not confirmed packets
-------------------------------------------------------------------------------
-- Copyright (c) 2012
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2012-03-30 1.0 WZab Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
X
entity eth_sender is
X
X port (
X -- Configuration
X peer_mac : in std_logic_vector(47 downto 0);
X my_mac : in std_logic_vector(47 downto 0);
X my_ether_type : in std_logic_vector(15 downto 0);
X set_number : in unsigned(15 downto 0);
X pkt_number : in unsigned(15 downto 0);
X retry_number : in unsigned(15 downto 0);
X transm_delay : in unsigned(31 downto 0);
X -- System interface
X clk : in std_logic;
X rst_n : in std_logic;
X -- Control interface
X ready : out std_logic;
X start : in std_logic;
X -- Data memory interface
X tx_mem_addr : out std_logic_vector(13 downto 0);
X tx_mem_data : in std_logic_vector(31 downto 0);
X -- MAC inerface
X Tx_mac_wa : in std_logic;
X Tx_mac_wr : out std_logic;
X Tx_mac_data : out std_logic_vector(31 downto 0);
X Tx_mac_BE : out std_logic_vector(1 downto 0);
X Tx_mac_sop : out std_logic;
X Tx_mac_eop : out std_logic
X );
X
end eth_sender;
X
X
architecture beh1 of eth_sender is
X
X type T_ETH_SENDER_STATE is (WST_IDLE, WST_SEND_1, WST_SEND_1a, WST_SEND_1b,
X WST_SEND_2, WST_SEND_3, WST_SEND_4, WST_SEND_5);
X
X type T_ETH_SENDER_REGS is record
X state : T_ETH_SENDER_STATE;
X ready : std_logic;
X tx_mem_addr : unsigned (7 downto 0);
X end record;
X
X constant ETH_SENDER_REGS_INI : T_ETH_SENDER_REGS := (
X tx_mem_addr => (others => '0'),
X state => WST_IDLE,
X ready => '1'
X ) ;
X
X signal r, r_i : T_ETH_SENDER_REGS := ETH_SENDER_REGS_INI;
X
X type T_ETH_SENDER_COMB is record
X Tx_mac_wr : std_logic;
X Tx_mac_sop : std_logic;
X Tx_mac_eop : std_logic;
X Tx_mac_data : std_logic_vector(31 downto 0);
X tx_mem_addr : unsigned(7 downto 0);
X end record;
X
X constant ETH_SENDER_COMB_DEFAULT : T_ETH_SENDER_COMB := (
X Tx_mac_wr => '0',
X Tx_mac_sop => '0',
X Tx_mac_eop => '0',
X Tx_mac_data => (others => '0'),
X tx_mem_addr => (others => '0')
X );
X
X signal c : T_ETH_SENDER_COMB := ETH_SENDER_COMB_DEFAULT;
X
begin -- beh1
X
X -- Connection of the signals
X Tx_mac_data <= c.Tx_mac_data;
X Tx_mac_eop <= c.Tx_mac_eop;
X Tx_mac_sop <= c.Tx_mac_sop;
X Tx_mac_wr <= C.Tx_mac_wr;
X Tx_mac_be <= "00";
X
X ready <= r.ready;
X
X -- The memory address is built from the packet number (6 bits) and word
X -- number (8 bits)
X tx_mem_addr <= std_logic_vector(pkt_number(5 downto 0)) & std_logic_vector(c.tx_mem_addr);
X
X -- Main state machine used to send the packet
X snd1 : process (clk, rst_n)
X begin
X if rst_n = '0' then -- asynchronous reset (active low)
X r <= ETH_SENDER_REGS_INI;
X elsif clk'event and clk = '1' then -- rising clock edge
X r <= r_i;
X end if;
X end process snd1; -- snd1
X
X snd2 : process (Tx_mac_wa, my_ether_type, my_mac, peer_mac, pkt_number, r,
X retry_number, set_number, start, transm_delay,
X tx_mem_data)
X begin -- process snd1
X -- default values
X c <= ETH_SENDER_COMB_DEFAULT;
X r_i <= r;
X case r.state is
X when WST_IDLE =>
X if start = '1' then
X r_i.ready <= '0';
X r_i.state <= WST_SEND_1;
X end if;
X when WST_SEND_1 =>
X if Tx_mac_wa = '1' then
X c.tx_mac_data <= peer_mac(47 downto 16);
X c.Tx_mac_sop <= '1';
X c.tx_mac_wr <= '1';
X r_i.state <= WST_SEND_1a;
X end if;
X when WST_SEND_1a =>
X if Tx_mac_wa = '1' then
X c.tx_mac_data <= peer_mac(15 downto 0) & my_mac(47 downto 32);
X c.tx_mac_wr <= '1';
X r_i.state <= WST_SEND_1b;
X end if;
X when WST_SEND_1b =>
X if Tx_mac_wa = '1' then
X c.tx_mac_data <= my_mac(31 downto 0);
X c.tx_mac_wr <= '1';
X r_i.state <= WST_SEND_2;
X end if;
X when WST_SEND_2 =>
X if Tx_mac_wa = '1' then
X c.tx_mac_data <= my_ether_type & x"a5a5";
X c.tx_mac_wr <= '1';
X r_i.state <= WST_SEND_3;
X end if;
X when WST_SEND_3 =>
X -- Now we send the set & packet number & retry_number
X if Tx_mac_wa = '1' then
X c.tx_mac_data <= std_logic_vector(set_number(15 downto 0)) & std_logic_vector(pkt_number(5 downto 0)) & std_logic_vector(retry_number(9 downto 0));
X c.tx_mac_wr <= '1';
X r_i.tx_mem_addr <= (others => '0');
X r_i.state <= WST_SEND_4;
X end if;
X when WST_SEND_4 =>
X -- Now we send the set & packet number & retry_number
X if Tx_mac_wa = '1' then
X c.tx_mac_data <= std_logic_vector(transm_delay);
X c.tx_mac_wr <= '1';
X r_i.tx_mem_addr <= (others => '0');
X r_i.state <= WST_SEND_5;
X end if;
X when WST_SEND_5 =>
X -- Now we send the packet data
X -- If the address is not incremented,
X -- we still send the last address to the memory...
X c.tx_mem_addr <= r.tx_mem_addr;
X if Tx_mac_wa = '1' then
X c.tx_mac_data <= tx_mem_data;
X c.tx_mac_wr <= '1';
X if r.tx_mem_addr < 255 then
X -- Still some data should be sent
X -- We increase the address, so the data are available
X -- in the next cycle
X r_i.tx_mem_addr <= r.tx_mem_addr + 1;
X c.tx_mem_addr <= r.tx_mem_addr + 1;
X r_i.state <= WST_SEND_5; -- we remain in the same state
X else
X -- All data sent
X -- set the "end_of_packet" flag
X c.Tx_mac_eop <= '1';
X r_i.state <= WST_IDLE;
X r_i.ready <= '1';
X end if;
X end if;
X end case;
X end process snd2;
X
end beh1;
SHAR_EOF
(set 20 12 05 03 21 13 14 'FPGA_sources/eth_sender.vhd'
eval "${shar_touch}") && \
chmod 0644 'FPGA_sources/eth_sender.vhd'
if test $? -ne 0
then ${echo} "restore of FPGA_sources/eth_sender.vhd failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'FPGA_sources/eth_sender.vhd': 'MD5 check failed'
) << \SHAR_EOF
f94e60b0820fcf0cbc5f951e6f2c6dfd FPGA_sources/eth_sender.vhd
SHAR_EOF
else
test `LC_ALL=C wc -c < 'FPGA_sources/eth_sender.vhd'` -ne 6897 && \
${echo} "restoration warning: size of 'FPGA_sources/eth_sender.vhd' is not 6897"
fi
fi
# ============= FPGA_sources/ack_fifo/rec_to_pkg.py ==============
if test ! -d 'FPGA_sources'; then
mkdir 'FPGA_sources'
if test $? -eq 0
then ${echo} "x - created directory FPGA_sources."
else ${echo} "x - failed to create directory FPGA_sources."
exit 1
fi
fi
if test ! -d 'FPGA_sources/ack_fifo'; then
mkdir 'FPGA_sources/ack_fifo'
if test $? -eq 0
then ${echo} "x - created directory FPGA_sources/ack_fifo."
else ${echo} "x - failed to create directory FPGA_sources/ack_fifo."
exit 1
fi
fi
if test -n "${keep_file}" && test -f 'FPGA_sources/ack_fifo/rec_to_pkg.py'
then
${echo} "x - SKIPPING FPGA_sources/ack_fifo/rec_to_pkg.py (file already exists)"
else
${echo} "x - extracting FPGA_sources/ack_fifo/rec_to_pkg.py (text)"
sed 's/^X//' << 'SHAR_EOF' > 'FPGA_sources/ack_fifo/rec_to_pkg.py' &&
#!/usr/bin/python
# The script below is written by Wojciech M. Zabolotny
# wzab<at>
ise.pw.edu.pl 19.03.2012
# it is published as PUBLIC DOMAIN
import sys
class field:
X last_bit = 0;
X def __init__(self,field_desc):
X fd = field_desc.split(",")
X self.fname = fd[0]
X if not fd[1] in ["signed","unsigned","std_logic_vector"]:
X raise Exception("Wrong field type")
X self.ftype = fd[1]
X if len(fd)==3:
X self.b1=int(fd[2])-1
X self.b2=0
X elif len(fd)==4:
X self.b1=int(fd[2])
X self.b2=int(fd[3])
X else:
X raise Exception("Syntax error in line: "+field_desc)
X #Assign vector bits
X self.v1=field.last_bit
X self.v2=field.last_bit+abs(self.b2-self.b1)
X field.last_bit = self.v2+1
X
if len(sys.argv) != 2:
X print """
The rec_to_pkg scripts creates VHDL package for conversion
between the VHDL records containing "signed" and "unsigned"
fields and std_logic_vectors.
It should be called as: rec_to_pkg.py description_file
where the description file should have the following syntax:
X
#Optional comment line
record record_name
#optional comment lines
#[...]
field_name,signed_or_unsigned,width
#or
field_name,signed_or_unsigned,left_bit_nr,right_bit_nr
end
X
The generated package is written to the record_name_pkg.vhd file
"""
X exit(0)
fin=open(sys.argv[1])
#Read the full description of the type
type_desc=[l.strip() for l in fin.readlines() if len(l) > 0 and l[0] != "#" ]
#The first line should contain the record name
l=type_desc[0].split(" ")
if l[0] != "record":
X raise Exception("Syntax error! The first line should have form \"record name_of_type\"")
type_name=l[1]
pkg_name=type_name+"_pkg"
#Prepare for analysis of fields
msb=0
fields=[]
end_found = False
#Find the field definitions
for l in type_desc[1:]:
X if l=="end":
X end_found=True
X break
X fields.append(field(l))
if not end_found:
X raise Exception("Syntax error: no \"end\" found")
#If we got here, probably the syntax was correct
#Lets generate the package
p="""\
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
"""
p+="package "+pkg_name+" is\n\n"
p+="type "+type_name+" is record\n"
for f in fields:
X s=" "+f.fname+" : "+f.ftype+"("
X if f.b1 > f.b2:
X s=s+str(f.b1)+" downto "+str(f.b2)+");\n"
X else:
X s=s+str(f.b1)+" to "+str(f.b2)+");\n"
X p+=s
p+="end record;\n\n"
#Write width of our type
p+="constant "+type_name+"_width : integer := "+str(field.last_bit)+";\n\n"
#Write headers of conversion functions
p+="function "+type_name+"_to_stlv(\n"
p+=" constant din : "+type_name+")\n"
p+=" return std_logic_vector;\n\n"
p+="function stlv_to_"+type_name+"(\n"
p+=" constant din : std_logic_vector)\n"
p+=" return "+type_name+";\n\n"
p+="end "+pkg_name+";\n\n"
#Now the body of the package - the conversion functions
p+="package body "+pkg_name+" is\n\n"
#
p+="function "+type_name+"_to_stlv(\n"
p+=" constant din : "+type_name+")\n"
p+=" return std_logic_vector is\n"
p+=" variable res : std_logic_vector("+str(field.last_bit-1)+" downto 0);\n"
p+="begin\n"
for f in fields:
X p+=" res("+str(f.v2)+" downto "+str(f.v1)+ ") := std_logic_vector(din."+f.fname+");\n"
p+=" return res;\n"
p+="end "+type_name+"_to_stlv;\n\n"
#
p+="function stlv_to_"+type_name+"(\n"
p+=" constant din : std_logic_vector)\n"
p+=" return "+type_name+" is\n"
p+=" variable res : "+type_name+";\n"
p+="begin\n"
for f in fields:
X p+=" res."+f.fname+":="+f.ftype+"(din("+str(f.v2)+" downto "+str(f.v1)+"));\n"
p+=" return res;\n"
p+="end stlv_to_"+type_name+";\n\n"
p+="end "+pkg_name+";\n"
X
#The output file name
fout_name=type_name+"_pkg.vhd"
fout=open(fout_name,"w")
fout.write(p)
fout.close()
X
SHAR_EOF
(set 20 12 04 15 01 27 43 'FPGA_sources/ack_fifo/rec_to_pkg.py'
eval "${shar_touch}") && \
chmod 0744 'FPGA_sources/ack_fifo/rec_to_pkg.py'
if test $? -ne 0
then ${echo} "restore of FPGA_sources/ack_fifo/rec_to_pkg.py failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'FPGA_sources/ack_fifo/rec_to_pkg.py': 'MD5 check failed'
) << \SHAR_EOF
1dd1bdc167123fcdcffb9b1d10bdc395 FPGA_sources/ack_fifo/rec_to_pkg.py
SHAR_EOF
else
test `LC_ALL=C wc -c < 'FPGA_sources/ack_fifo/rec_to_pkg.py'` -ne 3668 && \
${echo} "restoration warning: size of 'FPGA_sources/ack_fifo/rec_to_pkg.py' is not 3668"
fi
fi
# ============= FPGA_sources/ack_fifo/ack.rec ==============
if test ! -d 'FPGA_sources/ack_fifo'; then
mkdir 'FPGA_sources/ack_fifo'
if test $? -eq 0
then ${echo} "x - created directory FPGA_sources/ack_fifo."
else ${echo} "x - failed to create directory FPGA_sources/ack_fifo."
exit 1
fi
fi
if test -n "${keep_file}" && test -f 'FPGA_sources/ack_fifo/ack.rec'
then
${echo} "x - SKIPPING FPGA_sources/ack_fifo/ack.rec (file already exists)"
else
${echo} "x - extracting FPGA_sources/ack_fifo/ack.rec (text)"
sed 's/^X//' << 'SHAR_EOF' > 'FPGA_sources/ack_fifo/ack.rec' &&
# This is a test record - packet acknowledgment
record pkt_ack
# Below are fields definitions
# First two pointers fo linked list
# pkt - number of the packet
pkt,unsigned,8
# set - number of the set
set,unsigned,16
# cmd - command - 1 for ACK
cmd,unsigned,8
end
X
SHAR_EOF
(set 20 12 04 15 01 27 43 'FPGA_sources/ack_fifo/ack.rec'
eval "${shar_touch}") && \
chmod 0644 'FPGA_sources/ack_fifo/ack.rec'
if test $? -ne 0
then ${echo} "restore of FPGA_sources/ack_fifo/ack.rec failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'FPGA_sources/ack_fifo/ack.rec': 'MD5 check failed'
) << \SHAR_EOF
064e7846617f4ec6b3742037378d7387 FPGA_sources/ack_fifo/ack.rec
SHAR_EOF
else
test `LC_ALL=C wc -c < 'FPGA_sources/ack_fifo/ack.rec'` -ne 264 && \
${echo} "restoration warning: size of 'FPGA_sources/ack_fifo/ack.rec' is not 264"
fi
fi
# ============= FPGA_sources/ack_fifo/pkt_ack_pkg.vhd ==============
if test -n "${keep_file}" && test -f 'FPGA_sources/ack_fifo/pkt_ack_pkg.vhd'
then
${echo} "x - SKIPPING FPGA_sources/ack_fifo/pkt_ack_pkg.vhd (file already exists)"
else
${echo} "x - extracting FPGA_sources/ack_fifo/pkt_ack_pkg.vhd (text)"
sed 's/^X//' << 'SHAR_EOF' > 'FPGA_sources/ack_fifo/pkt_ack_pkg.vhd' &&
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package pkt_ack_pkg is
X
type pkt_ack is record
X pkt : unsigned(7 downto 0);
X set : unsigned(15 downto 0);
X cmd : unsigned(7 downto 0);
end record;
X
constant pkt_ack_width : integer := 32;
X
function pkt_ack_to_stlv(
X constant din : pkt_ack)
X return std_logic_vector;
X
function stlv_to_pkt_ack(
X constant din : std_logic_vector)
X return pkt_ack;
X
end pkt_ack_pkg;
X
package body pkt_ack_pkg is
X
function pkt_ack_to_stlv(
X constant din : pkt_ack)
X return std_logic_vector is
X variable res : std_logic_vector(31 downto 0);
begin
X res(7 downto 0) := std_logic_vector(din.pkt);
X res(23 downto 8) := std_logic_vector(din.set);
X res(31 downto 24) := std_logic_vector(din.cmd);
X return res;
end pkt_ack_to_stlv;
X
function stlv_to_pkt_ack(
X constant din : std_logic_vector)
X return pkt_ack is
X variable res : pkt_ack;
begin
X res.pkt:=unsigned(din(7 downto 0));
X res.set:=unsigned(din(23 downto 8));
X res.cmd:=unsigned(din(31 downto 24));
X return res;
end stlv_to_pkt_ack;
X
end pkt_ack_pkg;
SHAR_EOF
(set 20 12 04 15 01 27 43 'FPGA_sources/ack_fifo/pkt_ack_pkg.vhd'
eval "${shar_touch}") && \
chmod 0644 'FPGA_sources/ack_fifo/pkt_ack_pkg.vhd'
if test $? -ne 0
then ${echo} "restore of FPGA_sources/ack_fifo/pkt_ack_pkg.vhd failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'FPGA_sources/ack_fifo/pkt_ack_pkg.vhd': 'MD5 check failed'
) << \SHAR_EOF
1fdd7e54fb306a806df6ca56e821d184 FPGA_sources/ack_fifo/pkt_ack_pkg.vhd
SHAR_EOF
else
test `LC_ALL=C wc -c < 'FPGA_sources/ack_fifo/pkt_ack_pkg.vhd'` -ne 1075 && \
${echo} "restoration warning: size of 'FPGA_sources/ack_fifo/pkt_ack_pkg.vhd' is not 1075"
fi
fi
# ============= FPGA_sources/eth_receiver.vhd ==============
if test -n "${keep_file}" && test -f 'FPGA_sources/eth_receiver.vhd'
then
${echo} "x - SKIPPING FPGA_sources/eth_receiver.vhd (file already exists)"
else
${echo} "x - extracting FPGA_sources/eth_receiver.vhd (text)"
sed 's/^X//' << 'SHAR_EOF' > 'FPGA_sources/eth_receiver.vhd' &&
-------------------------------------------------------------------------------
-- Title : FPGA Ethernet interface - block receiving packets from Ethernet MAC
-- Project :
-------------------------------------------------------------------------------
-- File : desc_manager.vhd
-- Author : Wojciech M. Zabolotny (
wz...@ise.pw.edu.pl)
-- License : BSD License
-- Company :
-- Created : 2012-03-30
-- Last update: 2012-05-03
-- Platform :
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: This file implements the state machine, which manages the
-- table of packet descriptors, used to resend only not confirmed packets
-------------------------------------------------------------------------------
-- Copyright (c) 2012
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2012-03-30 1.0 WZab Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.pkt_ack_pkg.all;
X
entity eth_receiver is
X
X port (
X -- Configuration
X peer_mac : out std_logic_vector(47 downto 0);
X my_mac : in std_logic_vector(47 downto 0);
X my_ether_type : in std_logic_vector(15 downto 0);
X transmit_data : out std_logic;
X restart : out std_logic;
X -- ACK FIFO interface
X ack_fifo_full : in std_logic;
X ack_fifo_wr_en : out std_logic;
X ack_fifo_din : out std_logic_vector(pkt_ack_width-1 downto 0);
X -- System interface
X clk : in std_logic;
X rst_n : in std_logic;
X -- MAC inerface
X Rx_mac_pa : in std_logic;
X Rx_mac_ra : in std_logic;
X Rx_mac_rd : out std_logic;
X Rx_mac_data : in std_logic_vector(31 downto 0);
X Rx_mac_BE : in std_logic_vector(1 downto 0);
X Rx_mac_sop : in std_logic;
X Rx_mac_eop : in std_logic
X );
X
end eth_receiver;
X
X
architecture beh1 of eth_receiver is
X
X type T_STATE is (ST_IDLE, ST_ACK_1, ST_NACK_1, ST_SET_DELAY, ST_READ_SRC1, ST_READ_SRC2, ST_READ_OP);
X
X type T_RCV_REGS is record
X state : T_STATE;
X sender : std_logic_vector(47 downto 0);
X transmit_data : std_logic;
X peer_mac : std_logic_vector(47 downto 0);
X end record;
X
X constant RCV_REGS_INI : T_RCV_REGS := (
X state => ST_IDLE,
X sender => (others => '0'),
X transmit_data => '0',
X peer_mac => (others => '0')
X );
X
X signal r, r_i : T_RCV_REGS := RCV_REGS_INI;
X
X type T_RCV_COMB is record
X ack_fifo_wr_en : std_logic;
X Rx_mac_rd : std_logic;
X ack_fifo_din : std_logic_vector(pkt_ack_width-1 downto 0);
X restart : std_logic;
X end record;
X
X constant RCV_COMB_DEFAULT : T_RCV_COMB := (
X ack_fifo_wr_en => '0',
X Rx_mac_rd => '0',
X ack_fifo_din => (others => '0'),
X restart => '0'
X );
X
X signal c : T_RCV_COMB := RCV_COMB_DEFAULT;
X
begin -- beh1
X
X transmit_data <= r.transmit_data;
X peer_mac <= r.peer_mac;
X ack_fifo_din <= c.ack_fifo_din;
X ack_fifo_wr_en <= c.ack_fifo_wr_en;
X Rx_mac_rd <= c.Rx_mac_rd;
X restart <= c.restart;
X
X -- Reading of ethernet data
X rdp1 : process (clk, rst_n)
X begin -- process rdp1
X if rst_n = '0' then -- asynchronous reset (active low)
X r <= RCV_REGS_INI;
X elsif clk'event and clk = '1' then -- rising clock edge
X r <= r_i;
X end if;
X end process rdp1;
X
X rdp2 : process (Rx_mac_data, Rx_mac_ra, Rx_mac_sop, ack_fifo_full,
X my_ether_type, my_mac, r)
X
X variable ack_pkt_in : pkt_ack;
X
X begin -- process
X c <= RCV_COMB_DEFAULT;
X r_i <= r;
X case r.state is
X when ST_IDLE =>
X if Rx_mac_ra = '1' then
X c.Rx_mac_rd <= '1';
X if Rx_mac_sop = '1' then
X if Rx_mac_data(31 downto 0) = my_mac(47 downto 16) then
X r_i.state <= ST_READ_SRC1;
X else
X r_i.state <= ST_IDLE;
X end if;
X end if;
X end if;
X when ST_READ_SRC1 =>
X if Rx_mac_ra = '1' then
X c.Rx_mac_rd <= '1';
X if Rx_mac_sop = '1' then
X -- This shouldn't happen!
X r_i.state <= ST_IDLE;
X else
X if Rx_mac_data(31 downto 16) = my_mac(15 downto 0) then
X r_i.sender(47 downto 32) <= Rx_mac_data(15 downto 0);
X r_i.state <= ST_READ_SRC2;
X else
X r_i.state <= ST_IDLE;
X end if;
X end if;
X end if;
X when ST_READ_SRC2 =>
X if Rx_mac_ra = '1' then
X c.Rx_mac_rd <= '1';
X if Rx_mac_sop = '1' then
X -- This shouldn't happen!
X r_i.state <= ST_IDLE;
X else
X r_i.sender(31 downto 0) <= Rx_mac_data;
X r_i.state <= ST_READ_OP;
X end if;
X end if;
X when ST_READ_OP =>
X if Rx_mac_ra = '1' then
X c.Rx_mac_rd <= '1';
X if Rx_mac_sop = '1' then
X -- This shouldn't happen!
X r_i.state <= ST_IDLE;
X -- check the Ethernet type
X elsif Rx_mac_data(31 downto 16) /= my_ether_type then
X r_i.state <= ST_IDLE;
X else
X -- This is a packet in our protocol, so we can update
X -- the peer address
X r_i.peer_mac <= r.sender;
X -- check the command
X case Rx_mac_data(15 downto 0) is
X when x"0001" =>
X -- Start transmission command
X r_i.transmit_data <= '1';
X r_i.state <= ST_IDLE;
X when x"0002" =>
X -- Stop transmission command
X r_i.transmit_data <= '0';
X r_i.state <= ST_IDLE;
X when x"0003" =>
X -- Packet ACK command
X r_i.state <= ST_ACK_1;
X when x"0004" =>
X -- Packet NACK command (currently not used)
X r_i.state <= ST_NACK_1;
X when x"0005" =>
X -- Stop transmission and retransmission
X c.restart <= '1';
X r_i.state <= ST_IDLE;
X when others =>
X r_i.state <= ST_IDLE;
X end case;
X end if;
X end if;
X when ST_ACK_1 =>
X if Rx_mac_ra = '1' then
X c.Rx_mac_rd <= '1';
X if Rx_mac_sop = '1' then
X -- This shouldn't happen!
X r_i.state <= ST_IDLE;
X else
X -- put the ACK info int the FIFO queue
X ack_pkt_in.cmd := (others => '0');
X ack_pkt_in.set := unsigned(Rx_mac_data(31 downto 16));
X ack_pkt_in.pkt := "00" & unsigned(Rx_mac_data(15 downto 10));
X c.ack_fifo_din <= pkt_ack_to_stlv(ack_pkt_in);
X c.ack_fifo_wr_en <= '1';
X r_i.state <= ST_IDLE;
X end if;
X end if;
X when ST_NACK_1 =>
X if Rx_mac_ra = '1' then
X c.Rx_mac_rd <= '1';
X if Rx_mac_sop = '1' then
X -- This shouldn't happen!
X r_i.state <= ST_IDLE;
X else
X -- put the ACK info int the FIFO queue
X -- (if FIFO is full, we simply drop the packet)
X if ack_fifo_full = '0' then
X ack_pkt_in.cmd := (others => '0');
X ack_pkt_in.set := unsigned(Rx_mac_data(31 downto 16));
X ack_pkt_in.pkt := "00" & unsigned(Rx_mac_data(15 downto 10));
X c.ack_fifo_din <= pkt_ack_to_stlv(ack_pkt_in);
X c.ack_fifo_wr_en <= '1';
X end if;
X r_i.state <= ST_IDLE;
X end if;
X end if;
X when others => null;
X end case;
X end process rdp2;
X
end beh1;
SHAR_EOF
(set 20 12 05 03 21 06 03 'FPGA_sources/eth_receiver.vhd'
eval "${shar_touch}") && \
chmod 0644 'FPGA_sources/eth_receiver.vhd'
if test $? -ne 0
then ${echo} "restore of FPGA_sources/eth_receiver.vhd failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'FPGA_sources/eth_receiver.vhd': 'MD5 check failed'
) << \SHAR_EOF
bac81d45dc350495fdd6b7a4d8a428f0 FPGA_sources/eth_receiver.vhd
SHAR_EOF
else
test `LC_ALL=C wc -c < 'FPGA_sources/eth_receiver.vhd'` -ne 7892 && \
${echo} "restoration warning: size of 'FPGA_sources/eth_receiver.vhd' is not 7892"
fi
fi
# ============= FPGA_sources/dcm1.xco ==============
if test -n "${keep_file}" && test -f 'FPGA_sources/dcm1.xco'
then
${echo} "x - SKIPPING FPGA_sources/dcm1.xco (file already exists)"
else
${echo} "x - extracting FPGA_sources/dcm1.xco (text)"
sed 's/^X//' << 'SHAR_EOF' > 'FPGA_sources/dcm1.xco' &&
##############################################################
##############################################################
##############################################################
SET designentry = VHDL
SET BusFormat = BusFormatAngleBracketNotRipped
SET devicefamily = spartan6
SET device = xc6slx16
SET package = csg324
SET speedgrade = -2
SET FlowVendor = Foundation_ISE
SET VerilogSim = True
SET VHDLSim = True
SELECT Clocking_Wizard family Xilinx,_Inc. 1.7
CSET calc_done=DONE
CSET clk_out1_use_fine_ps_gui=false
CSET clk_out2_use_fine_ps_gui=false
CSET clk_out3_use_fine_ps_gui=false
CSET clk_out4_use_fine_ps_gui=false
CSET clk_out5_use_fine_ps_gui=false
CSET clk_out6_use_fine_ps_gui=false
CSET clk_out7_use_fine_ps_gui=false
CSET clkfb_in_signaling=SINGLE
CSET clkin1_jitter_ps=50.0
CSET clkin1_ui_jitter=0.01
CSET clkin2_jitter_ps=100.0
CSET clkin2_ui_jitter=0.01
CSET clkout1_drives=BUFG
CSET clkout1_requested_duty_cycle=50.000
CSET clkout1_requested_out_freq=125.000
CSET clkout1_requested_phase=0.000
CSET clkout2_drives=BUFG
CSET clkout2_requested_duty_cycle=50.000
CSET clkout2_requested_out_freq=64.000
CSET clkout2_requested_phase=0.000
CSET clkout2_used=true
CSET clkout3_drives=BUFG
CSET clkout3_requested_duty_cycle=50.000
CSET clkout3_requested_out_freq=64.000
CSET clkout3_requested_phase=0.000
CSET clkout3_used=true
CSET clkout4_drives=BUFG
CSET clkout4_requested_duty_cycle=50.000
CSET clkout4_requested_out_freq=100.000
CSET clkout4_requested_phase=0.000
CSET clkout4_used=false
CSET clkout5_drives=BUFG
CSET clkout5_requested_duty_cycle=50.000
CSET clkout5_requested_out_freq=100.000
CSET clkout5_requested_phase=0.000
CSET clkout5_used=false
CSET clkout6_drives=BUFG
CSET clkout6_requested_duty_cycle=50.000
CSET clkout6_requested_out_freq=100.000
CSET clkout6_requested_phase=0.000
CSET clkout6_used=false
CSET clkout7_drives=BUFG
CSET clkout7_requested_duty_cycle=50.000
CSET clkout7_requested_out_freq=100.000
CSET clkout7_requested_phase=0.000
CSET clkout7_used=false
CSET clock_mgr_type=AUTO
CSET component_name=dcm1
CSET dcm_clk_feedback=1X
CSET dcm_clk_out1_port=CLKFX
CSET dcm_clk_out2_port=CLKDV
CSET dcm_clk_out3_port=CLK0
CSET dcm_clk_out4_port=CLK0
CSET dcm_clk_out5_port=CLK0
CSET dcm_clk_out6_port=CLK0
CSET dcm_clkdv_divide=10.0
CSET dcm_clkfx_divide=4
CSET dcm_clkfx_multiply=5
CSET dcm_clkgen_clk_out1_port=CLKFX
CSET dcm_clkgen_clk_out2_port=CLKFX
CSET dcm_clkgen_clk_out3_port=CLKFX
CSET dcm_clkgen_clkfx_divide=1
CSET dcm_clkgen_clkfx_md_max=0.000
CSET dcm_clkgen_clkfx_multiply=4
CSET dcm_clkgen_clkfxdv_divide=2
CSET dcm_clkgen_clkin_period=10.000
CSET dcm_clkgen_notes=None
CSET dcm_clkgen_spread_spectrum=NONE
CSET dcm_clkgen_startup_wait=false
CSET dcm_clkin_divide_by_2=true
CSET dcm_clkin_period=5.000
CSET dcm_clkout_phase_shift=NONE
CSET dcm_deskew_adjust=SYSTEM_SYNCHRONOUS
CSET dcm_notes=None
CSET dcm_phase_shift=0
CSET dcm_startup_wait=false
CSET feedback_source=FDBK_AUTO
CSET in_freq_units=Units_MHz
CSET in_jitter_units=Units_UI
CSET jitter_options=UI
CSET jitter_sel=No_Jitter
CSET mmcm_bandwidth=OPTIMIZED
CSET mmcm_clkfbout_mult_f=4.000
CSET mmcm_clkfbout_phase=0.000
CSET mmcm_clkfbout_use_fine_ps=false
CSET mmcm_clkin1_period=10.000
CSET mmcm_clkin2_period=10.000
CSET mmcm_clkout0_divide_f=4.000
CSET mmcm_clkout0_duty_cycle=0.500
CSET mmcm_clkout0_phase=0.000
CSET mmcm_clkout0_use_fine_ps=false
CSET mmcm_clkout1_divide=1
CSET mmcm_clkout1_duty_cycle=0.500
CSET mmcm_clkout1_phase=0.000
CSET mmcm_clkout1_use_fine_ps=false
CSET mmcm_clkout2_divide=1
CSET mmcm_clkout2_duty_cycle=0.500
CSET mmcm_clkout2_phase=0.000
CSET mmcm_clkout2_use_fine_ps=false
CSET mmcm_clkout3_divide=1
CSET mmcm_clkout3_duty_cycle=0.500
CSET mmcm_clkout3_phase=0.000
CSET mmcm_clkout3_use_fine_ps=false
CSET mmcm_clkout4_cascade=false
CSET mmcm_clkout4_divide=1
CSET mmcm_clkout4_duty_cycle=0.500
CSET mmcm_clkout4_phase=0.000
CSET mmcm_clkout4_use_fine_ps=false
CSET mmcm_clkout5_divide=1
CSET mmcm_clkout5_duty_cycle=0.500
CSET mmcm_clkout5_phase=0.000
CSET mmcm_clkout5_use_fine_ps=false
CSET mmcm_clkout6_divide=1
CSET mmcm_clkout6_duty_cycle=0.500
CSET mmcm_clkout6_phase=0.000
CSET mmcm_clkout6_use_fine_ps=false
CSET mmcm_clock_hold=false
CSET mmcm_compensation=ZHOLD
CSET mmcm_divclk_divide=1
CSET mmcm_notes=None
CSET mmcm_ref_jitter1=0.010
CSET mmcm_ref_jitter2=0.010
CSET mmcm_startup_wait=false
CSET num_out_clks=3
CSET override_dcm=false
CSET override_dcm_clkgen=false
CSET override_mmcm=false
CSET override_pll=false
CSET platform=lin
CSET pll_bandwidth=OPTIMIZED
CSET pll_clk_feedback=CLKFBOUT
CSET pll_clkfbout_mult=5
CSET pll_clkfbout_phase=0.000
CSET pll_clkin_period=5.000
CSET pll_clkout0_divide=4
CSET pll_clkout0_duty_cycle=0.500
CSET pll_clkout0_phase=0.000
CSET pll_clkout1_divide=8
CSET pll_clkout1_duty_cycle=0.500
CSET pll_clkout1_phase=0.000
CSET pll_clkout2_divide=8
CSET pll_clkout2_duty_cycle=0.500
CSET pll_clkout2_phase=0.000
CSET pll_clkout3_divide=1
CSET pll_clkout3_duty_cycle=0.500
CSET pll_clkout3_phase=0.000
CSET pll_clkout4_divide=1
CSET pll_clkout4_duty_cycle=0.500
CSET pll_clkout4_phase=0.000
CSET pll_clkout5_divide=1
CSET pll_clkout5_duty_cycle=0.500
CSET pll_clkout5_phase=0.000
CSET pll_compensation=SYSTEM_SYNCHRONOUS
CSET pll_divclk_divide=2
CSET pll_notes=None
CSET pll_ref_jitter=0.010
CSET prim_in_freq=200.000
CSET prim_in_jitter=0.010
CSET prim_source=Differential_clock_capable_pin
CSET primtype_sel=PLL_BASE
CSET relative_inclk=REL_PRIMARY
CSET secondary_in_freq=100.000
CSET secondary_in_jitter=0.010
CSET secondary_source=Single_ended_clock_capable_pin
CSET summary_strings=empty
CSET use_clk_valid=false
CSET use_dyn_phase_shift=false
CSET use_dyn_reconfig=false
CSET use_freeze=false
CSET use_freq_synth=true
CSET use_inclk_stopped=false
CSET use_inclk_switchover=false
CSET use_locked=true
CSET use_max_i_jitter=false
CSET use_min_o_jitter=false
CSET use_min_power=false
CSET use_phase_alignment=true
CSET use_power_down=false
CSET use_reset=true
CSET use_spread_spectrum=false
CSET use_status=false
SHAR_EOF
(set 20 12 04 14 14 46 35 'FPGA_sources/dcm1.xco'
eval "${shar_touch}") && \
chmod 0644 'FPGA_sources/dcm1.xco'
if test $? -ne 0
then ${echo} "restore of FPGA_sources/dcm1.xco failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'FPGA_sources/dcm1.xco': 'MD5 check failed'
) << \SHAR_EOF
dc2e87409f4668a1984030da6af4c38b FPGA_sources/dcm1.xco
SHAR_EOF
else
test `LC_ALL=C wc -c < 'FPGA_sources/dcm1.xco'` -ne 6020 && \
${echo} "restoration warning: size of 'FPGA_sources/dcm1.xco' is not 6020"
fi
fi
# ============= FPGA_sources/dpram_inf.vhd ==============
if test -n "${keep_file}" && test -f 'FPGA_sources/dpram_inf.vhd'
then
${echo} "x - SKIPPING FPGA_sources/dpram_inf.vhd (file already exists)"
else
${echo} "x - extracting FPGA_sources/dpram_inf.vhd (text)"
sed 's/^X//' << 'SHAR_EOF' > 'FPGA_sources/dpram_inf.vhd' &&
-- A parameterized, inferable, true dual-port, common-clock block RAM in VHDL.
-- Original file was taken from:
http://danstrother.com/2010/09/11/inferring-rams-in-fpgas/
-- No license information were provided by the original author.
-- Minimal modifications were introduced by me to make it suitable for my FPGA
-- interface.
X
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
X
entity dp_ram_scl is
X generic (
X DATA_WIDTH : integer := 72;
X ADDR_WIDTH : integer := 10
X );
X port (
-- common clock
X clk : in std_logic;
X -- Port A
X we_a : in std_logic;
X addr_a : in std_logic_vector(ADDR_WIDTH-1 downto 0);
X data_a : in std_logic_vector(DATA_WIDTH-1 downto 0);
X q_a : out std_logic_vector(DATA_WIDTH-1 downto 0);
X
X -- Port B
X we_b : in std_logic;
X addr_b : in std_logic_vector(ADDR_WIDTH-1 downto 0);
X data_b : in std_logic_vector(DATA_WIDTH-1 downto 0);
X q_b : out std_logic_vector(DATA_WIDTH-1 downto 0)
X );
end dp_ram_scl;
X
architecture rtl of dp_ram_scl is
X -- Shared memory
X type mem_type is array ((2**ADDR_WIDTH)-1 downto 0) of std_logic_vector(DATA_WIDTH-1 downto 0);
X shared variable mem : mem_type;
begin
X
-- Port A
X process(clk)
X begin
X if(clk'event and clk = '1') then
X if(we_a = '1') then
X mem(conv_integer(addr_a)) := data_a;
X end if;
X q_a <= mem(conv_integer(addr_a));
X end if;
X end process;
X
-- Port B
X process(clk)
X begin
X if(clk'event and clk = '1') then
X if(we_b = '1') then
X mem(conv_integer(addr_b)) := data_b;
X end if;
X q_b <= mem(conv_integer(addr_b));
X end if;
X end process;
X
end rtl;
SHAR_EOF
(set 20 12 05 03 21 07 23 'FPGA_sources/dpram_inf.vhd'
eval "${shar_touch}") && \
chmod 0644 'FPGA_sources/dpram_inf.vhd'
if test $? -ne 0
then ${echo} "restore of FPGA_sources/dpram_inf.vhd failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'FPGA_sources/dpram_inf.vhd': 'MD5 check failed'
) << \SHAR_EOF
693cc876e30fd7c63f56129c379d850d FPGA_sources/dpram_inf.vhd
SHAR_EOF
else
test `LC_ALL=C wc -c < 'FPGA_sources/dpram_inf.vhd'` -ne 1665 && \
${echo} "restoration warning: size of 'FPGA_sources/dpram_inf.vhd' is not 1665"
fi
fi
# ============= FPGA_sources/ack_fifo.xco ==============
if test -n "${keep_file}" && test -f 'FPGA_sources/ack_fifo.xco'
then
${echo} "x - SKIPPING FPGA_sources/ack_fifo.xco (file already exists)"
else
${echo} "x - extracting FPGA_sources/ack_fifo.xco (text)"
sed 's/^X//' << 'SHAR_EOF' > 'FPGA_sources/ack_fifo.xco' &&
##############################################################
#
# Xilinx Core Generator version 13.4
# Date: Mon Apr 16 20:47:28 2012
#
##############################################################
#
# This file contains the customisation parameters for a
# Xilinx CORE Generator IP GUI. It is strongly recommended
# that you do not manually alter this file as it may cause
# unexpected and unsupported behavior.
#
##############################################################
#
# Generated from component: xilinx.com:ip:fifo_generator:6.2
#
##############################################################
#
# BEGIN Project Options
SET addpads = false
SET asysymbol = true
SET busformat = BusFormatAngleBracketNotRipped
SET createndf = false
SET designentry = VHDL
SET device = xc6slx16
SET devicefamily = spartan6
SET flowvendor = Foundation_ISE
SET formalverification = false
SET foundationsym = false
SET implementationfiletype = Ngc
SET package = csg324
SET removerpms = false
SET simulationfiles = Behavioral
SET speedgrade = -2
SET verilogsim = false
SET vhdlsim = true
# END Project Options
# BEGIN Select
SELECT Fifo_Generator family Xilinx,_Inc. 6.2
# END Select
# BEGIN Parameters
CSET almost_empty_flag=false
CSET almost_full_flag=false
CSET component_name=ack_fifo
CSET data_count=false
CSET data_count_width=11
CSET disable_timing_violations=false
CSET dout_reset_value=0
CSET empty_threshold_assert_value=4
CSET empty_threshold_negate_value=5
CSET enable_ecc=false
CSET enable_int_clk=false
CSET enable_reset_synchronization=true
CSET fifo_implementation=Common_Clock_Block_RAM
CSET full_flags_reset_value=0
CSET full_threshold_assert_value=1023
CSET full_threshold_negate_value=1022
CSET inject_dbit_error=false
CSET inject_sbit_error=false
CSET input_data_width=32
CSET input_depth=1024
CSET output_data_width=32
CSET output_depth=1024
CSET overflow_flag=false
CSET overflow_sense=Active_High
CSET performance_options=First_Word_Fall_Through
CSET programmable_empty_type=No_Programmable_Empty_Threshold
CSET programmable_full_type=No_Programmable_Full_Threshold
CSET read_clock_frequency=1
CSET read_data_count=false
CSET read_data_count_width=11
CSET reset_pin=true
CSET reset_type=Asynchronous_Reset
CSET underflow_flag=false
CSET underflow_sense=Active_High
CSET use_dout_reset=true
CSET use_embedded_registers=false
CSET use_extra_logic=true
CSET valid_flag=false
CSET valid_sense=Active_High
CSET write_acknowledge_flag=false
CSET write_acknowledge_sense=Active_High
CSET write_clock_frequency=1
CSET write_data_count=false
CSET write_data_count_width=11
# END Parameters
# BEGIN Extra information
MISC pkg_timestamp=2012-01-07T15:29:19Z
# END Extra information
GENERATE
# CRC: 2e8c307d
SHAR_EOF
(set 20 12 04 16 22 47 28 'FPGA_sources/ack_fifo.xco'
eval "${shar_touch}") && \
chmod 0644 'FPGA_sources/ack_fifo.xco'
if test $? -ne 0
then ${echo} "restore of FPGA_sources/ack_fifo.xco failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'FPGA_sources/ack_fifo.xco': 'MD5 check failed'
) << \SHAR_EOF
5a0c6ac677a5f13c69869c3f69386bb9 FPGA_sources/ack_fifo.xco
SHAR_EOF
else
test `LC_ALL=C wc -c < 'FPGA_sources/ack_fifo.xco'` -ne 2715 && \
${echo} "restoration warning: size of 'FPGA_sources/ack_fifo.xco' is not 2715"
fi
fi
# ============= FPGA_sources/sp601_eth.ucf ==============
if test -n "${keep_file}" && test -f 'FPGA_sources/sp601_eth.ucf'
then
${echo} "x - SKIPPING FPGA_sources/sp601_eth.ucf (file already exists)"
else
${echo} "x - extracting FPGA_sources/sp601_eth.ucf (text)"
sed 's/^X//' << 'SHAR_EOF' > 'FPGA_sources/sp601_eth.ucf' &&
NET "FLASH_CE_B" LOC = "L17"; ## 14 on U10
NET "FLASH_OE_B" LOC = "L18"; ## 54 on U10
NET "FLASH_WE_B" LOC = "M16"; ## 55 on U10
NET "GPIO_LED<0>" LOC = "E13"; ## 2 on DS11 LED
NET "GPIO_LED<1>" LOC = "C14"; ## 2 on DS12 LED
NET "GPIO_LED<2>" LOC = "C4"; ## 2 on DS13 LED
NET "GPIO_LED<3>" LOC = "A4"; ## 2 on DS14 LED
X
NET "SWITCHES<0>" LOC = "D14";
NET "SWITCHES<1>" LOC = "E12";
NET "SWITCHES<2>" LOC = "F12";
NET "SWITCHES<3>" LOC = "V13";
X
##
NET "CPU_RESET" LOC = "N4"; ## 2 on SW9 pushbutton
##
NET "PHY_COL" LOC = "L14"; ## 114 on U3
NET "PHY_CRS" LOC = "M13"; ## 115 on U3
NET "PHY_INT" LOC = "J13"; ## 32 on U3
NET "PHY_MDC" LOC = "N14"; ## 35 on U3
NET "PHY_MDIO" LOC = "P16"; ## 33 on U3
NET "PHY_RESET" LOC = "L13"; ## 36 on U3
NET "PHY_RXCLK" LOC = "L16"; ## 7 on U3
NET "PHY_RXCTL_RXDV" LOC = "N18"; ## 4 on U3
NET "PHY_RXD<0>" LOC = "M14"; ## 3 on U3
NET "PHY_RXD<1>" LOC = "U18"; ## 128 on U3
NET "PHY_RXD<2>" LOC = "U17"; ## 126 on U3
NET "PHY_RXD<3>" LOC = "T18"; ## 125 on U3
NET "PHY_RXD<4>" LOC = "T17"; ## 124 on U3
NET "PHY_RXD<5>" LOC = "N16"; ## 123 on U3
NET "PHY_RXD<6>" LOC = "N15"; ## 121 on U3
NET "PHY_RXD<7>" LOC = "P18"; ## 120 on U3
NET "PHY_RXER" LOC = "P17"; ## 8 on U3
NET "PHY_TXCLK" LOC = "B9"; ## 10 on U3
NET "PHY_TXCTL_TXEN" LOC = "B8"; ## 16 on U3
NET "PHY_TXC_GTXCLK" LOC = "A9"; ## 14 on U3
NET "PHY_TXD<0>" LOC = "F8"; ## 18 on U3
NET "PHY_TXD<1>" LOC = "G8"; ## 19 on U3
NET "PHY_TXD<2>" LOC = "A6"; ## 20 on U3
NET "PHY_TXD<3>" LOC = "B6"; ## 24 on U3
NET "PHY_TXD<4>" LOC = "E6"; ## 25 on U3
NET "PHY_TXD<5>" LOC = "F7"; ## 26 on U3
NET "PHY_TXD<6>" LOC = "A5"; ## 28 on U3
NET "PHY_TXD<7>" LOC = "C5"; ## 29 on U3
NET "PHY_TXER" LOC = "A8"; ## 13 on U3
##
NET "SYSCLK_N" LOC = "K16"; ## 5 on U5 EG2121CA, 5 of U20 SI500D (DNP)
NET "SYSCLK_P" LOC = "K15"; ## 6 on U5 EG2121CA, 4 of U20 SI500D (DNP)
##
#NET "FMC_LA28_N" LOC = "V11"; ## H32 on J1
#NET "FMC_LA28_P" LOC = "U11"; ## H31 on J1
#NET "FMC_LA29_N" LOC = "N8"; ## G31 on J1
#NET "FMC_LA29_P" LOC = "M8"; ## G30 on J1
#NET "FMC_LA30_N" LOC = "V12"; ## H35 on J1
#NET "FMC_LA30_P" LOC = "T12"; ## H34 on J1
#NET "FMC_LA31_N" LOC = "V6"; ## G34 on J1
#NET "FMC_LA31_P" LOC = "T6"; ## G33 on J1
#
NET "GPIO_HDR0" LOC = "N17"; ## 1 on J13 (thru series R100 200 ohm)
NET "GPIO_HDR1" LOC = "M18"; ## 3 on J13 (thru series R102 200 ohm)
NET "GPIO_HDR2" LOC = "A3"; ## 5 on J13 (thru series R101 200 ohm)
NET "GPIO_HDR3" LOC = "L15"; ## 7 on J13 (thru series R103 200 ohm)
NET "GPIO_HDR4" LOC = "F15"; ## 2 on J13 (thru series R99 200 ohm)
NET "GPIO_HDR5" LOC = "B4"; ## 4 on J13 (thru series R98 200 ohm)
NET "GPIO_HDR6" LOC = "F13"; ## 6 on J13 (thru series R97 200 ohm)
NET "GPIO_HDR7" LOC = "P12"; ## 8 on J13 (thru series R96 200 ohm)
#
NET "IIC_SCL_MAIN" LOC = "P11"; ## 6 on U7 (thru series R203 0 ohm), C30 on J1, 2 on J16
NET "IIC_SDA_MAIN" LOC = "N10"; ## 5 on U7 (thru series R204 0 ohm), C31 on J1, 1 on J16
#
PIN "dcm1_1/clkout1_buf.O" CLOCK_DEDICATED_ROUTE = FALSE;
X
#Created by Constraints Editor (xc6slx16-csg324-2) - 2010/08/04
NET "sysclk_p" TNM_NET = sysclk_p;
TIMESPEC TS_sysclk_p = PERIOD "sysclk_p" 5 ns HIGH 50%;
NET "sysclk_n" TNM_NET = sysclk_n;
TIMESPEC TS_sysclk_n = PERIOD "sysclk_n" 5 ns HIGH 50%;
#Created by Constraints Editor (xc6slx16-csg324-2) - 2012/04/30
NET "phy_rxclk" TNM_NET = phy_rxclk;
TIMESPEC TS_phy_rxclk = PERIOD "phy_rxclk" 8 ns HIGH 50%;
NET "phy_txclk" TNM_NET = phy_txclk;
TIMESPEC TS_phy_txclk = PERIOD "phy_txclk" 40 ns HIGH 50%;
NET "phy_txc_gtxclk" TNM_NET = phy_txc_gtxclk;
TIMESPEC TS_phy_txc_gtxclk = PERIOD "phy_txc_gtx_clk" 8 ns HIGH 50%;
SHAR_EOF
(set 20 12 05 03 21 15 08 'FPGA_sources/sp601_eth.ucf'
eval "${shar_touch}") && \
chmod 0644 'FPGA_sources/sp601_eth.ucf'
if test $? -ne 0
then ${echo} "restore of FPGA_sources/sp601_eth.ucf failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'FPGA_sources/sp601_eth.ucf': 'MD5 check failed'
) << \SHAR_EOF
bd23ca8a49b4a690e8d863939c542029 FPGA_sources/sp601_eth.ucf
SHAR_EOF
else
test `LC_ALL=C wc -c < 'FPGA_sources/sp601_eth.ucf'` -ne 4827 && \
${echo} "restoration warning: size of 'FPGA_sources/sp601_eth.ucf' is not 4827"
fi
fi
# ============= FPGA_sources/sp601_eth.prj ==============
if test -n "${keep_file}" && test -f 'FPGA_sources/sp601_eth.prj'
then
${echo} "x - SKIPPING FPGA_sources/sp601_eth.prj (file already exists)"
else
${echo} "x - extracting FPGA_sources/sp601_eth.prj (text)"
sed 's/^X//' << 'SHAR_EOF' > 'FPGA_sources/sp601_eth.prj' &&
verilog work "./eth/TECH/xilinx/duram.v"
verilog work "./eth/TECH/xilinx/CLK_SWITCH.v"
verilog work "./eth/TECH/xilinx/CLK_DIV2.v"
verilog work "./eth/RMON/RMON_dpram.v"
verilog work "./eth/RMON/RMON_ctrl.v"
verilog work "./eth/RMON/RMON_addr_gen.v"
verilog work "./eth/miim/eth_shiftreg.v"
verilog work "./eth/miim/eth_outputcontrol.v"
verilog work "./eth/miim/eth_clockgen.v"
verilog work "./eth/MAC_tx/Ramdon_gen.v"
verilog work "./eth/MAC_tx/MAC_tx_FF.v"
verilog work "./eth/MAC_tx/MAC_tx_Ctrl.v"
verilog work "./eth/MAC_tx/MAC_tx_addr_add.v"
verilog work "./eth/MAC_tx/flow_ctrl.v"
verilog work "./eth/MAC_tx/CRC_gen.v"
verilog work "./eth/MAC_rx/MAC_rx_FF.v"
verilog work "./eth/MAC_rx/MAC_rx_ctrl.v"
verilog work "./eth/MAC_rx/MAC_rx_add_chk.v"
verilog work "./eth/MAC_rx/CRC_chk.v"
verilog work "./eth/MAC_rx/Broadcast_filter.v"
verilog work "./eth/RMON.v"
verilog work "./eth/reg_int.v"
verilog work "./eth/Phy_int.v"
verilog work "./eth/MAC_tx.v"
verilog work "./eth/MAC_rx.v"
verilog work "./eth/eth_miim.v"
verilog work "./eth/Clk_ctrl.v"
verilog work "./eth/afifo.v"
vhdl work "./ack_fifo/pkt_ack_pkg.vhd"
vhdl work "./eth_sender.vhd"
vhdl work "./eth_receiver.vhd"
verilog work "./eth/MAC_top.v"
vhdl work "./dpram_inf.vhd"
vhdl work "./desc_manager_simple.vhd"
vhdl work "./dcm1.vhd"
vhdl work "./ack_fifo.vhd"
vhdl work "./sp601_eth_top.vhd"
SHAR_EOF
(set 20 12 05 03 22 17 54 'FPGA_sources/sp601_eth.prj'
eval "${shar_touch}") && \
chmod 0644 'FPGA_sources/sp601_eth.prj'
if test $? -ne 0
then ${echo} "restore of FPGA_sources/sp601_eth.prj failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'FPGA_sources/sp601_eth.prj': 'MD5 check failed'
) << \SHAR_EOF
aee47362ad8923b03b1fa3550c9190f3 FPGA_sources/sp601_eth.prj
SHAR_EOF
else
test `LC_ALL=C wc -c < 'FPGA_sources/sp601_eth.prj'` -ne 1358 && \
${echo} "restoration warning: size of 'FPGA_sources/sp601_eth.prj' is not 1358"
fi
fi
# ============= FPGA_sources/sp601_eth_top.vhd ==============
if test -n "${keep_file}" && test -f 'FPGA_sources/sp601_eth_top.vhd'
then
${echo} "x - SKIPPING FPGA_sources/sp601_eth_top.vhd (file already exists)"
else
${echo} "x - extracting FPGA_sources/sp601_eth_top.vhd (text)"
sed 's/^X//' << 'SHAR_EOF' > 'FPGA_sources/sp601_eth_top.vhd' &&
-------------------------------------------------------------------------------
-- Title : L3 FADE protocol demo for SP601 board
-- Project :
-------------------------------------------------------------------------------
-- File : sp601_eth_top.vhd
-- Author : Wojciech M. Zabolotny <
wz...@ise.pw.edu.pl>
-- License : BSD License
-- Company :
-- Created : 2010-08-03
-- Last update: 2012-05-03
-- Platform :
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description:
-- This file implements the top entity, integrating all component
-------------------------------------------------------------------------------
-- Copyright (c) 2012
-- This is public domain code!!!
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-08-03 1.0 wzab Created
-------------------------------------------------------------------------------
X
X
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.pkt_ack_pkg.all;
use work.desc_mgr_pkg.all;
X
entity sp601_eth is
X
X port (
X cpu_reset : in std_logic;
-- -- DDR2 interface
-- ddr2_a : out std_logic_vector(12 downto 0);
-- ddr2_ba : out std_logic_vector(2 downto 0);
-- ddr2_cas_b : out std_logic;
-- ddr2_cke : out std_logic;
-- ddr2_clk_n : out std_logic;
-- ddr2_clk_p : out std_logic;
-- ddr2_dq : inout std_logic_vector(15 downto 0);
-- ddr2_ldm : out std_logic;
-- ddr2_ldqs_n : out std_logic;
-- ddr2_ldqs_p : out std_logic;
-- ddr2_odt : out std_logic;
-- ddr2_ras_b : out std_logic;
-- ddr2_udm : out std_logic;
-- ddr2_udqs_n : out std_logic;
-- ddr2_udqs_p : out std_logic;
-- ddr2_we_b : out std_logic;
-- -- FLASH interface
-- flash_a : out std_logic_vector(24 downto 0);
X flash_ce_b : out std_logic;
-- flash_d : inout std_logic_vector(7 downto 0);
X flash_oe_b : out std_logic;
X flash_we_b : out std_logic;
-- -- FMC interface
-- fmc_la28_n : out std_logic;
-- fmc_la28_p : out std_logic;
-- fmc_la29_n : out std_logic;
-- fmc_la29_p : out std_logic;
-- fmc_la30_n : out std_logic;
-- fmc_la30_p : out std_logic;
-- fmc_la31_n : out std_logic;
-- fmc_la31_p : out std_logic;
X iic_scl_main : out std_logic;
X iic_sda_main : out std_logic;
X
X gpio_hdr0 : in std_logic;
X gpio_hdr1 : in std_logic;
X gpio_hdr2 : in std_logic;
X gpio_hdr3 : in std_logic;
X gpio_hdr4 : in std_logic;
X gpio_hdr5 : in std_logic;
X gpio_hdr6 : in std_logic;
X gpio_hdr7 : in std_logic;
X
-- fmc_clk0_m2c_n : out std_logic;
-- fmc_clk0_m2c_p : out std_logic;
-- fmc_clk1_m2c_n : out std_logic;
-- fmc_clk1_m2c_p : out std_logic;
-- fmc_la00_cc_n : out std_logic;
-- fmc_la00_cc_p : out std_logic;
-- fmc_la01_cc_n : out std_logic;
-- fmc_la01_cc_p : out std_logic;
-- fmc_la02_n : out std_logic;
-- fmc_la02_p : out std_logic;
-- fmc_la03_n : out std_logic;
-- fmc_la03_p : out std_logic;
-- fmc_la04_n : out std_logic;
-- fmc_la04_p : out std_logic;
-- led : out std_logic_vector(3 downto 0);
X switches : in std_logic_vector(3 downto 0);
-- flash_oen : out std_logic;
-- flash_wen : out std_logic;
-- flash_cen : out std_logic;
X gpio_led : out std_logic_vector(3 downto 0);
X -- PHY interface
X phy_col : in std_logic;
X phy_crs : in std_logic;
X phy_int : in std_logic;
X phy_mdc : out std_logic;
X phy_mdio : inout std_logic;
X phy_reset : out std_logic;
X phy_rxclk : in std_logic;
X phy_rxctl_rxdv : in std_logic;
X phy_rxd : in std_logic_vector(7 downto 0);
X phy_rxer : in std_logic;
X phy_txclk : in std_logic;
X phy_txctl_txen : out std_logic;
X phy_txc_gtxclk : out std_logic;
X phy_txd : out std_logic_vector(7 downto 0);
X phy_txer : out std_logic;
X sysclk_n : in std_logic;
X sysclk_p : in std_logic
X );
X
end sp601_eth;
X
architecture beh of sp601_eth is
X
X component dp_ram_scl
X generic (
X DATA_WIDTH : integer;
X ADDR_WIDTH : integer);
X port (
X clk : in std_logic;
X we_a : in std_logic;
X addr_a : in std_logic_vector(ADDR_WIDTH-1 downto 0);
X data_a : in std_logic_vector(DATA_WIDTH-1 downto 0);
X q_a : out std_logic_vector(DATA_WIDTH-1 downto 0);
X we_b : in std_logic;
X addr_b : in std_logic_vector(ADDR_WIDTH-1 downto 0);
X data_b : in std_logic_vector(DATA_WIDTH-1 downto 0);
X q_b : out std_logic_vector(DATA_WIDTH-1 downto 0));
X end component;
X
X component ack_fifo
X port (
X clk : in std_logic;
X rst : in std_logic;
X din : in std_logic_vector(pkt_ack_width-1 downto 0);
X wr_en : in std_logic;
X rd_en : in std_logic;
X dout : out std_logic_vector(pkt_ack_width-1 downto 0);
X full : out std_logic;
X empty : out std_logic);
X end component;
X
X component dcm1
X port
X ( -- Clock in ports
X CLK_IN1_P : in std_logic;
X CLK_IN1_N : in std_logic;
X -- Clock out ports
X CLK_OUT1 : out std_logic;
X CLK_OUT2 : out std_logic;
X CLK_OUT3 : out std_logic;
X -- Status and control signals
X RESET : in std_logic;
X LOCKED : out std_logic
X );
X end component;
X
X component desc_manager
X generic (
X N_OF_PKTS : integer);
X port (
X dta : in std_logic_vector(31 downto 0);
X dta_we : in std_logic;
X dta_ready : out std_logic;
X set_number : out unsigned(15 downto 0);
X pkt_number : out unsigned(15 downto 0);
X snd_start : out std_logic;
X snd_ready : in std_logic;
X dmem_addr : out std_logic_vector(13 downto 0);
X dmem_dta : out std_logic_vector(31 downto 0);
X dmem_we : out std_logic;
X ack_fifo_empty : in std_logic;
X ack_fifo_rd_en : out std_logic;
X ack_fifo_dout : in std_logic_vector(pkt_ack_width-1 downto 0);
X transmit_data : in std_logic;
X transm_delay : out unsigned(31 downto 0);
X clk : in std_logic;
X rst_n : in std_logic);
X end component;
X
X component eth_sender
X port (
X peer_mac : in std_logic_vector(47 downto 0);
X my_mac : in std_logic_vector(47 downto 0);
X my_ether_type : in std_logic_vector(15 downto 0);
X set_number : in unsigned(15 downto 0);
X pkt_number : in unsigned(15 downto 0);
X retry_number : in unsigned(15 downto 0);
X transm_delay : in unsigned(31 downto 0);
X clk : in std_logic;
X rst_n : in std_logic;
X ready : out std_logic;
X start : in std_logic;
X tx_mem_addr : out std_logic_vector(13 downto 0);
X tx_mem_data : in std_logic_vector(31 downto 0);
X Tx_mac_wa : in std_logic;
X Tx_mac_wr : out std_logic;
X Tx_mac_data : out std_logic_vector(31 downto 0);
X Tx_mac_BE : out std_logic_vector(1 downto 0);
X Tx_mac_sop : out std_logic;
X Tx_mac_eop : out std_logic);
X end component;
X
X component eth_receiver
X port (
X peer_mac : out std_logic_vector(47 downto 0);
X my_mac : in std_logic_vector(47 downto 0);
X my_ether_type : in std_logic_vector(15 downto 0);
X transmit_data : out std_logic;
X restart : out std_logic;
X ack_fifo_full : in std_logic;
X ack_fifo_wr_en : out std_logic;
X ack_fifo_din : out std_logic_vector(pkt_ack_width-1 downto 0);
X clk : in std_logic;
X rst_n : in std_logic;
X Rx_mac_pa : in std_logic;
X Rx_mac_ra : in std_logic;
X Rx_mac_rd : out std_logic;
X Rx_mac_data : in std_logic_vector(31 downto 0);
X Rx_mac_BE : in std_logic_vector(1 downto 0);
X Rx_mac_sop : in std_logic;
X Rx_mac_eop : in std_logic);
X end component;
X
X component jtag_bus_ctl
X generic (
X d_width : integer;
X a_width : integer);
X port (
X din : in std_logic_vector((d_width-1) downto 0);
X dout : out std_logic_vector((d_width-1) downto 0);
X addr : out std_logic_vector((a_width-1) downto 0);
X nwr : out std_logic;
X nrd : out std_logic);
X end component;
X
X component MAC_top
X port (
X --system signals
X Reset : in std_logic;
X Clk_125M : in std_logic;
X Clk_user : in std_logic;
X Clk_reg : in std_logic;
X Speed : out std_logic_vector(2 downto 0);
X --user interface
X Rx_mac_ra : out std_logic;
X Rx_mac_rd : in std_logic;
X Rx_mac_data : out std_logic_vector(31 downto 0);
X Rx_mac_BE : out std_logic_vector(1 downto 0);
X Rx_mac_pa : out std_logic;
X Rx_mac_sop : out std_logic;
X Rx_mac_eop : out std_logic;
X --user interface
X Tx_mac_wa : out std_logic;
X Tx_mac_wr : in std_logic;
X Tx_mac_data : in std_logic_vector(31 downto 0);
X Tx_mac_BE : in std_logic_vector(1 downto 0);
X Tx_mac_sop : in std_logic;
X Tx_mac_eop : in std_logic;
X -- pkg_lgth fifo
X Pkg_lgth_fifo_rd : in std_logic;
X Pkg_lgth_fifo_ra : out std_logic;
X Pkg_lgth_fifo_data : out std_logic_vector(15 downto 0);
X --Phy interface
X Gtx_clk : out std_logic; -- used only in GMII mode
X Rx_clk : in std_logic;
X Tx_clk : in std_logic; -- used only in MII mode
X Tx_er : out std_logic;
X Tx_en : out std_logic;
X Txd : out std_logic_vector(7 downto 0);
X Rx_er : in std_logic;
X Rx_dv : in std_logic;
X Rxd : in std_logic_vector(7 downto 0);
X Crs : in std_logic;
X Col : in std_logic;
X -- host interface
X CSB : in std_logic;
X WRB : in std_logic;
X CD_in : in std_logic_vector(15 downto 0);
X CD_out : out std_logic_vector(15 downto 0);
X CA : in std_logic_vector(7 downto 0);
X -- mdx
X Mdo : out std_logic; -- MII Management Data Output
X MdoEn : out std_logic; -- MII Management Data Output Enable
X Mdi : in std_logic;
X Mdc : out std_logic -- MII Management Data Clock
X );
X end component;
X
X signal my_mac : std_logic_vector(47 downto 0);
X constant my_ether_type : std_logic_vector(15 downto 0) := x"fade";
X signal transm_delay : unsigned(31 downto 0);
X signal restart : std_logic;
X signal dta : std_logic_vector(31 downto 0);
X signal dta_we : std_logic := '0';
X signal dta_ready : std_logic;
X signal snd_start : std_logic;
X signal snd_ready : std_logic;
X signal dmem_addr : std_logic_vector(13 downto 0);
X signal dmem_dta : std_logic_vector(31 downto 0);
X signal dmem_we : std_logic;
X signal addr_a, addr_b : integer;
X signal test_dta : unsigned(31 downto 0);
X signal tx_mem_addr : std_logic_vector(13 downto 0);
X signal tx_mem_data : std_logic_vector(31 downto 0);
X
X signal arg1, arg2, res1 : unsigned(7 downto 0);
X signal res2 : unsigned(15 downto 0);
X signal sender : std_logic_vector(47 downto 0);
X signal peer_mac : std_logic_vector(47 downto 0);
X signal inputs, din, dout : std_logic_vector(7 downto 0);
X signal addr, leds : std_logic_vector(3 downto 0);
X signal nwr, nrd, rst_p, rst_n, dcm_locked : std_logic;
X signal not_cpu_reset, rst_del : std_logic;
X
X signal set_number : unsigned(15 downto 0);
X signal pkt_number : unsigned(15 downto 0);
X signal retry_number : unsigned(15 downto 0) := (others => '0');
X signal start_pkt, stop_pkt : unsigned(7 downto 0) := (others => '0');
X
X
X signal ack_fifo_din, ack_fifo_dout : std_logic_vector(pkt_ack_width-1 downto 0);
X signal ack_fifo_wr_en, ack_fifo_rd_en, ack_fifo_empty, ack_fifo_full : std_logic;
X signal transmit_data : std_logic := '0';
X
X signal read_addr : std_logic_vector(15 downto 0);
X signal read_data : std_logic_vector(15 downto 0);
X signal read_done, read_in_progress : std_logic;
X
X
X signal led_counter : integer := 0;
X signal tx_counter : integer := 10000;
X signal sysclk : std_logic;
X signal Reset : std_logic;
X signal Clk_125M : std_logic;
X signal Clk_user : std_logic;
X signal Clk_reg : std_logic;
X signal Speed : std_logic_vector(2 downto 0);
X signal Rx_mac_ra : std_logic;
X signal Rx_mac_rd : std_logic;
X signal Rx_mac_data : std_logic_vector(31 downto 0);
X signal Rx_mac_BE : std_logic_vector(1 downto 0);
X signal Rx_mac_pa : std_logic;
X signal Rx_mac_sop : std_logic;
X signal Rx_mac_eop : std_logic;
X signal Tx_mac_wa : std_logic;
X signal Tx_mac_wr : std_logic;
X signal Tx_mac_data : std_logic_vector(31 downto 0);
X signal Tx_mac_BE : std_logic_vector(1 downto 0);
X signal Tx_mac_sop : std_logic;
X signal Tx_mac_eop : std_logic;
X signal Pkg_lgth_fifo_rd : std_logic;
X signal Pkg_lgth_fifo_ra : std_logic;
X signal Pkg_lgth_fifo_data : std_logic_vector(15 downto 0);
X signal Gtx_clk : std_logic;
X signal Rx_clk : std_logic;
X signal Tx_clk : std_logic;
X signal Tx_er : std_logic;
X signal Tx_en : std_logic;
X signal Txd : std_logic_vector(7 downto 0);
X signal Rx_er : std_logic;
X signal Rx_dv : std_logic;
X signal Rxd : std_logic_vector(7 downto 0);
X signal Crs : std_logic;
X signal Col : std_logic;
X signal CSB : std_logic := '1';
X signal WRB : std_logic := '1';
X signal CD_in : std_logic_vector(15 downto 0) := (others => '0');
X signal CD_out : std_logic_vector(15 downto 0) := (others => '0');
X signal CA : std_logic_vector(7 downto 0) := (others => '0');
X signal s_Mdo : std_logic;
X signal s_MdoEn : std_logic;
X signal s_Mdi : std_logic;
X
X signal s_dta_we : std_logic;
X
begin -- beh
X
X -- Allow selection of MAC with the DIP switch to allow testing
X -- with multiple boards!
X with switches(1 downto 0) select
X my_mac <=
X x"de_ad_ba_be_be_ef" when "00",
X x"de_ad_ba_be_be_e1" when "01",
X x"de_ad_ba_be_be_e2" when "10",
X x"de_ad_ba_be_be_e3" when "11";
X
X
X iic_sda_main <= 'Z';
X iic_scl_main <= 'Z';
X
X not_cpu_reset <= not cpu_reset;
X rst_p <= not rst_n;
X
X flash_oe_b <= '1';
X flash_we_b <= '1';
X flash_ce_b <= '1';
X
X MAC_top_1 : MAC_top
X port map (
X Reset => rst_p,
X Clk_125M => Clk_125M,
X Clk_user => Clk_user,
X Clk_reg => Clk_user, -- was Clk_reg
X Speed => Speed,
X Rx_mac_ra => Rx_mac_ra,
X Rx_mac_rd => Rx_mac_rd,
X Rx_mac_data => Rx_mac_data,
X Rx_mac_BE => Rx_mac_BE,
X Rx_mac_pa => Rx_mac_pa,
X Rx_mac_sop => Rx_mac_sop,
X Rx_mac_eop => Rx_mac_eop,
X Tx_mac_wa => Tx_mac_wa,
X Tx_mac_wr => Tx_mac_wr,
X Tx_mac_data => Tx_mac_data,
X Tx_mac_BE => Tx_mac_BE,
X Tx_mac_sop => Tx_mac_sop,
X Tx_mac_eop => Tx_mac_eop,
X Pkg_lgth_fifo_rd => Pkg_lgth_fifo_rd,
X Pkg_lgth_fifo_ra => Pkg_lgth_fifo_ra,
X Pkg_lgth_fifo_data => Pkg_lgth_fifo_data,
X Gtx_clk => PHY_TXC_Gtxclk,
X Rx_clk => PHY_Rxclk,
X Tx_clk => PHY_Txclk,
X Tx_er => PHY_Txer,
X Tx_en => PHY_TXCTL_Txen,
X Txd => PHY_Txd,
X Rx_er => PHY_Rxer,
X Rx_dv => PHY_RXCTL_Rxdv,
X Rxd => PHY_Rxd,
X Crs => PHY_Crs,
X Col => PHY_Col,
X -- Host interface
X CSB => CSB,
X WRB => WRB,
X CD_in => CD_in,
X CD_out => CD_out,
X CA => CA,
X -- MDI interface
X Mdo => s_Mdo,
X MdoEn => s_MdoEn,
X Mdi => s_Mdi,
X Mdc => PHY_Mdc);
X
X Pkg_lgth_fifo_rd <= Pkg_lgth_fifo_ra;
X
X addr_a <= to_integer(unsigned(dmem_addr));
X addr_b <= to_integer(unsigned(tx_mem_addr));
X
X dp_ram_scl_1 : dp_ram_scl
X generic map (
X DATA_WIDTH => 32,
X ADDR_WIDTH => 13)
X port map (
X clk => clk_user,
X we_a => dmem_we,
X addr_a => dmem_addr(12 downto 0),
X data_a => dmem_dta,
X q_a => open,
X we_b => '0',
X addr_b => tx_mem_addr(12 downto 0),
X data_b => (others => '0'),
X q_b => tx_mem_data);
X
X desc_manager_1 : desc_manager
X generic map (
X N_OF_PKTS => N_OF_PKTS)
X port map (
X dta => dta,
X dta_we => dta_we,
X dta_ready => dta_ready,
X set_number => set_number,
X pkt_number => pkt_number,
X snd_start => snd_start,
X snd_ready => snd_ready,
X dmem_addr => dmem_addr,
X dmem_dta => dmem_dta,
X dmem_we => dmem_we,
X ack_fifo_empty => ack_fifo_empty,
X ack_fifo_rd_en => ack_fifo_rd_en,
X ack_fifo_dout => ack_fifo_dout,
X transmit_data => transmit_data,
X transm_delay => transm_delay,
X clk => clk_user,
X rst_n => rst_n);
X
X eth_sender_1 : eth_sender
X port map (
X peer_mac => peer_mac,
X my_mac => my_mac,
X my_ether_type => my_ether_type,
X transm_delay => transm_delay,
X set_number => set_number,
X pkt_number => pkt_number,
X retry_number => retry_number,
X clk => clk_user,
X rst_n => rst_n,
X ready => snd_ready,
X start => snd_start,
X tx_mem_addr => tx_mem_addr,
X tx_mem_data => tx_mem_data,
X Tx_mac_wa => Tx_mac_wa,
X Tx_mac_wr => Tx_mac_wr,
X Tx_mac_data => Tx_mac_data,
X Tx_mac_BE => Tx_mac_BE,
X Tx_mac_sop => Tx_mac_sop,
X Tx_mac_eop => Tx_mac_eop);
X
X eth_receiver_1 : eth_receiver
X port map (
X peer_mac => peer_mac,
X my_mac => my_mac,
X my_ether_type => my_ether_type,
X restart => restart,
X transmit_data => transmit_data,
X ack_fifo_full => ack_fifo_full,
X ack_fifo_wr_en => ack_fifo_wr_en,
X ack_fifo_din => ack_fifo_din,
X clk => clk_user,
X rst_n => rst_n,
X Rx_mac_pa => Rx_mac_pa,
X Rx_mac_ra => Rx_mac_ra,
X Rx_mac_rd => Rx_mac_rd,
X Rx_mac_data => Rx_mac_data,
X Rx_mac_BE => Rx_mac_BE,
X Rx_mac_sop => Rx_mac_sop,
X Rx_mac_eop => Rx_mac_eop);
X
X dcm1_1 : dcm1
X port map (
X CLK_IN1_P => sysclk_P,
X CLK_IN1_N => sysclk_N,
X CLK_OUT1 => Clk_125M,
X CLK_OUT2 => Clk_user,
X CLK_OUT3 => Clk_reg,
X RESET => cpu_reset,
X LOCKED => dcm_locked);
X
X process (Clk_user, cpu_reset)
X begin -- process
X if cpu_reset = '1' then -- asynchronous reset (active low)
X rst_n <= '0';
X rst_del <= '0';
X elsif Clk_user'event and Clk_user = '1' then -- rising clock edge
X if restart = '1' then
X rst_n <= '0';
X rst_del <= '0';
X else
X if dcm_locked = '1' then
X rst_del <= '1';
X rst_n <= rst_del;
X end if;
X end if;
X end if;
X end process;
X
X -- reset
X
X phy_reset <= rst_n;
X
X -- Connection of MDI
X s_Mdi <= PHY_MDIO;
X PHY_MDIO <= 'Z' when s_MdoEn = '0' else s_Mdo;
X ack_fifo_1 : ack_fifo
X port map (
X clk => Clk_user,
X rst => rst_p,
X din => ack_fifo_din,
X wr_en => ack_fifo_wr_en,
X rd_en => ack_fifo_rd_en,
X dout => ack_fifo_dout,
X full => ack_fifo_full,
X empty => ack_fifo_empty);
X
X --E_TXD <= s_Txd(3 downto 0);
X --s_Rxd <= "0000" & E_RXD;
X
X -- signal generator
X
X dta <= std_logic_vector(test_dta);
X s_dta_we <= '1' when dta_ready = '1' and transmit_data = '1' else '0';
X dta_we <= s_dta_we;
X
X process (Clk_user, rst_n)
X begin -- process
X if rst_n = '0' then -- asynchronous reset (active low)
X test_dta <= (others => '0');
X elsif Clk_user'event and Clk_user = '1' then -- rising clock edge
X if s_dta_we = '1' then
X test_dta <= test_dta + 1;
X end if;
X end if;
X end process;
X
X -- gpio_led(1 downto 0) <= std_logic_vector(to_unsigned(led_counter, 2));
X gpio_led(0) <= snd_ready;
X gpio_led(1) <= transmit_data;
X gpio_led(2) <= cpu_reset;
X gpio_led(3) <= Tx_mac_wa;
end beh;
SHAR_EOF
(set 20 12 05 03 21 03 31 'FPGA_sources/sp601_eth_top.vhd'
eval "${shar_touch}") && \
chmod 0644 'FPGA_sources/sp601_eth_top.vhd'
if test $? -ne 0
then ${echo} "restore of FPGA_sources/sp601_eth_top.vhd failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'FPGA_sources/sp601_eth_top.vhd': 'MD5 check failed'
) << \SHAR_EOF
2d4dfe95b3a1b410b532b794c8859add FPGA_sources/sp601_eth_top.vhd
SHAR_EOF
else
test `LC_ALL=C wc -c < 'FPGA_sources/sp601_eth_top.vhd'` -ne 22288 && \
${echo} "restoration warning: size of 'FPGA_sources/sp601_eth_top.vhd' is not 22288"
fi
fi
# ============= FPGA_sources/desc_manager_simple.vhd ==============
if test -n "${keep_file}" && test -f 'FPGA_sources/desc_manager_simple.vhd'
then
${echo} "x - SKIPPING FPGA_sources/desc_manager_simple.vhd (file already exists)"
else
${echo} "x - extracting FPGA_sources/desc_manager_simple.vhd (text)"
sed 's/^X//' << 'SHAR_EOF' > 'FPGA_sources/desc_manager_simple.vhd' &&
-------------------------------------------------------------------------------
-- Title : FPGA Ethernet interface - descriptor manager
-- Project :
-------------------------------------------------------------------------------
-- File : desc_manager.vhd
-- Author : Wojciech M. Zabolotny (
wz...@ise.pw.edu.pl)
-- License : BSD License
-- Company :
-- Created : 2012-03-30
-- Last update: 2012-05-03
-- Platform :
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: This file implements the state machine, which manages the
-- table of packet descriptors, used to resend only not confirmed packets
-------------------------------------------------------------------------------
-- Copyright (c) 2012
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2012-03-30 1.0 WZab Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
use ieee.std_logic_textio.all;
library work;
use work.pkt_ack_pkg.all;
X
package desc_mgr_pkg is
X
X constant N_OF_PKTS : integer := 32;
X constant N_OF_SETS : integer := 65536;
X
X type T_PKT_DESC is record
X set : integer range 0 to N_OF_SETS-1; -- number of sets
X confirmed : std_logic;
X valid : std_logic;
X sent : std_logic;
X end record;
X
end desc_mgr_pkg;
X
X
X
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
library work;
use work.pkt_ack_pkg.all;
use work.desc_mgr_pkg.all;
X
-- The below implementation of the descriptor memory is awfull,
-- but seemed to be necessary to force XST to infer it as an
-- single port BRAM.
-- I simply provide vector long enough to accomodate my T_PKT_DESC
-- type, and hope that the synthesis tool (XST) will optimize out
-- unused bits.should be inferred as block memory (so be carefull
-- when modifying the below process)!
X
entity desc_memory is
X
X port (
X clk : in std_logic;
X desc_we : in std_logic;
X desc_addr : in integer range 0 to N_OF_PKTS-1;
X desc_out : in T_PKT_DESC;
X desc_in : out T_PKT_DESC);
X
end desc_memory;
X
architecture beh1 of desc_memory is
X
X type T_PKT_DESC_MEM is array (0 to N_OF_PKTS-1) of unsigned(22 downto 0);
X signal desc_mem : T_PKT_DESC_MEM := (others => (others => '0'));
X signal din : unsigned(22 downto 0) := (others => '0');
X signal dout : unsigned(22 downto 0) := (others => '0');
X signal rdaddr : integer range 0 to N_OF_PKTS-1;
X
begin -- beh1
X
X process (desc_out, dout)
X begin -- process
X din <= (others => '0');
X din(22) <= desc_out.valid;
X din(21) <= desc_out.confirmed;
X din(20) <= desc_out.sent;
X din(19 downto 0) <= to_unsigned(desc_out.set, 20);
X desc_in.valid <= dout(22);
X desc_in.confirmed <= dout(21);
X desc_in.sent <= dout(20);
X desc_in.set <= to_integer(dout(19 downto 0));
X end process;
X
X process (clk)
X begin -- process
X if (clk'event and clk = '1') then -- rising clock edge
X if (desc_we = '1') then
X desc_mem(desc_addr) <= din;
X end if;
X rdaddr <= desc_addr;
X end if;
X end process;
X dout <= desc_mem(rdaddr);
X
end beh1;
X
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
library work;
use work.pkt_ack_pkg.all;
use work.desc_mgr_pkg.all;
X
entity desc_manager is
X
X generic (
X N_OF_PKTS : integer := 64); -- Number of packet_logi buffers
X
X port (
X -- Data input interface
X dta : in std_logic_vector(31 downto 0);
X dta_we : in std_logic;
X dta_ready : out std_logic;
X -- ETH Sender interface
X set_number : out unsigned(15 downto 0);
X pkt_number : out unsigned(15 downto 0);
X snd_start : out std_logic;
X snd_ready : in std_logic;
X
X -- Data memory interface
X dmem_addr : out std_logic_vector(13 downto 0);
X dmem_dta : out std_logic_vector(31 downto 0);
X dmem_we : out std_logic;
X -- Interface to the ACK FIFO
X ack_fifo_empty : in std_logic;
X ack_fifo_rd_en : out std_logic;
X ack_fifo_dout : in std_logic_vector(pkt_ack_width-1 downto 0);
X
X --
X transmit_data : in std_logic;
X transm_delay : out unsigned(31 downto 0);
X
X --
X clk : in std_logic;
X rst_n : in std_logic);
X
end desc_manager;
X
architecture dmgr_a1 of desc_manager is
X
X constant PKT_CNT_MAX : integer := 10000;
X
X -- To simplify description of state machines, all registers are grouped
X -- in a record:
X
X type T_DESC_MGR_REGS is record
X set : integer range 0 to N_OF_SETS-1;
X cur_set : integer range 0 to N_OF_SETS-1;
X all_pkt_count : integer range 0 to PKT_CNT_MAX;
X retr_pkt_count : integer range 0 to PKT_CNT_MAX;
X retr_delay : unsigned(31 downto 0);
X transm_delay : unsigned(31 downto 0);
X nxt : integer range 0 to N_OF_PKTS-1;
X tail_ptr : integer range 0 to N_OF_PKTS-1;
X head_ptr : integer range 0 to N_OF_PKTS-1;
X retr_ptr : integer range 0 to N_OF_PKTS-1; -- buffer, which is retransmitted
X -- when equal to head_ptr -
X -- retransmission is finished
X retr_nxt : integer range 0 to N_OF_PKTS-1; -- buffer, which will be
X -- retransmitted next
X -- when equal to head_ptr -- no retransmission
X -- is performed
X end record;
X
X constant DESC_MGR_REGS_INI : T_DESC_MGR_REGS := (
X retr_delay => (others => '0'),
X transm_delay => to_unsigned(10000, 32),
X all_pkt_count => 0,
X retr_pkt_count => 0,
X set => 0,
X cur_set => 0,
X nxt => 0,
X tail_ptr => 0,
X head_ptr => 0,
X retr_ptr => 0,
X retr_nxt => 0
X );
X
X -- To simplify setting of outputs of my Mealy state machine, all combinatorial
X -- outputs are grouped in a record
X type T_DESC_MGR_COMB is record
X dta_buf_free : std_logic;
X desc_addr : integer range 0 to N_OF_PKTS-1;
X desc_we : std_logic;
X ack_rd : std_logic;
X snd_start : std_logic;
X desc_out : T_PKT_DESC;
X end record;
X
X constant DESC_MGR_COMB_DEFAULT : T_DESC_MGR_COMB := (
X dta_buf_free => '0',
X desc_addr => 0,
X desc_we => '0',
X ack_rd => '0',
X snd_start => '0',
X desc_out => (confirmed => '0', valid => '0', sent => '0', set => 0)
X );
X
X type T_DESC_MGR_STATE is (ST_DMGR_IDLE, ST_DMGR_START, ST_DMGR_RST, ST_DMGR_RST1,
X ST_DMGR_ACK1, ST_DMGR_INS1, ST_DMGR_INS2, ST_DMGR_ACK_TAIL,
X ST_DMGR_ACK_TAIL_1,
X ST_DMGR_RETR, ST_DMGR_RETR_2);
X
X signal desc_in : T_PKT_DESC;
X
X signal r, r_i : T_DESC_MGR_REGS := DESC_MGR_REGS_INI;
X signal c : T_DESC_MGR_COMB;
X signal dmgr_state, dmgr_state_next : T_DESC_MGR_STATE := ST_DMGR_RST;
X attribute keep : string;
X attribute keep of dmgr_state : signal is "true";
X
X signal dta_buf_full : std_logic := '0';
X
X signal ack_pkt_in : pkt_ack;
X
X signal wrd_addr : integer range 0 to 255;
X
X component desc_memory
X port (
X clk : in std_logic;
X desc_we : in std_logic;
X desc_addr : in integer range 0 to N_OF_PKTS-1;
X desc_out : in T_PKT_DESC;
X desc_in : out T_PKT_DESC);
X end component;
X
X
begin -- dmgr_a1
X
X transm_delay <= r.transm_delay;
X set_number <= to_unsigned(r.set, 16);
X pkt_number <= to_unsigned(r.retr_ptr, 16);
X dta_ready <= not dta_buf_full;
X snd_start <= c.snd_start;
X ack_fifo_rd_en <= c.ack_rd;
X
X ack_pkt_in <= stlv_to_pkt_ack(ack_fifo_dout);
X
X
X -- Packet descriptors are stored in the desc_memory
X
X desc_memory_1 : desc_memory
X port map (
X clk => clk,
X desc_we => c.desc_we,
X desc_addr => c.desc_addr,
X desc_out => c.desc_out,
X desc_in => desc_in);
X
X -- Process used to fill the buffer memory with the data to be transmitted
X -- We simply write words to the memory buffer pointed by r.head_ptr
X -- When we write the last (0xff-th) word, we signal that the buffer
X -- is full. Only after reception of
X dta_rcv : process (clk, rst_n)
X begin -- process dta_rcv
X if rst_n = '0' then -- asynchronous reset (active low)
X wrd_addr <= 0;
X dta_buf_full <= '0';
X dmem_we <= '0';
X elsif clk'event and clk = '1' then -- rising clock edge
X dmem_we <= '0';
X -- if we signalled "data full", we are only waiting for
X -- dta_buf_free;
X if dta_buf_full = '1' then
X if c.dta_buf_free = '1' then
X dta_buf_full <= '0';
X wrd_addr <= 0;
X end if;
X else
X -- if data write requested - write it
X if dta_we = '1' then
X dmem_addr <= std_logic_vector(to_unsigned(r.head_ptr, 6)) &
X std_logic_vector(to_unsigned(wrd_addr, 8));
X dmem_we <= '1';
X dmem_dta <= dta;
X if wrd_addr < 255 then
X wrd_addr <= wrd_addr + 1;
X else
X dta_buf_full <= '1';
X end if;
X end if;
X end if;
X end if;
X end process dta_rcv;
X
X
X c1 : process (ack_fifo_empty, ack_pkt_in, desc_in, dmgr_state, dta_buf_full,
X r, snd_ready)
X begin -- process c1
X c <= DESC_MGR_COMB_DEFAULT; -- set defaults
X r_i <= r; -- avoid latches
X
X if r.retr_delay /= to_unsigned(0, r.retr_delay'length) then
X r_i.retr_delay <= r.retr_delay-1;
X end if;
X dmgr_state_next <= dmgr_state;
X -- State machine
X case dmgr_state is
X when ST_DMGR_RST =>
X dmgr_state_next <= ST_DMGR_RST1;
X when ST_DMGR_RST1 =>
X -- We should initialize the 0th position of list descriptors
X c.desc_addr <= r.head_ptr;
X c.desc_out <= desc_in;
X c.desc_out.confirmed <= '0';
X c.desc_out.valid <= '0';
X c.desc_out.sent <= '0';
X c.desc_out.set <= 0;
X c.desc_we <= '1';
X dmgr_state_next <= ST_DMGR_IDLE;
X when ST_DMGR_IDLE =>
X -- First we check, if there are any packets to acknowledge
X if ack_fifo_empty = '0' then
X -- Read the description of the acknowledged packet
X c.desc_addr <= to_integer(ack_pkt_in.pkt);
X dmgr_state_next <= ST_DMGR_ACK1;
X elsif dta_buf_full = '1' then
X -- We should handle reception of data.
X -- If the previously filled buffer is full, pass it for transmission,
X -- and allocate the next one.
X --
X -- Calculate the number of the packet, which shoud be the next "head"
X -- packet.
X if r.head_ptr = N_OF_PKTS-1 then
X r_i.nxt <= 0;
X else
X r_i.nxt <= r.head_ptr + 1;
X end if;
X -- Prepare for reading of the current "head" descriptor
X c.desc_addr <= r.head_ptr;
X dmgr_state_next <= ST_DMGR_INS1;
X elsif (r.tail_ptr /= r.head_ptr) and (r.retr_delay = to_unsigned(0, r.retr_delay'length)) then
X -- We need to (re)transmit some buffers
X -- prepare reading of the descriptor, which should be transmitted
X c.desc_addr <= r.retr_nxt;
X dmgr_state_next <= ST_DMGR_RETR;
X end if;
X when ST_DMGR_INS1 =>
X -- First we check, if there is free space, r.nxt is the number of the
X -- future head packet.
X if (r.nxt = r.tail_ptr) then
X -- No free place! The packet, which we would like to fill is still
X -- occupied.
X -- Return to idle, waiting until something is freed.
X -- In this case we should also force retransmission
X if r.retr_delay = 0 then
X c.desc_addr <= r.retr_nxt;
X dmgr_state_next <= ST_DMGR_RETR;
X else
X dmgr_state_next <= ST_DMGR_IDLE;
X end if;
X else
X -- We can fill the next buffer
X -- First we mark the previous head packet
X -- as valid and not confirmed
X c.desc_addr <= r.head_ptr;
X c.desc_out <= desc_in;
X c.desc_out.confirmed <= '0';
X c.desc_out.valid <= '1';
X c.desc_we <= '1';
X -- Now we move the "head" pointer
X r_i.head_ptr <= r.nxt;
X -- Increase the set number if we wrapped around
X if r.nxt = 0 then
X if r.cur_set = N_OF_SETS-1 then
X r_i.cur_set <= 0;
X else
X r_i.cur_set <= r.cur_set + 1;
X end if;
X end if;
X dmgr_state_next <= ST_DMGR_INS2;
X end if;
X when ST_DMGR_INS2 =>
X -- We fill the new head descriptor
X c.desc_addr <= r.head_ptr;
X c.desc_out.set <= r.cur_set;
X c.desc_out.confirmed <= '0';
X c.desc_out.valid <= '0';
X c.desc_out.sent <= '0';
X c.desc_we <= '1';
X -- Signal, that the buffer is freed
X c.dta_buf_free <= '1';
X dmgr_state_next <= ST_DMGR_IDLE;
X when ST_DMGR_ACK1 =>
X -- In this state the desc memory should respond with the data of the
X -- buffered packet, so we can state, if this packet is really correctly
X -- acknowledged
X if (ack_pkt_in.set = desc_in.set) and
X (desc_in.valid = '1') then
X -- This is really correct, unconfirmed packet
X -- Increase the counter of not-repeated ACK packets
X -- Write the confirmation
X c.desc_addr <= to_integer(ack_pkt_in.pkt);
X c.desc_out <= desc_in;
X c.desc_out.valid <= '0';
X c.desc_out.confirmed <= '1';
X c.desc_we <= '1';
X -- Here we also handle the case, if the acknowledged packet was
X -- the one which is now scheduled for retransmission...
X if ack_pkt_in.pkt = r.retr_nxt then
X if r.retr_nxt < N_OF_PKTS-1 then
X r_i.retr_nxt <= r.retr_nxt + 1;
X else
X r_i.retr_nxt <= 0;
X end if;
X end if;
X -- Check, if we need to update the "tail" pointer
X if r.tail_ptr = ack_pkt_in.pkt then
X c.ack_rd <= '1';
X dmgr_state_next <= ST_DMGR_ACK_TAIL;
X else
X c.ack_rd <= '1';
X dmgr_state_next <= ST_DMGR_IDLE;
X end if;
X else
X -- This packet was already confirmed
X -- just flush the ack_fifo
X c.ack_rd <= '1';
X dmgr_state_next <= ST_DMGR_IDLE;
X end if;
X when ST_DMGR_ACK_TAIL =>
X c.desc_addr <= r.tail_ptr;
X dmgr_state_next <= ST_DMGR_ACK_TAIL_1;
X when ST_DMGR_ACK_TAIL_1 =>
X -- In this state we update the "tail" pointer if necessary
X if r.tail_ptr /= r.head_ptr then
X if desc_in.confirmed = '1' then
X if r.tail_ptr < N_OF_PKTS-1 then
X r_i.tail_ptr <= r.tail_ptr + 1;
X c.desc_addr <= r.tail_ptr + 1;
X else
X r_i.tail_ptr <= 0;
X c.desc_addr <= 0;
X end if;
X -- We remain in that state, to check the next packet descriptor
X else
X -- We return to idle
X dmgr_state_next <= ST_DMGR_IDLE;
X end if;
X else
X -- Buffer is empty - return to idle
X dmgr_state_next <= ST_DMGR_IDLE;
X end if;
X when ST_DMGR_RETR =>
X -- Here we handle the transmission of a new packet,
X -- retransmission of not confirmed packet
X -- We must be sure, that the transmitter is ready
X if snd_ready = '0' then
X -- transmitter not ready, return to idle
X dmgr_state_next <= ST_DMGR_IDLE;
X else
X -- We will be able to send the next packet, but let's check if
X -- this is not the currently filled packet
X if r.retr_nxt = r.head_ptr then
X -- All packets (re)transmitted, go to the begining of the list
X -- and return to idle.
X r_i.retr_nxt <= r.tail_ptr;
X dmgr_state_next <= ST_DMGR_IDLE;
X else
X -- before jumping to ST_DMGR_RETR, the address bus
X -- was set to the address of r.retr_nxt, so now
X -- we can read the descriptor, and check if the packet
X -- needs to be retransmitted at all...
X r_i.set <= desc_in.set;
X r_i.retr_ptr <= r.retr_nxt;
X if r.retr_nxt < N_OF_PKTS-1 then
X r_i.retr_nxt <= r.retr_nxt + 1;
X else
X r_i.retr_nxt <= 0;
X end if;
X if desc_in.valid = '1' and desc_in.confirmed = '0' then
X if desc_in.sent = '1' then
X -- Increase count of retransmitted packets for
X -- adaptive adjustment of delay
X if r.retr_pkt_count < PKT_CNT_MAX then
X r_i.retr_pkt_count <= r.retr_pkt_count + 1;
X end if;
X end if;
X -- Increase count of all packets for adaptive adjustment
X -- of delay
X if r.all_pkt_count < PKT_CNT_MAX then
X r_i.all_pkt_count <= r.all_pkt_count + 1;
X end if;
X -- Mark the packet as sent
X c.desc_addr <= r.retr_nxt;
X c.desc_out <= desc_in;
X c.desc_out.sent <= '1';
X c.desc_we <= '1';
X dmgr_state_next <= ST_DMGR_RETR_2;
X else
X dmgr_state_next <= ST_DMGR_IDLE;
X end if;
X end if;
X end if;
X when ST_DMGR_RETR_2 =>
X -- In this state, we simply trigger the sender!
X c.snd_start <= '1';
X r_i.retr_delay <= r.transm_delay;
X -- And we update the delay using the packet statistics
X -- You may change the constants used in expressions
X -- below to change speed of adjustment
X if r.all_pkt_count >= PKT_CNT_MAX then
X if r.retr_pkt_count < PKT_CNT_MAX/32 then
X if r.transm_delay > 32 then
X r_i.transm_delay <= r.transm_delay-r.transm_delay/4;
X end if;
X elsif r.retr_pkt_count > PKT_CNT_MAX/8 then
X if r.transm_delay < 1000000 then
X r_i.transm_delay <= r.transm_delay+r.transm_delay/4;
X end if;
X end if;
X r_i.all_pkt_count <= 0;
X r_i.retr_pkt_count <= 0;
X end if;
X dmgr_state_next <= ST_DMGR_IDLE;
X when others => null;
X end case;
X end process c1;
X
-- Synchronous process
X process (clk, rst_n)
X begin -- process
X if rst_n = '0' then -- asynchronous reset (active low)
X r <= DESC_MGR_REGS_INI;
X dmgr_state <= ST_DMGR_RST;
X elsif clk'event and clk = '1' then -- rising clock edge
X r <= r_i;
X dmgr_state <= dmgr_state_next;
X end if;
X end process;
X
-- Process debugging the descriptors memory - for simulation only!
X process (clk, rst_n)
X variable L : line;
X begin -- process
X if rst_n = '0' then -- asynchronous reset (active low)
X null;
X elsif clk'event and clk = '1' then -- rising clock edge
X if c.desc_we = '1' then
X write(L, string'("nr="));
X write(L, c.desc_addr);
X write(L, string'(" set="));
X write(L, c.desc_out.set);
X write(L, string'(" valid="));
X --write(L,c.desc_out.valid);
X if c.desc_out.valid = '1' then
X write(L, string'("1"));
X else
X write(L, string'("0"));
X end if;
X write(L, string'(" confirmed="));
X --write(L,c.desc_out.valid);
X if c.desc_out.confirmed = '1' then
X write(L, string'("1"));
X else
X write(L, string'("0"));
X end if;
X write(L, string'(" r.tail="));
X write(L, r.tail_ptr);
X write(L, string'(" r.head="));
X write(L, r.head_ptr);
X writeline(output, L);
X end if;
X end if;
X end process;
X
end dmgr_a1;
X
X
X
SHAR_EOF
(set 20 12 05 03 21 21 53 'FPGA_sources/desc_manager_simple.vhd'
eval "${shar_touch}") && \
chmod 0644 'FPGA_sources/desc_manager_simple.vhd'
if test $? -ne 0
then ${echo} "restore of FPGA_sources/desc_manager_simple.vhd failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'FPGA_sources/desc_manager_simple.vhd': 'MD5 check failed'
) << \SHAR_EOF
518e6f1d2118c9fdb5fb210da502c31f FPGA_sources/desc_manager_simple.vhd
SHAR_EOF
else
test `LC_ALL=C wc -c < 'FPGA_sources/desc_manager_simple.vhd'` -ne 20479 && \
${echo} "restoration warning: size of 'FPGA_sources/desc_manager_simple.vhd' is not 20479"
fi
fi
# ============= linux_driver_and_application/receiver2.c ==============
if test ! -d 'linux_driver_and_application'; then
mkdir 'linux_driver_and_application'
if test $? -eq 0
then ${echo} "x - created directory linux_driver_and_application."
else ${echo} "x - failed to create directory linux_driver_and_application."
exit 1
fi
fi
if test -n "${keep_file}" && test -f 'linux_driver_and_application/receiver2.c'
then
${echo} "x - SKIPPING linux_driver_and_application/receiver2.c (file already exists)"
else
${echo} "x - extracting linux_driver_and_application/receiver2.c (text)"
sed 's/^X//' << 'SHAR_EOF' > 'linux_driver_and_application/receiver2.c' &&
/*
X * fpga_l3_fade - driver for L3 communication protocol with FPGA based system
X * Copyright (C) 2012 by Wojciech M. Zabolotny
X * Institute of Electronic Systems, Warsaw University of Technology
X *
X * This code is PUBLIC DOMAIN
X */
X
#include<termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <poll.h>
#include <unistd.h>
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
#include <stdint.h>
X
#include <sys/socket.h>
#include <linux/serial.h>
#include "fpga_l3_fade.h"
X
void main()
{
X struct l3_v1_buf_pointers bp;
X struct l3_v1_slave sl = {
X .mac = {0xde, 0xad, 0xba, 0xbe, 0xbe,0xef},
X .devname = "eth0"
X };
X int res, blen;
X int data = 0;
X unsigned char * v;
X int frs=open("/dev/l3_fpga0",O_RDONLY);
X blen = ioctl(frs,L3_V1_IOC_GETBUFLEN,NULL);
X res=ioctl(frs,L3_V1_IOC_SETWAKEUP,2000000);
X printf("length of buffer: %d, result of set wakeup: %d\n",blen,res);
X v=(unsigned char *)mmap(0,blen,PROT_READ,MAP_PRIVATE,frs,0);
X if(!v) {
X printf("mmap failed\n");
X exit(1);
X }
X //Start the transmission
X res = ioctl(frs,L3_V1_IOC_STARTMAC,&sl);
X printf("Result of ster: %d\n",res);
X do{
X struct pollfd pfd[1] = {{.fd = frs, .events = POLLIN, .revents = 0}};
X int ptr=0;
X int len=0;
X int pres;
X //Wait for data using "poll"
X pres = poll(pfd,1,-1);
X if(pres<0) {
X perror("Error in poll:");
X exit(1);
X }
X len = ioctl(frs,L3_V1_IOC_READPTRS,&bp);
X printf("len=%d head:%d tail: %d\n",len,bp.head, bp.tail);
X //OK. The data are read, let's analyze them
X while (bp.head != bp.tail) {
X uint32_t c;
X c = *(uint32_t *)(v+bp.tail);
X c = ntohl(c);
X bp.tail=(bp.tail+1) & (blen-1);
X bp.tail=(bp.tail+1) & (blen-1);
X bp.tail=(bp.tail+1) & (blen-1);
X bp.tail=(bp.tail+1) & (blen-1);
X if(c != data) {
X printf("odebrane: %8.8x oczekiwane: %8.8x \n",c,data);
X exit(1);
X }
X data ++;
X }
X //printf("\n");
X fflush(stdout);
X //Confirm reception of data
X ioctl(frs,L3_V1_IOC_WRITEPTRS,len);
X sleep(1);
X } while (1);
X //fo=fopen("data.bin","w");
X //fwrite(v,i,1,fo);
X //fclose(fo);
}
SHAR_EOF
(set 20 12 05 03 22 04 09 'linux_driver_and_application/receiver2.c'
eval "${shar_touch}") && \
chmod 0646 'linux_driver_and_application/receiver2.c'
if test $? -ne 0
then ${echo} "restore of linux_driver_and_application/receiver2.c failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'linux_driver_and_application/receiver2.c': 'MD5 check failed'
) << \SHAR_EOF
5e9a5d7eb375da458f079359781acbe7 linux_driver_and_application/receiver2.c
SHAR_EOF
else
test `LC_ALL=C wc -c < 'linux_driver_and_application/receiver2.c'` -ne 2196 && \
${echo} "restoration warning: size of 'linux_driver_and_application/receiver2.c' is not 2196"
fi
fi
# ============= linux_driver_and_application/fpga_l3_fade.h ==============
if test ! -d 'linux_driver_and_application'; then
mkdir 'linux_driver_and_application'
if test $? -eq 0
then ${echo} "x - created directory linux_driver_and_application."
else ${echo} "x - failed to create directory linux_driver_and_application."
exit 1
fi
fi
if test -n "${keep_file}" && test -f 'linux_driver_and_application/fpga_l3_fade.h'
then
${echo} "x - SKIPPING linux_driver_and_application/fpga_l3_fade.h (file already exists)"
else
${echo} "x - extracting linux_driver_and_application/fpga_l3_fade.h (text)"
sed 's/^X//' << 'SHAR_EOF' > 'linux_driver_and_application/fpga_l3_fade.h' &&
/*
X * fpga_l3_fade - header for L3 communication protocol with FPGA based system
X * Copyright (C) 2012 by Wojciech M. Zabolotny
X * Institute of Electronic Systems, Warsaw University of Technology
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
X *
X * Additionally I (Wojciech Zabolotny) allow you to include this header file
X * to compile your closed source applications (however yo should check, that
X * license terms of other include files used by this one allow you to do it...).
X */
X
#ifndef _FPGA_L3_FADE_H_
X
X
#include <linux/socket.h>
#include <linux/if_ether.h>
#include <linux/if.h>
X
struct l3_v1_buf_pointers {
X int head;
X int tail;
} __attribute__ ((__packed__));
X
struct l3_v1_slave {
X unsigned char mac[ETH_ALEN];
X char devname[IFNAMSIZ];
} __attribute__ ((__packed__));
X
#define L3_V1_IOC_MAGIC 0xa5
X
#define L3_V1_IOC_SETWAKEUP _IO(L3_V1_IOC_MAGIC,0x30)
#define L3_V1_IOC_GETBUFLEN _IO(L3_V1_IOC_MAGIC,0x31)
#define L3_V1_IOC_READPTRS _IOR(L3_V1_IOC_MAGIC,0x32,struct l3_v1_buf_pointers)
#define L3_V1_IOC_WRITEPTRS _IO(L3_V1_IOC_MAGIC,0x33)
#define L3_V1_IOC_STARTMAC _IOW(L3_V1_IOC_MAGIC,0x34,struct l3_v1_slave)
#define L3_V1_IOC_STOPMAC _IO(L3_V1_IOC_MAGIC,0x35)
X
/* Error flags */
#define FADE_ERR_INCORRECT_PACKET_TYPE (1<<0)
#define FADE_ERR_INCORRECT_SET (1<<1)
#define FADE_ERR_INCORRECT_LENGTH (1<<2)
X
X
X
#define _FPGA_L3_FADE_H_
#endif
SHAR_EOF
(set 20 12 05 03 22 03 49 'linux_driver_and_application/fpga_l3_fade.h'
eval "${shar_touch}") && \
chmod 0644 'linux_driver_and_application/fpga_l3_fade.h'
if test $? -ne 0
then ${echo} "restore of linux_driver_and_application/fpga_l3_fade.h failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'linux_driver_and_application/fpga_l3_fade.h': 'MD5 check failed'
) << \SHAR_EOF
04511529477daf6f50ec126adee96703 linux_driver_and_application/fpga_l3_fade.h
SHAR_EOF
else
test `LC_ALL=C wc -c < 'linux_driver_and_application/fpga_l3_fade.h'` -ne 2075 && \
${echo} "restoration warning: size of 'linux_driver_and_application/fpga_l3_fade.h' is not 2075"
fi
fi
# ============= linux_driver_and_application/fpga_l3_fade.c ==============
if test -n "${keep_file}" && test -f 'linux_driver_and_application/fpga_l3_fade.c'
then
${echo} "x - SKIPPING linux_driver_and_application/fpga_l3_fade.c (file already exists)"
else
${echo} "x - extracting linux_driver_and_application/fpga_l3_fade.c (text)"
sed 's/^X//' << 'SHAR_EOF' > 'linux_driver_and_application/fpga_l3_fade.c' &&
/*
X * fpga_l3_fade - driver for L3 communication protocol with FPGA based system
X * Copyright (C) 2012 by Wojciech M. Zabolotny
X * Institute of Electronic Systems, Warsaw University of Technology
X *
X * This program is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 2 of the License, or
X * (at your option) any later version.
X *
X * This program is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with this program; if not, write to the Free Software
X * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
X */
X
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/uaccess.h>
X
MODULE_LICENSE("GPL v2");
X
#include <linux/device.h>
#include <linux/netdevice.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/poll.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <asm/uaccess.h> /* for put_user */
X
#include "fpga_l3_fade.h"
X
#define SUCCESS 0
#define DEVICE_NAME "fpga_l3_fade"
X
/* Maximum number of packets' set (the set counter will wrap
X * after this number is reached) should be power of two!*/
#define SET_NUMBER (1<<16)
#define SET_NUMBER_MASK (SET_NUMBER-1)
X
/* Number of packets in set - this number depends on amount of RAM
X * in the FPGA - all set must fit in the FPGA RAM
X * Should be power of two! */
#define PKTS_IN_SET (1<<5)
#define PKT_IN_SET_MASK (PKTS_IN_SET-1)
X
/* Capacity of kernel buffer (mmapped into user space) measured in
X * number of sets - should be equal to power of two, to simplify
X * the modulo operation (replacing it by binary AND) */
#define SETS_IN_BUFFER (1<<8)
X
#define MY_BUF_LEN (SETS_IN_BUFFER * PKTS_IN_SET * 1024)
#define MY_BUF_LEN_MASK (MY_BUF_LEN-1)
X
/* Length of the user header in the packet -
X * command - 2 bytes
X * set number - 2 bytes,
X * packet number and retry number (not used
X * yet) 2 bytes
X * current inter-packet delay (used to monitor the
X * process of delay adaptation) 4 bytes
X */
#define USER_HDR_LEN 10
X
/* Number of bytes of user data in a packet */
#define USER_LEN 1024
#define PAYL_LEN ( USER_HDR_LEN + USER_LEN )
X
/* Length of the acknowledment packet and command packets */
#define MY_ACK_LEN 64
X
/* Number of bytes to be copied from data packet to ack packet */
#define MY_ACK_COPIED 4
X
/* The Ethernet type of our packet. This is NOT OFFICIALLY REGISTERED type,
X * however our protocol is:
X * 1. experimental,
X * 2. supposed to be used only in private networks
X */
#define MY_PROTO_ID 0xfade
X
static int max_slaves = 4;
module_param(max_slaves,int,1);
MODULE_PARM_DESC(max_slaves,"Maximum number of slave FPGA devices serviced by the system.");
X
static int proto_registered = 0; //Was the protocol registred? Should be deregistered at exit?
X
DEFINE_RWLOCK(slave_table_lock); //Used to protect table of slaves
X
/* Structure used to store offset of two currently serviced sets in the data buffer */
struct pkt_map {
X int num;
X int offset;
};
X
typedef struct
{
X // fields related to the circular buffer
X volatile int head;
X volatile int tail;
X rwlock_t ptrs_lock; //Used to protect the head and tail pointers
X
X unsigned char * buffer;
X
X rwlock_t pkts_rwlock; //Protects the pkts table and last_pkt
X int last_pkt; /* position of the last packet, which is still
X replaced with the packet from the next set */
X int pkts[PKTS_IN_SET];
X
X rwlock_t maps_rwlock; //Protects the maps table
X struct pkt_map maps[2];
X
X rwlock_t flags_lock; //Protects other fields of the slave_data struct
X char err_flag;
X char active;
X char is_open;
X int rx_wakeup_thr;
X unsigned char mac[ETH_ALEN];
X struct net_device * dev;
} slave_data;
X
/*
X * The array pkts holds the number of set, from which we expect the particulal packet
X * (so we can safely start with this array filled with zeroes).
X * After the packet is sent and acknowledged, we increase the number corresponding
X * to this packet.
X * At each moment this table may be filled with two different values - n, and n+1
X * because we service two consecutive sets
X */
static slave_data * slave_table = NULL;
X
static int my_proto_rcv(struct sk_buff * skb, struct net_device * dev, struct packet_type * pt,
X struct net_device * orig_dev);
X
static struct packet_type my_proto_pt __read_mostly = {
X .type = cpu_to_be16(MY_PROTO_ID),
X .dev = NULL,
X .func = my_proto_rcv,
};
X
// Prototypes of functions defined in module
void cleanup_my_proto1( void );
int init_my_proto1( void );
static int my_proto1_open(struct inode *inode, struct file *file);
static int my_proto1_release(struct inode *inode, struct file *file);
static long my_proto1_ioctl (struct file *filp, unsigned int cmd, unsigned long arg);
int my_proto1_mmap(struct file *filp, struct vm_area_struct *vma);
unsigned int my_proto1_poll(struct file *filp,poll_table *wait);
X
//Wait queue for user application
DECLARE_WAIT_QUEUE_HEAD (read_queue);
X
dev_t my_dev=0;
struct cdev * my_cdev = NULL;
static struct class *class_my_proto = NULL;
X
struct file_operations Fops = {
X .owner = THIS_MODULE,
X .open=my_proto1_open,
X .release=my_proto1_release, /* a.k.a. close */
X .poll = my_proto1_poll,
X .unlocked_ioctl=my_proto1_ioctl,
X .mmap=my_proto1_mmap
};
X
static long my_proto1_ioctl (struct file *filp,
X unsigned int cmd, unsigned long arg)
{
X slave_data * sd = filp->private_data;
X if (_IOC_TYPE(cmd) != L3_V1_IOC_MAGIC) {
X return -EINVAL;
X }
X switch (cmd) {
X case L3_V1_IOC_SETWAKEUP:
X if (arg > MY_BUF_LEN/2)
X return -EINVAL; //Don't allow to set too high read threshold!
X write_lock_bh(&sd->flags_lock);
X sd->rx_wakeup_thr = arg;
X write_unlock_bh(&sd->flags_lock);
X return 0;
X case L3_V1_IOC_GETBUFLEN:
X /* Inform the user application about the length of the buffer */
X return MY_BUF_LEN;
X case L3_V1_IOC_READPTRS:
X {
X void * res = (void *) arg;
X struct l3_v1_buf_pointers bp;
X if (!access_ok(VERIFY_WRITE,res,sizeof(bp))) {
X return -EFAULT;
X } else {
X read_lock_bh(&sd->ptrs_lock);
X bp.head=sd->head;
X bp.tail=sd->tail;
X read_unlock_bh(&sd->ptrs_lock);
X __copy_to_user(res,&bp,sizeof(bp));
X if (sd->err_flag)
X return -EIO; /* In this case user must him/herself
X calculate the number of available bytes */
X else
X return (bp.head-bp.tail) & MY_BUF_LEN_MASK;
X /* Return the number of available bytes */
X }
X }
X case L3_V1_IOC_WRITEPTRS:
X /* Update the read pointer
X * The argument contains information about the number of bytes
X * consumed by the application
X */
X {
X int rptr;
X int wptr;
X int available_data;
X //We need to check if the amount of consumed data is correct
X write_lock_bh(&sd->ptrs_lock);
X wptr = sd->head;
X rptr = sd->tail;
X available_data = (wptr - rptr) & MY_BUF_LEN_MASK;
X if (arg>available_data)
X {
X write_unlock_bh(&sd->ptrs_lock);
X return -EINVAL;
X }
X //If the number of consumed bytes is correct, update the number of bytes
X sd->tail = (rptr + arg) & MY_BUF_LEN_MASK;
X write_unlock_bh(&sd->ptrs_lock);
X return SUCCESS;
X }
X case L3_V1_IOC_STARTMAC: //Open the slave
X {
X void * source = (void *) arg;
X struct l3_v1_slave sl;
X struct sk_buff *newskb = NULL;
X struct net_device *dev = NULL;
X char * my_data = NULL;
X if (!access_ok(VERIFY_READ,source,sizeof(sl))) {
X return -EFAULT;
X }
X /* First deactivate the slave to avoid situation where data are modified
X * while slave is active */
X if (sd->active) sd->active = 0;
X /* Prepare the data structure for reception of packets */
X write_lock_bh(&sd->maps_rwlock);
X sd->maps[0].num = 0;
X sd->maps[0].offset = 0;
X sd->maps[1].num=1;
X sd->maps[1].offset = PKTS_IN_SET*USER_LEN;
X write_unlock_bh(&sd->maps_rwlock);
X write_lock_bh(&sd->pkts_rwlock);
X memset(&sd->pkts,0,sizeof(sd->pkts));
X sd->last_pkt=0;
X write_unlock_bh(&sd->pkts_rwlock);
X __copy_from_user(&sl,source,sizeof(sl));
X write_lock_bh(&slave_table_lock);
X /* Copy the MAC address */
X memcpy(&sd->mac,sl.mac,ETH_ALEN);
X sd->active = 1;
X write_unlock_bh(&slave_table_lock);
X /* Now send the "start transmission" packet to the slave */
X /* Find the net device */
X sl.devname[IFNAMSIZ-1]=0; // Protect against incorrect device name
X if (sd->dev) {
X //Maybe there was no STOPMAC call after previous STARTMAC?
X dev_put(sd->dev);
X sd->dev=NULL;
X }
X dev = dev_get_by_name(&init_net,sl.devname);
X if (!dev) return -ENODEV;
X sd->dev = dev;
X newskb = alloc_skb(LL_RESERVED_SPACE(dev)+MY_ACK_LEN, GFP_ATOMIC);
X skb_reserve(newskb,LL_RESERVED_SPACE(dev));
X skb_reset_network_header(newskb);
X newskb->dev = dev;
X newskb->protocol = htons(MY_PROTO_ID);
X //Build the MAC header for the new packet
X // Based on
http://lxr.linux.no/#linux+v3.3.4/net/ipv4/arp.c#L586 !
X if (dev_hard_header(newskb,dev,MY_PROTO_ID,&sl.mac,dev->dev_addr,MY_ACK_LEN+ETH_HLEN) < 0) {
X kfree_skb(newskb);
X return -EINVAL;
X }
X //Put the "start" command to the packet
X my_data = skb_put(newskb,2);
X *(my_data++) = 0;
X *(my_data++) = 1;
X my_data = skb_put(newskb,MY_ACK_LEN -2);
X memset(my_data,0xa5,MY_ACK_LEN - 2);
#ifdef FADE_DEBUG
X printk(KERN_INFO "skb_nh: %x, skb_dt: %x, skb_nh2: %x, skb_t: %x\n tail: %d head: %d\n",skb_network_header(newskb),newskb->data,
X newskb->network_header,newskb->tail, sd->tail, sd->head) ;
#endif
X dev_queue_xmit(newskb);
X return SUCCESS;
X }
X case L3_V1_IOC_STOPMAC: //Close the slave and reset it to stop transmission immediately
X {
X struct sk_buff *newskb = NULL;
X char * my_data = NULL;
X write_lock_bh(&slave_table_lock);
X /* Clear the MAC address */
X sd->active = 0;
X memset(&sd->mac,0,ETH_ALEN);
X write_unlock_bh(&slave_table_lock);
X /* Now send the "stop transmission" packet to the slave */
X /* Find the net device */
X if (!sd->dev) return -ENODEV;
X newskb = alloc_skb(LL_RESERVED_SPACE(sd->dev)+MY_ACK_LEN, GFP_ATOMIC);
X skb_reserve(newskb,LL_RESERVED_SPACE(sd->dev));
X skb_reset_network_header(newskb);
X newskb->dev = sd->dev;
X newskb->protocol = htons(MY_PROTO_ID);
X //Build the MAC header for the new packet
X // Based on
http://lxr.linux.no/#linux+v3.3.4/net/ipv4/arp.c#L586 !
X if (dev_hard_header(newskb,sd->dev,MY_PROTO_ID,&sd->mac,sd->dev->dev_addr,MY_ACK_LEN+ETH_HLEN) < 0) {
X kfree_skb(newskb);
X return -EINVAL;
X }
X //Put the "stop" command to the packet
X my_data = skb_put(newskb,2);
X *(my_data++) = 0;
X *(my_data++) = 5;
X my_data = skb_put(newskb,MY_ACK_LEN -2);
X memset(my_data,0xa5,MY_ACK_LEN - 2);
#ifdef FADE_DEBUG
X printk(KERN_INFO "skb_nh: %x, skb_dt: %x, skb_nh2: %x, skb_t: %x\n tail: %d head: %d\n",skb_network_header(newskb),newskb->data,
X newskb->network_header,newskb->tail, sd->tail, sd->head) ;
#endif
X dev_queue_xmit(newskb);
X dev_put(sd->dev);
X sd->dev=NULL;
X return SUCCESS;
X }
X }
X return -EINVAL;
}
/*
X Implementation of the poll method
*/
unsigned int my_proto1_poll(struct file *filp,poll_table *wait)
{
X unsigned int mask =0;
X slave_data * sd = filp->private_data;
X unsigned int data_available;
X poll_wait(filp,&read_queue,wait);
X read_lock_bh(&sd->ptrs_lock);
X data_available = (sd->head - sd->tail) & MY_BUF_LEN_MASK;
X if (data_available>=sd->rx_wakeup_thr) mask |= POLLIN |POLLRDNORM;
#ifdef FADE_DEBUG
X printk(KERN_INFO "poll head: %d tail: %d data: %d prog: %d.\n",sd->head,sd->tail,data_available,sd->rx_wakeup_thr);
#endif
X //Check if the error occured
X if (sd->err_flag) mask |= POLLERR;
X read_unlock_bh(&sd->ptrs_lock);
X return mask;
}
X
/* Module initialization */
int init_my_proto1( void )
{
X int res;
X int i;
X /* Create the device class for udev */
X class_my_proto = class_create(THIS_MODULE, "my_proto");
X if (IS_ERR(class_my_proto)) {
X printk(KERN_ERR "Error creating my_proto class.\n");
X res=PTR_ERR(class_my_proto);
X goto err1;
X }
X /* Allocate the device number */
X res=alloc_chrdev_region(&my_dev, 0, max_slaves, DEVICE_NAME);
X if (res) {
X printk (KERN_ERR "Alocation of the device number for %s failed\n",
X DEVICE_NAME);
X goto err1;
X };
X /* Allocate the character device structure */
X my_cdev = cdev_alloc( );
X if (my_cdev == NULL) {
X printk (KERN_ERR "Allocation of cdev for %s failed\n",
X DEVICE_NAME);
X goto err1;
X }
X my_cdev->ops = &Fops;
X my_cdev->owner = THIS_MODULE;
X /* Add the character device to the system */
X res=cdev_add(my_cdev, my_dev, max_slaves);
X if (res) {
X printk (KERN_ERR "Registration of the device number for %s failed\n",
X DEVICE_NAME);
X goto err1;
X };
X /* Create our devices in the system */
X for (i=0;i<max_slaves;i++) {
X device_create(class_my_proto,NULL,MKDEV(MAJOR(my_dev),MINOR(my_dev)+i),NULL,"l3_fpga%d",i);
X }
X printk (KERN_ERR "%s The major device number is %d.\n",
X "Registration is a success.",
X MAJOR(my_dev));
X //Prepare the table of slaves
X slave_table = kzalloc(sizeof(slave_data)*max_slaves, GFP_KERNEL);
X if (!slave_table) return -ENOMEM;
X for (i=0;i<max_slaves;i++) {
X slave_data * sd = &slave_table[i];
X sd->active=0; //Entry not used
X sd->dev=NULL;
X rwlock_init(&sd->maps_rwlock);
X rwlock_init(&sd->pkts_rwlock);
X rwlock_init(&sd->ptrs_lock);
X rwlock_init(&sd->flags_lock);
X }
X //Install our protocol sniffer
X dev_add_pack(&my_proto_pt);
X proto_registered = 1;
X return SUCCESS;
err1:
X /* In case of error free all allocated resources */
X cleanup_my_proto1();
X return res;
}
X
module_init(init_my_proto1);
X
/* Clean-up when removing the module */
void cleanup_my_proto1( void )
{
X /* Unregister the protocol sniffer */
X if (proto_registered) dev_remove_pack(&my_proto_pt);
X /* Free the slave table */
X if (slave_table) {
X int i;
X for (i=0;i<max_slaves;i++) {
X if (slave_table[i].buffer) {
X vfree(slave_table[i].buffer);
X slave_table[i].buffer = NULL;
X }
X if (slave_table[i].dev) {
X dev_put(slave_table[i].dev);
X slave_table[i].dev=NULL;
X }
X if (slave_table[i].active) {
X slave_table[i].active = 0;
X }
X }
X kfree(slave_table);
X slave_table=NULL;
X }
X /* Remove device from the class */
X if (my_dev && class_my_proto) {
X int i;
X for (i=0;i<max_slaves;i++) {
X device_destroy(class_my_proto,MKDEV(MAJOR(my_dev),MINOR(my_dev)+i));
X }
X }
X /* Deregister device */
X if (my_cdev) cdev_del(my_cdev);
X my_cdev=NULL;
X /* Free the device number */
X unregister_chrdev_region(my_dev, max_slaves);
X /* Deregister class */
X if (class_my_proto) {
X class_destroy(class_my_proto);
X class_my_proto=NULL;
X }
X
}
module_exit(cleanup_my_proto1);
/*
X Function, which receives my packet, copies the data and acknowledges the packet
X as soon as possible...
X I've tried to allow this function to handle multiple packets in parallel
X in the SMP system, however I've used rwlocks for that.
X Probably it should be improved, according to the last tendency to avoid
X rwlocks in the kernel...
*/
X
static int my_proto_rcv(struct sk_buff * skb, struct net_device * dev, struct packet_type * pt,
X struct net_device * orig_dev)
{
X struct sk_buff *newskb = NULL;
X struct ethhdr * rcv_hdr = NULL;
X //unsigned int head;
X //unsigned int tail;
X int res;
X unsigned int set_number;
X unsigned int packet_number;
X int ns; //Number of slave
X slave_data * sd = NULL;
X int set_num_diff;
X unsigned int buf_free = 0;
X char * my_data = NULL;
X unsigned char tmp_buf[USER_HDR_LEN];
X char ack_packet = 0; //Should we acknowledge the packet?
X //Extract the MAC header from the received packet
X rcv_hdr=eth_hdr(skb);
X //First we try to identify the sender so we search the table of active slaves
X //The table is protected during the search, so it should not be changed
#ifdef FADE_DEBUG
X printk("snd: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",(int)rcv_hdr->h_source[0],
X (int)rcv_hdr->h_source[1],(int)rcv_hdr->h_source[2],(int)rcv_hdr->h_source[3],
X (int)rcv_hdr->h_source[4],(int)rcv_hdr->h_source[5]);
#endif
X read_lock_bh(&slave_table_lock);
X for (ns=0;ns<max_slaves;ns++) {
#ifdef FADE_DEBUG
X printk("slv: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x act: %d\n",
X (int)slave_table[ns].mac[0],(int)slave_table[ns].mac[1],(int)slave_table[ns].mac[2],
X (int)slave_table[ns].mac[3],(int)slave_table[ns].mac[4],(int)slave_table[ns].mac[5],
X (int)slave_table[ns].active);
#endif
X if (
X slave_table[ns].active!=0 &&
X memcmp(slave_table[ns].mac,rcv_hdr->h_source, sizeof(slave_table[0].mac))==0
X ) break;
X }
X read_unlock_bh(&slave_table_lock);
X //Now we know which slave sent us the packet (ns<max_slaves) or that
X //the packet came from an unknown slave (ns==max_slaves)
X if (unlikely(ns==max_slaves)) {
X printk(KERN_WARNING " Received packet from incorrect slave!\n");
X //Sender is not opened, so ignore the packet, and send
X //to the sender request to stop the transmission immediately
X newskb = alloc_skb(LL_RESERVED_SPACE(dev)+MY_ACK_LEN, GFP_ATOMIC);
X skb_reserve(newskb,LL_RESERVED_SPACE(dev));
X skb_reset_network_header(newskb);
X newskb->dev = dev;
X newskb->protocol = htons(MY_PROTO_ID);
X //Build the MAC header for the new packet
X // Here is shown how to build a packet:
http://lxr.linux.no/linux+*/net/ipv4/arp.c#L586
X if (dev_hard_header(newskb,dev,MY_PROTO_ID,&rcv_hdr->h_source,&rcv_hdr->h_dest,MY_ACK_LEN+ETH_HLEN) < 0)
X goto error;
X //Put the "restart" command to the packet
X my_data = skb_put(newskb,2);
X *(my_data++) = 0;
X *(my_data++) = 5;
X my_data = skb_put(newskb,MY_ACK_LEN -2);
X memset(my_data,0xa5,MY_ACK_LEN - 2);
X dev_queue_xmit(newskb);
X kfree_skb(skb);
X return NET_RX_DROP;
X }
X sd = &slave_table[ns]; //To speed up access to the data describing state of the slave
#ifdef FADE_DEBUG
X printk(KERN_INFO " Received packet!\n");
#endif
X //Now we should analyze the origin and meaning of the packet
X //To avoid problems with scattered packets, we copy initial part of data to the buffer
X //using the skb_copy_bits
X skb_copy_bits(skb,0,tmp_buf,USER_HDR_LEN);
X /* We extract the information from the user header
X * First we check if this is a data packet: */
X if (unlikely((tmp_buf[0] != 0xa5) ||
X (tmp_buf[1] != 0xa5))) {
X kfree_skb(skb);
X write_lock_bh(&sd->flags_lock);
X sd->err_flag |= FADE_ERR_INCORRECT_PACKET_TYPE;
X write_unlock_bh(&sd->flags_lock);
X return NET_RX_DROP;
X }
X /* Now we check the set number and the packet number:
X PLEASE NOTE, THAT THIS MUST TIGHTLY CORRESPOND
X TO YOUR FPGA IMPLEMENTATION! */
X set_number = (int)tmp_buf[2]*256+tmp_buf[3];
X packet_number = ((int)tmp_buf[4]>>2);
#ifdef FADE_DEBUG
X printk(KERN_INFO "set=%d pkt=%d\n",set_number,packet_number);
#endif
X /* To know if this is a new packet, we compare the set number
X * in the received packet with the expected set number,
X * calculating the difference between those two numbers: */
X read_lock_bh(&sd->pkts_rwlock);
X set_num_diff=(set_number - sd->pkts[packet_number]) & SET_NUMBER_MASK;
X read_unlock_bh(&sd->pkts_rwlock);
X if (likely(set_num_diff==0)) {
X /* This is the expected data packet. */
X int set = -1;
X /* Because we often handle two sets of packets
X simultaneously, we use "set" variable to store the relative set number */
X int needed_space;
X /* We determine the relative set number: 1 or 0 */
X read_lock_bh(&sd->maps_rwlock);
X if (set_number == sd->maps[0].num) set = 0;
X else if (set_number == sd->maps[1].num) set = 1;
X //Set equal to -1 should never happen!
X if (set==-1) {
X printk(KERN_WARNING "Incorrect set number in received packet!\n");
X read_unlock_bh(&sd->maps_rwlock);
X write_lock_bh(&sd->flags_lock);
X sd->err_flag |= FADE_ERR_INCORRECT_SET;
X write_unlock_bh(&sd->flags_lock);
X kfree_skb(skb);
X return NET_RX_DROP;
X }
X /* Now we can calculate how much free space requires this packet
X Amount of space is calculated between the byte after the received packet
X and the byte pointed by the head pointer */
X needed_space = (sd->maps[set].offset + USER_LEN*(packet_number+1) - sd->head) & MY_BUF_LEN_MASK;
X read_unlock_bh(&sd->maps_rwlock); //We stop to use the "maps" table
X read_lock_bh(&sd->ptrs_lock);
X buf_free=( sd->tail - sd->head -1 ) & MY_BUF_LEN_MASK;
#ifdef FADE_DEBUG
X printk(KERN_INFO "Offset: %d packet_nr: %d Free buffer: %d needed space: %d set=%d offset=%d head=%d last=%d\n",
X sd->maps[set].offset, packet_number, buf_free, needed_space,set,sd->maps[set].offset,sd->head,sd->last_pkt);
#endif
X read_unlock_bh(&sd->ptrs_lock);
X if ( buf_free > needed_space ) {
X int ackd_set_nr;
X //Packet fits in the buffer!
X // Length of the payload should be 1024+header???
X if (skb->len != PAYL_LEN) {
X printk(KERN_ERR "Error! Length of data should be %d but is %d!\n",PAYL_LEN, skb->len);
X sd->err_flag |= FADE_ERR_INCORRECT_LENGTH;
X kfree_skb(skb);
X return NET_RX_DROP;
X }
X // We can safely copy all the packet to the buffer:
X // As buffer's boundary never is located in the middle of the packet set,
X // we can simply calculate the begining of the data in the buffer
X // as &sd->buffer[sd->maps[set].offset+USER_LEN*packet_number
X res = skb_copy_bits(skb,10,&sd->buffer[sd->maps[set].offset+USER_LEN*packet_number],USER_LEN);
#ifdef FADE_DEBUG
X printk(KERN_INFO " skb_copy_bits: %d", res);
#endif
X //Packet was copied, so note, that we should confirm it
X if (res>=0) {
X ack_packet=1;
X /* We modify the expected set number for the packet, to modify the
X * pkts table, we must close pkts_rwlock for writing */
X write_lock_bh(&sd->pkts_rwlock);
X ackd_set_nr = (set_number + 1) & SET_NUMBER_MASK;
X sd->pkts[packet_number]= ackd_set_nr;
X if (packet_number == sd->last_pkt) {
X /* If our packet was the last, which prevented shifting of the head pointer,
X * we can try now to move the head pointer.
X * We browse the pkts table, looking for the first uncorfirmed packet.
X */
X while ((++(sd->last_pkt)) < PKTS_IN_SET) {
X if (sd->pkts[sd->last_pkt] != ackd_set_nr) break; //Packet not confirmed
X }
X if (sd->last_pkt == PKTS_IN_SET) {
X /* All packets from the "old" set are received, so we can change
X * the set_nr
X */
X sd->last_pkt = 0;
X /* Update the maps table. Remove the 0th set, move the 1st to the 0th.
X * Add the new set as the 1st one */
X write_lock_bh(&sd->maps_rwlock);
X memcpy(&sd->maps[0],&sd->maps[1],sizeof(sd->maps[0]));
X sd->maps[1].num = (sd->maps[1].num + 1) & SET_NUMBER_MASK;
X sd->maps[1].offset = (sd->maps[1].offset + USER_LEN*PKTS_IN_SET) & MY_BUF_LEN_MASK;
X write_unlock_bh(&sd->maps_rwlock);
X /* Now we need to check for confirmed packet from the next set */
X ackd_set_nr+=1;
X while (sd->last_pkt < PKTS_IN_SET) {
X if (sd->pkts[sd->last_pkt] != ackd_set_nr) break; //Packet not cofirmed
X else sd->last_pkt++;
X }
X write_unlock_bh(&sd->pkts_rwlock);
X } else {
X //No need to change packet sets, simply release the lock
X write_unlock_bh(&sd->pkts_rwlock);
X }
X /* Now we can move the head position right after the last serviced packet */
X write_lock_bh(&sd->ptrs_lock);
X sd->head = sd->maps[0].offset+sd->last_pkt*USER_LEN;
X /* When we have moved the head pointer, we can try to wake up the reading processes */
X wake_up_interruptible(&read_queue);
X write_unlock_bh(&sd->ptrs_lock);
X } else {
X // It was not the last packet, no need to move the head pointer
X write_unlock_bh(&sd->pkts_rwlock);
X }
X }
X }
X } else {
X /* This packet has incorrect set number. If the number is too low, we ignore the packet,
X * but send the confirmation (ack was received too late, or was lost?) */
X if (set_num_diff>(SET_NUMBER/2)) {
X /* In fact it means, that set_num_diff is negative, but we calculate
X * it modulo SET_NUMBER! */
X ack_packet = 1;
#ifdef FADE_DEBUG
X printk(KERN_INFO "Packet already confirmed: pkt=%d set=%d expect=%d last=%d\n",packet_number, set_number, sd->pkts[packet_number], sd->last_pkt);
#endif
X } else {
X /* This is a packet with too high set number (packet "from the future"
X * it my be a symptom of serious communication problem! */
X printk(KERN_ERR "Packet from the future! number: %d expected: %d\n", set_number, sd->pkts[packet_number]);
X }
X }
X //Now send the confirmation
X if (likely(ack_packet)) {
X newskb = alloc_skb(LL_RESERVED_SPACE(dev)+MY_ACK_LEN, GFP_ATOMIC);
X skb_reserve(newskb,LL_RESERVED_SPACE(dev));
X skb_reset_network_header(newskb);
X newskb->dev = dev;
X newskb->protocol = htons(MY_PROTO_ID);
X //Build the MAC header for the new packet
X // Tu
http://lxr.linux.no/linux+*/net/ipv4/arp.c#L586 jest pokazane jak zbudować pakiet!
X if (dev_hard_header(newskb,dev,MY_PROTO_ID,&rcv_hdr->h_source,&rcv_hdr->h_dest,MY_ACK_LEN+ETH_HLEN) < 0)
X goto error;
X //Put the "ACKNOWLEDGE" type
X my_data = skb_put(newskb,2);
X *(my_data++) = 0;
X *(my_data++) = 3; //ACK!
X //Copy the begining of the received packet to the acknowledge packet
X my_data = skb_put(newskb,MY_ACK_COPIED);
X res = skb_copy_bits(skb,2,my_data,MY_ACK_COPIED);
X my_data = skb_put(newskb,MY_ACK_LEN -MY_ACK_COPIED-2);
X memset(my_data,0xa5,MY_ACK_LEN - MY_ACK_COPIED-2);
#ifdef FADE_DEBUG
X printk(KERN_INFO " skb_nh: %x, skb_dt: %x, skb_nh2: %x, skb_t: %x\n tail: %d head: %d\n",skb_network_header(newskb),newskb->data,
X newskb->network_header,newskb->tail, sd->tail, sd->head) ;
#endif
X dev_queue_xmit(newskb);
X }
X kfree_skb(skb);
X return NET_RX_SUCCESS;
X
error:
X if (newskb) kfree_skb(newskb);
X if (skb) kfree_skb(skb);
X return NET_RX_DROP;
}
X
/*
X Implementation of the "device open" function
*/
static int my_proto1_open(struct inode *inode,
X struct file *file)
{
X int i;
X slave_data * sd = NULL;
X unsigned long flags;
X i=iminor(inode)-MINOR(my_dev);
X if (i >= max_slaves) {
X printk(KERN_WARNING "Trying to access %s slave with too high minor number: %d\n",
X DEVICE_NAME, i);
X return -ENODEV;
X }
X read_lock_irqsave(&slave_table_lock,flags);
X sd = &slave_table[i];
X //Each device may be opened only once!
X if (sd->is_open) {
X return -EBUSY;
X read_unlock_irqrestore(&slave_table_lock,flags);
X }
X //Prepare slave_table for operation
X read_unlock_irqrestore(&slave_table_lock,flags);
X sd->buffer = vmalloc_user(MY_BUF_LEN);
X if (!sd->buffer) return -ENOMEM;
X //Set the MAC address to 0
X memset(sd->mac,0,sizeof(sd->mac));
X sd->head = 0;
X sd->tail = 0;
X sd->err_flag = 0;
X sd->last_pkt = 0;
X sd->rx_wakeup_thr = 1;
X sd->active = 0;
X sd->is_open = 1;
X file->private_data=sd;
X return SUCCESS;
}
X
X
static int my_proto1_release(struct inode *inode,
X struct file *file)
{
X slave_data * sd = file->private_data;
#ifdef FADE_DEBUG
X printk (KERN_INFO "device_release(%p,%p)\n", inode, file);
#endif
X //Release resources associated with servicing of the particular device
X if (sd) {
X if (sd->is_open) {
X sd->is_open = 0; //It can be dangerous! Before freeing the buffer, we must be sure, that
X //no our packet is being processed!
X if (sd->active) {
X sd->active = 0;
X }
X if (sd->buffer) {
X vfree(sd->buffer);
X sd->buffer = NULL;
X }
X }
X }
X return SUCCESS;
}
X
/* Memory mapping */
void my_proto1_vma_open (struct vm_area_struct * area)
{ }
X
void my_proto1_vma_close (struct vm_area_struct * area)
{ }
X
static struct vm_operations_struct my_proto1_vm_ops = {
X my_proto1_vma_open,
X my_proto1_vma_close,
};
X
/*
X mmap method implementation
*/
int my_proto1_mmap(struct file *filp,
X struct vm_area_struct *vma)
{
X slave_data * sd = filp->private_data;
X unsigned long vsize = vma->vm_end - vma->vm_start;
X unsigned long psize = MY_BUF_LEN;
X if (vsize>psize)
X return -EINVAL;
X remap_vmalloc_range(vma,sd->buffer, 0);
X if (vma->vm_ops)
X return -EINVAL; //It should never happen...
X vma->vm_ops = &my_proto1_vm_ops;
X my_proto1_vma_open(vma); //No open(vma) was called, we have called it ourselves
X return 0;
}
X
SHAR_EOF
(set 20 12 05 03 22 03 48 'linux_driver_and_application/fpga_l3_fade.c'
eval "${shar_touch}") && \
chmod 0644 'linux_driver_and_application/fpga_l3_fade.c'
if test $? -ne 0
then ${echo} "restore of linux_driver_and_application/fpga_l3_fade.c failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'linux_driver_and_application/fpga_l3_fade.c': 'MD5 check failed'
) << \SHAR_EOF
6d0e5510fac19f62852ba9700ffd2b70 linux_driver_and_application/fpga_l3_fade.c
SHAR_EOF
else
test `LC_ALL=C wc -c < 'linux_driver_and_application/fpga_l3_fade.c'` -ne 31482 && \
${echo} "restoration warning: size of 'linux_driver_and_application/fpga_l3_fade.c' is not 31482"
fi
fi
# ============= linux_driver_and_application/Makefile ==============
if test -n "${keep_file}" && test -f 'linux_driver_and_application/Makefile'
then
${echo} "x - SKIPPING linux_driver_and_application/Makefile (file already exists)"
else
${echo} "x - extracting linux_driver_and_application/Makefile (text)"
sed 's/^X//' << 'SHAR_EOF' > 'linux_driver_and_application/Makefile' &&
ifneq ($(KERNELRELEASE),)
X obj-m := fpga_l3_fade.o
else
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
X $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
X gcc -O2 -o receiver2 receiver2.c
endif
SHAR_EOF
(set 20 12 05 03 22 10 12 'linux_driver_and_application/Makefile'
eval "${shar_touch}") && \
chmod 0644 'linux_driver_and_application/Makefile'
if test $? -ne 0
then ${echo} "restore of linux_driver_and_application/Makefile failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'linux_driver_and_application/Makefile': 'MD5 check failed'
) << \SHAR_EOF
5254391d1fba7348be67d34425874172 linux_driver_and_application/Makefile
SHAR_EOF
else
test `LC_ALL=C wc -c < 'linux_driver_and_application/Makefile'` -ne 219 && \
${echo} "restoration warning: size of 'linux_driver_and_application/Makefile' is not 219"
fi
fi
# ============= desc.txt ==============
if test -n "${keep_file}" && test -f 'desc.txt'
then
${echo} "x - SKIPPING desc.txt (file already exists)"
else
${echo} "x - extracting desc.txt (text)"
sed 's/^X//' << 'SHAR_EOF' > 'desc.txt' &&
DESCRIPTION
X
This archive implements the simple and light protocol for transmission
of data from low resources FPGA connected to the Ethernet MAC
and an embedded system running Linux OS.
The main goal was to assure the reliable transmission over unreliable
Ethernet link without need to buffer significant amount of data
in the FPGA. This created a need to obtain possibly early
acknowledgment of received packets from the embedded system,
and therefore the protocol had to be implemented in layer 3.
X
The Ethernet type 0xfade was used (unregistered, but as this
protocol should be used only in a small private networks,
without routers, with switches only, it should not be a problem).
X
We assume, that the FPGA is capable to store one "set" of packets
(in the example design length of this set is equal to 32).
To start the transmission, receiver sends the "start transmission"
packet:
TGT,SRC,0xfade,0x0001,pad to 64 bytes
X
After reception of the "start transmission" packet, the transmitter
(FPGA) starts to send the data packets:
TGT,SRC,0xfade,0xa5a5,set & packet number, delay, 1024 bytes of data
X
X
After reception of the correct data packet, the receiver sends the
"acknowledge" packet:
TGT,SRC,0xfade,0x0003,set & packet number, pad to 64 bytes
X
Another packet may be used to request immediate stop of transmission:
TGT,SRC,0xfade,0x0005, pad to 64 bytes
X
When first packets from the current set buffered in FPGA are
transmitted and acknowledged, they may be replaced with the packets
from the next set - the current state of transmission is stored
in desc_memory in the desc_manager entity.
X
When particular packet is not acknowledged, it is transmitted once
again. In current example design each packet has simple attributes:
1. set number
2. valid (ready to be sent)
3. sent (has been sent at least once - used for delay adaptation)
4. confirmed (reception has been confirmed, packet may be replaced
X with the same packet from the next set)
X
List of packets is cyclically browsed to move the "head" and "tail"
pointers.
I've also tried another approach with more sophisticated packet
manager based on linked lists, but it is not fully debugged and not
ready for release yet. However the approach with cyclic browsing is
sufficient, as anyway an additional delay between packets had to be
introduced to achieve optimal transmission.
X
If the data packets are sent too quickly, the acknowledge
packets from the embedded system are received too late,
and the packet is retransmitted before acknowledge arrives.
The same may occur if the embedded system is overloaded
with packets from different slaves and drops some packets.
X
Therefore paradoxically resending of packets as soon as possible
does not provide the maximal throughput, and a delay between
packets must be introduced.
Of course if this delay is too big, the transmission also slows down.
X
To find the optimal delay, I have implemented a simple adaptive
algorithm based on analysis of the ratio between number of all sent
packets and of retransmitted packets: Nretr/Nall
If the data packets are sent too quickly, the ratio of Nretr/Nall
increases indicating, that the delay should be higher.
If the ratio Nretr/Nall is near to 0, we may reduce the delay.
Such a simple algorithm works quite satisfactory.
X
In the embedded system, the fpga_l3_fade.ko driver allows you
to service multiple FPGA slaves connected to different network
interfaces.
The "max_slaves" parameter lets you to set the maximum number of
slaves, when module is loaded.
X
After that, you can open /dev/l3_fpga0, /dev/l3_fpga1 ...
devices, to connect different slaves.
To connect one of those devices to particular FPGA slave,
you need to use the ioctl command L3_V1_IOC_STARTMAC
(please see the attached receiver2.c application for
an example).
The data received from the FPGA are placed in a kernel
buffer (each subdevice has its own buffer) which may be mmapped
to the user space application, providing very quick access
to the data. Another ioctl commands: L3_V1_IOC_READPTRS
and L3_V1_IOC_WRITEPTRS allow you to read the head and tail
pointers in this buffer and to confirm reception of data.
The attached receiver2.c application uses the described
mechanisms and simply tests, if the connected FPGA slave
sends consecutive 32-bit integers.
X
DISCLAIMER:
The published sources are "the first iteration". They work for me,
but I do not provide any warranty. You can use it only on your
own risk!
X
I hope to prepare the new, more mature version, which will be
described in a "official" publication (I'll send the reference,
when it is ready).
X
I'll also publish further versions of sources on my website:
http://www.ise.pw.edu.pl/~wzab/fpga_l3_fade
X
To compile this sources, you should download the sources of Ethernet MAC
http://opencores.org/project,ethernet_tri_mode written by Jon Gao
(which is published under LGPL) and unpack them into the eth
subdirectory.
X
You should also modify the reg_int.v file so, that the MAC starts to work
autonomously without control form the CPU.
X
I had to set the following register values:
X
// RegCPUData U_0_000(Tx_Hwmark ,7'd000,16'h0009,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_000(Tx_Hwmark ,7'd000,16'h001a,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_001(Tx_Lwmark ,7'd001,16'h0009,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_002(pause_frame_send_en ,7'd002,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_003(pause_quanta_set ,7'd003,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_004(IFGset ,7'd004,16'h000c,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_005(FullDuplex ,7'd005,16'h0001,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_006(MaxRetry ,7'd006,16'h0002,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_007(MAC_tx_add_en ,7'd007,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_008(MAC_tx_add_prom_data ,7'd008,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_009(MAC_tx_add_prom_add ,7'd009,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_010(MAC_tx_add_prom_wr ,7'd010,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_011(tx_pause_en ,7'd011,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_012(xoff_cpu ,7'd012,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_013(xon_cpu ,7'd013,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_014(MAC_rx_add_chk_en ,7'd014,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_015(MAC_rx_add_prom_data ,7'd015,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_016(MAC_rx_add_prom_add ,7'd016,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_017(MAC_rx_add_prom_wr ,7'd017,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_018(broadcast_filter_en ,7'd018,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_019(broadcast_bucket_depth ,7'd019,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_020(broadcast_bucket_interval,7'd020,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_021(RX_APPEND_CRC ,7'd021,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_022(Rx_Hwmark ,7'd022,16'h001a,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_023(Rx_Lwmark ,7'd023,16'h0010,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_024(CRC_chk_en ,7'd024,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_025(RX_IFG_SET ,7'd025,16'h000c,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_026(RX_MAX_LENGTH ,7'd026,16'h2710,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_027(RX_MIN_LENGTH ,7'd027,16'h0040,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_028(CPU_rd_addr ,7'd028,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_029(CPU_rd_apply ,7'd029,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
// RegCPUData U_0_030(CPU_rd_grant ,7'd030,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
// RegCPUData U_0_031(CPU_rd_dout_l ,7'd031,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
// RegCPUData U_0_032(CPU_rd_dout_h ,7'd032,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X RegCPUData U_0_033(Line_loop_en ,7'd033,16'h0000,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
//Line below for 1Gb Ethernet
X RegCPUData U_0_034(Speed ,7'd034,16'h0004,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
//Line below for 100Mb Ethernet
// RegCPUData U_0_034(Speed ,7'd034,16'h0002,Reset,Clk_reg,!WRB,CSB,CA,CD_in);
X
X
LICENSING:
1. My kernel driver is released under the GPL license
2. My user space application is public domain
3. My FPGA code is published with BSD license
4. Due to licensing issues I can include only xco files for blocks
X generated by Xilinx tools. I hope that you'll be able to rebuild
X my design with them
X
If you create something basing on this my work, I'll be glad if you
provide information about my project (especially if you cite my
article, after it is ready and published)
X
Wojciech M. Zabolotny
wz...@ise.pw.edu.pl
X
SHAR_EOF
(set 20 12 05 03 23 35 14 'desc.txt'
eval "${shar_touch}") && \
chmod 0644 'desc.txt'
if test $? -ne 0
then ${echo} "restore of desc.txt failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'desc.txt': 'MD5 check failed'
) << \SHAR_EOF
a03844a3ba32df649847709d461a95fa desc.txt
SHAR_EOF
else
test `LC_ALL=C wc -c < 'desc.txt'` -ne 9345 && \
${echo} "restoration warning: size of 'desc.txt' is not 9345"
fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
exit 1
fi
exit 0