This commit is contained in:
Zack Buhman 2025-08-07 10:52:53 -05:00
commit 3eee14d4bd
2 changed files with 247 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
*.aux
*.log
*.toc
*.out
.#*
_minted/
*.pdf

240
book.tex Normal file
View File

@ -0,0 +1,240 @@
\documentclass{report}
\usepackage{hyperref}
%\usepackage{dirtytalk}
\usepackage{scrextend}
\usepackage{graphicx}
%\usepackage{wrapfig}
\usepackage{minted}
\usepackage[svgnames]{xcolor}
\usepackage[T1]{fontenc}
\usepackage{inconsolata}
\title{Dreamcast from scratch the hard way}
\hypersetup{colorlinks=true,urlcolor=blue}
\begin{document}
\maketitle
\tableofcontents
\chapter{Motivation}
\begin{listing}[H]
\begin{minted}[bgcolor=Beige, bgcolorpadding=0.5em]{C}
int main() {
printf("hello, world");
return 0;
}
\end{minted}
\caption{Example of a listing.}
\label{lst:example}
\end{listing}
\chapter{Toolchain}
This section shows how to build and install a toolchain for compiling C and C++
source code to SH4 (Dreamcast) binaries.
\section{Toolchain download}
Download and extract source archives for Binutils and GCC; this could be done for example like this:
\begin{listing}[H]
\begin{minted}[bgcolor=Beige, bgcolorpadding=0.5em]{shell}
cd ~
curl -LO https://ftp.gnu.org/gnu/binutils/binutils-2.45.tar.xz
curl -LO https://ftp.gnu.org/gnu/gcc/gcc-15.1.0/gcc-15.1.0.tar.xz
tar xJf binutils-2.45.tar.xz
tar xJf gcc-15.1.0.tar.xz
\end{minted}
\caption{Toolchain download and extract}
\label{lst:toolchain-download-extract}
\end{listing}
\section{Binutils configuration}
The binutils configuration script is easy to invoke. The only option needed is:
\begin{minted}[bgcolor=Beige, bgcolorpadding=0.5em]{shell}
--target=sh4-none-elf
\end{minted}
The \texttt{target} option causes the binutils build system to create a
cross-assembler\footnote{assuming you aren't running binutils on a computer that
also contains an SH4 CPU} that is capable of generating code for the SH4
(Dreamcast) CPU. This also causes all installed commands to be prefixed with
\texttt{sh4-none-elf-}, for example: \texttt{sh4-none-elf-ld} for the binutils
linker.
These ``target triples'' are underdocumented.
While nearly any \texttt{sh*-*-*} triplet would have worked, a secondary goal of
choosing this specific triplet is to not conflict with the name chosen for the
KallistiOS toolchain, \texttt{sh-elf}.
The complete configure command is:
\begin{listing}[H]
\begin{minted}[bgcolor=Beige, bgcolorpadding=0.5em]{shell}
mkdir ~/binutils-2.45/build
cd ~/binutils-2.45/build
../configure --target=sh4-none-elf
\end{minted}
\caption{Binutils configure}
\label{lst:binutils-configure}
\end{listing}
\section{Binutils build and install}
Build and install binutils with:
\begin{listing}[H]
\begin{minted}[bgcolor=Beige, bgcolorpadding=0.5em]{shell}
cd ~/binutils-2.45/build
make -j$(nproc)
make install
\end{minted}
\caption{Binutils build and install}
\label{lst:binutils-build-install}
\end{listing}
You may need to prefix the \texttt{make install} command with \texttt{sudo} or
\texttt{su} depending on your system.
Note that binutils must be installed correctly prior to proceeding. You can test
this by running the command \texttt{sh4-none-elf-ld -v}. If
\texttt{sh4-none-elf} binutils is properly installed, you will get output
identical to:
\begin{minted}[bgcolor=Beige, bgcolorpadding=0.5em]{shell}
GNU ld (GNU Binutils) 2.45
\end{minted}
\section{GCC configuration}
The GCC we will build in particular will have no support for linking with
a C standard library. In Dreamcast game development, the C standard library
isn't particularly useful (e.g: string manipulation functions are hardly used).
Anything we do need that we could have used from the C standard library we will
reimplement ourselves.
While it is obvious that the GCC developers don't support this use-case as well
as they could, the only problem occurs when GCC automatically emits a call to
\texttt{memcpy} or \texttt{memzero} in code that did not explicitly call either.
Most of the time, such calls can be removed by changing optimization levels or
refactoring code. In other cases, it may be situationally convenient to
implement either as trivial one-line loops.
To compile gcc, invoke the \texttt{./configure} script with the appropriate
options. Here are explanations for a few of the more interesting options:
\begin{minted}[bgcolor=Beige, bgcolorpadding=0.5em]{shell}
--with-endian=little
\end{minted}
The SH4 CPU in the Dreamcast is jumpered to little endian mode, and CPU
endianness is not reconfigurable without physical modification.
\begin{minted}[bgcolor=Beige, bgcolorpadding=0.5em]{shell}
--with-cpu=m4-single
\end{minted}
\texttt{m4-single} is a floating point calling convention where functions assume
the SH4 CPU is in ``single precision'' mode on function entry. In this ABI,
functions that use double precision operations require extra instructions (and
CPU cycles) to switch to double precision mode on function entry, and switch
back to single precision mode prior to function return.
\begin{minted}[bgcolor=Beige, bgcolorpadding=0.5em]{shell}
--disable-hosted-libstdcxx
\end{minted}
This disables all libstdcxx features that depend on exceptions and heap
allocation. For example, \texttt{<list>} and \texttt{<vector>} are not
available, but \texttt{<bit>} and \texttt{<type\_traits>} are available.
The cppreference.com article on
\href{https://en.cppreference.com/w/cpp/freestanding.html}{freestanding} has
more information on which features are (not) available with a freestanding
libstdc++ build.
The complete configure command is:
\begin{listing}[H]
\begin{minted}[bgcolor=Beige, bgcolorpadding=0.5em]{shell}
mkdir ~/gcc-15.1.0/build
cd ~/gcc-15.1.0/build
../configure \
--target=sh4-none-elf \
--with-endian=little \
--with-cpu=m4-single \
--without-newlib \
--without-headers \
--disable-nls \
--disable-shared \
--disable-multilib \
--disable-decimal-float \
--disable-threads \
--disable-libatomic \
--disable-libgomp \
--disable-libquadmath \
--disable-libssp \
--disable-libvtv \
--disable-hosted-libstdcxx \
--disable-libstdcxx-pch \
--disable-libstdcxx-verbose \
--disable-libstdcxx-filesystem-ts \
--disable-libstdcxx-threads \
--disable-libstdcxx-backtrace \
--enable-languages=c,c++ \
--disable-bootstrap
\end{minted}
\caption{GCC configure}
\label{lst:gcc-configure}
\end{listing}
\section{GCC build and install}
Build and install gcc with:
\begin{listing}[H]
\begin{minted}[bgcolor=Beige, bgcolorpadding=0.5em]{shell}
cd ~/gcc-15.1.0/build
make -j$(nproc)
make install
\end{minted}
\caption{GCC build and install}
\label{lst:gcc-build-install}
\end{listing}
You will notice that the time required to build GCC is significantly longer than
the time required to build binutils.
You may need to prefix the \texttt{make install} command with \texttt{sudo} or
\texttt{su} depending on your system.
If installed correctly, you should be able to run the \texttt{sh4-none-elf-gcc -v}
command, which should produce output identical to:
\begin{minted}[bgcolor=Beige, bgcolorpadding=0.5em, breaklines, breakanywhere]{text}
Using built-in specs.
COLLECT_GCC=sh4-none-elf-gcc
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/sh4-none-elf/15.1.0/lto-wrapper
Target: sh4-none-elf
Configured with: ../configure --target=sh4-none-elf --with-endian=little --with-cpu=m4-single --without-newlib --without-headers --disable-nls --disable-shared --disable-multilib --disable-decimal-float --disable-threads --disable-libatomic --disable-libgomp --disable-libquadmath --disable-libssp --disable-libvtv --disable-hosted-libstdcxx --disable-libstdcxx-pch --disable-libstdcxx-verbose --disable-libstdcxx-filesystem-ts --disable-libstdcxx-threads --disable-libstdcxx-backtrace --enable-languages=c,c++ --disable-bootstrap
Thread model: single
Supported LTO compression algorithms: zlib zstd
gcc version 15.1.0 (GCC)
\end{minted}
\chapter{Dreamcast hardware registers}
\section{An absolute minimal demo}
The objective of this section is to get code running on Dreamcast while avoiding
as much boilerplate as possible.
\end{document}