commit 3eee14d4bda6b65799fd3c7cf1f94e163f207bb0 Author: Zack Buhman Date: Thu Aug 7 10:52:53 2025 -0500 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3bcd9ee --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.aux +*.log +*.toc +*.out +.#* +_minted/ +*.pdf diff --git a/book.tex b/book.tex new file mode 100644 index 0000000..1fefe82 --- /dev/null +++ b/book.tex @@ -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{} 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}