v6502
The MOS 6502 Virtual Machine and Toolchain Infrastructure
Memory Map Cache

Background

The memory map cache consists of three arrays of host-width pointers that are the length of the entire memory in bytes. That is to say, for a 64 kilobyte virtual memory object (the maximum addressable) you will get a 65536 length array of pointers to v6502_readFunction's, a same-sized array of v6502_writeFunction's, and a same-sized array of context pointers. Each pointer being the word size of the host architecture. This is a classic space-time tradeoff that reduces memory map lookups to the subscripting of a C-array, rather than the traditional linked list traversal that was used in v6502 earlier on. On many architectures, this requires only adding a relative offset to the existing branch instruction that will end up calling the function. The time overhead is slightly increased during v6502_map calls, since it has to update the map, but only the portions of the map that change are updated, and the map is not intended to be changed rapidly during runtime, so the performance hit should be negligible.

Caveats

The large memory overhead is the obvious downside. This is somewhat mitigated by the fact that read, write, and context caches are allocated separately, and lazily. In the case where there are only context-free write-trap mappings, this saves two-thirds of the cache size.

A more important and much more dangerous caveat is that the map cache should not be toggled. There is currently no cache rebuild function (although one will probably come eventually). When map caching is disabled, maps will not be added to the caches (which will also not be dynamically allocated). So, if mappings are made with caching off, and then caching is turned on, the cache will be hit without a hard lookup, causing cache misses that trick the mapper into thinking that the mappings don't exist at runtime. This can all be avoided by setting the map caching as early as possible, and not altering it later.