Forum Discussion
How to implement DE0 SDRAM as 2-port RAM
I currently use the tiny bit of memory on the FPGA for a computer vision project but it's way too limited. I have a stand-alone SDRAM controller from Altera (partially pasted below) but I need one more layer above that which implements this controller as a 2-port RAM entity. It seems like overkill to use QSYS with NiosII though, plus I'm not very familiar with it. What's resource will help me implement this controller as a 2-port RAM entity in the simplest way possible?
entity sdr_sdram is
generic(
ASIZE : integer := 23;
DSIZE : integer := 32;
ROWSIZE : integer := 12;
COLSIZE : integer := 9;
BANKSIZE : integer := 2;
ROWSTART : integer := 9;
COLSTART : integer := 0;
BANKSTART : integer := 20
);
port(
CLK : in std_logic; --System Clock
RESET_N : in std_logic; --System Reset
ADDR : in std_logic_vector(ASIZE - 1 downto 0); --Address for controller requests
CMD : in std_logic_vector(2 downto 0); --Controller command
CMDACK : out std_logic; --Controller command acknowledgement
DATAIN : in std_logic_vector(DSIZE - 1 downto 0); --Data input
DATAOUT : out std_logic_vector(DSIZE - 1 downto 0); --Data output
DM : in std_logic_vector(DSIZE / 8 - 1 downto 0); --Data mask input
SA : out std_logic_vector(11 downto 0); --SDRAM address output
BA : out std_logic_vector(1 downto 0); --SDRAM bank address
CS_N : out std_logic_vector(1 downto 0); --SDRAM Chip Selects
CKE : out std_logic; --SDRAM clock enable
RAS_N : out std_logic; --SDRAM Row address Strobe
CAS_N : out std_logic; --SDRAM Column address Strobe
WE_N : out std_logic; --SDRAM write enable
DQ : inout std_logic_vector(DSIZE - 1 downto 0); --SDRAM data bus
DQM : out std_logic_vector(DSIZE / 8 - 1 downto 0) --SDRAM data mask lines
);
end sdr_sdram;
I need a wrapper so that this SDRAM controller is implemented like this: Inst_frame_buffer : entity work.sdram_wrapper_frame_buffer PORT MAP(
rdaddress => rdaddress, -- IN std_logic_vector(18 downto 0);
rdclock => clk_vga, -- IN std_logic;
q => rddata, -- OUT std_logic_vector(11 downto 0)
wrclock => camera_pclk, -- IN std_logic;
wraddress => wraddress, -- IN std_logic_vector(18 downto 0);
data => wrdata, -- IN std_logic_vector(11 downto 0);
wren => wren -- IN std_logic;
);48 Replies
- Altera_Forum
Honored Contributor
--- Quote Start --- It seems like QSYS is for projects where the developer wants to use a NiosII processor or JTAG interface. --- Quote End --- No, Qsys is for projects where you want to connect Avalon-MM devices together without having to "think" about how all the glue logic is generated. --- Quote Start --- I want to focus on making the wrapper for the SDRAM controller. It is likely only an hour or less of work for someone more experienced than myself. What is the next step in getting assistance in developing this wrapper? --- Quote End --- Follow along, and lets see if we can get you an SDRAM wrapper ... 1. Download the DE0-nano SDRAM example design http://www.alteraforum.com/forum/showthread.php?t=45927 This gives us a starting point. Ignore the fact that the DE0 may have different SDRAM. 2. Unzip it and build it per the readme.txt instructions, i.e., Quartus Tcl: tcl> cd {c:\temp\de0_nano_sdram} tcl> source scripts/synth.tcl The build procedure creates the qsys_system.qsys file and "Generates" the Qsys system files. WRAPPER GENERATION METHOD# 1 3. Look at the generated source c:\temp\de0_nano_sdram\qsys_system\synthesis\submodules\qsys_system_sdram.v There's your wrapper code right there. Its got an Avalon-MM slave interface and the SDRAM interface. WRAPPER GENERATION METHOD# 2 4. Delete the generated source, i.e., delete the folder c:\temp\de0_nano_sdram\qsys_system\synthesis 5. Start Qsys, open qsys_system.qsys 6. Delete the clock and JTAG master, leaving only the SDRAM component. 7. "Export" all of the SDRAM ports, eg., sdram_clk, sdram_reset, sdram_slave, sdram_mem. 8. Look at the HDL Example - its pretty much identical to the wrapper code (with port name changes) 9. Try to "Generate" this new system and ... failure ... at least on 12.1sp1 as there is no clock defined, which the SDRAM generator must need. A slight variation on this is to export an Avalon-MM master from the Qsys system. Your external logic would then control that master interface. Why is this a better option? It allows you to let Qsys generate the SDRAM controller. Note that an SDRAM controller is not that difficult to write. Its only a state machine and logic. There are probably examples on the OpenCore web site. Its much harder to write a DDR SDRAM controller, so that is one case where you'd definitely want to re-use the Qsys generated DDR controller. In the case of an SDRAM controller, you might want to find a non-Qsys version (Altera used to have an example design, long before the days of Qsys). Cheers, Dave - Altera_Forum
Honored Contributor
I finally had time to get back to this.
Method 1 is fine except that JTAG is still in there and the address size is only 13bit which seems way too short for 8Mb. Also the ram size hasn't been changed. The column and row values may also be wrong. 1. For WRAPPER GENERATION METHOD# 2, why remove the clock? Why not leave the clock and SDRAM and just remove the JTAG component? - Altera_Forum
Honored Contributor
--- Quote Start --- Method 1 is fine except that JTAG is still in there --- Quote End --- No its not. Look at the file qsys_system_sdram.v, it is *ONLY* the SDRAM controller component. --- Quote Start --- and the address size is only 13bit which seems way too short for 8Mb. Also the ram size hasn't been changed. The column and row values may also be wrong. --- Quote End --- That would be the "Ignore the fact that the DE0 may have different SDRAM". If you edit the SDRAM controller parameters to match those on the DE0 and then "Generate" the system, the generated .v file will have the parameters you need. --- Quote Start --- 1. For WRAPPER GENERATION METHOD# 2, why remove the clock? Why not leave the clock and SDRAM and just remove the JTAG component? --- Quote End --- Now you are starting to see the possibilities :) Cheers, Dave - Altera_Forum
Honored Contributor
Using QSYS, I corrected the SDRAM size to 8Mb by correcting hte row and column sizes, fixed the the clock frequency, removed JTAG, added a 100MHz clock generator, and exported it to VHDL. It looks like it will work but I'm still messing with it...
- Altera_Forum
Honored Contributor
--- Quote Start --- It looks like it will work but I'm still messing with it... --- Quote End --- I haven't tried this with the SDRAM controller, but with the DDR controller, you can have Qsys generate a testbench, and it will include an DDR SDRAM model. For DDR SDRAM, I get Qsys to generate a top-level testbench, and then use that as a template for my own testbench. The piece of code I am typically interested in, is the SDRAM model instance, i.e., the fake SDRAM that the SDRAM controller reads/writes to. I then go back to the Qsys system and add a BFM, or I'd connect to the Avalon-MM slave port you're going to export to your top-level design, and use that to generate Avalon-MM transactions. Cheers, Dave - Altera_Forum
Honored Contributor
I'm having an issue where I want to use one of the FIFO, frame buffer, or 1-port ram IP cores but since I'm not using a NioII, I just have to export everything and end up with even more connections to map. I'm trying to get back to the same position I was in with the on-board FPGA memory where all I have map is a rd_clk, rd_addr, rd_data, wr_clk, wr_addr, and wr_data. (Of course the SDRAM pins will also be mapped to the device.) Is there a way to get what I described?
- Altera_Forum
Honored Contributor
Seems like I'm making progress.. I have a few questions about entity instance below:
sdram_controller_wire: 1. In the DE0 manual, the size of SDRAM_ADDR is 13bits, [12:0], but the wizard generates a 12 bit vector, [11:0]. Which one is right if the SDRAM size is 8Mb? 2. Do you see anything wrong with the "sdram_controller_wire" block of signals? Like BA or DQM are backwards? sdram_controller_s1: 3. Is chip select just used to enable sdram_controller_s1? 4. What is byte enable for in this instance? 5. Why isn't read_n and write_n one signal instead of two? Does that mean you can write and read at the same time?-- sdram controller sdram_controller : process(clk50, btn(2)) begin if btn(2) = '0' then sdram_controller_s1_address_s <= (others => '0'); elsif rising_edge(clk50) then if (wren = '0') then sdram_controller_s1_address_s <= wraddress; else sdram_controller_s1_address_s <= rdaddress; end if; end if; end process; SDRAM_BA_1 <= sdram_controller_wire_ba_s(1); SDRAM_BA_0 <= sdram_controller_wire_ba_s(0); SDRAM_UDQM <= sdram_controller_wire_dqm_s(1); SDRAM_LDQM <= sdram_controller_wire_dqm_s(0); SDRAM_ADDR <= '0' & sdram_controller_wire_addr_s(11 downto 0); Inst_sdram : entity work.SDRAM_QSYS port map( clk_100mhz_clk => sdram_clk_s, --: in std_logic := '0'; clk.clk reset_reset_n => btn(2), --: in std_logic := '0'; reset.reset_n sdram_controller_wire_addr => sdram_controller_wire_addr_s, --: out std_logic_vector(11 downto 0); sdram_controller_wire.addr sdram_controller_wire_ba => sdram_controller_wire_ba_s, --: out std_logic_vector(1 downto 0); .ba sdram_controller_wire_cas_n => SDRAM_CAS_N, --: out std_logic; .cas_n sdram_controller_wire_cke => SDRAM_CKE, --: out std_logic; .cke sdram_controller_wire_cs_n => SDRAM_CS_N, --: out std_logic; .cs_n sdram_controller_wire_dq => SDRAM_DQ, --: inout std_logic_vector(15 downto 0) := (others => '0'); .dq sdram_controller_wire_dqm => sdram_controller_wire_dqm_s, --: out std_logic_vector(1 downto 0); .dqm sdram_controller_wire_ras_n => SDRAM_RAS_N, --: out std_logic; .ras_n sdram_controller_wire_we_n => SDRAM_WE_N, --: out std_logic; .we_n sdram_controller_s1_address => sdram_controller_s1_address_s, --: in std_logic_vector(21 downto 0) := (others => '0'); sdram_controller_s1.address sdram_controller_s1_byteenable_n => "11", --: in std_logic_vector(1 downto 0) := (others => '0'); .byteenable_n sdram_controller_s1_chipselect => '1', --: in std_logic := '0'; .chipselect sdram_controller_s1_writedata => wrdata, --: in std_logic_vector(15 downto 0) := (others => '0'); .writedata sdram_controller_s1_read_n => wren, --: in std_logic := '0'; .read_n sdram_controller_s1_write_n => not wren, --: in std_logic := '0'; .write_n sdram_controller_s1_readdata => open, --: out std_logic_vector(15 downto 0); .readdata sdram_controller_s1_readdatavalid => open, --: out std_logic; .readdatavalid sdram_controller_s1_waitrequest => open --: out std_logic ); - Altera_Forum
Honored Contributor
--- Quote Start --- 1. In the DE0 manual, the size of SDRAM_ADDR is 13bits, [12:0], but the wizard generates a 12 bit vector, [11:0]. Which one is right if the SDRAM size is 8Mb? --- Quote End --- Check the data sheet for the SDRAM. Most board designers are conservative and include "extra" address bits to make the board suitable for loading several device sizes. --- Quote Start --- 2. Do you see anything wrong with the "sdram_controller_wire" block of signals? Like BA or DQM are backwards? --- Quote End --- What do you mean by backwards? The port direction appears correct - the controller drives those signals. --- Quote Start --- sdram_controller_s1: 3. Is chip select just used to enable sdram_controller_s1? 4. What is byte enable for in this instance? 5. Why isn't read_n and write_n one signal instead of two? Does that mean you can write and read at the same time? --- Quote End --- Create a simulation model and use that to answer these questions :) Its likely that chipselect and read_n need to assert for read, and chipselect and write_n need to assert for write. Cheers, Dave - Altera_Forum
Honored Contributor
no idea what the two bit byte enable could be for?
- Altera_Forum
Honored Contributor
--- Quote Start --- no idea what the two bit byte enable could be for? --- Quote End --- The byte-enable controls allow you to write to a single byte. Eg., if you have a 16-bit Avalon-MM master, you can write 16-bits, write to the low 8-bits, or write to the high 8-bits. If you have a 32-bit Avalon-MM master, then you can write 32-bits, 16-bits low or high, or any of the four bytes. The byte enables allow you to indicate which bytes get written. The SDRAM controller then passes these though to assert the data mask signals (DQM ). Again, this is a question that you can answer yourself by creating a simulation of the design. HINT HINT: Create a simulation! :) Cheers, Dave