m6502dasm.c

リファクタリング済み

リファクタリング済み

  • タグ:
  • タグはありません
/**********************************************************************
6280dasm.c Hudsonsoft Hu6280 (HuC6280/Hu6280a) disassembler

Copyright Bryan McPhail, mish@tendril.co.uk

This source code is based (with permission!) on the 6502 emulator by
Juergen Buchmueller.  It is released as part of the Mame emulator project.
Let me know if you intend to use this code in any other project.


Notes relating to Mame:

The dasm window shows 'real' memory, as executed by the cpu
The data windows show 'physical' memory, as defined in the memory map
 *********************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "m6502dasm.h"

enum addr_mode {
	_non = 0, /* no additional arguments */
	_acc, /* accumulator */
	_imp, /* implicit */
	_imm, /* immediate */
	_abs, /* absolute */
	_zpg, /* zero page */
	_zpx, /* zero page + X */
	_zpy, /* zero page + Y */
	_zpi, /* zero page indirect */
	_abx, /* absolute + X */
	_aby, /* absolute + Y */
	_rel, /* relative */
	_idx, /* zero page pre indexed */
	_idy, /* zero page post indexed */
	_ind, /* indirect */
	_iax, /* indirect + X */
	_blk, /* block */
	_zrl, /* zero page relative */
	_imz, /* immediate, zero page */
	_izx, /* immediate, zero page + X */
	_ima, /* immediate, absolute */
	_imx /* immediate, absolute + X */
};

enum opcodes {
	/* 6502 opcodes */
	_adc = 0, _and,  _asl,  _bcc,      _bcs,  _beq,  _bit,  _bmi,
	_bne,  _bpl,  _brk,  _bvc,      _bvs,  _clc,  _cld,  _cli,
	_clv,  _cmp,  _cpx,  _cpy,      _dec,  _dex,  _dey,  _eor,
	_inc,  _inx,  _iny,  _jmp,      _jsr,  _lda,  _ldx,  _ldy,
	_lsr,  _nop,  _ora,  _pha,      _php,  _pla,  _plp,  _rol,
	_ror,  _rti,  _rts,  _sbc,      _sec,  _sed,  _sei,  _sta,
	_stx,  _sty,  _tax,  _tay,      _tsx,  _txa,  _txs,  _tya,
	_ill,

	/* 65C02 opcodes */
	_bra,  _stz,  _trb,  _tsb,  _dea,  _ina,  
	_phx,  _phy,  _plx,  _ply,
	_sm0,  _sm1,  _sm2,  _sm3,  _sm4,  _sm5,  _sm6,  _sm7,
	_rm0,  _rm1,  _rm2,  _rm3,  _rm4,  _rm5,  _rm6,  _rm7,
	_bs0,  _bs1,  _bs2,  _bs3,  _bs4,  _bs5,  _bs6,  _bs7,
	_br0,  _br1,  _br2,  _br3,  _br4,  _br5,  _br6,  _br7,

	/* Hu6280 opcodes */
	_sax,  _bsr,
	_csh,  _csl,  _tam,  _tma,
	_cla,  _cly,  _clx,  _st0,  _st1,  _st2,  _tst,  _set,
	_tdd,  _tia,  _tii,  _tin,  _tai,  _say,  _sxy
};

static const char*const token[] = {
	/* 6502 opcodes */
	"adc", "and", "asl", "bcc", "bcs", "beq", "bit", "bmi",
	"bne", "bpl", "brk", "bvc", "bvs", "clc", "cld", "cli",
	"clv", "cmp", "cpx", "cpy", "dec", "dex", "dey", "eor",
	"inc", "inx", "iny", "jmp", "jsr", "lda", "ldx", "ldy",
	"lsr", "nop", "ora", "pha", "php", "pla", "plp", "rol",
	"ror", "rti", "rts", "sbc", "sec", "sed", "sei", "sta",
	"stx", "sty", "tax", "tay", "tsx", "txa", "txs", "tya",
	"ill",

	/* 65C02 opcodes */
	"bra", "stz", "trb", "tsb", "dea", "ina", 
	"phx", "phy", "plx", "ply", 
	"smb0", "smb1", "smb2", "smb3", "smb4", "smb5", "smb6", "smb7",
	"rmb0", "rmb1", "rmb2", "rmb3", "rmb4", "rmb5", "rmb6", "rmb7",

	"bbs0", "bbs1", "bbs2", "bbs3", "bbs4", "bbs5", "bbs6", "bbs7",
	"bbr0", "bbr1", "bbr2", "bbr3", "bbr4", "bbr5", "bbr6", "bbr7",
	
	/* Hu6280 opcodes */
	"sax", "bsr",
	"csh", "csl", "tam", "tma",
	"cla", "cly", "clx", "st0", "st1", "st2", "tst", "set",
	"tdd", "tia", "tii", "tin", "tai", "say", "sxy"
};
static const struct list{
	enum opcodes opcode;
	enum addr_mode addressingmode;
}list6280[0x100] = {
#include "h6280.inc"
};
static const struct list list6502[0x100] = {
#include "m6502.inc"
};
static const struct list list65c02[0x100] = {
#include "m65c02.inc"
};
static const struct list LIST_INA = {_inc, _acc};
static const struct list LIST_DEA = {_dec, _acc};

struct m6502disasm{
	const struct list *list;
	size_t bufsize;
	char *buffer;
	const char *(*abssign)(int);
	const uint8_t *instmem, *datamem;
};
static const char *abssign_none(int v)
{
	return "";
}
static const char *abssign_6280(int v)
{
	if(v < 0x0100){
		return ">";
	}
	return "";
}
static struct m6502disasm *diasm_new(const struct list *list, size_t bufsize, char *buf)
{
	static struct m6502disasm t;
	t.list = list;
	t.bufsize = bufsize;
	t.buffer = buf;
	t.abssign = abssign_none;
	return &t;
}
struct m6502disasm *m6502_diasm_new(size_t bufsize, char *buf)
{
	return diasm_new(list6502, bufsize, buf);
}
struct m6502disasm *m65c02_diasm_new(size_t bufsize, char *buf)
{
	return diasm_new(list65c02, bufsize, buf);
}
struct m6502disasm *h6280_diasm_new(size_t bufsize, char *buf)
{
	struct m6502disasm *r = diasm_new(list6280, bufsize, buf);
	r->abssign = abssign_6280;
	return r;
}
#define DASMFLAG_SUPPORTED (1<<24)
#define DASMFLAG_STEP_OVER (1<<25)
#define DASMFLAG_STEP_OUT (1<<26)

static inline uint8_t rdop(struct m6502disasm *t, int addr)
{
	return t->instmem[addr];
}
static inline uint8_t rdbyte(struct m6502disasm *t, int addr)
{
	return t->datamem[addr];
}
static inline uint16_t rdword(struct m6502disasm *t, int addr)
{
	uint16_t r = rdbyte(t, addr++);
	return  r | (rdop(t, addr) << 8);
}
static inline uint16_t relative(struct m6502disasm *t, int pc, int addr)
{
	uint16_t r = pc + 2;
	r += (signed char) rdbyte(t, addr);
	return r;
}
/**********************************************************************
*  Disassemble a single command and return the number of bytes it uses.
**********************************************************************/
uint32_t m6502_disassemble(struct m6502disasm *t, const int pc_prev, const uint8_t *instmem, const uint8_t *datamem)
{
	t->instmem = instmem;
	t->datamem = datamem;
	uint32_t flags = 0;
	int read_count = 0;
	const uint8_t opraw = rdop(t, read_count++);
	const struct list *l = t->list + opraw;

	switch(l->opcode){
	case _jsr: case _bsr:
		flags = DASMFLAG_STEP_OVER;
		break;
	case _rts:
		flags = DASMFLAG_STEP_OUT;
		break;
	case _ina:
		l = &LIST_INA;
		break;
	case _dea:
		l = &LIST_DEA;
		break;
	default:
		break;
	}
	const char withx[] = ",x";
	const char withy[] = ",y";
	const char withnone[] = "";
	const char *const opname = token[l->opcode];
	switch(l->addressingmode){
	case _acc:
		snprintf(t->buffer, t->bufsize, "%-5sa", opname);
		break;
	case _imp:
		snprintf(t->buffer, t->bufsize, "%s", opname);
		break;
	case _rel:
		snprintf(t->buffer, t->bufsize, "%-5s$%04x", opname, relative(t, pc_prev, read_count));
		read_count += 1;
		break;
	case _imm:
		snprintf(t->buffer, t->bufsize, "%-5s#$%02x", opname, rdbyte(t, read_count));
		read_count += 1;
		break;
	case _zpg: case _zpx: case _zpy:{
		snprintf(t->buffer, t->bufsize, "%-5s<$%02x", opname, rdbyte(t, read_count));
		read_count += 1;
		const char *app = withnone;
		switch(l->addressingmode){
		case _zpx: app = withx; break;
		case _zpy: app = withy; break;
		default: break;
		}
		strncat(t->buffer, app, t->bufsize);
		}break;
	case _idx:
		snprintf(t->buffer, t->bufsize, "%-5s(<$%02x,x)", opname, rdbyte(t, read_count));
		read_count += 1;
		break;
	case _idy:
		snprintf(t->buffer, t->bufsize, "%-5s(<$%02x),y", opname, rdbyte(t, read_count));
		read_count += 1;
		break;
	case _zpi:
		snprintf(t->buffer, t->bufsize, "%-5s(<$%02x)", opname, rdbyte(t, read_count));
		read_count += 1;
		break;
	case _abs: case _abx: case _aby:{
		snprintf(t->buffer, t->bufsize, "%-5s%s$%04x", opname, t->abssign(rdword(t, read_count)), rdword(t, read_count));
		read_count += 2;
		const char *app = withnone;
		switch(l->addressingmode){
		case _abx: app = withx; break;
		case _aby: app = withy; break;
		default: break;
		}
		strncat(t->buffer, app, t->bufsize);
		}break;
	case _ind:
		snprintf(t->buffer, t->bufsize, "%-5s($%04x)", opname, rdword(t, read_count));
		read_count += 2;
		break;
	case _iax:
		snprintf(t->buffer, t->bufsize, "%-5s($%04x,x)", opname, rdword(t, read_count));
		read_count += 2;
		break;
	case _blk:
		snprintf(t->buffer, t->bufsize, "%-5s$%04x,$%04x,$%04x", opname, rdword(t, read_count), rdword(t, read_count + 2), rdword(t, read_count + 4));
		read_count += 6;
		break;
	case _zrl:
		snprintf(t->buffer, t->bufsize, "%-5s<$%02x,$%04x", opname, rdbyte(t, read_count), relative(t, pc_prev, read_count));
		read_count += 2;
		break;
	case _imz:
		snprintf(t->buffer, t->bufsize, "%-5s#$%02x,<$%02x", opname, rdbyte(t, read_count), rdbyte(t, read_count + 1));
		read_count += 2;
		break;
	case _izx:
		snprintf(t->buffer, t->bufsize, "%-5s#$%02x,<$%02x,x", opname, rdbyte(t, read_count), rdbyte(t, read_count + 1));
		read_count += 2;
		break;
	case _ima:
		snprintf(t->buffer, t->bufsize, "%-5s#$%02x,$%04x", opname, rdbyte(t, read_count), rdword(t, read_count + 1));
		read_count += 3;
		break;
	case _imx:
		snprintf(t->buffer, t->bufsize, "%-5s#$%02x,$%04x,x", opname, rdbyte(t, read_count), rdword(t, read_count + 1));
		read_count += 3;
		break;
	default:
		snprintf(t->buffer, t->bufsize, "%-5s$%02x", opname, opraw);
		break;
	}
	return read_count | flags | DASMFLAG_SUPPORTED;
}