OSDN Git Service

[VM][FM7] keyboard.cpp : Add implementation ofd RTC, includes within keyboard.
[csp-qt/common_source_project-fm7.git] / source / src / vm / event.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2006.11.29-
6
7         [ event manager ]
8 */
9
10 #include "event.h"
11 #include "../fileio.h"
12
13 #ifndef EVENT_CONTINUOUS_SOUND
14 //#ifdef PCM1BIT_HIGH_QUALITY
15 #define EVENT_CONTINUOUS_SOUND
16 //#endif
17 #endif
18
19 void EVENT::initialize()
20 {
21         // load config
22         if(!(0 <= config.cpu_power && config.cpu_power <= 4)) {
23                 config.cpu_power = 0;
24         }
25         power = config.cpu_power;
26         
27         // initialize sound buffer
28         sound_buffer = NULL;
29         sound_tmp = NULL;
30         
31         dont_skip_frames = 0;
32         prev_skip = next_skip = false;
33         sound_changed = false;
34 }
35
36 void EVENT::initialize_sound(int rate, int samples)
37 {
38         // initialize sound
39         sound_rate = rate;
40         sound_samples = samples;
41 #ifdef EVENT_CONTINUOUS_SOUND
42         sound_tmp_samples = samples * 2;
43 #else
44         sound_tmp_samples = samples;
45 #endif
46         sound_buffer = (uint16*)malloc(sound_samples * sizeof(uint16) * 2);
47         memset(sound_buffer, 0, sound_samples * sizeof(uint16) * 2);
48         sound_tmp = (int32*)malloc(sound_tmp_samples * sizeof(int32) * 2);
49         memset(sound_tmp, 0, sound_tmp_samples * sizeof(int32) * 2);
50         buffer_ptr = accum_samples = 0;
51 }
52
53 void EVENT::release()
54 {
55         // release sound
56         if(sound_buffer) {
57                 free(sound_buffer);
58         }
59         if(sound_tmp) {
60                 free(sound_tmp);
61         }
62 }
63
64 void EVENT::reset()
65 {
66         // clear events except loop event
67         for(int i = 0; i < MAX_EVENT; i++) {
68                 if(event[i].active && event[i].loop_clock == 0) {
69                         cancel_event(NULL, i);
70                 }
71         }
72         
73         event_remain = 0;
74         cpu_remain = cpu_accum = cpu_done = 0;
75         
76         // reset sound
77         if(sound_buffer) {
78                 memset(sound_buffer, 0, sound_samples * sizeof(uint16) * 2);
79         }
80         if(sound_tmp) {
81                 memset(sound_tmp, 0, sound_tmp_samples * sizeof(int32) * 2);
82         }
83 //      buffer_ptr = 0;
84         
85 #ifdef _DEBUG_LOG
86         initialize_done = true;
87 #endif
88 }
89
90 void EVENT::drive()
91 {
92         // raise pre frame events to update timing settings
93         for(int i = 0; i < frame_event_count; i++) {
94                 frame_event[i]->event_pre_frame();
95         }
96         
97         // generate clocks per line
98         if(frames_per_sec != next_frames_per_sec || lines_per_frame != next_lines_per_frame) {
99                 frames_per_sec = next_frames_per_sec;
100                 lines_per_frame = next_lines_per_frame;
101                 
102                 int sum = (int)((double)d_cpu[0].cpu_clocks / frames_per_sec + 0.5);
103                 int remain = sum;
104                 
105                 for(int i = 0; i < lines_per_frame; i++) {
106                         vclocks[i] = (int)(sum / lines_per_frame);
107                         remain -= vclocks[i];
108                 }
109                 for(int i = 0; i < remain; i++) {
110                         int index = (int)((double)lines_per_frame * (double)i / (double)remain);
111                         vclocks[index]++;
112                 }
113                 for(int i = 1; i < dcount_cpu; i++) {
114                         d_cpu[i].update_clocks = (int)(1024.0 * (double)d_cpu[i].cpu_clocks / (double)d_cpu[0].cpu_clocks + 0.5);
115                 }
116                 for(DEVICE* device = vm->first_device; device; device = device->next_device) {
117                         if(device->event_manager_id() == this_device_id) {
118                                 device->update_timing(d_cpu[0].cpu_clocks, frames_per_sec, lines_per_frame);
119                         }
120                 }
121                 update_samples = (int)(1024.0 * (double)sound_rate / frames_per_sec / (double)lines_per_frame + 0.5);
122         }
123         
124         // run virtual machine for 1 frame period
125         for(int i = 0; i < frame_event_count; i++) {
126                 frame_event[i]->event_frame();
127         }
128         for(int v = 0; v < lines_per_frame; v++) {
129                 // run virtual machine per line
130                 for(int i = 0; i < vline_event_count; i++) {
131                         vline_event[i]->event_vline(v, vclocks[v]);
132                 }
133                 
134                 if(event_remain < 0) {
135                         if(-event_remain > vclocks[v]) {
136                                 update_event(vclocks[v]);
137                         } else {
138                                 update_event(-event_remain);
139                         }
140                 }
141                 event_remain += vclocks[v];
142                 cpu_remain += vclocks[v] << power;
143                 
144                 while(event_remain > 0) {
145                         int event_done = event_remain;
146                         if(cpu_remain > 0) {
147                                 // run one opecode on primary cpu
148                                 int cpu_done_tmp;
149                                 if(dcount_cpu == 1) {
150                                         cpu_done_tmp = d_cpu[0].device->run(-1);
151                                 } else {
152                                         // sync to sub cpus
153                                         if(cpu_done == 0) {
154                                                 cpu_done = d_cpu[0].device->run(-1);
155                                         }
156                                         cpu_done_tmp = (cpu_done < 4) ? cpu_done : 4;
157                                         cpu_done -= cpu_done_tmp;
158                                         
159                                         for(int i = 1; i < dcount_cpu; i++) {
160                                                 // run sub cpus
161                                                 d_cpu[i].accum_clocks += d_cpu[i].update_clocks * cpu_done_tmp;
162                                                 int sub_clock = d_cpu[i].accum_clocks >> 10;
163                                                 if(sub_clock) {
164                                                         d_cpu[i].accum_clocks -= sub_clock << 10;
165                                                         d_cpu[i].device->run(sub_clock);
166                                                 }
167                                         }
168                                 }
169                                 cpu_remain -= cpu_done_tmp;
170                                 cpu_accum += cpu_done_tmp;
171                                 event_done = cpu_accum >> power;
172                                 cpu_accum -= event_done << power;
173                         }
174                         if(event_done > 0) {
175                                 if(event_done > event_remain) {
176                                         update_event(event_remain);
177                                 } else {
178                                         update_event(event_done);
179                                 }
180                                 event_remain -= event_done;
181                         }
182                 }
183                 update_sound();
184         }
185 }
186
187 void EVENT::update_event(int clock)
188 {
189         uint64 event_clocks_tmp = event_clocks + clock;
190         
191         while(first_fire_event != NULL && first_fire_event->expired_clock <= event_clocks_tmp) {
192                 event_t *event_handle = first_fire_event;
193                 uint64 expired_clock = event_handle->expired_clock;
194                 
195                 first_fire_event = event_handle->next;
196                 if(first_fire_event != NULL) {
197                         first_fire_event->prev = NULL;
198                 }
199                 if(event_handle->loop_clock != 0) {
200                         event_handle->expired_clock += event_handle->loop_clock;
201                         insert_event(event_handle);
202                 } else {
203                         event_handle->active = false;
204                         event_handle->next = first_free_event;
205                         first_free_event = event_handle;
206                 }
207                 event_clocks = expired_clock;
208                 event_handle->device->event_callback(event_handle->event_id, 0);
209         }
210         event_clocks = event_clocks_tmp;
211 }
212
213 uint32 EVENT::current_clock()
214 {
215         return (uint32)(event_clocks & 0xffffffff);
216 }
217
218 uint32 EVENT::passed_clock(uint32 prev)
219 {
220         uint32 current = current_clock();
221         return (current > prev) ? current - prev : current + (0xffffffff - prev) + 1;
222 }
223
224 double EVENT::passed_usec(uint32 prev)
225 {
226         return 1000000.0 * passed_clock(prev) / d_cpu[0].cpu_clocks;
227 }
228
229 uint32 EVENT::get_cpu_pc(int index)
230 {
231         return d_cpu[index].device->get_pc();
232 }
233
234 void EVENT::register_event(DEVICE* device, int event_id, double usec, bool loop, int* register_id)
235 {
236         int clock = (int)((double)d_cpu[0].cpu_clocks / 1000000.0 * usec + 0.5);
237         register_event_by_clock(device, event_id, clock, loop, register_id);
238 }
239
240 void EVENT::register_event_by_clock(DEVICE* device, int event_id, int clock, bool loop, int* register_id)
241 {
242 #ifdef _DEBUG_LOG
243         if(!initialize_done && !loop) {
244                 emu->out_debug_log(_T("EVENT: non-loop event is registered before initialize is done\n"));
245         }
246 #endif
247         
248         // register event
249         if(first_free_event == NULL) {
250 #ifdef _DEBUG_LOG
251                 emu->out_debug_log(_T("EVENT: too many events !!!\n"));
252 #endif
253                 if(register_id != NULL) {
254                         *register_id = -1;
255                 }
256                 return;
257         }
258         event_t *event_handle = first_free_event;
259         first_free_event = first_free_event->next;
260         
261         if(register_id != NULL) {
262                 *register_id = event_handle->index;
263         }
264         event_handle->active = true;
265         event_handle->device = device;
266         event_handle->event_id = event_id;
267         event_handle->expired_clock = event_clocks + clock;
268         event_handle->loop_clock = loop ? clock : 0;
269         
270         insert_event(event_handle);
271 }
272
273 void EVENT::insert_event(event_t *event_handle)
274 {
275         if(first_fire_event == NULL) {
276                 first_fire_event = event_handle;
277                 event_handle->prev = event_handle->next = NULL;
278         } else {
279                 for(event_t *insert_pos = first_fire_event; insert_pos != NULL; insert_pos = insert_pos->next) {
280                         if(insert_pos->expired_clock > event_handle->expired_clock) {
281                                 if(insert_pos->prev != NULL) {
282                                         // insert
283                                         insert_pos->prev->next = event_handle;
284                                         event_handle->prev = insert_pos->prev;
285                                         event_handle->next = insert_pos;
286                                         insert_pos->prev = event_handle;
287                                         break;
288                                 } else {
289                                         // add to head
290                                         first_fire_event = event_handle;
291                                         event_handle->prev = NULL;
292                                         event_handle->next = insert_pos;
293                                         insert_pos->prev = event_handle;
294                                         break;
295                                 }
296                         } else if(insert_pos->next == NULL) {
297                                 // add to tail
298                                 insert_pos->next = event_handle;
299                                 event_handle->prev = insert_pos;
300                                 event_handle->next = NULL;
301                                 break;
302                         }
303                 }
304         }
305 }
306
307 void EVENT::cancel_event(DEVICE* device, int register_id)
308 {
309         // cancel registered event
310         if(0 <= register_id && register_id < MAX_EVENT) {
311                 event_t *event_handle = &event[register_id];
312                 if(device != NULL && device != event_handle->device) {
313                         emu->out_debug_log("EVENT: event cannot be canceled by non ownew device (id=%d) !!!\n", device->this_device_id);
314                         return;
315                 }
316                 if(event_handle->active) {
317                         if(event_handle->prev != NULL) {
318                                 event_handle->prev->next = event_handle->next;
319                         } else {
320                                 first_fire_event = event_handle->next;
321                         }
322                         if(event_handle->next != NULL) {
323                                 event_handle->next->prev = event_handle->prev;
324                         }
325                         event_handle->active = false;
326                         event_handle->next = first_free_event;
327                         first_free_event = event_handle;
328                 }
329         }
330 }
331
332 void EVENT::register_frame_event(DEVICE* dev)
333 {
334         if(frame_event_count < MAX_EVENT) {
335                 frame_event[frame_event_count++] = dev;
336         } else {
337 #ifdef _DEBUG_LOG
338                 emu->out_debug_log(_T("EVENT: too many frame events !!!\n"));
339 #endif
340         }
341 }
342
343 void EVENT::register_vline_event(DEVICE* dev)
344 {
345         if(vline_event_count < MAX_EVENT) {
346                 vline_event[vline_event_count++] = dev;
347         } else {
348 #ifdef _DEBUG_LOG
349                 emu->out_debug_log(_T("EVENT: too many vline events !!!\n"));
350 #endif
351         }
352 }
353
354 void EVENT::mix_sound(int samples)
355 {
356         if(samples > 0) {
357                 int32* buffer = sound_tmp + buffer_ptr * 2;
358                 memset(buffer, 0, samples * sizeof(int32) * 2);
359                 for(int i = 0; i < dcount_sound; i++) {
360                         d_sound[i]->mix(buffer, samples);
361                 }
362                 if(!sound_changed) {
363                         for(int i = 0; i < samples * 2; i += 2) {
364                                 if(buffer[i] != sound_tmp[0] || buffer[i + 1] != sound_tmp[1]) {
365                                         sound_changed = true;
366                                         break;
367                                 }
368                         }
369                 }
370                 buffer_ptr += samples;
371         } else {
372                 // notify to sound devices
373                 for(int i = 0; i < dcount_sound; i++) {
374                         d_sound[i]->mix(sound_tmp + buffer_ptr * 2, 0);
375                 }
376         }
377 }
378
379 void EVENT::update_sound()
380 {
381         accum_samples += update_samples;
382         int samples = accum_samples >> 10;
383         accum_samples -= samples << 10;
384         
385         // mix sound
386         if(prev_skip && dont_skip_frames == 0 && !sound_changed) {
387                 buffer_ptr = 0;
388         }
389         if(samples > sound_tmp_samples - buffer_ptr) {
390                 samples = sound_tmp_samples - buffer_ptr;
391         }
392         mix_sound(samples);
393 }
394
395 uint16* EVENT::create_sound(int* extra_frames)
396 {
397         if(prev_skip && dont_skip_frames == 0 && !sound_changed) {
398                 memset(sound_buffer, 0, sound_samples * sizeof(uint16) * 2);
399                 *extra_frames = 0;
400                 return sound_buffer;
401         }
402         int frames = 0;
403         
404 #ifdef EVENT_CONTINUOUS_SOUND
405         // drive extra frames to fill the sound buffer
406         while(sound_samples > buffer_ptr) {
407                 drive();
408                 frames++;
409         }
410 #else
411         // fill sound buffer
412         int samples = sound_samples - buffer_ptr;
413         mix_sound(samples);
414 #endif
415 #ifdef LOW_PASS_FILTER
416         // low-pass filter
417         for(int i = 0; i < sound_samples - 1; i++) {
418                 sound_tmp[i * 2    ] = (sound_tmp[i * 2    ] + sound_tmp[i * 2 + 2]) / 2; // L
419                 sound_tmp[i * 2 + 1] = (sound_tmp[i * 2 + 1] + sound_tmp[i * 2 + 3]) / 2; // R
420         }
421 #endif
422         // copy to buffer
423         for(int i = 0; i < sound_samples * 2; i++) {
424                 int dat = sound_tmp[i];
425                 uint16 highlow = (uint16)(dat & 0x0000ffff);
426                 
427                 if((dat > 0) && (highlow >= 0x8000)) {
428                         sound_buffer[i] = 0x7fff;
429                         continue;
430                 }
431                 if((dat < 0) && (highlow < 0x8000)) {
432                         sound_buffer[i] = 0x8000;
433                         continue;
434                 }
435                 sound_buffer[i] = highlow;
436         }
437         if(buffer_ptr > sound_samples) {
438                 buffer_ptr -= sound_samples;
439                 memcpy(sound_tmp, sound_tmp + sound_samples * 2, buffer_ptr * sizeof(int32) * 2);
440         } else {
441                 buffer_ptr = 0;
442         }
443         *extra_frames = frames;
444         return sound_buffer;
445 }
446
447 int EVENT::sound_buffer_ptr()
448 {
449         return buffer_ptr;
450 }
451
452 void EVENT::request_skip_frames()
453 {
454         next_skip = true;
455 }
456
457 bool EVENT::now_skip()
458 {
459         bool value = next_skip;
460         
461         if(sound_changed || (prev_skip && !next_skip)) {
462                 dont_skip_frames = (int)frames_per_sec;
463         }
464         if(dont_skip_frames > 0) {
465                 value = false;
466                 dont_skip_frames--;
467         }
468         prev_skip = next_skip;
469         next_skip = false;
470         sound_changed = false;
471         
472         return value;
473 }
474
475 void EVENT::update_config()
476 {
477         if(power != config.cpu_power) {
478                 power = config.cpu_power;
479                 cpu_accum = 0;
480         }
481 }
482
483 #define STATE_VERSION   1
484
485 void EVENT::save_state(FILEIO* state_fio)
486 {
487         state_fio->FputUint32(STATE_VERSION);
488         state_fio->FputInt32(this_device_id);
489         
490         state_fio->FputInt32(dcount_cpu);
491         for(int i = 0; i < dcount_cpu; i++) {
492                 state_fio->FputInt32(d_cpu[i].cpu_clocks);
493                 state_fio->FputInt32(d_cpu[i].update_clocks);
494                 state_fio->FputInt32(d_cpu[i].accum_clocks);
495         }
496         state_fio->Fwrite(vclocks, sizeof(vclocks), 1);
497         state_fio->FputInt32(event_remain);
498         state_fio->FputInt32(cpu_remain);
499         state_fio->FputInt32(cpu_accum);
500         state_fio->FputInt32(cpu_done);
501         state_fio->FputUint64(event_clocks);
502         for(int i = 0; i < MAX_EVENT; i++) {
503                 state_fio->FputInt32(event[i].device != NULL ? event[i].device->this_device_id : -1);
504                 state_fio->FputInt32(event[i].event_id);
505                 state_fio->FputUint64(event[i].expired_clock);
506                 state_fio->FputUint32(event[i].loop_clock);
507                 state_fio->FputBool(event[i].active);
508                 state_fio->FputInt32(event[i].next != NULL ? event[i].next->index : -1);
509                 state_fio->FputInt32(event[i].prev != NULL ? event[i].prev->index : -1);
510         }
511         state_fio->FputInt32(first_free_event != NULL ? first_free_event->index : -1);
512         state_fio->FputInt32(first_fire_event != NULL ? first_fire_event->index : -1);
513         state_fio->FputDouble(frames_per_sec);
514         state_fio->FputDouble(next_frames_per_sec);
515         state_fio->FputInt32(lines_per_frame);
516         state_fio->FputInt32(next_lines_per_frame);
517 }
518
519 bool EVENT::load_state(FILEIO* state_fio)
520 {
521         if(state_fio->FgetUint32() != STATE_VERSION) {
522                 return false;
523         }
524         if(state_fio->FgetInt32() != this_device_id) {
525                 return false;
526         }
527         if(state_fio->FgetInt32() != dcount_cpu) {
528                 return false;
529         }
530         for(int i = 0; i < dcount_cpu; i++) {
531                 d_cpu[i].cpu_clocks = state_fio->FgetInt32();
532                 d_cpu[i].update_clocks = state_fio->FgetInt32();
533                 d_cpu[i].accum_clocks = state_fio->FgetInt32();
534         }
535         state_fio->Fread(vclocks, sizeof(vclocks), 1);
536         event_remain = state_fio->FgetInt32();
537         cpu_remain = state_fio->FgetInt32();
538         cpu_accum = state_fio->FgetInt32();
539         cpu_done = state_fio->FgetInt32();
540         event_clocks = state_fio->FgetUint64();
541         for(int i = 0; i < MAX_EVENT; i++) {
542                 event[i].device = vm->get_device(state_fio->FgetInt32());
543                 event[i].event_id = state_fio->FgetInt32();
544                 event[i].expired_clock = state_fio->FgetUint64();
545                 event[i].loop_clock = state_fio->FgetUint32();
546                 event[i].active = state_fio->FgetBool();
547                 event[i].next = (event_t *)get_event(state_fio->FgetInt32());
548                 event[i].prev = (event_t *)get_event(state_fio->FgetInt32());
549         }
550         first_free_event = (event_t *)get_event(state_fio->FgetInt32());
551         first_fire_event = (event_t *)get_event(state_fio->FgetInt32());
552         frames_per_sec = state_fio->FgetDouble();
553         next_frames_per_sec = state_fio->FgetDouble();
554         lines_per_frame = state_fio->FgetInt32();
555         next_lines_per_frame = state_fio->FgetInt32();
556         
557         // post process
558         if(sound_buffer) {
559                 memset(sound_buffer, 0, sound_samples * sizeof(uint16) * 2);
560         }
561         if(sound_tmp) {
562                 memset(sound_tmp, 0, sound_tmp_samples * sizeof(int32) * 2);
563         }
564         buffer_ptr = accum_samples = 0;
565         update_samples = (int)(1024.0 * (double)sound_rate / frames_per_sec / (double)lines_per_frame + 0.5);
566         return true;
567 }
568
569 void* EVENT::get_event(int index)
570 {
571         if(index >= 0 && index < MAX_EVENT) {
572                 return &event[index];
573         }
574         return NULL;
575 }