News: 11 March 2016 - Forum Rules
Current Moderators - DarkSol, KingMike, MathOnNapkins, Azkadellia, Danke

Author Topic: [Need help]6502 text routine (Saint Seiya 2)  (Read 2680 times)

yugisokubodai

  • Full Member
  • ***
  • Posts: 144
    • View Profile
    • Assembly
[Need help]6502 text routine (Saint Seiya 2)
« on: June 27, 2015, 08:17:12 am »
Hello, I’m just a newbie to 6502. I’m translating the game Saint Seiya Ougon no densetsu on the NES to my language. My language has many accents above the letters, such as â, ă, ấ…. But the NES tile is only 8x8 pixel, which is impossible to draw accent above these letters.
However, in the Japanese verison of the Rom, they uses the technique to display Dakuten (") and Handakuten (゜) above the Kanas. Like this

Code: [Select]
09=か
0A=き
0B=く
0C=け
0D=こ
0E=さ
0F=し
10=す
11=せ
12=そ
13=た
14=ち
15=つ
16=て
17=と
3B="
3C=゜

When 3B or 3C is after these characters, it will be displayed on the upper line of these Kanas.



Here you can see the dialogue box can display up to 4 rows, but the game actually uses 2 rows (2nd and 4th) to display the main text, and the remanining (1st and 3rd) are used to display Dakuten and Handakuten. Say, 13=た, 3B=゛so in the ROM, we have 13-3B, then it is displayed as だ on the screen, but in the PPU it looks like this:
Row 1: xxxxxxxx3B (゛)
Row2: xxxxxxxx13 (た)

So I want to copy the routine of these Handakuten and Dakuten (3C, 3B) to another tiles to display accents in my language. The concept is like this




The picture above is not excatly I did to the Rom, I just played round in the PPU to change the display.
I want to apply to the ROM, but hasn’t found the routine that display 3B and 3C one row upper than other letters yet.
The Dakuten (font) start at $213C0 in the Rom, or $1040 in the PPU.
 



I set a breakpoint on read/write at $13B0 in PPU, but the game didn’t snap when it display the Dakuten to the screen. I wonder why?
So the next step, I searched the pharse

そんなことをしているときでは (12-31-18-0D-17-30-0F-16-05-2C-17-0A-16-1D)
ありませんよ (04-2B-22-11-31-29)

And found it starts at $2089 in PPU. Then I set a breakpoint on write in PPU with the condition A==#12, the result looks like this

Code: [Select]
06:8FA2:A9 00     LDA #$00
06:8FA4:8D 41 06  STA $0641 = #$02
06:8FA7:85 EC     STA $00EC = #$FF
06:8FA9:4C 67 90  JMP $9067
06:8FAC:EE 41 06  INC $0641 = #$02
06:8FAF:EE 44 06  INC $0644 = #$89
06:8FB2:D0 D7     BNE $8F8B
06:8FB4:EE 45 06  INC $0645 = #$20
06:8FB7:D0 D2     BNE $8F8B
06:8FB9:AE 45 06  LDX $0645 = #$20 ;645: text position
06:8FBC:8E 06 20  STX $2006 = #$89
06:8FBF:AE 44 06  LDX $0644 = #$89
06:8FC2:8E 06 20  STX $2006 = #$89
06:8FC5:8D 07 20  STA $2007 = #$31
06:8FC8:EE 44 06  INC $0644 = #$89
06:8FCB:D0 03     BNE $8FD0
06:8FCD:EE 45 06  INC $0645 = #$20
06:8FD0:EE 41 06  INC $0641 = #$02
06:8FD3:20 30 90  JSR $9030

Meanwhile, the Dakuten starts at $2075 for the above sentence (sonna koto wo shiteiru toki dewa arimasen yo)
I set a break point on write at $2075 with the condition A==#3B to know where and when the 3B (code value for Dakuten) is written to $2075. But the game did not snap when it display the Dakuten. Why?
Can anybody explain to my why it didn’t snap? Where I get wrong?
What I have to do to find the routine that display 3B (゛) one row upper than the other code?


P/s: below are what I have known after playing around in the RAM

Code: [Select]
$CF: avatar graphic control
$580:delete displaying text, delete border: #$01: del 1st line, #$06: don't del after displaying
$640 in Ram: 02: write normal, 03: write from line 1+shift right
$641: 1st moji, 2nd moji.... (from 03~)
$642: text speed
$643: text speed 2?
$644: continous character postion X, (X+1)
$645: text postion, $20: upper dialogue box, $21: middle dialogue box, $22: lowe dialogue box
$646: <line> next postion position
$647: <line> next line postion
$693: text block ID?
$66A: text block ID?

KingMike

  • Forum Moderator
  • Hero Member
  • *****
  • Posts: 6894
  • *sigh* A changed avatar. Big deal.
    • View Profile
Re: [Need help]6502 text routine (Saint Seiya 2)
« Reply #1 on: June 27, 2015, 10:08:35 am »
Find where the text is stored in the ROM.
Set a CPU breakpoint for when the text is read from the ROM.
There's probably a routine that checks if the text is a dakuten value (like if 09 is ka, ga will probably be a different value, say 89). The routine is probably doing a check like if the text byte is above 80 (or whatever the start point of the dakuten character range is), then it adds the symbols. You will probably need to expand the routine (probably more to free space if you can find some) to include more checks for your language.
"My watch says 30 chickens" Google, 2018

yugisokubodai

  • Full Member
  • ***
  • Posts: 144
    • View Profile
    • Assembly
Re: [Need help]6502 text routine (Saint Seiya 2)
« Reply #2 on: June 27, 2015, 11:03:39 am »
The text starts at $3574A in the Rom. Strangely I can't find it in RAM.
Beside, $3574A is beyond $FFFF, how could the Cpu read from this address?

Disch

  • Hero Member
  • *****
  • Posts: 2717
  • NES Junkie
    • View Profile
Re: [Need help]6502 text routine (Saint Seiya 2)
« Reply #3 on: June 27, 2015, 11:22:28 am »
You had the right idea in your first post

Put a breakpoint on the PPU write -- use the trace logger to backtrack the code to find out where it's getting the value from.

Your problems were this:

- get rid of the breakpoint condition.  The game might be doing a STX, in which case A might be irrelevant.

- "I set a breakpoint on read/write at $13B0 in PPU,"   <-  $13B0 is the pattern tables  The game won't be writing there.  Nametables are between $2000-2FFF, that's where your breakpoint should be.  Look at the nametable viewer, hover over the tile in question, and it'll tell you the PPU address at the bottom of the window.

- If that still doesn't work, maybe the game is writing to the mirrored NT, so put a breakpoint on that one as well.

KingMike

  • Forum Moderator
  • Hero Member
  • *****
  • Posts: 6894
  • *sigh* A changed avatar. Big deal.
    • View Profile
Re: [Need help]6502 text routine (Saint Seiya 2)
« Reply #4 on: June 27, 2015, 03:46:25 pm »
The text starts at $3574A in the Rom. Strangely I can't find it in RAM.
Beside, $3574A is beyond $FFFF, how could the Cpu read from this address?
You have to understand what a mapper is.
It breaks the ROM into (usually) 16KB "banks". Most mappers "hardwire" (or permanently fix) the last 16KB of PRG-ROM to CPU $C000-FFFF (meaning if the PRG-ROM was $40000 bytes (excluding header), then $3C000-3FFFF of the ROM would equate to CPU $C000-FFFF.
(going again by what is typical of NES mappers) For the rest of the ROM, they would choose one 16KB ROM bank and map that into $8000-BFFF.
So if bank 3 was selected, ROM $C000-FFFF would be mapped to CPU $8000-BFFF.

Assuming a 16KB mapper (I haven't looked at which mapper your game uses. Look in FCEUX' Message Log window, then lookup the mapper info on nesdev.com)...
then take your address $3574A. Subtract $10 for the header. That gives $3573A.
Take the nearest lower multiple of $4000 to find the start of the ROM bank. That gives ROM $34000-37FFF. That means your text is $3573A-$34000 = $173A bytes into the ROM bank. So the CPU address would be $8000+$173A = $973A.
"My watch says 30 chickens" Google, 2018

yugisokubodai

  • Full Member
  • ***
  • Posts: 144
    • View Profile
    • Assembly
Re: [Need help]6502 text routine (Saint Seiya 2)
« Reply #5 on: June 27, 2015, 08:34:25 pm »
Thank you very much, King Mike.
I read Disch's document about Nes mapping and made it clear.
FCEUX says, the game uses mapper #1, MMC1 and 8 x 16KiB PRG ROM.
So 0x3574A is page $0D, and this offset is equivalent to address $973A in CPU. But actually, there's no text string at this address. I also set a break point on read at $973A, but it's no use.
Morever, if the string is in CPU, we could do a search for these hex value, it's simpler than doing the mapping calculation?
Actually, I searched the string in CPU but it's no use. The string only appears in ROM and PPU.

So I did a trace log and found things like below


Code: [Select]
$903A:AD 41 06  LDA $0641 = #$02           A:01 X:00 Y:00 S:EB P:nvUbdIzc
$903D:38        SEC                        A:02 X:00 Y:00 S:EB P:nvUbdIzc
$903E:E9 02     SBC #$02                   A:02 X:00 Y:00 S:EB P:nvUbdIzC
$9040:18        CLC                        A:00 X:00 Y:00 S:EB P:nvUbdIZC
$9041:65 D1     ADC $00D1 = #$7A           A:00 X:00 Y:00 S:EB P:nvUbdIZc
$9043:A8        TAY                        A:7A X:00 Y:00 S:EB P:nvUbdIzc
$9044:A5 D2     LDA $00D2 = #$08           A:7A X:00 Y:7A S:EB P:nvUbdIzc
$9046:69 00     ADC #$00                   A:08 X:00 Y:7A S:EB P:nvUbdIzc
$9048:8D 06 20  STA $2006 = #$00           A:08 X:00 Y:7A S:EB P:nvUbdIzc
$904B:8C 06 20  STY $2006 = #$00           A:08 X:00 Y:7A S:EB P:nvUbdIzc
$904E:AD 07 20  LDA $2007 = #$09           A:08 X:00 Y:7A S:EB P:nvUbdIzc
$9051:AD 07 20  LDA $2007 = #$18           A:09 X:00 Y:7A S:EB P:nvUbdIzc
$9054:60        RTS                        A:18 X:00 Y:7A S:EB P:nvUbdIzc

Code: [Select]
$8F8E:C9 3B     CMP #$3B                   A:18 X:00 Y:7A S:ED P:nvUbdIzc
$8F90:F0 4F     BEQ $8FE1                  A:18 X:00 Y:7A S:ED P:NvUbdIzc
$8F92:C9 3C     CMP #$3C                   A:18 X:00 Y:7A S:ED P:NvUbdIzc
$8F94:F0 4B     BEQ $8FE1                  A:18 X:00 Y:7A S:ED P:NvUbdIzc
$8F96:C9 01     CMP #$01                   A:18 X:00 Y:7A S:ED P:NvUbdIzc
$8F98:F0 12     BEQ $8FAC                  A:18 X:00 Y:7A S:ED P:nvUbdIzC
$8F9A:C9 A4     CMP #$A4                   A:18 X:00 Y:7A S:ED P:nvUbdIzC
$8F9C:F0 5F     BEQ $8FFD                  A:18 X:00 Y:7A S:ED P:nvUbdIzc
$8F9E:C9 FF     CMP #$FF                   A:18 X:00 Y:7A S:ED P:nvUbdIzc
$8FA0:D0 17     BNE $8FB9                  A:18 X:00 Y:7A S:ED P:nvUbdIzc
$8FB9:AE 45 06  LDX $0645 = #$20           A:18 X:00 Y:7A S:ED P:nvUbdIzc
$8FBC:8E 06 20  STX $2006 = #$7C           A:18 X:20 Y:7A S:ED P:nvUbdIzc
$8FBF:AE 44 06  LDX $0644 = #$89           A:18 X:20 Y:7A S:ED P:nvUbdIzc
$8FC2:8E 06 20  STX $2006 = #$7C           A:18 X:89 Y:7A S:ED P:NvUbdIzc
$8FC5:8D 07 20  STA $2007 = #$31           A:18 X:89 Y:7A S:ED P:NvUbdIzc
$8FC8:EE 44 06  INC $0644 = #$89           A:18 X:89 Y:7A S:ED P:NvUbdIzc
$8FCB:D0 03     BNE $8FD0                  A:18 X:89 Y:7A S:ED P:NvUbdIzc
$8FD0:EE 41 06  INC $0641 = #$02           A:18 X:89 Y:7A S:ED P:NvUbdIzc
$8FD3:20 30 90  JSR $9030                  A:18 X:89 Y:7A S:ED P:nvUbdIzc

Code: [Select]
$8FE1:AA        TAX                        A:3B X:8B Y:7D S:EF P:nvUbdIZC
$8FE2:AD 44 06  LDA $0644 = #$8C           A:3B X:3B Y:7D S:EF P:nvUbdIzC
$8FE5:38        SEC                        A:8C X:3B Y:7D S:EF P:NvUbdIzC
$8FE6:E9 21     SBC #$21                   A:8C X:3B Y:7D S:EF P:NvUbdIzC
$8FE8:A8        TAY                        A:6B X:3B Y:7D S:EF P:nVUbdIzC
$8FE9:AD 45 06  LDA $0645 = #$20           A:6B X:3B Y:6B S:EF P:nVUbdIzC
$8FEC:E9 00     SBC #$00                   A:20 X:3B Y:6B S:EF P:nVUbdIzC
$8FEE:8D 06 20  STA $2006 = #$7F           A:20 X:3B Y:6B S:EF P:nvUbdIzC
$8FF1:8C 06 20  STY $2006 = #$7F           A:20 X:3B Y:6B S:EF P:nvUbdIzC
$8FF4:8E 07 20  STX $2007 = #$05           A:20 X:3B Y:6B S:EF P:nvUbdIzC
$8FF7:EE 41 06  INC $0641 = #$05           A:20 X:3B Y:6B S:EF P:nvUbdIzC
$8FFA:4C 55 90  JMP $9055                  A:20 X:3B Y:6B S:EF P:nvUbdIzC
$9055:AD 37 06  LDA $0637 = #$1E           A:20 X:3B Y:6B S:EF P:nvUbdIzC
$9058:20 5B E5  JSR $E55B                  A:1E X:3B Y:6B S:EF P:nvUbdIzC
$E55B:8D 37 06  STA $0637 = #$1E           A:1E X:3B Y:6B S:ED P:nvUbdIzC
$E55E:8D FF BF  STA $BFFF = #$FF           A:1E X:3B Y:6B S:ED P:nvUbdIzC
$E561:4A        LSR                        A:1E X:3B Y:6B S:ED P:nvUbdIzC
$E562:8D FF BF  STA $BFFF = #$FF           A:0F X:3B Y:6B S:ED P:nvUbdIzc
$E565:4A        LSR                        A:0F X:3B Y:6B S:ED P:nvUbdIzc
$E566:8D FF BF  STA $BFFF = #$FF           A:07 X:3B Y:6B S:ED P:nvUbdIzC
$E569:4A        LSR                        A:07 X:3B Y:6B S:ED P:nvUbdIzC
$E56A:8D FF BF  STA $BFFF = #$FF           A:03 X:3B Y:6B S:ED P:nvUbdIzC
$E56D:4A        LSR                        A:03 X:3B Y:6B S:ED P:nvUbdIzC
$E56E:8D FF BF  STA $BFFF = #$FF           A:01 X:3B Y:6B S:ED P:nvUbdIzC
$E571:60        RTS                        A:01 X:3B Y:6B S:ED P:nvUbdIzC
$905B:AD 38 06  LDA $0638 = #$01           A:01 X:3B Y:6B S:EF P:nvUbdIzC
$905E:20 72 E5  JSR $E572                  A:01 X:3B Y:6B S:EF P:nvUbdIzC
$E572:8D 38 06  STA $0638 = #$01           A:01 X:3B Y:6B S:ED P:nvUbdIzC
$E575:8D FF DF  STA $DFFF = #$FF           A:01 X:3B Y:6B S:ED P:nvUbdIzC
$E578:4A        LSR                        A:01 X:3B Y:6B S:ED P:nvUbdIzC
$E579:8D FF DF  STA $DFFF = #$FF           A:00 X:3B Y:6B S:ED P:nvUbdIZC
$E57C:4A        LSR                        A:00 X:3B Y:6B S:ED P:nvUbdIZC
$E57D:8D FF DF  STA $DFFF = #$FF           A:00 X:3B Y:6B S:ED P:nvUbdIZc
$E580:4A        LSR                        A:00 X:3B Y:6B S:ED P:nvUbdIZc
$E581:8D FF DF  STA $DFFF = #$FF           A:00 X:3B Y:6B S:ED P:nvUbdIZc
$E584:4A        LSR                        A:00 X:3B Y:6B S:ED P:nvUbdIZc
$E585:8D FF DF  STA $DFFF = #$FF           A:00 X:3B Y:6B S:ED P:nvUbdIZc
$E588:60        RTS                        A:00 X:3B Y:6B S:ED P:nvUbdIZc


3B, 3C is the value for the Dakuten and Handakuten, while A4 is the line break code and FF is the end code, 01 is the code to draw space.

$8F8E:C9 3B     CMP #$3B
$8F90:F0 4F     BEQ $8FE1
$8F92:C9 3C     CMP #$3C
$8F94:F0 4B     BEQ $8FE1

$8F96:C9 01     CMP #$01
$8F98:F0 12     BEQ $8FAC
$8F9A:C9 A4     CMP #$A4
$8F9C:F0 5F     BEQ $8FFD
$8F9E:C9 FF     CMP #$FF
$8FA0:D0 17     BNE $8FB9 

So $8FE1 is the Dakuten routine I'm searching for?
The routine is some what difficult for a novice like me. So could anybody explain to me how to properly understand the $8FE1 rountine?
So far as I known:

$638: unknown.Can not be changed.
$637: unknown. Can not be changed.
$641: the value keeps increasing by 1, drawing letters after letters. If I freeze a value, it keeps drawing
the same letter forever.
$644: the value keeps increasing by 1. If I freeze a value, it keeps drawing letters one by obe at the same position.
$645: text postion. $20 for the upper dialogue box (boss character), $21 in the middle of the screen, $22 for the lower postion (main character)
$BFFF: unknown. Changed in Rom but no effect is visible.
$DFFF: unknown. Changed in Rom but no effect is visible.

KingMike

  • Forum Moderator
  • Hero Member
  • *****
  • Posts: 6894
  • *sigh* A changed avatar. Big deal.
    • View Profile
Re: [Need help]6502 text routine (Saint Seiya 2)
« Reply #6 on: June 27, 2015, 10:09:20 pm »
No wonder you can't do a CPU trace.
This game is weird and is storing the text IN CHR-ROM. As in, that is EXTREMELY unusual and I have NEVER seen it done before.
(when I was looking for an answer for you, I unknowingly looked at a prototype version. Which did store text in PRG-ROM like games NORMALLY do! :P )

Which means it has to read it into RAM. Okay, CHR-ROM bank size is 4KB (1KB) so that requires a read breakpoint on $073A or $173A (trial and error results in a hit on the former).
Which means it has to read the text from VROM into RAM.
"My watch says 30 chickens" Google, 2018

yugisokubodai

  • Full Member
  • ***
  • Posts: 144
    • View Profile
    • Assembly
Re: [Need help]6502 text routine (Saint Seiya 2)
« Reply #7 on: June 28, 2015, 12:04:02 pm »
Thanks to your help, I was able to arrange the routine and success with it.

Now a new problem arise, it's limitation of the text space. Is it possible to expand a NES Rom as we do for Snes rom?


June 29, 2015, 09:39:41 am - (Auto Merged - Double Posts are not allowed before 7 days.)
The game uses mapper #1 MMC1.
The original text block begins at $35010 in the Rom, and the first pointer value is 0000. This means we must subtract $35010 from the Rom offset to get the pointer value.

I used Nflate101 to expand the Rom. Now from 0x20000 to 0x40000 has a lot of space.

I want to move the text block to 0x20000 but now the original text block was moved to 0x55010, which means the base pointer is no longer $35010. How can I change the base pointer to make it point to 0x20000?

June 29, 2015, 09:40:12 am - (Auto Merged - Double Posts are not allowed before 7 days.)
The game uses mapper #1 MMC1.
The original text block begins at $35010 in the Rom, and the first pointer value is 0000. This means we must subtract $35010 from the Rom offset to get the pointer value.

I used Nflate101 to expand the Rom. Now from 0x20000 to 0x40000 has a lot of space.

I want to move the text block to 0x20000 but now the original text block was moved to 0x55010, which means the base pointer is no longer $35010. How can I change the base pointer to make it point to 0x20000?
« Last Edit: June 29, 2015, 09:40:12 am by yugisokubodai »

Guyver

  • Jr. Member
  • **
  • Posts: 40
  • =<O_O>=
    • View Profile
    • Chief-Net.ru
Re: [Need help]6502 text routine (Saint Seiya 2)
« Reply #8 on: June 29, 2015, 09:42:22 am »



On the Internet there is a Russian translation of the game. Hackers were able to solve two problems:

1. You can insert more text.
2. Added support for 4 lines of text.
« Last Edit: June 29, 2015, 09:52:12 am by Guyver »
I not the wizard, I only study...