summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Andrew Gardner <andrew-gardner@users.noreply.github.com>2009-01-15 04:40:57 +0000
committer Andrew Gardner <andrew-gardner@users.noreply.github.com>2009-01-15 04:40:57 +0000
commit6ea9ca05895547064a789f42aad5c1affcfd435a (patch)
treebf50323c3a755ee4215f9e0c470c07578132df34 /src
parentf4392d4c6fac506018a4f150e3fee442372aff40 (diff)
Virtual Combat driver improvements. [Jason Eckhardt, Andrew Gardner]
* Graphics decoded, video improved, inputs mapped. Intel i860 CPU core added. [Jason Eckhardt] (The CPU core doesn't have accurate cycle counts for each opcode yet, but it'll have them soon. I believe that is the main culprit behind the sync of the two i860s and the 68k being outta' whack. You can still see the i860s do their thing and rasterize a voxel? groundplane and some simple polygon bad guys).
Diffstat (limited to 'src')
-rw-r--r--src/emu/cpu/cpu.mak8
-rw-r--r--src/emu/cpu/i860/i860.c380
-rw-r--r--src/emu/cpu/i860/i860.h203
-rw-r--r--src/emu/cpu/i860/i860dec.c4722
-rw-r--r--src/emu/cpu/i860/i860dis.c694
-rw-r--r--src/mame/drivers/vcombat.c504
-rw-r--r--src/mame/mamedriv.c2
7 files changed, 6340 insertions, 173 deletions
diff --git a/src/emu/cpu/cpu.mak b/src/emu/cpu/cpu.mak
index 8c54a6e456e..7ecd0813948 100644
--- a/src/emu/cpu/cpu.mak
+++ b/src/emu/cpu/cpu.mak
@@ -744,12 +744,12 @@ CPUDEFS += -DHAS_I860=$(if $(filter I860,$(CPUS)),1,0)
ifneq ($(filter I860,$(CPUS)),)
OBJDIRS += $(CPUOBJ)/i860
CPUOBJS += $(CPUOBJ)/i860/i860.o
-DBGOBJS += $(CPUOBJ)/i860/i860dasm.o
+DBGOBJS += $(CPUOBJ)/i860/i860dis.o
endif
-$(CPUOBJ)/i860/i860.o: $(CPUSRC)/i860/i860.c \
- $(CPUSRC)/i860/i860.h
-
+$(CPUOBJ)/i860/i860.o: $(CPUSRC)/i860/i860.c \
+ $(CPUSRC)/i860/i860.h \
+ $(CPUSRC)/i860/i860dec.c
#-------------------------------------------------
# Intel i960
diff --git a/src/emu/cpu/i860/i860.c b/src/emu/cpu/i860/i860.c
index 68fc190fcff..076083c4181 100644
--- a/src/emu/cpu/i860/i860.c
+++ b/src/emu/cpu/i860/i860.c
@@ -1,21 +1,25 @@
-#include "debugger.h"
-#include "i860.h"
+/***************************************************************************
-/**************************************************************************
- * The core struct
- **************************************************************************/
-typedef struct _i860_state_t i860_state_t;
-struct _i860_state_t
-{
- const device_config *device;
- const address_space *program;
+ i860.c
- UINT32 pc;
- UINT32 ppc;
+ Interface file for the Intel i860 emulator.
- int icount;
-};
+ Copyright (C) 1995-present Jason Eckhardt (jle@rice.edu)
+ Released for general non-commercial use under the MAME license
+ with the additional requirement that you are free to use and
+ redistribute this code in modified or unmodified form, provided
+ you list me in the credits.
+ Visit http://mamedev.org for licensing and usage restrictions.
+***************************************************************************/
+
+/*
+TODO: Separate out i860XR and i860XP (make different types, etc).
+ Hook IRQ lines into MAME core (they're custom functions atm).
+*/
+
+#include "debugger.h"
+#include "i860.h"
/**************************************************************************
* Functions specified by GET_INFO
@@ -23,69 +27,259 @@ struct _i860_state_t
static CPU_INIT( i860 )
{
- i860_state_t *i860 = device->token;
- i860->device = device;
- i860->program = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM);
+ i860_state_t *cpustate = device->token;
+ cpustate->device = device;
+ cpustate->program = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM);
+ reset_i860(cpustate);
+ i860_set_pin(cpustate, DEC_PIN_BUS_HOLD, 0);
+ i860_set_pin(cpustate, DEC_PIN_RESET, 0);
+ cpustate->single_stepping = 0;
+
+ state_save_register_device_item_array(device, 0, cpustate->iregs);
+ state_save_register_device_item_array(device, 0, cpustate->cregs);
+ state_save_register_device_item_array(device, 0, cpustate->frg);
+ state_save_register_device_item(device, 0, cpustate->pc);
}
static CPU_RESET( i860 )
{
- logerror("i860 reset\n");
+ i860_state_t *cpustate = device->token;
+ reset_i860(cpustate);
}
-static CPU_EXECUTE( i860 )
+
+/***************************************************************************
+ * Disassembler hook
+ ***************************************************************************/
+
+static CPU_DISASSEMBLE( i860 )
{
- /* Just a disassembler ATM */
- return cycles;
+ extern unsigned disasm_i860(char*, unsigned, UINT32);
+
+ /* Hard-coded little endian for now. */
+ return disasm_i860(buffer, pc, (oprom[0] << 0) |
+ (oprom[1] << 8) |
+ (oprom[2] << 16) |
+ (oprom[3] << 24));
}
-extern CPU_DISASSEMBLE( i860 );
+
+/**************************************************************************
+ * The actual decode and execute code.
+ **************************************************************************/
+#include "i860dec.c"
/**************************************************************************
* Generic set_info/get_info
**************************************************************************/
+
+#define CPU_SET_INFO_F(fnum) cpustate->frg[0+(4*fnum)] = (info->i & 0x000000ff); \
+ cpustate->frg[1+(4*fnum)] = (info->i & 0x0000ff00) >> 8; \
+ cpustate->frg[2+(4*fnum)] = (info->i & 0x00ff0000) >> 16; \
+ cpustate->frg[3+(4*fnum)] = (info->i & 0xff000000) >> 24;
+
static CPU_SET_INFO( i860 )
{
- i860_state_t *i860 = device->token;
+ i860_state_t *cpustate = device->token;
switch(state)
{
- /* Interfacing */
case CPUINFO_INT_PC:
- case CPUINFO_INT_REGISTER + I860_PC: i860->pc = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_PC: cpustate->pc = info->i & 0xffffffff; break;
+
+ case CPUINFO_INT_REGISTER + I860_FIR: cpustate->cregs[CR_FIR] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_PSR: cpustate->cregs[CR_PSR] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_DIRBASE: cpustate->cregs[CR_DIRBASE] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_DB: cpustate->cregs[CR_DB] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_FSR: cpustate->cregs[CR_FSR] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_EPSR: cpustate->cregs[CR_EPSR] = info->i & 0xffffffff; break;
+
+ case CPUINFO_INT_REGISTER + I860_R0: cpustate->iregs[0] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R1: cpustate->iregs[1] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R2: cpustate->iregs[2] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R3: cpustate->iregs[3] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R4: cpustate->iregs[4] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R5: cpustate->iregs[5] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R6: cpustate->iregs[6] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R7: cpustate->iregs[7] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R8: cpustate->iregs[8] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R9: cpustate->iregs[9] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R10: cpustate->iregs[10] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R11: cpustate->iregs[11] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R12: cpustate->iregs[12] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R13: cpustate->iregs[13] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R14: cpustate->iregs[14] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R15: cpustate->iregs[15] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R16: cpustate->iregs[16] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R17: cpustate->iregs[17] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R18: cpustate->iregs[18] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R19: cpustate->iregs[19] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R20: cpustate->iregs[20] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R21: cpustate->iregs[21] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R22: cpustate->iregs[22] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R23: cpustate->iregs[23] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R24: cpustate->iregs[24] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R25: cpustate->iregs[25] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R26: cpustate->iregs[26] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R27: cpustate->iregs[27] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R28: cpustate->iregs[28] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R29: cpustate->iregs[29] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R30: cpustate->iregs[30] = info->i & 0xffffffff; break;
+ case CPUINFO_INT_REGISTER + I860_R31: cpustate->iregs[31] = info->i & 0xffffffff; break;
+
+ case CPUINFO_INT_REGISTER + I860_F0: CPU_SET_INFO_F(0); break;
+ case CPUINFO_INT_REGISTER + I860_F1: CPU_SET_INFO_F(1); break;
+ case CPUINFO_INT_REGISTER + I860_F2: CPU_SET_INFO_F(2); break;
+ case CPUINFO_INT_REGISTER + I860_F3: CPU_SET_INFO_F(3); break;
+ case CPUINFO_INT_REGISTER + I860_F4: CPU_SET_INFO_F(4); break;
+ case CPUINFO_INT_REGISTER + I860_F5: CPU_SET_INFO_F(5); break;
+ case CPUINFO_INT_REGISTER + I860_F6: CPU_SET_INFO_F(6); break;
+ case CPUINFO_INT_REGISTER + I860_F7: CPU_SET_INFO_F(7); break;
+ case CPUINFO_INT_REGISTER + I860_F8: CPU_SET_INFO_F(8); break;
+ case CPUINFO_INT_REGISTER + I860_F9: CPU_SET_INFO_F(9); break;
+ case CPUINFO_INT_REGISTER + I860_F10: CPU_SET_INFO_F(10); break;
+ case CPUINFO_INT_REGISTER + I860_F11: CPU_SET_INFO_F(11); break;
+ case CPUINFO_INT_REGISTER + I860_F12: CPU_SET_INFO_F(12); break;
+ case CPUINFO_INT_REGISTER + I860_F13: CPU_SET_INFO_F(13); break;
+ case CPUINFO_INT_REGISTER + I860_F14: CPU_SET_INFO_F(14); break;
+ case CPUINFO_INT_REGISTER + I860_F15: CPU_SET_INFO_F(15); break;
+ case CPUINFO_INT_REGISTER + I860_F16: CPU_SET_INFO_F(16); break;
+ case CPUINFO_INT_REGISTER + I860_F17: CPU_SET_INFO_F(17); break;
+ case CPUINFO_INT_REGISTER + I860_F18: CPU_SET_INFO_F(18); break;
+ case CPUINFO_INT_REGISTER + I860_F19: CPU_SET_INFO_F(19); break;
+ case CPUINFO_INT_REGISTER + I860_F20: CPU_SET_INFO_F(20); break;
+ case CPUINFO_INT_REGISTER + I860_F21: CPU_SET_INFO_F(21); break;
+ case CPUINFO_INT_REGISTER + I860_F22: CPU_SET_INFO_F(22); break;
+ case CPUINFO_INT_REGISTER + I860_F23: CPU_SET_INFO_F(23); break;
+ case CPUINFO_INT_REGISTER + I860_F24: CPU_SET_INFO_F(24); break;
+ case CPUINFO_INT_REGISTER + I860_F25: CPU_SET_INFO_F(25); break;
+ case CPUINFO_INT_REGISTER + I860_F26: CPU_SET_INFO_F(26); break;
+ case CPUINFO_INT_REGISTER + I860_F27: CPU_SET_INFO_F(27); break;
+ case CPUINFO_INT_REGISTER + I860_F28: CPU_SET_INFO_F(28); break;
+ case CPUINFO_INT_REGISTER + I860_F29: CPU_SET_INFO_F(29); break;
+ case CPUINFO_INT_REGISTER + I860_F30: CPU_SET_INFO_F(30); break;
+ case CPUINFO_INT_REGISTER + I860_F31: CPU_SET_INFO_F(31); break;
}
}
+#define CPU_GET_INFO_INT_F(fnum) (info->i = cpustate->frg[0+(4*fnum)] | \
+ cpustate->frg[1+(4*fnum)] << 8 | \
+ cpustate->frg[2+(4*fnum)] << 16 | \
+ cpustate->frg[3+(4*fnum)] << 24)
+
+#define CPU_GET_INFO_STR_F(fnum) (sprintf(info->s, "F%d : %08x", fnum, cpustate->frg[0+(4*fnum)] | \
+ cpustate->frg[1+(4*fnum)] << 8 | \
+ cpustate->frg[2+(4*fnum)] << 16 | \
+ cpustate->frg[3+(4*fnum)] << 24))
+
CPU_GET_INFO( i860 )
{
- i860_state_t *i860 = (device != NULL) ? device->token : NULL;
+ i860_state_t *cpustate = (device != NULL) ? device->token : NULL;
switch (state)
{
- // --- the following bits of info are returned as 64-bit signed integers ---
- case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(i860_state_t); break;
- case CPUINFO_INT_INPUT_LINES: info->i = 0; break;
- case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0x00000000; break;
- case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_LITTLE; break;
- case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break;
- case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
- case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
- case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
- case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
- case CPUINFO_INT_MAX_CYCLES: info->i = 8; break;
-
- case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
- case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
- case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
- case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
- case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
- case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
- case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
- case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
- case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
-
- // --- the following bits of info are returned as pointers to data or functions ---
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(i860_state_t); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 0; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0x00000000; break;
+ case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_LITTLE; break;
+ case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 8; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH_PROGRAM: info->i = 64; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH_DATA: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH_IO: info->i = 0; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT_IO: info->i = 0; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + I860_PC: info->i = cpustate->pc; break;
+ case CPUINFO_INT_PREVIOUSPC: info->i = cpustate->ppc; break;
+
+ case CPUINFO_INT_REGISTER + I860_FIR: info->i = cpustate->cregs[CR_FIR]; break;
+ case CPUINFO_INT_REGISTER + I860_PSR: info->i = cpustate->cregs[CR_PSR]; break;
+ case CPUINFO_INT_REGISTER + I860_DIRBASE: info->i = cpustate->cregs[CR_DIRBASE]; break;
+ case CPUINFO_INT_REGISTER + I860_DB: info->i = cpustate->cregs[CR_DB]; break;
+ case CPUINFO_INT_REGISTER + I860_FSR: info->i = cpustate->cregs[CR_FSR]; break;
+ case CPUINFO_INT_REGISTER + I860_EPSR: info->i = cpustate->cregs[CR_EPSR]; break;
+
+ case CPUINFO_INT_REGISTER + I860_R0: info->i = cpustate->iregs[0]; break;
+ case CPUINFO_INT_REGISTER + I860_R1: info->i = cpustate->iregs[1]; break;
+ case CPUINFO_INT_REGISTER + I860_R2: info->i = cpustate->iregs[2]; break;
+ case CPUINFO_INT_REGISTER + I860_R3: info->i = cpustate->iregs[3]; break;
+ case CPUINFO_INT_REGISTER + I860_R4: info->i = cpustate->iregs[4]; break;
+ case CPUINFO_INT_REGISTER + I860_R5: info->i = cpustate->iregs[5]; break;
+ case CPUINFO_INT_REGISTER + I860_R6: info->i = cpustate->iregs[6]; break;
+ case CPUINFO_INT_REGISTER + I860_R7: info->i = cpustate->iregs[7]; break;
+ case CPUINFO_INT_REGISTER + I860_R8: info->i = cpustate->iregs[8]; break;
+ case CPUINFO_INT_REGISTER + I860_R9: info->i = cpustate->iregs[9]; break;
+ case CPUINFO_INT_REGISTER + I860_R10: info->i = cpustate->iregs[10]; break;
+ case CPUINFO_INT_REGISTER + I860_R11: info->i = cpustate->iregs[11]; break;
+ case CPUINFO_INT_REGISTER + I860_R12: info->i = cpustate->iregs[12]; break;
+ case CPUINFO_INT_REGISTER + I860_R13: info->i = cpustate->iregs[13]; break;
+ case CPUINFO_INT_REGISTER + I860_R14: info->i = cpustate->iregs[14]; break;
+ case CPUINFO_INT_REGISTER + I860_R15: info->i = cpustate->iregs[15]; break;
+ case CPUINFO_INT_REGISTER + I860_R16: info->i = cpustate->iregs[16]; break;
+ case CPUINFO_INT_REGISTER + I860_R17: info->i = cpustate->iregs[17]; break;
+ case CPUINFO_INT_REGISTER + I860_R18: info->i = cpustate->iregs[18]; break;
+ case CPUINFO_INT_REGISTER + I860_R19: info->i = cpustate->iregs[19]; break;
+ case CPUINFO_INT_REGISTER + I860_R20: info->i = cpustate->iregs[20]; break;
+ case CPUINFO_INT_REGISTER + I860_R21: info->i = cpustate->iregs[21]; break;
+ case CPUINFO_INT_REGISTER + I860_R22: info->i = cpustate->iregs[22]; break;
+ case CPUINFO_INT_REGISTER + I860_R23: info->i = cpustate->iregs[23]; break;
+ case CPUINFO_INT_REGISTER + I860_R24: info->i = cpustate->iregs[24]; break;
+ case CPUINFO_INT_REGISTER + I860_R25: info->i = cpustate->iregs[25]; break;
+ case CPUINFO_INT_REGISTER + I860_R26: info->i = cpustate->iregs[26]; break;
+ case CPUINFO_INT_REGISTER + I860_R27: info->i = cpustate->iregs[27]; break;
+ case CPUINFO_INT_REGISTER + I860_R28: info->i = cpustate->iregs[28]; break;
+ case CPUINFO_INT_REGISTER + I860_R29: info->i = cpustate->iregs[29]; break;
+ case CPUINFO_INT_REGISTER + I860_R30: info->i = cpustate->iregs[30]; break;
+ case CPUINFO_INT_REGISTER + I860_R31: info->i = cpustate->iregs[31]; break;
+
+ case CPUINFO_INT_REGISTER + I860_F0: CPU_GET_INFO_INT_F(0); break;
+ case CPUINFO_INT_REGISTER + I860_F1: CPU_GET_INFO_INT_F(1); break;
+ case CPUINFO_INT_REGISTER + I860_F2: CPU_GET_INFO_INT_F(2); break;
+ case CPUINFO_INT_REGISTER + I860_F3: CPU_GET_INFO_INT_F(3); break;
+ case CPUINFO_INT_REGISTER + I860_F4: CPU_GET_INFO_INT_F(4); break;
+ case CPUINFO_INT_REGISTER + I860_F5: CPU_GET_INFO_INT_F(5); break;
+ case CPUINFO_INT_REGISTER + I860_F6: CPU_GET_INFO_INT_F(6); break;
+ case CPUINFO_INT_REGISTER + I860_F7: CPU_GET_INFO_INT_F(7); break;
+ case CPUINFO_INT_REGISTER + I860_F8: CPU_GET_INFO_INT_F(8); break;
+ case CPUINFO_INT_REGISTER + I860_F9: CPU_GET_INFO_INT_F(9); break;
+ case CPUINFO_INT_REGISTER + I860_F10: CPU_GET_INFO_INT_F(10); break;
+ case CPUINFO_INT_REGISTER + I860_F11: CPU_GET_INFO_INT_F(11); break;
+ case CPUINFO_INT_REGISTER + I860_F12: CPU_GET_INFO_INT_F(12); break;
+ case CPUINFO_INT_REGISTER + I860_F13: CPU_GET_INFO_INT_F(13); break;
+ case CPUINFO_INT_REGISTER + I860_F14: CPU_GET_INFO_INT_F(14); break;
+ case CPUINFO_INT_REGISTER + I860_F15: CPU_GET_INFO_INT_F(15); break;
+ case CPUINFO_INT_REGISTER + I860_F16: CPU_GET_INFO_INT_F(16); break;
+ case CPUINFO_INT_REGISTER + I860_F17: CPU_GET_INFO_INT_F(17); break;
+ case CPUINFO_INT_REGISTER + I860_F18: CPU_GET_INFO_INT_F(18); break;
+ case CPUINFO_INT_REGISTER + I860_F19: CPU_GET_INFO_INT_F(19); break;
+ case CPUINFO_INT_REGISTER + I860_F20: CPU_GET_INFO_INT_F(20); break;
+ case CPUINFO_INT_REGISTER + I860_F21: CPU_GET_INFO_INT_F(21); break;
+ case CPUINFO_INT_REGISTER + I860_F22: CPU_GET_INFO_INT_F(22); break;
+ case CPUINFO_INT_REGISTER + I860_F23: CPU_GET_INFO_INT_F(23); break;
+ case CPUINFO_INT_REGISTER + I860_F24: CPU_GET_INFO_INT_F(24); break;
+ case CPUINFO_INT_REGISTER + I860_F25: CPU_GET_INFO_INT_F(25); break;
+ case CPUINFO_INT_REGISTER + I860_F26: CPU_GET_INFO_INT_F(26); break;
+ case CPUINFO_INT_REGISTER + I860_F27: CPU_GET_INFO_INT_F(27); break;
+ case CPUINFO_INT_REGISTER + I860_F28: CPU_GET_INFO_INT_F(28); break;
+ case CPUINFO_INT_REGISTER + I860_F29: CPU_GET_INFO_INT_F(29); break;
+ case CPUINFO_INT_REGISTER + I860_F30: CPU_GET_INFO_INT_F(30); break;
+ case CPUINFO_INT_REGISTER + I860_F31: CPU_GET_INFO_INT_F(31); break;
+
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(i860); break;
case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(i860); break;
case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(i860); break;
@@ -98,16 +292,90 @@ CPU_GET_INFO( i860 )
case CPUINFO_FCT_READ: info->read = NULL; break;
case CPUINFO_FCT_WRITE: info->write = NULL; break;
case CPUINFO_FCT_READOP: info->readop = NULL; break;
- case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &i860->icount; break;
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cpustate->icount; break;
- // --- the following bits of info are returned as NULL-terminated strings ---
- case CPUINFO_STR_NAME: strcpy(info->s, "i860"); break;
- case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Intel"); break;
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case CPUINFO_STR_NAME: strcpy(info->s, "i860XR"); break;
+ case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Intel i860"); break;
case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "0.1"); break;
case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
- case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Jason Eckhardt and Andrew Gardner"); break;
+ case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Jason Eckhardt"); break;
+
+ case CPUINFO_STR_FLAGS:
+ strcpy(info->s, ""); break;
+
+ case CPUINFO_STR_REGISTER + I860_PC: sprintf(info->s, "PC : %08x", cpustate->pc); break;
+ case CPUINFO_STR_REGISTER + I860_FIR: sprintf(info->s, "FIR : %08x", cpustate->cregs[CR_FIR]); break;
+ case CPUINFO_STR_REGISTER + I860_PSR: sprintf(info->s, "PSR : %08x", cpustate->cregs[CR_PSR]); break;
+ case CPUINFO_STR_REGISTER + I860_DIRBASE: sprintf(info->s, "DIRBASE : %08x", cpustate->cregs[CR_DIRBASE]);break;
+ case CPUINFO_STR_REGISTER + I860_DB: sprintf(info->s, "DB : %08x", cpustate->cregs[CR_DB]); break;
+ case CPUINFO_STR_REGISTER + I860_FSR: sprintf(info->s, "FSR : %08x", cpustate->cregs[CR_FSR]); break;
+ case CPUINFO_STR_REGISTER + I860_EPSR: sprintf(info->s, "EPSR : %08x", cpustate->cregs[CR_EPSR]); break;
+
+ case CPUINFO_STR_REGISTER + I860_R0: sprintf(info->s, "R0 : %08x", cpustate->iregs[0]); break;
+ case CPUINFO_STR_REGISTER + I860_R1: sprintf(info->s, "R1 : %08x", cpustate->iregs[1]); break;
+ case CPUINFO_STR_REGISTER + I860_R2: sprintf(info->s, "R2 : %08x", cpustate->iregs[2]); break;
+ case CPUINFO_STR_REGISTER + I860_R3: sprintf(info->s, "R3 : %08x", cpustate->iregs[3]); break;
+ case CPUINFO_STR_REGISTER + I860_R4: sprintf(info->s, "R4 : %08x", cpustate->iregs[4]); break;
+ case CPUINFO_STR_REGISTER + I860_R5: sprintf(info->s, "R5 : %08x", cpustate->iregs[5]); break;
+ case CPUINFO_STR_REGISTER + I860_R6: sprintf(info->s, "R6 : %08x", cpustate->iregs[6]); break;
+ case CPUINFO_STR_REGISTER + I860_R7: sprintf(info->s, "R7 : %08x", cpustate->iregs[7]); break;
+ case CPUINFO_STR_REGISTER + I860_R8: sprintf(info->s, "R8 : %08x", cpustate->iregs[8]); break;
+ case CPUINFO_STR_REGISTER + I860_R9: sprintf(info->s, "R9 : %08x", cpustate->iregs[9]); break;
+ case CPUINFO_STR_REGISTER + I860_R10: sprintf(info->s, "R10 : %08x", cpustate->iregs[10]); break;
+ case CPUINFO_STR_REGISTER + I860_R11: sprintf(info->s, "R11 : %08x", cpustate->iregs[11]); break;
+ case CPUINFO_STR_REGISTER + I860_R12: sprintf(info->s, "R12 : %08x", cpustate->iregs[12]); break;
+ case CPUINFO_STR_REGISTER + I860_R13: sprintf(info->s, "R13 : %08x", cpustate->iregs[13]); break;
+ case CPUINFO_STR_REGISTER + I860_R14: sprintf(info->s, "R14 : %08x", cpustate->iregs[14]); break;
+ case CPUINFO_STR_REGISTER + I860_R15: sprintf(info->s, "R15 : %08x", cpustate->iregs[15]); break;
+ case CPUINFO_STR_REGISTER + I860_R16: sprintf(info->s, "R16 : %08x", cpustate->iregs[16]); break;
+ case CPUINFO_STR_REGISTER + I860_R17: sprintf(info->s, "R17 : %08x", cpustate->iregs[17]); break;
+ case CPUINFO_STR_REGISTER + I860_R18: sprintf(info->s, "R18 : %08x", cpustate->iregs[18]); break;
+ case CPUINFO_STR_REGISTER + I860_R19: sprintf(info->s, "R19 : %08x", cpustate->iregs[19]); break;
+ case CPUINFO_STR_REGISTER + I860_R20: sprintf(info->s, "R20 : %08x", cpustate->iregs[20]); break;
+ case CPUINFO_STR_REGISTER + I860_R21: sprintf(info->s, "R21 : %08x", cpustate->iregs[21]); break;
+ case CPUINFO_STR_REGISTER + I860_R22: sprintf(info->s, "R22 : %08x", cpustate->iregs[22]); break;
+ case CPUINFO_STR_REGISTER + I860_R23: sprintf(info->s, "R23 : %08x", cpustate->iregs[23]); break;
+ case CPUINFO_STR_REGISTER + I860_R24: sprintf(info->s, "R24 : %08x", cpustate->iregs[24]); break;
+ case CPUINFO_STR_REGISTER + I860_R25: sprintf(info->s, "R25 : %08x", cpustate->iregs[25]); break;
+ case CPUINFO_STR_REGISTER + I860_R26: sprintf(info->s, "R26 : %08x", cpustate->iregs[26]); break;
+ case CPUINFO_STR_REGISTER + I860_R27: sprintf(info->s, "R27 : %08x", cpustate->iregs[27]); break;
+ case CPUINFO_STR_REGISTER + I860_R28: sprintf(info->s, "R28 : %08x", cpustate->iregs[28]); break;
+ case CPUINFO_STR_REGISTER + I860_R29: sprintf(info->s, "R29 : %08x", cpustate->iregs[29]); break;
+ case CPUINFO_STR_REGISTER + I860_R30: sprintf(info->s, "R30 : %08x", cpustate->iregs[30]); break;
+ case CPUINFO_STR_REGISTER + I860_R31: sprintf(info->s, "R31 : %08x", cpustate->iregs[31]); break;
- case CPUINFO_INT_PC: info->i = i860->pc; break;
- case CPUINFO_INT_PREVIOUSPC: info->i = i860->ppc; break;
+ case CPUINFO_STR_REGISTER + I860_F0: CPU_GET_INFO_STR_F(0); break;
+ case CPUINFO_STR_REGISTER + I860_F1: CPU_GET_INFO_STR_F(1); break;
+ case CPUINFO_STR_REGISTER + I860_F2: CPU_GET_INFO_STR_F(2); break;
+ case CPUINFO_STR_REGISTER + I860_F3: CPU_GET_INFO_STR_F(3); break;
+ case CPUINFO_STR_REGISTER + I860_F4: CPU_GET_INFO_STR_F(4); break;
+ case CPUINFO_STR_REGISTER + I860_F5: CPU_GET_INFO_STR_F(5); break;
+ case CPUINFO_STR_REGISTER + I860_F6: CPU_GET_INFO_STR_F(6); break;
+ case CPUINFO_STR_REGISTER + I860_F7: CPU_GET_INFO_STR_F(7); break;
+ case CPUINFO_STR_REGISTER + I860_F8: CPU_GET_INFO_STR_F(8); break;
+ case CPUINFO_STR_REGISTER + I860_F9: CPU_GET_INFO_STR_F(9); break;
+ case CPUINFO_STR_REGISTER + I860_F10: CPU_GET_INFO_STR_F(10); break;
+ case CPUINFO_STR_REGISTER + I860_F11: CPU_GET_INFO_STR_F(11); break;
+ case CPUINFO_STR_REGISTER + I860_F12: CPU_GET_INFO_STR_F(12); break;
+ case CPUINFO_STR_REGISTER + I860_F13: CPU_GET_INFO_STR_F(13); break;
+ case CPUINFO_STR_REGISTER + I860_F14: CPU_GET_INFO_STR_F(14); break;
+ case CPUINFO_STR_REGISTER + I860_F15: CPU_GET_INFO_STR_F(15); break;
+ case CPUINFO_STR_REGISTER + I860_F16: CPU_GET_INFO_STR_F(16); break;
+ case CPUINFO_STR_REGISTER + I860_F17: CPU_GET_INFO_STR_F(17); break;
+ case CPUINFO_STR_REGISTER + I860_F18: CPU_GET_INFO_STR_F(18); break;
+ case CPUINFO_STR_REGISTER + I860_F19: CPU_GET_INFO_STR_F(19); break;
+ case CPUINFO_STR_REGISTER + I860_F20: CPU_GET_INFO_STR_F(20); break;
+ case CPUINFO_STR_REGISTER + I860_F21: CPU_GET_INFO_STR_F(21); break;
+ case CPUINFO_STR_REGISTER + I860_F22: CPU_GET_INFO_STR_F(22); break;
+ case CPUINFO_STR_REGISTER + I860_F23: CPU_GET_INFO_STR_F(23); break;
+ case CPUINFO_STR_REGISTER + I860_F24: CPU_GET_INFO_STR_F(24); break;
+ case CPUINFO_STR_REGISTER + I860_F25: CPU_GET_INFO_STR_F(25); break;
+ case CPUINFO_STR_REGISTER + I860_F26: CPU_GET_INFO_STR_F(26); break;
+ case CPUINFO_STR_REGISTER + I860_F27: CPU_GET_INFO_STR_F(27); break;
+ case CPUINFO_STR_REGISTER + I860_F28: CPU_GET_INFO_STR_F(28); break;
+ case CPUINFO_STR_REGISTER + I860_F29: CPU_GET_INFO_STR_F(29); break;
+ case CPUINFO_STR_REGISTER + I860_F30: CPU_GET_INFO_STR_F(30); break;
+ case CPUINFO_STR_REGISTER + I860_F31: CPU_GET_INFO_STR_F(31); break;
}
}
diff --git a/src/emu/cpu/i860/i860.h b/src/emu/cpu/i860/i860.h
index caf6af58200..ed843ea4b11 100644
--- a/src/emu/cpu/i860/i860.h
+++ b/src/emu/cpu/i860/i860.h
@@ -1,3 +1,18 @@
+/***************************************************************************
+
+ i860.h
+
+ Interface file for the Intel i860 emulator.
+
+ Copyright (C) 1995-present Jason Eckhardt (jle@rice.edu)
+ Released for general non-commercial use under the MAME license
+ with the additional requirement that you are free to use and
+ redistribute this code in modified or unmodified form, provided
+ you list me in the credits.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
#pragma once
#ifndef __I860_H__
@@ -5,13 +20,199 @@
#include "cpuintrf.h"
+/***************************************************************************
+ REGISTER ENUMERATION
+***************************************************************************/
+
enum
{
- I860_PC = 0
+ I860_PC = 1,
+
+ I860_FIR,
+ I860_PSR,
+ I860_DIRBASE,
+ I860_DB,
+ I860_FSR,
+ I860_EPSR,
+
+ I860_R0, I860_R1, I860_R2, I860_R3, I860_R4, I860_R5, I860_R6, I860_R7, I860_R8, I860_R9,
+ I860_R10, I860_R11, I860_R12, I860_R13, I860_R14, I860_R15, I860_R16, I860_R17, I860_R18, I860_R19,
+ I860_R20, I860_R21, I860_R22, I860_R23, I860_R24, I860_R25, I860_R26, I860_R27, I860_R28, I860_R29,
+ I860_R30, I860_R31,
+
+ I860_F0, I860_F1, I860_F2, I860_F3, I860_F4, I860_F5, I860_F6, I860_F7, I860_F8, I860_F9,
+ I860_F10, I860_F11, I860_F12, I860_F13, I860_F14, I860_F15, I860_F16, I860_F17, I860_F18, I860_F19,
+ I860_F20, I860_F21, I860_F22, I860_F23, I860_F24, I860_F25, I860_F26, I860_F27, I860_F28, I860_F29,
+ I860_F30, I860_F31,
+
};
+/* Needed for MAME */
CPU_GET_INFO( i860 );
#define CPU_I860 CPU_GET_INFO_NAME( i860 )
+
+/***************************************************************************
+ STRUCTURES & TYPEDEFS
+***************************************************************************/
+
+/* i860 state. */
+typedef struct {
+ /* Integer registers (32 x 32-bits). */
+ UINT32 iregs[32];
+
+ /* Floating point registers (32 x 32-bits, 16 x 64 bits, or 8 x 128 bits).
+ When referenced as pairs or quads, the higher numbered registers
+ are the upper bits. E.g., double precision f0 is f1:f0. */
+ UINT8 frg[32 * 4];
+
+ /* Control registers (6 x 32-bits). */
+ UINT32 cregs[6];
+
+ /* Program counter (1 x 32-bits). Reset starts at pc=0xffffff00. */
+ UINT32 pc;
+
+ /* Special registers (4 x 64-bits). */
+ union
+ {
+ float s;
+ double d;
+ } KR, KI, T;
+ UINT64 merge;
+
+ /* The adder pipeline, always 3 stages. */
+ struct
+ {
+ /* The stage contents. */
+ union {
+ float s;
+ double d;
+ } val;
+
+ /* The stage status bits. */
+ struct {
+ /* Adder result precision (1 = dbl, 0 = sgl). */
+ char arp;
+ } stat;
+ } A[3];
+
+ /* The multiplier pipeline. 3 stages for single precision, 2 stages
+ for double precision, and confusing for mixed precision. */
+ struct {
+ /* The stage contents. */
+ union {
+ float s;
+ double d;
+ } val;
+
+ /* The stage status bits. */
+ struct {
+ /* Multiplier result precision (1 = dbl, 0 = sgl). */
+ char mrp;
+ } stat;
+ } M[3];
+
+ /* The load pipeline, always 3 stages. */
+ struct {
+ /* The stage contents. */
+ union {
+ float s;
+ double d;
+ } val;
+
+ /* The stage status bits. */
+ struct {
+ /* Load result precision (1 = dbl, 0 = sgl). */
+ char lrp;
+ } stat;
+ } L[3];
+
+ /* The graphics/integer pipeline, always 1 stage. */
+ struct {
+ /* The stage contents. */
+ union {
+ float s;
+ double d;
+ } val;
+
+ /* The stage status bits. */
+ struct {
+ /* Integer/graphics result precision (1 = dbl, 0 = sgl). */
+ char irp;
+ } stat;
+ } G;
+
+ /* Pins. */
+ int pin_bus_hold;
+ int pin_reset;
+
+ /*
+ * Other emulator state.
+ */
+ int exiting_readmem;
+ int exiting_ifetch;
+
+ /* Indicate a control-flow instruction, so we know the PC is updated. */
+ int pc_updated;
+
+ /* Indicate an instruction just generated a trap, so we know the PC
+ needs to go to the trap address. */
+ int pending_trap;
+
+ /* This is 1 if the next fir load gets the trap address, otherwise
+ it is 0 to get the ld.c address. This is set to 1 only when a
+ non-reset trap occurs. */
+ int fir_gets_trap_addr;
+
+ /* Single stepping flag for internal use. */
+ int single_stepping;
+
+ /*
+ * MAME-specific stuff.
+ */
+ const device_config *device;
+ const address_space *program;
+ UINT32 ppc;
+ int icount;
+
+} i860_state_t;
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+/* This is the external interface for asserting an external interrupt
+ to the i860. */
+extern void i860_gen_interrupt(i860_state_t*);
+
+/* This is the external interface for asserting/deasserting a pin on
+ the i860. */
+extern void i860_set_pin(i860_state_t*, int, int);
+
+/* Hard or soft reset. */
+extern void reset_i860(i860_state_t*);
+
+/* i860 pins. */
+enum {
+ DEC_PIN_BUS_HOLD, /* Bus HOLD pin. */
+ DEC_PIN_RESET /* System reset pin. */
+};
+
+
+/* TODO: THESE WILL BE REPLACED BY MAME FUNCTIONS
+#define BYTE_REV32(t) \
+ do { \
+ (t) = ((UINT32)(t) >> 16) | ((UINT32)(t) << 16); \
+ (t) = (((UINT32)(t) >> 8) & 0x00ff00ff) | (((UINT32)(t) << 8) & 0xff00ff00); \
+ } while (0);
+
+#define BYTE_REV16(t) \
+ do { \
+ (t) = (((UINT16)(t) >> 8) & 0x00ff) | (((UINT16)(t) << 8) & 0xff00); \
+ } while (0);
+#endif
+*/
+
#endif /* __I860_H__ */
diff --git a/src/emu/cpu/i860/i860dec.c b/src/emu/cpu/i860/i860dec.c
new file mode 100644
index 00000000000..75c76e00647
--- /dev/null
+++ b/src/emu/cpu/i860/i860dec.c
@@ -0,0 +1,4722 @@
+/***************************************************************************
+
+ i860dec.c
+
+ Execution engine for the Intel i860 emulator.
+
+ Copyright (C) 1995-present Jason Eckhardt (jle@rice.edu)
+ Released for general non-commercial use under the MAME license
+ with the additional requirement that you are free to use and
+ redistribute this code in modified or unmodified form, provided
+ you list me in the credits.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+/*
+ * References:
+ * `i860 Microprocessor Programmer's Reference Manual', Intel, 1990.
+ *
+ * This code was originally written by Jason Eckhardt as part of an
+ * emulator for some i860-based Unix workstations (early 1990's) such
+ * as the Stardent Vistra 800 series and the OkiStation/i860 7300 series.
+ * The code you are reading now is the i860 CPU portion only, which has
+ * been adapted to (and simplified for) MAME.
+ * MAME-specific notes:
+ * - i860XR emulation only (i860XP unnecessary for MAME).
+ * - No emulation of data and instruction caches (unnecessary for MAME version).
+ * - No emulation of DIM mode or CS8 mode (unnecessary for MAME version).
+ * - No BL/IL/locked sequences (unnecessary for MAME).
+ * - Emulate only the i860's LSB-first mode (BE = 0).
+ * Generic notes:
+ * - There is some amount of code duplication (e.g., see the
+ * various insn_* routines for the branches and FP routines) that
+ * could be eliminated.
+ * - The host's floating point types are used to emulate the i860's
+ * floating point. Should probably be made machine independent by
+ * using an IEEE FP emulation library. On the other hand, most machines
+ * today also use IEEE FP.
+ *
+ */
+#include "i860.h"
+#include <math.h>
+
+
+#ifdef LSB_FIRST
+#undef HOST_MSB
+#else
+#define HOST_MSB
+#endif
+
+
+#undef TRACE_RDWR_MEM
+#undef TRACE_ADDR_TRANSLATION
+#undef TRACE_PAGE_FAULT
+#define TRACE_UNDEFINED_I860
+#undef TRACE_EXT_INT
+#define TRACE_UNALIGNED_MEM
+
+
+
+#define i860s i860_state_t
+
+
+/* Prototypes. */
+static void decode_exec (i860s *, UINT32, UINT32);
+static UINT32 get_address_translation (i860s *, UINT32, int, int);
+static UINT32 readmemi_emu (i860s *cpustate, UINT32, int);
+
+//static void debugger (i860s *cpustate);
+//static void disasm (i860s *cpustate, UINT32, int);
+//static void dump_state (i860s *cpustate);
+
+
+
+
+/* Defines for pending_trap. */
+enum {
+ TRAP_NORMAL = 0x01,
+ TRAP_IN_DELAY_SLOT = 0x02,
+ TRAP_WAS_EXTERNAL = 0x04
+};
+
+
+
+
+/* Get/set general register value -- watch for r0 on writes. */
+#define get_iregval(gr) (cpustate->iregs[(gr)])
+#define set_iregval(gr, val) (cpustate->iregs[(gr)] = ((gr) == 0 ? 0 : (val)))
+
+INLINE float get_fregval_s (i860s *cpustate, int fr)
+{
+ float f;
+ UINT32 x;
+ UINT8 *tp;
+ fr = 31 - fr;
+ tp = (UINT8 *)(&cpustate->frg[fr * 4]);
+ x = ((UINT32)tp[0] << 24) | ((UINT32)tp[1] << 16) |
+ ((UINT32)tp[2] << 8) | ((UINT32)tp[3]);
+ f = *(float *)(&x);
+ return f;
+}
+
+INLINE double get_fregval_d (i860s *cpustate, int fr)
+{
+ double d;
+ UINT64 x;
+ UINT8 *tp;
+ fr = 31 - (fr + 1);
+ tp = (UINT8 *)(&cpustate->frg[fr * 4]);
+ x = ((UINT64)tp[0] << 56) | ((UINT64)tp[1] << 48) |
+ ((UINT64)tp[2] << 40) | ((UINT64)tp[3] << 32) |
+ ((UINT64)tp[4] << 24) | ((UINT64)tp[5] << 16) |
+ ((UINT64)tp[6] << 8) | ((UINT64)tp[7]);
+ d = *(double *)(&x);
+ return d;
+}
+
+INLINE void set_fregval_s (i860s *cpustate, int fr, float s)
+{
+ UINT8 *f = (UINT8 *)&s;
+ UINT8 *tp;
+ int newfr = 31 - fr;
+ float jj = s;
+ tp = (UINT8 *)(&cpustate->frg[newfr * 4]);
+
+ f = (UINT8 *)(&jj);
+ if (fr == 0 || fr == 1)
+ {
+ tp[0] = 0; tp[1] = 0; tp[2] = 0; tp[3] = 0;
+ }
+ else
+ {
+#ifndef HOST_MSB
+ tp[0] = f[3]; tp[1] = f[2]; tp[2] = f[1]; tp[3] = f[0];
+#else
+ tp[0] = f[0]; tp[1] = f[1]; tp[2] = f[2]; tp[3] = f[3];
+#endif
+ }
+}
+
+INLINE void set_fregval_d (i860s *cpustate, int fr, double d)
+{
+ UINT8 *f = (UINT8 *)&d;
+ UINT8 *tp;
+ int newfr = 31 - (fr + 1);
+ double jj = d;
+ tp = (UINT8 *)(&cpustate->frg[newfr * 4]);
+
+ f = (UINT8 *)(&jj);
+
+ if (fr == 0)
+ {
+ tp[0] = 0; tp[1] = 0; tp[2] = 0; tp[3] = 0;
+ tp[4] = 0; tp[5] = 0; tp[6] = 0; tp[7] = 0;
+ }
+ else
+ {
+#ifndef HOST_MSB
+ tp[0] = f[7]; tp[1] = f[6]; tp[2] = f[5]; tp[3] = f[4];
+ tp[4] = f[3]; tp[5] = f[2]; tp[6] = f[1]; tp[7] = f[0];
+#else
+ tp[0] = f[0]; tp[1] = f[1]; tp[2] = f[2]; tp[3] = f[3];
+ tp[4] = f[4]; tp[5] = f[5]; tp[6] = f[6]; tp[7] = f[7];
+#endif
+ }
+}
+
+
+/* Macros for accessing register fields in instruction word. */
+#define get_isrc1(bits) (((bits) >> 11) & 0x1f)
+#define get_isrc2(bits) (((bits) >> 21) & 0x1f)
+#define get_idest(bits) (((bits) >> 16) & 0x1f)
+#define get_fsrc1(bits) (((bits) >> 11) & 0x1f)
+#define get_fsrc2(bits) (((bits) >> 21) & 0x1f)
+#define get_fdest(bits) (((bits) >> 16) & 0x1f)
+#define get_creg(bits) (((bits) >> 21) & 0x7)
+
+/* Macros for accessing immediate fields. */
+/* 16-bit immediate. */
+#define get_imm16(insn) ((insn) & 0xffff)
+
+/* Control register numbers. */
+enum {
+ CR_FIR = 0,
+ CR_PSR = 1,
+ CR_DIRBASE = 2,
+ CR_DB = 3,
+ CR_FSR = 4,
+ CR_EPSR = 5
+};
+
+/* A mask for all the trap bits of the PSR (FT, DAT, IAT, IN, IT, or
+ bits [12..8]). */
+#define PSR_ALL_TRAP_BITS_MASK 0x00001f00
+
+/* A mask for PSR bits which can only be changed from supervisor level. */
+#define PSR_SUPERVISOR_ONLY_MASK 0x0000fff3
+
+
+/* PSR: BR flag (PSR[0]): set/get. */
+#define GET_PSR_BR() ((cpustate->cregs[CR_PSR] >> 0) & 1)
+#define SET_PSR_BR(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~(1 << 0)) | (((val) & 1) << 0))
+
+/* PSR: BW flag (PSR[1]): set/get. */
+#define GET_PSR_BW() ((cpustate->cregs[CR_PSR] >> 1) & 1)
+#define SET_PSR_BW(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~(1 << 1)) | (((val) & 1) << 1))
+
+/* PSR: Shift count (PSR[21..17]): set/get. */
+#define GET_PSR_SC() ((cpustate->cregs[CR_PSR] >> 17) & 0x1f)
+#define SET_PSR_SC(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~0x003e0000) | (((val) & 0x1f) << 17))
+
+/* PSR: CC flag (PSR[2]): set/get. */
+#define GET_PSR_CC() ((cpustate->cregs[CR_PSR] >> 2) & 1)
+#define SET_PSR_CC(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~(1 << 2)) | (((val) & 1) << 2))
+
+/* PSR: IT flag (PSR[8]): set/get. */
+#define GET_PSR_IT() ((cpustate->cregs[CR_PSR] >> 8) & 1)
+#define SET_PSR_IT(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~(1 << 8)) | (((val) & 1) << 8))
+
+/* PSR: IN flag (PSR[9]): set/get. */
+#define GET_PSR_IN() ((cpustate->cregs[CR_PSR] >> 9) & 1)
+#define SET_PSR_IN(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~(1 << 9)) | (((val) & 1) << 9))
+
+/* PSR: IAT flag (PSR[10]): set/get. */
+#define GET_PSR_IAT() ((cpustate->cregs[CR_PSR] >> 10) & 1)
+#define SET_PSR_IAT(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~(1 << 10)) | (((val) & 1) << 10))
+
+/* PSR: DAT flag (PSR[11]): set/get. */
+#define GET_PSR_DAT() ((cpustate->cregs[CR_PSR] >> 11) & 1)
+#define SET_PSR_DAT(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~(1 << 11)) | (((val) & 1) << 11))
+
+/* PSR: FT flag (PSR[12]): set/get. */
+#define GET_PSR_FT() ((cpustate->cregs[CR_PSR] >> 12) & 1)
+#define SET_PSR_FT(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~(1 << 12)) | (((val) & 1) << 12))
+
+/* PSR: DS flag (PSR[13]): set/get. */
+#define GET_PSR_DS() ((cpustate->cregs[CR_PSR] >> 13) & 1)
+#define SET_PSR_DS(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~(1 << 13)) | (((val) & 1) << 13))
+
+/* PSR: DIM flag (PSR[14]): set/get. */
+#define GET_PSR_DIM() ((cpustate->cregs[CR_PSR] >> 14) & 1)
+#define SET_PSR_DIM(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~(1 << 14)) | (((val) & 1) << 14))
+
+/* PSR: LCC (PSR[3]): set/get. */
+#define GET_PSR_LCC() ((cpustate->cregs[CR_PSR] >> 3) & 1)
+#define SET_PSR_LCC(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~(1 << 3)) | (((val) & 1) << 3))
+
+/* PSR: IM (PSR[4]): set/get. */
+#define GET_PSR_IM() ((cpustate->cregs[CR_PSR] >> 4) & 1)
+#define SET_PSR_IM(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~(1 << 4)) | (((val) & 1) << 4))
+
+/* PSR: PIM (PSR[5]): set/get. */
+#define GET_PSR_PIM() ((cpustate->cregs[CR_PSR] >> 5) & 1)
+#define SET_PSR_PIM(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~(1 << 5)) | (((val) & 1) << 5))
+
+/* PSR: U (PSR[6]): set/get. */
+#define GET_PSR_U() ((cpustate->cregs[CR_PSR] >> 6) & 1)
+#define SET_PSR_U(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~(1 << 6)) | (((val) & 1) << 6))
+
+/* PSR: PU (PSR[7]): set/get. */
+#define GET_PSR_PU() ((cpustate->cregs[CR_PSR] >> 7) & 1)
+#define SET_PSR_PU(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~(1 << 7)) | (((val) & 1) << 7))
+
+/* PSR: Pixel size (PSR[23..22]): set/get. */
+#define GET_PSR_PS() ((cpustate->cregs[CR_PSR] >> 22) & 0x3)
+#define SET_PSR_PS(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~0x00c00000) | (((val) & 0x3) << 22))
+
+/* PSR: Pixel mask (PSR[31..24]): set/get. */
+#define GET_PSR_PM() ((cpustate->cregs[CR_PSR] >> 24) & 0xff)
+#define SET_PSR_PM(val) (cpustate->cregs[CR_PSR] = (cpustate->cregs[CR_PSR] & ~0xff000000) | (((val) & 0xff) << 24))
+
+/* EPSR: WP bit (EPSR[14]): set/get. */
+#define GET_EPSR_WP() ((cpustate->cregs[CR_EPSR] >> 14) & 1)
+#define SET_EPSR_WP(val) (cpustate->cregs[CR_EPSR] = (cpustate->cregs[CR_EPSR] & ~(1 << 14)) | (((val) & 1) << 14))
+
+/* EPSR: INT bit (EPSR[17]): set/get. */
+#define GET_EPSR_INT() ((cpustate->cregs[CR_EPSR] >> 17) & 1)
+#define SET_EPSR_INT(val) (cpustate->cregs[CR_EPSR] = (cpustate->cregs[CR_EPSR] & ~(1 << 17)) | (((val) & 1) << 17))
+
+
+/* EPSR: OF flag (EPSR[24]): set/get. */
+#define GET_EPSR_OF() ((cpustate->cregs[CR_EPSR] >> 24) & 1)
+#define SET_EPSR_OF(val) (cpustate->cregs[CR_EPSR] = (cpustate->cregs[CR_EPSR] & ~(1 << 24)) | (((val) & 1) << 24))
+
+/* EPSR: BE flag (EPSR[23]): set/get. */
+#define GET_EPSR_BE() ((cpustate->cregs[CR_EPSR] >> 23) & 1)
+#define SET_EPSR_BE(val) (cpustate->cregs[CR_EPSR] = (cpustate->cregs[CR_EPSR] & ~(1 << 23)) | (((val) & 1) << 23))
+
+/* DIRBASE: ATE bit (DIRBASE[0]): get. */
+#define GET_DIRBASE_ATE() (cpustate->cregs[CR_DIRBASE] & 1)
+
+/* DIRBASE: CS8 bit (DIRBASE[7]): get. */
+#define GET_DIRBASE_CS8() ((cpustate->cregs[CR_DIRBASE] >> 7) & 1)
+
+/* FSR: FTE bit (FSR[5]): set/get. */
+#define GET_FSR_FTE() ((cpustate->cregs[CR_FSR] >> 5) & 1)
+#define SET_FSR_FTE(val) (cpustate->cregs[CR_FSR] = (cpustate->cregs[CR_FSR] & ~(1 << 5)) | (((val) & 1) << 5))
+
+/* FSR: SE bit (FSR[8]): set/get. */
+#define GET_FSR_SE() ((cpustate->cregs[CR_FSR] >> 8) & 1)
+#define SET_FSR_SE(val) (cpustate->cregs[CR_FSR] = (cpustate->cregs[CR_FSR] & ~(1 << 8)) | (((val) & 1) << 8))
+
+
+/*
+static int has_delay_slot(UINT32 insn)
+{
+ int opc = (insn >> 26) & 0x3f;
+ if (opc == 0x10 || opc == 0x1a || opc == 0x1b || opc == 0x1d ||
+ opc == 0x1f || opc == 0x2d || (opc == 0x13 && (insn & 3) == 2))
+ return 1;
+ return 0;
+}
+*/
+
+/* This is the external interface for asserting/deasserting pins on
+ the i860. */
+void i860_set_pin (i860s *cpustate, int pin, int val)
+{
+ if (pin == DEC_PIN_BUS_HOLD)
+ cpustate->pin_bus_hold = val;
+ else if (pin == DEC_PIN_RESET)
+ cpustate->pin_reset = val;
+ else
+ assert (0);
+}
+
+
+/* This is the external interface for indicating an external interrupt
+ to the i860. */
+void i860_gen_interrupt (i860s *cpustate)
+{
+ /* If interrupts are enabled, then set PSR.IN and prepare for trap.
+ Otherwise, the external interrupt is ignored. We also set
+ bit EPSR.INT (which tracks the INT pin). */
+ if (GET_PSR_IM ())
+ {
+ SET_PSR_IN (1);
+ SET_EPSR_INT (1);
+ cpustate->pending_trap = TRAP_WAS_EXTERNAL;
+ }
+
+#ifdef TRACE_EXT_INT
+ fprintf (stderr, "i860_gen_interrupt: External interrupt received ");
+ if (GET_PSR_IM ())
+ fprintf (stderr, "[PSR.IN set, preparing to trap]\n");
+ else
+ fprintf (stderr, "[ignored (interrupts disabled)]\n");
+#endif
+}
+
+
+/* Fetch instructions from instruction cache.
+ Note: The instruction cache is not implemented for MAME version,
+ this just fetches and returns 1 instruction from memory. */
+static UINT32 ifetch (i860s *cpustate, UINT32 pc)
+{
+ UINT32 phys_pc = 0;
+ UINT32 w1 = 0;
+
+ /* If virtual mode, get translation. */
+ if (GET_DIRBASE_ATE ())
+ {
+ phys_pc = get_address_translation (cpustate, pc, 0 /* is_dataref */, 0 /* is_write */);
+ cpustate->exiting_ifetch = 0;
+ if (cpustate->pending_trap && (GET_PSR_DAT () || GET_PSR_IAT ()))
+ {
+ cpustate->exiting_ifetch = 1;
+ return 0xffeeffee;
+ }
+ }
+ else
+ phys_pc = pc;
+
+ /* Since i860 instructions are always stored LSB first (regardless of
+ the BE bit), we need to adjust the instruction below on MSB hosts. */
+ w1 = memory_read_dword_64le(cpustate->program, phys_pc);
+#ifdef HOST_MSB
+ BYTE_REV32 (w1);
+#endif /* HOST_MSB. */
+ return w1;
+}
+
+
+/* Given a virtual address, perform the i860 address translation and
+ return the corresponding physical address.
+ vaddr: virtual address
+ is_dataref: 1 = load/store, 0 = instruction fetch.
+ is_write: 1 = writing to vaddr, 0 = reading from vaddr
+ The last two arguments are only used to determine what types
+ of traps should be taken.
+
+ Page tables must always be in memory (not cached). So the routine
+ here only accesses memory. */
+static UINT32 get_address_translation (i860s *cpustate, UINT32 vaddr, int is_dataref, int is_write)
+{
+ UINT32 vdir = (vaddr >> 22) & 0x3ff;
+ UINT32 vpage = (vaddr >> 12) & 0x3ff;
+ UINT32 voffset = vaddr & 0xfff;
+ UINT32 dtb = (cpustate->cregs[CR_DIRBASE]) & 0xfffff000;
+ UINT32 pg_dir_entry_a = 0;
+ UINT32 pg_dir_entry = 0;
+ UINT32 pg_tbl_entry_a = 0;
+ UINT32 pg_tbl_entry = 0;
+ UINT32 pfa1 = 0;
+ UINT32 pfa2 = 0;
+ UINT32 ret = 0;
+ UINT32 ttpde = 0;
+ UINT32 ttpte = 0;
+
+ assert (GET_DIRBASE_ATE ());
+
+ /* Get page directory entry at DTB:DIR:00. */
+ pg_dir_entry_a = dtb | (vdir << 2);
+ pg_dir_entry = memory_read_dword_64le(cpustate->program, pg_dir_entry_a);
+#ifdef HOST_MSB
+ BYTE_REV32 (pg_dir_entry);
+#endif
+
+ /* Check for non-present PDE. */
+ if (!(pg_dir_entry & 1))
+ {
+ /* PDE is not present, generate DAT or IAT. */
+ if (is_dataref)
+ SET_PSR_DAT (1);
+ else
+ SET_PSR_IAT (1);
+ cpustate->pending_trap = 1;
+
+ /* Dummy return. */
+ return 0;
+ }
+
+ /* PDE Check for write protection violations. */
+ if (is_write && is_dataref
+ && !(pg_dir_entry & 2) /* W = 0. */
+ && (GET_PSR_U () || GET_EPSR_WP ())) /* PSR_U = 1 or EPSR_WP = 1. */
+ {
+ SET_PSR_DAT (1);
+ cpustate->pending_trap = 1;
+ /* Dummy return. */
+ return 0;
+ }
+
+ /* PDE Check for user-mode access to supervisor pages. */
+ if (GET_PSR_U ()
+ && !(pg_dir_entry & 4)) /* U = 0. */
+ {
+ if (is_dataref)
+ SET_PSR_DAT (1);
+ else
+ SET_PSR_IAT (1);
+ cpustate->pending_trap = 1;
+ /* Dummy return. */
+ return 0;
+ }
+
+ /* FIXME: How exactly to handle A check/update?. */
+
+ /* Get page table entry at PFA1:PAGE:00. */
+ pfa1 = pg_dir_entry & 0xfffff000;
+ pg_tbl_entry_a = pfa1 | (vpage << 2);
+ pg_tbl_entry = memory_read_dword_64le(cpustate->program, pg_tbl_entry_a);
+#ifdef HOST_MSB
+ BYTE_REV32 (pg_tbl_entry);
+#endif
+
+ /* Check for non-present PTE. */
+ if (!(pg_tbl_entry & 1))
+ {
+ /* PTE is not present, generate DAT or IAT. */
+ if (is_dataref)
+ SET_PSR_DAT (1);
+ else
+ SET_PSR_IAT (1);
+ cpustate->pending_trap = 1;
+
+ /* Dummy return. */
+ return 0;
+ }
+
+ /* PTE Check for write protection violations. */
+ if (is_write && is_dataref
+ && !(pg_tbl_entry & 2) /* W = 0. */
+ && (GET_PSR_U () || GET_EPSR_WP ())) /* PSR_U = 1 or EPSR_WP = 1. */
+ {
+ SET_PSR_DAT (1);
+ cpustate->pending_trap = 1;
+ /* Dummy return. */
+ return 0;
+ }
+
+ /* PTE Check for user-mode access to supervisor pages. */
+ if (GET_PSR_U ()
+ && !(pg_tbl_entry & 4)) /* U = 0. */
+ {
+ if (is_dataref)
+ SET_PSR_DAT (1);
+ else
+ SET_PSR_IAT (1);
+ cpustate->pending_trap = 1;
+ /* Dummy return. */
+ return 0;
+ }
+
+ /* Update A bit and check D bit. */
+ ttpde = pg_dir_entry | 0x20;
+ ttpte = pg_tbl_entry | 0x20;
+#ifdef HOST_MSB
+ BYTE_REV32 (ttpde);
+ BYTE_REV32 (ttpte);
+#endif
+ memory_write_dword_64le(cpustate->program, pg_dir_entry_a, ttpde);
+ memory_write_dword_64le(cpustate->program, pg_tbl_entry_a, ttpte);
+
+ if (is_write && is_dataref && (pg_tbl_entry & 0x40) == 0)
+ {
+ /* fprintf(stderr, "DAT trap on write without dirty bit v0x%08x/p0x%08x\n",
+ vaddr, (pg_tbl_entry & ~0xfff)|voffset); */
+ SET_PSR_DAT (1);
+ cpustate->pending_trap = 1;
+ /* Dummy return. */
+ return 0;
+ }
+
+ pfa2 = (pg_tbl_entry & 0xfffff000);
+ ret = pfa2 | voffset;
+
+#ifdef TRACE_ADDR_TRANSLATION
+ fprintf (stderr, "get_address_translation: virt(0x%08x) -> phys(0x%08x)\n",
+ vaddr, ret);
+#endif
+
+ return ret;
+}
+
+
+/* Read memory emulation.
+ addr = address to read.
+ size = size of read in bytes. */
+static UINT32 readmemi_emu (i860s *cpustate, UINT32 addr, int size)
+{
+#ifdef TRACE_RDWR_MEM
+ fprintf (stderr, "readmemi_emu: (ATE=%d) addr = 0x%08x, size = %d\n",
+ GET_DIRBASE_ATE (), addr, size);
+#endif
+
+ /* If virtual mode, do translation. */
+ if (GET_DIRBASE_ATE ())
+ {
+ UINT32 phys = get_address_translation (cpustate, addr, 1 /* is_dataref */, 0 /* is_write */);
+ if (cpustate->pending_trap && (GET_PSR_IAT () || GET_PSR_DAT ()))
+ {
+#ifdef TRACE_PAGE_FAULT
+ fprintf (stderr, "0x%08x: ## Page fault (readmemi_emu).\n",
+ cpustate->pc);
+#endif
+ cpustate->exiting_readmem = 1;
+ return 0;
+ }
+ addr = phys;
+ }
+
+ /* First check for match to db register (before read). */
+ if (((addr & ~(size - 1)) == cpustate->cregs[CR_DB]) && GET_PSR_BR ())
+ {
+ SET_PSR_DAT (1);
+ cpustate->pending_trap = 1;
+ return 0;
+ }
+
+ /* Now do the actual read. */
+ if (size == 1)
+ {
+ UINT32 ret = memory_read_byte_64le(cpustate->program, addr);
+ return ret & 0xff;
+ }
+ else if (size == 2)
+ {
+ UINT32 ret = memory_read_word_64le(cpustate->program, addr);
+#ifdef HOST_MSB
+ BYTE_REV16 (ret);
+#endif
+ return ret & 0xffff;
+ }
+ else if (size == 4)
+ {
+ UINT32 ret = memory_read_dword_64le(cpustate->program, addr);
+#ifdef HOST_MSB
+ BYTE_REV32 (ret);
+#endif
+ return ret;
+ }
+ else
+ assert (0);
+
+ return 0;
+}
+
+
+/* Write memory emulation.
+ addr = address to write.
+ size = size of write in bytes.
+ data = data to write. */
+static void writememi_emu (i860s *cpustate, UINT32 addr, int size, UINT32 data)
+{
+#ifdef TRACE_RDWR_MEM
+ fprintf (stderr, "writememi_emu: (ATE=%d) addr = 0x%08x, size = %d, data = 0x%08x\n",
+ GET_DIRBASE_ATE (), addr, size, data);
+#endif
+
+ /* If virtual mode, do translation. */
+ if (GET_DIRBASE_ATE ())
+ {
+ UINT32 phys = get_address_translation (cpustate, addr, 1 /* is_dataref */, 1 /* is_write */);
+ if (cpustate->pending_trap && (GET_PSR_IAT () || GET_PSR_DAT ()))
+ {
+#ifdef TRACE_PAGE_FAULT
+ fprintf (stderr, "0x%08x: ## Page fault (writememi_emu).\n",
+ cpustate->pc);
+#endif
+ cpustate->exiting_readmem = 2;
+ return;
+ }
+ addr = phys;
+ }
+
+ /* First check for match to db register (before write). */
+ if (((addr & ~(size - 1)) == cpustate->cregs[CR_DB]) && GET_PSR_BW ())
+ {
+ SET_PSR_DAT (1);
+ cpustate->pending_trap = 1;
+ return;
+ }
+
+ /* Now do the actual write. */
+ if (size == 1)
+ memory_write_byte_64le(cpustate->program, addr, data);
+ else if (size == 2)
+ {
+#ifdef HOST_MSB
+ BYTE_REV16 (data);
+#endif
+ memory_write_word_64le(cpustate->program, addr, data);
+ }
+ else if (size == 4)
+ {
+#ifdef HOST_MSB
+ BYTE_REV32 (data);
+#endif
+ memory_write_dword_64le(cpustate->program, addr, data);
+ }
+ else
+ assert (0);
+}
+
+
+/* Floating-point read mem routine.
+ addr = address to read.
+ size = size of read in bytes.
+ dest = memory to put read data. */
+static void fp_readmem_emu (i860s *cpustate, UINT32 addr, int size, UINT8 *dest)
+{
+#ifdef TRACE_RDWR_MEM
+ fprintf (stderr, "fp_readmem_emu: (ATE=%d) addr = 0x%08x, size = %d\n",
+ GET_DIRBASE_ATE (), addr, size);
+#endif
+
+ assert (size == 4 || size == 8 || size == 16);
+
+ /* If virtual mode, do translation. */
+ if (GET_DIRBASE_ATE ())
+ {
+ UINT32 phys = get_address_translation (cpustate, addr, 1 /* is_dataref */, 0 /* is_write */);
+ if (cpustate->pending_trap && (GET_PSR_IAT () || GET_PSR_DAT ()))
+ {
+#ifdef TRACE_PAGE_FAULT
+ fprintf (stderr, "0x%08x: ## Page fault (fp_readmem_emu).\n",
+ cpustate->pc);
+#endif
+ cpustate->exiting_readmem = 3;
+ return;
+ }
+ addr = phys;
+ }
+
+ /* First check for match to db register (before read). */
+ if (((addr & ~(size - 1)) == cpustate->cregs[CR_DB]) && GET_PSR_BR ())
+ {
+ SET_PSR_DAT (1);
+ cpustate->pending_trap = 1;
+ return;
+ }
+
+ if (size == 4)
+ {
+ dest[0] = memory_read_byte_64le(cpustate->program, addr+3);
+ dest[1] = memory_read_byte_64le(cpustate->program, addr+2);
+ dest[2] = memory_read_byte_64le(cpustate->program, addr+1);
+ dest[3] = memory_read_byte_64le(cpustate->program, addr+0);
+ }
+ else if (size == 8)
+ {
+ dest[0] = memory_read_byte_64le(cpustate->program, addr+7);
+ dest[1] = memory_read_byte_64le(cpustate->program, addr+6);
+ dest[2] = memory_read_byte_64le(cpustate->program, addr+5);
+ dest[3] = memory_read_byte_64le(cpustate->program, addr+4);
+ dest[4] = memory_read_byte_64le(cpustate->program, addr+3);
+ dest[5] = memory_read_byte_64le(cpustate->program, addr+2);
+ dest[6] = memory_read_byte_64le(cpustate->program, addr+1);
+ dest[7] = memory_read_byte_64le(cpustate->program, addr+0);
+ }
+ else if (size == 16)
+ {
+ int i;
+ for (i = 0; i < 16; i++)
+ {
+ dest[i] = memory_read_byte_64le(cpustate->program, addr+15-i);
+ }
+ }
+}
+
+
+/* Floating-point write mem routine.
+ addr = address to read.
+ size = size of read in bytes.
+ data = pointer to the data.
+ wmask = bit mask of bytes to write (only for pst.d). */
+static void fp_writemem_emu (i860s *cpustate, UINT32 addr, int size, UINT8 *data, UINT32 wmask)
+{
+#ifdef TRACE_RDWR_MEM
+ fprintf (stderr, "fp_writemem_emu: (ATE=%d) addr = 0x%08x, size = %d\n",
+ GET_DIRBASE_ATE (), addr, size);
+#endif
+
+ assert (size == 4 || size == 8 || size == 16);
+
+ /* If virtual mode, do translation. */
+ if (GET_DIRBASE_ATE ())
+ {
+ UINT32 phys = get_address_translation (cpustate, addr, 1 /* is_dataref */, 1 /* is_write */);
+ if (cpustate->pending_trap && GET_PSR_DAT ())
+ {
+#ifdef TRACE_PAGE_FAULT
+ fprintf (stderr, "0x%08x: ## Page fault (fp_writememi_emu).\n",
+ cpustate->pc);
+#endif
+ cpustate->exiting_readmem = 4;
+ return;
+ }
+ addr = phys;
+ }
+
+ /* First check for match to db register (before read). */
+ if (((addr & ~(size - 1)) == cpustate->cregs[CR_DB]) && GET_PSR_BW ())
+ {
+ SET_PSR_DAT (1);
+ cpustate->pending_trap = 1;
+ return;
+ }
+
+ if (size == 4)
+ {
+#if 1
+ memory_write_byte_64le(cpustate->program, addr+3, data[0]);
+ memory_write_byte_64le(cpustate->program, addr+2, data[1]);
+ memory_write_byte_64le(cpustate->program, addr+1, data[2]);
+ memory_write_byte_64le(cpustate->program, addr+0, data[3]);
+#else
+ UINT32 ddd = (data[3]) | (data[2] << 8) | (data[1] << 16) |(data[0] << 24);
+ memory_write_dword_64le(cpustate->program, addr+0, ddd);
+#endif
+ }
+ else if (size == 8)
+ {
+ /* Special: watch for wmask != 0xff, which means we're doing pst.d. */
+ if (wmask == 0xff)
+ {
+ memory_write_byte_64le(cpustate->program, addr+7, data[0]);
+ memory_write_byte_64le(cpustate->program, addr+6, data[1]);
+ memory_write_byte_64le(cpustate->program, addr+5, data[2]);
+ memory_write_byte_64le(cpustate->program, addr+4, data[3]);
+ memory_write_byte_64le(cpustate->program, addr+3, data[4]);
+ memory_write_byte_64le(cpustate->program, addr+2, data[5]);
+ memory_write_byte_64le(cpustate->program, addr+1, data[6]);
+ memory_write_byte_64le(cpustate->program, addr+0, data[7]);
+ }
+ else
+ {
+ if (wmask & 0x80) memory_write_byte_64le(cpustate->program, addr+7, data[0]);
+ if (wmask & 0x40) memory_write_byte_64le(cpustate->program, addr+6, data[1]);
+ if (wmask & 0x20) memory_write_byte_64le(cpustate->program, addr+5, data[2]);
+ if (wmask & 0x10) memory_write_byte_64le(cpustate->program, addr+4, data[3]);
+ if (wmask & 0x08) memory_write_byte_64le(cpustate->program, addr+3, data[4]);
+ if (wmask & 0x04) memory_write_byte_64le(cpustate->program, addr+2, data[5]);
+ if (wmask & 0x02) memory_write_byte_64le(cpustate->program, addr+1, data[6]);
+ if (wmask & 0x01) memory_write_byte_64le(cpustate->program, addr+0, data[7]);
+ }
+ }
+ else if (size == 16)
+ {
+ int i;
+ for (i = 0; i < 16; i++)
+ {
+ memory_write_byte_64le(cpustate->program, addr+15-i, data[i]);
+ }
+ }
+
+}
+
+
+#if 0
+/* Do a pipeline dump.
+ type: 0 (all), 1 (add), 2 (mul), 3 (load), 4 (graphics). */
+static void dump_pipe (i860s *cpustate, int type)
+{
+ int i = 0;
+
+ fprintf (stderr, "pipeline state:\n");
+ /* Dump the adder pipeline, if requested. */
+ if (type == 0 || type == 1)
+ {
+ fprintf (stderr, " A: ");
+ for (i = 0; i < 3; i++)
+ {
+ if (cpustate->A[i].stat.arp)
+ fprintf (stderr, "[%dd] 0x%016llx ", i + 1,
+ *(UINT64 *)(&cpustate->A[i].val.d));
+ else
+ fprintf (stderr, "[%ds] 0x%08x ", i + 1,
+ *(UINT32 *)(&cpustate->A[i].val.s));
+ }
+ fprintf (stderr, "\n");
+ }
+
+
+ /* Dump the multiplier pipeline, if requested. */
+ if (type == 0 || type == 2)
+ {
+ fprintf (stderr, " M: ");
+ for (i = 0; i < 3; i++)
+ {
+ if (cpustate->M[i].stat.mrp)
+ fprintf (stderr, "[%dd] 0x%016llx ", i + 1,
+ *(UINT64 *)(&cpustate->M[i].val.d));
+ else
+ fprintf (stderr, "[%ds] 0x%08x ", i + 1,
+ *(UINT32 *)(&cpustate->M[i].val.s));
+ }
+ fprintf (stderr, "\n");
+ }
+
+ /* Dump the load pipeline, if requested. */
+ if (type == 0 || type == 3)
+ {
+ fprintf (stderr, " L: ");
+ for (i = 0; i < 3; i++)
+ {
+ if (cpustate->L[i].stat.lrp)
+ fprintf (stderr, "[%dd] 0x%016llx ", i + 1,
+ *(UINT64 *)(&cpustate->L[i].val.d));
+ else
+ fprintf (stderr, "[%ds] 0x%08x ", i + 1,
+ *(UINT32 *)(&cpustate->L[i].val.s));
+ }
+ fprintf (stderr, "\n");
+ }
+
+ /* Dump the graphics pipeline, if requested. */
+ if (type == 0 || type == 4)
+ {
+ fprintf (stderr, " I: ");
+ if (cpustate->G.stat.irp)
+ fprintf (stderr, "[1d] 0x%016llx\n",
+ *(UINT64 *)(&cpustate->G.val.d));
+ else
+ fprintf (stderr, "[1s] 0x%08x\n",
+ *(UINT32 *)(&cpustate->G.val.s));
+ }
+}
+
+
+/* Do a register/state dump. */
+static void dump_state (i860s *cpustate)
+{
+ int rn;
+
+ /* GR's first, 4 per line. */
+ for (rn = 0; rn < 32; rn++)
+ {
+ if ((rn % 4) == 0)
+ fprintf (stderr, "\n");
+ fprintf (stderr, "%%r%-3d: 0x%08x ", rn, get_iregval (rn));
+ }
+ fprintf (stderr, "\n");
+
+ /* FR's (as 32-bits), 4 per line. */
+ for (rn = 0; rn < 32; rn++)
+ {
+ float ff = get_fregval_s (cpustate, rn);
+ if ((rn % 4) == 0)
+ fprintf (stderr, "\n");
+ fprintf (stderr, "%%f%-3d: 0x%08x ", rn, *(UINT32 *)&ff);
+ }
+ fprintf (stderr, "\n");
+
+ fprintf (stderr, " psr: CC = %d, LCC = %d, SC = %d, IM = %d, U = %d\n",
+ GET_PSR_CC (), GET_PSR_LCC (), GET_PSR_SC (), GET_PSR_IM (),
+ GET_PSR_U ());
+ fprintf (stderr, " IT/FT/IAT/DAT/IN = %d/%d/%d/%d/%d\n",
+ GET_PSR_IT (), GET_PSR_FT (), GET_PSR_IAT (),
+ GET_PSR_DAT (), GET_PSR_IN ());
+ fprintf (stderr, "epsr: INT = %d, OF = %d, BE = %d\n",
+ GET_EPSR_INT (), GET_EPSR_OF (), GET_EPSR_BE ());
+ fprintf (stderr, " fir: 0x%08x dirbase: 0x%08x fsr: 0x%08x\n",
+ cpustate->cregs[CR_FIR], cpustate->cregs[CR_DIRBASE],
+ cpustate->cregs[CR_FSR]);
+ fprintf (stderr, " pc: 0x%08x\n", cpustate->pc);
+}
+#endif
+
+/* Sign extend N-bit number. */
+INLINE INT32 sign_ext (UINT32 x, int n)
+{
+ INT32 t;
+ t = x >> (n - 1);
+ t = ((-t) << n) | x;
+ return t;
+}
+
+
+static void unrecog_opcode (UINT32 pc, UINT32 insn)
+{
+ fprintf (stderr, "0x%08x: 0x%08x (unrecognized opcode)\n", pc, insn);
+}
+
+
+/* Execute "ld.c csrc2,idest" instruction. */
+static void insn_ld_ctrl (i860s *cpustate, UINT32 insn)
+{
+ UINT32 csrc2 = get_creg (insn);
+ UINT32 idest = get_idest (insn);
+
+#ifdef TRACE_UNDEFINED_I860
+ if (csrc2 > 5)
+ {
+ /* Control register not between 0..5. Undefined i860XR behavior. */
+ fprintf (stderr, "WARNING: insn_ld_from_ctrl (pc=0x%08x): bad creg in ld.c (ignored)\n", cpustate->pc);
+ return;
+ }
+#endif
+
+ /* If this is a load of the fir, then there are two cases:
+ 1. First load of fir after a trap = usual value.
+ 2. Not first load of fir after a trap = address of the ld.c insn. */
+ if (csrc2 == CR_FIR)
+ {
+ if (cpustate->fir_gets_trap_addr)
+ set_iregval (idest, cpustate->cregs[csrc2]);
+ else
+ {
+ cpustate->cregs[csrc2] = cpustate->pc;
+ set_iregval (idest, cpustate->cregs[csrc2]);
+ }
+ cpustate->fir_gets_trap_addr = 0;
+ }
+ else
+ set_iregval (idest, cpustate->cregs[csrc2]);
+}
+
+
+/* Execute "st.c isrc1,csrc2" instruction. */
+static void insn_st_ctrl (i860s *cpustate, UINT32 insn)
+{
+ UINT32 csrc2 = get_creg (insn);
+ UINT32 isrc1 = get_isrc1 (insn);
+
+#ifdef TRACE_UNDEFINED_I860
+ if (csrc2 > 5)
+ {
+ /* Control register not between 0..5. Undefined i860XR behavior. */
+ fprintf (stderr, "WARNING: insn_st_to_ctrl (pc=0x%08x): bad creg in st.c (ignored)\n", cpustate->pc);
+ return;
+ }
+#endif
+
+ /* Look for ITI bit turned on (but it never actually is written --
+ it always appears to be 0). */
+ if (csrc2 == CR_DIRBASE && (get_iregval (isrc1) & 0x20))
+ {
+ /* NOTE: The actual icache and TLB flush are unimplemented for
+ the MAME version. */
+
+ /* Make sure ITI isn't actually written. */
+ set_iregval (isrc1, (get_iregval (isrc1) & ~0x20));
+ }
+
+ if (csrc2 == CR_DIRBASE && (get_iregval (isrc1) & 1)
+ && GET_DIRBASE_ATE () == 0)
+ {
+ fprintf (stderr, "0x%08x: ** ATE going high!\n", cpustate->pc);
+ }
+
+ /* Update the register -- unless it is fir which cannot be updated. */
+ if (csrc2 == CR_EPSR)
+ {
+ UINT32 enew = 0, tmp = 0;
+ /* Make sure unchangeable EPSR bits stay unchanged (DCS, stepping,
+ and type). Also, some bits are only writeable in supervisor
+ mode. */
+ if (GET_PSR_U ())
+ {
+ enew = get_iregval (isrc1) & ~(0x003e1fff | 0x00c06000);
+ tmp = cpustate->cregs[CR_EPSR] & (0x003e1fff | 0x00c06000);
+ }
+ else
+ {
+ enew = get_iregval (isrc1) & ~0x003e1fff;
+ tmp = cpustate->cregs[CR_EPSR] & 0x003e1fff;
+ }
+ cpustate->cregs[CR_EPSR] = enew | tmp;
+ }
+ else if (csrc2 == CR_PSR)
+ {
+ /* Some PSR bits are only writeable in supervisor mode. */
+ if (GET_PSR_U ())
+ {
+ UINT32 enew = get_iregval (isrc1) & ~PSR_SUPERVISOR_ONLY_MASK;
+ UINT32 tmp = cpustate->cregs[CR_PSR] & PSR_SUPERVISOR_ONLY_MASK;
+ cpustate->cregs[CR_PSR] = enew | tmp;
+ }
+ else
+ cpustate->cregs[CR_PSR] = get_iregval (isrc1);
+ }
+ else if (csrc2 == CR_FSR)
+ {
+ /* I believe that only 21..17, 8..5, and 3..0 should be updated. */
+ UINT32 enew = get_iregval (isrc1) & 0x003e01ef;
+ UINT32 tmp = cpustate->cregs[CR_FSR] & ~0x003e01ef;
+ cpustate->cregs[CR_FSR] = enew | tmp;
+ }
+ else if (csrc2 != CR_FIR)
+ cpustate->cregs[csrc2] = get_iregval (isrc1);
+}
+
+
+/* Execute "ld.{s,b,l} isrc1(isrc2),idest" or
+ "ld.{s,b,l} #const(isrc2),idest". */
+static void insn_ldx (i860s *cpustate, UINT32 insn)
+{
+ UINT32 isrc1 = get_isrc1 (insn);
+ INT32 immsrc1 = sign_ext (get_imm16 (insn), 16);
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 eff = 0;
+ /* Operand size, in bytes. */
+ int sizes[4] = { 1, 1, 2, 4};
+ int size = 0;
+ int form_disp_reg = 0;
+
+ /* Bits 28 and 0 determine the operand size. */
+ size = sizes[((insn >> 27) & 2) | (insn & 1)];
+
+ /* Bit 26 determines the addressing mode (reg+reg or disp+reg). */
+ form_disp_reg = (insn & 0x04000000);
+
+ /* Get effective address depending on disp+reg or reg+reg form. */
+ if (form_disp_reg)
+ {
+ /* Chop off lower bits of displacement. */
+ immsrc1 &= ~(size - 1);
+ eff = (UINT32)(immsrc1 + (INT32)(get_iregval (isrc2)));
+ }
+ else
+ eff = get_iregval (isrc1) + get_iregval (isrc2);
+
+#ifdef TRACE_UNALIGNED_MEM
+ if (eff & (size - 1))
+ {
+ fprintf (stderr, "0x%08x: Unaligned access detected (0x%08x).\n",
+ cpustate->pc, eff);
+ SET_PSR_DAT (1);
+ cpustate->pending_trap = 1;
+ return;
+ }
+#endif
+
+ /* The i860 sign-extends 8- or 16-bit integer loads.
+
+ Below, the readmemi_emu() needs to happen outside of the
+ set_iregval macro (otherwise the readmem won't occur if r0
+ is the target register). */
+ if (size < 4)
+ {
+ UINT32 readval = sign_ext (readmemi_emu (cpustate, eff, size), size * 8);
+ /* Do not update register on page fault. */
+ if (cpustate->exiting_readmem)
+ {
+ return;
+ }
+ set_iregval (idest, readval);
+ }
+ else
+ {
+ UINT32 readval = readmemi_emu (cpustate, eff, size);
+ /* Do not update register on page fault. */
+ if (cpustate->exiting_readmem)
+ {
+ return;
+ }
+ set_iregval (idest, readval);
+ }
+}
+
+
+/* Execute "st.x isrc1ni,#const(isrc2)" instruction (there is no
+ (reg + reg form). Store uses the split immediate, not the normal
+ 16-bit immediate as in ld.x. */
+static void insn_stx (i860s *cpustate, UINT32 insn)
+{
+ INT32 immsrc = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
+ UINT32 isrc1 = get_isrc1 (insn);
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 eff = 0;
+ /* Operand size, in bytes. */
+ int sizes[4] = { 1, 1, 2, 4};
+ int size = 0;
+
+ /* Bits 28 and 0 determine the operand size. */
+ size = sizes[((insn >> 27) & 2) | (insn & 1)];
+
+ /* FIXME: Do any necessary traps. */
+
+ /* Get effective address. Chop off lower bits of displacement. */
+ immsrc &= ~(size - 1);
+ eff = (UINT32)(immsrc + (INT32)get_iregval (isrc2));
+
+ /* Write data (value of reg isrc1) to memory at eff. */
+ writememi_emu (cpustate, eff, size, get_iregval (isrc1));
+ if (cpustate->exiting_readmem)
+ return;
+}
+
+
+/* Execute "fst.y fdest,isrc1(isrc2)", "fst.y fdest,isrc1(isrc2)++",
+ "fst.y fdest,#const(isrc2)" or "fst.y fdest,#const(isrc2)++"
+ instruction. */
+static void insn_fsty (i860s *cpustate, UINT32 insn)
+{
+ UINT32 isrc1 = get_isrc1 (insn);
+ INT32 immsrc1 = sign_ext (get_imm16 (insn), 16);
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 fdest = get_fdest (insn);
+ UINT32 eff = 0;
+ /* Operand size, in bytes. */
+ int sizes[4] = { 8, 4, 16, 4};
+ int size = 0;
+ int form_disp_reg = 0;
+ int auto_inc = (insn & 1);
+
+ /* Bits 2 and 1 determine the operand size. */
+ size = sizes[((insn >> 1) & 3)];
+
+ /* Bit 26 determines the addressing mode (reg+reg or disp+reg). */
+ form_disp_reg = (insn & 0x04000000);
+
+ /* FIXME: Check for undefined behavior, non-even or non-quad
+ register operands for fst.d and fst.q respectively. */
+
+ /* Get effective address depending on disp+reg or reg+reg form. */
+ if (form_disp_reg)
+ {
+ /* Chop off lower bits of displacement. */
+ immsrc1 &= ~(size - 1);
+ eff = (UINT32)(immsrc1 + (INT32)(get_iregval (isrc2)));
+ }
+ else
+ eff = get_iregval (isrc1) + get_iregval (isrc2);
+
+#ifdef TRACE_UNALIGNED_MEM
+ if (eff & (size - 1))
+ {
+ fprintf (stderr, "0x%08x: Unaligned access detected (0x%08x).\n",
+ cpustate->pc, eff);
+ SET_PSR_DAT (1);
+ cpustate->pending_trap = 1;
+ return;
+ }
+#endif
+
+ /* Do (post) auto-increment. */
+ if (auto_inc)
+ {
+ set_iregval (isrc2, eff);
+#ifdef TRACE_UNDEFINED_I860
+ /* When auto-inc, isrc1 and isrc2 regs can't be the same. */
+ if (isrc1 == isrc2)
+ {
+ /* Undefined i860XR behavior. */
+ fprintf (stderr, "WARNING: insn_fsty (pc=0x%08x): isrc1 = isrc2 in fst with auto-inc (ignored)\n", cpustate->pc);
+ return;
+ }
+#endif
+ }
+
+ /* Write data (value of freg fdest) to memory at eff. */
+ if (size == 4)
+ fp_writemem_emu (cpustate, eff, size, (UINT8 *)(&cpustate->frg[4 * (31 - fdest)]), 0xff);
+ else if (size == 8)
+ fp_writemem_emu (cpustate, eff, size, (UINT8 *)(&cpustate->frg[4 * (31 - (fdest + 1))]), 0xff);
+ else
+ fp_writemem_emu (cpustate, eff, size, (UINT8 *)(&cpustate->frg[4 * (31 - (fdest + 3))]), 0xff);
+
+}
+
+
+/* Execute "fld.y isrc1(isrc2),fdest", "fld.y isrc1(isrc2)++,idest",
+ "fld.y #const(isrc2),fdest" or "fld.y #const(isrc2)++,idest".
+ Where y = {l,d,q}. Note, there is no pfld.q, though. */
+static void insn_fldy (i860s *cpustate, UINT32 insn)
+{
+ UINT32 isrc1 = get_isrc1 (insn);
+ INT32 immsrc1 = sign_ext (get_imm16 (insn), 16);
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 fdest = get_fdest (insn);
+ UINT32 eff = 0;
+ /* Operand size, in bytes. */
+ int sizes[4] = { 8, 4, 16, 4};
+ int size = 0;
+ int form_disp_reg = 0;
+ int auto_inc = (insn & 1);
+ int piped = (insn & 0x40000000);
+
+ /* Bits 2 and 1 determine the operand size. */
+ size = sizes[((insn >> 1) & 3)];
+
+ /* Bit 26 determines the addressing mode (reg+reg or disp+reg). */
+ form_disp_reg = (insn & 0x04000000);
+
+ /* There is no pipelined load quad. */
+ if (piped && size == 16)
+ {
+ unrecog_opcode (cpustate->pc, insn);
+ return;
+ }
+
+ /* FIXME: Check for undefined behavior, non-even or non-quad
+ register operands for fld.d and fld.q respectively. */
+
+ /* Get effective address depending on disp+reg or reg+reg form. */
+ if (form_disp_reg)
+ {
+ /* Chop off lower bits of displacement. */
+ immsrc1 &= ~(size - 1);
+ eff = (UINT32)(immsrc1 + (INT32)(get_iregval (isrc2)));
+ }
+ else
+ eff = get_iregval (isrc1) + get_iregval (isrc2);
+
+ /* Do (post) auto-increment. */
+ if (auto_inc)
+ {
+ set_iregval (isrc2, eff);
+#ifdef TRACE_UNDEFINED_I860
+ /* When auto-inc, isrc1 and isrc2 regs can't be the same. */
+ if (isrc1 == isrc2)
+ {
+ /* Undefined i860XR behavior. */
+ fprintf (stderr, "WARNING: insn_fldy (pc=0x%08x): isrc1 = isrc2 in fst with auto-inc (ignored)\n", cpustate->pc);
+ return;
+ }
+#endif
+ }
+
+#ifdef TRACE_UNALIGNED_MEM
+ if (eff & (size - 1))
+ {
+ fprintf (stderr, "0x%08x: Unaligned access detected (0x%08x).\n",
+ cpustate->pc, eff);
+ SET_PSR_DAT (1);
+ cpustate->pending_trap = 1;
+ return;
+ }
+#endif
+
+ /* Update the load pipe if necessary. */
+ /* FIXME: Copy result-status bits to fsr from last stage. */
+ if (!piped)
+ {
+ /* Scalar version writes the current result to fdest. */
+ /* Read data at 'eff' into freg 'fdest' (reads to f0 or f1 are
+ thrown away). */
+ if (fdest > 1)
+ {
+ if (size == 4)
+ fp_readmem_emu (cpustate, eff, size, (UINT8 *)&(cpustate->frg[4 * (31 - fdest)]));
+ else if (size == 8)
+ fp_readmem_emu (cpustate, eff, size, (UINT8 *)&(cpustate->frg[4 * (31 - (fdest + 1))]));
+ else if (size == 16)
+ fp_readmem_emu (cpustate, eff, size, (UINT8 *)&(cpustate->frg[4 * (31 - (fdest + 3))]));
+ }
+ }
+ else
+ {
+ /* Read the data into a temp space first. This way we can test
+ for any traps before updating the pipeline. The pipeline must
+ stay unaffected after a trap so that the instruction can be
+ properly restarted. */
+ UINT8 bebuf[8];
+ fp_readmem_emu (cpustate, eff, size, bebuf);
+ if (cpustate->pending_trap && cpustate->exiting_readmem)
+ goto ab_op;
+
+ /* Pipelined version writes fdest with the result from the last
+ stage of the pipeline, with precision specified by the LRP
+ bit of the stage's result-status bits. */
+#if 1 /* FIXME: WIP on FSR update. This may not be correct. */
+ /* Copy 3rd stage LRP to FSR. */
+ if (cpustate->L[1 /* 2 */].stat.lrp)
+ cpustate->cregs[CR_FSR] |= 0x04000000;
+ else
+ cpustate->cregs[CR_FSR] &= ~0x04000000;
+#endif
+ if (cpustate->L[2].stat.lrp) /* 3rd (last) stage. */
+ set_fregval_d (cpustate, fdest, cpustate->L[2].val.d);
+ else
+ set_fregval_s (cpustate, fdest, cpustate->L[2].val.s);
+
+ /* Now advance pipeline and write loaded data to first stage. */
+ cpustate->L[2] = cpustate->L[1];
+ cpustate->L[1] = cpustate->L[0];
+ if (size == 8)
+ {
+ UINT8 *t = (UINT8 *)&(cpustate->L[0].val.d);
+#ifndef HOST_MSB
+ t[7] = bebuf[0]; t[6] = bebuf[1]; t[5] = bebuf[2]; t[4] = bebuf[3];
+ t[3] = bebuf[4]; t[2] = bebuf[5]; t[1] = bebuf[6]; t[0] = bebuf[7];
+#else
+ t[0] = bebuf[0]; t[1] = bebuf[1]; t[2] = bebuf[2]; t[3] = bebuf[3];
+ t[4] = bebuf[4]; t[5] = bebuf[5]; t[6] = bebuf[6]; t[7] = bebuf[7];
+#endif
+ cpustate->L[0].stat.lrp = 1;
+ }
+ else
+ {
+ UINT8 *t = (UINT8 *)&(cpustate->L[0].val.s);
+#ifndef HOST_MSB
+ t[3] = bebuf[0]; t[2] = bebuf[1]; t[1] = bebuf[2]; t[0] = bebuf[3];
+#else
+ t[0] = bebuf[0]; t[1] = bebuf[1]; t[2] = bebuf[2]; t[3] = bebuf[3];
+#endif
+ cpustate->L[0].stat.lrp = 0;
+ }
+ }
+
+ ab_op:;
+}
+
+
+/* Execute "pst.d fdest,#const(isrc2)" or "fst.d fdest,#const(isrc2)++"
+ instruction. */
+static void insn_pstd (i860s *cpustate, UINT32 insn)
+{
+ INT32 immsrc1 = sign_ext (get_imm16 (insn), 16);
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 fdest = get_fdest (insn);
+ UINT32 eff = 0;
+ int auto_inc = (insn & 1);
+ UINT8 *bebuf = 0;
+ int pm = GET_PSR_PM ();
+ int i;
+ UINT32 wmask;
+ int orig_pm = pm;
+
+ /* Get the pixel size, where:
+ PS: 0 = 8 bits, 1 = 16 bits, 2 = 32-bits. */
+ int ps = GET_PSR_PS ();
+
+#ifdef TRACE_UNDEFINED_I860
+ if (!(ps == 0 || ps == 1 || ps == 2))
+ fprintf (stderr, "insn_pstd: Undefined i860XR behavior, invalid value %d for pixel size.\n", ps);
+#endif
+
+#ifdef TRACE_UNDEFINED_I860
+ /* Bits 2 and 1 determine the operand size, which must always be
+ zero (indicating a 64-bit operand). */
+ if (insn & 0x6)
+ {
+ /* Undefined i860XR behavior. */
+ fprintf (stderr, "WARNING: insn_pstd (pc=0x%08x): bad operand size specifier\n", cpustate->pc);
+ }
+#endif
+
+ /* FIXME: Check for undefined behavior, non-even register operands. */
+
+ /* Get effective address. Chop off lower bits of displacement. */
+ immsrc1 &= ~(8 - 1);
+ eff = (UINT32)(immsrc1 + (INT32)(get_iregval (isrc2)));
+
+#ifdef TRACE_UNALIGNED_MEM
+ if (eff & (8 - 1))
+ {
+ fprintf (stderr, "0x%08x: Unaligned access detected (0x%08x).\n",
+ cpustate->pc, eff);
+ SET_PSR_DAT (1);
+ cpustate->pending_trap = 1;
+ return;
+ }
+#endif
+
+ /* Do (post) auto-increment. */
+ if (auto_inc)
+ set_iregval (isrc2, eff);
+
+ /* Update the the pixel mask depending on the pixel size. Shift PM
+ right by 8/2^ps bits. */
+ if (ps == 0)
+ pm = (pm >> 8) & 0x00;
+ else if (ps == 1)
+ pm = (pm >> 4) & 0x0f;
+ else if (ps == 2)
+ pm = (pm >> 2) & 0x3f;
+ SET_PSR_PM (pm);
+
+ /* Write data (value of freg fdest) to memory at eff-- but only those
+ bytes that are enabled by the bits in PSR.PM. Bit 0 of PM selects
+ the pixel at the lowest address. */
+ wmask = 0;
+ for (i = 0; i < 8; )
+ {
+ if (ps == 0)
+ {
+ if (orig_pm & 0x80)
+ wmask |= 1 << (7-i);
+ i += 1;
+ }
+ else if (ps == 1)
+ {
+ if (orig_pm & 0x08)
+ wmask |= 0x3 << (6-i);
+ i += 2;
+ }
+ else if (ps == 2)
+ {
+ if (orig_pm & 0x02)
+ wmask |= 0xf << (4-i);
+ i += 4;
+ }
+ else
+ {
+ wmask = 0xff;
+ break;
+ }
+ orig_pm <<= 1;
+ }
+ bebuf = (UINT8 *)(&cpustate->frg[4 * (31 - (fdest + 1))]);
+ fp_writemem_emu (cpustate, eff, 8, bebuf, wmask);
+}
+
+
+/* Execute "ixfr isrc1ni,fdest" instruction. */
+static void insn_ixfr (i860s *cpustate, UINT32 insn)
+{
+ UINT32 isrc1 = get_isrc1 (insn);
+ UINT32 fdest = get_fdest (insn);
+ UINT32 iv = 0;
+
+ /* This is a bit-pattern transfer, not a conversion. */
+ iv = get_iregval (isrc1);
+ set_fregval_s (cpustate, fdest, *(float *)&iv);
+}
+
+
+/* Execute "addu isrc1,isrc2,idest". */
+static void insn_addu (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 tmp_dest_val = 0;
+ UINT64 tmp = 0;
+
+ src1val = get_iregval (get_isrc1 (insn));
+
+ /* We don't update the actual idest register now because below we
+ need to test the original src1 and src2 if either happens to
+ be the destination register. */
+ tmp_dest_val = src1val + get_iregval (isrc2);
+
+ /* Set OF and CC flags.
+ For unsigned:
+ OF = bit 31 carry
+ CC = bit 31 carry.
+ */
+ tmp = (UINT64)src1val + (UINT64)(get_iregval (isrc2));
+ if ((tmp >> 32) & 1)
+ {
+ SET_PSR_CC (1);
+ SET_EPSR_OF (1);
+ }
+ else
+ {
+ SET_PSR_CC (0);
+ SET_EPSR_OF (0);
+ }
+
+ /* Now update the destination register. */
+ set_iregval (idest, tmp_dest_val);
+}
+
+
+/* Execute "addu #const,isrc2,idest". */
+static void insn_addu_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 tmp_dest_val = 0;
+ UINT64 tmp = 0;
+
+ src1val = sign_ext (get_imm16 (insn), 16);
+
+ /* We don't update the actual idest register now because below we
+ need to test the original src1 and src2 if either happens to
+ be the destination register. */
+ tmp_dest_val = src1val + get_iregval (isrc2);
+
+ /* Set OF and CC flags.
+ For unsigned:
+ OF = bit 31 carry
+ CC = bit 31 carry.
+ */
+ tmp = (UINT64)src1val + (UINT64)(get_iregval (isrc2));
+ if ((tmp >> 32) & 1)
+ {
+ SET_PSR_CC (1);
+ SET_EPSR_OF (1);
+ }
+ else
+ {
+ SET_PSR_CC (0);
+ SET_EPSR_OF (0);
+ }
+
+ /* Now update the destination register. */
+ set_iregval (idest, tmp_dest_val);
+}
+
+
+/* Execute "adds isrc1,isrc2,idest". */
+static void insn_adds (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 tmp_dest_val = 0;
+ int sa, sb, sres;
+
+ src1val = get_iregval (get_isrc1 (insn));
+
+ /* We don't update the actual idest register now because below we
+ need to test the original src1 and src2 if either happens to
+ be the destination register. */
+ tmp_dest_val = src1val + get_iregval (isrc2);
+
+ /* Set OF and CC flags.
+ For signed:
+ OF = standard signed overflow.
+ CC set if isrc2 < -isrc1
+ CC clear if isrc2 >= -isrc1
+ */
+ sa = src1val & 0x80000000;
+ sb = get_iregval (isrc2) & 0x80000000;
+ sres = tmp_dest_val & 0x80000000;
+ if (sa != sb && sa != sres)
+ SET_EPSR_OF (1);
+ else
+ SET_EPSR_OF (0);
+
+ if ((INT32)get_iregval (isrc2) < -(INT32)(src1val))
+ SET_PSR_CC (1);
+ else
+ SET_PSR_CC (0);
+
+ /* Now update the destination register. */
+ set_iregval (idest, tmp_dest_val);
+}
+
+
+/* Execute "adds #const,isrc2,idest". */
+static void insn_adds_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 tmp_dest_val = 0;
+ int sa, sb, sres;
+
+ src1val = sign_ext (get_imm16 (insn), 16);
+
+ /* We don't update the actual idest register now because below we
+ need to test the original src1 and src2 if either happens to
+ be the destination register. */
+ tmp_dest_val = src1val + get_iregval (isrc2);
+
+ /* Set OF and CC flags.
+ For signed:
+ OF = standard signed overflow.
+ CC set if isrc2 < -isrc1
+ CC clear if isrc2 >= -isrc1
+ */
+ sa = src1val & 0x80000000;
+ sb = get_iregval (isrc2) & 0x80000000;
+ sres = tmp_dest_val & 0x80000000;
+ if (sa != sb && sa != sres)
+ SET_EPSR_OF (1);
+ else
+ SET_EPSR_OF (0);
+
+ if ((INT32)get_iregval (isrc2) < -(INT32)(src1val))
+ SET_PSR_CC (1);
+ else
+ SET_PSR_CC (0);
+
+ /* Now update the destination register. */
+ set_iregval (idest, tmp_dest_val);
+}
+
+
+/* Execute "subu isrc1,isrc2,idest". */
+static void insn_subu (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 tmp_dest_val = 0;
+
+ src1val = get_iregval (get_isrc1 (insn));
+
+ /* We don't update the actual idest register now because below we
+ need to test the original src1 and src2 if either happens to
+ be the destination register. */
+ tmp_dest_val = src1val - get_iregval (isrc2);
+
+ /* Set OF and CC flags.
+ For unsigned:
+ OF = NOT(bit 31 carry)
+ CC = bit 31 carry.
+ (i.e. CC set if isrc2 <= isrc1
+ CC clear if isrc2 > isrc1
+ */
+ if ((UINT32)get_iregval (isrc2) <= (UINT32)src1val)
+ {
+ SET_PSR_CC (1);
+ SET_EPSR_OF (0);
+ }
+ else
+ {
+ SET_PSR_CC (0);
+ SET_EPSR_OF (1);
+ }
+
+ /* Now update the destination register. */
+ set_iregval (idest, tmp_dest_val);
+}
+
+
+/* Execute "subu #const,isrc2,idest". */
+static void insn_subu_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 tmp_dest_val = 0;
+
+ src1val = sign_ext (get_imm16 (insn), 16);
+
+ /* We don't update the actual idest register now because below we
+ need to test the original src1 and src2 if either happens to
+ be the destination register. */
+ tmp_dest_val = src1val - get_iregval (isrc2);
+
+ /* Set OF and CC flags.
+ For unsigned:
+ OF = NOT(bit 31 carry)
+ CC = bit 31 carry.
+ (i.e. CC set if isrc2 <= isrc1
+ CC clear if isrc2 > isrc1
+ */
+ if ((UINT32)get_iregval (isrc2) <= (UINT32)src1val)
+ {
+ SET_PSR_CC (1);
+ SET_EPSR_OF (0);
+ }
+ else
+ {
+ SET_PSR_CC (0);
+ SET_EPSR_OF (1);
+ }
+
+ /* Now update the destination register. */
+ set_iregval (idest, tmp_dest_val);
+}
+
+
+/* Execute "subs isrc1,isrc2,idest". */
+static void insn_subs (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 tmp_dest_val = 0;
+ int sa, sb, sres;
+
+ src1val = get_iregval (get_isrc1 (insn));
+
+ /* We don't update the actual idest register now because below we
+ need to test the original src1 and src2 if either happens to
+ be the destination register. */
+ tmp_dest_val = src1val - get_iregval (isrc2);
+
+ /* Set OF and CC flags.
+ For signed:
+ OF = standard signed overflow.
+ CC set if isrc2 > isrc1
+ CC clear if isrc2 <= isrc1
+ */
+ sa = src1val & 0x80000000;
+ sb = get_iregval (isrc2) & 0x80000000;
+ sres = tmp_dest_val & 0x80000000;
+ if (sa != sb && sa != sres)
+ SET_EPSR_OF (1);
+ else
+ SET_EPSR_OF (0);
+
+ if ((INT32)get_iregval (isrc2) > (INT32)(src1val))
+ SET_PSR_CC (1);
+ else
+ SET_PSR_CC (0);
+
+ /* Now update the destination register. */
+ set_iregval (idest, tmp_dest_val);
+}
+
+
+/* Execute "subs #const,isrc2,idest". */
+static void insn_subs_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 tmp_dest_val = 0;
+ int sa, sb, sres;
+
+ src1val = sign_ext (get_imm16 (insn), 16);
+
+ /* We don't update the actual idest register now because below we
+ need to test the original src1 and src2 if either happens to
+ be the destination register. */
+ tmp_dest_val = src1val - get_iregval (isrc2);
+
+ /* Set OF and CC flags.
+ For signed:
+ OF = standard signed overflow.
+ CC set if isrc2 > isrc1
+ CC clear if isrc2 <= isrc1
+ */
+ sa = src1val & 0x80000000;
+ sb = get_iregval (isrc2) & 0x80000000;
+ sres = tmp_dest_val & 0x80000000;
+ if (sa != sb && sa != sres)
+ SET_EPSR_OF (1);
+ else
+ SET_EPSR_OF (0);
+
+ if ((INT32)get_iregval (isrc2) > (INT32)(src1val))
+ SET_PSR_CC (1);
+ else
+ SET_PSR_CC (0);
+
+ /* Now update the destination register. */
+ set_iregval (idest, tmp_dest_val);
+}
+
+
+/* Execute "shl isrc1,isrc2,idest". */
+static void insn_shl (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+
+ src1val = get_iregval (get_isrc1 (insn));
+ set_iregval (idest, get_iregval (isrc2) << src1val);
+}
+
+
+/* Execute "shl #const,isrc2,idest". */
+static void insn_shl_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+
+ src1val = sign_ext (get_imm16 (insn), 16);
+ set_iregval (idest, get_iregval (isrc2) << src1val);
+}
+
+
+/* Execute "shr isrc1,isrc2,idest". */
+static void insn_shr (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+
+ src1val = get_iregval (get_isrc1 (insn));
+
+ /* The iregs array is UINT32, so this is a logical shift. */
+ set_iregval (idest, get_iregval (isrc2) >> src1val);
+
+ /* shr also sets the SC in psr (shift count). */
+ SET_PSR_SC (src1val);
+}
+
+
+/* Execute "shr #const,isrc2,idest". */
+static void insn_shr_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+
+ src1val = sign_ext (get_imm16 (insn), 16);
+
+ /* The iregs array is UINT32, so this is a logical shift. */
+ set_iregval (idest, get_iregval (isrc2) >> src1val);
+
+ /* shr also sets the SC in psr (shift count). */
+ SET_PSR_SC (src1val);
+}
+
+
+/* Execute "shra isrc1,isrc2,idest". */
+static void insn_shra (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+
+ src1val = get_iregval (get_isrc1 (insn));
+
+ /* The iregs array is UINT32, so cast isrc2 to get arithmetic shift. */
+ set_iregval (idest, (INT32)get_iregval (isrc2) >> src1val);
+}
+
+
+/* Execute "shra #const,isrc2,idest". */
+static void insn_shra_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+
+ src1val = sign_ext (get_imm16 (insn), 16);
+
+ /* The iregs array is UINT32, so cast isrc2 to get arithmetic shift. */
+ set_iregval (idest, (INT32)get_iregval (isrc2) >> src1val);
+}
+
+
+/* Execute "shrd isrc1ni,isrc2,idest" instruction. */
+static void insn_shrd (i860s *cpustate, UINT32 insn)
+{
+ UINT32 isrc1 = get_isrc1 (insn);
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 sc = GET_PSR_SC ();
+ UINT32 tmp;
+
+ /* Do the operation:
+ idest = low_32(isrc1ni:isrc2 >> sc). */
+ if (sc == 0)
+ tmp = get_iregval (isrc2);
+ else
+ {
+ tmp = get_iregval (isrc1) << (32 - sc);
+ tmp |= (get_iregval (isrc2) >> sc);
+ }
+ set_iregval (idest, tmp);
+}
+
+
+/* Execute "and isrc1,isrc2,idest". */
+static void insn_and (i860s *cpustate, UINT32 insn)
+{
+ UINT32 isrc1 = get_isrc1 (insn);
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 res = 0;
+
+ /* Do the operation. */
+ res = get_iregval (isrc1) & get_iregval (isrc2);
+
+ /* Set flags. */
+ if (res == 0)
+ SET_PSR_CC (1);
+ else
+ SET_PSR_CC (0);
+
+ set_iregval (idest, res);
+}
+
+
+/* Execute "and #const,isrc2,idest". */
+static void insn_and_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 res = 0;
+
+ /* Do the operation. */
+ src1val = get_imm16 (insn);
+ res = src1val & get_iregval (isrc2);
+
+ /* Set flags. */
+ if (res == 0)
+ SET_PSR_CC (1);
+ else
+ SET_PSR_CC (0);
+
+ set_iregval (idest, res);
+}
+
+
+/* Execute "andh #const,isrc2,idest". */
+static void insn_andh_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 res = 0;
+
+ /* Do the operation. */
+ src1val = get_imm16 (insn);
+ res = (src1val << 16) & get_iregval (isrc2);
+
+ /* Set flags. */
+ if (res == 0)
+ SET_PSR_CC (1);
+ else
+ SET_PSR_CC (0);
+
+ set_iregval (idest, res);
+}
+
+
+/* Execute "andnot isrc1,isrc2,idest". */
+static void insn_andnot (i860s *cpustate, UINT32 insn)
+{
+ UINT32 isrc1 = get_isrc1 (insn);
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 res = 0;
+
+ /* Do the operation. */
+ res = (~get_iregval (isrc1)) & get_iregval (isrc2);
+
+ /* Set flags. */
+ if (res == 0)
+ SET_PSR_CC (1);
+ else
+ SET_PSR_CC (0);
+
+ set_iregval (idest, res);
+}
+
+
+/* Execute "andnot #const,isrc2,idest". */
+static void insn_andnot_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 res = 0;
+
+ /* Do the operation. */
+ src1val = get_imm16 (insn);
+ res = (~src1val) & get_iregval (isrc2);
+
+ /* Set flags. */
+ if (res == 0)
+ SET_PSR_CC (1);
+ else
+ SET_PSR_CC (0);
+
+ set_iregval (idest, res);
+}
+
+
+/* Execute "andnoth #const,isrc2,idest". */
+static void insn_andnoth_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 res = 0;
+
+ /* Do the operation. */
+ src1val = get_imm16 (insn);
+ res = (~(src1val << 16)) & get_iregval (isrc2);
+
+ /* Set flags. */
+ if (res == 0)
+ SET_PSR_CC (1);
+ else
+ SET_PSR_CC (0);
+
+ set_iregval (idest, res);
+}
+
+
+/* Execute "or isrc1,isrc2,idest". */
+static void insn_or (i860s *cpustate, UINT32 insn)
+{
+ UINT32 isrc1 = get_isrc1 (insn);
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 res = 0;
+
+ /* Do the operation. */
+ res = get_iregval (isrc1) | get_iregval (isrc2);
+
+ /* Set flags. */
+ if (res == 0)
+ SET_PSR_CC (1);
+ else
+ SET_PSR_CC (0);
+
+ set_iregval (idest, res);
+}
+
+
+/* Execute "or #const,isrc2,idest". */
+static void insn_or_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 res = 0;
+
+ /* Do the operation. */
+ src1val = get_imm16 (insn);
+ res = src1val | get_iregval (isrc2);
+
+ /* Set flags. */
+ if (res == 0)
+ SET_PSR_CC (1);
+ else
+ SET_PSR_CC (0);
+
+ set_iregval (idest, res);
+}
+
+
+/* Execute "orh #const,isrc2,idest". */
+static void insn_orh_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 res = 0;
+
+ /* Do the operation. */
+ src1val = get_imm16 (insn);
+ res = (src1val << 16) | get_iregval (isrc2);
+
+ /* Set flags. */
+ if (res == 0)
+ SET_PSR_CC (1);
+ else
+ SET_PSR_CC (0);
+
+ set_iregval (idest, res);
+}
+
+
+/* Execute "xor isrc1,isrc2,idest". */
+static void insn_xor (i860s *cpustate, UINT32 insn)
+{
+ UINT32 isrc1 = get_isrc1 (insn);
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 res = 0;
+
+ /* Do the operation. */
+ res = get_iregval (isrc1) ^ get_iregval (isrc2);
+
+ /* Set flags. */
+ if (res == 0)
+ SET_PSR_CC (1);
+ else
+ SET_PSR_CC (0);
+
+ set_iregval (idest, res);
+}
+
+
+/* Execute "xor #const,isrc2,idest". */
+static void insn_xor_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 res = 0;
+
+ /* Do the operation. */
+ src1val = get_imm16 (insn);
+ res = src1val ^ get_iregval (isrc2);
+
+ /* Set flags. */
+ if (res == 0)
+ SET_PSR_CC (1);
+ else
+ SET_PSR_CC (0);
+
+ set_iregval (idest, res);
+}
+
+
+/* Execute "xorh #const,isrc2,idest". */
+static void insn_xorh_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 idest = get_idest (insn);
+ UINT32 res = 0;
+
+ /* Do the operation. */
+ src1val = get_imm16 (insn);
+ res = (src1val << 16) ^ get_iregval (isrc2);
+
+ /* Set flags. */
+ if (res == 0)
+ SET_PSR_CC (1);
+ else
+ SET_PSR_CC (0);
+
+ set_iregval (idest, res);
+}
+
+
+/* Execute "trap isrc1ni,isrc2,idest" instruction. */
+static void insn_trap (i860s *cpustate, UINT32 insn)
+{
+ SET_PSR_IT (1);
+ cpustate->pending_trap = 1;
+}
+
+
+/* Execute "intovr" instruction. */
+static void insn_intovr (i860s *cpustate, UINT32 insn)
+{
+ if (GET_EPSR_OF ())
+ {
+ SET_PSR_IT (1);
+ cpustate->pending_trap = 1;
+ }
+}
+
+
+/* Execute "bte isrc1,isrc2,sbroff". */
+static void insn_bte (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 target_addr = 0;
+ INT32 sbroff = 0;
+ int res = 0;
+
+ src1val = get_iregval (get_isrc1 (insn));
+
+ /* Compute the target address from the sbroff field. */
+ sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
+ target_addr = (INT32)cpustate->pc + 4 + (sbroff << 2);
+
+ /* Determine comparison result. */
+ res = (src1val == get_iregval (isrc2));
+
+ /* Branch routines always update the PC. */
+ if (res)
+ cpustate->pc = target_addr;
+ else
+ cpustate->pc += 4;
+
+ cpustate->pc_updated = 1;
+}
+
+
+/* Execute "bte #const5,isrc2,sbroff". */
+static void insn_bte_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 target_addr = 0;
+ INT32 sbroff = 0;
+ int res = 0;
+
+ src1val = (insn >> 11) & 0x1f; /* 5-bit field, zero-extended. */
+
+ /* Compute the target address from the sbroff field. */
+ sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
+ target_addr = (INT32)cpustate->pc + 4 + (sbroff << 2);
+
+ /* Determine comparison result. */
+ res = (src1val == get_iregval (isrc2));
+
+ /* Branch routines always update the PC. */
+ if (res)
+ cpustate->pc = target_addr;
+ else
+ cpustate->pc += 4;
+
+ cpustate->pc_updated = 1;
+}
+
+
+/* Execute "btne isrc1,isrc2,sbroff". */
+static void insn_btne (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 target_addr = 0;
+ INT32 sbroff = 0;
+ int res = 0;
+
+ src1val = get_iregval (get_isrc1 (insn));
+
+ /* Compute the target address from the sbroff field. */
+ sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
+ target_addr = (INT32)cpustate->pc + 4 + (sbroff << 2);
+
+ /* Determine comparison result. */
+ res = (src1val != get_iregval (isrc2));
+
+ /* Branch routines always update the PC. */
+ if (res)
+ cpustate->pc = target_addr;
+ else
+ cpustate->pc += 4;
+
+ cpustate->pc_updated = 1;
+}
+
+
+/* Execute "btne #const5,isrc2,sbroff". */
+static void insn_btne_imm (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = 0;
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 target_addr = 0;
+ INT32 sbroff = 0;
+ int res = 0;
+
+ src1val = (insn >> 11) & 0x1f; /* 5-bit field, zero-extended. */
+
+ /* Compute the target address from the sbroff field. */
+ sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
+ target_addr = (INT32)cpustate->pc + 4 + (sbroff << 2);
+
+ /* Determine comparison result. */
+ res = (src1val != get_iregval (isrc2));
+
+ /* Branch routines always update the PC. */
+ if (res)
+ cpustate->pc = target_addr;
+ else
+ cpustate->pc += 4;
+
+ cpustate->pc_updated = 1;
+}
+
+
+/* Execute "bc lbroff" instruction. */
+static void insn_bc (i860s *cpustate, UINT32 insn)
+{
+ UINT32 target_addr = 0;
+ INT32 lbroff = 0;
+ int res = 0;
+
+ /* Compute the target address from the lbroff field. */
+ lbroff = sign_ext ((insn & 0x03ffffff), 26);
+ target_addr = (INT32)cpustate->pc + 4 + (lbroff << 2);
+
+ /* Determine comparison result. */
+ res = (GET_PSR_CC () == 1);
+
+ /* Branch routines always update the PC. */
+ if (res)
+ cpustate->pc = target_addr;
+ else
+ cpustate->pc += 4;
+
+ cpustate->pc_updated = 1;
+}
+
+
+/* Execute "bnc lbroff" instruction. */
+static void insn_bnc (i860s *cpustate, UINT32 insn)
+{
+ UINT32 target_addr = 0;
+ INT32 lbroff = 0;
+ int res = 0;
+
+ /* Compute the target address from the lbroff field. */
+ lbroff = sign_ext ((insn & 0x03ffffff), 26);
+ target_addr = (INT32)cpustate->pc + 4 + (lbroff << 2);
+
+ /* Determine comparison result. */
+ res = (GET_PSR_CC () == 0);
+
+ /* Branch routines always update the PC, since pc_updated is set
+ in the decode routine. */
+ if (res)
+ cpustate->pc = target_addr;
+ else
+ cpustate->pc += 4;
+
+ cpustate->pc_updated = 1;
+}
+
+
+/* Execute "bc.t lbroff" instruction. */
+static void insn_bct (i860s *cpustate, UINT32 insn)
+{
+ UINT32 target_addr = 0;
+ INT32 lbroff = 0;
+ int res = 0;
+ UINT32 orig_pc = cpustate->pc;
+
+ /* Compute the target address from the lbroff field. */
+ lbroff = sign_ext ((insn & 0x03ffffff), 26);
+ target_addr = (INT32)cpustate->pc + 4 + (lbroff << 2);
+
+ /* Determine comparison result. */
+ res = (GET_PSR_CC () == 1);
+
+ /* Careful. Unlike bla, the delay slot instruction is only executed
+ if the branch is taken. */
+ if (res)
+ {
+ /* Execute delay slot instruction. */
+ cpustate->pc += 4;
+ decode_exec (cpustate, ifetch (cpustate, orig_pc + 4), 0);
+ cpustate->pc = orig_pc;
+ if (cpustate->pending_trap)
+ {
+ cpustate->pending_trap |= TRAP_IN_DELAY_SLOT;
+ goto ab_op;
+ }
+ }
+
+ /* Since this branch is delayed, we must jump 2 instructions if
+ if isn't taken. */
+ if (res)
+ cpustate->pc = target_addr;
+ else
+ cpustate->pc += 8;
+
+ cpustate->pc_updated = 1;
+
+ ab_op:
+ ;
+}
+
+
+/* Execute "bnc.t lbroff" instruction. */
+static void insn_bnct (i860s *cpustate, UINT32 insn)
+{
+ UINT32 target_addr = 0;
+ INT32 lbroff = 0;
+ int res = 0;
+ UINT32 orig_pc = cpustate->pc;
+
+ /* Compute the target address from the lbroff field. */
+ lbroff = sign_ext ((insn & 0x03ffffff), 26);
+ target_addr = (INT32)cpustate->pc + 4 + (lbroff << 2);
+
+ /* Determine comparison result. */
+ res = (GET_PSR_CC () == 0);
+
+ /* Careful. Unlike bla, the delay slot instruction is only executed
+ if the branch is taken. */
+ if (res)
+ {
+ /* Execute delay slot instruction. */
+ cpustate->pc += 4;
+ decode_exec (cpustate, ifetch (cpustate, orig_pc + 4), 0);
+ cpustate->pc = orig_pc;
+ if (cpustate->pending_trap)
+ {
+ cpustate->pending_trap |= TRAP_IN_DELAY_SLOT;
+ goto ab_op;
+ }
+ }
+
+ /* Since this branch is delayed, we must jump 2 instructions if
+ if isn't taken. */
+ if (res)
+ cpustate->pc = target_addr;
+ else
+ cpustate->pc += 8;
+
+ cpustate->pc_updated = 1;
+
+ ab_op:
+ ;
+}
+
+
+/* Execute "call lbroff" instruction. */
+static void insn_call (i860s *cpustate, UINT32 insn)
+{
+ UINT32 target_addr = 0;
+ INT32 lbroff = 0;
+ UINT32 orig_pc = cpustate->pc;
+
+ /* Compute the target address from the lbroff field. */
+ lbroff = sign_ext ((insn & 0x03ffffff), 26);
+ target_addr = (INT32)cpustate->pc + 4 + (lbroff << 2);
+
+ /* Execute the delay slot instruction. */
+ cpustate->pc += 4;
+ decode_exec (cpustate, ifetch (cpustate, orig_pc + 4), 0);
+ cpustate->pc = orig_pc;
+ if (cpustate->pending_trap)
+ {
+ cpustate->pending_trap |= TRAP_IN_DELAY_SLOT;
+ goto ab_op;
+ }
+
+ /* Sets the return pointer (r1). */
+ set_iregval (1, orig_pc + 8);
+
+ /* New target. */
+ cpustate->pc = target_addr;
+ cpustate->pc_updated = 1;
+
+ ab_op:;
+}
+
+
+/* Execute "br lbroff". */
+static void insn_br (i860s *cpustate, UINT32 insn)
+{
+ UINT32 target_addr = 0;
+ INT32 lbroff = 0;
+ UINT32 orig_pc = cpustate->pc;
+
+ /* Compute the target address from the lbroff field. */
+ lbroff = sign_ext ((insn & 0x03ffffff), 26);
+ target_addr = (INT32)cpustate->pc + 4 + (lbroff << 2);
+
+ /* Execute the delay slot instruction. */
+ cpustate->pc += 4;
+ decode_exec (cpustate, ifetch (cpustate, orig_pc + 4), 0);
+ cpustate->pc = orig_pc;
+ if (cpustate->pending_trap)
+ {
+ cpustate->pending_trap |= TRAP_IN_DELAY_SLOT;
+ goto ab_op;
+ }
+
+ /* New target. */
+ cpustate->pc = target_addr;
+ cpustate->pc_updated = 1;
+
+ ab_op:;
+}
+
+
+/* Execute "bri isrc1ni" instruction.
+ Note: I didn't merge this code with calli because bri must do
+ a lot of flag manipulation if any trap bits are set. */
+static void insn_bri (i860s *cpustate, UINT32 insn)
+{
+ UINT32 isrc1 = get_isrc1 (insn);
+ UINT32 orig_pc = cpustate->pc;
+ UINT32 orig_psr = cpustate->cregs[CR_PSR];
+ UINT32 orig_src1_val = get_iregval (isrc1);
+
+#if 1 /* TURBO. */
+ cpustate->cregs[CR_PSR] &= ~PSR_ALL_TRAP_BITS_MASK;
+#endif
+
+ /* Execute the delay slot instruction. */
+ cpustate->pc += 4;
+ decode_exec (cpustate, ifetch (cpustate, orig_pc + 4), 0);
+ cpustate->pc = orig_pc;
+
+ /* Delay slot insn caused a trap, abort operation. */
+ if (cpustate->pending_trap)
+ {
+ cpustate->pending_trap |= TRAP_IN_DELAY_SLOT;
+ goto ab_op;
+ }
+
+ /* If any trap bits are set, we need to do the return from
+ trap work. Note, we must use the PSR value that existed
+ before the delay slot instruction was executed since the
+ delay slot instruction might itself cause a trap bit to
+ be set. */
+ if (orig_psr & PSR_ALL_TRAP_BITS_MASK)
+ {
+ /* Restore U and IM from their previous copies. */
+ SET_PSR_U (GET_PSR_PU ());
+ SET_PSR_IM (GET_PSR_PIM ());
+
+ cpustate->fir_gets_trap_addr = 0;
+ }
+
+ /* Update PC. */
+ cpustate->pc = orig_src1_val;
+
+ cpustate->pc_updated = 1;
+ ab_op:;
+}
+
+/* Execute "calli isrc1ni" instruction. */
+static void insn_calli (i860s *cpustate, UINT32 insn)
+{
+ UINT32 isrc1 = get_isrc1 (insn);
+ UINT32 orig_pc = cpustate->pc;
+ UINT32 orig_src1_val = get_iregval (isrc1);
+
+#ifdef TRACE_UNDEFINED_I860
+ /* Check for undefined behavior. */
+ if (isrc1 == 1)
+ {
+ /* Src1 must not be r1. */
+ fprintf (stderr, "WARNING: insn_calli (pc=0x%08x): isrc1 = r1 on a calli\n", cpustate->pc);
+ }
+#endif
+
+ /* Set return pointer before executing delay slot instruction. */
+ set_iregval (1, cpustate->pc + 8);
+
+ /* Execute the delay slot instruction. */
+ cpustate->pc += 4;
+ decode_exec (cpustate, ifetch (cpustate, orig_pc + 4), 0);
+ cpustate->pc = orig_pc;
+ if (cpustate->pending_trap)
+ {
+ set_iregval (1, orig_src1_val);
+ cpustate->pending_trap |= TRAP_IN_DELAY_SLOT;
+ goto ab_op;
+ }
+
+ /* Set new PC. */
+ cpustate->pc = orig_src1_val;
+ cpustate->pc_updated = 1;
+
+ ab_op:;
+}
+
+
+/* Execute "bla isrc1ni,isrc2,sbroff" instruction. */
+static void insn_bla (i860s *cpustate, UINT32 insn)
+{
+ UINT32 isrc1 = get_isrc1 (insn);
+ UINT32 isrc2 = get_isrc2 (insn);
+ UINT32 target_addr = 0;
+ INT32 sbroff = 0;
+ int lcc_tmp = 0;
+ UINT32 orig_pc = cpustate->pc;
+ UINT32 orig_isrc2val = get_iregval (isrc2);
+
+#ifdef TRACE_UNDEFINED_I860
+ /* Check for undefined behavior. */
+ if (isrc1 == isrc2)
+ {
+ /* Src1 and src2 the same is undefined i860XR behavior. */
+ fprintf (stderr, "WARNING: insn_bla (pc=0x%08x): isrc1 and isrc2 are the same (ignored)\n", cpustate->pc);
+ return;
+ }
+#endif
+
+ /* Compute the target address from the sbroff field. */
+ sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
+ target_addr = (INT32)cpustate->pc + 4 + (sbroff << 2);
+
+ /* Determine comparison result based on opcode. */
+ lcc_tmp = ((INT32)get_iregval (isrc2) >= -(INT32)get_iregval (isrc1));
+
+ set_iregval (isrc2, get_iregval (isrc1) + orig_isrc2val);
+
+ /* Execute the delay slot instruction. */
+ cpustate->pc += 4;
+ decode_exec (cpustate, ifetch (cpustate, orig_pc + 4), 0);
+ cpustate->pc = orig_pc;
+ if (cpustate->pending_trap)
+ {
+ cpustate->pending_trap |= TRAP_IN_DELAY_SLOT;
+ goto ab_op;
+ }
+
+ if (GET_PSR_LCC ())
+ cpustate->pc = target_addr;
+ else
+ {
+ /* Since this branch is delayed, we must jump 2 instructions if
+ if isn't taken. */
+ cpustate->pc += 8;
+ }
+ SET_PSR_LCC (lcc_tmp);
+
+ cpustate->pc_updated = 1;
+ ab_op:;
+}
+
+
+/* Execute "flush #const(isrc2)" or "flush #const(isrc2)++" instruction. */
+static void insn_flush (i860s *cpustate, UINT32 insn)
+{
+ UINT32 src1val = sign_ext (get_imm16 (insn), 16);
+ UINT32 isrc2 = get_isrc2 (insn);
+ int auto_inc = (insn & 1);
+ UINT32 eff = 0;
+
+ /* Technically, idest should be encoded as r0 because idest
+ is undefined after the instruction. We don't currently
+ check for this.
+
+ Flush D$ block at address #const+isrc2. Block is undefined
+ after. The effective address must be 16-byte aligned.
+
+ FIXME: Need to examine RB and RC and do this right.
+ */
+
+ /* Chop off lower bits of displacement to 16-byte alignment. */
+ src1val &= ~(16-1);
+ eff = src1val + get_iregval (isrc2);
+ if (auto_inc)
+ set_iregval (isrc2, eff);
+
+ /* In user mode, the flush is ignored. */
+ if (GET_PSR_U () == 0)
+ {
+ /* If line is dirty, write it to memory and invalidate.
+ NOTE: The actual dirty write is unimplemented in the MAME version
+ as we don't emulate the dcache. */
+ }
+}
+
+
+/* Execute "[p]fmul.{ss,sd,dd} fsrc1,fsrc2,fdest" instruction or
+ pfmul3.dd fsrc1,fsrc2,fdest.
+
+ The pfmul3.dd differs from pfmul.dd in that it treats the pipeline
+ as 3 stages, even though it is a double precision multiply. */
+static void insn_fmul (i860s *cpustate, UINT32 insn)
+{
+ UINT32 fsrc1 = get_fsrc1 (insn);
+ UINT32 fsrc2 = get_fsrc2 (insn);
+ UINT32 fdest = get_fdest (insn);
+ int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
+ int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
+ int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
+ double dbl_tmp_dest = 0.0;
+ float sgl_tmp_dest = 0.0;
+ double dbl_last_stage_contents = 0.0;
+ float sgl_last_stage_contents = 0.0;
+ int is_pfmul3 = insn & 0x4;
+ int num_stages = (src_prec && !is_pfmul3) ? 2 : 3;
+
+ /* Only .dd is valid for pfmul. */
+ if (is_pfmul3 && (insn & 0x180) != 0x180)
+ {
+ unrecog_opcode (cpustate->pc, insn);
+ return;
+ }
+
+ /* Check for invalid .ds combination. */
+ if ((insn & 0x180) == 0x100)
+ {
+ unrecog_opcode (cpustate->pc, insn);
+ return;
+ }
+
+ /* For pipelined version, retrieve the contents of the last stage
+ of the pipeline, whose precision is specified by the MRP bit
+ of the stage's result-status bits. Note for pfmul, the number
+ of stages is determined by the source precision of the current
+ operation. */
+ if (piped)
+ {
+ if (cpustate->M[num_stages - 1].stat.mrp)
+ dbl_last_stage_contents = cpustate->M[num_stages - 1].val.d;
+ else
+ sgl_last_stage_contents = cpustate->M[num_stages - 1].val.s;
+ }
+
+ /* Do the operation, being careful about source and result
+ precision. */
+ if (src_prec)
+ {
+ double v1 = get_fregval_d (cpustate, fsrc1);
+ double v2 = get_fregval_d (cpustate, fsrc2);
+
+ /* For pipelined mul, if fsrc2 is the same as fdest, then the last
+ stage is bypassed to fsrc2 (rather than using the value in fsrc2).
+ This bypass is not available for fsrc1, and is undefined behavior. */
+ if (0 && piped && fdest != 0 && fsrc1 == fdest)
+ v1 = dbl_last_stage_contents;
+ if (piped && fdest != 0 && fsrc2 == fdest)
+ v2 = dbl_last_stage_contents;
+
+ if (res_prec)
+ dbl_tmp_dest = v1 * v2;
+ else
+ sgl_tmp_dest = (float)(v1 * v2);
+ }
+ else
+ {
+ float v1 = get_fregval_s (cpustate, fsrc1);
+ float v2 = get_fregval_s (cpustate, fsrc2);
+
+ /* For pipelined mul, if fsrc2 is the same as fdest, then the last
+ stage is bypassed to fsrc2 (rather than using the value in fsrc2).
+ This bypass is not available for fsrc1, and is undefined behavior. */
+ if (0 && piped && fdest != 0 && fsrc1 == fdest)
+ v1 = sgl_last_stage_contents;
+ if (piped && fdest != 0 && fsrc2 == fdest)
+ v2 = sgl_last_stage_contents;
+
+ if (res_prec)
+ dbl_tmp_dest = (double)(v1 * v2);
+ else
+ sgl_tmp_dest = v1 * v2;
+ }
+
+ /* FIXME: Set result-status bits besides MRP. And copy to fsr from
+ last stage. */
+ /* FIXME: Scalar version flows through all stages. */
+ /* FIXME: Mixed precision (only wierd for pfmul). */
+ if (!piped)
+ {
+ /* Scalar version writes the current calculation to the fdest
+ register, with precision specified by the R bit. */
+ if (res_prec)
+ set_fregval_d (cpustate, fdest, dbl_tmp_dest);
+ else
+ set_fregval_s (cpustate, fdest, sgl_tmp_dest);
+ }
+ else
+ {
+ /* Pipelined version writes fdest with the result from the last
+ stage of the pipeline. */
+#if 1 /* FIXME: WIP on FSR update. This may not be correct. */
+ /* Copy 3rd stage MRP to FSR. */
+ if (cpustate->M[num_stages - 2 /* 1 */].stat.mrp)
+ cpustate->cregs[CR_FSR] |= 0x10000000;
+ else
+ cpustate->cregs[CR_FSR] &= ~0x10000000;
+#endif
+
+ if (cpustate->M[num_stages - 1].stat.mrp)
+ set_fregval_d (cpustate, fdest, dbl_last_stage_contents);
+ else
+ set_fregval_s (cpustate, fdest, sgl_last_stage_contents);
+
+ /* Now advance pipeline and write current calculation to
+ first stage. */
+ if (num_stages == 3)
+ {
+ cpustate->M[2] = cpustate->M[1];
+ cpustate->M[1] = cpustate->M[0];
+ }
+ else
+ cpustate->M[1] = cpustate->M[0];
+
+ if (res_prec)
+ {
+ cpustate->M[0].val.d = dbl_tmp_dest;
+ cpustate->M[0].stat.mrp = 1;
+ }
+ else
+ {
+ cpustate->M[0].val.s = sgl_tmp_dest;
+ cpustate->M[0].stat.mrp = 0;
+ }
+ }
+}
+
+
+/* Execute "fmlow.dd fsrc1,fsrc2,fdest" instruction. */
+static void insn_fmlow (i860s *cpustate, UINT32 insn)
+{
+ UINT32 fsrc1 = get_fsrc1 (insn);
+ UINT32 fsrc2 = get_fsrc2 (insn);
+ UINT32 fdest = get_fdest (insn);
+
+ double v1 = get_fregval_d (cpustate, fsrc1);
+ double v2 = get_fregval_d (cpustate, fsrc2);
+ INT64 i1 = *(UINT64 *)&v1;
+ INT64 i2 = *(UINT64 *)&v2;
+ INT64 tmp = 0;
+
+ /* Only .dd is valid for fmlow. */
+ if ((insn & 0x180) != 0x180)
+ {
+ unrecog_opcode (cpustate->pc, insn);
+ return;
+ }
+
+ /* The lower 32-bits are obvious. What exactly goes in the upper
+ bits?
+ Technically, the upper-most 10 bits are undefined, but i'd like
+ to be undefined in the same way as the real i860 if possible. */
+
+ /* Keep lower 53 bits of multiply. */
+ tmp = i1 * i2;
+ tmp &= 0x001fffffffffffffULL;
+ tmp |= (i1 & 0x8000000000000000LL) ^ (i2 & 0x8000000000000000LL);
+ set_fregval_d (cpustate, fdest, *(double *)&tmp);
+}
+
+
+/* Execute [p]fadd.{ss,sd,dd} fsrc1,fsrc2,fdest (.ds disallowed above). */
+static void insn_fadd_sub (i860s *cpustate, UINT32 insn)
+{
+ UINT32 fsrc1 = get_fsrc1 (insn);
+ UINT32 fsrc2 = get_fsrc2 (insn);
+ UINT32 fdest = get_fdest (insn);
+ int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
+ int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
+ int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
+ int is_sub = insn & 1; /* 1 = sub, 0 = add. */
+ double dbl_tmp_dest = 0.0;
+ float sgl_tmp_dest = 0.0;
+ double dbl_last_stage_contents = 0.0;
+ float sgl_last_stage_contents = 0.0;
+
+ /* Check for invalid .ds combination. */
+ if ((insn & 0x180) == 0x100)
+ {
+ unrecog_opcode (cpustate->pc, insn);
+ return;
+ }
+
+ /* For pipelined version, retrieve the contents of the last stage
+ of the pipeline, whose precision is specified by the ARP bit
+ of the stage's result-status bits. There are always three stages
+ for pfadd/pfsub. */
+ if (piped)
+ {
+ if (cpustate->A[2].stat.arp)
+ dbl_last_stage_contents = cpustate->A[2].val.d;
+ else
+ sgl_last_stage_contents = cpustate->A[2].val.s;
+ }
+
+ /* Do the operation, being careful about source and result
+ precision. */
+ if (src_prec)
+ {
+ double v1 = get_fregval_d (cpustate, fsrc1);
+ double v2 = get_fregval_d (cpustate, fsrc2);
+
+ /* For pipelined add/sub, if fsrc1 is the same as fdest, then the last
+ stage is bypassed to fsrc1 (rather than using the value in fsrc1).
+ Likewise for fsrc2. */
+ if (piped && fdest != 0 && fsrc1 == fdest)
+ v1 = dbl_last_stage_contents;
+ if (piped && fdest != 0 && fsrc2 == fdest)
+ v2 = dbl_last_stage_contents;
+
+ if (res_prec)
+ dbl_tmp_dest = is_sub ? v1 - v2 : v1 + v2;
+ else
+ sgl_tmp_dest = is_sub ? (float)(v1 - v2) : (float)(v1 + v2);
+ }
+ else
+ {
+ float v1 = get_fregval_s (cpustate, fsrc1);
+ float v2 = get_fregval_s (cpustate, fsrc2);
+
+ /* For pipelined add/sub, if fsrc1 is the same as fdest, then the last
+ stage is bypassed to fsrc1 (rather than using the value in fsrc1).
+ Likewise for fsrc2. */
+ if (piped && fdest != 0 && fsrc1 == fdest)
+ v1 = sgl_last_stage_contents;
+ if (piped && fdest != 0 && fsrc2 == fdest)
+ v2 = sgl_last_stage_contents;
+
+ if (res_prec)
+ dbl_tmp_dest = is_sub ? (double)(v1 - v2) : (double)(v1 + v2);
+ else
+ sgl_tmp_dest = is_sub ? v1 - v2 : v1 + v2;
+ }
+
+ /* FIXME: Set result-status bits besides ARP. And copy to fsr from
+ last stage. */
+ /* FIXME: Scalar version flows through all stages. */
+ if (!piped)
+ {
+ /* Scalar version writes the current calculation to the fdest
+ register, with precision specified by the R bit. */
+ if (res_prec)
+ set_fregval_d (cpustate, fdest, dbl_tmp_dest);
+ else
+ set_fregval_s (cpustate, fdest, sgl_tmp_dest);
+ }
+ else
+ {
+ /* Pipelined version writes fdest with the result from the last
+ stage of the pipeline, with precision specified by the ARP
+ bit of the stage's result-status bits. */
+#if 1 /* FIXME: WIP on FSR update. This may not be correct. */
+ /* Copy 3rd stage ARP to FSR. */
+ if (cpustate->A[1 /* 2 */].stat.arp)
+ cpustate->cregs[CR_FSR] |= 0x20000000;
+ else
+ cpustate->cregs[CR_FSR] &= ~0x20000000;
+#endif
+ if (cpustate->A[2].stat.arp) /* 3rd (last) stage. */
+ set_fregval_d (cpustate, fdest, dbl_last_stage_contents);
+ else
+ set_fregval_s (cpustate, fdest, sgl_last_stage_contents);
+
+ /* Now advance pipeline and write current calculation to
+ first stage. */
+ cpustate->A[2] = cpustate->A[1];
+ cpustate->A[1] = cpustate->A[0];
+ if (res_prec)
+ {
+ cpustate->A[0].val.d = dbl_tmp_dest;
+ cpustate->A[0].stat.arp = 1;
+ }
+ else
+ {
+ cpustate->A[0].val.s = sgl_tmp_dest;
+ cpustate->A[0].stat.arp = 0;
+ }
+ }
+}
+
+
+/* Operand types for PFAM/PFMAM routine below. */
+enum {
+ OP_SRC1 = 0,
+ OP_SRC2 = 1,
+ OP_KI = 2,
+ OP_KR = 4,
+ OP_T = 8,
+ OP_MPIPE = 16,
+ OP_APIPE = 32,
+ FLAGM = 64 /* Indicates PFMAM uses M rather than A pipe result. */
+};
+
+/* A table to map DPC value to source operands.
+
+ The PFAM and PFMAM tables are nearly identical, and the only differences
+ are that every time PFAM uses the A pipe, PFMAM uses the M pipe instead.
+ So we only represent the PFAM table and use a special flag on any entry
+ where the PFMAM table would use the M pipe rather than the A pipe.
+ Also, entry 16 is not valid for PFMAM. */
+static struct
+{
+ int M_unit_op1;
+ int M_unit_op2;
+ int A_unit_op1;
+ int A_unit_op2;
+ int T_loaded;
+ int K_loaded;
+} src_opers[] = {
+ /* 0000 */ { OP_KR, OP_SRC2, OP_SRC1, OP_MPIPE, 0, 0},
+ /* 0001 */ { OP_KR, OP_SRC2, OP_T, OP_MPIPE, 0, 1},
+ /* 0010 */ { OP_KR, OP_SRC2, OP_SRC1, OP_APIPE|FLAGM, 1, 0},
+ /* 0011 */ { OP_KR, OP_SRC2, OP_T, OP_APIPE|FLAGM, 1, 1},
+ /* 0100 */ { OP_KI, OP_SRC2, OP_SRC1, OP_MPIPE, 0, 0},
+ /* 0101 */ { OP_KI, OP_SRC2, OP_T, OP_MPIPE, 0, 1},
+ /* 0110 */ { OP_KI, OP_SRC2, OP_SRC1, OP_APIPE|FLAGM, 1, 0},
+ /* 0111 */ { OP_KI, OP_SRC2, OP_T, OP_APIPE|FLAGM, 1, 1},
+ /* 1000 */ { OP_KR, OP_APIPE|FLAGM, OP_SRC1, OP_SRC2, 1, 0},
+ /* 1001 */ { OP_SRC1, OP_SRC2, OP_APIPE|FLAGM, OP_MPIPE, 0, 0},
+ /* 1010 */ { OP_KR, OP_APIPE|FLAGM, OP_SRC1, OP_SRC2, 0, 0},
+ /* 1011 */ { OP_SRC1, OP_SRC2, OP_T, OP_APIPE|FLAGM, 1, 0},
+ /* 1100 */ { OP_KI, OP_APIPE|FLAGM, OP_SRC1, OP_SRC2, 1, 0},
+ /* 1101 */ { OP_SRC1, OP_SRC2, OP_T, OP_MPIPE, 0, 0},
+ /* 1110 */ { OP_KI, OP_APIPE|FLAGM, OP_SRC1, OP_SRC2, 0, 0},
+ /* 1111 */ { OP_SRC1, OP_SRC2, OP_T, OP_APIPE|FLAGM, 0, 0}
+};
+
+float get_fval_from_optype_s (i860s *cpustate, UINT32 insn, int optype)
+{
+ float retval = 0.0;
+ UINT32 fsrc1 = get_fsrc1 (insn);
+ UINT32 fsrc2 = get_fsrc2 (insn);
+
+ optype &= ~FLAGM;
+ switch (optype)
+ {
+ case OP_SRC1:
+ retval = get_fregval_s (cpustate, fsrc1);
+ break;
+ case OP_SRC2:
+ retval = get_fregval_s (cpustate, fsrc2);
+ break;
+ case OP_KI:
+ retval = cpustate->KI.s;
+ break;
+ case OP_KR:
+ retval = cpustate->KR.s;
+ break;
+ case OP_T:
+ retval = cpustate->T.s;
+ break;
+ case OP_MPIPE:
+ /* Last stage is 3rd stage for single precision input. */
+ retval = cpustate->M[2].val.s;
+ break;
+ case OP_APIPE:
+ retval = cpustate->A[2].val.s;
+ break;
+ default:
+ assert (0);
+ }
+
+ return retval;
+}
+
+
+double get_fval_from_optype_d (i860s *cpustate, UINT32 insn, int optype)
+{
+ double retval = 0.0;
+ UINT32 fsrc1 = get_fsrc1 (insn);
+ UINT32 fsrc2 = get_fsrc2 (insn);
+
+ optype &= ~FLAGM;
+ switch (optype)
+ {
+ case OP_SRC1:
+ retval = get_fregval_d (cpustate, fsrc1);
+ break;
+ case OP_SRC2:
+ retval = get_fregval_d (cpustate, fsrc2);
+ break;
+ case OP_KI:
+ retval = cpustate->KI.d;
+ break;
+ case OP_KR:
+ retval = cpustate->KR.d;
+ break;
+ case OP_T:
+ retval = cpustate->T.d;
+ break;
+ case OP_MPIPE:
+ /* Last stage is 2nd stage for double precision input. */
+ retval = cpustate->M[1].val.d;
+ break;
+ case OP_APIPE:
+ retval = cpustate->A[2].val.d;
+ break;
+ default:
+ assert (0);
+ }
+
+ return retval;
+}
+
+
+/* Execute pf[m]{a,s}m.{ss,sd,dd} fsrc1,fsrc2,fdest (FP dual ops).
+
+ Since these are always pipelined, the P bit is used to distinguish
+ family pfam (P=1) from family pfmam (P=0), and the lower 4 bits
+ of the extended opcode is the DPC.
+
+ Note also that the S and R bits are slightly different than normal
+ floating point operations. The S bit denotes the precision of the
+ multiplication source, while the R bit denotes the precision of
+ the addition source as well as precision of all results. */
+static void insn_dualop (i860s *cpustate, UINT32 insn)
+{
+ UINT32 fsrc1 = get_fsrc1 (insn);
+ UINT32 fsrc2 = get_fsrc2 (insn);
+ UINT32 fdest = get_fdest (insn);
+ int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
+ int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
+ int is_pfam = insn & 0x400; /* 1 = pfam, 0 = pfmam. */
+ int is_sub = insn & 0x10; /* 1 = pf[m]sm, 0 = pf[m]am. */
+ double dbl_tmp_dest_mul = 0.0;
+ float sgl_tmp_dest_mul = 0.0;
+ double dbl_tmp_dest_add = 0.0;
+ float sgl_tmp_dest_add = 0.0;
+ double dbl_last_Mstage_contents = 0.0;
+ float sgl_last_Mstage_contents = 0.0;
+ double dbl_last_Astage_contents = 0.0;
+ float sgl_last_Astage_contents = 0.0;
+ int num_mul_stages = src_prec ? 2 : 3;
+
+ int dpc = insn & 0xf;
+ int M_unit_op1 = src_opers[dpc].M_unit_op1;
+ int M_unit_op2 = src_opers[dpc].M_unit_op2;
+ int A_unit_op1 = src_opers[dpc].A_unit_op1;
+ int A_unit_op2 = src_opers[dpc].A_unit_op2;
+ int T_loaded = src_opers[dpc].T_loaded;
+ int K_loaded = src_opers[dpc].K_loaded;
+
+ /* Check for invalid .ds combination. */
+ if ((insn & 0x180) == 0x100)
+ {
+ unrecog_opcode (cpustate->pc, insn);
+ return;
+ }
+
+ if (is_pfam == 0)
+ {
+ /* Check for invalid DPC combination 16 for PFMAM. */
+ if (dpc == 16)
+ {
+ unrecog_opcode (cpustate->pc, insn);
+ return;
+ }
+
+ /* PFMAM table adjustments (M_unit_op1 is never a pipe stage,
+ so no adjustment made for it). */
+ M_unit_op2 = (M_unit_op2 & FLAGM) ? OP_MPIPE : M_unit_op2;
+ A_unit_op1 = (A_unit_op1 & FLAGM) ? OP_MPIPE : A_unit_op1;
+ A_unit_op2 = (A_unit_op2 & FLAGM) ? OP_MPIPE : A_unit_op2;
+ }
+
+ /* FIXME: Check for fsrc1/fdest overlap for some mul DPC combinations. */
+
+ /* Retrieve the contents of the last stage of the multiplier pipeline,
+ whose precision is specified by the MRP bit of the stage's result-
+ status bits. Note for multiply, the number of stages is determined
+ by the source precision of the current operation. */
+ if (cpustate->M[num_mul_stages - 1].stat.mrp)
+ dbl_last_Mstage_contents = cpustate->M[num_mul_stages - 1].val.d;
+ else
+ sgl_last_Mstage_contents = cpustate->M[num_mul_stages - 1].val.s;
+
+ /* Similarly, retrieve the last stage of the adder pipe. */
+ if (cpustate->A[2].stat.arp)
+ dbl_last_Astage_contents = cpustate->A[2].val.d;
+ else
+ sgl_last_Astage_contents = cpustate->A[2].val.s;
+
+ /* Do the mul operation, being careful about source and result
+ precision. */
+ if (src_prec)
+ {
+ double v1 = get_fval_from_optype_d (cpustate, insn, M_unit_op1);
+ double v2 = get_fval_from_optype_d (cpustate, insn, M_unit_op2);
+
+ /* For mul, if fsrc2 is the same as fdest, then the last stage
+ is bypassed to fsrc2 (rather than using the value in fsrc2).
+ This bypass is not available for fsrc1, and is undefined behavior. */
+ if (0 && M_unit_op1 == OP_SRC1 && fdest != 0 && fsrc1 == fdest)
+ v1 = is_pfam ? dbl_last_Astage_contents : dbl_last_Mstage_contents;
+ if (M_unit_op2 == OP_SRC2 && fdest != 0 && fsrc2 == fdest)
+ v2 = is_pfam ? dbl_last_Astage_contents : dbl_last_Mstage_contents;
+
+ if (res_prec)
+ dbl_tmp_dest_mul = v1 * v2;
+ else
+ sgl_tmp_dest_mul = (float)(v1 * v2);
+ }
+ else
+ {
+ float v1 = get_fval_from_optype_s (cpustate, insn, M_unit_op1);
+ float v2 = get_fval_from_optype_s (cpustate, insn, M_unit_op2);
+
+ /* For mul, if fsrc2 is the same as fdest, then the last stage
+ is bypassed to fsrc2 (rather than using the value in fsrc2).
+ This bypass is not available for fsrc1, and is undefined behavior. */
+ if (0 && M_unit_op1 == OP_SRC1 && fdest != 0 && fsrc1 == fdest)
+ v1 = is_pfam ? sgl_last_Astage_contents : sgl_last_Mstage_contents;
+ if (M_unit_op2 == OP_SRC2 && fdest != 0 && fsrc2 == fdest)
+ v2 = is_pfam ? sgl_last_Astage_contents : sgl_last_Mstage_contents;
+
+ if (res_prec)
+ dbl_tmp_dest_mul = (double)(v1 * v2);
+ else
+ sgl_tmp_dest_mul = v1 * v2;
+ }
+
+ /* Do the add operation, being careful about source and result
+ precision. Remember, the R bit indicates source and result precision
+ here. */
+ if (res_prec)
+ {
+ double v1 = get_fval_from_optype_d (cpustate, insn, A_unit_op1);
+ double v2 = get_fval_from_optype_d (cpustate, insn, A_unit_op2);
+
+ /* For add/sub, if fsrc1 is the same as fdest, then the last stage
+ is bypassed to fsrc1 (rather than using the value in fsrc1).
+ Likewise for fsrc2. */
+ if (A_unit_op1 == OP_SRC1 && fdest != 0 && fsrc1 == fdest)
+ v1 = is_pfam ? dbl_last_Astage_contents : dbl_last_Mstage_contents;
+ if (A_unit_op2 == OP_SRC2 && fdest != 0 && fsrc2 == fdest)
+ v2 = is_pfam ? dbl_last_Astage_contents : dbl_last_Mstage_contents;
+
+ if (res_prec)
+ dbl_tmp_dest_add = is_sub ? v1 - v2 : v1 + v2;
+ else
+ sgl_tmp_dest_add = is_sub ? (float)(v1 - v2) : (float)(v1 + v2);
+ }
+ else
+ {
+ float v1 = get_fval_from_optype_s (cpustate, insn, A_unit_op1);
+ float v2 = get_fval_from_optype_s (cpustate, insn, A_unit_op2);
+
+ /* For add/sub, if fsrc1 is the same as fdest, then the last stage
+ is bypassed to fsrc1 (rather than using the value in fsrc1).
+ Likewise for fsrc2. */
+ if (A_unit_op1 == OP_SRC1 && fdest != 0 && fsrc1 == fdest)
+ v1 = is_pfam ? sgl_last_Astage_contents : sgl_last_Mstage_contents;
+ if (A_unit_op2 == OP_SRC2 && fdest != 0 && fsrc2 == fdest)
+ v2 = is_pfam ? sgl_last_Astage_contents : sgl_last_Mstage_contents;
+
+ if (res_prec)
+ dbl_tmp_dest_add = is_sub ? (double)(v1 - v2) : (double)(v1 + v2);
+ else
+ sgl_tmp_dest_add = is_sub ? v1 - v2 : v1 + v2;
+ }
+
+ /* If necessary, load T. */
+ if (T_loaded)
+ {
+ /* T is loaded from the result of the last stage of the multiplier. */
+ if (cpustate->M[num_mul_stages - 1].stat.mrp)
+ cpustate->T.d = dbl_last_Mstage_contents;
+ else
+ cpustate->T.s = sgl_last_Mstage_contents;
+ }
+
+ /* If necessary, load KR or KI. */
+ if (K_loaded)
+ {
+ /* KI or KR is loaded from the first register input. */
+ if (M_unit_op1 == OP_KI)
+ {
+ if (src_prec)
+ cpustate->KI.d = get_fregval_d (cpustate, fsrc1);
+ else
+ cpustate->KI.s = get_fregval_s (cpustate, fsrc1);
+ }
+ else if (M_unit_op1 == OP_KR)
+ {
+ if (src_prec)
+ cpustate->KR.d = get_fregval_d (cpustate, fsrc1);
+ else
+ cpustate->KR.s = get_fregval_s (cpustate, fsrc1);
+ }
+ else
+ assert (0);
+ }
+
+ /* Now update fdest (either from adder pipe or multiplier pipe,
+ depending on whether the instruction is pfam or pfmam). */
+ if (is_pfam)
+ {
+ /* Update fdest with the result from the last stage of the
+ adder pipeline, with precision specified by the ARP
+ bit of the stage's result-status bits. */
+ if (cpustate->A[2].stat.arp)
+ set_fregval_d (cpustate, fdest, dbl_last_Astage_contents);
+ else
+ set_fregval_s (cpustate, fdest, sgl_last_Astage_contents);
+ }
+ else
+ {
+ /* Update fdest with the result from the last stage of the
+ multiplier pipeline, with precision specified by the MRP
+ bit of the stage's result-status bits. */
+ if (cpustate->M[num_mul_stages - 1].stat.mrp)
+ set_fregval_d (cpustate, fdest, dbl_last_Mstage_contents);
+ else
+ set_fregval_s (cpustate, fdest, sgl_last_Mstage_contents);
+ }
+
+ /* FIXME: Set result-status bits besides MRP. And copy to fsr from
+ last stage. */
+ /* FIXME: Mixed precision (only wierd for pfmul). */
+#if 1 /* FIXME: WIP on FSR update. This may not be correct. */
+ /* Copy 3rd stage MRP to FSR. */
+ if (cpustate->M[num_mul_stages - 2 /* 1 */].stat.mrp)
+ cpustate->cregs[CR_FSR] |= 0x10000000;
+ else
+ cpustate->cregs[CR_FSR] &= ~0x10000000;
+#endif
+
+ /* Now advance multiplier pipeline and write current calculation to
+ first stage. */
+ if (num_mul_stages == 3)
+ {
+ cpustate->M[2] = cpustate->M[1];
+ cpustate->M[1] = cpustate->M[0];
+ }
+ else
+ cpustate->M[1] = cpustate->M[0];
+
+ if (res_prec)
+ {
+ cpustate->M[0].val.d = dbl_tmp_dest_mul;
+ cpustate->M[0].stat.mrp = 1;
+ }
+ else
+ {
+ cpustate->M[0].val.s = sgl_tmp_dest_mul;
+ cpustate->M[0].stat.mrp = 0;
+ }
+
+ /* FIXME: Set result-status bits besides ARP. And copy to fsr from
+ last stage. */
+#if 1 /* FIXME: WIP on FSR update. This may not be correct. */
+ /* Copy 3rd stage ARP to FSR. */
+ if (cpustate->A[1 /* 2 */].stat.arp)
+ cpustate->cregs[CR_FSR] |= 0x20000000;
+ else
+ cpustate->cregs[CR_FSR] &= ~0x20000000;
+#endif
+
+ /* Now advance adder pipeline and write current calculation to
+ first stage. */
+ cpustate->A[2] = cpustate->A[1];
+ cpustate->A[1] = cpustate->A[0];
+ if (res_prec)
+ {
+ cpustate->A[0].val.d = dbl_tmp_dest_add;
+ cpustate->A[0].stat.arp = 1;
+ }
+ else
+ {
+ cpustate->A[0].val.s = sgl_tmp_dest_add;
+ cpustate->A[0].stat.arp = 0;
+ }
+}
+
+
+/* Execute frcp.{ss,sd,dd} fsrc2,fdest (.ds disallowed above). */
+static void insn_frcp (i860s *cpustate, UINT32 insn)
+{
+ UINT32 fsrc2 = get_fsrc2 (insn);
+ UINT32 fdest = get_fdest (insn);
+ int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
+ int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
+
+ /* Do the operation, being careful about source and result
+ precision. */
+ if (src_prec)
+ {
+ double v = get_fregval_d (cpustate, fsrc2);
+ double res;
+ if (v == (double)0.0)
+ {
+ /* Generate source-exception trap if fsrc2 is 0. */
+ if (0 /* && GET_FSR_FTE () */)
+ {
+ SET_PSR_FT (1);
+ SET_FSR_SE (1);
+ cpustate->pending_trap = GET_FSR_FTE ();
+ }
+ /* Set fdest to INF or some other exceptional value here? */
+ }
+ else
+ {
+ /* Real i860 isn't a precise as a real divide, but this should
+ be okay. */
+ SET_FSR_SE (0);
+ *((UINT64 *)&v) &= 0xfffff00000000000ULL;
+ res = (double)1.0/v;
+ *((UINT64 *)&res) &= 0xfffff00000000000ULL;
+ if (res_prec)
+ set_fregval_d (cpustate, fdest, res);
+ else
+ set_fregval_s (cpustate, fdest, (float)res);
+ }
+ }
+ else
+ {
+ float v = get_fregval_s (cpustate, fsrc2);
+ float res;
+ if (v == 0.0)
+ {
+ /* Generate source-exception trap if fsrc2 is 0. */
+ if (0 /* GET_FSR_FTE () */)
+ {
+ SET_PSR_FT (1);
+ SET_FSR_SE (1);
+ cpustate->pending_trap = GET_FSR_FTE ();
+ }
+ /* Set fdest to INF or some other exceptional value here? */
+ }
+ else
+ {
+ /* Real i860 isn't a precise as a real divide, but this should
+ be okay. */
+ SET_FSR_SE (0);
+ *((UINT32 *)&v) &= 0xffff8000;
+ res = (float)1.0/v;
+ *((UINT32 *)&res) &= 0xffff8000;
+ if (res_prec)
+ set_fregval_d (cpustate, fdest, (double)res);
+ else
+ set_fregval_s (cpustate, fdest, res);
+ }
+ }
+}
+
+
+/* Execute frsqr.{ss,sd,dd} fsrc2,fdest (.ds disallowed above). */
+static void insn_frsqr (i860s *cpustate, UINT32 insn)
+{
+ UINT32 fsrc2 = get_fsrc2 (insn);
+ UINT32 fdest = get_fdest (insn);
+ int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
+ int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
+
+ /* Check for invalid .ds combination. */
+ if ((insn & 0x180) == 0x100)
+ {
+ unrecog_opcode (cpustate->pc, insn);
+ return;
+ }
+
+ /* Check for invalid .ds combination. */
+ if ((insn & 0x180) == 0x100)
+ {
+ unrecog_opcode (cpustate->pc, insn);
+ return;
+ }
+
+ /* Do the operation, being careful about source and result
+ precision. */
+ if (src_prec)
+ {
+ double v = get_fregval_d (cpustate, fsrc2);
+ double res;
+ if (v == 0.0 || v < 0.0)
+ {
+ /* Generate source-exception trap if fsrc2 is 0 or negative. */
+ if (0 /* GET_FSR_FTE () */)
+ {
+ SET_PSR_FT (1);
+ SET_FSR_SE (1);
+ cpustate->pending_trap = GET_FSR_FTE ();
+ }
+ /* Set fdest to INF or some other exceptional value here? */
+ }
+ else
+ {
+ SET_FSR_SE (0);
+ *((UINT64 *)&v) &= 0xfffff00000000000ULL;
+ res = (double)1.0/sqrt (v);
+ *((UINT64 *)&res) &= 0xfffff00000000000ULL;
+ if (res_prec)
+ set_fregval_d (cpustate, fdest, res);
+ else
+ set_fregval_s (cpustate, fdest, (float)res);
+ }
+ }
+ else
+ {
+ float v = get_fregval_s (cpustate, fsrc2);
+ float res;
+ if (v == 0.0 || v < 0.0)
+ {
+ /* Generate source-exception trap if fsrc2 is 0 or negative. */
+ if (0 /* GET_FSR_FTE () */)
+ {
+ SET_PSR_FT (1);
+ SET_FSR_SE (1);
+ cpustate->pending_trap = GET_FSR_FTE ();
+ }
+ /* Set fdest to INF or some other exceptional value here? */
+ }
+ else
+ {
+ SET_FSR_SE (0);
+ *((UINT32 *)&v) &= 0xffff8000;
+ res = (float)1.0/sqrt (v);
+ *((UINT32 *)&res) &= 0xffff8000;
+ if (res_prec)
+ set_fregval_d (cpustate, fdest, (double)res);
+ else
+ set_fregval_s (cpustate, fdest, res);
+ }
+ }
+}
+
+
+/* Execute fxfr fsrc1,idest. */
+static void insn_fxfr (i860s *cpustate, UINT32 insn)
+{
+ UINT32 fsrc1 = get_fsrc1 (insn);
+ UINT32 idest = get_idest (insn);
+ float fv = 0;
+
+ /* This is a bit-pattern transfer, not a conversion. */
+ fv = get_fregval_s (cpustate, fsrc1);
+ set_iregval (idest, *(UINT32 *)&fv);
+}
+
+
+/* Execute [p]ftrunc.{ss,sd,dd} fsrc1,idest. */
+/* FIXME: Is .ss really a valid combination? On the one hand,
+ the programmer's reference (1990) lists ftrunc.p where .p
+ is any of {ss,sd,dd}. On the other hand, a paragraph on the
+ same page states that [p]ftrunc must specify double-precision
+ results. Inconsistent.
+ Update: The vendor SVR4 assembler does not accept .ss combination,
+ so the latter sentence above appears to be the correct way. */
+static void insn_ftrunc (i860s *cpustate, UINT32 insn)
+{
+ UINT32 fsrc1 = get_fsrc1 (insn);
+ UINT32 fdest = get_fdest (insn);
+ int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
+ int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
+ int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
+
+ /* Check for invalid .ds or .ss combinations. */
+ if ((insn & 0x080) == 0)
+ {
+ unrecog_opcode (cpustate->pc, insn);
+ return;
+ }
+
+ /* Do the operation, being careful about source and result
+ precision. Operation: fdest = integer part of fsrc1 in
+ lower 32-bits. */
+ if (src_prec)
+ {
+ double v1 = get_fregval_d (cpustate, fsrc1);
+ INT32 iv = (INT32)v1;
+ /* We always write a single, since the lower 32-bits of fdest
+ get the result (and the even numbered reg is the lower). */
+ set_fregval_s (cpustate, fdest, *(float *)&iv);
+ }
+ else
+ {
+ float v1 = get_fregval_s (cpustate, fsrc1);
+ INT32 iv = (INT32)v1;
+ /* We always write a single, since the lower 32-bits of fdest
+ get the result (and the even numbered reg is the lower). */
+ set_fregval_s (cpustate, fdest, *(float *)&iv);
+ }
+
+ /* FIXME: Handle updating of pipestages for pftrunc. */
+ /* Includes looking at ARP (add result precision.) */
+ if (piped)
+ {
+ fprintf (stderr, "insn_ftrunc: FIXME: pipelined not functional yet.\n");
+ if (res_prec)
+ set_fregval_d (cpustate, fdest, 0.0);
+ else
+ set_fregval_s (cpustate, fdest, 0.0);
+ }
+}
+
+
+/* Execute [p]famov.{ss,sd,ds,dd} fsrc1,fdest. */
+static void insn_famov (i860s *cpustate, UINT32 insn)
+{
+ UINT32 fsrc1 = get_fsrc1 (insn);
+ UINT32 fdest = get_fdest (insn);
+ int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
+ int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
+ int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
+ double dbl_tmp_dest = 0.0;
+ double sgl_tmp_dest = 0.0;
+
+ /* Do the operation, being careful about source and result
+ precision. */
+ if (src_prec)
+ {
+ double v1 = get_fregval_d (cpustate, fsrc1);
+ if (res_prec)
+ dbl_tmp_dest = v1;
+ else
+ sgl_tmp_dest = (float)v1;
+ }
+ else
+ {
+ float v1 = get_fregval_s (cpustate, fsrc1);
+ if (res_prec)
+ dbl_tmp_dest = (double)v1;
+ else
+ sgl_tmp_dest = v1;
+ }
+
+ /* FIXME: Set result-status bits besides ARP. And copy to fsr from
+ last stage. */
+ /* FIXME: Scalar version flows through all stages. */
+ if (!piped)
+ {
+ /* Scalar version writes the current calculation to the fdest
+ register, with precision specified by the R bit. */
+ if (res_prec)
+ set_fregval_d (cpustate, fdest, dbl_tmp_dest);
+ else
+ set_fregval_s (cpustate, fdest, sgl_tmp_dest);
+ }
+ else
+ {
+ /* Pipelined version writes fdest with the result from the last
+ stage of the pipeline, with precision specified by the ARP
+ bit of the stage's result-status bits. */
+#if 1 /* FIXME: WIP on FSR update. This may not be correct. */
+ /* Copy 3rd stage ARP to FSR. */
+ if (cpustate->A[1 /* 2 */].stat.arp)
+ cpustate->cregs[CR_FSR] |= 0x20000000;
+ else
+ cpustate->cregs[CR_FSR] &= ~0x20000000;
+#endif
+ if (cpustate->A[2].stat.arp) /* 3rd (last) stage. */
+ set_fregval_d (cpustate, fdest, cpustate->A[2].val.d);
+ else
+ set_fregval_s (cpustate, fdest, cpustate->A[2].val.s);
+
+ /* Now advance pipeline and write current calculation to
+ first stage. */
+ cpustate->A[2] = cpustate->A[1];
+ cpustate->A[1] = cpustate->A[0];
+ if (res_prec)
+ {
+ cpustate->A[0].val.d = dbl_tmp_dest;
+ cpustate->A[0].stat.arp = 1;
+ }
+ else
+ {
+ cpustate->A[0].val.s = sgl_tmp_dest;
+ cpustate->A[0].stat.arp = 0;
+ }
+ }
+}
+
+
+/* Execute [p]fiadd/sub.{ss,dd} fsrc1,fsrc2,fdest. */
+static void insn_fiadd_sub (i860s *cpustate, UINT32 insn)
+{
+ UINT32 fsrc1 = get_fsrc1 (insn);
+ UINT32 fsrc2 = get_fsrc2 (insn);
+ UINT32 fdest = get_fdest (insn);
+ int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
+ int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
+ int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
+ int is_sub = insn & 0x4; /* 1 = sub, 0 = add. */
+ double dbl_tmp_dest = 0.0;
+ float sgl_tmp_dest = 0.0;
+
+ /* Check for invalid .ds and .sd combinations. */
+ if ((insn & 0x180) == 0x100
+ || (insn & 0x180) == 0x080)
+ {
+ unrecog_opcode (cpustate->pc, insn);
+ return;
+ }
+
+ /* Do the operation, being careful about source and result
+ precision. */
+ if (src_prec)
+ {
+ double v1 = get_fregval_d (cpustate, fsrc1);
+ double v2 = get_fregval_d (cpustate, fsrc2);
+ UINT64 iv1 = *(UINT64 *)&v1;
+ UINT64 iv2 = *(UINT64 *)&v2;
+ UINT64 r;
+ if (is_sub)
+ r = iv1 - iv2;
+ else
+ r = iv1 + iv2;
+ if (res_prec)
+ dbl_tmp_dest = *(double *)&r;
+ else
+ assert (0); /* .ds not allowed. */
+ }
+ else
+ {
+ float v1 = get_fregval_s (cpustate, fsrc1);
+ float v2 = get_fregval_s (cpustate, fsrc2);
+ UINT64 iv1 = (UINT64)(*(UINT32 *)&v1);
+ UINT64 iv2 = (UINT64)(*(UINT32 *)&v2);
+ UINT32 r;
+ if (is_sub)
+ r = (UINT32)(iv1 - iv2);
+ else
+ r = (UINT32)(iv1 + iv2);
+ if (res_prec)
+ assert (0); /* .sd not allowed. */
+ else
+ sgl_tmp_dest = *(float *)&r;
+ }
+
+ /* FIXME: Copy result-status bit IRP to fsr from last stage. */
+ /* FIXME: Scalar version flows through all stages. */
+ if (!piped)
+ {
+ /* Scalar version writes the current calculation to the fdest
+ register, with precision specified by the R bit. */
+ if (res_prec)
+ set_fregval_d (cpustate, fdest, dbl_tmp_dest);
+ else
+ set_fregval_s (cpustate, fdest, sgl_tmp_dest);
+ }
+ else
+ {
+ /* Pipelined version writes fdest with the result from the last
+ stage of the pipeline, with precision specified by the IRP
+ bit of the stage's result-status bits. */
+#if 1 /* FIXME: WIP on FSR update. This may not be correct. */
+ /* Copy stage IRP to FSR. */
+ if (res_prec)
+ cpustate->cregs[CR_FSR] |= 0x08000000;
+ else
+ cpustate->cregs[CR_FSR] &= ~0x08000000;
+#endif
+ if (cpustate->G.stat.irp) /* 1st (and last) stage. */
+ set_fregval_d (cpustate, fdest, cpustate->G.val.d);
+ else
+ set_fregval_s (cpustate, fdest, cpustate->G.val.s);
+
+ /* Now write current calculation to first and only stage. */
+ if (res_prec)
+ {
+ cpustate->G.val.d = dbl_tmp_dest;
+ cpustate->G.stat.irp = 1;
+ }
+ else
+ {
+ cpustate->G.val.s = sgl_tmp_dest;
+ cpustate->G.stat.irp = 0;
+ }
+ }
+}
+
+
+/* Execute pf{gt,le,eq}.{ss,dd} fsrc1,fsrc2,fdest.
+ Opcode pfgt has R bit cleared; pfle has R bit set. */
+static void insn_fcmp (i860s *cpustate, UINT32 insn)
+{
+ UINT32 fsrc1 = get_fsrc1 (insn);
+ UINT32 fsrc2 = get_fsrc2 (insn);
+ UINT32 fdest = get_fdest (insn);
+ int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
+ double dbl_tmp_dest = 0.0;
+ double sgl_tmp_dest = 0.0;
+ /* int is_eq = insn & 1; */
+ int is_gt = ((insn & 0x81) == 0x00);
+ int is_le = ((insn & 0x81) == 0x80);
+
+ /* Do the operation. Source and result precision must be the same.
+ pfgt: CC set if fsrc1 > fsrc2, else cleared.
+ pfle: CC cleared if fsrc1 <= fsrc2, else set.
+ pfeq: CC set if fsrc1 = fsrc2, else cleared.
+
+ Note that the compares write an undefined (but non-exceptional)
+ result into the first stage of the adder pipeline. We'll model
+ this by just pushing in dbl_ or sgl_tmp_dest which equal 0.0. */
+ if (src_prec)
+ {
+ double v1 = get_fregval_d (cpustate, fsrc1);
+ double v2 = get_fregval_d (cpustate, fsrc2);
+ if (is_gt) /* gt. */
+ SET_PSR_CC (v1 > v2 ? 1 : 0);
+ else if (is_le) /* le. */
+ SET_PSR_CC (v1 <= v2 ? 0 : 1);
+ else /* eq. */
+ SET_PSR_CC (v1 == v2 ? 1 : 0);
+ }
+ else
+ {
+ float v1 = get_fregval_s (cpustate, fsrc1);
+ float v2 = get_fregval_s (cpustate, fsrc2);
+ if (is_gt) /* gt. */
+ SET_PSR_CC (v1 > v2 ? 1 : 0);
+ else if (is_le) /* le. */
+ SET_PSR_CC (v1 <= v2 ? 0 : 1);
+ else /* eq. */
+ SET_PSR_CC (v1 == v2 ? 1 : 0);
+ }
+
+ /* FIXME: Set result-status bits besides ARP. And copy to fsr from
+ last stage. */
+ /* These write fdest with the result from the last
+ stage of the pipeline, with precision specified by the ARP
+ bit of the stage's result-status bits. */
+#if 1 /* FIXME: WIP on FSR update. This may not be correct. */
+ /* Copy 3rd stage ARP to FSR. */
+ if (cpustate->A[1 /* 2 */].stat.arp)
+ cpustate->cregs[CR_FSR] |= 0x20000000;
+ else
+ cpustate->cregs[CR_FSR] &= ~0x20000000;
+#endif
+ if (cpustate->A[2].stat.arp) /* 3rd (last) stage. */
+ set_fregval_d (cpustate, fdest, cpustate->A[2].val.d);
+ else
+ set_fregval_s (cpustate, fdest, cpustate->A[2].val.s);
+
+ /* Now advance pipeline and write current calculation to
+ first stage. */
+ cpustate->A[2] = cpustate->A[1];
+ cpustate->A[1] = cpustate->A[0];
+ if (src_prec)
+ {
+ cpustate->A[0].val.d = dbl_tmp_dest;
+ cpustate->A[0].stat.arp = 1;
+ }
+ else
+ {
+ cpustate->A[0].val.s = sgl_tmp_dest;
+ cpustate->A[0].stat.arp = 0;
+ }
+}
+
+
+/* Execute [p]fzchk{l,s} fsrc1,fsrc2,fdest.
+ The fzchk instructions have S and R bits set. */
+static void insn_fzchk (i860s *cpustate, UINT32 insn)
+{
+ UINT32 fsrc1 = get_fsrc1 (insn);
+ UINT32 fsrc2 = get_fsrc2 (insn);
+ UINT32 fdest = get_fdest (insn);
+ int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
+ int is_fzchks = insn & 8; /* 1 = fzchks, 0 = fzchkl. */
+ double dbl_tmp_dest = 0.0;
+ int i;
+ double v1 = get_fregval_d (cpustate, fsrc1);
+ double v2 = get_fregval_d (cpustate, fsrc2);
+ UINT64 iv1 = *(UINT64 *)&v1;
+ UINT64 iv2 = *(UINT64 *)&v2;
+ UINT64 r = 0;
+ char pm = GET_PSR_PM ();
+
+ /* Check for S and R bits set. */
+ if ((insn & 0x180) != 0x180)
+ {
+ unrecog_opcode (cpustate->pc, insn);
+ return;
+ }
+
+ /* Do the operation. The fzchks version operates in parallel on
+ four 16-bit pixels, while the fzchkl operates on two 32-bit
+ pixels (pixels are unsigned ordinals in this context). */
+ if (is_fzchks)
+ {
+ pm = (pm >> 4) & 0x0f;
+ for (i = 3; i >= 0; i--)
+ {
+ UINT16 ps1 = (iv1 >> (i * 16)) & 0xffff;
+ UINT16 ps2 = (iv2 >> (i * 16)) & 0xffff;
+ if (ps2 <= ps1)
+ {
+ r |= ((UINT64)ps2 << (i * 16));
+ pm |= (1 << (7 - (3 - i)));
+ }
+ else
+ {
+ r |= ((UINT64)ps1 << (i * 16));
+ pm &= ~(1 << (7 - (3 - i)));
+ }
+ }
+ }
+ else
+ {
+ pm = (pm >> 2) & 0x3f;
+ for (i = 1; i >= 0; i--)
+ {
+ UINT32 ps1 = (iv1 >> (i * 32)) & 0xffffffff;
+ UINT32 ps2 = (iv2 >> (i * 32)) & 0xffffffff;
+ if (ps2 <= ps1)
+ {
+ r |= ((UINT64)ps2 << (i * 32));
+ pm |= (1 << (7 - (1 - i)));
+ }
+ else
+ {
+ r |= ((UINT64)ps1 << (i * 32));
+ pm &= ~(1 << (7 - (1 - i)));
+ }
+ }
+ }
+
+ dbl_tmp_dest = *(double *)&r;
+ SET_PSR_PM (pm);
+ cpustate->merge = 0;
+
+ /* FIXME: Copy result-status bit IRP to fsr from last stage. */
+ /* FIXME: Scalar version flows through all stages. */
+ if (!piped)
+ {
+ /* Scalar version writes the current calculation to the fdest
+ register, always with double precision. */
+ set_fregval_d (cpustate, fdest, dbl_tmp_dest);
+ }
+ else
+ {
+ /* Pipelined version writes fdest with the result from the last
+ stage of the pipeline, with precision specified by the IRP
+ bit of the stage's result-status bits. */
+ if (cpustate->G.stat.irp) /* 1st (and last) stage. */
+ set_fregval_d (cpustate, fdest, cpustate->G.val.d);
+ else
+ set_fregval_s (cpustate, fdest, cpustate->G.val.s);
+
+ /* Now write current calculation to first and only stage. */
+ cpustate->G.val.d = dbl_tmp_dest;
+ cpustate->G.stat.irp = 1;
+ }
+}
+
+
+/* Execute [p]form.dd fsrc1,fdest.
+ The form.dd instructions have S and R bits set. */
+static void insn_form (i860s *cpustate, UINT32 insn)
+{
+ UINT32 fsrc1 = get_fsrc1 (insn);
+ UINT32 fdest = get_fdest (insn);
+ int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
+ double dbl_tmp_dest = 0.0;
+ double v1 = get_fregval_d (cpustate, fsrc1);
+ UINT64 iv1 = *(UINT64 *)&v1;
+
+ /* Check for S and R bits set. */
+ if ((insn & 0x180) != 0x180)
+ {
+ unrecog_opcode (cpustate->pc, insn);
+ return;
+ }
+
+ iv1 |= cpustate->merge;
+ dbl_tmp_dest = *(double *)&iv1;
+ cpustate->merge = 0;
+
+ /* FIXME: Copy result-status bit IRP to fsr from last stage. */
+ /* FIXME: Scalar version flows through all stages. */
+ if (!piped)
+ {
+ /* Scalar version writes the current calculation to the fdest
+ register, always with double precision. */
+ set_fregval_d (cpustate, fdest, dbl_tmp_dest);
+ }
+ else
+ {
+ /* Pipelined version writes fdest with the result from the last
+ stage of the pipeline, with precision specified by the IRP
+ bit of the stage's result-status bits. */
+ if (cpustate->G.stat.irp) /* 1st (and last) stage. */
+ set_fregval_d (cpustate, fdest, cpustate->G.val.d);
+ else
+ set_fregval_s (cpustate, fdest, cpustate->G.val.s);
+
+ /* Now write current calculation to first and only stage. */
+ cpustate->G.val.d = dbl_tmp_dest;
+ cpustate->G.stat.irp = 1;
+ }
+}
+
+
+/* Execute [p]faddp fsrc1,fsrc2,fdest. */
+static void insn_faddp (i860s *cpustate, UINT32 insn)
+{
+ UINT32 fsrc1 = get_fsrc1 (insn);
+ UINT32 fsrc2 = get_fsrc2 (insn);
+ UINT32 fdest = get_fdest (insn);
+ int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
+ double dbl_tmp_dest = 0.0;
+ double v1 = get_fregval_d (cpustate, fsrc1);
+ double v2 = get_fregval_d (cpustate, fsrc2);
+ UINT64 iv1 = *(UINT64 *)&v1;
+ UINT64 iv2 = *(UINT64 *)&v2;
+ UINT64 r = 0;
+ int ps = GET_PSR_PS ();
+
+ r = iv1 + iv2;
+ dbl_tmp_dest = *(double *)&r;
+
+ /* Update the merge register depending on the pixel size.
+ PS: 0 = 8 bits, 1 = 16 bits, 2 = 32-bits. */
+ if (ps == 0)
+ {
+ cpustate->merge = ((cpustate->merge >> 8) & ~0xff00ff00ff00ff00ULL);
+ cpustate->merge |= (r & 0xff00ff00ff00ff00ULL);
+ }
+ else if (ps == 1)
+ {
+ cpustate->merge = ((cpustate->merge >> 6) & ~0xfc00fc00fc00fc00ULL);
+ cpustate->merge |= (r & 0xfc00fc00fc00fc00ULL);
+ }
+ else if (ps == 2)
+ {
+ cpustate->merge = ((cpustate->merge >> 8) & ~0xff000000ff000000ULL);
+ cpustate->merge |= (r & 0xff000000ff000000ULL);
+ }
+#ifdef TRACE_UNDEFINED_I860
+ else
+ fprintf (stderr, "insn_faddp: Undefined i860XR behavior, invalid value %d for pixel size.\n", ps);
+#endif
+
+ /* FIXME: Copy result-status bit IRP to fsr from last stage. */
+ /* FIXME: Scalar version flows through all stages. */
+ if (!piped)
+ {
+ /* Scalar version writes the current calculation to the fdest
+ register, always with double precision. */
+ set_fregval_d (cpustate, fdest, dbl_tmp_dest);
+ }
+ else
+ {
+ /* Pipelined version writes fdest with the result from the last
+ stage of the pipeline, with precision specified by the IRP
+ bit of the stage's result-status bits. */
+ if (cpustate->G.stat.irp) /* 1st (and last) stage. */
+ set_fregval_d (cpustate, fdest, cpustate->G.val.d);
+ else
+ set_fregval_s (cpustate, fdest, cpustate->G.val.s);
+
+ /* Now write current calculation to first and only stage. */
+ cpustate->G.val.d = dbl_tmp_dest;
+ cpustate->G.stat.irp = 1;
+ }
+}
+
+
+/* Execute [p]faddz fsrc1,fsrc2,fdest. */
+static void insn_faddz (i860s *cpustate, UINT32 insn)
+{
+ UINT32 fsrc1 = get_fsrc1 (insn);
+ UINT32 fsrc2 = get_fsrc2 (insn);
+ UINT32 fdest = get_fdest (insn);
+ int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
+ double dbl_tmp_dest = 0.0;
+ double v1 = get_fregval_d (cpustate, fsrc1);
+ double v2 = get_fregval_d (cpustate, fsrc2);
+ UINT64 iv1 = *(UINT64 *)&v1;
+ UINT64 iv2 = *(UINT64 *)&v2;
+ UINT64 r = 0;
+
+ r = iv1 + iv2;
+ dbl_tmp_dest = *(double *)&r;
+
+ /* Update the merge register depending on the pixel size. */
+ cpustate->merge = ((cpustate->merge >> 16) & ~0xffff0000ffff0000ULL);
+ cpustate->merge |= (r & 0xffff0000ffff0000ULL);
+
+ /* FIXME: Copy result-status bit IRP to fsr from last stage. */
+ /* FIXME: Scalar version flows through all stages. */
+ if (!piped)
+ {
+ /* Scalar version writes the current calculation to the fdest
+ register, always with double precision. */
+ set_fregval_d (cpustate, fdest, dbl_tmp_dest);
+ }
+ else
+ {
+ /* Pipelined version writes fdest with the result from the last
+ stage of the pipeline, with precision specified by the IRP
+ bit of the stage's result-status bits. */
+ if (cpustate->G.stat.irp) /* 1st (and last) stage. */
+ set_fregval_d (cpustate, fdest, cpustate->G.val.d);
+ else
+ set_fregval_s (cpustate, fdest, cpustate->G.val.s);
+
+ /* Now write current calculation to first and only stage. */
+ cpustate->G.val.d = dbl_tmp_dest;
+ cpustate->G.stat.irp = 1;
+ }
+}
+
+
+/* Flags for the decode table. */
+enum {
+ DEC_MORE = 1, /* More decoding necessary. */
+ DEC_DECODED = 2 /* Fully decoded, go. */
+};
+
+
+typedef struct {
+ /* Execute function for this opcode. */
+ void (*insn_exec)(i860s *, UINT32);
+
+ /* Flags for this opcode. */
+ char flags;
+} decode_tbl_t;
+
+
+/* First-level decode table (i.e., for the 6 primary opcode bits). */
+static decode_tbl_t decode_tbl[64] = {
+ /* A slight bit of decoding for loads and stores is done in the
+ execution routines (operand size and addressing mode), which
+ is why their respective entries are identical. */
+ { insn_ldx, DEC_DECODED}, /* ld.b isrc1(isrc2),idest. */
+ { insn_ldx, DEC_DECODED}, /* ld.b #const(isrc2),idest. */
+ { insn_ixfr, DEC_DECODED}, /* ixfr isrc1ni,fdest. */
+ { insn_stx, DEC_DECODED}, /* st.b isrc1ni,#const(isrc2). */
+ { insn_ldx, DEC_DECODED}, /* ld.{s,l} isrc1(isrc2),idest. */
+ { insn_ldx, DEC_DECODED}, /* ld.{s,l} #const(isrc2),idest. */
+ { 0, 0},
+ { insn_stx, DEC_DECODED}, /* st.{s,l} isrc1ni,#const(isrc2),idest.*/
+ { insn_fldy, DEC_DECODED}, /* fld.{l,d,q} isrc1(isrc2)[++],fdest. */
+ { insn_fldy, DEC_DECODED}, /* fld.{l,d,q} #const(isrc2)[++],fdest. */
+ { insn_fsty, DEC_DECODED}, /* fst.{l,d,q} fdest,isrc1(isrc2)[++] */
+ { insn_fsty, DEC_DECODED}, /* fst.{l,d,q} fdest,#const(isrc2)[++] */
+ { insn_ld_ctrl, DEC_DECODED}, /* ld.c csrc2,idest. */
+ { insn_flush, DEC_DECODED}, /* flush #const(isrc2) (or autoinc). */
+ { insn_st_ctrl, DEC_DECODED}, /* st.c isrc1,csrc2. */
+ { insn_pstd, DEC_DECODED}, /* pst.d fdest,#const(isrc2)[++]. */
+ { insn_bri, DEC_DECODED}, /* bri isrc1ni. */
+ { insn_trap, DEC_DECODED}, /* trap isrc1ni,isrc2,idest. */
+ { 0, DEC_MORE}, /* FP ESCAPE FORMAT, more decode. */
+ { 0, DEC_MORE}, /* CORE ESCAPE FORMAT, more decode. */
+ { insn_btne, DEC_DECODED}, /* btne isrc1,isrc2,sbroff. */
+ { insn_btne_imm, DEC_DECODED}, /* btne #const,isrc2,sbroff. */
+ { insn_bte, DEC_DECODED}, /* bte isrc1,isrc2,sbroff. */
+ { insn_bte_imm, DEC_DECODED}, /* bte #const5,isrc2,idest. */
+ { insn_fldy, DEC_DECODED}, /* pfld.{l,d,q} isrc1(isrc2)[++],fdest.*/
+ { insn_fldy, DEC_DECODED}, /* pfld.{l,d,q} #const(isrc2)[++],fdest.*/
+ { insn_br, DEC_DECODED}, /* br lbroff. */
+ { insn_call, DEC_DECODED}, /* call lbroff . */
+ { insn_bc, DEC_DECODED}, /* bc lbroff. */
+ { insn_bct, DEC_DECODED}, /* bc.t lbroff. */
+ { insn_bnc, DEC_DECODED}, /* bnc lbroff. */
+ { insn_bnct, DEC_DECODED}, /* bnc.t lbroff. */
+ { insn_addu, DEC_DECODED}, /* addu isrc1,isrc2,idest. */
+ { insn_addu_imm, DEC_DECODED}, /* addu #const,isrc2,idest. */
+ { insn_subu, DEC_DECODED}, /* subu isrc1,isrc2,idest. */
+ { insn_subu_imm, DEC_DECODED}, /* subu #const,isrc2,idest. */
+ { insn_adds, DEC_DECODED}, /* adds isrc1,isrc2,idest. */
+ { insn_adds_imm, DEC_DECODED}, /* adds #const,isrc2,idest. */
+ { insn_subs, DEC_DECODED}, /* subs isrc1,isrc2,idest. */
+ { insn_subs_imm, DEC_DECODED}, /* subs #const,isrc2,idest. */
+ { insn_shl, DEC_DECODED}, /* shl isrc1,isrc2,idest. */
+ { insn_shl_imm, DEC_DECODED}, /* shl #const,isrc2,idest. */
+ { insn_shr, DEC_DECODED}, /* shr isrc1,isrc2,idest. */
+ { insn_shr_imm, DEC_DECODED}, /* shr #const,isrc2,idest. */
+ { insn_shrd, DEC_DECODED}, /* shrd isrc1ni,isrc2,idest. */
+ { insn_bla, DEC_DECODED}, /* bla isrc1ni,isrc2,sbroff. */
+ { insn_shra, DEC_DECODED}, /* shra isrc1,isrc2,idest. */
+ { insn_shra_imm, DEC_DECODED}, /* shra #const,isrc2,idest. */
+ { insn_and, DEC_DECODED}, /* and isrc1,isrc2,idest. */
+ { insn_and_imm, DEC_DECODED}, /* and #const,isrc2,idest. */
+ { 0, 0},
+ { insn_andh_imm, DEC_DECODED}, /* andh #const,isrc2,idest. */
+ { insn_andnot, DEC_DECODED}, /* andnot isrc1,isrc2,idest. */
+ { insn_andnot_imm, DEC_DECODED}, /* andnot #const,isrc2,idest. */
+ { 0, 0},
+ { insn_andnoth_imm, DEC_DECODED}, /* andnoth #const,isrc2,idest. */
+ { insn_or, DEC_DECODED}, /* or isrc1,isrc2,idest. */
+ { insn_or_imm, DEC_DECODED}, /* or #const,isrc2,idest. */
+ { 0, 0},
+ { insn_orh_imm, DEC_DECODED}, /* orh #const,isrc2,idest. */
+ { insn_xor, DEC_DECODED}, /* xor isrc1,isrc2,idest. */
+ { insn_xor_imm, DEC_DECODED}, /* xor #const,isrc2,idest. */
+ { 0, 0},
+ { insn_xorh_imm, DEC_DECODED}, /* xorh #const,isrc2,idest. */
+};
+
+
+/* Second-level decode table (i.e., for the 3 core escape opcode bits). */
+static decode_tbl_t core_esc_decode_tbl[8] = {
+ { 0, 0},
+ { 0, 0}, /* lock (FIXME: unimplemented). */
+ { insn_calli, DEC_DECODED}, /* calli isrc1ni. */
+ { 0, 0},
+ { insn_intovr, DEC_DECODED}, /* intovr. */
+ { 0, 0},
+ { 0, 0},
+ { 0, 0}, /* unlock (FIXME: unimplemented). */
+};
+
+
+/* Second-level decode table (i.e., for the 7 FP extended opcode bits). */
+static decode_tbl_t fp_decode_tbl[128] = {
+ /* Floating point instructions. The least significant 7 bits are
+ the (extended) opcode and bits 10:7 are P,D,S,R respectively
+ ([p]ipelined, [d]ual, [s]ource prec., [r]esult prec.).
+ For some operations, I defer decoding the P,S,R bits to the
+ emulation routine for them. */
+ { insn_dualop, DEC_DECODED}, /* 0x00 pf[m]am */
+ { insn_dualop, DEC_DECODED}, /* 0x01 pf[m]am */
+ { insn_dualop, DEC_DECODED}, /* 0x02 pf[m]am */
+ { insn_dualop, DEC_DECODED}, /* 0x03 pf[m]am */
+ { insn_dualop, DEC_DECODED}, /* 0x04 pf[m]am */
+ { insn_dualop, DEC_DECODED}, /* 0x05 pf[m]am */
+ { insn_dualop, DEC_DECODED}, /* 0x06 pf[m]am */
+ { insn_dualop, DEC_DECODED}, /* 0x07 pf[m]am */
+ { insn_dualop, DEC_DECODED}, /* 0x08 pf[m]am */
+ { insn_dualop, DEC_DECODED}, /* 0x09 pf[m]am */
+ { insn_dualop, DEC_DECODED}, /* 0x0A pf[m]am */
+ { insn_dualop, DEC_DECODED}, /* 0x0B pf[m]am */
+ { insn_dualop, DEC_DECODED}, /* 0x0C pf[m]am */
+ { insn_dualop, DEC_DECODED}, /* 0x0D pf[m]am */
+ { insn_dualop, DEC_DECODED}, /* 0x0E pf[m]am */
+ { insn_dualop, DEC_DECODED}, /* 0x0F pf[m]am */
+ { insn_dualop, DEC_DECODED}, /* 0x10 pf[m]sm */
+ { insn_dualop, DEC_DECODED}, /* 0x11 pf[m]sm */
+ { insn_dualop, DEC_DECODED}, /* 0x12 pf[m]sm */
+ { insn_dualop, DEC_DECODED}, /* 0x13 pf[m]sm */
+ { insn_dualop, DEC_DECODED}, /* 0x14 pf[m]sm */
+ { insn_dualop, DEC_DECODED}, /* 0x15 pf[m]sm */
+ { insn_dualop, DEC_DECODED}, /* 0x16 pf[m]sm */
+ { insn_dualop, DEC_DECODED}, /* 0x17 pf[m]sm */
+ { insn_dualop, DEC_DECODED}, /* 0x18 pf[m]sm */
+ { insn_dualop, DEC_DECODED}, /* 0x19 pf[m]sm */
+ { insn_dualop, DEC_DECODED}, /* 0x1A pf[m]sm */
+ { insn_dualop, DEC_DECODED}, /* 0x1B pf[m]sm */
+ { insn_dualop, DEC_DECODED}, /* 0x1C pf[m]sm */
+ { insn_dualop, DEC_DECODED}, /* 0x1D pf[m]sm */
+ { insn_dualop, DEC_DECODED}, /* 0x1E pf[m]sm */
+ { insn_dualop, DEC_DECODED}, /* 0x1F pf[m]sm */
+ { insn_fmul, DEC_DECODED}, /* 0x20 [p]fmul */
+ { insn_fmlow, DEC_DECODED}, /* 0x21 fmlow.dd */
+ { insn_frcp, DEC_DECODED}, /* 0x22 frcp.{ss,sd,dd} */
+ { insn_frsqr, DEC_DECODED}, /* 0x23 frsqr.{ss,sd,dd} */
+ { insn_fmul, DEC_DECODED}, /* 0x24 pfmul3.dd */
+ { 0, 0}, /* 0x25 */
+ { 0, 0}, /* 0x26 */
+ { 0, 0}, /* 0x27 */
+ { 0, 0}, /* 0x28 */
+ { 0, 0}, /* 0x29 */
+ { 0, 0}, /* 0x2A */
+ { 0, 0}, /* 0x2B */
+ { 0, 0}, /* 0x2C */
+ { 0, 0}, /* 0x2D */
+ { 0, 0}, /* 0x2E */
+ { 0, 0}, /* 0x2F */
+ { insn_fadd_sub, DEC_DECODED}, /* 0x30, [p]fadd.{ss,sd,dd} */
+ { insn_fadd_sub, DEC_DECODED}, /* 0x31, [p]fsub.{ss,sd,dd} */
+ { 0, 0}, /* 0x32, [p]fix.{ss,sd,dd} FIXME: nyi. */
+ { insn_famov, DEC_DECODED}, /* 0x33, [p]famov.{ss,sd,ds,dd} */
+ { insn_fcmp, DEC_DECODED}, /* 0x34, pf{gt,le}.{ss,dd} */
+ { insn_fcmp, DEC_DECODED}, /* 0x35, pfeq.{ss,dd} */
+ { 0, 0}, /* 0x36 */
+ { 0, 0}, /* 0x37 */
+ { 0, 0}, /* 0x38 */
+ { 0, 0}, /* 0x39 */
+ { insn_ftrunc, DEC_DECODED}, /* 0x3A, [p]ftrunc.{ss,sd,dd} */
+ { 0, 0}, /* 0x3B */
+ { 0, 0}, /* 0x3C */
+ { 0, 0}, /* 0x3D */
+ { 0, 0}, /* 0x3E */
+ { 0, 0}, /* 0x3F */
+ { insn_fxfr, DEC_DECODED}, /* 0x40, fxfr */
+ { 0, 0}, /* 0x41 */
+ { 0, 0}, /* 0x42 */
+ { 0, 0}, /* 0x43 */
+ { 0, 0}, /* 0x44 */
+ { 0, 0}, /* 0x45 */
+ { 0, 0}, /* 0x46 */
+ { 0, 0}, /* 0x47 */
+ { 0, 0}, /* 0x48 */
+ { insn_fiadd_sub, DEC_DECODED}, /* 0x49, [p]fiadd.{ss,dd} */
+ { 0, 0}, /* 0x4A */
+ { 0, 0}, /* 0x4B */
+ { 0, 0}, /* 0x4C */
+ { insn_fiadd_sub, DEC_DECODED}, /* 0x4D, [p]fisub.{ss,dd} */
+ { 0, 0}, /* 0x4E */
+ { 0, 0}, /* 0x4F */
+ { insn_faddp, DEC_DECODED}, /* 0x50, [p]faddp */
+ { insn_faddz, DEC_DECODED}, /* 0x51, [p]faddz */
+ { 0, 0}, /* 0x52 */
+ { 0, 0}, /* 0x53 */
+ { 0, 0}, /* 0x54 */
+ { 0, 0}, /* 0x55 */
+ { 0, 0}, /* 0x56 */
+ { insn_fzchk, DEC_DECODED}, /* 0x57, [p]fzchkl */
+ { 0, 0}, /* 0x58 */
+ { 0, 0}, /* 0x59 */
+ { insn_form, DEC_DECODED}, /* 0x5A, [p]form.dd */
+ { 0, 0}, /* 0x5B */
+ { 0, 0}, /* 0x5C */
+ { 0, 0}, /* 0x5D */
+ { 0, 0}, /* 0x5E */
+ { insn_fzchk, DEC_DECODED}, /* 0x5F, [p]fzchks */
+ { 0, 0}, /* 0x60 */
+ { 0, 0}, /* 0x61 */
+ { 0, 0}, /* 0x62 */
+ { 0, 0}, /* 0x63 */
+ { 0, 0}, /* 0x64 */
+ { 0, 0}, /* 0x65 */
+ { 0, 0}, /* 0x66 */
+ { 0, 0}, /* 0x67 */
+ { 0, 0}, /* 0x68 */
+ { 0, 0}, /* 0x69 */
+ { 0, 0}, /* 0x6A */
+ { 0, 0}, /* 0x6B */
+ { 0, 0}, /* 0x6C */
+ { 0, 0}, /* 0x6D */
+ { 0, 0}, /* 0x6E */
+ { 0, 0}, /* 0x6F */
+ { 0, 0}, /* 0x70 */
+ { 0, 0}, /* 0x71 */
+ { 0, 0}, /* 0x72 */
+ { 0, 0}, /* 0x73 */
+ { 0, 0}, /* 0x74 */
+ { 0, 0}, /* 0x75 */
+ { 0, 0}, /* 0x76 */
+ { 0, 0}, /* 0x77 */
+ { 0, 0}, /* 0x78 */
+ { 0, 0}, /* 0x79 */
+ { 0, 0}, /* 0x7A */
+ { 0, 0}, /* 0x7B */
+ { 0, 0}, /* 0x7C */
+ { 0, 0}, /* 0x7D */
+ { 0, 0}, /* 0x7E */
+ { 0, 0}, /* 0x7F */
+};
+
+
+/*
+ * Main decoder driver.
+ * insn = instruction at the current PC to execute.
+ * non_shadow = This insn is not in the shadow of a delayed branch).
+ */
+static void decode_exec (i860s *cpustate, UINT32 insn, UINT32 non_shadow)
+{
+ int upper_6bits = (insn >> 26) & 0x3f;
+ char flags = 0;
+ int unrecognized = 1;
+
+ if (cpustate->exiting_ifetch)
+ return;
+
+ if ((upper_6bits == 0x12 || upper_6bits == 0x2c) && insn & 0x0200)
+ logerror("D-bit seen.\n");
+ if (GET_EPSR_BE ())
+ logerror("BE-bit high.\n");
+ if (GET_DIRBASE_CS8 ())
+ logerror("CS8-bit high.\n");
+
+ flags = decode_tbl[upper_6bits].flags;
+ if (flags & DEC_DECODED)
+ {
+ decode_tbl[upper_6bits].insn_exec (cpustate, insn);
+ unrecognized = 0;
+ }
+ else if (flags & DEC_MORE)
+ {
+ if (upper_6bits == 0x12)
+ {
+ /* FP instruction format handled here. */
+ char fp_flags = fp_decode_tbl[insn & 0x7f].flags;
+ if (fp_flags & DEC_DECODED)
+ {
+ fp_decode_tbl[insn & 0x7f].insn_exec (cpustate, insn);
+ unrecognized = 0;
+ }
+ }
+ else if (upper_6bits == 0x13)
+ {
+ /* Core escape instruction format handled here. */
+ char esc_flags = core_esc_decode_tbl[insn & 0x3].flags;
+ if (esc_flags & DEC_DECODED)
+ {
+ core_esc_decode_tbl[insn & 0x3].insn_exec (cpustate, insn);
+ unrecognized = 0;
+ }
+ }
+ }
+
+ if (unrecognized)
+ unrecog_opcode (cpustate->pc, insn);
+
+ /* For now, just treat every instruction as taking the same number of
+ clocks-- a major oversimplification. */
+ cpustate->icount -= 9;
+}
+
+
+/* Set-up all the default power-on/reset values. */
+void reset_i860 (i860s *cpustate)
+{
+ int i;
+ /* On power-up/reset, i860 has values:
+ PC = 0xffffff00.
+ Integer registers: r0 = 0, others = undefined.
+ FP registers: f0:f1 = 0, others undefined.
+ psr: U = IM = BR = BW = 0; others = undefined.
+ epsr: IL = WP = PBM = BE = 0; processor type, stepping, and
+ DCS are proper and read-only; others = undefined.
+ db: undefined.
+ dirbase: DPS, BL, ATE = 0
+ fir, fsr, KR, KI, MERGE: undefined. (what about T?)
+
+ I$: flushed.
+ D$: undefined (all modified bits = 0).
+ TLB: flushed.
+
+ Note that any undefined values are set to 0x55aa55aa patterns to
+ try to detect defective i860 software. */
+
+ /* PC is at trap address after reset. */
+ cpustate->pc = 0xffffff00;
+
+ /* Set grs and frs to undefined/nonsense values, except r0. */
+ for (i = 0; i < 32; i++)
+ {
+ set_iregval (i, 0x55aa55aa);
+ set_fregval_s (cpustate, i, 0.0);
+ }
+ set_iregval (0, 0);
+ set_fregval_s (cpustate, 0, 0.0);
+ set_fregval_s (cpustate, 1, 0.0);
+
+ /* Set whole psr to 0. This sets the proper bits to 0 as specified
+ above, and zeroes the undefined bits. */
+ cpustate->cregs[CR_PSR] = 0;
+
+ /* Set most of the epsr bits to 0 (as specified above), leaving
+ undefined as zero as well. Then properly set processor type,
+ step, and DCS. Type = EPSR[7..0], step = EPSR[12..8],
+ DCS = EPSR[21..18] (2^[12+dcs] = cache size).
+ We'll pretend to be stepping D0, since it has the fewest bugs
+ (and I don't want to emulate the many defects in the earlier
+ steppings).
+ Proc type: 1 = XR, 2 = XP (XR has 8KB data cache -> DCS = 1).
+ Steppings (XR): 3,4,5,6,7 = (B2, C0, B3, C1, D0 respectively).
+ Steppings (XP): 0, 2, 3, 4 = (A0, B0, B1, B2) (any others?). */
+ cpustate->cregs[CR_EPSR] = 0x00040701;
+
+ /* Set DPS, BL, ATE = 0 and the undefined parts also to 0. */
+ cpustate->cregs[CR_DIRBASE] = 0x00000000;
+
+ /* Set fir, fsr, KR, KI, MERGE, T to undefined. */
+ cpustate->cregs[CR_FIR] = 0xaa55aa55;
+ cpustate->cregs[CR_FSR] = /* 0xaa55aa55; */ 0;
+ cpustate->KR.d = 0.0;
+ cpustate->KI.d = 0.0;
+ cpustate->T.d = 0.0;
+ cpustate->merge = 0xaa55aa55;
+
+ cpustate->fir_gets_trap_addr = 0;
+}
+
+
+
+
+/*=================================================================*/
+/* MAME execution hook for i860 emulator. */
+/*=================================================================*/
+
+#include "cpuintrf.h"
+
+static CPU_EXECUTE( i860 )
+{
+ i860_state_t *cpustate = device->token;
+
+ /* Check if the data bus is held by another device, and bail if so.
+ Also check for reset. */
+ if (cpustate->pin_reset)
+ reset_i860 (cpustate);
+ if (cpustate->pin_bus_hold)
+ return cycles;
+
+ cpustate->exiting_readmem = 0;
+ cpustate->exiting_ifetch = 0;
+ cpustate->icount = cycles;
+
+ /* Decode and execute loop. */
+ while (cpustate->icount > 0)
+ {
+ UINT32 savepc = cpustate->pc;
+ cpustate->pc_updated = 0;
+ cpustate->pending_trap = 0;
+
+#if 1 /* Delete me soon, for debugging VC inter-processor synch. */
+ if (cpustate->pc == 0xfffc0370 ||
+ cpustate->pc == 0xfffc03a4)
+ {
+ fprintf(stderr, "(%s) 0x%08x: snag 0x20000000\n", cpustate->device->tag, cpustate->pc);
+ cpustate->single_stepping = 0;
+ }
+ else if (cpustate->pc == 0xfffc0384 ||
+ cpustate->pc == 0xfffc03b8)
+ {
+ fprintf(stderr, "(%s) 0x%08x: passed 0x20000000\n", cpustate->device->tag, cpustate->pc);
+ cpustate->single_stepping = 0;
+ }
+#endif
+
+ savepc = cpustate->pc;
+ debugger_instruction_hook(cpustate->device, cpustate->pc);
+ decode_exec (cpustate, ifetch (cpustate, cpustate->pc), 1);
+
+ cpustate->exiting_ifetch = 0;
+ cpustate->exiting_readmem = 0;
+
+ if (cpustate->pending_trap)
+ {
+ /* If we need to trap, change PC to trap address.
+ Also set supervisor mode, copy U and IM to their
+ previous versions, clear IM. */
+ if ((cpustate->pending_trap & TRAP_WAS_EXTERNAL) || (GET_EPSR_INT () && GET_PSR_IN ()))
+ {
+ if (!cpustate->pc_updated)
+ cpustate->cregs[CR_FIR] = savepc + 4;
+ else
+ cpustate->cregs[CR_FIR] = cpustate->pc;
+ }
+ else if (cpustate->pending_trap & TRAP_IN_DELAY_SLOT)
+ {
+ cpustate->cregs[CR_FIR] = savepc + 4;
+ }
+ else
+ cpustate->cregs[CR_FIR] = savepc;
+
+ cpustate->fir_gets_trap_addr = 1;
+ SET_PSR_PU (GET_PSR_U ());
+ SET_PSR_PIM (GET_PSR_IM ());
+ SET_PSR_U (0);
+ SET_PSR_IM (0);
+ SET_PSR_DIM (0);
+ SET_PSR_DS (0);
+ cpustate->pc = 0xffffff00;
+ cpustate->pending_trap = 0;
+ }
+ else if (!cpustate->pc_updated)
+ {
+ /* If the PC wasn't updated by a control flow instruction, just
+ bump to next sequential instruction. */
+ cpustate->pc += 4;
+ }
+
+ /*if (cpustate->single_stepping)
+ debugger (cpustate); */
+ }
+
+ return cycles - cpustate->icount;
+}
+/*=================================================================*/
+
+
+
+
+#if 0
+/*=================================================================*/
+/* Internal debugger-related stuff. */
+
+extern unsigned disasm_i860 (char *buf, unsigned int pc, unsigned int insn);
+
+
+/* Disassemble `len' instructions starting at `addr'. */
+static void disasm (i860s *cpustate, UINT32 addr, int len)
+{
+ UINT32 insn;
+ int j;
+ for (j = 0; j < len; j++)
+ {
+ char buf[256];
+ UINT32 phys_addr = addr;
+ if (GET_DIRBASE_ATE ())
+ phys_addr = get_address_translation (cpustate, addr, 1 /* is_dataref */, 0 /* is_write */);
+
+ /* Note that we print the incoming (possibly virtual) address as the
+ PC rather than the translated address. */
+ fprintf (stderr, " (%s) 0x%08x: ", cpustate->device->tag, addr);
+ insn = memory_read_dword_64le(cpustate->program, phys_addr);
+#ifdef HOST_MSB
+ BYTE_REV32 (insn);
+#endif /* HOST_MSB. */
+ disasm_i860 (buf, addr, insn); fprintf (stderr, "%s", buf);
+ fprintf (stderr, "\n");
+ addr += 4;
+#if 1
+ if (cpustate->single_stepping == 1 && has_delay_slot (insn))
+ len += 1;
+#endif
+ }
+}
+
+
+/* Dump `len' bytes starting at `addr'. */
+static void dbg_db (i860s *cpustate, UINT32 addr, int len)
+{
+ UINT8 b[16];
+ int i;
+ /* This will always dump a multiple of 16 bytes, even if 'len' isn't. */
+ while (len > 0)
+ {
+ /* Note that we print the incoming (possibly virtual) address
+ rather than the translated address. */
+ fprintf (stderr, "0x%08x: ", addr);
+ for (i = 0; i < 16; i++)
+ {
+ UINT32 phys_addr = addr;
+ if (GET_DIRBASE_ATE ())
+ phys_addr = get_address_translation (cpustate, addr, 1 /* is_dataref */, 0 /* is_write */);
+
+ b[i] = memory_read_byte_64le(cpustate->program, phys_addr);
+ fprintf (stderr, "%02x ", b[i]);
+ addr++;
+ }
+ fprintf (stderr, "| ");
+ for (i = 0; i < 16; i++)
+ {
+ if (isprint (b[i]))
+ fprintf (stderr, "%c", b[i]);
+ else
+ fprintf (stderr, ".");
+ }
+ fprintf (stderr, "\n");
+ len -= 16;
+ }
+}
+
+
+/* A simple internal debugger. */
+void debugger (i860s *cpustate)
+{
+ char buf[256];
+ UINT32 curr_disasm = cpustate->pc;
+ UINT32 curr_dumpdb = 0;
+ int c = 0;
+
+ if (cpustate->single_stepping > 1 && cpustate->single_stepping != cpustate->pc)
+ return;
+
+ buf[0] = 0;
+
+ /* Always disassemble the upcoming instruction when single-stepping. */
+ if (cpustate->single_stepping)
+ {
+ disasm (cpustate, cpustate->pc, 1);
+ if (has_delay_slot (2))
+ disasm (cpustate, cpustate->pc + 4, 1);
+ }
+ else
+ fprintf (stderr, "\nEmulator: internal debugger started (? for help).\n");
+
+ fflush (stdin);
+
+ cpustate->single_stepping = 0;
+ while (!cpustate->single_stepping)
+ {
+ fprintf (stderr, "- ");
+#if 0 /* Doesn't work on MacOSX BSD flavor. */
+ fscanf (stdin, "%s", buf);
+#else
+ while (1)
+ {
+ char it = 0;
+ if (read(STDIN_FILENO, &it, 1) == 1)
+ {
+ if (it == '\n')
+ {
+ buf[c] = 0;
+ c = 0;
+ break;
+ }
+ buf[c++] = it;
+ }
+ }
+#endif
+ if (buf[0] == 'g')
+ {
+ if (buf[1] == '0')
+ sscanf (buf + 1, "%x", &cpustate->single_stepping);
+ else
+ break;
+ buf[1] = 0;
+ fprintf (stderr, "go until pc = 0x%08x.\n",
+ cpustate->single_stepping);
+ cpustate->single_stepping = 0; /* HACK */
+ }
+ else if (buf[0] == 'r')
+ dump_state (cpustate);
+ else if (buf[0] == 'u')
+ {
+ if (buf[1] == '0')
+ sscanf (buf + 1, "%x", &curr_disasm);
+ disasm (cpustate, curr_disasm, 10);
+ curr_disasm += 10 * 4;
+ buf[1] = 0;
+ }
+ else if (buf[0] == 'p')
+ {
+ if (buf[1] >= '0' && buf[1] <= '4')
+ dump_pipe (cpustate, buf[1] - 0x30);
+ buf[1] = 0;
+ }
+ else if (buf[0] == 's')
+ cpustate->single_stepping = 1;
+ else if (buf[0] == 'l')
+ ; //cpustate->pc = elf_load(buf + 1);
+ else if (buf[0] == 'd' && buf[1] == 'b')
+ {
+ if (buf[2] == '0')
+ sscanf (buf + 2, "%x", &curr_dumpdb);
+ dbg_db (cpustate, curr_dumpdb, 32);
+ curr_dumpdb += 32;
+ }
+ else if (buf[0] == 'x' && buf[1] == '0')
+ {
+ UINT32 v;
+ sscanf (buf + 1, "%x", &v);
+ if (GET_DIRBASE_ATE ())
+ fprintf (stderr, "vma 0x%08x ==> phys 0x%08x\n", v,
+ get_address_translation (cpustate, v, 1, 0));
+ else
+ fprintf (stderr, "not in virtual address mode.\n");
+ }
+ else if (buf[0] == 'B')
+ {
+ ;//cpustate->pc = elf_load("bins/bsd");
+ break;
+ }
+ else if (buf[0] == '?')
+ {
+ fprintf (stderr, " db: dump bytes (db[0xaddress])\n r: dump registers\n s: single-step\n g: go back to emulator (g[0xaddress])\n u: disassemble (u[0xaddress])\n p: dump pipelines (p{0-4} for all, add, mul, load, graphics)\n l: load an ELF binary (lpath)\n x: give virt->phys translation (x{0xaddress})\n");
+ }
+ else
+ fprintf (stderr, "Bad command '%s'.\n", buf);
+ }
+
+ /* Less noise when single-stepping. */
+ if (cpustate->single_stepping != 1)
+ fprintf (stderr, "Debugger done, continuing emulation.\n");
+}
+
+#endif
diff --git a/src/emu/cpu/i860/i860dis.c b/src/emu/cpu/i860/i860dis.c
new file mode 100644
index 00000000000..e6b7f384ad1
--- /dev/null
+++ b/src/emu/cpu/i860/i860dis.c
@@ -0,0 +1,694 @@
+/***************************************************************************
+
+ i860dis.c
+
+ Disassembler for the Intel i860 emulator.
+
+ Copyright (C) 1995-present Jason Eckhardt (jle@rice.edu)
+ Released for general non-commercial use under the MAME license
+ with the additional requirement that you are free to use and
+ redistribute this code in modified or unmodified form, provided
+ you list me in the credits.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "i860.h"
+#include <string.h>
+
+/* Macros for accessing register fields in instruction word. */
+#define get_isrc1(bits) (((bits) >> 11) & 0x1f)
+#define get_isrc2(bits) (((bits) >> 21) & 0x1f)
+#define get_idest(bits) (((bits) >> 16) & 0x1f)
+#define get_fsrc1(bits) (((bits) >> 11) & 0x1f)
+#define get_fsrc2(bits) (((bits) >> 21) & 0x1f)
+#define get_fdest(bits) (((bits) >> 16) & 0x1f)
+#define get_creg(bits) (((bits) >> 21) & 0x7)
+
+/* Macros for accessing immediate fields. */
+/* 16-bit immediate. */
+#define get_imm16(insn) ((insn) & 0xffff)
+
+
+/* Control register names. */
+static const char *const cr2str[] =
+ {"fir", "psr", "dirbase", "db", "fsr", "epsr", "!", "!"};
+
+
+/* Sign extend N-bit number. */
+static INT32 sign_ext(UINT32 x, int n)
+{
+ INT32 t;
+ t = x >> (n - 1);
+ t = ((-t) << n) | x;
+ return t;
+}
+
+
+/* Basic integer 3-address register format:
+ * mnemonic %rs1,%rs2,%rd */
+static void int_12d(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ /* Possibly prefix shrd with 'd.' */
+ if (((insn & 0xfc000000) == 0xb0000000) && (insn & 0x200))
+ sprintf(buf, "d.%s\t%%r%d,%%r%d,%%r%d", mnemonic,
+ get_isrc1 (insn), get_isrc2 (insn), get_idest (insn));
+ else
+ sprintf(buf, "%s\t%%r%d,%%r%d,%%r%d", mnemonic,
+ get_isrc1 (insn), get_isrc2 (insn), get_idest (insn));
+}
+
+
+/* Basic integer 3-address imm16 format:
+ * mnemonic #imm16,%rs2,%rd */
+static void int_i2d(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ /* Sign extend the 16-bit immediate.
+ Print as hex for the bitwise operations. */
+ int upper_6bits = (insn >> 26) & 0x3f;
+ if (upper_6bits >= 0x30 && upper_6bits <= 0x3f)
+ sprintf(buf, "%s\t0x%04x,%%r%d,%%r%d", mnemonic,
+ (UINT32)(get_imm16 (insn)), get_isrc2 (insn), get_idest (insn));
+ else
+ sprintf(buf, "%s\t%d,%%r%d,%%r%d", mnemonic,
+ sign_ext(get_imm16 (insn), 16), get_isrc2 (insn), get_idest (insn));
+}
+
+
+/* Integer (mixed) 2-address isrc1ni,fdest. */
+static void int_1d(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ sprintf(buf, "%s\t%%r%d,%%f%d", mnemonic, get_isrc1 (insn), get_fdest (insn));
+}
+
+
+/* Integer (mixed) 2-address csrc2,idest. */
+static void int_cd(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ sprintf(buf, "%s\t%%%s,%%r%d", mnemonic, cr2str[get_creg (insn)], get_idest (insn));
+}
+
+
+/* Integer (mixed) 2-address isrc1,csrc2. */
+static void int_1c(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ sprintf(buf, "%s\t%%r%d,%%%s", mnemonic, get_isrc1(insn), cr2str[get_creg (insn)]);
+}
+
+
+/* Integer 1-address register format:
+ * mnemonic %rs1 */
+static void int_1(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ sprintf(buf, "%s\t%%r%d", mnemonic, get_isrc1 (insn));
+}
+
+
+/* Integer no-address register format:
+ * mnemonic */
+static void int_0(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ sprintf(buf, "%s", mnemonic);
+}
+
+
+/* Basic floating-point 3-address register format:
+ * mnemonic %fs1,%fs2,%fd */
+static void flop_12d(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ const char *suffix[4] = { "ss", "sd", "ds", "dd" };
+ const char *prefix_d, *prefix_p;
+ int s = (insn & 0x180) >> 7;
+ prefix_p = (insn & 0x400) ? "p" : "";
+ prefix_d = (insn & 0x200) ? "d." : "";
+
+ /* Special case: pf[m]am and pf[m]sm families are always pipelined, so they
+ do not have a prefix. Also, for the pfmam and pfmsm families, replace
+ any 'a' in the mnemonic with 'm' and prepend an 'm'. */
+ if ((insn & 0x7f) < 0x20)
+ {
+ int is_pfam = insn & 0x400;
+ if (!is_pfam)
+ {
+ char newname[256];
+ char *op = mnemonic;
+ char *np = newname + 1;
+ newname[0] = 'm';
+ while (*op)
+ {
+ if (*op == 'a')
+ *np = 'm';
+ else
+ *np = *op;
+ np++;
+ op++;
+ }
+ *np = 0;
+ mnemonic = newname;
+ }
+ prefix_p = "";
+ }
+
+ /* Special case: pfgt/pfle-- R-bit distinguishes the two. */
+ if ((insn & 0x7f) == 0x34)
+ {
+ const char *mn[2] = { "fgt.", "fle." };
+ int r = (insn & 0x080) >> 7;
+ int s = (insn & 0x100) ? 3 : 0;
+ sprintf(buf, "%s%s%s%s\t%%f%d,%%f%d,%%f%d", prefix_d, prefix_p, mn[r],
+ suffix[s], get_fsrc1 (insn), get_fsrc2 (insn), get_fdest (insn));
+ }
+ else
+ sprintf(buf, "%s%s%s%s\t%%f%d,%%f%d,%%f%d", prefix_d, prefix_p, mnemonic,
+ suffix[s], get_fsrc1 (insn), get_fsrc2 (insn), get_fdest (insn));
+}
+
+
+/* Floating-point 2-address register format:
+ * mnemonic %fs1,%fd */
+static void flop_1d(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ const char *suffix[4] = { "ss", "sd", "ds", "dd" };
+ const char *prefix_d, *prefix_p;
+ int s = (insn & 0x180) >> 7;
+ prefix_p = (insn & 0x400) ? "p" : "";
+ prefix_d = (insn & 0x200) ? "d." : "";
+ sprintf(buf, "%s%s%s%s\t%%f%d,%%f%d", prefix_d, prefix_p, mnemonic,
+ suffix[s], get_fsrc1 (insn), get_fdest (insn));
+}
+
+
+/* Floating-point 2-address register format:
+ * mnemonic %fs2,%fd */
+static void flop_2d(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ const char *suffix[4] = { "ss", "sd", "ds", "dd" };
+ const char *prefix_d;
+ int s = (insn & 0x180) >> 7;
+ prefix_d = (insn & 0x200) ? "d." : "";
+ sprintf(buf, "%s%s%s\t%%f%d,%%f%d", prefix_d, mnemonic, suffix[s],
+ get_fsrc2 (insn), get_fdest (insn));
+}
+
+
+/* Floating-point (mixed) 2-address register format:
+ * fxfr fsrc1,idest. */
+static void flop_fxfr(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ const char *prefix_d = (insn & 0x200) ? "d." : "";
+ sprintf(buf, "%s%s\t%%f%d,%%r%d", prefix_d, mnemonic, get_fsrc1 (insn),
+ get_idest (insn));
+}
+
+
+/* Branch with reg,reg,sbroff format:
+ * mnemonic %rs1,%rs2,sbroff */
+static void int_12S(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ INT32 sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
+ INT32 rel = (INT32)pc + (sbroff << 2) + 4;
+
+ sprintf(buf, "%s\t%%r%d,%%r%d,0x%08x", mnemonic, get_isrc1 (insn),
+ get_isrc2 (insn), (UINT32)rel);
+}
+
+
+/* Branch with #const5,reg,sbroff format:
+ * mnemonic #const5,%rs2,sbroff */
+static void int_i2S(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ INT32 sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
+ INT32 rel = (INT32)pc + (sbroff << 2) + 4;
+
+ sprintf(buf, "%s\t%d,%%r%d,0x%08x", mnemonic, ((insn >> 11) & 0x1f),
+ get_isrc2 (insn), (UINT32)rel);
+}
+
+
+/* Branch with lbroff format:
+ * mnemonic lbroff */
+static void int_L(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ INT32 lbroff = sign_ext ((insn & 0x03ffffff), 26);
+ INT32 rel = (INT32)pc + (lbroff << 2) + 4;
+
+ sprintf(buf, "%s\t0x%08x", mnemonic, (UINT32)rel);
+}
+
+
+/* Integer load.
+ * ld.{b,s,l} isrc1(isrc2),idest
+ * ld.{b,s,l} #const(isrc2),idest */
+static void int_ldx(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ /* Operand size, in bytes. */
+ int sizes[4] = { 1, 1, 2, 4 };
+ const char *suffix[4] = { "b", "b", "s", "l" };
+ UINT32 idx = 0;
+
+ /* Bits 28 and 0 determine the operand size. */
+ idx = ((insn >> 27) & 2) | (insn & 1);
+
+ /* Bit 26 determines the addressing mode (reg+reg or disp+reg). */
+ if (insn & 0x04000000)
+ {
+ /* Chop off lower bits of displacement. */
+ INT32 immsrc1 = sign_ext (get_imm16 (insn), 16);
+ int size = sizes[idx];
+ immsrc1 &= ~(size - 1);
+ sprintf(buf, "%s%s\t%d(%%r%d),%%r%d", mnemonic, suffix[idx],
+ immsrc1, get_isrc2 (insn), get_idest (insn));
+ }
+ else
+ sprintf(buf, "%s%s\t%%r%d(%%r%d),%%r%d", mnemonic, suffix[idx],
+ get_isrc1 (insn), get_isrc2 (insn), get_idest (insn));
+}
+
+
+/* Integer store: st.b isrc1ni,#const(isrc2) */
+static void int_stx(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ /* Operand size, in bytes. */
+ int sizes[4] = { 1, 1, 2, 4 };
+ const char *suffix[4] = { "b", "b", "s", "l" };
+ int idx = 0;
+ int size;
+ INT32 immsrc = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
+
+ /* Bits 28 and 0 determine the operand size. */
+ idx = ((insn >> 27) & 2) | (insn & 1);
+
+ /* Chop off lower bits of displacement. */
+ size = sizes[idx];
+ immsrc &= ~(size - 1);
+ sprintf(buf, "%s%s\t%%r%d,%d(%%r%d)", mnemonic, suffix[idx],
+ get_isrc1 (insn), immsrc, get_isrc2 (insn));
+}
+
+
+/* Disassemble:
+ * "[p]fld.y isrc1(isrc2),fdest", "[p]fld.y isrc1(isrc2)++,idest",
+ * "[p]fld.y #const(isrc2),fdest" or "[p]fld.y #const(isrc2)++,idest".
+ * "fst.y fdest,isrc1(isrc2)", "fst.y fdest,isrc1(isrc2)++",
+ * "fst.y fdest,#const(isrc2)" or "fst.y fdest,#const(isrc2)++"
+ * Where y = {l,d,q}. Note, there is no pfld.q, though. */
+static void int_fldst(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ INT32 immsrc1 = sign_ext (get_imm16 (insn), 16);
+ /* Operand size, in bytes. */
+ int sizes[4] = { 8, 4, 16, 4 };
+ const char *suffix[4] = { "d", "l", "q", "l" };
+ int idx = 0;
+ int size = 0;
+ int auto_inc = (insn & 1);
+ const char *auto_suff[2] = { "", "++" };
+ int piped = (insn & 0x40000000) >> 29;
+ const char *piped_suff[2] = { "", "p" };
+ int upper_6bits = (insn >> 26) & 0x3f;
+ int is_load = (upper_6bits == 8 || upper_6bits == 9 || upper_6bits == 24
+ || upper_6bits == 25);
+
+ /* Bits 2 and 1 determine the operand size. */
+ idx = ((insn >> 1) & 3);
+ size = sizes[idx];
+
+ /* There is no pipelined load quad on XR. */
+ if (piped && size == 16)
+ {
+ sprintf (buf, ".long\t%#08x; *", insn);
+ return;
+ }
+
+ /* There is only a 64-bit pixel store. */
+ if ((upper_6bits == 15) && size != 8)
+ {
+ sprintf (buf, ".long\t%#08x", insn);
+ return;
+ }
+
+ /* Bit 26 determines the addressing mode (reg+reg or disp+reg). */
+ if (insn & 0x04000000)
+ {
+ /* Chop off lower bits of displacement. */
+ immsrc1 &= ~(size - 1);
+ if (is_load)
+ sprintf(buf, "%s%s%s\t%d(%%r%d)%s,%%f%d", piped_suff[piped], mnemonic,
+ suffix[idx], immsrc1, get_isrc2 (insn), auto_suff[auto_inc],
+ get_fdest (insn));
+ else
+ sprintf(buf, "%s%s\t%%f%d,%d(%%r%d)%s", mnemonic, suffix[idx],
+ get_fdest (insn), immsrc1, get_isrc2 (insn), auto_suff[auto_inc]);
+ }
+ else
+ {
+ if (is_load)
+ sprintf(buf, "%s%s%s\t%%r%d(%%r%d)%s,%%f%d", piped_suff[piped],
+ mnemonic, suffix[idx], get_isrc1 (insn), get_isrc2 (insn),
+ auto_suff[auto_inc], get_fdest (insn));
+ else
+ sprintf(buf, "%s%s\t%%f%d,%%r%d(%%r%d)%s", mnemonic, suffix[idx],
+ get_fdest (insn), get_isrc1 (insn), get_isrc2 (insn),
+ auto_suff[auto_inc]);
+ }
+}
+
+
+/* flush #const(isrc2)[++]. */
+static void int_flush(char *buf, char *mnemonic, UINT32 pc, UINT32 insn)
+{
+ const char *auto_suff[2] = { "", "++" };
+ INT32 immsrc = sign_ext (get_imm16 (insn), 16);
+ immsrc &= ~(16-1);
+ sprintf(buf, "%s\t%d(%%r%d)%s", mnemonic, immsrc, get_isrc2 (insn),
+ auto_suff[(insn & 1)]);
+}
+
+
+/* Flags for the decode table. */
+enum
+{
+ DEC_MORE = 1, /* More decoding necessary. */
+ DEC_DECODED = 2 /* Fully decoded, go. */
+};
+
+
+typedef struct
+{
+ /* Disassembly function for this opcode.
+ Call with buffer, mnemonic, pc, insn. */
+ void (*insn_dis)(char *, char *, UINT32, UINT32);
+
+ /* Flags for this opcode. */
+ char flags;
+
+ /* Mnemonic of this opcode (sometimes partial when more decode is
+ done in disassembly routines-- e.g., loads and stores). */
+ const char *mnemonic;
+} decode_tbl_t;
+
+
+/* First-level decode table (i.e., for the 6 primary opcode bits). */
+static decode_tbl_t decode_tbl[64] =
+{
+ /* A slight bit of decoding for loads and stores is done in the
+ execution routines (operand size and addressing mode), which
+ is why their respective entries are identical. */
+ { int_ldx, DEC_DECODED, "ld." }, /* ld.b isrc1(isrc2),idest. */
+ { int_ldx, DEC_DECODED, "ld." }, /* ld.b #const(isrc2),idest. */
+ { int_1d, DEC_DECODED, "ixfr" }, /* ixfr isrc1ni,fdest. */
+ { int_stx, DEC_DECODED, "st." }, /* st.b isrc1ni,#const(isrc2). */
+ { int_ldx, DEC_DECODED, "ld." }, /* ld.{s,l} isrc1(isrc2),idest. */
+ { int_ldx, DEC_DECODED, "ld." }, /* ld.{s,l} #const(isrc2),idest. */
+ { 0, 0 , 0 },
+ { int_stx, DEC_DECODED, "st." }, /* st.{s,l} isrc1ni,#const(isrc2),idest.*/
+ { int_fldst, DEC_DECODED, "fld." }, /* fld.{l,d,q} isrc1(isrc2)[++],fdest. */
+ { int_fldst, DEC_DECODED, "fld." }, /* fld.{l,d,q} #const(isrc2)[++],fdest. */
+ { int_fldst, DEC_DECODED, "fst." }, /* fst.{l,d,q} fdest,isrc1(isrc2)[++] */
+ { int_fldst, DEC_DECODED, "fst." }, /* fst.{l,d,q} fdest,#const(isrc2)[++] */
+ { int_cd, DEC_DECODED, "ld.c" }, /* ld.c csrc2,idest. */
+ { int_flush, DEC_DECODED, "flush" }, /* flush #const(isrc2) (or autoinc). */
+ { int_1c, DEC_DECODED, "st.c" }, /* st.c isrc1,csrc2. */
+ { int_fldst, DEC_DECODED, "pstd." }, /* pst.d fdest,#const(isrc2)[++]. */
+ { int_1, DEC_DECODED, "bri" }, /* bri isrc1ni. */
+ { int_12d, DEC_DECODED, "trap" }, /* trap isrc1ni,isrc2,idest. */
+ { 0, DEC_MORE, 0 }, /* FP ESCAPE FORMAT, more decode. */
+ { 0, DEC_MORE, 0 }, /* CORE ESCAPE FORMAT, more decode. */
+ { int_12S, DEC_DECODED, "btne" }, /* btne isrc1,isrc2,sbroff. */
+ { int_i2S, DEC_DECODED, "btne" }, /* btne #const,isrc2,sbroff. */
+ { int_12S, DEC_DECODED, "bte" }, /* bte isrc1,isrc2,sbroff. */
+ { int_i2S, DEC_DECODED, "bte" }, /* bte #const5,isrc2,idest. */
+ { int_fldst, DEC_DECODED, "pfld." }, /* pfld.{l,d,q} isrc1(isrc2)[++],fdest. */
+ { int_fldst, DEC_DECODED, "pfld." }, /* pfld.{l,d,q} #const(isrc2)[++],fdest.*/
+ { int_L, DEC_DECODED, "br" }, /* br lbroff. */
+ { int_L, DEC_DECODED, "call" }, /* call lbroff . */
+ { int_L, DEC_DECODED, "bc" }, /* bc lbroff. */
+ { int_L, DEC_DECODED, "bc.t" }, /* bc.t lbroff. */
+ { int_L, DEC_DECODED, "bnc" }, /* bnc lbroff. */
+ { int_L, DEC_DECODED, "bnc.t" }, /* bnc.t lbroff. */
+ { int_12d, DEC_DECODED, "addu" }, /* addu isrc1,isrc2,idest. */
+ { int_i2d, DEC_DECODED, "addu" }, /* addu #const,isrc2,idest. */
+ { int_12d, DEC_DECODED, "subu" }, /* subu isrc1,isrc2,idest. */
+ { int_i2d, DEC_DECODED, "subu" }, /* subu #const,isrc2,idest. */
+ { int_12d, DEC_DECODED, "adds" }, /* adds isrc1,isrc2,idest. */
+ { int_i2d, DEC_DECODED, "adds" }, /* adds #const,isrc2,idest. */
+ { int_12d, DEC_DECODED, "subs" }, /* subs isrc1,isrc2,idest. */
+ { int_i2d, DEC_DECODED, "subs" }, /* subs #const,isrc2,idest. */
+ { int_12d, DEC_DECODED, "shl" }, /* shl isrc1,isrc2,idest. */
+ { int_i2d, DEC_DECODED, "shl" }, /* shl #const,isrc2,idest. */
+ { int_12d, DEC_DECODED, "shr" }, /* shr isrc1,isrc2,idest. */
+ { int_i2d, DEC_DECODED, "shr" }, /* shr #const,isrc2,idest. */
+ { int_12d, DEC_DECODED, "shrd" }, /* shrd isrc1ni,isrc2,idest. */
+ { int_12S, DEC_DECODED, "bla" }, /* bla isrc1ni,isrc2,sbroff. */
+ { int_12d, DEC_DECODED, "shra" }, /* shra isrc1,isrc2,idest. */
+ { int_i2d, DEC_DECODED, "shra" }, /* shra #const,isrc2,idest. */
+ { int_12d, DEC_DECODED, "and" }, /* and isrc1,isrc2,idest. */
+ { int_i2d, DEC_DECODED, "and" }, /* and #const,isrc2,idest. */
+ { 0, 0 , 0 },
+ { int_i2d, DEC_DECODED, "andh" }, /* andh #const,isrc2,idest. */
+ { int_12d, DEC_DECODED, "andnot" }, /* andnot isrc1,isrc2,idest. */
+ { int_i2d, DEC_DECODED, "andnot" }, /* andnot #const,isrc2,idest. */
+ { 0, 0 , 0 },
+ { int_i2d, DEC_DECODED, "andnoth" }, /* andnoth #const,isrc2,idest.*/
+ { int_12d, DEC_DECODED, "or" }, /* or isrc1,isrc2,idest. */
+ { int_i2d, DEC_DECODED, "or" }, /* or #const,isrc2,idest. */
+ { 0, 0 , 0 },
+ { int_i2d, DEC_DECODED, "orh" }, /* orh #const,isrc2,idest. */
+ { int_12d, DEC_DECODED, "xor" }, /* xor isrc1,isrc2,idest. */
+ { int_i2d, DEC_DECODED, "xor" }, /* xor #const,isrc2,idest. */
+ { 0, 0 , 0 },
+ { int_i2d, DEC_DECODED, "xorh" }, /* xorh #const,isrc2,idest. */
+};
+
+
+/* Second-level decode table (i.e., for the 3 core escape opcode bits). */
+static decode_tbl_t core_esc_decode_tbl[8] =
+{
+ { 0, 0 , 0 },
+ { int_0, DEC_DECODED, "lock" }, /* lock. */
+ { int_1, DEC_DECODED, "calli" }, /* calli isrc1ni. */
+ { 0, 0 , 0 },
+ { int_0, DEC_DECODED, "intovr" }, /* intovr. */
+ { 0, 0 , 0 },
+ { 0, 0 , 0 },
+ { int_0, DEC_DECODED, "unlock" }, /* unlock. */
+};
+
+
+/* Second-level decode table (i.e., for the 7 FP extended opcode bits). */
+static decode_tbl_t fp_decode_tbl[128] =
+{
+ /* Floating point instructions. The least significant 7 bits are
+ the (extended) opcode and bits 10:7 are P,D,S,R respectively
+ ([p]ipelined, [d]ual, [s]ource prec., [r]esult prec.).
+ For some operations, I defer decoding the P,S,R bits to the
+ emulation routine for them. */
+ { flop_12d, DEC_DECODED, "r2p1." }, /* 0x00 pf[m]am */
+ { flop_12d, DEC_DECODED, "r2pt." }, /* 0x01 pf[m]am */
+ { flop_12d, DEC_DECODED, "r2ap1." }, /* 0x02 pf[m]am */
+ { flop_12d, DEC_DECODED, "r2apt." }, /* 0x03 pf[m]am */
+ { flop_12d, DEC_DECODED, "i2p1." }, /* 0x04 pf[m]am */
+ { flop_12d, DEC_DECODED, "i2pt." }, /* 0x05 pf[m]am */
+ { flop_12d, DEC_DECODED, "i2ap1." }, /* 0x06 pf[m]am */
+ { flop_12d, DEC_DECODED, "i2apt." }, /* 0x07 pf[m]am */
+ { flop_12d, DEC_DECODED, "rat1p2." }, /* 0x08 pf[m]am */
+ { flop_12d, DEC_DECODED, "m12apm." }, /* 0x09 pf[m]am */
+ { flop_12d, DEC_DECODED, "ra1p2." }, /* 0x0A pf[m]am */
+ { flop_12d, DEC_DECODED, "m12ttpa." }, /* 0x0B pf[m]am */
+ { flop_12d, DEC_DECODED, "iat1p2." }, /* 0x0C pf[m]am */
+ { flop_12d, DEC_DECODED, "m12tpm." }, /* 0x0D pf[m]am */
+ { flop_12d, DEC_DECODED, "ia1p2." }, /* 0x0E pf[m]am */
+ { flop_12d, DEC_DECODED, "m12tpa." }, /* 0x0F pf[m]am */
+ { flop_12d, DEC_DECODED, "r2s1." }, /* 0x10 pf[m]sm */
+ { flop_12d, DEC_DECODED, "r2st." }, /* 0x11 pf[m]sm */
+ { flop_12d, DEC_DECODED, "r2as1." }, /* 0x12 pf[m]sm */
+ { flop_12d, DEC_DECODED, "r2ast." }, /* 0x13 pf[m]sm */
+ { flop_12d, DEC_DECODED, "i2s1." }, /* 0x14 pf[m]sm */
+ { flop_12d, DEC_DECODED, "i2st." }, /* 0x15 pf[m]sm */
+ { flop_12d, DEC_DECODED, "i2as1." }, /* 0x16 pf[m]sm */
+ { flop_12d, DEC_DECODED, "i2ast." }, /* 0x17 pf[m]sm */
+ { flop_12d, DEC_DECODED, "rat1s2." }, /* 0x18 pf[m]sm */
+ { flop_12d, DEC_DECODED, "m12asm." }, /* 0x19 pf[m]sm */
+ { flop_12d, DEC_DECODED, "ra1s2." }, /* 0x1A pf[m]sm */
+ { flop_12d, DEC_DECODED, "m12ttsa." }, /* 0x1B pf[m]sm */
+ { flop_12d, DEC_DECODED, "iat1s2." }, /* 0x1C pf[m]sm */
+ { flop_12d, DEC_DECODED, "m12tsm." }, /* 0x1D pf[m]sm */
+ { flop_12d, DEC_DECODED, "ia1s2." }, /* 0x1E pf[m]sm */
+ { flop_12d, DEC_DECODED, "m12tsa." }, /* 0x1F pf[m]sm */
+ { flop_12d, DEC_DECODED, "fmul." }, /* 0x20 [p]fmul */
+ { flop_12d, DEC_DECODED, "fmlow." }, /* 0x21 fmlow.dd */
+ { flop_2d, DEC_DECODED, "frcp." }, /* 0x22 frcp.{ss,sd,dd} */
+ { flop_2d, DEC_DECODED, "frsqr." }, /* 0x23 frsqr.{ss,sd,dd} */
+ { flop_12d, DEC_DECODED, "pfmul3.dd" }, /* 0x24 pfmul3.dd */
+ { 0, 0 , 0 }, /* 0x25 */
+ { 0, 0 , 0 }, /* 0x26 */
+ { 0, 0 , 0 }, /* 0x27 */
+ { 0, 0 , 0 }, /* 0x28 */
+ { 0, 0 , 0 }, /* 0x29 */
+ { 0, 0 , 0 }, /* 0x2A */
+ { 0, 0 , 0 }, /* 0x2B */
+ { 0, 0 , 0 }, /* 0x2C */
+ { 0, 0 , 0 }, /* 0x2D */
+ { 0, 0 , 0 }, /* 0x2E */
+ { 0, 0 , 0 }, /* 0x2F */
+ { flop_12d, DEC_DECODED, "fadd." }, /* 0x30, [p]fadd.{ss,sd,dd} */
+ { flop_12d, DEC_DECODED, "fsub." }, /* 0x31, [p]fsub.{ss,sd,dd} */
+ { flop_1d, DEC_DECODED, "fix." }, /* 0x32, [p]fix.{ss,sd,dd} */
+ { flop_1d, DEC_DECODED, "famov." }, /* 0x33, [p]famov.{ss,sd,ds,dd} */
+ { flop_12d, DEC_DECODED, "f{gt,le}" }, /* 0x34, pf{gt,le}.{ss,dd} */
+ { flop_12d, DEC_DECODED, "feq." }, /* 0x35, pfeq.{ss,dd} */
+ { 0, 0 , 0 }, /* 0x36 */
+ { 0, 0 , 0 }, /* 0x37 */
+ { 0, 0 , 0 }, /* 0x38 */
+ { 0, 0 , 0 }, /* 0x39 */
+ { flop_1d, DEC_DECODED, "ftrunc." }, /* 0x3A, [p]ftrunc.{ss,sd,dd} */
+ { 0, 0 , 0 }, /* 0x3B */
+ { 0, 0 , 0 }, /* 0x3C */
+ { 0, 0 , 0 }, /* 0x3D */
+ { 0, 0 , 0 }, /* 0x3E */
+ { 0, 0 , 0 }, /* 0x3F */
+ { flop_fxfr, DEC_DECODED, "fxfr" }, /* 0x40, fxfr fsrc1,idest. */
+ { 0, 0 , 0 }, /* 0x41 */
+ { 0, 0 , 0 }, /* 0x42 */
+ { 0, 0 , 0 }, /* 0x43 */
+ { 0, 0 , 0 }, /* 0x44 */
+ { 0, 0 , 0 }, /* 0x45 */
+ { 0, 0 , 0 }, /* 0x46 */
+ { 0, 0 , 0 }, /* 0x47 */
+ { 0, 0 , 0 }, /* 0x48 */
+ { flop_12d, DEC_DECODED, "fiadd." }, /* 0x49, [p]fiadd.{ss,dd} */
+ { 0, 0 , 0 }, /* 0x4A */
+ { 0, 0 , 0 }, /* 0x4B */
+ { 0, 0 , 0 }, /* 0x4C */
+ { flop_12d, DEC_DECODED, "fisub." }, /* 0x4D, [p]fisub.{ss,dd} */
+ { 0, 0 , 0 }, /* 0x4E */
+ { 0, 0 , 0 }, /* 0x4F */
+ { flop_12d, DEC_DECODED, "faddp" }, /* 0x50, [p]faddp */
+ { flop_12d, DEC_DECODED, "faddz" }, /* 0x51, [p]faddz */
+ { 0, 0 , 0 }, /* 0x52 */
+ { 0, 0 , 0 }, /* 0x53 */
+ { 0, 0 , 0 }, /* 0x54 */
+ { 0, 0 , 0 }, /* 0x55 */
+ { 0, 0 , 0 }, /* 0x56 */
+ { flop_12d, DEC_DECODED, "fzchkl" }, /* 0x57, [p]fzchkl */
+ { 0, 0 , 0 }, /* 0x58 */
+ { 0, 0 , 0 }, /* 0x59 */
+ { flop_1d, DEC_DECODED, "form" }, /* 0x5A, [p]form.dd */
+ { 0, 0 , 0 }, /* 0x5B */
+ { 0, 0 , 0 }, /* 0x5C */
+ { 0, 0 , 0 }, /* 0x5D */
+ { 0, 0 , 0 }, /* 0x5E */
+ { flop_12d, DEC_DECODED, "fzchks" }, /* 0x5F, [p]fzchks */
+ { 0, 0 , 0 }, /* 0x60 */
+ { 0, 0 , 0 }, /* 0x61 */
+ { 0, 0 , 0 }, /* 0x62 */
+ { 0, 0 , 0 }, /* 0x63 */
+ { 0, 0 , 0 }, /* 0x64 */
+ { 0, 0 , 0 }, /* 0x65 */
+ { 0, 0 , 0 }, /* 0x66 */
+ { 0, 0 , 0 }, /* 0x67 */
+ { 0, 0 , 0 }, /* 0x68 */
+ { 0, 0 , 0 }, /* 0x69 */
+ { 0, 0 , 0 }, /* 0x6A */
+ { 0, 0 , 0 }, /* 0x6B */
+ { 0, 0 , 0 }, /* 0x6C */
+ { 0, 0 , 0 }, /* 0x6D */
+ { 0, 0 , 0 }, /* 0x6E */
+ { 0, 0 , 0 }, /* 0x6F */
+ { 0, 0 , 0 }, /* 0x70 */
+ { 0, 0 , 0 }, /* 0x71 */
+ { 0, 0 , 0 }, /* 0x72 */
+ { 0, 0 , 0 }, /* 0x73 */
+ { 0, 0 , 0 }, /* 0x74 */
+ { 0, 0 , 0 }, /* 0x75 */
+ { 0, 0 , 0 }, /* 0x76 */
+ { 0, 0 , 0 }, /* 0x77 */
+ { 0, 0 , 0 }, /* 0x78 */
+ { 0, 0 , 0 }, /* 0x79 */
+ { 0, 0 , 0 }, /* 0x7A */
+ { 0, 0 , 0 }, /* 0x7B */
+ { 0, 0 , 0 }, /* 0x7C */
+ { 0, 0 , 0 }, /* 0x7D */
+ { 0, 0 , 0 }, /* 0x7E */
+ { 0, 0 , 0 }, /* 0x7F */
+};
+
+
+/* Replaces tabs with spaces. */
+static void i860_dasm_tab_replacer(char* buf, int tab_size)
+{
+ int i = 0;
+ int tab_count = 0;
+ char tab_buf[1024];
+ memset(tab_buf, 0, 1024);
+
+ while (i != strlen(buf))
+ {
+ if (buf[i] != '\t')
+ {
+ tab_buf[tab_count] = buf[i];
+ tab_count++;
+ }
+ else
+ {
+ while (tab_count % tab_size != 0)
+ {
+ strcat(tab_buf, " ");
+ tab_count++;
+ }
+ }
+ i++;
+ }
+
+ tab_buf[tab_count] = 0x00;
+ strcpy(buf, tab_buf);
+}
+
+
+/* Entry point for disassembler. */
+unsigned disasm_i860(char *buf, unsigned pc, UINT32 insn)
+{
+ int unrecognized_op = 1;
+ int upper_6bits = (insn >> 26) & 0x3f;
+ char flags = decode_tbl[upper_6bits].flags;
+ if (flags & DEC_DECODED)
+ {
+ const char *s = decode_tbl[upper_6bits].mnemonic;
+ decode_tbl[upper_6bits].insn_dis (buf, (char *)s, pc, insn);
+ unrecognized_op = 0;
+ }
+ else if (flags & DEC_MORE)
+ {
+ if (upper_6bits == 0x12)
+ {
+ /* FP instruction format handled here. */
+ char fp_flags = fp_decode_tbl[insn & 0x7f].flags;
+ const char *s = fp_decode_tbl[insn & 0x7f].mnemonic;
+ if (fp_flags & DEC_DECODED)
+ {
+ fp_decode_tbl[insn & 0x7f].insn_dis (buf, (char *)s, pc, insn);
+ unrecognized_op = 0;
+ }
+ }
+ else if (upper_6bits == 0x13)
+ {
+ /* Core escape instruction format handled here. */
+ char esc_flags = core_esc_decode_tbl[insn & 0x3].flags;
+ const char *s = core_esc_decode_tbl[insn & 0x3].mnemonic;
+ if (esc_flags & DEC_DECODED)
+ {
+ core_esc_decode_tbl[insn & 0x3].insn_dis (buf, (char *)s, pc, insn);
+ unrecognized_op = 0;
+ }
+ }
+ }
+
+ if (unrecognized_op)
+ sprintf (buf, ".long\t%#08x", insn);
+
+ /* Replace tabs with spaces */
+ i860_dasm_tab_replacer(buf, 10);
+
+ /* Return number of bytes disassembled. */
+ /* MAME dasm flags haven't been added yet */
+ return (4);
+}
diff --git a/src/mame/drivers/vcombat.c b/src/mame/drivers/vcombat.c
index a5437a2ec2c..797eaccc674 100644
--- a/src/mame/drivers/vcombat.c
+++ b/src/mame/drivers/vcombat.c
@@ -1,8 +1,8 @@
/*
Virtual Combat hardware games.
-
-Driver by Jason Eckhardt and Andrew Gardner.
-
+
+Driver by Jason Eckhardt and Andrew Gardner.
+
----
There are two known games on this hardware. Both are developed by
@@ -17,10 +17,10 @@ Shadow Fighters (German) (c) Sega? 1989?
There are two boards to this hardware. The upper, which contains the
graphics ROMs and the i860, and the lower which contains the main
-and sound CPUs. Virtual Combat sports two upper boards which presumably
+and sound CPUs. Virtual Combat sports two upper boards which
output a different rasterization of the scene for each stereo eye.
-UPPER:
+UPPER: (Virtual Combat has an identical MIDDLE board also).
Intel I860 XR processor
MB8298-25P-SK RAMS x12 (silkscreen said 62256)
Analog device ADV476KN50E (silkscreen said BT476)
@@ -28,7 +28,7 @@ UPPER:
8-way DIP switch
574200D x4
PAL palce24v10 x2 (next to the i860)
- Bt476 RAMDAC
+ Bt476 RAMDAC
LOWER:
Motorola MC68000P12 x2
@@ -54,20 +54,50 @@ NOTES : Shadow Fighters appears to have been dumped from an earlier
The data stored in "samples" is simply a series of
Creative Media VOC files concatenated to eachother.
The sound program ("sound") is about 640 bytes long.
- The graphics ROMs have had images successfully extracted from
- them. Pictures for Shadow Fighters can be found online.
The hardware is said to run at medium resolution.
The SRAM module dump can likely be thrown away for both games.
The PAL that's dumped for Shadow Fighters looks pretty bad.
- Websites seem to say Shadow Fighters is a SEGA game, but I
- couldn't find a SEGA string anywhere in the ROMs. I also,
- however, could not find a VR8 string in the Virtual Combat
- ROMs, so who knows... Kyle's name is easily found in both
- though :).
-
-TODO : This is a skeleton driver. Nearly everything.
- i860XR-25 CPU core!
+TODO : This is a partially working driver. Most of the memory maps for
+ all four CPUs are complete. An Intel i860XR CPU core has now
+ been incorporated into MAME.
+
+ -------- Notes/questions ----------
+ - Most of the memory maps and input ports are complete now.
+ For "main", the only I/O locations that seem to be left
+ mysterious are:
+ 0x600010,
+ 0x60000C: Only written; maybe mc6845? Often accessed
+ together, and 16 consecutive words of data are
+ written to 0x60000C, making me think it might be
+ 6845-related. May or may not be important for
+ reasonable emulation.
+ 0x60001C: Only read; might be a latch of some sort. It is
+ read each time M0's interrupt service routine syncs
+ with the i860's to have them update the frame buffer.
+ Might this be a HW blank bit so things look clean when
+ the i860's do their updates?
+ The two other times I see it read are just before
+ and after one of the pallette setups is done.
+ 0x600018: ? No info yet.
+ 0x704000: (VC only) Likely analog axis for VR headset
+ 0x703000: (VC only) Likely analog axis for VR headset
+ 0x702000: (Shadow only). I think this is another IN port. It
+ is always read at the same time as the other two
+ ports.
+
+ - Assuming a single framebuffer, as I think we are at the moment,
+ how are all the CPUs writes to the framebuffer prioritized,
+ if at all? The zero values written by the 68k side erase
+ the i860-generated FB data (i.e., zero maps to black in the
+ pallette). On the other hand, treating the zero values as
+ transparent doesn't quite look right either. Could just the
+ i860s each have their own framebuffers? After
+ all, since each eye of the binocular sees a slightly different
+ picture, the i860's might just maintain their own. Then maybe
+ the 68k shares with each of the two, since I think it just
+ generates a single picture (not sure about that either).
+ ----------------------------------------------
*/
#include <stdio.h>
@@ -77,61 +107,266 @@ TODO : This is a skeleton driver. Nearly everything.
#include "video/generic.h"
#include "video/tlc34076.h"
-static UINT16* framebuffer;
+static UINT16* framebuffer_main;
+static UINT16* framebuffer_secondary;
static UINT16* vid_0_shared_RAM;
static UINT16* vid_1_shared_RAM;
+
+static VIDEO_UPDATE( vcombat )
+{
+ int x, y;
+ int count = 0;
+ const rgb_t *pens = tlc34076_get_pens();
+
+ /* TODO: It looks like the leftmost chunk of the ground should really be on the right side? */
+ /* But the i860 draws the background correctly, so it may be an original game issue. */
+ /* There's also some garbage in the upper-left corner. Might be related to this 'wraparound'. */
+ /* Or maybe it's related to the 68k's alpha? It might come from the 68k side of the house. */
+
+ /* Main eye */
+ for(y = 0; y < 256; y++)
+ {
+ for(x = 384; x < 640; x++)
+ {
+ UINT32 color;
+ if (x % 2) color = (framebuffer_main[count] & 0xff00) >> 8;
+ else color = framebuffer_main[count] & 0x00ff;
+
+ /* Vcombat's screen renders 'flopped' - very likely because VR headset displays may reflect off mirrors.
+ Shadfgtr isn't flopped, so it's not a constant feature of the hardware. */
+ if(x < video_screen_get_visible_area(screen)->max_x && y < video_screen_get_visible_area(screen)->max_y)
+ *BITMAP_ADDR32(bitmap, y, x) = pens[color];
+
+ if (x % 2) count++;
+ }
+ }
+
+ /* Early out for shadow fighters */
+ if (!framebuffer_secondary)
+ return 0;
+
+ /* Secondary eye */
+ count = 0;
+ for(y = 0; y < 256; y++)
+ {
+ for(x = 0; x < 256; x++)
+ {
+ UINT32 color;
+ if (x % 2) color = (framebuffer_secondary[count] & 0xff00) >> 8;
+ else color = framebuffer_secondary[count] & 0x00ff;
+
+ /* Vcombat's screen renders 'flopped' - very likely because VR headset displays may reflect off mirrors.
+ Shadfgtr isn't flopped, so it's not a constant feature of the hardware. */
+ if(x < video_screen_get_visible_area(screen)->max_x && y < video_screen_get_visible_area(screen)->max_y)
+ *BITMAP_ADDR32(bitmap, y, x) = pens[color];
+
+ if (x % 2) count++;
+ }
+ }
+
+ return 0;
+}
+
+
+/* Maybe there's a blend chip between the 68k and the framebuffer? */
+static WRITE16_HANDLER( main_video_write )
+{
+ /* Doesn't seem to make sense for shadow fighters. Maybe some of that factory rework disables this? */
+ /* Doesn't always seem to work for vcombat either. More testing needed. */
+ if (data != 0x00000000) {
+ framebuffer_main[offset] = data;
+ }
+}
+
+static READ16_HANDLER( control_1_r )
+{
+ return (input_port_read(space->machine, "IN0") << 8);
+}
+
+static READ16_HANDLER( control_2_r )
+{
+ return (input_port_read(space->machine, "IN1") << 8);
+}
+
+static void wiggle_i860_common(int n, UINT16 data, const device_config *device)
+{
+ int bus_hold = (data & 0x03) == 0x03;
+ int reset = data & 0x10;
+ assert(n >= 0 && n < 2);
+ if (!device)
+ return;
+ if (bus_hold)
+ {
+ fprintf(stderr, "M0 asserting bus HOLD to i860 %s\n", device->tag);
+ i860_set_pin(device->token, DEC_PIN_BUS_HOLD, 1);
+ }
+ else
+ {
+ fprintf(stderr, "M0 clearing bus HOLD to i860 %s\n", device->tag);
+ i860_set_pin(device->token, DEC_PIN_BUS_HOLD, 0);
+ }
+
+ if (reset)
+ {
+ fprintf(stderr, "M0 asserting RESET to i860 %s\n", device->tag);
+ i860_set_pin(device->token, DEC_PIN_RESET, 1);
+ }
+ else
+ i860_set_pin(device->token, DEC_PIN_RESET, 0);
+}
+
+static WRITE16_HANDLER( wiggle_i860p0_pins_w )
+{
+ wiggle_i860_common(0, data, cputag_get_cpu(space->machine, "vid_0"));
+}
+
+static WRITE16_HANDLER( wiggle_i860p1_pins_w )
+{
+ wiggle_i860_common(1, data, cputag_get_cpu(space->machine, "vid_1"));
+}
+
+static READ16_HANDLER( main_irqiack_r )
+{
+ //fprintf(stderr, "M0: irq iack\n");
+ cpu_set_input_line(cputag_get_cpu(space->machine, "main"), M68K_IRQ_1, CLEAR_LINE);
+ //cpu_set_input_line(cputag_get_cpu(space->machine, "main"), INPUT_LINE_RESET, CLEAR_LINE);
+ return 0;
+}
+
+static READ16_HANDLER( sound_resetmain_r )
+{
+ //fprintf(stderr, "M1: reset line to M0\n");
+ //cpu_set_input_line(cputag_get_cpu(space->machine, "main"), INPUT_LINE_RESET, PULSE_LINE);
+ return 0;
+}
+
+static WRITE64_HANDLER( v0_fb_w )
+{
+ /* The frame buffer seems to sit on a 32-bit data bus, while the
+ i860 uses a 64-bit data bus. Adjust accordingly. */
+ char *p = (char *)framebuffer_main;
+ int m = mem_mask;
+ int o = (offset << 2);
+ if (m & 0xff000000) {
+ p[o+3] = (data >> 24) & 0xff;
+ }
+ if (m & 0x00ff0000) {
+ p[o+2] = (data >> 16) & 0xff;
+ }
+ if (m & 0x0000ff00) {
+ p[o+1] = (data >> 8) & 0xff;
+ }
+ if (m & 0x000000ff) {
+ p[o+0] = (data >> 0) & 0xff;
+ }
+}
+
+/* This is just temporary so we can see what each i860 is doing to the
+ framebuffer. */
+static WRITE64_HANDLER( v1_fb_w )
+{
+ /* The frame buffer seems to sit on a 32-bit data bus, while the
+ i860 uses a 64-bit data bus. Adjust accordingly. */
+ char *p = (char *)framebuffer_secondary;
+ int m = mem_mask;
+ int o = (offset << 2);
+ if (m & 0xff000000) {
+ p[o+3] = (data >> 24) & 0xff;
+ }
+ if (m & 0x00ff0000) {
+ p[o+2] = (data >> 16) & 0xff;
+ }
+ if (m & 0x0000ff00) {
+ p[o+1] = (data >> 8) & 0xff;
+ }
+ if (m & 0x000000ff) {
+ p[o+0] = (data >> 0) & 0xff;
+ }
+}
+
+
static ADDRESS_MAP_START( main_map, ADDRESS_SPACE_PROGRAM, 16 )
AM_RANGE(0x000000, 0x0fffff) AM_ROM
AM_RANGE(0x200000, 0x2fffff) AM_RAM
- AM_RANGE(0x300000, 0x3fffff) AM_RAM AM_BASE(&framebuffer) AM_SHARE(1)
-
+ AM_RANGE(0x300000, 0x30ffff) AM_RAM_WRITE(main_video_write)
+
AM_RANGE(0x400000, 0x43ffff) AM_RAM AM_BASE(&vid_0_shared_RAM) AM_SHARE(2) /* First i860 shared RAM */
-// AM_RANGE(0x440000, 0x440003) i860 #1 com 1
-// AM_RANGE(0x480000, 0x480003) i860 #1 com 2
-// AM_RANGE(0x4c0000, 0x4c0003) i860 #1 stop/start/reset
+ AM_RANGE(0x440000, 0x440003) AM_RAM AM_SHARE(6) /* M0->P0 i860 #1 com 1 */
+ AM_RANGE(0x480000, 0x480003) AM_RAM AM_SHARE(7) /* M0<-P0 i860 #1 com 2 */
+ AM_RANGE(0x4c0000, 0x4c0003) AM_WRITE(wiggle_i860p0_pins_w) /* i860 #1 stop/start/reset */
AM_RANGE(0x500000, 0x53ffff) AM_RAM AM_BASE(&vid_1_shared_RAM) AM_SHARE(3) /* Second i860 shared RAM */
-// AM_RANGE(0x540000, 0x540003) i860 #2 com 1
-// AM_RANGE(0x580000, 0x580003) i860 #2 com 2
-// AM_RANGE(0x5c0000, 0x5c0003) i860 #2 stop/start/reset
+ AM_RANGE(0x540000, 0x540003) AM_RAM AM_SHARE(8) /* M0->P1 i860 #2 com 1 */
+ AM_RANGE(0x580000, 0x580003) AM_RAM AM_SHARE(9) /* M0<-P1 i860 #2 com 2 */
+ AM_RANGE(0x5c0000, 0x5c0003) AM_WRITE(wiggle_i860p1_pins_w) /* i860 #2 stop/start/reset */
+
+ AM_RANGE(0x600000, 0x600001) AM_READ(control_1_r) /* IN0 port */
+ AM_RANGE(0x600004, 0x600005) AM_RAM AM_SHARE(5) /* M0<-M1 */
+ AM_RANGE(0x600008, 0x600009) AM_READ(control_2_r) /* IN1 port */
+ /* AM_RANGE(0x60000c, 0x60000d) See notes at top of driver. */
+ /* AM_RANGE(0x600010, 0x600011) See notes at top of driver. */
+ AM_RANGE(0x700000, 0x7007ff) AM_RAM /* TODO: Non-volatile RAM */
+ AM_RANGE(0x701000, 0x701001) AM_READ(main_irqiack_r)
+ AM_RANGE(0x705000, 0x705001) AM_RAM AM_SHARE(4) /* M1->M0 */
+
+ //AM_RANGE(0x703000, 0x703001) /* Headset rotation axis? */
+ //AM_RANGE(0x704000, 0x704001) /* Headset rotation axis? */
AM_RANGE(0x706000, 0x70601f) AM_READWRITE(tlc34076_lsb_r, tlc34076_lsb_w)
ADDRESS_MAP_END
/* The first i860 - middle board */
-static ADDRESS_MAP_START( vid_0_map, ADDRESS_SPACE_PROGRAM, 32 )
- AM_RANGE(0x00000000, 0x000fffff) AM_RAM AM_SHARE(1) /* Shared framebuffer */
-// AM_RANGE(0x20000000, 0x20000003) com 1 (0x440000 in 68k-land)
-// AM_RANGE(0x40000000, 0x401fffff) AM_ROM /* 3d data ROMs */
-// AM_RANGE(0x80000000, 0x80000003) com 2 (0x480000 in 68k-land)
- AM_RANGE(0xfffc0000, 0xffffffff) AM_RAM AM_SHARE(2) /* Shared RAM with main */
+static ADDRESS_MAP_START( vid_0_map, ADDRESS_SPACE_PROGRAM, 64 )
+ AM_RANGE(0x00000000, 0x0001ffff) AM_RAM_WRITE(v0_fb_w) /* Shared framebuffer - half of the bits lost to 32-bit bus */
+ AM_RANGE(0x20000000, 0x20000007) AM_RAM AM_SHARE(6) /* M0<-P0 com 1 (0x440000 in 68k-land) */
+ AM_RANGE(0x40000000, 0x401fffff) AM_ROM AM_REGION("gfx", 0)
+ AM_RANGE(0x80000000, 0x80000007) AM_RAM AM_SHARE(7) /* M0->P0 com 2 (0x480000 in 68k-land) */
+ AM_RANGE(0xc0000000, 0xc0000fff) AM_NOP /* Dummy D$ flush page. */
+ AM_RANGE(0xfffc0000, 0xffffffff) AM_RAM AM_SHARE(2) /* Shared RAM with main */
ADDRESS_MAP_END
/* The second i860 - top board */
-static ADDRESS_MAP_START( vid_1_map, ADDRESS_SPACE_PROGRAM, 32 )
- AM_RANGE(0x00000000, 0x000fffff) AM_RAM AM_SHARE(1) /* Shared framebuffer */
-// AM_RANGE(0x20000000, 0x20000003) com 1 (0x540000 in 68k-land)
-// AM_RANGE(0x40000000, 0x401fffff) AM_ROM /* 3d data ROMs */
-// AM_RANGE(0x80000000, 0x80000003) com 2 (0x580000 in 68k-land)
- AM_RANGE(0xfffc0000, 0xffffffff) AM_RAM AM_SHARE(3) /* Shared RAM with main */
+static ADDRESS_MAP_START( vid_1_map, ADDRESS_SPACE_PROGRAM, 64 )
+ AM_RANGE(0x00000000, 0x0001ffff) AM_RAM_WRITE(v1_fb_w) /* Half of the bits lost to 32-bit bus */
+ AM_RANGE(0x20000000, 0x20000007) AM_RAM AM_SHARE(8) /* M0->P1 com 1 (0x540000 in 68k-land) */
+ AM_RANGE(0x40000000, 0x401fffff) AM_ROM AM_REGION("gfx", 0)
+ AM_RANGE(0x80000000, 0x80000007) AM_RAM AM_SHARE(9) /* M0<-P1 com 2 (0x580000 in 68k-land) */
+ AM_RANGE(0xc0000000, 0xc0000fff) AM_NOP /* Dummy D$ flush page. */
+ AM_RANGE(0xfffc0000, 0xffffffff) AM_RAM AM_SHARE(3) /* Shared RAM with main */
ADDRESS_MAP_END
-/* Sound CPU - temprarily disabled */
-//static ADDRESS_MAP_START( sound_map, ADDRESS_SPACE_PROGRAM, 16 )
-// AM_RANGE(0x000000, 0x03ffff) AM_ROM
-//ADDRESS_MAP_END
+/* Sound CPU */
+static ADDRESS_MAP_START( sound_map, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0x000000, 0x03ffff) AM_ROM
+ AM_RANGE(0x081000, 0x081fff) AM_RAM
+ AM_RANGE(0x140000, 0x140001) AM_READ(sound_resetmain_r) /* Ping M0's reset line */
+ AM_RANGE(0x180000, 0x180001) AM_RAM AM_SHARE(4) /* M1<-M0 */
+ AM_RANGE(0x1C0000, 0x1C0001) AM_RAM AM_SHARE(5) /* M1->M0 */
+ADDRESS_MAP_END
static MACHINE_RESET( vcombat )
{
/* Setup the Bt476 VGA RAMDAC palette chip */
tlc34076_reset(6);
+
+ i860_set_pin(cputag_get_cpu(machine, "vid_0")->token, DEC_PIN_BUS_HOLD, 1);
+ i860_set_pin(cputag_get_cpu(machine, "vid_1")->token, DEC_PIN_BUS_HOLD, 1);
}
+static MACHINE_RESET( shadfgtr )
+{
+ /* Setup the Bt476 VGA RAMDAC palette chip */
+ tlc34076_reset(6);
+
+ i860_set_pin(cputag_get_cpu(machine, "vid_0")->token, DEC_PIN_BUS_HOLD, 1);
+}
+
+
static DIRECT_UPDATE_HANDLER( vid_0_direct_handler )
{
if (address >= 0xfffc0000 && address <= 0xffffffff)
@@ -152,6 +387,7 @@ static DIRECT_UPDATE_HANDLER( vid_1_direct_handler )
return address;
}
+
static DRIVER_INIT( vcombat )
{
UINT8 *ROM = memory_region(machine, "main");
@@ -160,89 +396,133 @@ static DRIVER_INIT( vcombat )
memory_set_direct_update_handler(cputag_get_address_space(machine, "vid_0", ADDRESS_SPACE_PROGRAM), vid_0_direct_handler);
memory_set_direct_update_handler(cputag_get_address_space(machine, "vid_1", ADDRESS_SPACE_PROGRAM), vid_1_direct_handler);
- // Hacks
- // pc==4016 : jump 4038 ... There's something strange about how it waits at 402e (interrupts all masked out)
+ /* Allocate the two framebuffers */
+ framebuffer_main = auto_malloc(0x10000 * sizeof(UINT16));
+ framebuffer_secondary = auto_malloc(0x10000 * sizeof(UINT16));
+
+ /* pc==4016 : jump 4038 ... There's something strange about how it waits at 402e (interrupts all masked out)
+ I think what is happening here is that M0 snags the first time
+ it hits this point based on a counter test just above this
+ instruction. That counter gets updated just past this instruction.
+ However, the only way this can be passed is if the M0 CPU is
+ reset (the IPL=7, but irq 7 is a nop). I am almost sure that M1
+ reads a latch, which resets M0 (probably to ensure M0 and M1 are
+ both alive) and gets passed this snag. I tried to hook up a reset
+ which should work, but asserting the reset line on the m68k doesn't
+ seem to do anything. Maybe the 68k emulator doesn't respond to
+ that, or I didn't do it correctly. But I think that is what needs
+ to be done. But it isn't crucial for emulation. Shadow does not
+ have this snag. */
ROM[0x4017] = 0x66;
+}
- // Sound CPU comm bits
- // pc==40fa : jump 40fc ... 600004 should be -16
- ROM[0x40fb] = 0x67;
- // pc==410e : jump 4110 ... 600004 should be 31
- ROM[0x410f] = 0x67;
+static DRIVER_INIT( shadfgtr )
+{
+ /* Allocate just one framebuffer */
+ framebuffer_main = auto_malloc(0x10000 * sizeof(UINT16));
+ framebuffer_secondary = NULL;
- // pc==e220 : jump e222 ... 20119a should not be 0. (no interrupts masked)
- // TODO: I wonder if this is an input bit that's ticked on vblank or something. The menu selection continually crawls up.
+ /* The i860 executes out of RAM */
+ memory_set_direct_update_handler(cputag_get_address_space(machine, "vid_0", ADDRESS_SPACE_PROGRAM), vid_0_direct_handler);
}
static INPUT_PORTS_START( vcombat )
+ PORT_START("IN0")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) /* Left button */
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) /* Right button */
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_4WAY
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_4WAY
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN )
+
+ PORT_START("IN1")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN2 )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_SERVICE )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN )
INPUT_PORTS_END
-static VIDEO_UPDATE( vcombat )
-{
- int x, y;
- int count = 0;
- const rgb_t *pens = tlc34076_get_pens();
+static INPUT_PORTS_START( shadfgtr )
+ PORT_START("IN0")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_4WAY
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_4WAY /* ? */
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_4WAY /* ? */
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_4WAY
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN )
+
+ PORT_START("IN1")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN2 )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START1 )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_START2 )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_SERVICE )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN )
+INPUT_PORTS_END
- for(y = 0; y < 480; y++)
- {
- for(x = 0; x < 256; x++)
- {
- UINT32 color;
- if (x % 2) color = (framebuffer[count] & 0xff00) >> 8;
- else color = framebuffer[count] & 0x00ff;
+static MACHINE_DRIVER_START( vcombat )
+ MDRV_CPU_ADD("main", M68000, XTAL_12MHz)
+ MDRV_CPU_PROGRAM_MAP(main_map,0)
+ MDRV_CPU_VBLANK_INT("main", irq1_line_assert)
- if(x < video_screen_get_visible_area(screen)->max_x && y < video_screen_get_visible_area(screen)->max_y)
- *BITMAP_ADDR32(bitmap, y, x) = pens[color];
+ /* The middle board i860 */
+ MDRV_CPU_ADD("vid_0", I860, XTAL_20MHz)
+ MDRV_CPU_PROGRAM_MAP(vid_0_map,0)
- if (x % 2) count++;
- }
- }
- return 0;
-}
+ /* The top board i860 */
+ MDRV_CPU_ADD("vid_1", I860, XTAL_20MHz)
+ MDRV_CPU_PROGRAM_MAP(vid_1_map,0)
+ /* Sound CPU */
+ MDRV_CPU_ADD("sound", M68000, XTAL_12MHz)
+ MDRV_CPU_PROGRAM_MAP(sound_map,0)
-// This is just here to show that there is text in the main program ROM. It probably won't really be a useful decode.
-static const gfx_layout vcombat_charlayout =
-{
- 8, 8,
- 0x100000 / 0x80,
- 8,
- { 0,1,2,3,4,5,6,7 },
- { 0*16, 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16 },
- { 0*16*8, 1*16*8, 2*16*8, 3*16*8, 4*16*8, 5*16*8, 6*16*8, 7*16*8 },
- 8 * 0x80
-};
+ MDRV_MACHINE_RESET(vcombat)
+/* Temporary hack for experimenting with timing. */
+#if 0
+ //MDRV_QUANTUM_TIME(HZ(1200))
+ MDRV_QUANTUM_PERFECT_CPU("main")
+#endif
-static GFXDECODE_START( vcombat )
- GFXDECODE_ENTRY( "main", 0, vcombat_charlayout, 0, 256 )
-GFXDECODE_END
+ MDRV_SCREEN_ADD("main", RASTER)
+ MDRV_SCREEN_REFRESH_RATE(50)
+ MDRV_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0))
+ MDRV_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)
+ MDRV_SCREEN_SIZE(640, 480)
+ MDRV_SCREEN_VISIBLE_AREA(0, 640-1, 0, 480-1)
+ MDRV_VIDEO_UPDATE(vcombat)
+MACHINE_DRIVER_END
-static MACHINE_DRIVER_START( vcombat )
+
+static MACHINE_DRIVER_START( shadfgtr )
MDRV_CPU_ADD("main", M68000, XTAL_12MHz)
MDRV_CPU_PROGRAM_MAP(main_map,0)
- //MDRV_CPU_VBLANK_INT("main", irq7_line_hold)
+ MDRV_CPU_VBLANK_INT("main", irq1_line_assert)
/* The middle board i860 */
MDRV_CPU_ADD("vid_0", I860, XTAL_20MHz)
MDRV_CPU_PROGRAM_MAP(vid_0_map,0)
- /* The top board i860 */
- MDRV_CPU_ADD("vid_1", I860, XTAL_20MHz)
- MDRV_CPU_PROGRAM_MAP(vid_1_map,0)
+ /* Sound CPU */
+ MDRV_CPU_ADD("sound", M68000, XTAL_12MHz)
+ MDRV_CPU_PROGRAM_MAP(sound_map,0)
- /* Sound CPU Disabled for now */
- //MDRV_CPU_ADD("sound", M68000, XTAL_12MHz)
- //MDRV_CPU_PROGRAM_MAP(sound_map,0)
-
- MDRV_MACHINE_RESET(vcombat)
-
- // Likely will go away
- MDRV_GFXDECODE(vcombat)
+ MDRV_MACHINE_RESET(shadfgtr)
MDRV_SCREEN_ADD("main", RASTER)
MDRV_SCREEN_REFRESH_RATE(60)
@@ -255,6 +535,9 @@ static MACHINE_DRIVER_START( vcombat )
MACHINE_DRIVER_END
+/* Perhaps add this to the core romload.h file? */
+#define ROM_LOAD64_WORD(name,offset,length,hash) ROMX_LOAD(name, offset, length, hash, ROM_GROUPWORD | ROM_SKIP(6))
+
ROM_START( vcombat )
ROM_REGION( 0x100000, "main", 0 )
ROM_LOAD16_BYTE( "ep8v2.b49", 0x00000, 0x80000, CRC(98d5a45d) SHA1(099e314f11c93ad6e642ceaa311e2a5b6fd7193c) )
@@ -270,15 +553,15 @@ ROM_START( vcombat )
ROM_LOAD16_BYTE( "ep3v2.b40", 0x100000, 0x40000, CRC(8c491526) SHA1(95c6bcbe0adcfffb12fd2b86c9f4ca26aa188bbf) )
ROM_LOAD16_BYTE( "ep5v2.b36", 0x100001, 0x40000, CRC(7592b2eb) SHA1(92a540726306d7adbf207fe86a4c4fa66958f90b) )
- ROM_REGION( 0x800, "user1", 0 ) /* The SRAM module */
+ ROM_REGION( 0x800, "user1", 0 ) /* The SRAM module */
ROM_LOAD( "ds1220y.b53", 0x000, 0x800, CRC(b21cfe5f) SHA1(898ace3cd0913ea4b0dc84320219777773ef856f) )
/* These roms are identical on both of the upper boards */
- ROM_REGION( 0x200000, "3d", 0 )
- ROM_LOAD16_BYTE( "11.u56", 0x000000, 0x80000, CRC(a83094ce) SHA1(c3512375fecdb5e7eb02a4aa140ae4efe0233cb8) )
- ROM_LOAD16_BYTE( "9.u54", 0x000001, 0x80000, CRC(a276e18b) SHA1(6d60e519196a4858b82241504592413df498e12f) )
- ROM_LOAD16_BYTE( "12.u57", 0x100000, 0x80000, CRC(0cdffd4f) SHA1(65ace78711b3ef6e0ff9a7ad7343b5558e652f6c) )
- ROM_LOAD16_BYTE( "10.u55", 0x100001, 0x80000, CRC(8921f20e) SHA1(6e9ca2eaad3e1108ba0e1d7792fd5d0305bec201) )
+ ROM_REGION( 0x200000, "gfx", 0 )
+ ROM_LOAD64_WORD( "9.u55", 0x000000, 0x80000, CRC(a276e18b) SHA1(6d60e519196a4858b82241504592413df498e12f) )
+ ROM_LOAD64_WORD( "10.u57", 0x000002, 0x80000, CRC(8921f20e) SHA1(6e9ca2eaad3e1108ba0e1d7792fd5d0305bec201) )
+ ROM_LOAD64_WORD( "11.u54", 0x000004, 0x80000, CRC(a83094ce) SHA1(c3512375fecdb5e7eb02a4aa140ae4efe0233cb8) )
+ ROM_LOAD64_WORD( "12.u56", 0x000006, 0x80000, CRC(0cdffd4f) SHA1(65ace78711b3ef6e0ff9a7ad7343b5558e652f6c) )
ROM_REGION( 0x400, "plds", 0 )
ROM_LOAD( "pal1_w2.u51", 0x000, 0x1f1, CRC(af497420) SHA1(03aa82189d91ae194dd5a6e7b9dbdb7cd473ddb6) )
@@ -301,18 +584,17 @@ ROM_START( shadfgtr )
ROM_REGION( 0x800, "user1", 0 ) /* The SRAM module */
ROM_LOAD( "shadfgtr.b53", 0x000, 0x800, CRC(e766a3ab) SHA1(e7696ec08d5c86f64d768480f43edbd19ded162d) )
- /* These roms are identical on both of the upper boards */
- ROM_REGION( 0x200000, "3d", 0 )
- ROM_LOAD16_BYTE( "shadfgtr.u56", 0x000000, 0x80000, CRC(fb76db5a) SHA1(fa546f465df113c13037abed1162bfa6f9b1dc9b) )
- ROM_LOAD16_BYTE( "shadfgtr.u54", 0x000001, 0x80000, CRC(c45d68d6) SHA1(a133e4f13d3af18bccf0d060a659d64ac699b159) )
- ROM_LOAD16_BYTE( "shadfgtr.u57", 0x100000, 0x80000, CRC(60d701d7) SHA1(936473b5e3b2e9e9e3b50cf977fc5a670a097850) )
- ROM_LOAD16_BYTE( "shadfgtr.u55", 0x100001, 0x80000, CRC(e807631d) SHA1(9027ff7dc60b808434dac292c08f0630d3d52186) )
+ ROM_REGION( 0x200000, "gfx", 0 )
+ ROM_LOAD64_WORD( "shadfgtr.u55", 0x000000, 0x80000, CRC(e807631d) SHA1(9027ff7dc60b808434dac292c08f0630d3d52186) )
+ ROM_LOAD64_WORD( "shadfgtr.u57", 0x000002, 0x80000, CRC(60d701d7) SHA1(936473b5e3b2e9e9e3b50cf977fc5a670a097850) )
+ ROM_LOAD64_WORD( "shadfgtr.u54", 0x000004, 0x80000, CRC(c45d68d6) SHA1(a133e4f13d3af18bccf0d060a659d64ac699b159) )
+ ROM_LOAD64_WORD( "shadfgtr.u56", 0x000006, 0x80000, CRC(fb76db5a) SHA1(fa546f465df113c13037abed1162bfa6f9b1dc9b) )
ROM_REGION( 0x200, "plds", 0 )
ROM_LOAD( "shadfgtr.u51", 0x000, 0x1f1, CRC(bab58337) SHA1(c4a79c8e53aeadb7f64d49d214b607b5b36f144e) )
/* The second upper-board PAL couldn't be read */
ROM_END
-/* YEAR NAME PARENT MACHINE INPUT INIT MONITOR COMPANY FULLNAME FLAGS */
-GAME( 1993, vcombat, 0, vcombat, vcombat, vcombat, ROT0, "VR8 Inc.", "Virtual Combat", GAME_NOT_WORKING | GAME_NO_SOUND )
-GAME( 1989, shadfgtr, 0, vcombat, vcombat, 0, ROT0, "Sega?", "Shadow Fighters", GAME_NOT_WORKING | GAME_NO_SOUND )
+/* YEAR NAME PARENT MACHINE INPUT INIT MONITOR COMPANY FULLNAME FLAGS */
+GAME( 1993, vcombat, 0, vcombat, vcombat, vcombat, ORIENTATION_FLIP_X, "VR8 Inc.", "Virtual Combat", GAME_NOT_WORKING | GAME_NO_SOUND )
+GAME( 1989, shadfgtr, 0, shadfgtr, shadfgtr, shadfgtr, ROT0, "DUTECH Inc.", "Shadow Fighters", GAME_NOT_WORKING | GAME_NO_SOUND )
diff --git a/src/mame/mamedriv.c b/src/mame/mamedriv.c
index e7f988131e9..dc3f397a89b 100644
--- a/src/mame/mamedriv.c
+++ b/src/mame/mamedriv.c
@@ -8433,7 +8433,7 @@ Other Sun games
DRIVER( blazlaz ) /* (c) 1989 Hudson Soft */
DRIVER( paranoia ) /* (c) 1990 Naxat Soft */
DRIVER( vcombat ) /* (c) 1993 VR8 Inc. */
- DRIVER( shadfgtr ) /* (c) 1989 Sega? */
+ DRIVER( shadfgtr ) /* (c) 1989 DUTECH Inc. */
DRIVER( blackt96 ) /* (c) 1996 D.G.R.M. of Korea */
DRIVER( magictg ) /* (c) 199? Acclaim */
DRIVER( magictga ) /* (c) 199? Acclaim */