3

Consider STL's unordered_map. The same template class is used for both hashtables that are generated at runtime, and hashtables comprised of compile-time constant values. While recent versions of C++ add constexpr support it does not extend to more complex operations involving the free-store, consequently building a hashtable from compile-time constants must still happen at runtime, making it just as expensive as building any other hashtable at runtime.

Ideally, a perfect compiler would see this and pre-evaluate the hashtable construction at compile-time and embed it directly within the program.

It got me thinking about retrocomputing and microcontrollers which would conceivably have their software written in C or C++ given the development cost of assembly: these environments often have limited RAM but plenty of ROM, and those in-memory data structures (such as an unordered_map) certainly could be pre-generated and persisted to ROM all at compile-time.

As mentioned, the C++ language does not support this for non-trivial constexpr. I understand you could hack this together assuming you can base your complex data-structure on an array-type or reduce it down to a constexpr - or write it all in assembly and manually setting each byte of the structure in a hex-editor and hope it matches the compiler's representation of your struct types (for example).

How is it done today then? And how was it done in the days of 16-bit and 32-bit games consoles where RAM and CPU cycles were at a premium? I'm especially keen to learn about ROM cartridge-based games where the structures are immediately accessible as raw memory.

Dai
  • 141,631
  • 28
  • 261
  • 374
  • RAM is much faster than flash and eeprom. Typically you want your program stored in flash, your persistent data in eeprom and your runtime data in RAM.. – Sid S Jun 28 '18 at 03:08
  • 2
    It probably is/was done by not using C++. – user253751 Jun 28 '18 at 03:14

3 Answers3

2

unordered_map is a highly inefficient type of data structure you'd never use in that kind of setting. More reasonable things like arrays and trees are easy to do with static initializers. If it gets more complex, you write a program to generate C containing the wanted static initializers and run it on a system that can handle it.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • 2
    What is it about unordered_map that makes it inefficient in this kind of setting? – Jeremy Friesner Jun 28 '18 at 04:19
  • 2
    It's a mutable hash table, which requires a fairly heavy implementation and has largish runtime costs. If you really need hash table functionality, it's trivial to write immutable ones that can be used in-place. A very good example would be the symbol tables used in object files and dynamic-linked programs/libraries. But for such constrained environments as you asked about, it's better not to need this kind of mapping at all, and instead use pointers/indices everywhere instead of some other key that has to be mapped to an address. – R.. GitHub STOP HELPING ICE Jun 28 '18 at 14:12
2

In C++ microcontroller systems, all constructors of objects with static storage duration are called during boot-up, around the point where .data and .bss etc segments are initialized, before main() is called. This is one of several reasons why C++ tend to be unsuitable for such systems - it actually executes application code during the start-up phase.

The kind of applications you mention, like old video games, most likely had tables pre-calculated and written in ROM. I doubt that C++ was used much for such games, or if it was, they used a restricted sub-set of the language.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 1
    So it is quite common to see embedded C++ code written by quacks/"PC programmers", where you have some heavy data structure initialization code executing before fundamental hardware of the MCU is set up (*cougharduinocoughcough*). Even before the internal system clock is initialized... And then they come online on SO and scream at everyone who is claiming that C is much faster than C++... – Lundin Jun 28 '18 at 13:29
  • Don't understand the point of your reasoning. You are blaming the language for elections that the programmer does. The language provides you with different mechanisms and is up to you to choose those that suit your needs. In C++ you can perfectly define constant compile-time-generated data to use in the ROM of any embeded system, as the question asks. If you have a problem with static object initialization (which I doubt it represents a general problem, but one for concrete cases), just use other mechanisms. – ronaldo Mar 07 '19 at 18:26
0

Back in "Ye Olden Days" - early 80's and 90's, RAM was very expensive, flash was both expensive and unreliable, but ROM, particularly masked ROM was cheap.

Video game consoles usually executed the games from ROM using a tiny amount of RAM as "scratchpad" memory. For example, the original NES console had 2048 bytes of RAM

Compiled languages weren't used in game development, so to answer your original question, data structures were initialized copying an empty structure from ROM to RAM