SCALETTA LEZIONE SERT E10 -- 6 dicembre 2012 *** Gestione delle interruzioni *** 1 I punti salienti della gestione delle interruzioni in SERT 1.1 Utilizzo soltanto di interruzioni IRQ "vectored" (per ora non servono gli altri tipi) 1.2 Il modo normale di esecuzione per il sistema e' SYSTEM 1.2.1 Tutti i "task" sono privilegiati 1.3 I gestori delle interruzioni non fanno uso di uno stack diverso da quello del modo SYSTEM 1.3.1 Il salvataggio del contesto di esecuzione all'occorrenza di una interruzione deve essere effettuato sullo stack SYSTEM 1.3.2 Il modo corrente della CPU e' indicato da bit nel registro cpsr: - modo SYSTEM: maschera 0x1f - modo IRQ: maschera 0x12 - modo FIQ: maschera 0x11 1.4 La gestione delle interruzioni ha tre livelli: 1.4.1 Livello basso: procedura Assembler definita all'indirizzo di memoria 0x00000018 (vedi lucido 23 della lez. E4) che salva e recupera il contesto di esecuzione 1.4.2 Livello intermedio: procedura C che interagisce con il VIC e ricava l'indirizzo della ISR da eseguire 1.4.3 Livello alto: ISR, ossia funzione C specifica per l'interruzione attivata 1.5 Sezioni critiche implementate tramite disabilitazione delle interruzioni 1.5.1 Il bit 0x80 del registro cpsr disabilita gli IRQ 1.5.2 Il bit 0x40 del registro cpsr disabilita i FIQ 2 Modficare il file startup.S per impostare la modalita' iniziale d'esecuzione +--------------------------------------------+ |.equ IRQ_MODE, 0x12 | |.equ SYS_MODE, 0x1f | |.equ FIQ_BIT, 0x40 | |.equ IRQ_BIT, 0x80 | |[...] | |msr cpsr_c,#(SYS_MODE|IRQ_BIT|FIQ_BIT) | +--------------------------------------------+ 3 Modificare il file ts7250.h per la programmazione dei VIC: +----------------------------------------------------------------------+ |static const unsigned int VIC1_BASE = 0x800b0000 / 4; | |static const unsigned int VIC2_BASE = 0x800c0000 / 4; | |enum { VICIRQStatus, VICFIQStatus, VICRawIntr, VICIntSelect, | | VICIntEnable, VICIntEnClear, VICSoftInt, VICSoftIntClear, | | VICProtection, VICVectAddr = 12, VICDefVectAddr, | | VICVectAddrBase = 0x40, VicVectCntlBase = 0x80 }; | | #define VICIRQStatus1 (u32)(VIC1_BASE+VICIRQStatus) | | #define VICIRQStatus2 (u32)(VIC2_BASE+VICIRQStatus) | | #define VICFIQStatus1 (u32)(VIC1_BASE+VICFIQStatus) | | #define VICFIQStatus2 (u32)(VIC2_BASE+VICFIQStatus) | | #define VICRawIntr1 (u32)(VIC1_BASE+VICRawIntr) | | #define VICRawIntr2 (u32)(VIC2_BASE+VICRawIntr) | | #define VICIntSelect1 (u32)(VIC1_BASE+VICIntSelect) | | #define VICIntSelect2 (u32)(VIC2_BASE+VICIntSelect) | | #define VICIntEnable1 (u32)(VIC1_BASE+VICIntEnable) | | #define VICIntEnable2 (u32)(VIC2_BASE+VICIntEnable) | | #define VICIntEnClear1 (u32)(VIC1_BASE+VICIntEnClear) | | #define VICIntEnClear2 (u32)(VIC2_BASE+VICIntEnClear) | | #define VICIntSoftInt1 (u32)(VIC1_BASE+VICIntSoftInt) | | #define VICIntSoftInt2 (u32)(VIC2_BASE+VICIntSoftInt) | | #define VICSoftIntClear1 (u32)(VIC1_BASE+VICSoftIntClear) | | #define VICSoftIntClear2 (u32)(VIC2_BASE+VICSoftIntClear) | | #define VICProtection1 (u32)(VIC1_BASE+VICProtection) | | #define VICProtection2 (u32)(VIC2_BASE+VICProtection) | | #define VICVectAddr1 (u32)(VIC1_BASE+VICVectAddr) | | #define VICVectAddr2 (u32)(VIC2_BASE+VICVectAddr) | | #define VICDefVectAddr1 (u32)(VIC1_BASE+VICDefVectAddr) | | #define VICDefVectAddr2 (u32)(VIC2_BASE+VICDefVectAddr) | | #define VICVectAddrBase1 (u32)(VIC1_BASE+VICVectAddrBase) | | #define VICVectAddrBase2 (u32)(VIC2_BASE+VICVectAddrBase) | | #define VICVectCntlBase1 (u32)(VIC1_BASE+VICVectCntlBase) | | #define VICVectCntlBase2 (u32)(VIC2_BASE+VICVectCntlBase) | |#define irq_enable() do { \ | | __asm__ __volatile__ ("mrs %0,cpsr\n\t" \ | | "bic %0,%0,#0x80\n\t" \ | | "msr cpsr_c,%0\n\t" \ | | : "=r" (_temp) \ | | : : "memory"); \ | |} while (0) | |#define irq_disable() do { \ | | unsigned long _temp; \ | | __asm__ __volatile__ ("mrs %0,cpsr\n\t" \ | | "orr %0,%0,#0x80\n\t" \ | | "msr cpsr_c,%0\n\t" \ | | : "=r" (_temp) \ | | : : "memory"); \ | |} while (0) | +-------------------------------------------------------------------+ 4 Modificare init.c per inizializzare i VICs +------------------------------------------------------+ |extern void _irq_handler(void); | |[...] | |static void init_vics(void) | |{ | | iomem[VIC1_BASE+VICIntEnClear] = 0xffffffffUL; | | iomem[VIC2_BASE+VICIntEnClear] = 0xffffffffUL; | | iomem[VIC1_BASE+VICIntSelect] = 0UL; | | iomem[VIC2_BASE+VICIntSelect] = 0UL; | | iomem[VIC1_BASE+VICDefVectAddr] = (u32) _panic; | | iomem[VIC2_BASE+VICDefVectAddr] = (u32) _panic; | | irq_enable(); | |} | |[...] | | vector[14] = (u32) _irq_handler; | |[...] | | init_vics(); | +------------------------------------------------------+ 5 Scrivere la funzione Assembly _irq_handler() in irqhandler.S +--------------------------------------+ | .equ NO_IRQ, 0x80 | | .equ NO_FIQ, 0x40 | | .equ NO_INT, (NO_IRQ|NO_FIQ) | | .equ FIQ_MODE, 0x11 | | .equ IRQ_MODE, 0x12 | | .equ SYS_MODE, 0x1f | | .section .text | | .code 32 | | .globl _irq_handler | |_irq_handler: | | mov r13,r0 | | sub r0,lr,#4 | | mov lr,r1 | | mrs r1,spsr | | msr cpsr_c,#(SYS_MODE|NO_IRQ) | | stmfd sp!,{r0,r1} | | stmfd sp!,{r2-r3,r12,lr} | | mov r0,sp | | sub sp,sp,#(2*4) | | msr cpsr_c,#(IRQ_MODE|NO_IRQ) | | stmfd r0!,{r13,r14} | | msr cpsr_c,#(SYS_MODE|NO_IRQ) | | ldr r12,=_bsp_irq | | mov lr,pc | | bx r12 | | msr cpsr_c,#(SYS_MODE|NO_INT) | | mov r0,sp | | add sp,sp,#(8*4) | | msr cpsr_c,#(IRQ_MODE|NO_INT) | | mov sp,r0 | | ldr r0,[sp,#(7*4)] | | msr spsr_cxsf,r0 | | ldmfd sp,{r0-r3,r12,lr}^ | | nop | | ldr lr,[sp,#(6*4)] | | movs pc,lr | +--------------------------------------+ 6 Scrivere la funzione C _bsp_irq() in irq.c +-------------------------------------------------------+ |void _bsp_irq(void) | |{ | | typedef void (*isr_t)(void); | | isr_t isr; | | iomem[VICSoftIntClear1] = 0xffffffffUL; | | iomem[VICSoftIntClear2] = 0xffffffffUL; | | if (iomem[VICIRQStatus1] != 0) { | | isr = (isr_t) iomem[VICVectAddr1]; | | if (!isr) _panic(); | | isr(); | | irq_disable(); | | iomem[VICVectAddr1] = (u32) isr; | | } | | if (iomem[VICIRQStatus2] != 0) { | | isr = (isr_t) iomem[VICVectAddr2]; | | if (!isr) _panic(); | | isr(); | | irq_disable(); | | iomem[VICVectAddr2] = (u32) isr; | | } | |} | +-------------------------------------------------------+ *** Tick periodico *** 7 Attivazione del tick periodico 7.1 Leggere la documentazione (manuale EP93xx, da pag. 5-12) 7.2 Aggiungere definizione del tick periodico in ts7250.h +-------------------------------------------------+ |static const unsigned int TEOI = 0x80930018 / 4; | |#define HZ (64) | +-------------------------------------------------+ 7.3 Aggiungere inizializzazione del tick periodico in init.c */ +------------------------------+ |[...] | |extern void init_ticks(void); | |init_ticks(); | +------------------------------+ 7.4 Scrivere l'inizializzazione del tick periodico in tick.c */ +------------------------------------------------------------------+ |#define TICK_INTERRUPT (35) | |#define TICK_VIC2_INTERRUPT (TICK_INTERRUPT-32) | |#define TICK_VIC2_INTERRUPT_MASK (1UL<