世にも珍しいVCSじゃない方のTV BOYエミュレータです。
ソースコード差分は以下になります。
vm.h
// GAKKEN TV BOY #ifdef _TVBOY #include "tvboy/tvboy.h" #endif
tvboy.h
/* GAKKEN TV BOY Emulator 'yaTVBOY' Author : tanam Date : 2020.06.13 [ virtual machine ] */ #ifndef _TVBOY_H_ #define _TVBOY_H_ #define DEVICE_NAME "GAKKEN TV BOY" #define CONFIG_NAME "tvboy" // device informations for virtual machine #define FRAMES_PER_SEC 60 #define LINES_PER_FRAME 262 #define CPU_CLOCKS 3579545 / 4 #define SCREEN_WIDTH 256 #define SCREEN_HEIGHT 192 #define HAS_MC6801 #define MC6847_VRAM_INV 0x40 // device informations for win32 #define USE_CART 1 #define USE_SOUND_VOLUME 2 #define USE_DEBUGGER #define USE_STATE #include "../../common.h" #include "../../fileio.h" #include "../vm_template.h" #ifdef USE_SOUND_VOLUME static const _TCHAR *sound_device_caption[] = { _T("PCM"), }; #endif class EMU; class DEVICE; class EVENT; class MC6847; class MC6800; class PCM1BIT; class MEMORY; class VM : public VM_TEMPLATE { protected: // EMU* emu; // devices EVENT* event; MC6847* vdp; MC6800* cpu; PCM1BIT* pcm; MEMORY* memory; public: // ---------------------------------------- // initialize // ---------------------------------------- VM(EMU* parent_emu); ~VM(); // ---------------------------------------- // for emulation class // ---------------------------------------- // drive virtual machine void reset(); void run(); double get_frame_rate() { return FRAMES_PER_SEC; } #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); // notify key void key_down(int code, bool repeat); void key_up(int code); bool is_frame_skippable(); void update_config(); bool process_state(FILEIO* state_fio, bool loading); // ---------------------------------------- // for each device // ---------------------------------------- // devices DEVICE* get_device(int id); // DEVICE* dummy; // DEVICE* first_device; // DEVICE* last_device; }; #endif
tvboy.cpp
/* GAKKEN TV BOY Emulator 'yaTVBOY' Author : tanam Date : 2020.06.13 [ virtual machine ] */ #include "tvboy.h" #include "../../emu.h" #include "../device.h" #include "../event.h" #include "../mc6847.h" #include "../mc6800.h" #include "../pcm1bit.h" #ifdef USE_DEBUGGER #include "../debugger.h" #endif #include "memory.h" // ---------------------------------------------------------------------------- // initialize // ---------------------------------------------------------------------------- VM::VM(EMU* parent_emu) : VM_TEMPLATE(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 vdp = new MC6847(this, emu); cpu = new MC6800(this, emu); memory = new MEMORY(this, emu); memory->set_context_cpu(cpu); memory->set_context_vdp(vdp); pcm = new PCM1BIT(this, emu); cpu->set_context_port1(pcm, SIG_PCM1BIT_SIGNAL, 0x20, 0); cpu->set_context_port1(pcm, SIG_PCM1BIT_SIGNAL, 0x40, 0); cpu->set_context_port1(memory, SIG_MEMORY_PORT_1, 0x0F, 0); // set contexts event->set_context_cpu(cpu); event->set_context_sound(pcm); vdp->set_vram_ptr(memory->get_vram(), 0x800); vdp->set_context_cpu(cpu); // cpu bus cpu->set_context_mem(memory); #ifdef USE_DEBUGGER cpu->set_context_debugger(new DEBUGGER(this, emu)); #endif pcm = new PCM1BIT(this, emu); // 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; } // ---------------------------------------------------------------------------- // 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(); } // ---------------------------------------------------------------------------- // debugger // ---------------------------------------------------------------------------- #ifdef USE_DEBUGGER DEVICE *VM::get_cpu(int index) { if(index == 0) { return cpu; } return NULL; } #endif // ---------------------------------------------------------------------------- // draw screen // ---------------------------------------------------------------------------- void VM::draw_screen() { vdp->draw_screen(); } // ---------------------------------------------------------------------------- // notify key // ---------------------------------------------------------------------------- void VM::key_down(int code, bool repeat) { memory->key_down(code); } void VM::key_up(int code) { memory->key_up(code); } // ---------------------------------------------------------------------------- // soud manager // ---------------------------------------------------------------------------- void VM::initialize_sound(int rate, int samples) { // init sound manager event->initialize_sound(rate, samples); pcm->initialize_sound(rate, 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) { pcm->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 3 bool VM::process_state(FILEIO* state_fio, bool loading) { if(!state_fio->StateCheckUint32(STATE_VERSION)) { return false; } for(DEVICE* device = first_device; device; device = device->next_device) { const char *name = typeid(*device).name() + 6; // skip "class " int len = strlen(name); if(!state_fio->StateCheckInt32(len)) { return false; } if(!state_fio->StateCheckBuffer(name, len, 1)) { return false; } if(!device->process_state(state_fio, loading)) { return false; } } return true; }
memory.h
/* GAKKEN TV BOY Emulator 'yaTVBOY' Author : tanam Date : 2020.06.13 [ memory ] */ #ifndef _MEMORY_H_ #define _MEMORY_H_ #include "../vm.h" #include "../../emu.h" #include "../device.h" #include "../mc6800.h" #include "../mc6847.h" #define SIG_MEMORY_PORT_1 0 class MEMORY : public DEVICE { private: MC6800 *d_cpu; MC6847 *d_vdp; uint8_t rom[0x1000]; uint8_t ram[0x1000]; uint8_t vram[0x1000]; uint8_t wdmy[0x400]; uint8_t rdmy[0x400]; uint8_t* wbank[64]; uint8_t* rbank[64]; int shot1; int shot2; int up; int down; int left; int right; bool event; bool inserted; public: MEMORY(VM_TEMPLATE* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) { set_device_name(_T("Memory Bus")); } ~MEMORY() {} // common functions void initialize(); void reset(); void write_data8(uint32_t addr, uint32_t data); uint32_t read_data8(uint32_t addr); void write_signal(int id, uint32_t data, uint32_t mask); void event_callback(int event_id, int err); bool process_state(FILEIO* state_fio, bool loading); // unique functions void key_down(int code); void key_up(int code); void set_context_cpu(MC6800* device) { d_cpu = device; } void set_context_vdp(MC6847* device) { d_vdp = device; } void open_cart(const _TCHAR* file_path); void close_cart(); bool is_cart_inserted() { return inserted; } uint8_t* get_vram() { return vram; } }; #endif
memory.cpp
/* GAKKEN TV BOY Emulator 'yaTVBOY' Author : tanam Date : 2020.06.13 [ memory ] */ #include "memory.h" #define SET_BANK(s, e, w, r) { \ int sb = (s) >> 10, eb = (e) >> 10; \ for(int i = sb; i <= eb; i++) { \ if((w) == wdmy) { \ wbank[i] = wdmy; \ } else { \ wbank[i] = (w) + 0x400 * (i - sb); \ } \ if((r) == rdmy) { \ rbank[i] = rdmy; \ } else { \ rbank[i] = (r) + 0x400 * (i - sb); \ } \ } \ } void MEMORY::initialize() { memset(rom, 0xff, sizeof(rom)); memset(rdmy, 0xff, sizeof(rdmy)); // set memory map SET_BANK(0x0000, 0x0fff, ram, ram ); SET_BANK(0x1000, 0x1fff, vram, vram); SET_BANK(0x2000, 0xefff, wdmy, rdmy); SET_BANK(0xf000, 0xffff, wdmy, rom ); // register event register_event_by_clock(this, 0, 256, true, NULL); event = false; inserted = false; } void MEMORY::reset() { memset(ram, 0, sizeof(ram)); for (int i=0; i<sizeof(vram); i++) { vram[i]=rand() % 256; } d_vdp->write_signal(SIG_MC6847_AS, 0x00, 0x08); d_vdp->write_signal(SIG_MC6847_AG, 0x10, 0x10); d_vdp->write_signal(SIG_MC6847_CSS, 0x20, 0x20); d_vdp->write_signal(SIG_MC6847_GM, 0x00, 0x02); d_vdp->write_signal(SIG_MC6847_GM, 0x01, 0x01); d_vdp->write_signal(SIG_MC6847_INTEXT, 0x00, 0x04); shot1 = shot2 = up = down = left = right = 0; } void MEMORY::write_data8(uint32_t addr, uint32_t data) { addr &= 0xffff; if(addr >= 0x80 && addr < 0x100) { d_cpu->ram[addr-0x80]=data; } if(addr == 0x2000) { d_vdp->write_signal(SIG_MC6847_AS, data, 0x08); d_vdp->write_signal(SIG_MC6847_AG, data, 0x10); d_vdp->write_signal(SIG_MC6847_CSS, data, 0x20); d_vdp->write_signal(SIG_MC6847_GM, data << 1, 0x02); d_vdp->write_signal(SIG_MC6847_GM, data >> 1, 0x01); d_vdp->write_signal(SIG_MC6847_INTEXT, data, 0x04); return; } wbank[addr >> 10][addr & 0x3ff] = data; } uint32_t MEMORY::read_data8(uint32_t addr) { addr &= 0xffff; if(addr >= 0x80 && addr < 0x100) { return d_cpu->ram[addr-0x80]; } return rbank[addr >> 10][addr & 0x3ff]; } void MEMORY::write_signal(int id, uint32_t data, uint32_t mask) { d_cpu->write_signal(SIG_MC6801_PORT_2, 0x1E, 0x1E); if (shot2==1 && d_cpu->port[0].wreg==1) { d_cpu->write_signal(SIG_MC6801_PORT_2, 0x00, 0x04); } if (down==1 && d_cpu->port[0].wreg==2) { d_cpu->write_signal(SIG_MC6801_PORT_2, 0x00, 0x04); } if (shot1==1 && d_cpu->port[0].wreg==1) { d_cpu->write_signal(SIG_MC6801_PORT_2, 0x00, 0x02); } if (up==1 && d_cpu->port[0].wreg==2) { d_cpu->write_signal(SIG_MC6801_PORT_2, 0x00, 0x02); } if (left==1 && d_cpu->port[0].wreg==2) { d_cpu->write_signal(SIG_MC6801_PORT_2, 0x00, 0x08); } if (right==1 && d_cpu->port[0].wreg==2) { d_cpu->write_signal(SIG_MC6801_PORT_2, 0x00, 0x10); } } void MEMORY::event_callback(int event_id, int err) { if (event) { d_cpu->write_signal(SIG_CPU_IRQ, 1, 1); event = false; } else { d_cpu->write_signal(SIG_CPU_IRQ, 0, 1); event = true; } } void MEMORY::key_down(int code) { if (code==0x20) { shot1 =1; } if (code==0x11) { shot2 =1; } if (code==0x25) { left =1; } if (code==0x26) { up =1; } if (code==0x27) { right =1; } if (code==0x28) { down =1; } } void MEMORY::key_up(int code) { if (code==0x20) { shot1 =0; } if (code==0x11) { shot2 =0; } if (code==0x25) { left =0; } if (code==0x26) { up =0; } if (code==0x27) { right =0; } if (code==0x28) { down =0; } } void MEMORY::open_cart(const _TCHAR* file_path) { FILEIO* fio = new FILEIO(); if(fio->Fopen(file_path, FILEIO_READ_BINARY)) { fio->Fread(rom, sizeof(rom), 1); fio->Fclose(); inserted = true; } delete fio; } void MEMORY::close_cart() { memset(rom, 0xff, sizeof(rom)); inserted = false; } #define STATE_VERSION 1 bool MEMORY::process_state(FILEIO* state_fio, bool loading) { if(!state_fio->StateCheckUint32(STATE_VERSION)) { return false; } if(!state_fio->StateCheckInt32(this_device_id)) { return false; } state_fio->StateArray(ram, sizeof(ram), 1); state_fio->StateArray(vram, sizeof(vram), 1); return true; }
mc6800.h
/* Skelton for retropc emulator Origin : MAME 0.142 Author : Takeda.Toshiya Date : 2011.04.23- [ MC6800 ] */ #ifndef _MC6800_H_ #define _MC6800_H_ #include "vm.h" #include "../emu.h" #include "device.h" #if defined(HAS_MC6801) || defined(HAS_HD6301) #define SIG_MC6801_PORT_1 0 #define SIG_MC6801_PORT_2 1 #define SIG_MC6801_PORT_3 2 #define SIG_MC6801_PORT_4 3 #define SIG_MC6801_PORT_3_SC1 4 #define SIG_MC6801_PORT_3_SC2 5 #define SIG_MC6801_SIO_RECV 6 class FIFO; #endif #ifdef USE_DEBUGGER class DEBUGGER; #endif class MC6800 : public DEVICE { private: DEVICE *d_mem; #ifdef USE_DEBUGGER DEBUGGER *d_debugger; DEVICE *d_mem_stored; #endif pair32_t pc; uint16_t prevpc; pair32_t sp; pair32_t ix; pair32_t acc_d; pair32_t ea; uint8_t cc; int wai_state; int int_state; #ifdef USE_DEBUGGER uint64_t total_icount; uint64_t prev_total_icount; #endif int icount; bool one_more_insn; uint32_t RM(uint32_t Addr); void WM(uint32_t Addr, uint32_t Value); uint32_t RM16(uint32_t Addr); void WM16(uint32_t Addr, pair32_t *p); #if defined(HAS_MC6801) || defined(HAS_HD6301) // data // struct { // uint8_t wreg; // uint8_t rreg; // uint8_t ddr; // uint8_t latched_data; // bool latched; // output signals // outputs_t outputs; // bool first_write; // } port[4]; uint8_t p3csr; bool p3csr_is3_flag_read; bool sc1_state; bool sc2_state; // timer pair32_t counter; pair32_t output_compare; pair32_t timer_over; uint8_t tcsr; uint8_t pending_tcsr; uint16_t input_capture; #ifdef HAS_HD6301 uint16_t latch09; #endif uint32_t timer_next; // serial i/o outputs_t outputs_sio; FIFO *recv_buffer; uint8_t trcsr, rdr, tdr; bool trcsr_read_tdre, trcsr_read_orfe, trcsr_read_rdrf; uint8_t rmcr; int sio_counter; // memory controller uint8_t ram_ctrl; // uint8_t ram[128]; uint32_t mc6801_io_r(uint32_t offset); void mc6801_io_w(uint32_t offset, uint32_t data); #endif void increment_counter(int amount); void run_one_opecode(); void enter_interrupt(uint16_t irq_vector); void insn(uint8_t code); void aba(); void abx(); void adca_di(); void adca_ex(); void adca_im(); void adca_ix(); void adcb_di(); void adcb_ex(); void adcb_im(); void adcb_ix(); void adda_di(); void adda_ex(); void adda_im(); void adda_ix(); void addb_di(); void addb_ex(); void addb_im(); void addb_ix(); void addd_di(); void addd_ex(); void addd_im(); void addd_ix(); void adx_ex(); void adx_im(); void aim_di(); void aim_ix(); void nim_ix(); void anda_di(); void anda_ex(); void anda_im(); void anda_ix(); void andb_di(); void andb_ex(); void andb_im(); void andb_ix(); void asl_ex(); void asl_ix(); void asla(); void aslb(); void asld(); void asr_ex(); void asr_ix(); void asra(); void asrb(); void bcc(); void bcs(); void beq(); void bge(); void bgt(); void bhi(); void bita_di(); void bita_ex(); void bita_im(); void bita_ix(); void bitb_di(); void bitb_ex(); void bitb_im(); void bitb_ix(); void ble(); void bls(); void blt(); void bmi(); void bne(); void bpl(); void bra(); void brn(); void bsr(); void bvc(); void bvs(); void cba(); void clc(); void cli(); void clr_ex(); void clr_ix(); void clra(); void clrb(); void clv(); void cmpa_di(); void cmpa_ex(); void cmpa_im(); void cmpa_ix(); void cmpb_di(); void cmpb_ex(); void cmpb_im(); void cmpb_ix(); void cmpx_di(); void cmpx_ex(); void cmpx_im(); void cmpx_ix(); void com_ex(); void com_ix(); void coma(); void comb(); void daa(); void dec_ex(); void dec_ix(); void deca(); void decb(); void des(); void dex(); void eim_di(); void eim_ix(); void xim_ix(); void eora_di(); void eora_ex(); void eora_im(); void eora_ix(); void eorb_di(); void eorb_ex(); void eorb_im(); void eorb_ix(); void illegal(); void inc_ex(); void inc_ix(); void inca(); void incb(); void ins(); void inx(); void jmp_ex(); void jmp_ix(); void jsr_di(); void jsr_ex(); void jsr_ix(); void lda_di(); void lda_ex(); void lda_im(); void lda_ix(); void ldb_di(); void ldb_ex(); void ldb_im(); void ldb_ix(); void ldd_di(); void ldd_ex(); void ldd_im(); void ldd_ix(); void lds_di(); void lds_ex(); void lds_im(); void lds_ix(); void ldx_di(); void ldx_ex(); void ldx_im(); void ldx_ix(); void lsr_ex(); void lsr_ix(); void lsra(); void lsrb(); void lsrd(); void mul(); void neg_ex(); void neg_ix(); void nega(); void negb(); void nop(); void oim_di(); void oim_ix(); void oim_ix_mb8861(); void ora_di(); void ora_ex(); void ora_im(); void ora_ix(); void orb_di(); void orb_ex(); void orb_im(); void orb_ix(); void psha(); void pshb(); void pshx(); void pula(); void pulb(); void pulx(); void rol_ex(); void rol_ix(); void rola(); void rolb(); void ror_ex(); void ror_ix(); void rora(); void rorb(); void rti(); void rts(); void sba(); void sbca_di(); void sbca_ex(); void sbca_im(); void sbca_ix(); void sbcb_di(); void sbcb_ex(); void sbcb_im(); void sbcb_ix(); void sec(); void sei(); void sev(); void slp(); void sta_di(); void sta_ex(); void sta_im(); void sta_ix(); void stb_di(); void stb_ex(); void stb_im(); void stb_ix(); void std_di(); void std_ex(); void std_im(); void std_ix(); void sts_di(); void sts_ex(); void sts_im(); void sts_ix(); void stx_di(); void stx_ex(); void stx_im(); void stx_ix(); void suba_di(); void suba_ex(); void suba_im(); void suba_ix(); void subb_di(); void subb_ex(); void subb_im(); void subb_ix(); void subd_di(); void subd_ex(); void subd_im(); void subd_ix(); void swi(); void tab(); void tap(); void tba(); void tim_di(); void tim_ix(); void tmm_ix(); void tpa(); void tst_ex(); void tst_ix(); void tsta(); void tstb(); void tsx(); void txs(); void undoc1(); void undoc2(); void wai(); void xgdx(); void cpx_di(); void cpx_ex(); void cpx_im(); void cpx_ix(); public: MC6800(VM_TEMPLATE* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) { #ifdef USE_DEBUGGER total_icount = prev_total_icount = 0; #endif #if defined(HAS_MC6801) || defined(HAS_HD6301) for(int i = 0; i < 4; i++) { initialize_output_signals(&port[i].outputs); port[i].wreg = port[i].rreg = 0;//0xff; } initialize_output_signals(&outputs_sio); #endif #if defined(HAS_MC6801) set_device_name(_T("MC6801 MPU")); #elif defined(HAS_HD6301) set_device_name(_T("HD6301 MPU")); #else set_device_name(_T("MC6800 MPU")); #endif } ~MC6800() {} // common functions uint8_t ram[128]; struct { uint8_t wreg; uint8_t rreg; uint8_t ddr; uint8_t latched_data; bool latched; outputs_t outputs; bool first_write; } port[4]; void initialize(); #if defined(HAS_MC6801) || defined(HAS_HD6301) void release(); #endif void reset(); int run(int clock); void write_signal(int id, uint32_t data, uint32_t mask); uint32_t get_pc() { return prevpc; } uint32_t get_next_pc() { return pc.w.l; } #ifdef USE_DEBUGGER bool is_cpu() { return true; } bool is_debugger_available() { return true; } void *get_debugger() { return d_debugger; } uint32_t get_debug_prog_addr_mask() { return 0xffff; } uint32_t get_debug_data_addr_mask() { return 0xffff; } void write_debug_data8(uint32_t addr, uint32_t data); uint32_t read_debug_data8(uint32_t addr); // implement 16bit/32bit functions because this cpu is big endian void write_debug_data16(uint32_t addr, uint32_t data); uint32_t read_debug_data16(uint32_t addr); void write_debug_data32(uint32_t addr, uint32_t data); uint32_t read_debug_data32(uint32_t addr); bool write_debug_reg(const _TCHAR *reg, uint32_t data); bool get_debug_regs_info(_TCHAR *buffer, size_t buffer_len); int debug_dasm(uint32_t pc, _TCHAR *buffer, size_t buffer_len); #endif bool process_state(FILEIO* state_fio, bool loading); // unique functions void set_context_mem(DEVICE* device) { d_mem = device; } #ifdef USE_DEBUGGER void set_context_debugger(DEBUGGER* device) { d_debugger = device; } #endif #if defined(HAS_MC6801) || defined(HAS_HD6301) void set_context_port1(DEVICE* device, int id, uint32_t mask, int shift) { register_output_signal(&port[0].outputs, device, id, mask, shift); } void set_context_port2(DEVICE* device, int id, uint32_t mask, int shift) { register_output_signal(&port[1].outputs, device, id, mask, shift); } void set_context_port3(DEVICE* device, int id, uint32_t mask, int shift) { register_output_signal(&port[2].outputs, device, id, mask, shift); } void set_context_port4(DEVICE* device, int id, uint32_t mask, int shift) { register_output_signal(&port[2].outputs, device, id, mask, shift); } void set_context_sio(DEVICE* device, int id) { register_output_signal(&outputs_sio, device, id, 0xff); } #endif }; #endif