Etape 10 : Création d'un première instruction complète
Rien de tel, pour tester globalement l'architecture que nous venons de décrire que de réaliser une première instruction. LOADd est une instruction simple à réaliser mais aussi très utile pour tester le fonctionnement des registres, c'est donc celle-ci que j'ai choisi pour débuter.
Création de l'ALU
LOADd sert à charger une valeur directe dans un registre suivant différent modes qui permettent de ne modifier que les bits de poids fort ou faibles voir tous les bits lors de chargement de type SIGNED ou UNSIGNED. Cette instruction va passer à l'ALU la valeur direct en se connectant sur le bus de première opérande DNN. Il y aura donc un signal permettant de réaliser cet aiguillage comme le montre le code suivant :
-- ========================================================================================== -- DNN Specific routing i_DNN(15 downto 0) <= IVV(IVV_LOADd_VALUE_TOP downto IVV_LOADd_VALUE_TOP-15) when I_LOADd = '1' else DNN; i_DNN(31 downto 16) <= "0000000000000000" when I_LOADd = '1' else DNN;
La valeur du registre de destination servira de seconde opérande, nécessaire au calcul des bits inchangé dans le résultat final. Faute de place dans le codage de l'instruction, l'aiguillage classique de RMM ne sera pas possible. Le séquenseur devra donc aiguiller spécifiquement RDD vers RMM pour que DMM soit positionné avec la valeur adéquat. Enfin le calcul de la nouvelle valeur de RDD pourra se faire comme suit, en fonction du mode :
-- ============================================================================ -- LOADd Instruction block LOADd_MODE(1 downto 0) <= IVV(IVV_LOADd_MODE_TOP downto IVV_LOADd_MODE_TOP-1); LOADd_c <= '0'; for i in 31 downto 16 generate LOADd_out(i) <= i_DNN(i-16) when LOADd_mode = LOADd_MODE_HIGH else i_DNN(15) when LOADd_mode = LOADd_MODE_SIGNED else DMM(i) when LOADd_mode = LOADd_MODE_LOW else '0'; end generate; for i in 15 downto 0 generate LOADd_out(i) <= DMM(i) when LOADd_mode = LOADd_MODE_HIGH else i_DNN(i); end generate;
Bref, bien que d'approche assez simple, cette instruction demande quelques spécificités, autant dans le séquenceur (avec un aiguillage des registres particulier) que dans l'ALU (avec un aiguillage du bus DNN particulier).
Création du Séquenceur
Le bloc séquenceur doit tout d'abord charger l'instruction à exécuter, il devra s'assurer qu'une instruction soit prête sans quoi il devra insérer une bulle (a savoir un NOP) sans pour autant incrémenter le compteur ordinal. Cette opération est exécutée par le premier bloc suivant :
-- ============================================================================= -- CURRENT INSTRUCTION REGISTER PC_LOAD <= IN_RDY; i_INSTR <= INSTR when ( IN_RDY = '1' ) else INSTRUCTION_NOP; i_rinstr : cl_reg generic map ( WIDTH => 32 ) port map ( D => i_INSTR, Q => instruction, CLK => CLK, LOAD => '1', RESET => RST); IVV <= instruction;
Le signal IN_RDY pour INstruction ReaDY est émis par le bloc de gestion
de la mémoire et indique par un état haut que l'instruction est prette a être récupérée.
Le signal PC_LOAD commande le chargement du registre R00 au prochain cycle. Cette
ligne permet de ne pas incrémenter le compteur ordinal lorsque l'on insère une bulle (un NOP).
Le registre d'instruction sera chargé avec l'INSTRuction ou avec une commande NOP dans le cas où la
mémoire ne serait pas prette.
Le décodage de l'instruction est en suite réalisé sur le schéma suivant :
-- ===================================================================== -- INSTRUCTION DECODING process ( instruction ) begin -- Default values t_LOADd <= '0'; SPP <= '0'; SPM <= '0'; LFL <= '1'; PC_R00 <= "00"; LDD <= '0'; if ( instruction(31 downto 30) = "00" ) then -- Instuction JMP elsif ( instruction(31 downto 30) = "01" ) then -- Instruction CALL elsif ( instruction(31 downto 29) = "110" ) then -- Instruction JB elsif ( instruction(31 downto 29) = "101" ) then -- Instruction ADDd else case instruction(31 downto 24) is when "10000000" => -- Instruction ADDr when "11111100" => -- Instruction LOADd t_LOADd <= '1'; LDD <= '1'; when others => end case; end if; end process;
Le signaux de contrôle de l'ALU sont mis à jour en fonction de l'instruction en cours d'exécution. Ce modèle sera complété au fur et à mesure de l'ajout d'instructions. Le sequenceur contient aussi le routage des signaux RDD, RNN, RMM ... Dans le cas de l'instruction LOADd ici décrite, le signal t_LOADd permet l'aiguillage spécifique de RDD sur RMM pour lire et charger le même registre. LDD déclenche le chargement du registre de destination. LFL, par défaut, actif entraine la mise à jour des flags.
Programme de test
Outre la réalisation des blocs séquenceur et alu, cette instruction est l'occasion de réaliser la partie
mémoire pour y paramétrer le premier programme de test. Pour l'instant, la mémoire de programme et celle
de données seront séparés (durant la phase de conception). La mémoire des programme est donc consituée
par une ROM de 128 mots de 32 bits. Le programme est actuellement inscrit en dur dans le vhdl de ce bloc.
Pour réaliser le test de cette première instruction, l'horloge est controlée manuellement à l'aide de
l'un des boutons poussoir de la carte d'essai. L'afficheur 7 segments imprime la valeur du registre R04
utilisé dans le jeu d'essai.
Le programme utilisé pour les tests est décrit ci-dessous :
i_romCode : cl_rom128x32 generic map ( INIT => ( "11111100001000100001100100001000", -- FC 00100 0100001100100001 00 0 - LOADd R04,0x4321, low 0 "11111100001001000011101100101010", -- FC 00100 1000011101100101 01 0 - LOADd R04,0x8765, high 1 "11111100001000100001100100001010", -- FC 00100 0100001100100001 01 0 - LOADd R04,0x4321, high 2 "11111100001001000011101100101000", -- FC 00100 1000011101100101 00 0 - LOADd R04,0x8765, low 3 "11111100001000100001100100001100", -- FC 00100 0100001100100001 10 0 - LOADd R04,0x4321, signed 4 "11111100001001000011101100101100", -- FC 00100 1000011101100101 10 0 - LOADd R04,0x8765, signed 5 "11111100001000100001100100001110", -- FC 00100 0100001100100001 11 0 - LOADd R04,0x4321, unsigned 6 "11111100001001000011101100101110", -- FC 00100 1000011101100101 11 0 - LOADd R04,0x8765, unsigned 7 X"00000000", -- 8 X"00000000", -- 9 X"00000000", -- 10 X"00000000", -- 11 X"00000000", -- 12 X"00000000", -- 13 X"00000000", -- 14 X"00000000", -- 15 [...]
Petite remarque - pour voir si vous suivez ;o) -
Lors du demarrage, le registre instruction est initialisé à zéro, et durant le premier cycle c'est bien cette instruction qui sera exécutée avant même que la première vraie instruction soit chargée il est donc important que cette instruction "0" ne pause pas de problème. Comme il s'agit d'après le jeu d'instruction d'un JMP à l'adresse 0 ... Tout va bien.