1 |
2 |
DavidRAMBA |
--=============================================================================
|
2 |
|
|
-- TITRE : LAYER2_TX
|
3 |
|
|
-- DESCRIPTION :
|
4 |
|
|
-- Encapsule la trame applicative dans une trame Layer2
|
5 |
|
|
-- Ajoute les fanions de début et de fin, effectue le byte stuffing
|
6 |
|
|
-- et calcule le CRC
|
7 |
|
|
-- FICHIER : layer2_tx.vhd
|
8 |
|
|
--=============================================================================
|
9 |
|
|
-- CREATION
|
10 |
|
|
-- DATE AUTEUR PROJET REVISION
|
11 |
|
|
-- 10/04/2014 DRA SATURN V1.0
|
12 |
|
|
--=============================================================================
|
13 |
|
|
-- HISTORIQUE DES MODIFICATIONS :
|
14 |
|
|
-- DATE AUTEUR PROJET REVISION
|
15 |
|
|
--=============================================================================
|
16 |
|
|
|
17 |
|
|
LIBRARY IEEE;
|
18 |
|
|
USE IEEE.STD_LOGIC_1164.ALL;
|
19 |
|
|
USE IEEE.STD_LOGIC_ARITH.ALL;
|
20 |
|
|
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
|
21 |
|
|
|
22 |
|
|
entity layer2_tx is
|
23 |
|
|
PORT (
|
24 |
|
|
-- Ports système
|
25 |
|
|
clk_sys : IN STD_LOGIC; -- Clock système
|
26 |
|
|
rst_n : IN STD_LOGIC; -- Reset général système
|
27 |
|
|
|
28 |
|
|
-- Interfaces vers le module d'interface du PIC
|
29 |
|
|
dat_in : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- Flux de données applicatives à émettre
|
30 |
|
|
-- La première donnée du flux qui suit le sof est l'@ de destination
|
31 |
|
|
val_in : IN STD_LOGIC; -- validant du bus dat_in
|
32 |
|
|
sof : IN STD_LOGIC; -- Indique le début d'une trame à émettre (non synchrone de la 1ère donnée)
|
33 |
|
|
eof : IN STD_LOGIC; -- Indique le dernier octet de la trame à émettre
|
34 |
|
|
datin_free: OUT STD_LOGIC; -- Indique que le module layer2_tx est prêt à recevoir 1 octet suivant
|
35 |
|
|
|
36 |
|
|
-- Interfaces vers les FIFO de transmissions
|
37 |
|
|
dat_out : OUT STD_LOGIC_VECTOR(7 downto 0);-- Flux de données Layer2 à stocker dans les FIFO Tx
|
38 |
|
|
val_out : OUT STD_LOGIC; -- Validant du bus dat_out
|
39 |
|
|
clr_fifo : IN STD_LOGIC; -- Signal de reset des FIFO Tx
|
40 |
|
|
progfull1: IN STD_LOGIC; -- Indique la FIFO Tx1 est presque pleine
|
41 |
|
|
progfull2: IN STD_LOGIC; -- Indique la FIFO Tx2 est presque pleine
|
42 |
|
|
full1 : IN STD_LOGIC; -- Indique la FIFO Tx1 est pleine
|
43 |
|
|
empty1 : IN STD_LOGIC; -- Indique la FIFO Tx1 est vide
|
44 |
|
|
full2 : IN STD_LOGIC; -- Indique la FIFO Tx2 est pleine
|
45 |
|
|
empty2 : IN STD_LOGIC -- Indique la FIFO Tx2 est vide
|
46 |
|
|
);
|
47 |
|
|
end layer2_tx;
|
48 |
|
|
|
49 |
|
|
architecture rtl of layer2_tx is
|
50 |
|
|
SIGNAL crc : STD_LOGIC_VECTOR(15 downto 0); -- Valeur dynamique du crc
|
51 |
|
|
SIGNAL val_crc : STD_LOGIC; -- Validant du CCRC
|
52 |
|
|
SIGNAL init_crc : STD_LOGIC; -- Initialise le calcul du CRC
|
53 |
|
|
SIGNAL dat_crc : STD_LOGIC_VECTOR(7 DOWNTO 0); -- Donnée à prendre en compte pour le calcul du CRC
|
54 |
|
|
SIGNAL last_char: STD_LOGIC; -- Pour mémoriser le eof au cas ou il y'ait du stuffing sur le dernier char
|
55 |
|
|
SIGNAL empty1_r1, empty1_r2: STD_LOGIC; -- Pour changer empty1 d'horloge
|
56 |
|
|
SIGNAL empty2_r1, empty2_r2: STD_LOGIC; -- Pour changer empty2 d'horloge
|
57 |
|
|
-- Machine d'état de gestion du module
|
58 |
|
|
TYPE layer2_tx_type IS (idle_st, addest_st, data_st, fifo_full_st, stuf5E_st, stuf5D_st,
|
59 |
|
|
waitcrc_st, crc1_st, stufcrc1_st, crc2_st, stufcrc2_st, fanionfin_st, waitendsend_st);
|
60 |
|
|
SIGNAL fsm_layer2_tx : layer2_tx_type;
|
61 |
|
|
|
62 |
|
|
-- Module de calcul du CRC16
|
63 |
|
|
COMPONENT crc16
|
64 |
|
|
GENERIC (
|
65 |
|
|
poly : STD_LOGIC_VECTOR(15 downto 0) := x"1021" -- CCITT16 par défaut
|
66 |
|
|
);
|
67 |
|
|
PORT(
|
68 |
|
|
clk_sys : IN std_logic;
|
69 |
|
|
rst_n : IN std_logic;
|
70 |
|
|
data : IN std_logic_vector(7 downto 0);
|
71 |
|
|
val : IN std_logic;
|
72 |
|
|
init : IN std_logic;
|
73 |
|
|
crc : OUT std_logic_vector(15 downto 0)
|
74 |
|
|
);
|
75 |
|
|
END COMPONENT;
|
76 |
|
|
|
77 |
|
|
BEGIN
|
78 |
|
|
--------------------------------------------
|
79 |
|
|
-- Machine d'état de génération du flux et d'écriture dans la FIFO Tx
|
80 |
|
|
-- Les FIFO Tx font 512 octet mais leur 'prog_full' est calé à 495 octets
|
81 |
|
|
-- En testant le prog_full, on a donc toujours au moins 15 octets de libre
|
82 |
|
|
-- On ne teste donc le prog_full que quand on écrit des donées utiles de la trame
|
83 |
|
|
-- Lorsqu'on écrit l'entête ou le CRC ou du stuffing, il n 'y a pas besoin de tester
|
84 |
|
|
-- le niveau de remplissage
|
85 |
|
|
--------------------------------------------
|
86 |
|
|
-- La donnée entrante est prise en compte que si on est dans l'état data_st ou addest_st
|
87 |
|
|
-- Autrement dit, le module est dipos pour une nouvelle donnée dans ces cas là
|
88 |
|
|
datin_free <= '1' WHEN (fsm_layer2_tx = data_st OR fsm_layer2_tx = addest_st) ELSE '0';
|
89 |
|
|
man_fsm : PROCESS(clk_sys, rst_n)
|
90 |
|
|
BEGIN
|
91 |
|
|
IF (rst_n = '0') THEN
|
92 |
|
|
fsm_layer2_tx <= idle_st;
|
93 |
|
|
init_crc <= '1';
|
94 |
|
|
val_crc <= '0';
|
95 |
|
|
val_out <= '0';
|
96 |
|
|
last_char <= '0';
|
97 |
|
|
empty1_r1 <= '0';
|
98 |
|
|
empty1_r2 <= '0';
|
99 |
|
|
empty2_r1 <= '0';
|
100 |
|
|
empty2_r2 <= '0';
|
101 |
|
|
dat_out <= (others => '0');
|
102 |
|
|
dat_crc <= (others => '0');
|
103 |
|
|
|
104 |
|
|
ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
|
105 |
|
|
empty1_r1 <= empty1; -- Changement d'horloge de empty1
|
106 |
|
|
empty1_r2 <= empty1_r1;
|
107 |
|
|
empty2_r1 <= empty2; -- Changement d'horloge de empty2
|
108 |
|
|
empty2_r2 <= empty2_r1;
|
109 |
|
|
CASE fsm_layer2_tx IS
|
110 |
|
|
WHEN idle_st =>
|
111 |
|
|
-- Etat d'attente du signal sof
|
112 |
|
|
IF (sof = '1' AND full1 = '0' AND full2 = '0' AND clr_fifo = '0') THEN
|
113 |
|
|
-- Si on commence une trame et que le processus de clr est terminé
|
114 |
|
|
-- Lors d'un reset de fifo, le flag full reste actif durant quelques cycle après
|
115 |
|
|
-- le relachement du clr_fifo
|
116 |
|
|
dat_out <= x"7E"; -- On envoie le fanion de début
|
117 |
|
|
init_crc <= '0'; -- On annule le reset du CRC
|
118 |
|
|
val_crc <= '0'; -- L'octet qu'on va sortir ne compte pas dans le calcul du crc
|
119 |
|
|
val_out <= '1'; -- On l'écrit dans la FIFO
|
120 |
|
|
fsm_layer2_tx <= addest_st; -- On va générer l'octet de commande
|
121 |
|
|
ELSE
|
122 |
|
|
-- Si pas de début de trame
|
123 |
|
|
init_crc <= '1'; -- On initialise le CRC
|
124 |
|
|
val_crc <= '0'; -- On fait rien
|
125 |
|
|
val_out <= '0';
|
126 |
|
|
END IF;
|
127 |
|
|
|
128 |
|
|
WHEN addest_st =>
|
129 |
|
|
IF (val_in = '1') THEN
|
130 |
|
|
-- La première donnée de la trmae est l'@ destination. Elle ne peut pas être stuffée car 7E et 7D sont interdites
|
131 |
|
|
val_out <= '1'; -- Quelle que soit la donnée on la prend en compte dans le calcul du CRC
|
132 |
|
|
val_crc <= '1'; -- Elle compte dans le calcul du CRC
|
133 |
|
|
dat_out <= dat_in; -- On la fournit à la FIFO
|
134 |
|
|
dat_crc <= dat_in; -- On la forunit au CRC
|
135 |
|
|
fsm_layer2_tx <= data_st; -- On va traiter l'octet suivant
|
136 |
|
|
ELSE
|
137 |
|
|
-- Tant qu'on recoit pas de donnée
|
138 |
|
|
val_out <= '0'; -- Rien dans le FIFO
|
139 |
|
|
val_crc <= '0'; -- CRC inchangé
|
140 |
|
|
END IF;
|
141 |
|
|
|
142 |
|
|
WHEN data_st =>
|
143 |
|
|
-- On attend une donnée disponible sur le bus d'entrée
|
144 |
|
|
IF (val_in = '1') THEN
|
145 |
|
|
-- Si il y'a une donnée sur le bus
|
146 |
|
|
val_crc <= '1'; -- Quelle que soit la donnée on la prend en compte dans le calcul du CRC
|
147 |
|
|
dat_crc <= dat_in;
|
148 |
|
|
val_out <= '1'; -- Quelle que soit la donnée on va écrire quelque chose dans la FIFO
|
149 |
|
|
IF (dat_in = x"7E") THEN
|
150 |
|
|
dat_out <= x"7D"; -- Si c'est un 7E il doit être remplacé par la séquence 7D 5E
|
151 |
|
|
last_char <= eof; -- On mémorise s'il s'agit du dernier char de la trame
|
152 |
|
|
fsm_layer2_tx <= stuf5E_st;-- On va insérer le code 5E dans le flux
|
153 |
|
|
ELSIF (dat_in = x"7D") THEN
|
154 |
|
|
dat_out <= x"7D"; -- Si c'est un 7D il doit être remplacé par la séquence 7D 5D
|
155 |
|
|
last_char <= eof; -- On mémorise s'il s'agit du dernier char de la trame
|
156 |
|
|
fsm_layer2_tx <= stuf5D_st;-- On va insérer le code 5D dans le flux
|
157 |
|
|
ELSE
|
158 |
|
|
-- Si c'est une donnée normale
|
159 |
|
|
dat_out <= dat_in; -- On la met dans le flux
|
160 |
|
|
IF (eof = '1') THEN -- Si c'est la dernière donnée de la trame
|
161 |
|
|
fsm_layer2_tx <= waitcrc_st; -- On va attendre que le CRC soit prêt
|
162 |
|
|
ELSIF (progfull1 = '1' OR progfull2 = '1') THEN
|
163 |
|
|
-- Si une des 2 FIFO en écriture est presque pleine
|
164 |
|
|
fsm_layer2_tx <= fifo_full_st; -- On va attendre
|
165 |
|
|
END IF;
|
166 |
|
|
END IF;
|
167 |
|
|
ELSE
|
168 |
|
|
-- Si il n'y a pas de nouvelle donnée sur le bus
|
169 |
|
|
val_crc <= '0'; -- On fait rien
|
170 |
|
|
val_out <= '0';
|
171 |
|
|
END IF;
|
172 |
|
|
|
173 |
|
|
WHEN fifo_full_st =>
|
174 |
|
|
-- Etat d'attente qu'il y'ait de la place dans les FIFO en écriture
|
175 |
|
|
val_crc <= '0'; -- On fait rien
|
176 |
|
|
val_out <= '0';
|
177 |
|
|
IF (progfull1 = '0' AND progfull2 = '0') THEN
|
178 |
|
|
-- On attend que les 2 FIFO ne soient plus pleines
|
179 |
|
|
fsm_layer2_tx <= data_st;
|
180 |
|
|
END IF;
|
181 |
|
|
|
182 |
|
|
|
183 |
|
|
WHEN stuf5E_st =>
|
184 |
|
|
-- Etat d'insertion du char 5E dans le flux
|
185 |
|
|
dat_out <= x"5E";
|
186 |
|
|
val_crc <= '0'; -- Le CRC ne doit pa sêtre mis à jour avec l'octet de bourrage
|
187 |
|
|
val_out <= '1'; -- On l'écrit dans la FIFO
|
188 |
|
|
IF (last_char = '1') THEN -- Si c'était le dernier octet, on va insérer le CRC
|
189 |
|
|
fsm_layer2_tx <= crc1_st;
|
190 |
|
|
ELSE
|
191 |
|
|
fsm_layer2_tx <= data_st;
|
192 |
|
|
END IF;
|
193 |
|
|
|
194 |
|
|
WHEN stuf5D_st =>
|
195 |
|
|
-- Etat d'insertion du char 5D dans le flux
|
196 |
|
|
dat_out <= x"5D";
|
197 |
|
|
val_crc <= '0'; -- Le CRC ne doit pa sêtre mis à jour avec l'octet de bourrage
|
198 |
|
|
val_out <= '1'; -- On l'écrit dans la FIFO
|
199 |
|
|
IF (last_char = '1') THEN -- Si c'était le dernier octet, on va insérer le CRC
|
200 |
|
|
fsm_layer2_tx <= crc1_st;
|
201 |
|
|
ELSE
|
202 |
|
|
fsm_layer2_tx <= data_st;
|
203 |
|
|
END IF;
|
204 |
|
|
|
205 |
|
|
WHEN waitcrc_st =>
|
206 |
|
|
-- On attend un cycle que le CRC soit à jour avec la dernière donnée
|
207 |
|
|
val_crc <= '0';
|
208 |
|
|
val_out <= '0';
|
209 |
|
|
fsm_layer2_tx <= crc1_st; -- On va traiter les 8 MSB du CRC
|
210 |
|
|
|
211 |
|
|
WHEN crc1_st =>
|
212 |
|
|
-- Etat de traitement des 8 MSB du CRC
|
213 |
|
|
val_crc <= '0'; -- On doit pas modifier le CRC
|
214 |
|
|
val_out <= '1'; -- On va écrire une donnée en FIFO
|
215 |
|
|
IF (crc(15 downto 8) = x"7E" OR crc(15 downto 8) = x"7D") THEN
|
216 |
|
|
-- Si les 8 MSB sont une donnée à stuffer
|
217 |
|
|
dat_out <= x"7D"; -- On écrit le code de stuffing
|
218 |
|
|
fsm_layer2_tx <= stufcrc1_st; -- On va traiter le stuf
|
219 |
|
|
ELSE
|
220 |
|
|
-- Si les 8 MSB ne sont pas à stuffer
|
221 |
|
|
dat_out <= crc(15 downto 8); -- On les met tel quel dans le flux
|
222 |
|
|
fsm_layer2_tx <= crc2_st; -- On va traiter les 8 LSB du CRC
|
223 |
|
|
END IF;
|
224 |
|
|
|
225 |
|
|
WHEN stufcrc1_st =>
|
226 |
|
|
-- Etat de gestion du stuffing des 8 MSB du CRC
|
227 |
|
|
val_crc <= '0';
|
228 |
|
|
val_out <= '1';
|
229 |
|
|
IF (crc(15 downto 8) = x"7E") THEN
|
230 |
|
|
-- Selon la valeur à stuffer
|
231 |
|
|
dat_out <= x"5E"; -- On envoie le bon code
|
232 |
|
|
ELSE
|
233 |
|
|
dat_out <= x"5D";
|
234 |
|
|
END IF;
|
235 |
|
|
fsm_layer2_tx <= crc2_st; -- On va traiter les 8 LSB du CRC
|
236 |
|
|
|
237 |
|
|
WHEN crc2_st =>
|
238 |
|
|
-- Etat de traitement des 8 LSB du CRC
|
239 |
|
|
val_crc <= '0';
|
240 |
|
|
val_out <= '1';
|
241 |
|
|
IF (crc(7 downto 0) = x"7E" OR crc(7 downto 0) = x"7D") THEN
|
242 |
|
|
-- Si les 8 LSB sont une donnée à stuffer
|
243 |
|
|
dat_out <= x"7D";
|
244 |
|
|
fsm_layer2_tx <= stufcrc2_st;
|
245 |
|
|
ELSE
|
246 |
|
|
-- Si les 8 MSB ne sont pas à stuffer
|
247 |
|
|
dat_out <= crc(7 downto 0);
|
248 |
|
|
fsm_layer2_tx <= fanionfin_st; -- On va insérer le fanion de fin dans le flux
|
249 |
|
|
END IF;
|
250 |
|
|
|
251 |
|
|
WHEN stufcrc2_st =>
|
252 |
|
|
-- Etat de gestion du stuffing des 8 LSB du CRC
|
253 |
|
|
val_crc <= '0';
|
254 |
|
|
val_out <= '1';
|
255 |
|
|
IF (crc(7 downto 0) = x"7E") THEN
|
256 |
|
|
dat_out <= x"5E";
|
257 |
|
|
ELSE
|
258 |
|
|
dat_out <= x"5D";
|
259 |
|
|
END IF;
|
260 |
|
|
fsm_layer2_tx <= fanionfin_st;
|
261 |
|
|
|
262 |
|
|
WHEN fanionfin_st =>
|
263 |
|
|
-- On envoie le fanion de fin
|
264 |
|
|
dat_out <= x"7E";
|
265 |
|
|
val_crc <= '0';
|
266 |
|
|
init_crc <= '1';
|
267 |
|
|
val_out <= '1';
|
268 |
|
|
fsm_layer2_tx <= waitendsend_st; -- On va attendre la fin des transmission
|
269 |
|
|
|
270 |
|
|
WHEN waitendsend_st =>
|
271 |
|
|
-- Etat d'attente que la trame soit partie. Permet de laisser le temps au réseau privé de
|
272 |
|
|
-- reprendre la main sur le Tx
|
273 |
|
|
val_out <= '0';
|
274 |
|
|
IF (empty1_r2 = '1' AND empty2_r2 = '1') THEN
|
275 |
|
|
-- Si les 2 FIFO Tx sont vides
|
276 |
|
|
fsm_layer2_tx <= idle_st;
|
277 |
|
|
END IF;
|
278 |
|
|
|
279 |
|
|
WHEN OTHERS =>
|
280 |
|
|
fsm_layer2_tx <= idle_st;
|
281 |
|
|
|
282 |
|
|
END CASE;
|
283 |
|
|
END IF;
|
284 |
|
|
END PROCESS;
|
285 |
|
|
|
286 |
|
|
--------------------------------------------
|
287 |
|
|
-- Calcul du crc16
|
288 |
|
|
--------------------------------------------
|
289 |
|
|
inst_crc16: crc16
|
290 |
|
|
GENERIC MAP (
|
291 |
|
|
poly => x"1021" -- CCITT16
|
292 |
|
|
)
|
293 |
|
|
PORT MAP(
|
294 |
|
|
clk_sys => clk_sys,
|
295 |
|
|
rst_n => rst_n,
|
296 |
|
|
data => dat_crc, -- Dans le calcul du CRC, on prend en compte le flux déstuffé
|
297 |
|
|
val => val_crc,
|
298 |
|
|
init => init_crc,
|
299 |
|
|
crc => crc
|
300 |
|
|
);
|
301 |
|
|
|
302 |
|
|
end rtl;
|
303 |
|
|
|