• AVincentInSpace
    link
    fedilink
    English
    arrow-up
    5
    ·
    edit-2
    1 month ago

    90% of the knowledge here came from looooooong rabbit holes on https://nesdev.org as well as some YouTube videos by The Gaming Historian. If you’re interested in the inner workings of 8-bit systems that aren’t the NES, The 8-Bit Guy on YouTube has some great visual walkthroughs. Also Connections Museum has some really cool in-depth looks of old-school electromechanical telephone switching equipment and the stuff that engineers in the 1930s cooked up to make telephone switching automatic before the concept of an electronic computer was a twinkle in IBM’s eye. Also also, if you haven’t discovered Technology Connections yet, I cannot recommend it enough.

    Also unrelated, but I mentioned in that massive comment that the dual-bus architecture allows the NES to never show a loading screen but didn’t elaborate on how, and I wanna do that. Loading data is the process of copying it from some slow storage medium, like a cartridge, hard drive, or (horror of horrors) optical media into RAM, and loading screens arise from the fact that said storage mediums often take quite a while to spit out all that data and the user needs something to let them know the program isn’t just frozen. Since all data on the NES is read directly from the cartridge as it’s needed, it never has to load anything. All the data for the game is always right there. Unfortunately, this technique is all but useless today – the NES’s CPU was very slow (1.79 megahertz – for reference, no CPU slower than 1000 megahertz has been manufactured in over a decade), allowing it to get away with reading directly from the storage medium. Modern CPUs need to access data orders of magnitude faster than the fastest flash chips available, and actual mask-ROM like the NES used is so expensive to manufacture nowadays that they’re basically never seen outside of the firmware powering your CPU. Besides, never ever ever having even one microsecond of loading time is not really necessary anyway, and there are techniques that work on modern CPUs to get something like that without actually having it. As an example, here’s some more modern trivia for you: virtually all modern operating systems use a techique called memory mapped files to launch their local equivalent of an .exe file. Essentially, all modern CPUs (at least, the ones intended to run an operating system as opposed to a single gigantic firmware program) have a memory mapper unit, which essentially allows the CPU to pretend that it has more RAM than it does. Whenever a program tries to access a block of memory that doesn’t actually exist, it will trigger what’s called a page fault, where it will stop that application for a while, run a special function in the operating system to figure out what data is supposed to be there, put that data somewhere in physical memory where the program can access it, and then resume the program. Memory-mapping a file is when you connect a file to this system, essentially asking the operating system to pretend like it has the entire contents of the file loaded into an area of RAM, but only when someone actually goes to access that RAM does the operating system pause the application that asked for it, open the file, load just the portion it needs right at that minute, and resume the application again. This can lead to major speedups: most programs don’t need the entire contents of their EXE file right when they start up – they don’t need the code that finds out what text you have highlighted and copies it to the clipboard, for example, before you press Ctrl+C. Memory-mapping the EXE file allows the operating system to wait to load the code that does that off the hard disk until the program actually needs it, and thus have the whole program running before it’s finished loading the EXE file. If the user closes the application before ever pressing Ctrl+C, that portion of the EXE file might never get loaded! (Which bits get loaded is often not that granular, and the code for Ctrl+C specifically is small enough that it’s likely to get loaded anyway along with something else, but you get the idea.)

    Programs can use this technique to “lazy-load” their internal data files (or files you create yourself) too, but this unfortunately doesn’t have as broad an application as you’d think. It only really helps when you don’t need the entire file at once, and when the file is large enough that loading it into RAM all at once isn’t feasible. I’m currently working on one such program: a desktop client for a furry imageboard. I wasn’t satisfied with the search features the site had, so I built my own search algorithm that supported more granular tag constraints and rigged it up to the full database dump available from the site. Loading the entire database into RAM uses over a gigabyte of RAM, and that’s not going to fly if I want to port it to mobile devices, so I’m currently working on setting up memory mapping so I can only have the database loaded while I’m doing a search and let the OS swap it out when my app isn’t running.