📄 npi_vga.vhd
字号:
heal_the_world <= '0';
elsif clk'event and clk = '1' then
heal_the_world <= '0';
XIL_NPI_RdFIFO_Flush <= '0';
-- start running the VGA timing when the first pixel data is already available
if run_timing = '0' and shadow_reg_filled = '1' then
run_timing <= '1';
shadow_reg_filled <= '0';
pixel_shift_register <= shadow_reg;
pixel_shift_register_content <= to_unsigned(C_PI_DATA_WIDTH/16-1,3); -- two or four new pixels!
end if;
x_pos_t <= x_pos;
if vsync = '0' then
low_x_resolution_set_dis <= low_x_resolution_set;
end if;
-- in case there is space for new pixel data in the rdFIFO
-- and we are currently not waiting for an request acknowledge
-- request new pixel data!
if pixels_requested < PIXEL_REQUEST_LOW and
wait_for_addr_ack = '0' and wait_for_addr_ack_wr = '0' then
-- set the request and correct address
XIL_NPI_AddrReq <= '1';
XIL_NPI_RNW <= '1';
-- remember that we are waiting for an acknowledge
-- such that we do not enter this if branch again the next clk
wait_for_addr_ack <= '1';
-- and handle update the address of the frame buffer for the next time
if screen_address_offset = frame_buffer_size then
-- only update this bound after a whole picture was requested
-- like this we stay synchronous even if the screen address is not set in the vsync
XIL_NPI_Addr <= frame_buffer_address;
screen_address_offset <= to_unsigned(REQUEST_SIZE*2, 22);
pixel_counter_x <= to_unsigned(REQUEST_SIZE, 11);
line_displayed_once <= '0';
-- set the new resolution
low_x_resolution_set <= low_x_resolution;
low_y_resolution_set <= low_y_resolution;
else
XIL_NPI_Addr <= std_logic_vector(unsigned(frame_buffer_address) + screen_address_offset);
screen_address_offset <= screen_address_offset + REQUEST_SIZE*2;
-- in case we have to display each line twice
-- test whether one line was displayed twice or not
if low_y_resolution_set = '1' then
-- test whether a whole line was displayed
if (low_x_resolution_set = '0' and pixel_counter_x = x_res - REQUEST_SIZE) or
(low_x_resolution_set = '1' and pixel_counter_x = x_res/2 - REQUEST_SIZE) then
pixel_counter_x <= (others => '0');
if line_displayed_once = '0' then
-- this was the first time the line was displayed
-- so display it another time and reset the screen offset counter
if low_x_resolution_set = '1' then
screen_address_offset <= screen_address_offset - x_res + REQUEST_SIZE*2;
else
screen_address_offset <= screen_address_offset - x_res*2 + REQUEST_SIZE*2;
end if;
line_displayed_once <= '1';
else
line_displayed_once <= '0';
end if;
else
pixel_counter_x <= pixel_counter_x + REQUEST_SIZE;
end if;
end if;
end if;
-----------------------------------------
-- FAST CLEARING OF SCREEN FUNCTIONALITY
-----------------------------------------
elsif fast_clear_pending = '1' and wait_for_addr_ack = '0' and wait_for_addr_ack_wr = '0'
and fast_clear_pixels_cleared < unsigned(fast_clear_pixels) then
XIL_NPI_AddrReq <= '1';
XIL_NPI_Addr <= std_logic_vector(unsigned(fast_clear_start_address) + fast_clear_offset);
XIL_NPI_RNW <= '0';
fast_clear_offset <= fast_clear_offset + to_unsigned(REQUEST_SIZE*2,22);
wait_for_addr_ack_wr <= '1';
end if;
if fast_clear_init = '1' then
fast_clear_pending <= '1';
fast_clear_done <= '0';
end if;
if wait_for_addr_ack_wr = '1' and XIL_NPI_AddrAck = '1' then
wait_for_addr_ack_wr <= '0';
XIL_NPI_AddrReq <= '0';
if fast_clear_pixels_cleared + REQUEST_SIZE >= unsigned(fast_clear_pixels) then
fast_clear_pending <= '0';
fast_clear_done <= '1'; -- initialize an interrupt
fast_clear_pixels_cleared <= (others => '0');
fast_clear_offset <= (others => '0');
else
fast_clear_pixels_cleared <= fast_clear_pixels_cleared + REQUEST_SIZE;
end if;
end if;
-- fill the output FIFO as much as possible with zeros (black)
if XIL_NPI_WrFIFO_AlmostFull = '0' and XIL_NPI_InitDone = '1' then
XIL_NPI_WrFIFO_Push <= '1';
else
XIL_NPI_WrFIFO_Push <= '0';
end if;
-- are we reading an entry of the FIFO?
-- If so: four pixels are read (64 bit entries, 16 bit pixels)
-- make this clocked, in mpmc3 empty-flag seems to be asynchronous
-- we thus need to do this to achieve the target clock frequency
XIL_NPI_RdFIFO_Pop_int_reg <= XIL_NPI_RdFIFO_Pop_int;
if XIL_NPI_RdFIFO_Pop_int_reg = '1' then
pixels_requested <= pixels_requested - C_PI_DATA_WIDTH/16;
end if;
-- was the read request acknowledged?
if wait_for_addr_ack = '1' and XIL_NPI_AddrAck = '1' then
-- yes: remove the request signal at once!
XIL_NPI_AddrReq <= '0';
wait_for_addr_ack <= '0';
-- and there is new data in the FIFO soon!
if XIL_NPI_RdFIFO_Pop_int_reg = '1' then
-- when reading in the same clock cycle some pixels are removed at the same time
pixels_requested <= pixels_requested + REQUEST_SIZE - C_PI_DATA_WIDTH/16;
else
pixels_requested <= pixels_requested + REQUEST_SIZE;
end if;
end if;
-- check whether the FIFO is empty for a long time
-- this happens when something is loaded with xmd
-- for unknown reasons
if XIL_NPI_RdFIFO_Empty = '1' and run_timing = '1' then
time_out_counter <= time_out_counter + 1;
else
time_out_counter <= (others => '0');
end if;
-- READING FIFO OF MPMC2/3/4
-- this is a small FSM that handles the latency of the rdFIFO
-- according to the MPMC2-XIL_NPI manual three values for the latency are possible:
-- 0: No latency at all
-- 1: 1 clock cycle
-- 2: 2 clock cycles
case reading_FSM is
when FIFO_REQ_0 =>
-- if our shadow register is empty and data is available in the FIFO
-- read data from the FIFO and store it in the shadow register
if shadow_reg_filled = '0' and XIL_NPI_RdFIFO_Empty = '0' then
-- here we also pop from the rdFIFO (async)
-- in case of zero latency we are done here
if XIL_NPI_RdFIFO_Latency = "00" then
shadow_reg_filled <= '1';
shadow_reg <= XIL_NPI_RdFIFO_Data;
else
-- else wait one or two clock cycles
reading_FSM <= FIFO_REQ_1;
end if;
end if;
when FIFO_REQ_1 =>
-- one clock latency? Yes: we are done
if XIL_NPI_RdFIFO_Latency = "01" then
shadow_reg_filled <= '1';
shadow_reg <= XIL_NPI_RdFIFO_Data;
reading_FSM <= FIFO_REQ_0;
else
-- else wait another clock cycle
reading_FSM <= FIFO_REQ_2;
end if;
when FIFO_REQ_2 =>
-- two clock cycles latency is the maximum
if XIL_NPI_RdFIFO_Latency = "10" then
shadow_reg_filled <= '1';
shadow_reg <= XIL_NPI_RdFIFO_Data;
reading_FSM <= FIFO_REQ_0;
end if;
end case;
-- TIMEOUT!!!!
-- SO HEAL THE WORLD!
if enable_screen = '0' or heal_the_world = '1' or time_out_counter = 1023 then
time_out_counter <= (others => '0');
wait_for_addr_ack <= '0';
XIL_NPI_AddrReq <= '0';
pixels_requested <= (others => '0');
-- this resets the VGA timing
run_timing <= '0';
XIL_NPI_RdFIFO_Flush <= '1';
screen_address_offset <= (others => '0');
reading_fsm <= FIFO_REQ_0;
x_pos_t <= (others => '0');
pixel_counter_x <= (others => '0');
line_displayed_once <= '0';
shadow_reg_filled <= '0';
reading_FSM <= FIFO_REQ_0;
end if;
blank_t <= blank;
tft_lcd_de <= '0';
-- display black only when a sync applies
-- we take the delayed blank to guarantee a constant time for all pixels
if blank_t = '1' or run_timing = '0' then
tft_lcd_r <= (others => '0');
tft_lcd_g <= (others => '0');
tft_lcd_b <= (others => '0');
-- or take the background color where possible
-- switch of the background color when the electron ray runs to the start position
if run_timing = '1' and hsync = '1' and (unsigned(y_pos) < bgnd_high or unsigned(y_pos) > bgnd_low) then
tft_lcd_r <= background_color(15 downto 11);
tft_lcd_g <= background_color(10 downto 5);
tft_lcd_b <= background_color( 4 downto 0);
end if;
else
-- we now display a new x, so display a new pixel
-- the data enable flag has to be set in any case, since we want to display one pixel twice!
if x_pos /= x_pos_t and run_timing = '1' then
tft_lcd_de <= '1';
end if;
-- we now display a new x, so display a new pixel
if (low_x_resolution_set_dis = '0' and x_pos /= x_pos_t and run_timing = '1') or
(low_x_resolution_set_dis = '1' and x_pos(10 downto 1) /= x_pos_t(10 downto 1) and run_timing = '1') then
-- thus, shift the 64 bit wide pixel shift register by 16 bits
-- and remember that one pixel less is pending in it
pixel_shift_register(C_PI_DATA_WIDTH-16-1 downto 0) <= pixel_shift_register(C_PI_DATA_WIDTH-1 downto 16);
pixel_shift_register_content <= pixel_shift_register_content - 1;
-- read two/four new pixels from shadow register if we display the very last pixel of the pixel shift register
if pixel_shift_register_content = 0 then
if shadow_reg_filled = '1' then
shadow_reg_filled <= '0';
pixel_shift_register <= shadow_reg;
pixel_shift_register_content <= to_unsigned(C_PI_DATA_WIDTH/16-1,3); -- two or four new pixels!
else
-- ERROR!! We need to use new pixels but they are not yet available!
-- So initialize a reset of the screen display!
heal_the_world <= '1';
end if;
end if;
end if;
-- inverse the bytes, due to little endianess
pixel_endian_inverse := pixel_shift_register(7 downto 0) & pixel_shift_register(15 downto 8);
tft_lcd_r <= pixel_endian_inverse(15 downto 11);
tft_lcd_g <= pixel_endian_inverse(10 downto 5);
tft_lcd_b <= pixel_endian_inverse(4 downto 0);
end if;
end if;
end process;
end rtl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -