123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- ----------------------------------------------------------------------------------
- -- Company: INSA-Toulouse
- -- Engineer: Paul Faure
- --
- -- Create Date: 18.04.2021 21:19:41
- -- Module Name: Etage1_LectureInstruction - Behavioral
- -- Project Name: Processeur sécurisé
- -- Target Devices: Basys 3 ARTIX7
- -- Tool Versions: Vivado 2016.4
- -- Description: Etage 1 du processeur
- -- - Gestion des instructions, lecture en mémoire
- -- - Gestion des aléas sur les registres
- -- - Gestion des sauts et appels de fonction
- --
- -- Dependencies:
- -- - MemoireInstruction
- -- - MemoireAdressesRetour
- ----------------------------------------------------------------------------------
-
-
- library IEEE;
- use IEEE.STD_LOGIC_1164.ALL;
- use IEEE.STD_LOGIC_UNSIGNED.ALL;
- use IEEE.NUMERIC_STD.ALL;
-
-
- entity Etage1_LectureInstruction is
- Generic (Instruction_size_in_memory : Natural; -- Taille d'une instruction en mémoire (Taille d'un code instruction + 3*Taille d'un mot binaire)
- Addr_size_mem_instruction : Natural; -- Nombre de bits pour adresser la mémoire d'instruction
- Mem_instruction_size : Natural; -- Taille de la mémoire d'instruction (nombre d'instructions stockées)
- Nb_bits : Natural; -- Taille d'un mot binaire
- Instruction_bus_size : Natural; -- Nombre de bits du bus d'instruction (Taille d'un code instruction)
- Nb_registres : Natural; -- Nombre de registres du processeurs
- Mem_adresse_retour_size : Natural; -- Taille de la mémoire des adresses de retour (nombre d'adresse maximum) (profondeur d'appel maximale)
- Adresse_size_mem_adresse_retour : Natural; -- Nombre de bits pour adresser la mémoire des adresses de retour
- Instructions_critiques_lecture_A : STD_LOGIC_VECTOR; -- Vecteur de bit représentant les instruction critiques sur l'opérande A (si le bit i est a un, l'instruction i lit une valeur dans le registre n°opérandeA)
- Instructions_critiques_lecture_B : STD_LOGIC_VECTOR; -- Vecteur de bit représentant les instruction critiques sur l'opérande B (si le bit i est a un, l'instruction i lit une valeur dans le registre n°opérandeB)
- Instructions_critiques_lecture_C : STD_LOGIC_VECTOR; -- Vecteur de bit représentant les instruction critiques sur l'opérande C (si le bit i est a un, l'instruction i lit une valeur dans le registre n°opérandeC)
- Instructions_critiques_ecriture : STD_LOGIC_VECTOR; -- Vecteur de bit représentant les instruction critiques en écriture (toujours sur l'opérande A) (si le bit i est a un, l'instruction i ecrit une valeur dans le registre n°opérandeA)
-
- -- Exemple 1 : Soit MUL i j k avec pour numéro d'instruction 7 avec le comportement Ri <- Rj*Rk
- -- Instructions_critiques_lecture_A(7) = '0' --> MUL ne lit pas dans le registre de l'opérande A
- -- Instructions_critiques_lecture_B(7) = '1' --> MUL lit dans le registre de l'opérande B
- -- Instructions_critiques_lecture_C(7) = '1' --> MUL lit dans le registre de l'opérande C
- -- Instructions_critiques_ecriture(7) = '1' --> MUL ecrit dans le registre de l'opérande A
-
- -- Exemple 2 : Soit AFC i val avec pour numéro d'instruction 5 avec le comportement Ri <- val
- -- Instructions_critiques_lecture_A(5) = '0' --> AFC ne lit pas dans le registre de l'opérande A
- -- Instructions_critiques_lecture_B(5) = '0' --> AFC ne lit pas dans le registre de l'opérande B (pour AFC, B est directement la valeur, pas un numero de registre, il n'y a donc pas de lecture)
- -- Instructions_critiques_lecture_C(5) = '0' --> AFC ne lit pas dans le registre de l'opérande C
- -- Instructions_critiques_ecriture(5) = '1' --> AFC ecrit dans le registre de l'opérande A
-
- Code_Instruction_JMP : STD_LOGIC_VECTOR; -- Numéro de l'instruction JMP
- Code_Instruction_JMZ : STD_LOGIC_VECTOR; -- Numéro de l'instruction JMZ
- Code_Instruction_PRI : STD_LOGIC_VECTOR; -- Numéro de l'instruction PRI
- Code_Instruction_PRIC : STD_LOGIC_VECTOR; -- Numéro de l'instruction PRIC
- Code_Instruction_CALL : STD_LOGIC_VECTOR; -- Numéro de l'instruction CALL
- Code_Instruction_RET : STD_LOGIC_VECTOR; -- Numéro de l'instruction RET
- Code_Instruction_STOP : STD_LOGIC_VECTOR); -- Numéro de l'instruction STOP
- Port ( CLK : in STD_LOGIC; -- Clock
- RST : in STD_LOGIC; -- Reset
- Z : in STD_LOGIC; -- Flag Zero de l'ALU (utile pour le JMZ)
- STD_IN_Request : in STD_LOGIC;
- A : out STD_LOGIC_VECTOR (Nb_bits - 1 downto 0); -- Sortie de l'opérande A
- B : out STD_LOGIC_VECTOR (Nb_bits - 1 downto 0); -- Sortie de l'opérande B
- C : out STD_LOGIC_VECTOR (Nb_bits - 1 downto 0); -- Sortie de l'opérande C
- Instruction : out STD_LOGIC_VECTOR (Instruction_bus_size - 1 downto 0)); -- Sortie du code de l'instruction
- end Etage1_LectureInstruction;
-
-
-
- architecture Behavioral of Etage1_LectureInstruction is
- component MemoireInstructions is
- Generic (Nb_bits : Natural;
- Addr_size : Natural;
- Mem_size : Natural);
- Port ( Addr : in STD_LOGIC_VECTOR (Addr_size-1 downto 0);
- D_OUT : out STD_LOGIC_VECTOR (Nb_bits-1 downto 0) := (others => '0'));
- end component;
-
- component MemoireAdressesRetour is
- Generic (Nb_bits : Natural;
- Addr_size : Natural;
- Mem_size : Natural);
- Port ( R : in STD_LOGIC;
- W : in STD_LOGIC;
- D_IN : in STD_LOGIC_VECTOR (Nb_bits-1 downto 0);
- RST : in STD_LOGIC;
- CLK : in STD_LOGIC;
- D_OUT : out STD_LOGIC_VECTOR (Nb_bits-1 downto 0) := (others => '0');
- E : out STD_LOGIC;
- F : out STD_LOGIC);
- end component;
-
- -- Signaux pour récuperer l'instruction de la mémoire
- signal Pointeur_instruction : STD_LOGIC_VECTOR (Addr_size_mem_instruction - 1 downto 0) := (others => '0');
- signal Pointeur_instruction_next : STD_LOGIC_VECTOR (Addr_size_mem_instruction - 1 downto 0) := (0 => '1', others => '0');
- signal Instruction_courante : STD_LOGIC_VECTOR (Instruction_size_in_memory - 1 downto 0) := (others => '0');
-
-
- -- Tableau pour gérer les aléas des registres (lecture en étage 2 avant écriture en étage 5)
- subtype Registre is integer range -1 to Nb_registres - 1;
- type Tab_registres is array (1 to 3) of Registre;
- signal Tableau : Tab_registres := (others => - 1);
-
- -- Signaux de gestion pour la mémoire des adresses de retour
- signal Adresse_Retour : STD_LOGIC_VECTOR (Addr_size_mem_instruction - 1 downto 0) := (others => '0');
- signal E : STD_LOGIC;
- signal F : STD_LOGIC;
- signal R_Aux : STD_LOGIC := '0';
- signal W_Aux : STD_LOGIC := '0';
-
- -- constantes pour injecter des bulles dans le pipeline
- constant Instruction_nulle : STD_LOGIC_VECTOR (Instruction_bus_size - 1 downto 0) := (others => '0');
- constant Argument_nul : STD_LOGIC_VECTOR (Nb_bits - 1 downto 0) := (others => '0');
-
- -- condition pour detecter si une bulle doit être injectée
- signal bulles : boolean := false;
-
- -- Compteur pour attendre lors d'un JMZ que l'instruction d'avant soit a l'ALU, ou lors d'un STOP k
- signal compteur : integer := 0;
-
- -- Compteur de protection des collisions entre les prints
- signal Compteur_PRI : integer range 0 to Nb_bits/4 + 1 := 0;
-
- -- Signal d'arret (STOP 0)
- signal locked : boolean := false;
-
- begin
- instance : MemoireInstructions
- generic map (Nb_bits => Instruction_size_in_memory,
- Addr_size => Addr_size_mem_instruction,
- Mem_size => Mem_instruction_size)
- port map (Addr => Pointeur_Instruction,
- D_OUT => Instruction_courante);
-
- instance_MemoireAdressesRetour : MemoireAdressesRetour
- generic map (Nb_bits => Addr_size_mem_instruction,
- Addr_size => Adresse_size_mem_adresse_retour,
- Mem_size => Mem_adresse_retour_size
- )
- port map ( R => R_Aux,
- W => W_Aux,
- D_IN => Pointeur_instruction_next,
- RST => RST,
- CLK => CLK,
- D_OUT => Adresse_Retour,
- E => E,
- F => F
- );
-
-
- process
- begin
- -- Synchronisation
- wait until CLK'event and CLK = '1';
- if (RST = '0') then
- -- Reset de l'étage
- Tableau <= (others => -1);
- Pointeur_Instruction <= (others => '0');
- compteur <= 0;
- Compteur_PRI <= 0;
- locked <= false;
- C <= Argument_nul;
- B <= Argument_nul;
- A <= Argument_nul;
- Instruction <= Instruction_nulle;
- elsif (STD_IN_Request = '0') then
- -- Avancement des instructions en écritures dans le pipeline
- Tableau(3) <= Tableau(2);
- Tableau(2) <= Tableau(1);
- Tableau(1) <= -1;
- if (Compteur_PRI > 0) then
- Compteur_PRI <= Compteur_PRI - 1;
- end if;
- if (not bulles) then
- -- S'il ne faut pas injecter de bulles ont traite l'instruction (Possible code factorisable sur ce if)
- if ((Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits) = Code_Instruction_CALL) or (Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits) = Code_Instruction_JMP)) then
- -- CAS PARTICULIER : CALL ou JMP, on transmet et on saute
- C <= Instruction_courante (1 * Nb_bits - 1 downto 0 * Nb_bits);
- B <= Instruction_courante (2 * Nb_bits - 1 downto 1 * Nb_bits);
- A <= Instruction_courante (3 * Nb_bits - 1 downto 2 * Nb_bits);
- Instruction <= Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits);
- Pointeur_Instruction <= Instruction_courante (2 * Nb_bits + Addr_size_mem_instruction - 1 downto 2 * Nb_bits);
- elsif (Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits) = Code_Instruction_RET) then
- -- CAS PARTICULIER : RET, on transmet et on revient
- C <= Instruction_courante (1 * Nb_bits - 1 downto 0 * Nb_bits);
- B <= Instruction_courante (2 * Nb_bits - 1 downto 1 * Nb_bits);
- A <= Instruction_courante (3 * Nb_bits - 1 downto 2 * Nb_bits);
- Instruction <= Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits);
- Pointeur_Instruction <= Adresse_Retour;
- elsif (Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits) = Code_Instruction_JMZ) then
- -- CAS PARTICULIER : JMZ, on attends que l'instruction précedente arrive sur l'ALU, si le flag Zero est a un on saute, sinon on continue normalement
- compteur <= compteur + 1;
- C <= Instruction_courante (1 * Nb_bits - 1 downto 0 * Nb_bits);
- B <= Instruction_courante (2 * Nb_bits - 1 downto 1 * Nb_bits);
- A <= Instruction_courante (3 * Nb_bits - 1 downto 2 * Nb_bits);
- Instruction <= Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits);
- if (compteur = 2) then
- if (Z = '1') then
- Pointeur_Instruction <= Instruction_courante (2 * Nb_bits + Addr_size_mem_instruction - 1 downto 2 * Nb_bits);
- else
- Pointeur_Instruction <= Pointeur_Instruction + 1;
- end if;
- compteur <= 0;
- end if;
- elsif (Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits) = Code_Instruction_STOP) then
- -- CAS PARTICULIER : STOP, si on est bloqué, on ne fait rien, programme arrété
- -- sinon, on regarde si l'on doit se bloquer
- -- sinon, on incremente le compteur et on attends
- if (not locked) then
- if (Instruction_courante (3 * Nb_bits - 1 downto 2 * Nb_bits) = Argument_nul) then
- locked <= true;
- end if;
- compteur <= compteur + 1;
- if (compteur + 1 = to_integer(unsigned(Instruction_courante (3 * Nb_bits - 1 downto 2 * Nb_bits))) * 1000) then
- Pointeur_Instruction <= Pointeur_Instruction + 1;
- compteur <= 0;
- end if;
- end if;
- C <= Instruction_courante (1 * Nb_bits - 1 downto 0 * Nb_bits);
- B <= Instruction_courante (2 * Nb_bits - 1 downto 1 * Nb_bits);
- A <= Instruction_courante (3 * Nb_bits - 1 downto 2 * Nb_bits);
- Instruction <= Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits);
- elsif (Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits) = Code_Instruction_PRI) then
- -- CAS PARTICULIER : PRI, on transmet l'instruction et fixe le compteur pour proteger des collisions
- Compteur_PRI <= Nb_bits/4 + 1;
- C <= Instruction_courante (1 * Nb_bits - 1 downto 0 * Nb_bits);
- B <= Instruction_courante (2 * Nb_bits - 1 downto 1 * Nb_bits);
- A <= Instruction_courante (3 * Nb_bits - 1 downto 2 * Nb_bits);
- Instruction <= Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits);
- Pointeur_Instruction <= Pointeur_Instruction + 1;
- else
- -- CAS GENERAL : On transmet l'instruction et les opérandes, si elle est critique en ecriture, on enregistre le registre associé dans le tableau
- C <= Instruction_courante (1 * Nb_bits - 1 downto 0 * Nb_bits);
- B <= Instruction_courante (2 * Nb_bits - 1 downto 1 * Nb_bits);
- A <= Instruction_courante (3 * Nb_bits - 1 downto 2 * Nb_bits);
- Instruction <= Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits);
- if (Instructions_critiques_ecriture(to_integer(unsigned(Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits)))) = '1') then
- Tableau(1) <= to_integer(unsigned(Instruction_courante (3 * Nb_bits - 1 downto 2 * Nb_bits)));
- end if;
- Pointeur_Instruction <= Pointeur_Instruction + 1;
- end if;
- else
- -- Si besoin de bulle, on l'injecte
- C <= Argument_nul;
- B <= Argument_nul;
- A <= Argument_nul;
- Instruction <= Instruction_nulle;
- end if;
- end if;
- end process;
-
-
- -- Condition horrible -> Instruction critique en lecture sur A qui lit dans A=i et Ri dans tableau ou instruction critique en lecture sur B qui lit dans B=j et Rj dans tableau ou instruction critique en lecture sur C qui lit dans C=k et Rk dans tableau
- bulles <=
- (
- (
- Instructions_critiques_lecture_A(to_integer(unsigned(Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits)))) = '1' -- Intruction critique sur A
- )
- and
- (
- (to_integer(unsigned(Instruction_courante (3 * Nb_bits - 1 downto 2 * Nb_bits))) = Tableau(1)) -- A est
- or
- (to_integer(unsigned(Instruction_courante (3 * Nb_bits - 1 downto 2 * Nb_bits))) = Tableau(2)) -- dans le
- or
- (to_integer(unsigned(Instruction_courante (3 * Nb_bits - 1 downto 2 * Nb_bits))) = Tableau(3)) -- tableau
- )
- )
- or
- (
- (
- Instructions_critiques_lecture_B(to_integer(unsigned(Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits)))) = '1'
- )
- and
- (
- (to_integer(unsigned(Instruction_courante (2 * Nb_bits - 1 downto 1 * Nb_bits))) = Tableau(1))
- or
- (to_integer(unsigned(Instruction_courante (2 * Nb_bits - 1 downto 1 * Nb_bits))) = Tableau(2))
- or
- (to_integer(unsigned(Instruction_courante (2 * Nb_bits - 1 downto 1 * Nb_bits))) = Tableau(3))
- )
- )
- or
- (
- (
- Instructions_critiques_lecture_C(to_integer(unsigned(Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits)))) = '1'
- )
- and
- (
- (to_integer(unsigned(Instruction_courante (1 * Nb_bits - 1 downto 0 * Nb_bits))) = Tableau(1))
- or
- (to_integer(unsigned(Instruction_courante (1 * Nb_bits - 1 downto 0 * Nb_bits))) = Tableau(2))
- or
- (to_integer(unsigned(Instruction_courante (1 * Nb_bits - 1 downto 0 * Nb_bits))) = Tableau(3))
- )
- )
- or
- (
- (
- (Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits) = Code_Instruction_PRI)
- or
- (Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits) = Code_Instruction_PRIC)
- )
- and
- (
- not (Compteur_PRI = 0)
- )
- );
-
- -- Gestion de l'écriture/lecture dans la mémoire des adresses de retour
- R_Aux <= '1' when Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits) = Code_Instruction_RET and STD_IN_Request = '0' else
- '0';
- W_Aux <= '1' when Instruction_courante (Instruction_bus_size + 3 * Nb_bits - 1 downto 3 * Nb_bits) = Code_instruction_CALL and STD_IN_Request = '0' else
- '0';
-
-
- Pointeur_instruction_next <= Pointeur_instruction + 1;
- end Behavioral;
|