Spinner controlに対応したyaCOLECOVISIONできました。TURBOで遊べます。
http://atariage.com/forums/topic/196556-spinner-control-hook-up/
FAQ
Q1.COLECOVISIONって何?
A1.Enriさんのサイトで確認ください。
http://www43.tok2.com/home/cmpslv/Coleco/EnrCol.htm
Q2.どこで手に入るの?
A2.国内ではSAMMLERさんで購入できます。
Q3.エミュレータはすでにあるのでは?
A3.はい、blueMSXがとても良いです。yaCOLECOVISIONではハンドルコントローラーに対応してSEGA TURBOで遊ぶのがゴールです。
http://bluemsx.msxblue.com/jindex.htm
resource.h
// COLECO COLECOVISION #ifdef _COLECO #define MENU_POS_CONTROL 0 #define MENU_POS_CART1 1 #define MENU_POS_SCREEN 2 #define MENU_POS_SOUND 3 #define MENU_POS_INPUT 4 #endif
vm.h
// COLECO COLECOVISION #ifdef _COLECO #include "coleco/coleco.h" #endif
coleco.h
/* COLECO COLECOVISION Emulator 'yaCOLECOVISION' Author : tanam Date : 2016.08.14- [ virtual machine ] */ #ifndef _COLECO_H_ #define _COLECO_H_ #define DEVICE_NAME "COLECO COLECOVISION" #define CONFIG_NAME "coleco" // device informations for virtual machine #define FRAMES_PER_SEC 60 #define LINES_PER_FRAME 262 #define CPU_CLOCKS 3579545 #define SCREEN_WIDTH 256 #define SCREEN_HEIGHT 192 #define TMS9918A_VRAM_SIZE 0x4000 #define TMS9918A_LIMIT_SPRITES // device informations for win32 #define USE_CART1 #define USE_SOUND_VOLUME 2 #define USE_JOYSTICK #define USE_DEBUGGER #define USE_STATE #include "../../common.h" #include "../../fileio.h" #ifdef USE_SOUND_VOLUME static const _TCHAR *sound_device_caption[] = { _T("PSG"), }; #endif class EMU; class DEVICE; class EVENT; class IO; class SN76489AN; class TMS9918A; class Z80; class KEYBOARD; class MEMORY; class VM { protected: EMU* emu; // devices EVENT* event; IO* io; SN76489AN* psg; TMS9918A* vdp; Z80* cpu; KEYBOARD* key; MEMORY* memory; public: // ---------------------------------------- // initialize // ---------------------------------------- VM(EMU* parent_emu); ~VM(); // ---------------------------------------- // for emulation class // ---------------------------------------- // drive virtual machine void reset(); void run(); #ifdef USE_DEBUGGER // debugger DEVICE *get_cpu(int index); #endif // draw screen void draw_screen(); // sound generation void initialize_sound(int rate, int samples); uint16_t* create_sound(int* extra_frames); int get_sound_buffer_ptr(); #ifdef USE_SOUND_VOLUME void set_sound_device_volume(int ch, int decibel_l, int decibel_r); #endif // user interface void open_cart(int drv, const _TCHAR* file_path); void close_cart(int drv); bool is_cart_inserted(int drv); bool is_frame_skippable(); void update_config(); void save_state(FILEIO* state_fio); bool load_state(FILEIO* state_fio); // ---------------------------------------- // for each device // ---------------------------------------- // devices DEVICE* get_device(int id); DEVICE* dummy; DEVICE* first_device; DEVICE* last_device; }; #endif
coleco.cpp
/* COLECO COLECOVISION Emulator 'yaCOLECOVISION' Author : tanam Date : 2016.08.14- [ virtual machine ] */ #include "coleco.h" #include "../../emu.h" #include "../device.h" #include "../event.h" #include "../io.h" #include "../sn76489an.h" #include "../tms9918a.h" #include "../z80.h" #ifdef USE_DEBUGGER #include "../debugger.h" #endif #include "keyboard.h" #include "memory.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 io = new IO(this, emu); psg = new SN76489AN(this, emu); vdp = new TMS9918A(this, emu); cpu = new Z80(this, emu); key = new KEYBOARD(this, emu); memory = new MEMORY(this, emu); // set contexts event->set_context_cpu(cpu); event->set_context_sound(psg); vdp->set_context_irq(cpu, SIG_CPU_NMI, 1); key->set_context_cpu(cpu); // cpu bus cpu->set_context_mem(memory); cpu->set_context_io(io); cpu->set_context_intr(dummy); #ifdef USE_DEBUGGER cpu->set_context_debugger(new DEBUGGER(this, emu)); #endif // i/o bus io->set_iomap_range_w(0x80, 0x9f, key); io->set_iomap_range_rw(0xbe, 0xbf, vdp); io->set_iomap_range_w(0xc0, 0xdf, key); io->set_iomap_range_r(0xfc, 0xff, key); io->set_iomap_range_w(0xff, 0xff, psg); // initialize all devices for(DEVICE* device = first_device; device; device = device->next_device) { device->initialize(); } } 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; } // ---------------------------------------------------------------------------- // debugger // ---------------------------------------------------------------------------- #ifdef USE_DEBUGGER DEVICE *VM::get_cpu(int index) { if(index == 0) { return cpu; } return NULL; } #endif // ---------------------------------------------------------------------------- // 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(); } // ---------------------------------------------------------------------------- // soud manager // ---------------------------------------------------------------------------- void VM::initialize_sound(int rate, int samples) { // init sound manager event->initialize_sound(rate, samples); // init sound gen psg->initialize_sound(rate, 3579545, 8000); } uint16_t* VM::create_sound(int* extra_frames) { return event->create_sound(extra_frames); } int VM::get_sound_buffer_ptr() { return event->get_sound_buffer_ptr(); } #ifdef USE_SOUND_VOLUME void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r) { if(ch == 0) { psg->set_volume(0, decibel_l, decibel_r); } } #endif // ---------------------------------------------------------------------------- // user interface // ---------------------------------------------------------------------------- void VM::open_cart(int drv, const _TCHAR* file_path) { if(drv == 0) { memory->open_cart(file_path); reset(); } } void VM::close_cart(int drv) { if(drv == 0) { memory->close_cart(); reset(); } } bool VM::is_cart_inserted(int drv) { if(drv == 0) { return memory->is_cart_inserted(); } else { return false; } } bool VM::is_frame_skippable() { return event->is_frame_skippable(); } void VM::update_config() { for(DEVICE* device = first_device; device; device = device->next_device) { device->update_config(); } } #define STATE_VERSION 1 void VM::save_state(FILEIO* state_fio) { state_fio->FputUint32(STATE_VERSION); for(DEVICE* device = first_device; device; device = device->next_device) { device->save_state(state_fio); } } bool VM::load_state(FILEIO* state_fio) { if(state_fio->FgetUint32() != STATE_VERSION) { return false; } for(DEVICE* device = first_device; device; device = device->next_device) { if(!device->load_state(state_fio)) { return false; } } return true; }
memory.h
/* COLECO COLECOVISION Emulator 'yaCOLECOVISION' Author : tanam Date : 2016.08.14- [ memory ] */ #ifndef _MEMORY_H_ #define _MEMORY_H_ #include "../vm.h" #include "../../emu.h" #include "../device.h" class MEMORY : public DEVICE { private: // memory uint8_t cart[0x8000]; uint8_t ipl[0x2000]; uint8_t ram[0x10000]; uint8_t wdmy[0x10000]; uint8_t rdmy[0x10000]; uint8_t* wbank[16]; uint8_t* rbank[16]; bool inserted; public: MEMORY(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) {} ~MEMORY() {} // common functions void initialize(); void write_data8(uint32_t addr, uint32_t data); uint32_t read_data8(uint32_t addr); void save_state(FILEIO* state_fio); bool load_state(FILEIO* state_fio); // unique functions void open_cart(const _TCHAR* file_path); void close_cart(); bool is_cart_inserted() { return inserted; } }; #endif
memory.cpp
/* COLECO COLECOVISION Emulator 'yaCOLECOVISION' Author : tanam Date : 2016.08.14- [ memory ] */ #include "memory.h" #define SET_BANK(s, e, w, r) { \ int sb = (s) >> 12, eb = (e) >> 12; \ for(int i = sb; i <= eb; i++) { \ if((w) == wdmy) { \ wbank[i] = wdmy; \ } else { \ wbank[i] = (w) + 0x1000 * (i - sb); \ } \ if((r) == rdmy) { \ rbank[i] = rdmy; \ } else { \ rbank[i] = (r) + 0x1000 * (i - sb); \ } \ } \ } void MEMORY::initialize() { memset(cart, 0xff, sizeof(cart)); memset(ipl, 0xff, sizeof(ipl)); memset(ram, 0, sizeof(ram)); memset(rdmy, 0xff, sizeof(rdmy)); // load ipl FILEIO* fio = new FILEIO(); if(fio->Fopen(create_local_path(_T("COLECO.ROM")), FILEIO_READ_BINARY)) { fio->Fread(ipl, sizeof(ipl), 1); fio->Fclose(); } delete fio; // set memory map SET_BANK(0x0000, 0x1fff, wdmy, ipl); SET_BANK(0x2000, 0x5fff, wdmy, rdmy); SET_BANK(0x6000, 0x7fff, ram, ram); SET_BANK(0x8000, 0xffff, wdmy, cart); inserted = false; } void MEMORY::write_data8(uint32_t addr, uint32_t data) { addr &= 0xffff; wbank[addr >> 12][addr & 0xfff] = data; } uint32_t MEMORY::read_data8(uint32_t addr) { addr &= 0xffff; return rbank[addr >> 12][addr & 0xfff]; } void MEMORY::open_cart(const _TCHAR* file_path) { FILEIO* fio = new FILEIO(); if(fio->Fopen(file_path, FILEIO_READ_BINARY)) { memset(cart, 0xff, sizeof(cart)); fio->Fread(cart, sizeof(cart), 1); fio->Fclose(); inserted = true; // set memory map SET_BANK(0x8000, 0xffff, wdmy, cart); } delete fio; } void MEMORY::close_cart() { memset(cart, 0xff, sizeof(cart)); inserted = false; // set memory map SET_BANK(0x0000, 0x1fff, wdmy, ipl); SET_BANK(0x2000, 0x5fff, wdmy, rdmy); SET_BANK(0x6000, 0x7fff, ram, ram); SET_BANK(0x8000, 0xffff, wdmy, cart); } #define STATE_VERSION 1 void MEMORY::save_state(FILEIO* state_fio) { state_fio->FputUint32(STATE_VERSION); state_fio->FputInt32(this_device_id); state_fio->Fwrite(ram, sizeof(ram), 1); state_fio->FputBool(inserted); } bool MEMORY::load_state(FILEIO* state_fio) { if(state_fio->FgetUint32() != STATE_VERSION) { return false; } if(state_fio->FgetInt32() != this_device_id) { return false; } state_fio->Fread(ram, sizeof(ram), 1); inserted = state_fio->FgetBool(); // post process if(inserted) { SET_BANK(0x8000, 0xffff, wdmy, cart); } else { SET_BANK(0x0000, 0x1fff, wdmy, ipl); SET_BANK(0x2000, 0x5fff, wdmy, rdmy); SET_BANK(0x6000, 0x7fff, ram, ram); SET_BANK(0x8000, 0xffff, wdmy, cart); } return true; }
keyboard.h
/* COLECO COLECOVISION Emulator 'yaCOLECOVISION' Author : tanam Date : 2016.08.14- [ keyboard ] */ #ifndef _KEYBOARD_H_ #define _KEYBOARD_H_ #include "../vm.h" #include "../../emu.h" #include "../device.h" class KEYBOARD : public DEVICE { private: DEVICE *d_cpu; const uint8_t* key_stat; const uint32_t* joy_stat; bool tenkey; public: KEYBOARD(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) {} ~KEYBOARD() {} // common functions void initialize(); void event_frame(); uint32_t read_io8(uint32_t addr); void write_io8(uint32_t addr, uint32_t data); void save_state(FILEIO* state_fio); bool load_state(FILEIO* state_fio); // unique functions void set_context_cpu(DEVICE* device) { d_cpu = device; } }; #endif
keyboard.cpp
/* COLECO COLECOVISION Emulator 'yaCOLECOVISION' Author : tanam Date : 2016.08.14- [ keyboard ] */ #include "keyboard.h" void KEYBOARD::initialize() { key_stat = emu->get_key_buffer(); joy_stat = emu->get_joy_buffer(); // register event to update the key status register_frame_event(this); } void KEYBOARD::event_frame() { if (joy_stat[0] & 0x04 || joy_stat[0] & 0x08) { d_cpu->write_signal(SIG_CPU_IRQ, 1, 1); } } void KEYBOARD::write_io8(uint32_t addr, uint32_t data) { if ((addr & 0x000000ff)==0x80) { tenkey=true; } if ((addr & 0x000000ff)==0xc0) { tenkey=false; } return; } uint32_t KEYBOARD::read_io8(uint32_t addr) { // Controller 1 if ((addr & 0x000000ff)==0xfc) { uint8_t button=0xf0; if (joy_stat[0] & 0x10) button=0xb0; // F2 if (!tenkey) { uint32_t joystick=0xff; if (joy_stat[0] & 0x01) joystick &= 0xfe; // U if (joy_stat[0] & 0x02) joystick &= 0xfb; // D if (joy_stat[0] & 0x04) { joystick &= 0x67; // L } if (joy_stat[0] & 0x08) { joystick &= 0x4d; // R } if (joy_stat[0] & 0x20) joystick &= 0xbf; // F1 return joystick; } if (key_stat[0x31] & 0x80) return (button | 0x0d); // 1 if (key_stat[0x32] & 0x80) return (button | 0x07); // 2 if (key_stat[0x33] & 0x80) return (button | 0x0c); // 3 if (key_stat[0x34] & 0x80) return (button | 0x02); // 4 if (key_stat[0x35] & 0x80) return (button | 0x03); // 5 if (key_stat[0x36] & 0x80) return (button | 0x0e); // 6 if (key_stat[0x37] & 0x80) return (button | 0x05); // 7 if (key_stat[0x38] & 0x80) return (button | 0x01); // 8 if (key_stat[0x39] & 0x80) return (button | 0x0b); // 9 if (key_stat[0x30] & 0x80) return (button | 0x0a); // 0 if (key_stat[0xbd] & 0x80) return (button | 0x09); // * '-' if (key_stat[0xde] & 0x80) return (button | 0x06); // # '^' if (key_stat[0x43] & 0x80) return (button | 0x08); // F3 'c' if (key_stat[0x56] & 0x80) return (button | 0x04); // F4 'v' return (button | 0x0f); } // Controller 2 if ((addr & 0x000000ff)==0xff) { uint8_t button=0xf0; if (joy_stat[1] & 0x10) button=0xb0; // F2 if (!tenkey) { uint32_t joystick=0xff; if (joy_stat[1] & 0x01) joystick &= 0xfe; // U if (joy_stat[1] & 0x02) joystick &= 0xfb; // D if (joy_stat[1] & 0x04) joystick &= 0xf7; // L if (joy_stat[1] & 0x08) joystick &= 0xfd; // R if (joy_stat[1] & 0x20) joystick &= 0xbf; // F1 return joystick; } if (key_stat[0x51] & 0x80) return (button | 0x0d); // 1 'q' if (key_stat[0x57] & 0x80) return (button | 0x07); // 2 'w' if (key_stat[0x45] & 0x80) return (button | 0x0c); // 3 'e' if (key_stat[0x52] & 0x80) return (button | 0x02); // 4 'r' if (key_stat[0x54] & 0x80) return (button | 0x03); // 5 't' if (key_stat[0x59] & 0x80) return (button | 0x0e); // 6 'y' if (key_stat[0x55] & 0x80) return (button | 0x05); // 7 'u' if (key_stat[0x49] & 0x80) return (button | 0x01); // 8 'i' if (key_stat[0x4f] & 0x80) return (button | 0x0b); // 9 'o' if (key_stat[0x50] & 0x80) return (button | 0x0a); // 0 'p' if (key_stat[0xc0] & 0x80) return (button | 0x09); // * '@' if (key_stat[0xdb] & 0x80) return (button | 0x06); // # '[' if (key_stat[0xbc] & 0x80) return (button | 0x08); // F3 ',' if (key_stat[0xbe] & 0x80) return (button | 0x04); // F4 '.' return (button | 0x0f); } return 0x0ff; } #define STATE_VERSION 1 void KEYBOARD::save_state(FILEIO* state_fio) { state_fio->FputUint32(STATE_VERSION); state_fio->FputInt32(this_device_id); } bool KEYBOARD::load_state(FILEIO* state_fio) { if(state_fio->FgetUint32() != STATE_VERSION) { return false; } if(state_fio->FgetInt32() != this_device_id) { return false; } return true; }