Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
17043 Discussions

Instanciating dual port memory with different r/w widths

Altera_Forum
Honored Contributor II
1,696 Views

Im trying to get Quartus to infer a vhdl array of record as dual port memory with write side being a 32bit, and read side a N*32bit datawidth. To make it even more difficult, I need it to be inferred as two separate memory banks with two different address pointers on the read side. 

 

Is this possible to do the simple way? 

 

Im trying something like this, but it doesnt find the memory, even if I try to add the ramstyle attribute. 

 

--pseudocode (not verified) type TableEntry is record x : std_logic_vector(15 downto 0); y : std_logic_vector(15 downto 0); size_x : std_logic_vector(15 downto 0); size_y : std_logic_vector(15 downto 0); end record; type TableArray is array (integer range 127 downto 0) of TableEntry; signal Table : TableArray; alias write_wordadr : std_logic_vector(2 downto 0) is addr(2 downto 0); alias wrire_index : std_logic_vector(addr'high-3 downto 0) is addr(addr'high downto 3); --writing from cpu case conv_integer(write_wordadr) is when 0=> Table(write_index).x <=data(31 downto 16); Table(write_index).y <=data(15 downto 0); when 1=> Table(write_index).size_x <=data(31 downto 16); Table(write_index).size_y <=data(15 downto 0); when others=> end case; --reading x,y testx<=Table(posindex).x; testy<=Table(posindex).y; --reading size_x,size_y with different index testsizex<=Table(sizeindex).size_x; testsizey<=Table(sizeindex).size_y;
0 Kudos
6 Replies
Altera_Forum
Honored Contributor II
641 Views

Inferencing rams is only garanteed to work for the code templates, and these will only work for arrays of normal types (like unsigned, std_logic_vector etc). I dont think you will get it to work with record types at all, unless you convert the records to single type arrays. 

 

But you havent posted all of the code, just snippets, so I cannot see if the code is suitable for memory inference in the first place. The code has to follow a certain template before it will work - the ramstyle attribute only works when the templates are followed.
0 Kudos
Altera_Forum
Honored Contributor II
641 Views

 

--- Quote Start ---  

Inferencing rams is only garanteed to work for the code templates, and these will only work for arrays of normal types (like unsigned, std_logic_vector etc). I dont think you will get it to work with record types at all, unless you convert the records to single type arrays. 

 

--- Quote End ---  

 

I can get it to infer for records. The breaking part seems to be the different adressing schemes or bus widths on both sides, and Quartus doesnt seem to try splitting the record up in smaller blocks. Its all or nothing. 

 

 

--- Quote Start ---  

But you havent posted all of the code, just snippets, so I cannot see if the code is suitable for memory inference in the first place. The code has to follow a certain template before it will work - the ramstyle attribute only works when the templates are followed. 

--- Quote End ---  

 

I'd be glad for any code that would do this, so my code was just the essence of my current longer code. Of course I could write a implementable proof of concept code but I doubt that will help anyone. 

 

PS:Ive just tried to break the record into single signals, and it seems to do what I want. Its just uglier code.
0 Kudos
Altera_Forum
Honored Contributor II
641 Views

It would help. If it wont work when it should, you should raise an enhancement request in altera Mysupport. Given they have only just started to support mixed width dual port inference recently, I doubt they will allow more complex inputs (ie records) without enough ERs.

0 Kudos
Altera_Forum
Honored Contributor II
641 Views

 

--- Quote Start ---  

It would help. If it wont work when it should, you should raise an enhancement request in altera Mysupport. Given they have only just started to support mixed width dual port inference recently, I doubt they will allow more complex inputs (ie records) without enough ERs. 

--- Quote End ---  

 

Ok, I will spend some minutes on this and post a copy here.. Thanks.
0 Kudos
Altera_Forum
Honored Contributor II
641 Views

Here is an example that builds horribly wrong. I expected Table to be split into any kind of memory even without the ramstyle attrib, but fails. It all goes into ALUT's (stratix III, Q10.1sp1 and Q11.0sp1). 

I will try to raise my first ER on this case.. 

 

--testing the record to mem instanciation library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; entity record_mem is port ( --write bus clk1 : in std_logic; de1 : in std_logic; adr1 : in std_logic_vector(8 downto 0); data1 : in std_logic_vector(31 downto 0); --32bit output from the record array clk2 : in std_logic; adr2 : in std_logic_vector(7 downto 0); data2 : out std_logic_vector(31 downto 0); --16bit output from the record array clk3 : in std_logic; adr3 : in std_logic_vector(7 downto 0); data3 : out std_logic_vector(15 downto 0); --8bit output from the record array clk4 : in std_logic; adr4 : in std_logic_vector(8 downto 0); data4 : out std_logic_vector(7 downto 0) ); end record_mem; architecture rtl of record_mem is type TableEntry is record record_32bit_at_adr0 : std_logic_vector(31 downto 0); record_16bit_at_adr1_high_word : std_logic_vector(15 downto 0); record_8bit_at_adr1_low_word_low_byte : std_logic_vector(7 downto 0); record_8bit_at_adr1_low_word_high_byte : std_logic_vector(7 downto 0); end record; type TableArray is array (integer range 255 downto 0) of TableEntry; signal Table : TableArray; alias adr1_wordadr : std_logic_vector(0 downto 0) is adr1(0 downto 0); alias adr1_memidx : std_logic_vector(7 downto 0) is adr1(adr1'high downto 1); alias adr4_wordadr : std_logic_vector(0 downto 0) is adr4(0 downto 0); alias adr4_memidx : std_logic_vector(7 downto 0) is adr4(adr4'high downto 1); begin write_dp_mem:process (clk1) begin if(rising_edge(clk1)) then if(de1='1') then case conv_integer(adr1_wordadr) is when 0=> Table(conv_integer(adr1_memidx)).record_32bit_at_adr0 <=data1; when 1=> Table(conv_integer(adr1_memidx)).record_16bit_at_adr1_high_word <=data1(31 downto 16); Table(conv_integer(adr1_memidx)).record_8bit_at_adr1_low_word_low_byte <=data1(7 downto 0); Table(conv_integer(adr1_memidx)).record_8bit_at_adr1_low_word_high_byte <=data1(15 downto 8); when others=> end case; end if; end if; end process; read_32bit_mem:process (clk2) begin if(rising_edge(clk2)) then data2<=Table(conv_integer(adr2)).record_32bit_at_adr0; end if; end process; read_16bit_mem:process (clk3) begin if(rising_edge(clk3)) then data3<=Table(conv_integer(adr3)).record_16bit_at_adr1_high_word; end if; end process; read_8bit_mem:process (clk4) begin if(rising_edge(clk4)) then if(conv_integer(adr4_wordadr)=0) then data4<=Table(conv_integer(adr4_memidx)).record_8bit_at_adr1_low_word_low_byte; else data4<=Table(conv_integer(adr4_memidx)).record_8bit_at_adr1_low_word_high_byte; end if; end if; end process; end rtl;
0 Kudos
Altera_Forum
Honored Contributor II
641 Views

I think that the memory array definition is unsuitable from the start. Quartus is generally able to infer dual port rams with different port width, you'll find examples in the Quartus software handbook. Why don't you start with a known working example? Copying the record elements as "wires" to and from the memory shouldn't be a problem.

0 Kudos
Reply