diff options
Diffstat (limited to 'firmware/target/hosted/sdl/kernel-sdl.c')
-rw-r--r-- | firmware/target/hosted/sdl/kernel-sdl.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/firmware/target/hosted/sdl/kernel-sdl.c b/firmware/target/hosted/sdl/kernel-sdl.c new file mode 100644 index 0000000000..d796921e35 --- /dev/null +++ b/firmware/target/hosted/sdl/kernel-sdl.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Felix Arends | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include <stdlib.h> | ||
23 | #include <stdio.h> | ||
24 | #include <SDL.h> | ||
25 | #include <SDL_thread.h> | ||
26 | #include "memory.h" | ||
27 | #include "system-sdl.h" | ||
28 | #include "thread-sdl.h" | ||
29 | #include "kernel.h" | ||
30 | #include "thread.h" | ||
31 | #include "panic.h" | ||
32 | #include "debug.h" | ||
33 | |||
34 | static SDL_TimerID tick_timer_id; | ||
35 | long start_tick; | ||
36 | |||
37 | /* Condition to signal that "interrupts" may proceed */ | ||
38 | static SDL_cond *sim_thread_cond; | ||
39 | /* Mutex to serialize changing levels and exclude other threads while | ||
40 | * inside a handler */ | ||
41 | static SDL_mutex *sim_irq_mtx; | ||
42 | static int interrupt_level = HIGHEST_IRQ_LEVEL; | ||
43 | static int handlers_pending = 0; | ||
44 | static int status_reg = 0; | ||
45 | |||
46 | /* Nescessary logic: | ||
47 | * 1) All threads must pass unblocked | ||
48 | * 2) Current handler must always pass unblocked | ||
49 | * 3) Threads must be excluded when irq routine is running | ||
50 | * 4) No more than one handler routine should execute at a time | ||
51 | */ | ||
52 | int set_irq_level(int level) | ||
53 | { | ||
54 | SDL_LockMutex(sim_irq_mtx); | ||
55 | |||
56 | int oldlevel = interrupt_level; | ||
57 | |||
58 | if (status_reg == 0 && level == 0 && oldlevel != 0) | ||
59 | { | ||
60 | /* Not in a handler and "interrupts" are being reenabled */ | ||
61 | if (handlers_pending > 0) | ||
62 | SDL_CondSignal(sim_thread_cond); | ||
63 | } | ||
64 | |||
65 | interrupt_level = level; /* save new level */ | ||
66 | |||
67 | SDL_UnlockMutex(sim_irq_mtx); | ||
68 | return oldlevel; | ||
69 | } | ||
70 | |||
71 | void sim_enter_irq_handler(void) | ||
72 | { | ||
73 | SDL_LockMutex(sim_irq_mtx); | ||
74 | handlers_pending++; | ||
75 | |||
76 | if(interrupt_level != 0) | ||
77 | { | ||
78 | /* "Interrupts" are disabled. Wait for reenable */ | ||
79 | SDL_CondWait(sim_thread_cond, sim_irq_mtx); | ||
80 | } | ||
81 | |||
82 | status_reg = 1; | ||
83 | } | ||
84 | |||
85 | void sim_exit_irq_handler(void) | ||
86 | { | ||
87 | if (--handlers_pending > 0) | ||
88 | SDL_CondSignal(sim_thread_cond); | ||
89 | |||
90 | status_reg = 0; | ||
91 | SDL_UnlockMutex(sim_irq_mtx); | ||
92 | } | ||
93 | |||
94 | static bool sim_kernel_init(void) | ||
95 | { | ||
96 | sim_irq_mtx = SDL_CreateMutex(); | ||
97 | if (sim_irq_mtx == NULL) | ||
98 | { | ||
99 | panicf("Cannot create sim_handler_mtx\n"); | ||
100 | return false; | ||
101 | } | ||
102 | |||
103 | sim_thread_cond = SDL_CreateCond(); | ||
104 | if (sim_thread_cond == NULL) | ||
105 | { | ||
106 | panicf("Cannot create sim_thread_cond\n"); | ||
107 | return false; | ||
108 | } | ||
109 | |||
110 | return true; | ||
111 | } | ||
112 | |||
113 | void sim_kernel_shutdown(void) | ||
114 | { | ||
115 | SDL_RemoveTimer(tick_timer_id); | ||
116 | SDL_DestroyMutex(sim_irq_mtx); | ||
117 | SDL_DestroyCond(sim_thread_cond); | ||
118 | } | ||
119 | |||
120 | Uint32 tick_timer(Uint32 interval, void *param) | ||
121 | { | ||
122 | long new_tick; | ||
123 | |||
124 | (void) interval; | ||
125 | (void) param; | ||
126 | |||
127 | new_tick = (SDL_GetTicks() - start_tick) / (1000/HZ); | ||
128 | |||
129 | while(new_tick != current_tick) | ||
130 | { | ||
131 | sim_enter_irq_handler(); | ||
132 | |||
133 | /* Run through the list of tick tasks - increments tick | ||
134 | * on each iteration. */ | ||
135 | call_tick_tasks(); | ||
136 | |||
137 | sim_exit_irq_handler(); | ||
138 | } | ||
139 | |||
140 | return 1; | ||
141 | } | ||
142 | |||
143 | void tick_start(unsigned int interval_in_ms) | ||
144 | { | ||
145 | if (!sim_kernel_init()) | ||
146 | { | ||
147 | panicf("Could not initialize kernel!"); | ||
148 | exit(-1); | ||
149 | } | ||
150 | |||
151 | if (tick_timer_id != NULL) | ||
152 | { | ||
153 | SDL_RemoveTimer(tick_timer_id); | ||
154 | tick_timer_id = NULL; | ||
155 | } | ||
156 | else | ||
157 | { | ||
158 | start_tick = SDL_GetTicks(); | ||
159 | } | ||
160 | |||
161 | tick_timer_id = SDL_AddTimer(interval_in_ms, tick_timer, NULL); | ||
162 | } | ||