Rev 2355 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2355 | Rev 2357 | ||
---|---|---|---|
Line 81... | Line 81... | ||
81 | .suspend = gxemul_disable, |
81 | .suspend = gxemul_disable, |
82 | .write = gxemul_write, |
82 | .write = gxemul_write, |
83 | .read = gxemul_do_read, |
83 | .read = gxemul_do_read, |
84 | }; |
84 | }; |
85 | 85 | ||
- | 86 | ||
86 | /** Returns the mask of active interrupts. */ |
87 | /** Returns the mask of active interrupts. */ |
87 | static inline uint32_t gxemul_irqc_get_sources(void) |
88 | static inline uint32_t gxemul_irqc_get_sources(void) |
88 | { |
89 | { |
89 | return *(uint32_t*) gxemul_hw_map.irqc; |
90 | return *(uint32_t*) gxemul_hw_map.irqc; |
90 | } |
91 | } |
91 | 92 | ||
- | 93 | ||
92 | /** Masks interrupt. |
94 | /** Masks interrupt. |
93 | * |
95 | * |
94 | * @param irq interrupt number |
96 | * @param irq interrupt number |
95 | */ |
97 | */ |
96 | static inline void gxemul_irqc_mask(uint32_t irq) |
98 | static inline void gxemul_irqc_mask(uint32_t irq) |
97 | { |
99 | { |
98 | *(uint32_t*) gxemul_hw_map.irqc_mask = irq; |
100 | *(uint32_t*) gxemul_hw_map.irqc_mask = irq; |
99 | } |
101 | } |
100 | 102 | ||
- | 103 | ||
101 | /** Unmasks interrupt. |
104 | /** Unmasks interrupt. |
102 | * |
105 | * |
103 | * @param irq interrupt number |
106 | * @param irq interrupt number |
104 | */ |
107 | */ |
105 | static inline void gxemul_irqc_unmask(uint32_t irq) |
108 | static inline void gxemul_irqc_unmask(uint32_t irq) |
106 | { |
109 | { |
107 | *(uint32_t*) gxemul_hw_map.irqc_unmask = irq; |
110 | *(uint32_t*) gxemul_hw_map.irqc_unmask = irq; |
108 | } |
111 | } |
109 | 112 | ||
- | 113 | ||
110 | /** Initializes #gxemul_hw_map. */ |
114 | /** Initializes #gxemul_hw_map. */ |
111 | void machine_hw_map_init(void) |
115 | void machine_hw_map_init(void) |
112 | { |
116 | { |
113 | gxemul_hw_map.videoram = hw_map(GXEMUL_VIDEORAM, PAGE_SIZE); |
117 | gxemul_hw_map.videoram = hw_map(GXEMUL_VIDEORAM, PAGE_SIZE); |
114 | gxemul_hw_map.kbd = hw_map(GXEMUL_KBD, PAGE_SIZE); |
118 | gxemul_hw_map.kbd = hw_map(GXEMUL_KBD, PAGE_SIZE); |
115 | gxemul_hw_map.rtc = hw_map(GXEMUL_RTC, PAGE_SIZE); |
119 | gxemul_hw_map.rtc = hw_map(GXEMUL_RTC, PAGE_SIZE); |
116 | gxemul_hw_map.irqc = hw_map(GXEMUL_IRQC, PAGE_SIZE); |
120 | gxemul_hw_map.irqc = hw_map(GXEMUL_IRQC, PAGE_SIZE); |
- | 121 | gxemul_hw_map.fb = hw_map(GXEMUL_FB, PAGE_SIZE); |
|
117 | 122 | ||
118 | gxemul_hw_map.rtc_freq = gxemul_hw_map.rtc + GXEMUL_RTC_FREQ_OFFSET; |
123 | gxemul_hw_map.rtc_freq = gxemul_hw_map.rtc + GXEMUL_RTC_FREQ_OFFSET; |
119 | gxemul_hw_map.rtc_ack = gxemul_hw_map.rtc + GXEMUL_RTC_ACK_OFFSET; |
124 | gxemul_hw_map.rtc_ack = gxemul_hw_map.rtc + GXEMUL_RTC_ACK_OFFSET; |
120 | gxemul_hw_map.irqc_mask = gxemul_hw_map.irqc + GXEMUL_IRQC_MASK_OFFSET; |
125 | gxemul_hw_map.irqc_mask = gxemul_hw_map.irqc + GXEMUL_IRQC_MASK_OFFSET; |
121 | gxemul_hw_map.irqc_unmask = gxemul_hw_map.irqc + GXEMUL_IRQC_UNMASK_OFFSET; |
126 | gxemul_hw_map.irqc_unmask = gxemul_hw_map.irqc + GXEMUL_IRQC_UNMASK_OFFSET; |
122 | 127 | ||
123 | hw_map_init_called = true; |
128 | hw_map_init_called = true; |
124 | } |
129 | } |
125 | 130 | ||
- | 131 | ||
126 | /** Putchar that works with gxemul */ |
132 | /** Putchar that works with gxemul */ |
127 | static void gxemul_write(chardev_t *dev, const char ch) |
133 | static void gxemul_write(chardev_t *dev, const char ch) |
128 | { |
134 | { |
129 | *((char *) gxemul_hw_map.videoram) = ch; |
135 | *((char *) gxemul_hw_map.videoram) = ch; |
130 | } |
136 | } |
131 | 137 | ||
- | 138 | ||
132 | /* Called from getc(). */ |
139 | /* Called from getc(). */ |
133 | static void gxemul_enable(chardev_t *dev) |
140 | static void gxemul_enable(chardev_t *dev) |
134 | { |
141 | { |
135 | gxemul_irqc_unmask(GXEMUL_KBD_IRQ); |
142 | gxemul_irqc_unmask(GXEMUL_KBD_IRQ); |
136 | } |
143 | } |
137 | 144 | ||
- | 145 | ||
138 | /* Called from getc(). */ |
146 | /* Called from getc(). */ |
139 | static void gxemul_disable(chardev_t *dev) |
147 | static void gxemul_disable(chardev_t *dev) |
140 | { |
148 | { |
141 | gxemul_irqc_mask(GXEMUL_KBD_IRQ); |
149 | gxemul_irqc_mask(GXEMUL_KBD_IRQ); |
142 | } |
150 | } |
143 | 151 | ||
- | 152 | ||
144 | /** Read character using polling, assume interrupts disabled */ |
153 | /** Read character using polling, assume interrupts disabled. |
- | 154 | * |
|
- | 155 | * @param dev Not used. |
|
- | 156 | */ |
|
145 | static char gxemul_do_read(chardev_t *dev) |
157 | static char gxemul_do_read(chardev_t *dev) |
146 | { |
158 | { |
147 | char ch; |
159 | char ch; |
148 | 160 | ||
149 | while (1) { |
161 | while (1) { |
Line 156... | Line 168... | ||
156 | return ch; |
168 | return ch; |
157 | } |
169 | } |
158 | } |
170 | } |
159 | } |
171 | } |
160 | 172 | ||
- | 173 | ||
161 | /** Process keyboard interrupt. */ |
174 | /** Process keyboard interrupt. */ |
162 | static void gxemul_irq_handler(irq_t *irq, void *arg, ...) |
175 | static void gxemul_irq_handler(irq_t *irq, void *arg, ...) |
163 | { |
176 | { |
164 | if ((irq->notif_cfg.notify) && (irq->notif_cfg.answerbox)) |
177 | if ((irq->notif_cfg.notify) && (irq->notif_cfg.answerbox)) { |
165 | ipc_irq_send_notif(irq); |
178 | ipc_irq_send_notif(irq); |
166 | else { |
179 | } else { |
167 | char ch = 0; |
180 | char ch = 0; |
168 | 181 | ||
169 | ch = *((char *) gxemul_hw_map.kbd); |
182 | ch = *((char *) gxemul_hw_map.kbd); |
170 | if (ch =='\r') |
183 | if (ch == '\r') { |
171 | ch = '\n'; |
184 | ch = '\n'; |
- | 185 | } |
|
172 | if (ch == 0x7f) |
186 | if (ch == 0x7f) { |
173 | ch = '\b'; |
187 | ch = '\b'; |
- | 188 | } |
|
174 | chardev_push_character(&console, ch); |
189 | chardev_push_character(&console, ch); |
175 | } |
190 | } |
176 | } |
191 | } |
177 | 192 | ||
- | 193 | ||
178 | static irq_ownership_t gxemul_claim(void) |
194 | static irq_ownership_t gxemul_claim(void) |
179 | { |
195 | { |
180 | return IRQ_ACCEPT; |
196 | return IRQ_ACCEPT; |
181 | } |
197 | } |
182 | 198 | ||
- | 199 | ||
183 | void machine_grab_console(void) |
200 | void machine_grab_console(void) |
184 | { |
201 | { |
185 | ipl_t ipl = interrupts_disable(); |
202 | ipl_t ipl = interrupts_disable(); |
186 | spinlock_lock(&gxemul_irq.lock); |
203 | spinlock_lock(&gxemul_irq.lock); |
187 | gxemul_irq.notif_cfg.notify = false; |
204 | gxemul_irq.notif_cfg.notify = false; |
188 | spinlock_unlock(&gxemul_irq.lock); |
205 | spinlock_unlock(&gxemul_irq.lock); |
189 | interrupts_restore(ipl); |
206 | interrupts_restore(ipl); |
190 | } |
207 | } |
191 | 208 | ||
- | 209 | ||
192 | void machine_release_console(void) |
210 | void machine_release_console(void) |
193 | { |
211 | { |
194 | ipl_t ipl = interrupts_disable(); |
212 | ipl_t ipl = interrupts_disable(); |
195 | spinlock_lock(&gxemul_irq.lock); |
213 | spinlock_lock(&gxemul_irq.lock); |
196 | if (gxemul_irq.notif_cfg.answerbox) |
214 | if (gxemul_irq.notif_cfg.answerbox) { |
197 | gxemul_irq.notif_cfg.notify = true; |
215 | gxemul_irq.notif_cfg.notify = true; |
- | 216 | } |
|
198 | spinlock_unlock(&gxemul_irq.lock); |
217 | spinlock_unlock(&gxemul_irq.lock); |
199 | interrupts_restore(ipl); |
218 | interrupts_restore(ipl); |
200 | } |
219 | } |
201 | 220 | ||
202 | 221 | ||
203 | /** Return console object representing gxemul console */ |
222 | /** Initializes console object representing gxemul console. |
- | 223 | * |
|
- | 224 | * @param Console device number. |
|
- | 225 | */ |
|
204 | void machine_console_init(devno_t devno) |
226 | void machine_console_init(devno_t devno) |
205 | { |
227 | { |
206 | chardev_initialize("gxemul_console", &console, &gxemul_ops); |
228 | chardev_initialize("gxemul_console", &console, &gxemul_ops); |
207 | stdin = &console; |
229 | stdin = &console; |
208 | stdout = &console; |
230 | stdout = &console; |
Line 224... | Line 246... | ||
224 | 246 | ||
225 | 247 | ||
226 | 248 | ||
227 | /** Starts gxemul Real Time Clock device, which asserts regular interrupts. |
249 | /** Starts gxemul Real Time Clock device, which asserts regular interrupts. |
228 | * |
250 | * |
229 | * @param frequency interrupts frequency (0 disables RTC) |
251 | * @param frequency Interrupts frequency (0 disables RTC). |
230 | */ |
252 | */ |
231 | static void gxemul_timer_start(uint32_t frequency) |
253 | static void gxemul_timer_start(uint32_t frequency) |
232 | { |
254 | { |
233 | *(uint32_t*) gxemul_hw_map.rtc_freq = frequency; |
255 | *(uint32_t*) gxemul_hw_map.rtc_freq = frequency; |
234 | } |
256 | } |
235 | 257 | ||
- | 258 | ||
236 | static irq_ownership_t gxemul_timer_claim(void) |
259 | static irq_ownership_t gxemul_timer_claim(void) |
237 | { |
260 | { |
238 | return IRQ_ACCEPT; |
261 | return IRQ_ACCEPT; |
239 | } |
262 | } |
240 | 263 | ||
- | 264 | ||
241 | /** Timer interrupt handler. |
265 | /** Timer interrupt handler. |
242 | * |
266 | * |
243 | * @param irq interrupt information |
267 | * @param irq Interrupt information. |
- | 268 | * @param arg Not used. |
|
244 | */ |
269 | */ |
245 | static void gxemul_timer_irq_handler(irq_t *irq, void *arg, ...) |
270 | static void gxemul_timer_irq_handler(irq_t *irq, void *arg, ...) |
246 | { |
271 | { |
247 | /* TODO time drifts ?? |
272 | /* TODO time drifts ?? |
248 | unsigned long drift; |
273 | unsigned long drift; |
Line 271... | Line 296... | ||
271 | if (virtual_timer_fnc != NULL) |
296 | if (virtual_timer_fnc != NULL) |
272 | virtual_timer_fnc(); |
297 | virtual_timer_fnc(); |
273 | */ |
298 | */ |
274 | } |
299 | } |
275 | 300 | ||
- | 301 | ||
276 | /** Initializes and registers timer interrupt handler. |
302 | /** Initializes and registers timer interrupt handler. */ |
277 | */ |
- | |
278 | static void gxemul_timer_irq_init() |
303 | static void gxemul_timer_irq_init() |
279 | { |
304 | { |
280 | irq_initialize(&gxemul_timer_irq); |
305 | irq_initialize(&gxemul_timer_irq); |
281 | gxemul_timer_irq.devno = device_assign_devno(); |
306 | gxemul_timer_irq.devno = device_assign_devno(); |
282 | gxemul_timer_irq.inr = GXEMUL_TIMER_IRQ; |
307 | gxemul_timer_irq.inr = GXEMUL_TIMER_IRQ; |
Line 284... | Line 309... | ||
284 | gxemul_timer_irq.handler = gxemul_timer_irq_handler; |
309 | gxemul_timer_irq.handler = gxemul_timer_irq_handler; |
285 | 310 | ||
286 | irq_register(&gxemul_timer_irq); |
311 | irq_register(&gxemul_timer_irq); |
287 | } |
312 | } |
288 | 313 | ||
- | 314 | ||
289 | /** Starts timer. |
315 | /** Starts timer. |
290 | * |
316 | * |
291 | * Initiates regular timer interrupts after initializing |
317 | * Initiates regular timer interrupts after initializing |
292 | * corresponding interrupt handler. |
318 | * corresponding interrupt handler. |
293 | */ |
319 | */ |
Line 295... | Line 321... | ||
295 | { |
321 | { |
296 | gxemul_timer_irq_init(); |
322 | gxemul_timer_irq_init(); |
297 | gxemul_timer_start(GXEMUL_TIMER_FREQ); |
323 | gxemul_timer_start(GXEMUL_TIMER_FREQ); |
298 | } |
324 | } |
299 | 325 | ||
- | 326 | ||
300 | /** Returns the size of emulated memory. |
327 | /** Returns the size of emulated memory. |
301 | * |
328 | * |
302 | * @return size in bytes |
329 | * @return Size in bytes. |
303 | */ |
330 | */ |
304 | size_t machine_get_memory_size(void) |
331 | size_t machine_get_memory_size(void) |
305 | { |
332 | { |
306 | return *((int*)(GXEMUL_MP + GXEMUL_MP_MEMSIZE_OFFSET)); |
333 | return *((int*)(GXEMUL_MP + GXEMUL_MP_MEMSIZE_OFFSET)); |
307 | } |
334 | } |
308 | 335 | ||
- | 336 | ||
309 | void machine_debug_putc(char ch) |
337 | void machine_debug_putc(char ch) |
310 | { |
338 | { |
311 | char * addr = 0; |
339 | char * addr = 0; |
312 | if (!hw_map_init_called) { |
340 | if (!hw_map_init_called) { |
313 | addr = (char *) GXEMUL_KBD; |
341 | addr = (char *) GXEMUL_KBD; |
Line 316... | Line 344... | ||
316 | } |
344 | } |
317 | 345 | ||
318 | *(addr) = ch; |
346 | *(addr) = ch; |
319 | } |
347 | } |
320 | 348 | ||
- | 349 | ||
321 | /** Stops gxemul. */ |
350 | /** Stops gxemul. */ |
322 | void machine_cpu_halt(void) |
351 | void machine_cpu_halt(void) |
323 | { |
352 | { |
324 | char * addr = 0; |
353 | char * addr = 0; |
325 | if (!hw_map_init_called) { |
354 | if (!hw_map_init_called) { |
Line 329... | Line 358... | ||
329 | } |
358 | } |
330 | 359 | ||
331 | *(addr + GXEMUL_HALT_OFFSET) = '\0'; |
360 | *(addr + GXEMUL_HALT_OFFSET) = '\0'; |
332 | } |
361 | } |
333 | 362 | ||
- | 363 | ||
334 | /** Gxemul specific interrupt exception handler. |
364 | /** Gxemul specific interrupt exception handler. |
335 | * |
365 | * |
336 | * Determines sources of the interrupt from interrupt controller and |
366 | * Determines sources of the interrupt from interrupt controller and |
337 | * calls high-level handlers for them. |
367 | * calls high-level handlers for them. |
338 | * |
368 | * |
339 | * @param exc_no interrupt exception number |
369 | * @param exc_no Interrupt exception number. |
340 | * @param istate saved processor state |
370 | * @param istate Saved processor state. |
341 | */ |
371 | */ |
342 | void machine_irq_exception(int exc_no, istate_t *istate) |
372 | void machine_irq_exception(int exc_no, istate_t *istate) |
343 | { |
373 | { |
344 | uint32_t sources = gxemul_irqc_get_sources(); |
374 | uint32_t sources = gxemul_irqc_get_sources(); |
345 | int i = 0; |
375 | int i = 0; |
Line 357... | Line 387... | ||
357 | } |
387 | } |
358 | } |
388 | } |
359 | } |
389 | } |
360 | 390 | ||
361 | 391 | ||
- | 392 | uintptr_t machine_get_fb_address(void) |
|
- | 393 | { |
|
- | 394 | return gxemul_hw_map.fb; |
|
- | 395 | } |
|
- | 396 | ||
362 | /** @} |
397 | /** @} |
363 | */ |
398 | */ |