mirror of
https://github.com/sanni/cartreader.git
synced 2024-11-30 16:34:14 +01:00
commit
4cc3092bbd
@ -825,6 +825,11 @@ void print_Msg_PaddedHexByte(byte message) {
|
|||||||
print_Msg(message, HEX);
|
print_Msg(message, HEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print_Msg_PaddedHex16(word message) {
|
||||||
|
print_Msg_PaddedHexByte((message >> 8) & 0xFF);
|
||||||
|
print_Msg_PaddedHexByte((message >> 0) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
void print_Msg_PaddedHex32(unsigned long message) {
|
void print_Msg_PaddedHex32(unsigned long message) {
|
||||||
print_Msg_PaddedHexByte((message >> 24) & 0xFF);
|
print_Msg_PaddedHexByte((message >> 24) & 0xFF);
|
||||||
print_Msg_PaddedHexByte((message >> 16) & 0xFF);
|
print_Msg_PaddedHexByte((message >> 16) & 0xFF);
|
||||||
|
@ -85,6 +85,85 @@ unsigned long bramSize = 0;
|
|||||||
|
|
||||||
// REALTEC MAPPER
|
// REALTEC MAPPER
|
||||||
boolean realtec = 0;
|
boolean realtec = 0;
|
||||||
|
|
||||||
|
#define DEFAULT_VALUE_segaSram16bit 0
|
||||||
|
int segaSram16bit = DEFAULT_VALUE_segaSram16bit;
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
Configuration
|
||||||
|
*****************************************/
|
||||||
|
void mdLoadConf() {
|
||||||
|
if (myFile.open("md.txt", O_READ)) {
|
||||||
|
char line[64];
|
||||||
|
int n;
|
||||||
|
int i;
|
||||||
|
while ((n = myFile.fgets(line, sizeof(line)-1)) > 0) {
|
||||||
|
// preprocess
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (line[i] == ';') {
|
||||||
|
// comments
|
||||||
|
line[i] = '\0';
|
||||||
|
n = i;
|
||||||
|
break;
|
||||||
|
} else if (line[i] == '\n' || line[i] == '\r') {
|
||||||
|
// EOL
|
||||||
|
line[n] = '\0';
|
||||||
|
n = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//print_Msg(F("read line: "));
|
||||||
|
//println_Msg(line);
|
||||||
|
if (line[0] == '[') {
|
||||||
|
char *name;
|
||||||
|
char *value;
|
||||||
|
i = 1;
|
||||||
|
name = line + i;
|
||||||
|
for (; i < sizeof(line); i++) {
|
||||||
|
if (line[i] == ']') {
|
||||||
|
line[i] = '\0';
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (line[i] != '\0') {
|
||||||
|
for (; i < sizeof(line); i++) {
|
||||||
|
if (line[i] != ' ') {
|
||||||
|
value = line + i;
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (; i < sizeof(line) && line[i] != '\0'; i++) {
|
||||||
|
if (line[i] == ' ') {
|
||||||
|
line[i] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//print_Msg(F("read name: "));
|
||||||
|
//println_Msg(name);
|
||||||
|
//print_Msg(F("value: "));
|
||||||
|
//println_Msg(value);
|
||||||
|
if (!strcmp("segaSram16bit", name)) {
|
||||||
|
// Retrode compatible setting
|
||||||
|
// [segaSram16bit] 1 ; 0=no, 1=yes, 2=y+large
|
||||||
|
// 0: Output each byte once. Not supported by most emulators.
|
||||||
|
// 1: Duplicate each byte. Usable by Kega Fusion.
|
||||||
|
// 2: Duplicate each byte. Pad with 0xFF so that the file size is 64KB.
|
||||||
|
segaSram16bit = atoi(value);
|
||||||
|
if (segaSram16bit != 0 && segaSram16bit != 1 && segaSram16bit != 2) {
|
||||||
|
segaSram16bit = DEFAULT_VALUE_segaSram16bit;
|
||||||
|
}
|
||||||
|
print_Msg(F("segaSram16bit: "));
|
||||||
|
println_Msg(segaSram16bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
myFile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************
|
/******************************************
|
||||||
Menu
|
Menu
|
||||||
*****************************************/
|
*****************************************/
|
||||||
@ -221,7 +300,7 @@ void mdCartMenu() {
|
|||||||
case 1:
|
case 1:
|
||||||
display_Clear();
|
display_Clear();
|
||||||
// Does cartridge have SRAM
|
// Does cartridge have SRAM
|
||||||
if ((saveType == 1) || (saveType == 2) || (saveType == 3) || (saveType == 5)) {
|
if ((saveType == 1) || (saveType == 2) || (saveType == 3)) {
|
||||||
// Change working dir to root
|
// Change working dir to root
|
||||||
sd.chdir("/");
|
sd.chdir("/");
|
||||||
println_Msg(F("Reading Sram..."));
|
println_Msg(F("Reading Sram..."));
|
||||||
@ -238,7 +317,7 @@ void mdCartMenu() {
|
|||||||
case 2:
|
case 2:
|
||||||
display_Clear();
|
display_Clear();
|
||||||
// Does cartridge have SRAM
|
// Does cartridge have SRAM
|
||||||
if ((saveType == 1) || (saveType == 2) || (saveType == 3) || (saveType == 5)) {
|
if ((saveType == 1) || (saveType == 2) || (saveType == 3)) {
|
||||||
// Change working dir to root
|
// Change working dir to root
|
||||||
sd.chdir("/");
|
sd.chdir("/");
|
||||||
// Launch file browser
|
// Launch file browser
|
||||||
@ -358,6 +437,8 @@ void segaCDMenu() {
|
|||||||
Setup
|
Setup
|
||||||
*****************************************/
|
*****************************************/
|
||||||
void setup_MD() {
|
void setup_MD() {
|
||||||
|
mdLoadConf();
|
||||||
|
|
||||||
// Set Address Pins to Output
|
// Set Address Pins to Output
|
||||||
//A0-A7
|
//A0-A7
|
||||||
DDRF = 0xFF;
|
DDRF = 0xFF;
|
||||||
@ -597,7 +678,10 @@ void getCartInfo_MD() {
|
|||||||
// Get sram start and end
|
// Get sram start and end
|
||||||
sramBase = ((long(readWord_MD(0xDA)) << 16) | readWord_MD(0xDB));
|
sramBase = ((long(readWord_MD(0xDA)) << 16) | readWord_MD(0xDB));
|
||||||
sramEnd = ((long(readWord_MD(0xDC)) << 16) | readWord_MD(0xDD));
|
sramEnd = ((long(readWord_MD(0xDC)) << 16) | readWord_MD(0xDD));
|
||||||
|
if (sramBase == 0x20000020 && sramEnd == 0x00010020) { // Fix for Psy-o-blade
|
||||||
|
sramBase = 0x200001;
|
||||||
|
sramEnd = 0x203fff;
|
||||||
|
}
|
||||||
// Check alignment of sram
|
// Check alignment of sram
|
||||||
if ((sramBase == 0x200001) || (sramBase == 0x300001)) { // ADDED 0x300001 FOR HARDBALL '95 (U)
|
if ((sramBase == 0x200001) || (sramBase == 0x300001)) { // ADDED 0x300001 FOR HARDBALL '95 (U)
|
||||||
// low byte
|
// low byte
|
||||||
@ -605,10 +689,6 @@ void getCartInfo_MD() {
|
|||||||
sramSize = (sramEnd - sramBase + 2) / 2;
|
sramSize = (sramEnd - sramBase + 2) / 2;
|
||||||
// Right shift sram base address so [A21] is set to high 0x200000 = 0b001[0]00000000000000000000
|
// Right shift sram base address so [A21] is set to high 0x200000 = 0b001[0]00000000000000000000
|
||||||
sramBase = sramBase >> 1;
|
sramBase = sramBase >> 1;
|
||||||
if (chksum == 0x5D33 && sramEnd == 0x203FFF) { // Dragon Slayer Eiyuu Densetsu
|
|
||||||
// the high byte read as zero
|
|
||||||
saveType = 5; // BOTH
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (sramBase == 0x200000) {
|
else if (sramBase == 0x200000) {
|
||||||
// high byte
|
// high byte
|
||||||
@ -617,9 +697,19 @@ void getCartInfo_MD() {
|
|||||||
// Right shift sram base address so [A21] is set to high 0x200000 = 0b001[0]00000000000000000000
|
// Right shift sram base address so [A21] is set to high 0x200000 = 0b001[0]00000000000000000000
|
||||||
sramBase = sramBase / 2;
|
sramBase = sramBase / 2;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
|
print_Msg(("sramType: "));
|
||||||
|
print_Msg_PaddedHex16(sramType);
|
||||||
|
println_Msg(F(""));
|
||||||
|
print_Msg(("sramBase: "));
|
||||||
|
print_Msg_PaddedHex32(sramBase);
|
||||||
|
println_Msg(F(""));
|
||||||
|
print_Msg(("sramEnd: "));
|
||||||
|
print_Msg_PaddedHex32(sramEnd);
|
||||||
|
println_Msg(F(""));
|
||||||
print_Error(F("Unknown Sram Base"), true);
|
print_Error(F("Unknown Sram Base"), true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (sramType == 0xE020) { // SRAM BOTH BYTES
|
else if (sramType == 0xE020) { // SRAM BOTH BYTES
|
||||||
// Get sram start and end
|
// Get sram start and end
|
||||||
sramBase = ((long(readWord_MD(0xDA)) << 16) | readWord_MD(0xDB));
|
sramBase = ((long(readWord_MD(0xDA)) << 16) | readWord_MD(0xDB));
|
||||||
@ -635,10 +725,20 @@ void getCartInfo_MD() {
|
|||||||
sramSize = sramEnd - sramBase + 1;
|
sramSize = sramEnd - sramBase + 1;
|
||||||
sramBase = sramBase >> 1;
|
sramBase = sramBase >> 1;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
|
print_Msg(("sramType: "));
|
||||||
|
print_Msg_PaddedHex16(sramType);
|
||||||
|
println_Msg(F(""));
|
||||||
|
print_Msg(("sramBase: "));
|
||||||
|
print_Msg_PaddedHex32(sramBase);
|
||||||
|
println_Msg(F(""));
|
||||||
|
print_Msg(("sramEnd: "));
|
||||||
|
print_Msg_PaddedHex32(sramEnd);
|
||||||
|
println_Msg(F(""));
|
||||||
print_Error(F("Unknown Sram Base"), true);
|
print_Error(F("Unknown Sram Base"), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
// SRAM CARTS WITH BAD/MISSING HEADER SAVE DATA
|
// SRAM CARTS WITH BAD/MISSING HEADER SAVE DATA
|
||||||
switch (chksum) {
|
switch (chksum) {
|
||||||
@ -725,10 +825,11 @@ void getCartInfo_MD() {
|
|||||||
println_Msg(F(" "));
|
println_Msg(F(" "));
|
||||||
print_Msg(F("Name: "));
|
print_Msg(F("Name: "));
|
||||||
println_Msg(romName);
|
println_Msg(romName);
|
||||||
|
if (bramCheck != 0x00FF) {
|
||||||
print_Msg(F("bramCheck: "));
|
print_Msg(F("bramCheck: "));
|
||||||
print_Msg_PaddedHexByte(bramCheck >> 8);
|
print_Msg_PaddedHex16(bramCheck);
|
||||||
print_Msg_PaddedHexByte(bramCheck & 0x00ff);
|
|
||||||
println_Msg(F(""));
|
println_Msg(F(""));
|
||||||
|
}
|
||||||
if (bramSize > 0) {
|
if (bramSize > 0) {
|
||||||
print_Msg(F("bramSize(KB): "));
|
print_Msg(F("bramSize(KB): "));
|
||||||
println_Msg(bramSize >> 10);
|
println_Msg(bramSize >> 10);
|
||||||
@ -966,21 +1067,31 @@ void writeSram_MD() {
|
|||||||
// Write to the lower byte
|
// Write to the lower byte
|
||||||
if (saveType == 1) {
|
if (saveType == 1) {
|
||||||
for (unsigned long currByte = sramBase; currByte < sramBase + sramSize; currByte++) {
|
for (unsigned long currByte = sramBase; currByte < sramBase + sramSize; currByte++) {
|
||||||
writeWord_MD(currByte, (myFile.read() & 0xFF));
|
if (segaSram16bit > 0) {
|
||||||
|
// skip high byte
|
||||||
|
myFile.read();
|
||||||
|
}
|
||||||
|
word data = myFile.read() & 0xFF;
|
||||||
|
writeWord_MD(currByte, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Write to the upper byte
|
// Write to the upper byte
|
||||||
else if (saveType == 2) {
|
else if (saveType == 2) {
|
||||||
for (unsigned long currByte = sramBase; currByte < sramBase + sramSize; currByte++) {
|
for (unsigned long currByte = sramBase; currByte < sramBase + sramSize; currByte++) {
|
||||||
writeWord_MD(currByte, ((myFile.read() << 8 ) & 0xFF));
|
word data = (myFile.read() << 8) & 0xFF00;
|
||||||
|
writeWord_MD(currByte, data);
|
||||||
|
if (segaSram16bit > 0) {
|
||||||
|
// skip low byte
|
||||||
|
myFile.read();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Write to both bytes
|
// Write to both bytes
|
||||||
else if (saveType == 5) {
|
else if (saveType == 3) {
|
||||||
for (unsigned long currByte = sramBase; currByte < sramBase + sramSize; currByte++) {
|
for (unsigned long currByte = sramBase; currByte < sramBase + sramSize; currByte++) {
|
||||||
word w0 = (myFile.read() & 0xFF); // skip
|
word data = (myFile.read() << 8) & 0xFF00;
|
||||||
word w1 = (myFile.read() & 0xFF);
|
data |= (myFile.read() & 0xFF);
|
||||||
writeWord_MD(currByte, w1);
|
writeWord_MD(currByte, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1026,26 +1137,43 @@ void readSram_MD() {
|
|||||||
|
|
||||||
if (saveType == 2) {
|
if (saveType == 2) {
|
||||||
// Only use the upper byte
|
// Only use the upper byte
|
||||||
|
if (segaSram16bit > 0) {
|
||||||
|
sdBuffer[(currWord * 2) + 0] = (( myWord >> 8 ) & 0xFF);
|
||||||
|
sdBuffer[(currWord * 2) + 1] = (( myWord >> 8 ) & 0xFF);
|
||||||
|
} else {
|
||||||
sdBuffer[currWord] = (( myWord >> 8 ) & 0xFF);
|
sdBuffer[currWord] = (( myWord >> 8 ) & 0xFF);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (saveType == 1) {
|
else if (saveType == 1) {
|
||||||
// Only use the lower byte
|
// Only use the lower byte
|
||||||
|
if (segaSram16bit > 0) {
|
||||||
|
sdBuffer[(currWord * 2) + 0] = (myWord & 0xFF);
|
||||||
|
sdBuffer[(currWord * 2) + 1] = (myWord & 0xFF);
|
||||||
|
} else {
|
||||||
sdBuffer[currWord] = (myWord & 0xFF);
|
sdBuffer[currWord] = (myWord & 0xFF);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (saveType == 3) { // BOTH
|
else if (saveType == 3) { // BOTH
|
||||||
sdBuffer[currWord * 2] = (( myWord >> 8 ) & 0xFF);
|
sdBuffer[currWord * 2] = (( myWord >> 8 ) & 0xFF);
|
||||||
sdBuffer[(currWord * 2) + 1] = (myWord & 0xFF);
|
sdBuffer[(currWord * 2) + 1] = (myWord & 0xFF);
|
||||||
}
|
}
|
||||||
else if (saveType == 5) { // duplicate the lower byte
|
|
||||||
sdBuffer[(currWord * 2) + 0] = (myWord & 0xFF);
|
|
||||||
sdBuffer[(currWord * 2) + 1] = (myWord & 0xFF);
|
|
||||||
}
|
}
|
||||||
}
|
if (saveType == 3 || segaSram16bit > 0)
|
||||||
if (saveType == 3 || saveType == 5)
|
|
||||||
myFile.write(sdBuffer, 512);
|
myFile.write(sdBuffer, 512);
|
||||||
else
|
else
|
||||||
myFile.write(sdBuffer, 256);
|
myFile.write(sdBuffer, 256);
|
||||||
}
|
}
|
||||||
|
if (segaSram16bit == 2) {
|
||||||
|
// pad to 64KB
|
||||||
|
for (int i = 0; i < 512; i++) {
|
||||||
|
sdBuffer[i] = 0xFF;
|
||||||
|
}
|
||||||
|
unsigned long padsize = (1UL << 16) - (sramSize << 1);
|
||||||
|
unsigned long padblockcount = padsize >> 9; // number of 512 byte blocks
|
||||||
|
for (int i = 0; i < padblockcount; i++) {
|
||||||
|
myFile.write(sdBuffer, 512);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Close the file:
|
// Close the file:
|
||||||
myFile.close();
|
myFile.close();
|
||||||
print_Msg(F("Saved to "));
|
print_Msg(F("Saved to "));
|
||||||
@ -1060,22 +1188,36 @@ unsigned long verifySram_MD() {
|
|||||||
|
|
||||||
// Open file on sd card
|
// Open file on sd card
|
||||||
if (myFile.open(filePath, O_READ)) {
|
if (myFile.open(filePath, O_READ)) {
|
||||||
for (unsigned long currBuffer = sramBase; currBuffer < sramBase + sramSize; currBuffer += 512) {
|
for (unsigned long currBuffer = sramBase; currBuffer < sramBase + sramSize; currBuffer += 256) {
|
||||||
for (int currWord = 0; currWord < 512; currWord++) {
|
for (int currWord = 0; currWord < 256; currWord++) {
|
||||||
word myWord = readWord_MD(currBuffer + currWord);
|
word myWord = readWord_MD(currBuffer + currWord);
|
||||||
|
|
||||||
if (saveType == 2) {
|
if (saveType == 2) {
|
||||||
// Only use the upper byte
|
// Only use the upper byte
|
||||||
sdBuffer[currWord] = (( myWord >> 8 ) & 0xFF);
|
sdBuffer[currWord * 2] = (( myWord >> 8 ) & 0xFF);
|
||||||
}
|
}
|
||||||
else if (saveType == 1) {
|
else if (saveType == 1) {
|
||||||
// Only use the lower byte
|
// Only use the lower byte
|
||||||
sdBuffer[currWord] = (myWord & 0xFF);
|
sdBuffer[currWord * 2] = (myWord & 0xFF);
|
||||||
|
}
|
||||||
|
else if (saveType == 3) { // BOTH
|
||||||
|
sdBuffer[(currWord * 2) + 0] = (( myWord >> 8 ) & 0xFF);
|
||||||
|
sdBuffer[(currWord * 2) + 1] = (myWord & 0xFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int step = saveType == 3 ? 1 : 2;
|
||||||
// Check sdBuffer content against file on sd card
|
// Check sdBuffer content against file on sd card
|
||||||
for (int i = 0; i < 512; i++) {
|
for (int i = 0; i < 512; i += step) {
|
||||||
if (myFile.read() != sdBuffer[i]) {
|
if (saveType == 1 && segaSram16bit > 0) {
|
||||||
|
// skip high byte
|
||||||
|
myFile.read();
|
||||||
|
}
|
||||||
|
byte b = myFile.read();
|
||||||
|
if (saveType == 2 && segaSram16bit > 0) {
|
||||||
|
// skip low byte
|
||||||
|
myFile.read();
|
||||||
|
}
|
||||||
|
if (b != sdBuffer[i]) {
|
||||||
writeErrors++;
|
writeErrors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user