Programmable Devices
CPLDs, FPGAs, SoC FPGAs, Configuration, and Transceivers
20705 Discussions

Blockram: RAM model read/write

Altera_Forum
Honored Contributor II
1,846 Views

Hello, 

 

Can someone point me out how I can read/write to the following blockram RAM model ? 

 

I can read and write to external SRAM, but I am not able to make this work using blockram. Could someone help? 

 

ENTITY vram8k IS PORT ( data : IN STD_LOGIC_VECTOR (7 DOWNTO 0); rdaddress : IN STD_LOGIC_VECTOR (12 DOWNTO 0); rdclock : IN STD_LOGIC ; rden : IN STD_LOGIC := '1'; wraddress : IN STD_LOGIC_VECTOR (12 DOWNTO 0); wrclock : IN STD_LOGIC ; wren : IN STD_LOGIC := '1'; q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) ); END vram8k;  

 

Instantiation: 

 

vram8k_inst : work.vram8k PORT MAP ( data => v_data_sig, rdaddress => v_address_r_sig(12 downto 0), rdclock => Clk_Z80, wraddress => v_address_w_sig(12 downto 0), wrclock => Clk_Z80, wren => vram_we_sig, rden => vram_re_sig, q => vram_q_sig );  

 

I have tried a lot, and at this time, I have the following assertions for read/writing to the memory: 

 

v_address_w_sig <= A - x"2000" when (A >= x"2000" and MReq_n = '0'); v_address_r_sig <= A - x"2000" when (A >= x"2000" and MReq_n = '0'); vram_we_sig <= Wr_n; vram_re_sig <= Rd_n; v_data_sig <= DO_CPU when (Wr_n = '0' and MReq_n = '0'); DI_CPU <= vram_q_sig when (Rd_n = '0' and MReq_n = '0' and A >= x"2000");  

 

What must be changed for this to work? 

 

Thanks.
0 Kudos
15 Replies
Altera_Forum
Honored Contributor II
539 Views

At least, these signals seem to have wrong polarity: 

vram_we_sig <= Wr_n; vram_re_sig <= Rd_n; 

The other other point is, that the timing may be inappropriate for your design, but that can't be seen from the shown code. FPGA internal RAM act as synchronous RAM, you should check the timing to see if read and write operation occur at the intended moment. Also registered or non-registered read operation can be choosen. 

 

I wonder, why conditional assignment (a multiplexer) is used for the RAM input signals, but it shouldn't have any effect.
0 Kudos
Altera_Forum
Honored Contributor II
539 Views

 

--- Quote Start ---  

At least, these signals seem to have wrong polarity: 

vram_we_sig <= Wr_n; vram_re_sig <= Rd_n; 

The other other point is, that the timing may be inappropriate for your design, but that can't be seen from the shown code. FPGA internal RAM act as synchronous RAM, you should check the timing to see if read and write operation occur at the intended moment. Also registered or non-registered read operation can be choosen. 

 

I wonder, why conditional assignment (a multiplexer) is used for the RAM input signals, but it shouldn't have any effect. 

--- Quote End ---  

 

 

Thanks for replying. 

The timing may be wrong... I will try to check this. 

 

However, the polarity in the said signals are ok. they are asserted LOW: 

vram_we_sig <= Wr_n 

vram_re_sig <= Rd_n 

 

Wr_n is the Z80 write enable signal.  

vram_we_sig is the RAM write enable signal. 

 

The multiplexers are there because it will address differente RAM/ROMS, and this is only some code to debug the block ram access.
0 Kudos
Altera_Forum
Honored Contributor II
539 Views

I understand that wr_n is active low, as usual with external RAM, but the internal RAM we signal, that's connected to wr_n isn't, thus I think the polarity is wrong.

0 Kudos
Altera_Forum
Honored Contributor II
539 Views

I think the polarity is wrong also. Appears that you are sending an active low signal to the internal memory that needs an active high signal. 

 

Put not(Wr_n) to wren and not(Rd_n) to rden and it should be correct polarity.
0 Kudos
Altera_Forum
Honored Contributor II
539 Views

I have checked the timing. Read operation needs 3 clock cycle. I have inserted this delay in the logic and will test for functionality. 

I have also inverted the driving logic for control signals. 

Thanks guys for pointing that out .
0 Kudos
Altera_Forum
Honored Contributor II
539 Views

I don't think, that you need three clock cycles for read. You can use unregistered outputs with separate read and write clocks. Then read as write can be performed at the next clock edge.

0 Kudos
Altera_Forum
Honored Contributor II
539 Views

Thanks everyone for the tips. 

 

But I really will need some definitive help on this. I am trying this for a few days now, but have not achieved knowledge enough to make this work. 

 

Here is the latest code.  

 

-- Write into RAM vram_wraddress_sig <= A - x"2000"; vram_wren_sig <= (not Wr_n) or (not MReq_n); process (Clk_Z80) begin if Clk_Z80'event and Clk_Z80 ='1' then if Wr_n = '0' and MReq_n = '0' and A >= x"2000" then vram_data_sig <= DO_CPU; elsif Rd_n = '0' and MReq_n = '0' and A >= x"2000" then vram_q_sig_reg <= vram_q_sig; end if; end if; end process; -- Read from RAM vram_rden_sig <= '1'; vram_rdaddress_sig <= A - x"2000"; DI_CPU <= vram_q_sig_reg when (Wr_n = '0' and MReq_n = '0' and A >= x"2000") else D_ROM when (Rd_n = '0' and MReq_n = '0'); -- vram8k_inst : work.vram8k PORT MAP ( data => vram_data_sig, rdaddress => vram_rdaddress_sig(12 downto 0), rdclock => Clk_Z80, rden => vram_rden_sig, wraddress => vram_wraddress_sig(12 downto 0), wrclock => Clk_Z80, wren => vram_wren_sig, q => vram_q_sig );  

 

It is a simple operation: 

Write into RAM, Read from RAM.
0 Kudos
Altera_Forum
Honored Contributor II
539 Views

Displaying the RAM timing in simulator or using SignalTap should help to understand what's wrong.  

 

If Wr_n is active for one clock cycle only, vram_data_sig assignment in edge sensitive process code causes the data to be one cycle late. Write data must be present simultaneously with address and WE signal. If any multiplex action is needed, it should be placed in concurrent code or outside of the edge sensitive condition.
0 Kudos
Altera_Forum
Honored Contributor II
539 Views

There seems to be some logic issues in the code if I understand what you are trying to do. 

 

Assuming that A is a vector of 14 bits (13 downto 0).... 

 

It appears you are using bit 13 of the address, A, to select the ram. If this is the case, you need to qualify the vram_wren_sig with bit 13 of A. 

Something like: vram_wren_sig <= not Wr_n when A(13) = '1' else '0'; 

 

You can also take vram_data_sig and vram_q_sig_reg out of the clocked process. 

 

And, you should not have to subtract x"2000" for vram_rdaddress_sig or vram_wraddress_sig. Just assign them to A(12 downto 0) 

 

The key is to make sure you are only writing to ram when you should be, I assume it is when A(13) = '1'. And to make sure you are muxing DI_CPU correctly based on the address. For DI_CPU, I assume that when A(13) = '0' then you mux in the data from D_ROM and when A(13) = '1' then you mux in the data from the ram.
0 Kudos
Altera_Forum
Honored Contributor II
539 Views

Little explanation: 

 

It is a SoC based on Z80. 

 

When Z80 writes to RAM, it must be above 0x2000h. 

When it reads, it can be ROM (0x0000h to 0x1FFFh), or RAM (above 0x2000h). 

 

In the simulation (only the RAM model, not the full SoC), the read operations returned the data only on the 3rd clock cycle. 

 

But, starting over, this is the code I understand you guys suggested: 

 

 

-- Write into RAM vram_wraddress_sig <= A - x"2000"; vram_wren_sig <= (not Wr_n) or (not MReq_n) when A >= x"2000"; vram_data_sig <= DO_CPU when Wr_n = '0' and MReq_n = '0' and A >= x"2000"; -- Read from RAM vram_rden_sig <= '1'; vram_rdaddress_sig <= A - x"2000"; DI_CPU <= vram_q_sig when (Rd_n = '0' and MReq_n = '0' and A >= x"2000") else D_ROM when (Rd_n = '0' and MReq_n = '0'); This is the RAM instantiation: vram8k_inst : work.vram8k PORT MAP ( data => vram_data_sig, rdaddress => vram_rdaddress_sig(12 downto 0), rdclock => Clk_Z80, rden => vram_rden_sig, wraddress => vram_wraddress_sig(12 downto 0), wrclock => Clk_Z80, wren => vram_wren_sig, q => vram_q_sig );  

 

The write operations are OK? 

 

What may I change to read correctly from RAM? (above 0x2000h in Z80, which is 0x0000 in RAM) ? 

 

Thanks again.
0 Kudos
Altera_Forum
Honored Contributor II
539 Views

It would be easier to have a design example, that contains the complete path from generating addresses, write data and control signals up to reading the data. From your post, I also don't see clearly, which step of the RAM access doesn't work as intended. This could easily be seen from a simulation, also a simulation would help us to understand the timing as achieved in the present design.  

 

I'm pretty sure that the intended operation can be performed with internal RAM if used correct.
0 Kudos
Altera_Forum
Honored Contributor II
539 Views

These seems to have worked very well: 

 

-- Write into RAM vram_wraddress_sig <= A - x"2000"; vram_wren_sig <= not Wr_n when (A >= x"2000" and A <= x"4000"); vram_data_sig <= DO_CPU; -- Read from RAM vram_rden_sig <= Rd_n; vram_rdaddress_sig <= A - x"2000"; DI_CPU <= vram_q_sig when (A >= x"2000" and A <= x"4000") else D_ROM when (Rd_n = '0' and MReq_n = '0' and A < x"2000") else .....  

 

Also, I am now able to write using a 3.58Mhz clock, and read at 25Mhz. 

 

However, I am very confused. The LPM model for ram have control signals asserted low: 

ENTITY vram8k IS 

PORT 

data : IN STD_LOGIC_VECTOR (7 DOWNTO 0); 

rdaddress : IN STD_LOGIC_VECTOR (12 DOWNTO 0); 

rdclock : IN STD_LOGIC ; 

rden : IN STD_LOGIC := '1'; 

wraddress : IN STD_LOGIC_VECTOR (12 DOWNTO 0); 

wrclock : IN STD_LOGIC ; 

wren : IN STD_LOGIC := '1'; 

q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) 

); 

END vram8k; 

 

In my code, asserting write HIGH will write data. Asserting READ LOW will read data. something is very wrong here.... Is it me?
0 Kudos
Altera_Forum
Honored Contributor II
539 Views

I can't say anything about lpm_ram Megafunctions, I used altsyncram since Quartus V2, if I remember right. It has active high control signals, I would have thought the same of lpm_ram function, cause it's actually a wrapper of altsyncram, not inverting any signals as far as I see. Thus I guess, there is a misunderstanding of the basic operation of your design.

0 Kudos
Altera_Forum
Honored Contributor II
539 Views

You might want to change this snipet of code... 

 

(A >= x"2000" and A <= x"4000") 

to  

(A >= x"2000" and A < x"4000")  

 

otherwise you will be writing to ram when the address is x"2000" and x"4000".
0 Kudos
Altera_Forum
Honored Contributor II
539 Views

That's right, thank you... 

:)
0 Kudos
Reply