konami cpu: corrections to EXG/TFR opcode [hap, Jim Westfall]

This commit is contained in:
hap 2025-04-02 22:32:01 +02:00
parent c6e93c06f3
commit 456d6b7619
3 changed files with 58 additions and 46 deletions

View File

@ -16,6 +16,11 @@
Thanks to Franklin Bowen for bug fixes, ideas
TODO:
- KONAMI EXG/TFR isn't disassembled accurately:
0x3E/0x3F + param bit 7 clear = EXG
0x3E/0x3F + param bit 7 set = TFR
*****************************************************************************/
#include "emu.h"
@ -27,7 +32,7 @@ const char *const m6x09_base_disassembler::m6x09_regs[5] = { "X", "Y", "U", "S",
const char *const m6x09_base_disassembler::m6x09_btwregs[5] = { "CC", "A", "B", "inv" };
const char *const m6x09_base_disassembler::hd6309_tfmregs[16] = {
"D", "X", "Y", "U", "S", "inv", "inv", "inv",
"D", "X", "Y", "U", "S", "inv", "inv", "inv",
"inv", "inv", "inv", "inv", "inv", "inv", "inv", "inv"
};
@ -50,7 +55,7 @@ m6x09_base_disassembler::m6x09_base_disassembler(const opcodeinfo *opcodes, size
: m_level(level), m_page(0)
{
// create filtered opcode table
for (int i=0; i<opcode_count; i++)
for (int i = 0; i < opcode_count; i++)
{
if (opcodes[i].level() & level)
{
@ -1242,7 +1247,7 @@ const m6x09_base_disassembler::opcodeinfo konami_disassembler::konami_opcodes[]
{ 0x8C, 0, "DECA", INH, M6x09_GENERAL },
{ 0x8D, 0, "DECB", INH, M6x09_GENERAL },
{ 0x8E, 1, "DEC", IND, M6x09_GENERAL },
{ 0x8F, 0, "RTS", INH , M6x09_GENERAL, STEP_OUT },
{ 0x8F, 0, "RTS", INH, M6x09_GENERAL, STEP_OUT },
{ 0x90, 0, "TSTA", INH, M6x09_GENERAL },
{ 0x91, 0, "TSTB", INH, M6x09_GENERAL },
@ -1259,7 +1264,7 @@ const m6x09_base_disassembler::opcodeinfo konami_disassembler::konami_opcodes[]
{ 0x9C, 0, "ASLA", INH, M6x09_GENERAL },
{ 0x9D, 0, "ASLB", INH, M6x09_GENERAL },
{ 0x9E, 1, "ASL", IND, M6x09_GENERAL },
{ 0x9F, 0, "RTI", INH , M6x09_GENERAL, STEP_OUT },
{ 0x9F, 0, "RTI", INH, M6x09_GENERAL, STEP_OUT },
{ 0xA0, 0, "ROLA", INH, M6x09_GENERAL },
{ 0xA1, 0, "ROLB", INH, M6x09_GENERAL },
@ -1281,10 +1286,10 @@ const m6x09_base_disassembler::opcodeinfo konami_disassembler::konami_opcodes[]
{ 0xB1, 0, "DAA", INH, M6x09_GENERAL },
{ 0xB2, 0, "SEX", INH, M6x09_GENERAL },
{ 0xB3, 0, "MUL", INH, M6x09_GENERAL },
{ 0xB4, 0, "LMUL", INH, M6x09_GENERAL },
{ 0xB5, 0, "DIV X,B", INH, M6x09_GENERAL },
{ 0xB4, 0, "LMUL", INH, M6x09_GENERAL },
{ 0xB5, 0, "DIV X,B", INH, M6x09_GENERAL },
{ 0xB6, 0, "BMOVE Y,X,U", INH, M6x09_GENERAL },
{ 0xB7, 0, "MOVE Y,X,U", INH, M6x09_GENERAL },
{ 0xB7, 0, "MOVE Y,X,U", INH, M6x09_GENERAL },
{ 0xB8, 1, "LSRD", IMM, M6x09_GENERAL },
{ 0xB9, 1, "LSRD", IND, M6x09_GENERAL },
{ 0xBA, 1, "RORD", IMM, M6x09_GENERAL },
@ -1309,9 +1314,9 @@ const m6x09_base_disassembler::opcodeinfo konami_disassembler::konami_opcodes[]
{ 0xCC, 0, "ABSA", INH, M6x09_GENERAL },
{ 0xCD, 0, "ABSB", INH, M6x09_GENERAL },
{ 0xCE, 0, "ABSD", INH, M6x09_GENERAL },
{ 0xCF, 0, "BSET A,X,U", INH, M6x09_GENERAL },
{ 0xCF, 0, "BSET A,X,U", INH, M6x09_GENERAL },
{ 0xD0, 0, "BSET D,X,U", INH, M6x09_GENERAL }
{ 0xD0, 0, "BSET D,X,U", INH, M6x09_GENERAL }
};
@ -1513,11 +1518,12 @@ void konami_disassembler::indexed(std::ostream &stream, uint8_t mode, const data
void konami_disassembler::register_register(std::ostream &stream, uint8_t pb)
{
static const char konami_teregs[8] =
const char *const konami_teregs[8] =
{
'A', 'B', 'X', 'Y', 'S', 'U', '?', '?'
// B: D when reading, B when writing
"A", "B", "X", "Y", "DP", "U", "S", "PC"
};
util::stream_format(stream, "%c,%c",
util::stream_format(stream, "%s,%s",
konami_teregs[(pb >> 0) & 0x7],
konami_teregs[(pb >> 4) & 0x7]);
}

View File

@ -10,6 +10,9 @@
TODO:
- verify cycle timing
- verify status flag handling
- EXG/TFR DP: DP here is apparently part of a 16-bit register. DP is
the high byte, and the low byte is an unknown hidden register? It
doesn't look like any game uses this. See MAME issue #13544.
References:
@ -184,15 +187,15 @@ inline uint16_t &konami_cpu_device::ireg()
{
switch(m_opcode & 0x70)
{
case 0x20: return m_x.w;
case 0x30: return m_y.w;
case 0x50: return m_u.w;
case 0x60: return m_s.w;
case 0x70: return m_pc.w;
case 0x20: return m_x.w; // X
case 0x30: return m_y.w; // Y
case 0x50: return m_u.w; // U
case 0x60: return m_s.w; // S
case 0x70: return m_pc.w; // PC
default:
fatalerror("Should not get here");
// never executed
//return m_x.w;
}
}
@ -207,12 +210,14 @@ inline uint16_t konami_cpu_device::read_exgtfr_register(uint8_t reg)
switch(reg & 0x07)
{
case 0: result = m_q.r.a; break; // A
case 1: result = m_q.r.b; break; // B
case 2: result = m_x.w; break; // X
case 3: result = m_y.w; break; // Y
case 4: result = m_s.w; break; // S
case 5: result = m_u.w; break; // U
case 0: result = m_q.r.a; break; // A
case 1: result = m_q.r.d; break; // D
case 2: result = m_x.w; break; // X
case 3: result = m_y.w; break; // Y
case 4: logerror("EXG/TFR unemulated DP reg\n"); break; // DP
case 5: result = m_u.w; break; // U
case 6: result = m_s.w; break; // S
case 7: result = m_pc.w; break; // PC
}
return result;
@ -227,12 +232,14 @@ inline void konami_cpu_device::write_exgtfr_register(uint8_t reg, uint16_t value
{
switch(reg & 0x07)
{
case 0: m_q.r.a = value; break; // A
case 1: m_q.r.b = value; break; // B
case 2: m_x.w = value; break; // X
case 3: m_y.w = value; break; // Y
case 4: m_s.w = value; break; // S
case 5: m_u.w = value; break; // U
case 0: m_q.r.a = value; break; // A
case 1: m_q.r.b = value; break; // B
case 2: m_x.w = value; break; // X
case 3: m_y.w = value; break; // Y
case 4: logerror("EXG/TFR unemulated DP reg\n"); break; // DP
case 5: m_u.w = value; break; // U
case 6: m_s.w = value; break; // S
case 7: m_pc.w = value; break; // PC
}
}

View File

@ -76,8 +76,7 @@ MAIN:
case 0x3B: set_regop8(m_q.r.b); %INDEXED; %ST8; return;
case 0x3C: set_imm(); %ANDCC; return;
case 0x3D: set_imm(); %ORCC; return;
case 0x3E: %EXG; return;
case 0x3F: %TFR; return;
case 0x3E: case 0x3F: %EXGTFR; return;
case 0x40: set_regop16(m_q.p.d); set_imm(); %LD16; return;
case 0x41: set_regop16(m_q.p.d); %INDEXED; %LD16; return;
@ -434,24 +433,24 @@ INDEXED:
set_ea(m_temp.w);
return;
EXG:
EXGTFR:
{
// konami's EXG instruction differs enough from 6809 to fork the code
uint8_t param = read_opcode_arg();
uint16_t reg1 = read_exgtfr_register(param >> 0);
uint16_t reg2 = read_exgtfr_register(param >> 4);
write_exgtfr_register(param >> 0, reg2);
write_exgtfr_register(param >> 4, reg1);
}
eat(3);
return;
TFR:
{
// konami's TFR instruction differs enough from 6809 to fork the code
// konami's EXG/TFR instruction differs enough from HD6309 to fork the code
uint8_t param = read_opcode_arg();
uint16_t reg = read_exgtfr_register(param >> 0);
// Opcodes 0x3E and 0x3F are the same! The bit that distinguishes between EXG and TFR
// is actually opcode_arg bit 7. Although Konami software behaves as expected.
if (!BIT(param, 7))
{
uint16_t reg2 = read_exgtfr_register(param >> 4);
write_exgtfr_register(param >> 0, reg2);
eat(1);
}
write_exgtfr_register(param >> 4, reg);
//if (BIT(m_opcode, 0) != BIT(param, 7))
// logerror("KONAMI: Malformed EXG/TFR opcode\n");
}
eat(2);
return;