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

Subversion Repositories saturn

[/] [saturn/] [trunk/] [IPCommunication/] [com_exec.vhd] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 DavidRAMBA
--============================================================================= 
2
--  TITRE : COM_EXEC
3
--  DESCRIPTION : 
4
--       Exécute les actions codées dans la trame applicative 
5
--       Gère des registres Internes (zone d'adresse de 0 à 7F)
6
--       Gère les écritures et lectures des registres externes 
7
--       (zone d'adresse de 80 à FF)
8
 
9
--  FICHIER :        com_exec.vhd 
10
--=============================================================================
11
--  CREATION 
12
--  DATE              AUTEUR    PROJET  REVISION 
13
--  10/04/2014  DRA        SATURN       V1.0 
14
--=============================================================================
15
--  HISTORIQUE  DES  MODIFICATIONS :
16
--  DATE              AUTEUR    PROJET  REVISION 
17
--=============================================================================
18
 
19
LIBRARY IEEE;
20
USE IEEE.STD_LOGIC_1164.ALL;
21
USE IEEE.STD_LOGIC_ARITH.ALL;
22
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
23
 
24
ENTITY com_exec IS
25
   GENERIC (
26
      freq_clksys : INTEGER := 48;                    -- Fréquence de l'horloge système en MHz
27
      reg_typemio : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"10";  -- Type du MIO
28
      reg_version : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"10";  -- Version du MIO
29
      ad_ref      : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"80";  -- Adresse des registre à transmettre sur synchro
30
      sz_ref      : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"04"   -- Nombre d'octets à transmetrte sur synchro
31
      );
32
   PORT (
33
      -- Ports système
34
      clk_sys     : IN  STD_LOGIC;                    -- Clock système
35
      rst_n       : IN  STD_LOGIC;                    -- Reset général système
36
      tid         : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); -- Adresse affectée au MIO (8F au reset)
37
      iid         : IN  STD_LOGIC_VECTOR(63 downto 0);-- Adresse IID du composant
38
      sync_lock   : OUT STD_LOGIC;                    -- Indique qu'on est calé sur une synchro
39
 
40
      -- Interfaces vers le bloc métier
41
      datout_write: OUT STD_LOGIC_VECTOR(7 DOWNTO 0); -- Données à écrire sur l'interface externe
42
      datout_read : IN STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Données lues sur l'interface externe
43
      ad_out      : OUT STD_LOGIC_VECTOR(6 DOWNTO 0); -- Adresse d'écriture et de lecture des données externes
44
      wr_out      : OUT STD_LOGIC;                    -- Signal d'écriture sur l'interface externe
45
      rd_out      : OUT STD_LOGIC;                    -- Signal de lecture sur l'interface externe
46
 
47
      -- Interfaces vers les modules layer2_rx
48
      activity1   : IN STD_LOGIC;                     -- 1 pulse indique qu'il y'a de l'activité sur le port de com 1
49
      activity2   : IN STD_LOGIC;                     -- 1 pulse indique qu'il y'a de l'activité sur le port de com 2
50
 
51
      -- Interfaces vers le module frame_store1
52
      datin1      : IN STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Données utiles de la couche applicative (commande, @, data)
53
      socin1      : IN STD_LOGIC;                     -- Indique que l'octet sur datin1 est le 1er d'une commande
54
      rd_datin1   : OUT STD_LOGIC;                    -- Signal de lecture d'un nouvel octet applicatif
55
      new_frame1  : IN STD_LOGIC;                     -- 1 Pulse indique qu'une nouvelle trame est disponible
56
      l7_ok1      : IN STD_LOGIC;                     -- 1 Pulse indique que la nouvelle trame est conforme du point de vue layer 7
57
      l7_overflow1: IN STD_LOGIC;                     -- Indique un débordement de la mémoire de frame_store
58
      com_dispo1  : IN STD_LOGIC;                     -- A 1 tant qu'il y'a des données de commande à traiter dans la DPRAM
59
 
60
      -- Interfaces vers le module frame_store2
61
      datin2      : IN STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Données utiles de la couche applicative (commande, @, data)
62
      socin2      : IN STD_LOGIC;                     -- Indique que l'octet sur datin2 est le 1er d'une commande
63
      rd_datin2   : OUT STD_LOGIC;                    -- Signal de lecture d'un nouvel octet applicatif
64
      new_frame2  : IN STD_LOGIC;                     -- 1 Pulse indique qu'une nouvelle trame est disponible
65
      l7_ok2      : IN STD_LOGIC;                     -- 1 Pulse indique que la nouvelle trame est conforme du point de vue layer 7
66
      l7_overflow2: IN STD_LOGIC;                     -- Indique un débordement de la mémoire de frame_store
67
      com_dispo2  : IN STD_LOGIC;                     -- A 1 tant qu'il y'a des données de commande à traiter dans la DPRAM
68
 
69
      -- Interfaces ver le module layer2_tx
70
      datsent     : OUT  STD_LOGIC_VECTOR(7 DOWNTO 0); -- Flux de données applicatives à émettre
71
                                                       -- La première donnée du flux qui suit le sof est l'@ de destination
72
      valsent     : OUT  STD_LOGIC;                    -- validant du bus datsent
73
      sof         : OUT  STD_LOGIC;                    -- Indique le début d'une trame à émettre
74
      eof         : OUT STD_LOGIC;                     -- Indique le dernier octet de la trame à émettre
75
      datsent_free: IN  STD_LOGIC;                     -- Indique que le module layer2_tx a pris en compte l'octet datsent
76
      clr_fifo_tx : OUT STD_LOGIC;                     -- Signal de purge de la FIFO Tx
77
 
78
      -- Interface vers les modules switch
79
      copy_ena1   : OUT STD_LOGIC;                     -- Autorise la copie de Rx1 sur Tx2
80
      copy_ena2   : OUT STD_LOGIC;                     -- Autorise la copie de Rx2 sur Tx1
81
 
82
      -- Interface de pilotage du module SPI
83
      reload_fpgan: OUT STD_LOGIC;                     -- Ordre de reconfiguration du FPGA
84
      spitx_dat   : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Data + commande à sérialiser
85
      spitx_val   : OUT STD_LOGIC;                     -- Validant de spitx_dat
86
      spirx_dat   : IN  STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Data reçue
87
      spirx_val   : IN STD_LOGIC;                      -- Indique des données dispo dans spirx_val
88
      spirx_next  : OUT STD_LOGIC;                     -- Lit un octet de plus dans spirx_val
89
      spi_typecom : OUT STD_LOGIC;                     -- Type de commande à éxécuter
90
      spi_execcom : OUT STD_LOGIC;                     -- Ordre d'exécution d'une commande
91
      spi_busy    : IN  STD_LOGIC;                     -- Indique que le module SPI est occupé
92
      spi_nbread  : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Nombre d 'octets à lire avec une commande de lecture
93
      spi_rstn    : OUT STD_LOGIC                      -- Reset du module SPI
94
      );
95
END com_exec;
96
 
97
ARCHITECTURE rtl OF com_exec IS
98
   CONSTANT typ_sync     : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"00";  -- Type pour trame de synchronisation
99
   CONSTANT typ_reqnoseq : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"08";  -- Type pour trame de requête non sécuritaire
100
   CONSTANT typ_repnoseq : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"80";  -- Type pour trame de réponse non sécuritaire
101
   CONSTANT typ_atttid   : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"3C";  -- Type pour trame d'attribution de TID
102
   CONSTANT com_write    : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"01";  -- Commande d'écriture dans une requête non sec
103
   CONSTANT com_read     : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"02";  -- Commande de lecture dans une requête non sec
104
 
105
 
106
   -- Définition des adresses des registres internes
107
   CONSTANT adreg_mac   : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(0, 7);
108
   CONSTANT adreg_iid   : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(8, 7);
109
   CONSTANT adreg_typ   : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(16, 7);
110
   CONSTANT adreg_ver   : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(17, 7);
111
   CONSTANT adreg_verpic: STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(18, 7);
112
   CONSTANT adreg_tid   : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(19, 7);
113
   CONSTANT adreg_sid   : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(20, 7);
114
   -- CONSTANT adreg_outrep: STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(23, 7);
115
   CONSTANT adreg_tcyc  : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(24, 7);
116
   CONSTANT adreg_status: STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(25, 7);
117
   --CONSTANT adreg_cnfrep: STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(26, 7);
118
   --CONSTANT adreg_cnfcyc: STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(27, 7);
119
   CONSTANT adreg_adref : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(28, 7);
120
   CONSTANT adreg_szref : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(29, 7);
121
   CONSTANT adreg_toco1 : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(30, 7);
122
   CONSTANT adreg_toco2 : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(31, 7);
123
   --CONSTANT adreg_seq   : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(32, 7);
124
   CONSTANT adreg_toac1 : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(33, 7);
125
   CONSTANT adreg_toac2 : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(34, 7);
126
   CONSTANT adreg_sync  : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(35, 7);
127
   CONSTANT adreg_for   : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(36, 7);
128
   CONSTANT adreg_conf  : STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(37, 7);
129
   CONSTANT adreg_loadfpga: STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(124, 7);
130
   CONSTANT adreg_spinbr: STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(125, 7);
131
   CONSTANT adreg_spictl: STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(126, 7);
132
   CONSTANT adreg_spidat: STD_LOGIC_VECTOR(6 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(127, 7);
133
 
134
   -- Définition des registres internes
135
   SIGNAL reg_tid       : STD_LOGIC_VECTOR(7 DOWNTO 0);
136
   SIGNAL reg_config    : STD_LOGIC_VECTOR(7 DOWNTO 0);
137
   SIGNAL reg_status    : STD_LOGIC_VECTOR(7 DOWNTO 0);
138
   SIGNAL reg_adref     : STD_LOGIC_VECTOR(7 DOWNTO 0);
139
   SIGNAL reg_szref     : STD_LOGIC_VECTOR(7 DOWNTO 0);
140
   SIGNAL reg_cpttoco1  : STD_LOGIC_VECTOR(7 DOWNTO 0);
141
   SIGNAL reg_cpttoco2  : STD_LOGIC_VECTOR(7 DOWNTO 0);
142
   SIGNAL reg_cpttoac1  : STD_LOGIC_VECTOR(7 DOWNTO 0);
143
   SIGNAL reg_cpttoac2  : STD_LOGIC_VECTOR(7 DOWNTO 0);
144
   SIGNAL reg_cptsync   : STD_LOGIC_VECTOR(7 DOWNTO 0);
145
   SIGNAL reg_cptfor    : STD_LOGIC_VECTOR(7 DOWNTO 0);
146
   SIGNAL reg_tcyc      : STD_LOGIC_VECTOR(7 DOWNTO 0);
147
   SIGNAL reg_spinbr    : STD_LOGIC_VECTOR(7 DOWNTO 0);
148
   SIGNAL reg_spictl    : STD_LOGIC_VECTOR(7 DOWNTO 0);
149
   SIGNAL reg_loadfpga  : STD_LOGIC_VECTOR(7 DOWNTO 0);
150
 
151
   -- Signaux de gestion du cycle
152
   SIGNAL synchro       : STD_LOGIC;               -- 1 Pulse sur réception d'1 trame de synchro valide
153
   SIGNAL start_cycle   : STD_LOGIC;               -- 1 Pulse indique le début d'un cycle (sur synhcro ou timer interne)
154
   SIGNAL tc_tcyc       : STD_LOGIC_VECTOR(15 DOWNTO 0); -- Pour calculer reg_tcyc * 100
155
   SIGNAL mescycle      : STD_LOGIC_VECTOR(16 DOWNTO 0); -- compteur de mesure de périodes de 10us
156
   SIGNAL mes10us       : STD_LOGIC_vector(10 DOWNTO 0); -- Compteur de période de clk_sys pour mesurer 10us
157
   SIGNAL synchro_lock  : STD_LOGIC;               -- A 0 tant qu'on a pas reçu une première synchro
158
   SIGNAL win_syncbefore: STD_LOGIC;               -- Signal de validité d'une syncro en avance (dernier quart d'un cycle de com)
159
   SIGNAL win_syncafter : STD_LOGIC;               -- Signal de validité d'une synchro en retard (premier quart d'un cycle de com)
160
   SIGNAL synchro_miss  : STD_LOGIC;               -- 1 Pulse à 1 indique qu'on a pas reçu de trame de synhcro sur une durée de 1.125xTcyc
161
   SIGNAL cpt_seq       : STD_LOGIC_VECTOR(7 DOWNTO 0); -- Compteur de numéro de cycle de communication en cours
162
   SIGNAL mem_sync      : STD_LOGIC;               -- Pour mémoriser le fait que le start_cycle est issue d'une trame de synchro
163
 
164
   -- Signaux de gestion des monitoring
165
   SIGNAL mem_activity1 : STD_LOGIC;               -- Pour mémoriser une activité sur le port 1 entre 2 synchros
166
   SIGNAL mem_activity2 : STD_LOGIC;               -- Pour mémoriser une activité sur le port 2entre 2 synchros
167
   SIGNAL err_toco      : STD_LOGIC;               -- 1 Pulse indique une trame réçue sur un port mais pas sur l'autre
168
   SIGNAL voie_toco     : STD_LOGIC;               -- 0 pour err_toco sur le port 1, 1 pour err_toco sur le port 2
169
 
170
   -- Signaux d'interprétation et d'exécution des commandes
171
   SIGNAL datin         : STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Données applicatives à traiter (voie 1 ou 2 multiplexée)
172
   SIGNAL rd_com        : STD_LOGIC;                     -- Ordre de fetch d'un nouvel octet de donnée applicative 
173
   SIGNAL com_dispo     : STD_LOGIC;                     -- Multiplexage de com_dispo 1 ou 2 selon la voie
174
   SIGNAL rd_combuf     : STD_LOGIC;                     -- Buffer provisoire pour multiplexer rd_com
175
   SIGNAL sel_voie      : STD_LOGIC;                     -- A 0 si on traite la voie 1, a 1 si on traite la voie 2
176
   SIGNAL typ_field     : STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Pour mémoriser le type de trame
177
   SIGNAL seq_field     : STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Pour mémoriser le champ SEQ de la trmae de synhcro
178
   SIGNAL com_field     : STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Pour mémoriser le champ COM d'une trame de requête non secu
179
   --SIGNAL ad_source     : STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Pour mémoriser l'adresse de l'expéditeur de la commande
180
   SIGNAL oldcom1       : STD_LOGIC_vector(9 DOWNTO 0);  -- Pour stocker jusqu'à 3 commandes
181
   SIGNAL oldcom2       : STD_LOGIC_vector(9 DOWNTO 0);  -- MSB = voie de réception de la commande, MSB - 1 : le registre est libre (0) ou occupé (1)
182
   SIGNAL oldcom3       : STD_LOGIC_vector(9 DOWNTO 0);  -- 8 LSB : champs TYP de la commande enregistrée 
183
   SIGNAL store_com     : STD_LOGIC;                     -- 1 pulse pour enregistrer la commande en cours dans un oldcomx
184
   SIGNAL delete_com    : STD_LOGIC;                     -- 1 pulse pour effacer la commande en cours des oldcomx
185
   SIGNAL com_recue     : STD_LOGIC;                     -- A 1 si la commande en cours a déjà été enregistrée dans un oldcomx
186
   SIGNAL synchro_valide: STD_LOGIC;                     -- A 1 si la commande en cours est une synchrone valide
187
   SIGNAL iid_temp      : STD_LOGIC_vector(63 DOWNTO 0); -- Registre à décalage pour la réception de l'adresse IID
188
   SIGNAL cpt_byt       : STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Compteur d'octets en émission ou réception
189
   SIGNAL wr            : STD_LOGIC;                     -- Signal d'écriture d'un octet à l'adresse ad_buf
190
   SIGNAL rd            : STD_LOGIC;                     -- Signal de lecture d'un octet à l'adresse ad_buf
191
   SIGNAL rd_r          : STD_LOGIC;                     -- Pour retarder le signal rd de 1 cycle
192
   SIGNAL ad_buf        : STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Adresse de lecture ou d'écriture
193
   SIGNAL wr_int        : STD_LOGIC;                     -- Signal d'écriture si ad_buf pointe sur un registre interne
194
   SIGNAL rd_int        : STD_LOGIC;                     -- Signal de lecture si ad_buf pointe sur un registre interne
195
   SIGNAL dataread      : STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Multiplexeur pour la lecture
196
   SIGNAL memadbuf7     : STD_LOGIC;                     -- Pour latcher le MSB du adbus lors d'une lecture
197
   SIGNAL datawrite     : STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Pour latcher les données à écrire
198
   SIGNAL datint_read   : STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Multiplexeur pour la lecture des registres internes
199
   SIGNAL socin         : STD_LOGIC;                     -- Multiplexage des signaux socinx
200
   SIGNAL synchro_outwin: STD_LOGIC;                     -- A 1 sur une synchro en dehors des fenêtres autorisées
201
   -- Signaux de gestion des SYNC absents
202
   SIGNAL cpt_syncmiss  : STD_LOGIC_VECTOR(7 DOWNTO 0);  -- Compteur de trames de synhcro absentes
203
 
204
   -- Machine d'état de gestion du module
205
   TYPE comexec_type IS (idle_st, rectyp_st, getadsrce_st, attribtid_st, purgesidsync_st, getseq_st, purgecrcsync_st, getadbuf_st, getnr_st, getcom_st,
206
                         writebyt_st, startframe_st, sendseq_st, sendcom_st, sendsrce_st, sendadr_st, sendnr_st, senddata_st,
207
                         sendstatus_st, endframe_st,purgecom_st);
208
   SIGNAL fsm_comexec   : comexec_type;
209
 
210
 
211
 
212
begin
213
   --------------------------------------------
214
   -- Affectation des sorties de configuration du module
215
   --------------------------------------------
216
   sync_lock <= synchro_lock;    -- Indique que le module est calé sur une synchro
217
   tid <= reg_tid;               -- Adresse attribuée au MIO à destination des autres modules
218
   copy_ena1 <= reg_config(0);   -- Autorisation de recopie du port 1 sur le port 2
219
   copy_ena2 <= reg_config(1);   -- Autorisationd e recopie du port 2 sur le port 1
220
   clr_fifo_tx <= '0';           -- On n'utilsie pas le clr des FIFO Tx pour l'instant
221
   spi_typecom <= reg_spictl(0); -- Type de commande sur le port SPI PROM
222
   spi_execcom <= reg_spictl(3); -- Lance l'exécution d'une commande SPI PROM
223
   spi_rstn <= reg_spictl(4);    -- Reset du module SPI PROM
224
   spi_nbread <= reg_spinbr;     -- Nombre d'octets à lire avec une commande lecture en PROM FPGA
225
 
226
   --------------------------------------------
227
   -- Gestion du signal de reprogrammation du FPGA
228
   --------------------------------------------
229
   gest_progb : PROCESS(clk_sys, rst_n)
230
   BEGIN
231
      IF (rst_n = '0') THEN
232
         reload_fpgan <= '1';
233
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
234
         IF (reg_spictl(4) = '0') THEN
235
         -- Tant que le reset du module SPI est actif
236
            reload_fpgan <= '1';             -- On fait rien
237
         ELSIF (reg_loadfpga = x"31") THEN
238
         -- Si le module SPI est actif et qu'on trouve la valeur magique dan le registre
239
            reload_fpgan <= '0';             -- On force la reprogrammation
240
         END IF;
241
      END IF;
242
   END PROCESS;
243
 
244
   --------------------------------------------
245
   -- Gestion des bus d'accès mémoire 
246
   --    interne (module SPI inclus)
247
   --    externe
248
   --------------------------------------------
249
   ad_out <= ad_buf(6 DOWNTO 0);    -- Bus d'accès aux registres externes (7 bits de long)
250
   datout_write <= datawrite;       -- Donnée à écrire dans un registre externe
251
   wr_int <= wr AND NOT(ad_buf(7)); -- On écrit un registre interne selon le MSB de l'@
252
   -- On lit un registre interne selon le MSB de l'@
253
   rd_int <= rd AND datsent_free AND NOT(ad_buf(7));  -- On ne lit rien si le module destination n'est pas prêt
254
   wr_out <= wr AND ad_buf(7);      -- On écrit un registre externe selon le MSB de l'@
255
   -- On lit un registre externe selon le MSB de l'@
256
   rd_out <= rd AND datsent_free AND ad_buf(7);       -- On ne lit rien si le module destination n'est pas prêt 
257
 
258
   -- On écrit dans la FIFO de commande SPI si signal d'écriture à l'adresse de la FIFO
259
   spitx_val <= wr_int WHEN (ad_buf(6 DOWNTO 0) =  adreg_spidat) ELSE '0';
260
   spitx_dat <= datawrite;          -- la donnée est directement sur le bus d'écriture (passe pas par un regditre)
261
 
262
   -- On fetche un octet de plus dans la FIFO de lecture SPI si signal de lecture à l'adresse de la FIFO
263
   spirx_next<= rd_int WHEN (ad_buf(6 DOWNTO 0) =  adreg_spidat) ELSE '0';
264
 
265
   --------------------------------------------
266
   -- Gestion de la lecture sur le bus interne
267
   --------------------------------------------
268
   gest_readint : PROCESS(clk_sys, rst_n)
269
   BEGIN
270
      IF (rst_n = '0') THEN
271
         datint_read <= (others => '0');
272
         memadbuf7 <= '0';
273
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
274
         IF (rd_int = '1') THEN
275
            CASE ad_buf(6 DOWNTO 0) IS
276
            -- Décodage du registre lu en focntion de l'adresse du registre
277
               WHEN adreg_mac   | adreg_mac+1 | adreg_mac+2 | adreg_mac+3 |
278
                    adreg_mac+4 | adreg_mac+5 | adreg_mac+6 | adreg_mac+7 => datint_read <= x"FF";
279
               WHEN adreg_iid =>    datint_read <= iid( 7 DOWNTO  0);
280
               WHEN adreg_iid+1 =>  datint_read <= iid(15 DOWNTO  8);
281
               WHEN adreg_iid+2 =>  datint_read <= iid(23 DOWNTO 16);
282
               WHEN adreg_iid+3 =>  datint_read <= iid(31 DOWNTO 24);
283
               WHEN adreg_iid+4 =>  datint_read <= iid(39 DOWNTO 32);
284
               WHEN adreg_iid+5 =>  datint_read <= iid(47 DOWNTO 40);
285
               WHEN adreg_iid+6 =>  datint_read <= iid(55 DOWNTO 48);
286
               WHEN adreg_iid+7 =>  datint_read <= iid(63 DOWNTO 56);
287
               WHEN adreg_typ =>    datint_read <= reg_typemio;
288
               WHEN adreg_ver =>    datint_read <= reg_version;
289
                                        WHEN adreg_verpic => datint_read <= x"00";
290
               WHEN adreg_tid =>    datint_read <= reg_tid;
291
               WHEN adreg_sid   | adreg_sid+1 | adreg_sid+2 => datint_read <= x"FF";
292
               WHEN adreg_tcyc =>   datint_read <= reg_tcyc;
293
               WHEN adreg_status => datint_read <= reg_status;
294
               WHEN adreg_adref =>  datint_read <= reg_adref;
295
               WHEN adreg_szref =>  datint_read <= reg_szref;
296
               WHEN adreg_toco1 =>  datint_read <= reg_cpttoco1;
297
               WHEN adreg_toco2 =>  datint_read <= reg_cpttoco2;
298
               WHEN adreg_toac1 =>  datint_read <= reg_cpttoac1;
299
               WHEN adreg_toac2 =>  datint_read <= reg_cpttoac2;
300
               WHEN adreg_sync =>   datint_read <= reg_cptsync;
301
               WHEN adreg_for =>    datint_read <= reg_cptfor;
302
               WHEN adreg_conf =>   datint_read <= reg_config;
303
               WHEN adreg_spinbr => datint_read <= reg_spinbr;
304
               WHEN adreg_spictl => datint_read <= spirx_val & reg_spictl(6 DOWNTO 4) & spi_busy & reg_spictl(2 DOWNTO 0);
305
               WHEN adreg_spidat => datint_read <= spirx_dat;
306
               WHEN OTHERS =>       datint_read <= reg_status;
307
            END CASE;
308
         END IF;
309
         IF (rd = '1') THEN
310
         -- sur une lecture, que ce soit interne ou externe
311
            memadbuf7 <= ad_buf(7);       -- On mémrosie quelle zone mémoire était lue
312
         END IF;
313
      END IF;
314
   END PROCESS;
315
   -- Lorsqu'on lit une donnée, on multiplexe soit le bus externe, soit les registres internes selon le MSB de l'adresse de lecture
316
   dataread <= datout_read WHEN memadbuf7 = '1' ELSE datint_read;
317
 
318
   --------------------------------------------
319
   -- Gestion des écritures dans les registres internes de configuration
320
   -- L'écriture dans les registres internes de status est gérée au cas par cas.
321
   --------------------------------------------
322
   gest_wrreg : PROCESS(clk_sys, rst_n)
323
   BEGIN
324
      IF (rst_n = '0') THEN
325
         reg_config <= x"03";
326
         reg_adref  <= ad_ref;
327
         reg_szref  <= sz_ref;
328
         reg_tcyc   <= x"FF";
329
         reg_spinbr   <= x"00";
330
         reg_loadfpga <= x"00";
331
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
332
         IF (wr_int = '1') THEN
333
            CASE ad_buf(6 DOWNTO 0) IS
334
            -- Mise à jour du registre en focntion du décodage de l'adresse du registre
335
               WHEN adreg_conf =>
336
                  reg_config <= datawrite;
337
               WHEN adreg_adref =>
338
                  reg_adref <= datawrite;
339
               WHEN adreg_szref =>
340
                  reg_szref <= datawrite;
341
               WHEN adreg_tcyc =>
342
                  reg_tcyc <=  datawrite;
343
               WHEN adreg_loadfpga =>
344
                  IF (reg_spictl(4) = '1') THEN
345
                  -- On autorise la mise à jour du registre que si le reste SPI est relaché
346
                     reg_loadfpga <= datawrite;
347
                  END IF;
348
               WHEN adreg_spinbr =>
349
                  reg_spinbr <= datawrite;
350
               WHEN OTHERS =>
351
                  NULL;
352
            END CASE;
353
         END IF;
354
         IF (wr_int = '1' AND ad_buf(6 DOWNTO 0) = adreg_spictl) THEN
355
            reg_spictl <= datawrite;
356
         ELSE
357
         -- On s'assure que le pulse de commande du SPI ne dure qu'un seul cycle
358
            reg_spictl(3) <= '0';
359
         END IF;
360
      END IF;
361
   END PROCESS;
362
 
363
   ----------------------------------
364
   -- Gestion du registre de status
365
   ----------------------------------
366
   gest_stat : PROCESS(clk_sys, rst_n)
367
   BEGIN
368
      IF (rst_n = '0') THEN
369
      -- Par défaut le bit REP est à 1
370
         reg_status <= x"80";
371
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
372
         IF (rd_int = '1' AND ad_buf(6 DOWNTO 0) = adreg_status) OR
373
            (fsm_comexec = sendstatus_st AND datsent_free = '1') THEN
374
         -- Le registre status est resetté à chaque lecture
375
            reg_status <= x"00";
376
         ELSE
377
            IF (err_toco = '1') THEN
378
            -- Gestion du bit CNR (trame non reçue sur un des ports)
379
               reg_status(0) <= '1';
380
            END IF;
381
            -- Bit ESE non implémenté
382
            IF (start_cycle = '1' AND mem_activity1 = '0') THEN
383
            -- Gestion du bit NA1 (pas d'activité sur le port 1)
384
               reg_status(2) <= '1';
385
            END IF;
386
            IF (start_cycle = '1' AND mem_activity2 = '0') THEN
387
            -- Gestion du bit NA2 (pas d'activité sur le port 2)
388
               reg_status(3) <= '1';
389
            END IF;
390
            IF (synchro_miss = '1') THEN
391
            -- Gestion du bit NTS (pas de trame de synhcro)
392
               reg_status(4) <= '1';
393
            END IF;
394
            IF (new_frame1 = '1' AND l7_ok1 = '0') OR
395
               (new_frame2 = '1' AND l7_ok2 = '0') THEN
396
            -- Gestion du bit BFO (format de trame non supporté)
397
               reg_status(5) <= '1';
398
            END IF;
399
            reg_status(6) <= sel_voie;
400
            reg_status(7) <= '0';
401
         END IF;
402
      END IF;
403
   END PROCESS;
404
 
405
   --------------------------------------------
406
   -- Gestion de la synchro
407
   --------------------------------------------
408
   gest_sync : PROCESS(clk_sys, rst_n)
409
   BEGIN
410
      IF (rst_n = '0') THEN
411
         cpt_syncmiss <= (others => '0');
412
         synchro_lock <= '0';
413
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
414
         IF (synchro_outwin = '1' AND synchro_lock = '1') THEN
415
         -- Sur synchro en dehors de la fenêtre alors qu'on est déjà locké
416
            cpt_syncmiss <= (others => '0');    -- On annule le compteur de trame de sync manquante
417
            synchro_lock <= '0';                -- On se délocke de la synchro d'avant
418
         ELSE
419
            IF (synchro = '1') THEN
420
            -- Sur chaque trame de synchro traitée
421
               synchro_lock <= '1';
422
               cpt_syncmiss <= (others => '0');
423
            ELSIF (synchro_miss = '1') THEN
424
            -- Sur chaque cycle sans trame de synchro
425
               IF (cpt_syncmiss /= x"FF") THEN
426
               -- On comtpe de 0 à 255 et on s'arrêt de compter
427
                  cpt_syncmiss <= cpt_syncmiss + 1;
428
               ELSE
429
                  synchro_lock <= '0';          -- On considère qu'on a perdu la synchro au bout de 255 cycles sans synchro
430
               END IF;
431
            END IF;
432
         END IF;
433
      END IF;
434
   END PROCESS;
435
 
436
   --------------------------------------------
437
   -- Gestion du temps de cycle de communication
438
   --------------------------------------------
439
   gest_cycle : PROCESS(clk_sys, rst_n)
440
   BEGIN
441
      IF (rst_n = '0') THEN
442
         mes10us <= (others => '0');
443
         mescycle <= CONV_STD_LOGIC_VECTOR(1, mescycle'LENGTH);
444
         tc_tcyc <= (OTHERS => '0');
445
         start_cycle <= '0';
446
         win_syncbefore <= '0';
447
         win_syncafter <= '0';
448
         synchro_miss <= '0';
449
         cpt_seq <= (others => '0');
450
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
451
         --tc_tcyc <= reg_tcyc * 100;       -- reg_tcyc est en périodes de 1ms mais la mesure se fait en périodes de 10us
452
         tc_tcyc <= EXT(reg_tcyc & "000000", tc_tcyc'LENGTH) + EXT(reg_tcyc & "00000", tc_tcyc'LENGTH) + EXT(reg_tcyc & "00", tc_tcyc'LENGTH);
453
         IF (synchro = '1') THEN
454
         -- Si on a reçu une trame de synchro valide
455
            mes10us <= (others => '0');            -- Compteur de durée de 10us
456
            mescycle <= CONV_STD_LOGIC_VECTOR(1, mescycle'LENGTH);   -- Compteur de périodes de 10us (compte de 1 à TCYC)
457
            start_cycle <= '1';                    -- On indique au module un début de cycle
458
            win_syncbefore <= '0';                 -- On a plus besoin de la fenêtre de validité de synchro en avance
459
            win_syncafter <= '1';                  -- Par contre, onpeut recevoir une synchro en retard
460
            synchro_miss <= '0';
461
            cpt_seq <= seq_field;                  -- Le numéro de cycle est celui de la commande
462
         ELSE
463
            IF (mes10us = CONV_STD_LOGIC_VECTOR(freq_clksys*10-1, mes10us'length)) THEN
464
            -- Toutes les 10 us
465
               mes10us <= (others => '0');
466
               IF (mescycle = ('0' & tc_tcyc) + ("0000" & tc_tcyc(tc_tcyc'LEFT DOWNTO 3))) THEN
467
               -- Si on a mesuré 1.125xTCYC
468
                  win_syncbefore <= '0';           -- Les fenêtres de validité sont annulées
469
                  win_syncafter <= '0';
470
                  -- On remet le compteur à 0.125xTCYC pour mesure 1 TCYC entre 0.125 et 1.125TCYC
471
                  mescycle <= ("0000" & tc_tcyc(tc_tcyc'LEFT DOWNTO 3)) + 1;
472
                  synchro_miss <= '1';             -- On indique qu'on a manqué une synchro sur la période précédente
473
                  start_cycle <= '1';              -- On démarre un cycle sur ordre interne (pas de trame de synchro)
474
               ELSE
475
               -- Si on a pas encore atteind le 1.125xTCYC
476
                  mescycle <= mescycle + 1;
477
                  IF (mescycle = ('0' & tc_tcyc) - ("0000" & tc_tcyc(tc_tcyc'LEFT DOWNTO 3))) THEN
478
                  -- Si on est à 0.875x TCYC
479
                     win_syncbefore <= '1';        -- On active le signal de validité en avance de la synchro
480
                     win_syncafter <= '0';         -- Par contre la synchro en retard ne serait pas valide
481
                  ELSIF (mescycle = ('0' & tc_tcyc)) THEN
482
                  -- Si on est pile à TCYC
483
                     win_syncbefore <= '0';
484
                     win_syncafter <= '1';         -- On active le signal de validité en retard de la synchro
485
                     cpt_seq <= cpt_seq + 1;       -- On est dans le numéro de cycle suivant
486
                  ELSIF (mescycle = ("0000" & tc_tcyc(tc_tcyc'LEFT DOWNTO 3))) THEN
487
                  -- Si on est pile à 0.125xTCYC
488
                     win_syncafter <= '0';         -- On annule le signal de validité en retard de la synchro
489
                 END IF;
490
               END IF;
491
            ELSE
492
            -- pour tous les autres états dans le cycle
493
               start_cycle <= '0';                 -- On assure que les signaux ne durent qu'un clk
494
               synchro_miss <= '0';
495
               mes10us <= mes10us + 1;
496
            END IF;
497
         END IF;
498
      END IF;
499
   END PROCESS;
500
 
501
   --------------------------------------------
502
   -- Gestion des compteurs de monitoring
503
   --------------------------------------------
504
   -- Compteur de trames avec un mauvais format (champs invalides, CRC faux, ...)
505
   gest_for : PROCESS(clk_sys, rst_n)
506
   BEGIN
507
      IF (rst_n = '0') THEN
508
         reg_cptfor <= (others => '0');
509
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
510
         IF (rd_int = '1' AND ad_buf(6 DOWNTO 0) = adreg_for) THEN
511
         -- Le registre est remis à 0 ou à 1 lors d'une lecture selon la condition de génération
512
            IF (new_frame1 = '1' AND l7_ok1 = '0') OR (new_frame2 = '1' AND l7_ok2 = '0') THEN
513
               reg_cptfor(0) <= '1';
514
            ELSE
515
               reg_cptfor(0) <= '0';
516
            END IF;
517
            reg_cptfor(7 DOWNTO 1) <= "0000000";
518
         ELSIF (reg_cptfor /= x"FF") THEN
519
            IF (new_frame1 = '1' AND l7_ok1 = '0') OR
520
               (new_frame2 = '1' AND l7_ok2 = '0') THEN
521
            -- Sur réception d'une nouvelle trame avec un mauvais format quel que soit le port
522
               reg_cptfor <= reg_cptfor + 1;
523
            END IF;
524
         END IF;
525
      END IF;
526
   END PROCESS;
527
 
528
   -- Compteur d'absence de trame de synchro
529
   gest_abssync : PROCESS(clk_sys, rst_n)
530
   BEGIN
531
      IF (rst_n = '0') THEN
532
         reg_cptsync <= (others => '0');
533
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
534
         IF (rd_int = '1' AND ad_buf(6 DOWNTO 0) = adreg_sync) THEN
535
         -- Le registre est remis à 0 ou à 1 lors d'une lecture selon la condition de génération
536
            reg_cptsync <= "0000000" & synchro_miss;
537
         ELSIF (reg_cptsync /= x"FF") THEN
538
            IF (synchro_miss = '1') THEN
539
               reg_cptsync <= reg_cptsync + 1;
540
            END IF;
541
         END IF;
542
      END IF;
543
   END PROCESS;
544
 
545
   -- Compteur de cycles sans activité sur le port 1
546
   gest_toac1 : PROCESS(clk_sys, rst_n)
547
   BEGIN
548
      IF (rst_n = '0') THEN
549
         reg_cpttoac1 <= (others => '0');
550
         mem_activity1 <= '1';
551
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
552
         IF (rd_int = '1' AND ad_buf(6 DOWNTO 0) = adreg_toac1) THEN
553
         -- Le registre est remis à 0 ou à 1 lors d'une lecture selon la condition de génération         
554
            IF (start_cycle = '1' AND mem_activity1 = '0') THEN
555
               reg_cpttoac1(0) <= '1';
556
            ELSE
557
               reg_cpttoac1(0) <= '0';
558
            END IF;
559
            reg_cpttoac1(7 DOWNTO 1) <= "0000000";
560
         ELSIF (reg_cpttoac1 /= x"FF") THEN
561
            IF (start_cycle = '1' AND mem_activity1 = '0') THEN
562
            -- A chaque début de cycle, si on a pas eu du tout d'activité
563
               reg_cpttoac1 <= reg_cpttoac1 + 1;
564
            END IF;
565
         END IF;
566
         IF (activity1 = '1') THEN
567
         -- Bascule JK de mémorisation d'activité
568
            mem_activity1 <= '1';
569
         ELSIF (start_cycle = '1') THEN
570
         -- Remise à 0 à chaque début de cycle
571
            mem_activity1 <= '0';
572
         END IF;
573
      END IF;
574
   END PROCESS;
575
 
576
   -- Compteur de cycles sans activité sur le port 2
577
   gest_toac2 : PROCESS(clk_sys, rst_n)
578
   BEGIN
579
      IF (rst_n = '0') THEN
580
         reg_cpttoac2 <= (others => '0');
581
         mem_activity2 <= '1';
582
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
583
         IF (rd_int = '1' AND ad_buf(6 DOWNTO 0) = adreg_toac2) THEN
584
         -- Le registre est remis à 0 ou à 1 lors d'une lecture selon la condition de génération         
585
            IF (start_cycle = '1' AND mem_activity2 = '0') THEN
586
               reg_cpttoac2(0) <= '1';
587
            ELSE
588
               reg_cpttoac2(0) <= '0';
589
            END IF;
590
            reg_cpttoac2(7 DOWNTO 1) <= "0000000";
591
         ELSIF (reg_cpttoac2 /= x"FF") THEN
592
            IF (start_cycle = '1' AND mem_activity2 = '0') THEN
593
               reg_cpttoac2 <= reg_cpttoac2 + 1;
594
            END IF;
595
         END IF;
596
         IF (activity2 = '1') THEN
597
            mem_activity2 <= '1';
598
         ELSIF (start_cycle = '1') THEN
599
            mem_activity2 <= '0';
600
         END IF;
601
      END IF;
602
   END PROCESS;
603
 
604
   -- Compteur de trames reçues sur le port 2 mais pas sur le port 1 durant le cycle
605
   gest_toco1 : PROCESS(clk_sys, rst_n)
606
   BEGIN
607
      IF (rst_n = '0') THEN
608
         reg_cpttoco1 <= (others => '0');
609
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
610
         IF (rd_int = '1' AND ad_buf(6 DOWNTO 0) = adreg_toco1) THEN
611
         -- Sur lecture du registre, remise à 0 ou à 1 du compteur selon la condition de généraltion de l'évènement
612
            IF (err_toco = '1' AND voie_toco = '0') THEN
613
               reg_cpttoco1(0) <= '1';
614
            ELSE
615
               reg_cpttoco1(0) <= '0';
616
            END IF;
617
            reg_cpttoco1(7 DOWNTO 1) <= "0000000";
618
         ELSIF (reg_cpttoco1 /= x"FF") THEN
619
            IF (err_toco = '1' AND voie_toco = '0') THEN
620
            -- Si on a une trame absente (err_toco) sur le voie 1 (voie_toco)
621
               reg_cpttoco1 <= reg_cpttoco1 + 1;
622
            END IF;
623
         END IF;
624
      END IF;
625
   END PROCESS;
626
 
627
   -- Compteur de trames reçues sur le port 1 mais pas sur le port 2 durant le cycle
628
   gest_toco2 : PROCESS(clk_sys, rst_n)
629
   BEGIN
630
      IF (rst_n = '0') THEN
631
         reg_cpttoco2 <= (others => '0');
632
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
633
         IF (rd_int = '1' AND ad_buf(6 DOWNTO 0) = adreg_toco2) THEN
634
            IF (err_toco = '1' AND voie_toco = '1') THEN
635
               reg_cpttoco2(0) <= '1';
636
            ELSE
637
               reg_cpttoco2(0) <= '0';
638
            END IF;
639
            reg_cpttoco2(7 DOWNTO 1) <= "0000000";
640
         ELSIF (reg_cpttoco2 /= x"FF") THEN
641
            IF (err_toco = '1' AND voie_toco = '1') THEN
642
            -- Si on a une trame absente (err_toco) sur le voie 2 (voie_toco)
643
               reg_cpttoco2 <= reg_cpttoco2 + 1;
644
            END IF;
645
         END IF;
646
      END IF;
647
   END PROCESS;
648
 
649
   --------------------------------------------
650
   -- multiplexage des données selon si on traite la voie 1 ou la voie 2
651
   --------------------------------------------
652
   datin <= datin1 WHEN (sel_voie = '0') ELSE datin2;    -- Sélection de la donnée à traiter
653
   socin <= socin1 WHEN (sel_voie = '0') ELSE socin2;    -- Sélection du signal soc selon la voie
654
   rd_datin1 <= rd_combuf WHEN (sel_voie = '0') ELSE '0';-- On lit un octet de plus dans le bon buffer
655
   rd_datin2 <= rd_combuf WHEN (sel_voie = '1') ELSE '0';
656
   com_dispo <= com_dispo1 WHEN (sel_voie = '0') ELSE com_dispo2; -- Il y'a une commande dispo sur la voie sélectionnée
657
 
658
   -- Condition de lecture dans une méoire de commande. Si on est en purge, on lit jusqu'à la trame suivante 
659
   -- ou bien que la méoire soit vide
660
   rd_combuf <= rd_com AND com_dispo AND NOT(socin) WHEN (fsm_comexec = purgecom_st) ELSE
661
                rd_com AND com_dispo;
662
 
663
   --------------------------------------------
664
   -- Mémorisation des commandes déjà reçues dans le cycle
665
   -- Format des oldcom
666
   --    MSB : Voie où la commande a été reçue
667
   --  MSB-1 : Le oldcom est occupé (une commande est mémorisée)
668
   --  8 LSB : champs de la commande
669
   -- Les oldcom sont gérés comme une FIFO (oldcom1 est le premier remplit)
670
   --------------------------------------------
671
   mem_oldcom : PROCESS(clk_sys, rst_n)
672
   BEGIN
673
      IF (rst_n = '0') THEN
674
         oldcom1 <= (others => '0');
675
         oldcom2 <= (others => '0');
676
         oldcom3 <= (others => '0');
677
         err_toco <= '0';
678
         voie_toco <= '0';
679
         mem_sync <= '0';
680
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
681
         IF (synchro = '1') THEN
682
         -- mem_sync est une bascule JK de mémorisation de réception d'une trame de synchro dans le cycle en cours
683
            mem_sync <= '1';
684
         ELSIF (start_cycle = '1') THEN
685
         -- A chaque début de cycle (qu'il soit sur réception de synchro ou timer)
686
            mem_sync <= '0';
687
         END IF;
688
         IF (start_cycle = '1') THEN
689
         -- Au début d'un cycle
690
            IF (mem_sync = '1') THEN
691
            -- Si ce cycle a été induit par une trame de synchro
692
            -- On utilise typ_sync (en dur) au lieu de typ_field car typ_field est écrasé pour la trame réflexe
693
               oldcom1 <= sel_voie & '1' & typ_sync; -- On mémorise la commande
694
               oldcom2(8) <= '0';         -- Au début d'un cycle initié par une trame de synchro
695
               oldcom3(8) <= '0';         -- On purge les FIFO oldcom
696
            END IF;
697
            IF (oldcom1(8) = '1') THEN
698
            -- Si la première case mémoire n'était pas vide
699
               err_toco <= '1';              -- Ca veut dire qu'une commande d'une cycle précédent n'a pas eu sa jumelle 
700
               voie_toco <= NOT(oldcom1(9)); -- On va incrémenter le compteur opposé au port
701
            ELSE
702
               err_toco <= '0';
703
            END IF;
704
         ELSIF (store_com = '1') THEN
705
         -- Sur réception d'un ordre de stockage de la commande, on cherche la première case vide
706
            IF (oldcom1(8) = '0') THEN
707
               oldcom1 <= sel_voie & '1' & typ_field;
708
            ELSIF (oldcom2(8) = '0') THEN
709
               oldcom2 <= sel_voie & '1' & typ_field;
710
            ELSIF (oldcom3(8) = '0') THEN
711
               oldcom3 <= sel_voie & '1' & typ_field;
712
            ELSE
713
            -- Si pas de case vide, on jette la plus vieille et on stoke à la fin de la file
714
               oldcom1 <= oldcom2;
715
               oldcom2 <= oldcom3;
716
               oldcom3 <= sel_voie & '1' & typ_field;
717
            END IF;
718
            err_toco <= '0';
719
         ELSIF (delete_com = '1') THEN
720
         -- Sur réception d'un ordre d'effacement (i.e. la commande en cours a déjà été reçue, donc on l'efface de la mémoire)
721
            IF (oldcom1 = NOT(sel_voie) & '1' & typ_field) THEN
722
            -- En principe, il faut que ce soit la première disponible car elles arrivent forcément dans le même ordre sur les 2 ports
723
               oldcom1 <= oldcom2;              -- On efface la première en recopiant la 2ème et la 3ème
724
               oldcom2 <= oldcom3;
725
               oldcom3(8) <= '0';               -- On vide la 3ème case
726
               err_toco <= '0';
727
            ELSIF (oldcom2 = NOT(sel_voie) & '1' & typ_field) THEN
728
            -- Si la commande en cours est stockée en 2ème position, ça veut dire que la commande stockée
729
            -- en première position a été perdue sur l'autre port
730
               oldcom1 <= oldcom3;              -- On jette les 2 premières mémoires
731
               oldcom2(8) <= '0';
732
               oldcom3(8) <= '0';
733
               err_toco <= '1';                 -- On indique l'erreur   
734
               voie_toco <= NOT(oldcom1(9));    -- et sur quelle voie il y'a eu l'erreur
735
            ELSIF (oldcom3 = NOT(sel_voie) & '1' & typ_field) THEN
736
            -- Si la commande en cours est stockée en 3ème position, ça veut dire que les commandes stockées
737
            -- en première et deuxième position ont été perdues sur l'autre port. On a donc 2 erreurs à enregistrer
738
            -- On purge la mémoire 1 et 3 et on indiquee une erreur. On garde la mémoire 2 en mémoire 1 pour traiter l'erreur
739
            -- à la prochaine commande ou au début du cycle suivant
740
               oldcom1 <= oldcom2;              -- On purge donc toutes les mémoires
741
               oldcom2(8) <= '0';
742
               oldcom3(8) <= '0';
743
               err_toco <= '1';                 -- On indique l'erreur               
744
               voie_toco <= NOT(oldcom1(9));    -- et sur quelle voie il y'a eu l'erreur
745
            END IF;
746
         ELSE
747
            err_toco <= '0';                    -- Pour assurer qu'il ne dure qu'un seul cycle
748
         END IF;
749
      END IF;
750
   END PROCESS;
751
 
752
   --------------------------------------------
753
   -- Machine d'état de gestion du module
754
   --------------------------------------------
755
   -- Une commande est déjà reçue sur l'autre port si elle dans une des 3 cases mémoires
756
   com_recue <= '1' WHEN ((oldcom1 = NOT(sel_voie) & '1' & datin) OR
757
                          (oldcom2 = NOT(sel_voie) & '1' & datin) OR
758
                          (oldcom3 = NOT(sel_voie) & '1' & datin)) ELSE '0';
759
 
760
   -- Une trame de synchro est valide si c'est la première (synchro_lock = '0') ou bien si elle est
761
   -- dans la fenêtre de validité en avance avec SEQ = cpt_seq+1 ou bien si elle est dans la
762
   -- fenêtre de validité en retard avec SEQ = cpt_seq
763
   synchro_valide <= '1' WHEN (typ_field = typ_sync AND
764
                              (synchro_lock = '0' OR
765
                              (win_syncbefore = '1' AND datin = cpt_seq + 1) OR
766
                              (win_syncafter = '1' AND datin = cpt_seq))) ELSE '0';
767
 
768
   man_fsm : PROCESS(clk_sys, rst_n)
769
   BEGIN
770
      IF (rst_n = '0') THEN
771
         fsm_comexec <= idle_st;
772
         sel_voie <= '1';
773
         cpt_byt <= (others => '0');
774
         reg_tid <= x"8F";
775
         wr <= '0';
776
         rd <= '0';
777
         rd_r <= '0';
778
         ad_buf <= (others => '0');
779
         --ad_source <= (others => '0');     -- Inutilisé car les TID sdestination sont en dur (multicast)
780
         store_com <= '0';
781
         delete_com <= '0';
782
         synchro_outwin <= '0';
783
         rd_com <= '0';
784
         sof <= '0';
785
         eof <= '0';
786
         datsent <= (others => '0');
787
         valsent <= '0';
788
         datawrite <= (others => '0');
789
         synchro <= '0';
790
      ELSIF (clk_sys'EVENT and clk_sys = '1') THEN
791
         CASE fsm_comexec IS
792
            WHEN idle_st =>
793
            -- Etat d'attente de données disponibles dans les modules frame_ana
794
               wr <= '0';
795
               rd <= '0';
796
               synchro <= '0';
797
               store_com <= '0';
798
               delete_com <= '0';
799
               synchro_outwin <= '0';
800
               sof <= '0';
801
               eof <= '0';
802
               valsent <= '0';
803
               IF (com_dispo1 = '1' AND (com_dispo2 = '0' OR sel_voie = '1')) THEN
804
               -- On s'assure qu'on traite par alternance une voie et puis l'autre. On traite la voie 1 que si y'a
805
               -- des données a traiter et que soit la voie 2 est vide soit on a traité la voie 2 au coup d'avant
806
                  sel_voie <= '0';              -- Sélection de la voie de traitement
807
                  rd_com <= '1';                -- On demande un octet de plus par anticipation
808
                  fsm_comexec <= rectyp_st;
809
               ELSIF (com_dispo2 = '1') THEN
810
               -- Si on des données dans la voie 2
811
                  sel_voie <= '1';              -- Sélection de la voie à traiter
812
                  rd_com <= '1';
813
                  fsm_comexec <= rectyp_st;
814
               ELSE
815
                  rd_com <= '0';
816
               END IF;
817
 
818
            WHEN rectyp_st =>
819
            -- Etat d'enregistrement du type de commande
820
               typ_field <= datin;    -- Mémorise la partie typ
821
               IF (com_recue = '0') THEN
822
               -- Si on a pas déjà reçu cette com dans ce cycle
823
                  fsm_comexec <= getadsrce_st;     -- 
824
                  IF (datin /= typ_sync) THEN
825
                  -- Si c'est pas une synchro, on l'enregistre. La synchro est mémorisée lors du start_cycle
826
                     store_com <= '1';
827
                  END IF;
828
               ELSE
829
               -- Si on a déjà reçu cette commande
830
                  delete_com <= '1';         -- On efface la commande des mémoires
831
                  fsm_comexec <= purgecom_st;-- On va purger la mémoire sans faire l'action associée
832
               END IF;
833
 
834
            WHEN getadsrce_st =>
835
            -- Etat de récupération de l'adresse source de la commande
836
               --ad_source <= datin;
837
               store_com <= '0';
838
               delete_com <= '0';
839
               -- On va traiter la commande en fonction de son type
840
               IF (typ_field = typ_sync) THEN
841
               -- Si c'est une trame de synchro
842
                  cpt_byt <= x"01";
843
                  fsm_comexec <= purgesidsync_st;  -- On va purger le SID de la trame de synhcro
844
               ELSIF (typ_field = typ_atttid) THEN
845
               -- Si c'est une commande type attribution de TID
846
                  cpt_byt <= x"08";             -- On se prépare à recevoir l'@ IID (8 octets)
847
                  fsm_comexec <= attribtid_st;
848
               ELSIF (typ_field = typ_reqnoseq) THEN
849
               -- Si c'est une commande non sécu
850
                  fsm_comexec <= getcom_st;
851
               ELSE
852
               -- Si c'est une trame qu'on ne sait pas traiter, on va la purger
853
                  rd_com <= '0';
854
                  fsm_comexec <= purgecom_st;
855
               END IF;
856
 
857
            WHEN purgesidsync_st =>
858
            -- Etat d'attente de récupération du SID de la trame de synhcro (on n'en fait rien)
859
               cpt_byt <= cpt_byt - 1;
860
               IF (cpt_byt = "00") THEN
861
                  fsm_comexec <= getseq_st;
862
               END IF;
863
 
864
            WHEN getseq_st =>
865
            -- Etat de réception du compteur de séquence de la trame de SYNC
866
               seq_field <= datin;
867
               IF (synchro_valide = '1') THEN
868
               -- Si le champ SEQ est valable
869
                  rd_com <= '1';                -- On continu de lire pour supprimer le CRC
870
                  synchro <= '1';               -- On signale une synchro valide
871
                  IF (reg_config(3) = '1') THEN
872
                  -- Si on est autorisé à émettre la trame de réponse réflexe
873
                  -- On va d'abord purger les 2 CRC de la commande
874
                     fsm_comexec <= purgecrcsync_st;
875
                     cpt_byt <= x"01";
876
                  ELSE
877
                  -- Si on n'est pas autorisé à émettre la trame réflexe
878
                     fsm_comexec <= purgecom_st;   -- On va purger la commande
879
                  END IF;
880
               ELSE
881
                  IF (win_syncbefore = '0' AND win_syncafter = '0') THEN
882
                  -- Si on a reçu une trame de synchro en dehors des fenêtres de validité
883
                     synchro_outwin <= '1';
884
                  END IF;
885
                  fsm_comexec <= purgecom_st;
886
                  rd_com <= '0';
887
               END IF;
888
 
889
            WHEN purgecrcsync_st =>
890
            -- Etat de purge des 2 octets de CRC de la trmae de synchro
891
               synchro <= '0';
892
               cpt_byt <= cpt_byt - 1;
893
               IF (cpt_byt = "00") THEN
894
                  -- Si on a fini de purger le CRC de la trame de synchro
895
                  fsm_comexec <= startframe_st; -- On va émettre une trame
896
                  sof <= '1';
897
                  datsent <= x"F0";             -- Le 1er octet à envoyer est l'adresse de destination (i.e multicast concentrateur)
898
                  valsent <= '1';               -- On valide l'octet sorti
899
                  ad_buf <= reg_adref;          -- l'@ des données à émettre est donnée par ce registre
900
                  cpt_byt <= reg_szref;         -- le nombre d'octets à émettre est donné par ce registre
901
                  rd_com <= '0';
902
               END IF;
903
 
904
            WHEN attribtid_st =>
905
            -- Etat d'exécution d'une trame d'attribution de TID
906
               iid_temp <= datin & iid_temp(63 DOWNTO 8);   -- On récupère l'@ IID octet par octet
907
               cpt_byt <= cpt_byt - 1;
908
               IF (cpt_byt = x"00") THEN
909
               -- Si on reçu les 8 octets
910
                  IF (iid_temp = iid) THEN
911
                  -- Si l@ IID reçue correspond à l'@ IID du module
912
                     reg_tid <= datin;                    -- On mémorise le nouveau TID
913
                  END IF;
914
                  fsm_comexec <= idle_st;
915
                  rd_com <= '0';
916
               END IF;
917
 
918
            WHEN getcom_st =>
919
            -- Etat de récupération de l'octet de commande de la trame de requête non sécu
920
               com_field <= datin;
921
               rd_com <= '1';
922
               fsm_comexec <= getnr_st;
923
 
924
            WHEN getnr_st =>
925
            -- Etat de récupération du nombre d'octets à traiter dans la requête, que ce soit une écriture ou une lecture
926
               cpt_byt <= datin;
927
               rd_com <= '1';
928
               fsm_comexec <= getadbuf_st;
929
 
930
            WHEN getadbuf_st =>
931
            -- Etat de récupération de l'adresse où lire ou écrire
932
               ad_buf <= datin;
933
               IF (com_field = com_write) THEN
934
               -- Si c'est une commande d'écriture
935
                  fsm_comexec <= writebyt_st;
936
                  rd_com <= '1';
937
               ELSIF (com_field = com_read) THEN
938
               -- Si c'est une commande de lecture
939
                  fsm_comexec <= startframe_st; -- On va émettre une trame
940
                  sof <= '1';                   -- On signale au module layer2_Tx qu'on veut émettre une trame
941
                  datsent <= x"F0";             -- Le 1er octet à envoyer est l'adresse de destination (i.e multicast concentrateur)
942
                  valsent <= '1';               -- On valide l'octet sorti
943
                  rd_com <= '0';                -- On ne lit plus rien de la commande pour l'instant
944
               ELSE               -- Si c'est autre chose, il y'a eu un problème de desynchronisation -> on va purger la mémoire de commande
945
                  fsm_comexec <= purgecom_st;
946
                  rd_com <= '0';
947
               END IF;
948
 
949
            WHEN writebyt_st =>
950
            -- Etat d'écriture d'une séquence d'octets
951
               datawrite <= datin;
952
               wr <= '1';
953
               cpt_byt <= cpt_byt - 1 ;
954
               IF (wr = '1' AND (ad_buf /= ('0' & adreg_spidat)) AND ad_buf /= x"FF") THEN
955
               -- on n'incrémente l'adresse que si le WR a été effectué
956
               -- Si on accède à la FIFO SPI, le registre d'addresse reste bloqué à cette valeur
957
                  ad_buf <= ad_buf + 1;
958
               END IF;
959
               IF (cpt_byt = x"01") THEN
960
               -- Si on a traité tous les octets
961
                  rd_com <= '0';             -- On arrête de lire dans la commande
962
                  fsm_comexec <= idle_st;    -- Mais le signal de wr reste actif un cycle de plus (remis à 0 dans idle)
963
               END IF;
964
 
965
            WHEN startframe_st =>
966
               -- Prépare l'envoie d'une trame
967
               synchro <= '0';   -- Le signal de synhcro ne doit durer qu'1 pulse
968
               IF (datsent_free = '1') THEN
969
               -- Si le 1er octet est en cours de traitement, l'octet suivant est le TYPE
970
                  sof <= '0';             -- Le sof a été pris en compte
971
                  datsent <= x"80";       -- Type de réponse non sécu
972
                  valsent <= '1';
973
                  fsm_comexec <= sendsrce_st;
974
               END IF;
975
 
976
            WHEN sendsrce_st =>
977
            -- Envoie l'@ source (i.e l'@ du MIO) de la trame à émettre
978
               IF (datsent_free = '1') THEN
979
                  datsent <= reg_tid;
980
                  valsent <= '1';
981
                  fsm_comexec <= sendcom_st;
982
               END IF;
983
 
984
            WHEN sendcom_st =>
985
            -- Envoie du numéro de séquence courante
986
               IF (datsent_free = '1') THEN
987
                  IF (typ_field = typ_sync) THEN
988
                  -- Si on répond à une trame de synchro
989
                     datsent <= x"01";
990
                  ELSE
991
                  -- Si on répond à une trame de requête
992
                     datsent <= x"02";
993
                  END IF;
994
                  valsent <= '1';
995
                  fsm_comexec <= sendnr_st;
996
               END IF;
997
 
998
            WHEN sendnr_st =>
999
            -- Envoie du nombre d 'octets lus
1000
               IF (datsent_free = '1') THEN
1001
                  datsent <= cpt_byt;
1002
                  valsent <= '1';
1003
                  fsm_comexec <= sendadr_st;
1004
               END IF;
1005
 
1006
            WHEN sendadr_st =>
1007
            -- Envoie de l'adresse ou on a lu les octets
1008
               IF (datsent_free = '1') THEN
1009
                  datsent <= ad_buf;
1010
                  rd <= '1';
1011
                  rd_r <= '0';
1012
                  valsent <= '1';
1013
                  fsm_comexec <= senddata_st;
1014
               END IF;
1015
 
1016
            WHEN senddata_st =>
1017
            -- Envoie les octets lus. rd_r est utilisé pour signaler que la donnée en lecture est disponible.
1018
            -- Il est décalé de 1 cycle par rappott à rd 
1019
               IF (rd = '1' AND datsent_free = '1') THEN
1020
                  rd_r <= '1';
1021
                  IF ((ad_buf /= ('0' & adreg_spidat)) AND ad_buf /= x"FF") THEN
1022
                  -- Si on accède à la FIFO rx du SPI, on reste calé sur cette adresse
1023
                     ad_buf <= ad_buf + 1;
1024
                  END IF;
1025
                  cpt_byt <= cpt_byt - 1;
1026
               END IF;
1027
               IF (datsent_free = '1') THEN
1028
               -- Si le module layer2_tx est dispo pour prendre la donnée
1029
                  IF (cpt_byt = x"01") THEN
1030
                     rd <= '0';                       -- Il ne faut plus lire en mémoire
1031
                  END IF;
1032
                  IF (rd_r = '1') THEN
1033
                  -- Si le module layer2_tx est dispo et qu'une donnée est dispo
1034
                     datsent <= dataread;         -- On l'envoie
1035
                     valsent <= '1';
1036
                     IF (cpt_byt = x"00") THEN
1037
                     -- Si c'est la dernière donnée
1038
                        IF (typ_field = typ_sync) THEN
1039
                        -- Si on répond à une trame de synchro
1040
                           fsm_comexec <= sendstatus_st; -- Il faut envoyer l'octet de status
1041
                        ELSE
1042
                        -- Si c'est une requête normale
1043
                           fsm_comexec <= endframe_st; -- On a fini
1044
                           eof <= '1';
1045
                        END IF;
1046
                     END IF;
1047
                  ELSE
1048
                  -- S'il n'y a pas dedonnée prête (cas se présente quand on rentre dans cet état et qu'on a pas encore lu)  
1049
                     valsent <= '0';         -- On indique au module layer2_tx qu'il n'y a pas de nouvelle donnée
1050
                  END IF;
1051
               END IF;
1052
 
1053
            WHEN sendstatus_st =>
1054
            -- Envoie du registre de status
1055
               IF (datsent_free = '1') THEN
1056
                  datsent <= reg_status;
1057
                  valsent <= '1';
1058
                  eof <= '1';
1059
                  fsm_comexec <= endframe_st;
1060
               END IF;
1061
 
1062
            WHEN endframe_st =>
1063
            -- Gestion de la fin d'envoie d'une trame
1064
               IF (datsent_free = '1') THEN
1065
                  eof <= '0';
1066
                  valsent <= '0';
1067
                  fsm_comexec <= idle_st;
1068
               END IF;
1069
 
1070
            WHEN purgecom_st =>
1071
            -- Purge la mémoire de commande pour se recaler au début de la commande suivante
1072
            -- en cas de problème ou en cas de commande déjà reçue
1073
               store_com <= '0';
1074
               delete_com <= '0';
1075
               synchro_outwin <= '0';
1076
               IF (sel_voie = '0') THEN
1077
                  IF (com_dispo1 = '1' AND socin1 = '0') THEN
1078
                  -- On lit jusqu'à ce qu'il n'y ait plus de commande ou qu'on ait atteind le début de la commande suivante
1079
                     rd_com <= '1';
1080
                  ELSE
1081
                     rd_com <= '0';
1082
                     fsm_comexec <= idle_st;
1083
                  END IF;
1084
               ELSE
1085
                  IF (com_dispo2 = '1' AND socin2 = '0') THEN
1086
                     rd_com <= '1';
1087
                  ELSE
1088
                     rd_com <= '0';
1089
                     fsm_comexec <= idle_st;
1090
                  END IF;
1091
               END IF;
1092
 
1093
            WHEN OTHERS =>
1094
               fsm_comexec <= idle_st;
1095
         END CASE;
1096
      END IF;
1097
   END PROCESS;
1098
 
1099
end rtl;
1100
 

powered by: WebSVN 2.1.0

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