# PDI-2025: Practice 2-B: Basic Management of Interrupts, Exceptions and System calls. ## Objective In this practice, the student is expected to understand the hardware mechanisms that support interruptions, exceptions and system calls, so that they are able to define and use basic routines for their management. The use of these routines will allow the student to understand how other higher level services of embedded software systems can be defined (device drivers or system calls), and how to deal with the exceptional situations that can occur during their execution. ## Event handling mechanisms The event handling mechanisms (interrupts, exceptions and system calls) provided by the processors facilitate access to system resources in a protected manner, ensuring their integrity against misuse. On the one hand, by means of system call instructions (also known as executive calls or TRAPs) the user can request services that were configured during the system initialization stage. These services allow managing abstractions such as file systems, processes or access to communication ports. The interrupt mechanism, on the other hand, allows external devices to request the processor's attention, so that a routine is executed in response to its request. Thanks to this mechanism, it is possible to avoid the polling of the job status assigned to the devices. Finally, the exceptions allow you to define what to do when the processor is in an unstable state, such as when it executes an instruction whose code is not valid, or an unaligned access to data. ![](https://i.imgur.com/p5nEf9R.png) ### Schedule This practice is planned to be carried out in 2 weeks. ### P2-B project creation In order to create the ```P2-B``` project follow the same steps as for creating ```P2-A```. ## Exception/SYSCALL Handling Write to ```main``` function the following code: ```c= #include "riscv_types.h" #include "dispatch.h" #include "log.h" int main() { printf("----------SyscallS--------------\n"); printf("syscall 22\n"); syscall(22, 1); printf("syscall 15\n"); syscall(15, 2); printf("----------EXCEPTIONS---------\n"); printf("Write NULL pointer\n"); uint32_t *p = 0; *p = 234; // Attempt to write using a NULL pointer printf("READ NULL pointer\n"); uint32_t x = *p; // Attempt to read using a NULL pointer printf("UNALIGNED WRITE\n"); p = (uint32_t *)123; *p = 334; // Attempt to write an uint32_t value to an odd address printf("UNALIGNED READ\n"); x = *p; // Attempt to read an uint32_t value from an odd address return 0; } ``` ### Exception/TRAP handling test In order to test the program follow the steps below: * Build P2-B project and run it typing ```./runP2-B``` in eclipse terminal window. The output should look like as follows: ``` ----------SyscallS-------------- syscall 22 Syscall: 22 dispatch Param: 1 syscall 15 Syscall: 15 dispatch Param: 2 ----------EXCEPTIONS--------- Write NULL pointer Exception: 7 dispatch READ NULL pointer Exception: 5 dispatch UNALIGNED WRITE Exception: 6 dispatch UNALIGNED READ Exception: 4 dispatch ``` :::success :raising_hand: Consult the documentation and note which exceptions are 4, 5, 6 and 7. :raising_hand: What does ***unaligned/misaligned*** memory access mean? :raising_hand: Try to find out the program flow for each exceptions and each TRAPs. In which function are the messages ***Exception: N dispatch / Syscall: N dispatch*** printed? ::: ## UART Receive IRQ Handling In this section the work to be done consists of configuring the UART to generate interrupts and handle those interrupts by means of an Interrupt Service Routine (ISR) Add to the already existing file ```riscv_uart.h``` the following content: ```c= // Function prototypes void riscv_uart_enable_RI(); /* Enable UART IRQs */ void riscv_uart_disable_RI(); /* Disable UART IRQs */ // UART CONTROL REGISTER MASKS #define RISCV_UART_RI (TO DEFINE) /* Receiver interrupt enable */ /* UART IRQ */ #define UART_IRQ 3 ``` See the definition of the UART ```Control``` register to assign de right value to ```RISCV_UART_RI``` Add to the already existing file ```riscv_uart.c``` the code of the functions ```riscv_uart_enable_RI``` and ```riscv_uart_disable_RI``` * ```riscv_uart_enable_RI``` must **set** receiver interrupt,```RI``` bit in control register. * ```riscv_uart_disable_RI``` must **clear** receiver interrupt,```RI``` bit in control register ### Installing an IRQ handler See the functions ```install_irq_handler``` and ```uninstall_irq_handler``` in file ```dispatch.h```. They have the following prototypes: ```c= void install_irq_handler( uint32_t irq_num, void (*f)(void) ); void uninstall_irq_handler( uint32_t irq_num ); ``` The first function receives a pointer to a function handler (ISR) and an IRQ number. When the IRQ is raised the ISR is automatically called by the system. The second parameter ```void (*f)(void)``` type means that ISRs are functions that receive NO parameters nor return values. They use global variables to communicate with ```main```. ### Unmasking UART IRQ in PLIC controller See the functions ```plic_irq_mask``` and ```plic_irq_unmask``` in file ```dispatch.h```: ```c= // MASK PLIC external IRQ void plic_irq_mask(uint32_t source); // UNMASK PLIC external IRQ void plic_irq_unmask(uint32_t source); ``` They are used to mask/umask an IRQ in PLIC controller. ### Enable external interrupts See the functions ```enable_ext_irq``` and ```disable_ext_irq``` in file ```dispatch.h```: ```c= // SET MIE REG EXT_IRQ BIT (EXT IRQ enable) void enable_ext_irq(void); // CLEAR MIE REG EXT_IRQ BIT (EXT IRQ disable) void disable_ext_irq(void); ``` They are used to enable/disable all external IRQs. ### Enable global interrupts See the functions ```enable_irq``` and ```disable_irq``` in file ```dispatch.h```: ```c= // SET STATUS REG MIE BIT (Global IRQ enable) void enable_irq(void); // CLEAR STATUS REG MIE BIT (Global IRQ disable) void disable_irq(void); ``` They are used to enable/disable all IRQ handling in the processor. ### Coding IRQ handler and main program Comment the previous main program. In ```main.c``` file and before the ```main``` function add the following handler and variables: ```c= #include "riscv_types.h" #include "riscv_uart.h" #include "dispatch.h" #include "log.h" #define ESC 27 char car; uint32_t flag = 0; uint32_t end = 0; // UART ISR handler // It is going to be called each time a new car is received void uart_rx_irq_handler (void) { car = (char)riscv_getchar(); flag = 1; } ``` Write to ```main``` function the following code: ```c= int main() { // TX/RX enable riscv_uart_enable_TX(); riscv_uart_enable_RX(); // Install uart handler install_irq_handler( UART_IRQ, uart_rx_irq_handler ); riscv_uart_enable_RI(); // Enable RX irq plic_irq_unmask( UART_IRQ ); // PLIC UART irq unmask enable_ext_irq(); // Enable MIE.MEI enable_irq(); // Global interrupt enable riscv_print_string("Programación de Dispositivos e Interfaces\n"); while( !end ) { if ( flag ) { printf("%d: ", car); if ( car == ESC ) // ESC { end = 1; } else { printf("%c\n", car); riscv_putchar(car); flag = 0; } } // else do nothing } printf("Program end\n"); return 0; } ``` :::success :raising_hand: Try to figure out the behaviour of the code and which would be its output before running it. :raising_hand: Pay attention to all IRQ related configuration issues you must take in account in order to handle IRQ properly. ```c= // Install UART handler install_irq_handler( UART_IRQ, uart_rx_irq_handler ); riscv_uart_enable_RI(); // Enable RX irq plic_irq_unmask( UART_IRQ ); // PLIC UART irq unmask enable_ext_irq(); // Enable MIE.MEI enable_irq(); // Global interrupt enable ``` ::: Build P2-B project and correct any typing errors. :::info :information_source: Do not forget to declare all the variables you may need. Also include all the headers files that may be required ::: ### UART receiver IRQ test The test requires an element that transmits characters that will be received by the UART. To do so ```cutecom``` is used. * Build P2-B project and run it typing ```./runP2-B``` in eclipse terminal window. This will connect the simulator to ```cutecom``` terminal. At this point, the example program is waiting for bytes sent to P2-B by ```cutecom```. Send several char sequences and see eclipse terminal messages. ![](https://hackmd.io/_uploads/BJzVKxLJ6.png) ``` atcsol@atcsol:~/eclipse-workspace/P2-B$ ./runP2-B TCP Sockets... Connected to picsimlab-PDI... 104: h 111: o 108: l 97: a 27: Program end atcsol@atcsol:~/eclipse-workspace/P2-B$ ``` :::success :raising_hand: Describe the operation of the program for each character sent from ```cutecom```. ::: ## Student work: Parsing the fields of a Telecommand Header using interrupt driven I/O In practice 2-A, you have coded a program that parses a sequence of 6 bytes belonging to a telecommand primary header. This sequence was received by the UART, using a polling I/O policy. Now, the practice is asked to be recoded using IRQ driven I/O. Write a ```main``` program that runs as follows: 1. Define an ISR (***Interrupt Service Routine***) for UART RX. ISR will run complete for each byte received. 2. The start of TC is always ```0x1B``` since APID must not change. All data received before will be ignored. 3. After ```0x1B``` is read, the following five ```uint8_t``` data must be saved in an array. 4. Using a global variable (***flag***) shared by ```ISR``` and ```main``` program, the ```ISR``` will notify that the TC header is complete. 5. ```main``` is in a loop waiting for the ***flag*** become ***true***. 6. Clear the ***flag*** and decode de packet header and print the values of the following packet fields: * TYPE * PKT SEC HDR FLAG * APID * SEQUENCE FLAGS * PACKET SEQUENCE * PKT DATA LEN 7. Wait for next time the ***flag*** become ***true***. 8. Write sequences corresponding to a different TCs, changing de values of some fields (```SEQUENCE FLAGS```, ```PACKET SEQUENCE```, ```PKT DATA LEN``` ) and test if the decoding procedures runs as expected. 9. Analyze the bahaviour of your program under abnormal circumstances. For example, test what happpens if more than 6 bytes are sent or if two different consecutives TC headers are received. :::info :information_source: Do not forget to declare all the variables you may need. Also include all the headers files that may be required :::