• Updated 2023-07-12: Hello, Guest! Welcome back, and be sure to check out this follow-up post about our outage a week or so ago.

In-System-Programmable ROM SIMM

zigzagjoe

Well-known member
This is a project I've had in the works for a bit in order to support a later project of mine. I expect to be doing a *lot* of reflashing, and removing and re-inserting the SIMM each time I wanted to iterate did /not/ appeal, so this is a 16MB ROM SIMM with onboard programming provided by a Pi Pico board. Result: it does not need to be removed from the mac it's currently installed in to write a new ROM image.

I'm still working on the code, in current form it erases, writes, and verifies a 1MB ROM image in 9 seconds. It'll slow down a little once I introduce USB (planning on UF2) support... but I'm already very happy with that performance.

I'm still trying to figure out what to have the pico do while idle; unfortunately due to the nature of the architecture of the board the pico only has visibility into the ROM control lines and lower bytes of the data bus of the ROM accesses. I'm thinking to have it act as USB-Serial adapter while not actively programming, at least.

Notable features...
  • 16MB of flash (in two banks, switchable)
  • Open-collector RESET output to be connected to the mac to hold Mac in reset while programming is in progress (release & boot when done).
  • Expected to be Quadra compatible
    • Detect +12v VPP on pin 2 and holds CS high to properly disable the onboard ROM
    • Incompatible with the Lobos board flash utility; there's no Mac OS where we're going...
  • GPIO/I2C/Serial Expansion header for later use
Also, thanks to @pgreenland for the fun idea of doing UF2 in order to do driverless programming.

1705097783470.jpeg1705097798701.jpeg

I expect this will appeal to a very small demographic, but I've got parts for a few more of these and as code matures I'll likely post them for sale.
 

Phipli

Well-known member
This is a project I've had in the works for a bit in order to support a later project of mine. I expect to be doing a *lot* of reflashing, and removing and re-inserting the SIMM each time I wanted to iterate did /not/ appeal, so this is a 16MB ROM SIMM with onboard programming provided by a Pi Pico board. Result: it does not need to be removed from the mac it's currently installed in to write a new ROM image.

I'm still working on the code, in current form it erases, writes, and verifies a 1MB ROM image in 9 seconds. It'll slow down a little once I introduce USB (planning on UF2) support... but I'm already very happy with that performance.

I'm still trying to figure out what to have the pico do while idle; unfortunately due to the nature of the architecture of the board the pico only has visibility into the ROM control lines and lower bytes of the data bus of the ROM accesses. I'm thinking to have it act as USB-Serial adapter while not actively programming, at least.

Notable features...
  • 16MB of flash (in two banks, switchable)
  • Open-collector RESET output to be connected to the mac to hold Mac in reset while programming is in progress (release & boot when done).
  • Expected to be Quadra compatible
    • Detect +12v VPP on pin 2 and holds CS high to properly disable the onboard ROM
    • Incompatible with the Lobos board flash utility; there's no Mac OS where we're going...
  • GPIO/I2C/Serial Expansion header for later use
Also, thanks to @pgreenland for the fun idea of doing UF2 in order to do driverless programming.

View attachment 68022View attachment 68023

I expect this will appeal to a very small demographic, but I've got parts for a few more of these and as code matures I'll likely post them for sale.
If you use a Pico W, can you flash over WiFi without taking the case off? And select banks for next power on?
 

zigzagjoe

Well-known member
If you use a Pico W, can you flash over WiFi without taking the case off? And select banks for next power on?
There's no technical reason that wireless upload couldn't be implemented, other than the effort to write the code. Though, wifi reception inside of a shielded case I would expect to be problematic; the Pico W has enough trouble in open air.

Bank selection would only currently be possible by using a remote switch, though a bodge of the bank select pin to one of the two spare GPIOs could make that possible too.
 

eharmon

Well-known member
If you use a Pico W, can you flash over WiFi without taking the case off? And select banks for next power on?
Mumbles something raving mad like a wifi driver that uses unused space on the address lines to use the Pico's wifi for internet.
 

zigzagjoe

Well-known member
Bravo! You're really on a roll with cool projects lately.
Haha, thanks! Gotta keep myself entertained. This is (part of) the reason this interposer simm came to be. Blinkenlights!

Mumbles something raving mad like a wifi driver that uses unused space on the address lines to use the Pico's wifi for internet.
I thought about it!! I think the pico could easily keep up with the bus with some PIO support, but currently the buffers/latches are all unidirectional due to being short on IOs / not needing bidirectional IO. There's no path to write data to the pico from the host system unless we do something hideous like bit-bang input using ROM OE :ROFLMAO:
 

eharmon

Well-known member
Haha, thanks! Gotta keep myself entertained. This is (part of) the reason this interposer simm came to be. Blinkenlights!


I thought about it!! I think the pico could easily keep up with the bus with some PIO support, but currently the buffers/latches are all unidirectional due to being short on IOs / not needing bidirectional IO. There's no path to write data to the pico from the host system unless we do something hideous like bit-bang input using ROM OE :ROFLMAO:
Clearly the solution is two picos ;)
 

bigmessowires

Well-known member
Cool! How is the programming performed? What's the interface? Are you connecting a USB cable to the Pico and initiating programming with a custom application running on a nearby PC? Can the Mac continue running while the SIMM is being reprogrammed? Or do you have a Mac-hosted program that communicates with the Pico through a memory-mapped interface?

Reading between the lines, this seems sort of like a SIMM programmer that's permanently attached to the SIMM?
 

zigzagjoe

Well-known member
Clearly the solution is two picos ;)
It actually gets worse. I had the mad thought: if I put a 128KB table of incrementing 16 bit numbers somewhere in ROM, and read from it in a sensitive pattern the RP2040 was rigged to recognize, the RP2040 could then override the output of the flash on another read to facilitate bidirectional communication. Certain requirements would have to be met on the host side, no caching, no other ROM accesses... but dang, it could actually work!
  1. "Write" Magic Recognition sequence 1
  2. "Write" Magic Recognition sequence 2
  3. "Write" Magic command
  4. (optional) Data "write"
  5. Data read (rp2040 overrides flash)
Where all the "Writes" are actually reads from that table which correspond to certain values in that table....

How is the programming performed? What's the interface? Are you connecting a USB cable to the Pico and initiating programming with a custom application running on a nearby PC? Can the Mac continue running while the SIMM is being reprogrammed? Or do you have a Mac-hosted program that communicates with the Pico through a memory-mapped interface?

Reading between the lines, this seems sort of like a SIMM programmer that's permanently attached to the SIMM?
Yeah, that's the basic nature of the beast, it's an onboard simm programmer. Connect via USB, it will present as a mass storage device and allow programming or reading either bank (or the current bank) by UF2 files. MAYBE support direct binary, later, as it's more difficult.

The Mac is prevented from accessing the flash while the RP2040 is working on it, so it will crash (*if you're running MacOS). I have an open collector output that can be used with the system reset to keep the system down while the programming is in process and let Mac restart when done.

It's intended for bare metal programming with the ability to far more rapidly iterate on code than needing to remove the ROM would allow.
 

eharmon

Well-known member
It actually gets worse. I had the mad thought: if I put a 128KB table of incrementing 16 bit numbers somewhere in ROM, and read from it in a sensitive pattern the RP2040 was rigged to recognize, the RP2040 could then override the output of the flash on another read to facilitate bidirectional communication. Certain requirements would have to be met on the host side, no caching, no other ROM accesses... but dang, it could actually work!
  1. "Write" Magic Recognition sequence 1
  2. "Write" Magic Recognition sequence 2
  3. "Write" Magic command
  4. (optional) Data "write"
  5. Data read (rp2040 overrides flash)
Where all the "Writes" are actually reads from that table which correspond to certain values in that table....
Huh, so you "read" the table of information you want and the pico sniffs the reads to construct the data in it's own memory?

I wonder if you could crush it small enough to just fit in a hole in the ROM that has unused data today. Maybe a really dumb codeword table that encodes all permutations of 4-bit patterns instead, for instance? Then instead of reading the numbers directly, you just read the offset matching the codeword and the pico can reconstruct which bit-pattern that is based on that offset.

So I want to read 0101 and that's at offset 5. I just need to read offset 5 to encode that. Then you can rapidly "load" 4-bit patterns into the pico by reading a single bit. But maybe I'm missing one of the constraints you're seeing.

I don't think there's any caching for the ROM on 68k (except 840av/660av or accelerator cards) so you could use a small ring buffer to read/write larger data sets quickly. And you could have an optional codeword table for common commands and use the data loading codewords only for raw data transfer.

And then since it's sitting in a hole, you just unconditionally override flash when the read buffer is used. No need for a magic pattern, you just know those offsets are now "registers" to be treated as codeword reads. Then on the return side, if there's nothing in the ring buffer it just returns empty data, like an empty ring buffer. And each bit read automatically generates an ack on the pico side to know it can fill more of the buffer.

Might be slow....but I don't think so. On both read and write on the Mac side you can just read the bit and index directly into the codeword table offset to get the data and copy it into the buffer. And at least from the system side most machines can read the ROM at > 10MB/s. Far outclasses the TCP/AT stack.

It'll use more RAM depending on the size of the codeword table, but that's pretty cheap realistically...

But I'm tired so maybe I'm talking crazy.
 

zigzagjoe

Well-known member
Huh, so you "read" the table of information you want and the pico sniffs the reads to construct the data in it's own memory?

I wonder if you could crush it small enough to just fit in a hole in the ROM that has unused data today. Maybe a really dumb codeword table that encodes all permutations of 4-bit patterns instead, for instance? Then instead of reading the numbers directly, you just read the offset matching the codeword and the pico can reconstruct which bit-pattern that is based on that offset.

So I want to read 0101 and that's at offset 5. I just need to read offset 5 to encode that. Then you can rapidly "load" 4-bit patterns into the pico by reading a single bit. But maybe I'm missing one of the constraints you're seeing.

I don't think there's any caching for the ROM on 68k (except 840av/660av or accelerator cards) so you could use a small ring buffer to read/write larger data sets quickly. And you could have an optional codeword table for common commands and use the data loading codewords only for raw data transfer.

And then since it's sitting in a hole, you just unconditionally override flash when the read buffer is used. No need for a magic pattern, you just know those offsets are now "registers" to be treated as codeword reads. Then on the return side, if there's nothing in the ring buffer it just returns empty data, like an empty ring buffer. And each bit read automatically generates an ack on the pico side to know it can fill more of the buffer.

Might be slow....but I don't think so. On both read and write on the Mac side you can just read the bit and index directly into the codeword table offset to get the data and copy it into the buffer. And at least from the system side most machines can read the ROM at > 10MB/s. Far outclasses the TCP/AT stack.

But I'm tired so maybe I'm talking crazy.

I think that could be made to work too. The main constraint is that the RP2040 only can read/write buffered D15-D0 (within the module), ROM_OE/some flash control lines; it can't read address lines (write only from RP2040). And the data lines to the host are read only (from the host side).

So whatever shows up on that lower data bus on "writes" (actually read from flash) must be unique and/or sequenced in such a way that the RP2040 can recognize and reply when it's appropriate, while avoiding any chance of that sequence occurring "naturally" and breaking things.

Though, with 8MB of space per bank, it's not exactly lacking space for a full table and 16 bits of reasonably fast IO would not be bad at all.
Not in a great hurry to implement this, but it's sure fun to think about these nonconventional IO approaches!
 
Last edited:

eharmon

Well-known member
I think that could be made to work too. The main constraint is that the RP2040 only can read/write D15-D0 and ROM_OE; it can't read address lines (write only). So whatever shows up on that lower data bus on "writes" (read from flash) must be unique and/or sequenced in such a way that the RP2040 can recognize and reply when it's appropriate, while avoiding any chance of that sequence occurring "naturally" and breaking things.

Though, with 8MB of space per bank, it's not exactly lacking space for a full table and 16 bits of reasonably fast IO would not be bad at all.
Not in a great hurry to implement this, but it's sure fun to think about these nonconventional IO approaches!
Ahhhh you can only see the data lines. I didn't read carefully enough before. So yeah I guess you'd need a unique-enough initiation sequence, followed by the Mac side reading codewords, which you could watch to extract the data sequence.
 

zigzagjoe

Well-known member
Ahhhh you can only see the data lines. I didn't read carefully enough before. So yeah I guess you'd need a unique-enough initiation sequence, followed by the Mac side reading codewords, which you could watch to extract the data sequence.
Yeah. With that and some timing I'd think it'd be doable, it might be a little "interesting" to do that from Mac OS but not impossible. Though to do it properly / to be kind to the flash I'd need to bodge in a resistor so that the pico can override the OE signal to the flash which is currently pulled to ground by one of the buffers when ROM_OE is asserted.

Still, it's been fun food for thought for later... My initial goal is basic programmer functionality fully functional then look to see what fun I might do with the two spare GPIOs in the vein of assisting troubleshooting. It's a bit of a waste to have a dual core microcontroller just twiddling its metaphorical thumbs, after all.
 

zigzagjoe

Well-known member
Progress is being made on the software: I've got basic flashing/reading working.

A 512KB IIsi image writes in 4 seconds from dragging the file to the drive and the mac beginning to boot from it. It's almost surreal. A full write of 8MB over USB takes 40 seconds, and a full read takes 27 seconds. Not bad at all, and there's room for optimization. Though, a decent chunk of this is waiting on the flash to erase itself and USB overhead.

The drag and drop UI is nice, but I'm running afoul of certain limitations of pretending to be a storage device; no easy way to indicate failures, such as if you write an invalid file type that it's just going to ignore. There's also no easy way to inform the host about changes short of pretending like the entire USB device was removed and re-inserted... ideally, I'd persist the size of the last written image in each bank so on read back we only read that much data.

Still, early days.
 

jmacz

Well-known member
Is your next version going to have the lights embedded? Or will you stack this on the interposer? :)
 

Phipli

Well-known member
Progress is being made on the software: I've got basic flashing/reading working.

A 512KB IIsi image writes in 4 seconds from dragging the file to the drive and the mac beginning to boot from it. It's almost surreal. A full write of 8MB over USB takes 40 seconds, and a full read takes 27 seconds. Not bad at all, and there's room for optimization. Though, a decent chunk of this is waiting on the flash to erase itself and USB overhead.

The drag and drop UI is nice, but I'm running afoul of certain limitations of pretending to be a storage device; no easy way to indicate failures, such as if you write an invalid file type that it's just going to ignore. There's also no easy way to inform the host about changes short of pretending like the entire USB device was removed and re-inserted... ideally, I'd persist the size of the last written image in each bank so on read back we only read that much data.

Still, early days.
You could have a text log file shown on the emulated storage device? Could even include the latest status in the filename "log - failed.txt".
 
Top