mirror of
https://github.com/Oibaf66/uae-wii.git
synced 2024-11-11 05:15:06 +01:00
1641 lines
45 KiB
C
1641 lines
45 KiB
C
/*
|
|
* UAE Action Replay 1/2/3 and HRTMon support
|
|
*
|
|
* (c) 2000-2002 Toni Wilen <twilen@arabuusimiehet.com>
|
|
* (c) 2003 Mark Cox <markcox@email.com>
|
|
*
|
|
* Toni's unofficial UAE patches are located at:
|
|
* http://www.arabuusimiehet.com/twilen/uae/
|
|
*
|
|
* HRTMon:
|
|
*
|
|
* HRTMon support is tested with version 2.25 + patch.
|
|
* More information about HRTMon can be found from
|
|
* http://dumbo.cryogen.ch/hrtmon/
|
|
*
|
|
* Action Replay 2/3:
|
|
*
|
|
* Tested with AR3 ROM version 3.09 (10/13/91) and AR2 2.12 (12/24/90)
|
|
*
|
|
* Found to work for the following roms by Mark Cox:
|
|
* (Yes the date format is inconsistent, i just copied it straight from the rom)
|
|
* 1.15
|
|
* 2.14 22/02/91 dd/mm/yy
|
|
* 3.09 10/13/91 mm/dd/yy
|
|
* 3.17 12/17/91 mm/dd/yy
|
|
*
|
|
* This patch also makes AR3 compatible with KickStart's other than 1.3
|
|
* (ROM checksum error is normal with KS != 1.3)
|
|
* NOTE: AR has problems with 68020+ processors.
|
|
* For maximum compatibility select 68000/68010 and A500 speed from UAE
|
|
* options.
|
|
*
|
|
* How to rip Action Replay 1/2/3 ROM:
|
|
*
|
|
* Find A500 with AR1/2/3, press 'freeze'-button
|
|
*
|
|
* type following:
|
|
*
|
|
* AR1:
|
|
* lord olaf<RETURN>
|
|
*
|
|
* AR2 or AR3:
|
|
* may<RETURN>
|
|
* the<RETURN>
|
|
* force<RETURN>
|
|
* be<RETURN>
|
|
* with<RETURN>
|
|
* you<RETURN>
|
|
* new<RETURN> (AR3 only)
|
|
*
|
|
* AR1: 64K ROM is visible at 0xf00000-0xf0ffff
|
|
* and 16K RAM at 0x9fc000-0x9fffff
|
|
* AR2: 128K ROM is visible at 0x400000-0x41ffff
|
|
* AR3: 256K ROM is visible at 0x400000-0x43ffff
|
|
* and 64K RAM at 0x440000-0x44ffff
|
|
*
|
|
* following command writes ROM to disk:
|
|
*
|
|
* AR1: sm ar1.rom,f00000 f10000
|
|
* AR2: sm ar2.rom,400000 420000
|
|
* AR3: sm ar3.rom,400000 440000
|
|
*
|
|
* NOTE: I (mark) could not get the action replay 1 dump to work as above.
|
|
* (also, it will only dump to the action replay special disk format)
|
|
* To dump the rom i had to :
|
|
* 1. Boot the a500 and start a monitor (e.g. cmon).
|
|
* 2. Use the monitor to allocate 64k memory.
|
|
* 3. Enter the action replay.
|
|
* 4. Enter sysop mode.
|
|
* 5. Copy the rom into the address the monitor allocated.
|
|
* 6. Exit the action replay.
|
|
* 7. Save the ram from the monitor to disk.
|
|
*
|
|
* I DO NOT REPLY MAILS ASKING FOR ACTION REPLAY ROMS!
|
|
*
|
|
* AR2/3 hardware notes (not 100% correct..)
|
|
*
|
|
* first 8 bytes of ROM are not really ROM, they are
|
|
* used to read/write cartridge's hardware state
|
|
*
|
|
* 0x400000: hides cartridge ROM/RAM when written
|
|
* 0x400001: read/write HW state
|
|
* 3 = reset (read-only)
|
|
* 2 = sets HW to activate when breakpoint condition is detected
|
|
* 1 = ???
|
|
* 0 = freeze pressed
|
|
* 0x400002/0x400003: mirrors 0x400000/0x400001
|
|
* 0x400006/0x400007: when written to, turns chip-ram overlay off
|
|
*
|
|
* breakpoint condition is detected when CPU first accesses
|
|
* chip memory below 1024 bytes and then reads CIA register
|
|
* $BFE001.
|
|
*
|
|
* cartridge hardware also snoops CPU accesses to custom chip
|
|
* registers (DFF000-DFF1FE). All CPU custom chip accesses are
|
|
* saved to RAM at 0x44f000-0x44f1ff. Note that emulated AR3 also
|
|
* saves copper's custom chip accesses. This fix stops programs
|
|
* that try to trick AR by using copper to update write-only
|
|
* custom registers.
|
|
*
|
|
* 30.04.2001 - added AR2 support
|
|
* 21.07.2001 - patch updated
|
|
* 29.07.2002 - added AR1 support
|
|
* 11.03.2003 - added AR1 breakpoint support, checksum support and fixes. (Mark Cox)
|
|
*
|
|
*/
|
|
|
|
/* AR2/3 'NORES' info.
|
|
* On ar2 there is a 'nores' command,
|
|
* on ar3, it is accessible using the mouse.
|
|
* This command will not work using the current infrastructure,
|
|
* so don't use it 8).
|
|
*/
|
|
|
|
/* AR1 Breakpoint info.
|
|
* 1.15 If a breakpoint occurred. Its address is stored at 9fe048.
|
|
* The 5 breakpoint entries each consisting of 6 bytes are stored at 9fe23e.
|
|
* Each entry contains the breakpoint long word followed by 2 bytes of the original contents of memory
|
|
* that is replaced by a trap instruction in mem.
|
|
* So the table finishes at 9fe25c.
|
|
*/
|
|
|
|
/* How AR1 is entered on reset:
|
|
* In the kickstart (1.3) there is the following code:
|
|
* I have marked the important lines:
|
|
*
|
|
* fc00e6 lea f00000,a1 ; address where AR1 rom is located.
|
|
* fc00ec cmpa.l a1,a0
|
|
* fc00ee beq fc00fe.s
|
|
* fc00f0 lea C(pc), a5
|
|
* fc00f4 cmpi.w #1111,(a1) ; The first word of the AR1 rom is set to 1111.
|
|
* fc00f8 bne fc00fe.s
|
|
* fc00fa jmp 2(a1) ; This is the entry point of the rom.
|
|
*/
|
|
|
|
/* Flag info:
|
|
* AR3:'ARON'. This is unset initially. It is set the first time you enter the AR via a freeze.
|
|
* It enables you to keep the keyboard buffer and such.
|
|
* If this flag is unset, the keyboard buffer is cleared, the breakpoints are deleted and ... */
|
|
|
|
/* AR3:'PRIN'. This flag is unset initially. It is set at some point and when you switch to the 2nd screen
|
|
* for the first time it displays all the familiar text. Then unsets 'PRIN'.
|
|
*/
|
|
|
|
#ifdef ACTION_REPLAY
|
|
|
|
#include "sysconfig.h"
|
|
#include "sysdeps.h"
|
|
|
|
#include "options.h"
|
|
#include "uae.h"
|
|
#include "memory.h"
|
|
#include "custom.h"
|
|
#include "newcpu.h"
|
|
#include "zfile.h"
|
|
#include "ar.h"
|
|
#include "savestate.h"
|
|
|
|
//#define DEBUG
|
|
#ifdef DEBUG
|
|
#define write_log_debug write_log
|
|
#else
|
|
#define write_log_debug(...) do {;} while(0)
|
|
|
|
#endif
|
|
|
|
|
|
#define ARMODE_FREEZE 0 /* AR2/3 The action replay 'freeze' button has been pressed. */
|
|
#define ARMODE_BREAKPOINT_AR2 2 /* AR2: The action replay is activated via a breakpoint. */
|
|
#define ARMODE_BREAKPOINT_ACTIVATED 1
|
|
#define ARMODE_BREAKPOINT_AR3_RESET_AR2 3 /* AR2: The action replay is activated after a reset. */
|
|
/* AR3: The action replay is activated by a breakpoint. */
|
|
|
|
/* HRTMon baseaddress, can be freely changed */
|
|
#define HRTMON_BASE 0x980000
|
|
|
|
uae_u8 ar_custom[2*256];
|
|
|
|
int hrtmon_flag = ACTION_REPLAY_INACTIVE;
|
|
|
|
static uae_u8 *hrtmemory = 0;
|
|
static uae_u8 *armemory_rom = 0, *armemory_ram = 0;
|
|
|
|
static uae_u32 hrtmem_mask;
|
|
static uae_u8 *hrtmon_custom;
|
|
uae_u32 hrtmem_start, hrtmem_size;
|
|
|
|
static uae_u32 hrtmem_lget (uaecptr) REGPARAM;
|
|
static uae_u32 hrtmem_wget (uaecptr) REGPARAM;
|
|
static uae_u32 hrtmem_bget (uaecptr) REGPARAM;
|
|
static void hrtmem_lput (uaecptr, uae_u32) REGPARAM;
|
|
static void hrtmem_wput (uaecptr, uae_u32) REGPARAM;
|
|
static void hrtmem_bput (uaecptr, uae_u32) REGPARAM;
|
|
static int hrtmem_check (uaecptr addr, uae_u32 size) REGPARAM;
|
|
static uae_u8 *hrtmem_xlate (uaecptr addr) REGPARAM;
|
|
static void hrtmon_unmap_banks(void);
|
|
|
|
void check_prefs_changed_carts(int in_memory_reset);
|
|
int action_replay_unload(int in_memory_reset);
|
|
|
|
static uae_u32 REGPARAM2 hrtmem_lget (uaecptr addr)
|
|
{
|
|
uae_u32 *m;
|
|
addr -= hrtmem_start & hrtmem_mask;
|
|
addr &= hrtmem_mask;
|
|
m = (uae_u32 *)(hrtmemory + addr);
|
|
return do_get_mem_long (m);
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 hrtmem_wget (uaecptr addr)
|
|
{
|
|
uae_u16 *m;
|
|
addr -= hrtmem_start & hrtmem_mask;
|
|
addr &= hrtmem_mask;
|
|
m = (uae_u16 *)(hrtmemory + addr);
|
|
return do_get_mem_word (m);
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 hrtmem_bget (uaecptr addr)
|
|
{
|
|
addr -= hrtmem_start & hrtmem_mask;
|
|
addr &= hrtmem_mask;
|
|
return hrtmemory[addr];
|
|
}
|
|
|
|
static void REGPARAM2 hrtmem_lput (uaecptr addr, uae_u32 l)
|
|
{
|
|
uae_u32 *m;
|
|
addr -= hrtmem_start & hrtmem_mask;
|
|
addr &= hrtmem_mask;
|
|
m = (uae_u32 *)(hrtmemory + addr);
|
|
do_put_mem_long (m, l);
|
|
}
|
|
|
|
static void REGPARAM2 hrtmem_wput (uaecptr addr, uae_u32 w)
|
|
{
|
|
uae_u16 *m;
|
|
addr -= hrtmem_start & hrtmem_mask;
|
|
addr &= hrtmem_mask;
|
|
m = (uae_u16 *)(hrtmemory + addr);
|
|
do_put_mem_word (m, (uae_u16)w);
|
|
}
|
|
|
|
static void REGPARAM2 hrtmem_bput (uaecptr addr, uae_u32 b)
|
|
{
|
|
addr -= hrtmem_start & hrtmem_mask;
|
|
addr &= hrtmem_mask;
|
|
hrtmemory[addr] = b;
|
|
}
|
|
|
|
static int REGPARAM2 hrtmem_check (uaecptr addr, uae_u32 size)
|
|
{
|
|
addr -= hrtmem_start & hrtmem_mask;
|
|
addr &= hrtmem_mask;
|
|
return (addr + size) <= hrtmem_size;
|
|
}
|
|
|
|
static uae_u8 REGPARAM2 *hrtmem_xlate (uaecptr addr)
|
|
{
|
|
addr -= hrtmem_start & hrtmem_mask;
|
|
addr &= hrtmem_mask;
|
|
return hrtmemory + addr;
|
|
}
|
|
|
|
addrbank hrtmem_bank = {
|
|
hrtmem_lget, hrtmem_wget, hrtmem_bget,
|
|
hrtmem_lput, hrtmem_wput, hrtmem_bput,
|
|
hrtmem_xlate, hrtmem_check, NULL
|
|
};
|
|
|
|
static void copyfromamiga (uae_u8 *dst, uaecptr src, int len)
|
|
{
|
|
while(len--) {
|
|
*dst++ = (uae_u8) get_byte (src);
|
|
src++;
|
|
}
|
|
}
|
|
|
|
static void copytoamiga (uaecptr dst, const uae_u8 *src, int len)
|
|
{
|
|
while (len--) {
|
|
put_byte (dst, *src++);
|
|
dst++;
|
|
}
|
|
}
|
|
|
|
int action_replay_flag = ACTION_REPLAY_INACTIVE;
|
|
static int ar_rom_file_size;
|
|
|
|
/* Use this for relocating AR? */
|
|
static int ar_rom_location;
|
|
/*static*/ int armodel;
|
|
static uae_u8 artemp[4]; /* Space to store the 'real' level 7 interrupt */
|
|
static uae_u8 armode;
|
|
|
|
static uae_u32 arrom_start, arrom_size, arrom_mask;
|
|
static uae_u32 arram_start, arram_size, arram_mask;
|
|
|
|
static int ar_wait_pop = 0; /* bool used by AR1 when waiting for the program counter to exit it's ram. */
|
|
uaecptr wait_for_pc = 0; /* The program counter that we wait for. */
|
|
|
|
/* returns true if the Program counter is currently in the AR rom. */
|
|
int is_ar_pc_in_rom()
|
|
{
|
|
uaecptr pc = m68k_getpc (®s) & 0xFFFFFF;
|
|
return pc >= arrom_start && pc < arrom_start+arrom_size;
|
|
}
|
|
|
|
/* returns true if the Program counter is currently in the AR RAM. */
|
|
int is_ar_pc_in_ram()
|
|
{
|
|
uaecptr pc = m68k_getpc (®s) & 0xFFFFFF;
|
|
return pc >= arram_start && pc < arram_start+arram_size;
|
|
}
|
|
|
|
|
|
/* flag writing == 1 for writing memory, 0 for reading from memory. */
|
|
STATIC_INLINE int ar3a (uaecptr addr, uae_u8 b, int writing)
|
|
{
|
|
uaecptr pc;
|
|
/* if ( addr < 8 ) //|| writing ) */
|
|
/* { */
|
|
/* if ( writing ) */
|
|
/* write_log_debug("ARSTATUS armode:%d, Writing %d to address %p, PC=%p\n", armode, b, addr, m68k_getpc (®s)); */
|
|
/* else */
|
|
/* write_log_debug("ARSTATUS armode:%d, Reading %d from address %p, PC=%p\n", armode, armemory_rom[addr], addr, m68k_getpc (®s)); */
|
|
/* } */
|
|
|
|
if (armodel == 1 ) /* With AR1. It is always a read. Actually, it is a strobe on exit of the AR.
|
|
* but, it is also read during the checksum routine. */
|
|
{
|
|
if ( addr < 2)
|
|
{
|
|
if ( is_ar_pc_in_rom() )
|
|
{
|
|
if ( ar_wait_pop )
|
|
{
|
|
action_replay_flag = ACTION_REPLAY_WAIT_PC;
|
|
/* write_log_debug("SP %p\n", m68k_areg (®s, 7)); */
|
|
/* write_log_debug("SP+2 %p\n", m68k_areg (®s, 7)+2 ); */
|
|
/* write_log_debug("(SP+2) %p\n", longget (m68k_areg (®s,7)+2)); */
|
|
ar_wait_pop = 0;
|
|
/* We get (SP+2) here, as the first word on the stack is the status register. */
|
|
/* We want the following long, which is the return program counter. */
|
|
wait_for_pc = longget (m68k_areg (®s, 7)+2); /* Get (SP+2) */
|
|
set_special (®s, SPCFLAG_ACTION_REPLAY);
|
|
|
|
pc = m68k_getpc (®s);
|
|
/* write_log_debug("Action Replay marked as ACTION_REPLAY_WAIT_PC, PC=%p\n",pc);*/
|
|
}
|
|
else
|
|
{
|
|
uaecptr pc = m68k_getpc (®s);
|
|
/* write_log_debug("Action Replay marked as IDLE, PC=%p\n",pc);*/
|
|
action_replay_flag = ACTION_REPLAY_IDLE;
|
|
}
|
|
}
|
|
}
|
|
/* This probably violates the hide_banks thing except ar1 doesn't use that yet .*/
|
|
return armemory_rom[addr];
|
|
}
|
|
|
|
#ifdef ACTION_REPLAY_HIDE_CARTRIDGE
|
|
if (addr >= 8 )
|
|
return armemory_rom[addr];
|
|
|
|
if (action_replay_flag != ACTION_REPLAY_ACTIVE)
|
|
return 0;
|
|
#endif
|
|
|
|
if (!writing) /* reading */
|
|
{
|
|
if (addr == 1) /* This is necessary because we don't update rom location 0 every time we change armode */
|
|
return armode;
|
|
else
|
|
return armemory_rom[addr];
|
|
}
|
|
/* else, we are writing */
|
|
else if (addr == 1) {
|
|
armode = b;
|
|
if(armode >= 2)
|
|
{
|
|
if ( armode == ARMODE_BREAKPOINT_AR2 )
|
|
{
|
|
write_log("AR2: exit with breakpoint(s) active\n"); /* Correct for AR2 */
|
|
}
|
|
else if ( armode == ARMODE_BREAKPOINT_AR3_RESET_AR2 )
|
|
{
|
|
write_log("AR3: exit waiting for breakpoint.\n"); /* Correct for AR3 (waiting for breakpoint)*/
|
|
}
|
|
else
|
|
{
|
|
write_log("AR2/3: mode(%d) > 3 this shouldn't happen.\n", armode);
|
|
}
|
|
} else {
|
|
write_log("AR: exit with armode(%d)\n", armode);
|
|
}
|
|
set_special (®s, SPCFLAG_ACTION_REPLAY);
|
|
action_replay_flag = ACTION_REPLAY_HIDE;
|
|
} else if (addr == 6) {
|
|
copytoamiga (regs.vbr + 0x7c, artemp, 4);
|
|
write_log ("AR: chipmem returned\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void REGPARAM2 chipmem_lput_actionreplay1 (uaecptr addr, uae_u32 l)
|
|
{
|
|
uae_u32 *m;
|
|
addr -= chipmem_start & chipmem_mask;
|
|
addr &= chipmem_mask;
|
|
if (addr == 0x60 && !is_ar_pc_in_rom())
|
|
action_replay_chipwrite ();
|
|
m = (uae_u32 *)(chipmemory + addr);
|
|
do_put_mem_long (m, l);
|
|
}
|
|
void REGPARAM2 chipmem_wput_actionreplay1 (uaecptr addr, uae_u32 w)
|
|
{
|
|
uae_u16 *m;
|
|
|
|
addr -= chipmem_start & chipmem_mask;
|
|
addr &= chipmem_mask;
|
|
if (addr == 0x62 && !is_ar_pc_in_rom())
|
|
action_replay_chipwrite ();
|
|
m = (uae_u16 *)(chipmemory + addr);
|
|
do_put_mem_word (m, w);
|
|
}
|
|
void REGPARAM2 chipmem_bput_actionreplay1 (uaecptr addr, uae_u32 b)
|
|
{
|
|
addr -= chipmem_start & chipmem_mask;
|
|
addr &= chipmem_mask;
|
|
if (addr >= 0x60 && addr <= 0x63 && !is_ar_pc_in_rom())
|
|
action_replay_chipwrite();
|
|
chipmemory[addr] = b;
|
|
}
|
|
void REGPARAM2 chipmem_lput_actionreplay23 (uaecptr addr, uae_u32 l)
|
|
{
|
|
uae_u32 *m;
|
|
addr -= chipmem_start & chipmem_mask;
|
|
addr &= chipmem_mask;
|
|
m = (uae_u32 *)(chipmemory + addr);
|
|
do_put_mem_long (m, l);
|
|
if (addr >= 0x40 && addr < 0x200 && action_replay_flag == ACTION_REPLAY_WAITRESET)
|
|
action_replay_chipwrite();
|
|
}
|
|
void REGPARAM2 chipmem_wput_actionreplay23 (uaecptr addr, uae_u32 w)
|
|
{
|
|
uae_u16 *m;
|
|
|
|
addr -= chipmem_start & chipmem_mask;
|
|
addr &= chipmem_mask;
|
|
m = (uae_u16 *)(chipmemory + addr);
|
|
do_put_mem_word (m, w);
|
|
if (addr >= 0x40 && addr < 0x200 && action_replay_flag == ACTION_REPLAY_WAITRESET)
|
|
action_replay_chipwrite();
|
|
}
|
|
|
|
|
|
static uae_u32 arram_lget (uaecptr) REGPARAM;
|
|
static uae_u32 arram_wget (uaecptr) REGPARAM;
|
|
static uae_u32 arram_bget (uaecptr) REGPARAM;
|
|
static void arram_lput (uaecptr, uae_u32) REGPARAM;
|
|
static void arram_wput (uaecptr, uae_u32) REGPARAM;
|
|
static void arram_bput (uaecptr, uae_u32) REGPARAM;
|
|
static int arram_check (uaecptr addr, uae_u32 size) REGPARAM;
|
|
static uae_u8 *arram_xlate (uaecptr addr) REGPARAM;
|
|
|
|
static uae_u32 arrom_lget (uaecptr) REGPARAM;
|
|
static uae_u32 arrom_wget (uaecptr) REGPARAM;
|
|
static uae_u32 arrom_bget (uaecptr) REGPARAM;
|
|
static void arrom_lput (uaecptr, uae_u32) REGPARAM;
|
|
static void arrom_wput (uaecptr, uae_u32) REGPARAM;
|
|
static void arrom_bput (uaecptr, uae_u32) REGPARAM;
|
|
static int arrom_check (uaecptr addr, uae_u32 size) REGPARAM;
|
|
static uae_u8 *arrom_xlate (uaecptr addr) REGPARAM;
|
|
static void action_replay_unmap_banks(void);
|
|
|
|
static uae_u32 action_replay_calculate_checksum(void);
|
|
static uae_u8* get_checksum_location(void);
|
|
static void disable_rom_test(void);
|
|
|
|
static uae_u32 REGPARAM2 arram_lget (uaecptr addr)
|
|
{
|
|
uae_u32 *m;
|
|
#ifdef JIT
|
|
special_mem |= SPECIAL_MEM_READ;
|
|
#endif
|
|
addr -= arram_start;
|
|
addr &= arram_mask;
|
|
m = (uae_u32 *)(armemory_ram + addr);
|
|
if (strncmp("T8", (char*)m, 2) == 0)
|
|
write_log_debug("Reading T8 from addr %08.08x PC=%p\n", addr, m68k_getpc (®s));
|
|
if (strncmp("LAME", (char*)m, 4) == 0)
|
|
write_log_debug("Reading LAME from addr %08.08x PC=%p\n", addr, m68k_getpc (®s));
|
|
if (strncmp("RES1", (char*)m, 4) == 0)
|
|
write_log_debug("Reading RES1 from addr %08.08x PC=%p\n", addr, m68k_getpc (®s));
|
|
if (strncmp("ARON", (char*)m, 4) == 0)
|
|
write_log_debug("Reading ARON from addr %08.08x PC=%p\n", addr, m68k_getpc (®s));
|
|
if (strncmp("KILL", (char*)m, 4) == 0)
|
|
write_log_debug("Reading KILL from addr %08.08x PC=%p\n", addr, m68k_getpc (®s));
|
|
if (strncmp("BRON", (char*)m, 4) == 0)
|
|
write_log_debug("Reading BRON from addr %08.08x PC=%p\n", addr, m68k_getpc (®s));
|
|
if (strncmp("PRIN", (char*)m, 4) == 0)
|
|
write_log_debug("Reading PRIN from addr %08.08x PC=%p\n", addr, m68k_getpc (®s));
|
|
return do_get_mem_long (m);
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 arram_wget (uaecptr addr)
|
|
{
|
|
uae_u16 *m;
|
|
#ifdef JIT
|
|
special_mem |= SPECIAL_MEM_READ;
|
|
#endif
|
|
addr -= arram_start;
|
|
addr &= arram_mask;
|
|
m = (uae_u16 *)(armemory_ram + addr);
|
|
return do_get_mem_word (m);
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 arram_bget (uaecptr addr)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= SPECIAL_MEM_READ;
|
|
#endif
|
|
addr -= arram_start;
|
|
addr &= arram_mask;
|
|
return armemory_ram[addr];
|
|
}
|
|
|
|
void REGPARAM2 arram_lput (uaecptr addr, uae_u32 l)
|
|
{
|
|
uae_u32 *m;
|
|
|
|
addr -= arram_start;
|
|
addr &= arram_mask;
|
|
m = (uae_u32 *)(armemory_ram + addr);
|
|
if (strncmp("T8", (char*)m, 2) == 0)
|
|
write_log_debug("Writing T8 to addr %08.08x PC=%p\n", addr, m68k_getpc (®s));
|
|
if (strncmp("LAME", (char*)m, 4) == 0)
|
|
write_log_debug("Writing LAME to addr %08.08x PC=%p\n", addr, m68k_getpc (®s));
|
|
if (strncmp("RES1", (char*)m, 4) == 0)
|
|
write_log_debug("Writing RES1 to addr %08.08x PC=%p\n", addr, m68k_getpc (®s));
|
|
if (strncmp("ARON", (char*)m, 4) == 0)
|
|
write_log_debug("Writing ARON to addr %08.08x PC=%p\n", addr, m68k_getpc (®s));
|
|
if (strncmp("KILL", (char*)m, 4) == 0)
|
|
write_log_debug("Writing KILL to addr %08.08x PC=%p\n", addr, m68k_getpc (®s));
|
|
if (strncmp("BRON", (char*)m, 4) == 0)
|
|
write_log_debug("Writing BRON to addr %08.08x PC=%p\n", addr, m68k_getpc (®s));
|
|
if (strncmp("PRIN", (char*)m, 4) == 0)
|
|
write_log_debug("Writing PRIN to addr %08.08x PC=%p\n", addr, m68k_getpc (®s));
|
|
do_put_mem_long (m, l);
|
|
}
|
|
|
|
void REGPARAM2 arram_wput (uaecptr addr, uae_u32 w)
|
|
{
|
|
uae_u16 *m;
|
|
|
|
#ifdef JIT
|
|
special_mem |= SPECIAL_MEM_WRITE;
|
|
#endif
|
|
addr -= arram_start;
|
|
addr &= arram_mask;
|
|
m = (uae_u16 *)(armemory_ram + addr);
|
|
do_put_mem_word (m, w);
|
|
}
|
|
|
|
void REGPARAM2 arram_bput (uaecptr addr, uae_u32 b)
|
|
{
|
|
addr -= arram_start;
|
|
addr &= arram_mask;
|
|
armemory_ram[addr] = b;
|
|
}
|
|
|
|
static int REGPARAM2 arram_check (uaecptr addr, uae_u32 size)
|
|
{
|
|
addr -= arram_start;
|
|
addr &= arram_mask;
|
|
return (addr + size) <= arram_size;
|
|
}
|
|
|
|
static uae_u8 REGPARAM2 *arram_xlate (uaecptr addr)
|
|
{
|
|
addr -= arram_start;
|
|
addr &= arram_mask;
|
|
return armemory_ram + addr;
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 arrom_lget (uaecptr addr)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= SPECIAL_MEM_READ;
|
|
#endif
|
|
addr -= arrom_start;
|
|
addr &= arrom_mask;
|
|
return (ar3a (addr, 0, 0) << 24) | (ar3a (addr + 1, 0, 0) << 16) | (ar3a (addr + 2, 0, 0) << 8) | ar3a (addr + 3, 0, 0);
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 arrom_wget (uaecptr addr)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= SPECIAL_MEM_READ;
|
|
#endif
|
|
addr -= arrom_start;
|
|
addr &= arrom_mask;
|
|
return (ar3a (addr, 0, 0) << 8) | ar3a (addr + 1, 0, 0);
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 arrom_bget (uaecptr addr)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= SPECIAL_MEM_READ;
|
|
#endif
|
|
addr -= arrom_start;
|
|
addr &= arrom_mask;
|
|
return ar3a (addr, 0, 0);
|
|
}
|
|
|
|
static void REGPARAM2 arrom_lput (uaecptr addr, uae_u32 l)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= SPECIAL_MEM_WRITE;
|
|
#endif
|
|
addr -= arrom_start;
|
|
addr &= arrom_mask;
|
|
ar3a (addr + 0,(uae_u8)(l >> 24), 1);
|
|
ar3a (addr + 1,(uae_u8)(l >> 16), 1);
|
|
ar3a (addr + 2,(uae_u8)(l >> 8), 1);
|
|
ar3a (addr + 3,(uae_u8)(l >> 0), 1);
|
|
}
|
|
|
|
static void REGPARAM2 arrom_wput (uaecptr addr, uae_u32 w)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= SPECIAL_MEM_WRITE;
|
|
#endif
|
|
addr -= arrom_start;
|
|
addr &= arrom_mask;
|
|
ar3a (addr + 0,(uae_u8)(w >> 8), 1);
|
|
ar3a (addr + 1,(uae_u8)(w >> 0), 1);
|
|
}
|
|
|
|
static void REGPARAM2 arrom_bput (uaecptr addr, uae_u32 b)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= SPECIAL_MEM_WRITE;
|
|
#endif
|
|
addr -= arrom_start;
|
|
addr &= arrom_mask;
|
|
ar3a (addr, b, 1);
|
|
}
|
|
|
|
static int REGPARAM2 arrom_check (uaecptr addr, uae_u32 size)
|
|
{
|
|
addr -= arrom_start;
|
|
addr &= arrom_mask;
|
|
return (addr + size) <= arrom_size;
|
|
}
|
|
|
|
static uae_u8 REGPARAM2 *arrom_xlate (uaecptr addr)
|
|
{
|
|
addr -= arrom_start;
|
|
addr &= arrom_mask;
|
|
return armemory_rom + addr;
|
|
}
|
|
|
|
static addrbank arrom_bank = {
|
|
arrom_lget, arrom_wget, arrom_bget,
|
|
arrom_lput, arrom_wput, arrom_bput,
|
|
arrom_xlate, arrom_check, NULL
|
|
};
|
|
static addrbank arram_bank = {
|
|
arram_lget, arram_wget, arram_bget,
|
|
arram_lput, arram_wput, arram_bput,
|
|
arram_xlate, arram_check, NULL
|
|
};
|
|
|
|
static void action_replay_unmap_banks()
|
|
{
|
|
if(!armemory_rom)
|
|
return;
|
|
|
|
map_banks (&dummy_bank, arrom_start >> 16 , arrom_size >> 16, 0);
|
|
map_banks (&dummy_bank, arram_start >> 16 , arram_size >> 16, 0);
|
|
}
|
|
|
|
void action_replay_map_banks()
|
|
{
|
|
if(!armemory_rom)
|
|
return;
|
|
|
|
map_banks (&arrom_bank, arrom_start >> 16, arrom_size >> 16, 0);
|
|
map_banks (&arram_bank, arram_start >> 16, arram_size >> 16, 0);
|
|
}
|
|
|
|
static void hide_cart(int hide)
|
|
{
|
|
#ifdef ACTION_REPLAY_HIDE_CARTRIDGE
|
|
if(hide) {
|
|
action_replay_unmap_banks();
|
|
} else {
|
|
action_replay_map_banks();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*extern void Interrupt (int nr);*/
|
|
|
|
/* Cartridge activates itself by overlaying its rom
|
|
* over chip-ram and then issuing IRQ 7
|
|
*
|
|
* I just copy IRQ vector 7 from ROM to chip RAM
|
|
* instead of fully emulating cartridge's behaviour.
|
|
*/
|
|
|
|
static void action_replay_go (void)
|
|
{
|
|
hide_cart (0);
|
|
memcpy (armemory_ram + 0xf000, ar_custom, 2 * 256);
|
|
action_replay_flag = ACTION_REPLAY_ACTIVE;
|
|
set_special (®s, SPCFLAG_ACTION_REPLAY);
|
|
copyfromamiga (artemp, regs.vbr + 0x7c, 4);
|
|
copytoamiga (regs.vbr + 0x7c, armemory_rom + 0x7c, 4);
|
|
Interrupt (7);
|
|
}
|
|
|
|
static void action_replay_go1 (int irq)
|
|
{
|
|
hide_cart (0);
|
|
action_replay_flag = ACTION_REPLAY_ACTIVE;
|
|
|
|
memcpy (armemory_ram + 0xf000, ar_custom, 2 * 256);
|
|
Interrupt (7);
|
|
}
|
|
|
|
static void hrtmon_go (int mode)
|
|
{
|
|
memcpy (hrtmon_custom, ar_custom, 2 * 256);
|
|
hrtmon_flag = ACTION_REPLAY_ACTIVE;
|
|
set_special (®s, SPCFLAG_ACTION_REPLAY);
|
|
put_long (regs.vbr + 0x7c, hrtmem_start + 8 + (mode ? 4 : 0));
|
|
Interrupt (7);
|
|
}
|
|
|
|
void hrtmon_enter (void)
|
|
{
|
|
if (!hrtmemory) return;
|
|
write_log("HRTMON: freeze\n");
|
|
hrtmon_go(1);
|
|
}
|
|
|
|
void action_replay_enter(void)
|
|
{
|
|
if (!armemory_rom) return;
|
|
if (armodel == 1) {
|
|
write_log("AR1: Enter PC:%p\n", m68k_getpc (®s));
|
|
action_replay_go1 (7);
|
|
unset_special (®s, SPCFLAG_ACTION_REPLAY);
|
|
return;
|
|
}
|
|
if (action_replay_flag == ACTION_REPLAY_DORESET) {
|
|
write_log("AR2/3: reset\n");
|
|
armode = ARMODE_BREAKPOINT_AR3_RESET_AR2;
|
|
}
|
|
else if (armode == ARMODE_FREEZE) {
|
|
write_log("AR2/3: activated (freeze)\n");
|
|
}
|
|
else if (armode >= 2)
|
|
{
|
|
if ( armode == ARMODE_BREAKPOINT_AR2 )
|
|
{
|
|
write_log("AR2: activated (breakpoint)\n");
|
|
}
|
|
else if ( armode == ARMODE_BREAKPOINT_AR3_RESET_AR2 )
|
|
{
|
|
write_log("AR3: activated (breakpoint)\n");
|
|
}
|
|
else
|
|
{
|
|
write_log("AR2/3: mode(%d) > 3 this shouldn't happen.\n", armode);
|
|
}
|
|
armode = ARMODE_BREAKPOINT_ACTIVATED;
|
|
}
|
|
action_replay_go();
|
|
}
|
|
|
|
void check_prefs_changed_carts(int in_memory_reset)
|
|
{
|
|
if (strcmp (currprefs.cartfile, changed_prefs.cartfile) != 0)
|
|
{
|
|
write_log("Cartridge ROM Prefs changed.\n");
|
|
if (action_replay_unload(in_memory_reset))
|
|
{
|
|
memcpy (currprefs.cartfile, changed_prefs.cartfile, sizeof currprefs.cartfile);
|
|
#ifdef ACTION_REPLAY
|
|
action_replay_load();
|
|
action_replay_init(1);
|
|
#endif
|
|
#ifdef ACTION_REPLAY_HRTMON
|
|
hrtmon_load(1);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void action_replay_reset(void)
|
|
{
|
|
if (action_replay_flag == ACTION_REPLAY_INACTIVE)
|
|
return;
|
|
write_log_debug("action_replay_reset()\n");
|
|
|
|
if (savestate_state == STATE_RESTORE) {
|
|
if (regs.pc >= arrom_start && regs.pc <= arrom_start + arrom_size) {
|
|
action_replay_flag = ACTION_REPLAY_ACTIVE;
|
|
hide_cart (0);
|
|
} else {
|
|
action_replay_flag = ACTION_REPLAY_IDLE;
|
|
hide_cart (1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (armodel == 1 )
|
|
{
|
|
/* We need to mark it as active here, because the kickstart rom jumps directly into it. */
|
|
action_replay_flag = ACTION_REPLAY_ACTIVE;
|
|
}
|
|
else
|
|
{
|
|
write_log_debug("Setting flag to ACTION_REPLAY_WAITRESET\n");
|
|
write_log_debug("armode == %d\n", armode);
|
|
action_replay_flag = ACTION_REPLAY_WAITRESET;
|
|
}
|
|
}
|
|
|
|
void action_replay_ciaread(void)
|
|
{
|
|
if (armodel < 2)
|
|
return;
|
|
if (action_replay_flag != ACTION_REPLAY_IDLE) return;
|
|
if (action_replay_flag == ACTION_REPLAY_INACTIVE) return;
|
|
if (armode < 2) /* If there are no active breakpoints*/ return;
|
|
if (m68k_getpc (®s) >= 0x200) return;
|
|
action_replay_flag = ACTION_REPLAY_ACTIVATE;
|
|
set_special (®s, SPCFLAG_ACTION_REPLAY);
|
|
}
|
|
|
|
int action_replay_freeze(void)
|
|
{
|
|
if(action_replay_flag == ACTION_REPLAY_IDLE)
|
|
{
|
|
if (armodel == 1)
|
|
{
|
|
action_replay_chipwrite();
|
|
}
|
|
else
|
|
{
|
|
action_replay_flag = ACTION_REPLAY_ACTIVATE;
|
|
set_special (®s, SPCFLAG_ACTION_REPLAY);
|
|
armode = ARMODE_FREEZE;
|
|
}
|
|
return 1;
|
|
} else if(hrtmon_flag == ACTION_REPLAY_IDLE) {
|
|
hrtmon_flag = ACTION_REPLAY_ACTIVATE;
|
|
set_special (®s, SPCFLAG_ACTION_REPLAY);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void action_replay_chipwrite(void)
|
|
{
|
|
if (armodel > 1)
|
|
{
|
|
action_replay_flag = ACTION_REPLAY_DORESET;
|
|
set_special (®s, SPCFLAG_ACTION_REPLAY);
|
|
}
|
|
else
|
|
{
|
|
/* copy 0x60 addr info to level 7 */
|
|
/* This is to emulate the 0x60 interrupt. */
|
|
copyfromamiga (artemp, regs.vbr + 0x60, 4);
|
|
copytoamiga (regs.vbr + 0x7c, artemp, 4);
|
|
ar_wait_pop = 1; /* Wait for stack to pop. */
|
|
|
|
action_replay_flag = ACTION_REPLAY_ACTIVATE;
|
|
set_special (®s, SPCFLAG_ACTION_REPLAY);
|
|
}
|
|
}
|
|
|
|
void action_replay_hide(void)
|
|
{
|
|
hide_cart(1);
|
|
action_replay_flag = ACTION_REPLAY_IDLE;
|
|
}
|
|
|
|
void hrtmon_hide(void)
|
|
{
|
|
hrtmon_flag = ACTION_REPLAY_IDLE;
|
|
/* write_log_debug("HRTMON: exit\n"); */
|
|
}
|
|
|
|
void hrtmon_breakenter(void)
|
|
{
|
|
hrtmon_flag = ACTION_REPLAY_HIDE;
|
|
set_special (®s, SPCFLAG_ACTION_REPLAY);
|
|
/* write_log_debug("HRTMON: In hrtmon routine.\n"); */
|
|
}
|
|
|
|
|
|
/* Disabling copperlist processing:
|
|
* On: ar317 an rts at 41084c does it.
|
|
* On: ar214: an rts at 41068e does it.
|
|
*/
|
|
|
|
|
|
/* Original AR3 only works with KS 1.3
|
|
* this patch fixes that problem.
|
|
*/
|
|
|
|
static uae_u8 ar3patch1[]={0x20,0xc9,0x51,0xc9,0xff,0xfc};
|
|
static uae_u8 ar3patch2[]={0x00,0xfc,0x01,0x44};
|
|
|
|
static void action_replay_patch(void)
|
|
{
|
|
unsigned int off1,off2;
|
|
uae_u8 *kickmem = kickmemory;
|
|
|
|
if (armodel != 3 || !kickmem)
|
|
return;
|
|
if (!memcmp (kickmem, kickmem + 262144, 262144)) off1 = 262144; else off1 = 0;
|
|
for (;;) {
|
|
if (!memcmp (kickmem + off1, ar3patch1, sizeof (ar3patch1)) || off1 == 524288 - sizeof (ar3patch1)) break;
|
|
off1++;
|
|
}
|
|
off2 = 0;
|
|
for(;;) {
|
|
if (!memcmp (armemory_rom + off2, ar3patch2, sizeof(ar3patch2)) || off2 == ar_rom_file_size - sizeof (ar3patch2)) break;
|
|
off2++;
|
|
}
|
|
if (off1 == 524288 - sizeof (ar3patch1) || off2 == ar_rom_file_size - sizeof (ar3patch2))
|
|
return;
|
|
armemory_rom[off2 + 0] = (uae_u8)((off1 + kickmem_start + 2) >> 24);
|
|
armemory_rom[off2 + 1] = (uae_u8)((off1 + kickmem_start + 2) >> 16);
|
|
armemory_rom[off2 + 2] = (uae_u8)((off1 + kickmem_start + 2) >> 8);
|
|
armemory_rom[off2 + 3] = (uae_u8)((off1 + kickmem_start + 2) >> 0);
|
|
write_log ("AR ROM patched for KS2.0+\n");
|
|
}
|
|
|
|
/* Returns 0 if the checksum is OK.
|
|
* Else, it returns the calculated checksum.
|
|
* Note: Will be wrong if the checksum is zero, but i'll take my chances on that not happenning ;)
|
|
*/
|
|
static uae_u32 action_replay_calculate_checksum()
|
|
{
|
|
uae_u32* checksum_end;
|
|
uae_u32* checksum_start;
|
|
uae_u8 checksum_start_offset[] = {0, 0, 4, 0x7c};
|
|
uae_u32 checksum = 0;
|
|
uae_u32 stored_checksum;
|
|
|
|
/* All models: The checksum is calculated right upto the long checksum in the rom.
|
|
* AR1: The checksum starts at offset 0.
|
|
* AR1: The checksum is the last non-zero long in the rom.
|
|
* AR2: The checksum starts at offset 4.
|
|
* AR2: The checksum is the last Long in the rom.
|
|
* AR3: The checksum starts at offset 0x7c.
|
|
* AR3: The checksum is the last Long in the rom.
|
|
*
|
|
* Checksums: (This is a good way to compare roms. I have two with different md5sums,
|
|
* but the same checksum, so the difference must be in the first four bytes.)
|
|
* 3.17 0xf009bfc9
|
|
* 3.09 0xd34d04a7
|
|
* 2.14 0xad839d36
|
|
* 2.14 0xad839d36
|
|
* 1.15 0xee12116
|
|
*/
|
|
|
|
if (!armemory_rom)
|
|
return 0; /* If there is no rom then i guess the checksum is ok */
|
|
|
|
checksum_start = (uae_u32*)&armemory_rom[checksum_start_offset[armodel]];
|
|
checksum_end = (uae_u32*)&armemory_rom[ar_rom_file_size];
|
|
|
|
/* Search for first non-zero Long starting from the end of the rom. */
|
|
/* Assume long alignment, (will always be true for AR2 and AR3 and the AR1 rom i've got). */
|
|
/* If anyone finds an AR1 rom with a word-aligned checksum, then this code will have to be modified. */
|
|
while (! *(--checksum_end) );
|
|
|
|
if ( armodel == 1)
|
|
{
|
|
uae_u16* rom_ptr_word;
|
|
uae_s16 sign_extended_word;
|
|
|
|
rom_ptr_word = (uae_u16*)checksum_start;
|
|
while ( rom_ptr_word != (uae_u16*)checksum_end )
|
|
{
|
|
sign_extended_word = (uae_s16)do_get_mem_word (rom_ptr_word);
|
|
/* When the word is cast on the following line, it will get sign-extended. */
|
|
checksum += (uae_u32)sign_extended_word;
|
|
rom_ptr_word++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uae_u32* rom_ptr_long;
|
|
|
|
rom_ptr_long = checksum_start;
|
|
while ( rom_ptr_long != checksum_end )
|
|
{
|
|
checksum += do_get_mem_long (rom_ptr_long);
|
|
rom_ptr_long++;
|
|
}
|
|
}
|
|
|
|
stored_checksum = do_get_mem_long(checksum_end);
|
|
|
|
return checksum == stored_checksum ? 0 : checksum;
|
|
}
|
|
|
|
/* Returns 0 on error. */
|
|
static uae_u8* get_checksum_location()
|
|
{
|
|
uae_u32* checksum_end;
|
|
|
|
/* See action_replay_calculate_checksum() for checksum info. */
|
|
|
|
if (!armemory_rom)
|
|
return 0;
|
|
|
|
checksum_end = (uae_u32*)&armemory_rom[ar_rom_file_size];
|
|
|
|
/* Search for first non-zero Long starting from the end of the rom. */
|
|
while (! *(--checksum_end) );
|
|
|
|
return (uae_u8*)checksum_end;
|
|
}
|
|
|
|
|
|
/* Replaces the existing cart checksum with a correct one. */
|
|
/* Useful if you want to patch the rom. */
|
|
static void action_replay_fixup_checksum(uae_u32 new_checksum)
|
|
{
|
|
uae_u32* checksum = (uae_u32*)get_checksum_location();
|
|
if ( checksum )
|
|
{
|
|
do_put_mem_long(checksum, new_checksum);
|
|
}
|
|
else
|
|
{
|
|
write_log("Unable to locate Checksum in ROM.\n");
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* Longword search on word boundary
|
|
* the search_value is assumed to already be in the local endian format
|
|
* return 0 on failure
|
|
*/
|
|
static uae_u8* find_absolute_long(uae_u8* start_addr, uae_u8* end_addr, uae_u32 search_value)
|
|
{
|
|
uae_u8* addr;
|
|
|
|
for ( addr = start_addr; addr < end_addr; )
|
|
{
|
|
if ( do_get_mem_long((uae_u32*)addr) == search_value )
|
|
{
|
|
/* write_log_debug("Found %p at offset %p.\n", search_value, addr - start_addr);*/
|
|
return addr;
|
|
}
|
|
addr+=2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* word search on word boundary
|
|
* the search_addr is assumed to already be in the local endian format
|
|
* return 0 on failure
|
|
* Currently only tested where the address we are looking for is AFTER the instruction.
|
|
* Not sure it works with negative offsets.
|
|
*/
|
|
static uae_u8* find_relative_word(uae_u8* start_addr, uae_u8* end_addr, uae_u16 search_addr)
|
|
{
|
|
uae_u8* addr;
|
|
|
|
for ( addr = start_addr; addr < end_addr; )
|
|
{
|
|
if ( do_get_mem_word((uae_u16*)addr) == (uae_u16)(search_addr - (uae_u16)(addr-start_addr)) )
|
|
{
|
|
/* write_log_debug("Found %p at offset %p.\n", search_addr, addr - start_addr);*/
|
|
return addr;
|
|
}
|
|
addr+=2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Disable rom test */
|
|
/* This routine replaces the rom-test routine with a 'rts'.
|
|
* It does this in a 'safe' way, by searching for a reference to the checksum
|
|
* and only disables it if the surounding bytes are what it expects.
|
|
*/
|
|
|
|
static void disable_rom_test()
|
|
{
|
|
uae_u8* addr;
|
|
|
|
uae_u8* start_addr = armemory_rom;
|
|
uae_u8* end_addr = get_checksum_location();
|
|
|
|
/*
|
|
* To see what the routine below is doing. Here is some code from the Action replay rom where it does the
|
|
* checksum test.
|
|
* AR1:
|
|
* F0D4D0 6100 ???? bsr.w calc_checksum ; calculate the checksum
|
|
* F0D4D4 41FA 147A lea (0xf0e950,PC),a0 ; load the existing checksum.
|
|
* ; do a comparison.
|
|
* AR2:
|
|
* 40EC92 6100 ???? bsr.w calc_checksum
|
|
* 40EC96 41F9 0041 FFFC lea (0x41fffc),a0
|
|
*/
|
|
|
|
if ( armodel == 1)
|
|
{
|
|
uae_u16 search_value_rel = end_addr - start_addr;
|
|
addr = find_relative_word(start_addr, end_addr, search_value_rel);
|
|
|
|
if ( addr )
|
|
{
|
|
if ( do_get_mem_word((uae_u16*)(addr-6)) == 0x6100 && /* bsr.w */
|
|
do_get_mem_word((uae_u16*)(addr-2)) == 0x41fa ) /* lea relative */
|
|
{
|
|
write_log("Patching to disable ROM TEST.\n");
|
|
do_put_mem_word((uae_u16*)(addr-6), 0x4e75); /* rts */
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uae_u32 search_value_abs = arrom_start + end_addr - start_addr;
|
|
addr = find_absolute_long(start_addr, end_addr, search_value_abs);
|
|
|
|
if ( addr )
|
|
{
|
|
if ( do_get_mem_word((uae_u16*)(addr-6)) == 0x6100 && /* bsr.w */
|
|
do_get_mem_word((uae_u16*)(addr-2)) == 0x41f9 ) /* lea absolute */
|
|
{
|
|
write_log("Patching to disable ROM TEST.\n");
|
|
do_put_mem_word((uae_u16*)(addr-6), 0x4e75); /* rts */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* After we have calculated the checksum, and verified the rom is ok,
|
|
* we can do two things.
|
|
* 1. (optionally)Patch it and then update the checksum.
|
|
* 2. Remove the checksum check and (optionally) patch it.
|
|
* I have chosen to use no.2 here, because it should speed up the Action Replay slightly (and it was fun).
|
|
*/
|
|
static void action_replay_checksum_info(void)
|
|
{
|
|
if (!armemory_rom)
|
|
return;
|
|
if ( action_replay_calculate_checksum() == 0 )
|
|
{
|
|
write_log("Action Replay Checksum is OK.\n");
|
|
}
|
|
else
|
|
{
|
|
write_log("Action Replay Checksum is INVALID.\n");
|
|
}
|
|
disable_rom_test();
|
|
}
|
|
|
|
|
|
|
|
static void action_replay_setbanks (void)
|
|
{
|
|
if (!savestate_state && chipmem_bank.lput == chipmem_lput) {
|
|
switch (armodel)
|
|
{
|
|
case 2:
|
|
case 3:
|
|
if (currprefs.cpu_cycle_exact)
|
|
chipmem_bank.wput = chipmem_wput_actionreplay23;
|
|
chipmem_bank.lput = chipmem_lput_actionreplay23;
|
|
break;
|
|
case 1:
|
|
chipmem_bank.bput = chipmem_bput_actionreplay1;
|
|
chipmem_bank.wput = chipmem_wput_actionreplay1;
|
|
chipmem_bank.lput = chipmem_lput_actionreplay1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void action_replay_unsetbanks (void)
|
|
{
|
|
chipmem_bank.bput = chipmem_bput;
|
|
chipmem_bank.wput = chipmem_wput;
|
|
chipmem_bank.lput = chipmem_lput;
|
|
}
|
|
|
|
/* param to allow us to unload the cart. Currently we know it is safe if we are doing a reset to unload it.*/
|
|
int action_replay_unload(int in_memory_reset)
|
|
{
|
|
static const char *state[] =
|
|
{
|
|
"ACTION_REPLAY_WAIT_PC",
|
|
"ACTION_REPLAY_INACTIVE",
|
|
"ACTION_REPLAY_WAITRESET",
|
|
"0",
|
|
"ACTION_REPLAY_IDLE",
|
|
"ACTION_REPLAY_ACTIVATE",
|
|
"ACTION_REPLAY_ACTIVE",
|
|
"ACTION_REPLAY_DORESET",
|
|
"ACTION_REPLAY_HIDE",
|
|
};
|
|
|
|
write_log_debug("Action Replay State:(%s) Hrtmon State:(%s)\n", state[action_replay_flag+3],state[hrtmon_flag+3] );
|
|
|
|
if ( armemory_rom && armodel == 1 )
|
|
{
|
|
if ( is_ar_pc_in_ram() || is_ar_pc_in_rom() || action_replay_flag == ACTION_REPLAY_WAIT_PC )
|
|
{
|
|
write_log("Can't Unload Action Replay 1. It is Active.\n");
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( action_replay_flag != ACTION_REPLAY_IDLE && action_replay_flag != ACTION_REPLAY_INACTIVE )
|
|
{
|
|
write_log("Can't Unload Action Replay. It is Active.\n");
|
|
return 0; /* Don't unload it whilst it's active, or it will crash the amiga if not the emulator */
|
|
}
|
|
if ( hrtmon_flag != ACTION_REPLAY_IDLE && hrtmon_flag != ACTION_REPLAY_INACTIVE )
|
|
{
|
|
write_log("Can't Unload Hrtmon. It is Active.\n");
|
|
return 0; /* Don't unload it whilst it's active, or it will crash the amiga if not the emulator */
|
|
}
|
|
}
|
|
|
|
unset_special (®s, SPCFLAG_ACTION_REPLAY); /* This shouldn't be necessary here, but just in case. */
|
|
action_replay_flag = ACTION_REPLAY_INACTIVE;
|
|
hrtmon_flag = ACTION_REPLAY_INACTIVE;
|
|
action_replay_unsetbanks();
|
|
action_replay_unmap_banks();
|
|
hrtmon_unmap_banks();
|
|
/* Make sure you unmap everything before you call action_replay_cleanup() */
|
|
action_replay_cleanup();
|
|
return 1;
|
|
}
|
|
|
|
|
|
int action_replay_load(void)
|
|
{
|
|
struct zfile *f;
|
|
|
|
armodel = 0;
|
|
action_replay_flag = ACTION_REPLAY_INACTIVE;
|
|
write_log_debug("Entered action_replay_load()\n");
|
|
/* Don't load a rom if one is already loaded. Use action_replay_unload() first. */
|
|
if (armemory_rom || hrtmemory)
|
|
{
|
|
write_log("action_replay_load() ROM already loaded.\n");
|
|
return 0;
|
|
}
|
|
|
|
if (strlen(currprefs.cartfile) == 0)
|
|
return 0;
|
|
f = zfile_fopen(currprefs.cartfile,"rb");
|
|
if (!f) {
|
|
write_log("failed to load '%s' Action Replay ROM\n", currprefs.cartfile);
|
|
return 0;
|
|
}
|
|
zfile_fseek(f, 0, SEEK_END);
|
|
ar_rom_file_size = zfile_ftell(f);
|
|
zfile_fseek(f, 0, SEEK_SET);
|
|
if (ar_rom_file_size != 65536 && ar_rom_file_size != 131072 && ar_rom_file_size != 262144) {
|
|
write_log("rom size must be 64KB (AR1), 128KB (AR2) or 256KB (AR3)\n");
|
|
zfile_fclose(f);
|
|
return 0;
|
|
}
|
|
action_replay_flag = ACTION_REPLAY_INACTIVE;
|
|
armemory_rom = xmalloc (ar_rom_file_size);
|
|
zfile_fread (armemory_rom, ar_rom_file_size, 1, f);
|
|
zfile_fclose (f);
|
|
if (ar_rom_file_size == 65536) {
|
|
armodel = 1;
|
|
arrom_start = 0xf00000;
|
|
arrom_size = 0x10000;
|
|
/* real AR1 RAM location is 0x9fc000-0x9fffff */
|
|
arram_start = 0x9f0000;
|
|
arram_size = 0x10000;
|
|
} else {
|
|
armodel = ar_rom_file_size / 131072 + 1;
|
|
arrom_start = 0x400000;
|
|
arrom_size = armodel == 2 ? 0x20000 : 0x40000;
|
|
arram_start = 0x440000;
|
|
arram_size = 0x10000;
|
|
}
|
|
arram_mask = arram_size - 1;
|
|
arrom_mask = arrom_size - 1;
|
|
armemory_ram = xcalloc (arram_size, 1);
|
|
write_log("Action Replay %d installed at %08.8X, size %08.8X\n", armodel, arrom_start, arrom_size);
|
|
action_replay_setbanks ();
|
|
action_replay_version();
|
|
return armodel;
|
|
}
|
|
|
|
void action_replay_init (int activate)
|
|
{
|
|
if (!armemory_rom)
|
|
return;
|
|
hide_cart (0);
|
|
if (armodel > 1)
|
|
hide_cart (1);
|
|
if (activate) {
|
|
if (armodel > 1)
|
|
action_replay_flag = ACTION_REPLAY_WAITRESET;
|
|
}
|
|
}
|
|
|
|
/* This only deallocates memory, it is not suitable for unloading roms and continuing */
|
|
void action_replay_cleanup()
|
|
{
|
|
if (armemory_rom)
|
|
free (armemory_rom);
|
|
if (armemory_ram)
|
|
free (armemory_ram);
|
|
if (hrtmemory)
|
|
free (hrtmemory);
|
|
|
|
armemory_rom = 0;
|
|
armemory_ram = 0;
|
|
hrtmemory = 0;
|
|
}
|
|
|
|
#ifndef FALSE
|
|
#define FALSE 0
|
|
#endif
|
|
#ifndef TRUE
|
|
#define TRUE 1
|
|
#endif
|
|
|
|
typedef struct {
|
|
char jmps[20];
|
|
unsigned int mon_size;
|
|
unsigned short col0, col1;
|
|
char right;
|
|
char keyboard;
|
|
char key;
|
|
char ide;
|
|
char a1200;
|
|
char aga;
|
|
char insert;
|
|
char delay;
|
|
char lview;
|
|
char cd32;
|
|
char screenmode;
|
|
char vbr;
|
|
char entered;
|
|
char hexmode;
|
|
unsigned short error_sr;
|
|
unsigned int error_pc;
|
|
unsigned short error_status;
|
|
char newid[6];
|
|
unsigned short mon_version;
|
|
unsigned short mon_revision;
|
|
unsigned int whd_base;
|
|
unsigned short whd_version;
|
|
unsigned short whd_revision;
|
|
unsigned int max_chip;
|
|
unsigned int custom;
|
|
} HRTCFG;
|
|
|
|
static void hrtmon_configure(HRTCFG *cfg)
|
|
{
|
|
do_put_mem_word(&cfg->col0,0x000);
|
|
do_put_mem_word(&cfg->col1,0xeee);
|
|
cfg->right = 0;
|
|
cfg->key = FALSE;
|
|
cfg->ide = 0;
|
|
cfg->a1200 = 0;
|
|
cfg->aga = (currprefs.chipset_mask & 4) ? 1 : 0;
|
|
cfg->insert = TRUE;
|
|
cfg->delay = 15;
|
|
cfg->lview = FALSE;
|
|
cfg->cd32 = 0;
|
|
cfg->screenmode = 0;
|
|
cfg->vbr = TRUE;
|
|
cfg->hexmode = FALSE;
|
|
cfg->mon_size=0;
|
|
cfg->hexmode = TRUE;
|
|
do_put_mem_long(&cfg->max_chip,currprefs.chipmem_size);
|
|
hrtmon_custom = do_get_mem_long ((uae_u32*)&cfg->custom)+hrtmemory;
|
|
}
|
|
|
|
static void hrtmon_reloc (uae_u32 *mem, uae_u32 *header)
|
|
{
|
|
uae_u32 *p;
|
|
uae_u8 *base;
|
|
uae_u32 len, i;
|
|
|
|
len = do_get_mem_long (header + 7); /* Get length of file from exe header.*/
|
|
p = mem + len + 3;
|
|
len = do_get_mem_long (p - 2);
|
|
for (i = 0; i < len; i++) {
|
|
base = (uae_u8 *)((unsigned long)do_get_mem_long (p) + (unsigned long)mem);
|
|
do_put_mem_long ((uae_u32*)base, do_get_mem_long ((uae_u32 *)base) + hrtmem_start);
|
|
p++;
|
|
}
|
|
}
|
|
|
|
static uae_u8 hrt_header[] = {
|
|
0x0, 0x0, 0x3, 0xf3,
|
|
0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x1,
|
|
0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0,
|
|
0x0
|
|
};
|
|
|
|
int hrtmon_load(int activate)
|
|
{
|
|
struct zfile *f;
|
|
int size;
|
|
uae_u32 header[8];
|
|
uae_u32 id_string[2];
|
|
|
|
/* Don't load a rom if one is already loaded. Use action_replay_unload() first. */
|
|
if (armemory_rom)
|
|
return 0;
|
|
if (hrtmemory)
|
|
return 0;
|
|
|
|
armodel = 0;
|
|
if (strlen(currprefs.cartfile) == 0)
|
|
return 0;
|
|
f=zfile_fopen(currprefs.cartfile,"rb");
|
|
if(!f) {
|
|
write_log("failed to load '%s' HRTMon ROM\n", currprefs.cartfile);
|
|
return 0;
|
|
}
|
|
zfile_fseek(f,0,SEEK_END);
|
|
size = zfile_ftell(f) - 8*4;
|
|
zfile_fseek(f,0,SEEK_SET);
|
|
if ( size < (int)(sizeof(header)+sizeof(id_string)) )
|
|
{
|
|
write_log("Not a Hrtmon Rom.\n");
|
|
zfile_fclose (f);
|
|
return 0;
|
|
}
|
|
zfile_fread(header,sizeof(header),1,f);
|
|
|
|
/* Check the header */
|
|
/* uae_u8* ptr = (uae_u8*)&header; */
|
|
/* for ( ; ptr < sizeof(header); ptr++) */
|
|
/* { */
|
|
/* if ( *ptr != *header */
|
|
|
|
zfile_fread(id_string,sizeof(id_string),1,f);
|
|
if (strncmp((char*)&id_string[1], "HRT!",4) != 0 )
|
|
{
|
|
write_log("Not a Hrtmon Rom\n");
|
|
zfile_fclose (f);
|
|
return 0;
|
|
}
|
|
zfile_fseek(f,sizeof(header),SEEK_SET);
|
|
|
|
hrtmem_size = size;
|
|
hrtmem_size += 65535;
|
|
hrtmem_size &= ~65535;
|
|
hrtmem_mask = hrtmem_size - 1;
|
|
hrtmem_start = HRTMON_BASE;
|
|
hrtmemory = xmalloc (hrtmem_size);
|
|
zfile_fread (hrtmemory,size,1,f);
|
|
zfile_fclose (f);
|
|
hrtmon_configure((HRTCFG*)hrtmemory);
|
|
hrtmon_reloc((uae_u32*)hrtmemory,/*(uae_u32*)*/header);
|
|
hrtmem_bank.baseaddr = hrtmemory;
|
|
hrtmon_flag = ACTION_REPLAY_IDLE;
|
|
if(!activate) hrtmon_flag = ACTION_REPLAY_INACTIVE;
|
|
write_log("HRTMon installed at %08.8X, size %08.8X\n",hrtmem_start, hrtmem_size);
|
|
return 1;
|
|
}
|
|
|
|
void hrtmon_map_banks()
|
|
{
|
|
if(!hrtmemory)
|
|
return;
|
|
|
|
map_banks (&hrtmem_bank, hrtmem_start >> 16, hrtmem_size >> 16, hrtmem_size);
|
|
}
|
|
|
|
static void hrtmon_unmap_banks()
|
|
{
|
|
if(!hrtmemory)
|
|
return;
|
|
|
|
map_banks (&dummy_bank, hrtmem_start >> 16, hrtmem_size >> 16, hrtmem_size);
|
|
}
|
|
|
|
|
|
|
|
#define AR_VER_STR_OFFSET 0x4 /* offset in the rom where the version string begins. */
|
|
#define AR_VER_STR_END 0x7c /* offset in the rom where the version string ends. */
|
|
#define AR_VER_STR_LEN (AR_VER_STR_END - AR_VER_STR_OFFSET)
|
|
char arVersionString[AR_VER_STR_LEN+1];
|
|
|
|
/* This function extracts the version info for AR2 and AR3. */
|
|
|
|
void action_replay_version()
|
|
{
|
|
char* tmp;
|
|
int iArVersionMajor = -1 ;
|
|
int iArVersionMinor = -1;
|
|
char* pNext;
|
|
char sArDate[11];
|
|
*sArDate = '\0';
|
|
|
|
if (!armemory_rom)
|
|
return;
|
|
|
|
if ( armodel == 1 )
|
|
return; /* no support yet. */
|
|
|
|
/* Extract Version string */
|
|
memcpy(arVersionString, armemory_rom+AR_VER_STR_OFFSET, AR_VER_STR_LEN);
|
|
arVersionString[AR_VER_STR_LEN]= '\0';
|
|
tmp = strchr(arVersionString, 0x0d);
|
|
if ( tmp )
|
|
{
|
|
*tmp = '\0';
|
|
}
|
|
/* write_log_debug("Version string is : '%s'\n", arVersionString); */
|
|
|
|
tmp = strchr(arVersionString,')');
|
|
if ( tmp )
|
|
{
|
|
*tmp = '\0';
|
|
tmp = strchr(arVersionString, '(');
|
|
if ( tmp )
|
|
{
|
|
if ( *(tmp + 1 ) == 'V' )
|
|
{
|
|
pNext = tmp + 2;
|
|
tmp = strchr(pNext, '.');
|
|
if ( tmp )
|
|
{
|
|
*tmp = '\0';
|
|
iArVersionMajor = atoi(pNext);
|
|
pNext = tmp+1;
|
|
tmp = strchr(pNext, ' ');
|
|
if ( tmp )
|
|
{
|
|
*tmp = '\0';
|
|
iArVersionMinor = atoi(pNext);
|
|
}
|
|
pNext = tmp+1;
|
|
strcpy(sArDate, pNext);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( iArVersionMajor > 0 )
|
|
{
|
|
write_log("Version of cart is '%d.%.02d', date is '%s'\n", iArVersionMajor, iArVersionMinor, sArDate);
|
|
}
|
|
}
|
|
|
|
/* This function doesn't reset the Cart memory, it is just called during a memory reset */
|
|
void action_replay_memory_reset(void)
|
|
{
|
|
#ifdef ACTION_REPLAY
|
|
if ( armemory_rom )
|
|
{
|
|
action_replay_hide();
|
|
}
|
|
#endif
|
|
#ifdef ACTION_REPLAY_HRTMON
|
|
if ( hrtmemory )
|
|
{
|
|
hrtmon_hide(); /* It is never really idle */
|
|
}
|
|
#endif
|
|
#ifdef ACTION_REPLAY_COMMON
|
|
check_prefs_changed_carts(1);
|
|
#endif
|
|
action_replay_patch();
|
|
action_replay_checksum_info();
|
|
}
|
|
|
|
|
|
#ifdef SAVESTATE
|
|
|
|
uae_u8 *save_action_replay (uae_u32 *len, uae_u8 *dstptr)
|
|
{
|
|
uae_u8 *dstbak, *dst;
|
|
|
|
*len = 1;
|
|
if (!armemory_ram || !armemory_rom || !armodel)
|
|
return 0;
|
|
*len = 1 + strlen (currprefs.cartfile) + 1 + arram_size + 256;
|
|
if (dstptr)
|
|
dstbak = dst = dstptr;
|
|
else
|
|
dstbak = dst = malloc (*len);
|
|
save_u8 (armodel);
|
|
strcpy ((char *) dst, currprefs.cartfile);
|
|
dst += strlen ((const char *) dst) + 1;
|
|
memcpy (dst, armemory_ram, arram_size);
|
|
return dstbak;
|
|
}
|
|
|
|
const uae_u8 *restore_action_replay (const uae_u8 *src)
|
|
{
|
|
action_replay_unload (1);
|
|
armodel = restore_u8 ();
|
|
if (!armodel)
|
|
return src;
|
|
strncpy (changed_prefs.cartfile, (char *) src, 255);
|
|
strcpy (currprefs.cartfile, changed_prefs.cartfile);
|
|
src += strlen ((const char *) src) + 1;
|
|
action_replay_load ();
|
|
if (armemory_ram) {
|
|
memcpy (armemory_ram, src, arram_size);
|
|
memcpy (ar_custom, armemory_ram + 0xf000, 2 * 256);
|
|
src += arram_size;
|
|
}
|
|
src += 256;
|
|
return src;
|
|
}
|
|
|
|
#endif /* SAVESTATE */
|
|
|
|
#endif /* ACTION_REPLAY */
|