2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
11 #include "../fileio.h"
15 void EVENT::initialize()
18 if(!(0 <= config.cpu_power && config.cpu_power <= 4)) {
21 power = config.cpu_power;
23 // initialize sound buffer
28 prev_skip = next_skip = false;
29 sound_changed = false;
32 void EVENT::initialize_sound(int rate, int samples)
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);
44 this->register_event(this, EVENT_MIX, 1000000.0 / rate, true, NULL);
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);
68 cpu_remain = cpu_accum = cpu_done = 0;
72 memset(sound_buffer, 0, sound_samples * sizeof(uint16) * 2);
75 memset(sound_tmp, 0, sound_tmp_samples * sizeof(int32) * 2);
80 initialize_done = true;
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();
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;
97 int sum = (int)((double)d_cpu[0].cpu_clocks / frames_per_sec + 0.5);
100 for(int i = 0; i < lines_per_frame; i++) {
101 vclocks[i] = (int)(sum / lines_per_frame);
102 remain -= vclocks[i];
104 for(int i = 0; i < remain; i++) {
105 int index = (int)((double)lines_per_frame * (double)i / (double)remain);
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);
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);
118 // run virtual machine for 1 frame period
119 for(int i = 0; i < frame_event_count; i++) {
120 frame_event[i]->event_frame();
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]);
128 if(event_remain < 0) {
129 if(-event_remain > vclocks[v]) {
130 update_event(vclocks[v]);
132 update_event(-event_remain);
135 event_remain += vclocks[v];
136 cpu_remain += vclocks[v] << power;
138 while(event_remain > 0) {
139 int event_done = event_remain;
141 // run one opecode on primary cpu
143 if(dcount_cpu == 1) {
144 cpu_done_tmp = d_cpu[0].device->run(-1);
148 cpu_done = d_cpu[0].device->run(-1);
150 cpu_done_tmp = (cpu_done < 4) ? cpu_done : 4;
151 cpu_done -= cpu_done_tmp;
153 for(int i = 1; i < dcount_cpu; i++) {
155 d_cpu[i].accum_clocks += d_cpu[i].update_clocks * cpu_done_tmp;
156 int sub_clock = d_cpu[i].accum_clocks >> 10;
158 d_cpu[i].accum_clocks -= sub_clock << 10;
159 d_cpu[i].device->run(sub_clock);
163 cpu_remain -= cpu_done_tmp;
164 cpu_accum += cpu_done_tmp;
165 event_done = cpu_accum >> power;
166 cpu_accum -= event_done << power;
169 if(event_done > event_remain) {
170 update_event(event_remain);
172 update_event(event_done);
174 event_remain -= event_done;
180 void EVENT::update_event(int clock)
182 uint64 event_clocks_tmp = event_clocks + clock;
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;
188 first_fire_event = event_handle->next;
189 if(first_fire_event != NULL) {
190 first_fire_event->prev = NULL;
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);
199 event_handle->active = false;
200 event_handle->next = first_free_event;
201 first_free_event = event_handle;
203 event_clocks = expired_clock;
204 event_handle->device->event_callback(event_handle->event_id, 0);
206 event_clocks = event_clocks_tmp;
209 uint32 EVENT::current_clock()
211 return (uint32)(event_clocks & 0xffffffff);
214 uint32 EVENT::passed_clock(uint32 prev)
216 uint32 current = current_clock();
217 return (current > prev) ? current - prev : current + (0xffffffff - prev) + 1;
220 double EVENT::passed_usec(uint32 prev)
222 return 1000000.0 * passed_clock(prev) / d_cpu[0].cpu_clocks;
225 uint32 EVENT::get_cpu_pc(int index)
227 return d_cpu[index].device->get_pc();
230 void EVENT::register_event(DEVICE* device, int event_id, double usec, bool loop, int* register_id)
233 if(!initialize_done && !loop) {
234 emu->out_debug_log(_T("EVENT: non-loop event is registered before initialize is done\n"));
239 if(first_free_event == NULL) {
241 emu->out_debug_log(_T("EVENT: too many events !!!\n"));
243 if(register_id != NULL) {
248 event_t *event_handle = first_free_event;
249 first_free_event = first_free_event->next;
251 if(register_id != NULL) {
252 *register_id = event_handle->index;
254 event_handle->active = true;
255 event_handle->device = device;
256 event_handle->event_id = event_id;
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;
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;
268 event_handle->expired_clock = event_clocks + clock;
270 insert_event(event_handle);
273 void EVENT::register_event_by_clock(DEVICE* device, int event_id, uint64 clock, bool loop, int* register_id)
276 if(!initialize_done && !loop) {
277 emu->out_debug_log(_T("EVENT: non-loop event is registered before initialize is done\n"));
282 if(first_free_event == NULL) {
284 emu->out_debug_log(_T("EVENT: too many events !!!\n"));
286 if(register_id != NULL) {
291 event_t *event_handle = first_free_event;
292 first_free_event = first_free_event->next;
294 if(register_id != NULL) {
295 *register_id = event_handle->index;
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;
304 insert_event(event_handle);
307 void EVENT::insert_event(event_t *event_handle)
309 if(first_fire_event == NULL) {
310 first_fire_event = event_handle;
311 event_handle->prev = event_handle->next = NULL;
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) {
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;
324 first_fire_event = event_handle;
325 event_handle->prev = NULL;
326 event_handle->next = insert_pos;
327 insert_pos->prev = event_handle;
330 } else if(insert_pos->next == NULL) {
332 insert_pos->next = event_handle;
333 event_handle->prev = insert_pos;
334 event_handle->next = NULL;
341 void EVENT::cancel_event(DEVICE* device, int register_id)
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);
350 if(event_handle->active) {
351 if(event_handle->prev != NULL) {
352 event_handle->prev->next = event_handle->next;
354 first_fire_event = event_handle->next;
356 if(event_handle->next != NULL) {
357 event_handle->next->prev = event_handle->prev;
359 event_handle->active = false;
360 event_handle->next = first_free_event;
361 first_free_event = event_handle;
366 void EVENT::register_frame_event(DEVICE* dev)
368 if(frame_event_count < MAX_EVENT) {
369 frame_event[frame_event_count++] = dev;
372 emu->out_debug_log(_T("EVENT: too many frame events !!!\n"));
377 void EVENT::register_vline_event(DEVICE* dev)
379 if(vline_event_count < MAX_EVENT) {
380 vline_event[vline_event_count++] = dev;
383 emu->out_debug_log(_T("EVENT: too many vline events !!!\n"));
388 void EVENT::event_callback(int event_id, int err)
390 // if(event_id == EVENT_MIX) {
392 if(prev_skip && dont_skip_frames == 0 && !sound_changed) {
395 if(sound_tmp_samples - buffer_ptr > 0) {
401 void EVENT::mix_sound(int samples)
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);
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;
417 buffer_ptr += samples;
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);
426 uint16* EVENT::create_sound(int* extra_frames)
428 if(prev_skip && dont_skip_frames == 0 && !sound_changed) {
429 memset(sound_buffer, 0, sound_samples * sizeof(uint16) * 2);
435 // drive extra frames to fill the sound buffer
436 while(sound_samples > buffer_ptr) {
440 #ifdef 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
448 for(int i = 0; i < sound_samples * 2; i++) {
449 int dat = sound_tmp[i];
450 uint16 highlow = (uint16)(dat & 0x0000ffff);
452 if((dat > 0) && (highlow >= 0x8000)) {
453 sound_buffer[i] = 0x7fff;
456 if((dat < 0) && (highlow < 0x8000)) {
457 sound_buffer[i] = 0x8000;
460 sound_buffer[i] = highlow;
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);
468 *extra_frames = frames;
472 int EVENT::sound_buffer_ptr()
477 void EVENT::request_skip_frames()
482 bool EVENT::now_skip()
484 bool value = next_skip;
486 if(sound_changed || (prev_skip && !next_skip)) {
487 dont_skip_frames = (int)frames_per_sec;
489 if(dont_skip_frames > 0) {
493 prev_skip = next_skip;
495 sound_changed = false;
500 void EVENT::update_config()
502 if(power != config.cpu_power) {
503 power = config.cpu_power;
508 #define STATE_VERSION 2
510 void EVENT::save_state(FILEIO* state_fio)
512 state_fio->FputUint32(STATE_VERSION);
513 state_fio->FputInt32(this_device_id);
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);
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);
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);
545 bool EVENT::load_state(FILEIO* state_fio)
547 if(state_fio->FgetUint32() != STATE_VERSION) {
550 if(state_fio->FgetInt32() != this_device_id) {
553 if(state_fio->FgetInt32() != dcount_cpu) {
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();
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());
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();
586 memset(sound_buffer, 0, sound_samples * sizeof(uint16) * 2);
589 memset(sound_tmp, 0, sound_tmp_samples * sizeof(int32) * 2);
595 void* EVENT::get_event(int index)
597 if(index >= 0 && index < MAX_EVENT) {
598 return &event[index];