Séance 6
Transcription
Séance 6
DSP Plan Présentation générale du domaine DSP Le choix du DSP L’architecture interne du 21061 Jeu d’instruction Registres d’état du DSP Accès mémoire et pipeline Les interruptions Assembleur Sharc I - Présentation générale Flexibilité Vs performances Flexibilité Proc. généraliste Coût de conception µ. Contrôleur DSP ASIP Performances-1 Idem avec l’efficacité énergétique Générations de DSP La R&D autour des DSP en France II – Le choix des DSP Comparaison DSP / Proc généraliste Sharc Pentium critère 60-66 MHz 2-3 GHz Fréquence 1 cycle/inst 2-3 cycles/inst Add 1cycle/inst 1-10 cycles/inst Mul 1 cycle/inst 20* plus vite = 20*60 = 1,2GHz ~20 cycles/inst (MMX) MAC : Lecture échantillon Lecture coef filtre Mul ACC Calcul prochaine @ Comparaison DSP / Proc généraliste Sharc Pentium critère Mem on Chip Bus système 100-166MHz (Pentium = 100MHz) Cache : PCI = 66 MHz ISA = 8 MHz … Bus + Mem Unités de calcul // 3 cycles/inst FIR Questions… Pourquoi le DSP n’a-t-il pas alors remplacé les CISC ? Compatibilité Performance limité sur applis générales Espace adressable réduit sur DSP Futur du DSP : TMS 320C54 ou BlackFin = DSP + RISC Harvard / Von Neuman Les accès mémoire sont découplés Accès instructions Accès données Harvard : 2 accès // par instruction 2 fois + rapide Au prix d’une architecture beaucoup plus complexe : tout est doublé Von Neumann Accès mémoire séquentiels Plus flexible Archi plus simple III – Architecture Sharc Les concurrents Texas Instruments TMS320C54x, TMS320C6x… De 20 à 400 MIPS en mono core Plus de 2000 MIPS en multi core Plus souvent en virgule fixe 16 bits Motorola DSP 56x00 Analog Device 1er DSP, 1980, ADSP-2100 3 unités de calculs // : instructions multi-fonctions 1990, famille Sharc (Super Harvard Architecture) 2106x, 66MFLOPS La carte utilisée en TP – EZ-KIT Lite UART CODEC Caractéristiques de l’architecture Sharc Architecture de type Harvard (bus Data 40 bits + Bus Program 48 bits) Cache 32 instructions 16 registres de données (40 bits) Structure pipeline à 3 étages (F + D + E) Parallélisme d’instructions (sous certaines conditions) Unité de calcul avec multiplieur, additionneur en virgule fixe ou flottante et registre à décalage 2 unités de génération d’adresses (DAG) avec buffers circulaires (convolutions) et adressage « bit-reversed » (FFT) Gestion câblée des boucles Le pipeline instruction i instruction i+1 lecture décodage exécution lecture décodage exécution lecture instruction i+2 en permanence ! décodage exécution temps Architecture interne du 21061 CACHE MEMORY 32 x 48 DAG 1 8 x 4 x 32 DAG 2 8 x 4 x 24 JTAG TEST & EMULATION PROGRAM SEQUENCER PMA BUS 24 DMA BUS 32 PMD BUS 48 DMD BUS 40 FLAGS TIMER PMA DMA PMD BUS CONNECT FLOATING & FIXED-POINT MULTIPLIER, FIXED-POINT ACCUMULATOR DMD REGISTER FILE 16 x 40 32-BIT BARREL SHIFTER FLOATING-POINT & FIXED-POINT ALU Vue système Benchmarks Principe d’utilisation en TP Host PC Binaire LDF Étapes de traitement Acquisition du signal audio analogique Conversion analogique-numérique Réception des échantillons (DMA, liaison série) Lecture échantillons en mémoire Traitement des échantillons Envoie des résultats (DMA, liaison série) Mémoire Organisation mémoire Architecture de Harvard modifiée La mémoire peut contenir soit des instructions soit des données Memoire interne (0x0000 0000 -> 0x0007 FFFF) Registres du proc + IO registers + 2 blocs 0 et 1 de 0,5 Mbits = 16K*32 bits Mémoire partagée (0x0008 0000 => 0x003F FFFF) Bus externe = 6 Sharc Mémoire externe (0x0040 0000 => 0xFFFF FFFF) Memory Map Organisation mémoire interne 0x 0000 0000 256 registres interne 0x 0000 0100 Réservé Accès 32 ou 48 bits Bloc0 Adressage normal Bloc 1 Adressage normal 0x 0002 0000 0x 0002 4000 0x 0002 8000 Alias Bloc 1 Accès 16 bits Bloc 0 Adressage court Bloc 1 Adressage court Alias Bloc 1 Adressage court 0x 0004 0000 0x 0004 8000 0x 0005 0000 0x 0008 0000 Bus d’adresse Accès // en 1 cycle sauf si même bloc 3 bus : PM (programmes) 24 bits d’@ 48 bits de données (inst) DM Fetch 16Mmots (data) 32 bits d’@ 32/40 bits de données Read/Wr 4Gmots IO 17 bits d’@ 48 bits de données PX Pont entre le bus PM et DM 6 contrôleurs DMA 128 Kmots Blocs - accès par taille de mots variables Harvard modifiée : chaque bloc peut contenir code et données Blocs à double accès : accès DMA par bus IO sur un port + accès PM/DM sur 2e port Bloc = 8 colonnes de 4K mots de 16 bits Un accès mot de 16, 32, 40 ou 48 bits 8 colonnes 1 instruction = 48 bits Accès 40/48 bits Accès 32 bits Accès 16 bits 4Kmots Accès 40 ou 48 bits Les données de 40 bits sont stockées dans de mots de 48 cadrées sur les MSB Un mot est donc stocké sur 3 colonnes dont seules les 6 première sont utilisables => 8K mots de 40 ou 48 bits c0 c1 c2 H M L 0x2 0000 B0 0x2 1000 0x2 0FFF 0x2 1FFF 0x2 4000 0x2 5000 B1 0x2 4FFF H M L c3 c4 c5 L H M c6 c7 - - - - 0x2 3FFF L 0x2 5FFF 0x2 3000 H M Accès 32 bits Un mot de 32 est donc stocké sur 2 colonnes => 16K mots de 32 par bloc c0 c1 H L 0x2 0000 B0 0x2 1000 c2 c3 H L 0x2 2000 c4 c5 H L 0x2 3000 0x2 0FFF 0x2 1FFF 0x2 2FFF 0x2 3FFF 0x2 4000 0x2 5000 0x2 6000 0x2 7000 B1 0x2 4FFF H L H 0x2 5FFF L H 0x2 6FFF L 0x2 7FFF c6 c7 H L H L Accès 16 bits (adressage court) Les adresses des accès 16 bits sont celles des accès 32 bits multipliées par 2 (cf. organisation mémoire) Avec le bit LSB à 0 pour lire les 16 bits LSB (colonnes 1, 3, 5, 7) et à 1 pour lire les MSB des mots de 32 bits (colonnes 0, 2, 4, 6) Exemple – contenu du bloc1 @ 0 1 2 3 4 5 6 7 0x000 140A 0004 0000 7FA1 1301 0002 A52D 05DF 0x001 142A 0000 0020 014B 063E 0002 BC45 69C3 0x002 0FDE 0131 2D91 AC05 A632 4593 F8EC 8726 … Accès 48 bits Adresse Mot lu - H M L 0x2 4000 140A 0004 0000 0x2 4001 142A 0000 0020 1301 0002 7FA1 … 0x2 5000 Accès 32 bits Adresse Mot lu - H L 0x2 4000 140A 0004 0x2 4001 142A 0000 0000 7FA1 … 0x2 5000 Accès 16 bits Adresse Mot Adresse mot 0x4 8000 0004 0x4 A000 7FA1 0x4 8001 140A 0x4 A001 0000 0FDE 0x4 E000 05DF … 0x4 8005 Accès à un bloc avec des formats différents Il est possible de mélanger dans un même bloc des instructions de 48 bits et des données de 32 bits Toujours placer les données après les instructions ! Toujours placer les données à partir d’une colonne paire (adresses multiples de 4K)! ‘Mapping’ de l’exécutable dans l’espace mémoire - segments MEMORY { isr_table { TYPE(PM RAM) START(0x00020000) END(0x000200FF) WIDTH(48) } seg_init { TYPE(PM RAM) START(0x00020100) END(0x0002010F) WIDTH(48) } b0_code { TYPE(PM RAM) START(0x000200e0) END(0x00020fff) WIDTH(48) } b0_data { TYPE(PM RAM) START(0x00022800) END(0x00022cff) WIDTH(32) } b0_idat { TYPE(DM RAM) START(0x00022d00) END(0x00022fff) WIDTH(32) } b1_code { TYPE(PM RAM) START(0x00024000) END(0x00024Bff) WIDTH(48) } b1_data { TYPE(DM RAM) START(0x00024C00) END(0x00024Eff) WIDTH(32) } seg_heap seg_stak { TYPE(DM RAM) START(0x00026000) END(0x000266ff) WIDTH(32) } { TYPE(DM RAM) START(0x00026700) END(0x00026Aff) WIDTH(32)} } Configuration du type d’accès Résultat de l’édition de lien 0xCF28 0x0000 File2.o Image exécutable ‘loader’ section ‘loader’ section Code/data (file1.o) Code/data .text section .text section code .text (file1.o) .text (file2.o) .bss section data code 0x0000 File1.o .text section code .data section Init data Bibliothèque.lib .data section .data (file1.o) .data (file2.o) .bss section .bss (file1.o) .bss (file2.o) .data section Init data .bss section data }} Sections de code ROCESSOR p0{ LINK_AGAINST( $COMMAND_LINE_LINK_AGAINST) // Other object files to link against. OUTPUT( $COMMAND_LINE_OUTPUT_FILE ) // Resulting executable file name. SECTIONS{ interupt_vector_table { INPUT_SECTIONS( $OBJECTS(seg_rth) $LIBRARIES(seg_rth)) } >isr_table seg_init { INPUT_SECTIONS( $OBJECTS(seg_init) $LIBRARIES(seg_init)) } >seg_init block0_program_code { INPUT_SECTIONS( $OBJECTS(seg_pmco) $LIBRARIES(seg_pmco)) } >b0_code block1_program_code { INPUT_SECTIONS( $OBJECTS(seg_pmco) ) } >b1_code block0_data { INPUT_SECTIONS( $OBJECTS(seg_pmda) $LIBRARIES(seg_pmda)) } >b0_data block1_data { INPUT_SECTIONS( $OBJECTS(seg_dmda) $LIBRARIES(seg_dmda)) } >b1_data stackseg { ldf_stack_space = .; ldf_stack_length = MEMORY_SIZEOF(seg_stak); } > seg_stak heap { ldf_heap_space = .; ldf_heap_end = ldf_heap_space + MEMORY_SIZEOF(seg_heap) - 1; ldf_heap_length = ldf_heap_end - ldf_heap_space; } > seg_heap Modes d’adressage Modes d’adressage L’accès à la mémoire est utilisé avec : DM(adr) ou PM(adr) désigne l’accès mémoire par les bus DM/PM à l’adresse adr Adressage direct DM (0x24000) = R0; // accès par bus DM PM (0x24001) = R1; //accès par bus PM Adressage indirect Le Sharc dirpose de 2 jeux de registres DAG1 et DAG 2 (Data Adress Generator) permettant l’adressage indirect Cf. schéma suivant Chaque jeu de registre est doublé (shadows registres) DAG1 est relié au bus DM, 32 bits Les registres 0 à 7 sont donc de 32 bits DAG2 est relié au bus PM, 24 bits Les registres 8 à 15 sont donc de 24 bits Les DAGs DAG1 (32 bits) I0 I1 I2 I3 I4 I5 I6 I7 M0 M1 M2 M3 M4 M5 M6 M7 L0 L1 L2 L3 L4 L5 L6 L7 B0 B1 B2 B3 B4 B5 B6 B7 registres d’index registres modifieurs registres longueur et base (buffers circulaires) registres principaux registres shadow Les DAGs DAG1 (32 bits) I0 I1 I2 I3 I4 I5 I6 I7 DAG2 (24 bits) I8 I9 I10 I11 I12 I13 I14 I15 M0 M1 M2 M3 M4 M5 M6 M7 M8 M9 M10 M11 M12 M13 M14 M15 L0 L1 L2 L3 L4 L5 L6 L7 L8 L9 L10 L11 L12 L13 L14 L15 B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 registres principaux registres shadow registres principaux registres shadow DAGs Ix registres d’index Chaque registre Ix peut être associé à un offset sous forme D’un immédiat Ou d’un registre My (modificateur) 2 modes : Pré incrémenté sans modification de l’index Post incrémenté avec modification Exemple Post R0 = 0xA0A0A0A0; M6 = 2; I0 = 0x0002 4000; DM(I0, M6) = R0; // I0 est modifié après accès mémoire et devient 0x0002 4002 Pré R0 = 0xA0A0A0A0; I0 = 0x0002 4000; DM(0xFFFF FFFF, I0) = R0; // accès mémoire à l’@ 0x23FFF (+ (-1)) et I0 reste à la valeur 0x0002 4000 Adressage circulaire Utilisation des registres Bx et Lx associés à un reg. Ix Bx = Base de buffer Lx = Longueur à initialiser à une valeur non nulle Lorsque Bx est initialisé, le Ix correspondant est automatiquement initialisé à la même valeur Ix est utilisé en indirect normal avec 2 restrictions : L’offset (My ou Imd) doit être inférieur à Lx Le mode pré incrémenté ne peut être utilisé Une interruptions indicative est généré au dépassement lorsque Ix est ramené circulairement Exemple Adressage de buffers circulaires : B0 = 0x00024000, //init. de B0 et I0 L0 = 8; //init. longueur du buffer M1 = 1; //init. modifieur R0 = DM(I0,M1); //si IO>B0+L0 alors // I0=B0 L’utilisation des buffers circulaires B0 L0 longueur et base du tableau I0 pointeur sur le tableau Les mécanismes de déplacement du pointeur, de test de la fin du tableau et de ré-initialisation sont câblés dans les DAG... Modes d’adressage Codes Conditions Pipeline Pipeline Le sharc dispose d’un pipeline à 3 étages 3 instructions sont en cours de traitement 1 instruction se termine à chaque cycle Le fonctionnement idéal est perturbé lorsque : Une instruction N utilise le bus PM pour accéder à la mémoire. Il y a alors conflit avec la phase de fetch de l’instruction N+2. Le compilateur ajoute un cycle d’attente (NOP) L’instruction N provoque une rupture de séquence (JUMP, CALL). L’instruction N+1 adresse la mémoire avec un registre de DAG modifié par l’instruction N exemple d’utilisation du cache 0x20000: ... 0x20001: R0 = PM(0x23013); // lecture sur bus PM 0x20002: R2 = R0 + R1; // opération arithmétique 0x20003: DM(0x24000) = R0; // écriture sur le bus DM 0x20004: ... 0x20005: ... exemple d’utilisation du cache (1ère occurrence) Execute Execute Decode Decode Execute Fetch Fetch Execute Decode Lecture data sur leDecode bus Fetch PM Fetch Decode Recherche sur le bus PM 0x20000: ... 0x20001: R0 = PM(0x23013); 0x20002: R2 = R0 + R1; 0x20003: DM(0x24000) = R0; 0x20004: ... 0x20005: ... Les deux opérations nécessitent deux accès simultanés sur le même bus ! exemple d’utilisation du cache (1ère occurrence) .... .... Fetch + Mise en cache 0x20000: ... 0x20001: R0 = PM(0x23013); 0x20002: R2 = R0 + R1; 0x20003: DM(0x24000) = R0; 0x20004: ... 0x20005: ... Cache instructions : 00 0 01 0 03 1 DM(0x24000) = R0 exemple d’utilisation du cache (1ère occurrence) Execute Decode .... 0x20000: ... 0x20001: R0 = PM(0x23013); 0x20002: R2 = R0 + R1; 0x20003: DM(0x24000) = R0; 0x20004: ... 0x20005: ... Cache instructions : 00 0 01 0 03 1 DM(0x24000) = R0 exemple d’utilisation du cache (1ère occurrence) Execute Decode Fetch 0x20000: ... 0x20001: R0 = PM(0x23013); 0x20002: R2 = R0 + R1; 0x20003: DM(0x24000) = R0; 0x20004: ... 0x20005: ... Cache instructions : 00 0 01 0 03 1 DM(0x24000) = R0 exemple d’utilisation du cache (1ère occurrence) Execute Decode Fetch 0x20000: ... 0x20001: R0 = PM(0x23013); 0x20002: R2 = R0 + R1; 0x20003: DM(0x24000) = R0; 0x20004: ... 0x20005: ... Cache instructions : 00 0 01 0 03 1 DM(0x24000) = R0 exemple d’utilisation du cache (2ème occurrence) Execute Execute Decode Decode Execute Fetch Fetch Execute Decode Decode Fetch Fetch 0x20000: ... 0x20001: R0 = PM(0x23013); 0x20002: R2 = R0 + R1; 0x20003: DM(0x24000) = R0; 0x20004: ... 0x20005: ... Cache instructions : 00 0 01 0 03 1 DM(0x24000) = R0 exemple d’utilisation du cache (2ème occurrence) Execute Decode Fetch 0x20000: ... 0x20001: R0 = PM(0x23013); 0x20002: R2 = R0 + R1; 0x20003: DM(0x24000) = R0; 0x20004: ... 0x20005: ... Cache instructions : 00 0 01 0 03 1 DM(0x24000) = R0 exemple d’utilisation du cache (2ème occurrence) Execute Decode Fetch 0x20000: ... 0x20001: R0 = PM(0x23013); 0x20002: R2 = R0 + R1; 0x20003: DM(0x24000) = R0; 0x20004: ... 0x20005: ... Cache instructions : 00 0 01 0 03 1 DM(0x24000) = R0 exemple d’utilisation du cache (2ème occurrence) Execute Decode Fetch 0x20000: ... 0x20001: R0 = PM(0x23013); 0x20002: R2 = R0 + R1; 0x20003: DM(0x24000) = R0; 0x20004: ... 0x20005: ... Cache instructions : 00 0 01 0 03 1 DM(0x24000) = R0 Conclusion sur l’utilisation du cache Le pipeline entraîne l’ajout d’un cycle supplémentaire à chaque fois qu’un conflit d’accès au bus est détecté. La présence du cache d’instruction ne permet de résoudre le conflit qu’à la deuxième occurrence seulement. ⇒ Un code optimisé (en vitesse) ne contient de conflits de bus qu’à l’intérieur des boucles... problème 2 : Le cas des dépendances de données Lors de la phase de décodage de l’instruction, le processeur prépare l’accès aux données et calcule l’adresse des accès en mémoire. Il y a conflit de dépendance de données lorsqu’une instruction effectue un accès en mémoire avec un registre d’index (Ix) modifié lors de l’instruction précédente. Execute 0x20002: Decode 0x20003: 0x20004: I0 = 0x23013; // Init index I0 R2 = DM(I0,M0) // accès avec IO ... La modification de l’index I0 et le calcul de l’adresse avec I0 nécessiteront deux cycles au lieu d’un ! problème 3 : Le cas des ruptures de séquence Execute R0 = R1 + R2; Execute Decode R2 = lshift R2 by 12; Decode Execute Fetch CALL Fetch !! !! routine; routine: R5 = 1; R5 = 0; R9 = min(R5, R2); I8 = tableau; ... ... problème 3 : Le cas des ruptures de séquence R0 = R1 + R2; R2 = lshift R2 by 12; CALL NOP !! routine; routine: Fetch R5 = 1; R5 = 0; R9 = min(R5, R2); I8 = tableau; ... ... problème 3 : Le cas des ruptures de séquence R0 = R1 + R2; R2 = lshift R2 by 12; CALL routine; R5 = 0; NOP I8 = tableau; ... routine: Decode Fetch R5 = 1; R9 = min(R5, R2); ... problème 3 : Le cas des ruptures de séquence R0 = R1 + R2; R2 = lshift R2 by 12; CALL routine; R5 = 0; I8 = tableau; ... routine: Execute R5 = 1; Decode R9 = min(R5, R2); Fetch ... ⇒ Deux cycles sont perdus (idem lors du retour de la routine) !! solution : Utilisation des branchements retardés Execute Decode Execute CALL Execute Fetch Decode R0 = R1 + R2; Execute Decode Fetch Fetch Decode R2 = lshift R2 by 12; Execute Fetch Decode R5 = 0; routine (DB); I8 = tableau; routine: Fetch R5 = 1; R9 = min(R5, R2); ... ... ⇒ Pas de perte de cycles au moment du branchement (idem lors du retour du sous-programme) ! INCONVENIENT : si la rupture de séquence se trouve à l ’intérieur d’une boucle de moins de trois instructions, le branchement retardé est impossible ! 2.4.3) Les boucles câblées Dans les applications de traitement du signal, la plupart des traitements font intervenir des calculs sur des structures de données de taille connue à l’avance (convolutions, matrices, FFT, etc). Pour optimiser ces calculs, le processeur DSP possède un mécanisme de boucles câblées (hardware loops) qui accélère les tests de fin de boucle. R4 = 8; MRF = 0; test de fin LCNTR = 8, DO _loop UNTIL LCE; R0 = DM(I0,M0); longueur de la boucle R5 = lshift R0 by R4; _loop: MRF= MRF + R5*R5; ... corps de la boucle R4 = 8; MRF = 0; LCNTR = 8, DO _loop UNTIL LCE; R0 = DM(I0,M0); A l’exécution : le compteur est initialisé, les adresses de fin et de début sont empilées dans des piles hardware R5 = lshift R0 by R4; _loop: MRF= MRF + R5*R5; ... Au cycle Fetch : le compteur est décrémenté, la condition de fin est testée et la prochaine adresse est calculée (adresse de début ou prochaine adresse) Pour la réalisation de boucles imbriquées, le processeur dispose de piles matérielles (hardware) de profondeur 6 (6 boucles imbriquées maximum) : Pile des compteurs de programme, Pile des compteurs de boucle, Pile des adresses de fin de boucle. problème 1 : Le pipeline et les boucles câblées R4 = 32; La condition est un résultat nul DO _loop UNTIL EQ; R0 = DM(I0,M0); _loop: R5 = R0 - R4; ... Au cycle Fetch : l’indicateur est celui résultant de l’exécution de R4=32 (pour le premier passage)... Pour des boucles de longueur faible, le processeur « duplique » les instructions dans son pipeline et ajoute, lorsque c’est nécessaire, des « NOP » en fin de boucle pour la terminaison : longueur 1 1 2 2 répétition 1 ou 2 >= 3 1 >= 2 dummy cycles 2 0 2 0 problème 2 : Le pipeline, les branchements et les boucles câblées R4 = 32; LCNTR = 8, DO _loop UNTIL LCE; ... CALL routine; R0 = DM(I0,M0); _loop: R5 = R0 - R4; ... Cette instruction sera lue (cycle Fetch) deux fois à cause de l’instruction de branchement : 1ère fois sans être exécutée (CALL), 2ème fois au retour de la routine. ⇒ Le compteur de boucle est décrémenté deux fois ! PAS de ruptures de séquence non retardées dans les trois dernières instructions d’une boucle câblée ! Plus généralement : pas de branchements dans les boucles (code peu efficace) ! Conclusion sur l’utilisation des boucles Les boucles câblées sont un moyen efficace d’optimiser les performances d’un code (traitement du signal = nombreuses boucles) mais le pipeline impose une attention particulière pour le codage des boucle ! ⇒ Un code optimisé (en vitesse) ne contient de conflits de bus qu’à l’intérieur des boucles... ⇒ Les boucles doivent être de longeurs significatives (déroulage des boucles courtes) ⇒ Les boucles ne doivent pas contenir de branchements ! Les registres du Sharc Registres du processeur SHARC 21061 Universal Registers Program Sequencer Data Address Generators Bus Exchange Timer System Registers Registres du processeur Registres de contrôle Registres d’état Register Function Initialization After Reset MODE1 Mode Control 1 0x0000 (cleared) MODE2 Mode Control 2 0xn000 0000 * ASTAT Arithmetic Status 0x00nn 0000 ** STKY Sticky Status 0x0540 0000 IRPTL Interrupt Latch 0x0000 (cleared) IMASK Interrupt Mask 0x0003 IMASKP Interrupt Mask Pointer 0x0000 (cleared) USTAT1 User Status 1 0x0000 (cleared) USTAT2 User Status 2 0x0000 (cleared) Registres d’IO Register Function Initialization After Reset SYSCON System Configuration 0x0000 0010 SYSTAT System Status 0x0000 0nn0 * Interruptions Interruptions Les Sharc dispose de 3 entrées d’IR externes : IRQ0, IRQ1, IRQ2 Actives sur front (descendant) Ou sur niveau (bas) Il y a également des sources d’IR internes Lorsque qu’une IR est détectée, elle est mémorisée dans le registre IRPTL. Son numéro dans le registre correspond à sa priorité La table des vecteurs d’IR comporte 32 entrées de 4 instructions chacune à l’adresse 0x0002 0000 en mémoire interne bloc 0. Vecteur d’interruption Masquage des IR Globalement par le bit IRPTEN du registre MODE1 (0=masquée) Individuellement avec les bits du registre IMASK (sauf le RESET) Lorsqu’une IR est acceptée Le PC est poussé dans la pile PC Les registres ASTAT sont poussés dans la pile de statut La demande est effacée de IRPTL La prochaine instruction est celle du vecteur d’IR associé Programmation du DSP Modes de programmation 3 choix de programmation Langage C Langage Assembleur Mixte Programmation en C Le mode de programmation C est le mode par défaut si aucun fichier .LDF n’a été associé. Dans ce cas le fichier 21061.LDF est utilisé par défaut. Le fichier 060_hdr.doj qui initialise les tables d’interruptions et appelle la fonction main() est ajouté. Le point d’entrée du programme est à l’adresse 0x20005 (2e mot du vecteur RESET) La fin du programme est un boucle infinie contenant IDLE associée au label __lib_prog_term. Le paramètre n de return (n) est écrit dans R0 ou il peut être lu après l’exécution. Extension du C ANSI Mots clés : Inline <function> : indique que le code de function doit être intégré dans le code l’appelant asm(‘’texte’’) : insère le code ASM dans le prog C dm/pm : forcer l’allocation es variables globales ou statique en DM ou en PM Segment(‘nom’) : spécifier explicitement le nom du segment des instr/données qui suivent Bool : type booléen Programmation assembleur Registres et paramètres de fonctions Paramètres Les 3 premiers paramètres passés à une fonction asm sont passés dans les registres R4,R8 et R12 dans cet ordre. Ensuite les autres sont passés dans la pile. Gestion de la pile I6 est le frame pointer I7 est le stack pointer Valeur de retour La valeur retournée par une fonction est passée dans R0. Nommage Une variable nommée X et C doit être nommée _X en assembleur Exemple Y(n) = a.X(n) + b.X(n-1) // Acquisition R0 = dm (Entree_Droite); R0 = ashift r0 by -1; R1 = dm (Entree_Droite); R1 = ashift r1 by -1; R15 = r0 + r1; // Traitement R2 = 0x7FFF FFFF; // 1 en Q1.31 R3 = dm (Coeff_RC); // r3 = Coef a R2 = r2-r3; // r2 = coef b = 1-a R0 = r15*r3 (SSF); // r0 = x(n)*a R1 = dm (Accu_Sortie);// - R1 = r1 * r2 (SSF); //r1 = y(n-1) * b R4 = r1 + r0 // r4 = a.x(n) + b.y(n-1) Dm (Accu_sortie) = r4; // Sortie Dm(Sortie_Droite) = r4; Dm (Sortie_Gauche) = r4; 2.4.4) Les instructions parallèles Certaines instructions peuvent provoquer des opérations en parallèle : Double additions-soustractions : R0 = R8+R12, R1 = R8-R12; Multiplication/Accumulation et addition/soustraction en virgule fixe R0 = R1*R4 (SSFR), R2 = R8-R12; Multiplication et opération arithmétique en virgule flottante F2 = F0*F4, F5 = (F8+F12)/2; Multiplication et double addition-soustraction en virgule fixe ou flottante R5=R0*R4(SSFR),R6=R9+R13,R7=R9-R13; F0=F1*F5, F1=F8+F12, F2=F8-F12; Ces instructions peuvent s’effectuer également en parallèle avec des transferts sur les bus DM et PM simultanés... F0=F1*F5, F1=F8+F12, F5=F8-F12, F8=DM(I0,M0),F12=PM(I8,M8); Exemple Code C : Int additionne(int a, int b, int c, int d, int e){ Int J; J = additionne (1,2,3,4,5); J++; } Code asm compilé R2 = 5; // dernier paramètre DM (I7, -1) = R2; // mise au sommet de pile R1 = 4; // avant dernier DM(I7, -1) = R1; R12 = 3; R8 = 2; R4 = 1; CJUMP _additionne(DB); // DB = retardé CJUMP fait aussi R2 = I6 et I6 = I7 DM (I7, -1) = R2; // empile R2 = ancien frame pointer DM(I7, -1) = PC; // empile l’@ courante MODIFY (I7, 2); // Au retour de l’appel dépile les 2 dernier paramètres R3 = R0; R3 = R3 +1; // J++ Code du fichier asm .SECTION/PM seg_pmco; .GLOBAL _Additionne; _Additionne : MODIFY(I7, -1); DM (-2, I6) = R1; R0 = R0 +R8; R0 = R0 + R12, R1 = DM(1, I6); // avant dernier paramètre R0 = R0 + R1, R1 = DM(1,I6); // dernier paramètre R0 = R0 + R1, R1 = DM(-2;I6);// Restitue R1 I12 = DM(-1, I6); // Adresse de retour -1 JUMP (M14, I12) (DB); I7 = I6; I6 = DM(0, I6); // saut de retour, M14 = 1 !! // restitue la pile // restitue ‘ancien frame pointer Illustration I7 Sauvegarde de R1 Adresse de retour -1 (@ de DM(I7, -1) = PC Ancienne valeur de I6 (dans le prog principal) 4 (avant dernier param) 5 (dernier param) I7 au début de la fonction I6 (I7 à la fin de la fonction)