(For educational purposes only)
Made by Seongjun An and Matthew Suh
Our project recreates a simplified version of a Pokémon battle using VHDL and runs on a Nexys A7-100T FPGA board. The project is displayed on a monitor using a VGA to HDMI adapter plugged directly into the FPGA. The player is able to create a team of 3 Pokémon, choosing from 6 available Pokémon. The player then battles against a CPU trainer that also has a team of 3 Pokémon. The demo ends when the player defeats all of the CPU's Pokémon or when all of their Pokémon are defeated.
- BTNU: Move cursor up
- BTND: Move cursor down
- BTNL: Move cursor left
- BTNR: Move cursor right
- BTNC: Select
(In battle)
- BTNL/BTNR: Swap Pokémon
- BTNC: Attack
- Digilent Nexys A7-100T FPGA Board
- Micro USB Cable
- VGA to HDMI Adapter
- HDMI Cable
- TV or Monitor with an HDMI input
- AMD Vivado™ Design Suite
- Download the
.vhdand.xdcfiles inside the folder VHDL files - Open Vivado and create a new RTL project
- Add the
.vhdfiles you just downloaded as sourcespokemon.vhdvga_sync.vhdclk_wiz_0.vhdclk_wiz_0_clk_wiz.vhdalphabet.vhdIntro.vhdchooseTeam.vhdbattle.vhdOutro.vhdopponent.vhdpikachu.vhdgiratina.vhdempoleon.vhdgarchomp.vhdtorterra.vhdbidoof.vhd
- Add
pokemon.xdcas a constraint file - Plug the Nexys A7 board into your computer
- Connect the board to a monitor
- Run Synthesis
- Run Implementation
- Generate Bitstream
- Open Hardware Manager and Program the Device
entity pokemon is
port (
clk_in : in std_logic;
-- buttons
btnu : in std_logic;
btnd : in std_logic;
btnl : in std_logic;
btnr : in std_logic;
btnc : in std_logic;
-- VGA
VGA_hsync : out std_logic;
VGA_vsync : out std_logic;
VGA_red : out std_logic_vector(3 downto 0);
VGA_green : out std_logic_vector(3 downto 0);
VGA_blue : out std_logic_vector(3 downto 0)
);
end entity pokemon;Inputs
clk_in: System clock (100 MHz)btnubtndbtnlbtnrbtnc: Buttons for navigation and selection/attack
Outputs
VGA_hsyncVGA_vsync: Horizontal and vertical signals for the displayVGA_redVGA_greenVGA_blue: Red, green, and blue color channels for VGA output
entity Intro is
port (
clk : in std_logic;
pixel_row : in std_logic_vector(10 downto 0);
pixel_col : in std_logic_vector(10 downto 0);
btnc : in std_logic;
red : out std_logic_vector(3 downto 0);
green : out std_logic_vector(3 downto 0);
blue : out std_logic_vector(3 downto 0);
done : out std_logic
);
end entity;Inputs
clk: Pixel clock (25 MHz)pixel_rowpixel_col: Vertical and horizontal pixel positioning on the displaybtnc: Button for advancing to the next screen
Outputs
redgreenblue: Red, green, and blue color channels for VGA outputdone: Tells the program to advance to the next screen
entity chooseTeam is
port (
clk : in std_logic;
pixel_row : in std_logic_vector(10 downto 0);
pixel_col : in std_logic_vector(10 downto 0);
btnu : in std_logic;
btnd : in std_logic;
btnl : in std_logic;
btnr : in std_logic;
btnc : in std_logic;
red : out std_logic_vector(3 downto 0);
green : out std_logic_vector(3 downto 0);
blue : out std_logic_vector(3 downto 0);
team_p0 : out std_logic_vector(2 downto 0);
team_p1 : out std_logic_vector(2 downto 0);
team_p2 : out std_logic_vector(2 downto 0);
done : out std_logic
);
end entity chooseTeam;Inputs
clk: Pixel clock (25 MHz)pixel_rowpixel_col: Vertical and horizontal pixel positioning on the displaybtnubtndbtnlbtnrbtnc: Buttons for navigation and selection
Outputs
redgreenblue: Red, green, and blue color channels for VGA outputteam_p0: ID of the first Pokémon selected by the playerteam_p1: ID of the second Pokémon selected by the playerteam_p2: ID of the third Pokémon selected by the playerdone: Tells the program to advance to the next screen
entity battle is
port (
clk : in std_logic;
active : in std_logic;
pixel_row : in std_logic_vector(10 downto 0);
pixel_col : in std_logic_vector(10 downto 0);
player_p0 : in std_logic_vector(2 downto 0);
player_p1 : in std_logic_vector(2 downto 0);
player_p2 : in std_logic_vector(2 downto 0);
enemy_p0 : in std_logic_vector(2 downto 0);
enemy_p1 : in std_logic_vector(2 downto 0);
enemy_p2 : in std_logic_vector(2 downto 0);
btnu : in std_logic;
btnd : in std_logic;
btnl : in std_logic;
btnr : in std_logic;
btnc : in std_logic;
red : out std_logic_vector(3 downto 0);
green : out std_logic_vector(3 downto 0);
blue : out std_logic_vector(3 downto 0);
player_win : out std_logic;
enemy_win : out std_logic;
done : out std_logic;
hp_summary : out std_logic_vector(15 downto 0)
);
end entity;Inputs
clk: Pixel clock (25 MHz)active: Enable signal from the top-level FSM indicating the battle state is activepixel_rowpixel_col: Vertical and horizontal pixel positioning on the displayplayer_p0player_p1player_p2: Player’s Pokémon IDsenemy_p0enemy_p1enemy_p2: Opponent’s Pokémon IDsbtnubtndbtnlbtnrbtnc: Buttons for swapping Pokémon and attack
Outputs
redgreenblue: Red, green, and blue color channels for VGA outputplayer_win: Activated when player winsenemy_win: Activated when opponent winsdone: Tells the program to advance to the next screenhp_summary: Summary of current Pokémon health values
entity Outro is
port (
clk : in std_logic;
pixel_row : in std_logic_vector(10 downto 0);
pixel_col : in std_logic_vector(10 downto 0);
btnc : in std_logic;
player_win : in std_logic;
enemy_win : in std_logic;
red : out std_logic_vector(3 downto 0);
green : out std_logic_vector(3 downto 0);
blue : out std_logic_vector(3 downto 0);
done : out std_logic
);
end entity;Inputs
clk: Pixel clock (25 MHz)pixel_rowpixel_col: Vertical and horizontal pixel positioning on the displaybtnc: Button for advancingplayer_win: Indicates the player won the battleenemy_win: Indicates the opponent won the battle
Outputs
redgreenblue: Red, green, and blue color channels for VGA outputdone: Tells the program to advance to the next screen
entity alphabet is
port (
char_code : in std_logic_vector(5 downto 0); -- 0-9, A-Z
glyph_x : in std_logic_vector(2 downto 0); -- 0..4
glyph_y : in std_logic_vector(2 downto 0); -- 0..6
pixel_on : out std_logic -- '1' = draw
);
end entity alphabet;Inputs
char_code: 6-bit character code selecting the glyph to draw (0–9, A–Z)glyph_xglyph_y: Horizontal and vertical pixel index within the character glyph
Outputs
pixel_on: Asserted when the selected glyph pixel should be drawn at the current glyph coordinates
ENTITY vga_sync IS
PORT (
pixel_clk : IN STD_LOGIC;
red_in : IN STD_LOGIC_VECTOR (3 DOWNTO 0);
green_in : IN STD_LOGIC_VECTOR (3 DOWNTO 0);
blue_in : IN STD_LOGIC_VECTOR (3 DOWNTO 0);
red_out : OUT STD_LOGIC_VECTOR (3 DOWNTO 0);
green_out : OUT STD_LOGIC_VECTOR (3 DOWNTO 0);
blue_out : OUT STD_LOGIC_VECTOR (3 DOWNTO 0);
hsync : OUT STD_LOGIC;
vsync : OUT STD_LOGIC;
pixel_row : OUT STD_LOGIC_VECTOR (10 DOWNTO 0);
pixel_col : OUT STD_LOGIC_VECTOR (10 DOWNTO 0)
);
END vga_sync;Inputs
pixel_clk: Pixel clock (25 MHz)red_ingreen_inblue_in: Red, green, and blue color values for the current pixel from the active scene
Outputs
red_outgreen_outblue_out: Red, green, and blue color values driven to the VGA connectorhsyncvsync: Horizontal and vertical synchronization signal for the displaypixel_rowpixel_col: Vertical and horizontal pixel positioning on the display
Because we knew we wanted to make a game that used a display and user input, we started off using Lab 6 as a starting point for our project. We pulled clk_wiz_0.vhd, clk_wiz_0_clk_wiz.vhd, and vga_sync.vhd to use for our project. We made no modifications to these 3 files.
For our pokemon.xdc we copied the pong.xdc code from Lab 6. The only modification we made to this file was removing the physical pin assignments connected to the 7 segment displays. We did this because we knew we weren't going to display anything on them.
The rest of our code was coded from scratch while using bat_n_ball.vhd and pong.vhd from Lab 6 as references. A majority of our code was also developed with the help of ChatGPT. We started out by creating different files for different "scenes" that the program would run through. After making the necessary modifications required for each scene, we then attached them to our top level file pokemon.vhd. For the Pokémon, we created a separate file for each which contained their sprite and color palette data. The sprites we used were based off the sprites from Pokémon Platinum and drawn by hand in google sheets. They were then converted into .csv files and then converted into VHDL using csvConversion.py. Keeping the Pokémon data in separate files allowed us to reduce clutter in our main files while maintaining convenience since we were able to directly call the packages whenever we needed.
Seongjun: Worked on main code base such as battle logic and moving between scenes.
Matthew: Worked on visuals drawing sprites and bringing them into VHDL. Also worked on organizing the GitHub repository and the README.
Week of 11/18: Started working on the overall project
Week of 11/25: Split tasks and worked on basic battle mechanics and displaying simple sprites
Week of 12/2: Continued working on battle mechanics and translating complete sprites into VHDL
Week of 12/9: Finished battle mechanics and implemented sprites into final code
While developing the Pokémon battle system in VHDL, the main challenges we encountered involved managing timing for battle logic and handling sprite overlap in the display system. In our implementation of turn-based combat, we needed to fine tune timings to make sure attacks were done in the correct order and that animations wouldn't trigger too early. Additionally, integrating our sprite system introduced complexity where sprites would overlap and the different scenes would unintentionally render on top of each other. We addressed this by defining clear rendering priorities, bounding-box checks, and scene-level enable signals so that only the correct sprites and backgrounds were active at any given time. This allowed us to have stable visuals and consistent battle behavior.
If given more time, we would want to expand the battle system and make it more accurate by adding Pokémon type mechanics and a more diverse attack move system. Since the current version is more based on luck, implementing type advantages and resistances (such as Fire, Water, and Grass interactions) would add strategic depth by modifying damage calculations based on whether an attack is effective, super effective, or not very effective. We also want to introduce multiple attack moves per Pokémon, each with distinct power, accuracy, cooldowns, and visual effects, making it more accurate to the games.



