Table of Contents
VHDL
SDRAM Memory
https://electronics.stackexchange.com/questions/631943/fpga-to-sdram-communication
and https://github.com/nullobject/sdram-fpga/blob/master/sdram.vhd
DE-25 Standard
DE-10 Standard
https://fpgacademy.org/Downloads/DE10-Standard_Computer_ARM.pdf
https://www.scribd.com/document/804051962/DE10-Standard-User-Manual
https://www.scribd.com/document/605613587/DE10-Standard-OpenCL-18-0
schema https://www.rocketboards.org/foswiki/pub/Documentation/DE10Standard/DE10-Standard_Schematic.pdf
https://www.terasic.com.tw/wiki/DE10_Advance_Board_Setup:_MSEL_Settings
https://github.com/joaomiguelvieira/DE10_Standard_boilerplate
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
PDF https://dspace.cvut.cz/server/api/core/bitstreams/31b3bbb8-6926-43c8-8d53-7c19862c9aa4/content
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
VGA https://github.com/vacer25/Nios_II-VGA-Out
RAM https://www.scribd.com/document/528291695/Lab3-SDRAM-modified-2020-1
FPGA SDRAM Communication https://github.com/zangman/de10-nano/blob/master/docs/FPGA-SDRAM-Communication_-Avalon-MM-Host-Master-Component-Part-3.md
https://github.com/zangman/de10-nano/blob/master/docs/Write-Linux-Driver.md
