学研TV BOYエミュレータをつくる その2

世にも珍しいVCSじゃない方のTV BOYエミュレータです。

www.youtube.com

ソースコード差分は以下になります。

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