From 8c791115b811987597e1eb53b8bcd3939bbab915 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Fri, 25 Jul 2014 11:49:34 +0300 Subject: [PATCH] 2820b5 --- cfgfile.cpp | 18 +- cpuboard.cpp | 537 +++- cpummu.cpp | 105 +- cpummu30.cpp | 170 +- custom.cpp | 7 +- disk.cpp | 2 +- expansion.cpp | 13 +- filesys.cpp | 179 +- flashrom.cpp | 155 ++ fpp.cpp | 1348 ++++++--- gayle.cpp | 42 +- gencpu.cpp | 85 +- hardfile.cpp | 10 +- include/cpu_prefetch.h | 9 +- include/cpuboard.h | 12 +- include/cpummu.h | 95 +- include/cpummu030.h | 12 +- include/filesys.h | 3 +- include/flashrom.h | 7 + include/gui.h | 2 +- include/mmu_common.h | 9 + include/ncr_scsi.h | 23 +- include/newcpu.h | 44 +- include/options.h | 1 + jit/gencomp.cpp | 56 +- main.cpp | 18 +- memory.cpp | 21 +- ncr_scsi.cpp | 382 ++- newcpu.cpp | 663 ++++- newcpu_common.cpp | 36 + od-win32/hardfile_win32.cpp | 2 +- od-win32/md-fpp.h | 131 +- od-win32/mman.cpp | 9 +- od-win32/resources/winuae.rc | 4 +- od-win32/serial_win32.cpp | 4 +- od-win32/statusline_win32.cpp | 24 +- od-win32/sysconfig.h | 5 +- od-win32/win32.h | 4 +- od-win32/win32gui.cpp | 24 +- od-win32/winuae_msvc11/winuae_msvc.vcxproj | 9 +- .../winuae_msvc11/winuae_msvc.vcxproj.filters | 9 + od-win32/winuaechangelog.txt | 47 + qemuvga/lsi53c710.cpp | 2437 +++++++++++++++++ qemuvga/lsi53c895a.cpp | 726 ++--- qemuvga/qemuuaeglue.h | 33 +- qemuvga/scsi/scsi.h | 49 +- statusline.cpp | 4 +- 47 files changed, 6059 insertions(+), 1526 deletions(-) create mode 100644 flashrom.cpp create mode 100644 include/flashrom.h create mode 100644 qemuvga/lsi53c710.cpp diff --git a/cfgfile.cpp b/cfgfile.cpp index 99fb6086..ea613798 100644 --- a/cfgfile.cpp +++ b/cfgfile.cpp @@ -205,7 +205,7 @@ static const TCHAR *rtgtype[] = { _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 }; @@ -215,7 +215,7 @@ static const TCHAR *hdcontrollers[] = { _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[] = { @@ -1072,10 +1072,8 @@ void cfgfile_save_options (struct zfile *f, struct uae_prefs *p, int type) 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); @@ -1483,6 +1481,8 @@ void cfgfile_save_options (struct zfile *f, struct uae_prefs *p, int type) 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); @@ -3037,8 +3037,8 @@ static void get_filesys_controller (const TCHAR *hdc, int *type, int *num) 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; @@ -3561,12 +3561,13 @@ static int cfgfile_parse_hardware (struct uae_prefs *p, const TCHAR *option, TCH || 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) @@ -5240,7 +5241,6 @@ void default_prefs (struct uae_prefs *p, int type) 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; @@ -5388,6 +5388,8 @@ void default_prefs (struct uae_prefs *p, int type) 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; diff --git a/cpuboard.cpp b/cpuboard.cpp index ed20bc49..8681f164 100644 --- a/cpuboard.cpp +++ b/cpuboard.cpp @@ -19,6 +19,70 @@ #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 @@ -33,11 +97,23 @@ static int maprom_state; 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; @@ -50,7 +126,7 @@ MEMORY_FUNCTIONS(blizzardram); 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 }; @@ -100,7 +176,7 @@ static void REGPARAM2 blizzardram_nojit_bput(uaecptr addr, uae_u32 b) 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 }; @@ -160,10 +236,11 @@ static void REGPARAM2 blizzardmaprom_bput(uaecptr addr, uae_u32 b) 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 }; @@ -206,8 +283,6 @@ static addrbank blizzarde8_bank = { 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 @@ -215,6 +290,11 @@ static uae_u32 REGPARAM2 blizzardf0_lget(uaecptr addr) #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); @@ -226,6 +306,11 @@ static uae_u32 REGPARAM2 blizzardf0_wget(uaecptr addr) #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); @@ -237,18 +322,85 @@ static uae_u32 REGPARAM2 blizzardf0_bget(uaecptr addr) 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 }; @@ -332,7 +484,7 @@ static uae_u32 REGPARAM2 blizzarde8_lget(uaecptr addr) 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); @@ -340,36 +492,204 @@ static void copymaprom(void) 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) @@ -385,39 +705,64 @@ void cpuboard_map(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) @@ -425,6 +770,11 @@ 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 { @@ -441,6 +791,7 @@ void cpuboard_cleanup(void) blizzardea_bank.baseaddr = NULL; cpuboard_size = cpuboard2_size = -1; + } void cpuboard_init(void) @@ -455,7 +806,7 @@ 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; @@ -483,14 +834,34 @@ void cpuboard_init(void) 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; } } @@ -502,17 +873,38 @@ bool cpuboard_maprom(void) { 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: @@ -525,19 +917,42 @@ addrbank *cpuboard_autoconfig_init(void) 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; @@ -558,11 +973,19 @@ addrbank *cpuboard_autoconfig_init(void) 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 @@ -578,7 +1001,7 @@ addrbank *cpuboard_autoconfig_init(void) 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; diff --git a/cpummu.cpp b/cpummu.cpp index 4fc9c54a..c5ee841b 100644 --- a/cpummu.cpp +++ b/cpummu.cpp @@ -33,6 +33,8 @@ #include "cpummu.h" #include "debug.h" +#define MMUDUMP 0 + #define DBG_MMU_VERBOSE 1 #define DBG_MMU_SANITY 1 #if 0 @@ -41,7 +43,6 @@ #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]; @@ -108,7 +109,7 @@ void mmu_tt_modified (void) } -#if 0 +#if MMUDUMP /* {{{ mmu_dump_table */ static void mmu_dump_table(const char * label, uaecptr root_ptr) { @@ -124,7 +125,7 @@ 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); @@ -132,7 +133,7 @@ static void mmu_dump_table(const char * label, uaecptr root_ptr) 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 @@ -187,7 +188,7 @@ static void mmu_dump_table(const char * label, uaecptr root_ptr) 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 @@ -198,7 +199,7 @@ static void mmu_dump_table(const char * label, uaecptr root_ptr) 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, @@ -206,7 +207,7 @@ static void mmu_dump_table(const char * label, uaecptr root_ptr) ); } 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, @@ -245,8 +246,8 @@ void mmu_dump_tables(void) 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 } /* }}} */ @@ -665,6 +666,26 @@ uae_u32 REGPARAM2 mmu_get_long_unaligned(uaecptr addr, bool data, bool rmw) 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; @@ -724,7 +745,7 @@ uae_u8 REGPARAM2 mmu_get_byte_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_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, @@ -735,7 +756,17 @@ 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, @@ -746,7 +777,17 @@ 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) @@ -797,7 +838,7 @@ void REGPARAM2 mmu_put_byte_slow(uaecptr addr, uae_u8 val, bool super, bool data 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, @@ -809,7 +850,7 @@ void REGPARAM2 mmu_put_word_slow(uaecptr addr, uae_u16 val, bool super, bool dat 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, @@ -821,7 +862,7 @@ void REGPARAM2 mmu_put_long_slow(uaecptr addr, uae_u32 val, bool super, bool dat 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) @@ -987,9 +1028,9 @@ void mmu_get_move16(uaecptr addr, uae_u32 *v, bool data, int size) 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); } @@ -1003,9 +1044,9 @@ void mmu_put_move16(uaecptr addr, uae_u32 *val, bool data, int size) 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); } @@ -1140,6 +1181,26 @@ void REGPARAM2 mmu_flush_atc_all(bool global) 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; + } } @@ -1154,7 +1215,11 @@ void REGPARAM2 mmu_set_tc(uae_u16 tc) 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) diff --git a/cpummu30.cpp b/cpummu30.cpp index c120b5a1..05485259 100644 --- a/cpummu30.cpp +++ b/cpummu30.cpp @@ -1601,7 +1601,7 @@ void mmu030_put_long_atc(uaecptr addr, uae_u32 val, int l, uae_u32 fc) { 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) { @@ -1620,7 +1620,7 @@ 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) { @@ -1639,7 +1639,7 @@ 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) { @@ -1658,7 +1658,25 @@ 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) { @@ -1677,7 +1695,26 @@ 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) { @@ -1696,7 +1733,7 @@ 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 */ @@ -1716,11 +1753,11 @@ void mmu030_put_atc_generic(uaecptr addr, uae_u32 val, int l, uae_u32 fc, int si 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) { @@ -1739,10 +1776,10 @@ uae_u32 mmu030_get_atc_generic(uaecptr addr, int l, uae_u32 fc, int size, int fl 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); } @@ -1815,7 +1852,7 @@ void mmu030_put_long(uaecptr addr, uae_u32 val, uae_u32 fc) { // 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; } @@ -1833,7 +1870,7 @@ void mmu030_put_word(uaecptr addr, uae_u16 val, uae_u32 fc) { // 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; } @@ -1851,7 +1888,7 @@ void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc) { // 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; } @@ -1865,6 +1902,23 @@ void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc) { } } +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 @@ -1882,6 +1936,23 @@ uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc) { } } +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 @@ -1903,7 +1974,7 @@ uae_u8 mmu030_get_byte(uaecptr addr, uae_u32 fc) { // 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); @@ -1923,11 +1994,11 @@ void mmu030_put_generic(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int acc // 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; } @@ -2048,6 +2119,23 @@ uae_u16 REGPARAM2 mmu030_get_word_unaligned(uaecptr addr, uae_u32 fc, int flags) 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; @@ -2150,6 +2238,31 @@ uaecptr mmu030_translate(uaecptr addr, bool super, bool data, bool write) } } +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) { @@ -2165,6 +2278,25 @@ 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; + } } diff --git a/custom.cpp b/custom.cpp index 0d782dc1..f15328a7 100644 --- a/custom.cpp +++ b/custom.cpp @@ -4623,6 +4623,10 @@ static void rethink_intreq (void) rethink_akiko (); rethink_cd32fmv(); #endif +#ifdef NCR + ncr_rethink(); +#endif + cpuboard_rethink(); rethink_gayle (); } @@ -8028,7 +8032,8 @@ void custom_reset (bool hardreset, bool keyboardreset) gfxboard_reset (); #endif #ifdef NCR - ncr_reset (); + ncr710_reset(); + ncr_reset(); #endif #ifdef JIT compemu_reset (); diff --git a/disk.cpp b/disk.cpp index 6c2edbf8..31ee02e9 100644 --- a/disk.cpp +++ b/disk.cpp @@ -2299,7 +2299,7 @@ static void drive_eject (drive * drv) 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); diff --git a/expansion.cpp b/expansion.cpp index 92bb49df..f60d79f2 100644 --- a/expansion.cpp +++ b/expansion.cpp @@ -1433,9 +1433,10 @@ uaecptr need_uae_boot_rom (void) static addrbank *expamem_init_a2065(void) { #ifdef A2065 - a2065_init (); -#endif + return a2065_init (); +#else return NULL; +#endif } static addrbank *expamem_init_cdtv(void) { @@ -1463,7 +1464,7 @@ static addrbank *expamem_init_a2091_2(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 @@ -1471,7 +1472,7 @@ static addrbank *expamem_init_a4091(void) 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 @@ -1479,7 +1480,7 @@ static addrbank *expamem_init_a4091_2(void) static addrbank *expamem_init_warpengine(void) { #ifdef NCR - return ncr_warpengine_autoconfig_init(); + return ncr710_warpengine_autoconfig_init(); #else return NULL; #endif @@ -1531,7 +1532,7 @@ void expamem_reset (void) 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"); diff --git a/filesys.cpp b/filesys.cpp index 6e6b475e..b4ddfdc7 100644 --- a/filesys.cpp +++ b/filesys.cpp @@ -870,11 +870,17 @@ static void initialize_mountinfo (void) 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) { @@ -2619,7 +2625,7 @@ static a_inode *lookup_child_aino_for_exnext (Unit *unit, a_inode *base, TCHAR * 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; } @@ -3642,91 +3648,18 @@ static void 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; @@ -4473,8 +4406,8 @@ static void populate_directory (Unit *unit, a_inode *base) 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]; @@ -4502,35 +4435,32 @@ static void populate_directory (Unit *unit, a_inode *base) 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)); @@ -4541,47 +4471,48 @@ static void action_examine_next (Unit *unit, dpacket packet, bool 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); } @@ -7854,7 +7785,7 @@ static uae_u8 *restore_filesys_hardfile (UnitInfo *ui, uae_u8 *src) _tcscpy (hfd->product_rev, s); xfree (s); s = restore_string (); - _tcscpy (hfd->device_name, s); + _tcscpy (hfd->ci.devname, s); xfree (s); return src; } @@ -7878,7 +7809,7 @@ static uae_u8 *save_filesys_hardfile (UnitInfo *ui, uae_u8 *dst) 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; } diff --git a/flashrom.cpp b/flashrom.cpp new file mode 100644 index 00000000..f9fcc19c --- /dev/null +++ b/flashrom.cpp @@ -0,0 +1,155 @@ +/* +* 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]; +} diff --git a/fpp.cpp b/fpp.cpp index 078de3e9..6f14b41d 100644 --- a/fpp.cpp +++ b/fpp.cpp @@ -33,6 +33,8 @@ #include "cpummu030.h" #include "debug.h" +#include "softfloatx80.h" + #ifdef X86_MSVC_ASSEMBLY #define X86_MSVC_ASSEMBLY_FPU #define NATIVE_FPUCW @@ -64,6 +66,7 @@ uae_u32 xhex_1e2048[]={0xc53d5de5, 0x9e8b3b5d, 0x5a92}; 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; @@ -125,44 +128,181 @@ static bool fpu_mmu_fixup; #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) @@ -191,7 +331,7 @@ 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) @@ -269,41 +409,168 @@ bool fpu_get_constant(fpdata *fp, int cr) 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? */ @@ -338,16 +605,18 @@ static void fpu_format_error (void) #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.. */ @@ -375,6 +644,7 @@ static void fpu_op_unimp (uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr old 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; @@ -393,7 +663,7 @@ static void fpu_op_unimp (uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr old 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; @@ -412,6 +682,7 @@ static void fpu_op_unimp (uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr old 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; @@ -425,7 +696,7 @@ static void fpu_op_unimp (uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr old 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; @@ -458,7 +729,7 @@ static void fpu_op_illg2 (uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr old { 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; @@ -503,7 +774,7 @@ static bool fault_if_unimplemented_680x0 (uae_u16 opcode, uae_u16 extra, uaecptr 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; @@ -513,7 +784,7 @@ static bool fault_if_unimplemented_680x0 (uae_u16 opcode, uae_u16 extra, uaecptr 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; @@ -548,7 +819,7 @@ static bool fault_if_unimplemented_680x0 (uae_u16 opcode, uae_u16 extra, uaecptr 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; } } @@ -584,7 +855,7 @@ static bool fault_if_unimplemented_6888x (uae_u16 opcode, uae_u16 extra, uaecptr 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; @@ -598,7 +869,7 @@ static bool fault_if_4060 (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr ol 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; @@ -610,7 +881,7 @@ static bool fault_if_no_fpu_u (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecpt 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; @@ -669,79 +940,118 @@ static void fpu_null (void) #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))) @@ -758,23 +1068,22 @@ uae_u32 get_fpsr (void) 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 (); } @@ -784,7 +1093,7 @@ STATIC_INLINE void set_fpsr (uae_u32 x) 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) @@ -793,14 +1102,16 @@ STATIC_INLINE void set_fpsr (uae_u32 x) 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; @@ -809,7 +1120,7 @@ uae_u32 get_ftag (uae_u32 w1, uae_u32 w2, uae_u32 w3) return 3; // NAN } else { if (!(w2 & 0x80000000)) - return 4; // UNNORMAL + return 4; // Extended UNNORMAL return 0; // NORMAL } } @@ -822,7 +1133,7 @@ uae_u32 get_ftag (uae_u32 w1, uae_u32 w2, uae_u32 w3) /* 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; @@ -861,30 +1172,47 @@ static fptype to_pack (uae_u32 *wrd) #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 @@ -1002,10 +1330,40 @@ void from_pack (fptype src, uae_u32 *wrd, int kfactor) 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]; @@ -1015,6 +1373,8 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old 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; @@ -1026,16 +1386,18 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old 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; @@ -1121,6 +1483,7 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old } *adp = ad; + ad2 = ad; if (currprefs.fpu_model == 68060 && fault_if_unimplemented_680x0 (opcode, extra, ad, oldpc, src, -1)) return -1; @@ -1128,10 +1491,12 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old 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: { @@ -1142,6 +1507,8 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old 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: @@ -1159,11 +1526,12 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old 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: { @@ -1171,11 +1539,13 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old 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; @@ -1193,9 +1563,6 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o #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)) @@ -1213,18 +1580,18 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o 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; @@ -1286,15 +1653,21 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o 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); @@ -1308,12 +1681,12 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o 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]); @@ -1322,19 +1695,25 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o } 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; @@ -1394,16 +1773,14 @@ STATIC_INLINE int get_fp_ad (uae_u32 opcode, uae_u32 * ad) 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) { @@ -1680,8 +2057,8 @@ void fpuop_save (uae_u32 opcode) 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; @@ -1689,7 +2066,7 @@ void fpuop_save (uae_u32 opcode) 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 @@ -1916,11 +2293,6 @@ void fpuop_restore (uae_u32 opcode) 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; @@ -2045,15 +2417,393 @@ static uaecptr fmovem2fpp (uaecptr ad, uae_u32 list, int incr, int regdir) 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. */ + /* 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 ()) @@ -2269,9 +3019,6 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) 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; @@ -2296,7 +3043,6 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) 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)) @@ -2305,221 +3051,14 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra) 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. */ - /* 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; @@ -2536,21 +3075,23 @@ void fpuop_arithmetic (uae_u32 opcode, uae_u16 extra) 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 } @@ -2562,6 +3103,21 @@ void fpu_reset (void) 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) @@ -2573,9 +3129,9 @@ 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 (); @@ -2587,13 +3143,13 @@ uae_u8 *restore_fpu (uae_u8 *src) 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(); @@ -2627,9 +3183,9 @@ uae_u8 *save_fpu (int *len, uae_u8 *dstptr) 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); @@ -2639,13 +3195,13 @@ uae_u8 *save_fpu (int *len, uae_u8 *dstptr) 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]); diff --git a/gayle.cpp b/gayle.cpp index a8ca55f8..54420a8d 100644 --- a/gayle.cpp +++ b/gayle.cpp @@ -1557,12 +1557,12 @@ static uae_u32 REGPARAM2 gayle_lget (uaecptr addr) 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; } @@ -1591,7 +1591,7 @@ static uae_u32 REGPARAM2 gayle_wget (uaecptr addr) 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; } @@ -1614,7 +1614,7 @@ static uae_u32 REGPARAM2 gayle_bget (uaecptr addr) if (isa4000t (&addr)) { if (addr >= NCR_OFFSET) { addr &= NCR_MASK; - return ncr_io_bget_a4000t (addr); + return ncr710_io_bget_a4000t(addr); } return 0; } @@ -1632,16 +1632,16 @@ static void REGPARAM2 gayle_lput (uaecptr addr, uae_u32 value) 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; } @@ -1665,8 +1665,8 @@ static void REGPARAM2 gayle_wput (uaecptr addr, uae_u32 value) 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; } @@ -1689,7 +1689,7 @@ static void REGPARAM2 gayle_bput (uaecptr addr, uae_u32 value) if (isa4000t (&addr)) { if (addr >= NCR_OFFSET) { addr &= NCR_MASK; - ncr_io_bput_a4000t (addr, value); + ncr710_io_bput_a4000t(addr, value); } return; } @@ -2287,9 +2287,9 @@ static void initsramattr (int size, int readonly) *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; @@ -2841,8 +2841,8 @@ void gayle_reset (int hardreset) #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; diff --git a/gencpu.cpp b/gencpu.cpp index b0a66ad4..ed27dc62 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -181,10 +181,26 @@ static void cpulimit (void) 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) @@ -202,21 +218,21 @@ static void addcycles_ce020 (int cycles) 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 (); @@ -285,7 +301,7 @@ static void returncycles (char *s, int cycles) static void addcycles_ce020 (char *name, int head, int tail, int cycles) { - if (!using_ce020) + if (!isce020()) return; if (!head && !tail && !cycles) return; @@ -293,7 +309,7 @@ static void addcycles_ce020 (char *name, int head, int tail, int cycles) } 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"); @@ -512,7 +528,7 @@ static const char *gen_nextibyte (int flags) static void makefromsr (void) { printf ("\tMakeFromSR();\n"); - if (using_ce || using_ce020) + if (using_ce || isce020()) printf ("\tregs.ipl_pin = intlev ();\n"); } @@ -520,7 +536,7 @@ static void check_ipl (void) { if (ipl_fetched) return; - if (using_ce || using_ce020) + if (using_ce || isce020()) printf ("\tipl_fetch ();\n"); ipl_fetched = true; } @@ -570,7 +586,7 @@ static void fill_prefetch_full (void) 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); @@ -749,7 +765,7 @@ static void head_cycs (int h) static void add_head_cycs (int h) { - if (!using_ce020) + if (!isce020()) return; head_ce020_cycs_done = false; head_cycs (h); @@ -842,7 +858,7 @@ static void addopcycles_ce20 (int h, int t, int c, int subhead) static void addop_ce020 (instr *curi, int subhead) { - if (!using_ce020) + if (!isce020()) return; int h = curi->head; int t = curi->tail; @@ -1555,7 +1571,7 @@ static void genamode (instr *curi, amodes mode, char *reg, wordsizes size, char { int oldfixup = mmufixupstate; int subhead = 0; - if (using_ce020 && curi) { + if (isce020() && curi) { switch (curi->fetchmode) { case fetchmode_fea: @@ -1576,7 +1592,7 @@ static void genamode (instr *curi, amodes mode, char *reg, wordsizes size, char // 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); } @@ -1596,7 +1612,7 @@ static void genamodedual (instr *curi, amodes smode, char *sreg, wordsizes ssize int subhead = 0; bool eadmode = false; - if (using_ce020) { + if (isce020()) { switch (curi->fetchmode) { case fetchmode_fea: @@ -2578,6 +2594,23 @@ static void resetvars (void) 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"; @@ -3229,7 +3262,7 @@ static void gen_opcode (unsigned long int opcode) * - 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; @@ -3749,7 +3782,7 @@ static void gen_opcode (unsigned long int opcode) 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) { @@ -5402,7 +5435,7 @@ static void generate_cpu (int id, int mode) } 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; @@ -5457,13 +5490,21 @@ static void generate_cpu (int id, int mode) 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; } diff --git a/hardfile.cpp b/hardfile.cpp index 4b244496..cee0469a 100644 --- a/hardfile.cpp +++ b/hardfile.cpp @@ -341,9 +341,9 @@ static void create_virtual_rdb (struct hardfiledata *hfd) 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); @@ -355,8 +355,8 @@ static void create_virtual_rdb (struct hardfiledata *hfd) 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); diff --git a/include/cpu_prefetch.h b/include/cpu_prefetch.h index 22517d40..3c14ef3f 100644 --- a/include/cpu_prefetch.h +++ b/include/cpu_prefetch.h @@ -147,24 +147,19 @@ STATIC_INLINE void m68k_do_rts_ce020 (void) #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) { @@ -212,8 +207,6 @@ STATIC_INLINE void m68k_do_rts_ce030 (void) m68k_areg (regs, 7) += 4; } -extern uae_u32 get_word_ce040_prefetch (int); - #endif #ifdef CPUEMU_11 diff --git a/include/cpuboard.h b/include/cpuboard.h index ce5e5771..88485210 100644 --- a/include/cpuboard.h +++ b/include/cpuboard.h @@ -7,10 +7,20 @@ extern void cpuboard_cleanup(void); 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 + diff --git a/include/cpummu.h b/include/cpummu.h index 458b1972..54264396 100644 --- a/include/cpummu.h +++ b/include/cpummu.h @@ -323,6 +323,8 @@ extern void REGPARAM3 mmu060_put_rmw_bitfield (uae_u32 dst, uae_u32 bdata[2], ua 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, @@ -330,6 +332,11 @@ 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; @@ -394,33 +401,57 @@ static ALWAYS_INLINE uae_u32 mmu_get_long(uaecptr addr, bool data, int size, boo // 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); } @@ -430,11 +461,11 @@ static ALWAYS_INLINE void mmu_put_long(uaecptr addr, uae_u32 val, bool data, int // 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); } @@ -445,11 +476,11 @@ static ALWAYS_INLINE void mmu_put_word(uaecptr addr, uae_u16 val, bool data, int // 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); } @@ -460,11 +491,11 @@ static ALWAYS_INLINE void mmu_put_byte(uaecptr addr, uae_u8 val, bool data, int // 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); } @@ -475,9 +506,9 @@ static ALWAYS_INLINE uae_u32 mmu_get_user_long(uaecptr addr, bool super, bool da // 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); } @@ -487,9 +518,9 @@ static ALWAYS_INLINE uae_u16 mmu_get_user_word(uaecptr addr, bool super, bool da // 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); } @@ -499,9 +530,9 @@ static ALWAYS_INLINE uae_u8 mmu_get_user_byte(uaecptr addr, bool super, bool dat // 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); } @@ -511,11 +542,11 @@ static ALWAYS_INLINE void mmu_put_user_long(uaecptr addr, uae_u32 val, bool supe // 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); } @@ -526,11 +557,11 @@ static ALWAYS_INLINE void mmu_put_user_word(uaecptr addr, uae_u16 val, bool supe // 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); } @@ -541,11 +572,11 @@ static ALWAYS_INLINE void mmu_put_user_byte(uaecptr addr, uae_u8 val, bool super // 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); } @@ -579,14 +610,12 @@ static ALWAYS_INLINE uae_u32 HWget_b(uaecptr addr) 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) { @@ -632,14 +661,12 @@ static ALWAYS_INLINE void uae_mmu040_put_long(uaecptr addr, uae_u32 val) 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) { diff --git a/include/cpummu030.h b/include/cpummu030.h index 7f3ebb8b..6eebf99e 100644 --- a/include/cpummu030.h +++ b/include/cpummu030.h @@ -85,6 +85,8 @@ void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc); 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); @@ -93,6 +95,7 @@ uae_u32 mmu030_get_generic(uaecptr addr, uae_u32 fc, int size, int accesssize, i 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; @@ -103,16 +106,13 @@ static ALWAYS_INLINE uae_u32 uae_mmu030_get_ilong(uaecptr addr) 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) { diff --git a/include/filesys.h b/include/filesys.h index 73f38d01..009d0a82 100644 --- a/include/filesys.h +++ b/include/filesys.h @@ -39,7 +39,6 @@ struct hardfiledata { 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; @@ -99,7 +98,7 @@ struct hd_hardfiledata { #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 diff --git a/include/flashrom.h b/include/flashrom.h new file mode 100644 index 00000000..64609f2e --- /dev/null +++ b/include/flashrom.h @@ -0,0 +1,7 @@ + +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); diff --git a/include/gui.h b/include/gui.h index fe7a0342..12df295f 100644 --- a/include/gui.h +++ b/include/gui.h @@ -55,7 +55,7 @@ struct gui_info 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; diff --git a/include/mmu_common.h b/include/mmu_common.h index 50241798..f3effca4 100644 --- a/include/mmu_common.h +++ b/include/mmu_common.h @@ -147,4 +147,13 @@ static ALWAYS_INLINE uae_u32 phys_get_byte(uaecptr addr) 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 diff --git a/include/ncr_scsi.h b/include/ncr_scsi.h index 18b05589..c0566475 100644 --- a/include/ncr_scsi.h +++ b/include/ncr_scsi.h @@ -1,14 +1,23 @@ -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); diff --git a/include/newcpu.h b/include/newcpu.h index ccb61ded..8fd416fd 100644 --- a/include/newcpu.h +++ b/include/newcpu.h @@ -10,6 +10,10 @@ #include "machdep/m68k.h" #include "events.h" +#ifdef WITH_SOFTFLOAT +#include +#endif + #ifndef SET_CFLG #define SET_CFLG(x) (CFLG() = (x)) @@ -72,7 +76,7 @@ typedef uae_u8 flagtype; #ifdef FPUEMU -#if USE_LONG_DOUBLE +#ifdef USE_LONG_DOUBLE typedef long double fptype; #define LDPTR tbyte ptr #else @@ -105,16 +109,15 @@ struct cache030 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 { @@ -126,10 +129,8 @@ extern struct mmufixup mmufixup[2]; typedef struct { fptype fp; -#ifdef USE_SOFT_LONG_DOUBLE - bool fpx; - uae_u32 fpm; - uae_u64 fpe; +#ifdef WITH_SOFTFLOAT + floatx80 fpx; #endif } fpdata; @@ -174,6 +175,7 @@ struct regstruct 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 @@ -204,6 +206,7 @@ struct regstruct bool ce020memcycle_data; int ce020_tail; frame_time_t ce020_tail_cycles; + int memory_waitstate_cycles; }; extern struct regstruct regs; @@ -439,6 +442,25 @@ extern uae_u32 (*x_cp_next_ilong)(void); 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); @@ -446,6 +468,7 @@ 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; @@ -511,6 +534,7 @@ extern void exception3i (uae_u32 opcode, uaecptr addr); 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); @@ -522,15 +546,15 @@ extern void fill_prefetch_030 (void); /* 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[]; diff --git a/include/options.h b/include/options.h index 27691cfe..1c5306b3 100644 --- a/include/options.h +++ b/include/options.h @@ -329,6 +329,7 @@ struct uae_prefs { bool comp_midopt; bool comp_lowopt; bool fpu_strict; + bool fpu_softfloat; bool comp_hardflush; bool comp_constjump; diff --git a/jit/gencomp.cpp b/jit/gencomp.cpp index d4baf31e..6750279c 100644 --- a/jit/gencomp.cpp +++ b/jit/gencomp.cpp @@ -715,60 +715,60 @@ genmovemel (uae_u16 opcode) 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"); @@ -791,9 +791,9 @@ genmovemle (uae_u16 opcode) 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) { diff --git a/main.cpp b/main.cpp index 7ac6f51c..12b0d6a9 100644 --- a/main.cpp +++ b/main.cpp @@ -263,11 +263,6 @@ void fixup_cpu (struct uae_prefs *p) 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; @@ -282,8 +277,10 @@ void fixup_cpu (struct uae_prefs *p) 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")); @@ -613,10 +610,12 @@ void fixup_prefs (struct uae_prefs *p) 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) @@ -972,7 +971,8 @@ void do_leave_program (void) a3000scsi_free (); #endif #ifdef NCR - ncr_free (); + ncr710_free(); + ncr_free(); #endif #ifdef CD32 akiko_free (); @@ -1052,6 +1052,10 @@ void virtualdevice_init (void) #ifdef WITH_TABLETLIBRARY tabletlib_install (); #endif +#ifdef NCR + ncr710_init(); + ncr_init(); +#endif } static int real_main2 (int argc, TCHAR **argv) diff --git a/memory.cpp b/memory.cpp index 94367d1a..62637a14 100644 --- a/memory.cpp +++ b/memory.cpp @@ -45,6 +45,8 @@ int special_mem; #endif static int mem_hardreset; +#define FLASHEMU 0 + static bool isdirectjit (void) { return currprefs.cachesize && !currprefs.comptrustbyte; @@ -216,6 +218,10 @@ static bool gary_nonrange(uaecptr addr) 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); @@ -228,15 +234,11 @@ uae_u32 dummy_get (uaecptr addr, int size, bool inst) { 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 @@ -977,7 +979,6 @@ uae_u8 *REGPARAM2 default_xlate (uaecptr a) #if defined(ENFORCER) enforcer_disable (); #endif - if (be_cnt < 3) { int i, j; uaecptr a2 = a - 32; diff --git a/ncr_scsi.cpp b/ncr_scsi.cpp index 4256fb9b..14fced07 100644 --- a/ncr_scsi.cpp +++ b/ncr_scsi.cpp @@ -24,6 +24,7 @@ #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" @@ -45,14 +46,20 @@ #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; @@ -61,6 +68,8 @@ struct ncr_state 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; @@ -68,12 +77,16 @@ static struct ncr_state ncr_a4091_2; 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 }; @@ -83,24 +96,47 @@ static struct ncr_state *ncra4091[] = &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) @@ -113,8 +149,8 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, uint8_t *bu 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; } @@ -123,10 +159,10 @@ int32_t scsi_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); + 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) @@ -135,7 +171,7 @@ int32_t scsi_req_enqueue(SCSIRequest *req) } void scsi_req_unref(SCSIRequest *req) { - xfree (req); + xfree(req); } uint8_t *scsi_req_get_buf(SCSIRequest *req) { @@ -152,17 +188,101 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun) } 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; @@ -179,30 +299,56 @@ int pci_dma_rw(PCIDevice *dev, dma_addr_t addr, void *buf, dma_addr_t len, DMADi 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) @@ -214,10 +360,12 @@ 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) @@ -243,6 +391,8 @@ static uae_u32 REGPARAM2 ncr_wget (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; @@ -328,7 +478,9 @@ static void REGPARAM2 ncr_wput (struct ncr_state *ncr, uaecptr addr, uae_u32 w) } return; } - ncr_bput2 (ncr, addr, w >> 8); + if (ncr->newncr) + return; + ncr_bput2(ncr, addr, w >> 8); ncr_bput2 (ncr, addr + 1, w); } @@ -356,13 +508,13 @@ static void REGPARAM2 ncr_bput (struct ncr_state *ncr, uaecptr addr, uae_u32 b) 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) @@ -440,6 +592,57 @@ static uae_u32 REGPARAM2 we_lget (uaecptr addr) 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, @@ -457,10 +660,25 @@ static addrbank ncr_bank_a4091_2 = { 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) { @@ -473,20 +691,42 @@ 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; @@ -500,9 +740,14 @@ static void ncr_reset_board (struct ncr_state *ncr) 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] = { @@ -510,7 +755,7 @@ 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; @@ -551,13 +796,13 @@ addrbank *ncr_warpengine_autoconfig_init(void) 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]; @@ -606,8 +851,8 @@ addrbank *ncr_a4091_autoconfig_init (int devnum) 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; } @@ -628,7 +873,7 @@ static void freescsi (SCSIDevice *scsi) } } -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]); @@ -636,22 +881,38 @@ void ncr_free2(struct ncr_state *ncr) } } -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) @@ -739,6 +1000,25 @@ int a4091_add_scsi_unit (int ch, struct uaedev_config_info *ci, int devnum) 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 diff --git a/newcpu.cpp b/newcpu.cpp index 1d88a40c..a4f30818 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -61,6 +61,7 @@ int mmu_enabled, mmu_triggered; int cpu_cycles; static int baseclock; bool m68k_pc_indirect; +bool m68k_interrupt_delay; static int cpu_prefs_changed_flag; int cpucycleunit; @@ -90,9 +91,9 @@ static uae_u16 fake_mmusr_030; 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]; @@ -195,6 +196,15 @@ void (*x_do_cycles)(unsigned long); 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; @@ -813,7 +823,7 @@ static void set_x_funcs (void) 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; @@ -830,6 +840,22 @@ static void set_x_funcs (void) 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; @@ -865,7 +891,7 @@ static void set_x_funcs (void) 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; @@ -881,6 +907,22 @@ static void set_x_funcs (void) 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; @@ -1023,17 +1065,17 @@ void set_cpu_caches (bool flush) 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 } } @@ -1071,7 +1113,9 @@ static void build_cpufunctbl (void) 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; } @@ -1081,7 +1125,9 @@ static void build_cpufunctbl (void) 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; } @@ -1091,7 +1137,7 @@ static void build_cpufunctbl (void) 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; } @@ -1214,6 +1260,12 @@ static void build_cpufunctbl (void) 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")); @@ -1558,12 +1610,20 @@ static uaecptr ShowEA (void *f, uaecptr pc, uae_u16 opcode, int reg, amodes mode 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: { @@ -2628,7 +2688,7 @@ void NMI (void) } -static void m68k_reset (bool hardreset) +static void m68k_reset2(bool hardreset) { uae_u32 v; @@ -2721,6 +2781,11 @@ static void m68k_reset (bool hardreset) regs.ce020memcycles = 0; fill_prefetch (); } +void m68k_reset(void) +{ + m68k_reset2(false); +} + void REGPARAM2 op_unimpl (uae_u16 opcode) { @@ -3071,7 +3136,6 @@ static void do_trace (void) } } - // handle interrupt delay (few cycles) STATIC_INLINE bool time_for_interrupt (void) { @@ -3080,7 +3144,7 @@ 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; @@ -3191,7 +3255,7 @@ static int do_specialties (int cycles) 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); @@ -3240,7 +3304,7 @@ static int do_specialties (int cycles) if (regs.spcflags & SPCFLAG_TRACE) do_trace (); - if (currprefs.cpu_cycle_exact) { + if (m68k_interrupt_delay) { if (time_for_interrupt ()) { do_interrupt (regs.ipl); } @@ -3353,13 +3417,23 @@ static void out_cd32io (uae_u32 pc) #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 @@ -3491,6 +3565,7 @@ static void m68k_run_1_ce (void) r->instruction_pc = m68k_getpc (); (*cpufunctbl[opcode])(opcode); + wait_memory_cycles(); if (cpu_tracer) { cputrace.state = 0; } @@ -3680,7 +3755,7 @@ void cpu_halt (int id) 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 (); @@ -3902,7 +3977,6 @@ insretry: #endif -#if 0 /* "cycle exact" 68040+ */ static void m68k_run_3ce (void) @@ -3910,26 +3984,62 @@ 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 */ @@ -4034,6 +4144,8 @@ static void m68k_run_2ce (void) } (*cpufunctbl[opcode])(opcode); + + wait_memory_cycles(); cont: if (r->spcflags || time_for_interrupt ()) { @@ -4232,7 +4344,7 @@ void m68k_go (int may_quit) #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")); @@ -4341,11 +4453,14 @@ void m68k_go (int may_quit) 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 @@ -5258,6 +5373,24 @@ uae_u8 *restore_cpu (uae_u8 *src) } 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 (); @@ -5493,7 +5626,7 @@ uae_u8 *save_cpu (int *len, uae_u8 *dstptr) 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 */ @@ -5583,6 +5716,22 @@ uae_u8 *save_cpu (int *len, uae_u8 *dstptr) 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); @@ -5756,44 +5905,6 @@ void m68k_resumestopped (void) 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)) { @@ -6162,7 +6273,8 @@ static void fill_icache030 (uae_u32 addr) 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; @@ -6175,14 +6287,14 @@ STATIC_INLINE bool cancache030 (uaecptr 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; @@ -6226,6 +6338,25 @@ void write_dcache030 (uaecptr addr, uae_u32 val, int size) } } } +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) { @@ -6236,7 +6367,7 @@ 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); @@ -6332,9 +6463,372 @@ uae_u32 get_word_ce030_prefetch (int o) 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++) { @@ -6384,7 +6878,12 @@ void fill_prefetch (void) { 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) diff --git a/newcpu_common.cpp b/newcpu_common.cpp index 6196d0aa..9121d6c9 100644 --- a/newcpu_common.cpp +++ b/newcpu_common.cpp @@ -575,6 +575,42 @@ uae_u32 REGPARAM2 x_get_disp_ea_ce020 (uae_u32 base, int idx) 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 diff --git a/od-win32/hardfile_win32.cpp b/od-win32/hardfile_win32.cpp index 25bc03cf..7fa9f89b 100644 --- a/od-win32/hardfile_win32.cpp +++ b/od-win32/hardfile_win32.cpp @@ -1111,7 +1111,7 @@ static int hdf_write_2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, 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; diff --git a/od-win32/md-fpp.h b/od-win32/md-fpp.h index 8b93ed93..d7cb7885 100644 --- a/od-win32/md-fpp.h +++ b/od-win32/md-fpp.h @@ -20,6 +20,10 @@ #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; @@ -35,7 +39,7 @@ STATIC_INLINE void exten_zeronormalize(uae_u32 *pwrd1, uae_u32 *pwrd2, uae_u32 * } #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 @@ -49,14 +53,14 @@ STATIC_INLINE void to_exten(fpdata *dst, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd 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]; @@ -68,7 +72,7 @@ STATIC_INLINE void from_exten(fpdata *src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u #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; @@ -82,7 +86,7 @@ STATIC_INLINE double to_single (uae_u32 longvalue) #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; @@ -96,7 +100,7 @@ STATIC_INLINE uae_u32 from_single (double floatfake) #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; @@ -110,46 +114,32 @@ STATIC_INLINE void to_exten(fpdata *fpd, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd 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; @@ -163,7 +153,7 @@ STATIC_INLINE double to_single (uae_u32 value) #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; @@ -177,7 +167,7 @@ STATIC_INLINE uae_u32 from_single (double src) #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; @@ -192,7 +182,7 @@ STATIC_INLINE double to_double(uae_u32 wrd1, uae_u32 wrd2) #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; @@ -204,65 +194,50 @@ STATIC_INLINE void from_double(double src, uae_u32 * wrd1, uae_u32 * wrd2) 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 diff --git a/od-win32/mman.cpp b/od-win32/mman.cpp index e3d3c71e..de26a45c 100644 --- a/od-win32/mman.cpp +++ b/od-win32/mman.cpp @@ -588,10 +588,13 @@ void *shmat (int shmid, void *shmaddr, int shmflg) 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; diff --git a/od-win32/resources/winuae.rc b/od-win32/resources/winuae.rc index 582f25c8..e3b2a454 100644 --- a/od-win32/resources/winuae.rc +++ b/od-win32/resources/winuae.rc @@ -204,9 +204,9 @@ BEGIN 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 diff --git a/od-win32/serial_win32.cpp b/od-win32/serial_win32.cpp index e4633b64..002bee09 100644 --- a/od-win32/serial_win32.cpp +++ b/od-win32/serial_win32.cpp @@ -385,9 +385,9 @@ static void serdatcopy(void) 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; diff --git a/od-win32/statusline_win32.cpp b/od-win32/statusline_win32.cpp index de9d344d..6b5638f7 100644 --- a/od-win32/statusline_win32.cpp +++ b/od-win32/statusline_win32.cpp @@ -11,6 +11,8 @@ #include "picasso96_win.h" #include "win32gfx.h" #include "statusline.h" +#include "gui.h" +#include "xwin.h" static HDC statusline_hdc; static HBITMAP statusline_bitmap; @@ -112,22 +114,32 @@ void statusline_render(uae_u8 *buf, int bpp, int pitch, int width, int height, u 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++) { diff --git a/od-win32/sysconfig.h b/od-win32/sysconfig.h index 9396ab1a..37dd182f 100644 --- a/od-win32/sysconfig.h +++ b/od-win32/sysconfig.h @@ -47,7 +47,7 @@ #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 */ @@ -55,7 +55,8 @@ #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 */ diff --git a/od-win32/win32.h b/od-win32/win32.h index 56bf8b66..6da45052 100644 --- a/od-win32/win32.h +++ b/od-win32/win32.h @@ -20,12 +20,12 @@ #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") diff --git a/od-win32/win32gui.cpp b/od-win32/win32gui.cpp index 92e14427..de7827d8 100644 --- a/od-win32/win32gui.cpp +++ b/od-win32/win32gui.cpp @@ -4222,7 +4222,7 @@ void InitializeListView (HWND hDlg) _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")); @@ -7659,6 +7659,7 @@ static void values_to_memorydlg (HWND hDlg) 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]]); @@ -8154,8 +8155,11 @@ static INT_PTR CALLBACK MemoryDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARA 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); @@ -9019,9 +9023,9 @@ static void enable_for_cpudlg (HWND hDlg) 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); @@ -9168,8 +9172,8 @@ static void values_from_cpudlg (HWND hDlg) 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); @@ -10099,8 +10103,8 @@ static void inithdcontroller (HWND hDlg, int ctype, int devtype) 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); diff --git a/od-win32/winuae_msvc11/winuae_msvc.vcxproj b/od-win32/winuae_msvc11/winuae_msvc.vcxproj index 404b20e4..6d07e2d1 100644 --- a/od-win32/winuae_msvc11/winuae_msvc.vcxproj +++ b/od-win32/winuae_msvc11/winuae_msvc.vcxproj @@ -350,7 +350,7 @@ 0x0409 - 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) + 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) $(OutDir)$(TargetName)$(TargetExt) true %(AdditionalLibraryDirectories);$(SolutionDir)\..\lib\ @@ -428,7 +428,7 @@ 0x0409 - 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) + 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) $(OutDir)$(TargetName)$(TargetExt) true %(AdditionalLibraryDirectories);$(SolutionDir)\..\lib\ @@ -649,7 +649,7 @@ 0x0409 - 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) + 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) $(OutDir)$(TargetName)$(TargetExt) true %(AdditionalLibraryDirectories);$(SolutionDir)\..\lib\ @@ -792,11 +792,13 @@ + + @@ -804,6 +806,7 @@ + diff --git a/od-win32/winuae_msvc11/winuae_msvc.vcxproj.filters b/od-win32/winuae_msvc11/winuae_msvc.vcxproj.filters index 3fb0ad54..72f3243b 100644 --- a/od-win32/winuae_msvc11/winuae_msvc.vcxproj.filters +++ b/od-win32/winuae_msvc11/winuae_msvc.vcxproj.filters @@ -658,6 +658,15 @@ win32 + + common + + + common + + + qemu + diff --git a/od-win32/winuaechangelog.txt b/od-win32/winuaechangelog.txt index 96d0d017..bff519e6 100644 --- a/od-win32/winuaechangelog.txt +++ b/od-win32/winuaechangelog.txt @@ -18,6 +18,53 @@ Things that may happen in 2015: - 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.. diff --git a/qemuvga/lsi53c710.cpp b/qemuvga/lsi53c710.cpp new file mode 100644 index 00000000..3c46995a --- /dev/null +++ b/qemuvga/lsi53c710.cpp @@ -0,0 +1,2437 @@ +/* + * 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 + +#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 diff --git a/qemuvga/lsi53c895a.cpp b/qemuvga/lsi53c895a.cpp index 59724161..5be343e1 100644 --- a/qemuvga/lsi53c895a.cpp +++ b/qemuvga/lsi53c895a.cpp @@ -13,8 +13,6 @@ * as well-behaved operating systems will not try to use them. */ -/* Hacked to support LSI53C710 for UAE by Toni Wilen */ - #include #include "qemuuaeglue.h" @@ -36,24 +34,23 @@ 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__);} 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 @@ -66,39 +63,41 @@ do { write_log("lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0) #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 @@ -127,9 +126,11 @@ do { write_log("lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0) #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 @@ -159,18 +160,11 @@ do { write_log("lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0) #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 @@ -197,7 +191,7 @@ typedef struct lsi_request { typedef struct { /*< private >*/ - //PCIDevice parent_obj; + // PCIDevice parent_obj; /*< public >*/ //MemoryRegion mmio_io; @@ -228,63 +222,83 @@ typedef struct { 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; @@ -293,40 +307,66 @@ static void lsi_soft_reset(LSIState *s) 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) @@ -347,7 +387,6 @@ static int lsi_dma_64bit(LSIState *s) 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); @@ -364,7 +403,7 @@ static inline uint32_t read_dword(LSIState *s, uint32_t addr) static void lsi_stop_script(LSIState *s) { - s->script_active = 0; + s->istat1 &= ~LSI_ISTAT1_SRUN; } static void lsi_update_irq(LSIState *s) @@ -381,22 +420,24 @@ 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); @@ -414,22 +455,22 @@ static void lsi_update_irq(LSIState *s) } /* 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); @@ -446,21 +487,25 @@ static void lsi_script_dma_interrupt(LSIState *s, int stat) 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; } @@ -478,13 +523,13 @@ static void lsi_resume_script(LSIState *s) 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); } @@ -512,17 +557,16 @@ static void lsi_do_dma(LSIState *s, int out) 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) { @@ -557,7 +601,7 @@ static void lsi_queue_command(LSIState *s) 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. */ @@ -581,11 +625,11 @@ static void lsi_reselect(LSIState *s, lsi_request *p) 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); @@ -598,7 +642,7 @@ static void lsi_reselect(LSIState *s, lsi_request *p) } if (lsi_irq_on_rsl(s)) { - lsi_script_scsi_interrupt(s, LSI_SSTAT0_SEL); + lsi_script_scsi_interrupt(s, LSI_SIST0_RSL, 0); } } @@ -625,10 +669,10 @@ static void lsi_request_free(LSIState *s, lsi_request *p) 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); @@ -652,7 +696,7 @@ static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len) 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; @@ -669,9 +713,8 @@ void lsi_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; + 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) { @@ -703,7 +746,7 @@ void lsi_transfer_data(SCSIRequest *req, uint32_t len) } } - 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); @@ -718,18 +761,6 @@ void lsi_transfer_data(SCSIRequest *req, uint32_t 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; @@ -741,13 +772,11 @@ static void lsi_do_command(LSIState *s) 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; @@ -1014,11 +1043,11 @@ static void lsi_execute_script(LSIState *s) { 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); @@ -1029,18 +1058,22 @@ again: 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); @@ -1054,33 +1087,33 @@ again: 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; @@ -1114,17 +1147,16 @@ again: 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); @@ -1150,11 +1182,13 @@ again: 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. */ @@ -1167,7 +1201,7 @@ again: } else { id = insn; } - id = (id >> 16) & 0xff; + id = (id >> 16) & 0xf; if (insn & (1 << 26)) { addr = s->dsp + sextract32(addr, 0, 24); } @@ -1180,20 +1214,20 @@ again: 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); @@ -1219,7 +1253,6 @@ again: } if (insn & (1 << 9)) { BADF("Target mode not implemented\n"); - exit(1); } if (insn & (1 << 10)) s->carry = 1; @@ -1242,7 +1275,7 @@ again: 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"}; @@ -1253,10 +1286,10 @@ again: 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) { @@ -1265,12 +1298,12 @@ again: 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; @@ -1280,7 +1313,7 @@ again: break; } - switch (xoperator) { + switch (oper) { case 0: /* move */ op0 = op1; break; @@ -1337,7 +1370,7 @@ again: 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; @@ -1349,10 +1382,10 @@ again: } 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; @@ -1384,6 +1417,7 @@ again: 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); @@ -1443,11 +1477,11 @@ again: 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 { @@ -1457,7 +1491,6 @@ again: DPRINTF("SCRIPTS execution stopped\n"); } -#if 0 static uint8_t lsi_reg_readb(LSIState *s, int offset) { uint8_t tmp; @@ -1628,271 +1661,11 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset) 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) \ @@ -1923,7 +1696,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) } 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); } @@ -1979,9 +1752,9 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) 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; @@ -1989,10 +1762,13 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t 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 */ @@ -2008,7 +1784,6 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) 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; @@ -2129,7 +1904,6 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) #undef CASE_SET_REG24 #undef CASE_SET_REG32 } -#endif void lsi_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) @@ -2149,19 +1923,19 @@ uint64_t lsi_mmio_read(void *opaque, hwaddr addr, #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; @@ -2177,7 +1951,7 @@ static void lsi_ram_write(void *opaque, hwaddr addr, 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; @@ -2188,32 +1962,32 @@ static uint64_t lsi_ram_read(void *opaque, hwaddr addr, } 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 @@ -2425,4 +2199,4 @@ static void lsi53c895a_register_types(void) } type_init(lsi53c895a_register_types) -#endif \ No newline at end of file +#endif diff --git a/qemuvga/qemuuaeglue.h b/qemuvga/qemuuaeglue.h index d689072a..af143a0a 100644 --- a/qemuvga/qemuuaeglue.h +++ b/qemuvga/qemuuaeglue.h @@ -292,11 +292,15 @@ struct DeviceState }; #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*); @@ -328,18 +332,30 @@ typedef enum { 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 { @@ -353,5 +369,8 @@ 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); diff --git a/qemuvga/scsi/scsi.h b/qemuvga/scsi/scsi.h index 04c8cda2..f4d73215 100644 --- a/qemuvga/scsi/scsi.h +++ b/qemuvga/scsi/scsi.h @@ -136,7 +136,7 @@ struct SCSIBus { //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); } @@ -205,12 +205,12 @@ uint32_t scsi_data_cdb_length(uint8_t *buf); 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); @@ -233,11 +233,50 @@ int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed); 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 diff --git a/statusline.cpp b/statusline.cpp index 67979552..4a695c0c 100644 --- a/statusline.cpp +++ b/statusline.cpp @@ -353,8 +353,8 @@ void statusline_vsync(void) 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; -- 2.47.3