Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified Assets/dll/ares64_interpreter.wbx.zst
Binary file not shown.
Binary file modified Assets/dll/ares64_recompiler.wbx.zst
Binary file not shown.
42 changes: 34 additions & 8 deletions src/BizHawk.Emulation.Cores/Consoles/Nintendo/Ares64/Ares64.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using BizHawk.Common;
using BizHawk.Emulation.Common;
Expand Down Expand Up @@ -64,18 +65,40 @@ static bool IsGBRom(byte[] rom)
return ninLogoSha1 == SHA1Checksum.ComputeDigestHex(new ReadOnlySpan<byte>(rom).Slice(0x104, 48));
}

List<byte[]> gbRoms = [ ];
byte[] rom = null;
byte[] disk = null;
byte[] error = null;
byte[] sdCard = null;

// TODO: this is normally handled frontend side
// except XML files don't go through RomGame
// (probably should, but needs refactoring)
foreach (var r in lp.Roms) _ = N64RomByteswapper.ToZ64Native(r.RomData); // no-op if N64 magic bytes not present
foreach (var r in lp.Roms)
{
_ = N64RomByteswapper.ToZ64Native(r.RomData); // no-op if N64 magic bytes not present

var gbRoms = lp.Roms.FindAll(r => IsGBRom(r.FileData)).Select(r => r.FileData).ToArray();
var rom = lp.Roms.Find(r => !gbRoms.Contains(r.FileData) && (char)r.RomData[0x3B] is 'N' or 'C')?.RomData;
var (disk, error) = TransformDisk(lp.Roms.Find(r => !gbRoms.Contains(r.FileData) && r.RomData != rom)?.FileData);
if (r.FileData.Length is 0x435B0C0 or 0x3DEC800)
{
(disk, error) = TransformDisk(r.FileData);
}
else if (IsGBRom(r.FileData))
{
gbRoms.Add(r.FileData);
}
else if ((char) r.RomData[0x3B] is 'N' or 'C')
{
rom = r.RomData;
}
else if(BinaryPrimitives.ReadUInt16LittleEndian(r.FileData.AsSpan(0x1FE, 2)) == 0xAA55)
{
sdCard = r.FileData;
}
}

if (rom is null && disk is null)
{
if (gbRoms.Length == 0 && lp.Roms.Count == 1) // let's just assume it's an N64 ROM then
if (gbRoms.Count == 0 && lp.Roms.Count == 1) // let's just assume it's an N64 ROM then
{
rom = lp.Roms[0].RomData;
}
Expand Down Expand Up @@ -116,7 +139,7 @@ static bool IsGBRom(byte[] rom)
}

byte[] GetGBRomOrNull(int n)
=> n < gbRoms.Length ? gbRoms[n] : null;
=> n < gbRoms.Count ? gbRoms[n] : null;

unsafe
{
Expand All @@ -129,7 +152,8 @@ byte[] GetGBRomOrNull(int n)
gb1RomPtr = GetGBRomOrNull(0),
gb2RomPtr = GetGBRomOrNull(1),
gb3RomPtr = GetGBRomOrNull(2),
gb4RomPtr = GetGBRomOrNull(3))
gb4RomPtr = GetGBRomOrNull(3),
sdPtr = sdCard)
{
var loadData = new LibAres64.LoadData
{
Expand All @@ -151,6 +175,8 @@ byte[] GetGBRomOrNull(int n)
Gb3RomLen = GetGBRomOrNull(2)?.Length ?? 0,
Gb4RomData = (IntPtr)gb4RomPtr,
Gb4RomLen = GetGBRomOrNull(3)?.Length ?? 0,
SdData = (IntPtr)sdPtr,
SdLen = sdCard?.Length ?? 0,
};
if (!_core.Init(ref loadData, ControllerSettings, pal, GetRtcTime(!DeterministicEmulation)))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ public struct LoadData
public long Gb3RomLen;
public IntPtr Gb4RomData;
public long Gb4RomLen;
public IntPtr SdData;
public long SdLen;
}

[BizImport(CC)]
Expand Down
13 changes: 13 additions & 0 deletions waterbox/ares64/BizInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ static array_view<u8>* diskErrorData = nullptr;
static array_view<u8>* saveData = nullptr;
static array_view<u8>* rtcData = nullptr;
static array_view<u8>* gbRomData[4] = { nullptr, nullptr, nullptr, nullptr, };
static array_view<u8>* sdData = nullptr;

typedef enum
{
Expand Down Expand Up @@ -417,6 +418,8 @@ typedef struct
u8* DiskErrorData;
u64 DiskErrorLen;
GbRom GbRoms[4];
u8* SdData;
u64 SdLen;
} LoadData;

static bool LoadRom(LoadData* loadData, bool isPal)
Expand Down Expand Up @@ -560,6 +563,16 @@ ECL_EXPORT bool Init(LoadData* loadData, ControllerType* controllers, bool isPal
platform->bizpak->append(name, *iplData);
}

if (loadData->SdData)
{
name = "sd.raw";
len = loadData->SdLen;
data = new u8[len];
memcpy(data, loadData->SdData, len);
sdData = new array_view<u8>(data, len);
platform->bizpak->append(name, *sdData);
}

string region = isPal ? "PAL" : "NTSC";
platform->bizpak->setAttribute("region", region);

Expand Down
19 changes: 19 additions & 0 deletions waterbox/ares64/ares/ares/n64/cartridge/cartridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Cartridge& cartridge = cartridgeSlot.cartridge;
#include "flash.cpp"
#include "rtc.cpp"
#include "joybus.cpp"
#include "sc64.cpp"
#include "isviewer.cpp"
#include "debugger.cpp"
#include "serialization.cpp"
Expand Down Expand Up @@ -54,6 +55,14 @@ auto Cartridge::connect() -> void {
isviewer.tracer->setTerminal(true);
}

if(auto fp = pak->read("sd.raw")) {
sc64.sd.allocate(fp->size());
sc64.sd.load(fp);
sc64.buffer.allocate(0x2000);
sc64.buffer.fill();
sc64.enabled = true;
}

debugger.load(node);

power(false);
Expand All @@ -69,6 +78,10 @@ auto Cartridge::disconnect() -> void {
flash.reset();
isviewer.ram.reset();
pak.reset();
if(sc64.enabled) {
sc64.sd.reset();
sc64.buffer.reset();
}
node.reset();
}

Expand All @@ -88,6 +101,12 @@ auto Cartridge::save() -> void {
}

rtc.save();

if(sc64.enabled) {
if(auto fp = system.pak->write("sd.raw")) {
sc64.sd.save(fp);
}
}
}

auto Cartridge::power(bool reset) -> void {
Expand Down
35 changes: 35 additions & 0 deletions waterbox/ares64/ares/ares/n64/cartridge/cartridge.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,41 @@ struct Cartridge {
Memory::Readable16 rom;
Memory::Writable16 ram;
Memory::Writable16 eeprom;
struct SC64 {
static constexpr u32 SDSectorWords = 512/4;

n1 enabled = false;
Memory::Writable sd;
Memory::Writable buffer;

n2 lockState = 0;
n1 busy = 0;
n1 error = 0;
u32 data0 = 0;
u32 data1 = 0;

n1 sdIsInit = 0;
u32 sdAddr = 0;

auto regReadWord(u32 address) -> u64;
auto regWriteWord(u32 address, u64 data_) -> void;

auto serialize(serializer& s) -> void;

template<u32 Size>
auto regRead(u32 address) -> u64 {
if constexpr(Size == Word) return regReadWord(address);
debug(unimplemented, "[SC64] Register read of size other than Word");
return 0; //Other sizes unimplemented
}

template<u32 Size>
auto regWrite(u32 address, u64 data) -> void {
if constexpr(Size == Word) return regWriteWord(address, data);
debug(unimplemented, "[SC64] Register write of size other than Word");
return; //Other sizes unimplemented
}
} sc64;
struct Flash : Memory::Writable {
template<u32 Size>
auto read(u32 address) -> u64 {
Expand Down
143 changes: 143 additions & 0 deletions waterbox/ares64/ares/ares/n64/cartridge/sc64.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
auto Cartridge::SC64::regReadWord(u32 address) -> u64 {
n32 data;
data.bit(0,31) = (address << 16) | (address & 0xFFFF);
address = (address & 0x1F) >> 2;

if (lockState != 2) {
return u64(data);
}

if(address == 0) {
//SCR, command execution and status
//Mostly unimplemented
data.bit(31) = busy;
data.bit(30) = error;
}

if(address == 1) {
//DATA0, command arg/result 0
data.bit(0,31) = data0;
}

if(address == 2) {
//DATA1, command arg/result 1
data.bit(0,31) = data1;
}

if(address == 3) {
//IDENTIFIER, flashcart identifier
//Read-only
data.bit(0,31) = 0x53'43'76'32; /* SCv2 */
}

if(address == 4) {
//KEY
//Write-only
}

if(address == 5) {
//IRQ
//Unimplemented
}

if(address == 6) {
//AUX
//Unimplemented
}

return u64(data);
}

auto Cartridge::SC64::regWriteWord(u32 address, u64 data_) -> void {
address = (address & 0x1F) >> 2;
n32 data = data_;

if(address == 0 && lockState == 2) {
//SCR, command execution and status
//Writes initiate a command
u8 cmd = data.bit(0,7);

switch (cmd) {
case 'i': //SD Operation
if(data1 == 1) //SD Init
sdIsInit = true;
break;

case 'I': //SD Sector Set
sdAddr = data0 * SC64::SDSectorWords * 4;
break;

case 's': //SD Read Sectors
if(sdIsInit) {
u32 piAddress = data0;
u32 numSectors = data1;
u32 numWords = numSectors * SC64::SDSectorWords;
//Note: Only data buffer is supported here but real SC64 is more flexible
for(auto offset : range(numWords))
buffer.write<Word>(piAddress + offset * 4, sd.read<Word>(sdAddr + offset * 4));
}
break;

case 'S': //SD Write Sectors
if(sdIsInit) {
u32 piAddress = data0;
u32 numSectors = data1;
u32 numWords = numSectors * SC64::SDSectorWords;
//Note: Only data buffer is supported here but real SC64 is more flexible
for(auto offset : range(numWords))
sd.write<Word>(sdAddr + offset * 4, buffer.read<Word>(piAddress + offset * 4));
}
break;

default: break; //Unrecongized/Unimplemented
}
}

if(address == 1 && lockState == 2) {
//DATA0, command arg/result 0
data0 = data.bit(0,31);
}

if(address == 2 && lockState == 2) {
//DATA1, command arg/result 1
data1 = data.bit(0,31);
}

if(address == 3 && lockState == 2) {
//IDENTIFIER, flashcart identifier
//Read-only
}

if(address == 4) {
//KEY
if(data.bit(0,31) == 0x00000000 || data.bit(0,31) == 0xFFFFFFFF)
lockState = 0;
else if(data.bit(0,31) == 0x5F554E4C && lockState == 0)
lockState = 1;
else if(data.bit(0,31) == 0x4F434B5F && lockState == 1)
lockState = 2;
}

if(address == 5 && lockState == 2) {
//IRQ
//Unimplemented
}

if(address == 6 && lockState == 2) {
//AUX
//Unimplemented
}
}

auto Cartridge::SC64::serialize(serializer& s) -> void {
s(enabled);
s(sd);
s(buffer);
s(lockState);
s(busy);
s(error);
s(data0);
s(data1);
s(sdIsInit);
s(sdAddr);
}
1 change: 1 addition & 0 deletions waterbox/ares64/ares/ares/n64/cartridge/serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ auto Cartridge::serialize(serializer& s) -> void {
s(eeprom);
s(flash);
s(rtc);
s(sc64);
}
Loading