Site Tools


vhdl

This is an old revision of the document!


VHDL

SDRAM Memory

DE-25 Standard

DE-10 Standard

Memory

Cyclone V 5CSXFC6D6F31C6

Total block memory bits 5,662,720

https://fpgacademy.org/Downloads/DE10-Standard_Computer_ARM.pdf

DE10-STANDARD COMPUTER SYSTEM WITH ARM* CORTEX* A9 For Quartus® Prime 19.1

2.9.1 SDRAM An SDRAM Controller in the FPGA provides an interface to the 64 MB synchronous dynamic RAM (SDRAM) on the DE10-Standard board, which is organized as 32M x 16 bits. It is accessible by the ARM A9 processor using word (32-bit), halfword (16-bit), or byte operations, and is mapped to the address space 0xC0000000 to 0xC3FFFFFF.

2.9.2 On-Chip Memory The DE10-Standard Computer includes a 256 KB memory that is implemented inside the FPGA. This memory is organized as 64K x 32 bits, and spans addresses in the range 0xC8000000 to 0xC803FFFF. The memory is used as a pixel buffer for the video-out and video-in ports.

2.9.3 On-Chip Memory Character Buffer The DE10-Standard Computer includes an 8 KB memory implemented inside the FPGA that is used as a character buffer for the video-out port, which is described in Section 4.2. The character buffer memory is organized as 8K x 8 bits, and spans the address range 0xC9000000 to 0xC9001FFF.

VGA Video buffer

4.2 Video-out Port The DE10-Standard Computer includes a video-out port connected to the on-board VGA controller that can be connected to a standard VGA monitor. The video-out port support a screen resolution of 640 × 480. The image that is displayed by the video-out port is derived from two sources: a pixel buffer, and a character buffer.

4.2.1 Pixel Buffer The pixel buffer for the video-out port holds the data (color) for each pixel that will be displayed. As illustrated in Figure 18, the pixel buffer provides an image resolution of 320 × 240 pixels, with the coordinate 0,0 being at the top-left corner of the image. Since the video-out port supports the screen resolution of 640 × 480, each of the pixel values in the pixel buffer is replicated in both the x and y dimensions when it is being displayed on the screen.

HPS access to SDRAM

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
 
// Define the assumed physical base address of the FPGA SDRAM as seen by the HPS (check your Qsys map!)
// A typical HPS-to-FPGA bridge range starts around 0xC0000000
#define FPGA_SDRAM_BASE 0xC0000000 
#define SDRAM_SPAN (64*1024*1024) // 64 MB
 
int main() {
    void *virtual_base;
    int fd;
    volatile unsigned int *sdram_ptr;
    int i;
 
    // Open /dev/mem to access physical memory
    if( (fd = open( "/dev/mem", ( O_RDWR | O_SYNC ) )) == -1 ) {
        printf( "ERROR: could not open /dev/mem...\n" );
        return( 1 );
    }
 
    // Map the physical address into virtual memory
    virtual_base = mmap( NULL, SDRAM_SPAN, ( PROT_READ | PROT_WRITE ), MAP_SHARED, fd, FPGA_SDRAM_BASE );      
 
    if( virtual_base == MAP_FAILED ) {
        printf( "ERROR: mmap failed...\n" );
        close( fd );
        return( 1 );
    }
 
    // Get the address to the first location in memory
    sdram_ptr = (unsigned int *)virtual_base;
 
    // HPS writes data to the FPGA SDRAM
    for (i = 0; i < 100; i++) {
        *(sdram_ptr + i) = i + 0x1234; 
        // Example of simple read back and print
        // printf("Wrote %x to address %p\n", *(sdram_ptr + i), (void*)(sdram_ptr + i));
    }
    printf("HPS finished writing to FPGA SDRAM.\n");
 
    // Clean up our memory mapping and file handle
    if( munmap( virtual_base, SDRAM_SPAN ) != 0 ) {
        printf( "ERROR: munmap failed...\n" );
    }
 
    close( fd );
    return( 0 );
}

Ask Google : C code de10-standard map FPGA SDRAM on HPS

Ask Google : instructions on how to use the Platform Designer to map the FPGA SDRAM so the HPS can access it

MEMORY M9K

    -- Total depth is 256 * 256 = 65536 locations
    constant MEM_DEPTH : natural := 65536; 
    constant DATA_WIDTH : natural := 32;
 
    -- Define a 1D array type for easier memory inference
    type memory_array_t is array (0 to MEM_DEPTH-1) of STD_LOGIC_VECTOR(DATA_WIDTH-1 downto 0);
 
    -- Declare the signal that will be mapped to M9K blocks
    signal memory_array : memory_array_t;
 
    -- VHDL attribute to force mapping to block RAM (M9K)
    attribute ramstyle : string;
    attribute ramstyle of memory_array : signal is "M9K";
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity OnChip_RAM is
    generic (
        -- Define the memory size and data width
        DATA_WIDTH : integer := 8;
        ADDR_WIDTH : integer := 10 -- 2^10 = 1024 addresses (fits within one or more M9K blocks)
    );
    Port (
        clk     : in STD_LOGIC;
        we      : in STD_LOGIC; -- Write enable
        addr    : in STD_LOGIC_VECTOR(ADDR_WIDTH-1 downto 0);
        data_in : in STD_LOGIC_VECTOR(DATA_WIDTH-1 downto 0);
        data_out: out STD_LOGIC_VECTOR(DATA_WIDTH-1 downto 0)
    );
end entity OnChip_RAM;
 
architecture behavioral of OnChip_RAM is
    -- Declare the memory type as an array
    type RAM_ARRAY is array (0 to (2**ADDR_WIDTH)-1) of STD_LOGIC_VECTOR(DATA_WIDTH-1 downto 0);
    -- Initialize the RAM content (optional, can be done via .mif file)
    signal ram_memory : RAM_ARRAY; 
    signal read_address_reg : STD_LOGIC_VECTOR(ADDR_WIDTH-1 downto 0);
 
begin
 
    process(clk)
    begin
        if rising_edge(clk) then
            -- Write operation: occurs on the rising edge of the clock when write enable is high
            if we = '1' then
                ram_memory(to_integer(unsigned(addr))) <= data_in;
            end if;
            -- The read address is registered for synchronous read
            read_address_reg <= addr;
        end if;
    end process;
 
    -- Read operation: output is combinational based on the registered read address
    -- This behavior is characteristic of how FPGAs implement block RAMs for high speed
    data_out <= ram_memory(to_integer(unsigned(read_address_reg)));
 
end architecture behavioral;

Inference: Quartus Prime's synthesis tool will automatically infer M9K blocks from this code because it follows standard synchronous write and registered read practices.

Attributes: To explicitly force the use of block RAM or change behavior during simultaneous read/write to the same address, you can use VHDL attributes, e.g.,

attribute ramstyle : string; attribute ramstyle of ram_memory: signal is "M9K";.

Initialization: You can initialize the RAM contents using a Memory Initialization File (.mif) or Hexadecimal file (.hex) by following the Quartus settings to include initialization data in the bitstream.

DSP

The Cyclone V SX SoC (5CSXFC6D6F31C6N) contains 112 Digital Signal Processing (DSP) blocks

Cyclone V DSPs have two banks of eight internal coefficients each, which can be selected as a multiplicand in the multiplier, alongside dynamic input. These coefficient banks are part of the internal memory, and the DSP block can choose between the dynamic input and the internal coefficient memory.

The simplest way to use a DSP block is to write a standard VHDL multiplier using the numeric_std library's signed or unsigned types. The Quartus synthesizer will automatically map this operation to one of the dedicated hardware multipliers (e.g., a 9×9, 18×18, or 27×27 multiplier depending on your data width) if timing and resource constraints allow.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity simple_multiplier is
    Port (
        clk      : in  STD_LOGIC;
        operand_a: in  SIGNED (17 downto 0); -- 18-bit signed input
        operand_b: in  SIGNED (17 downto 0); -- 18-bit signed input
        result   : out SIGNED (35 downto 0)  -- 36-bit signed output (18+18)
    );
end entity simple_multiplier;
 
architecture behavioral of simple_multiplier is
    -- Intermediate signal for registered output
    signal mult_result_reg : SIGNED (35 downto 0);
 
begin
 
    process(clk)
    begin
        if rising_edge(clk) then
            -- The synthesizer will infer an 18x18 hardware multiplier here
            mult_result_reg <= operand_a * operand_b;
        end if;
    end process;
 
    result <= mult_result_reg;
 
end architecture behavioral;

Data Types: Use SIGNED or UNSIGNED from numeric_std. Using STD_LOGIC_VECTOR requires casting, which can sometimes hinder inference.

Pipelining/Registers: Adding registers (as in the example above with mult_result_reg) helps the synthesizer absorb the registers into the DSP block itself, improving performance and utilizing the dedicated pipelining features of the hardware.

Attributes: You can use VHDL attributes to guide the synthesizer if necessary, though it's usually automatic for simple multiplication:

attribute use_dsp : string;
attribute use_dsp of behavioral : architecture is "yes";

VGA

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity vga_controller is
    Port (
        clk_25mhz : in  STD_LOGIC;  -- The pixel clock (25.175 MHz)
        hsync     : out STD_LOGIC;  -- Horizontal Sync
        vsync     : out STD_LOGIC;  -- Vertical Sync
 
        -- Pixel coordinates for drawing (active display area)
        pixel_x   : out NATURAL range 0 to 639;
        pixel_y   : out NATURAL range 0 to 479;
 
        -- Signal to indicate when the beam is in the active display area
        display_on : out STD_LOGIC
    );
end entity vga_controller;
 
architecture behavioral of vga_controller is
    -- VGA 640x480 @ 60Hz timing constants
    constant H_DISPLAY  : NATURAL := 640;
    constant H_FRONT    : NATURAL := 16;
    constant H_SYNC     : NATURAL := 96;
    constant H_BACK     : NATURAL := 48;
    constant H_TOTAL    : NATURAL := 800;
 
    constant V_DISPLAY  : NATURAL := 480;
    constant V_FRONT    : NATURAL := 10;
    constant V_SYNC     : NATURAL := 2;
    constant V_BACK     : NATURAL := 33;
    constant V_TOTAL    : NATURAL := 525;
 
    signal h_count      : NATURAL range 0 to H_TOTAL-1 := 0;
    signal v_count      : NATURAL range 0 to V_TOTAL-1 := 0;
    signal h_sync_sig   : STD_LOGIC := '1';
    signal v_sync_sig   : STD_LOGIC := '1';
    signal display_on_sig : STD_LOGIC := '0';
 
begin
    process(clk_25mhz)
    begin
        if rising_edge(clk_25mhz) then
            -- Horizontal counter logic
            if h_count < H_TOTAL - 1 then
                h_count <= h_count + 1;
            else
                h_count <= 0;
                -- Vertical counter logic: only increments when horizontal count resets
                if v_count < V_TOTAL - 1 then
                    v_count <= v_count + 1;
                else
                    v_count <= 0;
                end if;
            end if;
 
            -- Horizontal sync pulse generation (active low)
            if h_count >= (H_DISPLAY + H_FRONT) and h_count < (H_DISPLAY + H_FRONT + H_SYNC) then
                h_sync_sig <= '0';
            else
                h_sync_sig <= '1';
            end if;
 
            -- Vertical sync pulse generation (active low)
            if v_count >= (V_DISPLAY + V_FRONT) and v_count < (V_DISPLAY + V_FRONT + V_SYNC) then
                v_sync_sig <= '0';
            else
                v_sync_sig <= '1';
            end if;
 
            -- Display enable signal (active during the active display area)
            if h_count < H_DISPLAY and v_count < V_DISPLAY then
                display_on_sig <= '1';
            else
                display_on_sig <= '0';
            end if;
 
        end if;
    end process;
 
    -- Map internal signals to output ports
    hsync <= h_sync_sig;
    vsync <= v_sync_sig;
    display_on <= display_on_sig;
 
    -- Provide current active pixel coordinates (adjusting for counter start from 0)
    pixel_x <= h_count when display_on_sig = '1' else 0;
    pixel_y <= v_count when display_on_sig = '1' else 0;
 
end architecture behavioral;
-- Example connection logic in a separate module or top-level architecture
-- ...
-- signal current_red, current_green, current_blue : STD_LOGIC_VECTOR(3 downto 0); -- DE10 uses 4-bit color per channel
-- ...
 
-- Instantiate the controller
-- UUT_VGA_Controller : entity work.vga_controller port map (...);
 
-- Logic to determine color based on coordinates (e.g., drawing a red square)
-- process(pixel_x, pixel_y, display_on)
-- begin
--   if display_on = '1' then
--     if pixel_x > 100 and pixel_x < 200 and pixel_y > 100 and pixel_y < 200 then
--       current_red <= "1111"; -- Full Red
--       current_green <= "0000";
--       current_blue <= "0000";
--     else
--       current_red <= "0000"; -- Black background
--       current_green <= "0000";
--       current_blue <= "0000";
--     end if;
--   else
--     current_red <= "0000"; -- Blanking period, output 0
--     current_green <= "0000";
--     current_blue <= "0000";
--   end if;
-- end process;
-- ...

VGA Display image from SDRAM

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity vga_sdram_bridge is
    Port (
        -- Clocks and Reset
        clk_50mhz   : in  STD_LOGIC;  -- System Clock
        reset       : in  STD_LOGIC;
 
        -- From the VGA Controller (Timing side)
        pixel_x     : in  NATURAL range 0 to 639;
        pixel_y     : in  NATURAL range 0 to 479;
        display_on  : in  STD_LOGIC;
 
        -- To the VGA DAC (Color output)
        vga_red     : out STD_LOGIC_VECTOR(3 downto 0);
        vga_green   : out STD_LOGIC_VECTOR(3 downto 0);
        vga_blue    : out STD_LOGIC_VECTOR(3 downto 0);
 
        -- Avalon Master Interface to SDRAM Controller (Connect via Qsys/Platform Designer)
        av_address  : out STD_LOGIC_VECTOR(21 downto 0); -- Address lines for 64MB SDRAM
        av_read     : out STD_LOGIC;
        av_readdata : in  STD_LOGIC_VECTOR(15 downto 0); -- SDRAM provides 16-bit data
        av_waitreq  : in  STD_LOGIC;
        av_readdata_valid: in STD_LOGIC
    );
end entity vga_sdram_bridge;
 
architecture behavioral of vga_sdram_bridge is
    signal current_read_address : STD_LOGIC_VECTOR(21 downto 0) := (others => '0');
    signal next_pixel_data      : STD_LOGIC_VECTOR(15 downto 0);
    signal vga_read_enable      : STD_LOGIC := '0';
 
begin
 
    process (clk_50mhz)
    begin
        if rising_edge(clk_50mhz) then
            if reset = '1' then
                vga_read_enable <= '0';
                av_read <= '0';
                -- ... reset colors ...
            else
                -- 1. Generate the Address based on X, Y coordinates
                if display_on = '1' then
                    -- Calculate sequential address (assuming 16-bit color data per pixel)
                    -- Address = (Y * H_DISPLAY + X) * 2 bytes/pixel 
                    -- Note: Exact calculation depends on pixel packing and memory layout
                    current_read_address <= std_logic_vector(to_unsigned(pixel_y * 640 + pixel_x, 22)); 
                    vga_read_enable <= '1';
                else
                    vga_read_enable <= '0';
                end if;
 
                -- 2. Issue Read Request to SDRAM Controller
                -- The SDRAM controller IP handles the wait cycles (av_waitreq)
                av_read <= vga_read_enable;
                av_address <= current_read_address;
 
                -- 3. Capture Data when valid (requires FSM for multi-cycle transactions)
                -- For simple (slow) systems, you can check av_readdata_valid or av_waitreq
                -- In a real SDRAM interface, you need a state machine to wait for the data
                -- This simplified example assumes data arrives quickly:
                if (av_readdata_valid = '1' and av_read = '1') then
                    next_pixel_data <= av_readdata;
                end if;
 
                -- 4. Drive VGA DAC with the captured data
                -- Assuming 5/6/5 RGB format in 16 bits (common in Terasic examples)
                -- Red [15:11], Green [10:5], Blue [4:0] (Adjust these bit slices for your format)
                vga_red <= next_pixel_data(15 downto 12); -- Top 4 bits of 5
                vga_green <= next_pixel_data(10 downto 7); -- Top 4 bits of 6
                vga_blue <= next_pixel_data(4 downto 1); -- Top 4 bits of 5
            end if;
        end if;
    end process;
end architecture behavioral;

Verilog SDRAM

https://www.reddit.com/r/FPGA/comments/x5x4a8/stuck_on_simple_fpga_sdram_controller_dropped/

https://drive.google.com/file/d/1asn0ytD_ntwQrTm7IzxEVtITTo8kwDs3/view

// SDRAM command and control
// Model ISIS IS4216320D 32Mx16 SDRAM
 
`define ZERO_ADDRESS \
    A <= 0;
 
`define ISSUE_NOP \
	nRAS <= 1; nCAS <= 1; nWE <= 1; DQM <= 2'b11;
 
`define ISSUE_PRECHARGE_ALLBANKS \
    nRAS <= 0; nCAS <= 1; nWE <= 0; A[10] <= 1; 
 
`define ISSUE_REFRESH \
    nRAS <= 0; nCAS <= 0; nWE <= 1;
 
`define ISSUE_MODE_SELECT \
    nRAS <= 0; nCAS <= 0; nWE <= 0; A[10] <= 0; BA <= 0;
 
`define SELECT_NOBURST_MODE \
    BA <= 0; A[12:10] <= 0; A[9] <= 1'b1; A[8:7] <= 0; A[6:4] <= 3'b010; A[3:0] <= 4'b0000;
 
`define SELECT_BURST32_MODE \
    BA <= 0; A[12:10] <= 0; A[9] <= 1'b0; A[8:7] <= 0; A[6:4] <= 3'b010; A[3:0] <= 4'b0001;
 
`define SET_COMMAND_LENGTH(cmdcyclebit, length) \
    cmdcyclebit <= length > 1? (1 << (length-2)) : 0;
 
`define ISSUE_ACTIVATE(BANK, ROW) \
    nRAS <= 0; nCAS <= 1; nWE <= 1; \
	 BA <= BANK; A <= ROW;
 
`define ISSUE_RD_WITH_AUTOCHARGE(BANK, COL) \
    nRAS <= 1; nCAS <= 0; nWE <= 1; A[10] <= 1; \
	 BA <= BANK; A[9:0] <= COL; DQM <= 0;
 
`define ISSUE_WR_WITH_AUTOCHARGE(BANK, COL, DATA) \
    nRAS <= 1; nCAS <= 0; nWE <= 0; A[10] <= 1; \
	 BA <= BANK; A[9:0] <= COL; DQM <= 0; DQ_buf <= DATA; dq_flag <= 1;

Quartus

Flow Status	Successful - Sat Dec 13 17:32:19 2025
Quartus Prime Version	25.1std.0 Build 1129 10/21/2025 SC Standard Edition
Revision Name	de10_standard_ver
Top-level Entity Name	de10_standard_ver
Family	Cyclone V
Device	5CSXFC6D6F31C6
Timing Models	Final
Logic utilization (in ALMs)	3,776 / 41,910 ( 9 % )
Total registers	6123
Total pins	177 / 499 ( 35 % )
Total virtual pins	0
Total block memory bits	704,584 / 5,662,720 ( 12 % )
Total DSP Blocks	0 / 112 ( 0 % )
Total HSSI RX PCSs	0 / 9 ( 0 % )
Total HSSI PMA RX Deserializers	0 / 9 ( 0 % )
Total HSSI TX PCSs	0 / 9 ( 0 % )
Total HSSI PMA TX Serializers	0 / 9 ( 0 % )
Total PLLs	2 / 15 ( 13 % )
Total DLLs	1 / 4 ( 25 % )

https://gitlab.fel.cvut.cz/korinlu1/de10_standard_ov7670_project

https://gitlab.fel.cvut.cz/korinlu1/de10_standard_ov7670_project/-/blob/main/fpga/de10_standard_ver/ov7670_camera_module.vhd

https://gitlab.fel.cvut.cz/korinlu1/de10_standard_ov7670_project/-/blob/main/fpga/de10_standard_ver/ov7670_camera_module.vhd

Download https://gitlab.fel.cvut.cz/korinlu1/de10_standard_ov7670_project/-/archive/main/de10_standard_ov7670_project-main.tar.gz?ref_type=heads

architecture Behavioral of ov7670_camera_module is
 
	constant IMAGE_SIZE : natural := 228*1024;
	type image_type is array (0 to IMAGE_SIZE-1) of std_logic_vector(15 downto 0);
	shared variable image : image_type := (others => (others => '0'));
 
	variable image_inx : integer := 0;
        variable value : std_logic_vector(15 downto 0) := (others => '0');
 
		value := data(7 downto 0) & data_in;
 
		data <= image (image_inx);
		wren_reg  <= '0';
 
		image (image_inx) := value;
		if image_inx < IMAGE_SIZE-1 then
		   image_inx := image_inx + 1;
		else
  	            image_inx := 0;
		end if;	
constant IMAGE_SIZE : natural := 256*1024;
COMPILATION ERROR

Logic utilization (in ALMs)	4,664 / 41,910 ( 11 % )
Total registers	5859
Total pins	177 / 499 ( 35 % )
Total virtual pins	0
Total block memory bits	4,898,888 / 5,662,720 ( 87 % )
constant IMAGE_SIZE : natural := 128*1024;
O.K.

Logic utilization (in ALMs)	3,872 / 41,910 ( 9 % )
Total registers	6100
Total pins	177 / 499 ( 35 % )
Total virtual pins	0
Total block memory bits	2,801,736 / 
----
( 49 % )
112 * 1024 32-bit
224 * 1024 16-bit
448 * 1024  8-bit
O.K.

114 * 1024 32-bit
228 * 1024 16-bit 
456 * 1024  8-bit
O.K.

248 * 1024 16-bit COMPILATION ERROR
240 * 1024 16-bit COMPILATION ERROR
232 * 1024 16-bit COMPILATION ERROR
230 * 1024 16-bit COMPILATION ERROR
229 * 1024 16-bit COMPILATION ERROR

RAM https://www.cs.columbia.edu/~sedwards/classes/2013/4840/lab3.pdf

https://www.scribd.com/document/528291698/lab1-week-1

PROCESSOR https://github.com/NTP17/AKVP_x09

NIOS

vhdl.1765652411.txt.gz · Last modified: 2025/12/13 19:00 by 2a00:1028:919d:bcb2:740a:d1bf:c035:85fb