Writing to external RAM that is also accessed from another host?

Hi, I have just done a very successful project with an ATmega32u4 Pro Micro where I transfer data from a PC to a Commodore 64 through its UserPort at a great speed. For quick transfer and testing of code on a real machine its a fantastic little and cheap way to achieve this. I was actually quite surprised how easy it was - and it was my first project with Arduino.

Now, I have another idea for integration that is quite a bit more complex and that is to use the Arduino to write to some sort of RAM that is also accessed as a ROM would normally through the cartridge port of the C64. The standard ROM used for most C64 cartridges is normal 8KB 2764 EEPROMS. Although the address bus can access a full 64KB, the C64 only sees 8KB at a time so more advanced and bigger cartridges did simple bank switching logic to reach all 64KB (and indeed bigger ones).

Well I know its rather easy to add RAM to an Arduino, although its both rather slow to write and read, normally through SPI type of communication. Write speed does not bother me as its very little data we are talking about here - but I need the circuit to also be able to address the RAM from the C64 at the same time! Yes so instead of being a plain ROM it works like a piece of 8KB memory that is dynamically altered by Arduino. Imagine the possibilities. :slight_smile:

My question is rather simple, how hard would it be to do this? The C64 is a rather old device running at 1Mhz so I can't imagine timing for adressing the RAM would be a big problem - although I have no idea how one would achieve this and how to make the Arduino writing to RAM and the C64 reading it not tripping over each other. From what I have seen from another project where the Arduino was used to dump the contents of a C64 cartridge the only thing he did to read it was set the address bus pins and read the data pins after. I somehow doubt the Arduino have high enough speed to emulate that, and besides it has too little memory as well.

Here is some info about the C64 Expansion Port:

https://www.c64-wiki.com/index.php/Expansion_Port

What could you do with something like this? http://www.atmel.com/Images/doc4146.pdf

Cheers!

As far as I remember the 6502 is only active on one half of the cycle,
so maybe you could access the memory in the other half.

That way the Apple II interleaved the CPU with the screen generation via TTL-DMA.

Yes, you can multiplex the address/data/control lines between 2 controllers to share access to a device like an SRAM, either in parallel format or a serially controlled device. Leo72 actually did this a while ago a with a parallel access SRAM.
http://forum.arduino.cc/index.php?topic=21917.0

Wouldn't Dual-ported_RAM DP(S)RAM be the cleanest approach?
They are designed exactly for that type of application.

IDT Synchronous Dual-Port RAMs | Renesas

App note http://notes-application.abcelectronique.com/007/7-12139.pdf

Dual-Ported SRAM seems to be a nice approach. Just one question, does these work so you can write to them at the same time they are read from, or is there some sort of handshake between the two sides that needs to be done or being careful of? I realize its possible for race conditions with regards to data corruption if one writes to the same address as being read from but that is something I can manage.

Also, is it easy to write to these from the Arduino using few pins? Would I need some kind of mux for this or are the Dual Ports set up to this kind of communication too? From the Commodore 64 I would need full 16 bits address and 8 bits data bus access though.

As far as I understood, there are different types of DPRAMs with different restrictions,
but reading and writing at the same time (from different sides) should be possible.

Many pins to control means many pins for full speed.
Using shift registers slows you, but saves a lot of pins.

Maybe a Mega (or at least its processor) could be used to acces the memory.

An optional external data SRAM can be used with the ATmega640/1280/1281/2560/2561. This SRAM will occupy
an area in the remaining address locations in the 64K address space. This area starts at the address following the
internal SRAM. The Register file, I/O, Extended I/O and Internal SRAM occupies the lowest 4,608/8,704 bytes, so
when using 64Kbytes (65,536 bytes) of External Memory, 60,478/56,832 Bytes of External Memory are available.
See “External Memory Interface” on page 27 for details on how to take advantage of the external memory map.

Dual port SRAM is very pricey. Double buffering from both sides with a pin to show who has access (see arbitration) is much less expensive way to go.

Ok so the Mega then extends the SRAM that the CPU can address directly, which is no doubt the fastest way. But I am not so sure I can deliver the data from the Mega if that reads and do direct port manipulation of 8 data pins based on 14 address pins. The ports are a mess on the Mega as well so even direct port manipulation to read the address pins isnt simple, since some of those would be mid-bit on a different port. The microcontroller would likely hardly be able to keep up mapping this to a read and setting the data bytes - which defeats the purpose of the project, that I can dynamically adjust that 8KB over a USB connection or Wifi (if using an ESP8266 on it at well).

Likely dual port is easier - and around $10 isn't really expensive for a project like this. But you say double buffering with a pin to show who has access, I am not sure if I even get a signal that the C64 is accessing the bus you see (but perhaps there is), as I believe its hardwired directly to the address/data bus of the machine, although its possible to control whether it is visible on the bus or not. I am not sure how the behaviour would be, but likely I could control the access from the Arduino, by sending a signal to the C64 when the data can access the expansion port (and that way switch its visibility in and out). It would likely be more than powerful enough if I could just read/copy down its contents to C64 memory.

Here is a description of how the cartridge port of the C64 works:

http://blog.worldofjani.com/?p=879#prettyPhoto

It's all rather simple. Although studying the port there is a pin called R/W so that is likely then used to indicate if data should be read or written to the address (although traditionally the external carts never had write access as far as I know).

Previously I have been working with a game cartridge (for a game I developed myself for the C64 called Rocket Smash) that had a 64KB of memory split into 8 banks of 8KB each. By writing to address $de00 it was possible to adjust the bank that was visible, but I assume this was special handing on the cartridge that adjusted the addressing. There is a special IO address in the C64 that is mapped to a pin on the expansion port. From the "Mapping the C64" book:

Location Range: 56832-57087 ($DE00-$DEFF)
Reserved for I/O Expansion

This range of locations is not used directly by the 64's internal
hardware. It is, however, accessible via pin 7 of the Expansion Port.
It can be used to control cartridges which are connected to this port.
For example, the CP/M module uses this space to control which
microprocessor is in control of the system. The Z-80 microprocessor
is turned on and off by writing to 56832 ($DE00).

Another cartridge which uses this space is Simon's BASIC. This 16K
cartridge is addressed at memory locations 32768-49151 ($8000-$BFFF),
which means that it overlaps the regular BASIC ROM at 40960-49151
($A000-$BFFF). But since it contains additions to BASIC, it must use
the BASIC ROM as well. This problem is solved by copying the
cartridge at 32768-40959 ($8000-$9FFF) to RAM, and turning the
cartridge on and off by writing to or reading from location 56832
($DE00).

johncl:
By writing to address $de00 it was possible to adjust the bank that was visible, but I assume this was special handing on the cartridge that adjusted the addressing.

This is probably a simple latch holding three of the address bits.

On this site you can see some bus-timings for c64

http://www.frank-buss.de/c64/timings2/index.html