This protocol is a brilliant piece of engineering that brings modern software flexibility to legacy hardware without a single solder joint. It elegantly overcomes 8-bit architectural constraints by turning static ROMs into a dynamic, software-defined environment.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
GRUB-style bootloaders for all your retro systems?! - One ROM canAdded:
This is a completely stock Commodore 64, apart from the fact I've got one ROMs installed as the basic kernel and character ROMs. So, if I turn on this Commodore 64 now, it's going to boot into the regular stock kernel. Nothing special about that, you might think.
Now, I'm going to put the keyboard in place. Now, I'm going to boot this Commodore 64 while holding down the Commodore key.
And you can see it's booted into a different kernel. This is a bootloadader kernel that has queried the contents of the kernel one ROM detected that it's got these different kernel ROMs installed on it and gives us a menu so we can boot into them. So if we want to boot into the SX64 kernel, we can do that now. One ROM has remembered the last booted kernel. So if I turn the kernel 64 off and then turn it on again, it's going to boot straight into the SX64 kernel. If I want to change kernels, turn it off. Hold the Commodore key down, turn it on, enters the boot loader, load up Jify DOSs.
Jify DOSs is booted. Now, if I want to enter the dead Test ROM, same again.
Boot it up with the Commodore key held down, scroll down to dead test, and hit return. Now, if you ever wondered what dead test is doing in the 10 seconds it takes before it displays anything on the screen, you can see now it's actually doing a test of the screen RAM. Once that's complete, it's going to enter the regular dead test routines. Then, if I want to go back to booting the regular kernel, I'll turn the machine on, holding down the Commodore key, go back up to the latest kernel, hit enter, and it boots into that. If I turn it off and on again, it's going to auto boot into the regular kernel.
Hello, welcome back to Pierers Rocks. If you've not come across one ROM, the most flexible replacement ROM for your retro system, where have you been? One ROM replaces pretty much every ROM type in nearly every retro system from the late 1970s through into the 1980s, even into the 1990s. And it comes in 24, 28, 32, and 40 pin variants. And each of those hardware variants can itself replace lots of different ROM types. Nearly every ROM type that came with that number of pins. A single one ROM can store lots of different ROM images for different ROM types simultaneously. And it has header pins at the top to allow you to switch between those different ROMs at boot time. Today that's all changed. You no longer need to use these header pins to switch between ROM types because one ROM now includes functionality to allow your retro system like this Commodore 64 sitting behind me to switch between the different ROM images itself at runtime. If you don't already have your own one ROMs, why not?
It's a fully open- source project. All of the firmware and the hardware design files you need to have your own PCBs assembled and manufactured are open source. Links down in this video's description. If you'd rather buy ready assembled one ROMs, see the link on the screen now for a bunch of different vendors who will ship fully assembled one ROMs to your door. Now, as well as replacing individual ROMs, the 24 pin version of one RROM can also replace multiple different ROMs simultaneously, let's see this new image selection capability working with the multi-ROM capability. This new bootloadader is compatible with one ROM's multi-ROM support where a single one ROM can actually serve up to three ROMs simultaneously just by adding a flying lead from each of the two unpopulated sockets into it. We see it booting normally now into the kernel ROM. Now out of shot, I'm going to boot it into the bootloadader by holding down the Commodore key while turning it on. And you can see I've got two different combinations of ROM images installed.
the stock images that we just saw booting and also Jify DOSS which also has a custom character ROM installed and you'll see the character ROM actually change instantaneously when I select this set of images. There we go. It's switched images now and it's booting into Jify DOSs again. This remembers the last booted combination. So if you turn it off and on again then it boots into that combination. Now the bootloadader that you've just seen running on this Commodore 64 behind me is written by one of my viewers Hular. I wanted to show that this capability isn't just limited to the Commodore 64, though. So, I wrote a bootloadader for the VIC 20. Let's take a look at that. Now, this is a VIC 20, and I've got one ROM placing the kernel ROM. So, if I turn it on, it'll boot into the stock VIC 20 kernel. Now, if I turn it off and hold the Commodore key down, which is out of shot, then it'll boot into a bootloader, and it will show me all the different images that I've got installed. So, if I boot into the stock NTSC kernel, then you'll get to see what us Europeans see when we put an NTSC kernel or cartridge into one of our PAL machines. I can turn it off and on again. And I can select, let's select the PAL Jify DOSs image. It's booted straight into that. Again, if I turn it off and on without holding down the Commodore key, it's going to auto boot into the last selected kernel. And of course, I can also boot into the dead test ROM by selecting it from the menu.
And again, if I turn it off, turn it on again, then it's going to remember that selection and boot straight into dead test. Just to reiterate, this new capability of one ROM doesn't require any physical switching between the images using jumpers or DIP switches. It also doesn't require any hardware modifications to your retro system like other runtime kernel switching mechanisms do other than installing a one RROM in the ROM socket in your system and installing the right firmware and collection of images on your one ROM. That's it. That's all you need to do. No flying leads coming from non-maskable interrupt lines or anything else. How's it done? We're going to see that now. So, I thought where we should start is a quick refresher on what a ROM chip is actually doing. What you can see on the screen right now is a logic analyzer style view of all of the pins on a ROM chip. Other than the power and the ground lines, there are three other types of lines on a ROM chip. There's the address lines, the data lines, and any chip select or chip enable or output enable lines. The address lines on this particular ROM type we're looking at right now, there are 13 of them. These are used by the host system, the system that the ROM is installed in to signal to the ROM chip the address of the data that the host system would like to retrieve from read only memory. So the host system here is going to signal a 13 bit address. So that's within an 8 kilobyte address space to the ROM chip using the address lines. These can only be driven by the host system. They can't be driven by the ROM chip. the chip select line or lines or chip enable lines or output enable lines. This particular ROM type has a single one. It has a single chip select line which is active when it goes low. Signals to the ROM the data on the address lines is valid. Now I want you to look up the bite that's available at that address in your readonly memory and I want you to output it on the data lines using low for zeros and high for ones. That's what a ROM is doing thousands, hundreds of thousands or millions of times a second is it's being signaled by the host system on it chip select lines to go active to do something. It looks at the address that's sitting on signaled using the address lines and it outputs the data using the data lines. Now, in order to implement functionality like we've just seen where the Commodore 64 boots up and it retrieves information from one ROM about the kernel images that are stored within it and also instructs one ROM to do some things like to load a new image requires some kind of birectional communication mechanism between the host computer and the ROM installed in the ROM socket. one ROM unless we want to make some hardware modifications to the host system to plug some additional cables from somewhere on the home host system into one ROM then we're limited to using the address lines the data lines and any chip select lines as the physical medium used for this communication mechanism. Now there are really two pieces to how the underlying communication is working. The first is that one ROM is looking at the bottom eight bits of every address that's being signaled to it. So every time the chip select line goes active, as well as actually serving the bite that's located in its memory at the address that's being signaled by all of the address pins, it's also looking at the bottom eight bits and it's seeing whether those eight bits are indicating that it should do something special. We'll come on and talk about precisely how it's going to indicate the different special sorts of things that it can do. The second part is one ROM is going to signal back information to the application running on the host system. So respond to whatever commands and instructions it's being given in these bottom eight bits.
It's going to do that using a portion of the ROM space that it is currently serving to the host system. So that needs to be reserved so that it can contain information for one ROM to send back to the host system. So two parts.
One, we're using the bottom eight bits of every address that's signaled to one ROM to detect whether we're being told to do something and if so what. And then second, for the back channel for communicating back to the host system, we're using a portion of the ROM image that's reserved specifically for this purpose. Now, I may have made it sound simpler than it actually is. I don't know, some of you might already be thinking it sounds quite complicated, but actually it's more complicated than that because the host system is constantly reading data from ROMs.
Indeed, many of these systems are actually loading code from the ROMs that they're executing. So there are lots of address reads happening from one ROM all the time and it's very difficult for us to discern when an the bottom eight bits of a particular address are going to signify a command that one ROM should do something. Also a ROM image may not actually have any spare space within it reserved for this back channel communication. Right? These ROMs were typically very small and the manufacturers of the systems and the developers of the code that were stored in these ROMs would typically they used up all the space. So we have to be a bit more subtle than I've described on looking at the addresses and figuring out whether to execute commands. What one ROM is actually doing is it's looking for what is hoped to be a unique prefix of address reads. So a certain sequence of address bytes being signaled one after the other to put it into command mode and then the address bytes that follow actually signaling a particular command type for one ROM to execute. Now this only gives us unidirectional communication. It gives us communication from from the host to the ROM if there's no dedicated shared space for communication back in the other direction. So some of the commands that can be sent in this unidirectional manner can actually tell one ROM to change the contents of the ROM that is currently serving to the host system and switch out certain sections of it and instead dynamically assign them as a back channel for communication back to the host system. We have to be very very careful when doing this. There's lots of different nuances and complications when trying to hijack what is inherently quite a simple mechanism of addresses being signaled and bytes being read for our own purposes. Because of this, I defined a new protocol called the ROM bus control protocol. And this uses the address lines, the data lines, and the chip select lines in the way we've just been talking about, and defines a set of commands, both unidirectional and birectional commands that can be sent from the host system to a ROM emulator like one ROM, and can cause it to do certain things like retrieve the information that's stored on one ROM and populate that information within a certain section of the ROM, or switch the ROM image that's actually being served. served live by one ROM in an atomic way where atomic there means that at one point it was serving the entirety of a one ROM and then at another instant it's serving the entirety of a completely different ROM. So the ROM control protocol [snorts] I've released on GitHub and link down in the description. This is quite an extensive protocol to allow a lot of different commands to flow between the host and a ROM ROM emulator like one ROM unlocking the sorts of application that you've seen so far in this video. In parallel with releasing the protocol, there is now a new one RROM plug-in that runs on one of its spare CPU cores that implements the ROM bus control protocol and therefore can listen for commands from a retro system and will perform the actions that defined by the protocol that's running in the kernel one ROM for both the Commodore 64 and VIC 20 demos that we looked at earlier. We'll take a quick look at some of the details of the protocol. Probably the most important part of the protocol is the knock, the session initiation. This is the unique sequence of bytes that one ROM is listening out for. And if it receives, it then starts actually trying to interpret following reads as commands to execute. The standard knock is six bytes long and is the string exclamation mark RBCP exclamation mark. This may need changing, tweaking, tuning on different systems depending on what sequence of addresses they naturally read based on their standard firmware or ROM implementations. Once one ROM reads the knock, it's then going to be looking for a command framed like this. The first bite, so the bottom eight bits of the next address read signify the group. So commands are grouped together into similar types of commands. Then the second bite is the command itself. And then the subsequent bytes are any arguments to the command. And each command has a well-known a well- definfined number of arguments. Once the group the command have been received and have been interpreted as valid commands and all the address bytes have been received then the ROM emulator one ROM is going to execute the command. Now there's two modes that one ROM operates in. One is in command mode which is unidirectional mode which it receives commands and executes them but it has no way of sending any kind of response back to the host application and then command response mode which the host must manually put the ROM into and this defines the back channel region for example that one ROM can use to communicate back to the ROM. Then the groups of commands we have control commands which are really about setting up sessions between the host and one ROM. There's read commands which is get information back from one ROM like what sort of ROM emulator is it? What version of firmware is it running? How many images are in flash?
What are the image names stored on flash? Modify commands are loading new images in from flash into RAM slots.
Switching between RAM slots, that kind of thing. The envy storage group of commands actually modifies the ROM emulator's nonvolatile storage. So flash associated with the RP2350 microcontroller. This for example is how the bootloadader that we looked at is storing the last booted image so that it can be retrieved by the host application next time the host system is turned on.
It's turned on. It tries to read a bite of nonvolatile storage and it uses the value in that location to decide which image to boot from if you're not holding down the Commodore key. Then there's a special reset command and this is about resetting a ROM emulator one ROM that might have been communicated with by a host previously. Maybe it's reset since then and just resetting the rhombus control protocol implementation back to a known start state. So communication will work this time around. And we just take a look at some of the commands. For example, we've got the get device type.
One ROM will return one ROM if it receives this command. Get device versions returns the firmware version of the device. Get protocol version. Slot peak actually allows the host to retrieve the value that is currently being served by one ROM at a certain address. And there's also a slot poke modify command that can change individual bytes [snorts] in the ROM image currently being served. This might be useful if a host application wanted to go in and modify the interrupt vectors in a particular ROM image for example. So it disables interrupts. It then goes and changes the interrupt vector in the in the ROM being served and then it reenables interrupts. And then we've got definitions for the data that is actually being returned by one ROM when commands are executed. So the get type get device type command returns essentially a 24 byt string in the back channel region. The get device version command similarly returns a device version in 24 bytes of that region. lots more within the specification. If you're really interested in understanding the guts of how this protocol works, then I suggest you read this specification.
Also, as part of this, I've implemented a reference implementation for the 6502 processor. So, this should be usable by any computer based around a 6502 or 6504 or 6507 or 6510 CPU to communicate with a ROM emulator that supports the ROM bus control protocol, which today means one ROM. And this reference implementation is released as assembly code and it exports a whole bunch of functions to allow you to perform the rhombus control protocol tasks very simply and easily.
So we're just going to take a quick look at a sample program to do some useful stuff using the rhombus control protocol. So first thing we do is we import some of the routines that we're going to use from the reference implementation library. We then do any startup that's required for our specific host system like initialize the video chip that kind of thing. Then we move into the portion of the code that's actually going to communicate with the ROM emulator. One ROM in this case.
First thing that needs to be done is to disable interrupts. It only needs to be done while initiating communication with the ROM emulator. Interrupts can be uh reenabled after this. But it's important for this phase of the communication that interrupts are enabled. So there are no speurious address reads coming in on the ROM emulator while the initial unique sequence of address reads is signaling that the host wants to start talking to the ROM emulators internal ROM control protocol implementation. As this comment says, it's really important that this section of code, this is the code that's actually initiating communication with one ROM under the covers, does not run from the ROM that is being communicated with. Either it copies itself into RAM and executes from there or it's running from a different ROM. If it's running from the ROM that the code is trying to communicate with, then the CPU is going to be retrieving instructions this code to execute at the same time as this code is trying to uniquely signal one ROM.
And that interle of the address reads is going to confuse one ROM. It's not going to detect that the host is trying to communicate with it. So just this section here needs to run as I say from RAM or from a different ROM. The next thing the code does is it calls the reset routine. Now this just resets the ROM bus control protocol implementation that's running in your ROM emulator. If the host was previously talking to it and the host was reset or rebooted, this should reset the rhombus control protocol back to a starting state. so that it's ready to start talking to a new host. The next thing that the host is doing is it's calling this enter command response mode command. This actually configures and enables the back channel from one ROM back to the host.
And this at this point once this command has been executed, we've now got a reliable transport mechanism established between the host and the ROM emulator.
So the ROM emulator can actually signal progress of of subsequent commands that it receives and it can provide return codes and it can provide chunks of data.
There's configuration available within this particular routine to specify the exact bits of a ROM that could be reused as the back channel for communication back from the ROM emulator to the home system. So if there's 32 bytes or 256 bytes or some amount of data available somewhere in the existing ROM image that can be used as part of the back channel.
There are some other mechanisms that can be used. It can we can actually switch out and switch in a new ROM image at this point to use as a back channel if that's desirable. But this is the simplest way of doing it. The host implementation can now actually start sending birectional messages, ones that that ask one ROM to do something and will retrieve a response like checking that one ROM supports the version of this protocol that the host does. You can also find out the name of a particular ROM emulator. In this case, obviously one ROM and the version of the firmware running on the ROM emulator.
But here we have another much more important function which is loading a ROM image that's sitting on the ROM emulator's flash into a spare slot in the ROM emulators RAM. Depending on the type of ROM that one ROM is serving, it will have a number of different spare RAM slots that are not being used but can be switched to to serve ROMs from in an atomic fashion. This is actually doing populating one of those backup RAM slots if you like.
And then this final command is telling one ROM to switch atomically over to starting to serve from a different location in RAM. And it's also at the same time exiting command response mode because the ROM image that's being served is being switched. The new ROM image does not have a back channel region reserved for communicating back to the host. Then it's also exiting command response at this point. Now this command includes a slight pause to give one ROM time to make to receive the command and make that switch.
And then this host program is now switching to the reset vector that's stored in the new ROM image that's being served. So at its heart that's what the application that we saw running on the Commodore 64 is doing this functionality. There's actually more complexity because obviously that is providing a list of the images to switch to. And to do that it's got to send a different command and receive some data in the back channel and parse that and stick it on the screen and do some keyboard scanning to detect the cursor keys being pressed and the return key being pressed and so on. But this is how simple it is to write a host program to communicate under the covers using the existing ROM bus with a ROM emulator like one ROM. Now this was really quite difficult to get working. Having said that, I do think it is now working stably on the Commodore 64 and Vic 20.
There's really been two significant challenges with getting this working.
The first is that all of the address bytes that are being signaled by the host are being reviewed by the microcontroller on one ROM in real time using the CPU and that is a relatively complex thing to do when you don't have very many nanose to do that in. The second complexity is that at least on the Commodore 64, which is what I've done most of my testing on so far, there are seem to be a lot of speurious chip select activations on that platform, which only last for maybe 10 nanose, 15 nanconds. But the microcontroller on one ROM is able to detect those glitches as chip select very briefly goes active when really it shouldn't have done and think that that was a request from the host to read from a particular address on the ROM. So one ROM has had to provide some filtering within it, some debouncing if you like to be able to ignore to filter out those particular glitches and that's taken a little bit of tuning to get right.
Now as of today most of the rhombus control protocol is only implemented on one ROM for the 2364 ROM type. So that's used in the kind of early 80s systems like Commodore 64s and Vic 20s and so on. There's nothing inherent in the ROM as control protocol that means its can only ever be supported on 2364 and I'm planning to add support for other ROM types in future. If you would like a particular ROM type implemented soon because you want to write a bootloadader or other ROM bus control protocol application for your particular host system and you need a different ROM type, hit me up. I'm anticipating some questions as to why I've implemented things the way I have in a rumbus control protocol. Some people might be aware that there's some types of devices, EPROMs, flash devices that can be put into programming mode by sending a certain sequence of address reads to it. Why haven't I haven't used those sequence of address reads? Well, first of all, you can use whatever knock sequence you like in Rumbus control protocol. So, if you want to use that sequence, then fine. But those sequences were not defined as far as I'm aware to be unlikely statistically to appear in normal behavior on the sorts of devices that a rumbus control protocol is targeting. Second question I'm anticipating is people asking why I haven't implemented the same type of protocol support as the no slot clock device. This is a clock device that was shipped in some retro systems like the Apple 2 and listened for unique sequences of address reads. And if that unique sequence was detected would then hijack certain bits often just bit zero of the data lines to transmit serially over that single bit in all in as many subsequent address reads as were necessary a certain type of data. So in the no slot clock implementation it was providing time of day information just using D0 for however many subsequent data reads needed to that's not really a reliable and robust mechanism to use in the sorts of retro systems again that I'm targeting here where these retro systems might at any point in time be triggering interrupts in particular non-maskable interrupts and if the CPU is trying to get the non-maskable interrupt address but data bit zero is corrupted is changed to the wrong value because it's being used to transmit data then that's going to crash the whole system. The mechanism that I've tried to implement here is thinking about how these systems operate and hopefully being a robust implementation that is not going to cause the host system to crash unless it's under very kind of pathological conditions. I guess the third question I'm anticipating is why have you done this at all? And the answer to that is really because I wanted to see if it could be done and I enjoyed the process.
I was kicking around this whole idea of communication between a host system and an emulated ROM with Jamie Idol Pix who invented the Meatloaf device for Commodore Systems at VCF Midwest in Chicago in September. And this has been the thing that's been playing on my mind most since then. That took me quite a while to get around to doing cuz I thought it was going to be hard and it was hard but turned out that it was entirely feasible. The reason I defined the ROM control protocol as a generic protocol rather than a one ROM specific protocol is it would be perfectly possible for other ROM emulators either microcontroller based ones or full PC, Mac, Linux retro system emulators to also implement the rhombus control protocol.
If they did so, then the same host applications like the boot loaders we've just seen for the Commodore 64 and Vic 20 would work with those other ROM emulators. So, for example, if Vice the Commodore 64, Vick 20 and PET emulator implemented the ROM bus control protocol, then the Commodore 64 and Vic 20 kernel bootloadaders would work in those emulators.
Now, to be clear, I'm not planning on adding support device for the ROM control protocol. I'm probably not going to write too many more host implementations. My focus is on one ROM and I'm hoping by providing this functionality within one ROM that those of you who are interested in particular retro systems and have the expertise may write your own bootloadaders and other applications that support the ROM bus control protocol. If you'd like to learn more about OneROM or the functionality that you've seen in this video or maybe even write a ROM bootloader or BIOS bootloader for your particular favorite retro system, please reach out to me.
You can get in touch with me on Discord in the GitHub project discussions or issues or obviously in the YouTube comments below. Links for everything that you've seen available down in the description. I hope you found this video interesting and useful. If you did, please do consider subscribing and sticking around for the next video. Till then, rock on.
Related Videos
Agentforce NOW AMA: Build with React and Salesforce Multi-Framework
SalesforceDevs
490 viewsโข2026-05-28
How agent o11y differs from traditional o11y โ Phil Hetzel, Braintrust
aiDotEngineer
450 viewsโข2026-05-28
Re: ๐ฃ๏ธ๐theprophedu๐2026 GST 103 CLASS (E-EXAM REVISION)
theprophedu
636 viewsโข2026-06-04
WEB TECHNOLOGIES UNIT-2 | Degree 4th sem BCOM Computers web technologies unit-2 full explanation๐ฏโ
LearnwithSahera
1K viewsโข2026-05-29
More tests are always better? How to use AI to identify tests that bring little value
Alliance4Qualification
335 viewsโข2026-05-29
Search Algorithms Explained in 60 Seconds! ๐ค๐จ
samarthtuliofficial
218 viewsโข2026-06-01
People of Game of Thrones using JavaScript DOM
AltCampus
296 viewsโข2026-05-30
Introduction to Problem Solving Part - 1 | Lecture 1 | Intermediate DSA
ascensionix
107 viewsโข2026-05-29











