Logic Design - How to write simple RAM in VHDL

Custom thumbnail using:


Hello Steemians it's a me Drifter Programming!
   Today we get back to Logic Design to talk about the implementation of many simply types of RAM in the Hardware Description Language (HDL) that we covered during my series which is VHDL! (I promised to do Verilog also and it will come in the following Weeks I promise!)

    To understand what I will be talking about I highly suggest you to refresh your knowledge using my series that contains simulating the circuits and even the implementation of more complex units like the ALU that does mathematical operations for CPU's!

You  can find the previous posts in my recap!

So, without further do, let's get RAMing! xD

RAM architecture and types

So, let's start with the simple question:
What is RAM?

    RAM is defined as Random-Access Memory and allows us to read and write information to a physical location inside of the RAM which is the so called memory array.

    Lots and lots of types of RAM are out there nowadays, but an basic separation can be done by saying that there are:

  • Static RAM's (SRAM)
  • Dynamic RAM's (DRAM)

Static RAM

    SRAM is static, which means that it has a specific number of memory cells that build up the memory array. This of course means that it's more expensive to produce (more transistors, cause each bit of data is stored in a specific predefined location), but also faster and less power consuming than DRAM.

This type of RAM is mostly used in Cache memory of CPU's.

Dynamic RAM

    DRAM is stores the bits (information) using a transistor-capacitor pair which create a so called DRAM cell. This means that the capacitor will either be charged (1) or not charged (0) and that the access is defined using the transistor that acts like a switch that let's us "read/write" the capacitor or not.

Because it's less expensive to build it's the predominant form of computer memory nowadays!

Some information from wikipedia.

    Either way any RAM is considered volatile, cause it loses it's state and so information whenever there is a power loss or reset. To store information permanently we use another type of memory called ROM, that I will cover next time!


We covered the basic types of RAM, but what is the I/O of RAM?

Of course RAM communicates using the following:

  • Data Input -> information to write
  • Data Output -> information to read
  • Address -> we need to know where to read or write
  • Read/Write -> specifying if we want to read or write from an address
  • Enable -> we enable the RAM only when needed to "save power".
  • Clock -> RAM is of course a synchronous circuit and so needs a Clock Input 

    Depending on the application we may want to read and write at the same time, and maybe even on different addresses. This can of course be done by having 2 addresses and two separate read and write signals.

This means that RAM can also be splitted into these categories:

  • Single-Port RAM with separate read and write signals (no enable needed) 
  • Single-Port RAM with a single read/write signal and RAM enable
  • Dual-Port RAM with separate signals (that may be combined R/W signals) for each "line"

    We can of course continue on and insert 3, 4 or even more lines as we wish, but I guess that after a point a second or even third memory might be better.

Combined R/W or not

    You can see that the read/write signal can be defined as a combined signal or as two separate ones, but when do we use each one?

    RAM is a synchronous circuit which means that the information will be stored into it (or the requested send to the output) after a clock event...

    If the application we have needs to be able to read at the same clock without having to wait for a clock event or even a whole clock period, then we can simply define only a write signal (1 -> write, 0 -> not write) and make the output show us directly what the specified address has, which means that we read all the times, without having to specify that we want to! Keep in mind that this implementation should contain a memory enable signal!

    In VHDL we will of course only implement static RAM that is build up of memory cells and so creates a memory array.

So, let's get into the implementation of these 3 categories we talked about.

VHDL implementation of Single-Port RAM with Read and Write signals

The VHDL code looks like this:

    You can see that I used the generic declaration to specify the address length and data length, so that it's easier to edit those values afterwards.

    Also, note that I use a conv_integer() function that takes in the address which is in binary and converts it to an integer which is used in the declaration of the memory array!

The actual memory array is a user-defined type of 2^n- bit memory celss for a n-bit address.

    You can see that when reading or writing we have to set the specific "enable" signal to '1', cause else nothing is gonna happen.

Here a small simulation using Modelsim:

    You can see that I first define the clock signal using the "right-click"-technique and that I then write and read the value "10100110" into/from the address "00000000".

    Note that stuff gets written or read only on a rising edge of a clock and so the yellow-line is the point where we "read". Because the clock starts with '1' we of course "write" directly!

VHDL Implementation of Single-Port RAM with one combined R/W signal and RAM enable

    To make it even more interesting let's make it so that we read with '0' and just keep the then specified address in a temporary signal and simply send this directly to the output all the times!

The VHDL code looks like this:

We simply need a combined r/w signal and a mem_enable signal.

    To make it easier for us to output what we read we also specify a temp_address signal which will store the last address for which we have rw_enable = '0' (read) and so outputs the information of that address to data_output!

    Running it for another input and address you can see that we again have to wait for a rising edge, but this time the write/read signal is actually the same signal and specifying if we want to do something in general is of course done using the mem_enable signal.

Here a Modelsim simulation graph:

VHDL implementation of Dual-Port RAM with Combined Read and Write signals

To do this we simply have to "duplicate" the previous design!

The code looks like this:

    From all the stuff duplicates and to make it easy to enable/disable the ports I also included a new port_enable signal for each line!

Let's simulate it so that port1 writes and port2 reads from the same address:

You can find all the codes that I implemented here on pastebin:

How and when to use RAM in your designs

So, that's cool and all, but when should you use it?

    Well, whenever you have ton of information it's not good if you store information directly into registers, cause registers make the design more expensive and also can't store that much and so you end up with a ton of registers!

    This means that large information should be stored into RAM modules that should have the right data-size and also that exact "space" that you need to store your stuff.

Ok, so this covers when, but how do we use it?

Well, this is of course more complicated...

    To manage RAM we have to create a FSM (finite-state-machine) or control unit that sends signals to the different modules of our design and organizes, synchronizes our workflow. Or we could also send the signal directly from the module that wants to store.

    For example a multplier or adder could send a write-signal to the memory and store the calculated result into the memory. The problem would be managing the address for which an FSM (which could even be a simple binary counter) has to be used.

    I guess that it's really up to you to how you will use it and of course the amount of lines, exact type of RAM, and maybe even unique signals can be changed, tweaked etc. by you any time when you think that it might help with the performance of your circuit!

Always remember faster and smaller is what we need in Internet of Things (IoT) nowadays!

And this is actually it and I hope that you enjoyed it!

    Next time I think of covering how we implement ROM (read-only memory), cause a lot of times information just has to be read and we don't have to re-write stuff to the memory!


3 columns
2 columns
1 column