DEV Community

Javad
Javad

Posted on

Stranger Things #1: VHDL wrotes GTN (Guess The Number)?? WTF!

Hello, hardware enthusiasts and developers! Today, we’re diving into a project that blends the rigorous world of hardware design with a dash of whimsical humor. Welcome to GTN (Guess The Number), a strange VHDL project that will keep you guessing—literally! Built with VHDL, one of the most industrial and challenging Hardware Description Languages (HDLs), GTN combines seriousness with fun, resulting in a quirky system that plays mind games with you. Let’s explore this "Stranger Things" style project!

What is GTN?

GTN is a hardware system that, when initialized, displays a number and asks you to guess what that number was. But here’s the twist:

  • If you guess correctly, it says, "No! It was wrong," shows you a false number (just to mess with you), and restarts.
  • If you guess incorrectly, it says, "No, it was wrong," and displays the real number it originally showed, adding a bit of pressure (LOL).

It’s all in good fun, designed to poke fun at perfectionism in hardware design and bring a smile to your face. Now, let’s get into the technical details!

VHDL Source Code

We’ll provide two versions of the code: one for emulation (simulation) and one for FPGA/ASIC boards. The core logic is similar, but I/O handling differs based on the target.

Version 1: Emulation Version

This version is designed for simulation in tools like ModelSim or GHDL. It uses standard logic signals for input and output. Below is the VHDL code for the entity and architecture.

-- GTN_Emulate.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity GTN_Emulate is
    Port (
        clk            : in  STD_LOGIC;
        reset          : in  STD_LOGIC;
        guess          : in  STD_LOGIC_VECTOR (7 downto 0);  -- 8-bit guess input
        number_display : out STD_LOGIC_VECTOR (7 downto 0);  -- 8-bit number display
        response       : out STD_LOGIC_VECTOR (1 downto 0)   -- "00": init, "01": correct guess (false response), "10": incorrect guess
    );
end GTN_Emulate;

architecture Behavioral of GTN_Emulate is
    signal internal_number : STD_LOGIC_VECTOR (7 downto 0) := (others => '0');
    signal displayed_number : STD_LOGIC_VECTOR (7 downto 0) := (others => '0');
    signal state : integer range 0 to 2 := 0;  -- 0: init, 1: wait for guess, 2: respond
    signal fake_number : STD_LOGIC_VECTOR (7 downto 0) := (others => '0');
begin
    process (clk, reset)
        variable seed : integer := 123456789;  -- Simple seed for pseudo-random number
    begin
        if reset = '1' then
            internal_number   <= (others => '0');
            displayed_number  <= (others => '0');
            fake_number       <= (others => '0');
            state             <= 0;
            response          <= "00";
        elsif rising_edge(clk) then
            case state is
                when 0 =>
                    -- Initialize: generate a "random" number
                    seed := seed + 1;
                    internal_number  <= std_logic_vector(to_unsigned(seed mod 256, 8));
                    displayed_number <= internal_number;  -- Display real number
                    response         <= "00";              -- Init state
                    state            <= 1;

                when 1 =>
                    -- Wait for guess input (assume guess is stable in simulation)
                    if guess = internal_number then
                        -- Correct guess: show fake number (real number + 1)
                        fake_number       <= std_logic_vector(unsigned(internal_number) + 1);
                        displayed_number  <= fake_number;
                        response          <= "01";          -- Correct guess, but false response
                    else
                        -- Incorrect guess: show real number
                        displayed_number  <= internal_number;
                        response          <= "10";          -- Incorrect guess
                    end if;
                    state <= 2;

                when 2 =>
                    -- Respond and restart after one clock cycle
                    state <= 0;
            end case;
        end if;
    end process;

    number_display <= displayed_number;
end Behavioral;
Enter fullscreen mode Exit fullscreen mode

Testbench for Emulation

To simulate the design, here’s a simple testbench:

-- GTN_Emulate_tb.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity GTN_Emulate_tb is
end GTN_Emulate_tb;

architecture sim of GTN_Emulate_tb is
    signal clk            : STD_LOGIC := '0';
    signal reset          : STD_LOGIC := '0';
    signal guess          : STD_LOGIC_VECTOR (7 downto 0) := (others => '0');
    signal number_display : STD_LOGIC_VECTOR (7 downto 0);
    signal response       : STD_LOGIC_VECTOR (1 downto 0);

    constant clk_period : time := 10 ns;
begin
    uut: entity work.GTN_Emulate
        port map (
            clk            => clk,
            reset          => reset,
            guess          => guess,
            number_display => number_display,
            response       => response
        );

    clk_process: process
    begin
        clk <= '0';
        wait for clk_period/2;
        clk <= '1';
        wait for clk_period/2;
    end process;

    stimulus: process
begin
    -- Reset the system
    reset <= '1';
    wait for 20 ns;
    reset <= '0';
    wait for 20 ns;

    -- Let system initialize and display a number
    wait until rising_edge(clk);
    wait for clk_period;

    -- Guess correctly (match the displayed number)
    guess <= number_display;
    wait for clk_period * 2;
    report "No!! Your wrong! The number was = " &
           integer'image(to_integer(unsigned(number_display))) &
           " But you wrote = " &
           integer'image(to_integer(unsigned(guess)));

    -- Guess incorrectly (add 5 to the displayed number)
    guess <= std_logic_vector(unsigned(number_display) + 5);
    wait for clk_period * 2;
    report "You wrote wrong again! The number was = " &
           integer'image(to_integer(unsigned(number_display))) &
           " but you wrote = " &
           integer'image(to_integer(unsigned(guess)));

    wait for 100 ns;
    assert false report "Simulation finished. Are you really think you can win? LOL" severity failure;
end process;
end sim;
Enter fullscreen mode Exit fullscreen mode

Just change the fake_number <= std_logic_vector(unsigned(internal_number) + YOUR_NUMBER_HERE); in GTN_Emulate, then you can see the result! (Because of limitions of HDL Languages (Not only VHDL, all of them), we can't input straight to user, and the users must change it from source code, but in real FPGA/ASIC Boards are easier!)

Version 2: FPGA/ASIC Board Version

This version is tailored for physical implementation, with inputs from switches and buttons, and outputs to LEDs. It includes button debouncing for reliability.

-- GTN_FPGA.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity GTN_FPGA is
    Port (
        clk            : in  STD_LOGIC;                     -- Board clock (e.g., 100 MHz)
        reset          : in  STD_LOGIC;                     -- Reset button
        guess_switches : in  STD_LOGIC_VECTOR (7 downto 0); -- 8 switches for guess input
        submit_button  : in  STD_LOGIC;                     -- Button to submit guess
        leds           : out STD_LOGIC_VECTOR (7 downto 0); -- 8 LEDs to display number
        response_led   : out STD_LOGIC_VECTOR (1 downto 0)  -- Additional LEDs for response feedback
    );
end GTN_FPGA;

architecture Behavioral of GTN_FPGA is
    signal internal_number : STD_LOGIC_VECTOR (7 downto 0) := (others => '0');
    signal displayed_number : STD_LOGIC_VECTOR (7 downto 0) := (others => '0');
    signal state : integer range 0 to 2 := 0;
    signal button_debounced : STD_LOGIC := '0';
    signal fake_number : STD_LOGIC_VECTOR (7 downto 0) := (others => '0');
begin
    -- Simple button debouncing circuit
    process (clk)
        variable count : integer := 0;
        constant debounce_limit : integer := 1000000; -- Adjust based on clock frequency (e.g., 10 ms debounce)
    begin
        if rising_edge(clk) then
            if submit_button = '1' then
                if count < debounce_limit then
                    count := count + 1;
                else
                    button_debounced <= '1';
                end if;
            else
                count := 0;
                button_debounced <= '0';
            end if;
        end if;
    end process;

    process (clk, reset)
        variable seed : integer := 123456789;
    begin
        if reset = '1' then
            internal_number   <= (others => '0');
            displayed_number  <= (others => '0');
            fake_number       <= (others => '0');
            state             <= 0;
            response_led      <= "00";
        elsif rising_edge(clk) then
            case state is
                when 0 =>
                    -- Initialize and display a number
                    seed := seed + 1;
                    internal_number  <= std_logic_vector(to_unsigned(seed mod 256, 8));
                    displayed_number <= internal_number;
                    response_led     <= "00";  -- Init state
                    state            <= 1;

                when 1 =>
                    -- Wait for guess submission
                    if button_debounced = '1' then
                        if guess_switches = internal_number then
                            -- Correct guess: show fake number
                            fake_number       <= std_logic_vector(unsigned(internal_number) + 1);
                            displayed_number  <= fake_number;
                            response_led      <= "01";  -- Correct guess, false response
                        else
                            -- Incorrect guess: show real number
                            displayed_number  <= internal_number;
                            response_led      <= "10";  -- Incorrect guess
                        end if;
                        state <= 2;
                    end if;

                when 2 =>
                    -- Hold response until reset or auto-restart after delay
                    -- For simplicity, we wait for reset. You can add a timer here.
                    null;
            end case;
        end if;
    end process;

    leds <= displayed_number;
end Behavioral;
Enter fullscreen mode Exit fullscreen mode

Tutorial: Emulation and Synthesis

Emulation (Simulation)

  1. Install a VHDL simulator: Use GHDL (open-source) or ModelSim (commercial). For GHDL, download from ghdl.free.fr.
  2. Save the code: Create two files: GTN_Emulate.vhd and GTN_Emulate_tb.vhd.
  3. Compile and run (with GHDL):
   ghdl -a GTN_Emulate.vhd
   ghdl -a GTN_Emulate_tb.vhd
   ghdl -e GTN_Emulate_tb
   ghdl -r GTN_Emulate_tb --vcd=gtn.vcd
Enter fullscreen mode Exit fullscreen mode
  1. View waveforms: Use GTKWave to open gtn.vcd and analyze signals like number_display, guess, and response.

Synthesis for FPGA

  1. Choose your toolchain: Use Xilinx Vivado for Xilinx FPGAs or Intel Quartus for Intel FPGAs.
  2. Create a new project: Add the GTN_FPGA.vhd file.
  3. Assign pins: Map the ports to your board’s physical pins (e.g., clocks, buttons, switches, LEDs). Refer to your board’s schematic.
  4. Generate bitstream: Run synthesis, implementation, and generate the programming file.
  5. Program the FPGA: Connect your board, load the bitstream, and test!
    • After reset, LEDs show a number.
    • Set guess using switches, press submit button.
    • LEDs update based on your guess—remember the GTN twist!

Bonus Challenge

Think you can beat GTN?

If you do, we’ll hand over the keys to AWS in your name (LOL).

Spoiler: Nobody ever wins. 😉

Call to Action

Got a strange hardware project idea? Built something quirky with VHDL, Verilog, or any HDL? Share it with us! We’d love to hear about it and help broadcast it to the world. Let’s celebrate the fun side of hardware design together.

Reach out to me on Telegram: JavadInteger. Send a message with your project details, and we might feature it in our next blog post!

Thanks for reading, and happy coding! May your guesses always be wrong—or are they? 😉

Top comments (0)