IS1200 Exempelsamling till övning CE_O9, 2015 CE_O9. Exceptions, interrupts, traps. Förberedelser för lab 3, nios2int 9.1. Hantering av exceptions i Nios II. Vektoriserad hantering av Exceptions. Hur fungerar avbrottssystemet i Nios-II-processorn? Beskriv och diskutera idén med vektoriserad hantering av exceptions! Skissa hur man i Nios-II kan strukturera sin programvara för att efterlikna vektoriserad hantering av exceptions. DEL1: Assembler-kod för hantering av exceptions 9.2. Kopiering av trampolin / "stubbe" Exception i Nios-2-processorn leder till att den vanliga programexekveringen avbryts och viss information sparas i utvalda register i processorn. Körningen fortsätter på en av hårdvaran (av konstruktören) bestämd fast adress som i vår labutrustning är 0x800020. Det går inte att placera hela Exception Handler på adress 0x800020; dels finns det för lite plats och dels är det inte enkelt att få länkaren att lägga kod på en adress som programmeraren bestämmer själv. För att kunna placera sin Exception Handler på vilken plats som helst i minnet kan man på adress 0x800020 och framåt skriva in instruktioner som medför "hopp till ExceptionHandler". Att på adress 0x800020 skriva in önskade instruktioner ska du låta ett program utföra. Det görs genom att ha en "trampolin" som består av de instruktioner som ska kopieras till adress 0x800020. Sedan skriver du en instruktionsföljd som utför kopiering av stubben till plats 0x800020. Här följer ett exempel på lämpliga instruktioner att placera på adress 0x800020 stub: movhi r24,%hi(exchand) # ladda 16 MSB av adressen ori r24,r24,%lo(exchand) # ladda 16 LSB av adressen jmp r24 # utför hopp till Handler... ExcHand: # här finns koden för ExceptionHandler... Skriv assembler-kod som kopierar 3 instruktioner från stub: till 0x800020. Du kan antingen använda en subrutin av typen memcpy, eller skriva "rakt-på-kod". Uppgifter till övning CE_O9, sida 1 (av 9) 2015-02-24
9.3. Orsak till Exception: Interrupt, TRAP eller något annat? Skriv den del av assembler-koden i ExceptionHandler som "listar ut" om undantaget har orsakats av en Interrupt eller av en TRAP-instruktion. Hopp ska ske till de symboliska adresserna IntHandler respektive TrapHandler. Vid undantag av annat slag ska hopp ske till adressen ElseHandler. Denna programkod motsvarar övre delen av Figure 3-3 i Nios II Processor Reference Handbook, kapitel 3 Programming Model. 9.4. Nios II. Avbrott från timerenheten timer_1. Skriv ett huvudprogram i assembler som 5 gånger per sekund skriver ut en rad med texten "Bakgrundsprogram". Använd dig av subrutinerna WAITX (se exempel från övning 3) och PRTEX (se exempel från övning 5). Komplettera detta program och initiera timerkretsen för att generera avbrott varje millisekund och använd dessa avbrott för att en gång per sekund skriva ut "Time- Out" längst till vänster på en ny rad i terminalfönstret. Utskrifterna ska inte "blandas" dvs hela texten "Bakgrundsprogram" ska skrivas ut på en egen rad och hela texten "Time-Out" ska skrivas på egen rad. I denna uppgift ingår att skriva den del av IntHandler (enligt föregående uppgift) som upptäcker att avbrottet kommer just från timer_1 och som vid den upptäckten (gör ett hopp och) fortsätter exekvering vid den symboliska adresser TimerInt där man hittar koden för att hantera avbrott från timern. På adress 0x924 ska bit med index 0 vara ettställd för att tillåta avbrott från Timern. En Time-Out kvitteras genom att ett (godtyckligt) värde skrivs till adress 0x920. Timer_1 genererar avbrott med index 10. Uppgifter till övning CE_O9, sida 2 (av 9) 2015-02-24
9.5. Avbrott från serieport uart_0. Serieporten uart_0 kan ställas in så att den genererar avbrott då biten RxRdy ettställs. RxRdy är bit med index 7 på adress 0x868. Motsvarande gäller för TxRdy (bit med index 6 på adress 0x868). På adress 0x86C finns en maskbit vardera för RxRdy och TxRdy i motsvarande positioner, det vill säga bitar med index 7 och 6. Då man läser data från DataIn nollställs RxRdy. Då man skriver data till DataUt nollställs TxRdy. Serieporten uart_0 på adress 0x860 är ansluten till nios2-processorn, så att serieporten kan generera avbrott med index 4. Skriv i assemblerkod en avbrottsrutin, Uart0Int, som baserat på avbrott från uart_0 på adress 0x860 ekar tecken från tangentbord till terminalfönster. Använd in_char och out_char från uppgift 7.3. Komplettera programkoden i IntHandler, i uppgift 7.3 och 7.4 så att den vid avbrott från uart_0 "hoppar" med en br-instruktion till den symboliska adressen Uart0Int. 9.6. Avbrott från parallellport de2_pio_keys4. Beskriv hur avbrott kan genereras från KEY3 KEY0 i Nios2:s PIO-enhet de2_pio_keys4. Skriv en programkod, Keys_Int, som använder avbrott och skriver ut en siffra 3, 2, 1 eller 0 varje gång motsvarande knapp KEY3 KEY0 trycks ner och skriver ut tecken E, S, I eller O när knappen släpps. Observera att avbrott ges vid varje växling på någon av KEY3 KEY0 och att utskrift ska göras både då knappen trycks ner och släpps upp. Utforma programmet så att ingen knappnedtryckning "tappas bort", även om användaren trycker på flera knappar samtidigt i oförutsägbara kombinationer. Komplettera programkoden i IntHandler, i uppgift 7.3 och 7.4 så att den vid avbrott från button_pio "hoppar" till den symboliska adressen de2_pio_int. VIKTIG KOMPLETTERANDE INFORMATION OM de2_pio_keys4: På adress 0x840 finns "data-register" där bit 3 0 visar aktuellt värde på KEY3 KEY0. Släppt knapp ger en etta och nedtryckt knapp ger en nolla. KEY3 svarar mot bit 3, KEY2 mot bit 2, KEY1 mot bit 1 och KEY0 mot bit 0. På adress 0x848 finns avbrottsmask (interrupt mask). För att en knapp KEYi ska kunna generera avbrott måste motsvarande bit (av bitarna 3 0) i avbrottsmasken vara ettställd. På adress 0x84C finns "edge capture register". En växling av värde, från 0 till 1 eller från 1 till 0, på en knapp KEYi ger ettställning av motsvarande bit i registret. Om man skriver ett värde, vilket som helst, till Edge Capture Register så nollställs alla bitar i registret, alla avbrottssignaler kvitteras. Obs! Man kan inte nollställa (kvittera) enskilda bitar i Edge Capture Register varje skrivning nollställer alltid alla bitar. Porten de2_pio_keys4 genererar avbrott med index 2. Uppgifter till övning CE_O9, sida 3 (av 9) 2015-02-24
9.7. Exception med TRAP-instruktion Skriv programkod i Nios-2-assembler som använder en TRAP-instruktion. a) Du ska skriva kod för ett huvudprogram som med instruktionen TRAP "anropar" en "trap handler", som skriver ut en textsträng (nul-terminated string) som finns lagrad i minnet. Vid TRAP-anropet ska adressen till det första tecknet i strängen skickas med som en parameter i register r5 (Ja, i r5 eftersom r4 eventuellt ska användas för annat). b) Du ska skriva koden för Trap-rutinen som ska anropa subrutinen PRTEX, se uppgift 5.4, för att skriva ut textsträngen. Exempel på användbart direktiv: hello:.asciz "Hello World!" # texten lagras som null-terminated ASCII-code 9.8. Avbrott i en avbrottsrutin. Diskutera vilka åtgärder som krävs för att ett avbrott ska kunna tillåtas och hanteras inne i en avbrottsrutin. Vilka åtgärder måste vidtagas i en avbrottsrutin för KEY3 för att kunna släppa fram ett avbrott från knapp KEY0? 9.9. Timeravbrott i avbrottsrutin för timer_1. Antag att timern används för att generera avbrott varje millisekund och att man exakt varje sekund vill anropa en subrutin, WORK, som tar cirka 10-20 millisekunder att utföra, men olika lång tid vid varje anrop. Diskutera hur man detta kan åstadkommas genom att man låter avbrottsrutinen för timern bli avbruten av timern själv. Uppgifter till övning CE_O9, sida 4 (av 9) 2015-02-24
DEL2: C-kod för hantering av exceptions int 0 1 Avbrottsrutin 2 3 som gör subrutinanrop (call) till rätt avbrottshanterare null irq00hand irq01hand instr 31 irq31hand Interrupt Vector Table 9.10. Vektoriserat avbrott med Altera-supplied exception wrapper. Det finns en färdig Exception Handler (Altera-supplied exception wrapper) i den programvara som alltid länkas med vid kompilering i Nios II IDE. Hur fungerar denna Exception Handler? Läs beskrivning i lab-pm för laboration 3, Nios2Int. 9.11. Funktion/subrutin för avbrottshantering. En programmerare som vill använda Alteras färdiga Exception Handler (Alterasupplied exception wrapper) måste skriva en specialiserad funktion/subrutin (i C eller assembler), anpassad till den enhet som ska ge avbrott. Hur ska den funktionen/subrutinen se ut? Vilken/vilka inparametrar krävs och vilken parameter ska returneras. Läs beskrivning i lab-pm för laboration 3, Nios2Int. 9.12. Initialisering av vektoriserat avbrott. Förutsätt användning av Altera-supplied exception wrapper. Hur ska avbrottssystemet initialiseras för att programmerarens funktion/subrutin ska anropas vid avbrott? Kom ihåg att anropa alt_ic_isr_register ( ) Läs beskrivning i lab-pm för laboration 3, Nios2Int. Uppgifter till övning CE_O9, sida 5 (av 9) 2015-02-24
9.13. Speciellt för laborationerna: funktionen intfix Vad gör funktionen intfix (se bifogad kod) och varför behövs den? / intfix.c Unregisters all interrupt handlers, except for the JTAG UART and timer_0. Written by F Lundevall, re-written 2013-09-17. Copyright abandoned. This file is in the public domain. / #include <sys/alt_irq.h> / Allow interrupts for JTAG UART (number 0), and for timer_0 (number 1) which is used for the JTAG UART host-connection check. Calling alt_irq_register with some IRQ number, and the last argument set to 0 (NULL), will disable interrupts for that IRQ number. The initfix_int function calls alt_irq_register this way for all IRQ numbers except number 0 (the IRQ number of the JTAG UART), and 1 (the IRQ number of timer_0, used for the JTAG UART host-connection check. Note: to enable (rather than disable) an interrupt, call alt_irq_register with the last argument set to the address of an interrupt-handler function. / #define LOWEST_IRQ_NUMBER (2) #define HIGHEST_IRQ_NUMBER (16) / Additional side-effect, added 2013-09-17: disable the interrupt-outputs of serial ports uart_0 and uart_1. To do this properly, their addresses are defined here. / #define UART_0 ( (volatile int ) 0x860 ) #define UART_1 ( (volatile int ) 0x880 ) #define NULL ( (void ) 0) / initfix_int - unregister unused interrupt handlers Returns 0 if successful, a nonzero value otherwise. / int intfix( void ) { / Declare a temporary for checking return values from system-calls and library functions. / register int ret_val_check = 0; register int irq_number; for( irq_number = LOWEST_IRQ_NUMBER; irq_number < HIGHEST_IRQ_NUMBER; irq_number += 1 ) { ret_val_check = alt_ic_irq_disable( 0, irq_number ); } UART_0[3] = UART_1[3] = 0; / Serial ports / return( ret_val_check ); } Uppgifter till övning CE_O9, sida 6 (av 9) 2015-02-24
9.14. Huvudprogram i C. Skriv ett huvudprogram som anropar lämpliga initialiseringsrutiner för avbrott från serieport uart_0, som har basadress 0x860. Efter initialisering ska huvudprogrammet skriva ut punkter med jämna mellanrum. Förutsätt att initialiseringsrutinen för uart_0 heter uart_0_init. 9.15. Initialisering av serieport uart_0 i C. Skriv initialiseringsrutin i C för avbrott från uart_0. Kalla rutinen för uart_0_init. Avbrott ska göras vid inmatning från tangentbord eller motsvarande, då RxRdy ettställs. Utmatning (TxRDy) ska ej ge avbrott. Förutsätt att avbrottshanteraren för uart_0 heter uart_0_handler. 9.16. Avbrottshanterare för serieport uart_0 i C. Skriv avbrottshanterare i C för avbrott från uart_0. Kalla rutinen för uart_0_handler. Vid avbrott ska det inlästa tecknet "ekas" till skärmen, men med mellanslagstecken (ASCII-kod 0x20) före och efter. 8.17 Placering av subrutiner i C-program. Visa var i huvudprogrammet från uppgift 8.14 som initialiseringsrutinen från uppgift 8.15 ska placeras. Visa också var i huvudprogrammet som avbrottshanteraren från uppgift 8.16 ska placeras. Markera tydligt hur initialiseringsrutin och avbrottshanterare ska placeras i förhållande till varandra. Uppgifter till övning CE_O9, sida 7 (av 9) 2015-02-24
8.18...nios2int/nios2int.c Studera programkoden i nios2int.c (tidigare lab3upg6main.c ) a) Repetera innebörden av varje ord i raden volatile int const de2_pio_reled18_base = (volatile int ) 0x810; b) Studera och diskutera den bifogade koden för funktionen void timerinit_int( void ) { / Declare a local temporary variable for checking return values from system-calls and library functions. / register int ret_val_check; / Disable interrupts for timer_1, if they were enabled. The function alt_irq_disable returns an int, which always has the value 0. We use a type cast to void to tell the compiler that we really want to ignore the return value. / (void) alt_ic_irq_disable( 0, timer_1_intindex ); timer_1_period_low = TIMER_1_TIMEOUT & 0xffff; timer_1_period_high = TIMER_1_TIMEOUT >> 16; timer_1_control = 7; / START bit (must always be a 1) CONT bit (timer restarts on timeout) ITO bit (interrupt on timeout) / } / Set up Altera's interrupt wrapper for interrupts from the timer_1 device. Return value is zero for success, nonzero for failure. / ret_val_check = alt_ic_isr_register( 0, timer_1_intindex, timer_isr, NULL_POINTER, NULL_POINTER ); / If there was an error, terminate the program. / if( ret_val_check!= 0 ) n2_fatal_error(); Uppgifter till övning CE_O9, sida 8 (av 9) 2015-02-24
c) Studera och diskutera den bifogade koden för funktionen / Interrupt handler for timer_1. The parameters are ignored here, but are required for correct compilation. The type alt_u32 is an Altera-defined unsigned integer type. / void timer_isr( void context ) { timer_1_status = 0; / Acknowledge interrupt / tick( &mytime ); puttime( &mytime ); } 8.19 Eventuella uppgifter för framtiden (överkurs!!!) Modifiera koden för Toggles18-Handler så att man under tiden som BigDeal körs tillåter avbrott från Keys4, från Toggles18 och från Uart0 dvs avbrott med index 2, 3 och 4. (Och varför inte även från Timer med index 10?) Denna uppgift avser att förstärka insikten i behov av, innebörd av och användning av HAL-funktionerna alt_irq_interruptable() och alt_irq_non_interruptable() inklusive behov av inparametrar och returparametrar. Det är antagligen även fruktbart att försöka (be-)skriva den bakomliggande assemblerkoden eller med andra ord till vilken assemblerkod dessa funktioner översättes. Eller ännu mera maskinnära: hur påverkas hårdvaran i Nios2 av dessa 2 rutiner och parametervärden. Dessutom bör alla begravda hundar grävas upp och synas. Det är rimligt att förvänta sig att erbjudandet att använda HAL-funktioner ska underlätta användning av avbrottshantering helst utan att dölja eller försvåra förståelsen av hur det hela hänger ihop. Om programmeraren vill tillåta avbrott i avbrott måste programmeraren vidtaga vissa försiktighetsmått. Exakt vad och varför? Uppgifter till övning CE_O9, sida 9 (av 9) 2015-02-24