Home
Admin | Edit

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 :
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 change VIDEO_RAM (and also VIDEO_BASE) constant to 0xa5200000 instead of 0xa5000000 and assemble them. (see setup below)

This is due to the state of the PowerVR graphics engine after boot which is set to this address on original BIOS, it was probably unneeded at the time of these intros due to the state of Dreamcast emulation.

This is not a perfect solution though because the intros will run in a tiny area of the screen, 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 RGB565, this might depend on video connection type though which was set to VGA for my test.

The alternative is to change the framebuffer start address and setup a video mode, this is much bigger obviously, it can be done by looking at dreamhal videos mode setup.

Documentation

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.

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 failed
  • CC=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/buildir/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.

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) :

#!/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/buildir/mkdcdisc -v 3 -e $1.elf -o $1.cdi -n "" -m
~/redream.x86_64-linux-v1.5.0-1106-g01ef607/redream $1.cdi

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 RGB565 but might depend on video connection type, mine was set to VGA here.

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 4
    CLRCOUNT: .long 640*480

main:
    mov #-1,r1 ! full white; pixel16 = ((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3) << 0)
    mov.l CENTERED_PIXEL_ADDR,r0
    mov.l r1,@r0
    bra main
    nop

.align 4
    VIDEO_BASE: .long 0xa5200000
    CENTERED_PIXEL_ADDR: .long 0xa5200000 + (320 + (320 * 480)) * 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 4
    VIDEO_BASE: .long 0xa5200000
    CENTERED_PIXEL_ADDR: .long (320 + (320 * 480)) * 4

back to topLicence Creative Commons