Skip to content
Browse files

first commit

  • Loading branch information...
0 parents commit 4a259ad871aefc8b6b530672a1eb2a69a8a077a1 @MatthewCallis committed Sep 20, 2009
Showing with 13,619 additions and 0 deletions.
  1. +76 −0 AppController.h
  2. +1,511 −0 AppController.m
  3. +15 −0 Console.h
  4. +38 −0 Console.m
  5. +1 −0 Driver Installer.pmdoc/01libftd-contents.xml
  6. +1 −0 Driver Installer.pmdoc/01libftd.xml
  7. +1 −0 Driver Installer.pmdoc/02libftd-contents.xml
  8. +1 −0 Driver Installer.pmdoc/02libftd.xml
  9. +1 −0 Driver Installer.pmdoc/03libftd-contents.xml
  10. +1 −0 Driver Installer.pmdoc/03libftd.xml
  11. +1 −0 Driver Installer.pmdoc/index.xml
  12. +475 −0 English.lproj/Console.xib
  13. BIN English.lproj/InfoPlist.strings
  14. +2,100 −0 English.lproj/MainMenu.xib
  15. +1 −0 FFArchive.framework/FFArchive
  16. +1 −0 FFArchive.framework/Headers
  17. +1 −0 FFArchive.framework/Resources
  18. BIN FFArchive.framework/Versions/A/FFArchive
  19. +39 −0 FFArchive.framework/Versions/A/Headers/FFArchive.h
  20. +28 −0 FFArchive.framework/Versions/A/Headers/FFArchive7Z.h
  21. +10 −0 FFArchive.framework/Versions/A/Headers/FFArchiveRAR.h
  22. +14 −0 FFArchive.framework/Versions/A/Headers/FFArchiveZIP.h
  23. BIN FFArchive.framework/Versions/A/Resources/English.lproj/Localizable.strings
  24. BIN FFArchive.framework/Versions/A/Resources/German.lproj/Localizable.strings
  25. +20 −0 FFArchive.framework/Versions/A/Resources/Info.plist
  26. BIN FFArchive.framework/Versions/A/Resources/Italian.lproj/Localizable.strings
  27. BIN FFArchive.framework/Versions/A/Resources/Spanish.lproj/Localizable.strings
  28. +1 −0 FFArchive.framework/Versions/Current
  29. BIN FTD2XX USB Driver Installer.pkg
  30. +24 −0 Info.plist
  31. +22 −0 NSData+RSHexDump.h
  32. +102 −0 NSData+RSHexDump.m
  33. +16 −0 NSString+Truncate.h
  34. +47 −0 NSString+Truncate.m
  35. +1,330 −0 SNES USB.xcodeproj/gapetto.mode1
  36. +1,397 −0 SNES USB.xcodeproj/gapetto.mode1v3
  37. +343 −0 SNES USB.xcodeproj/gapetto.pbxuser
  38. +394 −0 SNES USB.xcodeproj/liyanage.pbxuser
  39. +1,449 −0 SNES USB.xcodeproj/liyanage.perspective
  40. +1,366 −0 SNES USB.xcodeproj/michaelseeberger.mode1
  41. +201 −0 SNES USB.xcodeproj/michaelseeberger.pbxuser
  42. +488 −0 SNES USB.xcodeproj/project.pbxproj
  43. +87 −0 WinTypes.h
  44. +912 −0 ftd2xx.0.1.0h.h
  45. +6 −0 ftd2xx.cfg
  46. +927 −0 ftd2xx.h
  47. BIN germ.icns
  48. BIN libftd2xx.0.1.0.dylib
  49. BIN libftd2xx.0.1.4.dylib
  50. BIN libftd2xx.0.1.6.dylib
  51. BIN libftd2xx.0.1.6.ppc.dylib
  52. +13 −0 main.m
  53. +1 −0 þekking.framework/Headers
  54. +1 −0 þekking.framework/Resources
  55. +16 −0 þekking.framework/Versions/A/Headers/ParseRomDelegate.h
  56. +116 −0 þekking.framework/Versions/A/Headers/RomFile.h
  57. BIN þekking.framework/Versions/A/Resources/English.lproj/InfoPlist.strings
  58. +22 −0 þekking.framework/Versions/A/Resources/Info.plist
  59. BIN þekking.framework/Versions/A/þekking
  60. +1 −0 þekking.framework/Versions/Current
  61. +1 −0 þekking.framework/þekking
76 AppController.h
@@ -0,0 +1,76 @@
+/* AppController */
+
+#import <Cocoa/Cocoa.h>
+#import "Console.h"
+
+// List of supported chip IDs
+typedef struct {
+ const char* chipname;
+ unsigned char manufacturer;
+ unsigned char device;
+ bool bottomBoot; // boot block sectors start at addr 0
+} FlashChipCode;
+
+@interface AppController : NSObject {
+ IBOutlet NSButton *openFile;
+ IBOutlet NSWindow *window;
+ IBOutlet NSProgressIndicator *indicator;
+
+ NSArray *algorithmTags;
+ NSString *filename;
+
+ BOOL cartBanking; // TRUE = HiROM, FALSE = LoROM
+ int cartSize;
+ int saveSize;
+ int flashChip;
+
+ Console *console;
+}
+
+- (IBAction)detectRomType:(id)sender;
+- (IBAction)dumpCart:(id)sender;
+- (IBAction)dumpSave:(id)sender;
+- (IBAction)writeCart:(id)sender;
+- (IBAction)writeSave:(id)sender;
+- (IBAction)eraseCart:(id)sender;
+
+- (BOOL)dragIsFile:(id <NSDraggingInfo>)sender;
+- (NSString *)getFileForDrag:(id <NSDraggingInfo>)sender;
+
+// USB Functions
+- (void)powerOn;
+- (void)powerOff;
+- (BOOL)openPort;
+- (void)closePort;
+- (BOOL)readEEPROM;
+- (BOOL)writeEEPROM:(NSString *)fileName;
+- (BOOL)detectHIROM;
+- (BOOL)readBytes:(unsigned char *)data bytes:(int)bytes;
+- (BOOL)writeBytes:(unsigned char *)data bytes:(int)bytes;
+- (BOOL)flashDetect;
+
+- (BOOL) flashErase:(int)romsize;
+
+- (BOOL) flashEraseCommand:(int)addr chipErase:(BOOL)chiperase;
+
+- (BOOL)flashROM:(NSString *)fileName;
+
+- (int)readROM:(NSString *)fileName kbytes:(int)kbytes;
+
+- (BOOL)readSaveFile:(NSString *)fileName;
+
+- (BOOL)writeSaveFile:(NSString *)fileName;
+
+- (BOOL)clearSave;
+
+- (BOOL)sendJunk;
+
+- (void)disableEE;
+
+- (BOOL)sendEEBit:(int)bit read:(int)read;
+
+- (BOOL)readEE:(unsigned char *)data bytes:(int)bytes;
+
+- (BOOL)writeEE:(unsigned char *)data bytes:(int)bytes;
+
+@end
1,511 AppController.m
@@ -0,0 +1,1511 @@
+#import "AppController.h"
+#include "ftd2xx.h"
+#include "NSString+Truncate.h"
+
+#import <þekking/RomFile.h>
+#import <þekking/ParseRomDelegate.h>
+
+FT_HANDLE ftHandleA; // DATA BUS
+FT_STATUS ftStatus; // STATUS
+
+//Number of boot block and regular sectors
+#define FLASH_BOOT_8K 8
+#define FLASH_MIDDLE_64K 63
+
+@implementation AppController
+
+- (id)init{
+ if(self = [super init]){
+ cartBanking = FALSE;
+ }
+ filename = nil;
+ return self;
+}
+
+- (void)dealloc{
+ [algorithmTags release];
+ [super dealloc];
+}
+
+- (void)awakeFromNib{
+// NSLog(@"awakeFromNib");
+ NSArray *dragTypes = [NSArray arrayWithObjects:NSFilenamesPboardType, nil];
+ [window registerForDraggedTypes:dragTypes];
+ console = [[Console alloc] init];
+ [console show];
+}
+
+- (IBAction)detectRomType:(id)sender{
+ [console addText:@"Detecting ROM Type...\n"];
+ if(![self openPort]) return;
+ [self powerOn];
+ if([self flashDetect]){
+ [self readEEPROM];
+ }
+ else{
+ [self disableEE];
+ [self detectHIROM];
+ }
+ [self powerOff];
+ [self closePort];
+}
+
+- (IBAction)dumpCart:(id)sender{
+ NSSavePanel *outputDirectory = [NSSavePanel savePanel];
+ [outputDirectory setCanSelectHiddenExtension:TRUE];
+ [outputDirectory setCanCreateDirectories:TRUE];
+ if([outputDirectory runModalForDirectory:nil file:nil] == NSFileHandlingPanelOKButton){
+ [console addText:[NSString stringWithFormat:@"File will be saved as: %@\n", [[outputDirectory filename] lastPathComponent]]];
+ if(![self openPort]) return;
+ [self powerOn];
+ [self disableEE];
+ [self detectHIROM];
+ [self readROM:[outputDirectory filename] kbytes:cartSize];
+ [self powerOff];
+ [self closePort];
+ }
+ else{
+ return;
+ }
+}
+
+- (IBAction)dumpSave:(id)sender{
+ NSSavePanel *outputDirectory = [NSSavePanel savePanel];
+ [outputDirectory setCanSelectHiddenExtension:TRUE];
+ [outputDirectory setCanCreateDirectories:TRUE];
+ if([outputDirectory runModalForDirectory:nil file:nil] == NSFileHandlingPanelOKButton){
+ [console addText:[NSString stringWithFormat:@"File will be saved as: %@\n", [outputDirectory filename]]];
+ if(![self openPort]) return;
+ [self powerOn];
+ [self disableEE];
+ [self detectHIROM];
+ [self readSaveFile:[outputDirectory filename]];
+ [self powerOff];
+ [self closePort];
+ }
+ else{
+ return;
+ }
+}
+
+- (IBAction)writeCart:(id)sender{
+ NSOpenPanel *outputDirectory = [NSOpenPanel openPanel];
+ [outputDirectory setCanChooseFiles:TRUE];
+ [outputDirectory setAllowsMultipleSelection:FALSE];
+ [outputDirectory setCanCreateDirectories:TRUE];
+ if([outputDirectory runModalForDirectory:nil file:nil] == NSFileHandlingPanelOKButton){
+ [console addText:[NSString stringWithFormat:@"'%@' will be written to Flash Cart.\n", [[outputDirectory filename] lastPathComponent]]];
+ ParseRomDelegate *parseRom = [[ParseRomDelegate alloc] init];
+ NSMutableArray *parsedRomsArray = (NSMutableArray *)[parseRom listFiles:[outputDirectory filenames]];
+ [parseRom release];
+
+ NSEnumerator *filesEnumerator = [parsedRomsArray objectEnumerator];
+ RomFile *currentFile;
+ while(currentFile = [filesEnumerator nextObject]){
+ [console addText:[NSString stringWithFormat:@"Cart Type: %@\n", [currentFile cartType]]];
+ [console addText:[NSString stringWithFormat:@"Country %@\n", [currentFile country]]];
+ [console addText:[NSString stringWithFormat:@"Game Code: %@\n", [currentFile gameCode]]];
+ [console addText:[NSString stringWithFormat:@"Version: %@\n", [currentFile version]]];
+ [console addText:[NSString stringWithFormat:@"Header: %@\n", [currentFile headerCheck]]];
+ [console addText:[NSString stringWithFormat:@"Title: %@\n", [currentFile internalTitle]]];
+ [console addText:[NSString stringWithFormat:@"CRC32: %@\n", [currentFile fileCRC32]]];
+ [console addText:[NSString stringWithFormat:@"SHA1: %@\n", [currentFile fileSHA1]]];
+ [console addText:[NSString stringWithFormat:@"MD5: %@\n", [currentFile fileMD5]]];
+ [console addText:[NSString stringWithFormat:@"Save Size: %@\n", [currentFile saveSize]]];
+ [console addText:[NSString stringWithFormat:@"File Size: %@\n", [currentFile romSize]]];
+ [console addText:[NSString stringWithFormat:@"ROM Map: %@\n", [currentFile romMap]]];
+ if([[currentFile romMap] isEqualToString:[NSString stringWithString:@"HiROM"]]){
+ cartBanking = TRUE;
+ }
+ else{
+ cartBanking = FALSE;
+ }
+ }
+
+ NSFileManager *fm = [NSFileManager defaultManager];
+ NSDictionary *fattrs = [fm fileAttributesAtPath:[outputDirectory filename] traverseLink:NO];
+ cartSize = [[fattrs objectForKey:NSFileSize] intValue] / 1024;
+
+ [console addText:[NSString stringWithFormat:@"Cart Size: %d\n", cartSize]];
+
+ if(![self openPort]) return;
+ [self powerOn];
+ sleep(1);
+ [self writeEEPROM:[[outputDirectory filename] lastPathComponent]];
+ sleep(1);
+ [self disableEE];
+ sleep(2);
+ if([self flashDetect]){
+ sleep(2);
+ [self flashErase: cartSize];
+ sleep(2);
+ [self flashROM:[outputDirectory filename]];
+ sleep(1);
+ [self clearSave];
+ }
+ [self powerOff];
+ [self closePort];
+ }
+ else{
+ return;
+ }
+}
+
+- (IBAction)writeSave:(id)sender{
+ NSOpenPanel *outputDirectory = [NSOpenPanel openPanel];
+ [outputDirectory setCanChooseFiles:TRUE];
+ [outputDirectory setAllowsMultipleSelection:FALSE];
+ [outputDirectory setCanCreateDirectories:TRUE];
+ if([outputDirectory runModalForDirectory:nil file:nil] == NSFileHandlingPanelOKButton){
+ [console addText:[NSString stringWithFormat:@"'%@' will be written to Flash Cart.\n", [[outputDirectory filename] lastPathComponent]]];
+ if(![self openPort]) return;
+ [self powerOn];
+ [self disableEE];
+ [self detectHIROM];
+ [self writeSaveFile:[outputDirectory filename]];
+ [self powerOff];
+ [self closePort];
+ }
+ else{
+ return;
+ }
+}
+
+- (IBAction)eraseCart:(id)sender{
+ [console addText:@"Erase Cart...\n"];
+ if(![self openPort]) return;
+ [self powerOn];
+ cartBanking = FALSE;
+ sleep(1);
+ [self writeEEPROM:@""];
+ sleep(1);
+ [self disableEE];
+ sleep(1);
+ if([self flashDetect]){
+ [self flashErase: 4096];
+ sleep(1);
+ cartBanking = TRUE;
+ [self flashErase: 4096];
+ sleep(1);
+ [self clearSave];
+ sleep(1);
+ }
+ [self powerOff];
+ [self closePort];
+}
+
+#pragma mark -
+#pragma mark - Drag & Drop Functions
+
+- (unsigned int)draggingEntered:(id <NSDraggingInfo>)sender{
+ NSView *view = [window contentView];
+
+ if(![self dragIsFile:sender]){
+ return NSDragOperationNone;
+ }
+
+ [view lockFocus];
+
+ [[NSColor selectedControlColor] set];
+ [NSBezierPath setDefaultLineWidth:5];
+ [NSBezierPath strokeRect:[view bounds]];
+
+ [view unlockFocus];
+
+ [window flushWindow];
+
+ return NSDragOperationGeneric;
+}
+
+- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender{
+ filename = [self getFileForDrag:sender];
+
+ [[window contentView] setNeedsDisplay:YES];
+
+ return YES;
+}
+
+- (BOOL)dragIsFile:(id <NSDraggingInfo>)sender{
+ BOOL isDirectory;
+ NSString *dragFilename = [self getFileForDrag:sender];
+ [[NSFileManager defaultManager] fileExistsAtPath:dragFilename isDirectory:&isDirectory];
+ return !isDirectory;
+}
+
+- (NSString *)getFileForDrag:(id <NSDraggingInfo>)sender{
+ NSPasteboard *pb = [sender draggingPasteboard];
+ NSString *availableType = [pb availableTypeFromArray:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
+ NSString *dragFilename;
+ NSArray *props;
+
+ props = [pb propertyListForType:availableType];
+ dragFilename = [props objectAtIndex:0];
+
+ return dragFilename;
+}
+
+- (void)draggingExited:(id <NSDraggingInfo>)sender{
+ [[window contentView] setNeedsDisplay:YES];
+}
+
+#pragma mark -
+#pragma mark - USB Functions
+
+/* USB Interface */
+- (void) powerOn{
+ [console addText:@"Powering On...\n"];
+ unsigned char command[2];
+ command[0] = 'P'; //Power On
+ command[1] = 1;
+ [self writeBytes:command bytes:2];
+}
+
+- (void) powerOff{
+ [console addText:@"Powering Off...\n"];
+ unsigned char command[4];
+ command[0] = 'C'; // Set CS
+ command[1] = 0;
+ command[2] = 'P'; // Power Off
+ command[3] = 0;
+ [self writeBytes:command bytes:4];
+}
+
+- (BOOL) openPort{
+ [console addText:@"Opening Port...\n"];
+ ftStatus = FT_OpenEx("USB SNES FLASH", FT_OPEN_BY_DESCRIPTION, &ftHandleA); //open data bus
+ if(ftStatus == FT_OK){
+ // Success - Device Open
+ [console addText:@"Device Found!\n"];
+ }
+ else{
+ // Failure - one or both of the devices has not been opened
+ [console addText:@"USB Error: Opening of USB SNES FLASH Failed!\n"];
+ return FALSE;
+ }
+ return TRUE;
+}
+
+- (void) closePort{
+ [console addText:@"Port Closed!\n"];
+ FT_Close(ftHandleA);
+}
+
+/* Input / Output (IO) */
+- (BOOL) writeBytes:(unsigned char *)data bytes:(int)bytes{
+ DWORD bytesWritten = 0;
+
+ ftStatus = FT_Write(ftHandleA, data, bytes, &bytesWritten);
+// NSLog(@"Write Status: %i / %i", ftStatus, FT_OK);
+ if(ftStatus == FT_OK){
+// NSLog(@"Write Success! (%d bytes)", bytesWritten);
+ // FT_Read OK
+ return TRUE;
+ }
+ else{
+ // FT_Write Timeout
+ [console addText:[NSString stringWithFormat:@"FT STATUS = %i\n", ftStatus]];
+ return FALSE;
+ }
+}
+
+- (BOOL) readBytes:(unsigned char *)data bytes:(int)bytes{
+// NSLog(@"Reading %d bytes...", bytes);
+ DWORD bytesReceived = 0;
+ FT_SetTimeouts(ftHandleA, 10000, 0);
+ ftStatus = FT_Read(ftHandleA, data, bytes, &bytesReceived);
+ if(ftStatus == FT_OK){
+ if(bytesReceived != bytes){
+ [console addText:[NSString stringWithFormat:@"Timed out! Only %d bytes read!\n", bytesReceived]];
+ return FALSE;
+ }
+ // FT_Read OK
+// NSLog(@"Read Success (%d bytes)", bytes);
+ return TRUE;
+ }
+ else{
+ // FT_Read Failed
+ [console addText:[NSString stringWithFormat:@"USB Error: Read Failed!\n"]];
+ [console addText:[NSString stringWithFormat:@"FT STATUS = %i\n", ftStatus]];
+ return FALSE;
+ }
+}
+
+- (BOOL) detectHIROM{
+ unsigned char command[32];
+
+ unsigned char *buffer1 = (unsigned char*)malloc(1024);
+ unsigned char *buffer2 = (unsigned char*)malloc(1024);
+ unsigned char *buffer3 = (unsigned char*)malloc(1024);
+
+ // Read
+ command[0] = 'C'; // Set CS
+ command[1] = 1;
+ command[6] = 'R'; // Autoread 1
+ command[7] = 0x00; // 0x407C00 - A15=0 LoROM
+ command[8] = 0x7C;
+ command[9] = 0x40;
+ command[10] = 'R'; // Autoread 2
+ command[11] = 0x00; // 0x40FC00 - A15=1 HiROM
+ command[12] = 0xFC;
+ command[13] = 0x40;
+ command[14] = 'R'; // Autoread 3
+ command[15] = 0x00; // 0x400000 - A15=0
+ command[16] = 0x00;
+ command[17] = 0x40;
+ command[18] = 'C'; // Set CS
+ command[19] = 0;
+
+ // Send the command
+ [self writeBytes: command bytes: 20];
+
+ // Read back the data
+ [self readBytes:buffer1 bytes: 1024];
+ [self readBytes:buffer2 bytes: 1024];
+ [self readBytes:buffer3 bytes: 1024];
+
+ // Compare
+ cartBanking = FALSE;
+
+ // Check for 64k banks (uses A15 for bank 40, not mirror)
+ // Sometimes it does use A15 for LOROM and sets it to open bus
+ if(memcmp(buffer1, buffer2, 1024) != 0){
+ // Check for 64k banks again (real data when A15=0)
+ if(memcmp(buffer1, buffer3, 1024) != 0){
+ // Done!
+ cartBanking = TRUE;
+// NSLog(@"HiROM! (1)");
+// [textFieldBank setStringValue:@"HiROM"];
+ }
+ else{
+ cartBanking = FALSE;
+// NSLog(@"LoROM! (1)");
+// [textFieldBank setStringValue:@"LoROM"];
+ }
+ }
+
+ unsigned char sizeByte = buffer2[983];
+ unsigned char saveByte = buffer2[984];
+// NSData *bufferA = [NSData dataWithBytes:buffer1 length:1024];
+// NSLog(@"%@", [bufferA description]);
+// NSData *bufferB = [NSData dataWithBytes:buffer2 length:1024];
+// NSLog(@"%@", [bufferB description]);
+// NSData *bufferC = [NSData dataWithBytes:buffer3 length:1024];
+// NSLog(@"%@", [bufferC description]);
+// NSLog(@"Maker Code: %02x", buffer2[944]);
+// NSLog(@"Maker Code: %02x", buffer2[945]);
+// NSLog(@"ROM Speed: %02x", buffer2[981]);
+// NSLog(@"Cart Type: %02x", buffer2[982]);
+// NSLog(@"File Size: %02x", buffer2[983]);
+// NSLog(@"SRAM Size: %02x", buffer2[984]);
+
+ switch(sizeByte){
+ case 0x08: cartSize = 256; break; // 2MB
+ case 0x09: cartSize = 512; break; // 4MB
+ case 0x0A: cartSize = 1024; break; // 8MB
+ case 0x0B: cartSize = 2048; break; // 16MB
+ case 0x0C: cartSize = 4096; break; // 32MB
+ case 0x0D: cartSize = 6144; break; // 48MB
+ case 0x0E: cartSize = 8192; break; // 64MB
+ default: cartSize = 4096; break; // 32MB
+ }
+
+ switch(saveByte){
+ case 0x00: saveSize = 0; break;
+ case 0x01: saveSize = 2; break;
+ case 0x02: saveSize = 8; break;
+ case 0x03: saveSize = 8; break;
+ case 0x04: saveSize = 32; break; // ???
+ case 0x05: saveSize = 32; break; // Star Fox 2
+ case 0x06: saveSize = 32; break; // Marvelous (J)
+ case 0x07: saveSize = 32; break; // Kaite Tukutte Asoberu Dezaemon (J)
+ case 0x08: saveSize = 32; break; // Air Management - Oozora ni Kakeru (J) (V1.1) [!]
+ case 0x12: saveSize = 32; break; // Super Power League 2 (J) (V1.1) [!]
+ default: saveSize = 32; break;
+ }
+
+ [console addText:[NSString stringWithFormat:@"Cart Size: %d\n", cartSize]];
+ [console addText:[NSString stringWithFormat:@"Save Size: %d\n", saveSize]];
+
+ // Done
+ free(buffer3);
+ free(buffer2);
+ free(buffer1);
+
+ return cartBanking;
+}
+
+- (BOOL) writeEEPROM:(NSString *)fileName{
+ sleep(3);
+ [console addText:@"Writing EEPROM Setting...\n"];
+ unsigned char eedata[128];
+ int bytes;
+
+ // Set Config Bits
+ eedata[0] = 0;
+
+ if(cartBanking) eedata[0] |= 0x10; // AddrMode = 0x10
+ if(saveSize == 2) eedata[0] |= 0x20; // SaveRAMEnable = 0x20
+ else if(saveSize == 8) eedata[0] |= 0x60; // SaveRAMMask1 = 0x40
+ else if(saveSize == 32) eedata[0] |= 0xE0; // SaveRAMMask2 = 0x80
+
+ [console addText:[NSString stringWithFormat:@"EEPROM Save: 0x%02x\n", eedata[0]]];
+
+ if(![fileName isEqualToString:@""]){
+ int i;
+ for(i = 0; i < 128; i++){
+ if(i < ([[fileName lastPathComponent] length] - 4)){
+ eedata[i+1] = [[fileName lastPathComponent] characterAtIndex:i];
+// NSLog(@"eedata[%d+1] = %c", i, [[fileName lastPathComponent] characterAtIndex:i]);
+ }
+ else if(i == ([[fileName lastPathComponent] length] - 4)){
+ eedata[i+1] = 0;
+ }
+ else{
+ eedata[i+1] = -1;
+ }
+ }
+ bytes = 128;
+ }
+ else{
+ bytes = 1;
+ }
+
+ if([self writeEE:eedata bytes:bytes] == FALSE){
+ [console addText:@"ERROR: Could not write EEPROM!\n"];
+ return FALSE;
+ }
+
+ [console addText:[NSString stringWithFormat:@"Wrote %d byte EEPROM!\n", bytes]];
+ return TRUE;
+}
+
+- (BOOL) readEEPROM{
+ unsigned char *eedata = (unsigned char*)malloc(128);
+ [self readEE:eedata bytes:128];
+ int i = 0;
+ eedata[127] = 0;
+
+ NSData *bufferA = [NSData dataWithBytes:eedata length:128];
+ [console addText:[NSString stringWithFormat:@"%@\n", [bufferA description]]];
+
+ if((eedata[1] != 0x00) && (eedata[1] != 0xFF)){
+ //Decode SaveRAM size
+ if ((eedata[0] & 0xE0) == 0x20) i = 2;
+ else if ((eedata[0] & 0xE0) == 0x60) i = 8;
+ else if ((eedata[0] & 0xE0) == 0xE0) i = 32;
+ else i = 0;
+
+ // NSLog(@"Filename: %s", &eedata[1]);
+ // NSLog(@"Mode: %s", ((eedata[0] & 0x10) ? "HIROM" : "LOROM") );
+ // NSLog(@"SaveRAM: %d kB", i);
+
+ //Autodetect from EEPROM
+ cartBanking = (eedata[0] & 0x10) ? TRUE : FALSE;
+// saveramsize = i;
+
+// autodetect = FALSE;
+ }
+ else{
+ [console addText:@"No EEPROM Detected!\n"];
+ }
+ return FALSE;
+}
+
+- (BOOL) flashDetect{
+ sleep(5);
+ int i = 0;
+
+// cartBanking = TRUE;
+
+ unsigned char command[128];
+ unsigned char results[2];
+
+ FlashChipCode flashChipCodes[] = {
+ {"Atmel AT49BV322D", 0x1F, 0xC8, TRUE},
+ {"Atmel AT49BV322DT", 0x1F, 0xC9, FALSE},
+ {"Spansion S29JL032H-21", 0x01, 0x55, FALSE}, //Top
+ {"Spansion S29JL032H-31", 0x01, 0x50, FALSE},
+ {"Spansion S29JL032H-41", 0x01, 0x5C, FALSE},
+ {"Spansion S29JL032H-22", 0x01, 0x56, TRUE}, //Bottom
+ {"Spansion S29JL032H-32", 0x01, 0x53, TRUE},
+ {"Spansion S29JL032H-42", 0x01, 0x5F, TRUE},
+ {"Winbond W19B320AB", 0xDA, 0x7E, TRUE}
+ };
+
+ // Write Flash Commands
+ i = 0;
+ command[i++] = 'C';
+ command[i++] = 0;
+
+ command[i++] = 'C'; //Product ID mode
+ command[i++] = 1;
+ command[i++] = 'w';
+ command[i++] = 0xAA;
+ command[i++] = 0x8A;
+ command[i++] = 0x00;
+ command[i++] = 0xAA;
+ command[i++] = 'C';
+ command[i++] = 0;
+
+ command[i++] = 'C';
+ command[i++] = 1;
+ command[i++] = 'w';
+ command[i++] = 0x55;
+ command[i++] = 0x85;
+ command[i++] = 0x00;
+ command[i++] = 0x55;
+ command[i++] = 'C';
+ command[i++] = 0;
+
+ command[i++] = 'C';
+ command[i++] = 1;
+ command[i++] = 'w';
+ command[i++] = 0xAA;
+ command[i++] = 0x8A;
+ command[i++] = 0x00;
+ command[i++] = 0x90;
+ command[i++] = 'C';
+ command[i++] = 0;
+
+ command[i++] = 'C'; //Read Codes
+ command[i++] = 1;
+ command[i++] = 'r';
+ command[i++] = 0x00; //Manufacturer
+ command[i++] = 0x80;
+ command[i++] = 0x00;
+ command[i++] = 'C';
+ command[i++] = 0;
+
+ command[i++] = 'C';
+ command[i++] = 1;
+ command[i++] = 'r';
+ command[i++] = 0x02; //Device
+ command[i++] = 0x80;
+ command[i++] = 0x00;
+ command[i++] = 'C';
+ command[i++] = 0;
+
+ command[i++] = 'C'; //Exit Product ID
+ command[i++] = 1;
+ command[i++] = 'w';
+ command[i++] = 0x00;
+ command[i++] = 0x80;
+ command[i++] = 0x00;
+ command[i++] = 0xF0;
+ command[i++] = 'C';
+ command[i++] = 0;
+
+ [self writeBytes:command bytes:i];
+ [self readBytes:results bytes:2];
+
+ // Find chip using ID
+ flashChip = 999;
+
+ for(i = 0; i < 9; i++){
+// NSLog(@"Found: %02x %02x", results[0], results[1]);
+// NSLog(@"Maybe: %02x %02x", flashChipCodes[i].manufacturer, flashChipCodes[i].device);
+ if((results[0] == flashChipCodes[i].manufacturer) && (results[1] == flashChipCodes[i].device)){
+ flashChip = i;
+ break;
+ }
+ }
+
+ if(flashChip == 999){
+ [console addText:@"ERROR: No flash chip detected\n"];
+ return FALSE;
+ }
+
+ [console addText:[NSString stringWithFormat:@"Found %s\n", flashChipCodes[flashChip].chipname]];
+
+ // Set up writing protocol
+ command[0] = 'G';
+ command[1] = 0xAA; // flashcmd0addr0
+ command[2] = 0x8A; // flashcmd0addr1
+ command[3] = 0x00; // flashcmd0addr2
+ command[4] = 0xAA; // flashcmd0data
+
+ command[5] = 0x55; //flashcmd1
+ command[6] = 0x85;
+ command[7] = 0x00;
+ command[8] = 0x55;
+
+ command[9] = 0xAA; //flashcmd2
+ command[10] = 0x8A;
+ command[11] = 0x00;
+ command[12] = 0xA0;
+
+ [self writeBytes:command bytes:13];
+
+ return TRUE;
+}
+
+// Erases FLASH memory. May take up to a minute
+- (BOOL) flashErase:(int)romsize{
+ int i;
+ int addr;
+ int error = 0;
+// long starttime;
+
+ FlashChipCode flashChipCodes[] = {
+ {"Atmel AT49BV322D", 0x1F, 0xC8, TRUE},
+ {"Atmel AT49BV322DT", 0x1F, 0xC9, FALSE},
+ {"Spansion S29JL032H-21", 0x01, 0x55, FALSE}, //Top
+ {"Spansion S29JL032H-31", 0x01, 0x50, FALSE},
+ {"Spansion S29JL032H-41", 0x01, 0x5C, FALSE},
+ {"Spansion S29JL032H-22", 0x01, 0x56, TRUE}, //Bottom
+ {"Spansion S29JL032H-32", 0x01, 0x53, TRUE},
+ {"Spansion S29JL032H-42", 0x01, 0x5F, TRUE},
+ {"Winbond W19B320AB", 0xDA, 0x7E, TRUE}
+ };
+
+ [console addText:@"Flash Erase...\n"];
+// starttime = TickCount();
+
+ if(1 || (cartBanking) || (romsize > 3*1024*1024) || (romsize == 0)){
+ // Chip Erase
+ // MUST DO THIS FOR HIROM, because of the way A15 is decoded
+ if([self flashEraseCommand:0 chipErase: TRUE] == 0){
+ [console addText:@"ERROR: Error erasing flash!\n"];
+ return FALSE;
+ }
+ }
+ else{
+ // Sector Erase
+ addr = 0;
+ // 8k Bottom Sectors (64k in total)
+ [console addText:@"8k Bottom Sectors (64k in total)\n"];
+ if(flashChipCodes[flashChip].bottomBoot){
+ for(i = 0; i < FLASH_BOOT_8K; i++){
+ if([self flashEraseCommand:addr chipErase: FALSE] == 0){
+ error = 1;
+ break;
+ }
+ addr += 8*1024;
+ }
+ if(error){
+ [console addText:@"ERROR: Error erasing flash!\n"];
+ return 0;
+ }
+ }
+
+ // 64k Sectors
+ [console addText:@"64k Sectors\n"];
+ for(i = 0; i < FLASH_MIDDLE_64K; i++){
+ if([self flashEraseCommand:addr chipErase:FALSE] == 0){
+ error = 1;
+ break;
+ }
+ addr += 64*1024;
+ // Only check size for 64k sectors
+ // Always go one sector over, so size can be autodetected
+ if(addr > romsize){
+ break;
+ }
+ }
+ if(error){
+ [console addText:@"ERROR: Error erasing flash!\n"];
+ return 0;
+ }
+ // Will never have to erase the top 8k sectors. Just use chip erase!
+ }
+ // Done
+// NSLog(@"Done! %d Seconds", (TickCount() - starttime) / 1000);
+ return TRUE;
+}
+
+- (BOOL) flashEraseCommand:(int)addr chipErase:(BOOL)chiperase{
+// NSLog(@"Flash Erase Command...");
+ int i;
+ long starttime;
+ unsigned char cmd;
+ unsigned char command[64];
+
+ if(chiperase){
+ addr = 0x008AAA;
+ cmd = 0x10;
+ }
+ else{
+ // Sector Erase address decoding (LOROM only!)
+ addr = ((addr & 0xFFFF8000) << 1) | 0x008000 | (addr & 0x00007FFF);
+ cmd = 0x30;
+ }
+
+ //--- Write Flash Commands
+ i = 0;
+ command[i++] = 'C';
+ command[i++] = 0;
+
+ command[i++] = 'C'; //Chip Erase command. From the datasheet
+ command[i++] = 1;
+ command[i++] = 'w';
+ command[i++] = 0xAA;
+ command[i++] = 0x8A;
+ command[i++] = 0x00;
+ command[i++] = 0xAA;
+ command[i++] = 'C';
+ command[i++] = 0;
+
+ command[i++] = 'C';
+ command[i++] = 1;
+ command[i++] = 'w';
+ command[i++] = 0x55;
+ command[i++] = 0x85;
+ command[i++] = 0x00;
+ command[i++] = 0x55;
+ command[i++] = 'C';
+ command[i++] = 0;
+
+ command[i++] = 'C';
+ command[i++] = 1;
+ command[i++] = 'w';
+ command[i++] = 0xAA;
+ command[i++] = 0x8A;
+ command[i++] = 0x00;
+ command[i++] = 0x80;
+ command[i++] = 'C';
+ command[i++] = 0;
+
+ command[i++] = 'C';
+ command[i++] = 1;
+ command[i++] = 'w';
+ command[i++] = 0xAA;
+ command[i++] = 0x8A;
+ command[i++] = 0x00;
+ command[i++] = 0xAA;
+ command[i++] = 'C';
+ command[i++] = 0;
+
+ command[i++] = 'C';
+ command[i++] = 1;
+ command[i++] = 'w';
+ command[i++] = 0x55;
+ command[i++] = 0x85;
+ command[i++] = 0x00;
+ command[i++] = 0x55;
+ command[i++] = 'C';
+ command[i++] = 0;
+
+ command[i++] = 'C';
+ command[i++] = 1;
+ command[i++] = 'w';
+ command[i++] = addr & 0xFF;
+ command[i++] = (addr >> 8) & 0xFF;
+ command[i++] = (addr >> 16) & 0xFF;
+ command[i++] = cmd;
+ command[i++] = 'C';
+ command[i++] = 0;
+
+ [self writeBytes:command bytes:i];
+
+ // Data Polling
+ command[0] = 'C';
+ command[1] = 1;
+ command[2] = 'r';
+ command[3] = addr & 0xFF;
+ command[4] = (addr >> 8) & 0xFF;
+ command[5] = (addr >> 16) & 0xFF;
+ command[6] = 'C';
+ command[7] = 0;
+
+ starttime= TickCount();
+ int seconds = 0;
+
+ while(1){
+ sleep(5);
+ if((TickCount() - starttime) >= 1000){
+ seconds++;
+ starttime += 1000;
+// printf(".");
+ }
+
+ [self writeBytes:command bytes:8];
+ [self readBytes:&command[32] bytes:1];
+
+ // Check Result
+ if(command[32] == 0xFF){
+// NSLog(@"Checked Result: %02x", command[32]);
+// printf(".");
+ break;
+ }
+
+ // Check Timeout
+ if(chiperase){
+ if(seconds >= 120){
+ return 0;
+ }
+ }
+ else{
+ if(seconds >= 15){
+ return 0;
+ }
+ }
+ }
+// NSLog(@"Flash Erase Command sent!");
+ return TRUE;
+}
+
+// Programs Flash memory using contents of file. May take up to a minute
+// This function uses CROMReader to support different formats
+- (BOOL)flashROM:(NSString *)fileName{
+ int i;
+ int kbread;
+ BOOL error;
+
+ unsigned int addr = 0;
+ unsigned char *buffer = (unsigned char*)malloc(32*1024);
+ unsigned char command[32];
+
+ [console addText:@"Flashing ROM...\n"];
+
+ // Flash Data
+// long starttime = TickCount();
+ kbread = 0;
+ error = FALSE;
+
+ NSData *myROM = [NSData dataWithContentsOfFile:fileName];
+// NSData *myBuffer;
+// NSLog(@"%@", [myROM description]);
+ do{
+ if(cartBanking){
+// NSLog(@"HiROM");
+ addr = ((kbread * 1024) | 0x400000);
+ if(kbread == 0) addr = 0x400000;
+ }
+ else{
+ // Skip every other 32k
+// NSLog(@"LoROM");
+ addr = ((kbread * 2 * 1024) | 0x008000);
+// NSLog(@"0x%x = ((%i * 2 * 1024) | 0x008000)", addr, kbread);
+ }
+
+// NSLog(@"0x%x = (%i * 1024) | 0x400000", addr, kbread);
+// NSLog(@"...at 0x%x", addr);
+
+ // Flash Write
+ for(i = 0; i < 32; i++){
+ // Read Data
+ int location = ((kbread + i) * 1024);
+ if(kbread == 0 && i == 0) location = 0;
+// NSLog(@"%x = ((%d + 1) * 1024)", location, kbread);
+ [myROM getBytes:buffer range:NSMakeRange(location, 1024)];
+// myBuffer = [NSData dataWithBytes:buffer length:1024];
+// NSLog(@"%@", [myBuffer description]);
+
+ command[0] = 'F'; // Flash
+ command[1] = addr & 0xFF;
+ command[2] = (addr >> 8) & 0xFF;
+ command[3] = (addr >> 16) & 0xFF;
+
+ [self writeBytes:command bytes:4];
+ [self writeBytes:buffer bytes:1024];
+
+// [console addText:[NSString stringWithFormat:@"Wrote to 0x%x\n", addr]];
+ addr += 1024;
+ }
+
+ // Read result codes
+ [self readBytes:command bytes:32];
+ kbread += 32;
+ [console addText:[NSString stringWithFormat:@"Read %dKB... of %dKB\n", kbread, cartSize]];
+
+// myBuffer = [NSData dataWithBytes:command length:32];
+// NSLog(@"%@", [myBuffer description]);
+
+ // Check for errors. Should all be dots
+ for(i = 0; i < 32; i++){
+ if(command[i] != '.'){
+ // NSLog(@"Error: %c", command[i]);
+ error = TRUE;
+ }
+ }
+
+ if(error){
+ [console addText:@"Failed to FlashROM!\n"];
+ free(buffer);
+ return FALSE;
+ }
+ }while(kbread < cartSize);
+
+// NSLog("Done! %d Seconds", (TickCount() - starttime) / 1000);
+ free(buffer);
+ return TRUE;
+}
+
+// Reads contents of ROM cartridge into outfile. kbytes is the size to read, 0 to autodetect
+// Returns number of kB read, 0 for error
+- (int) readROM:(NSString *)fileName kbytes:(int)kbytes{
+ int i;
+ int kbread;
+ unsigned int addr;
+
+ unsigned char *buffer = (unsigned char*)malloc(32*1024);
+ unsigned char *firstdata = NULL;
+ unsigned char command[4];
+
+ [console addText:@"Reading ROM...\n"];
+
+ // Read ROM Data
+ command[0] = 'C'; //Set CS
+ command[1] = 1;
+
+ [self writeBytes: command bytes: 2];
+
+ kbread = 0;
+
+ NSMutableData *outData = [NSMutableData dataWithCapacity:1];
+
+ do{
+ // Read 32kb at a time
+ if(cartBanking) addr = (kbread * 1024) | 0x400000;
+ else addr = (kbread * 2 * 1024) | 0x008000; // Skip every other 32k
+
+ // Send Commands
+ for(i = 0; i < 32; i++){
+ command[0] = 'R'; // Autoread
+ command[1] = addr & 0xFF;
+ command[2] = (addr >> 8) & 0xFF;
+ command[3] = (addr >> 16) & 0xFF;
+
+ [self writeBytes: command bytes: 4];
+
+ addr += 1024;
+ }
+
+ // Read Data
+ [self readBytes:buffer bytes: (32 * 1024)];
+
+ kbread += 32;
+
+ // Autodetect Size - Check for mirror or empty data
+ if(kbytes == 0){
+ // Save first 32kbytes for later
+ if(firstdata == NULL){
+ firstdata = (unsigned char*)malloc(32*1024);
+ memcpy(firstdata, buffer, 32*1024);
+ }
+
+ // Check on size boundries
+ if( (kbread == (256+32)) || (kbread == (512+32)) || (kbread == (1024+32)) || (kbread == (1536+32)) || (kbread == (2048+32)) || (kbread == (3072+32)) ){
+ BOOL check = TRUE;
+ // Check for all 0s, all 1s or mirror of first 32k
+ for(i = 0; i < 32 * 1024; i++){
+ if((buffer[i] != firstdata[i]) && (buffer[i] != 0x00) && (buffer[i] != 0xFF)){
+// NSLog(@"Not a mirror, and not open bus");
+ // Not a mirror, and not open bus
+ check = FALSE;
+ break;
+ }
+ }
+ // The End
+ if(check){
+// NSLog(@"The End");
+ kbread -= 32;
+ break;
+ }
+ }
+ }
+ [outData appendBytes:buffer length:(32 * 1024)];
+ // fwrite(buffer, 1, 32*1024, f);
+ // printf(".");
+
+ // Check size limit (4MB max)
+ if((kbytes) && (kbread >= kbytes)){
+// NSLog(@"Size limit reached!");
+ break;
+ }
+ }while(kbread < kbytes);
+ // }while(kbread < 5120);
+
+ // Save to file
+ [outData writeToFile:fileName atomically:YES];
+
+ command[0] = 'C'; //Set CS
+ command[1] = 0;
+
+ [self writeBytes: command bytes: 2];
+
+ [console addText:[NSString stringWithFormat:@"Read %d kB\n", kbread]];
+
+ if(firstdata) free(firstdata);
+ free(buffer);
+
+ return kbread;
+}
+
+// Reads SaveRAM to outfile. Autodetects the size
+- (BOOL) readSaveFile:(NSString *)fileName{
+ int i;
+ int savesize;
+ unsigned int addr;
+
+ unsigned char *buffer = (unsigned char*)malloc(32*1024); //MAX SIZE
+ unsigned char command[32];
+
+ [console addText:@"Reading Save RAM...\n"];
+
+ NSMutableData *outData = [NSMutableData dataWithCapacity:1];
+
+ // Read SaveRAM
+ if(cartBanking){
+ addr = 0x306000;
+ savesize = 8*1024;
+
+ command[0] = 'C'; //NO CS
+ command[1] = 0;
+ }
+ else{
+ addr = 0x700000;
+ savesize = 32*1024;
+
+ command[0] = 'C'; //Yes CS
+ command[1] = 1;
+ }
+
+ [self writeBytes:command bytes: 2];
+
+ // Read Commands
+ for(i = 0; i < savesize; i += 1024){
+ command[0] = 'R'; //Autoread
+ command[1] = addr & 0xFF;
+ command[2] = (addr >> 8) & 0xFF;
+ command[3] = (addr >> 16) & 0xFF;
+
+ [self writeBytes:command bytes: 4];
+
+ addr += 1024;
+ }
+
+ // Read Data
+ [self readBytes:buffer bytes:savesize];
+
+ // Determine Size
+ while(savesize > 2048){
+ i = savesize / 2;
+ if(memcmp(&buffer[0], &buffer[i], i) == 0) savesize = i;
+ else break;
+ }
+
+ // Write to file
+ [outData appendBytes:buffer length:savesize];
+ [outData writeToFile:fileName atomically:YES];
+
+ [console addText:[NSString stringWithFormat:@"Read %d Bytes\n", savesize]];
+
+ command[0] = 'C'; //Set CS
+ command[1] = 0;
+
+ [self writeBytes:command bytes: 2];
+
+ return savesize;
+}
+
+// Reads SaveRAM from infile and writes to cartridge
+- (BOOL) writeSaveFile:(NSString *)fileName{
+ int i;
+ int savesize;
+ unsigned int addr;
+ unsigned char *buffer = (unsigned char*)malloc(32*1024);
+ unsigned char command[4];
+
+ [console addText:@"Writing Save RAM...\n"];
+
+ // Read File
+ NSData *mySave = [NSData dataWithContentsOfFile:fileName];
+ [mySave getBytes:buffer];
+
+// fseek(f, 0, SEEK_END);
+ savesize = (int)[mySave length];
+// fseek(f, 0, SEEK_SET);
+ savesize = (savesize + 0x3FF) & ~0x3FF; // Multiple of 1k
+
+ if(savesize > 32*1024){
+ savesize = 32*1024;
+ }
+
+
+ // Write Data
+ if(cartBanking){
+ addr = 0x306000;
+ if(savesize > 8192){
+ savesize = 8192;
+ }
+ command[0] = 'C'; // NO CS
+ command[1] = 0;
+ }
+ else{
+ addr = 0x700000;
+ command[0] = 'C'; // Set CS
+ command[1] = 1;
+ }
+
+ [self writeBytes:command bytes:2];
+
+ // Write Commands
+ for(i = 0; i < savesize; i += 1024){
+ command[0] = 'W'; //Autowrite
+ command[1] = addr & 0xFF;
+ command[2] = (addr >> 8) & 0xFF;
+ command[3] = (addr >> 16) & 0xFF;
+
+ [self writeBytes:command bytes:4];
+ [self writeBytes:(buffer + i) bytes:1024];
+
+ addr += 1024;
+ }
+
+ command[0] = 'C'; // Set CS
+ command[1] = 0;
+
+ [self writeBytes:command bytes:2];
+
+ [console addText:[NSString stringWithFormat:@"Wrote %d Bytes\n", savesize]];
+
+ // Close
+ free(buffer);
+
+ return TRUE;
+}
+
+// Fills SaveRAM with all 0s
+- (BOOL) clearSave{
+ [console addText:@"Clear Save...\n"];
+ int i;
+ int savesize;
+ int addr;
+ unsigned char *buffer;
+ unsigned char command[4];
+
+ // Write Data
+ buffer = (unsigned char*)malloc(1024);
+ memset(buffer, 0, 1024);
+
+ if(cartBanking){
+ addr = 0x306000;
+ savesize = 8*1024;
+ command[0] = 'C'; //NO CS
+ command[1] = 0;
+ }
+ else{
+ addr = 0x700000;
+ savesize = 32*1024;
+ command[0] = 'C'; //Set CS
+ command[1] = 1;
+ }
+
+ [self writeBytes:command bytes:2];
+
+ // Write Commands
+ for(i = 0; i < savesize; i += 1024){
+ command[0] = 'W'; // Autowrite
+ command[1] = addr & 0xFF;
+ command[2] = (addr >> 8) & 0xFF;
+ command[3] = (addr >> 16) & 0xFF;
+
+ [self writeBytes:command bytes:4];
+ [self writeBytes:buffer bytes:1024]; // 1K of zeros
+
+ addr += 1024;
+ }
+
+ command[0] = 'C'; //Set CS
+ command[1] = 0;
+
+ [self writeBytes:command bytes:2];
+
+ free(buffer);
+
+ return TRUE;
+}
+
+// Send junk bytes, in case it was reset in the middle of a write
+- (BOOL) sendJunk{
+ int i;
+ unsigned char command[32];
+
+ memset(command, 0, 32);
+
+ for(i = 0; i < 32; i++){
+ [self writeBytes: command bytes: 32];
+ }
+
+ return TRUE;
+}
+
+// Makes IRQn go high, disabling EEPROM writing till poweroff
+- (void) disableEE{
+ [console addText:@"Disable EEPROM Writing!\n"];
+ unsigned char command[2];
+ command[0] = 'C';
+ command[1] = 2;
+
+ [self writeBytes:command bytes:2];
+ sleep(1);
+}
+
+// Sends 1 bit of data to EEPROM using Address bus
+// read = 1 to read back the bit later
+// Uses a side channel to access the EEPROM
+- (BOOL) sendEEBit:(int)bit read:(int)read{
+ // EECLK_Out <= BUS_A12; 0x10
+ // EECS_Out <= BUS_A13; 0x20
+ // EEDIN_Out <= BUS_A14; 0x40
+ int i;
+ unsigned char command[16];
+ command[0] = 'w'; // Write with A15=1, A11=0 and CS disabled
+ command[1] = 0x00;
+ command[2] = 0xA0; // CLK=0, CS=1, DIN=0
+ command[3] = 0x00;
+ command[4] = 0x00;
+ command[5] = 'w';
+ command[6] = 0x00;
+ command[7] = 0xB0; // CLK=1, CS=1, DIN=0
+ command[8] = 0x00;
+ command[9] = 0x00;
+ command[10] = 'S'; // Get RST (EE_DOUT)
+
+ if(bit){
+ command[2] |= 0x40; // Set DIN
+ command[7] |= 0x40;
+ }
+
+ if(read) i = 11;
+ else i = 10; // Skip last command
+
+ [self writeBytes:command bytes:i];
+
+ return TRUE;
+}
+
+// Reads a number of bytes from the EEPROM. Not too fast :(
+// Commands from 93C46 datasheet
+- (BOOL) readEE:(unsigned char *)data bytes:(int)bytes{
+ int i, n;
+ unsigned char c;
+ unsigned char bits[8];
+ unsigned char command[8];
+
+ [console addText:@"Reading EEPROM...\n"];
+
+ if(bytes > 128) bytes = 128;
+
+ // CS disabled
+ command[0] = 'C';
+ command[1] = 0;
+
+ [self writeBytes:command bytes:2];
+
+ // READ
+ [self sendEEBit:1 read:0]; // START
+ [self sendEEBit:1 read:0]; // CMD1
+ [self sendEEBit:0 read:0]; // CMD0
+ [self sendEEBit:0 read:0]; // A6
+ [self sendEEBit:0 read:0]; // A5
+ [self sendEEBit:0 read:0]; // A4
+ [self sendEEBit:0 read:0]; // A3
+ [self sendEEBit:0 read:0]; // A2
+ [self sendEEBit:0 read:0]; // A1
+ [self sendEEBit:0 read:0]; // A0
+
+ for(i = 0; i < bytes; i++){
+ // Read data bits
+ for(n = 0; n < 8; n++){
+ [self sendEEBit:0 read:1];
+ }
+
+ // Get bits and decode
+ [self readBytes:bits bytes:8];
+
+ c = 0;
+ for(n = 0; n < 8; n++){
+ c <<= 1;
+ c |= bits[n] & 0x01;
+ }
+ data[i] = c;
+ // NSLog(@"%x ", c);
+ }
+
+ // FINISH
+ command[0] = 'w';
+ command[1] = 0x00;
+ command[2] = 0x80; // CLK=0, CS=0, DIN=0
+ command[3] = 0x00;
+ command[4] = 0x00;
+
+ [self writeBytes:command bytes:5];
+
+ return TRUE;
+}
+
+// Writes a number of bytes to the EEPROM
+// Commands from 93C46 datasheet
+- (BOOL) writeEE:(unsigned char *)data bytes:(int)bytes{
+ int i;
+ int timeout;
+
+ unsigned char command[16];
+
+ [console addText:@"Writing to EEPROM...\n"];
+
+ if(bytes > 128) bytes = 128;
+
+ // CS disabled
+ command[0] = 'C';
+ command[1] = 0;
+
+ [self writeBytes:command bytes:2];
+
+ // WRITE ENABLE
+ [self sendEEBit:1 read:0]; // START
+ [self sendEEBit:0 read:0]; // CMD1
+ [self sendEEBit:0 read:0]; // CMD0
+ [self sendEEBit:1 read:0]; // A6
+ [self sendEEBit:1 read:0]; // A5
+ [self sendEEBit:0 read:0]; // A4
+ [self sendEEBit:0 read:0]; // A3
+ [self sendEEBit:0 read:0]; // A2
+ [self sendEEBit:0 read:0]; // A1
+ [self sendEEBit:0 read:0]; // A0
+
+ command[0] = 'w';
+ command[1] = 0x00;
+ command[2] = 0x80; // CLK=0, CS=0, DIN=0 (lower CS)
+ command[3] = 0x00;
+ command[4] = 0x00;
+
+ [self writeBytes:command bytes:5];
+
+ // ERASE ALL BYTES
+ [console addText:@"Erasing EEPROM...\n"];
+ for(i = 0; i < bytes; i++){
+ // ERASE
+ [self sendEEBit:1 read:0]; //START
+ [self sendEEBit:1 read:0]; //CMD1
+ [self sendEEBit:1 read:0]; //CMD0
+ [self sendEEBit:(i & 0x40) read: 0]; //A6
+ [self sendEEBit:(i & 0x20) read: 0]; //A5
+ [self sendEEBit:(i & 0x10) read: 0]; //A4
+ [self sendEEBit:(i & 0x08) read: 0]; //A3
+ [self sendEEBit:(i & 0x04) read: 0]; //A2
+ [self sendEEBit:(i & 0x02) read: 0]; //A1
+ [self sendEEBit:(i & 0x01) read: 0]; //A0
+
+ command[0] = 'w';
+ command[1] = 0x00;
+ command[2] = 0x80; //CLK=0, CS=0, DIN=0 (start erase cycle)
+ command[3] = 0x00;
+ command[4] = 0x00;
+ command[5] = 'w';
+ command[6] = 0x00;
+ command[7] = 0xA0; //CLK=0, CS=1, DIN=0 (raise CS to get status)
+ command[8] = 0x00;
+ command[9] = 0x00;
+
+ [self writeBytes:command bytes:10];
+
+ // Wait for it to be done
+ timeout = 0;
+ do{
+ timeout++;
+
+ // Takes 5ms to erase a byte
+ if(timeout >= 200){
+ [console addText:@"ERROR: Timed Out!\n"];
+ return FALSE;
+ }
+
+ command[0] = 'S';
+
+ [self writeBytes:command bytes:1];
+ [self readBytes:command bytes:1];
+ }while((command[0] & 0x01) == 0);
+
+ command[0] = 'w';
+ command[1] = 0x00;
+ command[2] = 0x80; //CLK=0, CS=0, DIN=0 (lower CS)
+ command[3] = 0x00;
+ command[4] = 0x00;
+
+ [self writeBytes:command bytes:5];
+ }
+
+ // WRITE
+ [console addText:@"Writing new EEPROM...\n"];
+
+ for(i=0; i < bytes; i++){
+ if(data[i] == 0xFF) continue;
+
+ //WRITE
+ [self sendEEBit:(1) read: 0]; //START
+ [self sendEEBit:(0) read: 0]; //CMD1
+ [self sendEEBit:(1) read: 0]; //CMD0
+
+ [self sendEEBit:(i & 0x40) read: 0]; //A6
+ [self sendEEBit:(i & 0x20) read: 0]; //A5
+ [self sendEEBit:(i & 0x10) read: 0]; //A4
+ [self sendEEBit:(i & 0x08) read: 0]; //A3
+ [self sendEEBit:(i & 0x04) read: 0]; //A2
+ [self sendEEBit:(i & 0x02) read: 0]; //A1
+ [self sendEEBit:(i & 0x01) read: 0]; //A0
+
+ [self sendEEBit:(data[i] & 0x80) read: 0]; //D7
+ [self sendEEBit:(data[i] & 0x40) read: 0]; //D6
+ [self sendEEBit:(data[i] & 0x20) read: 0]; //D5
+ [self sendEEBit:(data[i] & 0x10) read: 0]; //D4
+ [self sendEEBit:(data[i] & 0x08) read: 0]; //D3
+ [self sendEEBit:(data[i] & 0x04) read: 0]; //D2
+ [self sendEEBit:(data[i] & 0x02) read: 0]; //D1
+ [self sendEEBit:(data[i] & 0x01) read: 0]; //D0
+
+ command[0] = 'w';
+ command[1] = 0x00;
+ command[2] = 0x80; //CLK=0, CS=0, DIN=0 (start write cycle)
+ command[3] = 0x00;
+ command[4] = 0x00;
+ command[5] = 'w';
+ command[6] = 0x00;
+ command[7] = 0xA0; //CLK=0, CS=1, DIN=0 (raise CS to get status)
+ command[8] = 0x00;
+ command[9] = 0x00;
+
+ [self writeBytes:command bytes:10];
+
+ // Wait for it to be done
+ do{
+ command[0] = 'S';
+ [self writeBytes:command bytes:1];
+ [self readBytes:command bytes:1];
+ }while((command[0] & 0x01) == 0);
+
+ command[0] = 'w';
+ command[1] = 0x00;
+ command[2] = 0x80; //CLK=0, CS=0, DIN=0 (lower CS)
+ command[3] = 0x00;
+ command[4] = 0x00;
+
+ [self writeBytes:command bytes:5];
+ }
+
+ // Reset EEPROM State Machine
+ // So it gets into the new ROM mode
+ [console addText:@"Reset EEPROM State Machine...\n"];
+ command[0] = 'w';
+ command[1] = 0x00;
+ command[2] = 0x88; //A11=1 means reset
+ command[3] = 0x00;
+ command[4] = 0x00;
+ command[5] = 'S'; //Wait for it to finish resetting
+ command[6] = 'S';
+ command[7] = 'S';
+ command[8] = 'S';
+ command[9] = 'S';
+ command[10] = 'S';
+ command[11] = 'S';
+ command[12] = 'S';
+
+ [self writeBytes:command bytes:13];
+ [self readBytes:command bytes:8];
+
+ return TRUE;
+}
+
+@end
15 Console.h
@@ -0,0 +1,15 @@
+/* Console */
+
+#import <Cocoa/Cocoa.h>
+
+@interface Console : NSWindowController{
+ IBOutlet id textView;
+}
+
+- (IBAction)clear:(id)sender;
+
+- (void)show;
+
+- (void)addText:(NSString *)notif;
+
+@end
38 Console.m
@@ -0,0 +1,38 @@
+#import "Console.h"
+
+@implementation Console
+
+- (id)init{
+ self = [super init];
+ [NSBundle loadNibNamed:@"Console" owner:self];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(addText:) name:@"ConsoleNotification" object:nil];
+ return self;
+}
+
+- (void)dealloc{
+ [super dealloc];
+}
+
+- (void)awakeFromNib{
+ [textView setFont:[NSFont fontWithName:@"Monaco" size:10.0]];
+ [textView setContinuousSpellCheckingEnabled:NO];
+}
+
+- (IBAction)clear:(id)sender{
+ NSRange range = NSMakeRange (0, [[[textView textStorage] string] length]);
+ [textView setSelectedRange:range];
+ [textView delete:nil];
+}
+
+- (void)show{
+ [[self window] makeKeyAndOrderFront:self];
+}
+
+- (void)addText:(NSString *)notif{
+// NSLog(@"%@", notif);
+ [textView insertText:notif];
+ NSRange range = NSMakeRange([[textView string] length], 0);
+ [textView scrollRangeToVisible: range];
+}
+
+@end
1 Driver Installer.pmdoc/01libftd-contents.xml
@@ -0,0 +1 @@
+<pkg-contents spec="1.12"><f n="libftd2xx.0.1.4.dylib" o="root" g="everyone" p="33261" pt="/Users/gapetto/SNESminni/SNESudo/libftd2xx.0.1.4.dylib" m="false" t="file"><mod>owner</mod><mod>group</mod></f></pkg-contents>
1 Driver Installer.pmdoc/01libftd.xml
@@ -0,0 +1 @@
+<pkgref spec="1.12" uuid="9AC22702-C28B-4E5B-8646-EAA8D36AAFBA"><config><identifier>org.eludevisibity.ftd2xxUsbDriverInstaller.libftd2xx014.pkg</identifier><version>0.1.4</version><description/><post-install type="none"/><requireAuthorization/><installFrom>/Users/gapetto/SNESminni/SNESudo/libftd2xx.0.1.4.dylib</installFrom><installTo mod="true">/usr/local/lib/</installTo><flags><followSymbolicLinks/></flags><packageStore type="internal"/><mod>parent</mod><mod>version</mod><mod>installTo.path</mod><mod>installTo</mod></config><contents><file-list>01libftd-contents.xml</file-list><filter>/CVS$</filter><filter>/\.svn$</filter><filter>/\.cvsignore$</filter><filter>/\.cvspass$</filter><filter>/\.DS_Store$</filter></contents></pkgref>
1 Driver Installer.pmdoc/02libftd-contents.xml
@@ -0,0 +1 @@
+<pkg-contents spec="1.12"><f n="libftd2xx.0.1.6.dylib" o="root" g="everyone" p="33261" pt="/Users/gapetto/SNESminni/SNESudo/libftd2xx.0.1.6.dylib" m="false" t="file"><mod>owner</mod><mod>group</mod></f></pkg-contents>
1 Driver Installer.pmdoc/02libftd.xml
@@ -0,0 +1 @@
+<pkgref spec="1.12" uuid="DE28854B-0BDE-4BC3-95EF-14C58CF89B46"><config><identifier>org.eludevisibity.ftd2xxUsbDriverInstaller.libftd2xx016.pkg</identifier><version>0.1.6</version><description/><post-install type="none"/><requireAuthorization/><installFrom>/Users/gapetto/SNESminni/SNESudo/libftd2xx.0.1.6.dylib</installFrom><installTo mod="true">/usr/local/lib/</installTo><flags><followSymbolicLinks/></flags><packageStore type="internal"/><mod>parent</mod><mod>version</mod><mod>installTo.path</mod><mod>installTo</mod></config><contents><file-list>02libftd-contents.xml</file-list><filter>/CVS$</filter><filter>/\.svn$</filter><filter>/\.cvsignore$</filter><filter>/\.cvspass$</filter><filter>/\.DS_Store$</filter></contents></pkgref>
1 Driver Installer.pmdoc/03libftd-contents.xml
@@ -0,0 +1 @@
+<pkg-contents spec="1.12"><f n="libftd2xx.0.1.0.dylib" o="root" g="everyone" p="33263" pt="/Users/gapetto/SNESminni/SNESudo/libftd2xx.0.1.0.dylib" m="false" t="file"><mod>owner</mod><mod>group</mod></f></pkg-contents>
1 Driver Installer.pmdoc/03libftd.xml
@@ -0,0 +1 @@
+<pkgref spec="1.12" uuid="970DC9FA-B430-4698-9EAC-AB67D722D12C"><config><identifier>org.eludevisibity.ftd2xxUsbDriverInstaller.libftd2xx010.pkg</identifier><version>0.1.0</version><description/><post-install type="none"/><requireAuthorization/><installFrom>/Users/gapetto/SNESminni/SNESudo/libftd2xx.0.1.0.dylib</installFrom><installTo mod="true">/usr/local/lib/</installTo><flags><followSymbolicLinks/></flags><packageStore type="internal"/><mod>parent</mod><mod>version</mod><mod>installTo.path</mod><mod>installTo</mod></config><contents><file-list>03libftd-contents.xml</file-list><filter>/CVS$</filter><filter>/\.svn$</filter><filter>/\.cvsignore$</filter><filter>/\.cvspass$</filter><filter>/\.DS_Store$</filter></contents></pkgref>
1 Driver Installer.pmdoc/index.xml
@@ -0,0 +1 @@
+<pkmkdoc spec="1.12"><properties><title>FTD2XX USB Driver Installer</title><build>/Users/gapetto/SNESminni/SNESudo/FTD2XX USB Driver Installer.pkg</build><organization>org.eludevisibity</organization><userSees ui="both"/><min-target os="3"/><domain system="true"/></properties><distribution><versions min-spec="1.000000"/><scripts></scripts></distribution><description>This will install the FTD2XX drivers needed by CopyNES USB and SNES Flash Tool.</description><contents><choice title="libftd2xx.0.1.4" id="choice0" starts_selected="true" starts_enabled="true" starts_hidden="false"><pkgref id="org.eludevisibity.ftd2xxUsbDriverInstaller.libftd2xx014.pkg"/></choice><choice title="libftd2xx.0.1.6" id="choice1" starts_selected="true" starts_enabled="true" starts_hidden="false"><pkgref id="org.eludevisibity.ftd2xxUsbDriverInstaller.libftd2xx016.pkg"/></choice><choice title="libftd2xx.0.1.0" id="choice2" starts_selected="true" starts_enabled="true" starts_hidden="false"><pkgref id="org.eludevisibity.ftd2xxUsbDriverInstaller.libftd2xx010.pkg"/></choice></contents><resources bg-scale="none" bg-align="topleft"><locale lang="en"/></resources><flags/><item type="file">01libftd.xml</item><item type="file">02libftd.xml</item><item type="file">03libftd.xml</item><mod>properties.title</mod><mod>description</mod><mod>properties.systemDomain</mod><mod>properties.anywhereDomain</mod></pkmkdoc>
475 English.lproj/Console.xib
@@ -0,0 +1,475 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.03">
+ <data>
+ <int key="IBDocument.SystemTarget">1050</int>
+ <string key="IBDocument.SystemVersion">9J61</string>
+ <string key="IBDocument.InterfaceBuilderVersion">677</string>
+ <string key="IBDocument.AppKitVersion">949.46</string>
+ <string key="IBDocument.HIToolboxVersion">353.00</string>
+ <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="5"/>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.RootObjects" id="167626652">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSCustomObject" id="949139129">
+ <string key="NSClassName">KWConsole</string>
+ </object>
+ <object class="NSCustomObject" id="236070366">
+ <string key="NSClassName">FirstResponder</string>
+ </object>
+ <object class="NSCustomObject" id="989180474">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSWindowTemplate" id="260996935">
+ <int key="NSWindowStyleMask">15</int>
+ <int key="NSWindowBacking">2</int>
+ <string key="NSWindowRect">{{13, 10}, {505, 149}}</string>
+ <int key="NSWTFlags">1886912512</int>
+ <string key="NSWindowTitle">Console</string>
+ <object class="NSMutableString" key="NSWindowClass">
+ <characters key="NS.bytes">NSWindow</characters>
+ </object>
+ <object class="NSMutableString" key="NSViewClass">
+ <characters key="NS.bytes">View</characters>
+ </object>
+ <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string>
+ <string key="NSWindowContentMinSize">{213, 107}</string>
+ <object class="NSView" key="NSWindowView" id="635916005">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSScrollView" id="523855993">
+ <reference key="NSNextResponder" ref="635916005"/>
+ <int key="NSvFlags">274</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSClipView" id="186921581">
+ <reference key="NSNextResponder" ref="523855993"/>
+ <int key="NSvFlags">2304</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTextView" id="707543414">
+ <reference key="NSNextResponder" ref="186921581"/>
+ <int key="NSvFlags">2322</int>
+ <object class="NSMutableSet" key="NSDragTypes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="set.sortedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>Apple HTML pasteboard type</string>
+ <string>Apple PDF pasteboard type</string>
+ <string>Apple PICT pasteboard type</string>
+ <string>Apple PNG pasteboard type</string>
+ <string>Apple URL pasteboard type</string>
+ <string>CorePasteboardFlavorType 0x6D6F6F76</string>
+ <string>CorePasteboardFlavorType 0x75726C20</string>
+ <string>NSColor pasteboard type</string>
+ <string>NSFilenamesPboardType</string>
+ <string>NSStringPboardType</string>
+ <string>NeXT Encapsulated PostScript v1.2 pasteboard type</string>
+ <string>NeXT RTFD pasteboard type</string>
+ <string>NeXT Rich Text Format v1.0 pasteboard type</string>
+ <string>NeXT TIFF v4.0 pasteboard type</string>
+ <string>NeXT font pasteboard type</string>
+ <string>NeXT ruler pasteboard type</string>
+ <string>WebURLsWithTitlesPboardType</string>
+ </object>
+ </object>
+ <string key="NSFrameSize">{503, 14}</string>
+ <reference key="NSSuperview" ref="186921581"/>
+ <object class="NSTextContainer" key="NSTextContainer" id="999155559">
+ <object class="NSLayoutManager" key="NSLayoutManager">
+ <object class="NSTextStorage" key="NSTextStorage">
+ <object class="NSMutableString" key="NSString">
+ <characters key="NS.bytes"/>
+ </object>
+ <nil key="NSDelegate"/>
+ </object>
+ <object class="NSMutableArray" key="NSTextContainers">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="999155559"/>
+ </object>
+ <int key="NSLMFlags">6</int>
+ <nil key="NSDelegate"/>
+ </object>
+ <reference key="NSTextView" ref="707543414"/>
+ <double key="NSWidth">5.030000e+02</double>
+ <int key="NSTCFlags">1</int>
+ </object>
+ <object class="NSTextViewSharedData" key="NSSharedData">
+ <int key="NSFlags">11235</int>
+ <object class="NSColor" key="NSBackgroundColor" id="1013937766">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MQA</bytes>
+ </object>
+ <object class="NSColor" key="NSInsertionColor" id="928262214">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MAA</bytes>
+ </object>
+ <object class="NSDictionary" key="NSSelectedAttributes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSBackgroundColor</string>
+ <string>NSColor</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">selectedTextBackgroundColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC42NjY2NjY2OQA</bytes>
+ </object>
+ </object>
+ <object class="NSColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">selectedTextColor</string>
+ <reference key="NSColor" ref="928262214"/>
+ </object>
+ </object>
+ </object>
+ <nil key="NSMarkedAttributes"/>
+ <object class="NSDictionary" key="NSLinkAttributes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSColor</string>
+ <string>NSUnderline</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSColor">
+ <int key="NSColorSpace">1</int>
+ <bytes key="NSRGB">MCAwIDEAA</bytes>
+ </object>
+ <integer value="1"/>
+ </object>
+ </object>
+ <nil key="NSDefaultParagraphStyle"/>
+ </object>
+ <int key="NSTVFlags">6</int>
+ <string key="NSMaxSize">{569, 1e+07}</string>
+ <string key="NSMinize">{114, 0}</string>
+ <nil key="NSDelegate"/>
+ </object>
+ </object>
+ <string key="NSFrame">{{1, 1}, {503, 114}}</string>
+ <reference key="NSSuperview" ref="523855993"/>
+ <reference key="NSNextKeyView" ref="707543414"/>
+ <reference key="NSDocView" ref="707543414"/>
+ <reference key="NSBGColor" ref="1013937766"/>
+ <object class="NSCursor" key="NSCursor">
+ <string key="NSHotSpot">{4, -5}</string>
+ <int key="NSCursorType">1</int>
+ </object>
+ <int key="NScvFlags">4</int>
+ </object>
+ <object class="NSScroller" id="397671833">
+ <reference key="NSNextResponder" ref="523855993"/>
+ <int key="NSvFlags">-2147483392</int>
+ <string key="NSFrame">{{434, 1}, {15, 105}}</string>
+ <reference key="NSSuperview" ref="523855993"/>
+ <reference key="NSTarget" ref="523855993"/>
+ <string key="NSAction">_doScroller:</string>
+ <double key="NSPercent">9.577465e-01</double>
+ </object>
+ <object class="NSScroller" id="574734298">
+ <reference key="NSNextResponder" ref="523855993"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{-100, -100}, {87, 18}}</string>
+ <reference key="NSSuperview" ref="523855993"/>
+ <int key="NSsFlags">1</int>
+ <reference key="NSTarget" ref="523855993"/>
+ <string key="NSAction">_doScroller:</string>
+ <double key="NSCurValue">1.000000e+00</double>
+ <double key="NSPercent">9.456522e-01</double>
+ </object>
+ </object>
+ <string key="NSFrame">{{0, 34}, {505, 116}}</string>
+ <reference key="NSSuperview" ref="635916005"/>
+ <reference key="NSNextKeyView" ref="186921581"/>
+ <int key="NSsFlags">530</int>
+ <reference key="NSVScroller" ref="397671833"/>
+ <reference key="NSHScroller" ref="574734298"/>
+ <reference key="NSContentView" ref="186921581"/>
+ </object>
+ <object class="NSButton" id="372002132">
+ <reference key="NSNextResponder" ref="635916005"/>
+ <int key="NSvFlags">292</int>
+ <string key="NSFrame">{{15, 2}, {80, 28}}</string>
+ <reference key="NSSuperview" ref="635916005"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="100182037">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134348800</int>
+ <string key="NSContents">Clear</string>
+ <object class="NSFont" key="NSSupport">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">1.100000e+01</double>
+ <int key="NSfFlags">3100</int>
+ </object>
+ <reference key="NSControlView" ref="372002132"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">1</int>
+ <object class="NSFont" key="NSAlternateImage">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">1.100000e+01</double>
+ <int key="NSfFlags">16</int>
+ </object>
+ <string key="NSAlternateContents"/>
+ <object class="NSMutableString" key="NSKeyEquivalent">
+ <characters key="NS.bytes"/>
+ </object>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{505, 149}</string>
+ <reference key="NSSuperview"/>
+ </object>
+ <string key="NSScreenRect">{{0, 0}, {1280, 778}}</string>
+ <string key="NSMinSize">{213, 129}</string>
+ <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string>
+ <string key="NSFrameAutosaveName">Console</string>
+ </object>
+ </object>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <object class="NSMutableArray" key="connectionRecords">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">window</string>
+ <reference key="source" ref="949139129"/>
+ <reference key="destination" ref="260996935"/>
+ </object>
+ <int key="connectionID">11</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">textView</string>
+ <reference key="source" ref="949139129"/>
+ <reference key="destination" ref="707543414"/>
+ </object>
+ <int key="connectionID">12</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">clear:</string>
+ <reference key="source" ref="949139129"/>
+ <reference key="destination" ref="372002132"/>
+ </object>
+ <int key="connectionID">13</int>
+ </object>
+ </object>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <object class="NSArray" key="orderedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <object class="NSArray" key="object" id="0">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="children" ref="167626652"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="949139129"/>
+ <reference key="parent" ref="0"/>
+ <string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="236070366"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">First Responder</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-3</int>
+ <reference key="object" ref="989180474"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Application</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">5</int>
+ <reference key="object" ref="260996935"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="635916005"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Window</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">6</int>
+ <reference key="object" ref="635916005"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="523855993"/>
+ <reference ref="372002132"/>
+ </object>
+ <reference key="parent" ref="260996935"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">7</int>
+ <reference key="object" ref="523855993"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="707543414"/>
+ <reference ref="397671833"/>
+ <reference ref="574734298"/>
+ </object>
+ <reference key="parent" ref="635916005"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">8</int>
+ <reference key="object" ref="707543414"/>
+ <reference key="parent" ref="523855993"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">9</int>
+ <reference key="object" ref="372002132"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="100182037"/>
+ </object>
+ <reference key="parent" ref="635916005"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">15</int>
+ <reference key="object" ref="100182037"/>
+ <reference key="parent" ref="372002132"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">16</int>
+ <reference key="object" ref="397671833"/>
+ <reference key="parent" ref="523855993"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">17</int>
+ <reference key="object" ref="574734298"/>
+ <reference key="parent" ref="523855993"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="flattenedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>-1.IBPluginDependency</string>
+ <string>-2.IBPluginDependency</string>
+ <string>-3.IBPluginDependency</string>
+ <string>-3.ImportedFromIB2</string>
+ <string>16.IBShouldRemoveOnLegacySave</string>
+ <string>17.IBShouldRemoveOnLegacySave</string>
+ <string>5.IBEditorWindowLastContentRect</string>
+ <string>5.IBWindowTemplateEditedContentRect</string>
+ <string>5.ImportedFromIB2</string>
+ <string>5.windowTemplate.hasMinSize</string>
+ <string>5.windowTemplate.minSize</string>
+ <string>6.IBPluginDependency</string>
+ <string>6.ImportedFromIB2</string>
+ <string>7.IBPluginDependency</string>
+ <string>7.ImportedFromIB2</string>
+ <string>8.IBPluginDependency</string>
+ <string>8.ImportedFromIB2</string>
+ <string>9.IBPluginDependency</string>
+ <string>9.ImportedFromIB2</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="YES" id="5"/>
+ <reference ref="5"/>
+ <reference ref="5"/>
+ <string>{{55, 341}, {505, 149}}</string>
+ <string>{{55, 341}, {505, 149}}</string>
+ <reference ref="5"/>
+ <reference ref="5"/>
+ <string>{213, 107}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="5"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="5"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="5"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="5"/>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="unlocalizedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="activeLocalization"/>
+ <object class="NSMutableDictionary" key="localizations">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="sourceID"/>
+ <int key="maxID">17</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">FirstResponder</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBUserSource</string>
+ <string key="minorKey"/>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">KWConsole</string>
+ <string key="superclassName">NSWindowController</string>
+ <object class="NSMutableDictionary" key="actions">
+ <string key="NS.key.0">clear:</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <string key="NS.key.0">textView</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBUserSource</string>
+ <string key="minorKey"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.LastKnownRelativeProjectPath">../SNES USB.xcodeproj</string>
+ <int key="IBDocument.defaultPropertyAccessControl">3</int>
+ </data>
+</archive>
BIN English.lproj/InfoPlist.strings
Binary file not shown.
2,100 English.lproj/MainMenu.xib
@@ -0,0 +1,2100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.03">
+ <data>
+ <int key="IBDocument.SystemTarget">1050</int>
+ <string key="IBDocument.SystemVersion">9J61</string>
+ <string key="IBDocument.InterfaceBuilderVersion">677</string>
+ <string key="IBDocument.AppKitVersion">949.46</string>
+ <string key="IBDocument.HIToolboxVersion">353.00</string>
+ <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="57"/>
+ <integer value="21"/>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool