VHDL Code for DMA Controller: Syntax, Example, and Tips
A DMA controller in
VHDL manages direct memory access by controlling data transfers between memory and peripherals without CPU intervention. The code typically includes state machines for control signals like start, done, and address counters. You can implement it using processes and signals to handle read/write cycles and handshaking.Syntax
The basic structure of a DMA controller in VHDL includes:
- Entity: Defines inputs and outputs like clock, reset, start signal, source/destination addresses, and data buses.
- Architecture: Contains the logic, usually a state machine, to control the transfer process.
- Processes: Handle synchronous operations like address increment, data transfer, and status signaling.
vhdl
entity dma_controller is
Port (
clk : in std_logic;
reset : in std_logic;
start : in std_logic;
src_addr : in std_logic_vector(15 downto 0);
dest_addr : in std_logic_vector(15 downto 0);
length : in std_logic_vector(15 downto 0);
mem_read : out std_logic;
mem_write : out std_logic;
mem_addr : out std_logic_vector(15 downto 0);
mem_data_in : in std_logic_vector(7 downto 0);
mem_data_out : out std_logic_vector(7 downto 0);
done : out std_logic
);
end dma_controller;Example
This example shows a simple DMA controller that copies data from a source address to a destination address for a given length. It uses a state machine to control the read and write cycles and signals when the transfer is done.
vhdl
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity dma_controller is
Port (
clk : in std_logic;
reset : in std_logic;
start : in std_logic;
src_addr : in std_logic_vector(15 downto 0);
dest_addr : in std_logic_vector(15 downto 0);
length : in std_logic_vector(15 downto 0);
mem_read : out std_logic;
mem_write : out std_logic;
mem_addr : out std_logic_vector(15 downto 0);
mem_data_in : in std_logic_vector(7 downto 0);
mem_data_out : out std_logic_vector(7 downto 0);
done : out std_logic
);
end dma_controller;
architecture Behavioral of dma_controller is
type state_type is (IDLE, READ, WRITE, DONE);
signal state : state_type := IDLE;
signal count : unsigned(15 downto 0) := (others => '0');
signal current_src : unsigned(15 downto 0);
signal current_dest: unsigned(15 downto 0);
signal data_buffer : std_logic_vector(7 downto 0);
begin
process(clk, reset)
begin
if reset = '1' then
state <= IDLE;
mem_read <= '0';
mem_write <= '0';
mem_addr <= (others => '0');
mem_data_out <= (others => '0');
done <= '0';
count <= (others => '0');
current_src <= (others => '0');
current_dest <= (others => '0');
elsif rising_edge(clk) then
case state is
when IDLE =>
done <= '0';
mem_read <= '0';
mem_write <= '0';
if start = '1' then
current_src <= unsigned(src_addr);
current_dest <= unsigned(dest_addr);
count <= unsigned(length);
state <= READ;
end if;
when READ =>
mem_addr <= std_logic_vector(current_src);
mem_read <= '1';
mem_write <= '0';
data_buffer <= mem_data_in;
state <= WRITE;
when WRITE =>
mem_addr <= std_logic_vector(current_dest);
mem_read <= '0';
mem_write <= '1';
mem_data_out <= data_buffer;
if count = 0 then
state <= DONE;
else
current_src <= current_src + 1;
current_dest <= current_dest + 1;
count <= count - 1;
state <= READ;
end if;
when DONE =>
mem_read <= '0';
mem_write <= '0';
done <= '1';
if start = '0' then
state <= IDLE;
end if;
when others =>
state <= IDLE;
end case;
end if;
end process;
end Behavioral;Output
No direct console output; the DMA controller signals 'done' when transfer completes.
Common Pitfalls
Common mistakes when writing a DMA controller in VHDL include:
- Not properly synchronizing signals with the clock, causing glitches.
- Forgetting to reset internal counters and states on reset.
- Incorrectly handling the
donesignal, which can cause the controller to restart unexpectedly. - Not managing read/write enable signals properly, leading to bus contention.
Always use a clear state machine and reset all signals to known states.
vhdl
---- Wrong: Missing reset for count and state process(clk) begin if rising_edge(clk) then if start = '1' then count <= count - 1; -- count not reset on reset end if; end if; end process; ---- Right: Proper reset and state management process(clk, reset) begin if reset = '1' then count <= (others => '0'); state <= IDLE; elsif rising_edge(clk) then -- state machine logic end if; end process;
Quick Reference
Tips for writing a DMA controller in VHDL:
- Use a finite state machine to control the transfer phases.
- Synchronize all signals with the clock and reset.
- Use unsigned types for address and length counters.
- Buffer data between read and write cycles to avoid timing issues.
- Signal completion clearly with a
doneoutput.
Key Takeaways
A DMA controller in VHDL uses a state machine to manage memory read/write cycles without CPU intervention.
Always reset internal counters and states to avoid unpredictable behavior.
Synchronize all control signals with the clock to prevent glitches.
Buffer data between read and write phases to ensure correct data transfer.
Use a clear done signal to indicate transfer completion.