Skip to content
Diogo Valadares Reis dos Santos edited this page Aug 26, 2025 · 5 revisions

[Português]

[← Previous Page | Next Page →]

The Random Access Memory

The Random Access Memory (RAM) is an external component responsible for storing instructions and data for the system. Although RAM is not an internal component, it is required for the basic functionality of the system.

image

In DRISC-V, the RAM needs to be byte-addressable, allow read and write operations of words through a bidirectional bus, and be writable with three different data sizes (byte, short, and word) at any arbitrary offset. Word-misaligned data handling is not required by the RAM and is instead managed by the CSR Controller.

The DRISC-V architecture uses Little-Endian, which means that the least significant byte of a word is placed at the lowest address. For example, a NOP (No Operation) instruction, which is encoded as 0x00000013, is stored in memory as 13 00 00 00. Another example is the word 0x76543210, which in Little-Endian would be stored as 10 32 54 76, while in Big-Endian it would be stored as 76 54 32 10. While Big-Endian may seem more intuitive for reading RAM directly, placing the bytes with the largest value at the lowest address does not make much sense and complicates certain processes for the machine. This is why, like most computer systems today, DRISC-V utilizes the Little-Endian format.

The component used for the RAM in Logisim Evolution is native to the tool and does not contain any internal components. Along with the RAM, there is a micro-component called the Address Selector. This component allows a component to receive read-write signals only if the address transmitted by the processor is within a specified range.

image

In its general form, it can be read as:

    wire is_correct_address = (address_bus >= min_address) && (address_bus < max_address);
    wire write = write && is_correct_address;
    wire read = read && is_correct_address;

This micro-component is reused in each IO device, allowing only one to be active at a time.

In real systems, there is usually a component called a cache inside the processor, which serves as faster memory. However, this component has not been implemented in the current version of DRISC-V, and because of that, it is assumed that the RAM (as well as other IO devices) does not contain any delay in its data transmission.

SystemVerilog Code

The SystemVerilog code for the RAM contains extra features that allow it to directly load a program from a file every time the simulation is restarted, as well as parameters that allow its size to be modified. The file that initializes the RAM needs to be in a specific format, which will be explained further in the SystemVerilog Simulation page.

`timescale 1s/1s
//Parameters to customized the RAM
module ram #(
    parameter MEM_INIT_FILE = "", //The path for the file that will initialize the RAM
    parameter ADDR_WIDTH = 12, //How many bits are used for the RAM address
    parameter MEM_DEPTH = 1 << ADDR_WIDTH, //How many bytes can be addresses in the memory
    parameter PROGRAM_SIZE = MEM_DEPTH //The program file can be smaller then the RAM size, and this parameter allows you to specify its size in bytes
) 
//inputs and outputs
(
    input clock,
    input write,
    input read,
    input [1:0] data_size, // 00: 1 byte, 01: 2 bytes, 11: 4 bytes
    input [ADDR_WIDTH-1 : 0] address,
    inout [31:0] data
);

// Memory array
    reg [7:0] mem [0:MEM_DEPTH-1];
//If the ram is not being read or is being written to, it should be disconnected from the Data IO Bus.
    assign data = (read && !write) ? {mem[address+3], mem[address+2], mem[address+1], mem[address]} : 32'bz;

//Inicializes the ram with a program file, or zeroes if a program is not specified.
    initial begin
        integer i;
        for (i = 0; i < MEM_DEPTH; i = i + 1) begin
            mem[i] = 0;
        end
        if (MEM_INIT_FILE != "") begin
            $readmemh(MEM_INIT_FILE, mem, 0, PROGRAM_SIZE-1);
        end
    end

//Write logic
    always @(posedge clock) begin
        if (write) begin
            case (data_size)
                2'b00: mem[address] <= data[7:0];
                2'b01: begin
                    mem[address] <= data[7:0];
                    mem[address+1] <= data[15:8];
                end
                2'b10: ; // Invalid case, do nothing
                2'b11: begin
                    mem[address] <= data[7:0];
                    mem[address+1] <= data[15:8];
                    mem[address+2] <= data[23:16];
                    mem[address+3] <= data[31:24];
                end
            endcase
        end
    end
endmodule

Clone this wiki locally