this is my first post in this nice community of people. Thank you in advance for any help.
Here follows a description of my problem ...
I have implemented and simulated (using questa) a part of my code in VHDL that instantiates a true dual port ram (ports A, B use the same clock).
When I try to synthesize in quartus I got the following error:
Started Tue Feb 23 21:23:16 2021
Error (272006): Must connect clock1 port of altsyncram megafunction when using current set of parameters File: /home/amakris/ddm/exe_rs_siob5_mk2_odf_11_feb_21/hdl/lib_siob_application/mmio_transfer_sm.vhd Line: 119
Error (272006): Cannot use different clock ports for address_b port and data_b|wren_b|byteena_b(if used) port in altsyncram megafunction File: /home/amakris/ddm/exe_rs_siob5_mk2_odf_11_feb_21/hdl/lib_siob_application/mmio_transfer_sm.vhd Line: 119
Error (287078): Assertion error: The current megafunction is configured for use with the clear box feature and cannot be used when the clear box feature is disabled File: /ecad/alt/vq18.1/quartus/libraries/megafunctions/altsyncram.tdf Line: 2877
Error (12152): Can't elaborate user hierarchy "siob_application:i_siob_application|mmio_ctrl:i_mmio_ctrl|mmio_transfer_sm:i_mmio_transfer_sm|altsyncram:shadow_mem_1" File: /home/amakris/ddm/exe_rs_siob5_mk2_odf_11_feb_21/hdl/lib_siob_application/mmio_transfer_sm.vhd Line: 119
Error: Quartus Prime Analysis & Synthesis was unsuccessful. 4 errors, 385 warnings
Error Line 119 is the first line of the components mapping:
shadow_mem_1 : altsyncram
address_reg_b => "CLOCK0",
clock_enable_input_a => "BYPASS",
clock_enable_input_b => "BYPASS",
clock_enable_output_a => "BYPASS",
clock_enable_output_b => "BYPASS",
indata_reg_b => "CLOCK0",
intended_device_family => "Arria 10",
lpm_type => "altera_syncram",
numwords_a => 16384,
numwords_b => 16384,
operation_mode => "BIDIR_DUAL_PORT",
outdata_aclr_a => "NONE",
--outdata_sclr_a => "NONE",
outdata_aclr_b => "NONE",
--outdata_sclr_b => "NONE",
outdata_reg_a => "CLOCK0",
outdata_reg_b => "CLOCK0",
power_up_uninitialized => "FALSE",
read_during_write_mode_mixed_ports => "DONT_CARE", --"OLD_DATA",
read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ",
read_during_write_mode_port_b => "NEW_DATA_NO_NBE_READ",
widthad_a => 14,
widthad_b => 14,
width_a => 32,
width_b => 32,
width_byteena_a => 1,
width_byteena_b => 1
data_a => mmio_mem_data_from_reg_map, -- data from register map to shadow memory (APPL)
data_b => mem_m_writedata, -- data from mstr to shadow memory (MSTR)
address_a => appl_addr, -- appl addr from register map (different for read or write due to design particulars) (APPL)
address_b => mem_m_address, -- mstr address (coming directly from master avalon bus) (MSTR)
wren_a => mmio_mem_wr, -- wr enable from register map (APPL)
wren_b => mem_m_write, -- wr enable from mstr (MSTR)
clock0 => mmio_clk_sys, -- clock
rden_a => mmio_mem_rd, -- rd_enable from register map (APPL)
rden_b => mem_m_read, -- rd_enable from mstr (MSTR)
q_a => mmio_mem_data_to_reg_map, -- read data from shadow memory fed to register map (APPL)
q_b => mem_m_readdata -- read data from shadow memory fed to mstr (MSTR) -
It looks like there is some dependency between the generics and the actual mapped ports (as the actual component from the library has more available ports). I tied connecting some other input ports of the component (like clock1 => mmio_clk_sys - although still not sure if this is the recomended way) in the port mapping and that helps me get rid of the first error but not the others...
I really need to use this approach where I simply reference the altsyncram component from the altera_mf library in vhdl (and not use a qsys component) for a couple of reasons that are related with the compilation environment setup. I feel like I am so close
Any help to alleviate my memory-ache will be greatly appreciated.
Usually I will just go to Quartus IP Catalog> RAM: 2-PORT to generate the .qip/ .qsys file needed for my project as it will automatically include the other files needed for the IP.
Not sure why you have a different compilation environment setup, what I can think of is probably compare the design files generated by the IP with the design files you have. Perhaps you may find the discrepancy and what is missing in your design files.
I've done this, (creating the qsys ip) but there is a complex automated script environment for the design and qsys components are rather troublesome to treat (need to update makefiles ...).
Furthermore the qsys ip, at its lower level generated a verilog file that uses the altera_syncram component and the number of the generic generic parameters is not identical to those of the altsyncram vhdl component ...
There is still one more thing that you can try. Our Quartus tool has the full design template for true dual port in which you can just pop it into your project and use it right away.
Create a new .vhd file, right-click on the blank space to opens the context menu, scroll to Insert Template, then a window Insert Template will pop up, choose VHDL > Full Designs > RAMs and ROMs > True Dual Port RAM (single clock).
Hope it helps on your case.
Thank you for the help.
So what you suggest is an RTL implementation of the memory (e.g. not structural using the altsyncram function directly).
entity true_dual_port_ram_single_clock is
DATA_WIDTH : natural := 8;
ADDR_WIDTH : natural := 6
clk : in std_logic;
addr_a : in natural range 0 to 2**ADDR_WIDTH - 1;
addr_b : in natural range 0 to 2**ADDR_WIDTH - 1;
data_a : in std_logic_vector((DATA_WIDTH-1) downto 0);
data_b : in std_logic_vector((DATA_WIDTH-1) downto 0);
we_a : in std_logic := '1';
we_b : in std_logic := '1';
q_a : out std_logic_vector((DATA_WIDTH -1) downto 0);
q_b : out std_logic_vector((DATA_WIDTH -1) downto 0)
architecture rtl of true_dual_port_ram_single_clock is
-- Build a 2-D array type for the RAM
subtype word_t is std_logic_vector((DATA_WIDTH-1) downto 0);
type memory_t is array(2**ADDR_WIDTH-1 downto 0) of word_t;
-- Declare the RAM
shared variable ram : memory_t;
-- Port A
if(we_a = '1') then
ram(addr_a) := data_a;
q_a <= ram(addr_a);
-- Port B
if(we_b = '1') then
ram(addr_b) := data_b;
q_b <= ram(addr_b);
The only problem with this approach is that you might not be able to customize input/output registers and modes of operation (but it is some sort of an alternative I guess).