\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{} and \texttt{} are not available, but \texttt{} and \texttt{} 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}