<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title>Articles tagged c at The Segfault Garden</title>
  <link rel="alternate" type="text/html"
        href="https://blog.segv.page/tags/c/"/>
  <link rel="self" type="application/atom+xml"
        href="https://blog.segv.page/tags/c/feed/"/>
  <updated>2026-06-05T17:18:02Z</updated>
  <id>urn:uuid:0ba7b921-5597-4fbc-8ceb-88afb378c637</id>

  <author>
    <name>Luna</name>
    <uri>https://blog.segv.page</uri>
    <email>frgmntedflower@linux.com</email>
  </author>

  
    
  
    
  <entry>
    <title>wad: Building an ELF Packer — Coming Soon</title>
    <link rel="alternate" type="text/html" href="https://blog.segv.page/blog/2026/05/15/wad-elf-packer/"/>
    <id>urn:uuid:2b4c9d7e-8f6a-4e31-90b2-d1c5a7e3f60b</id>
    <updated>2026-05-15T14:00:00Z</updated>
    <category term="c"/><category term="assembly"/><category term="linux"/><category term="security"/>
    <content type="html">
      <![CDATA[<p>Working on a deep dive into building <code class="language-plaintext highlighter-rouge">wad</code> — an ELF packer from scratch.</p>

<p>The write-up will cover ELF segment parsing, position-independent assembly
stubs, embedded encryption, and the whole pack/unpack flow. No libc, no
dependencies, no nonsense.</p>

<p>Coming once the stubs are solid and I’ve shaken out the edge cases.</p>
]]>
    </content>
  </entry>
    
  
    
  
    
  
    
  
    
  <entry>
    <title>gb-emu: Building a Game Boy CPU Emulator</title>
    <link rel="alternate" type="text/html" href="https://blog.segv.page/blog/2024/12/27/gb-emu-building-a-game-boy-cpu-emulator/"/>
    <id>urn:uuid:72f8d1c4-9e6b-4a0d-b573-8c1f5a2e7d90</id>
    <updated>2024-12-27T23:15:10Z</updated>
    <category term="c"/><category term="emulation"/>
    <content type="html">
      <![CDATA[<p>gb-emu is an emulator for the original Game Boy that implements the
LR35902 CPU and memory bus but stops short of the PPU. The PPU is the
hardest component in the system — everyone gets stuck there — and I wanted
to write up what <em>did</em> work rather than waiting until the whole thing is
finished. A working CPU with a cycle-accurate memory bus is already enough
to load, decode, and step through commercial ROMs up to the point they
start asking for video memory.</p>

<h2 id="the-lr35902-instruction-set">The LR35902 Instruction Set</h2>

<p>The LR35902 is a hybrid of the Intel 8080 and the Z80, with a slightly
different register file and a unique instruction encoding. The key
differences from a Z80:</p>

<ul>
  <li>No <code class="language-plaintext highlighter-rouge">IX</code>, <code class="language-plaintext highlighter-rouge">IY</code> index registers; instead we have the standard AF/BC/DE/HL
set plus a 16-bit stack pointer SP and program counter PC.</li>
  <li>The <code class="language-plaintext highlighter-rouge">LD</code> family covers most data movement; <code class="language-plaintext highlighter-rouge">LDH</code> is a fast 8-bit port load.</li>
  <li>Interrupt handling uses the IE/IF registers at 0xFFFF/0xFF0F.</li>
</ul>

<p>The instruction decoder is a giant switch over the first opcode byte, with
a second switch for <code class="language-plaintext highlighter-rouge">0xCB</code>-prefixed instructions. Each case maps an opcode
to its mnemonic, operand width, and cycle count. The implementation maps an
opcode to a function pointer at init time so dispatch is an indirect call
rather than a nested switch — 200kB of function table, but the CPU only
touches the entries it needs.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="nf">void</span> <span class="p">(</span><span class="o">*</span><span class="n">opcode_fn</span><span class="p">)(</span><span class="n">lr35902_t</span> <span class="o">*</span><span class="n">cpu</span><span class="p">);</span>
<span class="k">static</span> <span class="n">opcode_fn</span> <span class="n">dispatch</span><span class="p">[</span><span class="mi">512</span><span class="p">];</span> <span class="c1">// 256 main + 256 cb-prefixed</span>

<span class="kt">void</span> <span class="nf">lr35902_step</span><span class="p">(</span><span class="n">lr35902_t</span> <span class="o">*</span><span class="n">cpu</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">uint8_t</span> <span class="n">op</span> <span class="o">=</span> <span class="n">bus_read</span><span class="p">(</span><span class="n">cpu</span><span class="o">-&gt;</span><span class="n">bus</span><span class="p">,</span> <span class="n">cpu</span><span class="o">-&gt;</span><span class="n">pc</span><span class="o">++</span><span class="p">);</span>
    <span class="n">dispatch</span><span class="p">[</span><span class="n">op</span><span class="p">](</span><span class="n">cpu</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="memory-bus">Memory Bus</h2>

<p>The Game Boy addresses 64kB of memory split into regions:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">0x0000–0x3FFF</code>: ROM bank 0 (16kB fixed)</li>
  <li><code class="language-plaintext highlighter-rouge">0x4000–0x7FFF</code>: ROM bank N (16kB switchable via MBC)</li>
  <li><code class="language-plaintext highlighter-rouge">0x8000–0x9FFF</code>: VRAM (8kB)</li>
  <li><code class="language-plaintext highlighter-rouge">0xA000–0xBFFF</code>: external RAM (8kB, battery-backed in cartridges)</li>
  <li><code class="language-plaintext highlighter-rouge">0xC000–0xDFFF</code>: WRAM (8kB)</li>
  <li><code class="language-plaintext highlighter-rouge">0xE000–0xFDFF</code>: echo RAM (mirrors WRAM, rarely used)</li>
  <li><code class="language-plaintext highlighter-rouge">0xFE00–0xFE9F</code>: OAM (sprite data)</li>
  <li><code class="language-plaintext highlighter-rouge">0xFF00–0xFF7F</code>: I/O registers</li>
  <li><code class="language-plaintext highlighter-rouge">0xFF80–0xFFFE</code>: HRAM (high RAM)</li>
  <li><code class="language-plaintext highlighter-rouge">0xFFFF</code>: interrupt enable register</li>
</ul>

<p>The bus struct contains pointers to each region and the MBC state machine.
Reads and writes route through a single <code class="language-plaintext highlighter-rouge">bus_read</code>/<code class="language-plaintext highlighter-rouge">bus_write</code> pair that
maps the address to the correct backing store. MBC1, MBC3, and MBC5
cartridge controllers are handled by swapping the ROM and RAM bank pointers
when the CPU writes to the magic addresses (0x2000–0x3FFF range).</p>

<h2 id="where-i-stopped-the-ppu">Where I Stopped: The PPU</h2>

<p>The Game Boy PPU runs on a pixel pipeline that produces a 160x144 frame 59.7
times per second. It has four modes (HBlank, VBlank, OAM search, pixel
transfer) driven by a 4MHz dot clock, reads from VRAM and OAM, applies
window and sprite priority, and mixes four shades of green. Getting the
timing even slightly wrong produces visual garbage.</p>

<p>I implemented the mode state machine and the LCD status register (<code class="language-plaintext highlighter-rouge">0xFF40</code>),
but pixel compositing — correctly handling sprite priority, window
positioning, and the exact cycle counts for each mode — is where I hit the
wall. Rather than ship a half-baked renderer, I decided to write up the
parts that are solid.</p>

<h2 id="lessons">Lessons</h2>

<p>The CPU and memory bus were straightforward because they’re deterministic
and well-documented. The instruction set is small (roughly 250 unique
opcodes) and every operation reduces to register moves, ALU ops, and
memory access. The PPU is where determinism meets analogue — exact timing
matters, and emulation bugs produce subtly wrong output that’s hard to
distinguish from correct output without reference frame data.</p>

<p>I still plan to finish the PPU. But the CPU and bus are complete, tested
with the Blargg test ROMs, and that’s worth writing about on its own.</p>

]]>
    </content>
  </entry>
    
  

</feed>
