mirror of
https://github.com/mupen64plus/mupen64plus-core.git
synced 2024-06-02 19:27:51 -04:00
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:
parent
678210c002
commit
740406ff15
|
@ -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
|
||||
|}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/* ----------------------------------------- */
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
||||
/* ----------------------------------------- */
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
925
src/device/dd/dd_controller.c
Normal file
925
src/device/dd/dd_controller.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
138
src/device/dd/dd_controller.h
Normal file
138
src/device/dd/dd_controller.h
Normal 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
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -30,7 +30,8 @@ enum cic_version
|
|||
CIC_X105,
|
||||
CIC_X106,
|
||||
CIC_5101,
|
||||
CIC_5167
|
||||
CIC_5167,
|
||||
CIC_8303
|
||||
};
|
||||
|
||||
struct cic
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
151
src/main/main.c
151
src/main/main.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue