Compare commits

..

3 Commits

Author SHA1 Message Date
ISSOtm
bffe7eb4de Implement new instructions
"Who are you? What are you doing in my commit history?"
~ https://xkcd.com/163/
2022-04-01 12:46:52 +02:00
ISSOtm
cd454d2e9a Hack in new register syntax
Oh my god I want to die x_x
2022-04-01 12:46:52 +02:00
ISSOtm
c814a616d6 Port Gan's work to Mandoc format
Hopefully I didn't forget anything
2022-04-01 12:46:52 +02:00
1977 changed files with 27555 additions and 45869 deletions

88
.checkpatch.conf Normal file
View File

@@ -0,0 +1,88 @@
# Configuration for checkpatch.pl
# ===============================
# Enable more tests
--strict
# Quiet
--quiet
# No per-file summary
--no-summary
# Don't expect the Linux kernel tree
--no-tree
# Show file line, not input line
--showfile
# Don't expect SPDX tag in the first line of a file
--ignore SPDX_LICENSE_TAG
# Don't expect Signed-off-by lines in commit messages
--no-signoff
# List of ignored rules
# ---------------------
# There's no BIT macro
--ignore BIT_MACRO
# Don't complain when bools are used in structs
--ignore BOOL_MEMBER
# Allow CamelCase
--ignore CAMELCASE
# Comparing to NULL explicitly isn't a bad thing
--ignore COMPARISON_TO_NULL
# Causes false positives
--ignore COMPLEX_MACRO
# Don't complain about structs not being const
--ignore CONST_STRUCT
# Don't complain about printing "warning:" without the function name, as warning
# printing is relevant to the code being parsed, not RGBDS' code
--ignore EMBEDDED_FUNCTION_NAME
# Do not check the format of commit messages
--ignore GIT_COMMIT_ID
# Do not check for global initializers (this is specific to the kernel)
--ignore GLOBAL_INITIALISERS
# Don't complain about initializing statics (this is specific to the kernel)
--ignore INITIALISED_STATIC
# We don't have a MAINTAINERS file, don't complain about it.
--ignore FILE_PATH_CHANGES
# Writing the continuation on the start of the line can make it clearer
--ignore LOGICAL_CONTINUATIONS
# Don't complain if a line that contains a string is too long. It's better to
# have a really long line that can be found with grep.
--ignore LONG_LINE_STRING
# Don't complain when files are modified in 'include/asm'
--ignore MODIFIED_INCLUDE_ASM
# Allow new typedefs
--ignore NEW_TYPEDEFS
# We allow lines ending with parentheses for the usage prints
--ignore OPEN_ENDED_LINE
# Prefer stdint.h types over kernel types
--ignore PREFER_KERNEL_TYPES
# Don't ask to replace sscanf by kstrto
--ignore SSCANF_TO_KSTRTO
# Parentheses can make the code clearer
--ignore UNNECESSARY_PARENTHESES
# We don't have `fallthrough;` */
--ignore PREFER_FALLTHROUGH

View File

@@ -1,13 +1,13 @@
AccessModifierOffset: -4 AccessModifierOffset: -4
AlignAfterOpenBracket: BlockIndent AlignAfterOpenBracket: Align
AlignArrayOfStructures: Left AlignArrayOfStructures: Left
AlignConsecutiveAssignments: None AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: Consecutive AlignConsecutiveBitFields: Consecutive
AlignConsecutiveDeclarations: None AlignConsecutiveDeclarations: None
AlignConsecutiveMacros: Consecutive AlignConsecutiveMacros: Consecutive
AlignEscapedNewlines: DontAlign AlignEscapedNewlines: Left
AlignOperands: Align AlignOperands: Align
AlignTrailingComments: true AlignTrailingComments: false
AllowShortBlocksOnASingleLine: Empty AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: true AllowShortEnumsOnASingleLine: true
@@ -21,10 +21,9 @@ AlwaysBreakTemplateDeclarations: Yes
AttributeMacros: AttributeMacros:
- format_ - format_
- attr_ - attr_
BinPackArguments: false BinPackArguments: true
BinPackParameters: false BinPackParameters: true
BitFieldColonSpacing: Both BitFieldColonSpacing: Both
BreakAfterAttributes: Always
BreakBeforeBinaryOperators: NonAssignment BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Attach BreakBeforeBraces: Attach
BreakBeforeConceptDeclarations: true BreakBeforeConceptDeclarations: true
@@ -55,28 +54,22 @@ IncludeCategories:
IndentAccessModifiers: false IndentAccessModifiers: false
IndentCaseBlocks: false IndentCaseBlocks: false
IndentCaseLabels: false IndentCaseLabels: false
IndentExternBlock: Indent IndentExternBlock: NoIndent
IndentGotoLabels: false IndentGotoLabels: false
IndentPPDirectives: BeforeHash IndentPPDirectives: BeforeHash
IndentRequires: true IndentRequires: true
IndentWidth: 4 IndentWidth: 4
IndentWrappedFunctionNames: true IndentWrappedFunctionNames: true
InsertBraces: true # Only support for Javascript as of clang-format 13...
InsertNewlineAtEOF: true # InsertTrailingCommas: true
# Only support for Javascript as of clang-format 14...
# InsertTrailingCommas: Wrapped
KeepEmptyLinesAtTheStartOfBlocks: false KeepEmptyLinesAtTheStartOfBlocks: false
LambdaBodyIndentation: Signature LambdaBodyIndentation: Signature
Language: Cpp Language: Cpp
MaxEmptyLinesToKeep: 1 MaxEmptyLinesToKeep: 1
NamespaceIndentation: None NamespaceIndentation: None
PPIndentWidth: -1 PPIndentWidth: -1
PenaltyBreakScopeResolution: 1000
PointerAlignment: Right PointerAlignment: Right
QualifierAlignment: Right
ReflowComments: true ReflowComments: true
RemoveParentheses: ReturnStatement
RemoveSemicolon: true
SortIncludes: CaseSensitive SortIncludes: CaseSensitive
SortUsingDeclarations: true SortUsingDeclarations: true
SpaceAfterCStyleCast: false SpaceAfterCStyleCast: false
@@ -103,4 +96,4 @@ SpacesInSquareBrackets: false
Standard: c++20 Standard: c++20
TabWidth: 4 TabWidth: 4
UseCRLF: false UseCRLF: false
UseTab: ForIndentation UseTab: AlignWithSpaces

View File

@@ -1,6 +0,0 @@
---
Checks: ''
WarningsAsErrors: ''
HeaderFilterRegex: ''
FormatStyle: none
SystemHeaders: false

View File

@@ -1,2 +1,7 @@
# This file is part of RGBDS.
#
# Copyright (c) 2018-2019, Phil Smith and RGBDS contributors.
#
# SPDX-License-Identifier: MIT
.git .git
docs docs

View File

@@ -2,7 +2,7 @@
root = true root = true
indent_style = tab indent_style = tab
indent_size = tab indent_size = tab
tab_width = 4 tab_width = 8
charset = utf-8 charset = utf-8
insert_final_newline = true insert_final_newline = true
trim_trailing_whitespace = true trim_trailing_whitespace = true

16
.gitattributes vendored
View File

@@ -1,18 +1,2 @@
# Shell scripts need Unix line endings (see https://github.com/gbdev/rgbds/issues/841) # Shell scripts need Unix line endings (see https://github.com/gbdev/rgbds/issues/841)
*.sh text eol=lf *.sh text eol=lf
*.bash text eol=lf
# Flags also need Unix line endings (see https://github.com/gbdev/rgbds/issues/955)
*.flags text eol=lf
# Binary files need exact bytes
*.bin binary
*.gb binary
*.1bpp binary
*.2bpp binary
*.pal binary
*.attrmap binary
*.tilemap binary
*.palmap binary
*.patch binary
*.png binary

3
.github/FUNDING.yml vendored
View File

@@ -1,2 +1,3 @@
github: avivace
patreon: gbdev01
open_collective: gbdev open_collective: gbdev
github: gbdev

56
.github/actions/doc_postproc.awk vendored Executable file
View File

@@ -0,0 +1,56 @@
#!/usr/bin/awk -f
/^\s+<td><b class="Sy">.+<\/b><\/td>$/ {
# Assuming that all cells whose contents are bold are heading cells,
# use the HTML tag for those
sub(/td><b class="Sy"/, "th");
sub(/b><\/td/, "th");
}
# The whole page is being generated, so it's not meant to contain any Liquid
BEGIN {
print "{% raw %}"
}
END {
print "{% endraw %}"
}
BEGIN {
in_synopsis = 0
}
/<table class="Nm">/ {
in_synopsis = 1
}
/<\/table>/ {
# Resets synopsis state even when already reset, but whatever
in_synopsis = 0
}
/<code class="Fl">-[a-zA-Z]/ {
# Add links to arg descr in synopsis section
if (in_synopsis) {
while (match($0, /<code class="Fl">-[a-zA-Z]+/)) {
# 123456789012345678 -> 18 chars
optchars = substr($0, RSTART + 18, RLENGTH - 18)
i = length(optchars)
while (i) {
end = RSTART + 18 + i
i -= 1
len = i ? 1 : 2
$0 = sprintf("%s<a href=\"#%s\">%s</a>%s",
substr($0, 0, end - len - 1),
substr($0, end - 1, 1),
substr($0, end - len, len),
substr($0, end))
}
}
}
}
{
# Make long opts (defined using `Fl Fl`) into a single tag
gsub(/<code class="Fl">-<\/code>\s*<code class="Fl">/, "<code class=\"Fl\">-")
}
{
print
}

113
.github/actions/get-pages.sh vendored Executable file
View File

@@ -0,0 +1,113 @@
#!/bin/bash
usage() {
cat <<EOF
Usage: $0 [-h] [-r] <rgbds-www> <version>
Copy renders from RGBDS repository to rgbds-www documentation
Execute from the root folder of the RGBDS repo, checked out at the desired tag
<rgbds-www> : Path to the rgbds-www repository
<version> : Version to be copied, such as 'v0.4.1' or 'master'
-h Display this help message
-r Update "latest stable" redirection pages and add a new entry to the index
(use for releases, not master)
EOF
}
is_release=0
bad_usage=0
while getopts ":hr" opt; do
case $opt in
r)
is_release=1
;;
h)
usage
exit 0
;;
\?)
echo "Unknown option '$OPTARG'"
bad_usage=1
;;
esac
done
if [ $bad_usage -ne 0 ]; then
usage
exit 1
fi
shift $(($OPTIND - 1))
declare -A PAGES
PAGES=(
[rgbasm.1.html]=src/asm/rgbasm.1
[rgbasm.5.html]=src/asm/rgbasm.5
[rgblink.1.html]=src/link/rgblink.1
[rgblink.5.html]=src/link/rgblink.5
[rgbfix.1.html]=src/fix/rgbfix.1
[rgbgfx.1.html]=src/gfx/rgbgfx.1
[rgbds.5.html]=src/rgbds.5
[rgbds.7.html]=src/rgbds.7
[gbz80.7.html]=src/gbz80.7
)
WWWPATH="/docs"
mkdir -p "$1/_documentation/$2"
# `mandoc` uses a different format for referring to man pages present in the **current** directory.
# We want that format for RGBDS man pages, and the other one for the rest;
# we thus need to copy all pages to a temporary directory, and process them there.
# Copy all pages to current dir
cp "${PAGES[@]}" .
for page in "${!PAGES[@]}"; do
stem="${page%.html}"
manpage="${stem%.?}(${stem#*.})"
descr="$(awk -v 'FS=.Nd ' '/.Nd/ { print $2; }' "${PAGES[$page]}")"
cat >"$1/_documentation/$2/$page" <<EOF
---
layout: doc
title: $manpage [$2]
description: RGBDS $2 — $descr
---
EOF
options=fragment,man='%N.%S;https://linux.die.net/man/%S/%N'
if [ $stem = rgbasm.5 ]; then
options+=,toc
fi
mandoc -Thtml -I os=Linux -O$options "${PAGES[$page]##*/}" | .github/actions/doc_postproc.awk >> "$1/_documentation/$2/$page"
groff -Tpdf -mdoc -wall "${PAGES[$page]##*/}" >"$1/_documentation/$2/$stem.pdf"
if [ $is_release -ne 0 ]; then
cat - >"$1/_documentation/$page" <<EOF
---
redirect_to: $WWWPATH/$2/${page%.html}
permalink: $WWWPATH/${page%.html}/
title: $manpage [latest stable]
description: RGBDS latest stable — $descr
---
EOF
fi
done
cat - >"$1/_documentation/$2/index.html" <<EOF
---
layout: doc_index
permalink: /docs/$2/
title: RGBDS online manual [$2]
description: RGBDS $2 - Online manual
---
EOF
# If making a release, add a new entry right after `master`
if [ $is_release -ne 0 ]; then
awk '{ print }
/"name": "master"/ { print "\t\t{\"name\": \"'$2'\", \"text\": \"'$2'\" }," }
' "$1/_data/doc.json" >"$1/_data/doc.json.tmp"
mv "$1/_data/doc.json"{.tmp,}
fi
# Clean up
rm "${PAGES[@]##*/}"

21
.github/actions/install_deps.sh vendored Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
set -e
case "${1%-*}" in
ubuntu)
sudo apt-get -qq update
sudo apt-get install -yq bison libpng-dev pkg-config
;;
macos)
brew install bison libpng pkg-config md5sha1sum
# For the version check below exclusively, re-do this before building
export PATH="/usr/local/opt/bison/bin:$PATH"
;;
*)
echo "WARNING: Cannot install deps for OS '$1'"
;;
esac
bison --version
make --version
cmake --version

17
.github/actions/mingw-configure.sh vendored Normal file
View File

@@ -0,0 +1,17 @@
#!/bin/bash
source mingw-env @TRIPLE@
echo LAST IS: $last
# check if last arg is a path to configure, else use parent
for last; do true; done
if test -x "${last}/configure"; then
config_path="$last"
else
config_path=".."
fi
${config_path}/configure \
--host=@TRIPLE@ --target=@TRIPLE@ --build="$CHOST" \
--prefix=/usr/@TRIPLE@ --libdir=/usr/@TRIPLE@/lib --includedir=/usr/@TRIPLE@/include \
--enable-shared --enable-static "$@"

16
.github/actions/mingw-env.sh vendored Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
_arch=$1
default_mingw_pp_flags="-D_FORTIFY_SOURCE=2"
default_mingw_compiler_flags="$default_mingw_pp_flags -O2 -pipe -fno-plt -fexceptions --param=ssp-buffer-size=4"
default_mingw_linker_flags="-Wl,-O1,--sort-common,--as-needed -fstack-protector"
export CPPFLAGS="${MINGW_CPPFLAGS:-$default_mingw_pp_flags $CPPFLAGS}"
export CFLAGS="${MINGW_CFLAGS:-$default_mingw_compiler_flags $CFLAGS}"
export CXXFLAGS="${MINGW_CXXFLAGS:-$default_mingw_compiler_flags $CXXFLAGS}"
export LDFLAGS="${MINGW_LDFLAGS:-$default_mingw_linker_flags $LDFLAGS}"
mingw_prefix=/usr/${_arch}
export PKG_CONFIG_SYSROOT_DIR="${mingw_prefix}"
export PKG_CONFIG_LIBDIR="${mingw_prefix}/lib/pkgconfig:${mingw_prefix}/share/pkgconfig"

44
.github/actions/mingw-w64-libpng-dev.sh vendored Executable file
View File

@@ -0,0 +1,44 @@
#!/bin/sh
# This script was written by ISSOtm while looking at Arch Linux's PKGBUILD for
# the corresponding package. (And its dependencies)
# https://aur.archlinux.org/packages/mingw-w64-libpng/
set -e
pngver=1.6.37
_apngver=$pngver
_arch="$1"
## Install mingw-configure and mingw-env (both build dependencies)
install -m 755 .github/actions/mingw-env.sh /usr/bin/mingw-env
sed "s|@TRIPLE@|${_arch}|g" .github/actions/mingw-configure.sh > ${_arch}-configure
install -m 755 ${_arch}-configure /usr/bin/
## Grab sources and check them
wget http://downloads.sourceforge.net/sourceforge/libpng/libpng-$pngver.tar.xz
wget http://downloads.sourceforge.net/project/apng/libpng/libpng16/libpng-$_apngver-apng.patch.gz
sha256sum -c .github/actions/mingw-w64-libpng-dev.sha256sums
## Extract sources
tar -xf libpng-$pngver.tar.xz
gunzip libpng-$_apngver-apng.patch.gz
## Start building!
cd libpng-$pngver
# Patch in apng support
patch -p0 ../libpng-$_apngver-apng.patch
mkdir -p build-${_arch}
cd build-${_arch}
${_arch}-configure LDFLAGS=-static-libgcc
make
make install

View File

@@ -0,0 +1,2 @@
10d9e0cb60e2b387a79b355eb7527c0bee2ed8cbd12cf04417cabc4d6976683c libpng-1.6.37-apng.patch.gz
505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca libpng-1.6.37.tar.xz

View File

@@ -1,27 +0,0 @@
#!/bin/bash
set -euo pipefail
pngver=1.6.50
## Grab sources and check them
curl -LOJ "http://prdownloads.sourceforge.net/libpng/libpng-$pngver.tar.xz?download"
# Brew doesn't provide any sha256sum, so we're making do with `sha2` instead.
if [ "$(sha2 -q -256 libpng-$pngver.tar.xz)" != 4df396518620a7aa3651443e87d1b2862e4e88cad135a8b93423e01706232307 ]; then
sha2 -256 libpng-$pngver.tar.xz
echo Checksum mismatch! Aborting. >&2
exit 1
fi
## Extract sources and patch them
tar -xvf libpng-$pngver.tar.xz
## Start building!
mkdir -p build
cd build
../libpng-$pngver/configure --disable-shared --enable-static \
CFLAGS="-O3 -flto -DNDEBUG -mmacosx-version-min=10.9 -arch x86_64 -arch arm64 -fno-exceptions"
make -kj
make install prefix="$PWD/../libpng-staging"

View File

@@ -1,23 +0,0 @@
function getlibrary ([string] $URI, [string] $filename, [string] $hash, [string] $destdir) {
$wc = New-Object Net.WebClient
[string] $downloadhash = $null
try {
$wc.DownloadFile($URI, $filename)
$downloadhash = $(Get-FileHash $filename -Algorithm SHA256).Hash
} catch {
Write-Host "${filename}: failed to download"
exit 1
}
if ($hash -ne $downloadhash) {
Write-Host "${filename}: SHA256 mismatch ($downloadhash)"
exit 1
}
Expand-Archive -DestinationPath $destdir $filename
}
getlibrary 'https://www.zlib.net/zlib131.zip' 'zlib.zip' '72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17' .
getlibrary 'https://github.com/pnggroup/libpng/archive/refs/tags/v1.6.50.zip' 'libpng.zip' 'f6bb2544d2cf5465af3a695dee0b7eacff82f11a50aa4672ef0e19df6e16d455' .
getlibrary 'https://github.com/lexxmark/winflexbison/releases/download/v2.5.25/win_flex_bison-2.5.25.zip' 'winflexbison.zip' '8d324b62be33604b2c45ad1dd34ab93d722534448f55a16ca7292de32b6ac135' install_dir
Move-Item zlib-1.3.1 zlib
Move-Item libpng-1.6.50 libpng

View File

@@ -1,7 +0,0 @@
#!/usr/bin/env bash
install -d /usr/local/bin/ /usr/local/share/man/man1/ /usr/local/share/man/man5/ /usr/local/share/man/man7/
install -s -m 755 rgbasm rgblink rgbfix rgbgfx /usr/local/bin/
install -m 644 rgbasm.1 rgblink.1 rgbfix.1 rgbgfx.1 /usr/local/share/man/man1/
install -m 644 rgbds.5 rgbasm.5 rgblink.5 rgbasm-old.5 /usr/local/share/man/man5/
install -m 644 rgbds.7 gbz80.7 /usr/local/share/man/man7/

View File

@@ -1,23 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
case "${1%-*}" in
ubuntu)
sudo apt-get -qq update
sudo apt-get install -yq bison libpng-dev pkg-config
;;
macos)
brew install bison sha2 md5sha1sum
# Export `bison` to allow using the version we install from Homebrew,
# instead of the outdated one preinstalled on macOS (which doesn't even support `-Wall`...)
export PATH="/opt/homebrew/opt/bison/bin:$PATH"
printf 'PATH=%s\n' "$PATH" >>"$GITHUB_ENV" # Make it available to later CI steps too
;;
*)
echo "WARNING: Cannot install deps for OS '$1'"
;;
esac
bison --version
make --version
cmake --version

View File

@@ -1,28 +0,0 @@
#!/bin/bash
set -euo pipefail
pngver=1.6.50
arch="$1"
## Grab sources and check them
wget http://downloads.sourceforge.net/project/libpng/libpng16/$pngver/libpng-$pngver.tar.xz
echo 4df396518620a7aa3651443e87d1b2862e4e88cad135a8b93423e01706232307 libpng-$pngver.tar.xz | sha256sum -c -
## Extract sources and patch them
tar -xf libpng-$pngver.tar.xz
## Start building!
mkdir -p build
cd build
../libpng-$pngver/configure \
--host="$arch" --target="$arch" \
--prefix="/usr/$arch" \
--enable-shared --disable-static \
CPPFLAGS="-D_FORTIFY_SOURCE=2" \
CFLAGS="-O2 -pipe -fno-plt -fno-exceptions --param=ssp-buffer-size=4" \
LDFLAGS="-Wl,-O1,--sort-common,--as-needed -fstack-protector"
make -kj
sudo make install

View File

@@ -1,18 +0,0 @@
name: Static analysis
on:
- push
- pull_request
jobs:
analysis:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Install deps
shell: bash
run: |
./.github/scripts/install_deps.sh ubuntu-latest
- name: Static analysis
run: | # Silence warnings with too many false positives (https://stackoverflow.com/a/73913076)
make -kj CXX=g++-14 CXXFLAGS="-fanalyzer -fanalyzer-verbosity=0 -Wno-analyzer-use-of-uninitialized-value -DNDEBUG" Q=

View File

@@ -1,53 +0,0 @@
name: Build container image
on:
push:
branches:
- master
tags:
- '*'
jobs:
publish-docker-image:
if: github.repository_owner == 'gbdev'
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push the master container image
if: github.ref == 'refs/heads/master'
run: |
COMMIT_HASH=$(git rev-parse --short HEAD)
sed -i "2i LABEL org.opencontainers.image.description=\"RGBDS container image, containing the git version master:$COMMIT_HASH\"" Dockerfile
docker build . --tag ghcr.io/gbdev/rgbds:master
docker push ghcr.io/gbdev/rgbds:master
- name: Build and push the version-tagged container image
if: startsWith(github.ref, 'refs/tags/')
run: |
TAG_NAME=${GITHUB_REF#refs/tags/}
sed -i "2i LABEL org.opencontainers.image.description=\"RGBDS container image for the release version $TAG_NAME\"" Dockerfile
docker build . --tag ghcr.io/gbdev/rgbds:$TAG_NAME
docker tag ghcr.io/gbdev/rgbds:$TAG_NAME ghcr.io/gbdev/rgbds:latest
docker push ghcr.io/gbdev/rgbds:$TAG_NAME
docker push ghcr.io/gbdev/rgbds:latest
- name: Delete untagged container images
if: github.repository_owner == 'gbdev'
uses: Chizkiyahu/delete-untagged-ghcr-action@v5
with:
# Requires a personal access token with delete:packages permissions
token: ${{ secrets.PAT_TOKEN }}
package_name: 'rgbds'
untagged_only: true
except_untagged_multiplatform: true
owner_type: 'org'

View File

@@ -1,4 +1,4 @@
name: Diff completeness check name: "Code coverage checking"
on: pull_request on: pull_request
jobs: jobs:
@@ -11,7 +11,7 @@ jobs:
cd rgbds cd rgbds
git remote add upstream "${{ github.event.pull_request.base.repo.clone_url }}" git remote add upstream "${{ github.event.pull_request.base.repo.clone_url }}"
git fetch upstream git fetch upstream
- name: Check diff - name: Checkdiff
working-directory: rgbds working-directory: rgbds
run: | run: |
make checkdiff "BASE_REF=${{ github.event.pull_request.base.sha }}" Q= | tee log make checkdiff "BASE_REF=${{ github.event.pull_request.base.sha }}" Q= | tee log

View File

@@ -1,12 +0,0 @@
name: Code format checking
on: pull_request
jobs:
checkformat:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Check format
run: |
contrib/checkformat.bash

25
.github/workflows/checkpatch.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: "Code style checking"
on: pull_request
jobs:
checkpatch:
runs-on: ubuntu-latest
steps:
- name: Set up repo
run: |
git clone -b "${{ github.event.pull_request.head.ref }}" "${{ github.event.pull_request.head.repo.clone_url }}" rgbds
cd rgbds
git remote add upstream "${{ github.event.pull_request.base.repo.clone_url }}"
git fetch upstream
- name: Set up checkpatch
working-directory: rgbds
run: |
wget 'https://raw.githubusercontent.com/torvalds/linux/master/scripts/checkpatch.pl'
chmod +x checkpatch.pl
wget 'https://raw.githubusercontent.com/torvalds/linux/master/scripts/const_structs.checkpatch'
wget 'https://raw.githubusercontent.com/torvalds/linux/master/scripts/spelling.txt'
- name: Checkpatch
working-directory: rgbds
run: |
make checkpatch CHECKPATCH=./checkpatch.pl "BASE_REF=${{ github.event.pull_request.base.sha }}" Q= | tee log
if grep -q ERROR: log; then exit 1; else exit 0; fi

View File

@@ -1,34 +0,0 @@
name: Code coverage report
on:
- push
- pull_request
jobs:
coverage:
runs-on: ubuntu-24.04
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Install deps
shell: bash
run: |
./.github/scripts/install_deps.sh ubuntu
- name: Install LCOV
run: |
sudo apt-get install lcov
- name: Install test dependency dependencies
shell: bash
run: |
test/fetch-test-deps.sh --get-deps ubuntu
- name: Generate coverage report
run: |
contrib/coverage.bash ubuntu-ci
- name: Upload coverage report
uses: actions/upload-artifact@v4
with:
name: coverage-report
# Workaround for keeping the top-level coverage/ directory
# https://github.com/actions/upload-artifact/issues/174
path: |
coverage
dummy-file-to-keep-directory-structure.txt

View File

@@ -0,0 +1,96 @@
name: "Create release artifacts"
on:
push:
tags:
- v[0-9]*
jobs:
windows:
runs-on: windows-2019
steps:
- uses: actions/checkout@v2
- name: Get version from tag
shell: bash
run: | # Turn "refs/tags/vX.Y.Z" into "X.Y.Z"
VERSION="${{ github.ref }}"
echo "version=${VERSION##*/v}" >> $GITHUB_ENV
- name: Get zlib, libpng and bison
run: | # TODO: use an array
$wc = New-Object System.Net.WebClient
$wc.DownloadFile('https://www.zlib.net/zlib1212.zip', 'zlib.zip')
$hash = (Get-FileHash "zlib.zip" -Algorithm SHA256).Hash
if ($hash -ne '173e89893dcb8b4a150d7731cd72f0602f1d6b45e60e2a54efdf7f3fc3325fd7') {
Write-Host "zlib SHA256 mismatch! ($hash)"
exit 1
}
$wc.DownloadFile('https://download.sourceforge.net/libpng/lpng1637.zip', 'libpng.zip')
$hash = (Get-FileHash "libpng.zip" -Algorithm SHA256).Hash
if ($hash -ne '3b4b1cbd0bae6822f749d39b1ccadd6297f05e2b85a83dd2ce6ecd7d09eabdf2') {
Write-Host "libpng SHA256 mismatch! ($hash)"
exit 1
}
$wc.DownloadFile('https://github.com/lexxmark/winflexbison/releases/download/v2.5.24/win_flex_bison-2.5.24.zip', 'winflexbison.zip')
$hash = (Get-FileHash "winflexbison.zip" -Algorithm SHA256).Hash
if ($hash -ne '39c6086ce211d5415500acc5ed2d8939861ca1696aee48909c7f6daf5122b505') {
Write-Host "bison SHA256 mismatch! ($hash)"
}
Expand-Archive -DestinationPath . "zlib.zip"
Expand-Archive -DestinationPath . "libpng.zip"
Expand-Archive -DestinationPath install_dir "winflexbison.zip"
Move-Item zlib-1.2.12 zlib
Move-Item lpng1637 libpng
- name: Build 32-bit zlib
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
cmake -S zlib -B zbuild32 -A Win32 -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
cmake --build zbuild32 --config Release
cmake --install zbuild32
- name: Build 32-bit libpng
run: |
cmake -S libpng -B pngbuild32 -A Win32 -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=ON -DPNG_TESTS=OFF
cmake --build pngbuild32 --config Release
cmake --install pngbuild32
- name: Build 32-bit Windows binaries
run: |
cmake -S . -B build32 -A Win32 -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release
cmake --build build32 --config Release
cmake --install build32
- name: Package 32-bit binaries
run: |
Compress-Archive -LiteralPath @("install_dir/bin/rgbasm.exe", "install_dir/bin/rgblink.exe", "install_dir/bin/rgbfix.exe", "install_dir/bin/rgbgfx.exe", "install_dir/bin/zlib1.dll", "install_dir/bin/libpng16.dll") "rgbds-${{ env.version }}-win32.zip"
- name: Build 64-bit zlib
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
cmake -S zlib -B zbuild64 -A x64 -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
cmake --build zbuild64 --config Release
cmake --install zbuild64
- name: Build 64-bit libpng
run: |
cmake -S libpng -B pngbuild64 -A x64 -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=ON -DPNG_TESTS=OFF
cmake --build pngbuild64 --config Release
cmake --install pngbuild64
- name: Build 64-bit Windows binaries
run: |
cmake -S . -B build64 -A x64 -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release
cmake --build build64 --config Release
cmake --install build64
- name: Package 64-bit binaries
run: |
Compress-Archive -LiteralPath @("install_dir/bin/rgbasm.exe", "install_dir/bin/rgblink.exe", "install_dir/bin/rgbfix.exe", "install_dir/bin/rgbgfx.exe", "install_dir/bin/zlib1.dll", "install_dir/bin/libpng16.dll") "rgbds-${{ env.version }}-win64.zip"
- name: Package sources
run: |
make dist
- name: Release
uses: softprops/action-gh-release@v1
with:
body: |
Please ensure that the three assets below work properly.
Once that's done, replace this text with the changelog, un-draft the release, and update the `release` branch.
By the way, if you forgot to update `include/version.h`, RGBASM's version test is gonna fail in the tag's regression testing! (Use `git push --delete origin <tag>` to delete it)
draft: true # Don't publish the release quite yet...
prerelease: ${{ contains(github.ref, '-rc') }}
files: |
rgbds-${{ env.version }}-win32.zip
rgbds-${{ env.version }}-win64.zip
rgbds-${{ env.version }}.tar.gz
fail_on_unmatched_files: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,165 +0,0 @@
name: Create release artifacts
on:
push:
tags:
- v[0-9]*
jobs:
windows:
runs-on: windows-2022
strategy:
matrix:
bits: [32, 64]
include:
- bits: 32
arch: x86
platform: Win32
- bits: 64
arch: x86_x64
platform: x64
fail-fast: false
steps:
- name: Get version from tag
shell: bash
run: | # Turn "vX.Y.Z" into "X.Y.Z"
VERSION="${{ github.ref_name }}"
echo "version=${VERSION#v}" >> $GITHUB_ENV
- name: Checkout repo
uses: actions/checkout@v4
- name: Install deps
run: .github/scripts/get_win_deps.ps1
- name: Check libraries cache
id: cache
uses: actions/cache@v4
with:
path: |
zbuild
pngbuild
key: ${{ matrix.arch }}-${{ hashFiles('zlib/**', 'libpng/**') }}
- name: Build zlib
if: steps.cache.outputs.cache-hit != 'true'
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
cmake -S zlib -B zbuild -A ${{ matrix.platform }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
cmake --build zbuild --config Release -j
- name: Install zlib
run: |
cmake --install zbuild
- name: Build libpng
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
run: |
cmake -S libpng -B pngbuild -A ${{ matrix.platform }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=OFF -DPNG_TESTS=OFF
cmake --build pngbuild --config Release -j
- name: Install libpng
run: |
cmake --install pngbuild
- name: Build Windows binaries
shell: bash
run: |
cmake -S . -B build -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release -j --verbose
cmake --install build --verbose --prefix install_dir --strip
- name: Package binaries
run: |
Compress-Archive -LiteralPath @("install_dir/bin/rgbasm.exe", "install_dir/bin/rgblink.exe", "install_dir/bin/rgbfix.exe", "install_dir/bin/rgbgfx.exe", "install_dir/bin/zlib1.dll", "install_dir/bin/libpng16.dll") "rgbds-win${{ matrix.bits }}.zip"
- name: Upload Windows binaries
uses: actions/upload-artifact@v4
with:
name: win${{ matrix.bits }}
path: rgbds-win${{ matrix.bits }}.zip
macos:
runs-on: macos-14
steps:
- name: Get version from tag
shell: bash
run: | # Turn "refs/tags/vX.Y.Z" into "X.Y.Z"
VERSION="${{ github.ref_name }}"
echo "version=${VERSION#v}" >> $GITHUB_ENV
- name: Checkout repo
uses: actions/checkout@v4
- name: Install deps
shell: bash
run: |
./.github/scripts/install_deps.sh macos
- name: Build libpng
run: |
./.github/scripts/build_libpng.sh
# We force linking libpng statically; the other libs are provided by macOS itself
- name: Build binaries
run: |
make -kj CXXFLAGS="-O3 -flto -DNDEBUG -mmacosx-version-min=10.9 -arch x86_64 -arch arm64" PNGCFLAGS="-I libpng-staging/include" PNGLDLIBS="libpng-staging/lib/libpng.a -lz" Q=
strip rgb{asm,link,fix,gfx}
- name: Package binaries
run: |
zip --junk-paths rgbds-macos.zip rgb{asm,link,fix,gfx} man/* .github/scripts/install.sh
- name: Upload macOS binaries
uses: actions/upload-artifact@v4
with:
name: macos
path: rgbds-macos.zip
linux:
runs-on: ubuntu-22.04 # Oldest supported, for best glibc compatibility.
steps:
- name: Get version from tag
shell: bash
run: | # Turn "refs/tags/vX.Y.Z" into "X.Y.Z"
VERSION="${{ github.ref_name }}"
echo "version=${VERSION#v}" >> $GITHUB_ENV
- name: Checkout repo
uses: actions/checkout@v4
- name: Install deps
shell: bash
run: |
./.github/scripts/install_deps.sh ubuntu-22.04
- name: Build binaries
run: |
make -kj WARNFLAGS="-Wall -Wextra -pedantic -static" PKG_CONFIG="pkg-config --static" Q=
strip rgb{asm,link,fix,gfx}
- name: Package binaries
run: |
tar caf rgbds-linux-x86_64.tar.xz --transform='s#.*/##' rgb{asm,link,fix,gfx} man/* .github/scripts/install.sh
- name: Upload Linux binaries
uses: actions/upload-artifact@v4
with:
name: linux
path: rgbds-linux-x86_64.tar.xz
release:
runs-on: ubuntu-latest
needs: [windows, macos, linux]
permissions:
contents: write
steps:
- name: Get version from tag
shell: bash
run: | # Turn "refs/tags/vX.Y.Z" into "X.Y.Z"
VERSION="${{ github.ref_name }}"
echo "version=${VERSION#v}" >> $GITHUB_ENV
- name: Checkout repo
uses: actions/checkout@v4
- name: Package sources
run: |
make dist Q=
ls
- name: Download Linux binaries
uses: actions/download-artifact@v4
- name: Release
uses: softprops/action-gh-release@v2
with:
body: |
Please ensure that the packages below work properly.
Once that's done, replace this text with the changelog, un-draft the release, and update the `release` branch.
By the way, if you forgot to update `include/version.hpp`, RGBASM's version test is going to fail in the tag's regression testing! (Use `git push --delete origin <tag>` to delete it)
draft: true # Don't publish the release quite yet...
prerelease: ${{ contains(github.ref, '-rc') }}
files: |
win32/rgbds-win32.zip
win64/rgbds-win64.zip
macos/rgbds-macos.zip
linux/rgbds-linux-x86_64.tar.xz
rgbds-source.tar.gz
fail_on_unmatched_files: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,4 +1,4 @@
name: Create release docs name: "Create release docs"
on: on:
release: release:
types: types:
@@ -7,26 +7,32 @@ on:
jobs: jobs:
build: build:
if: github.repository_owner == 'gbdev' if: github.repository_owner == 'gbdev'
runs-on: ubuntu-latest runs-on: ubuntu-18.04
steps: steps:
- name: Checkout rgbds@release - name: Checkout rgbds@release
uses: actions/checkout@v4 uses: actions/checkout@v2
with: with:
path: rgbds path: rgbds
- name: Checkout rgbds-www@master - name: Checkout rgbds-www@master
uses: actions/checkout@v4 uses: actions/checkout@v2
with: with:
repository: ${{ github.repository_owner }}/rgbds-www repository: ${{ github.repository_owner }}/rgbds-www
path: rgbds-www path: rgbds-www
- name: Install groff and mandoc # `-O toc` was added in 1.14.5, but the repos only have 1.14.4
- name: Build and install mandoc + install groff
run: | run: |
sudo apt-get -qq update sudo apt-get -qq update
sudo apt-get install -yq groff mandoc sudo apt-get install -yq groff zlib1g-dev
wget 'http://mandoc.bsd.lv/snapshots/mandoc-1.14.5.tar.gz'
tar xf mandoc-1.14.5.tar.gz
cd mandoc-1.14.5
./configure
make
sudo make install
- name: Update pages - name: Update pages
working-directory: rgbds/man working-directory: rgbds
run: | # The ref appears to be in the format "refs/tags/<version>", so strip that run: | # The ref appears to be in the format "refs/tags/<version>", so strip that
../../rgbds-www/maintainer/man_to_html.sh ${GITHUB_REF##*/} * ./.github/actions/get-pages.sh -r ../rgbds-www ${GITHUB_REF##*/}
../../rgbds-www/maintainer/new_release.sh ${GITHUB_REF##*/}
- name: Push new pages - name: Push new pages
working-directory: rgbds-www working-directory: rgbds-www
run: | run: |

View File

@@ -1,133 +1,64 @@
name: Regression testing name: "Regression testing"
on: on:
- push - push
- pull_request - pull_request
jobs: jobs:
unix: unix-testing:
strategy: strategy:
matrix: matrix:
os: [ubuntu-22.04, macos-14] os: [ubuntu-20.04, ubuntu-18.04, macos-11.0, macos-10.15]
cxx: [g++, clang++] cc: [gcc, clang]
buildsys: [make, cmake] buildsys: [make, cmake]
exclude: exclude:
# Don't use `g++` on macOS; it's just an alias to `clang++`. # `gcc` is just an alias to `clang` on macOS, don't bother
- os: macos-14 - os: macos-10.15
cxx: g++ cc: gcc
- os: macos-11.0
cc: gcc
fail-fast: false fail-fast: false
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout repo - uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install deps - name: Install deps
shell: bash shell: bash
run: | run: |
./.github/scripts/install_deps.sh ${{ matrix.os }} ./.github/actions/install_deps.sh ${{ matrix.os }}
# The `export` lines are to allow working on macOS...
# Apple's base version is severely outdated, not even supporting -Wall,
# but it overrides Homebrew's version nonetheless...
- name: Build & install using Make - name: Build & install using Make
if: matrix.buildsys == 'make'
run: | run: |
make develop -kj Q= CXX=${{ matrix.cxx }} export PATH="/usr/local/opt/bison/bin:$PATH"
make develop -j Q= CC=${{ matrix.cc }}
sudo make install -j Q= sudo make install -j Q=
if: matrix.buildsys == 'make'
- name: Build & install using CMake - name: Build & install using CMake
run: |
export PATH="/usr/local/opt/bison/bin:$PATH"
cmake -S . -B build -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=${{ matrix.cc }} -DSANITIZERS=ON -DMORE_WARNINGS=ON
cmake --build build -j
cp build/src/rgb{asm,link,fix,gfx} .
sudo cmake --install build
if: matrix.buildsys == 'cmake' if: matrix.buildsys == 'cmake'
run: |
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} -DSANITIZERS=ON -DMORE_WARNINGS=ON
cmake --build build -j --verbose
sudo cmake --install build --verbose
- name: Package binaries - name: Package binaries
run: | run: |
mkdir bins mkdir bins
cp rgb{asm,link,fix,gfx} bins cp rgb{asm,link,fix,gfx} bins
- name: Upload binaries - name: Upload binaries
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v1
with: with:
name: rgbds-canary-${{ matrix.os }}-${{ matrix.cxx }}-${{ matrix.buildsys }} name: rgbds-canary-${{ matrix.os }}-${{ matrix.cc }}-${{ matrix.buildsys }}
path: bins path: bins
- name: Compute test dependency cache params - name: Test
id: test-deps-cache-params
shell: bash shell: bash
run: | run: |
paths=$(test/fetch-test-deps.sh --get-paths) test/run-tests.sh
hash=$(test/fetch-test-deps.sh --get-hash)
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
- name: Check test dependency repositories cache
id: test-deps-cache
uses: actions/cache@v4
with:
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
key: ${{ matrix.os }}-${{ steps.test-deps-cache-params.outputs.hash }}
- name: Fetch test dependency repositories
if: steps.test-deps-cache.outputs.cache-hit != 'true'
continue-on-error: true
run: |
test/fetch-test-deps.sh
- name: Install test dependency dependencies
shell: bash
run: |
test/fetch-test-deps.sh --get-deps ${{ matrix.os }}
- name: Run tests
shell: bash
run: |
CXX=${{ matrix.cxx }} test/run-tests.sh --os ${{ matrix.os }}
macos-static: windows-testing:
runs-on: macos-14
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Install deps
shell: bash
run: |
./.github/scripts/install_deps.sh macos
- name: Build libpng
run: |
./.github/scripts/build_libpng.sh
- name: Build & install
run: |
make -kj CXXFLAGS="-O3 -flto -DNDEBUG -mmacosx-version-min=10.9 -arch x86_64 -arch arm64" PNGCFLAGS="-I libpng-staging/include" PNGLDLIBS="libpng-staging/lib/libpng.a -lz" Q=
- name: Package binaries
run: |
mkdir bins
cp rgb{asm,link,fix,gfx} bins
- name: Upload binaries
uses: actions/upload-artifact@v4
with:
name: rgbds-canary-macos-static
path: bins
- name: Compute test dependency cache params
id: test-deps-cache-params
shell: bash
run: |
paths=$(test/fetch-test-deps.sh --get-paths)
hash=$(test/fetch-test-deps.sh --get-hash)
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
- name: Check test dependency repositories cache
id: test-deps-cache
uses: actions/cache@v4
with:
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
key: ${{ matrix.os }}-${{ steps.test-deps-cache-params.outputs.hash }}
- name: Fetch test dependency repositories
if: steps.test-deps-cache.outputs.cache-hit != 'true'
continue-on-error: true
run: |
test/fetch-test-deps.sh
- name: Install test dependency dependencies
shell: bash
run: |
test/fetch-test-deps.sh --get-deps macos
- name: Run tests
shell: bash
run: |
test/run-tests.sh --os macos
windows:
strategy: strategy:
matrix: matrix:
bits: [32, 64] bits: [32, 64]
os: [windows-2022, windows-2025]
include: include:
- bits: 32 - bits: 32
arch: x86 arch: x86
@@ -136,89 +67,70 @@ jobs:
arch: x86_x64 arch: x86_x64
platform: x64 platform: x64
fail-fast: false fail-fast: false
runs-on: ${{ matrix.os }} runs-on: windows-2019
steps: steps:
- name: Checkout repo - uses: actions/checkout@v2
uses: actions/checkout@v4 - name: Get zlib, libpng and bison
- name: Install deps run: | # TODO: use an array
run: .github/scripts/get_win_deps.ps1 $wc = New-Object System.Net.WebClient
- name: Check libraries cache $wc.DownloadFile('https://www.zlib.net/zlib1212.zip', 'zlib.zip')
id: cache $hash = (Get-FileHash "zlib.zip" -Algorithm SHA256).Hash
uses: actions/cache@v4 if ($hash -ne '173e89893dcb8b4a150d7731cd72f0602f1d6b45e60e2a54efdf7f3fc3325fd7') {
with: Write-Host "zlib SHA256 mismatch! ($hash)"
path: | exit 1
zbuild }
pngbuild $wc.DownloadFile('https://download.sourceforge.net/libpng/lpng1637.zip', 'libpng.zip')
key: ${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles('zlib/**', 'libpng/**') }} $hash = (Get-FileHash "libpng.zip" -Algorithm SHA256).Hash
if ($hash -ne '3b4b1cbd0bae6822f749d39b1ccadd6297f05e2b85a83dd2ce6ecd7d09eabdf2') {
Write-Host "libpng SHA256 mismatch! ($hash)"
exit 1
}
$wc.DownloadFile('https://github.com/lexxmark/winflexbison/releases/download/v2.5.24/win_flex_bison-2.5.24.zip', 'winflexbison.zip')
$hash = (Get-FileHash "winflexbison.zip" -Algorithm SHA256).Hash
if ($hash -ne '39c6086ce211d5415500acc5ed2d8939861ca1696aee48909c7f6daf5122b505') {
Write-Host "bison SHA256 mismatch! ($hash)"
}
Expand-Archive -DestinationPath . "zlib.zip"
Expand-Archive -DestinationPath . "libpng.zip"
Expand-Archive -DestinationPath install_dir "winflexbison.zip"
Move-Item zlib-1.2.12 zlib
Move-Item lpng1637 libpng
- name: Build zlib - name: Build zlib
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll` run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
cmake -S zlib -B zbuild -A ${{ matrix.platform }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON cmake -S zlib -B zbuild -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
cmake --build zbuild --config Release -j cmake --build zbuild --config Release -j
- name: Install zlib
run: |
cmake --install zbuild cmake --install zbuild
- name: Build libpng - name: Build libpng
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
run: | run: |
cmake -S libpng -B pngbuild -A ${{ matrix.platform }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=OFF -DPNG_TESTS=OFF cmake -S libpng -B pngbuild -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=ON -DPNG_TESTS=OFF
cmake --build pngbuild --config Release -j cmake --build pngbuild --config Release -j
- name: Install libpng
run: |
cmake --install pngbuild cmake --install pngbuild
- name: Build Windows binaries - name: Build Windows binaries
shell: bash
run: | run: |
cmake -S . -B build -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release cmake -S . -B build -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release -j --verbose cmake --build build --config Release -j
cmake --install build --verbose --prefix install_dir cmake --install build
- name: Package binaries - name: Package binaries
shell: bash shell: bash
run: | run: |
mkdir bins mkdir bins
cp install_dir/bin/{rgbasm.exe,rgblink.exe,rgbfix.exe,rgbgfx.exe,zlib1.dll,libpng16.dll} bins cp install_dir/bin/{rgbasm.exe,rgblink.exe,rgbfix.exe,rgbgfx.exe,zlib1.dll,libpng16.dll} bins
- name: Upload Windows binaries - name: Upload Windows binaries
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v1
with: with:
name: rgbds-canary-w${{ matrix.bits }}-${{ matrix.os }} name: rgbds-canary-win${{ matrix.bits }}
path: bins path: bins
- name: Compute test dependency cache params - name: Test
id: test-deps-cache-params
shell: bash
run: |
paths=$(test/fetch-test-deps.sh --get-paths)
hash=$(test/fetch-test-deps.sh --get-hash)
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
- name: Check test dependency repositories cache
id: test-deps-cache
uses: actions/cache@v4
with:
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
key: ${{ matrix.os }}-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
- name: Fetch test dependency repositories
if: steps.test-deps-cache.outputs.cache-hit != 'true'
shell: bash
continue-on-error: true
run: |
test/fetch-test-deps.sh
- name: Install test dependency dependencies
shell: bash
run: |
test/fetch-test-deps.sh --get-deps ${{ matrix.os }}
- name: Run tests
shell: bash shell: bash
run: | run: |
cp bins/* . cp bins/* .
cp bins/*.dll test/gfx test/run-tests.sh
test/run-tests.sh --os ${{ matrix.os }}
windows-mingw-build: windows-xbuild:
strategy: strategy:
matrix: matrix:
bits: [32, 64] bits: [32, 64]
os: [ubuntu-18.04]
include: include:
- bits: 32 - bits: 32
arch: i686 arch: i686
@@ -227,163 +139,59 @@ jobs:
arch: x86-64 arch: x86-64
triplet: x86_64-w64-mingw32 triplet: x86_64-w64-mingw32
fail-fast: false fail-fast: false
runs-on: ubuntu-22.04 runs-on: ${{ matrix.os }}
env: env:
DIST_DIR: win${{ matrix.bits }} DIST_DIR: win${{ matrix.bits }}
steps: steps:
- name: Checkout repo - uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install deps - name: Install deps
shell: bash shell: bash
run: | run: |
./.github/scripts/install_deps.sh ubuntu ./.github/actions/install_deps.sh ${{ matrix.os }}
- name: Install MinGW - name: Install MinGW
run: | # dpkg-dev is apparently required for pkg-config for cross-building run: |
sudo apt-get install g++-mingw-w64-${{ matrix.arch }}-win32 mingw-w64-tools libz-mingw-w64-dev dpkg-dev sudo apt-get install gcc-mingw-w64-${{ matrix.arch }} mingw-w64-tools libz-mingw-w64-dev
- name: Install libpng dev headers for MinGW - name: Install libpng dev headers for MinGW
run: | run: |
./.github/scripts/mingw-w64-libpng-dev.sh ${{ matrix.triplet }} sudo ./.github/actions/mingw-w64-libpng-dev.sh ${{ matrix.triplet }}
- name: Cross-build Windows binaries - name: Cross-build Windows binaries
run: | run: |
make mingw${{ matrix.bits }} -kj Q= make mingw${{ matrix.bits }} -j Q=
- name: Package binaries - name: Package binaries
run: | # DLL dependencies can be figured out using e.g. Dependency Walker or objdump -p run: |
mkdir bins mkdir bins
mv -v rgb{asm,link,fix,gfx}.exe bins/ mv rgbasm bins/rgbasm.exe
cp -v /usr/${{ matrix.triplet }}/lib/zlib1.dll bins mv rgblink bins/rgblink.exe
cp -v /usr/${{ matrix.triplet }}/bin/libpng16-16.dll bins mv rgbfix bins/rgbfix.exe
cp -v /usr/lib/gcc/${{ matrix.triplet }}/10-win32/lib{ssp-0,stdc++-6}.dll bins mv rgbgfx bins/rgbgfx.exe
[ "${{ matrix.bits }}" -ne 32 ] || cp -v /usr/lib/gcc/${{ matrix.triplet }}/10-win32/libgcc_s_dw2-1.dll bins cp /usr/${{ matrix.triplet }}/lib/zlib1.dll bins
cp /usr/${{ matrix.triplet }}/bin/libpng16-16.dll bins
if [ ${{ matrix.bits }} -eq 32 ]; then cp /usr/lib/gcc/${{ matrix.triplet }}/7.3-win32/libgcc_s_sjlj-1.dll bins; fi
- name: Upload Windows binaries - name: Upload Windows binaries
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v1
with: with:
name: rgbds-canary-mingw-win${{ matrix.bits }} name: rgbds-canary-mingw-win${{ matrix.bits }}
path: bins path: bins
- name: Upload Windows test binaries
uses: actions/upload-artifact@v4
with:
name: testing-programs-mingw-win${{ matrix.bits }}
path: |
test/gfx/randtilegen.exe
test/gfx/rgbgfx_test.exe
windows-mingw-testing: windows-xtesting:
needs: windows-mingw-build needs: windows-xbuild
strategy: strategy:
matrix: matrix:
os: [windows-2022, windows-2025]
bits: [32, 64] bits: [32, 64]
fail-fast: false fail-fast: false
runs-on: ${{ matrix.os }} runs-on: windows-2019
steps: steps:
- name: Checkout repo - uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Retrieve binaries - name: Retrieve binaries
uses: actions/download-artifact@v4 uses: actions/download-artifact@v1
with: with:
name: rgbds-canary-mingw-win${{ matrix.bits }} name: rgbds-canary-mingw-win${{ matrix.bits }}
path: bins path: bins
- name: Retrieve test binaries
uses: actions/download-artifact@v4
with:
name: testing-programs-mingw-win${{ matrix.bits }}
path: test/gfx
- name: Extract binaries - name: Extract binaries
shell: bash shell: bash
run: | run: |
cp bins/* . cp bins/* .
cp bins/*.dll test/gfx
- name: Compute test dependency cache params
id: test-deps-cache-params
shell: bash
run: |
paths=$(test/fetch-test-deps.sh --get-paths)
hash=$(test/fetch-test-deps.sh --get-hash)
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
- name: Check test dependency repositories cache
id: test-deps-cache
uses: actions/cache@v4
with:
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
key: mingw-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
- name: Fetch test dependency repositories
if: steps.test-deps-cache.outputs.cache-hit != 'true'
shell: bash
continue-on-error: true
run: |
test/fetch-test-deps.sh
- name: Install test dependency dependencies
shell: bash
run: |
test/fetch-test-deps.sh --get-deps ${{ matrix.os }}
- name: Run tests - name: Run tests
shell: bash shell: bash
run: | run: |
test/run-tests.sh --os ${{ matrix.os }} test/run-tests.sh
cygwin:
strategy:
matrix:
bits: [32, 64]
include:
- bits: 32
arch: x86
- bits: 64
arch: x86_64
fail-fast: false
runs-on: windows-2022
timeout-minutes: 30
steps:
- name: Checkout repo
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Setup Cygwin
uses: cygwin/cygwin-install-action@v4
with:
platform: ${{ matrix.arch }}
packages: >-
bison
gcc-g++
git
libpng-devel
make
pkg-config
- name: Build & install using Make
shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -o igncr '{0}'
run: | # Cygwin does not support `make develop` sanitizers ASan or UBSan
make -kj Q=
make install -j Q=
- name: Run tests
shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -o igncr '{0}'
run: |
test/run-tests.sh --only-internal
freebsd:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Build & test using CMake on FreeBSD
uses: vmactions/freebsd-vm@v1
with:
release: "14.3"
usesh: true
prepare: |
pkg install -y \
bash \
bison \
cmake \
git \
png
run: | # FreeBSD `c++` compiler does not support `make develop` sanitizers ASan or UBSan
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=c++ -DUSE_EXTERNAL_TESTS=OFF -DOS=bsd
cmake --build build -j4 --verbose
cmake --install build --verbose
cmake --build build --target test

View File

@@ -1,45 +1,51 @@
name: Update master docs name: "Update master docs"
on: on:
push: push:
branches: branches:
- master - master
paths: paths:
- man/gbz80.7 - .github/actions/get-pages.sh
- man/rgbds.5 - src/gbz80.7
- man/rgbds.7 - src/rgbds.5
- man/rgbasm.1 - src/rgbds.7
- man/rgbasm.5 - src/asm/rgbasm.1
- man/rgbasm-old.5 - src/asm/rgbasm.5
- man/rgblink.1 - src/link/rgblink.1
- man/rgblink.5 - src/link/rgblink.5
- man/rgbfix.1 - src/fix/rgbfix.1
- man/rgbgfx.1 - src/gfx/rgbgfx.1
jobs: jobs:
build: build:
if: github.repository_owner == 'gbdev' if: github.repository_owner == 'gbdev'
runs-on: ubuntu-latest runs-on: ubuntu-18.04
steps: steps:
- name: Checkout rgbds@master - name: Checkout rgbds@master
uses: actions/checkout@v4 uses: actions/checkout@v2
with: with:
repository: gbdev/rgbds repository: gbdev/rgbds
ref: master ref: master
path: rgbds path: rgbds
- name: Checkout rgbds-www@master - name: Checkout rgbds-www@master
uses: actions/checkout@v4 uses: actions/checkout@v2
with: with:
repository: gbdev/rgbds-www repository: gbdev/rgbds-www
ref: master ref: master
path: rgbds-www path: rgbds-www
- name: Install groff and mandoc - name: Build and install mandoc + install groff
run: | run: |
sudo apt-get -qq update sudo apt-get -qq update
sudo apt-get install -yq groff mandoc sudo apt-get install -yq groff zlib1g-dev
wget 'http://mandoc.bsd.lv/snapshots/mandoc-1.14.5.tar.gz'
tar xf mandoc-1.14.5.tar.gz
cd mandoc-1.14.5
./configure
make
sudo make install
- name: Update pages - name: Update pages
working-directory: rgbds/man working-directory: rgbds
run: | run: |
../../rgbds-www/maintainer/man_to_html.sh master * ./.github/actions/get-pages.sh ../rgbds-www master
- name: Push new pages - name: Push new pages
working-directory: rgbds-www working-directory: rgbds-www
run: | run: |
@@ -50,7 +56,7 @@ jobs:
ssh-add ~/.ssh/id_ed25519 ssh-add ~/.ssh/id_ed25519
git config --global user.name "GitHub Action" git config --global user.name "GitHub Action"
git config --global user.email "community@gbdev.io" git config --global user.email "community@gbdev.io"
git add -A git add .
git commit -m "Update RGBDS master documentation" git commit -m "Update RGBDS master documentation"
if git remote | grep -q origin; then if git remote | grep -q origin; then
git remote set-url origin git@github.com:gbdev/rgbds-www.git git remote set-url origin git@github.com:gbdev/rgbds-www.git

8
.gitignore vendored
View File

@@ -3,16 +3,10 @@
/rgbfix /rgbfix
/rgbgfx /rgbgfx
/rgbshim.sh /rgbshim.sh
/coverage/
*.o *.o
*.exe *.exe
*.dll *.dll
*.gcno .checkpatch-camelcase.*
*.gcda
*.gcov
CMakeCache.txt CMakeCache.txt
CMakeFiles/ CMakeFiles/
cmake_install.cmake cmake_install.cmake
build/
*.dSYM/
callgrind.out.*

View File

@@ -1,279 +0,0 @@
# RGBDS Architecture
The RGBDS package consists of four programs: RGBASM, RGBLINK, RGBFIX, and RGBGFX.
- RGBASM is the assembler. It takes assembly code as input, and produces an RGB object file as output (and optionally a state file, logging the final state of variables and constants).
- RGBLINK is the linker. It takes object files as input, and produces a ROM file as output (and optionally a symbol and/or map file, logging where the assembly declarations got placed in the ROM).
- RGBFIX is the checksum/header fixer. It takes a ROM file as input, and outputs the same ROM file (or modifies it in-place) with the cartridge header's checksum and other metadata fixed for consistency.
- RGBGFX is the graphics converter. It takes a PNG image file as input, and outputs the tile data, palettes, tilemap, attribute map, and/or palette map in formats that the Game Boy can use.
In the simplest case, a single pipeline can turn an assembly file into a ROM:
```console
(rgbasm -o - - | rgblink -o - - | rgbfix -v -p 0) < game.asm > game.gb
```
This document describes how these four programs are structured. It goes over each source code file, noting which data is *global* (and thus scoped in all files), *owned* by that file (i.e. that is where the data's memory is managed, via [RAII](https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization)) or *referenced* by that file (i.e. there are non-owning pointers to some data, and care must be taken to not dereference those pointers after the data's owner has moved or deleted the data).
We assume that the programs are single-threaded; data structures and operations may not be thread-safe.
## Folder Organization
The RGBDS source code file structure is as follows:
```
rgbds/
├── .github/
│ ├── scripts/
│ │ └── ...
│ └── workflows/
│ └── ...
├── contrib/
│ ├── bash_compl/
│ ├── zsh_compl/
│ │ └── ...
│ └── ...
├── include/
│ └── ...
├── man/
│ └── ...
├── src/
│ ├── asm/
│ │ └── ...
│ ├── extern/
│ │ └── ...
│ ├── fix/
│ │ └── ...
│ ├── gfx/
│ │ └── ...
│ ├── link/
│ │ └── ...
│ ├── CMakeLists.txt
│ ├── bison.sh
│ └── ...
├── test/
│ ├── fetch-test-deps.sh
│ ├── run-tests.sh
│ └── ...
├── .clang-format
├── .clang-tidy
├── CMakeLists.txt
├── compile_flags.txt
├── Dockerfile
└── Makefile
```
- **`.github/`:**
Files related to the integration of the RGBDS codebase with GitHub features.
* **`scripts/`:**
Scripts used by GitHub Actions workflow files.
* **`workflows/`:**
GitHub Actions CI workflow description files. Used for automated testing, deployment, etc.
- **`contrib/`:**
Scripts and other resources which may be useful to RGBDS users and developers.
* **`bash_compl/`:**
Tab completion scripts for use with `bash`. Run them with `source` somewhere in your `.bashrc`, and they should auto-load when you open a shell.
* **`zsh_compl/`:**
Tab completion scripts for use with `zsh`. Put them somewhere in your `fpath`, and they should auto-load when you open a shell.
- **`include/`:**
Header files for the respective source files in `src`.
- **`man/`:**
Manual pages to be read with `man`, written in the [`mandoc`](https://mandoc.bsd.lv) dialect.
- **`src/`:**
Source code of RGBDS.
* **`asm/`:**
Source code of RGBASM.
* **`extern/`:**
Source code copied from external sources.
* **`fix/`:**
Source code of RGBFIX.
* **`gfx/`:**
Source code of RGBGFX.
* **`link/`:**
Source code of RGBLINK.
* **`CMakeLists.txt`:**
Defines how to build individual RGBDS programs with CMake, including the source files that each program depends on.
* **`bison.sh`:**
Script used to run the Bison parser generator with the latest flags that the user's version supports.
- **`test/`:**
Testing framework used to verify that changes to the code don't break or modify the behavior of RGBDS.
* **`fetch-test-deps.sh`:**
Script used to fetch dependencies for building external repositories. `fetch-test-deps.sh --help` describes its options.
* **`run-tests.sh`:**
Script used to run tests, including internal test cases and external repositories. `run-tests.sh --help` describes its options.
- **`.clang-format`:**
Code style for automated C++ formatting with [`clang-format`](https://clang.llvm.org/docs/ClangFormat.html) (for which we define the shortcut `make format`).
- **`.clang-tidy`:**
Configuration for C++ static analysis with [`clang-tidy`](https://clang.llvm.org/extra/clang-tidy/) (for which we define the shortcut `make tidy`).
- **`CMakeLists.txt`:**
Defines how to build RGBDS with CMake.
- **`compile_flags.txt`:**
Compiler flags for `clang-tidy`.
- **`Dockerfile`:**
Defines how to build RGBDS with Docker (which we do in CI to provide a [container image](https://github.com/gbdev/rgbds/pkgs/container/rgbds)).
- **`Makefile`:**
Defines how to build RGBDS with `make`, including the source files that each program depends on.
## RGBDS
These files in the `src/` directory are shared across multiple programs: often all four (RGBASM, RGBLINK, RGBFIX, and RGBGFX), sometimes only RGBASM and RGBLINK.
- **`backtrace.cpp`:**
Generic printing of location backtraces for RGBASM and RGBLINK. Allows configuring backtrace styles with a command-line flag (conventionally `-B/--backtrace`). Renders warnings in yellow, errors in red, and locations in cyan.
- **`cli.cpp`:**
A function for parsing command-line options, including RGBDS-specific "at-files" (a filename containing more options, prepended with an "`@`").
This is the only file to use the extern/getopt.cpp variables and functions.
- **`diagnostics.cpp`:**
Generic warning/error diagnostic support for all programs. Allows command-line flags (conventionally `-W`) to have `no-`, `error=`, or `no-error=` prefixes, and `=` level suffixes; allows "meta" flags to affect groups of individual flags; and counts how many total errors there have been. Every program has its own `warning.cpp` file that uses this.
- **`linkdefs.cpp`:**
Constants, data, and functions related to RGBDS object files, which are used for RGBASM output and RGBLINK input.
This file defines two *global* variables, `sectionTypeInfo` (metadata about each section type) and `sectionModNames` (names of section modifiers, for error reporting). RGBLINK may change some values in `sectionTypeInfo` depending on its command-line options (this only affects RGBLINK; `sectionTypeInfo` is immutable in RGBASM).
- **`opmath.cpp`:**
Functions for mathematical operations in RGBASM and RGBLINK that aren't trivially equivalent to built-in C++ ones, such as division and modulo with well-defined results for negative values.
- **`style.cpp`:**
Generic printing of cross-platform colored or bold text. Obeys the [`FORCE_COLOR`](https://force-color.org/) and [`NO_COLOR`](https://no-color.org/) environment variables, and allows configuring with a command-line flag (conventionally `--color`).
- **`usage.cpp`:**
Generic printing of usage information. Renders headings in green, flags in cyan, and URLs in blue. Every program has its own `main.cpp` file that uses this.
- **`util.cpp`:**
Utility functions applicable to most programs, mostly dealing with text strings, such as locale-independent character checks.
- **`verbosity.cpp`:**
Generic printing of messages conditionally at different verbosity levels. Allows configuring with a command-line flag (conventionally `-v/--verbose`).
- **`version.cpp`:**
RGBDS version number and string for all the programs.
## External
These files have been copied ("vendored") from external authors and adapted for use with RGBDS. Both of our vendored dependencies use the same MIT license as RGBDS.
- **`getopt.cpp`:**
Functions for parsing command-line options, including conventional single-dash and double-dash options.
This file defines some *global* `musl_opt*` variables, including `musl_optarg` (the argument given after an option flag) and `musl_optind` (the index of the next option in `argv`). Copied from [musl libc](https://musl.libc.org/).
- **`utf8decoder.cpp`:**
Function for decoding UTF-8 bytes into Unicode code points. Copied from [Björn Höhrmann](https://bjoern.hoehrmann.de/utf-8/decoder/dfa/).
## RGBASM
- **`actions.cpp`:**
Actions taken by the assembly language parser, to avoid large amounts of code going in the parser.y file.
- **`charmap.cpp`:**
Functions and data related to charmaps.
This file *owns* the `Charmap`s in its `charmaps` collection. It also maintains a static `currentCharmap` pointer, and a `charmapStack` stack of pointers to `Charmap`s within `charmaps` (which is affected by `PUSHC` and `POPC` directives).
- **`fixpoint.cpp`:**
Functions for fixed-point math, with configurable [Q*m*.*n*](https://en.wikipedia.org/wiki/Q_(number_format)) precision.
- **`format.cpp`:**
`FormatSpec` methods for parsing and applying format specs, as used by `{interpolations}` and `STRFMT`.
- **`fstack.cpp`:**
Functions and data related to "fstack" nodes (the contents of top-level or `INCLUDE`d files, macro expansions, or `REPT`/`FOR` loop iterations) and their "contexts" (metadata that is only relevant while a node's content is being lexed and parsed).
This file *owns* the `Context`s in its `contextStack` collection. Each of those `Context`s *owns* its `LexerState`, and *refers* to its `FileStackNode`, `uniqueIDStr`, and `macroArgs`. Each `FileStackNode` also *references* its `parent`.
- **`lexer.cpp`:**
Functions and data related to [lexing](https://en.wikipedia.org/wiki/Lexical_analysis) assembly source code into tokens, which can then be parsed.
This file maintains static `lexerState` and `lexerStateEOL` pointers to `LexerState`s from the `Context`s in `fstack.cpp`.
Each `LexerState` *owns* its `content` and its `expansions`' content. Each `Expansion` (the contents of an `{interpolation}` or macro argument) in turn *owns* its `contents`.
The lexer and parser are interdependent: when the parser reaches certain tokens, it changes the lexer's mode, which affects how characters get lexed into tokens. For example, when the parser reaches a macro name, it changes the lexer to "raw" mode, which lexes the rest of the line as a sequence of string arguments to the macro.
- **`macro.cpp`:**
`MacroArgs` methods related to macro arguments. Each `MacroArgs` *references* its arguments' contents.
- **`main.cpp`:**
The `main` function for running RGBASM, including the initial handling of command-line options.
This file defines a *global* `options` variable with the parsed CLI options.
- **`opt.cpp`:**
Functions for parsing options specified by `OPT` or by certain command-line options.
This file *owns* the `OptStackEntry`s in its `stack` collection (which is affected by `PUSHO` and `POPO` directives).
- **`output.cpp`:**
Functions and data related to outputting object files (with `-o/--output`) and state files (with `-s/--state`).
This file *owns* its `assertions` (created by `ASSERT` and `STATIC_ASSERT` directives). Every assertion gets output in the object file.
This file also *references* some `fileStackNodes`, and maintains static pointers to `Symbol`s in `objectSymbols`. Only the "registered" symbols and fstack nodes get output in the object file. The `fileStackNodes` and `objectSymbols` collections keep track of which nodes and symbols have been registered for output.
- **`parser.y`:**
Grammar for the RGBASM assembly language, which Bison preprocesses into a [LALR(1) parser](https://en.wikipedia.org/wiki/LALR_parser).
The Bison-generated parser calls `yylex` (defined in `lexer.cpp`) to get the next token, and calls `yywrap` (defined in `fstack.cpp`) when the current context is out of tokens and returns `EOF`.
- **`rpn.cpp`:**
`Expression` methods and data related to "[RPN](https://en.wikipedia.org/wiki/Reverse_Polish_notation)" expressions. When a numeric expression is parsed, if its value cannot be calculated at assembly time, it is built up into a buffer of RPN-encoded operations to do so at link time by RGBLINK. The valid RPN operations are defined in [man/rgbds.5](man/rgbds.5).
- **`section.cpp`:**
Functions and data related to `SECTION`s.
This file *owns* the `Section`s in its `sections` collection. It also maintains various static pointers to those sections, including the `currentSection`, `currentLoadSection`, and `sectionStack` (which is affected by `PUSHS` and `POPS` directives). (Note that sections cannot be deleted.)
- **`symbol.cpp`:**
Functions and data related to symbols (labels, constants, variables, string constants, macros, etc).
This file *owns* the `Symbol`s in its `symbols` collection, and the various built-in ones outside that collection (`PCSymbol` for "`@`", `NARGSymbol` for "`_NARG`", etc). It also maintains a static `purgedSymbols` collection to remember which symbol names have been `PURGE`d from `symbols`, for error reporting purposes.
- **`warning.cpp`:**
Functions and data for warning and error output.
This file defines a *global* `warnings` variable using the `diagnostics.cpp` code for RGBASM-specific warning flags.
## RGBFIX
- **`fix.cpp`:**
Functions for fixing the ROM header.
- **`main.cpp`:**
The `main` function for running RGBFIX, including the initial handling of command-line options.
This file defines a *global* `options` variable with the parsed CLI options.
- **`mbc.cpp`:**
Functions and data related to [MBCs](https://gbdev.io/pandocs/MBCs.html), including the names of known MBC values.
- **`warning.cpp`:**
Functions and data for warning and error output.
This file defines a *global* `warnings` variable using the `diagnostics.cpp` code for RGBFIX-specific warning flags.
## RGBGFX
- **`color_set.cpp`:**
`ColorSet` methods for creating and comparing sets of colors. A color set includes the unique colors used by a single tile, and these sets are then packed into palettes.
- **`main.cpp`:**
The `main` function for running RGBGFX, including the initial handling of command-line options.
This file defines a *global* `options` variable with the parsed CLI options.
- **`pal_packing.cpp`:**
Functions for packing color sets into palettes. This is done with an ["overload-and-remove" heuristic](https://arxiv.org/abs/1605.00558) for a pagination algorithm.
- **`pal_sorting.cpp`:**
Functions for sorting colors within palettes, which works differently for grayscale, RGB, or indexed-color palettes.
- **`pal_spec.cpp`:**
Functions for parsing various formats of palette specifications (from `-c/--colors`).
- **`palette.cpp`:**
`Palette` methods for working with up to four GBC-native (RGB555) colors.
- **`png.cpp`:**
`Png` methods for reading PNG image files, standardizing them to 8-bit RGBA pixels while also reading their indexed palette if there is one.
- **`process.cpp`:**
Functions related to generating and outputting files (tile data, palettes, tilemap, attribute map, and/or palette map).
- **`reverse.cpp`:**
Functions related to reverse-generating RGBGFX outputs into a PNG file (for `-r/--reverse`).
- **`rgba.cpp`:**
`Rgba` methods related to RGBA colors and their 8-bit or 5-bit representations.
- **`warning.cpp`:**
Functions and data for warning and error output.
This file defines a *global* `warnings` variable using the `diagnostics.cpp` code for RGBGFX-specific warning flags.
## RGBLINK
- **`assign.cpp`:**
Functions and data for assigning `SECTION`s to specific banks and addresses.
This file *owns* the `memory` table of free space: each section type is associated with a list of each bank's free address ranges, which are allocated to sections using a [first-fit decreasing](https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm) bin-packing algorithm.
- **`fstack.cpp`:**
Functions related to "fstack" nodes (the contents of top-level or `INCLUDE`d files, macro expansions, or `REPT`/`FOR` loop iterations) read from the object files. At link time, these nodes are only needed for printing of location backtraces.
- **`layout.cpp`:**
Actions taken by the linker script parser, to avoid large amounts of code going in the script.y file.
This file maintains some static data about the current bank and address layout, which get checked and updated for consistency as the linker script is parsed.
- **`lexer.cpp`:**
Functions and data related to [lexing](https://en.wikipedia.org/wiki/Lexical_analysis) linker script files into tokens, which can then be parsed.
This file *owns* the `LexerStackEntry`s in its `lexerStack` collection. Each of those `LexerStackEntry`s *owns* its `file`. The stack is updated as linker scripts can `INCLUDE` other linker script pieces.
The linker script lexer is simpler than the RGBASM one, and does not have modes.
- **`main.cpp`:**
The `main` function for running RGBLINK, including the initial handling of command-line options.
This file defines a *global* `options` variable with the parsed CLI options.
- **`object.cpp`:**
Functions and data for reading object files generated by RGBASM.
This file *owns* the `Symbol`s in its `symbolLists` collection, and the `FileStackNode`s in its `nodes` collection.
- **`output.cpp`:**
Functions and data related to outputting ROM files (with `-o/--output`), symbol files (with `-n/--sym`), and map files (with `-m/--map`).
This file *references* some `Symbol`s and `Section`s, in collections that keep them sorted by address and name, which allows the symbol and map output to be in order.
- **`patch.cpp`:**
Functions and data related to "[RPN](https://en.wikipedia.org/wiki/Reverse_Polish_notation)" expression patches read from the object files, including the ones for `ASSERT` conditions. After sections have been assigned specific locations, the RPN patches can have their values calculated and applied to the ROM. The valid RPN operations are defined in [man/rgbds.5](man/rgbds.5).
This file *owns* the `Assertion`s in its `assertions` collection, and the `RPNStackEntry`s in its `rpnStack` collection.
- **`script.y`:**
Grammar for the linker script language, which Bison preprocesses into a [LALR(1) parser](https://en.wikipedia.org/wiki/LALR_parser).
The Bison-generated parser calls `yylex` (defined in `lexer.cpp`) to get the next token, and calls `yywrap` (also defined in `lexer.cpp`) when the current context is out of tokens and returns `EOF`.
- **`sdas_obj.cpp`:**
Functions and data for reading object files generated by [GBDK with SDCC](https://gbdk.org/). RGBLINK support for these object files is incomplete.
- **`section.cpp`:**
Functions and data related to `SECTION`s read from the object files.
This file *owns* the `Section`s in its `sections` collection.
- **`symbol.cpp`:**
Functions and data related to symbols read from the object files.
This file *references* the `Symbol`s in its `symbols` and `localSymbols` collections, which allow accessing symbols by name.
- **`warning.cpp`:**
Functions and data for warning and error output.
This file defines a *global* `warnings` variable using the `diagnostics.cpp` code for RGBLINK-specific warning flags.

View File

@@ -1,13 +1,16 @@
#
# This file is part of RGBDS.
#
# Copyright (c) 2020 RGBDS contributors.
#
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
#
# 3.9 required for LTO checks # 3.9 required for LTO checks
# 3.17 optional for CMAKE_CTEST_ARGUMENTS cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
cmake_minimum_required(VERSION 3.9..3.17 FATAL_ERROR)
project(rgbds project(rgbds
LANGUAGES CXX) LANGUAGES C)
include(CTest)
# get real path of source and binary directories # get real path of source and binary directories
get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH) get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH)
@@ -24,45 +27,36 @@ option(SANITIZERS "Build with sanitizers enabled" OFF) # Ignored on MSVC
option(MORE_WARNINGS "Turn on more warnings" OFF) # Ignored on MSVC option(MORE_WARNINGS "Turn on more warnings" OFF) # Ignored on MSVC
if(MSVC) if(MSVC)
# MSVC's own standard library triggers warning C5105, # MSVC's standard library triggers warning C5105,
# "macro expansion producing 'defined' has undefined behavior". # "macro expansion producing 'defined' has undefined behavior"
# Warning C5030 is about unknown attributes (`[[gnu::ATTR]]`), none of ours being load-bearing. add_compile_options(/std:c11 /W1 /MP /wd5105)
# Warning C4996 is about using POSIX names, which we want to do for portability.
# We also opt into the C++20-conformant preprocessor.
add_compile_options(/MP /wd5105 /wd5030 /wd4996 /Zc:preprocessor)
add_definitions(/D_CRT_SECURE_NO_WARNINGS) add_definitions(/D_CRT_SECURE_NO_WARNINGS)
if(SANITIZERS)
set(SAN_FLAGS /fsanitize=address)
add_compile_options(${SAN_FLAGS})
add_link_options(${SAN_FLAGS})
endif()
else() else()
add_compile_options(-Wall -pedantic) add_compile_options(-Wall -pedantic)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_definitions(-D_POSIX_C_SOURCE=200809L -D_ISOC11_SOURCE)
# C++20 allows macros to take zero variadic arguments, but Clang (aka AppleClang on macOS)
# does not recognize this yet.
add_compile_options(-Wno-gnu-zero-variadic-macro-arguments)
endif()
if(SANITIZERS) if(SANITIZERS)
set(SAN_FLAGS -fsanitize=address -fsanitize=undefined set(SAN_FLAGS -fsanitize=shift -fsanitize=integer-divide-by-zero
-fsanitize=float-divide-by-zero) -fsanitize=unreachable -fsanitize=vla-bound
-fsanitize=signed-integer-overflow -fsanitize=bounds
-fsanitize=object-size -fsanitize=bool -fsanitize=enum
-fsanitize=alignment -fsanitize=null -fsanitize=address)
add_compile_options(${SAN_FLAGS}) add_compile_options(${SAN_FLAGS})
add_link_options(${SAN_FLAGS}) link_libraries(${SAN_FLAGS})
add_definitions(-D_GLIBCXX_ASSERTIONS)
# A non-zero optimization level is desired in debug mode, but allow overriding it nonetheless # A non-zero optimization level is desired in debug mode, but allow overriding it nonetheless
set(CMAKE_CXX_FLAGS_DEBUG "-g -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls ${CMAKE_CXX_FLAGS_DEBUG}" # TODO: this overrides anything previously set... that's a bit sloppy!
CACHE STRING "" FORCE) set(CMAKE_C_FLAGS_DEBUG "-g -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls" CACHE STRING "" FORCE)
endif() endif()
if(MORE_WARNINGS) if(MORE_WARNINGS)
add_compile_options(-Werror -Wextra add_compile_options(-Werror -Wextra
-Walloc-zero -Wcast-align -Wcast-qual -Wduplicated-branches -Wduplicated-cond -Walloc-zero -Wcast-align -Wcast-qual -Wduplicated-branches -Wduplicated-cond
-Wfloat-equal -Wlogical-op -Wnull-dereference -Wold-style-cast -Wshift-overflow=2 -Wfloat-equal -Winline -Wlogical-op -Wnested-externs -Wnull-dereference
-Wstringop-overflow=4 -Wtrampolines -Wundef -Wuninitialized -Wunused -Wshadow -Wold-style-definition -Wshift-overflow=2 -Wstrict-overflow=5
-Wstrict-prototypes -Wstringop-overflow=4 -Wundef -Wuninitialized -Wunused
-Wshadow # TODO: -Wshadow=compatible-local ?
-Wformat=2 -Wformat-overflow=2 -Wformat-truncation=1 -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=1
-Wno-format-nonliteral -Wno-strict-overflow -Wno-format-nonliteral # We have a couple of "dynamic" prints
-Wno-unused-but-set-variable # bison's `yynerrs_` is incremented but unused # We do some range checks that are always false on some platforms (GCC, Clang)
-Wno-type-limits -Wno-tautological-constant-out-of-range-compare -Wno-type-limits -Wno-tautological-constant-out-of-range-compare
-Wvla # MSVC does not support VLAs -Wvla # MSVC does not support VLAs
-Wno-unknown-warning-option) # Clang shouldn't diagnose unknown warnings -Wno-unknown-warning-option) # Clang shouldn't diagnose unknown warnings
@@ -74,7 +68,7 @@ endif()
find_program(GIT git) find_program(GIT git)
if(GIT) if(GIT)
execute_process(COMMAND ${GIT} --git-dir=.git -c safe.directory='*' describe --tags --dirty --always execute_process(COMMAND ${GIT} describe --tags --dirty --always
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_REV OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE GIT_REV OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET) ERROR_QUIET)
@@ -83,24 +77,12 @@ else(GIT)
message(STATUS "Cannot determine RGBDS version (Git not installed), falling back") message(STATUS "Cannot determine RGBDS version (Git not installed), falling back")
endif(GIT) endif(GIT)
find_package(PkgConfig)
if(MSVC OR NOT PKG_CONFIG_FOUND)
# fallback to find_package
# cmake's FindPNG is very fragile; it breaks when multiple versions are installed
# this is most evident on macOS but can occur on Linux too
find_package(PNG REQUIRED)
else()
pkg_check_modules(LIBPNG REQUIRED libpng)
endif()
include_directories("${PROJECT_SOURCE_DIR}/include") include_directories("${PROJECT_SOURCE_DIR}/include")
set(CMAKE_CXX_STANDARD 20) set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_C_STANDARD_REQUIRED True)
add_subdirectory(src) add_subdirectory(src)
set(CMAKE_CTEST_ARGUMENTS "--verbose")
add_subdirectory(test)
# By default, build in Release mode; Debug mode must be explicitly requested # By default, build in Release mode; Debug mode must be explicitly requested
# (You may want to augment it with the options above) # (You may want to augment it with the options above)
@@ -115,20 +97,3 @@ if(CMAKE_BUILD_TYPE STREQUAL "Release")
message(CHECK_FAIL "no") message(CHECK_FAIL "no")
endif() endif()
endif() endif()
set(MANDIR "share/man")
set(man1 "man/rgbasm.1"
"man/rgbfix.1"
"man/rgbgfx.1"
"man/rgblink.1")
set(man5 "man/rgbasm.5"
"man/rgbasm-old.5"
"man/rgblink.5"
"man/rgbds.5")
set(man7 "man/gbz80.7"
"man/rgbds.7")
foreach(SECTION "man1" "man5" "man7")
set(DEST "${MANDIR}/${SECTION}")
install(FILES ${${SECTION}} DESTINATION ${DEST})
endforeach()

View File

@@ -1,257 +0,0 @@
# Contributing
RGBDS was created in the late '90s and has received contributions from several
developers since then. It wouldn't have been possible to get to this point
without their work, and it is always open to the contributions of other people.
## Reporting Bugs
Bug reports are essential to improve RGBDS and they are always welcome. If you
want to report a bug:
1. Make sure that there isn't a similar issue
[already reported](https://github.com/gbdev/rgbds/issues).
2. Figure out a way of reproducing it reliably.
3. If there is a piece of code that triggers the bug, try to reduce it to the
smallest file you can.
4. Create a new [issue](https://github.com/gbdev/rgbds/issues).
Of course, it may not always be possible to give an accurate bug report, but it
always helps to fix it.
## Requesting new features
If you come up with a good idea that could be implemented, you can propose it to
be done.
1. Create a new [issue](https://github.com/gbdev/rgbds/issues).
2. Try to be as accurate as possible. Describe what you need and why you need
it, maybe with examples.
Please understand that the contributors are doing it in their free time, so
simple requests are more likely to catch the interest of a contributor than
complicated ones. If you really need something to be done, and you think you can
implement it yourself, you can always contribute to RGBDS with your own code.
## Contributing code
If you want to contribute with your own code, whether it is to fix a current
issue or to add something that nobody had requested, you should first consider
if your change is going to be small (and likely to be accepted as-is) or big
(and will have to go through some rework).
Big changes will most likely require some discussion, so open an
[issue](https://github.com/gbdev/rgbds/issues) and explain what you want to
do and how you intend to do it. If you already have a prototype, it's always a
good idea to show it. Tests help, too.
If you are going to work on a specific issue that involves a lot of work, it is
always a good idea to leave a message, just in case someone else is interested
but doesn't know that there's someone working on it.
Note that you must contribute all your changes under the MIT License. If you are
just modifying a file, you don't need to do anything (maybe update the copyright
years). If you are adding new files, you need to use the
`SPDX-License-Identifier: MIT` header.
1. Fork this repository.
2. Checkout the `master` branch.
3. Create a new branch to work on. You could still work on `master`, but it's
easier that way.
4. Compile your changes with `make develop` instead of just `make`. This
target checks for additional warnings. Your patches shouldn't introduce any
new warning (but it may be possible to remove some warning checks if it makes
the code much easier).
5. Test your changes by running `./run-tests.sh` in the `test` directory.
(You must run `./fetch-test-deps.sh` first; if you forget to, the test suite
will fail and remind you mid-way.)
5. Format your changes according to `clang-format`, which will reformat the
coding style according to our standards defined in `.clang-format`.
6. Create a pull request against the branch `master`.
7. Check the results of the GitHub Actions CI jobs for your pull request. The
"Code format checking" and "Regression testing" jobs should all succeed.
The "Diff completeness check" and "Static analysis" jobs should be manually
checked, as they may output warnings which do not count as failure errors.
The "Code coverage report" provides an
[LCOV](https://github.com/linux-test-project/lcov)-generated report which
can be downloaded and checked to see if your new code has full test coverage.
8. Be prepared to get some comments about your code and to modify it. Tip: Use
`git rebase -i origin/master` to modify chains of commits.
## Adding a test
The test suite is a little ad-hoc, so the way tests work is different for each
program being tested.
Feel free to modify how the test scripts work, if the thing you want to test
doesn't fit the existing scheme(s).
### RGBASM
There are two kinds of test.
#### Simple tests
Each `.asm` file corresponds to one test.
RGBASM will be invoked on the `.asm` file with all warnings enabled.
If a `.flags` file exists, its first line contains flags to pass to RGBASM.
(There may be more lines, which will be ignored; they can serve as comments to
explain what the test is about.)
If a `.out` file exists, RGBASM's output (`print`, `println`, etc.) must match
its contents.
If a `.err` file exists, RGBASM's error output (`warn`, errors, etc.) must match
its contents.
If a `.out.bin` file exists, the object file will be linked, and the generated
ROM truncated to the length of the `.out.bin` file.
After that, the ROM must match the `.out.bin` file.
#### CLI tests
Each `.flags` file in `cli/` corresponds to one test.
RGBASM will be invoked, passing it the first line of the `.flags` file.
(There may be more lines, which will be ignored; they can serve as comments to
explain what the test is about.)
If a `.out` file exists, RGBASM's output (`print`, `println`, etc.) must match
its contents.
If a `.err` file exists, RGBASM's error output (`warn`, errors, etc.) must match
its contents.
### RGBLINK
Each `.asm` file corresponds to one test, or one *set* of tests.
All tests begin by assembling the `.asm` file into an object file, which will be
linked in various ways depending on the test.
#### Simple tests
These simply check that RGBLINK's output matches some expected output.
A `.out` file **must** exist, and RGBLINK's total output must match that file's
contents.
Additionally, if a `.out.bin` file exists, the `.gb` file generated by RGBLINK
must match it.
#### Linker script tests
These allow applying various linker scripts to the same object file.
If one or more `.link` files exist, whose names start the same as the `.asm`
file, then each of those files correspond to one test.
Each `.link` linker script **must** be accompanied by a `.out` file, and
RGBLINK's total output must match that file's contents when passed the
corresponding linker script.
#### Variant tests
These allow testing RGBLINK's `-d`, `-t`, and `-w` flags.
If one or more
<code>-<var>&lt;flag&gt;</var>.out</code> or <code>-no-<var>&lt;flag&gt;</var>.out</code>
files exist, then each of them corresponds to one test.
The object file will be linked with and without said flag, respectively; and in
each case, RGBLINK's total output must match the `.out` file's contents.
### RGBFIX
Each `.flags` file corresponds to one test.
Each one is a text file whose first line contains flags to pass to RGBFIX.
(There may be more lines, which will be ignored; they can serve as comments to
explain what the test is about.)
RGBFIX will be invoked on the `.bin` file if it exists, or else on
default-input.bin.
If no `.out` file exist, RGBFIX is not expected to output anything.
If one *does* exist, RGBFIX's output **must** match the `.out` file's contents.
If no `.err` file exists, RGBFIX is simply expected to be able to process the
file normally.
If one *does* exist, RGBFIX's return status is ignored, but its error output
**must** match the `.err` file's contents.
Additionally, if a `.gb` file exists, the output of RGBFIX must match the `.gb`.
### RGBGFX
There are three kinds of test.
#### Simple tests
Each `.png` file corresponds to one test.
RGBGFX will be invoked on the file.
If a `.flags` file exists, it will be used as part of the RGBGFX invocation
(<code>@<var>&lt;file&gt;</var>.flags</code>).
If `.out.1bpp`, `.out.2bpp`, `.out.pal`, `.out.tilemap`, `.out.attrmap`, or
`.out.palmap` files exist, RGBGFX will create the corresponding kind of output,
which must match the file's contents.
Multiple kinds of output may be tested for the same input.
If no `.err` file exists, RGBGFX is simply expected to be able to process the
file normally.
If one *does* exist, RGBGFX's return status is ignored, but its output **must**
match the `.err` file's contents.
#### Reverse tests
Each `.1bpp` or `.2bpp` file corresponds to one test.
RGBGFX will be invoked on the file with `-r 1` for reverse mode, then invoked on
the output without `-r 1`.
The round-trip output must match the input file's contents.
If a `.flags` file exists, it will be used as part of the RGBGFX invocation
(<code>@<var>&lt;file&gt;</var>.flags</code>).
#### Random seed tests
Each `seed*.bin` file corresponds to one test.
Each one is a binary RNG file which is passed to the `rgbgfx_test` program.
### Downstream projects
1. Make sure the downstream project supports
<code>make <var>&lt;target&gt;</var> RGBDS=<var>&lt;path/to/RGBDS/&gt;</var></code>.
While the test suite supports any Make target name, only
[Make](//gnu.org/software/make) is currently supported, and the Makefile must
support a `RGBDS` variable to use a non-system RGBDS directory.
Also, only projects hosted on GitHub are currently supported.
2. Add the project to `test/fetch-test-deps.sh`: add a new `action` line at the
bottom, following the existing pattern:
```sh
action <owner> <repo> <date of last commit> <hash of last commit>
```
(The date is used to avoid fetching too much history when cloning the
repositories.)
3. Add the project to `test/run-tests.sh`: add a new `test_downstream` line at
the bottom, following the existing pattern:
```sh
test_downstream <owner> <repo> <makefile target> <build file> <sha1 hash of build file>
```
## Container images
The CI will
[take care](https://github.com/gbdev/rgbds/blob/master/.github/workflows/build-container.yml)
of updating the
[rgbds container](https://github.com/gbdev/rgbds/pkgs/container/rgbds) image
tagged `master`.
When a git tag is pushed, the image is also tagged with that tag.
The image can be built locally and pushed to the GitHub container registry by
manually running:
```bash
# e.g. to build and tag as 'master'
docker build . --tag ghcr.io/gbdev/rgbds:master
docker push ghcr.io/gbdev/rgbds:master
```

95
CONTRIBUTING.rst Normal file
View File

@@ -0,0 +1,95 @@
Contributing
============
RGBDS was created in the late '90s and has received contributions from several
developers since then. It wouldn't have been possible to get to this point
without their work, and it is always open to the contributions of other people.
Reporting Bugs
--------------
Bug reports are essential to improve RGBDS and they are always welcome. If you
want to report a bug:
1. Make sure that there isn't a similar issue already reported
`here <https://github.com/rednex/rgbds/issues>`__.
2. Figure out a way of reproducing it reliably.
3. If there is a piece of code that triggers the bug, try to reduce it to the
smallest file you can.
4. Create a new `issue <https://github.com/rednex/rgbds/issues>`__.
Of course, it may not always be possible to give an accurate bug report, but it
always helps to fix it.
Requesting new features
-----------------------
If you come up with a good idea that could be implemented, you can propose it to
be done.
1. Create a new `issue <https://github.com/rednex/rgbds/issues>`__.
2. Try to be as accurate as possible. Describe what you need and why you need
it, maybe with examples.
Please understand that the contributors are doing it in their free time, so
simple requests are more likely to catch the interest of a contributor than
complicated ones. If you really need something to be done, and you think you can
implement it yourself, you can always contribute to RGBDS with your own code.
Contributing code
-----------------
If you want to contribute with your own code, whether it is to fix a current
issue or to add something that nobody had requested, you should first consider
if your change is going to be small (and likely to be accepted as-is) or big
(and will have to go through some rework).
Big changes will most likely require some discussion, so open an
`issue <https://github.com/rednex/rgbds/issues>`__ and explain what you want to
do and how you intend to do it. If you already have a prototype, it's always a
good idea to show it. Tests help, too.
If you are going to work on a specific issue that involves a lot of work, it is
always a good idea to leave a message, just in case someone else is interested
but doesn't know that there's someone working on it.
Note that you must contribute all your changes under the MIT License. If you are
just modifying a file, you don't need to do anything (maybe update the copyright
years). If you are adding new files, you need to use the correct header with the
copyright and the reference to the MIT License.
1. Fork this repository.
2. Checkout the ``master`` branch.
3. Create a new branch to work on. You could still work on ``master``, but it's
easier that way.
4. Compile your changes with ``make develop`` instead of just ``make``. This
target checks for additional warnings. Your patches shouldn't introduce any
new warning (but it may be possible to remove some warning checks if it makes
the code much easier).
5. Follow the Linux kernel coding style, which can be found in the file
``Documentation/process/coding-style.rst`` in the Linux kernel repository.
Note that the coding style isn't written in stone, if there is a good reason
to deviate from it, it should be fine.
6. Download the files ``checkpatch.pl``, ``const_structs.checkpatch`` and
``spelling.txt`` from the folder ``scripts`` in the Linux kernel repository.
7. To use ``checkpatch.pl`` you can use ``make checkpatch``, which will check
the coding style of all patches between the current one and the upstream
code. By default, the Makefile expects the script (and associate files) to be
located in ``../linux/scripts/``, but you can place them anywhere you like as
long as you specify it when executing the command:
``make checkpatch CHECKPATCH=../path/to/folder``.
8. Create a pull request against the branch ``master``.
9. Be prepared to get some comments about your code and to modify it. Tip: Use
``git rebase -i origin/master`` to modify chains of commits.

View File

@@ -1,48 +0,0 @@
# Contributors to RGBDS
## Original author
- Carsten Elton Sørensen &lt;csoren@gmail.com&gt;
## Main contributors
- Justin Lloyd &lt;jlloyd@imf.la&gt;
- Vegard Nossum &lt;vegard.nossum@gmail.com&gt;
- Anthony J. Bentley &lt;anthony@anjbe.name&gt;
- stag019 &lt;stag019@gmail.com&gt;
- Antonio Niño Díaz &lt;antonio_nd@outlook.com&gt;
- Eldred "ISSOtm" Habert &lt;me@eldred.fr&gt;
- Sylvie "Rangi" Oukaour &lt;https://github.com/Rangi42&gt;
## Other contributors
- Ben Hetherington &lt;dev@ben-h.uk&gt;
- Björn Höhrmann &lt;bjoern@hoehrmann.de&gt;
- Christophe Staïesse &lt;chastai@skynet.be&gt;
- David Brotz &lt;dbrotz007@gmail.com&gt;
- Evie &lt;https://evie.gbdev.io&gt;
- James "JL2210" Larrowe &lt;https://github.com/JL2210&gt;
- Maja Kądziołka &lt;github@compilercrim.es&gt;
- The Musl C library &lt;https://musl.libc.org/&gt;
- obskyr &lt;powpowd@gmail.com&gt;
- The OpenBSD Project &lt;http://www.openbsd.org&gt;
- Quint Guvernator &lt;quint@guvernator.net&gt;
- Sanqui &lt;gsanky@gmail.com&gt;
- YamaArashi &lt;shadow962@live.com&gt;
- yenatch &lt;yenatch@gmail.com&gt;
- phs &lt;phil@philhsmith.com&gt;
- jidoc01 &lt;jidoc01@naver.com&gt;
[<img src="https://contrib.rocks/image?repo=gbdev/rgbds">](https://github.com/gbdev/rgbds/graphs/contributors)
Contributor image made with [contrib.rocks](https://contrib.rocks).
## Acknowledgements
RGBGFX generates palettes using algorithms found in the paper
["Algorithms for the Pagination Problem, a Bin Packing with Overlapping Items"](https://arxiv.org/abs/1605.00558)
([GitHub](https://github.com/pagination-problem/pagination), MIT license),
by Aristide Grange, Imed Kacem, and Sébastien Martin.
RGBGFX's color palette was taken from [SameBoy](https://sameboy.github.io), with
permission and help by [LIJI](https://github.com/LIJI32).

57
CONTRIBUTORS.rst Normal file
View File

@@ -0,0 +1,57 @@
Contributors to RGBDS
=====================
Original author
---------------
- Carsten Elton Sørensen <csoren@gmail.com>
Main contributors
-----------------
- Justin Lloyd <jlloyd@imf.la>
- Vegard Nossum <vegard.nossum@gmail.com>
- Anthony J. Bentley <anthony@anjbe.name>
- stag019 <stag019@gmail.com>
- Antonio Niño Díaz <antonio_nd@outlook.com>
- Eldred "ISSOtm" Habert <eldredhabert0@gmail.com>
- Rangi <http://github.com/Rangi42>
Other contributors
------------------
- Ben Hetherington <dev@ben-h.uk>
- Björn Höhrmann <bjoern@hoehrmann.de>
- Christophe Staïesse <chastai@skynet.be>
- David Brotz <dbrotz007@gmail.com>
- Jakub Kądziołka <kuba@kadziolka.net>
- James "JL2210" Larrowe <https://github.com/JL2210>
- The Musl C library <http://www.musl-libc.org>
- obskyr <powpowd@gmail.com>
- The OpenBSD Project <http://www.openbsd.org>
- Quint Guvernator <quint@guvernator.net>
- Sanqui <gsanky@gmail.com>
- YamaArashi <shadow962@live.com>
- yenatch <yenatch@gmail.com>
- phs <phil@philhsmith.com>
- jidoc01 <jidoc01@naver.com>

View File

@@ -1,21 +1,24 @@
FROM debian:12-slim # This file is part of RGBDS.
LABEL org.opencontainers.image.source=https://github.com/gbdev/rgbds #
ARG version=1.0.0 # Copyright (c) 2018-2019, Phil Smith and RGBDS contributors.
#
# SPDX-License-Identifier: MIT
# docker build -t rgbds:vX.X.X-alpine
FROM alpine:latest
RUN apk add --update \
build-base \
bison \
libpng-dev
COPY . /rgbds
WORKDIR /rgbds WORKDIR /rgbds
RUN make Q='' all
COPY . . FROM alpine:latest
RUN apk add --update \
RUN apt-get update && \ libpng
apt-get install sudo make cmake gcc build-essential -y COPY --from=0 \
/rgbds/rgbasm \
# Install dependencies and compile RGBDS /rgbds/rgbfix \
RUN ./.github/scripts/install_deps.sh ubuntu-22.04 /rgbds/rgblink \
RUN make -j CXXFLAGS="-O3 -flto -DNDEBUG -static" PKG_CONFIG="pkg-config --static" Q= /rgbds/rgbgfx \
/bin/
# Create an archive with the compiled executables and all the necessary to install it,
# so it can be copied outside of the container and installed/used in another system
RUN tar caf rgbds-linux-x86_64.tar.xz --transform='s#.*/##' rgbasm rgblink rgbfix rgbgfx man/* .github/scripts/install.sh
# Install RGBDS on the container so all the executables will be available in the PATH
RUN cp man/* .
RUN ./.github/scripts/install.sh

View File

@@ -1,6 +1,6 @@
The MIT License The MIT License
Copyright (c) 1996-2025, Carsten Sørensen and RGBDS contributors. Copyright (c) 1997-2020, Carsten Sorensen and RGBDS contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to of this software and associated documentation files (the "Software"), to

314
Makefile
View File

@@ -1,65 +1,62 @@
#
# This file is part of RGBDS.
#
# Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
#
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
#
.SUFFIXES: .SUFFIXES:
.SUFFIXES: .cpp .y .o .SUFFIXES: .h .y .c .o
.PHONY: all clean install checkdiff develop debug profile coverage format tidy iwyu mingw32 mingw64 wine-shim dist
# User-defined variables # User-defined variables
Q := @ Q := @
PREFIX := /usr/local PREFIX := /usr/local
bindir := ${PREFIX}/bin bindir := ${PREFIX}/bin
mandir := ${PREFIX}/share/man mandir := ${PREFIX}/share/man
SUFFIX := STRIP := -s
STRIP := -s BINMODE := 755
BINMODE := 755 MANMODE := 644
MANMODE := 644 CHECKPATCH := ../linux/scripts/checkpatch.pl
# Other variables # Other variables
PKG_CONFIG := pkg-config PKG_CONFIG := pkg-config
PNGCFLAGS := `${PKG_CONFIG} --cflags libpng` PNGCFLAGS := `${PKG_CONFIG} --cflags libpng`
PNGLDFLAGS := `${PKG_CONFIG} --libs-only-L libpng` PNGLDFLAGS := `${PKG_CONFIG} --libs-only-L libpng`
PNGLDLIBS := `${PKG_CONFIG} --libs-only-l libpng` PNGLDLIBS := `${PKG_CONFIG} --libs-only-l libpng`
# Note: if this comes up empty, `version.cpp` will automatically fall back to last release number # Note: if this comes up empty, `version.c` will automatically fall back to last release number
VERSION_STRING := `git --git-dir=.git -c safe.directory='*' describe --tags --dirty --always 2>/dev/null` VERSION_STRING := `git describe --tags --dirty --always 2>/dev/null`
WARNFLAGS := -Wall -pedantic -Wno-unknown-warning-option -Wno-gnu-zero-variadic-macro-arguments WARNFLAGS := -Wall -pedantic
# Overridable CXXFLAGS # Overridable CFLAGS
CXXFLAGS ?= -O3 -flto -DNDEBUG CFLAGS ?= -O3 -flto -DNDEBUG
# Non-overridable CXXFLAGS # Non-overridable CFLAGS
REALCXXFLAGS := ${CXXFLAGS} ${WARNFLAGS} -std=c++2a -I include -fno-exceptions -fno-rtti # _ISOC11_SOURCE is required on certain platforms to get C11 on top of the C99-based POSIX 2008
REALCFLAGS := ${CFLAGS} ${WARNFLAGS} -std=gnu11 -I include \
-D_POSIX_C_SOURCE=200809L -D_ISOC11_SOURCE
# Overridable LDFLAGS # Overridable LDFLAGS
LDFLAGS ?= LDFLAGS ?=
# Non-overridable LDFLAGS # Non-overridable LDFLAGS
REALLDFLAGS := ${LDFLAGS} ${WARNFLAGS} -DBUILD_VERSION_STRING=\"${VERSION_STRING}\" REALLDFLAGS := ${LDFLAGS} ${WARNFLAGS} \
-DBUILD_VERSION_STRING=\"${VERSION_STRING}\"
# Wrapper around bison that passes flags depending on what the version supports YFLAGS ?= -Wall
BISON := src/bison.sh
RM := rm -rf BISON := bison
RM := rm -rf
# Used for checking pull requests # Used for checking pull requests
BASE_REF := origin/master BASE_REF := origin/master
# Rules to build the RGBDS binaries # Rules to build the RGBDS binaries
all: rgbasm rgblink rgbfix rgbgfx all: rgbasm rgblink rgbfix rgbgfx
common_obj := \
src/extern/getopt.o \
src/cli.o \
src/diagnostics.o \
src/style.o \
src/usage.o \
src/util.o
rgbasm_obj := \ rgbasm_obj := \
${common_obj} \
src/asm/actions.o \
src/asm/charmap.o \ src/asm/charmap.o \
src/asm/fixpoint.o \ src/asm/fixpoint.o \
src/asm/format.o \ src/asm/format.o \
@@ -73,207 +70,182 @@ rgbasm_obj := \
src/asm/rpn.o \ src/asm/rpn.o \
src/asm/section.o \ src/asm/section.o \
src/asm/symbol.o \ src/asm/symbol.o \
src/asm/util.o \
src/asm/warning.o \ src/asm/warning.o \
src/extern/getopt.o \
src/extern/utf8decoder.o \ src/extern/utf8decoder.o \
src/backtrace.o \ src/error.o \
src/hashmap.o \
src/linkdefs.o \ src/linkdefs.o \
src/opmath.o \ src/opmath.o
src/verbosity.o
src/asm/lexer.o src/asm/main.o: src/asm/parser.hpp src/asm/lexer.o src/asm/main.o: src/asm/parser.h
rgblink_obj := \ rgblink_obj := \
${common_obj} \
src/link/assign.o \ src/link/assign.o \
src/link/fstack.o \
src/link/lexer.o \
src/link/layout.o \
src/link/main.o \ src/link/main.o \
src/link/object.o \ src/link/object.o \
src/link/output.o \ src/link/output.o \
src/link/patch.o \ src/link/patch.o \
src/link/script.o \ src/link/script.o \
src/link/sdas_obj.o \
src/link/section.o \ src/link/section.o \
src/link/symbol.o \ src/link/symbol.o \
src/link/warning.o \ src/extern/getopt.o \
src/extern/utf8decoder.o \ src/error.o \
src/backtrace.o \ src/hashmap.o \
src/linkdefs.o \ src/linkdefs.o \
src/opmath.o \ src/opmath.o
src/verbosity.o
src/link/lexer.o src/link/main.o: src/link/script.hpp
rgbfix_obj := \ rgbfix_obj := \
${common_obj} \
src/fix/fix.o \
src/fix/main.o \ src/fix/main.o \
src/fix/mbc.o \ src/extern/getopt.o \
src/fix/warning.o src/error.o
rgbgfx_obj := \ rgbgfx_obj := \
${common_obj} \ src/gfx/gb.o \
src/gfx/color_set.o \
src/gfx/main.o \ src/gfx/main.o \
src/gfx/pal_packing.o \ src/gfx/makepng.o \
src/gfx/pal_sorting.o \ src/extern/getopt.o \
src/gfx/pal_spec.o \ src/error.o
src/gfx/palette.o \
src/gfx/png.o \
src/gfx/process.o \
src/gfx/reverse.o \
src/gfx/rgba.o \
src/gfx/warning.o \
src/verbosity.o
rgbasm: ${rgbasm_obj} rgbasm: ${rgbasm_obj}
$Q${CXX} ${REALLDFLAGS} -o $@ ${rgbasm_obj} ${REALCXXFLAGS} src/version.cpp $Q${CC} ${REALLDFLAGS} -o $@ ${rgbasm_obj} ${REALCFLAGS} src/version.c -lm
rgblink: ${rgblink_obj} rgblink: ${rgblink_obj}
$Q${CXX} ${REALLDFLAGS} -o $@ ${rgblink_obj} ${REALCXXFLAGS} src/version.cpp $Q${CC} ${REALLDFLAGS} -o $@ ${rgblink_obj} ${REALCFLAGS} src/version.c
rgbfix: ${rgbfix_obj} rgbfix: ${rgbfix_obj}
$Q${CXX} ${REALLDFLAGS} -o $@ ${rgbfix_obj} ${REALCXXFLAGS} src/version.cpp $Q${CC} ${REALLDFLAGS} -o $@ ${rgbfix_obj} ${REALCFLAGS} src/version.c
rgbgfx: ${rgbgfx_obj} rgbgfx: ${rgbgfx_obj}
$Q${CXX} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ ${rgbgfx_obj} ${REALCXXFLAGS} ${PNGLDLIBS} src/version.cpp $Q${CC} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ ${rgbgfx_obj} ${REALCFLAGS} src/version.c ${PNGLDLIBS}
test/gfx/randtilegen: test/gfx/randtilegen.cpp
$Q${CXX} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ $^ ${REALCXXFLAGS} ${PNGCFLAGS} ${PNGLDLIBS}
test/gfx/rgbgfx_test: test/gfx/rgbgfx_test.cpp
$Q${CXX} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ $^ ${REALCXXFLAGS} ${PNGCFLAGS} ${PNGLDLIBS}
# Rules to process files # Rules to process files
# We want the Bison invocation to pass through our rules, not default ones # We want the Bison invocation to pass through our rules, not default ones
.y.o: .y.o:
.y.cpp: # Bison-generated C files have an accompanying header
$Q${BISON} $@ $< src/asm/parser.h: src/asm/parser.c
# Bison-generated C++ files have an accompanying header
src/asm/parser.hpp: src/asm/parser.cpp
$Qtouch $@
src/link/script.hpp: src/link/script.cpp
$Qtouch $@ $Qtouch $@
# Only RGBGFX uses libpng (POSIX make doesn't support pattern rules to cover all these) src/asm/parser.c: src/asm/parser.y
src/gfx/color_set.o: src/gfx/color_set.cpp $QDEFS=; \
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $< add_flag(){ \
src/gfx/main.o: src/gfx/main.cpp if src/check_bison_ver.sh $$1 $$2; then \
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $< DEFS="-D$$3 $$DEFS"; \
src/gfx/pal_packing.o: src/gfx/pal_packing.cpp fi \
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $< }; \
src/gfx/pal_sorting.o: src/gfx/pal_sorting.cpp add_flag 3 5 api.token.raw=true; \
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $< add_flag 3 6 parse.error=detailed; \
src/gfx/pal_spec.o: src/gfx/pal_spec.cpp add_flag 3 0 parse.error=verbose; \
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $< add_flag 3 0 parse.lac=full; \
src/gfx/png.o: src/gfx/png.cpp add_flag 3 0 lr.type=ielr; \
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $< echo "DEFS=$$DEFS"; \
src/gfx/process.o: src/gfx/process.cpp ${BISON} $$DEFS -d ${YFLAGS} -o $@ $<
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $<
src/gfx/reverse.o: src/gfx/reverse.cpp
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $<
src/gfx/rgba.o: src/gfx/rgba.cpp
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $<
.cpp.o: .c.o:
$Q${CXX} ${REALCXXFLAGS} -c -o $@ $< $Q${CC} ${REALCFLAGS} ${PNGCFLAGS} -c -o $@ $<
# Target used to remove all files generated by other Makefile targets # Target used to remove all files generated by other Makefile targets
clean: clean:
$Q${RM} rgbasm rgbasm.exe $Q${RM} rgbasm rgbasm.exe
$Q${RM} rgblink rgblink.exe $Q${RM} rgblink rgblink.exe
$Q${RM} rgbfix rgbfix.exe $Q${RM} rgbfix rgbfix.exe
$Q${RM} rgbgfx rgbgfx.exe $Q${RM} rgbgfx rgbgfx.exe
$Qfind src/ -name "*.o" -exec rm {} \; $Qfind src/ -name "*.o" -exec rm {} \;
$Qfind . -type f \( -name "*.gcno" -o -name "*.gcda" -o -name "*.gcov" \) -exec rm {} \;
$Q${RM} rgbshim.sh $Q${RM} rgbshim.sh
$Q${RM} src/asm/parser.cpp src/asm/parser.hpp src/asm/stack.hh $Q${RM} src/asm/parser.c src/asm/parser.h
$Q${RM} src/link/script.cpp src/link/script.hpp src/link/stack.hh
$Q${RM} test/gfx/randtilegen test/gfx/rgbgfx_test
# Target used to install the binaries and man pages. # Target used to install the binaries and man pages.
install: all install: all
$Qinstall -d ${DESTDIR}${bindir}/ ${DESTDIR}${mandir}/man1/ ${DESTDIR}${mandir}/man5/ ${DESTDIR}${mandir}/man7/ $Qmkdir -p ${DESTDIR}${bindir}
$Qinstall ${STRIP} -m ${BINMODE} rgbasm ${DESTDIR}${bindir}/rgbasm${SUFFIX} $Qinstall ${STRIP} -m ${BINMODE} rgbasm ${DESTDIR}${bindir}/rgbasm
$Qinstall ${STRIP} -m ${BINMODE} rgblink ${DESTDIR}${bindir}/rgblink${SUFFIX} $Qinstall ${STRIP} -m ${BINMODE} rgbfix ${DESTDIR}${bindir}/rgbfix
$Qinstall ${STRIP} -m ${BINMODE} rgbfix ${DESTDIR}${bindir}/rgbfix${SUFFIX} $Qinstall ${STRIP} -m ${BINMODE} rgblink ${DESTDIR}${bindir}/rgblink
$Qinstall ${STRIP} -m ${BINMODE} rgbgfx ${DESTDIR}${bindir}/rgbgfx${SUFFIX} $Qinstall ${STRIP} -m ${BINMODE} rgbgfx ${DESTDIR}${bindir}/rgbgfx
$Qinstall -m ${MANMODE} man/rgbasm.1 man/rgblink.1 man/rgbfix.1 man/rgbgfx.1 ${DESTDIR}${mandir}/man1/ $Qmkdir -p ${DESTDIR}${mandir}/man1 ${DESTDIR}${mandir}/man5 ${DESTDIR}${mandir}/man7
$Qinstall -m ${MANMODE} man/rgbds.5 man/rgbasm.5 man/rgbasm-old.5 man/rgblink.5 ${DESTDIR}${mandir}/man5/ $Qinstall -m ${MANMODE} src/rgbds.7 ${DESTDIR}${mandir}/man7/rgbds.7
$Qinstall -m ${MANMODE} man/rgbds.7 man/gbz80.7 ${DESTDIR}${mandir}/man7/ $Qinstall -m ${MANMODE} src/gbz80.7 ${DESTDIR}${mandir}/man7/gbz80.7
$Qinstall -m ${MANMODE} src/rgbds.5 ${DESTDIR}${mandir}/man5/rgbds.5
$Qinstall -m ${MANMODE} src/asm/rgbasm.1 ${DESTDIR}${mandir}/man1/rgbasm.1
$Qinstall -m ${MANMODE} src/asm/rgbasm.5 ${DESTDIR}${mandir}/man5/rgbasm.5
$Qinstall -m ${MANMODE} src/fix/rgbfix.1 ${DESTDIR}${mandir}/man1/rgbfix.1
$Qinstall -m ${MANMODE} src/link/rgblink.1 ${DESTDIR}${mandir}/man1/rgblink.1
$Qinstall -m ${MANMODE} src/link/rgblink.5 ${DESTDIR}${mandir}/man5/rgblink.5
$Qinstall -m ${MANMODE} src/gfx/rgbgfx.1 ${DESTDIR}${mandir}/man1/rgbgfx.1
# Target used to check the coding style of the whole codebase.
# `extern/` is excluded, as it contains external code that should not be patched
# to meet our coding style, so applying upstream patches is easier.
# `.y` files aren't checked, unfortunately...
checkcodebase:
$Qfor file in `git ls-files | grep -E '(\.c|\.h)$$' | grep -Ev '(src|include)/extern/'`; do \
${CHECKPATCH} -f "$$file"; \
done
# Target used to check the coding style of the patches from the upstream branch
# to the HEAD. Runs checkpatch once for each commit between the current HEAD and
# the first common commit between the HEAD and origin/master.
# `.y` files aren't checked, unfortunately...
checkpatch:
$QCOMMON_COMMIT=`git merge-base HEAD ${BASE_REF}`; \
for commit in `git rev-list $$COMMON_COMMIT..HEAD`; do \
echo "[*] Analyzing commit '$$commit'"; \
git format-patch --stdout "$$commit~..$$commit" \
-- src include '!src/extern' '!include/extern' \
| ${CHECKPATCH} - || true; \
done
# Target used to check for suspiciously missing changed files. # Target used to check for suspiciously missing changed files.
checkdiff: checkdiff:
$Qcontrib/checkdiff.bash `git merge-base HEAD ${BASE_REF}` $Qcontrib/checkdiff.bash `git merge-base HEAD ${BASE_REF}`
# Target used in development to prevent adding new issues to the source code. # This target is used during development in order to prevent adding new issues
# All warnings are treated as errors to block the compilation and make the # to the source code. All warnings are treated as errors in order to block the
# continous integration infrastructure return failure. # compilation and make the continous integration infrastructure return failure.
# The rationale for some of the flags is documented in the CMakeLists. # The rationale for some of the flags is documented in the CMakeLists.
develop: develop:
$Q${MAKE} WARNFLAGS="${WARNFLAGS} -Werror -Wextra \ $Qenv ${MAKE} WARNFLAGS="-Werror -Wextra \
-Walloc-zero -Wcast-align -Wcast-qual -Wduplicated-branches -Wduplicated-cond \ -Walloc-zero -Wcast-align -Wcast-qual -Wduplicated-branches -Wduplicated-cond \
-Wfloat-equal -Wlogical-op -Wnull-dereference -Wold-style-cast -Wshift-overflow=2 \ -Wfloat-equal -Winline -Wlogical-op -Wnested-externs -Wold-style-definition \
-Wstringop-overflow=4 -Wtrampolines -Wundef -Wuninitialized -Wunused -Wshadow \ -Wshift-overflow=2 \
-Wstrict-overflow=5 -Wstrict-prototypes -Wundef -Wuninitialized -Wunused \
-Wshadow \
-Wnull-dereference -Wstringop-overflow=4 \
-Wformat=2 -Wformat-overflow=2 -Wformat-truncation=1 \ -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=1 \
-Wno-format-nonliteral -Wno-strict-overflow -Wno-unused-but-set-variable \ -Wno-format-nonliteral \
-Wno-type-limits -Wno-tautological-constant-out-of-range-compare -Wvla \ -Wno-type-limits -Wno-tautological-constant-out-of-range-compare \
-D_GLIBCXX_ASSERTIONS -fsanitize=address -fsanitize=undefined \ -Wvla \
-fsanitize=float-divide-by-zero" \ -Wno-unknown-warning-option \
CXXFLAGS="-ggdb3 -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls" -fsanitize=shift -fsanitize=integer-divide-by-zero \
-fsanitize=unreachable -fsanitize=vla-bound \
# Target used in development to debug with gdb. -fsanitize=signed-integer-overflow -fsanitize=bounds \
debug: -fsanitize=object-size -fsanitize=bool -fsanitize=enum \
$Qenv ${MAKE} \ -fsanitize=alignment -fsanitize=null -fsanitize=address" \
CXXFLAGS="-ggdb3 -O0 -fno-omit-frame-pointer -fno-optimize-sibling-calls" CFLAGS="-ggdb3 -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls"
# Target used in development to profile with callgrind.
profile:
$Qenv ${MAKE} \
CXXFLAGS="-ggdb3 -O3 -fno-omit-frame-pointer -fno-optimize-sibling-calls"
# Target used in development to inspect code coverage with gcov.
coverage:
$Qenv ${MAKE} \
CXXFLAGS="-ggdb3 -Og --coverage -fno-omit-frame-pointer -fno-optimize-sibling-calls"
# Target used in development to format source code with clang-format.
format:
$Qclang-format -i $$(git ls-files '*.hpp' '*.cpp')
# Target used in development to check code with clang-tidy.
# Requires Bison-generated header files to exist.
tidy: src/asm/parser.hpp src/link/script.hpp
$Qclang-tidy -p . $$(git ls-files '*.hpp' '*.cpp')
# Target used in development to remove unused `#include` headers.
iwyu:
$Qenv ${MAKE} \
CXX="include-what-you-use" \
REALCXXFLAGS="-std=c++2a -I include"
# Targets for the project maintainer to easily create Windows exes. # Targets for the project maintainer to easily create Windows exes.
# This is not for Windows users! # This is not for Windows users!
# If you're building on Windows with Cygwin or MinGW, just follow the Unix # If you're building on Windows with Cygwin or Mingw, just follow the Unix
# install instructions instead. # install instructions instead.
mingw32: mingw32:
$Q${MAKE} all test/gfx/randtilegen test/gfx/rgbgfx_test \ $Q${MAKE} CC=i686-w64-mingw32-gcc BISON=bison \
CXX=i686-w64-mingw32-g++ \ PKG_CONFIG=i686-w64-mingw32-pkg-config -j
CXXFLAGS="-O3 -flto -DNDEBUG -static-libgcc -static-libstdc++" \
PKG_CONFIG="PKG_CONFIG_SYSROOT_DIR=/usr/i686-w64-mingw32 pkg-config"
mingw64: mingw64:
$Q${MAKE} all test/gfx/randtilegen test/gfx/rgbgfx_test \ $Q${MAKE} CC=x86_64-w64-mingw32-gcc BISON=bison \
CXX=x86_64-w64-mingw32-g++ \ PKG_CONFIG=x86_64-w64-mingw32-pkg-config -j
PKG_CONFIG="PKG_CONFIG_SYSROOT_DIR=/usr/x86_64-w64-mingw32 pkg-config"
wine-shim: wine-shim:
$Qecho '#!/usr/bin/env bash' > rgbshim.sh $Qecho '#!/bin/bash' > rgbshim.sh
$Qecho 'WINEDEBUG=-all wine $$0.exe "$${@:1}"' >> rgbshim.sh $Qecho 'WINEDEBUG=-all wine $$0.exe "$${@:1}"' >> rgbshim.sh
$Qchmod +x rgbshim.sh $Qchmod +x rgbshim.sh
$Qln -s rgbshim.sh rgbasm $Qln -s rgbshim.sh rgbasm
@@ -286,4 +258,4 @@ wine-shim:
dist: dist:
$Qgit ls-files | sed s~^~$${PWD##*/}/~ \ $Qgit ls-files | sed s~^~$${PWD##*/}/~ \
| tar -czf rgbds-source.tar.gz -C .. -T - | tar -czf rgbds-`git describe --tags | cut -c 2-`.tar.gz -C .. -T -

View File

@@ -1,57 +0,0 @@
# RGBDS
RGBDS (Rednex Game Boy Development System) is a free assembler/linker package
for the Game Boy and Game Boy Color. It consists of:
- RGBASM (assembler)
- RGBLINK (linker)
- RGBFIX (checksum/header fixer)
- RGBGFX (PNG-to-Game Boy graphics converter)
This is a fork of the original RGBDS which aims to make the programs more like
other UNIX tools.
This toolchain is maintained [on GitHub](https://github.com/gbdev/rgbds).
The documentation of this toolchain can be [viewed online](https://rgbds.gbdev.io/docs/),
including its [basic usage and development history](https://rgbds.gbdev.io/docs/rgbds.7).
It is generated from the man pages found in this repository.
The source code of the website itself is on GitHub as well under the repository
[rgbds-www](https://github.com/gbdev/rgbds-www).
If you want to contribute or maintain RGBDS, read [CONTRIBUTING.md](CONTRIBUTING.md).
If you have questions regarding the code, its organization, etc. you can find the maintainers
[on the GBDev community channels](https://gbdev.io/chat) or via mail at `rgbds at gbdev dot io`.
## Installing RGBDS
The [installation procedure](https://rgbds.gbdev.io/install) is available
online for various platforms. [Building from source](https://rgbds.gbdev.io/install/source)
is possible using `make` or `cmake`; follow the link for more detailed instructions.
```sh
make
sudo make install
```
```sh
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
cmake --install build
```
Two parameters available when building are a prefix (e.g. to put the executables in a directory)
and a suffix (e.g. to append the version number or commit ID).
```sh
make
sudo make install PREFIX=install_dir/ SUFFIX=-$(git rev-parse --short HEAD)
```
```sh
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DSUFFIX=-$(git rev-parse --short HEAD)
cmake --build build
cmake --install build --prefix install_dir
```
(If you set a `SUFFIX`, it should include the `.exe` extension on Windows.)

128
README.rst Normal file
View File

@@ -0,0 +1,128 @@
RGBDS
=====
RGBDS (Rednex Game Boy Development System) is a free assembler/linker package
for the Game Boy and Game Boy Color. It consists of:
- rgbasm (assembler)
- rgblink (linker)
- rgbfix (checksum/header fixer)
- rgbgfx (PNGtoGame Boy graphics converter)
This is a fork of the original RGBDS which aims to make the programs more like
other UNIX tools.
This toolchain is maintained on `GitHub <https://github.com/rednex/rgbds>`__.
The documentation of this toolchain can be viewed online
`here <https://rgbds.gbdev.io/docs/>`__, it is generated from the man pages
found in this repository.
If you want to contribute or maintain RGBDS, and have questions regarding the code, its organisation, etc. you can find me `on GBDev <https://gbdev.io/chat>`__ or via mail at ``rgbds at eldred dot fr``.
1. Installing RGBDS
-------------------
The `installation procedure <https://rgbds.gbdev.io/install>`__ is available
online for various platforms. `Building from source <https://rgbds.gbdev.io/install/source>`__
is possible using ``make`` or ``cmake``; follow the link for more detailed instructions.
.. code:: sh
make
sudo make install
.. code:: sh
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
cmake --install build
2. RGBDS Folder Organization
----------------------------
The RGBDS source code file structure somewhat resembles the following:
::
.
├── .github/
│ ├── actions/
│ │ └── ...
│ └── workflows/
│ └── ...
├── contrib/
│ ├── zsh_compl/
│ │ └── ...
│ └── ...
├── include/
│ └── ...
├── src/
│ ├── asm/
│ │ └── ...
│ ├── extern/
│ │ └── ...
│ ├── fix/
│ │ └── ...
│ ├── gfx/
│ │ └── ...
│ ├── link/
│ │ └── ...
│ ├── CMakeLists.txt
│ └── ...
├── test/
│ ├── ...
│ └── run-tests.sh
├── .clang-format
├── CMakeLists.txt
├── Makefile
└── README.rst
.. |clang-format| replace:: ``clang-format``
.. _clang-format: https://clang.llvm.org/docs/ClangFormat.html
- ``.github/`` - files and scripts related to the integration of the RGBDS codebase with
GitHub.
* ``actions/`` - scripts used by workflow files.
* ``workflows/`` - CI workflow description files.
- ``contrib/`` - scripts and other resources which may be useful to users and developers of
RGBDS.
* ``zsh_compl`` contains tab completion scripts for use with zsh. Put them somewhere in your ``fpath``, and they should auto-load.
* ``bash_compl`` contains tab completion scripts for use with bash. Run them with ``source`` somewhere in your ``.bashrc``, and they should load every time you open a shell.
- ``include/`` - header files for each respective C files in `src`.
- ``src/`` - source code and manual pages for RGBDS.
* Note that the code unique to each RGBDS tool is stored in its respective subdirectory
(rgbasm -> ``src/asm/``, for example). ``src/extern/`` contains code imported from external sources.
- ``test/`` - testing framework used to verify that changes to the code don't break or modify the behavior of RGBDS.
- ``.clang-format`` - code style for automated formatting with |clang-format|_. The C code does not currently follow this style, but all C++ code should.
3. History
----------
- Around 1997, Carsten Sørensen (AKA SurfSmurf) writes ASMotor as a
general-purpose assembler/linker system for DOS/Win32
- Around 1999, Justin Lloyd (AKA Otaku no Zoku) adapts ASMotor to read and
produce GBZ80 assembly/machine code, and releases this version as RGBDS.
- 2009, Vegard Nossum adapts the code to be more UNIX-like and releases
this version as rgbds-linux on
`GitHub <https://github.com/vegard/rgbds-linux>`__.
- 2010, Anthony J. Bentley forks that repository. The fork becomes the reference
implementation of rgbds.
- 2017, Bentley's repository is moved to a neutral name.
- 2018, codebase relicensed under the MIT license.
- 2020, repository is moved to the `gbdev <https://github.com/gbdev>`__ organisation. The `rgbds.gbdev.io <https://rgbds.gbdev.io>`__ website serving documentation and downloads is created.

View File

@@ -1,83 +0,0 @@
# Releasing
This describes for the maintainers of RGBDS how to publish a new release on
GitHub.
1. Update the following files, then commit and push.
You can use <code>git commit -m "Release <i>&lt;version&gt;</i>"</code> and `git push origin master`.
- [include/version.hpp](include/version.hpp): set appropriate values for `PACKAGE_VERSION_MAJOR`,
`PACKAGE_VERSION_MINOR`, `PACKAGE_VERSION_PATCH`, and `PACKAGE_VERSION_RC`.
**Only** define `PACKAGE_VERSION_RC` if you are publishing a release candidate!
- [Dockerfile](Dockerfile): update `ARG version`.
- [test/fetch-test-deps.sh](test/fetch-test-deps.sh): update test dependency commits
(preferably, use the latest available).
- [man/\*](man/): update dates and authors.
2. Create a Git tag formatted as <code>v<i>&lt;MAJOR&gt;</i>.<i>&lt;MINOR&gt;</i>.<i>&lt;PATCH&gt;</i></code>,
or <code>v<i>&lt;MAJOR&gt;</i>.<i>&lt;MINOR&gt;</i>.<i>&lt;PATCH&gt;</i>-rc<i>&lt;RC&gt;</i></code>
for a release candidate. <code><i>MAJOR</i></code>, <code><i>MINOR</i></code>,
<code><i>PATCH</i></code>, and <code><i>RC</i></code> should match their values from
[include/version.hpp](include/version.hpp). You can use <code>git tag <i>&lt;tag&gt;</i></code>.
3. Push the tag to GitHub. You can use <code>git push origin <i>&lt;tag&gt;</i></code>.
GitHub Actions will run the [create-release-artifacts.yaml](.github/workflows/create-release-artifacts.yaml)
workflow to detect the tag starting with "`v[0-9]`" and automatically do the following:
1. Build 32-bit and 64-bit RGBDS binaries for Windows with `cmake`.
2. Package the binaries into zip files.
3. Package the source code into a tar.gz file with `make dist`.
4. Create a draft GitHub release for the tag, attaching the three
packaged files. It will be a prerelease if the tag contains "`-rc`".
If an error occurred in the above steps, delete the tag and restart the
procedure. You can use <code>git push --delete origin <i>&lt;tag&gt;</i></code> and
<code>git tag --delete <i>&lt;tag&gt;</i></code>.
4. GitHub Actions will run the [create-release-docs.yml](.github/workflows/create-release-docs.yml)
workflow to add the release documentation to [rgbds-www](https://github.com/gbdev/rgbds-www).
This is not done automatically for prereleases, since we do not normally publish documentation
for them. If you want to manually publish prerelease documentation, such as for an April Fools
joke prerelease,
1. Clone [rgbds-www](https://github.com/gbdev/rgbds-www). You can use
`git clone https://github.com/gbdev/rgbds-www.git`.
2. Make sure that you have installed `groff` and `mandoc`. You will
need `mandoc` 1.14.5 or later to support `-O toc`.
3. Inside of the `man` directory, run <code><i>&lt;path/to/rgbds-www&gt;</i>/maintainer/man_to_html.sh <i>&lt;tag&gt;</i> *</code> then <code><i>&lt;path/to/rgbds-www&gt;</i>/maintainer/new_release.sh <i>&lt;tag&gt;</i></code>.
This will render the RGBDS documentation as HTML and PDF and copy it to
`rgbds-www`.
If you do not have `groff` installed, you can change
`groff -Tpdf -mdoc -wall` to `mandoc -Tpdf -I os=Linux` in
[maintainer/man_to_html.sh](https://github.com/gbdev/rgbds-www/blob/master/maintainer/man_to_html.sh)
and it will suffice.
4. Commit and push the documentation. You can use <code>git commit -m
"Create RGBDS <i>&lt;tag&gt;</i> documentation"</code> and `git push origin master`
(within the `rgbds-www` directory, not RGBDS).
5. Write a changelog in the GitHub draft release.
6. Click the "Publish release" button to publish it!
7. Update the `release` branch. You can use `git push origin master:release`.
8. Update the following related projects.
1. [rgbds-www](https://github.com/gbdev/rgbds-www): update
[src/pages/versions.mdx](https://github.com/gbdev/rgbds-www/blob/master/src/pages/versions.mdx)
to list the new release.
2. [rgbds-live](https://github.com/gbdev/rgbds-live): update the `rgbds` submodule (and
[patches/rgbds.patch](https://github.com/gbdev/rgbds-live/blob/master/patches/rgbds.patch)
if necessary) to use the new release.
3. [rgbobj](https://github.com/gbdev/rgbobj) and [rgbds-obj](https://github.com/gbdev/rgbds-obj):
make sure that object files created by the latest RGBASM can be parsed and displayed.
If the object file revision has been updated, `rgbobj` will need a corresponding release.

67
RELEASE.rst Normal file
View File

@@ -0,0 +1,67 @@
Releasing
=========
This describes for the maintainers of RGBDS how to publish a new release on
GitHub.
1. Update, commit, and push `include/version.h <include/version.h>`__ with
values for ``PACKAGE_VERSION_MAJOR``, ``PACKAGE_VERSION_MINOR``,
``PACKAGE_VERSION_PATCH``, and ``PACKAGE_VERSION_RC``. Only define
``PACKAGE_VERSION_RC`` if you are publishing a release candidate! You can
use ``git commit -m "Release <version>"`` and ``git push origin master``.
2. Create a Git tag formatted as ``v<MAJOR>.<MINOR>.<PATCH>``, or
``v<MAJOR>.<MINOR>.<PATCH>-rc<RC>`` for a release candidate. ``MAJOR``,
``MINOR``, ``PATCH``, and ``RC`` should match their values from
`include/version.h <include/version.h>`__. You can use ``git tag <tag>``.
3. Push the tag to GitHub. You can use ``git push origin <tag>``.
GitHub Actions will run the `create-release-artifacts.yaml
<.github/workflows/create-release-artifacts.yaml>`__ workflow to detect the
tag starting with "``v[0-9]``" and automatically do the following:
1. Build 32-bit and 64-bit RGBDS binaries for Windows with ``cmake``.
2. Package the binaries into zip files.
3. Package the source code into a tar.gz file with ``make dist``.
4. Create a draft GitHub release for the tag, attaching the three
packaged files. It will be a prerelease if the tag contains "``-rc``".
If an error occurred in the above steps, delete the tag and restart the
procedure. You can use ``git push --delete origin <tag>`` and
``git tag --delete <tag>``.
4. GitHub Actions will run the `create-release-docs.yml
<.github/workflows/create-release-docs.yml>`__ workflow to add the release
documentation to `rgbds-www <https://github.com/gbdev/rgbds-www>`__.
For a release candidate, which creates a prerelease, you will have to
take these steps yourself.
1. Clone `rgbds-www <https://github.com/gbdev/rgbds-www>`__. You can use
``git clone https://github.com/gbdev/rgbds-www.git``.
2. Make sure that you have installed ``groff`` and ``mandoc``. You will
need ``mandoc`` 1.14.5 or later to support ``-O toc``.
3. Run ``.github/actions/get-pages.sh -r <path/to/rgbds-www> <tag>``. This
will render the RGBDS documentation as HTML and PDF and copy it to
``rgbds-www``.
If you do not have ``groff`` installed, you can change
``groff -Tpdf -mdoc -wall`` to ``mandoc -Tpdf -I os=Linux`` in
`.github/actions/get-pages.sh <.github/actions/get-pages.sh>`__ and it
will suffice.
4. Commit and push the documentation. You can use ``git commit -m
"Create RGBDS <tag> documentation"`` and ``git push origin master``
(within the ``rgbds-www`` directory, not RGBDS).
5. Write a changelog in the GitHub draft release.
6. Click the "Publish release" button to publish it!
7. Update the `release` branch. You can use ``git push origin release``.

View File

@@ -1,6 +0,0 @@
-std=c++2a
-I
include
-fno-exceptions
-fno-rtti
-fno-caret-diagnostics

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash #/usr/bin/env bash
# Known bugs: # Known bugs:
# - Newlines in file/directory names break this script # - Newlines in file/directory names break this script
@@ -11,7 +11,7 @@
# - Directories are not completed as such in "coalesced" short-opt arguments. For example, # - Directories are not completed as such in "coalesced" short-opt arguments. For example,
# `rgbasm -M d<tab>` can autocomplete to `rgbasm -M dir/` (no space), but # `rgbasm -M d<tab>` can autocomplete to `rgbasm -M dir/` (no space), but
# `rgbasm -Md<tab>` would autocomplete to `rgbasm -Mdir ` (trailing space) instead. # `rgbasm -Md<tab>` would autocomplete to `rgbasm -Mdir ` (trailing space) instead.
# This is because directory handling is performed by Readline, whom we can't tell about the short # This is because dircetory handling is performed by Readline, whom we can't tell about the short
# opt kerfuffle. The user can work around by separating the argument, as shown above. # opt kerfuffle. The user can work around by separating the argument, as shown above.
# (Also, there might be more possible bugs if `-Mdir` is actually a directory. Ugh.) # (Also, there might be more possible bugs if `-Mdir` is actually a directory. Ugh.)
@@ -20,29 +20,27 @@
# Thus, we don't need to do much to handle that form of argument passing: skip '=' after long opts. # Thus, we don't need to do much to handle that form of argument passing: skip '=' after long opts.
_rgbasm_completions() { _rgbasm_completions() {
COMPREPLY=()
# Format: "long_opt:state_after" # Format: "long_opt:state_after"
# Empty long opt = it doesn't exit # Empty long opt = it doesn't exit
# See the `state` variable below for info about `state_after` # See the `state` variable below for info about `state_after`
declare -A opts=( declare -A opts=(
[h]="help:normal"
[V]="version:normal" [V]="version:normal"
[W]="warning:warning" [E]="export-all:normal"
[h]="halt-without-nop:normal"
[L]="preserve-ld:normal"
[v]="verbose:normal"
[w]=":normal" [w]=":normal"
[B]="backtrace:unk"
[b]="binary-digits:unk" [b]="binary-digits:unk"
[D]="define:unk" [D]="define:unk"
[E]="export-all:normal"
[g]="gfx-chars:unk" [g]="gfx-chars:unk"
[I]="include:dir" [i]="include:dir"
[M]="dependfile:glob-*.mk *.d" [M]="dependfile:glob-*.mk *.d"
[o]="output:glob-*.o" [o]="output:glob-*.o"
[P]="preinclude:glob-*.asm *.inc"
[p]="pad-value:unk" [p]="pad-value:unk"
[Q]="q-precision:unk"
[r]="recursion-depth:unk" [r]="recursion-depth:unk"
[s]="state:unk" [W]="warning:warning"
[v]="verbose:normal"
[X]="max-errors:unk"
) )
# Parse command-line up to current word # Parse command-line up to current word
local opt_ena=true local opt_ena=true
@@ -60,18 +58,6 @@ _rgbasm_completions() {
# "normal" is not returned, `optlen` will be set to the length (dash included) of the "option" # "normal" is not returned, `optlen` will be set to the length (dash included) of the "option"
# part of the argument. # part of the argument.
parse_short_opt() { parse_short_opt() {
# These options act like a long option (= takes up the entire word), but only use a single dash
# So, they need some special handling
if [[ "$1" = "-M"[CGP] ]]; then
state=normal
optlen=${#1}
return;
elif [[ "$1" = "-M"[QT] ]]; then
state='glob-*.d *.mk *.o'
optlen=${#1}
return;
fi
for (( i = 1; i < "${#1}"; i++ )); do for (( i = 1; i < "${#1}"; i++ )); do
# If the option is not known, assume it doesn't take an argument # If the option is not known, assume it doesn't take an argument
local opt="${opts["${1:$i:1}"]:-":normal"}" local opt="${opts["${1:$i:1}"]:-":normal"}"
@@ -85,7 +71,7 @@ _rgbasm_completions() {
optlen=0 optlen=0
} }
for (( i = 1; i < COMP_CWORD; i++ )); do for (( i = 1; i < $COMP_CWORD; i++ )); do
local word="${COMP_WORDS[$i]}" local word="${COMP_WORDS[$i]}"
# If currently processing an argument, skip this word # If currently processing an argument, skip this word
@@ -101,7 +87,7 @@ _rgbasm_completions() {
fi fi
# Check if it's a long option # Check if it's a long option
if [[ "$word" = '--'* ]]; then if [[ "${word:0:2}" = '--' ]]; then
# If the option is unknown, assume it takes no arguments: keep the state at "normal" # If the option is unknown, assume it takes no arguments: keep the state at "normal"
for long_opt in "${opts[@]}"; do for long_opt in "${opts[@]}"; do
if [[ "$word" = "--${long_opt%%:*}" ]]; then if [[ "$word" = "--${long_opt%%:*}" ]]; then
@@ -117,16 +103,25 @@ _rgbasm_completions() {
fi fi
done done
# Check if it's a short option # Check if it's a short option
elif [[ "$word" = '-'* ]]; then elif [[ "${word:0:1}" = '-' ]]; then
parse_short_opt "$word" # The `-M?` ones are a mix of short and long, augh
# The last option takes an argument... # They must match the *full* word, but only take a single dash
if [[ "$state" != 'normal' ]]; then # So, handle them here
if [[ "$optlen" -ne "${#word}" ]]; then if [[ "$1" = "-M"[GP] ]]; then
# If it's contained within the word, we won't complete it, revert to "normal" state=normal
state=normal elif [[ "$1" = "-M"[TQ] ]]; then
else state='glob-*.d *.mk *.o'
# Otherwise, complete it, but start at the beginning of *that* word else
optlen=0 parse_short_opt "$word"
# The last option takes an argument...
if [[ "$state" != 'normal' ]]; then
if [[ "$optlen" -ne "${#word}" ]]; then
# If it's contained within the word, we won't complete it, revert to "normal"
state=normal
else
# Otherwise, complete it, but start at the beginning of *that* word
optlen=0
fi
fi fi
fi fi
fi fi
@@ -134,48 +129,48 @@ _rgbasm_completions() {
# Parse current word # Parse current word
# Careful that it might look like an option, so use `--` aggressively! # Careful that it might look like an option, so use `--` aggressively!
local cur_word="${COMP_WORDS[$i]}" local cur_word="${COMP_WORDS[$COMP_CWORD]}"
# Process options, as short ones may change the state # Process options, as short ones may change the state
if $opt_ena && [[ "$state" = 'normal' && "$cur_word" = '-'* ]]; then if $opt_ena && [[ "$state" = 'normal' && "${cur_word:0:1}" = '-' ]]; then
# We might want to complete to an option or an arg to that option # We might want to complete to an option or an arg to that option
# Parse the option word to check # Parse the option word to check
# There's no whitespace in the option names, so we can ride a little dirty... # There's no whitespace in the option names, so we can ride a little dirty...
# Is this a long option? # Is this a long option?
if [[ "$cur_word" = '--'* ]]; then if [[ "${cur_word:1:1}" = '-' ]]; then
# It is, try to complete one # It is, try to complete one
mapfile -t COMPREPLY < <(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}") COMPREPLY+=( $(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}") )
return 0
elif [[ "$cur_word" = '-M'[CGPQT] ]]; then
# These options act like long opts with no arguments, so return them and exactly them
COMPREPLY=( "$cur_word" )
return 0 return 0
else else
# Short options may be grouped, parse them to determine what to complete # Short options may be grouped, parse them to determine what to complete
parse_short_opt "$cur_word" # The `-M?` ones may not be followed by anything
if [[ "$1" != "-M"[GPTQ] ]]; then
parse_short_opt "$cur_word"
# We got some short options that behave like long ones
COMPREPLY+=( $(compgen -W '-MG -MP -MT -MQ' -- "$cur_word") )
if [[ "$state" = 'normal' ]]; then if [[ "$state" = 'normal' ]]; then
mapfile -t COMPREPLY < <(compgen -W "${!opts[*]}" -P "$cur_word" ''; compgen -W '-MC -MG -MP -MQ -MT' "$cur_word") COMPREPLY+=( $(compgen -W "${!opts[*]}" -P "$cur_word" '') )
return 0 return 0
elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then
# This short option group only awaits its argument! # This short option group only awaits its argument!
# Post the option group as-is as a reply so that Readline inserts a space, # Post the option group as-is as a reply so that Readline inserts a space,
# so that the next completion request switches to the argument # so that the next completion request switches to the argument
# An exception is made for warnings, since it's idiomatic to stick them to the # An exception is made for warnings, since it's idiomatic to stick them to the
# `-W`, and it doesn't break anything. # `-W`, and it doesn't break anything.
COMPREPLY=( "$cur_word" ) COMPREPLY+=( "$cur_word" )
return 0 return 0
fi
fi fi
fi fi
fi fi
COMPREPLY=()
case "$state" in case "$state" in
unk) # Return with no replies: no idea what to complete! unk) # Return with no replies: no idea what to complete!
;; ;;
warning) warning)
mapfile -t COMPREPLY < <(compgen -W " COMPREPLY+=( $(compgen -W "
assert assert
backwards-for backwards-for
builtin-args builtin-args
@@ -184,24 +179,20 @@ _rgbasm_completions() {
empty-data-directive empty-data-directive
empty-macro-arg empty-macro-arg
empty-strrpl empty-strrpl
export-undefined
large-constant large-constant
long-string
macro-shift macro-shift
nested-comment nested-comment
numeric-string numeric-string
obsolete obsolete
purge
shift shift
shift-amount shift-amount
truncation truncation
unmapped-char
unmatched-directive
unterminated-load
user user
all all
extra extra
everything everything
error" -P "${cur_word:0:$optlen}" -- "${cur_word:$optlen}") error" -P "${cur_word:0:$optlen}" -- "${cur_word:$optlen}") )
;; ;;
normal) # Acts like a glob... normal) # Acts like a glob...
state="glob-*.asm *.inc *.sm83" state="glob-*.asm *.inc *.sm83"
@@ -218,10 +209,6 @@ _rgbasm_completions() {
done < <(compgen -A directory -- "${cur_word:$optlen}") done < <(compgen -A directory -- "${cur_word:$optlen}")
compopt -o filenames compopt -o filenames
;; ;;
*)
echo >&2 "Internal completion error: invalid state \"$state\", please report this bug"
return 1
;;
esac esac
} }

View File

@@ -1,32 +1,29 @@
#!/usr/bin/env bash #/usr/bin/env bash
# Same notes as RGBASM # Same notes as RGBASM
_rgbfix_completions() { _rgbfix_completions() {
COMPREPLY=()
# Format: "long_opt:state_after" # Format: "long_opt:state_after"
# Empty long opt = it doesn't exit # Empty long opt = it doesn't exit
# See the `state` variable below for info about `state_after` # See the `state` variable below for info about `state_after`
declare -A opts=( declare -A opts=(
[h]="help:normal"
[V]="version:normal" [V]="version:normal"
[W]="warning:warning" [j]="non-japanese:normal"
[w]=":normal" [s]="sgb-compatible:normal"
[v]="validate:normal"
[C]="color-only:normal" [C]="color-only:normal"
[c]="color-compatible:normal" [c]="color-compatible:normal"
[f]="fix-spec:fix-spec" [f]="fix-spec:fix-spec"
[i]="game-id:unk" [i]="game-id:unk"
[j]="non-japanese:normal"
[k]="new-licensee:unk" [k]="new-licensee:unk"
[L]="custom-logo:glob-*.1bpp"
[l]="old-licensee:unk" [l]="old-licensee:unk"
[m]="mbc-type:mbc" [m]="mbc-type:mbc"
[n]="rom-version:unk" [n]="rom-version:unk"
[o]="output:glob-*.gb *.gbc *.sgb"
[p]="pad-value:unk" [p]="pad-value:unk"
[r]="ram-size:unk" [r]="ram-size:unk"
[s]="sgb-compatible:normal"
[t]="title:unk" [t]="title:unk"
[v]="validate:normal"
) )
# Parse command-line up to current word # Parse command-line up to current word
local opt_ena=true local opt_ena=true
@@ -57,7 +54,7 @@ _rgbfix_completions() {
optlen=0 optlen=0
} }
for (( i = 1; i < COMP_CWORD; i++ )); do for (( i = 1; i < $COMP_CWORD; i++ )); do
local word="${COMP_WORDS[$i]}" local word="${COMP_WORDS[$i]}"
# If currently processing an argument, skip this word # If currently processing an argument, skip this word
@@ -73,7 +70,7 @@ _rgbfix_completions() {
fi fi
# Check if it's a long option # Check if it's a long option
if [[ "$word" = '--'* ]]; then if [[ "${word:0:2}" = '--' ]]; then
# If the option is unknown, assume it takes no arguments: keep the state at "normal" # If the option is unknown, assume it takes no arguments: keep the state at "normal"
for long_opt in "${opts[@]}"; do for long_opt in "${opts[@]}"; do
if [[ "$word" = "--${long_opt%%:*}" ]]; then if [[ "$word" = "--${long_opt%%:*}" ]]; then
@@ -89,7 +86,7 @@ _rgbfix_completions() {
fi fi
done done
# Check if it's a short option # Check if it's a short option
elif [[ "$word" = '-'* ]]; then elif [[ "${word:0:1}" = '-' ]]; then
parse_short_opt "$word" parse_short_opt "$word"
# The last option takes an argument... # The last option takes an argument...
if [[ "$state" != 'normal' ]]; then if [[ "$state" != 'normal' ]]; then
@@ -106,25 +103,25 @@ _rgbfix_completions() {
# Parse current word # Parse current word
# Careful that it might look like an option, so use `--` aggressively! # Careful that it might look like an option, so use `--` aggressively!
local cur_word="${COMP_WORDS[$i]}" local cur_word="${COMP_WORDS[$COMP_CWORD]}"
# Process options, as short ones may change the state # Process options, as short ones may change the state
if $opt_ena && [[ "$state" = 'normal' && "$cur_word" = '-'* ]]; then if $opt_ena && [[ "$state" = 'normal' && "${cur_word:0:1}" = '-' ]]; then
# We might want to complete to an option or an arg to that option # We might want to complete to an option or an arg to that option
# Parse the option word to check # Parse the option word to check
# There's no whitespace in the option names, so we can ride a little dirty... # There's no whitespace in the option names, so we can ride a little dirty...
# Is this a long option? # Is this a long option?
if [[ "$cur_word" = '--'* ]]; then if [[ "${cur_word:1:1}" = '-' ]]; then
# It is, try to complete one # It is, try to complete one
mapfile -t COMPREPLY < <(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}") COMPREPLY+=( $(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}") )
return 0 return 0
else else
# Short options may be grouped, parse them to determine what to complete # Short options may be grouped, parse them to determine what to complete
parse_short_opt "$cur_word" parse_short_opt "$cur_word"
if [[ "$state" = 'normal' ]]; then if [[ "$state" = 'normal' ]]; then
mapfile -t COMPREPLY < <(compgen -W "${!opts[*]}" -P "$cur_word" '') COMPREPLY+=( $(compgen -W "${!opts[*]}" -P "$cur_word" '') )
return 0 return 0
elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then
# This short option group only awaits its argument! # This short option group only awaits its argument!
@@ -132,36 +129,22 @@ _rgbfix_completions() {
# so that the next completion request switches to the argument # so that the next completion request switches to the argument
# An exception is made for warnings, since it's idiomatic to stick them to the # An exception is made for warnings, since it's idiomatic to stick them to the
# `-W`, and it doesn't break anything. # `-W`, and it doesn't break anything.
COMPREPLY=( "$cur_word" ) COMPREPLY+=( "$cur_word" )
return 0 return 0
fi fi
fi fi
fi fi
COMPREPLY=()
case "$state" in case "$state" in
unk) # Return with no replies: no idea what to complete! unk) # Return with no replies: no idea what to complete!
;; ;;
warning)
mapfile -t COMPREPLY < <(compgen -W "
mbc
obsolete
overwrite
sgb
truncation
all
everything
error" -P "${cur_word:0:$optlen}" -- "${cur_word:$optlen}")
;;
fix-spec) fix-spec)
COMPREPLY=( "${cur_word}"{l,h,g,L,H,G} ) COMPREPLY+=( "${cur_word}"{l,h,g,L,H,G} )
;; ;;
mbc) mbc)
local cur_arg="${cur_word:$optlen}" local cur_arg="${cur_word:$optlen}"
cur_arg="${cur_arg@U}" cur_arg="${cur_arg@U}"
compopt -o nosort # Keep `help` first in the list, mainly COMPREPLY=( $(compgen -W "
mapfile -t COMPREPLY < <(compgen -W "help" -P "${cur_word:0:$optlen}" -- "${cur_word:$optlen}")
mapfile -t COMPREPLY -O ${#COMPREPLY} < <(compgen -W "
ROM_ONLY ROM_ONLY
MBC1{,+RAM,+RAM+BATTERY} MBC1{,+RAM,+RAM+BATTERY}
MBC2{,+BATTERY} MBC2{,+BATTERY}
@@ -174,7 +157,8 @@ _rgbfix_completions() {
BANDAI_TAMA5 BANDAI_TAMA5
HUC3 HUC3
HUC1+RAM+BATTERY HUC1+RAM+BATTERY
TPP1_1.0{,+BATTERY}{,+RTC}{,+RUMBLE,+MULTIRUMBLE}" -P "${cur_word:0:$optlen}" -- "${cur_word/ /_}") TPP1_1.0{,+BATTERY}{,+RTC}{,+RUMBLE,+MULTIRUMBLE}" -P "${cur_word:0:$optlen}" -- "`tr 'a-z ' 'A-Z_' <<<"${cur_word/ /_}"`") )
COMPREPLY+=( $(compgen -W "help" -P "${cur_word:0:$optlen}" -- "${cur_word:$optlen}") )
;; ;;
normal) # Acts like a glob... normal) # Acts like a glob...
state="glob-*.gb *.gbc *.sgb" state="glob-*.gb *.gbc *.sgb"
@@ -191,10 +175,6 @@ _rgbfix_completions() {
done < <(compgen -A directory -- "${cur_word:$optlen}") done < <(compgen -A directory -- "${cur_word:$optlen}")
compopt -o filenames compopt -o filenames
;; ;;
*)
echo >&2 "Internal completion error: invalid state \"$state\", please report this bug"
return 1
;;
esac esac
} }

View File

@@ -1,44 +1,32 @@
#!/usr/bin/env bash #/usr/bin/env bash
# Same notes as RGBASM # Same notes as RGBASM
_rgbgfx_completions() { _rgbgfx_completions() {
COMPREPLY=()
# Format: "long_opt:state_after" # Format: "long_opt:state_after"
# Empty long opt = it doesn't exit # Empty long opt = it doesn't exit
# See the `state` variable below for info about `state_after` # See the `state` variable below for info about `state_after`
declare -A opts=( declare -A opts=(
[h]="help:normal"
[V]="version:normal" [V]="version:normal"
[W]="warning:warning"
[w]=":normal"
[A]="auto-attr-map:normal"
[a]="attr-map:glob-*.attrmap"
[B]="background-color:unk"
[b]="base-tiles:unk"
[C]="color-curve:normal" [C]="color-curve:normal"
[c]="colors:unk" [D]="debug:normal"
[d]="depth:unk" [h]="horizontal:normal"
[i]="input-tileset:glob-*.2bpp"
[L]="slice:unk"
[m]="mirror-tiles:normal" [m]="mirror-tiles:normal"
[N]="nb-tiles:unk"
[n]="nb-palettes:unk"
[O]="group-outputs:normal"
[o]="output:glob-*.2bpp"
[P]="auto-palette:normal"
[p]="palette:glob-*.pal"
[Q]="auto-palette-map:normal"
[q]="palette-map:glob-*.palmap"
[r]="reverse:unk"
[s]="palette-size:unk"
[T]="auto-tilemap:normal"
[t]="tilemap:glob-*.tilemap"
[u]="unique-tiles:normal" [u]="unique-tiles:normal"
[v]="verbose:normal" [v]="verbose:normal"
[X]="mirror-x:normal" [f]="fix:normal"
[F]="fix-and-save:normal"
[a]="attr-map:*.attrmap"
[A]="output-attr-map:normal"
[d]="depth:unk"
[o]="output:glob *.2bpp"
[p]="palette:glob *.pal"
[P]="output-palette:normal"
[t]="tilemap:glob *.tilemap"
[T]="output-tilemap:normal"
[x]="trim-end:unk" [x]="trim-end:unk"
[Y]="mirror-y:normal"
[Z]="columns:normal"
) )
# Parse command-line up to current word # Parse command-line up to current word
local opt_ena=true local opt_ena=true
@@ -69,7 +57,7 @@ _rgbgfx_completions() {
optlen=0 optlen=0
} }
for (( i = 1; i < COMP_CWORD; i++ )); do for (( i = 1; i < $COMP_CWORD; i++ )); do
local word="${COMP_WORDS[$i]}" local word="${COMP_WORDS[$i]}"
# If currently processing an argument, skip this word # If currently processing an argument, skip this word
@@ -85,7 +73,7 @@ _rgbgfx_completions() {
fi fi
# Check if it's a long option # Check if it's a long option
if [[ "$word" = '--'* ]]; then if [[ "${word:0:2}" = '--' ]]; then
# If the option is unknown, assume it takes no arguments: keep the state at "normal" # If the option is unknown, assume it takes no arguments: keep the state at "normal"
for long_opt in "${opts[@]}"; do for long_opt in "${opts[@]}"; do
if [[ "$word" = "--${long_opt%%:*}" ]]; then if [[ "$word" = "--${long_opt%%:*}" ]]; then
@@ -101,7 +89,7 @@ _rgbgfx_completions() {
fi fi
done done
# Check if it's a short option # Check if it's a short option
elif [[ "$word" = '-'* ]]; then elif [[ "${word:0:1}" = '-' ]]; then
parse_short_opt "$word" parse_short_opt "$word"
# The last option takes an argument... # The last option takes an argument...
if [[ "$state" != 'normal' ]]; then if [[ "$state" != 'normal' ]]; then
@@ -118,25 +106,25 @@ _rgbgfx_completions() {
# Parse current word # Parse current word
# Careful that it might look like an option, so use `--` aggressively! # Careful that it might look like an option, so use `--` aggressively!
local cur_word="${COMP_WORDS[$i]}" local cur_word="${COMP_WORDS[$COMP_CWORD]}"
# Process options, as short ones may change the state # Process options, as short ones may change the state
if $opt_ena && [[ "$state" = 'normal' && "$cur_word" = '-'* ]]; then if $opt_ena && [[ "$state" = 'normal' && "${cur_word:0:1}" = '-' ]]; then
# We might want to complete to an option or an arg to that option # We might want to complete to an option or an arg to that option
# Parse the option word to check # Parse the option word to check
# There's no whitespace in the option names, so we can ride a little dirty... # There's no whitespace in the option names, so we can ride a little dirty...
# Is this a long option? # Is this a long option?
if [[ "$cur_word" = '--'* ]]; then if [[ "${cur_word:1:1}" = '-' ]]; then
# It is, try to complete one # It is, try to complete one
mapfile -t COMPREPLY < <(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}") COMPREPLY+=( $(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}") )
return 0 return 0
else else
# Short options may be grouped, parse them to determine what to complete # Short options may be grouped, parse them to determine what to complete
parse_short_opt "$cur_word" parse_short_opt "$cur_word"
if [[ "$state" = 'normal' ]]; then if [[ "$state" = 'normal' ]]; then
mapfile -t COMPREPLY < <(compgen -W "${!opts[*]}" -P "$cur_word" '') COMPREPLY+=( $(compgen -W "${!opts[*]}" -P "$cur_word" '') )
return 0 return 0
elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then
# This short option group only awaits its argument! # This short option group only awaits its argument!
@@ -144,25 +132,15 @@ _rgbgfx_completions() {
# so that the next completion request switches to the argument # so that the next completion request switches to the argument
# An exception is made for warnings, since it's idiomatic to stick them to the # An exception is made for warnings, since it's idiomatic to stick them to the
# `-W`, and it doesn't break anything. # `-W`, and it doesn't break anything.
COMPREPLY=( "$cur_word" ) COMPREPLY+=( "$cur_word" )
return 0 return 0
fi fi
fi fi
fi fi
COMPREPLY=()
case "$state" in case "$state" in
unk) # Return with no replies: no idea what to complete! unk) # Return with no replies: no idea what to complete!
;; ;;
warning)
mapfile -t COMPREPLY < <(compgen -W "
embedded
obsolete
trim-nonempty
all
everything
error" -P "${cur_word:0:$optlen}" -- "${cur_word:$optlen}")
;;
normal) # Acts like a glob... normal) # Acts like a glob...
state="glob-*.png" state="glob-*.png"
;& ;&
@@ -178,10 +156,6 @@ _rgbgfx_completions() {
done < <(compgen -A directory -- "${cur_word:$optlen}") done < <(compgen -A directory -- "${cur_word:$optlen}")
compopt -o filenames compopt -o filenames
;; ;;
*)
echo >&2 "Internal completion error: invalid state \"$state\", please report this bug"
return 1
;;
esac esac
} }

View File

@@ -1,28 +1,27 @@
#!/usr/bin/env bash #/usr/bin/env bash
# Same notes as RGBASM # Same notes as RGBASM
_rgblink_completions() { _rgblink_completions() {
COMPREPLY=()
# Format: "long_opt:state_after" # Format: "long_opt:state_after"
# Empty long opt = it doesn't exit # Empty long opt = it doesn't exit
# See the `state` variable below for info about `state_after` # See the `state` variable below for info about `state_after`
declare -A opts=( declare -A opts=(
[h]="help:normal"
[V]="version:normal" [V]="version:normal"
[W]="warning:warning"
[M]="no-sym-in-map:normal"
[d]="dmg:normal" [d]="dmg:normal"
[B]="backtrace:unk" [t]="tiny:normal"
[v]="verbose:normal"
[w]="wramx:normal"
[x]="nopad:normal"
[l]="linkerscript:glob-*" [l]="linkerscript:glob-*"
[m]="map:glob-*.map" [m]="map:glob-*.map"
[n]="sym:glob-*.sym" [n]="sym:glob-*.sym"
[O]="overlay:glob-*.gb *.gbc *.sgb" [O]="overlay:glob-*.gb *.gbc *.sgb"
[o]="output:glob-*.gb *.gbc *.sgb" [o]="output:glob-*.gb *.gbc *.sgb"
[p]="pad:unk" [p]="pad:unk"
[t]="tiny:normal" [s]="smart:unk"
[v]="verbose:normal"
[w]="wramx:normal"
[x]="nopad:normal"
) )
# Parse command-line up to current word # Parse command-line up to current word
local opt_ena=true local opt_ena=true
@@ -53,7 +52,7 @@ _rgblink_completions() {
optlen=0 optlen=0
} }
for (( i = 1; i < COMP_CWORD; i++ )); do for (( i = 1; i < $COMP_CWORD; i++ )); do
local word="${COMP_WORDS[$i]}" local word="${COMP_WORDS[$i]}"
# If currently processing an argument, skip this word # If currently processing an argument, skip this word
@@ -69,7 +68,7 @@ _rgblink_completions() {
fi fi
# Check if it's a long option # Check if it's a long option
if [[ "$word" = '--'* ]]; then if [[ "${word:0:2}" = '--' ]]; then
# If the option is unknown, assume it takes no arguments: keep the state at "normal" # If the option is unknown, assume it takes no arguments: keep the state at "normal"
for long_opt in "${opts[@]}"; do for long_opt in "${opts[@]}"; do
if [[ "$word" = "--${long_opt%%:*}" ]]; then if [[ "$word" = "--${long_opt%%:*}" ]]; then
@@ -85,7 +84,7 @@ _rgblink_completions() {
fi fi
done done
# Check if it's a short option # Check if it's a short option
elif [[ "$word" = '-'* ]]; then elif [[ "${word:0:1}" = '-' ]]; then
parse_short_opt "$word" parse_short_opt "$word"
# The last option takes an argument... # The last option takes an argument...
if [[ "$state" != 'normal' ]]; then if [[ "$state" != 'normal' ]]; then
@@ -102,25 +101,25 @@ _rgblink_completions() {
# Parse current word # Parse current word
# Careful that it might look like an option, so use `--` aggressively! # Careful that it might look like an option, so use `--` aggressively!
local cur_word="${COMP_WORDS[$i]}" local cur_word="${COMP_WORDS[$COMP_CWORD]}"
# Process options, as short ones may change the state # Process options, as short ones may change the state
if $opt_ena && [[ "$state" = 'normal' && "$cur_word" = '-'* ]]; then if $opt_ena && [[ "$state" = 'normal' && "${cur_word:0:1}" = '-' ]]; then
# We might want to complete to an option or an arg to that option # We might want to complete to an option or an arg to that option
# Parse the option word to check # Parse the option word to check
# There's no whitespace in the option names, so we can ride a little dirty... # There's no whitespace in the option names, so we can ride a little dirty...
# Is this a long option? # Is this a long option?
if [[ "$cur_word" = '--'* ]]; then if [[ "${cur_word:1:1}" = '-' ]]; then
# It is, try to complete one # It is, try to complete one
mapfile -t COMPREPLY < <(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}") COMPREPLY+=( $(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}") )
return 0 return 0
else else
# Short options may be grouped, parse them to determine what to complete # Short options may be grouped, parse them to determine what to complete
parse_short_opt "$cur_word" parse_short_opt "$cur_word"
if [[ "$state" = 'normal' ]]; then if [[ "$state" = 'normal' ]]; then
mapfile -t COMPREPLY < <(compgen -W "${!opts[*]}" -P "$cur_word" '') COMPREPLY+=( $(compgen -W "${!opts[*]}" -P "$cur_word" '') )
return 0 return 0
elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then
# This short option group only awaits its argument! # This short option group only awaits its argument!
@@ -128,28 +127,15 @@ _rgblink_completions() {
# so that the next completion request switches to the argument # so that the next completion request switches to the argument
# An exception is made for warnings, since it's idiomatic to stick them to the # An exception is made for warnings, since it's idiomatic to stick them to the
# `-W`, and it doesn't break anything. # `-W`, and it doesn't break anything.
COMPREPLY=( "$cur_word" ) COMPREPLY+=( "$cur_word" )
return 0 return 0
fi fi
fi fi
fi fi
COMPREPLY=()
case "$state" in case "$state" in
unk) # Return with no replies: no idea what to complete! unk) # Return with no replies: no idea what to complete!
;; ;;
warning)
mapfile -t COMPREPLY < <(compgen -W "
assert
div
obsolete
shift
shift-amount
truncation
all
everything
error" -P "${cur_word:0:$optlen}" -- "${cur_word:$optlen}")
;;
normal) # Acts like a glob... normal) # Acts like a glob...
state="glob-*.o *.obj" state="glob-*.o *.obj"
;& ;&
@@ -165,10 +151,6 @@ _rgblink_completions() {
done < <(compgen -A directory -- "${cur_word:$optlen}") done < <(compgen -A directory -- "${cur_word:$optlen}")
compopt -o filenames compopt -o filenames
;; ;;
*)
echo >&2 "Internal completion error: invalid state \"$state\", please report this bug"
return 1
;;
esac esac
} }

View File

@@ -1,11 +1,31 @@
#!/usr/bin/env bash #!/bin/bash
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
#
# Copyright (c) 2021 Rangi
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
declare -A FILES declare -A FILES
while read -r -d '' file; do while read -r -d '' file; do
FILES["$file"]="true" FILES["$file"]="true"
done < <(git diff --name-only -z "$1" HEAD) done < <(git diff --name-only -z $1 HEAD)
edited () { edited () {
${FILES["$1"]:-"false"} ${FILES["$1"]:-"false"}
@@ -20,74 +40,46 @@ dependency () {
# Pull requests that edit the first file without the second may be correct, # Pull requests that edit the first file without the second may be correct,
# but are suspicious enough to require review. # but are suspicious enough to require review.
dependency include/linkdefs.hpp man/rgbds.5 \ dependency include/linkdefs.h src/rgbds.5 \
"Was the object file format changed?" "Was the object file format changed?"
dependency src/asm/parser.y man/rgbasm.5 \ dependency src/asm/parser.y src/asm/rgbasm.5 \
"Was the rgbasm grammar changed?" "Was the rgbasm grammar changed?"
dependency src/asm/actions.cpp man/rgbasm.5 \ dependency include/asm/warning.h src/asm/rgbasm.1 \
"Was the rgbasm grammar changed?"
dependency src/link/script.y man/rgblink.5 \
"Was the linker script grammar changed?"
dependency src/link/layout.cpp man/rgblink.5 \
"Was the linker script grammar changed?"
dependency include/asm/warning.hpp man/rgbasm.1 \
"Were the rgbasm warnings changed?" "Were the rgbasm warnings changed?"
dependency include/link/warning.hpp man/rgblink.1 \
"Were the rgblink warnings changed?"
dependency include/fix/warning.hpp man/rgbfix.1 \
"Were the rgbfix warnings changed?"
dependency include/gfx/warning.hpp man/rgbgfx.1 \
"Were the rgbgfx warnings changed?"
dependency src/asm/object.cpp include/linkdefs.hpp \ dependency src/asm/object.c include/linkdefs.h \
"Should the object file revision be bumped?" "Should the object file revision be bumped?"
dependency src/link/object.cpp include/linkdefs.hpp \ dependency src/link/object.c include/linkdefs.h \
"Should the object file revision be bumped?" "Should the object file revision be bumped?"
dependency Makefile CMakeLists.txt \ dependency Makefile CMakeLists.txt \
"Did the build process change?" "Did the build process change?"
dependency Makefile src/CMakeLists.txt \ dependency Makefile src/CMakeLists.txt \
"Did the build process change?" "Did the build process change?"
dependency src/asm/main.cpp man/rgbasm.1 \ dependency src/asm/main.c src/asm/rgbasm.1 \
"Did the rgbasm CLI change?" "Did the rgbasm CLI change?"
dependency src/asm/main.cpp contrib/zsh_compl/_rgbasm \ dependency src/asm/main.c contrib/zsh_compl/_rgbasm \
"Did the rgbasm CLI change?" "Did the rgbasm CLI change?"
dependency src/asm/main.cpp contrib/bash_compl/_rgbasm.bash \ dependency src/asm/main.c contrib/bash_compl/_rgbasm.bash \
"Did the rgbasm CLI change?" "Did the rgbasm CLI change?"
dependency src/link/main.cpp man/rgblink.1 \ dependency src/link/main.c src/link/rgblink.1 \
"Did the rgblink CLI change?" "Did the rgblink CLI change?"
dependency src/link/main.cpp contrib/zsh_compl/_rgblink \ dependency src/link/main.c contrib/zsh_compl/_rgblink \
"Did the rgblink CLI change?" "Did the rgblink CLI change?"
dependency src/link/main.cpp contrib/bash_compl/_rgblink.bash \ dependency src/link/main.c contrib/bash_compl/_rgblink.bash \
"Did the rgblink CLI change?" "Did the rgblink CLI change?"
dependency src/fix/main.cpp man/rgbfix.1 \ dependency src/fix/main.c src/fix/rgbfix.1 \
"Did the rgbfix CLI change?" "Did the rgbfix CLI change?"
dependency src/fix/main.cpp contrib/zsh_compl/_rgbfix \ dependency src/fix/main.c contrib/zsh_compl/_rgbfix \
"Did the rgbfix CLI change?" "Did the rgbfix CLI change?"
dependency src/fix/main.cpp contrib/bash_compl/_rgbfix.bash \ dependency src/fix/main.c contrib/bash_compl/_rgbfix.bash \
"Did the rgbfix CLI change?" "Did the rgbfix CLI change?"
dependency src/gfx/main.cpp man/rgbgfx.1 \ dependency src/gfx/main.c src/gfx/rgbgfx.1 \
"Did the rgbgfx CLI change?" "Did the rgbgfx CLI change?"
dependency src/gfx/main.cpp contrib/zsh_compl/_rgbgfx \ dependency src/gfx/main.c contrib/zsh_compl/_rgbgfx \
"Did the rgbgfx CLI change?" "Did the rgbgfx CLI change?"
dependency src/gfx/main.cpp contrib/bash_compl/_rgbgfx.bash \ dependency src/gfx/main.c contrib/bash_compl/_rgbgfx.bash \
"Did the rgbgfx CLI change?" "Did the rgbgfx CLI change?"
dependency test/fetch-test-deps.sh CONTRIBUTING.md \
"Did the test protocol change?"
dependency test/run-tests.sh CONTRIBUTING.md \
"Did the test protocol change?"
dependency test/asm/test.sh CONTRIBUTING.md \
"Did the RGBASM test protocol change?"
dependency test/link/test.sh CONTRIBUTING.md \
"Did the RGBLINK test protocol change?"
dependency test/fix/test.sh CONTRIBUTING.md \
"Did the RGBFIX test protocol change?"
dependency test/gfx/test.sh CONTRIBUTING.md \
"Did the RGBGFX test protocol change?"

View File

@@ -1,15 +0,0 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MIT
clang-format --version
find . -type f \( -iname '*.hpp' -o -iname '*.cpp' \) -exec clang-format -i {} +
if ! git diff-index --quiet HEAD --; then
echo 'Unformatted files:'
git diff-index --name-only HEAD --
echo
git diff HEAD --
exit 1
fi

View File

@@ -1,35 +0,0 @@
#!/usr/bin/env bash
set -e
# Build RGBDS with gcov support
make coverage -j
# Run the tests
pushd test
./fetch-test-deps.sh
if [[ $# -eq 0 ]]; then
./run-tests.sh
else
./run-tests.sh --os "$1"
fi
popd
# Generate coverage logs
gcov src/**/*.cpp
mkdir -p coverage
# Generate coverage report, excluding Bison-generated files
COVERAGE_INFO=coverage/coverage.info
lcov -c --no-external -d . -o "$COVERAGE_INFO"
lcov -r "$COVERAGE_INFO" src/asm/parser.{hpp,cpp} src/link/script.{hpp,cpp} -o "$COVERAGE_INFO"
genhtml --dark-mode -f -s -o coverage/ "$COVERAGE_INFO"
# Check whether running from coverage.yml workflow
if [ "$1" != "ubuntu-ci" ]; then
# Open report in web browser
if [ "$(uname)" == "Darwin" ]; then
open coverage/index.html
else
xdg-open coverage/index.html
fi
fi

View File

@@ -1,54 +1,73 @@
#!/usr/bin/env bash #!/bin/bash
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
#
# Copyright (c) 2020 Eldred Habert
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
STATE=0 STATE=0
diff <(xxd "$1") <(xxd "$2") | while read -r LINE; do diff <(xxd $1) <(xxd $2) | while read -r LINE; do
if [[ $STATE -eq 0 ]]; then if [ $STATE -eq 0 ]; then
# Discard first line (line info) # Discard first line (line info)
STATE=1 STATE=1
elif [[ "$LINE" = '---' ]]; then elif [ "$LINE" = '---' ]; then
# Separator between files switches states # Separator between files switches states
echo "$LINE" echo $LINE
STATE=3 STATE=3
elif grep -Eq '^[0-9]+(,[0-9]+)?[cd][0-9]+(,[0-9]+)?' <<< "$LINE"; then elif grep -Eq '^[0-9]+(,[0-9]+)?[cd][0-9]+(,[0-9]+)?' <<< "$LINE"; then
# Line info resets the whole thing # Line info resets the whole thing
STATE=1 STATE=1
elif [[ $STATE -eq 1 || $STATE -eq 3 ]]; then elif [ $STATE -eq 1 -o $STATE -eq 3 ]; then
# Compute the GB address from the ROM offset # Compute the GB address from the ROM offset
OFS=$(cut -d ' ' -f 2 <<< "$LINE" | tr -d ':') OFS=$(cut -d ' ' -f 2 <<< "$LINE" | tr -d ':')
BANK=$((0x$OFS / 0x4000)) BANK=$((0x$OFS / 0x4000))
ADDR=$((0x$OFS % 0x4000 + (BANK != 0) * 0x4000)) ADDR=$((0x$OFS % 0x4000 + ($BANK != 0) * 0x4000))
# Try finding the preceding symbol closest to the diff # Try finding the preceding symbol closest to the diff
if [[ $STATE -eq 1 ]]; then if [ $STATE -eq 1 ]; then
STATE=2 STATE=2
SYMFILE=${1%.*}.sym SYMFILE=${1%.*}.sym
else else
STATE=4 STATE=4
SYMFILE=${2%.*}.sym SYMFILE=${2%.*}.sym
fi fi
EXTRA=$(if [[ -f "$SYMFILE" ]]; then EXTRA=$(if [ -f "$SYMFILE" ]; then
# Read the sym file for such a symbol # Read the sym file for such a symbol
# Ignore comment lines, only pick matching bank # Ignore comment lines, only pick matching bank
# (The bank regex ignores comments already, make `cut` and `tr` process less lines) # (The bank regex ignores comments already, make `cut` and `tr` process less lines)
grep -Ei "$(printf "^%02x:" $BANK)" "$SYMFILE" | grep -Ei $(printf "^%02x:" $BANK) "$SYMFILE" |
sed "s/$(printf "^%02x:" $BANK)/0x/g" |
cut -d ';' -f 1 | cut -d ';' -f 1 |
tr -d "\r" | tr -d "\r" |
sort -g |
while read -r SYMADDR SYM; do while read -r SYMADDR SYM; do
SYMADDR=$(($SYMADDR)) SYMADDR=$((0x${SYMADDR#*:}))
if [[ $SYMADDR -le $ADDR ]]; then if [ $SYMADDR -le $ADDR ]; then
printf " (%s+0x%x)\n" "$SYM" $((ADDR - SYMADDR)) printf " (%s+%#x)\n" "$SYM" $(($ADDR - $SYMADDR))
fi fi
# TODO: assumes sorted sym files
done | tail -n 1 done | tail -n 1
fi) fi)
printf "%02x:%04x %s\n" $BANK $ADDR "$EXTRA" printf "%02x:%04x %s\n" $BANK $ADDR $EXTRA
fi fi
if [[ $STATE -eq 2 || $STATE -eq 4 ]]; then if [ $STATE -eq 2 -o $STATE -eq 4 ]; then
OFS=$(cut -d ' ' -f 2 <<< "$LINE" | tr -d ':') OFS=$(cut -d ' ' -f 2 <<< "$LINE" | tr -d ':')
BANK=$((0x$OFS / 0x4000)) BANK=$((0x$OFS / 0x4000))
ADDR=$((0x$OFS % 0x4000 + (BANK != 0) * 0x4000)) ADDR=$((0x$OFS % 0x4000 + ($BANK != 0) * 0x4000))
printf "%s %02x:%04x: %s\n" "${LINE:0:1}" $BANK $ADDR "${LINE#*: }" printf "%s %02x:%04x: %s\n" "${LINE:0:1}" $BANK $ADDR "${LINE#*: }"
fi fi
done done

View File

@@ -1,25 +0,0 @@
#!/bin/bash
set -euo pipefail
if [[ $# -ne 2 ]]; then
cat <<EOF >&2
Usage: $0 <palettes.pal> <output.png>
EOF
exit 1
fi
TMP=$(mktemp -d)
readonly TMP
trap 'rm -rf "$TMP"' EXIT
tile() { for i in {0..7}; do printf "$1"; done }
{ tile '\x00\x00' && tile '\xFF\x00' && tile '\x00\xFF' && tile '\xFF\xFF'; } >"$TMP/tmp.2bpp"
NB_BYTES=$(wc -c <"$1")
(( NB_PALS = NB_BYTES / 8 ))
for (( i = 0; i < NB_PALS; i++ )); do
printf '\0\1\2\3' >>"$TMP/tmp.tilemap"
printf $(printf '\\x%x' $i{,,,}) >> "$TMP/tmp.palmap"
done
"${RGBGFX:-${RGBDS+$RGBDS/}rgbgfx}" -r 4 "$2" -o "$TMP/tmp.2bpp" -OTQ -p "$1" -n "$NB_PALS"

View File

@@ -16,53 +16,45 @@ _rgbasm_warnings() {
'empty-data-directive:Warn on arg-less d[bwl] in ROM' 'empty-data-directive:Warn on arg-less d[bwl] in ROM'
'empty-macro-arg:Warn on empty macro arg' 'empty-macro-arg:Warn on empty macro arg'
'empty-strrpl:Warn on calling STRRPL with empty pattern' 'empty-strrpl:Warn on calling STRRPL with empty pattern'
'export-undefined:Warn on EXPORT of an undefined symbol'
'large-constant:Warn on constants too large for a signed 32-bit int' 'large-constant:Warn on constants too large for a signed 32-bit int'
'long-string:Warn on strings too long'
'macro-shift:Warn when shifting macro args part their limits' 'macro-shift:Warn when shifting macro args part their limits'
'nested-comment:Warn on "/*" inside block comments' 'nested-comment:Warn on "/*" inside block comments'
'numeric-string:Warn when a multi-character string is treated as a number' 'numeric-string:Warn when a multi-character string is treated as a number'
'obsolete:Warn when using deprecated features' 'obsolete:Warn when using deprecated features'
'purge:Warn when purging exported symbols or labels'
'shift:Warn when shifting negative values' 'shift:Warn when shifting negative values'
'shift-amount:Warn when a shift'\''s operand is negative or \> 32' 'shift-amount:Warn when a shift'\''s operand it negative or \> 32'
'truncation:Warn when implicit truncation loses bits' 'truncation:Warn when implicit truncation loses bits'
'unmapped-char:Warn on unmapped character'
'unmatched-directive:Warn on unmatched directive pair'
'unterminated-load:Warn on LOAD without ENDL'
'user:Warn when executing the WARN built-in' 'user:Warn when executing the WARN built-in'
) )
# TODO: handle `no-` and `error=` somehow?
# TODO: handle `=0|1|2` levels for `numeric-string` and `truncation`?
_describe warning warnings _describe warning warnings
} }
local args=( local args=(
# Arguments are listed here in the same order as in the manual, except for the version and help # Arguments are listed here in the same order as in the manual, except for the version
'(- : * options)'{-V,--version}'[Print version number and exit]' '(- : * options)'{-V,--version}'[Print version number]'
'(- : * options)'{-h,--help}'[Print help text and exit]'
'(-E --export-all)'{-E,--export-all}'[Export all symbols]' '(-E --export-all)'{-E,--export-all}'[Export all symbols]'
'(-v --verbose)'{-v,--verbose}'[Enable verbose output]' '(-h --halt-without-nop)'{-h,--halt-without-nop}'[Avoid outputting a `nop` after `halt`]'
'(-L ---preserve-ld)'{-L,--preserve-ld}'[Prevent auto-optimizing `ld` into `ldh`]'
'(-v --verbose)'{-v,--verbose}'[Print additional messages regarding progression]'
-w'[Disable all warnings]' -w'[Disable all warnings]'
'(-B --backtrace)'{-B,--backtrace}'+[Set backtrace depth or style]:param:'
'(-b --binary-digits)'{-b,--binary-digits}'+[Change chars for binary constants]:digit spec:' '(-b --binary-digits)'{-b,--binary-digits}'+[Change chars for binary constants]:digit spec:'
--color'[Whether to use color in output]:color:(auto always never)'
'*'{-D,--define}'+[Define a string symbol]:name + value (default 1):' '*'{-D,--define}'+[Define a string symbol]:name + value (default 1):'
'(-g --gfx-chars)'{-g,--gfx-chars}'+[Change chars for gfx constants]:chars spec:' '(-g --gfx-chars)'{-g,--gfx-chars}'+[Change chars for gfx constants]:chars spec:'
'(-I --include)'{-I,--include}'+[Add an include directory]:include path:_files -/' '(-i --include)'{-i,--include}'+[Add an include directory]:include path:_files -/'
'(-M --dependfile)'{-M,--dependfile}"+[Write dependencies in Makefile format]:output file:_files -g '*.{d,mk}'" '(-M --dependfile)'{-M,--dependfile}"+[List deps in make format]:output file:_files -g '*.{d,mk}'"
-MC'[Continue after missing dependencies]' -MG'[Assume missing files should be generated]'
-MG'[Assume missing dependencies should be generated]' -MP'[Add phony targets to all deps]'
-MP'[Add phony targets to all dependencies]'
'*'-MT"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'" '*'-MT"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'"
'*'-MQ"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'" '*'-MQ"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'"
'(-o --output)'{-o,--output}'+[Output file]:output file:_files' '(-o --output)'{-o,--output}'+[Output file]:output file:_files'
'(-P --preinclude)'{-P,--preinclude}"+[Pre-include a file]:include file:_files -g '*.{asm,inc}'"
'(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:' '(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:'
'(-Q --q-precision)'{-Q,--q-precision}'+[Set fixed-point precision]:precision:'
'(-r --recursion-depth)'{-r,--recursion-depth}'+[Set maximum recursion depth]:depth:' '(-r --recursion-depth)'{-r,--recursion-depth}'+[Set maximum recursion depth]:depth:'
'(-s --state)'{-s,--state}"+[Write features of final state]:state file:_files -g '*.dump.asm'"
'(-W --warning)'{-W,--warning}'+[Toggle warning flags]:warning flag:_rgbasm_warnings' '(-W --warning)'{-W,--warning}'+[Toggle warning flags]:warning flag:_rgbasm_warnings'
'(-X --max-errors)'{-X,--max-errors}'+[Set maximum errors before aborting]:maximum errors:'
":assembly sources:_files -g '*.asm'" ":assembly sources:_files -g '*.asm'"
) )

View File

@@ -34,26 +34,9 @@ _mbc_names() {
_describe "MBC name" mbc_names _describe "MBC name" mbc_names
} }
_rgbfix_warnings() {
local warnings=(
'error:Turn all warnings into errors'
'all:Enable most warning messages'
'everything:Enable literally everything'
'mbc:Warn about issues with MBC specs'
'obsolete:Warn when using deprecated features'
'overwrite:Warn when overwriting non-zero bytes'
'sgb:Warn when SGB flag conflicts with old licensee code'
'truncation:Warn when values are truncated to fit'
)
_describe warning warnings
}
local args=( local args=(
# Arguments are listed here in the same order as in the manual, except for the version and help # Arguments are listed here in the same order as in the manual, except for the version
'(- : * options)'{-V,--version}'[Print version number and exit]' '(- : * options)'{-V,--version}'[Print version number]'
'(- : * options)'{-h,--help}'[Print help text and exit]'
'(-C --color-only -c --color-compatible)'{-C,--color-only}'[Mark ROM as GBC-only]' '(-C --color-only -c --color-compatible)'{-C,--color-only}'[Mark ROM as GBC-only]'
'(-C --color-only -c --color-compatible)'{-c,--color-compatible}'[Mark ROM as GBC-compatible]' '(-C --color-only -c --color-compatible)'{-c,--color-compatible}'[Mark ROM as GBC-compatible]'
@@ -61,21 +44,16 @@ local args=(
'(-O --overwrite)'{-O,--overwrite}'[Allow overwriting non-zero bytes]' '(-O --overwrite)'{-O,--overwrite}'[Allow overwriting non-zero bytes]'
'(-s --sgb-compatible)'{-s,--sgb-compatible}'[Set the SGB flag]' '(-s --sgb-compatible)'{-s,--sgb-compatible}'[Set the SGB flag]'
'(-f --fix-spec -v --validate)'{-v,--validate}'[Shorthand for -f lhg]' '(-f --fix-spec -v --validate)'{-v,--validate}'[Shorthand for -f lhg]'
-w'[Disable all warnings]'
--color'[Whether to use color in output]:color:(auto always never)'
'(-f --fix-spec -v --validate)'{-f,--fix-spec}'+[Fix or trash some header values]:fix spec:' '(-f --fix-spec -v --validate)'{-f,--fix-spec}'+[Fix or trash some header values]:fix spec:'
'(-i --game-id)'{-i,--game-id}'+[Set game ID string]:4-char game ID:' '(-i --game-id)'{-i,--game-id}'+[Set game ID string]:4-char game ID:'
'(-k --new-licensee)'{-k,--new-licensee}'+[Set new licensee string]:2-char licensee ID:' '(-k --new-licensee)'{-k,--new-licensee}'+[Set new licensee string]:2-char licensee ID:'
'(-l --old-licensee)'{-l,--old-licensee}'+[Set old licensee ID]:licensee number:' '(-l --old-licensee)'{-l,--old-licensee}'+[Set old licensee ID]:licensee number:'
'(-L --logo)'{-L,--logo}'+[Set custom logo]:1bpp image:'
'(-m --mbc-type)'{-m,--mbc-type}"+[Set MBC flags]:mbc name:_mbc_names" '(-m --mbc-type)'{-m,--mbc-type}"+[Set MBC flags]:mbc name:_mbc_names"
'(-n --rom-version)'{-n,--rom-version}'+[Set ROM version]:rom version byte:' '(-n --rom-version)'{-n,--rom-version}'+[Set ROM version]:rom version byte:'
'(-o --output)'{-o,--output}"+[Output file]:output file:_files -g '*.{gb,sgb,gbc}'"
'(-p --pad-value)'{-p,--pad-value}'+[Pad to next valid size using this byte as padding]:padding byte:' '(-p --pad-value)'{-p,--pad-value}'+[Pad to next valid size using this byte as padding]:padding byte:'
'(-r --ram-size)'{-r,--ram-size}'+[Set RAM size]:ram size byte:' '(-r --ram-size)'{-r,--ram-size}'+[Set RAM size]:ram size byte:'
'(-t --title)'{-t,--title}'+[Set title string]:11-char title string:' '(-t --title)'{-t,--title}'+[Set title string]:11-char title string:'
'(-W --warning)'{-W,--warning}'+[Toggle warning flags]:warning flag:_rgbfix_warnings'
'*'":ROM files:_files -g '*.{gb,sgb,gbc}'" '*'":ROM files:_files -g '*.{gb,sgb,gbc}'"
) )

View File

@@ -9,56 +9,27 @@ _depths() {
_describe 'bit depth' depths _describe 'bit depth' depths
} }
_rgbgfx_warnings() {
local warnings=(
'error:Turn all warnings into errors'
'all:Enable most warning messages'
'everything:Enable literally everything'
'embedded:Warn when using embedded PLTE without "-c embedded"'
'obsolete:Warn when using deprecated features'
'trim-nonempty:Warn when "-x" trims nonempty tiles'
)
_describe warning warnings
}
local args=( local args=(
# Arguments are listed here in the same order as in the manual, except for the version and help # Arguments are listed here in the same order as in the manual, except for the version
'(- : * options)'{-V,--version}'[Print version number and exit]' '(- : * options)'{-V,--version}'[Print version number]'
'(- : * options)'{-h,--help}'[Print help text and exit]'
'(-a --attr-map -A --auto-attr-map)'{-A,--auto-attr-map}'[Shortcut for -a <file>.attrmap]' '(-a --attr-map -A --output-attr-map)'{-A,--output-attr-map}'[Shortcut for -a <file>.attrmap]'
'(-C --color-curve)'{-C,--color-curve}'[Generate palettes using GBC color curve]' '(-C --color-curve)'{-C,--color-curve}'[Generate palettes using GBC color curve]'
'(-D --debug)'{-D,--debug}'[Enable debug features]'
'(-f --fix -F --fix-and-save)'{-f,--fix}'[Fix input PNG into an indexed image]'
'(-f --fix -F --fix-and-save)'{-F,--fix-and-save}'[Like -f but also save CLI params within the PNG]'
'(-h --horizontal)'{-h,--horizontal}'[Lay out tiles horizontally instead of vertically]'
'(-m --mirror-tiles)'{-m,--mirror-tiles}'[Eliminate mirrored tiles from output]' '(-m --mirror-tiles)'{-m,--mirror-tiles}'[Eliminate mirrored tiles from output]'
'(-O --group-outputs)'{-O,--group-outputs}'[Base "shortcut" options on the output path, not input]' '(-p --palette -P --output-palette)'{-P,--output-palette}'[Shortcut for -p <file>.pal]'
'(-p --palette -P --auto-palette)'{-P,--auto-palette}'[Shortcut for -p <file>.pal]' '(-t --tilemap -T --output-tilemap)'{-T,--output-tilemap}'[Shortcut for -t <file>.tilemap]'
'(-q --palette-map -Q --auto-palette-map)'{-Q,--auto-palette-map}'[Shortcut for -p <file>.palmap]'
'(-t --tilemap -T --auto-tilemap)'{-T,--auto-tilemap}'[Shortcut for -t <file>.tilemap]'
'(-u --unique-tiles)'{-u,--unique-tiles}'[Eliminate redundant tiles]' '(-u --unique-tiles)'{-u,--unique-tiles}'[Eliminate redundant tiles]'
'(-v --verbose)'{-v,--verbose}'[Enable verbose output]' '(-v --verbose)'{-v,--verbose}'[Enable verbose output]'
-w'[Disable all warnings]'
'(-X --mirror-x)'{-X,--mirror-x}'[Eliminate horizontally mirrored tiles from output]'
'(-Y --mirror-y)'{-Y,--mirror-y}'[Eliminate vertically mirrored tiles from output]'
'(-Z --columns)'{-Z,--columns}'[Read the image in column-major order]'
'(-a --attr-map -A --auto-attr-map)'{-a,--attr-map}'+[Generate a map of tile attributes (mirroring)]:attrmap file:_files' '(-a --attr-map -A --output-attr-map)'{-a,--attr-map}'+[Generate a map of tile attributes (mirroring)]:attrmap file:_files'
'(-B --background-color)'{-B,--background-color}'+[Ignore tiles containing only specified color]:color:'
'(-b --base-tiles)'{-b,--base-tiles}'+[Base tile IDs for tile map output]:base tile IDs:'
--color'[Whether to use color in output]:color:(auto always never)'
'(-c --colors)'{-c,--colors}'+[Specify color palettes]:palette spec:'
'(-d --depth)'{-d,--depth}'+[Set bit depth]:bit depth:_depths' '(-d --depth)'{-d,--depth}'+[Set bit depth]:bit depth:_depths'
'(-i --input-tileset)'{-i,--input-tileset}'+[Use specific tiles]:tileset file:_files -g "*.2bpp"'
'(-L --slice)'{-L,--slice}'+[Only process a portion of the image]:input slice:'
'(-N --nb-tiles)'{-N,--nb-tiles}'+[Limit number of tiles]:tile count:'
'(-n --nb-palettes)'{-n,--nb-palettes}'+[Limit number of palettes]:palette count:'
'(-o --output)'{-o,--output}'+[Set output file]:output file:_files' '(-o --output)'{-o,--output}'+[Set output file]:output file:_files'
'(-p --palette -P --auto-palette)'{-p,--palette}"+[Output the image's palette in little-endian native RGB555 format]:palette file:_files" '(-p --palette -P --output-palette)'{-p,--palette}"+[Output the image's palette in little-endian native RGB555 format]:palette file:_files"
'(-q --palette-map -Q --auto-palette-map)'{-q,--palette-map}"+[Output the image's palette map]:palette map file:_files" '(-t --tilemap -T --output-tilemap)'{-t,--tilemap}'+[Generate a map of tile indices]:tilemap file:_files'
'(-r --reverse)'{-r,--reverse}'+[Yield an image from binary data]:image width (in tiles):'
'(-s --palette-size)'{-s,--palette-size}'+[Limit palette size]:palette size:'
'(-t --tilemap -T --auto-tilemap)'{-t,--tilemap}'+[Generate a map of tile indices]:tilemap file:_files'
'(-W --warning)'{-W,--warning}'+[Toggle warning flags]:warning flag:_rgbgfx_warnings'
'(-x --trim-end)'{-x,--trim-end}'+[Trim end of output by this many tiles]:tile count:' '(-x --trim-end)'{-x,--trim-end}'+[Trim end of output by this many tiles]:tile count:'
":input png file:_files -g '*.png'" ":input png file:_files -g '*.png'"

View File

@@ -1,26 +1,8 @@
#compdef rgblink #compdef rgblink
_rgblink_warnings() {
local warnings=(
'error:Turn all warnings into errors'
'all:Enable most warning messages'
'everything:Enable literally everything'
'assert:Warn when WARN-type asserts fail'
'div:Warn when dividing the smallest int by -1'
'obsolete:Warn when using deprecated features'
'shift:Warn when shifting negative values'
'shift-amount:Warn when a shift'\''s operand is negative or \> 32'
'truncation:Warn when implicit truncation loses bits'
)
_describe warning warnings
}
local args=( local args=(
# Arguments are listed here in the same order as in the manual, except for the version and help # Arguments are listed here in the same order as in the manual, except for the version
'(- : * options)'{-V,--version}'[Print version number and exit]' '(- : * options)'{-V,--version}'[Print version number]'
'(- : * options)'{-h,--help}'[Print help text and exit]'
'(-d --dmg)'{-d,--dmg}'[Enable DMG mode (-w + no VRAM banking)]' '(-d --dmg)'{-d,--dmg}'[Enable DMG mode (-w + no VRAM banking)]'
'(-t --tiny)'{-t,--tiny}'[Enable tiny mode, disabling ROM banking]' '(-t --tiny)'{-t,--tiny}'[Enable tiny mode, disabling ROM banking]'
@@ -28,17 +10,14 @@ local args=(
'(-w --wramx)'{-w,--wramx}'[Disable WRAM banking]' '(-w --wramx)'{-w,--wramx}'[Disable WRAM banking]'
'(-x --nopad)'{-x,--nopad}'[Disable padding the end of the final file]' '(-x --nopad)'{-x,--nopad}'[Disable padding the end of the final file]'
'(-B --backtrace)'{-B,--backtrace}'+[Set backtrace depth or style]:param:'
--color'[Whether to use color in output]:color:(auto always never)'
'(-l --linkerscript)'{-l,--linkerscript}"+[Use a linker script]:linker script:_files -g '*.link'" '(-l --linkerscript)'{-l,--linkerscript}"+[Use a linker script]:linker script:_files -g '*.link'"
'(-M --no-sym-in-map)'{-M,--no-sym-in-map}'[Do not output symbol names in map file]'
'(-m --map)'{-m,--map}"+[Produce a map file]:map file:_files -g '*.map'" '(-m --map)'{-m,--map}"+[Produce a map file]:map file:_files -g '*.map'"
'(-n --sym)'(-n,--sym)"+[Produce a symbol file]:sym file:_files -g '*.sym'" '(-n --sym)'(-n,--sym)"+[Produce a symbol file]:sym file:_files -g '*.sym'"
'(-O --overlay)'{-O,--overlay}'+[Overlay sections over on top of bin file]:base overlay:_files' '(-O --overlay)'{-O,--overlay}'+[Overlay sections over on top of bin file]:base overlay:_files'
'(-o --output)'{-o,--output}"+[Write ROM image to this file]:rom file:_files -g '*.{gb,sgb,gbc}'" '(-o --output)'{-o,--output}"+[Write ROM image to this file]:rom file:_files -g '*.{gb,sgb,gbc}'"
'(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:' '(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:'
'(-S --scramble)'{-s,--scramble}'+[Activate scrambling]:scramble spec' '(-S --scramble)'{-s,--scramble}'+[Activate scrambling]:scramble spec'
'(-W --warning)'{-W,--warning}'+[Toggle warning flags]:warning flag:_rgblink_warnings' '(-s --smart)'{-s,--smart}'+[!BROKEN! Perform smart linking from this symbol]:symbol name:'
'*'":object files:_files -g '*.o'" '*'":object files:_files -g '*.o'"
) )

View File

@@ -1,61 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_ASM_ACTIONS_HPP
#define RGBDS_ASM_ACTIONS_HPP
#include <optional>
#include <stddef.h>
#include <stdint.h>
#include <string>
#include <string_view>
#include <variant>
#include <vector>
#include "linkdefs.hpp" // AssertionType, RPNCommand
#include "asm/rpn.hpp" // Expression
struct AlignmentSpec {
uint8_t alignment;
uint16_t alignOfs;
};
void act_If(int32_t condition);
void act_Elif(int32_t condition);
void act_Else();
void act_Endc();
AlignmentSpec act_Alignment(int32_t alignment, int32_t alignOfs);
void act_Assert(AssertionType type, Expression const &expr, std::string const &message);
void act_StaticAssert(AssertionType type, int32_t condition, std::string const &message);
std::optional<std::string> act_ReadFile(std::string const &name, uint32_t maxLen);
uint32_t act_CharToNum(std::string const &str);
uint32_t act_StringToNum(std::string const &str);
int32_t act_CharVal(std::string const &str);
int32_t act_CharVal(std::string const &str, int32_t negIdx);
uint8_t act_StringByte(std::string const &str, int32_t negIdx);
size_t act_StringLen(std::string const &str, bool printErrors);
std::string
act_StringSlice(std::string const &str, int32_t negStart, std::optional<int32_t> negStop);
std::string act_StringSub(std::string const &str, int32_t negPos, std::optional<uint32_t> optLen);
size_t act_CharLen(std::string const &str);
std::string act_StringChar(std::string const &str, int32_t negIdx);
std::string act_CharSub(std::string const &str, int32_t negPos);
int32_t act_CharCmp(std::string_view str1, std::string_view str2);
std::string act_StringReplace(std::string_view str, std::string const &old, std::string const &rep);
std::string act_StringFormat(
std::string const &spec, std::vector<std::variant<uint32_t, std::string>> const &args
);
std::string act_SectionName(std::string const &symName);
void act_CompoundAssignment(std::string const &symName, RPNCommand op, int32_t constValue);
#endif // RGBDS_ASM_ACTIONS_HPP

23
include/asm/charmap.h Normal file
View File

@@ -0,0 +1,23 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ASM_CHARMAP_H
#define RGBDS_ASM_CHARMAP_H
#include <stdint.h>
struct Charmap *charmap_New(char const *name, char const *baseName);
void charmap_Delete(struct Charmap *charmap);
void charmap_Set(char const *name);
void charmap_Push(void);
void charmap_Pop(void);
void charmap_Add(char *mapping, uint8_t value);
size_t charmap_Convert(char const *input, uint8_t *output);
size_t charmap_ConvertNext(char const **input, uint8_t **output);
#endif /* RGBDS_ASM_CHARMAP_H */

View File

@@ -1,32 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_ASM_CHARMAP_HPP
#define RGBDS_ASM_CHARMAP_HPP
#include <optional>
#include <stddef.h>
#include <stdint.h>
#include <string>
#include <string_view>
#include <vector>
#define DEFAULT_CHARMAP_NAME "main"
bool charmap_ForEach(
void (*mapFunc)(std::string const &),
void (*charFunc)(std::string const &, std::vector<int32_t>)
);
void charmap_New(std::string const &name, std::string const *baseName);
void charmap_Set(std::string const &name);
void charmap_Push();
void charmap_Pop();
void charmap_CheckStack();
void charmap_Add(std::string const &mapping, std::vector<int32_t> &&value);
bool charmap_HasChar(std::string const &mapping);
size_t charmap_CharSize(std::string const &mapping);
std::optional<int32_t> charmap_CharValue(std::string const &mapping, size_t idx);
std::vector<int32_t> charmap_Convert(std::string const &input);
size_t charmap_ConvertNext(std::string_view &input, std::vector<int32_t> *output);
std::string charmap_Reverse(std::vector<int32_t> const &value, bool &unique);
#endif // RGBDS_ASM_CHARMAP_HPP

31
include/asm/fixpoint.h Normal file
View File

@@ -0,0 +1,31 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2021, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ASM_FIXPOINT_H
#define RGBDS_ASM_FIXPOINT_H
#include <stdint.h>
int32_t fix_Callback_PI(void);
void fix_Print(int32_t i);
int32_t fix_Sin(int32_t i);
int32_t fix_Cos(int32_t i);
int32_t fix_Tan(int32_t i);
int32_t fix_ASin(int32_t i);
int32_t fix_ACos(int32_t i);
int32_t fix_ATan(int32_t i);
int32_t fix_ATan2(int32_t i, int32_t j);
int32_t fix_Mul(int32_t i, int32_t j);
int32_t fix_Div(int32_t i, int32_t j);
int32_t fix_Pow(int32_t i, int32_t j);
int32_t fix_Log(int32_t i, int32_t j);
int32_t fix_Round(int32_t i);
int32_t fix_Ceil(int32_t i);
int32_t fix_Floor(int32_t i);
#endif /* RGBDS_ASM_FIXPOINT_H */

View File

@@ -1,24 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_ASM_FIXPOINT_HPP
#define RGBDS_ASM_FIXPOINT_HPP
#include <stdint.h>
int32_t fix_Sin(int32_t i, int32_t q);
int32_t fix_Cos(int32_t i, int32_t q);
int32_t fix_Tan(int32_t i, int32_t q);
int32_t fix_ASin(int32_t i, int32_t q);
int32_t fix_ACos(int32_t i, int32_t q);
int32_t fix_ATan(int32_t i, int32_t q);
int32_t fix_ATan2(int32_t i, int32_t j, int32_t q);
int32_t fix_Mul(int32_t i, int32_t j, int32_t q);
int32_t fix_Mod(int32_t i, int32_t j, int32_t q);
int32_t fix_Div(int32_t i, int32_t j, int32_t q);
int32_t fix_Pow(int32_t i, int32_t j, int32_t q);
int32_t fix_Log(int32_t i, int32_t j, int32_t q);
int32_t fix_Round(int32_t i, int32_t q);
int32_t fix_Ceil(int32_t i, int32_t q);
int32_t fix_Floor(int32_t i, int32_t q);
#endif // RGBDS_ASM_FIXPOINT_HPP

63
include/asm/format.h Normal file
View File

@@ -0,0 +1,63 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2020, RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_FORMAT_SPEC_H
#define RGBDS_FORMAT_SPEC_H
#include <stdbool.h>
#include <stdint.h>
enum FormatState {
FORMAT_SIGN, // expects '+' or ' ' (optional)
FORMAT_PREFIX, // expects '#' (optional)
FORMAT_ALIGN, // expects '-' (optional)
FORMAT_WIDTH, // expects '0'-'9', max 255 (optional) (leading '0' indicates pad)
FORMAT_FRAC, // got '.', expects '0'-'9', max 255 (optional)
FORMAT_DONE, // got [duXxbofs] (required)
FORMAT_INVALID, // got unexpected character
};
struct FormatSpec {
enum FormatState state;
int sign;
bool prefix;
bool alignLeft;
bool padZero;
size_t width;
bool hasFrac;
size_t fracWidth;
int type;
bool valid;
};
struct StrFmtArg {
union {
uint32_t number;
char *string;
};
bool isNumeric;
};
#define INITIAL_STRFMT_ARG_SIZE 4
struct StrFmtArgList {
char *format;
size_t nbArgs;
size_t capacity;
struct StrFmtArg *args;
};
struct FormatSpec fmt_NewSpec(void);
bool fmt_IsEmpty(struct FormatSpec const *fmt);
bool fmt_IsValid(struct FormatSpec const *fmt);
bool fmt_IsFinished(struct FormatSpec const *fmt);
void fmt_UseCharacter(struct FormatSpec *fmt, int c);
void fmt_FinishCharacters(struct FormatSpec *fmt);
void fmt_PrintString(char *buf, size_t bufLen, struct FormatSpec const *fmt, char const *value);
void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uint32_t value);
#endif /* RGBDS_FORMAT_SPEC_H */

View File

@@ -1,33 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_ASM_FORMAT_HPP
#define RGBDS_ASM_FORMAT_HPP
#include <stddef.h>
#include <stdint.h>
#include <string>
class FormatSpec {
int sign;
bool exact;
bool alignLeft;
bool padZero;
size_t width;
bool hasFrac;
size_t fracWidth;
bool hasPrec;
size_t precision;
int type;
bool parsed;
public:
bool isValid() const { return !!type; }
bool isParsed() const { return parsed; }
size_t parseSpec(char const *spec);
void appendString(std::string &str, std::string const &value) const;
void appendNumber(std::string &str, uint32_t value) const;
};
#endif // RGBDS_ASM_FORMAT_HPP

83
include/asm/fstack.h Normal file
View File

@@ -0,0 +1,83 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
/*
* Contains some assembler-wide defines and externs
*/
#ifndef RGBDS_ASM_FSTACK_H
#define RGBDS_ASM_FSTACK_H
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "asm/lexer.h"
struct FileStackNode {
struct FileStackNode *parent; /* Pointer to parent node, for error reporting */
/* Line at which the parent context was exited; meaningless for the root level */
uint32_t lineNo;
struct FileStackNode *next; /* Next node in the output linked list */
bool referenced; /* If referenced, don't free! */
uint32_t ID; /* Set only if referenced: ID within the object file, -1 if not output yet */
enum {
NODE_REPT,
NODE_FILE,
NODE_MACRO,
} type;
};
struct FileStackReptNode { /* NODE_REPT */
struct FileStackNode node;
uint32_t reptDepth;
/* WARNING: if changing this type, change overflow check in `fstk_Init` */
uint32_t iters[]; /* REPT iteration counts since last named node, in reverse depth order */
};
struct FileStackNamedNode { /* NODE_FILE, NODE_MACRO */
struct FileStackNode node;
char name[]; /* File name for files, file::macro name for macros */
};
extern size_t maxRecursionDepth;
struct MacroArgs;
void fstk_Dump(struct FileStackNode const *node, uint32_t lineNo);
void fstk_DumpCurrent(void);
struct FileStackNode *fstk_GetFileStack(void);
/* The lifetime of the returned chars is until reaching the end of that file */
char const *fstk_GetFileName(void);
void fstk_AddIncludePath(char const *s);
/**
* @param path The user-provided file name
* @param fullPath The address of a pointer, which will be made to point at the full path
* The pointer's value must be a valid argument to `realloc`, including NULL
* @param size Current size of the buffer, or 0 if the pointer is NULL
* @return True if the file was found, false if no path worked
*/
bool fstk_FindFile(char const *path, char **fullPath, size_t *size);
bool yywrap(void);
void fstk_RunInclude(char const *path);
void fstk_RunMacro(char const *macroName, struct MacroArgs *args);
void fstk_RunRept(uint32_t count, int32_t reptLineNo, char *body, size_t size);
void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
int32_t reptLineNo, char *body, size_t size);
void fstk_StopRept(void);
bool fstk_Break(void);
void fstk_NewRecursionDepth(size_t newDepth);
void fstk_Init(char const *mainPath, size_t maxDepth);
#endif /* RGBDS_ASM_FSTACK_H */

View File

@@ -1,89 +0,0 @@
// SPDX-License-Identifier: MIT
// Contains some assembler-wide defines and externs
#ifndef RGBDS_ASM_FSTACK_HPP
#define RGBDS_ASM_FSTACK_HPP
#include <memory>
#include <optional>
#include <stdint.h>
#include <stdio.h>
#include <string>
#include <variant>
#include <vector>
#include "linkdefs.hpp"
#include "asm/lexer.hpp"
struct FileStackNode {
FileStackNodeType type;
std::variant<
std::vector<uint32_t>, // NODE_REPT
std::string // NODE_FILE, NODE_MACRO
>
data;
bool isQuiet; // Whether to omit this node from error reporting
std::shared_ptr<FileStackNode> parent; // Pointer to parent node, for error reporting
// Line at which the parent context was exited
// Meaningless at the root level, but gets written to the object file anyway, so init it
uint32_t lineNo = 0;
// Set only if referenced: ID within the object file, `UINT32_MAX` if not output yet
uint32_t ID = UINT32_MAX;
// REPT iteration counts since last named node, in reverse depth order
std::vector<uint32_t> &iters() { return std::get<std::vector<uint32_t>>(data); }
std::vector<uint32_t> const &iters() const { return std::get<std::vector<uint32_t>>(data); }
// File name for files, file::macro name for macros
std::string &name() { return std::get<std::string>(data); }
std::string const &name() const { return std::get<std::string>(data); }
FileStackNode(
FileStackNodeType type_,
std::variant<std::vector<uint32_t>, std::string> data_,
bool isQuiet_
)
: type(type_), data(data_), isQuiet(isQuiet_) {}
void printBacktrace(uint32_t curLineNo) const;
};
struct MacroArgs;
void fstk_VerboseOutputConfig();
void fstk_TraceCurrent();
std::shared_ptr<FileStackNode> fstk_GetFileStack();
std::shared_ptr<std::string> fstk_GetUniqueIDStr();
MacroArgs *fstk_GetCurrentMacroArgs();
void fstk_AddIncludePath(std::string const &path);
void fstk_AddPreIncludeFile(std::string const &path);
std::optional<std::string> fstk_FindFile(std::string const &path);
bool fstk_FileError(std::string const &path, char const *functionName);
bool fstk_FailedOnMissingInclude();
bool yywrap();
bool fstk_RunInclude(std::string const &path, bool isQuiet);
void fstk_RunMacro(
std::string const &macroName, std::shared_ptr<MacroArgs> macroArgs, bool isQuiet
);
void fstk_RunRept(uint32_t count, int32_t reptLineNo, ContentSpan const &span, bool isQuiet);
void fstk_RunFor(
std::string const &symName,
int32_t start,
int32_t stop,
int32_t step,
int32_t reptLineNo,
ContentSpan const &span,
bool isQuiet
);
bool fstk_Break();
void fstk_NewRecursionDepth(size_t newDepth);
void fstk_Init(std::string const &mainPath);
#endif // RGBDS_ASM_FSTACK_HPP

102
include/asm/lexer.h Normal file
View File

@@ -0,0 +1,102 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ASM_LEXER_H
#define RGBDS_ASM_LEXER_H
#include <stdbool.h>
#define MAXSTRLEN 255
struct LexerState;
extern struct LexerState *lexerState;
extern struct LexerState *lexerStateEOL;
static inline struct LexerState *lexer_GetState(void)
{
return lexerState;
}
static inline void lexer_SetState(struct LexerState *state)
{
lexerState = state;
}
static inline void lexer_SetStateAtEOL(struct LexerState *state)
{
lexerStateEOL = state;
}
extern char binDigits[2];
extern char gfxDigits[4];
static inline void lexer_SetBinDigits(char const digits[2])
{
binDigits[0] = digits[0];
binDigits[1] = digits[1];
}
static inline void lexer_SetGfxDigits(char const digits[4])
{
gfxDigits[0] = digits[0];
gfxDigits[1] = digits[1];
gfxDigits[2] = digits[2];
gfxDigits[3] = digits[3];
}
/*
* `path` is referenced, but not held onto..!
*/
struct LexerState *lexer_OpenFile(char const *path);
struct LexerState *lexer_OpenFileView(char const *path, char *buf, size_t size, uint32_t lineNo);
void lexer_RestartRept(uint32_t lineNo);
void lexer_DeleteState(struct LexerState *state);
void lexer_Init(void);
enum LexerMode {
LEXER_NORMAL,
LEXER_RAW,
LEXER_SKIP_TO_ELIF,
LEXER_SKIP_TO_ENDC,
LEXER_SKIP_TO_ENDR
};
void lexer_SetMode(enum LexerMode mode);
void lexer_ToggleStringExpansion(bool enable);
uint32_t lexer_GetIFDepth(void);
void lexer_IncIFDepth(void);
void lexer_DecIFDepth(void);
bool lexer_RanIFBlock(void);
bool lexer_ReachedELSEBlock(void);
void lexer_RunIFBlock(void);
void lexer_ReachELSEBlock(void);
struct CaptureBody {
uint32_t lineNo;
char *body;
size_t size;
};
void lexer_CheckRecursionDepth(void);
char const *lexer_GetFileName(void);
uint32_t lexer_GetLineNo(void);
uint32_t lexer_GetColNo(void);
void lexer_DumpStringExpansions(void);
int yylex(void);
bool lexer_CaptureRept(struct CaptureBody *capture);
bool lexer_CaptureMacroBody(struct CaptureBody *capture);
#define INITIAL_DS_ARG_SIZE 2
struct DsArgList {
size_t nbArgs;
size_t capacity;
struct Expression *args;
};
#endif /* RGBDS_ASM_LEXER_H */

View File

@@ -1,147 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_ASM_LEXER_HPP
#define RGBDS_ASM_LEXER_HPP
#include <deque>
#include <memory>
#include <optional>
#include <stddef.h>
#include <stdint.h>
#include <string>
#include <variant>
#include <vector>
#include "platform.hpp" // SSIZE_MAX
// This value is a compromise between `LexerState` allocation performance when reading the entire
// file works, and buffering performance when it doesn't (e.g. when piping a file into RGBASM).
static constexpr size_t LEXER_BUF_SIZE = 64;
// The buffer needs to be large enough for the maximum `lexerState->peek()` lookahead distance
static_assert(LEXER_BUF_SIZE > 1, "Lexer buffer size is too small");
// This caps the size of buffer reads, and according to POSIX, passing more than SSIZE_MAX is UB
static_assert(LEXER_BUF_SIZE <= SSIZE_MAX, "Lexer buffer size is too large");
enum LexerMode {
LEXER_NORMAL,
LEXER_RAW,
LEXER_SKIP_TO_ELIF,
LEXER_SKIP_TO_ENDC,
LEXER_SKIP_TO_ENDR,
NB_LEXER_MODES
};
struct Expansion {
std::optional<std::string> name;
std::shared_ptr<std::string> contents;
size_t offset; // Cursor into `contents`
size_t size() const { return contents->size(); }
bool advance(); // Increment `offset`; return whether it then exceeds `contents`
};
struct ContentSpan {
std::shared_ptr<char[]> ptr;
size_t size;
};
struct ViewedContent {
ContentSpan span; // Span of chars
size_t offset = 0; // Cursor into `span.ptr`
ViewedContent(ContentSpan const &span_) : span(span_) {}
ViewedContent(std::shared_ptr<char[]> ptr, size_t size) : span({.ptr = ptr, .size = size}) {}
std::shared_ptr<char[]> makeSharedContentPtr() const {
return std::shared_ptr<char[]>(span.ptr, &span.ptr[offset]);
}
};
struct BufferedContent {
int fd; // File from which to read chars
char buf[LEXER_BUF_SIZE] = {}; // Circular buffer of chars
size_t offset = 0; // Cursor into `buf`
size_t size = 0; // Number of "fresh" chars in `buf`
BufferedContent(int fd_) : fd(fd_) {}
~BufferedContent();
void advance(); // Increment `offset` circularly, decrement `size`
void refill(); // Read from `fd` to fill `buf`
private:
size_t readMore(size_t startIndex, size_t nbChars);
};
struct IfStackEntry {
bool ranIfBlock; // Whether an IF/ELIF/ELSE block ran already
bool reachedElseBlock; // Whether an ELSE block ran already
};
struct LexerState {
std::string path;
LexerMode mode;
bool atLineStart;
uint32_t lineNo;
int lastToken;
int nextToken;
std::deque<IfStackEntry> ifStack;
bool capturing; // Whether the text being lexed should be captured
size_t captureSize; // Amount of text captured
std::shared_ptr<std::vector<char>> captureBuf; // Buffer to send the captured text to if set
bool disableExpansions;
size_t expansionScanDistance; // Max distance already scanned for expansions
bool expandStrings;
std::deque<Expansion> expansions; // Front is the innermost current expansion
std::variant<std::monostate, ViewedContent, BufferedContent> content;
~LexerState();
int peekChar();
int peekCharAhead();
std::shared_ptr<char[]> makeSharedCaptureBufPtr() const {
return std::shared_ptr<char[]>(captureBuf, captureBuf->data());
}
void setAsCurrentState();
void setFileAsNextState(std::string const &filePath, bool updateStateNow);
void setViewAsNextState(char const *name, ContentSpan const &span, uint32_t lineNo_);
void clear(uint32_t lineNo_);
};
void lexer_SetBinDigits(char const digits[2]);
void lexer_SetGfxDigits(char const digits[4]);
bool lexer_AtTopLevel();
void lexer_RestartRept(uint32_t lineNo);
void lexer_SetMode(LexerMode mode);
void lexer_ToggleStringExpansion(bool enable);
uint32_t lexer_GetIFDepth();
void lexer_IncIFDepth();
void lexer_DecIFDepth();
bool lexer_RanIFBlock();
bool lexer_ReachedELSEBlock();
void lexer_RunIFBlock();
void lexer_ReachELSEBlock();
void lexer_CheckRecursionDepth();
uint32_t lexer_GetLineNo();
void lexer_TraceStringExpansions();
struct Capture {
uint32_t lineNo;
ContentSpan span;
};
Capture lexer_CaptureRept();
Capture lexer_CaptureMacro();
#endif // RGBDS_ASM_LEXER_HPP

37
include/asm/macro.h Normal file
View File

@@ -0,0 +1,37 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2020, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_MACRO_H
#define RGBDS_MACRO_H
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "asm/warning.h"
#include "helpers.h"
struct MacroArgs;
struct MacroArgs *macro_GetCurrentArgs(void);
struct MacroArgs *macro_NewArgs(void);
void macro_AppendArg(struct MacroArgs **args, char *s);
void macro_UseNewArgs(struct MacroArgs *args);
void macro_FreeArgs(struct MacroArgs *args);
char const *macro_GetArg(uint32_t i);
char const *macro_GetAllArgs(void);
uint32_t macro_GetUniqueID(void);
char const *macro_GetUniqueIDStr(void);
void macro_SetUniqueID(uint32_t id);
uint32_t macro_UseNewUniqueID(void);
void macro_ShiftCurrentArgs(int32_t count);
uint32_t macro_NbArgs(void);
#endif

View File

@@ -1,23 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_ASM_MACRO_HPP
#define RGBDS_ASM_MACRO_HPP
#include <memory>
#include <stdint.h>
#include <string>
#include <vector>
struct MacroArgs {
uint32_t shift;
std::vector<std::shared_ptr<std::string>> args;
uint32_t nbArgs() const { return args.size() - shift; }
std::shared_ptr<std::string> getArg(int32_t i) const;
std::shared_ptr<std::string> getAllArgs() const;
void appendArg(std::shared_ptr<std::string> arg);
void shiftArgs(int32_t count);
};
#endif // RGBDS_ASM_MACRO_HPP

29
include/asm/main.h Normal file
View File

@@ -0,0 +1,29 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2021, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_MAIN_H
#define RGBDS_MAIN_H
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "helpers.h"
extern bool haltnop;
extern bool optimizeLoads;
extern bool verbose;
extern bool warnings; /* True to enable warnings, false to disable them. */
extern FILE *dependfile;
extern char *targetFileName;
extern bool generatedMissingIncludes;
extern bool failedOnMissingInclude;
extern bool generatePhonyDeps;
#endif /* RGBDS_MAIN_H */

View File

@@ -1,46 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_ASM_MAIN_HPP
#define RGBDS_ASM_MAIN_HPP
#include <optional>
#include <stdint.h>
#include <stdio.h>
#include <string>
enum MissingInclude {
INC_ERROR, // A missing included file is an error that halts assembly
GEN_EXIT, // A missing included file is assumed to be generated; exit normally
GEN_CONTINUE, // A missing included file is assumed to be generated; continue assembling
};
struct Options {
bool exportAll = false; // -E
uint8_t fixPrecision = 16; // -Q
size_t maxRecursionDepth = 64; // -r
char binDigits[2] = {'0', '1'}; // -b
char gfxDigits[4] = {'0', '1', '2', '3'}; // -g
FILE *dependFile = nullptr; // -M
std::optional<std::string> targetFileName{}; // -MQ, -MT
MissingInclude missingIncludeState = INC_ERROR; // -MC, -MG
bool generatePhonyDeps = false; // -MP
std::optional<std::string> objectFileName{}; // -o
uint8_t padByte = 0; // -p
uint64_t maxErrors = 0; // -X
~Options() {
if (dependFile) {
fclose(dependFile);
}
}
void printDep(std::string const &depName) {
if (dependFile) {
fprintf(dependFile, "%s: %s\n", targetFileName->c_str(), depName.c_str());
}
}
};
extern Options options;
#endif // RGBDS_ASM_MAIN_HPP

25
include/asm/opt.h Normal file
View File

@@ -0,0 +1,25 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2021, Eldred Habert and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_OPT_H
#define RGBDS_OPT_H
#include <stdbool.h>
#include <stdint.h>
void opt_B(char const chars[2]);
void opt_G(char const chars[4]);
void opt_P(uint8_t fill);
void opt_L(bool optimize);
void opt_W(char const *flag);
void opt_Parse(char const *option);
void opt_Push(void);
void opt_Pop(void);
#endif

View File

@@ -1,19 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_ASM_OPT_HPP
#define RGBDS_ASM_OPT_HPP
#include <stdint.h>
void opt_B(char const binDigits[2]);
void opt_G(char const gfxDigits[4]);
void opt_P(uint8_t padByte);
void opt_Q(uint8_t fixPrecision);
void opt_W(char const *flag);
void opt_Parse(char const *option);
void opt_Push();
void opt_Pop();
void opt_CheckStack();
#endif // RGBDS_ASM_OPT_HPP

30
include/asm/output.h Normal file
View File

@@ -0,0 +1,30 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ASM_OUTPUT_H
#define RGBDS_ASM_OUTPUT_H
#include <stdint.h>
#include "linkdefs.h"
struct Expression;
struct FileStackNode;
extern char *objectName;
extern struct Section *sectionList;
void out_RegisterNode(struct FileStackNode *node);
void out_ReplaceNode(struct FileStackNode *node);
void out_SetFileName(char *s);
void out_CreatePatch(uint32_t type, struct Expression const *expr, uint32_t ofs, uint32_t pcShift);
bool out_CreateAssert(enum AssertionType type, struct Expression const *expr,
char const *message, uint32_t ofs);
void out_WriteObject(void);
#endif /* RGBDS_ASM_OUTPUT_H */

View File

@@ -1,28 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_ASM_OUTPUT_HPP
#define RGBDS_ASM_OUTPUT_HPP
#include <memory>
#include <stdint.h>
#include <string>
#include <vector>
#include "linkdefs.hpp"
struct Expression;
struct FileStackNode;
struct Symbol;
enum StateFeature { STATE_EQU, STATE_VAR, STATE_EQUS, STATE_CHAR, STATE_MACRO, NB_STATE_FEATURES };
void out_RegisterNode(std::shared_ptr<FileStackNode> node);
void out_RegisterSymbol(Symbol &sym);
void out_CreatePatch(uint32_t type, Expression const &expr, uint32_t ofs, uint32_t pcShift);
void out_CreateAssert(
AssertionType type, Expression const &expr, std::string const &message, uint32_t ofs
);
void out_WriteObject();
void out_WriteState(std::string name, std::vector<StateFeature> const &features);
#endif // RGBDS_ASM_OUTPUT_HPP

70
include/asm/rpn.h Normal file
View File

@@ -0,0 +1,70 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ASM_RPN_H
#define RGBDS_ASM_RPN_H
#include <stdint.h>
#include <stdbool.h>
#include "linkdefs.h"
#define MAXRPNLEN 1048576
struct Expression {
int32_t val; // If the expression's value is known, it's here
char *reason; // Why the expression is not known, if it isn't
bool isKnown; // Whether the expression's value is known
bool isSymbol; // Whether the expression represents a symbol
uint8_t *rpn; // Array of bytes serializing the RPN expression
uint32_t rpnCapacity; // Size of the `rpn` buffer
uint32_t rpnLength; // Used size of the `rpn` buffer
uint32_t rpnPatchSize; // Size the expression will take in the object file
};
/*
* Determines if an expression is known at assembly time
*/
static inline bool rpn_isKnown(struct Expression const *expr)
{
return expr->isKnown;
}
/*
* Determines if an expression is a symbol suitable for const diffing
*/
static inline bool rpn_isSymbol(const struct Expression *expr)
{
return expr->isSymbol;
}
void rpn_Symbol(struct Expression *expr, char const *symName);
void rpn_Number(struct Expression *expr, uint32_t i);
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src);
struct Symbol const *rpn_SymbolOf(struct Expression const *expr);
bool rpn_IsDiffConstant(struct Expression const *src, struct Symbol const *symName);
void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
const struct Expression *src1,
const struct Expression *src2);
void rpn_HIGH(struct Expression *expr, const struct Expression *src);
void rpn_LOW(struct Expression *expr, const struct Expression *src);
void rpn_ISCONST(struct Expression *expr, const struct Expression *src);
void rpn_UNNEG(struct Expression *expr, const struct Expression *src);
void rpn_UNNOT(struct Expression *expr, const struct Expression *src);
void rpn_BankSymbol(struct Expression *expr, char const *symName);
void rpn_BankSection(struct Expression *expr, char const *sectionName);
void rpn_BankSelf(struct Expression *expr);
void rpn_SizeOfSection(struct Expression *expr, char const *sectionName);
void rpn_StartOfSection(struct Expression *expr, char const *sectionName);
void rpn_Free(struct Expression *expr);
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src);
void rpn_CheckRST(struct Expression *expr, const struct Expression *src);
void rpn_CheckNBit(struct Expression const *expr, uint8_t n);
int32_t rpn_GetConstVal(struct Expression const *expr);
#endif /* RGBDS_ASM_RPN_H */

View File

@@ -1,64 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_ASM_RPN_HPP
#define RGBDS_ASM_RPN_HPP
#include <stdint.h>
#include <string>
#include <variant>
#include <vector>
#include "linkdefs.hpp"
struct Symbol;
struct RPNValue {
RPNCommand command; // The RPN_* command ID
std::variant<std::monostate, uint8_t, uint32_t, std::string> data; // Data after the ID, if any
RPNValue(RPNCommand cmd);
RPNValue(RPNCommand cmd, uint8_t val);
RPNValue(RPNCommand cmd, uint32_t val);
RPNValue(RPNCommand cmd, std::string const &name);
void appendEncoded(std::vector<uint8_t> &buffer) const;
};
struct Expression {
std::variant<
int32_t, // If the expression's value is known, it's here
std::string // Why the expression is not known, if it isn't
>
data = 0;
std::vector<RPNValue> rpn{}; // Values to be serialized into the RPN expression
bool isKnown() const { return std::holds_alternative<int32_t>(data); }
int32_t value() const { return std::get<int32_t>(data); }
int32_t getConstVal() const;
Symbol const *symbolOf() const;
bool isDiffConstant(Symbol const *symName) const;
void makeNumber(uint32_t value);
void makeSymbol(std::string const &symName);
void makeBankSymbol(std::string const &symName);
void makeBankSection(std::string const &sectName);
void makeSizeOfSection(std::string const &sectName);
void makeStartOfSection(std::string const &sectName);
void makeSizeOfSectionType(SectionType type);
void makeStartOfSectionType(SectionType type);
void makeUnaryOp(RPNCommand op, Expression &&src);
void makeBinaryOp(RPNCommand op, Expression &&src1, Expression const &src2);
void addCheckHRAM();
void addCheckRST();
void addCheckBitIndex(uint8_t mask);
void checkNBit(uint8_t n) const;
void encode(std::vector<uint8_t> &buffer) const;
};
bool checkNBit(int32_t v, uint8_t n, char const *name);
#endif // RGBDS_ASM_RPN_HPP

82
include/asm/section.h Normal file
View File

@@ -0,0 +1,82 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2020, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_SECTION_H
#define RGBDS_SECTION_H
#include <stdint.h>
#include <stdbool.h>
#include "linkdefs.h"
#include "platform.h" // NONNULL
extern uint8_t fillByte;
struct Expression;
struct Section {
char *name;
enum SectionType type;
enum SectionModifier modifier;
struct FileStackNode *src; /* Where the section was defined */
uint32_t fileLine; /* Line where the section was defined */
uint32_t size;
uint32_t org;
uint32_t bank;
uint8_t align; // Exactly as specified in `ALIGN[]`
uint16_t alignOfs;
struct Section *next;
struct Patch *patches;
uint8_t *data;
};
struct SectionSpec {
uint32_t bank;
uint8_t alignment;
uint16_t alignOfs;
};
extern struct Section *currentSection;
struct Section *sect_FindSectionByName(char const *name);
void sect_NewSection(char const *name, uint32_t secttype, uint32_t org,
struct SectionSpec const *attributes, enum SectionModifier mod);
void sect_SetLoadSection(char const *name, uint32_t secttype, uint32_t org,
struct SectionSpec const *attributes, enum SectionModifier mod);
void sect_EndLoadSection(void);
struct Section *sect_GetSymbolSection(void);
uint32_t sect_GetSymbolOffset(void);
uint32_t sect_GetOutputOffset(void);
void sect_AlignPC(uint8_t alignment, uint16_t offset);
void sect_StartUnion(void);
void sect_NextUnionMember(void);
void sect_EndUnion(void);
void sect_CheckUnionClosed(void);
void sect_AbsByte(uint8_t b);
void sect_AbsByteGroup(uint8_t const *s, size_t length);
void sect_AbsWordGroup(uint8_t const *s, size_t length);
void sect_AbsLongGroup(uint8_t const *s, size_t length);
void sect_Skip(uint32_t skip, bool ds);
void sect_String(char const *s);
void sect_RelByte(struct Expression *expr, uint32_t pcShift);
void sect_RelBytes(uint32_t n, struct Expression *exprs, size_t size);
void sect_RelWord(struct Expression *expr, uint32_t pcShift);
void sect_RelLong(struct Expression *expr, uint32_t pcShift);
void sect_PCRelByte(struct Expression *expr, uint32_t pcShift);
void sect_BinaryFile(char const *s, int32_t startPos);
void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length);
void sect_PushSection(void);
void sect_PopSection(void);
bool sect_IsSizeKnown(struct Section const NONNULL(name));
#endif

View File

@@ -1,112 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_ASM_SECTION_HPP
#define RGBDS_ASM_SECTION_HPP
#include <deque>
#include <memory>
#include <optional>
#include <stddef.h>
#include <stdint.h>
#include <string>
#include <vector>
#include "linkdefs.hpp"
struct Expression;
struct FileStackNode;
struct Section;
struct Patch {
std::shared_ptr<FileStackNode> src;
uint32_t lineNo;
uint32_t offset;
Section *pcSection;
uint32_t pcOffset;
uint8_t type;
std::vector<uint8_t> rpn;
};
struct Section {
std::string name;
SectionType type;
SectionModifier modifier;
std::shared_ptr<FileStackNode> src; // Where the section was defined
uint32_t fileLine; // Line where the section was defined
uint32_t size;
uint32_t org;
uint32_t bank;
uint8_t align; // Exactly as specified in `ALIGN[]`
uint16_t alignOfs;
std::deque<Patch> patches;
std::vector<uint8_t> data;
uint32_t getID() const; // ID of the section in the object file (`UINT32_MAX` if none)
bool isSizeKnown() const;
};
struct SectionSpec {
uint32_t bank;
uint8_t alignment;
uint16_t alignOfs;
};
size_t sect_CountSections();
void sect_ForEach(void (*callback)(Section &));
Section *sect_FindSectionByName(std::string const &name);
void sect_NewSection(
std::string const &name,
SectionType type,
uint32_t org,
SectionSpec const &attrs,
SectionModifier mod
);
void sect_SetLoadSection(
std::string const &name,
SectionType type,
uint32_t org,
SectionSpec const &attrs,
SectionModifier mod
);
void sect_EndLoadSection(char const *cause);
void sect_CheckLoadClosed();
Section *sect_GetSymbolSection();
uint32_t sect_GetSymbolOffset();
uint32_t sect_GetOutputOffset();
std::optional<uint32_t> sect_GetOutputBank();
Patch *sect_AddOutputPatch();
uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset);
void sect_AlignPC(uint8_t alignment, uint16_t offset);
void sect_CheckSizes();
void sect_StartUnion();
void sect_NextUnionMember();
void sect_EndUnion();
void sect_CheckUnionClosed();
void sect_ConstByte(uint8_t byte);
void sect_ByteString(std::vector<int32_t> const &str);
void sect_WordString(std::vector<int32_t> const &str);
void sect_LongString(std::vector<int32_t> const &str);
void sect_Skip(uint32_t skip, bool ds);
void sect_RelByte(Expression const &expr, uint32_t pcShift);
void sect_RelBytes(uint32_t n, std::vector<Expression> const &exprs);
void sect_RelWord(Expression const &expr, uint32_t pcShift);
void sect_RelLong(Expression const &expr, uint32_t pcShift);
void sect_PCRelByte(Expression const &expr, uint32_t pcShift);
bool sect_BinaryFile(std::string const &name, uint32_t startPos);
bool sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t length);
void sect_EndSection();
void sect_PushSection();
void sect_PopSection();
void sect_CheckStack();
std::string sect_PushSectionFragmentLiteral();
#endif // RGBDS_ASM_SECTION_HPP

150
include/asm/symbol.h Normal file
View File

@@ -0,0 +1,150 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2020, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_SYMBOL_H
#define RGBDS_SYMBOL_H
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include "asm/section.h"
#include "platform.h" // MIN_NB_ELMS
#define MAXSYMLEN 255
enum SymbolType {
SYM_LABEL,
SYM_EQU,
SYM_VAR,
SYM_MACRO,
SYM_EQUS,
SYM_REF // Forward reference to a label
};
struct Symbol {
char name[MAXSYMLEN + 1];
enum SymbolType type;
bool isExported; /* Whether the symbol is to be exported */
bool isBuiltin; /* Whether the symbol is a built-in */
struct Section *section;
struct FileStackNode *src; /* Where the symbol was defined */
uint32_t fileLine; /* Line where the symbol was defined */
bool hasCallback;
union {
/* If sym_IsNumeric */
int32_t value;
int32_t (*numCallback)(void);
/* For SYM_MACRO and SYM_EQUS; TODO: have separate fields */
struct {
size_t macroSize;
char *macro;
};
/* For SYM_EQUS */
char const *(*strCallback)(void);
};
uint32_t ID; /* ID of the symbol in the object file (-1 if none) */
struct Symbol *next; /* Next object to output in the object file */
};
bool sym_IsPC(struct Symbol const *sym);
static inline bool sym_IsDefined(struct Symbol const *sym)
{
return sym->type != SYM_REF;
}
static inline struct Section *sym_GetSection(struct Symbol const *sym)
{
return sym_IsPC(sym) ? sect_GetSymbolSection() : sym->section;
}
static inline bool sym_IsConstant(struct Symbol const *sym)
{
if (sym->type == SYM_LABEL) {
struct Section const *sect = sym_GetSection(sym);
return sect && sect->org != (uint32_t)-1;
}
return sym->type == SYM_EQU || sym->type == SYM_VAR;
}
static inline bool sym_IsNumeric(struct Symbol const *sym)
{
return sym->type == SYM_LABEL || sym->type == SYM_EQU || sym->type == SYM_VAR;
}
static inline bool sym_IsLabel(struct Symbol const *sym)
{
return sym->type == SYM_LABEL || sym->type == SYM_REF;
}
static inline bool sym_IsLocal(struct Symbol const *sym)
{
return sym_IsLabel(sym) && strchr(sym->name, '.');
}
static inline bool sym_IsExported(struct Symbol const *sym)
{
return sym->isExported;
}
/*
* Get a string equate's value
*/
static inline char const *sym_GetStringValue(struct Symbol const *sym)
{
if (sym->hasCallback)
return sym->strCallback();
return sym->macro;
}
void sym_ForEach(void (*func)(struct Symbol *, void *), void *arg);
int32_t sym_GetValue(struct Symbol const *sym);
void sym_SetExportAll(bool set);
struct Symbol *sym_AddLocalLabel(char const *symName);
struct Symbol *sym_AddLabel(char const *symName);
struct Symbol *sym_AddAnonLabel(void);
void sym_WriteAnonLabelName(char buf[MIN_NB_ELMS(MAXSYMLEN + 1)], uint32_t ofs, bool neg);
void sym_Export(char const *symName);
struct Symbol *sym_AddEqu(char const *symName, int32_t value);
struct Symbol *sym_RedefEqu(char const *symName, int32_t value);
struct Symbol *sym_AddVar(char const *symName, int32_t value);
uint32_t sym_GetPCValue(void);
uint32_t sym_GetConstantSymValue(struct Symbol const *sym);
uint32_t sym_GetConstantValue(char const *symName);
/*
* Find a symbol by exact name, bypassing expansion checks
*/
struct Symbol *sym_FindExactSymbol(char const *symName);
/*
* Find a symbol by exact name; may not be scoped, produces an error if it is
*/
struct Symbol *sym_FindUnscopedSymbol(char const *symName);
/*
* Find a symbol, possibly scoped, by name
*/
struct Symbol *sym_FindScopedSymbol(char const *symName);
struct Symbol const *sym_GetPC(void);
struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size);
struct Symbol *sym_Ref(char const *symName);
struct Symbol *sym_AddString(char const *symName, char const *value);
struct Symbol *sym_RedefString(char const *symName, char const *value);
void sym_Purge(char const *symName);
void sym_Init(time_t now);
/* Functions to save and restore the current symbol scope. */
char const *sym_GetCurrentSymbolScope(void);
void sym_SetCurrentSymbolScope(char const *newScope);
#endif /* RGBDS_SYMBOL_H */

View File

@@ -1,106 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_ASM_SYMBOL_HPP
#define RGBDS_ASM_SYMBOL_HPP
#include <memory>
#include <stdint.h>
#include <string>
#include <time.h>
#include <utility>
#include <variant>
#include "asm/lexer.hpp"
#include "asm/section.hpp"
enum SymbolType {
SYM_LABEL,
SYM_EQU,
SYM_VAR,
SYM_MACRO,
SYM_EQUS,
SYM_REF // Forward reference to a label
};
struct Symbol; // Forward declaration for `sym_IsPC`
bool sym_IsPC(Symbol const *sym); // Forward declaration for `getSection`
struct Symbol {
std::string name;
SymbolType type;
bool isBuiltin;
bool isExported; // Not relevant for SYM_MACRO or SYM_EQUS
bool isQuiet; // Only relevant for SYM_MACRO
Section *section;
std::shared_ptr<FileStackNode> src; // Where the symbol was defined
uint32_t fileLine; // Line where the symbol was defined
std::variant<
int32_t, // If isNumeric()
int32_t (*)(), // If isNumeric() via a callback
ContentSpan, // For SYM_MACRO
std::shared_ptr<std::string>, // For SYM_EQUS
std::shared_ptr<std::string> (*)() // For SYM_EQUS via a callback
>
data;
uint32_t ID; // ID of the symbol in the object file (`UINT32_MAX` if none)
uint32_t defIndex; // Ordering of the symbol in the state file
bool isDefined() const { return type != SYM_REF; }
bool isNumeric() const { return type == SYM_LABEL || type == SYM_EQU || type == SYM_VAR; }
bool isLabel() const { return type == SYM_LABEL || type == SYM_REF; }
bool isConstant() const {
if (type == SYM_LABEL) {
Section const *sect = getSection();
return sect && sect->org != UINT32_MAX;
}
return type == SYM_EQU || type == SYM_VAR;
}
Section *getSection() const { return sym_IsPC(this) ? sect_GetSymbolSection() : section; }
int32_t getValue() const;
int32_t getOutputValue() const;
ContentSpan const &getMacro() const;
std::shared_ptr<std::string> getEqus() const;
uint32_t getConstantValue() const;
};
void sym_ForEach(void (*callback)(Symbol &));
Symbol *sym_AddLocalLabel(std::string const &symName);
Symbol *sym_AddLabel(std::string const &symName);
Symbol *sym_AddAnonLabel();
std::string sym_MakeAnonLabelName(uint32_t ofs, bool neg);
void sym_Export(std::string const &symName);
Symbol *sym_AddEqu(std::string const &symName, int32_t value);
Symbol *sym_RedefEqu(std::string const &symName, int32_t value);
Symbol *sym_AddVar(std::string const &symName, int32_t value);
int32_t sym_GetRSValue();
void sym_SetRSValue(int32_t value);
// Find a symbol by exact name, bypassing expansion checks
Symbol *sym_FindExactSymbol(std::string const &symName);
// Find a symbol, possibly scoped, by name
Symbol *sym_FindScopedSymbol(std::string const &symName);
// Find a scoped symbol by name; do not return `@` or `_NARG` when they have no value
Symbol *sym_FindScopedValidSymbol(std::string const &symName);
Symbol const *sym_GetPC();
Symbol *sym_AddMacro(
std::string const &symName, int32_t defLineNo, ContentSpan const &span, bool isQuiet
);
Symbol *sym_Ref(std::string const &symName);
Symbol *sym_AddString(std::string const &symName, std::shared_ptr<std::string> value);
Symbol *sym_RedefString(std::string const &symName, std::shared_ptr<std::string> value);
void sym_Purge(std::string const &symName);
bool sym_IsPurgedExact(std::string const &symName);
bool sym_IsPurgedScoped(std::string const &symName);
void sym_Init(time_t now);
// Functions to save and restore the current label scopes.
std::pair<Symbol const *, Symbol const *> sym_GetCurrentLabelScopes();
void sym_SetCurrentLabelScopes(std::pair<Symbol const *, Symbol const *> newScopes);
void sym_ResetCurrentLabelScopes();
#endif // RGBDS_ASM_SYMBOL_HPP

21
include/asm/util.h Normal file
View File

@@ -0,0 +1,21 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_UTIL_H
#define RGBDS_UTIL_H
#include <stdint.h>
char const *printChar(int c);
/*
* @return The number of bytes read, or 0 if invalid data was found
*/
size_t readUTF8Char(uint8_t *dest, char const *src);
#endif /* RGBDS_UTIL_H */

93
include/asm/warning.h Normal file
View File

@@ -0,0 +1,93 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2019, Eldred Habert and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef WARNING_H
#define WARNING_H
#include "helpers.h"
extern unsigned int nbErrors;
enum WarningState {
WARNING_DEFAULT,
WARNING_DISABLED,
WARNING_ENABLED,
WARNING_ERROR
};
enum WarningID {
WARNING_ASSERT, // Assertions
WARNING_BACKWARDS_FOR, // `for` loop with backwards range
WARNING_BUILTIN_ARG, // Invalid args to builtins
WARNING_CHARMAP_REDEF, // Charmap entry re-definition
WARNING_DIV, // Division undefined behavior
WARNING_EMPTY_DATA_DIRECTIVE, // `db`, `dw` or `dl` directive without data in ROM
WARNING_EMPTY_MACRO_ARG, // Empty macro argument
WARNING_EMPTY_STRRPL, // Empty second argument in `STRRPL`
WARNING_LARGE_CONSTANT, // Constants too large
WARNING_LONG_STR, // String too long for internal buffers
WARNING_MACRO_SHIFT, // Shift past available arguments in macro
WARNING_NESTED_COMMENT, // Comment-start delimiter in a block comment
WARNING_OBSOLETE, // Obsolete things
WARNING_SHIFT, // Shifting undefined behavior
WARNING_SHIFT_AMOUNT, // Strange shift amount
WARNING_USER, // User warnings
NB_PLAIN_WARNINGS,
// Warnings past this point are "parametric" warnings, only mapping to a single flag
#define PARAM_WARNINGS_START NB_PLAIN_WARNINGS
// Treating string as number may lose some bits
WARNING_NUMERIC_STRING_1 = PARAM_WARNINGS_START,
WARNING_NUMERIC_STRING_2,
// Implicit truncation loses some bits
WARNING_TRUNCATION_1,
WARNING_TRUNCATION_2,
NB_PLAIN_AND_PARAM_WARNINGS,
#define NB_PARAM_WARNINGS (NB_PLAIN_AND_PARAM_WARNINGS - PARAM_WARNINGS_START)
// Warnings past this point are "meta" warnings
#define META_WARNINGS_START NB_PLAIN_AND_PARAM_WARNINGS
WARNING_ALL = META_WARNINGS_START,
WARNING_EXTRA,
WARNING_EVERYTHING,
NB_WARNINGS,
#define NB_META_WARNINGS (NB_WARNINGS - META_WARNINGS_START)
};
extern enum WarningState warningStates[NB_PLAIN_AND_PARAM_WARNINGS];
extern bool warningsAreErrors;
void processWarningFlag(char *flag);
/*
* Used to warn the user about problems that don't prevent the generation of
* valid code.
*/
void warning(enum WarningID id, char const *fmt, ...) format_(printf, 2, 3);
/*
* Used for errors that compromise the whole assembly process by affecting the
* following code, potencially making the assembler generate errors caused by
* the first one and unrelated to the code that the assembler complains about.
* It is also used when the assembler goes into an invalid state (for example,
* when it fails to allocate memory).
*/
_Noreturn void fatalerror(char const *fmt, ...) format_(printf, 1, 2);
/*
* Used for errors that make it impossible to assemble correctly, but don't
* affect the following code. The code will fail to assemble but the user will
* get a list of all errors at the end, making it easier to fix all of them at
* once.
*/
void error(char const *fmt, ...) format_(printf, 1, 2);
#endif

View File

@@ -1,85 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_ASM_WARNING_HPP
#define RGBDS_ASM_WARNING_HPP
#include <functional>
#include "diagnostics.hpp"
enum WarningLevel {
LEVEL_DEFAULT, // Warnings that are enabled by default
LEVEL_ALL, // Warnings that probably indicate an error
LEVEL_EXTRA, // Warnings that are less likely to indicate an error
LEVEL_EVERYTHING, // Literally every warning
};
enum WarningID {
WARNING_ASSERT, // Assertions
WARNING_BACKWARDS_FOR, // `FOR` loop with backwards range
WARNING_BUILTIN_ARG, // Invalid args to builtins
WARNING_CHARMAP_REDEF, // Charmap entry re-definition
WARNING_DIV, // Undefined division behavior
WARNING_EMPTY_DATA_DIRECTIVE, // `db`, `dw` or `dl` directive without data in ROM
WARNING_EMPTY_MACRO_ARG, // Empty macro argument
WARNING_EMPTY_STRRPL, // Empty second argument in `STRRPL`
WARNING_EXPORT_UNDEFINED, // `EXPORT` of an undefined symbol
WARNING_LARGE_CONSTANT, // Constants too large
WARNING_MACRO_SHIFT, // `SHIFT` past available arguments in macro
WARNING_NESTED_COMMENT, // Comment-start delimiter in a block comment
WARNING_OBSOLETE, // Obsolete/deprecated things
WARNING_SHIFT, // Undefined `SHIFT` behavior
WARNING_SHIFT_AMOUNT, // Strange `SHIFT` amount
WARNING_UNMATCHED_DIRECTIVE, // `PUSH[C|O|S]` without `POP[C|O|S]`
WARNING_UNTERMINATED_LOAD, // `LOAD` without `ENDL`
WARNING_USER, // User-defined `WARN`ings
NB_PLAIN_WARNINGS,
// Warnings past this point are "parametric" warnings, only mapping to a single flag
// Treating string as number may lose some bits
WARNING_NUMERIC_STRING_1 = NB_PLAIN_WARNINGS,
WARNING_NUMERIC_STRING_2,
// Purging an exported symbol or label
WARNING_PURGE_1,
WARNING_PURGE_2,
// Implicit truncation loses some bits
WARNING_TRUNCATION_1,
WARNING_TRUNCATION_2,
// Character without charmap entry
WARNING_UNMAPPED_CHAR_1,
WARNING_UNMAPPED_CHAR_2,
NB_WARNINGS,
};
extern Diagnostics<WarningLevel, WarningID> warnings;
// Used to warn the user about problems that don't prevent the generation of
// valid code.
[[gnu::format(printf, 2, 3)]]
void warning(WarningID id, char const *fmt, ...);
// Used for errors that compromise the whole assembly process by affecting the
// following code, potencially making the assembler generate errors caused by
// the first one and unrelated to the code that the assembler complains about.
// It is also used when the assembler goes into an invalid state (for example,
// when it fails to allocate memory).
[[gnu::format(printf, 1, 2), noreturn]]
void fatal(char const *fmt, ...);
// Used for errors that make it impossible to assemble correctly, but don't
// affect the following code. The code will fail to assemble but the user will
// get a list of all errors at the end, making it easier to fix all of them at
// once.
[[gnu::format(printf, 1, 2)]]
void error(char const *fmt, ...);
// Used for errors that handle their own backtrace output. The code will fail
// to assemble but the user will get a list of all errors at the end, making it
// easier to fix all of them at once.
void errorNoTrace(std::function<void()> callback);
void requireZeroErrors();
#endif // RGBDS_ASM_WARNING_HPP

View File

@@ -1,89 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_BACKTRACE_HPP
#define RGBDS_BACKTRACE_HPP
#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <vector>
#include "style.hpp"
#define TRACE_SEPARATOR "<-"
#define NODE_SEPARATOR "::"
#define REPT_NODE_PREFIX "REPT~"
struct Tracing {
uint64_t depth = 0;
bool collapse = false;
bool loud = false;
};
extern Tracing tracing;
bool trace_ParseTraceDepth(char const *arg);
template<typename NodeT, typename NameFnT, typename LineNoFnT>
void trace_PrintBacktrace(std::vector<NodeT> const &stack, NameFnT getName, LineNoFnT getLineNo) {
size_t n = stack.size();
if (n == 0) {
return; // LCOV_EXCL_LINE
}
auto printLocation = [&](size_t i) {
NodeT const &item = stack[n - i - 1];
style_Reset(stderr);
if (!tracing.collapse) {
fputs(" ", stderr); // Just three spaces; the fourth will be printed next
}
fprintf(stderr, " %s ", i == 0 ? "at" : TRACE_SEPARATOR);
style_Set(stderr, STYLE_CYAN, true);
fputs(getName(item), stderr);
style_Set(stderr, STYLE_CYAN, false);
fprintf(stderr, "(%" PRIu32 ")", getLineNo(item));
if (!tracing.collapse) {
putc('\n', stderr);
}
};
if (tracing.collapse) {
fputs(" ", stderr); // Just three spaces; the fourth will be handled by the loop
}
if (tracing.depth == 0 || static_cast<size_t>(tracing.depth) >= n) {
for (size_t i = 0; i < n; ++i) {
printLocation(i);
}
} else {
size_t last = tracing.depth / 2;
size_t first = tracing.depth - last;
size_t skipped = n - tracing.depth;
for (size_t i = 0; i < first; ++i) {
printLocation(i);
}
style_Reset(stderr);
if (tracing.collapse) {
fputs(" " TRACE_SEPARATOR, stderr);
} else {
fputs(" ", stderr); // Just three spaces; the fourth will be printed next
}
fprintf(stderr, " ...%zu more%s", skipped, last ? "..." : "");
if (!tracing.collapse) {
putc('\n', stderr);
}
for (size_t i = n - last; i < n; ++i) {
printLocation(i);
}
}
if (tracing.collapse) {
putc('\n', stderr);
}
style_Reset(stderr);
}
#endif // RGBDS_BACKTRACE_HPP

View File

@@ -1,21 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_CLI_HPP
#define RGBDS_CLI_HPP
#include <stdarg.h>
#include <string>
#include "extern/getopt.hpp" // option
#include "usage.hpp"
void cli_ParseArgs(
int argc,
char *argv[],
char const *shortOpts,
option const *longOpts,
void (*parseArg)(int, char *),
Usage usage
);
#endif // RGBDS_CLI_HPP

View File

@@ -1,211 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_DIAGNOSTICS_HPP
#define RGBDS_DIAGNOSTICS_HPP
#include <inttypes.h>
#include <optional>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <utility>
#include <vector>
#include "helpers.hpp"
#include "itertools.hpp"
[[gnu::format(printf, 1, 2)]]
void warnx(char const *fmt, ...);
enum WarningAbled { WARNING_DEFAULT, WARNING_ENABLED, WARNING_DISABLED };
struct WarningState {
WarningAbled state;
WarningAbled error;
void update(WarningState other);
};
std::pair<WarningState, std::optional<uint32_t>> getInitialWarningState(std::string &flag);
template<typename LevelEnumT>
struct WarningFlag {
char const *name;
LevelEnumT level;
};
enum WarningBehavior { DISABLED, ENABLED, ERROR };
template<typename WarningEnumT>
struct ParamWarning {
WarningEnumT firstID;
WarningEnumT lastID;
uint8_t defaultLevel;
};
template<typename WarningEnumT>
struct DiagnosticsState {
WarningState flagStates[WarningEnumT::NB_WARNINGS];
WarningState metaStates[WarningEnumT::NB_WARNINGS];
bool warningsEnabled = true;
bool warningsAreErrors = false;
};
template<typename LevelEnumT, typename WarningEnumT>
struct Diagnostics {
std::vector<WarningFlag<LevelEnumT>> metaWarnings;
std::vector<WarningFlag<LevelEnumT>> warningFlags;
std::vector<ParamWarning<WarningEnumT>> paramWarnings;
DiagnosticsState<WarningEnumT> state;
uint64_t nbErrors;
void incrementErrors() {
if (nbErrors != UINT64_MAX) {
++nbErrors;
}
}
WarningBehavior getWarningBehavior(WarningEnumT id) const;
void processWarningFlag(char const *flag);
};
template<typename LevelEnumT, typename WarningEnumT>
WarningBehavior Diagnostics<LevelEnumT, WarningEnumT>::getWarningBehavior(WarningEnumT id) const {
// Check if warnings are globally disabled
if (!state.warningsEnabled) {
return WarningBehavior::DISABLED;
}
// Get the state of this warning flag
WarningState const &flagState = state.flagStates[id];
WarningState const &metaState = state.metaStates[id];
// If subsequent checks determine that the warning flag is enabled, this checks whether it has
// -Werror without -Wno-error=<flag> or -Wno-error=<meta>, which makes it into an error
bool warningIsError = state.warningsAreErrors && flagState.error != WARNING_DISABLED
&& metaState.error != WARNING_DISABLED;
WarningBehavior enabledBehavior =
warningIsError ? WarningBehavior::ERROR : WarningBehavior::ENABLED;
// First, check the state of the specific warning flag
if (flagState.state == WARNING_DISABLED) { // -Wno-<flag>
return WarningBehavior::DISABLED;
}
if (flagState.error == WARNING_ENABLED) { // -Werror=<flag>
return WarningBehavior::ERROR;
}
if (flagState.state == WARNING_ENABLED) { // -W<flag>
return enabledBehavior;
}
// If no flag is specified, check the state of the "meta" flags that affect this warning flag
if (metaState.state == WARNING_DISABLED) { // -Wno-<meta>
return WarningBehavior::DISABLED;
}
if (metaState.error == WARNING_ENABLED) { // -Werror=<meta>
return WarningBehavior::ERROR;
}
if (metaState.state == WARNING_ENABLED) { // -W<meta>
return enabledBehavior;
}
// If no meta flag is specified, check the default state of this warning flag
if (warningFlags[id].level == LevelEnumT::LEVEL_DEFAULT) { // enabled by default
return enabledBehavior;
}
// No flag enables this warning, explicitly or implicitly
return WarningBehavior::DISABLED;
}
template<typename LevelEnumT, typename WarningEnumT>
void Diagnostics<LevelEnumT, WarningEnumT>::processWarningFlag(char const *flag) {
std::string rootFlag = flag;
// Check for `-Werror` or `-Wno-error` to return early
if (rootFlag == "error") {
// `-Werror` promotes warnings to errors
state.warningsAreErrors = true;
return;
} else if (rootFlag == "no-error") {
// `-Wno-error` disables promotion of warnings to errors
state.warningsAreErrors = false;
return;
}
auto [flagState, param] = getInitialWarningState(rootFlag);
// Try to match the flag against a parametric warning
// If there was an equals sign, it will have set `param`; if not, `param` will be 0,
// which applies to all levels
for (ParamWarning<WarningEnumT> const &paramWarning : paramWarnings) {
WarningEnumT baseID = paramWarning.firstID;
uint8_t maxParam = paramWarning.lastID - baseID + 1;
assume(paramWarning.defaultLevel <= maxParam);
if (rootFlag != warningFlags[baseID].name) {
continue;
}
// If making the warning an error but param is 0, set to the maximum
// This accommodates `-Werror=<flag>`, but also `-Werror=<flag>=0`, which is
// thus filtered out by the caller.
// A param of 0 makes sense for disabling everything, but neither for
// enabling nor "erroring". Use the default for those.
if (!param.has_value() || *param == 0) {
param = paramWarning.defaultLevel;
} else if (*param > maxParam) {
warnx(
"Invalid warning flag parameter \"%s=%" PRIu32 "\"; capping at maximum %" PRIu8,
rootFlag.c_str(),
*param,
maxParam
);
*param = maxParam;
}
// Set the first <param> to enabled/error, and disable the rest
for (uint32_t ofs = 0; ofs < maxParam; ++ofs) {
if (WarningState &warning = state.flagStates[baseID + ofs]; ofs < *param) {
warning.update(flagState);
} else {
warning.state = WARNING_DISABLED;
}
}
return;
}
if (param.has_value()) {
warnx("Unknown warning flag parameter \"%s=%" PRIu32 "\"", rootFlag.c_str(), *param);
return;
}
// Try to match against a "meta" warning
for (WarningFlag<LevelEnumT> const &metaWarning : metaWarnings) {
if (rootFlag != metaWarning.name) {
continue;
}
// Set each of the warning flags that meets this level
for (WarningEnumT id : EnumSeq(WarningEnumT::NB_WARNINGS)) {
if (metaWarning.level >= warningFlags[id].level) {
state.metaStates[id].update(flagState);
}
}
return;
}
// Try to match against a "normal" flag
for (WarningEnumT id : EnumSeq(WarningEnumT::NB_PLAIN_WARNINGS)) {
if (rootFlag == warningFlags[id].name) {
state.flagStates[id].update(flagState);
return;
}
}
warnx("Unknown warning flag \"%s\"", rootFlag.c_str());
}
#endif // RGBDS_DIAGNOSTICS_HPP

21
include/error.h Normal file
View File

@@ -0,0 +1,21 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2021, RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ERROR_H
#define RGBDS_ERROR_H
#include "helpers.h"
#include "platform.h"
void warn(char const NONNULL(fmt), ...) format_(printf, 1, 2);
void warnx(char const NONNULL(fmt), ...) format_(printf, 1, 2);
_Noreturn void err(char const NONNULL(fmt), ...) format_(printf, 1, 2);
_Noreturn void errx(char const NONNULL(fmt), ...) format_(printf, 1, 2);
#endif /* RGBDS_ERROR_H */

46
include/extern/getopt.h vendored Normal file
View File

@@ -0,0 +1,46 @@
/*
* Copyright © 2005-2020 Rich Felker, et al.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* This implementation was taken from musl and modified for RGBDS */
#ifndef RGBDS_EXTERN_GETOPT_H
#define RGBDS_EXTERN_GETOPT_H
extern char *musl_optarg;
extern int musl_optind, musl_opterr, musl_optopt, musl_optreset;
struct option {
char const *name;
int has_arg;
int *flag;
int val;
};
int musl_getopt_long_only(int argc, char **argv, char const *optstring,
const struct option *longopts, int *idx);
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#endif

View File

@@ -1,26 +0,0 @@
// SPDX-License-Identifier: MIT
// This implementation was taken from musl and modified for RGBDS
#ifndef RGBDS_EXTERN_GETOPT_HPP
#define RGBDS_EXTERN_GETOPT_HPP
// clang-format off: vertically align values
static constexpr int no_argument = 0;
static constexpr int required_argument = 1;
static constexpr int optional_argument = 2;
// clang-format on
extern char *musl_optarg;
extern int musl_optind, musl_optopt;
struct option {
char const *name;
int has_arg;
int *flag;
int val;
};
int musl_getopt_long_only(int argc, char **argv, char const *optstring, option const *longopts);
#endif // RGBDS_EXTERN_GETOPT_HPP

14
include/extern/utf8decoder.h vendored Normal file
View File

@@ -0,0 +1,14 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2018, Antonio Nino Diaz and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef EXTERN_UTF8DECODER_H
#define EXTERN_UTF8DECODER_H
uint32_t decode(uint32_t *state, uint32_t *codep, uint8_t byte);
#endif /* EXTERN_UTF8DECODER_H */

View File

@@ -1,13 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_EXTERN_UTF8DECODER_HPP
#define RGBDS_EXTERN_UTF8DECODER_HPP
#include <stdint.h>
#define UTF8_ACCEPT 0
#define UTF8_REJECT 12
uint32_t decode(uint32_t *state, uint32_t *codep, uint8_t byte);
#endif // RGBDS_EXTERN_UTF8DECODER_HPP

View File

@@ -1,61 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_FILE_HPP
#define RGBDS_FILE_HPP
#include <fcntl.h>
#include <fstream>
#include <ios>
#include <iostream>
#include <streambuf>
#include <string>
#include <variant>
#include "helpers.hpp" // assume
#include "platform.hpp"
class File {
std::variant<std::streambuf *, std::filebuf> _file;
public:
File() : _file(nullptr) {}
// This should only be called once, and before doing any `->` operations.
// Returns `nullptr` on error, and a non-null pointer otherwise.
File *open(std::string const &path, std::ios_base::openmode mode) {
if (path != "-") {
return _file.emplace<std::filebuf>().open(path, mode) ? this : nullptr;
} else if (mode & std::ios_base::in) {
assume(!(mode & std::ios_base::out));
_file.emplace<std::streambuf *>(std::cin.rdbuf());
if (setmode(STDIN_FILENO, (mode & std::ios_base::binary) ? O_BINARY : O_TEXT) == -1) {
return nullptr;
}
} else {
assume(mode & std::ios_base::out);
_file.emplace<std::streambuf *>(std::cout.rdbuf());
}
return this;
}
std::streambuf &operator*() {
return std::holds_alternative<std::filebuf>(_file) ? std::get<std::filebuf>(_file)
: *std::get<std::streambuf *>(_file);
}
std::streambuf const &operator*() const {
// The non-`const` version does not perform any modifications, so it's okay.
return **const_cast<File *>(this);
}
std::streambuf *operator->() { return &**this; }
std::streambuf const *operator->() const {
// See the `operator*` equivalent.
return const_cast<File *>(this)->operator->();
}
char const *c_str(std::string const &path) const {
return std::holds_alternative<std::filebuf>(_file) ? path.c_str()
: std::get<std::streambuf *>(_file) == std::cin.rdbuf() ? "<stdin>"
: "<stdout>";
}
};
#endif // RGBDS_FILE_HPP

View File

@@ -1,8 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_FIX_FIX_HPP
#define RGBDS_FIX_FIX_HPP
bool fix_ProcessFile(char const *name, char const *outputName);
#endif // RGBDS_FIX_FIX_HPP

View File

@@ -1,51 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_FIX_MAIN_HPP
#define RGBDS_FIX_MAIN_HPP
#include <optional>
#include <stdint.h>
#include <string>
#include "fix/mbc.hpp" // UNSPECIFIED, MbcType
// clang-format off: vertically align values
static constexpr uint8_t FIX_LOGO = 1 << 7;
static constexpr uint8_t TRASH_LOGO = 1 << 6;
static constexpr uint8_t FIX_HEADER_SUM = 1 << 5;
static constexpr uint8_t TRASH_HEADER_SUM = 1 << 4;
static constexpr uint8_t FIX_GLOBAL_SUM = 1 << 3;
static constexpr uint8_t TRASH_GLOBAL_SUM = 1 << 2;
// clang-format on
enum Model { DMG, BOTH, CGB };
struct Options {
uint8_t fixSpec = 0; // -f, -v
Model model = DMG; // -C, -c
bool japanese = true; // -j
uint16_t oldLicensee = UNSPECIFIED; // -l
uint16_t romVersion = UNSPECIFIED; // -n
uint16_t padValue = UNSPECIFIED; // -p
uint16_t ramSize = UNSPECIFIED; // -r
bool sgb = false; // -s
std::optional<std::string> gameID; // -i
uint8_t gameIDLen;
std::optional<std::string> newLicensee; // -k
uint8_t newLicenseeLen;
std::optional<std::string> logoFilename; // -L
uint8_t logo[48] = {};
MbcType cartridgeType = MBC_NONE; // -m
uint8_t tpp1Rev[2];
std::optional<std::string> title; // -t
uint8_t titleLen;
};
extern Options options;
#endif // RGBDS_FIX_MAIN_HPP

View File

@@ -1,79 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_FIX_MBC_HPP
#define RGBDS_FIX_MBC_HPP
#include <stdint.h>
#include <stdio.h>
constexpr uint16_t UNSPECIFIED = 0x200;
static_assert(UNSPECIFIED > 0xFF, "UNSPECIFIED should not be in byte range!");
enum MbcType {
ROM = 0x00,
ROM_RAM = 0x08,
ROM_RAM_BATTERY = 0x09,
MBC1 = 0x01,
MBC1_RAM = 0x02,
MBC1_RAM_BATTERY = 0x03,
MBC2 = 0x05,
MBC2_BATTERY = 0x06,
MMM01 = 0x0B,
MMM01_RAM = 0x0C,
MMM01_RAM_BATTERY = 0x0D,
MBC3 = 0x11,
MBC3_TIMER_BATTERY = 0x0F,
MBC3_TIMER_RAM_BATTERY = 0x10,
MBC3_RAM = 0x12,
MBC3_RAM_BATTERY = 0x13,
MBC5 = 0x19,
MBC5_RAM = 0x1A,
MBC5_RAM_BATTERY = 0x1B,
MBC5_RUMBLE = 0x1C,
MBC5_RUMBLE_RAM = 0x1D,
MBC5_RUMBLE_RAM_BATTERY = 0x1E,
MBC6 = 0x20,
MBC7_SENSOR_RUMBLE_RAM_BATTERY = 0x22,
POCKET_CAMERA = 0xFC,
BANDAI_TAMA5 = 0xFD,
HUC3 = 0xFE,
HUC1_RAM_BATTERY = 0xFF,
// "Extended" values (still valid, but not directly actionable)
// A high byte of 0x01 means TPP1, the low byte is the requested features
// This does not include SRAM, which is instead implied by a non-zero SRAM size
// Note: Multiple rumble speeds imply rumble
TPP1 = 0x100,
TPP1_RUMBLE = 0x101,
TPP1_MULTIRUMBLE_RUMBLE = 0x103,
TPP1_TIMER = 0x104,
TPP1_TIMER_RUMBLE = 0x105,
TPP1_TIMER_MULTIRUMBLE_RUMBLE = 0x107,
TPP1_BATTERY = 0x108,
TPP1_BATTERY_RUMBLE = 0x109,
TPP1_BATTERY_MULTIRUMBLE_RUMBLE = 0x10B,
TPP1_BATTERY_TIMER = 0x10C,
TPP1_BATTERY_TIMER_RUMBLE = 0x10D,
TPP1_BATTERY_TIMER_MULTIRUMBLE_RUMBLE = 0x10F,
// Error values
MBC_NONE = UNSPECIFIED, // No MBC specified, do not act on it
};
bool mbc_HasRAM(MbcType type);
char const *mbc_Name(MbcType type);
MbcType mbc_ParseName(char const *name, uint8_t &tpp1Major, uint8_t &tpp1Minor);
#endif // RGBDS_FIX_MBC_HPP

View File

@@ -1,44 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_FIX_WARNING_HPP
#define RGBDS_FIX_WARNING_HPP
#include <stdint.h>
#include "diagnostics.hpp"
enum WarningLevel {
LEVEL_DEFAULT, // Warnings that are enabled by default
LEVEL_ALL, // Warnings that probably indicate an error
LEVEL_EVERYTHING, // Literally every warning
};
enum WarningID {
WARNING_MBC, // Issues with MBC specs
WARNING_OBSOLETE, // Obsolete/deprecated things
WARNING_OVERWRITE, // Overwriting non-zero bytes
WARNING_SGB, // SGB flag conflicts with old licensee code
WARNING_TRUNCATION, // Truncating values to fit
NB_PLAIN_WARNINGS,
NB_WARNINGS = NB_PLAIN_WARNINGS,
};
extern Diagnostics<WarningLevel, WarningID> warnings;
// Warns the user about problems that don't prevent fixing the ROM header
[[gnu::format(printf, 2, 3)]]
void warning(WarningID id, char const *fmt, ...);
// Prints an error, and increments the error count
[[gnu::format(printf, 1, 2)]]
void error(char const *fmt, ...);
// Prints an error, and exits with failure
[[gnu::format(printf, 1, 2), noreturn]]
void fatal(char const *fmt, ...);
uint32_t checkErrors(char const *filename);
#endif // RGBDS_FIX_WARNING_HPP

View File

@@ -1,38 +0,0 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_GFX_COLOR_SET_HPP
#define RGBDS_GFX_COLOR_SET_HPP
#include <array>
#include <stddef.h>
#include <stdint.h>
class ColorSet {
public:
static constexpr size_t capacity = 4;
private:
// Up to 4 colors, sorted, and where SIZE_MAX means the slot is empty
// (OK because it's not a valid color index)
// Sorting is done on the raw numerical values to lessen `compare`'s complexity
std::array<uint16_t, capacity> _colorIndices{UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX};
public:
// Adds the specified color to the set, or **silently drops it** if the set is full.
void add(uint16_t color);
enum ComparisonResult {
NEITHER,
WE_BIGGER,
THEY_BIGGER = -1,
};
ComparisonResult compare(ColorSet const &other) const;
size_t size() const;
bool empty() const;
decltype(_colorIndices)::const_iterator begin() const;
decltype(_colorIndices)::const_iterator end() const;
};
#endif // RGBDS_GFX_COLOR_SET_HPP

Some files were not shown because too many files have changed in this diff Show More