Hello,
I am trying to use a screen buffer to store, change and output the bits of a video data to the DVI transmit interface.
I can not decide what kind of a RAM to use as the screen buffer. With some reading, I came to the conclusion that dual port inferred RAM would be the best choice. However, I am not sure how to use its read and write ports. I already managed to infer a ram block and instantiated it with using a function that generates a .mif file.
My current progress is as follows:
I think I managed to write data inside the RAM, but now I am stuck with feeding my data to DVI. For the time being I hold 1 bit per pixel inside the ram, and conclude the 24bit color inside the DVI block I designed. The color depends on the coordinate of the hcounter and vcounter. So, reading 16 bits from the RAM is not enough to pass it on to DVI, I need to pass it bit by bit at each clock edge.
Currently I do it as follows:
I use a register and hold the buffer output inside. Then at each clock cycle for 16 cycles, I output the LSB of the contents of the register and shift the data to right. What stucks in my head is that if I need to generate the read address earlier or not.
Currently if there is a 0 in buffer, that pixel corresponds to green. If 1, it corresponds to blue. What I do is that I instantiate the RAM full of '1's. Then I write '0' to a portion of it, and try to observe a thick horizontal line on the screen. Fortunately enough, I see that horizontal line, but it is not stationary. Its sweeping the screen from top to bottom or bottom to top, I can not differentiate. What might the cause of that particular issue?
I am trying to use a screen buffer to store, change and output the bits of a video data to the DVI transmit interface.
- I am using Altera Cyclone III development kit.
- I will be using 1440x900@60Hz for my resolution so my pixel clock rate is 106.7 MHz. The DVI interface is written and is tested within another project that was not using a screen buffer, but I think it is not a source to any problem.
I can not decide what kind of a RAM to use as the screen buffer. With some reading, I came to the conclusion that dual port inferred RAM would be the best choice. However, I am not sure how to use its read and write ports. I already managed to infer a ram block and instantiated it with using a function that generates a .mif file.
My current progress is as follows:
- Words will be 16 bits long. This means that RAM will have 81K addresses.
- The READ port will always have its write enable signal LOW (0).
- The WRITE port will always have its write enable signal HIGH (1).
- So I am trying to write and read SIMULTANEOUSLY. The clock for both is the same.
Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity FrameBuffer is
port
(
data_a : in std_logic_vector(15 downto 0);
data_b : in std_logic_vector(15 downto 0);
addr_a : in natural range 0 to 80999;
addr_b : in natural range 0 to 80999;
we_a : in std_logic ;
we_b : in std_logic ;
clk_106 : in std_logic;
q_a : out std_logic_vector(15 downto 0);
q_b : out std_logic_vector(15 downto 0)
);
end FrameBuffer;
architecture rtl of FrameBuffer is
-- Build a 2-D array type for the RAM
subtype word_t is std_logic_vector(15 downto 0);
type memory_t is array(0 to 80999) of word_t;
FUNCTION initialize_ram
return memory_t is
variable result : memory_t;
BEGIN
FOR i IN 0 to 80999 LOOP
result(i) := "1111111111111111";
END LOOP;
RETURN result;
END initialize_ram;
-- Declare the RAM
shared variable ram : memory_t :=initialize_ram ;
begin
-- Port A
process(clk_106)
begin
if(rising_edge(clk_106)) then -- Port A
if(we_a = '1') then
ram(addr_a) := data_a;
-- Read-during-write on the same port returns NEW data
q_a <= data_a;
else
-- Read-during-write on the mixed port returns OLD data
q_a <= ram(addr_a);
end if;
end if;
end process;
-- Port B
process(clk_106)
begin
if(rising_edge(clk_106)) then -- Port B
if(we_b = '1') then
ram(addr_b) := data_b;
-- Read-during-write on the same port returns NEW data
q_b <= data_b;
else
-- Read-during-write on the mixed port returns OLD data
q_b <= ram(addr_b);
end if;
end if;
end process;
end rtl;
Currently I do it as follows:
Code:
process(clk106M, locked_sgnl)
begin
if locked_sgnl = '0' then
address_counter <= (others => '0');
counter <= "10000";
pixel_in_register <= (others => '0');
elsif rising_edge(clk106M) and (locked_sgnl = '1') then
if (address_counter < "10011110001101000") then
if counter >= 16 then
pixel_in_register <= pixel_in;
address_counter <= address_counter + '1';
counter <= "00000";
else
pixel_in_sgnl <= pixel_in_register(0);
pixel_in_register <= '0' & pixel_in_register(15 downto 1);
counter <= counter + '1';
end if;
else
address_counter <= (others => '0');
end if;
end if;
end process;
buffer_address_dvi <= address_counter;
I use a register and hold the buffer output inside. Then at each clock cycle for 16 cycles, I output the LSB of the contents of the register and shift the data to right. What stucks in my head is that if I need to generate the read address earlier or not.
Currently if there is a 0 in buffer, that pixel corresponds to green. If 1, it corresponds to blue. What I do is that I instantiate the RAM full of '1's. Then I write '0' to a portion of it, and try to observe a thick horizontal line on the screen. Fortunately enough, I see that horizontal line, but it is not stationary. Its sweeping the screen from top to bottom or bottom to top, I can not differentiate. What might the cause of that particular issue?