| 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 | |
|---|