@jcm@wafrn.jcm.re asked
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity my_code is
generic(
WIDTH : integer := 640;
HEIGHT : integer := 480;
CONSOLE_COLUMNS : integer := WIDTH / 8;
CONSOLE_ROWS : integer := HEIGHT / 8
);
port(
clk : in std_logic;
rst : in std_logic;
px : in integer range 0 to WIDTH - 1;
py : in integer range 0 to HEIGHT - 1;
hsync : in std_logic;
vsync : in std_logic;
col : in integer range 0 to CONSOLE_COLUMNS - 1;
row : in integer range 0 to CONSOLE_ROWS - 1;
char : out integer range 0 to 127 := 0;
foreground_color : out std_logic_vector(23 downto 0) := (others => '0');
background_color : out std_logic_vector(23 downto 0) := (others => '1')
);
end my_code;
architecture rtl of my_code is
-- STATE MACHINE DEFINITIONS
type demo_state_t is (CALM_TUNNEL, DATA_STORM, RETRO_WAVE);
signal current_state : demo_state_t := CALM_TUNNEL;
-- SIGNALS
signal frame_counter : unsigned(31 downto 0) := (others => '0');
signal lfsr : unsigned(15 downto 0) := x"ACE1"; -- Linear Feedback Shift Register (Randomness)
-- COLOR OUTPUT BUFFERS
signal r_out, g_out, b_out : unsigned(7 downto 0);
constant MSG_1 : string := " INITIATING NEURAL LINK... ";
constant MSG_2 : string := " WARNING: DATA CORRUPTION DETECTED ";
begin
----------------------------------------------------------------------------
-- 1. MASTER TIMING & STATE CONTROL
----------------------------------------------------------------------------
process(clk)
variable old_vsync : std_logic := '0';
begin
if rising_edge(clk) then
if rst = '1' then
frame_counter <= (others => '0');
current_state <= CALM_TUNNEL;
lfsr <= x"ACE1"; -- Non-zero seed
else
-- LFSR: Generate pseudo-random noise every clock cycle
-- Taps: 16, 14, 13, 11 (Standard 16-bit LFSR polynomial)
lfsr <= lfsr(14 downto 0) & (lfsr(15) xor lfsr(13) xor lfsr(12) xor lfsr(10));
if vsync = '0' and old_vsync = '1' then
frame_counter <= frame_counter + 1;
-- Cycle states every 128 frames (~2 seconds)
if frame_counter(6 downto 0) = 127 then
case current_state is
when CALM_TUNNEL => current_state <= DATA_STORM;
when DATA_STORM => current_state <= RETRO_WAVE;
when RETRO_WAVE => current_state <= CALM_TUNNEL;
end case;
end if;
end if;
old_vsync := vsync;
end if;
end if;
end process;
----------------------------------------------------------------------------
-- 2. TEXT OVERLAY LOGIC
----------------------------------------------------------------------------
process(col, row, current_state)
variable str_idx : integer;
begin
char <= 0;
foreground_color <= (others => '0');
-- Center the text row
if row = CONSOLE_ROWS / 2 then
-- Simple centering logic
str_idx := col - (CONSOLE_COLUMNS/2 - 15);
if current_state = DATA_STORM then
-- In Data Storm mode, show warning
if str_idx >= 0 and str_idx < MSG_2'length then
char <= character'pos(MSG_2(str_idx + 1));
foreground_color <= x"FF0000"; -- Red Alert
end if;
else
-- Otherwise show status
if str_idx >= 0 and str_idx < MSG_1'length then
char <= character'pos(MSG_1(str_idx + 1));
foreground_color <= x"00FFFF"; -- Cyan
end if;
end if;
end if;
end process;
----------------------------------------------------------------------------
-- 3. PIXEL SHADER ARCHITECTURE (Latch-Free)
----------------------------------------------------------------------------
process(px, py, frame_counter, lfsr, current_state)
-- Variables for coordinate math
variable dx, dy : integer;
variable dist_man : unsigned(9 downto 0); -- Manhattan Distance
variable time_val : unsigned(7 downto 0);
variable noise_pixel: std_logic;
variable scan_line : integer;
begin
-- 3a. DEFAULT ASSIGNMENTS (Crucial to prevent latches)
r_out <= (others => '0');
g_out <= (others => '0');
b_out <= (others => '0');
-- 3b. MATH PRE-CALCULATION
-- Calculate distance from center (WIDTH/2 = 320, HEIGHT/2 = 240)
if px > 320 then dx := px - 320; else dx := 320 - px; end if;
if py > 240 then dy := py - 240; else dy := 240 - py; end if;
-- Manhattan distance (Diamond shape) |x| + |y|
-- We clamp it to 10 bits to prevent overflow issues
dist_man := to_unsigned(dx + dy, 10);
time_val := resize(frame_counter(7 downto 0), 8);
-- 3c. VISUAL GENERATION
case current_state is
when CALM_TUNNEL =>
-- Effect: A smooth purple/blue diamond tunnel zooming inward
-- Logic: (Distance - Time) creates inward movement
r_out <= dist_man(7 downto 0) - time_val;
g_out <= (others => '0');
b_out <= dist_man(7 downto 0) + time_val;
when DATA_STORM =>
-- Effect: The tunnel turns green/matrix and gets noisy
-- We use the LSFR bit 0 to randomly turn pixels bright white
if lfsr(0) = '1' and lfsr(4) = '1' then
r_out <= x"FF"; g_out <= x"FF"; b_out <= x"FF"; -- Sparkle
else
r_out <= (others => '0');
g_out <= dist_man(7 downto 0) xor time_val; -- Matrix Green XOR pattern
b_out <= (others => '0');
end if;
when RETRO_WAVE =>
-- Effect: Synthwave style horizontal scanlines
-- We use modulo on Y + Time to create scrolling bars
scan_line := (py + to_integer(time_val)*2) mod 32;
if scan_line < 4 then
-- Bright Grid Line
r_out <= x"FF"; g_out <= x"00"; b_out <= x"80"; -- Hot Pink
else
-- Background Gradient
r_out <= to_unsigned(py / 2, 8); -- Vertical Red Gradient
g_out <= (others => '0');
b_out <= to_unsigned(px / 3, 8); -- Horizontal Blue Gradient
end if;
end case;
end process;
-- MAP OUTPUTS
background_color <= std_logic_vector(r_out) &
std_logic_vector(g_out) &
std_logic_vector(b_out);
end architecture;
Sucess!
UtilizationCellUsedAvailableUsage
DCCA2563.6%
EHXPLLL1250%
TRELLIS_COMB1402242885.8%
TRELLIS_FF162242880.7%
TRELLIS_IO101975.1%
TimingClockAchievedConstraint
$glbnet$clkp39.94 MHz25 MHz
$glbnet$clkt303.67 MHz250 MHz
#FPGA #Icepi-Zero #HDL #VHDL