とりあえず簡単なラッパークラスを書いただけですが、YM2413を移植しました。VDPの違いによる色化けもお楽しみください。
http://www.geocities.jp/parallel_computer_inc/android.html
ym2413.h
/* Skelton for retropc emulator Author : Takeo.Namiki Date : 2013.10.26- [ YM2413 ] */ #ifndef _YM2413_H_ #define _YM2413_H_ #include "vm.h" #include "../emu.h" #include "device.h" typedef INT16 SAMP; typedef void (*OPLL_UPDATEHANDLER)(int param,int min_interval_us); void YM2413SetUpdateHandler(int which, OPLL_UPDATEHANDLER UpdateHandler, int param); class YM2413 : public DEVICE { private: uint8 latch; uint8 reg[0x40]; bool mute; public: YM2413(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) {} ~YM2413() {} // common functions void initialize(); void release(); void reset(); void write_io8(uint32 addr, uint32 data); uint32 read_io8(uint32 addr); void mix(int32* buffer, int cnt); // unique functions void init(int rate, int clock, int samples); }; #endif
ym2413.c
/* ** ** File: ym2413.c - software implementation of YM2413 ** FM sound generator type OPLL ** ** Copyright (C) 2002 Jarek Burczynski ** ** Version 1.0 ** to do: - make sure of the sinus amplitude bits - make sure of the EG resolution bits (looks like the biggest modulation index generated by the modulator is 123, 124 = no modulation) - find proper algorithm for attack phase of EG - tune up instruments ROM - support sample replay in test mode (it is NOT as simple as setting bit 0 in register 0x0f and using register 0x10 for sample data). Which games use this feature ? */ #include "ym2413.h" #define MAME_INLINE static #define logerror(...) #ifndef PI #define PI 3.14159265358979323846 #endif (中略) /* Skelton for retropc emulator Author : Takeo.Namiki Date : 2013.10.26- [ YM2413 ] */ void YM2413::initialize() { mute = false; } void YM2413::release() { YM2413Shutdown(); } void YM2413::reset() { YM2413ResetChip(0); } void YM2413::write_io8(uint32 addr, uint32 data) { if (addr & 1) { reg[ latch & 0x3F] = data; latch = data; } else { latch = data; } YM2413Write(0, addr & 1, data); } uint32 YM2413::read_io8(uint32 addr) { return latch; } void YM2413::mix(int32* buffer, int cnt) { if(mute) { return; } INT16 *buf[2]; buf[0]=(INT16 *)malloc(sizeof(INT16) * cnt); buf[1]=(INT16 *)malloc(sizeof(INT16) * cnt); if(cnt > 0) YM2413UpdateOne(0, buf, cnt); for(int i = 0; i < cnt; i++) { int32 vol1 = 0; int32 vol2 = 0; vol1 += buf[0][i]; vol2 += buf[1][i]; *buffer++ += vol1<<2; // L *buffer++ += vol2<<2; // R } free(buf[0]); free(buf[1]); } void YM2413::init(int rate, int clock, int samples) { YM2413Init(1, clock, rate); YM2413ResetChip(0); }
mastersystem.cpp
/* SEGA MASTER SYSTEM Emulator 'yaMASTER SYSTEM' Author : tanam Date : 2013.10.20- [ virtual machine ] */ #include "mastersystem.h" #include "../../emu.h" #include "../device.h" #include "../event.h" ///#include "../datarec.h" ///#include "../disk.h" ///#include "../i8251.h" #include "../i8255.h" #include "../io.h" #include "../ym2413.h" #include "../sn76489an.h" #include "../315-5124.h" ///#include "../upd765a.h" #include "../z80.h" #include "keyboard.h" #include "memory.h" #include "system.h" // ---------------------------------------------------------------------------- // initialize // ---------------------------------------------------------------------------- VM::VM(EMU* parent_emu) : emu(parent_emu) { // create devices first_device = last_device = NULL; dummy = new DEVICE(this, emu); // must be 1st device event = new EVENT(this, emu); // must be 2nd device /// drec = new DATAREC(this, emu); /// sio = new I8251(this, emu); pio_k = new I8255(this, emu); pio_f = new I8255(this, emu); io = new IO(this, emu); psg = new SN76489AN(this, emu); fm = new YM2413(this, emu); vdp = new _315_5124(this, emu); /// fdc = new UPD765A(this, emu); cpu = new Z80(this, emu); key = new KEYBOARD(this, emu); memory = new MEMORY(this, emu); system = new SYSTEM(this, emu); // set contexts event->set_context_cpu(cpu); event->set_context_sound(psg); event->set_context_sound(fm); /// drec->set_context_out(pio_k, SIG_I8255_PORT_B, 0x80); pio_k->set_context_port_c(key, SIG_KEYBOARD_COLUMN, 0x07, 0); /// pio_k->set_context_port_c(drec, SIG_DATAREC_REMOTE, 0x08, 0); /// pio_k->set_context_port_c(drec, SIG_DATAREC_OUT, 0x10, 0); /// pio_f->set_context_port_c(fdc, SIG_UPD765A_MOTOR_NEG, 2, 0); /// pio_f->set_context_port_c(fdc, SIG_UPD765A_TC, 4, 0); /// pio_f->set_context_port_c(fdc, SIG_UPD765A_RESET, 8, 0); pio_f->set_context_port_c(memory, SIG_MEMORY_SEL, 0x40, 0); vdp->set_context_irq(cpu, SIG_CPU_IRQ, 1); /// fdc->set_context_irq(pio_f, SIG_I8255_PORT_A, 1); /// fdc->set_context_index(pio_f, SIG_I8255_PORT_A, 4); key->set_context_cpu(cpu); key->set_context_pio(pio_k); system->set_context_key(key); /// vdp->set_context_cpu(cpu); vdp->set_context_key(key); vdp->set_context_psg(psg); // cpu bus cpu->set_context_mem(memory); cpu->set_context_io(io); cpu->set_context_intr(system); // i/o bus io->set_iomap_single_r(0x00, system); // GG START io->set_iomap_single_w(0x80, system); // COL TENKEY io->set_iomap_single_w(0xc0, system); // COL JOYPAD io->set_iomap_range_rw(0xfc, 0xfe, system); // COL JOYPAD io->set_iomap_range_rw(0xff, 0xff, psg); // COL PSG io->set_iomap_range_rw(0x7e, 0x7f, vdp); // SG VDP io->set_iomap_range_rw(0xbe, 0xbf, vdp); // SG VDP io->set_iomap_range_rw(0xdc, 0xdf, pio_k); // SG KEY /// io->set_iomap_range_rw(0xe0, 0xe3, fdc); // SG FDD /// io->set_iomap_range_rw(0xe4, 0xe7, pio_f); // SG FDD /// io->set_iomap_range_rw(0xe8, 0xe9, sio); // SG SERIAL io->set_iomap_range_rw(0xf0, 0xf2, fm); // MS FM // initialize all devices for(DEVICE* device = first_device; device; device = device->next_device) { device->initialize(); } // BIOS memory->bios(); /// for(int i = 0; i < 4; i++) { /// fdc->set_drive_type(i, DRIVE_TYPE_2D); /// } } VM::~VM() { // delete all devices for(DEVICE* device = first_device; device;) { DEVICE *next_device = device->next_device; device->release(); delete device; device = next_device; } } DEVICE* VM::get_device(int id) { for(DEVICE* device = first_device; device; device = device->next_device) { if(device->this_device_id == id) { return device; } } return NULL; } // ---------------------------------------------------------------------------- // drive virtual machine // ---------------------------------------------------------------------------- void VM::reset() { // reset all devices for(DEVICE* device = first_device; device; device = device->next_device) { device->reset(); } } void VM::run() { event->drive(); } // ---------------------------------------------------------------------------- // draw screen // ---------------------------------------------------------------------------- void VM::draw_screen() { vdp->draw_screen(); } ///int VM::access_lamp() ///{ /// uint32 status = fdc->read_signal(0); /// return (status & (1 | 4)) ? 1 : (status & (2 | 8)) ? 2 : 0; ///} // ---------------------------------------------------------------------------- // soud manager // ---------------------------------------------------------------------------- void VM::initialize_sound(int rate, int samples) { // init sound manager event->initialize_sound(rate, samples); // init sound gen psg->init(rate, 3579545, 4000); fm->init(rate, 3579545, samples); } uint16* VM::create_sound(int* extra_frames) { return event->create_sound(extra_frames); } int VM::sound_buffer_ptr() { return event->sound_buffer_ptr(); } // ---------------------------------------------------------------------------- // user interface // ---------------------------------------------------------------------------- void VM::open_cart(int drv, _TCHAR* file_path) { if(drv == 0) { memory->open_cart(file_path); if (strstr(file_path, ".col") || strstr(file_path, ".COL")) { vdp->set_console(0x00); memory->bios(); } else { if (strstr(file_path, ".gg") || strstr(file_path, ".GG")) vdp->set_console(0x40); else vdp->set_console(0x20); } reset(); } } void VM::close_cart(int drv) { if(drv == 0) { memory->close_cart(); reset(); } } bool VM::cart_inserted(int drv) { if(drv == 0) { return memory->cart_inserted(); } else { return false; } } ///void VM::open_disk(int drv, _TCHAR* file_path, int offset) ///{ /// fdc->open_disk(drv, file_path, offset); ///} ///void VM::close_disk(int drv) ///{ /// fdc->close_disk(drv); ///} ///bool VM::disk_inserted(int drv) ///{ /// return fdc->disk_inserted(drv); ///} ///void VM::play_tape(_TCHAR* file_path) ///{ /// drec->play_tape(file_path); ///} ///void VM::rec_tape(_TCHAR* file_path) ///{ /// drec->rec_tape(file_path); ///} ///void VM::close_tape() ///{ /// drec->close_tape(); ///} ///bool VM::tape_inserted() ///{ /// return drec->tape_inserted(); ///} bool VM::now_skip() { return event->now_skip(); } void VM::update_config() { for(DEVICE* device = first_device; device; device = device->next_device) { device->update_config(); } }