0
\$\begingroup\$

I am creating a homebrew computer and am stuck on how to design/approach handling data requests between two different sections. I am creating it from mostly 74HCxxx series logic chips.

I have a homebrew CPU that runs at 1Mhz and has a bus to the RAM. It has 32 address lines and 32 data lines along with a Clock and Read lines. So an address is placed on the address lines and if the Read line is high then it expects the appropriate data to be placed on the data lines immediately. If the Read is low then the CPU also places a value on the data lines and the memory should update at the next clock tick. All very simple and works because the SRAM is comparatively fast (~50ns) and easily meets the timing needs of the CPU (1000ns).

I have now created a separate piece of hardware which is a video driver. It works at 12.587Mhz in order to output a low res VGA signal. It internally has some SRAM memory that stores the data for display. This works fine on its own.

But I have no idea of the correct approach to getting the CPU to be able to send data to the video driver. I want the video driver to be memory mapped and so when the CPU writes to a defined range of memory addresses the video driver will notice this and pick up the new value and store it internally. It would be nice to be able to also read from the video driver memory but that is optional.

I am a programmer and have no training in electrical enginerring so this might be trivial to others but not obvious to me. Should I be looking at FIFO buffers? Do I need some complicated interface between the two? My concern is that they are going at different clock speeds and so sometimes they will clash in timing?

\$\endgroup\$
  • 1
    \$\begingroup\$ Either use a contention resolution mechanism or use dual-port RAM. \$\endgroup\$ – Ignacio Vazquez-Abrams Nov 8 '16 at 1:38
  • 1
    \$\begingroup\$ If the CPU wants to write to the RAM and the video driver read at different addresses then how would that work? \$\endgroup\$ – Phil Wright Nov 8 '16 at 2:12
  • \$\begingroup\$ Either one of them waits or they're using different ports. \$\endgroup\$ – Ignacio Vazquez-Abrams Nov 8 '16 at 2:26
  • \$\begingroup\$ Am I the only one who recognises this is exactly the problem solved by the ULA chip in a Spectrum 48k home computer? I think it used a simple principle of triggering the HALT function of the CPU when it was reading video memory to be output to the display, if the address ranges overlapped. \$\endgroup\$ – Simon Tillson Nov 8 '16 at 2:29
  • \$\begingroup\$ I grew up using the ZX Spectrum and ZX81. I want to avoid stalling the CPU to help out the video driver. \$\endgroup\$ – Phil Wright Nov 8 '16 at 3:21
2
\$\begingroup\$

There are 4 solutions (maybe a few others?), none of which are perfect.

a) Grab a video cycle. Simple, cheap, low hardware cost, snow on the screen.

Build a simply synchroniser interface to the video RAM, and give the CPU prioroty. After all, it will only write at a max of one per uS, where the video is reading 12 or so per uS. Every video cycle, has the CPU written a word? If yes, perform a write, if not, read a pixel to display. Snow can be mitigated by repeating the last video output pixel, rather than outputting a fixed value.

b) Insert a write cycle. Simple, no snow, needs faster video RAM.

Arrange the video RAM timing so there are two cycles per pixel, a CPU write (most of which will be idle) and a pixel read.

c1) Save all writes for retrace intervals. No snow, needs a wide FIFO.

Write pixel values and addresses into a FIFO, burst the FIFO into the video RAM when the screen is dark

c2) only write during blanking intervals. No need for FIFO, but restricts CPU update speed. Saves a synchroniser.

Switch the video RAM bus over to the CPU during retrace, let it write randomly.

d) Double buffered. Simple, no snow, needs twice as much video RAM.

Have two RAM buffers, one outputting to screen, one being written from the CPU. Swap them over sufficiently often. RAM is cheap. You may want a hardware BLIT or some extra software to fast update the buffer that wasn't being updated by the CPU when you next get it.

e) (I thought there'd be more than 4!) Wide RAM.

This is one I implemented back at the start of the '80s, when RAM was slow and expensive. Full speed RAM is arranged 2 wide, so does one read of two successive pixels every 2 pixel times. A simple mux serialises the pixels out to the display, and that spare cycle is then available for a random CPU write. 2 could be generalised to N, if necessary.

f) (I'm sure I can't have listed them all!)

\$\endgroup\$
  • \$\begingroup\$ Thanks for the great answer. That is more options that I would ever have thought of myself. I am thinking of going with the dual ported RAM because it would be easiest to implement and I only need a few kilobytes of memory. \$\endgroup\$ – Phil Wright Nov 8 '16 at 22:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.