2013-02-06 04:11:41 +00:00
|
|
|
/*=========================================================================*/
|
|
|
|
/* Fellow */
|
|
|
|
/* Virtual Memory System */
|
|
|
|
/* */
|
|
|
|
/* Authors: Petter Schau, Torsten Enderling */
|
|
|
|
/* */
|
|
|
|
/* This program is free software; you can redistribute it and/or modify */
|
|
|
|
/* it under the terms of the GNU General Public License as published by */
|
|
|
|
/* the Free Software Foundation; either version 2, or (at your option) */
|
|
|
|
/* any later version. */
|
|
|
|
/* */
|
|
|
|
/* This program is distributed in the hope that it will be useful, */
|
|
|
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
|
|
|
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
|
|
|
|
/* GNU General Public License for more details. */
|
|
|
|
/* */
|
|
|
|
/* You should have received a copy of the GNU General Public License */
|
|
|
|
/* along with this program; if not, write to the Free Software Foundation, */
|
|
|
|
/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
|
|
/*=========================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
#ifdef _FELLOW_DEBUG_CRT_MALLOC
|
|
|
|
#define _CRTDBG_MAP_ALLOC
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <crtdbg.h>
|
|
|
|
#endif
|
|
|
|
|
2013-02-06 04:11:41 +00:00
|
|
|
#include "defs.h"
|
|
|
|
#include "fellow.h"
|
2023-10-05 22:47:48 +00:00
|
|
|
#include "chipset.h"
|
2013-02-06 04:11:41 +00:00
|
|
|
#include "draw.h"
|
|
|
|
#include "CpuModule.h"
|
|
|
|
#include "CpuIntegration.h"
|
2023-10-05 22:47:48 +00:00
|
|
|
#include "fellow/api/module/IHardfileHandler.h"
|
2013-02-06 04:11:41 +00:00
|
|
|
#include "graph.h"
|
|
|
|
#include "floppy.h"
|
|
|
|
#include "copper.h"
|
|
|
|
#include "cia.h"
|
|
|
|
#include "blit.h"
|
|
|
|
#include "fmem.h"
|
|
|
|
#include "fswrap.h"
|
|
|
|
#include "wgui.h"
|
2023-10-05 22:47:48 +00:00
|
|
|
#include "rtc.h"
|
|
|
|
#include "fileops.h"
|
|
|
|
#include "zlib.h" // crc32 function
|
2013-02-06 04:11:41 +00:00
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
#include <tchar.h>
|
|
|
|
#endif
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
using namespace fellow::api::module;
|
|
|
|
|
2013-02-06 04:11:41 +00:00
|
|
|
/*============================================================================*/
|
|
|
|
/* Holds configuration for memory */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memory_chipsize;
|
|
|
|
uint32_t memory_fastsize;
|
|
|
|
uint32_t memory_slowsize;
|
|
|
|
bool memory_useautoconfig;
|
2013-02-06 04:11:41 +00:00
|
|
|
BOOLE memory_address32bit;
|
2023-10-05 22:47:48 +00:00
|
|
|
char memory_kickimage[CFG_FILENAME_LENGTH];
|
|
|
|
char memory_kickimage_ext[CFG_FILENAME_LENGTH];
|
|
|
|
char memory_key[256];
|
|
|
|
bool memory_a1000_wcs = false; ///< emulate the Amiga 1000 WCS (writable control store)
|
|
|
|
uint8_t *memory_a1000_bootstrap = NULL; ///< hold A1000 bootstrap ROM, if used
|
|
|
|
bool memory_a1000_bootstrap_mapped = false; ///< true while A1000 bootstrap ROM mapped to KS area
|
2013-02-06 04:11:41 +00:00
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Holds actual memory */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t memory_chip[0x200000 + 32];
|
|
|
|
uint8_t memory_slow[0x1c0000 + 32];
|
|
|
|
uint8_t memory_kick[0x080000 + 32];
|
|
|
|
uint8_t *memory_kick_ext = NULL;
|
|
|
|
uint8_t *memory_fast = NULL;
|
|
|
|
uint32_t memory_fast_baseaddress;
|
|
|
|
uint32_t memory_fastallocatedsize;
|
|
|
|
uint8_t *memory_slow_base;
|
2013-02-06 04:11:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Autoconfig data */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
#define EMEM_MAXARDS 4
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t memory_emem[0x10000];
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryEmemCardInitFunc memory_ememard_initfunc[EMEM_MAXARDS];
|
|
|
|
memoryEmemCardMapFunc memory_ememard_mapfunc[EMEM_MAXARDS];
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memory_ememardcount; /* Number of cards */
|
|
|
|
uint32_t memory_ememards_finishedcount; /* Current card */
|
2013-02-06 04:11:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Device memory data */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
#define MEMORY_DMEM_OFFSET 0xf40000
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t memory_dmem[65536];
|
|
|
|
uint32_t memory_dmemcounter;
|
2013-02-06 04:11:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Additional Kickstart data */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memory_initial_PC;
|
|
|
|
uint32_t memory_initial_SP;
|
2013-02-06 04:11:41 +00:00
|
|
|
BOOLE memory_kickimage_none;
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memory_kickimage_size;
|
|
|
|
uint32_t memory_kickimage_version;
|
|
|
|
char memory_kickimage_versionstr[80];
|
|
|
|
uint32_t memory_kickimage_basebank;
|
|
|
|
uint32_t memory_kickimage_ext_size = 0;
|
|
|
|
uint32_t memory_kickimage_ext_basebank = 0;
|
|
|
|
const char *memory_kickimage_versionstrings[14] = {
|
2013-02-06 04:11:41 +00:00
|
|
|
"Kickstart, version information unavailable",
|
|
|
|
"Kickstart Pre-V1.0",
|
|
|
|
"Kickstart V1.0",
|
|
|
|
"Kickstart V1.1 (NTSC)",
|
|
|
|
"Kickstart V1.1 (PAL)",
|
|
|
|
"Kickstart V1.2",
|
|
|
|
"Kickstart V1.3",
|
|
|
|
"Kickstart V1.3",
|
|
|
|
"Kickstart V2.0",
|
|
|
|
"Kickstart V2.04",
|
|
|
|
"Kickstart V2.1",
|
|
|
|
"Kickstart V3.0",
|
|
|
|
"Kickstart V3.1",
|
|
|
|
"Kickstart Post-V3.1"};
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryKickSettingsClear();
|
2013-02-06 04:11:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Illegal read / write fault information */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
BOOLE memory_fault_read; /* TRUE - read / FALSE - write */
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memory_fault_address;
|
2013-02-06 04:11:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Some run-time scratch variables */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryKickA1000BootstrapSetMapped(const bool);
|
2013-02-06 04:11:41 +00:00
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryWriteByteToPointer(uint8_t data, uint8_t *address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
address[0] = data;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryWriteWordToPointer(uint16_t data, uint8_t *address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
address[0] = (uint8_t) (data >> 8);
|
|
|
|
address[1] = (uint8_t) data;
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryWriteLongToPointer(uint32_t data, uint8_t *address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
address[0] = (uint8_t) (data >> 24);
|
|
|
|
address[1] = (uint8_t) (data >> 16);
|
|
|
|
address[2] = (uint8_t) (data >> 8);
|
|
|
|
address[3] = (uint8_t) data;
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------
|
2023-10-05 22:47:48 +00:00
|
|
|
Chip read register functions
|
2013-02-06 04:11:41 +00:00
|
|
|
----------------------------*/
|
|
|
|
|
|
|
|
// To simulate noise, return 0 and -1 every second time.
|
|
|
|
// Why? Bugged demos test write-only registers for various bit-values
|
|
|
|
// and to break out of loops, both 0 and 1 values must be returned.
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint16_t rdefault(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
return (uint16_t)(rand() % 65536);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void wdefault(uint16_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Table of register read/write functions */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
memoryIoReadFunc memory_iobank_read[257]; // Account for long writes to the last
|
|
|
|
memoryIoWriteFunc memory_iobank_write[257]; // word
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Memory mapping tables */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
memoryReadByteFunc memory_bank_readbyte[65536];
|
|
|
|
memoryReadWordFunc memory_bank_readword[65536];
|
|
|
|
memoryReadLongFunc memory_bank_readlong[65536];
|
|
|
|
memoryWriteByteFunc memory_bank_writebyte[65536];
|
|
|
|
memoryWriteWordFunc memory_bank_writeword[65536];
|
|
|
|
memoryWriteLongFunc memory_bank_writelong[65536];
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *memory_bank_pointer[65536]; /* Used by the filesystem */
|
2013-02-06 04:11:41 +00:00
|
|
|
BOOLE memory_bank_pointer_can_write[65536];
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Memory bank mapping functions */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Set read and write stubs for a bank, as well as a direct pointer to */
|
|
|
|
/* its memory. NULL pointer is passed when the memory must always be */
|
2023-10-05 22:47:48 +00:00
|
|
|
/* read through the stubs, like in a bank of regsters where writing */
|
2013-02-06 04:11:41 +00:00
|
|
|
/* or reading the value generates side-effects. */
|
|
|
|
/* Datadirect is TRUE when data accesses can be made through a pointer */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryBankSet(memoryReadByteFunc rb,
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryReadWordFunc rw,
|
|
|
|
memoryReadLongFunc rl,
|
|
|
|
memoryWriteByteFunc wb,
|
|
|
|
memoryWriteWordFunc ww,
|
|
|
|
memoryWriteLongFunc wl,
|
|
|
|
uint8_t *basep,
|
|
|
|
uint32_t bank,
|
|
|
|
uint32_t basebank,
|
|
|
|
BOOLE pointer_can_write)
|
|
|
|
{
|
|
|
|
uint32_t j = (memoryGetAddress32Bit()) ? 65536 : 256;
|
|
|
|
for (uint32_t i = bank; i < 65536; i += j)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
memory_bank_readbyte[i] = rb;
|
|
|
|
memory_bank_readword[i] = rw;
|
|
|
|
memory_bank_readlong[i] = rl;
|
|
|
|
memory_bank_writebyte[i] = wb;
|
|
|
|
memory_bank_writeword[i] = ww;
|
|
|
|
memory_bank_writelong[i] = wl;
|
|
|
|
memory_bank_pointer_can_write[i] = pointer_can_write;
|
|
|
|
|
|
|
|
if (basep != NULL)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
memory_bank_pointer[i] = basep - (basebank<<16);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
memory_bank_pointer[i] = NULL;
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
basebank += j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Clear one bank data to safe "do-nothing" values */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
/* Unmapped memory interface */
|
2023-10-05 22:47:48 +00:00
|
|
|
// Some memory tests use CLR to write and read present memory (Last Ninja 2), so 0 can not be returned, ever.
|
2013-02-06 04:11:41 +00:00
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
static uint8_t memory_previous_unmapped_byte = 0;
|
|
|
|
uint8_t memoryUnmappedReadByte(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t val;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
val = rand() % 256;
|
|
|
|
}
|
|
|
|
while (val == 0 || val == memory_previous_unmapped_byte);
|
|
|
|
|
|
|
|
memory_previous_unmapped_byte = val;
|
|
|
|
return val;
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
static uint16_t memory_previous_unmapped_word = 0;
|
|
|
|
uint16_t memoryUnmappedReadWord(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint16_t val;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
val = rand() % 65536;
|
|
|
|
} while (val == 0 || val == memory_previous_unmapped_word);
|
|
|
|
|
|
|
|
memory_previous_unmapped_word = val;
|
|
|
|
return val;
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
static uint32_t memory_previous_unmapped_long = 0;
|
|
|
|
uint32_t memoryUnmappedReadLong(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t val;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
val = rand();
|
|
|
|
} while (val == 0 || val == memory_previous_unmapped_long);
|
|
|
|
|
|
|
|
memory_previous_unmapped_long = val;
|
|
|
|
return val;
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryUnmappedWriteByte(uint8_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
// NOP
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryUnmappedWriteWord(uint16_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
// NOP
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryUnmappedWriteLong(uint32_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
// NOP
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryBankClear(uint32_t bank)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
memoryBankSet(memoryUnmappedReadByte,
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryUnmappedReadWord,
|
|
|
|
memoryUnmappedReadLong,
|
|
|
|
memoryUnmappedWriteByte,
|
|
|
|
memoryUnmappedWriteWord,
|
|
|
|
memoryUnmappedWriteLong,
|
|
|
|
NULL,
|
|
|
|
bank,
|
|
|
|
0,
|
|
|
|
FALSE);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Clear all bank data to safe "do-nothing" values */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryBankClearAll(void)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t hilim = (memoryGetAddress32Bit()) ? 65536 : 256;
|
|
|
|
for (uint32_t bank = 0; bank < hilim; bank++)
|
|
|
|
{
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryBankClear(bank);
|
2023-10-05 22:47:48 +00:00
|
|
|
}
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Expansion cards autoconfig */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Clear the expansion config bank */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryEmemClear(void)
|
|
|
|
{
|
|
|
|
memset(memory_emem, 0xff, 65536);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Add card to table */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryEmemCardAdd(memoryEmemCardInitFunc cardinit,
|
|
|
|
memoryEmemCardMapFunc cardmap)
|
|
|
|
{
|
|
|
|
if (memory_ememardcount < EMEM_MAXARDS)
|
|
|
|
{
|
|
|
|
memory_ememard_initfunc[memory_ememardcount] = cardinit;
|
|
|
|
memory_ememard_mapfunc[memory_ememardcount] = cardmap;
|
|
|
|
memory_ememardcount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Advance the card pointer */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryEmemCardNext(void)
|
|
|
|
{
|
|
|
|
memory_ememards_finishedcount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Init the current card */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryEmemCardInit(void)
|
|
|
|
{
|
|
|
|
memoryEmemClear();
|
|
|
|
if (memory_ememards_finishedcount != memory_ememardcount)
|
|
|
|
memory_ememard_initfunc[memory_ememards_finishedcount]();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Map this card */
|
|
|
|
/* Mapping is bank number set by AmigaOS */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryEmemCardMap(uint32_t mapping)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
if (memory_ememards_finishedcount == memory_ememardcount)
|
|
|
|
memoryEmemClear();
|
|
|
|
else
|
|
|
|
memory_ememard_mapfunc[memory_ememards_finishedcount](mapping);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Reset card setup */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryEmemCardsReset(void)
|
|
|
|
{
|
|
|
|
memory_ememards_finishedcount = 0;
|
|
|
|
memoryEmemCardInit();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Clear the card table */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryEmemCardsRemove(void)
|
|
|
|
{
|
|
|
|
memory_ememardcount = memory_ememards_finishedcount = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Set a byte in autoconfig space, for initfunc routines */
|
|
|
|
/* so they can make their configuration visible */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryEmemSet(uint32_t index, uint32_t value)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
index &= 0xffff;
|
|
|
|
switch (index)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
case 2:
|
|
|
|
case 0x40:
|
|
|
|
case 0x42:
|
2023-10-05 22:47:48 +00:00
|
|
|
memory_emem[index] = (uint8_t) (value & 0xf0);
|
|
|
|
memory_emem[index + 2] = (uint8_t) ((value & 0xf)<<4);
|
2013-02-06 04:11:41 +00:00
|
|
|
break;
|
|
|
|
default:
|
2023-10-05 22:47:48 +00:00
|
|
|
memory_emem[index] = (uint8_t) (~(value & 0xf0));
|
|
|
|
memory_emem[index + 2] = (uint8_t) (~((value & 0xf)<<4));
|
2013-02-06 04:11:41 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Copy data into emem space */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryEmemMirror(uint32_t emem_offset, uint8_t *src, uint32_t size)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
memcpy(memory_emem + emem_offset, src, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Read/Write stubs for autoconfig memory */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t memoryEmemReadByte(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_emem + (address & 0xffff);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadByteFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint16_t memoryEmemReadWord(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_emem + (address & 0xffff);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadWordFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryEmemReadLong(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_emem + (address & 0xffff);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadLongFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryEmemWriteByte(uint8_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
static uint32_t mapping;
|
2013-02-06 04:11:41 +00:00
|
|
|
|
|
|
|
switch (address & 0xffff)
|
|
|
|
{
|
|
|
|
case 0x30:
|
|
|
|
case 0x32:
|
|
|
|
mapping = data = 0;
|
|
|
|
case 0x48:
|
2023-10-05 22:47:48 +00:00
|
|
|
mapping = (mapping & 0xff) | (((uint32_t)data) << 8);
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryEmemCardMap(mapping);
|
|
|
|
memoryEmemCardNext();
|
|
|
|
memoryEmemCardInit();
|
|
|
|
break;
|
|
|
|
case 0x4a:
|
2023-10-05 22:47:48 +00:00
|
|
|
mapping = (mapping & 0xff00) | ((uint32_t)data);
|
2013-02-06 04:11:41 +00:00
|
|
|
break;
|
|
|
|
case 0x4c:
|
|
|
|
memoryEmemCardNext();
|
|
|
|
memoryEmemCardInit();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryEmemWriteWord(uint16_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryEmemWriteLong(uint32_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*/
|
|
|
|
/* Map the autoconfig memory bank into memory */
|
|
|
|
/*===========================================================================*/
|
|
|
|
|
|
|
|
void memoryEmemMap(void)
|
|
|
|
{
|
|
|
|
if (memoryGetKickImageBaseBank() >= 0xf8)
|
2023-10-05 22:47:48 +00:00
|
|
|
{
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryBankSet(memoryEmemReadByte,
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryEmemReadWord,
|
|
|
|
memoryEmemReadLong,
|
|
|
|
memoryEmemWriteByte,
|
|
|
|
memoryEmemWriteWord,
|
|
|
|
memoryEmemWriteLong,
|
|
|
|
NULL,
|
|
|
|
0xe8,
|
|
|
|
0xe8,
|
|
|
|
FALSE);
|
|
|
|
}
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*===================*/
|
|
|
|
/* End of autoconfig */
|
|
|
|
/*===================*/
|
|
|
|
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* dmem is the data area used by the hardfile device to communicate info */
|
|
|
|
/* about itself with the Amiga */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Functions to set data in dmem by the native device drivers */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t memoryDmemReadByte(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_dmem + (address & 0xffff);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadByteFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint16_t memoryDmemReadWord(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_dmem + (address & 0xffff);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadWordFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryDmemReadLong(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_dmem + (address & 0xffff);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadLongFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryDmemWriteByte(uint8_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
// NOP
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryDmemWriteWord(uint16_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
// NOP
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Writing a long to $f40000 runs a native function */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryDmemWriteLong(uint32_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
if ((address & 0xffffff) == 0xf40000)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
HardfileHandler->Do(data);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryDmemClear(void)
|
|
|
|
{
|
|
|
|
memset(memory_dmem, 0, 4096);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryDmemSetCounter(uint32_t c)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
memory_dmemcounter = c;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryDmemGetCounterWithoutOffset(void)
|
|
|
|
{
|
|
|
|
return memory_dmemcounter;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t memoryDmemGetCounter(void)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
return memory_dmemcounter + MEMORY_DMEM_OFFSET;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryDmemSetString(const char *st)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
strcpy((char *) (memory_dmem + memory_dmemcounter), st);
|
|
|
|
memory_dmemcounter += (uint32_t) strlen(st) + 1;
|
2013-02-06 04:11:41 +00:00
|
|
|
if (memory_dmemcounter & 1) memory_dmemcounter++;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryDmemSetByte(uint8_t data)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
memory_dmem[memory_dmemcounter++] = data;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryDmemSetWord(uint16_t data)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
memoryWriteWordToPointer(data, memory_dmem + memory_dmemcounter);
|
|
|
|
memory_dmemcounter += 2;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryDmemSetLong(uint32_t data)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
memoryWriteLongToPointer(data, memory_dmem + memory_dmemcounter);
|
|
|
|
memory_dmemcounter += 4;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryDmemSetLongNoCounter(uint32_t data, uint32_t offset)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
memoryWriteLongToPointer(data, memory_dmem + offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryDmemMap(void)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t bank = 0xf40000>>16;
|
2013-02-06 04:11:41 +00:00
|
|
|
|
|
|
|
if (memory_useautoconfig && (memory_kickimage_basebank >= 0xf8))
|
2023-10-05 22:47:48 +00:00
|
|
|
{
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryBankSet(memoryDmemReadByte,
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryDmemReadWord,
|
|
|
|
memoryDmemReadLong,
|
|
|
|
memoryDmemWriteByte,
|
|
|
|
memoryDmemWriteWord,
|
|
|
|
memoryDmemWriteLong,
|
|
|
|
memory_dmem,
|
|
|
|
bank,
|
|
|
|
bank,
|
|
|
|
FALSE);
|
|
|
|
}
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Converts an address to a direct pointer to memory. Used by hardfile device */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *memoryAddressToPtr(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *result = memory_bank_pointer[address>>16];
|
2013-02-06 04:11:41 +00:00
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
if (result != NULL)
|
2013-02-06 04:11:41 +00:00
|
|
|
result += address;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Chip memory handling */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
#define chipmemMaskAddress(ptr) ((ptr) & chipset.address_mask)
|
|
|
|
|
|
|
|
uint8_t memoryChipReadByte(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_chip + chipmemMaskAddress(address);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadByteFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint16_t memoryChipReadWord(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_chip + chipmemMaskAddress(address);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadWordFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryChipReadLong(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_chip + chipmemMaskAddress(address);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadLongFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryChipWriteByte(uint8_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_chip + chipmemMaskAddress(address);
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryWriteByteToPointer(data, p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryChipWriteWord(uint16_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_chip + chipmemMaskAddress(address);
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryWriteWordToPointer(data, p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryChipWriteLong(uint32_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_chip + chipmemMaskAddress(address);
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryWriteLongToPointer(data, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryChipClear(void)
|
|
|
|
{
|
|
|
|
memset(memory_chip, 0, memoryGetChipSize());
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t memoryOverlayReadByte(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_kick + (address & 0xffffff);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadByteFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint16_t memoryOverlayReadWord(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_kick + (address & 0xffffff);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadWordFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryOverlayReadLong(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_kick + (address & 0xffffff);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadLongFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryOverlayWriteByte(uint8_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
// NOP
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryOverlayWriteWord(uint16_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
// NOP
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryOverlayWriteLong(uint32_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
// NOP
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryChipGetLastBank(void)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t lastbank = memoryGetChipSize()>>16;
|
2013-02-06 04:11:41 +00:00
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
if (chipsetGetECS())
|
|
|
|
{
|
|
|
|
return (lastbank <= 32) ? lastbank : 32;
|
|
|
|
}
|
|
|
|
|
|
|
|
// OCS
|
|
|
|
return (lastbank <= 8) ? lastbank : 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryChipMap(bool overlay)
|
|
|
|
{
|
|
|
|
uint32_t bank;
|
|
|
|
|
|
|
|
// Build first, "real" chipmem area
|
2013-02-06 04:11:41 +00:00
|
|
|
if (overlay)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
// 256k ROMs are already mirrored once in the memory_kick area
|
|
|
|
// Map entire 512k ROM area to $0
|
2013-02-06 04:11:41 +00:00
|
|
|
for (bank = 0; bank < 8; bank++)
|
2023-10-05 22:47:48 +00:00
|
|
|
{
|
|
|
|
memoryBankSet(memoryOverlayReadByte,
|
|
|
|
memoryOverlayReadWord,
|
|
|
|
memoryOverlayReadLong,
|
|
|
|
memoryOverlayWriteByte,
|
|
|
|
memoryOverlayWriteWord,
|
|
|
|
memoryOverlayWriteLong,
|
|
|
|
memory_kick,
|
|
|
|
bank,
|
|
|
|
0,
|
|
|
|
FALSE);
|
|
|
|
}
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
// Map 512k to 2MB of chip memory, possibly skipping the overlay area
|
|
|
|
uint32_t lastbank = memoryChipGetLastBank();
|
2013-02-06 04:11:41 +00:00
|
|
|
for (bank = (overlay) ? 8 : 0; bank < lastbank; bank++)
|
2023-10-05 22:47:48 +00:00
|
|
|
{
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryBankSet(memoryChipReadByte,
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryChipReadWord,
|
|
|
|
memoryChipReadLong,
|
|
|
|
memoryChipWriteByte,
|
|
|
|
memoryChipWriteWord,
|
|
|
|
memoryChipWriteLong,
|
|
|
|
memory_chip,
|
|
|
|
bank,
|
|
|
|
0,
|
|
|
|
TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// In the case of 256k chip memory and not overlaying, clear the second 256k map
|
|
|
|
// as this area could have been mapped for the ROM overlay
|
|
|
|
if (lastbank < 8 && !overlay)
|
|
|
|
{
|
|
|
|
for (bank = lastbank; bank < 8; ++bank)
|
|
|
|
{
|
|
|
|
memoryBankClear(bank);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!chipsetGetECS())
|
|
|
|
{
|
|
|
|
// OCS: Make 3 more copies of the chipram at $80000, $100000 and $180000
|
|
|
|
for (uint32_t i = 1; i < 4; ++i)
|
|
|
|
{
|
|
|
|
uint32_t bank_start = 8*i;
|
|
|
|
uint32_t bank_end = bank_start + lastbank;
|
|
|
|
for (bank = bank_start; bank < bank_end; bank++)
|
|
|
|
{
|
|
|
|
memoryBankSet(memoryChipReadByte,
|
|
|
|
memoryChipReadWord,
|
|
|
|
memoryChipReadLong,
|
|
|
|
memoryChipWriteByte,
|
|
|
|
memoryChipWriteWord,
|
|
|
|
memoryChipWriteLong,
|
|
|
|
memory_chip,
|
|
|
|
bank,
|
|
|
|
bank_start,
|
|
|
|
TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Fast memory handling */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t memoryFastReadByte(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_fast + ((address & 0xffffff) - memory_fast_baseaddress);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadByteFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint16_t memoryFastReadWord(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_fast + ((address & 0xffffff) - memory_fast_baseaddress);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadWordFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryFastReadLong(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_fast + ((address & 0xffffff) - memory_fast_baseaddress);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadLongFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryFastWriteByte(uint8_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_fast + ((address & 0xffffff) - memory_fast_baseaddress);
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryWriteByteToPointer(data, p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryFastWriteWord(uint16_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_fast + ((address & 0xffffff) - memory_fast_baseaddress);
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryWriteWordToPointer(data, p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryFastWriteLong(uint32_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_fast + ((address & 0xffffff) - memory_fast_baseaddress);
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryWriteLongToPointer(data, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Set up autoconfig values for fastmem card */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryFastCardInit(void)
|
|
|
|
{
|
|
|
|
if (memoryGetFastSize() == 0x100000) memoryEmemSet(0, 0xe5);
|
|
|
|
else if (memoryGetFastSize() == 0x200000) memoryEmemSet(0, 0xe6);
|
|
|
|
else if (memoryGetFastSize() == 0x400000) memoryEmemSet(0, 0xe7);
|
|
|
|
else if (memoryGetFastSize() == 0x800000) memoryEmemSet(0, 0xe0);
|
|
|
|
memoryEmemSet(8, 128);
|
|
|
|
memoryEmemSet(4, 1);
|
|
|
|
memoryEmemSet(0x10, 2011>>8);
|
|
|
|
memoryEmemSet(0x14, 2011 & 0xf);
|
|
|
|
memoryEmemSet(0x18, 0);
|
|
|
|
memoryEmemSet(0x1c, 0);
|
|
|
|
memoryEmemSet(0x20, 0);
|
|
|
|
memoryEmemSet(0x24, 1);
|
|
|
|
memoryEmemSet(0x28, 0);
|
|
|
|
memoryEmemSet(0x2c, 0);
|
|
|
|
memoryEmemSet(0x40, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Allocate memory for the fast card memory */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryFastClear(void)
|
|
|
|
{
|
|
|
|
if (memory_fast != NULL)
|
|
|
|
memset(memory_fast, 0, memoryGetFastSize());
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryFastFree(void)
|
|
|
|
{
|
|
|
|
if (memory_fast != NULL)
|
|
|
|
{
|
|
|
|
free(memory_fast);
|
|
|
|
memory_fast = NULL;
|
|
|
|
memory_fast_baseaddress = 0;
|
|
|
|
memorySetFastAllocatedSize(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryFastAllocate(void)
|
|
|
|
{
|
|
|
|
if (memoryGetFastSize() != memoryGetFastAllocatedSize())
|
|
|
|
{
|
|
|
|
memoryFastFree();
|
2023-10-05 22:47:48 +00:00
|
|
|
memory_fast = (uint8_t *) malloc(memoryGetFastSize());
|
2013-02-06 04:11:41 +00:00
|
|
|
if (memory_fast == NULL) memorySetFastSize(0);
|
|
|
|
else memoryFastClear();
|
|
|
|
memorySetFastAllocatedSize((memory_fast == NULL) ? 0 : memoryGetFastSize());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
2023-10-05 22:47:48 +00:00
|
|
|
/* Map fastcard. */
|
2013-02-06 04:11:41 +00:00
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryFastCardMap(uint32_t mapping)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t lastbank;
|
2013-02-06 04:11:41 +00:00
|
|
|
|
|
|
|
memory_fast_baseaddress = (mapping >> 8) << 16;
|
2023-10-05 22:47:48 +00:00
|
|
|
if (memoryGetFastSize() > 0x800000)
|
|
|
|
{
|
|
|
|
lastbank = 0xa00000>>16;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lastbank = (memory_fast_baseaddress + memoryGetFastSize())>>16;
|
|
|
|
}
|
|
|
|
for (uint32_t bank = memory_fast_baseaddress >> 16; bank < lastbank; bank++)
|
|
|
|
{
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryBankSet(memoryFastReadByte,
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryFastReadWord,
|
|
|
|
memoryFastReadLong,
|
|
|
|
memoryFastWriteByte,
|
|
|
|
memoryFastWriteWord,
|
|
|
|
memoryFastWriteLong,
|
|
|
|
memory_fast,
|
|
|
|
bank,
|
|
|
|
memory_fast_baseaddress>>16,
|
|
|
|
TRUE);
|
|
|
|
}
|
2013-02-06 04:11:41 +00:00
|
|
|
memset(memory_fast, 0, memoryGetFastSize());
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryFastCardAdd(void)
|
|
|
|
{
|
|
|
|
if (memoryGetFastSize() != 0)
|
|
|
|
memoryEmemCardAdd(memoryFastCardInit, memoryFastCardMap);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Slow memory handling */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t memorySlowReadByte(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_slow_base + ((address & 0xffffff) - 0xc00000);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadByteFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint16_t memorySlowReadWord(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_slow_base + ((address & 0xffffff) - 0xc00000);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadWordFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memorySlowReadLong(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_slow_base + ((address & 0xffffff) - 0xc00000);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadLongFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memorySlowWriteByte(uint8_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_slow_base + ((address & 0xffffff) - 0xc00000);
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryWriteByteToPointer(data, p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memorySlowWriteWord(uint16_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_slow_base + ((address & 0xffffff) - 0xc00000);
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryWriteWordToPointer(data, p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memorySlowWriteLong(uint32_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_slow_base + ((address & 0xffffff) - 0xc00000);
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryWriteLongToPointer(data, p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
bool memorySlowMapAsChip(void)
|
|
|
|
{
|
|
|
|
return chipsetGetECS() && memoryGetChipSize() == 0x80000 && memoryGetSlowSize() == 0x80000;
|
|
|
|
}
|
|
|
|
|
2013-02-06 04:11:41 +00:00
|
|
|
void memorySlowClear(void)
|
|
|
|
{
|
|
|
|
memset(memory_slow, 0, memoryGetSlowSize());
|
2023-10-05 22:47:48 +00:00
|
|
|
if (memorySlowMapAsChip())
|
|
|
|
{
|
|
|
|
memset(memory_chip + 0x80000, 0, memoryGetSlowSize());
|
|
|
|
}
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void memorySlowMap(void)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t lastbank;
|
|
|
|
|
|
|
|
if (memoryGetSlowSize() > 0x1c0000)
|
|
|
|
{
|
|
|
|
lastbank = 0xdc0000>>16;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lastbank = (0xc00000 + memoryGetSlowSize())>>16;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Special config on ECS with 512k chip + 512k slow, chips see slow mem at $80000
|
|
|
|
memory_slow_base = (memorySlowMapAsChip()) ? (memory_chip + 0x80000) : memory_slow;
|
2013-02-06 04:11:41 +00:00
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
for (uint32_t bank = 0xc00000>>16; bank < lastbank; bank++)
|
|
|
|
{
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryBankSet(memorySlowReadByte,
|
2023-10-05 22:47:48 +00:00
|
|
|
memorySlowReadWord,
|
|
|
|
memorySlowReadLong,
|
|
|
|
memorySlowWriteByte,
|
|
|
|
memorySlowWriteWord,
|
|
|
|
memorySlowWriteLong,
|
|
|
|
memory_slow_base,
|
|
|
|
bank,
|
|
|
|
0xc00000>>16,
|
|
|
|
TRUE);
|
|
|
|
}
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Probably a disk controller, we need it to pass dummy values to get past */
|
|
|
|
/* the bootstrap of some Kickstart versions. */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t memoryMysteryReadByte(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
return memoryUnmappedReadByte(address);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint16_t memoryMysteryReadWord(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
return memoryUnmappedReadWord(address);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryMysteryReadLong(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
return memoryUnmappedReadLong(address);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryMysteryWriteByte(uint8_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryMysteryWriteWord(uint16_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryMysteryWriteLong(uint32_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryMysteryMap(void)
|
|
|
|
{
|
|
|
|
memoryBankSet(memoryMysteryReadByte,
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryMysteryReadWord,
|
|
|
|
memoryMysteryReadLong,
|
|
|
|
memoryMysteryWriteByte,
|
|
|
|
memoryMysteryWriteWord,
|
|
|
|
memoryMysteryWriteLong,
|
|
|
|
NULL,
|
|
|
|
0xe9,
|
|
|
|
0,
|
|
|
|
FALSE);
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryBankSet(memoryMysteryReadByte,
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryMysteryReadWord,
|
|
|
|
memoryMysteryReadLong,
|
|
|
|
memoryMysteryWriteByte,
|
|
|
|
memoryMysteryWriteWord,
|
|
|
|
memoryMysteryWriteLong,
|
|
|
|
NULL,
|
|
|
|
0xde,
|
|
|
|
0,
|
|
|
|
FALSE);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* IO Registers */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t memoryIoReadByte(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t adr = address & 0x1fe;
|
2013-02-06 04:11:41 +00:00
|
|
|
if (address & 0x1)
|
|
|
|
{ // Odd address
|
2023-10-05 22:47:48 +00:00
|
|
|
return (uint8_t) memory_iobank_read[adr >> 1](adr);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // Even address
|
2023-10-05 22:47:48 +00:00
|
|
|
return (uint8_t) (memory_iobank_read[adr >> 1](adr) >> 8);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint16_t memoryIoReadWord(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
return memory_iobank_read[(address & 0x1fe) >> 1](address & 0x1fe);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryIoReadLong(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t adr = address & 0x1fe;
|
|
|
|
uint32_t r1 = (uint32_t)memory_iobank_read[adr >> 1](adr);
|
|
|
|
uint32_t r2 = (uint32_t)memory_iobank_read[(adr + 2) >> 1](adr + 2);
|
2013-02-06 04:11:41 +00:00
|
|
|
return (r1 << 16) | r2;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryIoWriteByte(uint8_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t adr = address & 0x1fe;
|
2013-02-06 04:11:41 +00:00
|
|
|
if (address & 0x1)
|
|
|
|
{ // Odd address
|
2023-10-05 22:47:48 +00:00
|
|
|
memory_iobank_write[adr >> 1]((uint16_t) data, adr);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // Even address
|
2023-10-05 22:47:48 +00:00
|
|
|
memory_iobank_write[adr >> 1](((uint16_t) data) << 8, adr);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryIoWriteWord(uint16_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t adr = address & 0x1fe;
|
2013-02-06 04:11:41 +00:00
|
|
|
memory_iobank_write[adr >> 1](data, adr);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryIoWriteLong(uint32_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t adr = address & 0x1fe;
|
|
|
|
memory_iobank_write[adr >> 1]((uint16_t)(data >> 16), adr);
|
|
|
|
memory_iobank_write[(adr + 2) >> 1]((uint16_t)data, adr + 2);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void memoryIoMap(void)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t lastbank;
|
2013-02-06 04:11:41 +00:00
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
if (memoryGetSlowSize() > 0x1c0000)
|
|
|
|
{
|
|
|
|
lastbank = 0xdc0000>>16;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lastbank = (0xc00000 + memoryGetSlowSize())>>16;
|
|
|
|
}
|
|
|
|
for (uint32_t bank = lastbank; bank < 0xe00000>>16; bank++)
|
|
|
|
{
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryBankSet(memoryIoReadByte,
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryIoReadWord,
|
|
|
|
memoryIoReadLong,
|
|
|
|
memoryIoWriteByte,
|
|
|
|
memoryIoWriteWord,
|
|
|
|
memoryIoWriteLong,
|
|
|
|
NULL,
|
|
|
|
bank,
|
|
|
|
0,
|
|
|
|
FALSE);
|
|
|
|
}
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*/
|
|
|
|
/* Initializes one entry in the IO register access table */
|
|
|
|
/*===========================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memorySetIoReadStub(uint32_t index, memoryIoReadFunc ioreadfunction)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
memory_iobank_read[index>>1] = ioreadfunction;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memorySetIoWriteStub(uint32_t index, memoryIoWriteFunc iowritefunction)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
memory_iobank_write[index>>1] = iowritefunction;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*/
|
|
|
|
/* Clear all IO-register accessors */
|
|
|
|
/*===========================================================================*/
|
|
|
|
|
|
|
|
void memoryIoClear(void)
|
|
|
|
{
|
|
|
|
// Array has 257 elements to account for long writes to the last address.
|
2023-10-05 22:47:48 +00:00
|
|
|
for (uint32_t i = 0; i <= 512; i += 2) {
|
2013-02-06 04:11:41 +00:00
|
|
|
memorySetIoReadStub(i, rdefault);
|
|
|
|
memorySetIoWriteStub(i, wdefault);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Kickstart handling */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Map the Kickstart image into Amiga memory */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t memoryKickReadByte(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_kick + ((address & 0xffffff) - 0xf80000);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadByteFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t memoryKickExtendedReadByte(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_kick_ext + ((address & 0xffffff) - 0xe00000);
|
|
|
|
return memoryReadByteFromPointer(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t memoryKickReadWord(uint32_t address)
|
|
|
|
{
|
|
|
|
uint8_t *p = memory_kick + ((address & 0xffffff) - 0xf80000);
|
|
|
|
return memoryReadWordFromPointer(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t memoryKickExtendedReadWord(uint32_t address)
|
|
|
|
{
|
|
|
|
uint8_t *p = memory_kick_ext + ((address & 0xffffff) - 0xe00000);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadWordFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryKickReadLong(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_kick + ((address & 0xffffff) - 0xf80000);
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadLongFromPointer(p);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryKickExtendedReadLong(uint32_t address)
|
|
|
|
{
|
|
|
|
uint8_t *p = memory_kick_ext + ((address & 0xffffff) - 0xe00000);
|
|
|
|
return memoryReadLongFromPointer(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryKickWriteByte(uint8_t data, uint32_t address)
|
|
|
|
{
|
|
|
|
// NOP
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryKickExtendedWriteByte(uint8_t data, uint32_t address)
|
|
|
|
{
|
|
|
|
// NOP
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryKickWriteWord(uint16_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
// NOP
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryKickExtendedWriteWord(uint16_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
// NOP
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryKickWriteLong(uint32_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
// NOP
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryKickExtendedWriteLong(uint32_t data, uint32_t address)
|
|
|
|
{
|
|
|
|
// NOP
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryKickWriteByteA1000WCS(uint8_t data, uint32_t address)
|
|
|
|
{
|
|
|
|
if(address >= 0xfc0000) {
|
|
|
|
uint8_t *p = NULL;
|
|
|
|
address = (address & 0xffffff) - 0xf80000;
|
|
|
|
p = memory_kick + address;
|
|
|
|
memoryWriteByteToPointer(data, p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
memoryKickA1000BootstrapSetMapped(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryKickWriteWordA1000WCS(uint16_t data, uint32_t address)
|
|
|
|
{
|
|
|
|
if(address >= 0xfc0000) {
|
|
|
|
uint8_t *p = NULL;
|
|
|
|
address = (address & 0xffffff) - 0xf80000;
|
|
|
|
p = memory_kick + address;
|
|
|
|
memoryWriteWordToPointer(data, p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
memoryKickA1000BootstrapSetMapped(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryKickWriteLongA1000WCS(uint32_t data, uint32_t address)
|
|
|
|
{
|
|
|
|
if(address >= 0xfc0000) {
|
|
|
|
uint8_t *p = NULL;
|
|
|
|
address = (address & 0xffffff) - 0xf80000;
|
|
|
|
p = memory_kick + address ;
|
|
|
|
memoryWriteLongToPointer(data, p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
memoryKickA1000BootstrapSetMapped(false);
|
|
|
|
}
|
|
|
|
|
2013-02-06 04:11:41 +00:00
|
|
|
void memoryKickMap(void)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t basebank = memory_kickimage_basebank & 0xf8;
|
|
|
|
for (uint32_t bank = basebank; bank < (basebank + 8); bank++)
|
|
|
|
{
|
|
|
|
if(!memory_a1000_bootstrap_mapped)
|
|
|
|
memoryBankSet(memoryKickReadByte,
|
|
|
|
memoryKickReadWord,
|
|
|
|
memoryKickReadLong,
|
|
|
|
memoryKickWriteByte,
|
|
|
|
memoryKickWriteWord,
|
|
|
|
memoryKickWriteLong,
|
|
|
|
memory_kick,
|
|
|
|
bank,
|
|
|
|
memory_kickimage_basebank,
|
|
|
|
FALSE);
|
|
|
|
else
|
|
|
|
memoryBankSet(memoryKickReadByte,
|
|
|
|
memoryKickReadWord,
|
|
|
|
memoryKickReadLong,
|
|
|
|
memoryKickWriteByteA1000WCS,
|
|
|
|
memoryKickWriteWordA1000WCS,
|
|
|
|
memoryKickWriteLongA1000WCS,
|
|
|
|
memory_kick,
|
|
|
|
bank,
|
|
|
|
memory_kickimage_basebank,
|
|
|
|
FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryKickExtendedMap(void)
|
|
|
|
{
|
|
|
|
if (memory_kickimage_ext_size == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
uint32_t basebank = memory_kickimage_ext_basebank;
|
|
|
|
uint32_t numbanks = memory_kickimage_ext_size / 65536;
|
|
|
|
|
|
|
|
for (uint32_t bank = basebank; bank < (basebank + numbanks); bank++)
|
|
|
|
{
|
|
|
|
memoryBankSet(memoryKickExtendedReadByte,
|
|
|
|
memoryKickExtendedReadWord,
|
|
|
|
memoryKickExtendedReadLong,
|
|
|
|
memoryKickExtendedWriteByte,
|
|
|
|
memoryKickExtendedWriteWord,
|
|
|
|
memoryKickExtendedWriteLong,
|
|
|
|
memory_kick_ext,
|
2013-02-06 04:11:41 +00:00
|
|
|
bank,
|
2023-10-05 22:47:48 +00:00
|
|
|
basebank,
|
2013-02-06 04:11:41 +00:00
|
|
|
FALSE);
|
2023-10-05 22:47:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryKickA1000BootstrapSetMapped(const bool bBootstrapMapped)
|
|
|
|
{
|
|
|
|
if(!memory_a1000_wcs || !memory_a1000_bootstrap) return;
|
|
|
|
|
|
|
|
fellowAddLog("memoryKickSetA1000BootstrapMapped(%s)\n",
|
|
|
|
bBootstrapMapped ? "true" : "false");
|
|
|
|
|
|
|
|
if (bBootstrapMapped) {
|
|
|
|
memcpy(memory_kick, memory_a1000_bootstrap, 262144);
|
|
|
|
memory_kickimage_version = 0;
|
|
|
|
} else {
|
|
|
|
memcpy(memory_kick, memory_kick + 262144, 262144);
|
|
|
|
memory_kickimage_version = (memory_kick[262144 + 12] << 8) | memory_kick[262144 + 13];
|
|
|
|
if (memory_kickimage_version == 0xffff)
|
|
|
|
memory_kickimage_version = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(bBootstrapMapped != memory_a1000_bootstrap_mapped) {
|
|
|
|
memory_a1000_bootstrap_mapped = bBootstrapMapped;
|
|
|
|
memoryKickMap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryKickA1000BootstrapFree(void)
|
|
|
|
{
|
|
|
|
if(memory_a1000_bootstrap != NULL) {
|
|
|
|
free(memory_a1000_bootstrap);
|
|
|
|
memory_a1000_bootstrap = NULL;
|
|
|
|
memory_a1000_bootstrap_mapped = false;
|
|
|
|
memory_a1000_wcs = false;
|
|
|
|
}
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
2023-10-05 22:47:48 +00:00
|
|
|
/* An error occured during loading a kickstart file. Uses GUI to display */
|
2013-02-06 04:11:41 +00:00
|
|
|
/* an errorstring. */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryKickError(uint32_t errorcode, uint32_t data)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
static char error1[80], error2[160], error3[160];
|
2013-02-06 04:11:41 +00:00
|
|
|
|
|
|
|
sprintf(error1, "Kickstart file could not be loaded");
|
|
|
|
sprintf(error2, "%s", memory_kickimage);
|
|
|
|
error3[0] = '\0';
|
|
|
|
switch (errorcode)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
case MEMORY_ROM_ERROR_SIZE:
|
|
|
|
sprintf(error3,
|
|
|
|
"Illegal size: %u bytes, size must be either 8kB (A1000 bootstrap ROM), 256kB or 512kB.",
|
|
|
|
data);
|
|
|
|
break;
|
|
|
|
case MEMORY_ROM_ERROR_AMIROM_VERSION:
|
|
|
|
sprintf(error3, "Unsupported encryption method, version found was %u",
|
|
|
|
data);
|
|
|
|
break;
|
|
|
|
case MEMORY_ROM_ERROR_AMIROM_READ:
|
|
|
|
sprintf(error3, "Read error in encrypted Kickstart or keyfile");
|
|
|
|
break;
|
|
|
|
case MEMORY_ROM_ERROR_KEYFILE:
|
|
|
|
sprintf(error3, "Unable to access keyfile %s", memory_key);
|
|
|
|
break;
|
|
|
|
case MEMORY_ROM_ERROR_EXISTS_NOT:
|
|
|
|
sprintf(error3, "File does not exist");
|
|
|
|
break;
|
|
|
|
case MEMORY_ROM_ERROR_FILE:
|
|
|
|
sprintf(error3, "File is a directory");
|
|
|
|
break;
|
|
|
|
case MEMORY_ROM_ERROR_KICKDISK_NOT:
|
|
|
|
sprintf(error3, "The ADF-image is not a kickdisk");
|
|
|
|
break;
|
|
|
|
case MEMORY_ROM_ERROR_CHECKSUM:
|
|
|
|
sprintf(error3,
|
|
|
|
"The Kickstart image has a checksum error, checksum is %X",
|
|
|
|
data);
|
|
|
|
break;
|
|
|
|
case MEMORY_ROM_ERROR_KICKDISK_SUPER:
|
|
|
|
sprintf(error3,
|
|
|
|
"The ADF-image contains a superkickstart. Fellow can not handle it.");
|
|
|
|
break;
|
|
|
|
case MEMORY_ROM_ERROR_BAD_BANK:
|
|
|
|
sprintf(error3, "The ROM has a bad baseaddress: %X",
|
|
|
|
memory_kickimage_basebank*0x10000);
|
|
|
|
break;
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
2023-10-05 22:47:48 +00:00
|
|
|
fellowAddLogRequester(FELLOW_REQUESTER_TYPE_ERROR, "%s\n%s\n%s\n", error1, error2, error3);
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryKickSettingsClear();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Returns the checksum of the current kickstart image. */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryKickChksum(void)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t lastsum;
|
2013-02-06 04:11:41 +00:00
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t sum = lastsum = 0;
|
|
|
|
for (uint32_t i = 0; i < 0x80000; i += 4) {
|
|
|
|
uint8_t *p = memory_kick + i;
|
2013-02-06 04:11:41 +00:00
|
|
|
sum += memoryReadLongFromPointer(p);
|
|
|
|
if (sum < lastsum) sum++;
|
|
|
|
lastsum = sum;
|
|
|
|
}
|
|
|
|
return ~sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Identifies a loaded Kickstart */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
char *memoryKickIdentify(char *s)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *rom = memory_kick;
|
|
|
|
uint32_t ver = (rom[12] << 8) | rom[13];
|
|
|
|
uint32_t rev = (rom[14] << 8) | rom[15];
|
2013-02-06 04:11:41 +00:00
|
|
|
if (ver == 65535) memory_kickimage_version = 28;
|
|
|
|
else if (ver < 29) memory_kickimage_version = 29;
|
|
|
|
else if (ver > 41) memory_kickimage_version = 41;
|
|
|
|
else memory_kickimage_version = ver;
|
|
|
|
sprintf(s,
|
2023-10-05 22:47:48 +00:00
|
|
|
"%s (%u.%u)",
|
2013-02-06 04:11:41 +00:00
|
|
|
memory_kickimage_versionstrings[memory_kickimage_version - 28],
|
|
|
|
ver,
|
|
|
|
rev);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Verifies that a loaded Kickstart is OK */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryKickOK(void)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t chksum;
|
|
|
|
bool bVerifyChecksum = !memory_a1000_wcs;
|
2013-02-06 04:11:41 +00:00
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
if (bVerifyChecksum && ((chksum = memoryKickChksum()) != 0))
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryKickError(MEMORY_ROM_ERROR_CHECKSUM, chksum);
|
|
|
|
else
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t basebank = memory_kick[5];
|
2013-02-06 04:11:41 +00:00
|
|
|
if ((basebank == 0xf8) || (basebank == 0xfc)) {
|
2023-10-05 22:47:48 +00:00
|
|
|
memory_kickimage_basebank = basebank;
|
|
|
|
memory_kickimage_none = FALSE;
|
|
|
|
memoryKickIdentify(memory_kickimage_versionstr);
|
|
|
|
memory_initial_PC = memoryReadLongFromPointer((memory_kick + 4));
|
|
|
|
memory_initial_SP = memoryReadLongFromPointer(memory_kick);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
else
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryKickError(MEMORY_ROM_ERROR_BAD_BANK, basebank);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Returns size of decoded kickstart */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
int memoryKickDecodeAF(char *filename, char *keyfile, uint8_t *memory_kick, const bool suppressgui)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
char *keybuffer = NULL;
|
|
|
|
uint32_t keysize, filesize = 0, keypos = 0, c;
|
2013-02-06 04:11:41 +00:00
|
|
|
/* Read key */
|
2023-10-05 22:47:48 +00:00
|
|
|
if (FILE *KF; (KF = fopen(keyfile, "rb")) != NULL)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
fseek(KF, 0, SEEK_END);
|
|
|
|
keysize = ftell(KF);
|
2023-10-05 22:47:48 +00:00
|
|
|
keybuffer = (char*)malloc(keysize);
|
2013-02-06 04:11:41 +00:00
|
|
|
if (keybuffer != NULL)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
fseek(KF, 0, SEEK_SET);
|
|
|
|
fread(keybuffer, 1, keysize, KF);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
fclose(KF);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#ifdef WIN32
|
2023-10-05 22:47:48 +00:00
|
|
|
HMODULE hAmigaForeverDLL = NULL;
|
|
|
|
char *strLibName = TEXT("amigaforever.dll");
|
|
|
|
char strPath[CFG_FILENAME_LENGTH] = "";
|
|
|
|
char strAmigaForeverRoot[CFG_FILENAME_LENGTH] = "";
|
|
|
|
DWORD dwRet = 0;
|
|
|
|
|
|
|
|
// the preferred way to locate the DLL is by relative path, so it is
|
|
|
|
// of a matching version (DVD/portable installation with newer version
|
|
|
|
// than what is installed)
|
|
|
|
if(fileopsGetWinFellowInstallationPath(strPath, CFG_FILENAME_LENGTH)) {
|
|
|
|
strncat(strPath, "\\..\\Player\\", 11);
|
|
|
|
strncat(strPath, strLibName, strlen(strLibName) + 1);
|
|
|
|
hAmigaForeverDLL = LoadLibrary(strPath);
|
|
|
|
}
|
2013-02-06 04:11:41 +00:00
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
if(!hAmigaForeverDLL) {
|
|
|
|
// DLL not found via relative path, fallback to env. variable
|
2013-02-06 04:11:41 +00:00
|
|
|
dwRet = GetEnvironmentVariable("AMIGAFOREVERROOT", strAmigaForeverRoot, CFG_FILENAME_LENGTH);
|
2023-10-05 22:47:48 +00:00
|
|
|
if((dwRet > 0) && strAmigaForeverRoot) {
|
|
|
|
TCHAR strTemp[CFG_FILENAME_LENGTH];
|
|
|
|
_tcscpy(strTemp, strAmigaForeverRoot);
|
|
|
|
if (strTemp[_tcslen(strTemp) - 1] == '/' || strTemp[_tcslen(strTemp) - 1] == '\\')
|
|
|
|
_tcscat(strTemp, TEXT("\\"));
|
|
|
|
_stprintf(strPath, TEXT("%sPlayer\\%s"), strTemp, strLibName);
|
|
|
|
hAmigaForeverDLL = LoadLibrary(strPath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(hAmigaForeverDLL) {
|
|
|
|
typedef DWORD (STDAPICALLTYPE *PFN_GetKey)(LPVOID lpvBuffer, DWORD dwSize);
|
|
|
|
|
|
|
|
PFN_GetKey pfnGetKey = (PFN_GetKey)GetProcAddress(hAmigaForeverDLL, "GetKey");
|
|
|
|
if (pfnGetKey) {
|
|
|
|
keysize = pfnGetKey(NULL, 0);
|
|
|
|
if (keysize) {
|
|
|
|
keybuffer = (char*)malloc(keysize);
|
2013-02-06 04:11:41 +00:00
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
if (keybuffer) {
|
|
|
|
if (pfnGetKey(keybuffer, keysize) == keysize) {
|
|
|
|
// key successfully retrieved
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (!suppressgui)
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryKickError(MEMORY_ROM_ERROR_KEYFILE, 0);
|
2023-10-05 22:47:48 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
2023-10-05 22:47:48 +00:00
|
|
|
FreeLibrary(hAmigaForeverDLL);
|
|
|
|
#endif
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
if (!keybuffer) {
|
|
|
|
if (!suppressgui)
|
|
|
|
memoryKickError(MEMORY_ROM_ERROR_KEYFILE, 0);
|
2013-02-06 04:11:41 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!keybuffer)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Read file */
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
if (FILE*RF; (RF = fopen(filename, "rb")) != NULL)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
fseek(RF, 11, SEEK_SET);
|
|
|
|
while (((c = fgetc(RF)) != EOF) && filesize < 524288)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
if (keysize != 0)
|
|
|
|
c ^= keybuffer[keypos++];
|
|
|
|
if (keypos == keysize)
|
|
|
|
keypos = 0;
|
|
|
|
memory_kick[filesize++] = (uint8_t) c;
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
while ((c = fgetc(RF)) != EOF)
|
2023-10-05 22:47:48 +00:00
|
|
|
filesize++;
|
2013-02-06 04:11:41 +00:00
|
|
|
fclose(RF);
|
|
|
|
free(keybuffer);
|
|
|
|
return filesize;
|
|
|
|
}
|
|
|
|
free(keybuffer);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Load Amiga Forever encrypted ROM-files */
|
|
|
|
/* Return TRUE if file was handled, that is both if the file is */
|
|
|
|
/* valid, or has wrong version */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
int memoryKickLoadAF2(char *filename, FILE *F, uint8_t *memory_kick, const bool suppressgui)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
char IDString[12];
|
|
|
|
memory_a1000_wcs = false;
|
2013-02-06 04:11:41 +00:00
|
|
|
fread(IDString, 11, 1, F);
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t version = IDString[10] - '0';
|
2013-02-06 04:11:41 +00:00
|
|
|
IDString[10] = '\0';
|
|
|
|
if (stricmp(IDString, "AMIROMTYPE") == 0)
|
|
|
|
{ /* Header seems OK */
|
|
|
|
if (version != 1)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
if(!suppressgui)
|
|
|
|
memoryKickError(MEMORY_ROM_ERROR_AMIROM_VERSION, version);
|
|
|
|
return TRUE; /* File was handled */
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{ /* Seems to be a file we can handle */
|
2023-10-05 22:47:48 +00:00
|
|
|
fclose(F);
|
|
|
|
uint32_t size = memoryKickDecodeAF(filename,
|
|
|
|
memory_key, memory_kick, suppressgui);
|
|
|
|
if (size == -1)
|
|
|
|
{
|
|
|
|
if(!suppressgui)
|
|
|
|
memoryKickError(MEMORY_ROM_ERROR_AMIROM_READ, 0);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
if (size != 8192 && size != 262144 && size != 524288)
|
|
|
|
{
|
|
|
|
if(!suppressgui)
|
|
|
|
memoryKickError(MEMORY_ROM_ERROR_SIZE, size);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (size == 8192)
|
|
|
|
{ /* Load A1000 bootstrap ROM */
|
|
|
|
memory_a1000_wcs = true;
|
|
|
|
|
|
|
|
if(memory_a1000_bootstrap == NULL)
|
|
|
|
memory_a1000_bootstrap = (uint8_t *) malloc(262144);
|
|
|
|
|
|
|
|
if(memory_a1000_bootstrap) {
|
|
|
|
uint32_t lCRC32 = 0;
|
|
|
|
memset(memory_a1000_bootstrap, 0xff, 262144);
|
|
|
|
memcpy(memory_a1000_bootstrap, memory_kick, 8192);
|
|
|
|
lCRC32 = crc32(0, memory_kick, 8192);
|
|
|
|
if (lCRC32 != 0x62F11C04) {
|
|
|
|
free(memory_a1000_bootstrap);
|
|
|
|
memory_a1000_bootstrap = NULL;
|
|
|
|
memoryKickError(MEMORY_ROM_ERROR_CHECKSUM, lCRC32);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (size == 262144)
|
|
|
|
memcpy(memory_kick + 262144, memory_kick, 262144);
|
|
|
|
|
|
|
|
memory_kickimage_none = FALSE;
|
|
|
|
memoryKickIdentify(memory_kickimage_versionstr);
|
|
|
|
return TRUE;
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Here, header was not recognized */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Detect and load kickdisk */
|
|
|
|
/* Based on information provided by Jerry Lawrence */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryKickDiskLoad(FILE *F)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
char head[5];
|
2013-02-06 04:11:41 +00:00
|
|
|
|
|
|
|
/* Check header */
|
|
|
|
|
|
|
|
fseek(F, 0, SEEK_SET);
|
|
|
|
fread(head, 4, 1, F);
|
|
|
|
head[4] = '\0';
|
|
|
|
if (strcmp(head, "KICK") != 0)
|
|
|
|
{
|
|
|
|
memoryKickError(MEMORY_ROM_ERROR_KICKDISK_NOT, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
fread(head, 3, 1, F);
|
|
|
|
head[3] = '\0';
|
|
|
|
if (strcmp(head, "SUP") == 0)
|
|
|
|
{
|
|
|
|
memoryKickError(MEMORY_ROM_ERROR_KICKDISK_SUPER, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
fseek(F, 512, SEEK_SET); /* Load image */
|
|
|
|
fread(memory_kick, 262144, 1, F);
|
|
|
|
memcpy(memory_kick + 262144, memory_kick, 262144);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* memory_kickimage is the file we want to load */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryKickLoad(void)
|
|
|
|
{
|
|
|
|
FILE *F;
|
|
|
|
BOOLE kickdisk = FALSE;
|
|
|
|
BOOLE afkick = FALSE;
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
memory_a1000_wcs = false;
|
|
|
|
|
2013-02-06 04:11:41 +00:00
|
|
|
/* New file is different from previous */
|
|
|
|
/* Must load file */
|
|
|
|
|
|
|
|
fs_navig_point *fsnp;
|
|
|
|
|
|
|
|
memory_kickimage_none = FALSE;/* Initially Kickstart is expected to be OK */
|
|
|
|
if ((fsnp = fsWrapMakePoint(memory_kickimage)) == NULL)
|
|
|
|
memoryKickError(MEMORY_ROM_ERROR_EXISTS_NOT, 0);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (fsnp->type != FS_NAVIG_FILE)
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryKickError(MEMORY_ROM_ERROR_FILE, 0);
|
2013-02-06 04:11:41 +00:00
|
|
|
else
|
|
|
|
{ /* File passed initial tests */
|
2023-10-05 22:47:48 +00:00
|
|
|
if ((F = fopen(memory_kickimage, "rb")) == NULL)
|
|
|
|
memoryKickError(MEMORY_ROM_ERROR_EXISTS_NOT, 0);
|
|
|
|
else memory_kickimage_size = fsnp->size;
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
free(fsnp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Either the file is open, or memory_kickimage_none is TRUE */
|
|
|
|
|
|
|
|
if (!memory_kickimage_none)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* File opened successfully */
|
|
|
|
|
|
|
|
/* Kickdisk flag */
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
char* suffix = strchr(memory_kickimage, '.');
|
2013-02-06 04:11:41 +00:00
|
|
|
if (suffix != NULL)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
char* lastsuffix = suffix;
|
|
|
|
while ((suffix = strchr(lastsuffix + 1, '.')) != NULL)
|
|
|
|
lastsuffix = suffix;
|
|
|
|
kickdisk = (stricmp(lastsuffix + 1, "ADF") == 0);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
/* mem_loadrom_af2 will return TRUE if file was handled */
|
|
|
|
/* Handled also means any error conditions */
|
|
|
|
/* The result can be that no kickstart was loaded */
|
|
|
|
|
|
|
|
if (kickdisk)
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryKickDiskLoad(F);
|
2013-02-06 04:11:41 +00:00
|
|
|
else
|
2023-10-05 22:47:48 +00:00
|
|
|
afkick = memoryKickLoadAF2(memory_kickimage, F, memory_kick, false);
|
2013-02-06 04:11:41 +00:00
|
|
|
if (!kickdisk && !afkick)
|
|
|
|
{ /* Normal kickstart image */
|
2023-10-05 22:47:48 +00:00
|
|
|
fseek(F, 0, SEEK_SET);
|
|
|
|
if (memory_kickimage_size == 8192)
|
|
|
|
{ /* Load A1000 bootstrap ROM */
|
|
|
|
memory_a1000_wcs = true;
|
|
|
|
|
|
|
|
if(memory_a1000_bootstrap == NULL)
|
|
|
|
memory_a1000_bootstrap = (uint8_t *) malloc(262144);
|
|
|
|
|
|
|
|
if(memory_a1000_bootstrap) {
|
|
|
|
uint32_t lCRC32 = 0;
|
|
|
|
memset(memory_a1000_bootstrap, 0xff, 262144);
|
|
|
|
fread(memory_a1000_bootstrap, 1, 8192, F);
|
|
|
|
memcpy(memory_kick, memory_a1000_bootstrap, 262144);
|
|
|
|
memcpy(memory_kick + 262144, memory_a1000_bootstrap, 262144);
|
|
|
|
lCRC32 = crc32(0, memory_a1000_bootstrap, 8192);
|
|
|
|
if (lCRC32 != 0x62F11C04) {
|
|
|
|
free(memory_a1000_bootstrap);
|
|
|
|
memory_a1000_bootstrap = NULL;
|
|
|
|
memoryKickError(MEMORY_ROM_ERROR_CHECKSUM, lCRC32);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (memory_kickimage_size == 262144)
|
|
|
|
{ /* Load 256k ROM */
|
|
|
|
fread(memory_kick, 1, 262144, F);
|
|
|
|
memcpy(memory_kick + 262144, memory_kick, 262144);
|
|
|
|
}
|
|
|
|
else if (memory_kickimage_size == 524288)/* Load 512k ROM */
|
|
|
|
fread(memory_kick, 1, 524288, F);
|
|
|
|
else
|
|
|
|
{ /* Rom size is wrong */
|
|
|
|
memoryKickError(MEMORY_ROM_ERROR_SIZE, memory_kickimage_size);
|
|
|
|
}
|
|
|
|
fclose(F);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
}
|
2023-10-05 22:47:48 +00:00
|
|
|
if (!memory_kickimage_none) {
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryKickOK();
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryKickA1000BootstrapSetMapped(true);
|
|
|
|
}
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Clear memory used for kickstart image */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryKickClear(void)
|
|
|
|
{
|
|
|
|
memset(memory_kick, 0, 0x80000);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
/*============================================================================*/
|
|
|
|
/* Free memory used for extended kickstart image */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryKickExtendedFree(void)
|
|
|
|
{
|
|
|
|
if (memory_kick_ext) {
|
|
|
|
free(memory_kick_ext);
|
|
|
|
memory_kick_ext = NULL;
|
|
|
|
}
|
|
|
|
memory_kickimage_ext_size = 0;
|
|
|
|
memory_kickimage_ext_basebank = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Load extended Kickstart ROM into memory */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryKickExtendedLoad(void)
|
|
|
|
{
|
|
|
|
FILE *F;
|
|
|
|
fs_navig_point *fsnp;
|
|
|
|
uint32_t size = 0;
|
|
|
|
|
|
|
|
/* New file is different from previous, must load file */
|
|
|
|
|
|
|
|
memoryKickExtendedFree();
|
|
|
|
|
|
|
|
if (stricmp(memory_kickimage_ext, "") == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fsnp = fsWrapMakePoint(memory_kickimage_ext)) == NULL)
|
|
|
|
return;
|
|
|
|
if (fsnp->type != FS_NAVIG_FILE)
|
|
|
|
return;
|
|
|
|
/* File passed initial tests */
|
|
|
|
if ((F = fopen(memory_kickimage_ext, "rb")) == NULL)
|
|
|
|
return;
|
|
|
|
size = fsnp->size;
|
|
|
|
free(fsnp);
|
|
|
|
|
|
|
|
if (F) {
|
|
|
|
fseek(F, 0, SEEK_SET);
|
|
|
|
|
|
|
|
if (size == 262155 || size == 524299) {
|
|
|
|
// Amiga Forever - encrypted ROM?
|
|
|
|
char IDString[12];
|
|
|
|
|
|
|
|
fread(IDString, 11, 1, F);
|
|
|
|
uint32_t version = IDString[10] - '0';
|
|
|
|
IDString[10] = '\0';
|
|
|
|
if (stricmp(IDString, "AMIROMTYPE") == 0)
|
|
|
|
{ /* Header seems OK */
|
|
|
|
if (version != 1)
|
|
|
|
return;
|
|
|
|
/* Seems to be a file we can handle */
|
|
|
|
memory_kick_ext = (uint8_t *) malloc(size - 11);
|
|
|
|
size = memoryKickDecodeAF(memory_kickimage_ext, memory_key, memory_kick_ext, false);
|
|
|
|
memory_kickimage_ext_size = size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (size == 262144 || size == 524288) {
|
|
|
|
memory_kick_ext = (uint8_t *) malloc(size);
|
|
|
|
|
|
|
|
if (memory_kick_ext) {
|
|
|
|
memset(memory_kick_ext, 0xff, size);
|
|
|
|
fread(memory_kick_ext, 1, size, F);
|
|
|
|
memory_kickimage_ext_size = size;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
memory_kickimage_ext_basebank = memory_kick_ext[5];
|
|
|
|
|
|
|
|
// AROS extended ROM does not have basebank at byte 6, override
|
|
|
|
if (memory_kickimage_ext_basebank == 0xf8)
|
|
|
|
memory_kickimage_ext_basebank = 0xe0;
|
|
|
|
|
|
|
|
fclose(F);
|
|
|
|
F = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-06 04:11:41 +00:00
|
|
|
/*============================================================================*/
|
|
|
|
/* Top-level memory access functions */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
/*==============================================================================
|
|
|
|
Raises exception 3 when a word or long is accessing an odd address
|
|
|
|
and the CPU is < 020
|
|
|
|
==============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
static void memoryOddRead(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
if (address & 1)
|
|
|
|
{
|
|
|
|
if (cpuGetModelMajor() < 2)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
memory_fault_read = TRUE;
|
|
|
|
memory_fault_address = address;
|
|
|
|
cpuThrowAddressErrorException();
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
static void memoryOddWrite(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
if (address & 1)
|
|
|
|
{
|
|
|
|
if (cpuGetModelMajor() < 2)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
memory_fault_read = FALSE;
|
|
|
|
memory_fault_address = address;
|
|
|
|
cpuThrowAddressErrorException();
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t memoryReadByteViaBankHandler(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
return memory_bank_readbyte[address >> 16](address);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
__inline uint8_t memoryReadByte(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *memory_ptr = memory_bank_pointer[address>>16];
|
2013-02-06 04:11:41 +00:00
|
|
|
if (memory_ptr != NULL)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_ptr + address;
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadByteFromPointer(p);
|
|
|
|
}
|
|
|
|
return memoryReadByteViaBankHandler(address);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint16_t memoryReadWordViaBankHandler(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
memoryOddRead(address);
|
|
|
|
return memory_bank_readword[address >> 16](address);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
__inline uint16_t memoryReadWord(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *memory_ptr = memory_bank_pointer[address>>16];
|
2013-02-06 04:11:41 +00:00
|
|
|
if ((memory_ptr != NULL) && !(address & 1))
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint8_t *p = memory_ptr + address;
|
2013-02-06 04:11:41 +00:00
|
|
|
return memoryReadWordFromPointer(p);
|
|
|
|
}
|
|
|
|
return memoryReadWordViaBankHandler(address);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
__inline uint32_t memoryReadLong(uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
return ((uint32_t)memoryReadWord(address) << 16) | ((uint32_t)memoryReadWord(address + 2));
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryWriteByte(uint8_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t bank = address>>16;
|
2013-02-06 04:11:41 +00:00
|
|
|
if (memory_bank_pointer_can_write[bank])
|
|
|
|
{
|
|
|
|
memoryWriteByteToPointer(data, memory_bank_pointer[bank] + address);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memory_bank_writebyte[bank](data, address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryWriteWordViaBankHandler(uint16_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
memoryOddWrite(address);
|
|
|
|
memory_bank_writeword[address >> 16](data, address);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryWriteWord(uint16_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t bank = address>>16;
|
2013-02-06 04:11:41 +00:00
|
|
|
if (memory_bank_pointer_can_write[bank] && !(address & 1))
|
|
|
|
{
|
|
|
|
memoryWriteWordToPointer(data, memory_bank_pointer[bank] + address);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memoryWriteWordViaBankHandler(data, address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryWriteLongViaBankHandler(uint32_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
memoryOddWrite(address);
|
|
|
|
memory_bank_writelong[address >> 16](data, address);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memoryWriteLong(uint32_t data, uint32_t address)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t bank = address>>16;
|
2013-02-06 04:11:41 +00:00
|
|
|
if (memory_bank_pointer_can_write[bank] && !(address & 1))
|
|
|
|
{
|
|
|
|
memoryWriteLongToPointer(data, memory_bank_pointer[bank] + address);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memoryWriteLongViaBankHandler(data, address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Memory configuration interface */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
BOOLE memorySetChipSize(uint32_t chipsize)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
BOOLE needreset = (memory_chipsize != chipsize);
|
|
|
|
memory_chipsize = chipsize;
|
|
|
|
return needreset;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryGetChipSize(void)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
return memory_chipsize;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
BOOLE memorySetFastSize(uint32_t fastsize)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
BOOLE needreset = (memory_fastsize != fastsize);
|
|
|
|
memory_fastsize = fastsize;
|
|
|
|
if (needreset) memoryFastAllocate();
|
|
|
|
return needreset;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryGetFastSize(void)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
return memory_fastsize;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memorySetFastAllocatedSize(uint32_t fastallocatedsize)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
memory_fastallocatedsize = fastallocatedsize;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryGetFastAllocatedSize(void)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
return memory_fastallocatedsize;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
BOOLE memorySetSlowSize(uint32_t slowsize)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
BOOLE needreset = (memory_slowsize != slowsize);
|
|
|
|
memory_slowsize = slowsize;
|
|
|
|
return needreset;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryGetSlowSize(void)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
return memory_slowsize;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
bool memorySetUseAutoconfig(bool useautoconfig)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
bool needreset = memory_useautoconfig != useautoconfig;
|
2013-02-06 04:11:41 +00:00
|
|
|
memory_useautoconfig = useautoconfig;
|
|
|
|
return needreset;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
bool memoryGetUseAutoconfig(void)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
return memory_useautoconfig;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLE memorySetAddress32Bit(BOOLE address32bit)
|
|
|
|
{
|
|
|
|
BOOLE needreset = memory_address32bit != address32bit;
|
|
|
|
memory_address32bit = address32bit;
|
|
|
|
return needreset;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLE memoryGetAddress32Bit(void)
|
|
|
|
{
|
|
|
|
return memory_address32bit;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
BOOLE memorySetKickImage(char *kickimage)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
BOOLE needreset = !!strncmp(memory_kickimage, kickimage, CFG_FILENAME_LENGTH);
|
|
|
|
strncpy(memory_kickimage, kickimage, CFG_FILENAME_LENGTH);
|
|
|
|
if (needreset) memoryKickLoad();
|
|
|
|
return needreset;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
BOOLE memorySetKickImageExtended(char *kickimageext)
|
|
|
|
{
|
|
|
|
BOOLE needreset = !!strncmp(memory_kickimage_ext, kickimageext, CFG_FILENAME_LENGTH);
|
|
|
|
strncpy(memory_kickimage_ext, kickimageext, CFG_FILENAME_LENGTH);
|
|
|
|
if (needreset)
|
|
|
|
memoryKickExtendedLoad();
|
|
|
|
return needreset;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *memoryGetKickImage(void)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
return memory_kickimage;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
void memorySetKey(char *key)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
strncpy(memory_key, key, CFG_FILENAME_LENGTH);
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
char *memoryGetKey(void)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
return memory_key;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryGetKickImageBaseBank(void)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
return memory_kickimage_basebank;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryGetKickImageVersion(void)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
return memory_kickimage_version;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLE memoryGetKickImageOK(void)
|
|
|
|
{
|
|
|
|
return !memory_kickimage_none;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryInitialPC(void)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
return memory_initial_PC;
|
|
|
|
}
|
|
|
|
|
2023-10-05 22:47:48 +00:00
|
|
|
uint32_t memoryInitialSP(void)
|
2013-02-06 04:11:41 +00:00
|
|
|
{
|
|
|
|
return memory_initial_SP;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
/* Sets all settings a clean state */
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
void memoryChipSettingsClear(void)
|
|
|
|
{
|
|
|
|
memorySetChipSize(0x200000);
|
|
|
|
memoryChipClear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryFastSettingsClear(void)
|
|
|
|
{
|
|
|
|
memory_fast = NULL;
|
|
|
|
memory_fast_baseaddress = 0;
|
|
|
|
memorySetFastAllocatedSize(0);
|
|
|
|
memorySetFastSize(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void memorySlowSettingsClear(void)
|
|
|
|
{
|
|
|
|
memorySetSlowSize(0x1c0000);
|
|
|
|
memorySlowClear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryIoSettingsClear(void)
|
|
|
|
{
|
|
|
|
memoryIoClear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryKickSettingsClear(void)
|
|
|
|
{
|
|
|
|
memory_kickimage[0] = '\0';
|
|
|
|
memory_kickimage_none = TRUE;
|
|
|
|
memoryKickClear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryEmemSettingsClear(void)
|
|
|
|
{
|
|
|
|
memoryEmemCardsRemove();
|
|
|
|
memoryEmemClear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryDmemSettingsClear(void)
|
|
|
|
{
|
|
|
|
memoryDmemSetCounter(0);
|
|
|
|
memoryDmemClear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryBankSettingsClear(void)
|
|
|
|
{
|
|
|
|
memoryBankClearAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*==============*/
|
|
|
|
/* Generic init */
|
|
|
|
/*==============*/
|
|
|
|
|
|
|
|
void memorySaveState(FILE *F)
|
|
|
|
{
|
|
|
|
fwrite(&memory_chipsize, sizeof(memory_chipsize), 1, F);
|
|
|
|
fwrite(&memory_slowsize, sizeof(memory_slowsize), 1, F);
|
|
|
|
fwrite(&memory_fastsize, sizeof(memory_fastsize), 1, F);
|
|
|
|
if (memory_chipsize > 0)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
fwrite(&memory_chip[0], sizeof(uint8_t), memory_chipsize, F);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
if (memory_slowsize > 0)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
fwrite(&memory_slow[0], sizeof(uint8_t), memory_slowsize, F);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
if (memory_fastsize > 0)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
fwrite(memory_fast, sizeof(uint8_t), memory_fastsize, F);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryLoadState(FILE *F)
|
|
|
|
{
|
|
|
|
fread(&memory_chipsize, sizeof(memory_chipsize), 1, F);
|
|
|
|
fread(&memory_slowsize, sizeof(memory_slowsize), 1, F);
|
|
|
|
fread(&memory_fastsize, sizeof(memory_fastsize), 1, F);
|
|
|
|
if (memory_chipsize > 0)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
fread(&memory_chip[0], sizeof(uint8_t), memory_chipsize, F);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
if (memory_slowsize > 0)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
fread(&memory_slow[0], sizeof(uint8_t), memory_slowsize, F);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
if (memory_fastsize > 0)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
fread(memory_fast, sizeof(uint8_t), memory_fastsize, F);
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryEmulationStart(void)
|
|
|
|
{
|
|
|
|
memoryIoClear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryEmulationStop(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void memorySoftReset(void)
|
|
|
|
{
|
|
|
|
memoryDmemClear();
|
|
|
|
memoryEmemClear();
|
|
|
|
memoryEmemCardsRemove();
|
|
|
|
memoryFastCardAdd();
|
|
|
|
memoryBankClearAll();
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryChipMap(true);
|
2013-02-06 04:11:41 +00:00
|
|
|
memorySlowMap();
|
|
|
|
memoryIoMap();
|
|
|
|
memoryEmemMap();
|
|
|
|
memoryDmemMap();
|
|
|
|
memoryMysteryMap();
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryKickA1000BootstrapSetMapped(true);
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryKickMap();
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryKickExtendedMap();
|
|
|
|
rtcMap();
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void memoryHardReset(void)
|
|
|
|
{
|
2023-10-05 22:47:48 +00:00
|
|
|
fellowAddLog("memoryHardReset()\n");
|
|
|
|
|
2013-02-06 04:11:41 +00:00
|
|
|
memoryChipClear(),
|
|
|
|
memoryFastClear();
|
|
|
|
memorySlowClear();
|
|
|
|
memoryDmemClear();
|
|
|
|
memoryEmemClear();
|
|
|
|
memoryEmemCardsRemove();
|
|
|
|
memoryFastCardAdd();
|
|
|
|
memoryBankClearAll();
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryChipMap(true);
|
2013-02-06 04:11:41 +00:00
|
|
|
memorySlowMap();
|
|
|
|
memoryIoMap();
|
|
|
|
memoryEmemMap();
|
|
|
|
memoryDmemMap();
|
|
|
|
memoryMysteryMap();
|
|
|
|
memoryKickMap();
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryKickExtendedMap();
|
|
|
|
rtcMap();
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void memoryHardResetPost(void)
|
|
|
|
{
|
|
|
|
memoryEmemCardInit();
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryStartup(void)
|
|
|
|
{
|
|
|
|
memorySetAddress32Bit(TRUE);
|
|
|
|
memoryBankSettingsClear();
|
|
|
|
memorySetAddress32Bit(FALSE);
|
|
|
|
memoryChipSettingsClear();
|
|
|
|
memoryFastSettingsClear();
|
|
|
|
memorySlowSettingsClear();
|
|
|
|
memoryIoSettingsClear();
|
|
|
|
memoryKickSettingsClear();
|
|
|
|
memoryEmemSettingsClear();
|
|
|
|
memoryDmemSettingsClear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void memoryShutdown(void)
|
|
|
|
{
|
|
|
|
memoryFastFree();
|
2023-10-05 22:47:48 +00:00
|
|
|
memoryKickExtendedFree();
|
|
|
|
memoryKickA1000BootstrapFree();
|
2013-02-06 04:11:41 +00:00
|
|
|
}
|
|
|
|
|