Skip to content

Emulator core for a fixed virtual game console defining a stable MC68030-based hardware model with YM2612 FM sound and a custom VDP.

License

MIT and 3 other licenses found

Licenses found

MIT
LICENSE-Musashi.txt
Zlib
LICENSE-SDL2.txt
MIT
LICENSE-VGSX.txt
BSD-3-Clause
LICENSE-ymfm.txt
Notifications You must be signed in to change notification settings

suzukiplan/vgsx

VGS-X CircleCI

vgsx.png

VGS Philosophy

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.

Relationship to VGS-Zero

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.

About VGS-X

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:

VDP Features:

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 Runtime Philosophy and Portability

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.

First Step Guide

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.

Setup Build Environment

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.

Setup Build Environment: macOS

Please install m68k-elf-gcc and SDL2 in an environment where Xcode and Homebrew are installed.

brew install m68k-elf-gcc
brew install sdl2

Setup Build Environment: Ubuntu Linux

Below 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-libgcc

Add 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!

Build and Execute an Example

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
make

screen shot

How to Create a New Project

You 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/MyGame

Compatibility Policy

VGS-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).

Architecture Reference Manual

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.

Screen Specification

  • 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).

4k Display

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.

Memory Map

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.

Program

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.h provided by GCC.

Character Pattern

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.

Character Pattern RAM

Palette

  • 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.

Name Table

  • 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.

Attribute

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 (Object Attribute Memory)

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.

(Size of Sprite)

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 |
|        |        |        |        |
+--------+--------+--------+--------+

(Rotate of Sprite)

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.

(Scale of Sprite)

  • You can specify the magnification rate as a percentage on the scale within the range of 0 to 400.
  • Setting either slx or sly to a value other than zero will prevent scaling of either the X or Y axis.

(Alpha Blend of Sprite)

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.

(Mask of Sprite)

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.

(High Priority Flag)

Setting the high priority flag pri allows the drawing priority to be set higher than sprites without pri set.

(Bitmap Sprite)

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)²

VDP Register

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.

0xD20000: Skip Screen Update

Setting a value other than zero to this register will skip the screen update every frame (60fps).

0xD20004: Sprite Position

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

0xD20008-0xD20024: Hardware Scroll

The hardware scroll register behaves differently in Character Pattern Mode and Bitmap Mode.

(for Character Pattern 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.

(for Bitmap Mode)

  • Writing a positive number to SX scrolls the screen right by the specified number of pixels.
  • Writing a negative number to SX scrolls the screen left by the specified number of pixels.
  • Writing a positive number to SY scrolls the screen down by the specified number of pixels.
  • Writing a negative number to SY scrolls the screen upward by the specified number of pixels.
  • The area after scrolling will be cleared to zero.

0xD20028-0xD20034: Bitmap Mode

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.

0xD20038-0xD20048: Clear Screen

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.

0xD2004C-0xD20068: Bitmap Graphic Draw

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:

  1. Reading G_EXE allows you to read the color of the pixel drawn at the (G_X1, G_Y1) position on the background plane specified by G_BG.
  2. When drawing a character, specify the palette number (0 to 15) in G_COL and the pattern number (0 to 65535) in G_OPT. Additionally, setting the most significant bit of G_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.

0xD2006C-0xD20078: Skip Rendering a Specific BG

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.

0xD2007C-0xD2008C: Proportional Font

  • Setting the starting character pattern number to 0xD2007C (PF_INIT) initializes the coordinate information for proportional fonts.
  • At PF_INIT, PF_DX and PF_WIDTH are initialized appropriately, but PF_DY is set to a fixed value determined by the character code.
    • '_', '.', ',', 'g' and 'j' are PF_DY = 1
    • 'p', 'q' and 'y' are PF_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 of PF_PTN
  • 0xD20088 (PF_DY): Read or Update a Y-coodinate difference of PF_PTN
  • 0xD2008C (PF_WIDTH): Read or Update a width of PF_PTN

See the example of usage: ./example/05_pro-font/program.c

usage

0xD20090-0xD20094: Copy Character Pattern

Copies data from a specified pattern number to another specified pattern number.

  1. Set the source pattern number in CP_FR (0xD20090).
  2. Specify the destination pattern number in CP_TO (0xD20094).

Remarks:

  • The copy completes immediately when CP_TO is written.

0xD20098-0xD200A0: Transfer Character Pattern

Transfers data from a specified memory address to a specified pattern number.

  1. Set the source memory address in TR_ADDR (0xD20098).
  2. Specify the transfer size (in bytes) in TR_SIZE (0xD2009C).
  3. Transfer to the pattern number specified by TR_TO (0xD200A0).

Remarks:

  • The memory address specified in TR_ADDR must contain raw character pattern data in the Character Pattern Table format.
  • TR_SIZE must be a multiple of 32.
  • The transfer completes immediately when TR_TO is written.

I/O Map

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.

Address In Out Description
0xE00000 o - V-SYNC
0xE00000 - o Console Output
0xE00004 o o Random
0xE00008 - o DMA: Destination
0xE0000C - o DMA: Source
0xE00010 - o DMA: Argument
0xE00014 o o DMA: Execute
0xE00100 - o Angle: X1
0xE00104 - o Angle: Y1
0xE00108 - o Angle: X2
0xE0010C - o Angle: Y2
0xE00110 o o Angle: Get/Set Degree (0 to 359)
0xE00114 o - Angle: Get int-sin (-256 to 256)
0xE00118 o - Angle: Get int-cos (-256 to 256)
0xE01000 - o Play BGM
0xE01004 - o BGM Playback Options
0xE01008 o o Set/Get the BGM Master Volume
0xE01100 - o Play SFX
0xE01104 - o Stop SFX
0xE01108 o o Set/Get the SFX Master Volume
0xE02000 o - Gamepad: D-pad - Up
0xE02004 o - Gamepad: D-pad - Down
0xE02008 o - Gamepad: D-pad - Left
0xE0200C o - Gamepad: D-pad - Right
0xE02010 o - Gamepad: A button
0xE02014 o - Gamepad: B button
0xE02018 o - Gamepad: X button
0xE0201C o - Gamepad: Y button
0xE02020 o - Gamepad: Start button
0xE02100 o o Gamepad: Type
0xE02104 o - Gamepad: Get Button ID of A button
0xE02108 o - Gamepad: Get Button ID of B button
0xE0210C o - Gamepad: Get Button ID of X button
0xE02110 o - Gamepad: Get Button ID of Y button
0xE02114 o - Gamepad: Get Button ID of Start button
0xE02118 - o Gamepad: Get Button Name String (Button ID)
0xE0211C - o Gamepad: Get Button Name String (RAM address)
0xE03000 o - SaveData: Address
0xE03004 o o SaveData: Execute Save(out) or Load(in)
0xE03008 - o SaveData: Check Size
0xE03100 o - Sequencial: Open for Write
0xE03104 o - Sequencial: Write a Byte
0xE03108 o - Sequencial: Commit
0xE03110 o - Sequencial: Open for Read
0xE03114 - o Sequencial: Read a Byte
0xE04000 o - UTC: Year
0xE04004 o - UTC: Month
0xE04008 o - UTC: Day of Month
0xE0400C o - UTC: Hour
0xE04010 o - UTC: Minute
0xE04014 o - UTC: Second
0xE04020 o - Local: Year
0xE04024 o - Local: Month
0xE04028 o - Local: Day of Month
0xE0402C o - Local: Hour
0xE04030 o - Local: Minute
0xE04034 o - Local: Second
0xE7FFF4 o - Abort
0xE7FFF8 - o Reset
0xE7FFFC - o Exit
0xE80000 ~ 0xE8FFFC o o User-Defined I/O

0xE00000[in] - V-SYNC

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.

0xE00000[out] - Console Output

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.

0xE00004[i/o] - Random

  • 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.

0xE00008-0xE00014[i/o] - Direct Memory Access

Destination Source Argument Execute Description
- ☑︎ target in Search
☑︎ ☑︎ size out(0) Copy
☑︎ ☑︎ size out(1) Set
☑︎ ☑︎ - out(2) UTF8 to SJIS

DMA Search

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 Argument are ignored.
  • The Source must 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 Source to the first matching byte. 0 may indicate either "found at Source" or "not found".
  • Please note that performing searches not expected to yield results can result in significant overhead.

DMA Copy

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 Source must be either a Program Address (0x000000 to Size-of-Program) or a RAM Address (0xF00000 to 0xFFFFFF).
  • The Destination must be a RAM Address (0xF00000 to 0xFFFFFF).
  • When both Source and Destination point to RAM addresses, overlapping copy ranges are acceptable. (A copy equivalent to memmove is performed.)
  • If an invalid address range (including the result of the addition) is specified, DMA will not be executed.

DMA Set

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 Source are ignored.
  • The Destination must 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.

DMA UTF8 to SJIS String

  • Executing this DMA operation copies the zero-terminated UTF-8 string set in Source, converted to SJIS, to Destination.
  • The Source must be either a Program Address (0x000000 to Size-of-Program) or a RAM Address (0xF00000 to 0xFFFFFF).
  • The Destination must be a RAM Address (0xF00000 to 0xFFFFFF).

0xE00100-0xE00118[io] - Angle

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 value degree to VGS_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.

./angle.png

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.

facing right pattern

For a concrete example, please refer to the implementation in ./example/03_rotate/program.c.

03_rotate

0xE010xx[o] - Background Music (BGM)

  • 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.

0xE011xx[o] - Sound Effect (SFX)

  • 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.wav

0xE020xx[i] - Gamepad

The VGS-X can capture button inputs from the D-pad, ABXY buttons, and Start button as shown in the diagram below.

gamepad.png

  • When buttons are pressed, the corresponding input result for 0xE020xx becomes non-zero.
  • The cursor keys and left stick are always linked.
  • Use the A button for confirmation operations.
  • Use the B button for cancel operations.
  • The X button is intended for use in operations requiring rapid button presses (e.g., as an attack button in shoot 'em ups).
  • The Y button is intended for use in auxiliary operations.
  • The Start button 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.

0xE021xx[io] - Gamepad Types

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"

0xE030xx[io] - SaveData

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.

Usage

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_EXECUTE saves that number of bytes from RAM to save.dat.
  • Reading from VGS_IO_SAVE_EXECUTE loads data from save.dat into RAM and returns the number of bytes actually loaded.

Remarks

  • VGS_OUT_SAVE_ADDRESS must 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.dat does 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.

0xE031xx[io] - Large Sequencial File I/O

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.

File Model

  • 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.dat to save255.dat) in the save data directory.

Write Operation

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.dat
  1. VGS_IO_SEQ_OPEN_W selects the target sequential file.
  2. Each write to VGS_IO_SEQ_WRITE appends one byte to an internal buffer.
  3. VGS_IO_SEQ_COMMIT writes the buffered data to the file, overwriting any existing file with the same index.

Read Operation

VGS_IO_SEQ_OPEN_R = index;        // Select file index (0–255)
uint32_t value = VGS_IO_SEQ_READ; // Read next byte
  1. VGS_IO_SEQ_OPEN_R loads the entire file into an internal buffer.
  2. Each read from VGS_IO_SEQ_READ returns the next byte in sequence.
  3. When all buffered data has been consumed, VGS_IO_SEQ_READ returns 0xFFFFFFFF.

Buffer Size and Limitations

  • 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_WRITE operations are silently ignored.
  • There is no support for streaming, chunked I/O, or incremental flushing.
  • The effective maximum recordable length depends entirely on this internal buffer size.

Remarks

  • 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.

(Write Large Sequencial File)

// 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.

(Read Large Sequencial File)

// 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_READ returns 0xFFFFFFFF.
  • 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.

0xE040xx[in] - Calendar

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)

0xE7FFF4[out] - Abort

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.

0xE7FFF8[out] - Reset

Issuing a reset request for VGS-X.

0xE7FFFC[out] - Exit

Issuing an exit request for VGS-X.

In the Emulator for Debug (SDL2), the value written here becomes the process exit code.

0xE8XXXX[i/o] - User-Defined I/O

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.

VGS Standard Library

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.

Static Libraries

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 - Basic Function

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>

(Video Game Functions)

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.

(Standard Functions)

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 - Logging Function

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");

Toolchain

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

VGS-X Emulator for Debug

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 -i option causes the application to launch after the boot logo appears. In this case, the file must be in the ROM format created by makerom command.
  • When the -d option is specified, the RAM and save data will be dumped when the program exits.
  • The -g, -b, and -s options 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 -x option 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.

bin2var

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 to u16).
  • u16b : Input files shall be in big-endian.

The u16b option is provided for cases where you wish to use binary files created in big-endian environments, such as the X68000, with VGS-X.

bmp2chr

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.

bmp2img

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 .img files produced by this tool are intended to be linked into your program after being converted with the bin2var command.

bmp2pal

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

csv2var

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)

makeprj

Path: ./tools/makeprj

Create a new game project.

Usage: makeprj /path/to/project

Remarks:

  • The makeprj command is a simple shell script.
  • The project path must specify a directory that does not exist.
  • Project directories created with the makeprj command 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" vgsx

Please note that since submodule initialization always occurs within make all, you must commit any submodule updates beforehand.

makerom

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 -s options can be specified multiple times.
  • The -g, -b, and -s options 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 -g option is loaded at index 0, and the index of the pattern specified with the second -g option is the next one.

vgmplay

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.

Runtime Implementation Guide

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.

1. Setup Your C++ Project

  1. Add the core source code (./src) to your C++ project. (For specific examples of the required core source code, refer to ./tools/sdl2/Makefile.)
  2. #include "vgsx.h"
  3. You can run the VGS-X emulator via the singleton instance vgsx of VGSX class.

2. Load a game ROM

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.

3. Main Loop Sequence

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.

  1. 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.
  2. Execute one frame (60fps) of the MC68030 using the VGSX::tick method.
  3. The VGSX::getDisplay method retrieves the pixel data to be displayed and executes screen rendering.
  4. The VGSX::tickSound method executes the sound processor for one frame (sound buffering interval).

4. VGSX::tick

  • VGSX::tick continuously advances the MC68030 by 4Hz intervals until the user program either inputs V-SYNC or exits.
  • The execution interval of VGSX::tick must be 60 times per second.
  • When executing the VGSX::tick method and the VGSX::tickSound method in parallel on different threads, you must implement that exclusion control.

5. VGS::tickSound

  • Typical OS sound APIs perform fixed-size buffering in a separate thread via callbacks, so the VGSX::tickSound method assumes it will be called within that callback.
  • The VGSX::tickSound method must be executed at intervals corresponding to the buffer size of the PCM (44100Hz, 16bits, 2ch) specified as an argument.

6. User-Defined I/O

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.

License

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.

Required (Used Internally by VGS-X)

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
  • Japanese Font - k8x12
  • VGS-X and VGS Standard Library for MC68030
    • Copyright (c) 2025-2026 Yoji Suzuki.
    • License: MIT

Optional (Runtime Implementation Dependent)

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.

If you implement your own runtime environment or target a platform that does not rely on SDL2, this dependency is not required.

About

Emulator core for a fixed virtual game console defining a stable MC68030-based hardware model with YM2612 FM sound and a custom VDP.

Topics

Resources

License

MIT and 3 other licenses found

Licenses found

MIT
LICENSE-Musashi.txt
Zlib
LICENSE-SDL2.txt
MIT
LICENSE-VGSX.txt
BSD-3-Clause
LICENSE-ymfm.txt

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages