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;