VGS (SUZUKI PLAN - Video Game System) is designed around a single, consistent philosophy: to define a stable virtual hardware model and preserve it over time through emulation.
Rather than treating a game engine as a collection of APIs or libraries, VGS defines the computer itself on which games run — including CPU, graphics, sound, and memory layout. By fixing this model, games are decoupled from real hardware, operating systems, and evolving toolchains.
The goal of VGS is not technical novelty or maximum performance. Its value lies in allowing developers to continue creating games with the same mental model for decades, without being forced to adapt to external platform changes.
VGS exists to make long-term game creation practical, sustainable, and intellectually stable.
VGS-X is the successor to VGS-Zero, but it is not a simple performance upgrade. Both systems share the same core philosophy: defining a fixed virtual hardware model and preserving it long-term through emulation, independent of real hardware and operating systems.
A key design principle common to both VGS-Zero and VGS-X is real-clock–independent design. This principle does not prohibit the use of modern host performance. Rather, it states that the semantics and behavior of software must never be defined in terms of real CPU clocks, host execution speed, or frame timing characteristics.
In VGS-X, all game logic, timing, and audiovisual behavior are expressed exclusively within the rules of the virtual hardware—CPU, VDP, sound system, DMA, and memory layout. Host performance is used only as an implementation resource to faithfully and stably realize this virtual machine, not as a variable that influences game behavior.
VGS-Zero embodied this idea with an 8-bit Z80-based model, where strong constraints and complete isolation from host timing allowed games to be treated as artifacts bound to a timeless machine definition. VGS-X redefines the same concept around a 32-bit MC68030-based architecture, greatly expanding computational scale and asset capacity while preserving the same rule: software behavior must remain invariant regardless of host performance.
Rather than competing on raw speed or technological novelty, VGS-X exists to provide a stable, long-lived virtual game platform. By clearly separating software semantics from implementation performance, developers can continue creating games for decades without changing their fundamental assumptions about time or execution.
The VGS-X is a 16-bit game console featuring an MC68030 processor, the YM2612(OPN) FM sound chip, and a proprietary VDP optimized for MC68k architecture.
Basic Features:
- CPU: MC68030 (unlimited clocks)
- Fully compatible with the VGS Standard Library
- VDP: VGS-X Video
- BGM: .vgm format (YM2612)
- SFX: .wav format (44,100Hz, 16-bits, 2ch)
- High speed DMA; Direct Memory Access
- High speed i-math (integer math) API
- Save Data
VDP Features:
- Screen Resolution: 320x200 pixels (internally: 640x400)
- Color: 24-bits color (RGB888)
- BG: Four nametables, and Two modes (Character Pattern and Bitmap)
- BG nametable size: 256x256 (2048x2048 pixels)
- Supported the BG Hardware Scroll function
- Character Pattern number: 65,536
- Number of OAM (Sprites): 1,024
- Size of Sprite: from 8x8 pixels to 256x256 pixels
- Supports Rotation, Scaling, Alpha-blending and Mask for each sprites
- Supports the Bitmap Graphic Draw functions for Bitmap Mode
- Supports the Proportional Font functions for Bitmap Mode
- Supports Japanese display for JIS-X-0201 and JIS-X-0208 using k8x12 for Bitmap Mode
Games can be developed using the GCC; GNU Compiler Collection for MC68k.
Supported development environment operating systems are Ubuntu Linux or macOS. (If you want to use Windows as a development machine, please use WSL2.)
The runtime environment supports the all of PC operating systems (Windows, macOS, and Linux) that supported by Steam Client.
In the future, we also plan to provide runtimes capable of running on Nintendo Switch 1/2 and PlayStation 4/5. Due to an NDA, we cannot disclose details, but we will be confirmed that the core modules can be built and run using the SDKs for those game consoles.
VGS-X aims to provide game developers and publishers with an environment that enables them to deliver games that are fully compatible across any computer with certain performance specifications.
VGS-X is provided under the MIT License, which allows free modification, customization, and redistribution of both the specification and its reference implementations.
The SDL2-based runtime included in this repository is provided as a reference implementation, intended for development, testing, and practical use on general-purpose platforms such as PC and Steam. It is not intended to be the only possible or mandatory runtime.
VGS-X is designed so that developers who require a different execution environment — including proprietary hardware or console platforms — can implement their own runtime as needed, based on the published specification and I/O definitions.
In other words, VGS-X does not attempt to provide “every possible runtime”, but instead provides a stable virtual hardware specification that makes such implementations feasible when required.
This section describes the first steps for developing applications for VGS-X. It covers setting up the development environment, building and running the Example (Hello, World), creating a new project, and the guidelines necessary to maintain compatibility of your game over time.
By the end of this section, you will be able to build and run a VGS-X application on your own environment and proceed with game development in a stable and future-proof manner.
Since VGS-X can execute MC68030 ELF format modules, you must install m68k-elf-gcc to develop games for VGS-X.
On macOS, it can be easily installed via Homebrew. However, since no apt package is provided for Ubuntu Linux, you will need to build it yourself.
Please install m68k-elf-gcc and SDL2 in an environment where Xcode and Homebrew are installed.
brew install m68k-elf-gcc
brew install sdl2Below are the installation steps required for game development for the VGS-X.
# Install Dependencies
sudo apt update
sudo apt install build-essential bison flex libgmp-dev libmpc-dev libmpfr-dev texinfo libncurses5-dev
# Install SDL2 and ALSA
sudo apt install libsdl2-dev libasound2 libasound2-dev
# Make a work directory for build m68k-elf
mkdir ~/m68k-work
# Build and Install the binutils for MC68k
cd ~/m68k-work
wget https://ftp.gnu.org/gnu/binutils/binutils-2.40.tar.gz
tar xvf binutils-2.40.tar.gz
cd binutils-2.40
mkdir ../binutils-build
cd ../binutils-build
../binutils-2.40/configure --target=m68k-elf --prefix=/usr/local/m68k-elf --disable-nls --disable-werror
make -j$(nproc)
sudo make install
export PATH=$PATH:/usr/local/m68k-elf/bin
# Build and Install GCC for MC68k
cd ~/m68k-work
wget https://ftp.gnu.org/gnu/gcc/gcc-12.2.0/gcc-12.2.0.tar.gz
tar xvf gcc-12.2.0.tar.gz
cd gcc-12.2.0
./contrib/download_prerequisites
mkdir ../gcc-build
cd ../gcc-build
../gcc-12.2.0/configure --target=m68k-elf --prefix=/usr/local/m68k-elf --enable-languages=c --disable-nls --disable-libssp --without-headers
make all-gcc -j$(nproc)
make all-target-libgcc -j$(nproc)
sudo make install-gcc install-target-libgccAdd the following line to ~/.zprofile so that the path is set when Terminal launches.
export PATH=$PATH:/usr/local/m68k-elf/bin
We referenced the following article.
https://computeralgebra.hatenablog.com/entry/2025/02/26/233231.
We would like to thank the author for writing it!
If you've finished installing m68k-elf-gcc, you're now ready to start developing games for the VGS-X.
The following steps show how to obtain this repository using git clone and then run the example that displays “HELLO, WORLD!”.
# Move to the home directory.
cd ~
# Clone the VGS-X repository
git clone https://github.com/suzukiplan/vgsx
# Move to the example directory
cd vgsx/example/01_hello
# Build and Execute
makeYou can create a new project for developing your game by executing the makeprj command.
# Create a new project: "My Game"
~/vgsx/tools/makeprj/makeprj ~/projects/MyGameVGS-X may introduce changes in future updates that do not preserve backward compatibility (i.e., breaking changes).
As long as you keep the submodule versions that were generated when you ran the makeprj command, your project’s compatibility will not be affected. However, if you need features provided by the latest version of VGS-X, review CHANGES.md and carefully check the changes in any entries marked (Disruptive).
This section provides a detailed reference to the VGS-X virtual hardware architecture. It is not intended to be read linearly from start to finish.
The contents here are designed to be used while writing actual game code— as a technical reference you can consult whenever you need to understand memory layout, VDP behavior, I/O semantics, or low-level system details.
If you are new to VGS-X, it is perfectly fine to skip this section at first and return to it as your implementation progresses.
All hardware features described in this section can be accessed through the C-language runtime library explained later in the VGS Standard Library.
- It has a fixed screen resolution of 320x200 pixels.
- It has 4 layers of BGs and 1 layer of sprites.
- Each BGs has two modes: Character Pattern Mode and Bitmap Mode.
- Sprites can display up to 1024.
The screen resolution of VGS-X (320x200) is designed to enable full-screen display on the SteamDeck (1280x800).
The resolution (coordinate system) of VGS-X is 320×200 pixels, but internally, the screen buffer operates at 640×400 pixels.
Sprites and backgrounds are always rendered at 4× size (twice the width and twice the height).
This design allows sprites to be scaled down to 50% or more without losing pixel detail.
It also reduces pixel loss when rotating sprites.
In VGS-X, the first 12MB (0x000000 ~ 0xBFFFFF) of the MC68030's 24-bit (16MB) address space is allocated for programs.
The final 1MB (0xF00000 ~ 0xFFFFFF) constitutes the WRAM; Work RAM area.
The space between the program and WRAM (0xC00000 ~ 0xEFFFFF = 3MB) constitutes the memory map for the VDP and I/O.
| Address | Size | Description |
|---|---|---|
| 0x000000 ~ 0xBFFFFF | 12288KB | Program (ELF module) |
| 0xC00000 ~ 0xCFFFFF | 1024KB | Name Table |
| 0xD00000 ~ 0xD0FFFF | 64KB | OAM |
| 0xD10000 ~ 0xD1FFFF | 64KB | Palette |
| 0xD20000 ~ 0xD2FFFF | 64KB | VDP Register |
| 0xD30000 ~ 0xDFFFFF | 832KB | Reserved |
| 0xE00000 ~ 0xEFFFFF | 1024KB | I/O |
| 0xF00000 ~ 0xFFFFFF | 1024KB | WRAM |
When accessing the address range 0xC00000 to 0xEFFFFF used as mmap, access must always be 32-bit aligned.
Since the least significant two bits are always masked when accessing this address space, accesses to 0xC00000, 0xC00001, 0xC00002, and 0xC00003 always behave as if accessing 0xC00000.
Character patterns and Sound data are stored in Read Only Memory, which cannot be directly referenced from the program. Like VGS-Zero, it is specified by pattern number.
The program area (0x000000 ~ 0xBFFFFF) contains the ELF32 (Executable and Linkable Format 32bit) binary module.
When tune on the VGS-X, it begins executing the program from the entry point specified in the ELF header of the program loaded from the ROM cartridge.
Note that even if you wish to write your program solely in MC68k assembly language, you must always specify the ELF32 header and Program header that contains valid entry point and executable text.
However, since there is no advantage to writing high-performance programs in assembly language on the VGS-X, we generally do not recommend writing programs entirely in assembly language.
The following command line the compilation options that must be specified when outputting programs that can run on VGS-X using m68k-elf-gcc.
m68k-elf-gcc
-mc68030 ... Compile as MC68030 binary
-O2 ... Optimize the Runtime Speed
-I${VGSX_ROOT}/lib ... Specify the VGS-X API header path using the -I option
-o program
program.c
-L${VGSX_ROOT}/lib ... Specify the VGS-X API archive path using the -L option
-T${VGSX_ROOT}/lib/linker.ld ... Specify the linker.ld file describing the VGS-X memory map using the -T option.
-Wl,-ecrt0 ... Specify crt0 as the entry point when using the VGS-X runtime
Note that VGS-X does not provide the C standard library, but it does provide the VGS Standard Library.
As an exception, you can use the
stdarg.hprovided by GCC.
VGS-X can use 65,536 character patterns.
One character pattern is 8x8 pixels.
The data consists of 32 bytes with the following bit layout:
| px0 | px1 | px2 | px3 | px4 | px5 | px6 | px7 | Line number |
|---|---|---|---|---|---|---|---|---|
| H00 | L00 | H01 | L01 | H02 | L02 | H03 | L03 | Line 0 |
| H04 | L04 | H05 | L05 | H06 | L06 | H07 | L07 | Line 1 |
| H08 | L08 | H09 | L09 | H10 | L10 | H11 | L11 | Line 2 |
| H12 | L12 | H13 | L13 | H14 | L14 | H15 | L15 | Line 3 |
| H16 | L16 | H17 | L17 | H18 | L18 | H19 | L19 | Line 4 |
| H20 | L20 | H21 | L21 | H22 | L22 | H23 | L23 | Line 5 |
| H24 | L24 | H25 | L25 | H26 | L26 | H27 | L27 | Line 6 |
| H28 | L28 | H29 | L29 | H30 | L30 | H31 | L31 | Line 7 |
Hxx: Upper 4 bits (0 ~ 15 = color number)Lxx: Lower 4 bits (0 ~ 15 = color number)
Remarks:
- This bit layout is compatible with VGS-Zero.
- Character patterns cannot be referenced directly from the program. You can draw the desired character by specifying the pattern number in the name table or OAM.
- Character pattern number is shared between BGs and Sprites.
WIP Note: Currently, the character pattern specification assumes that all necessary patterns are loaded at program startup. This means we intend to restrict dynamic pattern rewriting after startup. However, we also believe there is room to consider changing this specification.
- At startup (initial state), the chr file specified by makerom is loaded into memory (Character Pattern RAM).
- Using the Copy Character Pattern feature, you can copy a character from one character pattern number to another.
- Using the Transfer Character Pattern feature, you can load character patterns stored in Program ROM or RAM into memory.
- Any memory contents modified by Copy Character Pattern or Transfer Character Pattern will be restored to the initial state after a reset.
- VGS-X allows up to 16 palettes
- Each palette can contain 16 colors in RGB888 format
- Color number 0 is the transparent color
- Color number 0 in Palette number 0 becomes the backdrop (overall background) color.
| Address | Palette Number | Color Number |
|---|---|---|
| 0xD10000 ~ 0xD10003 | 0 | 0 |
| 0xD10004 ~ 0xD10007 | 0 | 1 |
| 0xD10008 ~ 0xD1000B | 0 | 2 |
| : | : | : |
| 0xD10034 ~ 0xD10037 | 0 | 13 |
| 0xD10038 ~ 0xD1003B | 0 | 14 |
| 0xD1003C ~ 0xD1003F | 0 | 15 |
| 0xD10040 ~ 0xD10043 | 1 | 0 |
| 0xD10044 ~ 0xD10047 | 1 | 1 |
| 0xD10048 ~ 0xD1004B | 1 | 2 |
| : | : | : |
| 0xD103F4 ~ 0xD103F7 | 15 | 13 |
| 0xD103F8 ~ 0xD103FB | 15 | 14 |
| 0xD103FC ~ 0xD103FF | 15 | 15 |
Remarks:
- Bit Layout:
******** rrrrrrrr gggggggg bbbbbbbb - 0xD10400 ~ 0xD1FFFF is a mirror of 0xD10000 ~ 0xD103FF (1024 bytes).
- Please note that access to the palette table must always be 4-byte aligned.
- The Name Table is a 256x256 x 4bytes two-dimensional array of the attributes.
- The visible displayed area is 40x25 in the Name Table (256x256).
- By setting character patterns and attribute data to it, graphics can be displayed on the background layer.
- The Name Table has a four-layer structure, with BG1 displayed on top of BG0, BG2 on top of BG1, and BG3 on top of BG2.
| Address | Size | Name Table |
|---|---|---|
| 0xC00000 ~ 0xC3FFFF | 256KB | BG0 |
| 0xC40000 ~ 0xC7FFFF | 256KB | BG1 |
| 0xC80000 ~ 0xCBFFFF | 256KB | BG2 |
| 0xCC0000 ~ 0xCFFFFF | 256KB | BG3 |
In Bitmap Mode, these areas corresponds to 320x200 pixels.
Please note that access to the name table must always be 4-byte aligned.
The Bit-Layout of the Name Table and OAM's attribute are as follows:
| Bit | Mnemonic | Description |
|---|---|---|
| 0 | F/H | Flip Horizontal |
| 1 | F/V | Flip Vertical |
| 2~7 | reserved | Specify 0 to maintain future compatibility. |
| 12~15 | PAL | Palette Number (0~15) |
| 16~31 | PTN | Character Pattern Number (0~65535) |
OAM is a structure with the following attributes.
typedef struct {
uint32_t visible; // Visible (0 or not 0)
int32_t y; // Position (Y)
int32_t x; // Position (X)
uint32_t attr; // Attribute
uint32_t size; // Size (0: 8x8, 1: 16x16, 2: 24x24, 3: 32x32 ... 31: 256x256)
int32_t rotate; // Rotate (-360 ~ 360)
uint32_t scale; // Scale (0: disabled, or 1 ~ 400 percent)
uint32_t alpha; // Alpha (0: disabled, or 0x000001 ~ 0xFFFFFF)
uint32_t mask; // Mask (0: disabled, or RGB888)
uint32_t sly; // Scale Lock (Y)
uint32_t slx; // Scale Lock (X)
uint32_t pri; // High Priority Flag
uint32_t ram_ptr; // Bitmap Sprite Buffer (RGB888)
uint32_t reserved[3]; // Reserved (Specify 0 to maintain future compatibility.)
} ObjectAttributeMemory;The specifications for each attribute are shown in the table below.
| Name | Valid Range | Description |
|---|---|---|
| visible | 0 or 1 | Display sprite with a non-zero setting. |
| y | -32768 ~ 32767 | Sprite display coordinates |
| x | -32768 ~ 32767 | Sprite display coordinates |
| attr | 32bit | Attribute |
| size | 0 ~ 31 | Size |
| rotate | -360 ~ 360 | Rotate |
| scale | 0 ~ 400 | Scale |
| alpha | 0 or 0xRRGGBB | Alpha Blend |
| mask | 0 or 0xRRGGBB | Mask |
| sly | 0 or 1 | Lock Scale (Y) |
| slx | 0 or 1 | Lock Scale (X) |
| pri | 0 or 1 | High Priority Flag |
| ram_ptr | 0 or RAM addr | Bitmap Sprite Buffer (RGB888) |
| reserved | - | Do not set a value other than zero. |
Sprites are displayed as squares measuring (size + 1) * 8 pixels.
For example, when size is set to 3 (32x32 pixels), the sprite is displayed using 16 = (size + 1) ^ 2 patterns. The layout of the pattern numbers at that time is as follows:
Size 3 Pattern Number Layout
+--------+--------+--------+--------+
| | | | |
| ptn+0 | ptn+1 | ptn+2 | ptn+3 |
| | | | |
+--------+--------+--------+--------+
| | | | |
| ptn+4 | ptn+5 | ptn+6 | ptn+7 |
| | | | |
+--------+--------+--------+--------+
| | | | |
| ptn+8 | ptn+9 | ptn+10 | ptn+11 |
| | | | |
+--------+--------+--------+--------+
| | | | |
| ptn+12 | ptn+13 | ptn+14 | ptn+15 |
| | | | |
+--------+--------+--------+--------+
By specifying an angle (-360 to 360) for rotate, you can draw a rotated sprite.
Note that setting rotate to a non-zero value increases the sprite's drawing overhead.
The Sprite rotation feature is useful when combined with the Angle function.
- You can specify the magnification rate as a percentage on the
scalewithin the range of 0 to 400. - Setting either
slxorslyto a value other than zero will prevent scaling of either the X or Y axis.
You can specify the alpha blend value for alpha in the range of 0x000000 to 0xFFFFFF.
You can assign different alpha values to each RGB component:
- Specifying 0xFF0000 renders only the red component.
- Specifying 0x00FF00 renders only the green component.
- Specifying 0x0000FF renders only the blue component.
Setting a non-zero value (in RGB888 format) to the mask fills the sprite with the specified solid color.
For example, combining the Scale, Alpha Blend, and Mask functions can be used to render the shadows of shoot 'em up aircraft.
Setting the high priority flag pri allows the drawing priority to be set higher than sprites without pri set.
By setting a RAM address (non-zero) to ram_ptr in the Bitmap Sprite Buffer (RGB888), you can display an RGB888-format sprite (1 px = 4 bytes) stored directly in RAM/ROM without using a Character Pattern.
* RAM buffer size = ((size + 1) * 8)²
| Address | Name | Mnemonic | Description |
|---|---|---|---|
| 0xD20000 | R0 | SKIP | Skip Screen Update |
| 0xD20004 | R1 | SPOS | Sprites Position |
| 0xD20008 | R2 | SX0 | Scroll X of BG0 |
| 0xD2000C | R3 | SX1 | Scroll X of BG1 |
| 0xD20010 | R4 | SX2 | Scroll X of BG2 |
| 0xD20014 | R5 | SX3 | Scroll X of BG3 |
| 0xD20018 | R6 | SY0 | Scroll Y of BG0 |
| 0xD2001C | R7 | SY1 | Scroll Y of BG1 |
| 0xD20020 | R8 | SY2 | Scroll Y of BG2 |
| 0xD20024 | R9 | SY3 | Scroll Y of BG3 |
| 0xD20028 | R10 | BMP0 | Bitmap Mode of BG0 |
| 0xD2002C | R11 | BMP1 | Bitmap Mode of BG1 |
| 0xD20030 | R12 | BMP2 | Bitmap Mode of BG2 |
| 0xD20034 | R13 | BMP3 | Bitmap Mode of BG3 |
| 0xD20038 | R14 | CLSA | Clear Screen of All BGs |
| 0xD2003C | R15 | CLS0 | Clear Screen of BG0 |
| 0xD20040 | R16 | CLS1 | Clear Screen of BG1 |
| 0xD20044 | R17 | CLS2 | Clear Screen of BG2 |
| 0xD20048 | R18 | CLS3 | Clear Screen of BG3 |
| 0xD2004C | R19 | G_BG | Bitmap Graphic Draw |
| 0xD20050 | R20 | G_X1 | Bitmap Graphic Draw |
| 0xD20054 | R21 | G_Y1 | Bitmap Graphic Draw |
| 0xD20058 | R22 | G_X2 | Bitmap Graphic Draw |
| 0xD2005C | R23 | G_Y2 | Bitmap Graphic Draw |
| 0xD20060 | R24 | G_COL | Bitmap Graphic Draw |
| 0xD20064 | R25 | G_OPT | Bitmap Graphic Draw |
| 0xD20068 | R26 | G_EXE | Bitmap Graphic Draw |
| 0xD2006C | R27 | SKIP0 | Skip Rendering BG0 |
| 0xD20070 | R28 | SKIP1 | Skip Rendering BG1 |
| 0xD20074 | R29 | SKIP2 | Skip Rendering BG2 |
| 0xD20078 | R30 | SKIP3 | Skip Rendering BG3 |
| 0xD2007C | R31 | PF_INIT | Initialize the Proportional Font coodinates. |
| 0xD20080 | R32 | PF_PTN | Proportional Font pattern number |
| 0xD20084 | R33 | PF_DX | Proportional Font diff-X |
| 0xD20088 | R34 | PF_DY | Proportional Font diff-Y |
| 0xD2008C | R35 | PF_WIDTH | Proportional Font width |
| 0xD20090 | R36 | CP_FR | Copy Character Pattern (From) |
| 0xD20094 | R37 | CP_TO | Copy Character Pattern (To) |
| 0xD20098 | R38 | TR_ADDR | Transfer Character Pattern (address) |
| 0xD2009C | R39 | TR_SIZE | Transfer Character Pattern (size) |
| 0xD200A0 | R40 | TR_TO | Transfer Character Pattern (pattern) |
Please note that access to the VDP register must always be 4-byte aligned.
Setting a value other than zero to this register will skip the screen update every frame (60fps).
Specify the BG layer on which to display the sprite, within the range of 0 to 3.
- 0: Sprites are displayed above BG0 and below BG1 through BG3.
- 1: Sprites are displayed above BG1 and below BG2 through BG3.
- 2: Sprites are displayed above BG2 and below BG3.
- 3: Sprites are displayed above BG3
The hardware scroll register behaves differently in Character Pattern Mode and Bitmap Mode.
The VGS-X has a virtual display of 2048x2048 pixels for each BG plane.
For each BG plane, the SX and SY coordinates can be specified within the range 0 to 2047 to define the display origin at the top-left corner.
- Writing a positive number to
SXscrolls the screen right by the specified number of pixels. - Writing a negative number to
SXscrolls the screen left by the specified number of pixels. - Writing a positive number to
SYscrolls the screen down by the specified number of pixels. - Writing a negative number to
SYscrolls the screen upward by the specified number of pixels. - The area after scrolling will be cleared to zero.
The VGS-X's display mode defaults to character pattern mode, but can be switched to bitmap mode by setting the BMP register (0xD20028-0xD20034).
- 0: Character Pattern Mode (default)
- 1: Bitmap Mode
When set to Bitmap mode, the name table corresponds to the pixels on the screen (320x200).
Each pixel is set in RGB888 format.
When the pixel color is 0x00000000, it becomes transparent.
You can delete all BGs or specific BGs in bulk.
Note that when the value to be cleared in bulk is 0, the process is faster compared to non-zero values.
You can draw various types of shapes to the BG in Bitmap Mode.
Drawing processing is executed when the execution identifier is written to G_EXE.
G_BG |
G_X1 |
G_Y1 |
G_X2 |
G_Y2 |
G_COL |
G_OPT |
G_EXE |
Shape |
|---|---|---|---|---|---|---|---|---|
| ☑︎ | ☑︎ | ☑︎ | - | - | ☑︎ | - | 0 |
Pixel *1 |
| ☑︎ | ☑︎ | ☑︎ | ☑︎ | ☑︎ | ☑︎ | - | 1 |
Line |
| ☑︎ | ☑︎ | ☑︎ | ☑︎ | ☑︎ | ☑︎ | - | 2 |
Box |
| ☑︎ | ☑︎ | ☑︎ | ☑︎ | ☑︎ | ☑︎ | - | 3 |
Box Fill |
| ☑︎ | ☑︎ | ☑︎ | - | - | ☑︎ | ☑︎ | 4 |
CHR *2 |
| ☑︎ | ☑︎ | ☑︎ | - | - | ☑︎ | ☑︎ | 5 |
JIS-X-0201 |
| ☑︎ | ☑︎ | ☑︎ | - | - | ☑︎ | ☑︎ | 6 |
JIS-X-0208 |
| ☑︎ | ☑︎ | ☑︎ | ☑︎ | ☑︎ | - | - | 7 |
Clear |
| ☑︎ | ☑︎ | ☑︎ | ☑︎ | ☑︎ | - | - | 8 |
Window |
Remarks:
- Reading
G_EXEallows you to read the color of the pixel drawn at the (G_X1,G_Y1) position on the background plane specified byG_BG. - When drawing a character, specify the palette number (0 to 15) in
G_COLand the pattern number (0 to 65535) inG_OPT. Additionally, setting the most significant bit ofG_COL (0x80000000)draws the transparent color, while resetting it skips drawing the transparent color.
Please note that character drawing performance is not as good as in Character Pattern Mode.
Skip displaying a specified BG plane.
This function only skips displaying information on the screen. Information that has already been drawn remains stored in VRAM, so you can read the pixel color using vgs_read_pixel.
For example, we envision using this by skipping the rendering of specific background planes designated as “collision detection surfaces,” enabling collision detection via vgs_read_pixel.
- Setting the starting character pattern number to
0xD2007C (PF_INIT)initializes the coordinate information for proportional fonts. - At
PF_INIT,PF_DXandPF_WIDTHare initialized appropriately, butPF_DYis set to a fixed value determined by the character code.'_','.',',','g'and'j'arePF_DY = 1'p','q'and'y'arePF_DY = 2- Others are
PF_DY = 0
- Set the ASCII code (0x00 to 0x7F) of the proportional font to be loaded or updated to
0xD20080 (PF_PTN). 0xD20084 (PF_DX): Read or Update a X-coodinate difference ofPF_PTN0xD20088 (PF_DY): Read or Update a Y-coodinate difference ofPF_PTN0xD2008C (PF_WIDTH): Read or Update a width ofPF_PTN
See the example of usage: ./example/05_pro-font/program.c
Copies data from a specified pattern number to another specified pattern number.
- Set the source pattern number in
CP_FR(0xD20090). - Specify the destination pattern number in
CP_TO(0xD20094).
Remarks:
- The copy completes immediately when
CP_TOis written.
Transfers data from a specified memory address to a specified pattern number.
- Set the source memory address in
TR_ADDR(0xD20098). - Specify the transfer size (in bytes) in
TR_SIZE(0xD2009C). - Transfer to the pattern number specified by
TR_TO(0xD200A0).
Remarks:
- The memory address specified in
TR_ADDRmust contain raw character pattern data in the Character Pattern Table format. TR_SIZEmust be a multiple of 32.- The transfer completes immediately when
TR_TOis written.
I/O instructions in VGS-X can be executed by performing input/output operations on the memory area from 0xE00000 to 0xEFFFFF.
Note that all addresses and values for I/O instructions must be specified as 32-bit values.
VGS-Zero employed the typical drawing method of the CRT era, namely drawing line by line. However, VGS-X differs significantly from this approach.
When an MC68k program inputs V-SYNC (0xE00000), VGS-X references the VRAM at that point to draw BG0 through BG3 and sprites. It then synchronizes at 60fps before returning a response to the MC68k.
// Execute the process to update the VRAM
drawProc();
// Waiting for vertical sync (Internally executes the InPort at 0xE00000)
vgs_vsync();
// Below processing will be executed after synchronization is complete.
afterDrawProc();The vgs_vsync function is defined in vgs.h.
Design Philosophy: By adopting this specification, the VGS-X MC68k eliminates the concept of operating clock frequency. VGS-X can execute MC68k code up to the host computer's maximum performance. You (Game Developers) themselves must describe the minimum spec required to run your game to your customers.
Writing a value to 0xE00000 allows you to output characters to the console.
This feature is intended for use in game log output and similar applications.
vgs_print("Hello, World!\n");The vgs_print function is defined in log.h.
- You can set the seed for random numbers by writing a value to 0xE00004.
- Reading 0xE00004 allows you to obtain a random number (0 to 65535).
- The random number generation in VGS-X is deterministic and repeats every 65,536 reads for the same seed.
Destination |
Source |
Argument |
Execute |
Description |
|---|---|---|---|---|
| - | ☑︎ | target |
in |
Search |
| ☑︎ | ☑︎ | size |
out(0) |
Copy |
| ☑︎ | ☑︎ | size |
out(1) |
Set |
| ☑︎ | ☑︎ | - | out(2) |
UTF8 to SJIS |
Search for the byte data specified by the lower 8 bits of Argument (target) starting from the address specified by Source.
Remarks:
- The upper 24 bits of
Argumentare ignored. - The
Sourcemust be either a Program Address (0x000000 to Size-of-Program) or a RAM Address (0xF00000 to 0xFFFFFF). - The return value is the byte offset from
Sourceto the first matching byte.0may indicate either "found atSource" or "not found". - Please note that performing searches not expected to yield results can result in significant overhead.
Transfer the data from the address specified in Source to the address specified in Destination, for the number of bytes specified in Argument (size).
Remarks:
- The
Sourcemust be either a Program Address (0x000000 to Size-of-Program) or a RAM Address (0xF00000 to 0xFFFFFF). - The
Destinationmust be a RAM Address (0xF00000 to 0xFFFFFF). - When both
SourceandDestinationpoint to RAM addresses, overlapping copy ranges are acceptable. (A copy equivalent tomemmoveis performed.) - If an invalid address range (including the result of the addition) is specified, DMA will not be executed.
Transfer the value specified by the lower 8 bits of Source to the address specified by Destination, for the number of bytes specified by Argument (size).
Remarks:
- The upper 24 bits of
Sourceare ignored. - The
Destinationmust be a RAM Address (0xF00000 to 0xFFFFFF). - If an invalid address range (including the result of the addition) is specified, DMA will not be executed.
- Executing this DMA operation copies the zero-terminated UTF-8 string set in
Source, converted to SJIS, toDestination. - The
Sourcemust be either a Program Address (0x000000 to Size-of-Program) or a RAM Address (0xF00000 to 0xFFFFFF). - The
Destinationmust be a RAM Address (0xF00000 to 0xFFFFFF).
The angle function can quickly calculate the degrees (from 0 to 359) between two points with coordinates (X1, Y1) and (X2, Y2).
VGS_OUT_ANGLE_X1 = x1;
VGS_OUT_ANGLE_Y1 = y1;
VGS_OUT_ANGLE_X2 = x2;
VGS_OUT_ANGLE_Y2 = y2;
// Get (and Set) degree of (x1,y1) and (x2,y2)
int32_t degree = VGS_IO_ANGLE_DEGREE; Note that entering
VGS_IO_ANGLE_DEGREE (0xE00110)will implicitly output the calculated valuedegreetoVGS_IO_ANGLE_DEGREE (0xE00110).
When VGS_IO_ANGLE_DEGREE (0xE00110) is input (or output), inputting 0xE00114 yields the integer-sine, and inputting 0xE00118 yields the integer-cosine.
// Get integer sin/cos
int32_t s = VGS_IN_ANGLE_SIN;
int32_t c = VGS_IN_ANGLE_COS;The standard sin() and cos() functions return double values ranging from -1.0 to 1.0, whereas VGS's integer sine and cosine functions return integers ranging from -256 to 256. Therefore, it can be used directly for fixed-point arithmetic operations where the lower 8 bits represent the fractional part.
The relationship between the sine and cosine of two points is illustrated below.
In order to align the specified degree value for the 'OAM.rotate' attribute with that for the 'Sin/Cos' function, draw the sprite's character pattern facing right, as depicted in the figure below.
For a concrete example, please refer to the implementation in ./example/03_rotate/program.c.
- Set the VGM index value to 0xE01000 to play the background music (BGM).
- Set 0 to 0xE01004 to pause BGM playback.
- Set 1 to 0xE01004 to resume BGM playback.
- Set 2 to 0xE01004 to fadeout the BGM.
- Set BGM Master Volume to 0xE01008: 0=0%, 255=100% (default: 255)
- Get BGM Master Volume from 0xE01008
VGS-X can play VGM data compatible with the YM2612 (OPN2).
We recommend using Furnace Tracker to create VGM data compatible with a YM2612(OPN2) FM sound chip.
- Set the .wav index value to 0xE01100 to play the sound effect (SFX).
- Set the .wav index value to 0xE01104 to stop the SFX.
- Set SFX Master Volume to 0xE01108: 0=0%, 255=100% (default: 255)
- Get SFX Master Volume from 0xE01108
Plays the SFX loaded at the index corresponding to the output value.
The VGS-X ROM cartridge can hold up to 256 .wav files in the following formats.
- Sampling Rate: 44100Hz
- Bit Rate: 16bits
- Number of Channels: 2 (Stereo)
Please note that while the sound effect functionality is nearly identical to VGS-Zero, the Number of Channels differs. (VGS-Zero: 1ch, VGS-X: 2ch)
You can encode to the .wav format compatible with VGS-X by specifying the following options in the ffmpeg command:
ffmpeg -i input.mp3 -acodec pcm_s16le -ar 44100 -ac 2 sfx.wavThe VGS-X can capture button inputs from the D-pad, ABXY buttons, and Start button as shown in the diagram below.
- When buttons are pressed, the corresponding input result for 0xE020xx becomes non-zero.
- The cursor keys and left stick are always linked.
- Use the
Abutton for confirmation operations. - Use the
Bbutton for cancel operations. - The
Xbutton is intended for use in operations requiring rapid button presses (e.g., as an attack button in shoot 'em ups). - The
Ybutton is intended for use in auxiliary operations. - The
Startbutton is intended for opening menus or starting games.
The following table shows the button assignments for a typical gamepad:
| VGS-X and XBOX | PC Keybord | Switch | PlayStation |
|---|---|---|---|
A |
Z |
A |
Cross |
B |
X |
B |
Circle |
X |
A |
X |
Square |
Y |
S |
Y |
Triangle |
Start |
Space |
Plus |
Options |
When using a Switch gamepad (Pro Controller), the positions of the A/B and X/Y buttons are reversed compared to the standard (Xbox) layout.
VGS-X supports input from either a PC keyboard, Xbox controller, PlayStation controller, or Nintendo Switch controller.
Reading 0xE02100 allows you to obtain the type of gamepad currently connected.
uint32_t gamepadType = VGS_KEY_TYPE;
switch (gamepadType) {
case VGS_KEY_ID_KEYBOARD: vgs_putlog("Keyboard connected!"); break;
case VGS_KEY_ID_XBOX: vgs_putlog("XBOX gamepad connected!"); break;
case VGS_KEY_ID_SWITCH: vgs_putlog("Switch gamepad connected!"); break;
case VGS_KEY_ID_PS: vgs_putlog("PlayStation gamepad connected!"); break;
default: vgs_putlog("Unknown gamepad connected!");
}| Key Identifer | #define name |
|---|---|
| 0 | VGS_KEY_ID_UNKNOWN |
| 1 | VGS_KEY_ID_KEYBOARD |
| 2 | VGS_KEY_ID_XBOX |
| 3 | VGS_KEY_ID_SWITCH |
| 4 | VGS_KEY_ID_PS |
Additionally, you can overwrite the type of currently connected gamepad by writing a key identifier to
0xE02100. (This is intended for debugging purposes only.)
Reading 0xE02104 to 0xE02114 allows you to obtain the button identifiers for the currently connected gamepad's ABXY or Start buttons.
(Button Identifiers and Strings)
| Button Identifer | #define name |
Button Name String |
|---|---|---|
| 0 | VGS_BUTTON_ID_UNKNOWN | "UNKNOWN" |
| 1 | VGS_BUTTON_ID_A | "A" |
| 2 | VGS_BUTTON_ID_B | "B" |
| 3 | VGS_BUTTON_ID_X | "X" |
| 4 | VGS_BUTTON_ID_Y | "Y" |
| 5 | VGS_BUTTON_ID_Z | "Z" |
| 6 | VGS_BUTTON_ID_S | "S" |
| 7 | VGS_BUTTON_ID_CROSS | "CROSS" |
| 8 | VGS_BUTTON_ID_CIRCLE | "CIRCLE" |
| 9 | VGS_BUTTON_ID_TRIANGLE | "TRIANGLE" |
| 10 | VGS_BUTTON_ID_SQUARE | "SQUARE" |
| 11 | VGS_BUTTON_ID_START | "START" |
| 12 | VGS_BUTTON_ID_SPACE | "SPACE" |
| 13 | VGS_BUTTON_ID_PLUS | "+" |
| 14 | VGS_BUTTON_ID_OPTIONS | "OPTIONS" |
You can retrieve the Button Name String by setting the button ID to 0xE02108 and then specifying the address of RAM with at least 12 bytes of allocated space at 0xE0211C.
char buf[12];
VGS_OUT_KEY_BUTTON_ID = 14;
VGS_OUT_KEY_BUTTON_NAME = (uint32_t)buf;
// buf will be "OPTIONS\0"This interface allows the program to save data from RAM to persistent storage (save.dat) and load previously saved data back into RAM.
The same I/O address is used for both operations, depending on whether it is accessed as an output or an input.
VGS_OUT_SAVE_ADDRESS = (uint32_t)&mydata; // Base RAM address for save/load
VGS_IO_SAVE_EXECUTE = sizeof(mydata); // Save: write RAM → save.dat
uint32_t size = VGS_IO_SAVE_EXECUTE; // Load: read save.dat → RAM- Writing a value to
VGS_IO_SAVE_EXECUTEsaves that number of bytes from RAM tosave.dat. - Reading from
VGS_IO_SAVE_EXECUTEloads data fromsave.datinto RAM and returns the number of bytes actually loaded.
VGS_OUT_SAVE_ADDRESSmust specify an address within the RAM range 0xF00000 to 0xFFFFFF (24-bit address space).- For save operations, the specified size must be between 1 and 0x100000 bytes, and the address range must not exceed the RAM limit.
- For load operations, if
save.datdoes not exist, has an invalid size, or cannot be read successfully, the load result will be 0. - The returned value from a load operation represents the number of bytes loaded into RAM.
- This interface does not perform integrity verification of the save data contents; only file existence, size validity, and read success are checked.
This interface provides buffered sequential file I/O in byte units, designed for recording and replaying moderate-sized data streams such as compact input logs or replay data.
All data is accumulated in a fixed-size internal memory buffer and written to or read from a file in a single operation. This interface is not intended for large or streaming data.
- Up to 256 sequential files can be used.
- Files are identified by an 8-bit index (0–255).
- Each file is stored as
saveNNN.dat(save000.dattosave255.dat) in the save data directory.
VGS_IO_SEQ_OPEN_W = index; // Select file index (0–255)
VGS_IO_SEQ_WRITE = value; // Write 1 byte to internal buffer
VGS_IO_SEQ_COMMIT = 0; // Write buffer to saveNNN.datVGS_IO_SEQ_OPEN_Wselects the target sequential file.- Each write to
VGS_IO_SEQ_WRITEappends one byte to an internal buffer. VGS_IO_SEQ_COMMITwrites the buffered data to the file, overwriting any existing file with the same index.
VGS_IO_SEQ_OPEN_R = index; // Select file index (0–255)
uint32_t value = VGS_IO_SEQ_READ; // Read next byteVGS_IO_SEQ_OPEN_Rloads the entire file into an internal buffer.- Each read from
VGS_IO_SEQ_READreturns the next byte in sequence. - When all buffered data has been consumed,
VGS_IO_SEQ_READreturns0xFFFFFFFF.
- The maximum size of a sequential file is limited by a fixed internal buffer of approximately 64 KB.
- If the buffer becomes full during a write operation:
- Additional
VGS_IO_SEQ_WRITEoperations are silently ignored.
- Additional
- There is no support for streaming, chunked I/O, or incremental flushing.
- The effective maximum recordable length depends entirely on this internal buffer size.
- This interface performs buffered file I/O only; it is not suitable for large datasets or long-duration recordings.
- No data integrity verification (such as checksums or versioning) is performed.
- This design favors simplicity and predictability over scalability.
// Specify the index of the sequential file (0 ~ 255) to write to.
// Note: if another sequential file is open for writing, the previous one will not be committed automatically, resulting in data loss.
VGS_OUT_SEQ_OPEN_W = 0;
// Write 1, 2, 3 (3 bytes) to the sequential file.
VGS_OUT_SEQ_WRITE = 1;
VGS_OUT_SEQ_WRITE = 2;
VGS_OUT_SEQ_WRITE = 3;
// An explicit commit will write to the file (save000.dat).
// The value specified in the commit will be ignored.
VGS_OUT_SEQ_COMMIT = 0;Remarks:
- You cannot write to multiple sequential files simultaneously.
- It is possible to read and write to sequential files simultaneously. However, it is not possible to read and write to the same index file simultaneously.
- Writes are processed in memory, so there is no overhead from disk I/O.
- If another sequential file is open for writing, the previous one will not be committed automatically, resulting in data loss.
- Sequential files that were not committed will be lost without being saved.
// Specify the index of the sequential file (0 ~ 255) to read.
VGS_OUT_SEQ_OPEN_R = 0;
// Continue reading data until EOF is detected.
while (1) {
uint32_t data = VGS_IN_SEQ_READ;
if (0x100 < data) {
break; // EOF is detected
}
playback_replay(data);
}Remarks:
- When the file reaches EOF,
VGS_IN_SEQ_READreturns0xFFFFFFFF. - You cannot read to multiple sequential files simultaneously.
- It is possible to read and write to sequential files simultaneously. However, it is not possible to read and write to the same index file simultaneously.
- Since loading is processed in memory, there is no overhead from disk I/O.
Retrieves the current date and time.
Coordinated Universal Time (UTC):
- 0xE04000: Year (e.g., 2025)
- 0xE04004: Month (1 to 12)
- 0xE04008: Day of Month (1 to 31)
- 0xE0400C: Hour (0 to 23)
- 0xE04010: Minute (0 to 59)
- 0xE04014: Second (0 to 59)
Local Time Zone:
- 0xE04020: Year (e.g., 2025)
- 0xE04024: Month (1 to 12)
- 0xE04028: Day of Month (1 to 31)
- 0xE0402C: Hour (0 to 23)
- 0xE04030: Minute (0 to 59)
- 0xE04034: Second (0 to 59)
Displays a stack backtrace and terminates the program abnormally.
Note that when compiler optimizations (-O) are enabled, the backtrace may not be captured correctly.
If you plan to use this feature, temporarily disable compiler optimizations.
Example output when an Abort occurs with optimizations disabled:
[error] Stack trace (FP=0xFFFF74):
[error] #0: 0x001A78 <main+0x1286>
[error] #1: 0x001BDC <crt0+0xA>
From this, you can see that a VGS-X program calls main from the initial entry point crt0.
Issuing a reset request for VGS-X.
Issuing an exit request for VGS-X.
In the Emulator for Debug (SDL2), the value written here becomes the process exit code.
Addresses from 0xE80000 to 0xE8FFFC can be used as user-defined I/O.
For detailed usage instructions, refer to the User-Defined I/O section in the Runtime Implementation Guide.
The Video Game System Standard Library is a specification for a C language library designed (standardized) to maintain source code compatibility for user programs across VGS-X and future VGS series as much as possible. This standard specification has been designed with the policy of comprehensively providing all the functions necessary for developing the “Typical 2D Games”.
All hardware functions of the VGS-X specified in this README.md can be utilized from game programs written in C language through this library.
| Library | Header File | Desctiption |
|---|---|---|
libc.a (-lc) |
vgs.h | Basic Function |
liblog.a (-llog) |
log.h | Logging Function |
Since each function specification is documented in Doxygen format within header files, entering the function name in a code editor such as Visual Studio Code with the correct C/C++ plug-in installed will provide the relevant specification suggestions.
libc.a is a C library that defines APIs to help develop games on VGS series.
This library is always linked implicitly (-lc), so you do not need to specify it with the linker's -l option.
Basic Functions can be classified into Video Game Functions and Standard Functions. All these functions can be used by including the header file vgs.h.
#include <vgs.h>| Category | Function | Description |
|---|---|---|
| system | vgs_abort |
Abort with Stack Backtrace |
| system | vgs_vsync |
Synchronize the V-SYNC (screen output with 60fps) |
| system | vgs_user_in |
User-Defined I/O (Input) |
| system | vgs_user_out |
User-Defined I/O (Output) |
| cg | vgs_ptn_copy |
Copy Character Pattern. |
| cg | vgs_ptn_transfer |
Transfer Character Pattern. |
| cg | vgs_pal_get |
Get a color code from the Palette. |
| cg | vgs_pal_set |
Set a color code to the Palette. |
| cg:bg | vgs_bg_width |
Get the Name Table width in Character Pattern Mode. |
| cg:bg | vgs_bg_height |
Get the Name Table height in Character Pattern Mode. |
| cg:bg | vgs_chr_width |
Get the Visible Name Table width in Character Pattern Mode. |
| cg:bg | vgs_chr_height |
Get the Visible Name Table height in Character Pattern Mode. |
| cg:bg | vgs_put_bg |
Display a character on the BG in Character Pattern Mode |
| cg:bg | vgs_print_bg |
Display a string on the BG in Character Pattern Mode |
| cg:bg | vgs_cls_bg_all |
Clear all BGs |
| cg:bg | vgs_cls_bg |
Clear a specific BG |
| cg:bmp | vgs_draw_mode |
BG Mode Switching: Bitmap or Character Pattern |
| cg:bmp | vgs_draw_window |
Set a window to display only a specific rectangular area in Bitmap Mode. |
| cg:bmp | vgs_read_pixel |
Read a pixel on the BG in Bitmap Mode |
| cg:bmp | vgs_draw_pixel |
Draw a pixel on the BG in Bitmap Mode |
| cg:bmp | vgs_draw_line |
Draw a line on the BG in Bitmap Mode |
| cg:bmp | vgs_draw_lineH |
Draw a horizontal line on the BG in Bitmap Mode |
| cg:bmp | vgs_draw_lineV |
Draw a vertical line on the BG in Bitmap Mode |
| cg:bmp | vgs_draw_box |
Draw a rectangle on the BG in Bitmap Mode |
| cg:bmp | vgs_draw_boxf |
Draw a filled-rectangle on the BG in Bitmap Mode |
| cg:bmp | vgs_draw_clear |
Clear a specific rectangular area to zero. |
| cg:bmp | vgs_draw_character |
Draw a character-pattern on the BG in Bitmap Mode |
| cg:bg+bmp | vgs_skip_bg |
Skip Rendering a Specific BG |
| cg:bg+bmp | vgs_scroll |
Scroll BG |
| cg:bg+bmp | vgs_scroll_x |
Scroll BG (X) |
| cg:bg+bmp | vgs_scroll_y |
Scroll BG (Y) |
| cg:sp | vgs_sprite_priority |
Set sprite display priority. |
| cg:sp | vgs_sprite |
Set OAM attribute values in bulk |
| cg:sp | vgs_sprite_hide_all |
Make all sprites invisible. |
| cg:sp | vgs_oam |
Get an OAM record. |
| cg:sp | vgs_sprite_alpha8 |
Set the sprite's alpha value with 8-bit precision. |
| bmpfont | vgs_pfont_init |
Proportional Font Initialization. |
| bmpfont | vgs_pfont_get |
Acquiring Proportional Font Information. |
| bmpfont | vgs_pfont_set |
Setting Proportional Font Information. |
| bmpfont | vgs_pfont_print |
Drawing strings using Proportional Font |
| bmpfont | vgs_pfont_strlen |
Width of a string displayed in a Proportional Font (in pixels). |
| bmpfont | vgs_k8x12_print |
Drawing strings using k8x12 Japanese Font. |
| bgm | vgs_bgm_master_volume |
Set master volume of background music |
| bgm | vgs_bgm_master_volume_get |
Get master volume of background music |
| bgm | vgs_bgm_play |
Play background music |
| bgm | vgs_bgm_pause |
Pause background music |
| bgm | vgs_bgm_resume |
Resume background music |
| bgm | vgs_bgm_fadeout |
Fadeout background music |
| sfx | vgs_sfx_master_volume |
Set master volume of sound effect |
| sfx | vgs_sfx_master_volume_get |
Get master volume of sound effect |
| sfx | vgs_sfx_play |
Play sound effect |
| sfx | vgs_sfx_stop |
Stop sound effect |
| sfx | vgs_sfx_stop_all |
Stop the all of sound effects |
| gamepad | vgs_key_up |
Check if the up directional pad is pressed. |
| gamepad | vgs_key_down |
Check if the down directional pad is pressed. |
| gamepad | vgs_key_left |
Check if the left directional pad is pressed. |
| gamepad | vgs_key_right |
Check if the right directional pad is pressed. |
| gamepad | vgs_key_a |
Check if the A button is pressed. |
| gamepad | vgs_key_b |
Check if the B button is pressed. |
| gamepad | vgs_key_x |
Check if the X button is pressed. |
| gamepad | vgs_key_y |
Check if the Y button is pressed. |
| gamepad | vgs_key_code |
Retrieve the state of the directional pad and ABXY buttons being pressed in uint8_t code format. |
| gamepad | vgs_key_code_up |
Key code check: D-pad Up |
| gamepad | vgs_key_code_down |
Key code check: D-pad Down |
| gamepad | vgs_key_code_left |
Key code check: D-pad Left |
| gamepad | vgs_key_code_right |
Key code check: D-pad Right |
| gamepad | vgs_key_code_a |
Key code check: A button |
| gamepad | vgs_key_code_b |
Key code check: B button |
| gamepad | vgs_key_code_x |
Key code check: X button |
| gamepad | vgs_key_code_y |
Key code check: Y button |
| gamepad | vgs_key_type |
Get the Gamepad Type currently connected. |
| gamepad | vgs_button_id_a |
Get the Button ID for the A button on the connected gamepad. |
| gamepad | vgs_button_id_b |
Get the Button ID for the B button on the connected gamepad. |
| gamepad | vgs_button_id_x |
Get the Button ID for the X button on the connected gamepad. |
| gamepad | vgs_button_id_y |
Get the Button ID for the Y button on the connected gamepad. |
| gamepad | vgs_button_id_start |
Get the Button ID for the Start button on the connected gamepad. |
| gamepad | vgs_button_name |
Get the Name String of the button identifier. |
| save | vgs_save |
Save save data. |
| save | vgs_load |
Load save data. |
| save | vgs_save_check |
Check the size of save data. |
| save | vgs_seq_open_w |
Open a Large Sequencial File for write. |
| save | vgs_seq_write |
Write a byte data to a Large Sequencial File. |
| save | vgs_seq_commit |
Commit a Large Sequencial File for write. |
| save | vgs_seq_open_r |
Open a Large Sequencial File for write. |
| save | vgs_seq_read |
Read a byte data to a Large Sequencial File. |
| calendar | vgs_utc_year |
Retrieves the current year in UTC. |
| calendar | vgs_utc_month |
Retrieves the current month in UTC. |
| calendar | vgs_utc_mday |
Retrieves the current day of month in UTC. |
| calendar | vgs_utc_hour |
Retrieves the current hour in UTC. |
| calendar | vgs_utc_minute |
Retrieves the current minute in UTC. |
| calendar | vgs_utc_second |
Retrieves the current second in UTC. |
| calendar | vgs_local_year |
Retrieves the current year in the local timezone. |
| calendar | vgs_local_month |
Retrieves the current month in the local timezone. |
| calendar | vgs_local_mday |
Retrieves the current day of month in the local timezone. |
| calendar | vgs_local_hour |
Retrieves the current hour in the local timezone. |
| calendar | vgs_local_minute |
Retrieves the current minute in the local timezone. |
| calendar | vgs_local_second |
Retrieves the current second in the local timezone. |
| Category | Function | Description |
|---|---|---|
| stdlib | vgs_rand |
Obtain a 16-bit random value |
| stdlib | vgs_rand32 |
Obtain a 32-bit random value |
| stdlib | vgs_srand |
Set the random number seed |
| stdlib | vgs_exit |
Exit process |
| string | vgs_d32str |
Convert a 32-bit signed integer to a string |
| string | vgs_u32str |
Convert a 32-bit unsigned integer to a string |
| string | vgs_memcpy |
High-speed memory copy using DMA Copy |
| string | vgs_memset |
High-Speed bulk memory writing using DMA Set |
| string | vgs_strlen |
High-Speed string length retrieval using DMA Search |
| string | vgs_sjis_from_utf8 |
Convert UTF-8 string to SJIS using DMA. |
| string | vgs_strchr |
Search for specific characters in a string |
| string | vgs_strrchr |
Search for specific characters in a string that right to left |
| string | vgs_strcmp |
Compare strings |
| string | vgs_stricmp |
Case-insensitive string comparison. |
| string | vgs_strncmp |
Comparing strings of a specific length |
| string | vgs_strstr |
Search for a specific string in a string |
| string | vgs_strcpy |
Copy the string. |
| string | vgs_strcat |
Concatenate two strings. |
| ctype | vgs_atoi |
Convert a string to an integer. |
| ctype | vgs_isdigit |
Check if a character is a number |
| ctype | vgs_isupper |
Check if a character is an uppercase |
| ctype | vgs_islower |
Check if a character is a lowercase |
| ctype | vgs_isalpha |
Check if a character is an alphabet |
| ctype | vgs_isalnum |
Check if a character is an alphabet or a digit |
| ctype | vgs_toupper |
Convert a lowercase letter to an uppercase letter |
| ctype | vgs_tolower |
Convert an uppercase letter to a lowercase letter. |
| math | vgs_degree |
Calculate the angle between two points (in degrees) |
| math | vgs_sin |
Calculate integer sine from the angle in degrees |
| math | vgs_cos |
Calculate integer cosine from the angle in degrees |
| math | vgs_abs |
Calculate the absolute value of an integer. |
| math | vgs_sgn |
Determine whether an integer is positive, negative or zero. |
| math | vgs_hitchk |
Rectangular Collision Detection. |
liblog.a is a library that helps with debug logging (print debug).
To use this library, you must specify the -llog option at link time.
#include <log.h>| Function | Description |
|---|---|
vgs_print |
Output text to the console (no line breaks) |
vgs_println |
Output text to the console (with line breaks) |
vgs_putlog |
Output formatted string logs to the console. |
vgs_putlog can display embedded characters using %d, %u, and %s.
Note that %d corresponds to int32_t and %u corresponds to uint32_t. (Using variables of type 16-bit int or 8-bit char instead will corrupt the stack.)
// Example
vgs_putlog("d32=%d, u32=%u, str=%s", (int32_t)123, (uint32_t)456, "text");This section provides a manual for the command-line tools included in this repository. These tools are designed to assist each stage of the VGS-X development workflow, such as building programs, converting assets, and generating ROM images.
You do not need to understand or use all of these tools from the beginning. Refer to the relevant tools as needed, depending on your implementation details and development phase.
| Name | Description |
|---|---|
| vgsx | VGS-X Emulator for Debug |
| bin2var | Convert binary files to C language code |
| bmp2chr | Make CHR data from .bmp or .png file |
| bmp2img | Make Bitmap Sprite data from .bmp or .png file |
| bmp2pal | Make initial palette from .bmp or .png file |
| csv2var | Convert Tiled Map Editor CSV format to binary format. |
| makeprj | Create a new project |
| makerom | Make ROM file from Program and Assets |
| vgmplay | Play a .vgm file from the command line |
Path: ./tools/sdl2/
This is a VGS-X emulator built using SDL2.
It is primarily provided for debugging purposes during game development.
usage: vgsx [-i]
[-d]
[-g /path/to/pattern.chr]
[-c /path/to/palette.bin]
[-b /path/to/bgm.vgm]
[-s /path/to/sfx.wav]
[-x expected_exit_code]
{ /path/to/program.elf | /path/to/program.rom }
- Specifying the
-ioption causes the application to launch after the boot logo appears. In this case, the file must be in the ROM format created bymakeromcommand. - When the
-doption is specified, the RAM and save data will be dumped when the program exits. - The
-g,-b, and-soptions can be specified multiple times. - Program file (
.elf) or ROM file (rom) are automatically identified based on the header information in the file header. - The
-xoption is intended for use in testing environments such as CI. If the exit code specified by the user program matches the expected value, the process exits with 0; otherwise, it exits with -1. When this option is specified, SDL video and audio output is skipped.
Path: ./tools/bin2var
Converts a binary file into program code for a const uint8_t array in C language.
For example, it comes in handy when you want to use files such as stage map data, scenario scripts and text, or proprietary image formats within your program.
bin2var /path/to/binary.rom [u8|u16|u16l|u16b]
Remarks
- The conversion results are output to standard output, so please redirect them for use.
u8: Output input file as numerical values in uint8_t (default)u16: Output input file as numerical values in uint16_t (default)u16l: Input files shall be in little-endian (equivalent tou16).u16b: Input files shall be in big-endian.
The
u16boption is provided for cases where you wish to use binary files created in big-endian environments, such as the X68000, with VGS-X.
Path: ./tools/bmp2chr
Generates a VGS-X Character Pattern from either
a 256-color or 16-color .bmp (Windows Bitmap) file, or a 256-color .png file without an alpha channel.
usage: bmp2chr input.png output.chr
Remarks:
- The image width and height must be multiples of 8.
- Tiles are read sequentially from the top-left corner in 8×8-pixel units.
Path: ./tools/bmp2img
Generates VGS-X Bitmap Sprite–format pixel data from a
256-color or 16-color .bmp (Windows Bitmap) file, or a 256-color .png file without an alpha channel.
Usage: bmp2img input.(png|bmp) output.img
- The image width and height must be multiples of 8.
- The
.imgfiles produced by this tool are intended to be linked into your program after being converted with the bin2var command.
Path: ./tools/bmp2pal
Generates initial Palette data for VGS-X from either
a 256-color or 16-color .bmp (Windows Bitmap) file, or a 256-color .png file without an alpha channel.
usage: bmp2pal input.png palette.dat
Path: ./tools/csv2var
Convert Tiled Map Editor CSV format to binary format.
usage: csv2var input.csv [u8|u16]
Remarks
- This is designed to work only with CSV format for layerless Tiled Map Editor; operation with other formats is undefined.
- The conversion results are output to standard output, so please redirect them for use.
u8: Output input file as numerical values in uint8_t (default)u16: Output input file as numerical values in uint16_t (default)
Path: ./tools/makeprj
Create a new game project.
Usage: makeprj /path/to/project
Remarks:
- The
makeprjcommand is a simple shell script. - The project path must specify a directory that does not exist.
- Project directories created with the
makeprjcommand are initialized with Git and include the latest master branch of the suzukiplan/vgsx repository as a submodule at the time of command execution. This ensures compatibility even if VGS-X specifications change. Of course, you can also update the vgsx submodule to the latest state within your game project repository. - You can rename or move the project's root directory later without any issues.
The steps to update VGS-X to the latest version in your project are as follows:
cd /path/to/your_project
cd vgsx
git pull origin master
cd ..
git commit -m "update submodule" vgsxPlease note that since submodule initialization always occurs within
make all, you must commit any submodule updates beforehand.
Path: ./tools/makerom
Generates a ROM file that combines the program and assets into a single file.
usage: makerom -o /path/to/output.rom
-e /path/to/program.elf
[-c /path/to/palette.bin]
[-g /path/to/pattern.chr ...]
[-b /path/to/bgm.vgm ...]
[-s /path/to/sfx.wav ...]
Remarks:
- The
-g,-b, and-soptions can be specified multiple times. - The
-g,-b, and-soptions can also specify multiple files in the format-g file1 file2 file3. - Files are read sequentially from the specified file.
- The character pattern specified with the first
-goption is loaded at index 0, and the index of the pattern specified with the second-goption is the next one.
Play a .vgm file from the command line.
usage: vgmplay /path/to/bgm.vgm
This command is not built by default, so please build it as needed before use.
This section is not intended for developing VGS-X games.
It provides guidance and reference information for developers who want to
implement a runtime environment (emulator or execution platform)
that runs the VGS-X virtual hardware specification.
The SDL2-based runtime included in this repository is only one reference implementation, primarily intended for development and verification on PC platforms. VGS-X is designed as a platform-independent virtual hardware specification, and developers are free to implement their own runtimes for other environments or platforms as needed.
The content of this section serves as design guidance and implementation hints to help interpret and realize the VGS-X specification correctly. Game developers do not need to read this section unless they are interested in runtime or emulator implementation.
- Add the core source code (./src) to your C++ project. (For specific examples of the required core source code, refer to ./tools/sdl2/Makefile.)
#include "vgsx.h"- You can run the VGS-X emulator via the singleton instance
vgsxofVGSXclass.
First, call the VGSX::enableBootBios method or the VGSX::disableBootBios method to configure whether to boot the BIOS. Then, use the VGSX::loadRom method to load your ROM file created with the makerom command.
vgsx.enableBootBios();
vgsx.loadRom(romData, romSize);Note that the romData area must not be freed while VGS-X is running.
Booting the BIOS is optional, but it is recommended that you boot it whenever possible.
While the result of the VGSX::isExit method is false (while the user program has not terminated), the game runs by repeatedly executing the following processing.
- Set
vgsx.key.{up|down|left|right|a|b|x|y|start}to 1 if the gamepad's button is pressed, 0 if not pressed. - Execute one frame (60fps) of the MC68030 using the
VGSX::tickmethod. - The
VGSX::getDisplaymethod retrieves the pixel data to be displayed and executes screen rendering. - The
VGSX::tickSoundmethod executes the sound processor for one frame (sound buffering interval).
VGSX::tickcontinuously advances the MC68030 by 4Hz intervals until the user program either inputs V-SYNC or exits.- The execution interval of
VGSX::tickmust be 60 times per second. - When executing the
VGSX::tickmethod and theVGSX::tickSoundmethod in parallel on different threads, you must implement that exclusion control.
- Typical OS sound APIs perform fixed-size buffering in a separate thread via callbacks, so the
VGSX::tickSoundmethod assumes it will be called within that callback. - The
VGSX::tickSoundmethod must be executed at intervals corresponding to the buffer size of the PCM (44100Hz, 16bits, 2ch) specified as an argument.
When using user-defined I/O, describe the callback processing for when the user-defined I/O is executed using the VGSX::subscribeInput method or the VGSX::subscribeOutput method before calling the VGSX::tick method.
// Subscribe Input
vgsx.subscribeInput([](uint32_t port) {
uint32_t result = myInputFunction(port);
return result;
});
// Subscribe Output
vgsx.subscribeOutput([](uint32_t port, uint32_t value) {
myOutputFunction(port, value);
});By utilizing user-defined I/O, you can implement native processing that cannot be implemented on the MC68k side, such as retrieving Steam leaderboards and unlocking achievements.
This section lists the licenses of the software and assets related to VGS-X.
Although VGS-X is built using multiple open-source components, not all of them are strictly required in every use case. Each library listed below serves a different purpose and has a different role within the overall system.
The following components are used internally by the VGS-X virtual hardware and its reference implementation, and are considered required parts of VGS-X:
- MC680x0 Emulator - Musashi
- Copyright © 1998-2001 Karl Stenerud
- License: MIT
- FM Sound Chip Emulator - ymfm
- Copyright (c) 2021, Aaron Giles
- License: 3-clause BSD
- Japanese Font - k8x12
- Created by Num Kadoma
- License: Free Software
- VGS-X and VGS Standard Library for MC68030
- Copyright (c) 2025-2026 Yoji Suzuki.
- License: MIT
The following component is not required by the VGS-X specification itself. It is only necessary when developing or using the SDL2-based runtime implementation included in this repository.
- SDL2
- Copyright (C) 1997-2025 Sam Lantinga slouken@libsdl.org
- License: ZLIB License
If you implement your own runtime environment or target a platform that does not rely on SDL2, this dependency is not required.






