Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/famicom-dumper-client.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com>2020-11-25 21:24:36 +0300
committerAlexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com>2020-11-25 21:24:36 +0300
commit2b86dd2f5be378a67b3ee574f66f03578fb0e24f (patch)
tree08dd322f5de98c074b631d1469725ab35d1a2ecd
parent7fc7c4426478c9025ec65f7526601df484d57ed3 (diff)
COOLBOY GPIO and direct combined now, refactoring
-rw-r--r--FamicomDumper/CoolboyWriter.cs101
-rw-r--r--FamicomDumper/CoolgirlWriter.cs45
-rw-r--r--FamicomDumper/FamicomDumper.csproj.user2
-rw-r--r--FamicomDumper/FlashHelper.cs90
-rw-r--r--FamicomDumper/Program.cs69
-rw-r--r--FamicomDumperConnection/FamicomDumperConnection.cs87
-rw-r--r--FamicomDumperConnection/FamicomDumperConnection.csproj6
m---------NesContainers0
8 files changed, 183 insertions, 217 deletions
diff --git a/FamicomDumper/CoolboyWriter.cs b/FamicomDumper/CoolboyWriter.cs
index 95db2bd..f35efa0 100644
--- a/FamicomDumper/CoolboyWriter.cs
+++ b/FamicomDumper/CoolboyWriter.cs
@@ -44,71 +44,6 @@ namespace com.clusterrr.Famicom
return version;
}
- public static void WriteWithGPIO(FamicomDumperConnection dumper, string fileName)
- {
- byte[] PRG;
- try
- {
- var nesFile = new NesFile(fileName);
- PRG = nesFile.PRG;
- }
- catch
- {
- var nesFile = new UnifFile(fileName);
- PRG = nesFile.Fields["PRG0"];
- }
- while (PRG.Length < 512 * 1024)
- {
- var PRGbig = new byte[PRG.Length * 2];
- Array.Copy(PRG, 0, PRGbig, 0, PRG.Length);
- Array.Copy(PRG, 0, PRGbig, PRG.Length, PRG.Length);
- PRG = PRGbig;
- }
-
- int prgBanks = PRG.Length / 0x2000;
-
- Console.Write("Reset... ");
- dumper.Reset();
- Console.WriteLine("OK");
- var version = DetectVersion(dumper);
- var CoolboyReg = (UInt16)(version == 2 ? 0x5000 : 0x6000);
- dumper.WriteCpu(0xA001, 0x00); // RAM protect
- var writeStartTime = DateTime.Now;
- var lastSectorTime = DateTime.Now;
- var timeTotal = new TimeSpan();
- for (int bank = 0; bank < prgBanks; bank += 2)
- {
- int outbank = bank / 16;
- byte r0 = (byte)((outbank & 0x07) | ((outbank & 0xc0) >> 2));
- byte r1 = (byte)(((outbank & 0x30) >> 2) | ((outbank << 1) & 0x10));
- byte r2 = 0;
- byte r3 = 0;
- dumper.WriteCpu(CoolboyReg, new byte[] { r0, r1, r2, r3 });
-
- int inbank = bank % 64;
- dumper.WriteCpu(0x8000, new byte[] { 6, (byte)(inbank) });
- dumper.WriteCpu(0x8000, new byte[] { 7, (byte)(inbank | 1) });
-
- var data = new byte[0x4000];
- int pos = bank * 0x2000;
- if (pos % (128 * 1024) == 0)
- {
- timeTotal = new TimeSpan((DateTime.Now - lastSectorTime).Ticks * (prgBanks - bank) / 16);
- timeTotal = timeTotal.Add(DateTime.Now - writeStartTime);
- lastSectorTime = DateTime.Now;
- Console.Write("Erasing sector... ");
- dumper.EraseCpuFlashSector(FamicomDumperConnection.MemoryAccessMethod.CoolboyGPIO);
- Console.WriteLine("OK");
- }
- Array.Copy(PRG, pos, data, 0, data.Length);
- var timePassed = DateTime.Now - writeStartTime;
- Console.Write("Writing {0}/{1} ({2}%, {3:D2}:{4:D2}:{5:D2}/{6:D2}:{7:D2}:{8:D2})... ", bank / 2 + 1, prgBanks / 2, (int)(100 * bank / prgBanks),
- timePassed.Hours, timePassed.Minutes, timePassed.Seconds, timeTotal.Hours, timeTotal.Minutes, timeTotal.Seconds);
- dumper.WriteCpuFlash(0x0000, data, FamicomDumperConnection.MemoryAccessMethod.CoolboyGPIO);
- Console.WriteLine("OK");
- }
- }
-
public static void GetInfo(FamicomDumperConnection dumper)
{
Console.Write("Reset... ");
@@ -144,7 +79,7 @@ namespace com.clusterrr.Famicom
try
{
var nesFile = new NesFile(fileName);
- PRG = nesFile.PRG;
+ PRG = nesFile.PRG.ToArray();
}
catch
{
@@ -167,12 +102,12 @@ namespace com.clusterrr.Famicom
throw new ArgumentOutOfRangeException("PRG.Length", "This ROM is too big for this cartridge");
try
{
- PPBErase(dumper, coolboyReg);
+ PPBClear(dumper, coolboyReg);
}
catch (Exception ex)
{
if (!silent) Program.PlayErrorSound();
- Console.WriteLine($"ERROR! {ex.Message}. Lets try anyway.");
+ Console.WriteLine($"ERROR! {ex.Message}. Lets continue anyway.");
}
var writeStartTime = DateTime.Now;
@@ -205,19 +140,19 @@ namespace com.clusterrr.Famicom
timeTotal = timeTotal.Add(DateTime.Now - writeStartTime);
lastSectorTime = DateTime.Now;
Console.Write($"Erasing sector #{bank / 8}... ");
- dumper.EraseCpuFlashSector(FamicomDumperConnection.MemoryAccessMethod.Direct);
+ dumper.EraseCpuFlashSector();
Console.WriteLine("OK");
}
Array.Copy(PRG, pos, data, 0, data.Length);
var timePassed = DateTime.Now - writeStartTime;
Console.Write("Writing {0}/{1} ({2}%, {3:D2}:{4:D2}:{5:D2}/{6:D2}:{7:D2}:{8:D2})... ", bank + 1, prgBanks, (int)(100 * bank / prgBanks),
timePassed.Hours, timePassed.Minutes, timePassed.Seconds, timeTotal.Hours, timeTotal.Minutes, timeTotal.Seconds);
- dumper.WriteCpuFlash(0x0000, data, FamicomDumperConnection.MemoryAccessMethod.Direct);
+ dumper.WriteCpuFlash(0x0000, data);
Console.WriteLine("OK");
if ((bank % 8 == 7) || (bank == prgBanks - 1)) // After last bank in sector
{
if (writePBBs)
- PPBSet(dumper, coolboyReg, (uint)bank / 8);
+ FlashHelper.PPBSet(dumper);
currentErrorCount = 0;
}
}
@@ -333,24 +268,7 @@ namespace com.clusterrr.Famicom
throw new IOException("Cartridge is not writed correctly");
}
- public static byte PPBRead(FamicomDumperConnection dumper, ushort coolboyReg, uint sector)
- {
- // Select sector
- int bank = (int)(sector * 8);
- byte r0 = (byte)(((bank >> 3) & 0x07) // 5, 4, 3 bits
- | (((bank >> 9) & 0x03) << 4) // 10, 9 bits
- | (1 << 6)); // resets 4th mask bit
- byte r1 = (byte)((((bank >> 7) & 0x03) << 2) // 8, 7
- | (((bank >> 6) & 1) << 4) // 6
- | (1 << 7)); // resets 5th mask bit
- byte r2 = 0;
- byte r3 = (byte)((1 << 4) // NROM mode
- | ((bank & 7) << 1)); // 2, 1, 0 bits
- dumper.WriteCpu(coolboyReg, new byte[] { r0, r1, r2, r3 });
-
- return FlashHelper.PPBRead(dumper);
- }
-
+ /*
public static void PPBSet(FamicomDumperConnection dumper, ushort coolboyReg, uint sector)
{
Console.Write($"Writing PPB for sector #{sector}... ");
@@ -369,8 +287,9 @@ namespace com.clusterrr.Famicom
FlashHelper.PPBSet(dumper);
}
+ */
- public static void PPBErase(FamicomDumperConnection dumper, ushort coolboyReg)
+ public static void PPBClear(FamicomDumperConnection dumper, ushort coolboyReg)
{
// Sector 0
int bank = 0;
@@ -385,7 +304,7 @@ namespace com.clusterrr.Famicom
| ((bank & 7) << 1)); // 2, 1, 0 bits
dumper.WriteCpu(coolboyReg, new byte[] { r0, r1, r2, r3 });
- FlashHelper.PPBErase(dumper);
+ FlashHelper.PPBClear(dumper);
}
}
}
diff --git a/FamicomDumper/CoolgirlWriter.cs b/FamicomDumper/CoolgirlWriter.cs
index 1111d8a..1d45e3d 100644
--- a/FamicomDumper/CoolgirlWriter.cs
+++ b/FamicomDumper/CoolgirlWriter.cs
@@ -36,7 +36,7 @@ namespace com.clusterrr.Famicom
try
{
var nesFile = new NesFile(fileName);
- PRG = nesFile.PRG;
+ PRG = nesFile.PRG.ToArray();
}
catch
{
@@ -61,12 +61,12 @@ namespace com.clusterrr.Famicom
throw new ArgumentOutOfRangeException("PRG.Length", "This ROM is too big for this cartridge");
try
{
- PPBErase(dumper);
+ PPBClear(dumper);
}
catch (Exception ex)
{
if (!silent) Program.PlayErrorSound();
- Console.WriteLine($"ERROR! {ex.Message}. Lets try anyway.");
+ Console.WriteLine($"ERROR! {ex.Message}. Lets continue anyway.");
}
var writeStartTime = DateTime.Now;
@@ -93,19 +93,19 @@ namespace com.clusterrr.Famicom
timeTotal = timeTotal.Add(DateTime.Now - writeStartTime);
lastSectorTime = DateTime.Now;
Console.Write($"Erasing sector #{bank / 4}... ");
- dumper.EraseCpuFlashSector(FamicomDumperConnection.MemoryAccessMethod.Direct);
+ dumper.EraseCpuFlashSector();
Console.WriteLine("OK");
}
Array.Copy(PRG, pos, data, 0, data.Length);
var timePassed = DateTime.Now - writeStartTime;
Console.Write("Writing {0}/{1} ({2}%, {3:D2}:{4:D2}:{5:D2}/{6:D2}:{7:D2}:{8:D2})... ", bank + 1, prgBanks, (int)(100 * bank / prgBanks),
timePassed.Hours, timePassed.Minutes, timePassed.Seconds, timeTotal.Hours, timeTotal.Minutes, timeTotal.Seconds);
- dumper.WriteCpuFlash(0x0000, data, FamicomDumperConnection.MemoryAccessMethod.Direct);
+ dumper.WriteCpuFlash(0x0000, data);
Console.WriteLine("OK");
if ((bank % 4 == 3) || (bank == prgBanks - 1)) // After last bank in sector
{
if (writePBBs)
- PPBSet(dumper, (uint)bank / 4);
+ FlashHelper.PPBSet(dumper);
currentErrorCount = 0;
}
}
@@ -217,23 +217,7 @@ namespace com.clusterrr.Famicom
throw new IOException("Cartridge is not writed correctly");
}
- public static byte PPBRead(FamicomDumperConnection dumper, uint sector)
- {
- dumper.WriteCpu(0x5007, 0x04); // enable PRG write
- dumper.WriteCpu(0x5002, 0xFE); // mask = 32K
- // Select sector
- byte r0 = (byte)((sector * 4) >> 7);
- byte r1 = (byte)((sector * 4) << 1);
- dumper.WriteCpu(0x5000, r0);
- dumper.WriteCpu(0x5001, r1);
- // PPB Command Set Entry
- dumper.WriteCpu(0x8AAA, 0xAA);
- dumper.WriteCpu(0x8555, 0x55);
- dumper.WriteCpu(0x8AAA, 0xC0);
-
- return FlashHelper.PPBRead(dumper);
- }
-
+ /*
public static void PPBSet(FamicomDumperConnection dumper, uint sector)
{
Console.Write($"Writing PPB for sector #{sector}... ");
@@ -257,8 +241,9 @@ namespace com.clusterrr.Famicom
FlashHelper.PPBSet(dumper);
}
+ */
- public static void PPBErase(FamicomDumperConnection dumper)
+ public static void PPBClear(FamicomDumperConnection dumper)
{
// enable PRG write
dumper.WriteCpu(0x5007, 0x04);
@@ -268,7 +253,7 @@ namespace com.clusterrr.Famicom
dumper.WriteCpu(0x5000, 0);
dumper.WriteCpu(0x5001, 0);
- FlashHelper.PPBErase(dumper);
+ FlashHelper.PPBClear(dumper);
}
public static void FindBads(FamicomDumperConnection dumper, bool silent)
@@ -280,7 +265,7 @@ namespace com.clusterrr.Famicom
dumper.WriteCpu(0x5002, 0xFE); // mask = 32K
try
{
- PPBErase(dumper);
+ PPBClear(dumper);
}
catch (Exception ex)
{
@@ -293,12 +278,12 @@ namespace com.clusterrr.Famicom
FlashHelper.LockBitsCheckPrint(dumper);
Console.Write("Erasing sector #0... ");
- dumper.EraseCpuFlashSector(FamicomDumperConnection.MemoryAccessMethod.Direct);
+ dumper.EraseCpuFlashSector();
Console.WriteLine("OK");
var data = new byte[0x8000];
new Random().NextBytes(data);
Console.Write("Writing sector #0 for test... ");
- dumper.WriteCpuFlash(0x0000, data, FamicomDumperConnection.MemoryAccessMethod.Direct);
+ dumper.WriteCpuFlash(0x0000, data);
Console.WriteLine("OK");
Console.Write("Reading sector #0 for test... ");
var datar = dumper.ReadCpu(0x8000, 0x8000);
@@ -329,7 +314,7 @@ namespace com.clusterrr.Famicom
timePassed.Hours, timePassed.Minutes, timePassed.Seconds, timeTotal.Hours, timeTotal.Minutes, timeTotal.Seconds);
try
{
- dumper.EraseCpuFlashSector(FamicomDumperConnection.MemoryAccessMethod.Direct);
+ dumper.EraseCpuFlashSector();
Console.WriteLine("OK");
}
catch
@@ -344,7 +329,7 @@ namespace com.clusterrr.Famicom
dumper.WriteCpu(0x5001, r1);
try
{
- dumper.EraseCpuFlashSector(FamicomDumperConnection.MemoryAccessMethod.Direct);
+ dumper.EraseCpuFlashSector();
Console.WriteLine("OK");
}
catch
diff --git a/FamicomDumper/FamicomDumper.csproj.user b/FamicomDumper/FamicomDumper.csproj.user
index a094520..8cc4dbc 100644
--- a/FamicomDumper/FamicomDumper.csproj.user
+++ b/FamicomDumper/FamicomDumper.csproj.user
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
- <StartArguments>write-coolgirl --file F:\coolgirl\multirom_games.sokolov_alexey.unf --check --sound</StartArguments>
+ <StartArguments>dump --mapper coolboy --port COM20 --file coolboy.unf --psize 32M --sound</StartArguments>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<StartArguments>info-coolgirl</StartArguments>
diff --git a/FamicomDumper/FlashHelper.cs b/FamicomDumper/FlashHelper.cs
index 6807040..bbadfa8 100644
--- a/FamicomDumper/FlashHelper.cs
+++ b/FamicomDumper/FlashHelper.cs
@@ -51,7 +51,7 @@ namespace com.clusterrr.Famicom
}
finally
{
- dumper.WriteCpu(0x8000, 0xF0); // Reset
+ dumper.WriteCpu(0x8000, 0xF0);
}
}
@@ -78,9 +78,7 @@ namespace com.clusterrr.Famicom
}
finally
{
- // Password Protection Set Exit
- dumper.WriteCpu(0x8000, 0x90);
- dumper.WriteCpu(0x8000, 0x00);
+ ResetFlash(dumper);
}
Console.WriteLine("OK");
@@ -100,9 +98,7 @@ namespace com.clusterrr.Famicom
}
finally
{
- // PPB Command Set Exit
- dumper.WriteCpu(0x8000, 0x90);
- dumper.WriteCpu(0x8000, 0x00);
+ ResetFlash(dumper);
}
Console.WriteLine("OK");
}
@@ -128,9 +124,7 @@ namespace com.clusterrr.Famicom
}
finally
{
- // Password Protection Set Exit
- dumper.WriteCpu(0x8000, 0x90);
- dumper.WriteCpu(0x8000, 0x00);
+ ResetFlash(dumper);
}
}
@@ -152,9 +146,7 @@ namespace com.clusterrr.Famicom
}
finally
{
- // PPB Lock Command Set Exit
- dumper.WriteCpu(0x8000, 0x90);
- dumper.WriteCpu(0x8000, 0x00);
+ ResetFlash(dumper);
}
}
@@ -172,9 +164,7 @@ namespace com.clusterrr.Famicom
}
finally
{
- // PPB Lock Command Set Exit
- dumper.WriteCpu(0x8000, 0x90);
- dumper.WriteCpu(0x8000, 0x00);
+ ResetFlash(dumper);
}
}
@@ -191,9 +181,7 @@ namespace com.clusterrr.Famicom
}
finally
{
- // PPB Command Set Exit
- dumper.WriteCpu(0x8000, 0x90);
- dumper.WriteCpu(0x8000, 0x00);
+ ResetFlash(dumper);
}
}
@@ -209,43 +197,24 @@ namespace com.clusterrr.Famicom
// Check
try
{
+ DateTime startTime = DateTime.Now;
while (true)
{
- var b0 = dumper.ReadCpu(0x8000, 1)[0];
- var b1 = dumper.ReadCpu(0x8000, 1)[0];
- var tg = b0 ^ b1;
- if ((tg & (1 << 6)) == 0) // DQ6 = not toggle
- {
+ byte b = dumper.ReadCpu(0x8000, 1)[0];
+ if (b == 0x00)
break;
- }
- else// DQ6 = toggle
- {
- if ((b0 & (1 << 5)) != 0) // DQ5 = 1
- {
- b0 = dumper.ReadCpu(0x8000, 1)[0];
- b1 = dumper.ReadCpu(0x8000, 1)[0];
- tg = b0 ^ b1;
- if ((tg & (1 << 6)) == 0) // DQ6 = not toggle
- break;
- else
- throw new IOException("PPB write failed (DQ5 is set)");
- }
- }
+ if ((DateTime.Now - startTime).TotalMilliseconds >= 1500)
+ throw new IOException("PPB write failed");
}
- var r = dumper.ReadCpu(0x8000, 1)[0];
- if ((r & 1) != 0) // DQ0 = 1
- throw new IOException("PPB write failed (DQ0 is not set)");
}
finally
{
- // PPB Command Set Exit
- dumper.WriteCpu(0x8000, 0x90);
- dumper.WriteCpu(0x8000, 0x00);
+ ResetFlash(dumper);
}
Console.WriteLine("OK");
}
- public static void PPBErase(FamicomDumperConnection dumper)
+ public static void PPBClear(FamicomDumperConnection dumper)
{
PPBLockBitCheckPrint(dumper);
Console.Write($"Erasing all PBBs... ");
@@ -259,38 +228,19 @@ namespace com.clusterrr.Famicom
// Check
try
{
+ DateTime startTime = DateTime.Now;
while (true)
{
- var b0 = dumper.ReadCpu(0x8000, 1)[0];
- var b1 = dumper.ReadCpu(0x8000, 1)[0];
- var tg = b0 ^ b1;
- if ((tg & (1 << 6)) == 0) // DQ6 = not toggle
- {
+ byte b = dumper.ReadCpu(0x8000, 1)[0];
+ if (b == 0x01)
break;
- }
- else// DQ6 = toggle
- {
- if ((b0 & (1 << 5)) != 0) // DQ5 = 1
- {
- b0 = dumper.ReadCpu(0x8000, 1)[0];
- b1 = dumper.ReadCpu(0x8000, 1)[0];
- tg = b0 ^ b1;
- if ((tg & (1 << 6)) == 0) // DQ6 = not toggle
- break;
- else
- throw new IOException("PPB erase failed (DQ5 is set)");
- }
- }
+ if ((DateTime.Now - startTime).TotalMilliseconds >= 1500)
+ throw new IOException("PPB clear failed");
}
- var r = dumper.ReadCpu(0x8000, 1)[0];
- if ((r & 1) != 1) // DQ0 = 0
- throw new IOException("PPB erase failed (DQ0 is not set)");
}
finally
{
- // PPB Command Set Exit
- dumper.WriteCpu(0x8000, 0x90);
- dumper.WriteCpu(0x8000, 0x00);
+ ResetFlash(dumper);
}
Console.WriteLine("OK");
}
diff --git a/FamicomDumper/Program.cs b/FamicomDumper/Program.cs
index cf49360..cfb2bf9 100644
--- a/FamicomDumper/Program.cs
+++ b/FamicomDumper/Program.cs
@@ -36,6 +36,7 @@ using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Security;
+using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
@@ -264,9 +265,6 @@ namespace com.clusterrr.Famicom
case "dump-tiles":
DumpTiles(dumper, filename ?? "output.png", mapper, ParseSize(csize));
break;
- case "write-coolboy-gpio":
- CoolboyWriter.WriteWithGPIO(dumper, filename ?? "game.nes");
- break;
case "write-coolboy":
case "write-coolboy-direct":
CoolboyWriter.Write(dumper, filename ?? "game.nes", badSectors, silent, needCheck, needCheckPause, writePBBs, ignoreBadSectors);
@@ -316,7 +314,7 @@ namespace com.clusterrr.Famicom
+ ex.StackTrace
#endif
);
- if (!silent)
+ if (!silent)
PlayErrorSound();
return 1;
}
@@ -368,8 +366,7 @@ namespace com.clusterrr.Famicom
Console.WriteLine(" {0,-25}{1}", "dump-tiles", "dump CHR data to PNG file");
Console.WriteLine(" {0,-25}{1}", "read-prg-ram", "read PRG RAM (battery backed save if exists)");
Console.WriteLine(" {0,-25}{1}", "write-prg-ram", "write PRG RAM");
- Console.WriteLine(" {0,-25}{1}", "write-coolboy-gpio", "write COOLBOY cartridge using GPIO");
- Console.WriteLine(" {0,-25}{1}", "write-coolboy-direct", "write COOLBOY cartridge directly");
+ Console.WriteLine(" {0,-25}{1}", "write-coolboy", "write COOLBOY cartridge directly");
Console.WriteLine(" {0,-25}{1}", "write-coolgirl", "write COOLGIRL cartridge");
Console.WriteLine(" {0,-25}{1}", "write-eeprom", "write EEPROM-based cartridge");
Console.WriteLine(" {0,-25}{1}", "test-prg-ram", "run PRG RAM test");
@@ -525,7 +522,7 @@ namespace com.clusterrr.Famicom
{
instanceMethod.Invoke(obj, new object[] { dumper });
}
- catch (TargetInvocationException ex)
+ catch (TargetInvocationException ex)
{
if (ex.InnerException != null)
throw ex.InnerException;
@@ -578,6 +575,49 @@ namespace com.clusterrr.Famicom
static void Dump(FamicomDumperConnection dumper, string fileName, string mapperName, int prgSize, int chrSize, string unifName, string unifAuthor)
{
+ /*
+ dumper.Timeout = 30000;
+ var driveStatus = dumper.ReadCpu(0x4032, 1)[0];
+ if ((driveStatus & 1) != 0)
+ {
+ Console.Write("Please set disk card... ");
+ while ((driveStatus & 1) != 0)
+ {
+ Thread.Sleep(500);
+ driveStatus = dumper.ReadCpu(0x4032, 1)[0];
+ }
+ Console.WriteLine("OK!");
+ }
+ var blocks = new List<IFdsBlock>();
+ for (var i = 0; i < 16; i++)
+ {
+ while (true)
+ {
+ try
+ {
+ var fdsData = dumper.ReadFdsBlocks((byte)i, 1);
+ if (fdsData.Length != 1)
+ throw new InvalidDataException($"Only {fdsData.Length} received");
+ if (!fdsData[0].CrcOk)
+ throw new Exception($"Invalid CRC on block #{i}");
+ blocks.AddRange(fdsData);
+ Console.WriteLine($"Block #{i} - OK!");
+ break;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error {ex.GetType()}: {ex.Message}");
+ Thread.Sleep(5000);
+ }
+ }
+ }
+ var fds = blocks.Select(d => d.ToBytes()).SelectMany(d => d).ToArray();
+ fds = Enumerable.Concat(fds, new byte[65500 - fds.Length]).ToArray();
+ File.WriteAllBytes(@"E:\dump.fds", fds);
+ Console.WriteLine("Done!");
+ return;
+ */
+
var mapper = GetMapper(mapperName);
if (mapper.Number >= 0)
Console.WriteLine($"Using mapper: #{mapper.Number} ({mapper.Name})");
@@ -590,13 +630,13 @@ namespace com.clusterrr.Famicom
chrSize = chrSize >= 0 ? chrSize : mapper.DefaultChrSize;
if (prgSize > 0)
{
- Console.WriteLine("PRG memory size: {0}K", prgSize / 1024);
+ Console.WriteLine("PRG memory size: {0}KB", prgSize / 1024);
mapper.DumpPrg(dumper, prg, prgSize);
while (prg.Count % 0x4000 != 0) prg.Add(0);
}
if (chrSize > 0)
{
- Console.WriteLine("CHR memory size: {0}K", chrSize / 1024);
+ Console.WriteLine("CHR memory size: {0}KB", chrSize / 1024);
mapper.DumpChr(dumper, chr, chrSize);
while (chr.Count % 0x2000 != 0) chr.Add(0);
}
@@ -610,7 +650,8 @@ namespace com.clusterrr.Famicom
}
else if (mirroringRaw.Length == 4)
{
- switch (string.Format("{0}{1}{2}{3}", mirroringRaw[0] ? 1 : 0, mirroringRaw[1] ? 1 : 0, mirroringRaw[2] ? 1 : 0, mirroringRaw[3] ? 1 : 0))
+ var mirrstr = $"{(mirroringRaw[0] ? 1 : 0)}{(mirroringRaw[1] ? 1 : 0)}{(mirroringRaw[2] ? 1 : 0)}{(mirroringRaw[3] ? 1 : 0)}";
+ switch (mirrstr)
{
case "0011":
mirroring = NesFile.MirroringType.Horizontal; // Horizontal
@@ -803,16 +844,16 @@ namespace com.clusterrr.Famicom
int s = 0;
while (s < prg.Length)
{
- var n = Math.Min(nesFile.PRG.Length, prg.Length - s);
- Array.Copy(nesFile.PRG, s % nesFile.PRG.Length, prg, s, n);
+ var n = Math.Min(nesFile.PRG.Count(), prg.Length - s);
+ Array.Copy(nesFile.PRG.ToArray(), s % nesFile.PRG.Count(), prg, s, n);
s += n;
}
var chr = new byte[0x2000];
s = 0;
while (s < chr.Length)
{
- var n = Math.Min(nesFile.CHR.Length, chr.Length - s);
- Array.Copy(nesFile.CHR, s % nesFile.CHR.Length, chr, s, n);
+ var n = Math.Min(nesFile.CHR.Count(), chr.Length - s);
+ Array.Copy(nesFile.CHR.ToArray(), s % nesFile.CHR.Count(), chr, s, n);
s += n;
}
diff --git a/FamicomDumperConnection/FamicomDumperConnection.cs b/FamicomDumperConnection/FamicomDumperConnection.cs
index 4d9dbe6..9896ab4 100644
--- a/FamicomDumperConnection/FamicomDumperConnection.cs
+++ b/FamicomDumperConnection/FamicomDumperConnection.cs
@@ -7,6 +7,7 @@ using System.IO.Ports;
using System.Linq;
using System.Threading;
using System.Management;
+using com.clusterrr.Famicom.Containers;
namespace com.clusterrr.Famicom.DumperConnection
{
@@ -87,6 +88,9 @@ namespace com.clusterrr.Famicom.DumperConnection
FLASH_WRITE_TIMEOUT = 42,
FLASH_ERASE_ERROR = 43,
FLASH_ERASE_TIMEOUT = 44,
+ FDS_READ_REQUEST = 45,
+ FDS_READ_RESULT_BLOCK = 46,
+ FDS_READ_RESULT_END = 47,
BOOTLOADER = 0xFE,
DEBUG = 0xFF
@@ -295,7 +299,7 @@ namespace com.clusterrr.Famicom.DumperConnection
}
else if (d2xxPort != null)
{
- UInt32 numBytesAvailable = 0;
+ uint numBytesAvailable = 0;
FTDI.FT_STATUS ftStatus;
int t = 0;
do
@@ -567,9 +571,9 @@ namespace com.clusterrr.Famicom.DumperConnection
var wdata = new byte[Math.Min(maxWritePacketSize, wlength)];
Array.Copy(data, pos, wdata, 0, wdata.Length);
WriteCpuBlock(address, wdata);
- address += maxWritePacketSize;
- pos += maxWritePacketSize;
- wlength -= maxWritePacketSize;
+ address += (ushort)wdata.Length;
+ pos += wdata.Length;
+ wlength -= wdata.Length;
}
if (Verbose)
Console.WriteLine(" OK");
@@ -635,9 +639,9 @@ namespace com.clusterrr.Famicom.DumperConnection
Array.Copy(data, pos, wdata, 0, wdata.Length);
if (data.Select(b => b != 0xFF).Any()) // if there is any not FF byte
WriteCpuFlashBlock(address, wdata, flashType);
- address += maxWritePacketSize;
- pos += maxWritePacketSize;
- wlength -= maxWritePacketSize;
+ address += (ushort)wdata.Length;
+ pos += wdata.Length;
+ wlength -= wdata.Length;
}
if (Verbose)
Console.WriteLine(" OK");
@@ -692,7 +696,7 @@ namespace com.clusterrr.Famicom.DumperConnection
return result.ToArray();
}
- public byte[] ReadPpuBlock(ushort address, int length)
+ private byte[] ReadPpuBlock(ushort address, int length)
{
var buffer = new byte[4];
buffer[0] = (byte)(address & 0xFF);
@@ -750,9 +754,9 @@ namespace com.clusterrr.Famicom.DumperConnection
var wdata = new byte[Math.Min(maxWritePacketSize, wlength)];
Array.Copy(data, pos, wdata, 0, wdata.Length);
WritePpu(address, wdata);
- address += maxWritePacketSize;
- pos += maxWritePacketSize;
- wlength -= maxWritePacketSize;
+ address += (ushort)wdata.Length;
+ pos += wdata.Length;
+ wlength -= wdata.Length;
}
if (Verbose)
Console.WriteLine(" OK");
@@ -772,6 +776,67 @@ namespace com.clusterrr.Famicom.DumperConnection
throw new IOException($"Invalid data received: {recv.Command}");
}
+ public IFdsBlock[] ReadFdsBlocks(byte startBlock, byte blockCount = 0)
+ {
+ if (ProtocolVersion < 3)
+ throw new NotSupportedException("Dumper firmware version is too old, update it to read/write FDS cards");
+
+ if (Verbose)
+ Console.Write($"Reading FDS block(s) {startBlock}-{startBlock + blockCount - 1}... ");
+
+ var blocks = new List<IFdsBlock>();
+ var buffer = new byte[2];
+ buffer[0] = startBlock;
+ buffer[1] = blockCount;
+ SendCommand(DumperCommand.FDS_READ_REQUEST, buffer);
+ bool receiving = true;
+ bool parseError = false;
+ int currentBlock = startBlock;
+ while (receiving && !parseError)
+ {
+ var recv = RecvCommand();
+ switch (recv.Command)
+ {
+ case DumperCommand.FDS_READ_RESULT_BLOCK:
+ {
+ // ignore any data after invalid data
+ if (parseError)
+ break;
+ var data = recv.Data.Take(recv.Data.Length - 2).ToArray();
+ IFdsBlock newBlock;
+ try
+ {
+ if (currentBlock == 0)
+ newBlock = FdsDiskInfoBlock.FromBytes(data);
+ else if (currentBlock == 1)
+ newBlock = FdsFileAmountBlock.FromBytes(data);
+ else if ((currentBlock % 2) == 0)
+ newBlock = FdsFileHeaderBlock.FromBytes(data);
+ else
+ newBlock = FdsFileDataBlock.FromBytes(data);
+ newBlock.CrcOk = recv.Data[recv.Data.Length - 2] != 0;
+ newBlock.EndOfHeadMeet = recv.Data[recv.Data.Length - 1] != 0;
+ blocks.Add(newBlock);
+ }
+ catch (InvalidDataException)
+ {
+ parseError = true;
+ }
+ currentBlock++;
+ }
+ break;
+ case DumperCommand.FDS_READ_RESULT_END:
+ receiving = false;
+ break;
+ default:
+ throw new IOException($"Invalid data received: {recv.Command}");
+ }
+ }
+ if (Verbose)
+ Console.WriteLine(" OK");
+ return blocks.ToArray();
+ }
+
public bool[] GetMirroring()
{
if (Verbose)
diff --git a/FamicomDumperConnection/FamicomDumperConnection.csproj b/FamicomDumperConnection/FamicomDumperConnection.csproj
index b87fc8b..767d3ed 100644
--- a/FamicomDumperConnection/FamicomDumperConnection.csproj
+++ b/FamicomDumperConnection/FamicomDumperConnection.csproj
@@ -52,5 +52,11 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\NesContainers\NesContainers.csproj">
+ <Project>{dbde5f39-ff67-496f-999f-65f86dcec1d5}</Project>
+ <Name>NesContainers</Name>
+ </ProjectReference>
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project> \ No newline at end of file
diff --git a/NesContainers b/NesContainers
-Subproject fcae9cde2ff4abd0251372303744c4ba9f34542
+Subproject 448bda7a1feac448d04eaac8ca2997d482eae24