Forum Discussion
14 Replies
- Altera_Forum
Honored Contributor
Altera altsyncram MegaFunction is actually the low level primitive used by Quartus, when inferring RAM from HDL code, you may want to check the physical mapping of your designs. It can be also instantiated in HDL directly, which is, as far I'm aware of, the only way to create dual port RAM with different width. At least, I'm usually going this way. As far as I understand, you don't want to hear about.
- Altera_Forum
Honored Contributor
Ive had this very problem myself:
Solution: Either use the megawizard or include the altera_mf library and instantiate an altsyncram manually. Unfortunately this is no way to infer an altsyncram with different sized in and out ports, and had it confirmed from altera themselves. I have raised it as an enhancement request, so if enough people ask for it, maybe it will appear one day. As a point of note: Xilinx, synopsis and Mentor tools cant do it either. - Altera_Forum
Honored Contributor
I must admit, that I don't even see how a dual port RAM with different port widths could be declared unequivocally in VHDL. Do you have a suggestion?
- Altera_Forum
Honored Contributor
Something like this? (this infers dual port ram fine when addr_a/b and data_a/q_b sizes match) :
entity test_build is port ( clka : in std_logic; clkb : in std_logic; addr_a : in natural range 0 to 127; data_a : in std_logic_vector(63 downto 0); addr_b : in natural range 0 to 511; q_b : out std_logic_vector(15 downto 0) ); end entity; architecture rtl of test_build is type mem_t is array(0 to 511) of std_logic_vector(15 downto 0); signal mem : mem_t; signal addr_b_r : integer; begin process(clka) begin if rising_edge(clka) then mem(addr_a*4) <= data_a(15 downto 0); mem(addr_a*4+1) <= data_a(31 downto 16); mem(addr_a*4+2) <= data_a(47 downto 32); mem(addr_a*4+3) <= data_a(63 downto 48); end if; end process; process(clkb) begin if rising_edge(clkb) then addr_b_r <= addr_b; end if; end process; q_b <= mem(addr_b_r); --alt_ram : altsyncram --generic map ( -- Width_a => 64, -- width_b => 16, -- -- widthad_a => 7, -- widthad_b => 9 -- --) --port map ( -- -- clock0 => clka, -- clock1 => clkb, -- -- data_a => data_a, -- address_a => std_logic_vector(to_unsigned(addr_a, 7) ), -- -- address_b => std_logic_vector(to_unsigned(addr_b, 9) ), -- q_b => q_b -- --); end architecture rtl; - Altera_Forum
Honored Contributor
I am not sure if this would work
type mem_t is array(0 to 511) of std_logic_vector(15 downto 0); signal mem : mem_t; Won't this still infer a memory that is 16 bits wide on both ports? I guess the inference rules for memories are ambiguous and tool dependent. The "not to be named" mega-function wizard seems the safest way;) - Altera_Forum
Honored Contributor
This is the point, you cannot currently infer a memory with missmatched in/out port sizes. The code was one suggested way it "might" be done.
The synthesiser would have to look at the behaviour around the code rather than the declarations, to infer the memory correctly. - Altera_Forum
Honored Contributor
Thank you for elaborating the idea. Thinking about similar options, I see a problem that it would blow up the rules of "how to infer RAM from HDL" considerably. They are partly difficult yet, e.g. regarding the registered/unregistered features of internal RAM and handling of simultanous write accesses. Thus I think, it may an acceptable idea to leave it as is, requiring explicite altsyncram instantiation for the complex cases.
- Altera_Forum
Honored Contributor
Example from application note 226:
For your second port, use an address translation and bit selection from 16 to 64 in an upper module. Edit: copy and past issue: thanks to Tricky for the feedback.LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_signed.all; ENTITY dualport_ram IS PORT ( data_out : OUT STD_LOGIC_VECTOR (63 DOWNTO 0); data_in : IN STD_LOGIC_VECTOR (63 DOWNTO 0); wr_addr : IN STD_LOGIC_VECTOR (6 DOWNTO 0); rd_addr : IN STD_LOGIC_VECTOR (6 DOWNTO 0); we : IN STD_LOGIC; clk : IN STD_LOGIC); END dualport_ram; ARCHITECTURE ram_infer OF dualport_ram IS TYPE Mem_Type IS ARRAY (127 DOWNTO 0) OF STD_LOGIC_VECTOR (63 DOWNTO 0); SIGNAL mem: Mem_Type; SIGNAL addr_reg: STD_LOGIC_VECTOR (6 DOWNTO 0); BEGIN data_out <= mem (CONV_INTEGER(rd_addr)); PROCESS (clk, we, data_in) BEGIN IF (clk=’1’ AND clk’EVENT) THEN IF (we=’1’) THEN mem(CONV_INTEGER(wr_addr)) <= data_in; END IF; END IF; END PROCESS; END ram_infer; - Altera_Forum
Honored Contributor
That will never work - the mem_type stores 8 bit values, while data in is 64 bits wide.
- Altera_Forum
Honored Contributor
--- Quote Start --- For your second port, use an address translation and bit selection from 16 to 64 in an upper module. --- Quote End --- Thats fine, but its not as elegant as the direct instantiation - it will add muxes on the output. Its not terrible, just not as compact.