Jump to content
IGNORED

ESP32 as a cartridge emulator


tschak909

Recommended Posts

I'm currently in the middle of doing hardware bring-up for #FujiNet for Coleco Adam, but it occurred to me, that there may be enough I/O pins to connect to data/address lines to emulate cartridge ROMs and any supporting mapping hardware.

 

This would have the advantage of being able to not only stream cartridges over the Internet, but also to provide network connectivity for new games.

 

Thoughts?

 

-Thom

  • Like 3
Link to comment
Share on other sites

I thought about that some time ago and decided that it isn't worth it. There's barely enough GPIOs, and it is not clear to me whether the ESP32 will tolerate the 5V bus of the VCS over an extended time --- you'd have to level shift It's an attractive platform, though, you get two cores and a full RTOS for managing them --- you can allocate one core to solely driving the bus and run everything else on the other one.

Link to comment
Share on other sites

Oh, and there is one other thing, I think that the boot-up time of FreeRTOS is too long (I brought it down to a few 100 millseconds in my own projects) to take over the bus before the 6507 comes up. You'd have to extend the bootloader to first "park" the VCS in RAM before continuing to boot the OS. However, that's doable

Link to comment
Share on other sites

4 hours ago, DirtyHairy said:

I thought about that some time ago and decided that it isn't worth it. There's barely enough GPIOs, and it is not clear to me whether the ESP32 will tolerate the 5V bus of the VCS over an extended time --- you'd have to level shift It's an attractive platform, though, you get two cores and a full RTOS for managing them --- you can allocate one core to solely driving the bus and run everything else on the other one.

When we moved FujiNet to ESP32, We talked with the designer of the ESP32, and confirmed that the ESP32 is indeed +5V tolerant for the GPIO pins over long periods of time. 

With about 1000 Fujinet in the field and functioning normally, this checks out.

 

Boot time is indeed the issue, we have a 557ms boot time due to SPIRAM initialization. Something to think about.

 

-Thom

Link to comment
Share on other sites

1 hour ago, tschak909 said:

When we moved FujiNet to ESP32, We talked with the designer of the ESP32, and confirmed that the ESP32 is indeed +5V tolerant for the GPIO pins over long periods of time. 

With about 1000 Fujinet in the field and functioning normally, this checks out.

Interesting, thanks, there is conflicting information in other places on the web, so it is good to have something close to an authoritative answer ? What would remain to be seen is whether the logic levels of the ESP32 on input pins are suitable for a clean readout of the 6507 bus.

 

I think the boot issue could be circumvented by extending the second stage loader that runs from SPI flash to drive the bus and run a small payload that makes the VCS jump into a RAM routine that idles until a ROM address is driven to a specific value. At that point the loader can continue to boot. The questionable point here is whether the the time required for the SPIROM loader to come up is sufficiently small.

 

I think this would be a very interesting platform if it can be made to work. Imagine one core driving the bus with a VCS program, and the other core running game logic in Micropython... ?

Edited by DirtyHairy
Link to comment
Share on other sites

Hm, this has raised my curiosity. I have done some more research, and it seems that first stage loader loads the second stage loader into RAM before it executes it, so this may still take too long (especially as it is likely that SPI flash has not been configured for full speed at this point). Another alternative would be to use a supercap to provide enough power to keep the ESP in deep sleep while the VCS is turned off. As soon as the bus is powered the ESP would wake up and execute a "wakeup stub" from RTC RAM. It seems this happens instantly, before the first stage loader is executed. The stub could park the 6507, and after that startup can continue normally.

Edited by DirtyHairy
Link to comment
Share on other sites

What about adding a secondary STM32 or simpler processor to the board to act as ROM emulator, with it talking to the ESP32 over an internal serial bus? It would increase BOM cost, but would solve all the timing issues, as it could init into a holding state until the ESP32 sends data.

Link to comment
Share on other sites

9 hours ago, tschak909 said:

yeah, that's doable. and would be a solid plan B, but the cost on this MUST be as low as possible.

 

-Thom

 

Agree, an extra micro on board seems overkill as the ESP is pretty powerful on its own. There should be a way to trick the 2600 into staying busy for a half second with minimal hardware. A bunch of resistors would do it, or a PLD could feed instructions. But I think it can be done with a single TTL chip. I will draw something up on a schematic later that may work and I’ll share it (as I personally have a need to solve this problem too for another project.)

  • Like 4
Link to comment
Share on other sites

22 hours ago, bcombee said:

What about adding a secondary STM32 or simpler processor to the board to act as ROM emulator, with it talking to the ESP32 over an internal serial bus? It would increase BOM cost, but would solve all the timing issues, as it could init into a holding state until the ESP32 sends data.

Using the ESP32 for driving the bus has the advantage that code running on the core not serving the bus could prepare data for the VCS without any communication overhead; once it is ready it can notify the other thread, which then can present the newly generated data to the VCS. This is similar to what CDF and DPC+ games do on the harmony, but the game logic on the ESP could run even while the VCS kernel is busy rendering, while the harmony has to put NOP on the bus while the game logic runs.

 

If an additional MCU is used this would require communication between both processors, while the secondary MCU is also busy serving the VCS.

Edited by DirtyHairy
Link to comment
Share on other sites

1 hour ago, DirtyHairy said:

Using the ESP32 for driving the bus has the advantage that code running on the core not serving the bus could prepare data for the VCS without any communication overhead; once it is ready it can notify the other thread, which then can present the newly generated data to the VCS. This is similar to what CDF and DPC+ games do on the harmony, but the game logic on the ESP could run even while the VCS kernel is busy rendering, while the harmony has to put NOP on the bus while the game logic runs

 

. If an additional MCU is used this would require communication between both processors, while the secondary MCU is also busy serving the VCS.

 

A custom bootloader is your friend, should get you to < 100ms boot times. A nice step by step on how to setup bootloader/bare metal/GDB here:

https://vivonomicon.com/2019/03/30/getting-started-with-bare-metal-esp32-programming/

 

Agree that using the ESP32 alone would be really cool. I built an Atari 800 / NES / SMS on one of those that generated composite audio/video entirely in software and still had plenty of time for a full emulation with bluetooth peripherals: https://rossumblog.com/2020/05/10/130/

 

One core will need to be pretty locked down to meet timing and some faffing will be needed if you still want wifi and bluetooth to keep working. If you wanted a single core version (ESP32S) you would probably need a modal strategy to be either running wifi or 2600 but not both simultaneously.

 

Jeroen Domburg is the right guy to ask about any ESP32 challenges / opportunities. Has built STM32F411 carts and is the heart and soul of ESP32 software.
https://spritesmods.com/?art=veccart&page=1

 

I really love these parts. A ESP32 dual core module with 4M of flash built can be had for $2.50 unit 1:

https://www.mouser.com/datasheet/2/891/esp32_wroom_32e_esp32_wroom_32ue_datasheet_en-1855879.pdf

The schematic for a cart would be preposterously simple: just the module and a voltage regulator.

 

 

Link to comment
Share on other sites

 

4 minutes ago, rossum said:

 

A custom bootloader is your friend, should get you to < 100ms boot times. A nice step by step on how to setup bootloader/bare metal/GDB here:

https://vivonomicon.com/2019/03/30/getting-started-with-bare-metal-esp32-programming/

 

Agree that using the ESP32 alone would be really cool. I built an Atari 800 / NES / SMS on one of those that generated composite audio/video entirely in software and still had plenty of time for a full emulation with bluetooth peripherals: https://rossumblog.com/2020/05/10/130/

 

One core will need to be pretty locked down to meet timing and some faffing will be needed if you still want wifi and bluetooth to keep working. If you wanted a single core version (ESP32S) you would probably need a modal strategy to be either running wifi or 2600 but not both simultaneously.

 

Jeroen Domburg is the right guy to ask about any ESP32 challenges / opportunities. Has built STM32F411 carts and is the heart and soul of ESP32 software.
https://spritesmods.com/?art=veccart&page=1

 

I really love these parts. A ESP32 dual core module with 4M of flash built can be had for $2.50 unit 1:

https://www.mouser.com/datasheet/2/891/esp32_wroom_32e_esp32_wroom_32ue_datasheet_en-1855879.pdf

The schematic for a cart would be preposterously simple: just the module and a voltage regulator.

 

 

Indeed, I am one of the guys behind FujiNet. http://fujinet.online/ :)

 

It should be possible to do a nice trimmed down firmware with disk slots being replaced by a single cartridge slot, removing the printer emulator (dunno what would actually use it), removing the wifi modem, and having the network adapter device.

I have developed a severe allergic reaction to the Bluetooth stack, as it is exceedingly memory hungry (lots of static allocation), so wouldn't add the bluetooth support, just use the WiFi.

 

One of the things that _really_ helped us, was using the WROVER-E module, with its large chunk of PSRAM, it is giving #FujiNet enough breathing room for just about anything that anyon wants to do with it, and would like to keep using it for new targets.

 

-Thom 

Link to comment
Share on other sites

13 minutes ago, tschak909 said:

 

Indeed, I am one of the guys behind FujiNet. http://fujinet.online/ :)

 

It should be possible to do a nice trimmed down firmware with disk slots being replaced by a single cartridge slot, removing the printer emulator (dunno what would actually use it), removing the wifi modem, and having the network adapter device.

I have developed a severe allergic reaction to the Bluetooth stack, as it is exceedingly memory hungry (lots of static allocation), so wouldn't add the bluetooth support, just use the WiFi.

 

One of the things that _really_ helped us, was using the WROVER-E module, with its large chunk of PSRAM, it is giving #FujiNet enough breathing room for just about anything that anyon wants to do with it, and would like to keep using it for new targets.

 

-Thom 

 

Agree that the BT stack is a mess. That said ESP_8_BIT includes a minimal HCI/L2CAP/HID stack implemented directly on top of the VHCI api. This hid_server implementation is designed to support EDR Keyboards, WiiMotes and other peripherals. The implementation is bare bones but supports paring/reconnections and is easily separable to be used in other projects. Might be useful for Fujinet if you reconsider: https://github.com/rossumur/esp_8_bit/tree/master/src/hid_server

 

Would also love a Fujinet in this form factor: https://hackaday.com/2015/11/03/minituarizing-the-atari-disk-drive/

cheers

 

Link to comment
Share on other sites

On 8/7/2021 at 6:40 PM, batari said:

Agree, an extra micro on board seems overkill as the ESP is pretty powerful on its own. There should be a way to trick the 2600 into staying busy for a half second with minimal hardware. A bunch of resistors would do it, or a PLD could feed instructions. But I think it can be done with a single TTL chip. I will draw something up on a schematic later that may work and I’ll share it (as I personally have a need to solve this problem too for another project.)

Following up here a little:

 

There are several ways I can think of to trick the console using only resistors. One way is to write pull-down resistors on all data pins but D4. Wire a series resistor between D4 and A0. I'd use something large like 10k or more to minimize the effect on the bus. Basically, all even addresses see $00, and all odd addresses see $10.

 

At the reset vector, the console sees $00, $10. It will boot at $1000 and immediate hit a BRK at $1000. Then the IRQ vector contains $00, $10 and the process repeats. You may be able to use a resistor array with common bus (lower pin count) and a single resistor for D4/A0, rather than needing 8 independent resistors.

 

However, this also fills the stack with garbage which means the TIA gets filled with junk for a time. It might not be objectionable if it's not set up like this for long. Another way that might work is to put pull-down resistors on D0-D3, pull-ups on D7, D6, and D5 and then a series resistor between A6 and D4. This will put either $F0 or $D0 on the bus at various locations. You'd get $F0F0 for the reset vector. At location $F0F0 the CPU will encounter $F0, $F0 which is a reverse branch (BEQ). The state of the flag doesn’t matter, because eventually (when A6=0) this will switch to $D0, $D0 which is BNE and progress through memory again until D6=1. So it will bounce back and forth in a limited memory space until things are ready and you can take over the bus. This may have a higher pin count but still, 8 resistors cost pennies.

 

If resistors on the bus isn't desired, I think either of the above schemes can probably be done with a single 74-series chip (74245). This is a transceiver chip, as it has A1-A8 and B1-B8, a signal direction pin and an /OE pin. I think you can wire A12 to the directional control pin, The data bus to B1-B8 and the above (high, low, and and address pin) to the appropriate pins on A1-A8. A pull-down resistor on /OE will be needed to enable the chip but after boot the ESP32 needs a control line pulled high to turn off this chip. That way you have control over the bus. The 74245 can be found in various forms for as low as 40 cents.

 

There might be a way to do this with a 74-series chip with a smaller pin count, I am not sure yet but investigating.

 

None of these methods are tested, they are just thoughts. If anyone can expand/improve I would like to hear.

  • Like 1
Link to comment
Share on other sites

  • 1 month later...
  • 3 weeks later...

@batari

 

Having some discussions with @mozzwald, @jeffpiep and @48kRAM.

 

A couple potential possibilities have come to mind:

 

* Using shift registers like the 597. @jeffpiep did a schematic for one, see attached. main-rc201903.pdf

* Using a really small CPLD (like a https://www.latticestore.com/products/tabid/417/categoryid/12/productid/408/default.aspx coupled with a bus transciever like: https://www.ti.com/product/SN74LXCH8T245

Thoughts?

Link to comment
Share on other sites

On 8/7/2021 at 4:20 AM, DirtyHairy said:

You'd have to extend the bootloader to first "park" the VCS in RAM before continuing to boot the OS.

 

? wonder if putting a single byte, such as $11, on the 6507's data bus could idle the 2600 for a long enough time without having to park the VCS in RAM.  If my thinking is correct:

  • 6507 would jump to address $1111, a fairly early address in cartridge space
  • 6507 would repeatedly execute ORA ($11),y which is a 2 byte instruction taking 5+ cycles

 

1FFF - 1111 = EEE, or 3822 bytes.  (3822 / 2) * 5 = 9555 cycles before the 6507 would exit the ROM addresses and crash the 6507.

 

If the bootloader process can finish in under 9555 9545 cycles of 6507 time then the last thing it would need to do is put the 3 bytes for JMP (RESET) on the bus. As @Al_Nafuur points out below, that should be the 4 bytes for NOP, JMP(RESET) on the bus.  

 

Also forgot to factor in the ROM needed for these 4 bytes, which reduce the 9555 cycles to 9545.

  • Like 1
Link to comment
Share on other sites

30 minutes ago, SpiceWare said:

 

? wonder if putting a single byte, such as $11, on the 6507's data bus could idle the 2600 for a long enough time without having to park the VCS in RAM.  If my thinking is correct:

  • 6507 would jump to address $1111, a fairly early address in cartridge space
  • 6507 would repeatedly execute ORA ($11),y which is a 2 byte instruction taking 5+ cycles

 

1FFF - 1111 = EEE, or 3822 bytes.  (3822 / 2) * 5 = 9555 cycles before the 6507 would exit the ROM addresses and crash the 6507.

 

If the bootloader process can finish in under 9555 cycles of 6507 time then the last thing it would need to do is put the 3 bytes for JMP (RESET) on the bus.

 

before feeding the JMP (RESET) you need to feed a NOP, because the 6507 might be in the middle of the ORA instruction and then your JMP would be interpreted as the operand of the ORA

 

I did something similar with the emulation exit function in the PlusCart:

https://gitlab.com/firmaplus/atari-2600-pluscart/-/blob/master/source/STM32firmware/PlusCart/Src/cartridge_emulation.c#L27

 

  • Like 1
Link to comment
Share on other sites

40 minutes ago, SpiceWare said:

 

? wonder if putting a single byte, such as $11, on the 6507's data bus could idle the 2600 for a long enough time without having to park the VCS in RAM.  If my thinking is correct:

  • 6507 would jump to address $1111, a fairly early address in cartridge space
  • 6507 would repeatedly execute ORA ($11),y which is a 2 byte instruction taking 5+ cycles

 

1FFF - 1111 = EEE, or 3822 bytes.  (3822 / 2) * 5 = 9555 cycles before the 6507 would exit the ROM addresses and crash the 6507.

$4C as single byte might work too. I seem to remember discussing this with @Andrew Davie before.

 

$4C would repeatedly execute JMP $4C4C which is (AFAIK) the mirrored TIA write address REFP1 so the TIA won't touch the data bus..

 

 

Link to comment
Share on other sites

Just now, SpiceWare said:

$4C4C isn't in ROM. The mirrored ROM addresses are $1xxx, $3xxx, $5xxx, ..., $FFFF.

It doesn't need to be in ROM. The important thing is that no one else on the data bus tries to answer the request from the 6507

  • Like 1
Link to comment
Share on other sites

3 hours ago, Al_Nafuur said:

$4C as single byte might work too. I seem to remember discussing this with @Andrew Davie before.

 

$4C would repeatedly execute JMP $4C4C which is (AFAIK) the mirrored TIA write address REFP1 so the TIA won't touch the data bus..

 

 

Maybe $4C will not work

 

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...