PlusROMs can communicate with their dedicated back end in the internet. Sending and receiving bytes to and from these hosts does not need a waitroutine in the VCS RAM!

The back end path and hostname (or IP address) must be encoded as '\0' terminated strings inside the ROM. The NMI vector (1FFA and 1FFB) of the last bank is used as a pointer to these strings. The base address (ROM file start) is 1000. Hostname and path can be defined everywhere in the ROM file up to address $efff. Even the RAM area or the bankswitching and PlusROM hotspots can be used.

These definition is only needed by PlusROM functions enabled hardware or emulators at startup, to detect that PlusROM functions are used by this ROM and of course to know where to send and receive the data.

Currently the PlusROM functions are supported by the PlusCart, Gopher2600 and javatari.js with 2K, 4K, 3F, 3E and 3E+ cartridges and any standard bankswitching cartridge with or without 128 bytes of RAM (@ 1000 to 10FF) and a 'Standard' F4 Bankswitching (@ 1FF4 to 1FFB).

PlusROMs functions use 4 hotspot adresses (before the bankswitching area):

  • 1FF0 is for writing a byte to the send buffer (max 256 bytes)
  • 1FF1 is for writing a byte to the send buffer and submit the buffer to the back end API
  • 1FF2 contains the next byte of the response from the host, every read will increment the receive buffer pointer (receive buffer is max 256 bytes also!)
  • 1FF3 contains the number of (unread) bytes left in the receive buffer (these bytes can be from multiple responses)

The bytes are send to the back end as content of an HTTP 1.0 POST request with "Content-Type: application/octet-stream". The "PlusStore-ID" header of this request starts with the Firmware version (e.g. "v0.7.1") and after a space a 24 Hex digit which is the STM unique device Id, for identifing the cart at the back end.

The response of the back end should also be a "Content-Type: application/octet-stream" and the response-body should contain the payload and the first byte of the response should be the length of the payload, so "Content-Length" is payload + 1 byte. This is a workaround, because we don't have enough time in the emulator routine to analyse the "Content-Length" header of the response.

These definitions may change in the future (depending on the suggestions of experienced VCS Programmer).

The PlusROM emulation routine has been ported to javatari.js the forked repository is here and your homebrew PlusROMs can be tested here

VCS Developer hints

You can determine inside your ROM whether PlusFunctions are available or not, by checking the response buffer size ($1ff3) at startup. If you define, in your asm-code, a different value than 0 for that address:

org $1ff3
.byte #255      ; Counter for Receive Buffer

if you read at startup with "lda $1ff3" the value you have defined and not a "0", you know the emulator/cart has no online functions.


The PlusCart is sending an unique Id ("PlusStore-ID" header) with every request.

This unique Id should not be published by a PlusROM back end. There will be an API at the PlusStore where "registered" back ends can query the User-Name (and in future maybe more) of the owner of this specific Cart.

Of course this will only work for registered/connected PlusCarts.

For unregistered PlusCarts the back ends have to query their necessary information thru the ROM (input-field or select box...) or use a hash (e.g. md5) of the unique Id!

Emulators should generate a "PlusStore-ID" http-header with their request, that consists of a nickname given by the user and a generated uuid (starting with "WE") separated by a space character.