OSDN Git Service

[VM] Add vm_template.h . This class, VM_TEMPLATE:: must be mother of VM:: .See fm7...
[csp-qt/common_source_project-fm7.git] / source / src / vm / event.h
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2006.11.29-
6
7         [ event manager ]
8 */
9
10 #ifndef _EVENT_H_
11 #define _EVENT_H_
12
13 #include "vm.h"
14 #include "../emu.h"
15 #include "device.h"
16
17 #include <typeinfo>
18
19 #define MAX_DEVICE      64
20 #define MAX_CPU         8
21 #define MAX_SOUND       32
22 #define MAX_LINES       1024
23 #define MAX_EVENT       64
24 #define NO_EVENT        -1
25
26 enum {
27         EVENT_CPUTYPE_GENERIC = 0,
28         EVENT_CPUTYPE_HD6301,
29         EVENT_CPUTYPE_HUC6280,
30         EVENT_CPUTYPE_I286,
31         EVENT_CPUTYPE_I386,
32         EVENT_CPUTYPE_I8080,
33         EVENT_CPUTYPE_M6502,
34         EVENT_CPUTYPE_N2A03,
35         EVENT_CPUTYPE_MB8861,
36         EVENT_CPUTYPE_MC6800,
37         EVENT_CPUTYPE_MC6801,
38         EVENT_CPUTYPE_MC6809,
39         EVENT_CPUTYPE_MCS48,
40         EVENT_CPUTYPE_TMS9995,
41         EVENT_CPUTYPE_UPD7801,
42         EVENT_CPUTYPE_Z80
43 };
44 class EVENT : public DEVICE
45 {
46 private:
47         // event manager
48         typedef struct {
49                 DEVICE* device;
50                 uint32_t cpu_clocks;
51                 uint32_t update_clocks;
52                 uint32_t accum_clocks;
53         } cpu_t;
54         cpu_t d_cpu[MAX_CPU];
55
56         uint32_t cpu_update_clocks[MAX_CPU][6];
57         uint32_t cpu_type[MAX_CPU];
58         
59         int dcount_cpu;
60         
61         int vclocks[MAX_LINES];
62         int power;
63         int event_remain;
64         int cpu_remain, cpu_accum, cpu_done;
65         uint64_t event_clocks;
66         
67         typedef struct event_t {
68                 DEVICE* device;
69                 int event_id;
70                 uint64_t expired_clock;
71                 uint64_t loop_clock;
72                 uint64_t accum_clocks;
73                 bool active;
74                 int index;
75                 event_t *next;
76                 event_t *prev;
77         } event_t;
78         event_t event[MAX_EVENT];
79         event_t *first_free_event;
80         event_t *first_fire_event;
81         // For State
82         DEVICE* frame_event[MAX_EVENT];
83         DEVICE* vline_event[MAX_EVENT];
84         int frame_event_count, vline_event_count;
85         
86         double frames_per_sec, next_frames_per_sec;
87         int lines_per_frame, next_lines_per_frame;
88         uint32_t vline_start_clock;
89         int cur_vline;
90         
91         void update_event(int clock);
92         void insert_event(event_t *event_handle);
93         
94         // sound manager
95         DEVICE* d_sound[MAX_SOUND];
96         int dcount_sound;
97         
98         uint16_t* sound_buffer;
99         int32_t* sound_tmp;
100         int buffer_ptr;
101         int sound_samples;
102         int sound_tmp_samples;
103         
104         int dont_skip_frames;
105         bool prev_skip, next_skip;
106         bool sound_changed;
107         
108         int mix_counter;
109         int mix_limit;
110         bool dev_need_mix[MAX_DEVICE];
111         int need_mix;
112         
113         void mix_sound(int samples);
114         void* get_event(int index);
115         int run_cpu(uint32_t num, int cycles);
116
117 #ifdef _DEBUG_LOG
118         bool initialize_done;
119 #endif
120         template <class T>
121                 void set_cpu_type(T *p, int num)
122         {
123                 if((num < 0) || (num >= MAX_CPU)) return;
124 #if defined(USE_CPU_HD6301)
125                 if(typeid(T) == typeid(HD6301)) {
126                         cpu_type[num] = EVENT_CPUTYPE_HD6301;
127                 } else
128 #endif
129 #if defined(USE_CPU_HUC6280)
130                 if(typeid(T) == typeid(HUC6280)) {
131                         cpu_type[num] = EVENT_CPUTYPE_HUC6280;
132                 } else
133 #endif
134 #if defined(USE_CPU_I86) || defined(USE_CPU_I286) || defined(USE_CPU_I186) || defined(USE_CPU_V30)
135                 if(typeid(T) == typeid(I286)) {
136                         cpu_type[num] = EVENT_CPUTYPE_I286;
137                 } else
138 #endif
139 #if defined(USE_CPU_I386) || defined(USE_CPU_I486) || defined(USE_CPU_PENTIUM)
140                 if(typeid(T) == typeid(I386)) {
141                         cpu_type[num] = EVENT_CPUTYPE_I386;
142                 } else
143 #endif
144 #if defined(USE_CPU_I8080)
145                 if(typeid(T) == typeid(I8080)) {
146                         cpu_type[num] = EVENT_CPUTYPE_I8080;
147                 } else
148 #endif
149 #if defined(USE_CPU_M6502)
150                 if(typeid(T) == typeid(M6502)) {
151                         cpu_type[num] = EVENT_CPUTYPE_M6502;
152                 } else
153 #endif
154 #if defined(USE_CPU_N2A03)
155                 if(typeid(T) == typeid(N2A03)) {
156                         cpu_type[num] = EVENT_CPUTYPE_N2A03;
157                 } else
158 #endif
159 #if defined(USE_CPU_MB8861)
160                 if(typeid(T) == typeid(MB8861)) {
161                         cpu_type[num] = EVENT_CPUTYPE_MB8861;
162                 } else
163 #endif
164 #if defined(USE_CPU_MC6800)
165                 if(typeid(T) == typeid(MC6800)) {
166                         cpu_type[num] = EVENT_CPUTYPE_MC6800;
167                 } else
168 #endif
169 #if defined(USE_CPU_MC6801)
170                 if(typeid(T) == typeid(MC6801)) {
171                         cpu_type[num] = EVENT_CPUTYPE_MC6801;
172                 } else
173 #endif
174 #if defined(USE_CPU_MC6809)
175                 if(typeid(T) == typeid(MC6809)) {
176                         cpu_type[num] = EVENT_CPUTYPE_MC6809;
177                 } else
178 #endif
179 #if defined(USE_CPU_MCS48)
180                 if(typeid(T) == typeid(MCS48)) {
181                         cpu_type[num] = EVENT_CPUTYPE_MCS48;
182                 } else
183 #endif
184 #if defined(USE_CPU_TMS9995)
185                 if(typeid(T) == typeid(TMS9995)) {
186                         cpu_type[num] = EVENT_CPUTYPE_TMS9995;
187                 } else
188 #endif
189 #if defined(USE_CPU_UPD7801)
190                 if(typeid(T) == typeid(UPD7801)) {
191                         cpu_type[num] = EVENT_CPUTYPE_UPD7801;
192                 } else
193 #endif
194 #if defined(USE_CPU_Z80)
195                 if(typeid(T) == typeid(Z80)) {
196                         cpu_type[num] = EVENT_CPUTYPE_Z80;
197                 } else
198 #endif
199                 {
200                         cpu_type[num] = EVENT_CPUTYPE_GENERIC;
201                 }
202         }
203 public:
204         EVENT(VM_TEMPLATE* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
205         {
206                 dcount_cpu = dcount_sound = 0;
207                 frame_event_count = vline_event_count = 0;
208                 
209                 // initialize event
210                 memset(event, 0, sizeof(event));
211                 for(int i = 0; i < MAX_EVENT; i++) {
212                         event[i].active = false;
213                         event[i].index = i;
214                         event[i].next = (i + 1 < MAX_EVENT) ? &event[i + 1] : NULL;
215                 }
216                 first_free_event = &event[0];
217                 first_fire_event = NULL;
218                 
219                 event_clocks = 0;
220                 
221                 // force update timing in the first frame
222                 frames_per_sec = 0.0;
223                 lines_per_frame = 0;
224                 next_frames_per_sec = FRAMES_PER_SEC;
225                 next_lines_per_frame = LINES_PER_FRAME;
226                 // reset before other device may call set_realtime_render()
227                 memset(dev_need_mix, 0, sizeof(dev_need_mix));
228                 need_mix = 0;
229                 
230 #ifdef _DEBUG_LOG
231                 initialize_done = false;
232 #endif
233                 for(int i = 0; i < MAX_CPU; i++) {
234                         cpu_type[i] = EVENT_CPUTYPE_GENERIC;
235                 }
236                 set_device_name(_T("Event Manager"));
237         }
238         ~EVENT() {}
239         
240         // common functions
241         void initialize();
242         void release();
243         void reset();
244         void event_callback(int event_id, int err);
245         void update_config();
246         void decl_state();
247         void save_state(FILEIO* state_fio);
248         bool load_state(FILEIO* state_fio);
249         
250         // common event functions
251         int get_event_manager_id()
252         {
253                 return this_device_id;
254         }
255         void set_frames_per_sec(double new_frames_per_sec)
256         {
257                 next_frames_per_sec = new_frames_per_sec;
258         }
259         void set_lines_per_frame(int new_lines_per_frame)
260         {
261                 if(new_lines_per_frame < MAX_LINES) {
262                         next_lines_per_frame = new_lines_per_frame;
263                 }
264         }
265         int get_lines_per_frame()
266         {
267                 return next_lines_per_frame;
268         }
269         void register_event(DEVICE* device, int event_id, double usec, bool loop, int* register_id);
270         void register_event_by_clock(DEVICE* device, int event_id, uint64_t clock, bool loop, int* register_id);
271         void cancel_event(DEVICE* device, int register_id);
272         void register_frame_event(DEVICE* device);
273         void register_vline_event(DEVICE* device);
274         uint32_t get_event_remaining_clock(int register_id);
275         double get_event_remaining_usec(int register_id);
276         uint32_t get_current_clock();
277         uint32_t get_passed_clock(uint32_t prev);
278         double get_passed_usec(uint32_t prev);
279         uint32_t get_passed_clock_since_vline();
280         double get_passed_usec_since_vline();
281         int get_cur_vline()
282         {
283                 return cur_vline;
284         }
285         int get_cur_vline_clocks()
286         {
287                 return vclocks[cur_vline];
288         }
289         uint32_t get_cpu_pc(int index);
290         void request_skip_frames();
291         void touch_sound();
292         void set_realtime_render(DEVICE* device, bool flag);
293         
294         // unique functions
295         double get_frame_rate()
296         {
297                 return next_frames_per_sec;
298         }
299         void drive();
300         
301         void initialize_sound(int rate, int samples);
302         uint16_t* create_sound(int* extra_frames);
303         int get_sound_buffer_ptr();
304         template <class T>
305                 void set_context_cpu(T* device, uint32_t clocks = CPU_CLOCKS)
306         {
307                 assert(dcount_cpu < MAX_CPU);
308                 int index = dcount_cpu++;
309                 d_cpu[index].device = (DEVICE *)device;
310                 d_cpu[index].cpu_clocks = clocks;
311                 d_cpu[index].accum_clocks = 0;
312                 set_cpu_type(device, index);
313                 for(int k = 0; k < 6; k++) cpu_update_clocks[index][k] = d_cpu[index].update_clocks * k;
314         }
315         void set_secondary_cpu_clock(DEVICE* device, uint32_t clocks)
316         {
317                 // XXX: primary cpu clock should not be changed
318                 for(int index = 1; index < dcount_cpu; index++) {
319                         if(d_cpu[index].device == device) {
320                                 d_cpu[index].accum_clocks = 0;
321                                 d_cpu[index].cpu_clocks = clocks;
322                                 d_cpu[index].update_clocks = (int)(1024.0 * (double)d_cpu[index].cpu_clocks / (double)d_cpu[0].cpu_clocks + 0.5)
323 ;
324                                 for(int k = 0; k < 6; k++) cpu_update_clocks[index][k] = d_cpu[index].update_clocks * k;
325                                 break;
326                         }
327                 }
328         }
329         void set_context_sound(DEVICE* device)
330         {
331                 assert(dcount_sound < MAX_SOUND);
332                 d_sound[dcount_sound++] = device;
333         }
334         bool is_frame_skippable();
335 };
336
337 /*
338  * Faster runncing cpu.
339  * Expect to optimize switch(...) - case to jump table.
340  * You should include real header of CPU DEVICE begin of this file.
341  * -- 20180317 K.O.
342  */
343
344
345
346 #endif
347