OSDN Git Service

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