| 1 | /************************************************************************************* | 
|---|
| 2 | File : isr.c | 
|---|
| 3 | Authors : Alain Greiner | 
|---|
| 4 | Date : april 2011 | 
|---|
| 5 |  | 
|---|
| 6 | These routines must be "intalled" by the boot code in the | 
|---|
| 7 | interrupt vector, depending on the system architecture. | 
|---|
| 8 | *************************************************************************************/ | 
|---|
| 9 |  | 
|---|
| 10 | #include "isr.h" | 
|---|
| 11 | #include "drivers.h" | 
|---|
| 12 |  | 
|---|
| 13 | #define in_isr __attribute__((section (".isr"))) | 
|---|
| 14 |  | 
|---|
| 15 | struct plaf; | 
|---|
| 16 |  | 
|---|
| 17 | extern struct plaf seg_dma_base; | 
|---|
| 18 | extern struct plaf seg_ioc_base; | 
|---|
| 19 | extern struct plaf seg_timer_base; | 
|---|
| 20 | extern struct plaf seg_tty_base; | 
|---|
| 21 |  | 
|---|
| 22 | extern struct plaf NB_TIMERS; | 
|---|
| 23 | extern struct plaf NB_TASKS; | 
|---|
| 24 |  | 
|---|
| 25 | ////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 26 | //  _isr_dma | 
|---|
| 27 | //  Each processor controls its own private DMA. | 
|---|
| 28 | //  It acknowledge the IRQ using the dma base address depending on the proc_id | 
|---|
| 29 | //  as computed by the  _segment_increment() function, writes the transfer | 
|---|
| 30 | //  status in the _dma_status[pid] variable, and resets the _dma_busy[pid] | 
|---|
| 31 | //  synchrnisation variable to signal completion. | 
|---|
| 32 | //  Both variables are defined in the drivers.c file. | 
|---|
| 33 | ///////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 34 | in_isr void _isr_dma() | 
|---|
| 35 | { | 
|---|
| 36 | int*                dma_address; | 
|---|
| 37 | unsigned int        base            = (unsigned int)&seg_dma_base; | 
|---|
| 38 | unsigned int        increment       = _segment_increment(DMA_SPAN*4); | 
|---|
| 39 | size_t              pid             = _procid(); | 
|---|
| 40 |  | 
|---|
| 41 | dma_address = (int*)(base + increment); | 
|---|
| 42 |  | 
|---|
| 43 | _dma_status[pid]            = dma_address[DMA_LEN]; // save status | 
|---|
| 44 | _dma_busy[pid]              = 0;                    // release DMA | 
|---|
| 45 | dma_address[DMA_RESET]      = 0;                    // reset IRQ | 
|---|
| 46 | } | 
|---|
| 47 | ////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 48 | //  _isr_ioc | 
|---|
| 49 | //  There is only one IOC controler shared by all tasks. | 
|---|
| 50 | //  It acknowledge the IRQ using the ioc base address, save the status, | 
|---|
| 51 | //  and set the _ioc_done variable to signal completion. | 
|---|
| 52 | //  This variable is defined in the drivers.c file. | 
|---|
| 53 | ////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 54 | in_isr void _isr_ioc() | 
|---|
| 55 | { | 
|---|
| 56 | int* ioc_address = (int*)&seg_ioc_base; | 
|---|
| 57 |  | 
|---|
| 58 | _ioc_status = ioc_address[BLOCK_DEVICE_STATUS];     // save status & reset IRQ | 
|---|
| 59 | _ioc_done   = 1;                                    // signals completion | 
|---|
| 60 | } | 
|---|
| 61 | ////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 62 | //  _isr_timer* (* = 0,1,2,3) | 
|---|
| 63 | //  A single processor can use up to 4 independant timers. | 
|---|
| 64 | //  These 4 ISRs handle up to 4 IRQs generated by 4 independant timers, | 
|---|
| 65 | //  connected to a single processor. | 
|---|
| 66 | //  It acknowledge the IRQ using the timer base address depending | 
|---|
| 67 | //  on both the proc_id and the timer_id (0,1,2,3). | 
|---|
| 68 | //  It displays a message on TTY[proc_id,task_id]. | 
|---|
| 69 | ////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 70 | in_isr void _isr_timer_indexed(size_t timer_id) | 
|---|
| 71 | { | 
|---|
| 72 | int*                timer_address; | 
|---|
| 73 | size_t              ntimers         = (size_t)&NB_TIMERS; | 
|---|
| 74 | unsigned int        base            = (unsigned int)&seg_timer_base; | 
|---|
| 75 | unsigned int        increment       = _segment_increment(ntimers*TIMER_SPAN*4); | 
|---|
| 76 | int                 date            = (int)_proctime(); | 
|---|
| 77 | char                buf[10]; | 
|---|
| 78 |  | 
|---|
| 79 | timer_address = (int*)(base + increment + timer_id*TIMER_SPAN*4); | 
|---|
| 80 |  | 
|---|
| 81 | timer_address[TIMER_RESETIRQ] = 0;                  // reset IRQ | 
|---|
| 82 |  | 
|---|
| 83 | _itoa_dec(date, buf);                               // print message | 
|---|
| 84 | _tty_write("\n!!! interrupt timer0 received at cycle ", 40); | 
|---|
| 85 | _tty_write(buf, 10); | 
|---|
| 86 | _tty_write("\n\n", 2); | 
|---|
| 87 | } | 
|---|
| 88 | in_isr void _isr_timer() | 
|---|
| 89 | { | 
|---|
| 90 | _isr_timer_indexed(0); | 
|---|
| 91 | } | 
|---|
| 92 | in_isr void _isr_timer0() | 
|---|
| 93 | { | 
|---|
| 94 | _isr_timer_indexed(0); | 
|---|
| 95 | } | 
|---|
| 96 | in_isr void _isr_timer1() | 
|---|
| 97 | { | 
|---|
| 98 | _isr_timer_indexed(1); | 
|---|
| 99 | } | 
|---|
| 100 | in_isr void _isr_timer2() | 
|---|
| 101 | { | 
|---|
| 102 | _isr_timer_indexed(2); | 
|---|
| 103 | } | 
|---|
| 104 | in_isr void _isr_timer3() | 
|---|
| 105 | { | 
|---|
| 106 | _isr_timer_indexed(3); | 
|---|
| 107 | } | 
|---|
| 108 | ////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 109 | //  _isr_tty_get_task* (* = 0,1,2,3) | 
|---|
| 110 | //  A single processor can run up to 4 tasks in pseudo-parallelismr, | 
|---|
| 111 | //  and each task has is own private terminal. | 
|---|
| 112 | //  These 4 ISRs handle up to 4 IRQs associate to 4 independant terminals | 
|---|
| 113 | //  connected to a single processor. | 
|---|
| 114 | //  It acknowledge the IRQ using the terminal basee address depending | 
|---|
| 115 | //  on both the proc_id  and the task_id (0,1,2,3). | 
|---|
| 116 | //  There is one communication buffer _tty_get_buf[tty_id] per terminal. | 
|---|
| 117 | //  protected by a set/reset variable _tty_get_full[tty_id]. | 
|---|
| 118 | //  The _tty_get_full[tty_id] synchronisation variable is set | 
|---|
| 119 | //  by the ISR, and reset by the OS. | 
|---|
| 120 | //  Both variables are defined in the drivers.c file. | 
|---|
| 121 | //  To access these buffers, the terminal index is computed as | 
|---|
| 122 | //      tty_id = proc_id*ntasks + task_id | 
|---|
| 123 | //  A character is lost if the buffer is full when the ISR is executed. | 
|---|
| 124 | ////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 125 | in_isr void _isr_tty_get_indexed(size_t task_id) | 
|---|
| 126 | { | 
|---|
| 127 | char*               tty_address; | 
|---|
| 128 | size_t              ntasks          = (size_t)&NB_TASKS; | 
|---|
| 129 | size_t              tty_id          = _procid()*ntasks + task_id; | 
|---|
| 130 | unsigned int        base            = (unsigned int)&seg_tty_base; | 
|---|
| 131 | unsigned int        increment       = _segment_increment(ntasks*TTY_SPAN*4); | 
|---|
| 132 |  | 
|---|
| 133 | tty_address = (char*)(base + increment + task_id*TTY_SPAN*4); | 
|---|
| 134 |  | 
|---|
| 135 | _tty_get_buf[tty_id] = tty_address[TTY_READ*4];     // save character and reset IRQ | 
|---|
| 136 | _tty_get_full[tty_id] = 1;                          // signals character available | 
|---|
| 137 | } | 
|---|
| 138 | in_isr void _isr_tty_get() | 
|---|
| 139 | { | 
|---|
| 140 | _isr_tty_get_indexed(0); | 
|---|
| 141 | } | 
|---|
| 142 | in_isr void _isr_tty_get_task0() | 
|---|
| 143 | { | 
|---|
| 144 | _isr_tty_get_indexed(0); | 
|---|
| 145 | } | 
|---|
| 146 | in_isr void _isr_tty_get_task1() | 
|---|
| 147 | { | 
|---|
| 148 | _isr_tty_get_indexed(1); | 
|---|
| 149 | } | 
|---|
| 150 | in_isr void _isr_tty_get_task2() | 
|---|
| 151 | { | 
|---|
| 152 | _isr_tty_get_indexed(2); | 
|---|
| 153 | } | 
|---|
| 154 | in_isr void _isr_tty_get_task3() | 
|---|
| 155 | { | 
|---|
| 156 | _isr_tty_get_indexed(3); | 
|---|
| 157 | } | 
|---|
| 158 | ////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 159 | //  _isr_switch | 
|---|
| 160 | //  This ISR is in charge of context switch. | 
|---|
| 161 | //  It handles up to 4 IRQs, corresponding to 4 different processors. | 
|---|
| 162 | //  If the processor uses several timers, the context switch is driven | 
|---|
| 163 | //  by the IRQ associated to timer0. | 
|---|
| 164 | //  It acknowledges the IRQ on TIMER[proc_id] and calls the _ctx_switch() function. | 
|---|
| 165 | ////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 166 | in_isr void _isr_switch() | 
|---|
| 167 | { | 
|---|
| 168 | int*                timer_address; | 
|---|
| 169 | unsigned int        base            = (unsigned int)&seg_timer_base; | 
|---|
| 170 | unsigned int        increment       = _segment_increment(TIMER_SPAN*4); | 
|---|
| 171 |  | 
|---|
| 172 | timer_address = (int*)(base + increment); | 
|---|
| 173 |  | 
|---|
| 174 | timer_address[TIMER_RESETIRQ] = 0;                  // reset IRQ | 
|---|
| 175 | _ctx_switch(); | 
|---|
| 176 | } | 
|---|
| 177 |  | 
|---|
| 178 | /* Local Variables: | 
|---|
| 179 | tab-width: 4; | 
|---|
| 180 | c-basic-offset: 4; | 
|---|
| 181 | c-file-offsets:((innamespace . 0)(inline-open . 0)); | 
|---|
| 182 | indent-tabs-mode: nil; | 
|---|
| 183 | End: */ | 
|---|
| 184 |  | 
|---|
| 185 | /* vim: set filetype=c expandtab shiftwidth=4 tabstop=4 softtabstop=4: */ | 
|---|
| 186 |  | 
|---|