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