/* ---------------------------------------------------------- @ led_blink_irq.s: Utilisation des interruptions AIC, d'un @ des trois timers et du PIO ---------------------------------------------------------- */ .include "carte.inc" .global _start @ Pour éviter le warning de arm-elf-ld _start: main: @ Pour le point d'arrêt automatique @mov r13,#0x20000 @ pile en 0x20000 adr r9, tableau ldr r8, =ft bl INIT_PIO_AIC bl INIT_USART @affichage initial bl AFFICH_CADRE @On attend que la procédure de départ soit finie pour commencer la partie att_depart: cmp r9, r8 bne att_depart exit: @ Retour â Angel par exception (appel systême) mov r0, #0x18 ldr r1, =0x20026 swi 0x123456 @ =============================================================== @ Fin du programme principal @ =============================================================== @=====Affiche le cadre du plateau de jeu========================= AFFICH_CADRE: @----------------Dimensions du cadre ~ 80 / 22------------------- stmfd r13!, {r0, r1, r14} mov r1, #1 @r1 est le compteur pour savoir combien de caractère on a affiché @affichage de la 1e ligne @Passage en mode graphique pour pouvoir afficher le cadre mov r0, #0xe bl PUTCHAR @angle en haut à gauche mov r0, #0x6c bl PUTCHAR @ligne horizontale mov r0, #0x71 tq_affich_ligne_plateau: cmp r1, #50 beq ftq_affich_ligne_plateau bl PUTCHAR add r1, r1, #1 b tq_affich_ligne_plateau ftq_affich_ligne_plateau: @angle au milieu à gauche mov r0, #0x77 bl PUTCHAR add r1, r1, #1 @pour avoir une longueur de 80 @ligne horizontale mov r0, #0x71 tq_affich_ligne_score: cmp r1, #79 @le 80e caractère est un angle beq ftq_affich_ligne_score bl PUTCHAR add r1, r1, #1 b tq_affich_ligne_score ftq_affich_ligne_score: @angle au milieu à droite mov r0, #0x6b bl PUTCHAR @barre verticale mov r1, #2 @on commence à la 2e ligne mov r0, #0x78 tq_affich_barre: cmp r1, #20 @le plateau fait 20 lignes de hauteur beq ftq_affich_barre @positionnement du caractère bl ITOA mov r4, #'0' mov r5, #'0' stmfd r13!, {r2, r3, r4, r5} bl POS sub r13, r13, #16 @affichage du caractère bl PUTCHAR mov r4, #'5' mov r5, #'0' stmfd r13!, {r2, r3, r4, r5} bl POS sub r13, r13, #16 @affichage du caractère bl PUTCHAR add r1, r1, #1 b tq_affich_barre ftq_affich_barre: @Sortie du mode graphique mov r0, #0x1b bl PUTCHAR mov r0, #'n' bl PUTCHAR ldmfd r13!, {r0, r1, r15} @===================Integer TO Ascii, entier placé par registre r1, renvoie les caractères par registres r2, r3============================= ITOA: mov r3, r1 mov r2, #0 tq_itoa: cmp r3, #10 blo ftq_itoa add r2, r2, #1 sub r3, r3, #10 b ftq_itoa ftq_itoa: @on convertit chaque chiffre en caractère add r2, r2, #48 add r3, r3, #48 mov r15, r14 @=====Position du curseur (4 paramètres placés par pile)========= POS: stmfd r13!, {r0, r14} mov r0, #0x1B bl PUTCHAR mov r0, #'[' bl PUTCHAR ldr r0, [r13, #8] bl PUTCHAR ldr r0, [r13, #12] bl PUTCHAR mov r0, #';' bl PUTCHAR ldr r0, [r13, #16] bl PUTCHAR ldr r0, [r13, #20] bl PUTCHAR mov r0, #'H' bl PUTCHAR ldmfd r13!, {r0, r15} @=============Initiallisation PIO / AIC=========================== INIT_PIO_AIC: @ initialisation des leds @ ----------------------- ldr r12,=PIO_BASE ldr r0,=(LED8|LED7|LED6|LED5|LED4|LED2|LED3|LED1) str r0,[r12, #PIO_PER] @ Autoriser les ports str r0,[r12, #PIO_OER] @ P6 et P16 en sortie @str r0,[r1, #PIO_CODR]@ eteindre les leds 8 et 1 @ initialisation du timer1 @ ----------------------- ldr r10,=TC1_BASE mov r0,#0b10 str r0,[r10, #TC_CCR] @ interdire l'horloge du compteur mvn r0,#0x0 str r0,[r10, #TC_IDR] @ interdire la génération d'interruption ldr r0,[r10, #TC_SR] @ lire le SR de TC1 ldr r0,=0x4004 str r0,[r10, #TC_CMR] @ TC1 utilise MCK/1024 et redémarrage auto mov r0,#1 str r0,[r10, #TC_CCR] @ Autoriser l'horloge mov r0,#0x10 str r0,[r10, #TC_IER] @ Valider l'interruption de comparaison avec RC @ Initialisation AIC @ ----------------------- ldr r11,=AIC_BASE mov r0,#0b100000 str r0,[r11, #AIC_IDCR] @ Interdire l'interruption du Timer1 dans l'AIC adr r0, DRIVER_TIMER @ Mettre l'adresse de la routine d'interruption str r0,[r11, #AIC_SVR5] @ dans AIC_SVR5 (vecteur relatif à TC1_IRQ) mov r0,#0x04 @ Priorité 4 pour l'interruption TC1 str r0,[r11, #AIC_SMR5] mov r0,#0b100000 str r0,[r11, #AIC_ICCR] @ RAZ de l'interruption TC1 str r0,[r11, #AIC_IECR] @ Autorise l'interruption TC1 @ paramètres de timing du timer1 @ ----------------------- ldr r0,=64453 @ 64453 * MCK/1024 -> une seconde str r0,[r10, #TC_RC] @ Placer le délai dans le registre C mov r0,#0b100 @ Mise à 1 bu bit 2 de CCR str r0,[r10, #TC_CCR] @ -> RAZ compteur et démarrage mov r15, r14 @ =============================================================== @ Gestionnaire de l'interruption du timer 1 @ =============================================================== DRIVER_TIMER: @ ------------------------ @- Ajuster et sauvegarder le registre de retour du mode IRQ dans la pile IRQ sub r14, r14, #4 @ r14 pointe une instruction trop loin stmfd sp!, {r14} @ sauvegarder l'adresse de retour dans la pile IRQ @ Sauvegarder SPSR et R0 dans la pile IRQ mrs r14, spsr stmfd sp!, {r0, r14} @ passer en mode systême mrs r14, cpsr orr r14, r14, #0b11111 @ (mode systême) msr cpsr, r14 @ Sauvegarde de registres dans la pile systême stmfd sp!, { r1, r2, r14} @ autoriser les interruptions mrs r14, cpsr bic r14, r14, #0x80 @ CPSR[I] <- 0 msr cpsr, r14 @ ----------------------- @ ldr r1,=TC1_BASE ldr r0,[r10, #TC_SR] @ Lecture SR pour le remettre à 0 @ (pour signifier qu'on traite l'IT) @ ldr r1,=PIO_BASE ldr r0, =LED1|LED2|LED3|LED4 ldrb r2, [r9], #1 mov r3, r2, lsl #16 and r0, r0, r3 str r0, [r12, #PIO_CODR] mvn r0, r0 str r0, [r12, #PIO_SODR] @ Fin interruption fin_irq: @- Interdire les interruptions mrs r0, cpsr orr r0, r0, #0b10000000 @ CPSR[I] <- 1 msr cpsr, r0 @ Restaurer les registres depuis la pile systême ldmfd sp!, { r1, r2, r14} @- repasser en mode IRQ mrs r0, cpsr bic r0, r0, #0x1F @ CPSR[MO..M4] <- 0b00000 orr r0, r0, #0b10010 @ CPSR[MO..M4] <- 0b10010 msr cpsr, r0 @ Indiquer la prise en compte de l'interruption à l'AIC @ = écriture de n'importe quoi dans AIC_EOICR @ ldr r0, =AIC_BASE str r11, [r11, #AIC_EOICR] @ Restaurer SPSR_irq et r0 à partir de la pile IRQ ldmfd sp!, {r0, r14} msr spsr, r14 @ Restaurer LR_irq depuis la pile IRQ et le mettre directement dans le PC ldmfd sp!, {pc}^ @ Fin du sous_programme d'interruption @==================================================================@ @ Sous-programme initialisation USART @ @ ----------------------------------- @ @ Paramètres : néant @ @ Valeur de retour : néant @ @==================================================================@ INIT_USART: stmfd r13!,{r0,r1,r14} @ Au cas ou, on desactive les ports du PIO @ pour USART1 @ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ldr r0,=PIO_BASE ldr r1,=0x700000 str r1,[r0,#PIO_PDR] str r1,[r0,#PIO_IDR] @ On initialise l'USART pour recevoir et transmettre des caractères @ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ldr r0,=USART1_BASE @ On fait un reset de l'émetteur et du récepteur @----------------------------------------------- ldr r1,=(US_RSTRX|US_RSTTX|US_RSTSTA) str r1,[r0,#US_CR] @ On active l'émetteur et le récepteur @------------------------------------- ldr r1,=(US_RXEN|US_TXEN) str r1,[r0,#US_CR] @ Configuration des modes @------------------------ @ - Clock Selection = MCK (US_CLKS_MCK) @ - Taille de caractère = 8 (US_CHRL_8) @ - Mode Asynchrone (SYNC=0) @ - Pas de parité (US_PAR_NO) @ - 1 stop bit (US_NBSTOP_1) @ - Normal Channel Mode (US_CHMODE_NORMAL) ldr r1,=(US_CLKS_MCK8|US_CHRL_8|US_PAR_NO|US_NBSTOP_1|US_CHMODE_NORMAL) str r1,[r0,#US_MR] @Initialisation du baud rate generator register (CD) @--------------------------------------------------- @ Cette valeur est calculée à partir de @ - MCK = 66.6 MHz @ - débit du terminal = 57600 @ - mode asynchrone (débit = MCK/(CD*16)) mov r1,#9 str r1,[r0,#US_BRGR] @Initialisation du temps de garde @-------------------------------- mov r1,#0xa str r1,[r0,#US_TTGR] @ Désactivation des interruptions de tout genre @---------------------------------------------- mov r1,#0x3F str r1,[r0,#US_IDR] ldmfd r13!,{r0,r1,r15} @==================================================================@ @ Sous-programme envoi d'un caractère sur gtkterm @ @ ----------------------------------------------- @ @ Paramètres : code ASCII passé dans r0 @ @ Valeur de retour : néant @ @==================================================================@ PUTCHAR: stmfd r13!,{r1,r2,r14} ldr r1,=USART1_BASE put_wait: ldr r2,[r1,#US_CSR] ands r2,r2,#US_TXRDY beq put_wait @ On place le caractère dans le registre @ Transmitter Holding Register ( US_THR) strb r0,[r1,#US_THR] ldmfd r13!,{r1,r2,r15} @==================================================================@ @ Sous-programme saisie d'un caractère au clavier @ @ ----------------------------------------------- @ @ Paramètres : néant @ @ Valeur de retour : code ASCII passé dans r0 @ @==================================================================@ GETCHAR: stmfd r13!,{r1,r2,r14} ldr r1,=USART1_BASE @ Attente active de l'arrivée d'un caractère @ tapé au clavier get_wait: ldr r2,[r1,#US_CSR] ands r2,r2,#US_RXRDY beq get_wait @ Une fois le caractère saisi, on le place dans r0 ldrb r0,[r1,#US_RHR] ldmfd r13!,{r1,r2,r15} tableau: .byte 1, 3, 7, 15, 0, 15, 0, 15, 0 ft: