Skip to content

Commit

Permalink
n64: add 64dd disk swapping + safety checks + change manufacture time…
Browse files Browse the repository at this point in the history
…stamp (#1280)

This adds:
- 64DD Disk Swapping for both 64DD standalone games and N64 Combo games
(only if a disk is loaded).
- Safety checks to prevent corruptions.
- Change manufacture timestamp and line to differenciate different disk
files from each other to avoid confusion
  • Loading branch information
LuigiBlood authored Nov 8, 2023
1 parent 0ceaf17 commit 87ae65a
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 5 deletions.
6 changes: 5 additions & 1 deletion ares/n64/dd/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,11 @@ auto DD::command(n16 command) -> void {
auto DD::mechaResponse() -> void {
if(state.seek) {
state.seek = 0;
motorActive();
if (io.status.diskPresent) {
motorActive();
} else {
motorStop();
}
}
io.status.busyState = 0;
raise(IRQ::MECHA);
Expand Down
35 changes: 33 additions & 2 deletions ares/n64/dd/dd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ auto DD::load(Node::Object parent) -> void {
iplrom.load(fp);
}

rtcLoad();

debugger.load(parent->append<Node::Object>("Nintendo 64DD"));
}

Expand Down Expand Up @@ -79,17 +81,45 @@ auto DD::connect() -> void {
if(auto fp = pak->read("program.disk")) {
disk.allocate(fp->size());
disk.load(fp);
io.status.diskChanged = 1;
io.status.diskPresent = 1;
}

rtcLoad();
}

auto DD::disconnect() -> void {
if(!port) return;

save();
pak.reset();
disk.reset();
information = {};

if(iplrom) {
string id;
id.append((char)iplrom.read<Byte>(0x3b));
id.append((char)iplrom.read<Byte>(0x3c));
id.append((char)iplrom.read<Byte>(0x3d));
id.append((char)iplrom.read<Byte>(0x3e));
if(id.match("NDDJ")) dd.information.cic = "CIC-NUS-8303";
if(id.match("NDDE")) dd.information.cic = "CIC-NUS-DDUS";
if(id.match("NDXJ")) dd.information.cic = "CIC-NUS-8401";
}

io.status.diskChanged = 0;
io.status.diskPresent = 0;

//Deal with cases when the disk is removed while in use
if(io.status.busyState) {
//MECHA
io.status.mechaError = 1;
}

if(io.bm.start) {
//BM
io.bm.start = 0;
io.bm.error = 1;
}
motorStop();
}

auto DD::save() -> void {
Expand All @@ -112,6 +142,7 @@ auto DD::power(bool reset) -> void {
state = {};

io.status.resetState = 1;
if(disk) io.status.diskPresent = 1;
io.id = 3;
if(dd.information.cic.match("CIC-NUS-8401")) io.id = 4;

Expand Down
1 change: 1 addition & 0 deletions ares/n64/dd/dd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ struct DD : Memory::PI<DD> {
n1 writeProtect;
n1 mechaError;
n1 diskChanged;
n1 diskPresent;
} status;

n16 currentTrack;
Expand Down
4 changes: 2 additions & 2 deletions ares/n64/dd/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ auto DD::readHalf(u32 address) -> u16 {
data.bit(4) = io.status.spindleMotorStopped;
data.bit(6) = io.status.resetState;
data.bit(7) = io.status.busyState;
data.bit(8) = (bool)disk; //disk present
data.bit(8) = io.status.diskPresent;
data.bit(9) = irq.mecha.line;
data.bit(10) = irq.bm.line;
data.bit(11) = io.bm.error;
Expand Down Expand Up @@ -57,7 +57,7 @@ auto DD::readHalf(u32 address) -> u16 {
data.bit(0,7) = io.error.sector;
data.bit(8) = io.error.selfStop;
data.bit(9) = io.error.clockUnlock;
data.bit(10) = ~(bool)disk; //no disk
data.bit(10) = ~io.status.diskPresent; //no disk
data.bit(11) = io.error.offTrack;
data.bit(12) = io.error.overrun;
data.bit(13) = io.error.spindle;
Expand Down
26 changes: 26 additions & 0 deletions desktop-ui/emulator/nintendo-64.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
struct Nintendo64 : Emulator {
Nintendo64();
auto load() -> bool override;
auto load(Menu) -> void override;
auto save() -> bool override;
auto pak(ares::Node::Object) -> shared_pointer<vfs::directory> override;

shared_pointer<mia::Pak> gamepad;
shared_pointer<mia::Pak> disk;
shared_pointer<mia::Pak> gb;
u32 regionID = 0;
Timer diskInsertTimer;
};

Nintendo64::Nintendo64() {
Expand Down Expand Up @@ -162,6 +164,30 @@ auto Nintendo64::load() -> bool {
return true;
}

auto Nintendo64::load(Menu menu) -> void {
if(disk) {
MenuItem changeDisk{&menu};
changeDisk.setIcon(Icon::Device::Optical);
changeDisk.setText("Change Disk").onActivate([&] {
save();
auto drive = root->find<ares::Node::Port>("Nintendo 64DD/Disk Drive");
drive->disconnect();

if(!disk->load(Emulator::load(disk, configuration.game))) {
return;
}

//give the emulator core a few seconds to notice an empty drive state before reconnecting
diskInsertTimer.onActivate([&] {
diskInsertTimer.setEnabled(false);
auto drive = root->find<ares::Node::Port>("Nintendo 64DD/Disk Drive");
drive->allocate();
drive->connect();
}).setInterval(3000).setEnabled();
});
}
}

auto Nintendo64::save() -> bool {
root->save();
system->save(system->location);
Expand Down
24 changes: 24 additions & 0 deletions desktop-ui/emulator/nintendo-64dd.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
struct Nintendo64DD : Emulator {
Nintendo64DD();
auto load() -> bool override;
auto load(Menu) -> void override;
auto save() -> bool override;
auto pak(ares::Node::Object) -> shared_pointer<vfs::directory> override;

shared_pointer<mia::Pak> gamepad;
u32 regionID = 0;
Timer diskInsertTimer;
};

Nintendo64DD::Nintendo64DD() {
Expand Down Expand Up @@ -109,6 +111,28 @@ auto Nintendo64DD::load() -> bool {
return true;
}

auto Nintendo64DD::load(Menu menu) -> void {
MenuItem changeDisk{&menu};
changeDisk.setIcon(Icon::Device::Optical);
changeDisk.setText("Change Disk").onActivate([&] {
save();
auto drive = root->find<ares::Node::Port>("Nintendo 64DD/Disk Drive");
drive->disconnect();

if(!game->load(Emulator::load(game, configuration.game))) {
return;
}

//give the emulator core a few seconds to notice an empty drive state before reconnecting
diskInsertTimer.onActivate([&] {
diskInsertTimer.setEnabled(false);
auto drive = root->find<ares::Node::Port>("Nintendo 64DD/Disk Drive");
drive->allocate();
drive->connect();
}).setInterval(3000).setEnabled();
});
}

auto Nintendo64DD::save() -> bool {
root->save();
system->save(system->location);
Expand Down
37 changes: 37 additions & 0 deletions mia/medium/nintendo-64dd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,5 +516,42 @@ auto Nintendo64DD::transform(array_view<u8> input, vector<u8> errorTable) -> vec
}
}

//add new timestamp to differenciate every disk file for swapping
{
//get current time
chrono::timeinfo timeinfo = chrono::local::timeinfo();

u8 rng = random();
u8 second = BCD::encode(min(59, timeinfo.second));
u8 minute = BCD::encode(timeinfo.minute);
u8 hour = BCD::encode(timeinfo.hour);
u8 day = BCD::encode(timeinfo.day);
u8 month = BCD::encode(1 + timeinfo.month);
u8 yearlo = BCD::encode(timeinfo.year % 100);
u8 yearhi = BCD::encode(timeinfo.year / 100);

u32 diskIdBlocks[2] = {14, 15};
for(u32 n : range(2)) {
u32 offsetCalc = diskIdBlocks[n] * blockSizeTable[0];
//change disk id to all sectors
for(u32 m : range(85)) {
//change manufacture line info (0x08 to 0x0F) (is normally a BCD number but officially "PTN64" was also used there)
output[offsetCalc + (m * (blockSizeTable[0] / 85)) + 0x0B] = rng;
output[offsetCalc + (m * (blockSizeTable[0] / 85)) + 0x0C] = 0x41; //'A'
output[offsetCalc + (m * (blockSizeTable[0] / 85)) + 0x0D] = 0x52; //'R'
output[offsetCalc + (m * (blockSizeTable[0] / 85)) + 0x0E] = 0x45; //'E'
output[offsetCalc + (m * (blockSizeTable[0] / 85)) + 0x0F] = 0x53; //'S'
//change disk manufacture time (0x10 to 0x17) to now
output[offsetCalc + (m * (blockSizeTable[0] / 85)) + 0x11] = yearhi;
output[offsetCalc + (m * (blockSizeTable[0] / 85)) + 0x12] = yearlo;
output[offsetCalc + (m * (blockSizeTable[0] / 85)) + 0x13] = month;
output[offsetCalc + (m * (blockSizeTable[0] / 85)) + 0x14] = day;
output[offsetCalc + (m * (blockSizeTable[0] / 85)) + 0x15] = hour;
output[offsetCalc + (m * (blockSizeTable[0] / 85)) + 0x16] = minute;
output[offsetCalc + (m * (blockSizeTable[0] / 85)) + 0x17] = second;
}
}
}

return output;
}

0 comments on commit 87ae65a

Please sign in to comment.