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