Super Hucard
This place can be thought as the public side of the project called Super Hucard
and maintained by Benjamin Quinn.
The goal is to make a pc engine native cd application which compiles several
roms on it so that they are playable on real pc engine systems.
To be able to enjoy it, you'll need a cd enabled pc engine system, either japanese
or american. You'll then have to burn a cd based on the downloads below and play the
resulting cd-r.
This project is just a technical demonstration of what we can now achieve
on pc engine. Don't expect it to be usable for all games, nor bigger games, etc..
It's a just a proof of concept and a technical challenge that was fun to face.
So, now it's more or less useable, it's publicly available for pc engine fans.
Of course you shouldn't sell it, claim it's ours nor blame anyone if your dog cites Socrate
quotes every other minuts because of what you found here.
Status
20190224 : Add local copy of the project, most mirrors being down.
20030827 : First public release. About 75 games works.
200306 : First working version. About 60 games works.
How does it work ?
Without entering too much in details, here are the concepts applied here. First, the
cd enabled pc engine systems have some RAM usable at runtime. This is the place where
data coming from the cd are placed and used as code, graphics, etc... Starting from
version 3.0 (hence Super Cd system 3.0 and the Arcade Cards), there are 2 Mega bits
available. This room is enough for storing a whole hucard in it, making the system
very close of the state where a hucard is inserted in the console.
What are the differences ?
Well, a hucard has data located from the physical bank 0 and all operations at
runtime expect this mapping to be respected (to the exception of a few nice games). If
we're loaded a hucard content in the cd system card ram, the data starts at bank 0x68.
So when an operation saying "make bank 4 available in ram at location 0x4000" is
executed, it makes the bank 4 of the cd system (the cd player, game booter, etc...)
available at location 0x4000 and not the bank 4 of our hucard since it's located
at 0x68 + 4.
How to make operations dealing with bank aware of this 0x68 bank offset ?
In our task, we have some luck, there's just one operation which is problematic.
It's TAM, an operation which takes an argument, a field of bit, indicating the
location in RAM where to map a physical bank (Actually, it could point at
several locations at once, but the normal use makes such that there's only bit
set at once). It uses the value of the register A to know the value of the physical bank.
Well, ok, we only have to make sure that A got incremented by 0x68 before every TAM.
Easy.
Easy ? Not really. You can't insert an instruction in a bytecode without breaking
everything. The problem is that jumps, calls, etc... will be fooled if you insert
extra data. The matter is that we can eventually alter the code but not changing the
length of instructions. Now, we have to check how the value of the register A is set.
Hopefully, it's mostly loaded with a fixed value just before a TAM. That's quite a
perfect situation, we can simply add 0x68 to the argument in the code and A will
be incremented of 0x68 at runtime. Sometimes, A is incremented from another value
of physical bank. If we assume we managed to catch others TAM argument, the incrementation
will retains the 0x68 offset, being a relative alteration of the argument. Still,
there are a few tricky things, like values loaded dynamically from the memory where
the location is also loaded from the memory at runtime. And eventually they are
computation on the register A before having it used which makes this way of
doing unusable (imagine "Load A with the physical bank at 0x4000 (normally 2), double
A (4) and map the bank indicated by A (4) at 0x6000" with A been incremented by 0x68,
the final value would be (0x68 + 2) * 2 instead of 0x68 + (2 * 2) ). On another hand,
to detect the usual pattern (loading A with immediate value then apply TAM) we can only
rely on a basic expression of 4 bytes such that 2 are fixes (opcode of the A loading and
TAM), 1 is under a given value (the argument of the loading of A) and the last only
have one bit set. As it's not very sharp, it was easy to be fooled and "patch" piece
of data which aren't to be patched. It could lead to crashes or corruption in graphics,
sound, etc...
While the static approach works in a few number of case, it shows its limits.
One day, by checking at pc engine internals stuff, Ben noticed that the BRK opcode,
which is normally used to indicate an error but in fact is a software interruption,
ie an operation which jumps to a subroutine, located via a fixed location in RAM. But
unlike usual soft interruption opcodes, it takes an argument and set the return point
of the interruption handler to the opcode after this argument, as if it was a 2-bytes
long opcode. Hmm, doesn't it sounds like similar to our dear TAM opcode ? Of course.
Now what, we can replace all TAM occurence by a jump to a subroutine and have an argument
handy for our subroutine (well, in a very tricky way, but still...). As this subroutine
is normally an error one, or used to debug, in games, it's unused, we can safely put
a custom handler in it. What will it do ? As you may guess, it will reconstruct a TAM
from the BRK argument using self modifying code inline and alter the value of A by
adding 0x68 when needed (yes, indeed, sometimes, it references absolute, system bank
where we shouldn't add 0x68). We then call our custom TAM and we can even restore the old
value of A if we want.
In order to catch all relevant TAM and only them, the best way is to detect them
at runtime. So, as Hu-Go! is a working GPL pc engine emulator, the best was to
integrate the code to detect TAM in it and convert all TAM opcode into BRK opcode.
Before this, we had redirected statically the BRK handler to a subroutine we had
inserted in some free space (found in almost every game, the handler is just about
40-50 bytes long).
Here is it, thanks to this dynamic handling of A incrementation, we don't have to
worry about the way A is computed, as we're handling this at the very latest moment.
Still, since TAM are patched at runtime, to be able to run the game fully, all TAM
should have been catched when playing the special version of Hu-Go!. Still, using a
light static detection along with this dynamic one should lead to a very large coverage
of TAM with few efforts but it hasn't been done yet. Just a few minutes with Hu-Go!
on each game generaly (which is often enough as many games reuses the same TAM operation
all the time).
Download
(2019/02/24 update) After all those years, the mirrors went down, so here is a local copy now that bandwidth and such allows it.
Full version.
Schmorp proposed a mirror for all files on a high speed server in Europe. Big thanks to him.
Full version. This archive contains all what you want in a full cd dump.
Short cooked ISO file. This file is the bare minimum to enjoy Super Hucard. It can be complemented with the following file.
Audio track file. This file is the music track of the Super Hucard, which can be used along with the ISO file. The full version already includes this.
Areios offered a mirror for the full version, you can
grab it here. Thanks a
lot
Squaresoft74 is also hosting the files on his site.Thanks to
him.
Download Super Hucard Iso - ed2k link (Direct link), OS : none added on 2003-09-02
Download Super Hucard Ogg - ed2k link (Direct link), OS : none added on 2003-09-02
Download Super Hucard Full - ed2k link (Direct link), OS : none added on 2003-09-02
|
Original design work by Nostromo
|
|