1 /***************************************************************************
3 * ZXEmuT -- ZX Spectrum Emulator with Tcl scripting
5 * Copyright (C) 2012-2020 Ketmar Dark <ketmar@ketmar.no-ip.org>
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **************************************************************************/
20 #include "emuevents.h"
28 static KnownEvent
*knownEvTypes
= NULL
;
29 static uint32_t knownEvAlloted
= 0;
30 static uint32_t knownEvUsed
= 0;
32 static EmuEvent
*evList
= NULL
;
33 static uint32_t evListAlloted
= 0;
34 static uint32_t evListUsed
= 0;
36 static EmuEvHandlerCB
*evHandlers
= NULL
;
37 static uint32_t evHandlersAlloted
= 0;
38 static uint32_t evHandlersUsed
= 0;
41 uint32_t emuEvLastFrameCallTS
= 0;
44 //==========================================================================
46 // emuEvRegisterHandler
48 // register new event handler
50 //==========================================================================
51 void emuEvRegisterHandler (EmuEvHandlerCB cb
) {
53 for (uint32_t f
= 0; f
< evHandlersUsed
; ++f
) {
54 if (evHandlers
[f
] == cb
) return;
56 if (evHandlersUsed
== evHandlersAlloted
) {
57 evHandlersAlloted
+= 128;
58 evHandlers
= realloc(evHandlers
, sizeof(EmuEvHandlerCB
)*evHandlersAlloted
);
60 fprintf(stderr
, "FATAL: out of memory for event handlers!\n");
64 evHandlers
[evHandlersUsed
++] = cb
;
69 //==========================================================================
73 // register new event; never returns 0
75 //==========================================================================
76 uint32_t emuEvRegister (const char *name
) {
77 if (!name
|| !name
[0]) {
80 for (uint32_t f
= 0; f
< knownEvUsed
; ++f
) {
81 if (strcmp(knownEvTypes
[f
].name
, name
) == 0) {
82 fprintf(stderr
, "FATAL: duplicate event name '%s'!\n", name
);
88 if (knownEvUsed
== knownEvAlloted
) {
89 knownEvAlloted
+= 1024;
90 knownEvTypes
= realloc(knownEvTypes
, sizeof(KnownEvent
)*knownEvAlloted
);
92 fprintf(stderr
, "FATAL: out of memory for event types!\n");
97 if (!(knownEvTypes
[knownEvUsed
].name
= strdup(name
))) {
98 fprintf(stderr
, "FATAL: out of memory for event types!\n");
102 knownEvTypes
[knownEvUsed
].type
= knownEvUsed
+1;
104 return ++knownEvUsed
;
108 //==========================================================================
112 // get event name by its type
114 //==========================================================================
115 const char *emuEvNameByType (uint32_t type
) {
116 if (type
== 0) return "<null event>";
117 if (type
> knownEvUsed
) return "<invalid event>";
118 return knownEvTypes
[knownEvUsed
-1].name
;
122 //==========================================================================
128 //==========================================================================
129 void emuEvClear (void) {
134 //==========================================================================
136 // emuEvForceTimePassed
138 // called when one frame passed
139 // fixes tstates for all events, drops out unprocessed frame events
141 //==========================================================================
143 void emuEvForceTimePassed (uint32_t tskip) {
146 while (evnext < evListUsed && evList[evnext].tstates < tskip) ++evnext;
147 if (evnext >= evListUsed) {
150 memcpy(&evList[0], &evList[evnext], (evListUsed-evnext)*sizeof(EmuEvent));
151 evListUsed -= evnext;
152 for (uint32_t f = 0; f < evListUsed; ++f) evList[f].tstates -= tskip;
158 //==========================================================================
162 // pass time, call event handlers
163 // it is ok to add new events from handlers
165 //==========================================================================
166 void emuTimePassed (uint32_t tskip
) {
167 while (evListUsed
&& evList
[0].tstates
<= tskip
) {
168 EmuEvent ev
= evList
[0];
170 memcpy(&evList
[0], &evList
[1], evListUsed
*sizeof(EmuEvent
));
171 for (uint32_t f
= 0; f
< evListUsed
; ++f
) {
172 evList
[f
].tstates
-= ev
.tstates
;
176 for (uint32_t f
= 0; f
< evHandlersUsed
; ++f
) evHandlers
[f
](&ev
);
182 //==========================================================================
184 // emuEvRemoveAllWithType
186 // remove all events with the given type
188 //==========================================================================
189 void emuEvRemoveAllWithType (uint32_t type
) {
191 while (ev
< evListUsed
) {
192 if (evList
[ev
].type
== type
) {
193 if (ev
!= evListUsed
-1U) memcpy(&evList
[ev
], &evList
[ev
+1], (evListUsed
-1U)*sizeof(EmuEvent
));
202 //==========================================================================
207 // tstates is tstates from the current event time
209 //==========================================================================
210 void emuEvAdd (uint32_t tstates
, uint32_t type
, void *udata
) {
211 if (evListUsed
== evListAlloted
) {
212 evListAlloted
+= 1024;
213 evList
= realloc(evList
, evListAlloted
*sizeof(EmuEvent
));
215 fprintf(stderr
, "FATAL: out of memory for emulator event queue!\n");
220 // find where we should put our event
223 while (evidx
< evListUsed
&& evList
[evidx
].tstates
<= tstates
) ++evidx
;
224 // insert AFTER evidx
225 if (evidx
!= evListUsed
) {
227 memmove(&evList
[evidx
+1], &evList
[evidx
], (evListUsed
-evidx
-1)*sizeof(EmuEvent
));
232 evList
[evidx
].tstates
= tstates
;
233 evList
[evidx
].type
= type
;
234 evList
[evidx
].udata
= udata
;
238 //==========================================================================
242 // peek next event time; returns `EMU_EV_NONE` if there are no events
244 //==========================================================================
245 uint32_t emuEvNextTime (void) {
246 return (evListUsed
? evList
[0].tstates
: EMU_EV_NONE
);
250 //==========================================================================
255 // returns zero if there are no more event
257 //==========================================================================
258 int emuEvGet (EmuEvent
*ev
) {
259 if (evListUsed
== 0) {
260 if (ev
) memset(ev
, 0, sizeof(EmuEvent
));
264 if (ev
) memcpy(ev
, &evList
[0], sizeof(EmuEvent
));
267 if (evListUsed
!= 0) memcpy(&evList
[0], &evList
[1], sizeof(EmuEvent
)*evListUsed
);