3DS reverse engineering

Discussion of development of software for any "obsolete" computer or video game system.
nocash
Posts: 1200
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Sat Mar 14, 2020 5:46 pm

profi200 wrote:
Sat Mar 14, 2020 5:31 am
I looked at P9 (and i really don't like looking at P9 code since it's just disgusting). For ROM read it looks like it's using a faster clock than what i use.
The final CNT value seems to be 0xD104822C. I'm not sure if this was choosen because of data corruption (another long standing issue) or just copy & paste. And not sure if this is actually clock or just a delay.
I guess that P9 is the firmware's ARM9 code... Hmm, oddly, they are using value 7 as slowest setting in bit24-26 (so values 5 and 6 would be reserved, and 7 being the "offically used" setting for slow clocks) (then on the other hand, I would bet that their hardware designer had intended value 0..5 to be used). The 2Ch in the timeout field is funny, I could see a reason for setting bit5 (to not discard old error bits), but it makes no sense when not even having timeout checks enabled in bit6. Looks like a bug. Unless the old 3DS registers did work differently than my New3DS hardware.

Going by my comparision of 4-byte reads and 2000h-byte reads, bit24-26 are definetly behaving like a per-byte-clock selection.
The bits don't control a delay before or between data blocks. For those delays it would be interesting if sixteen 200h-byte reads are slower than one 16x200h-byte read (with sixteen blocks selected in CTRCARD_BLKCNT). Quite possible that the latter is faster when reading from sequential addresses.
profi200 wrote:
Sat Mar 14, 2020 5:31 am
You are not turning on the data cache. It makes a huge difference if i recall correctly.
And this directly from the ARM TRM: 2.3.5. Register 1, Control Register
Thanks, it's been 10 years since I looked at ARM9 specs. I was a bit surprised when realizing that ARM11 could use code cache without PU/MMU (and then I had assumed that ARM9 could do the same). Okay, I've now enabled the PU with a large 4GB dummy region that enables code cache everywhere... and my ARM9 code is now running much faster : )

Yeah, data cache could be nice, but it would require more originazation of what is cached, and what isn't. For my hacky hardware tests, it's more important to be able to access stuff in uncached memory from either CPU. And data caching isn't so important for ASM code anyways (where all critical code is using cpu registers instead of variables).
profi200 wrote:
Sat Mar 14, 2020 5:31 am
What makes you think they are before VCC goes high?
Mostly common sense: If the power on function is executed after card insert detection, then the power cannot be switched on before card insert detection.
The card VCC pin is switched on (or otherwise, pulled low) by the two transistors seen at the bottom of larger snippet in middle/right of this picture: http://problemkaputt.de/twl-core.jpg (ie. card VCC can be switched by software, it isn't just directly wired to supply VCC, I haven't tested which of the two steps in the power on function is activating VCC though).
profi200 wrote:
Sat Mar 14, 2020 5:31 am
For completeness sake the last (software) delay on slot poweron is 270 ms in P9.
That is potentially the only relevant delay (might be needed if a card needs to "boot up" before accepting commands, but I wouldn't spend 270ms on waiting for such crap, too). On the DSi, it was "only" 120ms. But knowing Nintendo, it does make perfect sense that they think that newer hardware must use better and more powerful delays ; )
homepage - patreon - you can think of a bit as a bottle that is either half full or half empty

nocash
Posts: 1200
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Sun Mar 15, 2020 8:59 am

I am just starting to look at the YUV-to-RGB converter registers. With info from 3dbrew, they should work somewhat as so:

Code: Select all

Y2R Registers (aka YUV-to-RGB)
  Address    Width Old3DS  Name
  10102000h  4     Yes   Y2R_PARAMS                  R/W: E8C31F07h ;\
  10102004h  2     Yes   Y2R_LINEW ;width?           R/W: 03F8h     ;
  10102006h  2     Yes   Y2R_LINES ;height?          R/W: 03FFh     ; Control
  10102010h  2     Yes   Y2R_COEFFICIENT_Y_A  ;uh?   R/W: 03FFh     ; Regs
  10102012h  2     Yes   Y2R_COEFFICIENT_R_V  ;red   R/W: 03FFh     ;
  10102014h  2     Yes   Y2R_COEFFICIENT_G_x  ;green R/W: 03FFh     ;
  10102016h  2     Yes   Y2R_COEFFICIENT_G_x  ;green R/W: 03FFh     ;
  10102018h  2     Yes   Y2R_COEFFICIENT_B_U  ;blue  R/W: 03FFh     ;
  1010201Ah  2     Yes   Y2R_COEFFICIENT_R_offset    R/W: FFFFh     ;
  1010201Ch  2     Yes   Y2R_COEFFICIENT_G_offset    R/W: FFFFh     ;
  1010201Eh  2     Yes   Y2R_COEFFICIENT_B_offset    R/W: FFFFh     ;
  10102020h  2     Yes   Y2R_ALPHA                   R/W: 000000FFh ;
  10102100h  4     Yes   Y2R_???       ;\            R/W: 0000CCCCh ;
  10102108h  4     Yes   Y2R_???       ; maybe       R/W: 0000CCCCh ;
  10102110h  4     Yes   Y2R_???       ; dither?     R/W: 0000CCCCh ;
  10102118h  4     Yes   Y2R_???       ;/            R/W: 0000CCCCh ;/
  10302000h  80h?  Yes   Y2R_INPUT_Y                                ;\
  10302080h  80h?  Yes   Y2R_INPUT_U                                ; DMA
  10302100h  80h?  Yes   Y2R_INPUT_V                                ; region
  10302180h  80h?  Yes   Y2R_INPUT_X?         ;uh?                  ; (ARM11)
  10302200h  80h?  Yes   Y2R_OUTPUT_RGB                             ;/

10102000h - Y2R_PARAMS
  0-2   Input Format YUV (0-4 = 422'8, 420'8, 422'16, 420'16, 422'BATCH)  (R/W)
  3-7   Unused (0)                                                        (-)
  8-9   Output Format A:R:G:B   (0-3 = 8:8:8:8, 0:8:8:8, ?:5:5:5, 0:5:6:5)(R/W)
  10-11 Output Clockwise Rotate (0-3 = None, 90', 180', 270')             (R/W)
  12    Output Block Alignment  (0=LinearFramebuf, 1=MortonSwizzleTexture)(R/W)
  13-14 Unused (0) ?                                                      (-)
  15    ?                                                                 (-)
  16    !! ?                             (?)                              (R/W)
  17    !! ?                             (?)                              (R/W)
  18-20 Unused (0) ?                                                      (-)
  21    ?                                                                 (-)
  22    !! ?                             (?)                              (R/W)
  23    unknown/unspecified, R/W         (?)                              (R/W)
  24    ?                                                                 (-)
  25    ?                                                                 (-)
  26    ?                                                                 (-)
  27    !! ?                             (?)                              (R/W)
  28    ?                                                                 (-)
  29    !! ?                             (?)                              (R/W)
  30    Transfer end interrupt      ;maybe interrupt enable?              (R/W)
  31    Enable/Busy                                                       (R/W)
there should be a 2bit "StandardCoefficient" setting
and maybe flags for dither-enable, or signed/unsigned input, etc.
and maybe status for fifo(s)?
There are still dozens of question marks. And some general unknown things... what is a BATCH (the camera format?), what are the standard coefficients, and are they signed/unsigned, and how does the rotation work... rotating 8x8 or 16x16 pixel tiles should be possible, but the camera does usually output scanlines instead of tiles, that data format would make rotation more or less impossible. With jpeg/mpeg in mind, there might be also zigzag input-reordering, or even DC/AC stuff.

There's probably still lots of testing needed to figure out all bits and functions, but if some details are already known would be cool!
homepage - patreon - you can think of a bit as a bottle that is either half full or half empty

nocash
Posts: 1200
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Sun Mar 15, 2020 4:19 pm

Bit 24-28 seem to be data requests for the five input/output register areas. So the control register does now look as so:

Code: Select all

10102000h - Y2R_PARAMS
  0-2   Input Format YUV (0-4 = 422'8, 420'8, 422'16, 420'16, 422'BATCH)  (R/W)
  3-7   Unused (0)                                                        (-)
  8-9   Output Format A:R:G:B   (0-3 = 8:8:8:8, 0:8:8:8, ?:5:5:5, 0:5:6:5)(R/W)
  10-11 Output Clockwise Rotate (0-3 = None, 90', 180', 270')             (R/W)
  12    Output Block Alignment  (0=LinearFramebuf, 1=MortonSwizzleTexture)(R/W)
  13-14 Unused (0) ?                                                      (-)
  15    ?                                                                 (-)
  16    !! ?                             (?)                              (R/W)
  17    !! ?                             (?)                              (R/W)
  18-20 Unused (0) ?                                                      (-)
  21    ?                                                                 (-)
  22    !! ?                             (?)                              (R/W)
  23    unknown/unspecified, R/W         (?)                              (R/W)
  24    Input DRQ Y?             (0=No, 1=DRQ) (write 1 to ack)        (R/ack?)
  25    Input DRQ U?             (0=No, 1=DRQ) (write 1 to ack)        (R/ack?)
  26    Input DRQ V?             (0=No, 1=DRQ) (write 1 to ack)        (R/ack?)
  27    Input DRQ YUYV (batch?)  (0=No, 1=DRQ) (write 1 to ack)        (R/ack?)
  28    Output DRQ RGB           (0=No, 1=DRQ) (write 1 to ack)        (R/ack?)
  29    !! ?                             (?)                              (R/W)
  30    Transfer end interrupt      ;maybe interrupt enable?              (R/W)
  31    Enable/Busy                                                       (R/W)
What is weird is that it seems to be required to manually acknowledge the data requests (ie. write 80h-bytes to the INPUT field, AND write a 1 to the DRQ bit).
It's probably impossible to do that via CDMA, but CDMA seems to have some support for handshaking, so it might work automatically there without needing manual acknowledges.

What they have called INPUT_X and BATCH format seems to be YUYV format (two pixels with separate Y, and shared U/V values; ie. the default format for DSi camera scanlines).
homepage - patreon - you can think of a bit as a bottle that is either half full or half empty

nocash
Posts: 1200
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Mon Mar 16, 2020 2:51 pm

Usually the DRQs stay set forever (once when the 1st request has occurred), it seems to be possible to acknowledge them via writes, but I haven't really figured out how to make use of that feature. There is also a hidden feature with similar effects: Doing a dummy read or write to address 10102008h, but I haven't figured out how to make use of that, too.

Basically, that DRQ bits are somewhat useless... the conversion works best when completely ignoring them. The one thing that was useful about them was observing that the output/reponse DRQ gets set after writing NINE scanlines. That means that the 'FIFOs' are really huge, several kilobytes (eg. enough for 320*2*9 bytes for nine camera scanlines at 320 pixels with 2 bytes per pixel) (and probably even more bytes for other YUV formats and resolutions).

To get the data transferred, after many tries, I found this to be working: Send ONE scanline. Then repeatedly send+receive blocks with EIGHT scanlines. Everything else seems to result in weird effects with lost left-most pixels, and/or an 8-line-block at top (or near top) of image getting lost, etc.

The output format is RGBA, in that order, with Alpha in lower bit(s). For the RGBA=5551 format, alpha is taken from bit7 of the alpha register.
The three "coefficient offsets" seem to be signed. And I think that all other parameters & data are unsigned.
With 320pix camera scanlines, rotate 180 does rotate each 320x8 pixel block. But rotate 90 or 270 are randomly reordering pixles, maybe treating them as 8x8 pixels blocks instead of 320 pixel scanlines.
homepage - patreon - you can think of a bit as a bottle that is either half full or half empty

profi200
Posts: 44
Joined: Fri May 10, 2019 4:48 am

Re: 3DS reverse engineering

Post by profi200 » Tue Mar 17, 2020 5:33 am

Ok, i have checked the clock used for gamecard ROM reading. Code was the exact code i linked in my gist:

Image
So bit 24-26 does control the clock. Note that the result is not as accurate as a scope as i mentioned above.

nocash
Posts: 1200
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Tue Mar 17, 2020 7:06 am

Looks like the slowest CTRCARD setting with 67.027964MHz/16 = circa 4.2MHz.
Ooops, in an earlier post, I had described it as "67.027964MHz/4 = 4.2MHz" (that was of course meant to be saying /16, not /4).

Y2R_PARAMS.bit16 is Dither enable (and register 101021xxh allow to specify a 4x4 pixel dither pattern). The dither is visible at 5bit color depth, at 8bit depth it is rather not visible (don't know if dither is supported for that at all).

For the Y2R_COEFFICIENTs, the standard YUV/YCbCr to RGB formula is:

Code: Select all

  R = Y+(Cr-80h)*1.402
  G = Y-(Cr-80h)*0.714)-(Cb-80h)*0.344
  B = Y+(Cb-80h)*1.772
So I have tried these settings:

Code: Select all

 ldr  r0,=100h*1000/1000   // strh r0,[r9,REG_Y2R_COEFFICIENT_Y_TO_RGB] ;R/W: 03FFh
 ldr  r0,=100h*1402/1000   // strh r0,[r9,REG_Y2R_COEFFICIENT_V_TO_R]   ;R/W: 03FFh
 ldr  r0,=100h*0714/1000   // strh r0,[r9,REG_Y2R_COEFFICIENT_V_TO_G]   ;R/W: 03FFh
 ldr  r0,=100h*0344/1000   // strh r0,[r9,REG_Y2R_COEFFICIENT_U_TO_G]   ;R/W: 03FFh
 ldr  r0,=100h*1772/1000   // strh r0,[r9,REG_Y2R_COEFFICIENT_U_TO_B]   ;R/W: 03FFh
The result looks more or less okay (but, using camera input, it's hard to say how each color should look like exactly, but at least red comes out as red).
For the purpose of the variable parameters: There seem to be other formulas with different constants (dunno if those would be used/useful for 3ds). And one could intentionally calibrate the values to get a more pale or more colorful picture. And one could swap the U/V coefficients (and U/V inputs) to change RGBA to BGRA order (if there should be any reason for doing that).

But, those coefficients do still look all wrong without the offset values. Using offset -1000h,+1000h,-1000h does look roughly okay. My current theory is that they "forgot" to subtract 80h from the U,V values before multiplication, and they do instead need to subtract 80h*coefficient after multiplication. So I have tried this:

Code: Select all

 ldr  r0,=-1000h*(1402)/1000      // strh r0,[r9,REG_Y2R_COEFFICIENT_R_OFFSET]   ;R/W: FFFFh
 ldr  r0,=+1000h*(0714+0344)/1000 // strh r0,[r9,REG_Y2R_COEFFICIENT_G_OFFSET]   ;R/W: FFFFh
 ldr  r0,=-1000h*(1772)/1000      // strh r0,[r9,REG_Y2R_COEFFICIENT_B_OFFSET]   ;R/W: FFFFh
That does also look okay, but it's mostly a guess. For more exact results it would be better to write a jpeg decoder and compare the output with a PC screen. Or to send test values to the inputs, and verify the numeric output instead of just gazing at pixel colors. Or to look at nintendo's official code to see what values they are using for coefficients and offsets.

I have renamed some of the coefficient, dither, and input registers. They are now named as so:

Code: Select all

  10102000h  4     Y2R_PARAMS                  R/W: E8C31F07h ;\
  10102004h  2     Y2R_LINEW   ;width (pix)    R/W: 03F8h     ;
  10102006h  2     Y2R_LINES   ;height (pix)   R/W: 03FFh     ;
  10102008h  ??    Y2R_STROBE  ;ack fifo?      dummy r/w?     ;
  10102010h  2     Y2R_COEFFICIENT_Y_TO_RGB    R/W: 03FFh     ; Control
  10102012h  2     Y2R_COEFFICIENT_V_TO_R      R/W: 03FFh     ; Regs
  10102014h  2     Y2R_COEFFICIENT_V_TO_G      R/W: 03FFh     ;
  10102016h  2     Y2R_COEFFICIENT_U_TO_G      R/W: 03FFh     ;
  10102018h  2     Y2R_COEFFICIENT_U_TO_B      R/W: 03FFh     ;
  1010201Ah  2     Y2R_COEFFICIENT_R_OFFSET    R/W: FFFFh     ; ;\
  1010201Ch  2     Y2R_COEFFICIENT_G_OFFSET    R/W: FFFFh     ; ; signed
  1010201Eh  2     Y2R_COEFFICIENT_B_OFFSET    R/W: FFFFh     ; ;/
  10102020h  2     Y2R_ALPHA  ;bit7 for 5551   R/W: 000000FFh ;
  10102100h  4     Y2R_DITHER0                 R/W: 0000CCCCh ;
  10102108h  4     Y2R_DITHER1                 R/W: 0000CCCCh ;
  10102110h  4     Y2R_DITHER2                 R/W: 0000CCCCh ;
  10102118h  4     Y2R_DITHER3                 R/W: 0000CCCCh ;/
  10302000h  80h   Y2R_INPUT_Y    ;Y aka luminance            ;\
  10302080h  80h   Y2R_INPUT_U    ;Cb aka U                   ; DMA
  10302100h  80h   Y2R_INPUT_V    ;Cr aka V                   ; region
  10302180h  80h   Y2R_INPUT_YUYV ;Y1,U,Y2,V camera scanlines ; (ARM11)
  10302200h  80h   Y2R_OUTPUT_RGB                             ;/
The 80h-byte INPUTs are actually mirrored all across those 80h-byte areas (but that's ways too small for sending several scanlines, so it's better to write to fixed 4-byte locations instead of using increasing addresses in those 80h-byte windows).

The params are now:

Code: Select all

10102000h - Y2R_PARAMS
  0-2   Input Format YUV (0-4 = 422'8, 420'8, 422'16, 420'16, 422'BATCH)  (R/W)
  3-7   Unused (0)                                                        (-)
  8-9   Output Format R:G:B:A   (0-3 = 8:8:8:8, 8:8:8:0, 5:5:5:1, 5:6:5:0)(R/W)
  10-11 Output Clockwise Rotate (0-3 = None, 90', 180', 270')             (R/W)
  12    Output Block Alignment  (0=LinearFramebuf, 1=MortonSwizzleTexture)(R/W)
  13-14 Unused (0)                                                        (-)
  15    Unknown, reportedly used, but always 0 (maybe write-only?)        (?)
  16    Dither Enable           (0=Off, 1=Use Y2R_DITHER0-3)              (R/W)
  17    unknown/undescribed, R/W         (?)                              (R/W)
  18-20 Unused (0)                                                        (-)
  21    Unknown, reportedly used, but always 0 (maybe write-only?)        (?)
  22    unknown/undescribed, R/W         (?)                              (R/W)
  23    unknown/unspecified, R/W         (?)                              (R/W)
  24    Input DRQ Y?                   (0=No, 1=DRQ) (write 1 to ack?) (R/ack?)
  25    Input DRQ U?                   (0=No, 1=DRQ) (write 1 to ack?) (R/ack?)
  26    Input DRQ V?                   (0=No, 1=DRQ) (write 1 to ack?) (R/ack?)
  27    Input DRQ YUYV (batch?)        (0=No, 1=DRQ) (write 1 to ack?) (R/ack?)
  28    Output DRQ RGB, 9th input line (0=No, 1=DRQ) (write 1 to ack?) (R/ack?)
  29    unknown/undescribed, R/W         (?)                              (R/W)
  30    Transfer end interrupt      ;maybe interrupt enable?              (R/W)
  31    Start/Busy                     (0=Idle/Ready, 1=Start/Busy)       (R/W)
There are still four unknown R/W bits (and two further reportedly-unknown bits; which might be write-only, or don't exist at all).
None of those bits seems to have visible effects. At least not when using the camera/batch/YUYV input mode. One or two bits might be DMA enable. Any idea what the remaining bits could be good for?
homepage - patreon - you can think of a bit as a bottle that is either half full or half empty

nocash
Posts: 1200
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Tue Mar 17, 2020 4:01 pm

Roughly related, I've had another look at the "MVD" registers. There are three register blocks. The block with Y2R is simple:

Code: Select all

10132000h - New3DS: Movie Decoder or so? Y2R Registers
10332000h - New3DS: Movie Decoder or so? Y2R FIFOs
These are same as the old Y2R unit at 10102000h, see above posts.
The R/W masks are same as for the old Y2R unit. And I've changed my test code to output the camera picture via the MVD-Y2R unit instead of the old Y2R unit, and it worked without problems.

Then there is this, it does also look very simple (in fact so simple that I couldn't imagine what it could be good for):

Code: Select all

10130000h - New3DS: Movie Decoder or so? whatever...?
10131000h - New3DS: Movie Decoder or so? whatever...? same as above...?
  10130000h 4    R/W  e1c00303h  MVD Registers Control? bit24=DRQ(readonly)?
  10130004h 4    R/W  03f803f8h  MVD Registers Width/Height?
  10130008h 18h  -    00000000h  MVD Registers -
  10130020h 4    R/W  000000ffh  MVD Registers Alpha maybe?
  10130024h FDCh -    00000000h  MVD Registers -
Unknown, the Control/Width/Height/Alpha? settings resemble those of the Y2R 
units, but without Coefficients. And unknown, if/where any FIFOs do exist
(10330000h triggers data abort, so they don't seem to be there, unless they
need to be enabled somehow) (being read-only or write-only, they might be
anywhere at 10130xxxh though).
I don't know. It might be an I/O interface for streaming data to the MVD unit, with control registers located elsewhere. Or it is something more trivial that has it's own purpose... Just guessing: Maybe something for blending two source bitmaps to a destination bitmap? Or maybe two RGB to RGBA converters ; ) or well, that might be actually slightly useful, if it could convert between 5bit and 8bit RGB values, and/or convert between scanlines and 8x8pix tiles.

Hmmmm, looking at 3dbrew DMA descriptions, there are four ominous "MVD L2B" dma channels. Maybe the above are those L2Bs?
Whatever that is... a level 2 cache dma channel?? Or, if Y2R is short for YUV-to-RGB, then L2B might be short for Lomething-to-Bomething??


With those abbreviations, the 3dbrew people could at least take the time to say,
If you don't know what L2B means then you shouldn't be reading this (and, no, we don't know what it means either).
As it is now, I couldn't tell if half of the 3dbrewers are arrogant assholes or arrogant idiots... or if I am an arrogant asshole & idiot myself : /
Either way, abbreviations can be frustating!

And finally this stuff:

Code: Select all

0207000h - New3DS: Movie Decoder or so? Rockchip...?
  10207000h 4    R    67312398h  MVD Registers Chip ID?
  10207004h C4h  R/W  ffffffffh  MVD Registers
  102070C8h 4    R    07b4af80h  MVD Registers
  102070CCh 4    R/W  ffffffffh  MVD Registers
  102070D0h 4    -    00000000h  MVD Registers
  102070D4h 4    -    00000000h  MVD Registers
  102070D8h 4    R    c09a0000h  MVD Registers
  102070DCh 4    R/W  ffffffffh  MVD Registers
  102070E0h 4    -    00000000h  MVD Registers
  102070E4h 4    R    8516ffffh  MVD Registers
  102070E8h 4    -    00000000h  MVD Registers
  102070ECh 40h  R/W  ffffffffh  MVD Registers
  1020712Ch 4    -    00000000h  MVD Registers
  10207130h 4    -    00000000h  MVD Registers
  10207134h 4    -    00000000h  MVD Registers
  10207138h 4    -    00000000h  MVD Registers
  1020713Ch 44h  R/W  ffffffffh  MVD Registers
  10207180h 4    -    00000000h  MVD Registers
  10207184h 4    -    00000000h  MVD Registers
  10207188h 4    -    00000000h  MVD Registers
  1020718Ch 4    R    ffffffffh  MVD Registers
  10207190h 4    R    ff874780h  MVD Registers
  10207194h 6Ch  -    00000000h  Zerofilled
  10207200h E00h Mirrors of above 200h byte area
The ID value 67312398h appears to be known as "HW_ID" for linux/android "VPU SERVICES". Searching for that two strings gives this source code,
http://git.jp.linux-rockchip.org/cgit/r ... _service.c
which defines VPU_DEC_ID_9190=6731h (the upper 16bit of the 67312398h value), so the "MVD" might be identical to that Rockchip hardware (whatever that is).

I guess that's one of the cases where one could say:
Hey cool it's all open source, but if anybody understands the source code? Probably not. But that isn't the point about freedom of information, or is it?
If there are any die-hard open source enthusiasts here, please convince me, and tell me where to find the address map for the memory mapped I/O ports in the source code file(s)!
homepage - patreon - you can think of a bit as a bottle that is either half full or half empty

profi200
Posts: 44
Joined: Fri May 10, 2019 4:48 am

Re: 3DS reverse engineering

Post by profi200 » Thu Mar 19, 2020 8:11 am

nocash wrote:
Tue Mar 17, 2020 4:01 pm
With those abbreviations, the 3dbrew people could at least take the time to say,
If you don't know what L2B means then you shouldn't be reading this (and, no, we don't know what it means either).
As it is now, I couldn't tell if half of the 3dbrewers are arrogant assholes or arrogant idiots... or if I am an arrogant asshole & idiot myself : /
Either way, abbreviations can be frustating!
Or you could actually be thankful for the countless of hours spent by people over years + contribute back and add your findings to 3dbrew instead of publishing them exclusively on your site without proper diffs. Do you realize how rude of you it is to say this? Without 3dbrew and the community you would have to start completely from scratch and you would not even have code execution right now.
I explained to you some pages ago, that the writers of the documentation didn't invent some of the names but they often come from strings, symbols or elsewhere.

I wanted to be a nice guy and help you a bit but i'm not sure i want that anymore.

nocash
Posts: 1200
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Thu Mar 19, 2020 8:51 am

The L2B registers (or what they are called) are really "RGB-to-RGBA converters" (without additional swizzling and bit-depth conversion), working unrelated of the MVD registers.

Code: Select all

10130000h - New3DS - L2B_1 - First RGB-to-RGBA converter (New3DS only)
10131000h - New3DS - L2B_2 - Second RGB-to-RGBA converter (New3DS only)
  10130000h/10131000h 4     L2B_CNT     Control  R/W  e3c00303h
  10130004h/10131004h 2     L2B_WIDTH   Width    R/W  03f8h
  10130006h/10131006h 2     L2B_HEIGHT  Height   R/W  03f8h
  10130020h/10131020h 4     L2B_ALPHA   Alpha    R/W  000000ffh
  10330000h/10331000h 1000h L2B_FIFO (IN and OUT, empty=data_abort) (R+W)
Similar to the YUV-to-RGBA converters, but merely converting from RGB-to-RGBA
(and also allowing to convert between 5bit and 8bit color depts). And, always
re-ordering the data from scanline format to swizzled texture format:
--> 3DS Video Texture Swizzling

10130000h/10131000h - New3DS - L2B_CNT (R/W)
  0-1   Input RGBx Format            (0=8888, 1=8880, 2=5551, 3=5650)     (R/W)
  2-7   Unused (0)
  8-9   Output RGBA Format           (0=8888, 1=8880, 2=5551, 3=5650)     (R/W)
  10-21 Unused (0)
  22    Input DMA Enable             (0=Disable, 1=Enable CDMA 17h/19h)   (R/W)
  23    Output DMA Enable            (0=Disable, 1=Enable CDMA 18h/1Ah)   (R/W)
  24    Input DRQ                    (0=No, 1=DRQ) (write 1 to ack?)   (R/ack?)
  25    Output DRQ, 8th input line   (0=No, 1=DRQ) (write 1 to ack?)   (R/ack?)
  26-28 Unused (0)
  29    Interrupt upon DRQ(s)?       (0=Disable, 1=Enable IRQ 45h/46h)    (R/W)
  30    Interrupt upon Transfer done (0=Disable, 1=Enable IRQ 45h/46h)    (R/W)
  31    Start/Busy         (0=Idle/Ready, 1=Start/Busy)                   (R/W)
Send/Recv is done in units of 8 lines (unlike Y2R, which requires sending 9
lines in first block).

10130004h/10131004h - New3DS - L2B_WIDTH (R/W)
10130006h/10131006h - New3DS - L2B_HEIGHT (R/W)
  0-2   Unused (0)
  3-9   Width/Height in 8 pixel units (01h..7Fh=8..1016? pixels, or 00h=?)
  10-15 Unused (0)

10130020h/10131020h - New3DS - L2B_ALPHA (R/W)
  0-7   Alpha value for all pixels    (00h..FFh = Transparent..Solid)
  8-31  Unused (0)
Used as alpha for output format 8888 and 5551 (the latter uses only bit7 of the
8bit value).
Note: Any alpha values written to the input fifo are ignored, the alpha value
is always taken from the alpha register, not from the incoming pixels.

10330000h/10331000h - New3DS - L2B_FIFO (R and W) (empty=data_abort)
  0-31  Pixel data
The FIFO is mirrored across a 1000h-byte window (but eight large scanlines may
be larger than that, so it's better to used fixed a FIFO address instead of
increasing addresses in that window).
homepage - patreon - you can think of a bit as a bottle that is either half full or half empty

nocash
Posts: 1200
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Thu Mar 19, 2020 9:14 am

The Y2R registers do also have similar DMA enable and IRQ enable bits. So Y2R_CNT (or Y2R_PARAMS) does now look as so:

Code: Select all

10102000h/10132000h - Y2R_CNT (R/W)
  0-2   Input Format YUV (0-4 = 422'8, 420'8, 422'16, 420'16, 422'BATCH)  (R/W)
  3-7   Unused (0)
  8-9   Output Format RGBA      (0=8888, 1=8880, 2=5551, 3=5650)          (R/W)
  10-11 Output Clockwise Rotate (0=None, 1=90', 2=180', 3=270')           (R/W)
  12    Output Block Alignment  (0=LinearFramebuf, 1=MortonSwizzleTexture)(R/W)
  13-14 Unused (0)
  15    Unknown, reportedly used, but always 0 (maybe write-only?)          (?)
  16    Brightness Dither Enable   (0=No, 1=Use Y2R_DITHER0-3)            (R/W)
  17    Brightness Ugly Pulsation? (0=No, 1=Add 0,1,2,3 in frame 0,1,2,3) (R/W)
  18-20 Unused (0)
  21    Unknown, reportedly used, but always 0 (maybe write-only?)          (?)
  22    Input DMA Enable   (0=Disable, 1=Enable CDMA 09h/15h)             (R/W)
  23    Output DMA Enable  (0=Disable, 1=Enable CDMA 0Ah/16h)             (R/W)
  24    Input DRQ Y?                   (0=No, 1=DRQ) (write 1 to ack?) (R/ack?)
  25    Input DRQ U?                   (0=No, 1=DRQ) (write 1 to ack?) (R/ack?)
  26    Input DRQ V?                   (0=No, 1=DRQ) (write 1 to ack?) (R/ack?)
  27    Input DRQ YUYV (batch)         (0=No, 1=DRQ) (write 1 to ack?) (R/ack?)
  28    Output DRQ RGB, 9th input line (0=No, 1=DRQ) (write 1 to ack?) (R/ack?)
  29    Interrupt upon DRQ(s)?       (0=Disable, 1=Enable IRQ 4Bh/4Eh)    (R/W)
  30    Interrupt upon Transfer done (0=Disable, 1=Enable IRQ 4Bh/4Eh)    (R/W)
  31    Start/Busy                     (0=Idle/Ready, 1=Start/Busy)       (R/W)
The "Brightness Pulsation" bit does apply different brightness/dithering in each 4 conversions. At a low framerate it is just ugly: Dithering seems to "drift". And without dithering, dark areas appear to grow and shrink in size. At 60Hz it might look a bit better, but it's probably still visible as it extends through 4 frames. When using dither, it would be probably better to invert the dither pattern manually in each 2 frames.

For the input formats,

Code: Select all

  INPUT_YUV422_INDIV_8   0     is that 8bit? or 8x8pix? or divide by 8?
  INPUT_YUV420_INDIV_8   1
  INPUT_YUV422_INDIV_16  2     is that 16bit? or 16x16pix? or divide by 16?
  INPUT_YUV420_INDIV_16  3
  INPUT_YUV422_BATCH     4     aka camera YUYV
I have only used the camera "BATCH" format so far. I am not sure what the "INDIV" ones are doing, and if they are arranged in scanlines or blocks.

For the data requests, my current conclusion is:

Code: Select all

Conversion is done units of 8 lines. However, the 1st Input block must be 9
lines (unless the total height is smaller), and the final blocks can be smaller
(depending on amount of remaining lines). For example:
  Send 9,8,8,8,8,3 scanlines    ;\for 44 scanlines
  Recv 8,8,8,8,8,4 scanlines    ;/
The odd amount of sending 9 lines in 1st block might allow to keep converting
data while receiving responses.
When transferring the data in that exact amounts of scanlines, it's probably possible to acknowledge the DRQ flags in a working fashion (which is also needed for acknowleding DRQ-triggered interrupts).
Hmmm, if Input format 0-3 are working differently (perhaps in non-scanline fashion), then I am not sure if that formats require sending 9 lines in first block, too.
Last edited by nocash on Thu Mar 19, 2020 9:24 am, edited 1 time in total.
homepage - patreon - you can think of a bit as a bottle that is either half full or half empty

nocash
Posts: 1200
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Thu Mar 19, 2020 9:21 am

And I've also tried to describe the texture swizzling stuff... I hope I got that right.

Code: Select all

Texture Swizzling
Morton Swizzling, or Z-order Swizzling is done by reading source pixels from a
scanline based bitmap in "Z-shaped" read-direction, and then storing that
pixels at continous VRAM addresses.
In the drawing below, each "Z" represents 2x2 pixels (arranged as a "Z" shape,
ie. upper-left, upper-right, lower-left, lower-right). On a larger scale, each
2x2 Z's are also forming a larger Z, and so on.
  Z/Z  /Z/Z
  .-' / .-'
  Z/Z/  Z/Z
      ..--'
  .--'
  Z/Z  /Z/Z
  .-' / .-'
  Z/Z/  Z/Z
This can improve cache hits for adjacent pixels. In a large bitmap, pixels in
adjacent scanlines are always located in separate cache entries. With the
swizzling, there is a better chance that they are in the same cache entry.

Swizzling Hardware
The 3DS has some hardware for converting scanlines to swizzled textures:
  Y2R Registers (YUV-to-RGBA)
  L2B Registers (RGB-to-RGBA) (New3DS only)

Swizzling Examples
Examples for scanline pixels before/after swizzling:
  Linear scanlines, 16x8 pixels:                    Linear lines, 8x8 pixels:
  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F   00 01 02 03 04 05 06 07
  10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F   08 09 0A 0B 0C 0D 0E 0F
  20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F   10 11 12 13 14 15 16 17
  30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F   18 19 1A 1B 1C 1D 1E 1F
  40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F   20 21 22 23 24 25 26 27
  50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F   28 29 2A 2B 2C 2D 2E 2F
  60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F   30 31 32 33 34 35 36 37
  70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F   38 39 3A 3B 3C 3D 3E 3F
  Swizzled texture, 2 tiles:                        Swizzled texture, 1 tile:
  00 01 10 11 02 03 12 13  ;\                       00 01 08 09 02 03 0A 0B
  20 21 30 31 22 23 32 33  ;                        10 11 18 19 12 13 1A 1B
  04 05 14 15 06 07 16 17  ;                        04 05 0C 0D 06 07 0E 0F
  24 25 34 35 26 27 36 37  ; left tile              14 15 1C 1D 16 17 1E 1F
  40 41 50 51 42 43 52 53  ;                        20 21 28 29 22 23 2A 2B
  60 61 70 71 62 63 72 73  :                        30 31 38 39 32 33 3A 3B
  44 45 54 55 46 47 56 57  ;                        24 25 2C 2D 26 27 2E 2F
  64 65 74 75 66 67 76 77  ;/                       34 35 3C 3D 36 37 3E 3F
  08 09 18 19 0A 0B 1A 1B  ;\
  28 29 38 39 2A 2B 3A 3B  ;
  0C 0D 1C 1D 0E 0F 1E 1F  ;
  2C 2D 3C 3D 2E 2F 3E 3F  ; right tile
  48 49 58 59 4A 4B 5A 5B  ;
  68 69 78 79 6A 6B 7A 7B  :
  4C 4D 5C 5D 4E 4F 5E 5F  ;
  6C 6D 7C 7D 6E 6F 7E 7F  ;/

Note: Z-order refers to the shape of the letter "Z", not to be confused with
Z-axis, and not to be cofused with the zigzag-order that is used in JPEGs.
homepage - patreon - you can think of a bit as a bottle that is either half full or half empty

tepples
Posts: 21946
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: 3DS reverse engineering

Post by tepples » Thu Mar 19, 2020 1:59 pm

Did or could you mention that the effect is like that of interleaving the bits of the X and Y coordinates?

nocash
Posts: 1200
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Fri Mar 20, 2020 5:04 am

I had only gazed at internet drawings with Z's, and at the 3DS FIFO output, and didn't even think about the binary addressing yet.
For bitmap coordinates "Xxxxxxxx","Yyyyyyyy", the lookup address in the swizzled array would be "YXyxyxyxyxyxyxyx" in binary?

Ah, wait, the Y2R and L2B registers are processing chunks of 8 lines, so they would rather output 32 chunks with "Xxxxxyxyxyx".
If that order isn't desired, the CDMA controller could be programmed to interleave the upper address bits, too.
homepage - patreon - you can think of a bit as a bottle that is either half full or half empty

nocash
Posts: 1200
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Sat Mar 21, 2020 4:43 pm

Now I have had a look at the LGYFB registers (aka MTX registers). They are supposedly intended for forwarding the GBA/NDS video signal to the 3DS framebuffer, with optional scaling, and with similar dithering (and alpha?) settings as for the Y2R and L2B registers.

I have got it partially working: It does require to enable NDS or GBA mode, and LGYFB0/1 do then fire IRQ 4Ch/4Dh and CDMA 0Dh/0Eh. Only, I couldn't find any input or output FIFOs for the CDMA (or manual) data transfers : /
The input might come directly from the GBA/NDS video chip (?) but I assume that the output needs to be manually tranferred (or DMA'ed) to the 3DS framebuffer.
But without FIFOs, I am stuck now, maybe the FIFOs do require further init of the 2D video hardware (although the CDMA peripheral requests for the FIFOs are already alive).

And an unexpected offspring: I have finally found the long lost microphone dma channel. It's CDMA 00h, and needs to be enabled via Port 1014010Ch.bit0=1.

For activating GBA/NDS mode:
First write the desired mode to "ARM7_CNT" aka ARM9 Port 10018000h (0=3DS, 1=NDS/DSi, 2=GBA, or 3=Invalid, automatically replaced by 0). Then apply that setting by writing 8000h to "CFG11_TWLMODE_0" aka ARM11 Port 10141100h.bit15 (bit0-1 of that register contain a readonly copy of the value that was written to ARM7_CNT, and, setting bit15 works only if that value was nonzero).

Selecting GBA mode is easiest because it does keep ARM9 running as usually, and it's still enough to activate LGYFB interrupts and CDMA requests.
Selecting NDS/DSi mode changes the ARM9 memory map, that would survive only when running ARM9 code in ITCM.

I am not sure if directly switching to GBA mode is really working though. Maybe one does first need to switch to DSi mode, then init the DSi registers for switching to NDS mode, and then excecute NDS code that switches to GBA mode; similar as on real NDS/DSi consoles.

But, if switching to GBA mode is working, then ARM7 should probably execute a small 32 byte bootstub stored in the ARM7_BOOT registers. I don't know if it's already working - I haven't found a register or memory location that could be used to send data from ARM7 to ARM9 or ARM11 yet.

EDIT: Wrinting to the KEYCNT register can be mis-used to transfer data from ARM7 to CFG11_TWLMODE_HID on ARM11 side, so the ARM7 is actually running, and there is at least some way to built a simple terminal, with KEYINPUT for user input, and KEYCNT for sending data to ARM11 display functions.

And the LGYFB registers... here's the current work in progress description. That's based on the MTX Registers page on 3dbrew, mixed with guesses and info from similar registers in the Y2R/L2B units. The only things are more or less tested and working are the Unused bits (always 0), the two LGY_IRQ_xxx registers, and the Start/Enable and DMA Enable bits in LGY_CNT bit 0 and 15.

Code: Select all

10110000h - LGYFB0 (Legacy Framebuffer 0 or so) ("bottom screen")
10111000h - LGYFB1 (Legacy Framebuffer 1 or so) ("top screen")
  1011x000h 4     LGY_CNT        R/W   mask: 00019f37h
  1011x004h 2     LGY_WIDTH      R/W   mask: 01ffh
  1011x006h 2     LGY_HEIGHT     R/W   mask: 01ffh
  1011x008h 2     LGY_IRQ_FLAG   R/ack
  1011x00Ah 2     LGY_?_00Ah     R
  1011x00Ch 2     LGY_IRQ_ENABLE R/W   mask: 0007h
  1011x020h 4     LGY_ALPHA      R/W mask: 000000ffh  ;-alpha alike Y2R ?
  1011x0f0h 4     LGY_?_0F0h     R/W mask: 0000000fh
  1011x100h 4     LGY_DITHER0    R/W mask: 0000cccch  ;\
  1011x108h 4     LGY_DITHER1    R/W mask: 0000cccch  ; DITHER
  1011x110h 4     LGY_DITHER2    R/W mask: 0000cccch  ; alike Y2R ?
  1011x118h 4     LGY_DITHER3    R/W mask: 0000cccch  ;/
  1011x200h 4     LGY_V_SIZE     R/W mask: 00000007h  ;\
  1011x204h 4     LGY_V_PATTERN  R/W mask: 0000000fh  ; Vertical Scaling
  1011x240h 4x30h LGY_V_ARRAY    R/W mask: 0000fff0h  ;/
  1011x300h 4     LGY_H_SIZE     R/W mask: 00000007h  ;\
  1011x304h 4     LGY_H_PATTERN  R/W mask: 0000000fh  ; Horizontal Scaling
  1011x340h 4x30h LGY_H_ARRAY    R/W mask: 0000fff0h  ;/

1011x000h - LGY_CNT (R/W)
  0     Start/Enable (?)           (0=?, 1=Start...busy?)                 (R/W)
  1     Enable vertical matrix     (?)                                    (R/W)
  2     Enable horizontal matrix   (?)                                    (R/W)
  3     Unused (0)
  4     ???            ;\maybe dither/pulsation alike Y2R ?               (R/W)
  5     ???            ;/                                                 (R/W)
  6-7   Unused (0)
  8-9   Output Format RGBA      (0=8888, 1=8880, 2=5551, 3=5650)          (R/W)
  10-11 Output Clockwise Rotate (0=None, 1=90', 2=180', 3=270')           (R/W)
  12    Output Swizzle          (0=LinearFramebuf, 1=MortonSwizzleTexture)(R/W)
  13-14 Unused (0)
  15    Enable DMA (0=Off, 1=Enable CDMA 0Dh/0Eh)                         (R/W)
  16    ??? data available (?) but, this is R/W, not a status bit         (R/W)
  17-31 Unused (0)

1011x004h - LGY_WIDTH (R/W)
1011x006h - LGY_HEIGHT (R/W)
  0-8   Output?? Width/Height, minus-1   (0..1FFh = 1..512 pixels)
  9-15  Unused (0)

1011x008h - LGY_IRQ_FLAG (R/ack)
  0     Interrupt 0    (can get set when ON) (1=IRQ)   (write 1 to clear)
  1     Interrupt 1    (can get set when ON) (1=IRQ)   (write 1 to clear)
  2     Interrupt 2    (usually 0)           (1=IRQ?)  (write 1 to clear?)
  3-15  Unused (0) ?
bit0 gets set ONCE after changing LGY_CNT.bit from 0 to 1
bit1 gets set REPEATEDLY in each test?

1011x00Ah - LGY_?_00Ah (R)
  0-8   Unknown (readonly, initially garbage?)
  9-15  Unused (0) ?
Tends to be 0E8h/170h when STILL OFF, and 000h when ON.
Some of the initial bits are somewhat random, and/or seem to change when
lcd/backlight is on?

1011x00Ch - LGY_IRQ_ENABLE - ? (R/W)
  0     Enable IRQ on First Input Line?    (0=Off, 1=Enable IRQ 4Ch/4Dh)
  1     Enable IRQ on Next Output Block?   (0=Off, 1=Enable IRQ 4Ch/4Dh)
  2     Enable IRQ on Last Block maybe? ... but never gets triggered?
  3-31  Unused (0)
Maybe somewhat vblank/hblank from 2D engine, or data transfer flags?
IRQ enable does also require LGY_CNT.bit0=1 and CFG11_TWLMODE_0.bit15=1.

1011x020h - LGY_ALPHA - maybe alpha alike Y2R ? (R/W)
  0-7   Unknown, maybe alpha   ... hmmm, or is that something for the "ghosting" effect?
  8-31  Unused (0)

1011x0F0h - LGY_?_0F0h (R/W)
  0-3   Unknown
  4-31  Unused (0)
00h,01h,02h,03h,04h,05h=Disables IRQs? (IRQ_FLAG's don't get set)
06h,07h,08h,0Fh=Enables IRQs?
Other = ?
Hmmm, sometimes IRQs occur even when using smaller values. Maybe the register
is used only in some cases, or the setting is compared against another register
value?

1011x100h - LGY_DITHER0 (R/W)
1011x108h - LGY_DITHER1 (R/W)
1011x110h - LGY_DITHER2 (R/W)
1011x118h - LGY_DITHER3 (R/W)
RW-mask 0000CCCCh, DITHER alike Y2R ?

1011x200h - LGY_V_SIZE - Vertical scaling (R/W)
1011x300h - LGY_H_SIZE - Horizontal scaling (R/W)
  0-2   Batch width-1     (0..7 = 1..8 pixels)
  3-31  Unused (0)

1011x204h - LGY_V_PATTERN - Vertical scaling (R/W)
1011x304h - LGY_H_PATTERN - Horizontal scaling (R/W)
  0-3   "If the corresponding bit for the current batch iteration index is
          set then a new pixel is read."
  4-31  Unused (0)
"The amount of set bits determine how many pixels are read each batch."
"Any bit indexes past LGY_x_SIZE are ignored."
"This value is 8 bits, but it has to be written with a 32bit write."

1011x240h..1011x2FFh - LGY_V_ARRAY - Vertical scaling, 6x8 words (R/W)
1011x340h..1011x3FFh - LGY_H_ARRAY - Horizontal scaling, 6x8 words (R/W)
  0-3   Unused (0)
  4-15  Unknown, "matrix data, height is always 6"
  16-31 Unused (0)           ;hmmm, and maybe "width" is from LGY_x_SIZE ?
Last edited by nocash on Wed Mar 25, 2020 6:19 am, edited 2 times in total.
homepage - patreon - you can think of a bit as a bottle that is either half full or half empty

nocash
Posts: 1200
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: 3DS reverse engineering

Post by nocash » Tue Mar 24, 2020 9:05 am

Does anyone have "gba footers" for some gba titles, and could post or PM some of that footers?

The format of the footer seems to be more or less unknown... http://3dbrew.org/wiki/3DS_Virtual_Console#Footer does have some details, and below does have some other details, but they are conflicting with each other. I guess it could make a bit more sense when seeing a hexdump of the original footers.

Oh, and what the heck is a ghosting?

Code: Select all

meta:
  id: gba_3ds_vc_footer
  file-extension: ftr
  endian: le
  
doc-ref: "https://3dbrew.org/wiki/3DS_Virtual_Console#Footer"
doc-ref: "https://gbatemp.net/threads/release-agb_firm-signature-patcher-gba-rom-converter.390313/"
doc-ref: "https://gbatemp.net/threads/restoring-original-colors-to-gba-vc.427642/page-5#post-6423110"
doc-ref: "https://gbatemp.net/threads/restoring-original-colors-to-gba-vc.427642/"
doc-ref: "https://www.reddit.com/r/3dshacks/comments/6znqqg/1_mbit_agb_firm_lennies_%CA%96/"

seq:
  - id: unk1
    size: 4
  - id: rom_filesize1
    type: u4
  - id: save_type
    type: u4
    enum: save_type_enum
  - id: unk2
    size: 20
    doc: |
     EEPROM     : FF FF 00 00 3E D4 17 00 06 62 02 00 86 00 00 00 13 DD 02 00
     Flash/SRAM : FF FF 00 00 86 C8 27 00 35 CE 08 00 84 01 00 00 70 11 03 00
  - id: lcd_ghosting
    type: u4
    enum: lcd_ghosting_enum
  - id: video_lut
    doc: "black to full, rgbrgbrgb ?"
    size: 0x300
    doc: |
     original = 00 00 00 01 01 01 02 02 02 03 03 03 04 04 04 05 05 05 06 06 06 07 07 07 08 08 08 09 09 09 0A 0A 0A 0B 0B 0B 0C 0C 0C 0D 0D 0D 0E 0E 0E 0F 0F 0F 10 10 10 11 11 11 12 12 12 13 13 13 14 14 14 15 15 15 16 16 16 17 17 17 18 18 18 19 19 19 1A 1A 1A 1B 1B 1B 1C 1C 1C 1D 1D 1D 1E 1E 1E 1F 1F 1F 20 20 20 21 21 21 22 22 22 23 23 23 24 24 24 25 25 25 26 26 26 27 27 27 28 28 28 29 29 29 2A 2A 2A 2B 2B 2B 2C 2C 2C 2D 2D 2D 2F 2F 2F 30 30 30 31 31 31 32 32 32 33 33 33 34 34 34 35 35 35 36 36 36 37 37 37 38 38 38 39 39 39 3A 3A 3A 3B 3B 3B 3C 3C 3C 3D 3D 3D 3E 3E 3E 3F 3F 3F 40 40 40 41 41 41 42 42 42 43 43 43 44 44 44 45 45 45 46 46 46 47 47 47 48 48 48 49 49 49 4A 4A 4A 4B 4B 4B 4C 4C 4C 4D 4D 4D 4E 4E 4E 4F 4F 4F 50 50 50 51 51 51 52 52 52 53 53 53 54 54 54 55 55 55 56 56 56 57 57 57 58 58 58 59 59 59 5A 5A 5A 5B 5B 5B 5C 5C 5C 5D 5D 5D 5E 5E 5E 5F 5F 5F 60 60 60 61 61 61 62 62 62 63 63 63 64 64 64 65 65 65 66 66 66 67 67 67 68 68 68 69 69 69 6A 6A 6A 6B 6B 6B 6C 6C 6C 6D 6D 6D 6E 6E 6E 6F 6F 6F 70 70 70 71 71 71 72 72 72 73 73 73 74 74 74 75 75 75 76 76 76 77 77 77 78 78 78 79 79 79 7A 7A 7A 7B 7B 7B 7C 7C 7C 7D 7D 7D 7E 7E 7E 7F 7F 7F 80 80 80 81 81 81 82 82 82 83 83 83 84 84 84 85 85 85 86 86 86 87 87 87 88 88 88 89 89 89 8A 8A 8A 8B 8B 8B 8C 8C 8C 8D 8D 8D 8E 8E 8E 8F 8F 8F 90 90 90 91 91 91 92 92 92 93 93 93 94 94 94 95 95 95 96 96 96 97 97 97 98 98 98 99 99 99 9A 9A 9A 9B 9B 9B 9C 9C 9C 9D 9D 9D 9E 9E 9E 9F 9F 9F A0 A0 A0 A1 A1 A1 A2 A2 A2 A3 A3 A3 A4 A4 A4 A5 A5 A5 A6 A6 A6 A7 A7 A7 A8 A8 A8 A9 A9 A9 AA AA AA AB AB AB AC AC AC AD AD AD AE AE AE AF AF AF B0 B0 B0 B1 B1 B1 B2 B2 B2 B3 B3 B3 B4 B4 B4 B5 B5 B5 B6 B6 B6 B7 B7 B7 B8 B8 B8 B9 B9 B9 BA BA BA BB BB BB BC BC BC BD BD BD BE BE BE BF BF BF C0 C0 C0 C1 C1 C1 C2 C2 C2 C3 C3 C3 C4 C4 C4 C5 C5 C5 C6 C6 C6 C7 C7 C7 C8 C8 C8 C9 C9 C9 CA CA CA CB CB CB CC CC CC CD CD CD CE CE CE CF CF CF D0 D0 D0 D1 D1 D1 D2 D2 D2 D3 D3 D3 D4 D4 D4 D5 D5 D5 D6 D6 D6 D7 D7 D7 D8 D8 D8 D9 D9 D9 DA DA DA DB DB DB DC DC DC DD DD DD DE DE DE DF DF DF E0 E0 E0 E1 E1 E1 E2 E2 E2 E3 E3 E3 E4 E4 E4 E5 E5 E5 E6 E6 E6 E7 E7 E7 E8 E8 E8 E9 E9 E9 EA EA EA EB EB EB EC EC EC ED ED ED EE EE EE EF EF EF F0 F0 F0 F1 F1 F1 F2 F2 F2 F3 F3 F3 F4 F4 F4 F5 F5 F5 F6 F6 F6 F7 F7 F7 F8 F8 F8 F9 F9 F9 FA FA FA FB FB FB FC FC FC FD FD FD FE FE FE FF FF FF FF FF FF
     default? = 00 00 00 00 00 00 01 01 01 02 02 02 02 02 02 03 03 03 04 04 04 04 04 04 05 05 05 06 06 06 07 07 07 07 07 07 08 08 08 09 09 09 09 09 09 0A 0A 0A 0B 0B 0B 0B 0B 0B 0C 0C 0C 0D 0D 0D 0E 0E 0E 0E 0E 0E 0F 0F 0F 10 10 10 10 10 10 11 11 11 12 12 12 12 12 12 13 13 13 14 14 14 15 15 15 15 15 15 16 16 16 17 17 17 17 17 17 18 18 18 19 19 19 19 19 19 1A 1A 1A 1B 1B 1B 1C 1C 1C 1C 1C 1C 1D 1D 1D 1E 1E 1E 1E 1E 1E 1F 1F 1F 20 20 20 20 20 20 21 21 21 22 22 22 23 23 23 23 23 23 24 24 24 25 25 25 25 25 25 26 26 26 27 27 27 27 27 27 28 28 28 29 29 29 2A 2A 2A 2A 2A 2A 2B 2B 2B 2C 2C 2C 2C 2C 2C 2D 2D 2D 2E 2E 2E 2E 2E 2E 2F 2F 2F 30 30 30 31 31 31 31 31 31 32 32 32 33 33 33 33 33 33 34 34 34 35 35 35 35 35 35 36 36 36 37 37 37 38 38 38 38 38 38 39 39 39 3A 3A 3A 3A 3A 3A 3B 3B 3B 3C 3C 3C 3C 3C 3C 3D 3D 3D 3E 3E 3E 3F 3F 3F 3F 3F 3F 40 40 40 41 41 41 41 41 41 42 42 42 43 43 43 43 43 43 44 44 44 45 45 45 46 46 46 46 46 46 47 47 47 48 48 48 48 48 48 49 49 49 4A 4A 4A 4A 4A 4A 4B 4B 4B 4C 4C 4C 4D 4D 4D 4D 4D 4D 4E 4E 4E 4F 4F 4F 4F 4F 4F 50 50 50 51 51 51 51 51 51 52 52 52 53 53 53 54 54 54 54 54 54 55 55 55 56 56 56 56 56 56 57 57 57 58 58 58 58 58 58 59 59 59 5A 5A 5A 5B 5B 5B 5B 5B 5B 5C 5C 5C 5D 5D 5D 5D 5D 5D 5E 5E 5E 5F 5F 5F 5F 5F 5F 60 60 60 61 61 61 62 62 62 62 62 62 63 63 63 64 64 64 64 64 64 65 65 65 66 66 66 66 66 66 67 67 67 68 68 68 69 69 69 69 69 69 6A 6A 6A 6B 6B 6B 6B 6B 6B 6C 6C 6C 6D 6D 6D 6D 6D 6D 6E 6E 6E 6F 6F 6F 70 70 70 70 70 70 71 71 71 72 72 72 72 72 72 73 73 73 74 74 74 74 74 74 75 75 75 76 76 76 77 77 77 77 77 77 78 78 78 79 79 79 79 79 79 7A 7A 7A 7B 7B 7B 7B 7B 7B 7C 7C 7C 7D 7D 7D 7E 7E 7E 7E 7E 7E 7F 7F 7F 80 80 80 80 80 80 81 81 81 82 82 82 82 82 82 83 83 83 84 84 84 85 85 85 85 85 85 86 86 86 87 87 87 87 87 87 88 88 88 89 89 89 89 89 89 8A 8A 8A 8B 8B 8B 8C 8C 8C 8C 8C 8C 8D 8D 8D 8E 8E 8E 8E 8E 8E 8F 8F 8F 90 90 90 90 90 90 91 91 91 92 92 92 93 93 93 93 93 93 94 94 94 95 95 95 95 95 95 96 96 96 97 97 97 97 97 97 98 98 98 99 99 99 9A 9A 9A 9A 9A 9A 9B 9B 9B 9C 9C 9C 9C 9C 9C 9D 9D 9D 9E 9E 9E 9E 9E 9E 9F 9F 9F A0 A0 A0 A1 A1 A1 A1 A1 A1 A2 A2 A2 A3 A3 A3 A3 A3 A3 A4 A4 A4 A5 A5 A5 A5 A5 A5 A6 A6 A6 A7 A7 A7 A8 A8 A8 A8 A8 A8 A9 A9 A9 AA AA AA AA AA AA AB AB AB AC AC AC AC AC AC AD AD AD AE AE AE AF AF AF AF AF AF B0 B0 B0 B1 B1 B1 B1 B1 B1 B2 B2 B2
     darker1  = 00 00 00 00 00 00 01 01 01 01 01 01 02 02 02 03 03 03 03 03 03 04 04 04 05 05 05 05 05 05 06 06 06 07 07 07 07 07 07 08 08 08 09 09 09 09 09 09 0A 0A 0A 0B 0B 0B 0B 0B 0B 0C 0C 0C 0D 0D 0D 0D 0D 0D 0E 0E 0E 0E 0E 0E 0F 0F 0F 10 10 10 10 10 10 11 11 11 12 12 12 12 12 12 13 13 13 14 14 14 14 14 14 15 15 15 16 16 16 16 16 16 17 17 17 18 18 18 18 18 18 19 19 19 1A 1A 1A 1A 1A 1A 1B 1B 1B 1B 1B 1B 1C 1C 1C 1D 1D 1D 1D 1D 1D 1E 1E 1E 1F 1F 1F 1F 1F 1F 20 20 20 21 21 21 21 21 21 22 22 22 23 23 23 23 23 23 24 24 24 25 25 25 25 25 25 26 26 26 27 27 27 27 27 27 28 28 28 28 28 28 29 29 29 2A 2A 2A 2A 2A 2A 2B 2B 2B 2C 2C 2C 2C 2C 2C 2D 2D 2D 2E 2E 2E 2E 2E 2E 2F 2F 2F 30 30 30 30 30 30 31 31 31 32 32 32 32 32 32 33 33 33 34 34 34 34 34 34 35 35 35 35 35 35 36 36 36 37 37 37 37 37 37 38 38 38 39 39 39 39 39 39 3A 3A 3A 3B 3B 3B 3B 3B 3B 3C 3C 3C 3D 3D 3D 3D 3D 3D 3E 3E 3E 3F 3F 3F 3F 3F 3F 40 40 40 41 41 41 41 41 41 42 42 42 42 42 42 43 43 43 44 44 44 44 44 44 45 45 45 46 46 46 46 46 46 47 47 47 48 48 48 48 48 48 49 49 49 4A 4A 4A 4A 4A 4A 4B 4B 4B 4C 4C 4C 4C 4C 4C 4D 4D 4D 4E 4E 4E 4E 4E 4E 4F 4F 4F 4F 4F 4F 50 50 50 51 51 51 51 51 51 52 52 52 53 53 53 53 53 53 54 54 54 55 55 55 55 55 55 56 56 56 57 57 57 57 57 57 58 58 58 59 59 59 59 59 59 5A 5A 5A 5B 5B 5B 5B 5B 5B 5C 5C 5C 5C 5C 5C 5D 5D 5D 5E 5E 5E 5E 5E 5E 5F 5F 5F 60 60 60 60 60 60 61 61 61 62 62 62 62 62 62 63 63 63 64 64 64 64 64 64 65 65 65 66 66 66 66 66 66 67 67 67 68 68 68 68 68 68 69 69 69 69 69 69 6A 6A 6A 6B 6B 6B 6B 6B 6B 6C 6C 6C 6D 6D 6D 6D 6D 6D 6E 6E 6E 6F 6F 6F 6F 6F 6F 70 70 70 71 71 71 71 71 71 72 72 72 73 73 73 73 73 73 74 74 74 75 75 75 75 75 75 76 76 76 76 76 76 77 77 77 78 78 78 78 78 78 79 79 79 7A 7A 7A 7A 7A 7A 7B 7B 7B 7C 7C 7C 7C 7C 7C 7D 7D 7D 7E 7E 7E 7E 7E 7E 7F 7F 7F 80 80 80 80 80 80 81 81 81 82 82 82 82 82 82 83 83 83 83 83 83 84 84 84 85 85 85 85 85 85 86 86 86 87 87 87 87 87 87 88 88 88 89 89 89 89 89 89 8A 8A 8A 8B 8B 8B 8B 8B 8B 8C 8C 8C 8D 8D 8D 8D 8D 8D 8E 8E 8E 8F 8F 8F 8F 8F 8F 90 90 90 90 90 90 91 91 91 92 92 92 92 92 92 93 93 93 94 94 94 94 94 94 95 95 95 96 96 96 96 96 96 97 97 97 98 98 98 98 98 98 99 99 99 9A 9A 9A 9A 9A 9A 9B 9B 9B 9C 9C 9C 9C 9C 9C 9D 9D 9D 9D 9D 9D 9E 9E 9E 9F 9F 9F 9F 9F 9F A0 A0 A0 A1 A1 A1 A1 A1 A1 A2 A2 A2 A3 A3 A3 A3 A3 A3 A4 A4 A4 A5 A5 A5 A5 A5 A5
     darker2  = 00 00 00 00 00 00 01 01 01 01 01 01 02 02 02 03 03 03 03 03 03 04 04 04 04 04 04 05 05 05 06 06 06 06 06 06 07 07 07 07 07 07 08 08 08 09 09 09 09 09 09 0A 0A 0A 0A 0A 0A 0B 0B 0B 0C 0C 0C 0C 0C 0C 0D 0D 0D 0D 0D 0D 0E 0E 0E 0F 0F 0F 0F 0F 0F 10 10 10 10 10 10 11 11 11 12 12 12 12 12 12 13 13 13 13 13 13 14 14 14 15 15 15 15 15 15 16 16 16 16 16 16 17 17 17 18 18 18 18 18 18 19 19 19 19 19 19 1A 1A 1A 1B 1B 1B 1B 1B 1B 1C 1C 1C 1C 1C 1C 1D 1D 1D 1E 1E 1E 1E 1E 1E 1F 1F 1F 1F 1F 1F 20 20 20 21 21 21 21 21 21 22 22 22 22 22 22 23 23 23 24 24 24 24 24 24 25 25 25 25 25 25 26 26 26 27 27 27 27 27 27 28 28 28 28 28 28 29 29 29 2A 2A 2A 2A 2A 2A 2B 2B 2B 2B 2B 2B 2C 2C 2C 2D 2D 2D 2D 2D 2D 2E 2E 2E 2E 2E 2E 2F 2F 2F 30 30 30 30 30 30 31 31 31 31 31 31 32 32 32 33 33 33 33 33 33 34 34 34 34 34 34 35 35 35 36 36 36 36 36 36 37 37 37 37 37 37 38 38 38 39 39 39 39 39 39 3A 3A 3A 3A 3A 3A 3B 3B 3B 3C 3C 3C 3C 3C 3C 3D 3D 3D 3D 3D 3D 3E 3E 3E 3F 3F 3F 3F 3F 3F 40 40 40 40 40 40 41 41 41 42 42 42 42 42 42 43 43 43 43 43 43 44 44 44 45 45 45 45 45 45 46 46 46 46 46 46 47 47 47 48 48 48 48 48 48 49 49 49 49 49 49 4A 4A 4A 4B 4B 4B 4B 4B 4B 4C 4C 4C 4C 4C 4C 4D 4D 4D 4E 4E 4E 4E 4E 4E 4F 4F 4F 4F 4F 4F 50 50 50 51 51 51 51 51 51 52 52 52 52 52 52 53 53 53 54 54 54 54 54 54 55 55 55 55 55 55 56 56 56 57 57 57 57 57 57 58 58 58 58 58 58 59 59 59 5A 5A 5A 5A 5A 5A 5B 5B 5B 5B 5B 5B 5C 5C 5C 5D 5D 5D 5D 5D 5D 5E 5E 5E 5E 5E 5E 5F 5F 5F 60 60 60 60 60 60 61 61 61 61 61 61 62 62 62 63 63 63 63 63 63 64 64 64 64 64 64 65 65 65 66 66 66 66 66 66 67 67 67 67 67 67 68 68 68 69 69 69 69 69 69 6A 6A 6A 6A 6A 6A 6B 6B 6B 6C 6C 6C 6C 6C 6C 6D 6D 6D 6D 6D 6D 6E 6E 6E 6F 6F 6F 6F 6F 6F 70 70 70 70 70 70 71 71 71 72 72 72 72 72 72 73 73 73 73 73 73 74 74 74 75 75 75 75 75 75 76 76 76 76 76 76 77 77 77 78 78 78 78 78 78 79 79 79 79 79 79 7A 7A 7A 7B 7B 7B 7B 7B 7B 7C 7C 7C 7C 7C 7C 7D 7D 7D 7E 7E 7E 7E 7E 7E 7F 7F 7F 7F 7F 7F 80 80 80 81 81 81 81 81 81 82 82 82 82 82 82 83 83 83 84 84 84 84 84 84 85 85 85 85 85 85 86 86 86 87 87 87 87 87 87 88 88 88 88 88 88 89 89 89 8A 8A 8A 8A 8A 8A 8B 8B 8B 8B 8B 8B 8C 8C 8C 8D 8D 8D 8D 8D 8D 8E 8E 8E 8E 8E 8E 8F 8F 8F 90 90 90 90 90 90 91 91 91 91 91 91 92 92 92 93 93 93 93 93 93 94 94 94 94 94 94 95 95 95 96 96 96 96 96 96 97 97 97 97 97 97 98 98 98 99 99 99
     In NSUI / GBA Footer generator mod : 
       no dark     / original = original
       soft dark   / darker 1 = default
       strong dark / darker 2 = darker2
     In GBA Footer generator, config type : 1 = default, 2 = darker1, 3 = darker2
  - id: unk3
    size: 20
  - id: rom_filesize2
    type: u4
  - id: unk4
    size: 8
  - id: rom_filesize3
    type: u4
  - id: unk5
    size: 8
  - id: magic
    size: 4
    contents: ".CAA"
  - id: unk6
    size: 6
  - id: rom_filesizehigh
    type: u2

enums:
  save_type_enum:
    0x0: eeprom_8k
    0x1: eeprom_8k_hum
    0x2: eeprom_64k
    0x3: eeprom_64k_hum
    0x4: flash_512k_amtel_rtc
    0x5: flash_512k_amtel
    0x6: flash_512k_sst_rtc
    0x7: flash_512k_sst
    0x8: flash_512k_panasonic_rtc
    0x9: flash_512k_panasonic
    0xA: flash_1m_macronix_rtc
    0xB: flash_1m_macronix
    0xC: flash_1m_sanyo_rtc
    0xD: flash_1m_sanyo
    0xE: sram_fram_256k
  lcd_ghosting_enum:
    0xFFFF: no # Some seems to use this ..
    0xFF: no
    0xF0: little
    0xC0: official_standard
    0x80: official_more
    0x90: official_more_plus # ?
    0x20: insane
    0x01: max
Running code in gba mode is working fine so far. Except, one cannot see it in lack of the seeming missing FIFO for the LGYFB registers.
But, the trick for tunneling text output through the KEYCNT register is working well, so showing test results is no problem.
homepage - patreon - you can think of a bit as a bottle that is either half full or half empty

Post Reply