Gameboy Development Forum

Discussion about software development for the old-school Gameboys, ranging from the "Gray brick" to Gameboy Color
(Launched in 2008)

You are not logged in.


#1 2020-09-04 03:36:55

Registered: 2017-05-24
Posts: 12

HuC-3 research (WIP)

TAMA5 is bad, but at least it doesn't leak state like this...this...pile of silicon.

HuC-3 is an extension of HuC-1 (basically just MBC5 + an IR sensor), but it has several "modes", set by writing to $0000, which affect the external memory region ("SRAM"). As with most mappers, writing 0xA allows direct access to the SRAM, and the top nybble is ignored (so a 4-bit output).

Mode $0: SRAM read-only access. Not sure why this is here, but it would seem that you can read from the SRAM same as in mode $A, but not write to it.
Modes $1-$9: Reads out $FF. There doesn't seem to be any difference between these.
Mode $A: SRAM access, same as a normal MBC.
Mode $B: Register write. Bits 2-6 like to bleed out in other modes for some reason. Bit 7 always seems to be high when read. Bits 4-6 seem to demarcate the type write, and bits 0-3 are the value written, at least according to SameBoy's source.
Mode $C: Register read. However, the there are some weird leaks from the mode $B register.
Mode $D: Not really sure what this one is, but it seems to be used for committing changes in other modes. When switching to this mode, bit 0 is always high, and clearing it appears to commit changes.
Mode $E: IR mode, according to LIJI. Not very well investigated yet, but bit 0 is if it detects an IR signal.
Mode $F: Reads out $FF. Seems to be unused.

Both register read and write appear to access a transfer register; it can be written to directly in mode $B (see below) and used to manipulate state.

A list of "mode $B" write types from SameBoy's source, but not fully investigated yet appear to be:
$10: Load the value from the register at the access index to the transfer register. Committing this command increments the index.
$30: Store the value in the transfer register to the register at the access index. Committing this command increments the index.
$40: Set the low nybble of the access index.
$50: Set the high nybble of the access index.
$60: Set the "access flags". This is only used in one place, and I've confirmed that the behavior in SameBoy for this is inaccurate. This is not a flags register, but I don't know what it is yet. Registers $20-$FF are writable if it's set to $60. Setting it appears to copy the RTC registers ($10-$15) to the register scratch window (at $00)

Other mode $B write types seem to be unmapped, but they do leaking state for some reason, so the value of $B will affect other reads regardless of whether or not the "type" is mapped.

The registers are as follows
$00-$06: Read/write scratch space. The RTC registers seem to get copied in here when accessed (see command $60 above)
$07: Parity bit of the scratch space? Not sure.
$08-$0F: Unknown
$10-$12: RTC minutes since the start of the day, LSB (0 - 1439, rolls over at 1440 to increment the day value below)
$13-$15: RTC number of days since the timer started, LSB
$16: Unknown, maybe RTC enable? (seen: 1)
$20 - $25: Unknown (zero)
$26: Tone to play (lower two bits)
$27: Should play tone when command $6E is sent (only if exactly 1; all bits seem to be checked)
$28 - $57: Unknown (zero)
$58-$5A: Alarm? minutes, LSB
$5B-$5D: Alarm? days, LSB
$5E: Unknown, maybe alarm tone to play? (seen: 3)
$5F: Unknown, maybe alarm enable? (seen: 1)
$60 - $71: Unknown (zero)
$72: Turn on extra hardware? 8 = enable speaker, other settings unknown
$73 - $FF: Unknown (zero)

The following "access flags" are known:
$60: Read/write, copy RTC value to scratch space
$61: Copy scratch space to RTC
$62: Read-only
$6E: Send twice to play tone in $26 if $27 is 1

The following tones exist:
$0: Old cellphone ringing
$1: Deep beeping
$2: Fast, long, annoying beeping
$3: "Bing bong"

It appears the way time works in this game is that it stores an "epoch" in the save and uses the RTC to mark days since the epoch. All multi-register RTC values are LSB, so the first nybble is the lowest four bits, etc. Also, it maxes out at 0xFFF (4095) days, afaict. You need to reset the year at some point to change the epoch.

Also, I haven't even confirmed there is an alarm yet. As far as I can tell, the tone that's played when the alarm elapses is done *manually* using the tone playing commands above. Trying to program the alarm by hand and letting it elapsed visible effect. The only effect I've yet found those registers have is when changing the RTC manually (as in, it doesn't happen as time elapses), the difference between the current time and the new time will be applied to these registers too. If you manually reprogram the time ahead 10 minutes, the alarm registers also advance by 10 minutes. It's very strange.

When the game Robot Poncots: Sun Version (the only HuC-3 game I have at the moment; should be getting Star Version somewhat soon) boots, it writes $01 to $6000 (which afaik is unmapped, but due to how many bits like to randomly float this may have an actual effect...), then does the following operations (on loop):

Write $0000 := $0D # Switch to mode $D
Read $A000 # Purpose unknown
Write $0000 := $0B # Switch to mode $B
Write $A000 := $62 # Seems to set some internal latch that affects the value of the mode $C register
Write $0000 := $0D # Switch to mode $D
Write $A000 := $FE # Commit mode $B change?
Read $A000 # Purpose unknown
Write $0000 := $0C # Switch to mode $C
Read $A000 # It checks that the low nybble is $1, and only breaks out of the loop if it is.

Now, about the modes $C and $D registers...the top bits seem to be directly leaked from the mode $B register, though how much depends on which one:
The mode $C register bits 4-6 are directly leaked from the mode $B register. Bit 7 is always high. Bits 0-3 seem to be output, though what asserts this output seems...strange. When writing $62 to the mode $B register, this register becomes $E1. ($80 from what appears to be an always-high bit. $60 from the mode $B register, and $1 from whatever $60-type writes do--bits 2-3 of the $60-type write also get output here, but bits 0-1 are distinct.)
The mode $D register bits 2-6 (I think) are directly leaked from the mode $B register. Bit 7 is again always high. What asserts bit 1 is...currently unknown, but has some weird properties. Bit 0 can be directly modified, but is initially asserted when entering mode $D.

This mapper is...a huge mess. I'm almost tearing my hair out trying to figure out what any of it is. State leaks all over the place, which makes it hard to tell which change is doing what; some bits just seem to be floating; nothing makes any sense. I really don't know what the people who designed this thing were thinking.

Last edited by endrift (2022-02-04 20:42:50)



#2 2020-09-14 17:46:59

Registered: 2014-06-17
Posts: 133

Re: HuC-3 research (WIP)

Wow. Okay. That's certainly annoying to reverse engineer...



#3 2022-01-31 21:39:55

Registered: 2017-05-24
Posts: 12

Re: HuC-3 research (WIP)

Been doing a lot of work on this lately; I had been putting findings in here but I'm not just editing the first post instead.

Last edited by endrift (2022-02-04 05:29:13)



#4 2022-03-28 06:22:43

New member
Registered: 2022-03-28
Posts: 1

Re: HuC-3 research (WIP)

Figured I should post some observations I'm seeing from Pocket Family GB2. These are from my HuC3 implementation in Gambatte. I'm ordering a Pocket Family GB2 cart so I'll be able to verify/refute these in a few weeks.

This game seems to do a $20 "$B mode" write sometime on bootup. This probably indicates this type is actually mapped? Right before it sets the access index to $07, maybe indicating some connection.

The game seems to have an alarm menu of sorts, able to set the alarm sound, some "event" (???), whether to turn on or off the alarm, and time for alarm (hours:minutes). These seem to touch a lot of registers. The alarm sound seems to just change 0x2E, the alarm enable changes 0x2F, and the alarm time seems to be stored in 0x28-0x2A (minutes LSB). 0x2B-0x2D would make sense to be years LSB, but the written values don't make sense for this. The event thing can affect whether 0x37/0x47/0x57, 0x3F/0x4F/0x5F, and 0x5B-0x5D have values written to them, or are 0'd out. I have no idea what to make of this.

The game also seems to write to a ton of other registers, often for no apparent reason, here's a hex dump of the registers showing the madness this game is inflicting:


07 00 01 00 00 00 01 00 00 00 00 00 00 00 00 00
07 00 01 00 00 00 01 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 01 0F 09 05 00 00 09 00 06
00 00 00 02 0B 01 00 06 00 00 00 02 0B 01 00 06
00 00 00 02 0B 01 00 06 00 00 00 02 0B 01 00 06
00 00 00 02 0B 01 00 06 00 00 08 00 00 00 00 06
04 01 0F 0A 0A 03 03 08 01 06 01 05 03 01 01 03
01 05 01 03 0A 02 01 00 08 01 01 00 01 02 0A 03
01 01 01 03 01 0A 03 08 01 08 01 0F 03 0D 01 0D
01 08 03 06 01 05 01 06 01 08 01 05 01 06 01 0A
03 08 01 06 01 05 03 01 01 03 01 05 01 03 0A 02
01 00 08 01 01 00 01 02 0A 03 01 01 01 03 01 0A
03 08 01 08 01 0F 03 0D 01 0D 01 08 01 06 01 05
01 03 01 05 01 01 08 04 0B 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Last edited by CasualPokePlayer (2022-03-28 06:25:45)



Board footer

Powered by PunBB
© Copyright 2002–2005 Rickard Andersson