mirror of
https://github.com/Wiimpathy/HatariWii.git
synced 2024-06-02 16:48:43 +02:00
1583 lines
38 KiB
C
1583 lines
38 KiB
C
/*
|
|
* UAE - The Un*x Amiga Emulator - CPU core
|
|
*
|
|
* Memory management
|
|
*
|
|
* (c) 1995 Bernd Schmidt
|
|
*
|
|
* Adaptation to Hatari by Thomas Huth
|
|
*
|
|
* This file is distributed under the GNU General Public License, version 2
|
|
* or at your option any later version. Read the file gpl.txt for details.
|
|
*/
|
|
const char Memory_fileid[] = "Hatari memory.c : " __DATE__ " " __TIME__;
|
|
|
|
#include <SDL.h>
|
|
#include "config.h"
|
|
#include "sysdeps.h"
|
|
#include "hatari-glue.h"
|
|
#include "maccess.h"
|
|
#include "memory.h"
|
|
|
|
#include "main.h"
|
|
#include "tos.h"
|
|
#include "ide.h"
|
|
#include "ioMem.h"
|
|
#include "reset.h"
|
|
#include "stMemory.h"
|
|
#include "m68000.h"
|
|
#include "configuration.h"
|
|
|
|
#include "newcpu.h"
|
|
|
|
|
|
/* Set illegal_mem to 1 for debug output: */
|
|
#define illegal_mem 1
|
|
|
|
static int illegal_count = 50;
|
|
|
|
static uae_u32 STmem_size;
|
|
uae_u32 TTmem_size = 0;
|
|
static uae_u32 TTmem_mask;
|
|
|
|
#define STmem_start 0x00000000
|
|
#define ROMmem_start 0x00E00000
|
|
#define IdeMem_start 0x00F00000
|
|
#define IOmem_start 0x00FF0000
|
|
#define TTmem_start 0x01000000 /* TOS 3 and TOS 4 always expect extra RAM at this address */
|
|
#define TTmem_end 0x80000000 /* Max value for end of TT ram, which gives 2047 MB */
|
|
|
|
#define IdeMem_size 65536
|
|
#define IOmem_size 65536
|
|
#define ROMmem_size (0x00FF0000 - 0x00E00000) /* So we cover both possible ROM regions + cartridge */
|
|
|
|
#define STmem_mask 0x00ffffff
|
|
#define ROMmem_mask 0x00ffffff
|
|
#define IdeMem_mask (IdeMem_size - 1)
|
|
#define IOmem_mask (IOmem_size - 1)
|
|
|
|
/* Some prototypes: */
|
|
static int STmem_check (uaecptr addr, uae_u32 size) REGPARAM;
|
|
static uae_u8 *STmem_xlate (uaecptr addr) REGPARAM;
|
|
|
|
|
|
|
|
#ifdef WINUAE_FOR_HATARI
|
|
#undef NATMEM_OFFSET
|
|
#endif
|
|
|
|
#ifdef NATMEM_OFFSET
|
|
bool canbang;
|
|
int candirect = -1;
|
|
#endif
|
|
|
|
#ifdef JIT
|
|
/* Set by each memory handler that does not simply access real memory. */
|
|
int special_mem;
|
|
#endif
|
|
|
|
#ifdef NATMEM_OFFSET
|
|
static bool isdirectjit (void)
|
|
{
|
|
return currprefs.cachesize && !currprefs.comptrustbyte;
|
|
}
|
|
|
|
static bool canjit (void)
|
|
{
|
|
if (currprefs.cpu_model < 68020 || currprefs.address_space_24)
|
|
return false;
|
|
return true;
|
|
}
|
|
static bool needmman (void)
|
|
{
|
|
if (!currprefs.jit_direct_compatible_memory)
|
|
return false;
|
|
#ifdef _WIN32
|
|
return true;
|
|
#endif
|
|
if (canjit ())
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
static void nocanbang (void)
|
|
{
|
|
canbang = 0;
|
|
}
|
|
#endif
|
|
|
|
uae_u8 ce_banktype[65536];
|
|
uae_u8 ce_cachable[65536];
|
|
|
|
|
|
/* The address space setting used during the last reset. */
|
|
static bool last_address_space_24;
|
|
|
|
addrbank *mem_banks[MEMORY_BANKS];
|
|
|
|
/* This has two functions. It either holds a host address that, when added
|
|
to the 68k address, gives the host address corresponding to that 68k
|
|
address (in which case the value in this array is even), OR it holds the
|
|
same value as mem_banks, for those banks that have baseaddr==0. In that
|
|
case, bit 0 is set (the memory access routines will take care of it). */
|
|
|
|
uae_u8 *baseaddr[MEMORY_BANKS];
|
|
|
|
#ifdef NO_INLINE_MEMORY_ACCESS
|
|
__inline__ uae_u32 longget (uaecptr addr)
|
|
{
|
|
return call_mem_get_func (get_mem_bank (addr).lget, addr);
|
|
}
|
|
__inline__ uae_u32 wordget (uaecptr addr)
|
|
{
|
|
return call_mem_get_func (get_mem_bank (addr).wget, addr);
|
|
}
|
|
__inline__ uae_u32 byteget (uaecptr addr)
|
|
{
|
|
return call_mem_get_func (get_mem_bank (addr).bget, addr);
|
|
}
|
|
__inline__ void longput (uaecptr addr, uae_u32 l)
|
|
{
|
|
call_mem_put_func (get_mem_bank (addr).lput, addr, l);
|
|
}
|
|
__inline__ void wordput (uaecptr addr, uae_u32 w)
|
|
{
|
|
call_mem_put_func (get_mem_bank (addr).wput, addr, w);
|
|
}
|
|
__inline__ void byteput (uaecptr addr, uae_u32 b)
|
|
{
|
|
call_mem_put_func (get_mem_bank (addr).bput, addr, b);
|
|
}
|
|
#endif
|
|
|
|
int addr_valid (const TCHAR *txt, uaecptr addr, uae_u32 len)
|
|
{
|
|
addrbank *ab = &get_mem_bank(addr);
|
|
if (ab == 0 || !(ab->flags & (ABFLAG_RAM | ABFLAG_ROM)) || addr < 0x100 || len > 16777215 || !valid_address (addr, len)) {
|
|
write_log (_T("corrupt %s pointer %x (%d) detected!\n"), txt, addr, len);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int illegal_count;
|
|
|
|
static uae_u32 REGPARAM3 dummy_lget (uaecptr) REGPARAM;
|
|
static uae_u32 REGPARAM3 dummy_wget (uaecptr) REGPARAM;
|
|
static uae_u32 REGPARAM3 dummy_bget (uaecptr) REGPARAM;
|
|
static void REGPARAM3 dummy_lput (uaecptr, uae_u32) REGPARAM;
|
|
static void REGPARAM3 dummy_wput (uaecptr, uae_u32) REGPARAM;
|
|
static void REGPARAM3 dummy_bput (uaecptr, uae_u32) REGPARAM;
|
|
static int REGPARAM3 dummy_check (uaecptr addr, uae_u32 size) REGPARAM;
|
|
|
|
#define MAX_ILG 200
|
|
#define NONEXISTINGDATA 0
|
|
//#define NONEXISTINGDATA 0xffffffff
|
|
|
|
|
|
|
|
|
|
static void print_illegal_counted(const char *txt, uaecptr addr)
|
|
{
|
|
if (!illegal_mem || illegal_count <= 0)
|
|
return;
|
|
|
|
write_log("%s at %08lx\n", txt, (long)addr);
|
|
if (--illegal_count == 0)
|
|
write_log("Suppressing further messages about illegal memory accesses.\n");
|
|
}
|
|
|
|
|
|
/* **** A dummy bank that only contains zeros **** */
|
|
/* TODO [NP] : in many cases, we should not return 0 but a value depending on the data */
|
|
/* last accessed on the bus */
|
|
|
|
static void dummylog (int rw, uaecptr addr, int size, uae_u32 val, int ins)
|
|
{
|
|
#ifndef WINUAE_FOR_HATARI
|
|
if (illegal_count >= MAX_ILG && MAX_ILG > 0)
|
|
return;
|
|
/* ignore Zorro3 expansion space */
|
|
if (addr >= 0xff000000 && addr <= 0xff000200)
|
|
return;
|
|
/* autoconfig and extended rom */
|
|
if (addr >= 0xe00000 && addr <= 0xf7ffff)
|
|
return;
|
|
/* motherboard ram */
|
|
if (addr >= 0x08000000 && addr <= 0x08000007)
|
|
return;
|
|
if (addr >= 0x07f00000 && addr <= 0x07f00007)
|
|
return;
|
|
if (addr >= 0x07f7fff0 && addr <= 0x07ffffff)
|
|
return;
|
|
if (MAX_ILG >= 0)
|
|
illegal_count++;
|
|
#endif
|
|
if (ins) {
|
|
write_log (_T("WARNING: Illegal opcode %cget at %08x PC=%x\n"),
|
|
size == 2 ? 'w' : 'l', addr, M68K_GETPC);
|
|
} else if (rw) {
|
|
write_log (_T("Illegal %cput at %08x=%08x PC=%x\n"),
|
|
size == 1 ? 'b' : size == 2 ? 'w' : 'l', addr, val, M68K_GETPC);
|
|
} else {
|
|
write_log (_T("Illegal %cget at %08x PC=%x\n"),
|
|
size == 1 ? 'b' : size == 2 ? 'w' : 'l', addr, M68K_GETPC);
|
|
}
|
|
}
|
|
|
|
void dummy_put (uaecptr addr, int size, uae_u32 val)
|
|
{
|
|
#ifndef WINUAE_FOR_HATARI
|
|
#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);
|
|
if (gary_toenb && currprefs.mmu_model)
|
|
exception2 (addr, true, size, regs.s ? 4 : 0);
|
|
}
|
|
|
|
#else
|
|
/* Hatari : do nothing in case of dummy_put */
|
|
#endif
|
|
}
|
|
|
|
uae_u32 dummy_get (uaecptr addr, int size, bool inst)
|
|
{
|
|
uae_u32 v = NONEXISTINGDATA;
|
|
|
|
#ifndef WINUAE_FOR_HATARI
|
|
#if FLASHEMU
|
|
if (addr >= 0xf00000 && addr < 0xf80000 && size < 2) {
|
|
if (addr < 0xf60000)
|
|
return flash_read(addr);
|
|
return 8;
|
|
}
|
|
#endif
|
|
|
|
if (gary_nonrange(addr) || (size > 1 && gary_nonrange(addr + size - 1))) {
|
|
if (gary_timeout)
|
|
gary_wait (addr, size, false);
|
|
if (gary_toenb)
|
|
exception2 (addr, false, size, (regs.s ? 4 : 0) | (inst ? 0 : 1));
|
|
return v;
|
|
}
|
|
|
|
if (currprefs.cpu_model >= 68040)
|
|
return v;
|
|
if (!currprefs.cpu_compatible)
|
|
return v;
|
|
if (currprefs.address_space_24)
|
|
addr &= 0x00ffffff;
|
|
if (addr >= 0x10000000)
|
|
return v;
|
|
if ((currprefs.cpu_model <= 68010) || (currprefs.cpu_model == 68020 && (currprefs.chipset_mask & CSMASK_AGA) && currprefs.address_space_24)) {
|
|
if (size == 4) {
|
|
v = regs.db & 0xffff;
|
|
if (addr & 1)
|
|
v = (v << 8) | (v >> 8);
|
|
v = (v << 16) | v;
|
|
} else if (size == 2) {
|
|
v = regs.db & 0xffff;
|
|
if (addr & 1)
|
|
v = (v << 8) | (v >> 8);
|
|
} else {
|
|
v = regs.db;
|
|
v = (addr & 1) ? (v & 0xff) : ((v >> 8) & 0xff);
|
|
}
|
|
}
|
|
#if 0
|
|
if (addr >= 0x10000000)
|
|
write_log (_T("%08X %d = %08x\n"), addr, size, v);
|
|
#endif
|
|
|
|
#else
|
|
/* Hatari : TODO returns 0 for now, but we should use last databus value */
|
|
v = 0;
|
|
#endif
|
|
return v;
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 dummy_lget (uaecptr addr)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= S_READ;
|
|
#endif
|
|
if (illegal_mem)
|
|
dummylog (0, addr, 4, 0, 0);
|
|
return dummy_get (addr, 4, false);
|
|
}
|
|
uae_u32 REGPARAM2 dummy_lgeti (uaecptr addr)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= S_READ;
|
|
#endif
|
|
if (illegal_mem)
|
|
dummylog (0, addr, 4, 0, 1);
|
|
return dummy_get (addr, 4, true);
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 dummy_wget (uaecptr addr)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= S_READ;
|
|
#endif
|
|
#if 0
|
|
if (addr == 0xb0b000) {
|
|
extern uae_u16 isideint(void);
|
|
return isideint();
|
|
}
|
|
#endif
|
|
if (illegal_mem)
|
|
dummylog (0, addr, 2, 0, 0);
|
|
return dummy_get (addr, 2, false);
|
|
}
|
|
uae_u32 REGPARAM2 dummy_wgeti (uaecptr addr)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= S_READ;
|
|
#endif
|
|
if (illegal_mem)
|
|
dummylog (0, addr, 2, 0, 1);
|
|
return dummy_get (addr, 2, true);
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 dummy_bget (uaecptr addr)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= S_READ;
|
|
#endif
|
|
if (illegal_mem)
|
|
dummylog (0, addr, 1, 0, 0);
|
|
return dummy_get (addr, 1, false);
|
|
}
|
|
|
|
static void REGPARAM2 dummy_lput (uaecptr addr, uae_u32 l)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= S_WRITE;
|
|
#endif
|
|
if (illegal_mem)
|
|
dummylog (1, addr, 4, l, 0);
|
|
dummy_put (addr, 4, l);
|
|
}
|
|
static void REGPARAM2 dummy_wput (uaecptr addr, uae_u32 w)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= S_WRITE;
|
|
#endif
|
|
if (illegal_mem)
|
|
dummylog (1, addr, 2, w, 0);
|
|
dummy_put (addr, 2, w);
|
|
}
|
|
static void REGPARAM2 dummy_bput (uaecptr addr, uae_u32 b)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= S_WRITE;
|
|
#endif
|
|
if (illegal_mem)
|
|
dummylog (1, addr, 1, b, 0);
|
|
dummy_put (addr, 1, b);
|
|
}
|
|
|
|
static int REGPARAM2 dummy_check (uaecptr addr, uae_u32 size)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= S_READ;
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static uae_u8 *dummy_xlate(uaecptr addr)
|
|
{
|
|
write_log("Your Atari program just did something terribly stupid:"
|
|
" dummy_xlate($%x)\n", addr);
|
|
/*Reset_Warm();*/
|
|
return STmem_xlate(addr); /* So we don't crash. */
|
|
}
|
|
|
|
|
|
#ifndef WINUAE_FOR_HATARI
|
|
static void REGPARAM2 none_put (uaecptr addr, uae_u32 v)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= S_WRITE;
|
|
#endif
|
|
}
|
|
static uae_u32 REGPARAM2 ones_get (uaecptr addr)
|
|
{
|
|
#ifdef JIT
|
|
special_mem |= S_READ;
|
|
#endif
|
|
return 0xffffffff;
|
|
}
|
|
|
|
addrbank *get_sub_bank(uaecptr *paddr)
|
|
{
|
|
int i;
|
|
uaecptr addr = *paddr;
|
|
addrbank *ab = &get_mem_bank(addr);
|
|
struct addrbank_sub *sb = ab->sub_banks;
|
|
if (!sb)
|
|
return &dummy_bank;
|
|
for (i = 0; sb[i].bank; i++) {
|
|
int offset = addr & 65535;
|
|
if (offset < sb[i + 1].offset) {
|
|
uae_u32 mask = sb[i].mask;
|
|
uae_u32 maskval = sb[i].maskval;
|
|
if ((offset & mask) == maskval) {
|
|
*paddr = addr - sb[i].suboffset;
|
|
return sb[i].bank;
|
|
}
|
|
}
|
|
}
|
|
*paddr = addr - sb[i - 1].suboffset;
|
|
return sb[i - 1].bank;
|
|
}
|
|
uae_u32 REGPARAM3 sub_bank_lget (uaecptr addr) REGPARAM
|
|
{
|
|
addrbank *ab = get_sub_bank(&addr);
|
|
return ab->lget(addr);
|
|
}
|
|
uae_u32 REGPARAM3 sub_bank_wget(uaecptr addr) REGPARAM
|
|
{
|
|
addrbank *ab = get_sub_bank(&addr);
|
|
return ab->wget(addr);
|
|
}
|
|
uae_u32 REGPARAM3 sub_bank_bget(uaecptr addr) REGPARAM
|
|
{
|
|
addrbank *ab = get_sub_bank(&addr);
|
|
return ab->bget(addr);
|
|
}
|
|
void REGPARAM3 sub_bank_lput(uaecptr addr, uae_u32 v) REGPARAM
|
|
{
|
|
addrbank *ab = get_sub_bank(&addr);
|
|
ab->lput(addr, v);
|
|
}
|
|
void REGPARAM3 sub_bank_wput(uaecptr addr, uae_u32 v) REGPARAM
|
|
{
|
|
addrbank *ab = get_sub_bank(&addr);
|
|
ab->wput(addr, v);
|
|
}
|
|
void REGPARAM3 sub_bank_bput(uaecptr addr, uae_u32 v) REGPARAM
|
|
{
|
|
addrbank *ab = get_sub_bank(&addr);
|
|
|
|
/* last accessed on the bus */ab->bput(addr, v);
|
|
}
|
|
uae_u32 REGPARAM3 sub_bank_lgeti(uaecptr addr) REGPARAM
|
|
{
|
|
addrbank *ab = get_sub_bank(&addr);
|
|
return ab->lgeti(addr);
|
|
}
|
|
uae_u32 REGPARAM3 sub_bank_wgeti(uaecptr addr) REGPARAM
|
|
{
|
|
addrbank *ab = get_sub_bank(&addr);
|
|
return ab->wgeti(addr);
|
|
}
|
|
int REGPARAM3 sub_bank_check(uaecptr addr, uae_u32 size) REGPARAM
|
|
{
|
|
addrbank *ab = get_sub_bank(&addr);
|
|
return ab->check(addr, size);
|
|
}
|
|
uae_u8 *REGPARAM3 sub_bank_xlate(uaecptr addr) REGPARAM
|
|
{
|
|
addrbank *ab = get_sub_bank(&addr);
|
|
return ab->xlateaddr(addr);
|
|
}
|
|
#endif
|
|
|
|
|
|
/* **** This memory bank only generates bus errors **** */
|
|
|
|
static uae_u32 BusErrMem_lget(uaecptr addr)
|
|
{
|
|
print_illegal_counted("Bus error lget", addr);
|
|
|
|
M68000_BusError(addr, 1, BUS_ERROR_SIZE_LONG, BUS_ERROR_ACCESS_DATA);
|
|
return 0;
|
|
}
|
|
|
|
static uae_u32 BusErrMem_wget(uaecptr addr)
|
|
{
|
|
print_illegal_counted("Bus error wget", addr);
|
|
|
|
M68000_BusError(addr, 1, BUS_ERROR_SIZE_WORD, BUS_ERROR_ACCESS_DATA);
|
|
return 0;
|
|
}
|
|
|
|
static uae_u32 BusErrMem_bget(uaecptr addr)
|
|
{
|
|
print_illegal_counted("Bus error bget", addr);
|
|
|
|
M68000_BusError(addr, 1, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
|
|
return 0;
|
|
}
|
|
|
|
static void BusErrMem_lput(uaecptr addr, uae_u32 l)
|
|
{
|
|
print_illegal_counted("Bus error lput", addr);
|
|
|
|
M68000_BusError(addr, 0, BUS_ERROR_SIZE_LONG, BUS_ERROR_ACCESS_DATA);
|
|
}
|
|
|
|
static void BusErrMem_wput(uaecptr addr, uae_u32 w)
|
|
{
|
|
print_illegal_counted("Bus error wput", addr);
|
|
|
|
M68000_BusError(addr, 0, BUS_ERROR_SIZE_WORD, BUS_ERROR_ACCESS_DATA);
|
|
}
|
|
|
|
static void BusErrMem_bput(uaecptr addr, uae_u32 b)
|
|
{
|
|
print_illegal_counted("Bus error bput", addr);
|
|
|
|
M68000_BusError(addr, 0, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
|
|
}
|
|
|
|
static int BusErrMem_check(uaecptr addr, uae_u32 size)
|
|
{
|
|
if (illegal_mem)
|
|
write_log ("Bus error check at %08lx\n", (long)addr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static uae_u8 *BusErrMem_xlate (uaecptr addr)
|
|
{
|
|
write_log("Your Atari program just did something terribly stupid:"
|
|
" BusErrMem_xlate($%x)\n", addr);
|
|
|
|
/*M68000_BusError(addr);*/
|
|
return STmem_xlate(addr); /* So we don't crash. */
|
|
}
|
|
|
|
|
|
/* **** ST RAM memory **** */
|
|
|
|
/*static uae_u8 *STmemory;*/
|
|
#define STmemory STRam
|
|
|
|
static uae_u32 STmem_lget(uaecptr addr)
|
|
{
|
|
addr -= STmem_start & STmem_mask;
|
|
addr &= STmem_mask;
|
|
return do_get_mem_long(STmemory + addr);
|
|
}
|
|
|
|
static uae_u32 STmem_wget(uaecptr addr)
|
|
{
|
|
addr -= STmem_start & STmem_mask;
|
|
addr &= STmem_mask;
|
|
return do_get_mem_word(STmemory + addr);
|
|
}
|
|
|
|
static uae_u32 STmem_bget(uaecptr addr)
|
|
{
|
|
addr -= STmem_start & STmem_mask;
|
|
addr &= STmem_mask;
|
|
return STmemory[addr];
|
|
}
|
|
|
|
static void STmem_lput(uaecptr addr, uae_u32 l)
|
|
{
|
|
addr -= STmem_start & STmem_mask;
|
|
addr &= STmem_mask;
|
|
do_put_mem_long(STmemory + addr, l);
|
|
}
|
|
|
|
static void STmem_wput(uaecptr addr, uae_u32 w)
|
|
{
|
|
addr -= STmem_start & STmem_mask;
|
|
addr &= STmem_mask;
|
|
do_put_mem_word(STmemory + addr, w);
|
|
}
|
|
|
|
static void STmem_bput(uaecptr addr, uae_u32 b)
|
|
{
|
|
addr -= STmem_start & STmem_mask;
|
|
addr &= STmem_mask;
|
|
STmemory[addr] = b;
|
|
}
|
|
|
|
static int STmem_check(uaecptr addr, uae_u32 size)
|
|
{
|
|
addr -= STmem_start & STmem_mask;
|
|
addr &= STmem_mask;
|
|
return (addr + size) <= STmem_size;
|
|
}
|
|
|
|
static uae_u8 *STmem_xlate(uaecptr addr)
|
|
{
|
|
addr -= STmem_start & STmem_mask;
|
|
addr &= STmem_mask;
|
|
return STmemory + addr;
|
|
}
|
|
|
|
|
|
/*
|
|
* **** ST RAM system memory ****
|
|
* We need a separate mem bank for this region since the first 0x800 bytes on
|
|
* the ST can only be accessed in supervisor mode. Note that the very first
|
|
* 8 bytes of the ST memory are also a mirror of the TOS ROM, so they are write
|
|
* protected!
|
|
*/
|
|
static uae_u32 SysMem_lget(uaecptr addr)
|
|
{
|
|
addr -= STmem_start & STmem_mask;
|
|
addr &= STmem_mask;
|
|
|
|
if(addr < 0x800 && !regs.s)
|
|
{
|
|
M68000_BusError(addr, 1, BUS_ERROR_SIZE_LONG, BUS_ERROR_ACCESS_DATA);
|
|
return 0;
|
|
}
|
|
|
|
return do_get_mem_long(STmemory + addr);
|
|
}
|
|
|
|
static uae_u32 SysMem_wget(uaecptr addr)
|
|
{
|
|
addr -= STmem_start & STmem_mask;
|
|
addr &= STmem_mask;
|
|
|
|
if(addr < 0x800 && !regs.s)
|
|
{
|
|
M68000_BusError(addr, 1, BUS_ERROR_SIZE_WORD, BUS_ERROR_ACCESS_DATA);
|
|
return 0;
|
|
}
|
|
|
|
return do_get_mem_word(STmemory + addr);
|
|
}
|
|
|
|
static uae_u32 SysMem_bget(uaecptr addr)
|
|
{
|
|
addr -= STmem_start & STmem_mask;
|
|
addr &= STmem_mask;
|
|
|
|
if(addr < 0x800 && !regs.s)
|
|
{
|
|
M68000_BusError(addr, 1, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
|
|
return 0;
|
|
}
|
|
|
|
return STmemory[addr];
|
|
}
|
|
|
|
static void SysMem_lput(uaecptr addr, uae_u32 l)
|
|
{
|
|
addr -= STmem_start & STmem_mask;
|
|
addr &= STmem_mask;
|
|
|
|
if(addr < 0x8 || (addr < 0x800 && !regs.s))
|
|
{
|
|
M68000_BusError(addr, 0, BUS_ERROR_SIZE_LONG, BUS_ERROR_ACCESS_DATA);
|
|
return;
|
|
}
|
|
|
|
do_put_mem_long(STmemory + addr, l);
|
|
}
|
|
|
|
static void SysMem_wput(uaecptr addr, uae_u32 w)
|
|
{
|
|
addr -= STmem_start & STmem_mask;
|
|
addr &= STmem_mask;
|
|
|
|
if(addr < 0x8 || (addr < 0x800 && !regs.s))
|
|
{
|
|
M68000_BusError(addr, 0, BUS_ERROR_SIZE_WORD, BUS_ERROR_ACCESS_DATA);
|
|
return;
|
|
}
|
|
|
|
do_put_mem_word(STmemory + addr, w);
|
|
}
|
|
|
|
static void SysMem_bput(uaecptr addr, uae_u32 b)
|
|
{
|
|
addr -= STmem_start & STmem_mask;
|
|
addr &= STmem_mask;
|
|
|
|
if(addr < 0x8 || (addr < 0x800 && !regs.s))
|
|
{
|
|
M68000_BusError(addr, 0, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
|
|
return;
|
|
}
|
|
|
|
STmemory[addr] = b;
|
|
}
|
|
|
|
|
|
/*
|
|
* **** Void memory ****
|
|
* Between the ST-RAM end and the 4 MB barrier, there is a void memory space:
|
|
* Reading always returns the same value and writing does nothing at all.
|
|
* [NP] : this is not correct, reading does not always return 0, when there's
|
|
* no memory, it will return the latest data that was read on the bus.
|
|
* In many cases, this will return the word that was just read in the 68000's
|
|
* prefetch register to decode the next opcode (tested on a real STF)
|
|
*/
|
|
|
|
static uae_u32 VoidMem_lget(uaecptr addr)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static uae_u32 VoidMem_wget(uaecptr addr)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static uae_u32 VoidMem_bget(uaecptr addr)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void VoidMem_lput(uaecptr addr, uae_u32 l)
|
|
{
|
|
}
|
|
|
|
static void VoidMem_wput(uaecptr addr, uae_u32 w)
|
|
{
|
|
}
|
|
|
|
static void VoidMem_bput (uaecptr addr, uae_u32 b)
|
|
{
|
|
}
|
|
|
|
static int VoidMem_check(uaecptr addr, uae_u32 size)
|
|
{
|
|
if (illegal_mem)
|
|
write_log ("Void memory check at %08lx\n", (long)addr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static uae_u8 *VoidMem_xlate (uaecptr addr)
|
|
{
|
|
write_log("Your Atari program just did something terribly stupid:"
|
|
" VoidMem_xlate($%x)\n", addr);
|
|
|
|
return STmem_xlate(addr); /* So we don't crash. */
|
|
}
|
|
|
|
|
|
/* **** TT fast memory **** */
|
|
|
|
uae_u8 *TTmemory;
|
|
|
|
static uae_u32 TTmem_lget(uaecptr addr)
|
|
{
|
|
addr -= TTmem_start & TTmem_mask;
|
|
addr &= TTmem_mask;
|
|
return do_get_mem_long(TTmemory + addr);
|
|
}
|
|
|
|
static uae_u32 TTmem_wget(uaecptr addr)
|
|
{
|
|
addr -= TTmem_start & TTmem_mask;
|
|
addr &= TTmem_mask;
|
|
return do_get_mem_word(TTmemory + addr);
|
|
}
|
|
|
|
static uae_u32 TTmem_bget(uaecptr addr)
|
|
{
|
|
addr -= TTmem_start & TTmem_mask;
|
|
addr &= TTmem_mask;
|
|
return TTmemory[addr];
|
|
}
|
|
|
|
static void TTmem_lput(uaecptr addr, uae_u32 l)
|
|
{
|
|
addr -= TTmem_start & TTmem_mask;
|
|
addr &= TTmem_mask;
|
|
do_put_mem_long(TTmemory + addr, l);
|
|
}
|
|
|
|
static void TTmem_wput(uaecptr addr, uae_u32 w)
|
|
{
|
|
addr -= TTmem_start & TTmem_mask;
|
|
addr &= TTmem_mask;
|
|
do_put_mem_word(TTmemory + addr, w);
|
|
}
|
|
|
|
static void TTmem_bput(uaecptr addr, uae_u32 b)
|
|
{
|
|
addr -= TTmem_start & TTmem_mask;
|
|
addr &= TTmem_mask;
|
|
TTmemory[addr] = b;
|
|
}
|
|
|
|
static int TTmem_check(uaecptr addr, uae_u32 size)
|
|
{
|
|
addr -= TTmem_start & TTmem_mask;
|
|
addr &= TTmem_mask;
|
|
return (addr + size) <= TTmem_size;
|
|
}
|
|
|
|
static uae_u8 *TTmem_xlate(uaecptr addr)
|
|
{
|
|
addr -= TTmem_start & TTmem_mask;
|
|
addr &= TTmem_mask;
|
|
return TTmemory + addr;
|
|
}
|
|
|
|
|
|
/* **** ROM memory **** */
|
|
|
|
uae_u8 *ROMmemory;
|
|
|
|
static uae_u32 ROMmem_lget(uaecptr addr)
|
|
{
|
|
addr -= ROMmem_start & ROMmem_mask;
|
|
addr &= ROMmem_mask;
|
|
return do_get_mem_long(ROMmemory + addr);
|
|
}
|
|
|
|
static uae_u32 ROMmem_wget(uaecptr addr)
|
|
{
|
|
addr -= ROMmem_start & ROMmem_mask;
|
|
addr &= ROMmem_mask;
|
|
return do_get_mem_word(ROMmemory + addr);
|
|
}
|
|
|
|
static uae_u32 ROMmem_bget(uaecptr addr)
|
|
{
|
|
addr -= ROMmem_start & ROMmem_mask;
|
|
addr &= ROMmem_mask;
|
|
return ROMmemory[addr];
|
|
}
|
|
|
|
static void ROMmem_lput(uaecptr addr, uae_u32 b)
|
|
{
|
|
print_illegal_counted("Illegal ROMmem lput", addr);
|
|
|
|
M68000_BusError(addr, 0, BUS_ERROR_SIZE_LONG, BUS_ERROR_ACCESS_DATA);
|
|
}
|
|
|
|
static void ROMmem_wput(uaecptr addr, uae_u32 b)
|
|
{
|
|
print_illegal_counted("Illegal ROMmem wput", addr);
|
|
|
|
M68000_BusError(addr, 0, BUS_ERROR_SIZE_WORD, BUS_ERROR_ACCESS_DATA);
|
|
}
|
|
|
|
static void ROMmem_bput(uaecptr addr, uae_u32 b)
|
|
{
|
|
print_illegal_counted("Illegal ROMmem bput", addr);
|
|
|
|
M68000_BusError(addr, 0, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
|
|
}
|
|
|
|
static int ROMmem_check(uaecptr addr, uae_u32 size)
|
|
{
|
|
addr -= ROMmem_start & ROMmem_mask;
|
|
addr &= ROMmem_mask;
|
|
return (addr + size) <= ROMmem_size;
|
|
}
|
|
|
|
static uae_u8 *ROMmem_xlate(uaecptr addr)
|
|
{
|
|
addr -= ROMmem_start & ROMmem_mask;
|
|
addr &= ROMmem_mask;
|
|
return ROMmemory + addr;
|
|
}
|
|
|
|
|
|
/* IDE controller IO memory */
|
|
/* see also ide.c */
|
|
|
|
static uae_u8 *IdeMemory;
|
|
|
|
static int IdeMem_check(uaecptr addr, uae_u32 size)
|
|
{
|
|
addr -= IdeMem_start;
|
|
addr &= IdeMem_mask;
|
|
return (addr + size) <= IdeMem_size;
|
|
}
|
|
|
|
static uae_u8 *IdeMem_xlate(uaecptr addr)
|
|
{
|
|
addr -= IdeMem_start;
|
|
addr &= IdeMem_mask;
|
|
return IdeMemory + addr;
|
|
}
|
|
|
|
|
|
/* Hardware IO memory */
|
|
/* see also ioMem.c */
|
|
|
|
uae_u8 *IOmemory;
|
|
|
|
static int IOmem_check(uaecptr addr, uae_u32 size)
|
|
{
|
|
addr -= IOmem_start;
|
|
addr &= IOmem_mask;
|
|
return (addr + size) <= IOmem_size;
|
|
}
|
|
|
|
static uae_u8 *IOmem_xlate(uaecptr addr)
|
|
{
|
|
addr -= IOmem_start;
|
|
addr &= IOmem_mask;
|
|
return IOmemory + addr;
|
|
}
|
|
|
|
|
|
|
|
/* **** Address banks **** */
|
|
|
|
static addrbank dummy_bank =
|
|
{
|
|
dummy_lget, dummy_wget, dummy_bget,
|
|
dummy_lput, dummy_wput, dummy_bput,
|
|
dummy_xlate, dummy_check, NULL, NULL, NULL,
|
|
dummy_lget, dummy_wget, ABFLAG_NONE
|
|
// dummy_lgeti, dummy_wgeti, ABFLAG_NONE
|
|
};
|
|
|
|
static addrbank BusErrMem_bank =
|
|
{
|
|
BusErrMem_lget, BusErrMem_wget, BusErrMem_bget,
|
|
BusErrMem_lput, BusErrMem_wput, BusErrMem_bput,
|
|
BusErrMem_xlate, BusErrMem_check, NULL, "bus_err_mem" , "BusError memory",
|
|
BusErrMem_lget, BusErrMem_wget, ABFLAG_NONE
|
|
};
|
|
|
|
static addrbank STmem_bank =
|
|
{
|
|
STmem_lget, STmem_wget, STmem_bget,
|
|
STmem_lput, STmem_wput, STmem_bput,
|
|
STmem_xlate, STmem_check, NULL, "st_mem" , "ST memory",
|
|
STmem_lget, STmem_wget, ABFLAG_RAM
|
|
};
|
|
|
|
static addrbank SysMem_bank =
|
|
{
|
|
SysMem_lget, SysMem_wget, SysMem_bget,
|
|
SysMem_lput, SysMem_wput, SysMem_bput,
|
|
STmem_xlate, STmem_check, NULL, "sys_mem" , "Sys memory",
|
|
SysMem_lget, SysMem_wget, ABFLAG_RAM
|
|
};
|
|
|
|
static addrbank VoidMem_bank =
|
|
{
|
|
VoidMem_lget, VoidMem_wget, VoidMem_bget,
|
|
VoidMem_lput, VoidMem_wput, VoidMem_bput,
|
|
VoidMem_xlate, VoidMem_check, NULL, "void_mem" , "Void memory",
|
|
VoidMem_lget, VoidMem_wget, ABFLAG_NONE
|
|
};
|
|
|
|
static addrbank TTmem_bank =
|
|
{
|
|
TTmem_lget, TTmem_wget, TTmem_bget,
|
|
TTmem_lput, TTmem_wput, TTmem_bput,
|
|
TTmem_xlate, TTmem_check, NULL, "tt_mem" , "TT memory",
|
|
TTmem_lget, TTmem_wget, ABFLAG_RAM /* NP TODO : use ABFLAG_RAM_TT for non DMA RAM */
|
|
};
|
|
|
|
static addrbank ROMmem_bank =
|
|
{
|
|
ROMmem_lget, ROMmem_wget, ROMmem_bget,
|
|
ROMmem_lput, ROMmem_wput, ROMmem_bput,
|
|
ROMmem_xlate, ROMmem_check, NULL, "rom_mem" , "ROM memory",
|
|
ROMmem_lget, ROMmem_wget, ABFLAG_ROM
|
|
};
|
|
|
|
static addrbank IdeMem_bank =
|
|
{
|
|
Ide_Mem_lget, Ide_Mem_wget, Ide_Mem_bget,
|
|
Ide_Mem_lput, Ide_Mem_wput, Ide_Mem_bput,
|
|
IdeMem_xlate, IdeMem_check, NULL, "ide_mem" , "IDE memory",
|
|
Ide_Mem_lget, Ide_Mem_wget, ABFLAG_IO
|
|
};
|
|
|
|
static addrbank IOmem_bank =
|
|
{
|
|
IoMem_lget, IoMem_wget, IoMem_bget,
|
|
IoMem_lput, IoMem_wput, IoMem_bput,
|
|
IOmem_xlate, IOmem_check, NULL, "io_mem" , "IO memory",
|
|
IoMem_lget, IoMem_wget, ABFLAG_IO
|
|
};
|
|
|
|
|
|
#ifdef WINUAE_FOR_HATARI
|
|
#undef NATMEM_OFFSET /* Don't use shm in Hatari */
|
|
#endif
|
|
|
|
#ifndef NATMEM_OFFSET
|
|
//extern uae_u8 *natmem_offset, *natmem_offset_end;
|
|
|
|
bool mapped_malloc (addrbank *ab)
|
|
{
|
|
ab->startmask = ab->start;
|
|
ab->baseaddr = xcalloc (uae_u8, ab->allocated + 4);
|
|
return ab->baseaddr != NULL;
|
|
}
|
|
|
|
void mapped_free (addrbank *ab)
|
|
{
|
|
xfree(ab->baseaddr);
|
|
ab->baseaddr = NULL;
|
|
}
|
|
|
|
#else
|
|
|
|
#include <sys/ipc.h>
|
|
#include <sys/shm.h>
|
|
#include <unistd.h>
|
|
#include <sys/mman.h>
|
|
|
|
shmpiece *shm_start;
|
|
|
|
static void dumplist (void)
|
|
{
|
|
shmpiece *x = shm_start;
|
|
write_log (_T("Start Dump:\n"));
|
|
while (x) {
|
|
write_log (_T("this=%p,Native %p,id %d,prev=%p,next=%p,size=0x%08x\n"),
|
|
x, x->native_address, x->id, x->prev, x->next, x->size);
|
|
x = x->next;
|
|
}
|
|
write_log (_T("End Dump:\n"));
|
|
}
|
|
|
|
static shmpiece *find_shmpiece (uae_u8 *base, bool safe)
|
|
{
|
|
shmpiece *x = shm_start;
|
|
|
|
while (x && x->native_address != base)
|
|
x = x->next;
|
|
if (!x) {
|
|
#ifndef WINUAE_FOR_HATARI
|
|
if (safe || bogomem_aliasing)
|
|
#else
|
|
if (safe)
|
|
#endif
|
|
return 0;
|
|
write_log (_T("NATMEM: Failure to find mapping at %08X, %p\n"), base - NATMEM_OFFSET, base);
|
|
nocanbang ();
|
|
return 0;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
static void delete_shmmaps (uae_u32 start, uae_u32 size)
|
|
{
|
|
if (!needmman ())
|
|
return;
|
|
|
|
while (size) {
|
|
uae_u8 *base = mem_banks[bankindex (start)]->baseaddr;
|
|
if (base) {
|
|
shmpiece *x;
|
|
//base = ((uae_u8*)NATMEM_OFFSET)+start;
|
|
|
|
x = find_shmpiece (base, true);
|
|
if (!x)
|
|
return;
|
|
|
|
if (x->size > size) {
|
|
if (isdirectjit ())
|
|
write_log (_T("NATMEM WARNING: size mismatch mapping at %08x (size %08x, delsize %08x)\n"),start,x->size,size);
|
|
size = x->size;
|
|
}
|
|
|
|
shmdt (x->native_address);
|
|
size -= x->size;
|
|
start += x->size;
|
|
if (x->next)
|
|
x->next->prev = x->prev; /* remove this one from the list */
|
|
if (x->prev)
|
|
x->prev->next = x->next;
|
|
else
|
|
shm_start = x->next;
|
|
xfree (x);
|
|
} else {
|
|
size -= 0x10000;
|
|
start += 0x10000;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void add_shmmaps (uae_u32 start, addrbank *what)
|
|
{
|
|
shmpiece *x = shm_start;
|
|
shmpiece *y;
|
|
uae_u8 *base = what->baseaddr;
|
|
|
|
if (!needmman ())
|
|
return;
|
|
|
|
if (!base)
|
|
return;
|
|
|
|
x = find_shmpiece (base, false);
|
|
if (!x)
|
|
return;
|
|
|
|
y = xmalloc (shmpiece, 1);
|
|
*y = *x;
|
|
base = ((uae_u8 *) NATMEM_OFFSET) + start;
|
|
y->native_address = (uae_u8*)shmat (y->id, base, 0);
|
|
if (y->native_address == (void *) -1) {
|
|
write_log (_T("NATMEM: Failure to map existing at %08x (%p)\n"), start, base);
|
|
dumplist ();
|
|
nocanbang ();
|
|
return;
|
|
}
|
|
y->next = shm_start;
|
|
y->prev = NULL;
|
|
if (y->next)
|
|
y->next->prev = y;
|
|
shm_start = y;
|
|
}
|
|
|
|
#define MAPPED_MALLOC_DEBUG 0
|
|
|
|
bool mapped_malloc (addrbank *ab)
|
|
{
|
|
int id;
|
|
void *answer;
|
|
shmpiece *x;
|
|
bool rtgmem = (ab->flags & ABFLAG_RTG) != 0;
|
|
static int recurse;
|
|
|
|
ab->startmask = ab->start;
|
|
if (!needmman () && (!rtgmem || currprefs.cpu_model < 68020)) {
|
|
nocanbang ();
|
|
ab->flags &= ~ABFLAG_DIRECTMAP;
|
|
if (ab->flags & ABFLAG_NOALLOC) {
|
|
#if MAPPED_MALLOC_DEBUG
|
|
write_log(_T("mapped_malloc noalloc %s\n"), ab->name);
|
|
#endif
|
|
return true;
|
|
}
|
|
ab->baseaddr = xcalloc (uae_u8, ab->allocated + 4);
|
|
#if MAPPED_MALLOC_DEBUG
|
|
write_log(_T("mapped_malloc nodirect %s %p\n"), ab->name, ab->baseaddr);
|
|
#endif
|
|
return ab->baseaddr != NULL;
|
|
}
|
|
|
|
id = shmget (IPC_PRIVATE, ab->allocated, 0x1ff, ab->label);
|
|
if (id == -1) {
|
|
nocanbang ();
|
|
if (recurse)
|
|
return NULL;
|
|
recurse++;
|
|
mapped_malloc (ab);
|
|
recurse--;
|
|
return ab->baseaddr != NULL;
|
|
}
|
|
if (!(ab->flags & ABFLAG_NOALLOC)) {
|
|
answer = shmat (ab, id, 0, 0);
|
|
shmctl (id, IPC_RMID, NULL);
|
|
} else {
|
|
answer = ab->baseaddr;
|
|
}
|
|
if (answer != (void *) -1) {
|
|
x = xmalloc (shmpiece, 1);
|
|
x->native_address = (uae_u8*)answer;
|
|
x->id = id;
|
|
x->size = ab->allocated;
|
|
x->name = ab->label;
|
|
x->next = shm_start;
|
|
x->prev = NULL;
|
|
if (x->next)
|
|
x->next->prev = x;
|
|
shm_start = x;
|
|
ab->baseaddr = x->native_address;
|
|
ab->flags |= ABFLAG_DIRECTMAP;
|
|
#if MAPPED_MALLOC_DEBUG
|
|
write_log(_T("mapped_malloc direct %s %p\n"), ab->name, ab->baseaddr);
|
|
#endif
|
|
return ab->baseaddr != NULL;
|
|
}
|
|
if (recurse)
|
|
return NULL;
|
|
nocanbang ();
|
|
recurse++;
|
|
mapped_malloc (ab);
|
|
recurse--;
|
|
#if MAPPED_MALLOC_DEBUG
|
|
write_log(_T("mapped_malloc indirect %s %p\n"), ab->name, ab->baseaddr);
|
|
#endif
|
|
return ab->baseaddr != NULL;}
|
|
|
|
#endif
|
|
|
|
static void init_mem_banks (void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MEMORY_BANKS; i++)
|
|
put_mem_bank (i << 16, &dummy_bank, 0);
|
|
#ifdef NATMEM_OFFSET
|
|
delete_shmmaps (0, 0xFFFF0000);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
#ifdef WINUAE_FOR_HATARI
|
|
/*
|
|
* Check if an address points to a memory region that causes bus error
|
|
* Returns true if region gives bus error
|
|
*/
|
|
bool memory_region_bus_error ( uaecptr addr )
|
|
{
|
|
return mem_banks[bankindex(addr)] == &BusErrMem_bank;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Initialize some extra parameters for the memory banks in CE mode
|
|
* By default, we set all banks to CHIP16 and not cachable
|
|
*
|
|
* Possible values for ce_banktype :
|
|
* CE_MEMBANK_CHIP16 shared between CPU and DMA, bus width = 16 bits
|
|
* CE_MEMBANK_CHIP32 shared between CPU and DMA, bus width = 16 bits (AGA chipset)
|
|
* CE_MEMBANK_FAST16 accessible only to the CPU, bus width = 16 bits
|
|
* CE_MEMBANK_FAST32 accessible only to the CPU, bus width = 32 bits
|
|
* CE_MEMBANK_CIA Amiga only, for CIA chips
|
|
*
|
|
* Possible values for ce_cachable :
|
|
* bit 0 : cachable yes/no (for 68030 data cache)
|
|
* bit 1 : burst mode allowed when caching yes/no (for 68030 data cache)
|
|
* (not used, check for CE_MEMBANK_FAST32 instead)
|
|
*/
|
|
static void init_ce_banks (void)
|
|
{
|
|
/* Default to CHIP16 */
|
|
memset (ce_banktype, CE_MEMBANK_CHIP16, sizeof ce_banktype);
|
|
|
|
/* Default to not cachable */
|
|
memset (ce_cachable, 0, sizeof ce_cachable);
|
|
}
|
|
|
|
|
|
/*
|
|
* For CE mode, set banktype and cachable for a memory region
|
|
*/
|
|
static void fill_ce_banks (int start, int size, int banktype, int cachable )
|
|
{
|
|
int i;
|
|
|
|
for ( i=start ; i<start+size ; i++ )
|
|
{
|
|
ce_banktype[ i ] = banktype;
|
|
ce_cachable[ i ] = cachable;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Initialize the memory banks
|
|
*/
|
|
void memory_init(uae_u32 nNewSTMemSize, uae_u32 nNewTTMemSize, uae_u32 nNewRomMemStart)
|
|
{
|
|
int addr;
|
|
|
|
currprefs.address_space_24 = ConfigureParams.System.bAddressSpace24; /* temp, do it in m68000.c */
|
|
last_address_space_24 = currprefs.address_space_24;
|
|
|
|
STmem_size = (nNewSTMemSize + 65535) & 0xFFFF0000;
|
|
TTmem_size = (nNewTTMemSize + 65535) & 0xFFFF0000;
|
|
|
|
/*write_log("memory_init: STmem_size=$%x, TTmem_size=$%x, ROM-Start=$%x,\n",
|
|
STmem_size, TTmem_size, nNewRomMemStart);*/
|
|
|
|
#if ENABLE_SMALL_MEM
|
|
|
|
/* Allocate memory for ROM areas, IDE and IO memory space (0xE00000 - 0xFFFFFF) */
|
|
ROMmemory = malloc(2*1024*1024);
|
|
if (!ROMmemory) {
|
|
fprintf(stderr, "Out of memory (ROM/IO mem)!\n");
|
|
SDL_Quit();
|
|
exit(1);
|
|
}
|
|
IdeMemory = ROMmemory + 0x100000;
|
|
IOmemory = ROMmemory + 0x1f0000;
|
|
|
|
/* Allocate memory for normal ST RAM */
|
|
STmemory = malloc(STmem_size);
|
|
while (!STmemory && STmem_size > 512*1024) {
|
|
STmem_size >>= 1;
|
|
STmemory = (uae_u8 *)malloc (STmem_size);
|
|
if (STmemory)
|
|
write_log ("Reducing STmem size to %dkb\n", STmem_size >> 10);
|
|
}
|
|
if (!STmemory) {
|
|
write_log ("virtual memory exhausted (STmemory)!\n");
|
|
SDL_Quit();
|
|
exit(1);
|
|
}
|
|
|
|
#else
|
|
|
|
/* STmemory points to the 16 MiB STRam array, we just have to set up
|
|
* the remaining pointers here: */
|
|
ROMmemory = STRam + ROMmem_start;
|
|
IdeMemory = STRam + IdeMem_start;
|
|
IOmemory = STRam + IOmem_start;
|
|
|
|
#endif
|
|
|
|
init_mem_banks();
|
|
init_ce_banks();
|
|
|
|
/* Set the infos about memory pointers for each mem bank, used for direct memory access in stMemory.c */
|
|
STmem_bank.baseaddr = STmemory;
|
|
STmem_bank.mask = STmem_mask;
|
|
STmem_bank.start = STmem_start;
|
|
|
|
SysMem_bank.baseaddr = STmemory;
|
|
SysMem_bank.mask = STmem_mask;
|
|
SysMem_bank.start = STmem_start;
|
|
|
|
dummy_bank.baseaddr = NULL; /* No real memory allocated for this region */
|
|
VoidMem_bank.baseaddr = NULL; /* No real memory allocated for this region */
|
|
BusErrMem_bank.baseaddr = NULL; /* No real memory allocated for this region */
|
|
|
|
|
|
/* Map the ST system RAM: */
|
|
map_banks_ce(&SysMem_bank, 0x00, 1, 0, CE_MEMBANK_CHIP16, CE_MEMBANK_CACHABLE);
|
|
/* Between STRamEnd and 4MB barrier, there is void space: */
|
|
map_banks_ce(&VoidMem_bank, 0x08, 0x38, 0, CE_MEMBANK_CHIP16, CE_MEMBANK_NOT_CACHABLE);
|
|
/* Space between 4MB barrier and TOS ROM causes a bus error: */
|
|
map_banks_ce(&BusErrMem_bank, 0x400000 >> 16, 0xA0, 0 , CE_MEMBANK_CHIP16, CE_MEMBANK_NOT_CACHABLE);
|
|
/* Now map main ST RAM, overwriting the void and bus error regions if necessary: */
|
|
map_banks_ce(&STmem_bank, 0x01, (STmem_size >> 16) - 1, 0, CE_MEMBANK_CHIP16, CE_MEMBANK_CACHABLE);
|
|
|
|
|
|
/* Handle extra RAM on TT and Falcon starting at 0x1000000 and up to 0x80000000 */
|
|
/* This requires the CPU to use 32 bit addressing */
|
|
TTmemory = NULL;
|
|
if ( ConfigureParams.System.bAddressSpace24 == false )
|
|
{
|
|
/* If there's no extra RAM on a TT, region 0x01000000 - 0x80000000 (2047 MB) must return bus errors */
|
|
if ( ConfigureParams.System.nMachineType == MACHINE_TT )
|
|
map_banks_ce ( &BusErrMem_bank, TTmem_start >> 16, ( TTmem_end - TTmem_start ) >> 16, 0, CE_MEMBANK_CHIP16, CE_MEMBANK_NOT_CACHABLE);
|
|
|
|
if ( TTmem_size > 0 )
|
|
{
|
|
TTmemory = (uae_u8 *)malloc ( TTmem_size );
|
|
|
|
if ( TTmemory != NULL )
|
|
{
|
|
/* 32 bit RAM for CPU only + cache/burst allowed */
|
|
map_banks_ce ( &TTmem_bank, TTmem_start >> 16, TTmem_size >> 16, 0, CE_MEMBANK_FAST32, CE_MEMBANK_CACHABLE_BURST );
|
|
TTmem_mask = 0xffffffff;
|
|
TTmem_bank.baseaddr = TTmemory;
|
|
TTmem_bank.mask = TTmem_mask;
|
|
TTmem_bank.start = TTmem_start;
|
|
}
|
|
else
|
|
{
|
|
write_log ("can't allocate %d MB for TT RAM\n" , TTmem_size / ( 1024*1024 ) );
|
|
TTmem_size = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* ROM memory: */
|
|
/* Depending on which ROM version we are using, the other ROM region is illegal! */
|
|
if(nNewRomMemStart == 0xFC0000)
|
|
{
|
|
map_banks_ce(&ROMmem_bank, 0xFC0000 >> 16, 0x3, 0, CE_MEMBANK_CHIP16, CE_MEMBANK_CACHABLE); /* [NP] FIXME test needed on real STF, could be FAST16 in fact */
|
|
map_banks_ce(&BusErrMem_bank, 0xE00000 >> 16, 0x10, 0, CE_MEMBANK_CHIP16, CE_MEMBANK_NOT_CACHABLE);
|
|
}
|
|
else if(nNewRomMemStart == 0xE00000)
|
|
{
|
|
map_banks_ce(&ROMmem_bank, 0xE00000 >> 16, 0x10, 0, CE_MEMBANK_CHIP16, CE_MEMBANK_CACHABLE); /* [NP] FIXME test needed on real STF, could be FAST16 in fact */
|
|
map_banks_ce(&BusErrMem_bank, 0xFC0000 >> 16, 0x3, 0, CE_MEMBANK_CHIP16, CE_MEMBANK_NOT_CACHABLE);
|
|
}
|
|
else
|
|
{
|
|
write_log("Illegal ROM memory start!\n");
|
|
}
|
|
|
|
/* Cartridge memory: */
|
|
map_banks_ce(&ROMmem_bank, 0xFA0000 >> 16, 0x2, 0, CE_MEMBANK_CHIP16, CE_MEMBANK_CACHABLE); /* [NP] FIXME test needed on real STF, could be FAST16 in fact */
|
|
ROMmem_bank.baseaddr = ROMmemory;
|
|
ROMmem_bank.mask = ROMmem_mask;
|
|
ROMmem_bank.start = ROMmem_start;
|
|
|
|
/* IO memory: */
|
|
map_banks_ce(&IOmem_bank, IOmem_start>>16, 0x1, 0, CE_MEMBANK_CHIP16, CE_MEMBANK_NOT_CACHABLE);
|
|
IOmem_bank.baseaddr = IOmemory;
|
|
IOmem_bank.mask = IOmem_mask;
|
|
IOmem_bank.start = IOmem_start;
|
|
|
|
/* IDE controller memory region: */
|
|
map_banks_ce(&IdeMem_bank, IdeMem_start >> 16, 0x1, 0, CE_MEMBANK_CHIP16, CE_MEMBANK_NOT_CACHABLE); /* IDE controller on the Falcon */
|
|
IdeMem_bank.baseaddr = IdeMemory;
|
|
IdeMem_bank.mask = IdeMem_mask;
|
|
IdeMem_bank.start = IdeMem_start ;
|
|
|
|
/* Illegal memory regions cause a bus error on the ST: */
|
|
map_banks_ce(&BusErrMem_bank, 0xF10000 >> 16, 0x9, 0, CE_MEMBANK_CHIP16, CE_MEMBANK_NOT_CACHABLE);
|
|
|
|
|
|
/* If MMU is disabled on TT/Falcon and we use full 32 bit addressing */
|
|
/* then we remap memory 00xxxxxx to FFxxxxxx (as a minimal replacement */
|
|
/* for the MMU's tables). Else, we get some crashes when booting TOS 3 and 4 */
|
|
if ( ( ConfigureParams.System.bAddressSpace24 == false )
|
|
&& ( ConfigureParams.System.bMMU == false )
|
|
&& ( ( ConfigureParams.System.nMachineType == MACHINE_TT )
|
|
|| ( ConfigureParams.System.nMachineType == MACHINE_FALCON ) ) )
|
|
{
|
|
/* Copy all 256 banks 0x0000-0x00FF to banks 0xFF00-0xFFFF */
|
|
for ( addr=0x0 ; addr<=0x00ffffff ; addr+=0x10000 )
|
|
{
|
|
//printf ( "put mem %x %x\n" , addr , addr|0xff000000 );
|
|
put_mem_bank ( 0xff000000|addr , &get_mem_bank ( addr ) , 0 );
|
|
|
|
/* Copy the CE parameters */
|
|
ce_banktype[ (0xff000000|addr)>>16 ] = ce_banktype[ addr>>16 ];
|
|
ce_cachable[ (0xff000000|addr)>>16 ] = ce_cachable[ addr>>16 ];
|
|
}
|
|
}
|
|
|
|
illegal_count = 50;
|
|
}
|
|
|
|
|
|
/*
|
|
* Uninitialize the memory banks.
|
|
*/
|
|
void memory_uninit (void)
|
|
{
|
|
/* Here, we free allocated memory from memory_init */
|
|
if (TTmemory) {
|
|
free(TTmemory);
|
|
TTmemory = NULL;
|
|
}
|
|
|
|
#if ENABLE_SMALL_MEM
|
|
|
|
if (STmemory) {
|
|
free(STmemory);
|
|
STmemory = NULL;
|
|
}
|
|
|
|
if (ROMmemory) {
|
|
free(ROMmemory);
|
|
ROMmemory = NULL;
|
|
}
|
|
|
|
#endif /* ENABLE_SMALL_MEM */
|
|
}
|
|
|
|
|
|
static void map_banks2 (addrbank *bank, int start, int size, int realsize, int quick)
|
|
{
|
|
#ifndef WINUAE_FOR_HATARI
|
|
int bnr, old;
|
|
unsigned long int hioffs = 0, endhioffs = 0x100;
|
|
addrbank *orgbank = bank;
|
|
uae_u32 realstart = start;
|
|
#else
|
|
int bnr;
|
|
unsigned long int hioffs = 0, endhioffs = 0x100;
|
|
uae_u32 realstart = start;
|
|
#endif
|
|
|
|
//printf ( "map %x %x 24=%d\n" , start<<16 , size<<16 , currprefs.address_space_24 );
|
|
#ifndef WINUAE_FOR_HATARI
|
|
if (quick <= 0)
|
|
old = debug_bankchange (-1);
|
|
#endif
|
|
flush_icache_hard (0, 3); /* Sure don't want to keep any old mappings around! */
|
|
#ifdef NATMEM_OFFSET
|
|
if (!quick)
|
|
delete_shmmaps (start << 16, size << 16);
|
|
#endif
|
|
|
|
if (!realsize)
|
|
realsize = size << 16;
|
|
|
|
if ((size << 16) < realsize) {
|
|
write_log (_T("Broken mapping, size=%x, realsize=%x\nStart is %x\n"),
|
|
size, realsize, start);
|
|
}
|
|
|
|
#ifndef ADDRESS_SPACE_24BIT
|
|
if (start >= 0x100) {
|
|
int real_left = 0;
|
|
for (bnr = start; bnr < start + size; bnr++) {
|
|
if (!real_left) {
|
|
realstart = bnr;
|
|
real_left = realsize >> 16;
|
|
#ifdef NATMEM_OFFSET
|
|
if (!quick)
|
|
add_shmmaps (realstart << 16, bank);
|
|
#endif
|
|
}
|
|
put_mem_bank (bnr << 16, bank, realstart << 16);
|
|
real_left--;
|
|
}
|
|
#ifndef WINUAE_FOR_HATARI
|
|
if (quick <= 0)
|
|
debug_bankchange (old);
|
|
#endif
|
|
return;
|
|
}
|
|
#endif
|
|
if (last_address_space_24)
|
|
endhioffs = 0x10000;
|
|
#ifdef ADDRESS_SPACE_24BIT
|
|
endhioffs = 0x100;
|
|
#endif
|
|
for (hioffs = 0; hioffs < endhioffs; hioffs += 0x100) {
|
|
int real_left = 0;
|
|
for (bnr = start; bnr < start + size; bnr++) {
|
|
if (!real_left) {
|
|
realstart = bnr + hioffs;
|
|
real_left = realsize >> 16;
|
|
#ifdef NATMEM_OFFSET
|
|
if (!quick)
|
|
add_shmmaps (realstart << 16, bank);
|
|
#endif
|
|
}
|
|
put_mem_bank ((bnr + hioffs) << 16, bank, realstart << 16);
|
|
real_left--;
|
|
}
|
|
}
|
|
#ifndef WINUAE_FOR_HATARI
|
|
if (quick <= 0)
|
|
debug_bankchange (old);
|
|
fill_ce_banks ();
|
|
#endif
|
|
}
|
|
|
|
void map_banks (addrbank *bank, int start, int size, int realsize)
|
|
{
|
|
map_banks2 (bank, start, size, realsize, 0);
|
|
}
|
|
void map_banks_quick (addrbank *bank, int start, int size, int realsize)
|
|
{
|
|
map_banks2 (bank, start, size, realsize, 1);
|
|
}
|
|
void map_banks_nojitdirect (addrbank *bank, int start, int size, int realsize)
|
|
{
|
|
map_banks2 (bank, start, size, realsize, -1);
|
|
}
|
|
|
|
void map_banks_ce (addrbank *bank, int start, int size, int realsize , int banktype, int cachable )
|
|
{
|
|
map_banks2 (bank, start, size, realsize, 0);
|
|
fill_ce_banks (start, size, banktype, cachable );
|
|
}
|
|
|
|
|
|
|
|
|
|
void memory_hardreset (void)
|
|
{
|
|
}
|