public static int GetFlashSizePrintInfo(FamicomDumperConnection dumper) { dumper.WriteCpu(0x8AAA, 0x98); // CFI mode var cfi = dumper.ReadCpu(0x8000, 0x200); dumper.WriteCpu(0x8000, 0xF0); // Reset if (cfi[0x20] != 0x51 || cfi[0x22] != 0x52 || cfi[0x24] != 0x59) { throw new Exception("Can't enter CFI mode. Invalid flash memory? Broken cartridge? Is it inserted?"); } int size = 1 << cfi[0x27 * 2]; FlashDeviceInterface flashDeviceInterface = (FlashDeviceInterface)(cfi[0x28 * 2] | (cfi[0x29 * 2] << 8)); Console.WriteLine("Primary Algorithm Command Set and Control Interface ID Code: {0:X2}{1:X2}h", cfi[0x13 * 2], cfi[0x14 * 2]); Console.WriteLine("Vcc Logic Supply Minimum Program / Erase voltage: {0}v", (cfi[0x1B * 2] >> 4) + 0.1 * (cfi[0x1B * 2] & 0x0F)); Console.WriteLine("Vcc Logic Supply Maximum Program / Erase voltage: {0}v", (cfi[0x1C * 2] >> 4) + 0.1 * (cfi[0x1C * 2] & 0x0F)); Console.WriteLine("Vpp [Programming] Supply Minimum Program / Erase voltage: {0}v", (cfi[0x1D * 2] >> 4) + 0.1 * (cfi[0x1D * 2] & 0x0F)); Console.WriteLine("Vpp [Programming] Supply Maximum Program / Erase voltage: {0}v", (cfi[0x1E * 2] >> 4) + 0.1 * (cfi[0x1E * 2] & 0x0F)); Console.WriteLine("Maximum number of bytes in multi-byte program: {0}", 1 << (cfi[0x2A * 2] | (cfi[0x2B * 2] << 8))); Console.WriteLine("Device size: {0} MByte / {1} Mbit", size / 1024 / 1024, size / 1024 / 1024 * 8); Console.WriteLine("Flash device interface: {0}", flashDeviceInterface.ToString().Replace("_", " ")); return(size); }
public CFIInfo(byte[] data, ParseMode parseMode) { switch (parseMode) { case ParseMode.Every2Bytes: { var newData = new byte[data.Length / 2]; for (int i = 0; i < newData.Length; i++) { newData[i] = data[i * 2]; } data = newData; break; } case ParseMode.Every4Bytes: { var newData = new byte[data.Length / 4]; for (int i = 0; i < newData.Length; i++) { newData[i] = data[i * 4]; } data = newData; break; } } if (data[0x10] != 0x51 || data[0x11] != 0x52 || data[0x12] != 0x59) { throw new IOException("Can't enter CFI mode. Invalid flash memory? Broken cartridge? Is it inserted?"); } PrimaryAlgorithmCommandSet = (ushort)(data[0x13] + data[0x14] * 0x100); //var p = (ushort)(data[0x15] + data[0x16] * 0x100); AlternativeAlgorithmCommandSet = (ushort)(data[0x17] + data[0x18] * 0x100); //var a = (ushort)(data[0x19] + data[0x20] * 0x100); VccLogicSupplyMinimumProgramErase = (float)((data[0x1B] >> 4) + 0.1 * (data[0x1B] & 0x0F)); VccLogicSupplyMaximumProgramErase = (float)((data[0x1C] >> 4) + 0.1 * (data[0x1C] & 0x0F)); VppSupplyMinimumProgramErasevoltage = (float)((data[0x1D] >> 4) + 0.1 * (data[0x1D] & 0x0F)); VppSupplyMaximumProgramErasevoltage = (float)((data[0x1E] >> 4) + 0.1 * (data[0x1E] & 0x0F)); TypicalTimeoutPerSingleProgram = data[0x1F] == 0 ? 0 : (1U << data[0x1F]); TypicalTimeoutForMaximumSizeMultiByteProgram = data[0x20] == 0 ? 0 : (1U << data[0x20]); TypicalTimeoutPerIndividualBlockErase = data[0x21] == 0 ? 0 : (1U << data[0x21]); TypicalTimeoutForFullChipErase = data[0x22] == 0 ? 0 : (1U << data[0x22]); MaximumTimeoutPerSingleProgram = data[0x1F] == 0 ? 0 : ((1U << data[0x1F]) * (1U << data[0x23])); MaximumTimeoutForMaximumSizeMultiByteProgram = data[0x20] == 0 ? 0 : ((1U << data[0x20]) * (1U << data[0x24])); MaximumTimeoutPerIndividualBlockErase = data[0x21] == 0 ? 0 : ((1U << data[0x21]) * (1U << data[0x25])); MaximumTimeoutForFullChipErase = data[0x22] == 0 ? 0 : ((1U << data[0x22]) * (1U << data[0x26])); DeviceSize = 1U << data[0x27]; FlashDeviceInterfaceCodeDescription = (FlashDeviceInterface)(data[0x28] + data[0x29] * 0x100); MaximumNumberOfBytesInMultiProgram = (ushort)(1U << (data[0x2A] + data[0x2B] * 0x100)); var eraseBlockRegions = data[0x2C]; var regions = new List <EraseBlockRegionInfo>(); for (int i = 0; i < eraseBlockRegions; i++) { ushort numberOfBlocks = (ushort)(data[0x2D + i * 4] + data[0x2E + i * 4] * 0x100 + 1); uint sizeOfBlocks = (ushort)(data[0x2F + i * 4] + data[0x30 + i * 4] * 0x100); sizeOfBlocks = sizeOfBlocks == 0 ? 128 : (256 * sizeOfBlocks); regions.Add(new EraseBlockRegionInfo(numberOfBlocks, sizeOfBlocks)); } EraseBlockRegionsInfo = regions.AsReadOnly(); }