Skip to content

RAM (pt‐br)

Diogo Valadares Reis dos Santos edited this page Aug 26, 2025 · 1 revision

[English]

[← Página Anterior | Próxima Página →]

Memória de Acesso Aleatório (RAM)

A Memória de Acesso Aleatório (RAM) é um componente externo responsável por armazenar instruções e dados do sistema. Embora não seja um componente interno, a RAM é essencial para o funcionamento básico do sistema.

RAM no Logisim

No DRISC-V, a RAM precisa ser endereçável por byte, permitir operações de leitura e escrita de palavras por meio de um barramento bidirecional, e ser capaz de escrever dados com três tamanhos diferentes (byte, short e word) em qualquer deslocamento arbitrário. O tratamento de dados desalinhados por palavra não é responsabilidade da RAM, sendo gerenciado pelo Controlador de CSR.

A arquitetura DRISC-V utiliza o formato Little-Endian, o que significa que o byte menos significativo de uma palavra é armazenado no endereço mais baixo. Por exemplo, uma instrução NOP (sem operação), codificada como 0x00000013, é armazenada na memória como 13 00 00 00. Outro exemplo é a palavra 0x76543210, que em Little-Endian seria armazenada como 10 32 54 76, enquanto em Big-Endian seria 76 54 32 10. Embora o Big-Endian possa parecer mais intuitivo para leitura direta da RAM, colocar os bytes de maior valor nos endereços mais baixos complica certos processos da máquina. Por isso, como na maioria dos sistemas modernos, o DRISC-V utiliza o formato Little-Endian.

O componente usado para a RAM no Logisim Evolution é nativo da ferramenta e não contém componentes internos. Junto com a RAM, há um microcomponente chamado Seletor de Endereço. Esse componente permite que um dispositivo receba sinais de leitura/escrita apenas se o endereço transmitido pelo processador estiver dentro de um intervalo especificado.

Seletor de Endereço

Na sua forma geral, pode ser lido como:

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

Esse microcomponente é reutilizado em cada dispositivo de E/S, permitindo que apenas um esteja ativo por vez.

Em sistemas reais, geralmente existe um componente chamado cache dentro do processador, que serve como memória mais rápida. No entanto, esse componente não foi implementado na versão atual do DRISC-V, e por isso assume-se que a RAM (assim como outros dispositivos de E/S) não possui atraso na transmissão de dados.

Código SystemVerilog

O código SystemVerilog da RAM contém recursos extras que permitem carregar diretamente um programa a partir de um arquivo sempre que a simulação for reiniciada, além de parâmetros que permitem modificar seu tamanho. O arquivo que inicializa a RAM precisa estar em um formato específico, que será explicado na página de Simulação SystemVerilog.

`timescale 1s/1s
//Parâmetros para personalizar a RAM
module ram #(
    parameter MEM_INIT_FILE = "", //Caminho para o arquivo que inicializa a RAM
    parameter ADDR_WIDTH = 12, //Quantidade de bits usados para o endereço da RAM
    parameter MEM_DEPTH = 1 << ADDR_WIDTH, //Quantidade de bytes endereçáveis na memória
    parameter PROGRAM_SIZE = MEM_DEPTH //O arquivo do programa pode ser menor que a RAM, este parâmetro define seu tamanho em bytes
) 
//Entradas e saídas
(
    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
);

// Array de memória
    reg [7:0] mem [0:MEM_DEPTH-1];
//Se a RAM não estiver sendo lida ou estiver sendo escrita, deve ser desconectada do barramento de dados
    assign data = (read && !write) ? {mem[address+3], mem[address+2], mem[address+1], mem[address]} : 32'bz;

//Inicializa a RAM com um arquivo de programa ou com zeros, se nenhum for especificado
    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

//Lógica de escrita
    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: ; // Caso inválido, não faz nada
                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