Thursday, April 1, 2021

Z80 Programming Sample II

In the previous post, we checked out Z80 Programming Sample for the Sega Master System: an 8-bit video game console based on the Z80 chip. Here we used WLA-DX assembler for our development environment.

Here, we analyzed existing Indie game projects and disassembled classic 8-bit commercial games to better understand the Z80 development process. For completeness, we would now like to better understand this relationship between source code written in C using the devkitSMS and the underlying Z80 assembly code.

Let's check it out!

Software
Follow all instructions from the previous post: this documents how to setup all the pre-requisite software. Note: ensure you have downloaded and installed WLA-DX assembler + Visual Studio Code cross platform.

Process
Build small demo project in C using the devkitSMS. Follow the numerous posts from devkitSMS category to completion. Next, disassemble the output. Refactor the underlying Z80 assembly code using this process:

Step #1
Create Temp01 folder | copy output.sms. Launch Emulicious | open output.sms. Tools | Debugger | Ctrl + A select all disassembled Z80 assembly code | Save Temp01.asm. Follow instructions from previous post using Binary-File-Write utility replace all instances of ".incbin ..." to refer to binary data files in the data folder.

Step #2
Create Temp02 folder | copy output.sms + output.map. Launch Emulicious | open output.sms. In Debugger | Ctrl + A to select all disassembled Z80 assembly code that now has devkitSMS symbols | Save Temp02.asm.

Step #3
Create asm folder. Copy .vscode folder from above with launch.json and tasks.json. Copy build.bat and build.sh. Don't forget to grant execute permission chmod +x build.sh command. Copy data folder above.

Step #4
Merge Temp01.asm with Temp02.asm! That is keep the structure of Temp01.asm but replace all generic auto-generated labels from Temp01 with specific labels and code from Temp02.asm. Save result file as main.asm.

Step #5
Launch Visual Studio Code. Open Temp03 foder. Create sub-folders that replicate the original C source code structure e.g. banks, devkit, engine, object, screen. Start from the top of main.asm and refactor as follows:

.sdsctag
Begin with the .sdsctag which includes the ROM build major . minor version, author, name and description:
.sdsctag 1.0,"Van Halen","Van Halen Record Covers for the SMS Power! 2021 Competition","StevePro Studios"

memory_manager.inc
Create memory_manager.inc beneath devkit folder. Add .include to file. Move all memory map code in here.

enum_manager.inc
Create enum_manager.inc beneath devkit folder. Add .include to file. Move all .enum exports here. Rename RAM enum references to actual variables used throughout the codebase. Ensure RAM addresses are correct.

define_manager.inc
Create define_manager.inc beneath devkit folder. Add .include to this file. Move all .define definitions here.
.define VDPControl $bf
.define VDPData $be
.define VRAMWrite $4000
.define CRAMWrite $c000

out.inc
Create content folder. Create out.inc beneath content folder. Add .include to file after the LABEL_70_ block. Extract three OUT sections OUT128, OUT64 and OUT32 into out.inc. Set the .ORG address at each section.

psg_manager.inc
Create psg_manager.inc beneath devkit folder. Add .include to file after the main loop block. Extract all PSG functions from PSGStop to PSGSFXFrame into psg_manager.inc. Ensure RAM references replaced by enums.

devkit_manager.inc
Create devkit_manager.inc beneath devkit folder. Add .include to file. Extract all functions from SMS_init to SFX_CHANNELS2AND3 into devkit_manager.inc. Ensure all RAM references replaced by enums as above.

engine
Create the following *_manager.inc files beneath engine folder: asm, audio, content, cursor, font, input, record, screen, scroll, storage, timer. Extract all code from main.asm to each corresponding engine file.

object
Create the following *_object.inc files beneath object folder: cursor, record. Extract all code from main.asm to each corresponding object file. Don't forget to add the corresponding .include statements in main.asm.

screen
Create the following *_screen.inc files beneath screen folder: none, splash, title, scroll, select and record. Extract all code from main.asm to each corresponding screen file. Add corresponding .include statements.

content
Create gfx.inc and psg.inc files beneath content folder. Extract all code from main.asm to each content file.

sms_manager.inc
Create sms_manager.inc beneath devkit folder. Add .include to file after all div functions. Extract all functions from UNSAFE_SMS_copySpritestoSAT to SMS_loadPSGaidencompressedTiles into the sms_manager.inc file.

bank_manager.inc
Create bank_manager.inc beneath engine folder. Add .include to file as last line of main.asm. Remove auto-generated data for SDSC and .incbin. In banks_manager.inc update labels + set .incbin to banks resources.

Sections
Finally, wrap logical blocks of code as .section free and hardcoded address code as .section force for example $0000, $0038 and $0066. Wrap banked code as .section free or superfree + ensure all BANK # has SLOT 2.

Opcodes
Manually disassemble code using the full Z80 Opcode list or Opcodes sorted by value. Any byte data can be converted using the Hex to ASCII text converter. Finally, here is a list of common opcodes regularly found:
 Opcode Mnemonic  Opcode Mnemonic  Opcode Mnemonic
 $00 nop  $C1 pop bc  $18 nn ld a, nn
 $C9 ret  $D1 pop de  $3E nn ld a, nn
 $3C inc a  $E1 pop hl  $DD $39 add ix, sp
 $3D dec a  $F1 pop af  $DD $E1 pop ix
 $A7 and a  $C5 push bc  $DD $E5 push ix
 $AF xor a  $D5 push de  $DD $F9 ld sp, ix
 $B7 or a  $E5 push hl  $C3 nnnn jp &nnnn
 $BF cp a  $F5 push af  $CD nnnn call &nnnn
IMPORTANT: nn represents a one byte operand in table above whereas nnnn represents two bytes operand.

Troubleshooting
Ensure that labels do not begin with an underscore otherwise you may receive FIX_REFERENCES error when assembling Z80 code with WLA-DX. Also, ensure all disassembled labels, esp. labels with "$" are removed. Otherwise when you debug step through Z80 source code breakpoints may skipped via disassembled code.

Download code sample here.

Summary
Although Z80 programming for the Sega Master System may be very niche development style, it still attracts interest on coding medium / large sized games using WLA-DX with further options for Z80 IDEs using Eclipse and other information on Visual Studio Code for SMS Development including sample SMS Framework to test.

Now that we have setup a productive Z80 assembler development environment and better understand this relationship between source code written in C using the devkitSMS and the underlying Z80 assembly code, we are now finally in a great spot to build our own Z80 projects from scratch for the Sega Master System!

Wednesday, March 17, 2021

Z80 Programming Sample

In the previous post, we checked out Z80 Programming Setup for the Sega Master System: an 8-bit video game console based on the Z80 chip. Here we used WLA-DX assembler for our development environment.

Now that we are setup, we would like to analyze existing Indie game projects for the Sega Master System and disassemble some classic 8-bit commercial games to better understand the Z80 development process.

Let's check it out!

Software
Follow all instructions from the previous post: this documents how to setup all the pre-requisite software. Note: ensure you have downloaded and installed WLA-DX assembler + Visual Studio Code cross platform.

Homebrew Games
In the previous post, we setup the obligatory "Hello World" program. Now we would like to analyze some larger Z80 projects. Checkout "Racing Game" article on SMS Power! which is an in depth coding tutorial.

Car Racer (classic)
Create C:\CarRacerClassic or ~/CarRacerClassic. Copy .vscode folder from previous post with launch.json + tasks.json. Copy build.bat + build.sh. Don't forget to grant execute permission chmod +x build.sh command.

Download source code. Copy Assets folder to CarRacerClassic. Copy main.asm file from Racer (classic) folder Version 1.12 here also. Launch VS Code. Some things to remember when coding Z80 source cross platform:
  1.  Ensure forward slash "/" used at all times for cross platform development
  2.  Ensure case sensitive folders + files are used at all times for include files
  3.  Ensure carriage returns is used between variables to avoid wla-dx errors

Press Ctrl + Shift + B to execute build script => compile, link and run output.sms launched from Emulicious! Assumption Emulicious installed C:\SEGA\Emulicious on Windows or ~/SEGA/Emulicious Mac OS/X + Linux.

Debugging
Launch Emulicious externally. Ensure Emulicious Debugger is installed with VS Code as per previous post. Open main.asm and set breakpoints. Press F5. Emulicious debugger should now break into Z80 assembly source code! Step through + investigate register variables, stackframes, access watch window, call stack:

Car Racer (rebooted)
Create C:\CarRacerRebooted or ~/CarRacerRebooted. Copy .vscode folder from above with launch.json and tasks.json. Copy build.bat + build.sh. Don't forget to grant execute permission chmod +x build.sh command.

Download source code. Copy all assets folders with *.inc files to CarRacerRebooted. Copy main.asm file from Racer (rebooted) folder here also. Launch VS Code. Tweak Z80 assembly code as above to be cross platform.

Press Ctrl + Shift + B to execute build script => compile, link and run! Repeat process for all these projects:
 Sega Master System  Astroswab
 Sega Master System  Car Racer [classic]
 Sega Master System  Car Racer [reboot]
 Sega Master System  Digger Ball
 Sega Master System  Digger Chan
 
 Sega Master System  Fairy Forest
 Sega Master System  Jetpac
 Sega Master System  KunKun & KokoKun
 Sega Master System  Mega Man 2
 Sega Master System  Minesweeper
IMPORTANT
For all examples: Launch Emulicious separately first. In VS Code press F5 to debug step through Z80 code!

Commercial Games
Now let us enhance this process to disassemble some commercial games built for the Sega Master System. This way, we may gain insight into the early development process plus be able to hack original source code!

Transbot
Create C:\Transbot or ~/Transbot folder. Copy .vscode folder from above with launch.json and tasks.json files. Copy build.bat + build.sh too. Don't forget to grant execute permission chmod +x build.sh command.

Download Transbot ROM. Launch Emulicious | Open ROM. Tools menu | Debugger | press Ctrl + A to select all disassembled code. Save as Transbot.asm. Update all ".incbin ..." statements using the following utility:

Utility
Download Binary-File-Write utility. Copy both TransBot.asm and TransBot.sms files to input folder. Update the config file | set key="fileName" value to "Transbot". Run BinaryFileWrite.exe. Copy output to Transbot folder.

Launch VS Code. Open Transbot folder. All prior ".incbin..." statements should now refer to binary data files. Press Ctrl + Shift + B to execute build script => compile, link and run! Repeat process for all these projects:
 Sega Master System  After Burner
 Sega Master System  Alien Syndrome
 SG-1000 / SC-3000  Congo Bongo
 SG-1000 / SC-3000  Flicky
 Sega Master System  Golden Axe
 
 SG-1000 / SC-3000  Monaco GP
 Sega Master System  Out Run
 Sega Master System  Shinobi
 Sega Master System  Transbot
 Sega Master System  Wonder Boy
IMPORTANT
For all examples: Launch Emulicious separately first. In VS Code press F5 to debug step through Z80 code!

Flicky
Create C:\Flicky or ~/Flicky folder. Repeat entire process for Transbot as above but with Flicky.sg ROM. Copy the .vscode folder with launch.json and tasks.json files plus build.bat + build.sh. Retreive main.asm + data folder from utility. Press Ctrl + Shift + B to execute build script + press F5 to debug step through Z80 code!

Hack
Use this new setup to hack the original source code! For example, in Flicky you always start at level #1. Wouudn't it be cool to start at any level? Also, wouldn't it be cool to have infinite lives? Let's check it out!

Start level and lives count default values are hardcoded in ROM and loaded into RAM. After debug stepping through Flicky source code we find a piece of code that loads 20x bytes of ROM into RAM on game start:

Bytes $02C3 and $02C4 default to $01; could either of these be start level #1? Byte $02CA defaults to $02; could this be lives left? The corresponding data is loaded in RAM at $C0E7, $C0E8 and $C0EE respectively.

Launch Emulicious. Tools menu | Memory Editor | RAM. Right click $C0E7 | Toggle Watchpoint. Repeat for $C0E8 and $C0EE. Resume code. Play game and die! The value at RAM $C0EE decreases from $02 to $01.

Therefore, RAM $C0EE stores the lives count loaded from ROM $02CA! Replace the original $02 with $FF for "infinite" lives. Repeat process: complete level; see RAM $C0E8 stores start level loaded from ROM $02C4!


Summary
Now that we have a productive Z80 assembler development environment and analyzed some larger projects to better understand the development process we are in a great spot to build our own projects from scratch.

For completeness, we would still like to better understand relationship between Sega Master System source code written in C using the devkitSMS and connect the underlying Z80 assembly code generated accordingly. This will be the topic of the next post.

Sunday, February 14, 2021

Z80 Programming Setup

In 2013, we checked out Sega Console Programming to setup video game development environment for the Sega Master System: an 8-bit video game console based on the Z80 chip. Here we used WLA-DX assembler. Remember, original cartridge-based video games built for 8-bit Sega Retro Gaming consoles were written in pure assembly!

Now we would like to extend our game development environment to Windows and Mac OS/X and Linux for cross platform development and also add better support for automated builds with debugging functionality. Let's check it out!

Assembler
Recommended is the WLA-DX assembler. Git clone the wla-dx repository and follow OS specific instructions.

Windows
Clone wla-dx repository to C:\GitHub\vhelin. Instructions on GitHub describe how to build WLA-LX for Linux whereas WLA-DX can be built for Windows directly from Visual Studio 2017 from the wla-dx\windows folder.
 1. Start | run | cmd  5. Launch WLA DX.sln in Visual Studio 2017
 2. cd C:\GitHub\vhelin  6. Build solution as Release | x86 configuration
 3. git clone https://github.com/vhelin/wla-dx.git  7. WLA DX compiler wla-z80.exe built
 4. cd C:\GitHub\vhelin\wla-dx\windows  8. WLA DX linker wlalink.exe built
If you have followed z88dk Programming Setup tutorial and you already have ConTEXT installed then copy the updated binaries wla-z80.exe and wlalink.exe built from previous step to output folder C:\wlaz80win32.

Also, tweak the original Compile.bat file as all main entry points will now be via main.asm thus align main.o object file during wla-z80 compilation. Finally, it seems -drvs wlalink linker flag is now no longer required.
 echo Compile
 ::"%WLAPATH%wla-z80.exe" -o %1 main.o
   "%WLAPATH%wla-z80.exe" -o main.o %1
 echo Link
 ::"%WLAPATH%wlalink.exe" -drvs linkfile output.sms
   "%WLAPATH%wlalink.exe"       linkfile output.sms


Mac OS/X
Instructions on GitHub describe how to build WLA-LX for Linux whereas WLA-DX can be built for Mac OS/X using brew. Install brew as per instructions. Then follow all instructions here to install wla-dx on Mac OS/X.

Launch Terminal. Enter the following commands below. Accept all prompts to install the latest Xcode tools:
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" < /dev/null 2> /dev/null
Accept prompt to install the latest Xcode tools
brew install wla-dx
IMPORTANT
During installation, you may encounter the following error: homebrew-core is a shallow clone. To `brew update`, first run: git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow

At the terminal, type brew update or brew update --force. If you still get errors then type the following:
git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow
brew update --force
brew install wla-dx

Linux
Clone wla-dx repo to ~/GitHub/vhelin. Follow all instructions on GitHub which describes how to build WLA-LX for Linux. Launch Terminal | enter commands. After completion, wla-z80 and wlalink should work universally.
 1. cmake --version  5. mkdir build && cd build
 2. cd ~/GitHub/vhelin  6. cmake ..
 3. git clone https://github.com/vhelin/wla-dx.git  7. cmake --build . --config Release
 4. cd ~/GitHub/vhelin/wla-dx  8. cmake -P cmake_install.cmake


Visual Studio Code
Install VS Code for Windows + Mac OS/X + Linux. Install the following extensions for Z80 ASM development:
 ASM Code Lens  Enables code lens, references, hover info, symbol renaming + assembler outline
 Z80 Assembly  Z80 Assembly support for Visual Studio Code
 Z80 Macro Assembler  Support for Z80 macro-assemblers in Visual Studio Code
 WLA-DX for VSCode  VSCode language support for WLA-DX assembler


Hello World
Download and extract the obligatory "Hello World" to C:\HelloWorld or ~/HelloWorld. Rename file main.asm. Launch VS Code. Open HelloWorld folder. Some things to remember when coding Z80 source cross platform:
  1.  Ensure forward slash "/" used at all times for cross platform development
  2.  Ensure case sensitive folders + files are used at all times for include files
  3.  Ensure carriage returns is used between variables to avoid wla-dx errors

Add build.bat file to compile, link and run souce code on Windows and build.sh file to compile, link and run souce code on Mac OS/X + Linux. Don't forget to grant execute permission chmod +x build.sh command:
 build.bat  build.sh
 @echo off
 cls

 wla-z80 -o main.o main.asm 

 echo [objects] > linkfile
 echo main.o >> linkfile

 wlalink linkfile output.sms

 java -jar C:\SEGA\Emulicious\Emulicious.jar output.sms
 ::output.sms
 @echo off
 clear

 wla-z80 -o main.o main.asm

 echo [objects] > linkfile
 echo main.o >> linkfile

 wlalink linkfile output.sms

 java -jar ~/SEGA/Emulicious/Emulicious.jar output.sms
 #output.sms

Press Ctrl + Shift + B to execute build script. If/when promted to add tasks.json file: Configure Build Task... Create tasks.json file from template | Others. This will create .vscode hidden folder and tasks.json file here. tasks.json
{
    "version": "2.0.0",
    "label": "build",
    "type": "shell",
    "linux": {
        "command": "./build.sh"
    },
    "osx": {
        "command": "./build.sh"
    },
    "windows": {
        "command": "build.bat"
      },
    "presentation": {"echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": false, "clear": true},
    "group": {"kind": "build", "isDefault": true},
}
Press Ctrl + Shift + B to execute build script => compile, link and run output.sms launched from Emulicious!

IMPORTANT
Assumption Emulicious installed C:\SEGA\Emulicious on Windows or ~/SEGA/Emulicious Mac OS/X + Linux.


Emulicious Debugger
Now that we are able to compile, link and run Z80 assembler directly within Visual Studio Code the final step is to configure debugging. In VS Code, install Emulicious Debugger extension. Click the Run icon and "create a launch.json file". Choose Emulicious Debugger from the drop down. Complete launch.json file accordingly: launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "emulicious-debugger",
            "request": "launch",
            "name": "Launch in Emulicious",
            "program": "${workspaceFolder}/output.sms",
            "port": 58870,
            "stopOnEntry": true
        }
    ]
}

Launch Emulicious. Configure the options below. Open Tools menu | Debugger. Configure these options also:
 Tools menu | Remote Debugging | Enabled | CHECK  Debugger | File menu | Load Sources automatically
 Tools menu | Reopen Tools | CHECK  Debugger | Run menu | Suspend On Open

In Visual Studio Code, open main.asm and set breakpoints. Press F5. Emulicious debugger should now break and debug step through Z80 assembly source code! Access register variables, watch window, call stack etc.

Emulicious Debugger II
For completeness, to better understand relationship between Sega Master System source code written in C and Z80 assembly code, let's debug step through "Hello World" program written in C using the devkitSMS.

Follow the Hello World main.c program in devkitSMS Programming Setup. Open C:\HelloWorld folder in VS Code. Modify build.bat script ever so slightly that is add --debug flag to the SDCC commands for example:
  sdcc --debug -c -mz80 --std-sdcc99 main.c
  sdcc --debug -mz80 --no-std-crt0 --data-loc 0xC000 -o output.ihx crt0_sms.rel main.rel SMSlib.lib

Fortunately, we can leverage the same launch.json and tasks.json files as before. Launch Emulicious | Press F5. Emulicious debugger should now break and debug step through C source code! In the external debugger navigate the Z80 assembly code wrapped in C functions via output.map to better understand C / Z80 code!

TROUBLESHOOTING
If you see popup "connect ECONNREFUSED 127.0.0:58870" then this is because Emulicious is not running. Also, if F5 does not launch the debugger from VS Code then click output.sms and choose Debug File icon.


Summary
Now that we have a productive Z80 assembler development environment we are in a great spot to analyze existing Indie game projects directly from the SMS Power! Homebrew section and 8-bit commercial games! This will be the topic of the next post.

Friday, January 1, 2021

Retrospective XII

Last year, I conducted a simple retrospective for 2019. Therefore, here is a retrospective for 2020.

2020 Achievements
  • Transition 8-bit Sega Master System development setup to 16-bit Sega Genesis
  • Collaborates coding Sega Master System homebrew game project MARKanoIIId
  • Revise C/C++ programming techniques rebuilding classic code bases like Doom
  • Reverse engineers Sega 8-bit ROMs for fun Z80 assembly language code hacks
  • Upgrade MonoGame 3D model + custom shader content pipeline cross platform
  • Integrate Docker + Kubernetes as software project containerization and scaling
  • Expands programming skillsets into DevOps and employ Infrastructure as Code
  • Prepares Python machine learning environment available per future exploration
Note: transitioning 8-bit Master System development to 16-bit Genesis is an achievement!

2021 Objectives
  • Collaborate with 16-bit Sega MegaDrive community similar to 8-bit Sega Master System
  • Leverage MonoGame 3D development environment to complete cross platform projects
  • Incorporate Docker and/or Kubernetes into personal and professional software dispatch
  • Explore retro game development applications for modern AI + Machine Learning upskill

Collaboration
After years of self publishing video game projects, concerns of an over-saturated marketplace and fears that it will soon be impossible to make any progress as an indie developer, it is becoming more apparent that the next phase of independent game development will be powered more by collaboration.

The network effect of working collaboratively, where each person has enhanced access to various networks, may lead to future collaborations which could inevitably perpetuate throughout the indie game community.

Earlier in the year I was fortunate enough to collaborate with some of the coding elements on MARKanoIIId which was awesome and exposed stronger relationships with other developers, pixel artists and musicians.

Discord is great vehicle also to encourage participation as I was fortunate to help test the new Emulicious VS Code plugin for the Master System. I am hopeful experiences like these will broaden to the Sega MegaDrive!

Connection
Another motivation to transition from 8-bit to 16-bit stems from earlier this year Sega Master System project Candy Kid as features were cut due to the constant challenge to stay within the 32KB ROM game code limit.
Fortunately, Candy Kid being a Pacman clone, presents new opportunities to port to the Sega MegaDrive with additional capacity and the possibly to explore a connection between Artificial Intelligence and video games.

Video games are an interesting field of study for many Artificial Intelligence (AI) researchers especially with Pacman because it is simple enough to be understood quickly and does not require powerful machine to run.

One approach could be to train automatic bots to play video games like Pacman via Reinforcement Learning: RL algorithms learn policies that associate good actions to execute in different game states based on reward obtained during the game simulation. Reinforcement Learning has also been used in other domains such as First Person Shooters like Doom.

Therefore, retro game development with Pacman and Doom clones seem like an excellent avenue to pursue with regards to future applications in software with Artificial Intelligence, ML and Reinforcement Learning J

Sunday, November 15, 2020

SGDK Programming Sample

In the previous post, we checked out SGDK Programming Setup. The SGDK is a free development kit which provides code and tools to compile resources and support homebrew development for the Sega Mega Drive.

Using the SGDK, it is possible to write game code using the C language rather than pure 68000 assembly. Therefore, we would now like to extend this knowledge and write more detailed programming sample code. Let's check it out!

Software
Follow all instructions from the previous post: this documents how to setup the pre-requisite software.
Note: ensure you have downloaded and installed the SGDK and the GNU Compiler Collection [GCC].

Library
Ultimately, we would like to build + debug step thru the C source code during SGDK development from in Visual Studio. Therefore, we need to build custom version of SGDK library to replace functions with stubs.

Launch Visual Studio 2015. File | New | Project... | Visual C++ | Win32 | Win32 Project | Static Library:

Create two folders lib and src. Copy all SGDK header files from %GDK_WIN%\inc and %GDK_WIN%\res beneath the lib folder. For each header file create corresponding translation unit [*.c] file in the src folder.

Finally, implement each header file function as stub function in each translation unit. Build custom library. Copy _genesis.lib and _genesis.pdb binaries to the lib folder. This will be used to link sample source code. Download custom library here.

Usage
SGDK uses a generic makefile to compile projects. In order to be properly recognized by the makefile you need to organize your project folder structure as following: Project root add sub folders: inc, out, res, src
 inc   include files  *.h [C include file] or *.inc [assembly include file]
 out   output files  rom.bin to be created automatically by makefile when SGDK project is built
 res   resource files  *.res [resource definition file compiled by rescomp tool see bin/rescomp.txt]
 src   source files  *.c [C source file], *.s [68000 asm source file] or *.s80 [Z80 asm source file]


Hello World
Create folder C:\HelloWorld. Copy new SGDK custom library lib folder [above] here. Create sub-folder: dev. Change directory to dev folder and create the following sub-folders as indicated per Usage: inc, out, res, src

Launch Visual Studio 2015. File | New | Project... | Visual C++ | Win32 | Win32 Project
 Name:  Game
 Location:  C:\HelloWorld\dev
 Create directory for solution  UNCHECKED
OK

 Application type:  Console application
 Additional options:  Empty project CHECKED
Finish

First, remove x64 build configuration! Right click Solution | Properties. Click Configuration Manager button. Click Active solution platform drop down | Edit. Click x64 option | Remove. Now will have only Win32 build.

Add the main.h source code to Header Files using the inc folder. Add main.c to Source Files using src folder:
 main.h  main.c
 #ifndef __MAIN__
 #define __MAIN__

 #ifdef _CONSOLE
   #include "_genesis.h"
 #else
   #include <genesis.h>
 #endif

 #endif//__MAIN__
 #include "main.h"
 int main()
 {
 	VDP_drawText( "Hello Genny World!", 10, 13 );
 	while( 1 )
 	{
 		VDP_waitVSync();
 	}
 	return 0;
 }

Right click Project | Properties | Configuration Properties | General. Set Output and Intermediate directories:
 Output Directory:  $(SolutionDir)..\bin\$(ConfigurationName)
 Intermediate Directory:  $(SolutionDir)..\obj\$(ConfigurationName)

Right click Project | Properties | Configuration Properties | C++ | General. Set Additional Include Directories:

 Value:   $(SolutionDir)..\lib;$(ProjectDir)inc;$(ProjectDir)res;$(GDK_WIN)\inc;$(IncludePath)

Right click Project | Properties | Configuration Properties | Linker | General | Additional Library Directories:

 Value:   $(SolutionDir)..\lib

Right click Project | Properties | Configuration Properties | Linker | Input. Set the Additional Dependencies:

 Value:   _genesis.lib;%(AdditionalDependencies)
Press Ctrl + Shift + B or [F7] to build source code. Pressing F5 will now debug step through C source code!

IMPORTANT
The first time you F5 debug step through C source code you may be prompted to navigate to src directory.

Add the following build.bat script to the dev folder to automate process to build + run the ROM output file:
@echo off
cls
echo Building...

:: Time build START
set _time=%time: =0%
set /a _hours=100%_time:~0,2%%%100,_min=100%_time:~3,2%%%100,_sec=100%_time:~6,2%%%100,_cs=%_time:~9,2%
set /a _started=_hours*60*60*100+_min*60*100+_sec*100+_cs

:: Build
%GDK_WIN%\bin\make -f %GDK_WIN%\makefile.gen > NUL

:: Time build -END-
set _time=%time: =0%
set /a _hours=100%_time:~0,2%%%100,_min=100%_time:~3,2%%%100,_sec=100%_time:~6,2%%%100,_cs=%_time:~9,2%
set /a _duration=_hours*60*60*100+_min*60*100+_sec*100+_cs-_started
set /a _hours=_duration/60/60/100,_min=100+_duration/60/100%%60,_sec=100+(_duration/100%%60%%60),_cs=100+_duration%%100
echo.
echo Time taken: %_sec:~-2%.%_cs:~-2% secs
echo.

:: Run
C:\SEGA\Fusion\fusion.exe out\rom.bin
::C:\SEGA\gens\gens.exe %~dp0\out\rom.bin
Here we measure the build execution time. Also, suppress the output of the build script to keep things clean. The final solution should look like this:
In Visual Studio, add the build.bat script to Resource Files. Connect the build.bat script to Ctrl + 1 keyboard shortcut as per this post. Press Ctrl + 1 to build + run the ROM output file all from within Visual Studio 2015.

Congratulations! You have just written your first Mega Drive program using the SGDK.

Hello Resources
Import all resources into your project as media files that your game will use such as images for background tiles + sprites, audio for music + sound effects etc. Clone the "Hello World" project and follow these steps;

Change directory to res folder under dev folder. Copy resource here. Create resources.res here for example:
resources.res
IMAGE splash "splash.bmp" 0

Next execute build.bat script to compile resource and generate corresponding header file e.g. resources.h. In Visual Studio add resources.h to Header Files. Update main.h to include new resources.h header file in code:
main.h
#ifndef __MAIN__
#define __MAIN__
// ...
#include "resources.h"
#endif//__MAIN__

IMPORTANT
If resources.h does not auto generate or the contents do not change then delete the out folder try again!

Create folder gfx at same level as dev folder. Create sub folder res. Add dummy corresponding translation unit resources.c under res sub folder. In Visual Studio add resources.c to Source Files with following code:
resources.c
#ifdef _CONSOLE
  #include "_genesis.h"
  const Image splash = { NULL, NULL, NULL };
#endif

Update main.c to render image. Leverage conditional compilation to inject resource palette data at runtime:
main.c
#include "main.h"
int main()
{
	u16 *data = NULL;
#ifndef _CONSOLE
	data = splash.palette->data;
#endif
	VDP_setPalette( PAL1, data );
	VDP_drawImageEx( BG_A, &splash, TILE_ATTR_FULL( PAL1, 0, 0, 0, 1 ), 4, 2, 0, CPU );
	while( 1 )
	{
		VDP_waitVSync();
	}
	return 0;
}

Press F5 to build + debug step through C source code. Press Ctrl + 1 to build + run the new ROM output file.


REMEMBER
More information about all SGDK resources found here. Also, compile resources directly using this command:
cd C:\HelloWorld\dev\res
java -jar %GDK_WIN%\bin\rescomp.jar resources.res

Ensure an up-to-date version of Java is installed, e.g. version "12.0.2" 2019-07-16 otherwise builds may fail!
Exception in thread "main" java.lang.IndexOutOfBoundsException: off < 0 || len < 0 || off + len > b.length!


Hello Folders
Up until now, there have been no nested folders in the inc or src directories. As projects expand, it makes sense to group common code together in its own folder. Therefore, add subfolders and update the makefile.

Clone the "Hello World" project and follow these steps: Update any resources similar to "Hello Resources". Build initial project using the build.bat script to generate resources.h. Add the gfx folder and resources.c

Launch Visual Studio and include resource files as before. Next, scale out engine and screen code but now organize into subfolders. Create as New Filters under Visual Studio Header Files and Source Files solution: Create corresponding engine and screen subfolders beneath inc folder under dev. Add header files. Create engine and screen subfolders beneath src folder under dev. Add all the corresponding translation unit code.

Right click Project | Properties | Configuration Properties | C++ | General. Set Additional Include Directories:

 Value:   $(SolutionDir)..\lib;$(ProjectDir)inc;$(ProjectDir)res;$(GDK_WIN)\inc;$(IncludePath);
 $(ProjectDir)inc\engine;$(ProjectDir)inc\screen

Customize the makefile.gen file to include the new subfolders accordingly. Copy %GDK_WIN%\makefile.gen to local dev folder. Update makefile: Add new $(wildcard $(SRC)/ and -I$(INCLUDE) entries per folder. makefile.gen
SRC_C= $(wildcard *.c)
SRC_C+= $(wildcard $(SRC)/*.c)
SRC_C+= $(wildcard $(SRC)/engine/*.c)
SRC_C+= $(wildcard $(SRC)/screen/*.c)
:: ...
INCS= -I$(INCLUDE) -I$(INCLUDE)/engine -I$(INCLUDE)/screen -I$(SRC) -I$(RES) -I$(LIBINCLUDE) -I$(LIBRES)
:: ...
pre-build:
	$(MKDIR) -p $(SRC)/boot
	$(MKDIR) -p out
	$(MKDIR) -p out/res
	$(MKDIR) -p out/src
	$(MKDIR) -p out/src/engine
	$(MKDIR) -p out/src/screen

Update dev built.bat file to use new local custom makefile.gen instead of de-facto %GDK_WIN% version. build.bat
:: Build
::%GDK_WIN%\bin\make -f %GDK_WIN%\makefile.gen > NUL
%GDK_WIN%\bin\make -f makefile.gen > NUL
For completeness, strip out any unnecessary steps in the makefile especially if you are not building *.s files! If you remove pre-build step to speed up makefile build then don't forget to create out subfolders manually.


Troubleshooting
Here is a short list of issues found when installing SGDK, setting up custom library + building new projects:

sprintf
If you have downloaded an older version of SGDK then you may get error Varargs warning on sprintf. The solution is git clone latest master as the fix is only available through direct repository content not in 1.51.

libres
If you have downloaded an older version of SGDK then you may get libres warning. Again upgrade to latest!


Input
Launch Gens KMod and define keys choosing Option menu | Joypads | Redefine Keys. However, some older builds of "gens" may crash while redefining keys. If this happens then build gens from source and redefine keys there. Afterwards copy Gens.cfg + GensKMod.cfg from bin directory to directory where gens.exe lives. PS: don't forget to choose Graphics menu in Gens KMod emulator then Render | Double.


Code Samples
Here are links to some Wiki code currently in Sega Genesis development kit built using our custom library:
 CUSTOM: Hello World  SOURCE: Hello World
 CUSTOM: Input  SOURCE: Input
 
 CUSTOM: Tile Basic  SOURCE: Tile Basic
 CUSTOM: Tile Bitmap  SOURCE: Tile Bitmap

Here are links to all Tutorials currently hosted at Ohsat Games website and built using our custom library:
 CUSTOM: Mega Pong  SOURCE: Mega Pong
 CUSTOM: Mega Runner  SOURCE: Mega Runner
 
 CUSTOM: Mega Galaga  SOURCE: Mega Galaga
 CUSTOM: Miscellaneous  SOURCE: Miscellaneous

Here are links to all samples included in the Sega Genesis development kit built using our custom library:
 CUSTOM: astrofra  SOURCE: astrofra
 CUSTOM: bench  SOURCE: cube_flat
 CUSTOM: cube_flat  SOURCE: cube_flat
 CUSTOM: hs_effect  SOURCE: hs_effect
 CUSTOM: image  SOURCE: image
 
 CUSTOM: joytest  SOURCE: joytest
 CUSTOM: partic  SOURCE: partic
 CUSTOM: sound  SOURCE: sound
 CUSTOM: sprite  SOURCE: sprite
 CUSTOM: xgmplayer  SOURCE: xgmplayer


68000 assembly
The SGDK bench code sample has an example of inline 68000 assembly with math_test_a.s. However, there is an active thriving community that focuses Sega Genesis development in pure 68000 assembly by default!

Some notable resources include:
 Matt Philips  Mega Drive Tutorials
 Matt Philips  Mega Drive Code Samples
 Hugues Johnson  Genesis Programming
 Nameless Algorithm  Genesis Development
 
 Wiki Books  Genesis Programming Info
 mode5.net  Genesis Programming Tutorials
 Markey Jester  Motorola 68000 Starter Tutorial
 ChibiAkumas  68000 Assembly Programming


Summary
Armed with all this knowledge, we are now in an excellent position to build complete video games for the Sega Mega Drive that should be able to execute on real 16-bit hardware using C language and the SGDK!

Tuesday, September 15, 2020

SGDK Programming Setup

In 2013, we checked out Sega Retro Gaming, specifically 8-bit hardware manufactured by Sega such as the SG-1000, SC-3000 and Sega Master System. Now, we turn our attention to the 16-bit Mega Drive [Genesis].

In 2017, we checked out devkitSMS Programming Setup to build 8-bit game code for the Master System. As we upgrade to the 16-bit MD we would like to replicate this process now using Sega Genesis Dev Kit [SGDK].
Let’s check it out!

SGDK
The SGDK is a free development kit allowing you to develop software in C language for the Sega Mega Drive. Note that SGDK also requires Java (custom tools need it) so you need to have Java installed on your system.

IMPORTANT
Ensure an up-to-date version of Java is installed, e.g. version "12.0.2" 2019-07-16 otherwise builds may fail!

Software
Follow most instructions from the previous post: this documents how to setup some pre-requisite software.

Here is a summary of some of the software to be installed:
 Name Version
 C IDE Editor Visual Studio 2015
 Emulators Fusion, Gens KMod
 
 Name Version
 Cross compiler GCC
 Make files Cygwin

Gens KMod "gens" can also be built from source. Add gens.exe to Gens folder similar to Fusion in this post. Note: you may already have gcc configured on you computer if you previously installed cygwin or Git Bash

SGDK
Navigate to the SGDK repository on github: @MegadriveDev has full instructions here. Download the latest release from SGDK archive e.g. 1.51 or simply git clone the latest source code. Extract code into C:\SGDK.

Setup the following environment variables for GDK + GDK_WIN to be used throughout SGDK development. Add the following two environment variables: System | Advanced system settings | Environment Variables:
 Variable  Value  Description
 GDK  C:/SGDK  UNIX path format
 GDK_WIN  C:\SGDK  Windows path format

Next, Stephane advises to add the %GDK_WIN%\bin to your PATH variable being careful if you have another GCC installation as you may have conflicts. I have multiple GCC installs but have not experienced any issues.

Finally, generate the SGDK library %GDK%/lib/libmd.a by entering the following command Start | run | cmd.
%GDK_WIN%\bin\make -f %GDK_WIN%\makelib.gen

Example
As an example, let's write a simple program that prints "Hello World" using SGDK. Create new directory: C:\HelloWorld. Create main.c file + enter the following code similar to the Hello World tutorial program.

main.c
#include <genesis.h>
int main()
{
	VDP_drawText( "Hello Genny World!", 10, 13 );
	while( 1 )
	{
		VDP_waitVSync();
	}
	return 0;
}

Build
Manually compile, link and execute the Hello World program. Launch command prompt: Start | Run | cmd.

Change directory cd C:\HelloWorld. Next, execute the following make command to produce the output ROM:
 ACTION  COMMAND  OUTPUT
 Compile  %GDK_WIN%\bin\make -f %GDK_WIN%\makefile.gen  out\rom.bin

Finally, type out\rom.bin. The Hello World program should launch in the Fusion emulator.
Congratulations! You have just written your first Mega Drive program using the SGDK.

Automate
Let's automate the build process: create C:\HelloWorld\build.bat script file that contains the commands:
@echo off
%GDK_WIN%\bin\make -f %GDK_WIN%\makefile.gen
out\rom.bin

Code Blocks
Follow all instructions here to setup SGDK with CodeBlocks. @matteusbeus has great video on how to setup SGDK using CodeBlocks also. Check out his YouTube channel for other interesting videos with SGDK topics.

Eclipse
Follow all instructions here to setup SGDK with Eclipse. @SpritesMind has a great tutorial on how to remote debug SGDK code using Gens KMod with Eclipse also. Follow all instructions here to complete debug setup:

Launch Eclipse. Choose Run menu | Debug Configurations | C/C++ Remote Application | New Configuration
 Name  Remote Debugging
 Project  HelloWorld
 C/C++ Application  C:\HelloWorld\out\rom.out
 Disable auto build  CHECKED
IMPORTANT ensure "Using GDB (DSF) Manual Remote Debugging Launcher" is preferred launcher selected!

 Stop on startup as: main  CHECKED
 GDB debugger  C:SGDK\bin\gdb.exe
 GDB command line  .gdbinit

 Type  TCP
 Host name or IP address  localhost
 Port number  6868
Build project. Load rom.bin in gens. Set breakpoints. Click debug. Hit Tab in gens to refresh + debug code!

Visual Studio Code
@ohsat_games has a great tutorial on how to setup SGDK using Visual Studio Code. You can even install the Genesis Code extension for code auto completion and to streamline the build process all from within the IDE.

Further SGDK tutorials from @ohsat_games can be found here. All projects have a similar build batch script:
%GDK_WIN%\bin\make -f %GDK_WIN%\makefile.gen

Visual Studio 2015
Retro Mike has a great video on how to setup SGDK using Visual Studio 2015. Launch Visual Studio 2015. File | New | Project... | Visual C++ | General | Makefile Project. Enter the following name + location info:
 Name:  HelloWorld
 Location:  C:\
 Create directory for solution  UNCHECKED

Choose Next. Enter the following Build command: %GDK_WIN%\bin\make -f %GDK_WIN%\makefile.gen

Choose Finish. Enter the previous "Hello World" code as above. Finally, right click Project | Properties | VC++ Directories | Include Directories. Enter the following in order to include SGDK header files: $(GDK_WIN)\inc

Press Ctrl + Shift + B to build source code and produce out\rom.bin. Launch Fusion emu + load ROM file! Alternatively, setup "Remote" debugging configuration in Visual Studio and Press Ctrl + F5 to build and run.

Right click Project | Properties | Debugging | Remote Windows Debugger. Update in the following properties:
 Remote Command  C:\SEGA\Fusion\Fusion.exe
 Remote Command Arguments  out\rom.bin
 Connection  Remote with no authentication
 Debugger Type  Native Only
 Attach  Yes


Summary
To summarize, there are multiple IDE setups available to use the SGDK. However, despite VS2015 being the most applicable to our previous devkitSMS process, we're still not able to debug step thru the C source code.

Ultimately, we would like to build + debug step thru the C source code during SGDK development whilst also being able to build + run the ROM output file all from in Visual Studio. This will be the topic of the next post.