M680x0 updates [Hans Ostermeyer]

- Instruction cache emulated on '020 and later
- Fixed interaction between MMU and bfextu/bfexts/bfins
- Added fsgldiv, fsglmul, and fscc FPU instructions
- Fixed fault address in stack frame
- Fixed supervisor violation bit in MMU status register
- Add fmovem modes 1 and 3
- Various other MMU fixes
This commit is contained in:
R. Belmont 2011-02-21 21:40:58 +00:00
parent 18aca550f0
commit 1fcc151bc9
5 changed files with 221 additions and 75 deletions

View File

@ -2634,17 +2634,20 @@ M68KMAKE_OP(bfexts, 32, ., .)
if(BIT_5(word2))
width = REG_D[width&7];
/* Offset is signed so we have to use ugly math =( */
ea += offset / 8;
offset %= 8;
if(offset < 0)
if(BIT_B(word2))
{
offset += 8;
ea--;
/* Offset is signed so we have to use ugly math =( */
ea += offset / 8;
offset %= 8;
if(offset < 0)
{
offset += 8;
ea--;
}
}
width = ((width-1) & 31) + 1;
data = m68ki_read_32(m68k, ea);
data = (offset+width) < 16 ? (m68ki_read_16(m68k, ea) << 16) : m68ki_read_32(m68k, ea);
data = MASK_OUT_ABOVE_32(data<<offset);
@ -2716,17 +2719,20 @@ M68KMAKE_OP(bfextu, 32, ., .)
if(BIT_5(word2))
width = REG_D[width&7];
/* Offset is signed so we have to use ugly math =( */
ea += offset / 8;
offset %= 8;
if(offset < 0)
if(BIT_B(word2))
{
offset += 8;
ea--;
/* Offset is signed so we have to use ugly math =( */
ea += offset / 8;
offset %= 8;
if(offset < 0)
{
offset += 8;
ea--;
}
}
width = ((width-1) & 31) + 1;
data = m68ki_read_32(m68k, ea);
data = (offset+width) < 16 ? (m68ki_read_16(m68k, ea) << 16) : m68ki_read_32(m68k, ea);
data = MASK_OUT_ABOVE_32(data<<offset);
if((offset+width) > 32)
@ -2813,7 +2819,7 @@ M68KMAKE_OP(bfffo, 32, ., .)
}
width = ((width-1) & 31) + 1;
data = m68ki_read_32(m68k, ea);
data = (offset+width) < 16 ? (m68ki_read_16(m68k, ea) << 16) : m68ki_read_32(m68k, ea);
data = MASK_OUT_ABOVE_32(data<<local_offset);
if((local_offset+width) > 32)
@ -2902,13 +2908,16 @@ M68KMAKE_OP(bfins, 32, ., .)
if(BIT_5(word2))
width = REG_D[width&7];
/* Offset is signed so we have to use ugly math =( */
ea += offset / 8;
offset %= 8;
if(offset < 0)
if(BIT_B(word2))
{
offset += 8;
ea--;
/* Offset is signed so we have to use ugly math =( */
ea += offset / 8;
offset %= 8;
if(offset < 0)
{
offset += 8;
ea--;
}
}
width = ((width-1) & 31) + 1;
@ -2920,11 +2929,18 @@ M68KMAKE_OP(bfins, 32, ., .)
m68k->not_z_flag = insert_base;
insert_long = insert_base >> offset;
data_long = m68ki_read_32(m68k, ea);
data_long = (offset+width) < 16 ? (m68ki_read_16(m68k, ea) << 16) : m68ki_read_32(m68k, ea);
m68k->v_flag = VFLAG_CLEAR;
m68k->c_flag = CFLAG_CLEAR;
m68ki_write_32(m68k, ea, (data_long & ~mask_long) | insert_long);
if((width + offset) < 16)
{
m68ki_write_16(m68k, ea, ((data_long & ~mask_long) | insert_long) >> 16);
}
else
{
m68ki_write_32(m68k, ea, (data_long & ~mask_long) | insert_long);
}
if((width + offset) > 32)
{
@ -6684,6 +6700,12 @@ M68KMAKE_OP(movec, 32, rc, .)
{
m68k->cacr = REG_DA[(word2 >> 12) & 15] & 0x0f;
}
// logerror("movec to cacr=%04x\n", m68k->cacr);
if (m68k->cacr & (M68K_CACR_CI | M68K_CACR_CEI))
{
m68ki_ic_clear(m68k);
}
return;
}
m68ki_exception_illegal(m68k);

View File

@ -632,9 +632,9 @@ static CPU_EXECUTE( m68k )
/* Call external hook to peek at CPU */
debugger_instruction_hook(device, REG_PC);
// FIXME: remove this
// void apollo_debug_instruction(device_t *device);
// apollo_debug_instruction(device);
/* call external instruction hook (independent of debug mode) */
if (m68k->instruction_hook != NULL)
m68k->instruction_hook(device, REG_PC);
/* Record previous program counter */
REG_PPC = REG_PC;
@ -672,13 +672,6 @@ static CPU_EXECUTE( m68k )
{
UINT32 sr;
// const char * disassemble(m68ki_cpu_core *m68k, offs_t pc);
// logerror(
// "PMMU: pc=%08x sp=%08x va=%08x bus error: %s\n",
// REG_PPC, REG_A[7], m68k->mmu_tmp_buserror_address,
// (m68k->mmu_tmp_buserror_address == REG_PPC) ? "-"
// : disassemble(m68k, REG_PPC));
m68k->mmu_tmp_buserror_occurred = 0;
// restore cpu address registers to value at start of instruction
@ -821,6 +814,15 @@ static CPU_RESET( m68k )
/* flush the MMU's cache */
pmmu_atc_flush(m68k);
if(CPU_TYPE_IS_EC020_PLUS(m68k->cpu_type))
{
// clear instruction cache
m68ki_ic_clear(m68k);
}
// disable instruction hook
m68k->instruction_hook = NULL;
}
static CPU_DISASSEMBLE( m68k )

View File

@ -103,6 +103,15 @@ typedef struct _m68ki_cpu_core m68ki_cpu_core;
/* MMU constants */
#define MMU_ATC_ENTRIES (22) // 68851 has 64, 030 has 22
/* instruction cache constants */
#define M68K_IC_SIZE 128
#define M68K_CACR_IBE 0x10 // Instruction Burst Enable
#define M68K_CACR_CI 0x08 // Clear Instruction Cache
#define M68K_CACR_CEI 0x04 // Clear Entry in Instruction Cache
#define M68K_CACR_FI 0x02 // Freeze Instruction Cache
#define M68K_CACR_EI 0x01 // Enable Instruction Cache
/* ======================================================================== */
/* ================================ MACROS ================================ */
/* ======================================================================== */
@ -706,6 +715,13 @@ struct _m68ki_cpu_core
UINT16 mmu_tmp_rw; /* temporary hack: read/write (1/0) for the mmu */
UINT32 mmu_tmp_buserror_address; /* temporary hack: (first) bus error address */
UINT16 mmu_tmp_buserror_occurred; /* temporary hack: flag that bus error has occurred from mmu */
UINT32 ic_address[M68K_IC_SIZE]; /* instruction cache address data */
UINT16 ic_data[M68K_IC_SIZE]; /* instruction cache content data */
/* external instruction hook (does not depend on debug mode) */
typedef int (*instruction_hook_t)(device_t *device, offs_t curpc);
instruction_hook_t instruction_hook;
};
@ -882,6 +898,43 @@ INLINE void m68kx_write_memory_32_pd(m68ki_cpu_core *m68k, unsigned int address,
/* ---------------------------- Read Immediate ---------------------------- */
// clear the instruction cache
INLINE void m68ki_ic_clear(m68ki_cpu_core *m68k)
{
int i;
for (i=0; i< M68K_IC_SIZE; i++) {
m68k->ic_address[i] = ~0;
}
}
// read immediate word using the instruction cache
INLINE UINT32 m68ki_ic_readimm16(m68ki_cpu_core *m68k, UINT32 address)
{
if(CPU_TYPE_IS_EC020_PLUS(m68k->cpu_type) && (m68k->cacr & M68K_CACR_EI))
{
UINT32 ic_offset = (address >> 1) % M68K_IC_SIZE;
if (m68k->ic_address[ic_offset] == address)
{
return m68k->ic_data[ic_offset];
}
else
{
UINT32 data = m68k->memory.readimm16(address);
if (!m68k->mmu_tmp_buserror_occurred)
{
m68k->ic_data[ic_offset] = data;
m68k->ic_address[ic_offset] = address;
}
return data;
}
}
else
{
return m68k->memory.readimm16(address);
}
}
/* Handles all immediate reads, does address error check, function code setting,
* and prefetching if they are enabled in m68kconf.h
*/
@ -896,14 +949,14 @@ INLINE UINT32 m68ki_read_imm_16(m68ki_cpu_core *m68k)
if(REG_PC != m68k->pref_addr)
{
m68k->pref_data = m68k->memory.readimm16(REG_PC);
m68k->pref_data = m68ki_ic_readimm16(m68k, REG_PC);
m68k->pref_addr = m68k->mmu_tmp_buserror_occurred ? ~0 : REG_PC;
}
result = MASK_OUT_ABOVE_16(m68k->pref_data);
REG_PC += 2;
if (!m68k->mmu_tmp_buserror_occurred) {
// prefetch only if no bus error occurred in opcode fetch
m68k->pref_data = m68k->memory.readimm16(REG_PC);
m68k->pref_data = m68ki_ic_readimm16(m68k, REG_PC);
m68k->pref_addr = m68k->mmu_tmp_buserror_occurred ? ~0 : REG_PC;
// ignore bus error on prefetch
m68k->mmu_tmp_buserror_occurred = 0;
@ -924,16 +977,16 @@ INLINE UINT32 m68ki_read_imm_32(m68ki_cpu_core *m68k)
if(REG_PC != m68k->pref_addr)
{
m68k->pref_addr = REG_PC;
m68k->pref_data = m68k->memory.readimm16(m68k->pref_addr);
m68k->pref_data = m68ki_ic_readimm16(m68k, m68k->pref_addr);
}
temp_val = MASK_OUT_ABOVE_16(m68k->pref_data);
REG_PC += 2;
m68k->pref_addr = REG_PC;
m68k->pref_data = m68k->memory.readimm16(m68k->pref_addr);
m68k->pref_data = m68ki_ic_readimm16(m68k, m68k->pref_addr);
temp_val = MASK_OUT_ABOVE_32((temp_val << 16) | MASK_OUT_ABOVE_16(m68k->pref_data));
REG_PC += 2;
m68k->pref_data = m68k->memory.readimm16(REG_PC);
m68k->pref_data = m68ki_ic_readimm16(m68k, REG_PC);
m68k->pref_addr = m68k->mmu_tmp_buserror_occurred ? ~0 : REG_PC;
return temp_val;
@ -1543,7 +1596,9 @@ void m68ki_stack_frame_1010(m68ki_cpu_core *m68k, UINT32 sr, UINT32 vector, UINT
m68ki_push_16(m68k, 0);
/* SPECIAL STATUS REGISTER */
m68ki_push_16(m68k, 0);
// set bit for: Rerun Faulted bus Cycle, or run pending prefetch
// set FC
m68ki_push_16(m68k, 0x0100 | m68k->mmu_tmp_fc );
/* INTERNAL REGISTER */
m68ki_push_16(m68k, 0);
@ -1590,7 +1645,7 @@ void m68ki_stack_frame_1011(m68ki_cpu_core *m68k, UINT32 sr, UINT32 vector, UINT
m68ki_push_32(m68k, 0);
/* STAGE B ADDRESS (2 words) */
m68ki_push_32(m68k, fault_address);
m68ki_push_32(m68k, 0);
/* INTERNAL REGISTER (4 words) */
m68ki_push_32(m68k, 0);
@ -1606,7 +1661,7 @@ void m68ki_stack_frame_1011(m68ki_cpu_core *m68k, UINT32 sr, UINT32 vector, UINT
m68ki_push_16(m68k, 0);
/* DATA CYCLE FAULT ADDRESS (2 words) */
m68ki_push_32(m68k, 0);
m68ki_push_32(m68k, fault_address);
/* INSTRUCTION PIPE STAGE B */
m68ki_push_16(m68k, 0);
@ -1615,7 +1670,7 @@ void m68ki_stack_frame_1011(m68ki_cpu_core *m68k, UINT32 sr, UINT32 vector, UINT
m68ki_push_16(m68k, 0);
/* SPECIAL STATUS REGISTER */
m68ki_push_16(m68k, 0);
m68ki_push_16(m68k, 0x0100 | m68k->mmu_tmp_fc);
/* INTERNAL REGISTER */
m68ki_push_16(m68k, 0);

View File

@ -1318,6 +1318,11 @@ static void fpgen_rm_reg(m68ki_cpu_core *m68k, UINT16 w2)
m68k->remaining_cycles -= 109;
break;
}
// case 0x0e: // FSIN
// {
// // TODO
// break;
// }
case 0x18: // FABS
{
REG_FP[dst] = source;
@ -1365,6 +1370,12 @@ static void fpgen_rm_reg(m68ki_cpu_core *m68k, UINT16 w2)
m68k->remaining_cycles -= 11;
break;
}
case 0x24: // FSGLDIV
{
REG_FP[dst] = floatx80_div(REG_FP[dst], source);
m68k->remaining_cycles -= 43; // // ? (value is from FDIV)
break;
}
case 0x25: // FREM
{
REG_FP[dst] = floatx80_rem(REG_FP[dst], source);
@ -1372,6 +1383,13 @@ static void fpgen_rm_reg(m68ki_cpu_core *m68k, UINT16 w2)
m68k->remaining_cycles -= 43; // guess
break;
}
case 0x27: // FSGLMUL
{
REG_FP[dst] = floatx80_mul(REG_FP[dst], source);
SET_CONDITION_CODES(m68k, REG_FP[dst]);
m68k->remaining_cycles -= 11; // ? (value is from FMUL)
break;
}
case 0x28: // FSUB
{
REG_FP[dst] = floatx80_sub(REG_FP[dst], source);
@ -1396,7 +1414,7 @@ static void fpgen_rm_reg(m68ki_cpu_core *m68k, UINT16 w2)
break;
}
default: fatalerror("fpgen_rm_reg: unimplemented opmode %02X at %08X\n", opmode, REG_PC-4);
default: fatalerror("fpgen_rm_reg: unimplemented opmode %02X at %08X\n", opmode, REG_PPC);
}
}
@ -1507,6 +1525,10 @@ static void fmovem(m68ki_cpu_core *m68k, UINT16 w2)
{
switch (mode)
{
case 1: // Dynamic register list, postincrement or control addressing mode.
// FIXME: not really tested, but seems to work
reglist = REG_D[(reglist >> 4) & 7];
case 0: // Static register list, predecrement or control addressing mode
{
for (i=0; i < 8; i++)
@ -1531,13 +1553,41 @@ static void fmovem(m68ki_cpu_core *m68k, UINT16 w2)
break;
}
default: fatalerror("040fpu0: FMOVEM: mode %d unimplemented at %08X\n", mode, REG_PC-4);
case 2: // Static register list, postdecrement or control addressing mode
{
for (i=0; i < 8; i++)
{
if (reglist & (1 << i))
{
switch (ea >> 3)
{
case 5: // (d16, An)
case 6: // (An) + (Xn) + d8
store_extended_float80(m68k, mem_addr, REG_FP[7-i]);
mem_addr += 12;
break;
default:
WRITE_EA_FPE(m68k, ea, REG_FP[7-i]);
break;
}
m68k->remaining_cycles -= 2;
}
}
break;
}
default: fatalerror("M680x0: FMOVEM: mode %d unimplemented at %08X\n", mode, REG_PC-4);
}
}
else // From mem to FP regs
{
switch (mode)
{
case 3: // Dynamic register list, predecrement addressing mode.
// FIXME: not really tested, but seems to work
reglist = REG_D[(reglist >> 4) & 7];
case 2: // Static register list, postincrement or control addressing mode
{
for (i=0; i < 8; i++)
@ -1561,11 +1611,20 @@ static void fmovem(m68ki_cpu_core *m68k, UINT16 w2)
break;
}
default: fatalerror("040fpu0: FMOVEM: mode %d unimplemented at %08X\n", mode, REG_PC-4);
default: fatalerror("M680x0: FMOVEM: mode %d unimplemented at %08X\n", mode, REG_PC-4);
}
}
}
static void fscc(m68ki_cpu_core *m68k)
{
int ea = m68k->ir & 0x3f;
int condition = (INT16)(OPER_I_16(m68k));
WRITE_EA_8(m68k, ea, TEST_CONDITION(m68k, condition) ? 0xff : 0);
m68k->remaining_cycles -= 7; // ???
}
static void fbcc16(m68ki_cpu_core *m68k)
{
INT32 offset;
@ -1646,15 +1705,15 @@ void m68040_fpu_op0(m68ki_cpu_core *m68k)
case 1: // FBcc disp16
{
switch ((m68k->ir >> 3) & 0x3) {
switch ((m68k->ir >> 3) & 0x7) {
case 1: // FDBcc
// TODO:
break;
default: // FScc (?)
// TODO:
break;
fscc(m68k);
return;
}
fatalerror("M68kFPU: unimplemented main op %d with mode %d\n", (m68k->ir >> 6) & 0x3, (m68k->ir >> 3) & 0x7);
fatalerror("M68kFPU: unimplemented main op %d with mode %d at %08X\n", (m68k->ir >> 6) & 0x3, (m68k->ir >> 3) & 0x7, REG_PPC);
}
case 2: // FBcc disp16

View File

@ -199,13 +199,13 @@ INLINE UINT32 get_dt2_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 ptest
return tbl_entry;
}
INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 ptest)
INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 fc, UINT8 ptest)
{
UINT32 tbl_entry2 = m68k->program->read_dword(tptr);
UINT32 tbl_entry = m68k->program->read_dword(tptr + 4);
UINT32 dt = tbl_entry2 & M68K_MMU_DF_DT;
m68k->mmu_tmp_sr |= tbl_entry2 & 0x0100 ? M68K_MMU_SR_SUPERVISOR_ONLY : 0;
m68k->mmu_tmp_sr |= ((tbl_entry2 & 0x0100) && !(fc & 4)) ? M68K_MMU_SR_SUPERVISOR_ONLY : 0;
m68k->mmu_tmp_sr |= tbl_entry2 & 0x0004 ? M68K_MMU_SR_WRITE_PROTECT : 0;
if (!ptest)
@ -272,27 +272,35 @@ INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 ptest
// first see if this is already in the ATC
for (i = 0; i < MMU_ATC_ENTRIES; i++)
{
// if tag bits and function code match, we've got it
if (m68k->mmu_atc_tag[i] == atc_tag)
if (m68k->mmu_atc_tag[i] != atc_tag)
{
if (m68k->mmu_tmp_rw || !(m68k->mmu_atc_data[i] & M68K_MMU_ATC_WRITE_PR))
{
// read access or write access and not write protected
if (!m68k->mmu_tmp_rw && !ptest)
{
// FIXME: must set modified in PMMU tables as well
m68k->mmu_atc_data[i] |= M68K_MMU_ATC_MODIFIED;
}
else
{
// FIXME: supervisor mode?
m68k->mmu_tmp_sr = M68K_MMU_SR_MODIFIED;
}
addr_out = (m68k->mmu_atc_data[i]<<8) | (addr_in & ~(~0 << ps));
// logerror("ATC[%2d] hit: log %08x -> phys %08x pc=%08x fc=%d\n", i, addr_in, addr_out, REG_PPC, fc);
// pmmu_atc_count++;
return addr_out;
}
// tag bits and function code don't match
}
else if (!m68k->mmu_tmp_rw && (m68k->mmu_atc_data[i] & M68K_MMU_ATC_WRITE_PR))
{
// write mode, but write protected
}
else if (!m68k->mmu_tmp_rw && !(m68k->mmu_atc_data[i] & M68K_MMU_ATC_MODIFIED))
{
// first write; must set modified in PMMU tables as well
}
else
{
// read access or write access and not write protected
if (!m68k->mmu_tmp_rw && !ptest)
{
// FIXME: must set modified in PMMU tables as well
m68k->mmu_atc_data[i] |= M68K_MMU_ATC_MODIFIED;
}
else
{
// FIXME: supervisor mode?
m68k->mmu_tmp_sr = M68K_MMU_SR_MODIFIED;
}
addr_out = (m68k->mmu_atc_data[i] << 8) | (addr_in & ~(~0 << ps));
// logerror("ATC[%2d] hit: log %08x -> phys %08x pc=%08x fc=%d\n", i, addr_in, addr_out, REG_PPC, fc);
// pmmu_atc_count++;
return addr_out;
}
}
@ -344,7 +352,7 @@ INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 ptest
case M68K_MMU_DF_DT3: // valid 8 byte descriptors
tofs *= 8;
// if (verbose) logerror("PMMU: reading table A entries at %08x\n", tofs + tptr);
tbl_entry = get_dt3_table_entry(m68k, tofs + tptr, ptest);
tbl_entry = get_dt3_table_entry(m68k, tofs + tptr, fc, ptest);
tamode = tbl_entry & M68K_MMU_DF_DT;
// if (verbose) logerror("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tamode, tofs);
break;
@ -377,7 +385,7 @@ INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 ptest
case M68K_MMU_DF_DT3: // 8-byte table B descriptor
tofs *= 8;
// if (verbose) logerror("PMMU: reading table B entries at %08x\n", tofs + tptr);
tbl_entry = get_dt3_table_entry(m68k, tptr + tofs, ptest);
tbl_entry = get_dt3_table_entry(m68k, tptr + tofs, fc, ptest);
tbmode = tbl_entry & M68K_MMU_DF_DT;
tbl_entry &= ~M68K_MMU_DF_DT;
// if (verbose) logerror("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tbmode, tofs);
@ -421,7 +429,7 @@ INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 ptest
case M68K_MMU_DF_DT3: // 8-byte table C descriptor
tofs *= 8;
// if (verbose) logerror("PMMU: reading table C entries at %08x\n", tofs + tptr);
tbl_entry = get_dt3_table_entry(m68k, tptr+ tofs, ptest);
tbl_entry = get_dt3_table_entry(m68k, tptr+ tofs, fc, ptest);
tcmode = tbl_entry & M68K_MMU_DF_DT;
// if (verbose) logerror("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tcmode, tofs);
break;
@ -470,7 +478,7 @@ INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 ptest
m68k->mmu_tmp_buserror_address = addr_in;
}
}
else if ((m68k->mmu_tmp_sr & M68K_MMU_SR_SUPERVISOR_ONLY) && !(fc & 4))
else if (m68k->mmu_tmp_sr & M68K_MMU_SR_SUPERVISOR_ONLY)
{
if (++m68k->mmu_tmp_buserror_occurred == 1)
{