2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
14 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;
31 vline_start_clock = 0;
33 vclocks[0] = (int)((double)d_cpu[0].cpu_clocks / (double)FRAMES_PER_SEC / (double)LINES_PER_FRAME + 0.5); // temporary
36 void EVENT::initialize_sound(int rate, int samples)
39 sound_samples = samples;
40 sound_tmp_samples = samples * 2;
41 sound_buffer = (uint16_t*)malloc(sound_samples * sizeof(uint16_t) * 2);
42 memset(sound_buffer, 0, sound_samples * sizeof(uint16_t) * 2);
43 sound_tmp = (int32_t*)malloc(sound_tmp_samples * sizeof(int32_t) * 2);
44 memset(sound_tmp, 0, sound_tmp_samples * sizeof(int32_t) * 2);
47 mix_limit = (int)((double)(emu->get_sound_rate() / 2000.0)); // per 0.5ms.
50 this->register_event(this, EVENT_MIX, 1000000.0 / rate, true, NULL);
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);
74 cpu_remain = cpu_accum = cpu_done = 0;
78 memset(sound_buffer, 0, sound_samples * sizeof(uint16_t) * 2);
81 memset(sound_tmp, 0, sound_tmp_samples * sizeof(int32_t) * 2);
86 initialize_done = true;
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();
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;
102 int sum = (int)((double)d_cpu[0].cpu_clocks / frames_per_sec + 0.5);
105 for(int i = 0; i < lines_per_frame; i++) {
106 assert(i < MAX_LINES);
107 vclocks[i] = (int)(sum / lines_per_frame);
108 remain -= vclocks[i];
110 for(int i = 0; i < remain; i++) {
111 int index = (int)((double)lines_per_frame * (double)i / (double)remain);
112 assert(index < MAX_LINES);
115 for(int i = 1; i < dcount_cpu; i++) {
116 d_cpu[i].update_clocks = (int)(1024.0 * (double)d_cpu[i].cpu_clocks / (double)d_cpu[0].cpu_clocks + 0.5);
118 for(DEVICE* device = vm->first_device; device; device = device->next_device) {
119 if(device->get_event_manager_id() == this_device_id) {
120 device->update_timing(d_cpu[0].cpu_clocks, frames_per_sec, lines_per_frame);
125 // run virtual machine for 1 frame period
126 for(int i = 0; i < frame_event_count; i++) {
127 frame_event[i]->event_frame();
129 for(cur_vline = 0; cur_vline < lines_per_frame; cur_vline++) {
130 vline_start_clock = get_current_clock();
132 // run virtual machine per line
133 for(int i = 0; i < vline_event_count; i++) {
134 vline_event[i]->event_vline(cur_vline, vclocks[cur_vline]);
137 if(event_remain < 0) {
138 if(-event_remain > vclocks[cur_vline]) {
139 update_event(vclocks[cur_vline]);
141 update_event(-event_remain);
144 event_remain += vclocks[cur_vline];
145 cpu_remain += vclocks[cur_vline] << power;
147 while(event_remain > 0) {
148 int event_done = event_remain;
151 if(dcount_cpu == 1) {
152 // run one opecode on primary cpu
153 cpu_done_tmp = d_cpu[0].device->run(-1);
157 // run one opecode on primary cpu
158 cpu_done = d_cpu[0].device->run(-1);
161 // sub cpu runs continuously and no events will be fired while the given clocks,
162 // so I need to give small enough clocks...
163 cpu_done_tmp = (cpu_done < 4) ? cpu_done : 4;
164 cpu_done -= cpu_done_tmp;
166 for(int i = 1; i < dcount_cpu; i++) {
168 d_cpu[i].accum_clocks += d_cpu[i].update_clocks * cpu_done_tmp;
169 int sub_clock = d_cpu[i].accum_clocks >> 10;
171 d_cpu[i].accum_clocks -= sub_clock << 10;
172 d_cpu[i].device->run(sub_clock);
176 cpu_remain -= cpu_done_tmp;
177 cpu_accum += cpu_done_tmp;
178 event_done = cpu_accum >> power;
179 cpu_accum -= event_done << power;
182 if(event_done > event_remain) {
183 update_event(event_remain);
185 update_event(event_done);
187 event_remain -= event_done;
193 void EVENT::update_event(int clock)
195 uint64_t event_clocks_tmp = event_clocks + clock;
197 while(first_fire_event != NULL && first_fire_event->expired_clock <= event_clocks_tmp) {
198 event_t *event_handle = first_fire_event;
199 uint64_t expired_clock = event_handle->expired_clock;
201 first_fire_event = event_handle->next;
202 if(first_fire_event != NULL) {
203 first_fire_event->prev = NULL;
205 if(event_handle->loop_clock != 0) {
206 event_handle->accum_clocks += event_handle->loop_clock;
207 uint64_t clock_tmp = event_handle->accum_clocks >> 10;
208 event_handle->accum_clocks -= clock_tmp << 10;
209 event_handle->expired_clock += clock_tmp;
210 insert_event(event_handle);
212 event_handle->active = false;
213 event_handle->next = first_free_event;
214 first_free_event = event_handle;
216 event_clocks = expired_clock;
217 event_handle->device->event_callback(event_handle->event_id, 0);
219 event_clocks = event_clocks_tmp;
222 uint32_t EVENT::get_current_clock()
224 return (uint32_t)(event_clocks & 0xffffffff);
227 uint32_t EVENT::get_passed_clock(uint32_t prev)
229 uint32_t current = get_current_clock();
230 return (current > prev) ? current - prev : current + (0xffffffff - prev) + 1;
233 double EVENT::get_passed_usec(uint32_t prev)
235 return 1000000.0 * get_passed_clock(prev) / d_cpu[0].cpu_clocks;
238 uint32_t EVENT::get_passed_clock_since_vline()
240 return get_passed_clock(vline_start_clock);
243 double EVENT::get_passed_usec_since_vline()
245 return get_passed_usec(vline_start_clock);
248 uint32_t EVENT::get_cpu_pc(int index)
250 return d_cpu[index].device->get_pc();
253 void EVENT::register_event(DEVICE* device, int event_id, double usec, bool loop, int* register_id)
256 if(!initialize_done && !loop) {
257 this->out_debug_log(_T("EVENT: non-loop event is registered before initialize is done\n"));
262 if(first_free_event == NULL) {
264 this->out_debug_log(_T("EVENT: too many events !!!\n"));
266 if(register_id != NULL) {
271 event_t *event_handle = first_free_event;
272 first_free_event = first_free_event->next;
274 if(register_id != NULL) {
275 *register_id = event_handle->index;
277 event_handle->active = true;
278 event_handle->device = device;
279 event_handle->event_id = event_id;
282 event_handle->loop_clock = (uint64_t)(1024.0 * (double)d_cpu[0].cpu_clocks / 1000000.0 * usec + 0.5);
283 event_handle->accum_clocks = event_handle->loop_clock;
284 clock = event_handle->accum_clocks >> 10;
285 event_handle->accum_clocks -= clock << 10;
287 clock = (uint64_t)((double)d_cpu[0].cpu_clocks / 1000000.0 * usec + 0.5);
288 event_handle->loop_clock = 0;
289 event_handle->accum_clocks = 0;
291 event_handle->expired_clock = event_clocks + clock;
293 insert_event(event_handle);
296 void EVENT::register_event_by_clock(DEVICE* device, int event_id, uint64_t clock, bool loop, int* register_id)
299 if(!initialize_done && !loop) {
300 this->out_debug_log(_T("EVENT: device (name=%s, id=%d) registeres non-loop event before initialize is done\n"), device->this_device_name, device->this_device_id);
305 if(first_free_event == NULL) {
307 this->out_debug_log(_T("EVENT: too many events !!!\n"));
309 if(register_id != NULL) {
314 event_t *event_handle = first_free_event;
315 first_free_event = first_free_event->next;
317 if(register_id != NULL) {
318 *register_id = event_handle->index;
320 event_handle->active = true;
321 event_handle->device = device;
322 event_handle->event_id = event_id;
323 event_handle->expired_clock = event_clocks + clock;
324 event_handle->loop_clock = loop ? (clock << 10) : 0;
325 event_handle->accum_clocks = 0;
327 insert_event(event_handle);
330 void EVENT::insert_event(event_t *event_handle)
332 if(first_fire_event == NULL) {
333 first_fire_event = event_handle;
334 event_handle->prev = event_handle->next = NULL;
336 for(event_t *insert_pos = first_fire_event; insert_pos != NULL; insert_pos = insert_pos->next) {
337 if(insert_pos->expired_clock > event_handle->expired_clock) {
338 if(insert_pos->prev != NULL) {
340 insert_pos->prev->next = event_handle;
341 event_handle->prev = insert_pos->prev;
342 event_handle->next = insert_pos;
343 insert_pos->prev = event_handle;
347 first_fire_event = event_handle;
348 event_handle->prev = NULL;
349 event_handle->next = insert_pos;
350 insert_pos->prev = event_handle;
353 } else if(insert_pos->next == NULL) {
355 insert_pos->next = event_handle;
356 event_handle->prev = insert_pos;
357 event_handle->next = NULL;
364 void EVENT::cancel_event(DEVICE* device, int register_id)
366 // cancel registered event
367 if(0 <= register_id && register_id < MAX_EVENT) {
368 event_t *event_handle = &event[register_id];
369 if(device != NULL && device != event_handle->device) {
370 this->out_debug_log(_T("EVENT: device (name=%s, id=%d) tries to cancel event that is not its own !!!\n"), device->this_device_name, device->this_device_id);
373 if(event_handle->active) {
374 if(event_handle->prev != NULL) {
375 event_handle->prev->next = event_handle->next;
377 first_fire_event = event_handle->next;
379 if(event_handle->next != NULL) {
380 event_handle->next->prev = event_handle->prev;
382 event_handle->active = false;
383 event_handle->next = first_free_event;
384 first_free_event = event_handle;
389 void EVENT::register_frame_event(DEVICE* device)
391 if(frame_event_count < MAX_EVENT) {
392 for(int i = 0; i < frame_event_count; i++) {
393 if(frame_event[i] == device) {
395 this->out_debug_log(_T("EVENT: device (name=%s, id=%d) has already registered frame event !!!\n"), device->this_device_name, device->this_device_id);
400 frame_event[frame_event_count++] = device;
403 this->out_debug_log(_T("EVENT: too many frame events !!!\n"));
408 void EVENT::register_vline_event(DEVICE* device)
410 if(vline_event_count < MAX_EVENT) {
411 for(int i = 0; i < vline_event_count; i++) {
412 if (vline_event[i] == device) {
414 this->out_debug_log(_T("EVENT: device (name=%s, id=%d) has already registered vline event !!!\n"), device->this_device_name, device->this_device_id);
419 vline_event[vline_event_count++] = device;
422 this->out_debug_log(_T("EVENT: too many vline events !!!\n"));
427 uint32_t EVENT::get_event_remaining_clock(int register_id)
429 if(0 <= register_id && register_id < MAX_EVENT) {
430 event_t *event_handle = &event[register_id];
431 if(event_handle->active && event->expired_clock > event_clocks) {
432 return (uint32_t)(event->expired_clock - event_clocks);
438 double EVENT::get_event_remaining_usec(int register_id)
440 return 1000000.0 * get_event_remaining_clock(register_id) / d_cpu[0].cpu_clocks;
443 void EVENT::touch_sound()
445 if(!(config.sound_strict_rendering || (need_mix > 0))) {
446 int samples = mix_counter;
447 if(samples >= (sound_tmp_samples - buffer_ptr)) {
448 samples = sound_tmp_samples - buffer_ptr;
452 mix_counter -= samples;
457 void EVENT::set_realtime_render(DEVICE* device, bool flag)
459 assert(device != NULL && device->this_device_id < MAX_DEVICE);
460 if(dev_need_mix[device->this_device_id] != flag) {
464 assert(need_mix > 0);
466 if(need_mix < 0) need_mix = 0;
468 dev_need_mix[device->this_device_id] = flag;
472 void EVENT::event_callback(int event_id, int err)
475 if(prev_skip && dont_skip_frames == 0 && !sound_changed) {
478 int remain = sound_tmp_samples - buffer_ptr;
481 int samples = mix_counter;
483 if(config.sound_strict_rendering || (need_mix > 0)) {
488 if(samples >= remain) {
491 if(config.sound_strict_rendering || (need_mix > 0)) {
497 if(samples > 0 && mix_counter >= mix_limit) {
499 mix_counter -= samples;
506 void EVENT::mix_sound(int samples)
509 int32_t* buffer = sound_tmp + buffer_ptr * 2;
510 memset(buffer, 0, samples * sizeof(int32_t) * 2);
511 for(int i = 0; i < dcount_sound; i++) {
512 d_sound[i]->mix(buffer, samples);
515 for(int i = 0; i < samples * 2; i += 2) {
516 if(buffer[i] != sound_tmp[0] || buffer[i + 1] != sound_tmp[1]) {
517 sound_changed = true;
522 buffer_ptr += samples;
524 // notify to sound devices
525 for(int i = 0; i < dcount_sound; i++) {
526 d_sound[i]->mix(sound_tmp + buffer_ptr * 2, 0);
531 uint16_t* EVENT::create_sound(int* extra_frames)
533 if(prev_skip && dont_skip_frames == 0 && !sound_changed) {
534 memset(sound_buffer, 0, sound_samples * sizeof(uint16_t) * 2);
540 // drive extra frames to fill the sound buffer
541 while(sound_samples > buffer_ptr) {
545 #ifdef LOW_PASS_FILTER
547 for(int i = 0; i < sound_samples - 1; i++) {
548 sound_tmp[i * 2 ] = (sound_tmp[i * 2 ] + sound_tmp[i * 2 + 2]) / 2; // L
549 sound_tmp[i * 2 + 1] = (sound_tmp[i * 2 + 1] + sound_tmp[i * 2 + 3]) / 2; // R
553 for(int i = 0; i < sound_samples * 2; i++) {
554 int dat = sound_tmp[i];
555 uint16_t highlow = (uint16_t)(dat & 0x0000ffff);
557 if((dat > 0) && (highlow >= 0x8000)) {
558 sound_buffer[i] = 0x7fff;
561 if((dat < 0) && (highlow < 0x8000)) {
562 sound_buffer[i] = 0x8000;
565 sound_buffer[i] = highlow;
567 if(buffer_ptr > sound_samples) {
568 buffer_ptr -= sound_samples;
569 memcpy(sound_tmp, sound_tmp + sound_samples * 2, buffer_ptr * sizeof(int32_t) * 2);
573 *extra_frames = frames;
577 int EVENT::get_sound_buffer_ptr()
582 void EVENT::request_skip_frames()
587 bool EVENT::is_frame_skippable()
589 bool value = next_skip;
591 if(sound_changed || (prev_skip && !next_skip)) {
592 dont_skip_frames = (int)frames_per_sec;
594 if(dont_skip_frames > 0) {
598 prev_skip = next_skip;
600 sound_changed = false;
605 void EVENT::update_config()
607 if(power != config.cpu_power) {
608 power = config.cpu_power;
613 #define STATE_VERSION 3
615 void EVENT::save_state(FILEIO* state_fio)
617 state_fio->FputUint32(STATE_VERSION);
618 state_fio->FputInt32(this_device_id);
620 state_fio->FputInt32(dcount_cpu);
621 for(int i = 0; i < dcount_cpu; i++) {
622 state_fio->FputUint32(d_cpu[i].cpu_clocks);
623 state_fio->FputUint32(d_cpu[i].update_clocks);
624 state_fio->FputUint32(d_cpu[i].accum_clocks);
626 state_fio->Fwrite(vclocks, sizeof(vclocks), 1);
627 state_fio->FputInt32(event_remain);
628 state_fio->FputInt32(cpu_remain);
629 state_fio->FputInt32(cpu_accum);
630 state_fio->FputInt32(cpu_done);
631 state_fio->FputUint64(event_clocks);
632 for(int i = 0; i < MAX_EVENT; i++) {
633 state_fio->FputInt32(event[i].device != NULL ? event[i].device->this_device_id : -1);
634 state_fio->FputInt32(event[i].event_id);
635 state_fio->FputUint64(event[i].expired_clock);
636 state_fio->FputUint64(event[i].loop_clock);
637 state_fio->FputUint64(event[i].accum_clocks);
638 state_fio->FputBool(event[i].active);
639 state_fio->FputInt32(event[i].next != NULL ? event[i].next->index : -1);
640 state_fio->FputInt32(event[i].prev != NULL ? event[i].prev->index : -1);
642 state_fio->FputInt32(first_free_event != NULL ? first_free_event->index : -1);
643 state_fio->FputInt32(first_fire_event != NULL ? first_fire_event->index : -1);
644 state_fio->FputDouble(frames_per_sec);
645 state_fio->FputDouble(next_frames_per_sec);
646 state_fio->FputInt32(lines_per_frame);
647 state_fio->FputInt32(next_lines_per_frame);
648 state_fio->Fwrite(dev_need_mix, sizeof(dev_need_mix), 1);
649 state_fio->FputInt32(need_mix);
652 bool EVENT::load_state(FILEIO* state_fio)
654 if(state_fio->FgetUint32() != STATE_VERSION) {
657 if(state_fio->FgetInt32() != this_device_id) {
660 if(state_fio->FgetInt32() != dcount_cpu) {
663 for(int i = 0; i < dcount_cpu; i++) {
664 d_cpu[i].cpu_clocks = state_fio->FgetUint32();
665 d_cpu[i].update_clocks = state_fio->FgetUint32();
666 d_cpu[i].accum_clocks = state_fio->FgetUint32();
668 state_fio->Fread(vclocks, sizeof(vclocks), 1);
669 event_remain = state_fio->FgetInt32();
670 cpu_remain = state_fio->FgetInt32();
671 cpu_accum = state_fio->FgetInt32();
672 cpu_done = state_fio->FgetInt32();
673 event_clocks = state_fio->FgetUint64();
674 for(int i = 0; i < MAX_EVENT; i++) {
675 event[i].device = vm->get_device(state_fio->FgetInt32());
676 event[i].event_id = state_fio->FgetInt32();
677 event[i].expired_clock = state_fio->FgetUint64();
678 event[i].loop_clock = state_fio->FgetUint64();
679 event[i].accum_clocks = state_fio->FgetUint64();
680 event[i].active = state_fio->FgetBool();
681 event[i].next = (event_t *)get_event(state_fio->FgetInt32());
682 event[i].prev = (event_t *)get_event(state_fio->FgetInt32());
684 first_free_event = (event_t *)get_event(state_fio->FgetInt32());
685 first_fire_event = (event_t *)get_event(state_fio->FgetInt32());
686 frames_per_sec = state_fio->FgetDouble();
687 next_frames_per_sec = state_fio->FgetDouble();
688 lines_per_frame = state_fio->FgetInt32();
689 next_lines_per_frame = state_fio->FgetInt32();
690 state_fio->Fread(dev_need_mix, sizeof(dev_need_mix), 1);
691 need_mix = state_fio->FgetInt32();
695 memset(sound_buffer, 0, sound_samples * sizeof(uint16_t) * 2);
698 memset(sound_tmp, 0, sound_tmp_samples * sizeof(int32_t) * 2);
702 mix_limit = (int)((double)(emu->get_sound_rate() / 2000.0)); // per 0.5ms.
706 void* EVENT::get_event(int index)
708 if(index >= 0 && index < MAX_EVENT) {
709 return &event[index];