# New cartridge design: ROMBA π

**URL:** <https://forum.cpcwiki.eu/t/new-cartridge-design-romba/1122>\
**Category:** CPC hardware\
**Tags:** hardware, extension, dma\
**Created:** [November 4, 2026, 9:20am UTC](https://forum.cpcwiki.eu/t/new-cartridge-design-romba/1122 "2026-11-04T09:20:10Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![doragasu](https://forum.cpcwiki.eu/user_avatar/forum.cpcwiki.eu/doragasu/32/1659_2.png) [@doragasu](https://forum.cpcwiki.eu/u/doragasu)\
**Post date:** [November 4, 2026, 9:20am UTC](https://forum.cpcwiki.eu/t/new-cartridge-design-romba/1122/1 "2026-11-04T09:20:10Z")

</div>

Some people might remember [ROMBA, a cart I released almost 10 years ago](https://www.cpcwiki.eu/forum/amstrad-cpc-hardware/rom-board-with-a-tiny-dma-engine/), that was a Rombox with some limited DMA capabilities. As it sat there, time went by, COVID came, the CPLD that cart uses went from less than 2€ a piece to more than 10€ a piece, and the very few people that were interested in the cart lost interest.

As it seems the pricing of CPLDs with a big amount of I/O will never go down to where it was, some time ago I started thinking about making a new design focused on, again, making it cheap to build, while adding some more features. Meet ROMBA π (or ROMBA 3.14):

 ![romba-pi](https://forum.cpcwiki.eu/uploads/default/original/2X/2/280065a6ff0e3b6a65aa975fcf446856bc0e9232.jpeg)

 ![1b58e682-883c-4af5-849e-9d0e45fea9e9](https://forum.cpcwiki.eu/uploads/default/original/2X/4/4158db1ff6e8255d2013e76cd17f65329cfa0302.jpeg)

The design is based on RP2350B, a “pi-pico2” microcontroller instead of a CPLD. These microcontrollers are cheap, with plenty 5V tolerant pins and support up to 16 MiB of cheap QSPI flash memory. The cart is connected to the expansion port, and as happened with my older ROMBA cart, it can be connected directly using an edge connector, or through an MX4 board using a DIL connector.

Using an MCU instead of a CPLD/FPGA for parallel bus interfacing, combined with using QSPI flash instead of parallel NOR flash has made this quite challenging to work as Rombox because of the latencies involved in polling the bus and reading from the QSPI chip, but there it is!

The currently implemented features are:

- Up to 16 MiB (128 megabits) Flash ROM capacity. Most is usable as ROM memory for the CPC, with the exception of the amount used for firmware (that currently is about 48 KiB but should grow if more features are added).
- USB host port. Currently mouse support is implemented, but other USB peripherals could be added.
- Mouse support includes configurable fractional scaling (to adjust sensitivity from the CPC side), with independent setting for X, Y and wheel.
- Compatible with Amstrad CPC Romboxes (up to 256 slots).
- Hardware DMA that can be used to copy data from ROM to internal RAM (1 byte per microsecond).
- DMA engine can copy in linear mode and in 2D mode, allowing to copy tiles to the screen memory without having to worry about the oddities of the CRTC and GA.
- DMA engine in 2D mode also supports on the fly tile mirroring for the 3 graphical modes.

Support for the features above is stable, but I would not consider the firmware feature complete as it is (more on this later). The hardware allows adding support also for these:

- Pixel shifting for tiles.
- Pixel masking for tiles (currently implemented but with byte granularity only).
- Lower ROM support.
- More complex memory mapping.
- RAM expansion (MCU has 512 KiB RAM, and the amount not used by the firm could be used as CPC RAM).
- Sound capabilities (FM capabilities, PCM sample playback).
- Flash data saving.
- Programmable NMI generator.
- Support for DMA from CPC internal RAM to CPC internal RAM (currently only ROM to RAM is supported).

Here you can see the mouse support in action:

[![](https://forum.cpcwiki.eu/uploads/default/original/2X/5/5095463539d2f1d078d3f4bdef82c99fcba27a33.jpeg "ROMBA π USB mouse support (Amstrad CPC)") ](https://www.youtube.com/watch?v=TyYUqYvNFLg)

SyX has patched a bunch of games to support the mouse and I should make a video of some of these also 😄. He also helped me a lot with things like understanding video memory layout, and some code snippets and programs for testing.

And here you can see the 2D DMA capabilities in action:

[![](https://forum.cpcwiki.eu/uploads/default/original/2X/4/4fe321b30646d92682cedc727ced62d8044320e1.jpeg "ROMBA π 2D DMA capabilities (Amstrad CPC)") ](https://www.youtube.com/watch?v=9G92sUIqzwg)

That sprite is 32x64 pixels (mode 0) and the DMA takes about 1 ms to draw it (it draws two mode 0 pixels per microsecond). The 2D DMA engine also does on the fly mirroring by hardware and handles screen clipping and masking (but in the current version everything only with byte granularity, so two mode 0 pixels).

Both [hardware](https://gitlab.com/doragasu/romba-pi) and [firmware](https://gitlab.com/doragasu/romba-pi-src) are released as Open Source. Documentation about how to program for these is lacking right now, but I plan to add it later.

Now, about the current “unfinished” firmware status. I wanted to add most (if not all) features listed above that are not yet implemented. But it seems a big chunk (maybe the majority?) of the CPC community only cares about software achievements and see these hardware expansions as “anti-features”, as “that is not a CPC anymore” and the like. So instead of pouring more effort into this, I am halting development until I see real interest in the cart. Like someone genuinely interested in developing for this platform using these features. Because if it is going to be my second design for the CPC that will end unused, I would rather spend my time on other hardware projects that might help other devs.

So what do you think. Is something like this interesting? Anyone interested in developing for these cheap and capable carts? Or adding anything other than memory is cheating and should be buried?

---

<div class="post-metadata">

**Author:** ![XeNoMoRPH](https://forum.cpcwiki.eu/user_avatar/forum.cpcwiki.eu/xenomorph/32/28_2.png) [@XeNoMoRPH](https://forum.cpcwiki.eu/u/XeNoMoRPH)\
**Post date:** [November 4, 2026, 9:31am UTC](https://forum.cpcwiki.eu/t/new-cartridge-design-romba/1122/2 "2026-11-04T09:31:33Z")

</div>

As a CPC hardware enthusiast, I would really like to see the project completed, although I’m not a developer, so I can’t create anything.

---

<div class="post-metadata">

**Author:** ![SagaDS](https://forum.cpcwiki.eu/user_avatar/forum.cpcwiki.eu/sagads/32/160_2.png) [@SagaDS](https://forum.cpcwiki.eu/u/SagaDS)\
**Post date:** [November 4, 2026, 9:44am UTC](https://forum.cpcwiki.eu/t/new-cartridge-design-romba/1122/3 "2026-11-04T09:44:11Z")

</div>

If this is cheap and useful (add ROM / RAM / Mouse / Some kind of fast sprite handling), I don’t see why it could not be interesting…  
The populous / god games could use the mouse as a easier input. Even me, I can modify my minesweep game to use it  
With Vespertino asking for a 4MB board to be able to play it, there is some room for good games with a little hardware help 🙂. And they use a lot of ROM if I am not mistaken.

In your future support, I would say by priority:

- RAM expension (it is always nice to have some in a new hardware)
- DMA CPC RAM to CPC RAM for fast transfer of memory
- Pixel shifting / masking for tiles
- Sound capabilities (samples with low impact on speed/memory is nice
- Flash data saving
- Lower ROM support

For other points, it’s not clear enough for me to give feedbacks (more complex memory mapping / Programmble NMI). I don’t see where I would be able to use it.

---

<div class="post-metadata">

**Author:** ![Gryzor](https://forum.cpcwiki.eu/user_avatar/forum.cpcwiki.eu/gryzor/32/7_2.png) [@Gryzor](https://forum.cpcwiki.eu/u/Gryzor)\
**Post date:** [November 4, 2026, 11:10am UTC](https://forum.cpcwiki.eu/t/new-cartridge-design-romba/1122/4 "2026-11-04T11:10:46Z")

</div>

Color me interested!

---

<div class="post-metadata">

**Author:** ![SoftDevil](https://forum.cpcwiki.eu/user_avatar/forum.cpcwiki.eu/softdevil/32/1204_2.png) [@SoftDevil](https://forum.cpcwiki.eu/u/SoftDevil)\
**Post date:** [November 4, 2026, 11:37am UTC](https://forum.cpcwiki.eu/t/new-cartridge-design-romba/1122/5 "2026-11-04T11:37:30Z")

</div>

I find your (doragasu) presentation extremely exciting 🙂

… I’ve been tinkering with a “GOD GAME” (similar to Populous) for a while now. No matter what I try, I’m constantly plagued by severe and equally stubborn performance bottlenecks. I would love to try out the new hardware (ROMBA **[π](https://forum.cpcwiki.eu/t/new-cartridge-design-romba/1122)** for sprites and mouse) as soon as it’s available. The sprites could help with the “bustling little figures” (= software sprites) on the playfield.

My personal challenge: I no longer have a CPC. I had to sell it back in the day. I only work with emulators now.

Idea: If you (doragasu) give me the specs, I’ll take a closer look at the Caprise32 CPC emulator to see whether Caprise32 can be expanded via software to match your hardware. Alternatively, create an adapter board to use the GPIO ports of a Raspberry Pi as a CPC expansion port. (Kind of crazy, but also kind of interesting). I haven’t looked at the Caprise32 code yet, but maybe all of us (the community) can come up with a suitable idea together…

---

<div class="post-metadata">

**Author:** ![eto](https://forum.cpcwiki.eu/user_avatar/forum.cpcwiki.eu/eto/32/24_2.png) [@eto](https://forum.cpcwiki.eu/u/eto)\
**Post date:** [November 4, 2026, 12:42pm UTC](https://forum.cpcwiki.eu/t/new-cartridge-design-romba/1122/6 "2026-11-04T12:42:28Z")

</div>

Sounds interesting. Honestly I was surprised that it took so long until the RP2350B is used for such a multi-feature-expansion.

One thing I would consider: if another expansion that contains RAM is connected at the same time, you will most likely get a conflict as they will always act in parallel. E.g. a DDI-5 still makes sense in parallel to your expansion. Maybe add a switch to turn off RAM for those scenarios.

---

<div class="post-metadata">

**Author:** ![doragasu](https://forum.cpcwiki.eu/user_avatar/forum.cpcwiki.eu/doragasu/32/1659_2.png) [@doragasu](https://forum.cpcwiki.eu/u/doragasu)\
**Post date:** [November 4, 2026, 4:51pm UTC](https://forum.cpcwiki.eu/t/new-cartridge-design-romba/1122/7 "2026-11-04T16:51:46Z")

</div>

Thanks for the interest.

@SoftDevil I will write the specs later when I get some time. The mouse interface should be final as is. As an advance, this is how it works. It uses I/O ports $F990 through $F993:

| Port | Read | Write | Default |
| --- | --- | --- | --- |
| $F990 | STAT | N/A | N/A |
| $F991 | WHEEL\_BTN | WHEEL\_SCALING | 64 (1.0) |
| $F992 | X\_AXIS | X\_SCALING | 32 (0.5) |
| $F993 | Y\_AXIS | Y\_SCALING | 32 (0.5) |

- STAT: bit 0 is 1 if mouse is connected, 0 if it is not connected.
- WHEEL\_BTN: 5 higher bits are the wheel reading delta (since last read) in two’s complement, positive for wheel movement up, negative for wheel movement down. Lower 3 bits are buttons current status: M, R, L.
- X\_AXIS: X axis delta (since last read) in 8-bit two’s complement. Positive for movement right, negative for movement left.
- Y\_AXIS: Y axis delta (since last read) in 8-bit two’s complement. Positive for movement up, negative for movement down.
- WHEEL\_SCALING: fractional wheel scaling factor.
- X\_SCALING: fractional X axis scaling factor.
- X\_SCALING: fractional Y axis scaling factor.

When reading wheel and axes, you get the delta since last read, and value is reset to 0. Values saturate to their maximum/minimum (15 to -16 for the wheel, 127 to -128 for the axes) if you move the mouse quick or take too much time between readings.

The scaling factors allow adjusting the sensitivity of the mouse. They are in Q1.6 fixed point format (1 sign bit, 1 bit for integer part, 6 bit for fractional part). To get the scaling value, you have to divide by 2^16 = 64. So a scaling factor of 64 corresponds to 1.0, a scaling of 32 to 0.5, a scaling of 20 to 20/64 = 0.3125 and so on.

Using negative scaling values cause the axis to be inverted (e.g. if you set Y axis to 0xE0 that corresponds to -0.5, in addition to the 0.5 scale factor, moving up will give you negative values, and moving down will give you positive values). Using 0 as scaling value effectively disables that axis.

Each axis can be individually configured. This is useful for example for inverting specific axes as explained above, but also because sometimes having different values for each axis is needed. For example the Operation Wolf mouse patch plays much better with X scaling set to 16 (0.25) and Y scaling set to 32 (0.5) than with the same scaling for both.

For the DMA I have not time right now to explain all the registers, but will do later. Also if firmware development continues, this is expected to change. **A lot**. They are located from $FC00 to $FC0F:

```C
enum rdma_reg {
	RDMA_REG_DMASRCL = 0,
	RDMA_REG_DMASRCH,
	RDMA_REG_DMASRCU,
	RDMA_REG_2D_MASK, // For 2D mode, does not copy if mask matches
	RDMA_REG_DMADSTL,
	RDMA_REG_DMADSTH,
	RDMA_REG_DMALENL,
	RDMA_REG_DMALENH,
	RDMA_REG_SCR_WIDTH, // In characters, e.g.: 40
	RDMA_REG_SCR_HEIGHT, // Line height - 1 and height in chars: lllhhhhh (e.g. 0xF9)
	RDMA_REG_2D_W, // In bytes. NOTE: height is inferred from LEN
	RDMA_REG_2D_X, // In bytes, signed
	RDMA_REG_2D_YL, // In lines, signed
	RDMA_REG_2D_YH,
	RDMA_REG_DMACTRL2,
	RDMA_REG_DMACTRL1,
	__RDMA_REG_MAX
};

// DMACTRL1 register masks
enum rdma_reg_dmactrl1 {
	RDMA_DMACTRL1_START_LSB = 0, // Start DMA when 1
	RDMA_DMACTRL1_SRCINC_LSB = 1, // SRC auto increment enable
	RDMA_DMACTRL1_DSTINC_LSB = 2, // DST auto increment enable
	RDMA_DMACTRL1_2D_MASK_LSB = 3, // Enable 2D masking when 1
	RDMA_DMACTRL1_2D_XMIR_LSB = 4, // Enable mirroring on X
	RDMA_DMACTRL1_FULLADDR_LSB = 6, // 0: use bank, 1: 24 bit address
	RDMA_DMACTRL1_MODE_LSB = 7, // 0: standard, 1: 2D
	RDMA_DMACTRL1_START_MASK = BIT(RDMA_DMACTRL1_START_LSB),
	RDMA_DMACTRL1_SRCINC_MASK = BIT(RDMA_DMACTRL1_SRCINC_LSB),
	RDMA_DMACTRL1_DSTINC_MASK = BIT(RDMA_DMACTRL1_DSTINC_LSB),
	RDMA_DMACTRL1_2D_MASK_MASK = BIT(RDMA_DMACTRL1_2D_MASK_LSB),
	RDMA_DMACTRL1_2D_XMIR_MASK = BIT(RDMA_DMACTRL1_2D_XMIR_LSB),
	RDMA_DMACTRL1_FULLADDR_MASK = BIT(RDMA_DMACTRL1_FULLADDR_LSB),
	RDMA_DMACTRL1_MODE_MASK = BIT(RDMA_DMACTRL1_MODE_LSB),
};

// DMACTRL2 register masks
// MIRORING SETTING:
// 0b00: no mirroring
// 0b01: mode 0 mirroring
// 0b10: mode 1 mirroring
// 0b11: mode 2 mirroring
enum rdma_reg_dmactrl2 {
	RDMA_DMACTRL2_XMIRR_LSB = 0, // Mirroring on X axis
	RDMA_DMACTRL2_XMIRR_MASK = 0x3,
};

```

Basically on initialization you have to configure a bunch of parameters related to the screen geometry, the video memory location, the source address of the sprite, etc. Then write the X, Y and mirror flags as needed, and start the DMA transaction writing to DMACTRL1. If this evolves, the idea would be having a bunch of preconfigured sprites, but currently you only have this set of register, so for example to draw a second sprite you would have to draw the first one, then change source address for the new sprite, dimensions if they change, etc. then draw it.

About people wanting to have a cart for testing: if there is enough interest I can make a bunch, but I would maybe need some advice for things like shipping, since it is something I have never done before. I live in Spain so maybe shipping inside Europe would not be problematic, but outside might be a problem.

---

<div class="post-metadata">

**Author:** ![SagaDS](https://forum.cpcwiki.eu/user_avatar/forum.cpcwiki.eu/sagads/32/160_2.png) [@SagaDS](https://forum.cpcwiki.eu/u/SagaDS)\
**Post date:** [November 4, 2026, 9:01pm UTC](https://forum.cpcwiki.eu/t/new-cartridge-design-romba/1122/8 "2026-11-04T21:01:40Z")

</div>

Hello, I have integrated mouse support on my minesweep clone (without X/Y scaling for the moment, but I have prepared code).

But it seems that winape returns bit0 = 1 on Port F990 and so it’s ON by default (and values for deltaX deltaY are -1 by default) so maybe 0xFF when nothing answers on a port is ‘normal’ (I don’t know as I don’t use a lot of hardware.

Do you have another way to tell if ROMBOX pi is present to check the port only when possible? Or maybe invert the bit 0 or provide a specific value to check (not only one bit) like 142 or 155.

If you want to test it with your card and tell me if everything is OK I will send it by DM.

---

<div class="post-metadata">

**Author:** ![CPC-International](https://forum.cpcwiki.eu/user_avatar/forum.cpcwiki.eu/cpc-international/32/707_2.png) [@CPC-International](https://forum.cpcwiki.eu/u/CPC-International)\
**Post date:** [November 4, 2026, 9:58pm UTC](https://forum.cpcwiki.eu/t/new-cartridge-design-romba/1122/9 "2026-11-04T21:58:29Z")

</div>

Right. Better to get rid of DDI5 in the first place and put disk emulation on the same card 😉 The RP2350 can handle both [https://youtube.com/playlist?list=PLa1DevUxKDmU&si=sxcJhFYr4qiDhYtl](https://youtube.com/playlist?list=PLa1DevUxKDmU&si=sxcJhFYr4qiDhYtl) We will probably put RAM expansion on top of ROM and disk emulation for the next PCB revision. This one lacks the required pins. Something has to give. But then, there are excellent RAM expansions such as Revaldhino’s available. But an all-in-one device is charming for sure.

In any case, the RP2350 IS AMAZING!!

---

<div class="post-metadata">

**Author:** ![doragasu](https://forum.cpcwiki.eu/user_avatar/forum.cpcwiki.eu/doragasu/32/1659_2.png) [@doragasu](https://forum.cpcwiki.eu/u/doragasu)\
**Post date:** [November 5, 2026, 8:09am UTC](https://forum.cpcwiki.eu/t/new-cartridge-design-romba/1122/10 "2026-11-05T08:09:36Z")

</div>

WinApe does not emulate this cart, and most likely reading from those ports will give you 0xFF all the time. SyX patched some games and also modified MAME to add ROMBA mouse support, I could ask him to release his modifications. Also @SoftDevil might try adding support to Caprice.

Until there’s a public release of an emulator with ROMBA support, if you want me to test your game no problem, you can DM me and I’ll test it.

About fractional scaling, using it is completely optional. Default config should work well for most games, and when needed it could be added even on a BASIC loader.

---

<div class="post-metadata">

**Author:** ![doragasu](https://forum.cpcwiki.eu/user_avatar/forum.cpcwiki.eu/doragasu/32/1659_2.png) [@doragasu](https://forum.cpcwiki.eu/u/doragasu)\
**Post date:** [November 5, 2026, 8:13am UTC](https://forum.cpcwiki.eu/t/new-cartridge-design-romba/1122/11 "2026-11-05T08:13:52Z")

</div>

The problem with RAM expansion, at least with my cart, is that I have no extra RAM soldered to the board (and I’m not planning to add it). So the only RAM I can use for RAM expansion is what the firmware is not using from the 520 KiB the RP2350 has inside. Depending on what ends on the cart, 256 KiB RAM expansion might be possible, but reaching 512 KiB is not (well, technically it could maybe be possible if you remove all the features but the ROM and RAM support, those should fit in 8 KiB).

Anyway, collision should not happen until an application tries using the RAM, right? So maybe instead of a switch, I could write into non volatile config (modifiable via write to a config port).

---

<div class="post-metadata">

**Author:** ![SagaDS](https://forum.cpcwiki.eu/user_avatar/forum.cpcwiki.eu/sagads/32/160_2.png) [@SagaDS](https://forum.cpcwiki.eu/u/SagaDS)\
**Post date:** [November 5, 2026, 9:48am UTC](https://forum.cpcwiki.eu/t/new-cartridge-design-romba/1122/12 "2026-11-05T09:48:53Z")

</div>

The question is: what do a real CPC without your extension when we read this port? If it returns -1 like winape then you need to send something else than just a 1 in bit 0 to tell if it’s here or not. A signature octet is enough from my point of view.  
I would prefer not create a version of my game with and without ROMBOX **π**. It either take advantage of it or not.

I send you a version in DM just to check if it plays better with a mouse.

---

<div class="post-metadata">

**Author:** ![doragasu](https://forum.cpcwiki.eu/user_avatar/forum.cpcwiki.eu/doragasu/32/1659_2.png) [@doragasu](https://forum.cpcwiki.eu/u/doragasu)\
**Post date:** [November 5, 2026, 10:50am UTC](https://forum.cpcwiki.eu/t/new-cartridge-design-romba/1122/13 "2026-11-05T10:50:42Z")

</div>

OK, you could consider the register as working like this (I’ll add it to the documentation):

| B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| PRESENT | R | R | R | R | R | R | STAT |

- Bit 7, PRESENT: 0 if ROMBA is connected to CPC, 1 if it isn’t
- Bit 6 through 1: reserved
- Bit 0, STAT: 0 if mouse is not detected, 1 if mouse is detected

Of course bit 0 can only be interpreted if bit 7 is 0. The reserved bits are just in case I add more features. For example I considered supporting two mice for two player games. If I implement that, bit 1 would be the status bit for the second mouse.
