Author
|
Topic: A Peculiar way of reading text on the NES (Read 2 times)
|
Kagemusha
Guest
|
|
« on: November 04, 2009, 02:58:33 pm » |
|
I've been trying to figure out how the text is read in a NES game. It appears that the game doesn't read text with a traditional method like straight from the PRG-ROM (or -RAM). Instead the text seems to be stored in the PPU (1300-13E0) and then read via the $2007 registers and then written to RAM. I've never dealt with anything like this before. Anyone know what's going on? Some code if anyone's interested. $A5A6:85 1C STA $001C = #$D0 A:E0 X:27 Y:3E P:NvUbdIzC $A5A8:AD 02 20 LDA $2002 = #$08 A:E0 X:27 Y:3E P:NvUbdIzC $A5AB:A5 1D LDA $001D = #$13 A:08 X:27 Y:3E P:nvUbdIzC $A5AD:8D 06 20 STA $2006 = #$00 A:13 X:27 Y:3E P:nvUbdIzC $A5B0:A5 1C LDA $001C = #$E0 A:13 X:27 Y:3E P:nvUbdIzC $A5B2:8D 06 20 STA $2006 = #$00 A:E0 X:27 Y:3E P:NvUbdIzC $A5B5:AD 07 20 LDA $2007 = #$00 A:E0 X:27 Y:3E P:NvUbdIzC $A5B8:A2 00 LDX #$00 A:00 X:27 Y:3E P:nvUbdIZC $A5BA:AD 07 20 LDA $2007 = #$00 A:00 X:00 Y:3E P:nvUbdIZC $A5BD:9D F0 04 STA $04F0,X @ $04F0 = #$9E A:00 X:00 Y:3E P:nvUbdIZC $A5C0:E8 INX A:00 X:00 Y:3E P:nvUbdIZC $A5C1:E0 10 CPX #$10 A:00 X:01 Y:3E P:nvUbdIzC $A5C3:D0 F5 BNE $A5BA A:00 X:01 Y:3E P:NvUbdIzc $A5BA:AD 07 20 LDA $2007 = #$A4 A:00 X:01 Y:3E P:NvUbdIzc $A5BD:9D F0 04 STA $04F0,X @ $04F1 = #$7B A:A4 X:01 Y:3E P:NvUbdIzc $A5C0:E8 INX A:A4 X:01 Y:3E P:NvUbdIzc $A5C1:E0 10 CPX #$10 A:A4 X:02 Y:3E P:nvUbdIzc $A5C3:D0 F5 BNE $A5BA A:A4 X:02 Y:3E P:NvUbdIzc $A5BA:AD 07 20 LDA $2007 = #$B6
|
|
|
|
KingMike
Guest
|
|
« Reply #1 on: November 04, 2009, 04:34:56 pm » |
|
They ran out of room in PRG?
I know that others have said SMB stored the title screen data in CHR.
|
|
|
|
Kagemusha
Guest
|
|
« Reply #2 on: November 04, 2009, 04:40:22 pm » |
|
Well, the game's PRG is 128KB, which might not be enough for an RPG, but I dunno. If it's indeed in the stored in the CHR, how do pointers work for something like that?
|
|
|
|
rveach
Guest
|
|
« Reply #3 on: November 04, 2009, 06:07:11 pm » |
|
I have seen a few games use the CHR to hold actual data instead of graphics. It's nothing new. $A5AB:A5 1D LDA $001D = #$13 A:08 X:27 Y:3E P:nvUbdIzC $A5AD:8D 06 20 STA $2006 = #$00 A:13 X:27 Y:3E P:nvUbdIzC $A5B0:A5 1C LDA $001C = #$E0 A:13 X:27 Y:3E P:nvUbdIzC $A5B2:8D 06 20 STA $2006 = #$00 A:E0 X:27 Y:3E P:NvUbdIzC
these lines position the VRAM to the position ($1C) (#13E0 in this case) ($1C) = $1D$1C = #13#E0 = #13E0
$A5B5:AD 07 20 LDA $2007 = #$00 A:E0 X:27 Y:3E P:NvUbdIzC
read and ignore garbage data (when reading $2007, the data you want always starts on the SECOND read)
$A5B8:A2 00 LDX #$00 A:00 X:27 Y:3E P:nvUbdIZC $A5BA:AD 07 20 LDA $2007 = #$00 A:00 X:00 Y:3E P:nvUbdIZC $A5BD:9D F0 04 STA $04F0,X @ $04F0 = #$9E A:00 X:00 Y:3E P:nvUbdIZC $A5C0:E8 INX A:00 X:00 Y:3E P:nvUbdIZC
read VRAM and store it into $04F0 array. Any read to $2007 will automatically increase the VRAM position by 1 or #20 (based on the value written to $2000), so you don't need to redo writes to $2006.
$A5C1:E0 10 CPX #$10 A:00 X:01 Y:3E P:nvUbdIzC $A5C3:D0 F5 BNE $A5BA A:00 X:01 Y:3E P:NvUbdIzc
branch while X <> #10
so when this is done, the first 16 bytes in the VRAM at ($1C) will be copied to $04F0.
|
|
|
|
KingMike
Guest
|
|
« Reply #4 on: November 04, 2009, 07:47:20 pm » |
|
Well, the game's PRG is 128KB, which might not be enough for an RPG, but I dunno. If it's indeed in the stored in the CHR, how do pointers work for something like that?
Since $1C-1D is used to set $2006 (VRAM read/write address register), trace and figure out how the data in $1C/1D got there.
|
|
|
|
aishsha
Guest
|
|
« Reply #5 on: November 04, 2009, 08:06:47 pm » |
|
Well, the game's PRG is 128KB, which might not be enough for an RPG, but I dunno. If it's indeed in the stored in the CHR, how do pointers work for something like that?
Since $1C-1D is used to set $2006 (VRAM read/write address register), trace and figure out how the data in $1C/1D got there. It's Minelvaton Saga, if anyone is interested. Pennywise is helping me with the pointers to find a possibility to avoid huffman or any other compression 'cause free space in that game is practically none. But yeah, the text seems to be stored in CHR alongside with graphics and code, so no direct pointers this time. Moreover, as I remember those 1c-1d, the value just jumps between them and 2006 port... And the mapper seems to allow expansion of both PRG and CHR, so I have no idea why they did it this way...
|
|
|
|
KingMike
Guest
|
|
« Reply #6 on: November 04, 2009, 08:35:14 pm » |
|
And the mapper seems to allow expansion of both PRG and CHR, so I have no idea why they did it this way...
Bigger ROM chips not within their budget?
|
|
|
|
rveach
Guest
|
|
« Reply #7 on: November 05, 2009, 08:49:19 am » |
|
trace and figure out how the data in $1C/1D got there.
If you look at the first line in his dump, it is a store to $1C, so he won't have to look far. Just some tid-bits for you guys working on 'Minelvaton Saga'. It is Mapper 80, find a document on this mapper so you can understand its registers and how the CHR swapping works. $7EF0-$7EF5 are your CHR registers. $7EFA-$7EFF are your PRG registers. Also, this game uses a easy custom pointer format, and it seems all the pointers are hardcoded (in a way) into the assembly, so you may have to do some searching if you want to change their values.
|
|
« Last Edit: November 05, 2009, 09:19:26 am by rveach »
|
|
|
|
DvD
Guest
|
|
« Reply #8 on: November 06, 2009, 01:05:35 am » |
|
Pennywise,
Everything everyone is saying here is correct, except replace the word VRAM with VROM. There would be no reason to store text in VRAM, because... well, you'd have to copy it to the VRAM from some ROM somewhere. And, in this case, M. Saga has VROM not VRAM.
|
|
|
|
|