#fpga

2026-02-21

Pourquoi j'ai l'impression que quand je tape un acronyme en trois lettres je tombe inévitablement sur des acronymes du ministère de l'éducation nationale ?

La je cherche VPI pour Verilog Procedural Interface, on est loin des vidéoprojecteurs interactifs quand même ;)

#vpi #en #verilog #fpga #simulation #flf

Selena the Retro-PrincessSuperSelena64@vmst.io
2026-02-20

This was an unexpected but welcome thing to wake up to! Quake running natively on the Analogue Pocket!
Definitely a bit choppy at times and with low-res textures and questionable audio, but it's still super rad.
It also supports the link cable for LAN play!
#retrogaming #quake #fpga

A list of cores on my Analogue Pocket with PocketQuake highlightedA picture of PocketQuake running, you can see the low-res textures, but it's identifiably Quake!
MPI for Gravitational Physicsmpi_grav@academiccloud.social
2026-02-20

✨ New selected research highlight ✨

LISA on a tabletop

First milestone towards a hardware-in-the-loop testbed of the space-based gravitational-wave detector

ℹ️ aei.mpg.de/1413242/lisa-on-a-t

📄 iopscience.iop.org/article/10.

A team of @mpi_grav and @unihannover researchers has successfully demonstrated hardware simulations of the LISA inter-satellite links. Their hardware testbed uses field-programmable gate arrays, high-speed computer memory, and signal converters.

It can digitally simulate realistic delays, Doppler shifts, and the injection and recovery of gravitational-wave signals.

#LISA #GravitationalWaves #Research #Science #Space #Laser #FPGA

Four-paneled diagram showing various measurements: Top left: Full time series of the η composite measurements and the minimized TDI combination. Red and blue boxes indicate zoomed regions. Top right: zoom of the central region showing the inspiral revealed in the TDI combination, the injected inspiral waveform, and the subtraction of the latter from the former. Bottom left: zoom of the time around the coalescence, showing the same. Bottom right: Spectral densities of these time series with the LISA benchmark scaled by the TDI X1 transfer function. The residual noise floor described earlier is recovered, albeit with an uptick at the lowest frequency bin likely due to DC spectral leakage from the signal injection.
2026-02-20

growing bigger

#fpga

2026-02-20

Well, I think this XCVU13P #FPGA is dead. I traced the short on the 1.8 V rail to caps under the BGA and removed three of them. The pads still show the same voltage 😕

Salvaging 4X LTM4630Y and 2X LTM4628Y DC-DC modules makes the purchase worth it anyway.

Big FPGA board labeled “Quantum Machines” with a XCVU13P on it, four FMC connectors, and a DDR4 DIMM slotClose up of three removed decoupling capacitors under the BGA
2026-02-19

@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 -- Aliases to map the 24-bit vectors to RGB channels easily alias bg_red : std_logic_vector(7 downto 0) is background_color(23 downto 16); alias bg_green : std_logic_vector(7 downto 0) is background_color(15 downto 8); alias bg_blue : std_logic_vector(7 downto 0) is background_color(7 downto 0); alias fg_red : std_logic_vector(7 downto 0) is foreground_color(23 downto 16); alias fg_green : std_logic_vector(7 downto 0) is foreground_color(15 downto 8); alias fg_blue : std_logic_vector(7 downto 0) is foreground_color(7 downto 0); signal frame_counter : unsigned(31 downto 0) := (others => '0'); -- Player Ship ASCII Graphics (Using safe characters to avoid escape sequence issues) constant ship_t : string(1 to 4) := " .^ "; constant ship_m : string(1 to 4) := "===>"; constant ship_b : string(1 to 4) := " 'v "; -- Enemy Asteroid Graphics constant ast_1 : string(1 to 3) := "(O)"; constant ast_2 : string(1 to 3) := "{#}"; -- Game Logic State Signals signal ship_y : integer := 20; signal ast_x : integer := 80; signal ast_y : integer := 20; signal ast_type : std_logic := '0'; signal laser_x : integer := -10; signal laser_y : integer := 0; signal laser_active : std_logic := '0'; -- Math signals for procedurally generated background elements signal xor_pattern : unsigned(7 downto 0); signal star_fast : unsigned(7 downto 0); signal star_slow : unsigned(7 downto 0); begin -- 1. Procedural "Munching Squares" Hyperspace Background -- By XORing the scaled coordinates and the frame counter, we create a mathematical -- fractal pattern that continuously zooms and shifts leftward. xor_pattern <= (to_unsigned(px / 4, 8) + frame_counter(9 downto 2)) xor to_unsigned(py / 4, 8); bg_red <= std_logic_vector(xor_pattern); -- Adding a bit of green and inverted blue makes it a crazy high-contrast neon vibe bg_green <= std_logic_vector(xor_pattern(6 downto 0) & '0'); bg_blue <= std_logic_vector(not xor_pattern); -- 2. Procedural Parallax Starfield Math -- We use prime number multipliers and bit masking to create a pseudo-random distribution -- that requires ZERO hardware division or modulo operators. star_fast <= to_unsigned(col * 13 + row * 7, 8) + frame_counter(8 downto 1); star_slow <= to_unsigned(col * 29 + row * 11, 8) + frame_counter(10 downto 3); -- 3. Character & Foreground Renderer process(col, row, ship_y, ast_x, ast_y, ast_type, frame_counter, laser_x, laser_y, laser_active, star_fast, star_slow) begin -- Default: Empty space char <= 0; fg_red <= x"FF"; fg_green <= x"FF"; fg_blue <= x"FF"; -- RENDER PLAYER SHIP if col >= 5 and col < 9 then if row = ship_y - 1 then char <= character'pos(ship_t(col - 5 + 1)); fg_red <= x"00"; fg_green <= x"FF"; fg_blue <= x"FF"; -- Cyan elsif row = ship_y then char <= character'pos(ship_m(col - 5 + 1)); fg_red <= x"00"; fg_green <= x"FF"; fg_blue <= x"FF"; elsif row = ship_y + 1 then char <= character'pos(ship_b(col - 5 + 1)); fg_red <= x"00"; fg_green <= x"FF"; fg_blue <= x"FF"; end if; -- RENDER ENGINE THRUST FLAME elsif col = 4 and row = ship_y then if frame_counter(2) = '1' then char <= character'pos('~'); fg_red <= x"FF"; fg_green <= x"45"; fg_blue <= x"00"; -- Orange-Red else char <= character'pos('-'); fg_red <= x"FF"; fg_green <= x"D7"; fg_blue <= x"00"; -- Gold end if; -- RENDER LASER BEAM elsif laser_active = '1' and row = laser_y and col >= laser_x and col < laser_x + 3 then char <= character'pos('-'); fg_red <= x"FF"; fg_green <= x"00"; fg_blue <= x"00"; -- Bright Red -- RENDER INCOMING ASTEROIDS elsif row = ast_y and col >= ast_x and col < ast_x + 3 then if ast_type = '0' then char <= character'pos(ast_1(col - ast_x + 1)); else char <= character'pos(ast_2(col - ast_x + 1)); end if; fg_red <= x"A9"; fg_green <= x"A9"; fg_blue <= x"A9"; -- Gray -- RENDER PARALLAX STARFIELD else -- Check the bitmasks of our math signals to spawn stars sparsely if star_fast(4 downto 0) = "00000" then char <= character'pos('-'); -- Fast streaks fg_red <= x"AA"; fg_green <= x"AA"; fg_blue <= x"FF"; elsif star_slow(5 downto 0) = "000000" then char <= character'pos('.'); -- Slow distant dots fg_red <= x"88"; fg_green <= x"88"; fg_blue <= x"88"; end if; end if; end process; -- 4. Game Engine (Animation & Collision Logic) process(clk) variable old_vsync : std_logic := '0'; begin if rising_edge(clk) then if rst = '1' then frame_counter <= (others => '0'); ship_y <= CONSOLE_ROWS / 2; ast_x <= CONSOLE_COLUMNS + 5; ast_y <= 20; laser_active <= '0'; elsif vsync = '0' and old_vsync = '1' then -- Increment global timer frame_counter <= frame_counter + 1; -- 4a. Ship bobbing (Sine wave approximation using counter bits) if frame_counter(5 downto 0) = "000000" then if frame_counter(6) = '1' and ship_y < CONSOLE_ROWS - 4 then ship_y <= ship_y + 1; elsif frame_counter(6) = '0' and ship_y > 4 then ship_y <= ship_y - 1; end if; end if; -- 4b. Asteroid Movement (Moves leftward) if frame_counter(1 downto 0) = "00" then if ast_x < -3 then ast_x <= CONSOLE_COLUMNS + 5; -- Respawn off-screen right -- Use bits of the frame counter to randomly select new Y row and type ast_y <= 5 + to_integer(frame_counter(7 downto 3)); ast_type <= frame_counter(2); else ast_x <= ast_x - 1; end if; end if; -- 4c. Laser Physics and Collision Detection if laser_active = '1' then -- Lasers move very fast to the right laser_x <= laser_x + 2; -- Deactivate if it goes off screen if laser_x > CONSOLE_COLUMNS then laser_active <= '0'; end if; -- Collision Check: Did the laser hit the asteroid? if laser_x >= ast_x and laser_y = ast_y then ast_x <= -10; -- Banish asteroid off-screen laser_active <= '0'; -- Turn off laser end if; else -- Auto-fire mechanism: Shoot a new laser periodically! if frame_counter(6 downto 0) = "0000000" then laser_active <= '1'; laser_x <= 10; laser_y <= ship_y; end if; end if; end if; old_vsync := vsync; end if; end process; end architecture;

Sucess!

UtilizationCellUsedAvailableUsage DCCA2563.6% EHXPLLL1250% MULT18X18D42814.3% TRELLIS_COMB1842242887.6% TRELLIS_FF281242881.2% TRELLIS_IO101975.1%
TimingClockAchievedConstraint $glbnet$clkp35.49 MHz25 MHz $glbnet$clkt312.7 MHz250 MHz
Code

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
    -- Aliases to map the 24-bit vectors to RGB channels easily
    alias bg_red   : std_logic_vector(7 downto 0) is background_color(23 downto 16);
    alias bg_green : std_logic_vector(7 downto 0) is background_color(15 downto 8);
    alias bg_blue  : std_logic_vector(7 downto 0) is background_color(7 downto 0);

    alias fg_red   : std_logic_vector(7 downto 0) is foreground_color(23 downto 16);
    alias fg_green : std_logic_vector(7 downto 0) is foreground_color(15 downto 8);
    alias fg_blue  : std_logic_vector(7 downto 0) is foreground_color(7 downto 0);

    signal frame_counter : unsigned(31 downto 0) := (others => '0');

    -- Player Ship ASCII Graphics (Using safe characters to avoid escape sequence issues)
    constant ship_t : string(1 to 4) := " .^ ";
    constant ship_m : string(1 to 4) := "===>";
    constant ship_b : string(1 to 4) := " 'v ";

    -- Enemy Asteroid Graphics
    constant ast_1 : string(1 to 3) := "(O)";
    constant ast_2 : string(1 to 3) := "{#}";

    -- Game Logic State Signals
    signal ship_y       : integer := 20;
    signal ast_x        : integer := 80;
    signal ast_y        : integer := 20;
    signal ast_type     : std_logic := '0';
    signal laser_x      : integer := -10;
    signal laser_y      : integer := 0;
    signal laser_active : std_logic := '0';

    -- Math signals for procedurally generated background elements
    signal xor_pattern  : unsigned(7 downto 0);
    signal star_fast    : unsigned(7 downto 0);
    signal star_slow    : unsigned(7 downto 0);

begin
    -- 1. Procedural "Munching Squares" Hyperspace Background
    -- By XORing the scaled coordinates and the frame counter, we create a mathematical 
    -- fractal pattern that continuously zooms and shifts leftward.
    xor_pattern <= (to_unsigned(px / 4, 8) + frame_counter(9 downto 2)) xor to_unsigned(py / 4, 8);

    bg_red   <= std_logic_vector(xor_pattern);
    -- Adding a bit of green and inverted blue makes it a crazy high-contrast neon vibe
    bg_green <= std_logic_vector(xor_pattern(6 downto 0) & '0'); 
    bg_blue  <= std_logic_vector(not xor_pattern); 

    -- 2. Procedural Parallax Starfield Math
    -- We use prime number multipliers and bit masking to create a pseudo-random distribution
    -- that requires ZERO hardware division or modulo operators.
    star_fast <= to_unsigned(col * 13 + row * 7, 8) + frame_counter(8 downto 1);
    star_slow <= to_unsigned(col * 29 + row * 11, 8) + frame_counter(10 downto 3);

    -- 3. Character & Foreground Renderer
    process(col, row, ship_y, ast_x, ast_y, ast_type, frame_counter, laser_x, laser_y, laser_active, star_fast, star_slow)
    begin
        -- Default: Empty space
        char <= 0;
        fg_red <= x"FF"; fg_green <= x"FF"; fg_blue <= x"FF";

        -- RENDER PLAYER SHIP
        if col >= 5 and col < 9 then
            if row = ship_y - 1 then
                char <= character'pos(ship_t(col - 5 + 1));
                fg_red <= x"00"; fg_green <= x"FF"; fg_blue <= x"FF"; -- Cyan
            elsif row = ship_y then
                char <= character'pos(ship_m(col - 5 + 1));
                fg_red <= x"00"; fg_green <= x"FF"; fg_blue <= x"FF";
            elsif row = ship_y + 1 then
                char <= character'pos(ship_b(col - 5 + 1));
                fg_red <= x"00"; fg_green <= x"FF"; fg_blue <= x"FF";
            end if;

        -- RENDER ENGINE THRUST FLAME
        elsif col = 4 and row = ship_y then
            if frame_counter(2) = '1' then
                char <= character'pos('~');
                fg_red <= x"FF"; fg_green <= x"45"; fg_blue <= x"00"; -- Orange-Red
            else
                char <= character'pos('-');
                fg_red <= x"FF"; fg_green <= x"D7"; fg_blue <= x"00"; -- Gold
            end if;

        -- RENDER LASER BEAM
        elsif laser_active = '1' and row = laser_y and col >= laser_x and col < laser_x + 3 then
            char <= character'pos('-');
            fg_red <= x"FF"; fg_green <= x"00"; fg_blue <= x"00"; -- Bright Red

        -- RENDER INCOMING ASTEROIDS
        elsif row = ast_y and col >= ast_x and col < ast_x + 3 then
            if ast_type = '0' then
                char <= character'pos(ast_1(col - ast_x + 1));
            else
                char <= character'pos(ast_2(col - ast_x + 1));
            end if;
            fg_red <= x"A9"; fg_green <= x"A9"; fg_blue <= x"A9"; -- Gray

        -- RENDER PARALLAX STARFIELD
        else
            -- Check the bitmasks of our math signals to spawn stars sparsely
            if star_fast(4 downto 0) = "00000" then
                char <= character'pos('-'); -- Fast streaks
                fg_red <= x"AA"; fg_green <= x"AA"; fg_blue <= x"FF"; 
            elsif star_slow(5 downto 0) = "000000" then
                char <= character'pos('.'); -- Slow distant dots
                fg_red <= x"88"; fg_green <= x"88"; fg_blue <= x"88"; 
            end if;
        end if;
    end process;

    -- 4. Game Engine (Animation & Collision Logic)
    process(clk)
        variable old_vsync : std_logic := '0';
    begin
        if rising_edge(clk) then
            if rst = '1' then
                frame_counter <= (others => '0');
                ship_y <= CONSOLE_ROWS / 2;
                ast_x <= CONSOLE_COLUMNS + 5;
                ast_y <= 20;
                laser_active <= '0';
            elsif vsync = '0' and old_vsync = '1' then
                -- Increment global timer
                frame_counter <= frame_counter + 1;

                -- 4a. Ship bobbing (Sine wave approximation using counter bits)
                if frame_counter(5 downto 0) = "000000" then
                    if frame_counter(6) = '1' and ship_y < CONSOLE_ROWS - 4 then
                        ship_y <= ship_y + 1;
                    elsif frame_counter(6) = '0' and ship_y > 4 then
                        ship_y <= ship_y - 1;
                    end if;
                end if;

                -- 4b. Asteroid Movement (Moves leftward)
                if frame_counter(1 downto 0) = "00" then
                    if ast_x < -3 then
                        ast_x <= CONSOLE_COLUMNS + 5; -- Respawn off-screen right
                        -- Use bits of the frame counter to randomly select new Y row and type
                        ast_y <= 5 + to_integer(frame_counter(7 downto 3)); 
                        ast_type <= frame_counter(2);
                    else
                        ast_x <= ast_x - 1;
                    end if;
                end if;

                -- 4c. Laser Physics and Collision Detection
                if laser_active = '1' then
                    -- Lasers move very fast to the right
                    laser_x <= laser_x + 2;

                    -- Deactivate if it goes off screen
                    if laser_x > CONSOLE_COLUMNS then
                        laser_active <= '0';
                    end if;

                    -- Collision Check: Did the laser hit the asteroid?
                    if laser_x >= ast_x and laser_y = ast_y then
                         ast_x <= -10;        -- Banish asteroid off-screen
                         laser_active <= '0'; -- Turn off laser
                    end if;
                else
                    -- Auto-fire mechanism: Shoot a new laser periodically!
                    if frame_counter(6 downto 0) = "0000000" then
                        laser_active <= '1';
                        laser_x <= 10;
                        laser_y <= ship_y;
                    end if;
                end if;
            end if;

            old_vsync := vsync;
        end if;
    end process;

end architecture;


#FPGA #Icepi-Zero #HDL #VHDL
2026-02-19

@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 -- Aliases for RGB color channels alias bg_red : std_logic_vector(7 downto 0) is background_color(23 downto 16); alias bg_green : std_logic_vector(7 downto 0) is background_color(15 downto 8); alias bg_blue : std_logic_vector(7 downto 0) is background_color(7 downto 0); alias fg_red : std_logic_vector(7 downto 0) is foreground_color(23 downto 16); alias fg_green : std_logic_vector(7 downto 0) is foreground_color(15 downto 8); alias fg_blue : std_logic_vector(7 downto 0) is foreground_color(7 downto 0); signal frame_counter : unsigned(31 downto 0) := (others => '0'); -- Our ASCII Aquarium residents constant fish_right : string(1 to 5) := " ><> "; constant fish_left : string(1 to 5) := " <>< "; constant crab : string(1 to 5) := "(\_/)"; -- Coordinates for our moving fish (unconstrained integers to allow them to swim off-screen) signal fish1_x : integer := -5; signal fish1_y : integer := 5; signal fish2_x : integer := CONSOLE_COLUMNS + 5; signal fish2_y : integer := 15; -- A slow toggle signal to make the seaweed wave back and forth signal wave_toggle : std_logic; begin -- 1. Deep Sea Gradient Background -- The water is brighter at the top (py = 0) and gets darker as it goes down. bg_red <= std_logic_vector(to_unsigned( 10, 8)); -- Minimal red underwater bg_green <= std_logic_vector(to_unsigned( 180 - (py / 3), 8)); bg_blue <= std_logic_vector(to_unsigned( 255 - (py / 4), 8)); -- 2. Foreground Color Logic process(row) begin if row >= CONSOLE_ROWS - 2 then -- Seaweed green for the bottom of the tank fg_red <= x"2E"; fg_green <= x"8B"; fg_blue <= x"57"; else -- Crisp white for the fish and bubbles fg_red <= x"FF"; fg_green <= x"FF"; fg_blue <= x"FF"; end if; end process; wave_toggle <= frame_counter(4); -- Toggles every 16 frames -- 3. Character Rendering Logic (The Magic) process(col, row, fish1_x, fish1_y, fish2_x, fish2_y, frame_counter, wave_toggle) variable bubble_offset : integer range 0 to 63; begin -- Default: Empty water char <= 0; -- Draw Fish 1 (swimming right) if row = fish1_y and col >= fish1_x and col < fish1_x + 5 then if (col - fish1_x + 1) >= 1 and (col - fish1_x + 1) <= 5 then char <= character'pos(fish_right(col - fish1_x + 1)); end if; -- Draw Fish 2 (swimming left) elsif row = fish2_y and col >= fish2_x and col < fish2_x + 5 then if (col - fish2_x + 1) >= 1 and (col - fish2_x + 1) <= 5 then char <= character'pos(fish_left(col - fish2_x + 1)); end if; -- Draw the little Crab hanging out on the sea floor elsif row = CONSOLE_ROWS - 1 and col >= 30 and col < 35 then char <= character'pos(crab(col - 30 + 1)); -- Draw animated Seaweed at the bottom elsif row >= CONSOLE_ROWS - 2 then if (col mod 7) = 0 then if wave_toggle = '1' then char <= character'pos('~'); else char <= character'pos('S'); end if; elsif (col mod 11) = 0 and row = CONSOLE_ROWS - 1 then if wave_toggle = '0' then char <= character'pos('~'); else char <= character'pos('S'); end if; end if; -- Draw organically rising bubbles else -- Select a few random-looking columns to spawn bubbles if (col = 12) or (col = 28) or (col = 52) or (col = 68) then -- Calculate an upward scrolling offset based on time and column position bubble_offset := to_integer(unsigned'(frame_counter(8 downto 3) + to_unsigned(col * 5, 6))); -- If the bubble is currently on the screen, draw it! if bubble_offset < CONSOLE_ROWS then if row = (CONSOLE_ROWS - 1 - bubble_offset) then if (col mod 3) = 0 then char <= character'pos('o'); else char <= character'pos('O'); end if; end if; end if; end if; end if; end process; -- 4. Animation Timing and Movement process(clk) variable old_vsync : std_logic := '0'; begin if rising_edge(clk) then if rst = '1' then frame_counter <= (others => '0'); fish1_x <= -5; fish2_x <= CONSOLE_COLUMNS + 5; elsif vsync = '0' and old_vsync = '1' then -- Increment frame counter at the start of each new frame frame_counter <= frame_counter + 1; -- Move Fish 1 to the right (Medium Speed) if frame_counter(2 downto 0) = "000" then if fish1_x > CONSOLE_COLUMNS then fish1_x <= -10; -- Wrap around -- Pseudo-randomize depth when it wraps fish1_y <= 3 + to_integer(frame_counter(4 downto 3)); else fish1_x <= fish1_x + 1; end if; end if; -- Move Fish 2 to the left (Slightly Faster) if frame_counter(1 downto 0) = "00" then if fish2_x < -10 then fish2_x <= CONSOLE_COLUMNS + 5; -- Wrap around -- Pseudo-randomize depth when it wraps fish2_y <= 12 + to_integer(frame_counter(5 downto 4)); else fish2_x <= fish2_x - 1; end if; end if; end if; old_vsync := vsync; end if; end process; end architecture;

Sucess!

UtilizationCellUsedAvailableUsage DCCA2563.6% EHXPLLL1250% MULT18X18D1283.6% TRELLIS_COMB2017242888.3% TRELLIS_FF210242880.9% TRELLIS_IO101975.1%
TimingClockAchievedConstraint $glbnet$clkp32 MHz25 MHz $glbnet$clkt276.93 MHz250 MHz
Code

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
    -- Aliases for RGB color channels
    alias bg_red   : std_logic_vector(7 downto 0) is background_color(23 downto 16);
    alias bg_green : std_logic_vector(7 downto 0) is background_color(15 downto 8);
    alias bg_blue  : std_logic_vector(7 downto 0) is background_color(7 downto 0);

    alias fg_red   : std_logic_vector(7 downto 0) is foreground_color(23 downto 16);
    alias fg_green : std_logic_vector(7 downto 0) is foreground_color(15 downto 8);
    alias fg_blue  : std_logic_vector(7 downto 0) is foreground_color(7 downto 0);

    signal frame_counter : unsigned(31 downto 0) := (others => '0');

    -- Our ASCII Aquarium residents
    constant fish_right : string(1 to 5) := " ><> ";
    constant fish_left  : string(1 to 5) := " <>< ";
    constant crab       : string(1 to 5) := "(\_/)";

    -- Coordinates for our moving fish (unconstrained integers to allow them to swim off-screen)
    signal fish1_x : integer := -5;
    signal fish1_y : integer := 5;

    signal fish2_x : integer := CONSOLE_COLUMNS + 5;
    signal fish2_y : integer := 15;

    -- A slow toggle signal to make the seaweed wave back and forth
    signal wave_toggle : std_logic;

begin
    -- 1. Deep Sea Gradient Background
    -- The water is brighter at the top (py = 0) and gets darker as it goes down.
    bg_red   <= std_logic_vector(to_unsigned( 10, 8)); -- Minimal red underwater
    bg_green <= std_logic_vector(to_unsigned( 180 - (py / 3), 8));
    bg_blue  <= std_logic_vector(to_unsigned( 255 - (py / 4), 8));

    -- 2. Foreground Color Logic
    process(row)
    begin
        if row >= CONSOLE_ROWS - 2 then
            -- Seaweed green for the bottom of the tank
            fg_red   <= x"2E"; fg_green <= x"8B"; fg_blue <= x"57";
        else
            -- Crisp white for the fish and bubbles
            fg_red   <= x"FF"; fg_green <= x"FF"; fg_blue <= x"FF";
        end if;
    end process;

    wave_toggle <= frame_counter(4); -- Toggles every 16 frames

    -- 3. Character Rendering Logic (The Magic)
    process(col, row, fish1_x, fish1_y, fish2_x, fish2_y, frame_counter, wave_toggle)
        variable bubble_offset : integer range 0 to 63;
    begin
        -- Default: Empty water
        char <= 0;

        -- Draw Fish 1 (swimming right)
        if row = fish1_y and col >= fish1_x and col < fish1_x + 5 then
            if (col - fish1_x + 1) >= 1 and (col - fish1_x + 1) <= 5 then
                char <= character'pos(fish_right(col - fish1_x + 1));
            end if;

        -- Draw Fish 2 (swimming left)
        elsif row = fish2_y and col >= fish2_x and col < fish2_x + 5 then
            if (col - fish2_x + 1) >= 1 and (col - fish2_x + 1) <= 5 then
                char <= character'pos(fish_left(col - fish2_x + 1));
            end if;

        -- Draw the little Crab hanging out on the sea floor
        elsif row = CONSOLE_ROWS - 1 and col >= 30 and col < 35 then
            char <= character'pos(crab(col - 30 + 1));

        -- Draw animated Seaweed at the bottom
        elsif row >= CONSOLE_ROWS - 2 then
            if (col mod 7) = 0 then
                if wave_toggle = '1' then 
                    char <= character'pos('~'); 
                else 
                    char <= character'pos('S'); 
                end if;
            elsif (col mod 11) = 0 and row = CONSOLE_ROWS - 1 then
                if wave_toggle = '0' then 
                    char <= character'pos('~'); 
                else 
                    char <= character'pos('S'); 
                end if;
            end if;

        -- Draw organically rising bubbles
        else
            -- Select a few random-looking columns to spawn bubbles
            if (col = 12) or (col = 28) or (col = 52) or (col = 68) then
                -- Calculate an upward scrolling offset based on time and column position
                bubble_offset := to_integer(unsigned'(frame_counter(8 downto 3) + to_unsigned(col * 5, 6)));

                -- If the bubble is currently on the screen, draw it!
                if bubble_offset < CONSOLE_ROWS then
                    if row = (CONSOLE_ROWS - 1 - bubble_offset) then
                        if (col mod 3) = 0 then
                            char <= character'pos('o');
                        else
                            char <= character'pos('O');
                        end if;
                    end if;
                end if;
            end if;
        end if;
    end process;

    -- 4. Animation Timing and Movement
    process(clk)
        variable old_vsync : std_logic := '0';
    begin
        if rising_edge(clk) then
            if rst = '1' then
                frame_counter <= (others => '0');
                fish1_x <= -5;
                fish2_x <= CONSOLE_COLUMNS + 5;
            elsif vsync = '0' and old_vsync = '1' then
                -- Increment frame counter at the start of each new frame
                frame_counter <= frame_counter + 1;

                -- Move Fish 1 to the right (Medium Speed)
                if frame_counter(2 downto 0) = "000" then
                    if fish1_x > CONSOLE_COLUMNS then
                        fish1_x <= -10; -- Wrap around
                        -- Pseudo-randomize depth when it wraps
                        fish1_y <= 3 + to_integer(frame_counter(4 downto 3)); 
                    else
                        fish1_x <= fish1_x + 1;
                    end if;
                end if;

                -- Move Fish 2 to the left (Slightly Faster)
                if frame_counter(1 downto 0) = "00" then
                    if fish2_x < -10 then
                        fish2_x <= CONSOLE_COLUMNS + 5; -- Wrap around
                        -- Pseudo-randomize depth when it wraps
                        fish2_y <= 12 + to_integer(frame_counter(5 downto 4));
                    else
                        fish2_x <= fish2_x - 1;
                    end if;
                end if;
            end if;

            old_vsync := vsync;
        end if;
    end process;

end architecture;


#FPGA #Icepi-Zero #HDL #VHDL

Nick Brown (@NickBrownHPC)

뮌헨 WAMTA 학회에서 열린 키노트에서 비동기 다중 작업(asynchronous many-tasking)에 대해 발표했으며, @cerebras, RISC-V 및 FPGA를 언급하며 작업 단위(task)가 성능 확보에 결정적 역할을 한다고 설명했습니다.

x.com/NickBrownHPC/status/2024

#cerebras #riscv #fpga #hardware

2026-02-19

@jcm@wafrn.jcm.re asked

module my_code #( parameter int WIDTH = 640, parameter int HEIGHT = 480, parameter int CONSOLE_COLUMNS = WIDTH / 8, parameter int CONSOLE_ROWS = HEIGHT / 8 )( input logic clk, input logic rst, input int px, input int py, input logic hsync, input logic vsync, input int col, input int row, output int char, output logic [23:0] foreground_color, output logic [23:0] background_color ); logic [31:0] frame_counter = 0; logic old_vsync = 0; logic [7:0] red, green, blue; // Define a simple character mapping for demonstration. logic [7:0] char_code; always_comb begin // Calculate the character code based on pixel coordinates. // This creates a very basic "pixelated" text effect. char_code = (px % 8) << 4 | (py % 8); // Combine X and Y into a single char code // Simple color palette - Red for important, Green for normal, Blue for background red = 8'(col * 2); // More intense red based on column. green = 8'(py); // Normal green for the row. blue = frame_counter[7:0]; // Blue changes with the frame counter background_color = {red, green, blue}; foreground_color = char_code[7:0] ? 1'b1 : 1'b0; // Turn on foreground only when a character is being drawn. char = char_code; end always_ff @(posedge clk) begin if (vsync == 1'b0 && old_vsync == 1'b1) begin frame_counter <= frame_counter + 1; end old_vsync <= vsync; end endmodule

Sucess!

UtilizationCellUsedAvailableUsage DCCA2563.6% EHXPLLL1250% TRELLIS_COMB855242883.5% TRELLIS_FF143242880.6% TRELLIS_IO101975.1%
TimingClockAchievedConstraint $glbnet$clkp38.29 MHz25 MHz $glbnet$clkt293.69 MHz250 MHz
Code

module my_code #(
    parameter int WIDTH = 640,
    parameter int HEIGHT = 480,
    parameter int CONSOLE_COLUMNS = WIDTH / 8,
    parameter int CONSOLE_ROWS = HEIGHT / 8
)(
    input  logic clk,
    input  logic rst,

    input  int px,
    input  int py,
    input  logic hsync,
    input  logic vsync,

    input  int col,
    input  int row,

    output int char,
    output logic [23:0] foreground_color,
    output logic [23:0] background_color
);
    logic [31:0] frame_counter = 0;
    logic old_vsync = 0;

    logic [7:0] red, green, blue;

    // Define a simple character mapping for demonstration.
    logic [7:0] char_code;

    always_comb begin
        // Calculate the character code based on pixel coordinates.
        // This creates a very basic "pixelated" text effect.
        char_code = (px % 8) << 4 | (py % 8); // Combine X and Y into a single char code

        // Simple color palette -  Red for important, Green for normal, Blue for background
        red   = 8'(col * 2);   // More intense red based on column.
        green = 8'(py);      // Normal green for the row.
        blue  = frame_counter[7:0]; // Blue changes with the frame counter

        background_color = {red, green, blue};
        foreground_color = char_code[7:0] ? 1'b1 : 1'b0; // Turn on foreground only when a character is being drawn.
        char = char_code;
    end

    always_ff @(posedge clk) begin
        if (vsync == 1'b0 && old_vsync == 1'b1) begin
            frame_counter <= frame_counter + 1;
        end

        old_vsync <= vsync;
    end
endmodule


#FPGA #Icepi-Zero #HDL #SystemVerilog
2026-02-19

@jcm@wafrn.jcm.re asked

module my_code #( parameter int WIDTH = 640, parameter int HEIGHT = 480, parameter int CONSOLE_COLUMNS = WIDTH / 8, parameter int CONSOLE_ROWS = HEIGHT / 8 )( input logic clk, input logic rst, input int px, input int py, input logic hsync, input logic vsync, input int col, input int row, output int char, output logic [23:0] foreground_color, output logic [23:0] background_color ); logic [7:0] frame_counter; logic old_vsync; logic [7:0] red, green, blue; logic [7:0] character_data; // Data for the character to display // Character mapping - a simplified ASCII representation. More characters can be added. localparam CHAR_A = 8'h41; localparam CHAR_B = 8'h42; localparam CHAR_C = 8'h43; always_ff @(posedge clk) begin if (rst) begin frame_counter <= 0; old_vsync <= 0; character_data <= 8'h00; // Blank character end else begin frame_counter <= frame_counter + 1; old_vsync <= vsync; // Simple animation: A rotating character if (frame_counter % 30 == 0) begin //Update every 30 frames character_data <= (frame_counter / 30) % 3 ? CHAR_A : (frame_counter / 30) % 3 + 1 ? CHAR_B : CHAR_C; end end end always_comb begin // Color mapping - a simple color scheme. Adjust as needed. red = 8'(col * 2); //Red scales with column position green = 8'(py * 3); //Green scales with row position blue = frame_counter[7:0] % 64; //Blue cycles through a range background_color = {red, green, blue}; //Foreground color based on the character being displayed. if (character_data == CHAR_A) begin foreground_color = 24'h00FF0000; //Green on Black for 'A' end else if(character_data == CHAR_B) begin foreground_color = 24'hFF000000; //Red on Black for 'B' end else if (character_data == CHAR_C) begin foreground_color = 24'h0000FF00; //Green on Black for 'C' end else begin foreground_color = 24'hFFFFFF00; //White on Black for default character. end char = character_data; end endmodule

Sucess!

UtilizationCellUsedAvailableUsage DCCA2563.6% DP16KD2563.6% EHXPLLL1250% MULT18X18D1283.6% TRELLIS_COMB1002242884.1% TRELLIS_FF143242880.6% TRELLIS_IO101975.1%
TimingClockAchievedConstraint $glbnet$clkp38.73 MHz25 MHz $glbnet$clkt279.49 MHz250 MHz
Code

module my_code #(
    parameter int WIDTH = 640,
    parameter int HEIGHT = 480,
    parameter int CONSOLE_COLUMNS = WIDTH / 8,
    parameter int CONSOLE_ROWS = HEIGHT / 8
)(
    input  logic clk,
    input  logic rst,

    input  int px,
    input  int py,
    input  logic hsync,
    input  logic vsync,

    input  int col,
    input  int row,

    output int char,
    output logic [23:0] foreground_color,
    output logic [23:0] background_color
);
    logic [7:0] frame_counter;
    logic old_vsync;

    logic [7:0] red, green, blue;
    logic [7:0] character_data; // Data for the character to display


    // Character mapping - a simplified ASCII representation.  More characters can be added.
    localparam  CHAR_A = 8'h41;
    localparam  CHAR_B = 8'h42;
    localparam  CHAR_C = 8'h43;

    always_ff @(posedge clk) begin
        if (rst) begin
            frame_counter <= 0;
            old_vsync <= 0;
            character_data <= 8'h00; // Blank character
        end else begin
            frame_counter <= frame_counter + 1;
            old_vsync <= vsync;

            // Simple animation:  A rotating character
            if (frame_counter % 30 == 0) begin //Update every 30 frames
                character_data <= (frame_counter / 30) % 3 ? CHAR_A : (frame_counter / 30) % 3 + 1 ? CHAR_B : CHAR_C;
            end
        end
    end


    always_comb begin
        // Color mapping - a simple color scheme.  Adjust as needed.
        red   = 8'(col * 2); //Red scales with column position
        green = 8'(py * 3);  //Green scales with row position
        blue  = frame_counter[7:0] % 64; //Blue cycles through a range

        background_color = {red, green, blue};

        //Foreground color based on the character being displayed.
        if (character_data == CHAR_A) begin
            foreground_color = 24'h00FF0000;  //Green on Black for 'A'
        end else if(character_data == CHAR_B) begin
            foreground_color = 24'hFF000000; //Red on Black for 'B'
        end else if (character_data == CHAR_C) begin
            foreground_color = 24'h0000FF00;  //Green on Black for 'C'
        end else begin
            foreground_color = 24'hFFFFFF00; //White on Black for default character.
        end

        char = character_data;
    end
endmodule


#FPGA #Icepi-Zero #HDL #SystemVerilog
2026-02-19

@jcm@wafrn.jcm.re asked

module my_code #( parameter int WIDTH = 640, parameter int HEIGHT = 480, parameter int CONSOLE_COLUMNS = WIDTH / 8, parameter int CONSOLE_ROWS = HEIGHT / 8 )( input logic clk, input logic rst, input int px, input int py, input logic hsync, input logic vsync, input int col, input int row, output int char, output logic [23:0] foreground_color, output logic [23:0] background_color ); logic [31:0] frame_counter = '0; logic old_vsync = '0; logic [7:0] red, green, blue; // Define a simple character set - ASCII for demonstration. Can be expanded. logic [7:0] char_code; localparam MAX_CHARS = 256; //ASCII range always_comb begin // Simple character mapping based on row and column. Makes it look like text! if (row < CONSOLE_ROWS && col < CONSOLE_COLUMNS) begin char_code = { (col % MAX_CHARS), (row % MAX_CHARS) }; //Basic char selection. //This is a simplistic demo, a real console would need more sophisticated mapping! end else begin char_code = 8'h20; // Space if out of bounds end red = 8'(col * 4); green = 8'(py); blue = frame_counter[7:0]; background_color = {red, green, blue}; //Foreground color - a simple gradient based on row. //This adds visual interest and makes it look like something is "drawing." foreground_color = { (row % 16'hF000) , // Red component: Gradual change in red (row % 16'h00FF), // Green component: Gradual change in green (row % 16'h0000) // Blue Component: Constant blue. }; char = char_code; end always_ff @(posedge clk) begin if (vsync == 1'b0 && old_vsync == 1'b1) begin frame_counter <= frame_counter + 1; end old_vsync <= vsync; end endmodule

Sucess!

UtilizationCellUsedAvailableUsage DCCA2563.6% EHXPLLL1250% TRELLIS_COMB819242883.4% TRELLIS_FF142242880.6% TRELLIS_IO101975.1%
TimingClockAchievedConstraint $glbnet$clkp41.45 MHz25 MHz $glbnet$clkt361.01 MHz250 MHz
Code

module my_code #(
    parameter int WIDTH = 640,
    parameter int HEIGHT = 480,
    parameter int CONSOLE_COLUMNS = WIDTH / 8,
    parameter int CONSOLE_ROWS = HEIGHT / 8
)(
    input  logic clk,
    input  logic rst,

    input  int px,
    input  int py,
    input  logic hsync,
    input  logic vsync,

    input  int col,
    input  int row,

    output int char,
    output logic [23:0] foreground_color,
    output logic [23:0] background_color
);
    logic [31:0] frame_counter = '0;
    logic old_vsync = '0;

    logic [7:0] red, green, blue;

    // Define a simple character set - ASCII for demonstration.  Can be expanded.
    logic [7:0] char_code;
    localparam  MAX_CHARS = 256; //ASCII range

    always_comb begin
        // Simple character mapping based on row and column.  Makes it look like text!
        if (row < CONSOLE_ROWS && col < CONSOLE_COLUMNS) begin
            char_code = { (col % MAX_CHARS), (row % MAX_CHARS) }; //Basic char selection. 
                                                                       //This is a simplistic demo, a real console would need more sophisticated mapping!  
        end else begin
            char_code = 8'h20; // Space if out of bounds
        end

        red   = 8'(col * 4);
        green = 8'(py);
        blue  = frame_counter[7:0];

        background_color = {red, green, blue};

        //Foreground color - a simple gradient based on row.
        //This adds visual interest and makes it look like something is "drawing."
        foreground_color = {
            (row % 16'hF000) , // Red component:  Gradual change in red
            (row % 16'h00FF), // Green component: Gradual change in green
            (row % 16'h0000)  // Blue Component: Constant blue.

        };


        char = char_code;

    end

    always_ff @(posedge clk) begin
        if (vsync == 1'b0 && old_vsync == 1'b1) begin
            frame_counter <= frame_counter + 1;
        end

        old_vsync <= vsync;
    end
endmodule


#FPGA #Icepi-Zero #HDL #SystemVerilog
2026-02-19

@jcm@wafrn.jcm.re asked

module my_code #( parameter int WIDTH = 640, parameter int HEIGHT = 480, parameter int CONSOLE_COLUMNS = WIDTH / 8, parameter int CONSOLE_ROWS = HEIGHT / 8 )( input logic clk, input logic rst, input int px, input int py, input logic hsync, input logic vsync, input int col, input int row, output int char, output logic [23:0] foreground_color, output logic [23:0] background_color ); logic [31:0] frame_counter = '0; logic old_vsync = '0; logic [7:0] red, green, blue; // Simulate a simple text rendering. Adjustments for character mapping and color. logic [7:0] character_code; // Representing the ASCII value of the character to display. always_comb begin // Map row/col to a character code (simplified). character_code = (py / 16) + (px / 8); // Example mapping, adjust as needed. if(character_code > 127) character_code = 127; // Limit to ASCII range red = 8'(col * 4); green = 8'(py); blue = frame_counter[7:0]; background_color = {red, green, blue}; foreground_color = '1; char = character_code; // Assign the character code to the output. end always_ff @(posedge clk) begin if (vsync == 1'b0 && old_vsync == 1'b1) begin frame_counter <= frame_counter + 1; end old_vsync <= vsync; end endmodule

Sucess!

UtilizationCellUsedAvailableUsage DCCA2563.6% EHXPLLL1250% TRELLIS_COMB1363242885.6% TRELLIS_FF143242880.6% TRELLIS_IO101975.1%
TimingClockAchievedConstraint $glbnet$clkp39.67 MHz25 MHz $glbnet$clkt265.46 MHz250 MHz
Code

module my_code #(
    parameter int WIDTH = 640,
    parameter int HEIGHT = 480,
    parameter int CONSOLE_COLUMNS = WIDTH / 8,
    parameter int CONSOLE_ROWS = HEIGHT / 8
)(
    input  logic clk,
    input  logic rst,

    input  int px,
    input  int py,
    input  logic hsync,
    input  logic vsync,

    input  int col,
    input  int row,

    output int char,
    output logic [23:0] foreground_color,
    output logic [23:0] background_color
);
    logic [31:0] frame_counter = '0;
    logic old_vsync = '0;

    logic [7:0] red, green, blue;

    // Simulate a simple text rendering.  Adjustments for character mapping and color.
    logic [7:0] character_code; // Representing the ASCII value of the character to display.

    always_comb begin
        // Map row/col to a character code (simplified).
        character_code = (py / 16) + (px / 8);  // Example mapping, adjust as needed.
        if(character_code > 127) character_code = 127; // Limit to ASCII range

        red   = 8'(col * 4);
        green = 8'(py);
        blue  = frame_counter[7:0];


        background_color = {red, green, blue};
        foreground_color = '1;

        char = character_code; // Assign the character code to the output.
    end

    always_ff @(posedge clk) begin
        if (vsync == 1'b0 && old_vsync == 1'b1) begin
            frame_counter <= frame_counter + 1;
        end

        old_vsync <= vsync;
    end
endmodule


#FPGA #Icepi-Zero #HDL #SystemVerilog
2026-02-19

@jcm@wafrn.jcm.re asked

module my_code #( parameter int WIDTH = 640, parameter int HEIGHT = 480, parameter int CONSOLE_COLUMNS = WIDTH / 8, parameter int CONSOLE_ROWS = HEIGHT / 8 )( input logic clk, input logic rst, input int px, input int py, input logic hsync, input logic vsync, input int col, input int row, output int char, output logic [23:0] foreground_color, output logic [23:0] background_color ); // Cute and creative architecture always_comb begin // Generate a cute rainbow effect for the background color case (col) 0: {red, green, blue} = 'hFF0000; // Red 1: {red, green, blue} = 'hFFFF00; // Yellow 2: {red, green, blue} = 'h00FF00; // Green 3: {red, green, blue} = 'h00FFFF; // Cyan 4: {red, green, blue} = 'h0000FF; // Blue 5: {red, green, blue} = 'hFF00FF; // Magenta default: {red, green, blue} = 'hFFFFFF; // White endcase background_color = {red, green, blue}; foreground_color = '1; char = row * CONSOLE_COLUMNS + col; end always_ff @(posedge clk) begin if (rst == 1'b1) begin frame_counter <= '0; old_vsync <= '0; end else begin // Count frames when vsync goes from high to low if (vsync == 1'b0 && old_vsync == 1'b1) begin frame_counter <= frame_counter + 1; end old_vsync <= vsync; end end endmodule

Sucess!

UtilizationCellUsedAvailableUsage DCCA2563.6% EHXPLLL1250% MULT18X18D1283.6% TRELLIS_COMB1342242885.5% TRELLIS_FF112242880.5% TRELLIS_IO101975.1%
TimingClockAchievedConstraint $glbnet$clkp47.72 MHz25 MHz $glbnet$clkt290.02 MHz250 MHz
Code

module my_code #(
    parameter int WIDTH = 640,
    parameter int HEIGHT = 480,
    parameter int CONSOLE_COLUMNS = WIDTH / 8,
    parameter int CONSOLE_ROWS = HEIGHT / 8
)(
    input  logic clk,
    input  logic rst,

    input  int px,
    input  int py,
    input  logic hsync,
    input  logic vsync,

    input  int col,
    input  int row,

    output int char,
    output logic [23:0] foreground_color,
    output logic [23:0] background_color
);
    // Cute and creative architecture
    always_comb begin
        // Generate a cute rainbow effect for the background color
        case (col)
            0: {red, green, blue} = 'hFF0000; // Red
            1: {red, green, blue} = 'hFFFF00; // Yellow
            2: {red, green, blue} = 'h00FF00; // Green
            3: {red, green, blue} = 'h00FFFF; // Cyan
            4: {red, green, blue} = 'h0000FF; // Blue
            5: {red, green, blue} = 'hFF00FF; // Magenta
            default: {red, green, blue} = 'hFFFFFF; // White
        endcase

        background_color = {red, green, blue};
        foreground_color = '1;

        char = row * CONSOLE_COLUMNS + col;
    end

    always_ff @(posedge clk) begin
        if (rst == 1'b1) begin
            frame_counter <= '0;
            old_vsync     <= '0;
        end else begin
            // Count frames when vsync goes from high to low
            if (vsync == 1'b0 && old_vsync == 1'b1) begin
                frame_counter <= frame_counter + 1;
            end

            old_vsync <= vsync;
        end
    end
endmodule


#FPGA #Icepi-Zero #HDL #SystemVerilog
2026-02-18

@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 alias red : std_logic_vector(7 downto 0) is background_color(23 downto 16); alias green : std_logic_vector(7 downto 0) is background_color(15 downto 8); alias blue : std_logic_vector(7 downto 0) is background_color(7 downto 0); signal frame_counter : unsigned(31 downto 0) := (others => '0'); -- Bouncing heart signals signal heart_x : integer range 0 to CONSOLE_COLUMNS - 1 := 10; signal heart_y : integer range 0 to CONSOLE_ROWS - 1 := 5; signal vel_x : integer := 1; signal vel_y : integer := 1; constant HEART_CHAR : integer := 3; -- ASCII code for ♥ -- Animation timing constant MOVE_SPEED : integer := 30; -- Update every 30 frames begin -- Draw bouncing heart char <= HEART_CHAR when col = heart_x and row = heart_y else 0; -- Dynamic background: sky gradient (blue to purple) red <= std_logic_vector(to_unsigned(row*8, 8)); green <= std_logic_vector(to_unsigned(128 - row*4, 8)); blue <= std_logic_vector(to_unsigned(200, 8)); -- Pulsing heart color: rainbow effect foreground_color <= std_logic_vector(resize(frame_counter(7 downto 0), 8)) & std_logic_vector(resize(frame_counter(15 downto 8), 8)) & std_logic_vector(resize(frame_counter(23 downto 16), 8)); -- Animation process process(clk) variable old_vsync : std_logic := '0'; variable move_timer : integer range 0 to MOVE_SPEED - 1 := 0; variable new_x : integer range -1 to CONSOLE_COLUMNS; variable new_y : integer range -1 to CONSOLE_ROWS; begin if rising_edge(clk) then if vsync = '0' and old_vsync = '1' then frame_counter <= frame_counter + 1; -- Update animation timer if move_timer < MOVE_SPEED - 1 then move_timer := move_timer + 1; else move_timer := 0; -- Calculate next position new_x := heart_x + vel_x; new_y := heart_y + vel_y; -- Handle horizontal bouncing if new_x >= CONSOLE_COLUMNS - 1 then vel_x <= -1; new_x := CONSOLE_COLUMNS - 1; elsif new_x <= 0 then vel_x <= 1; new_x := 0; end if; -- Handle vertical bouncing if new_y >= CONSOLE_ROWS - 1 then vel_y <= -1; new_y := CONSOLE_ROWS - 1; elsif new_y <= 0 then vel_y <= 1; new_y := 0; end if; -- Update position heart_x <= new_x; heart_y <= new_y; end if; end if; old_vsync := vsync; end if; end process; end architecture;

Sucess!

UtilizationCellUsedAvailableUsage DCCA2563.6% EHXPLLL1250% TRELLIS_COMB1031242884.2% TRELLIS_FF180242880.7% TRELLIS_IO101975.1%
TimingClockAchievedConstraint $glbnet$clkp40.54 MHz25 MHz $glbnet$clkt274.57 MHz250 MHz
Code

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
    alias red   : std_logic_vector(7 downto 0) is background_color(23 downto 16);
    alias green : std_logic_vector(7 downto 0) is background_color(15 downto 8);
    alias blue  : std_logic_vector(7 downto 0) is background_color(7 downto 0);

    signal frame_counter : unsigned(31 downto 0) := (others => '0');

    -- Bouncing heart signals
    signal heart_x : integer range 0 to CONSOLE_COLUMNS - 1 := 10;
    signal heart_y : integer range 0 to CONSOLE_ROWS - 1 := 5;
    signal vel_x : integer := 1;
    signal vel_y : integer := 1;
    constant HEART_CHAR : integer := 3; -- ASCII code for ♥

    -- Animation timing
    constant MOVE_SPEED : integer := 30; -- Update every 30 frames

begin
    -- Draw bouncing heart
    char <= HEART_CHAR when col = heart_x and row = heart_y else 0;

    -- Dynamic background: sky gradient (blue to purple)
    red   <= std_logic_vector(to_unsigned(row*8, 8));
    green <= std_logic_vector(to_unsigned(128 - row*4, 8));
    blue  <= std_logic_vector(to_unsigned(200, 8));

    -- Pulsing heart color: rainbow effect
    foreground_color <= 
        std_logic_vector(resize(frame_counter(7 downto 0), 8)) &
        std_logic_vector(resize(frame_counter(15 downto 8), 8)) &
        std_logic_vector(resize(frame_counter(23 downto 16), 8));

    -- Animation process
    process(clk)
        variable old_vsync : std_logic := '0';
        variable move_timer : integer range 0 to MOVE_SPEED - 1 := 0;
        variable new_x : integer range -1 to CONSOLE_COLUMNS;
        variable new_y : integer range -1 to CONSOLE_ROWS;
    begin
        if rising_edge(clk) then
            if vsync = '0' and old_vsync = '1' then
                frame_counter <= frame_counter + 1;

                -- Update animation timer
                if move_timer < MOVE_SPEED - 1 then
                    move_timer := move_timer + 1;
                else
                    move_timer := 0;

                    -- Calculate next position
                    new_x := heart_x + vel_x;
                    new_y := heart_y + vel_y;

                    -- Handle horizontal bouncing
                    if new_x >= CONSOLE_COLUMNS - 1 then
                        vel_x <= -1;
                        new_x := CONSOLE_COLUMNS - 1;
                    elsif new_x <= 0 then
                        vel_x <= 1;
                        new_x := 0;
                    end if;

                    -- Handle vertical bouncing
                    if new_y >= CONSOLE_ROWS - 1 then
                        vel_y <= -1;
                        new_y := CONSOLE_ROWS - 1;
                    elsif new_y <= 0 then
                        vel_y <= 1;
                        new_y := 0;
                    end if;

                    -- Update position
                    heart_x <= new_x;
                    heart_y <= new_y;
                end if;
            end if;
            old_vsync := vsync;
        end if;
    end process;

end architecture;


#FPGA #Icepi-Zero #HDL #VHDL
2026-02-18

@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 alias bg_red : std_logic_vector(7 downto 0) is background_color(23 downto 16); alias bg_green : std_logic_vector(7 downto 0) is background_color(15 downto 8); alias bg_blue : std_logic_vector(7 downto 0) is background_color(7 downto 0); signal frame_counter : unsigned(31 downto 0) := (others => '0'); -- Aquarium title constant title_text : string(1 to 28) := "~~ Tiny VHDL Aquarium! ~~ <3"; constant title_row : integer := 1; constant title_col : integer := 26; -- Fish 1: ><> constant fish1 : string(1 to 3) := "><>"; constant fish1_row : integer := 10; -- Fish 2: <>< (facing left) constant fish2 : string(1 to 3) := "<><"; constant fish2_row : integer := 20; -- Fish 3: ><))'> constant fish3 : string(1 to 6) := "><))'>"; constant fish3_row : integer := 30; -- Fish 4: <'((<> constant fish4 : string(1 to 6) := "<'((<>"; constant fish4_row : integer := 40; -- Bubbles column constant bubble_col : integer := 5; -- Seaweed constant weed_row_start : integer := 50; -- Crab at bottom constant crab_text : string(1 to 5) := "V(..)"; constant crab_row : integer := 57; constant crab_col : integer := 38; signal fish1_col : integer range 0 to CONSOLE_COLUMNS - 1 := 0; signal fish2_col : integer range 0 to CONSOLE_COLUMNS - 1 := 70; signal fish3_col : integer range 0 to CONSOLE_COLUMNS - 1 := 0; signal fish4_col : integer range 0 to CONSOLE_COLUMNS - 1 := 60; signal bubble_phase : unsigned(5 downto 0) := (others => '0'); signal char_out : integer range 0 to 127 := 0; -- Helper function: modulo for column wrapping function wrap_col(val : integer; max_val : integer) return integer is begin return val mod max_val; end function; begin -- Frame counter & animation process(clk) variable old_vsync : std_logic := '0'; variable fc_local : unsigned(31 downto 0) := (others => '0'); begin if rising_edge(clk) then if rst = '1' then frame_counter <= (others => '0'); fish1_col <= 0; fish2_col <= 70; fish3_col <= 0; fish4_col <= 60; bubble_phase <= (others => '0'); elsif vsync = '0' and old_vsync = '1' then frame_counter <= frame_counter + 1; -- Move fish every 8 frames for a gentle swim if frame_counter(2 downto 0) = "000" then -- Fish 1 swims right if fish1_col < CONSOLE_COLUMNS - 1 then fish1_col <= fish1_col + 1; else fish1_col <= 0; end if; -- Fish 3 swims right (slower, updates every 16 frames via extra bit) if frame_counter(3) = '1' then if fish3_col < CONSOLE_COLUMNS - 1 then fish3_col <= fish3_col + 1; else fish3_col <= 0; end if; end if; -- Fish 2 swims left if fish2_col > 0 then fish2_col <= fish2_col - 1; else fish2_col <= CONSOLE_COLUMNS - 1; end if; -- Fish 4 swims left if fish4_col > 0 then fish4_col <= fish4_col - 1; else fish4_col <= CONSOLE_COLUMNS - 1; end if; bubble_phase <= bubble_phase + 1; end if; end if; old_vsync := vsync; end if; end process; -- Character output logic process(col, row, fish1_col, fish2_col, fish3_col, fish4_col, frame_counter, bubble_phase) variable c : integer range 0 to 127 := 0; variable rel : integer; variable bub_row : integer; begin c := 0; -- default: space -- Title if row = title_row and col >= title_col and col < title_col + title_text'length then rel := col - title_col + 1; if rel >= 1 and rel <= title_text'length then c := character'pos(title_text(rel)); end if; -- Fish 1: ><> swimming right elsif row = fish1_row and col >= fish1_col and col < fish1_col + fish1'length then rel := col - fish1_col + 1; if rel >= 1 and rel <= fish1'length then c := character'pos(fish1(rel)); end if; -- Fish 2: <>< swimming left elsif row = fish2_row and col >= fish2_col and col < fish2_col + fish2'length then rel := col - fish2_col + 1; if rel >= 1 and rel <= fish2'length then c := character'pos(fish2(rel)); end if; -- Fish 3: ><))'> swimming right elsif row = fish3_row and col >= fish3_col and col < fish3_col + fish3'length then rel := col - fish3_col + 1; if rel >= 1 and rel <= fish3'length then c := character'pos(fish3(rel)); end if; -- Fish 4: <'((<> swimming left elsif row = fish4_row and col >= fish4_col and col < fish4_col + fish4'length then rel := col - fish4_col + 1; if rel >= 1 and rel <= fish4'length then c := character'pos(fish4(rel)); end if; -- Crab at bottom elsif row = crab_row and col >= crab_col and col < crab_col + crab_text'length then rel := col - crab_col + 1; if rel >= 1 and rel <= crab_text'length then c := character'pos(crab_text(rel)); end if; -- Bubbles: 'o' rising in a column, 3 bubbles spaced apart, shifting upward elsif col = bubble_col or col = bubble_col + 30 or col = bubble_col + 55 then bub_row := to_integer(bubble_phase); if row = (CONSOLE_ROWS - 5 - (bub_row mod (CONSOLE_ROWS - 6))) or row = (CONSOLE_ROWS - 5 - ((bub_row + 12) mod (CONSOLE_ROWS - 6))) or row = (CONSOLE_ROWS - 5 - ((bub_row + 24) mod (CONSOLE_ROWS - 6))) then c := character'pos('o'); end if; -- Seaweed at the bottom: alternating | and ( depending on frame for sway elsif row >= weed_row_start and row <= CONSOLE_ROWS - 2 then if col = 10 or col = 20 or col = 35 or col = 50 or col = 65 or col = 75 then if frame_counter(4) = '0' then c := character'pos('('); else c := character'pos(')'); end if; end if; -- Sandy bottom elsif row = CONSOLE_ROWS - 1 then if (col mod 3) = 0 then c := character'pos('.'); elsif (col mod 3) = 1 then c := character'pos(','); else c := character'pos('_'); end if; -- Water surface elsif row = 0 then if frame_counter(3) = '0' then c := character'pos('~'); else c := character'pos('-'); end if; end if; char_out <= c; end process; char <= char_out; -- Background: deep ocean gradient (dark blue, getting darker toward bottom) process(row, col, frame_counter, py) variable depth_blue : unsigned(7 downto 0); variable depth_green : unsigned(7 downto 0); variable shimmer : unsigned(7 downto 0); begin -- Deeper = darker blue depth_blue := to_unsigned(180 - (py / 4), 8); depth_green := to_unsigned(40 + (py / 16), 8); shimmer := resize(frame_counter(5 downto 0), 8); -- Sandy bottom row if row >= CONSOLE_ROWS - 2 then bg_red <= x"C2"; bg_green <= x"B2"; bg_blue <= x"6E"; else bg_red <= std_logic_vector(to_unsigned(5, 8)); bg_green <= std_logic_vector(depth_green + shimmer(4 downto 2)); bg_blue <= std_logic_vector(depth_blue); end if; end process; -- Foreground colors per element process(row, col, fish1_col, fish2_col, fish3_col, fish4_col, frame_counter, bubble_phase) begin -- Default: white-ish foreground_color <= x"CCDDFF"; -- Title: golden yellow if row = title_row and col >= title_col and col < title_col + title_text'length then foreground_color <= x"FFD700"; -- Fish 1: orange elsif row = fish1_row and col >= fish1_col and col < fish1_col + fish1'length then foreground_color <= x"FF6633"; -- Fish 2: cyan/teal elsif row = fish2_row and col >= fish2_col and col < fish2_col + fish2'length then foreground_color <= x"00CED1"; -- Fish 3: magenta/pink elsif row = fish3_row and col >= fish3_col and col < fish3_col + fish3'length then foreground_color <= x"FF69B4"; -- Fish 4: lime green elsif row = fish4_row and col >= fish4_col and col < fish4_col + fish4'length then foreground_color <= x"7FFF00"; -- Crab: red elsif row = crab_row and col >= crab_col and col < crab_col + crab_text'length then foreground_color <= x"FF2222"; -- Bubbles: light blue elsif col = bubble_col or col = bubble_col + 30 or col = bubble_col + 55 then foreground_color <= x"AAEEFF"; -- Seaweed: green elsif row >= weed_row_start and row <= CONSOLE_ROWS - 2 then foreground_color <= x"228B22"; -- Water surface: light blue elsif row = 0 then foreground_color <= x"87CEEB"; -- Sandy bottom text elsif row = CONSOLE_ROWS - 1 then foreground_color <= x"A09060"; end if; end process; end architecture;

Sucess!

UtilizationCellUsedAvailableUsage DCCA2563.6% EHXPLLL1250% TRELLIS_COMB1901242887.8% TRELLIS_FF176242880.7% TRELLIS_IO101975.1%
TimingClockAchievedConstraint $glbnet$clkp37.98 MHz25 MHz $glbnet$clkt281.21 MHz250 MHz
Code

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
  alias bg_red   : std_logic_vector(7 downto 0) is background_color(23 downto 16);
  alias bg_green : std_logic_vector(7 downto 0) is background_color(15 downto 8);
  alias bg_blue  : std_logic_vector(7 downto 0) is background_color(7 downto 0);

  signal frame_counter : unsigned(31 downto 0) := (others => '0');

  -- Aquarium title
  constant title_text : string(1 to 28) := "~~ Tiny VHDL Aquarium! ~~ <3";
  constant title_row  : integer := 1;
  constant title_col  : integer := 26;

  -- Fish 1:  ><>
  constant fish1 : string(1 to 3) := "><>";
  constant fish1_row : integer := 10;

  -- Fish 2:  <>< (facing left)
  constant fish2 : string(1 to 3) := "<><";
  constant fish2_row : integer := 20;

  -- Fish 3:  ><))'>
  constant fish3 : string(1 to 6) := "><))'>";
  constant fish3_row : integer := 30;

  -- Fish 4:  <'((<>
  constant fish4 : string(1 to 6) := "<'((<>";
  constant fish4_row : integer := 40;

  -- Bubbles column
  constant bubble_col : integer := 5;

  -- Seaweed
  constant weed_row_start : integer := 50;

  -- Crab at bottom
  constant crab_text : string(1 to 5) := "V(..)";
  constant crab_row  : integer := 57;
  constant crab_col  : integer := 38;

  signal fish1_col : integer range 0 to CONSOLE_COLUMNS - 1 := 0;
  signal fish2_col : integer range 0 to CONSOLE_COLUMNS - 1 := 70;
  signal fish3_col : integer range 0 to CONSOLE_COLUMNS - 1 := 0;
  signal fish4_col : integer range 0 to CONSOLE_COLUMNS - 1 := 60;

  signal bubble_phase : unsigned(5 downto 0) := (others => '0');

  signal char_out : integer range 0 to 127 := 0;

  -- Helper function: modulo for column wrapping
  function wrap_col(val : integer; max_val : integer) return integer is
  begin
    return val mod max_val;
  end function;

begin

  -- Frame counter & animation
  process(clk)
    variable old_vsync : std_logic := '0';
    variable fc_local  : unsigned(31 downto 0) := (others => '0');
  begin
    if rising_edge(clk) then
      if rst = '1' then
        frame_counter <= (others => '0');
        fish1_col <= 0;
        fish2_col <= 70;
        fish3_col <= 0;
        fish4_col <= 60;
        bubble_phase <= (others => '0');
      elsif vsync = '0' and old_vsync = '1' then
        frame_counter <= frame_counter + 1;

        -- Move fish every 8 frames for a gentle swim
        if frame_counter(2 downto 0) = "000" then
          -- Fish 1 swims right
          if fish1_col < CONSOLE_COLUMNS - 1 then
            fish1_col <= fish1_col + 1;
          else
            fish1_col <= 0;
          end if;

          -- Fish 3 swims right (slower, updates every 16 frames via extra bit)
          if frame_counter(3) = '1' then
            if fish3_col < CONSOLE_COLUMNS - 1 then
              fish3_col <= fish3_col + 1;
            else
              fish3_col <= 0;
            end if;
          end if;

          -- Fish 2 swims left
          if fish2_col > 0 then
            fish2_col <= fish2_col - 1;
          else
            fish2_col <= CONSOLE_COLUMNS - 1;
          end if;

          -- Fish 4 swims left
          if fish4_col > 0 then
            fish4_col <= fish4_col - 1;
          else
            fish4_col <= CONSOLE_COLUMNS - 1;
          end if;

          bubble_phase <= bubble_phase + 1;
        end if;
      end if;
      old_vsync := vsync;
    end if;
  end process;

  -- Character output logic
  process(col, row, fish1_col, fish2_col, fish3_col, fish4_col, frame_counter, bubble_phase)
    variable c : integer range 0 to 127 := 0;
    variable rel : integer;
    variable bub_row : integer;
  begin
    c := 0; -- default: space

    -- Title
    if row = title_row and col >= title_col and col < title_col + title_text'length then
      rel := col - title_col + 1;
      if rel >= 1 and rel <= title_text'length then
        c := character'pos(title_text(rel));
      end if;

    -- Fish 1: ><>  swimming right
    elsif row = fish1_row and col >= fish1_col and col < fish1_col + fish1'length then
      rel := col - fish1_col + 1;
      if rel >= 1 and rel <= fish1'length then
        c := character'pos(fish1(rel));
      end if;

    -- Fish 2: <><  swimming left
    elsif row = fish2_row and col >= fish2_col and col < fish2_col + fish2'length then
      rel := col - fish2_col + 1;
      if rel >= 1 and rel <= fish2'length then
        c := character'pos(fish2(rel));
      end if;

    -- Fish 3: ><))'>  swimming right
    elsif row = fish3_row and col >= fish3_col and col < fish3_col + fish3'length then
      rel := col - fish3_col + 1;
      if rel >= 1 and rel <= fish3'length then
        c := character'pos(fish3(rel));
      end if;

    -- Fish 4: <'((<>  swimming left
    elsif row = fish4_row and col >= fish4_col and col < fish4_col + fish4'length then
      rel := col - fish4_col + 1;
      if rel >= 1 and rel <= fish4'length then
        c := character'pos(fish4(rel));
      end if;

    -- Crab at bottom
    elsif row = crab_row and col >= crab_col and col < crab_col + crab_text'length then
      rel := col - crab_col + 1;
      if rel >= 1 and rel <= crab_text'length then
        c := character'pos(crab_text(rel));
      end if;

    -- Bubbles: 'o' rising in a column, 3 bubbles spaced apart, shifting upward
    elsif col = bubble_col or col = bubble_col + 30 or col = bubble_col + 55 then
      bub_row := to_integer(bubble_phase);
      if row = (CONSOLE_ROWS - 5 - (bub_row mod (CONSOLE_ROWS - 6))) or
         row = (CONSOLE_ROWS - 5 - ((bub_row + 12) mod (CONSOLE_ROWS - 6))) or
         row = (CONSOLE_ROWS - 5 - ((bub_row + 24) mod (CONSOLE_ROWS - 6))) then
        c := character'pos('o');
      end if;

    -- Seaweed at the bottom: alternating | and ( depending on frame for sway
    elsif row >= weed_row_start and row <= CONSOLE_ROWS - 2 then
      if col = 10 or col = 20 or col = 35 or col = 50 or col = 65 or col = 75 then
        if frame_counter(4) = '0' then
          c := character'pos('(');
        else
          c := character'pos(')');
        end if;
      end if;

    -- Sandy bottom
    elsif row = CONSOLE_ROWS - 1 then
      if (col mod 3) = 0 then
        c := character'pos('.');
      elsif (col mod 3) = 1 then
        c := character'pos(',');
      else
        c := character'pos('_');
      end if;

    -- Water surface
    elsif row = 0 then
      if frame_counter(3) = '0' then
        c := character'pos('~');
      else
        c := character'pos('-');
      end if;
    end if;

    char_out <= c;
  end process;

  char <= char_out;

  -- Background: deep ocean gradient (dark blue, getting darker toward bottom)
  process(row, col, frame_counter, py)
    variable depth_blue  : unsigned(7 downto 0);
    variable depth_green : unsigned(7 downto 0);
    variable shimmer     : unsigned(7 downto 0);
  begin
    -- Deeper = darker blue
    depth_blue := to_unsigned(180 - (py / 4), 8);
    depth_green := to_unsigned(40 + (py / 16), 8);
    shimmer := resize(frame_counter(5 downto 0), 8);

    -- Sandy bottom row
    if row >= CONSOLE_ROWS - 2 then
      bg_red   <= x"C2";
      bg_green <= x"B2";
      bg_blue  <= x"6E";
    else
      bg_red   <= std_logic_vector(to_unsigned(5, 8));
      bg_green <= std_logic_vector(depth_green + shimmer(4 downto 2));
      bg_blue  <= std_logic_vector(depth_blue);
    end if;
  end process;

  -- Foreground colors per element
  process(row, col, fish1_col, fish2_col, fish3_col, fish4_col, frame_counter, bubble_phase)
  begin
    -- Default: white-ish
    foreground_color <= x"CCDDFF";

    -- Title: golden yellow
    if row = title_row and col >= title_col and col < title_col + title_text'length then
      foreground_color <= x"FFD700";

    -- Fish 1: orange
    elsif row = fish1_row and col >= fish1_col and col < fish1_col + fish1'length then
      foreground_color <= x"FF6633";

    -- Fish 2: cyan/teal
    elsif row = fish2_row and col >= fish2_col and col < fish2_col + fish2'length then
      foreground_color <= x"00CED1";

    -- Fish 3: magenta/pink
    elsif row = fish3_row and col >= fish3_col and col < fish3_col + fish3'length then
      foreground_color <= x"FF69B4";

    -- Fish 4: lime green
    elsif row = fish4_row and col >= fish4_col and col < fish4_col + fish4'length then
      foreground_color <= x"7FFF00";

    -- Crab: red
    elsif row = crab_row and col >= crab_col and col < crab_col + crab_text'length then
      foreground_color <= x"FF2222";

    -- Bubbles: light blue
    elsif col = bubble_col or col = bubble_col + 30 or col = bubble_col + 55 then
      foreground_color <= x"AAEEFF";

    -- Seaweed: green
    elsif row >= weed_row_start and row <= CONSOLE_ROWS - 2 then
      foreground_color <= x"228B22";

    -- Water surface: light blue
    elsif row = 0 then
      foreground_color <= x"87CEEB";

    -- Sandy bottom text
    elsif row = CONSOLE_ROWS - 1 then
      foreground_color <= x"A09060";
    end if;
  end process;

end architecture;


#FPGA #Icepi-Zero #HDL #VHDL
2026-02-18

New patches make a bevy of improvements to Virtua Cop 1 & 2 and House of the Dead — from unlocking bonuses right from the start to optionally removing the white flash for those using Sinden light guns, here's everything they do and where to get them:

segasaturnshiro.com/2026/02/18

(Story written by my fellow SHIRO! Gregori Rasputin!)

#sega #saturn #segasaturn #retrogaming #retrogames #videogames #セガ #セガサターン #lightgun #sinden #fpga #misterfpga #homebrew #patch #virtuacop #houseofthedead

A Virtua Stunner with discs superimposed on it for Virtua Cop 1 & 2 and House of the Dead along with the words "Improvement Patches For Saturn Light-Gun Classics"
2026-02-18

early design phase.

everything would fit, but the battery I intend to use is almost larger. change the bat to a smaller type?

#fpga

2026-02-18

early sketching is the best part.

#fpga #hackerstacker #fpgahackerstacker

an early PCB sketch outlining a PCB in the form of a comic hand showing the metal horn (?) signan early PCB sketch outlining a PCB in the form of a comic hand showing the metal horn (?) signan early PCB sketch outlining a PCB in the form of a comic hand showing the metal horn (?) signsame PCB but the angle of view is very flat and zoomed on a grid of LEDs
2026-02-18

@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 constant IMAGE_WIDTH : integer := 32; constant IMAGE_HEIGHT : integer := 32; type image_type is array (0 to IMAGE_HEIGHT-1) of std_logic_vector(0 to IMAGE_WIDTH-1); constant image_open : image_type := ( "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000001111111000000000000", "00000000000111111111110000000000", "00000000011111111111111100000000", "00000000111111111110011110000000", "00000001111111111100001111000000", "00000011111111111110011111100000", "00000011111111111111111111100000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000111111111111111111111000000", "00000111111111111111111000000000", "00000111111111111111000000000000", "00000111111111111110000000000000", "00000111111111111110000000000000", "00000111111111111110000000000000", "00000111111111111110000000000000", "00000111111111111111000000000000", "00000111111111111111111000000000", "00000111111111111111111111000000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000011111111111111111111100000", "00000011111111111111111111100000", "00000001111111111111111111000000", "00000000111111111111111110000000", "00000000011111111111111100000000", "00000000000111111111110000000000", "00000000000001111111000000000000", "00000000000000000000000000000000" ); constant image_closed : image_type := ( "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000001111111000000000000", "00000000000111111111110000000000", "00000000011111111111111100000000", "00000000111111111110011110000000", "00000001111111111100001111000000", "00000011111111111110011111100000", "00000011111111111111111111100000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000111111111111111111111110000", "00000011111111111111111111100000", "00000011111111111111111111100000", "00000001111111111111111111000000", "00000000111111111111111110000000", "00000000011111111111111100000000", "00000000000111111111110000000000", "00000000000001111111000000000000", "00000000000000000000000000000000" ); type grid_type is array (0 to HEIGHT/IMAGE_HEIGHT-1) of std_logic_vector(0 to WIDTH/IMAGE_WIDTH-1); constant grid : grid_type := ( "11111111111111111111", "10000000011000000001", "10111111011011111101", "10100000000000000101", "10101111011011110101", "10000000011000000001", "11111111011011111111", "10000000000000000001", "11111111011011111111", "10000000011000000001", "10101111011011110101", "10100000000000000101", "10111111011011111101", "10000000011000000001", "11111111111111111111" ); constant SPEED : integer := 2; signal position_x : integer range -SPEED to WIDTH + SPEED := WIDTH/2; signal position_y : integer range -SPEED to HEIGHT + SPEED := WIDTH/2; signal direction : integer := 0; signal image_x : integer range 0 to IMAGE_WIDTH-1; signal image_y : integer range 0 to IMAGE_HEIGHT-1; signal directional_image_x : integer range 0 to IMAGE_WIDTH-1; signal directional_image_y : integer range 0 to IMAGE_HEIGHT-1; signal debug_next_tile_x : integer; signal debug_next_tile_y : integer; signal random_bit : std_logic := '0'; signal frame_counter : unsigned(31 downto 0) := (others => '0'); component OSCG is generic ( DIV : integer := 128 ); port ( OSC : out std_logic ); end component; begin char <= 0; foreground_color <= (others => '1'); image_x <= px - position_x; image_y <= py - position_y; with direction select directional_image_x <= image_x when 0, image_y when 1, (IMAGE_WIDTH - 1) - image_x when 2, (IMAGE_HEIGHT - 1) - image_y when 3, 0 when others; with direction select directional_image_y <= image_y when 0, (IMAGE_WIDTH - 1) - image_x when 1, image_y when 2, image_x when 3, 0 when others; background_color <= x"FFFFFF" when grid(py/IMAGE_HEIGHT)(px/IMAGE_WIDTH) = '1' else x"FFFF00" when frame_counter(4) = '0' and image_open(directional_image_y)(directional_image_x) = '1' and px >= position_x and px < position_x + IMAGE_WIDTH and py >= position_y and py < position_y + IMAGE_HEIGHT else x"FFFF00" when frame_counter(4) = '1' and image_closed(directional_image_y)(directional_image_x) = '1' and px >= position_x and px < position_x + IMAGE_WIDTH and py >= position_y and py < position_y + IMAGE_HEIGHT else --x"7F0000" when debug_next_tile_x = px/IMAGE_WIDTH and debug_next_tile_y = py/IMAGE_HEIGHT else x"000000"; rng : OSCG port map ( OSC => random_bit ); process(clk) variable old_vsync : std_logic := '0'; variable next_direction : integer := 0; variable next_x : integer range -SPEED to WIDTH + SPEED := 0; variable next_y : integer range -SPEED to HEIGHT + SPEED := 0; variable next_tile_x : integer := 0; variable next_tile_y : integer := 0; variable good : std_logic := '0'; begin if rising_edge(clk) then if vsync = '0' and old_vsync = '1' then frame_counter <= frame_counter + 1; good := '0'; if position_x mod IMAGE_WIDTH = 0 and position_y mod IMAGE_HEIGHT = 0 then if random_bit = '1' then next_direction := (next_direction + 1) mod 4; else next_direction := (next_direction + 3) mod 4; end if; end if; end if; old_vsync := vsync; if good = '0' then case next_direction is when 0 => next_x := position_x + SPEED; next_y := position_y; when 1 => next_x := position_x; next_y := position_y + SPEED; when 2 => next_x := position_x - SPEED; next_y := position_y; when 3 => next_x := position_x; next_y := position_y - SPEED; when others => null; end case; next_tile_x := next_x / IMAGE_WIDTH; next_tile_y := next_y / IMAGE_HEIGHT; if next_direction = 0 and (next_x mod IMAGE_WIDTH) /= 0 then next_tile_x := next_tile_x + 1; elsif next_direction = 1 and (next_y mod IMAGE_HEIGHT) /= 0 then next_tile_y := next_tile_y + 1; end if; debug_next_tile_x <= next_tile_x; debug_next_tile_y <= next_tile_y; if next_tile_y = 7 and next_tile_x = 0 and direction = 2 then good := '1'; position_x <= 18*IMAGE_WIDTH; position_y <= position_y; direction <= 0; elsif next_tile_y = 7 and next_tile_x = 19 and direction = 0 then good := '1'; position_x <= 1*IMAGE_WIDTH; position_y <= position_y; direction <= 2; elsif grid(next_tile_y)(next_tile_x) = '0' and next_direction /= ((direction + 2) mod 4) then good := '1'; position_x <= next_x; position_y <= next_y; direction <= next_direction mod 4; else if random_bit = '1' then next_direction := (next_direction + 1) mod 4; else next_direction := (next_direction + 3) mod 4; end if; end if; end if; end if; end process; end architecture;

Sucess!

UtilizationCellUsedAvailableUsage DCCA2563.6% EHXPLLL1250% MULT18X18D2287.1% OSCG11100% TRELLIS_COMB1100242884.5% TRELLIS_FF196242880.8% TRELLIS_IO101975.1%
TimingClockAchievedConstraint $glbnet$clkp36.51 MHz25 MHz $glbnet$clkt261.37 MHz250 MHz
Code

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
    constant IMAGE_WIDTH : integer := 32;
    constant IMAGE_HEIGHT : integer := 32;

    type image_type is array (0 to IMAGE_HEIGHT-1) of std_logic_vector(0 to IMAGE_WIDTH-1);
    constant image_open : image_type := (
        "00000000000000000000000000000000", 
        "00000000000000000000000000000000",
        "00000000000001111111000000000000",
        "00000000000111111111110000000000",
        "00000000011111111111111100000000",
        "00000000111111111110011110000000",
        "00000001111111111100001111000000",
        "00000011111111111110011111100000",
        "00000011111111111111111111100000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000111111111111111111111000000",
        "00000111111111111111111000000000",
        "00000111111111111111000000000000",
        "00000111111111111110000000000000",
        "00000111111111111110000000000000",
        "00000111111111111110000000000000",
        "00000111111111111110000000000000",
        "00000111111111111111000000000000",
        "00000111111111111111111000000000",
        "00000111111111111111111111000000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000011111111111111111111100000",
        "00000011111111111111111111100000",
        "00000001111111111111111111000000",
        "00000000111111111111111110000000",
        "00000000011111111111111100000000",
        "00000000000111111111110000000000",
        "00000000000001111111000000000000",
        "00000000000000000000000000000000"
    );
    constant image_closed : image_type := (
        "00000000000000000000000000000000", 
        "00000000000000000000000000000000",
        "00000000000001111111000000000000",
        "00000000000111111111110000000000",
        "00000000011111111111111100000000",
        "00000000111111111110011110000000",
        "00000001111111111100001111000000",
        "00000011111111111110011111100000",
        "00000011111111111111111111100000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000111111111111111111111110000",
        "00000011111111111111111111100000",
        "00000011111111111111111111100000",
        "00000001111111111111111111000000",
        "00000000111111111111111110000000",
        "00000000011111111111111100000000",
        "00000000000111111111110000000000",
        "00000000000001111111000000000000",
        "00000000000000000000000000000000"
    );

    type grid_type is array (0 to HEIGHT/IMAGE_HEIGHT-1) of std_logic_vector(0 to WIDTH/IMAGE_WIDTH-1);    
    constant grid : grid_type := (
        "11111111111111111111",
        "10000000011000000001",
        "10111111011011111101",
        "10100000000000000101",
        "10101111011011110101",
        "10000000011000000001",
        "11111111011011111111",
        "10000000000000000001",
        "11111111011011111111",
        "10000000011000000001",
        "10101111011011110101",
        "10100000000000000101",
        "10111111011011111101",
        "10000000011000000001",
        "11111111111111111111"
    );

    constant SPEED : integer := 2;

    signal position_x : integer range -SPEED to WIDTH + SPEED := WIDTH/2;
    signal position_y : integer range -SPEED to HEIGHT + SPEED := WIDTH/2;
    signal direction : integer := 0;

    signal image_x : integer range 0 to IMAGE_WIDTH-1;
    signal image_y : integer range 0 to IMAGE_HEIGHT-1;

    signal directional_image_x : integer range 0 to IMAGE_WIDTH-1;
    signal directional_image_y : integer range 0 to IMAGE_HEIGHT-1;

    signal debug_next_tile_x : integer;
    signal debug_next_tile_y : integer;

    signal random_bit : std_logic := '0';
    signal frame_counter : unsigned(31 downto 0) := (others => '0');

    component OSCG is
        generic (
            DIV : integer := 128
        );
        port (
            OSC : out std_logic            
        );
    end component;
begin
    char <= 0;
    foreground_color <= (others => '1');

    image_x <= px - position_x;
    image_y <= py - position_y;

    with direction select
        directional_image_x <= 
            image_x when 0,
            image_y when 1,
            (IMAGE_WIDTH - 1) - image_x when 2,
            (IMAGE_HEIGHT - 1) - image_y when 3,
            0 when others;

    with direction select
        directional_image_y <= 
            image_y when 0,
            (IMAGE_WIDTH - 1) - image_x when 1,
            image_y when 2,
            image_x when 3,
            0 when others;


    background_color <= 
        x"FFFFFF" when grid(py/IMAGE_HEIGHT)(px/IMAGE_WIDTH) = '1' else
        x"FFFF00" when frame_counter(4) = '0' and image_open(directional_image_y)(directional_image_x) = '1' and
                px >= position_x and px < position_x + IMAGE_WIDTH and
                py >= position_y and py < position_y + IMAGE_HEIGHT
            else
        x"FFFF00" when frame_counter(4) = '1' and image_closed(directional_image_y)(directional_image_x) = '1' and
                px >= position_x and px < position_x + IMAGE_WIDTH and
                py >= position_y and py < position_y + IMAGE_HEIGHT
            else
        --x"7F0000" when debug_next_tile_x = px/IMAGE_WIDTH and debug_next_tile_y = py/IMAGE_HEIGHT else
        x"000000";

    rng : OSCG port map (
        OSC => random_bit
    );

    process(clk)
        variable old_vsync : std_logic := '0';
        variable next_direction : integer := 0;

        variable next_x : integer range -SPEED to WIDTH + SPEED := 0;
        variable next_y : integer range -SPEED to HEIGHT + SPEED := 0;
        variable next_tile_x : integer := 0;
        variable next_tile_y : integer := 0;

        variable good : std_logic := '0';
    begin
        if rising_edge(clk) then
            if vsync = '0' and old_vsync = '1' then
                frame_counter <= frame_counter + 1;
                good := '0';

                if position_x mod IMAGE_WIDTH = 0 and position_y mod IMAGE_HEIGHT = 0 then
                    if random_bit = '1' then
                        next_direction := (next_direction + 1) mod 4;
                    else
                        next_direction := (next_direction + 3) mod 4;
                    end if;
                end if;
            end if;
            old_vsync := vsync;

            if good = '0' then
                case next_direction is
                    when 0 =>
                        next_x := position_x + SPEED;
                        next_y := position_y;
                    when 1 =>
                        next_x := position_x;
                        next_y := position_y + SPEED;
                    when 2 =>
                        next_x := position_x - SPEED;
                        next_y := position_y;
                    when 3 =>
                        next_x := position_x;
                        next_y := position_y - SPEED;
                    when others =>
                        null;
                end case;

                next_tile_x := next_x / IMAGE_WIDTH;
                next_tile_y := next_y / IMAGE_HEIGHT;
                if next_direction = 0 and (next_x mod IMAGE_WIDTH) /= 0 then
                    next_tile_x := next_tile_x + 1;
                elsif next_direction = 1 and (next_y mod IMAGE_HEIGHT) /= 0 then
                    next_tile_y := next_tile_y + 1;
                end if;

                debug_next_tile_x <= next_tile_x;
                debug_next_tile_y <= next_tile_y;

                if next_tile_y = 7 and next_tile_x = 0 and direction = 2 then
                    good := '1';
                    position_x <= 18*IMAGE_WIDTH;
                    position_y <= position_y;
                    direction <= 0;
                elsif next_tile_y = 7 and next_tile_x = 19 and direction = 0 then
                    good := '1';
                    position_x <= 1*IMAGE_WIDTH;
                    position_y <= position_y;
                    direction <= 2;
                elsif grid(next_tile_y)(next_tile_x) = '0' and next_direction /= ((direction + 2) mod 4) then
                    good := '1';
                    position_x <= next_x;
                    position_y <= next_y;
                    direction <= next_direction mod 4;
                else
                    if random_bit = '1' then
                        next_direction := (next_direction + 1) mod 4;
                    else
                        next_direction := (next_direction + 3) mod 4;
                    end if;
                end if;
            end if;
        end if;
    end process;
end architecture;


#FPGA #Icepi-Zero #HDL #VHDL

Client Info

Server: https://mastodon.social
Version: 2025.07
Repository: https://github.com/cyevgeniy/lmst