So many memories Nov 16, 2016

An EP4CE6 FPGA has 30 KB of built-in “Block RAM” memory. Fast, but limited in size. With SDRAM, you can have megabytes more, but it’s not quite as fast and harder to interface to, due to the periodic refreshes.

Another option is normal static RAM. Low-cost chips are available in various sizes and speed grades, e.g. this 512 KB chip on eBay.

SRAM still needs some glue logic to get the details right, but the result is predictable timing. This (basic!) SRAM controller needs 3 clock cycles per access, but it supports a 100 MHz clock, i.e. 30 ns per read or write.

I decided to create a little breakout board for these 44-pin TSSOP chips:

To stay within low-cost PCB manufacturing limits, the board is less than 50x50 mm. It won’t accommodate a full 2x20 pin header, but there are enough I/O pins to simply leave the outer four disconnected:

As you can see, I had to fix the PCB, i.e. cut one of the traces and re-route it manually using Kynar wire, used for wire-wrapping.

I don’t know why, but Quartus refused to let me define a connection on pin 101, so I had to use a spare pin on the header (pin 110).

Note that connecting the chip is only half the story. Once you have such a controller implemented, it needs to be tested - open or shorted wiring, but also driving the chip for extended periods to make sure it’s reliable.

For now, I’m re-using my SpiPeek trick, i.e. running a full test in Forth from a HyTiny:

The test code is simple. First we define two words to send and receive one SRAM byte:

31 bit constant SR.REQ
 8 bit constant SR.WRn  \ will be lshifted 22 more

: sr-cycle ( data addr -- u )
  swap  22 lshift or
  dup            >fpga> drop
  dup SR.REQ or  >fpga> drop
                 >fpga> ;

: >sr ( data addr -- )  sr-cycle drop ;
: sr> ( addr -- data )  SR.WRn swap sr-cycle 22 rshift $FF and ;

With these, we can define additional words:

Verification errors are reported on Forth’s serial console. Here is the code:

19 bit constant TEST-SIZE  \ 14 = 16 KB, 19 = 512 KB, 21 = 2048 KB

: test-range ( leds -- hi lo )  3 and 20 lshift  dup TEST-SIZE or  swap ;
: test-value ( n -- u )  211 * 8 rshift $FF and ;

: zero-ram ( leds -- )
  test-range do
    0 i >sr
  loop ;

: fill-ram ( leds -- )
  test-range do
    i test-value  i >sr
  loop ;

: zero-check ( leds -- )
  test-range do
    i sr>  if cr i hex. i sr> h.2 ." ?" then
  loop ;

: fill-check ( leds -- )
  test-range do
    i sr>  i test-value xor  if cr i hex. i sr> h.2 ." ?" then
  loop ;

And finally, a continuous test:

: test
  0  begin
    dup fill-ram    1+
    dup fill-check  1+
    dup zero-ram    1+
    dup zero-check  1+
  key? until  drop ;

There is a counter (on the stack), which gets incremented after each phase - this counter is sent to the FPGA board, and is connected to its LEDs. That way, successful tests are easy to spot: a binary counting pattern on the LEDs and no output on the serial port.

All 524,288 bytes work flawlessly, with the FPGA code running at 100 MHz. Note that this test is not a full speed back-to-back test: SpiPeek takes 10..20 µs per command, during which time the SRAM sits idle.

But still, it’s a good start: half a megabyte of RAM, who could possibly need more, eh?

Update - Puzzle solved: pin 101 is “nCEO”, Quartus must be told to allow normal I/O.

Weblog © Jean-Claude Wippler. Generated by Hugo.