- 新着としてマーク
- ブックマーク
- 購読
- ミュート
- RSS フィードを購読する
- ハイライト
- 印刷
- 不適切なコンテンツを報告
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;
コピーされたリンク
- 新着としてマーク
- ブックマーク
- 購読
- ミュート
- RSS フィードを購読する
- ハイライト
- 印刷
- 不適切なコンテンツを報告
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- 新着としてマーク
- ブックマーク
- 購読
- ミュート
- RSS フィードを購読する
- ハイライト
- 印刷
- 不適切なコンテンツを報告
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.- 新着としてマーク
- ブックマーク
- 購読
- ミュート
- RSS フィードを購読する
- ハイライト
- 印刷
- 不適切なコンテンツを報告
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.- 新着としてマーク
- ブックマーク
- 購読
- ミュート
- RSS フィードを購読する
- ハイライト
- 印刷
- 不適切なコンテンツを報告
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.- 新着としてマーク
- ブックマーク
- 購読
- ミュート
- RSS フィードを購読する
- ハイライト
- 印刷
- 不適切なコンテンツを報告
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.- 新着としてマーク
- ブックマーク
- 購読
- ミュート
- RSS フィードを購読する
- ハイライト
- 印刷
- 不適切なコンテンツを報告
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...
- 新着としてマーク
- ブックマーク
- 購読
- ミュート
- RSS フィードを購読する
- ハイライト
- 印刷
- 不適切なコンテンツを報告
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.