ℹ️ Select 'Choose Exercise', or randomize 'Next Random Exercise' in selected language.

Choose Exercise:
Timer 00:00
WPM --
Score --
Acc --
Correct chars --

VHDL Memory Controller for Simple RAM Access

VHDL

Goal -- WPM

Ready
Exercise Algorithm Area
1library ieee;
2use ieee.std_logic_1164.all;
3use ieee.numeric_std.all;
4
5entity ram_controller is
6generic (
7ADDR_WIDTH : integer := 10; -- Address bus width (e.g., 10 bits for 1024 locations)
8DATA_WIDTH : integer := 8; -- Data bus width (e.g., 8 bits)
9RAM_DEPTH : integer := 1024 -- Number of memory locations
10);
11port (
12clk : in std_logic;
13reset : in std_logic;
14
15-- Interface to the CPU/Master
16write_en : in std_logic; -- Write enable from master
17read_en : in std_logic; -- Read enable from master
18address : in std_logic_vector(ADDR_WIDTH-1 downto 0);
19data_in : in std_logic_vector(DATA_WIDTH-1 downto 0);
20data_out : out std_logic_vector(DATA_WIDTH-1 downto 0);
21ready : out std_logic; -- Indicates controller is ready for next operation
22
23-- Interface to the RAM chip
24ram_addr : out std_logic_vector(ADDR_WIDTH-1 downto 0);
25ram_data_in: out std_logic_vector(DATA_WIDTH-1 downto 0);
26ram_data_out: in std_logic_vector(DATA_WIDTH-1 downto 0);
27ram_we : out std_logic; -- RAM write enable
28ram_oe : out std_logic; -- RAM output enable
29ram_cs : out std_logic -- RAM chip select
30);
31end entity ram_controller;
32
33architecture rtl of ram_controller is
34
35-- State machine for controlling RAM access timing
36type state_t is (S_IDLE, S_READ_SETUP, S_READ_ACCESS, S_READ_HOLD, S_WRITE_SETUP, S_WRITE_ACCESS, S_WRITE_HOLD);
37signal current_state, next_state : state_t;
38
39-- Internal signals for RAM control
40signal internal_ram_addr : std_logic_vector(ADDR_WIDTH-1 downto 0);
41signal internal_ram_data_in: std_logic_vector(DATA_WIDTH-1 downto 0);
42signal internal_ram_we : std_logic;
43signal internal_ram_oe : std_logic;
44signal internal_ram_cs : std_logic;
45
46-- Internal signals for data buffering and output
47signal read_buffer : std_logic_vector(DATA_WIDTH-1 downto 0);
48signal ready_signal : std_logic;
49
50-- Timing parameters (adjust based on specific RAM datasheet)
51-- These represent clock cycles.
52constant T_SETUP_READ : integer := 1; -- Setup time before read enable
53constant T_ACCESS_READ : integer := 2; -- Access time for read operation
54constant T_HOLD_READ : integer := 1; -- Hold time after read enable
55
56constant T_SETUP_WRITE : integer := 1; -- Setup time before write enable
57constant T_ACCESS_WRITE: integer := 2; -- Access time for write operation (often same as read)
58constant T_HOLD_WRITE : integer := 1; -- Hold time after write enable
59
60-- Timer for state transitions
61signal timer : integer range 0 to T_ACCESS_READ + T_SETUP_READ + T_HOLD_READ + 1; -- Max possible duration
62
63-- Helper function to initialize RAM interface signals
64function init_ram_signals return (std_logic_vector(ADDR_WIDTH-1 downto 0), std_logic_vector(DATA_WIDTH-1 downto 0), std_logic, std_logic, std_logic) is
65begin
66return ( (others => '0'), (others => '0'), '1', '1', '1'); -- CS=low, WE=high, OE=high (inactive)
67end function init_ram_signals;
68
69begin
70
71-- Assign internal signals to output ports
72ram_addr <= internal_ram_addr;
73ram_data_in <= internal_ram_data_in;
74ram_we <= internal_ram_we;
75ram_oe <= internal_ram_oe;
76ram_cs <= internal_ram_cs;
77ready <= ready_signal;
78data_out <= read_buffer;
79
80-- State Register Process
81process (clk, reset)
82begin
83if reset = '1' then
84current_state <= S_IDLE;
85timer <= 0;
86ready_signal <= '1'; -- Ready initially
87(internal_ram_addr, internal_ram_data_in, internal_ram_we, internal_ram_oe, internal_ram_cs) <= init_ram_signals();
88read_buffer <= (others => '0');
89elsif rising_edge(clk) then
90current_state <= next_state;
91ready_signal <= '0'; -- Not ready during operation
92
93-- Timer logic
94if timer > 0 then
95timer <= timer - 1;
96end if;
97
98-- RAM Interface Signal Updates (based on state transitions)
99case next_state is -- Use next_state to determine signal setup
100when S_IDLE =>
101(internal_ram_addr, internal_ram_data_in, internal_ram_we, internal_ram_oe, internal_ram_cs) <= init_ram_signals();
102read_buffer <= (others => '0'); -- Clear buffer
103ready_signal <= '1'; -- Ready when idle
104
105when S_READ_SETUP =>
106internal_ram_addr <= address;
107internal_ram_cs <= '0'; -- Chip select active
108internal_ram_oe <= '0'; -- Output enable active
109internal_ram_we <= '1'; -- Write enable inactive
110timer <= T_SETUP_READ;
111
112when S_READ_ACCESS =>
113-- Address and CS are already set from S_READ_SETUP
114-- OE and WE remain as set
115timer <= T_ACCESS_READ;
116
117when S_READ_HOLD =>
118-- Capture data from RAM
119read_buffer <= ram_data_out;
120internal_ram_oe <= '1'; -- Output enable inactive
121-- Keep CS low until hold time is met
122timer <= T_HOLD_READ;
123
124when S_WRITE_SETUP =>
125internal_ram_addr <= address;
126internal_ram_data_in <= data_in;
127internal_ram_cs <= '0'; -- Chip select active
128internal_ram_we <= '0'; -- Write enable active
129internal_ram_oe <= '1'; -- Output enable inactive
130timer <= T_SETUP_WRITE;
131
132when S_WRITE_ACCESS =>
133-- Address, Data, CS, WE are set
134timer <= T_ACCESS_WRITE;
135
136when S_WRITE_HOLD =>
137internal_ram_we <= '1'; -- Write enable inactive
138internal_ram_cs <= '1'; -- Chip select inactive
139-- Keep address and data stable until hold time is met
140timer <= T_HOLD_WRITE;
141
142when others => -- Should not happen
143(internal_ram_addr, internal_ram_data_in, internal_ram_we, internal_ram_oe, internal_ram_cs) <= init_ram_signals();
144ready_signal <= '1';
145end case;
146end if;
147end process;
148
149-- Next State Logic Process
150process (current_state, timer, read_en, write_en, reset)
151begin
152next_state <= current_state; -- Default to current state
153ready_signal <= '0'; -- Assume not ready unless explicitly set in IDLE
154
155if reset = '1' then
156next_state <= S_IDLE;
157else
158case current_state is
159when S_IDLE =>
160if read_en = '1' then
161next_state <= S_READ_SETUP;
162ready_signal <= '0'; -- Not ready during operation
163elsif write_en = '1' then
164next_state <= S_WRITE_SETUP;
165ready_signal <= '0'; -- Not ready during operation
166else
167next_state <= S_IDLE;
168ready_signal <= '1'; -- Ready if no operation requested
169end if;
170
171when S_READ_SETUP =>
172if timer = 0 then
173next_state <= S_READ_ACCESS;
174end if;
175
176when S_READ_ACCESS =>
177if timer = 0 then
178next_state <= S_READ_HOLD;
179end if;
180
181when S_READ_HOLD =>
182if timer = 0 then
183next_state <= S_IDLE;
184end if;
185
186when S_WRITE_SETUP =>
187if timer = 0 then
188next_state <= S_WRITE_ACCESS;
189end if;
190
191when S_WRITE_ACCESS =>
192if timer = 0 then
193next_state <= S_WRITE_HOLD;
194end if;
195
196when S_WRITE_HOLD =>
197if timer = 0 then
198next_state <= S_IDLE;
199end if;
200
201when others => -- Should not happen
202next_state <= S_IDLE;
203end case;
204end if;
205end process;
206
207-- Edge Case: Address out of bounds (if RAM_DEPTH is less than 2^ADDR_WIDTH)
208-- This implementation assumes the address is always valid for the RAM_DEPTH.
209-- A real-world controller might add checks here.
210
211-- Edge Case: Simultaneous read and write requests.
212-- The current logic prioritizes read if both read_en and write_en are high.
213-- This priority can be adjusted by modifying the S_IDLE state transitions.
214
215-- Edge Case: RAM timing parameters.
216-- The T_SETUP, T_ACCESS, T_HOLD parameters are critical.
217-- They must be derived from the specific RAM datasheet.
218-- Incorrect values will lead to read/write errors.
219
220end architecture rtl;
Algorithm description viewbox

VHDL Memory Controller for Simple RAM Access

Algorithm description:

This VHDL code implements a synchronous RAM controller designed to interface with an external Static Random Access Memory (SRAM) chip. It manages read and write operations by generating the necessary control signals (chip select, write enable, output enable) and timing them correctly according to typical SRAM access requirements.

Algorithm explanation:

The controller utilizes a finite state machine (FSM) to sequence through the phases of a read or write operation. States like `S_READ_SETUP`, `S_READ_ACCESS`, and `S_READ_HOLD` define the timing for reading data, ensuring address and control signals are stable for the required durations. Similarly, write operations are managed through `S_WRITE_SETUP`, `S_WRITE_ACCESS`, and `S_WRITE_HOLD` states. A timer within the FSM controls the duration of each state, based on timing parameters derived from the RAM's datasheet. The `ready` output signal indicates when the controller is available for a new command. This design abstracts the complex timing of memory access, providing a simpler interface to a processor or other master device. It handles basic edge cases like simultaneous read/write requests by prioritizing reads.

Pseudocode:

Define states: IDLE, READ_SETUP, READ_ACCESS, READ_HOLD, WRITE_SETUP, WRITE_ACCESS, WRITE_HOLD.
Define timing constants for setup, access, and hold times for read/write.
Initialize controller to IDLE state, ready signal high, RAM control signals inactive.
On rising edge of clock:
  Update current_state to next_state.
  If in IDLE state:
    If read_en is high, transition to READ_SETUP, set ready to low.
    Else if write_en is high, transition to WRITE_SETUP, set ready to low.
    Else, remain in IDLE, set ready to high.
  If in READ_SETUP state:
    Set address, CS low, OE low, WE high. Start timer for READ_SETUP duration.
    If timer expires, transition to READ_ACCESS.
  If in READ_ACCESS state:
    Keep signals stable. Start timer for READ_ACCESS duration.
    If timer expires, transition to READ_HOLD.
  If in READ_HOLD state:
    Capture data from RAM into read_buffer. Keep signals stable. Start timer for READ_HOLD duration.
    If timer expires, transition to IDLE.
  If in WRITE_SETUP state:
    Set address, data_in, CS low, WE low, OE high. Start timer for WRITE_SETUP duration.
    If timer expires, transition to WRITE_ACCESS.
  If in WRITE_ACCESS state:
    Keep signals stable. Start timer for WRITE_ACCESS duration.
    If timer expires, transition to WRITE_HOLD.
  If in WRITE_HOLD state:
    Keep signals stable. Start timer for WRITE_HOLD duration.
    If timer expires, transition to IDLE.
Assign output signals (ram_addr, ram_data_in, ram_we, ram_oe, ram_cs, data_out, ready) based on current state and internal signals.