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

true dual port RAM

Altera_Forum
Honored Contributor II
2,627 Views

Hello, 

I am trying to implement a true dual port RAM. It compiles on Quartus, and when I simulate it with a waveform, it works as I want. 

But when I try to run it on ModelSim Altera, output is undefined. 

Does any one has ever solved that problem because I did not find any examples on internet. 

Thanks for help. 

 

 

Here is the code: 

LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.ALL; ENTITY ram512x36 IS PORT ( address_a : IN STD_LOGIC_VECTOR (8 DOWNTO 0); address_b : IN STD_LOGIC_VECTOR (8 DOWNTO 0); clock_a : IN STD_LOGIC ; clock_b : IN STD_LOGIC ; data_a : IN STD_LOGIC_VECTOR (35 DOWNTO 0); data_b : IN STD_LOGIC_VECTOR (35 DOWNTO 0); wren_a : IN STD_LOGIC:='1' ; wren_b : IN STD_LOGIC:='1' ; q_a : OUT STD_LOGIC_VECTOR (35 DOWNTO 0):="000000000000000000000000000000000000"; q_b : OUT STD_LOGIC_VECTOR (35 DOWNTO 0):="000000000000000000000000000000000000" ); END ram512x36; LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.ALL; ARCHITECTURE SYN OF ram512x36 IS Type mem_tram_type is array (0 to 511) of std_logic_vector(35 downto 0); signal dpram_mem_trame : mem_tram_type:=(others => (others =>'0')); attribute block_ram : boolean; attribute block_ram of dpram_mem_trame : signal is true; signal w_q_a : STD_LOGIC_VECTOR (35 DOWNTO 0):="000000000000000000000000000000000000"; signal w_q_b : STD_LOGIC_VECTOR (35 DOWNTO 0):="000000000000000000000000000000000000"; signal reg_rd_address_a : std_logic_vector(8 DOWNTO 0); signal reg_rd_address_b : std_logic_vector(8 DOWNTO 0); begin q_a <= dpram_mem_trame(conv_integer(unsigned(reg_rd_address_a))) ; q_b <= dpram_mem_trame(conv_integer(unsigned(reg_rd_address_b))) ; ------------------------------------------------------------------------ ----------------------------------- portA : process(clock_a) ----------------------------------- begin if clock_a'event and clock_a='1' then if wren_a='1' then reg_rd_address_a <= address_a; dpram_mem_trame(conv_integer(unsigned(address_a))) <= data_a; else reg_rd_address_a <= address_a; end if; end if; ----------------------------------- end process; ----------------------------------- portB : process(clock_b) ----------------------------------- begin if clock_b'event and clock_b='1' then if wren_b='1' then reg_rd_address_b <= address_b; dpram_mem_trame(conv_integer(unsigned(address_b))) <= data_b; else reg_rd_address_b <= address_b; end if; end if; ----------------------------------- end process; ----------------------------------- END SYN;
0 Kudos
7 Replies
Altera_Forum
Honored Contributor II
1,447 Views

You are writing to mem array on two clocks, one per each process. I don't see how this is going to work. You must decide the drive in one construct or else use Z assignments. 

 

Moreover, your code doesn't look right to me even for inferring ordinary ram. 

 

dual port ram is too difficult to infer - I believe. Why not use altera lpm
0 Kudos
Altera_Forum
Honored Contributor II
1,447 Views

The code is perfectly inferring a dual-port RAM in Quartus. That can be expected, cause it's basically following the syntax suggested in the Quartus Software Handbook for MegaFunction inference from HDL code. Using a dual-port RAM is actually the only legal method to have two clocks and two drivers controlling a register bit, as the above code has. 

 

Unfortunately ModelSim can't understand this special hardware prerequisites. This is probably the reason, why the RAM content is set to unknown. There may be a way to instruct ModelSim to understand the code, but I'm not aware of. 

 

I generally share kaz opinion, that it's easier to explicitely instantiate an altsyncram MegaFunction. This can be done without using the MegaWizard, directly in your code and assures a correct handling by ModelSim. It's necessary anyway, if you need additional features as different port widths on both sides, that aren't supported in RAM inference.
0 Kudos
Altera_Forum
Honored Contributor II
1,447 Views

I can't see how this can be an altera template. No way. They should withdraw it if so... 

It defies its own rule of multiple drivers, it is not portable and this defies the very purpose of inference. 

 

Moreover code like: 

if condition1  

a <= '1'; 

else 

a <= '1'; 

end 

 

is not a template surely. The read write registers/lack of registers is not explained.
0 Kudos
Altera_Forum
Honored Contributor II
1,447 Views

I didn't say it's a template, I say it follows the syntax rules. I particularly meant the way of registering respectively not registering addresses for read and write. I admit, that the Quartus Software Handbook doesn't explicitely show two write ports. But cause it's a feature of the hardware, the inference logic could be expected to understand it, too.  

 

I didn't explicitely comment meaningless code details as 

 

--- Quote Start ---  

if wren_a='1' then 

reg_rd_address_a <= address_a; 

dpram_mem_trame(conv_integer(unsigned(address_a))) <= data_a; 

else 

reg_rd_address_a <= address_a;  

end if; 

--- Quote End ---  

 

which is obviously equivalent to 

 

--- Quote Start ---  

if wren_a='1' then 

dpram_mem_trame(conv_integer(unsigned(address_a))) <= data_a; 

end if; 

reg_rd_address_a <= address_a; 

--- Quote End ---  

 

 

I also didn't want to discuss if inference is reasonable in this case, just state that Quartus does understand it. (I actually tried, not just claim it). I agree, that it's not portable (may be to architectures with similar hardware features, but not based on well defined VHDL language constructs). 

 

P.S.: I'm not an expert of general VHDL. (I guess you aren't, too). My main interest is in synthesizable code and corresponding simulation code. I notice however, that the VHDL language definition has effective means to define driver solution in different situations. They are also working in Quartus VHDL compiler without explicitely showing up. Thus I wouldn't say, that Quartus defines or uses it's own rules here. It apparently uses different rules than usual in assigning a signal to a register.
0 Kudos
Altera_Forum
Honored Contributor II
1,447 Views

Is it undefined ('U') or unknown ('X')? if it is 'U' are you sure you're putting a clock and other signals in, or even run the testbench? if it is 'X', you have multiple drivers on the same signal (which is coming from an external source). 

 

In Modelsim you need to write a test harness to actually simulate your design. you cannot simply simulate a single design file with no stimulus. 

 

I also notice you only write to the read address registers when you set write-enable high, meaning if you havent done a write cycle then the read_registers will be set all 'U's, and then it will either read an undefined address in the array (and return U) or read address 0. Move the read address registers outside the write enable if-then-else blocks.
0 Kudos
Altera_Forum
Honored Contributor II
1,447 Views

Thanks for your answers. 

Here is the version of my code which works in Modelsim but not in Quartus. In Quartus, the Ram is not infered. 

LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.ALL; ENTITY ram512x36 IS PORT ( address_a : IN STD_LOGIC_VECTOR (8 DOWNTO 0); address_b : IN STD_LOGIC_VECTOR (8 DOWNTO 0); clock : IN STD_LOGIC ; data_a : IN STD_LOGIC_VECTOR (35 DOWNTO 0); data_b : IN STD_LOGIC_VECTOR (35 DOWNTO 0); wren_a : IN STD_LOGIC:='1' ; wren_b : IN STD_LOGIC:='1' ; q_a : OUT STD_LOGIC_VECTOR (35 DOWNTO 0):="000000000000000000000000000000000000"; q_b : OUT STD_LOGIC_VECTOR (35 DOWNTO 0):="000000000000000000000000000000000000" ); END ram512x36; LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.ALL; ARCHITECTURE SYN OF ram512x36 IS Type mem_tram_type is array (0 to 511) of std_logic_vector(35 downto 0); signal dpram_mem_trame : mem_tram_type:=(others => (others =>'0')); attribute block_ram : boolean; attribute block_ram of dpram_mem_trame : signal is true; signal w_q_a : STD_LOGIC_VECTOR (35 DOWNTO 0):="000000000000000000000000000000000000"; signal w_q_b : STD_LOGIC_VECTOR (35 DOWNTO 0):="000000000000000000000000000000000000"; begin ------------------------------------------------------------------------ ----------------------------------- process(clock) ----------------------------------- begin if clock'event and clock='1' then if wren_a='1' then q_a <= dpram_mem_trame(conv_integer(unsigned(address_a))) ; dpram_mem_trame(conv_integer(unsigned(address_a))) <= data_a; else q_a <= dpram_mem_trame(conv_integer(unsigned(address_a))) ; end if; if wren_b='1' then q_b <= dpram_mem_trame(conv_integer(unsigned(address_b))) ; dpram_mem_trame(conv_integer(unsigned(address_b))) <= data_b; else q_b <= dpram_mem_trame(conv_integer(unsigned(address_b))) ; end if; end if; ----------------------------------- end process; ----------------------------------- END SYN;  

 

 

I do not want to use megawizard functions. 

Even if it does not work on modelsim, but is ok on quartus, it is what I want. I just want it to work on the board. 

 

I 'm going to check if I have U or X. Yes I am using a testbench etc...
0 Kudos
Altera_Forum
Honored Contributor II
1,447 Views

It will work in ModelSim because the sequential statements get updated such that the first assignment to mem array is overwritten now. 

 

If it works in quartus, then there is no problem.
0 Kudos
Reply