Hi All,
I am trying to make SMB work, but I am having difficulties with the background. The nametable at 0x2400 seems to hold incorrect data. Please, take a look at the attached images - from the game start and the demo run. Any suggestions would be helpful.
Thanks!
SMB corrupted nametable at 0x2400
Moderator: Moderators
Re: SMB corrupted nametable at 0x2400
Does your emulator fail any CPU tests? List which ones fail.
EDIT: Just thought of something. Do you have correct mirroring for the nametables?
EDIT: Just thought of something. Do you have correct mirroring for the nametables?
Re: SMB corrupted nametable at 0x2400
This.Alegend45 wrote:Do you have correct mirroring for the nametables?
Re: SMB corrupted nametable at 0x2400
The CPU seems to be fine. It passes the nestest tests (with cycle precision).
The mirroring logic also seems fine to me. Here is a snippet
ant the actual read and write to the name tables:
The mirroring logic also seems fine to me. Here is a snippet
Code: Select all
public class NameTableMirroring {
public enum NameTableIndex {
A,
B,
C,
D
}
public enum NameTableMirroringType {
HORIZONTAL,
VERTICAL,
ONE_SCREEN_A,
ONE_SCREEN_B,
FOUR_SCREEN
}
public static int getNameTableOffset(int address) {
if (0x2000 <= address && address < 0x2400) {
return address - 0x2000;
} else if (0x2400 <= address && address < 0x2800) {
return address - 0x2400;
} else if (0x2800 <= address && address < 0x2C00) {
return address - 0x2800;
} else {
assert (0x2C00 <= address && address < 0x3000);
return address - 0x2C00;
}
}
public static NameTableIndex getNameTableIndex(int address, NameTableMirroringType mirroringType) {
if (mirroringType == NameTableMirroringType.HORIZONTAL) {
// Horizontal Mirroring:
// [0x2000, 0x23FF] -> NTA, [0x2400, 0x27FF] -> NTA
// [0x2800, 0x2BFF] -> NTB, [0x2C00, 0x2FFF] -> NTB
if (0x2000 <= address && address < 0x2400) {
return NameTableIndex.A;
} else if (0x2400 <= address && address < 0x2800) {
return NameTableIndex.A;
} else if (0x2800 <= address && address < 0x2C00) {
return NameTableIndex.B;
} else {
assert(0x2C00 <= address && address < 0x3000);
return NameTableIndex.B;
}
} else if (mirroringType == NameTableMirroringType.VERTICAL) {
// Vertical Mirroring:
// [0x2000, 0x23FF] -> NTA, [0x2400, 0x27FF] -> NTB
// [0x2800, 0x2BFF] -> NTA, [0x2C00, 0x2FFF] -> NTB
if (0x2000 <= address && address < 0x2400) {
return NameTableIndex.A;
} else if (0x2400 <= address && address < 0x2800) {
return NameTableIndex.B;
} else if (0x2800 <= address && address < 0x2C00) {
return NameTableIndex.A;
} else {
assert(0x2C00 <= address && address < 0x3000);
return NameTableIndex.B;
}
} else if (mirroringType == NameTableMirroringType.ONE_SCREEN_A) {
// One Screen Mirroring: All address points to the same data.
// [0x2000, 0x23FF] -> NTA, [0x2400, 0x27FF] -> NTA
// [0x2800, 0x2BFF] -> NTA, [0x2C00, 0x2FFF] -> NTA
// Enabled by a mapper usually.
return NameTableIndex.A;
} else if (mirroringType == NameTableMirroringType.ONE_SCREEN_B) {
// One Screen Mirroring: All address points to the same data.
// [0x2000, 0x23FF] -> NTB, [0x2400, 0x27FF] -> NTB
// [0x2800, 0x2BFF] -> NTB, [0x2C00, 0x2FFF] -> NTB
// Enabled by a mapper usually.
return NameTableIndex.B;
} else if (mirroringType == NameTableMirroringType.FOUR_SCREEN) {
// 4 screen Mirroring: Each addresses have their own memory space.
// Enable by a mapper usually.
// [0x2000, 0x23FF] -> NTA, [0x2400, 0x27FF] -> NTB
// [0x2800, 0x2BFF] -> NTC, [0x2C00, 0x2FFF] -> NTD
if (0x2000 <= address && address < 0x2400) {
return NameTableIndex.A;
} else if (0x2400 <= address && address < 0x2800) {
return NameTableIndex.B;
} else if (0x2800 <= address && address < 0x2C00) {
return NameTableIndex.C;
} else {
assert(0x2C00 <= address && address < 0x3000);
return NameTableIndex.D;
}
}
// Keep compiler silent
return NameTableIndex.A;
}
}
Code: Select all
@Override
public int readNameTable(int address, int[][] extNTRAM) {
NameTableIndex nameTableIndex = NameTableMirroring.getNameTableIndex(
address, getNameTableMirroringType());
int nameTableOffset = NameTableMirroring.getNameTableOffset(address);
return readNameTable(nameTableIndex, nameTableOffset, extNTRAM);
}
@Override
public void writeNameTable(int address, int value, int[][] extNTRAM) {
NameTableIndex nameTableIndex = NameTableMirroring.getNameTableIndex(
address, getNameTableMirroringType());
int nameTableOffset = NameTableMirroring.getNameTableOffset(address);
writeNameTable(nameTableIndex, nameTableOffset, value, extNTRAM);
}
protected NameTableMirroringType getNameTableMirroringType() {
return _cartridgeMirroringType;
}
protected int readNameTable(NameTableIndex nameTableIndex,
int nameTableOffset, int[][] extNTRAM) {
switch (nameTableIndex) {
case A: return extNTRAM[0][nameTableOffset];
case B: return extNTRAM[1][nameTableOffset];
case C: assert false; break; //TODO
case D: assert false; break; //TODO
}
return 0;
}
protected void writeNameTable(NameTableIndex nameTableIndex,
int nameTableOffset, int value, int[][] extNTRAM) {
switch (nameTableIndex) {
case A: extNTRAM[0][nameTableOffset] = value;
case B: extNTRAM[1][nameTableOffset] = value;
case C: assert false; break; //TODO
case D: assert false; break; //TODO
}
}
Re: SMB corrupted nametable at 0x2400
That looks relatively OK, but since the most bugs happen in scrolling, check your scrolling logic.
Re: SMB corrupted nametable at 0x2400
My first guess would be that you aren't properly delaying CHR/nametable reads through $2007, but that would have resulted in the titlescreen also being corrupted...
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
P.S. If you don't get this note, let me know and I'll write you another.
Re: SMB corrupted nametable at 0x2400
You seem to have a problem in your nametable mirrorring code. The game seems to be writing or reading to the same memory zone.
Other than that, I don't really see anything wrong with your code, but I think you really should revise it. You go to China and back just to write/read a single byte! Right now, not only it is very hard to follow, but it will hurt your performance, and if you want some level of accuracy, you will need all the speed you can get...
As an example, your public static int getNameTableOffset(int address) could be rewritten as:
Other than that, I don't really see anything wrong with your code, but I think you really should revise it. You go to China and back just to write/read a single byte! Right now, not only it is very hard to follow, but it will hurt your performance, and if you want some level of accuracy, you will need all the speed you can get...
As an example, your public static int getNameTableOffset(int address) could be rewritten as:
Code: Select all
public static int getNameTableOffset(int address) {
return (address & 0x3FF);
}Re: SMB corrupted nametable at 0x2400 [Solved]
Code: Select all
protected void writeNameTable(NameTableIndex nameTableIndex,
int nameTableOffset, int value, int[][] extNTRAM) {
switch (nameTableIndex) {
case A: extNTRAM[0][nameTableOffset] = value;
case B: extNTRAM[1][nameTableOffset] = value;
case C: assert false; break; //TODO
case D: assert false; break; //TODO
}
}