Forum Discussion
Blockram: RAM model read/write
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.15 Replies
- Altera_Forum
Honored Contributor
That's right, thank you...
:) - Altera_Forum
Honored Contributor
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". - Altera_Forum
Honored Contributor
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.
- Altera_Forum
Honored Contributor
These seems to have worked very well:
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?-- 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 ..... - Altera_Forum
Honored Contributor
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. - Altera_Forum
Honored Contributor
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:
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.-- 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 ); - Altera_Forum
Honored Contributor
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. - Altera_Forum
Honored Contributor
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. - Altera_Forum
Honored Contributor
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.
It is a simple operation: Write into RAM, Read from RAM.-- 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 ); - Altera_Forum
Honored Contributor
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.