Uploaded March 2021 | Updated September 2026, 2 weeks ago
In this installment of the Fantasy Game Console Series (an extension to the 16-Bit Virtual Machine Series), we're integrating the system. We'll be covering building out the memory mapped devices, integrating the CPU, taking and mapping input to the address space, and wiring in the graphics pipeline and execution model. We explore the data format for games by setting up all the required data and code in memory, including configuring the interrupt vector and handlers. As a bonus, we implement a caching solution for graphics which greatly improves the performance of drawing and thus of the entire fantasy game console!
The fantasy console serves as a very simple model for an emulator of a classic game console like the NES or the GameBoy, only without all the tricky real world details and limitations that come with such systems. It allows us to contextualise all the topics we've been learning about while building the VM, and gain some understanding about how it must have been to be a programmer in the days of true resource constraint!
00:00 - Improving graphics performance with caching
03:10 - Writing the caching code
09:00 - Testing the cache performance
09:40 - Discussing the offscreen changes
12:13 - Creating memory mapped devices
13:52 - Setting up tile memory
14:47 - Setting up background and foreground memory
16:12 - Setting up the sprite table
16:57 - Building the memory mapped controller input device
17:55 - Caching tiles
18:27 - Writing some assembly code to bootstrap the machine
19:48 - Setting up the interrupt vector
20:23 - Initialising a CPU instance
20:40 - Setting up the game loop and graphics pipeline
=[💻 Changes Made Offscreen 💻]=
__New Instructions__
A few new instructions we're added to the VM, and all were to make it easier to move 8 bit values around, instead of the native 16 bit values. These are:
- move 8-bit literal value to register
- move 8-bit value in memory to register
- move low 8-bits of register to memory
- move high 8-bits of register to memory
- move 8-bit value, pointed to by register, to register
- move low 8-bits in register to address pointed to by register
__CreateRAM / CreateROM__
The old function `createMemory` has been replaced by 2 new functions: `createRAM` and `createROM`. `createRAM` is essentially the same as the older function, but adding more to the exposed interface (the interface being the DataView). Namely, it adds some new methods:
- load: which takes an array of bytes and places them into the memory buffer
- slice: which returns a continuous subset of the bytes contained in the memory buffer
The `createROM` function is like `createRAM` in every way, except that the exposed `setUint16` and `setUint8` methods do not actually set data - therefore a programmer writing assembly code for this system cannot alter what is in the memory. The emulator, however, can still use the `.load` method to set the initial value of the device. You can imagine that this will be done when the emulator decodes a "cartridge ROM".
As mentioned in the video, the controller input data is also modeled as a ROM - though it's not actually a ROM in the traditional sense. What we're really doing is using the interface to stop the programmer writing to this protected memory space, while using the `.load` method to update the input values every frame.
__Memory Mapper__
A small change that allows us to provide a start address and a size, instead of a start address and an end address. It's a better interface, (a) because you tend to think of devices in terms of their size anyway, and (b) because you're never sure whether start/end arguments are inclusive of the final element!
__Assembler__
This one was pretty self explanatory: The functionality of the assembler was simply wrapped up in a function, which instead of finding it's code directly in the file (which we did during testing), instead takes it from the argument. The offset argument (entry point is probably a better name), simply allows us to "position" the code in memory, by calculating the addresses of all labels and other symbols in reference to this initial offset.
=[ 🔗 Links 🔗 ]=
🎞 Series Playlist: youtube.com/playlist?list=PLP29wDx6QmW5DdwpdwHCRJsEubS5NrQ9b&playnext=1&index=1
💌 Updates to your inbox: tinyletter.com/lowleveljavascript
🗣 Discord: discord.gg/FPWaVgk
⭐️ Patreon: patreon.com/lowleveljavascript
💻 Github Repo: github.com/LowLevelJavaScript/16-Bit-Virtual-Machine
In this installment of the Fantasy Game Console Series (an extension to the 16-Bit Virtual Machine Series), we're integrating the system. We'll be covering building out the memory mapped devices, integrating the CPU, taking and mapping input to the address space, and wiring in the graphics pipeline and execution model. We explore the data format for games by setting up all the required data and code in memory, including configuring the interrupt vector and handlers. As a bonus, we implement a caching solution for graphics which greatly improves the performance of drawing and thus of the entire fantasy game console!
The fantasy console serves as a very simple model for an emulator of a classic game console like the NES or the GameBoy, only without all the tricky real world details and limitations that come with such systems. It allows us to contextualise all the topics we've been learning about while building the VM, and gain some understanding about how it must have been to be a programmer in the days of true resource constraint!
00:00 - Improving graphics performance with caching
03:10 - Writing the caching code
09:00 - Testing the cache performance
09:40 - Discussing the offscreen changes
12:13 - Creating memory mapped devices
13:52 - Setting up tile memory
14:47 - Setting up background and foreground memory
16:12 - Setting up the sprite table
16:57 - Building the memory mapped controller input device
17:55 - Caching tiles
18:27 - Writing some assembly code to bootstrap the machine
19:48 - Setting up the interrupt vector
20:23 - Initialising a CPU instance
20:40 - Setting up the game loop and graphics pipeline
=[💻 Changes Made Offscreen 💻]=
__New Instructions__
A few new instructions we're added to the VM, and all were to make it easier to move 8 bit values around, instead of the native 16 bit values. These are:
- move 8-bit literal value to register
- move 8-bit value in memory to register
- move low 8-bits of register to memory
- move high 8-bits of register to memory
- move 8-bit value, pointed to by register, to register
- move low 8-bits in register to address pointed to by register
__CreateRAM / CreateROM__
The old function `createMemory` has been replaced by 2 new functions: `createRAM` and `createROM`. `createRAM` is essentially the same as the older function, but adding more to the exposed interface (the interface being the DataView). Namely, it adds some new methods:
- load: which takes an array of bytes and places them into the memory buffer
- slice: which returns a continuous subset of the bytes contained in the memory buffer
The `createROM` function is like `createRAM` in every way, except that the exposed `setUint16` and `setUint8` methods do not actually set data - therefore a programmer writing assembly code for this system cannot alter what is in the memory. The emulator, however, can still use the `.load` method to set the initial value of the device. You can imagine that this will be done when the emulator decodes a "cartridge ROM".
As mentioned in the video, the controller input data is also modeled as a ROM - though it's not actually a ROM in the traditional sense. What we're really doing is using the interface to stop the programmer writing to this protected memory space, while using the `.load` method to update the input values every frame.
__Memory Mapper__
A small change that allows us to provide a start address and a size, instead of a start address and an end address. It's a better interface, (a) because you tend to think of devices in terms of their size anyway, and (b) because you're never sure whether start/end arguments are inclusive of the final element!
__Assembler__
This one was pretty self explanatory: The functionality of the assembler was simply wrapped up in a function, which instead of finding it's code directly in the file (which we did during testing), instead takes it from the argument. The offset argument (entry point is probably a better name), simply allows us to "position" the code in memory, by calculating the addresses of all labels and other symbols in reference to this initial offset.
=[ 🔗 Links 🔗 ]=
🎞 Series Playlist: youtube.com/playlist?list=PLP29wDx6QmW5DdwpdwHCRJsEubS5NrQ9b&playnext=1&index=1
💌 Updates to your inbox: tinyletter.com/lowleveljavascript
🗣 Discord: discord.gg/FPWaVgk
⭐️ Patreon: patreon.com/lowleveljavascript
💻 Github Repo: github.com/LowLevelJavaScript/16-Bit-Virtual-Machine
![Frogger In Assembly: Fantasy Console Part 3
In this installment of the Fantasy Game Console Series (an extension to the 16-Bit Virtual Machine Series), were creating a game in assembly! Specifically, were trying to recreate the mechanics of frogger, a classic which should a bunch of interesting challenges and problems to solve.
The fantasy console serves as a very simple model for an emulator of a classic game console like the NES or the GameBoy, only without all the tricky real world details and limitations that come with such systems. It allows us to contextualise all the topics weve been learning about while building the VM, and gain some understanding about how it must have been to be a programmer in the days of true resource constraint!
=[ 🔗 Links 🔗 ]=
🎞 Series Playlist: https://www.youtube.com/playlist?list=PLP29wDx6QmW5DdwpdwHCRJsEubS5NrQ9b&playnext=1&index=1
💌 Updates to your inbox: https://tinyletter.com/lowleveljavascript
🗣 Discord: https://discord.gg/FPWaVgk
⭐️ Patreon: https://www.patreon.com/lowleveljavascript
💻 Github Repo: https://github.com/LowLevelJavaScript/16-Bit-Virtual-Machine/ Frogger In Assembly: Fantasy Console Part 3](https://i.ytimg.com/vi/UkPB1ukAgbI/mqdefault.jpg)
![Addition In Digital Logic [The Bits And Bytes Of Binary ep. 4]
This mini series is all about binary. Over the course of the series, well be building a library that gives us precise control of every bit and operation.
Youll learn how the logical and arithmetic operations work, how different kinds of numbers are encoded, how to set, clear and toggle bits, and how we can create representations of structured binary data.
1. Bits
2. Operations
3. Unsigned Numbers
4. Addition
5. Zero Extension
6. Twos complement
7. Overflow Addition and Sign Extension
8. Shifting
9. Setting, Clearing, and Toggling Bits
10. Endianness
11. Structures
=[ 🔗 Links 🔗 ]=
💌 Updates to your inbox: https://tinyletter.com/lowleveljavascript
⭐️ Patreon: https://www.patreon.com/lowleveljavascript
🎥 Playlist: https://www.youtube.com/playlist?list=PLP29wDx6QmW47oPsNBFNEi_SYTOLDJXqQ
💻 Github Repo: https://github.com/LowLevelJavaScript/The-Bits-And-Bytes-Of-Binary
=[ 🎶 Music 🎶 ]=
Game Plan - Bad Snacks Addition In Digital Logic [The Bits And Bytes Of Binary ep. 4]](https://i.ytimg.com/vi/VMOyiYRFm8A/mqdefault.jpg)
![Hardware RISC-V CPU in TypeScript: First Steps
=[ 🔗 Links 🔗 ]=
🎥 Series Playlist: https://www.youtube.com/watch?v=ER7h4ZTe19A&list=PLP29wDx6QmW4sXTvFYgbHrLygqH8_oNEH
💌 Updates to your inbox: https://tinyletter.com/lowleveljavascript
🗣 Discord: https://discord.gg/FPWaVgk
⭐️ Patreon: https://www.patreon.com/lowleveljavascript
💻 Github Repo (emulator): https://github.com/LowLevelJavaScript/RISC-V-Emulator Hardware RISC-V CPU in TypeScript: First Steps](https://i.ytimg.com/vi/Vat4p2idDOA/mqdefault.jpg)
![Cryptographically Signed Firmware :: Bare Metal Programming Series 14
In the final episode of the Bare Metal Programming Series, were implementing signed firmware updates! Everything from using AES in the CBC-MAC configuration in the bootloader, to writing a signing application, to updating the firmware updater to work with the new images.
And of course, where would we be without a false celebration before the ultimate solution 😉
=[ 🔗 Links 🔗 ]=
AES Blog Post: https://github.com/francisrstokes/githublog/blob/main/2022/6/15/rolling-your-own-crypto-aes.md
Spec: https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.197.pdf
Deeper justifications and analysis: https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/aes-development/rijndael-ammended.pdf
Attacking AES with power analysis: https://www.youtube.com/watch?v=5Hn2D5lrzVo
🎥 Series Playlist: https://www.youtube.com/playlist?list=PLP29wDx6QmW7HaCrRydOnxcy8QmW0SNdQ
🗣 Discord: https://discord.gg/FPWaVgk
⭐️ Patreon: https://www.patreon.com/lowleveljavascript
💻 Github Repo: https://github.com/lowbyteproductions/bare-metal-series Cryptographically Signed Firmware :: Bare Metal Programming Series 14](https://i.ytimg.com/vi/Veu_fDPecM8/mqdefault.jpg)
![Designing A Packet Protocol :: Bare Metal Programming Series 7.1
In this episode of the bare metal programming series, were going over the design of a packet protocol, that runs on top of the UART physical layer weve been building up over the last few videos.
This protocol consists of a binary packet format, which includes a mechanism for validating the integrity of a packet, as well as a state machine for processing incoming packets, validating them, and automatically requesting retransmission if the packet fails the check.
=[ 🔗 Links 🔗 ]=
🎥 Series Playlist: https://www.youtube.com/playlist?list=PLP29wDx6QmW7HaCrRydOnxcy8QmW0SNdQ
🗣 Discord: https://discord.gg/FPWaVgk
⭐️ Patreon: https://www.patreon.com/lowleveljavascript
💻 Github Repo: https://github.com/lowbyteproductions/bare-metal-series Designing A Packet Protocol :: Bare Metal Programming Series 7.1](https://i.ytimg.com/vi/VzOPdQukW1Q/mqdefault.jpg)
![Ints, Uints, and Parsing an IP Packet Header [Parser Combinators From Scratch] Episode 7
In this episode we finish up with binary parsing by building (almost) arbitrary precision integer and unsigned integer parsers, as well as a parser for extracting ascii strings.
Apologies for my voice in this one - I recorded at the tail end of a chest infection at 6am and it turns out thats when my voice is at its most Barry White.
=[ ℹ About ℹ ]=
During this series we will develop an understanding of the concept of parsing, and build our own parser combinator system from scratch. The system we build will be capable of parsing both binary and text data. Well make use of both object-oriented and function programming principles to develop an effective and intuitive library.
=[ 🔗 Links 🔗 ]=
- ⭐️ Patreon: https://www.patreon.com/lowleveljavascript
- 💌 Updates to your inbox: https://tinyletter.com/lowleveljavascript
- Playlist: https://www.youtube.com/watch?v=6oQLRhw5Ah0&list=PLP29wDx6QmW5yfO1LAgO8kU3aQEj8SIrU
- Github Repo: https://github.com/LowLevelJavaScript/Parser-Combinators-From-Scratch
- LLJS Subreddit: https://reddit.com/r/lowleveljavascript
- IP Packets: https://en.wikipedia.org/wiki/IPv4#Packet_structure
- IP Packet Breakdown: http://www.cs.miami.edu/home/burt/learning/Csc524.092/notes/ip_example.html
- Ben Eater: https://www.youtube.com/user/eaterbc
- Twos Complement: https://en.wikipedia.org/wiki/Two%27s_complement
- Signed Binary: https://en.wikipedia.org/wiki/Signed_number_representations#Signed_magnitude_representation_(SMR) Ints, Uints, and Parsing an IP Packet Header [Parser Combinators From Scratch] Episode 7](https://i.ytimg.com/vi/X1sKg0_r4JM/mqdefault.jpg)
![A parser for every instruction? (16-Bit VM in JavaScript 010)
In this episode we build a parser that can handle every instruction that the VM currently supports.
=[ ℹ About ℹ ]=
This series is all about building a powerful virtual machine in JavaScript with the following features:
- A flexible, extensible, register-based virtual machine
- Support for signed, unsigned and floating point operations
- A call stack
- Interrupt capabilities
- Ability to do memory mapping for IO
- An assembly language with macro and module support
- A higher level, C like language. Well use and expand the library from the parser combinators from scratch series
- And finally, to be able to take the whole thing into the browser and extend it to create a sort of fantasy console - an emulator for a machine that never existed
- 💌 Updates to your inbox: https://tinyletter.com/lowleveljavascript
- ⭐️ Patreon: https://www.patreon.com/lowleveljavascript
- Series Playlist: https://www.youtube.com/playlist?list=PLP29wDx6QmW5DdwpdwHCRJsEubS5NrQ9b&playnext=1&index=1
- Github Repo: https://github.com/LowLevelJavaScript/16-Bit-Virtual-Machine
- arcsecond: https://github.com/francisrstokes/arcsecond
- Parser Combinators From Scratch: https://www.youtube.com/watch?v=6oQLRhw5Ah0&list=PLP29wDx6QmW5yfO1LAgO8kU3aQEj8SIrU A parser for every instruction? (16-Bit VM in JavaScript 010)](https://i.ytimg.com/vi/YYZopr1dr_E/mqdefault.jpg)
![What is a spinlock? //Source Dive// 002
In this installment of //Source Dive//, were back in the xv6 OS codebase, exploring timers, the early boot process, and a very useful concurrency primitive: The Spinlock!
=[ 🔗 Links 🔗 ]=
🐋 RISC-V Docker Image: https://github.com/francisrstokes/rv-toolchain-docker/pkgs/container/rv-toolchain-docker
🎥 Series Playlist:
🗣 Discord: https://discord.gg/FPWaVgk
⭐️ Patreon: https://www.patreon.com/lowleveljavascript
💻 Github Repo: https://github.com/mit-pdos/xv6-riscv What is a spinlock? //Source Dive// 002](https://i.ytimg.com/vi/ZE9OODanrDA/mqdefault.jpg)
![Ones and Zeros: Binary Part 1 [Parser Combinators from Scratch] Episode 6
In this episode the parser combinator system is turned on binary data. We learn how to specify and extract individual bits, Typed Arrays, ArrayBuffers and DataViews, and about important concepts like bit ordering.
=[ ℹ About ℹ ]=
During this series we will develop an understanding of the concept of parsing, and build our own parser combinator system from scratch. The system we build will be capable of parsing both binary and text data. Well make use of both object-oriented and function programming principles to develop an effective and intuitive library.
=[ 🔗 Links 🔗 ]=
- ⭐️ Patreon: https://www.patreon.com/lowleveljavascript
- 💌 Updates to your inbox: https://tinyletter.com/lowleveljavascript
- Playlist: https://www.youtube.com/watch?v=6oQLRhw5Ah0&list=PLP29wDx6QmW5yfO1LAgO8kU3aQEj8SIrU
- Github Repo: https://github.com/LowLevelJavaScript/Parser-Combinators-From-Scratch
- LLJS Subreddit: https://reddit.com/r/lowleveljavascript
- IP Packet Structure: https://en.wikipedia.org/wiki/IPv4#Packet_structure
- ArrayBuffer: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
- DataView: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView
- Typed Arrays: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray Ones and Zeros: Binary Part 1 [Parser Combinators from Scratch] Episode 6](https://i.ytimg.com/vi/ZgHlc3Q2YjU/mqdefault.jpg)
![Writing A Game For The Fantasy Console Emulator
In this video were continuing to develop a Frogger-like game for the Fantasy Console, built on top of the 16-Bit Virtual Machine! One thing were covering is bounds - making sure that when sprites go out of bounds they are correctly placed on the other side of the screen. The other is collision detection - where we can check and react on the idea of sprites intersecting with each other.
=[ 🔗 Links 🔗 ]=
- First Episode of Frogger Dev: https://www.youtube.com/watch?v=UkPB1ukAgbI
- 16BitVM Playlist: https://www.youtube.com/watch?v=fTBwD3sb5mw&list=PLP29wDx6QmW5DdwpdwHCRJsEubS5NrQ9b
- Fantasy Console Episodes: https://www.youtube.com/watch?v=g29vCtzZPuk&list=PLP29wDx6QmW6S4B2oQUN-fI-idy6UcesG
- Twos Complement: https://www.youtube.com/watch?v=vgbOTf8lgTQ
💌 Updates to your inbox: https://tinyletter.com/lowleveljavascript
🗣 Discord: https://discord.gg/FPWaVgk
⭐️ Patreon: https://www.patreon.com/lowleveljavascript
💻 Github Repo: https://github.com/LowLevelJavaScript/16-Bit-Virtual-Machine Writing A Game For The Fantasy Console Emulator](https://i.ytimg.com/vi/_eu8hFZP0oU/mqdefault.jpg)
![Bootloader Firmware Update Mechanism :: Bare Metal Programming Series 10
In this episode, were finally building the core firmware update mechanism in the bootloader! This involves taking all the elements weve been working on until now - timers, state machines, the packet protocol on top of uart, etc - and putting them together into a bootloader firmware that is able to communicate with a host PC and receive a firmware update.
In the next video, well build the PC side application, and complete this major milestone, before moving on to implementing a cryptographic code signing mechanism, to ensure only authorised code can be loaded onto the device.
=[ 🔗 Links 🔗 ]=
🎥 Series Playlist: https://www.youtube.com/playlist?list=PLP29wDx6QmW7HaCrRydOnxcy8QmW0SNdQ
🗣 Discord: https://discord.gg/FPWaVgk
⭐️ Patreon: https://www.patreon.com/lowleveljavascript
💻 Github Repo: https://github.com/lowbyteproductions/bare-metal-series Bootloader Firmware Update Mechanism :: Bare Metal Programming Series 10](https://i.ytimg.com/vi/_hd6FITV_Hw/mqdefault.jpg)