[158] | 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=asm expandtab shiftwidth=4 tabstop=4 softtabstop=4: */ |
---|
| 186 | |
---|