Wednesday, September 15, 2021

Kubernetes Cheat Sheet

Kubernetes is an open source container orchestration system for automating application deployment, scaling and management. Maintained by the Cloud Native Computing Foundation, Kubernetes works with a range of container tools and runs applications deployed in containers in a cluster often with images built using Docker.

Let's check it out!

Tools
Here are some commonly used tools that can be installed and to work with and manage Kubernetes clusters:
 kubectl  Command-line used to run commands against Kubernetes clusters
 minikube  Runs a single-node Kubernetes cluster on your personal computer
 kind  Runs Kubernetes on your local computer inside Docker containers
 kubeadm  Used to create and manage and secure larger Kubernetes clusters

Installation
Install Kubernetes with Docker Desktop on Windows and Mac OS/X. Install Kubernetes on Linux accordingly.

Minikube
Here are instructions how to get Kubernetes running locally as single node cluster on Ubuntu with Minikube:
# Prerequisites
sudo apt install cpu-checker && sudo kvm-ok
sudo apt install libvirt-clients libvirt-daemon-system qemu-kvm \
    && sudo usermod -a -G libvirt $(whoami) \
    && newgrp libvirt
    
sudo virt-host-validate
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl \
    && sudo install kubectl /usr/local/bin && rm kubectl

curl -LO https://storage.googleapis.com/minikube/releases/latest/docker-machine-driver-kvm2 \
    && sudo install docker-machine-driver-kvm2 /usr/local/bin/ && rm docker-machine-driver-kvm
    
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 \
    && sudo install minikube-linux-amd64 /usr/local/bin/minikube && rm minikube-linux-amd64

minikube version
minikube start


KinD
Kubernetes in Docker [KinD] allows an approach to run a full Kubernetes cluster using Docker containers to simulate multiple Kubernetes nodes operating all at once instead of running everything in virtual machine.

Assume Go installed. Launch Terminal. Enter commands to install KinD. Export path in ~/.bashrc and reboot:
 go get sigs.k8s.io/kind

 # Add KinD to $PATH in ~/.bashrc
 export PATH="$PATH:~/go/bin/"
 sudo reboot
 # Create test and delete cluster
 kind create cluster --wait 5m \
 export KUBECONFIG="$(kind get kubeconfig-path)"
 kubectl cluster-info
 kind delete cluster


kubeadm
kubeadm is another tool built to provide s fast path for creating Kuberentes clusters. kubeadm performs all actions to get minimum viable cluster up and running. Once you installed you can then create the cluster.
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl

sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
kubeadm version


Dashboard
Once Kubernetes cluster is setup there are various options to view all resources. Minikube simply the launch terminal | minikube start. Alternatively, install Visual Studio Code Kubernetes extension view all resources.


KinD dashboard is more involved. Enter these commands to configure KinD dashboard to run in the browser.
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.1.0/aio/deploy/recommended.yaml
kubectl get pod -n kubernetes-dashboard
kubectl create clusterrolebinding default-admin --clusterrole cluster-admin --serviceaccount=default:default

token=$(kubectl get secrets -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']==\
'default')].data.token}"|base64 --decode)
echo $token
kubectl proxy

IMPORTANT
If you receive following error: listen tcp 127.0.0.1:8001: bind: address already in use then enter command:
 netstat -tulnap | grep 5000
 sudo apt install net-tools
 sudo fuser -k 5000/tcp
 netstat -tulnap | grep 5000
Launch browser and enter the URL as per below. Once prompted enter the service token above and click OK.

k9s is the Kubernetes CLI to manage clusters. Download the latest binary and extract into /usr/local/bin. You may need to manually create the ~/.k9s folder otherwise you may receive the error Permission denied.


kubectl
Enable auto completion as per the kubectl Cheat Sheet and update ~/.bashrc to alias the kubectl command:
 # Auto complete
 source <(kubectl completion bash)
 echo "source <(kubectl completion bash)" >> ~/.bashrc
 
 # Alias kubectl
 alias k='kubectl'
 complete -F __start_kubectl k
 alias kdr='kubectl --dry-run=client -o yaml'

The Kubernetes cluster configuration file lives at ~/.kube/config. Obtain Kubernetes config + context info:
 kubectl config view  Show Kubernetes cluster configuration
 kubectl config get-contexts  Show all Kubernetes cluster contexts
 kubectl config current-context  Show current Kubernetes cluster context
 kubectl config use-context my-cluster-name  Set default context to my-cluster-name


Definitions
Here is some basic terminology when working with containerized applications running in Kubernetes cluster:
 Namespace  Scope cluster resources and a way to isolate Kubernetes objects
 Workload  Containerized application running within the Kubernetes cluster
 Container  Decouples applications from the underlying host infrastructure
 Pod  Smallest deployable unit as created and managed in Kubernetes
 Node  Workloads are placed in Containers on Pods to be run on Nodes
 Deployment  Provides a declarative way to update all Pods and ReplicaSets
 Service  Absract way to expose an application running on a set of Pods


Planes
Networking back in the day would have rules + policies about how to route network packets. These policies would make up the network control plane. The control plane is concerted with establishing network policy. Meanwhile, the data plane is everything else in the network architecture that enforces all network policies.

Control Plane
In Kubernetes, the control plane is the set of components that "make global decisions about the cluster" e.g. scheduling as well as detecting and responding to cluster events e.g. auto scaling pods due to traffic spikes.

Listed are control plane components that run on the master node to keep the cluster in the "desired state":
 Store (etcd)  Key-value backing store for all Kubernetes objects and data
 API Server  Exposes the Kubernetes API as the front end for the control plane
 Controller-Manager  Runs controller processes e.g. Nodes, Jobs, Endpoints + Services
 Scheduler  Watches for newly created pods and assigns nodes to run them on

Data Plane
In Kubernetes, the data plane is the set of worker nodes with their pods and containers that enforce all the global decisions made about the cluster from the master node e.g. auto scaling pods due to traffic spikes.

Listed are data plane components that run on each worker node maintaining pods and runtime environment:
 Kubelet  Worker agent that makes sure containers are running inside Pods
 Container Runtime  Software that is responsible for running containers on worker nodes
 Kube Proxy  Network proxy that maintains all network rules on the worker nodes

IMPORTANT
Here are 2x simple commands to get full information about control and data planes for Kubernetes cluster:
 kubectl cluster-info  Kubernetes control plane is running at https://192.168.49.2:8443
 kubectl cluster-info dump  Full description of all Kubernetes components running in the cluster


Commands
Here is list of useful commands. Foreach command you can add the --help flag to see more options to pass:
 kubectl get all -A  Get all resources across all namespaces
 kubectl describe pod my-pod  Get the full YAML declaration for my-pod
 kubectl get pod my-pod -o yaml  Get the expanded declaration for my-pod
 kubectl logs -f my-pod -o yaml  Get logs for my-pod + tail all its updates
 kubectl get nodes -o wide  List all full details of nodes in namepsace
 kubectl get deployments -A  List all deployments from all namespaces
 kubectl get services -A  List all services across all the namespaces
List all container(s) for my-pod kubectl get pod my-pod -o jsonpath="{.spec.containers[*].image}".

Tutorial
Hello MiniKube tutorial shows you how to create a sample app on Kubernetes applying the above resources.
 minikube start  Start Minikube cluster
 minikube dashboard  Launch Minikube dashboard
 minikube ip  Display Minikube IP address
 minikube ssh  Secure shell into Minikube node
 minikube stop  Stop Minikube cluster
 minikube delete  Delete Minikube cluster

Create Deployment
 minikube start
 minikube dashboard
 kubectl create deployment hello-node --image=k8s.gcr.io/echoserver:1.4
 kubectl get deployments

Create Service
 kubectl expose deployment hello-node --type=LoadBalancer --port=8080
 kubectl get services
 minikube service hello-node

Exec into Pod
 kubectl attach hello-node-7567d9fdc9-t7f8x -i
 kubectl exec hello-node-7567d9fdc9-t7f8x -- ls /
 kubectl exec --it hello-node-7567d9fdc9-t7f8x -- /bin/sh
 kubectl exec --stdin --tty hello-node-7567d9fdc9-t7f8x -- /bin/sh

Tail Logs
 kubectl logs -f hello-node-7567d9fdc9-t7f8x
 minikube stop
 minikube delete


Management
The tutorial demonstrates imperative commands using kubectl to operate directly on live Kubernetes objects in the cluster. This is the useful to get started or run one-off tasks however these actions provide no history.

Whereas using declarative object configuration requires configuration files first to be stored locally. All CRUD operations will be detected automatically per Kuberentes object thus configuration can be version controlled.


Source Code
Finally, navigate the Kubernetes source code to familiarize yourself with the code base and debug step thru the source code especially if you would like to participate in any one of the Special Interest Groups [SIGs].

Git clone the Kubernetes source code. Launch folder in VS Code. Search for main.go e.g. from ./cmd/cloud-controller-manager. Right click main.go | Open in | Terminal. go build . go run main.go. Press F5 to debug:
 git clone https://github.com/kubernetes/kubernetes.git
 cd kubernetes
 make
 find -L -type f -name 'main.go'
 cd ./cmd/cloud-controller-manager
 go build .
 go run main.go
 Press F5


Summary
To summarize, Kubernetes has greatly simplified cloud native infrastructure for developers and provides a scalable framework for application deployment. However, just like any new tool or technology, Kubernetes brings with it new security challenges especially due to the ephemeral nature of containerized applications.

Consequently, the Container Network Interface [CNI] initiative was created to define standardized common interface between container execution and Kubernetes networking layer to address these security concerns.

Thus Kubernetes plugins like Calico has become the most popular CNI for cluster networking thru definition and enforcement of network policies. Calico prescribes to which pods can send and receive traffic securely throughout the cluster which becomes critical esp. if Kubernetes adoption continues to grow in the future!

Tuesday, August 31, 2021

Docker Cheat Sheet

Docker is a Platform as a Service product that uses OS-level virtualization to deliver software in packages called containers. Containers are isolated from one another and bundle their own software + libraries and configuration files yet share single operating system kernel thus use fewer resource than virtual machines.

Let's check it out!

Installation
Docker Engine is available on a variety of Linux platforms. On Windows and Mac OS/X it is easiest to install Docker Desktop as a static binary installation. Install Docker Engine as per Operating System instructions.

Windows
Install Docker Desktop on Windows which will install the Docker Engine, Docker Compose and Kubernetes.

Mac OS/X
Install Docker Desktop on Mac OS/X which will install the Docker Engine, Docker Compose and Kubernetes.

Linux
Docker provides .deb + .rpm packages for various Linux distributions. For example Install Docker on Ubuntu:
sudo apt-get update
sudo apt-get remove docker docker-engine docker.io
sudo apt install docker.io
sudo systemctl start docker
sudo systemctl enable docker
docker version
docker images

The final 2x commands may throw the following error while trying to connect to the Docker daemon socket:

Here is one way to fix "Got permission denied while trying to connect to the Docker daemon socket" error:
sudo groupadd docker
sudo usermod -aG docker ${USER}
sudo reboot
docker version
docker images

IMPORTANT
You may also install docker-compose esp. if you are defining + running multi-container Docker applicaitons.
sudo apt install docker-compose
sudo docker-compose --version

If an older version of docker-compose is installed + you would like to upgrade then complete the following:
sudo apt remove docker-compose
sudo apt update
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo docker–compose --version


Definitions
When you learn Docker, you find that Docker Images are simply templates used to build Docker Containers. Docker Containers are small isolated environments which are runnable version of their Images. Finally, the Dockerfile contains all the commands that specify how an Image should be built and Container should run.

On brand new install on Docker there will be no Docker Images built or Docker Containers running. Verify:


Hello World
The simplest way to pull down Docker image from the Docker Hub is to execute docker run hello-world.


Getting Started
Here is more information on Docker Orientation and setup tutorial to build and run an image as a container:
docker run -d -p 80:80 docker/getting-started
docker images
docker ps

Launch browser. Enter http://localhost. You'll now see the same content locally as the Getting Started page! Afterwards cleanup. Enter the following commands from the Terminal to stop container and remove image:
docker stop $(docker ps -q)
docker rmi $(docker images -qa) --force
docker system prune -a

Example #1
Code an example from scratch: build simple Hello application in Python and run on localhost in a container:
 app.py  Dockerfile
 from flask import Flask
 
 app = Flask(__name__)
 @app.route("/")
 
 def hello():
     return "Hello World!"
 
 if __name__ == "__main__":
     app.run(debug=True, host="0.0.0.0")
 
 
 # Inherit from the Python Docker image
 FROM python:3.7-slim
 # Install the Flask package via pip
 RUN pip install flask==1.0.2
 # Copy the source code to app folder
 COPY ./app.py /app/
 # Change the working directory
 WORKDIR /app/
 # Set "python" as the entry point
 ENTRYPOINT ["python"]
 # Set the command as the script name
 CMD ["app.py"]
Follow best practices for writing DockerFile as each FROM, RUN, COPY, CMD instruction creates one layer.

Enter the following commands to build and run image as a container. Navigate browser to localhost:5000.
 Docker Image  Docker Container
 docker build -t flask_app:0.1 .
 docker images
 docker run -d -p 5000:5000 flask_app:0.1
 docker ps
Also curl http://localhost:5000. To stop the running container enter command: docker stop $(docker ps -q)

IMPORTANT
If you receive OSError: [Errno 98] Address already in use [Port 5000] then execute the following commands:
 netstat -tulnap | grep 5000
 sudo apt install net-tools
 sudo fuser -k 5000/tcp
 netstat -tulnap | grep 5000


Example #2
Code an example from scratch: build simple Hello application in GoLang but automate Dockerfile generation.
 app.go
 package main
 import (
 	"fmt"
 	"log"
 	"os"
 	"net/http"
 	"github.com/gorilla/mux"
 )
 func main() {
 	port := "5000"
 	r := mux.NewRouter()
 	r.HandleFunc("/", hello)
 	http.Handle("/", r)
 	fmt.Println("Starting up on " + port)
 	log.Fatal(http.ListenAndServe(":" + port, nil))
 }
 func hello(w http.ResponseWriter, req *http.Request) {
 	fmt.Fprintln(w, "Hello world!")
 }

Launch VS Code. Open folder hosting app.go. Install Docker extension. Generate Dockerfile with the actions:
  1. Ctrl+Shift+P. Choose Docker: Add Docker Files to Workspace...
  2. Select Application Platform. Choose GoLang
  3. What port does app listen on? Choose 5000
  4. Include optional Docker Compose files? Select No
 Dockerfile
 #build stage
 FROM golang:alpine AS builder
 RUN apk add --no-cache git
 WORKDIR /go/src/app
 COPY . .
 RUN go get -d -v ./...
 RUN go build -o /go/bin/app -v ./...
 
 #final stage
 FROM alpine:latest
 RUN apk --no-cache add ca-certificates
 COPY --from=builder /go/bin/app /app
 ENTRYPOINT /app
 LABEL Name=golang20 Version=0.0.1
 EXPOSE 5000

In VS Code | Right click Dockerfile | Build Image... Choose name to tag image. Once complete Image will be listed in Docker extension Images list. Expand image built | Run. Refresh Docker extension Containers list. Navigate browser to localhost:5000. Expand Container to see all files from the running Image built earlier:



Example #3
Code an example from scratch: build simple Hello application in C++ and run interactively inside container:
 main.cpp  Dockerfile
 #include <iostream>
 using namespace std;
 int main()
 {
     cout << "Hello World C++" < endl;
     return 0;
 };
 FROM gcc:latest

 COPY . /usr/src/cpp_test
 WORKDIR /usr/src/cpp_test

 RUN g++ -o Test main.cpp
 CMD [ "./Test" ]

Enter the following commands to build and run image as a container. Run interactive inside container also.
 Run normally  Run interactively
 docker build . -t cpp_test:1.0
 docker run --rm cpp_test:1.0
 docker run -it cpp_test:1.0 bash
 ./Test


Example #4
Run real world example. Pull Envoy image from Internet. Run locally to prove all dependencies contained:
docker run --rm envoyproxy/envoy-dev:716ee8abc526d51f07ed6d3c2a5aa8a3b2481d9d --version
docker run --rm envoyproxy/envoy-dev:716ee8abc526d51f07ed6d3c2a5aa8a3b2481d9d --help

Download envoy-demo.yaml configuration. Run following command + navigate to http://localhost:10000.
docker run --rm -it \
      -v $(pwd)/envoy-demo.yaml:/envoy-demo.yaml \
      -p 9901:9901 \
      -p 10000:10000 \
      envoyproxy/envoy-dev:1acf02f70c75a7723d0269b7f375b3a94cb0fbf0 \
          -c envoy-demo.yaml

 curl -v localhost:10000


Interactive
Shell into the remote running Container. Navigate the file system from above using the following command:
 docker exec -it $(docker ps -q) bash


Commands
Here is list of useful commands. Foreach command you can add the --help flag to see more options to pass:
 Command  Description
 docker build -t [image_name]:[tag] .  Build a Docker image
 docker run --name [container_name] [image_name]:[tag]  Run a Docker container specifying a name
 docker logs -f [container_id_or_name]  Fetch the logs of a container
 docker exec -it [container_id_or_name] bash  Run a command in a running container
 docker rm $(docker ps -aq)  Remove all containers
 docker rmi $(docker images -aq)  Remove all images


Samples
Here is a list of useful commonly used sample commands that can be used frequently as simple cheat sheet:
 Command  Description
 docker images  Show all Docker images
 docker ps  Show all running containers
 docker stop $(docker ps -q)  Stop all running containers
 docker system prune -a  Remove all images + containers
IMPORTANT: if any commands above throw a "docker: 'docker' is not a docker command" then run as sudo!

Registration
Create an account on the Docker hub. In VS Code | Docker extension | Registries | Connect Registry. Enter case sensitive Docker credentials. Right click Image | Push Image to registry | Pull Image from the registry.

Debugging
Once Dockerfiles become more complex you may like to follow some of these tips for debugging containers. The following video demonstrates some of these ideas to debug Docker containers like override ENTRYPOINT
  1. Override the container entrypoint and exec onto it
  2. Use docker cp to copy files between containers and host
  3. Run a debugger inside the container and connect to it from the host system

Summary
To summarize, Docker provides an open standard for packaging and distributing containerized applications, however, the challenge can then become how to coordinate and schedule increasing amount of containers?

This is where Kubernetes can help: Kubernetes is open-source orchestration software that provides an API controlling how and where those containers will run. Kubernetes can scale out multple deployed and more!
This will be the topic of the next post.

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!