Friday, January 18, 2013

How to use cellular ram from micron M45W8MW16

Purpose/Goal/Desire:
To use the micron cellular ram as if it was a block ram.
A cpu is useless without ram.  My original approach was to use
block ram to create a ROM to store the main program files. and then
to use block ram for general purpose ram to store the stack and heap stuff.
When it came down to synthesis, I found that I only had enough block ram
for the rom.  I had two options, buy a bigger machine, or use micron's block ram.
It took a large sum of time to figure out how to use it, but in the end it paid off.

Remember that this is a guide in using asynchronous mode.  Its slower, but it makes everything
more homogenous.  And since I'm using it as a ram, I have no idea where the cpu is going to set/get the data.

Stuff that you need to make it work:

  1.  spec sheet
    1. They added an extra T to the name, making it harder to find
  2. Spartan 6 on nexus 3
    1. it has enough bram for a 32kx16 rom.  If you have a bigger board then you probably don't need to use the micron cellular ram.
  3. A guide for asynchronous mode
    1. pay attention to only slides 13,14, 21, and 22
  4. xilinx (i used version 14, but other versions should still work)

Gotchas

  1. You gotta let the device power on before you can use it. see init state in the FSM
  2. The specs say that you can do async read and write in 70 ns.  True, but once you add the commands to start the device up you get closer to 100 ns.
  3. using tristate buffers on the bidirectional dq bus is a must.
  4. The specs brag about the memory running at 80mhz, but that is for burst/page mode which are much harder to use.  Async mode will get you 10mhz.


my FSM

T : timer 10 ns

//These pins are used to talk to the celular ram  (memory_interface <--> cellular_ram);
addr_o : out std_logic_vector( addr_width-1 downto 0);
clk_o : out  std_logic;
addr_valid_o :out std_logic;
cntl_reg_enable_o : out std_logic;
chip_enable_o : out std_logic;
output_enable_o : out std_logic;
write_en_o : out std_logic;
lower_byte_en_o : out std_logic;
upper_byte_en_o : out std_logic;
data_io : inout std_logic_vector( data_width-1 downto 0);
wait_i : in std_logic;
//These are the pins used to help interface the memory as if it were a block ram ( some module <--> memory_interface);
addr_i : in std_logic_vector (addr_width-1 downto 0);
we_i : in std_logic ;
data_i : in std_logic_vector (data_width-1 downto 0);
data_o : out std_logic_vector (data_width-1 downto 0);
clk_i : in std_logic;
go_i : in std_logic //top module should set this to 0.  when ready to use, set to 1 for one cycle (max 90 ns) then bring down.  when go_i is high it will read or write otherwise it will be idle.;

View this high level pic to see where everything falls in place

Code: the stuff you probably just wanna take and play with right out of the box and probably the only thing you care about

memory interface

component used to interact with the memory interface

The two links above are synthesis able.  I linked them together in a wrapper file, loaded them on to the FPGA and crossed my fingers.  The first link goes to the source code for the memory interface.  It lets you use the memory as if it was a block ram.  But be warned....you may only read/write every 100ns.  Any slower will cause unexpected data.  Going slower is pretty much acceptable.  Oh yeah, remember to toggle the go_i input when you want to read/write.

the second link takes you to what looks like a massively long entity.  In actuality it has several architectures.  Each architecture has a different test.  One of them writes to 16k memory arrays one after the other, then reads them one after another.  Another test jumps really far to write and then jumps to read each of them.



6 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Thanks a lot - much simpler than the Digilent example which was needlessly complicated by the "silly" Epp interface.

    ReplyDelete
  3. Do you have a timing diagram? I tried to instantiate it, but got duff data back after writing constant values.
    Thanks

    ReplyDelete
  4. OK, seem to have got it now. Raise 0 to 1, wait for a few 10s of nanoseconds, then pulse high for 1 clock cycle, wait few 10s of nanoseconds an drop back to zero. For read, pulse go for 1 clock cycle and wait a bit and then latch the data bus.

    ReplyDelete
  5. Sorry, seem to have lost the vital signal names!
    OK, seem to have got it now. Raise we_i 0 to 1, wait for a few 10s of nanoseconds, then pulse go high for 1 clock cycle, wait few 10s of nanoseconds an drop we_i back to zero. For read, pulse go for 1 clock cycle and wait a bit and then latch the data bus.

    ReplyDelete