Skip to main content
Icepi Zero Bot

Icepi Zero Bot

@icepi-zero-bot@wafrn.jcm.re

Send me asks with valid VHDL, SystemVerilog, Amaranth, Spade, or Veryl code and I will execute it for you on a real FPGA!

You can send me asks from outside Wafrn by sending me a direct message (private mention) in the following format: "!ask @icepi-zero-bot@wafrn.jcm.re " followed by your code.

If your instance has a character limitation, you can split your code into a thread of multiple direct messages. In this case, first send your code as multiple direct messages without the "!ask" prefix and then respond to the last message with a direct message containing only "!ask @icepi-zero-bot@wafrn.jcm.re". I will recognize the empty ask, fetch the entire thread, and use the entire text (excluding all mentions) as source code.

All successful responses are public and include your submitted code. Only submit code you are happy to share with the world.

For any questions/problems with this bot, please contact @jcm@wafrn.jcm.re or jcm@jcm.re.

Examples / Templates

VHDL
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');

        uart_data : out std_logic_vector(7 downto 0) := (others => '0');
        uart_ready : in std_logic;
        uart_valid : out std_logic := '0'
    );
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');

    constant example_text : string := "Hello Fediverse! <3";
    constant example_text_row : integer := 15;
    constant example_text_col : integer := 15;

    constant uart_text : string := "Hello Fediverse on UART!" & LF;
begin
    char <= character'pos(example_text(col + 1 - example_text_col))
        when col >= example_text_col and col < example_text'length + example_text_col and row = example_text_row else 0;

    red   <= std_logic_vector(to_unsigned(col*4, 8));
    green <= std_logic_vector(to_unsigned(py, 8));
    blue  <= std_logic_vector(resize(frame_counter, 8));

    foreground_color <= (others => '1');

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

        variable uart_counter : integer range uart_text'range := 1;
    begin
        if rising_edge(clk) then
            if vsync = '0' and old_vsync = '1' then
                frame_counter <= frame_counter + 1;
            end if;
            old_vsync := vsync;

            uart_data <= std_logic_vector(to_unsigned(character'pos(uart_text(uart_counter)), 8));
            uart_valid <= '1';
            if uart_ready = '1' and uart_valid = '1' then
                if uart_counter < uart_text'length then
                    uart_counter := uart_counter + 1;
                else
                    uart_counter := 1;
                end if;
            end if;
        end if;
    end process;
end architecture;
SystemVerilog
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,

    output logic [7:0] uart_data,
    input  logic uart_ready,
    output logic uart_valid
);
    logic [31:0] frame_counter = '0;
    logic old_vsync = '0;

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

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

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

        char = 0;

        uart_data = 8'h00;
        uart_valid = 1'b0;
    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
Amaranth
from amaranth import *

class MyCode(Elaboratable):
    def __init__(self, width, height, console_columns, console_rows):
        self.WIDTH = width
        self.HEIGHT = height
        self.CONSOLE_COLUMNS = console_columns
        self.CONSOLE_ROWS = console_rows

        self.px = Signal(signed(32), name="px")
        self.py = Signal(signed(32), name="py")
        self.hsync = Signal(name="hsync")
        self.vsync = Signal(name="vsync")

        self.col = Signal(signed(32), name="col")
        self.row = Signal(signed(32), name="row")

        self.char = Signal(signed(32), name="char")
        self.foreground_color = Signal(24, name="foreground_color")
        self.background_color = Signal(24, name="background_color")

        self.uart_data = Signal(8, name="uart_data")
        self.uart_ready = Signal(name="uart_ready")
        self.uart_valid = Signal(name="uart_valid")

    def elaborate(self, platform):
        m = Module()

        frame_counter = Signal(32)
        old_vsync = Signal()

        red = Signal(8)
        green = Signal(8)
        blue = Signal(8)

        m.d.comb += [
            red.eq(self.col * 4),
            green.eq(self.py),
            blue.eq(frame_counter),

            self.background_color.eq(Cat(blue, green, red)),
            self.foreground_color.eq(0xFFFFFF),
            self.char.eq(0),

            self.uart_data.eq(0x00),
            self.uart_valid.eq(0),
        ]

        m.d.sync += old_vsync.eq(self.vsync)
        with m.If(~self.vsync & old_vsync):
            m.d.sync += frame_counter.eq(frame_counter + 1)

        return m
Spade
#[no_mangle(all)]
entity my_code(
    clk: clock,
    rst: bool,
    px: int<32>,
    py: int<32>,
    hsync: bool,
    vsync: bool,
    col: int<32>,
    row: int<32>,
    char: inv &int<32>,
    foreground_color: inv &uint<24>,
    background_color: inv &uint<24>,
    uart_data: inv &uint<8>,
    uart_ready: bool,
    uart_valid: inv bool,
) {
    set char = &0;
    set foreground_color = &0xFFFFFFu24;
    set background_color = &0xFF7AFFu24;
    set uart_data = &0x00;
    set uart_valid = &false;
}
Veryl
module my_code #(
    param WIDTH: p32 = 640,
    param HEIGHT: p32 = 480,
    param CONSOLE_COLUMNS: p32 = WIDTH / 8,
    param CONSOLE_ROWS: p32 = HEIGHT / 8
) (
    clk: input clock,
    rst: input reset,

    px: input u32,
    py: input u32,
    hsync: input logic,
    vsync: input logic,

    col: input u32,
    row: input u32,

    char: output u32,
    foreground_color: output logic<24>,
    background_color: output logic<24>,

    uart_data: output logic<8>,
    uart_ready: input logic,
    uart_valid: output logic
) {
    var frame_counter: u32;
    var old_vsync: logic;

    var red: logic<8>;
    var green: logic<8>;
    var blue: logic<8>;

    always_comb {
        red   = (col * 4) as u8;
        green = py as u8;
        blue  = frame_counter as u8;

        background_color = {red, green, blue};
        foreground_color = 24'hff_ff_ff;

        char = 0;
        if(row == 10) {
            if(col == 5) { char = 8'h56; }
            if(col == 6) { char = 8'h65; }
            if(col == 7) { char = 8'h72; }
            if(col == 8) { char = 8'h79; }
            if(col == 9) { char = 8'h6c; }
        }

        uart_data = 0;
        uart_valid = 0;
    }

    always_ff (clk, rst) {
        if_reset {
            frame_counter = 0;
            old_vsync = 0;
        } else {
            if(!vsync && old_vsync) {
                frame_counter = frame_counter + 1;
            }
            old_vsync = vsync;
        }
    }
}

You need to keep the same entity name and interface (generics and ports) as in the examples or the synthesis won't work!

JCM

JCM

@jcm@wafrn.jcm.re

Hello World!

I am a Computer Engineering student in Berlin and do low-level programming, cursed C++ projects, FPGA stuff, and self-hosting in my free time :3

I absolutely love and adore my cute girlfriend @xcyndi.bsky.social!

I like modern C++, Vulkan, WebAssembly, VHDL, FPGAs, SBCs, Kubernetes, game modding, Ganqing Impact, and Cyberpunk 2077.

That's all folks...