<?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=BBHoodsta</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=BBHoodsta"/>
	<link rel="alternate" type="text/html" href="https://dreamcast.wiki/Special:Contributions/BBHoodsta"/>
	<updated>2026-04-15T01:18:03Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.3</generator>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_FIPR_Optimizations&amp;diff=3853</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=3853"/>
		<updated>2026-02-16T18:42:47Z</updated>

		<summary type="html">&lt;p&gt;BBHoodsta: &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;
    const float *td = d;&lt;br /&gt;
    const float *tv1 = v1;&lt;br /&gt;
    const float *tv2 = v2;&lt;br /&gt;
    uint32_t stride;&lt;br /&gt;
    float result;&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;
        ! s = 512 (stride: 128 floats * 4 bytes)&lt;br /&gt;
        mov     #2, %[s]&lt;br /&gt;
        shll8   %[s]               ! 2 &amp;lt;&amp;lt; 8 = 512&lt;br /&gt;
&lt;br /&gt;
        ! Load first vector into fv0 for first FIPR.&lt;br /&gt;
        fmov.s  @%[td]+, fr0       ! fr0 = d[0]&lt;br /&gt;
        fmov.s  @%[td]+, fr1       ! fr1 = d[1]&lt;br /&gt;
        fmov.s  @%[td]+, fr2       ! fr2 = d[2]&lt;br /&gt;
        fmov.s  @%[td]+, fr3       ! fr3 = d[3]&lt;br /&gt;
&lt;br /&gt;
        ! Load second vector into fv4 for first FIPR&lt;br /&gt;
        fmov.s  @%[tv1], fr4       ! fr4 = v1[0]&lt;br /&gt;
        add     %[s], %[tv1]       ! tv1 -&amp;gt; v1[128]&lt;br /&gt;
        fmov.s  @%[tv2], fr5       ! fr5 = v2[0]&lt;br /&gt;
        add     %[s], %[tv2]       ! tv2 -&amp;gt; v2[128]&lt;br /&gt;
        fmov.s  @%[tv1], fr6       ! fr6 = v1[128]&lt;br /&gt;
        add     %[s], %[tv1]       ! tv1 -&amp;gt; v1[256]&lt;br /&gt;
        fmov.s  @%[tv2], fr7       ! fr7 = v2[128]&lt;br /&gt;
        add     %[s], %[tv2]       ! tv2 -&amp;gt; v2[256]&lt;br /&gt;
&lt;br /&gt;
        ! Issue first FIPR&lt;br /&gt;
        fipr    fv0, fv4           ! fr7 = FIPR1 result&lt;br /&gt;
&lt;br /&gt;
        ! Load first vector into fv8 for second FIPR.&lt;br /&gt;
        fmov.s  @%[td]+, fr8       ! fr8  = d[4]&lt;br /&gt;
        fmov.s  @%[td]+, fr9       ! fr9  = d[5]&lt;br /&gt;
        fmov.s  @%[td]+, fr10      ! fr10 = d[6]&lt;br /&gt;
        fmov.s  @%[td]+, fr11      ! fr11 = d[7]&lt;br /&gt;
&lt;br /&gt;
        ! Load second vector into fv12 for second FIPR.&lt;br /&gt;
        fmov.s  @%[tv1], fr12      ! fr12 = v1[256]&lt;br /&gt;
        add     %[s], %[tv1]       ! tv1 -&amp;gt; v1[384]&lt;br /&gt;
        fmov.s  @%[tv2], fr13      ! fr13 = v2[256]&lt;br /&gt;
        add     %[s], %[tv2]       ! tv2 -&amp;gt; v2[384]&lt;br /&gt;
        fmov.s  @%[tv1], fr14      ! fr14 = v1[384]&lt;br /&gt;
        add     %[s], %[tv1]       ! tv1 -&amp;gt; v1[512]&lt;br /&gt;
        fmov.s  @%[tv2], fr15      ! fr15 = v2[384]&lt;br /&gt;
        add     %[s], %[tv2]       ! tv2 -&amp;gt; v2[512]&lt;br /&gt;
&lt;br /&gt;
        ! Issue second FIPR&lt;br /&gt;
        fipr    fv8, fv12          ! fr15 = FIPR2 result&lt;br /&gt;
        fmov.s  fr7, @-r15         ! push FIPR1 result onto stack&lt;br /&gt;
&lt;br /&gt;
        ! Load first vector into fv0 for third FIPR&lt;br /&gt;
        fmov.s  @%[td]+, fr0       ! fr0 = d[8]&lt;br /&gt;
        fmov.s  @%[td]+, fr1       ! fr1 = d[9]&lt;br /&gt;
        fmov.s  @%[td]+, fr2       ! fr2 = d[10]&lt;br /&gt;
        fmov.s  @%[td]+, fr3       ! fr3 = d[11]&lt;br /&gt;
&lt;br /&gt;
        ! Load second vector into fv4 for third FIPR&lt;br /&gt;
        fmov.s  @%[tv1], fr4       ! fr4 = v1[512]&lt;br /&gt;
        add     %[s], %[tv1]       ! tv1 -&amp;gt; v1[640]&lt;br /&gt;
        fmov.s  @%[tv2], fr5       ! fr5 = v2[512]&lt;br /&gt;
        add     %[s], %[tv2]       ! tv2 -&amp;gt; v2[640]&lt;br /&gt;
        fmov.s  @%[tv1], fr6       ! fr6 = v1[640]&lt;br /&gt;
        add     %[s], %[tv1]       ! tv1 -&amp;gt; v1[768]&lt;br /&gt;
        fmov.s  @%[tv2], fr7       ! fr7 = v2[640]&lt;br /&gt;
        add     %[s], %[tv2]       ! tv2 -&amp;gt; v2[768]&lt;br /&gt;
&lt;br /&gt;
        ! Issue third FIPR&lt;br /&gt;
        fipr    fv0, fv4           ! fr7 = FIPR3 result&lt;br /&gt;
        fmov.s  fr15, @-r15        ! push FIPR2 result onto stack&lt;br /&gt;
&lt;br /&gt;
        ! Load first vector into fv8 for fourth FIPR&lt;br /&gt;
        fmov.s  @%[td]+, fr8       ! fr8  = d[12]&lt;br /&gt;
        fmov.s  @%[td]+, fr9       ! fr9  = d[13]&lt;br /&gt;
        fmov.s  @%[td]+, fr10      ! fr10 = d[14]&lt;br /&gt;
        fmov.s  @%[td]+, fr11      ! fr11 = d[15]&lt;br /&gt;
&lt;br /&gt;
        ! Load second vector into fv12 for fourth FIPR&lt;br /&gt;
        fmov.s  @%[tv1], fr12      ! fr12 = v1[768]&lt;br /&gt;
        add     %[s], %[tv1]       ! tv1 -&amp;gt; v1[896]&lt;br /&gt;
        fmov.s  @%[tv2], fr13      ! fr13 = v2[768]&lt;br /&gt;
        add     %[s], %[tv2]       ! tv2 -&amp;gt; v2[896]&lt;br /&gt;
        fmov.s  @%[tv1], fr14      ! fr14 = v1[896]&lt;br /&gt;
        fmov.s  @%[tv2], fr15      ! fr15 = v2[896]&lt;br /&gt;
&lt;br /&gt;
        ! Issue fourth FIPR&lt;br /&gt;
        fipr    fv8, fv12          ! fr15 = FIPR4 result&lt;br /&gt;
&lt;br /&gt;
        ! Add up results from previous FIPRs while we wait&lt;br /&gt;
        fmov.s  @r15+, fr0         ! pop FIPR2 result&lt;br /&gt;
        fmov.s  @r15+, fr1         ! pop FIPR1 result&lt;br /&gt;
        fadd    fr1, fr0           ! fr0 = FIPR1 + FIPR2&lt;br /&gt;
        fadd    fr7, fr0           ! fr0 += FIPR3&lt;br /&gt;
&lt;br /&gt;
        ! Add result from fourth FIPR now that it&#039;s ready&lt;br /&gt;
        fadd    fr15, fr0          ! fr0 += FIPR4&lt;br /&gt;
&lt;br /&gt;
        ! Transfer result to primary bank via FPUL&lt;br /&gt;
        flds    fr0, FPUL          ! secondary fr0 -&amp;gt; FPUL&lt;br /&gt;
        frchg                      ! Switch back to primary FP bank&lt;br /&gt;
        fsts    FPUL, %[result]    ! FPUL -&amp;gt; result register (primary bank)&lt;br /&gt;
    )&amp;quot;&lt;br /&gt;
    : [td] &amp;quot;+r&amp;quot; (td), [tv1] &amp;quot;+r&amp;quot; (tv1), [tv2] &amp;quot;+r&amp;quot; (tv2),&lt;br /&gt;
      [s] &amp;quot;=r&amp;quot; (stride), [result] &amp;quot;=f&amp;quot; (result)&lt;br /&gt;
    :&lt;br /&gt;
    : &amp;quot;memory&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    return result;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>BBHoodsta</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=SH4_FIPR_Optimizations&amp;diff=3852</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=3852"/>
		<updated>2026-02-16T18:40:26Z</updated>

		<summary type="html">&lt;p&gt;BBHoodsta: Updated the function because it crashed before&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;
	const float *td = d;&lt;br /&gt;
	const float *tv1 = v1;&lt;br /&gt;
	const float *tv2 = v2;&lt;br /&gt;
	uint32_t stride;&lt;br /&gt;
	float result;&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;
		! s = 512 (stride: 128 floats * 4 bytes)&lt;br /&gt;
		mov     #2, %[s]&lt;br /&gt;
		shll8   %[s]               ! 2 &amp;lt;&amp;lt; 8 = 512&lt;br /&gt;
&lt;br /&gt;
		! Load first vector into fv0 for first FIPR.&lt;br /&gt;
		fmov.s  @%[td]+, fr0       ! fr0 = d[0]&lt;br /&gt;
		fmov.s  @%[td]+, fr1       ! fr1 = d[1]&lt;br /&gt;
		fmov.s  @%[td]+, fr2       ! fr2 = d[2]&lt;br /&gt;
		fmov.s  @%[td]+, fr3       ! fr3 = d[3]&lt;br /&gt;
&lt;br /&gt;
		! Load second vector into fv4 for first FIPR&lt;br /&gt;
		fmov.s  @%[tv1], fr4       ! fr4 = v1[0]&lt;br /&gt;
		add     %[s], %[tv1]       ! tv1 -&amp;gt; v1[128]&lt;br /&gt;
		fmov.s  @%[tv2], fr5       ! fr5 = v2[0]&lt;br /&gt;
		add     %[s], %[tv2]       ! tv2 -&amp;gt; v2[128]&lt;br /&gt;
		fmov.s  @%[tv1], fr6       ! fr6 = v1[128]&lt;br /&gt;
		add     %[s], %[tv1]       ! tv1 -&amp;gt; v1[256]&lt;br /&gt;
		fmov.s  @%[tv2], fr7       ! fr7 = v2[128]&lt;br /&gt;
		add     %[s], %[tv2]       ! tv2 -&amp;gt; v2[256]&lt;br /&gt;
&lt;br /&gt;
		! Issue first FIPR&lt;br /&gt;
		fipr    fv0, fv4           ! fr7 = FIPR1 result&lt;br /&gt;
&lt;br /&gt;
		! Load first vector into fv8 for second FIPR.&lt;br /&gt;
		fmov.s  @%[td]+, fr8       ! fr8  = d[4]&lt;br /&gt;
		fmov.s  @%[td]+, fr9       ! fr9  = d[5]&lt;br /&gt;
		fmov.s  @%[td]+, fr10      ! fr10 = d[6]&lt;br /&gt;
		fmov.s  @%[td]+, fr11      ! fr11 = d[7]&lt;br /&gt;
&lt;br /&gt;
		! Load second vector into fv12 for second FIPR.&lt;br /&gt;
		fmov.s  @%[tv1], fr12      ! fr12 = v1[256]&lt;br /&gt;
		add     %[s], %[tv1]       ! tv1 -&amp;gt; v1[384]&lt;br /&gt;
		fmov.s  @%[tv2], fr13      ! fr13 = v2[256]&lt;br /&gt;
		add     %[s], %[tv2]       ! tv2 -&amp;gt; v2[384]&lt;br /&gt;
		fmov.s  @%[tv1], fr14      ! fr14 = v1[384]&lt;br /&gt;
		add     %[s], %[tv1]       ! tv1 -&amp;gt; v1[512]&lt;br /&gt;
		fmov.s  @%[tv2], fr15      ! fr15 = v2[384]&lt;br /&gt;
		add     %[s], %[tv2]       ! tv2 -&amp;gt; v2[512]&lt;br /&gt;
&lt;br /&gt;
		! Issue second FIPR&lt;br /&gt;
		fipr    fv8, fv12          ! fr15 = FIPR2 result&lt;br /&gt;
		fmov.s  fr7, @-r15         ! push FIPR1 result onto stack&lt;br /&gt;
&lt;br /&gt;
		! Load first vector into fv0 for third FIPR&lt;br /&gt;
		fmov.s  @%[td]+, fr0       ! fr0 = d[8]&lt;br /&gt;
		fmov.s  @%[td]+, fr1       ! fr1 = d[9]&lt;br /&gt;
		fmov.s  @%[td]+, fr2       ! fr2 = d[10]&lt;br /&gt;
		fmov.s  @%[td]+, fr3       ! fr3 = d[11]&lt;br /&gt;
&lt;br /&gt;
		! Load second vector into fv4 for third FIPR&lt;br /&gt;
		fmov.s  @%[tv1], fr4       ! fr4 = v1[512]&lt;br /&gt;
		add     %[s], %[tv1]       ! tv1 -&amp;gt; v1[640]&lt;br /&gt;
		fmov.s  @%[tv2], fr5       ! fr5 = v2[512]&lt;br /&gt;
		add     %[s], %[tv2]       ! tv2 -&amp;gt; v2[640]&lt;br /&gt;
		fmov.s  @%[tv1], fr6       ! fr6 = v1[640]&lt;br /&gt;
		add     %[s], %[tv1]       ! tv1 -&amp;gt; v1[768]&lt;br /&gt;
		fmov.s  @%[tv2], fr7       ! fr7 = v2[640]&lt;br /&gt;
		add     %[s], %[tv2]       ! tv2 -&amp;gt; v2[768]&lt;br /&gt;
&lt;br /&gt;
		! Issue third FIPR&lt;br /&gt;
		fipr    fv0, fv4           ! fr7 = FIPR3 result&lt;br /&gt;
		fmov.s  fr15, @-r15        ! push FIPR2 result onto stack&lt;br /&gt;
&lt;br /&gt;
		! Load first vector into fv8 for fourth FIPR&lt;br /&gt;
		fmov.s  @%[td]+, fr8       ! fr8  = d[12]&lt;br /&gt;
		fmov.s  @%[td]+, fr9       ! fr9  = d[13]&lt;br /&gt;
		fmov.s  @%[td]+, fr10      ! fr10 = d[14]&lt;br /&gt;
		fmov.s  @%[td]+, fr11      ! fr11 = d[15]&lt;br /&gt;
&lt;br /&gt;
		! Load second vector into fv12 for fourth FIPR&lt;br /&gt;
		fmov.s  @%[tv1], fr12      ! fr12 = v1[768]&lt;br /&gt;
		add     %[s], %[tv1]       ! tv1 -&amp;gt; v1[896]&lt;br /&gt;
		fmov.s  @%[tv2], fr13      ! fr13 = v2[768]&lt;br /&gt;
		add     %[s], %[tv2]       ! tv2 -&amp;gt; v2[896]&lt;br /&gt;
		fmov.s  @%[tv1], fr14      ! fr14 = v1[896]&lt;br /&gt;
		fmov.s  @%[tv2], fr15      ! fr15 = v2[896]&lt;br /&gt;
&lt;br /&gt;
		! Issue fourth FIPR&lt;br /&gt;
		fipr    fv8, fv12          ! fr15 = FIPR4 result&lt;br /&gt;
&lt;br /&gt;
		! Add up results from previous FIPRs while we wait&lt;br /&gt;
		fmov.s  @r15+, fr0         ! pop FIPR2 result&lt;br /&gt;
		fmov.s  @r15+, fr1         ! pop FIPR1 result&lt;br /&gt;
		fadd    fr1, fr0           ! fr0 = FIPR1 + FIPR2&lt;br /&gt;
		fadd    fr7, fr0           ! fr0 += FIPR3&lt;br /&gt;
&lt;br /&gt;
		! Add result from fourth FIPR now that it&#039;s ready&lt;br /&gt;
		fadd    fr15, fr0          ! fr0 += FIPR4&lt;br /&gt;
&lt;br /&gt;
		! Transfer result to primary bank via FPUL&lt;br /&gt;
		flds    fr0, FPUL          ! secondary fr0 -&amp;gt; FPUL&lt;br /&gt;
		frchg                      ! Switch back to primary FP bank&lt;br /&gt;
		fsts    FPUL, %[result]    ! FPUL -&amp;gt; result register (primary bank)&lt;br /&gt;
	)&amp;quot;&lt;br /&gt;
	: [td] &amp;quot;+r&amp;quot; (td), [tv1] &amp;quot;+r&amp;quot; (tv1), [tv2] &amp;quot;+r&amp;quot; (tv2),&lt;br /&gt;
	  [s] &amp;quot;=r&amp;quot; (stride), [result] &amp;quot;=f&amp;quot; (result)&lt;br /&gt;
	:&lt;br /&gt;
	: &amp;quot;memory&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	return result;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>BBHoodsta</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Twiddling&amp;diff=3594</id>
		<title>Twiddling</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Twiddling&amp;diff=3594"/>
		<updated>2024-08-19T21:57:12Z</updated>

		<summary type="html">&lt;p&gt;BBHoodsta: /* How and why the Dreamcast uses Twiddling */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General Idea ==&lt;br /&gt;
&lt;br /&gt;
Twiddling, sometimes referred to as Swizzling in Playstation communities, and better known as Morton Encoding or a [https://en.wikipedia.org/wiki/Z-order_curve#l134 Z/N-Ordered curve], is a method of data organization that retains [https://en.wikipedia.org/wiki/Locality_of_reference#L146 Locality of Reference], which means that elements that reside physically close together in space, will be grouped together in memory. In the context of texture organization, this means that twiddling an image will make adjacent pixels to the right and below any given pixel reside close together in memory. This yields numerous benefits, such as easier calculation for AA and a texel configuration necessary for [https://en.wikipedia.org/wiki/Vector_quantization#L135 Vector Quantization] compression. &lt;br /&gt;
&lt;br /&gt;
== Origins and Classical Implementation ==&lt;br /&gt;
&lt;br /&gt;
The term &amp;quot;Twiddling&amp;quot; comes from the hacker term &amp;quot;bit-twiddling&amp;quot; owing to the classical way to calculate a Z-Ordered curve by manipulating the bits that make up the data (texel) index. The bit-twiddling way to arrive at a morton code is to take the binary representation of the X and Y coordinates of a texel and interleave them into one bitstring. The resultant bitstring will be twice the size of each individual input bitstring. For example, say you have a 4-bit number representing the X position of a Texel in a texture (e.g. XXXX) and you had a 4-bit number representing the Y position of a Texel (eg. YYYY), then your Z-Order position would be XYXY-XYXY (8-bit). This number is the index of where this texel lies in a new array that constitutes all the twiddled texels in the texture. If you convert every texel in the source texture into this new twiddled texture array, then iterating through the index will be the equivalent of navigating the source texture in a Z-pattern.&lt;br /&gt;
&lt;br /&gt;
Whether one is a Z-ordered curve or an N-ordered curve depends on whether you shift the X or Y bitstring, effectively making the traversal width by height (Z) or height by width (N). Technically, the dreamcast uses an N-ordered curve.&lt;br /&gt;
&lt;br /&gt;
A problem with using Z-ordered curves is that it&#039;s expensive to compute every frame because it uses division and multiplication heavily. Thus there exists numerous bit-twiddling hacks to speed up this operation, covered below.&lt;br /&gt;
&lt;br /&gt;
== Conceptualizing Twiddling ==&lt;br /&gt;
&lt;br /&gt;
Lets start with a recap of what Twiddled textures even are. Twiddled textures is just a particular way of re-organising pixels in an image so they&#039;re quicker to render.&lt;br /&gt;
&lt;br /&gt;
[[File:Twiddle.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
The example image where the numbers represent the original un-twiddled indexes and the &amp;quot;inverted Ns&amp;quot; show the original flow of indexes. Indexes from the original image were calculated from left to right, top to bottom (Scanline order). So we can see after index 0, number 1 is just below, 2 is to the right of 0 and 3 is just below 2. Then if we go to the next biggest inverted N we can see the order &#039;&#039;&#039;{0,1,2,3}, {4,5,6,7}, {8,9,10,11}, {12,13,14,15}&#039;&#039;&#039; following the same inverted N pattern.&lt;br /&gt;
&lt;br /&gt;
So if we are given index &#039;&#039;&#039;i&#039;&#039;&#039; from an untwiddled image and wished to find the twiddled index, then its a process of recursively narrowing down what part of the twiddled image that pixel now lives in.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
 Original:        Twiddled:&lt;br /&gt;
 &lt;br /&gt;
 0 1 2 3          0 2 8 A&lt;br /&gt;
 4 5 6 7          1 3 9 B&lt;br /&gt;
 8 9 A B          4 6 C E&lt;br /&gt;
 C D E F          5 7 D F&lt;br /&gt;
 G H I J          G I O Q&lt;br /&gt;
 K L M N          H J P R&lt;br /&gt;
 O P Q R          K M S U&lt;br /&gt;
 S T U V          L N T V&lt;br /&gt;
 W X Y Z          W Y % &amp;amp;&lt;br /&gt;
 ~ ! # $          X Z ^ *&lt;br /&gt;
 % ^ &amp;amp; *          ~ # ( _&lt;br /&gt;
 ( ) _ +          ! $ ) +&lt;br /&gt;
&lt;br /&gt;
== Look-up Table Hack ==&lt;br /&gt;
Taken from [https://graphics.stanford.edu/~seander/bithacks.html#InterleaveTableLookup#Stanford Stanford Bit-twiddling hacks page].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;static const unsigned short MortonTable256[256] = &lt;br /&gt;
{&lt;br /&gt;
  0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, &lt;br /&gt;
  0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, &lt;br /&gt;
  0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, &lt;br /&gt;
  0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, &lt;br /&gt;
  0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, &lt;br /&gt;
  0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, &lt;br /&gt;
  0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, &lt;br /&gt;
  0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, &lt;br /&gt;
  0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, &lt;br /&gt;
  0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, &lt;br /&gt;
  0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, &lt;br /&gt;
  0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, &lt;br /&gt;
  0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, &lt;br /&gt;
  0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, &lt;br /&gt;
  0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, &lt;br /&gt;
  0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, &lt;br /&gt;
  0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, &lt;br /&gt;
  0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, &lt;br /&gt;
  0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, &lt;br /&gt;
  0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, &lt;br /&gt;
  0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, &lt;br /&gt;
  0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, &lt;br /&gt;
  0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, &lt;br /&gt;
  0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, &lt;br /&gt;
  0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, &lt;br /&gt;
  0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, &lt;br /&gt;
  0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, &lt;br /&gt;
  0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, &lt;br /&gt;
  0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, &lt;br /&gt;
  0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, &lt;br /&gt;
  0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, &lt;br /&gt;
  0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
unsigned short x; // Interleave bits of x and y, so that all of the&lt;br /&gt;
unsigned short y; // bits of x are in the even positions and y in the odd;&lt;br /&gt;
unsigned int z;   // z gets the resulting 32-bit Morton Number.&lt;br /&gt;
&lt;br /&gt;
z = MortonTable256[y &amp;gt;&amp;gt; 8]   &amp;lt;&amp;lt; 17 | &lt;br /&gt;
    MortonTable256[x &amp;gt;&amp;gt; 8]   &amp;lt;&amp;lt; 16 |&lt;br /&gt;
    MortonTable256[y &amp;amp; 0xFF] &amp;lt;&amp;lt;  1 | &lt;br /&gt;
    MortonTable256[x &amp;amp; 0xFF];&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more speed, use an additional table with values that are MortonTable256 pre-shifted one bit to the left. This second table could then be used for the y lookups, thus reducing the operations by two, but almost doubling the memory required. Extending this same idea, four tables could be used, with two of them pre-shifted by 16 to the left of the previous two, so that we would only need 11 operations total.&lt;br /&gt;
&lt;br /&gt;
== Binary Magic Numbers Hack ==&lt;br /&gt;
Taken from [https://graphics.stanford.edu/~seander/bithacks.html#InterleaveTableLookup#Stanford Stanford Bit-twiddling hacks page].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;static const unsigned int B[] = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF};&lt;br /&gt;
static const unsigned int S[] = {1, 2, 4, 8};&lt;br /&gt;
&lt;br /&gt;
unsigned int x; // Interleave lower 16 bits of x and y, so the bits of x&lt;br /&gt;
unsigned int y; // are in the even positions and bits from y in the odd;&lt;br /&gt;
unsigned int z; // z gets the resulting 32-bit Morton Number. x and y must initially be less than 65536.&lt;br /&gt;
&lt;br /&gt;
x = (x | (x &amp;lt;&amp;lt; S[3])) &amp;amp; B[3];&lt;br /&gt;
x = (x | (x &amp;lt;&amp;lt; S[2])) &amp;amp; B[2];&lt;br /&gt;
x = (x | (x &amp;lt;&amp;lt; S[1])) &amp;amp; B[1];&lt;br /&gt;
x = (x | (x &amp;lt;&amp;lt; S[0])) &amp;amp; B[0];&lt;br /&gt;
y = (y | (y &amp;lt;&amp;lt; S[3])) &amp;amp; B[3];&lt;br /&gt;
y = (y | (y &amp;lt;&amp;lt; S[2])) &amp;amp; B[2];&lt;br /&gt;
y = (y | (y &amp;lt;&amp;lt; S[1])) &amp;amp; B[1];&lt;br /&gt;
y = (y | (y &amp;lt;&amp;lt; S[0])) &amp;amp; B[0];&lt;br /&gt;
z = x | (y &amp;lt;&amp;lt; 1);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Non-Dreamcast Bit-twiddling Hacks ==&lt;br /&gt;
On modern x86_64 processors from Intel actually have instructions built in to handle z-ordered curves. These are the Parallel Bit Deposit (PDEP) and Parallel bit Extraction (PEXT) instructions, which can be used in conjunction to interleave a bitstring. As the Dreamcast lacks these instructions, this is not a viable dreamcast solution.&lt;br /&gt;
&lt;br /&gt;
Another method for twiddling comes from multiplication without carry. A number multiplied upon itself using a carry-less multiplication will yield the original bitstring of the number interleaved with 0s. For example, given that the number 255 is 1111-1111 in binary, 255 multiplied-without-carry by 255 reveals a 16-bit number that is (1010-1010 1010-1010). Thus, if you use multiply without carry on the X and Y position of the texel in the texture, you&#039;ll arrive at two 16-bit numbers, e.g. X0X0-X0X0 X0X0-X0X0 and Y0Y0-Y0Y0 Y0Y0-Y0Y0. If you bitshift the X value to the right by 1, and then OR the X bitstring by the Y bitstring, the resultant 16-bit bitstring will be twiddled.&lt;br /&gt;
&lt;br /&gt;
The Dreamcast&#039;s SH4 CPU lacks a multiply-without-carry instruction, although you could create one that uses only addition like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;int multiplyWithoutCarry(int a, int b) {&lt;br /&gt;
    int result = 0;&lt;br /&gt;
    int multiplier = 1;&lt;br /&gt;
&lt;br /&gt;
    while (b != 0) {&lt;br /&gt;
        int digit = b;&lt;br /&gt;
        int temp = a;&lt;br /&gt;
&lt;br /&gt;
        while (digit &amp;gt; 9) {&lt;br /&gt;
            digit -= 10;&lt;br /&gt;
            temp += a;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        while (digit &amp;gt; 0) {&lt;br /&gt;
            result += temp;&lt;br /&gt;
            digit--;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        int divisor = 10;&lt;br /&gt;
        int tempMultiplier = multiplier;&lt;br /&gt;
&lt;br /&gt;
        while (divisor &amp;gt; 1) {&lt;br /&gt;
            if (divisor &amp;lt;= tempMultiplier) {&lt;br /&gt;
                tempMultiplier -= divisor;&lt;br /&gt;
                divisor = divisor &amp;lt;&amp;lt; 1;&lt;br /&gt;
                multiplier = multiplier &amp;lt;&amp;lt; 1;&lt;br /&gt;
            }&lt;br /&gt;
            else {&lt;br /&gt;
                divisor = divisor &amp;gt;&amp;gt; 1;&lt;br /&gt;
                tempMultiplier = tempMultiplier &amp;gt;&amp;gt; 1;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        b -= tempMultiplier;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return result;&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protofall&#039;s Implementation ==&lt;br /&gt;
&lt;br /&gt;
How to generated the twiddled index from an untwiddled texture:&lt;br /&gt;
&lt;br /&gt;
 Original:        Twiddled:&lt;br /&gt;
 &lt;br /&gt;
 0 1 2 3          0 2 8 A&lt;br /&gt;
 4 5 6 7          1 3 9 B&lt;br /&gt;
 8 9 A B          4 6 C E&lt;br /&gt;
 C D E F          5 7 D F&lt;br /&gt;
 G H I J          G I O Q&lt;br /&gt;
 K L M N          H J P R&lt;br /&gt;
 O P Q R          K M S U&lt;br /&gt;
 S T U V          L N T V&lt;br /&gt;
 W X Y Z          W Y % &amp;amp;&lt;br /&gt;
 ~ ! # $          X Z ^ *&lt;br /&gt;
 % ^ &amp;amp; *          ~ # ( _&lt;br /&gt;
 ( ) _ +          ! $ ) +&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The matching characters between the two images represent the same pixel, just relocated. These images would be 4 * 12 pixel images, but the steps work for any valid &#039;&#039;&#039;2^x * 2^&#039;&#039;&#039;y sizes, where x and y are whole numbers.&lt;br /&gt;
&lt;br /&gt;
Now lets say we want to find the twiddled index of the untwiddled &#039;&#039;&#039;&amp;quot;O&amp;quot;&#039;&#039;&#039; pixel (index 24). By hand we can work it out and tell the twiddle index should be &amp;quot;18&amp;quot;, but what algorithm/logic can we use to find this automatically for any &#039;&#039;&#039;i&#039;&#039;&#039;?&lt;br /&gt;
&lt;br /&gt;
Here are my steps:&lt;br /&gt;
* We first need to start by figuring out the &amp;quot;Biggest-Order Inverted-N&amp;quot; (&#039;&#039;&#039;BOIN&#039;&#039;&#039;) that fits in this image.&lt;br /&gt;
* Now if our starting image was a square, then the BOIN is the same size as the image&lt;br /&gt;
* For rectangles like this, we have to find the smallest side first (width) then our BOIN is width * width&lt;br /&gt;
* If we start off with a rectangle, then we need to do an extra step that squares can skip.&lt;br /&gt;
* Notice how we can completely encapsulate the whole image with &#039;&#039;&#039;(bigger_side / smaller_side) == 3&#039;&#039;&#039; BOINs? Our first step is to determine which of these BOINs our index &#039;&#039;&#039;i&#039;&#039;&#039; belongs in.&lt;br /&gt;
* We can take advantage of a quirk I mentioned earlier. Notice how the first BOIN contains the first 1/3 of the original pixels, the 2nd BOIN contains the next 1/3 and the 3rd BOIN contains the last 1/3.&lt;br /&gt;
* Therefore using the formula &#039;&#039;&#039;k = floor(i / (BOIN area == 4 * 4 = 16)) == 1&#039;&#039;&#039; we can determine that our twiddled index is somewhere in the middle/2nd BOIN (Since &#039;&#039;&#039;k&#039;&#039;&#039; is of the set &#039;&#039;&#039;{0,1,2}&#039;&#039;&#039;)&lt;br /&gt;
* Note the index where our BOIN starts according to the original texture. The first index in the 2nd BOIN is &amp;quot;16&amp;quot;. Keep track of this value, lets call it &#039;&#039;&#039;d&#039;&#039;&#039;&lt;br /&gt;
* Also keep track of the index where our BOIN starts according to the twiddled texture, this is also &#039;&#039;&#039;16&#039;&#039;&#039; in this case. Lets add this to a running sum &#039;&#039;&#039;s&#039;&#039;&#039;&lt;br /&gt;
* Forget about the other two BOINs and subtract &#039;&#039;&#039;d&#039;&#039;&#039; from the indexes in our new BOIN as well as &#039;&#039;&#039;i&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
So now we have:&lt;br /&gt;
&lt;br /&gt;
 i == 8&lt;br /&gt;
 0 2 8 A&lt;br /&gt;
 1 3 9 B&lt;br /&gt;
 4 6 C E&lt;br /&gt;
 5 7 D F&lt;br /&gt;
&lt;br /&gt;
Great! We can already see by hand that this still looks right, but how do we automatically solve square BOINs?&lt;br /&gt;
* In order to solve a square BOIN, we need to determine what quadrant our pixel is in&lt;br /&gt;
* So we determine how many pixels are in each quadrant (4 per quadrant here, &#039;&#039;&#039;== a&#039;&#039;&#039;), Then calculate &#039;&#039;&#039;k = floor(i / a) == 2&#039;&#039;&#039; to know its in the 3rd quadrant (&#039;&#039;&#039;k&#039;&#039;&#039; is in the set &#039;&#039;&#039;{0,1,2,3}&#039;&#039;&#039;).&lt;br /&gt;
* That means its in the top right. So we need to set &#039;&#039;&#039;d = a * k&#039;&#039;&#039;), add our new &#039;&#039;&#039;s&#039;&#039;&#039; value to the running sum, discard the other quadrants, then subtract &#039;&#039;&#039;i&#039;&#039;&#039; and the new BOIN&#039;s indexes by &#039;&#039;&#039;d&#039;&#039;&#039;&lt;br /&gt;
* The easy way to calculate the new part of &#039;&#039;&#039;s&#039;&#039;&#039; is that:&lt;br /&gt;
** top left quadrant is &#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
** top right quad is &#039;&#039;&#039;BOIN-width / 2&#039;&#039;&#039;&lt;br /&gt;
** bottom left is &#039;&#039;&#039;BOIN-width * (BOIN-height / 2)&#039;&#039;&#039;&lt;br /&gt;
** bottom right is &#039;&#039;&#039;(BOIN-width * (BOIN-height / 2)) + (BOIN-width / 2)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Now we have:&lt;br /&gt;
&lt;br /&gt;
 i == 0&lt;br /&gt;
 0 2&lt;br /&gt;
 1 3&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You would repeat until we have a single pixel. Once we have the last pixel, our new twiddled index should be the running sum &#039;&#039;&#039;s&#039;&#039;&#039; (16 + 2 + 0 == 18)&lt;br /&gt;
&lt;br /&gt;
== How and why the Dreamcast uses Twiddling ==&lt;br /&gt;
&lt;br /&gt;
Twiddling is used on the Dreamcast for two major purposes, both owing to the same mechanism. Inside the Dreamcast, there exists a form of hardware compression in the PVR called [https://en.wikipedia.org/wiki/Vector_quantization#L135 Vector Quantization], or VQ for short. VQ works by taking an image, and splitting the image up into tiles made of 2x2 pixel patterns. Each pattern is stored in a special bit of memory on the Dreamcast known as the VQ Dictionary. The VQ dictionary contains enough space to hold 1024 of these 2x2 pixel patterns. The purpose of this tiling is to reduce the ultimate size in memory of the original textured image, as the new texture, instead of containing RGB values for each texel, instead stores a single index value that references the VQ dictionary for every 4 texels. This is considered a form of [https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Welch*L136 Lempel Ziv Welch compression].&lt;br /&gt;
&lt;br /&gt;
One can use VQ to compress textures in two ways. Firstly, one can do basic image compression as described above. However, the Dreamcast has a secondary use for the same VQ hardware, which allows it to mimic dynamic palettes of older game consoles. In this case, the original textured image is treated as though it was scaled up, so each texel comprises a 2x2 pixel region. When this is done, the VQ dictionary entries become 2x2 pixel patterns of solid color. This effectively maps single texel colors in the original texture, to VQ 2x2 solor color entries, like a palette. By changing the definition of a VQ dictionary 2x2 pixel pattern to a different solid color, you can alter every texel in the texture which references that color index. In this palette mode, 1024 entries is broken up into two formats which can be selected by the user. The first divides the palette up into sixty-four banks of 16 colors each, which makes the original texture behave like a [https://en.wikipedia.org/wiki/Color_depth#L137 4-bits per pixel] image. The other format divides the palette up into four 256 color banks, which is an 8bpp texture format.&lt;br /&gt;
&lt;br /&gt;
Interestingly, it has been discovered that applying the twiddle operation three times in succession on a twiddled texture can effectively untwiddle it.&lt;br /&gt;
&lt;br /&gt;
A last, side benefit of Twiddling on the Dreamcast is that is provides the precise pixels needed to do a 2x2 area Anti-Alaiasing filter in hardware at no extra cost.&lt;br /&gt;
&lt;br /&gt;
== DISCLAIMER ==&lt;br /&gt;
&lt;br /&gt;
This theorized solution has only been tested on a few examples by hand, so I might have missed something. But I believe at least the general logic of this is sound. Also note for implementation, some of the divisions could be replaced with bit-shifting since some of those numbers are guaranteed to be powers of 2.&lt;br /&gt;
&lt;br /&gt;
For an example of an algorithm that does the reverse (Convert twiddled index to untwiddled), you can refer to [https://github.com/Protofall/Crayon-Utilities/blob/master/DtexToRGBA8888/DtexToRGBA8888.c#L146 this code made by JamoHTP]&lt;/div&gt;</summary>
		<author><name>BBHoodsta</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Twiddling&amp;diff=3593</id>
		<title>Twiddling</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Twiddling&amp;diff=3593"/>
		<updated>2024-08-19T21:50:21Z</updated>

		<summary type="html">&lt;p&gt;BBHoodsta: /* How and why the Dreamcast uses Twiddling */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General Idea ==&lt;br /&gt;
&lt;br /&gt;
Twiddling, sometimes referred to as Swizzling in Playstation communities, and better known as Morton Encoding or a [https://en.wikipedia.org/wiki/Z-order_curve#l134 Z/N-Ordered curve], is a method of data organization that retains [https://en.wikipedia.org/wiki/Locality_of_reference#L146 Locality of Reference], which means that elements that reside physically close together in space, will be grouped together in memory. In the context of texture organization, this means that twiddling an image will make adjacent pixels to the right and below any given pixel reside close together in memory. This yields numerous benefits, such as easier calculation for AA and a texel configuration necessary for [https://en.wikipedia.org/wiki/Vector_quantization#L135 Vector Quantization] compression. &lt;br /&gt;
&lt;br /&gt;
== Origins and Classical Implementation ==&lt;br /&gt;
&lt;br /&gt;
The term &amp;quot;Twiddling&amp;quot; comes from the hacker term &amp;quot;bit-twiddling&amp;quot; owing to the classical way to calculate a Z-Ordered curve by manipulating the bits that make up the data (texel) index. The bit-twiddling way to arrive at a morton code is to take the binary representation of the X and Y coordinates of a texel and interleave them into one bitstring. The resultant bitstring will be twice the size of each individual input bitstring. For example, say you have a 4-bit number representing the X position of a Texel in a texture (e.g. XXXX) and you had a 4-bit number representing the Y position of a Texel (eg. YYYY), then your Z-Order position would be XYXY-XYXY (8-bit). This number is the index of where this texel lies in a new array that constitutes all the twiddled texels in the texture. If you convert every texel in the source texture into this new twiddled texture array, then iterating through the index will be the equivalent of navigating the source texture in a Z-pattern.&lt;br /&gt;
&lt;br /&gt;
Whether one is a Z-ordered curve or an N-ordered curve depends on whether you shift the X or Y bitstring, effectively making the traversal width by height (Z) or height by width (N). Technically, the dreamcast uses an N-ordered curve.&lt;br /&gt;
&lt;br /&gt;
A problem with using Z-ordered curves is that it&#039;s expensive to compute every frame because it uses division and multiplication heavily. Thus there exists numerous bit-twiddling hacks to speed up this operation, covered below.&lt;br /&gt;
&lt;br /&gt;
== Conceptualizing Twiddling ==&lt;br /&gt;
&lt;br /&gt;
Lets start with a recap of what Twiddled textures even are. Twiddled textures is just a particular way of re-organising pixels in an image so they&#039;re quicker to render.&lt;br /&gt;
&lt;br /&gt;
[[File:Twiddle.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
The example image where the numbers represent the original un-twiddled indexes and the &amp;quot;inverted Ns&amp;quot; show the original flow of indexes. Indexes from the original image were calculated from left to right, top to bottom (Scanline order). So we can see after index 0, number 1 is just below, 2 is to the right of 0 and 3 is just below 2. Then if we go to the next biggest inverted N we can see the order &#039;&#039;&#039;{0,1,2,3}, {4,5,6,7}, {8,9,10,11}, {12,13,14,15}&#039;&#039;&#039; following the same inverted N pattern.&lt;br /&gt;
&lt;br /&gt;
So if we are given index &#039;&#039;&#039;i&#039;&#039;&#039; from an untwiddled image and wished to find the twiddled index, then its a process of recursively narrowing down what part of the twiddled image that pixel now lives in.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
 Original:        Twiddled:&lt;br /&gt;
 &lt;br /&gt;
 0 1 2 3          0 2 8 A&lt;br /&gt;
 4 5 6 7          1 3 9 B&lt;br /&gt;
 8 9 A B          4 6 C E&lt;br /&gt;
 C D E F          5 7 D F&lt;br /&gt;
 G H I J          G I O Q&lt;br /&gt;
 K L M N          H J P R&lt;br /&gt;
 O P Q R          K M S U&lt;br /&gt;
 S T U V          L N T V&lt;br /&gt;
 W X Y Z          W Y % &amp;amp;&lt;br /&gt;
 ~ ! # $          X Z ^ *&lt;br /&gt;
 % ^ &amp;amp; *          ~ # ( _&lt;br /&gt;
 ( ) _ +          ! $ ) +&lt;br /&gt;
&lt;br /&gt;
== Look-up Table Hack ==&lt;br /&gt;
Taken from [https://graphics.stanford.edu/~seander/bithacks.html#InterleaveTableLookup#Stanford Stanford Bit-twiddling hacks page].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;static const unsigned short MortonTable256[256] = &lt;br /&gt;
{&lt;br /&gt;
  0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, &lt;br /&gt;
  0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, &lt;br /&gt;
  0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, &lt;br /&gt;
  0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, &lt;br /&gt;
  0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, &lt;br /&gt;
  0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, &lt;br /&gt;
  0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, &lt;br /&gt;
  0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, &lt;br /&gt;
  0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, &lt;br /&gt;
  0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, &lt;br /&gt;
  0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, &lt;br /&gt;
  0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, &lt;br /&gt;
  0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, &lt;br /&gt;
  0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, &lt;br /&gt;
  0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, &lt;br /&gt;
  0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, &lt;br /&gt;
  0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, &lt;br /&gt;
  0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, &lt;br /&gt;
  0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, &lt;br /&gt;
  0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, &lt;br /&gt;
  0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, &lt;br /&gt;
  0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, &lt;br /&gt;
  0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, &lt;br /&gt;
  0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, &lt;br /&gt;
  0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, &lt;br /&gt;
  0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, &lt;br /&gt;
  0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, &lt;br /&gt;
  0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, &lt;br /&gt;
  0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, &lt;br /&gt;
  0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, &lt;br /&gt;
  0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, &lt;br /&gt;
  0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
unsigned short x; // Interleave bits of x and y, so that all of the&lt;br /&gt;
unsigned short y; // bits of x are in the even positions and y in the odd;&lt;br /&gt;
unsigned int z;   // z gets the resulting 32-bit Morton Number.&lt;br /&gt;
&lt;br /&gt;
z = MortonTable256[y &amp;gt;&amp;gt; 8]   &amp;lt;&amp;lt; 17 | &lt;br /&gt;
    MortonTable256[x &amp;gt;&amp;gt; 8]   &amp;lt;&amp;lt; 16 |&lt;br /&gt;
    MortonTable256[y &amp;amp; 0xFF] &amp;lt;&amp;lt;  1 | &lt;br /&gt;
    MortonTable256[x &amp;amp; 0xFF];&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more speed, use an additional table with values that are MortonTable256 pre-shifted one bit to the left. This second table could then be used for the y lookups, thus reducing the operations by two, but almost doubling the memory required. Extending this same idea, four tables could be used, with two of them pre-shifted by 16 to the left of the previous two, so that we would only need 11 operations total.&lt;br /&gt;
&lt;br /&gt;
== Binary Magic Numbers Hack ==&lt;br /&gt;
Taken from [https://graphics.stanford.edu/~seander/bithacks.html#InterleaveTableLookup#Stanford Stanford Bit-twiddling hacks page].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;static const unsigned int B[] = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF};&lt;br /&gt;
static const unsigned int S[] = {1, 2, 4, 8};&lt;br /&gt;
&lt;br /&gt;
unsigned int x; // Interleave lower 16 bits of x and y, so the bits of x&lt;br /&gt;
unsigned int y; // are in the even positions and bits from y in the odd;&lt;br /&gt;
unsigned int z; // z gets the resulting 32-bit Morton Number. x and y must initially be less than 65536.&lt;br /&gt;
&lt;br /&gt;
x = (x | (x &amp;lt;&amp;lt; S[3])) &amp;amp; B[3];&lt;br /&gt;
x = (x | (x &amp;lt;&amp;lt; S[2])) &amp;amp; B[2];&lt;br /&gt;
x = (x | (x &amp;lt;&amp;lt; S[1])) &amp;amp; B[1];&lt;br /&gt;
x = (x | (x &amp;lt;&amp;lt; S[0])) &amp;amp; B[0];&lt;br /&gt;
y = (y | (y &amp;lt;&amp;lt; S[3])) &amp;amp; B[3];&lt;br /&gt;
y = (y | (y &amp;lt;&amp;lt; S[2])) &amp;amp; B[2];&lt;br /&gt;
y = (y | (y &amp;lt;&amp;lt; S[1])) &amp;amp; B[1];&lt;br /&gt;
y = (y | (y &amp;lt;&amp;lt; S[0])) &amp;amp; B[0];&lt;br /&gt;
z = x | (y &amp;lt;&amp;lt; 1);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Non-Dreamcast Bit-twiddling Hacks ==&lt;br /&gt;
On modern x86_64 processors from Intel actually have instructions built in to handle z-ordered curves. These are the Parallel Bit Deposit (PDEP) and Parallel bit Extraction (PEXT) instructions, which can be used in conjunction to interleave a bitstring. As the Dreamcast lacks these instructions, this is not a viable dreamcast solution.&lt;br /&gt;
&lt;br /&gt;
Another method for twiddling comes from multiplication without carry. A number multiplied upon itself using a carry-less multiplication will yield the original bitstring of the number interleaved with 0s. For example, given that the number 255 is 1111-1111 in binary, 255 multiplied-without-carry by 255 reveals a 16-bit number that is (1010-1010 1010-1010). Thus, if you use multiply without carry on the X and Y position of the texel in the texture, you&#039;ll arrive at two 16-bit numbers, e.g. X0X0-X0X0 X0X0-X0X0 and Y0Y0-Y0Y0 Y0Y0-Y0Y0. If you bitshift the X value to the right by 1, and then OR the X bitstring by the Y bitstring, the resultant 16-bit bitstring will be twiddled.&lt;br /&gt;
&lt;br /&gt;
The Dreamcast&#039;s SH4 CPU lacks a multiply-without-carry instruction, although you could create one that uses only addition like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;int multiplyWithoutCarry(int a, int b) {&lt;br /&gt;
    int result = 0;&lt;br /&gt;
    int multiplier = 1;&lt;br /&gt;
&lt;br /&gt;
    while (b != 0) {&lt;br /&gt;
        int digit = b;&lt;br /&gt;
        int temp = a;&lt;br /&gt;
&lt;br /&gt;
        while (digit &amp;gt; 9) {&lt;br /&gt;
            digit -= 10;&lt;br /&gt;
            temp += a;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        while (digit &amp;gt; 0) {&lt;br /&gt;
            result += temp;&lt;br /&gt;
            digit--;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        int divisor = 10;&lt;br /&gt;
        int tempMultiplier = multiplier;&lt;br /&gt;
&lt;br /&gt;
        while (divisor &amp;gt; 1) {&lt;br /&gt;
            if (divisor &amp;lt;= tempMultiplier) {&lt;br /&gt;
                tempMultiplier -= divisor;&lt;br /&gt;
                divisor = divisor &amp;lt;&amp;lt; 1;&lt;br /&gt;
                multiplier = multiplier &amp;lt;&amp;lt; 1;&lt;br /&gt;
            }&lt;br /&gt;
            else {&lt;br /&gt;
                divisor = divisor &amp;gt;&amp;gt; 1;&lt;br /&gt;
                tempMultiplier = tempMultiplier &amp;gt;&amp;gt; 1;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        b -= tempMultiplier;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return result;&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protofall&#039;s Implementation ==&lt;br /&gt;
&lt;br /&gt;
How to generated the twiddled index from an untwiddled texture:&lt;br /&gt;
&lt;br /&gt;
 Original:        Twiddled:&lt;br /&gt;
 &lt;br /&gt;
 0 1 2 3          0 2 8 A&lt;br /&gt;
 4 5 6 7          1 3 9 B&lt;br /&gt;
 8 9 A B          4 6 C E&lt;br /&gt;
 C D E F          5 7 D F&lt;br /&gt;
 G H I J          G I O Q&lt;br /&gt;
 K L M N          H J P R&lt;br /&gt;
 O P Q R          K M S U&lt;br /&gt;
 S T U V          L N T V&lt;br /&gt;
 W X Y Z          W Y % &amp;amp;&lt;br /&gt;
 ~ ! # $          X Z ^ *&lt;br /&gt;
 % ^ &amp;amp; *          ~ # ( _&lt;br /&gt;
 ( ) _ +          ! $ ) +&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The matching characters between the two images represent the same pixel, just relocated. These images would be 4 * 12 pixel images, but the steps work for any valid &#039;&#039;&#039;2^x * 2^&#039;&#039;&#039;y sizes, where x and y are whole numbers.&lt;br /&gt;
&lt;br /&gt;
Now lets say we want to find the twiddled index of the untwiddled &#039;&#039;&#039;&amp;quot;O&amp;quot;&#039;&#039;&#039; pixel (index 24). By hand we can work it out and tell the twiddle index should be &amp;quot;18&amp;quot;, but what algorithm/logic can we use to find this automatically for any &#039;&#039;&#039;i&#039;&#039;&#039;?&lt;br /&gt;
&lt;br /&gt;
Here are my steps:&lt;br /&gt;
* We first need to start by figuring out the &amp;quot;Biggest-Order Inverted-N&amp;quot; (&#039;&#039;&#039;BOIN&#039;&#039;&#039;) that fits in this image.&lt;br /&gt;
* Now if our starting image was a square, then the BOIN is the same size as the image&lt;br /&gt;
* For rectangles like this, we have to find the smallest side first (width) then our BOIN is width * width&lt;br /&gt;
* If we start off with a rectangle, then we need to do an extra step that squares can skip.&lt;br /&gt;
* Notice how we can completely encapsulate the whole image with &#039;&#039;&#039;(bigger_side / smaller_side) == 3&#039;&#039;&#039; BOINs? Our first step is to determine which of these BOINs our index &#039;&#039;&#039;i&#039;&#039;&#039; belongs in.&lt;br /&gt;
* We can take advantage of a quirk I mentioned earlier. Notice how the first BOIN contains the first 1/3 of the original pixels, the 2nd BOIN contains the next 1/3 and the 3rd BOIN contains the last 1/3.&lt;br /&gt;
* Therefore using the formula &#039;&#039;&#039;k = floor(i / (BOIN area == 4 * 4 = 16)) == 1&#039;&#039;&#039; we can determine that our twiddled index is somewhere in the middle/2nd BOIN (Since &#039;&#039;&#039;k&#039;&#039;&#039; is of the set &#039;&#039;&#039;{0,1,2}&#039;&#039;&#039;)&lt;br /&gt;
* Note the index where our BOIN starts according to the original texture. The first index in the 2nd BOIN is &amp;quot;16&amp;quot;. Keep track of this value, lets call it &#039;&#039;&#039;d&#039;&#039;&#039;&lt;br /&gt;
* Also keep track of the index where our BOIN starts according to the twiddled texture, this is also &#039;&#039;&#039;16&#039;&#039;&#039; in this case. Lets add this to a running sum &#039;&#039;&#039;s&#039;&#039;&#039;&lt;br /&gt;
* Forget about the other two BOINs and subtract &#039;&#039;&#039;d&#039;&#039;&#039; from the indexes in our new BOIN as well as &#039;&#039;&#039;i&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
So now we have:&lt;br /&gt;
&lt;br /&gt;
 i == 8&lt;br /&gt;
 0 2 8 A&lt;br /&gt;
 1 3 9 B&lt;br /&gt;
 4 6 C E&lt;br /&gt;
 5 7 D F&lt;br /&gt;
&lt;br /&gt;
Great! We can already see by hand that this still looks right, but how do we automatically solve square BOINs?&lt;br /&gt;
* In order to solve a square BOIN, we need to determine what quadrant our pixel is in&lt;br /&gt;
* So we determine how many pixels are in each quadrant (4 per quadrant here, &#039;&#039;&#039;== a&#039;&#039;&#039;), Then calculate &#039;&#039;&#039;k = floor(i / a) == 2&#039;&#039;&#039; to know its in the 3rd quadrant (&#039;&#039;&#039;k&#039;&#039;&#039; is in the set &#039;&#039;&#039;{0,1,2,3}&#039;&#039;&#039;).&lt;br /&gt;
* That means its in the top right. So we need to set &#039;&#039;&#039;d = a * k&#039;&#039;&#039;), add our new &#039;&#039;&#039;s&#039;&#039;&#039; value to the running sum, discard the other quadrants, then subtract &#039;&#039;&#039;i&#039;&#039;&#039; and the new BOIN&#039;s indexes by &#039;&#039;&#039;d&#039;&#039;&#039;&lt;br /&gt;
* The easy way to calculate the new part of &#039;&#039;&#039;s&#039;&#039;&#039; is that:&lt;br /&gt;
** top left quadrant is &#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
** top right quad is &#039;&#039;&#039;BOIN-width / 2&#039;&#039;&#039;&lt;br /&gt;
** bottom left is &#039;&#039;&#039;BOIN-width * (BOIN-height / 2)&#039;&#039;&#039;&lt;br /&gt;
** bottom right is &#039;&#039;&#039;(BOIN-width * (BOIN-height / 2)) + (BOIN-width / 2)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Now we have:&lt;br /&gt;
&lt;br /&gt;
 i == 0&lt;br /&gt;
 0 2&lt;br /&gt;
 1 3&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You would repeat until we have a single pixel. Once we have the last pixel, our new twiddled index should be the running sum &#039;&#039;&#039;s&#039;&#039;&#039; (16 + 2 + 0 == 18)&lt;br /&gt;
&lt;br /&gt;
== How and why the Dreamcast uses Twiddling ==&lt;br /&gt;
&lt;br /&gt;
Twiddling is used on the Dreamcast for two major purposes, both owing to the same mechanism. Inside the Dreamcast, there exists a form of hardware compression in the PVR called [https://en.wikipedia.org/wiki/Vector_quantization#L135 Vector Quantization], or VQ for short. VQ works by taking an image, and splitting the image up into tiles made of 2x2 pixel patterns. Each pattern is stored in a special bit of memory on the Dreamcast known as the VQ Dictionary. The VQ dictionary contains enough space to hold 1024 of these 2x2 pixel patterns. The purpose of this tiling is to reduce the ultimate size in memory of the original textured image, as the new texture, instead of containing RGB values for each texel, instead stores a single index value that references the VQ dictionary for every 4 texels. This is considered a form of [https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Welch*L136 Lempel Ziv Welch compression].&lt;br /&gt;
&lt;br /&gt;
One can use VQ to compress textures in two ways. Firstly, one can do basic image compression as described above. However, the Dreamcast has a secondary use for the same VQ hardware, which allows it to mimic dynamic palettes of older game consoles. In this case, the original textured image is treated as though it was scaled up, so each texel comprises a 2x2 pixel region. When this is done, the VQ dictionary entries become 2x2 pixel patterns of solid color. This effectively maps single texel colors in the original texture, to VQ 2x2 solor color entries, like a palette. By changing the definition of a VQ dictionary 2x2 pixel pattern to a different solid color, you can alter every texel in the texture which references that color index. In this palette mode, 1024 entries is broken up into two formats which can be selected by the user. The first divides the palette up into sixty-four banks of 16 colors each, which makes the original texture behave like a [https://en.wikipedia.org/wiki/Color_depth#L137 4-bits per pixel] image. The other format divides the palette up into four 256 color banks, which is an 8bpp texture format.&lt;br /&gt;
&lt;br /&gt;
Interestingly, it has been discovered that applying the twiddle operation two times in succession on a twiddled texture can effectively untwiddle it.&lt;br /&gt;
&lt;br /&gt;
A last, side benefit of Twiddling on the Dreamcast is that is provides the precise pixels needed to do a 2x2 area Anti-Alaiasing filter in hardware at no extra cost.&lt;br /&gt;
&lt;br /&gt;
== DISCLAIMER ==&lt;br /&gt;
&lt;br /&gt;
This theorized solution has only been tested on a few examples by hand, so I might have missed something. But I believe at least the general logic of this is sound. Also note for implementation, some of the divisions could be replaced with bit-shifting since some of those numbers are guaranteed to be powers of 2.&lt;br /&gt;
&lt;br /&gt;
For an example of an algorithm that does the reverse (Convert twiddled index to untwiddled), you can refer to [https://github.com/Protofall/Crayon-Utilities/blob/master/DtexToRGBA8888/DtexToRGBA8888.c#L146 this code made by JamoHTP]&lt;/div&gt;</summary>
		<author><name>BBHoodsta</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Twiddling&amp;diff=3592</id>
		<title>Twiddling</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Twiddling&amp;diff=3592"/>
		<updated>2024-08-19T18:34:00Z</updated>

		<summary type="html">&lt;p&gt;BBHoodsta: /* How and why the Dreamcast uses Twiddling */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General Idea ==&lt;br /&gt;
&lt;br /&gt;
Twiddling, sometimes referred to as Swizzling in Playstation communities, and better known as Morton Encoding or a [https://en.wikipedia.org/wiki/Z-order_curve#l134 Z/N-Ordered curve], is a method of data organization that retains [https://en.wikipedia.org/wiki/Locality_of_reference#L146 Locality of Reference], which means that elements that reside physically close together in space, will be grouped together in memory. In the context of texture organization, this means that twiddling an image will make adjacent pixels to the right and below any given pixel reside close together in memory. This yields numerous benefits, such as easier calculation for AA and a texel configuration necessary for [https://en.wikipedia.org/wiki/Vector_quantization#L135 Vector Quantization] compression. &lt;br /&gt;
&lt;br /&gt;
== Origins and Classical Implementation ==&lt;br /&gt;
&lt;br /&gt;
The term &amp;quot;Twiddling&amp;quot; comes from the hacker term &amp;quot;bit-twiddling&amp;quot; owing to the classical way to calculate a Z-Ordered curve by manipulating the bits that make up the data (texel) index. The bit-twiddling way to arrive at a morton code is to take the binary representation of the X and Y coordinates of a texel and interleave them into one bitstring. The resultant bitstring will be twice the size of each individual input bitstring. For example, say you have a 4-bit number representing the X position of a Texel in a texture (e.g. XXXX) and you had a 4-bit number representing the Y position of a Texel (eg. YYYY), then your Z-Order position would be XYXY-XYXY (8-bit). This number is the index of where this texel lies in a new array that constitutes all the twiddled texels in the texture. If you convert every texel in the source texture into this new twiddled texture array, then iterating through the index will be the equivalent of navigating the source texture in a Z-pattern.&lt;br /&gt;
&lt;br /&gt;
Whether one is a Z-ordered curve or an N-ordered curve depends on whether you shift the X or Y bitstring, effectively making the traversal width by height (Z) or height by width (N). Technically, the dreamcast uses an N-ordered curve.&lt;br /&gt;
&lt;br /&gt;
A problem with using Z-ordered curves is that it&#039;s expensive to compute every frame because it uses division and multiplication heavily. Thus there exists numerous bit-twiddling hacks to speed up this operation, covered below.&lt;br /&gt;
&lt;br /&gt;
== Conceptualizing Twiddling ==&lt;br /&gt;
&lt;br /&gt;
Lets start with a recap of what Twiddled textures even are. Twiddled textures is just a particular way of re-organising pixels in an image so they&#039;re quicker to render.&lt;br /&gt;
&lt;br /&gt;
[[File:Twiddle.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
The example image where the numbers represent the original un-twiddled indexes and the &amp;quot;inverted Ns&amp;quot; show the original flow of indexes. Indexes from the original image were calculated from left to right, top to bottom (Scanline order). So we can see after index 0, number 1 is just below, 2 is to the right of 0 and 3 is just below 2. Then if we go to the next biggest inverted N we can see the order &#039;&#039;&#039;{0,1,2,3}, {4,5,6,7}, {8,9,10,11}, {12,13,14,15}&#039;&#039;&#039; following the same inverted N pattern.&lt;br /&gt;
&lt;br /&gt;
So if we are given index &#039;&#039;&#039;i&#039;&#039;&#039; from an untwiddled image and wished to find the twiddled index, then its a process of recursively narrowing down what part of the twiddled image that pixel now lives in.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
 Original:        Twiddled:&lt;br /&gt;
 &lt;br /&gt;
 0 1 2 3          0 2 8 A&lt;br /&gt;
 4 5 6 7          1 3 9 B&lt;br /&gt;
 8 9 A B          4 6 C E&lt;br /&gt;
 C D E F          5 7 D F&lt;br /&gt;
 G H I J          G I O Q&lt;br /&gt;
 K L M N          H J P R&lt;br /&gt;
 O P Q R          K M S U&lt;br /&gt;
 S T U V          L N T V&lt;br /&gt;
 W X Y Z          W Y % &amp;amp;&lt;br /&gt;
 ~ ! # $          X Z ^ *&lt;br /&gt;
 % ^ &amp;amp; *          ~ # ( _&lt;br /&gt;
 ( ) _ +          ! $ ) +&lt;br /&gt;
&lt;br /&gt;
== Look-up Table Hack ==&lt;br /&gt;
Taken from [https://graphics.stanford.edu/~seander/bithacks.html#InterleaveTableLookup#Stanford Stanford Bit-twiddling hacks page].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;static const unsigned short MortonTable256[256] = &lt;br /&gt;
{&lt;br /&gt;
  0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, &lt;br /&gt;
  0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, &lt;br /&gt;
  0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, &lt;br /&gt;
  0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, &lt;br /&gt;
  0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, &lt;br /&gt;
  0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, &lt;br /&gt;
  0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, &lt;br /&gt;
  0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, &lt;br /&gt;
  0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, &lt;br /&gt;
  0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, &lt;br /&gt;
  0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, &lt;br /&gt;
  0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, &lt;br /&gt;
  0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, &lt;br /&gt;
  0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, &lt;br /&gt;
  0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, &lt;br /&gt;
  0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, &lt;br /&gt;
  0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, &lt;br /&gt;
  0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, &lt;br /&gt;
  0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, &lt;br /&gt;
  0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, &lt;br /&gt;
  0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, &lt;br /&gt;
  0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, &lt;br /&gt;
  0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, &lt;br /&gt;
  0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, &lt;br /&gt;
  0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, &lt;br /&gt;
  0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, &lt;br /&gt;
  0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, &lt;br /&gt;
  0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, &lt;br /&gt;
  0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, &lt;br /&gt;
  0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, &lt;br /&gt;
  0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, &lt;br /&gt;
  0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
unsigned short x; // Interleave bits of x and y, so that all of the&lt;br /&gt;
unsigned short y; // bits of x are in the even positions and y in the odd;&lt;br /&gt;
unsigned int z;   // z gets the resulting 32-bit Morton Number.&lt;br /&gt;
&lt;br /&gt;
z = MortonTable256[y &amp;gt;&amp;gt; 8]   &amp;lt;&amp;lt; 17 | &lt;br /&gt;
    MortonTable256[x &amp;gt;&amp;gt; 8]   &amp;lt;&amp;lt; 16 |&lt;br /&gt;
    MortonTable256[y &amp;amp; 0xFF] &amp;lt;&amp;lt;  1 | &lt;br /&gt;
    MortonTable256[x &amp;amp; 0xFF];&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more speed, use an additional table with values that are MortonTable256 pre-shifted one bit to the left. This second table could then be used for the y lookups, thus reducing the operations by two, but almost doubling the memory required. Extending this same idea, four tables could be used, with two of them pre-shifted by 16 to the left of the previous two, so that we would only need 11 operations total.&lt;br /&gt;
&lt;br /&gt;
== Binary Magic Numbers Hack ==&lt;br /&gt;
Taken from [https://graphics.stanford.edu/~seander/bithacks.html#InterleaveTableLookup#Stanford Stanford Bit-twiddling hacks page].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;static const unsigned int B[] = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF};&lt;br /&gt;
static const unsigned int S[] = {1, 2, 4, 8};&lt;br /&gt;
&lt;br /&gt;
unsigned int x; // Interleave lower 16 bits of x and y, so the bits of x&lt;br /&gt;
unsigned int y; // are in the even positions and bits from y in the odd;&lt;br /&gt;
unsigned int z; // z gets the resulting 32-bit Morton Number. x and y must initially be less than 65536.&lt;br /&gt;
&lt;br /&gt;
x = (x | (x &amp;lt;&amp;lt; S[3])) &amp;amp; B[3];&lt;br /&gt;
x = (x | (x &amp;lt;&amp;lt; S[2])) &amp;amp; B[2];&lt;br /&gt;
x = (x | (x &amp;lt;&amp;lt; S[1])) &amp;amp; B[1];&lt;br /&gt;
x = (x | (x &amp;lt;&amp;lt; S[0])) &amp;amp; B[0];&lt;br /&gt;
y = (y | (y &amp;lt;&amp;lt; S[3])) &amp;amp; B[3];&lt;br /&gt;
y = (y | (y &amp;lt;&amp;lt; S[2])) &amp;amp; B[2];&lt;br /&gt;
y = (y | (y &amp;lt;&amp;lt; S[1])) &amp;amp; B[1];&lt;br /&gt;
y = (y | (y &amp;lt;&amp;lt; S[0])) &amp;amp; B[0];&lt;br /&gt;
z = x | (y &amp;lt;&amp;lt; 1);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Non-Dreamcast Bit-twiddling Hacks ==&lt;br /&gt;
On modern x86_64 processors from Intel actually have instructions built in to handle z-ordered curves. These are the Parallel Bit Deposit (PDEP) and Parallel bit Extraction (PEXT) instructions, which can be used in conjunction to interleave a bitstring. As the Dreamcast lacks these instructions, this is not a viable dreamcast solution.&lt;br /&gt;
&lt;br /&gt;
Another method for twiddling comes from multiplication without carry. A number multiplied upon itself using a carry-less multiplication will yield the original bitstring of the number interleaved with 0s. For example, given that the number 255 is 1111-1111 in binary, 255 multiplied-without-carry by 255 reveals a 16-bit number that is (1010-1010 1010-1010). Thus, if you use multiply without carry on the X and Y position of the texel in the texture, you&#039;ll arrive at two 16-bit numbers, e.g. X0X0-X0X0 X0X0-X0X0 and Y0Y0-Y0Y0 Y0Y0-Y0Y0. If you bitshift the X value to the right by 1, and then OR the X bitstring by the Y bitstring, the resultant 16-bit bitstring will be twiddled.&lt;br /&gt;
&lt;br /&gt;
The Dreamcast&#039;s SH4 CPU lacks a multiply-without-carry instruction, although you could create one that uses only addition like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;int multiplyWithoutCarry(int a, int b) {&lt;br /&gt;
    int result = 0;&lt;br /&gt;
    int multiplier = 1;&lt;br /&gt;
&lt;br /&gt;
    while (b != 0) {&lt;br /&gt;
        int digit = b;&lt;br /&gt;
        int temp = a;&lt;br /&gt;
&lt;br /&gt;
        while (digit &amp;gt; 9) {&lt;br /&gt;
            digit -= 10;&lt;br /&gt;
            temp += a;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        while (digit &amp;gt; 0) {&lt;br /&gt;
            result += temp;&lt;br /&gt;
            digit--;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        int divisor = 10;&lt;br /&gt;
        int tempMultiplier = multiplier;&lt;br /&gt;
&lt;br /&gt;
        while (divisor &amp;gt; 1) {&lt;br /&gt;
            if (divisor &amp;lt;= tempMultiplier) {&lt;br /&gt;
                tempMultiplier -= divisor;&lt;br /&gt;
                divisor = divisor &amp;lt;&amp;lt; 1;&lt;br /&gt;
                multiplier = multiplier &amp;lt;&amp;lt; 1;&lt;br /&gt;
            }&lt;br /&gt;
            else {&lt;br /&gt;
                divisor = divisor &amp;gt;&amp;gt; 1;&lt;br /&gt;
                tempMultiplier = tempMultiplier &amp;gt;&amp;gt; 1;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        b -= tempMultiplier;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return result;&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Protofall&#039;s Implementation ==&lt;br /&gt;
&lt;br /&gt;
How to generated the twiddled index from an untwiddled texture:&lt;br /&gt;
&lt;br /&gt;
 Original:        Twiddled:&lt;br /&gt;
 &lt;br /&gt;
 0 1 2 3          0 2 8 A&lt;br /&gt;
 4 5 6 7          1 3 9 B&lt;br /&gt;
 8 9 A B          4 6 C E&lt;br /&gt;
 C D E F          5 7 D F&lt;br /&gt;
 G H I J          G I O Q&lt;br /&gt;
 K L M N          H J P R&lt;br /&gt;
 O P Q R          K M S U&lt;br /&gt;
 S T U V          L N T V&lt;br /&gt;
 W X Y Z          W Y % &amp;amp;&lt;br /&gt;
 ~ ! # $          X Z ^ *&lt;br /&gt;
 % ^ &amp;amp; *          ~ # ( _&lt;br /&gt;
 ( ) _ +          ! $ ) +&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The matching characters between the two images represent the same pixel, just relocated. These images would be 4 * 12 pixel images, but the steps work for any valid &#039;&#039;&#039;2^x * 2^&#039;&#039;&#039;y sizes, where x and y are whole numbers.&lt;br /&gt;
&lt;br /&gt;
Now lets say we want to find the twiddled index of the untwiddled &#039;&#039;&#039;&amp;quot;O&amp;quot;&#039;&#039;&#039; pixel (index 24). By hand we can work it out and tell the twiddle index should be &amp;quot;18&amp;quot;, but what algorithm/logic can we use to find this automatically for any &#039;&#039;&#039;i&#039;&#039;&#039;?&lt;br /&gt;
&lt;br /&gt;
Here are my steps:&lt;br /&gt;
* We first need to start by figuring out the &amp;quot;Biggest-Order Inverted-N&amp;quot; (&#039;&#039;&#039;BOIN&#039;&#039;&#039;) that fits in this image.&lt;br /&gt;
* Now if our starting image was a square, then the BOIN is the same size as the image&lt;br /&gt;
* For rectangles like this, we have to find the smallest side first (width) then our BOIN is width * width&lt;br /&gt;
* If we start off with a rectangle, then we need to do an extra step that squares can skip.&lt;br /&gt;
* Notice how we can completely encapsulate the whole image with &#039;&#039;&#039;(bigger_side / smaller_side) == 3&#039;&#039;&#039; BOINs? Our first step is to determine which of these BOINs our index &#039;&#039;&#039;i&#039;&#039;&#039; belongs in.&lt;br /&gt;
* We can take advantage of a quirk I mentioned earlier. Notice how the first BOIN contains the first 1/3 of the original pixels, the 2nd BOIN contains the next 1/3 and the 3rd BOIN contains the last 1/3.&lt;br /&gt;
* Therefore using the formula &#039;&#039;&#039;k = floor(i / (BOIN area == 4 * 4 = 16)) == 1&#039;&#039;&#039; we can determine that our twiddled index is somewhere in the middle/2nd BOIN (Since &#039;&#039;&#039;k&#039;&#039;&#039; is of the set &#039;&#039;&#039;{0,1,2}&#039;&#039;&#039;)&lt;br /&gt;
* Note the index where our BOIN starts according to the original texture. The first index in the 2nd BOIN is &amp;quot;16&amp;quot;. Keep track of this value, lets call it &#039;&#039;&#039;d&#039;&#039;&#039;&lt;br /&gt;
* Also keep track of the index where our BOIN starts according to the twiddled texture, this is also &#039;&#039;&#039;16&#039;&#039;&#039; in this case. Lets add this to a running sum &#039;&#039;&#039;s&#039;&#039;&#039;&lt;br /&gt;
* Forget about the other two BOINs and subtract &#039;&#039;&#039;d&#039;&#039;&#039; from the indexes in our new BOIN as well as &#039;&#039;&#039;i&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
So now we have:&lt;br /&gt;
&lt;br /&gt;
 i == 8&lt;br /&gt;
 0 2 8 A&lt;br /&gt;
 1 3 9 B&lt;br /&gt;
 4 6 C E&lt;br /&gt;
 5 7 D F&lt;br /&gt;
&lt;br /&gt;
Great! We can already see by hand that this still looks right, but how do we automatically solve square BOINs?&lt;br /&gt;
* In order to solve a square BOIN, we need to determine what quadrant our pixel is in&lt;br /&gt;
* So we determine how many pixels are in each quadrant (4 per quadrant here, &#039;&#039;&#039;== a&#039;&#039;&#039;), Then calculate &#039;&#039;&#039;k = floor(i / a) == 2&#039;&#039;&#039; to know its in the 3rd quadrant (&#039;&#039;&#039;k&#039;&#039;&#039; is in the set &#039;&#039;&#039;{0,1,2,3}&#039;&#039;&#039;).&lt;br /&gt;
* That means its in the top right. So we need to set &#039;&#039;&#039;d = a * k&#039;&#039;&#039;), add our new &#039;&#039;&#039;s&#039;&#039;&#039; value to the running sum, discard the other quadrants, then subtract &#039;&#039;&#039;i&#039;&#039;&#039; and the new BOIN&#039;s indexes by &#039;&#039;&#039;d&#039;&#039;&#039;&lt;br /&gt;
* The easy way to calculate the new part of &#039;&#039;&#039;s&#039;&#039;&#039; is that:&lt;br /&gt;
** top left quadrant is &#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
** top right quad is &#039;&#039;&#039;BOIN-width / 2&#039;&#039;&#039;&lt;br /&gt;
** bottom left is &#039;&#039;&#039;BOIN-width * (BOIN-height / 2)&#039;&#039;&#039;&lt;br /&gt;
** bottom right is &#039;&#039;&#039;(BOIN-width * (BOIN-height / 2)) + (BOIN-width / 2)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Now we have:&lt;br /&gt;
&lt;br /&gt;
 i == 0&lt;br /&gt;
 0 2&lt;br /&gt;
 1 3&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You would repeat until we have a single pixel. Once we have the last pixel, our new twiddled index should be the running sum &#039;&#039;&#039;s&#039;&#039;&#039; (16 + 2 + 0 == 18)&lt;br /&gt;
&lt;br /&gt;
== How and why the Dreamcast uses Twiddling ==&lt;br /&gt;
&lt;br /&gt;
Twiddling is used on the Dreamcast for two major purposes, both owing to the same mechanism. Inside the Dreamcast, there exists a form of hardware compression in the PVR called [https://en.wikipedia.org/wiki/Vector_quantization#L135 Vector Quantization], or VQ for short. VQ works by taking an image, and splitting the image up into tiles made of 2x2 pixel patterns. Each pattern is stored in a special bit of memory on the Dreamcast known as the VQ Dictionary. The VQ dictionary contains enough space to hold 1024 of these 2x2 pixel patterns. The purpose of this tiling is to reduce the ultimate size in memory of the original textured image, as the new texture, instead of containing RGB values for each texel, instead stores a single index value that references the VQ dictionary for every 4 texels. This is considered a form of [https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Welch*L136 Lempel Ziv Welch compression].&lt;br /&gt;
&lt;br /&gt;
One can use VQ to compress textures in two ways. Firstly, one can do basic image compression as described above. However, the Dreamcast has a secondary use for the same VQ hardware, which allows it to mimic dynamic palettes of older game consoles. In this case, the original textured image is treated as though it was scaled up, so each texel comprises a 2x2 pixel region. When this is done, the VQ dictionary entries become 2x2 pixel patterns of solid color. This effectively maps single texel colors in the original texture, to VQ 2x2 solor color entries, like a palette. By changing the definition of a VQ dictionary 2x2 pixel pattern to a different solid color, you can alter every texel in the texture which references that color index. In this palette mode, 1024 entries is broken up into two formats which can be selected by the user. The first divides the palette up into sixty-four banks of 16 colors each, which makes the original texture behave like a [https://en.wikipedia.org/wiki/Color_depth#L137 4-bits per pixel] image. The other format divides the palette up into four 256 color banks, which is an 8bpp texture format.&lt;br /&gt;
&lt;br /&gt;
Interestingly, it has been discovered that applying the twiddle operation three times in succession can effectively untwiddle a texture.&lt;br /&gt;
&lt;br /&gt;
A last, side benefit of Twiddling on the Dreamcast is that is provides the precise pixels needed to do a 2x2 area Anti-Alaiasing filter in hardware at no extra cost.&lt;br /&gt;
&lt;br /&gt;
== DISCLAIMER ==&lt;br /&gt;
&lt;br /&gt;
This theorized solution has only been tested on a few examples by hand, so I might have missed something. But I believe at least the general logic of this is sound. Also note for implementation, some of the divisions could be replaced with bit-shifting since some of those numbers are guaranteed to be powers of 2.&lt;br /&gt;
&lt;br /&gt;
For an example of an algorithm that does the reverse (Convert twiddled index to untwiddled), you can refer to [https://github.com/Protofall/Crayon-Utilities/blob/master/DtexToRGBA8888/DtexToRGBA8888.c#L146 this code made by JamoHTP]&lt;/div&gt;</summary>
		<author><name>BBHoodsta</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Codespaces&amp;diff=3587</id>
		<title>Codespaces</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Codespaces&amp;diff=3587"/>
		<updated>2024-07-14T15:30:10Z</updated>

		<summary type="html">&lt;p&gt;BBHoodsta: /* Example 1: Build an .elf from a KallistiOS example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Github [https://www.youtube.com/watch?v=sYJ3CHtT6WM Codespaces] lets you spawn a complete Dreamcast development environment in your browser in a matter of minutes.&lt;br /&gt;
&lt;br /&gt;
The only things you need are:&lt;br /&gt;
* a browser&lt;br /&gt;
* a github login.&lt;br /&gt;
&lt;br /&gt;
No need for a complex installation process anymore !&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Steps Overview ==&lt;br /&gt;
The main steps to get a Codespace working, are:&lt;br /&gt;
* Login into [https://github.com github]&lt;br /&gt;
* Create your code repository, or fork one&lt;br /&gt;
* Add a .devcontainer/devcontainer.json file to that repository&lt;br /&gt;
* Create &amp;amp; launch your codespace, and enjoy the IDE in your browser !&lt;br /&gt;
&lt;br /&gt;
That&#039;s all there is to it.&lt;br /&gt;
&lt;br /&gt;
Free github accounts get [https://docs.github.com/en/billing/managing-billing-for-github-codespaces/about-billing-for-github-codespaces#monthly-included-storage-and-core-hours-for-personal-accounts 120 free core hours per month].&lt;br /&gt;
&lt;br /&gt;
== Example 1: Build an .elf from a KallistiOS example ==&lt;br /&gt;
To compile the executable .elf file from a KallistiOS examples in a Codespace:&lt;br /&gt;
* Login into [https://github.com github]&lt;br /&gt;
* Got to [https://github.com/KallistiOS/KallistiOS the KallistiOS repository]&lt;br /&gt;
* Click on the &amp;quot;Fork&amp;quot; button, this will create a KallistiOS repository inside your account&lt;br /&gt;
* Click on the &amp;quot;Add File&amp;quot; button, then &amp;quot;Create New File&amp;quot;&lt;br /&gt;
* Name the file: &amp;quot;.devcontainer/devcontainer.json&amp;quot;, and paste the following contents:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
// For format details, see https://aka.ms/devcontainer.json. &lt;br /&gt;
// For config options, see the README at: https://github.com/devcontainers/templates/tree/main/src/alpine&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;name&amp;quot;: &amp;quot;My_Codespace&amp;quot;,&lt;br /&gt;
		&lt;br /&gt;
	// Either use a pre-built image (= a Docker container)...&lt;br /&gt;
	&amp;quot;image&amp;quot;: &amp;quot;ghcr.io/kos-builds/kos-ports-dc:sha-656a397-14.1.0&amp;quot;,&lt;br /&gt;
	// ... or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile&lt;br /&gt;
	//&amp;quot;build&amp;quot;: { // Path is relative to the devcontainer.json file.&lt;br /&gt;
	//    &amp;quot;dockerfile&amp;quot;: &amp;quot;Dockerfile&amp;quot;&lt;br /&gt;
	//},&lt;br /&gt;
		&lt;br /&gt;
	// Features to add to the dev container. More info: https://containers.dev/features.&lt;br /&gt;
	// &amp;quot;features&amp;quot;: {},&lt;br /&gt;
&lt;br /&gt;
	// Use &#039;forwardPorts&#039; to make a list of ports inside the container available locally.&lt;br /&gt;
	// &amp;quot;forwardPorts&amp;quot;: [],&lt;br /&gt;
&lt;br /&gt;
	// Use &#039;postCreateCommand&#039; to run commands after the container is created.&lt;br /&gt;
	//&amp;quot;postCreateCommand&amp;quot;: &amp;quot;source /opt/toolchains/dc/kos/environ.sh&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
	// Configure tool-specific properties.&lt;br /&gt;
	&amp;quot;customizations&amp;quot;: {&lt;br /&gt;
	    &amp;quot;vscode&amp;quot;: {&lt;br /&gt;
	        &amp;quot;extensions&amp;quot;: [&lt;br /&gt;
		    &amp;quot;ms-vscode.cpptools&amp;quot;&lt;br /&gt;
	        ]&lt;br /&gt;
	    }&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.&lt;br /&gt;
	// &amp;quot;remoteUser&amp;quot;: &amp;quot;root&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* Click on &amp;quot;Commit changes&amp;quot;, then &amp;quot;Commit Changes&amp;quot; again to save the file&lt;br /&gt;
* Go back to the root directory of your repository&lt;br /&gt;
* Launch your Codespace by clicking on the &amp;quot;&amp;lt;&amp;gt; Code&amp;quot; button, then &amp;quot;Codespaces&amp;quot; - &amp;quot;Create codespace on master&amp;quot;.&lt;br /&gt;
[[File:Screen Shot 2024-07-14 at 8.28.13 AM.png|thumb]]&lt;br /&gt;
* This will launch Visual Studio Code in your browser. The first time it will take a couple of minutes to launch, after that it will be faster.&lt;br /&gt;
* 3-bars-Menu at the top left - Terminal - New Terminal&lt;br /&gt;
* cd examples/dreamcast/2ndmix&lt;br /&gt;
* make clean&lt;br /&gt;
* make&lt;br /&gt;
* You should now have a &amp;quot;2ndmix.elf&amp;quot; in that folder&lt;br /&gt;
* Navigate to that folder (examples/dreamcast/2ndmix) on the file tree on the left, right-click on the file, and choose &amp;quot;Download...&amp;quot;&lt;br /&gt;
* Congratulations ! You successfully built an executable file for the Dreamcast. You can now upload that file in your favorite emulator, or send it to a real Dreamcast via a [https://dreamcast.wiki/Coder%27s_cable Coder&#039;s Cable] or a [https://dreamcast.wiki/Broadband_adapter Broadband Adapter]&lt;br /&gt;
&lt;br /&gt;
== Example 2: create a .cdi from the .elf of Example 1 ==&lt;br /&gt;
Having an .elf executable file is nice for small tests, but often you&#039;ll find yourself needing to build a .cdi disc image file:&lt;br /&gt;
* If you closed your codespace, you can reopen it by going to your code repository, click on the &amp;quot;&amp;lt;&amp;gt; Code&amp;quot; button, then &amp;quot;Codespaces&amp;quot;, then on the auto-generated name of your codespace.&lt;br /&gt;
* Since our codespace does not contain mkdcdisc (the tool to build .cdi files), we&#039;ll add that to our codespace:&lt;br /&gt;
** Open a terminal in your codespace (3-bars-Menu at the top left - Terminal - New Terminal)&lt;br /&gt;
** cd /opt/toolchains/dc&lt;br /&gt;
** git clone https://gitlab.com/simulant/mkdcdisc&lt;br /&gt;
** cd mkdcdisc&lt;br /&gt;
** meson setup builddir&lt;br /&gt;
** meson compile -C builddir&lt;br /&gt;
** cp ./builddir/mkdcdisc /opt/toolchains/dc/bin&lt;br /&gt;
* Build the .cdi file for 2ndmix.elf&lt;br /&gt;
** cd /opt/toolchains/dc/kos/examples/dreamcast/2ndmix&lt;br /&gt;
** mkdcdisc -e 2ndmix.elf -o 2ndmix.cdi -n &amp;quot;2ndmix&amp;quot;&lt;br /&gt;
* Compress the .cdi file into a zip file with parts of max 25 MegaBytes (otherwise your browser will have problems downloading the .cdi):&lt;br /&gt;
** zip -s 25M 2ndmix.zip 2ndmix.cdi&lt;br /&gt;
* Right-click on the generated files, and download them into your local folders&lt;br /&gt;
* Unzip the files in your local folder to reconstruct 2ndmix.cdi&lt;br /&gt;
* Launch 2ndmix.cdi in your favorite emulator, or on a real Dreamcast&lt;br /&gt;
&lt;br /&gt;
== Example 3: Configuring a more complex Codespace ==&lt;br /&gt;
If you find yourself always adding the same extra application into the codespace provided in Example 1 (eg: always having to add mkdcdisc, ...), you can simplify your setup by specifying your own Dockerfile, and add setup commands in there:&lt;br /&gt;
&lt;br /&gt;
* Modify .devcontainer/devcontainer.json so that it points to a Dockerfile:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
// For format details, see https://aka.ms/devcontainer.json. &lt;br /&gt;
// For config options, see the README at: https://github.com/devcontainers/templates/tree/main/src/alpine&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;name&amp;quot;: &amp;quot;My_Codespace&amp;quot;,&lt;br /&gt;
		&lt;br /&gt;
	// Either use a pre-built image (= a Docker container)...&lt;br /&gt;
	//&amp;quot;image&amp;quot;: &amp;quot;ghcr.io/kos-builds/kos-ports-dc:sha-656a397-14.1.0&amp;quot;,&lt;br /&gt;
	// ... or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile&lt;br /&gt;
	&amp;quot;build&amp;quot;: { // Path is relative to the devcontainer.json file.&lt;br /&gt;
	    &amp;quot;dockerfile&amp;quot;: &amp;quot;Dockerfile&amp;quot;&lt;br /&gt;
	},&lt;br /&gt;
		&lt;br /&gt;
	// Features to add to the dev container. More info: https://containers.dev/features.&lt;br /&gt;
	// &amp;quot;features&amp;quot;: {},&lt;br /&gt;
&lt;br /&gt;
	// Use &#039;forwardPorts&#039; to make a list of ports inside the container available locally.&lt;br /&gt;
	// &amp;quot;forwardPorts&amp;quot;: [],&lt;br /&gt;
&lt;br /&gt;
	// Use &#039;postCreateCommand&#039; to run commands after the container is created.&lt;br /&gt;
	//&amp;quot;postCreateCommand&amp;quot;: &amp;quot;source /opt/toolchains/dc/kos/environ.sh&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
	// Configure tool-specific properties.&lt;br /&gt;
	&amp;quot;customizations&amp;quot;: {&lt;br /&gt;
	    &amp;quot;vscode&amp;quot;: {&lt;br /&gt;
	        &amp;quot;extensions&amp;quot;: [&lt;br /&gt;
		    &amp;quot;ms-vscode.cpptools&amp;quot;&lt;br /&gt;
	        ]&lt;br /&gt;
	    }&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.&lt;br /&gt;
	// &amp;quot;remoteUser&amp;quot;: &amp;quot;root&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* ... and add a new file: ./devcontainer/Dockerfile&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Stage 1&lt;br /&gt;
FROM &amp;quot;ghcr.io/kos-builds/kos-ports-dc:sha-656a397-14.1.0&amp;quot; as build&lt;br /&gt;
&lt;br /&gt;
# Add mkdcdisc&lt;br /&gt;
RUN git clone https://gitlab.com/simulant/mkdcdisc /opt/toolchains/dc/mkdcdisc \&lt;br /&gt;
    &amp;amp;&amp;amp; cd /opt/toolchains/dc/mkdcdisc \&lt;br /&gt;
    &amp;amp;&amp;amp; meson setup builddir \&lt;br /&gt;
    &amp;amp;&amp;amp; meson compile -C builddir \&lt;br /&gt;
    &amp;amp;&amp;amp; cp ./builddir/mkdcdisc /opt/toolchains/dc/bin&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* The next time you create a repository &amp;amp; copy the above 2 files in it, you will get a codespace with mkdcdisc already correctly installed !&lt;br /&gt;
&lt;br /&gt;
== Example 4: Build something not from KallistiOS ==&lt;br /&gt;
All the previous examples started by forking the KallistiOS repository, but most often you&#039;ll just want to work on your own code / another Dreamcast project, so you&#039;ll work from a repository other than KallistiOS:&lt;br /&gt;
* login into [https://www.github.com github]&lt;br /&gt;
* create/go to your own repository, or fork an existing project (eg doom64-dc, ...)&lt;br /&gt;
* add at least ./devcontainer/devcontainer.json, and ./devcontainer/Dockerfile if needed&lt;br /&gt;
* create/launch your codespace&lt;br /&gt;
* follow the build instructions of that project&lt;br /&gt;
* Notes:&lt;br /&gt;
** Everything for KallistiOS should be available in the terminal, you&#039;ll find KallistiOS stuff in the folder /opt/toolchains/dc&lt;br /&gt;
** In the file-tree on the left side, you&#039;ll see the files of your repository (folder: /workspaces). If you also want to add other folders there, eg /opt/toolchains/dc, execute something like this in the terminal: code -a /opt/toolchains/dc&lt;br /&gt;
&lt;br /&gt;
== Tips ==&lt;br /&gt;
* When you&#039;re finished with your Codespace, go to &lt;br /&gt;
** the 3-bars-Menu at the top left - &amp;quot;My Codespaces&amp;quot;&lt;br /&gt;
** on the left, select the codespace you were just running&lt;br /&gt;
** click on the 3 dots next to &amp;quot;Active&amp;quot;&lt;br /&gt;
** select &amp;quot;Stop codespace&amp;quot;&lt;br /&gt;
Doing this pro-actively will save you some free minutes, since the default timeout is 30 minutes.&lt;/div&gt;</summary>
		<author><name>BBHoodsta</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=File:Screen_Shot_2024-07-14_at_8.28.13_AM.png&amp;diff=3586</id>
		<title>File:Screen Shot 2024-07-14 at 8.28.13 AM.png</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=File:Screen_Shot_2024-07-14_at_8.28.13_AM.png&amp;diff=3586"/>
		<updated>2024-07-14T15:29:30Z</updated>

		<summary type="html">&lt;p&gt;BBHoodsta: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Screenshot of Codespace button&lt;/div&gt;</summary>
		<author><name>BBHoodsta</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Building_KOS_on_MinGW-w64/MSYS2&amp;diff=3195</id>
		<title>Building KOS on MinGW-w64/MSYS2</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Building_KOS_on_MinGW-w64/MSYS2&amp;diff=3195"/>
		<updated>2023-09-19T18:41:05Z</updated>

		<summary type="html">&lt;p&gt;BBHoodsta: /* Toolchain (cross-compiler and libraries) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
This tutorial is a step-by-step guide on how to setup a toolchain and KOS environment on your Windows system.&lt;br /&gt;
&lt;br /&gt;
The toolchain consists of a C/C++ compiler (GCC), assembler and linker (binutils), and C library (newlib). As the Dreamcast has two processors - the SH4 CPU and the AICA (ARM) sound processor - the toolchain includes compilers for both.&lt;br /&gt;
&lt;br /&gt;
KOS consists of the operating system core (kos) and a set of nicely integrated libraries (kos-ports).&lt;br /&gt;
&lt;br /&gt;
Since KOS was developed for Unix-compatible systems (like Linux, BSD, etc.), a Unix-compatible development environment must be installed. The available choices are Cygwin, MSYS and MSYS2. MSYS is unmaintained and out-dated. Cygwin and MSYS2 both work, but MSYS2 seems to be maintained more actively, work better and also offers a better package management system, so it is preferred.&lt;br /&gt;
&lt;br /&gt;
==Preparations==&lt;br /&gt;
Install MSYS2 from http://repo.msys2.org/distrib/i686 (this tutorial used http://repo.msys2.org/distrib/i686/msys2-i686-20160205.exe).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Please make sure to use partition C:\&#039;&#039;. A user reported issues of git, wget, etc. not working at all when installing to partition D:\. On the MSys2 website it&#039;s mentioned that FAT filesystems don&#039;t work, so that&#039;s an alternative explanation.&lt;br /&gt;
&lt;br /&gt;
As the setup completes, it will ask whether you want to open a shell. Don&#039;t. Open &#039;&#039;C:\msys32\mingw32_shell.bat&#039;&#039; instead (mingw shell instead of msys2 shell).&lt;br /&gt;
&lt;br /&gt;
==Install script==&lt;br /&gt;
At this point, please consider trying the install script first. It will perform the remaining steps below automatically. &lt;br /&gt;
&lt;br /&gt;
Download the install script: [[File:Kos_setup_script.zip]].&lt;br /&gt;
Then change to the directory of the script and execute it (uses Unix paths instead of Windows paths, &#039;&#039;C:\&#039;&#039; becomes &#039;&#039;/c/&#039;&#039;)&lt;br /&gt;
 $ cd /c/Documents\ and\ Settings (&#039;&#039;find your Download folder here..&#039;&#039;)&lt;br /&gt;
 $ sh kos_setup.sh&lt;br /&gt;
&lt;br /&gt;
The script should perform all the remaining steps. If something goes wrong, you can try to continue the steps manually or ask for help on the forums/IRC.&lt;br /&gt;
&lt;br /&gt;
==Install required packages==&lt;br /&gt;
MSYS2 uses the &#039;&#039;pacman&#039;&#039; package manager. The following command should download all required programs.&lt;br /&gt;
&lt;br /&gt;
 $ pacman -Sy --needed mingw-w64-i686-binutils mingw-w64-i686-gcc mingw-w64-i686-pkg-config mingw-w64-i686-libpng mingw-w64-i686-libjpeg-turbo diffutils git make subversion patch python tar texinfo wget&lt;br /&gt;
&lt;br /&gt;
==Downloading KOS==&lt;br /&gt;
&lt;br /&gt;
KOS is available through a Git repository at SourceForge.&lt;br /&gt;
The standard install directory assumed in the configuration files is /opt/toolchains/dc/{kos, kos-ports}.&lt;br /&gt;
&lt;br /&gt;
 $ git clone git://git.code.sf.net/p/cadcdev/kallistios /opt/toolchains/dc/kos&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Toolchain (cross-compiler and libraries)==&lt;br /&gt;
After cloning the KOS repository, navigate to dc-chain directory:&lt;br /&gt;
&lt;br /&gt;
 $ cd /opt/toolchains/dc/kos/utils/dc-chain&lt;br /&gt;
&lt;br /&gt;
Then compile the cross-compiler and system libraries.&lt;br /&gt;
The erase=1 will delete temporary files after a successful build.&lt;br /&gt;
&lt;br /&gt;
 $ make erase=1&lt;br /&gt;
&lt;br /&gt;
After this command completes successfully you have a working cross-compiler for Dreamcast and can compile KOS next.&lt;br /&gt;
&lt;br /&gt;
==Setting up KOS==&lt;br /&gt;
&lt;br /&gt;
You should read the documentation in the kos/doc directory for details, but here are the basic steps required to set up the KOS environment:&lt;br /&gt;
&lt;br /&gt;
Go into the kos directory and copy the template configuration: &lt;br /&gt;
&lt;br /&gt;
 $ cp /opt/toolchains/dc/kos/doc/environ.sh.sample /opt/toolchains/dc/kos/environ.sh &lt;br /&gt;
&lt;br /&gt;
Now edit environ.sh to match your installation. If you use the default installation directory you don&#039;t need to change anything.&lt;br /&gt;
&lt;br /&gt;
Execute the following command to set the KOS environment variables:&lt;br /&gt;
&lt;br /&gt;
 $ source /opt/toolchains/dc/kos/environ.sh&lt;br /&gt;
&lt;br /&gt;
Remember to do this every time you want to use the KOS environment in a newly opened shell.&lt;br /&gt;
Dont&#039;t forget to run the above command again when editing environ.sh. &lt;br /&gt;
&lt;br /&gt;
Now we are finally ready to compile KOS itself. In the kos directory, run: &lt;br /&gt;
 &lt;br /&gt;
 $ cd /opt/toolchains/dc/kos &lt;br /&gt;
 $ make&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==KOS-Ports==&lt;br /&gt;
KOS-Ports is a repository with commonly used libraries for development on the DC, like PNG or MP3 loading.&lt;br /&gt;
&lt;br /&gt;
Clone the repository:&lt;br /&gt;
&lt;br /&gt;
 $ git clone git://git.code.sf.net/p/cadcdev/kos-ports /opt/toolchains/dc/kos-ports&lt;br /&gt;
&lt;br /&gt;
Compile all KOS-ports using the build-all script&lt;br /&gt;
&lt;br /&gt;
 $ sh /opt/toolchains/dc/kos-ports/utils/build-all.sh&lt;br /&gt;
&lt;br /&gt;
Now you should have a working Dreamcast development environment :-) &lt;br /&gt;
&lt;br /&gt;
Check out the examples in the KallistiOS directory to find out how to use KOS in your own projects!&lt;/div&gt;</summary>
		<author><name>BBHoodsta</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Building_KOS_on_MinGW-w64/MSYS2&amp;diff=3194</id>
		<title>Building KOS on MinGW-w64/MSYS2</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Building_KOS_on_MinGW-w64/MSYS2&amp;diff=3194"/>
		<updated>2023-09-19T18:39:20Z</updated>

		<summary type="html">&lt;p&gt;BBHoodsta: /* Toolchain (cross-compiler and libraries) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
This tutorial is a step-by-step guide on how to setup a toolchain and KOS environment on your Windows system.&lt;br /&gt;
&lt;br /&gt;
The toolchain consists of a C/C++ compiler (GCC), assembler and linker (binutils), and C library (newlib). As the Dreamcast has two processors - the SH4 CPU and the AICA (ARM) sound processor - the toolchain includes compilers for both.&lt;br /&gt;
&lt;br /&gt;
KOS consists of the operating system core (kos) and a set of nicely integrated libraries (kos-ports).&lt;br /&gt;
&lt;br /&gt;
Since KOS was developed for Unix-compatible systems (like Linux, BSD, etc.), a Unix-compatible development environment must be installed. The available choices are Cygwin, MSYS and MSYS2. MSYS is unmaintained and out-dated. Cygwin and MSYS2 both work, but MSYS2 seems to be maintained more actively, work better and also offers a better package management system, so it is preferred.&lt;br /&gt;
&lt;br /&gt;
==Preparations==&lt;br /&gt;
Install MSYS2 from http://repo.msys2.org/distrib/i686 (this tutorial used http://repo.msys2.org/distrib/i686/msys2-i686-20160205.exe).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Please make sure to use partition C:\&#039;&#039;. A user reported issues of git, wget, etc. not working at all when installing to partition D:\. On the MSys2 website it&#039;s mentioned that FAT filesystems don&#039;t work, so that&#039;s an alternative explanation.&lt;br /&gt;
&lt;br /&gt;
As the setup completes, it will ask whether you want to open a shell. Don&#039;t. Open &#039;&#039;C:\msys32\mingw32_shell.bat&#039;&#039; instead (mingw shell instead of msys2 shell).&lt;br /&gt;
&lt;br /&gt;
==Install script==&lt;br /&gt;
At this point, please consider trying the install script first. It will perform the remaining steps below automatically. &lt;br /&gt;
&lt;br /&gt;
Download the install script: [[File:Kos_setup_script.zip]].&lt;br /&gt;
Then change to the directory of the script and execute it (uses Unix paths instead of Windows paths, &#039;&#039;C:\&#039;&#039; becomes &#039;&#039;/c/&#039;&#039;)&lt;br /&gt;
 $ cd /c/Documents\ and\ Settings (&#039;&#039;find your Download folder here..&#039;&#039;)&lt;br /&gt;
 $ sh kos_setup.sh&lt;br /&gt;
&lt;br /&gt;
The script should perform all the remaining steps. If something goes wrong, you can try to continue the steps manually or ask for help on the forums/IRC.&lt;br /&gt;
&lt;br /&gt;
==Install required packages==&lt;br /&gt;
MSYS2 uses the &#039;&#039;pacman&#039;&#039; package manager. The following command should download all required programs.&lt;br /&gt;
&lt;br /&gt;
 $ pacman -Sy --needed mingw-w64-i686-binutils mingw-w64-i686-gcc mingw-w64-i686-pkg-config mingw-w64-i686-libpng mingw-w64-i686-libjpeg-turbo diffutils git make subversion patch python tar texinfo wget&lt;br /&gt;
&lt;br /&gt;
==Downloading KOS==&lt;br /&gt;
&lt;br /&gt;
KOS is available through a Git repository at SourceForge.&lt;br /&gt;
The standard install directory assumed in the configuration files is /opt/toolchains/dc/{kos, kos-ports}.&lt;br /&gt;
&lt;br /&gt;
 $ git clone git://git.code.sf.net/p/cadcdev/kallistios /opt/toolchains/dc/kos&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Toolchain (cross-compiler and libraries)==&lt;br /&gt;
After cloning the KOS repository, run the toolchain download+unpack+compile scripts:&lt;br /&gt;
&lt;br /&gt;
 $ cd /opt/toolchains/dc/kos/utils/dc-chain&lt;br /&gt;
&lt;br /&gt;
Then compile the cross-compiler and system libraries.&lt;br /&gt;
The erase=1 will delete temporary files after a successful build.&lt;br /&gt;
&lt;br /&gt;
 $ make erase=1&lt;br /&gt;
&lt;br /&gt;
After this command completes successfully you have a working cross-compiler for Dreamcast and can compile KOS next.&lt;br /&gt;
&lt;br /&gt;
==Setting up KOS==&lt;br /&gt;
&lt;br /&gt;
You should read the documentation in the kos/doc directory for details, but here are the basic steps required to set up the KOS environment:&lt;br /&gt;
&lt;br /&gt;
Go into the kos directory and copy the template configuration: &lt;br /&gt;
&lt;br /&gt;
 $ cp /opt/toolchains/dc/kos/doc/environ.sh.sample /opt/toolchains/dc/kos/environ.sh &lt;br /&gt;
&lt;br /&gt;
Now edit environ.sh to match your installation. If you use the default installation directory you don&#039;t need to change anything.&lt;br /&gt;
&lt;br /&gt;
Execute the following command to set the KOS environment variables:&lt;br /&gt;
&lt;br /&gt;
 $ source /opt/toolchains/dc/kos/environ.sh&lt;br /&gt;
&lt;br /&gt;
Remember to do this every time you want to use the KOS environment in a newly opened shell.&lt;br /&gt;
Dont&#039;t forget to run the above command again when editing environ.sh. &lt;br /&gt;
&lt;br /&gt;
Now we are finally ready to compile KOS itself. In the kos directory, run: &lt;br /&gt;
 &lt;br /&gt;
 $ cd /opt/toolchains/dc/kos &lt;br /&gt;
 $ make&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==KOS-Ports==&lt;br /&gt;
KOS-Ports is a repository with commonly used libraries for development on the DC, like PNG or MP3 loading.&lt;br /&gt;
&lt;br /&gt;
Clone the repository:&lt;br /&gt;
&lt;br /&gt;
 $ git clone git://git.code.sf.net/p/cadcdev/kos-ports /opt/toolchains/dc/kos-ports&lt;br /&gt;
&lt;br /&gt;
Compile all KOS-ports using the build-all script&lt;br /&gt;
&lt;br /&gt;
 $ sh /opt/toolchains/dc/kos-ports/utils/build-all.sh&lt;br /&gt;
&lt;br /&gt;
Now you should have a working Dreamcast development environment :-) &lt;br /&gt;
&lt;br /&gt;
Check out the examples in the KallistiOS directory to find out how to use KOS in your own projects!&lt;/div&gt;</summary>
		<author><name>BBHoodsta</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Getting_Started_with_Dreamcast_development&amp;diff=3193</id>
		<title>Getting Started with Dreamcast development</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Getting_Started_with_Dreamcast_development&amp;diff=3193"/>
		<updated>2023-09-17T15:18:02Z</updated>

		<summary type="html">&lt;p&gt;BBHoodsta: /* Configuring and compiling KOS and kos-ports */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;float:right;&amp;quot;&amp;gt;__TOC__&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===This article is actively being worked on=== &lt;br /&gt;
&#039;&#039;Work in progress - items to be added and/or edited&#039;&#039;: Setting up debug link, building and burning a CD-R, setting up a first project, setting up an IDE, etc.&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
This article will cover the entire beginning process: starting from zero to having a working dev environment with debug link (serial or IP) and self-booting CD-R. This guide will cover the process for the following platforms:&lt;br /&gt;
* &#039;&#039;&#039;Microsoft Windows 10&#039;&#039;&#039; via [https://learn.microsoft.com/en-us/windows/wsl/about Windows Subsystem for Linux]&lt;br /&gt;
** Users desiring a native Windows approach, see [[DreamSDK]] instead&lt;br /&gt;
* &#039;&#039;&#039;macOS&#039;&#039;&#039; on Intel or Apple Silicon systems with the [https://brew.sh/ Homebrew] package manager installed&lt;br /&gt;
* &#039;&#039;&#039;Linux&#039;&#039;&#039;-based systems&lt;br /&gt;
** &#039;&#039;&#039;Debian&#039;&#039;&#039;- and &#039;&#039;&#039;Ubuntu&#039;&#039;&#039;-based distributions using the default &#039;&#039;&#039;apt&#039;&#039;&#039; package manger&lt;br /&gt;
** &#039;&#039;&#039;Fedora&#039;&#039;&#039;-based distributions using the default &#039;&#039;&#039;dnf&#039;&#039;&#039; package manager&lt;br /&gt;
** &#039;&#039;&#039;Arch&#039;&#039;&#039;-based distributions using the default &#039;&#039;&#039;pacman&#039;&#039;&#039; package manager&lt;br /&gt;
** &#039;&#039;&#039;Alpine&#039;&#039;&#039;-based distributions using the default &#039;&#039;&#039;apk&#039;&#039;&#039; package manager&lt;br /&gt;
&lt;br /&gt;
===Need help?===&lt;br /&gt;
Important note: &#039;&#039;This guide aims to remain up to date and work on all of the above platforms, but keeping instructions for such a variety of platforms up-to-date can be difficult. If you run into any errors or other challenges while following this tutorial, or simply need clarification on any of the steps, feel free to ask for assistance on the [https://dcemulation.org/phpBB/viewforum.php?f=29 message board] and we would be happy to aid you and update the guide for the benefit of future readers and others in the community.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Terms===&lt;br /&gt;
Before we get started, let&#039;s define several terms:&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;toolchain&#039;&#039;&#039; is a set of programs which turns your code into an executable file for your Dreamcast console. The toolchain includes:&lt;br /&gt;
* &#039;&#039;&#039;GCC&#039;&#039;&#039;, a C/C++/Objective-C compiler (with Rust support coming soon)&lt;br /&gt;
* &#039;&#039;&#039;binutils&#039;&#039;&#039;, an assembler and linker&lt;br /&gt;
* &#039;&#039;&#039;newlib&#039;&#039;&#039;, a C library&lt;br /&gt;
* &#039;&#039;&#039;gdb&#039;&#039;&#039;, a debugger&lt;br /&gt;
The toolchain includes a compiler for the Dreamcast&#039;s main SH4 CPU, and optionally a compiler for the ARM-based AICA sound processor. Your operating system may already have versions of these programs installed to compile code for your computer, but we will need to build a &amp;quot;cross-compiler&amp;quot; for compiling specifically for the Dreamcast. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;KallistiOS&#039;&#039;&#039; or &#039;&#039;KOS&#039;&#039; is an open source development library and pseudo-operating system for the Dreamcast console. It is the best documented and most widely used development kit in the homebrew community. KallistiOS&#039;s very flexible license allows both homebrew and commercial use with no restrictions other than a requirement to include credit for its use in your project, and indeed almost all commercially sold indie Dreamcast titles use it. There are others in existence, like [[libronin]] and [[libdream]], as well as the older development kits [[Katana]] and [[Windows CE]] created by Sega and Microsoft for use in retail games, but this guide will only cover the setup and use of KallistiOS. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;kos-ports&#039;&#039;&#039; is a repository including various libraries which integrate with KallistiOS. We will download and compile these libraries as well. &lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;debug link&#039;&#039;&#039; is a generic term referring to a hardware accessory to facilitate quickly running and debugging your programs. IP-based links include the Dreamcast&#039;s &#039;&#039;&#039;[[Broadband adapter]]&#039;&#039;&#039; and &#039;&#039;&#039;[[LAN adapter]]&#039;&#039;&#039; accessories, and serial-based links include the [[Coder&#039;s cable]], which is a cable that can connect the Dreamcast&#039;s serial port to your computer via USB or serial. This guide includes instructions for setting up and using the the Broadband adapter and a USB-based coder&#039;s cable.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dc-tool&#039;&#039;&#039; and &#039;&#039;&#039;dcload&#039;&#039;&#039; are a pair of programs to facilitate using a debug link. &#039;&#039;dc-tool&#039;&#039; runs on your computer and links to a Dreamcast running &#039;&#039;dcload-ip&#039;&#039; or &#039;&#039;dcload-serial&#039;&#039;. With this setup, you can quickly load programs, read console feedback, load assets, transfer data, redirect I/O, handle exceptions, debug problems, and so forth.&lt;br /&gt;
&lt;br /&gt;
=Choosing a debug link solution=&lt;br /&gt;
If you are building the toolchain for the purpose of building existing programs from source with little to no modifications, then a debug link setup might not be necessary for you. You may simply build programs to burn directly to CD-R. However, if you are planning to actively develop for the Dreamcast, then a debug link is a critical component. While Dreamcast emulators are mature and accurate enough to play the vast majority of the system&#039;s games library without issue, many critical bugs may show up on a real Dreamcast system, but not on a Dreamcast emulator. Therefore, it is highly recommended to test on a real system as much as possible. It&#039;s also possible to load software off of a [[Serial SD card adapter]], but without an active link to a computer, debugging and stepping through programs as they execute is significantly more challenging.&lt;br /&gt;
&lt;br /&gt;
Presented below is a table comparing the different options available for a debug link. Due to the cost, potential buyers may want to factor in the ability to play multiplayer games with their purchase. Thus, for comparison, we have included information about the [[Modem]] with [[DreamPi]] as well, but understand that the Modem with DreamPi cannot be used as a debug link.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;6&amp;quot; |Comparison of various Dreamcast connectivity options&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#c0c0c0;&amp;quot; width=&amp;quot;150&amp;quot; | Device: &lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; width=&amp;quot;400&amp;quot; | [[Broadband adapter]] (HIT-400 or HIT-401) &amp;lt;br /&amp;gt;Realtek RTL8139C chipset&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; width=&amp;quot;400&amp;quot; | [[LAN adapter]] (HIT-300) &amp;lt;br /&amp;gt;Fujitsu MB86967 chipset&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; width=&amp;quot;400&amp;quot; | [[Modem]] with [[DreamPi]]&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; width=&amp;quot;400&amp;quot; | USB [[Coder&#039;s cable]]&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; width=&amp;quot;400&amp;quot; | Serial [[Coder&#039;s cable]]&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; | Useful for dev? || Yes, supports dcload-ip || Yes, supports dcload-ip,&amp;lt;br/&amp;gt;but BBA is superior and cheaper || No, only useful for online multiplayer gaming || Yes, supports dcload-serial || Yes, supports dcload-serial&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; | Cost || $100 - $200 and up on used markets || $200 and up on used markets,&amp;lt;br/&amp;gt;due to extreme rarity || Kit prices vary, around $100 || Varies on used markets, uncommonly sold&amp;lt;br /&amp;gt;RetroOnyx sells for $85 || Varies on used markets, uncommonly sold&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; | Can make DIY? || No || No || Yes || Yes || Yes&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; | Performance || Up to 100 megabits/s || Up to 10 megabits/s || Up to 56 kilobits/s || Up to 1500 kilobits/s || Up to 120 kilobits/s&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; | Games support || Some games: Phantasy Star Online, Quake III Arena, Toy Racer, POD SpeedZone, Propellor Arena, Unreal Tournament&amp;lt;br /&amp;gt;Some browsers: Broadband Passport, PlanetWeb 3.0 || No games&amp;lt;br /&amp;gt;One browser: Dream Passport for LAN || All multiplayer games with network support&amp;lt;br /&amp;gt;All web browsers || NO multiplayer games support || NO multiplayer games support &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; | Homebrew support || Homebrew utilities like dcload-ip || Homebrew utilities like dcload-ip || Homebrew utilities don&#039;t support, only multiplayer games || Homebrew utilities like dcload-serial || Homebrew utilities like dcload-serial &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Setting up and compiling the toolchain with the dc-chain script=&lt;br /&gt;
===Dependencies===&lt;br /&gt;
First, we&#039;ll need to install dependencies before building the toolchain. Below we have provided commands to install these dependencies on various systems. Many of the packages will likely already be installed on your system, but we have provided an exhaustive list for good measure.&lt;br /&gt;
====macOS 13 Ventura on an Intel or Apple Silicon processor====&lt;br /&gt;
First, make sure you install Apple Xcode, including the Command Line tools. You will also need to install several other packages for which we&#039;ll include instructions assuming you have installed the [https://brew.sh/ Homebrew] package manager on your system.&lt;br /&gt;
 brew install wget gettext texinfo gmp mpfr libmpc libelf jpeg-turbo libpng meson libisofs&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Important Note for Apple Silicon users&#039;&#039;: On Apple Silicon, Homebrew installs libraries to a path not included by default by the compiler. If you haven&#039;t added these to your &#039;&#039;&#039;~/.zprofile&#039;&#039;&#039;, then add the following lines now and reload your session (or run them in your Terminal session whenever you compile KOS):&lt;br /&gt;
 export CPATH=/opt/homebrew/include&lt;br /&gt;
 export LIBRARY_PATH=/opt/homebrew/lib&lt;br /&gt;
&lt;br /&gt;
====Debian/Ubuntu-based Linux====&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt install gawk patch bzip2 tar make libgmp-dev libmpfr-dev libmpc-dev gettext wget libelf-dev texinfo bison flex sed git build-essential diffutils curl libjpeg-dev libpng-dev python3 pkg-config libisofs-dev meson ninja-build&lt;br /&gt;
&lt;br /&gt;
====Fedora-based Linux====&lt;br /&gt;
 sudo dnf install gawk patch bzip2 tar make gmp-devel mpfr-devel libmpc-devel gettext wget elfutils-libelf-devel texinfo bison flex sed git diffutils curl libjpeg-turbo-devel libpng-devel gcc-c++ python3 meson ninja-build&lt;br /&gt;
&lt;br /&gt;
====Arch-based Linux====&lt;br /&gt;
 sudo pacman -S --needed gawk patch bzip2 tar make gmp mpfr libmpc gettext wget libelf texinfo bison flex sed git diffutils curl libjpeg-turbo libpng python3 meson&lt;br /&gt;
&lt;br /&gt;
====Alpine-based Linux====&lt;br /&gt;
 sudo apk --update add build-base patch bash texinfo gmp-dev libjpeg-turbo-dev libpng-dev elfutils-dev curl wget python3 git&lt;br /&gt;
&lt;br /&gt;
====Other Linux distributions====&lt;br /&gt;
If you&#039;re using a different Linux- or Unix-based system besides the one above, you may need to reference your distribution&#039;s package database and package manager documentation for the equivalent package names and commands necessary for your system.&lt;br /&gt;
&lt;br /&gt;
===Creating a space for your toolchain installation===&lt;br /&gt;
Create the path where we&#039;ll install the toolchain and KOS, and grant it the proper permissions:&lt;br /&gt;
 sudo mkdir -p /opt/toolchains/dc&lt;br /&gt;
 sudo chmod -R 755 /opt/toolchains/dc&lt;br /&gt;
 sudo chown -R $(id -u):$(id -g) /opt/toolchains/dc&lt;br /&gt;
===Cloning the KOS git repository===&lt;br /&gt;
Clone the KOS git repository to your system:&lt;br /&gt;
 git clone https://github.com/KallistiOS/KallistiOS.git /opt/toolchains/dc/kos&lt;br /&gt;
&lt;br /&gt;
===Configuring the dc-chain script===&lt;br /&gt;
Enter the dc-chain directory:&lt;br /&gt;
 cd /opt/toolchains/dc/kos/utils/dc-chain&lt;br /&gt;
&lt;br /&gt;
We will choose the default &#039;&#039;&#039;stable&#039;&#039;&#039; configuration for the toolchain, which currently uses GCC 13.2. For advanced users, other configurations are available to you; read the &amp;lt;code&amp;gt;README.md&amp;lt;/code&amp;gt; file in the dc-chain directory for more information if you are interested.&lt;br /&gt;
 cp config/config.mk.stable.sample config.mk&lt;br /&gt;
&lt;br /&gt;
Now, you may configure config.mk options to your liking by using a text editor. You may alter the &amp;lt;code&amp;gt;makeopts&amp;lt;/code&amp;gt; parameter to the number of threads available on your CPU to speed up the compilation, if desired. However, if you run into errors during compilation, you may want to set &amp;lt;code&amp;gt;makeopts=-j1&amp;lt;/code&amp;gt;, as on some operating systems the toolchain may fail to build with a higher setting.&lt;br /&gt;
&lt;br /&gt;
===Downloading and compiling the toolchain===&lt;br /&gt;
Now we will run a script to download files and compile the toolchain. At this point, we have the option of building both the main CPU SH4 compiler and the AICA sound processor ARM compiler, or we can skip the ARM compiler and just build the SH4 compiler. Thankfully, KallistiOS includes a prebuilt sound driver, so the ARM compiler is only necessary if you&#039;re wanting to make changes to the sound driver or write custom code to run on the sound processor.&lt;br /&gt;
To build &#039;&#039;&#039;only the SH4 compiler&#039;&#039;&#039;:&lt;br /&gt;
 make build-sh4&lt;br /&gt;
To build &#039;&#039;&#039;both&#039;&#039;&#039; the SH4 and the ARM compilers:&lt;br /&gt;
 make&lt;br /&gt;
This will download and unpack the relevant necessary files and then begin the compilation process. The compilation can take anywhere from minutes to a few hours depending on your CPU and number of threads available. When successfully finished, the toolchains will be ready.&lt;br /&gt;
&lt;br /&gt;
Afterwards, if desired, you may also compile the GNU Debugger (gdb) as well:&lt;br /&gt;
 make gdb&lt;br /&gt;
&lt;br /&gt;
The GNU Debugger is now installed along with your toolchains.&lt;br /&gt;
&lt;br /&gt;
===Cleaning up temporary files===&lt;br /&gt;
After building everything, you can clean up the extraneous files in your dc-chain directory by entering:&lt;br /&gt;
 make clean&lt;br /&gt;
&lt;br /&gt;
=Configuring and compiling KOS and kos-ports=&lt;br /&gt;
===Setting up the environment settings===&lt;br /&gt;
Enter the KOS directory:&lt;br /&gt;
 cd /opt/toolchains/dc/kos&lt;br /&gt;
Copy the pre-made environment script into place:&lt;br /&gt;
 cp doc/environ.sh.sample environ.sh &lt;br /&gt;
For most users, the default settings will suffice. However, advanced users may edit the environ.sh to your liking if you&#039;d like to change compile flags or alter paths. If you&#039;d like to have multiple KOS versions installed or multiple toolchain versions installed, you can set up different environ.sh files corresponding to these different configurations by altering the paths. Run the source command on the desired environ.sh file to select that configuration prior to compiling your project. &lt;br /&gt;
&lt;br /&gt;
You will need to run the source command to apply the KOS environment settings to your currently running shell. Run the following now, &#039;&#039;&#039;and&#039;&#039;&#039; &#039;&#039;whenever&#039;&#039; you open a new shell to work on Dreamcast projects:&lt;br /&gt;
 source /opt/toolchains/dc/kos/environ.sh&lt;br /&gt;
&lt;br /&gt;
===Building KOS===&lt;br /&gt;
Build KOS:&lt;br /&gt;
 make&lt;br /&gt;
KOS is now built.&lt;br /&gt;
===Building kos-ports===&lt;br /&gt;
Clone the kos-ports repository to your system:&lt;br /&gt;
 git clone --recursive https://github.com/KallistiOS/kos-ports /opt/toolchains/dc/kos-ports&lt;br /&gt;
Run the script to build all of the included ports:&lt;br /&gt;
 /opt/toolchains/dc/kos-ports/utils/build-all.sh&lt;br /&gt;
kos-ports is now built.&lt;br /&gt;
&lt;br /&gt;
===Building the KOS examples===&lt;br /&gt;
Enter the KOS examples directory:&lt;br /&gt;
 cd /opt/toolchains/dc/kos/examples/dreamcast&lt;br /&gt;
Build the examples:&lt;br /&gt;
 make&lt;br /&gt;
All of the example programs provided with KallistiOS are now built.&lt;br /&gt;
&lt;br /&gt;
=Running an example program through a debug link=&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: &#039;&#039;Give a tutorial on compiling dcload/dc-tool, setting up a serial, USB, or IP debug link, and running 2ndmix demo on real hardware.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Download and burn the [[:File:Dcload-2023-06-22.zip|latest versions of dcload-ip or dcload-serial]] -- the IP version includes improved DHCP support, so there is no longer a need to configure things beforehand. &lt;br /&gt;
 &lt;br /&gt;
Run one of the examples from the &amp;lt;code&amp;gt;kos/examples/dreamcast&amp;lt;/code&amp;gt; directory with the following command:&lt;br /&gt;
 dc-tool-ip -t &amp;lt;dreamcast IP address&amp;gt; -x example.elf&lt;br /&gt;
Run &amp;lt;code&amp;gt;dc-tool-ip&amp;lt;/code&amp;gt; without any parameters to get additional options.&lt;br /&gt;
&lt;br /&gt;
=Burning an example program to CD-R=&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: &#039;&#039;Explain how to build mkdcdisc and write 2ndmix demo to CD-R and run on a Dreamcast console&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[https://gitlab.com/simulant/mkdcdisc mkdcdisc] can be used to easily generate a burnable self-boot CDI image.&lt;br /&gt;
Build &amp;lt;code&amp;gt;mkdcdisc&amp;lt;/code&amp;gt;:&lt;br /&gt;
 git clone https://gitlab.com/simulant/mkdcdisc.git&lt;br /&gt;
 cd mkdcdisc&lt;br /&gt;
 meson setup builddir&lt;br /&gt;
 meson compile -C builddir&lt;br /&gt;
 ./builddir/mkdcdisc -h&lt;br /&gt;
and create a CDI image from your compiled ELF like so:&lt;br /&gt;
 mkdcdisc -e MyProgram.elf -o MyProgram.cdi&lt;br /&gt;
Then you can burn the CDI file using DiscJuggler (Windows-only, but also works through [https://www.winehq.org/ WINE]), ImgBurn with the CDI plugin, or the cdiburn *nix script floating around out there. (document this better)&lt;br /&gt;
&lt;br /&gt;
=Creating your first project=&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: &#039;&#039;Explain how to create a new DC project folder with Makefile, adding an external library, create a basic program, and compile it&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
=Further reading=&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: Links to articles for using gdb, integrating the dev setup with an IDE, etc.&lt;br /&gt;
&lt;br /&gt;
e.g.&lt;br /&gt;
* [[Qt Creator Dreamcast Development Environment]]&lt;br /&gt;
* [[CLion Debugging]]&lt;br /&gt;
* [[Visual Studio Code]]&lt;/div&gt;</summary>
		<author><name>BBHoodsta</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Development&amp;diff=3186</id>
		<title>Development</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Development&amp;diff=3186"/>
		<updated>2023-09-06T14:10:41Z</updated>

		<summary type="html">&lt;p&gt;BBHoodsta: /* General */&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;
&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;
&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]]&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;
* [[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;
* [[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>BBHoodsta</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Development&amp;diff=3185</id>
		<title>Development</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Development&amp;diff=3185"/>
		<updated>2023-09-06T14:10:30Z</updated>

		<summary type="html">&lt;p&gt;BBHoodsta: /* General */&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;
&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;
&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]]&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;
* [[Store Queues]]&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>BBHoodsta</name></author>
	</entry>
	<entry>
		<id>https://dreamcast.wiki/wiki/index.php?title=Getting_Started_with_Dreamcast_development&amp;diff=3079</id>
		<title>Getting Started with Dreamcast development</title>
		<link rel="alternate" type="text/html" href="https://dreamcast.wiki/wiki/index.php?title=Getting_Started_with_Dreamcast_development&amp;diff=3079"/>
		<updated>2023-06-07T11:50:06Z</updated>

		<summary type="html">&lt;p&gt;BBHoodsta: /* Cleaning up temporary files */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;float:right;&amp;quot;&amp;gt;__TOC__&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===This article is actively being worked on=== &lt;br /&gt;
&#039;&#039;Work in progress - items to be added and/or edited&#039;&#039;: Setting up debug link, building and burning a CD-R, setting up a first project, setting up an IDE, etc.&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
This article will cover the entire beginning process: starting from zero to having a working dev environment with debug link (serial or IP) and self-booting CD-R. This guide will cover the process for the following platforms:&lt;br /&gt;
* Microsoft Windows 10 via [https://learn.microsoft.com/en-us/windows/wsl/about Windows Subsystem for Linux]&lt;br /&gt;
* macOS on Intel or Apple Silicon systems with the [https://brew.sh/ Homebrew] package manager installed&lt;br /&gt;
* Debian- and Ubuntu-based Linux distributions using the default apt package manager&lt;br /&gt;
* Fedora-based Linux distributions using the default dnf package manager&lt;br /&gt;
* Arch-based Linux distributions using the default pacman package manager&lt;br /&gt;
&lt;br /&gt;
===Need help?===&lt;br /&gt;
Important note: &#039;&#039;This guide aims to remain up to date and work on all of the above platforms, but keeping instructions for such a variety of platforms up-to-date can be difficult. If you run into any errors or other challenges while following this tutorial, or simply need clarification on any of the steps, feel free to ask for assistance on the [https://dcemulation.org/phpBB/viewforum.php?f=29 message board] and we would be happy to aid you and update the guide for the benefit of future readers and others in the community.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Terms===&lt;br /&gt;
Before we get started, let&#039;s define several terms:&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;toolchain&#039;&#039;&#039; is a set of programs which turns your code into an executable file for your Dreamcast console. The toolchain includes:&lt;br /&gt;
* &#039;&#039;&#039;GCC&#039;&#039;&#039;, a C/C++/Objective-C compiler&lt;br /&gt;
* &#039;&#039;&#039;binutils&#039;&#039;&#039;, an assembler and linker&lt;br /&gt;
* &#039;&#039;&#039;newlib&#039;&#039;&#039;, a C library&lt;br /&gt;
* &#039;&#039;&#039;gdb&#039;&#039;&#039;, a debugger&lt;br /&gt;
The toolchain includes a compiler for the Dreamcast&#039;s main SH4 CPU, and optionally a compiler for the ARM-based AICA sound processor. Your operating system may already have versions of these programs installed to compile code for your computer, but we will need to build a &amp;quot;cross-compiler&amp;quot; for compiling specifically for the Dreamcast. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;KallistiOS&#039;&#039;&#039; or &#039;&#039;KOS&#039;&#039; is an open source development library and pseudo-operating system for the Dreamcast console. It is the best documented and most widely used development kit in the homebrew community. KallistiOS&#039;s very flexible license allows both homebrew and commercial use with no restrictions other than a requirement to include credit for its use in your project, and indeed almost all commercially sold indie Dreamcast titles use it. There are others in existence, like [[libronin]] and [[libdream]], as well as the older development kits [[Katana]] and [[Windows CE]] created by Sega and Microsoft for use in retail games, but this guide will only cover the setup and use of KallistiOS. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;kos-ports&#039;&#039;&#039; is a repository including various libraries which integrate with KallistiOS. We will download and compile these libraries as well. &lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;debug link&#039;&#039;&#039; is a generic term referring to a hardware accessory to facilitate quickly running and debugging your programs. IP-based links include the Dreamcast&#039;s &#039;&#039;&#039;[[Broadband adapter]]&#039;&#039;&#039; and &#039;&#039;&#039;[[LAN adapter]]&#039;&#039;&#039; accessories, and serial-based links include the [[Coder&#039;s cable]], which is a cable that can connect the Dreamcast&#039;s serial port to your computer via USB or serial. This guide includes instructions for setting up and using the the Broadband adapter and a USB-based coder&#039;s cable.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dc-tool&#039;&#039;&#039; and &#039;&#039;&#039;dcload&#039;&#039;&#039; are a pair of programs to facilitate using a debug link. &#039;&#039;dc-tool&#039;&#039; runs on your computer and links to a Dreamcast running &#039;&#039;dcload-ip&#039;&#039; or &#039;&#039;dcload-serial&#039;&#039;. With this setup, you can quickly load programs, read console feedback, load assets, transfer data, redirect I/O, handle exceptions, debug problems, and so forth.&lt;br /&gt;
&lt;br /&gt;
=Choosing a debug link solution=&lt;br /&gt;
If you are building the toolchain for the purpose of building existing programs from source with little to no modifications, then a debug link setup might not be necessary for you. You may simply build programs to burn directly to CD-R. However, if you are planning to actively develop for the Dreamcast, then a debug link is a critical component. While Dreamcast emulators are mature and accurate enough to play the vast majority of the system&#039;s games library without issue, many critical bugs may show up on a real Dreamcast system, but not on a Dreamcast emulator. Therefore, it is highly recommended to test on a real system as much as possible. It&#039;s also possible to load software off of a [[Serial SD card adapter]], but without an active link to a computer, debugging and stepping through programs as they execute is significantly more challenging.&lt;br /&gt;
&lt;br /&gt;
Presented below is a table comparing the different options available for a debug link. Due to the cost, potential buyers may want to factor in the ability to play multiplayer games with their purchase. Thus, for comparison, we have included information about the [[Modem]] with [[DreamPi]] as well, but understand that the Modem with DreamPi cannot be used as a debug link.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!colspan=&amp;quot;6&amp;quot; |Comparison of various Dreamcast connectivity options&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#c0c0c0;&amp;quot; width=&amp;quot;150&amp;quot; | Device: &lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; width=&amp;quot;400&amp;quot; | [[Broadband adapter]] (HIT-400 or HIT-401) &amp;lt;br /&amp;gt;Realtek RTL8139C chipset&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; width=&amp;quot;400&amp;quot; | [[LAN adapter]] (HIT-300) &amp;lt;br /&amp;gt;Fujitsu MB86967 chipset&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; width=&amp;quot;400&amp;quot; | [[Modem]] with [[DreamPi]]&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; width=&amp;quot;400&amp;quot; | USB [[Coder&#039;s cable]]&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; width=&amp;quot;400&amp;quot; | Serial [[Coder&#039;s cable]]&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; | Useful for dev? || Yes, supports dcload-ip || Yes, supports dcload-ip,&amp;lt;br/&amp;gt;but BBA is superior and cheaper || No, only useful for online multiplayer gaming || Yes, supports dcload-serial || Yes, supports dcload-serial&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; | Cost || $100 - $200 and up on used markets || $200 and up on used markets,&amp;lt;br/&amp;gt;due to extreme rarity || Kit prices vary, around $100 || Varies on used markets, uncommonly sold&amp;lt;br /&amp;gt;RetroOnyx sells for $85 || Varies on used markets, uncommonly sold&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; | Can make DIY? || No || No || Yes || Yes || Yes&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; | Performance || Up to 100 megabits/s || Up to 10 megabits/s || Up to 56 kilobits/s || Up to 1500 kilobits/s || Up to 120 kilobits/s&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; | Games support || Some games: Phantasy Star Online, Quake III Arena, Toy Racer, POD SpeedZone, Propellor Arena, Unreal Tournament&amp;lt;br /&amp;gt;Some browsers: Broadband Passport, PlanetWeb 3.0 || No games&amp;lt;br /&amp;gt;One browser: Dream Passport for LAN || All multiplayer games with network support&amp;lt;br /&amp;gt;All web browsers || NO multiplayer games support || NO multiplayer games support &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#d0d0d0;&amp;quot; | Homebrew support || Homebrew utilities like dcload-ip || Homebrew utilities like dcload-ip || Homebrew utilities don&#039;t support, only multiplayer games || Homebrew utilities like dcload-serial || Homebrew utilities like dcload-serial &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Setting up and compiling the toolchain with the dc-chain script=&lt;br /&gt;
===Dependencies===&lt;br /&gt;
First, we&#039;ll need to install dependencies before building the toolchain. Below we have provided commands to install these dependencies on various systems. Many of the packages will likely already be installed on your system, but we have provided an exhaustive list for good measure.&lt;br /&gt;
====macOS 13 Ventura on an Intel or Apple Silicon processor====&lt;br /&gt;
First, make sure you install Apple Xcode, including the Command Line tools. You will also need to install several other packages for which we&#039;ll include instructions assuming you have installed the [https://brew.sh/ Homebrew] package manager on your system.&lt;br /&gt;
 brew install wget gettext texinfo gmp mpfr libmpc libelf jpeg-turbo libpng meson libisofs&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Important Note for Apple Silicon users&#039;&#039;: On Apple Silicon, Homebrew installs libraries to a path not included by default by the compiler. If you haven&#039;t added these to your &#039;&#039;&#039;~/.zprofile&#039;&#039;&#039;, then add the following lines now and reload your session (or run them in your Terminal session whenever you compile KOS):&lt;br /&gt;
 export CPATH=/opt/homebrew/include&lt;br /&gt;
 export LIBRARY_PATH=/opt/homebrew/lib&lt;br /&gt;
&lt;br /&gt;
====Debian/Ubuntu-based Linux====&lt;br /&gt;
 sudo apt install gawk patch bzip2 tar make libgmp-dev libmpfr-dev libmpc-dev gettext wget libelf-dev texinfo bison flex sed git build-essential diffutils curl libjpeg-dev libpng-dev python3 pkg-config libisofs-dev meson ninja-build&lt;br /&gt;
&lt;br /&gt;
====Fedora-based Linux====&lt;br /&gt;
 sudo dnf install gawk patch bzip2 tar make gmp-devel mpfr-devel libmpc-devel gettext wget elfutils-libelf-devel texinfo bison flex sed git diffutils curl libjpeg-turbo-devel libpng-devel gcc-c++ python3 meson ninja-build&lt;br /&gt;
&lt;br /&gt;
====Arch-based Linux====&lt;br /&gt;
 sudo pacman -S --needed gawk patch bzip2 tar make gmp mpfr libmpc gettext wget libelf texinfo bison flex sed git diffutils curl libjpeg-turbo libpng python3 meson&lt;br /&gt;
&lt;br /&gt;
====Other Linux distributions====&lt;br /&gt;
If you&#039;re using a different Linux- or Unix-based system besides the one above, you may need to reference your distribution&#039;s package database and package manager documentation for the equivalent package names and commands necessary for your system.&lt;br /&gt;
&lt;br /&gt;
===Creating a space for your toolchain installation===&lt;br /&gt;
Create the path where we&#039;ll install the toolchain and KOS, and grant it the proper permissions:&lt;br /&gt;
 sudo mkdir -p /opt/toolchains/dc&lt;br /&gt;
 sudo chmod -R 755 /opt/toolchains/dc&lt;br /&gt;
 sudo chown -R $(id -u):$(id -g) /opt/toolchains/dc&lt;br /&gt;
===Cloning the KOS git repository===&lt;br /&gt;
Clone the KOS git repository to your system:&lt;br /&gt;
 git clone https://github.com/KallistiOS/KallistiOS.git /opt/toolchains/dc/kos&lt;br /&gt;
&lt;br /&gt;
===Configuring the dc-chain script===&lt;br /&gt;
Enter the dc-chain directory:&lt;br /&gt;
 cd /opt/toolchains/dc/kos/utils/dc-chain&lt;br /&gt;
You&#039;ll need to choose one of the following pre-made toolchain configurations. The &#039;&#039;&#039;testing&#039;&#039;&#039; version uses GCC 13.1.0 with Newlib 4.3.0, the &#039;&#039;&#039;stable&#039;&#039;&#039; version uses GCC 9.3.0 and Newlib 3.3.0, and the &#039;&#039;&#039;legacy&#039;&#039;&#039; version uses GCC 4.7.4 and Newlib 2.2.0. &lt;br /&gt;
We suggest trying to use the &#039;&#039;testing&#039;&#039; or &#039;&#039;stable&#039;&#039; version. The latest version has more features, while the stable version has long been used by the community and is known to work well. Run one of the following commands to make your choice:&lt;br /&gt;
 &#039;&#039;&#039;(for GCC 13.1):&#039;&#039;&#039; mv config.mk.testing.sample config.mk &lt;br /&gt;
 &#039;&#039;&#039;(for GCC 9.3):&#039;&#039;&#039;  mv config.mk.stable.sample config.mk &lt;br /&gt;
 &#039;&#039;&#039;(for GCC 4.7):&#039;&#039;&#039;  mv config.mk.legacy.sample config.mk &lt;br /&gt;
Now, you may configure config.mk options to your liking by using a text editor. You may alter the &amp;lt;code&amp;gt;makeopts&amp;lt;/code&amp;gt; parameter to the number of threads available on your CPU to speed up the compilation, if desired. However, if you run into errors during compilation, you may want to set &amp;lt;code&amp;gt;makeopts=-j1&amp;lt;/code&amp;gt;, as on some operating systems the toolchain may fail to build with a higher setting.&lt;br /&gt;
&lt;br /&gt;
===Downloading and compiling the toolchain===&lt;br /&gt;
Now we will run a script to download files and compile the toolchain. At this point, we have the option of building both the main CPU SH4 compiler and the AICA sound processor ARM compiler, or we can skip the ARM compiler and just build the SH4 compiler. Thankfully, KallistiOS includes a prebuilt sound driver, so the ARM compiler is only necessary if you&#039;re wanting to make changes to the sound driver or write custom code to run on the sound processor.&lt;br /&gt;
To build &#039;&#039;&#039;only the SH4 compiler&#039;&#039;&#039;:&lt;br /&gt;
 make build-sh4&lt;br /&gt;
To build &#039;&#039;&#039;both&#039;&#039;&#039; the SH4 and the ARM compilers:&lt;br /&gt;
 make&lt;br /&gt;
This will download and unpack the relevant necessary files and then begin the compilation process. The compilation can take anywhere from minutes to a few hours depending on your CPU and number of threads available. When successfully finished, the toolchains will be ready.&lt;br /&gt;
&lt;br /&gt;
Afterwards, if desired, you may also compile the GNU Debugger (gdb) as well:&lt;br /&gt;
 make gdb&lt;br /&gt;
&lt;br /&gt;
The GNU Debugger is now installed along with your toolchains.&lt;br /&gt;
&lt;br /&gt;
===Cleaning up temporary files===&lt;br /&gt;
After building everything, you can clean up the extraneous files in your dc-chain directory by entering:&lt;br /&gt;
 make clean&lt;br /&gt;
&lt;br /&gt;
=Configuring and compiling KOS and kos-ports=&lt;br /&gt;
===Setting up the environment settings===&lt;br /&gt;
Enter the KOS directory:&lt;br /&gt;
 cd /opt/toolchains/dc/kos&lt;br /&gt;
Copy the pre-made environment script into place:&lt;br /&gt;
 cp doc/environ.sh.sample environ.sh &lt;br /&gt;
For most users, the default settings will suffice. However, advanced users may the environ.sh to your liking if you&#039;d like to change compile flags or alter paths. If you&#039;d like to have multiple KOS versions installed or multiple toolchain versions installed, you can set up different environ.sh files corresponding to these different configurations by altering the paths. Run the source command on the desired environ.sh file to select that configuration prior to compiling your project. &lt;br /&gt;
&lt;br /&gt;
You will need to run the source command to apply the KOS environment settings to your currently running shell. Run the following now, &#039;&#039;&#039;and&#039;&#039;&#039; &#039;&#039;whenever&#039;&#039; you open a new shell to work on Dreamcast projects:&lt;br /&gt;
 source /opt/toolchains/dc/kos/environ.sh&lt;br /&gt;
&lt;br /&gt;
===Building KOS===&lt;br /&gt;
Build KOS:&lt;br /&gt;
 make&lt;br /&gt;
KOS is now built.&lt;br /&gt;
===Building kos-ports===&lt;br /&gt;
Clone the kos-ports repository to your system:&lt;br /&gt;
 git clone --recursive https://github.com/KallistiOS/kos-ports /opt/toolchains/dc/kos-ports&lt;br /&gt;
Run the script to build all of the included ports:&lt;br /&gt;
 /opt/toolchains/dc/kos-ports/utils/build-all.sh&lt;br /&gt;
kos-ports is now built.&lt;br /&gt;
&lt;br /&gt;
===Building the KOS examples===&lt;br /&gt;
Enter the KOS examples directory:&lt;br /&gt;
 cd /opt/toolchains/dc/kos/examples/dreamcast&lt;br /&gt;
Build the examples:&lt;br /&gt;
 make&lt;br /&gt;
All of the example programs provided with KallistiOS are now built.&lt;br /&gt;
&lt;br /&gt;
=Running an example program through a debug link=&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: &#039;&#039;Give a tutorial on compiling dcload/dc-tool, setting up a serial, USB, or IP debug link, and running 2ndmix demo on real hardware.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Download and burn the [[:File:Dcload-2022-12-17.zip|latest versions of dcload-ip or dcload-serial]] -- the IP version includes improved DHCP support, so there is no longer a need to configure things beforehand. &lt;br /&gt;
 &lt;br /&gt;
Run one of the examples from the &amp;lt;code&amp;gt;kos/examples/dreamcast&amp;lt;/code&amp;gt; directory with the following command:&lt;br /&gt;
 dc-tool-ip -t &amp;lt;dreamcast IP address&amp;gt; -x example.elf&lt;br /&gt;
Run &amp;lt;code&amp;gt;dc-tool-ip&amp;lt;/code&amp;gt; without any parameters to get additional options.&lt;br /&gt;
&lt;br /&gt;
=Burning an example program to CD-R=&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: &#039;&#039;Explain how to build mkdcdisc and write 2ndmix demo to CD-R and run on a Dreamcast console&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[https://gitlab.com/simulant/mkdcdisc mkdcdisc] can be used to easily generate a burnable self-boot CDI image.&lt;br /&gt;
Build &amp;lt;code&amp;gt;mkdcdisc&amp;lt;/code&amp;gt;:&lt;br /&gt;
 git clone https://gitlab.com/simulant/mkdcdisc.git&lt;br /&gt;
 cd mkdcdisc&lt;br /&gt;
 meson setup builddir&lt;br /&gt;
 meson compile -C builddir&lt;br /&gt;
 ./builddir/mkdcdisc -h&lt;br /&gt;
and create a CDI image from your compiled ELF like so:&lt;br /&gt;
 mkdcdisc -e MyProgram.elf -o MyProgram.cdi&lt;br /&gt;
Then you can burn the CDI file using DiscJuggler (Windows-only, but also works through [https://www.winehq.org/ WINE]), ImgBurn with the CDI plugin, or the cdiburn *nix script floating around out there. (document this better)&lt;br /&gt;
&lt;br /&gt;
=Creating your first project=&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: &#039;&#039;Explain how to create a new DC project folder with Makefile, adding an external library, create a basic program, and compile it&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
=Further reading=&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: Links to articles for using gdb, integrating the dev setup with an IDE, etc.&lt;/div&gt;</summary>
		<author><name>BBHoodsta</name></author>
	</entry>
</feed>