GameRoy: JIT Compilation in High-Accuracy Game Boy Emulation
rodrigodd.github.io
rodrigodd.github.io
> It was designed to be efficient even for short inputs, with performance comparable to non-cryptographic hash functions, such as CityHash, this can be used to prevent denial-of-service attacks against hash tables ("hash flooding") [...]
I did not know this was a thing. What a massive amount of engineering effort is being wasted on protecting against outlandish attacks!
> It is not a cryptographically secure hash, so it is strongly recommended that you do not use this hash for cryptographic purproses. Furthermore, this hashing algorithm was not designed to prevent any attacks for determining collisions which could be used to potentially cause quadratic behavior in HashMaps. So it is not recommended to expose this hash in places where collissions or DDOS attacks may be a concern.
You mentioned that you do a hash map look for each (bank,addr) key. Suggestion which helped us: have this point to an Netey which contains the JIT code but also an index/pointer into the next block which executed last time you executed this block. You can do a simple check to see if this is still valid and fall back to the hashmap lookup. If you're careful about code invalidation (not an issue with ROM) then this can help skip the next lookup.
Congrats!
How wide is a bank number? Even if it's the full 8 bits, that's only 24 bits, which is nothing these days. 64 MB for the full table, assuming 32 bits is enough to cover every offset into the JIT buffer. (Assuming max 4 GB of JIT'd code. If that isn't, perhaps 40 bits would be? 128 MB table, max 1 TByte of JIT'd code.) Would you need a hash table rather than an array?
But of course I would like to avoid using that amount of memory if possible. Maybe I will also take a look at perfect hash mapping someday.
A JIT is something I’d been wondering about for a bit, and this post was eye-opening about the complexities involved (I have no real compiler background).
I have some small, 4fun experience with compilers and I do wonder - how people start with game emulators? what are the basic concepts? what is the easiest hello-world game to start w/?
I had some Computer Organization and Architecture classes in university, and a previously-existing burning desire to understand emulation. I decided that the NES would be a good target; it was the oldest game hardware that I had personal interest in. In 2008, I found as much info as I could about how to structure an emulator, and technical documents about the NES, and started building. I got something basic working in a couple months, and came back to it every couple of years, either to add functionality or experiment with optimizations.
> what are the basic concepts?
A CPU goes through a repeating fetch->decode->execute loop, and mostly communicates with the rest of the system over a "bus", which has some number of address lines (in the NES, 16 address lines provide access to 2^16 or 65,536 addresses), some number of data lines (in the NES, 8 lines for 8-bit values), and some number of control lines (read/write, ready, and others that vary system-to-system). Different devices are connected at different address ranges. They could be RAM, ROM, I/O hardware, etc. So when a CPU is booting, the system is usually designed to expose some ROM at the first address the CPU fetches from.
> what is the easiest hello-world game to start w/?
Chip-8, probably. Space Invaders is a good one too; simple, but using a CPU related to those in a lot of other systems, and a bit less of a toy-scale system than Chip-8.
Anyways cool post!
How come you don't consider conditional branches to be terminating instructions of your basic blocks?
Initially I was doing that, but it was making tight loops too slow. And what I am referring to as a "block" was not a basic block, but a entire compilation unit.