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.

Ads

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

endrift
Member
Registered: 2017-05-24
Posts: 16

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 gave...no 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)

Offline

 

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

AntonioND
Member
Registered: 2014-06-17
Posts: 134
Website

Re: HuC-3 research (WIP)

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

Offline

 

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

endrift
Member
Registered: 2017-05-24
Posts: 16

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)

Offline

 

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

CasualPokePlayer
New member
Registered: 2022-03-28
Posts: 5

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:


Code:

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)

Offline

 

#5 2022-09-12 17:46:55

cuavas
New member
Registered: 2022-09-12
Posts: 3

Re: HuC-3 research (WIP)

I’ve been mucking around with this, and I think it actually makes a fair bit of sense if you think about how the silicon underneath likely works.

First, some observations:
• The HuC-3 controller is only connected to A15-A13 and D6-D0.  Addresses are effectively masked with 0xE000 and data is effectively masked with 0x7F.  Anything written in the most significant bit is ignored by the HuC-3 controller, and it always reads floating bus (generally high).
• This is a conventional setup where the ROM and RAM chips have their data lines and low address lines connected directly to the cartridge bus.  It’s not like the MAC-GBD in the Pocket Camera where data and addresses are routed through logic inside the controller.
• HuC-3 pins 2, 3 and 4 are run out to the hex inverter U5 which drives the audio transducer via a resistor ladder.  This means it can produce eight levels.  Not bad – that’s two whole bits more than the TAMA6 chip has.
• I strongly suspect that if you decapsulated the HuC-3 chip, you’d find that the real-time clock and tone generator functionality are implemented using a 4-bit microcontroller rather than a dedicated real-time clock.
• Timekeeping is likely accomplished just by counting cycles.  The “Watch” part of Nintendo’s Game & Watch line works like this – everything’s done using a 4-bit microcontroller (Sharp SM5A, SM510, SM511 or SM512) with no dedicated real-time clock hardware.  This would explain why it uses minute-of-day and day counters rather than DHMS registers: tt’s easier to do it that way on a microcontroller.
• The “registers” accessible to the host are likely just a window into the microcontroller’s memory.  Consider that the Capcom QSound™ DSP (used for CPS-2, CPS-2, ZN-1 and ZN-2) works this way: it’s an AT&T DSP16 with internal program ROM, and the “registers” written by the host CPU are just the first 256 words of its internal RAM (this is why the sample bank, sound stage position and reverb contribution registers are at unintuitive offsets – it simplifies the DSP program to organise them like that).

With this in mind, the host interface to the microcontroller makes sense:
• The data written to 0x0B is conceptually two values: a 3-bit command in bits 6-4, and a four-bit operand in bits 3-0 (bit 7 is black-holed).
• The data read from 0x0C is conceptually two values: the same 3-bit command in bits 6-4, and a four-bit response in bits 3-0 (bit 7 is floating).
• The command doesn’t so much “leak” from 0xB to 0xC, you’re just seeing the same register.
• Writing 0xB and reading 0xC has no direct side effects.  It just sets or gets the data in the mailboxes.
• Bit 0 of 0xD is a semaphore.  It’s set (1) when the microcontroller is ready to execute a command.  The host clears it (writes 0) to request that the microcontroller execute the command written to 0xB.  The microcontroller detects this, executes the command, possibly sets the response that can be read in bits 3-0 of 0xC, and then sets the semaphore to indicate that it’s ready for another command.

With this in mind, the host program behaviour makes sense:
• Select 0xD (semaphore).
• Wait until bit 0 is set (microcontrolller ready for command).
• Select 0xB (command/operand).
• Write command (high nybble) and operand (low nybble), e.g. 0x62 for command 0x6, operand 0x2.
• Select 0xD (semaphore).
• Write 0xFE, clearing the semaphore so the microcontroller will execute the command.
• Wait until bit 0 is set again (command completed).
• Select 0x0C (command/result).
• Read result/command and use result value from from low nybble.

There are eight possible commands.  We definitely know what five of them do:
• 0x1: Read register and increment address.
• 0x3: Write register and increment address.
• 0x4: Set register address low nybble.
• 0x5: Set register address high nybble.
• 0x6: Execute extended command specified by parameter.

Commands 0x0, 0x2 and 0x7 are unknown.

We definitely know what four of the sixteen possible extended commands do:
• 0x0: Atomically copy real-time clock counters to registers 0-6.
• 0x1: Atomically copy registers 0-6 to real-time clock counters.
• 0x2: Some kind of status request – host software expects response 0x1.
• 0xE: Used to trigger tone generator.

Of course, working out what all the “registers” do is the hard part.  Given it’s likely using a microcontroller core, all kinds of behaviours could be programmed in.

Last edited by cuavas (2022-09-13 02:34:48)

Offline

 

#6 2022-09-13 09:16:37

cuavas
New member
Registered: 2022-09-12
Posts: 3

Re: HuC-3 research (WIP)

Updating the “alarm” time to maintain a fixed offset when updating the current time makes sense, too.  You just need to consider how the game uses alarms.

The “alarm” time is used to set the time until some in-game event when it wants to make you wait a certain amount of real time.  For example, this can be used to enforce a cooling off period after some action.  You don’t want to allow the player to bypass this just by adjusting the clock forward.  For example if it’s supposed to be 10 hours of real time until some in-game event can happen, and the player adjusts the clock forward by nine hours, it should still be 10 hours until the event can happen.

Making the microcontroller maintain the offset between the current time and alarm time means the game doesn’t have to do it.  Given this should only really an issue when adjusting the clock, I don’t know how much of a win that trade-off is, but it still makes sense.

Or alternatively, you can think of it conceptually as more as a kind of countdown timer than an alarm.  You set it for the duration you want, and it maintains the remaining duration even when you update the clock.

Offline

 

#7 2022-09-16 08:52:19

CasualPokePlayer
New member
Registered: 2022-03-28
Posts: 5

Re: HuC-3 research (WIP)

I suspected that there was indeed a microcontroller in there, given how complex this mapper operates. The semaphore makes a bit of sense here, I observed it took some (undeterminable) amount time before it ended up being set again, and if I did not actually wait I did not get expected behavior (I called this the "busy" bit). I would dare believe too the microcontroller has different internal ROMs on different games. I wasn't able to trigger "bing bong" sound that Robopon sometimes plays using my Pocket Family GB2 cartridge. I also see Pocket Family GB2 using different registers for the alarm compared to Robopon. The RTC regs appear to stay static anyways, possibly due to the RTC latching command.

On another note on Pocket Family GB2, it executes command "0x20", some time at bootup. I'm not sure what this does, and seems to be exclusive to Pocket Family GB2? May be again hinting at different internal roms (where that does something in Pocket Family GB2, but not Robopon).

cuavas wrote:

Timekeeping is likely accomplished just by counting cycles.  The “Watch” part of Nintendo’s Game & Watch line works like this – everything’s done using a 4-bit microcontroller (Sharp SM5A, SM510, SM511 or SM512) with no dedicated real-time clock hardware.  This would explain why it uses minute-of-day and day counters rather than DHMS registers: tt’s easier to do it that way on a microcontroller.

This would be interesting, and I suppose would just mean the crystal connected to the mapper is just for all its operation rather than just the RTC. I could suspect that's why it was seemingly random how much time it took for the busy bit to go high anyways, due to the nature of my cart swapping and it would start poking the mapper at a random point in time. Suppose it's in some loop constantly checking the busy bit to determine if to execute the command and where in that loop it is currently at determines how much time it takes until it goes high again?

Last edited by CasualPokePlayer (2022-09-17 07:27:47)

Offline

 

#8 2022-09-16 10:17:13

cuavas
New member
Registered: 2022-09-12
Posts: 3

Re: HuC-3 research (WIP)

CasualPokePlayer wrote:

I suspected that there was indeed a microcontroller in there, given how complex this mapper operates. The semaphore makes a bit of sense here, I observed it took some (undeterminable) amount time before it ended up being set again, and if I did not actually wait I did not get expected behavior. I would dare believe too the microcontroller has different internal ROMs on different games (I called this the "busy" bit). I wasn't able to trigger "bing bong" sound that Robopon sometimes plays using my Pocket Family GB2 cartridge. I also see Pocket Family GB2 using different registers for the alarm compared to Robopon. The RTC regs appear to stay static anyways, possibly due to the RTC latching command.

Oh, that would be really nasty if they have per-game microcontroller programs, but I wouldn’t put it past them.  Is there any difference in the silkscreen on the HuC-3 in Pocket Family GB2?  The one in Robopon doesn’t seem to have any kind of mask number on it, just a date code, e.g. 9842, and an “A” (possibly the revision).

CasualPokePlayer wrote:

This would be interesting, and I suppose would just mean the crystal connected to the mapper is just for all its operation rather than just the RTC.

I expect if you disconnected the crystal, the ROM/RAM banking functionality would still work, but you’d get no response to commands using the B/C/D registers.  Infrared may work with the crystal disconnected, too – the HuC1 doesn’t use a crystal.

CasualPokePlayer wrote:

I could suspect that's why it was seemingly random how much time it took for the busy bit to go high anyways, due to the nature of my cart swapping and it would start poking the mapper at a random point in time. Suppose it's in some loop constantly checking the busy bit to determine if to execute the command and where in that loop it is currently at determines how much time it takes until it goes high again?

Yeah, it’s likely using a simple event loop where it does its housekeeping, polls checks for commands, and spins when it has nothing to do.  Depending on where in the loop you catch it, the time to for the command to complete will vary.

The QSound™ DSP is like this, too.  It plays samples at a fixed rate, and once per sample it will enable interrupts for one instruction to allow a host register write to occur.  If the interrupt handler doesn’t run, it executes a loop that takes the same number of cycles to run as the interrupt handler does.  No matter when you send a command, it will get executed the next time around the sample playback loop.

Offline

 

#9 2022-09-17 07:32:06

CasualPokePlayer
New member
Registered: 2022-03-28
Posts: 5

Re: HuC-3 research (WIP)

https://gbhwdb.gekkio.fi/cartridges/huc3.html

gekkio has some HuC3 carts listed here, which all show only a date code and the letter A on the HuC3 chip. Unsure what A could even be if it's just on all carts, maybe marking a hardware revision with the chip but the early revision never actually shipped (or just very rare if it did ship)?

Last edited by CasualPokePlayer (2022-09-17 07:33:34)

Offline

 

#10 2024-07-16 10:43:22

sfiera
New member
Registered: 2024-07-16
Posts: 4

Re: HuC-3 research (WIP)

Hello. I’ve been doing some reverse-engineering on these carts, mostly on the software side of GBKiss. I’m able to to install software to cartridges, so I built a tool that dumps the 256 bytes of HuC-3 register space. Here’s the result of running it on-device:

https://live.staticflickr.com/65535/53861128980_1a9fd680e5.jpg
Source

Code:

 0123456789ABCDEF
06C4110000177B777
16C4110007040F0E1
2000000EE00021900
393401001C3401001
49A3010014B091021
5C70C2021825D2021
6430E2021C53E2021
7D4B0302140F7A731
83335833133358338
93533313335338331
A3335833133358338
B3533313335318338
C3835383A3A388335
D3533335183B00000
E0000000000000040
F0FA710B010000008

This is in Pocket Family GB. Before grabbing this, I also loaded the DLC ringtone (Saita Saita) onto the cartridge and set it as the alarm. You can clearly see the ringtone content from $7A to $DB. So, ringtone transfer space appears to be at least one more thing that this memory can be used for.

The source for this tool, such as it currently exists, is huxplore.asm.

Last edited by sfiera (2024-07-25 09:45:30)

Offline

 

#11 2024-07-18 09:03:48

sfiera
New member
Registered: 2024-07-16
Posts: 4

Re: HuC-3 research (WIP)

Hmm, did I actually enable the alarm or did I only run the sound test? I set it again, for 21:30, and now at $28 I see A0541987. $50A / 60 is 21.5, so it seems likely that $28-$2A is the configured alarm time. I don’t see A05 anywhere else.

Given how $28-$77 repeat similar data, I wonder if it’s a list of 8 alarms, with 3 bytes for the time, and 5 bytes for other flags (like if the alarm is one-shot).

If that hypothesis is correct, my next alarm is at $528—right at 10PM.

(10 minutes pass)

Nope, nothing. Oh well.

Changed it to play Silent Night at 20:15 and now the bytes at $28 are FB441987. $4BF / 60 is 20.25, so that checks out as the location of the alarm time. Silent Night is like Saita Saita in that the tune is transferred to the mapper, so it’s not surprising that the 41987 part matches.

Changed to the basic “alarm 1” at 21:30 and the data is A0541921. $419 is the same, but the final two bytes differ.

Trying all of the alarms:
めざましおん1: $21
めざましおん2: $61
ピンポンおん1: $31
ピンポンおん2: $E1
ピンポンおん3: $B1
ピンポンおん4: $F1
ほうかごうチャイム: $87
きゅうきゅう: $87
きよし このよる: $87
Alarm off: $00

This suggests that the final 1 indicates the tone is built into the mapper and 7 means it’s programmed from the ROM. Some of the other hypothesized alarms use $01 which might be a ringing phone which isn’t available in the alarm clock feature.

I hadn’t realized that the Ambulance tone (きゅうきゅう) was in the ROM. I’d found C6 D9 A8 42 43 B0 in the Pocket Family ROM but it looked too short to be an alarm. Still not sure exactly how to interpret those bytes, as it’s a “high, low” sequence repeated 7 times.

Last edited by sfiera (2024-07-25 00:50:23)

Offline

 

#12 2024-07-20 05:10:02

sfiera
New member
Registered: 2024-07-16
Posts: 4

Re: HuC-3 research (WIP)

Earlier today, I checked the cartridge. The date/time then was $533510 (13:41 on day 21). One of the 8-byte blocks was $42451001, and indeed I got a phone call at 17:40. The day number matches this time—I don’t think it did when I was expecting it in the previous post. Now, that line has been replaced by $42461001. Same time tomorrow? The only remaining blocks with day $510 (?) are my configured alarm for 21:30 and another with value $C3451001. That would be 18:04, just a few minutes from now.

Yep! Got it this time. And that line has now been replaced by $C3461001, again shifted to tomorrow. I wonder if successfully receiving an alert fixes the time. I suppose if it keeps alerts you receive and re-randomizes alerts you miss it will fall into a groove for your schedule.

Offline

 

#13 2024-07-23 10:19:32

sfiera
New member
Registered: 2024-07-16
Posts: 4

Re: HuC-3 research (WIP)

Added a feature to HUXPLORE to trigger extended commands. Now, Start triggers the extended command corresponding to the current column. I was able to use extended command $0 and $E. I suppose I should dump the register somewhere to test $2. Interestingly, even though I changed the alarm to one of the built-in tones, when I triggered $E, it played the most recent programmable tone I had configured.

Save file: pokefam-huxplore-2024-07-23.sav

Offline

 

Board footer

Powered by PunBB
© Copyright 2002–2005 Rickard Andersson