Add support for 64 Disk Drive.

Original porting effort has been done by LuigiBlood.
Original reverse engineering made by Happy-yppaH
This commit is contained in:
luigiblood 2017-11-11 00:28:50 +01:00 committed by Bobby Smiles
parent 678210c002
commit 740406ff15
21 changed files with 1501 additions and 36 deletions

View file

@ -187,7 +187,7 @@ Most libmupen64plus functions return an <tt>m64p_error</tt> return code, which i
|The emulator must be currently running or paused.
|-
|M64CMD_SET_MEDIA_LOADER
|This command allow frontends to register their media (such as GameBoy cartridge) loading functions. These functions will be called appropriately by the core at startup and when a new media is inserted.
|This command allow frontends to register their media (such as GameBoy cartridge or 64DD disk) loading functions. These functions will be called appropriately by the core at startup and when a new media is inserted.
|'''<tt>ParamInt</tt>''' must be sizeof(m64p_media_loader).'''<br /><tt>ParamPtr</tt>'''A pointer to the m64p_media_loader to register, cannot be NULL.
|None
|}

View file

@ -160,6 +160,20 @@
* Empty or NULL string results in the core generating a default save file with empty content.
*/
char* (*get_gb_cart_ram)(void* cb_data, int controller_num);
/* Allow the frontend to specify the DD IPL ROM file to load
* cb_data: points to frontend-defined callback data.
* Returns a NULL-terminated string owned by the core specifying the DD IPL ROM filename to load
* Empty or NULL string results in disabled 64DD.
*/
char* (*get_dd_rom)(void* cb_data);
/* Allow the frontend to specify the DD disk file to load
* cb_data: points to frontend-defined callback data.
* Returns a NULL-terminated string owned by the core specifying the DD disk filename to load
* Empty or NULL string results in no DD disk being loaded (eg. empty disk drive).
*/
char* (*get_dd_disk)(void* cb_data);
} m64p_media_loader;
/* ----------------------------------------- */

View file

@ -60,6 +60,7 @@
<ClCompile Include="..\..\src\device\controllers\paks\mempak.c" />
<ClCompile Include="..\..\src\device\controllers\paks\rumblepak.c" />
<ClCompile Include="..\..\src\device\controllers\paks\transferpak.c" />
<ClCompile Include="..\..\src\device\dd\dd_controller.c" />
<ClCompile Include="..\..\src\device\gb\gb_cart.c" />
<ClCompile Include="..\..\src\device\gb\m64282fp.c" />
<ClCompile Include="..\..\src\device\gb\mbc3_rtc.c" />
@ -273,6 +274,7 @@
<ClInclude Include="..\..\src\device\controllers\paks\mempak.h" />
<ClInclude Include="..\..\src\device\controllers\paks\rumblepak.h" />
<ClInclude Include="..\..\src\device\controllers\paks\transferpak.h" />
<ClInclude Include="..\..\src\device\dd\dd_controller.h" />
<ClInclude Include="..\..\src\device\gb\gb_cart.h" />
<ClInclude Include="..\..\src\device\gb\m64282fp.h" />
<ClInclude Include="..\..\src\device\gb\mbc3_rtc.h" />

View file

@ -192,6 +192,9 @@
<ClCompile Include="..\..\src\backends\clock_ctime_plus_delta.c">
<Filter>backends</Filter>
</ClCompile>
<ClCompile Include="..\..\src\device\dd\dd_controller.c">
<Filter>device\dd</Filter>
</ClCompile>
<ClCompile Include="..\..\src\plugin\dummy_audio.c">
<Filter>plugin</Filter>
</ClCompile>
@ -482,6 +485,9 @@
<ClInclude Include="..\..\src\backends\clock_ctime_plus_delta.h">
<Filter>backends</Filter>
</ClInclude>
<ClInclude Include="..\..\src\device\dd\dd_controller.h">
<Filter>device\dd</Filter>
</ClInclude>
<ClInclude Include="..\..\src\plugin\dummy_audio.h">
<Filter>plugin</Filter>
</ClInclude>

View file

@ -456,6 +456,7 @@ SOURCE = \
$(SRCDIR)/device/controllers/paks/mempak.c \
$(SRCDIR)/device/controllers/paks/rumblepak.c \
$(SRCDIR)/device/controllers/paks/transferpak.c \
$(SRCDIR)/device/dd/dd_controller.c \
$(SRCDIR)/device/device.c \
$(SRCDIR)/device/gb/gb_cart.c \
$(SRCDIR)/device/gb/mbc3_rtc.c \

View file

@ -184,6 +184,20 @@ typedef struct {
* Empty or NULL string results in the core generating a default save file with empty content.
*/
char* (*get_gb_cart_ram)(void* cb_data, int controller_num);
/* Allow the frontend to specify the DD IPL ROM file to load
* cb_data: points to frontend-defined callback data.
* Returns a NULL-terminated string owned by the core specifying the DD IPL ROM filename to load
* Empty or NULL string results in disabled 64DD.
*/
char* (*get_dd_rom)(void* cb_data);
/* Allow the frontend to specify the DD disk file to load
* cb_data: points to frontend-defined callback data.
* Returns a NULL-terminated string owned by the core specifying the DD disk filename to load
* Empty or NULL string results in no DD disk being loaded (eg. empty disk drive).
*/
char* (*get_dd_disk)(void* cb_data);
} m64p_media_loader;
/* ----------------------------------------- */

View file

@ -26,6 +26,7 @@
#include "api/callbacks.h"
#include "api/m64p_types.h"
#include "backends/api/storage_backend.h"
#include "device/dd/dd_controller.h"
#include "main/util.h"
int open_file_storage(struct file_storage* fstorage, size_t size, const char* filename)
@ -102,6 +103,36 @@ static void file_storage_parent_save(void* storage)
file_storage_save(fstorage);
}
static void file_storage_dd_sdk_dump_save(void* storage)
{
static uint8_t sdk_buffer[SDK_FORMAT_DUMP_SIZE];
struct file_storage* fstorage = (struct file_storage*)storage;
/* XXX: for now, don't overwrite the original file, because we don't want to corrupt dumps... */
char* filename = formatstr("%s.save", fstorage->filename);
if (filename == NULL) {
DebugMessage(M64MSG_ERROR, "Failed to allocate memory for sdk_dump filename");
return;
}
dd_convert_to_sdk(fstorage->data, sdk_buffer);
switch(write_to_file(filename, sdk_buffer, SDK_FORMAT_DUMP_SIZE))
{
case file_open_error:
DebugMessage(M64MSG_WARNING, "couldn't open storage file '%s' for writing", fstorage->filename);
break;
case file_write_error:
DebugMessage(M64MSG_WARNING, "failed to write storage file '%s'", fstorage->filename);
break;
default:
break;
}
free(filename);
}
const struct storage_backend_interface g_ifile_storage =
{
@ -125,3 +156,9 @@ const struct storage_backend_interface g_isubfile_storage =
file_storage_parent_save
};
const struct storage_backend_interface g_ifile_storage_dd_sdk_dump =
{
file_storage_data,
file_storage_size,
file_storage_dd_sdk_dump_save
};

View file

@ -40,5 +40,6 @@ void close_file_storage(struct file_storage* storage);
extern const struct storage_backend_interface g_ifile_storage;
extern const struct storage_backend_interface g_ifile_storage_ro;
extern const struct storage_backend_interface g_isubfile_storage;
extern const struct storage_backend_interface g_ifile_storage_dd_sdk_dump;
#endif

View file

@ -0,0 +1,925 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - dd_controller.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2015 LuigiBlood *
* *
* 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 of the License, 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., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "dd_controller.h"
#include <assert.h>
#include <string.h>
#include <time.h>
#define M64P_CORE_PROTOTYPES 1
#include "api/m64p_types.h"
#include "api/callbacks.h"
#include "backends/api/clock_backend.h"
#include "backends/api/storage_backend.h"
#include "device/device.h"
#include "device/memory/memory.h"
#include "device/r4300/r4300_core.h"
/* dd commands definition */
#define DD_CMD_NOOP UINT32_C(0x00000000)
#define DD_CMD_SEEK_READ UINT32_C(0x00010001)
#define DD_CMD_SEEK_WRITE UINT32_C(0x00020001)
#define DD_CMD_RECALIBRATE UINT32_C(0x00030001) // ???
#define DD_CMD_SLEEP UINT32_C(0x00040000)
#define DD_CMD_START UINT32_C(0x00050001)
#define DD_CMD_SET_STANDBY UINT32_C(0x00060000)
#define DD_CMD_SET_SLEEP UINT32_C(0x00070000)
#define DD_CMD_CLR_DSK_CHNG UINT32_C(0x00080000)
#define DD_CMD_CLR_RESET UINT32_C(0x00090000)
#define DD_CMD_READ_VERSION UINT32_C(0x000A0000)
#define DD_CMD_SET_DISK_TYPE UINT32_C(0x000B0001)
#define DD_CMD_REQUEST_STATUS UINT32_C(0x000C0000)
#define DD_CMD_STANDBY UINT32_C(0x000D0000)
#define DD_CMD_IDX_LOCK_RETRY UINT32_C(0x000E0000) // ???
#define DD_CMD_SET_YEAR_MONTH UINT32_C(0x000F0000)
#define DD_CMD_SET_DAY_HOUR UINT32_C(0x00100000)
#define DD_CMD_SET_MIN_SEC UINT32_C(0x00110000)
#define DD_CMD_GET_YEAR_MONTH UINT32_C(0x00120000)
#define DD_CMD_GET_DAY_HOUR UINT32_C(0x00130000)
#define DD_CMD_GET_MIN_SEC UINT32_C(0x00140000)
#define DD_CMD_FEATURE_INQ UINT32_C(0x001B0000)
/* dd status register bitfields definition */
#define DD_STATUS_DATA_RQ UINT32_C(0x40000000)
#define DD_STATUS_C2_XFER UINT32_C(0x10000000)
#define DD_STATUS_BM_ERR UINT32_C(0x08000000)
#define DD_STATUS_BM_INT UINT32_C(0x04000000)
#define DD_STATUS_MECHA_INT UINT32_C(0x02000000)
#define DD_STATUS_DISK_PRES UINT32_C(0x01000000)
#define DD_STATUS_BUSY_STATE UINT32_C(0x00800000)
#define DD_STATUS_RST_STATE UINT32_C(0x00400000)
#define DD_STATUS_MTR_N_SPIN UINT32_C(0x00100000)
#define DD_STATUS_HEAD_RTRCT UINT32_C(0x00080000)
#define DD_STATUS_WR_PR_ERR UINT32_C(0x00040000)
#define DD_STATUS_MECHA_ERR UINT32_C(0x00020000)
#define DD_STATUS_DISK_CHNG UINT32_C(0x00010000)
/* dd bm status register bitfields definition */
/* read flags */
#define DD_BM_STATUS_RUNNING UINT32_C(0x80000000)
#define DD_BM_STATUS_ERROR UINT32_C(0x04000000)
#define DD_BM_STATUS_MICRO UINT32_C(0x02000000) /* ??? */
#define DD_BM_STATUS_BLOCK UINT32_C(0x01000000)
#define DD_BM_STATUS_C1CRR UINT32_C(0x00800000)
#define DD_BM_STATUS_C1DBL UINT32_C(0x00400000)
#define DD_BM_STATUS_C1SNG UINT32_C(0x00200000)
#define DD_BM_STATUS_C1ERR UINT32_C(0x00010000) /* Typo ??? */
/* write flags */
#define DD_BM_CTL_START UINT32_C(0x80000000)
#define DD_BM_CTL_MNGRMODE UINT32_C(0x40000000)
#define DD_BM_CTL_INTMASK UINT32_C(0x20000000)
#define DD_BM_CTL_RESET UINT32_C(0x10000000)
#define DD_BM_CTL_DIS_OR_CHK UINT32_C(0x08000000) /* ??? */
#define DD_BM_CTL_DIS_C1_CRR UINT32_C(0x04000000)
#define DD_BM_CTL_BLK_TRANS UINT32_C(0x02000000)
#define DD_BM_CTL_MECHA_RST UINT32_C(0x01000000)
#define DD_TRACK_LOCK UINT32_C(0x60000000)
/* disk geometry definitions */
enum { SECTORS_PER_BLOCK = 85 };
enum { BLOCKS_PER_TRACK = 2 };
enum { DD_DISK_SYSTEM_DATA_SIZE = 0xe8 };
static const unsigned int zone_sec_size[16] = {
232, 216, 208, 192, 176, 160, 144, 128,
216, 208, 192, 176, 160, 144, 128, 112
};
static const uint32_t ZoneTracks[16] = {
158, 158, 149, 149, 149, 149, 149, 114,
158, 158, 149, 149, 149, 149, 149, 114
};
static const uint32_t DiskTypeZones[7][16] = {
{ 0, 1, 2, 9, 8, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10 },
{ 0, 1, 2, 3, 10, 9, 8, 4, 5, 6, 7, 15, 14, 13, 12, 11 },
{ 0, 1, 2, 3, 4, 11, 10, 9, 8, 5, 6, 7, 15, 14, 13, 12 },
{ 0, 1, 2, 3, 4, 5, 12, 11, 10, 9, 8, 6, 7, 15, 14, 13 },
{ 0, 1, 2, 3, 4, 5, 6, 13, 12, 11, 10, 9, 8, 7, 15, 14 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8, 15 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10, 9, 8 }
};
static const uint32_t RevDiskTypeZones[7][16] = {
{ 0, 1, 2, 5, 6, 7, 8, 9, 4, 3, 15, 14, 13, 12, 11, 10 },
{ 0, 1, 2, 3, 7, 8, 9, 10, 6, 5, 4, 15, 14, 13, 12, 11 },
{ 0, 1, 2, 3, 4, 9, 10, 11, 8, 7, 6, 5, 15, 14, 13, 12 },
{ 0, 1, 2, 3, 4, 5, 11, 12, 10, 9, 8, 7, 6, 15, 14, 13 },
{ 0, 1, 2, 3, 4, 5, 6, 13, 12, 11, 10, 9, 8, 7, 15, 14 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8, 15 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10, 9, 8 }
};
static const uint32_t StartBlock[7][16] = {
{ 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1 },
{ 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0 },
{ 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1 },
{ 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0 },
{ 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1 },
{ 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0 },
{ 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1 }
};
#define BLOCKSIZE(_zone) zone_sec_size[_zone] * SECTORS_PER_BLOCK
#define TRACKSIZE(_zone) BLOCKSIZE(_zone) * BLOCKS_PER_TRACK
#define ZONESIZE(_zone) TRACKSIZE(_zone) * ZoneTracks[_zone]
#define VZONESIZE(_zone) TRACKSIZE(_zone) * (ZoneTracks[_zone] - 0xC)
static unsigned char byte2bcd(int n)
{
n %= 100;
return ((n / 10) << 4) | (n % 10);
}
static uint32_t time2data(int hi, int lo)
{
return ((uint32_t)byte2bcd(hi) << 24)
| ((uint32_t)byte2bcd(lo) << 16);
}
static void update_rtc(struct dd_rtc* rtc)
{
/* update rtc->now */
time_t now = rtc->iclock->get_time(rtc->clock);
rtc->now += now - rtc->last_update_rtc;
rtc->last_update_rtc = now;
}
static void signal_dd_interrupt(struct dd_controller* dd, uint32_t bm_int)
{
dd->regs[DD_ASIC_CMD_STATUS] |= bm_int;
r4300_check_interrupt(dd->r4300, CP0_CAUSE_IP3, 1);
}
static void clear_dd_interrupt(struct dd_controller* dd, uint32_t bm_int)
{
dd->regs[DD_ASIC_CMD_STATUS] &= ~bm_int;
r4300_check_interrupt(dd->r4300, CP0_CAUSE_IP3, 0);
}
static void read_C2(struct dd_controller* dd)
{
size_t i;
size_t length = zone_sec_size[dd->bm_zone];
size_t offset = 0x40 * (dd->regs[DD_ASIC_CUR_SECTOR] - SECTORS_PER_BLOCK);
DebugMessage(M64MSG_INFO, "read C2: length=%08x, offset=%08x",
length, offset);
for (i = 0; i < length; ++i) {
dd->c2s_buf[(offset + i) ^ 3] = 0;
}
}
static void read_sector(struct dd_controller* dd)
{
size_t i;
const uint8_t* disk_mem = dd->idisk->data(dd->disk);
size_t offset = dd->bm_track_offset
+ dd->bm_block * BLOCKSIZE(dd->bm_zone)
+ dd->regs[DD_ASIC_CUR_SECTOR] * (dd->regs[DD_ASIC_HOST_SECBYTE] + 1);
size_t length = dd->regs[DD_ASIC_HOST_SECBYTE] + 1;
for (i = 0; i < length; ++i) {
dd->ds_buf[i ^ 3] = disk_mem[offset + i];
}
}
static void write_sector(struct dd_controller* dd)
{
size_t i;
uint8_t* disk_mem = dd->idisk->data(dd->disk);
size_t offset = dd->bm_track_offset
+ dd->bm_block * BLOCKSIZE(dd->bm_zone)
+ (dd->regs[DD_ASIC_CUR_SECTOR] - 1) * zone_sec_size[dd->bm_zone];
size_t length = zone_sec_size[dd->bm_zone];
for (i = 0; i < length; ++i) {
disk_mem[offset + i] = dd->ds_buf[i ^ 3];
}
#if 0 /* disabled for now, because it causes too much slowdowns */
dd->idisk->save(dd->disk);
#endif
}
static void seek_track(struct dd_controller* dd)
{
static const unsigned int start_offset[] = {
0x0000000, 0x05f15e0, 0x0b79d00, 0x10801a0,
0x1523720, 0x1963d80, 0x1d414c0, 0x20bbce0,
0x23196e0, 0x28a1e00, 0x2df5dc0, 0x3299340,
0x36d99a0, 0x3ab70e0, 0x3e31900, 0x4149200
};
static const unsigned int tracks[] = {
0x000, 0x09e, 0x13c, 0x1d1, 0x266, 0x2fb, 0x390, 0x425
};
unsigned int tr_off;
unsigned int head_x_8 = ((dd->regs[DD_ASIC_CUR_TK] & 0x1000) >> 9);
unsigned int track = (dd->regs[DD_ASIC_CUR_TK] & 0x0fff);
/* find track bm_zone */
for (dd->bm_zone = 7; dd->bm_zone > 0; --dd->bm_zone) {
if (track >= tracks[dd->bm_zone]) {
break;
}
}
tr_off = track - tracks[dd->bm_zone];
/* set zone and track offset */
dd->bm_zone += head_x_8;
dd->bm_track_offset = start_offset[dd->bm_zone] + tr_off * TRACKSIZE(dd->bm_zone);
/* lock track */
dd->regs[DD_ASIC_CUR_TK] |= DD_TRACK_LOCK;
}
void dd_update_bm(void* opaque)
{
struct dd_controller* dd = (struct dd_controller*)opaque;
/* not running */
if ((dd->regs[DD_ASIC_BM_STATUS_CTL] & DD_BM_STATUS_RUNNING) == 0) {
return;
}
/* handle writes (BM mode 0) */
if (dd->bm_write) {
/* first sector : just issue a BM interrupt to get things going */
if (dd->regs[DD_ASIC_CUR_SECTOR] == 0) {
++dd->regs[DD_ASIC_CUR_SECTOR];
dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_DATA_RQ;
}
/* subsequent sectors: write previous sector */
else if (dd->regs[DD_ASIC_CUR_SECTOR] < SECTORS_PER_BLOCK) {
write_sector(dd);
++dd->regs[DD_ASIC_CUR_SECTOR];
dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_DATA_RQ;
}
/* otherwise write last sector */
else if (dd->regs[DD_ASIC_CUR_SECTOR] < SECTORS_PER_BLOCK + 1) {
/* continue to next block */
if (dd->regs[DD_ASIC_BM_STATUS_CTL] & DD_BM_STATUS_BLOCK) {
write_sector(dd);
dd->bm_block = 1 - dd->bm_block;
dd->regs[DD_ASIC_CUR_SECTOR] = 1;
dd->regs[DD_ASIC_BM_STATUS_CTL] &= ~DD_BM_STATUS_BLOCK;
dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_DATA_RQ;
/* quit writing after second block */
} else {
write_sector(dd);
++dd->regs[DD_ASIC_CUR_SECTOR];
dd->regs[DD_ASIC_BM_STATUS_CTL] &= ~DD_BM_STATUS_RUNNING;
}
}
else {
DebugMessage(M64MSG_ERROR, "DD Write, sector overrun");
}
}
/* handle reads (BM mode 1) */
else {
/* track 6 fails to read on retail units (XXX: retail test) */
if (((dd->regs[DD_ASIC_CUR_TK] & 0x1fff) == 6) && dd->bm_block == 0) {
dd->regs[DD_ASIC_CMD_STATUS] &= ~DD_STATUS_DATA_RQ;
dd->regs[DD_ASIC_BM_STATUS_CTL] |= DD_BM_STATUS_MICRO;
}
/* data sectors : read sector and signal BM interrupt */
else if (dd->regs[DD_ASIC_CUR_SECTOR] < SECTORS_PER_BLOCK) {
read_sector(dd);
++dd->regs[DD_ASIC_CUR_SECTOR];
dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_DATA_RQ;
}
/* C2 sectors: do nothing since they're loaded with zeros */
else if (dd->regs[DD_ASIC_CUR_SECTOR] < SECTORS_PER_BLOCK + 4) {
read_C2(dd);
++dd->regs[DD_ASIC_CUR_SECTOR];
if (dd->regs[DD_ASIC_CUR_SECTOR] == SECTORS_PER_BLOCK + 4) {
dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_C2_XFER;
}
}
/* Gap sector: continue to next block, quit after second block */
else if (dd->regs[DD_ASIC_CUR_SECTOR] == SECTORS_PER_BLOCK + 4) {
if (dd->regs[DD_ASIC_BM_STATUS_CTL] & DD_BM_STATUS_BLOCK) {
dd->bm_block = 1 - dd->bm_block;
dd->regs[DD_ASIC_CUR_SECTOR] = 0;
dd->regs[DD_ASIC_BM_STATUS_CTL] &= ~DD_BM_STATUS_BLOCK;
}
else {
dd->regs[DD_ASIC_BM_STATUS_CTL] &= ~DD_BM_STATUS_RUNNING;
}
}
else {
DebugMessage(M64MSG_ERROR, "DD Read, sector overrun");
}
}
/* Signal a BM interrupt */
signal_dd_interrupt(dd, DD_STATUS_BM_INT);
}
void init_dd(struct dd_controller* dd,
void* clock, const struct clock_backend_interface* iclock,
const uint32_t* rom, size_t rom_size,
void* disk, const struct storage_backend_interface* idisk,
struct r4300_core* r4300)
{
dd->rtc.clock = clock;
dd->rtc.iclock = iclock;
dd->rom = rom;
dd->rom_size = rom_size;
dd->disk = disk;
dd->idisk = idisk;
dd->r4300 = r4300;
}
void poweron_dd(struct dd_controller* dd)
{
memset(dd->regs, 0, DD_ASIC_REGS_COUNT*sizeof(dd->regs[0]));
memset(dd->c2s_buf, 0, 0x400);
memset(dd->ds_buf, 0, 0x100);
memset(dd->ms_ram, 0, 0x40);
dd->bm_write = 0;
dd->bm_reset_held = 0;
dd->bm_block = 0;
dd->bm_zone = 0;
dd->bm_track_offset = 0;
dd->rtc.now = 0;
dd->rtc.last_update_rtc = 0;
dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_RST_STATE;
if (dd->idisk != NULL) {
dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_DISK_PRES;
}
/* XXX: add non retail support */
dd->regs[DD_ASIC_ID_REG] = 0x00030000;
}
void read_dd_regs(void* opaque, uint32_t address, uint32_t* value)
{
struct dd_controller* dd = (struct dd_controller*)opaque;
if (address < MM_DD_REGS || address >= MM_DD_MS_RAM) {
DebugMessage(M64MSG_ERROR, "Unknown access in DD registers MMIO space %08x", address);
*value = 0;
return;
}
uint32_t reg = dd_reg(address);
/* disk presence test */
if (reg == DD_ASIC_CMD_STATUS) {
if (dd->idisk != NULL) {
dd->regs[reg] |= DD_STATUS_DISK_PRES;
}
else {
dd->regs[reg] &= ~DD_STATUS_DISK_PRES;
}
}
*value = dd->regs[reg];
DebugMessage(M64MSG_INFO, "DD REG: %08X -> %08x", address, *value);
/* post read update. Not part of the returned value */
switch(reg)
{
case DD_ASIC_CMD_STATUS: {
/* clear BM interrupt when reading gap */
if ((dd->regs[DD_ASIC_CMD_STATUS] & DD_STATUS_BM_INT) && (dd->regs[DD_ASIC_CUR_SECTOR] > SECTORS_PER_BLOCK)) {
clear_dd_interrupt(dd, DD_STATUS_BM_INT);
dd_update_bm(dd);
}
} break;
}
}
void write_dd_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
{
uint8_t start_sector;
struct dd_controller* dd = (struct dd_controller*)opaque;
if (address < MM_DD_REGS || address >= MM_DD_MS_RAM) {
DebugMessage(M64MSG_ERROR, "Unknown access in DD registers MMIO space %08x", address);
return;
}
uint32_t reg = dd_reg(address);
assert(mask == ~UINT32_C(0));
DebugMessage(M64MSG_INFO, "DD REG: %08X <- %08x", address, value);
switch (reg)
{
case DD_ASIC_DATA:
dd->regs[DD_ASIC_DATA] = value;
break;
case DD_ASIC_CMD_STATUS:
update_rtc(&dd->rtc);
const struct tm* tm = localtime(&dd->rtc.now);
switch ((value >> 16) & 0xff)
{
/* No-op */
case 0x00:
break;
/* Seek track */
case 0x01:
case 0x02:
dd->regs[DD_ASIC_CUR_TK] = dd->regs[DD_ASIC_DATA] >> 16;
seek_track(dd);
dd->bm_write = (value >> 17) & 0x1;
break;
/* Clear Disk change flag */
case 0x08:
dd->regs[DD_ASIC_CMD_STATUS] &= ~DD_STATUS_DISK_CHNG;
break;
/* Clear reset flag */
case 0x09:
dd->regs[DD_ASIC_CMD_STATUS] &= ~DD_STATUS_RST_STATE;
dd->regs[DD_ASIC_CMD_STATUS] &= ~DD_STATUS_DISK_CHNG;
break;
/* Set Disk type */
case 0x0b:
DebugMessage(M64MSG_INFO, "Setting disk type %u", (dd->regs[DD_ASIC_DATA] >> 16) & 0xf);
break;
/* Read RTC in ASIC_DATA (BCD format) */
case 0x12:
dd->regs[DD_ASIC_DATA] = time2data(tm->tm_year, tm->tm_mon + 1);
break;
case 0x13:
dd->regs[DD_ASIC_DATA] = time2data(tm->tm_mday, tm->tm_hour);
break;
case 0x14:
dd->regs[DD_ASIC_DATA] = time2data(tm->tm_min, tm->tm_sec);
break;
/* Feature inquiry */
case 0x1b:
dd->regs[DD_ASIC_DATA] = 0x00000000;
break;
default:
DebugMessage(M64MSG_WARNING, "DD ASIC CMD not yet implemented (%08x)", value);
}
/* Signal a MECHA interrupt */
signal_dd_interrupt(dd, DD_STATUS_MECHA_INT);
break;
case DD_ASIC_BM_STATUS_CTL:
/* set sector */
start_sector = (value >> 16) & 0xff;
if (start_sector == 0x00) {
dd->bm_block = 0;
dd->regs[DD_ASIC_CUR_SECTOR] = 0;
} else if (start_sector == 0x5a) {
dd->bm_block = 1;
dd->regs[DD_ASIC_CUR_SECTOR] = 0;
}
else {
DebugMessage(M64MSG_ERROR, "Start sector not aligned");
}
/* clear MECHA interrupt */
if (value & DD_BM_CTL_MECHA_RST) {
dd->regs[DD_ASIC_CMD_STATUS] &= ~DD_STATUS_MECHA_INT;
}
/* start block transfer */
if (value & DD_BM_CTL_BLK_TRANS) {
dd->regs[DD_ASIC_BM_STATUS_CTL] |= DD_BM_STATUS_BLOCK;
}
/* handle reset */
if (value & DD_BM_CTL_RESET) {
dd->bm_reset_held = 1;
}
if (!(value & DD_BM_CTL_RESET) && dd->bm_reset_held) {
dd->bm_reset_held = 0;
dd->regs[DD_ASIC_CMD_STATUS] &= ~(DD_STATUS_DATA_RQ
| DD_STATUS_C2_XFER
| DD_STATUS_BM_ERR
| DD_STATUS_BM_INT);
dd->regs[DD_ASIC_BM_STATUS_CTL] = 0;
dd->regs[DD_ASIC_CUR_SECTOR] = 0;
dd->bm_block = 0;
}
/* clear DD interrupt if both MECHA and BM are cleared */
if ((dd->regs[DD_ASIC_CMD_STATUS] & (DD_STATUS_BM_INT | DD_STATUS_MECHA_INT)) == 0) {
clear_dd_interrupt(dd, DD_STATUS_BM_INT);
}
/* start transfer */
if (value & DD_BM_CTL_START) {
if (dd->bm_write && (value & DD_BM_CTL_MNGRMODE)) {
DebugMessage(M64MSG_WARNING, "Attempt to write disk with BM mode 1");
}
if (!dd->bm_write && !(value & DD_BM_CTL_MNGRMODE)) {
DebugMessage(M64MSG_WARNING, "Attempt to read disk with BM mode 0");
}
dd->regs[DD_ASIC_BM_STATUS_CTL] |= DD_BM_STATUS_RUNNING;
dd_update_bm(dd);
}
break;
case DD_ASIC_HARD_RESET:
if (value != 0xaaaa0000) {
DebugMessage(M64MSG_WARNING, "Unexpected hard reset value %08x", value);
}
dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_RST_STATE;
break;
case DD_ASIC_HOST_SECBYTE:
dd->regs[DD_ASIC_HOST_SECBYTE] = (value >> 16) & 0xff;
if ((dd->regs[DD_ASIC_HOST_SECBYTE] + 1) != zone_sec_size[dd->bm_zone]) {
DebugMessage(M64MSG_WARNING, "Sector size %u set different than expected %u",
dd->regs[DD_ASIC_HOST_SECBYTE] + 1, zone_sec_size[dd->bm_zone]);
}
break;
case DD_ASIC_SEC_BYTE:
dd->regs[DD_ASIC_SEC_BYTE] = (value >> 24) & 0xff;
if (dd->regs[DD_ASIC_SEC_BYTE] != SECTORS_PER_BLOCK + 4) {
DebugMessage(M64MSG_WARNING, "Sectors per block %u set different than expected %u",
dd->regs[DD_ASIC_SEC_BYTE] + 1, SECTORS_PER_BLOCK + 4);
}
break;
default:
dd->regs[reg] = value;
}
}
void read_dd_rom(void* opaque, uint32_t address, uint32_t* value)
{
struct dd_controller* dd = (struct dd_controller*)opaque;
uint32_t addr = dd_rom_address(address);
*value = dd->rom[addr];
DebugMessage(M64MSG_INFO, "DD ROM: %08X -> %08x", address, *value);
}
void write_dd_rom(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
{
DebugMessage(M64MSG_WARNING, "DD ROM: %08X <- %08x & %08x", address, value, mask);
}
unsigned int dd_dom_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
{
struct dd_controller* dd = (struct dd_controller*)opaque;
uint8_t* mem;
size_t i;
DebugMessage(M64MSG_INFO, "DD DMA read dram=%08x cart=%08x length=%08x",
dram_addr, cart_addr, length);
if (cart_addr == MM_DD_DS_BUFFER) {
cart_addr = (cart_addr - MM_DD_DS_BUFFER) & 0x3fffff;
mem = dd->ds_buf;
}
else {
DebugMessage(M64MSG_ERROR, "Unknown DD dma read dram=%08x cart=%08x length=%08x",
dram_addr, cart_addr, length);
return (length * 63) / 25;
}
for (i = 0; i < length; ++i) {
mem[(cart_addr + i) ^ S8] = dram[(dram_addr + i) ^ S8];
}
return (length * 63) / 25;
}
unsigned int dd_dom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
{
struct dd_controller* dd = (struct dd_controller*)opaque;
unsigned int cycles;
const uint8_t* mem;
size_t i;
DebugMessage(M64MSG_INFO, "DD DMA write dram=%08x cart=%08x length=%08x",
dram_addr, cart_addr, length);
if (cart_addr < MM_DD_ROM) {
if (cart_addr == MM_DD_C2S_BUFFER) {
/* C2 sector buffer */
cart_addr = (cart_addr - MM_DD_C2S_BUFFER);
mem = (const uint8_t*)&dd->c2s_buf;
}
else if (cart_addr == MM_DD_DS_BUFFER) {
/* Data sector buffer */
cart_addr = (cart_addr - MM_DD_DS_BUFFER);
mem = (const uint8_t*)&dd->ds_buf;
}
else {
DebugMessage(M64MSG_ERROR, "Unknown DD dma write dram=%08x cart=%08x length=%08x",
dram_addr, cart_addr, length);
return (length * 63) / 25;
}
cycles = (length * 63) / 25;
}
else {
/* DD ROM */
cart_addr = (cart_addr - MM_DD_ROM);
mem = (const uint8_t*)dd->rom;
cycles = (length * 63) / 25;
}
for (i = 0; i < length; ++i) {
dram[(dram_addr + i) ^ S8] = mem[(cart_addr + i) ^ S8];
}
invalidate_r4300_cached_code(dd->r4300, R4300_KSEG0 + dram_addr, length);
invalidate_r4300_cached_code(dd->r4300, R4300_KSEG1 + dram_addr, length);
return cycles;
}
void dd_on_pi_cart_addr_write(struct dd_controller* dd, uint32_t address)
{
/* clear C2 xfer */
if (address == MM_DD_C2S_BUFFER) {
dd->regs[DD_ASIC_CMD_STATUS] &= ~(DD_STATUS_C2_XFER | DD_STATUS_BM_ERR);
clear_dd_interrupt(dd, DD_STATUS_BM_INT);
}
/* clear data RQ */
else if (address == MM_DD_DS_BUFFER) {
dd->regs[DD_ASIC_CMD_STATUS] &= ~(DD_STATUS_DATA_RQ | DD_STATUS_BM_ERR);
clear_dd_interrupt(dd, DD_STATUS_BM_INT);
}
}
/* Disk conversion routines */
void dd_convert_to_mame(unsigned char* mame_disk, const unsigned char* sdk_disk)
{
/* Original code by Happy_ */
uint8_t system_data[DD_DISK_SYSTEM_DATA_SIZE];
uint8_t block_data[2][0x100 * SECTORS_PER_BLOCK];
uint32_t disktype = 0;
uint32_t zone, track = 0;
int32_t atrack = 0;
int32_t block = 0;
uint32_t InOffset, OutOffset = 0;
uint32_t InStart[16];
uint32_t OutStart[16];
int cur_offset = 0;
/* Read System Area */
memcpy(system_data, sdk_disk, DD_DISK_SYSTEM_DATA_SIZE);
disktype = system_data[5] & 0xf;
/* Prepare Input Offsets */
InStart[0] = 0;
for (zone = 1; zone < 16; ++zone) {
InStart[zone] = InStart[zone - 1] + VZONESIZE(DiskTypeZones[disktype][zone - 1]);
}
/* Prepare Output Offsets */
OutStart[0] = 0;
for (zone = 1; zone < 16; ++zone) {
OutStart[zone] = OutStart[zone - 1] + ZONESIZE(zone - 1);
}
/* Copy Head 0 */
for (zone = 0; zone < 8; zone++)
{
OutOffset = OutStart[zone];
InOffset = InStart[RevDiskTypeZones[disktype][zone]];
cur_offset = InOffset;
block = StartBlock[disktype][zone];
atrack = 0;
for (track = 0; track < ZoneTracks[zone]; track++)
{
if (atrack < 0xC && track == system_data[0x20 + zone * 0xC + atrack])
{
memset((void *)(&block_data[0]), 0, BLOCKSIZE(zone));
memset((void *)(&block_data[1]), 0, BLOCKSIZE(zone));
atrack += 1;
}
else
{
if ((block % 2) == 1)
{
memcpy(block_data[1], sdk_disk + cur_offset, BLOCKSIZE(zone));
cur_offset += BLOCKSIZE(zone);
memcpy(block_data[0], sdk_disk + cur_offset, BLOCKSIZE(zone));
cur_offset += BLOCKSIZE(zone);
}
else
{
memcpy(block_data[0], sdk_disk + cur_offset, BLOCKSIZE(zone));
cur_offset += BLOCKSIZE(zone);
memcpy(block_data[1], sdk_disk + cur_offset, BLOCKSIZE(zone));
cur_offset += BLOCKSIZE(zone);
}
block = 1 - block;
}
memcpy(mame_disk + OutOffset, &block_data[0], BLOCKSIZE(zone));
OutOffset += BLOCKSIZE(zone);
memcpy(mame_disk + OutOffset, &block_data[1], BLOCKSIZE(zone));
OutOffset += BLOCKSIZE(zone);
}
}
/* Copy Head 1 */
for (zone = 8; zone < 16; zone++)
{
InOffset = InStart[RevDiskTypeZones[disktype][zone]];
cur_offset = InOffset;
block = StartBlock[disktype][zone];
atrack = 0xB;
for (track = 1; track < ZoneTracks[zone] + 1; track++)
{
if (atrack > -1 && (ZoneTracks[zone] - track) == system_data[0x20 + (zone)* 0xC + atrack])
{
memset((void *)(&block_data[0]), 0, BLOCKSIZE(zone));
memset((void *)(&block_data[1]), 0, BLOCKSIZE(zone));
atrack -= 1;
}
else
{
if ((block % 2) == 1)
{
memcpy(block_data[1], sdk_disk + cur_offset, BLOCKSIZE(zone));
cur_offset += BLOCKSIZE(zone);
memcpy(block_data[0], sdk_disk + cur_offset, BLOCKSIZE(zone));
cur_offset += BLOCKSIZE(zone);
}
else
{
memcpy(block_data[0], sdk_disk + cur_offset, BLOCKSIZE(zone));
cur_offset += BLOCKSIZE(zone);
memcpy(block_data[1], sdk_disk + cur_offset, BLOCKSIZE(zone));
cur_offset += BLOCKSIZE(zone);
}
block = 1 - block;
}
OutOffset = OutStart[zone] + (ZoneTracks[zone] - track) * TRACKSIZE(zone);
memcpy(mame_disk + OutOffset, &block_data[0], BLOCKSIZE(zone));
OutOffset += BLOCKSIZE(zone);
memcpy(mame_disk + OutOffset, &block_data[1], BLOCKSIZE(zone));
OutOffset += BLOCKSIZE(zone);
}
}
}
void dd_convert_to_sdk(const unsigned char* mame_disk, unsigned char* sdk_disk)
{
/* Original code by Happy_ */
uint8_t system_data[DD_DISK_SYSTEM_DATA_SIZE];
uint8_t block_data[2][0x100 * SECTORS_PER_BLOCK];
uint32_t disktype = 0;
uint32_t zone, track = 0;
int32_t atrack = 0;
int32_t block = 0;
uint32_t InOffset, OutOffset = 0;
uint32_t InStart[16];
uint32_t OutStart[16];
/* Read System Area */
memcpy(system_data, mame_disk, DD_DISK_SYSTEM_DATA_SIZE);
disktype = system_data[5] & 0xf;
/* Prepare Input Offsets */
InStart[0] = 0;
for (zone = 1; zone < 16; ++zone) {
InStart[zone] = InStart[zone - 1] + VZONESIZE(DiskTypeZones[disktype][zone - 1]);
}
/* Prepare Output Offsets */
OutStart[0] = 0;
for (zone = 1; zone < 16; ++zone) {
OutStart[zone] = OutStart[zone - 1] + ZONESIZE(zone - 1);
}
/* Copy Head 0 */
for (zone = 0; zone < 8; zone++)
{
block = StartBlock[disktype][zone];
atrack = 0;
for (track = 0; track < ZoneTracks[zone]; track++)
{
InOffset = OutStart[zone] + (track)* TRACKSIZE(zone);
OutOffset = InStart[RevDiskTypeZones[disktype][zone]] + (track - atrack) * TRACKSIZE(zone);
if (atrack < 0xC && track == system_data[0x20 + zone * 0xC + atrack])
{
atrack += 1;
}
else
{
if ((block % 2) == 1)
{
memcpy(&block_data[1], mame_disk + InOffset, BLOCKSIZE(zone));
InOffset += BLOCKSIZE(zone);
memcpy(&block_data[0], mame_disk + InOffset, BLOCKSIZE(zone));
InOffset += BLOCKSIZE(zone);
}
else
{
memcpy(&block_data[0], mame_disk + InOffset, BLOCKSIZE(zone));
InOffset += BLOCKSIZE(zone);
memcpy(&block_data[1], mame_disk + InOffset, BLOCKSIZE(zone));
InOffset += BLOCKSIZE(zone);
}
block = 1 - block;
memcpy(sdk_disk + OutOffset, &block_data[0], BLOCKSIZE(zone));
OutOffset += BLOCKSIZE(zone);
memcpy(sdk_disk + OutOffset, &block_data[1], BLOCKSIZE(zone));
OutOffset += BLOCKSIZE(zone);
}
}
}
/* Copy Head 1 */
for (zone = 8; zone < 16; zone++)
{
block = StartBlock[disktype][zone];
atrack = 0xB;
for (track = 1; track < ZoneTracks[zone] + 1; track++)
{
InOffset = OutStart[zone] + (ZoneTracks[zone] - track) * TRACKSIZE(zone);
OutOffset = InStart[RevDiskTypeZones[disktype][zone]] + (track - (0xB - atrack) - 1) * TRACKSIZE(zone);
if (atrack > -1 && (ZoneTracks[zone] - track) == system_data[0x20 + (zone)* 0xC + atrack])
{
atrack -= 1;
}
else
{
if ((block % 2) == 1)
{
memcpy(&block_data[1], mame_disk + InOffset, BLOCKSIZE(zone));
InOffset += BLOCKSIZE(zone);
memcpy(&block_data[0], mame_disk + InOffset, BLOCKSIZE(zone));
InOffset += BLOCKSIZE(zone);
}
else
{
memcpy(&block_data[0], mame_disk + InOffset, BLOCKSIZE(zone));
InOffset += BLOCKSIZE(zone);
memcpy(&block_data[1], mame_disk + InOffset, BLOCKSIZE(zone));
InOffset += BLOCKSIZE(zone);
}
block = 1 - block;
memcpy(sdk_disk + OutOffset, &block_data[0], BLOCKSIZE(zone));
OutOffset += BLOCKSIZE(zone);
memcpy(sdk_disk + OutOffset, &block_data[1], BLOCKSIZE(zone));
OutOffset += BLOCKSIZE(zone);
}
}
}
}

View file

@ -0,0 +1,138 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - dd_controller.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2015 LuigiBlood *
* *
* 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 of the License, 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., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_DEVICE_DD_CONTROLLER_H
#define M64P_DEVICE_DD_CONTROLLER_H
struct r4300_core;
#include <stdint.h>
#include <time.h>
#include "osal/preproc.h"
struct clock_backend_interface;
struct storage_backend_interface;
/* Disk format sizes */
#define MAME_FORMAT_DUMP_SIZE 0x0435b0c0
#define SDK_FORMAT_DUMP_SIZE 0x03dec800
#define DD_REGION_JP UINT32_C(0xe848d316)
#define DD_REGION_US UINT32_C(0x2263ee56)
enum dd_registers {
DD_ASIC_DATA,
DD_ASIC_MISC_REG,
DD_ASIC_CMD_STATUS,
DD_ASIC_CUR_TK,
DD_ASIC_BM_STATUS_CTL,
DD_ASIC_ERR_SECTOR,
DD_ASIC_SEQ_STATUS_CTL,
DD_ASIC_CUR_SECTOR,
DD_ASIC_HARD_RESET,
DD_ASIC_C1_S0,
DD_ASIC_HOST_SECBYTE,
DD_ASIC_C1_S2,
DD_ASIC_SEC_BYTE,
DD_ASIC_C1_S4,
DD_ASIC_C1_S6,
DD_ASIC_CUR_ADDR,
DD_ASIC_ID_REG,
DD_ASIC_TEST_REG,
DD_ASIC_TEST_PIN_SEL,
DD_ASIC_REGS_COUNT
};
struct dd_rtc
{
time_t now;
time_t last_update_rtc;
void* clock;
const struct clock_backend_interface* iclock;
};
struct dd_controller
{
uint32_t regs[DD_ASIC_REGS_COUNT]; /* 0x500-0x54f: registers */
uint8_t c2s_buf[0x400]; /* 0x000-0x3ff: c2s buffer */
uint8_t ds_buf[0x100]; /* 0x400-0x4ff: data buffer */
uint8_t ms_ram[0x40]; /* 0x580-0x5bf: micro sequencer */
/* buffer manager */
unsigned char bm_write; /* [0-1] */
unsigned char bm_reset_held; /* [0-1] */
unsigned char bm_block; /* [0-1] */
unsigned int bm_zone; /* [0-15] */
unsigned int bm_track_offset; /* */
/* DD RTC */
struct dd_rtc rtc;
/* DD ROM */
const uint32_t* rom;
size_t rom_size;
/* DD Disk */
void* disk;
const struct storage_backend_interface* idisk;
struct r4300_core* r4300;
};
static osal_inline uint32_t dd_reg(uint32_t address)
{
return (address & 0xff) >> 2;
}
static osal_inline uint32_t dd_rom_address(uint32_t address)
{
return (address & 0x3fffff) >> 2;
}
void init_dd(struct dd_controller* dd,
void* clock, const struct clock_backend_interface* iclock,
const uint32_t* rom, size_t rom_size,
void* disk, const struct storage_backend_interface* idisk,
struct r4300_core* r4300);
void poweron_dd(struct dd_controller* dd);
void read_dd_regs(void* opaque, uint32_t address, uint32_t* value);
void write_dd_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask);
void read_dd_rom(void* opaque, uint32_t address, uint32_t* value);
void write_dd_rom(void* opaque, uint32_t address, uint32_t value, uint32_t mask);
unsigned int dd_dom_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
unsigned int dd_dom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
void dd_on_pi_cart_addr_write(struct dd_controller* dd, uint32_t address);
void dd_update_bm(void* opaque);
/* Disk conversion routines */
void dd_convert_to_mame(unsigned char* mame_disk, const unsigned char* sdk_disk);
void dd_convert_to_sdk (const unsigned char* mame_disk, unsigned char* sdk_disk);
#endif

View file

@ -46,18 +46,7 @@ static void write_open_bus(void* opaque, uint32_t address, uint32_t value, uint3
{
}
static unsigned int dd_dom_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
{
return /* length / 8 */0x1000;
}
static unsigned int dd_dom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
{
return /* length / 8 */0x1000;
}
static void get_pi_dma_handler(struct device* dev, uint32_t address, void** opaque, const struct pi_dma_handler** handler)
static void get_pi_dma_handler(struct cart* cart, struct dd_controller* dd, uint32_t address, void** opaque, const struct pi_dma_handler** handler)
{
#define RW(o, x) \
do { \
@ -69,21 +58,21 @@ static void get_pi_dma_handler(struct device* dev, uint32_t address, void** opaq
if (address >= MM_CART_ROM) {
if (address >= MM_CART_DOM3) {
/* 0x1fd00000 - 0x7fffffff : dom3 addr2, cart rom (Paper Mario (U)) ??? */
RW(&dev->cart, cart_dom3);
RW(cart, cart_dom3);
}
else {
/* 0x10000000 - 0x1fbfffff : dom1 addr2, cart rom */
RW(&dev->cart.cart_rom, cart_rom);
RW(&cart->cart_rom, cart_rom);
}
}
else if (address >= MM_DOM2_ADDR2) {
/* 0x08000000 - 0x0fffffff : dom2 addr2, cart save */
RW(&dev->cart, cart_dom2);
RW(cart, cart_dom2);
}
else if (address >= MM_DOM2_ADDR1) {
/* 0x05000000 - 0x05ffffff : dom2 addr1, dd buffers */
/* 0x06000000 - 0x07ffffff : dom1 addr1, dd rom */
RW(NULL, dd_dom);
RW(dd, dd_dom);
}
#undef RW
}
@ -114,7 +103,11 @@ void init_device(struct device* dev,
void* eeprom_storage, const struct storage_backend_interface* ieeprom_storage,
uint32_t flashram_type,
void* flashram_storage, const struct storage_backend_interface* iflashram_storage,
void* sram_storage, const struct storage_backend_interface* isram_storage)
void* sram_storage, const struct storage_backend_interface* isram_storage,
/* dd */
void* dd_rtc_clock, const struct clock_backend_interface* dd_rtc_iclock,
size_t dd_rom_size,
void* dd_disk, const struct storage_backend_interface* dd_idisk)
{
struct interrupt_handler interrupt_handlers[] = {
{ &dev->vi, vi_vertical_interrupt_event }, /* VI */
@ -152,11 +145,25 @@ void init_device(struct device* dev,
{ A(MM_PI_REGS, 0xffff), M64P_MEM_PI, { &dev->pi, RW(pi_regs) } },
{ A(MM_RI_REGS, 0xffff), M64P_MEM_RI, { &dev->ri, RW(ri_regs) } },
{ A(MM_SI_REGS, 0xffff), M64P_MEM_SI, { &dev->si, RW(si_regs) } },
{ A(MM_DOM2_ADDR1, 0xffffff), M64P_MEM_NOTHING, { NULL, RW(open_bus) } },
{ A(MM_DD_ROM, 0x1ffffff), M64P_MEM_NOTHING, { NULL, RW(open_bus) } },
{ A(MM_DOM2_ADDR2, 0x1ffff), M64P_MEM_FLASHRAMSTAT, { &dev->cart, RW(cart_dom2) } },
{ A(MM_CART_ROM, rom_size-1), M64P_MEM_ROM, { &dev->cart.cart_rom, RW(cart_rom) } },
{ A(MM_PIF_MEM, 0xffff), M64P_MEM_PIF, { &dev->pif, RW(pif_ram) } }
};
/* init and map DD if present */
if (dd_rom_size > 0) {
mappings[14] = (struct mem_mapping){ A(MM_DOM2_ADDR1, 0xffffff), M64P_MEM_NOTHING, { &dev->dd, RW(dd_regs) } };
mappings[15] = (struct mem_mapping){ A(MM_DD_ROM, dd_rom_size-1), M64P_MEM_NOTHING, { &dev->dd, RW(dd_rom) } };
init_dd(&dev->dd,
dd_rtc_clock, dd_rtc_iclock,
(const uint32_t*)((uint8_t*)base + MM_DD_ROM), dd_rom_size,
dd_disk, dd_idisk,
&dev->r4300);
}
struct mem_handler dbg_handler = { &dev->r4300, RW(with_bp_checks) };
#undef A
#undef R
@ -174,16 +181,26 @@ void init_device(struct device* dev,
init_ai(&dev->ai, &dev->mi, &dev->ri, &dev->vi, aout, iaout);
init_mi(&dev->mi, &dev->r4300);
init_pi(&dev->pi,
dev, get_pi_dma_handler,
get_pi_dma_handler,
&dev->cart, &dev->dd,
&dev->mi, &dev->ri, &dev->dp);
init_ri(&dev->ri, &dev->rdram);
init_si(&dev->si, si_dma_duration, &dev->mi, &dev->pif, &dev->ri);
init_vi(&dev->vi, vi_clock, expected_refresh_rate, &dev->mi, &dev->dp);
/* FIXME: should boot on cart, unless only a disk is present, but having no cart is not yet supported by ui/core,
* so use another way of selecting boot device:
* use CART unless DD is plugged and the plugged CART is not a combo media (cart+disk).
*/
uint8_t media = *((uint8_t*)mem_base_u32(base, MM_CART_ROM) + (0x3b ^ S8));
uint32_t rom_base = (dd_rom_size > 0 && media != 'C')
? MM_DD_ROM
: MM_CART_ROM;
init_pif(&dev->pif,
(uint8_t*)mem_base_u32(base, MM_PIF_MEM),
jbds, ijbds,
(uint8_t*)mem_base_u32(base, MM_CART_ROM + 0x40),
(uint8_t*)mem_base_u32(base, rom_base) + 0x40,
&dev->r4300);
init_cart(&dev->cart,
@ -223,6 +240,10 @@ void poweron_device(struct device* dev)
channel->ijbd->poweron(channel->jbd);
}
}
if (dev->dd.rom != NULL) {
poweron_dd(&dev->dd);
}
}
void run_device(struct device* dev)

View file

@ -30,6 +30,7 @@
#include "controllers/paks/mempak.h"
#include "controllers/paks/rumblepak.h"
#include "controllers/paks/transferpak.h"
#include "dd/dd_controller.h"
#include "gb/gb_cart.h"
#include "memory/memory.h"
#include "pif/pif.h"
@ -68,6 +69,10 @@ enum { GAME_CONTROLLERS_COUNT = 4 };
#define MM_SI_REGS UINT32_C(0x04800000)
#define MM_DOM2_ADDR1 UINT32_C(0x05000000)
#define MM_DD_C2S_BUFFER UINT32_C(0x05000000)
#define MM_DD_DS_BUFFER UINT32_C(0x05000400)
#define MM_DD_REGS UINT32_C(0x05000500)
#define MM_DD_MS_RAM UINT32_C(0x05000580)
#define MM_DD_ROM UINT32_C(0x06000000)
#define MM_DOM2_ADDR2 UINT32_C(0x08000000)
@ -100,6 +105,8 @@ struct device
struct gb_cart gb_carts[GAME_CONTROLLERS_COUNT];
struct cart cart;
struct dd_controller dd;
};
/* Setup device "static" properties. */
@ -129,7 +136,11 @@ void init_device(struct device* dev,
void* eeprom_storage, const struct storage_backend_interface* ieeprom_storage,
uint32_t flashram_type,
void* flashram_storage, const struct storage_backend_interface* iflashram_storage,
void* sram_storage, const struct storage_backend_interface* isram_storage);
void* sram_storage, const struct storage_backend_interface* isram_storage,
/* dd */
void* dd_rtc_clock, const struct clock_backend_interface* dd_rtc_iclock,
size_t dd_rom_size,
void* dd_disk, const struct storage_backend_interface* dd_idisk);
/* Setup device such that it's state is
* what it should be after power on.

View file

@ -45,7 +45,8 @@ void init_cic_using_ipl3(struct cic* cic, const void* ipl3)
{ "X103", CIC_X103, 0x78 },
{ "X105", CIC_X105, 0x91 },
{ "X106", CIC_X106, 0x85 },
{ "5167", CIC_5167, 0xdd }
{ "5167", CIC_5167, 0xdd },
{ "8303", CIC_8303, 0xdd }
};
for (i = 0; i < 0xfc0/4; i++)
@ -64,6 +65,7 @@ void init_cic_using_ipl3(struct cic* cic, const void* ipl3)
case UINT64_C(0x000000D6D5BE5580): i = 5; break; /* CIC_X106 */
case UINT64_C(0x000001053BC19870): i = 6; break; /* CIC 5167 */
case UINT64_C(0x000000A5F80BF620): i = 0; break; /* CIC 5101 */
case UINT64_C(0x000000D2E53EF008): i = 7; break; /* CIC 8303 */
}
memcpy(cic, &cics[i], sizeof(*cic));

View file

@ -30,7 +30,8 @@ enum cic_version
CIC_X105,
CIC_X106,
CIC_5101,
CIC_5167
CIC_5167,
CIC_8303
};
struct cic

View file

@ -146,7 +146,7 @@ void reset_pif(struct pif* pif, unsigned int reset_type)
size_t i;
/* HACK: for allowing pifbootrom execution */
unsigned int rom_type = 0;
unsigned int rom_type = (pif->cic.version == CIC_8303) ? 1 : 0;
unsigned int s7 = 0;
/* 0:ColdReset, 1:NMI */

View file

@ -246,7 +246,6 @@ int r4300_write_aligned_dword(struct r4300_core* r4300, uint32_t address, uint64
*/
void invalidate_r4300_cached_code(struct r4300_core* r4300, uint32_t address, size_t size);
/* Jump to the given address. This works for all r4300 emulator, but is slower.
* Use this for common code which can be executed from any r4300 emulator. */
void generic_jump_to(struct r4300_core* r4300, unsigned int address);

View file

@ -28,6 +28,7 @@
#include "api/callbacks.h"
#include "api/m64p_types.h"
#include "device/device.h"
#include "device/dd/dd_controller.h"
#include "device/memory/memory.h"
#include "device/r4300/r4300_core.h"
#include "device/rcp/mi/mi_controller.h"
@ -60,7 +61,7 @@ static void dma_pi_read(struct pi_controller* pi)
const struct pi_dma_handler* handler = NULL;
void* opaque = NULL;
pi->get_pi_dma_handler(pi->dev, cart_addr, &opaque, &handler);
pi->get_pi_dma_handler(pi->cart, pi->dd, cart_addr, &opaque, &handler);
if (handler == NULL) {
DebugMessage(M64MSG_WARNING, "Unknown PI DMA read: 0x%" PRIX32 " -> 0x%" PRIX32 " (0x%" PRIX32 ")", dram_addr, cart_addr, length);
@ -89,7 +90,7 @@ static void dma_pi_write(struct pi_controller* pi)
const struct pi_dma_handler* handler = NULL;
void* opaque = NULL;
pi->get_pi_dma_handler(pi->dev, cart_addr, &opaque, &handler);
pi->get_pi_dma_handler(pi->cart, pi->dd, cart_addr, &opaque, &handler);
if (handler == NULL) {
DebugMessage(M64MSG_WARNING, "Unknown PI DMA write: 0x%" PRIX32 " -> 0x%" PRIX32 " (0x%" PRIX32 ")", cart_addr, dram_addr, length);
@ -110,13 +111,16 @@ static void dma_pi_write(struct pi_controller* pi)
void init_pi(struct pi_controller* pi,
struct device* dev, pi_dma_handler_getter get_pi_dma_handler,
pi_dma_handler_getter get_pi_dma_handler,
struct cart* cart,
struct dd_controller* dd,
struct mi_controller* mi,
struct ri_controller* ri,
struct rdp_core* dp)
{
pi->dev = dev;
pi->get_pi_dma_handler = get_pi_dma_handler;
pi->cart = cart;
pi->dd = dd;
pi->mi = mi;
pi->ri = ri;
pi->dp = dp;
@ -142,6 +146,14 @@ void write_pi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask
switch (reg)
{
case PI_CART_ADDR_REG:
if (pi->dd != NULL) {
masked_write(&pi->regs[PI_CART_ADDR_REG], value, mask);
dd_on_pi_cart_addr_write(pi->dd, pi->regs[PI_CART_ADDR_REG]);
return;
}
break;
case PI_RD_LEN_REG:
masked_write(&pi->regs[PI_RD_LEN_REG], value, mask);
dma_pi_read(pi);
@ -178,5 +190,13 @@ void pi_end_of_dma_event(void* opaque)
{
struct pi_controller* pi = (struct pi_controller*)opaque;
pi->regs[PI_STATUS_REG] &= ~PI_STATUS_DMA_BUSY;
if (pi->dd != NULL) {
if ((pi->regs[PI_CART_ADDR_REG] == MM_DD_C2S_BUFFER) ||
(pi->regs[PI_CART_ADDR_REG] == MM_DD_DS_BUFFER)) {
dd_update_bm(pi->dd);
}
}
raise_rcp_interrupt(pi->mi, MI_INTR_PI);
}

View file

@ -27,7 +27,8 @@
#include "osal/preproc.h"
struct device;
struct cart;
struct dd_controller;
struct mi_controller;
struct ri_controller;
struct rdp_core;
@ -56,15 +57,16 @@ struct pi_dma_handler
unsigned int (*dma_write)(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
};
typedef void (*pi_dma_handler_getter)(struct device* dev, uint32_t address, void** opaque, const struct pi_dma_handler** handler);
typedef void (*pi_dma_handler_getter)(struct cart* cart, struct dd_controller* dd, uint32_t address, void** opaque, const struct pi_dma_handler** handler);
struct pi_controller
{
uint32_t regs[PI_REGS_COUNT];
struct device* dev;
pi_dma_handler_getter get_pi_dma_handler;
struct cart* cart;
struct dd_controller* dd;
struct mi_controller* mi;
struct ri_controller* ri;
struct rdp_core* dp;
@ -78,7 +80,9 @@ static osal_inline uint32_t pi_reg(uint32_t address)
void init_pi(struct pi_controller* pi,
struct device* dev, pi_dma_handler_getter get_pi_dma_handler,
pi_dma_handler_getter get_pi_dma_handler,
struct cart* cart,
struct dd_controller* dd,
struct mi_controller* mi,
struct ri_controller* ri,
struct rdp_core* dp);

View file

@ -961,6 +961,137 @@ static void open_eep_file(struct file_storage* fstorage)
}
}
static void load_dd_rom(uint8_t* rom, size_t* rom_size)
{
/* ask the core loader for DD disk filename */
char* dd_ipl_rom_filename = (g_media_loader.get_dd_rom == NULL)
? NULL
: g_media_loader.get_dd_rom(g_media_loader.cb_data);
if ((dd_ipl_rom_filename == NULL) || (strlen(dd_ipl_rom_filename) == 0)) {
goto no_dd;
}
struct file_storage dd_rom;
memset(&dd_rom, 0, sizeof(dd_rom));
if (open_rom_file_storage(&dd_rom, dd_ipl_rom_filename) != file_ok) {
DebugMessage(M64MSG_ERROR, "Failed to load DD IPL ROM: %s. Disabling 64DD", dd_ipl_rom_filename);
goto no_dd;
}
DebugMessage(M64MSG_INFO, "DD IPL ROM: %s", dd_ipl_rom_filename);
/* load and swap DD IPL ROM */
*rom_size = g_ifile_storage_ro.size(&dd_rom);
memcpy(rom, g_ifile_storage_ro.data(&dd_rom), *rom_size);
close_file_storage(&dd_rom);
/* fetch 1st word to identify IPL ROM format */
/* FIXME: use more robust ROM detection heuristic - do the same for regular ROMs */
uint32_t pi_bsd_dom1_config = 0
| ((uint32_t)rom[0] << 24)
| ((uint32_t)rom[1] << 16)
| ((uint32_t)rom[2] << 8)
| ((uint32_t)rom[3] << 0);
switch (pi_bsd_dom1_config)
{
case 0x80270740: /* Z64 - big endian */
to_big_endian_buffer(rom, 4, *rom_size/4);
break;
case 0x40072780: /* N64 - little endian */
to_little_endian_buffer(rom, 4, *rom_size/4);
break;
case 0x27804007: /* V64 - bi-endian */
swap_buffer(rom, 2, *rom_size/2);
break;
default: /* unknown */
DebugMessage(M64MSG_ERROR, "Invalid DD IPL ROM: Disabling 64DD.");
*rom_size = 0;
return;
}
return;
no_dd:
free(dd_ipl_rom_filename);
*rom_size = 0;
}
static void load_dd_disk(struct file_storage* dd_disk, const struct storage_backend_interface** dd_idisk)
{
const char* format_desc;
/* ask the core loader for DD disk filename */
char* dd_disk_filename = (g_media_loader.get_dd_disk == NULL)
? NULL
: g_media_loader.get_dd_disk(g_media_loader.cb_data);
/* handle the no disk case */
if (dd_disk_filename == NULL || strlen(dd_disk_filename) == 0) {
goto no_disk;
}
/* open file */
if (open_rom_file_storage(dd_disk, dd_disk_filename) != file_ok) {
DebugMessage(M64MSG_ERROR, "Failed to load DD Disk: %s.", dd_disk_filename);
goto no_disk;
}
/* FIXME: handle byte swapping */
switch (dd_disk->size)
{
case MAME_FORMAT_DUMP_SIZE:
/* already in a compatible format */
*dd_idisk = &g_ifile_storage;
format_desc = "MAME";
break;
case SDK_FORMAT_DUMP_SIZE: {
/* convert to mame format */
uint8_t* buffer = malloc(MAME_FORMAT_DUMP_SIZE);
if (buffer == NULL) {
DebugMessage(M64MSG_ERROR, "Failed to allocate memory for MAME disk dump");
close_file_storage(dd_disk);
goto no_disk;
}
dd_convert_to_mame(buffer, dd_disk->data);
free(dd_disk->data);
dd_disk->data = buffer;
dd_disk->size = MAME_FORMAT_DUMP_SIZE;
*dd_idisk = &g_ifile_storage_dd_sdk_dump;
format_desc = "SDK";
} break;
default:
DebugMessage(M64MSG_ERROR, "Invalid DD Disk size %u.", dd_disk->size);
close_file_storage(dd_disk);
goto no_disk;
}
DebugMessage(M64MSG_INFO, "DD Disk: %s - %zu - %s",
dd_disk->filename,
dd_disk->size,
format_desc);
uint32_t w = *(uint32_t*)dd_disk->data;
if (w == DD_REGION_JP || w == DD_REGION_US) {
DebugMessage(M64MSG_WARNING, "Loading a saved disk ");
}
return;
no_disk:
free(dd_disk_filename);
*dd_idisk = NULL;
}
struct gb_cart_data
{
@ -1113,6 +1244,8 @@ m64p_error main_run(void)
struct file_storage eep;
struct file_storage fla;
struct file_storage sra;
size_t dd_rom_size;
struct file_storage dd_disk;
int control_ids[GAME_CONTROLLERS_COUNT];
struct controller_input_compat cin_compats[GAME_CONTROLLERS_COUNT];
@ -1200,6 +1333,17 @@ m64p_error main_run(void)
open_fla_file(&fla);
open_sra_file(&sra);
/* Load 64DD IPL ROM and Disk */
const struct clock_backend_interface* dd_rtc_iclock = NULL;
const struct storage_backend_interface* dd_idisk = NULL;
memset(&dd_disk, 0, sizeof(dd_disk));
load_dd_rom((uint8_t*)mem_base_u32(g_mem_base, MM_DD_ROM), &dd_rom_size);
if (dd_rom_size > 0) {
dd_rtc_iclock = &g_iclock_ctime_plus_delta;
load_dd_disk(&dd_disk, &dd_idisk);
}
/* setup pif channel devices */
void* joybus_devices[PIF_CHANNELS_COUNT];
const struct joybus_device_interface* ijoybus_devices[PIF_CHANNELS_COUNT];
@ -1336,7 +1480,10 @@ m64p_error main_run(void)
&eep, &g_ifile_storage,
flashram_type,
&fla, &g_ifile_storage,
&sra, &g_ifile_storage);
&sra, &g_ifile_storage,
NULL, dd_rtc_iclock,
dd_rom_size,
&dd_disk, dd_idisk);
// Attach rom to plugins
if (!gfx.romOpen())
@ -1407,6 +1554,7 @@ m64p_error main_run(void)
close_file_storage(&fla);
close_file_storage(&eep);
close_file_storage(&mpk);
close_file_storage(&dd_disk);
if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
{
@ -1442,6 +1590,7 @@ on_gfx_open_failure:
close_file_storage(&fla);
close_file_storage(&eep);
close_file_storage(&mpk);
close_file_storage(&dd_disk);
return M64ERR_PLUGIN_FAIL;
}

View file

@ -60,8 +60,10 @@
enum { GB_CART_FINGERPRINT_SIZE = 0x1c };
enum { GB_CART_FINGERPRINT_OFFSET = 0x134 };
enum { DD_DISK_ID_OFFSET = 0x43670 };
static const char* savestate_magic = "M64+SAVE";
static const int savestate_latest_version = 0x00010300; /* 1.3 */
static const int savestate_latest_version = 0x00010400; /* 1.4 */
static const unsigned char pj64_magic[4] = { 0xC8, 0xA6, 0xD8, 0x23 };
static savestates_job job = savestates_job_nothing;
@ -739,6 +741,53 @@ static int savestates_load_m64p(struct device* dev, char *filepath)
dev->rdram.regs[i][RDRAM_ADDR_SELECT_REG] = GETDATA(curr, uint32_t);
dev->rdram.regs[i][RDRAM_DEVICE_MANUF_REG] = GETDATA(curr, uint32_t);
}
if (version >= 0x00010400) {
/* verify if DD data is present (and matches what's currently loaded) */
uint32_t disk_id = GETDATA(curr, uint32_t);
uint32_t* current_disk_id = ((dev->dd.rom_size > 0) && dev->dd.idisk != NULL)
? (uint32_t*)(dev->dd.idisk->data(dev->dd.disk) + DD_DISK_ID_OFFSET)
: NULL;
if (current_disk_id != NULL && *current_disk_id == disk_id) {
dev->dd.regs[DD_ASIC_DATA] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_MISC_REG] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_CMD_STATUS] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_CUR_TK] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_BM_STATUS_CTL] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_ERR_SECTOR] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_SEQ_STATUS_CTL] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_CUR_SECTOR] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_HARD_RESET] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_C1_S0] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_HOST_SECBYTE] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_C1_S2] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_SEC_BYTE] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_C1_S4] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_C1_S6] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_CUR_ADDR] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_ID_REG] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_TEST_REG] = GETDATA(curr, uint32_t);
dev->dd.regs[DD_ASIC_TEST_PIN_SEL] = GETDATA(curr, uint32_t);
/* C2S buffer is expected to be always zero */
memset(dev->dd.c2s_buf, 0, 0x400);
COPYARRAY(dev->dd.ds_buf, curr, uint8_t, 0x100);
COPYARRAY(dev->dd.ms_ram, curr, uint8_t, 0x40);
dev->dd.rtc.now = (time_t)GETDATA(curr, int64_t);
dev->dd.rtc.last_update_rtc = (time_t)GETDATA(curr, int64_t);
dev->dd.bm_write = (unsigned char)GETDATA(curr, uint32_t);
dev->dd.bm_reset_held = (unsigned char)GETDATA(curr, uint32_t);
dev->dd.bm_block = (unsigned char)GETDATA(curr, uint32_t);
dev->dd.bm_zone = GETDATA(curr, unsigned int);
dev->dd.bm_track_offset = GETDATA(curr, unsigned int);
}
else {
curr += (3+DD_ASIC_REGS_COUNT)*sizeof(uint32_t) + 0x100 + 0x40 + 2*sizeof(int64_t) + 2*sizeof(unsigned int);
}
}
}
else {
/* extra ai state */
@ -795,6 +844,11 @@ static int savestates_load_m64p(struct device* dev, char *filepath)
memcpy(dev->rdram.regs[i], dev->rdram.regs[0], RDRAM_REGS_COUNT*sizeof(dev->rdram.regs[0][0]));
dev->rdram.regs[i][RDRAM_DEVICE_ID_REG] = ri_address_to_id_field(i * 0x200000) << 2;
}
/* dd state */
if (dev->dd.rom_size > 0 && dev->dd.idisk != NULL) {
poweron_dd(&dev->dd);
}
}
/* Zilmar-Spec plugin expect a call with control_id = -1 when RAM processing is done */
@ -1146,6 +1200,11 @@ static int savestates_load_pj64(struct device* dev,
dev->rdram.regs[i][RDRAM_DEVICE_ID_REG] = ri_address_to_id_field(i * 0x200000) << 2;
}
/* dd state */
if (dev->dd.rom_size > 0 && dev->dd.idisk != NULL) {
poweron_dd(&dev->dd);
}
savestates_load_set_pc(&dev->r4300, *r4300_cp0_last_addr(&dev->r4300.cp0));
// assert(savestateData+savestateSize == curr)
@ -1699,6 +1758,49 @@ static int savestates_save_m64p(const struct device* dev, char *filepath)
PUTDATA(curr, uint32_t, dev->rdram.regs[i][RDRAM_DEVICE_MANUF_REG]);
}
uint32_t* disk_id = ((dev->dd.rom_size > 0) && dev->dd.idisk != NULL)
? (uint32_t*)(dev->dd.idisk->data(dev->dd.disk) + DD_DISK_ID_OFFSET)
: NULL;
if (disk_id == NULL) {
PUTDATA(curr, uint32_t, 0);
curr += (3+DD_ASIC_REGS_COUNT)*sizeof(uint32_t) + 0x100 + 0x40 + 2*sizeof(int64_t) + 2*sizeof(unsigned int);
}
else {
PUTDATA(curr, uint32_t, *disk_id);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_DATA]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_MISC_REG]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_CMD_STATUS]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_CUR_TK]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_BM_STATUS_CTL]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_ERR_SECTOR]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_SEQ_STATUS_CTL]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_CUR_SECTOR]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_HARD_RESET]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_C1_S0]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_HOST_SECBYTE]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_C1_S2]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_SEC_BYTE]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_C1_S4]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_C1_S6]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_CUR_ADDR]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_ID_REG]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_TEST_REG]);
PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_TEST_PIN_SEL]);
PUTARRAY(dev->dd.ds_buf, curr, uint8_t, 0x100);
PUTARRAY(dev->dd.ms_ram, curr, uint8_t, 0x40);
PUTDATA(curr, int64_t, (int64_t)dev->dd.rtc.now);
PUTDATA(curr, int64_t, (int64_t)dev->dd.rtc.last_update_rtc);
PUTDATA(curr, uint32_t, dev->dd.bm_write);
PUTDATA(curr, uint32_t, dev->dd.bm_reset_held);
PUTDATA(curr, uint32_t, dev->dd.bm_block);
PUTDATA(curr, unsigned int, dev->dd.bm_zone);
PUTDATA(curr, unsigned int, dev->dd.bm_track_offset);
}
init_work(&save->work, savestates_save_m64p_work);
queue_work(&save->work);

View file

@ -22,6 +22,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "api/callbacks.h"
#include "api/m64p_common.h"
@ -227,8 +228,25 @@ static m64p_error plugin_connect_gfx(m64p_dynlib_handle plugin_handle)
static m64p_error plugin_start_gfx(void)
{
uint8_t media = *((uint8_t*)mem_base_u32(g_mem_base, MM_CART_ROM) + (0x3b ^ S8));
/* Here we feed 64DD IPL ROM header to GFX plugin if 64DD is present.
* We use g_media_loader.get_dd_rom to detect 64DD presence
* instead of g_dev because the latter is not yet initialized at plugin_start time */
/* XXX: Not sure it is the best way to convey which game is being played to the GFX plugin
* as 64DD IPL is the same for all 64DD games... */
char* dd_ipl_rom_filename = (g_media_loader.get_dd_rom == NULL)
? NULL
: g_media_loader.get_dd_rom(g_media_loader.cb_data);
uint32_t rom_base = (dd_ipl_rom_filename != NULL && strlen(dd_ipl_rom_filename) != 0 && media != 'C')
? MM_DD_ROM
: MM_CART_ROM;
free(dd_ipl_rom_filename);
/* fill in the GFX_INFO data structure */
gfx_info.HEADER = (unsigned char *)mem_base_u32(g_mem_base, MM_CART_ROM);
gfx_info.HEADER = (unsigned char *)mem_base_u32(g_mem_base, rom_base);
gfx_info.RDRAM = (unsigned char *)mem_base_u32(g_mem_base, MM_RDRAM_DRAM);
gfx_info.DMEM = (unsigned char *)mem_base_u32(g_mem_base, MM_RSP_MEM);
gfx_info.IMEM = (unsigned char *)mem_base_u32(g_mem_base, MM_RSP_MEM + 0x1000);