<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://dreamcast.wiki/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=GyroVorbis</id>
	<title>dreamcast.wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://dreamcast.wiki/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=GyroVorbis"/>
	<link rel="alternate" type="text/html" href="https://dreamcast.wiki/Special:Contributions/GyroVorbis"/>
	<updated>2026-05-28T12:08:13Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.3</generator>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Development&amp;diff=3847</id>
		<title>Development</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Development&amp;diff=3847"/>
		<updated>2026-01-08T20:39:08Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: Added link to SH4ZAM documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Getting started ===&lt;br /&gt;
* [[Getting Started with Dreamcast development]] -- start here!&lt;br /&gt;
====Ready-to-use environments====&lt;br /&gt;
* [[Codespaces]] (Browser-based development)&lt;br /&gt;
* [[Docker images]]&lt;br /&gt;
* [[DreamSDK]] (Windows only)&lt;br /&gt;
&lt;br /&gt;
====[[KallistiOS]]====&lt;br /&gt;
* Building on Linux, macOS, Windows Subsystem for Linux&lt;br /&gt;
** see [[Getting Started with Dreamcast development|&#039;&#039;Getting Started with Dreamcast development&#039;&#039;]]&lt;br /&gt;
* [[Building KOS on Cygwin]]&lt;br /&gt;
* [[Building KOS on MinGW/MSYS]]&lt;br /&gt;
* [[Building KOS on MinGW-w64/MSYS2]]&lt;br /&gt;
* [https://kos-docs.dreamcast.wiki/ KallistiOS Doxygen documentation]&lt;br /&gt;
&lt;br /&gt;
====Other====&lt;br /&gt;
* [[Using Ruby for Sega Dreamcast development]] (experimental)&lt;br /&gt;
* [[Compiling for Naomi]]&lt;br /&gt;
&lt;br /&gt;
=== Build &amp;amp; test ===&lt;br /&gt;
* [[Building your project]]&lt;br /&gt;
* [[Emulators]]&lt;br /&gt;
* [[Broadband adapter]] / [[LAN adapter]]&lt;br /&gt;
** [[Using dcload-ip with Linux]]&lt;br /&gt;
** [[Using dcload-ip with Windows Subsystem for Linux|Using dcload-ip with Windows 10]] (via Windows Subsystem for Linux)&lt;br /&gt;
* [[Coder&#039;s cable]]&lt;br /&gt;
&lt;br /&gt;
=== Environments and IDEs ===&lt;br /&gt;
* [[CLion Debugging]]&lt;br /&gt;
* [[Visual Studio Code]]&lt;br /&gt;
&lt;br /&gt;
=== Tools &amp;amp; utilities ===&lt;br /&gt;
* [[Debugging throught GNU Debugger (GDB) and dcload/dc-tool]]&lt;br /&gt;
* [[Using dcprof]]&lt;br /&gt;
&lt;br /&gt;
=== Releasing your project ===&lt;br /&gt;
* Plain files&lt;br /&gt;
* Disc image&lt;br /&gt;
* Selfboot Inducer package&lt;br /&gt;
&lt;br /&gt;
=== Engines ===&lt;br /&gt;
&#039;&#039;See&#039;&#039; [[Engine &amp;amp; Library]]&lt;br /&gt;
&lt;br /&gt;
=== General ===&lt;br /&gt;
* [[Store Queues]]&lt;br /&gt;
* [[Romdisk Swapping]]&lt;br /&gt;
* [https://mc.pp.se/dc/hw.html Marcus Comstedt&#039;s Dreamcast Hardware Reference]&lt;br /&gt;
&lt;br /&gt;
=== Graphics ===&lt;br /&gt;
* [[Texture Formats]]&lt;br /&gt;
* [[Graphics APIs]]&lt;br /&gt;
* [[Paletted Textures]]&lt;br /&gt;
* [[2D Rendering Without PVR]]&lt;br /&gt;
* [[Twiddling]]&lt;br /&gt;
&lt;br /&gt;
* PVR&lt;br /&gt;
** [[PowerVR Introduction]]&lt;br /&gt;
** [[PVR Spritesheets]]&lt;br /&gt;
* [[GLdc]]&lt;br /&gt;
** [[Drawing 2D sprites using GLdc]]&lt;br /&gt;
** [[Drawing 3D shapes using GLdc]]&lt;br /&gt;
** [https://hkowsoftware.com/articles/gldc-vertex-formats-from-vec3f-to-fastpath-to-map_buffer/ GLdc Vertex Formats: From vec3f to fastpath to map_buffer]&lt;br /&gt;
* Others&lt;br /&gt;
** [http://www.numechanix.com/blog/index.php/2015/10/03/20/ Procedural texture]&lt;br /&gt;
** [[Notes on fillrate and drawing large textures]]&lt;br /&gt;
** [[KMG Textures]]&lt;br /&gt;
** [[Loading PNG images as OpenGL textures]]&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
&lt;br /&gt;
=== Maple ===&lt;br /&gt;
* Controller input&lt;br /&gt;
&lt;br /&gt;
=== VMU ===&lt;br /&gt;
* [[Save/Load file]]&lt;br /&gt;
* [[Show icon]]&lt;br /&gt;
* [[Play tone]]&lt;br /&gt;
&lt;br /&gt;
=== Optimization ===&lt;br /&gt;
* [[GCC-SH4 tips]]&lt;br /&gt;
* [[Fast SH4 Vertex Processing]]&lt;br /&gt;
* [[Useful programming tips]]&lt;br /&gt;
* [[Efficient usage of the Dreamcast RAM]]&lt;br /&gt;
* [[SH4 FIPR Optimizations]]&lt;br /&gt;
* [[SH4 FTRV Optimizations]]&lt;br /&gt;
* [http://sh4zam.falcogirgis.net SH4ZAM docs]&lt;br /&gt;
* Registers&lt;br /&gt;
* DMA&lt;br /&gt;
* TA&lt;br /&gt;
* PVR&lt;br /&gt;
&lt;br /&gt;
=== Website Development ===&lt;br /&gt;
*[[Development Resources]]&lt;br /&gt;
&lt;br /&gt;
=== Random Snippets ===&lt;br /&gt;
* [[Objdump]]&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Engine_%26_Library&amp;diff=3846</id>
		<title>Engine &amp; Library</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Engine_%26_Library&amp;diff=3846"/>
		<updated>2026-01-08T20:35:53Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: Added SH4ZAM&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This list is an adaptation of the [https://github.com/dreamcastdevs/awesome-dreamcast awesome-dreamcast] repo on github.&lt;br /&gt;
&lt;br /&gt;
==Tutorial==&lt;br /&gt;
*[https://dreamcast.wiki Dreamcast.wiki] - A brand new wiki with up-to-date information about the Dreamcast.&lt;br /&gt;
*[https://dcemulation.org/index.php?title=Development DCEmu Developement Wiki] - Great resource to start. Somewhat incomplete in certain aspect.&lt;br /&gt;
*[https://github.com/dreamcastdevs/dreamcast_tutorial Dreamcast-tutorial Github] - A new-ish sets of tutorial with code example. Covers the basic (installing the toolchain, graphics, audio, controller)&lt;br /&gt;
&lt;br /&gt;
==Framework==&lt;br /&gt;
*[https://sourceforge.net/projects/cadcdev/ KOS] - The pseudo-OS that&#039;s been used in a lot of homebrew/indie.&lt;br /&gt;
*[https://www.dreamsdk.org DreamSDK] - A multitool environment made for Windows. Maintained by [SiZiOUS](User:SiZiOUS)&lt;br /&gt;
*[http://wiki.bennugd.org/index.php?title=Bennu_Wiki BennuGD] - A multi-platform engine&lt;br /&gt;
*[https://github.com/FaucetDC/WincastCE WincastCE] - An experimental windows CE shell (?)&lt;br /&gt;
*[https://github.com/DC-SWAT/DreamShell DreamShell] - The popular alternative operating system for loading games/app from SD Card and IDE Drive&lt;br /&gt;
*[[libronin]] - an independent development library created by the DreamSNES team&lt;br /&gt;
*[http://sh4zam.falcogirgis.net SH4ZAM] - Fast math library for the Sega Dreamcast&#039;s SH4 CPU (included within kos-ports).&lt;br /&gt;
&lt;br /&gt;
==Engine==&lt;br /&gt;
*[[Simulant]] - A general purpose 2D-3D engine in active developement.&lt;br /&gt;
*[[nuQuake]] - Quake engine by MrNeo240&lt;br /&gt;
*[[RADquake]] - Quake engine by Ian Micheal&lt;br /&gt;
*[https://github.com/ianmicheal/Dreambor6.0 DreamBOR - unofficial] - OpenBOR dreamcast port forked an improved by Ian Michael&lt;br /&gt;
*[https://github.com/CaptainDreamcast/DolmexicaInfinite DolmexicaInfinite] - A Mugen-like engine for fighter games&lt;br /&gt;
*[[Antiruins]] - Minimal 2D game engine with Lua scripting by Lerabot.&lt;br /&gt;
&lt;br /&gt;
==Graphics==&lt;br /&gt;
*[https://gitlab.com/simulant/GLdc GLdc] - A OpenGL 1.2 implementation started by Kazade&lt;br /&gt;
*[https://github.com/Kannagi/LMP3D LMP3D] - A multi-platform 3D Lib. (*Looks abandoned but might be good for research*)&lt;br /&gt;
*[https://github.com/multimediamike/dreamroq DreamROQ] - A ROQ video player. (*Stable, no sound*)&lt;br /&gt;
&lt;br /&gt;
==Audio==&lt;br /&gt;
*[https://gitlab.com/simulant/ALdc ALdc] - A OpenAL 1.2 implementation started by Kazade&lt;br /&gt;
*https://github.com/Aurelien34/DreamcastAicaSoundDriver - A hardware accelerated S3M and sfx AICA driver.&lt;br /&gt;
&lt;br /&gt;
==VMU==&lt;br /&gt;
*[https://github.com/Protofall/Crayon-Utilities CrayonUtil] - Mostly tools for VMU icons, but also some texture converters. Made by [Protofall](https://github.com/Protofall)&lt;br /&gt;
&lt;br /&gt;
==Utilities==&lt;br /&gt;
*[https://github.com/CaptainDreamcast/prism Prism] - CaptainDreamcast&#039;s set of utilities for Physics, files loading, etc. (*untested*)&lt;br /&gt;
&lt;br /&gt;
==Memory Management==&lt;br /&gt;
&lt;br /&gt;
==Debugging==&lt;br /&gt;
&lt;br /&gt;
==Random==&lt;br /&gt;
*[https://github.com/Protofall/Homebrew-Tests Homebrew Tests (Protofall)]&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Development&amp;diff=3844</id>
		<title>Development</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Development&amp;diff=3844"/>
		<updated>2025-12-12T04:33:49Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Getting started ===&lt;br /&gt;
* [[Getting Started with Dreamcast development]] -- start here!&lt;br /&gt;
====Ready-to-use environments====&lt;br /&gt;
* [[Codespaces]] (Browser-based development)&lt;br /&gt;
* [[Docker images]]&lt;br /&gt;
* [[DreamSDK]] (Windows only)&lt;br /&gt;
&lt;br /&gt;
====[[KallistiOS]]====&lt;br /&gt;
* Building on Linux, macOS, Windows Subsystem for Linux&lt;br /&gt;
** see [[Getting Started with Dreamcast development|&#039;&#039;Getting Started with Dreamcast development&#039;&#039;]]&lt;br /&gt;
* [[Building KOS on Cygwin]]&lt;br /&gt;
* [[Building KOS on MinGW/MSYS]]&lt;br /&gt;
* [[Building KOS on MinGW-w64/MSYS2]]&lt;br /&gt;
* [https://kos-docs.dreamcast.wiki/ KallistiOS Doxygen documentation]&lt;br /&gt;
&lt;br /&gt;
====Other====&lt;br /&gt;
* [[Using Ruby for Sega Dreamcast development]] (experimental)&lt;br /&gt;
* [[Compiling for Naomi]]&lt;br /&gt;
&lt;br /&gt;
=== Build &amp;amp; test ===&lt;br /&gt;
* [[Building your project]]&lt;br /&gt;
* [[Emulators]]&lt;br /&gt;
* [[Broadband adapter]] / [[LAN adapter]]&lt;br /&gt;
** [[Using dcload-ip with Linux]]&lt;br /&gt;
** [[Using dcload-ip with Windows Subsystem for Linux|Using dcload-ip with Windows 10]] (via Windows Subsystem for Linux)&lt;br /&gt;
* [[Coder&#039;s cable]]&lt;br /&gt;
&lt;br /&gt;
=== Environments and IDEs ===&lt;br /&gt;
* [[CLion Debugging]]&lt;br /&gt;
* [[Visual Studio Code]]&lt;br /&gt;
&lt;br /&gt;
=== Tools &amp;amp; utilities ===&lt;br /&gt;
* [[Debugging throught GNU Debugger (GDB) and dcload/dc-tool]]&lt;br /&gt;
* [[Using dcprof]]&lt;br /&gt;
&lt;br /&gt;
=== Releasing your project ===&lt;br /&gt;
* Plain files&lt;br /&gt;
* Disc image&lt;br /&gt;
* Selfboot Inducer package&lt;br /&gt;
&lt;br /&gt;
=== Engines ===&lt;br /&gt;
&#039;&#039;See&#039;&#039; [[Engine &amp;amp; Library]]&lt;br /&gt;
&lt;br /&gt;
=== General ===&lt;br /&gt;
* [[Store Queues]]&lt;br /&gt;
* [[Romdisk Swapping]]&lt;br /&gt;
* [https://mc.pp.se/dc/hw.html Marcus Comstedt&#039;s Dreamcast Hardware Reference]&lt;br /&gt;
&lt;br /&gt;
=== Graphics ===&lt;br /&gt;
* [[Texture Formats]]&lt;br /&gt;
* [[Graphics APIs]]&lt;br /&gt;
* [[Paletted Textures]]&lt;br /&gt;
* [[2D Rendering Without PVR]]&lt;br /&gt;
* [[Twiddling]]&lt;br /&gt;
&lt;br /&gt;
* PVR&lt;br /&gt;
** [[PowerVR Introduction]]&lt;br /&gt;
** [[PVR Spritesheets]]&lt;br /&gt;
* [[GLdc]]&lt;br /&gt;
** [[Drawing 2D sprites using GLdc]]&lt;br /&gt;
** [[Drawing 3D shapes using GLdc]]&lt;br /&gt;
** [https://hkowsoftware.com/articles/gldc-vertex-formats-from-vec3f-to-fastpath-to-map_buffer/ GLdc Vertex Formats: From vec3f to fastpath to map_buffer]&lt;br /&gt;
* Others&lt;br /&gt;
** [http://www.numechanix.com/blog/index.php/2015/10/03/20/ Procedural texture]&lt;br /&gt;
** [[Notes on fillrate and drawing large textures]]&lt;br /&gt;
** [[KMG Textures]]&lt;br /&gt;
** [[Loading PNG images as OpenGL textures]]&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
&lt;br /&gt;
=== Maple ===&lt;br /&gt;
* Controller input&lt;br /&gt;
&lt;br /&gt;
=== VMU ===&lt;br /&gt;
* [[Save/Load file]]&lt;br /&gt;
* [[Show icon]]&lt;br /&gt;
* [[Play tone]]&lt;br /&gt;
&lt;br /&gt;
=== Optimization ===&lt;br /&gt;
* [[GCC-SH4 tips]]&lt;br /&gt;
* [[Fast SH4 Vertex Processing]]&lt;br /&gt;
* [[Useful programming tips]]&lt;br /&gt;
* [[Efficient usage of the Dreamcast RAM]]&lt;br /&gt;
* [[SH4 FIPR Optimizations]]&lt;br /&gt;
* [[SH4 FTRV Optimizations]]&lt;br /&gt;
* Registers&lt;br /&gt;
* DMA&lt;br /&gt;
* TA&lt;br /&gt;
* PVR&lt;br /&gt;
&lt;br /&gt;
=== Website Development ===&lt;br /&gt;
*[[Development Resources]]&lt;br /&gt;
&lt;br /&gt;
=== Random Snippets ===&lt;br /&gt;
* [[Objdump]]&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_in_Compiler_Explorer&amp;diff=3811</id>
		<title>SH4 in Compiler Explorer</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_in_Compiler_Explorer&amp;diff=3811"/>
		<updated>2025-08-27T17:31:21Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: /* Configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Thanks to the effort of Matt Godbolt (who hilariously enough is a former Dreamcast developer himself), the SuperH GCC toolchain is now available for use with [https://godbolt.org Compiler Explorer], along with all of the SH4-specific compiler flags and options typically used when targeting the Dreamcast. This gives us an invaluable tool for getting quick and immediate feedback on how well a given C or C++ source segment tends to translate into SH4 assembly, offering a little sandbox for testing and optimizing code targeting the Dreamcast.&lt;br /&gt;
&lt;br /&gt;
[[File:GCC Compiler Benchmarks.png|thumb|Benchmarking various GCC versions and flags]]&lt;br /&gt;
&lt;br /&gt;
= Configuration =&lt;br /&gt;
To arrive at a configuration mirroring a Dreamcast development environment, first select one of the GCC compiler versions for the SH architecture. Secondly, the following compiler options should be used as the baseline configuration:&lt;br /&gt;
* &amp;lt;code&amp;gt;-ml&amp;lt;/code&amp;gt;: compile code for the processor in little-endian mode&lt;br /&gt;
* FPU Mode:&lt;br /&gt;
** &amp;lt;code&amp;gt;-m4-single&amp;lt;/code&amp;gt;: generate code for the SH4 with a floating-point unit that supports both single and double-precision floating point arithmetic that defaults to single-precision mode upon function entry&lt;br /&gt;
** &amp;lt;code&amp;gt;-m4-single-only&amp;lt;/code&amp;gt;: generate code for the SH4 with a floating-point unit that only supports single-precision floating point arithmetic&lt;br /&gt;
* &amp;lt;code&amp;gt;-ffast-math&amp;lt;/code&amp;gt;: breaks strict IEEE compliance and allows for faster floating point approximations&lt;br /&gt;
* &amp;lt;code&amp;gt;-O3&amp;lt;/code&amp;gt;: optimization level 3&lt;br /&gt;
* &amp;lt;code&amp;gt;-mfsrra&amp;lt;/code&amp;gt;: enables emission of the fsrra instruction for reciprocal square root approximations (not available in GCC 4.7.4)&lt;br /&gt;
* &amp;lt;code&amp;gt;-mfsca&amp;lt;/code&amp;gt;: enables emission of the fsca instruction for sine and cosine approximations (not available in GCC 4.7.4)&lt;br /&gt;
* &amp;lt;code&amp;gt;-matomic-model=soft-imask&amp;lt;/code&amp;gt;: enables support for C11 and C++11 atomics by disabling then reenabling interrupts around atomic variable operations&lt;br /&gt;
* &amp;lt;code&amp;gt;-mtas&amp;lt;/code&amp;gt;: Backs C11&#039;s atomic_flag type by emitting the tas.b instruction, which atomically tests and sets the flag&#039;s value, also causing a purge of the cache line it lies within.&lt;br /&gt;
* &amp;lt;code&amp;gt;-ftls-model=local-exec&amp;lt;/code&amp;gt;: enables the model used by KOS for supporting variables declared with the &amp;quot;thread_local&amp;quot; keyword&lt;br /&gt;
&lt;br /&gt;
= Convenience Templates =&lt;br /&gt;
The following are pre-configured templates you can use as sample Dreamcast build configurations:&lt;br /&gt;
* GCC4.9.4:&lt;br /&gt;
** [https://godbolt.org/z/9MKzeMfMj C11 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/qGzoeo4sj C++14 Hello World]&lt;br /&gt;
* GCC9.5.0:&lt;br /&gt;
** [https://godbolt.org/z/rvW3s3594 C17 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/qYfE5G6Mx C++17 Hello World]&lt;br /&gt;
* GCC12.2.0:&lt;br /&gt;
** [https://godbolt.org/z/94TKvxazn C17 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/61jqhE3zn C++20 Hello World]&lt;br /&gt;
* GCC13.1.0:&lt;br /&gt;
** [https://godbolt.org/z/Kb9bKe8ro C2X Hello World]&lt;br /&gt;
** [https://godbolt.org/z/51dv4ePsG C++23 Hello World]&lt;br /&gt;
* GCC13.2.0:&lt;br /&gt;
** [https://godbolt.org/z/rafvMdWGb C2X Hello World]&lt;br /&gt;
** [https://godbolt.org/z/MeG3rqna7 C++23 Hello World]&lt;br /&gt;
* GCC 14.1.0&lt;br /&gt;
** [https://godbolt.org/z/7ha8oj4vd C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/eW8Yd8sG9 C++26 Hello World]&lt;br /&gt;
* GCC 14.2.0&lt;br /&gt;
** [https://godbolt.org/z/a54qTYon4 C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/5njMrrh8z C++26 Hello World]&lt;br /&gt;
* GCC 15.1.0&lt;br /&gt;
** [https://godbolt.org/z/WWsaaEqWW C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/raP67zWcY C++26 Hello World]&lt;br /&gt;
* GCC 15.2.0&lt;br /&gt;
** [https://godbolt.org/z/TGYr875vs C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/7ET55a9sh C++26 Hello World]&lt;br /&gt;
&lt;br /&gt;
Pre-configured template for ARM GCC8.5, Dreamcast&#039;s &amp;quot;AICA&amp;quot; sound chip:&lt;br /&gt;
* [https://godbolt.org/z/895dWG9qf C Hello World]&lt;br /&gt;
&lt;br /&gt;
= Tips and Notes =&lt;br /&gt;
* It has been noted that while &amp;lt;code&amp;gt;-O3&amp;lt;/code&amp;gt; is claimed to be the highest optimization level according to recent GCC documentation, some code differences can still be seen under certain circumstances when using &amp;lt;code&amp;gt;-O4&amp;lt;/code&amp;gt; and beyond.&lt;br /&gt;
* The compiler seems to ignore both &amp;lt;code&amp;gt;-mfsrra&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;-mfsca&amp;lt;/code&amp;gt; without the &amp;lt;code&amp;gt;-ffast-math&amp;lt;/code&amp;gt; option.&lt;br /&gt;
* With the proper flags enabled for fast-math, the compiler is smart enough to leverage the following from pure C code, almost certainly better than you can do with small intrinsic-style inline ASM calls, provided you&#039;re using the proper single-precision versions of any &amp;lt;code&amp;gt;&amp;lt;math.h&amp;gt;&amp;lt;/code&amp;gt; routines:&lt;br /&gt;
**&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{|&lt;br /&gt;
|+ Compiler-Generated Fast-Math Optimizations&lt;br /&gt;
|-&lt;br /&gt;
! Assembly Output !! C/C++ Input&lt;br /&gt;
|-&lt;br /&gt;
| FMAC || &amp;lt;code&amp;gt;z = x * y + z&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| FSCA || &amp;lt;code&amp;gt;s = sinf(angle); c = cosf(angle)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| FSRRA || &amp;lt;code&amp;gt;1.0f / sqrtf(x)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
*Unfortunately the compiler has no knowledge of the following SIMD instructions, even with fast-math, so it&#039;s quite necessary to use inline assembly routines (provided by KallistiOS) for fully leveraging the SH4&#039;s FPU, when working with vectors and matrices in linear algebra routines:&lt;br /&gt;
**&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{|&lt;br /&gt;
|+ Manual Inline Assembly Fast-Math Optimizations&lt;br /&gt;
|-&lt;br /&gt;
! Assembly Output !! C/C++ Input&lt;br /&gt;
|-&lt;br /&gt;
| FIPR || &amp;lt;code&amp;gt;Vector4 Dot Product&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| FTRV || &amp;lt;code&amp;gt;Vector4 * Matrix4x4 Transform&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
* Typically smaller code sizes and more tightly optimized code are seen with newer versions of GCC versus the older ones; however, this is not always the case.&lt;br /&gt;
* Evidently, even without a branch predictor, the C++20 &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[likely]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[unlikely]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; attributes as well as the GCC intrinsic &amp;lt;code&amp;gt;__builtin_expect()&amp;lt;/code&amp;gt; can have a fairly profound impact on code generation and optimization for conditionals and branches. More information can be found [https://dcemulation.org/phpBB/viewtopic.php?t=106029 here].&lt;br /&gt;
* &amp;lt;code&amp;gt;-fipa-pta&amp;lt;/code&amp;gt; allows the compiler to analyze pointer and reference usage beyond the scope of the current compiling function, which very often results in pretty decent performance increases at the cost of increased compile times and RAM usage.&lt;br /&gt;
* &amp;lt;code&amp;gt;-flto&amp;lt;/code&amp;gt; allows GCC to perform optimizations over the entire program and all translation units as a single entity during the linking phase, for the cost of increased compile times and RAM usage. This frequently results in more performant code.&lt;br /&gt;
* An in-depth benchmark comparing the run-time performance and compiled binary size output of every toolchain version officially supported by KOS with various optimization levels can be found [https://dcemulation.org/phpBB/viewtopic.php?t=106068 here].&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_in_Compiler_Explorer&amp;diff=3810</id>
		<title>SH4 in Compiler Explorer</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_in_Compiler_Explorer&amp;diff=3810"/>
		<updated>2025-08-27T17:30:34Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: Templates for GCC 15.2.0&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Thanks to the effort of Matt Godbolt (who hilariously enough is a former Dreamcast developer himself), the SuperH GCC toolchain is now available for use with [https://godbolt.org Compiler Explorer], along with all of the SH4-specific compiler flags and options typically used when targeting the Dreamcast. This gives us an invaluable tool for getting quick and immediate feedback on how well a given C or C++ source segment tends to translate into SH4 assembly, offering a little sandbox for testing and optimizing code targeting the Dreamcast.&lt;br /&gt;
&lt;br /&gt;
[[File:GCC Compiler Benchmarks.png|thumb|Benchmarking various GCC versions and flags]]&lt;br /&gt;
&lt;br /&gt;
= Configuration =&lt;br /&gt;
To arrive at a configuration mirroring a Dreamcast development environment, first select one of the GCC compiler versions for the SH architecture. Secondly, the following compiler options should be used as the baseline configuration:&lt;br /&gt;
* &amp;lt;code&amp;gt;-ml&amp;lt;/code&amp;gt;: compile code for the processor in little-endian mode&lt;br /&gt;
* FPU Mode:&lt;br /&gt;
** &amp;lt;code&amp;gt;-m4-single&amp;lt;/code&amp;gt;: generate code for the SH4 with a floating-point unit that supports both single and double-precision floating point arithmetic that defaults to single-precision mode upon function entry&lt;br /&gt;
** &amp;lt;code&amp;gt;-m4-single-only&amp;lt;/code&amp;gt;: generate code for the SH4 with a floating-point unit that only supports single-precision floating point arithmetic&lt;br /&gt;
* &amp;lt;code&amp;gt;-ffast-math&amp;lt;/code&amp;gt;: breaks strict IEEE compliance and allows for faster floating point approximations&lt;br /&gt;
* &amp;lt;code&amp;gt;-O3&amp;lt;/code&amp;gt;: optimization level 3&lt;br /&gt;
* &amp;lt;code&amp;gt;-mfsrra&amp;lt;/code&amp;gt;: enables emission of the fsrra instruction for reciprocal square root approximations (not available in GCC 4.7.4)&lt;br /&gt;
* &amp;lt;code&amp;gt;-mfsca&amp;lt;/code&amp;gt;: enables emission of the fsca instruction for sine and cosine approximations (not available in GCC 4.7.4)&lt;br /&gt;
* &amp;lt;code&amp;gt;-matomic-model=soft-imask&amp;lt;/code&amp;gt;: enables support for C11 and C++11 atomics by disabling then reenabling interrupts around atomic variable operations&lt;br /&gt;
* &amp;lt;code&amp;gt;-mtas&amp;lt;/code&amp;gt; Backs C11&#039;s atomic_flag type by emitting the tas.b instruction, which atomically tests and sets the flag&#039;s value, also causing a purge of the cache line it lies within.&lt;br /&gt;
* &amp;lt;code&amp;gt;-ftls-model=local-exec&amp;lt;/code&amp;gt;: enables the model used by KOS for supporting variables declared with the &amp;quot;thread_local&amp;quot; keyword&lt;br /&gt;
&lt;br /&gt;
= Convenience Templates =&lt;br /&gt;
The following are pre-configured templates you can use as sample Dreamcast build configurations:&lt;br /&gt;
* GCC4.9.4:&lt;br /&gt;
** [https://godbolt.org/z/9MKzeMfMj C11 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/qGzoeo4sj C++14 Hello World]&lt;br /&gt;
* GCC9.5.0:&lt;br /&gt;
** [https://godbolt.org/z/rvW3s3594 C17 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/qYfE5G6Mx C++17 Hello World]&lt;br /&gt;
* GCC12.2.0:&lt;br /&gt;
** [https://godbolt.org/z/94TKvxazn C17 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/61jqhE3zn C++20 Hello World]&lt;br /&gt;
* GCC13.1.0:&lt;br /&gt;
** [https://godbolt.org/z/Kb9bKe8ro C2X Hello World]&lt;br /&gt;
** [https://godbolt.org/z/51dv4ePsG C++23 Hello World]&lt;br /&gt;
* GCC13.2.0:&lt;br /&gt;
** [https://godbolt.org/z/rafvMdWGb C2X Hello World]&lt;br /&gt;
** [https://godbolt.org/z/MeG3rqna7 C++23 Hello World]&lt;br /&gt;
* GCC 14.1.0&lt;br /&gt;
** [https://godbolt.org/z/7ha8oj4vd C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/eW8Yd8sG9 C++26 Hello World]&lt;br /&gt;
* GCC 14.2.0&lt;br /&gt;
** [https://godbolt.org/z/a54qTYon4 C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/5njMrrh8z C++26 Hello World]&lt;br /&gt;
* GCC 15.1.0&lt;br /&gt;
** [https://godbolt.org/z/WWsaaEqWW C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/raP67zWcY C++26 Hello World]&lt;br /&gt;
* GCC 15.2.0&lt;br /&gt;
** [https://godbolt.org/z/TGYr875vs C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/7ET55a9sh C++26 Hello World]&lt;br /&gt;
&lt;br /&gt;
Pre-configured template for ARM GCC8.5, Dreamcast&#039;s &amp;quot;AICA&amp;quot; sound chip:&lt;br /&gt;
* [https://godbolt.org/z/895dWG9qf C Hello World]&lt;br /&gt;
&lt;br /&gt;
= Tips and Notes =&lt;br /&gt;
* It has been noted that while &amp;lt;code&amp;gt;-O3&amp;lt;/code&amp;gt; is claimed to be the highest optimization level according to recent GCC documentation, some code differences can still be seen under certain circumstances when using &amp;lt;code&amp;gt;-O4&amp;lt;/code&amp;gt; and beyond.&lt;br /&gt;
* The compiler seems to ignore both &amp;lt;code&amp;gt;-mfsrra&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;-mfsca&amp;lt;/code&amp;gt; without the &amp;lt;code&amp;gt;-ffast-math&amp;lt;/code&amp;gt; option.&lt;br /&gt;
* With the proper flags enabled for fast-math, the compiler is smart enough to leverage the following from pure C code, almost certainly better than you can do with small intrinsic-style inline ASM calls, provided you&#039;re using the proper single-precision versions of any &amp;lt;code&amp;gt;&amp;lt;math.h&amp;gt;&amp;lt;/code&amp;gt; routines:&lt;br /&gt;
**&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{|&lt;br /&gt;
|+ Compiler-Generated Fast-Math Optimizations&lt;br /&gt;
|-&lt;br /&gt;
! Assembly Output !! C/C++ Input&lt;br /&gt;
|-&lt;br /&gt;
| FMAC || &amp;lt;code&amp;gt;z = x * y + z&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| FSCA || &amp;lt;code&amp;gt;s = sinf(angle); c = cosf(angle)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| FSRRA || &amp;lt;code&amp;gt;1.0f / sqrtf(x)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
*Unfortunately the compiler has no knowledge of the following SIMD instructions, even with fast-math, so it&#039;s quite necessary to use inline assembly routines (provided by KallistiOS) for fully leveraging the SH4&#039;s FPU, when working with vectors and matrices in linear algebra routines:&lt;br /&gt;
**&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{|&lt;br /&gt;
|+ Manual Inline Assembly Fast-Math Optimizations&lt;br /&gt;
|-&lt;br /&gt;
! Assembly Output !! C/C++ Input&lt;br /&gt;
|-&lt;br /&gt;
| FIPR || &amp;lt;code&amp;gt;Vector4 Dot Product&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| FTRV || &amp;lt;code&amp;gt;Vector4 * Matrix4x4 Transform&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
* Typically smaller code sizes and more tightly optimized code are seen with newer versions of GCC versus the older ones; however, this is not always the case.&lt;br /&gt;
* Evidently, even without a branch predictor, the C++20 &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[likely]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[unlikely]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; attributes as well as the GCC intrinsic &amp;lt;code&amp;gt;__builtin_expect()&amp;lt;/code&amp;gt; can have a fairly profound impact on code generation and optimization for conditionals and branches. More information can be found [https://dcemulation.org/phpBB/viewtopic.php?t=106029 here].&lt;br /&gt;
* &amp;lt;code&amp;gt;-fipa-pta&amp;lt;/code&amp;gt; allows the compiler to analyze pointer and reference usage beyond the scope of the current compiling function, which very often results in pretty decent performance increases at the cost of increased compile times and RAM usage.&lt;br /&gt;
* &amp;lt;code&amp;gt;-flto&amp;lt;/code&amp;gt; allows GCC to perform optimizations over the entire program and all translation units as a single entity during the linking phase, for the cost of increased compile times and RAM usage. This frequently results in more performant code.&lt;br /&gt;
* An in-depth benchmark comparing the run-time performance and compiled binary size output of every toolchain version officially supported by KOS with various optimization levels can be found [https://dcemulation.org/phpBB/viewtopic.php?t=106068 here].&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_in_Compiler_Explorer&amp;diff=3809</id>
		<title>SH4 in Compiler Explorer</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_in_Compiler_Explorer&amp;diff=3809"/>
		<updated>2025-08-27T17:28:06Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: Added -mtas flag.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Thanks to the effort of Matt Godbolt (who hilariously enough is a former Dreamcast developer himself), the SuperH GCC toolchain is now available for use with [https://godbolt.org Compiler Explorer], along with all of the SH4-specific compiler flags and options typically used when targeting the Dreamcast. This gives us an invaluable tool for getting quick and immediate feedback on how well a given C or C++ source segment tends to translate into SH4 assembly, offering a little sandbox for testing and optimizing code targeting the Dreamcast.&lt;br /&gt;
&lt;br /&gt;
[[File:GCC Compiler Benchmarks.png|thumb|Benchmarking various GCC versions and flags]]&lt;br /&gt;
&lt;br /&gt;
= Configuration =&lt;br /&gt;
To arrive at a configuration mirroring a Dreamcast development environment, first select one of the GCC compiler versions for the SH architecture. Secondly, the following compiler options should be used as the baseline configuration:&lt;br /&gt;
* &amp;lt;code&amp;gt;-ml&amp;lt;/code&amp;gt;: compile code for the processor in little-endian mode&lt;br /&gt;
* FPU Mode:&lt;br /&gt;
** &amp;lt;code&amp;gt;-m4-single&amp;lt;/code&amp;gt;: generate code for the SH4 with a floating-point unit that supports both single and double-precision floating point arithmetic that defaults to single-precision mode upon function entry&lt;br /&gt;
** &amp;lt;code&amp;gt;-m4-single-only&amp;lt;/code&amp;gt;: generate code for the SH4 with a floating-point unit that only supports single-precision floating point arithmetic&lt;br /&gt;
* &amp;lt;code&amp;gt;-ffast-math&amp;lt;/code&amp;gt;: breaks strict IEEE compliance and allows for faster floating point approximations&lt;br /&gt;
* &amp;lt;code&amp;gt;-O3&amp;lt;/code&amp;gt;: optimization level 3&lt;br /&gt;
* &amp;lt;code&amp;gt;-mfsrra&amp;lt;/code&amp;gt;: enables emission of the fsrra instruction for reciprocal square root approximations (not available in GCC 4.7.4)&lt;br /&gt;
* &amp;lt;code&amp;gt;-mfsca&amp;lt;/code&amp;gt;: enables emission of the fsca instruction for sine and cosine approximations (not available in GCC 4.7.4)&lt;br /&gt;
* &amp;lt;code&amp;gt;-matomic-model=soft-imask&amp;lt;/code&amp;gt;: enables support for C11 and C++11 atomics by disabling then reenabling interrupts around atomic variable operations&lt;br /&gt;
* &amp;lt;code&amp;gt;-mtas&amp;lt;/code&amp;gt; Backs C11&#039;s atomic_flag type by emitting the tas.b instruction, which atomically tests and sets the flag&#039;s value, also causing a purge of the cache line it lies within.&lt;br /&gt;
* &amp;lt;code&amp;gt;-ftls-model=local-exec&amp;lt;/code&amp;gt;: enables the model used by KOS for supporting variables declared with the &amp;quot;thread_local&amp;quot; keyword&lt;br /&gt;
&lt;br /&gt;
= Convenience Templates =&lt;br /&gt;
The following are pre-configured templates you can use as sample Dreamcast build configurations:&lt;br /&gt;
* GCC4.9.4:&lt;br /&gt;
** [https://godbolt.org/z/9MKzeMfMj C11 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/qGzoeo4sj C++14 Hello World]&lt;br /&gt;
* GCC9.5.0:&lt;br /&gt;
** [https://godbolt.org/z/rvW3s3594 C17 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/qYfE5G6Mx C++17 Hello World]&lt;br /&gt;
* GCC12.2.0:&lt;br /&gt;
** [https://godbolt.org/z/94TKvxazn C17 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/61jqhE3zn C++20 Hello World]&lt;br /&gt;
* GCC13.1.0:&lt;br /&gt;
** [https://godbolt.org/z/Kb9bKe8ro C2X Hello World]&lt;br /&gt;
** [https://godbolt.org/z/51dv4ePsG C++23 Hello World]&lt;br /&gt;
* GCC13.2.0:&lt;br /&gt;
** [https://godbolt.org/z/rafvMdWGb C2X Hello World]&lt;br /&gt;
** [https://godbolt.org/z/MeG3rqna7 C++23 Hello World]&lt;br /&gt;
* GCC 14.1.0&lt;br /&gt;
** [https://godbolt.org/z/7ha8oj4vd C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/eW8Yd8sG9 C++26 Hello World]&lt;br /&gt;
* GCC 14.2.0&lt;br /&gt;
** [https://godbolt.org/z/a54qTYon4 C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/5njMrrh8z C++26 Hello World]&lt;br /&gt;
* GCC 15.1.0&lt;br /&gt;
** [https://godbolt.org/z/WWsaaEqWW C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/raP67zWcY C++26 Hello World]&lt;br /&gt;
&lt;br /&gt;
Pre-configured template for ARM GCC8.5, Dreamcast&#039;s &amp;quot;AICA&amp;quot; sound chip:&lt;br /&gt;
* [https://godbolt.org/z/895dWG9qf C Hello World]&lt;br /&gt;
&lt;br /&gt;
= Tips and Notes =&lt;br /&gt;
* It has been noted that while &amp;lt;code&amp;gt;-O3&amp;lt;/code&amp;gt; is claimed to be the highest optimization level according to recent GCC documentation, some code differences can still be seen under certain circumstances when using &amp;lt;code&amp;gt;-O4&amp;lt;/code&amp;gt; and beyond.&lt;br /&gt;
* The compiler seems to ignore both &amp;lt;code&amp;gt;-mfsrra&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;-mfsca&amp;lt;/code&amp;gt; without the &amp;lt;code&amp;gt;-ffast-math&amp;lt;/code&amp;gt; option.&lt;br /&gt;
* With the proper flags enabled for fast-math, the compiler is smart enough to leverage the following from pure C code, almost certainly better than you can do with small intrinsic-style inline ASM calls, provided you&#039;re using the proper single-precision versions of any &amp;lt;code&amp;gt;&amp;lt;math.h&amp;gt;&amp;lt;/code&amp;gt; routines:&lt;br /&gt;
**&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{|&lt;br /&gt;
|+ Compiler-Generated Fast-Math Optimizations&lt;br /&gt;
|-&lt;br /&gt;
! Assembly Output !! C/C++ Input&lt;br /&gt;
|-&lt;br /&gt;
| FMAC || &amp;lt;code&amp;gt;z = x * y + z&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| FSCA || &amp;lt;code&amp;gt;s = sinf(angle); c = cosf(angle)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| FSRRA || &amp;lt;code&amp;gt;1.0f / sqrtf(x)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
*Unfortunately the compiler has no knowledge of the following SIMD instructions, even with fast-math, so it&#039;s quite necessary to use inline assembly routines (provided by KallistiOS) for fully leveraging the SH4&#039;s FPU, when working with vectors and matrices in linear algebra routines:&lt;br /&gt;
**&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{|&lt;br /&gt;
|+ Manual Inline Assembly Fast-Math Optimizations&lt;br /&gt;
|-&lt;br /&gt;
! Assembly Output !! C/C++ Input&lt;br /&gt;
|-&lt;br /&gt;
| FIPR || &amp;lt;code&amp;gt;Vector4 Dot Product&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| FTRV || &amp;lt;code&amp;gt;Vector4 * Matrix4x4 Transform&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
* Typically smaller code sizes and more tightly optimized code are seen with newer versions of GCC versus the older ones; however, this is not always the case.&lt;br /&gt;
* Evidently, even without a branch predictor, the C++20 &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[likely]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[unlikely]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; attributes as well as the GCC intrinsic &amp;lt;code&amp;gt;__builtin_expect()&amp;lt;/code&amp;gt; can have a fairly profound impact on code generation and optimization for conditionals and branches. More information can be found [https://dcemulation.org/phpBB/viewtopic.php?t=106029 here].&lt;br /&gt;
* &amp;lt;code&amp;gt;-fipa-pta&amp;lt;/code&amp;gt; allows the compiler to analyze pointer and reference usage beyond the scope of the current compiling function, which very often results in pretty decent performance increases at the cost of increased compile times and RAM usage.&lt;br /&gt;
* &amp;lt;code&amp;gt;-flto&amp;lt;/code&amp;gt; allows GCC to perform optimizations over the entire program and all translation units as a single entity during the linking phase, for the cost of increased compile times and RAM usage. This frequently results in more performant code.&lt;br /&gt;
* An in-depth benchmark comparing the run-time performance and compiled binary size output of every toolchain version officially supported by KOS with various optimization levels can be found [https://dcemulation.org/phpBB/viewtopic.php?t=106068 here].&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3806</id>
		<title>SH4 FTRV Optimizations</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3806"/>
		<updated>2025-08-06T08:32:21Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: /* Bounding Sphere vs View Frustum Culling */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Without a doubt, the single most computationally powerful instruction on the SuperH4 CPU in the Sega Dreamcast is &#039;&#039;&#039;FTRV&#039;&#039;&#039;, or the &#039;&#039;&#039;F&#039;&#039;&#039;loating-point &#039;&#039;&#039;TR&#039;&#039;&#039;ansform &#039;&#039;&#039;V&#039;&#039;&#039;ector instruction. It is a single instruction which multiplies a 4D vector by the 4x4 matrix held within the back-bank of FPU registers, &#039;&#039;&#039;XMTRX&#039;&#039;&#039;. This article will teach you how to leverage this god instruction for FP performance gainz and introduce you to several example scenarios that have yielded fantastic gainz within the community.&lt;br /&gt;
&lt;br /&gt;
==Relationship to FIPR==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Instruction Summaries&lt;br /&gt;
|-&lt;br /&gt;
! Format !! Function !! Encoding !! Group !! Issue Cycles !! Latency Cycles&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fipr&#039;&#039;&#039;	FVm,FVn || inner_product (FVm, FVn) -&amp;gt; FR[n+3] || 1111nnmm11101101 || FE || 1 || 4/5&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ftrv&#039;&#039;&#039; XMTRX, FVn || transform_vector(XMTRX, FVn) -&amp;gt; FVn || 1111nn0111111101 || FE || 1 || 5/8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==When to use FTRV==&lt;br /&gt;
There are two things to look out for when developing an intuition for when you can leverage FTRV:&lt;br /&gt;
# There are 3 or more dot products (ax + by + cz + dw) being calculated back-to-back.&lt;br /&gt;
# One of the vectors is held constant while the other vector argument is variable across each.&lt;br /&gt;
&lt;br /&gt;
When you see such a scenario, the first thing that should pop into your head is that you are dealing with a vector x matrix transform, and you can use &#039;&#039;&#039;FTRV&#039;&#039;&#039; to accelerate it.&lt;br /&gt;
&lt;br /&gt;
==Real-World Examples==&lt;br /&gt;
The following are real-world examples of FTRV-based optimizations used within games and applications for the Sega Dreamcast within the community.&lt;br /&gt;
===Vertex Position Transformation===&lt;br /&gt;
The first and most obvious use of the FTRV instruction is for doing position transform calculations on the incoming vertex stream, transforming from local to view-space, while submitting vertices to the PowerVR during T&amp;amp;L. This is the first and absolute most crucial area for leveraging FTRV and was its original intended purpose. If you do nothing else with the instruction, bear in mind that the only way to come even remotely close to pushing a considerable volume of polygons on the DC is by properly harnessing the SH4 by using FTRV to transform your vertices.&lt;br /&gt;
&lt;br /&gt;
===Diffuse Lighting===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Collision and Physics===&lt;br /&gt;
===Bounding Sphere vs View Frustum Culling===&lt;br /&gt;
The following code snippet is taken from the DCA3 codebase as part of its Renderware driver back-end for Dreamcast. To check for intersection between a bounding sphere and the view frustum, you must compute the dot product between the centroid of the bounding sphere against all 6 of the view frustum planes. The result of each dot product represents the sphere&#039;s distance from that plane.&lt;br /&gt;
&lt;br /&gt;
The original algorithm was as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
&lt;br /&gt;
    // Iterate over each of the 6 frustum planes.&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
	for(int32 i = 0; i &amp;lt; 6; i++){&lt;br /&gt;
        // Compute dot product between each plane and the centroid.&lt;br /&gt;
        // Your FIPR senses should be tingling, since we&#039;ve got dot products!&lt;br /&gt;
		float32 distance = dot(p-&amp;gt;plane, s-&amp;gt;center) - p-&amp;gt;plane.distance;&lt;br /&gt;
		&lt;br /&gt;
        if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
			return SPHEREOUTSIDE; // No intersection&lt;br /&gt;
		if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
			res = SPHEREBOUNDARY; // Intersection&lt;br /&gt;
		&lt;br /&gt;
        p++;&lt;br /&gt;
	}&lt;br /&gt;
    return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we have a scenario where we have 4+ dot products being taken where one of the vectors remains constant for each, this is a textbook case for using FTRV to compute 4 of them in parallel.&lt;br /&gt;
&lt;br /&gt;
So we use FIPR to accelerate two of the dot products and FTRV for the other 4 of them at once. The following code uses [https://github.com/gyrovorbis/sh4zam libSH4ZAM] to achieve this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
&lt;br /&gt;
    // Use FIPR to accelerate first two dot products independently&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 2; ++i) {&lt;br /&gt;
        float distance = shz_vec3_dot(s-&amp;gt;center, p-&amp;gt;plane) - p-&amp;gt;plane.distance;&lt;br /&gt;
&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
&lt;br /&gt;
	    p++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Since each plane is a 4D vector, we can load each one as a column vector&lt;br /&gt;
       into XMTRX, creating a 4x4 matrix out of the 4 planes. */&lt;br /&gt;
    shz_xmtrx_load_4x4_cols(&amp;amp;p[0].plane, &amp;amp;p[1].plane, &amp;amp;p[2].plane, &amp;amp;p[3].plane);&lt;br /&gt;
&lt;br /&gt;
    /* Now we transform our constant vector, the bounding sphere&#039;s center, against&lt;br /&gt;
       our 4 plane vectors. This gives us a result vector where the value of each&lt;br /&gt;
       component is equal to the dot product between the sphere&#039;s centroid and the&lt;br /&gt;
       corresponding plane column vector. */&lt;br /&gt;
	shz_vec4_t distances = shz_xmtrx_trans_vec4(shz_vec4_t(s-&amp;gt;center, -1.0f));&lt;br /&gt;
&lt;br /&gt;
    /* Now we simply iterate over each of our 4 result components to check&lt;br /&gt;
       for intersection. */&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 4; ++i) {&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distances.elem[i])&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distances.elem[i])&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
	return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ADPCM Decoding===&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3805</id>
		<title>SH4 FTRV Optimizations</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3805"/>
		<updated>2025-08-06T08:13:07Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: /* Bounding Sphere vs View Frustum Culling */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Without a doubt, the single most computationally powerful instruction on the SuperH4 CPU in the Sega Dreamcast is &#039;&#039;&#039;FTRV&#039;&#039;&#039;, or the &#039;&#039;&#039;F&#039;&#039;&#039;loating-point &#039;&#039;&#039;TR&#039;&#039;&#039;ansform &#039;&#039;&#039;V&#039;&#039;&#039;ector instruction. It is a single instruction which multiplies a 4D vector by the 4x4 matrix held within the back-bank of FPU registers, &#039;&#039;&#039;XMTRX&#039;&#039;&#039;. This article will teach you how to leverage this god instruction for FP performance gainz and introduce you to several example scenarios that have yielded fantastic gainz within the community.&lt;br /&gt;
&lt;br /&gt;
==Relationship to FIPR==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Instruction Summaries&lt;br /&gt;
|-&lt;br /&gt;
! Format !! Function !! Encoding !! Group !! Issue Cycles !! Latency Cycles&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fipr&#039;&#039;&#039;	FVm,FVn || inner_product (FVm, FVn) -&amp;gt; FR[n+3] || 1111nnmm11101101 || FE || 1 || 4/5&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ftrv&#039;&#039;&#039; XMTRX, FVn || transform_vector(XMTRX, FVn) -&amp;gt; FVn || 1111nn0111111101 || FE || 1 || 5/8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==When to use FTRV==&lt;br /&gt;
There are two things to look out for when developing an intuition for when you can leverage FTRV:&lt;br /&gt;
# There are 3 or more dot products (ax + by + cz + dw) being calculated back-to-back.&lt;br /&gt;
# One of the vectors is held constant while the other vector argument is variable across each.&lt;br /&gt;
&lt;br /&gt;
When you see such a scenario, the first thing that should pop into your head is that you are dealing with a vector x matrix transform, and you can use &#039;&#039;&#039;FTRV&#039;&#039;&#039; to accelerate it.&lt;br /&gt;
&lt;br /&gt;
==Real-World Examples==&lt;br /&gt;
The following are real-world examples of FTRV-based optimizations used within games and applications for the Sega Dreamcast within the community.&lt;br /&gt;
===Vertex Position Transformation===&lt;br /&gt;
The first and most obvious use of the FTRV instruction is for doing position transform calculations on the incoming vertex stream, transforming from local to view-space, while submitting vertices to the PowerVR during T&amp;amp;L. This is the first and absolute most crucial area for leveraging FTRV and was its original intended purpose. If you do nothing else with the instruction, bear in mind that the only way to come even remotely close to pushing a considerable volume of polygons on the DC is by properly harnessing the SH4 by using FTRV to transform your vertices.&lt;br /&gt;
&lt;br /&gt;
===Diffuse Lighting===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Collision and Physics===&lt;br /&gt;
===Bounding Sphere vs View Frustum Culling===&lt;br /&gt;
The following code snippet is taken from the DCA3 codebase as part of its Renderware driver back-end for Dreamcast. To check for intersection between a bounding sphere and the view frustum, you must compute the dot product between the centroid of the bounding sphere against all 6 of the view frustum planes. The result of each dot product represents the sphere&#039;s distance from that plane.&lt;br /&gt;
&lt;br /&gt;
The original algorithm was as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
&lt;br /&gt;
    // Iterate over each of the 6 frustum planes.&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
	for(int32 i = 0; i &amp;lt; 6; i++){&lt;br /&gt;
        // Compute dot product between each plane and the centroid.&lt;br /&gt;
        // Your FIPR senses should be tingling, since we&#039;ve got dot products!&lt;br /&gt;
		float32 distance = dot(p-&amp;gt;plane, s-&amp;gt;center) - p-&amp;gt;plane.distance;&lt;br /&gt;
		&lt;br /&gt;
        if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
			return SPHEREOUTSIDE; // No intersection&lt;br /&gt;
		if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
			res = SPHEREBOUNDARY; // Intersection&lt;br /&gt;
		&lt;br /&gt;
        p++;&lt;br /&gt;
	}&lt;br /&gt;
    return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we have a scenario where we have 4+ dot products being taken where one of the vectors remains constant for each, this is a textbook case for using FTRV to compute 4 of them in parallel.&lt;br /&gt;
&lt;br /&gt;
So we use FIPR to accelerate two of the dot products and FTRV for the other 4 of them at once. The following code uses [https://github.com/gyrovorbis/sh4zam libSH4ZAM] to achieve this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
&lt;br /&gt;
    // Use FIPR to accelerate first two dot products independently&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 2; ++i) {&lt;br /&gt;
        float distance = shz_vec3_dot(s-&amp;gt;center, p-&amp;gt;plane) - p-&amp;gt;plane.distance;&lt;br /&gt;
&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
&lt;br /&gt;
	    p++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Since each plane is a 4D vector, we can load each one as a column vector&lt;br /&gt;
       into XMTRX, creating a 4x4 matrix out of the 4 planes. */&lt;br /&gt;
    shz_xmtrx_load_4x4_cols(&amp;amp;p[0].plane, &amp;amp;p[1].plane, &amp;amp;p[2].plane, &amp;amp;p[3].plane);&lt;br /&gt;
&lt;br /&gt;
    /* Now we transform our constant vector, the bounding sphere&#039;s center, against&lt;br /&gt;
       our 4 plane vectors. This gives us a result vector where the value of each&lt;br /&gt;
       component is equal to the dot product between the sphere&#039;s centroid and the&lt;br /&gt;
       corresponding plane column vector. */&lt;br /&gt;
	shz_vec4_t distances = shz_xmtrx_trans_vec4(shz_vec4_t(s-&amp;gt;center, -1.0f));&lt;br /&gt;
&lt;br /&gt;
    /* Now we simply iterate over each of our 4 result components to check&lt;br /&gt;
       for intersection. */&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 4; ++i) {&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distances.elem[0])&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distances.elem[0])&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
	return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ADPCM Decoding===&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3804</id>
		<title>SH4 FTRV Optimizations</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3804"/>
		<updated>2025-08-06T08:11:35Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: /* Bounding Sphere vs View Frustum Culling */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Without a doubt, the single most computationally powerful instruction on the SuperH4 CPU in the Sega Dreamcast is &#039;&#039;&#039;FTRV&#039;&#039;&#039;, or the &#039;&#039;&#039;F&#039;&#039;&#039;loating-point &#039;&#039;&#039;TR&#039;&#039;&#039;ansform &#039;&#039;&#039;V&#039;&#039;&#039;ector instruction. It is a single instruction which multiplies a 4D vector by the 4x4 matrix held within the back-bank of FPU registers, &#039;&#039;&#039;XMTRX&#039;&#039;&#039;. This article will teach you how to leverage this god instruction for FP performance gainz and introduce you to several example scenarios that have yielded fantastic gainz within the community.&lt;br /&gt;
&lt;br /&gt;
==Relationship to FIPR==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Instruction Summaries&lt;br /&gt;
|-&lt;br /&gt;
! Format !! Function !! Encoding !! Group !! Issue Cycles !! Latency Cycles&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fipr&#039;&#039;&#039;	FVm,FVn || inner_product (FVm, FVn) -&amp;gt; FR[n+3] || 1111nnmm11101101 || FE || 1 || 4/5&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ftrv&#039;&#039;&#039; XMTRX, FVn || transform_vector(XMTRX, FVn) -&amp;gt; FVn || 1111nn0111111101 || FE || 1 || 5/8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==When to use FTRV==&lt;br /&gt;
There are two things to look out for when developing an intuition for when you can leverage FTRV:&lt;br /&gt;
# There are 3 or more dot products (ax + by + cz + dw) being calculated back-to-back.&lt;br /&gt;
# One of the vectors is held constant while the other vector argument is variable across each.&lt;br /&gt;
&lt;br /&gt;
When you see such a scenario, the first thing that should pop into your head is that you are dealing with a vector x matrix transform, and you can use &#039;&#039;&#039;FTRV&#039;&#039;&#039; to accelerate it.&lt;br /&gt;
&lt;br /&gt;
==Real-World Examples==&lt;br /&gt;
The following are real-world examples of FTRV-based optimizations used within games and applications for the Sega Dreamcast within the community.&lt;br /&gt;
===Vertex Position Transformation===&lt;br /&gt;
The first and most obvious use of the FTRV instruction is for doing position transform calculations on the incoming vertex stream, transforming from local to view-space, while submitting vertices to the PowerVR during T&amp;amp;L. This is the first and absolute most crucial area for leveraging FTRV and was its original intended purpose. If you do nothing else with the instruction, bear in mind that the only way to come even remotely close to pushing a considerable volume of polygons on the DC is by properly harnessing the SH4 by using FTRV to transform your vertices.&lt;br /&gt;
&lt;br /&gt;
===Diffuse Lighting===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Collision and Physics===&lt;br /&gt;
===Bounding Sphere vs View Frustum Culling===&lt;br /&gt;
The following code snippet is taken from the DCA3 codebase as part of its Renderware driver back-end for Dreamcast. To check for intersection between a bounding sphere and the view frustum, you must compute the dot product between the centroid of the bounding sphere against all 6 of the view frustum planes. The result of each dot product represents the sphere&#039;s distance from that plane.&lt;br /&gt;
&lt;br /&gt;
The original algorithm was as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
&lt;br /&gt;
    // Iterate over each of the 6 frustum planes.&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
	for(int32 i = 0; i &amp;lt; 6; i++){&lt;br /&gt;
        // Compute dot product between each plane and the centroid.&lt;br /&gt;
        // Your FIPR senses should be tingling, since we&#039;ve got dot products!&lt;br /&gt;
		float32 distance = dot(p-&amp;gt;plane, s-&amp;gt;center) - p-&amp;gt;plane.distance;&lt;br /&gt;
		&lt;br /&gt;
        if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
			return SPHEREOUTSIDE; // No intersection&lt;br /&gt;
		if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
			res = SPHEREBOUNDARY; // Intersection&lt;br /&gt;
		&lt;br /&gt;
        p++;&lt;br /&gt;
	}&lt;br /&gt;
    return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we have a scenario where we have 4+ dot products being taken where one of the vectors remains constant for each, this is a textbook case for using FTRV to compute 4 of them in parallel.&lt;br /&gt;
&lt;br /&gt;
So we use FIPR to accelerate two of the dot products and FTRV for the other 4 of them at once. The following code uses [https://github.com/gyrovorbis/sh4zam libSH4ZAM] to achieve this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
&lt;br /&gt;
    // Use FIPR to accelerate first two dot products independently&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 2; ++i) {&lt;br /&gt;
        float distance = shz_vec3_dot(s-&amp;gt;center, p-&amp;gt;plane) - p-&amp;gt;plane.distance;&lt;br /&gt;
&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
&lt;br /&gt;
	    p++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Since each plane is a 4D vector, we can load each one as a column vector&lt;br /&gt;
       into XMTRX, creating a 4x4 matrix out of the 4 planes. */&lt;br /&gt;
    shz_xmtrx_load_4x4_cols(&amp;amp;p[0].plane, &amp;amp;p[1].plane, &amp;amp;p[2].plane, &amp;amp;p[3].plane);&lt;br /&gt;
&lt;br /&gt;
    /* Now we transform our constant vector, the bounding sphere&#039;s center, against&lt;br /&gt;
       our 4 plane vectors. This gives us a result vector where the value of each&lt;br /&gt;
       component is equal to the dot product between the sphere&#039;s centroid and the&lt;br /&gt;
       corresponding plane column vector. */&lt;br /&gt;
	shz_vec4_t distances = shz_xmtrx_trans_vec4(s-&amp;gt;center);&lt;br /&gt;
&lt;br /&gt;
    /* Now we simply iterate over each of our 4 result components to check&lt;br /&gt;
       for intersection. */&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 4; ++i) {&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distances.elem[0])&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distances.elem[0])&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
	return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ADPCM Decoding===&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3803</id>
		<title>SH4 FTRV Optimizations</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3803"/>
		<updated>2025-08-06T08:04:52Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: /* When to use FTRV */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Without a doubt, the single most computationally powerful instruction on the SuperH4 CPU in the Sega Dreamcast is &#039;&#039;&#039;FTRV&#039;&#039;&#039;, or the &#039;&#039;&#039;F&#039;&#039;&#039;loating-point &#039;&#039;&#039;TR&#039;&#039;&#039;ansform &#039;&#039;&#039;V&#039;&#039;&#039;ector instruction. It is a single instruction which multiplies a 4D vector by the 4x4 matrix held within the back-bank of FPU registers, &#039;&#039;&#039;XMTRX&#039;&#039;&#039;. This article will teach you how to leverage this god instruction for FP performance gainz and introduce you to several example scenarios that have yielded fantastic gainz within the community.&lt;br /&gt;
&lt;br /&gt;
==Relationship to FIPR==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Instruction Summaries&lt;br /&gt;
|-&lt;br /&gt;
! Format !! Function !! Encoding !! Group !! Issue Cycles !! Latency Cycles&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fipr&#039;&#039;&#039;	FVm,FVn || inner_product (FVm, FVn) -&amp;gt; FR[n+3] || 1111nnmm11101101 || FE || 1 || 4/5&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ftrv&#039;&#039;&#039; XMTRX, FVn || transform_vector(XMTRX, FVn) -&amp;gt; FVn || 1111nn0111111101 || FE || 1 || 5/8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==When to use FTRV==&lt;br /&gt;
There are two things to look out for when developing an intuition for when you can leverage FTRV:&lt;br /&gt;
# There are 3 or more dot products (ax + by + cz + dw) being calculated back-to-back.&lt;br /&gt;
# One of the vectors is held constant while the other vector argument is variable across each.&lt;br /&gt;
&lt;br /&gt;
When you see such a scenario, the first thing that should pop into your head is that you are dealing with a vector x matrix transform, and you can use &#039;&#039;&#039;FTRV&#039;&#039;&#039; to accelerate it.&lt;br /&gt;
&lt;br /&gt;
==Real-World Examples==&lt;br /&gt;
The following are real-world examples of FTRV-based optimizations used within games and applications for the Sega Dreamcast within the community.&lt;br /&gt;
===Vertex Position Transformation===&lt;br /&gt;
The first and most obvious use of the FTRV instruction is for doing position transform calculations on the incoming vertex stream, transforming from local to view-space, while submitting vertices to the PowerVR during T&amp;amp;L. This is the first and absolute most crucial area for leveraging FTRV and was its original intended purpose. If you do nothing else with the instruction, bear in mind that the only way to come even remotely close to pushing a considerable volume of polygons on the DC is by properly harnessing the SH4 by using FTRV to transform your vertices.&lt;br /&gt;
&lt;br /&gt;
===Diffuse Lighting===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Collision and Physics===&lt;br /&gt;
===Bounding Sphere vs View Frustum Culling===&lt;br /&gt;
The following code snippet is taken from the DCA3 codebase as part of its Renderware driver back-end for Dreamcast. To check for intersection between a bounding sphere and the view frustum, you must compute the dot product between the centroid of the bounding sphere against all 6 of the view frustum planes. The result of each dot product represents the sphere&#039;s distance from that plane.&lt;br /&gt;
&lt;br /&gt;
The original algorithm was as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
&lt;br /&gt;
    // Iterate over each of the 6 frustum planes.&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
	for(int32 i = 0; i &amp;lt; 6; i++){&lt;br /&gt;
        // Compute dot product between each plane and the centroid.&lt;br /&gt;
        // Your FIPR senses should be tingling, since we&#039;ve got dot products!&lt;br /&gt;
		float32 distance = dot(p-&amp;gt;plane, s-&amp;gt;center) - p-&amp;gt;plane.distance;&lt;br /&gt;
		&lt;br /&gt;
        if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
			return SPHEREOUTSIDE; // No intersection&lt;br /&gt;
		if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
			res = SPHEREBOUNDARY; // Intersection&lt;br /&gt;
		&lt;br /&gt;
        p++;&lt;br /&gt;
	}&lt;br /&gt;
    return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we have a scenario where we have 4+ dot products being taken where one of the vectors remains constant for each, this is a textbook case for using FTRV to compute 4 of them in parallel.&lt;br /&gt;
&lt;br /&gt;
So we use FIPR to accelerate two of the dot products and FTRV for the other 4 of them at once. The following code uses [https://github.com/gyrovorbis/sh4zam libSH4ZAM] to achieve this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
&lt;br /&gt;
    // Use FIPR to accelerate first two dot products independently&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 2; ++i) {&lt;br /&gt;
        float distance = shz_vec4_dot(s-&amp;gt;center, p-&amp;gt;plane);&lt;br /&gt;
&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
&lt;br /&gt;
	    p++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Since each plane is a 4D vector, we can load each one as a column vector&lt;br /&gt;
       into XMTRX, creating a 4x4 matrix out of the 4 planes. */&lt;br /&gt;
    shz_xmtrx_load_4x4_cols(&amp;amp;p[0].plane, &amp;amp;p[1].plane, &amp;amp;p[2].plane, &amp;amp;p[3].plane);&lt;br /&gt;
&lt;br /&gt;
    /* Now we transform our constant vector, the bounding sphere&#039;s center, against&lt;br /&gt;
       our 4 plane vectors. This gives us a result vector where the value of each&lt;br /&gt;
       component is equal to the dot product between the sphere&#039;s centroid and the&lt;br /&gt;
       corresponding plane column vector. */&lt;br /&gt;
	shz_vec4_t distances = shz_xmtrx_trans_vec4(s-&amp;gt;center);&lt;br /&gt;
&lt;br /&gt;
    /* Now we simply iterate over each of our 4 result components to check&lt;br /&gt;
       for intersection. */&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 4; ++i) {&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distances.elem[0])&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distances.elem[0])&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
	return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ADPCM Decoding===&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3802</id>
		<title>SH4 FTRV Optimizations</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3802"/>
		<updated>2025-08-06T08:04:16Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: /* When to use FTRV */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Without a doubt, the single most computationally powerful instruction on the SuperH4 CPU in the Sega Dreamcast is &#039;&#039;&#039;FTRV&#039;&#039;&#039;, or the &#039;&#039;&#039;F&#039;&#039;&#039;loating-point &#039;&#039;&#039;TR&#039;&#039;&#039;ansform &#039;&#039;&#039;V&#039;&#039;&#039;ector instruction. It is a single instruction which multiplies a 4D vector by the 4x4 matrix held within the back-bank of FPU registers, &#039;&#039;&#039;XMTRX&#039;&#039;&#039;. This article will teach you how to leverage this god instruction for FP performance gainz and introduce you to several example scenarios that have yielded fantastic gainz within the community.&lt;br /&gt;
&lt;br /&gt;
==Relationship to FIPR==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Instruction Summaries&lt;br /&gt;
|-&lt;br /&gt;
! Format !! Function !! Encoding !! Group !! Issue Cycles !! Latency Cycles&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fipr&#039;&#039;&#039;	FVm,FVn || inner_product (FVm, FVn) -&amp;gt; FR[n+3] || 1111nnmm11101101 || FE || 1 || 4/5&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ftrv&#039;&#039;&#039; XMTRX, FVn || transform_vector(XMTRX, FVn) -&amp;gt; FVn || 1111nn0111111101 || FE || 1 || 5/8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==When to use FTRV==&lt;br /&gt;
There are two things to look out for when developing an intuition for when you can leverage FTRV:&lt;br /&gt;
# There are 3 or more dot products (ax + by + cz + dw) being calculated back-to-back.&lt;br /&gt;
# One of the vectors is held constant while the other vector argument is variable.&lt;br /&gt;
&lt;br /&gt;
When you see such a scenario, the first thing that should pop into your head is that you are dealing with a vector x matrix transform, and you can use &#039;&#039;&#039;FTRV&#039;&#039;&#039; to accelerate it.&lt;br /&gt;
&lt;br /&gt;
==Real-World Examples==&lt;br /&gt;
The following are real-world examples of FTRV-based optimizations used within games and applications for the Sega Dreamcast within the community.&lt;br /&gt;
===Vertex Position Transformation===&lt;br /&gt;
The first and most obvious use of the FTRV instruction is for doing position transform calculations on the incoming vertex stream, transforming from local to view-space, while submitting vertices to the PowerVR during T&amp;amp;L. This is the first and absolute most crucial area for leveraging FTRV and was its original intended purpose. If you do nothing else with the instruction, bear in mind that the only way to come even remotely close to pushing a considerable volume of polygons on the DC is by properly harnessing the SH4 by using FTRV to transform your vertices.&lt;br /&gt;
&lt;br /&gt;
===Diffuse Lighting===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Collision and Physics===&lt;br /&gt;
===Bounding Sphere vs View Frustum Culling===&lt;br /&gt;
The following code snippet is taken from the DCA3 codebase as part of its Renderware driver back-end for Dreamcast. To check for intersection between a bounding sphere and the view frustum, you must compute the dot product between the centroid of the bounding sphere against all 6 of the view frustum planes. The result of each dot product represents the sphere&#039;s distance from that plane.&lt;br /&gt;
&lt;br /&gt;
The original algorithm was as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
&lt;br /&gt;
    // Iterate over each of the 6 frustum planes.&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
	for(int32 i = 0; i &amp;lt; 6; i++){&lt;br /&gt;
        // Compute dot product between each plane and the centroid.&lt;br /&gt;
        // Your FIPR senses should be tingling, since we&#039;ve got dot products!&lt;br /&gt;
		float32 distance = dot(p-&amp;gt;plane, s-&amp;gt;center) - p-&amp;gt;plane.distance;&lt;br /&gt;
		&lt;br /&gt;
        if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
			return SPHEREOUTSIDE; // No intersection&lt;br /&gt;
		if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
			res = SPHEREBOUNDARY; // Intersection&lt;br /&gt;
		&lt;br /&gt;
        p++;&lt;br /&gt;
	}&lt;br /&gt;
    return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we have a scenario where we have 4+ dot products being taken where one of the vectors remains constant for each, this is a textbook case for using FTRV to compute 4 of them in parallel.&lt;br /&gt;
&lt;br /&gt;
So we use FIPR to accelerate two of the dot products and FTRV for the other 4 of them at once. The following code uses [https://github.com/gyrovorbis/sh4zam libSH4ZAM] to achieve this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
&lt;br /&gt;
    // Use FIPR to accelerate first two dot products independently&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 2; ++i) {&lt;br /&gt;
        float distance = shz_vec4_dot(s-&amp;gt;center, p-&amp;gt;plane);&lt;br /&gt;
&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
&lt;br /&gt;
	    p++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Since each plane is a 4D vector, we can load each one as a column vector&lt;br /&gt;
       into XMTRX, creating a 4x4 matrix out of the 4 planes. */&lt;br /&gt;
    shz_xmtrx_load_4x4_cols(&amp;amp;p[0].plane, &amp;amp;p[1].plane, &amp;amp;p[2].plane, &amp;amp;p[3].plane);&lt;br /&gt;
&lt;br /&gt;
    /* Now we transform our constant vector, the bounding sphere&#039;s center, against&lt;br /&gt;
       our 4 plane vectors. This gives us a result vector where the value of each&lt;br /&gt;
       component is equal to the dot product between the sphere&#039;s centroid and the&lt;br /&gt;
       corresponding plane column vector. */&lt;br /&gt;
	shz_vec4_t distances = shz_xmtrx_trans_vec4(s-&amp;gt;center);&lt;br /&gt;
&lt;br /&gt;
    /* Now we simply iterate over each of our 4 result components to check&lt;br /&gt;
       for intersection. */&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 4; ++i) {&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distances.elem[0])&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distances.elem[0])&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
	return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ADPCM Decoding===&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3801</id>
		<title>SH4 FTRV Optimizations</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3801"/>
		<updated>2025-08-06T07:57:49Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: /* Bounding Sphere vs View Frustum Culling */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Without a doubt, the single most computationally powerful instruction on the SuperH4 CPU in the Sega Dreamcast is &#039;&#039;&#039;FTRV&#039;&#039;&#039;, or the &#039;&#039;&#039;F&#039;&#039;&#039;loating-point &#039;&#039;&#039;TR&#039;&#039;&#039;ansform &#039;&#039;&#039;V&#039;&#039;&#039;ector instruction. It is a single instruction which multiplies a 4D vector by the 4x4 matrix held within the back-bank of FPU registers, &#039;&#039;&#039;XMTRX&#039;&#039;&#039;. This article will teach you how to leverage this god instruction for FP performance gainz and introduce you to several example scenarios that have yielded fantastic gainz within the community.&lt;br /&gt;
&lt;br /&gt;
==Relationship to FIPR==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Instruction Summaries&lt;br /&gt;
|-&lt;br /&gt;
! Format !! Function !! Encoding !! Group !! Issue Cycles !! Latency Cycles&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fipr&#039;&#039;&#039;	FVm,FVn || inner_product (FVm, FVn) -&amp;gt; FR[n+3] || 1111nnmm11101101 || FE || 1 || 4/5&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ftrv&#039;&#039;&#039; XMTRX, FVn || transform_vector(XMTRX, FVn) -&amp;gt; FVn || 1111nn0111111101 || FE || 1 || 5/8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==When to use FTRV==&lt;br /&gt;
&lt;br /&gt;
==Real-World Examples==&lt;br /&gt;
The following are real-world examples of FTRV-based optimizations used within games and applications for the Sega Dreamcast within the community.&lt;br /&gt;
===Vertex Position Transformation===&lt;br /&gt;
The first and most obvious use of the FTRV instruction is for doing position transform calculations on the incoming vertex stream, transforming from local to view-space, while submitting vertices to the PowerVR during T&amp;amp;L. This is the first and absolute most crucial area for leveraging FTRV and was its original intended purpose. If you do nothing else with the instruction, bear in mind that the only way to come even remotely close to pushing a considerable volume of polygons on the DC is by properly harnessing the SH4 by using FTRV to transform your vertices.&lt;br /&gt;
&lt;br /&gt;
===Diffuse Lighting===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Collision and Physics===&lt;br /&gt;
===Bounding Sphere vs View Frustum Culling===&lt;br /&gt;
The following code snippet is taken from the DCA3 codebase as part of its Renderware driver back-end for Dreamcast. To check for intersection between a bounding sphere and the view frustum, you must compute the dot product between the centroid of the bounding sphere against all 6 of the view frustum planes. The result of each dot product represents the sphere&#039;s distance from that plane.&lt;br /&gt;
&lt;br /&gt;
The original algorithm was as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
&lt;br /&gt;
    // Iterate over each of the 6 frustum planes.&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
	for(int32 i = 0; i &amp;lt; 6; i++){&lt;br /&gt;
        // Compute dot product between each plane and the centroid.&lt;br /&gt;
        // Your FIPR senses should be tingling, since we&#039;ve got dot products!&lt;br /&gt;
		float32 distance = dot(p-&amp;gt;plane, s-&amp;gt;center) - p-&amp;gt;plane.distance;&lt;br /&gt;
		&lt;br /&gt;
        if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
			return SPHEREOUTSIDE; // No intersection&lt;br /&gt;
		if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
			res = SPHEREBOUNDARY; // Intersection&lt;br /&gt;
		&lt;br /&gt;
        p++;&lt;br /&gt;
	}&lt;br /&gt;
    return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we have a scenario where we have 4+ dot products being taken where one of the vectors remains constant for each, this is a textbook case for using FTRV to compute 4 of them in parallel.&lt;br /&gt;
&lt;br /&gt;
So we use FIPR to accelerate two of the dot products and FTRV for the other 4 of them at once. The following code uses [https://github.com/gyrovorbis/sh4zam libSH4ZAM] to achieve this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
&lt;br /&gt;
    // Use FIPR to accelerate first two dot products independently&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 2; ++i) {&lt;br /&gt;
        float distance = shz_vec4_dot(s-&amp;gt;center, p-&amp;gt;plane);&lt;br /&gt;
&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
&lt;br /&gt;
	    p++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Since each plane is a 4D vector, we can load each one as a column vector&lt;br /&gt;
       into XMTRX, creating a 4x4 matrix out of the 4 planes. */&lt;br /&gt;
    shz_xmtrx_load_4x4_cols(&amp;amp;p[0].plane, &amp;amp;p[1].plane, &amp;amp;p[2].plane, &amp;amp;p[3].plane);&lt;br /&gt;
&lt;br /&gt;
    /* Now we transform our constant vector, the bounding sphere&#039;s center, against&lt;br /&gt;
       our 4 plane vectors. This gives us a result vector where the value of each&lt;br /&gt;
       component is equal to the dot product between the sphere&#039;s centroid and the&lt;br /&gt;
       corresponding plane column vector. */&lt;br /&gt;
	shz_vec4_t distances = shz_xmtrx_trans_vec4(s-&amp;gt;center);&lt;br /&gt;
&lt;br /&gt;
    /* Now we simply iterate over each of our 4 result components to check&lt;br /&gt;
       for intersection. */&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 4; ++i) {&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distances.elem[0])&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distances.elem[0])&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
	return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ADPCM Decoding===&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3800</id>
		<title>SH4 FTRV Optimizations</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3800"/>
		<updated>2025-08-06T07:54:55Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: /* Bounding Sphere vs View Frustum Culling */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Without a doubt, the single most computationally powerful instruction on the SuperH4 CPU in the Sega Dreamcast is &#039;&#039;&#039;FTRV&#039;&#039;&#039;, or the &#039;&#039;&#039;F&#039;&#039;&#039;loating-point &#039;&#039;&#039;TR&#039;&#039;&#039;ansform &#039;&#039;&#039;V&#039;&#039;&#039;ector instruction. It is a single instruction which multiplies a 4D vector by the 4x4 matrix held within the back-bank of FPU registers, &#039;&#039;&#039;XMTRX&#039;&#039;&#039;. This article will teach you how to leverage this god instruction for FP performance gainz and introduce you to several example scenarios that have yielded fantastic gainz within the community.&lt;br /&gt;
&lt;br /&gt;
==Relationship to FIPR==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Instruction Summaries&lt;br /&gt;
|-&lt;br /&gt;
! Format !! Function !! Encoding !! Group !! Issue Cycles !! Latency Cycles&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fipr&#039;&#039;&#039;	FVm,FVn || inner_product (FVm, FVn) -&amp;gt; FR[n+3] || 1111nnmm11101101 || FE || 1 || 4/5&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ftrv&#039;&#039;&#039; XMTRX, FVn || transform_vector(XMTRX, FVn) -&amp;gt; FVn || 1111nn0111111101 || FE || 1 || 5/8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==When to use FTRV==&lt;br /&gt;
&lt;br /&gt;
==Real-World Examples==&lt;br /&gt;
The following are real-world examples of FTRV-based optimizations used within games and applications for the Sega Dreamcast within the community.&lt;br /&gt;
===Vertex Position Transformation===&lt;br /&gt;
The first and most obvious use of the FTRV instruction is for doing position transform calculations on the incoming vertex stream, transforming from local to view-space, while submitting vertices to the PowerVR during T&amp;amp;L. This is the first and absolute most crucial area for leveraging FTRV and was its original intended purpose. If you do nothing else with the instruction, bear in mind that the only way to come even remotely close to pushing a considerable volume of polygons on the DC is by properly harnessing the SH4 by using FTRV to transform your vertices.&lt;br /&gt;
&lt;br /&gt;
===Diffuse Lighting===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Collision and Physics===&lt;br /&gt;
===Bounding Sphere vs View Frustum Culling===&lt;br /&gt;
The following code snippet is taken from the DCA3 codebase as part of its Renderware driver back-end for Dreamcast. To check for intersection between a bounding sphere and the view frustum, you must compute the dot product between the centroid of the bounding sphere against all 6 of the view frustum planes. The result of each dot product represents the sphere&#039;s distance from that plane.&lt;br /&gt;
&lt;br /&gt;
The original algorithm was as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
&lt;br /&gt;
    // Iterate over each of the 6 frustum planes.&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
	for(int32 i = 0; i &amp;lt; 6; i++){&lt;br /&gt;
        // Compute dot product between each plane and the centroid.&lt;br /&gt;
        // Your FIPR senses should be tingling, since we&#039;ve got dot products!&lt;br /&gt;
		float32 distance = dot(p-&amp;gt;plane, s-&amp;gt;center) - p-&amp;gt;plane.distance;&lt;br /&gt;
		&lt;br /&gt;
        if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
			return SPHEREOUTSIDE; // No intersection&lt;br /&gt;
		if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
			res = SPHEREBOUNDARY; // Intersection&lt;br /&gt;
		&lt;br /&gt;
        p++;&lt;br /&gt;
	}&lt;br /&gt;
    return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we have a scenario where we have 4+ dot products being taken where one of the vectors remains constant for each, this is a textbook case for using FTRV to compute 4 of them in parallel.&lt;br /&gt;
&lt;br /&gt;
So we use FIPR to accelerate two of the dot products and FTRV for the other 4 of them at once. The following code uses [https://github.com/gyrovorbis/sh4zam libSH4ZAM] to achieve this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
&lt;br /&gt;
    // Use FIPR to accelerate first two dot products independently&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 2; ++i) {&lt;br /&gt;
        float distance = shz_vec4_dot(s-&amp;gt;center, p-&amp;gt;plane);&lt;br /&gt;
&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
	    p++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Since each plane is a 4D vector, we can load each one as a column vector&lt;br /&gt;
       into XMTRX, creating a 4x4 matrix out of the 4 planes. */&lt;br /&gt;
    shz_xmtrx_load_4x4_cols(&amp;amp;p[0].plane, &amp;amp;p[1].plane, &amp;amp;p[2].plane, &amp;amp;p[3].plane);&lt;br /&gt;
&lt;br /&gt;
    /* Now we transform our constant vector, the bounding sphere&#039;s center, against&lt;br /&gt;
       our 4 plane vectors. This gives us a result vector where the value of each&lt;br /&gt;
       component is equal to the dot product between the sphere&#039;s centroid and the&lt;br /&gt;
       corresponding plane column vector. */&lt;br /&gt;
	shz_vec4_t distances = shz_xmtrx_trans_vec4(s-&amp;gt;center);&lt;br /&gt;
&lt;br /&gt;
    /* Now we simply iterate over each of our 4 result components to check&lt;br /&gt;
       for intersection. */&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 4; ++i) {&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distances.elem[0])&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distances.elem[0])&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
	return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ADPCM Decoding===&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3799</id>
		<title>SH4 FTRV Optimizations</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3799"/>
		<updated>2025-08-06T07:53:52Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: /* Bounding Sphere vs View Frustum Culling */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Without a doubt, the single most computationally powerful instruction on the SuperH4 CPU in the Sega Dreamcast is &#039;&#039;&#039;FTRV&#039;&#039;&#039;, or the &#039;&#039;&#039;F&#039;&#039;&#039;loating-point &#039;&#039;&#039;TR&#039;&#039;&#039;ansform &#039;&#039;&#039;V&#039;&#039;&#039;ector instruction. It is a single instruction which multiplies a 4D vector by the 4x4 matrix held within the back-bank of FPU registers, &#039;&#039;&#039;XMTRX&#039;&#039;&#039;. This article will teach you how to leverage this god instruction for FP performance gainz and introduce you to several example scenarios that have yielded fantastic gainz within the community.&lt;br /&gt;
&lt;br /&gt;
==Relationship to FIPR==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Instruction Summaries&lt;br /&gt;
|-&lt;br /&gt;
! Format !! Function !! Encoding !! Group !! Issue Cycles !! Latency Cycles&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fipr&#039;&#039;&#039;	FVm,FVn || inner_product (FVm, FVn) -&amp;gt; FR[n+3] || 1111nnmm11101101 || FE || 1 || 4/5&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ftrv&#039;&#039;&#039; XMTRX, FVn || transform_vector(XMTRX, FVn) -&amp;gt; FVn || 1111nn0111111101 || FE || 1 || 5/8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==When to use FTRV==&lt;br /&gt;
&lt;br /&gt;
==Real-World Examples==&lt;br /&gt;
The following are real-world examples of FTRV-based optimizations used within games and applications for the Sega Dreamcast within the community.&lt;br /&gt;
===Vertex Position Transformation===&lt;br /&gt;
The first and most obvious use of the FTRV instruction is for doing position transform calculations on the incoming vertex stream, transforming from local to view-space, while submitting vertices to the PowerVR during T&amp;amp;L. This is the first and absolute most crucial area for leveraging FTRV and was its original intended purpose. If you do nothing else with the instruction, bear in mind that the only way to come even remotely close to pushing a considerable volume of polygons on the DC is by properly harnessing the SH4 by using FTRV to transform your vertices.&lt;br /&gt;
&lt;br /&gt;
===Diffuse Lighting===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Collision and Physics===&lt;br /&gt;
===Bounding Sphere vs View Frustum Culling===&lt;br /&gt;
The following code snippet is taken from the DCA3 codebase as part of its Renderware driver back-end for Dreamcast. To check for intersection between a bounding sphere and the view frustum, you must compute the dot product between the centroid of the bounding sphere against all 6 of the view frustum planes. The result of each dot product represents the sphere&#039;s distance from that plane.&lt;br /&gt;
&lt;br /&gt;
The original algorithm was as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
&lt;br /&gt;
    // Iterate over each of the 6 frustum planes.&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
	for(int32 i = 0; i &amp;lt; 6; i++){&lt;br /&gt;
        // Compute dot product between each plane and the centroid.&lt;br /&gt;
        // Your FIPR senses should be tingling, since we&#039;ve got dot products!&lt;br /&gt;
		float32 distance = dot(p-&amp;gt;plane, s-&amp;gt;center) - p-&amp;gt;plane.distance;&lt;br /&gt;
		&lt;br /&gt;
        if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
			return SPHEREOUTSIDE; // No intersection&lt;br /&gt;
		if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
			res = SPHEREBOUNDARY; // Intersection&lt;br /&gt;
		&lt;br /&gt;
        p++;&lt;br /&gt;
	}&lt;br /&gt;
    return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we have a scenario where we have 4+ dot products being taken where one of the vectors remains constant for each, this is a textbook case for using FTRV to compute 4 of them in parallel.&lt;br /&gt;
&lt;br /&gt;
So we use FIPR to accelerate two of the dot products and FTRV for the other 4 of them at once. The following code uses [https://github.com/gyrovorbis/sh4zam libSH4ZAM] to achieve this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
&lt;br /&gt;
    // Use FIPR to accelerate first two dot products independently&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 2; ++i) {&lt;br /&gt;
        float distance = shz_vec4_dot(s-&amp;gt;center, p-&amp;gt;plane);&lt;br /&gt;
&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
	    p++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Since each plane is a 4D vector, we can load each one as a column vector&lt;br /&gt;
       into XMTRX, creating a 4x4 matrix out of the 4 planes. */&lt;br /&gt;
    shz_xmtrx_load_4x4_cols(&amp;amp;p[0].plane, &amp;amp;p[1].plane, &amp;amp;p[2].plane, &amp;amp;p[3].plane);&lt;br /&gt;
&lt;br /&gt;
    /* Now we transform our constant vector, the bounding sphere&#039;s center, against&lt;br /&gt;
       our 4 plane vectors. This gives us a result vector where the value of each&lt;br /&gt;
       component is equal to the dot product between the sphere&#039;s centroid and the&lt;br /&gt;
       corresponding plane column vector.  */&lt;br /&gt;
	shz_vec4_t distances = shz_xmtrx_trans_vec4(s-&amp;gt;center);&lt;br /&gt;
&lt;br /&gt;
    /* Now we simply iterate over each of our 4 result components to check&lt;br /&gt;
       for intersection. */&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 4; ++i) {&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distances.elem[0])&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distances.elem[0])&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
	return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ADPCM Decoding===&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3798</id>
		<title>SH4 FTRV Optimizations</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3798"/>
		<updated>2025-08-06T07:53:24Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: /* Bounding Sphere vs View Frustum Culling */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Without a doubt, the single most computationally powerful instruction on the SuperH4 CPU in the Sega Dreamcast is &#039;&#039;&#039;FTRV&#039;&#039;&#039;, or the &#039;&#039;&#039;F&#039;&#039;&#039;loating-point &#039;&#039;&#039;TR&#039;&#039;&#039;ansform &#039;&#039;&#039;V&#039;&#039;&#039;ector instruction. It is a single instruction which multiplies a 4D vector by the 4x4 matrix held within the back-bank of FPU registers, &#039;&#039;&#039;XMTRX&#039;&#039;&#039;. This article will teach you how to leverage this god instruction for FP performance gainz and introduce you to several example scenarios that have yielded fantastic gainz within the community.&lt;br /&gt;
&lt;br /&gt;
==Relationship to FIPR==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Instruction Summaries&lt;br /&gt;
|-&lt;br /&gt;
! Format !! Function !! Encoding !! Group !! Issue Cycles !! Latency Cycles&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fipr&#039;&#039;&#039;	FVm,FVn || inner_product (FVm, FVn) -&amp;gt; FR[n+3] || 1111nnmm11101101 || FE || 1 || 4/5&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ftrv&#039;&#039;&#039; XMTRX, FVn || transform_vector(XMTRX, FVn) -&amp;gt; FVn || 1111nn0111111101 || FE || 1 || 5/8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==When to use FTRV==&lt;br /&gt;
&lt;br /&gt;
==Real-World Examples==&lt;br /&gt;
The following are real-world examples of FTRV-based optimizations used within games and applications for the Sega Dreamcast within the community.&lt;br /&gt;
===Vertex Position Transformation===&lt;br /&gt;
The first and most obvious use of the FTRV instruction is for doing position transform calculations on the incoming vertex stream, transforming from local to view-space, while submitting vertices to the PowerVR during T&amp;amp;L. This is the first and absolute most crucial area for leveraging FTRV and was its original intended purpose. If you do nothing else with the instruction, bear in mind that the only way to come even remotely close to pushing a considerable volume of polygons on the DC is by properly harnessing the SH4 by using FTRV to transform your vertices.&lt;br /&gt;
&lt;br /&gt;
===Diffuse Lighting===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Collision and Physics===&lt;br /&gt;
===Bounding Sphere vs View Frustum Culling===&lt;br /&gt;
The following code snippet is taken from the DCA3 codebase as part of its Renderware driver back-end for Dreamcast. To check for intersection between a bounding sphere and the view frustum, you must compute the dot product between the centroid of the bounding sphere against all 6 of the view frustum planes. The result of each dot product represents the sphere&#039;s distance from that plane.&lt;br /&gt;
&lt;br /&gt;
The original algorithm was as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
&lt;br /&gt;
    // Iterate over each of the 6 frustum planes.&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
	for(int32 i = 0; i &amp;lt; 6; i++){&lt;br /&gt;
        /* Compute dot product between each plane and the centroid&lt;br /&gt;
           Your FIPR senses should be tingling, since we&#039;ve got dot products! */&lt;br /&gt;
		float32 distance = dot(p-&amp;gt;plane, s-&amp;gt;center) - p-&amp;gt;plane.distance;&lt;br /&gt;
		&lt;br /&gt;
        if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
			return SPHEREOUTSIDE; // No intersection&lt;br /&gt;
		if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
			res = SPHEREBOUNDARY; // Intersection&lt;br /&gt;
		&lt;br /&gt;
        p++;&lt;br /&gt;
	}&lt;br /&gt;
    return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we have a scenario where we have 4+ dot products being taken where one of the vectors remains constant for each, this is a textbook case for using FTRV to compute 4 of them in parallel.&lt;br /&gt;
&lt;br /&gt;
So we use FIPR to accelerate two of the dot products and FTRV for the other 4 of them at once. The following code uses [https://github.com/gyrovorbis/sh4zam libSH4ZAM] to achieve this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
&lt;br /&gt;
    // Use FIPR to accelerate first two dot products independently&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 2; ++i) {&lt;br /&gt;
        float distance = shz_vec4_dot(s-&amp;gt;center, p-&amp;gt;plane);&lt;br /&gt;
&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
	    p++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Since each plane is a 4D vector, we can load each one as a column vector&lt;br /&gt;
       into XMTRX, creating a 4x4 matrix out of the 4 planes. */&lt;br /&gt;
    shz_xmtrx_load_4x4_cols(&amp;amp;p[0].plane, &amp;amp;p[1].plane, &amp;amp;p[2].plane, &amp;amp;p[3].plane);&lt;br /&gt;
&lt;br /&gt;
    /* Now we transform our constant vector, the bounding sphere&#039;s center, against&lt;br /&gt;
       our 4 plane vectors. This gives us a result vector where the value of each&lt;br /&gt;
       component is equal to the dot product between the sphere&#039;s centroid and the&lt;br /&gt;
       corresponding plane column vector.  */&lt;br /&gt;
	shz_vec4_t distances = shz_xmtrx_trans_vec4(s-&amp;gt;center);&lt;br /&gt;
&lt;br /&gt;
    /* Now we simply iterate over each of our 4 result components to check&lt;br /&gt;
       for intersection. */&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 4; ++i) {&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distances.elem[0])&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distances.elem[0])&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
	return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ADPCM Decoding===&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3797</id>
		<title>SH4 FTRV Optimizations</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3797"/>
		<updated>2025-08-06T07:52:37Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Without a doubt, the single most computationally powerful instruction on the SuperH4 CPU in the Sega Dreamcast is &#039;&#039;&#039;FTRV&#039;&#039;&#039;, or the &#039;&#039;&#039;F&#039;&#039;&#039;loating-point &#039;&#039;&#039;TR&#039;&#039;&#039;ansform &#039;&#039;&#039;V&#039;&#039;&#039;ector instruction. It is a single instruction which multiplies a 4D vector by the 4x4 matrix held within the back-bank of FPU registers, &#039;&#039;&#039;XMTRX&#039;&#039;&#039;. This article will teach you how to leverage this god instruction for FP performance gainz and introduce you to several example scenarios that have yielded fantastic gainz within the community.&lt;br /&gt;
&lt;br /&gt;
==Relationship to FIPR==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Instruction Summaries&lt;br /&gt;
|-&lt;br /&gt;
! Format !! Function !! Encoding !! Group !! Issue Cycles !! Latency Cycles&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fipr&#039;&#039;&#039;	FVm,FVn || inner_product (FVm, FVn) -&amp;gt; FR[n+3] || 1111nnmm11101101 || FE || 1 || 4/5&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ftrv&#039;&#039;&#039; XMTRX, FVn || transform_vector(XMTRX, FVn) -&amp;gt; FVn || 1111nn0111111101 || FE || 1 || 5/8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==When to use FTRV==&lt;br /&gt;
&lt;br /&gt;
==Real-World Examples==&lt;br /&gt;
The following are real-world examples of FTRV-based optimizations used within games and applications for the Sega Dreamcast within the community.&lt;br /&gt;
===Vertex Position Transformation===&lt;br /&gt;
The first and most obvious use of the FTRV instruction is for doing position transform calculations on the incoming vertex stream, transforming from local to view-space, while submitting vertices to the PowerVR during T&amp;amp;L. This is the first and absolute most crucial area for leveraging FTRV and was its original intended purpose. If you do nothing else with the instruction, bear in mind that the only way to come even remotely close to pushing a considerable volume of polygons on the DC is by properly harnessing the SH4 by using FTRV to transform your vertices.&lt;br /&gt;
&lt;br /&gt;
===Diffuse Lighting===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Collision and Physics===&lt;br /&gt;
===Bounding Sphere vs View Frustum Culling===&lt;br /&gt;
The following code snippet is taken from the DCA3 codebase as part of its Renderware driver back-end for Dreamcast. To check for intersection between a bounding sphere and the view frustum, you must compute the dot product between the centroid of the bounding sphere against all 6 of its planes.&lt;br /&gt;
&lt;br /&gt;
The original algorithm was as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
&lt;br /&gt;
    // Iterate over each of the 6 frustum planes.&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
	for(int32 i = 0; i &amp;lt; 6; i++){&lt;br /&gt;
        /* Compute dot product between each plane and the centroid&lt;br /&gt;
           Your FIPR senses should be tingling, since we&#039;ve got dot products! */&lt;br /&gt;
		float32 distance = dot(p-&amp;gt;plane, s-&amp;gt;center) - p-&amp;gt;plane.distance;&lt;br /&gt;
		&lt;br /&gt;
        if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
			return SPHEREOUTSIDE; // No intersection&lt;br /&gt;
		if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
			res = SPHEREBOUNDARY; // Intersection&lt;br /&gt;
		&lt;br /&gt;
        p++;&lt;br /&gt;
	}&lt;br /&gt;
    return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we have a scenario where we have 4+ dot products being taken where one of the vectors remains constant for each, this is a textbook case for using FTRV to compute 4 of them in parallel.&lt;br /&gt;
&lt;br /&gt;
So we use FIPR to accelerate two of the dot products and FTRV for the other 4 of them at once. The following code uses [https://github.com/gyrovorbis/sh4zam libSH4ZAM] to achieve this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
int32 Camera::frustumTestSphere(const Sphere *s) const {&lt;br /&gt;
	int32 res = SPHEREINSIDE;&lt;br /&gt;
	const FrustumPlane *p = this-&amp;gt;frustumPlanes;&lt;br /&gt;
&lt;br /&gt;
    // Use FIPR to accelerate first two dot products independently&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 2; ++i) {&lt;br /&gt;
        float distance = shz_vec4_dot(s-&amp;gt;center, p-&amp;gt;plane);&lt;br /&gt;
&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distance)&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distance)&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
	    p++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Since each plane is a 4D vector, we can load each one as a column vector&lt;br /&gt;
       into XMTRX, creating a 4x4 matrix out of the 4 planes. */&lt;br /&gt;
    shz_xmtrx_load_4x4_cols(&amp;amp;p[0].plane, &amp;amp;p[1].plane, &amp;amp;p[2].plane, &amp;amp;p[3].plane);&lt;br /&gt;
&lt;br /&gt;
    /* Now we transform our constant vector, the bounding sphere&#039;s center, against&lt;br /&gt;
       our 4 plane vectors. This gives us a result vector where the value of each&lt;br /&gt;
       component is equal to the dot product between the sphere&#039;s centroid and the&lt;br /&gt;
       corresponding plane column vector.  */&lt;br /&gt;
	shz_vec4_t distances = shz_xmtrx_trans_vec4(s-&amp;gt;center);&lt;br /&gt;
&lt;br /&gt;
    /* Now we simply iterate over each of our 4 result components to check&lt;br /&gt;
       for intersection. */&lt;br /&gt;
    for(unsigned i = 0; i &amp;lt; 4; ++i) {&lt;br /&gt;
	    if(s-&amp;gt;radius &amp;lt; distances.elem[0])&lt;br /&gt;
		    return SPHEREOUTSIDE;&lt;br /&gt;
	    else if(s-&amp;gt;radius &amp;gt; -distances.elem[0])&lt;br /&gt;
		    res = SPHEREBOUNDARY;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
	return res;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ADPCM Decoding===&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_FIPR_Optimizations&amp;diff=3789</id>
		<title>SH4 FIPR Optimizations</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_FIPR_Optimizations&amp;diff=3789"/>
		<updated>2025-07-26T14:25:29Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Yo, guys. At like 1AM @ian micheal got me looking at pl_mpeg&#039;s audio decoder to see if I could see any potential gainz... So here is its innermost hottest audio synthesis loop:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for (int i = 32; i; --i) {&lt;br /&gt;
    float u;&lt;br /&gt;
    u = pl_fipr(d[0], d[1], d[2], d[3], v1[0], v2[0], v1[128], v2[128]);&lt;br /&gt;
    u += pl_fipr(d[4], d[5], d[6], d[7], v1[256], v2[256], v1[384], v2[384]);&lt;br /&gt;
    u += pl_fipr(d[8], d[9], d[10], d[11], v1[512], v2[512], v1[640], v2[640]);&lt;br /&gt;
    u += pl_fipr(d[12], d[13], d[14], d[15], v1[768], v2[768], v1[896], v2[896]);&lt;br /&gt;
    d += 32;&lt;br /&gt;
    v1++;&lt;br /&gt;
    v2++;&lt;br /&gt;
    *out++ = (short)((int)u &amp;gt;&amp;gt; 16);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Which... you&#039;d think would be preeeetty efficient, right? 4 back-to-back FIPRs? I mean, it is hella gainzy compared to not using FIPR.&lt;br /&gt;
&lt;br /&gt;
But there are two problems with back-to-back FIPR-y, I wanna teach anyone interested:&lt;br /&gt;
&lt;br /&gt;
1) Very often one of the vector arguments stays constant between FIPR calls, but unfortunately the compiler is too dumb to not reload all 8 registers between calls regardless.&lt;br /&gt;
* LUCKILY every argument to these FIPRs is unique so this is not applicable, but... very often that&#039;s a perf destroyer.&lt;br /&gt;
&lt;br /&gt;
2) THE COMPILER CANNOT PIPELINE FIPR FOR SHIT.&lt;br /&gt;
* VERY applicable here. You know what the ASM looks like for these FIPR calls? Something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
! load first vector arg into fv0 (nothing wrong with this)&lt;br /&gt;
fmov.s @%[d]+, fr0&lt;br /&gt;
fmov.s @%[d}+, fr1&lt;br /&gt;
fmov.s @%[d]+, fr2&lt;br /&gt;
fmov.s @%[d]+, fr3&lt;br /&gt;
&lt;br /&gt;
! load second vector arg into fv4 (nothing wrong with this)&lt;br /&gt;
fmov.s @%[v1], fr4&lt;br /&gt;
add    %[offset], @[v1]&lt;br /&gt;
fmov.s @%[v2], fr5&lt;br /&gt;
add    %[offset], @[v2]&lt;br /&gt;
fmov.s @%[v1], fr6&lt;br /&gt;
fmov.s @%[v2], fr7&lt;br /&gt;
&lt;br /&gt;
! issue actual FIPR calculation&lt;br /&gt;
fipr fv0, fv4&lt;br /&gt;
&lt;br /&gt;
! VERY NEXT INSTRUCTION TRY TO STORE THE RESULT&lt;br /&gt;
fmov.s fr7, @%[result] ! PIPELINE STALL!!!!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now this is very very bad. FIPR has 4-5 cycles of latency, so every fucking call to FIPR, since the very next instruction tries to use the result before its been calculated, the entire pipeline must stall waiting for the result... FOR EVERY FIPR CALL.&lt;br /&gt;
So you&#039;re losing MASSIVE perf benefits there.&lt;br /&gt;
The solution? You have to pipeline your FIPRs so that while the previous FIPR call is still calculating, you&#039;re loading up and issuing the next FIPR call.&lt;br /&gt;
&lt;br /&gt;
So I wrote a new routine that replaces that inner loop body doing manually pipelined FIPR calls... This should be way better:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for (int i = 32; i; --i) {&lt;br /&gt;
#if 0 // Old FIPR path which didn&#039;t pipeline for shit.&lt;br /&gt;
    float u;&lt;br /&gt;
    u = pl_fipr(d[0], d[1], d[2], d[3], v1[0], v2[0], v1[128], v2[128]);&lt;br /&gt;
    u += pl_fipr(d[4], d[5], d[6], d[7], v1[256], v2[256], v1[384], v2[384]);&lt;br /&gt;
    u += pl_fipr(d[8], d[9], d[10], d[11], v1[512], v2[512], v1[640], v2[640]);&lt;br /&gt;
    u += pl_fipr(d[12], d[13], d[14], d[15], v1[768], v2[768], v1[896], v2[896]);&lt;br /&gt;
#else // New hand-written FIPR path with manual pipelining&lt;br /&gt;
    float u = shz_pl_inner_loop(d, v1, v2);&lt;br /&gt;
#endif&lt;br /&gt;
    d += 32;&lt;br /&gt;
    v1++;&lt;br /&gt;
    v2++;&lt;br /&gt;
    *out++ = (short)((int)u &amp;gt;&amp;gt; 16);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where the new implementation is this inline ASM:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
__always_inline &lt;br /&gt;
float shz_pl_inner_loop(const float *d, const float *v1, const float *v2) {&lt;br /&gt;
    float fp_scratch[2];&lt;br /&gt;
    uint32_t int_scratch;&lt;br /&gt;
&lt;br /&gt;
    asm volatile(R&amp;quot;(&lt;br /&gt;
        ! Swap to back-bank so we don&#039;t need to clobber any FP regs.&lt;br /&gt;
        frchg&lt;br /&gt;
&lt;br /&gt;
        ! Load first vector into fv0 for first FIPR.&lt;br /&gt;
        xor     %[s], %[s]&lt;br /&gt;
        fmov.s  @%[d]+, fr0&lt;br /&gt;
        add     #64, %[s]&lt;br /&gt;
        fmov.s  @%[d]+, fr1&lt;br /&gt;
        add     #64, %[s]&lt;br /&gt;
        fmov.s  @%[d]+, fr2&lt;br /&gt;
        add     #16, %[r]&lt;br /&gt;
        fmov.s  @%[d]+, fr3&lt;br /&gt;
&lt;br /&gt;
        ! Load second vector into fv4 for first FIPR&lt;br /&gt;
        fmov.s  @%[v1], fr4&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr5&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
        fmov.s  @%[v1], fr6&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr7&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
&lt;br /&gt;
        ! Issue first FIPR&lt;br /&gt;
        fipr    fv0, fv4&lt;br /&gt;
        ! DO NOT SAVE THE RESULT YET&lt;br /&gt;
&lt;br /&gt;
        ! Load first vector into fv8 for second FIPR.&lt;br /&gt;
        fmov.s  @%[d]+, fr8&lt;br /&gt;
        fmov.s  @%[d]+, fr9&lt;br /&gt;
        fmov.s  @%[d]+, fr10&lt;br /&gt;
        fmov.s  @%[d]+, fr11&lt;br /&gt;
&lt;br /&gt;
        ! Load second vector into fv12 for second FIPR.&lt;br /&gt;
        fmov.s  @%[v1], fr12&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr13&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
        fmov.s  @%[v1], fr14&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr15&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
&lt;br /&gt;
        ! Issue second FIPR&lt;br /&gt;
        fipr    fv8, fv12&lt;br /&gt;
        ! Store result from FIRST FIPR now that it&#039;s ready&lt;br /&gt;
        fmov.s  fr7, @-%[r]&lt;br /&gt;
&lt;br /&gt;
        ! Load first vector into fv0 for third FIPR&lt;br /&gt;
        fmov.s  @%[d]+, fr0&lt;br /&gt;
        fmov.s  @%[d]+, fr1&lt;br /&gt;
        fmov.s  @%[d]+, fr2&lt;br /&gt;
        fmov.s  @%[d]+, fr3&lt;br /&gt;
&lt;br /&gt;
        ! Load second vector into fv4 for third FIPR&lt;br /&gt;
        fmov.s  @%[v1], fr4&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr5&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
        fmov.s  @%[v1], fr6&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr7&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
        &lt;br /&gt;
        ! Issue third FIPR&lt;br /&gt;
        fipr    fv0, fv4&lt;br /&gt;
        ! Store result from SECOND FIPR now that it&#039;s ready.&lt;br /&gt;
        fmov.s  fr15, @-%[r]&lt;br /&gt;
&lt;br /&gt;
        ! Load first vector into fv8 for fourth FIPR&lt;br /&gt;
        fmov.s  @%[d]+, fr8&lt;br /&gt;
        fmov.s  @%[d]+, fr9&lt;br /&gt;
        fmov.s  @%[d]+, fr10&lt;br /&gt;
        fmov.s  @%[d]+, fr11&lt;br /&gt;
&lt;br /&gt;
        ! Load second vector into fv12 for fourth FIPR&lt;br /&gt;
        fmov.s  @%[v1], fr12&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr13&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
        fmov.s  @%[v1], fr14&lt;br /&gt;
        fmov.s  @%[v2], fr15&lt;br /&gt;
&lt;br /&gt;
        ! Issue fourth FIPR&lt;br /&gt;
        fipr    fv8, fv12&lt;br /&gt;
&lt;br /&gt;
        ! Add up results from previous FIPRs while we wait&lt;br /&gt;
        fmov.s  @%[r]+, fr0&lt;br /&gt;
        fmov.s  @%[r]+, fr1&lt;br /&gt;
        fadd    fr1, fr0&lt;br /&gt;
        fadd    fr7, fr0&lt;br /&gt;
        add     #-8, %[r]&lt;br /&gt;
&lt;br /&gt;
        ! Add result from fourth FIPR now that it&#039;s ready&lt;br /&gt;
        fadd    fr15, fr0&lt;br /&gt;
&lt;br /&gt;
        ! Store final result&lt;br /&gt;
        fmov.s  fr0, @%[r]&lt;br /&gt;
&lt;br /&gt;
        ! Swap back to primary FP register bank&lt;br /&gt;
        frchg&lt;br /&gt;
    )&amp;quot;&lt;br /&gt;
    : [d] &amp;quot;+&amp;amp;r&amp;quot; (d), [v1] &amp;quot;+r&amp;quot; (v1), [v2] &amp;quot;+r&amp;quot; (v2),&lt;br /&gt;
      [r] &amp;quot;+r&amp;quot; (fp_scratch), [s] &amp;quot;=&amp;amp;r&amp;quot; (int_scratch),&lt;br /&gt;
      &amp;quot;=m&amp;quot; (*fp_scratch));&lt;br /&gt;
&lt;br /&gt;
    return fp_scratch[0];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_FIPR_Optimizations&amp;diff=3788</id>
		<title>SH4 FIPR Optimizations</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_FIPR_Optimizations&amp;diff=3788"/>
		<updated>2025-07-26T14:22:56Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Yo, guys. At like 1AM @ian micheal got me looking at pl_mpeg&#039;s audio decoder to see if I could see any potential gainz... So here is its innermost hottest audio synthesis loop:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for (int i = 32; i; --i) {&lt;br /&gt;
    float u;&lt;br /&gt;
    u = pl_fipr(d[0], d[1], d[2], d[3], v1[0], v2[0], v1[128], v2[128]);&lt;br /&gt;
    u += pl_fipr(d[4], d[5], d[6], d[7], v1[256], v2[256], v1[384], v2[384]);&lt;br /&gt;
    u += pl_fipr(d[8], d[9], d[10], d[11], v1[512], v2[512], v1[640], v2[640]);&lt;br /&gt;
    u += pl_fipr(d[12], d[13], d[14], d[15], v1[768], v2[768], v1[896], v2[896]);&lt;br /&gt;
    d += 32;&lt;br /&gt;
    v1++;&lt;br /&gt;
    v2++;&lt;br /&gt;
    *out++ = (short)((int)u &amp;gt;&amp;gt; 16);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Which... you&#039;d think would be preeeetty efficient, right? 4 back-to-back FIPRs? I mean, it is hella gainzy compared to not using FIPR.&lt;br /&gt;
&lt;br /&gt;
But there are two problems with back-to-back FIPR-y, I wanna teach anyone interested:&lt;br /&gt;
&lt;br /&gt;
1) Very often one of the vector arguments stays constant between FIPR calls, but unfortunately the compiler is too dumb to not reload all 8 registers between calls regardless.&lt;br /&gt;
* LUCKILY every argument to these FIPRs is unique so this is not applicable, but... very often that&#039;s a perf destroyer.&lt;br /&gt;
&lt;br /&gt;
2) THE COMPILER CANNOT PIPELINE FIPR FOR SHIT.&lt;br /&gt;
* VERY applicable here. You know what the ASM looks like for these FIPR calls? Something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
! load first vector arg into fv0 (nothing wrong with this)&lt;br /&gt;
fmov.s @%[d]+, fr0&lt;br /&gt;
fmov.s @%[d}+, fr1&lt;br /&gt;
fmov.s @%[d]+, fr2&lt;br /&gt;
fmov.s @%[d]+, fr3&lt;br /&gt;
&lt;br /&gt;
! load second vector arg into fv4 (nothing wrong with this)&lt;br /&gt;
fmov.s @%[v1], fr4&lt;br /&gt;
add    %[offset], @[v1]&lt;br /&gt;
fmov.s @%[v2], fr5&lt;br /&gt;
add    %[offset], @[v2]&lt;br /&gt;
fmov.s @%[v1], fr6&lt;br /&gt;
fmov.s @%[v2], fr7&lt;br /&gt;
&lt;br /&gt;
! issue actual FIPR calculation&lt;br /&gt;
fipr fv0, fv4&lt;br /&gt;
&lt;br /&gt;
! VERY NEXT INSTRUCTION TRY TO STORE THE RESULT&lt;br /&gt;
fmov.s fr7, @%[result] ! PIPELINE STALL!!!!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now this is very very bad. FIPR has 5-8 cycles of latency, so every fucking call to FIPR, since the very next instruction tries to use the result before its been calculated, the entire pipeline must stall waiting for the result... FOR EVERY FIPR CALL.&lt;br /&gt;
So you&#039;re losing MASSIVE perf benefits there.&lt;br /&gt;
The solution? You have to pipeline your FIPRs so that while the previous FIPR call is still calculating, you&#039;re loading up and issuing the next FIPR call.&lt;br /&gt;
&lt;br /&gt;
So I wrote a new routine that replaces that inner loop body doing manually pipelined FIPR calls... This should be way better:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for (int i = 32; i; --i) {&lt;br /&gt;
#if 0 // Old FIPR path which didn&#039;t pipeline for shit.&lt;br /&gt;
    float u;&lt;br /&gt;
    u = pl_fipr(d[0], d[1], d[2], d[3], v1[0], v2[0], v1[128], v2[128]);&lt;br /&gt;
    u += pl_fipr(d[4], d[5], d[6], d[7], v1[256], v2[256], v1[384], v2[384]);&lt;br /&gt;
    u += pl_fipr(d[8], d[9], d[10], d[11], v1[512], v2[512], v1[640], v2[640]);&lt;br /&gt;
    u += pl_fipr(d[12], d[13], d[14], d[15], v1[768], v2[768], v1[896], v2[896]);&lt;br /&gt;
#else // New hand-written FIPR path with manual pipelining&lt;br /&gt;
    float u = shz_pl_inner_loop(d, v1, v2);&lt;br /&gt;
#endif&lt;br /&gt;
    d += 32;&lt;br /&gt;
    v1++;&lt;br /&gt;
    v2++;&lt;br /&gt;
    *out++ = (short)((int)u &amp;gt;&amp;gt; 16);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where the new implementation is this inline ASM:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
__always_inline &lt;br /&gt;
float shz_pl_inner_loop(const float *d, const float *v1, const float *v2) {&lt;br /&gt;
    float fp_scratch[2];&lt;br /&gt;
    uint32_t int_scratch;&lt;br /&gt;
&lt;br /&gt;
    asm volatile(R&amp;quot;(&lt;br /&gt;
        ! Swap to back-bank so we don&#039;t need to clobber any FP regs.&lt;br /&gt;
        frchg&lt;br /&gt;
&lt;br /&gt;
        ! Load first vector into fv0 for first FIPR.&lt;br /&gt;
        xor     %[s], %[s]&lt;br /&gt;
        fmov.s  @%[d]+, fr0&lt;br /&gt;
        add     #64, %[s]&lt;br /&gt;
        fmov.s  @%[d]+, fr1&lt;br /&gt;
        add     #64, %[s]&lt;br /&gt;
        fmov.s  @%[d]+, fr2&lt;br /&gt;
        add     #16, %[r]&lt;br /&gt;
        fmov.s  @%[d]+, fr3&lt;br /&gt;
&lt;br /&gt;
        ! Load second vector into fv4 for first FIPR&lt;br /&gt;
        fmov.s  @%[v1], fr4&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr5&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
        fmov.s  @%[v1], fr6&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr7&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
&lt;br /&gt;
        ! Issue first FIPR&lt;br /&gt;
        fipr    fv0, fv4&lt;br /&gt;
        ! DO NOT SAVE THE RESULT YET&lt;br /&gt;
&lt;br /&gt;
        ! Load first vector into fv8 for second FIPR.&lt;br /&gt;
        fmov.s  @%[d]+, fr8&lt;br /&gt;
        fmov.s  @%[d]+, fr9&lt;br /&gt;
        fmov.s  @%[d]+, fr10&lt;br /&gt;
        fmov.s  @%[d]+, fr11&lt;br /&gt;
&lt;br /&gt;
        ! Load second vector into fv12 for second FIPR.&lt;br /&gt;
        fmov.s  @%[v1], fr12&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr13&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
        fmov.s  @%[v1], fr14&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr15&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
&lt;br /&gt;
        ! Issue second FIPR&lt;br /&gt;
        fipr    fv8, fv12&lt;br /&gt;
        ! Store result from FIRST FIPR now that it&#039;s ready&lt;br /&gt;
        fmov.s  fr7, @-%[r]&lt;br /&gt;
&lt;br /&gt;
        ! Load first vector into fv0 for third FIPR&lt;br /&gt;
        fmov.s  @%[d]+, fr0&lt;br /&gt;
        fmov.s  @%[d]+, fr1&lt;br /&gt;
        fmov.s  @%[d]+, fr2&lt;br /&gt;
        fmov.s  @%[d]+, fr3&lt;br /&gt;
&lt;br /&gt;
        ! Load second vector into fv4 for third FIPR&lt;br /&gt;
        fmov.s  @%[v1], fr4&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr5&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
        fmov.s  @%[v1], fr6&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr7&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
        &lt;br /&gt;
        ! Issue third FIPR&lt;br /&gt;
        fipr    fv0, fv4&lt;br /&gt;
        ! Store result from SECOND FIPR now that it&#039;s ready.&lt;br /&gt;
        fmov.s  fr15, @-%[r]&lt;br /&gt;
&lt;br /&gt;
        ! Load first vector into fv8 for fourth FIPR&lt;br /&gt;
        fmov.s  @%[d]+, fr8&lt;br /&gt;
        fmov.s  @%[d]+, fr9&lt;br /&gt;
        fmov.s  @%[d]+, fr10&lt;br /&gt;
        fmov.s  @%[d]+, fr11&lt;br /&gt;
&lt;br /&gt;
        ! Load second vector into fv12 for fourth FIPR&lt;br /&gt;
        fmov.s  @%[v1], fr12&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr13&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
        fmov.s  @%[v1], fr14&lt;br /&gt;
        fmov.s  @%[v2], fr15&lt;br /&gt;
&lt;br /&gt;
        ! Issue fourth FIPR&lt;br /&gt;
        fipr    fv8, fv12&lt;br /&gt;
&lt;br /&gt;
        ! Add up results from previous FIPRs while we wait&lt;br /&gt;
        fmov.s  @%[r]+, fr0&lt;br /&gt;
        fmov.s  @%[r]+, fr1&lt;br /&gt;
        fadd    fr1, fr0&lt;br /&gt;
        fadd    fr7, fr0&lt;br /&gt;
        add     #-8, %[r]&lt;br /&gt;
&lt;br /&gt;
        ! Add result from fourth FIPR now that it&#039;s ready&lt;br /&gt;
        fadd    fr15, fr0&lt;br /&gt;
&lt;br /&gt;
        ! Store final result&lt;br /&gt;
        fmov.s  fr0, @%[r]&lt;br /&gt;
&lt;br /&gt;
        ! Swap back to primary FP register bank&lt;br /&gt;
        frchg&lt;br /&gt;
    )&amp;quot;&lt;br /&gt;
    : [d] &amp;quot;+&amp;amp;r&amp;quot; (d), [v1] &amp;quot;+r&amp;quot; (v1), [v2] &amp;quot;+r&amp;quot; (v2),&lt;br /&gt;
      [r] &amp;quot;+r&amp;quot; (fp_scratch), [s] &amp;quot;=&amp;amp;r&amp;quot; (int_scratch),&lt;br /&gt;
      &amp;quot;=m&amp;quot; (*fp_scratch));&lt;br /&gt;
&lt;br /&gt;
    return fp_scratch[0];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_FIPR_Optimizations&amp;diff=3787</id>
		<title>SH4 FIPR Optimizations</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_FIPR_Optimizations&amp;diff=3787"/>
		<updated>2025-07-26T14:18:22Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: Created page with &amp;quot;Yo, guys. At like 1AM @ian micheal got me looking at pl_mpeg&amp;#039;s audio decoder to see if I could see any potential gainz...  &amp;lt;pre&amp;gt; for (int i = 32; i; --i) {     float u;     u = pl_fipr(d[0], d[1], d[2], d[3], v1[0], v2[0], v1[128], v2[128]);     u += pl_fipr(d[4], d[5], d[6], d[7], v1[256], v2[256], v1[384], v2[384]);     u += pl_fipr(d[8], d[9], d[10], d[11], v1[512], v2[512], v1[640], v2[640]);     u += pl_fipr(d[12], d[13], d[14], d[15], v1[768], v2[768], v1[896], v2[...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Yo, guys. At like 1AM @ian micheal got me looking at pl_mpeg&#039;s audio decoder to see if I could see any potential gainz...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for (int i = 32; i; --i) {&lt;br /&gt;
    float u;&lt;br /&gt;
    u = pl_fipr(d[0], d[1], d[2], d[3], v1[0], v2[0], v1[128], v2[128]);&lt;br /&gt;
    u += pl_fipr(d[4], d[5], d[6], d[7], v1[256], v2[256], v1[384], v2[384]);&lt;br /&gt;
    u += pl_fipr(d[8], d[9], d[10], d[11], v1[512], v2[512], v1[640], v2[640]);&lt;br /&gt;
    u += pl_fipr(d[12], d[13], d[14], d[15], v1[768], v2[768], v1[896], v2[896]);&lt;br /&gt;
    d += 32;&lt;br /&gt;
    v1++;&lt;br /&gt;
    v2++;&lt;br /&gt;
    *out++ = (short)((int)u &amp;gt;&amp;gt; 16);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Which... you&#039;d think would be preeeetty efficient, right? 4 back-to-back FIPRs? I mean, it is hella gainzy compared to not using FIPR.&lt;br /&gt;
&lt;br /&gt;
But there are two problems with back-to-back FIPR-y, I wanna teach anyone interested:&lt;br /&gt;
&lt;br /&gt;
1) Very often one of the vector arguments stays constant between FIPR calls, but unfortunately the compiler is too dumb to not reload all 8 registers between calls regardless.&lt;br /&gt;
* LUCKILY every argument to these FIPRs is unique so this is not applicable, but... very often that&#039;s a perf destroyer.&lt;br /&gt;
&lt;br /&gt;
2) THE COMPILER CANNOT PIPELINE FIPR FOR SHIT.&lt;br /&gt;
* VERY applicable here. You know what the ASM looks like for these FIPR calls? Something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
! load first vector arg into fv0 (nothing wrong with this)&lt;br /&gt;
fmov.s @%[d]+, fr0&lt;br /&gt;
fmov.s @%[d}+, fr1&lt;br /&gt;
fmov.s @%[d]+, fr2&lt;br /&gt;
fmov.s @%[d]+, fr3&lt;br /&gt;
&lt;br /&gt;
! load second vector arg into fv4 (nothing wrong with this)&lt;br /&gt;
fmov.s @%[v1], fr4&lt;br /&gt;
add    %[offset], @[v1]&lt;br /&gt;
fmov.s @%[v2], fr5&lt;br /&gt;
add    %[offset], @[v2]&lt;br /&gt;
fmov.s @%[v1], fr6&lt;br /&gt;
fmov.s @%[v2], fr7&lt;br /&gt;
&lt;br /&gt;
! issue actual FIPR calculation&lt;br /&gt;
fipr fv0, fv4&lt;br /&gt;
&lt;br /&gt;
! VERY NEXT INSTRUCTION TRY TO STORE THE RESULT&lt;br /&gt;
fmov.s fr7, @%[result] ! PIPELINE STALL!!!!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now this is very very bad. FIPR has 5-8 cycles of latency, so every fucking call to FIPR, since the very next instruction tries to use the result before its been calculated, the entire pipeline must stall waiting for the result... FOR EVERY FIPR CALL.&lt;br /&gt;
So you&#039;re losing MASSIVE perf benefits there.&lt;br /&gt;
The solution? You have to pipeline your FIPRs so that while the previous FIPR call is still calculating, you&#039;re loading up and issuing the next FIPR call.&lt;br /&gt;
&lt;br /&gt;
So I wrote a new routine that replaces that inner loop body doing manually pipelined FIPR calls... This should be way better:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for (int i = 32; i; --i) {&lt;br /&gt;
#if 0 // Old FIPR path which didn&#039;t pipeline for shit.&lt;br /&gt;
    float u;&lt;br /&gt;
    u = pl_fipr(d[0], d[1], d[2], d[3], v1[0], v2[0], v1[128], v2[128]);&lt;br /&gt;
    u += pl_fipr(d[4], d[5], d[6], d[7], v1[256], v2[256], v1[384], v2[384]);&lt;br /&gt;
    u += pl_fipr(d[8], d[9], d[10], d[11], v1[512], v2[512], v1[640], v2[640]);&lt;br /&gt;
    u += pl_fipr(d[12], d[13], d[14], d[15], v1[768], v2[768], v1[896], v2[896]);&lt;br /&gt;
#else // New hand-written FIPR path with manual pipelining&lt;br /&gt;
    float u = shz_pl_inner_loop(d, v1, v2);&lt;br /&gt;
#endif&lt;br /&gt;
    d += 32;&lt;br /&gt;
    v1++;&lt;br /&gt;
    v2++;&lt;br /&gt;
    *out++ = (short)((int)u &amp;gt;&amp;gt; 16);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where the new implementation is this inline ASM:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
__always_inline &lt;br /&gt;
float shz_pl_inner_loop(const float *d, const float *v1, const float *v2) {&lt;br /&gt;
    float fp_scratch[2];&lt;br /&gt;
    uint32_t int_scratch;&lt;br /&gt;
&lt;br /&gt;
    asm volatile(R&amp;quot;(&lt;br /&gt;
        ! Swap to back-bank so we don&#039;t need to clobber any FP regs.&lt;br /&gt;
        frchg&lt;br /&gt;
&lt;br /&gt;
        ! Load first vector into fv0 for first FIPR.&lt;br /&gt;
        xor     %[s], %[s]&lt;br /&gt;
        fmov.s  @%[d]+, fr0&lt;br /&gt;
        add     #64, %[s]&lt;br /&gt;
        fmov.s  @%[d]+, fr1&lt;br /&gt;
        add     #64, %[s]&lt;br /&gt;
        fmov.s  @%[d]+, fr2&lt;br /&gt;
        add     #16, %[r]&lt;br /&gt;
        fmov.s  @%[d]+, fr3&lt;br /&gt;
&lt;br /&gt;
        ! Load second vector into fv4 for first FIPR&lt;br /&gt;
        fmov.s  @%[v1], fr4&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr5&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
        fmov.s  @%[v1], fr6&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr7&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
&lt;br /&gt;
        ! Issue first FIPR&lt;br /&gt;
        fipr    fv0, fv4&lt;br /&gt;
        ! DO NOT SAVE THE RESULT YET&lt;br /&gt;
&lt;br /&gt;
        ! Load first vector into fv8 for second FIPR.&lt;br /&gt;
        fmov.s  @%[d]+, fr8&lt;br /&gt;
        fmov.s  @%[d]+, fr9&lt;br /&gt;
        fmov.s  @%[d]+, fr10&lt;br /&gt;
        fmov.s  @%[d]+, fr11&lt;br /&gt;
&lt;br /&gt;
        ! Load second vector into fv12 for second FIPR.&lt;br /&gt;
        fmov.s  @%[v1], fr12&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr13&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
        fmov.s  @%[v1], fr14&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr15&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
&lt;br /&gt;
        ! Issue second FIPR&lt;br /&gt;
        fipr    fv8, fv12&lt;br /&gt;
        ! Store result from FIRST FIPR now that it&#039;s ready&lt;br /&gt;
        fmov.s  fr7, @-%[r]&lt;br /&gt;
&lt;br /&gt;
        ! Load first vector into fv0 for third FIPR&lt;br /&gt;
        fmov.s  @%[d]+, fr0&lt;br /&gt;
        fmov.s  @%[d]+, fr1&lt;br /&gt;
        fmov.s  @%[d]+, fr2&lt;br /&gt;
        fmov.s  @%[d]+, fr3&lt;br /&gt;
&lt;br /&gt;
        ! Load second vector into fv4 for third FIPR&lt;br /&gt;
        fmov.s  @%[v1], fr4&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr5&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
        fmov.s  @%[v1], fr6&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr7&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
        &lt;br /&gt;
        ! Issue third FIPR&lt;br /&gt;
        fipr    fv0, fv4&lt;br /&gt;
        ! Store result from SECOND FIPR now that it&#039;s ready.&lt;br /&gt;
        fmov.s  fr15, @-%[r]&lt;br /&gt;
&lt;br /&gt;
        ! Load first vector into fv8 for fourth FIPR&lt;br /&gt;
        fmov.s  @%[d]+, fr8&lt;br /&gt;
        fmov.s  @%[d]+, fr9&lt;br /&gt;
        fmov.s  @%[d]+, fr10&lt;br /&gt;
        fmov.s  @%[d]+, fr11&lt;br /&gt;
&lt;br /&gt;
        ! Load second vector into fv12 for fourth FIPR&lt;br /&gt;
        fmov.s  @%[v1], fr12&lt;br /&gt;
        add     %[s], %[v1]&lt;br /&gt;
        fmov.s  @%[v2], fr13&lt;br /&gt;
        add     %[s], %[v2]&lt;br /&gt;
        fmov.s  @%[v1], fr14&lt;br /&gt;
        fmov.s  @%[v2], fr15&lt;br /&gt;
&lt;br /&gt;
        ! Issue fourth FIPR&lt;br /&gt;
        fipr    fv8, fv12&lt;br /&gt;
&lt;br /&gt;
        ! Add up results from previous FIPRs while we wait&lt;br /&gt;
        fmov.s  @%[r]+, fr0&lt;br /&gt;
        fmov.s  @%[r]+, fr1&lt;br /&gt;
        fadd    fr1, fr0&lt;br /&gt;
        fadd    fr7, fr0&lt;br /&gt;
        add     #-8, %[r]&lt;br /&gt;
&lt;br /&gt;
        ! Add result from fourth FIPR now that it&#039;s ready&lt;br /&gt;
        fadd    fr15, fr0&lt;br /&gt;
&lt;br /&gt;
        ! Store final result&lt;br /&gt;
        fmov.s  fr0, @%[r]&lt;br /&gt;
&lt;br /&gt;
        ! Swap back to primary FP register bank&lt;br /&gt;
        frchg&lt;br /&gt;
    )&amp;quot;&lt;br /&gt;
    : [d] &amp;quot;+&amp;amp;r&amp;quot; (d), [v1] &amp;quot;+r&amp;quot; (v1), [v2] &amp;quot;+r&amp;quot; (v2),&lt;br /&gt;
      [r] &amp;quot;+r&amp;quot; (fp_scratch), [s] &amp;quot;=&amp;amp;r&amp;quot; (int_scratch),&lt;br /&gt;
      &amp;quot;=m&amp;quot; (*fp_scratch));&lt;br /&gt;
&lt;br /&gt;
    return fp_scratch[0];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3770</id>
		<title>SH4 FTRV Optimizations</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_FTRV_Optimizations&amp;diff=3770"/>
		<updated>2025-07-17T17:32:03Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: Created page with &amp;quot;Without a doubt, the single most computationally powerful instruction on the SuperH4 CPU in the Sega Dreamcast is &amp;#039;&amp;#039;&amp;#039;FTRV&amp;#039;&amp;#039;&amp;#039;, or the &amp;#039;&amp;#039;&amp;#039;F&amp;#039;&amp;#039;&amp;#039;loating-point &amp;#039;&amp;#039;&amp;#039;TR&amp;#039;&amp;#039;&amp;#039;ansform &amp;#039;&amp;#039;&amp;#039;V&amp;#039;&amp;#039;&amp;#039;ector instruction. It is a single instruction which multiplies a 4D vector by the 4x4 matrix held within the back-bank of FPU registers, &amp;#039;&amp;#039;&amp;#039;XMTRX&amp;#039;&amp;#039;&amp;#039;. This article will teach you how to leverage this god instruction for FP performance gainz and introduce you to several example scenarios that have y...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Without a doubt, the single most computationally powerful instruction on the SuperH4 CPU in the Sega Dreamcast is &#039;&#039;&#039;FTRV&#039;&#039;&#039;, or the &#039;&#039;&#039;F&#039;&#039;&#039;loating-point &#039;&#039;&#039;TR&#039;&#039;&#039;ansform &#039;&#039;&#039;V&#039;&#039;&#039;ector instruction. It is a single instruction which multiplies a 4D vector by the 4x4 matrix held within the back-bank of FPU registers, &#039;&#039;&#039;XMTRX&#039;&#039;&#039;. This article will teach you how to leverage this god instruction for FP performance gainz and introduce you to several example scenarios that have yielded fantastic gainz within the community.&lt;br /&gt;
&lt;br /&gt;
==Relationship to FIPR==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Instruction Summaries&lt;br /&gt;
|-&lt;br /&gt;
! Format !! Function !! Encoding !! Group !! Issue Cycles !! Latency Cycles&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;fipr&#039;&#039;&#039;	FVm,FVn || inner_product (FVm, FVn) -&amp;gt; FR[n+3] || 1111nnmm11101101 || FE || 1 || 4/5&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;ftrv&#039;&#039;&#039; XMTRX, FVn || transform_vector(XMTRX, FVn) -&amp;gt; FVn || 1111nn0111111101 || FE || 1 || 5/8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==When to use FTRV==&lt;br /&gt;
&lt;br /&gt;
==Real-World Examples==&lt;br /&gt;
The following are real-world examples of FTRV-based optimizations used within games and applications for the Sega Dreamcast within the community.&lt;br /&gt;
===Vertex Position Transformation===&lt;br /&gt;
The first and most obvious use of the FTRV instruction is for doing position transform calculations on the incoming vertex stream, transforming from local to view-space, while submitting vertices to the PowerVR during T&amp;amp;L. This is the first and absolute most crucial area for leveraging FTRV and was its original intended purpose. If you do nothing else with the instruction, bear in mind that the only way to come even remotely close to pushing a considerable volume of polygons on the DC is by properly harnessing the SH4 by using FTRV to transform your vertices.&lt;br /&gt;
&lt;br /&gt;
===Diffuse Lighting===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Collision and Physics===&lt;br /&gt;
===Bounding Sphere vs View Frustum Culling===&lt;br /&gt;
===ADPCM Decoding===&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_in_Compiler_Explorer&amp;diff=3755</id>
		<title>SH4 in Compiler Explorer</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_in_Compiler_Explorer&amp;diff=3755"/>
		<updated>2025-04-26T14:17:13Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: Added GCC15.1.0 templates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Thanks to the effort of Matt Godbolt (who hilariously enough is a former Dreamcast developer himself), the SuperH GCC toolchain is now available for use with [https://godbolt.org Compiler Explorer], along with all of the SH4-specific compiler flags and options typically used when targeting the Dreamcast. This gives us an invaluable tool for getting quick and immediate feedback on how well a given C or C++ source segment tends to translate into SH4 assembly, offering a little sandbox for testing and optimizing code targeting the Dreamcast.&lt;br /&gt;
&lt;br /&gt;
[[File:GCC Compiler Benchmarks.png|thumb|Benchmarking various GCC versions and flags]]&lt;br /&gt;
&lt;br /&gt;
= Configuration =&lt;br /&gt;
To arrive at a configuration mirroring a Dreamcast development environment, first select one of the GCC compiler versions for the SH architecture. Secondly, the following compiler options should be used as the baseline configuration:&lt;br /&gt;
* &amp;lt;code&amp;gt;-ml&amp;lt;/code&amp;gt;: compile code for the processor in little-endian mode&lt;br /&gt;
* FPU Mode:&lt;br /&gt;
** &amp;lt;code&amp;gt;-m4-single&amp;lt;/code&amp;gt;: generate code for the SH4 with a floating-point unit that supports both single and double-precision floating point arithmetic that defaults to single-precision mode upon function entry&lt;br /&gt;
** &amp;lt;code&amp;gt;-m4-single-only&amp;lt;/code&amp;gt;: generate code for the SH4 with a floating-point unit that only supports single-precision floating point arithmetic&lt;br /&gt;
* &amp;lt;code&amp;gt;-ffast-math&amp;lt;/code&amp;gt;: breaks strict IEEE compliance and allows for faster floating point approximations&lt;br /&gt;
* &amp;lt;code&amp;gt;-O3&amp;lt;/code&amp;gt;: optimization level 3&lt;br /&gt;
* &amp;lt;code&amp;gt;-mfsrra&amp;lt;/code&amp;gt;: enables emission of the fsrra instruction for reciprocal square root approximations (not available in GCC 4.7.4)&lt;br /&gt;
* &amp;lt;code&amp;gt;-mfsca&amp;lt;/code&amp;gt;: enables emission of the fsca instruction for sine and cosine approximations (not available in GCC 4.7.4)&lt;br /&gt;
* &amp;lt;code&amp;gt;-matomic-model=soft-imask&amp;lt;/code&amp;gt;: enables support for C11 and C++11 atomics by disabling then reenabling interrupts around atomic variable operations&lt;br /&gt;
* &amp;lt;code&amp;gt;-ftls-model=local-exec&amp;lt;/code&amp;gt;: enables the model used by KOS for supporting variables declared with the &amp;quot;thread_local&amp;quot; keyword&lt;br /&gt;
&lt;br /&gt;
= Convenience Templates =&lt;br /&gt;
The following are pre-configured templates you can use as sample Dreamcast build configurations:&lt;br /&gt;
* GCC4.9.4:&lt;br /&gt;
** [https://godbolt.org/z/9MKzeMfMj C11 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/qGzoeo4sj C++14 Hello World]&lt;br /&gt;
* GCC9.5.0:&lt;br /&gt;
** [https://godbolt.org/z/rvW3s3594 C17 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/qYfE5G6Mx C++17 Hello World]&lt;br /&gt;
* GCC12.2.0:&lt;br /&gt;
** [https://godbolt.org/z/94TKvxazn C17 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/61jqhE3zn C++20 Hello World]&lt;br /&gt;
* GCC13.1.0:&lt;br /&gt;
** [https://godbolt.org/z/Kb9bKe8ro C2X Hello World]&lt;br /&gt;
** [https://godbolt.org/z/51dv4ePsG C++23 Hello World]&lt;br /&gt;
* GCC13.2.0:&lt;br /&gt;
** [https://godbolt.org/z/rafvMdWGb C2X Hello World]&lt;br /&gt;
** [https://godbolt.org/z/MeG3rqna7 C++23 Hello World]&lt;br /&gt;
* GCC 14.1.0&lt;br /&gt;
** [https://godbolt.org/z/7ha8oj4vd C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/eW8Yd8sG9 C++26 Hello World]&lt;br /&gt;
* GCC 14.2.0&lt;br /&gt;
** [https://godbolt.org/z/a54qTYon4 C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/5njMrrh8z C++26 Hello World]&lt;br /&gt;
* GCC 15.1.0&lt;br /&gt;
** [https://godbolt.org/z/WWsaaEqWW C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/raP67zWcY C++26 Hello World]&lt;br /&gt;
&lt;br /&gt;
Pre-configured template for ARM GCC8.5, Dreamcast&#039;s &amp;quot;AICA&amp;quot; sound chip:&lt;br /&gt;
* [https://godbolt.org/z/895dWG9qf C Hello World]&lt;br /&gt;
&lt;br /&gt;
= Tips and Notes =&lt;br /&gt;
* It has been noted that while &amp;lt;code&amp;gt;-O3&amp;lt;/code&amp;gt; is claimed to be the highest optimization level according to recent GCC documentation, some code differences can still be seen under certain circumstances when using &amp;lt;code&amp;gt;-O4&amp;lt;/code&amp;gt; and beyond.&lt;br /&gt;
* The compiler seems to ignore both &amp;lt;code&amp;gt;-mfsrra&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;-mfsca&amp;lt;/code&amp;gt; without the &amp;lt;code&amp;gt;-ffast-math&amp;lt;/code&amp;gt; option.&lt;br /&gt;
* With the proper flags enabled for fast-math, the compiler is smart enough to leverage the following from pure C code, almost certainly better than you can do with small intrinsic-style inline ASM calls, provided you&#039;re using the proper single-precision versions of any &amp;lt;code&amp;gt;&amp;lt;math.h&amp;gt;&amp;lt;/code&amp;gt; routines:&lt;br /&gt;
**&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{|&lt;br /&gt;
|+ Compiler-Generated Fast-Math Optimizations&lt;br /&gt;
|-&lt;br /&gt;
! Assembly Output !! C/C++ Input&lt;br /&gt;
|-&lt;br /&gt;
| FMAC || &amp;lt;code&amp;gt;z = x * y + z&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| FSCA || &amp;lt;code&amp;gt;s = sinf(angle); c = cosf(angle)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| FSRRA || &amp;lt;code&amp;gt;1.0f / sqrtf(x)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
*Unfortunately the compiler has no knowledge of the following SIMD instructions, even with fast-math, so it&#039;s quite necessary to use inline assembly routines (provided by KallistiOS) for fully leveraging the SH4&#039;s FPU, when working with vectors and matrices in linear algebra routines:&lt;br /&gt;
**&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{|&lt;br /&gt;
|+ Manual Inline Assembly Fast-Math Optimizations&lt;br /&gt;
|-&lt;br /&gt;
! Assembly Output !! C/C++ Input&lt;br /&gt;
|-&lt;br /&gt;
| FIPR || &amp;lt;code&amp;gt;Vector4 Dot Product&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| FTRV || &amp;lt;code&amp;gt;Vector4 * Matrix4x4 Transform&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
* Typically smaller code sizes and more tightly optimized code are seen with newer versions of GCC versus the older ones; however, this is not always the case.&lt;br /&gt;
* Evidently, even without a branch predictor, the C++20 &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[likely]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[unlikely]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; attributes as well as the GCC intrinsic &amp;lt;code&amp;gt;__builtin_expect()&amp;lt;/code&amp;gt; can have a fairly profound impact on code generation and optimization for conditionals and branches. More information can be found [https://dcemulation.org/phpBB/viewtopic.php?t=106029 here].&lt;br /&gt;
* &amp;lt;code&amp;gt;-fipa-pta&amp;lt;/code&amp;gt; allows the compiler to analyze pointer and reference usage beyond the scope of the current compiling function, which very often results in pretty decent performance increases at the cost of increased compile times and RAM usage.&lt;br /&gt;
* &amp;lt;code&amp;gt;-flto&amp;lt;/code&amp;gt; allows GCC to perform optimizations over the entire program and all translation units as a single entity during the linking phase, for the cost of increased compile times and RAM usage. This frequently results in more performant code.&lt;br /&gt;
* An in-depth benchmark comparing the run-time performance and compiled binary size output of every toolchain version officially supported by KOS with various optimization levels can be found [https://dcemulation.org/phpBB/viewtopic.php?t=106068 here].&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=VMU_peripheral&amp;diff=3679</id>
		<title>VMU peripheral</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=VMU_peripheral&amp;diff=3679"/>
		<updated>2025-01-29T15:27:27Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The VMU peripheral on the [[Maple_bus|Maple Bus]] contains 3 functions: screen, storage, and timer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; Some information here is misleading and/or incomplete&lt;br /&gt;
&lt;br /&gt;
== Storage ==&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;block read&amp;quot; and &amp;quot;block write&amp;quot; commands (0x0B and 0x0C) with storage function code are used to read and write blocks of memory in the storage peripheral. &lt;br /&gt;
&lt;br /&gt;
Normally, there are 256 blocks of memory that make up the entire storage space, and normally each block consists of 512 bytes. That makes a total of 128 KB of memory. These values are configurable according to the Maple Bus spec, but anything other than these values is not practically usable by most games due to many high-level APIs and libraries within the SDKs not adhering properly to the Maple spec and making hardcoded assumptions about the volume information.&amp;lt;ref&amp;gt;&#039;&#039;[https://www.dreamcast-talk.com/forum/viewtopic.php?f=5&amp;amp;t=15562&amp;amp;p=171565] TapamN | 400 block VMU on emulator&#039;&#039;&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Function Definition ===&lt;br /&gt;
The function definition may be found in the peripheral&#039;s [[Maple_bus#Device_Info_Payload_Structure_.28cmd_0x05.29|device info packet]]. It is necessary to read this word to know how to access blocks of memory on the storage.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Byte 0 (LSB) !! Byte 1 !! Byte 2 !! Byte 3 (MSB)&lt;br /&gt;
|-&lt;br /&gt;
| bit 7: removable (1: true)&amp;lt;br&amp;gt;bit 6: CRC (1: needed)&amp;lt;br&amp;gt;bits 0-5: unused (0) || bits 4-7: number of write accesses per block&amp;lt;br&amp;gt;bits 0-3: number of read accesses per block || number of bytes per block&amp;lt;br&amp;gt;(x + 1)*32 bytes || number of partitions (x + 1)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Get Media Info ===&lt;br /&gt;
Execute a [[Maple_bus#Commands|get memory information]] command to get information about the size and locations of some information within the media. On successful execution, a [[Maple_bus#Commands|data transfer]] packet with the following payload will be returned. &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Word 0 !! Word 1 !! Word 2 !! Word 3 !! Word 4 !! Word 5 !! Word 6&lt;br /&gt;
|-&lt;br /&gt;
| [[Maple_bus#Function_Codes|Function code]] &amp;lt;br&amp;gt; 0x00000002 || 2 most sig bytes: total size &amp;lt;br&amp;gt; 2 least sig bytes: the partition number of this media || 2 most sig bytes: block number of system area &amp;lt;br&amp;gt; 2 least sig bytes: block number of start of FAT area || 2 most sig bytes: number of FAT blocks &amp;lt;br&amp;gt; 2 least sig bytes: block number of file information || 2 most sig bytes: number of file info blocks &amp;lt;br&amp;gt; 2 least sig bytes: icon number || 2 most sig bytes: block number of save area &amp;lt;br&amp;gt; 2 least sig bytes: number of blocks in save area || execution file info&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Block Read ===&lt;br /&gt;
Execute a sequence of [[Maple_bus#Commands|block reads]] to read data from storage. The number of sequences is dependent on the number of read accesses per block defined in the function definition above. On successful execution, a [[Maple_bus#Commands|data transfer]] packet will be returned.&lt;br /&gt;
&lt;br /&gt;
=== Block Write ===&lt;br /&gt;
Execute a sequence of [[Maple_bus#Commands|block writes]] to write data to storage. The number of sequences is dependent on the number of write accesses per block defined in the function definition above. On successful execution, a [[Maple_bus#Commands|acknowledge]] packet will be returned. After the final write sequence, execute a [[Maple_bus#Commands|get last error]] command with an incremented phase value to commit the block from RAM to storage. &lt;br /&gt;
* A VMU cannot handle successive block write packets faster than about 10 ms per write &lt;br /&gt;
** After such error, the storage functionality acts as if it never received this sequence and never returns a response packet - it may be possible to successfully resend this sequence, but writing a &amp;quot;get last error&amp;quot; command would be necessary before starting over at the first sequence&lt;br /&gt;
** The Dreamcast does each read/write sequence on the same cadence as controller polling (about every 16 ms)&lt;br /&gt;
&lt;br /&gt;
== Screen ==&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;block write&amp;quot; command (0x0C) with screen function code and 48 data words is used to write monochrome images to the screen. A screen is 48 bits wide and 32 bits tall. For each bit in the 48 data words, a value of 1 means the pixel is on (black) and 0 means the pixel is off (white). Data is written from left to right and top to bottom (when holding the VMU in the upright orientation i.e. controller flipped upside down). The most significant bit of the first word sets the pixel on the top, left of the screen. The two most significant bytes write to the 33rd through 48th bit of the first row. The next two bytes write to the 1st through 16th bits of the second row. This is repeated for the rest of the 48 words like pictured below.&lt;br /&gt;
&lt;br /&gt;
[[File:Dreamcast Screen Words.png|Dreamcast Screen Words]]&lt;br /&gt;
&lt;br /&gt;
== Timer ==&lt;br /&gt;
&lt;br /&gt;
The timer function allows the host to activate the buzzer on the VMU and get button conditions.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=User:GyroVorbis&amp;diff=3678</id>
		<title>User:GyroVorbis</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=User:GyroVorbis&amp;diff=3678"/>
		<updated>2025-01-29T15:20:52Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;My name is Falco Girgis.&lt;br /&gt;
&lt;br /&gt;
I am the infamous lead developer of Elysian Shadows, ESTk, and ElysianVMU. I am widely hated for failing to deliver on a successfully funded Kickstarter, but I&#039;ve actually poured my heart and soul into giving back to this community and contributing to its infrastructure for years now to atone for my sins.&lt;br /&gt;
&lt;br /&gt;
Feel free to come hang out with me on Discord or follow me on Twitter or something. I&#039;m happy to help!&lt;br /&gt;
&lt;br /&gt;
* GitHub: https://github.com/gyrovorbis&lt;br /&gt;
* Discord: https://discord.gg/SX2txgr&lt;br /&gt;
* Twitter: https://twitter.com/falco_girgis&lt;br /&gt;
* LinkedIn: https://www.linkedin.com/feed/&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_in_Compiler_Explorer&amp;diff=3677</id>
		<title>SH4 in Compiler Explorer</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_in_Compiler_Explorer&amp;diff=3677"/>
		<updated>2025-01-29T15:18:13Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Thanks to the effort of Matt Godbolt (who hilariously enough is a former Dreamcast developer himself), the SuperH GCC toolchain is now available for use with [https://godbolt.org Compiler Explorer], along with all of the SH4-specific compiler flags and options typically used when targeting the Dreamcast. This gives us an invaluable tool for getting quick and immediate feedback on how well a given C or C++ source segment tends to translate into SH4 assembly, offering a little sandbox for testing and optimizing code targeting the Dreamcast.&lt;br /&gt;
&lt;br /&gt;
[[File:GCC Compiler Benchmarks.png|thumb|Benchmarking various GCC versions and flags]]&lt;br /&gt;
&lt;br /&gt;
= Configuration =&lt;br /&gt;
To arrive at a configuration mirroring a Dreamcast development environment, first select one of the GCC compiler versions for the SH architecture. Secondly, the following compiler options should be used as the baseline configuration:&lt;br /&gt;
* &amp;lt;code&amp;gt;-ml&amp;lt;/code&amp;gt;: compile code for the processor in little-endian mode&lt;br /&gt;
* FPU Mode:&lt;br /&gt;
** &amp;lt;code&amp;gt;-m4-single&amp;lt;/code&amp;gt;: generate code for the SH4 with a floating-point unit that supports both single and double-precision floating point arithmetic that defaults to single-precision mode upon function entry&lt;br /&gt;
** &amp;lt;code&amp;gt;-m4-single-only&amp;lt;/code&amp;gt;: generate code for the SH4 with a floating-point unit that only supports single-precision floating point arithmetic&lt;br /&gt;
* &amp;lt;code&amp;gt;-ffast-math&amp;lt;/code&amp;gt;: breaks strict IEEE compliance and allows for faster floating point approximations&lt;br /&gt;
* &amp;lt;code&amp;gt;-O3&amp;lt;/code&amp;gt;: optimization level 3&lt;br /&gt;
* &amp;lt;code&amp;gt;-mfsrra&amp;lt;/code&amp;gt;: enables emission of the fsrra instruction for reciprocal square root approximations (not available in GCC 4.7.4)&lt;br /&gt;
* &amp;lt;code&amp;gt;-mfsca&amp;lt;/code&amp;gt;: enables emission of the fsca instruction for sine and cosine approximations (not available in GCC 4.7.4)&lt;br /&gt;
* &amp;lt;code&amp;gt;-matomic-model=soft-imask&amp;lt;/code&amp;gt;: enables support for C11 and C++11 atomics by disabling then reenabling interrupts around atomic variable operations&lt;br /&gt;
* &amp;lt;code&amp;gt;-ftls-model=local-exec&amp;lt;/code&amp;gt;: enables the model used by KOS for supporting variables declared with the &amp;quot;thread_local&amp;quot; keyword&lt;br /&gt;
&lt;br /&gt;
= Convenience Templates =&lt;br /&gt;
The following are pre-configured templates you can use as sample Dreamcast build configurations:&lt;br /&gt;
* GCC4.9.4:&lt;br /&gt;
** [https://godbolt.org/z/9MKzeMfMj C11 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/qGzoeo4sj C++14 Hello World]&lt;br /&gt;
* GCC9.5.0:&lt;br /&gt;
** [https://godbolt.org/z/rvW3s3594 C17 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/qYfE5G6Mx C++17 Hello World]&lt;br /&gt;
* GCC12.2.0:&lt;br /&gt;
** [https://godbolt.org/z/94TKvxazn C17 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/61jqhE3zn C++20 Hello World]&lt;br /&gt;
* GCC13.1.0:&lt;br /&gt;
** [https://godbolt.org/z/Kb9bKe8ro C2X Hello World]&lt;br /&gt;
** [https://godbolt.org/z/51dv4ePsG C++23 Hello World]&lt;br /&gt;
* GCC13.2.0:&lt;br /&gt;
** [https://godbolt.org/z/rafvMdWGb C2X Hello World]&lt;br /&gt;
** [https://godbolt.org/z/MeG3rqna7 C++23 Hello World]&lt;br /&gt;
* GCC 14.1.0&lt;br /&gt;
** [https://godbolt.org/z/7ha8oj4vd C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/eW8Yd8sG9 C++26 Hello World]&lt;br /&gt;
* GCC 14.2.0&lt;br /&gt;
** [https://godbolt.org/z/a54qTYon4 C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/5njMrrh8z C++26 Hello World]&lt;br /&gt;
&lt;br /&gt;
Pre-configured template for ARM GCC8.5, Dreamcast&#039;s &amp;quot;AICA&amp;quot; sound chip:&lt;br /&gt;
* [https://godbolt.org/z/895dWG9qf C Hello World]&lt;br /&gt;
&lt;br /&gt;
= Tips and Notes =&lt;br /&gt;
* It has been noted that while &amp;lt;code&amp;gt;-O3&amp;lt;/code&amp;gt; is claimed to be the highest optimization level according to recent GCC documentation, some code differences can still be seen under certain circumstances when using &amp;lt;code&amp;gt;-O4&amp;lt;/code&amp;gt; and beyond.&lt;br /&gt;
* The compiler seems to ignore both &amp;lt;code&amp;gt;-mfsrra&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;-mfsca&amp;lt;/code&amp;gt; without the &amp;lt;code&amp;gt;-ffast-math&amp;lt;/code&amp;gt; option.&lt;br /&gt;
* With the proper flags enabled for fast-math, the compiler is smart enough to leverage the following from pure C code, almost certainly better than you can do with small intrinsic-style inline ASM calls, provided you&#039;re using the proper single-precision versions of any &amp;lt;code&amp;gt;&amp;lt;math.h&amp;gt;&amp;lt;/code&amp;gt; routines:&lt;br /&gt;
**&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{|&lt;br /&gt;
|+ Compiler-Generated Fast-Math Optimizations&lt;br /&gt;
|-&lt;br /&gt;
! Assembly Output !! C/C++ Input&lt;br /&gt;
|-&lt;br /&gt;
| FMAC || &amp;lt;code&amp;gt;z = x * y + z&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| FSCA || &amp;lt;code&amp;gt;s = sinf(angle); c = cosf(angle)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| FSRRA || &amp;lt;code&amp;gt;1.0f / sqrtf(x)&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
*Unfortunately the compiler has no knowledge of the following SIMD instructions, even with fast-math, so it&#039;s quite necessary to use inline assembly routines (provided by KallistiOS) for fully leveraging the SH4&#039;s FPU, when working with vectors and matrices in linear algebra routines:&lt;br /&gt;
**&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
{|&lt;br /&gt;
|+ Manual Inline Assembly Fast-Math Optimizations&lt;br /&gt;
|-&lt;br /&gt;
! Assembly Output !! C/C++ Input&lt;br /&gt;
|-&lt;br /&gt;
| FIPR || &amp;lt;code&amp;gt;Vector4 Dot Product&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| FTRV || &amp;lt;code&amp;gt;Vector4 * Matrix4x4 Transform&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
* Typically smaller code sizes and more tightly optimized code are seen with newer versions of GCC versus the older ones; however, this is not always the case.&lt;br /&gt;
* Evidently, even without a branch predictor, the C++20 &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[likely]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[unlikely]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; attributes as well as the GCC intrinsic &amp;lt;code&amp;gt;__builtin_expect()&amp;lt;/code&amp;gt; can have a fairly profound impact on code generation and optimization for conditionals and branches. More information can be found [https://dcemulation.org/phpBB/viewtopic.php?t=106029 here].&lt;br /&gt;
* &amp;lt;code&amp;gt;-fipa-pta&amp;lt;/code&amp;gt; allows the compiler to analyze pointer and reference usage beyond the scope of the current compiling function, which very often results in pretty decent performance increases at the cost of increased compile times and RAM usage.&lt;br /&gt;
* &amp;lt;code&amp;gt;-flto&amp;lt;/code&amp;gt; allows GCC to perform optimizations over the entire program and all translation units as a single entity during the linking phase, for the cost of increased compile times and RAM usage. This frequently results in more performant code.&lt;br /&gt;
* An in-depth benchmark comparing the run-time performance and compiled binary size output of every toolchain version officially supported by KOS with various optimization levels can be found [https://dcemulation.org/phpBB/viewtopic.php?t=106068 here].&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Pushing_Polygons&amp;diff=3672</id>
		<title>Pushing Polygons</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Pushing_Polygons&amp;diff=3672"/>
		<updated>2025-01-08T04:09:08Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: Created Basic skeleton page with index of topics&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;WIP page for a deep-dive into how to efficiently maximize polygon throughput and and optimize T&amp;amp;L for the Sega Dreamcast with the KallistiOS SDK.&lt;br /&gt;
&lt;br /&gt;
= Rendering =&lt;br /&gt;
== Vertex Submission ==&lt;br /&gt;
* Basic&lt;br /&gt;
* DMA&lt;br /&gt;
* Direct&lt;br /&gt;
* Hybrid&lt;br /&gt;
== Mesh Formats ==&lt;br /&gt;
* triangle Strips&lt;br /&gt;
== Vertex Formats ==&lt;br /&gt;
* sprites&lt;br /&gt;
* 16-bit UV&lt;br /&gt;
* floating-point colors&lt;br /&gt;
== Polygon Headers ==&lt;br /&gt;
* Caching&lt;br /&gt;
= SH4 Math Acceleration = &lt;br /&gt;
* vec3f&lt;br /&gt;
* matrix_t&lt;br /&gt;
* fmath.h&lt;br /&gt;
= Cache Management = &lt;br /&gt;
* Prefetching&lt;br /&gt;
* OCRAM&lt;br /&gt;
* OCINDEX&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_in_Compiler_Explorer&amp;diff=3671</id>
		<title>SH4 in Compiler Explorer</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=SH4_in_Compiler_Explorer&amp;diff=3671"/>
		<updated>2025-01-08T03:42:00Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: Created page with &amp;quot;Thanks to the effort of Matt Godbolt (who hilariously enough is a former Dreamcast developer himself), the SuperH GCC toolchain is now available for use with [https://godbolt.org Compiler Explorer], along with all of the SH4-specific compiler flags and options typically used when targeting the Dreamcast. This gives us an invaluable tool for getting quick and immediate feedback on how well a given C or C++ source segment tends to translate into SH4 assembly, offering a li...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Thanks to the effort of Matt Godbolt (who hilariously enough is a former Dreamcast developer himself), the SuperH GCC toolchain is now available for use with [https://godbolt.org Compiler Explorer], along with all of the SH4-specific compiler flags and options typically used when targeting the Dreamcast. This gives us an invaluable tool for getting quick and immediate feedback on how well a given C or C++ source segment tends to translate into SH4 assembly, offering a little sandbox for testing and optimizing code targeting the Dreamcast.&lt;br /&gt;
&lt;br /&gt;
[[File:GCC Compiler Benchmarks.png|thumb|Benchmarking various GCC versions and flags]]&lt;br /&gt;
&lt;br /&gt;
= Configuration =&lt;br /&gt;
To arrive at a configuration mirroring a Dreamcast development environment, first select one of the GCC compiler versions for the SH architecture. Secondly, the following compiler options should be used as the baseline configuration:&lt;br /&gt;
* &amp;lt;code&amp;gt;-ml&amp;lt;/code&amp;gt;: compile code for the processor in little-endian mode&lt;br /&gt;
* FPU Mode:&lt;br /&gt;
** &amp;lt;code&amp;gt;-m4-single-only&amp;lt;/code&amp;gt;: generate code for the SH4 with a floating-point unit that only supports single-precision floating point arithmetic&lt;br /&gt;
** &amp;lt;code&amp;gt;-m4-single&amp;lt;/code&amp;gt;: generate code for the SH4 with a floating-point unit that supports both single and double-precision floating point arithmetic that defaults to single-precision mode upon function entry&lt;br /&gt;
* &amp;lt;code&amp;gt;-ffast-math&amp;lt;/code&amp;gt;: breaks strict IEEE compliance and allows for faster floating point approximations&lt;br /&gt;
* &amp;lt;code&amp;gt;-O3&amp;lt;/code&amp;gt;: optimization level 3&lt;br /&gt;
* &amp;lt;code&amp;gt;-mfsrra&amp;lt;/code&amp;gt;: enables emission of the fsrra instruction for reciprocal square root approximations (not available in GCC 4.7.4)&lt;br /&gt;
* &amp;lt;code&amp;gt;-mfsca&amp;lt;/code&amp;gt;: enables emission of the fsca instruction for sine and cosine approximations (not available in GCC 4.7.4)&lt;br /&gt;
* &amp;lt;code&amp;gt;-matomic-model=soft-imask&amp;lt;/code&amp;gt;: enables support for C11 and C++11 atomics by disabling then reenabling interrupts around atomic variable operations&lt;br /&gt;
* &amp;lt;code&amp;gt;-ftls-model=local-exec&amp;lt;/code&amp;gt;: enables the model used by KOS for supporting variables declared with the &amp;quot;thread_local&amp;quot; keyword&lt;br /&gt;
&lt;br /&gt;
= Convenience Templates =&lt;br /&gt;
The following are pre-configured templates you can use as sample Dreamcast build configurations:&lt;br /&gt;
* GCC4.9.4:&lt;br /&gt;
** [https://godbolt.org/z/9MKzeMfMj C11 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/qGzoeo4sj C++14 Hello World]&lt;br /&gt;
* GCC9.5.0:&lt;br /&gt;
** [https://godbolt.org/z/rvW3s3594 C17 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/qYfE5G6Mx C++17 Hello World]&lt;br /&gt;
* GCC12.2.0:&lt;br /&gt;
** [https://godbolt.org/z/94TKvxazn C17 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/61jqhE3zn C++20 Hello World]&lt;br /&gt;
* GCC13.1.0:&lt;br /&gt;
** [https://godbolt.org/z/Kb9bKe8ro C2X Hello World]&lt;br /&gt;
** [https://godbolt.org/z/51dv4ePsG C++23 Hello World]&lt;br /&gt;
* GCC13.2.0:&lt;br /&gt;
** [https://godbolt.org/z/rafvMdWGb C2X Hello World]&lt;br /&gt;
** [https://godbolt.org/z/MeG3rqna7 C++23 Hello World]&lt;br /&gt;
* GCC 14.1.0&lt;br /&gt;
** [https://godbolt.org/z/7ha8oj4vd C23 Hello World]&lt;br /&gt;
** [https://godbolt.org/z/eW8Yd8sG9 C++26 Hello World]&lt;br /&gt;
&lt;br /&gt;
Pre-configured template for ARM GCC8.5, Dreamcast&#039;s &amp;quot;AICA&amp;quot; sound chip:&lt;br /&gt;
* [https://godbolt.org/z/895dWG9qf C Hello World]&lt;br /&gt;
&lt;br /&gt;
= Tips and Notes =&lt;br /&gt;
* It has been noted that while &amp;lt;code&amp;gt;-O3&amp;lt;/code&amp;gt; is claimed to be the highest optimization level according to recent GCC documentation, some code differences can still be seen under certain circumstances when using &amp;lt;code&amp;gt;-O4&amp;lt;/code&amp;gt; and beyond.&lt;br /&gt;
* The compiler seems to ignore both &amp;lt;code&amp;gt;-mfsrra&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;-mfsca&amp;lt;/code&amp;gt; without the &amp;lt;code&amp;gt;-ffast-math&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;-m4-single-only&amp;lt;/code&amp;gt; options.&lt;br /&gt;
* It is highly recommended that C code is written to use &amp;lt;code&amp;gt;-mfsrra&amp;lt;/code&amp;gt; (1.0/sqrt(N)) and &amp;lt;code&amp;gt;-mfsca&amp;lt;/code&amp;gt; (builtin sin/cos) over using inline assembly directly, as this seems to give the compiler more context for code optimization around these instructions.&lt;br /&gt;
* The &amp;lt;code&amp;gt;__builtin_prefetch&amp;lt;/code&amp;gt; intrinsic does seem to generate a single &amp;quot;pref&amp;quot; instruction and should be preferred over inline assembly.&lt;br /&gt;
* The compiler does not seem smart enough to utilize the FIPR (inner/dot product), FMAC (multiply and accumulate), or FTRV (transform vector) instructions regardless of how embarrassingly vectorizable the supplied C code seems to be, so linear algebra routines are forced to use inline assembly to fully leverage the SH4&#039;s SIMD instructions.&lt;br /&gt;
* Typically smaller code sizes and more tightly optimized code are seen with newer versions of GCC versus the older ones; however, this is not always the case.&lt;br /&gt;
* Evidently, even without a branch predictor, the C++20 &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[likely]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;[[unlikely]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; attributes as well as the GCC intrinsic &amp;lt;code&amp;gt;__builtin_expect()&amp;lt;/code&amp;gt; can have a fairly profound impact on code generation and optimization for conditionals and branches. More information can be found [https://dcemulation.org/phpBB/viewtopic.php?t=106029 here].&lt;br /&gt;
* &amp;lt;code&amp;gt;-fipa-pta&amp;lt;/code&amp;gt; allows the compiler to analyze pointer and reference usage beyond the scope of the current compiling function, which very often results in pretty decent performance increases at the cost of increased compile times and RAM usage.&lt;br /&gt;
* &amp;lt;code&amp;gt;-flto&amp;lt;/code&amp;gt; allows GCC to perform optimizations over the entire program and all translation units as a single entity during the linking phase, for the cost of increased compile times and RAM usage. This frequently results in more performant code.&lt;br /&gt;
* An in-depth benchmark comparing the run-time performance and compiled binary size output of every toolchain version officially supported by KOS with various optimization levels can be found [https://dcemulation.org/phpBB/viewtopic.php?t=106068 here].&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=DCWiki:Hardware&amp;diff=3277</id>
		<title>DCWiki:Hardware</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=DCWiki:Hardware&amp;diff=3277"/>
		<updated>2024-01-15T17:47:37Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: /* Hardware */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hardware ==&lt;br /&gt;
{| style=&amp;quot;width:100%&amp;quot;&lt;br /&gt;
! style=&amp;quot;width: 50%&amp;quot;|Console and Peripherals&lt;br /&gt;
! style=&amp;quot;width: 50%&amp;quot;|Modifications and Repair&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding: 5px;vertical-align:top&amp;quot;|&lt;br /&gt;
* [[Hardware overview]], [[VMU hardware overview]]&lt;br /&gt;
* [[Hardware variations]]&lt;br /&gt;
* [[A/V connectivity]]&lt;br /&gt;
* [[G2 bus]]&lt;br /&gt;
** [[Modem]], [[Broadband adapter]], [[LAN adapter]], [[Karaoke]], [[Zip drive]], [[G2 Terminator|Terminator]]&lt;br /&gt;
* [[Maple bus]]&lt;br /&gt;
** [[Controller]], [[Keyboard]], [[Mouse]], [[Arcade stick]], [[Twin stick]], [[Race wheel]], [[Light gun]], [[Fishing rod]], [[Maracas]], [[DreamEye webcam]]&lt;br /&gt;
** [[Mission Stick]], [[Panther DC]],  [[Densha de Go! controller]], [[Dance mat]], [[Pop&#039;n controller]], [[DreamParaPara Sensors]], [[VCD remote]]&lt;br /&gt;
** [[VMU]], [[Memory card]], [[Jump pack]], [[Microphone]]&lt;br /&gt;
** [[Aftermarket adapters]]&lt;br /&gt;
* [[Serial interface]]&lt;br /&gt;
** [[Neo Geo Pocket Color link cable]], [[VS cable]], [[MIDI adapter]], [[Coder&#039;s cable]], [[Serial SD card adapter]], [[Touchscreen]]&lt;br /&gt;
| style=&amp;quot;padding: 5px;vertical-align:top&amp;quot;|&lt;br /&gt;
{|&lt;br /&gt;
* [[Optical drive replacements]]&lt;br /&gt;
* [[DCDigital]] HDMI, [[S/PDIF]], [[Internal VGA]], [[MIDI expansion|MIDI]]&lt;br /&gt;
* [[BIOS modification]]&lt;br /&gt;
* [[Region change]], [[NTSC/PAL mode enforcement]]&lt;br /&gt;
* [[Power supply replacement]], [[Fan replacement]]&lt;br /&gt;
* [[DreamPi]]&lt;br /&gt;
* [[IDE hard drive modification]]&lt;br /&gt;
* [[Overclocking]], [[32MB RAM expansion]]&lt;br /&gt;
* [[VMU mods]]&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* [[GD-ROM drive repair]]&lt;br /&gt;
* [[PSU repair]]&lt;br /&gt;
* Controller board: [[F1 fuse repair|Fuse repair]], [[battery replacement]]&lt;br /&gt;
* [[Case whitening]]&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=DreamParaPara_Sensors&amp;diff=3276</id>
		<title>DreamParaPara Sensors</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=DreamParaPara_Sensors&amp;diff=3276"/>
		<updated>2024-01-15T17:46:14Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: Created page with &amp;quot;Sensor controller for DreamParaPara&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:DreamParaPara Controller.jpg|thumb|Sensor controller for DreamParaPara]]&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=File:DreamParaPara_Controller.jpg&amp;diff=3275</id>
		<title>File:DreamParaPara Controller.jpg</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=File:DreamParaPara_Controller.jpg&amp;diff=3275"/>
		<updated>2024-01-15T17:45:57Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: GyroVorbis uploaded a new version of File:DreamParaPara Controller.jpg&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Sensor controller for DreamParaPara&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=File:DreamParaPara_Controller.jpg&amp;diff=3274</id>
		<title>File:DreamParaPara Controller.jpg</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=File:DreamParaPara_Controller.jpg&amp;diff=3274"/>
		<updated>2024-01-15T17:43:39Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Sensor controller for DreamParaPara&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Performance_3rd_Party_VMU&amp;diff=3245</id>
		<title>Performance 3rd Party VMU</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Performance_3rd_Party_VMU&amp;diff=3245"/>
		<updated>2023-12-05T03:01:24Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Performance VMU.jpg|thumb|Performance 3rd Party VMU]]&lt;br /&gt;
Despite popular belief, there is actually one known third-party Visual Memory Unit: the ultra-rare &amp;quot;Performance&amp;quot; VMU. While it lacks the full standalone GAME mode featured in the first-party VMUs, preventing it from playing minigames, it does provide equivalent functionality while plugged into the controller and even has a builtin firmware offering several features when used in standalone mode.&lt;br /&gt;
&lt;br /&gt;
=== Features ===&lt;br /&gt;
Maple Functionality (when connected to the controller):&lt;br /&gt;
* LCD Display Screen&lt;br /&gt;
* Buzzer Tone Generation&lt;br /&gt;
* 8-bit FAT Filesystem&lt;br /&gt;
&lt;br /&gt;
Standalone Functionality (when battery-powered):&lt;br /&gt;
* Calendar&lt;br /&gt;
&lt;br /&gt;
Unknown Support: &lt;br /&gt;
* Can VMU Buttons be accessed while plugged into the controller as with first-party VMUs?&lt;br /&gt;
&lt;br /&gt;
=== Packaging ===&lt;br /&gt;
[[File:Front Box of Performance VMU.jpg|thumb|left|Front Packaging of the Performance VMU]]&lt;br /&gt;
[[File:Performance VMU Box Rear.jpg|thumb|center|Front Packaging of the Performance VMU]]&lt;br /&gt;
&lt;br /&gt;
=== Hardware ===&lt;br /&gt;
[[File:Performance VMU Insides.png|thumb|center|Disassembled Performance VMU]]&lt;br /&gt;
&lt;br /&gt;
=== Bugs/Extras ===&lt;br /&gt;
[[File:Performance VMU Calendar.jpg|thumb|center|Performance VMU Calendar]]&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=File:Performance_VMU_Calendar.jpg&amp;diff=3244</id>
		<title>File:Performance VMU Calendar.jpg</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=File:Performance_VMU_Calendar.jpg&amp;diff=3244"/>
		<updated>2023-12-05T03:00:54Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Performance VMU Calendar&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=File:Performance_VMU_Insides.png&amp;diff=3243</id>
		<title>File:Performance VMU Insides.png</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=File:Performance_VMU_Insides.png&amp;diff=3243"/>
		<updated>2023-12-05T02:59:06Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Disassembled Performance VMU&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=File:Performance_VMU_Box_Rear.jpg&amp;diff=3242</id>
		<title>File:Performance VMU Box Rear.jpg</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=File:Performance_VMU_Box_Rear.jpg&amp;diff=3242"/>
		<updated>2023-12-05T02:53:42Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Rear Packaging of the Performance VMU&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=File:Performance_VMU_Box_Front.jpg&amp;diff=3241</id>
		<title>File:Performance VMU Box Front.jpg</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=File:Performance_VMU_Box_Front.jpg&amp;diff=3241"/>
		<updated>2023-12-05T02:53:26Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: GyroVorbis moved page File:Performance VMU Box Front.jpg to File:Performance VMU Box Rear.jpg: Misnamed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[File:Performance VMU Box Rear.jpg]]&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=File:Performance_VMU_Box_Rear.jpg&amp;diff=3240</id>
		<title>File:Performance VMU Box Rear.jpg</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=File:Performance_VMU_Box_Rear.jpg&amp;diff=3240"/>
		<updated>2023-12-05T02:53:26Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: GyroVorbis moved page File:Performance VMU Box Front.jpg to File:Performance VMU Box Rear.jpg: Misnamed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Front Packaging of the Performance VMU&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=File:Front_Box_of_Performance_VMU.jpg&amp;diff=3239</id>
		<title>File:Front Box of Performance VMU.jpg</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=File:Front_Box_of_Performance_VMU.jpg&amp;diff=3239"/>
		<updated>2023-12-05T02:51:46Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Front Packaging of the Performance VMU&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=File:Performance_VMU_Box_Rear.jpg&amp;diff=3238</id>
		<title>File:Performance VMU Box Rear.jpg</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=File:Performance_VMU_Box_Rear.jpg&amp;diff=3238"/>
		<updated>2023-12-05T02:49:33Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Front Packaging of the Performance VMU&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Performance_3rd_Party_VMU&amp;diff=3237</id>
		<title>Performance 3rd Party VMU</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Performance_3rd_Party_VMU&amp;diff=3237"/>
		<updated>2023-12-05T02:47:49Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: Created page with &amp;quot;Performance 3rd Party VMU Despite popular belief, there is actually one known third-party Visual Memory Unit: the ultra-rare &amp;quot;Performance&amp;quot; VMU. While it lacks the full standalone GAME mode featured in the first-party VMUs, preventing it from playing minigames, it does provide equivalent functionality while plugged into the controller and even has a builtin firmware offering several features when used in standalone mode.  === Features ==...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Performance VMU.jpg|thumb|Performance 3rd Party VMU]]&lt;br /&gt;
Despite popular belief, there is actually one known third-party Visual Memory Unit: the ultra-rare &amp;quot;Performance&amp;quot; VMU. While it lacks the full standalone GAME mode featured in the first-party VMUs, preventing it from playing minigames, it does provide equivalent functionality while plugged into the controller and even has a builtin firmware offering several features when used in standalone mode.&lt;br /&gt;
&lt;br /&gt;
=== Features ===&lt;br /&gt;
Maple Functionality (when connected to the controller):&lt;br /&gt;
* LCD Display Screen&lt;br /&gt;
* Buzzer Tone Generation&lt;br /&gt;
* 8-bit FAT Filesystem&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Unknown Support: &lt;br /&gt;
* Can VMU Buttons be accessed while plugged into the controller as with first-party VMUs?&lt;br /&gt;
&lt;br /&gt;
=== Packaging ===&lt;br /&gt;
&lt;br /&gt;
=== Hardware ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Bugs/Extras ===&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=File:Performance_VMU.jpg&amp;diff=3236</id>
		<title>File:Performance VMU.jpg</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=File:Performance_VMU.jpg&amp;diff=3236"/>
		<updated>2023-12-05T02:35:21Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Performance 3rd Party VMU&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Useful_programming_tips&amp;diff=3220</id>
		<title>Useful programming tips</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Useful_programming_tips&amp;diff=3220"/>
		<updated>2023-10-14T08:21:14Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: I&amp;#039;m sorry, but the way this is worded is just not quite correct. He&amp;#039;s talking about aspects of the processor, but he&amp;#039;s making it sound like modern software PARADIGMS and practices don&amp;#039;t apply to DC, when in reality we have C++20 and even all of the async, concurrent crap used in multicore working just fine.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Dreamcast&#039;s CPU, model SH7091, is virtually identical to the Renesas SH7750 series of SH4 CPUs. As such, anything that would normally apply to the SuperH-4 architecture applies here. Given that the SH4 is a processor from 1998, many hardware features that we have grown accustomed to on more recent x86 and ARM64 processors either do not apply or behave much more primitively on the SH4. For example, SH4 does not have branch prediction, speculative execution, or multiple cores, but it does have a 64-bit floating point unit,&amp;lt;ref&amp;gt;It&#039;s predominantly used for single-precision operations: it &#039;&#039;can&#039;&#039; do doubles, but that doesn&#039;t mean it&#039;s a great idea!&amp;lt;/ref&amp;gt; a couple of 128-bit vector operations on 4x packed 32-bit floats,&amp;lt;ref&amp;gt;See fipr, ftrv: http://www.shared-ptr.com/sh_insns.html&amp;lt;/ref&amp;gt; a memory management unit (MMU), and a direct memory access controller (DMAC).&lt;br /&gt;
&lt;br /&gt;
In truth, at a very basic level the SH4 architecture is fundamentally not that different from these other, more mainstream architectures (in fact, ARM Thumb is based on SuperH&amp;lt;ref&amp;gt;https://lwn.net/Articles/647636/&amp;lt;/ref&amp;gt;), so programming on the SH4 does not require much in the way of &amp;quot;re-learning&amp;quot; how to do things, especially since the Dreamcast uses it in little endian mode exclusively. Mainly, SH4 programming just requires paying a lot more attention to things that modern architectures have made very convenient, like data alignment, cache management, and pipelining.&lt;br /&gt;
&lt;br /&gt;
The following page is a collection of programming tips and tricks to help with optimizing programs to make full use of the SH4 CPU. &#039;&#039;&#039;&#039;&#039;This is not meant to be a substitute for reading the SH7750 series hardware and software manuals,&#039;&#039;&#039;&#039;&#039; rather it should be seen more as an additional reference based on experiences working with the chip (and, in fact, certain terms and hardware-specific concepts assume familiarity with those manuals). Both manuals, &amp;quot;SH7750, SH7750S, SH7750R Group User&#039;s Manual: Hardware&amp;quot; and &amp;quot;SH-4 Software Manual,&amp;quot; can be downloaded from the &amp;quot;Documents&amp;quot; section of any SH7750 series processor&#039;s product page on Renesas&#039;s website: https://www.renesas.com/eu/en/products/microcontrollers-microprocessors/superh/sh7750/sh7750r.html, and the SH4 C ABI on STMicroelectronics&#039;s website, &amp;quot;RM0197: SH-4 generic and C specific application binary interface,&amp;quot; is incredibly handy, too--search for RM0197: https://www.st.com/content/st_com/en.html.&lt;br /&gt;
&lt;br /&gt;
A very convenient SuperH assembly reference can be found here, as well: http://www.shared-ptr.com/sh_insns.html.&lt;br /&gt;
&lt;br /&gt;
This page refers to the documents as follows:&lt;br /&gt;
* SH7750 Hardware Manual: &amp;quot;SH7750, SH7750S, SH7750R Group User&#039;s Manual: Hardware&amp;quot;&lt;br /&gt;
* SH7750 Software Manual: &amp;quot;SH-4 Software Manual&amp;quot;&lt;br /&gt;
* SH4 C ABI: &amp;quot;RM0197: SH-4 generic and C specific application binary interface&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Alignment ==&lt;br /&gt;
&lt;br /&gt;
(Refer to: SH7750 Hardware Manual, Section 5 &amp;quot;Exceptions&amp;quot;) &lt;br /&gt;
&lt;br /&gt;
The SH4 lives and dies by alignment, and very strictly requires data to be aligned according to its type in memory. Crashes will otherwise ensue.&lt;br /&gt;
&lt;br /&gt;
Take the following example, which defines a packed structure aligned to 4 bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct __attribute__ ((packed, aligned(4))) {&lt;br /&gt;
	unsigned char id[4];&lt;br /&gt;
	unsigned int address;&lt;br /&gt;
	unsigned int size;&lt;br /&gt;
	unsigned char data[]; // Flexible array member&lt;br /&gt;
} command_t;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Accessing data from this struct is pretty simple, it should just need a simple 4-byte access. This works because the struct is aligned to 4 bytes.&lt;br /&gt;
&lt;br /&gt;
Doing this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
unsigned int cmd_addr = ntohl(command-&amp;gt;address);&lt;br /&gt;
unsigned int cmd_size = ntohl(command-&amp;gt;size);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Produces this output (GCC 9.2.0):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;objdump&amp;quot;&amp;gt;420 02e4 862F     		mov.l	r8,@-r15&lt;br /&gt;
421 02e6 4365     		mov	r4,r5&lt;br /&gt;
422 02e8 962F     		mov.l	r9,@-r15&lt;br /&gt;
423 02ea 0C75     		add	#12,r5&lt;br /&gt;
424 02ec 224F     		sts.l	pr,@-r15&lt;br /&gt;
425 02ee 4159     		mov.l	@(4,r4),r9&lt;br /&gt;
426 02f0 4256     		mov.l	@(8,r4),r6&lt;br /&gt;
427 02f2 12D0     		mov.l	.L71,r0&lt;br /&gt;
428 02f4 9869     		swap.b	r9,r9&lt;br /&gt;
429 02f6 6866     		swap.b	r6,r6&lt;br /&gt;
430 02f8 11D4     		mov.l	.L72,r4&lt;br /&gt;
431 02fa 6966     		swap.w	r6,r6&lt;br /&gt;
432 02fc 9969     		swap.w	r9,r9&lt;br /&gt;
433 02fe 9869     		swap.b	r9,r9&lt;br /&gt;
434 0300 6868     		swap.b	r6,r8&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But what if it weren&#039;t aligned to 4 bytes? Just this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct __attribute__ ((packed)) {&lt;br /&gt;
	unsigned char id[4];&lt;br /&gt;
	unsigned int address;&lt;br /&gt;
	unsigned int size;&lt;br /&gt;
	unsigned char data[]; // Flexible array member&lt;br /&gt;
} command_t;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Accessing the data looks like this, in that case (GCC 9.2.0):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;objdump&amp;quot;&amp;gt;555 03f0 862F             mov.l    r8,@-r15&lt;br /&gt;
556 03f2 4365             mov    r4,r5&lt;br /&gt;
557 03f4 962F             mov.l    r9,@-r15&lt;br /&gt;
558 03f6 0C75             add    #12,r5&lt;br /&gt;
559 03f8 224F             sts.l    pr,@-r15&lt;br /&gt;
560 03fa 4484             mov.b    @(4,r4),r0&lt;br /&gt;
561 03fc 0C63             extu.b    r0,r3&lt;br /&gt;
562 03fe 4584             mov.b    @(5,r4),r0&lt;br /&gt;
563 0400 0C61             extu.b    r0,r1&lt;br /&gt;
564 0402 4684             mov.b    @(6,r4),r0&lt;br /&gt;
565 0404 1861             swap.b    r1,r1&lt;br /&gt;
566 0406 0C60             extu.b    r0,r0&lt;br /&gt;
567 0408 3B21             or    r3,r1&lt;br /&gt;
568 040a 2840             shll16    r0&lt;br /&gt;
569 040c 0B21             or    r0,r1&lt;br /&gt;
570 040e 4784             mov.b    @(7,r4),r0&lt;br /&gt;
571 0410 2840             shll16    r0&lt;br /&gt;
572 0412 1840             shll8    r0&lt;br /&gt;
573 0414 1B20             or    r1,r0&lt;br /&gt;
574 0416 0869             swap.b    r0,r9&lt;br /&gt;
575 0418 4884             mov.b    @(8,r4),r0&lt;br /&gt;
576 041a 9969             swap.w    r9,r9&lt;br /&gt;
577 041c 0C63             extu.b    r0,r3&lt;br /&gt;
578 041e 4984             mov.b    @(9,r4),r0&lt;br /&gt;
579 0420 9869             swap.b    r9,r9&lt;br /&gt;
580 0422 0C62             extu.b    r0,r2&lt;br /&gt;
581 0424 4A84             mov.b    @(10,r4),r0&lt;br /&gt;
582 0426 2862             swap.b    r2,r2&lt;br /&gt;
583 0428 0C60             extu.b    r0,r0&lt;br /&gt;
584 042a 3B22             or    r3,r2&lt;br /&gt;
585 042c 2840             shll16    r0&lt;br /&gt;
586 042e 0B22             or    r0,r2&lt;br /&gt;
587 0430 4B84             mov.b    @(11,r4),r0&lt;br /&gt;
588 0432 12D4             mov.l    .L73,r4&lt;br /&gt;
589 0434 2840             shll16    r0&lt;br /&gt;
590 0436 1840             shll8    r0&lt;br /&gt;
591 0438 2B20             or    r2,r0&lt;br /&gt;
592 043a 0860             swap.b    r0,r0&lt;br /&gt;
593 043c 0961             swap.w    r0,r1&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
All of this is just from this simple operation:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
unsigned int cmd_addr = ntohl(command-&amp;gt;address);&lt;br /&gt;
unsigned int cmd_size = ntohl(command-&amp;gt;size);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What&#039;s going on here is GCC is avoiding an address alignment crash that would occur from accessing 1-byte-aligned data. This is because struct packing aligns to 1 byte, and GCC needs to do the following process to build an unsigned 4-byte integer from 1-byte accesses: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
mov.b, zero-extend&lt;br /&gt;
mov.b, zero-extend, shift, add&lt;br /&gt;
mov.b, zero-extend, shift, add&lt;br /&gt;
mov.b, zero-extend, shift, add&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Note: all the swap instructions come from ntohl, as this code is from a network driver that needs to byte swap data after receiving a network transmission.)&lt;br /&gt;
&lt;br /&gt;
Considering that 1x mov.b takes the same amount of time as 1x mov.l, plus all the other operations that must be done to build the 4-byte data out of 1-byte accesses, it&#039;s easy to see how big the performance hit from mismanaging alignment can be!&lt;br /&gt;
&lt;br /&gt;
== Cache Management ==&lt;br /&gt;
&lt;br /&gt;
(Refer to: SH7750 Hardware Manual, Section 4 &amp;quot;Caches&amp;quot; and SH7750 Software Manual, Section 9 &amp;quot;Instruction Descriptions&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Unlike modern processors, where caches are several megabytes in size and can therefore hold entire programs, the SH4 in the Dreamcast only has a 16kB data cache and 8kB instruction cache. Consequently, cache management is very important in order to achieve maximum performance. As is always true of cache optimization, write-back memory mode is required to make much use of it (it&#039;s used everywhere by default in [[KallistiOS]] and enabled for P0/U0/P3--but not P1--in [[DreamHAL]]&#039;s startup file).&lt;br /&gt;
&lt;br /&gt;
Half of the data cache can also be used as a form of high-speed RAM (referred to as OCRAM), but in most cases programs should stick to using the full cache size for cache purposes. The SH4 uses a direct-mapped cache, meaning that there is only one cache entry for every 16kB memory chunk (half that when used in OCRAM mode) and cache trashing can happen if trying to do something like copy data from some address to a destination address that is an integer multiple of the cache size away from that address (e.g. source = address offset 8 and destination = address 16kB + 8).&lt;br /&gt;
&lt;br /&gt;
The SH4 provides the following instructions in addition to the two 32-byte &amp;quot;store queues&amp;quot; (SQs) to make efficient use of the cache:&lt;br /&gt;
* &#039;&#039;&#039;movca.l:&#039;&#039;&#039; Store register data to cache, if there&#039;s a cache miss just allocate a cache block and write to it without first reading that cache block from memory&lt;br /&gt;
* &#039;&#039;&#039;ocbp:&#039;&#039;&#039; Purge cache block; write back cache block and invalidate it&lt;br /&gt;
* &#039;&#039;&#039;ocbi:&#039;&#039;&#039; Invalidate cache block without writing it back&lt;br /&gt;
* &#039;&#039;&#039;ocbwb:&#039;&#039;&#039; Write cache block back to external memory, and keep it in the cache&lt;br /&gt;
&lt;br /&gt;
== C Function Register Allocation ==&lt;br /&gt;
&lt;br /&gt;
(Refer to: SH4 C ABI) &lt;br /&gt;
&lt;br /&gt;
(Note: when using GCC 9.x at various optimization levels, like -O3, it tries its best to coalesce output code into this format wherever it can. Of course, if GCC is able to inline a function, parameter-passing becomes a moot point.)&lt;br /&gt;
&lt;br /&gt;
The SH4 C ABI specifies that 4 integers (r4-r7) and 8 floats (fr4-fr11) can be passed in registers as function call arguments, and that r0-r3 and fr0-fr3 are also call-clobbered. Passing arguments in registers means that functions can take 4 integers and 8 floats without forcing arguments to be pushed on the stack, saving the cycle penalties that would otherwise occur from stack pushes and associated memory accesses. The call-clobbering of r0-r3 and fr0-fr3 means that those can be used as 4 integer local variables and 4 float variables, as well. Additionally, any of these registers not used for parameters can be repurposed as local variables, so if one only needs to pass in 4 floats to a function, one can then define 4 more local variable floats on top of the 4 we get from fr0-fr3 and they will just use the unused registers.&lt;br /&gt;
&lt;br /&gt;
== Pipelining and Instruction-Level Parallelism ==&lt;br /&gt;
&lt;br /&gt;
(Refer to: SH7750 Hardware Manual, Section 8 &amp;quot;Pipelining&amp;quot;) &lt;br /&gt;
&lt;br /&gt;
This section is really only relevant when writing assembly. If you write code in a high-level language like C/C++, compilers [try to] take of this for you and there isn&#039;t much you can do about it.&lt;br /&gt;
&lt;br /&gt;
Because of the SH4&#039;s dual-issue superscalar design, the CPU preloads two instructions at once, and under the right circumstances these instructions can be executed in parallel. The SH4 architecture organizes various instructions into &amp;quot;instruction groups,&amp;quot; and parallel execution primarily occurs when two instructions of different groups are issued together. There are a variety of special cases to this rule of thumb, however, and more advanced code can be structured to take advantage of these properties.&lt;br /&gt;
&lt;br /&gt;
For example, if the two instructions are of different groups but have a dependency chain, the second instruction will stall into the next cycle, and there is also the fact that CO group instructions do not parallelize with anything. Conversely, there are special cases like 0-cycle instructions that can execute in parallel &#039;&#039;despite&#039;&#039; having dependency chains (e.g. a &amp;quot;mov Rn, Rm&amp;quot; followed by an &amp;quot;add #imm8, Rm&amp;quot;), and MT group instructions that can parallelize with other MT group instructions (unless there&#039;s a non-special-case dependency chain).&lt;br /&gt;
&lt;br /&gt;
Appropriate usage of instruction-level parallelism is the only way to achieve &amp;gt;200 MIPS (millions of instructions per second) on a 200MHz SH4.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=File:VMU_Dev_Lesson_1.png&amp;diff=3175</id>
		<title>File:VMU Dev Lesson 1.png</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=File:VMU_Dev_Lesson_1.png&amp;diff=3175"/>
		<updated>2023-07-28T11:55:04Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Screenshot from Marble_Grainite&#039;s first VMU Dev Lesson&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=VMU_emulators&amp;diff=3164</id>
		<title>VMU emulators</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=VMU_emulators&amp;diff=3164"/>
		<updated>2023-07-13T11:27:27Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: /* ElysianVMU */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;VMU Emulators are software applications that allow you to run enjoy VMU ROMs, games, applications, and animations without needing the actual VMU hardware. &lt;br /&gt;
&lt;br /&gt;
=ElysianVMU=&lt;br /&gt;
ElysianVMU is a cross-platform feature-rich emulator being developed alongside the Elysian Shadows Toolkit, with the goal of bringing Dreamcast-exclusive VMU content to all platforms supported by their engine. The team has decided to release the emulator to the Dreamcast scene. It serves as a gaming platform, VMU filesystem manager, and even includes development tools targeted at helping developers write custom VMU software. &lt;br /&gt;
* Official Page : [https://evmu.elysianshadows.com https://evmu.elysianshadows.com]&lt;br /&gt;
* Core Source Code : [https://github.com/gyrovorbis/libevmu GitHub]&lt;br /&gt;
* Documentation : [http://vmu.elysianshadows.com/index.html http://vmu.elysianshadows.com/index.html]&lt;br /&gt;
* Developer by : [[User:GyroVorbis|Falco Girgis]], Elysian Shadows Team&lt;br /&gt;
* Status : Active&lt;br /&gt;
* Compatibility: Very Good&lt;br /&gt;
* Platform(s) : &lt;br /&gt;
** Full Support: Windows, MacOS, Linux, Web, PSP, Raspberry Pi &lt;br /&gt;
** Partial Support: GameCube&lt;br /&gt;
** Future Support: iOS, Android, Dreamcast&lt;br /&gt;
* Features&lt;br /&gt;
** Supported File Formats: &lt;br /&gt;
*** ROM Images: .VMI/.VMS, .DCI, &lt;br /&gt;
*** Flash Images: .DCM, .VMU&lt;br /&gt;
*** Other: .BIN (bios), .LCD (VMU Animator)&lt;br /&gt;
** Emulation&lt;br /&gt;
*** Save/Load State&lt;br /&gt;
*** Japanese + US Bios Support&lt;br /&gt;
*** Accurate Audio&lt;br /&gt;
*** Gamepad/Joystick Support&lt;br /&gt;
*** Analog Stick Support&lt;br /&gt;
*** Fullscreen and Pixel-Perfect Scaling Modes&lt;br /&gt;
*** Physically Accurate LCD Emulation (pixel ghosting, emulated grayscale)&lt;br /&gt;
*** Fast-Forward &lt;br /&gt;
*** Low-battery Emulation&lt;br /&gt;
*** Serial Communications&lt;br /&gt;
**** VMU-to-DC (using Maple over TCP/IP)&lt;br /&gt;
***** ESTk/Elysian Shadows Engine support (full)&lt;br /&gt;
***** DC Emulator support (WIP, pending someone willing to collaborate)&lt;br /&gt;
**** VMU-to-VMU &lt;br /&gt;
***** TCP/IP (partial support, WIP)&lt;br /&gt;
***** Serial/GPIO pins (Raspberry Pi only, WIP)&lt;br /&gt;
** Filesystem Tools&lt;br /&gt;
*** File Filesystem Manager&lt;br /&gt;
*** VMU Animator File Playback&lt;br /&gt;
*** VMU Icon Ripping&lt;br /&gt;
*** VMU EyeCatch Ripping&lt;br /&gt;
*** Framebuffer Screenshot Capture&lt;br /&gt;
*** Record to Animated GIF&lt;br /&gt;
*** Convert/Export between file formats&lt;br /&gt;
*** Modify Volume Icon + Color&lt;br /&gt;
*** Jet Set (Grind) Radio Custom Graffiti Tool (WIP)&lt;br /&gt;
*** Lock/Unlock Extra Blocks&lt;br /&gt;
*** Defragmenter&lt;br /&gt;
*** File Checking/Repair/Debugging&lt;br /&gt;
** Developer Tools&lt;br /&gt;
*** Frame-by-Frame Execution&lt;br /&gt;
*** Real-Time Memory Browser and Hex Editor (RAM/Flash)&lt;br /&gt;
*** Invalid Hardware Operation/Warning Log&lt;br /&gt;
*** Buzzer Tool (for audio composition/debugging) (WIP)&lt;br /&gt;
&lt;br /&gt;
=SoftVMS=&lt;br /&gt;
The original VMU emulator, written by the man who helped to reverse engineer the platform and kickstart the homebrew scene.&lt;br /&gt;
* Official Page : [https://www.zophar.net/consoles/dreamcast/vms/softvms.html](https://www.zophar.net/consoles/dreamcast/vms/softvms.html)&lt;br /&gt;
* Developer : Marcus Comstedt&lt;br /&gt;
* Status : Inactive&lt;br /&gt;
* Compatibility: Good&lt;br /&gt;
* Platform(s) : Windows&lt;br /&gt;
&lt;br /&gt;
=VeMUlator PRO=&lt;br /&gt;
* Google Play : [https://apkhome.net/vemulator-pro-dreamcast-vmu-emulator-0-7/]&lt;br /&gt;
* Developer : MJaoune Software&lt;br /&gt;
* Compatibility: Unknown&lt;br /&gt;
* Platform(s) : Android&lt;br /&gt;
&lt;br /&gt;
=Visual Memory Emulator=&lt;br /&gt;
* Google Play : [https://play.google.com/store/apps/details?id=com.nuritsubushi.vmemu]&lt;br /&gt;
* Developer : Kum&lt;br /&gt;
* Compatibility : Unknown&lt;br /&gt;
* Platform(s) : Android&lt;br /&gt;
&lt;br /&gt;
=DirectVMS=&lt;br /&gt;
*Developer : [http://www.fallenrealm.com/directvms/index.html Fallen Realm]&lt;br /&gt;
*Platforms: Windows&lt;br /&gt;
* Latest release: 1.8, 09/24/2000&lt;br /&gt;
* Download [http://www.dcemulation.org/files/pcemu/DirectVMUexec.zip Binary], [http://www.dcemulation.org/files/pcemu/DirectVMUsource.zip Source Code]&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=VMU_emulators&amp;diff=3163</id>
		<title>VMU emulators</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=VMU_emulators&amp;diff=3163"/>
		<updated>2023-07-13T11:27:06Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: /* ElysianVMU */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;VMU Emulators are software applications that allow you to run enjoy VMU ROMs, games, applications, and animations without needing the actual VMU hardware. &lt;br /&gt;
&lt;br /&gt;
=ElysianVMU=&lt;br /&gt;
ElysianVMU is a cross-platform feature-rich emulator being developed alongside the Elysian Shadows Toolkit, with the goal of bringing Dreamcast-exclusive VMU content to all platforms supported by their engine. The team has decided to release the emulator to the Dreamcast scene. It serves as a gaming platform, VMU filesystem manager, and even includes development tools targeted at helping developers write custom VMU software. &lt;br /&gt;
* Official Page : [https://evmu.elysianshadows.com https://evmu.elysianshadows.com]&lt;br /&gt;
* Core Source Code : [https://github.com/gyrovorbis/libevmu|GitHub]&lt;br /&gt;
* Documentation : [http://vmu.elysianshadows.com/index.html http://vmu.elysianshadows.com/index.html]&lt;br /&gt;
* Developer by : [[User:GyroVorbis|Falco Girgis]], Elysian Shadows Team&lt;br /&gt;
* Status : Active&lt;br /&gt;
* Compatibility: Very Good&lt;br /&gt;
* Platform(s) : &lt;br /&gt;
** Full Support: Windows, MacOS, Linux, Web, PSP, Raspberry Pi &lt;br /&gt;
** Partial Support: GameCube&lt;br /&gt;
** Future Support: iOS, Android, Dreamcast&lt;br /&gt;
* Features&lt;br /&gt;
** Supported File Formats: &lt;br /&gt;
*** ROM Images: .VMI/.VMS, .DCI, &lt;br /&gt;
*** Flash Images: .DCM, .VMU&lt;br /&gt;
*** Other: .BIN (bios), .LCD (VMU Animator)&lt;br /&gt;
** Emulation&lt;br /&gt;
*** Save/Load State&lt;br /&gt;
*** Japanese + US Bios Support&lt;br /&gt;
*** Accurate Audio&lt;br /&gt;
*** Gamepad/Joystick Support&lt;br /&gt;
*** Analog Stick Support&lt;br /&gt;
*** Fullscreen and Pixel-Perfect Scaling Modes&lt;br /&gt;
*** Physically Accurate LCD Emulation (pixel ghosting, emulated grayscale)&lt;br /&gt;
*** Fast-Forward &lt;br /&gt;
*** Low-battery Emulation&lt;br /&gt;
*** Serial Communications&lt;br /&gt;
**** VMU-to-DC (using Maple over TCP/IP)&lt;br /&gt;
***** ESTk/Elysian Shadows Engine support (full)&lt;br /&gt;
***** DC Emulator support (WIP, pending someone willing to collaborate)&lt;br /&gt;
**** VMU-to-VMU &lt;br /&gt;
***** TCP/IP (partial support, WIP)&lt;br /&gt;
***** Serial/GPIO pins (Raspberry Pi only, WIP)&lt;br /&gt;
** Filesystem Tools&lt;br /&gt;
*** File Filesystem Manager&lt;br /&gt;
*** VMU Animator File Playback&lt;br /&gt;
*** VMU Icon Ripping&lt;br /&gt;
*** VMU EyeCatch Ripping&lt;br /&gt;
*** Framebuffer Screenshot Capture&lt;br /&gt;
*** Record to Animated GIF&lt;br /&gt;
*** Convert/Export between file formats&lt;br /&gt;
*** Modify Volume Icon + Color&lt;br /&gt;
*** Jet Set (Grind) Radio Custom Graffiti Tool (WIP)&lt;br /&gt;
*** Lock/Unlock Extra Blocks&lt;br /&gt;
*** Defragmenter&lt;br /&gt;
*** File Checking/Repair/Debugging&lt;br /&gt;
** Developer Tools&lt;br /&gt;
*** Frame-by-Frame Execution&lt;br /&gt;
*** Real-Time Memory Browser and Hex Editor (RAM/Flash)&lt;br /&gt;
*** Invalid Hardware Operation/Warning Log&lt;br /&gt;
*** Buzzer Tool (for audio composition/debugging) (WIP)&lt;br /&gt;
&lt;br /&gt;
=SoftVMS=&lt;br /&gt;
The original VMU emulator, written by the man who helped to reverse engineer the platform and kickstart the homebrew scene.&lt;br /&gt;
* Official Page : [https://www.zophar.net/consoles/dreamcast/vms/softvms.html](https://www.zophar.net/consoles/dreamcast/vms/softvms.html)&lt;br /&gt;
* Developer : Marcus Comstedt&lt;br /&gt;
* Status : Inactive&lt;br /&gt;
* Compatibility: Good&lt;br /&gt;
* Platform(s) : Windows&lt;br /&gt;
&lt;br /&gt;
=VeMUlator PRO=&lt;br /&gt;
* Google Play : [https://apkhome.net/vemulator-pro-dreamcast-vmu-emulator-0-7/]&lt;br /&gt;
* Developer : MJaoune Software&lt;br /&gt;
* Compatibility: Unknown&lt;br /&gt;
* Platform(s) : Android&lt;br /&gt;
&lt;br /&gt;
=Visual Memory Emulator=&lt;br /&gt;
* Google Play : [https://play.google.com/store/apps/details?id=com.nuritsubushi.vmemu]&lt;br /&gt;
* Developer : Kum&lt;br /&gt;
* Compatibility : Unknown&lt;br /&gt;
* Platform(s) : Android&lt;br /&gt;
&lt;br /&gt;
=DirectVMS=&lt;br /&gt;
*Developer : [http://www.fallenrealm.com/directvms/index.html Fallen Realm]&lt;br /&gt;
*Platforms: Windows&lt;br /&gt;
* Latest release: 1.8, 09/24/2000&lt;br /&gt;
* Download [http://www.dcemulation.org/files/pcemu/DirectVMUexec.zip Binary], [http://www.dcemulation.org/files/pcemu/DirectVMUsource.zip Source Code]&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=File:Dead_or_alive2.gif&amp;diff=3127</id>
		<title>File:Dead or alive2.gif</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=File:Dead_or_alive2.gif&amp;diff=3127"/>
		<updated>2023-06-23T18:28:09Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Fancy Effects from Dead or Alive 2&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Development&amp;diff=3053</id>
		<title>Development</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Development&amp;diff=3053"/>
		<updated>2023-05-26T20:13:13Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Getting started ===&lt;br /&gt;
* [[Getting Started with Dreamcast development]] -- start here!&lt;br /&gt;
====Ready-to-use environments====&lt;br /&gt;
* [[Docker images]]&lt;br /&gt;
* [[DreamSDK]] (Windows only)&lt;br /&gt;
====[[Building the required toolchains for Sega Dreamcast development]]====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====[[KallistiOS]]====&lt;br /&gt;
* [[Building KOS on Linux mint (or Ubuntu)]]&lt;br /&gt;
* [[Building KOS under Windows Subsystem for Linux (Windows 10 only)]]&lt;br /&gt;
* [[Building KOS on macOS]]&lt;br /&gt;
* [[Building KOS on Cygwin]]&lt;br /&gt;
* [[Building KOS on MinGW/MSYS]]&lt;br /&gt;
* [[Building KOS on MinGW-w64/MSYS2]]&lt;br /&gt;
* [https://kos-docs.dreamcast.wiki/ KallistiOS Doxygen documentation]&lt;br /&gt;
&lt;br /&gt;
====Other====&lt;br /&gt;
* [[Using Ruby for Sega Dreamcast development]] (experimental)&lt;br /&gt;
&lt;br /&gt;
=== Build &amp;amp; test ===&lt;br /&gt;
* [[Building your project]]&lt;br /&gt;
* [[Emulators]]&lt;br /&gt;
* [[Broadband adapter]] / [[LAN adapter]]&lt;br /&gt;
** [[Using dcload-ip with Linux]]&lt;br /&gt;
** [[Using dcload-ip with Windows Subsystem for Linux|Using dcload-ip with Windows 10]] (via Windows Subsystem for Linux)&lt;br /&gt;
* [[Coder&#039;s cable]]&lt;br /&gt;
&lt;br /&gt;
=== Environments and IDEs ===&lt;br /&gt;
* [[Qt Creator Dreamcast Development Environment]]&lt;br /&gt;
* [[CLion Debugging]]&lt;br /&gt;
* [[Visual Studio Code Debugging]]&lt;br /&gt;
&lt;br /&gt;
=== Tools &amp;amp; utilities ===&lt;br /&gt;
* [[Debugging throught GNU Debugger (GDB) and dcload/dc-tool]]&lt;br /&gt;
* [[Using dcprof]]&lt;br /&gt;
&lt;br /&gt;
=== Releasing your project ===&lt;br /&gt;
* Plain files&lt;br /&gt;
* Disc image&lt;br /&gt;
* Selfboot Inducer package&lt;br /&gt;
&lt;br /&gt;
=== Engines ===&lt;br /&gt;
* [[Simulant]]&lt;br /&gt;
** [[Windows WSL2 Setup]]&lt;br /&gt;
** [[Generate profiling data]]&lt;br /&gt;
&lt;br /&gt;
=== General ===&lt;br /&gt;
* [[Filesystem]]&lt;br /&gt;
* [[Romdisk Swapping]]&lt;br /&gt;
* [https://mc.pp.se/dc/hw.html Marcus Comstedt&#039;s Dreamcast Hardware Reference]&lt;br /&gt;
&lt;br /&gt;
=== Graphics ===&lt;br /&gt;
* [[Texture Formats]]&lt;br /&gt;
* [[Graphics APIs]]&lt;br /&gt;
* [[Paletted Textures]]&lt;br /&gt;
* [[2D Rendering Without PVR]]&lt;br /&gt;
* [[Twiddling]]&lt;br /&gt;
&lt;br /&gt;
* PVR&lt;br /&gt;
** [[PowerVR Introduction]]&lt;br /&gt;
** [[PVR Spritesheets]]&lt;br /&gt;
* [[GLdc]]&lt;br /&gt;
** [[Drawing 2D sprites using GLdc]]&lt;br /&gt;
** [[Drawing 3D shapes using GLdc]]&lt;br /&gt;
** [https://hkowsoftware.com/articles/gldc-vertex-formats-from-vec3f-to-fastpath-to-map_buffer/ GLdc Vertex Formats: From vec3f to fastpath to map_buffer]&lt;br /&gt;
* Others&lt;br /&gt;
** [http://www.numechanix.com/blog/index.php/2015/10/03/20/ Procedural texture]&lt;br /&gt;
** [[Notes on fillrate and drawing large textures]]&lt;br /&gt;
** [[KMG Textures]]&lt;br /&gt;
** [[Loading PNG images as OpenGL textures]]&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
* [[Playing SFX]]&lt;br /&gt;
* [[Streaming audio]]&lt;br /&gt;
&lt;br /&gt;
=== Maple ===&lt;br /&gt;
* Controller input&lt;br /&gt;
&lt;br /&gt;
=== VMU ===&lt;br /&gt;
* [[File Types]]&lt;br /&gt;
* [[Save/Load file]]&lt;br /&gt;
* [[Show icon]]&lt;br /&gt;
* [[Play tone]]&lt;br /&gt;
* [[VMU_development|Game Development]]&lt;br /&gt;
&lt;br /&gt;
=== Optimization ===&lt;br /&gt;
* [[GCC-SH4 tips]]&lt;br /&gt;
* [[SH4 in Compiler Explorer]]&lt;br /&gt;
* [[Fast SH4 Vertex Processing]]&lt;br /&gt;
* [[Useful programming tips]]&lt;br /&gt;
* [[Efficient usage of the Dreamcast RAM]]&lt;br /&gt;
* Registers&lt;br /&gt;
* DMA&lt;br /&gt;
* TA&lt;br /&gt;
* PVR&lt;br /&gt;
=== Website Development ===&lt;br /&gt;
*[[Development Resources]]&lt;br /&gt;
&lt;br /&gt;
=== Random Snippets ===&lt;br /&gt;
* [[Objdump]]&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Development&amp;diff=3052</id>
		<title>Development</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Development&amp;diff=3052"/>
		<updated>2023-05-26T20:12:09Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Getting started ===&lt;br /&gt;
* [[Getting Started with Dreamcast development]] -- start here!&lt;br /&gt;
====Ready-to-use environments====&lt;br /&gt;
* [[Docker images]]&lt;br /&gt;
* [[DreamSDK]] (Windows only)&lt;br /&gt;
====[[Building the required toolchains for Sega Dreamcast development]]====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====[[KallistiOS]]====&lt;br /&gt;
* [[Building KOS on Linux mint (or Ubuntu)]]&lt;br /&gt;
* [[Building KOS under Windows Subsystem for Linux (Windows 10 only)]]&lt;br /&gt;
* [[Building KOS on macOS]]&lt;br /&gt;
* [[Building KOS on Cygwin]]&lt;br /&gt;
* [[Building KOS on MinGW/MSYS]]&lt;br /&gt;
* [[Building KOS on MinGW-w64/MSYS2]]&lt;br /&gt;
* [https://kos-docs.dreamcast.wiki/ KallistiOS Doxygen documentation]&lt;br /&gt;
&lt;br /&gt;
====Other====&lt;br /&gt;
* [[Using Ruby for Sega Dreamcast development]] (experimental)&lt;br /&gt;
&lt;br /&gt;
=== Build &amp;amp; test ===&lt;br /&gt;
* [[Building your project]]&lt;br /&gt;
* [[Emulators]]&lt;br /&gt;
* [[Broadband adapter]] / [[LAN adapter]]&lt;br /&gt;
** [[Using dcload-ip with Linux]]&lt;br /&gt;
** [[Using dcload-ip with Windows Subsystem for Linux|Using dcload-ip with Windows 10]] (via Windows Subsystem for Linux)&lt;br /&gt;
* [[Coder&#039;s cable]]&lt;br /&gt;
&lt;br /&gt;
=== Environments and IDEs ===&lt;br /&gt;
* [[Qt Creator Dreamcast Development Environment]]&lt;br /&gt;
&lt;br /&gt;
=== Debugging &amp;amp; profiling ===&lt;br /&gt;
* [[Debugging throught GNU Debugger (GDB) and dcload/dc-tool]]&lt;br /&gt;
* [[Using dcprof]]&lt;br /&gt;
* [[CLion Debugging]]&lt;br /&gt;
* [[Visual Studio Code Debugging]]&lt;br /&gt;
&lt;br /&gt;
=== Releasing your project ===&lt;br /&gt;
* Plain files&lt;br /&gt;
* Disc image&lt;br /&gt;
* Selfboot Inducer package&lt;br /&gt;
&lt;br /&gt;
=== Engines ===&lt;br /&gt;
* [[Simulant]]&lt;br /&gt;
** [[Windows WSL2 Setup]]&lt;br /&gt;
** [[Generate profiling data]]&lt;br /&gt;
&lt;br /&gt;
=== General ===&lt;br /&gt;
* [[Filesystem]]&lt;br /&gt;
* [[Romdisk Swapping]]&lt;br /&gt;
* [https://mc.pp.se/dc/hw.html Marcus Comstedt&#039;s Dreamcast Hardware Reference]&lt;br /&gt;
&lt;br /&gt;
=== Graphics ===&lt;br /&gt;
* [[Texture Formats]]&lt;br /&gt;
* [[Graphics APIs]]&lt;br /&gt;
* [[Paletted Textures]]&lt;br /&gt;
* [[2D Rendering Without PVR]]&lt;br /&gt;
* [[Twiddling]]&lt;br /&gt;
&lt;br /&gt;
* PVR&lt;br /&gt;
** [[PowerVR Introduction]]&lt;br /&gt;
** [[PVR Spritesheets]]&lt;br /&gt;
* [[GLdc]]&lt;br /&gt;
** [[Drawing 2D sprites using GLdc]]&lt;br /&gt;
** [[Drawing 3D shapes using GLdc]]&lt;br /&gt;
** [https://hkowsoftware.com/articles/gldc-vertex-formats-from-vec3f-to-fastpath-to-map_buffer/ GLdc Vertex Formats: From vec3f to fastpath to map_buffer]&lt;br /&gt;
* Others&lt;br /&gt;
** [http://www.numechanix.com/blog/index.php/2015/10/03/20/ Procedural texture]&lt;br /&gt;
** [[Notes on fillrate and drawing large textures]]&lt;br /&gt;
** [[KMG Textures]]&lt;br /&gt;
** [[Loading PNG images as OpenGL textures]]&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
* [[Playing SFX]]&lt;br /&gt;
* [[Streaming audio]]&lt;br /&gt;
&lt;br /&gt;
=== Maple ===&lt;br /&gt;
* Controller input&lt;br /&gt;
&lt;br /&gt;
=== VMU ===&lt;br /&gt;
* [[File Types]]&lt;br /&gt;
* [[Save/Load file]]&lt;br /&gt;
* [[Show icon]]&lt;br /&gt;
* [[Play tone]]&lt;br /&gt;
* [[VMU_development|Game Development]]&lt;br /&gt;
&lt;br /&gt;
=== Optimization ===&lt;br /&gt;
* [[GCC-SH4 tips]]&lt;br /&gt;
* [[SH4 in Compiler Explorer]]&lt;br /&gt;
* [[Fast SH4 Vertex Processing]]&lt;br /&gt;
* [[Useful programming tips]]&lt;br /&gt;
* [[Efficient usage of the Dreamcast RAM]]&lt;br /&gt;
* Registers&lt;br /&gt;
* DMA&lt;br /&gt;
* TA&lt;br /&gt;
* PVR&lt;br /&gt;
=== Website Development ===&lt;br /&gt;
*[[Development Resources]]&lt;br /&gt;
&lt;br /&gt;
=== Random Snippets ===&lt;br /&gt;
* [[Objdump]]&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=User:GyroVorbis&amp;diff=3043</id>
		<title>User:GyroVorbis</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=User:GyroVorbis&amp;diff=3043"/>
		<updated>2023-05-26T01:30:53Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;My name is Falco Girgis.&lt;br /&gt;
&lt;br /&gt;
I am the infamous lead developer of Elysian Shadows, ESTk, and ElysianVMU. I am widely hated for being late on Kickstarter, but THE PROJECT IS MY LIFE, AND I&#039;M WORKING ON IT and fully intend to make it up to all of you. :)&lt;br /&gt;
&lt;br /&gt;
I&#039;ve recently begun to atone for my sins by giving back to the Dreamcast community as a KOS developer and writing content here for this wiki. Feel free to come hang out with me on Discord or follow me on Twitter or something. I&#039;m happy to help!&lt;br /&gt;
&lt;br /&gt;
* GitHub: https://github.com/gyrovorbis&lt;br /&gt;
* Discord: https://discord.gg/SX2txgr&lt;br /&gt;
* Twitter: https://twitter.com/falco_girgis&lt;br /&gt;
* LinkedIn: https://www.linkedin.com/feed/&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=User:GyroVorbis&amp;diff=3042</id>
		<title>User:GyroVorbis</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=User:GyroVorbis&amp;diff=3042"/>
		<updated>2023-05-26T01:29:19Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;My name is Falco Girgis.&lt;br /&gt;
&lt;br /&gt;
I am the infamous lead developer of Elysian Shadows, ESTk, and ElysianVMU. I am widely hated for being late on Kickstarter, but THE PROJECT IS MY LIFE, AND I&#039;M WORKING ON IT and fully intend to make it up to all of you. :)&lt;br /&gt;
&lt;br /&gt;
I&#039;ve recently begun to atone for my sins by giving back to the Dreamcast community as a KOS developer and writing content here for this wiki. &lt;br /&gt;
&lt;br /&gt;
* GitHub: https://github.com/gyrovorbis&lt;br /&gt;
* Twitter: https://twitter.com/falco_girgis&lt;br /&gt;
* Discord: https://discord.gg/SX2txgr&lt;br /&gt;
* LinkedIn: https://www.linkedin.com/feed/&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=User:GyroVorbis&amp;diff=3041</id>
		<title>User:GyroVorbis</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=User:GyroVorbis&amp;diff=3041"/>
		<updated>2023-05-26T01:28:11Z</updated>

		<summary type="html">&lt;p&gt;GyroVorbis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Infamous lead developer of Elysian Shadows, ESTk, and ElysianVMU, widely hated for being late on Kickstarter, but THE PROJECT IS HIS LIFE, AND HE&#039;S WORKING ON IT and fully intends to make it up to all of you. :)&lt;br /&gt;
&lt;br /&gt;
I&#039;ve recently begun to atone for my sins by giving back to the Dreamcast community as a KOS developer and writing content here for this wiki. &lt;br /&gt;
&lt;br /&gt;
GitHub: https://github.com/gyrovorbis&lt;br /&gt;
Twitter: https://twitter.com/falco_girgis&lt;br /&gt;
Discord: https://discord.gg/SX2txgr&lt;br /&gt;
LinkedIn: https://www.linkedin.com/feed/&lt;/div&gt;</summary>
		<author><name>GyroVorbis</name></author>
	</entry>
</feed>