Dreamcast low-level dev.
Contents
Introduction
The Dreamcast can be a challenging target for codegolfing, the
SH-4 CPU is a
traditional RISC to the core with 16-bit instruction size, this is
good for codegolfing but being RISC and without the "hacks" of
similar RISC CPU such as ARM (barrel shifter) there is constraints
such as :
- MOV only supports an 8-bit immediate; loading constants may
pass by a load operation or tricks
- you cannot shift by arbitrary constant amount
- delay
slot
- available
addressing modes may be annoying although not so horrible for
RISC
All these constraints are somehow balanced by the 16-bit
instruction size but some of these can still become a pain for
codegolfing...
The good stuff for codegolfing is relative to the amount of
available registers and instructions such as the floating-point
instructions (2-way superscalar architecture, SIMD), there is also
no headers. (unless you count the IP.BIN boot program or image file
as header)
How to run old intros
There is some
256b and
128b for Dreamcast but they don't run anymore on the emulators
i tried, to run them you may have to use official BIOS file and
change VIDEO_RAM (and also VIDEO_BASE) constant to 0xa5200000
instead of 0xa5000000 then assemble. (see setup below)
The reason is that the Dreamcast BootROM sets video
framebuffer base to 0xa5200000 (a 2MB offset from base VRAM), the
2MB below is reserved for a copy of the BootROM to pass bootup
checks, it is likely that this wasn't emulated at the time of these
intros or that the framebuffer base was already changed to
0xa5000000 due to the method by which they ran. Modifying the
framebuffer base to be 0xa5000000 after boot is expected so that
all the VRAM is available without fragmentation, this can be safely
ignored for code golfing purposes though.
It is not a perfect solution anyway to run these intros
because they will run in a tiny area of the screen after this fix,
this might be due to the intro being made for a different video
mode... didn't look yet but what i know is that after boot the
display mode is 640*480 ARGB8888, this might depend on BIOS /
video connection type though (cable type in Redream) which was set
to RGB for my test.
The alternative to run the original code of these intros is to
setup the framebuffer start address and a video mode, this is much
bigger obviously, it can be done by looking at
dreamhal videos mode setup.
Documentation
-
dreamhal hardware abstraction library is a good quick starting
resource (C code)
- SH4 manual and hardware documentation can be found here
- memory
map
- Dreamcast Dev/Box manual can be also useful
- Raymond Chen articles on the SuperH-3 is incredibly useful as a starting point (and apply to SH-4), giving many hints and tricks
- making games for the Dreamcast using standard GNU tools
- Dreamcast
documentation and source code for bare metal coding
Setup (on LINUX)
Here is a guide to setup a Dreamcast development environment,
note that i was only interested in running SH4 assembly code for
raw graphics stuff so i didn't test anything else :
Emulators
- Redream seems accurate so i use this, there is also Reicast which works fine
Toolchain
I basically followed
this guide up to building KOS examples to build the toolchain
on my machine.
Build may fail due to unavailable GNU mirror, this can be
easily fixed by using another one by editing the file
scripts/download.mk.
The steps i added afterward to be able to build images so the
program can be run on the Dreamcast is related to compiling
mkdcdisc tool
:
sudo apt install git meson build-essential pkg-config libisofs-dev
git clone https://gitlab.com/simulant/mkdcdisc /opt/toolchains/dc/mkdcdisc
cd /opt/toolchains/dc/mkdcdisc
CC=gcc-13 CXX=g++-13 meson setup builddir
note : you might have to replace gcc and g++ version, i used this because mine were old and compilation failedCC=gcc-13 CXX=g++-13 meson compile -C builddir
Assembly and running
your program
/opt/toolchains/dc/sh-elf/bin/sh-elf-as
-little test.s -o test.o
/opt/toolchains/dc/sh-elf/bin/sh-elf-ld --oformat elf32-shl -Ttext
0x8c010000 test.o -o test.elf
/opt/toolchains/dc/mkdcdisc/builddir/mkdcdisc -e test.elf -o
test.cdi -n "my test disc"
Then you can just call either reicast or redream with the .cdi
file as input on the command-line.
Note that you may need the original BIOS file. (emulator
provided one didn't work for me so i use a 1998 v1.01d EU
BIOS)
Note : There is also the old way (without mkdcdisc) with
mkisofs and cdi4dc tools detailed here.
cdi4dc tool can be downloaded here for Linux and you will
need to generate a valid IP.BIN file as well for this process,
makeip
is able to do that.
Assembly build shell script
Here is a shell script to assemble a .s, build the .cdi and
run it with redream, pass the .s filename without the extension to
assemble your code (may want to change redream path as well), it
will also output a raw .bin and output the disassembly :
#!/bin/sh
set -eu
/opt/toolchains/dc/sh-elf/bin/sh-elf-as -little $1.s -o $1.o
/opt/toolchains/dc/sh-elf/bin/sh-elf-ld --oformat elf32-shl -Ttext
0x8c010000 $1.o -o $1.elf
/opt/toolchains/dc/mkdcdisc/builddir/mkdcdisc -v 3 -e $1.elf -o
$1.cdi -n "" -m
/opt/toolchains/dc/sh-elf/bin/sh-elf-objcopy -R .stack -O binary
$1.elf $1.bin
/opt/toolchains/dc/sh-elf/bin/sh-elf-objdump -m sh4 -EL -b binary
--adjust-vma=0x8c010000 -D $1.bin
wc -c $1.bin
~/redream.x86_64-linux-v1.5.0-1106-g01ef607/redream
$1.cdi
The raw binary size is already shown without
wc (as hexadecimal) but i added this call so that it is
shown as decimal.
Old versions of mkdcdisc doesn't clean the
/tmp directory so might be preferable to check
mkdcdisc output to delete the temporary directory that
mkdcdisc generate, note that newer versions now clean the
temporary files except when the command is interrupted, some CD
sized data might still stay in /tmp and fill the drive so
might be worth to check out...
This command list the huge temporary files that
mkdcdisc might generate (-delete can be added to
remove them) :
cd /tmp && find .
-maxdepth 2 -name '0.0'
SH-4 basic template for pixels write after boot
This code clear the screen and plot a white centered pixel
right after boot, the video mode after boot is
640*480 ARGB8888 but might depend on BIOS / video connection
type ? (cable type in Redream), mine was set to RGB here.
(composite and VGA also works though)
Note that accessing VRAM directly is slow on the Dreamcast but
is handy for raw stuff !
mov.l VIDEO_BASE,r0
mov #0,r1
mov.l CLRCOUNT,r2
clr:
mov.l r1,@r0
dt r2
bf/s clr
add #4,r0
bra main
nop
.align 2
CLRCOUNT: .long 640*480
main:
mov #-1,r1 ! color; ARGB8888
mov.l CENTERED_PIXEL_ADDR,r0
mov.l r1,@r0
bra main
nop
.align 2
VIDEO_BASE: .long 0xa5200000
CENTERED_PIXEL_ADDR: .long 0xa5200000 + (320 +
(240 * 640)) * 4
As a small "trick" you can use r0 to reuse the VIDEO_BASE with
indexed register indirect addressing mode :
...
mov.l VIDEO_BASE,r0
main:
mov #-1,r2
mov.l CENTERED_PIXEL_ADDR,r1
mov.l r2,@(r0,r1)
bra main
nop
.align 2
VIDEO_BASE: .long 0xa5200000
CENTERED_PIXEL_ADDR: .long (320 + (340 * 640)) *
4
back to top