_T("Spectrum28/24_Z2"), _T("Spectrum28/24_Z3"),
_T("PicassoIV_Z2"), _T("PicassoIV_Z3"),
0 };
-static const TCHAR *cpuboards[] = { _T("none"), _T("Blizzard1230IV"), _T("Blizzard1260"), _T("Blizzard2060"), _T("WarpEngineA4000"), NULL };
+static const TCHAR *cpuboards[] = { _T("none"), _T("Blizzard1230IV"), _T("Blizzard1260"), _T("Blizzard2060"), _T("CyberStormMK3"), _T("CyberStormPPC"), _T("BlizzardPPC"), _T("WarpEngineA4000"), NULL };
static const TCHAR *waitblits[] = { _T("disabled"), _T("automatic"), _T("noidleonly"), _T("always"), 0 };
static const TCHAR *autoext2[] = { _T("disabled"), _T("copy"), _T("replace"), 0 };
static const TCHAR *leds[] = { _T("power"), _T("df0"), _T("df1"), _T("df2"), _T("df3"), _T("hd"), _T("cd"), _T("fps"), _T("cpu"), _T("snd"), _T("md"), 0 };
_T("uae"),
_T("ide%d"),
_T("scsi%d"), _T("scsi%d_a2091"), _T("scsi%d_a2091-2"), _T("scsi%d_a4091"), _T("scsi%d_a4091-2"),
- _T("scsi%d_a3000"), _T("scsi%d_a4000t"), _T("scsi%d_cdtv"), _T("scsi%d_warpengine"),
+ _T("scsi%d_a3000"), _T("scsi%d_a4000t"), _T("scsi%d_cdtv"), _T("scsi%d_cpuboard"),
_T("scsram"), _T("scide")
};
static const TCHAR *obsolete[] = {
cfgfile_write_bool (f, _T("comp_nf"), p->compnf);
cfgfile_write_bool (f, _T("comp_constjump"), p->comp_constjump);
cfgfile_write_bool (f, _T("comp_oldsegv"), p->comp_oldsegv);
-
cfgfile_write_str (f, _T("comp_flushmode"), flushmode[p->comp_hardflush]);
cfgfile_write_bool (f, _T("compfpu"), p->compfpu);
- cfgfile_write_bool (f, _T("fpu_strict"), p->fpu_strict);
cfgfile_write_bool (f, _T("comp_midopt"), p->comp_midopt);
cfgfile_write_bool (f, _T("comp_lowopt"), p->comp_lowopt);
cfgfile_write_bool (f, _T("avoid_cmov"), p->avoid_cmov);
cfgfile_write_bool (f, _T("cycle_exact"), p->cpu_cycle_exact && p->blitter_cycle_exact ? 1 : 0);
cfgfile_dwrite_bool (f, _T("fpu_no_unimplemented"), p->fpu_no_unimplemented);
cfgfile_dwrite_bool (f, _T("cpu_no_unimplemented"), p->int_no_unimplemented);
+ cfgfile_write_bool (f, _T("fpu_strict"), p->fpu_strict);
+ cfgfile_dwrite_bool (f, _T("fpu_softfloat"), p->fpu_softfloat);
cfgfile_write_bool (f, _T("rtg_nocustom"), p->picasso96_nocustom);
cfgfile_write (f, _T("rtg_modes"), _T("0x%x"), p->picasso96_modeflags);
hdcv = HD_CONTROLLER_TYPE_SCSI_A4000T;
if (!_tcsicmp(ext, _T("cdtv")))
hdcv = HD_CONTROLLER_TYPE_SCSI_CDTV;
- if (!_tcsicmp(ext, _T("warpengine")))
- hdcv = HD_CONTROLLER_TYPE_SCSI_WARPENGINE;
+ if (!_tcsicmp(ext, _T("cpuboard")))
+ hdcv = HD_CONTROLLER_TYPE_SCSI_CPUBOARD;
}
} else if (_tcslen (hdc) >= 6 && !_tcsncmp (hdc, _T("scsram"), 6)) {
hdcv = HD_CONTROLLER_TYPE_PCMCIA_SRAM;
|| cfgfile_yesno (option, value, _T("serial_on_demand"), &p->serial_demand)
|| cfgfile_yesno (option, value, _T("serial_hardware_ctsrts"), &p->serial_hwctsrts)
|| cfgfile_yesno (option, value, _T("serial_direct"), &p->serial_direct)
+ || cfgfile_yesno (option, value, _T("fpu_strict"), &p->fpu_strict)
+ || cfgfile_yesno (option, value, _T("fpu_softfloat"), &p->fpu_softfloat)
|| cfgfile_yesno (option, value, _T("comp_nf"), &p->compnf)
|| cfgfile_yesno (option, value, _T("comp_constjump"), &p->comp_constjump)
|| cfgfile_yesno (option, value, _T("comp_oldsegv"), &p->comp_oldsegv)
|| cfgfile_yesno (option, value, _T("compforcesettings"), &dummybool)
|| cfgfile_yesno (option, value, _T("compfpu"), &p->compfpu)
- || cfgfile_yesno (option, value, _T("fpu_strict"), &p->fpu_strict)
|| cfgfile_yesno (option, value, _T("comp_midopt"), &p->comp_midopt)
|| cfgfile_yesno (option, value, _T("comp_lowopt"), &p->comp_lowopt)
|| cfgfile_yesno (option, value, _T("rtg_nocustom"), &p->picasso96_nocustom)
p->comp_constjump = 1;
p->comp_oldsegv = 0;
p->compfpu = 1;
- p->fpu_strict = 0;
p->cachesize = 0;
p->avoid_cmov = 0;
p->comp_midopt = 0;
p->fpu_revision = 0;
p->fpu_no_unimplemented = false;
p->int_no_unimplemented = false;
+ p->fpu_strict = 0;
+ p->fpu_softfloat = 0;
p->m68k_speed = 0;
p->cpu_compatible = 1;
p->address_space_24 = 1;
#include "cpuboard.h"
#include "custom.h"
#include "newcpu.h"
+#include "ncr_scsi.h"
+#include "debug.h"
+#include "flashrom.h"
+#include "uae.h"
+
+#define F0_WAITSTATES (2 * CYCLE_UNIT)
+
+// CS MK3
+#define CYBERSTORM_MAPROM_BASE 0xfff00000
+#define CSIII_NCR 0xf40000
+#define CSIII_BASE 0xf60000
+#define CSIII_REG_RESET 0x00 // 0x00
+#define CSIII_REG_IRQ 0x01 // 0x08
+#define CSIII_REG_WAITSTATE 0x02 // 0x10
+#define CSIII_REG_SHADOW 0x03 // 0x18
+#define CSIII_REG_LOCK 0x04 // 0x20
+#define CSIII_REG_INT 0x05 // 0x28
+#define CSIII_IPL_EMU 0x06 // 0x30
+#define CSIII_INT_LVL 0x07 // 0x38
+#define BPPC_MAGIC 0x13
+
+/* bit definitions */
+#define P5_SET_CLEAR 0x80
+/* REQ_RESET */
+#define P5_PPC_RESET 0x10
+#define P5_M68K_RESET 0x08
+#define P5_AMIGA_RESET 0x04
+#define P5_AUX_RESET 0x02
+#define P5_SCSI_RESET 0x01
+/* REG_WAITSTATE */
+#define P5_PPC_WRITE 0x08
+#define P5_PPC_READ 0x04
+#define P5_M68K_WRITE 0x02
+#define P5_M68K_READ 0x01
+/* REG_SHADOW */
+#define P5_SELF_RESET 0x40
+#define P5_SHADOW 0x01
+/* REG_LOCK */
+#define P5_MAGIC1 0x60
+#define P5_MAGIC2 0x50
+#define P5_MAGIC3 0x30
+#define P5_MAGIC4 0x70
+/* REG_INT */
+#define P5_ENABLE_IPL 0x02
+#define P5_INT_MASTER 0x01
+/* IPL_EMU */
+#define P5_DISABLE_INT 0x40
+#define P5_M68K_IPL2 0x20
+#define P5_M68K_IPL1 0x10
+#define P5_M68K_IPL0 0x08
+#define P5_PPC_IPL2 0x04
+#define P5_PPC_IPL1 0x02
+#define P5_PPC_IPL0 0x01
+#define P5_IPL_MASK 0x07
+/* INT_LVL */
+#define P5_LVL7 0x40
+#define P5_LVL6 0x20
+#define P5_LVL5 0x10
+#define P5_LVL4 0x08
+#define P5_LVL3 0x04
+#define P5_LVL2 0x02
+#define P5_LVL1 0x01
+
+#define CS_RAM_BASE 0x0c000000
#define BLIZZARD_RAM_BASE 0x68000000
#define BLIZZARD_RAM_ALIAS_BASE 0x48000000
static uae_u32 maprom_base;
static int delayed_rom_protect;
static int f0rom_size, earom_size;
+static uae_u8 io_reg[64];
+static void *flashrom;
+static struct zfile *flashrom_file;
+static int flash_unlocked;
static bool is_blizzard(void)
{
return currprefs.cpuboard_type == BOARD_BLIZZARD_1230_IV || currprefs.cpuboard_type == BOARD_BLIZZARD_1260 || currprefs.cpuboard_type == BOARD_BLIZZARD_2060;
}
+static bool is_cs(void)
+{
+ return currprefs.cpuboard_type == BOARD_CSMK3 || currprefs.cpuboard_type == BOARD_CSPPC;
+}
+static bool is_blizzardppc(void)
+{
+ return currprefs.cpuboard_type == BOARD_BLIZZARDPPC;
+}
extern addrbank blizzardram_bank;
extern addrbank blizzardram_nojit_bank;
addrbank blizzardram_bank = {
blizzardram_lget, blizzardram_wget, blizzardram_bget,
blizzardram_lput, blizzardram_wput, blizzardram_bput,
- blizzardram_xlate, blizzardram_check, NULL, _T("Blizzard RAM"),
+ blizzardram_xlate, blizzardram_check, NULL, _T("CPUBoard RAM"),
blizzardram_lget, blizzardram_wget, ABFLAG_RAM
};
static addrbank blizzardram_nojit_bank = {
blizzardram_nojit_lget, blizzardram_nojit_wget, blizzardram_nojit_bget,
blizzardram_nojit_lput, blizzardram_nojit_wput, blizzardram_nojit_bput,
- blizzardram_nojit_xlate, blizzardram_nojit_check, NULL, _T("Blizzard RAM"),
+ blizzardram_nojit_xlate, blizzardram_nojit_check, NULL, _T("CPUBoard RAM"),
blizzardram_nojit_lget, blizzardram_nojit_wget, ABFLAG_RAM
};
kickmem_bank.baseaddr[addr] = b;
}
}
+
static addrbank blizzardmaprom_bank = {
blizzardmaprom_lget, blizzardmaprom_wget, blizzardmaprom_bget,
blizzardmaprom_lput, blizzardmaprom_wput, blizzardmaprom_bput,
- blizzardmaprom_xlate, blizzardmaprom_check, NULL, _T("Blizzard MAPROM"),
+ blizzardmaprom_xlate, blizzardmaprom_check, NULL, _T("CPUBoard MAPROM"),
blizzardmaprom_lget, blizzardmaprom_wget, ABFLAG_RAM
};
blizzarde8_lget, blizzarde8_wget, ABFLAG_IO | ABFLAG_SAFE
};
-// Blizzard F0 ROM is really slow, shoud slow it down to see color flashing..
-
static uae_u32 REGPARAM2 blizzardf0_lget(uaecptr addr)
{
#ifdef JIT
#endif
uae_u32 *m;
+ regs.memory_waitstate_cycles += F0_WAITSTATES * 6;
+
+ if (is_blizzardppc() && (flash_unlocked & 2))
+ addr += 262144;
+
addr &= blizzardf0_bank.mask;
m = (uae_u32 *)(blizzardf0_bank.baseaddr + addr);
return do_get_mem_long(m);
#endif
uae_u16 *m, v;
+ regs.memory_waitstate_cycles += F0_WAITSTATES * 3;
+
+ if (is_blizzardppc() && (flash_unlocked & 2))
+ addr += 262144;
+
addr &= blizzardf0_bank.mask;
m = (uae_u16 *)(blizzardf0_bank.baseaddr + addr);
v = do_get_mem_word(m);
special_mem |= S_READ;
#endif
uae_u8 v;
+
+ regs.memory_waitstate_cycles += F0_WAITSTATES * 1;
+
+ if (is_cs() || is_blizzardppc()) {
+ if (is_blizzardppc() && (flash_unlocked & 2))
+ addr += 262144;
+ if (flash_unlocked) {
+ return flash_read(flashrom, addr);
+ }
+ }
addr &= blizzardf0_bank.mask;
v = blizzardf0_bank.baseaddr[addr];
return v;
}
+// hack to map F41000 SCSI SCRIPTS RAM to JIT friendly address
+void cyberstorm_scsi_ram_put(uaecptr addr, uae_u32 v)
+{
+ addr &= 0xffff;
+ addr += (CSIII_NCR & 0x7ffff);
+ blizzardf0_bank.baseaddr[addr] = v;
+}
+uae_u32 cyberstorm_scsi_ram_get(uaecptr addr)
+{
+ uae_u32 v;
+ addr &= 0xffff;
+ addr += (CSIII_NCR & 0x7ffff);
+ v = blizzardf0_bank.baseaddr[addr];
+ return v;
+}
+uae_u8 *REGPARAM2 cyberstorm_scsi_ram_xlate (uaecptr addr)
+{
+ addr &= 0xffff;
+ addr += (CSIII_NCR & 0x7ffff);
+ return blizzardf0_bank.baseaddr + addr;
+}
+int REGPARAM2 cyberstorm_scsi_ram_check (uaecptr a, uae_u32 b)
+{
+ a &= 0xffff;
+ return a >= 0x1000 && a + b < 0x3000;
+}
+
+static void REGPARAM2 blizzardf0_lput(uaecptr addr, uae_u32 b)
+{
+#ifdef JIT
+ special_mem |= S_WRITE;
+#endif
+ regs.memory_waitstate_cycles += F0_WAITSTATES * 6;
+}
+static void REGPARAM2 blizzardf0_wput(uaecptr addr, uae_u32 b)
+{
+#ifdef JIT
+ special_mem |= S_WRITE;
+#endif
+ regs.memory_waitstate_cycles += F0_WAITSTATES * 3;
+}
+static void REGPARAM2 blizzardf0_bput(uaecptr addr, uae_u32 b)
+{
+#ifdef JIT
+ special_mem |= S_WRITE;
+#endif
+ regs.memory_waitstate_cycles += F0_WAITSTATES * 1;
+
+ if (is_cs() || is_blizzardppc()) {
+ if (flash_unlocked) {
+ if (is_blizzardppc() && (flash_unlocked & 2))
+ addr += 262144;
+ flash_write(flashrom, addr, b);
+ }
+ }
+}
+
MEMORY_CHECK(blizzardf0);
MEMORY_XLATE(blizzardf0);
static addrbank blizzardf0_bank = {
blizzardf0_lget, blizzardf0_wget, blizzardf0_bget,
- blizzardea_lput, blizzardea_wput, blizzardea_bput,
- blizzardf0_xlate, blizzardf0_check, NULL, _T("Blizzard F00000"),
+ blizzardf0_lput, blizzardf0_wput, blizzardf0_bput,
+ blizzardf0_xlate, blizzardf0_check, NULL, _T("CPUBoard F00000"),
blizzardf0_lget, blizzardf0_wget, ABFLAG_ROM
};
return v;
}
-static void copymaprom(void)
+static void blizzard_copymaprom(void)
{
uae_u8 *src = get_real_address(BLIZZARD_MAPROM_BASE);
uae_u8 *dst = get_real_address(0xf80000);
memcpy(dst, src, 524288);
protect_roms(true);
}
+static void cyberstorm_copymaprom(void)
+{
+ if (blizzardmaprom_bank.baseaddr) {
+ uae_u8 *src = blizzardmaprom_bank.baseaddr;
+ uae_u8 *dst = get_real_address(0xf80000);
+ protect_roms(false);
+ memcpy(dst, src, 524288);
+ protect_roms(true);
+ }
+}
+
+void cpuboard_rethink(void)
+{
+ if (is_cs() || is_blizzardppc()) {
+ if (!(io_reg[CSIII_REG_IRQ] & 3))
+ INTREQ(0x8000 | 0x0008);
+ }
+}
+
+static void cyberstorm_maprom(void)
+{
+ map_banks(&blizzardmaprom_bank, CYBERSTORM_MAPROM_BASE >> 16, 524288 >> 16, 0);
+}
+
+void cyberstorm_irq(int level)
+{
+ if (level)
+ io_reg[CSIII_REG_IRQ] &= ~1;
+ else
+ io_reg[CSIII_REG_IRQ] |= 1;
+ cpuboard_rethink();
+}
+
+void blizzardppc_irq(int level)
+{
+ if (level)
+ io_reg[CSIII_REG_IRQ] &= ~1;
+ else
+ io_reg[CSIII_REG_IRQ] |= 1;
+ cpuboard_rethink();
+}
+
static uae_u32 REGPARAM2 blizzardio_bget(uaecptr addr)
{
+ uae_u8 v = 0;
+#ifdef JIT
+ special_mem |= S_READ;
+#endif
+ if (is_cs() || is_blizzardppc()) {
+ uae_u32 bank = addr & 0x10000;
+ if (bank == 0) {
+ int reg = (addr & 0xff) / 8;
+ v = io_reg[reg];
+ if (reg == CSIII_REG_LOCK && is_blizzardppc())
+ v |= 0x08;
+ if (reg != CSIII_REG_IRQ)
+ write_log(_T("CS IO BGET %08x=%02X PC=%08x\n"), addr, v & 0xff, M68K_GETPC);
+ } else {
+ write_log(_T("CS IO BGET %08x=%02X PC=%08x\n"), addr, v & 0xff, M68K_GETPC);
+ }
+ }
+ return v;
+}
+static uae_u32 REGPARAM2 blizzardio_wget(uaecptr addr)
+{
+#ifdef JIT
+ special_mem |= S_READ;
+#endif
+ if (is_cs() || is_blizzardppc()) {
+ ;//write_log(_T("CS IO WGET %08x\n"), addr);
+ //activate_debugger();
+ }
+ return 0;
+}
+static uae_u32 REGPARAM2 blizzardio_lget(uaecptr addr)
+{
+#ifdef JIT
+ special_mem |= S_READ;
+#endif
+ if (is_cs() || is_blizzardppc()) {
+ write_log(_T("CS IO LGET %08x PC=%08x\n"), addr, M68K_GETPC);
+ //activate_debugger();
+ }
return 0;
}
static void REGPARAM2 blizzardio_bput(uaecptr addr, uae_u32 v)
{
- if ((addr & 65535) == (BLIZZARD_MAPROM_ENABLE & 65535)) {
- if (v != 0x42 || maprom_state || !currprefs.maprom)
- return;
- maprom_state = 1;
- write_log(_T("Blizzard MAPROM enabled\n"));
- copymaprom();
+#ifdef JIT
+ special_mem |= S_WRITE;
+#endif
+ if (is_blizzard()) {
+ if ((addr & 65535) == (BLIZZARD_MAPROM_ENABLE & 65535)) {
+ if (v != 0x42 || maprom_state || !currprefs.maprom)
+ return;
+ maprom_state = 1;
+ write_log(_T("Blizzard MAPROM enabled\n"));
+ blizzard_copymaprom();
+ }
+ } else if (is_cs() || is_blizzardppc()) {
+ write_log(_T("CS IO BPUT %08x %02x PC=%08x\n"), addr, v & 0xff, M68K_GETPC);
+ uae_u32 bank = addr & 0x10000;
+ if (bank == 0) {
+ addr &= 0xff;
+ if (is_blizzardppc()) {
+ if (addr == 0x92 && v == 0x42)
+ flash_unlocked |= 1;
+ if (addr == 0x93)
+ flash_unlocked &= ~1;
+ if (addr == 0x12) {
+ maprom_state = 1;
+ cyberstorm_copymaprom();
+ }
+ }
+ addr /= 8;
+ uae_u8 oldval = io_reg[addr];
+ if (addr == CSIII_REG_LOCK) {
+ if (v == P5_MAGIC1)
+ io_reg[CSIII_REG_LOCK] = v;
+ else if (v == P5_MAGIC2 && io_reg[CSIII_REG_LOCK] == P5_MAGIC1)
+ io_reg[CSIII_REG_LOCK] = v;
+ else if (v == P5_MAGIC3 && io_reg[CSIII_REG_LOCK] == P5_MAGIC2)
+ io_reg[CSIII_REG_LOCK] = v;
+ else if (v == P5_MAGIC4 && io_reg[CSIII_REG_LOCK] == P5_MAGIC3)
+ io_reg[CSIII_REG_LOCK] = v;
+ else
+ io_reg[CSIII_REG_LOCK] = 0;
+ if (io_reg[CSIII_REG_LOCK] == P5_MAGIC3)
+ flash_unlocked |= 2;
+ else
+ flash_unlocked &= ~2;
+ } else {
+ uae_u32 regval;
+ if (addr == CSIII_REG_SHADOW && io_reg[CSIII_REG_LOCK] != P5_MAGIC3)
+ return;
+ if (v & 0x80)
+ io_reg[addr] |= v & 0x7f;
+ else
+ io_reg[addr] &= ~v;
+ regval = io_reg[addr];
+ if (addr == CSIII_REG_RESET) {
+ if (regval & P5_SCSI_RESET) {
+ if (is_blizzardppc())
+ map_banks(&ncr_bank_blizzardppc, 0xf40000 >> 16, 65536 >> 16, 0);
+ else
+ map_banks(&ncr_bank_cyberstorm, 0xf40000 >> 16, 65536 >> 16, 0);
+ } else {
+ map_banks(&dummy_bank, 0xf40000 >> 16, 65536 >> 16, 0);
+ }
+ if (!(regval & P5_AMIGA_RESET)) {
+ uae_reset(0, 0);
+ io_reg[addr] |= P5_AMIGA_RESET;
+ }
+ if (!(regval & P5_M68K_RESET)) {
+ m68k_reset();
+ io_reg[addr] |= P5_M68K_RESET;
+ }
+ } else if (addr == CSIII_REG_SHADOW) {
+ if (is_cs() && ((oldval ^ regval) & 1)) {
+ maprom_state = (regval & 1) ? 0 : 1;
+ cyberstorm_copymaprom();
+ }
+ }
+ cpuboard_rethink();
+ }
+ }
}
}
static void REGPARAM2 blizzardio_wput(uaecptr addr, uae_u32 v)
{
- if((addr & 65535) == (BLIZZARD_BOARD_DISABLE & 65535)) {
- if (v != 0xcafe)
- return;
- write_log(_T("Blizzard board disable!\n"));
- cpu_halt(4); // not much choice..
+#ifdef JIT
+ special_mem |= S_WRITE;
+#endif
+ if (is_blizzard()) {
+ if((addr & 65535) == (BLIZZARD_BOARD_DISABLE & 65535)) {
+ if (v != 0xcafe)
+ return;
+ write_log(_T("Blizzard board disable!\n"));
+ cpu_halt(4); // not much choice..
+ }
+ } else if (is_cs() || is_blizzardppc()) {
+ write_log(_T("CS IO WPUT %08x %04x\n"), addr, v);
+ }
+}
+static void REGPARAM2 blizzardio_lput(uaecptr addr, uae_u32 v)
+{
+#ifdef JIT
+ special_mem |= S_WRITE;
+#endif
+ if (is_cs() || is_blizzardppc()) {
+ write_log(_T("CS IO LPUT %08x %08x\n"), addr, v);
}
}
-
static addrbank blizzardio_bank = {
- blizzardio_bget, blizzardio_bget, blizzardio_bget,
- blizzardio_wput, blizzardio_wput, blizzardio_bput,
- default_xlate, default_check, NULL, _T("Blizzard IO"),
- blizzardio_bget, blizzardio_bget, ABFLAG_IO
+ blizzardio_lget, blizzardio_wget, blizzardio_bget,
+ blizzardio_lput, blizzardio_wput, blizzardio_bput,
+ default_xlate, default_check, NULL, _T("CPUBoard IO"),
+ blizzardio_wget, blizzardio_bget, ABFLAG_IO
};
void cpuboard_vsync(void)
{
if (!currprefs.cpuboard_type)
return;
- if (cpuboard_size) {
- if (blizzard_jit) {
- map_banks(&blizzardram_bank, blizzardram_bank.start >> 16, cpuboard_size >> 16, 0);
- map_banks(&blizzardram_bank, BLIZZARD_RAM_BASE >> 16, cpuboard_size >> 16, 0);
- } else {
- for (int i = 0; i < 0x08000000; i += cpuboard_size) {
- map_banks_nojitdirect(&blizzardram_nojit_bank, (BLIZZARD_RAM_ALIAS_BASE + i) >> 16, cpuboard_size >> 16, 0);
- map_banks_nojitdirect(&blizzardram_nojit_bank, (BLIZZARD_RAM_BASE + i) >> 16, cpuboard_size >> 16, 0);
- }
- if (currprefs.maprom) {
+ if (is_blizzard() || is_blizzardppc()) {
+ if (cpuboard_size) {
+ if (blizzard_jit) {
+ map_banks(&blizzardram_bank, blizzardram_bank.start >> 16, cpuboard_size >> 16, 0);
+ map_banks(&blizzardram_bank, BLIZZARD_RAM_BASE >> 16, cpuboard_size >> 16, 0);
+ } else {
for (int i = 0; i < 0x08000000; i += cpuboard_size) {
- map_banks_nojitdirect(&blizzardmaprom_bank, (BLIZZARD_RAM_ALIAS_BASE + i + cpuboard_size - 524288) >> 16, 524288 >> 16, 0);
- map_banks_nojitdirect(&blizzardmaprom_bank, (BLIZZARD_RAM_BASE + i + cpuboard_size - 524288) >> 16, 524288 >> 16, 0);
+ map_banks_nojitdirect(&blizzardram_nojit_bank, (BLIZZARD_RAM_ALIAS_BASE + i) >> 16, cpuboard_size >> 16, 0);
+ map_banks_nojitdirect(&blizzardram_nojit_bank, (BLIZZARD_RAM_BASE + i) >> 16, cpuboard_size >> 16, 0);
+ }
+ if (currprefs.maprom && !is_blizzardppc()) {
+ for (int i = 0; i < 0x08000000; i += cpuboard_size) {
+ map_banks_nojitdirect(&blizzardmaprom_bank, (BLIZZARD_RAM_ALIAS_BASE + i + cpuboard_size - 524288) >> 16, 524288 >> 16, 0);
+ map_banks_nojitdirect(&blizzardmaprom_bank, (BLIZZARD_RAM_BASE + i + cpuboard_size - 524288) >> 16, 524288 >> 16, 0);
+ }
}
}
}
+ if (!is_blizzardppc()) {
+ map_banks(&blizzardf0_bank, 0xf00000 >> 16, 65536 >> 16, 0);
+ map_banks(&blizzardio_bank, BLIZZARD_MAPROM_ENABLE >> 16, 65536 >> 16, 0);
+ map_banks(&blizzardio_bank, BLIZZARD_BOARD_DISABLE >> 16, 65536 >> 16, 0);
+ } else {
+ map_banks(&blizzardf0_bank, 0xf00000 >> 16, 0x60000 >> 16, 0);
+ map_banks(&blizzardio_bank, 0xf60000 >> 16, (2 * 65536) >> 16, 0);
+ map_banks(&blizzardf0_bank, 0xf70000 >> 16, 0x10000 >> 16, 0);
+ cyberstorm_maprom();
+ }
}
- if (f0rom_size)
- map_banks(&blizzardf0_bank, 0xf00000 >> 16, f0rom_size >> 16, 0);
- if (is_blizzard()) {
- map_banks(&blizzardio_bank, BLIZZARD_MAPROM_ENABLE >> 16, 65536 >> 16, 0);
- map_banks(&blizzardio_bank, BLIZZARD_BOARD_DISABLE >> 16, 65536 >> 16, 0);
+ if (is_cs()) {
+ map_banks(&blizzardf0_bank, 0xf00000 >> 16, 262144 >> 16, 0);
+ map_banks(&blizzardio_bank, 0xf50000 >> 16, (3 * 65536) >> 16, 0);
+ cyberstorm_maprom();
}
}
void cpuboard_reset(bool hardreset)
{
- canbang = 0;
+ if (is_blizzard() || is_blizzardppc())
+ canbang = 0;
configured = false;
delayed_rom_protect = 0;
currprefs.cpuboardmem1_size = changed_prefs.cpuboardmem1_size;
if (hardreset || !currprefs.maprom)
maprom_state = 0;
+ if (is_cs() || is_blizzardppc()) {
+ if (hardreset)
+ memset(io_reg, 0x7f, sizeof io_reg);
+ io_reg[CSIII_REG_RESET] = 0x7f;
+ io_reg[CSIII_REG_IRQ] = 0x7f;
+ maprom_state = 0;
+ }
+ flash_unlocked = 0;
+
+ flash_free(flashrom);
+ flashrom = NULL;
+ zfile_fclose(flashrom_file);
+ flashrom_file = NULL;
}
void cpuboard_cleanup(void)
configured = false;
maprom_state = 0;
+ flash_free(flashrom);
+ flashrom = NULL;
+ zfile_fclose(flashrom_file);
+ flashrom_file = NULL;
+
if (blizzard_jit) {
mapped_free(blizzardram_bank.baseaddr);
} else {
blizzardea_bank.baseaddr = NULL;
cpuboard_size = cpuboard2_size = -1;
+
}
void cpuboard_init(void)
cpuboard_size = currprefs.cpuboardmem1_size;
- if (is_blizzard()) {
+ if (is_blizzard() || is_blizzardppc()) {
blizzardram_bank.start = BLIZZARD_RAM_ALIAS_BASE;
blizzardram_bank.allocated = cpuboard_size;
blizzardram_bank.mask = blizzardram_bank.allocated - 1;
maprom_base = blizzardram_bank.allocated - 524288;
blizzardf0_bank.start = 0x00f00000;
- blizzardf0_bank.allocated = 262144;
+ blizzardf0_bank.allocated = 524288;
blizzardf0_bank.mask = blizzardf0_bank.allocated - 1;
blizzardf0_bank.baseaddr = mapped_malloc(blizzardf0_bank.allocated, _T("rom_f0"));
- blizzardea_bank.allocated = 2 * 65536;
- blizzardea_bank.mask = blizzardea_bank.allocated - 1;
- // Blizzard 12xx autoconfig ROM must be mapped at $ea0000-$ebffff, board requires it.
- blizzardea_bank.baseaddr = mapped_malloc(blizzardea_bank.allocated, _T("rom_ea"));
+ if (!is_blizzardppc()) {
+ blizzardea_bank.allocated = 2 * 65536;
+ blizzardea_bank.mask = blizzardea_bank.allocated - 1;
+ // Blizzard 12xx autoconfig ROM must be mapped at $ea0000-$ebffff, board requires it.
+ blizzardea_bank.baseaddr = mapped_malloc(blizzardea_bank.allocated, _T("rom_ea"));
+ }
+
+ } else if (is_cs()) {
+
+ blizzardram_bank.start = CS_RAM_BASE;
+ blizzardram_bank.allocated = cpuboard_size;
+ blizzardram_bank.mask = blizzardram_bank.allocated - 1;
+ if (cpuboard_size)
+ blizzardram_bank.baseaddr = mapped_malloc(blizzardram_bank.allocated, _T("cyberstorm"));
+
+ blizzardf0_bank.start = 0x00f00000;
+ blizzardf0_bank.allocated = 524288;
+ blizzardf0_bank.mask = blizzardf0_bank.allocated - 1;
+ blizzardf0_bank.baseaddr = mapped_malloc(blizzardf0_bank.allocated, _T("rom_f0"));
+
+ blizzardmaprom_bank.baseaddr = a3000hmem_bank.baseaddr + a3000hmem_bank.allocated - 524288;
+ blizzardmaprom_bank.start = CYBERSTORM_MAPROM_BASE;
+ blizzardmaprom_bank.allocated = 524288;
+ blizzardmaprom_bank.mask = 524288 - 1;
}
}
{
if (!currprefs.cpuboard_type || !cpuboard_size)
return false;
- if (maprom_state)
- copymaprom();
+ if (is_blizzard() || is_blizzardppc()) {
+ if (maprom_state)
+ blizzard_copymaprom();
+ } else if (is_cs()) {
+ if (!(io_reg[CSIII_REG_SHADOW] & P5_SHADOW))
+ cyberstorm_copymaprom();
+ }
return true;
}
+static struct zfile *flashfile_open(const TCHAR *name)
+{
+ struct zfile *f;
+ TCHAR path[MAX_DPATH];
+
+ fetch_rompath(path, sizeof path / sizeof(TCHAR));
+ _tcscat(path, name);
+ f = zfile_fopen(path, _T("rb+"), ZFD_NONE);
+ if (!f)
+ f = zfile_fopen(path, _T("rb"), ZFD_NORMAL);
+ return f;
+}
+
addrbank *cpuboard_autoconfig_init(void)
{
struct zfile *autoconfig_rom = NULL;
int roms[2];
bool autoconf = true;
+ const TCHAR *romname = NULL;
+ roms[0] = -1;
+ roms[1] = -1;
switch (currprefs.cpuboard_type)
{
case BOARD_BLIZZARD_1230_IV:
roms[0] = 91;
break;
case BOARD_WARPENGINE_A4000:
- roms[0] = 93;
+ expamem_next();
+ return NULL;
+ case BOARD_CSMK3:
+ case BOARD_CSPPC:
+ case BOARD_BLIZZARDPPC:
break;
default:
expamem_next();
return NULL;
}
- roms[1] = -1;
struct romlist *rl = getromlistbyids(roms);
if (rl) {
autoconfig_rom = read_rom(rl->rd);
}
- if (!autoconfig_rom) {
+
+ if (currprefs.cpuboard_type == BOARD_CSMK3) {
+ romname = _T("cyberstormmk3.rom");
+ }
+ if (currprefs.cpuboard_type == BOARD_CSPPC) {
+ romname = _T("cyberstormppc.rom");
+ }
+ if (currprefs.cpuboard_type == BOARD_BLIZZARDPPC) {
+ romname = _T("blizzardppc.rom");
+ }
+
+ if (romname != NULL) {
+ autoconfig_rom = flashfile_open(romname);
+ if (!autoconfig_rom) {
+ write_log(_T("Couldn't open CPU board rom '%s'\n"), romname);
+ expamem_next();
+ return NULL;
+ }
+ }
+
+ if (!autoconfig_rom && roms[0] != -1) {
write_log (_T("ROM id %d not found for CPU board emulation\n"));
expamem_next();
return NULL;
zfile_fread(&b, 1, 1, autoconfig_rom);
blizzardea_bank.baseaddr[i * 2 + 0] = b;
}
- } else if (currprefs.cpuboard_type == BOARD_WARPENGINE_A4000) {
- f0rom_size = 0;
+ } else if (is_cs() || is_blizzardppc()) {
+ f0rom_size = is_blizzardppc() ? 524288 : 131072;
earom_size = 0;
+ memset(blizzardf0_bank.baseaddr, 0xff, f0rom_size);
+ zfile_fread(blizzardf0_bank.baseaddr, f0rom_size, 1, autoconfig_rom);
autoconf = false;
- } else {
+ if (zfile_needwrite(autoconfig_rom)) {
+ flashrom_file = autoconfig_rom;
+ autoconfig_rom = NULL;
+ }
+ flashrom = flash_new(blizzardf0_bank.baseaddr, f0rom_size, f0rom_size, flashrom_file);
+ }
+ else {
f0rom_size = 65536;
earom_size = 131072;
// 12xx = 1x32k
zfile_fclose(autoconfig_rom);
if (f0rom_size)
- map_banks(&blizzardf0_bank, 0xf00000 >> 16, f0rom_size >> 16, 0);
+ map_banks(&blizzardf0_bank, 0xf00000 >> 16, 262144 >> 16, 0);
if (!autoconf) {
expamem_next();
return NULL;
#include "cpummu.h"
#include "debug.h"
+#define MMUDUMP 0
+
#define DBG_MMU_VERBOSE 1
#define DBG_MMU_SANITY 1
#if 0
#ifdef FULLMMU
-
uae_u32 mmu_is_super;
uae_u32 mmu_tagmask, mmu_pagemask, mmu_pagemaski;
struct mmu_atc_line mmu_atc_array[ATC_TYPE][ATC_WAYS][ATC_SLOTS];
}
-#if 0
+#if MMUDUMP
/* {{{ mmu_dump_table */
static void mmu_dump_table(const char * label, uaecptr root_ptr)
{
uaecptr ptr_des_addr, page_addr,
root_log, ptr_log, page_log;
- write_log(_T("%s: root=%lx\n", label, root_ptr);
+ write_log(_T("%s: root=%lx\n"), label, root_ptr);
for (root_idx = 0; root_idx < ROOT_TABLE_SIZE; root_idx++) {
root_des = phys_get_long(root_ptr + root_idx);
if ((root_des & 2) == 0)
continue; /* invalid */
- write_log(_T("ROOT: %03d U=%d W=%d UDT=%02d\n", root_idx,
+ write_log(_T("ROOT: %03d U=%d W=%d UDT=%02d\n"), root_idx,
root_des & 8 ? 1 : 0,
root_des & 4 ? 1 : 0,
root_des & 3
if (n_pages_used == -1)
continue;
- write_log(_T(" PTR: %03d U=%d W=%d UDT=%02d\n", ptr_idx,
+ write_log(_T(" PTR: %03d U=%d W=%d UDT=%02d\n"), ptr_idx,
ptr_des & 8 ? 1 : 0,
ptr_des & 4 ? 1 : 0,
ptr_des & 3
page_des = page_info[page_idx].match;
if ((page_des & MMU_PDT_MASK) == 2) {
- write_log(_T(" PAGE: %03d-%03d log=%08lx INDIRECT --> addr=%08lx\n",
+ write_log(_T(" PAGE: %03d-%03d log=%08lx INDIRECT --> addr=%08lx\n"),
page_info[page_idx].start_idx,
page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1,
page_info[page_idx].log,
);
} else {
- write_log(_T(" PAGE: %03d-%03d log=%08lx addr=%08lx UR=%02d G=%d U1/0=%d S=%d CM=%d M=%d U=%d W=%d\n",
+ write_log(_T(" PAGE: %03d-%03d log=%08lx addr=%08lx UR=%02d G=%d U1/0=%d S=%d CM=%d M=%d U=%d W=%d\n"),
page_info[page_idx].start_idx,
page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1,
page_info[page_idx].log,
mmu_dump_ttr(_T("ITT0"), regs.itt0);
mmu_dump_ttr(_T("ITT1"), regs.itt1);
mmu_dump_atc();
-#if MMUDEBUG
- // mmu_dump_table("SRP", regs.srp);
+#if MMUDUMP
+ mmu_dump_table("SRP", regs.srp);
#endif
}
/* }}} */
return res;
}
+uae_u32 REGPARAM2 mmu_get_ilong_unaligned(uaecptr addr)
+{
+ uae_u32 res;
+
+ if (likely(!(addr & 1))) {
+ res = (uae_u32)mmu_get_iword(addr, sz_long) << 16;
+ SAVE_EXCEPTION;
+ TRY(prb) {
+ res |= mmu_get_iword(addr + 2, sz_long);
+ RESTORE_EXCEPTION;
+ }
+ CATCH(prb) {
+ RESTORE_EXCEPTION;
+ misalignednotfirst(addr);
+ THROW_AGAIN(prb);
+ } ENDTRY
+ }
+ return res;
+}
+
uae_u16 REGPARAM2 mmu_get_lrmw_word_unaligned(uaecptr addr)
{
uae_u16 res;
mmu_bus_error(addr, mmu_get_fc(super, data), 0, size, rmw, status);
return 0;
}
- return phys_get_byte(mmu_get_real_address(addr, cl));
+ return x_phys_get_byte(mmu_get_real_address(addr, cl));
}
uae_u16 REGPARAM2 mmu_get_word_slow(uaecptr addr, bool super, bool data,
mmu_bus_error(addr, mmu_get_fc(super, data), 0, size, rmw, status);
return 0;
}
- return phys_get_word(mmu_get_real_address(addr, cl));
+ return x_phys_get_word(mmu_get_real_address(addr, cl));
+}
+uae_u16 REGPARAM2 mmu_get_iword_slow(uaecptr addr, bool super,
+ int size, struct mmu_atc_line *cl)
+{
+ uae_u32 status;
+ if (!mmu_fill_atc_try(addr, super, false, 0, cl, &status)) {
+ mmu_bus_error(addr, mmu_get_fc(super, false), 0, size, false, status);
+ return 0;
+ }
+ return x_phys_get_iword(mmu_get_real_address(addr, cl));
}
uae_u32 REGPARAM2 mmu_get_long_slow(uaecptr addr, bool super, bool data,
mmu_bus_error(addr, mmu_get_fc(super, data), 0, size, rmw, status);
return 0;
}
- return phys_get_long(mmu_get_real_address(addr, cl));
+ return x_phys_get_long(mmu_get_real_address(addr, cl));
+}
+uae_u32 REGPARAM2 mmu_get_ilong_slow(uaecptr addr, bool super,
+ int size, struct mmu_atc_line *cl)
+{
+ uae_u32 status;
+ if (!mmu_fill_atc_try(addr, super, false, 0, cl, &status)) {
+ mmu_bus_error(addr, mmu_get_fc(super, false), 0, size, false, status);
+ return 0;
+ }
+ return x_phys_get_ilong(mmu_get_real_address(addr, cl));
}
void REGPARAM2 mmu_put_long_unaligned(uaecptr addr, uae_u32 val, bool data, bool rmw)
mmu_bus_error(addr, mmu_get_fc(super, data), 1, size, rmw, status);
return;
}
- phys_put_byte(mmu_get_real_address(addr, cl), val);
+ x_phys_put_byte(mmu_get_real_address(addr, cl), val);
}
void REGPARAM2 mmu_put_word_slow(uaecptr addr, uae_u16 val, bool super, bool data,
mmu_bus_error(addr, mmu_get_fc(super, data), 1, size, rmw, status);
return;
}
- phys_put_word(mmu_get_real_address(addr, cl), val);
+ x_phys_put_word(mmu_get_real_address(addr, cl), val);
}
void REGPARAM2 mmu_put_long_slow(uaecptr addr, uae_u32 val, bool super, bool data,
mmu_bus_error(addr, mmu_get_fc(super, data), 1, size, rmw, status);
return;
}
- phys_put_long(mmu_get_real_address(addr, cl), val);
+ x_phys_put_long(mmu_get_real_address(addr, cl), val);
}
uae_u32 REGPARAM2 sfc_get_long(uaecptr addr)
uaecptr addr2 = addr + i * 4;
// addr,super,data
if ((!regs.mmu_enabled) || (mmu_match_ttr(addr2,regs.s != 0,data,false)!=TTR_NO_MATCH))
- v[i] = phys_get_long(addr2);
+ v[i] = x_phys_get_long(addr2);
else if (likely(mmu_lookup(addr2, data, false, &cl)))
- v[i] = phys_get_long(mmu_get_real_address(addr2, cl));
+ v[i] = x_phys_get_long(mmu_get_real_address(addr2, cl));
else
v[i] = mmu_get_long_slow(addr2, regs.s != 0, data, size, false, cl);
}
uaecptr addr2 = addr + i * 4;
// addr,super,data
if ((!regs.mmu_enabled) || (mmu_match_ttr_write(addr2,regs.s != 0,data,val[i],size,false)==TTR_OK_MATCH))
- phys_put_long(addr2,val[i]);
+ x_phys_put_long(addr2,val[i]);
else if (likely(mmu_lookup(addr2, data, true, &cl)))
- phys_put_long(mmu_get_real_address(addr2, cl), val[i]);
+ x_phys_put_long(mmu_get_real_address(addr2, cl), val[i]);
else
mmu_put_long_slow(addr2, val[i], regs.s != 0, data, size, false, cl);
}
void REGPARAM2 mmu_reset(void)
{
mmu_flush_atc_all(true);
+
+ if (currprefs.cpu_cycle_exact || currprefs.cpu_compatible) {
+ x_phys_get_iword = get_word_icache040;
+ x_phys_get_ilong = get_long_icache040;
+ x_phys_get_byte = get_byte_cache_040;
+ x_phys_get_word = get_word_cache_040;
+ x_phys_get_long = get_long_cache_040;
+ x_phys_put_byte = put_byte_cache_040;
+ x_phys_put_word = put_word_cache_040;
+ x_phys_put_long = put_long_cache_040;
+ } else {
+ x_phys_get_iword = phys_get_word;
+ x_phys_get_ilong = phys_get_long;
+ x_phys_get_byte = phys_get_byte;
+ x_phys_get_word = phys_get_word;
+ x_phys_get_long = phys_get_long;
+ x_phys_put_byte = phys_put_byte;
+ x_phys_put_word = phys_put_word;
+ x_phys_put_long = phys_put_long;
+ }
}
mmu_flush_atc_all(true);
- write_log(_T("%d MMU: enabled=%d page8k=%d\n"), currprefs.mmu_model, regs.mmu_enabled, mmu_pagesize_8k);
+ write_log(_T("%d MMU: enabled=%d page8k=%d PC=%08x\n"), currprefs.mmu_model, regs.mmu_enabled, mmu_pagesize_8k, m68k_getpc());
+#if MMUDUMP
+ if (regs.mmu_enabled)
+ mmu_dump_tables();
+#endif
}
void REGPARAM2 mmu_set_super(bool super)
return;
}
- phys_put_long(physical_addr, val);
+ x_phys_put_long(physical_addr, val);
}
void mmu030_put_word_atc(uaecptr addr, uae_u16 val, int l, uae_u32 fc) {
return;
}
- phys_put_word(physical_addr, val);
+ x_phys_put_word(physical_addr, val);
}
void mmu030_put_byte_atc(uaecptr addr, uae_u8 val, int l, uae_u32 fc) {
return;
}
- phys_put_byte(physical_addr, val);
+ x_phys_put_byte(physical_addr, val);
}
uae_u32 mmu030_get_long_atc(uaecptr addr, int l, uae_u32 fc) {
return 0;
}
- return phys_get_long(physical_addr);
+ return x_phys_get_long(physical_addr);
+}
+uae_u32 mmu030_get_ilong_atc(uaecptr addr, int l, uae_u32 fc) {
+ uae_u32 page_index = addr & mmu030.translation.page.mask;
+ uae_u32 addr_mask = mmu030.translation.page.imask;
+
+ uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
+#if MMU030_ATC_DBG_MSG
+ write_log(_T("ATC match(%i): page addr = %08X, index = %08X (lget %08X)\n"), l,
+ physical_addr, page_index, phys_get_long(physical_addr + page_index));
+#endif
+ physical_addr += page_index;
+
+ if (mmu030.atc[l].physical.bus_error) {
+ mmu030_page_fault(addr, true, MMU030_SSW_SIZE_L, fc);
+ return 0;
+ }
+
+ return x_phys_get_ilong(physical_addr);
}
uae_u16 mmu030_get_word_atc(uaecptr addr, int l, uae_u32 fc) {
return 0;
}
- return phys_get_word(physical_addr);
+ return x_phys_get_word(physical_addr);
+}
+
+uae_u16 mmu030_get_iword_atc(uaecptr addr, int l, uae_u32 fc) {
+ uae_u32 page_index = addr & mmu030.translation.page.mask;
+ uae_u32 addr_mask = mmu030.translation.page.imask;
+
+ uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
+#if MMU030_ATC_DBG_MSG
+ write_log(_T("ATC match(%i): page addr = %08X, index = %08X (wget %04X)\n"), l,
+ physical_addr, page_index, phys_get_word(physical_addr + page_index));
+#endif
+ physical_addr += page_index;
+
+ if (mmu030.atc[l].physical.bus_error) {
+ mmu030_page_fault(addr, true, MMU030_SSW_SIZE_W, fc);
+ return 0;
+ }
+
+ return x_phys_get_iword(physical_addr);
}
uae_u8 mmu030_get_byte_atc(uaecptr addr, int l, uae_u32 fc) {
return 0;
}
- return phys_get_byte(physical_addr);
+ return x_phys_get_byte(physical_addr);
}
/* Generic versions of above */
return;
}
if (size == sz_byte)
- phys_put_byte(physical_addr, val);
+ x_phys_put_byte(physical_addr, val);
else if (size == sz_word)
- phys_put_word(physical_addr, val);
+ x_phys_put_word(physical_addr, val);
else
- phys_put_long(physical_addr, val);
+ x_phys_put_long(physical_addr, val);
}
uae_u32 mmu030_get_atc_generic(uaecptr addr, int l, uae_u32 fc, int size, int flags, bool checkwrite) {
return 0;
}
if (size == sz_byte)
- return phys_get_byte(physical_addr);
+ return x_phys_get_byte(physical_addr);
else if (size == sz_word)
- return phys_get_word(physical_addr);
- return phys_get_long(physical_addr);
+ return x_phys_get_word(physical_addr);
+ return x_phys_get_long(physical_addr);
}
// addr,super,write
if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr,fc,true)) || (fc==7)) {
- phys_put_long(addr,val);
+ x_phys_put_long(addr,val);
return;
}
// addr,super,write
if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr,fc,true)) || (fc==7)) {
- phys_put_word(addr,val);
+ x_phys_put_word(addr,val);
return;
}
// addr,super,write
if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr, fc, true)) || (fc==7)) {
- phys_put_byte(addr,val);
+ x_phys_put_byte(addr,val);
return;
}
}
}
+uae_u32 mmu030_get_ilong(uaecptr addr, uae_u32 fc) {
+
+ // addr,super,write
+ if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr, fc, false)) || (fc == 7)) {
+ return x_phys_get_ilong(addr);
+ }
+
+ int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
+
+ if (atc_line_num >= 0) {
+ return mmu030_get_ilong_atc(addr, atc_line_num, fc);
+ }
+ else {
+ mmu030_table_search(addr, fc, false, 0);
+ return mmu030_get_ilong_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc);
+ }
+}
uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc) {
// addr,super,write
}
}
+uae_u16 mmu030_get_iword(uaecptr addr, uae_u32 fc) {
+
+ // addr,super,write
+ if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr, fc, false)) || (fc == 7)) {
+ return x_phys_get_iword(addr);
+ }
+
+ int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
+
+ if (atc_line_num >= 0) {
+ return mmu030_get_iword_atc(addr, atc_line_num, fc);
+ }
+ else {
+ mmu030_table_search(addr, fc, false, 0);
+ return mmu030_get_iword_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc);
+ }
+}
uae_u16 mmu030_get_word(uaecptr addr, uae_u32 fc) {
// addr,super,write
// addr,super,write
if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr,fc,false)) || (fc==7)) {
- return phys_get_byte(addr);
+ return x_phys_get_byte(addr);
}
int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
// addr,super,write
if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr, fc, true)) || (fc==7)) {
if (size == sz_byte)
- phys_put_byte(addr, val);
+ x_phys_put_byte(addr, val);
else if (size == sz_word)
- phys_put_word(addr, val);
+ x_phys_put_word(addr, val);
else
- phys_put_long(addr, val);
+ x_phys_put_long(addr, val);
return;
}
return res;
}
+uae_u32 REGPARAM2 mmu030_get_ilong_unaligned(uaecptr addr, uae_u32 fc, int flags)
+{
+ uae_u32 res;
+
+ res = (uae_u32)mmu030_get_iword(addr, fc) << 16;
+ SAVE_EXCEPTION;
+ TRY(prb) {
+ res |= mmu030_get_iword(addr + 2, fc);
+ RESTORE_EXCEPTION;
+ }
+ CATCH(prb) {
+ RESTORE_EXCEPTION;
+ THROW_AGAIN(prb);
+ } ENDTRY
+ return res;
+}
+
uae_u32 REGPARAM2 mmu030_get_long_unaligned(uaecptr addr, uae_u32 fc, int flags)
{
uae_u32 res;
}
}
+static uae_u32 get_dcache_byte(uaecptr addr)
+{
+ return read_dcache030(addr, 0);
+}
+static uae_u32 get_dcache_word(uaecptr addr)
+{
+ return read_dcache030(addr, 1);
+}
+static uae_u32 get_dcache_long(uaecptr addr)
+{
+ return read_dcache030(addr, 2);
+}
+static void put_dcache_byte(uaecptr addr, uae_u32 v)
+{
+ write_dcache030(addr, v, 0);
+}
+static void put_dcache_word(uaecptr addr, uae_u32 v)
+{
+ write_dcache030(addr, v, 1);
+}
+static void put_dcache_long(uaecptr addr, uae_u32 v)
+{
+ write_dcache030(addr, v, 2);
+}
+
/* MMU Reset */
void mmu030_reset(int hardreset)
{
mmusr_030 = 0;
mmu030_flush_atc_all();
}
+ if (currprefs.cpu_cycle_exact || currprefs.cpu_compatible) {
+ x_phys_get_iword = get_word_icache030;
+ x_phys_get_ilong = get_long_icache030;
+ x_phys_get_byte = get_dcache_byte;
+ x_phys_get_word = get_dcache_word;
+ x_phys_get_long = get_dcache_long;
+ x_phys_put_byte = put_dcache_byte;
+ x_phys_put_word = put_dcache_word;
+ x_phys_put_long = put_dcache_long;
+ } else {
+ x_phys_get_iword = phys_get_word;
+ x_phys_get_ilong = phys_get_long;
+ x_phys_get_byte = phys_get_byte;
+ x_phys_get_word = phys_get_word;
+ x_phys_get_long = phys_get_long;
+ x_phys_put_byte = phys_put_byte;
+ x_phys_put_word = phys_put_word;
+ x_phys_put_long = phys_put_long;
+ }
}
rethink_akiko ();
rethink_cd32fmv();
#endif
+#ifdef NCR
+ ncr_rethink();
+#endif
+ cpuboard_rethink();
rethink_gayle ();
}
gfxboard_reset ();
#endif
#ifdef NCR
- ncr_reset ();
+ ncr710_reset();
+ ncr_reset();
#endif
#ifdef JIT
compemu_reset ();
if (isfloppysound (drv))
driveclick_insert (drv - floppy, 1);
#endif
- if (drv->diskfile || drv->filetype)
+ if (drv->diskfile || drv->filetype >= 0)
statusline_add_message(_T("DF%d: -"), drv - floppy);
gui_disk_image_change(drv - floppy, NULL, drv->wrprot);
drive_image_free (drv);
static addrbank *expamem_init_a2065(void)
{
#ifdef A2065
- a2065_init ();
-#endif
+ return a2065_init ();
+#else
return NULL;
+#endif
}
static addrbank *expamem_init_cdtv(void)
{
static addrbank *expamem_init_a4091(void)
{
#ifdef NCR
- return ncr_a4091_autoconfig_init (0);
+ return ncr710_a4091_autoconfig_init (0);
#else
return NULL;
#endif
static addrbank *expamem_init_a4091_2(void)
{
#ifdef NCR
- return ncr_a4091_autoconfig_init (1);
+ return ncr710_a4091_autoconfig_init (1);
#else
return NULL;
#endif
static addrbank *expamem_init_warpengine(void)
{
#ifdef NCR
- return ncr_warpengine_autoconfig_init();
+ return ncr710_warpengine_autoconfig_init();
#else
return NULL;
#endif
if (need_uae_boot_rom () == 0)
do_mount = 0;
- if (currprefs.cpuboard_type == BOARD_BLIZZARD_1230_IV || currprefs.cpuboard_type == BOARD_BLIZZARD_1260) {
+ if (currprefs.cpuboard_type) {
// This requires first 128k slot.
card_flags[cardno] = 1;
card_name[cardno] = _T("Blizzard");
added = true;
}
#endif
- } else if (type == HD_CONTROLLER_TYPE_SCSI_WARPENGINE) {
+ } else if (type == HD_CONTROLLER_TYPE_SCSI_CPUBOARD) {
#ifdef NCR
if (currprefs.cpuboard_type == BOARD_WARPENGINE_A4000) {
warpengine_add_scsi_unit(unit, uci);
added = true;
+ } else if (currprefs.cpuboard_type == BOARD_CSMK3 || currprefs.cpuboard_type == BOARD_CSPPC) {
+ cyberstorm_add_scsi_unit(unit, uci);
+ added = true;
+ } else if (currprefs.cpuboard_type == BOARD_BLIZZARDPPC) {
+ blizzardppc_add_scsi_unit(unit, uci);
+ added = true;
}
#endif
} else if (type == HD_CONTROLLER_TYPE_SCSI_A4000T) {
init_child_aino (unit, base, c);
recycle_aino (unit, c);
- TRACE((_T("created aino %x, exnext\n"), c->uniq));
+ TRACE((_T("created aino %s:%d, exnext\n"), c->nname, c->uniq));
return c;
}
action_dup_lock_2 (unit, packet, k->aino->uniq);
}
-static void free_exkey (Unit *unit, ExamineKey *ek)
+static void free_exkey (Unit *unit, a_inode *aino)
{
- if (--ek->aino->exnext_count == 0) {
+ if (--aino->exnext_count == 0) {
TRACE ((_T("Freeing ExKey and reducing total_locked from %d by %d\n"),
- unit->total_locked_ainos, ek->aino->locked_children));
- unit->total_locked_ainos -= ek->aino->locked_children;
- ek->aino->locked_children = 0;
- }
- ek->aino = 0;
- ek->uniq = 0;
-}
-
-static ExamineKey *lookup_exkey (Unit *unit, uae_u32 uniq)
-{
- ExamineKey *ek;
- int i;
-
- ek = unit->examine_keys;
- for (i = 0; i < EXKEYS; i++, ek++) {
- /* Did we find a free one? */
- if (ek->uniq == uniq)
- return ek;
- }
- write_log (_T("Houston, we have a BIG problem.\n"));
- return 0;
-}
-
-/* This is so sick... who invented ACTION_EXAMINE_NEXT? What did he THINK??? */
-static ExamineKey *new_exkey (Unit *unit, a_inode *aino)
-{
- uae_u32 uniq;
- uae_u32 oldest = 0xFFFFFFFE;
- ExamineKey *ek, *oldest_ek = 0;
- int i;
-
- ek = unit->examine_keys;
- for (i = 0; i < EXKEYS; i++, ek++) {
- /* Did we find a free one? */
- if (ek->aino == 0)
- continue;
- if (ek->uniq < oldest)
- oldest = (oldest_ek = ek)->uniq;
- }
- ek = unit->examine_keys;
- for (i = 0; i < EXKEYS; i++, ek++) {
- /* Did we find a free one? */
- if (ek->aino == 0)
- goto found;
- }
- /* This message should usually be harmless. */
- write_log (_T("Houston, we have a problem (%s).\n"), aino->nname);
- free_exkey (unit, oldest_ek);
- ek = oldest_ek;
-found:
-
- uniq = aino->uniq;
-#if 0
- if (uniq >= 0xFFFFFFFE) {
- /* Things will probably go wrong, but most likely the Amiga will crash
- * before this happens because of something else. */
- uniq = 1;
+ unit->total_locked_ainos, aino->locked_children));
+ unit->total_locked_ainos -= aino->locked_children;
+ aino->locked_children = 0;
}
- unit->next_exkey = uniq + 1;
-#endif
- ek->aino = aino;
- ek->curr_file = 0;
- ek->uniq = uniq;
- return ek;
}
static void move_exkeys (Unit *unit, a_inode *from, a_inode *to)
{
- int i;
- unsigned long tmp = 0;
- for (i = 0; i < EXKEYS; i++) {
- ExamineKey *k = unit->examine_keys + i;
- if (k->uniq == 0)
- continue;
- if (k->aino == from) {
- k->aino = to;
- tmp++;
- }
- }
- if (tmp != from->exnext_count)
- write_log (_T("filesys.c: Bug in ExNext bookkeeping. BAD.\n"));
to->exnext_count = from->exnext_count;
to->locked_children = from->locked_children;
from->exnext_count = 0;
base->locked_children++;
unit->total_locked_ainos++;
}
- TRACE3((_T("Populating directory, child %p, locked_children %d\n"),
- base->child, base->locked_children));
+ TRACE3((_T("Populating directory, child %s, locked_children %d\n"),
+ base->child->nname, base->locked_children));
for (;;) {
uae_u64 uniq = 0;
TCHAR fn[MAX_DPATH];
fs_closedir (d);
}
-static void do_examine (Unit *unit, dpacket packet, ExamineKey *ek, uaecptr info, bool longfilesize)
+static bool do_examine (Unit *unit, dpacket packet, a_inode *aino, uaecptr info, bool longfilesize)
{
for (;;) {
TCHAR *name;
- if (ek->curr_file == 0)
+ if (!aino)
break;
- name = ek->curr_file->nname;
- get_fileinfo (unit, packet, info, ek->curr_file, longfilesize);
- ek->curr_file = ek->curr_file->sibling;
+ name = aino->nname;
+ get_fileinfo (unit, packet, info, aino, longfilesize);
if (!(unit->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS)) && !fsdb_exists(name)) {
TRACE ((_T("%s orphaned"), name));
- continue;
+ return false;
}
- TRACE ((_T("curr_file set to %p %s\n"), ek->curr_file,
- ek->curr_file ? ek->curr_file->aname : _T("NULL")));
- return;
+ return true;
}
TRACE((_T("no more entries\n")));
- free_exkey (unit, ek);
+ free_exkey (unit, aino->parent);
PUT_PCK_RES1 (packet, DOS_FALSE);
PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
+ return true;
}
static void action_examine_next (Unit *unit, dpacket packet, bool largefilesize)
{
uaecptr lock = GET_PCK_ARG1 (packet) << 2;
uaecptr info = GET_PCK_ARG2 (packet) << 2;
- a_inode *aino = 0;
- ExamineKey *ek;
+ a_inode *aino = 0, *daino = 0;
uae_u32 uniq;
TRACE((_T("ACTION_EXAMINE_NEXT(0x%lx,0x%lx,%d)\n"), lock, info, largefilesize));
aino = aino_from_lock (unit, lock);
if (aino == 0)
aino = &unit->rootnode;
- for(;;) {
- uniq = get_long (info);
+ uniq = get_long(info);
+ for (;;) {
if (uniq == aino->uniq) {
// first exnext
if (!aino->dir) {
- write_log (_T("ExNext called for a file! (Houston?)\n"));
+ write_log (_T("ExNext called for a file! %s:%d (Houston?)\n"), aino->nname, uniq);
goto no_more_entries;
}
- TRACE((_T("Creating new ExKey\n")));
- ek = new_exkey (unit, aino);
- if (ek) {
- if (aino->exnext_count++ == 0)
- populate_directory (unit, aino);
- if (!aino->child) {
- free_exkey (unit, ek);
- goto no_more_entries;
+ if (aino->exnext_count++ == 0)
+ populate_directory (unit, aino);
+ if (!aino->child)
+ goto no_more_entries;
+ daino = aino->child;
+ } else {
+ daino = lookup_aino(unit, uniq);
+ if (!daino) {
+ // deleted? Look for next larger uniq in same directory
+ daino = aino->child;
+ while (daino && daino->uniq < uniq) {
+ daino = daino->sibling;
}
- ek->curr_file = aino->child;
- TRACE((_T("Initial curr_file: %p %s\n"), ek->curr_file,
- ek->curr_file ? ek->curr_file->aname : _T("NULL")));
- uniq = ek->curr_file->uniq;
+ } else {
+ daino = daino->sibling;
}
- } else {
- TRACE((_T("Looking up ExKey\n")));
- ek = lookup_exkey(unit, aino->uniq);
}
- if (ek == 0) {
- write_log (_T("Couldn't find a matching ExKey. Prepare for trouble.\n"));
+ if (!daino)
goto no_more_entries;
- }
- if (!ek->curr_file || ek->curr_file->mountcount == unit->mountcount)
- break;
- ek->curr_file = ek->curr_file->sibling;
- if (!ek->curr_file)
+ if (daino->parent != aino) {
+ write_log(_T("Houston, we have a BIG problem. %s is not parent of %s\n"), daino->nname, aino->nname);
goto no_more_entries;
+ }
+ uniq = daino->uniq;
+ if (daino->mountcount != unit->mountcount)
+ continue;
+ if (!do_examine (unit, packet, daino, info, largefilesize))
+ continue;
+ return;
}
- do_examine (unit, packet, ek, info, largefilesize);
- return;
no_more_entries:
- PUT_PCK_RES1 (packet, DOS_FALSE);
+ free_exkey(unit, aino);
+ PUT_PCK_RES1(packet, DOS_FALSE);
PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
}
_tcscpy (hfd->product_rev, s);
xfree (s);
s = restore_string ();
- _tcscpy (hfd->device_name, s);
+ _tcscpy (hfd->ci.devname, s);
xfree (s);
return src;
}
save_string (hfd->vendor_id);
save_string (hfd->product_id);
save_string (hfd->product_rev);
- save_string (hfd->device_name);
+ save_string (hfd->ci.devname);
return dst;
}
--- /dev/null
+/*
+* UAE - The Un*x Amiga Emulator
+*
+* Simple 29F010 flash ROM chip emulator
+*
+* (c) 2014 Toni Wilen
+*/
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "zfile.h"
+#include "flashrom.h"
+
+#define FLASH_LOG 0
+
+struct flashrom_data
+{
+ uae_u8 *rom;
+ int flashsize;
+ int allocsize;
+ int mask;
+ int state;
+ int modified;
+ struct zfile *zf;
+};
+
+void *flash_new(uae_u8 *rom, int flashsize, int allocsize, struct zfile *zf)
+{
+ struct flashrom_data *fd = xcalloc(struct flashrom_data, 1);
+ fd->flashsize = flashsize;
+ fd->allocsize = allocsize;
+ fd->mask = fd->flashsize - 1;
+ fd->zf = zf;
+ fd->rom = rom;
+ return fd;
+}
+
+void flash_free(void *fdv)
+{
+ struct flashrom_data *fd = (struct flashrom_data*)fdv;
+ if (!fd)
+ return;
+ if (fd->zf && fd->modified) {
+ zfile_fseek(fd->zf, 0, SEEK_SET);
+ zfile_fwrite(fd->rom, fd->allocsize, 1, fd->zf);
+ }
+ xfree(fdv);
+}
+
+bool flash_active(void *fdv, uaecptr addr)
+{
+ struct flashrom_data *fd = (struct flashrom_data*)fdv;
+
+ return fd->state != 0;
+}
+
+bool flash_write(void *fdv, uaecptr addr, uae_u8 v)
+{
+ struct flashrom_data *fd = (struct flashrom_data*)fdv;
+ int oldstate = fd->state;
+ uae_u32 addr2;
+
+#if FLASH_LOG
+ write_log(_T("flash write %08x %02x\n"), addr, v);
+#endif
+
+ addr &= fd->mask;
+ addr2 = addr & 0xffff;
+
+ if (fd->state == 7) {
+ fd->state = 0;
+ if (addr >= fd->allocsize)
+ return false;
+ if (fd->rom[addr] != v)
+ fd->modified = 1;
+ fd->rom[addr] = v;
+ return true;
+ }
+
+ if (v == 0xf0) {
+ fd->state = 0;
+ return false;
+ }
+
+ // unlock
+ if (addr2 == 0x5555 && fd->state == 0 && v == 0xaa)
+ fd->state = 1;
+ if (addr2 == 0x2aaa && fd->state == 1 && v == 0x55)
+ fd->state = 2;
+
+ // autoselect
+ if (addr2 == 0x5555 && fd->state == 2 && v == 0x90)
+ fd->state = 3;
+
+ // program
+ if (addr2 == 0x5555 && fd->state == 2 && v == 0xa0)
+ fd->state = 7;
+
+ // chip/sector erase
+ if (addr2 == 0x5555 && fd->state == 2 && v == 0x80)
+ fd->state = 4;
+ if (addr2 == 0x5555 && fd->state == 4 && v == 0xaa)
+ fd->state = 5;
+ if (addr2 == 0x2aaa && fd->state == 5 && v == 0x55)
+ fd->state = 6;
+ if (addr2 == 0x5555 && fd->state == 6 && v == 0x10) {
+ memset(fd->rom, 0xff, fd->allocsize);
+ fd->state = 0;
+ fd->modified = 1;
+#if FLASH_LOG
+ write_log(_T("flash chip erased\n"), addr);
+#endif
+ return true;
+ } else if (fd->state == 6 && v == 0x30) {
+ int saddr = addr & ~0x3fff;
+ if (saddr < fd->allocsize)
+ memset(fd->rom + saddr, 0xff, 0x4000);
+ fd->state = 0;
+ fd->modified = 1;
+#if FLASH_LOG
+ write_log(_T("flash sector %d erased\n"), saddr / 0x4000);
+#endif
+ return true;
+ }
+
+ if (fd->state == oldstate)
+ fd->state = 0;
+ return false;
+}
+
+uae_u32 flash_read(void *fdv, uaecptr addr)
+{
+ struct flashrom_data *fd = (struct flashrom_data*)fdv;
+ uae_u8 v = 0xff;
+
+#if FLASH_LOG
+ write_log(_T("flash read %08x\n"), addr);
+#endif
+
+ addr &= fd->mask;
+ if (fd->state == 3) {
+ uae_u8 a = addr & 0xff;
+ if (a == 0)
+ return 0x01;
+ if (a == 1)
+ return 0x20;
+ if (a == 2)
+ return 0x00;
+ }
+ fd->state = 0;
+ if (addr >= fd->allocsize)
+ return 0xff;
+ return fd->rom[addr];
+}
#include "cpummu030.h"
#include "debug.h"
+#include "softfloatx80.h"
+
#ifdef X86_MSVC_ASSEMBLY
#define X86_MSVC_ASSEMBLY_FPU
#define NATIVE_FPUCW
uae_u32 xhex_1e4096[]={0x8a20979b, 0xc4605202, 0x7525};
static uae_u32 xhex_inf[] ={0x00000000, 0x00000000, 0x7fff};
static uae_u32 xhex_nan[] ={0xffffffff, 0xffffffff, 0x7fff};
+static uae_u32 xhex_snan[] ={0xffffffff, 0xbfffffff, 0x7fff};
#if USE_LONG_DOUBLE
static long double *fp_pi = (long double *)xhex_pi;
static long double *fp_exp_1 = (long double *)xhex_exp_1;
#define FFLAG_N 0x0100
#define FFLAG_NAN 0x0400
+
+#ifdef WITH_SOFTFLOAT
+static floatx80 fxsizes[6] = { 0 };
+static floatx80 fxzero;
+static floatx80 fx_1e0, fx_1e1, fx_1e2, fx_1e4, fx_1e8;
+struct float_status_t fxstatus;
+#endif
+static fptype fsizes[] = { -128.0, 127.0, -32768.0, 32767.0, -2147483648.0, 2147483647.0 };
+
+#define FP_INEXACT (1 << 9)
+#define FP_DIVBYZERO (1 << 10)
+#define FP_UNDERFLOW (1 << 11)
+#define FP_OVERFLOW (1 << 12)
+#define FP_OPERAND (1 << 13)
+#define FP_SNAN (1 << 14)
+#define FP_BSUN (1 << 15)
+
STATIC_INLINE void MAKE_FPSR (fptype *fp)
{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat)
+ return;
+#endif
int status = fetestexcept (FE_ALL_EXCEPT);
- if (status)
- regs.fp_result_status |= status;
+ if (status) {
+ if (status & FE_INEXACT)
+ regs.fp_result_status |= FP_INEXACT;
+ if (status & FE_DIVBYZERO)
+ regs.fp_result_status |= FP_DIVBYZERO;
+ if (status & FE_UNDERFLOW)
+ regs.fp_result_status |= FP_UNDERFLOW;
+ if (status & FE_OVERFLOW)
+ regs.fp_result_status |= FP_OVERFLOW;
+ if (status & FE_INVALID)
+ regs.fp_result_status |= FP_OPERAND;
+ }
regs.fp_result.fp = *fp;
}
+#ifdef WITH_SOFTFLOAT
+STATIC_INLINE void MAKE_FPSR_SOFTFLOAT(floatx80 fx)
+{
+ if (fxstatus.float_exception_flags & float_flag_invalid)
+ regs.fp_result_status |= FP_OPERAND;
+ if (fxstatus.float_exception_flags & float_flag_divbyzero)
+ regs.fp_result_status |= FP_DIVBYZERO;
+ if (fxstatus.float_exception_flags & float_flag_overflow)
+ regs.fp_result_status |= FP_OVERFLOW;
+ if (fxstatus.float_exception_flags & float_flag_underflow)
+ regs.fp_result_status |= FP_UNDERFLOW;
+ if (fxstatus.float_exception_flags & float_flag_inexact)
+ regs.fp_result_status |= FP_INEXACT;
+ regs.fp_result.fpx = fx;
+}
+#endif
+
STATIC_INLINE void CLEAR_STATUS (void)
{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat)
+ return;
+#endif
feclearexcept (FE_ALL_EXCEPT);
}
+#ifdef WITH_SOFTFLOAT
+static void softfloat_set(floatx80 *fx, uae_u32 *f)
+{
+ fx->exp = (uae_u16)f[2];
+ fx->fraction = ((uae_u64)f[1] << 32) | f[0];
+}
+static void softfloat_get(floatx80 *fx, uae_u32 *f)
+{
+ f[2] = fx->exp;
+ f[1] = fx->fraction >> 32;
+ f[0] = (uae_u32)fx->fraction;
+}
+#endif
+
static void fpnan (fpdata *fpd)
{
fpd->fp = *fp_nan;
-#ifdef USE_SOFT_LONG_DOUBLE
- fpd->fpe = ((uae_u64)xhex_nan[0] << 32) | xhex_nan[1];
- fpd->fpm = xhex_nan[2];
+#ifdef WITH_SOFTFLOAT
+ softfloat_set(&fpd->fpx, xhex_nan);
#endif
}
static void fpclear (fpdata *fpd)
{
fpd->fp = 0;
-#ifdef USE_SOFT_LONG_DOUBLE
- fpd->fpe = 0;
- fpd->fpm = 0;
+#ifdef WITH_SOFTFLOAT
+ fpd->fpx = int32_to_floatx80(0);
+#endif
+}
+static void fpset (fpdata *fpd, uae_s32 val)
+{
+ fpd->fp = (fptype)val;
+#ifdef WITH_SOFTFLOAT
+ fpd->fpx = int32_to_floatx80(val);
+#endif
+}
+
+void to_single(fpdata *fpd, uae_u32 value)
+{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat) {
+ float32 f = value;
+ fpd->fpx = float32_to_floatx80(f, fxstatus);
+ } else
#endif
+ fpd->fp = to_single_x(value);
}
-static void fpset (fpdata *fpd, fptype f)
+static uae_u32 from_single(fpdata *fpd)
{
- fpd->fp = f;
-#ifdef USE_SOFT_LONG_DOUBLE
- fpd->fpe = 0;
- fpd->fpm = 0;
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat) {
+ float32 f = floatx80_to_float32(fpd->fpx, fxstatus);
+ return f;
+ } else
#endif
+ return from_single_x(fpd->fp);
}
+void to_double(fpdata *fpd, uae_u32 wrd1, uae_u32 wrd2)
+{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat) {
+ float64 f = ((float64)wrd1 << 32) | wrd2;
+ fpd->fpx = float64_to_floatx80(f, fxstatus);
+ } else
+#endif
+ fpd->fp = to_double_x(wrd1, wrd2);
+}
+static void from_double(fpdata *fpd, uae_u32 *wrd1, uae_u32 *wrd2)
+{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat) {
+ float64 f = floatx80_to_float64(fpd->fpx, fxstatus);
+ *wrd1 = f >> 32;
+ *wrd2 = (uae_u32)f;
+ return;
+ } else
+#endif
+ return from_double_x(fpd->fp, wrd1, wrd2);
+}
+void to_exten(fpdata *fpd, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
+{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat) {
+ fpd->fpx.exp = wrd1 >> 16;
+ fpd->fpx.fraction = ((uae_u64)wrd2 << 32) | wrd3;
+#if 0
+ if ((currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882) || currprefs.fpu_no_unimplemented) {
+ // automatically fix denormals if 6888x or no implemented emulation
+ Bit64u Sig = extractFloatx80Frac(fpd->fpx);
+ Bit32s Exp = extractFloatx80Exp(fpd->fpx);
+ if (Exp == 0 && Sig != 0)
+ normalizeFloatx80Subnormal(Sig, &Exp, &Sig);
+ }
+#endif
+ } else
+#endif
+ to_exten_x(&fpd->fp, wrd1, wrd2, wrd3);
+}
+static void from_exten(fpdata *fpd, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
+{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat) {
+ *wrd1 = fpd->fpx.exp << 16;
+ *wrd2 = fpd->fpx.fraction >> 32;
+ *wrd3 = (uae_u32)fpd->fpx.fraction;
+ } else
+#endif
+ from_exten_x(fpd->fp, wrd1, wrd2, wrd3);
+}
+
#if 0
static void normalize(uae_u32 *pwrd1, uae_u32 *pwrd2, uae_u32 *pwrd3)
}
#endif
-bool fpu_get_constant(fpdata *fp, int cr)
+static bool fpu_get_constant_fp(fpdata *fp, int cr)
{
fptype f;
switch (cr & 0x7f)
return true;
}
-static __inline__ void native_set_fpucw (uae_u32 m68k_cw)
+#ifdef WITH_SOFTFLOAT
+static bool fpu_get_constant_softfloat(fpdata *fp, int cr)
{
+ uae_u32 *f = NULL;
+ floatx80 fx;
+
+ switch (cr & 0x7f)
+ {
+ case 0x00:
+ f = xhex_pi;
+ break;
+ case 0x0b:
+ f = xhex_l10_2;
+ break;
+ case 0x0c:
+ f = xhex_exp_1;
+ break;
+ case 0x0d:
+ f = xhex_l2_e;
+ break;
+ case 0x0e:
+ f = xhex_l10_e;
+ break;
+ case 0x0f:
+ fx = fxzero;
+ break;
+ case 0x30:
+ f = xhex_ln_2;
+ break;
+ case 0x31:
+ f = xhex_ln_10;
+ break;
+ case 0x32:
+ fx = fx_1e0;
+ break;
+ case 0x33:
+ fx = fx_1e1;
+ break;
+ case 0x34:
+ fx = fx_1e2;
+ break;
+ case 0x35:
+ fx = fx_1e4;
+ break;
+ case 0x36:
+ fx = fx_1e8;
+ break;
+ case 0x37:
+ f = xhex_1e16;
+ break;
+ case 0x38:
+ f = xhex_1e32;
+ break;
+ case 0x39:
+ f = xhex_1e64;
+ break;
+ case 0x3a:
+ f = xhex_1e128;
+ break;
+ case 0x3b:
+ f = xhex_1e256;
+ break;
+ case 0x3c:
+ f = xhex_1e512;
+ break;
+ case 0x3d:
+ f = xhex_1e1024;
+ break;
+ case 0x3e:
+ f = xhex_1e2048;
+ break;
+ case 0x3f:
+ f = xhex_1e4096;
+ break;
+ default:
+ return false;
+ }
+ if (f)
+ softfloat_set(&fp->fpx, f);
+ else
+ fp->fpx = fx;
+ return true;
+}
+#endif
+
+bool fpu_get_constant(fpdata *fp, int cr)
+{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat)
+ return fpu_get_constant_softfloat(fp, cr);
+#endif
+ return fpu_get_constant_fp(fp, cr);
+}
+
+static void native_set_fpucw (uae_u32 m68k_cw)
+{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat) {
+ switch((m68k_cw >> 6) & 3)
+ {
+ case 0: // X
+ default: // undefined
+ fxstatus.float_rounding_precision = 80;
+ break;
+ case 1: // S
+ fxstatus.float_rounding_precision = 32;
+ break;
+ case 2: // D
+ fxstatus.float_rounding_precision = 64;
+ break;
+ }
+ switch((m68k_cw >> 4) & 3)
+ {
+ case 0: // to neareset
+ fxstatus.float_rounding_precision = float_round_nearest_even;
+ break;
+ case 1: // to zero
+ fxstatus.float_rounding_mode = float_round_to_zero;
+ break;
+ case 2: // to minus
+ fxstatus.float_rounding_mode = float_round_down;
+ break;
+ case 3: // to plus
+ fxstatus.float_rounding_mode = float_round_up;
+ break;
+ }
+ } else
+#endif
+ {
#ifdef NATIVE_FPUCW
#ifdef _WIN32
- static int ex = 0;
- // RN, RZ, RM, RP
- static const unsigned int fp87_round[4] = { _RC_NEAR, _RC_CHOP, _RC_DOWN, _RC_UP };
- // Extend X, Single S, Double D, Undefined
- static const unsigned int fp87_prec[4] = { _PC_64 , _PC_24 , _PC_53, 0 };
-
+ static int ex = 0;
+ // RN, RZ, RM, RP
+ static const unsigned int fp87_round[4] = { _RC_NEAR, _RC_CHOP, _RC_DOWN, _RC_UP };
+ // Extend X, Single S, Double D, Undefined
+ static const unsigned int fp87_prec[4] = { _PC_64 , _PC_24 , _PC_53, 0 };
#ifdef WIN64
- _controlfp (ex | fp87_round[(m68k_cw >> 4) & 3], _MCW_RC);
+ _controlfp (ex | fp87_round[(m68k_cw >> 4) & 3], _MCW_RC);
#else
- _control87 (ex | fp87_round[(m68k_cw >> 4) & 3] | fp87_prec[(m68k_cw >> 6) & 3], _MCW_RC | _MCW_PC);
+ _control87 (ex | fp87_round[(m68k_cw >> 4) & 3] | fp87_prec[(m68k_cw >> 6) & 3], _MCW_RC | _MCW_PC);
#endif
#else
-static const uae_u16 x87_cw_tab[] = {
- 0x137f, 0x1f7f, 0x177f, 0x1b7f, /* Extended */
- 0x107f, 0x1c7f, 0x147f, 0x187f, /* Single */
- 0x127f, 0x1e7f, 0x167f, 0x1a7f, /* Double */
- 0x137f, 0x1f7f, 0x177f, 0x1b7f /* undefined */
-};
+ static const uae_u16 x87_cw_tab[] = {
+ 0x137f, 0x1f7f, 0x177f, 0x1b7f, /* Extended */
+ 0x107f, 0x1c7f, 0x147f, 0x187f, /* Single */
+ 0x127f, 0x1e7f, 0x167f, 0x1a7f, /* Double */
+ 0x137f, 0x1f7f, 0x177f, 0x1b7f /* undefined */
+ };
#if USE_X86_FPUCW
- uae_u16 x87_cw = x87_cw_tab[(m68k_cw >> 4) & 0xf];
+ uae_u16 x87_cw = x87_cw_tab[(m68k_cw >> 4) & 0xf];
#if defined(X86_MSVC_ASSEMBLY)
- __asm {
- fldcw word ptr x87_cw
- }
+ __asm {
+ fldcw word ptr x87_cw
+ }
#elif defined(X86_ASSEMBLY)
- __asm__ ("fldcw %0" : : "m" (*&x87_cw));
+ __asm__ ("fldcw %0" : : "m" (*&x87_cw));
#endif
#endif
#endif
#endif
+ }
}
#if defined(uae_s64) /* Close enough for government work? */
#define FPU_EXP_UNIMP_INS 0
#define FPU_EXP_DISABLED 1
-#define FPU_EXP_UNIMP_DATATYPE_PACKED_PRE 2
-#define FPU_EXP_UNIMP_DATATYPE_PACKED_POST 3
-#define FPU_EXP_UNIMP_EA 4
+#define FPU_EXP_UNIMP_DATATYPE_PRE 2
+#define FPU_EXP_UNIMP_DATATYPE_POST 3
+#define FPU_EXP_UNIMP_DATATYPE_PACKED_PRE 4
+#define FPU_EXP_UNIMP_DATATYPE_PACKED_POST 5
+#define FPU_EXP_UNIMP_EA 6
static void fpu_arithmetic_exception (uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, int type, fpdata *src, int reg)
{
// TODO
}
-static void fpu_op_unimp (uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, int type, fpdata *src, int reg)
+static void fpu_op_unimp (uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, int type, fpdata *src, int reg, int size)
{
/* 68040 unimplemented/68060 FPU disabled exception.
* Line F exception with different stack frame.. */
regs.fpiar = oldpc;
regs.exp_extra = extra;
regs.exp_opcode = opcode;
+ regs.exp_size = size;
if (src)
regs.exp_src1 = *src;
regs.exp_type = type;
x_put_long (m68k_areg (regs, 7), ea);
m68k_areg (regs, 7) -= 2;
x_put_word (m68k_areg (regs, 7), 0x2000 + vector * 4);
- } else if (type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE || type == FPU_EXP_UNIMP_DATATYPE_PACKED_POST) {
+ } else if (type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE || type == FPU_EXP_UNIMP_DATATYPE_PACKED_POST || type == FPU_EXP_UNIMP_DATATYPE_PRE || type == FPU_EXP_UNIMP_DATATYPE_POST) {
regs.fpu_exp_state = 2; // EXC frame
// PC = next instruction
vector = 55;
regs.fpiar = oldpc;
regs.exp_extra = extra;
regs.exp_opcode = opcode;
+ regs.exp_size = size;
if (src)
regs.exp_src1 = *src;
regs.exp_type = type;
x_put_long (m68k_areg (regs, 7), ea);
m68k_areg (regs, 7) -= 2;
x_put_word (m68k_areg (regs, 7), 0x2000 + vector * 4);
- } else if (type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE || type == FPU_EXP_UNIMP_DATATYPE_PACKED_POST) {
+ } else if (type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE || type == FPU_EXP_UNIMP_DATATYPE_PACKED_POST || type == FPU_EXP_UNIMP_DATATYPE_PRE || type == FPU_EXP_UNIMP_DATATYPE_POST) {
// PC = next instruction
vector = 55;
m68k_areg (regs, 7) -= 4;
{
if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2)))
|| (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) {
- fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_DISABLED, NULL, -1);
+ fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_DISABLED, NULL, -1, -1);
return;
}
regs.fp_exception = true;
return false;
if ((extra & 0xfc00) == 0x5c00) {
// FMOVECR
- fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, src, reg);
+ fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, src, reg, -1);
return true;
}
uae_u16 v = extra & 0x7f;
case 0x03: /* FINTRZ */
// Unimplemented only in 68040.
if (currprefs.cpu_model == 68040) {
- fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, src, reg);
+ fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, src, reg, -1);
return true;
}
return false;
case 0x21: /* FMOD */
case 0x25: /* FREM */
case 0x26: /* FSCALE */
- fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, src, reg);
+ fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, src, reg, -1);
return true;
}
}
static bool fault_if_60 (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, int type)
{
if (currprefs.cpu_model == 68060 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
- fpu_op_unimp (opcode, extra, ea, oldpc, type, NULL, -1);
+ fpu_op_unimp (opcode, extra, ea, oldpc, type, NULL, -1, -1);
return true;
}
return false;
regs.exp_pack[1] = pack[1];
regs.exp_pack[2] = pack[2];
}
- fpu_op_unimp (opcode, extra, ea, oldpc, type, src, -1);
+ fpu_op_unimp (opcode, extra, ea, oldpc, type, src, -1, -1);
return true;
}
return false;
return true;
if (currprefs.cpu_model == 68060 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
// 68060 FTRAP, FDBcc or FScc are not implemented.
- fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, NULL, -1);
+ fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, NULL, -1, -1);
return true;
}
return false;
#define fp_round_to_zero(x) ((x) >= 0.0 ? floor(x) : ceil(x))
#define fp_round_to_nearest(x) ((x) >= 0.0 ? (int)((x) + 0.5) : (int)((x) - 0.5))
-STATIC_INLINE tointtype toint (fptype src, fptype minval, fptype maxval)
+static tointtype toint(fpdata *src, int size)
{
- if (src < minval)
- src = minval;
- if (src > maxval)
- src = maxval;
-#if defined(X86_MSVC_ASSEMBLY_FPU)
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat) {
+ if (floatx80_compare(src->fpx, fxsizes[size * 2 + 0], fxstatus) == float_relation_greater)
+ return floatx80_to_int32(fxsizes[size * 2 + 0], fxstatus);
+ if (floatx80_compare(src->fpx, fxsizes[size * 2 + 1], fxstatus) == float_relation_less)
+ return floatx80_to_int32(fxsizes[size * 2 + 1], fxstatus);
+ return floatx80_to_int32(src->fpx, fxstatus);
+ } else
+#endif
{
- fptype tmp_fp;
- __asm {
- fld LDPTR src
+ fptype fp = src->fp;
+ if (fp < fsizes[size * 2 + 0])
+ fp = fsizes[size * 2 + 0];
+ if (fp > fsizes[size * 2 + 1])
+ fp = fsizes[size * 2 + 1];
+ #if defined(X86_MSVC_ASSEMBLY_FPU)
+ {
+ fptype tmp_fp;
+ __asm {
+ fld LDPTR fp
frndint
fstp LDPTR tmp_fp
+ }
+ return (tointtype)tmp_fp;
}
- return (tointtype)tmp_fp;
- }
-#else /* no X86_MSVC */
- {
- int result = (int)src;
- switch (regs.fpcr & 0x30)
+ #else /* no X86_MSVC */
{
- case FPCR_ROUND_ZERO:
- result = (int)fp_round_to_zero (src);
- break;
- case FPCR_ROUND_MINF:
- result = (int)fp_round_to_minus_infinity (src);
- break;
- case FPCR_ROUND_NEAR:
- result = fp_round_to_nearest (src);
- break;
- case FPCR_ROUND_PINF:
- result = (int)fp_round_to_plus_infinity (src);
- break;
+ int result = (int)fp;
+ switch (regs.fpcr & 0x30)
+ {
+ case FPCR_ROUND_ZERO:
+ result = (int)fp_round_to_zero (fp);
+ break;
+ case FPCR_ROUND_MINF:
+ result = (int)fp_round_to_minus_infinity (fp);
+ break;
+ case FPCR_ROUND_NEAR:
+ result = fp_round_to_nearest (fp);
+ break;
+ case FPCR_ROUND_PINF:
+ result = (int)fp_round_to_plus_infinity (fp);
+ break;
+ }
+ return result;
}
- return result;
+ #endif
}
-#endif
}
-static bool fpu_isnan (fptype fp)
+static bool fp_is_snan(fpdata *fpd)
+{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat)
+ return floatx80_is_signaling_nan(fpd->fpx) != 0;
+#endif
+ return false;
+}
+static bool fp_is_nan (fpdata *fpd)
{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat)
+ return floatx80_is_nan(fpd->fpx) != 0;
+#endif
#ifdef HAVE_ISNAN
- return isnan (fp) != 0;
+ return isnan(fpd->fp) != 0;
#else
return false;
#endif
}
-static bool fpu_isinfinity (fptype fp)
+static bool fp_is_infinity (fpdata *fpd)
{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat) {
+ float_class_t fc = floatx80_class(fpd->fpx);
+ return fc == float_negative_inf || fc == float_positive_inf;
+ }
+#endif
#ifdef _MSC_VER
- return !_finite (fp);
+ return !_finite (fpd->fp);
#elif defined(HAVE_ISINF)
- return _isinf (fp);
+ return _isinf (fpd->fp);
#else
return false;
#endif
}
+static bool fp_is_zero(fpdata *fpd)
+{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat)
+ return floatx80_compare_quiet(fpd->fpx, fxzero, fxstatus) == float_relation_equal;
+#endif
+ return fpd->fp == 0.0;
+}
+static bool fp_is_neg(fpdata *fpd)
+{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat)
+ return extractFloatx80Sign(fpd->fpx) != 0;
+#endif
+ return fpd->fp < 0.0;
+}
uae_u32 get_fpsr (void)
{
uae_u32 answer = regs.fpsr & 0x00ff00f8;
// exception status byte
- if (regs.fp_result_status & FE_INEXACT)
- answer |= 1 << 9;
- if (regs.fp_result_status & FE_DIVBYZERO)
- answer |= 1 << 10;
- if (regs.fp_result_status & FE_UNDERFLOW)
- answer |= 1 << 11;
- if (regs.fp_result_status & FE_OVERFLOW)
- answer |= 1 << 12;
- if (regs.fp_result_status & FE_INVALID)
- answer |= 1 << 13;
+ answer |= regs.fp_result_status;
+ if (fp_is_snan(®s.fp_result))
+ answer |= 1 << 14;
// accrued exception byte
if (answer & ((1 << 14) | (1 << 13)))
regs.fpsr = answer;
// condition code byte
- if (fpu_isnan (regs.fp_result.fp))
+ if (fp_is_nan (®s.fp_result)) {
answer |= 1 << 24;
- else
- {
- if (regs.fp_result.fp == 0)
+ } else {
+ if (fp_is_zero(®s.fp_result))
answer |= 1 << 26;
- else if (regs.fp_result.fp < 0)
- answer |= 1 << 27;
- if (fpu_isinfinity (regs.fp_result.fp))
+ if (fp_is_infinity (®s.fp_result))
answer |= 1 << 25;
}
+ if (fp_is_neg(®s.fp_result))
+ answer |= 1 << 27;
return answer;
}
static void update_fpsr (uae_u32 v)
{
- regs.fp_result_status = FE_INVALID;
+ regs.fp_result_status = v;
get_fpsr ();
}
regs.fp_result_status = 0;
if (x & 0x01000000)
- fpset (®s.fp_result, *fp_nan);
+ fpnan (®s.fp_result);
else if (x & 0x04000000)
fpset (®s.fp_result, 0);
else if (x & 0x08000000)
fpset (®s.fp_result, 1);
}
-uae_u32 get_ftag (uae_u32 w1, uae_u32 w2, uae_u32 w3)
+uae_u32 get_ftag (uae_u32 w1, uae_u32 w2, uae_u32 w3, int size)
{
int exp = (w1 >> 16) & 0x7fff;
if (exp == 0) {
if (!w2 && !w3)
return 1; // ZERO
- return 4; // DENORMAL or UNNORMAL
+ if (size == 0 || size == 1)
+ return 5; // Single/double DENORMAL
+ return 4; // Extended DENORMAL or UNNORMAL
} else if (exp == 0x7fff) {
int s = w2 >> 30;
int z = (w2 & 0x3fffffff) == 0 && w3 == 0;
return 3; // NAN
} else {
if (!(w2 & 0x80000000))
- return 4; // UNNORMAL
+ return 4; // Extended UNNORMAL
return 0; // NORMAL
}
}
/* E = MAX & F # 0 -> NotANumber */
/* E = biased by 127 (single) ,1023 (double) ,16383 (extended) */
-static fptype to_pack (uae_u32 *wrd)
+static void to_pack (fpdata *fpd, uae_u32 *wrd)
{
fptype d;
char *cp;
#else
sscanf (str, "%le", &d);
#endif
- return d;
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat) {
+ uae_u32 wrd[3];
+ from_exten_x(d, &wrd[0], &wrd[1], &wrd[2]);
+ softfloat_set(&fpd->fpx, wrd);
+ } else
+#endif
+ fpd->fp = d;
}
-void from_pack (fptype src, uae_u32 *wrd, int kfactor)
+void from_pack (fpdata *src, uae_u32 *wrd, int kfactor)
{
int i, j, t;
int exp;
int ndigits;
char *cp, *strp;
char str[100];
+ fptype fp;
wrd[0] = wrd[1] = wrd[2] = 0;
- if (fpu_isnan (src) || fpu_isinfinity (src)) {
+ if (fp_is_nan (src) || fp_is_infinity (src)) {
wrd[0] |= (1 << 30) | (1 << 29) | (1 << 30); // YY=1
wrd[0] |= 0xfff << 16; // Exponent=FFF
// TODO: mantissa should be set if NAN
return;
}
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat) {
+ uae_u32 out[3];
+ softfloat_get(&src->fpx, out);
+ to_exten_x(&fp, out[0], out[1], out[2]);
+ } else
+#endif
+ fp = src->fp;
+
#if USE_LONG_DOUBLE
- sprintf (str, "%#.17Le", src);
+ sprintf (str, "%#.17Le", fp);
#else
- sprintf (str, "%#.17e", src);
+ sprintf (str, "%#.17e", fp);
#endif
// get exponent
wrd[0] |= t << 16;
}
+// 68040/060 does not support denormals
+static bool fault_if_no_denormal_support_pre(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *fpd, int size)
+{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented && currprefs.fpu_softfloat) {
+ Bit64u Sig = extractFloatx80Frac(fpd->fpx);
+ Bit32s Exp = extractFloatx80Exp(fpd->fpx);
+ if (Exp == 0 && Sig != 0) {
+ fpu_op_unimp(opcode, extra, ea, oldpc, FPU_EXP_UNIMP_DATATYPE_PRE, fpd, -1, size);
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+static bool fault_if_no_denormal_support_post(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *fpd, int size)
+{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat && currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
+ Bit64u Sig = extractFloatx80Frac(fpd->fpx);
+ Bit32s Exp = extractFloatx80Exp(fpd->fpx);
+ if (Exp == 0 && Sig != 0) {
+ fpu_op_unimp(opcode, extra, ea, oldpc, FPU_EXP_UNIMP_DATATYPE_POST, fpd, -1, size);
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr oldpc, uae_u32 *adp)
{
int size, mode, reg;
- uae_u32 ad = 0;
+ uae_u32 ad = 0, ad2;
static const int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
static const int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
uae_u32 exts[3];
if (fault_if_no_fpu (opcode, extra, 0, oldpc))
return -1;
*src = regs.fp[(extra >> 10) & 7];
+ if (fault_if_no_denormal_support_pre(opcode, extra, 0, oldpc, src, 2))
+ return -1;
return 1;
}
mode = (opcode >> 3) & 7;
switch (size)
{
case 6:
- src->fp = (fptype) (uae_s8) m68k_dreg (regs, reg);
+ fpset(src, (uae_s8) m68k_dreg (regs, reg));
break;
case 4:
- src->fp = (fptype) (uae_s16) m68k_dreg (regs, reg);
+ fpset(src, (uae_s16) m68k_dreg (regs, reg));
break;
case 0:
- src->fp = (fptype) (uae_s32) m68k_dreg (regs, reg);
+ fpset(src, (uae_s32) m68k_dreg (regs, reg));
break;
case 1:
- src->fp = to_single (m68k_dreg (regs, reg));
+ to_single (src, m68k_dreg (regs, reg));
+ if (fault_if_no_denormal_support_pre(opcode, extra, 0, oldpc, src, 0))
+ return -1;
break;
default:
return 0;
}
*adp = ad;
+ ad2 = ad;
if (currprefs.fpu_model == 68060 && fault_if_unimplemented_680x0 (opcode, extra, ad, oldpc, src, -1))
return -1;
switch (size)
{
case 0:
- src->fp = (fptype) (uae_s32) (doext ? exts[0] : x_cp_get_long (ad));
+ fpset(src, (uae_s32) (doext ? exts[0] : x_cp_get_long (ad)));
break;
case 1:
- src->fp = to_single ((doext ? exts[0] : x_cp_get_long (ad)));
+ to_single (src, (doext ? exts[0] : x_cp_get_long (ad)));
+ if (fault_if_no_denormal_support_pre(opcode, extra, 0, oldpc, src, 0))
+ return -1;
break;
case 2:
{
ad += 4;
wrd3 = (doext ? exts[2] : x_cp_get_long (ad));
to_exten (src, wrd1, wrd2, wrd3);
+ if (fault_if_no_denormal_support_pre(opcode, extra, 0, oldpc, src, 2))
+ return -1;
}
break;
case 3:
wrd[2] = (doext ? exts[2] : x_cp_get_long (ad));
if (fault_if_4060 (opcode, extra, adold, oldpc, FPU_EXP_UNIMP_DATATYPE_PACKED_PRE, NULL, wrd))
return -1;
- src->fp = to_pack (wrd);
+ to_pack (src, wrd);
+ return 1;
}
break;
case 4:
- src->fp = (fptype) (uae_s16) (doext ? exts[0] : x_cp_get_word (ad));
+ fpset(src, (uae_s16) (doext ? exts[0] : x_cp_get_word (ad)));
break;
case 5:
{
wrd1 = (doext ? exts[0] : x_cp_get_long (ad));
ad += 4;
wrd2 = (doext ? exts[1] : x_cp_get_long (ad));
- src->fp = to_double (wrd1, wrd2);
+ to_double (src, wrd1, wrd2);
+ if (fault_if_no_denormal_support_pre(opcode, extra, 0, oldpc, src, 1))
+ return -1;
}
break;
case 6:
- src->fp = (fptype) (uae_s8) (doext ? exts[0] : x_cp_get_byte (ad));
+ fpset(src, (uae_s8) (doext ? exts[0] : x_cp_get_byte (ad)));
break;
default:
return 0;
#if DEBUG_FPP
if (!isinrom ())
write_log (_T("PUTFP: %f %04X %04X\n"), value, opcode, extra);
-#endif
-#ifdef USE_SOFT_LONG_DOUBLE
- value->fpx = false;
#endif
if (!(extra & 0x4000)) {
if (fault_if_no_fpu (opcode, extra, 0, oldpc))
switch (size)
{
case 6:
- m68k_dreg (regs, reg) = (uae_u32)(((toint (value->fp, -128.0, 127.0) & 0xff)
+ m68k_dreg (regs, reg) = (uae_u32)(((toint (value, 0) & 0xff)
| (m68k_dreg (regs, reg) & ~0xff)));
break;
case 4:
- m68k_dreg (regs, reg) = (uae_u32)(((toint (value->fp, -32768.0, 32767.0) & 0xffff)
+ m68k_dreg (regs, reg) = (uae_u32)(((toint (value, 1) & 0xffff)
| (m68k_dreg (regs, reg) & ~0xffff)));
break;
case 0:
- m68k_dreg (regs, reg) = (uae_u32)toint (value->fp, -2147483648.0, 2147483647.0);
+ m68k_dreg (regs, reg) = (uae_u32)toint (value, 2);
break;
case 1:
- m68k_dreg (regs, reg) = from_single (value->fp);
+ m68k_dreg (regs, reg) = from_single (value);
break;
default:
return 0;
switch (size)
{
case 0:
- x_cp_put_long (ad, (uae_u32)toint (value->fp, -2147483648.0, 2147483647.0));
+ if (fault_if_no_denormal_support_post(opcode, extra, ad, oldpc, value, 2))
+ return 1;
+ x_cp_put_long(ad, (uae_u32)toint(value, 2));
break;
case 1:
- x_cp_put_long (ad, from_single (value->fp));
+ if (fault_if_no_denormal_support_post(opcode, extra, ad, oldpc, value, 2))
+ return -1;
+ x_cp_put_long(ad, from_single(value));
break;
case 2:
{
uae_u32 wrd1, wrd2, wrd3;
- from_exten (value, &wrd1, &wrd2, &wrd3);
+ if (fault_if_no_denormal_support_post(opcode, extra, ad, oldpc, value, 2))
+ return 1;
+ from_exten(value, &wrd1, &wrd2, &wrd3);
x_cp_put_long (ad, wrd1);
ad += 4;
x_cp_put_long (ad, wrd2);
uae_u32 wrd[3];
int kfactor;
if (fault_if_4060 (opcode, extra, ad, oldpc, FPU_EXP_UNIMP_DATATYPE_PACKED_POST, value, NULL))
- return -1;
+ return 1;
kfactor = size == 7 ? m68k_dreg (regs, (extra >> 4) & 7) : extra;
kfactor &= 127;
if (kfactor & 64)
kfactor |= ~63;
- from_pack (value->fp, wrd, kfactor);
+ from_pack (value, wrd, kfactor);
x_cp_put_long (ad, wrd[0]);
ad += 4;
x_cp_put_long (ad, wrd[1]);
}
break;
case 4:
- x_cp_put_word (ad, (uae_s16) toint (value->fp, -32768.0, 32767.0));
+ if (fault_if_no_denormal_support_post(opcode, extra, ad, oldpc, value, 2))
+ return 1;
+ x_cp_put_word(ad, (uae_s16)toint(value, 1));
break;
case 5:
{
uae_u32 wrd1, wrd2;
- from_double (value->fp, &wrd1, &wrd2);
+ if (fault_if_no_denormal_support_post(opcode, extra, ad, oldpc, value, 1))
+ return -1;
+ from_double(value, &wrd1, &wrd2);
x_cp_put_long (ad, wrd1);
ad += 4;
x_cp_put_long (ad, wrd2);
}
break;
case 6:
- x_cp_put_byte (ad, (uae_s8)toint (value->fp, -128.0, 127.0));
+ if (fault_if_no_denormal_support_post(opcode, extra, ad, oldpc, value, 2))
+ return 1;
+ x_cp_put_byte(ad, (uae_s8)toint(value, 0));
break;
default:
return 0;
int fpp_cond (int condition)
{
- int N = (regs.fp_result.fp < 0.0);
- int Z = (regs.fp_result.fp == 0.0);
- int NotANumber = 0;
+ int NotANumber, Z, N;
-#ifdef HAVE_ISNAN
- NotANumber = isnan (regs.fp_result.fp);
-#endif
+ NotANumber = fp_is_nan(®s.fp_result);
+ N = fp_is_neg(®s.fp_result);
+ Z = fp_is_zero(®s.fp_result);
- if (NotANumber)
- N=Z=0;
+ if ((condition & 0x10) && NotANumber)
+ regs.fp_result_status |= FP_BSUN;
switch (condition)
{
from_exten(®s.exp_src1, &src1[0], &src1[1], &src1[2]);
from_exten(®s.exp_src2, &src2[0], &src2[1], &src2[2]);
- stag = get_ftag(src1[0], src1[1], src1[2]);
- dtag = get_ftag(src2[0], src2[1], src2[2]);
+ stag = get_ftag(src1[0], src1[1], src1[2], regs.exp_size);
+ dtag = get_ftag(src2[0], src2[1], src2[2], -1);
if ((extra & 0x7f) == 4) // FSQRT 4->5
extra |= 1;
write_log(_T("68040 FSAVE %d (%d), CMDREG=%04X"), regs.exp_type, frame_size, extra);
if (regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE) {
write_log(_T(" PACKED %08x-%08x-%08x"), regs.exp_pack[0], regs.exp_pack[1], regs.exp_pack[2]);
- } else {
+ } else if (regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PACKED_POST) {
#if USE_LONG_DOUBLE
write_log(_T(" SRC=%Le (%08x-%08x-%08x %d), DST=%Le (%08x-%08x-%08x %d)"), regs.exp_src1.fp, src1[0], src1[1], src1[2], stag, regs.exp_src2.fp, src2[0], src2[1], src2[2], dtag);
#else
m68k_areg (regs, opcode & 7) = ad;
}
-static void fround (int reg)
-{
- regs.fp[reg].fp = (float)regs.fp[reg].fp;
-}
-
static uaecptr fmovem2mem (uaecptr ad, uae_u32 list, int incr, int regdir)
{
int reg;
return ad;
}
+// round to float
+static void fround (int reg)
+{
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat) {
+ float32 f = floatx80_to_float32(regs.fp[reg].fpx, fxstatus);
+ regs.fp[reg].fpx = float32_to_floatx80(f, fxstatus);
+ } else
+#endif
+ regs.fp[reg].fp = (float)regs.fp[reg].fp;
+}
+
+static bool arithmetic_fp(fptype src, int reg, int extra)
+{
+ bool sgl = false;
+ switch (extra & 0x7f)
+ {
+ case 0x00: /* FMOVE */
+ case 0x40: /* Explicit rounding. This is just a quick fix. */
+ case 0x44: /* Same for all other cases that have three choices */
+ regs.fp[reg].fp = src; /* Brian King was here. */
+ /*<ea> to register needs FPSR updated. See Motorola 68K Manual. */
+ break;
+ case 0x01: /* FINT */
+ /* need to take the current rounding mode into account */
+#if defined(X86_MSVC_ASSEMBLY_FPU)
+ {
+ fptype tmp_fp;
+ __asm {
+ fld LDPTR src
+ frndint
+ fstp LDPTR tmp_fp
+ }
+ regs.fp[reg].fp = tmp_fp;
+ }
+#else /* no X86_MSVC */
+ switch (regs.fpcr & 0x30)
+ {
+ case FPCR_ROUND_NEAR:
+ regs.fp[reg].fp = fp_round_to_nearest(src);
+ break;
+ case FPCR_ROUND_ZERO:
+ regs.fp[reg].fp = fp_round_to_zero(src);
+ break;
+ case FPCR_ROUND_MINF:
+ regs.fp[reg].fp = fp_round_to_minus_infinity(src);
+ break;
+ case FPCR_ROUND_PINF:
+ regs.fp[reg].fp = fp_round_to_plus_infinity(src);
+ break;
+ default: /* never reached */
+ regs.fp[reg].fp = src;
+ break;
+ }
+#endif /* X86_MSVC */
+ break;
+ case 0x02: /* FSINH */
+ regs.fp[reg].fp = sinh (src);
+ break;
+ case 0x03: /* FINTRZ */
+ regs.fp[reg].fp = fp_round_to_zero (src);
+ break;
+ case 0x04: /* FSQRT */
+ case 0x41: /* FSSQRT */
+ case 0x45: /* FDSQRT */
+ regs.fp[reg].fp = sqrt (src);
+ break;
+ case 0x06: /* FLOGNP1 */
+ regs.fp[reg].fp = log (src + 1.0);
+ break;
+ case 0x08: /* FETOXM1 */
+ regs.fp[reg].fp = exp (src) - 1.0;
+ break;
+ case 0x09: /* FTANH */
+ regs.fp[reg].fp = tanh (src);
+ break;
+ case 0x0a: /* FATAN */
+ regs.fp[reg].fp = atan (src);
+ break;
+ case 0x0c: /* FASIN */
+ regs.fp[reg].fp = asin (src);
+ break;
+ case 0x0d: /* FATANH */
+ regs.fp[reg].fp = atanh (src);
+ break;
+ case 0x0e: /* FSIN */
+ regs.fp[reg].fp = sin (src);
+ break;
+ case 0x0f: /* FTAN */
+ regs.fp[reg].fp = tan (src);
+ break;
+ case 0x10: /* FETOX */
+ regs.fp[reg].fp = exp (src);
+ break;
+ case 0x11: /* FTWOTOX */
+ regs.fp[reg].fp = pow (2.0, src);
+ break;
+ case 0x12: /* FTENTOX */
+ regs.fp[reg].fp = pow (10.0, src);
+ break;
+ case 0x14: /* FLOGN */
+ regs.fp[reg].fp = log (src);
+ break;
+ case 0x15: /* FLOG10 */
+ regs.fp[reg].fp = log10 (src);
+ break;
+ case 0x16: /* FLOG2 */
+ regs.fp[reg].fp = *fp_l2_e * log (src);
+ break;
+ case 0x18: /* FABS */
+ case 0x58: /* FSABS */
+ case 0x5c: /* FDABS */
+ regs.fp[reg].fp = src < 0 ? -src : src;
+ break;
+ case 0x19: /* FCOSH */
+ regs.fp[reg].fp = cosh (src);
+ break;
+ case 0x1a: /* FNEG */
+ case 0x5a: /* FSNEG */
+ case 0x5e: /* FDNEG */
+ regs.fp[reg].fp = -src;
+ break;
+ case 0x1c: /* FACOS */
+ regs.fp[reg].fp = acos (src);
+ break;
+ case 0x1d: /* FCOS */
+ regs.fp[reg].fp = cos (src);
+ break;
+ case 0x1e: /* FGETEXP */
+ {
+ if (src == 0) {
+ regs.fp[reg].fp = 0;
+ } else {
+ int expon;
+ frexp (src, &expon);
+ regs.fp[reg].fp = (double) (expon - 1);
+ }
+ }
+ break;
+ case 0x1f: /* FGETMAN */
+ {
+ if (src == 0) {
+ regs.fp[reg].fp = 0;
+ } else {
+ int expon;
+ regs.fp[reg].fp = frexp (src, &expon) * 2.0;
+ }
+ }
+ break;
+ case 0x20: /* FDIV */
+ case 0x60: /* FSDIV */
+ case 0x64: /* FDDIV */
+ regs.fp[reg].fp /= src;
+ break;
+ case 0x21: /* FMOD */
+ {
+ fptype quot = fp_round_to_zero(regs.fp[reg].fp / src);
+ regs.fp[reg].fp = regs.fp[reg].fp - quot * src;
+ }
+ break;
+ case 0x22: /* FADD */
+ case 0x62: /* FSADD */
+ case 0x66: /* FDADD */
+ regs.fp[reg].fp += src;
+ break;
+ case 0x23: /* FMUL */
+ case 0x63: /* FSMUL */
+ case 0x67: /* FDMUL */
+ regs.fp[reg].fp *= src;
+ break;
+ case 0x24: /* FSGLDIV */
+ regs.fp[reg].fp /= src;
+ sgl = true;
+ break;
+ case 0x25: /* FREM */
+ {
+ fptype quot = fp_round_to_nearest(regs.fp[reg].fp / src);
+ regs.fp[reg].fp = regs.fp[reg].fp - quot * src;
+ }
+ break;
+ case 0x26: /* FSCALE */
+ if (src != 0) {
+#ifdef ldexp
+ regs.fp[reg] = ldexp (regs.fp[reg], (int) src);
+#else
+ regs.fp[reg].fp *= exp (*fp_ln_2 * (int) src);
+#endif
+ }
+ break;
+ case 0x27: /* FSGLMUL */
+ regs.fp[reg].fp *= src;
+ sgl = true;
+ break;
+ case 0x28: /* FSUB */
+ case 0x68: /* FSSUB */
+ case 0x6c: /* FDSUB */
+ regs.fp[reg].fp -= src;
+ break;
+ case 0x30: /* FSINCOS */
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ regs.fp[extra & 7].fp = cos (src);
+ regs.fp[reg].fp = sin (src);
+ break;
+ case 0x38: /* FCMP */
+ {
+ fptype tmp = regs.fp[reg].fp - src;
+ regs.fpsr = 0;
+ MAKE_FPSR (&tmp);
+ }
+ return true;
+ case 0x3a: /* FTST */
+ regs.fpsr = 0;
+ MAKE_FPSR (&src);
+ return true;
+ default:
+ return false;
+ }
+ // round to float?
+ if (sgl || (extra & 0x44) == 0x40)
+ fround (reg);
+ MAKE_FPSR (®s.fp[reg].fp);
+ return true;
+}
+
+#ifdef WITH_SOFTFLOAT
+static bool arithmetic_softfloat(floatx80 *srcd, int reg, int extra)
+{
+ floatx80 fx = *srcd;
+ floatx80 f = regs.fp[reg].fpx;
+ int float_rounding_mode;
+ bool sgl = false;
+ Bit64u q;
+
+ // SNAN -> QNAN if SNAN interrupt is not enabled
+ if (floatx80_is_signaling_nan(fx) && !(regs.fpcr & 0x4000)) {
+ fx.fraction |= 0x40000000;
+ }
+
+ switch (extra & 0x7f)
+ {
+ case 0x00: /* FMOVE */
+ case 0x40:
+ case 0x44:
+ regs.fp[reg].fpx = fx;
+ break;
+ case 0x01: /* FINT */
+ regs.fp[reg].fpx = floatx80_round_to_int(fx, fxstatus);
+ break;
+ case 0x03: /* FINTRZ */
+ float_rounding_mode = fxstatus.float_rounding_mode;
+ fxstatus.float_rounding_mode = float_round_to_zero;
+ regs.fp[reg].fpx = floatx80_round_to_int(fx, fxstatus);
+ float_rounding_mode = fxstatus.float_rounding_mode;
+ break;
+ case 0x04: /* FSQRT */
+ case 0x41: /* FSSQRT */
+ case 0x45: /* FDSQRT */
+ regs.fp[reg].fpx = floatx80_sqrt(fx, fxstatus);
+ break;
+ case 0x18: /* FABS */
+ case 0x58: /* FSABS */
+ case 0x5c: /* FDABS */
+ regs.fp[reg].fpx = floatx80_abs(fx);
+ break;
+ case 0x1a: /* FNEG */
+ case 0x5a: /* FSNEG */
+ case 0x5e: /* FDNEG */
+ // same here..
+ regs.fp[reg].fpx = floatx80_chs(fx);
+ break;
+ case 0x20: /* FDIV */
+ case 0x60: /* FSDIV */
+ case 0x64: /* FDDIV */
+ regs.fp[reg].fpx = floatx80_div(f, fx, fxstatus);
+ break;
+ case 0x22: /* FADD */
+ case 0x62: /* FSADD */
+ case 0x66: /* FDADD */
+ regs.fp[reg].fpx = floatx80_add(f, fx, fxstatus);
+ break;
+ case 0x23: /* FMUL */
+ case 0x63: /* FSMUL */
+ case 0x67: /* FDMUL */
+ regs.fp[reg].fpx = floatx80_mul(f, fx, fxstatus);
+ break;
+ case 0x24: /* FSGLDIV */
+ regs.fp[reg].fpx = floatx80_div(f, fx, fxstatus);
+ sgl = true;
+ break;
+ case 0x25: /* FREM */
+ floatx80_ieee754_remainder(f, fx, regs.fp[reg].fpx, q, fxstatus);
+ break;
+ case 0x27: /* FSGLMUL */
+ regs.fp[reg].fpx = floatx80_mul(f, fx, fxstatus);
+ sgl = true;
+ break;
+ case 0x28: /* FSUB */
+ case 0x68: /* FSSUB */
+ case 0x6c: /* FDSUB */
+ regs.fp[reg].fpx = floatx80_sub(f, fx, fxstatus);
+ break;
+ case 0x38: /* FCMP */
+ f = floatx80_sub(f, fx, fxstatus);
+ regs.fpsr = 0;
+ MAKE_FPSR_SOFTFLOAT(f);
+ return true;
+ case 0x3a: /* FTST */
+ regs.fpsr = 0;
+ MAKE_FPSR_SOFTFLOAT(f);
+ return true;
+
+ case 0x1d: /* FCOS */
+ fcos(f, fxstatus);
+ regs.fp[reg].fpx = f;
+ break;
+ case 0x0e: /* FSIN */
+ fsin(f, fxstatus);
+ regs.fp[reg].fpx = f;
+ break;
+ case 0x0f: /* FTAN */
+ ftan(f, fxstatus);
+ regs.fp[reg].fpx = f;
+ break;
+ case 0x30: /* FSINCOS */
+ case 0x31: /* FSINCOS */
+ case 0x32: /* FSINCOS */
+ case 0x33: /* FSINCOS */
+ case 0x34: /* FSINCOS */
+ case 0x35: /* FSINCOS */
+ case 0x36: /* FSINCOS */
+ case 0x37: /* FSINCOS */
+ fsincos(f, ®s.fp[extra & 7].fpx, ®s.fp[reg].fpx, fxstatus);
+ break;
+
+ // some of following are supported by softfloat, later..
+ case 0x06: /* FLOGNP1 */
+ case 0x08: /* FETOXM1 */
+ case 0x09: /* FTANH */
+ case 0x0a: /* FATAN */
+ case 0x0c: /* FASIN */
+ case 0x0d: /* FATANH */
+ case 0x10: /* FETOX */
+ case 0x11: /* FTWOTOX */
+ case 0x12: /* FTENTOX */
+ case 0x14: /* FLOGN */
+ case 0x15: /* FLOG10 */
+ case 0x16: /* FLOG2 */
+ case 0x19: /* FCOSH */
+ case 0x1c: /* FACOS */
+ case 0x1e: /* FGETEXP */
+ case 0x1f: /* FGETMAN */
+ {
+ // This is horribly ineffective..
+ fptype fp;
+ uae_u32 out[3];
+ // convert softfloat to raw words
+ softfloat_get(&fx, out);
+ // convert to double/long double
+ to_exten_x(&fp, out[0], out[1], out[2]);
+ // emulate instruction using normal fpu code
+ if (!arithmetic_fp(fp, reg, extra))
+ return false;
+ // convert back to raw
+ from_exten_x(regs.fp[reg].fp, &out[0], &out[1], &out[2]);
+ // convert to softfloat internal format
+ softfloat_set(®s.fp[reg].fpx, out);
+ MAKE_FPSR_SOFTFLOAT(regs.fp[reg].fpx);
+ }
+ break;
+ }
+ return true;
+}
+#endif
+
static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
{
int reg = -1;
int v;
- fptype src;
fpdata srcd;
uaecptr pc = m68k_getpc () - 4;
uaecptr ad = 0;
- bool sgl;
#if DEBUG_FPP
if (!isinrom ())
case 2: /* Extremely common */
regs.fpiar = pc;
reg = (extra >> 7) & 7;
-#ifdef USE_SOFT_LONG_DOUBLE
- regs.fp[reg].fpx = false;
-#endif
if ((extra & 0xfc00) == 0x5c00) {
if (fault_if_no_fpu (opcode, extra, 0, pc))
return;
fpu_noinst (opcode, pc);
return;
}
- src = srcd.fp;
// get_fp_value() checked this, but only if EA was nonzero (non-register)
if (fault_if_unimplemented_680x0 (opcode, extra, ad, pc, &srcd, reg))
regs.fpiar = pc;
CLEAR_STATUS ();
- sgl = false;
- switch (extra & 0x7f)
- {
- case 0x00: /* FMOVE */
- case 0x40: /* Explicit rounding. This is just a quick fix. */
- case 0x44: /* Same for all other cases that have three choices */
- regs.fp[reg].fp = src; /* Brian King was here. */
- /*<ea> to register needs FPSR updated. See Motorola 68K Manual. */
- break;
- case 0x01: /* FINT */
- /* need to take the current rounding mode into account */
-#if defined(X86_MSVC_ASSEMBLY_FPU)
- {
- fptype tmp_fp;
-
- __asm {
- fld LDPTR src
- frndint
- fstp LDPTR tmp_fp
- }
- regs.fp[reg].fp = tmp_fp;
- }
-#else /* no X86_MSVC */
- switch (regs.fpcr & 0x30)
- {
- case FPCR_ROUND_NEAR:
- regs.fp[reg].fp = fp_round_to_nearest(src);
- break;
- case FPCR_ROUND_ZERO:
- regs.fp[reg].fp = fp_round_to_zero(src);
- break;
- case FPCR_ROUND_MINF:
- regs.fp[reg].fp = fp_round_to_minus_infinity(src);
- break;
- case FPCR_ROUND_PINF:
- regs.fp[reg].fp = fp_round_to_plus_infinity(src);
- break;
- default: /* never reached */
- regs.fp[reg].fp = src;
- break;
- }
-#endif /* X86_MSVC */
- break;
- case 0x02: /* FSINH */
- regs.fp[reg].fp = sinh (src);
- break;
- case 0x03: /* FINTRZ */
- regs.fp[reg].fp = fp_round_to_zero (src);
- break;
- case 0x04: /* FSQRT */
- case 0x41: /* FSSQRT */
- case 0x45: /* FDSQRT */
- regs.fp[reg].fp = sqrt (src);
- break;
- case 0x06: /* FLOGNP1 */
- regs.fp[reg].fp = log (src + 1.0);
- break;
- case 0x08: /* FETOXM1 */
- regs.fp[reg].fp = exp (src) - 1.0;
- break;
- case 0x09: /* FTANH */
- regs.fp[reg].fp = tanh (src);
- break;
- case 0x0a: /* FATAN */
- regs.fp[reg].fp = atan (src);
- break;
- case 0x0c: /* FASIN */
- regs.fp[reg].fp = asin (src);
- break;
- case 0x0d: /* FATANH */
- regs.fp[reg].fp = atanh (src);
- break;
- case 0x0e: /* FSIN */
- regs.fp[reg].fp = sin (src);
- break;
- case 0x0f: /* FTAN */
- regs.fp[reg].fp = tan (src);
- break;
- case 0x10: /* FETOX */
- regs.fp[reg].fp = exp (src);
- break;
- case 0x11: /* FTWOTOX */
- regs.fp[reg].fp = pow (2.0, src);
- break;
- case 0x12: /* FTENTOX */
- regs.fp[reg].fp = pow (10.0, src);
- break;
- case 0x14: /* FLOGN */
- regs.fp[reg].fp = log (src);
- break;
- case 0x15: /* FLOG10 */
- regs.fp[reg].fp = log10 (src);
- break;
- case 0x16: /* FLOG2 */
- regs.fp[reg].fp = *fp_l2_e * log (src);
- break;
- case 0x18: /* FABS */
- case 0x58: /* FSABS */
- case 0x5c: /* FDABS */
- regs.fp[reg].fp = src < 0 ? -src : src;
- break;
- case 0x19: /* FCOSH */
- regs.fp[reg].fp = cosh (src);
- break;
- case 0x1a: /* FNEG */
- case 0x5a: /* FSNEG */
- case 0x5e: /* FDNEG */
- regs.fp[reg].fp = -src;
- break;
- case 0x1c: /* FACOS */
- regs.fp[reg].fp = acos (src);
- break;
- case 0x1d: /* FCOS */
- regs.fp[reg].fp = cos (src);
- break;
- case 0x1e: /* FGETEXP */
- {
- if (src == 0) {
- regs.fp[reg].fp = 0;
- } else {
- int expon;
- frexp (src, &expon);
- regs.fp[reg].fp = (double) (expon - 1);
- }
- }
- break;
- case 0x1f: /* FGETMAN */
- {
- if (src == 0) {
- regs.fp[reg].fp = 0;
- } else {
- int expon;
- regs.fp[reg].fp = frexp (src, &expon) * 2.0;
- }
- }
- break;
- case 0x20: /* FDIV */
- case 0x60: /* FSDIV */
- case 0x64: /* FDDIV */
- regs.fp[reg].fp /= src;
- break;
- case 0x21: /* FMOD */
- {
- fptype quot = fp_round_to_zero(regs.fp[reg].fp / src);
- regs.fp[reg].fp = regs.fp[reg].fp - quot * src;
- }
- break;
- case 0x22: /* FADD */
- case 0x62: /* FSADD */
- case 0x66: /* FDADD */
- regs.fp[reg].fp += src;
- break;
- case 0x23: /* FMUL */
- case 0x63: /* FSMUL */
- case 0x67: /* FDMUL */
- regs.fp[reg].fp *= src;
- break;
- case 0x24: /* FSGLDIV */
- regs.fp[reg].fp /= src;
- sgl = true;
- break;
- case 0x25: /* FREM */
- {
- fptype quot = fp_round_to_nearest(regs.fp[reg].fp / src);
- regs.fp[reg].fp = regs.fp[reg].fp - quot * src;
- }
- break;
- case 0x26: /* FSCALE */
- if (src != 0) {
-#ifdef ldexp
- regs.fp[reg] = ldexp (regs.fp[reg], (int) src);
-#else
- regs.fp[reg].fp *= exp (*fp_ln_2 * (int) src);
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat)
+ v = arithmetic_softfloat(&srcd.fpx, reg, extra);
+ else
#endif
- }
- break;
- case 0x27: /* FSGLMUL */
- regs.fp[reg].fp *= src;
- sgl = true;
- break;
- case 0x28: /* FSUB */
- case 0x68: /* FSSUB */
- case 0x6c: /* FDSUB */
- regs.fp[reg].fp -= src;
- break;
- case 0x30: /* FSINCOS */
- case 0x31:
- case 0x32:
- case 0x33:
- case 0x34:
- case 0x35:
- case 0x36:
- case 0x37:
- regs.fp[extra & 7].fp = cos (src);
- regs.fp[reg].fp = sin (src);
- break;
- case 0x38: /* FCMP */
- {
- fptype tmp = regs.fp[reg].fp - src;
- regs.fpsr = 0;
- MAKE_FPSR (&tmp);
- }
- return;
- case 0x3a: /* FTST */
- regs.fpsr = 0;
- MAKE_FPSR (&src);
- return;
- default:
- fpu_noinst (opcode, pc);
- return;
- }
- // round to float?
- if (sgl || (extra & 0x44) == 0x40)
- fround (reg);
- MAKE_FPSR (®s.fp[reg].fp);
+ v = arithmetic_fp(srcd.fp, reg, extra);
+ if (!v)
+ fpu_noinst (opcode, pc);
return;
default:
break;
if (fpu_mmu_fixup) {
mmufixup[0].reg = -1;
}
-#if 0
- // Any exception status bit and matching exception enable bits set?
- if ((regs.fpcr >> 8) & (regs.fpsr >> 8)) {
- uae_u32 mask = regs.fpcr >> 8;
- int vector = 0;
- for (int i = 7; i >= 0; i--) {
- if (mask & (1 << i)) {
- if (i > 0)
- i--;
- vector = i + 48;
- break;
+#ifdef WITH_SOFTFLOAT
+ if (currprefs.fpu_softfloat) {
+ // Any exception status bit and matching exception enable bits set?
+ if ((regs.fpcr >> 8) & (regs.fpsr >> 8)) {
+ uae_u32 mask = regs.fpcr >> 8;
+ int vector = 0;
+ for (int i = 7; i >= 0; i--) {
+ if (mask & (1 << i)) {
+ if (i > 0)
+ i--;
+ vector = i + 48;
+ break;
+ }
}
+ // logging only so far
+ write_log (_T("FPU exception: %08x %d!\n"), regs.fpsr, vector);
}
- // logging only so far
- write_log (_T("FPU exception: %08x %d!\n"), regs.fpsr, vector);
}
#endif
}
fpset (®s.fp_result, 1);
native_set_fpucw (regs.fpcr);
fpux_restore (NULL);
+
+#ifdef WITH_SOFTFLOAT
+ fxsizes[0] = int32_to_floatx80(-128);
+ fxsizes[1] = int32_to_floatx80(127);
+ fxsizes[2] = int32_to_floatx80(-32768);
+ fxsizes[3] = int32_to_floatx80(32767);
+ fxsizes[4] = int32_to_floatx80(-2147483648);
+ fxsizes[5] = int32_to_floatx80(2147483647);
+ fxzero = int32_to_floatx80(0);
+ fx_1e0 = int32_to_floatx80(1);
+ fx_1e1 = int32_to_floatx80(10);
+ fx_1e2 = int32_to_floatx80(100);
+ fx_1e4 = int32_to_floatx80(10000);
+ fx_1e8 = int32_to_floatx80(100000000);
+#endif
}
uae_u8 *restore_fpu (uae_u8 *src)
changed_prefs.fpu_model = currprefs.fpu_model = restore_u32 ();
flags = restore_u32 ();
for (i = 0; i < 8; i++) {
- w1 = restore_u32 ();
+ w1 = restore_u16 () << 16;
w2 = restore_u32 ();
- w3 = restore_u16 ();
+ w3 = restore_u32 ();
to_exten (®s.fp[i], w1, w2, w3);
}
regs.fpcr = restore_u32 ();
restore_u32 ();
}
if (flags & 0x40000000) {
- w1 = restore_u32();
+ w1 = restore_u16() << 16;
w2 = restore_u32();
- w3 = restore_u16();
+ w3 = restore_u32();
to_exten(®s.exp_src1, w1, w2, w3);
- w1 = restore_u32();
+ w1 = restore_u16() << 16;
w2 = restore_u32();
- w3 = restore_u16();
+ w3 = restore_u32();
to_exten(®s.exp_src2, w1, w2, w3);
regs.exp_pack[0] = restore_u32();
regs.exp_pack[1] = restore_u32();
save_u32 (0x80000000 | 0x40000000 | (regs.fpu_state == 0 ? 1 : 0) | (regs.fpu_exp_state ? 2 : 0) | (regs.fpu_exp_state > 1 ? 4 : 0));
for (i = 0; i < 8; i++) {
from_exten (®s.fp[i], &w1, &w2, &w3);
- save_u32 (w1);
+ save_u16 (w1 >> 16);
save_u32 (w2);
- save_u16 (w3);
+ save_u32 (w3);
}
save_u32 (regs.fpcr);
save_u32 (regs.fpsr);
save_u32 (0);
from_exten(®s.exp_src1, &w1, &w2, &w3);
- save_u32(w1);
+ save_u16(w1 >> 16);
save_u32(w2);
- save_u16(w3);
+ save_u32(w3);
from_exten(®s.exp_src2, &w1, &w2, &w3);
- save_u32(w1);
+ save_u16(w1 >> 16);
save_u32(w2);
- save_u16(w3);
+ save_u32(w3);
save_u32(regs.exp_pack[0]);
save_u32(regs.exp_pack[1]);
save_u32(regs.exp_pack[2]);
if (isa4000t (&addr)) {
if (addr >= NCR_ALT_OFFSET) {
addr &= NCR_MASK;
- v = (ncr_io_bget_a4000t (addr + 3) << 0) | (ncr_io_bget_a4000t (addr + 2) << 8) |
- (ncr_io_bget_a4000t (addr + 1) << 16) | (ncr_io_bget_a4000t (addr + 0) << 24);
+ v = (ncr710_io_bget_a4000t(addr + 3) << 0) | (ncr710_io_bget_a4000t(addr + 2) << 8) |
+ (ncr710_io_bget_a4000t(addr + 1) << 16) | (ncr710_io_bget_a4000t(addr + 0) << 24);
} else if (addr >= NCR_OFFSET) {
addr &= NCR_MASK;
- v = (ncr_io_bget_a4000t (addr + 3) << 0) | (ncr_io_bget_a4000t (addr + 2) << 8) |
- (ncr_io_bget_a4000t (addr + 1) << 16) | (ncr_io_bget_a4000t (addr + 0) << 24);
+ v = (ncr710_io_bget_a4000t(addr + 3) << 0) | (ncr710_io_bget_a4000t(addr + 2) << 8) |
+ (ncr710_io_bget_a4000t(addr + 1) << 16) | (ncr710_io_bget_a4000t(addr + 0) << 24);
}
return v;
}
if (isa4000t (&addr)) {
if (addr >= NCR_OFFSET) {
addr &= NCR_MASK;
- v = (ncr_io_bget_a4000t (addr) << 8) | ncr_io_bget_a4000t (addr + 1);
+ v = (ncr710_io_bget_a4000t(addr) << 8) | ncr710_io_bget_a4000t(addr + 1);
}
return v;
}
if (isa4000t (&addr)) {
if (addr >= NCR_OFFSET) {
addr &= NCR_MASK;
- return ncr_io_bget_a4000t (addr);
+ return ncr710_io_bget_a4000t(addr);
}
return 0;
}
if (isa4000t (&addr)) {
if (addr >= NCR_ALT_OFFSET) {
addr &= NCR_MASK;
- ncr_io_bput_a4000t (addr + 3, value >> 0);
- ncr_io_bput_a4000t (addr + 2, value >> 8);
- ncr_io_bput_a4000t (addr + 1, value >> 16);
- ncr_io_bput_a4000t (addr + 0, value >> 24);
+ ncr710_io_bput_a4000t(addr + 3, value >> 0);
+ ncr710_io_bput_a4000t(addr + 2, value >> 8);
+ ncr710_io_bput_a4000t(addr + 1, value >> 16);
+ ncr710_io_bput_a4000t(addr + 0, value >> 24);
} else if (addr >= NCR_OFFSET) {
addr &= NCR_MASK;
- ncr_io_bput_a4000t (addr + 3, value >> 0);
- ncr_io_bput_a4000t (addr + 2, value >> 8);
- ncr_io_bput_a4000t (addr + 1, value >> 16);
- ncr_io_bput_a4000t (addr + 0, value >> 24);
+ ncr710_io_bput_a4000t(addr + 3, value >> 0);
+ ncr710_io_bput_a4000t(addr + 2, value >> 8);
+ ncr710_io_bput_a4000t(addr + 1, value >> 16);
+ ncr710_io_bput_a4000t(addr + 0, value >> 24);
}
return;
}
if (isa4000t (&addr)) {
if (addr >= NCR_OFFSET) {
addr &= NCR_MASK;
- ncr_io_bput_a4000t (addr, value >> 8);
- ncr_io_bput_a4000t (addr + 1, value);
+ ncr710_io_bput_a4000t(addr, value >> 8);
+ ncr710_io_bput_a4000t(addr + 1, value);
}
return;
}
if (isa4000t (&addr)) {
if (addr >= NCR_OFFSET) {
addr &= NCR_MASK;
- ncr_io_bput_a4000t (addr, value);
+ ncr710_io_bput_a4000t(addr, value);
}
return;
}
*p++= 4; /* PCMCIA 2.1 */
*p++= 1;
if (real) {
- ua_copy ((char*)p, -1, hfd->product_id);
+ ua_copy ((char*)p, 8, hfd->product_id);
p += strlen ((char*)p) + 1;
- ua_copy ((char*)p, -1, hfd->product_rev);
+ ua_copy ((char*)p, 16, hfd->product_rev);
} else {
strcpy ((char*)p, "UAE");
p += strlen ((char*)p) + 1;
#ifdef NCR
if (currprefs.cs_mbdmac == 2) {
_tcscat (bankname, _T(" + NCR53C710 SCSI"));
- ncr_init ();
- ncr_reset ();
+ ncr710_init();
+ ncr710_reset();
}
#endif
gayle_bank.name = bankname;
printf ("#ifndef CPUEMU_68000_ONLY\n");
}
+static bool isce020(void)
+{
+ if (!using_ce020)
+ return false;
+ if (using_ce020 >= 3)
+ return false;
+ return true;
+}
+static bool isprefetch020(void)
+{
+ if (!using_prefetch_020)
+ return false;
+ if (using_prefetch_020 >= 3)
+ return false;
+ return true;
+}
static void addcycles_ce020 (int cycles, char *s)
{
- if (!using_ce020)
+ if (!isce020())
return;
if (cycles > 0) {
if (s == NULL)
static void get_prefetch_020 (void)
{
- if (!using_prefetch_020 || no_prefetch_ce020)
+ if (!isprefetch020() || no_prefetch_ce020)
return;
printf ("\tregs.irc = %s (%d);\n", prefetch_word, m68k_pc_offset);
}
static void get_prefetch_020_0 (void)
{
- if (!using_prefetch_020 || no_prefetch_ce020)
+ if (!isprefetch020() || no_prefetch_ce020)
return;
printf ("\tregs.irc = %s (0);\n", prefetch_word);
}
static void returntail (bool iswrite)
{
- if (!using_ce020) {
- if (using_prefetch_020) {
+ if (!isce020()) {
+ if (isprefetch020()) {
if (!tail_ce020_done) {
if (!did_prefetch)
get_prefetch_020 ();
static void addcycles_ce020 (char *name, int head, int tail, int cycles)
{
- if (!using_ce020)
+ if (!isce020())
return;
if (!head && !tail && !cycles)
return;
}
static void addcycles_ce020 (char *name, int head, int tail, int cycles, int ophead)
{
- if (!using_ce020)
+ if (!isce020())
return;
if (!head && !tail && !cycles && !ophead) {
printf ("\t/* OP zero */\n");
static void makefromsr (void)
{
printf ("\tMakeFromSR();\n");
- if (using_ce || using_ce020)
+ if (using_ce || isce020())
printf ("\tregs.ipl_pin = intlev ();\n");
}
{
if (ipl_fetched)
return;
- if (using_ce || using_ce020)
+ if (using_ce || isce020())
printf ("\tipl_fetch ();\n");
ipl_fetched = true;
}
fill_prefetch_1 (0);
irc2ir ();
fill_prefetch_1 (2);
- } else if (using_prefetch_020) {
+ } else if (isprefetch020()) {
did_prefetch = 2;
total_ce020 -= 4;
returntail (false);
static void add_head_cycs (int h)
{
- if (!using_ce020)
+ if (!isce020())
return;
head_ce020_cycs_done = false;
head_cycs (h);
static void addop_ce020 (instr *curi, int subhead)
{
- if (!using_ce020)
+ if (!isce020())
return;
int h = curi->head;
int t = curi->tail;
{
int oldfixup = mmufixupstate;
int subhead = 0;
- if (using_ce020 && curi) {
+ if (isce020() && curi) {
switch (curi->fetchmode)
{
case fetchmode_fea:
// we have fixup already active = this genamode call is destination mode and we can now clear previous source fixup.
clearmmufixup (0);
}
- if (using_ce020 && curi)
+ if (isce020() && curi)
addop_ce020 (curi, subhead);
}
int subhead = 0;
bool eadmode = false;
- if (using_ce020) {
+ if (isce020()) {
switch (curi->fetchmode)
{
case fetchmode_fea:
do_cycles = "do_cycles_ce020";
nextw = "next_iword_030ce";
nextl = "next_ilong_030ce";
+ } else if (using_ce020 == 3) {
+ // 68040/060 CE
+ disp020 = "x_get_disp_ea_040";
+ prefetch_long = "get_ilong_cache_040";
+ prefetch_word = "get_iword_cache_040";
+ srcli = "x_get_ilong";
+ srcwi = "x_get_iword";
+ srcbi = "x_get_ibyte";
+ srcl = "x_get_long";
+ dstl = "x_put_long";
+ srcw = "x_get_word";
+ dstw = "x_put_word";
+ srcb = "x_get_byte";
+ dstb = "x_put_byte";
+ do_cycles = "do_cycles_ce020";
+ nextw = "next_iword_cache040";
+ nextl = "next_ilong_cache040";
} else if (using_prefetch_020) {
disp020 = "x_get_disp_ea_020";
prefetch_word = "get_word_020_prefetch";
* - move.x xxx,[at least 1 extension word here] = fetch 1 extension word before (xxx)
*
*/
- if (using_ce020) {
+ if (isce020()) {
// MOVE is too complex to handle in table68k
int h = 0, t = 0, c = 0, subhead = 0;
bool fea = false;
break;
case i_BSR:
// .b/.w = idle cycle, store high, store low, 2xprefetch
- if (using_ce020)
+ if (isce020())
no_prefetch_ce020 = true;
printf ("\tuae_s32 s;\n");
if (curi->size == sz_long) {
}
postfix = id;
- if (id == 0 || id == 11 || id == 13 || id == 20 || id == 21 || id == 22 || id == 31 || id == 32 || id == 33) {
+ if (id == 0 || id == 11 || id == 13 || id == 20 || id == 21 || id == 22 || id == 23 || id == 31 || id == 32 || id == 33) {
if (generate_stbl)
fprintf (stblfile, "#ifdef CPUEMU_%d%s\n", postfix, extraup);
postfix2 = postfix;
read_counts ();
for (rp = 0; rp < nr_cpuop_funcs; rp++)
opcode_next_clev[rp] = cpu_level;
- } else if (id == 22 || id == 23 || id == 24) { // 68030/040/60 "cycle-exact"
- cpu_level = 3 + (24 - id);
+ } else if (id == 22) { // 68030 "cycle-exact"
+ cpu_level = 3;
using_ce020 = 2;
using_prefetch_020 = 2;
memory_cycle_cnt = 2;
- if (id == 22) {
- read_counts ();
+ read_counts ();
+ for (rp = 0; rp < nr_cpuop_funcs; rp++)
+ opcode_next_clev[rp] = cpu_level;
+ } else if (id == 23 || id == 24) { // 68040/060 "cycle-exact"
+ cpu_level = id == 23 ? 5 : 4;
+ using_ce020 = 3;
+ using_prefetch_020 = 3;
+ memory_cycle_cnt = 0;
+ if (id == 23) {
+ read_counts();
for (rp = 0; rp < nr_cpuop_funcs; rp++)
opcode_next_clev[rp] = cpu_level;
}
pl(rdb, 37, 0); // autopark
pl(rdb, 38, 2); // highrdskblock
pl(rdb, 39, -1); // res
- ua_copy ((char*)rdb + 40 * 4, -1, hfd->vendor_id);
- ua_copy ((char*)rdb + 42 * 4, -1, hfd->product_id);
- ua_copy ((char*)rdb + 46 * 4, -1, _T("UAE"));
+ ua_copy ((char*)rdb + 40 * 4, 8, hfd->vendor_id);
+ ua_copy ((char*)rdb + 42 * 4, 16, hfd->product_id);
+ ua_copy ((char*)rdb + 46 * 4, 4, _T("UAE"));
rdb_crc (rdb);
pl(part, 0, 0x50415254);
pl(part, 6, -1);
pl(part, 7, -1);
pl(part, 8, 0); // devflags
- part[9 * 4] = _tcslen (hfd->device_name);
- ua_copy ((char*)part + 9 * 4 + 1, -1, hfd->device_name);
+ part[9 * 4] = _tcslen (hfd->ci.devname);
+ ua_copy ((char*)part + 9 * 4 + 1, 30, hfd->ci.devname);
denv = part + 128;
pl(denv, 0, 80);
#ifdef CPUEMU_22
-extern uae_u32 get_word_ce030_prefetch (int);
-extern void write_dcache030 (uaecptr, uae_u32, int);
-extern uae_u32 read_dcache030 (uaecptr, int);
+extern uae_u32 get_word_ce030_prefetch(int);
STATIC_INLINE void put_long_ce030 (uaecptr addr, uae_u32 v)
{
write_dcache030 (addr, v, 2);
- mem_access_delay_long_write_ce020 (addr, v);
}
STATIC_INLINE void put_word_ce030 (uaecptr addr, uae_u32 v)
{
write_dcache030 (addr, v, 1);
- mem_access_delay_word_write_ce020 (addr, v);
}
STATIC_INLINE void put_byte_ce030 (uaecptr addr, uae_u32 v)
{
write_dcache030 (addr, v, 0);
- mem_access_delay_byte_write_ce020 (addr, v);
}
STATIC_INLINE uae_u32 get_long_ce030 (uaecptr addr)
{
m68k_areg (regs, 7) += 4;
}
-extern uae_u32 get_word_ce040_prefetch (int);
-
#endif
#ifdef CPUEMU_11
extern void cpuboard_init(void);
extern void cpuboard_clear(void);
extern void cpuboard_vsync(void);
+extern void cpuboard_rethink(void);
+
+extern void cyberstorm_scsi_ram_put(uaecptr addr, uae_u32);
+extern uae_u32 cyberstorm_scsi_ram_get(uaecptr addr);
+extern int REGPARAM3 cyberstorm_scsi_ram_check(uaecptr addr, uae_u32 size) REGPARAM;
+extern uae_u8 *REGPARAM3 cyberstorm_scsi_ram_xlate(uaecptr addr) REGPARAM;
extern addrbank blizzardram_bank;
#define BOARD_BLIZZARD_1230_IV 1
#define BOARD_BLIZZARD_1260 2
#define BOARD_BLIZZARD_2060 3
-#define BOARD_WARPENGINE_A4000 4
+#define BOARD_CSMK3 4
+#define BOARD_CSPPC 5
+#define BOARD_BLIZZARDPPC 6
+#define BOARD_WARPENGINE_A4000 7
+
extern uae_u16 REGPARAM3 mmu_get_word_unaligned(uaecptr addr, bool data, bool rmw) REGPARAM;
extern uae_u32 REGPARAM3 mmu_get_long_unaligned(uaecptr addr, bool data, bool rmw) REGPARAM;
+extern uae_u32 REGPARAM3 mmu_get_ilong_unaligned(uaecptr addr) REGPARAM;
+
extern uae_u8 REGPARAM3 mmu_get_byte_slow(uaecptr addr, bool super, bool data,
int size, bool rmw, struct mmu_atc_line *cl) REGPARAM;
extern uae_u16 REGPARAM3 mmu_get_word_slow(uaecptr addr, bool super, bool data,
extern uae_u32 REGPARAM3 mmu_get_long_slow(uaecptr addr, bool super, bool data,
int size, bool rmw, struct mmu_atc_line *cl) REGPARAM;
+extern uae_u16 REGPARAM3 mmu_get_iword_slow(uaecptr addr, bool super,
+ int size, struct mmu_atc_line *cl) REGPARAM;
+extern uae_u32 REGPARAM3 mmu_get_ilong_slow(uaecptr addr, bool super,
+ int size, struct mmu_atc_line *cl) REGPARAM;
+
extern void REGPARAM3 mmu_put_word_unaligned(uaecptr addr, uae_u16 val, bool data, bool rmw) REGPARAM;
extern void REGPARAM3 mmu_put_long_unaligned(uaecptr addr, uae_u32 val, bool data, bool rmw) REGPARAM;
// addr,super,data
if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,regs.s != 0,data,rmw)!=TTR_NO_MATCH))
- return phys_get_long(addr);
+ return x_phys_get_long(addr);
if (likely(mmu_lookup(addr, data, false, &cl)))
- return phys_get_long(mmu_get_real_address(addr, cl));
+ return x_phys_get_long(mmu_get_real_address(addr, cl));
return mmu_get_long_slow(addr, regs.s != 0, data, size, rmw, cl);
}
+static ALWAYS_INLINE uae_u32 mmu_get_ilong(uaecptr addr, int size)
+{
+ struct mmu_atc_line *cl;
+
+ // addr,super,data
+ if ((!regs.mmu_enabled) || (mmu_match_ttr(addr, regs.s != 0, false, false) != TTR_NO_MATCH))
+ return x_phys_get_ilong(addr);
+ if (likely(mmu_lookup(addr, false, false, &cl)))
+ return x_phys_get_ilong(mmu_get_real_address(addr, cl));
+ return mmu_get_ilong_slow(addr, regs.s != 0, size, cl);
+}
+
static ALWAYS_INLINE uae_u16 mmu_get_word(uaecptr addr, bool data, int size, bool rmw)
{
struct mmu_atc_line *cl;
// addr,super,data
if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,regs.s != 0,data,rmw)!=TTR_NO_MATCH))
- return phys_get_word(addr);
+ return x_phys_get_word(addr);
if (likely(mmu_lookup(addr, data, false, &cl)))
- return phys_get_word(mmu_get_real_address(addr, cl));
+ return x_phys_get_word(mmu_get_real_address(addr, cl));
return mmu_get_word_slow(addr, regs.s != 0, data, size, rmw, cl);
}
+static ALWAYS_INLINE uae_u16 mmu_get_iword(uaecptr addr, int size)
+{
+ struct mmu_atc_line *cl;
+
+ // addr,super,data
+ if ((!regs.mmu_enabled) || (mmu_match_ttr(addr, regs.s != 0, false, false) != TTR_NO_MATCH))
+ return x_phys_get_iword(addr);
+ if (likely(mmu_lookup(addr, false, false, &cl)))
+ return x_phys_get_iword(mmu_get_real_address(addr, cl));
+ return mmu_get_iword_slow(addr, regs.s != 0, size, cl);
+}
+
static ALWAYS_INLINE uae_u8 mmu_get_byte(uaecptr addr, bool data, int size, bool rmw)
{
struct mmu_atc_line *cl;
// addr,super,data
if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,regs.s != 0,data,rmw)!=TTR_NO_MATCH))
- return phys_get_byte(addr);
+ return x_phys_get_byte(addr);
if (likely(mmu_lookup(addr, data, false, &cl)))
- return phys_get_byte(mmu_get_real_address(addr, cl));
+ return x_phys_get_byte(mmu_get_real_address(addr, cl));
return mmu_get_byte_slow(addr, regs.s != 0, data, size, rmw, cl);
}
// addr,super,data
if ((!regs.mmu_enabled) || mmu_match_ttr_write(addr,regs.s != 0,data,val,size,rmw)==TTR_OK_MATCH) {
- phys_put_long(addr,val);
+ x_phys_put_long(addr,val);
return;
}
if (likely(mmu_lookup(addr, data, true, &cl)))
- phys_put_long(mmu_get_real_address(addr, cl), val);
+ x_phys_put_long(mmu_get_real_address(addr, cl), val);
else
mmu_put_long_slow(addr, val, regs.s != 0, data, size, rmw, cl);
}
// addr,super,data
if ((!regs.mmu_enabled) || (mmu_match_ttr_write(addr,regs.s != 0,data,val,size,rmw)==TTR_OK_MATCH)) {
- phys_put_word(addr,val);
+ x_phys_put_word(addr,val);
return;
}
if (likely(mmu_lookup(addr, data, true, &cl)))
- phys_put_word(mmu_get_real_address(addr, cl), val);
+ x_phys_put_word(mmu_get_real_address(addr, cl), val);
else
mmu_put_word_slow(addr, val, regs.s != 0, data, size, rmw, cl);
}
// addr,super,data
if ((!regs.mmu_enabled) || (mmu_match_ttr_write(addr,regs.s != 0,data,val,size,rmw)==TTR_OK_MATCH)) {
- phys_put_byte(addr,val);
+ x_phys_put_byte(addr,val);
return;
}
if (likely(mmu_lookup(addr, data, true, &cl)))
- phys_put_byte(mmu_get_real_address(addr, cl), val);
+ x_phys_put_byte(mmu_get_real_address(addr, cl), val);
else
mmu_put_byte_slow(addr, val, regs.s != 0, data, size, rmw, cl);
}
// addr,super,data
if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,super,data,false)!=TTR_NO_MATCH))
- return phys_get_long(addr);
+ return x_phys_get_long(addr);
if (likely(mmu_user_lookup(addr, super, data, write, &cl)))
- return phys_get_long(mmu_get_real_address(addr, cl));
+ return x_phys_get_long(mmu_get_real_address(addr, cl));
return mmu_get_long_slow(addr, super, data, size, false, cl);
}
// addr,super,data
if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,super,data,false)!=TTR_NO_MATCH))
- return phys_get_word(addr);
+ return x_phys_get_word(addr);
if (likely(mmu_user_lookup(addr, super, data, write, &cl)))
- return phys_get_word(mmu_get_real_address(addr, cl));
+ return x_phys_get_word(mmu_get_real_address(addr, cl));
return mmu_get_word_slow(addr, super, data, size, false, cl);
}
// addr,super,data
if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,super,data,false)!=TTR_NO_MATCH))
- return phys_get_byte(addr);
+ return x_phys_get_byte(addr);
if (likely(mmu_user_lookup(addr, super, data, write, &cl)))
- return phys_get_byte(mmu_get_real_address(addr, cl));
+ return x_phys_get_byte(mmu_get_real_address(addr, cl));
return mmu_get_byte_slow(addr, super, data, size, false, cl);
}
// addr,super,data
if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,super,data,false)==TTR_OK_MATCH)) {
- phys_put_long(addr,val);
+ x_phys_put_long(addr,val);
return;
}
if (likely(mmu_user_lookup(addr, super, data, true, &cl)))
- phys_put_long(mmu_get_real_address(addr, cl), val);
+ x_phys_put_long(mmu_get_real_address(addr, cl), val);
else
mmu_put_long_slow(addr, val, super, data, size, false, cl);
}
// addr,super,data
if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,super,data,false)==TTR_OK_MATCH)) {
- phys_put_word(addr,val);
+ x_phys_put_word(addr,val);
return;
}
if (likely(mmu_user_lookup(addr, super, data, true, &cl)))
- phys_put_word(mmu_get_real_address(addr, cl), val);
+ x_phys_put_word(mmu_get_real_address(addr, cl), val);
else
mmu_put_word_slow(addr, val, super, data, size, false, cl);
}
// addr,super,data
if ((!regs.mmu_enabled) || (mmu_match_ttr(addr,super,data,false)==TTR_OK_MATCH)) {
- phys_put_byte(addr,val);
+ x_phys_put_byte(addr,val);
return;
}
if (likely(mmu_user_lookup(addr, super, data, true, &cl)))
- phys_put_byte(mmu_get_real_address(addr, cl), val);
+ x_phys_put_byte(mmu_get_real_address(addr, cl), val);
else
mmu_put_byte_slow(addr, val, super, data, size, false, cl);
}
static ALWAYS_INLINE uae_u32 uae_mmu040_get_ilong(uaecptr addr)
{
if (unlikely(is_unaligned(addr, 4)))
- return mmu_get_long_unaligned(addr, false, false);
- return mmu_get_long(addr, false, sz_long, false);
+ return mmu_get_ilong_unaligned(addr);
+ return mmu_get_ilong(addr, sz_long);
}
static ALWAYS_INLINE uae_u16 uae_mmu040_get_iword(uaecptr addr)
{
- if (unlikely(is_unaligned(addr, 2)))
- return mmu_get_word_unaligned(addr, false, false);
- return mmu_get_word(addr, false, sz_word, false);
+ return mmu_get_iword(addr, sz_word);
}
static ALWAYS_INLINE uae_u16 uae_mmu040_get_ibyte(uaecptr addr)
{
static ALWAYS_INLINE uae_u32 uae_mmu060_get_ilong(uaecptr addr)
{
if (unlikely(is_unaligned(addr, 4)))
- return mmu_get_long_unaligned(addr, false, false);
- return mmu_get_long(addr, false, sz_long, false);
+ return mmu_get_ilong_unaligned(addr);
+ return mmu_get_ilong(addr, sz_long);
}
static ALWAYS_INLINE uae_u16 uae_mmu060_get_iword(uaecptr addr)
{
- if (unlikely(is_unaligned(addr, 2)))
- return mmu_get_word_unaligned(addr, false, false);
- return mmu_get_word(addr, false, sz_word, false);
+ return mmu_get_iword(addr, sz_word);
}
static ALWAYS_INLINE uae_u16 uae_mmu060_get_ibyte(uaecptr addr)
{
uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc);
uae_u16 mmu030_get_word(uaecptr addr, uae_u32 fc);
uae_u8 mmu030_get_byte(uaecptr addr, uae_u32 fc);
+uae_u32 mmu030_get_ilong(uaecptr addr, uae_u32 fc);
+uae_u16 mmu030_get_iword(uaecptr addr, uae_u32 fc);
uae_u32 uae_mmu030_get_lrmw(uaecptr addr, int size);
void uae_mmu030_put_lrmw(uaecptr addr, uae_u32 val, int size);
extern uae_u16 REGPARAM3 mmu030_get_word_unaligned(uaecptr addr, uae_u32 fc, int flags) REGPARAM;
extern uae_u32 REGPARAM3 mmu030_get_long_unaligned(uaecptr addr, uae_u32 fc, int flags) REGPARAM;
+extern uae_u32 REGPARAM3 mmu030_get_ilong_unaligned(uaecptr addr, uae_u32 fc, int flags) REGPARAM;
extern uae_u16 REGPARAM3 mmu030_get_lrmw_word_unaligned(uaecptr addr, uae_u32 fc, int flags) REGPARAM;
extern uae_u32 REGPARAM3 mmu030_get_lrmw_long_unaligned(uaecptr addr, uae_u32 fc, int flags) REGPARAM;
extern void REGPARAM3 mmu030_put_word_unaligned(uaecptr addr, uae_u16 val, uae_u32 fc, int flags) REGPARAM;
uae_u32 fc = (regs.s ? 4 : 0) | 2;
if (unlikely(is_unaligned(addr, 4)))
- return mmu030_get_long_unaligned(addr, fc, 0);
- return mmu030_get_long(addr, fc);
+ return mmu030_get_ilong_unaligned(addr, fc, 0);
+ return mmu030_get_ilong(addr, fc);
}
static ALWAYS_INLINE uae_u16 uae_mmu030_get_iword(uaecptr addr)
{
uae_u32 fc = (regs.s ? 4 : 0) | 2;
-
- if (unlikely(is_unaligned(addr, 2)))
- return mmu030_get_word_unaligned(addr, fc, 0);
- return mmu030_get_word(addr, fc);
+ return mmu030_get_iword(addr, fc);
}
static ALWAYS_INLINE uae_u16 uae_mmu030_get_ibyte(uaecptr addr)
{
TCHAR vendor_id[8 + 1];
TCHAR product_id[16 + 1];
TCHAR product_rev[4 + 1];
- TCHAR device_name[256];
/* geometry from possible RDSK block */
int rdbcylinders;
int rdbsectors;
#define HD_CONTROLLER_TYPE_SCSI_A3000 7
#define HD_CONTROLLER_TYPE_SCSI_A4000T 8
#define HD_CONTROLLER_TYPE_SCSI_CDTV 9
-#define HD_CONTROLLER_TYPE_SCSI_WARPENGINE 10
+#define HD_CONTROLLER_TYPE_SCSI_CPUBOARD 10
#define HD_CONTROLLER_TYPE_PCMCIA_SRAM 11
#define HD_CONTROLLER_TYPE_PCMCIA_IDE 12
--- /dev/null
+
+void *flash_new(uae_u8 *rom, int flashsize, int allocsize, struct zfile *zf);
+void flash_free(void *fdv);
+
+bool flash_write(void *fdv, uaecptr addr, uae_u8 v);
+uae_u32 flash_read(void *fdv, uaecptr addr);
+bool flash_active(void *fdv, uaecptr addr);
uae_s8 hd; /* harddrive */
uae_s8 cd; /* CD */
uae_s8 md; /* CD32 or CDTV internal storage */
- bool cpu_halted;
+ int cpu_halted;
int fps, idle;
int fps_color;
int sndbuf, sndbuf_status;
return byteget (addr);
}
+extern uae_u32(*x_phys_get_iword)(uaecptr);
+extern uae_u32(*x_phys_get_ilong)(uaecptr);
+extern uae_u32(*x_phys_get_byte)(uaecptr);
+extern uae_u32(*x_phys_get_word)(uaecptr);
+extern uae_u32(*x_phys_get_long)(uaecptr);
+extern void(*x_phys_put_byte)(uaecptr, uae_u32);
+extern void(*x_phys_put_word)(uaecptr, uae_u32);
+extern void(*x_phys_put_long)(uaecptr, uae_u32);
+
#endif
-void ncr_io_bput_a4000t(uaecptr, uae_u32);
-uae_u32 ncr_io_bget_a4000t(uaecptr);
+void ncr710_io_bput_a4000t(uaecptr, uae_u32);
+uae_u32 ncr710_io_bget_a4000t(uaecptr);
+
+extern addrbank ncr_bank_cyberstorm;
+extern addrbank ncr_bank_blizzardppc;
extern void ncr_init(void);
-extern addrbank *ncr_a4091_autoconfig_init(int devnum);
-extern addrbank *ncr_warpengine_autoconfig_init(void);
extern void ncr_free(void);
extern void ncr_reset(void);
-extern int a4000t_add_scsi_unit (int ch, struct uaedev_config_info *ci);
-extern int warpengine_add_scsi_unit (int ch, struct uaedev_config_info *ci);
-extern int a4091_add_scsi_unit (int ch, struct uaedev_config_info *ci, int devnum);
+extern void ncr710_init(void);
+extern addrbank *ncr710_a4091_autoconfig_init(int devnum);
+extern addrbank *ncr710_warpengine_autoconfig_init(void);
+extern void ncr710_free(void);
+extern void ncr710_reset(void);
+extern void ncr_rethink(void);
+extern int a4000t_add_scsi_unit (int ch, struct uaedev_config_info *ci);
+extern int warpengine_add_scsi_unit(int ch, struct uaedev_config_info *ci);
+extern int cyberstorm_add_scsi_unit(int ch, struct uaedev_config_info *ci);
+extern int blizzardppc_add_scsi_unit(int ch, struct uaedev_config_info *ci);
+extern int a4091_add_scsi_unit(int ch, struct uaedev_config_info *ci, int devnum);
#include "machdep/m68k.h"
#include "events.h"
+#ifdef WITH_SOFTFLOAT
+#include <softfloat.h>
+#endif
+
#ifndef SET_CFLG
#define SET_CFLG(x) (CFLG() = (x))
#ifdef FPUEMU
-#if USE_LONG_DOUBLE
+#ifdef USE_LONG_DOUBLE
typedef long double fptype;
#define LDPTR tbyte ptr
#else
uae_u32 tag;
};
-#if 0
#define CACHESETS040 64
#define CACHELINES040 4
struct cache040
{
uae_u32 data[CACHELINES040][4];
+ bool dirty[CACHELINES040][4];
bool valid[CACHELINES040];
uae_u32 tag[CACHELINES040];
};
-#endif
struct mmufixup
{
typedef struct
{
fptype fp;
-#ifdef USE_SOFT_LONG_DOUBLE
- bool fpx;
- uae_u32 fpm;
- uae_u64 fpe;
+#ifdef WITH_SOFTFLOAT
+ floatx80 fpx;
#endif
} fpdata;
fpdata exp_src1, exp_src2;
uae_u32 exp_pack[3];
uae_u16 exp_opcode, exp_extra, exp_type;
+ uae_u16 exp_size;
bool fp_exception;
#endif
#ifndef CPUEMU_68000_ONLY
bool ce020memcycle_data;
int ce020_tail;
frame_time_t ce020_tail_cycles;
+ int memory_waitstate_cycles;
};
extern struct regstruct regs;
extern uae_u32 (REGPARAM3 *x_cp_get_disp_ea_020)(uae_u32 base, int idx) REGPARAM;
+extern void write_dcache030(uaecptr, uae_u32, int);
+extern uae_u32 read_dcache030(uaecptr, int);
+extern uae_u32 get_word_icache030(uaecptr addr);
+extern uae_u32 get_long_icache030(uaecptr addr);
+
+uae_u32 fill_icache040(uae_u32 addr);
+extern void put_long_cache_040(uaecptr, uae_u32);
+extern void put_word_cache_040(uaecptr, uae_u32);
+extern void put_byte_cache_040(uaecptr, uae_u32);
+extern uae_u32 get_ilong_cache_040(int);
+extern uae_u32 get_iword_cache_040(int);
+extern uae_u32 get_long_cache_040(uaecptr);
+extern uae_u32 get_word_cache_040(uaecptr);
+extern uae_u32 get_byte_cache_040(uaecptr);
+extern uae_u32 next_iword_cache040(void);
+extern uae_u32 next_ilong_cache040(void);
+extern uae_u32 get_word_icache040(uaecptr addr);
+extern uae_u32 get_long_icache040(uaecptr addr);
+
extern void (*x_do_cycles)(unsigned long);
extern void (*x_do_cycles_pre)(unsigned long);
extern void (*x_do_cycles_post)(unsigned long, uae_u32);
extern uae_u32 REGPARAM3 x_get_disp_ea_020 (uae_u32 base, int idx) REGPARAM;
extern uae_u32 REGPARAM3 x_get_disp_ea_ce020 (uae_u32 base, int idx) REGPARAM;
extern uae_u32 REGPARAM3 x_get_disp_ea_ce030 (uae_u32 base, int idx) REGPARAM;
+extern uae_u32 REGPARAM3 x_get_disp_ea_040(uae_u32 base, int idx) REGPARAM;
extern uae_u32 REGPARAM3 x_get_bitfield (uae_u32 src, uae_u32 bdata[2], uae_s32 offset, int width) REGPARAM;
extern void REGPARAM3 x_put_bitfield (uae_u32 dst, uae_u32 bdata[2], uae_u32 val, uae_s32 offset, int width) REGPARAM;
extern void exception3b (uae_u32 opcode, uaecptr addr, bool w, bool i, uaecptr pc);
extern void exception2 (uaecptr addr, bool read, int size, uae_u32 fc);
extern void exception2_fake (uaecptr addr);
+extern void m68k_reset (void);
extern void cpureset (void);
extern void cpu_halt (int id);
/* 68060 */
extern const struct cputbl op_smalltbl_0_ff[];
-extern const struct cputbl op_smalltbl_22_ff[]; // CE
+extern const struct cputbl op_smalltbl_23_ff[]; // CE
extern const struct cputbl op_smalltbl_33_ff[]; // MMU
/* 68040 */
extern const struct cputbl op_smalltbl_1_ff[];
-extern const struct cputbl op_smalltbl_23_ff[]; // CE
+extern const struct cputbl op_smalltbl_24_ff[]; // CE
extern const struct cputbl op_smalltbl_31_ff[]; // MMU
/* 68030 */
extern const struct cputbl op_smalltbl_2_ff[];
-extern const struct cputbl op_smalltbl_24_ff[]; // CE
+extern const struct cputbl op_smalltbl_22_ff[]; // CE
extern const struct cputbl op_smalltbl_32_ff[]; // MMU
/* 68020 */
extern const struct cputbl op_smalltbl_3_ff[];
bool comp_midopt;
bool comp_lowopt;
bool fpu_strict;
+ bool fpu_softfloat;
bool comp_hardflush;
bool comp_constjump;
comprintf ("\tint offset=0;\n");
genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, 1);
if (table68k[opcode].size == sz_long)
- comprintf("\tif (!currprefs.comptrustlong && !special_mem) {\n");
+ comprintf("\tif (1 && !special_mem) {\n");
else
- comprintf("\tif (!currprefs.comptrustword && !special_mem) {\n");
+ comprintf("\tif (1 && !special_mem) {\n");
/* Fast but unsafe... */
- comprintf("\tget_n_addr(srca,native,scratchie);\n");
+ comprintf("\t\tget_n_addr(srca,native,scratchie);\n");
- comprintf("\tfor (i=0;i<16;i++) {\n"
- "\t\tif ((mask>>i)&1) {\n");
+ comprintf("\t\tfor (i=0;i<16;i++) {\n"
+ "\t\t\tif ((mask>>i)&1) {\n");
switch(table68k[opcode].size) {
case sz_long:
- comprintf("\t\t\tmov_l_rR(i,native,offset);\n"
- "\t\t\tgen_bswap_32(i);\n"
- "\t\t\toffset+=4;\n");
+ comprintf("\t\t\t\tmov_l_rR(i,native,offset);\n"
+ "\t\t\t\tgen_bswap_32(i);\n"
+ "\t\t\t\toffset+=4;\n");
break;
case sz_word:
- comprintf("\t\t\tmov_w_rR(i,native,offset);\n"
- "\t\t\tgen_bswap_16(i);\n"
- "\t\t\tsign_extend_16_rr(i,i);\n"
- "\t\t\toffset+=2;\n");
+ comprintf("\t\t\t\tmov_w_rR(i,native,offset);\n"
+ "\t\t\t\tgen_bswap_16(i);\n"
+ "\t\t\t\tsign_extend_16_rr(i,i);\n"
+ "\t\t\t\toffset+=2;\n");
break;
default: abort();
}
- comprintf("\t\t}\n"
- "\t}");
+ comprintf("\t\t\t}\n"
+ "\t\t}\n");
if (table68k[opcode].dmode == Aipi) {
- comprintf("\t\t\tlea_l_brr(8+dstreg,srca,offset);\n");
+ comprintf("\t\tlea_l_brr(8+dstreg,srca,offset);\n");
}
/* End fast but unsafe. */
comprintf("\t} else {\n");
- comprintf ("\tint tmp=scratchie++;\n");
+ comprintf ("\t\tint tmp=scratchie++;\n");
- comprintf("\tmov_l_rr(tmp,srca);\n");
- comprintf("\tfor (i=0;i<16;i++) {\n"
- "\t\tif ((mask>>i)&1) {\n");
+ comprintf("\t\tmov_l_rr(tmp,srca);\n");
+ comprintf("\t\tfor (i=0;i<16;i++) {\n"
+ "\t\t\tif ((mask>>i)&1) {\n");
switch(table68k[opcode].size) {
case sz_long:
- comprintf("\t\t\treadlong(tmp,i,scratchie);\n"
- "\t\t\tadd_l_ri(tmp,4);\n");
+ comprintf("\t\t\t\treadlong(tmp,i,scratchie);\n"
+ "\t\t\t\tadd_l_ri(tmp,4);\n");
break;
case sz_word:
- comprintf("\t\t\treadword(tmp,i,scratchie);\n"
- "\t\t\tadd_l_ri(tmp,2);\n");
+ comprintf("\t\t\t\treadword(tmp,i,scratchie);\n"
+ "\t\t\t\tadd_l_ri(tmp,2);\n");
break;
default: abort();
}
- comprintf("\t\t}\n"
- "\t}");
+ comprintf("\t\t\t}\n"
+ "\t\t}\n");
if (table68k[opcode].dmode == Aipi) {
- comprintf("\t\t\tmov_l_rr(8+dstreg,tmp);\n");
+ comprintf("\t\tmov_l_rr(8+dstreg,tmp);\n");
}
comprintf("\t}\n");
act of cleverness means that movmle must pay attention to special_mem,
or Genetic Species is a rather boring-looking game ;-) */
if (table68k[opcode].size == sz_long)
- comprintf("\tif (!currprefs.comptrustlong && !special_mem) {\n");
+ comprintf("\tif (1 && !special_mem) {\n");
else
- comprintf("\tif (!currprefs.comptrustword && !special_mem) {\n");
+ comprintf("\tif (1 && !special_mem) {\n");
comprintf("\tget_n_addr(srca,native,scratchie);\n");
if (table68k[opcode].dmode!=Apdi) {
if (p->cpu_model >= 68040 && p->cachesize && p->cpu_compatible)
p->cpu_compatible = false;
- if (p->cpu_model >= 68040 && p->cpu_cycle_exact) {
- p->cpu_cycle_exact = 0;
- error_log (_T("68040/060 cycle-exact is not supported."));
- }
-
if ((p->cpu_model < 68030 || p->cachesize) && p->mmu_model) {
error_log (_T("MMU emulation requires 68030/040/060 and it is not JIT compatible."));
p->mmu_model = 0;
p->fpu_no_unimplemented = p->int_no_unimplemented = false;
}
- if (p->cpu_cycle_exact && p->m68k_speed < 0)
+#if 0
+ if (p->cpu_cycle_exact && p->m68k_speed < 0 && currprefs.cpu_model <= 68020)
p->m68k_speed = 0;
+#endif
if (p->immediate_blits && p->blitter_cycle_exact) {
error_log (_T("Cycle-exact and immediate blitter can't be enabled simultaneously.\n"));
error_log (_T("Cycle-exact and JIT can't be active simultaneously."));
p->cachesize = 0;
}
+#if 0
if (p->m68k_speed) {
error_log (_T("Adjustable CPU speed is not available in cycle-exact mode."));
p->m68k_speed = 0;
}
+#endif
}
#endif
if (p->maprom && !p->address_space_24)
a3000scsi_free ();
#endif
#ifdef NCR
- ncr_free ();
+ ncr710_free();
+ ncr_free();
#endif
#ifdef CD32
akiko_free ();
#ifdef WITH_TABLETLIBRARY
tabletlib_install ();
#endif
+#ifdef NCR
+ ncr710_init();
+ ncr_init();
+#endif
}
static int real_main2 (int argc, TCHAR **argv)
#endif
static int mem_hardreset;
+#define FLASHEMU 0
+
static bool isdirectjit (void)
{
return currprefs.cachesize && !currprefs.comptrustbyte;
void dummy_put (uaecptr addr, int size, uae_u32 val)
{
+#if FLASHEMU
+ if (addr >= 0xf00000 && addr < 0xf80000 && size < 2)
+ flash_write(addr, val);
+#endif
if (gary_nonrange(addr) || (size > 1 && gary_nonrange(addr + size - 1))) {
if (gary_timeout)
gary_wait (addr, size, true);
{
uae_u32 v = NONEXISTINGDATA;
-#if 0
- if (addr == 0xf00000 && size < 2) {
- return 0xff;
- }
- if (addr >= 0xf60000 && addr < 0xf80000 && size < 2) {
- //activate_debugger();
- if (addr == 0xf60020)
- return 0x8;
- return v;
+#if FLASHEMU
+ if (addr >= 0xf00000 && addr < 0xf80000 && size < 2) {
+ if (addr < 0xf60000)
+ return flash_read(addr);
+ return 8;
}
#endif
#if defined(ENFORCER)
enforcer_disable ();
#endif
-
if (be_cnt < 3) {
int i, j;
uaecptr a2 = a - 32;
#include "filesys.h"
#include "zfile.h"
#include "blkdev.h"
+#include "cpuboard.h"
#include "qemuvga\qemuuaeglue.h"
#include "qemuvga\queue.h"
#include "qemuvga\scsi\scsi.h"
#define WARP_ENGINE_IO_OFFSET 0x40000
#define WARP_ENGINE_IO_END 0x80000
+#define CYBERSTORM_SCSI_RAM_OFFSET 0x1000
+#define CYBERSTORM_SCSI_RAM_SIZE 0x2000
+#define CYBERSTORM_SCSI_RAM_MASK 0x1fff
+
struct ncr_state
{
+ bool newncr;
TCHAR *name;
DeviceState devobject;
SCSIDevice *scsid[8];
SCSIBus scsibus;
uae_u32 board_mask;
uae_u8 *rom;
+ int ramsize;
uae_u8 acmemory[128];
uae_u32 expamem_hi;
uae_u32 expamem_lo;
int rom_start, rom_end, rom_offset;
int io_start, io_end;
addrbank *bank;
+ bool irq;
+ void (*irq_func)(int);
};
static struct ncr_state ncr_a4091;
static struct ncr_state ncr_a4000t;
static struct ncr_state ncr_we;
+static struct ncr_state ncr_cs;
+static struct ncr_state ncr_bppc;
+
static struct ncr_state *ncrs[] =
{
&ncr_a4091,
&ncr_a4091_2,
&ncr_a4000t,
&ncr_we,
+ &ncr_bppc,
NULL
};
&ncr_a4091_2
};
+extern void cyberstorm_irq(int);
+extern void blizzardppc_irq(int);
+
+static void set_irq2(int level)
+{
+ if (level)
+ INTREQ(0x8000 | 0x0008);
+}
+
+void ncr_rethink(void)
+{
+ for (int i = 0; ncrs[i]; i++) {
+ if (ncrs[i]->irq)
+ INTREQ(0x8000 | 0x0008);
+ }
+ if (ncr_cs.irq)
+ cyberstorm_irq(1);
+}
+
+/* 720+ */
+
void pci_set_irq(PCIDevice *pci_dev, int level)
{
- if (!level)
- return;
- INTREQ (0x8000 | 0x0008);
+ struct ncr_state *ncr = (struct ncr_state*)pci_dev;
+ ncr->irq = level != 0;
+ ncr->irq_func(ncr->irq);
}
void scsi_req_continue(SCSIRequest *req)
{
struct scsi_data *sd = (struct scsi_data*)req->dev->handle;
if (sd->data_len < 0) {
- lsi_command_complete (req, sd->status, 0);
- } else if (sd->data_len) {
- lsi_transfer_data (req, sd->data_len);
- } else {
+ lsi_command_complete(req, sd->status, 0);
+ }
+ else if (sd->data_len) {
+ lsi_transfer_data(req, sd->data_len);
+ }
+ else {
if (sd->direction > 0)
scsi_emulate_cmd(sd);
- lsi_command_complete (req, sd->status, 0);
+ lsi_command_complete(req, sd->status, 0);
}
}
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, uint8_t *buf, int len, void *hba_private)
req->hba_private = hba_private;
req->bus = &ncr->scsibus;
req->bus->qbus.parent = &ncr->devobject;
-
- memcpy (sd->cmd, buf, len);
+
+ memcpy(sd->cmd, buf, len);
sd->cmd_len = len;
return req;
}
struct scsi_data *sd = (struct scsi_data*)req->dev->handle;
sd->data_len = 0;
- scsi_start_transfer (sd);
- scsi_emulate_analyze (sd);
+ scsi_start_transfer(sd);
+ scsi_emulate_analyze(sd);
//write_log (_T("%02x.%02x.%02x.%02x.%02x.%02x\n"), sd->cmd[0], sd->cmd[1], sd->cmd[2], sd->cmd[3], sd->cmd[4], sd->cmd[5]);
-
+
if (sd->direction < 0)
scsi_emulate_cmd(sd);
if (sd->direction == 0)
}
void scsi_req_unref(SCSIRequest *req)
{
- xfree (req);
+ xfree(req);
}
uint8_t *scsi_req_get_buf(SCSIRequest *req)
{
}
void scsi_req_cancel(SCSIRequest *req)
{
- write_log (_T("scsi_req_cancel\n"));
+ write_log(_T("scsi_req_cancel\n"));
}
-static uae_u8 read_rombyte (struct ncr_state *ncr, uaecptr addr)
+int pci_dma_rw(PCIDevice *dev, dma_addr_t addr, void *buf, dma_addr_t len, DMADirection dir)
{
- uae_u8 v = ncr->rom[addr];
- //write_log (_T("%08X = %02X PC=%08X\n"), addr, v, M68K_GETPC);
- return v;
+ int i = 0;
+ uae_u8 *p = (uae_u8*)buf;
+ while (len > 0) {
+ if (!dir) {
+ *p = get_byte(addr);
+ }
+ else {
+ put_byte(addr, *p);
+ }
+ p++;
+ len--;
+ addr++;
+ }
+ return 0;
}
+/* 710 */
-int pci_dma_rw(PCIDevice *dev, dma_addr_t addr, void *buf, dma_addr_t len, DMADirection dir)
+void pci710_set_irq(PCIDevice *pci_dev, int level)
+{
+ struct ncr_state *ncr = (struct ncr_state*)pci_dev;
+ ncr->irq = level != 0;
+ ncr->irq_func(ncr->irq);
+}
+
+void scsi710_req_continue(SCSIRequest *req)
+{
+ struct scsi_data *sd = (struct scsi_data*)req->dev->handle;
+ if (sd->data_len < 0) {
+ lsi710_command_complete(req, sd->status, 0);
+ } else if (sd->data_len) {
+ lsi710_transfer_data(req, sd->data_len);
+ } else {
+ if (sd->direction > 0)
+ scsi_emulate_cmd(sd);
+ lsi710_command_complete(req, sd->status, 0);
+ }
+}
+SCSIRequest *scsi710_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, uint8_t *buf, int len, void *hba_private)
+{
+ SCSIRequest *req = xcalloc(SCSIRequest, 1);
+ struct scsi_data *sd = (struct scsi_data*)d->handle;
+ struct ncr_state *ncr = (struct ncr_state*)sd->privdata;
+
+ req->dev = d;
+ req->hba_private = hba_private;
+ req->bus = &ncr->scsibus;
+ req->bus->qbus.parent = &ncr->devobject;
+
+ memcpy (sd->cmd, buf, len);
+ sd->cmd_len = len;
+ return req;
+}
+int32_t scsi710_req_enqueue(SCSIRequest *req)
+{
+ struct scsi_data *sd = (struct scsi_data*)req->dev->handle;
+
+ sd->data_len = 0;
+ scsi_start_transfer (sd);
+ scsi_emulate_analyze (sd);
+ //write_log (_T("%02x.%02x.%02x.%02x.%02x.%02x\n"), sd->cmd[0], sd->cmd[1], sd->cmd[2], sd->cmd[3], sd->cmd[4], sd->cmd[5]);
+
+ if (sd->direction < 0)
+ scsi_emulate_cmd(sd);
+ if (sd->direction == 0)
+ return 1;
+ return -sd->direction;
+}
+void scsi710_req_unref(SCSIRequest *req)
+{
+ xfree (req);
+}
+uint8_t *scsi710_req_get_buf(SCSIRequest *req)
+{
+ struct scsi_data *sd = (struct scsi_data*)req->dev->handle;
+ sd->data_len = 0;
+ return sd->buffer;
+}
+SCSIDevice *scsi710_device_find(SCSIBus *bus, int channel, int target, int lun)
+{
+ struct ncr_state *ncr = (struct ncr_state*)bus->privdata;
+ if (lun != 0 || target < 0 || target >= 8)
+ return NULL;
+ return ncr->scsid[target];
+}
+void scsi710_req_cancel(SCSIRequest *req)
+{
+ write_log (_T("scsi_req_cancel\n"));
+}
+
+int pci710_dma_rw(PCIDevice *dev, dma_addr_t addr, void *buf, dma_addr_t len, DMADirection dir)
{
int i = 0;
uae_u8 *p = (uae_u8*)buf;
return 0;
}
-static uaecptr beswap (uaecptr addr)
+static uae_u8 read_rombyte(struct ncr_state *ncr, uaecptr addr)
+{
+ uae_u8 v = ncr->rom[addr];
+ //write_log (_T("%08X = %02X PC=%08X\n"), addr, v, M68K_GETPC);
+ return v;
+}
+
+static uaecptr beswap(uaecptr addr)
{
return (addr & ~3) | (3 - (addr & 3));
}
-void ncr_io_bput (struct ncr_state *ncr, uaecptr addr, uae_u32 val)
+void ncr_io_bput(struct ncr_state *ncr, uaecptr addr, uae_u32 val)
{
+ if (addr >= CYBERSTORM_SCSI_RAM_OFFSET && ncr->ramsize) {
+ cyberstorm_scsi_ram_put(addr, val);
+ return;
+ }
addr &= IO_MASK;
- lsi_mmio_write (ncr->devobject.lsistate, beswap (addr), val, 1);
+ lsi_mmio_write(ncr->devobject.lsistate, beswap(addr), val, 1);
+}
+void ncr710_io_bput(struct ncr_state *ncr, uaecptr addr, uae_u32 val)
+{
+ addr &= IO_MASK;
+ lsi710_mmio_write(ncr->devobject.lsistate, beswap(addr), val, 1);
}
static void ncr_bput2 (struct ncr_state *ncr, uaecptr addr, uae_u32 val)
{
uae_u32 v = val;
addr &= ncr->board_mask;
- if (addr < ncr->io_start || addr >= ncr->io_end)
+ if (ncr->io_end && (addr < ncr->io_start || addr >= ncr->io_end))
return;
- ncr_io_bput (ncr, addr, val);
+ if (ncr->newncr)
+ ncr_io_bput(ncr, addr, val);
+ else
+ ncr710_io_bput(ncr, addr, val);
}
-uae_u32 ncr_io_bget (struct ncr_state *ncr, uaecptr addr)
+uae_u32 ncr_io_bget(struct ncr_state *ncr, uaecptr addr)
+{
+ if (addr >= CYBERSTORM_SCSI_RAM_OFFSET && ncr->ramsize)
+ return cyberstorm_scsi_ram_get(addr);
+ addr &= IO_MASK;
+ return lsi_mmio_read(ncr->devobject.lsistate, beswap(addr), 1);
+}
+uae_u32 ncr710_io_bget(struct ncr_state *ncr, uaecptr addr)
{
addr &= IO_MASK;
- return lsi_mmio_read (ncr->devobject.lsistate, beswap (addr), 1);
+ return lsi710_mmio_read(ncr->devobject.lsistate, beswap(addr), 1);
}
static uae_u32 ncr_bget2 (struct ncr_state *ncr, uaecptr addr)
return read_rombyte (ncr, addr - ncr->rom_offset);
if (addr == A4091_DIP_OFFSET)
return 0xff;
- if (addr < ncr->io_start || addr >= ncr->io_end)
+ if (ncr->io_end && (addr < ncr->io_start || addr >= ncr->io_end))
return v;
- addr &= IO_MASK;
- return ncr_io_bget (ncr, addr);
+ if (ncr->newncr)
+ return ncr_io_bget(ncr, addr);
+ else
+ return ncr710_io_bget(ncr, addr);
}
static uae_u32 REGPARAM2 ncr_lget (struct ncr_state *ncr, uaecptr addr)
#ifdef JIT
special_mem |= S_READ;
#endif
+ if (ncr->newncr)
+ return 0;
addr &= ncr->board_mask;
v = (ncr_bget2 (ncr, addr) << 8) | ncr_bget2 (ncr, addr + 1);
return v;
}
return;
}
- ncr_bput2 (ncr, addr, w >> 8);
+ if (ncr->newncr)
+ return;
+ ncr_bput2(ncr, addr, w >> 8);
ncr_bput2 (ncr, addr + 1, w);
}
ncr_bput2 (ncr, addr, b);
}
-void ncr_io_bput_a4000t(uaecptr addr, uae_u32 v)
+void ncr710_io_bput_a4000t(uaecptr addr, uae_u32 v)
{
- ncr_io_bput(&ncr_a4000t, addr, v);
+ ncr710_io_bput(&ncr_a4000t, addr, v);
}
-uae_u32 ncr_io_bget_a4000t(uaecptr addr)
+uae_u32 ncr710_io_bget_a4000t(uaecptr addr)
{
- return ncr_io_bget(&ncr_a4000t, addr);
+ return ncr710_io_bget(&ncr_a4000t, addr);
}
static void REGPARAM2 ncr4_bput (uaecptr addr, uae_u32 b)
return ncr_lget(&ncr_we, addr);
}
+static void REGPARAM2 cs_bput(uaecptr addr, uae_u32 b)
+{
+ ncr_bput(&ncr_cs, addr, b);
+}
+static void REGPARAM2 cs_wput(uaecptr addr, uae_u32 b)
+{
+ ncr_wput(&ncr_cs, addr, b);
+}
+static void REGPARAM2 cs_lput(uaecptr addr, uae_u32 b)
+{
+ ncr_lput(&ncr_cs, addr, b);
+}
+static uae_u32 REGPARAM2 cs_bget(uaecptr addr)
+{
+ return ncr_bget(&ncr_cs, addr);
+}
+static uae_u32 REGPARAM2 cs_wget(uaecptr addr)
+{
+ return ncr_wget(&ncr_cs, addr);
+}
+static uae_u32 REGPARAM2 cs_lget(uaecptr addr)
+{
+ return ncr_lget(&ncr_cs, addr);
+}
+
+
+static void REGPARAM2 bppc_bput(uaecptr addr, uae_u32 b)
+{
+ ncr_bput(&ncr_bppc, addr, b);
+}
+static void REGPARAM2 bppc_wput(uaecptr addr, uae_u32 b)
+{
+ ncr_wput(&ncr_bppc, addr, b);
+}
+static void REGPARAM2 bppc_lput(uaecptr addr, uae_u32 b)
+{
+ ncr_lput(&ncr_bppc, addr, b);
+}
+static uae_u32 REGPARAM2 bppc_bget(uaecptr addr)
+{
+ return ncr_bget(&ncr_bppc, addr);
+}
+static uae_u32 REGPARAM2 bppc_wget(uaecptr addr)
+{
+ return ncr_wget(&ncr_bppc, addr);
+}
+static uae_u32 REGPARAM2 bppc_lget(uaecptr addr)
+{
+ return ncr_lget(&ncr_bppc, addr);
+}
+
static addrbank ncr_bank_a4091 = {
ncr4_lget, ncr4_wget, ncr4_bget,
ncr4_lput, ncr4_wput, ncr4_bput,
static addrbank ncr_bank_warpengine = {
we_lget, we_wget, we_bget,
we_lput, we_wput, we_bput,
- default_xlate, default_check, NULL, _T("Warp Engine"),
+ default_xlate, default_check, NULL, _T("Warp Engine SCSI"),
dummy_lgeti, dummy_wgeti, ABFLAG_IO
};
+addrbank ncr_bank_cyberstorm = {
+ cs_lget, cs_wget, cs_bget,
+ cs_lput, cs_wput, cs_bput,
+ cyberstorm_scsi_ram_xlate, cyberstorm_scsi_ram_check, NULL, _T("CyberStorm SCSI"),
+ dummy_lgeti, dummy_wgeti, ABFLAG_IO
+};
+
+addrbank ncr_bank_blizzardppc = {
+ bppc_lget, bppc_wget, bppc_bget,
+ bppc_lput, bppc_wput, bppc_bput,
+ default_xlate, default_check, NULL, _T("Blizzard PPC SCSI"),
+ dummy_lgeti, dummy_wgeti, ABFLAG_IO
+};
+
+
static void ew (struct ncr_state *ncr, int addr, uae_u8 value)
{
}
}
-void ncr_init (void)
+void ncr_init(void)
+{
+ ncr_cs.newncr = true;
+ if (!ncr_cs.devobject.lsistate)
+ lsi_scsi_init(&ncr_cs.devobject);
+ ncr_cs.ramsize = CYBERSTORM_SCSI_RAM_SIZE;
+}
+
+void ncr710_init (void)
{
for (int i = 0; ncrs[i]; i++) {
+ ncrs[i]->newncr = false;
if (!ncrs[i]->devobject.lsistate)
- lsi_scsi_init (&ncrs[i]->devobject);
+ lsi710_scsi_init (&ncrs[i]->devobject);
}
}
-static void ncr_reset_board (struct ncr_state *ncr)
+static void ncr_reset_board(struct ncr_state *ncr)
{
ncr->configured = 0;
ncr->board_mask = 0xffff;
+ ncr->irq = false;
if (ncr->devobject.lsistate)
- lsi_scsi_reset (&ncr->devobject, ncr);
+ lsi_scsi_reset(&ncr->devobject, ncr);
+ ncr->bank = &ncr_bank_cyberstorm;
+ ncr->irq_func = cyberstorm_irq;
+}
+
+static void ncr710_reset_board (struct ncr_state *ncr)
+{
+ ncr->configured = 0;
+ ncr->board_mask = 0xffff;
+ ncr->irq = false;
+ ncr->irq_func = set_irq2;
+ if (ncr->devobject.lsistate)
+ lsi710_scsi_reset (&ncr->devobject, ncr);
if (ncr == &ncr_a4000t) {
ncr->name = _T("A4000T NCR SCSI");
ncr->bank = NULL;
ncr->bank = &ncr_bank_a4091_2;
}
if (ncr == &ncr_we) {
- ncr->name = _T("Warp Engine");
+ ncr->name = _T("Warp Engine SCSI");
ncr->bank = &ncr_bank_warpengine;
}
+ if (ncr == &ncr_bppc) {
+ ncr->name = _T("Blizzard PPC SCSI");
+ ncr->bank = &ncr_bank_blizzardppc;
+ ncr->irq_func = blizzardppc_irq;
+ }
}
static const uae_u8 warpengine_a4000_autoconfig[16] = {
};
#define WARP_ENGINE_ROM_SIZE 32768
-addrbank *ncr_warpengine_autoconfig_init(void)
+addrbank *ncr710_warpengine_autoconfig_init(void)
{
int roms[2];
struct ncr_state *ncr = &ncr_we;
romwarning (roms);
}
- ncr_init ();
- ncr_reset_board(ncr);
+ ncr710_init ();
+ ncr710_reset_board(ncr);
return &ncr_bank_warpengine;
}
-addrbank *ncr_a4091_autoconfig_init (int devnum)
+addrbank *ncr710_a4091_autoconfig_init (int devnum)
{
struct ncr_state *ncr = ncra4091[devnum];
int roms[3];
romwarning (roms);
}
- ncr_init ();
- ncr_reset_board(ncr);
+ ncr710_init ();
+ ncr710_reset_board(ncr);
return ncr == &ncr_a4091 ? &ncr_bank_a4091 : &ncr_bank_a4091_2;
}
}
}
-void ncr_free2(struct ncr_state *ncr)
+static void ncr_free2(struct ncr_state *ncr)
{
for (int ch = 0; ch < 8; ch++) {
freescsi (ncr->scsid[ch]);
}
}
-void ncr_free(void)
+void ncr710_free(void)
{
for (int i = 0; ncrs[i]; i++) {
ncr_free2(ncrs[i]);
}
}
-void ncr_reset (void)
+void ncr_free(void)
+{
+ ncr_free2(&ncr_cs);
+}
+
+void ncr710_reset(void)
{
for (int i = 0; ncrs[i]; i++) {
- ncr_reset_board(ncrs[i]);
+ ncr710_reset_board(ncrs[i]);
}
if (currprefs.cs_mbdmac & 2) {
ncr_a4000t.configured = -1;
ncr_a4000t.enabled = true;
}
+ if (currprefs.cpuboard_type == BOARD_BLIZZARDPPC) {
+ ncr_bppc.configured = -1;
+ ncr_bppc.enabled = true;
+ }
+}
+
+void ncr_reset(void)
+{
+ ncr_reset_board(&ncr_cs);
+ ncr_cs.configured = -1;
+ ncr_cs.enabled = true;
}
static int add_ncr_scsi_hd (struct ncr_state *ncr, int ch, struct hd_hardfiledata *hfd, struct uaedev_config_info *ci, int scsi_level)
return add_ncr_scsi_hd (ncr, ch, NULL, ci, 1);
}
+int cyberstorm_add_scsi_unit(int ch, struct uaedev_config_info *ci)
+{
+ if (ci->type == UAEDEV_CD)
+ return add_ncr_scsi_cd(&ncr_cs, ch, ci->device_emu_unit);
+ else if (ci->type == UAEDEV_TAPE)
+ return add_ncr_scsi_tape(&ncr_cs, ch, ci->rootdir, ci->readonly);
+ else
+ return add_ncr_scsi_hd(&ncr_cs, ch, NULL, ci, 1);
+}
+
+int blizzardppc_add_scsi_unit(int ch, struct uaedev_config_info *ci)
+{
+ if (ci->type == UAEDEV_CD)
+ return add_ncr_scsi_cd(&ncr_bppc, ch, ci->device_emu_unit);
+ else if (ci->type == UAEDEV_TAPE)
+ return add_ncr_scsi_tape(&ncr_bppc, ch, ci->rootdir, ci->readonly);
+ else
+ return add_ncr_scsi_hd(&ncr_bppc, ch, NULL, ci, 1);
+}
#endif
int cpu_cycles;
static int baseclock;
bool m68k_pc_indirect;
+bool m68k_interrupt_delay;
static int cpu_prefs_changed_flag;
int cpucycleunit;
static struct cache020 caches020[CACHELINES020];
static struct cache030 icaches030[CACHELINES030];
static struct cache030 dcaches030[CACHELINES030];
-#if 0
-static struct cache040 caches040[CACHESETS040];
-#endif
+static int icachelinecnt, dcachelinecnt;
+static struct cache040 icaches040[CACHESETS040];
+static struct cache040 dcaches040[CACHESETS040];
#if COUNT_INSTRS
static unsigned long int instrcount[65536];
void (*x_do_cycles_pre)(unsigned long);
void (*x_do_cycles_post)(unsigned long, uae_u32);
+uae_u32(*x_phys_get_iword)(uaecptr);
+uae_u32(*x_phys_get_ilong)(uaecptr);
+uae_u32(*x_phys_get_byte)(uaecptr);
+uae_u32(*x_phys_get_word)(uaecptr);
+uae_u32(*x_phys_get_long)(uaecptr);
+void(*x_phys_put_byte)(uaecptr, uae_u32);
+void(*x_phys_put_word)(uaecptr, uae_u32);
+void(*x_phys_put_long)(uaecptr, uae_u32);
+
static void set_x_cp_funcs(void)
{
x_cp_put_long = x_put_long;
x_do_cycles = do_cycles;
x_do_cycles_pre = do_cycles;
x_do_cycles_post = do_cycles_post;
- } else {
+ } else if (currprefs.cpu_model < 68040) {
// JIT or 68030+ does not have real prefetch only emulation
x_prefetch = NULL;
x_get_ilong = get_dilong;
x_do_cycles = do_cycles;
x_do_cycles_pre = do_cycles;
x_do_cycles_post = do_cycles_post;
+ } else {
+ x_prefetch = NULL;
+ x_get_ilong = get_ilong_cache_040;
+ x_get_iword = get_iword_cache_040;
+ x_get_ibyte = NULL;
+ x_next_iword = next_iword_cache040;
+ x_next_ilong = next_ilong_cache040;
+ x_put_long = put_long_cache_040;
+ x_put_word = put_word_cache_040;
+ x_put_byte = put_byte_cache_040;
+ x_get_long = get_long_cache_040;
+ x_get_word = get_word_cache_040;
+ x_get_byte = get_byte_cache_040;
+ x_do_cycles = do_cycles;
+ x_do_cycles_pre = do_cycles;
+ x_do_cycles_post = do_cycles_post;
}
} else {
x_prefetch = NULL;
x_do_cycles = do_cycles_ce020;
x_do_cycles_pre = do_cycles_ce020;
x_do_cycles_post = do_cycles_ce020_post;
- } else {
+ } else if (currprefs.cpu_model == 68030) {
x_prefetch = get_word_ce030_prefetch;
x_get_ilong = get_long_ce030_prefetch;
x_get_iword = get_word_ce030_prefetch;
x_do_cycles = do_cycles_ce020;
x_do_cycles_pre = do_cycles_ce020;
x_do_cycles_post = do_cycles_ce020_post;
+ } else if (currprefs.cpu_model >= 68040) {
+ x_prefetch = NULL;
+ x_get_ilong = get_ilong_cache_040;
+ x_get_iword = get_iword_cache_040;
+ x_get_ibyte = NULL;
+ x_next_iword = next_iword_cache040;
+ x_next_ilong = next_ilong_cache040;
+ x_put_long = put_long_cache_040;
+ x_put_word = put_word_cache_040;
+ x_put_byte = put_byte_cache_040;
+ x_get_long = get_long_cache_040;
+ x_get_word = get_word_cache_040;
+ x_get_byte = get_byte_cache_040;
+ x_do_cycles = do_cycles_ce020;
+ x_do_cycles_pre = do_cycles_ce020;
+ x_do_cycles_post = do_cycles_ce020_post;
}
x2_prefetch = x_prefetch;
x2_get_ilong = x_get_ilong;
dcaches030[(regs.caar >> 4) & (CACHELINES030 - 1)].valid[(regs.caar >> 2) & 3] = 0;
regs.cacr &= ~0x400;
}
-#if 0
} else if (currprefs.cpu_model == 68040) {
+ icachelinecnt = 0;
+ dcachelinecnt = 0;
if (!(regs.cacr & 0x8000)) {
for (i = 0; i < CACHESETS040; i++) {
- caches040[i].valid[0] = 0;
- caches040[i].valid[1] = 0;
- caches040[i].valid[2] = 0;
- caches040[i].valid[3] = 0;
+ icaches040[i].valid[0] = 0;
+ icaches040[i].valid[1] = 0;
+ icaches040[i].valid[2] = 0;
+ icaches040[i].valid[3] = 0;
}
}
-#endif
}
}
tbl = op_smalltbl_0_ff;
if (!currprefs.cachesize) {
if (currprefs.cpu_cycle_exact)
- tbl = op_smalltbl_22_ff;
+ tbl = op_smalltbl_23_ff;
+ if (currprefs.cpu_compatible)
+ tbl = op_smalltbl_23_ff;
if (currprefs.mmu_model)
tbl = op_smalltbl_33_ff;
}
tbl = op_smalltbl_1_ff;
if (!currprefs.cachesize) {
if (currprefs.cpu_cycle_exact)
- tbl = op_smalltbl_23_ff;
+ tbl = op_smalltbl_24_ff;
+ if (currprefs.cpu_compatible)
+ tbl = op_smalltbl_24_ff;
if (currprefs.mmu_model)
tbl = op_smalltbl_31_ff;
}
tbl = op_smalltbl_2_ff;
if (!currprefs.cachesize) {
if (currprefs.cpu_cycle_exact)
- tbl = op_smalltbl_24_ff;
+ tbl = op_smalltbl_22_ff;
if (currprefs.mmu_model)
tbl = op_smalltbl_32_ff;
}
if (currprefs.address_space_24 && currprefs.cpu_model >= 68030)
currprefs.address_space_24 = false;
}
+ m68k_interrupt_delay = false;
+ if (currprefs.cpu_cycle_exact) {
+ if (tbl == op_smalltbl_13_ff || tbl == op_smalltbl_21_ff || tbl == op_smalltbl_22_ff)
+ m68k_interrupt_delay = true;
+ }
+
if (currprefs.cpu_cycle_exact) {
if (currprefs.cpu_model == 68000)
write_log(_T(" prefetch and cycle-exact"));
pc += 4;
break;
case sz_single:
- _stprintf(buffer, _T("#%e"), to_single(get_ilong_debug(pc)));
- pc += 4;
+ {
+ fpdata fp;
+ to_single(&fp, get_ilong_debug(pc));
+ _stprintf(buffer, _T("#%e"), fp.fp);
+ pc += 4;
+ }
break;
case sz_double:
- _stprintf(buffer, _T("#%e"), to_double(get_ilong_debug(pc), get_ilong_debug(pc + 4)));
- pc += 8;
+ {
+ fpdata fp;
+ to_double(&fp, get_ilong_debug(pc), get_ilong_debug(pc + 4));
+ _stprintf(buffer, _T("#%e"), fp.fp);
+ pc += 8;
+ }
break;
case sz_extended:
{
}
-static void m68k_reset (bool hardreset)
+static void m68k_reset2(bool hardreset)
{
uae_u32 v;
regs.ce020memcycles = 0;
fill_prefetch ();
}
+void m68k_reset(void)
+{
+ m68k_reset2(false);
+}
+
void REGPARAM2 op_unimpl (uae_u16 opcode)
{
}
}
-
// handle interrupt delay (few cycles)
STATIC_INLINE bool time_for_interrupt (void)
{
void doint (void)
{
- if (currprefs.cpu_cycle_exact) {
+ if (m68k_interrupt_delay) {
regs.ipl_pin = intlev ();
unset_special (SPCFLAG_INT);
return;
if (regs.spcflags & SPCFLAG_COPPER)
do_copper ();
- if (currprefs.cpu_cycle_exact) {
+ if (m68k_interrupt_delay) {
ipl_fetch ();
if (time_for_interrupt ()) {
do_interrupt (regs.ipl);
if (regs.spcflags & SPCFLAG_TRACE)
do_trace ();
- if (currprefs.cpu_cycle_exact) {
+ if (m68k_interrupt_delay) {
if (time_for_interrupt ()) {
do_interrupt (regs.ipl);
}
#endif
+STATIC_INLINE void wait_memory_cycles (void)
+{
+ if (regs.memory_waitstate_cycles) {
+ x_do_cycles(regs.memory_waitstate_cycles);
+ regs.memory_waitstate_cycles = 0;
+ }
+}
+
STATIC_INLINE int adjust_cycles (int cycles)
{
+ int mc = regs.memory_waitstate_cycles;
+ regs.memory_waitstate_cycles = 0;
if (currprefs.m68k_speed < 0 || cycles_mult == 0)
- return cycles;
+ return cycles + mc;
cpu_cycles *= cycles_mult;
cpu_cycles /= CYCLES_DIV;
- return cpu_cycles;
+ return cpu_cycles + mc;
}
#ifndef CPUEMU_11
r->instruction_pc = m68k_getpc ();
(*cpufunctbl[opcode])(opcode);
+ wait_memory_cycles();
if (cpu_tracer) {
cputrace.state = 0;
}
if (!regs.halted) {
write_log (_T("CPU halted: reason = %d\n"), id);
regs.halted = id;
- gui_data.cpu_halted = true;
+ gui_data.cpu_halted = id;
gui_led (LED_CPU, 0);
regs.intmask = 7;
MakeSR ();
#endif
-#if 0
/* "cycle exact" 68040+ */
static void m68k_run_3ce (void)
struct regstruct *r = ®s;
uae_u16 opcode;
bool exit = false;
+ int cycles;
for (;;) {
- r->instruction_pc = m68k_getpc ();
- opcode = get_word_ce040_prefetch (0);
+ r->instruction_pc = m68k_getpc();
+ opcode = get_iword_cache_040(0);
+ // "prefetch"
+ if (regs.cacr & 0x8000)
+ fill_icache040(r->instruction_pc + 16);
(*cpufunctbl[opcode])(opcode);
- if (r->spcflags || time_for_interrupt ()) {
+ cpu_cycles = 4 * CYCLE_UNIT;
+ cycles = adjust_cycles(cpu_cycles);
+ do_cycles(cycles);
+
+ if (r->spcflags) {
if (do_specialties (0))
exit = true;
}
- regs.ipl = regs.ipl_pin;
-
if (exit)
return;
}
}
-#endif
+/* "prefetch" 68040+ */
+
+static void m68k_run_3p(void)
+{
+ struct regstruct *r = ®s;
+ uae_u16 opcode;
+ bool exit = false;
+ int cycles;
+
+ for (;;) {
+ r->instruction_pc = m68k_getpc();
+ opcode = get_iword_cache_040(0);
+ // "prefetch"
+ if (regs.cacr & 0x8000)
+ fill_icache040(r->instruction_pc + 16);
+
+ (*cpufunctbl[opcode])(opcode);
+
+ cpu_cycles = 4 * CYCLE_UNIT;
+ cycles = adjust_cycles(cpu_cycles);
+ do_cycles(cycles);
+
+ if (r->spcflags) {
+ if (do_specialties(0))
+ exit = true;
+ }
+
+ if (exit)
+ return;
+ }
+}
/* "cycle exact" 68020/030 */
}
(*cpufunctbl[opcode])(opcode);
+
+ wait_memory_cycles();
cont:
if (r->spcflags || time_for_interrupt ()) {
#endif
set_cycles (start_cycles);
custom_reset (hardreset != 0, kbreset);
- m68k_reset (hardreset != 0);
+ m68k_reset2 (hardreset != 0);
if (hardreset) {
memory_clear ();
write_log (_T("hardreset, memory cleared\n"));
currprefs.cpu_model == 68030 && currprefs.mmu_model ? m68k_run_mmu030 :
currprefs.cpu_model == 68040 && currprefs.mmu_model ? m68k_run_mmu040 :
currprefs.cpu_model == 68060 && currprefs.mmu_model ? m68k_run_mmu060 :
-#if 0
+
currprefs.cpu_model >= 68040 && currprefs.cpu_cycle_exact ? m68k_run_3ce :
-#endif
currprefs.cpu_model >= 68020 && currprefs.cpu_cycle_exact ? m68k_run_2ce :
- currprefs.cpu_compatible ? (currprefs.cpu_model <= 68020 ? m68k_run_2p : m68k_run_2pf) : m68k_run_2;
+
+ currprefs.cpu_model <= 68020 && currprefs.cpu_compatible ? m68k_run_2p :
+ currprefs.cpu_model >= 68040 && currprefs.cpu_compatible ? m68k_run_3p :
+
+ m68k_run_2;
#if 0
}
#endif
}
for (int i = 0; i < CPU_PIPELINE_MAX; i++)
regs.prefetch020[i] = restore_u32 ();
+ } else if (model == 68040) {
+ if (flags & 0x8000000) {
+ for (int i = 0; i < CACHESETS040; i++) {
+ for (int j = 0; j < CACHELINES040; j++) {
+ icaches040[i].data[j][0] = restore_u32();
+ icaches040[i].data[j][1] = restore_u32();
+ icaches040[i].data[j][2] = restore_u32();
+ icaches040[i].data[j][3] = restore_u32();
+ icaches040[i].tag[j] = restore_u32();
+ icaches040[i].valid[j] = restore_u16() & 1;
+ }
+ }
+ regs.prefetch020addr = restore_u32();
+ regs.cacheholdingaddr020 = restore_u32();
+ regs.cacheholdingdata020 = restore_u32();
+ for (int i = 0; i < CPU_PIPELINE_MAX; i++)
+ regs.prefetch020[i] = restore_u32();
+ }
}
if (model >= 68020) {
regs.ce020memcycles = restore_u32 ();
dstbak = dst = xmalloc (uae_u8, 1000);
model = currprefs.cpu_model;
save_u32 (model); /* MODEL */
- save_u32 (0x80000000 | 0x40000000 | 0x20000000 | 0x10000000 | (currprefs.address_space_24 ? 1 : 0)); /* FLAGS */
+ save_u32(0x80000000 | 0x40000000 | 0x20000000 | 0x10000000 | 0x8000000 |(currprefs.address_space_24 ? 1 : 0)); /* FLAGS */
for (i = 0;i < 15; i++)
save_u32 (regs.regs[i]); /* D0-D7 A0-A6 */
save_u32 (m68k_getpc ()); /* PC */
save_u32 (regs.cacheholdingdata020);
for (int i = 0; i < CPU_PIPELINE_MAX; i++)
save_u32 (regs.prefetch020[i]);
+ } else if (model >= 68040) {
+ for (int i = 0; i < CACHESETS040; i++) {
+ for (int j = 0; j < CACHELINES040; j++) {
+ save_u32(icaches040[i].data[j][0]);
+ save_u32(icaches040[i].data[j][1]);
+ save_u32(icaches040[i].data[j][2]);
+ save_u32(icaches040[i].data[j][3]);
+ save_u32(icaches040[i].tag[j]);
+ save_u16(icaches040[i].valid[j] ? 1 : 0);
+ }
+ }
+ save_u32(regs.prefetch020addr);
+ save_u32(regs.cacheholdingaddr020);
+ save_u32(regs.cacheholdingdata020);
+ for (int i = 0; i < CPU_PIPELINE_MAX; i++)
+ save_u32(regs.prefetch020[i]);
}
if (currprefs.cpu_model >= 68020) {
save_u32 (regs.ce020memcycles);
unset_special (SPCFLAG_STOP);
}
-#if 0
-STATIC_INLINE void fill_cache040 (uae_u32 addr)
-{
- int index, i, lws;
- uae_u32 tag;
- uae_u32 data;
- struct cache040 *c;
- static int linecnt;
-
- addr &= ~15;
- index = (addr >> 4) & (CACHESETS040 - 1);
- tag = regs.s | (addr & ~((CACHESETS040 << 4) - 1));
- lws = (addr >> 2) & 3;
- c = &caches040[index];
- for (i = 0; i < CACHELINES040; i++) {
- if (c->valid[i] && c->tag[i] == tag) {
- // cache hit
- regs.cacheholdingaddr020 = addr;
- regs.cacheholdingdata020 = c->data[i][lws];
- return;
- }
- }
- // cache miss
- data = mem_access_delay_longi_read_ce020 (addr);
- int line = linecnt;
- for (i = 0; i < CACHELINES040; i++) {
- int line = (linecnt + i) & (CACHELINES040 - 1);
- if (c->tag[i] != tag || c->valid[i] == false) {
- c->tag[i] = tag;
- c->valid[i] = true;
- c->data[i][0] = data;
- }
- }
- regs.cacheholdingaddr020 = addr;
- regs.cacheholdingdata020 = data;
-}
-#endif
-
// this one is really simple and easy
static void fill_icache020 (uae_u32 addr, uae_u32 (*fetch)(uaecptr))
{
c->data[1] = get_longi (addr + 4);
c->data[2] = get_longi (addr + 8);
c->data[3] = get_longi (addr + 12);
- do_cycles_ce020_mem (3 * (CPU020_MEM_CYCLE - 1), c->data[3]);
+ if (currprefs.cpu_cycle_exact)
+ do_cycles_ce020_mem (3 * (CPU020_MEM_CYCLE - 1), c->data[3]);
c->valid[1] = c->valid[2] = c->valid[3] = true;
}
regs.cacheholdingaddr020 = addr;
}
// and finally the worst part, 68030 data cache..
-void write_dcache030 (uaecptr addr, uae_u32 val, int size)
+static void write_dcache030x (uaecptr addr, uae_u32 val, int size)
{
struct cache030 *c1, *c2;
int lws1, lws2;
uae_u32 tag1, tag2;
int aligned = addr & 3;
- if (!(regs.cacr & 0x100) || currprefs.cpu_model == 68040) // data cache disabled? 68040 shares this too.
+ if (1 || !(regs.cacr & 0x100)) // data cache disabled?
return;
if (!cancache030 (addr))
return;
}
}
}
+void write_dcache030(uaecptr addr, uae_u32 v, int size)
+{
+ write_dcache030x(addr, v, size);
+ if (currprefs.cpu_cycle_exact) {
+ if (size == 2)
+ mem_access_delay_long_write_ce020(addr, v);
+ else if (size == 1)
+ mem_access_delay_word_write_ce020(addr, v);
+ else
+ mem_access_delay_byte_write_ce020(addr, v);
+ } else {
+ if (size == 2)
+ put_long(addr, v);
+ else if (size == 1)
+ put_word(addr, v);
+ else
+ put_byte(addr, v);
+ }
+}
uae_u32 read_dcache030 (uaecptr addr, int size)
{
int len = (1 << size) * 8;
uae_u32 v1, v2;
- if (!(regs.cacr & 0x100) || currprefs.cpu_model == 68040 || !cancache030 (addr)) { // data cache disabled? shared with 68040 "ce"
+ if (1 || !(regs.cacr & 0x100) || !cancache030 (addr)) { // data cache disabled?
if (currprefs.cpu_cycle_exact) {
if (size == 2)
return mem_access_delay_long_read_ce020 (addr);
return v;
}
+uae_u32 get_word_icache030(uaecptr addr)
+{
+ fill_icache030(addr);
+ return regs.cacheholdingdata020 >> ((addr & 2) ? 0 : 16);
+}
+uae_u32 get_long_icache030(uaecptr addr)
+{
+ uae_u32 v;
+ fill_icache030(addr);
+ if ((addr & 2) == 0)
+ return regs.cacheholdingdata020;
+ v = regs.cacheholdingdata020 << 16;
+ fill_icache030(addr + 4);
+ v |= regs.cacheholdingdata020 >> 16;
+ return v;
+}
+
+uae_u32 fill_icache040(uae_u32 addr)
+{
+ int index, i, lws;
+ uae_u32 tag;
+ struct cache040 *c;
+ int line;
+
+ if (!(regs.cacr & 0x8000)) {
+ uae_u32 addr2 = addr & ~15;
+ lws = (addr >> 2) & 3;
+ addr &= ~3;
+ if (regs.prefetch020addr == addr2)
+ return regs.prefetch020[lws];
+ regs.prefetch020addr = addr2;
+ if (currprefs.cpu_cycle_exact) {
+ regs.prefetch020[0] = mem_access_delay_longi_read_ce020(addr2 + 0);
+ regs.prefetch020[1] = mem_access_delay_longi_read_ce020(addr2 + 4);
+ regs.prefetch020[2] = mem_access_delay_longi_read_ce020(addr2 + 8);
+ regs.prefetch020[3] = mem_access_delay_longi_read_ce020(addr2 + 12);
+ } else {
+ regs.prefetch020[0] = get_longi(addr2 + 0);
+ regs.prefetch020[1] = get_longi(addr2 + 4);
+ regs.prefetch020[2] = get_longi(addr2 + 8);
+ regs.prefetch020[3] = get_longi(addr2 + 12);
+ }
+ return regs.prefetch020[lws];
+ }
+
+ index = (addr >> 4) & (CACHESETS040 - 1);
+ tag = regs.s | (addr & ~((CACHESETS040 << 4) - 1));
+ lws = (addr >> 2) & 3;
+ addr &= ~15;
+ c = &icaches040[index];
+ for (i = 0; i < CACHELINES040; i++) {
+ if (c->valid[i] && c->tag[i] == tag) {
+ // cache hit
+ icachelinecnt++;
+ return c->data[i][lws];
+ }
+ }
+ // cache miss
+ if (c->valid[0] && c->valid[1] && c->valid[2] && c->valid[3]) {
+ line = (icachelinecnt >> 1) & (CACHELINES040 - 1);
+ }
+ else {
+ for (line = 0; line < CACHELINES040; line++) {
+ if (c->valid[line] == false)
+ break;
+ }
+ }
+ c->tag[line] = tag;
+ c->valid[line] = true;
+ if (currprefs.cpu_cycle_exact) {
+ c->data[line][0] = mem_access_delay_longi_read_ce020(addr + 0);
+ c->data[line][1] = mem_access_delay_longi_read_ce020(addr + 4);
+ c->data[line][2] = mem_access_delay_longi_read_ce020(addr + 8);
+ c->data[line][3] = mem_access_delay_longi_read_ce020(addr + 12);
+ } else {
+ c->data[line][0] = get_longi(addr + 0);
+ c->data[line][1] = get_longi(addr + 4);
+ c->data[line][2] = get_longi(addr + 8);
+ c->data[line][3] = get_longi(addr + 12);
+ }
+ return c->data[line][lws];
+}
+
+#if 0
+static bool is_dcache040(uae_u32 addr)
+{
+ int index, i, lws;
+ uae_u32 tag;
+ struct cache040 *c;
+
+ addr &= ~15;
+ index = (addr >> 4) & (CACHESETS040 - 1);
+ tag = regs.s | (addr & ~((CACHESETS040 << 4) - 1));
+ lws = (addr >> 2) & 3;
+ c = &dcaches040[index];
+ for (i = 0; i < CACHELINES040; i++) {
+ if (c->valid[i] && c->tag[i] == tag) {
+ return true;
+ }
+ }
+ return false;
+}
+
+uae_u32 read_dcache040(uae_u32 addr)
+{
+ int index, i, lws;
+ uae_u32 tag;
+ struct cache040 *c;
+ int line;
+
+ addr &= ~15;
+ index = (addr >> 4) & (CACHESETS040 - 1);
+ tag = regs.s | (addr & ~((CACHESETS040 << 4) - 1));
+ lws = (addr >> 2) & 3;
+ c = &dcaches040[index];
+ for (i = 0; i < CACHELINES040; i++) {
+ if (c->valid[i] && c->tag[i] == tag) {
+ // cache hit
+ dcachelinecnt++;
+ return c->data[i][lws];
+ }
+ }
+ // cache miss
+ if (c->valid[0] && c->valid[1] && c->valid[2] && c->valid[3]) {
+ line = (icachelinecnt >> 1) & (CACHELINES040 - 1);
+ for (i = 0; i < 4; i++) {
+ if (c->dirty[line][i]) {
+ c->dirty[line][i] = false;
+ mem_access_delay_long_write_ce020(addr + i * 4, c->data[line][i]);
+ }
+ }
+ }
+ else {
+ for (line = 0; line < CACHELINES040; line++) {
+ if (c->valid[line] == false)
+ break;
+ }
+ }
+ c->tag[line] = tag;
+ c->valid[line] = true;
+ c->data[line][0] = mem_access_delay_long_read_ce020(addr + 0);
+ c->data[line][1] = mem_access_delay_long_read_ce020(addr + 4);
+ c->data[line][2] = mem_access_delay_long_read_ce020(addr + 8);
+ c->data[line][3] = mem_access_delay_long_read_ce020(addr + 12);
+ regs.cacheholdingaddr020 = addr;
+}
+
+void write_dcache040(uae_u32 addr, uae_u32 val)
+{
+ int index, i, lws;
+ uae_u32 tag;
+ struct cache040 *c;
+ int line;
+
+ addr &= ~15;
+ index = (addr >> 4) & (CACHESETS040 - 1);
+ tag = regs.s | (addr & ~((CACHESETS040 << 4) - 1));
+ lws = (addr >> 2) & 3;
+ c = &dcaches040[index];
+ for (i = 0; i < CACHELINES040; i++) {
+ if (c->valid[i] && c->tag[i] == tag) {
+ // cache hit
+ dcachelinecnt++;
+ c->data[i][lws] = val;
+ mem_access_delay_long_write_ce020(addr + i * 4, c->data[i][lws]);
+ //c->dirty[i][lws] = true;
+ }
+ }
+#if 0
+ // cache miss
+ if (c->valid[0] && c->valid[1] && c->valid[2] && c->valid[3]) {
+ line = (icachelinecnt >> 1) & (CACHELINES040 - 1);
+ for (i = 0; i < 4; i++) {
+ if (c->dirty[line][i]) {
+ c->dirty[line][i] = false;
+ mem_access_delay_long_write_ce020(addr + i * 4, c->data[line][i]);
+ }
+ }
+ }
+ else {
+ for (line = 0; line < CACHELINES040; line++) {
+ if (c->valid[line] == false)
+ break;
+ }
+ }
+ c->tag[line] = tag;
+ c->valid[line] = true;
+ c->data[line][0] = mem_access_delay_long_read_ce020(addr + 0);
+ c->data[line][1] = mem_access_delay_long_read_ce020(addr + 4);
+ c->data[line][2] = mem_access_delay_long_read_ce020(addr + 8);
+ c->data[line][3] = mem_access_delay_long_read_ce020(addr + 12);
+ c->data[line][lws] = val;
+ c->dirty[line][lws] = true;
+#endif
+}
+#endif
+
+// really unoptimized
+uae_u32 get_word_icache040(uaecptr addr)
+{
+ uae_u32 v = fill_icache040(addr);
+ return v >> ((addr & 2) ? 0 : 16);
+}
+uae_u32 get_long_icache040(uaecptr addr)
+{
+ uae_u32 v1, v2;
+ v1 = fill_icache040(addr);
+ if ((addr & 2) == 0)
+ return v1;
+ v2 = fill_icache040(addr + 4);
+ return (v2 >> 16) | (v1 << 16);
+}
+uae_u32 get_ilong_cache_040(int o)
+{
+ return get_long_icache040(m68k_getpci() + o);
+}
+uae_u32 get_iword_cache_040(int o)
+{
+ return get_word_icache040(m68k_getpci() + o);
+}
+
+void put_long_cache_040(uaecptr addr, uae_u32 v)
+{
+#if 1
+ if (currprefs.cpu_cycle_exact)
+ mem_access_delay_long_write_ce020(addr, v);
+ else
+ put_long(addr, v);
+#else
+ if ((addr & 2) == 0) {
+ if (is_dcache040(addr))
+ write_dcache040(addr, v);
+ else if (currprefs.cpu_cycle_exact)
+ mem_access_delay_long_write_ce020(addr, v);
+ else
+ put_long(addr, v);
+ } else {
+ uae_u32 vp;
+ if (is_dcache040(addr)) {
+ vp = read_dcache040(addr);
+ vp &= 0xffff0000;
+ vp |= v >> 16;
+ write_dcache040(addr, vp);
+ } else if (currprefs.cpu_cycle_exact) {
+ mem_access_delay_word_write_ce020(addr + 0, v >> 16);
+ } else {
+ put_word(addr + 0, v >> 16);
+ }
+ if (is_dcache040(addr + 4)) {
+ vp = read_dcache040(addr + 4);
+ vp &= 0x0000ffff;
+ vp |= v << 16;
+ write_dcache040(addr + 4, vp);
+ } else if (currprefs.cpu_cycle_exact) {
+ mem_access_delay_word_write_ce020(addr + 2, v);
+ } else {
+ put_word(addr + 2, v);
+ }
+ }
+#endif
+}
+void put_word_cache_040(uaecptr addr, uae_u32 v)
+{
+#if 1
+ if (currprefs.cpu_cycle_exact)
+ mem_access_delay_word_write_ce020(addr, v);
+ else
+ put_word(addr, v);
+#else
+ if (is_dcache040(addr)) {
+ uae_u32 vp;
+ vp = read_dcache040(addr);
+ if (addr & 2) {
+ vp &= 0xffff0000;
+ vp |= v & 0xffff;
+ } else {
+ vp &= 0x0000ffff;
+ vp |= v << 16;
+ }
+ write_dcache040(addr, vp);
+ } else if (currprefs.cpu_cycle_exact) {
+ mem_access_delay_word_write_ce020(addr, v);
+ } else {
+ put_word(addr, v);
+ }
+#endif
+}
+void put_byte_cache_040(uaecptr addr, uae_u32 v)
+{
+#if 1
+ if (currprefs.cpu_cycle_exact)
+ mem_access_delay_byte_write_ce020(addr, v);
+ else
+ put_byte(addr, v);
+#else
+ if (is_dcache040(addr)) {
+ uae_u32 vp;
+ uae_u32 mask = 0xff000000 >> (addr & 3);
+ vp = read_dcache040(addr);
+ vp &= ~mask;
+ vp |= (v << (3 - (addr & 3))) & mask;
+ write_dcache040(addr, vp);
+ } else if (currprefs.cpu_cycle_exact) {
+ mem_access_delay_byte_write_ce020(addr, v);
+ } else {
+ put_byte(addr, v);
+ }
+#endif
+}
+
+uae_u32 get_long_cache_040(uaecptr addr)
+{
+#if 1
+ if (currprefs.cpu_cycle_exact)
+ return mem_access_delay_long_read_ce020(addr);
+ else
+ return get_long(addr);
+#else
+ uae_u32 v1, v2;
+ v1 = read_dcache040(addr);
+ if ((addr & 2) == 0)
+ return v1;
+ v2 = read_dcache040(addr + 4);
+ return (v2 >> 16) | (v1 << 16);
+#endif
+}
+uae_u32 get_word_cache_040(uaecptr addr)
+{
+#if 1
+ if (currprefs.cpu_cycle_exact)
+ return mem_access_delay_word_read_ce020(addr);
+ else
+ return get_word(addr);
+#else
+ uae_u32 v = read_dcache040(addr);
+ return v >> ((addr & 2) ? 0 : 16);
+#endif
+}
+uae_u32 get_byte_cache_040(uaecptr addr)
+{
+#if 1
+ if (currprefs.cpu_cycle_exact)
+ return mem_access_delay_byte_read_ce020(addr);
+ else
+ return get_byte(addr);
+#else
+ uae_u32 v = read_dcache040(addr);
+ return v >> (8 * (3 - (addr & 3)));
+#endif
+}
+uae_u32 next_iword_cache040(void)
+{
+ uae_u32 r = get_word_icache040(m68k_getpci());
+ m68k_incpci(2);
+ return r;
+}
+uae_u32 next_ilong_cache040(void)
+{
+ uae_u32 r = get_long_icache040(m68k_getpci());
+ m68k_incpci(4);
+ return r;
+}
+
void flush_dcache (uaecptr addr, int size)
{
- if (!currprefs.cpu_cycle_exact)
+ if (!currprefs.cpu_cycle_exact && !currprefs.cpu_compatible)
return;
if (currprefs.cpu_model >= 68030) {
for (int i = 0; i < CACHELINES030; i++) {
{
if (currprefs.cachesize)
return;
- if (currprefs.cpu_model == 68020) {
+ if (currprefs.cpu_model >= 68040) {
+ if (currprefs.cpu_compatible || currprefs.cpu_cycle_exact) {
+ fill_icache040(m68k_getpc() + 16);
+ fill_icache040(m68k_getpc());
+ }
+ } else if (currprefs.cpu_model == 68020) {
fill_prefetch_020 ();
} else if (currprefs.cpu_model == 68030) {
if (!currprefs.cpu_cycle_exact)
return v;
}
+uae_u32 REGPARAM2 x_get_disp_ea_040(uae_u32 base, int idx)
+{
+ uae_u16 dp = next_iword_cache040();
+ int reg = (dp >> 12) & 15;
+ uae_s32 regd = regs.regs[reg];
+ if ((dp & 0x800) == 0)
+ regd = (uae_s32)(uae_s16)regd;
+ regd <<= (dp >> 9) & 3;
+ if (dp & 0x100) {
+ uae_s32 outer = 0;
+ if (dp & 0x80) base = 0;
+ if (dp & 0x40) regd = 0;
+
+ if ((dp & 0x30) == 0x20)
+ base += (uae_s32)(uae_s16)next_iword_cache040();
+ if ((dp & 0x30) == 0x30)
+ base += next_ilong_cache040();
+
+ if ((dp & 0x3) == 0x2)
+ outer = (uae_s32)(uae_s16)next_iword_cache040();
+ if ((dp & 0x3) == 0x3)
+ outer = next_ilong_cache040();
+
+ if ((dp & 0x4) == 0)
+ base += regd;
+ if (dp & 0x3)
+ base = x_get_long(base);
+ if (dp & 0x4)
+ base += regd;
+
+ return base + outer;
+ }
+ else {
+ return base + (uae_s32)((uae_s8)dp) + regd;
+ }
+}
/*
* Compute exact number of CPU cycles taken
if (offset == 0) {
if (!hfd->handle->firstwrite && (hfd->flags & HFD_FLAGS_REALDRIVE) && !(hfd->flags & HFD_FLAGS_REALDRIVEPARTITION)) {
hfd->handle->firstwrite = true;
- if (ismounted (hfd->device_name, hfd->handle->h)) {
+ if (ismounted (hfd->ci.devname, hfd->handle->h)) {
gui_message (_T("\"%s\"\n\nBlock zero write attempt but drive has one or more mounted PC partitions or WinUAE does not have Administrator privileges. Erase the drive or unmount all PC partitions first."), name);
hfd->ci.readonly = true;
return 0;
#define FPCR_PRECISION_DOUBLE 0x00000080
#define FPCR_PRECISION_EXTENDED 0x00000000
+extern void to_single(fpdata *fpd, uae_u32 value);
+extern void to_double(fpdata *fpd, uae_u32 wrd1, uae_u32 wrd2);
+extern void to_exten(fpdata *fpd, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3);
+
STATIC_INLINE void exten_zeronormalize(uae_u32 *pwrd1, uae_u32 *pwrd2, uae_u32 *pwrd3)
{
uae_u32 wrd1 = *pwrd1;
}
#if USE_LONG_DOUBLE
-STATIC_INLINE void to_exten(fpdata *dst, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
+STATIC_INLINE void to_exten_x(fptype *fp, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
{
// force correct long double alignment
union
uld.longarray[1] = wrd2;
uld.longarray[2] = wrd1 >> 16;
long double *longdoublewords = (long double *)uld.longarray;
- dst->fp = *longdoublewords;
+ *fp = *longdoublewords;
}
#define HAVE_to_exten
-STATIC_INLINE void from_exten(fpdata *src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
+STATIC_INLINE void from_exten_x(fptype fp, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
{
- uae_u32 *longarray = (uae_u32 *)&src->fp;
- uae_u16 *finalword = (uae_u16 *)(((uae_u8*)&src->fp) + 8);
+ uae_u32 *longarray = (uae_u32 *)&fp;
+ uae_u16 *finalword = (uae_u16 *)(((uae_u8*)&fp) + 8);
*wrd1 = finalword[0] << 16;
*wrd2 = longarray[1];
#if defined(X86_MSVC_ASSEMBLY_FPU)
#ifndef HAVE_to_single
#define HAVE_to_single
-STATIC_INLINE double to_single (uae_u32 longvalue)
+STATIC_INLINE double to_single_x (uae_u32 longvalue)
{
double floatfake;
#ifndef HAVE_from_single
#define HAVE_from_single
-STATIC_INLINE uae_u32 from_single (double floatfake)
+STATIC_INLINE uae_u32 from_single_x (double floatfake)
{
uae_u32 longvalue;
#ifndef HAVE_to_exten
#define HAVE_to_exten
-STATIC_INLINE void to_exten(fpdata *fpd, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
+STATIC_INLINE void to_exten_x(fptype *fp, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
{
uae_u32 longarray[3];
double extenfake;
fld tbyte ptr longarray;
fstp qword ptr extenfake;
}
- fpd->fp = extenfake;
-#ifdef USE_SOFT_LONG_DOUBLE
- fpd->fpe = ((uae_u64)wrd2 << 32) | wrd3;
- fpd->fpm = wrd1;
- fpd->fpx = true;
-#endif
+ *fp = extenfake;
}
#endif
#ifndef HAVE_from_exten
#define HAVE_from_exten
-STATIC_INLINE void from_exten(fpdata *fpd, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
+STATIC_INLINE void from_exten_x(fptype fp, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
{
-#ifdef USE_SOFT_LONG_DOUBLE
- if (fpd->fpx) {
- *wrd1 = fpd->fpm;
- *wrd2 = fpd->fpe >> 32;
- *wrd3 = (uae_u32)fpd->fpe;
- } else
-#endif
- {
- fptype src = fpd->fp;
- uae_u32 longarray[3], *srcarray = (uae_u32 *)&src;
- __asm {
- fld qword ptr src;
- fstp tbyte ptr longarray;
- }
- *wrd1 = (longarray[2] & 0xffff) <<16;
- *wrd2 = longarray[1];
- *wrd3 = longarray[0]; // little endian
- if (!srcarray[0] && (srcarray[1] == 0x7ff00000 || srcarray[1] == 0xfff00000))
- *wrd2 = 0; // The MSB of the mantissa was set wrongly for infinity, causing a NaN
+ fptype src = fp;
+ uae_u32 longarray[3], *srcarray = (uae_u32 *)&src;
+ __asm {
+ fld qword ptr src;
+ fstp tbyte ptr longarray;
}
+ *wrd1 = (longarray[2] & 0xffff) <<16;
+ *wrd2 = longarray[1];
+ *wrd3 = longarray[0]; // little endian
+ if (!srcarray[0] && (srcarray[1] == 0x7ff00000 || srcarray[1] == 0xfff00000))
+ *wrd2 = 0; // The MSB of the mantissa was set wrongly for infinity, causing a NaN
}
#endif
#endif /* X86_MSVC_ASSEMBLY */
#ifndef HAVE_to_single
#define HAVE_to_single
-STATIC_INLINE double to_single (uae_u32 value)
+STATIC_INLINE double to_single_x (uae_u32 value)
{
union {
float f;
#ifndef HAVE_from_single
#define HAVE_from_single
-STATIC_INLINE uae_u32 from_single (double src)
+STATIC_INLINE uae_u32 from_single_x (double src)
{
union {
float f;
#ifndef HAVE_to_double
#define HAVE_to_double
-STATIC_INLINE double to_double(uae_u32 wrd1, uae_u32 wrd2)
+STATIC_INLINE double to_double_x(uae_u32 wrd1, uae_u32 wrd2)
{
union {
double d;
#ifndef HAVE_from_double
#define HAVE_from_double
-STATIC_INLINE void from_double(double src, uae_u32 * wrd1, uae_u32 * wrd2)
+STATIC_INLINE void from_double_x(double src, uae_u32 * wrd1, uae_u32 * wrd2)
{
uae_u32 *longarray = (uae_u32 *)&src;
static const double twoto32 = 4294967296.0;
#ifndef HAVE_to_exten
#define HAVE_to_exten
-STATIC_INLINE void to_exten(fpdata *fpd, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
+STATIC_INLINE void to_exten_x(fptype *fp, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
{
double frac;
-
-#ifdef USE_SOFT_LONG_DOUBLE
- fpd->fpe = ((uae_u64)wrd2 << 32) | wrd3;
- fpd->fpm = wrd1;
- fpd->fpx = true;
-#endif
exten_zeronormalize(&wrd1, &wrd2, &wrd3);
if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) {
- fpd->fp = (wrd1 & 0x80000000) ? -0.0 : +0.0;
+ *fp = (wrd1 & 0x80000000) ? -0.0 : +0.0;
return;
}
frac = ((double)wrd2 + ((double)wrd3 / twoto32)) / 2147483648.0;
if (wrd1 & 0x80000000)
frac = -frac;
- fpd->fp = ldexp (frac, ((wrd1 >> 16) & 0x7fff) - 16383);
+ *fp = ldexp (frac, ((wrd1 >> 16) & 0x7fff) - 16383);
}
#endif
#ifndef HAVE_from_exten
#define HAVE_from_exten
-STATIC_INLINE void from_exten(fpdata *fpd, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
+STATIC_INLINE void from_exten_x(fptype fp, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
{
int expon;
double frac;
fptype v;
-#ifdef USE_SOFT_LONG_DOUBLE
- if (fpd->fpx) {
- *wrd1 = fpd->fpm;
- *wrd2 = fpd->fpe >> 32;
- *wrd3 = (uae_u32)fpd->fpe;
- } else
-#endif
- {
- v = fpd->fp;
- if (v == 0.0) {
- *wrd1 = signbit(v) ? 0x80000000 : 0;
- *wrd2 = 0;
- *wrd3 = 0;
- return;
- }
- if (v < 0) {
- *wrd1 = 0x80000000;
- v = -v;
- } else {
- *wrd1 = 0;
- }
- frac = frexp (v, &expon);
- frac += 0.5 / (twoto32 * twoto32);
- if (frac >= 1.0) {
- frac /= 2.0;
- expon++;
- }
- *wrd1 |= (((expon + 16383 - 1) & 0x7fff) << 16);
- *wrd2 = (uae_u32) (frac * twoto32);
- *wrd3 = (uae_u32) ((frac * twoto32 - *wrd2) * twoto32);
+ v = fp;
+ if (v == 0.0) {
+ *wrd1 = signbit(v) ? 0x80000000 : 0;
+ *wrd2 = 0;
+ *wrd3 = 0;
+ return;
+ }
+ if (v < 0) {
+ *wrd1 = 0x80000000;
+ v = -v;
+ } else {
+ *wrd1 = 0;
+ }
+ frac = frexp (v, &expon);
+ frac += 0.5 / (twoto32 * twoto32);
+ if (frac >= 1.0) {
+ frac /= 2.0;
+ expon++;
}
+ *wrd1 |= (((expon + 16383 - 1) & 0x7fff) << 16);
+ *wrd2 = (uae_u32) (frac * twoto32);
+ *wrd3 = (uae_u32) ((frac * twoto32 - *wrd2) * twoto32);
}
#endif
if (!a3000hmem_bank.start)
size += BARRIER;
got = TRUE;
- } else if(!_tcscmp (shmids[shmid].name, _T("ramsey_high"))) {
- shmaddr=natmem_offset + a3000hmem_bank.start;
+ } else if (!_tcscmp(shmids[shmid].name, _T("cyberstorm"))) {
+ shmaddr = natmem_offset + 0x0c000000;
got = TRUE;
- } else if(!_tcscmp (shmids[shmid].name, _T("z3"))) {
+ } else if (!_tcscmp(shmids[shmid].name, _T("cyberstormmaprom"))) {
+ shmaddr = natmem_offset + 0xfff00000;
+ got = TRUE;
+ } else if (!_tcscmp(shmids[shmid].name, _T("z3"))) {
shmaddr=natmem_offset + z3fastmem_bank.start;
if (!currprefs.z3fastmem2_size)
size += BARRIER;
EDITTEXT IDC_FASTRAM2,326,196,40,12,ES_CENTER | ES_READONLY
CONTROL "JIT Direct compatible Z3 memory mapping",IDC_Z3REALMAPPING,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,180,220,186,10
- COMBOBOX IDC_CPUBOARD_TYPE,25,257,89,75,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ COMBOBOX IDC_CPUBOARD_TYPE,8,257,117,75,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
RTEXT "Second Z2 Fast RAM board:",IDC_STATIC,129,194,116,15,SS_CENTERIMAGE
- RTEXT "Accelerator board memory:",IDC_STATIC,129,257,116,15,SS_CENTERIMAGE
+ RTEXT "Accelerator board memory:",IDC_STATIC,138,257,104,15,SS_CENTERIMAGE
CONTROL "",IDC_CPUBOARDMEM,"msctls_trackbar32",TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,251,253,68,20
EDITTEXT IDC_CPUBOARDRAM,326,256,40,12,ES_CENTER | ES_READONLY
CTEXT "Accelerator board emulation is not JIT Direct compatible.",IDC_STATIC,25,238,341,15,SS_CENTERIMAGE
per = ((serper & 0x7fff) + 1) * (bits - 1);
if (lastbitcycle_active_hsyncs) {
// if last bit still transmitting, add remaining time.
- int extraper = (lastbitcycle - get_cycles()) / CYCLE_UNIT;
+ int extraper = lastbitcycle - get_cycles();
if (extraper > 0)
- per += extraper;
+ per += extraper / CYCLE_UNIT;
}
if (per < 4)
per = 4;
#include "picasso96_win.h"
#include "win32gfx.h"
#include "statusline.h"
+#include "gui.h"
+#include "xwin.h"
static HDC statusline_hdc;
static HBITMAP statusline_bitmap;
uae_u32 white = rc[0xff] | gc[0xff] | bc[0xff] | (alpha ? alpha[0xff] : 0);
uae_u32 back = rc[0x00] | gc[0x00] | bc[0x00] | (alpha ? alpha[0xa0] : 0);
const TCHAR *text;
- int y = -1;
- int x = 10;
+ int y = -1, x = 10, textwidth = 0;
+ int bar_xstart;
- if (currprefs.gf[WIN32GFX_IsPicassoScreen()].gfx_filter == 0)
+ if (currprefs.gf[WIN32GFX_IsPicassoScreen()].gfx_filter == 0 && !currprefs.gfx_api)
return;
text = statusline_fetch();
//text = _T("Testing string 123!");
if (!text)
return;
BitBlt(statusline_hdc, 0, 0, statusline_width, statusline_height, NULL, 0, 0, BLACKNESS);
-#if 0
+
SIZE size;
if (GetTextExtentPoint32(statusline_hdc, text, _tcslen(text), &size)) {
- int w = size.cx;
+ textwidth = size.cx;
+ if (isfullscreen()) {
+ if (td_pos & TD_RIGHT) {
+ bar_xstart = width - TD_PADX - VISIBLE_LEDS * TD_WIDTH;
+ x = bar_xstart - textwidth - TD_LED_WIDTH;
+ } else {
+ bar_xstart = TD_PADX;
+ x = bar_xstart + textwidth + TD_LED_WIDTH;
+ }
+ }
}
-#endif
+ if (x < 0)
+ x = 0;
TextOut(statusline_hdc, x, y, text, _tcslen(text));
for (int y = 0; y < height && y < statusline_height; y++) {
#define UAESERIAL /* uaeserial.device emulation */
#define FPUEMU /* FPU emulation */
#define FPU_UAE
-#define USE_LONG_DOUBLE 0
+#define WITH_SOFTFLOAT
#define MMUEMU /* Aranym 68040 MMU */
#define FULLMMU /* Aranym 68040 MMU */
#define CPUEMU_0 /* generic 680x0 emulation */
#define CPUEMU_13 /* 68000/68010 cycle-exact cpu&blitter */
#define CPUEMU_20 /* 68020 prefetch */
#define CPUEMU_21 /* 68020 "cycle-exact" + blitter */
-#define CPUEMU_22 /* 68030 (040/060) "cycle-exact" + blitter */
+#define CPUEMU_22 /* 68030 "cycle-exact" + blitter */
+#define CPUEMU_23 /* 68040/060 "cycle-exact" + blitter */
#define CPUEMU_31 /* Aranym 68040 MMU */
#define CPUEMU_32 /* Previous 68030 MMU */
#define CPUEMU_33 /* 68060 MMU */
#define LANG_DLL_FULL_VERSION_MATCH 1
#if WINUAEPUBLICBETA
-#define WINUAEBETA _T("4")
+#define WINUAEBETA _T("5")
#else
#define WINUAEBETA _T("")
#endif
-#define WINUAEDATE MAKEBD(2014, 7, 20)
+#define WINUAEDATE MAKEBD(2014, 7, 25)
//#define WINUAEEXTRA _T("AmiKit Preview")
//#define WINUAEEXTRA _T("Amiga Forever Edition")
_T("A3000:%s"),
_T("A4000T:%s"),
_T("CDTV:%s"),
- _T("WarpEngine:%s")
+ _T("Accelerator:%s")
};
if (ci->controller_unit == 7 && (ctype == HD_CONTROLLER_TYPE_SCSI_A2091 || ctype == HD_CONTROLLER_TYPE_SCSI_A2091_2))
_tcscpy(sid, _T("XT"));
case 0x02000000: mem_size = 6; break;
case 0x04000000: mem_size = 7; break;
case 0x08000000: mem_size = 8; break;
+ case 0x10000000: mem_size = 9; break;
}
SendDlgItemMessage (hDlg, IDC_CPUBOARDMEM, TBM_SETPOS, TRUE, mem_size);
SetDlgItemText (hDlg, IDC_CPUBOARDRAM, memsize_names[msi_gfx[mem_size]]);
SendDlgItemMessage (hDlg, IDC_CPUBOARD_TYPE, CB_ADDSTRING, 0, (LPARAM)_T("-"));
SendDlgItemMessage (hDlg, IDC_CPUBOARD_TYPE, CB_ADDSTRING, 0, (LPARAM)_T("Blizzard 1230 IV"));
SendDlgItemMessage (hDlg, IDC_CPUBOARD_TYPE, CB_ADDSTRING, 0, (LPARAM)_T("Blizzard 1260"));
- SendDlgItemMessage (hDlg, IDC_CPUBOARD_TYPE, CB_ADDSTRING, 0, (LPARAM)_T("Blizzard 2060 (Do not use)"));
- SendDlgItemMessage (hDlg, IDC_CPUBOARD_TYPE, CB_ADDSTRING, 0, (LPARAM)_T("Warp Engine A4000"));
+ SendDlgItemMessage(hDlg, IDC_CPUBOARD_TYPE, CB_ADDSTRING, 0, (LPARAM)_T("Blizzard 2060 (Do not use)"));
+ SendDlgItemMessage(hDlg, IDC_CPUBOARD_TYPE, CB_ADDSTRING, 0, (LPARAM)_T("CyberStorm MK III"));
+ SendDlgItemMessage(hDlg, IDC_CPUBOARD_TYPE, CB_ADDSTRING, 0, (LPARAM)_T("CyberStorm PPC (NO PPC CPU!)"));
+ SendDlgItemMessage(hDlg, IDC_CPUBOARD_TYPE, CB_ADDSTRING, 0, (LPARAM)_T("Blizzard PPC (NO PPC CPU!)"));
+ SendDlgItemMessage(hDlg, IDC_CPUBOARD_TYPE, CB_ADDSTRING, 0, (LPARAM)_T("Warp Engine A4000"));
case WM_USER:
workprefs.fastmem_autoconfig = ischecked (hDlg, IDC_FASTMEMAUTOCONFIG);
ew (hDlg, IDC_SPEED, !workprefs.cpu_cycle_exact);
ew (hDlg, IDC_COMPATIBLE24, workprefs.cpu_model == 68020);
- ew (hDlg, IDC_CS_HOST, !workprefs.cpu_cycle_exact);
- ew (hDlg, IDC_CS_68000, !workprefs.cpu_cycle_exact);
- ew (hDlg, IDC_CS_ADJUSTABLE, !workprefs.cpu_cycle_exact);
+ //ew (hDlg, IDC_CS_HOST, !workprefs.cpu_cycle_exact);
+ //ew (hDlg, IDC_CS_68000, !workprefs.cpu_cycle_exact);
+ //ew (hDlg, IDC_CS_ADJUSTABLE, !workprefs.cpu_cycle_exact);
ew (hDlg, IDC_CPUIDLE, workprefs.m68k_speed != 0 ? TRUE : FALSE);
#if !defined(CPUEMU_0) || defined(CPUEMU_68000_ONLY)
ew (hDlg, IDC_CPU1, FALSE);
if (workprefs.cpu_compatible || workprefs.cpu_cycle_exact)
workprefs.fpu_model = 0;
workprefs.address_space_24 = 1;
- if (newcpu == 0 && workprefs.cpu_cycle_exact)
- workprefs.m68k_speed = 0;
+// if (newcpu == 0 && workprefs.cpu_cycle_exact)
+// workprefs.m68k_speed = 0;
break;
case 68020:
workprefs.fpu_model = newfpu == 0 ? 0 : (newfpu == 2 ? 68882 : 68881);
SendDlgItemMessage (hDlg, IDC_HDF_CONTROLLER, CB_ADDSTRING, 0, (LPARAM)_T("A3000 SCSI"));
SendDlgItemMessage (hDlg, IDC_HDF_CONTROLLER, CB_ADDSTRING, 0, (LPARAM)_T("A4000T SCSI"));
SendDlgItemMessage (hDlg, IDC_HDF_CONTROLLER, CB_ADDSTRING, 0, (LPARAM)_T("CDTV SCSI"));
- SendDlgItemMessage (hDlg, IDC_HDF_CONTROLLER, CB_ADDSTRING, 0, (LPARAM)_T("Warp Engine SCSI"));
- SendDlgItemMessage (hDlg, IDC_HDF_CONTROLLER, CB_ADDSTRING, 0, (LPARAM)_T("PCMCIA SRAM"));
+ SendDlgItemMessage(hDlg, IDC_HDF_CONTROLLER, CB_ADDSTRING, 0, (LPARAM)_T("Accelerator board SCSI"));
+ SendDlgItemMessage(hDlg, IDC_HDF_CONTROLLER, CB_ADDSTRING, 0, (LPARAM)_T("PCMCIA SRAM"));
SendDlgItemMessage (hDlg, IDC_HDF_CONTROLLER, CB_ADDSTRING, 0, (LPARAM)_T("PCMCIA IDE"));
SendDlgItemMessage (hDlg, IDC_HDF_CONTROLLER, CB_SETCURSEL, ctype, 0);
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
- <AdditionalDependencies>ws2_32.lib;ddraw.lib;dxguid.lib;winmm.lib;comctl32.lib;version.lib;msacm32.lib;dsound.lib;dinput8.lib;d3d9.lib;d3dx9.lib;winio.lib;setupapi.lib;wininet.lib;dxerr.lib;shlwapi.lib;libpng15.lib;lglcd.lib;wpcap.lib;packet.lib;openal32.lib;portaudio_x86.lib;vfw32.lib;wtsapi32.lib;enet.lib;lzmalib.lib;prowizard.lib;libFLAC_static.lib;Avrt.lib;hid.lib;zlibstat.lib;Iphlpapi.lib;luastatic.lib;libmpeg2_ff.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>ws2_32.lib;ddraw.lib;dxguid.lib;winmm.lib;comctl32.lib;version.lib;msacm32.lib;dsound.lib;dinput8.lib;d3d9.lib;d3dx9.lib;winio.lib;setupapi.lib;wininet.lib;dxerr.lib;shlwapi.lib;libpng15.lib;lglcd.lib;wpcap.lib;packet.lib;openal32.lib;portaudio_x86.lib;vfw32.lib;wtsapi32.lib;enet.lib;lzmalib.lib;prowizard.lib;libFLAC_static.lib;Avrt.lib;hid.lib;zlibstat.lib;Iphlpapi.lib;luastatic.lib;libmpeg2_ff.lib;softfloat.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories);$(SolutionDir)\..\lib\</AdditionalLibraryDirectories>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
- <AdditionalDependencies>ws2_32.lib;ddraw.lib;dxguid.lib;winmm.lib;comctl32.lib;version.lib;msacm32.lib;dsound.lib;dinput8.lib;d3d9.lib;d3dx9.lib;winio.lib;setupapi.lib;wininet.lib;dxerr.lib;shlwapi.lib;libpng15.lib;lglcd.lib;wpcap.lib;packet.lib;openal32.lib;portaudio_x86.lib;vfw32.lib;wtsapi32.lib;enet.lib;lzmalib.lib;prowizard.lib;libFLAC_static.lib;Avrt.lib;hid.lib;zlibstat.lib;Iphlpapi.lib;luastatic.lib;libmpeg2_ff.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>ws2_32.lib;ddraw.lib;dxguid.lib;winmm.lib;comctl32.lib;version.lib;msacm32.lib;dsound.lib;dinput8.lib;d3d9.lib;d3dx9.lib;winio.lib;setupapi.lib;wininet.lib;dxerr.lib;shlwapi.lib;libpng15.lib;lglcd.lib;wpcap.lib;packet.lib;openal32.lib;portaudio_x86.lib;vfw32.lib;wtsapi32.lib;enet.lib;lzmalib.lib;prowizard.lib;libFLAC_static.lib;Avrt.lib;hid.lib;zlibstat.lib;Iphlpapi.lib;luastatic.lib;libmpeg2_ff.lib;softfloat.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories);$(SolutionDir)\..\lib\</AdditionalLibraryDirectories>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
- <AdditionalDependencies>ws2_32.lib;ddraw.lib;dxguid.lib;winmm.lib;comctl32.lib;version.lib;msacm32.lib;dsound.lib;dinput8.lib;d3d9.lib;d3dx9.lib;winio.lib;setupapi.lib;wininet.lib;dxerr.lib;shlwapi.lib;zlibstat.lib;libpng15.lib;lglcd.lib;wpcap.lib;packet.lib;openal32.lib;portaudio_x86.lib;vfw32.lib;wtsapi32.lib;avrt.lib;enet.lib;prowizard.lib;lzmalib.lib;libFLAC_static.lib;Avrt.lib;hid.lib;Iphlpapi.lib;luastatic.lib;libmpeg2_ff.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>ws2_32.lib;ddraw.lib;dxguid.lib;winmm.lib;comctl32.lib;version.lib;msacm32.lib;dsound.lib;dinput8.lib;d3d9.lib;d3dx9.lib;winio.lib;setupapi.lib;wininet.lib;dxerr.lib;shlwapi.lib;zlibstat.lib;libpng15.lib;lglcd.lib;wpcap.lib;packet.lib;openal32.lib;portaudio_x86.lib;vfw32.lib;wtsapi32.lib;avrt.lib;enet.lib;prowizard.lib;lzmalib.lib;libFLAC_static.lib;Avrt.lib;hid.lib;Iphlpapi.lib;luastatic.lib;libmpeg2_ff.lib;softfloat.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories);$(SolutionDir)\..\lib\</AdditionalLibraryDirectories>
<ClCompile Include="..\..\cpuemu_13.cpp" />
<ClCompile Include="..\..\cpuemu_21.cpp" />
<ClCompile Include="..\..\cpuemu_22.cpp" />
+ <ClCompile Include="..\..\cpuemu_23.cpp" />
<ClCompile Include="..\..\cpuemu_32.cpp" />
<ClCompile Include="..\..\cpuemu_33.cpp" />
<ClCompile Include="..\..\cpummu30.cpp" />
<ClCompile Include="..\..\ethernet.cpp" />
<ClCompile Include="..\..\events.cpp" />
+ <ClCompile Include="..\..\flashrom.cpp" />
<ClCompile Include="..\..\gfxboard.cpp" />
<ClCompile Include="..\..\hrtmon.rom.cpp" />
<ClCompile Include="..\..\inputrecord.cpp" />
<ClCompile Include="..\..\luascript.cpp" />
<ClCompile Include="..\..\newcpu_common.cpp" />
<ClCompile Include="..\..\qemuvga\cirrus_vga.cpp" />
+ <ClCompile Include="..\..\qemuvga\lsi53c710.cpp" />
<ClCompile Include="..\..\qemuvga\lsi53c895a.cpp" />
<ClCompile Include="..\..\qemuvga\qemuuaeglue.cpp" />
<ClCompile Include="..\..\qemuvga\vga.cpp" />
<ClCompile Include="..\statusline_win32.cpp">
<Filter>win32</Filter>
</ClCompile>
+ <ClCompile Include="..\..\cpuemu_23.cpp">
+ <Filter>common</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\flashrom.cpp">
+ <Filter>common</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\qemuvga\lsi53c710.cpp">
+ <Filter>qemu</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\resources\35floppy.ico">
- restore only single input target to default.
+- New statusline showed disk eject messages even if drive was already empty.
+- Added optional FPU emulation that uses softfloat library, another feature not for normal use.
+ Full 80-bit FP accuracy, bit-perfect results (not including trigonometric functions), supports FPU
+ arithmetic exceptions, much slower (Uses integer algorithms, host FPU is not used).
+- 270b6 "JIT MOVEM used direct mode if memory was direct capable but direct mode was disabled." was wrong
+ fix, original code probably was done to work around some JIT indirect bug.. (AmiKit crash during boot
+ if JIT is in indirect mode)
+
+
+Beta 4:
+
+- Added Blizzard 1230-IV and Blizzard 1260 board options. Do not use if you only want to run
+ WB and other programs, it is not JIT direct compatible due to memory address space aliasing.
+ Only emulates memory layout (which is Blizzard unique), matching CPU is not 100% required if you want to try
+ weird configs. Map ROM is also emulated, old map rom checkbox in ROM panel enables Blizzard hardware maprom
+ if Blizzard board is selected. Requires matching Blizzard flash ROM images. (Only difference between 1230IV
+ and 1240/1260 is slightly different boot rom, hardware ram addresses appear to be exact same)
+ Mostly useless, mainly meant to help development and testing. (Useful for aros m68k testing for me at least)
+- Added Warp Engine board emulation (It has already emulated 53C710 SCSI), autoconfig works, ROM code runs,
+ SCSI (53C710) does not work yet, not yet sure how jumpers are mapped to board address space.
+- Really fixed CD32 data track checks. (CD32 Commodore Demo Disc 2.0 MPEG tracks)
+- Disk Swapper panel drag'n'drop or file dialog multiselect mangled file names strangely.
+- Added A590 XT drive emulation. A590 emulation is now complete :)
+ WARNING: XT drives use real physical CHS geometry, don't attempt to use hardfiles formatted using other
+ controller, it won't work in real world. (Emulation includes work around hack) Largest XT
+ drive was 40M and protocol max limit is 511 cylinders, 15 heads and 63 sectors = ~235M.
+ Both SCSI and XT drive can be active at the same time in same controller.
+ Interesting fact about ROM xt.device: It uses WD33C93 Translate Address command to convert LBA to CHS
+ which means WD33C93 chip needs to be inserted and working or XT (which has nothing to with SCSI) port
+ won't work.
+- Fixed A590/A2091 SCSI emulation crash if SCSI ID was non-zero.
+- Z3 autoconfig was broken (b1).
+- Serial port data rate register (SERPER) was not saved correctly to statefile.
+- Serial port transmit interrupt and transmit related status bits are now more accurately timed in cycle-exact
+ CPU modes. (If some software really cares, probably not)
+- Inter-process serial port emulation added, when selected, automatically creates virtual null modem cable
+ between two winuae processes. Uses shared memory, no latency. (Says "Master" in serial port selection menu
+ if WinUAE instance created shared memory and "Slave" if shared memory was already created by some other instance.
+ If nothing = something failed)
+- Added support for short text messages, appears in OSD bar's unused space and windowed mode bottom bar. Currently
+ only shows disk image eject/insert and input device autoswitch information.
+ OSD messages won't appear in following configurations: native mode + DirectDraw + no filter and RTG
+ mode + DirectDraw. (In DirectDraw mode status bar is drawn directly to target surface, erasing gets annoying
+ because it should not be read. In D3D mode it is another texture, hardware does the rest)
+- Added remove all button to Disk Swapper panel.
+- Game controllers can be now optionally kept active when winuae window is not active or minimized.
+
Beta 3:
- Selected chipset extra didn't match what dialog box shows (b2). This broke many configs..
--- /dev/null
+/*
+ * QEMU LSI53C895A SCSI Host Bus Adapter emulation
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL.
+ */
+
+/* Note:
+ * LSI53C810 emulation is incorrect, in the sense that it supports
+ * features added in later evolutions. This should not be a problem,
+ * as well-behaved operating systems will not try to use them.
+ */
+
+/* Hacked to support LSI53C710 for UAE by Toni Wilen */
+
+#include <assert.h>
+
+#include "qemuuaeglue.h"
+#include "queue.h"
+
+//#include "hw/hw.h"
+//#include "hw/pci/pci.h"
+#include "scsi/scsi.h"
+//#include "sysemu/dma.h"
+
+//#define DEBUG_LSI
+//#define DEBUG_LSI_REG
+
+#ifdef DEBUG_LSI
+#define DPRINTF(fmt, ...) \
+do { write_log("lsi_scsi: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { write_log("lsi_scsi: error: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { write_log("lsi_scsi: error: " fmt , ## __VA_ARGS__); assert(false);} while (0)
+#endif
+
+#define LSI_MAX_DEVS 7
+
+#define LSI_SCNTL0_TRG 0x01
+#define LSI_SCNTL0_AAP 0x02
+#define LSI_SCNTL0_EPG 0x08
+#define LSI_SCNTL0_EPC 0x08
+#define LSI_SCNTL0_WATN 0x10,
+#define LSI_SCNTL0_START 0x20
+
+#define LSI_SCNTL1_RCV 0x01
+#define LSI_SCNTL1_SND 0x02
+#define LSI_SCNTL1_AESP 0x04
+#define LSI_SCNTL1_RST 0x08
+#define LSI_SCNTL1_CON 0x10
+#define LSI_SCNTL1_ESR 0x20
+#define LSI_SCNTL1_ADB 0x40
+#define LSI_SCNTL1_EXC 0x80
+
+#define LSI_SCNTL2_WSR 0x01
+#define LSI_SCNTL2_VUE0 0x02
+#define LSI_SCNTL2_VUE1 0x04
+#define LSI_SCNTL2_WSS 0x08
+#define LSI_SCNTL2_SLPHBEN 0x10
+#define LSI_SCNTL2_SLPMD 0x20
+#define LSI_SCNTL2_CHM 0x40
+#define LSI_SCNTL2_SDU 0x80
+
+#define LSI_ISTAT_DIP 0x01
+#define LSI_ISTAT_SIP 0x02
+//#define LSI_ISTAT0_INTF 0x04
+#define LSI_ISTAT_CON 0x08
+//#define LSI_ISTAT0_SEM 0x10
+#define LSI_ISTAT_SIGP 0x20
+#define LSI_ISTAT_RST 0x40
+#define LSI_ISTAT_ABRT 0x80
+
+#define LSI_SSTAT1_WOA 0x04
+
+#define LSI_SSTAT0_PAR 0x01
+#define LSI_SSTAT0_RST 0x02
+#define LSI_SSTAT0_UDC 0x04
+#define LSI_SSTAT0_SGE 0x08
+#define LSI_SSTAT0_SEL 0x10
+#define LSI_SSTAT0_STO 0x20
+#define LSI_SSTAT0_FCMP 0x40
+#define LSI_SSTAT0_MA 0x80
+
+//#define LSI_SIST0_PAR 0x01
+//#define LSI_SIST0_RST 0x02
+//#define LSI_SIST0_UDC 0x04
+//#define LSI_SIST0_SGE 0x08
+//#define LSI_SIST0_RSL 0x10
+//#define LSI_SIST0_SEL 0x20
+//#define LSI_SIST0_CMP 0x40
+//#define LSI_SIST0_MA 0x80
+
+//#define LSI_SIST1_HTH 0x01
+//#define LSI_SIST1_GEN 0x02
+//#define LSI_SIST1_STO 0x04
+//#define LSI_SIST1_SBMC 0x10
+
+#define LSI_SOCL_IO 0x01
+#define LSI_SOCL_CD 0x02
+#define LSI_SOCL_MSG 0x04
+#define LSI_SOCL_ATN 0x08
+#define LSI_SOCL_SEL 0x10
+#define LSI_SOCL_BSY 0x20
+#define LSI_SOCL_ACK 0x40
+#define LSI_SOCL_REQ 0x80
+
+#define LSI_DSTAT_IID 0x01
+#define LSI_DSTAT_SIR 0x04
+#define LSI_DSTAT_SSI 0x08
+#define LSI_DSTAT_ABRT 0x10
+#define LSI_DSTAT_BF 0x20
+#define LSI_DSTAT_MDPE 0x40
+#define LSI_DSTAT_DFE 0x80
+
+#define LSI_DCNTL_COM 0x01
+#define LSI_DCNTL_IRQD 0x02
+#define LSI_DCNTL_STD 0x04
+#define LSI_DCNTL_IRQM 0x08
+#define LSI_DCNTL_SSM 0x10
+#define LSI_DCNTL_PFEN 0x20
+#define LSI_DCNTL_PFF 0x40
+#define LSI_DCNTL_CLSE 0x80
+
+#define LSI_DMODE_MAN 0x01
+#define LSI_DMODE_UO 0x02
+#define LSI_DMODE_FAM 0x04
+#define LSI_DMODE_PD 0x08
+
+#define LSI_CTEST2_DACK 0x01
+#define LSI_CTEST2_DREQ 0x02
+#define LSI_CTEST2_TEOP 0x04
+#define LSI_CTEST2_PCICIE 0x08
+#define LSI_CTEST2_CM 0x10
+#define LSI_CTEST2_CIO 0x20
+#define LSI_CTEST2_SIGP 0x40
+#define LSI_CTEST2_DDIR 0x80
+
+#define LSI_CTEST5_BL2 0x04
+#define LSI_CTEST5_DDIR 0x08
+#define LSI_CTEST5_MASR 0x10
+#define LSI_CTEST5_DFSN 0x20
+#define LSI_CTEST5_BBCK 0x40
+#define LSI_CTEST5_ADCK 0x80
+
+#define LSI_CCNTL0_DILS 0x01
+#define LSI_CCNTL0_DISFC 0x10
+#define LSI_CCNTL0_ENNDJ 0x20
+#define LSI_CCNTL0_PMJCTL 0x40
+#define LSI_CCNTL0_ENPMJ 0x80
+
+#define LSI_CCNTL1_EN64DBMV 0x01
+#define LSI_CCNTL1_EN64TIBMV 0x02
+#define LSI_CCNTL1_64TIMOD 0x04
+#define LSI_CCNTL1_DDAC 0x08
+#define LSI_CCNTL1_ZMOD 0x80
+
+#define LSI_SBCL_IO 0x01
+#define LSI_SBCL_CD 0x02
+#define LSI_SBCL_MSG 0x04
+#define LSI_SBCL_ATN 0x08
+#define LSI_SBCL_SEL 0x10
+#define LSI_SBCL_BSY 0x20
+#define LSI_SBCL_ACK 0x40
+#define LSI_SBCL_REQ 0x80
+
+/* Enable Response to Reselection */
+#define LSI_SCID_RRE 0x60
+
+#define PHASE_DO 0
+#define PHASE_DI 1
+#define PHASE_CMD 2
+#define PHASE_ST 3
+#define PHASE_MO 6
+#define PHASE_MI 7
+#define PHASE_MASK 7
+
+/* Maximum length of MSG IN data. */
+#define LSI_MAX_MSGIN_LEN 8
+
+/* Flag set if this is a tagged command. */
+#define LSI_TAG_VALID (1 << 16)
+
+typedef struct lsi_request {
+ SCSIRequest *req;
+ uint32_t tag;
+ uint32_t dma_len;
+ uint8_t *dma_buf;
+ uint32_t pending;
+ int out;
+ QTAILQ_ENTRY(lsi_request) next;
+} lsi_request;
+
+typedef struct {
+ /*< private >*/
+ //PCIDevice parent_obj;
+ /*< public >*/
+
+ //MemoryRegion mmio_io;
+ //MemoryRegion ram_io;
+ //MemoryRegion io_io;
+
+ int carry; /* ??? Should this be an a visible register somewhere? */
+ int status;
+ /* Action to take at the end of a MSG IN phase.
+ 0 = COMMAND, 1 = disconnect, 2 = DATA OUT, 3 = DATA IN. */
+ int msg_action;
+ int msg_len;
+ uint8_t msg[LSI_MAX_MSGIN_LEN];
+ /* 0 if SCRIPTS are running or stopped.
+ * 1 if a Wait Reselect instruction has been issued.
+ * 2 if processing DMA from lsi_execute_script.
+ * 3 if a DMA operation is in progress. */
+ int waiting;
+ SCSIBus bus;
+ int current_lun;
+ /* The tag is a combination of the device ID and the SCSI tag. */
+ uint32_t select_tag;
+ int command_complete;
+ QTAILQ_HEAD(, lsi_request) queue;
+ lsi_request *current;
+
+ uint32_t dsa;
+ uint32_t temp;
+ uint32_t dnad;
+ uint32_t dbc;
+ uint8_t istat;
+ uint8_t dcmd;
+ uint8_t dstat;
+ uint8_t dien;
+// uint8_t sist0;
+// uint8_t sist1;
+ uint8_t sien0;
+ uint8_t ctest2;
+ uint8_t ctest3;
+ uint8_t ctest4;
+ uint8_t ctest5;
+ uint32_t dsp;
+ uint32_t dsps;
+ uint8_t dmode;
+ uint8_t dcntl;
+ uint8_t scntl0;
+ uint8_t scntl1;
+ uint8_t sstat0;
+ uint8_t sstat1;
+ uint8_t scid;
+ uint8_t sxfer;
+ uint8_t socl;
+ uint8_t sdid;
+ uint8_t sfbr;
+ uint8_t sidl;
+ uint32_t sbc;
+ uint32_t scratch;
+ uint8_t sbr;
+
+ uint8_t ctest0;
+ uint8_t ctest1;
+ uint8_t ctest6;
+ uint8_t ctest7;
+ uint8_t ctest8;
+ uint8_t lcrc;
+ uint8_t sstat2;
+ uint8_t dwt;
+ uint8_t sbcl;
+ uint8_t script_active;
+} LSIState;
+
+//#define TYPE_LSI53C810 "lsi53c810"
+//#define TYPE_LSI53C895A "lsi53c895a"
+
+#define LSI53C895A(obj) (LSIState*)obj->lsistate
+ //((LSIState*)(OBJECT_CHECK(LSIState, (obj), TYPE_LSI53C895A)))
+
+static inline int lsi_irq_on_rsl(LSIState *s)
+{
+ return 0; //return (s->sien0 & LSI_SIST0_RSL) && (s->scid & LSI_SCID_RRE);
+}
+
+static void lsi_soft_reset(LSIState *s)
+{
+ DPRINTF("Reset\n");
+ s->carry = 0;
+ memset (s, 0, sizeof LSIState);
+
+ s->msg_action = 0;
+ s->msg_len = 0;
+ s->waiting = 0;
+ s->dsa = 0;
+ s->dnad = 0;
+ s->dbc = 0;
+ s->temp = 0;
+ s->scratch = 0;
+ s->istat = 0;
+ s->dcmd = 0x40;
+ s->dstat = LSI_DSTAT_DFE;
+ s->dien = 0;
+// s->sist0 = 0;
+// s->sist1 = 0;
+ s->sien0 = 0;
+// s->sien1 = 0;
+ s->ctest2 = LSI_CTEST2_DACK;
+ s->ctest3 = 0;
+ s->ctest4 = 0;
+ s->ctest5 = 0;
+ s->dsp = 0;
+ s->dsps = 0;
+ s->dmode = 0;
+ s->dcntl = 0;
+ s->scntl0 = 0xc0;
+ s->scntl1 = 0;
+ s->sstat0 = 0;
+ s->sstat1 = 0;
+ s->sstat2 = 0;
+ s->scid = 0x80;
+ s->sxfer = 0;
+ s->socl = 0;
+ s->sdid = 0;
+ s->sidl = 0;
+ s->sbc = 0;
+ s->sbr = 0;
+ assert(QTAILQ_EMPTY(&s->queue));
+ assert(!s->current);
+}
+
+#if 0
+static int lsi_dma_40bit(LSIState *s)
+{
+ if ((s->ccntl1 & LSI_CCNTL1_40BIT) == LSI_CCNTL1_40BIT)
+ return 1;
+ return 0;
+}
+
+static int lsi_dma_ti64bit(LSIState *s)
+{
+ if ((s->ccntl1 & LSI_CCNTL1_EN64TIBMV) == LSI_CCNTL1_EN64TIBMV)
+ return 1;
+ return 0;
+}
+
+static int lsi_dma_64bit(LSIState *s)
+{
+ if ((s->ccntl1 & LSI_CCNTL1_EN64DBMV) == LSI_CCNTL1_EN64DBMV)
+ return 1;
+ return 0;
+}
+#endif
+
+static uint8_t lsi_reg_readb(LSIState *s, int offset);
+static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
+static void lsi_execute_script(LSIState *s);
+static void lsi_reselect(LSIState *s, lsi_request *p);
+
+static inline uint32_t read_dword(LSIState *s, uint32_t addr)
+{
+ uint32_t buf;
+
+ pci710_dma_read(PCI_DEVICE(s), addr, &buf, 4);
+ return cpu_to_le32(buf);
+}
+
+static void lsi_stop_script(LSIState *s)
+{
+ s->script_active = 0;
+}
+
+static void lsi_update_irq(LSIState *s)
+{
+ PCIDevice *d = PCI_DEVICE(s);
+ int level;
+ static int last_level;
+ lsi_request *p;
+
+ /* It's unclear whether the DIP/SIP bits should be cleared when the
+ Interrupt Status Registers are cleared or when istat0 is read.
+ We currently do the formwer, which seems to work. */
+ level = 0;
+ if (s->dstat) {
+ if (s->dstat & s->dien)
+ level = 1;
+ s->istat |= LSI_ISTAT_DIP;
+ } else {
+ s->istat &= ~LSI_ISTAT_DIP;
+ }
+
+ if (s->sstat0) {
+ if ((s->sstat0 & s->sien0))
+ level = 1;
+ s->istat |= LSI_ISTAT_SIP;
+ } else {
+ s->istat &= ~LSI_ISTAT_SIP;
+ }
+
+ if (level != last_level) {
+ DPRINTF("Update IRQ level %d dstat %02x sist %02x%02x\n",
+ level, s->dstat, s->sstat0, s->sstat1);
+ last_level = level;
+ }
+ pci710_set_irq(d, level);
+
+ if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) {
+ DPRINTF("Handled IRQs & disconnected, looking for pending "
+ "processes\n");
+ QTAILQ_FOREACH(p, &s->queue, next) {
+ if (p->pending) {
+ lsi_reselect(s, p);
+ break;
+ }
+ }
+ }
+}
+
+/* Stop SCRIPTS execution and raise a SCSI interrupt. */
+static void lsi_script_scsi_interrupt(LSIState *s, int stat0)
+{
+ uint32_t mask0;
+ //uint32_t mask1;
+
+ DPRINTF("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n",
+ stat0, s->sstat0);
+ s->sstat0 |= stat0;
+ //s->sist1 |= stat1;
+ /* Stop processor on fatal or unmasked interrupt. As a special hack
+ we don't stop processing when raising STO. Instead continue
+ execution and stop at the next insn that accesses the SCSI bus. */
+ mask0 = s->sien0 | ~(LSI_SSTAT0_FCMP | LSI_SSTAT0_SEL); // | LSI_SIST1_RSL);
+ //mask1 = s->sien1 | ~(LSI_SIST1_GEN | LSI_SIST1_HTH);
+ //mask1 &= ~LSI_SIST1_STO;
+ if (s->sstat0 & mask0) { // || s->sist1 & mask1) {
+ lsi_stop_script(s);
+ }
+ lsi_update_irq(s);
+}
+
+/* Stop SCRIPTS execution and raise a DMA interrupt. */
+static void lsi_script_dma_interrupt(LSIState *s, int stat)
+{
+ DPRINTF("DMA Interrupt 0x%x prev 0x%x\n", stat, s->dstat);
+ s->dstat |= stat;
+ lsi_update_irq(s);
+ lsi_stop_script(s);
+}
+
+static inline void lsi_set_phase(LSIState *s, int phase)
+{
+ s->sstat2 = (s->sstat2 & ~PHASE_MASK) | phase;
+ s->ctest0 &= ~1;
+ if (phase == PHASE_DI)
+ s->ctest0 |= 1;
+ s->sbcl &= ~LSI_SBCL_REQ;
+}
+
+static void lsi_bad_phase(LSIState *s, int out, int new_phase)
+{
+ /* Trigger a phase mismatch. */
+ DPRINTF("Phase mismatch interrupt\n");
+ lsi_script_scsi_interrupt(s, LSI_SSTAT0_MA);
+ lsi_stop_script(s);
+ lsi_set_phase(s, new_phase);
+ s->sbcl |= LSI_SBCL_REQ;
+}
+
+
+/* Resume SCRIPTS execution after a DMA operation. */
+static void lsi_resume_script(LSIState *s)
+{
+ if (s->waiting != 2) {
+ s->waiting = 0;
+ lsi_execute_script(s);
+ } else {
+ s->waiting = 0;
+ }
+}
+
+static void lsi_disconnect(LSIState *s)
+{
+ s->scntl1 &= ~LSI_SCNTL1_CON;
+ s->sstat2 &= ~PHASE_MASK;
+}
+
+static void lsi_bad_selection(LSIState *s, uint32_t id)
+{
+ DPRINTF("Selected absent target %d\n", id);
+ lsi_script_scsi_interrupt(s, LSI_SSTAT0_STO);
+ lsi_disconnect(s);
+}
+
+/* Initiate a SCSI layer data transfer. */
+static void lsi_do_dma(LSIState *s, int out)
+{
+ PCIDevice *pci_dev;
+ uint32_t count;
+ dma_addr_t addr;
+ SCSIDevice *dev;
+
+ assert(s->current);
+ if (!s->current->dma_len) {
+ /* Wait until data is available. */
+ DPRINTF("DMA no data available\n");
+ return;
+ }
+
+ pci_dev = PCI_DEVICE(s);
+ dev = s->current->req->dev;
+ assert(dev);
+
+ count = s->dbc;
+ if (count > s->current->dma_len)
+ count = s->current->dma_len;
+
+ addr = s->dnad;
+#if 0
+ /* both 40 and Table Indirect 64-bit DMAs store upper bits in dnad64 */
+ if (lsi_dma_40bit(s) || lsi_dma_ti64bit(s))
+ addr |= ((uint64_t)s->dnad64 << 32);
+ else if (s->dbms)
+ addr |= ((uint64_t)s->dbms << 32);
+ else if (s->sbms)
+ addr |= ((uint64_t)s->sbms << 32);
+#endif
+
+ DPRINTF("DMA addr=0x" DMA_ADDR_FMT " len=%d\n", addr, count);
+ s->dnad += count;
+ s->dbc -= count;
+ if (s->current->dma_buf == NULL) {
+ s->current->dma_buf = scsi710_req_get_buf(s->current->req);
+ }
+ /* ??? Set SFBR to first data byte. */
+ if (out) {
+ pci710_dma_read(pci_dev, addr, s->current->dma_buf, count);
+ } else {
+ pci710_dma_write(pci_dev, addr, s->current->dma_buf, count);
+ }
+ s->current->dma_len -= count;
+ if (s->current->dma_len == 0) {
+ s->current->dma_buf = NULL;
+ scsi710_req_continue(s->current->req);
+ } else {
+ s->current->dma_buf += count;
+ lsi_resume_script(s);
+ }
+}
+
+
+/* Add a command to the queue. */
+static void lsi_queue_command(LSIState *s)
+{
+ lsi_request *p = s->current;
+
+ DPRINTF("Queueing tag=0x%x\n", p->tag);
+ assert(s->current != NULL);
+ assert(s->current->dma_len == 0);
+ QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
+ s->current = NULL;
+
+ p->pending = 0;
+ p->out = (s->sstat2 & PHASE_MASK) == PHASE_DO;
+}
+
+/* Queue a byte for a MSG IN phase. */
+static void lsi_add_msg_byte(LSIState *s, uint8_t data)
+{
+ if (s->msg_len >= LSI_MAX_MSGIN_LEN) {
+ BADF("MSG IN data too long\n");
+ } else {
+ DPRINTF("MSG IN 0x%02x\n", data);
+ s->msg[s->msg_len++] = data;
+ }
+}
+
+/* Perform reselection to continue a command. */
+static void lsi_reselect(LSIState *s, lsi_request *p)
+{
+ int id;
+
+ assert(s->current == NULL);
+ QTAILQ_REMOVE(&s->queue, p, next);
+ s->current = p;
+
+ id = (p->tag >> 8) & 0xf;
+ /* LSI53C700 Family Compatibility, see LSI53C895A 4-73 */
+ if (!(s->dcntl & LSI_DCNTL_COM)) {
+ s->sfbr = 1 << (id & 0x7);
+ }
+ s->lcrc = 0;
+ DPRINTF("Reselected target %d\n", id);
+ s->scntl1 |= LSI_SCNTL1_CON;
+ lsi_set_phase(s, PHASE_MI);
+ s->msg_action = p->out ? 2 : 3;
+ s->current->dma_len = p->pending;
+ lsi_add_msg_byte(s, 0x80);
+ if (s->current->tag & LSI_TAG_VALID) {
+ lsi_add_msg_byte(s, 0x20);
+ lsi_add_msg_byte(s, p->tag & 0xff);
+ }
+
+ if (lsi_irq_on_rsl(s)) {
+ lsi_script_scsi_interrupt(s, LSI_SSTAT0_SEL);
+ }
+}
+
+static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t tag)
+{
+ lsi_request *p;
+
+ QTAILQ_FOREACH(p, &s->queue, next) {
+ if (p->tag == tag) {
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+static void lsi_request_free(LSIState *s, lsi_request *p)
+{
+ if (p == s->current) {
+ s->current = NULL;
+ } else {
+ QTAILQ_REMOVE(&s->queue, p, next);
+ }
+ g_free(p);
+}
+
+void lsi_request_cancelled(SCSIRequest *req)
+{
+ LSIState *s = LSI53C895A(req->bus->qbus.parent);
+ lsi_request *p = (lsi_request*)req->hba_private;
+
+ req->hba_private = NULL;
+ lsi_request_free(s, p);
+ scsi710_req_unref(req);
+}
+
+/* Record that data is available for a queued command. Returns zero if
+ the device was reselected, nonzero if the IO is deferred. */
+static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
+{
+ lsi_request *p = (lsi_request*)req->hba_private;
+
+ if (p->pending) {
+ BADF("Multiple IO pending for request %p\n", p);
+ }
+ p->pending = len;
+ /* Reselect if waiting for it, or if reselection triggers an IRQ
+ and the bus is free.
+ Since no interrupt stacking is implemented in the emulation, it
+ is also required that there are no pending interrupts waiting
+ for service from the device driver. */
+ if (s->waiting == 1 ||
+ (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) &&
+ !(s->istat & (LSI_ISTAT_SIP | LSI_ISTAT_DIP)))) {
+ /* Reselect device. */
+ lsi_reselect(s, p);
+ return 0;
+ } else {
+ DPRINTF("Queueing IO tag=0x%x\n", p->tag);
+ p->pending = len;
+ return 1;
+ }
+}
+
+ /* Callback to indicate that the SCSI layer has completed a command. */
+void lsi710_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
+{
+ LSIState *s = LSI53C895A(req->bus->qbus.parent);
+ int out;
+
+ out = (s->sstat2 & PHASE_MASK) == PHASE_DO;
+ DPRINTF("Command complete status=%d\n", (int)status);
+ s->lcrc = 0;
+ s->status = status;
+ s->command_complete = 2;
+ if (s->waiting && s->dbc != 0) {
+ /* Raise phase mismatch for short transfers. */
+ lsi_bad_phase(s, out, PHASE_ST);
+ } else {
+ lsi_set_phase(s, PHASE_ST);
+ }
+
+ if (req->hba_private == s->current) {
+ req->hba_private = NULL;
+ lsi_request_free(s, s->current);
+ scsi710_req_unref(req);
+ }
+ lsi_resume_script(s);
+}
+
+ /* Callback to indicate that the SCSI layer has completed a transfer. */
+void lsi710_transfer_data(SCSIRequest *req, uint32_t len)
+{
+ LSIState *s = LSI53C895A(req->bus->qbus.parent);
+ int out;
+
+ assert(req->hba_private);
+ if (s->waiting == 1 || req->hba_private != s->current ||
+ (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
+ if (lsi_queue_req(s, req, len)) {
+ return;
+ }
+ }
+
+ out = (s->sstat2 & PHASE_MASK) == PHASE_DO;
+
+ /* host adapter (re)connected */
+ DPRINTF("Data ready tag=0x%x len=%d\n", req->tag, len);
+ s->current->dma_len = len;
+ s->command_complete = 1;
+ if (s->waiting) {
+ if (s->waiting == 1 || s->dbc == 0) {
+ lsi_resume_script(s);
+ } else {
+ lsi_do_dma(s, out);
+ }
+ }
+}
+
+static int idbitstonum(int id)
+{
+ int num = 0;
+ while (id > 1) {
+ num++;
+ id >>= 1;
+ }
+ if (num > 7)
+ num = -1;
+ return num;
+}
+
+static void lsi_do_command(LSIState *s)
+{
+ SCSIDevice *dev;
+ uint8_t buf[16];
+ uint32_t id;
+ int n;
+
+ DPRINTF("Send command len=%d\n", s->dbc);
+ if (s->dbc > 16)
+ s->dbc = 16;
+ pci710_dma_read(PCI_DEVICE(s), s->dnad, buf, s->dbc);
+ DPRINTF("Send command len=%d %02x.%02x.%02x.%02x.%02x.%02x\n", s->dbc, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+ s->sfbr = buf[0];
+ s->command_complete = 0;
+
+ id = (s->select_tag >> 8) & 0xff;
+ s->lcrc = id; //1 << (id & 0x7);
+ dev = scsi710_device_find(&s->bus, 0, idbitstonum(id), s->current_lun);
+ if (!dev) {
+ lsi_bad_selection(s, id);
+ return;
+ }
+
+ assert(s->current == NULL);
+ s->current = (lsi_request*)calloc(sizeof(lsi_request), 1);
+ s->current->tag = s->select_tag;
+ s->current->req = scsi710_req_new(dev, s->current->tag, s->current_lun, buf, s->dbc, s->current);
+
+ n = scsi710_req_enqueue(s->current->req);
+ if (n) {
+ if (n > 0) {
+ lsi_set_phase(s, PHASE_DI);
+ } else if (n < 0) {
+ lsi_set_phase(s, PHASE_DO);
+ }
+ scsi710_req_continue(s->current->req);
+ }
+ if (!s->command_complete) {
+ if (n) {
+ /* Command did not complete immediately so disconnect. */
+ lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */
+ lsi_add_msg_byte(s, 4); /* DISCONNECT */
+ /* wait data */
+ lsi_set_phase(s, PHASE_MI);
+ s->msg_action = 1;
+ lsi_queue_command(s);
+ } else {
+ /* wait command complete */
+ lsi_set_phase(s, PHASE_DI);
+ }
+ }
+}
+
+static void lsi_do_status(LSIState *s)
+{
+ uint8_t status;
+ DPRINTF("Get status len=%d status=%d\n", s->dbc, s->status);
+ if (s->dbc != 1)
+ BADF("Bad Status move\n");
+ s->dbc = 1;
+ status = s->status;
+ s->sfbr = status;
+ pci710_dma_write(PCI_DEVICE(s), s->dnad, &status, 1);
+ lsi_set_phase(s, PHASE_MI);
+ s->msg_action = 1;
+ lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */
+}
+
+static void lsi_do_msgin(LSIState *s)
+{
+ int len;
+ DPRINTF("Message in len=%d/%d\n", s->dbc, s->msg_len);
+ s->sfbr = s->msg[0];
+ len = s->msg_len;
+ if (len > s->dbc)
+ len = s->dbc;
+ pci710_dma_write(PCI_DEVICE(s), s->dnad, s->msg, len);
+ /* Linux drivers rely on the last byte being in the SIDL. */
+ s->sidl = s->msg[len - 1];
+ s->msg_len -= len;
+ if (s->msg_len) {
+ memmove(s->msg, s->msg + len, s->msg_len);
+ } else {
+ /* ??? Check if ATN (not yet implemented) is asserted and maybe
+ switch to PHASE_MO. */
+ switch (s->msg_action) {
+ case 0:
+ lsi_set_phase(s, PHASE_CMD);
+ break;
+ case 1:
+ lsi_disconnect(s);
+ break;
+ case 2:
+ lsi_set_phase(s, PHASE_DO);
+ break;
+ case 3:
+ lsi_set_phase(s, PHASE_DI);
+ break;
+ default:
+ abort();
+ }
+ }
+}
+
+/* Read the next byte during a MSGOUT phase. */
+static uint8_t lsi_get_msgbyte(LSIState *s)
+{
+ uint8_t data;
+ pci710_dma_read(PCI_DEVICE(s), s->dnad, &data, 1);
+ s->dnad++;
+ s->dbc--;
+ return data;
+}
+
+/* Skip the next n bytes during a MSGOUT phase. */
+static void lsi_skip_msgbytes(LSIState *s, unsigned int n)
+{
+ s->dnad += n;
+ s->dbc -= n;
+}
+
+static void lsi_do_msgout(LSIState *s)
+{
+ uint8_t msg;
+ int len;
+ uint32_t current_tag;
+ lsi_request *current_req, *p, *p_next;
+
+ if (s->current) {
+ current_tag = s->current->tag;
+ current_req = s->current;
+ } else {
+ current_tag = s->select_tag;
+ current_req = lsi_find_by_tag(s, current_tag);
+ }
+
+ DPRINTF("MSG out len=%d\n", s->dbc);
+ while (s->dbc) {
+ msg = lsi_get_msgbyte(s);
+ s->sfbr = msg;
+
+ switch (msg) {
+ case 0x04:
+ DPRINTF("MSG: Disconnect\n");
+ lsi_disconnect(s);
+ break;
+ case 0x08:
+ DPRINTF("MSG: No Operation\n");
+ lsi_set_phase(s, PHASE_CMD);
+ break;
+ case 0x01:
+ len = lsi_get_msgbyte(s);
+ msg = lsi_get_msgbyte(s);
+ (void)len; /* avoid a warning about unused variable*/
+ DPRINTF("Extended message 0x%x (len %d)\n", msg, len);
+ switch (msg) {
+ case 1:
+ DPRINTF("SDTR (ignored)\n");
+ lsi_skip_msgbytes(s, 2);
+ break;
+ case 3:
+ DPRINTF("WDTR (ignored)\n");
+ lsi_skip_msgbytes(s, 1);
+ break;
+ default:
+ goto bad;
+ }
+ break;
+ case 0x20: /* SIMPLE queue */
+ s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
+ DPRINTF("SIMPLE queue tag=0x%x\n", s->select_tag & 0xff);
+ break;
+ case 0x21: /* HEAD of queue */
+ BADF("HEAD queue not implemented\n");
+ s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
+ break;
+ case 0x22: /* ORDERED queue */
+ BADF("ORDERED queue not implemented\n");
+ s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
+ break;
+ case 0x0d:
+ /* The ABORT TAG message clears the current I/O process only. */
+ DPRINTF("MSG: ABORT TAG tag=0x%x\n", current_tag);
+ if (current_req) {
+ scsi710_req_cancel(current_req->req);
+ }
+ lsi_disconnect(s);
+ break;
+ case 0x06:
+ case 0x0e:
+ case 0x0c:
+ /* The ABORT message clears all I/O processes for the selecting
+ initiator on the specified logical unit of the target. */
+ if (msg == 0x06) {
+ DPRINTF("MSG: ABORT tag=0x%x\n", current_tag);
+ }
+ /* The CLEAR QUEUE message clears all I/O processes for all
+ initiators on the specified logical unit of the target. */
+ if (msg == 0x0e) {
+ DPRINTF("MSG: CLEAR QUEUE tag=0x%x\n", current_tag);
+ }
+ /* The BUS DEVICE RESET message clears all I/O processes for all
+ initiators on all logical units of the target. */
+ if (msg == 0x0c) {
+ DPRINTF("MSG: BUS DEVICE RESET tag=0x%x\n", current_tag);
+ }
+
+ /* clear the current I/O process */
+ if (s->current) {
+ scsi710_req_cancel(s->current->req);
+ }
+
+ /* As the current implemented devices scsi_disk and scsi_generic
+ only support one LUN, we don't need to keep track of LUNs.
+ Clearing I/O processes for other initiators could be possible
+ for scsi_generic by sending a SG_SCSI_RESET to the /dev/sgX
+ device, but this is currently not implemented (and seems not
+ to be really necessary). So let's simply clear all queued
+ commands for the current device: */
+ QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) {
+ if ((p->tag & 0x0000ff00) == (current_tag & 0x0000ff00)) {
+ scsi710_req_cancel(p->req);
+ }
+ }
+
+ lsi_disconnect(s);
+ break;
+ default:
+ if ((msg & 0x80) == 0) {
+ goto bad;
+ }
+ s->current_lun = msg & 7;
+ DPRINTF("Select LUN %d\n", s->current_lun);
+ lsi_set_phase(s, PHASE_CMD);
+ break;
+ }
+ }
+ return;
+bad:
+ BADF("Unimplemented message 0x%02x\n", msg);
+ lsi_set_phase(s, PHASE_MI);
+ lsi_add_msg_byte(s, 7); /* MESSAGE REJECT */
+ s->msg_action = 0;
+}
+
+#define LSI_BUF_SIZE 4096
+static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
+{
+ PCIDevice *d = PCI_DEVICE(s);
+ int n;
+ uint8_t buf[LSI_BUF_SIZE];
+
+ DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count);
+ while (count) {
+ n = (count > LSI_BUF_SIZE) ? LSI_BUF_SIZE : count;
+ pci710_dma_read(d, src, buf, n);
+ pci710_dma_write(d, dest, buf, n);
+ src += n;
+ dest += n;
+ count -= n;
+ }
+}
+
+static void lsi_wait_reselect(LSIState *s)
+{
+ lsi_request *p;
+
+ DPRINTF("Wait Reselect\n");
+
+ QTAILQ_FOREACH(p, &s->queue, next) {
+ if (p->pending) {
+ lsi_reselect(s, p);
+ break;
+ }
+ }
+ if (s->current == NULL) {
+ s->waiting = 1;
+ }
+}
+
+static void lsi_execute_script(LSIState *s)
+{
+ PCIDevice *pci_dev = PCI_DEVICE(s);
+ uint32_t insn;
+ uint32_t addr;
+ int opcode;
+ int insn_processed = 0;
+
+ s->script_active = 1;
+again:
+ insn_processed++;
+ insn = read_dword(s, s->dsp);
+ if (!insn) {
+ /* If we receive an empty opcode increment the DSP by 4 bytes
+ instead of 8 and execute the next opcode at that location */
+ s->dsp += 4;
+ goto again;
+ }
+ addr = read_dword(s, s->dsp + 4);
+ DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr);
+ s->dsps = addr;
+ s->dcmd = insn >> 24;
+ s->dsp += 8;
+ switch (insn >> 30) {
+ case 0: /* Block move. */
+ if (s->sstat0 & LSI_SSTAT0_STO) {
+ DPRINTF("Delayed select timeout\n");
+ lsi_stop_script(s);
+ break;
+ }
+ s->dbc = insn & 0xffffff;
+ if (insn & (1 << 29)) {
+ /* Indirect addressing. */
+ addr = read_dword(s, addr);
+ } else if (insn & (1 << 28)) {
+ uint32_t buf[2];
+ int32_t offset;
+ /* Table indirect addressing. */
+
+ /* 32-bit Table indirect */
+ offset = sextract32(addr, 0, 24);
+ pci710_dma_read(pci_dev, s->dsa + offset, buf, 8);
+ /* byte count is stored in bits 0:23 only */
+ s->dbc = cpu_to_le32(buf[0]) & 0xffffff;
+ addr = cpu_to_le32(buf[1]);
+
+#if 0
+ /* 40-bit DMA, upper addr bits [39:32] stored in first DWORD of
+ * table, bits [31:24] */
+ if (lsi_dma_40bit(s))
+ addr_high = cpu_to_le32(buf[0]) >> 24;
+ else if (lsi_dma_ti64bit(s)) {
+ int selector = (cpu_to_le32(buf[0]) >> 24) & 0x1f;
+ switch (selector) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ /* offset index into scratch registers since
+ * TI64 mode can use registers C to R */
+ addr_high = s->scratch[2 + selector];
+ break;
+ case 0x10:
+ addr_high = s->mmrs;
+ break;
+ case 0x11:
+ addr_high = s->mmws;
+ break;
+ case 0x12:
+ addr_high = s->sfs;
+ break;
+ case 0x13:
+ addr_high = s->drs;
+ break;
+ case 0x14:
+ addr_high = s->sbms;
+ break;
+ case 0x15:
+ addr_high = s->dbms;
+ break;
+ default:
+ BADF("Illegal selector specified (0x%x > 0x15)"
+ " for 64-bit DMA block move", selector);
+ break;
+ }
+ }
+ } else if (lsi_dma_64bit(s)) {
+ /* fetch a 3rd dword if 64-bit direct move is enabled and
+ only if we're not doing table indirect or indirect addressing */
+ s->dbms = read_dword(s, s->dsp);
+ s->dsp += 4;
+ s->ia = s->dsp - 12;
+#endif
+ }
+ if ((s->sstat2 & PHASE_MASK) != ((insn >> 24) & 7)) {
+ DPRINTF("Wrong phase got %d expected %d\n",
+ s->sstat2 & PHASE_MASK, (insn >> 24) & 7);
+ lsi_script_scsi_interrupt(s, LSI_SSTAT0_MA);
+ s->sbcl |= LSI_SBCL_REQ;
+ break;
+ }
+ s->dnad = addr;
+ switch (s->sstat2 & 0x7) {
+ case PHASE_DO:
+ s->waiting = 2;
+ lsi_do_dma(s, 1);
+ if (s->waiting)
+ s->waiting = 3;
+ break;
+ case PHASE_DI:
+ s->waiting = 2;
+ lsi_do_dma(s, 0);
+ if (s->waiting)
+ s->waiting = 3;
+ break;
+ case PHASE_CMD:
+ lsi_do_command(s);
+ break;
+ case PHASE_ST:
+ lsi_do_status(s);
+ break;
+ case PHASE_MO:
+ lsi_do_msgout(s);
+ break;
+ case PHASE_MI:
+ lsi_do_msgin(s);
+ break;
+ default:
+ BADF("Unimplemented phase %d\n", s->sstat2 & PHASE_MASK);
+ }
+ s->ctest5 = (s->ctest5 & 0xfc) | ((s->dbc >> 8) & 3);
+ s->sbc = s->dbc;
+ break;
+
+ case 1: /* IO or Read/Write instruction. */
+ opcode = (insn >> 27) & 7;
+ if (opcode < 5) {
+ uint32_t id;
+
+ if (insn & (1 << 25)) {
+ id = read_dword(s, s->dsa + sextract32(insn, 0, 24));
+ } else {
+ id = insn;
+ }
+ id = (id >> 16) & 0xff;
+ if (insn & (1 << 26)) {
+ addr = s->dsp + sextract32(addr, 0, 24);
+ }
+ s->dnad = addr;
+ switch (opcode) {
+ case 0: /* Select */
+ s->sdid = id;
+ if (s->scntl1 & LSI_SCNTL1_CON) {
+ DPRINTF("Already reselected, jumping to alternative address\n");
+ s->dsp = s->dnad;
+ break;
+ }
+ s->sstat1 |= LSI_SSTAT1_WOA;
+// s->scntl1 &= ~LSI_SCNTL1_IARB;
+ if (!scsi710_device_find(&s->bus, 0, idbitstonum(id), 0)) {
+ lsi_bad_selection(s, id);
+ break;
+ }
+ DPRINTF("Selected target %d%s\n",
+ id, insn & (1 << 24) ? " ATN" : "");
+ /* ??? Linux drivers compain when this is set. Maybe
+ it only applies in low-level mode (unimplemented).
+ lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
+ s->select_tag = id << 8;
+ s->scntl1 |= LSI_SCNTL1_CON;
+ if (insn & (1 << 24)) {
+ s->socl |= LSI_SOCL_ATN;
+ }
+ lsi_set_phase(s, PHASE_MO);
+ break;
+ case 1: /* Disconnect */
+ DPRINTF("Wait Disconnect\n");
+ s->scntl1 &= ~LSI_SCNTL1_CON;
+ break;
+ case 2: /* Wait Reselect */
+ if (!lsi_irq_on_rsl(s)) {
+ lsi_wait_reselect(s);
+ }
+ break;
+ case 3: /* Set */
+ DPRINTF("Set%s%s%s%s\n",
+ insn & (1 << 3) ? " ATN" : "",
+ insn & (1 << 6) ? " ACK" : "",
+ insn & (1 << 9) ? " TM" : "",
+ insn & (1 << 10) ? " CC" : "");
+ if (insn & (1 << 3)) {
+ s->socl |= LSI_SOCL_ATN;
+ lsi_set_phase(s, PHASE_MO);
+ }
+ if (insn & (1 << 9)) {
+ BADF("Target mode not implemented\n");
+ }
+ if (insn & (1 << 10))
+ s->carry = 1;
+ break;
+ case 4: /* Clear */
+ DPRINTF("Clear%s%s%s%s\n",
+ insn & (1 << 3) ? " ATN" : "",
+ insn & (1 << 6) ? " ACK" : "",
+ insn & (1 << 9) ? " TM" : "",
+ insn & (1 << 10) ? " CC" : "");
+ if (insn & (1 << 3)) {
+ s->socl &= ~LSI_SOCL_ATN;
+ }
+ if (insn & (1 << 10))
+ s->carry = 0;
+ break;
+ }
+ } else {
+ uint8_t op0;
+ uint8_t op1;
+ uint8_t data8;
+ int reg;
+ int xoperator;
+#ifdef DEBUG_LSI
+ static const char *opcode_names[3] =
+ {"Write", "Read", "Read-Modify-Write"};
+ static const char *operator_names[8] =
+ {"MOV", "SHL", "OR", "XOR", "AND", "SHR", "ADD", "ADC"};
+#endif
+
+ reg = ((insn >> 16) & 0x7f) | (insn & 0x80);
+ data8 = (insn >> 8) & 0xff;
+ opcode = (insn >> 27) & 7;
+ xoperator = (insn >> 24) & 7;
+ DPRINTF("%s reg 0x%x %s data8=0x%02x sfbr=0x%02x%s\n",
+ opcode_names[opcode - 5], reg,
+ operator_names[xoperator], data8, s->sfbr,
+ (insn & (1 << 23)) ? " SFBR" : "");
+ op0 = op1 = 0;
+ switch (opcode) {
+ case 5: /* From SFBR */
+ op0 = s->sfbr;
+ op1 = data8;
+ break;
+ case 6: /* To SFBR */
+ if (xoperator)
+ op0 = lsi_reg_readb(s, reg);
+ op1 = data8;
+ break;
+ case 7: /* Read-modify-write */
+ if (xoperator)
+ op0 = lsi_reg_readb(s, reg);
+ if (insn & (1 << 23)) {
+ op1 = s->sfbr;
+ } else {
+ op1 = data8;
+ }
+ break;
+ }
+
+ switch (xoperator) {
+ case 0: /* move */
+ op0 = op1;
+ break;
+ case 1: /* Shift left */
+ op1 = op0 >> 7;
+ op0 = (op0 << 1) | s->carry;
+ s->carry = op1;
+ break;
+ case 2: /* OR */
+ op0 |= op1;
+ break;
+ case 3: /* XOR */
+ op0 ^= op1;
+ break;
+ case 4: /* AND */
+ op0 &= op1;
+ break;
+ case 5: /* SHR */
+ op1 = op0 & 1;
+ op0 = (op0 >> 1) | (s->carry << 7);
+ s->carry = op1;
+ break;
+ case 6: /* ADD */
+ op0 += op1;
+ s->carry = op0 < op1;
+ break;
+ case 7: /* ADC */
+ op0 += op1 + s->carry;
+ if (s->carry)
+ s->carry = op0 <= op1;
+ else
+ s->carry = op0 < op1;
+ break;
+ }
+
+ switch (opcode) {
+ case 5: /* From SFBR */
+ case 7: /* Read-modify-write */
+ lsi_reg_writeb(s, reg, op0);
+ break;
+ case 6: /* To SFBR */
+ s->sfbr = op0;
+ break;
+ }
+ }
+ break;
+
+ case 2: /* Transfer Control. */
+ {
+ int cond;
+ int jmp;
+
+ if ((insn & 0x002e0000) == 0) {
+ DPRINTF("NOP\n");
+ break;
+ }
+ if (s->sstat0 & LSI_SSTAT0_STO) {
+ DPRINTF("Delayed select timeout\n");
+ lsi_stop_script(s);
+ break;
+ }
+ cond = jmp = (insn & (1 << 19)) != 0;
+ if (cond == jmp && (insn & (1 << 21))) {
+ DPRINTF("Compare carry %d\n", s->carry == jmp);
+ cond = s->carry != 0;
+ }
+ if (cond == jmp && (insn & (1 << 17))) {
+ DPRINTF("Compare phase %d %c= %d\n",
+ (s->sstat2 & PHASE_MASK),
+ jmp ? '=' : '!',
+ ((insn >> 24) & 7));
+ cond = (s->sstat2 & PHASE_MASK) == ((insn >> 24) & 7);
+ }
+ if (cond == jmp && (insn & (1 << 18))) {
+ uint8_t mask;
+
+ mask = (~insn >> 8) & 0xff;
+ DPRINTF("Compare data 0x%x & 0x%x %c= 0x%x\n",
+ s->sfbr, mask, jmp ? '=' : '!', insn & mask);
+ cond = (s->sfbr & mask) == (insn & mask);
+ }
+ if (cond == jmp) {
+ if (insn & (1 << 23)) {
+ /* Relative address. */
+ addr = s->dsp + sextract32(addr, 0, 24);
+ }
+ switch ((insn >> 27) & 7) {
+ case 0: /* Jump */
+ DPRINTF("Jump to 0x%08x\n", addr);
+ s->dsp = addr;
+ break;
+ case 1: /* Call */
+ DPRINTF("Call 0x%08x\n", addr);
+ s->temp = s->dsp;
+ s->dsp = addr;
+ break;
+ case 2: /* Return */
+ DPRINTF("Return to 0x%08x\n", s->temp);
+ s->dsp = s->temp;
+ break;
+ case 3: /* Interrupt */
+ DPRINTF("Interrupt 0x%08x\n", s->dsps);
+ if ((insn & (1 << 20)) != 0) {
+ lsi_update_irq(s);
+ } else {
+ lsi_script_dma_interrupt(s, LSI_DSTAT_SIR);
+ }
+ break;
+ default:
+ DPRINTF("Illegal transfer control\n");
+ lsi_script_dma_interrupt(s, LSI_DSTAT_IID);
+ break;
+ }
+ } else {
+ DPRINTF("Control condition failed\n");
+ }
+ }
+ break;
+
+ case 3:
+ if ((insn & (1 << 29)) == 0) {
+ /* Memory move. */
+ uint32_t dest;
+ /* ??? The docs imply the destination address is loaded into
+ the TEMP register. However the Linux drivers rely on
+ the value being presrved. */
+ dest = read_dword(s, s->dsp);
+ s->dsp += 4;
+ lsi_memcpy(s, dest, addr, insn & 0xffffff);
+ } else {
+ uint8_t data[7];
+ int reg;
+ int n;
+ int i;
+
+ if (insn & (1 << 28)) {
+ addr = s->dsa + sextract32(addr, 0, 24);
+ }
+ n = (insn & 7);
+ reg = (insn >> 16) & 0xff;
+ if (insn & (1 << 24)) {
+ pci710_dma_read(pci_dev, addr, data, n);
+ DPRINTF("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n,
+ addr, *(int *)data);
+ for (i = 0; i < n; i++) {
+ lsi_reg_writeb(s, reg + i, data[i]);
+ }
+ } else {
+ DPRINTF("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr);
+ for (i = 0; i < n; i++) {
+ data[i] = lsi_reg_readb(s, reg + i);
+ }
+ pci710_dma_write(pci_dev, addr, data, n);
+ }
+ }
+ }
+ if (insn_processed > 10000 && !s->waiting) {
+ /* Some windows drivers make the device spin waiting for a memory
+ location to change. If we have been executed a lot of code then
+ assume this is the case and force an unexpected device disconnect.
+ This is apparently sufficient to beat the drivers into submission.
+ */
+ if (!(s->sien0 & LSI_SSTAT0_UDC))
+ fprintf(stderr, "inf. loop with UDC masked\n");
+ lsi_script_scsi_interrupt(s, LSI_SSTAT0_UDC);
+ lsi_disconnect(s);
+ } else if (s->script_active && !s->waiting) {
+ if (s->dcntl & LSI_DCNTL_SSM) {
+ lsi_script_dma_interrupt(s, LSI_DSTAT_SSI);
+ } else {
+ goto again;
+ }
+ }
+ DPRINTF("SCRIPTS execution stopped\n");
+}
+
+#if 0
+static uint8_t lsi_reg_readb(LSIState *s, int offset)
+{
+ uint8_t tmp;
+#define CASE_GET_REG24(name, addr) \
+ case addr: return s->name & 0xff; \
+ case addr + 1: return (s->name >> 8) & 0xff; \
+ case addr + 2: return (s->name >> 16) & 0xff;
+
+#define CASE_GET_REG32(name, addr) \
+ case addr: return s->name & 0xff; \
+ case addr + 1: return (s->name >> 8) & 0xff; \
+ case addr + 2: return (s->name >> 16) & 0xff; \
+ case addr + 3: return (s->name >> 24) & 0xff;
+
+#ifdef DEBUG_LSI_REG
+ DPRINTF("Read reg %x\n", offset);
+#endif
+ switch (offset) {
+ case 0x00: /* SCNTL0 */
+ return s->scntl0;
+ case 0x01: /* SCNTL1 */
+ return s->scntl1;
+ case 0x02: /* SCNTL2 */
+ return s->scntl2;
+ case 0x03: /* SCNTL3 */
+ return s->scntl3;
+ case 0x04: /* SCID */
+ return s->scid;
+ case 0x05: /* SXFER */
+ return s->sxfer;
+ case 0x06: /* SDID */
+ return s->sdid;
+ case 0x07: /* GPREG0 */
+ return 0x7f;
+ case 0x08: /* Revision ID */
+ return 0x00;
+ case 0xa: /* SSID */
+ return s->ssid;
+ case 0xb: /* SBCL */
+ /* ??? This is not correct. However it's (hopefully) only
+ used for diagnostics, so should be ok. */
+ return 0;
+ case 0xc: /* DSTAT */
+ tmp = s->dstat | LSI_DSTAT_DFE;
+ if ((s->istat0 & LSI_ISTAT0_INTF) == 0)
+ s->dstat = 0;
+ lsi_update_irq(s);
+ return tmp;
+ case 0x0d: /* SSTAT0 */
+ return s->sstat0;
+ case 0x0e: /* SSTAT1 */
+ return s->sstat1;
+ case 0x0f: /* SSTAT2 */
+ return s->scntl1 & LSI_SCNTL1_CON ? 0 : 2;
+ CASE_GET_REG32(dsa, 0x10)
+ case 0x14: /* ISTAT0 */
+ return s->istat0;
+ case 0x15: /* ISTAT1 */
+ return s->istat1;
+ case 0x16: /* MBOX0 */
+ return s->mbox0;
+ case 0x17: /* MBOX1 */
+ return s->mbox1;
+ case 0x18: /* CTEST0 */
+ return 0xff;
+ case 0x19: /* CTEST1 */
+ return 0;
+ case 0x1a: /* CTEST2 */
+ tmp = s->ctest2 | LSI_CTEST2_DACK | LSI_CTEST2_CM;
+ if (s->istat0 & LSI_ISTAT0_SIGP) {
+ s->istat0 &= ~LSI_ISTAT0_SIGP;
+ tmp |= LSI_CTEST2_SIGP;
+ }
+ return tmp;
+ case 0x1b: /* CTEST3 */
+ return s->ctest3;
+ CASE_GET_REG32(temp, 0x1c)
+ case 0x20: /* DFIFO */
+ return 0;
+ case 0x21: /* CTEST4 */
+ return s->ctest4;
+ case 0x22: /* CTEST5 */
+ return s->ctest5;
+ case 0x23: /* CTEST6 */
+ return 0;
+ CASE_GET_REG24(dbc, 0x24)
+ case 0x27: /* DCMD */
+ return s->dcmd;
+ CASE_GET_REG32(dnad, 0x28)
+ CASE_GET_REG32(dsp, 0x2c)
+ CASE_GET_REG32(dsps, 0x30)
+ CASE_GET_REG32(scratch[0], 0x34)
+ case 0x38: /* DMODE */
+ return s->dmode;
+ case 0x39: /* DIEN */
+ return s->dien;
+ case 0x3a: /* SBR */
+ return s->sbr;
+ case 0x3b: /* DCNTL */
+ return s->dcntl;
+ case 0x40: /* SIEN0 */
+ return s->sien0;
+ case 0x41: /* SIEN1 */
+ return s->sien1;
+ case 0x42: /* SIST0 */
+ tmp = s->sist0;
+ s->sist0 = 0;
+ lsi_update_irq(s);
+ return tmp;
+ case 0x43: /* SIST1 */
+ tmp = s->sist1;
+ s->sist1 = 0;
+ lsi_update_irq(s);
+ return tmp;
+ case 0x46: /* MACNTL */
+ return 0x0f;
+ case 0x47: /* GPCNTL0 */
+ return 0x0f;
+ case 0x48: /* STIME0 */
+ return s->stime0;
+ case 0x4a: /* RESPID0 */
+ return s->respid0;
+ case 0x4b: /* RESPID1 */
+ return s->respid1;
+ case 0x4d: /* STEST1 */
+ return s->stest1;
+ case 0x4e: /* STEST2 */
+ return s->stest2;
+ case 0x4f: /* STEST3 */
+ return s->stest3;
+ case 0x50: /* SIDL */
+ /* This is needed by the linux drivers. We currently only update it
+ during the MSG IN phase. */
+ return s->sidl;
+ case 0x52: /* STEST4 */
+ return 0xe0;
+ case 0x56: /* CCNTL0 */
+ return s->ccntl0;
+ case 0x57: /* CCNTL1 */
+ return s->ccntl1;
+ case 0x58: /* SBDL */
+ /* Some drivers peek at the data bus during the MSG IN phase. */
+ if ((s->sstat1 & PHASE_MASK) == PHASE_MI)
+ return s->msg[0];
+ return 0;
+ case 0x59: /* SBDL high */
+ return 0;
+ CASE_GET_REG32(mmrs, 0xa0)
+ CASE_GET_REG32(mmws, 0xa4)
+ CASE_GET_REG32(sfs, 0xa8)
+ CASE_GET_REG32(drs, 0xac)
+ CASE_GET_REG32(sbms, 0xb0)
+ CASE_GET_REG32(dbms, 0xb4)
+ CASE_GET_REG32(dnad64, 0xb8)
+ CASE_GET_REG32(pmjad1, 0xc0)
+ CASE_GET_REG32(pmjad2, 0xc4)
+ CASE_GET_REG32(rbc, 0xc8)
+ CASE_GET_REG32(ua, 0xcc)
+ CASE_GET_REG32(ia, 0xd4)
+ CASE_GET_REG32(sbc, 0xd8)
+ CASE_GET_REG32(csbc, 0xdc)
+ }
+ if (offset >= 0x5c && offset < 0xa0) {
+ int n;
+ int shift;
+ n = (offset - 0x58) >> 2;
+ shift = (offset & 3) * 8;
+ return (s->scratch[n] >> shift) & 0xff;
+ }
+ BADF("readb 0x%x\n", offset);
+#undef CASE_GET_REG24
+#undef CASE_GET_REG32
+}
+#endif
+
+static uint8_t lsi_reg_readb2(LSIState *s, int offset)
+{
+ uint8_t tmp;
+#define CASE_GET_REG24(name, addr) \
+ case addr: return s->name & 0xff; \
+ case addr + 1: return (s->name >> 8) & 0xff; \
+ case addr + 2: return (s->name >> 16) & 0xff;
+
+#define CASE_GET_REG32(name, addr) \
+ case addr: return s->name & 0xff; \
+ case addr + 1: return (s->name >> 8) & 0xff; \
+ case addr + 2: return (s->name >> 16) & 0xff; \
+ case addr + 3: return (s->name >> 24) & 0xff;
+
+ switch (offset)
+ {
+ case 0x00: /* SCNTL0 */
+ return s->scntl0;
+ case 0x01: /* SCNTL1 */
+ return s->scntl1;
+ case 0x02: /* SDID */
+ return s->sdid;
+ case 0x03: /* SIEN */
+ return s->sien0;
+ case 0x04: /* SCID */
+ return s->scid;
+ case 0x05: /* SXFER */
+ return s->sxfer;
+ case 0x09: /* SIDL */
+ /* This is needed by the linux drivers. We currently only update it
+ during the MSG IN phase. */
+ return s->sidl;
+ case 0xb: /* SBCL */
+ tmp = 0;
+ if (s->scntl1 & LSI_SCNTL1_CON) {
+ /* NetBSD 1.x checks for REQ */
+ tmp = s->sstat2 & PHASE_MASK;
+ /* if phase mismatch, REQ is also active */
+ tmp |= s->sbcl;
+ if (s->socl & LSI_SOCL_ATN)
+ tmp |= LSI_SBCL_ATN;
+ }
+ return tmp;
+ case 0xc: /* DSTAT */
+ tmp = s->dstat | LSI_DSTAT_DFE;
+ s->dstat = 0;
+// if ((s->istat0 & LSI_ISTAT0_INTF) == 0)
+// s->dstat = 0;
+ lsi_update_irq(s);
+ return tmp;
+ case 0x0d: /* SSTAT0 */
+ tmp = s->sstat0;
+ s->sstat0 = 0;
+ lsi_update_irq(s);
+ return tmp;
+ case 0x0e: /* SSTAT1 */
+ return s->sstat1;
+ case 0x0f: /* SSTAT2 */
+ return s->sstat2;
+ CASE_GET_REG32(dsa, 0x10)
+ case 0x14: /* CTEST0 */
+ return s->ctest0;
+ case 0x15: /* CTEST1 */
+ return 0xf0; // FMT and FFL are always empty
+ case 0x16: /* CTEST2 */
+ tmp = s->ctest2 | LSI_CTEST2_DACK;
+ if (s->istat & LSI_ISTAT_SIGP) {
+ s->istat &= ~LSI_ISTAT_SIGP;
+ tmp |= LSI_CTEST2_SIGP;
+ }
+ return tmp;
+ case 0x17: /* CTEST3 */
+ return s->ctest3;
+ case 0x18: /* CTEST4 */
+ return s->ctest4;
+ case 0x19: /* CTEST5 */
+ return s->ctest5;
+ case 0x1a: /* CTEST6 */
+ return s->ctest6;
+ case 0x1b: /* CTEST7 */
+ return s->ctest7;
+ CASE_GET_REG32(temp, 0x1c)
+ case 0x20: /* DFIFO */
+ return 0;
+ case 0x21: /* ISTAT */
+ return s->istat;
+ case 0x22: /* CTEST8 */
+ return (s->ctest8 | (2 << 4)) & ~0x08; // clear CLF
+ case 0x23: /* LCRC */
+ return s->lcrc;
+ CASE_GET_REG24(dbc, 0x24)
+ case 0x27: /* DCMD */
+ return s->dcmd;
+ CASE_GET_REG32(dnad, 0x28)
+ CASE_GET_REG32(dsp, 0x2c)
+ CASE_GET_REG32(dsps, 0x30)
+ CASE_GET_REG32(scratch, 0x34)
+ case 0x38: /* DMODE */
+ return s->dmode;
+ case 0x3a: /* DWT */
+ return s->dwt;
+ case 0x3b: /* DCNTL */
+ return s->dcntl;
+ }
+#undef CASE_GET_REG24
+#undef CASE_GET_REG32
+ write_log ("read unknown register %02X\n", offset);
+ return 0;
+}
+static uint8_t lsi_reg_readb(LSIState *s, int offset)
+{
+ uint8_t v = lsi_reg_readb2(s, offset);
+#ifdef DEBUG_LSI_REG
+ DPRINTF("Read reg %x: %02X\n", offset, v);
+#endif
+ return v;
+}
+
+static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
+{
+#define CASE_SET_REG24(name, addr) \
+ case addr : s->name &= 0xffffff00; s->name |= val; break; \
+ case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \
+ case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break;
+
+#define CASE_SET_REG32(name, addr) \
+ case addr : s->name &= 0xffffff00; s->name |= val; break; \
+ case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \
+ case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \
+ case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break;
+
+#ifdef DEBUG_LSI_REG
+ DPRINTF("Write reg %x = %02x\n", offset, val);
+#endif
+ switch (offset) {
+ case 0x00: /* SCNTL0 */
+ s->scntl0 = val;
+ if (val & LSI_SCNTL0_START) {
+ BADF("Start sequence not implemented\n");
+ }
+ break;
+ case 0x01: /* SCNTL1 */
+ s->scntl1 = val;
+ if (val & LSI_SCNTL1_ADB) {
+ BADF("Immediate Arbritration not implemented\n");
+ }
+ if (val & LSI_SCNTL1_RST) {
+ if (!(s->sstat0 & LSI_SSTAT0_RST)) {
+// qbus_reset_all(&s->bus.qbus);
+ s->sstat0 |= LSI_SSTAT0_RST;
+ lsi_script_scsi_interrupt(s, LSI_SSTAT0_RST);
+ }
+ } else {
+ s->sstat0 &= ~LSI_SSTAT0_RST;
+ }
+ break;
+ case 0x03: /* SIEN */
+ s->sien0 = val;
+ lsi_update_irq(s);
+ break;
+ case 0x04: /* SCID */
+ s->scid = val;
+ break;
+ case 0x05: /* SXFER */
+ s->sxfer = val;
+ break;
+ case 0x0b: /* SBCL */
+ lsi_set_phase (s, val & PHASE_MASK);
+ break;
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ /* Linux writes to these readonly registers on startup. */
+ return;
+ CASE_SET_REG32(dsa, 0x10)
+ case 0x14: /* CTEST0 */
+ s->ctest0 = (val & 0xfe) | (s->ctest0 & 1);
+ break;
+ case 0x15: /* CTEST1, read-only */
+ break;
+ case 0x16: /* CTEST2, read-only */
+ break;
+ case 0x17: /* CTEST3 */
+ s->ctest3 = val;
+ break;
+ case 0x18: /* CTEST4 */
+ s->ctest4 = val;
+ break;
+ case 0x19: /* CTEST5 */
+ s->ctest5 = val;
+ break;
+ case 0x1a: /* CTEST6 */
+ s->ctest6 = val;
+ break;
+ case 0x1b: /* CTEST7 */
+ s->ctest7 = val;
+ break;
+ CASE_SET_REG32(temp, 0x1c)
+
+ case 0x21: /* ISTAT */
+ s->istat = (s->istat & 0x0f) | (val & 0xf0);
+ if (val & LSI_ISTAT_ABRT) {
+ lsi_script_dma_interrupt(s, LSI_DSTAT_ABRT);
+ }
+ if (s->waiting == 1 && (val & LSI_ISTAT_SIGP)) {
+ DPRINTF("Woken by SIGP\n");
+ s->waiting = 0;
+ s->dsp = s->dnad;
+ lsi_execute_script(s);
+ }
+ if (val & LSI_ISTAT_RST) {
+ ;//qdev_reset_all(DEVICE(s));
+ }
+ break;
+ case 0x22: /* CTEST8 */
+ s->ctest8 = val;
+ break;
+ case 0x23: /* LCRC */
+ s->lcrc = 0;
+ break;
+
+ CASE_SET_REG24(dbc, 0x24)
+ CASE_SET_REG32(dnad, 0x28)
+ case 0x2c: /* DSP[0:7] */
+ s->dsp &= 0xffffff00;
+ s->dsp |= val;
+ break;
+ case 0x2d: /* DSP[8:15] */
+ s->dsp &= 0xffff00ff;
+ s->dsp |= val << 8;
+ break;
+ case 0x2e: /* DSP[16:23] */
+ s->dsp &= 0xff00ffff;
+ s->dsp |= val << 16;
+ break;
+ case 0x2f: /* DSP[24:31] */
+ s->dsp &= 0x00ffffff;
+ s->dsp |= val << 24;
+ if ((s->dmode & LSI_DMODE_MAN) == 0) {
+ s->waiting = 0;
+ lsi_execute_script(s);
+ }
+ break;
+ CASE_SET_REG32(scratch, 0x34)
+ case 0x38: /* DMODE */
+#if 0
+ if (val & (LSI_DMODE_SIOM | LSI_DMODE_DIOM)) {
+ BADF("IO mappings not implemented\n");
+ }
+#endif
+ s->dmode = val;
+ break;
+ case 0x39: /* DIEN */
+ s->dien = val;
+ lsi_update_irq(s);
+ break;
+ case 0x3a: /* DWT */
+ s->dwt = val;
+ break;
+ case 0x3b: /* DCNTL */
+ s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD);
+ if ((val & LSI_DCNTL_STD) && (s->dmode & LSI_DMODE_MAN) == 0)
+ lsi_execute_script(s);
+ break;
+ default:
+ write_log ("write unknown register %02X\n", offset);
+ break;
+ }
+#undef CASE_SET_REG24
+#undef CASE_SET_REG32
+}
+
+#if 0
+static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
+{
+#define CASE_SET_REG24(name, addr) \
+ case addr : s->name &= 0xffffff00; s->name |= val; break; \
+ case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \
+ case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break;
+
+#define CASE_SET_REG32(name, addr) \
+ case addr : s->name &= 0xffffff00; s->name |= val; break; \
+ case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \
+ case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \
+ case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break;
+
+#ifdef DEBUG_LSI_REG
+ DPRINTF("Write reg %x = %02x\n", offset, val);
+#endif
+ switch (offset) {
+ case 0x00: /* SCNTL0 */
+ s->scntl0 = val;
+ if (val & LSI_SCNTL0_START) {
+ BADF("Start sequence not implemented\n");
+ }
+ break;
+ case 0x01: /* SCNTL1 */
+ s->scntl1 = val & ~LSI_SCNTL1_SST;
+ if (val & LSI_SCNTL1_IARB) {
+ BADF("Immediate Arbritration not implemented\n");
+ }
+ if (val & LSI_SCNTL1_RST) {
+ if (!(s->sstat0 & LSI_SSTAT0_RST)) {
+// qbus_reset_all(&s->bus.qbus);
+ s->sstat0 |= LSI_SSTAT0_RST;
+ lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
+ }
+ } else {
+ s->sstat0 &= ~LSI_SSTAT0_RST;
+ }
+ break;
+ case 0x02: /* SCNTL2 */
+ val &= ~(LSI_SCNTL2_WSR | LSI_SCNTL2_WSS);
+ s->scntl2 = val;
+ break;
+ case 0x03: /* SCNTL3 */
+ s->scntl3 = val;
+ break;
+ case 0x04: /* SCID */
+ s->scid = val;
+ break;
+ case 0x05: /* SXFER */
+ s->sxfer = val;
+ break;
+ case 0x06: /* SDID */
+ if ((s->ssid & 0x80) && (val & 0xf) != (s->ssid & 0xf)) {
+ BADF("Destination ID does not match SSID\n");
+ }
+ s->sdid = val & 0xf;
+ break;
+ case 0x07: /* GPREG0 */
+ break;
+ case 0x08: /* SFBR */
+ /* The CPU is not allowed to write to this register. However the
+ SCRIPTS register move instructions are. */
+ s->sfbr = val;
+ break;
+ case 0x0a: case 0x0b:
+ /* Openserver writes to these readonly registers on startup */
+ return;
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ /* Linux writes to these readonly registers on startup. */
+ return;
+ CASE_SET_REG32(dsa, 0x10)
+ case 0x14: /* ISTAT0 */
+ s->istat0 = (s->istat0 & 0x0f) | (val & 0xf0);
+ if (val & LSI_ISTAT0_ABRT) {
+ lsi_script_dma_interrupt(s, LSI_DSTAT_ABRT);
+ }
+ if (val & LSI_ISTAT0_INTF) {
+ s->istat0 &= ~LSI_ISTAT0_INTF;
+ lsi_update_irq(s);
+ }
+ if (s->waiting == 1 && val & LSI_ISTAT0_SIGP) {
+ DPRINTF("Woken by SIGP\n");
+ s->waiting = 0;
+ s->dsp = s->dnad;
+ lsi_execute_script(s);
+ }
+// if (val & LSI_ISTAT0_SRST) {
+// qdev_reset_all(DEVICE(s));
+// }
+ break;
+ case 0x16: /* MBOX0 */
+ s->mbox0 = val;
+ break;
+ case 0x17: /* MBOX1 */
+ s->mbox1 = val;
+ break;
+ case 0x18: /* CTEST0 */
+ /* nothing to do */
+ break;
+ case 0x1a: /* CTEST2 */
+ s->ctest2 = val & LSI_CTEST2_PCICIE;
+ break;
+ case 0x1b: /* CTEST3 */
+ s->ctest3 = val & 0x0f;
+ break;
+ CASE_SET_REG32(temp, 0x1c)
+ case 0x21: /* CTEST4 */
+ if (val & 7) {
+ BADF("Unimplemented CTEST4-FBL 0x%x\n", val);
+ }
+ s->ctest4 = val;
+ break;
+ case 0x22: /* CTEST5 */
+ if (val & (LSI_CTEST5_ADCK | LSI_CTEST5_BBCK)) {
+ BADF("CTEST5 DMA increment not implemented\n");
+ val &= ~(LSI_CTEST5_ADCK | LSI_CTEST5_BBCK);
+ }
+ s->ctest5 = val;
+ break;
+ CASE_SET_REG24(dbc, 0x24)
+ CASE_SET_REG32(dnad, 0x28)
+ case 0x2c: /* DSP[0:7] */
+ s->dsp &= 0xffffff00;
+ s->dsp |= val;
+ break;
+ case 0x2d: /* DSP[8:15] */
+ s->dsp &= 0xffff00ff;
+ s->dsp |= val << 8;
+ break;
+ case 0x2e: /* DSP[16:23] */
+ s->dsp &= 0xff00ffff;
+ s->dsp |= val << 16;
+ break;
+ case 0x2f: /* DSP[24:31] */
+ s->dsp &= 0x00ffffff;
+ s->dsp |= val << 24;
+ if ((s->dmode & LSI_DMODE_MAN) == 0
+ && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
+ lsi_execute_script(s);
+ break;
+ CASE_SET_REG32(dsps, 0x30)
+ CASE_SET_REG32(scratch[0], 0x34)
+ case 0x38: /* DMODE */
+ if (val & (LSI_DMODE_SIOM | LSI_DMODE_DIOM)) {
+ BADF("IO mappings not implemented\n");
+ }
+ s->dmode = val;
+ break;
+ case 0x39: /* DIEN */
+ s->dien = val;
+ lsi_update_irq(s);
+ break;
+ case 0x3a: /* SBR */
+ s->sbr = val;
+ break;
+ case 0x3b: /* DCNTL */
+ s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD);
+ if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
+ lsi_execute_script(s);
+ break;
+ case 0x40: /* SIEN0 */
+ s->sien0 = val;
+ lsi_update_irq(s);
+ break;
+ case 0x41: /* SIEN1 */
+ s->sien1 = val;
+ lsi_update_irq(s);
+ break;
+ case 0x47: /* GPCNTL0 */
+ break;
+ case 0x48: /* STIME0 */
+ s->stime0 = val;
+ break;
+ case 0x49: /* STIME1 */
+ if (val & 0xf) {
+ DPRINTF("General purpose timer not implemented\n");
+ /* ??? Raising the interrupt immediately seems to be sufficient
+ to keep the FreeBSD driver happy. */
+ lsi_script_scsi_interrupt(s, 0, LSI_SIST1_GEN);
+ }
+ break;
+ case 0x4a: /* RESPID0 */
+ s->respid0 = val;
+ break;
+ case 0x4b: /* RESPID1 */
+ s->respid1 = val;
+ break;
+ case 0x4d: /* STEST1 */
+ s->stest1 = val;
+ break;
+ case 0x4e: /* STEST2 */
+ if (val & 1) {
+ BADF("Low level mode not implemented\n");
+ }
+ s->stest2 = val;
+ break;
+ case 0x4f: /* STEST3 */
+ if (val & 0x41) {
+ BADF("SCSI FIFO test mode not implemented\n");
+ }
+ s->stest3 = val;
+ break;
+ case 0x56: /* CCNTL0 */
+ s->ccntl0 = val;
+ break;
+ case 0x57: /* CCNTL1 */
+ s->ccntl1 = val;
+ break;
+ CASE_SET_REG32(mmrs, 0xa0)
+ CASE_SET_REG32(mmws, 0xa4)
+ CASE_SET_REG32(sfs, 0xa8)
+ CASE_SET_REG32(drs, 0xac)
+ CASE_SET_REG32(sbms, 0xb0)
+ CASE_SET_REG32(dbms, 0xb4)
+ CASE_SET_REG32(dnad64, 0xb8)
+ CASE_SET_REG32(pmjad1, 0xc0)
+ CASE_SET_REG32(pmjad2, 0xc4)
+ CASE_SET_REG32(rbc, 0xc8)
+ CASE_SET_REG32(ua, 0xcc)
+ CASE_SET_REG32(ia, 0xd4)
+ CASE_SET_REG32(sbc, 0xd8)
+ CASE_SET_REG32(csbc, 0xdc)
+ default:
+ if (offset >= 0x5c && offset < 0xa0) {
+ int n;
+ int shift;
+ n = (offset - 0x58) >> 2;
+ shift = (offset & 3) * 8;
+ s->scratch[n] = deposit32(s->scratch[n], shift, 8, val);
+ } else {
+ BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val);
+ }
+ }
+#undef CASE_SET_REG24
+#undef CASE_SET_REG32
+}
+#endif
+
+void lsi710_mmio_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ LSIState *s = (LSIState*)opaque;
+
+ lsi_reg_writeb(s, addr & 0xff, val);
+}
+
+uint64_t lsi710_mmio_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ LSIState *s = (LSIState*)opaque;
+
+ return lsi_reg_readb(s, addr & 0xff);
+}
+
+#if 0
+static const MemoryRegionOps lsi_mmio_ops = {
+ lsi_mmio_read,
+ lsi_mmio_write,
+ DEVICE_NATIVE_ENDIAN,
+ {
+ 1,
+ 1,
+ },
+};
+
+static void lsi_ram_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ LSIState *s = (LSIState*)opaque;
+ uint32_t newval;
+ uint32_t mask;
+ int shift;
+
+ newval = s->script_ram[addr >> 2];
+ shift = (addr & 3) * 8;
+ mask = ((uint64_t)1 << (size * 8)) - 1;
+ newval &= ~(mask << shift);
+ newval |= val << shift;
+ s->script_ram[addr >> 2] = newval;
+}
+
+static uint64_t lsi_ram_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ LSIState *s = (LSIState*)opaque;
+ uint32_t val;
+ uint32_t mask;
+
+ val = s->script_ram[addr >> 2];
+ mask = ((uint64_t)1 << (size * 8)) - 1;
+ val >>= (addr & 3) * 8;
+ return val & mask;
+}
+
+static const MemoryRegionOps lsi_ram_ops = {
+ lsi_ram_read,
+ lsi_ram_write,
+ DEVICE_NATIVE_ENDIAN,
+};
+
+static uint64_t lsi_io_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ LSIState *s = (LSIState*)opaque;
+ return lsi_reg_readb(s, addr & 0xff);
+}
+
+static void lsi_io_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ LSIState *s = (LSIState*)opaque;
+ lsi_reg_writeb(s, addr & 0xff, val);
+}
+
+static const MemoryRegionOps lsi_io_ops = {
+ lsi_io_read,
+ lsi_io_write,
+ DEVICE_NATIVE_ENDIAN,
+ {
+ 1,
+ 1,
+ },
+};
+#endif
+
+void lsi710_scsi_reset(DeviceState *dev, void *privdata)
+{
+ LSIState *s = LSI53C895A(dev);
+
+ lsi_soft_reset(s);
+ s->bus.privdata = privdata;
+}
+
+void lsi710_scsi_init(DeviceState *dev)
+{
+ dev->lsistate = calloc (sizeof(LSIState), 1);
+}
+
+#if 0
+static void lsi_pre_save(void *opaque)
+{
+ LSIState *s = opaque;
+
+ if (s->current) {
+ assert(s->current->dma_buf == NULL);
+ assert(s->current->dma_len == 0);
+ }
+ assert(QTAILQ_EMPTY(&s->queue));
+}
+
+static const VMStateDescription vmstate_lsi_scsi = {
+ .name = "lsiscsi",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .pre_save = lsi_pre_save,
+ .fields = (VMStateField []) {
+ VMSTATE_PCI_DEVICE(parent_obj, LSIState),
+
+ VMSTATE_INT32(carry, LSIState),
+ VMSTATE_INT32(status, LSIState),
+ VMSTATE_INT32(msg_action, LSIState),
+ VMSTATE_INT32(msg_len, LSIState),
+ VMSTATE_BUFFER(msg, LSIState),
+ VMSTATE_INT32(waiting, LSIState),
+
+ VMSTATE_UINT32(dsa, LSIState),
+ VMSTATE_UINT32(temp, LSIState),
+ VMSTATE_UINT32(dnad, LSIState),
+ VMSTATE_UINT32(dbc, LSIState),
+ VMSTATE_UINT8(istat0, LSIState),
+ VMSTATE_UINT8(istat1, LSIState),
+ VMSTATE_UINT8(dcmd, LSIState),
+ VMSTATE_UINT8(dstat, LSIState),
+ VMSTATE_UINT8(dien, LSIState),
+ VMSTATE_UINT8(sist0, LSIState),
+ VMSTATE_UINT8(sist1, LSIState),
+ VMSTATE_UINT8(sien0, LSIState),
+ VMSTATE_UINT8(sien1, LSIState),
+ VMSTATE_UINT8(mbox0, LSIState),
+ VMSTATE_UINT8(mbox1, LSIState),
+ VMSTATE_UINT8(dfifo, LSIState),
+ VMSTATE_UINT8(ctest2, LSIState),
+ VMSTATE_UINT8(ctest3, LSIState),
+ VMSTATE_UINT8(ctest4, LSIState),
+ VMSTATE_UINT8(ctest5, LSIState),
+ VMSTATE_UINT8(ccntl0, LSIState),
+ VMSTATE_UINT8(ccntl1, LSIState),
+ VMSTATE_UINT32(dsp, LSIState),
+ VMSTATE_UINT32(dsps, LSIState),
+ VMSTATE_UINT8(dmode, LSIState),
+ VMSTATE_UINT8(dcntl, LSIState),
+ VMSTATE_UINT8(scntl0, LSIState),
+ VMSTATE_UINT8(scntl1, LSIState),
+ VMSTATE_UINT8(scntl2, LSIState),
+ VMSTATE_UINT8(scntl3, LSIState),
+ VMSTATE_UINT8(sstat0, LSIState),
+ VMSTATE_UINT8(sstat1, LSIState),
+ VMSTATE_UINT8(scid, LSIState),
+ VMSTATE_UINT8(sxfer, LSIState),
+ VMSTATE_UINT8(socl, LSIState),
+ VMSTATE_UINT8(sdid, LSIState),
+ VMSTATE_UINT8(ssid, LSIState),
+ VMSTATE_UINT8(sfbr, LSIState),
+ VMSTATE_UINT8(stest1, LSIState),
+ VMSTATE_UINT8(stest2, LSIState),
+ VMSTATE_UINT8(stest3, LSIState),
+ VMSTATE_UINT8(sidl, LSIState),
+ VMSTATE_UINT8(stime0, LSIState),
+ VMSTATE_UINT8(respid0, LSIState),
+ VMSTATE_UINT8(respid1, LSIState),
+ VMSTATE_UINT32(mmrs, LSIState),
+ VMSTATE_UINT32(mmws, LSIState),
+ VMSTATE_UINT32(sfs, LSIState),
+ VMSTATE_UINT32(drs, LSIState),
+ VMSTATE_UINT32(sbms, LSIState),
+ VMSTATE_UINT32(dbms, LSIState),
+ VMSTATE_UINT32(dnad64, LSIState),
+ VMSTATE_UINT32(pmjad1, LSIState),
+ VMSTATE_UINT32(pmjad2, LSIState),
+ VMSTATE_UINT32(rbc, LSIState),
+ VMSTATE_UINT32(ua, LSIState),
+ VMSTATE_UINT32(ia, LSIState),
+ VMSTATE_UINT32(sbc, LSIState),
+ VMSTATE_UINT32(csbc, LSIState),
+ VMSTATE_BUFFER_UNSAFE(scratch, LSIState, 0, 18 * sizeof(uint32_t)),
+ VMSTATE_UINT8(sbr, LSIState),
+
+ VMSTATE_BUFFER_UNSAFE(script_ram, LSIState, 0, 2048 * sizeof(uint32_t)),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void lsi_scsi_uninit(PCIDevice *d)
+{
+ LSIState *s = LSI53C895A(d);
+
+ memory_region_destroy(&s->mmio_io);
+ memory_region_destroy(&s->ram_io);
+ memory_region_destroy(&s->io_io);
+}
+
+static const struct SCSIBusInfo lsi_scsi_info = {
+ .tcq = true,
+ .max_target = LSI_MAX_DEVS,
+ .max_lun = 0, /* LUN support is buggy */
+
+ .transfer_data = lsi_transfer_data,
+ .complete = lsi_command_complete,
+ .cancel = lsi_request_cancelled
+};
+
+static int lsi_scsi_init(PCIDevice *dev)
+{
+ LSIState *s = LSI53C895A(dev);
+ DeviceState *d = DEVICE(dev);
+ uint8_t *pci_conf;
+ Error *err = NULL;
+
+ pci_conf = dev->config;
+
+ /* PCI latency timer = 255 */
+ pci_conf[PCI_LATENCY_TIMER] = 0xff;
+ /* Interrupt pin A */
+ pci_conf[PCI_INTERRUPT_PIN] = 0x01;
+
+ memory_region_init_io(&s->mmio_io, OBJECT(s), &lsi_mmio_ops, s,
+ "lsi-mmio", 0x400);
+ memory_region_init_io(&s->ram_io, OBJECT(s), &lsi_ram_ops, s,
+ "lsi-ram", 0x2000);
+ memory_region_init_io(&s->io_io, OBJECT(s), &lsi_io_ops, s,
+ "lsi-io", 256);
+
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_io);
+ pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_io);
+ pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_io);
+ QTAILQ_INIT(&s->queue);
+
+ scsi_bus_new(&s->bus, sizeof(s->bus), d, &lsi_scsi_info, NULL);
+ if (!d->hotplugged) {
+ scsi_bus_legacy_handle_cmdline(&s->bus, &err);
+ if (err != NULL) {
+ error_free(err);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static void lsi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = lsi_scsi_init;
+ k->exit = lsi_scsi_uninit;
+ k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
+ k->device_id = PCI_DEVICE_ID_LSI_53C895A;
+ k->class_id = PCI_CLASS_STORAGE_SCSI;
+ k->subsystem_id = 0x1000;
+ dc->reset = lsi_scsi_reset;
+ dc->vmsd = &vmstate_lsi_scsi;
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+}
+
+static const TypeInfo lsi_info = {
+ .name = TYPE_LSI53C895A,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(LSIState),
+ .class_init = lsi_class_init,
+};
+
+static void lsi53c810_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->device_id = PCI_DEVICE_ID_LSI_53C810;
+}
+
+static TypeInfo lsi53c810_info = {
+ .name = TYPE_LSI53C810,
+ .parent = TYPE_LSI53C895A,
+ .class_init = lsi53c810_class_init,
+};
+
+static void lsi53c895a_register_types(void)
+{
+ type_register_static(&lsi_info);
+ type_register_static(&lsi53c810_info);
+}
+
+type_init(lsi53c895a_register_types)
+#endif
* as well-behaved operating systems will not try to use them.
*/
-/* Hacked to support LSI53C710 for UAE by Toni Wilen */
-
#include <assert.h>
#include "qemuuaeglue.h"
#else
#define DPRINTF(fmt, ...) do {} while(0)
#define BADF(fmt, ...) \
-do { write_log("lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
+do { write_log("lsi_scsi: error: " fmt , ## __VA_ARGS__); activate_debugger();} while (0)
#endif
#define LSI_MAX_DEVS 7
#define LSI_SCNTL0_TRG 0x01
#define LSI_SCNTL0_AAP 0x02
-#define LSI_SCNTL0_EPG 0x08
#define LSI_SCNTL0_EPC 0x08
-#define LSI_SCNTL0_WATN 0x10,
+#define LSI_SCNTL0_WATN 0x10
#define LSI_SCNTL0_START 0x20
-#define LSI_SCNTL1_RCV 0x01
-#define LSI_SCNTL1_SND 0x02
+#define LSI_SCNTL1_SST 0x01
+#define LSI_SCNTL1_IARB 0x02
#define LSI_SCNTL1_AESP 0x04
#define LSI_SCNTL1_RST 0x08
#define LSI_SCNTL1_CON 0x10
-#define LSI_SCNTL1_ESR 0x20
+#define LSI_SCNTL1_DHP 0x20
#define LSI_SCNTL1_ADB 0x40
#define LSI_SCNTL1_EXC 0x80
#define LSI_SCNTL2_CHM 0x40
#define LSI_SCNTL2_SDU 0x80
-#define LSI_ISTAT_DIP 0x01
-#define LSI_ISTAT_SIP 0x02
-//#define LSI_ISTAT0_INTF 0x04
-#define LSI_ISTAT_CON 0x08
-//#define LSI_ISTAT0_SEM 0x10
-#define LSI_ISTAT_SIGP 0x20
-#define LSI_ISTAT_RST 0x40
-#define LSI_ISTAT_ABRT 0x80
+#define LSI_ISTAT0_DIP 0x01
+#define LSI_ISTAT0_SIP 0x02
+#define LSI_ISTAT0_INTF 0x04
+#define LSI_ISTAT0_CON 0x08
+#define LSI_ISTAT0_SEM 0x10
+#define LSI_ISTAT0_SIGP 0x20
+#define LSI_ISTAT0_SRST 0x40
+#define LSI_ISTAT0_ABRT 0x80
-#define LSI_SSTAT1_WOA 0x04
+#define LSI_ISTAT1_SI 0x01
+#define LSI_ISTAT1_SRUN 0x02
+#define LSI_ISTAT1_FLSH 0x04
-#define LSI_SSTAT0_PAR 0x01
+#define LSI_SSTAT0_SDP0 0x01
#define LSI_SSTAT0_RST 0x02
-#define LSI_SSTAT0_UDC 0x04
-#define LSI_SSTAT0_SGE 0x08
-#define LSI_SSTAT0_SEL 0x10
-#define LSI_SSTAT0_STO 0x20
-#define LSI_SSTAT0_FCMP 0x40
-#define LSI_SSTAT0_MA 0x80
-
-//#define LSI_SIST0_PAR 0x01
-//#define LSI_SIST0_RST 0x02
-//#define LSI_SIST0_UDC 0x04
-//#define LSI_SIST0_SGE 0x08
-//#define LSI_SIST0_RSL 0x10
-//#define LSI_SIST0_SEL 0x20
-//#define LSI_SIST0_CMP 0x40
-//#define LSI_SIST0_MA 0x80
-
-//#define LSI_SIST1_HTH 0x01
-//#define LSI_SIST1_GEN 0x02
-//#define LSI_SIST1_STO 0x04
-//#define LSI_SIST1_SBMC 0x10
+#define LSI_SSTAT0_WOA 0x04
+#define LSI_SSTAT0_LOA 0x08
+#define LSI_SSTAT0_AIP 0x10
+#define LSI_SSTAT0_OLF 0x20
+#define LSI_SSTAT0_ORF 0x40
+#define LSI_SSTAT0_ILF 0x80
+
+#define LSI_SIST0_PAR 0x01
+#define LSI_SIST0_RST 0x02
+#define LSI_SIST0_UDC 0x04
+#define LSI_SIST0_SGE 0x08
+#define LSI_SIST0_RSL 0x10
+#define LSI_SIST0_SEL 0x20
+#define LSI_SIST0_CMP 0x40
+#define LSI_SIST0_MA 0x80
+
+#define LSI_SIST1_HTH 0x01
+#define LSI_SIST1_GEN 0x02
+#define LSI_SIST1_STO 0x04
+#define LSI_SIST1_SBMC 0x10
#define LSI_SOCL_IO 0x01
#define LSI_SOCL_CD 0x02
#define LSI_DCNTL_CLSE 0x80
#define LSI_DMODE_MAN 0x01
-#define LSI_DMODE_UO 0x02
-#define LSI_DMODE_FAM 0x04
-#define LSI_DMODE_PD 0x08
+#define LSI_DMODE_BOF 0x02
+#define LSI_DMODE_ERMP 0x04
+#define LSI_DMODE_ERL 0x08
+#define LSI_DMODE_DIOM 0x10
+#define LSI_DMODE_SIOM 0x20
#define LSI_CTEST2_DACK 0x01
#define LSI_CTEST2_DREQ 0x02
#define LSI_CCNTL1_DDAC 0x08
#define LSI_CCNTL1_ZMOD 0x80
-#define LSI_SBCL_IO 0x01
-#define LSI_SBCL_CD 0x02
-#define LSI_SBCL_MSG 0x04
-#define LSI_SBCL_ATN 0x08
-#define LSI_SBCL_SEL 0x10
-#define LSI_SBCL_BSY 0x20
-#define LSI_SBCL_ACK 0x40
-#define LSI_SBCL_REQ 0x80
-
/* Enable Response to Reselection */
#define LSI_SCID_RRE 0x60
+#define LSI_CCNTL1_40BIT (LSI_CCNTL1_EN64TIBMV|LSI_CCNTL1_64TIMOD)
+
#define PHASE_DO 0
#define PHASE_DI 1
#define PHASE_CMD 2
typedef struct {
/*< private >*/
- //PCIDevice parent_obj;
+ // PCIDevice parent_obj;
/*< public >*/
//MemoryRegion mmio_io;
uint32_t temp;
uint32_t dnad;
uint32_t dbc;
- uint8_t istat;
+ uint8_t istat0;
+ uint8_t istat1;
uint8_t dcmd;
uint8_t dstat;
uint8_t dien;
-// uint8_t sist0;
-// uint8_t sist1;
+ uint8_t sist0;
+ uint8_t sist1;
uint8_t sien0;
+ uint8_t sien1;
+ uint8_t mbox0;
+ uint8_t mbox1;
+ uint8_t dfifo;
uint8_t ctest2;
uint8_t ctest3;
uint8_t ctest4;
uint8_t ctest5;
+ uint8_t ccntl0;
+ uint8_t ccntl1;
uint32_t dsp;
uint32_t dsps;
uint8_t dmode;
uint8_t dcntl;
uint8_t scntl0;
uint8_t scntl1;
+ uint8_t scntl2;
+ uint8_t scntl3;
uint8_t sstat0;
uint8_t sstat1;
uint8_t scid;
uint8_t sxfer;
uint8_t socl;
uint8_t sdid;
+ uint8_t ssid;
uint8_t sfbr;
+ uint8_t stest1;
+ uint8_t stest2;
+ uint8_t stest3;
uint8_t sidl;
+ uint8_t stime0;
+ uint8_t respid0;
+ uint8_t respid1;
+ uint32_t mmrs;
+ uint32_t mmws;
+ uint32_t sfs;
+ uint32_t drs;
+ uint32_t sbms;
+ uint32_t dbms;
+ uint32_t dnad64;
+ uint32_t pmjad1;
+ uint32_t pmjad2;
+ uint32_t rbc;
+ uint32_t ua;
+ uint32_t ia;
uint32_t sbc;
- uint32_t scratch;
+ uint32_t csbc;
+ uint32_t scratch[18]; /* SCRATCHA-SCRATCHR */
uint8_t sbr;
- uint8_t ctest0;
- uint8_t ctest1;
- uint8_t ctest6;
- uint8_t ctest7;
- uint8_t ctest8;
- uint8_t lcrc;
- uint8_t sstat2;
- uint8_t dwt;
- uint8_t sbcl;
- uint8_t script_active;
+ /* Script ram is stored as 32-bit words in host byteorder. */
+ uint32_t script_ram[2048];
} LSIState;
-//#define TYPE_LSI53C810 "lsi53c810"
-//#define TYPE_LSI53C895A "lsi53c895a"
+#define TYPE_LSI53C810 "lsi53c810"
+#define TYPE_LSI53C895A "lsi53c895a"
#define LSI53C895A(obj) (LSIState*)obj->lsistate
- //((LSIState*)(OBJECT_CHECK(LSIState, (obj), TYPE_LSI53C895A)))
+// OBJECT_CHECK(LSIState, (obj), TYPE_LSI53C895A)
static inline int lsi_irq_on_rsl(LSIState *s)
{
- return 0; //return (s->sien0 & LSI_SIST0_RSL) && (s->scid & LSI_SCID_RRE);
+ return (s->sien0 & LSI_SIST0_RSL) && (s->scid & LSI_SCID_RRE);
}
static void lsi_soft_reset(LSIState *s)
{
DPRINTF("Reset\n");
s->carry = 0;
- memset (s, 0, sizeof LSIState);
s->msg_action = 0;
s->msg_len = 0;
s->dnad = 0;
s->dbc = 0;
s->temp = 0;
- s->scratch = 0;
- s->istat = 0;
+ memset(s->scratch, 0, sizeof(s->scratch));
+ s->istat0 = 0;
+ s->istat1 = 0;
s->dcmd = 0x40;
s->dstat = LSI_DSTAT_DFE;
s->dien = 0;
-// s->sist0 = 0;
-// s->sist1 = 0;
+ s->sist0 = 0;
+ s->sist1 = 0;
s->sien0 = 0;
-// s->sien1 = 0;
+ s->sien1 = 0;
+ s->mbox0 = 0;
+ s->mbox1 = 0;
+ s->dfifo = 0;
s->ctest2 = LSI_CTEST2_DACK;
s->ctest3 = 0;
s->ctest4 = 0;
s->ctest5 = 0;
+ s->ccntl0 = 0;
+ s->ccntl1 = 0;
s->dsp = 0;
s->dsps = 0;
s->dmode = 0;
s->dcntl = 0;
s->scntl0 = 0xc0;
s->scntl1 = 0;
+ s->scntl2 = 0;
+ s->scntl3 = 0;
s->sstat0 = 0;
s->sstat1 = 0;
- s->sstat2 = 0;
- s->scid = 0x80;
+ s->scid = 7;
s->sxfer = 0;
s->socl = 0;
s->sdid = 0;
+ s->ssid = 0;
+ s->stest1 = 0;
+ s->stest2 = 0;
+ s->stest3 = 0;
s->sidl = 0;
+ s->stime0 = 0;
+ s->respid0 = 0x80;
+ s->respid1 = 0;
+ s->mmrs = 0;
+ s->mmws = 0;
+ s->sfs = 0;
+ s->drs = 0;
+ s->sbms = 0;
+ s->dbms = 0;
+ s->dnad64 = 0;
+ s->pmjad1 = 0;
+ s->pmjad2 = 0;
+ s->rbc = 0;
+ s->ua = 0;
+ s->ia = 0;
s->sbc = 0;
+ s->csbc = 0;
s->sbr = 0;
assert(QTAILQ_EMPTY(&s->queue));
assert(!s->current);
}
-#if 0
static int lsi_dma_40bit(LSIState *s)
{
if ((s->ccntl1 & LSI_CCNTL1_40BIT) == LSI_CCNTL1_40BIT)
return 1;
return 0;
}
-#endif
static uint8_t lsi_reg_readb(LSIState *s, int offset);
static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
static void lsi_stop_script(LSIState *s)
{
- s->script_active = 0;
+ s->istat1 &= ~LSI_ISTAT1_SRUN;
}
static void lsi_update_irq(LSIState *s)
if (s->dstat) {
if (s->dstat & s->dien)
level = 1;
- s->istat |= LSI_ISTAT_DIP;
+ s->istat0 |= LSI_ISTAT0_DIP;
} else {
- s->istat &= ~LSI_ISTAT_DIP;
+ s->istat0 &= ~LSI_ISTAT0_DIP;
}
- if (s->sstat0) {
- if ((s->sstat0 & s->sien0))
+ if (s->sist0 || s->sist1) {
+ if ((s->sist0 & s->sien0) || (s->sist1 & s->sien1))
level = 1;
- s->istat |= LSI_ISTAT_SIP;
+ s->istat0 |= LSI_ISTAT0_SIP;
} else {
- s->istat &= ~LSI_ISTAT_SIP;
+ s->istat0 &= ~LSI_ISTAT0_SIP;
}
+ if (s->istat0 & LSI_ISTAT0_INTF)
+ level = 1;
if (level != last_level) {
DPRINTF("Update IRQ level %d dstat %02x sist %02x%02x\n",
- level, s->dstat, s->sstat0, s->sstat1);
+ level, s->dstat, s->sist1, s->sist0);
last_level = level;
}
pci_set_irq(d, level);
}
/* Stop SCRIPTS execution and raise a SCSI interrupt. */
-static void lsi_script_scsi_interrupt(LSIState *s, int stat0)
+static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1)
{
uint32_t mask0;
- //uint32_t mask1;
+ uint32_t mask1;
DPRINTF("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n",
- stat0, s->sstat0);
- s->sstat0 |= stat0;
- //s->sist1 |= stat1;
+ stat1, stat0, s->sist1, s->sist0);
+ s->sist0 |= stat0;
+ s->sist1 |= stat1;
/* Stop processor on fatal or unmasked interrupt. As a special hack
we don't stop processing when raising STO. Instead continue
execution and stop at the next insn that accesses the SCSI bus. */
- mask0 = s->sien0 | ~(LSI_SSTAT0_FCMP | LSI_SSTAT0_SEL); // | LSI_SIST1_RSL);
- //mask1 = s->sien1 | ~(LSI_SIST1_GEN | LSI_SIST1_HTH);
- //mask1 &= ~LSI_SIST1_STO;
- if (s->sstat0 & mask0) { // || s->sist1 & mask1) {
+ mask0 = s->sien0 | ~(LSI_SIST0_CMP | LSI_SIST0_SEL | LSI_SIST0_RSL);
+ mask1 = s->sien1 | ~(LSI_SIST1_GEN | LSI_SIST1_HTH);
+ mask1 &= ~LSI_SIST1_STO;
+ if (s->sist0 & mask0 || s->sist1 & mask1) {
lsi_stop_script(s);
}
lsi_update_irq(s);
static inline void lsi_set_phase(LSIState *s, int phase)
{
- s->sstat2 = (s->sstat2 & ~PHASE_MASK) | phase;
- s->ctest0 &= ~1;
- if (phase == PHASE_DI)
- s->ctest0 |= 1;
- s->sbcl &= ~LSI_SBCL_REQ;
+ s->sstat1 = (s->sstat1 & ~PHASE_MASK) | phase;
}
static void lsi_bad_phase(LSIState *s, int out, int new_phase)
{
/* Trigger a phase mismatch. */
- DPRINTF("Phase mismatch interrupt\n");
- lsi_script_scsi_interrupt(s, LSI_SSTAT0_MA);
- lsi_stop_script(s);
+ if (s->ccntl0 & LSI_CCNTL0_ENPMJ) {
+ if ((s->ccntl0 & LSI_CCNTL0_PMJCTL)) {
+ s->dsp = out ? s->pmjad1 : s->pmjad2;
+ } else {
+ s->dsp = (s->scntl2 & LSI_SCNTL2_WSR ? s->pmjad2 : s->pmjad1);
+ }
+ DPRINTF("Data phase mismatch jump to %08x\n", s->dsp);
+ } else {
+ DPRINTF("Phase mismatch interrupt\n");
+ lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
+ lsi_stop_script(s);
+ }
lsi_set_phase(s, new_phase);
- s->sbcl |= LSI_SBCL_REQ;
}
static void lsi_disconnect(LSIState *s)
{
s->scntl1 &= ~LSI_SCNTL1_CON;
- s->sstat2 &= ~PHASE_MASK;
+ s->sstat1 &= ~PHASE_MASK;
}
static void lsi_bad_selection(LSIState *s, uint32_t id)
{
DPRINTF("Selected absent target %d\n", id);
- lsi_script_scsi_interrupt(s, LSI_SSTAT0_STO);
+ lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
lsi_disconnect(s);
}
count = s->current->dma_len;
addr = s->dnad;
-#if 0
- /* both 40 and Table Indirect 64-bit DMAs store upper bits in dnad64 */
+ /* both 40 and Table Indirect 64-bit DMAs store upper bits in dnad64 */
if (lsi_dma_40bit(s) || lsi_dma_ti64bit(s))
addr |= ((uint64_t)s->dnad64 << 32);
else if (s->dbms)
addr |= ((uint64_t)s->dbms << 32);
else if (s->sbms)
addr |= ((uint64_t)s->sbms << 32);
-#endif
DPRINTF("DMA addr=0x" DMA_ADDR_FMT " len=%d\n", addr, count);
+ s->csbc += count;
s->dnad += count;
s->dbc -= count;
if (s->current->dma_buf == NULL) {
s->current = NULL;
p->pending = 0;
- p->out = (s->sstat2 & PHASE_MASK) == PHASE_DO;
+ p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
}
/* Queue a byte for a MSG IN phase. */
s->current = p;
id = (p->tag >> 8) & 0xf;
+ s->ssid = id | 0x80;
/* LSI53C700 Family Compatibility, see LSI53C895A 4-73 */
if (!(s->dcntl & LSI_DCNTL_COM)) {
s->sfbr = 1 << (id & 0x7);
}
- s->lcrc = 0;
DPRINTF("Reselected target %d\n", id);
s->scntl1 |= LSI_SCNTL1_CON;
lsi_set_phase(s, PHASE_MI);
}
if (lsi_irq_on_rsl(s)) {
- lsi_script_scsi_interrupt(s, LSI_SSTAT0_SEL);
+ lsi_script_scsi_interrupt(s, LSI_SIST0_RSL, 0);
}
}
g_free(p);
}
-void lsi_request_cancelled(SCSIRequest *req)
+static void lsi_request_cancelled(SCSIRequest *req)
{
LSIState *s = LSI53C895A(req->bus->qbus.parent);
- lsi_request *p = (lsi_request*)req->hba_private;
+ lsi_request *p = (lsi_request*)req->hba_private;
req->hba_private = NULL;
lsi_request_free(s, p);
for service from the device driver. */
if (s->waiting == 1 ||
(lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) &&
- !(s->istat & (LSI_ISTAT_SIP | LSI_ISTAT_DIP)))) {
+ !(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) {
/* Reselect device. */
lsi_reselect(s, p);
return 0;
LSIState *s = LSI53C895A(req->bus->qbus.parent);
int out;
- out = (s->sstat2 & PHASE_MASK) == PHASE_DO;
+ out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
DPRINTF("Command complete status=%d\n", (int)status);
- s->lcrc = 0;
s->status = status;
s->command_complete = 2;
if (s->waiting && s->dbc != 0) {
}
}
- out = (s->sstat2 & PHASE_MASK) == PHASE_DO;
+ out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
/* host adapter (re)connected */
DPRINTF("Data ready tag=0x%x len=%d\n", req->tag, len);
}
}
-static int idbitstonum(int id)
-{
- int num = 0;
- while (id > 1) {
- num++;
- id >>= 1;
- }
- if (num > 7)
- num = -1;
- return num;
-}
-
static void lsi_do_command(LSIState *s)
{
SCSIDevice *dev;
if (s->dbc > 16)
s->dbc = 16;
pci_dma_read(PCI_DEVICE(s), s->dnad, buf, s->dbc);
- DPRINTF("Send command len=%d %02x.%02x.%02x.%02x.%02x.%02x\n", s->dbc, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
s->sfbr = buf[0];
s->command_complete = 0;
- id = (s->select_tag >> 8) & 0xff;
- s->lcrc = id; //1 << (id & 0x7);
- dev = scsi_device_find(&s->bus, 0, idbitstonum(id), s->current_lun);
+ id = (s->select_tag >> 8) & 0xf;
+ dev = scsi_device_find(&s->bus, 0, id, s->current_lun);
if (!dev) {
lsi_bad_selection(s, id);
return;
{
PCIDevice *pci_dev = PCI_DEVICE(s);
uint32_t insn;
- uint32_t addr;
+ uint32_t addr, addr_high;
int opcode;
int insn_processed = 0;
- s->script_active = 1;
+ s->istat1 |= LSI_ISTAT1_SRUN;
again:
insn_processed++;
insn = read_dword(s, s->dsp);
goto again;
}
addr = read_dword(s, s->dsp + 4);
+ addr_high = 0;
DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr);
s->dsps = addr;
s->dcmd = insn >> 24;
s->dsp += 8;
switch (insn >> 30) {
case 0: /* Block move. */
- if (s->sstat0 & LSI_SSTAT0_STO) {
+ if (s->sist1 & LSI_SIST1_STO) {
DPRINTF("Delayed select timeout\n");
lsi_stop_script(s);
break;
}
s->dbc = insn & 0xffffff;
+ s->rbc = s->dbc;
+ /* ??? Set ESA. */
+ s->ia = s->dsp - 8;
if (insn & (1 << 29)) {
/* Indirect addressing. */
addr = read_dword(s, addr);
pci_dma_read(pci_dev, s->dsa + offset, buf, 8);
/* byte count is stored in bits 0:23 only */
s->dbc = cpu_to_le32(buf[0]) & 0xffffff;
+ s->rbc = s->dbc;
addr = cpu_to_le32(buf[1]);
-#if 0
- /* 40-bit DMA, upper addr bits [39:32] stored in first DWORD of
+ /* 40-bit DMA, upper addr bits [39:32] stored in first DWORD of
* table, bits [31:24] */
if (lsi_dma_40bit(s))
addr_high = cpu_to_le32(buf[0]) >> 24;
else if (lsi_dma_ti64bit(s)) {
int selector = (cpu_to_le32(buf[0]) >> 24) & 0x1f;
switch (selector) {
- case 0x00:
- case 0x01:
- case 0x02:
- case 0x03:
- case 0x04:
- case 0x05:
- case 0x06:
- case 0x07:
- case 0x08:
- case 0x09:
- case 0x0a:
- case 0x0b:
- case 0x0c:
- case 0x0d:
- case 0x0e:
- case 0x0f:
- /* offset index into scratch registers since
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ /* offset index into scratch registers since
* TI64 mode can use registers C to R */
addr_high = s->scratch[2 + selector];
break;
s->dbms = read_dword(s, s->dsp);
s->dsp += 4;
s->ia = s->dsp - 12;
-#endif
}
- if ((s->sstat2 & PHASE_MASK) != ((insn >> 24) & 7)) {
+ if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) {
DPRINTF("Wrong phase got %d expected %d\n",
- s->sstat2 & PHASE_MASK, (insn >> 24) & 7);
- lsi_script_scsi_interrupt(s, LSI_SSTAT0_MA);
- s->sbcl |= LSI_SBCL_REQ;
+ s->sstat1 & PHASE_MASK, (insn >> 24) & 7);
+ lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
break;
}
s->dnad = addr;
- switch (s->sstat2 & 0x7) {
+ s->dnad64 = addr_high;
+ switch (s->sstat1 & 0x7) {
case PHASE_DO:
s->waiting = 2;
lsi_do_dma(s, 1);
lsi_do_msgin(s);
break;
default:
- BADF("Unimplemented phase %d\n", s->sstat2 & PHASE_MASK);
- exit(1);
+ BADF("Unimplemented phase %d\n", s->sstat1 & PHASE_MASK);
}
+ s->dfifo = s->dbc & 0xff;
s->ctest5 = (s->ctest5 & 0xfc) | ((s->dbc >> 8) & 3);
s->sbc = s->dbc;
+ s->rbc -= s->dbc;
+ s->ua = addr + s->dbc;
break;
case 1: /* IO or Read/Write instruction. */
} else {
id = insn;
}
- id = (id >> 16) & 0xff;
+ id = (id >> 16) & 0xf;
if (insn & (1 << 26)) {
addr = s->dsp + sextract32(addr, 0, 24);
}
s->dsp = s->dnad;
break;
}
- s->sstat1 |= LSI_SSTAT1_WOA;
-// s->scntl1 &= ~LSI_SCNTL1_IARB;
- if (!scsi_device_find(&s->bus, 0, idbitstonum(id), 0)) {
+ s->sstat0 |= LSI_SSTAT0_WOA;
+ s->scntl1 &= ~LSI_SCNTL1_IARB;
+ if (!scsi_device_find(&s->bus, 0, id, 0)) {
lsi_bad_selection(s, id);
break;
}
DPRINTF("Selected target %d%s\n",
- id, insn & (1 << 24) ? " ATN" : "");
+ id, insn & (1 << 3) ? " ATN" : "");
/* ??? Linux drivers compain when this is set. Maybe
it only applies in low-level mode (unimplemented).
lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
s->select_tag = id << 8;
s->scntl1 |= LSI_SCNTL1_CON;
- if (insn & (1 << 24)) {
+ if (insn & (1 << 3)) {
s->socl |= LSI_SOCL_ATN;
}
lsi_set_phase(s, PHASE_MO);
}
if (insn & (1 << 9)) {
BADF("Target mode not implemented\n");
- exit(1);
}
if (insn & (1 << 10))
s->carry = 1;
uint8_t op1;
uint8_t data8;
int reg;
- int xoperator;
+ int oper;
#ifdef DEBUG_LSI
static const char *opcode_names[3] =
{"Write", "Read", "Read-Modify-Write"};
reg = ((insn >> 16) & 0x7f) | (insn & 0x80);
data8 = (insn >> 8) & 0xff;
opcode = (insn >> 27) & 7;
- xoperator = (insn >> 24) & 7;
+ oper = (insn >> 24) & 7;
DPRINTF("%s reg 0x%x %s data8=0x%02x sfbr=0x%02x%s\n",
opcode_names[opcode - 5], reg,
- operator_names[xoperator], data8, s->sfbr,
+ operator_names[oper], data8, s->sfbr,
(insn & (1 << 23)) ? " SFBR" : "");
op0 = op1 = 0;
switch (opcode) {
op1 = data8;
break;
case 6: /* To SFBR */
- if (xoperator)
+ if (oper)
op0 = lsi_reg_readb(s, reg);
op1 = data8;
break;
case 7: /* Read-modify-write */
- if (xoperator)
+ if (oper)
op0 = lsi_reg_readb(s, reg);
if (insn & (1 << 23)) {
op1 = s->sfbr;
break;
}
- switch (xoperator) {
+ switch (oper) {
case 0: /* move */
op0 = op1;
break;
DPRINTF("NOP\n");
break;
}
- if (s->sstat0 & LSI_SSTAT0_STO) {
+ if (s->sist1 & LSI_SIST1_STO) {
DPRINTF("Delayed select timeout\n");
lsi_stop_script(s);
break;
}
if (cond == jmp && (insn & (1 << 17))) {
DPRINTF("Compare phase %d %c= %d\n",
- (s->sstat2 & PHASE_MASK),
+ (s->sstat1 & PHASE_MASK),
jmp ? '=' : '!',
((insn >> 24) & 7));
- cond = (s->sstat2 & PHASE_MASK) == ((insn >> 24) & 7);
+ cond = (s->sstat1 & PHASE_MASK) == ((insn >> 24) & 7);
}
if (cond == jmp && (insn & (1 << 18))) {
uint8_t mask;
case 3: /* Interrupt */
DPRINTF("Interrupt 0x%08x\n", s->dsps);
if ((insn & (1 << 20)) != 0) {
+ s->istat0 |= LSI_ISTAT0_INTF;
lsi_update_irq(s);
} else {
lsi_script_dma_interrupt(s, LSI_DSTAT_SIR);
assume this is the case and force an unexpected device disconnect.
This is apparently sufficient to beat the drivers into submission.
*/
- if (!(s->sien0 & LSI_SSTAT0_UDC))
+ if (!(s->sien0 & LSI_SIST0_UDC))
fprintf(stderr, "inf. loop with UDC masked\n");
- lsi_script_scsi_interrupt(s, LSI_SSTAT0_UDC);
+ lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0);
lsi_disconnect(s);
- } else if (s->script_active && !s->waiting) {
+ } else if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) {
if (s->dcntl & LSI_DCNTL_SSM) {
lsi_script_dma_interrupt(s, LSI_DSTAT_SSI);
} else {
DPRINTF("SCRIPTS execution stopped\n");
}
-#if 0
static uint8_t lsi_reg_readb(LSIState *s, int offset)
{
uint8_t tmp;
return (s->scratch[n] >> shift) & 0xff;
}
BADF("readb 0x%x\n", offset);
- exit(1);
-#undef CASE_GET_REG24
-#undef CASE_GET_REG32
-}
-#endif
-
-static uint8_t lsi_reg_readb2(LSIState *s, int offset)
-{
- uint8_t tmp;
-#define CASE_GET_REG24(name, addr) \
- case addr: return s->name & 0xff; \
- case addr + 1: return (s->name >> 8) & 0xff; \
- case addr + 2: return (s->name >> 16) & 0xff;
-
-#define CASE_GET_REG32(name, addr) \
- case addr: return s->name & 0xff; \
- case addr + 1: return (s->name >> 8) & 0xff; \
- case addr + 2: return (s->name >> 16) & 0xff; \
- case addr + 3: return (s->name >> 24) & 0xff;
-
- switch (offset)
- {
- case 0x00: /* SCNTL0 */
- return s->scntl0;
- case 0x01: /* SCNTL1 */
- return s->scntl1;
- case 0x02: /* SDID */
- return s->sdid;
- case 0x03: /* SIEN */
- return s->sien0;
- case 0x05: /* SXFER */
- return s->sxfer;
- case 0x09: /* SIDL */
- /* This is needed by the linux drivers. We currently only update it
- during the MSG IN phase. */
- return s->sidl;
- case 0xb: /* SBCL */
- /* NetBSD 1.x checks for REQ */
- tmp = s->sstat2 & PHASE_MASK;
- /* if phase mismatch, REQ is also active */
- tmp |= s->sbcl;
- if (s->socl & LSI_SOCL_ATN)
- tmp |= LSI_SBCL_ATN;
- return tmp;
- case 0xc: /* DSTAT */
- tmp = s->dstat | LSI_DSTAT_DFE;
- s->dstat = 0;
-// if ((s->istat0 & LSI_ISTAT0_INTF) == 0)
-// s->dstat = 0;
- lsi_update_irq(s);
- return tmp;
- case 0x0d: /* SSTAT0 */
- tmp = s->sstat0;
- s->sstat0 = 0;
- lsi_update_irq(s);
- return tmp;
- case 0x0e: /* SSTAT1 */
- return s->sstat1;
- case 0x0f: /* SSTAT2 */
- return s->sstat2;
- CASE_GET_REG32(dsa, 0x10)
- case 0x14: /* CTEST0 */
- return s->ctest0;
- case 0x15: /* CTEST1 */
- return 0xf0; // FMT and FFL are always empty
- case 0x16: /* CTEST2 */
- tmp = s->ctest2 | LSI_CTEST2_DACK;
- if (s->istat & LSI_ISTAT_SIGP) {
- s->istat &= ~LSI_ISTAT_SIGP;
- tmp |= LSI_CTEST2_SIGP;
- }
- return tmp;
- case 0x17: /* CTEST3 */
- return s->ctest3;
- case 0x18: /* CTEST4 */
- return s->ctest4;
- case 0x19: /* CTEST5 */
- return s->ctest5;
- case 0x1a: /* CTEST6 */
- return s->ctest6;
- case 0x1b: /* CTEST7 */
- return s->ctest7;
- CASE_GET_REG32(temp, 0x1c)
- case 0x20: /* DFIFO */
- return 0;
- case 0x21: /* ISTAT */
- return s->istat;
- case 0x22: /* CTEST8 */
- return (s->ctest8 | (2 << 4)) & ~0x08; // clear CLF
- case 0x23: /* LCRC */
- return s->lcrc;
- CASE_GET_REG24(dbc, 0x24)
- case 0x27: /* DCMD */
- return s->dcmd;
- CASE_GET_REG32(dnad, 0x28)
- CASE_GET_REG32(dsp, 0x2c)
- CASE_GET_REG32(dsps, 0x30)
- CASE_GET_REG32(scratch, 0x34)
- case 0x38: /* DMODE */
- return s->dmode;
- case 0x3a: /* DWT */
- return s->dwt;
- case 0x3b: /* DCNTL */
- return s->dcntl;
- }
+ return 0;
#undef CASE_GET_REG24
#undef CASE_GET_REG32
- write_log ("read unknown register %02X\n", offset);
- return 0;
-}
-static uint8_t lsi_reg_readb(LSIState *s, int offset)
-{
- uint8_t v = lsi_reg_readb2(s, offset);
-#ifdef DEBUG_LSI_REG
- DPRINTF("Read reg %x: %02X\n", offset, v);
-#endif
- return v;
-}
-
-static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
-{
-#define CASE_SET_REG24(name, addr) \
- case addr : s->name &= 0xffffff00; s->name |= val; break; \
- case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \
- case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break;
-
-#define CASE_SET_REG32(name, addr) \
- case addr : s->name &= 0xffffff00; s->name |= val; break; \
- case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \
- case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \
- case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break;
-
-#ifdef DEBUG_LSI_REG
- DPRINTF("Write reg %x = %02x\n", offset, val);
-#endif
- switch (offset) {
- case 0x00: /* SCNTL0 */
- s->scntl0 = val;
- if (val & LSI_SCNTL0_START) {
- BADF("Start sequence not implemented\n");
- }
- break;
- case 0x01: /* SCNTL1 */
- s->scntl1 = val;
- if (val & LSI_SCNTL1_ADB) {
- BADF("Immediate Arbritration not implemented\n");
- }
- if (val & LSI_SCNTL1_RST) {
- if (!(s->sstat0 & LSI_SSTAT0_RST)) {
-// qbus_reset_all(&s->bus.qbus);
- s->sstat0 |= LSI_SSTAT0_RST;
- lsi_script_scsi_interrupt(s, LSI_SSTAT0_RST);
- }
- } else {
- s->sstat0 &= ~LSI_SSTAT0_RST;
- }
- break;
- case 0x03: /* SIEN */
- s->sien0 = val;
- lsi_update_irq(s);
- break;
- case 0x04: /* SCID */
- s->scid = val;
- break;
- case 0x05: /* SXFER */
- s->sxfer = val;
- break;
- case 0x0b: /* SBCL */
- lsi_set_phase (s, val & PHASE_MASK);
- break;
- case 0x0c: case 0x0d: case 0x0e: case 0x0f:
- /* Linux writes to these readonly registers on startup. */
- return;
- CASE_SET_REG32(dsa, 0x10)
- case 0x14: /* CTEST0 */
- s->ctest0 = (val & 0xfe) | (s->ctest0 & 1);
- break;
- case 0x18: /* CTEST4 */
- s->ctest4 = val;
- break;
- case 0x19: /* CTEST5 */
- s->ctest5 = val;
- break;
- case 0x1a: /* CTEST6 */
- s->ctest6 = val;
- break;
- case 0x1b: /* CTEST7 */
- s->ctest7 = val;
- break;
- CASE_SET_REG32(temp, 0x1c)
-
- case 0x21: /* ISTAT */
- s->istat = (s->istat & 0x0f) | (val & 0xf0);
- if (val & LSI_ISTAT_ABRT) {
- lsi_script_dma_interrupt(s, LSI_DSTAT_ABRT);
- }
- if (s->waiting == 1 && (val & LSI_ISTAT_SIGP)) {
- DPRINTF("Woken by SIGP\n");
- s->waiting = 0;
- s->dsp = s->dnad;
- lsi_execute_script(s);
- }
- if (val & LSI_ISTAT_RST) {
- ;//qdev_reset_all(DEVICE(s));
- }
- break;
- case 0x22: /* CTEST8 */
- s->ctest8 = val;
- break;
- case 0x23: /* LCRC */
- s->lcrc = 0;
- break;
-
- CASE_SET_REG24(dbc, 0x24)
- CASE_SET_REG32(dnad, 0x28)
- case 0x2c: /* DSP[0:7] */
- s->dsp &= 0xffffff00;
- s->dsp |= val;
- break;
- case 0x2d: /* DSP[8:15] */
- s->dsp &= 0xffff00ff;
- s->dsp |= val << 8;
- break;
- case 0x2e: /* DSP[16:23] */
- s->dsp &= 0xff00ffff;
- s->dsp |= val << 16;
- break;
- case 0x2f: /* DSP[24:31] */
- s->dsp &= 0x00ffffff;
- s->dsp |= val << 24;
- if ((s->dmode & LSI_DMODE_MAN) == 0) {
- s->waiting = 0;
- lsi_execute_script(s);
- }
- break;
- CASE_SET_REG32(scratch, 0x34)
- case 0x38: /* DMODE */
-#if 0
- if (val & (LSI_DMODE_SIOM | LSI_DMODE_DIOM)) {
- BADF("IO mappings not implemented\n");
- }
-#endif
- s->dmode = val;
- break;
- case 0x39: /* DIEN */
- s->dien = val;
- lsi_update_irq(s);
- break;
- case 0x3a: /* DWT */
- s->dwt = val;
- break;
- case 0x3b: /* DCNTL */
- s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD);
- if ((val & LSI_DCNTL_STD) && (s->dmode & LSI_DMODE_MAN) == 0)
- lsi_execute_script(s);
- break;
- default:
- write_log ("write unknown register %02X\n", offset);
- break;
- }
-#undef CASE_SET_REG24
-#undef CASE_SET_REG32
}
-#if 0
static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
{
#define CASE_SET_REG24(name, addr) \
}
if (val & LSI_SCNTL1_RST) {
if (!(s->sstat0 & LSI_SSTAT0_RST)) {
-// qbus_reset_all(&s->bus.qbus);
+ ;//qbus_reset_all(&s->bus.qbus);
s->sstat0 |= LSI_SSTAT0_RST;
lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
}
s->dsp = s->dnad;
lsi_execute_script(s);
}
-// if (val & LSI_ISTAT0_SRST) {
-// qdev_reset_all(DEVICE(s));
-// }
+ if (val & LSI_ISTAT0_SRST) {
+ ;//qdev_reset_all(DEVICE(s));
+ }
break;
case 0x16: /* MBOX0 */
s->mbox0 = val;
case 0x17: /* MBOX1 */
s->mbox1 = val;
break;
- case 0x18: /* CTEST0 */
- /* nothing to do */
- break;
- case 0x1a: /* CTEST2 */
+ case 0x18: /* CTEST0 */
+ /* nothing to do */
+ break;
+ case 0x19: /* CTEST1 */
+ /* nothing to do */
+ break;
+ case 0x1a: /* CTEST2 */
s->ctest2 = val & LSI_CTEST2_PCICIE;
break;
case 0x1b: /* CTEST3 */
case 0x22: /* CTEST5 */
if (val & (LSI_CTEST5_ADCK | LSI_CTEST5_BBCK)) {
BADF("CTEST5 DMA increment not implemented\n");
- val &= ~(LSI_CTEST5_ADCK | LSI_CTEST5_BBCK);
}
s->ctest5 = val;
break;
#undef CASE_SET_REG24
#undef CASE_SET_REG32
}
-#endif
void lsi_mmio_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
#if 0
static const MemoryRegionOps lsi_mmio_ops = {
- lsi_mmio_read,
- lsi_mmio_write,
- DEVICE_NATIVE_ENDIAN,
- {
- 1,
- 1,
+ .read = lsi_mmio_read,
+ .write = lsi_mmio_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 1,
},
};
static void lsi_ram_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
- LSIState *s = (LSIState*)opaque;
+ LSIState *s = opaque;
uint32_t newval;
uint32_t mask;
int shift;
static uint64_t lsi_ram_read(void *opaque, hwaddr addr,
unsigned size)
{
- LSIState *s = (LSIState*)opaque;
+ LSIState *s = opaque;
uint32_t val;
uint32_t mask;
}
static const MemoryRegionOps lsi_ram_ops = {
- lsi_ram_read,
- lsi_ram_write,
- DEVICE_NATIVE_ENDIAN,
+ .read = lsi_ram_read,
+ .write = lsi_ram_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
};
static uint64_t lsi_io_read(void *opaque, hwaddr addr,
unsigned size)
{
- LSIState *s = (LSIState*)opaque;
+ LSIState *s = opaque;
return lsi_reg_readb(s, addr & 0xff);
}
static void lsi_io_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
- LSIState *s = (LSIState*)opaque;
+ LSIState *s = opaque;
lsi_reg_writeb(s, addr & 0xff, val);
}
static const MemoryRegionOps lsi_io_ops = {
- lsi_io_read,
- lsi_io_write,
- DEVICE_NATIVE_ENDIAN,
- {
- 1,
- 1,
+ .read = lsi_io_read,
+ .write = lsi_io_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 1,
},
};
#endif
}
type_init(lsi53c895a_register_types)
-#endif
\ No newline at end of file
+#endif
};
#define QEMUFile void*
-#define PCIDevice void*
+#define PCIDevice void
typedef unsigned long dma_addr_t;
-#define PCI_DEVICE(s) (void**)s
+#define PCI_DEVICE(s) ((void*)(s->bus.privdata))
#define DMA_ADDR_FMT "%08x"
+void pci710_set_irq(PCIDevice *pci_dev, int level);
+void lsi710_scsi_init(DeviceState *dev);
+void lsi710_scsi_reset(DeviceState *dev, void*);
+
void pci_set_irq(PCIDevice *pci_dev, int level);
void lsi_scsi_init(DeviceState *dev);
void lsi_scsi_reset(DeviceState *dev, void*);
DMA_DIRECTION_FROM_DEVICE = 1,
} DMADirection;
-int pci_dma_rw(PCIDevice *dev, dma_addr_t addr, void *buf, dma_addr_t len, DMADirection dir);
+int pci710_dma_rw(PCIDevice *dev, dma_addr_t addr, void *buf, dma_addr_t len, DMADirection dir);
-static inline int pci_dma_read(PCIDevice *dev, dma_addr_t addr,
+static inline int pci710_dma_read(PCIDevice *dev, dma_addr_t addr,
void *buf, dma_addr_t len)
{
- return pci_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE);
+ return pci710_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE);
+}
+static inline int pci710_dma_write(PCIDevice *dev, dma_addr_t addr,
+ const void *buf, dma_addr_t len)
+{
+ return pci710_dma_rw(dev, addr, (void *) buf, len, DMA_DIRECTION_FROM_DEVICE);
}
+int pci_dma_rw(PCIDevice *dev, dma_addr_t addr, void *buf, dma_addr_t len, DMADirection dir);
+
+static inline int pci_dma_read(PCIDevice *dev, dma_addr_t addr,
+ void *buf, dma_addr_t len)
+{
+ return pci_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE);
+}
static inline int pci_dma_write(PCIDevice *dev, dma_addr_t addr,
- const void *buf, dma_addr_t len)
+ const void *buf, dma_addr_t len)
{
- return pci_dma_rw(dev, addr, (void *) buf, len, DMA_DIRECTION_FROM_DEVICE);
+ return pci_dma_rw(dev, addr, (void *)buf, len, DMA_DIRECTION_FROM_DEVICE);
}
struct BusState {
};
+extern void lsi710_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size);
+extern uint64_t lsi710_mmio_read(void *opaque, hwaddr addr, unsigned size);
+
extern void lsi_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size);
extern uint64_t lsi_mmio_read(void *opaque, hwaddr addr, unsigned size);
//void scsi_bus_new(SCSIBus *bus, size_t bus_size, DeviceState *host,
// const SCSIBusInfo *info, const char *bus_name);
-static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
+static inline SCSIBus *scsi710_bus_from_device(SCSIDevice *d)
{
return NULL; //return DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus);
}
uint32_t scsi_cdb_length(uint8_t *buf);
int scsi_sense_valid(SCSISense sense);
int scsi_build_sense(uint8_t *in_buf, int in_len,
- uint8_t *buf, int len, bool fixed);
+ uint8_t *buf, int len, bool fixed);
SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
- uint32_t tag, uint32_t lun, void *hba_private);
+ uint32_t tag, uint32_t lun, void *hba_private);
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
- uint8_t *buf, int len, void *hba_private);
+ uint8_t *buf, int len, void *hba_private);
int32_t scsi_req_enqueue(SCSIRequest *req);
void scsi_req_free(SCSIRequest *req);
SCSIRequest *scsi_req_ref(SCSIRequest *req);
SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
/* scsi-generic.c. */
-extern const SCSIReqOps scsi_generic_req_ops;
+extern const SCSIReqOps scsi710_generic_req_ops;
void lsi_request_cancelled(SCSIRequest *req);
void lsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid);
void lsi_transfer_data(SCSIRequest *req, uint32_t len);
+uint32_t scsi710_data_cdb_length(uint8_t *buf);
+uint32_t scsi710_cdb_length(uint8_t *buf);
+int scsi710_sense_valid(SCSISense sense);
+int scsi710_build_sense(uint8_t *in_buf, int in_len,
+ uint8_t *buf, int len, bool fixed);
+
+SCSIRequest *scsi710_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
+ uint32_t tag, uint32_t lun, void *hba_private);
+SCSIRequest *scsi710_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
+ uint8_t *buf, int len, void *hba_private);
+int32_t scsi710_req_enqueue(SCSIRequest *req);
+void scsi710_req_free(SCSIRequest *req);
+SCSIRequest *scsi710_req_ref(SCSIRequest *req);
+void scsi710_req_unref(SCSIRequest *req);
+
+void scsi710_req_build_sense(SCSIRequest *req, SCSISense sense);
+void scsi710_req_print(SCSIRequest *req);
+void scsi710_req_continue(SCSIRequest *req);
+void scsi710_req_data(SCSIRequest *req, int len);
+void scsi710_req_complete(SCSIRequest *req, int status);
+uint8_t *scsi710_req_get_buf(SCSIRequest *req);
+int scsi710_req_get_sense(SCSIRequest *req, uint8_t *buf, int len);
+void scs710i_req_abort(SCSIRequest *req, int status);
+void scsi710_req_cancel(SCSIRequest *req);
+void scsi710_req_retry(SCSIRequest *req);
+void scsi710_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
+void scsi710_device_set_ua(SCSIDevice *sdev, SCSISense sense);
+void scsi710_device_report_change(SCSIDevice *dev, SCSISense sense);
+int scsi710_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
+SCSIDevice *scsi710_device_find(SCSIBus *bus, int channel, int target, int lun);
+
+/* scsi-generic.c. */
+extern const SCSIReqOps scsi710_generic_req_ops;
+
+void lsi710_request_cancelled(SCSIRequest *req);
+void lsi710_command_complete(SCSIRequest *req, uint32_t status, size_t resid);
+void lsi710_transfer_data(SCSIRequest *req, uint32_t len);
+
+
#endif
statusline_delay = STATUSLINE_MS * vblank_hz / (1000 * 1);
if (statusline_delay > STATUSLINE_MS * vblank_hz / (1000 * 1))
statusline_delay = STATUSLINE_MS * vblank_hz / (1000 * 1);
- if (statusline_delay > STATUSLINE_MS * vblank_hz / (1000 * 2) && statusline_text[1])
- statusline_delay = STATUSLINE_MS * vblank_hz / (1000 * 2);
+ if (statusline_delay > STATUSLINE_MS * vblank_hz / (1000 * 3) && statusline_text[1])
+ statusline_delay = STATUSLINE_MS * vblank_hz / (1000 * 3);
statusline_delay--;
if (statusline_delay)
return;