<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"><generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator><link href="https://alessandroferrari.live/feed.xml" rel="self" type="application/atom+xml" /><link href="https://alessandroferrari.live/" rel="alternate" type="text/html" hreflang="en-US" /><updated>2026-02-28T22:02:30+00:00</updated><id>https://alessandroferrari.live/feed.xml</id><title type="html">Alessandro Ferrari’s Website</title><subtitle>This is my website. It contains a blog, my portfolio, and ways to contact me.</subtitle><author><name>Alessandro Ferrari</name><email>alessandroferrari@gatech.edu</email></author><entry><title type="html">Rust Networking for xv6</title><link href="https://alessandroferrari.live/rust-networking-inside-xv6/" rel="alternate" type="text/html" title="Rust Networking for xv6" /><published>2025-12-05T10:59:13+00:00</published><updated>2025-12-05T10:59:13+00:00</updated><id>https://alessandroferrari.live/rust-networking-inside-xv6</id><content type="html" xml:base="https://alessandroferrari.live/rust-networking-inside-xv6/"><![CDATA[<h1 id="intro">Intro</h1>

<p>In my <a href="/rust-inside-xv6/">previous post</a> I explained how to compile and link Rust modules for the x86 target, showing how to print a simple message from rust to the xv6 console.</p>

<p>In this guide I will expand on the framework explained above, implementing interrupt-driven networking with a single TCP socket (similar to *BSD) in the xv6 kernel, fully written in Rust, using the Intel e1000 network card.</p>

<p>On top of this, this project is built on the <a href="https://github.com/mit-pdos/xv6-public">public xv6 source</a> (instead of my school’s private xv6 fork) meaning that I can show the <a href="https://github.com/Ferryistaken/xv6-public">full repo</a>.</p>

<p>I will then show this functionality by telling ChatGPT 5.1 what syscalls it has access to and making it write a userspace HTTP server.</p>

<h1 id="e1000-xv6-driver-layer">e1000 xv6 Driver layer</h1>

<p>There are a lot of <a href="https://xiayingp.gitbook.io/build_a_os/labs/lab-10-networking-part-1">great guides</a> explaining how the e1000 works and how to interface to it in xv6.</p>

<p>On a very basic level:</p>
<ul>
  <li>You first <strong>initialize</strong> the card by sending it a series of numbers over PCI.
    <ul>
      <li>On the internet you’ll find <a href="https://courses.cs.washington.edu/courses/cse451/16au/readings/e1000.pdf">very extensive docs</a> explaining exactly what everything does, but ChatGPT does a good job at making it so that you don’t have to read through function codes.</li>
    </ul>
  </li>
  <li>When the e1000 NIC <strong>receives</strong> a packet, it writes it to a circular buffer and generates an interrupt</li>
  <li>When you want to <strong>transmit</strong> a packet, you write a packet to a separate circular buffer and set a flag.</li>
</ul>

<p>The kernel should therefore map these buffers into memory and then use MMIO to read and write to the network card.</p>

<p><img src="/assets/posts/xv6-networking/ring_buffer.png" alt="ring_buffer" /></p>
<blockquote>
  <p><em>From the docs linked above</em></p>
</blockquote>

<p>How I chose to implement this was by having four main functions:</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">e1000_init(void)</code>
    <ul>
      <li>Reads card, maps memory, sends codes to set the card in the right mode.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">e1000_tx(data, len)</code>
    <ul>
      <li>Given ethernet frames (and its length), write packets to the circular buffer.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">e1000_rx_poll(buf, len)</code>
    <ul>
      <li>Check the NIC RX ring, if we received a packet, read it into buf.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">e1000_intr(void)</code>
    <ul>
      <li>The interrupt handler, when we receive an interrupt, pass control to the Rust handler.</li>
    </ul>
  </li>
</ol>

<h2 id="init-e1000">Init e1000</h2>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span>
<span class="nf">e1000_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
  <span class="n">ioapicenable</span><span class="p">(</span><span class="n">IRQ_E1000</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">uint</span> <span class="n">bus</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">uint</span> <span class="n">slot</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>

  <span class="n">uint</span> <span class="n">bar0</span> <span class="o">=</span> <span class="n">pci_config_read32</span><span class="p">(</span><span class="n">bus</span><span class="p">,</span> <span class="n">slot</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0x10</span><span class="p">);</span>
  <span class="n">uint</span> <span class="n">mmio_pa</span> <span class="o">=</span> <span class="n">bar0</span> <span class="o">&amp;</span> <span class="o">~</span><span class="mh">0xF</span><span class="p">;</span>

  <span class="n">uint</span> <span class="n">pa_page</span> <span class="o">=</span> <span class="n">mmio_pa</span> <span class="o">&amp;</span> <span class="o">~</span><span class="p">(</span><span class="n">PGSIZE</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
  <span class="kt">void</span> <span class="o">*</span><span class="n">va_page</span> <span class="o">=</span> <span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">P2V</span><span class="p">(</span><span class="n">pa_page</span><span class="p">);</span>
  <span class="n">uint</span> <span class="n">mmio_size</span> <span class="o">=</span> <span class="mh">0x4000</span><span class="p">;</span> <span class="c1">// 4 pages</span>

  <span class="kt">int</span> <span class="n">perm</span> <span class="o">=</span> <span class="n">PTE_W</span> <span class="o">|</span> <span class="n">PTE_P</span><span class="p">;</span>

  <span class="k">if</span><span class="p">(</span><span class="n">mappages</span><span class="p">(</span><span class="n">kpgdir</span><span class="p">,</span> <span class="n">va_page</span><span class="p">,</span> <span class="n">mmio_size</span><span class="p">,</span> <span class="n">pa_page</span><span class="p">,</span> <span class="n">perm</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">){</span>
    <span class="n">cprintf</span><span class="p">(</span><span class="s">"e1000: mappages failed for mmio_pa=0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">mmio_pa</span><span class="p">);</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="c1">// Reload CR3 so CPU picks up new mapping</span>
  <span class="n">lcr3</span><span class="p">(</span><span class="n">V2P</span><span class="p">(</span><span class="n">kpgdir</span><span class="p">));</span>

  <span class="n">e1000_regs</span> <span class="o">=</span> <span class="p">(</span><span class="k">volatile</span> <span class="n">uint</span> <span class="o">*</span><span class="p">)</span><span class="n">P2V</span><span class="p">(</span><span class="n">mmio_pa</span><span class="p">);</span>
  <span class="n">cprintf</span><span class="p">(</span><span class="s">"e1000: BAR0=0x%x mmio_pa=0x%x regs=%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">bar0</span><span class="p">,</span> <span class="n">mmio_pa</span><span class="p">,</span> <span class="n">e1000_regs</span><span class="p">);</span>

  <span class="n">uint</span> <span class="n">status</span> <span class="o">=</span> <span class="n">e1000_read_reg</span><span class="p">(</span><span class="n">E1000_STATUS</span><span class="p">);</span>
  <span class="n">cprintf</span><span class="p">(</span><span class="s">"e1000: status=0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">status</span><span class="p">);</span>

  <span class="c1">// Enable bus mastering + memory space on the PCI device</span>
  <span class="n">uint</span> <span class="n">cmd</span> <span class="o">=</span> <span class="n">pci_config_read32</span><span class="p">(</span><span class="n">bus</span><span class="p">,</span> <span class="n">slot</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">);</span>
  <span class="n">ushort</span> <span class="n">cmd_lo</span> <span class="o">=</span> <span class="n">cmd</span> <span class="o">&amp;</span> <span class="mh">0xFFFF</span><span class="p">;</span>

  <span class="c1">// Bit 1 = Memory Space Enable, Bit 2 = Bus Master Enable</span>
  <span class="n">cmd_lo</span> <span class="o">|=</span> <span class="mh">0x0002</span><span class="p">;</span> <span class="c1">// MSE</span>
  <span class="n">cmd_lo</span> <span class="o">|=</span> <span class="mh">0x0004</span><span class="p">;</span> <span class="c1">// BME</span>

  <span class="n">cmd</span> <span class="o">=</span> <span class="p">(</span><span class="n">cmd</span> <span class="o">&amp;</span> <span class="mh">0xFFFF0000</span><span class="p">)</span> <span class="o">|</span> <span class="n">cmd_lo</span><span class="p">;</span>
  <span class="n">pci_config_write32</span><span class="p">(</span><span class="n">bus</span><span class="p">,</span> <span class="n">slot</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="n">cmd</span><span class="p">);</span>

  <span class="n">cprintf</span><span class="p">(</span><span class="s">"e1000: PCI CMD=0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">cmd_lo</span><span class="p">);</span>

  <span class="c1">// Init TX ring</span>
  <span class="kt">int</span> <span class="n">i</span><span class="p">;</span>
  <span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">TX_RING_SIZE</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span>
    <span class="n">tx_ring</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">addr_lo</span> <span class="o">=</span> <span class="n">V2P</span><span class="p">(</span><span class="n">tx_bufs</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="n">tx_ring</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">addr_hi</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">tx_ring</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">length</span>  <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">tx_ring</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">cso</span>     <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">tx_ring</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">cmd</span>     <span class="o">=</span> <span class="n">E1000_TXD_CMD_RS</span> <span class="o">|</span> <span class="n">E1000_TXD_CMD_IFCS</span><span class="p">;</span>
    <span class="n">tx_ring</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">status</span>  <span class="o">=</span> <span class="n">E1000_TXD_STAT_DD</span><span class="p">;</span>  <span class="c1">// mark free</span>
    <span class="n">tx_ring</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">css</span>     <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">tx_ring</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">special</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_TDBAL</span><span class="p">,</span> <span class="n">V2P</span><span class="p">(</span><span class="n">tx_ring</span><span class="p">));</span>
  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_TDBAH</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_TDLEN</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">tx_ring</span><span class="p">));</span>
  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_TDH</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_TDT</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">tx_tail</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

  <span class="c1">// Init RX ring</span>
  <span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">RX_RING_SIZE</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span>
    <span class="n">rx_ring</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">addr_lo</span> <span class="o">=</span> <span class="n">V2P</span><span class="p">(</span><span class="n">rx_bufs</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="n">rx_ring</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">addr_hi</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">rx_ring</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">length</span>  <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">rx_ring</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">csum</span>    <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">rx_ring</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">status</span>  <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>   <span class="c1">// owned by NIC</span>
    <span class="n">rx_ring</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">errors</span>  <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">rx_ring</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">special</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_RDBAL</span><span class="p">,</span> <span class="n">V2P</span><span class="p">(</span><span class="n">rx_ring</span><span class="p">));</span>
  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_RDBAH</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_RDLEN</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">rx_ring</span><span class="p">));</span>
  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_RDH</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_RDT</span><span class="p">,</span> <span class="n">RX_RING_SIZE</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
  <span class="n">rx_next</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

  <span class="c1">// 5) Configure transmit control</span>
  <span class="n">uint</span> <span class="n">tctl</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">tctl</span> <span class="o">|=</span> <span class="n">E1000_TCTL_EN</span><span class="p">;</span>   <span class="c1">// enable TX</span>
  <span class="n">tctl</span> <span class="o">|=</span> <span class="n">E1000_TCTL_PSP</span><span class="p">;</span>  <span class="c1">// pad short packets</span>
  <span class="n">tctl</span> <span class="o">|=</span> <span class="p">(</span><span class="mh">0x10</span> <span class="o">&lt;&lt;</span> <span class="n">E1000_TCTL_CT_SHIFT</span><span class="p">);</span>   <span class="c1">// collision threshold ~16</span>
  <span class="n">tctl</span> <span class="o">|=</span> <span class="p">(</span><span class="mh">0x40</span> <span class="o">&lt;&lt;</span> <span class="n">E1000_TCTL_COLD_SHIFT</span><span class="p">);</span> <span class="c1">// collision distance ~64</span>
  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_TCTL</span><span class="p">,</span> <span class="n">tctl</span><span class="p">);</span>

  <span class="c1">// 6) Configure inter-packet gap</span>
  <span class="n">uint</span> <span class="n">tipg</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">tipg</span> <span class="o">|=</span> <span class="n">E1000_TIPG_IPGT</span><span class="p">;</span>
  <span class="n">tipg</span> <span class="o">|=</span> <span class="p">(</span><span class="n">E1000_TIPG_IPGR1</span> <span class="o">&lt;&lt;</span> <span class="n">E1000_TIPG_IPGR1_SHIFT</span><span class="p">);</span>
  <span class="n">tipg</span> <span class="o">|=</span> <span class="p">(</span><span class="n">E1000_TIPG_IPGR2</span> <span class="o">&lt;&lt;</span> <span class="n">E1000_TIPG_IPGR2_SHIFT</span><span class="p">);</span>
  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_TIPG</span><span class="p">,</span> <span class="n">tipg</span><span class="p">);</span>

  <span class="c1">// 7) Configure receive control</span>
  <span class="n">uint</span> <span class="n">rctl</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">rctl</span> <span class="o">|=</span> <span class="n">E1000_RCTL_EN</span><span class="p">;</span>        <span class="c1">// enable RX</span>
  <span class="n">rctl</span> <span class="o">|=</span> <span class="n">E1000_RCTL_BAM</span><span class="p">;</span>       <span class="c1">// accept broadcast</span>
  <span class="n">rctl</span> <span class="o">|=</span> <span class="n">E1000_RCTL_UPE</span><span class="p">;</span>       <span class="c1">// accept all unicast</span>
  <span class="n">rctl</span> <span class="o">|=</span> <span class="n">E1000_RCTL_MPE</span><span class="p">;</span>       <span class="c1">// accept all multicast</span>
  <span class="n">rctl</span> <span class="o">|=</span> <span class="n">E1000_RCTL_SZ_2048</span><span class="p">;</span>   <span class="c1">// 2K buffers</span>
  <span class="n">rctl</span> <span class="o">|=</span> <span class="n">E1000_RCTL_SECRC</span><span class="p">;</span>     <span class="c1">// strip CRC</span>
  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_RCTL</span><span class="p">,</span> <span class="n">rctl</span><span class="p">);</span>

  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_IMC</span><span class="p">,</span> <span class="mh">0xffffffff</span><span class="p">);</span>  <span class="c1">// mask all</span>
  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">e1000_read_reg</span><span class="p">(</span><span class="n">E1000_ICR</span><span class="p">);</span>         <span class="c1">// clear pending</span>
  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_IMS</span><span class="p">,</span>
                  <span class="n">E1000_IMS_RXT0</span> <span class="o">|</span>   <span class="c1">// RX timer / normal receive</span>
                  <span class="n">E1000_IMS_RXO</span>  <span class="o">|</span>   <span class="c1">// RX overrun (optional)</span>
                  <span class="n">E1000_IMS_RXDMT0</span> <span class="o">|</span> <span class="c1">// RX desc low watermark</span>
                  <span class="n">E1000_IMS_TXDW</span><span class="p">);</span>   <span class="c1">// TX descriptor write-back</span>

  <span class="c1">// debug: read back RCTL to confirm</span>
  <span class="n">uint</span> <span class="n">rctl_read</span> <span class="o">=</span> <span class="n">e1000_read_reg</span><span class="p">(</span><span class="n">E1000_RCTL</span><span class="p">);</span>
  <span class="n">cprintf</span><span class="p">(</span><span class="s">"e1000: RCTL=0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">rctl_read</span><span class="p">);</span>

  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">e1000_test_send</span><span class="p">;</span>
  <span class="c1">// e1000_test_send();  // optional</span>

  <span class="n">cprintf</span><span class="p">(</span><span class="s">"e1000: initialized</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

  <span class="c1">// Initialize Rust+smoltcp stack now that NIC is ready.</span>
  <span class="n">rust_net_init</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="transmit-frame">Transmit frame</h2>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span>
<span class="nf">e1000_tx</span><span class="p">(</span><span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="kt">int</span> <span class="n">len</span><span class="p">)</span>
<span class="p">{</span>
  <span class="k">if</span><span class="p">(</span><span class="n">len</span> <span class="o">&lt;=</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">len</span> <span class="o">&gt;</span> <span class="n">PKT_BUF_SIZE</span><span class="p">)</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>

  <span class="kt">int</span> <span class="n">tdt</span> <span class="o">=</span> <span class="n">e1000_read_reg</span><span class="p">(</span><span class="n">E1000_TDT</span><span class="p">);</span>
  <span class="k">struct</span> <span class="n">e1000_tx_desc</span> <span class="o">*</span><span class="n">d</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">tx_ring</span><span class="p">[</span><span class="n">tdt</span><span class="p">];</span>

  <span class="n">cprintf</span><span class="p">(</span><span class="s">"e1000_tx: tdt=%d status=0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">tdt</span><span class="p">,</span> <span class="n">d</span><span class="o">-&gt;</span><span class="n">status</span><span class="p">);</span>

  <span class="k">if</span><span class="p">((</span><span class="n">d</span><span class="o">-&gt;</span><span class="n">status</span> <span class="o">&amp;</span> <span class="n">E1000_TXD_STAT_DD</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">){</span>
    <span class="n">cprintf</span><span class="p">(</span><span class="s">"e1000_tx: ring full at %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">tdt</span><span class="p">);</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">memmove</span><span class="p">(</span><span class="n">tx_bufs</span><span class="p">[</span><span class="n">tdt</span><span class="p">],</span> <span class="n">data</span><span class="p">,</span> <span class="n">len</span><span class="p">);</span>

  <span class="n">d</span><span class="o">-&gt;</span><span class="n">length</span> <span class="o">=</span> <span class="n">len</span><span class="p">;</span>
  <span class="n">d</span><span class="o">-&gt;</span><span class="n">status</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">d</span><span class="o">-&gt;</span><span class="n">cmd</span> <span class="o">=</span> <span class="n">E1000_TXD_CMD_RS</span> <span class="o">|</span> <span class="n">E1000_TXD_CMD_EOP</span> <span class="o">|</span> <span class="n">E1000_TXD_CMD_IFCS</span><span class="p">;</span>

  <span class="n">tdt</span> <span class="o">=</span> <span class="p">(</span><span class="n">tdt</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="n">TX_RING_SIZE</span><span class="p">;</span>
  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_TDT</span><span class="p">,</span> <span class="n">tdt</span><span class="p">);</span>

  <span class="n">cprintf</span><span class="p">(</span><span class="s">"e1000_tx: queued len=%d new TDT=%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">len</span><span class="p">,</span> <span class="n">tdt</span><span class="p">);</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="read-frame">Read frame</h2>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span>
<span class="nf">e1000_rx_poll</span><span class="p">(</span><span class="n">uchar</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">int</span> <span class="n">maxlen</span><span class="p">)</span>
<span class="p">{</span>
  <span class="k">struct</span> <span class="n">e1000_rx_desc</span> <span class="o">*</span><span class="n">d</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">rx_ring</span><span class="p">[</span><span class="n">rx_next</span><span class="p">];</span>

  <span class="k">if</span><span class="p">((</span><span class="n">d</span><span class="o">-&gt;</span><span class="n">status</span> <span class="o">&amp;</span> <span class="n">E1000_RXD_STAT_DD</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>

  <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

  <span class="k">if</span><span class="p">((</span><span class="n">d</span><span class="o">-&gt;</span><span class="n">status</span> <span class="o">&amp;</span> <span class="n">E1000_RXD_STAT_EOP</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">){</span>
    <span class="n">cprintf</span><span class="p">(</span><span class="s">"e1000: RX fragment, dropping (len=%d status=0x%x)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span>
                  <span class="n">d</span><span class="o">-&gt;</span><span class="n">length</span><span class="p">,</span> <span class="n">d</span><span class="o">-&gt;</span><span class="n">status</span><span class="p">);</span>
    <span class="c1">// n stays 0 -&gt; caller won't use this packet</span>
    <span class="k">goto</span> <span class="n">rearm</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="n">n</span> <span class="o">=</span> <span class="n">d</span><span class="o">-&gt;</span><span class="n">length</span><span class="p">;</span>
  <span class="k">if</span><span class="p">(</span><span class="n">n</span> <span class="o">&gt;</span> <span class="n">maxlen</span><span class="p">)</span>
    <span class="n">n</span> <span class="o">=</span> <span class="n">maxlen</span><span class="p">;</span>

  <span class="n">memmove</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="n">rx_bufs</span><span class="p">[</span><span class="n">rx_next</span><span class="p">],</span> <span class="n">n</span><span class="p">);</span>

<span class="nl">rearm:</span>
  <span class="n">d</span><span class="o">-&gt;</span><span class="n">status</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">d</span><span class="o">-&gt;</span><span class="n">errors</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

  <span class="n">rx_next</span> <span class="o">=</span> <span class="p">(</span><span class="n">rx_next</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="n">RX_RING_SIZE</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">rdt</span> <span class="o">=</span> <span class="p">(</span><span class="n">rx_next</span> <span class="o">+</span> <span class="n">RX_RING_SIZE</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="n">RX_RING_SIZE</span><span class="p">;</span>
  <span class="n">e1000_write_reg</span><span class="p">(</span><span class="n">E1000_RDT</span><span class="p">,</span> <span class="n">rdt</span><span class="p">);</span>

  <span class="k">return</span> <span class="n">n</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="handle-interrupt">Handle Interrupt</h2>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span>
<span class="nf">e1000_intr</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
  <span class="n">uint</span> <span class="n">icr</span> <span class="o">=</span> <span class="n">e1000_read_reg</span><span class="p">(</span><span class="n">E1000_ICR</span><span class="p">);</span>

  <span class="k">if</span><span class="p">(</span><span class="n">icr</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
    <span class="k">return</span><span class="p">;</span>

  <span class="c1">// RX-related interrupt?</span>
  <span class="k">if</span><span class="p">(</span><span class="n">icr</span> <span class="o">&amp;</span> <span class="p">(</span><span class="n">E1000_ICR_RXT0</span> <span class="o">|</span> <span class="n">E1000_ICR_RXDMT0</span> <span class="o">|</span> <span class="n">E1000_ICR_RXO</span><span class="p">)){</span>
    <span class="c1">// Let Rust+smoltcp pull packets with e1000_rx_poll() and handle them.</span>
    <span class="n">cprintf</span><span class="p">(</span><span class="s">"handling packet in rust</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="n">rust_net_poll</span><span class="p">();</span>
  <span class="p">}</span>

  <span class="k">if</span><span class="p">(</span><span class="n">icr</span> <span class="o">&amp;</span> <span class="n">E1000_ICR_TXDW</span><span class="p">){</span>
    <span class="n">cprintf</span><span class="p">(</span><span class="s">"e1000: TXDW</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">e1000_debug_dump</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h1 id="os-layer">OS Layer</h1>
<h2 id="manual-networking">“Manual” Networking</h2>

<p>I started the project by implementing my own TCP/IP stack, however I realized early on that it would have involved writing hundreds of lines of code handling every specific IP protocols that I wanted (ICMP, HTTP, just to name a few) by reading their spec and manually creating all the specific packets, and I have no interest in doing so right now, given that this is an OS-focused project.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cd">/// Inside the interrupt handler</span>
<span class="o">...</span>
    <span class="k">match</span> <span class="n">ethertype</span> <span class="p">{</span>
        <span class="mi">0x0806</span> <span class="k">=&gt;</span> <span class="p">{</span>
            <span class="c1">// ARP</span>
            <span class="k">unsafe</span> <span class="p">{</span> <span class="nf">puts_const</span><span class="p">(</span><span class="s">b"rust_net_rx: ARP frame</span><span class="se">\n\0</span><span class="s">"</span><span class="p">)</span> <span class="p">};</span>
            <span class="nf">arp_rx</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="n">src</span><span class="p">,</span> <span class="n">dst</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="mi">0x0800</span> <span class="k">=&gt;</span> <span class="p">{</span>
            <span class="c1">// IPv4</span>
            <span class="k">unsafe</span> <span class="p">{</span> <span class="nf">puts_const</span><span class="p">(</span><span class="s">b"rust_net_rx: IPv4 frame</span><span class="se">\n\0</span><span class="s">"</span><span class="p">)</span> <span class="p">};</span>
            <span class="nf">ipv4_rx</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="n">src</span><span class="p">,</span> <span class="n">dst</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="n">_</span> <span class="k">=&gt;</span> <span class="p">{</span>
            <span class="c1">// unsupported ethertype, drop silently for now</span>
        <span class="p">}</span>
<span class="o">...</span>

<span class="cd">/// Example of a ~120loc function just to handle basic ARP packets.</span>
<span class="cd">/// Most of the funciton is just manually building the correct buffers.</span>
<span class="k">fn</span> <span class="nf">arp_rx</span><span class="p">(</span><span class="n">payload</span><span class="p">:</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">],</span> <span class="n">src_mac</span><span class="p">:</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">],</span> <span class="n">_dst_mac</span><span class="p">:</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">])</span> <span class="p">{</span>
    <span class="c1">// We assume Ethernet/IPv4 ARP, which is 28 bytes minimum.</span>
    <span class="k">if</span> <span class="n">payload</span><span class="nf">.len</span><span class="p">()</span> <span class="o">&lt;</span> <span class="mi">28</span> <span class="p">||</span> <span class="n">src_mac</span><span class="nf">.len</span><span class="p">()</span> <span class="o">&lt;</span> <span class="mi">6</span> <span class="p">{</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">let</span> <span class="n">htype</span> <span class="o">=</span> <span class="nn">u16</span><span class="p">::</span><span class="nf">from_be_bytes</span><span class="p">([</span><span class="n">payload</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">payload</span><span class="p">[</span><span class="mi">1</span><span class="p">]]);</span>
    <span class="k">let</span> <span class="n">ptype</span> <span class="o">=</span> <span class="nn">u16</span><span class="p">::</span><span class="nf">from_be_bytes</span><span class="p">([</span><span class="n">payload</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">payload</span><span class="p">[</span><span class="mi">3</span><span class="p">]]);</span>
    <span class="k">let</span> <span class="n">hlen</span>  <span class="o">=</span> <span class="n">payload</span><span class="p">[</span><span class="mi">4</span><span class="p">];</span>
    <span class="k">let</span> <span class="n">plen</span>  <span class="o">=</span> <span class="n">payload</span><span class="p">[</span><span class="mi">5</span><span class="p">];</span>
    <span class="k">let</span> <span class="n">oper</span>  <span class="o">=</span> <span class="nn">u16</span><span class="p">::</span><span class="nf">from_be_bytes</span><span class="p">([</span><span class="n">payload</span><span class="p">[</span><span class="mi">6</span><span class="p">],</span> <span class="n">payload</span><span class="p">[</span><span class="mi">7</span><span class="p">]]);</span>

    <span class="c1">// Only handle Ethernet (1) + IPv4 (0x0800), MAC len 6, IP len 4</span>
    <span class="k">if</span> <span class="n">htype</span> <span class="o">!=</span> <span class="mi">1</span> <span class="p">||</span> <span class="n">ptype</span> <span class="o">!=</span> <span class="mi">0x0800</span> <span class="p">||</span> <span class="n">hlen</span> <span class="o">!=</span> <span class="mi">6</span> <span class="p">||</span> <span class="n">plen</span> <span class="o">!=</span> <span class="mi">4</span> <span class="p">{</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// Layout:</span>
    <span class="c1">// [ 8..14 ] sender hw</span>
    <span class="c1">// [14..18] sender IP</span>
    <span class="c1">// [18..24] target hw</span>
    <span class="c1">// [24..28] target IP</span>
    <span class="k">let</span> <span class="n">sha</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">payload</span><span class="p">[</span><span class="mi">8</span><span class="o">..</span><span class="mi">14</span><span class="p">];</span>   <span class="c1">// sender MAC</span>
    <span class="k">let</span> <span class="n">spa</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">payload</span><span class="p">[</span><span class="mi">14</span><span class="o">..</span><span class="mi">18</span><span class="p">];</span>  <span class="c1">// sender IP</span>
    <span class="k">let</span> <span class="n">tpa</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">payload</span><span class="p">[</span><span class="mi">24</span><span class="o">..</span><span class="mi">28</span><span class="p">];</span>  <span class="c1">// target IP</span>
<span class="o">...</span>
</code></pre></div></div>
<blockquote>
  <p><em>Snippet of what the could would have looked like was I to implement everything by myself. Hopefully you can see how this isn’t aligned with the scope of this project.</em></p>
</blockquote>

<h2 id="the-smoltcp-crate">The smoltcp crate</h2>

<p>After some research I came across <a href="https://github.com/smoltcp-rs/smoltcp"><code class="language-plaintext highlighter-rouge">smoltcp</code></a>, a <em>“standalone, event-driven TCP/IP stack that is designed for bare-metal, real-time systems”</em>. Very importantly, this crate compiles with <code class="language-plaintext highlighter-rouge">no_std</code>, making it an excellent choice for xv6 development.</p>

<p>The simplicity of this crate is what drew me to it. A <a href="https://docs.rs/smoltcp/latest/smoltcp/phy/trait.Device.html"><code class="language-plaintext highlighter-rouge">Device</code></a> only needs to implement <code class="language-plaintext highlighter-rouge">receive</code>, <code class="language-plaintext highlighter-rouge">transmit</code>, and <code class="language-plaintext highlighter-rouge">capabilities</code>. With these three methods done (which are really only 2, since capabilities is just a way to describe the device’s capabilities.), we basically have a fully functional TCP/IP stack. For my <code class="language-plaintext highlighter-rouge">xv6</code> e1000 driver, these implementations looked like:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span> <span class="n">Device</span> <span class="k">for</span> <span class="n">Xv6Device</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">RxToken</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="o">=</span> <span class="n">Xv6RxToken</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="k">where</span> <span class="k">Self</span><span class="p">:</span> <span class="nv">'a</span><span class="p">;</span>
    <span class="k">type</span> <span class="n">TxToken</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="o">=</span> <span class="n">Xv6TxToken</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="k">where</span> <span class="k">Self</span><span class="p">:</span> <span class="nv">'a</span><span class="p">;</span>

    <span class="k">fn</span> <span class="nf">capabilities</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">DeviceCapabilities</span> <span class="p">{</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">caps</span> <span class="o">=</span> <span class="nn">DeviceCapabilities</span><span class="p">::</span><span class="nf">default</span><span class="p">();</span>
        <span class="n">caps</span><span class="py">.medium</span> <span class="o">=</span> <span class="nn">Medium</span><span class="p">::</span><span class="n">Ethernet</span><span class="p">;</span>
        <span class="n">caps</span><span class="py">.max_transmission_unit</span> <span class="o">=</span> <span class="n">MAX_FRAME_SIZE</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">;</span>
        <span class="n">caps</span>
    <span class="p">}</span>

    <span class="k">fn</span> <span class="nf">receive</span><span class="p">(</span>
        <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span>
        <span class="n">_timestamp</span><span class="p">:</span> <span class="n">Instant</span><span class="p">,</span>
    <span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="p">(</span><span class="k">Self</span><span class="p">::</span><span class="n">RxToken</span><span class="o">&lt;</span><span class="nv">'_</span><span class="o">&gt;</span><span class="p">,</span> <span class="k">Self</span><span class="p">::</span><span class="n">TxToken</span><span class="o">&lt;</span><span class="nv">'_</span><span class="o">&gt;</span><span class="p">)</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="k">unsafe</span> <span class="p">{</span> <span class="nf">puts_const</span><span class="p">(</span><span class="s">b"rust: smoltcp receive() got frame</span><span class="se">\n\0</span><span class="s">"</span><span class="p">);</span> <span class="p">}</span>

        <span class="k">self</span><span class="py">.rx_len</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="c1">// ↓ C function</span>
        <span class="k">let</span> <span class="n">n</span> <span class="o">=</span> <span class="k">unsafe</span> <span class="p">{</span> <span class="nf">e1000_rx_poll</span><span class="p">(</span><span class="k">self</span><span class="py">.rx_buf</span><span class="nf">.as_mut_ptr</span><span class="p">(),</span> <span class="n">MAX_FRAME_SIZE</span> <span class="k">as</span> <span class="nb">c_int</span><span class="p">)</span> <span class="p">};</span>
        <span class="k">if</span> <span class="n">n</span> <span class="o">&lt;=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">return</span> <span class="nb">None</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">self</span><span class="py">.rx_len</span> <span class="o">=</span> <span class="n">n</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">;</span>
        <span class="k">let</span> <span class="n">rx</span> <span class="o">=</span> <span class="n">Xv6RxToken</span> <span class="p">{</span>
            <span class="n">buffer</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">self</span><span class="py">.rx_buf</span><span class="p">[</span><span class="o">..</span><span class="k">self</span><span class="py">.rx_len</span><span class="p">],</span>
        <span class="p">};</span>
        <span class="k">let</span> <span class="n">tx</span> <span class="o">=</span> <span class="n">Xv6TxToken</span> <span class="p">{</span>
            <span class="n">buffer</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.tx_buf</span><span class="p">[</span><span class="o">..</span><span class="p">],</span>
        <span class="p">};</span>
        <span class="nf">Some</span><span class="p">((</span><span class="n">rx</span><span class="p">,</span> <span class="n">tx</span><span class="p">))</span>
    <span class="p">}</span>

    <span class="k">fn</span> <span class="nf">transmit</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">_timestamp</span><span class="p">:</span> <span class="n">Instant</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="k">Self</span><span class="p">::</span><span class="n">TxToken</span><span class="o">&lt;</span><span class="nv">'_</span><span class="o">&gt;&gt;</span> <span class="p">{</span>
        <span class="k">unsafe</span> <span class="p">{</span> <span class="nf">puts_const</span><span class="p">(</span><span class="s">b"rust: smoltcp transmit() called</span><span class="se">\n\0</span><span class="s">"</span><span class="p">);</span> <span class="p">}</span>
        <span class="nf">Some</span><span class="p">(</span><span class="n">Xv6TxToken</span> <span class="p">{</span>
            <span class="n">buffer</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.tx_buf</span><span class="p">[</span><span class="o">..</span><span class="p">],</span>
        <span class="p">})</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">struct</span> <span class="n">Xv6Device</span> <span class="p">{</span>
    <span class="n">rx_buf</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="n">MAX_FRAME_SIZE</span><span class="p">],</span>
    <span class="n">rx_len</span><span class="p">:</span> <span class="nb">usize</span><span class="p">,</span>
    <span class="n">tx_buf</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="n">MAX_FRAME_SIZE</span><span class="p">],</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Xv6Device</span> <span class="p">{</span>
    <span class="k">const</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="k">Self</span> <span class="p">{</span>
            <span class="n">rx_buf</span><span class="p">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">;</span> <span class="n">MAX_FRAME_SIZE</span><span class="p">],</span>
            <span class="n">rx_len</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
            <span class="n">tx_buf</span><span class="p">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">;</span> <span class="n">MAX_FRAME_SIZE</span><span class="p">],</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">struct</span> <span class="n">Xv6RxToken</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">buffer</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span>
<span class="p">}</span>

<span class="k">struct</span> <span class="n">Xv6TxToken</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">buffer</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="n">RxToken</span> <span class="k">for</span> <span class="n">Xv6RxToken</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="n">consume</span><span class="o">&lt;</span><span class="n">R</span><span class="p">,</span> <span class="n">F</span><span class="o">&gt;</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">f</span><span class="p">:</span> <span class="n">F</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">R</span>
    <span class="k">where</span>
        <span class="n">F</span><span class="p">:</span> <span class="nf">FnOnce</span><span class="p">(</span><span class="o">&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">])</span> <span class="k">-&gt;</span> <span class="n">R</span><span class="p">,</span>
    <span class="p">{</span>
        <span class="nf">f</span><span class="p">(</span><span class="k">self</span><span class="py">.buffer</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="n">TxToken</span> <span class="k">for</span> <span class="n">Xv6TxToken</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="n">consume</span><span class="o">&lt;</span><span class="n">R</span><span class="p">,</span> <span class="n">F</span><span class="o">&gt;</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">len</span><span class="p">:</span> <span class="nb">usize</span><span class="p">,</span> <span class="n">f</span><span class="p">:</span> <span class="n">F</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">R</span>
    <span class="k">where</span>
        <span class="n">F</span><span class="p">:</span> <span class="nf">FnOnce</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">])</span> <span class="k">-&gt;</span> <span class="n">R</span><span class="p">,</span>
    <span class="p">{</span>
        <span class="k">let</span> <span class="n">slice</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.buffer</span><span class="p">[</span><span class="o">..</span><span class="n">len</span><span class="p">];</span>
        <span class="k">let</span> <span class="n">result</span> <span class="o">=</span> <span class="nf">f</span><span class="p">(</span><span class="n">slice</span><span class="p">);</span>

        <span class="k">unsafe</span> <span class="p">{</span>
            <span class="nf">puts_const</span><span class="p">(</span><span class="s">b"rust: smoltcp TxToken::consume, sending frame</span><span class="se">\n\0</span><span class="s">"</span><span class="p">);</span>
            <span class="c1">// ↓ C function</span>
            <span class="nf">e1000_tx</span><span class="p">(</span><span class="n">slice</span><span class="nf">.as_ptr</span><span class="p">(),</span> <span class="n">len</span> <span class="k">as</span> <span class="nb">c_int</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="n">result</span>
    <span class="p">}</span>
<span class="p">}</span>

</code></pre></div></div>

<p>With this done, we have a working TCP/IP stack that we can use from the xv6 kernel, however the user still has no way to access these resources.</p>

<h1 id="os-syscall-layer">OS Syscall Layer</h1>

<p>To give the user access to networking resources, I chose to implement 4 syscalls:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">int  net_listen(int port);</code>
    <ul>
      <li>Listen on TCP port <code class="language-plaintext highlighter-rouge">port</code>.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">int  net_accept(void);</code>
    <ul>
      <li>Returns 1 if a connection is established, 0 if not yet, -1 on error.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">int  net_recv(void *buf, int n);</code>
    <ul>
      <li>Returns bytes read, 0 if no data, -1 on error.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">int net_send(void *buf, int n);</code>
    <ul>
      <li>Returns bytes sent, 0 if would-block, -1 on error.</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">int net_close(void);</code>
    <ul>
      <li>Close current connection.</li>
    </ul>
  </li>
</ul>

<h2 id="c-side">C Side</h2>

<p>On the C side, these functions simply do argument parsing and pass the control to the Rust module:</p>

<pre><code class="language-C">int
sys_net_listen(void)
{
  int port;
  if(argint(0, &amp;port) &lt; 0)
    return -1;
  if(port &lt; 0 || port &gt; 65535)
    return -1;
  return rust_net_listen(port);
}

// int net_accept(void);
// returns 1 if a connection is established, 0 if not yet, -1 on error
int
sys_net_accept(void)
{
  return rust_net_accept();
}

// int net_recv(void *buf, int len);
int
sys_net_recv(void)
{
  int len;
  char *buf;

  if(argptr(0, &amp;buf, 0) &lt; 0) // size checked below
    return -1;
  if(argint(1, &amp;len) &lt; 0)
    return -1;
  if(len &lt; 0)
    return -1;

  return rust_net_recv(buf, len);
}

// int net_send(void *buf, int len);
int
sys_net_send(void)
{
  int len;
  char *buf;

  if(argptr(0, &amp;buf, 0) &lt; 0)
    return -1;
  if(argint(1, &amp;len) &lt; 0)
    return -1;
  if(len &lt; 0)
    return -1;

  return rust_net_send(buf, len);
}

// int net_close(void);
int
sys_net_close(void)
{
  rust_net_close();
  return 0;
}
</code></pre>

<h2 id="rust-side">Rust Side</h2>

<p>The real logic is all implement in the safe Rust module. However, due to <code class="language-plaintext highlighter-rouge">smoltcp</code>, these syscall handlers are very light:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[no_mangle]</span>
<span class="k">pub</span> <span class="k">extern</span> <span class="s">"C"</span> <span class="k">fn</span> <span class="nf">rust_net_listen</span><span class="p">(</span><span class="n">port</span><span class="p">:</span> <span class="nb">i32</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">i32</span> <span class="p">{</span>
    <span class="k">unsafe</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">sockets</span> <span class="o">=</span> <span class="k">match</span> <span class="n">SOCKET_SET</span><span class="nf">.as_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="nf">Some</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">s</span><span class="p">,</span>
            <span class="nb">None</span> <span class="k">=&gt;</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span>
        <span class="p">};</span>
        <span class="k">let</span> <span class="n">handle</span> <span class="o">=</span> <span class="k">match</span> <span class="n">TCP_HANDLE</span> <span class="p">{</span>
            <span class="nf">Some</span><span class="p">(</span><span class="n">h</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">h</span><span class="p">,</span>
            <span class="nb">None</span> <span class="k">=&gt;</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span>
        <span class="p">};</span>
        <span class="k">let</span> <span class="n">socket</span> <span class="o">=</span> <span class="n">sockets</span><span class="py">.get_mut</span><span class="p">::</span><span class="o">&lt;</span><span class="nn">tcp</span><span class="p">::</span><span class="n">Socket</span><span class="o">&gt;</span><span class="p">(</span><span class="n">handle</span><span class="p">);</span>
        <span class="k">match</span> <span class="n">socket</span><span class="nf">.listen</span><span class="p">(</span><span class="n">port</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">)</span> <span class="p">{</span>
            <span class="nf">Ok</span><span class="p">(())</span> <span class="k">=&gt;</span> <span class="mi">0</span><span class="p">,</span>
            <span class="nf">Err</span><span class="p">(</span><span class="n">_</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="nd">#[no_mangle]</span>
<span class="k">pub</span> <span class="k">extern</span> <span class="s">"C"</span> <span class="k">fn</span> <span class="nf">rust_net_accept</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="nb">i32</span> <span class="p">{</span>
    <span class="k">unsafe</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">sockets</span> <span class="o">=</span> <span class="k">match</span> <span class="n">SOCKET_SET</span><span class="nf">.as_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="nf">Some</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">s</span><span class="p">,</span>
            <span class="nb">None</span> <span class="k">=&gt;</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span>
        <span class="p">};</span>
        <span class="k">let</span> <span class="n">handle</span> <span class="o">=</span> <span class="k">match</span> <span class="n">TCP_HANDLE</span> <span class="p">{</span>
            <span class="nf">Some</span><span class="p">(</span><span class="n">h</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">h</span><span class="p">,</span>
            <span class="nb">None</span> <span class="k">=&gt;</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span>
        <span class="p">};</span>
        <span class="k">let</span> <span class="n">socket</span> <span class="o">=</span> <span class="n">sockets</span><span class="py">.get_mut</span><span class="p">::</span><span class="o">&lt;</span><span class="nn">tcp</span><span class="p">::</span><span class="n">Socket</span><span class="o">&gt;</span><span class="p">(</span><span class="n">handle</span><span class="p">);</span>
        <span class="k">use</span> <span class="nn">smoltcp</span><span class="p">::</span><span class="nn">socket</span><span class="p">::</span><span class="nn">tcp</span><span class="p">::</span><span class="n">State</span><span class="p">;</span>
        <span class="k">match</span> <span class="n">socket</span><span class="nf">.state</span><span class="p">()</span> <span class="p">{</span>
            <span class="nn">State</span><span class="p">::</span><span class="n">Established</span> <span class="k">=&gt;</span> <span class="mi">1</span><span class="p">,</span>
            <span class="nn">State</span><span class="p">::</span><span class="n">Listen</span> <span class="p">|</span> <span class="nn">State</span><span class="p">::</span><span class="n">SynReceived</span> <span class="p">|</span> <span class="nn">State</span><span class="p">::</span><span class="n">SynSent</span> <span class="k">=&gt;</span> <span class="mi">0</span><span class="p">,</span>
            <span class="n">_</span> <span class="k">=&gt;</span> <span class="mi">0</span><span class="p">,</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="nd">#[no_mangle]</span>
<span class="k">pub</span> <span class="k">extern</span> <span class="s">"C"</span> <span class="k">fn</span> <span class="nf">rust_net_recv</span><span class="p">(</span><span class="n">buf</span><span class="p">:</span> <span class="o">*</span><span class="k">mut</span> <span class="nb">u8</span><span class="p">,</span> <span class="n">len</span><span class="p">:</span> <span class="nb">i32</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">i32</span> <span class="p">{</span>
    <span class="k">if</span> <span class="n">buf</span><span class="nf">.is_null</span><span class="p">()</span> <span class="p">||</span> <span class="n">len</span> <span class="o">&lt;=</span> <span class="mi">0</span> <span class="p">{</span>
        <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">unsafe</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">sockets</span> <span class="o">=</span> <span class="k">match</span> <span class="n">SOCKET_SET</span><span class="nf">.as_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="nf">Some</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">s</span><span class="p">,</span>
            <span class="nb">None</span> <span class="k">=&gt;</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span>
        <span class="p">};</span>
        <span class="k">let</span> <span class="n">handle</span> <span class="o">=</span> <span class="k">match</span> <span class="n">TCP_HANDLE</span> <span class="p">{</span>
            <span class="nf">Some</span><span class="p">(</span><span class="n">h</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">h</span><span class="p">,</span>
            <span class="nb">None</span> <span class="k">=&gt;</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span>
        <span class="p">};</span>
        <span class="k">let</span> <span class="n">socket</span> <span class="o">=</span> <span class="n">sockets</span><span class="py">.get_mut</span><span class="p">::</span><span class="o">&lt;</span><span class="nn">tcp</span><span class="p">::</span><span class="n">Socket</span><span class="o">&gt;</span><span class="p">(</span><span class="n">handle</span><span class="p">);</span>

        <span class="k">if</span> <span class="o">!</span><span class="n">socket</span><span class="nf">.may_recv</span><span class="p">()</span> <span class="p">{</span>
            <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">let</span> <span class="n">max_len</span> <span class="o">=</span> <span class="n">len</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">;</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">out_n</span><span class="p">:</span> <span class="nb">i32</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

        <span class="k">let</span> <span class="n">res</span> <span class="o">=</span> <span class="n">socket</span><span class="nf">.recv</span><span class="p">(|</span><span class="n">data</span><span class="p">|</span> <span class="p">{</span>
            <span class="k">let</span> <span class="n">n</span> <span class="o">=</span> <span class="nn">core</span><span class="p">::</span><span class="nn">cmp</span><span class="p">::</span><span class="nf">min</span><span class="p">(</span><span class="n">data</span><span class="nf">.len</span><span class="p">(),</span> <span class="n">max_len</span><span class="p">);</span>
            <span class="k">if</span> <span class="n">n</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="p">{</span>
                <span class="nn">core</span><span class="p">::</span><span class="nn">ptr</span><span class="p">::</span><span class="nf">copy_nonoverlapping</span><span class="p">(</span><span class="n">data</span><span class="nf">.as_ptr</span><span class="p">(),</span> <span class="n">buf</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="n">out_n</span> <span class="o">=</span> <span class="n">n</span> <span class="k">as</span> <span class="nb">i32</span><span class="p">;</span>
            <span class="c1">// consume n bytes, return n as the closure result</span>
            <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="p">())</span>
        <span class="p">});</span>

        <span class="k">if</span> <span class="n">res</span><span class="nf">.is_err</span><span class="p">()</span> <span class="p">{</span>
            <span class="o">-</span><span class="mi">1</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">out_n</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="nd">#[no_mangle]</span>
<span class="k">pub</span> <span class="k">extern</span> <span class="s">"C"</span> <span class="k">fn</span> <span class="nf">rust_net_send</span><span class="p">(</span><span class="n">buf</span><span class="p">:</span> <span class="o">*</span><span class="k">const</span> <span class="nb">u8</span><span class="p">,</span> <span class="n">len</span><span class="p">:</span> <span class="nb">i32</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">i32</span> <span class="p">{</span>
    <span class="k">if</span> <span class="n">buf</span><span class="nf">.is_null</span><span class="p">()</span> <span class="p">||</span> <span class="n">len</span> <span class="o">&lt;=</span> <span class="mi">0</span> <span class="p">{</span>
        <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">unsafe</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">sockets</span> <span class="o">=</span> <span class="k">match</span> <span class="n">SOCKET_SET</span><span class="nf">.as_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="nf">Some</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">s</span><span class="p">,</span>
            <span class="nb">None</span> <span class="k">=&gt;</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span>
        <span class="p">};</span>
        <span class="k">let</span> <span class="n">handle</span> <span class="o">=</span> <span class="k">match</span> <span class="n">TCP_HANDLE</span> <span class="p">{</span>
            <span class="nf">Some</span><span class="p">(</span><span class="n">h</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">h</span><span class="p">,</span>
            <span class="nb">None</span> <span class="k">=&gt;</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span>
        <span class="p">};</span>
        <span class="k">let</span> <span class="n">socket</span> <span class="o">=</span> <span class="n">sockets</span><span class="py">.get_mut</span><span class="p">::</span><span class="o">&lt;</span><span class="nn">tcp</span><span class="p">::</span><span class="n">Socket</span><span class="o">&gt;</span><span class="p">(</span><span class="n">handle</span><span class="p">);</span>

        <span class="c1">// Only send if TCP state/window allows</span>
        <span class="k">if</span> <span class="o">!</span><span class="n">socket</span><span class="nf">.may_send</span><span class="p">()</span> <span class="p">{</span>
            <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// would block / not ready</span>
        <span class="p">}</span>

        <span class="k">let</span> <span class="n">slice</span> <span class="o">=</span> <span class="nn">core</span><span class="p">::</span><span class="nn">slice</span><span class="p">::</span><span class="nf">from_raw_parts</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="n">len</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">);</span>

        <span class="k">match</span> <span class="n">socket</span><span class="nf">.send_slice</span><span class="p">(</span><span class="n">slice</span><span class="p">)</span> <span class="p">{</span>
            <span class="nf">Ok</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">n</span> <span class="k">as</span> <span class="nb">i32</span><span class="p">,</span> <span class="c1">// actual bytes queued</span>
            <span class="nf">Err</span><span class="p">(</span><span class="n">_</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>


<span class="nd">#[no_mangle]</span>
<span class="k">pub</span> <span class="k">extern</span> <span class="s">"C"</span> <span class="k">fn</span> <span class="nf">rust_net_close</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">unsafe</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">sockets</span> <span class="o">=</span> <span class="k">match</span> <span class="n">SOCKET_SET</span><span class="nf">.as_mut</span><span class="p">()</span> <span class="p">{</span>
            <span class="nf">Some</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">s</span><span class="p">,</span>
            <span class="nb">None</span> <span class="k">=&gt;</span> <span class="k">return</span><span class="p">,</span>
        <span class="p">};</span>
        <span class="k">let</span> <span class="n">handle</span> <span class="o">=</span> <span class="k">match</span> <span class="n">TCP_HANDLE</span> <span class="p">{</span>
            <span class="nf">Some</span><span class="p">(</span><span class="n">h</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">h</span><span class="p">,</span>
            <span class="nb">None</span> <span class="k">=&gt;</span> <span class="k">return</span><span class="p">,</span>
        <span class="p">};</span>
        <span class="k">let</span> <span class="n">socket</span> <span class="o">=</span> <span class="n">sockets</span><span class="py">.get_mut</span><span class="p">::</span><span class="o">&lt;</span><span class="nn">tcp</span><span class="p">::</span><span class="n">Socket</span><span class="o">&gt;</span><span class="p">(</span><span class="n">handle</span><span class="p">);</span>
        <span class="n">socket</span><span class="nf">.close</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h1 id="testing--conclusion">Testing &amp; Conclusion</h1>

<p>From my linux host, I’ve then created a tap device:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>modprobe tun
<span class="nb">sudo </span>ip tuntap add dev tap0 mode tap user <span class="s2">"</span><span class="nv">$USER</span><span class="s2">"</span>
<span class="nb">sudo </span>ip addr add 10.0.3.1/24 dev tap0
</code></pre></div></div>

<p>And put in on the <code class="language-plaintext highlighter-rouge">10.0.3.1/24</code> network. On the xv6 device I’ve then hardcoded an ip and MAC address (I don’t have a dhcp server running on my host):</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="n">MY_MAC_BYTES</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">6</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0x02</span><span class="p">,</span> <span class="mi">0xaa</span><span class="p">,</span> <span class="mi">0xbb</span><span class="p">,</span> <span class="mi">0xcc</span><span class="p">,</span> <span class="mi">0xdd</span><span class="p">,</span> <span class="mi">0xee</span><span class="p">];</span>
<span class="k">const</span> <span class="n">MY_IP_V4</span><span class="p">:</span> <span class="n">Ipv4Address</span> <span class="o">=</span> <span class="nn">Ipv4Address</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
</code></pre></div></div>

<p>And asked ChatGPT to write a simple HTTP server using the syscalls written above:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//server.c, generated by ChatGPT 5.1</span>
<span class="cp">#include</span> <span class="cpf">"types.h"</span><span class="cp">
#include</span> <span class="cpf">"stat.h"</span><span class="cp">
#include</span> <span class="cpf">"user.h"</span><span class="cp">
</span>
<span class="c1">// Returns 1 if request body == "close"</span>
<span class="k">static</span> <span class="kt">int</span>
<span class="nf">body_is_close</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span>
<span class="p">{</span>
  <span class="k">if</span><span class="p">(</span><span class="n">n</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>

  <span class="c1">// find "\r\n\r\n" manually</span>
  <span class="kt">int</span> <span class="n">i</span><span class="p">;</span>
  <span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">+</span><span class="mi">3</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">){</span>
    <span class="k">if</span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>   <span class="o">==</span> <span class="sc">'\r'</span> <span class="o">&amp;&amp;</span>
       <span class="n">buf</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'\n'</span> <span class="o">&amp;&amp;</span>
       <span class="n">buf</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'\r'</span> <span class="o">&amp;&amp;</span>
       <span class="n">buf</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">3</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'\n'</span><span class="p">)</span>
    <span class="p">{</span>
      <span class="c1">// body begins after the blank line</span>
      <span class="kt">int</span> <span class="n">body_start</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">4</span><span class="p">;</span>

      <span class="c1">// skip spaces/newlines</span>
      <span class="k">while</span><span class="p">(</span><span class="n">body_start</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">&amp;&amp;</span>
           <span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="n">body_start</span><span class="p">]</span> <span class="o">==</span> <span class="sc">' '</span> <span class="o">||</span>
            <span class="n">buf</span><span class="p">[</span><span class="n">body_start</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'\n'</span> <span class="o">||</span>
            <span class="n">buf</span><span class="p">[</span><span class="n">body_start</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'\r'</span><span class="p">))</span>
        <span class="n">body_start</span><span class="o">++</span><span class="p">;</span>

      <span class="c1">// check for "close"</span>
      <span class="k">if</span><span class="p">(</span><span class="n">body_start</span> <span class="o">+</span> <span class="mi">5</span> <span class="o">&lt;=</span> <span class="n">n</span> <span class="o">&amp;&amp;</span>
         <span class="n">buf</span><span class="p">[</span><span class="n">body_start</span><span class="p">]</span>   <span class="o">==</span> <span class="sc">'c'</span> <span class="o">&amp;&amp;</span>
         <span class="n">buf</span><span class="p">[</span><span class="n">body_start</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'l'</span> <span class="o">&amp;&amp;</span>
         <span class="n">buf</span><span class="p">[</span><span class="n">body_start</span><span class="o">+</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'o'</span> <span class="o">&amp;&amp;</span>
         <span class="n">buf</span><span class="p">[</span><span class="n">body_start</span><span class="o">+</span><span class="mi">3</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'s'</span> <span class="o">&amp;&amp;</span>
         <span class="n">buf</span><span class="p">[</span><span class="n">body_start</span><span class="o">+</span><span class="mi">4</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'e'</span><span class="p">)</span>
        <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>

      <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// found body, but not "close"</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// didn't find end of headers</span>
<span class="p">}</span>

<span class="kt">int</span>
<span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
  <span class="k">for</span><span class="p">(;;){</span>
    <span class="c1">// Put the TCP socket back into LISTEN state each iteration.</span>
    <span class="c1">// On first iteration the socket is Closed; later it is Closed again</span>
    <span class="c1">// after net_close().</span>
    <span class="k">if</span><span class="p">(</span><span class="n">net_listen</span><span class="p">(</span><span class="mi">80</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">){</span>
      <span class="n">printf</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="s">"httpd: net_listen(80) failed</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
      <span class="n">exit</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="n">printf</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">"httpd: listening on port 80</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

    <span class="c1">// Wait until the TCP connection reaches Established</span>
    <span class="k">while</span><span class="p">(</span><span class="n">net_accept</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
      <span class="n">sleep</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span>

    <span class="n">printf</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">"httpd: connection established</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

    <span class="kt">char</span> <span class="n">buf</span><span class="p">[</span><span class="mi">512</span><span class="p">];</span>
    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">net_recv</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">buf</span><span class="p">));</span>

    <span class="k">if</span><span class="p">(</span><span class="n">n</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span>
      <span class="n">printf</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">"httpd: received %d bytes</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span>

    <span class="k">if</span><span class="p">(</span><span class="n">body_is_close</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="n">n</span><span class="p">)){</span>
      <span class="c1">// Shutdown reply</span>
      <span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">hdr</span><span class="p">[]</span> <span class="o">=</span>
        <span class="s">"HTTP/1.0 200 OK</span><span class="se">\r\n</span><span class="s">"</span>
        <span class="s">"Content-Length: 13</span><span class="se">\r\n</span><span class="s">"</span>
        <span class="s">"Content-Type: text/plain</span><span class="se">\r\n</span><span class="s">"</span>
        <span class="s">"</span><span class="se">\r\n</span><span class="s">"</span><span class="p">;</span>
      <span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">body</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"shutting down</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="c1">// 13 bytes</span>

      <span class="n">net_send</span><span class="p">((</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">hdr</span><span class="p">,</span>  <span class="k">sizeof</span><span class="p">(</span><span class="n">hdr</span><span class="p">)</span>  <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
      <span class="n">net_send</span><span class="p">((</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">body</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">body</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
      <span class="n">net_close</span><span class="p">();</span>

      <span class="n">printf</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">"httpd: close command received, exiting.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
      <span class="n">exit</span><span class="p">();</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="c1">// Normal reply</span>
      <span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">hdr</span><span class="p">[]</span> <span class="o">=</span>
        <span class="s">"HTTP/1.0 200 OK</span><span class="se">\r\n</span><span class="s">"</span>
        <span class="s">"Content-Length: 13</span><span class="se">\r\n</span><span class="s">"</span>
        <span class="s">"Content-Type: text/plain</span><span class="se">\r\n</span><span class="s">"</span>
        <span class="s">"</span><span class="se">\r\n</span><span class="s">"</span><span class="p">;</span>
      <span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">body</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"hi from user</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="c1">// 13 bytes</span>

      <span class="n">net_send</span><span class="p">((</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">hdr</span><span class="p">,</span>  <span class="k">sizeof</span><span class="p">(</span><span class="n">hdr</span><span class="p">)</span>  <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
      <span class="n">net_send</span><span class="p">((</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">body</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">body</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
      <span class="n">net_close</span><span class="p">();</span>

    <span class="p">}</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This server returns a simple message when a GET request is sent, and shuts down when someones POSTs “close”.</p>

<p><img src="/assets/posts/xv6-networking/final_test.png" alt="final test" /></p>
<blockquote>
  <p><em>On the left: qemu running xv6 with rust networking, on the right: linux host connecting to the server. The final <code class="language-plaintext highlighter-rouge">ls</code> output shows that sending a <code class="language-plaintext highlighter-rouge">close</code> in the post payload shuts down the server.</em></p>
</blockquote>

<h1 id="code--patch">Code &amp; Patch</h1>

<p>The code is accessible at <a href="https://github.com/Ferryistaken/xv6-public">github.com/Ferryistaken/xv6-public</a>, and a full patch is pasted below.</p>

<p><a href="/assets/posts/xv6-networking/patch.diff">⤓ patch.diff</a></p>

<h3 id="thanks--acknowledgements">Thanks &amp; Acknowledgements</h3>

<p>Special thanks to my <em>CS3210: Design of Operating Systems</em> professor <a href="https://mikespecter.com/">Michael Specter</a>, <a href="https://xiayingp.gitbook.io/build_a_os">this</a> OS guide, and the <a href="https://github.com/smoltcp-rs/smoltcp">smoltcp</a> dev team.</p>]]></content><author><name>Alessandro Ferrari</name><email>alessandroferrari@gatech.edu</email></author><category term="linux" /><category term="os" /><category term="hardware" /><summary type="html"><![CDATA[Writing the networking stack for xv6 in Rust]]></summary></entry><entry><title type="html">Rust Inside xv6</title><link href="https://alessandroferrari.live/rust-inside-xv6/" rel="alternate" type="text/html" title="Rust Inside xv6" /><published>2025-11-26T10:59:13+00:00</published><updated>2025-11-26T10:59:13+00:00</updated><id>https://alessandroferrari.live/rust-inside-xv6</id><content type="html" xml:base="https://alessandroferrari.live/rust-inside-xv6/"><![CDATA[<h2 id="writing-a-rust-module-for-the-xv6-kernel-x86">Writing a Rust module for the xv6 kernel (x86)</h2>
<p>In this short guide I will go over adding Rust “modules” to a base xv6 kernel for the x86 target (although it could be adapted to RISC-V with minimal changes).</p>

<p>While xv6 doesn’t really support “modules” in the same way that the Linux kernel does, here I describe a module simply as a subsystem of the kernel that in this case will be completely done in Rust.</p>

<h3 id="why">Why?</h3>
<p>With this approach you gain memory safety in all the code you abstract to Rust, and only stay unsafe in:</p>

<ol>
  <li>The handoff of data from C to Rust and back.</li>
  <li>MMIO and DMA whenever it’s used.</li>
</ol>

<p>Gaining:</p>

<ol>
  <li>No out-of-bounds memory access.</li>
  <li>No dangling pointers.</li>
  <li>No double-free.</li>
</ol>

<h3 id="setup">Setup</h3>

<p>This approach uses:</p>

<ul>
  <li>A standalone Rust crate (<code class="language-plaintext highlighter-rouge">rustmod/</code>)</li>
  <li>A static library (<code class="language-plaintext highlighter-rouge">librustmod.a1</code>)</li>
  <li>CMake glue to build Rust before linking the kernel</li>
  <li>A minimal C → Rust → C FFI interface</li>
</ul>

<h3 id="rust-crate">Rust crate</h3>

<p>Inside of the root xv6 project, create a <code class="language-plaintext highlighter-rouge">rustmod</code> crate:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir </span>rustmod
<span class="nb">cd </span>rustmod
cargo init <span class="nt">--lib</span>
</code></pre></div></div>

<h4 id="cargo">Cargo</h4>

<p>And make this your <code class="language-plaintext highlighter-rouge">Cargo.toml</code>:</p>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">[</span><span class="n">package</span><span class="k">]</span>
<span class="n">name</span> <span class="o">=</span><span class="w"> </span><span class="s">"rustmod"</span>
<span class="n">version</span> <span class="o">=</span><span class="w"> </span><span class="s">"0.1.0"</span>
<span class="n">edition</span> <span class="o">=</span><span class="w"> </span><span class="s">"2021"</span>

<span class="k">[</span><span class="n">lib</span><span class="k">]</span>
<span class="n">crate-type</span> <span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s">"staticlib"</span><span class="p">]</span>

<span class="k">[</span><span class="n">profile</span><span class="k">.</span><span class="n">release</span><span class="k">]</span>
<span class="n">panic</span> <span class="o">=</span><span class="w"> </span><span class="s">"abort"</span>
<span class="n">lto</span> <span class="o">=</span><span class="w"> </span><span class="kc">true</span>
<span class="n">codegen-units</span> <span class="o">=</span><span class="w"> </span><span class="mi">1</span>
</code></pre></div></div>

<p>And make this your <code class="language-plaintext highlighter-rouge">.cargo/config.toml</code></p>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">[</span><span class="n">build</span><span class="k">]</span>
<span class="n">target</span> <span class="o">=</span><span class="w"> </span><span class="s">"i686-unknown-linux-gnu"</span>

<span class="k">[</span><span class="n">target</span><span class="k">.</span><span class="n">i686-unknown-linux-gnu</span><span class="k">]</span>
<span class="n">linker</span> <span class="o">=</span><span class="w"> </span><span class="s">"gcc"</span>
<span class="n">rustflags</span> <span class="o">=</span><span class="w"> </span><span class="p">[</span>
  <span class="s">"-C"</span><span class="p">,</span> <span class="s">"relocation-model=static"</span><span class="p">,</span>
  <span class="s">"-C"</span><span class="p">,</span> <span class="s">"link-arg=-m32"</span><span class="p">,</span>
  <span class="s">"-C"</span><span class="p">,</span> <span class="s">"target-feature=-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2"</span><span class="p">,</span>
  <span class="s">"-C"</span><span class="p">,</span> <span class="s">"soft-float"</span><span class="p">,</span>
<span class="p">]</span>
</code></pre></div></div>
<p>This will make cargo to emit a .a file suitable for linking with the xv6 kernel.</p>

<h4 id="rust">Rust</h4>

<p>Let’s write a basic Rust function to test that everything is working correctly:</p>

<p><code class="language-plaintext highlighter-rouge">rustmod/src/lib.rs</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#![no_std]

use core::panic::PanicInfo;

extern "C" {
    fn c_kputs(msg: *const u8);
}

#[no_mangle]
pub extern "C" fn rust_test() {
    static MSG: &amp;[u8] = b"Rust support loaded\n\0";

    unsafe {
        c_kputs(MSG.as_ptr());
    }
}

#[panic_handler]
fn panic(_info: &amp;PanicInfo) -&gt; ! {
    loop {}
}
</code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">#![no_std]</code> is required because the kernel provides no standard library.</li>
  <li><code class="language-plaintext highlighter-rouge">#[no_mangle]</code> and <code class="language-plaintext highlighter-rouge">extern "C"</code> ensure ABI compatibility with xv6.</li>
  <li><code class="language-plaintext highlighter-rouge">panic = "abort"</code> avoids Rust’s complex unwinding.</li>
</ul>

<h3 id="c-glue">C Glue</h3>

<p>Inside <code class="language-plaintext highlighter-rouge">kernel/include/defs.h</code> add:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// external rust</span>
<span class="k">extern</span> <span class="kt">void</span> <span class="nf">rust_test</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
</code></pre></div></div>

<p>And in <code class="language-plaintext highlighter-rouge">console.c</code> add:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span>
<span class="nf">c_kputs</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">s</span><span class="p">)</span>
<span class="p">{</span>
  <span class="n">cprintf</span><span class="p">(</span><span class="s">"%s"</span><span class="p">,</span> <span class="n">s</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Finally, in <code class="language-plaintext highlighter-rouge">main()</code> add the <code class="language-plaintext highlighter-rouge">rust_test();</code> function:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span>
<span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
  <span class="p">...</span>
  <span class="n">userinit</span><span class="p">();</span>
  <span class="n">rust_test</span><span class="p">();</span>
  <span class="n">mpmain</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="building--linking">Building &amp; Linking</h3>

<p>The xv6 kernel is built using <code class="language-plaintext highlighter-rouge">kernel/CMakeLists.txt</code>. This file has to be modified such that it:</p>

<ul>
  <li>Builds the Rust crate via a custom target.</li>
  <li>Links the resulting static library into the kernel ELF.</li>
  <li>Adds correct dependencies so Rust always builds before the kernel.</li>
</ul>

<h4 id="building-rust-target-in-cmake">Building Rust target in CMake</h4>

<p>Add this to <code class="language-plaintext highlighter-rouge">kernel/CMakeLists.txt</code></p>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Path to the rust staticlib
</span><span class="err">set(RUSTMOD_DIR</span> <span class="err">${CMAKE_SOURCE_DIR}/rustmod)</span>
<span class="err">set(RUSTMOD_TARGET</span> <span class="err">i686-unknown-linux-gnu)</span>
<span class="err">set(RUSTMOD_LIB</span> <span class="err">${RUSTMOD_DIR}/target/${RUSTMOD_TARGET}/release/librustmod.a)</span>

<span class="c"># Build the Rust kernel module with cargo
</span><span class="err">add_custom_target(rustmod_build</span>
    <span class="err">COMMAND</span> <span class="err">cargo</span> <span class="err">build</span> <span class="err">--release</span>
    <span class="err">WORKING_DIRECTORY</span> <span class="err">${RUSTMOD_DIR}</span>
    <span class="err">BYPRODUCTS</span> <span class="err">${RUSTMOD_LIB}</span>
    <span class="err">COMMENT</span> <span class="s2">"Building Rust kernel module"</span>
<span class="err">)</span>
</code></pre></div></div>

<p>Which defines:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cargo build <span class="nt">--release</span> <span class="nt">--target</span> i686-unknown-linux-gnu
</code></pre></div></div>

<p>To output <code class="language-plaintext highlighter-rouge">librustmod.a</code>.</p>

<h4 id="linking-into-xv6-kernel">Linking into xv6 kernel</h4>

<p>Find wherever you’re linking the kernel and all kernel objects:</p>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">COMMAND</span> <span class="err">ld</span> <span class="err">-m</span> <span class="err">elf_i386</span> <span class="err">-nostdlib</span> <span class="err">-T</span> <span class="err">kernel.ld</span> <span class="err">...</span>
        <span class="err">${kernel_OBJECTS}</span> <span class="err">-b</span> <span class="err">binary</span> <span class="err">initcode</span> <span class="err">entryother</span>
</code></pre></div></div>

<p>And change it with:</p>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">COMMAND</span> <span class="err">ld</span> <span class="err">-m</span> <span class="err">elf_i386</span> <span class="err">-nostdlib</span> <span class="err">-T</span> <span class="err">${CMAKE_CURRENT_SOURCE_DIR}/kernel.ld</span> <span class="err">-o</span> <span class="err">kernel</span>
        <span class="err">${kernel_OBJECTS}</span> <span class="err">${RUSTMOD_LIB}</span> <span class="err">-b</span> <span class="err">binary</span> <span class="err">initcode</span> <span class="err">entryother</span>
<span class="err">DEPENDS</span>
        <span class="err">...</span>
        <span class="err">rustmod_build</span>
</code></pre></div></div>

<h2 id="testing-functionality">Testing Functionality</h2>

<p>Finally, when building and starting xv6, you should see:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SeaBIOS <span class="o">(</span>version 1.15.0-1<span class="o">)</span>


iPXE <span class="o">(</span>https://ipxe.org<span class="o">)</span> 00:03.0 CA00 PCI2.10 PnP PMM+1FF8B4A0+1FECB4A0 CA00



Booting from Hard Disk..xv6...
Rust support loaded.             &lt;<span class="nt">--</span> From Rust!
cpu0: starting 0
sb: size 20000 nblocks 19937 ninodes 200 nlog 30 logstart 2 inodestart 32 bmap start 58
init: starting sh
<span class="nv">$ </span><span class="nb">ls</span>
<span class="nb">.</span>              1 1 512
..             1 1 512
init           2 2 46876
README         2 3 2170
sh             2 4 54604
<span class="nb">ls             </span>2 5 48684
<span class="nb">cat            </span>2 6 47016
<span class="nb">rm             </span>2 7 46448
test_sha256    2 8 48236
test_aes256    2 9 47872
console        3 10 0
<span class="err">$</span>
</code></pre></div></div>]]></content><author><name>Alessandro Ferrari</name><email>alessandroferrari@gatech.edu</email></author><category term="linux" /><category term="os" /><category term="hardware" /><summary type="html"><![CDATA[Writing Rust modules for the x86 xv6 kernel]]></summary></entry><entry><title type="html">How to install the Displaylink drivers on Fedora 40</title><link href="https://alessandroferrari.live/install-displaylink-fedora39/" rel="alternate" type="text/html" title="How to install the Displaylink drivers on Fedora 40" /><published>2024-04-20T09:59:13+00:00</published><updated>2024-04-20T09:59:13+00:00</updated><id>https://alessandroferrari.live/install-displaylink-fedora39</id><content type="html" xml:base="https://alessandroferrari.live/install-displaylink-fedora39/"><![CDATA[<h1 id="setup">Setup</h1>

<p>First off, make sure to remove previously install <code class="language-plaintext highlighter-rouge">displaylink</code> and <code class="language-plaintext highlighter-rouge">evdi</code> packages.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo dnf remove displaylink 'evdi-*'
</code></pre></div></div>

<p>And install tools to build packages from source.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo dnf groupinstall 'Development Tools'
</code></pre></div></div>

<h1 id="building-evdi">Building evdi</h1>

<p>Now build and install the evdi modules.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/DisplayLink/evdi
cd evdi
export CPLUS_INCLUDE_PATH="/usr/include/python3.12:$CPLUS_INCLUDE_PATH"
make
sudo make install
</code></pre></div></div>

<h1 id="installing-displaylink">Installing displaylink</h1>

<p>Now, download the right displaylink RPM version from <a href="https://github.com/displaylink-rpm/displaylink-rpm/releases">the displaylink github</a>.</p>

<p>Both the built and src rpm should work, but this guide is going to use the <code class="language-plaintext highlighter-rouge">x86_64</code> version.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo dnf install '/path/to/rpm/fedora-40-displaylink-1.14.4-1.github_evdi.x86_64.rpm
</code></pre></div></div>

<p>Finally reboot. Now displaylink should work. This guide works for Fedora 38, 39, and possibly any new version, given that you pull the latest evdi version, and download the correct displaylink driver rpm.</p>]]></content><author><name>Alessandro Ferrari</name><email>alessandroferrari@gatech.edu</email></author><category term="linux" /><category term="os" /><category term="hardware" /><summary type="html"><![CDATA[Setup]]></summary></entry><entry><title type="html">Embedding book highlights onto a vector space</title><link href="https://alessandroferrari.live/book-highlights/" rel="alternate" type="text/html" title="Embedding book highlights onto a vector space" /><published>2023-11-20T09:57:43+00:00</published><updated>2023-11-20T09:57:43+00:00</updated><id>https://alessandroferrari.live/book-highlights</id><content type="html" xml:base="https://alessandroferrari.live/book-highlights/"><![CDATA[<p><img src="/assets/posts/book-highlights/book-highlight-diagram.png" alt="book-highlight-diagram.png" /></p>

<p>Inspired by <a href="https://sawyerh.medium.com/building-a-scrappy-semantic-search-for-my-reading-highlights-5bb2bcaf25da">this post</a>, I chose to create my own solution to automatically export my book highlights on <a href="https://books.alessandroferrari.live">a website</a> and map them onto a vector space in order to have features such as semantic search.</p>

<p>The process is all serverless, free, and automated. As a bonus, I also get 3 highlights sent to my inbox every day. And again, my total cost for this whole infrastructure is $0.</p>

<p>Here’s the final result: <a href="https://books.alessandroferrari.live">books.alessandroferrari.live</a></p>

<p>And a live representation of my highlights:</p>

<iframe src="https://books.alessandroferrari.live/plotly-out" width="100%" height="600" style="border:none;"></iframe>

<p>The whole system is structured in such a way that every time the google sheet gets updated, the website reflects it after just a few minutes. The system is open an expandable, and features such as <a href="#email-quotes-to-your-inbox">emailing yourself your own quotes</a> can be implemented trivially.</p>

<h2 id="exporting-book-highlights-onto-a-website">Exporting book highlights onto a website</h2>

<p>There are <a href="https://medium.com/@keisuke_w/how-to-copy-and-paste-kindle-highlights-beyond-the-export-limits-8df9c0119981#:~:text=If%20you'd%20like%20to,It%20starts%20downloading.">plenty of resources</a> that explain how to automatically export highlights taken on platforms such as kindle or iBook as a csv format, so I won’t cover that step of the process. It only takes 5 minutes per book to do it manually anyways, and the process varies drastically depending on which reading app you use, for this reason I haven’t included any book exporting pipeline in my system.</p>

<p>The important part is: <strong>all your highlights should be held in a google sheet formatted like this</strong>:</p>

<p><img src="/assets/posts/book-highlights/book-highlight-csv.png" alt="book-highlight-csv.png" /></p>

<p>All I keep is the actual highlight and the isbn. <strong>Anything else is just useless data to move around</strong>. I have been thinking about keeping highlight notes in this csv as well, however I like the idea of the website being pure quotes, with my own thoughts on those quotes being stored somewhere else.</p>

<p>The next step is to somehow put these quotes onto a website. Going from this google sheet to a published website is a 4 step process:</p>
<h1 id="steps">Steps</h1>

<ol>
  <li>Getting the data as a csv file</li>
  <li>Break up and format the data in a way that is understandable by jekyll</li>
  <li>Generate embeddings from this data</li>
  <li>Deploy the generated site on a hosting service</li>
</ol>

<h3 id="getting-the-data">Getting the Data</h3>

<p>I found out recently that you can just curl google sheets documents as csv files with this command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-L</span> &lt;google sheet url&gt; <span class="nt">-o</span> sheet.csv
</code></pre></div></div>

<p>This completes part 1. The only caveat is that the google sheets needs to be readable by anyone with the link, which isn’t something that I particularly care about as everything on that sheet will already be published onto the website.</p>

<h3 id="formatting-the-data">Formatting the data</h3>

<p>Since <a href="https://alessandroferrari.live/host-a-blog-for-free/">I already use Jekyll for the main section of my website</a> I chose to use jekyll for this section too. It’s simple and I’m somewhat familiar with it, however this same process could be replicated with any SSG (or even a webdev framework).</p>

<p>I have a simple python script that generates the jekyll pages based on the url of the spreadsheet. It also adds the authors, titles, cover images, and publishing dates based on google books API. You can find the script <a href="https://github.com/Ferryistaken/books/blob/master/gethighlights.py">here</a>.</p>

<p>For the script to work, make sure that you google books API key is in the environment variable <code class="language-plaintext highlighter-rouge">GOOGLE_API_KEY</code>.</p>

<p>The script will generate markdown files of this format:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>---
layout: post
title: "The Sailor Who Fell from Grace with the Sea"
authors: "Yukio Mishima"
publisher: "Vintage"
publishedDate: "1994-05-31"
coverImage: "http://books.google.com/books/content?id=B-eBAAAAIAAJ&amp;printsec=frontcover&amp;img=1&amp;zoom=1&amp;source=gbs_api"
highlights:
  - "While Noboru wandered through private dreams Tsukazaki stood at Fusako’s side, and the heat of his body in the sultry chart room was beginning to oppress her: when the parasol she had leaned against a desk clattered suddenly to the floor, she felt as if she herself, fainting, had fallen."
  - "He hadn’t been able to explain his ideas of glory and death, or the longing and the melancholy pent up in his chest, or the other dark passions choking in the ocean’s swell."
  - "He ..."
---
</code></pre></div></div>

<p>And this is the <code class="language-plaintext highlighter-rouge">post</code> layout that this script uses:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>---
layout: default
---

<span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="nt">&lt;html&gt;</span>
<span class="nt">&lt;head&gt;</span>
    <span class="nt">&lt;title&gt;</span>Embedding book highlights onto a vector space<span class="nt">&lt;/title&gt;</span>
    <span class="nt">&lt;script&gt;</span>
    <span class="kd">function</span> <span class="nf">copyToClipboard</span><span class="p">(</span><span class="nx">elementId</span><span class="p">,</span> <span class="nx">element</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">var</span> <span class="nx">url</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="dl">'</span><span class="s1">#</span><span class="dl">'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">#</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">elementId</span><span class="p">;</span>
        <span class="nb">navigator</span><span class="p">.</span><span class="nx">clipboard</span><span class="p">.</span><span class="nf">writeText</span><span class="p">(</span><span class="nx">url</span><span class="p">).</span><span class="nf">then</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
            <span class="nx">element</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="dl">"</span><span class="s2">clicked</span><span class="dl">"</span><span class="p">);</span>

            <span class="nf">setTimeout</span><span class="p">(</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
                <span class="nx">element</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nf">remove</span><span class="p">(</span><span class="dl">"</span><span class="s2">clicked</span><span class="dl">"</span><span class="p">);</span>
            <span class="p">},</span> <span class="mi">100</span><span class="p">);</span>
        <span class="p">}).</span><span class="k">catch</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Could not copy text: </span><span class="dl">'</span><span class="p">,</span> <span class="nx">err</span><span class="p">);</span>
        <span class="p">});</span>
    <span class="p">}</span>
    <span class="nt">&lt;/script&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">style=</span><span class="s">'text-align: center;'</span><span class="nt">&gt;</span>
        <span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">''</span> <span class="na">alt=</span><span class="s">'Embedding book highlights onto a vector space'</span> <span class="na">style=</span><span class="s">'max-width: 80%;'</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/div&gt;</span>

    <span class="nt">&lt;h2</span> <span class="na">style=</span><span class="s">'text-align: center; font-weight: bold; font-size: 24px;'</span><span class="nt">&gt;</span>Embedding book highlights onto a vector space<span class="nt">&lt;/h2&gt;</span>
    <span class="nt">&lt;p</span> <span class="na">style=</span><span class="s">'text-align: center;'</span><span class="nt">&gt;&lt;br&gt;&lt;/p&gt;</span>

    <span class="nt">&lt;h3</span> <span class="na">style=</span><span class="s">'text-align: center;'</span><span class="nt">&gt;</span>Highlights<span class="nt">&lt;/h3&gt;</span>
    <span class="nt">&lt;ul</span> <span class="na">style=</span><span class="s">"list-style-type: none; text-align: center; padding: 0;"</span><span class="nt">&gt;</span>
        
    <span class="nt">&lt;/ul&gt;</span>

    <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"/"</span><span class="nt">&gt;</span>Back to Home<span class="nt">&lt;/a&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>

<p>Already, this creates a perfectly functioning website in which all of your book highlights will be displayed. I wanted to go a step further:</p>
<h3 id="generating-embeddings-from-the-book-highlights">Generating embeddings from the book highlights</h3>

<p>Now to part 3: generating embeddings for features such as clustering and semantic search.</p>

<p>I have a second script, <code class="language-plaintext highlighter-rouge">embeddings.py</code> which takes in the downloaded google sheet and generates embeddings using <a href="https://huggingface.co/sentence-transformers"><code class="language-plaintext highlighter-rouge">sentence-transformers</code></a>. The best performing model that I have found is <a href="https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2"><code class="language-plaintext highlighter-rouge">all-MiniLM-L6-v2</code></a>, a model that maps sentences and paragraphs to a 384 dimensional dense vector space.</p>

<p>This is the script to generate embeddings:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Loading libraries</span><span class="sh">"</span><span class="p">)</span>

<span class="kn">import</span> <span class="n">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="kn">from</span> <span class="n">sentence_transformers</span> <span class="kn">import</span> <span class="n">SentenceTransformer</span>
<span class="kn">import</span> <span class="n">json</span>
<span class="kn">import</span> <span class="n">umap.umap_</span> <span class="k">as</span> <span class="n">umap</span>
<span class="kn">import</span> <span class="n">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="n">requests</span>
<span class="kn">import</span> <span class="n">os</span>

<span class="k">def</span> <span class="nf">get_book_title</span><span class="p">(</span><span class="n">isbn</span><span class="p">):</span>
    <span class="n">api_key</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">GOOGLE_API_KEY</span><span class="sh">'</span><span class="p">)</span>
    <span class="n">url</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">"</span><span class="s">https://www.googleapis.com/books/v1/volumes?q=isbn:</span><span class="si">{</span><span class="n">isbn</span><span class="si">}</span><span class="s">&amp;key=</span><span class="si">{</span><span class="n">api_key</span><span class="si">}</span><span class="sh">"</span>
    <span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">response</span><span class="p">.</span><span class="n">status_code</span> <span class="o">!=</span> <span class="mi">200</span><span class="p">:</span>
        <span class="k">return</span> <span class="sh">"</span><span class="s">Title Not Found</span><span class="sh">"</span>

    <span class="n">data</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="nf">json</span><span class="p">()</span>
    <span class="k">if</span> <span class="sh">"</span><span class="s">items</span><span class="sh">"</span> <span class="ow">in</span> <span class="n">data</span><span class="p">:</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">title</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="sh">"</span><span class="s">items</span><span class="sh">"</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="sh">"</span><span class="s">volumeInfo</span><span class="sh">"</span><span class="p">][</span><span class="sh">"</span><span class="s">title</span><span class="sh">"</span><span class="p">]</span>
            <span class="k">return</span> <span class="n">title</span>
        <span class="nf">except </span><span class="p">(</span><span class="nb">IndexError</span><span class="p">,</span> <span class="nb">KeyError</span><span class="p">):</span>
            <span class="k">return</span> <span class="sh">"</span><span class="s">Title Not Found</span><span class="sh">"</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="sh">"</span><span class="s">Title Not Found</span><span class="sh">"</span>

<span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Loading Model</span><span class="sh">"</span><span class="p">)</span>

<span class="c1"># Load the model
</span><span class="n">model</span> <span class="o">=</span> <span class="nc">SentenceTransformer</span><span class="p">(</span><span class="sh">"</span><span class="s">all-MiniLM-L6-v2</span><span class="sh">"</span><span class="p">)</span>
<span class="n">model</span><span class="p">.</span><span class="n">max_seq_length</span> <span class="o">=</span> <span class="mi">256</span>

<span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Loading data</span><span class="sh">"</span><span class="p">)</span>

<span class="c1"># Read the CSV file
</span><span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="nf">read_csv</span><span class="p">(</span><span class="sh">'</span><span class="s">sheet.csv</span><span class="sh">'</span><span class="p">)</span>

<span class="c1"># Maintain the original 'index' column
</span><span class="n">df</span><span class="p">[</span><span class="sh">'</span><span class="s">original_index</span><span class="sh">'</span><span class="p">]</span> <span class="o">=</span> <span class="n">df</span><span class="p">.</span><span class="n">index</span>

<span class="c1"># Group by ISBN and create indices within each group
</span><span class="n">df</span><span class="p">[</span><span class="sh">'</span><span class="s">group_index</span><span class="sh">'</span><span class="p">]</span> <span class="o">=</span> <span class="n">df</span><span class="p">.</span><span class="nf">groupby</span><span class="p">(</span><span class="sh">'</span><span class="s">isbn</span><span class="sh">'</span><span class="p">).</span><span class="nf">cumcount</span><span class="p">()</span>

<span class="c1"># Extract sentences (highlights/quotes), ISBNs, and group indices
</span><span class="n">sentences</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="sh">'</span><span class="s">highlight</span><span class="sh">'</span><span class="p">].</span><span class="nf">tolist</span><span class="p">()</span>
<span class="n">isbns</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="sh">'</span><span class="s">isbn</span><span class="sh">'</span><span class="p">].</span><span class="nf">tolist</span><span class="p">()</span>
<span class="n">group_indices</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="sh">'</span><span class="s">group_index</span><span class="sh">'</span><span class="p">].</span><span class="nf">tolist</span><span class="p">()</span>

<span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Encoding data</span><span class="sh">"</span><span class="p">)</span>

<span class="c1"># Generate embeddings
</span><span class="n">embeddings</span> <span class="o">=</span> <span class="n">model</span><span class="p">.</span><span class="nf">encode</span><span class="p">(</span><span class="n">sentences</span><span class="p">,</span> <span class="n">normalize_embeddings</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>

<span class="c1"># Convert embeddings to list for JSON compatibility and save to JSON
</span><span class="n">embeddings_list</span> <span class="o">=</span> <span class="n">embeddings</span><span class="p">.</span><span class="nf">tolist</span><span class="p">()</span>
<span class="n">data</span> <span class="o">=</span> <span class="p">{</span>
    <span class="sh">"</span><span class="s">sentences</span><span class="sh">"</span><span class="p">:</span> <span class="n">sentences</span><span class="p">,</span> 
    <span class="sh">"</span><span class="s">embeddings</span><span class="sh">"</span><span class="p">:</span> <span class="n">embeddings_list</span><span class="p">,</span> 
    <span class="sh">"</span><span class="s">isbns</span><span class="sh">"</span><span class="p">:</span> <span class="n">isbns</span><span class="p">,</span> 
    <span class="sh">"</span><span class="s">group_indices</span><span class="sh">"</span><span class="p">:</span> <span class="n">group_indices</span>
<span class="p">}</span>

<span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Saving embeddings</span><span class="sh">"</span><span class="p">)</span>

<span class="k">with</span> <span class="nf">open</span><span class="p">(</span><span class="sh">"</span><span class="s">embeddings.json</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">w</span><span class="sh">"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="n">json</span><span class="p">.</span><span class="nf">dump</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="nb">file</span><span class="p">)</span>

<span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Generating visualization</span><span class="sh">"</span><span class="p">)</span>

<span class="c1"># Dimensionality reduction using UMAP
</span><span class="n">umap_embeddings</span> <span class="o">=</span> <span class="n">umap</span><span class="p">.</span><span class="nc">UMAP</span><span class="p">(</span><span class="n">n_neighbors</span><span class="o">=</span><span class="mi">15</span><span class="p">,</span> <span class="n">n_components</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">metric</span><span class="o">=</span><span class="sh">'</span><span class="s">cosine</span><span class="sh">'</span><span class="p">).</span><span class="nf">fit_transform</span><span class="p">(</span><span class="n">embeddings</span><span class="p">)</span>

<span class="n">markers</span> <span class="o">=</span> <span class="p">[</span><span class="sh">'</span><span class="s">o</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">s</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">^</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">D</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">*</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">x</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">+</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">&gt;</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">&lt;</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">p</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">h</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">H</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">X</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">d</span><span class="sh">'</span><span class="p">]</span>

<span class="c1"># Creating a color map and fetching titles for each unique ISBN
</span><span class="n">unique_isbns</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">set</span><span class="p">(</span><span class="n">isbns</span><span class="p">))</span>
<span class="n">isbn_to_title</span> <span class="o">=</span> <span class="p">{</span><span class="n">isbn</span><span class="p">:</span> <span class="nf">get_book_title</span><span class="p">(</span><span class="n">isbn</span><span class="p">)</span> <span class="k">for</span> <span class="n">isbn</span> <span class="ow">in</span> <span class="n">unique_isbns</span><span class="p">}</span>
<span class="n">colors</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">cm</span><span class="p">.</span><span class="nf">jet</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nf">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="nf">len</span><span class="p">(</span><span class="n">unique_isbns</span><span class="p">)))</span>
<span class="n">isbn_to_color</span> <span class="o">=</span> <span class="p">{</span><span class="n">isbn</span><span class="p">:</span> <span class="n">color</span> <span class="k">for</span> <span class="n">isbn</span><span class="p">,</span> <span class="n">color</span> <span class="ow">in</span> <span class="nf">zip</span><span class="p">(</span><span class="n">unique_isbns</span><span class="p">,</span> <span class="n">colors</span><span class="p">)}</span>

<span class="n">plt</span><span class="p">.</span><span class="n">style</span><span class="p">.</span><span class="nf">use</span><span class="p">(</span><span class="sh">'</span><span class="s">https://github.com/dhaitz/matplotlib-stylesheets/raw/master/pitayasmoothie-dark.mplstyle</span><span class="sh">'</span><span class="p">)</span>

<span class="c1"># Plotting
</span><span class="n">plt</span><span class="p">.</span><span class="nf">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span><span class="mi">10</span><span class="p">))</span>
<span class="n">legend_elements</span> <span class="o">=</span> <span class="p">[]</span>

<span class="k">for</span> <span class="n">idx</span><span class="p">,</span> <span class="n">isbn</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="n">unique_isbns</span><span class="p">):</span>
    <span class="n">indices</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">x</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="n">isbns</span><span class="p">)</span> <span class="k">if</span> <span class="n">x</span> <span class="o">==</span> <span class="n">isbn</span><span class="p">]</span>
    <span class="n">marker_style</span> <span class="o">=</span> <span class="n">markers</span><span class="p">[</span><span class="n">idx</span> <span class="o">%</span> <span class="nf">len</span><span class="p">(</span><span class="n">markers</span><span class="p">)]</span>  <span class="c1"># Cycle through markers
</span>
    <span class="c1"># Scatter plot
</span>    <span class="n">scatter</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="nf">scatter</span><span class="p">(</span><span class="n">umap_embeddings</span><span class="p">[</span><span class="n">indices</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">umap_embeddings</span><span class="p">[</span><span class="n">indices</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="n">s</span><span class="o">=</span><span class="mi">30</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">isbn_to_color</span><span class="p">[</span><span class="n">isbn</span><span class="p">],</span> <span class="n">marker</span><span class="o">=</span><span class="n">marker_style</span><span class="p">)</span>

    <span class="c1"># Calculating centroid of each cluster
</span>    <span class="n">centroid_x</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">mean</span><span class="p">(</span><span class="n">umap_embeddings</span><span class="p">[</span><span class="n">indices</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span>
    <span class="n">centroid_y</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">mean</span><span class="p">(</span><span class="n">umap_embeddings</span><span class="p">[</span><span class="n">indices</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span>

    <span class="c1"># Annotate with book title at the centroid
</span>    <span class="n">plt</span><span class="p">.</span><span class="nf">annotate</span><span class="p">(</span><span class="n">isbn_to_title</span><span class="p">[</span><span class="n">isbn</span><span class="p">],</span> <span class="p">(</span><span class="n">centroid_x</span><span class="p">,</span> <span class="n">centroid_y</span><span class="p">),</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">9</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="sh">'</span><span class="s">center</span><span class="sh">'</span><span class="p">,</span> <span class="n">va</span><span class="o">=</span><span class="sh">'</span><span class="s">center</span><span class="sh">'</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="sh">'</span><span class="s">white</span><span class="sh">'</span><span class="p">)</span>

    <span class="c1"># Create a custom legend entry for each ISBN
</span>    <span class="n">legend_elements</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">plt</span><span class="p">.</span><span class="nc">Line2D</span><span class="p">([</span><span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">marker</span><span class="o">=</span><span class="n">marker_style</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="sh">'</span><span class="s">w</span><span class="sh">'</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="n">isbn_to_title</span><span class="p">[</span><span class="n">isbn</span><span class="p">],</span> <span class="n">markersize</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">markerfacecolor</span><span class="o">=</span><span class="n">scatter</span><span class="p">.</span><span class="nf">get_facecolor</span><span class="p">()[</span><span class="mi">0</span><span class="p">],</span> <span class="n">linestyle</span><span class="o">=</span><span class="sh">'</span><span class="s">None</span><span class="sh">'</span><span class="p">))</span>

<span class="n">plt</span><span class="p">.</span><span class="nf">title</span><span class="p">(</span><span class="sh">'</span><span class="s">Vector Space (UMAP)</span><span class="sh">'</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">20</span><span class="p">)</span>

<span class="c1"># Add a legend and adjust its properties
</span><span class="n">legend</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="nf">legend</span><span class="p">(</span><span class="n">handles</span><span class="o">=</span><span class="n">legend_elements</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="sh">''</span><span class="p">,</span> <span class="n">loc</span><span class="o">=</span><span class="sh">'</span><span class="s">upper right</span><span class="sh">'</span><span class="p">,</span> <span class="n">bbox_to_anchor</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">),</span> <span class="n">bbox_transform</span><span class="o">=</span><span class="n">plt</span><span class="p">.</span><span class="nf">gcf</span><span class="p">().</span><span class="n">transFigure</span><span class="p">)</span>
<span class="n">legend</span><span class="p">.</span><span class="nf">get_frame</span><span class="p">().</span><span class="nf">set_alpha</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>  <span class="c1"># Adjust the opacity
</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">grid</span><span class="p">(</span><span class="bp">False</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">axis</span><span class="p">(</span><span class="sh">'</span><span class="s">off</span><span class="sh">'</span><span class="p">)</span>

<span class="c1"># Save the plot as a PNG file
</span><span class="n">plt</span><span class="p">.</span><span class="nf">savefig</span><span class="p">(</span><span class="sh">"</span><span class="s">umap.png</span><span class="sh">"</span><span class="p">,</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">300</span><span class="p">,</span> <span class="n">bbox_inches</span><span class="o">=</span><span class="sh">'</span><span class="s">tight</span><span class="sh">'</span><span class="p">)</span>
</code></pre></div></div>

<p>This script does two things:</p>
<ol>
  <li>Downloads the highlights and generates embeddings from it.</li>
  <li>Visualizes this embeddings through <a href="https://books.alessandroferrari.live/umap.png">UMAP</a>.</li>
</ol>

<p>This is enough to visualize all the highlights and cluster the books. As can be seen from the UMAP visualization, highlights from the same book cluster together and books on the same topic also cluster together, which is very interesting to see.</p>

<h3 id="semantic-search">Semantic Search</h3>

<p>The second part of this system is the script that takes user inputs and queries the vector space for similar highlights. This is done through the following serverless netilfy function:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">math</span> <span class="o">=</span> <span class="nf">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">mathjs</span><span class="dl">'</span><span class="p">);</span>

<span class="kd">let</span> <span class="nx">pipeline</span><span class="p">;</span>

<span class="p">(</span><span class="k">async </span><span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">transformers</span> <span class="o">=</span> <span class="k">await</span> <span class="k">import</span><span class="p">(</span><span class="dl">'</span><span class="s1">@xenova/transformers</span><span class="dl">'</span><span class="p">);</span>
  <span class="nx">pipeline</span> <span class="o">=</span> <span class="nx">transformers</span><span class="p">.</span><span class="nx">pipeline</span><span class="p">;</span>
<span class="p">})();</span>

<span class="nx">exports</span><span class="p">.</span><span class="nx">handler</span> <span class="o">=</span> <span class="k">async </span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="c1">// URL of the embeddings JSON file</span>
    <span class="kd">const</span> <span class="nx">embeddingsUrl</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">https://books.alessandroferrari.live/embeddings.json</span><span class="dl">'</span><span class="p">;</span>

    <span class="c1">// Fetch the embeddings data from the URL</span>
    <span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="k">await</span> <span class="nf">fetch</span><span class="p">(</span><span class="nx">embeddingsUrl</span><span class="p">);</span>
    <span class="kd">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">response</span><span class="p">.</span><span class="nf">json</span><span class="p">();</span>

    <span class="kd">const</span> <span class="nx">sentences</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">sentences</span><span class="p">;</span>
    <span class="kd">const</span> <span class="nx">embeddings</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">embeddings</span><span class="p">;</span>
    <span class="kd">const</span> <span class="nx">isbns</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">isbns</span><span class="p">;</span> <span class="c1">// Include the ISBNs</span>
    <span class="kd">const</span> <span class="nx">indexes</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">group_indices</span><span class="p">;</span>

    <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">isbns</span><span class="p">);</span>
    <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">indexes</span><span class="p">);</span>

    <span class="c1">// Extract query from event</span>
    <span class="kd">const</span> <span class="nx">query</span> <span class="o">=</span> <span class="nx">event</span><span class="p">.</span><span class="nx">queryStringParameters</span><span class="p">.</span><span class="nx">q</span><span class="p">;</span>

    <span class="c1">// Initialize the feature extraction pipeline</span>
    <span class="kd">let</span> <span class="nx">extractor</span> <span class="o">=</span> <span class="k">await</span> <span class="nf">pipeline</span><span class="p">(</span><span class="dl">'</span><span class="s1">feature-extraction</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">Xenova/all-MiniLM-L6-v2</span><span class="dl">'</span><span class="p">);</span>

    <span class="c1">// Calculate query embedding</span>
    <span class="kd">const</span> <span class="nx">queryEmbeddingOutput</span> <span class="o">=</span> <span class="k">await</span> <span class="nf">extractor</span><span class="p">(</span><span class="nx">query</span><span class="p">,</span> <span class="p">{</span> <span class="na">pooling</span><span class="p">:</span> <span class="dl">'</span><span class="s1">mean</span><span class="dl">'</span><span class="p">,</span> <span class="na">normalize</span><span class="p">:</span> <span class="kc">true</span> <span class="p">});</span>
    <span class="kd">const</span> <span class="nx">queryEmbedding</span> <span class="o">=</span> <span class="nx">queryEmbeddingOutput</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> <span class="c1">// Extract the embedding</span>

    <span class="kd">const</span> <span class="nx">arrayQueryEmbedding</span> <span class="o">=</span> <span class="nb">Array</span><span class="p">.</span><span class="k">from</span><span class="p">(</span><span class="nx">queryEmbedding</span><span class="p">.</span><span class="nx">data</span><span class="p">);</span>

    <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">arrayQueryEmbedding</span><span class="p">);</span>
    <span class="c1">//console.log(embeddings.every(embedding =&gt; Array.isArray(embedding))); // Should also be true</span>


    <span class="c1">// Calculate similarities</span>
    <span class="kd">let</span> <span class="nx">scores</span> <span class="o">=</span> <span class="nx">embeddings</span><span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="nx">embedding</span> <span class="o">=&gt;</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nx">math</span><span class="p">.</span><span class="nf">dot</span><span class="p">(</span><span class="nx">arrayQueryEmbedding</span><span class="p">,</span> <span class="nx">embedding</span><span class="p">)</span> <span class="o">/</span> 
               <span class="p">(</span><span class="nx">math</span><span class="p">.</span><span class="nf">norm</span><span class="p">(</span><span class="nx">arrayQueryEmbedding</span><span class="p">)</span> <span class="o">*</span> <span class="nx">math</span><span class="p">.</span><span class="nf">norm</span><span class="p">(</span><span class="nx">embedding</span><span class="p">));</span>
    <span class="p">});</span>

    <span class="c1">// Find top results</span>
    <span class="kd">let</span> <span class="nx">indices</span> <span class="o">=</span> <span class="nx">scores</span><span class="p">.</span><span class="nf">map</span><span class="p">((</span><span class="nx">score</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="nx">score</span><span class="p">,</span> <span class="nx">index</span><span class="p">]);</span>
    <span class="nx">indices</span><span class="p">.</span><span class="nf">sort</span><span class="p">((</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">b</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="nx">a</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="kd">let</span> <span class="nx">topResults</span> <span class="o">=</span> <span class="nx">indices</span><span class="p">.</span><span class="nf">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>

    <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">topResults</span><span class="p">);</span>

    <span class="c1">// Prepare response</span>
    <span class="kd">const</span> <span class="nx">results</span> <span class="o">=</span> <span class="nx">topResults</span><span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="nx">item</span> <span class="o">=&gt;</span> <span class="p">{</span>
        <span class="k">return</span> <span class="p">{</span>
            <span class="na">sentence</span><span class="p">:</span> <span class="nx">sentences</span><span class="p">[</span><span class="nx">item</span><span class="p">[</span><span class="mi">1</span><span class="p">]],</span>
            <span class="na">similarity</span><span class="p">:</span> <span class="nx">item</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>  <span class="c1">// Add the similarity score</span>
            <span class="na">isbn</span><span class="p">:</span> <span class="nx">isbns</span><span class="p">[</span><span class="nx">item</span><span class="p">[</span><span class="mi">1</span><span class="p">]],</span> <span class="c1">// Include the ISBN</span>
            <span class="na">index</span><span class="p">:</span> <span class="nx">indexes</span><span class="p">[</span><span class="nx">item</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span>
        <span class="p">};</span>
    <span class="p">});</span>

    <span class="k">return</span> <span class="p">{</span>
        <span class="na">statusCode</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span>
        <span class="na">body</span><span class="p">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">results</span><span class="p">)</span>
    <span class="p">};</span>

<span class="p">};</span>
</code></pre></div></div>

<p>It’s important to use the same embedding model, otherwise the query will be mapped differently and won’t be of much use.</p>

<p>Through this function I implemented <strong>semantic search</strong>, meaning that I can search for things such as “Stoicism in financial markets” or “Finding meaning through hard work” and these will be the responses:</p>

<p><img src="/assets/posts/book-highlights/semantic-search-demo1.png" alt="semantic-search-demo1.png" />
<img src="/assets/posts/book-highlights/semantic-search-demo2.png" alt="semantic-search-demo2.png" /></p>
<h3 id="interactively-visualizing-vector-embeddings">Interactively visualizing vector embeddings</h3>

<p>I however wanted to go a step further: I wanted to see a live representation of my highlights, so I wrote a simple python script that lets me see the vector space of the highlights in an interactive manner. Here is <code class="language-plaintext highlighter-rouge">live-embeddings.py</code>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">json</span>
<span class="kn">import</span> <span class="n">plotly.graph_objects</span> <span class="k">as</span> <span class="n">go</span>
<span class="kn">import</span> <span class="n">plotly.express</span> <span class="k">as</span> <span class="n">px</span>
<span class="kn">import</span> <span class="n">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="kn">import</span> <span class="n">umap.umap_</span> <span class="k">as</span> <span class="n">umap</span>
<span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="n">os</span>
<span class="kn">import</span> <span class="n">requests</span>
<span class="kn">import</span> <span class="n">textwrap</span>

<span class="c1"># Function to fetch book titles using Google Books API
</span><span class="k">def</span> <span class="nf">get_book_title</span><span class="p">(</span><span class="n">isbn</span><span class="p">):</span>
    <span class="n">api_key</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">GOOGLE_API_KEY</span><span class="sh">'</span><span class="p">)</span>
    <span class="n">url</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">"</span><span class="s">https://www.googleapis.com/books/v1/volumes?q=isbn:</span><span class="si">{</span><span class="n">isbn</span><span class="si">}</span><span class="s">&amp;key=</span><span class="si">{</span><span class="n">api_key</span><span class="si">}</span><span class="sh">"</span>
    <span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">response</span><span class="p">.</span><span class="n">status_code</span> <span class="o">!=</span> <span class="mi">200</span><span class="p">:</span>
        <span class="k">return</span> <span class="sh">"</span><span class="s">Title Not Found</span><span class="sh">"</span>

    <span class="n">data</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="nf">json</span><span class="p">()</span>
    <span class="k">if</span> <span class="sh">"</span><span class="s">items</span><span class="sh">"</span> <span class="ow">in</span> <span class="n">data</span><span class="p">:</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">title</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="sh">"</span><span class="s">items</span><span class="sh">"</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="sh">"</span><span class="s">volumeInfo</span><span class="sh">"</span><span class="p">][</span><span class="sh">"</span><span class="s">title</span><span class="sh">"</span><span class="p">]</span>
            <span class="k">return</span> <span class="n">title</span>
        <span class="nf">except </span><span class="p">(</span><span class="nb">IndexError</span><span class="p">,</span> <span class="nb">KeyError</span><span class="p">):</span>
            <span class="k">return</span> <span class="sh">"</span><span class="s">Title Not Found</span><span class="sh">"</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="sh">"</span><span class="s">Title Not Found</span><span class="sh">"</span>

<span class="c1"># Load data from embeddings.json
</span><span class="k">with</span> <span class="nf">open</span><span class="p">(</span><span class="sh">"</span><span class="s">embeddings.json</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">r</span><span class="sh">"</span><span class="p">)</span> <span class="k">as</span> <span class="nb">file</span><span class="p">:</span>
    <span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="nf">load</span><span class="p">(</span><span class="nb">file</span><span class="p">)</span>

<span class="n">embeddings</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="sh">"</span><span class="s">embeddings</span><span class="sh">"</span><span class="p">])</span>
<span class="n">sentences</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="sh">"</span><span class="s">sentences</span><span class="sh">"</span><span class="p">]</span>
<span class="n">isbns</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="sh">"</span><span class="s">isbns</span><span class="sh">"</span><span class="p">]</span>

<span class="c1"># Dimensionality reduction using UMAP
</span><span class="n">umap_embeddings</span> <span class="o">=</span> <span class="n">umap</span><span class="p">.</span><span class="nc">UMAP</span><span class="p">(</span><span class="n">n_neighbors</span><span class="o">=</span><span class="mi">15</span><span class="p">,</span> <span class="n">n_components</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">metric</span><span class="o">=</span><span class="sh">'</span><span class="s">cosine</span><span class="sh">'</span><span class="p">).</span><span class="nf">fit_transform</span><span class="p">(</span><span class="n">embeddings</span><span class="p">)</span>

<span class="c1"># Get unique ISBNs and their corresponding titles
</span><span class="n">unique_isbns</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">set</span><span class="p">(</span><span class="n">isbns</span><span class="p">))</span>
<span class="n">isbn_to_title</span> <span class="o">=</span> <span class="p">{</span><span class="n">isbn</span><span class="p">:</span> <span class="nf">get_book_title</span><span class="p">(</span><span class="n">isbn</span><span class="p">)</span> <span class="k">for</span> <span class="n">isbn</span> <span class="ow">in</span> <span class="n">unique_isbns</span><span class="p">}</span>
<span class="n">colors</span> <span class="o">=</span> <span class="n">px</span><span class="p">.</span><span class="n">colors</span><span class="p">.</span><span class="n">qualitative</span><span class="p">.</span><span class="n">Plotly</span>

<span class="n">highlight_ids</span> <span class="o">=</span> <span class="p">{</span><span class="n">isbn</span><span class="p">:</span> <span class="mi">0</span> <span class="k">for</span> <span class="n">isbn</span> <span class="ow">in</span> <span class="n">unique_isbns</span><span class="p">}</span>

<span class="c1"># Function to generate URL and update highlight IDs
</span><span class="k">def</span> <span class="nf">generate_url</span><span class="p">(</span><span class="n">isbn</span><span class="p">):</span>
    <span class="n">url</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">"</span><span class="s">https://books.alessandroferrari.live/</span><span class="si">{</span><span class="n">isbn</span><span class="si">}</span><span class="s">#</span><span class="si">{</span><span class="n">highlight_ids</span><span class="p">[</span><span class="n">isbn</span><span class="p">]</span><span class="si">}</span><span class="sh">"</span>
    <span class="n">highlight_ids</span><span class="p">[</span><span class="n">isbn</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
    <span class="k">return</span> <span class="n">url</span>

<span class="c1"># Generate URLs for each highlight
</span><span class="n">urls</span> <span class="o">=</span> <span class="p">[</span><span class="nf">generate_url</span><span class="p">(</span><span class="n">isbn</span><span class="p">)</span> <span class="k">for</span> <span class="n">isbn</span> <span class="ow">in</span> <span class="n">isbns</span><span class="p">]</span>

<span class="c1"># Wrap text for each highlight and append URL
</span><span class="n">wrapped_sentences_with_url</span> <span class="o">=</span> <span class="p">[</span>
    <span class="sh">'</span><span class="s">&lt;br&gt;</span><span class="sh">'</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">textwrap</span><span class="p">.</span><span class="nf">wrap</span><span class="p">(</span><span class="n">sentence</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mi">80</span><span class="p">))</span> <span class="o">+</span> <span class="sa">f</span><span class="sh">"</span><span class="s">&lt;br&gt;URL: </span><span class="si">{</span><span class="n">url</span><span class="si">}</span><span class="sh">"</span> 
    <span class="k">for</span> <span class="n">sentence</span><span class="p">,</span> <span class="n">url</span> <span class="ow">in</span> <span class="nf">zip</span><span class="p">(</span><span class="n">sentences</span><span class="p">,</span> <span class="n">urls</span><span class="p">)</span>
<span class="p">]</span>

<span class="c1"># Prepare Plotly data
</span><span class="n">plot_data</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="nc">DataFrame</span><span class="p">({</span>
    <span class="sh">'</span><span class="s">x</span><span class="sh">'</span><span class="p">:</span> <span class="n">umap_embeddings</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">],</span>
    <span class="sh">'</span><span class="s">y</span><span class="sh">'</span><span class="p">:</span> <span class="n">umap_embeddings</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">],</span>
    <span class="sh">'</span><span class="s">text</span><span class="sh">'</span><span class="p">:</span> <span class="n">wrapped_sentences_with_url</span><span class="p">,</span>
    <span class="sh">'</span><span class="s">isbn</span><span class="sh">'</span><span class="p">:</span> <span class="n">isbns</span>
<span class="p">})</span>

<span class="c1"># Create Plotly figure
</span><span class="n">fig</span> <span class="o">=</span> <span class="n">go</span><span class="p">.</span><span class="nc">Figure</span><span class="p">()</span>

<span class="k">for</span> <span class="n">idx</span><span class="p">,</span> <span class="n">isbn</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="n">unique_isbns</span><span class="p">):</span>
    <span class="n">isbn_data</span> <span class="o">=</span> <span class="n">plot_data</span><span class="p">[</span><span class="n">plot_data</span><span class="p">[</span><span class="sh">'</span><span class="s">isbn</span><span class="sh">'</span><span class="p">]</span> <span class="o">==</span> <span class="n">isbn</span><span class="p">]</span>
    <span class="n">fig</span><span class="p">.</span><span class="nf">add_trace</span><span class="p">(</span><span class="n">go</span><span class="p">.</span><span class="nc">Scatter</span><span class="p">(</span>
        <span class="n">x</span><span class="o">=</span><span class="n">isbn_data</span><span class="p">[</span><span class="sh">'</span><span class="s">x</span><span class="sh">'</span><span class="p">],</span>
        <span class="n">y</span><span class="o">=</span><span class="n">isbn_data</span><span class="p">[</span><span class="sh">'</span><span class="s">y</span><span class="sh">'</span><span class="p">],</span>
        <span class="n">mode</span><span class="o">=</span><span class="sh">'</span><span class="s">markers</span><span class="sh">'</span><span class="p">,</span>
        <span class="n">marker</span><span class="o">=</span><span class="nf">dict</span><span class="p">(</span><span class="n">color</span><span class="o">=</span><span class="n">colors</span><span class="p">[</span><span class="n">idx</span> <span class="o">%</span> <span class="nf">len</span><span class="p">(</span><span class="n">colors</span><span class="p">)],</span> <span class="n">size</span><span class="o">=</span><span class="mi">10</span><span class="p">),</span>
        <span class="n">text</span><span class="o">=</span><span class="n">isbn_data</span><span class="p">[</span><span class="sh">'</span><span class="s">text</span><span class="sh">'</span><span class="p">],</span>  <span class="c1"># Include the wrapped text with URL
</span>        <span class="n">hoverinfo</span><span class="o">=</span><span class="sh">'</span><span class="s">text</span><span class="sh">'</span><span class="p">,</span>       <span class="c1"># Only show the text on hover
</span>        <span class="n">name</span><span class="o">=</span><span class="n">isbn_to_title</span><span class="p">[</span><span class="n">isbn</span><span class="p">]</span>
    <span class="p">))</span>

<span class="c1"># Update layout
</span><span class="n">fig</span><span class="p">.</span><span class="nf">update_layout</span><span class="p">(</span>
    <span class="n">title</span><span class="o">=</span><span class="sh">''</span><span class="p">,</span>
    <span class="n">plot_bgcolor</span><span class="o">=</span><span class="sh">'</span><span class="s">white</span><span class="sh">'</span><span class="p">,</span>
    <span class="n">xaxis</span><span class="o">=</span><span class="nf">dict</span><span class="p">(</span><span class="n">showgrid</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">zeroline</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">showticklabels</span><span class="o">=</span><span class="bp">False</span><span class="p">),</span>
    <span class="n">yaxis</span><span class="o">=</span><span class="nf">dict</span><span class="p">(</span><span class="n">showgrid</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">zeroline</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">showticklabels</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="p">)</span>

<span class="c1"># Save the figure as an HTML file
</span><span class="n">fig</span><span class="p">.</span><span class="nf">write_html</span><span class="p">(</span><span class="sh">"</span><span class="s">plotly-out.html</span><span class="sh">"</span><span class="p">)</span>
</code></pre></div></div>

<p>This simple script generates an html file that can be seen <a href="https://books.alessandroferrari.live/plot">here</a>. From this I can see all my highlights by hovering my mouse over the dots.</p>

<p>As a cherry on top, a netlify build can be triggered every time the google sheet gets updated through a simple Google AppScript and AppScript trigger:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">triggerNetlifyBuild</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">scriptProperties</span> <span class="o">=</span> <span class="nx">PropertiesService</span><span class="p">.</span><span class="nf">getScriptProperties</span><span class="p">();</span>
<span class="kd">var</span> <span class="nx">lastDeployTime</span> <span class="o">=</span> <span class="nx">scriptProperties</span><span class="p">.</span><span class="nf">getProperty</span><span class="p">(</span><span class="dl">'</span><span class="s1">lastDeployTime</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">currentTime</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Date</span><span class="p">().</span><span class="nf">getTime</span><span class="p">();</span>

<span class="c1">// Check if last deploy was less than 5 minutes ago</span>
<span class="k">if </span><span class="p">(</span><span class="nx">lastDeployTime</span> <span class="o">!==</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="nx">currentTime</span> <span class="o">-</span> <span class="nx">lastDeployTime</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">5</span> <span class="o">*</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">)</span> <span class="p">{</span>
	<span class="nx">Logger</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Deploy skipped to prevent spamming. Less than 5 minutes since last deploy.</span><span class="dl">'</span><span class="p">);</span>
	<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>

<span class="nx">scriptProperties</span><span class="p">.</span><span class="nf">setProperty</span><span class="p">(</span><span class="dl">'</span><span class="s1">lastDeployTime</span><span class="dl">'</span><span class="p">,</span> <span class="nx">currentTime</span><span class="p">.</span><span class="nf">toString</span><span class="p">());</span>

<span class="c1">// Your Netlify hook URL</span>
<span class="kd">var</span> <span class="nx">netlifyHookUrl</span> <span class="o">=</span> <span class="nx">scriptProperties</span><span class="p">.</span><span class="nf">getProperty</span><span class="p">(</span><span class="dl">'</span><span class="s1">NETLIFY_BUILD_ID</span><span class="dl">'</span><span class="p">)</span>

<span class="nx">UrlFetchApp</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="nx">netlifyHookUrl</span><span class="p">,</span> <span class="p">{</span> <span class="na">method</span><span class="p">:</span> <span class="dl">'</span><span class="s1">POST</span><span class="dl">'</span> <span class="p">});</span>
<span class="nx">Logger</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Netlify build triggered.</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This script sends a post request to a netlify build hook, and can be triggered every time the script gets edited. I also added a countdown to avoid spam.</p>

<h1 id="email-quotes-to-your-inbox">Email quotes to your inbox</h1>

<p>Since this whole system is very expandable and modular, I implemented another cool feature that I saw in products such as Readwise: getting your own quotes in your inbox for recollection and resurfacing old concepts. I implemented this using Google AppScript, making it again free and serverless.</p>

<p>I have a trigger that runs every day between 6am and 7am which picks 3 random quotes from the sheet and formats them nicely in my inbox. Here are the functions:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">getBookInfoByISBN</span><span class="p">(</span><span class="nx">isbn</span><span class="p">)</span> <span class="p">{</span>
	<span class="kd">var</span> <span class="nx">scriptProperties</span> <span class="o">=</span> <span class="nx">PropertiesService</span><span class="p">.</span><span class="nf">getScriptProperties</span><span class="p">();</span>
	<span class="kd">var</span> <span class="nx">API_KEY</span> <span class="o">=</span> <span class="nx">scriptProperties</span><span class="p">.</span><span class="nf">getProperty</span><span class="p">(</span><span class="dl">'</span><span class="s1">BOOK_API</span><span class="dl">'</span><span class="p">);</span>
	<span class="kd">var</span> <span class="nx">url</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">https://www.googleapis.com/books/v1/volumes?q=isbn:</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">isbn</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">&amp;key=</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">API_KEY</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">&amp;country=US</span><span class="dl">'</span><span class="p">;</span>
	<span class="kd">var</span> <span class="nx">response</span> <span class="o">=</span> <span class="nx">UrlFetchApp</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="nx">url</span><span class="p">);</span>
	<span class="kd">var</span> <span class="nx">json</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nf">getContentText</span><span class="p">());</span>
	
	<span class="k">if </span><span class="p">(</span><span class="nx">json</span><span class="p">.</span><span class="nx">totalItems</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
		<span class="kd">var</span> <span class="nx">book</span> <span class="o">=</span> <span class="nx">json</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">volumeInfo</span><span class="p">;</span>
		<span class="k">return</span> <span class="p">{</span> <span class="na">title</span><span class="p">:</span> <span class="nx">book</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span> <span class="na">author</span><span class="p">:</span> <span class="nx">book</span><span class="p">.</span><span class="nx">authors</span> <span class="p">?</span> <span class="nx">book</span><span class="p">.</span><span class="nx">authors</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="dl">"</span><span class="s2">, </span><span class="dl">"</span><span class="p">)</span> <span class="p">:</span> <span class="dl">"</span><span class="s2">Unknown Author</span><span class="dl">"</span> <span class="p">};</span>
	<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
		<span class="k">return</span> <span class="p">{</span> <span class="na">title</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Unknown Title</span><span class="dl">'</span><span class="p">,</span> <span class="na">author</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Unknown Author</span><span class="dl">'</span> <span class="p">};</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">sendRandomQuotesEmail</span><span class="p">()</span> <span class="p">{</span>
	<span class="kd">var</span> <span class="nx">sheet</span> <span class="o">=</span> <span class="nx">SpreadsheetApp</span><span class="p">.</span><span class="nf">getActiveSpreadsheet</span><span class="p">().</span><span class="nf">getActiveSheet</span><span class="p">();</span>
	<span class="kd">var</span> <span class="nx">data</span> <span class="o">=</span> <span class="nx">sheet</span><span class="p">.</span><span class="nf">getDataRange</span><span class="p">().</span><span class="nf">getValues</span><span class="p">();</span>
	<span class="kd">var</span> <span class="nx">randomQuotes</span> <span class="o">=</span> <span class="nf">getRandomQuotes</span><span class="p">(</span><span class="nx">data</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
	
	<span class="kd">var</span> <span class="nx">message</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">&lt;div style="font-family: Arial, sans-serif; font-size: 14px;"&gt;</span><span class="dl">'</span><span class="p">;</span>
	
	<span class="nx">randomQuotes</span><span class="p">.</span><span class="nf">forEach</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">quote</span><span class="p">)</span> <span class="p">{</span>
		<span class="c1">// Each quote with highlighted background and citation in standard text</span>
		<span class="nx">message</span> <span class="o">+=</span> <span class="s2">`&lt;p style="word-wrap: break-word;"&gt;`</span> <span class="o">+</span>
		<span class="s2">`&lt;span style="background-color: rgba(255, 226, 130, 0.5);"&gt;</span><span class="p">${</span><span class="nx">quote</span><span class="p">.</span><span class="nx">text</span><span class="p">}</span><span class="s2">&lt;/span&gt;`</span> <span class="o">+</span>
		<span class="s2">`&lt;/p&gt;`</span> <span class="o">+</span>
		<span class="s2">`&lt;p style="font-style: italic; margin-top: 5px;"&gt;—</span><span class="p">${</span><span class="nx">quote</span><span class="p">.</span><span class="nx">title</span><span class="p">}</span><span class="s2"> by </span><span class="p">${</span><span class="nx">quote</span><span class="p">.</span><span class="nx">author</span><span class="p">}</span><span class="s2">&lt;/p&gt;`</span><span class="p">;</span>
	<span class="p">});</span>
	
	<span class="c1">// End of the message</span>
	<span class="nx">message</span> <span class="o">+=</span> <span class="dl">'</span><span class="s1">&lt;/div&gt;</span><span class="dl">'</span><span class="p">;</span>
	
	<span class="nx">MailApp</span><span class="p">.</span><span class="nf">sendEmail</span><span class="p">({</span>
		<span class="na">to</span><span class="p">:</span> <span class="dl">"</span><span class="s2">&lt;your email&gt;</span><span class="dl">"</span><span class="p">,</span>
		<span class="na">subject</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Your Daily Book Quotes</span><span class="dl">"</span><span class="p">,</span>
		<span class="na">htmlBody</span><span class="p">:</span> <span class="nx">message</span>
	<span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nf">getRandomQuotes</span><span class="p">(</span><span class="nx">data</span><span class="p">,</span> <span class="nx">numberOfQuotes</span><span class="p">)</span> <span class="p">{</span>
	<span class="kd">var</span> <span class="nx">quotes</span> <span class="o">=</span> <span class="p">[];</span>
	<span class="kd">var</span> <span class="nx">usedIndices</span> <span class="o">=</span> <span class="p">[];</span>
	
	<span class="k">while </span><span class="p">(</span><span class="nx">quotes</span><span class="p">.</span><span class="nx">length</span> <span class="o">&lt;</span> <span class="nx">numberOfQuotes</span><span class="p">)</span> <span class="p">{</span>
		<span class="kd">var</span> <span class="nx">randomIndex</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nf">random</span><span class="p">()</span> <span class="o">*</span> <span class="nx">data</span><span class="p">.</span><span class="nx">length</span><span class="p">);</span>
		<span class="k">if </span><span class="p">(</span><span class="nx">usedIndices</span><span class="p">.</span><span class="nf">indexOf</span><span class="p">(</span><span class="nx">randomIndex</span><span class="p">)</span> <span class="o">===</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
			<span class="nx">usedIndices</span><span class="p">.</span><span class="nf">push</span><span class="p">(</span><span class="nx">randomIndex</span><span class="p">);</span>
			<span class="kd">var</span> <span class="nx">isbn</span> <span class="o">=</span> <span class="nx">data</span><span class="p">[</span><span class="nx">randomIndex</span><span class="p">][</span><span class="mi">1</span><span class="p">];</span>
			<span class="kd">var</span> <span class="nx">bookInfo</span> <span class="o">=</span> <span class="nf">getBookInfoByISBN</span><span class="p">(</span><span class="nx">isbn</span><span class="p">);</span>
			<span class="kd">var</span> <span class="nx">quoteText</span> <span class="o">=</span> <span class="nx">data</span><span class="p">[</span><span class="nx">randomIndex</span><span class="p">][</span><span class="mi">0</span><span class="p">];</span>
			
			<span class="nx">quotes</span><span class="p">.</span><span class="nf">push</span><span class="p">({</span>
				<span class="na">text</span><span class="p">:</span> <span class="nx">quoteText</span><span class="p">,</span>
				<span class="na">title</span><span class="p">:</span> <span class="nx">bookInfo</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span>
				<span class="na">author</span><span class="p">:</span> <span class="nx">bookInfo</span><span class="p">.</span><span class="nx">author</span>
			<span class="p">});</span>
		<span class="p">}</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="nx">quotes</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This way I get a daily email with 3 highlights that looks like this:</p>

<p><img src="/assets/posts/book-highlights/daily-email.png" alt="daily-email.png" /></p>

<h1 id="summary">Summary</h1>
<p>Wrapping up, this project is a cost-effective solution for transforming book highlights into an interactive, searchable vector space on my website. The system, entirely serverless and automated, updates in real-time with each addition to a Google Sheet. It also leaves space for plugins and extensions, such as the three daily highlights that land in my inbox.</p>

<p>The core of this project lies in how these highlights are not just static text but dynamic data points in a vector space, enabling semantic search. This integration of technology with literature not only highthens the reading experience but also demonstrates the practical application of machine learning in personal projects.</p>

<p>Although this project is public on the internet, I will probably be the one benefitting from it the most, as I like looking back at my own highlights.</p>

<p>The project is currently live at <a href="https://books.alessandroferrari.live">books.alessandroferrari.live</a>. And the source code for it can be found <a href="https://github.com/Ferryistaken/books">on github</a>.</p>]]></content><author><name>Alessandro Ferrari</name><email>alessandroferrari@gatech.edu</email></author><category term="ai" /><summary type="html"><![CDATA[Discover how to transform book highlights into a searchable vector space using serverless technology for an innovative, cost-effective reading experience.]]></summary></entry><entry><title type="html">The idea of “Sunk Cost Opportunity”.</title><link href="https://alessandroferrari.live/sunk-cost-opportunity/" rel="alternate" type="text/html" title="The idea of “Sunk Cost Opportunity”." /><published>2023-11-09T19:05:00+00:00</published><updated>2023-11-09T19:05:00+00:00</updated><id>https://alessandroferrari.live/sunk-cost-opportunity</id><content type="html" xml:base="https://alessandroferrari.live/sunk-cost-opportunity/"><![CDATA[<h1 id="the-case-for-generating-content-and-curating-an-outlet">The case for generating content and curating an outlet</h1>

<p>The thought of creating a personal brand, building an audience, and curating content that is relevant to what I care about and research is more tempting than ever.</p>

<p>I think that there is a case for me to take time out of my days to share my views and expertise on different subjects that I’m well versed in, as I might genuinely <strong>create value</strong> for some of my readers (I’ll define what I mean by create value later).</p>

<p>However I view time as my scarcest (and most valuable) commodity, and taking time out of my research, studies, side projects, job search, etc, etc, etc in order to curate my thoughts is often hard to justify in my own mind.</p>

<p>Either choice seems a no-brainer. I should start curating content because:</p>

<ul>
  <li>People that I respect and are extremely successful in their own fields do it (Huberman, Walker, Housel, etc).</li>
  <li>I already write on my own, almost every day, so it seems natural to just post what I write.</li>
  <li>It’s good to have a personal brand. Ideally when someone googles your name you’re the first person that pops up, otherwise you’re being dominated in the late-stage capitalism hierarchy :).</li>
  <li>I like the idea of having an audience that I <strong>create value</strong> for.</li>
</ul>

<p>However, it’s a bad idea to start curating content because:</p>

<ul>
  <li>It takes time to <strong>create value</strong>. It takes a long time to even get to the point in your life where you’re in a position to <strong>create value</strong>, and then it takes more time to <strong>create value</strong> once you’re in that position.</li>
  <li>What if you’re falling in the <a href="https://www.behance.net/blog/the-creative-worlds-bullshit-industrial-complex">The Creative World’s Bullshit Industrial Complex</a> trap?</li>
  <li>It’s scary. Does your voice really need to be heard? What if you write something that you don’t agree with in 3 years? What about in 10 years?</li>
  <li>The positive outcomes aren’t clear. Are you getting payed? Are you getting recognition? Will this help you academically, professionally, spiritually or in any other way?</li>
</ul>

<p>While thinking about this, I came up with an idea:</p>
<h1 id="the-sunk-cost-opportunity">The Sunk Cost Opportunity</h1>

<p>We are all familiar with the sunk cost fallacy: our tendency to follow through on something if we are already invested in it. To this fun concept, I raise: the <strong>sunk cost opportunity</strong>.</p>

<p>On any given week, I spend tens of hours researching random topics. Some weeks I read publications on the <a href="https://x.com/BioAlessandro/status/1721648737700008021?s=20">effect on noise machines on sleep</a>, some other weeks I’ll sink time into <a href="/open-source-business-card/">building a “smart” business card</a> for no apparent benefit, at other times I will <a href="/chip8-emulator-written-in-rust/">code an emulator to learn Rust</a>.</p>

<p>These are all endeavours that feed my constant research for knowledge. They are almost therapeutic. They keep me sharp. They keep me updated on current events. They even train my ability to pivot from one project to another quickly–a nice switch up from the semester or year-long projects that I’m faced with in my school or research.</p>

<p>Point is: <strong>I am already at peace with committing 7 hours of my week researching the effects of white noise on my sleep. I do it for fun.</strong> Those hours are a cost that I’m willing to sink at any time of my life–there is no friction at all in spending them however I see fit.</p>

<p>Naturally, after this realization, my next thought was: <strong><em>why don’t I spend another 20 minutes on top of those 7 hours curating a simple blog post, a thread on twitter, or even simply a well-written journal entry that no one but me will read?</em></strong></p>

<p>This is the essence of the sunk cost opportunity: how can I create the most amount of value from cost that is already “sunk” in order to generate an asymmetrically large outcome.</p>

<blockquote>
  <p>how can I create the most amount of value from cost that is already “sunk” in order to generate an asymmetrically large outcome.</p>
</blockquote>

<p>I’m not going to spend 4 hours researching something just to publish it to my audience. I’m not a writer, philosopher, or influencer, however I’m perfectly ok with spending 30 minutes writing about something that I already commit hours to for others reasons. That’s perfectly reasonable in my head.</p>

<h2 id="creating-value">Creating Value</h2>

<p>This way I’m also sure to create value. There surely is someone else like me, who has the same thirst for knowledge in similar topics, who will enjoy not having to spend 7 hours researching the effect of white noise on sleep. Someone who would rather read my blog post about it and invest his weekly personal-research hours into something else.</p>

<p>On the other side of things, there will also be someone that reads what I have to say and chooses to go on an even deeper dive, however that person will now have a good starting point.</p>

<p>These are the archetypes of people that I’m creating value for: the student in my same position who will now be able to devote his hours to something else. The kid that is trying to get in the same intersection of CS and Biology as me and that won’t need to go through as many hurdles to get to where I’m at. Or the person that reads my content and chooses that they want to delve deeper into the subject.</p>

<p>I find content valuable if:</p>

<ul>
  <li>It saves me hours of time.</li>
  <li>It makes me waste hours of time because I’m so captivated by it that I need more of it.</li>
</ul>

<p>And my content is aimed at provoking the same outcome in other people.</p>

<blockquote>
  <p>I find content valuable if it saves me hours of time or of it makes me waste hours of time researching more about. No in-between.</p>
</blockquote>

<p><em>PS: This is a great read that in part motivated me to write this. His whole blog is great.</em></p>

<p><a href="https://jakobgreenfeld.com/build_an_audience">⭐️ Build a business, not an audience</a></p>]]></content><author><name>Alessandro Ferrari</name><email>alessandroferrari@gatech.edu</email></author><category term="writing" /><summary type="html"><![CDATA[My thoughts on creating a personal brand and the idea of "Sunk Cost Opportunity".]]></summary></entry><entry><title type="html">How to Quality Control RNA from ArchR objects</title><link href="https://alessandroferrari.live/how-to-qc-rna-from-archr/" rel="alternate" type="text/html" title="How to Quality Control RNA from ArchR objects" /><published>2023-09-25T08:20:17+00:00</published><updated>2023-09-25T08:20:17+00:00</updated><id>https://alessandroferrari.live/how-to-qc-rna-from-archr</id><content type="html" xml:base="https://alessandroferrari.live/how-to-qc-rna-from-archr/"><![CDATA[<h1 id="introduction">Introduction</h1>

<p>When doing single cell multiome analysis (ATAC + RNA) in R using packages like <a href="https://satijalab.org/seurat/">Seurat</a> or <a href="https://www.archrproject.com/">ArchR</a>, it is useful to load both the scRNA-seq and scATAC-seq datasets in the same object under the same framework.</p>

<p>This however brings some problems, as ArchR doesn’t have built-in functions or tutorials on how to filter out bad RNA reads from the ArchR object, and vice versa from the Seurat object.</p>

<p>This is an easy problem to fix, however I haven’t found any easy resources online that explain the very simple process, and chose to write my own.</p>

<h1 id="loading-the-data">Loading the data</h1>

<p>For this tutorial, I’m going to use ArchR as the main framework. I first load in the data like this:</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">inputFiles</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="s2">"data/&lt;your-file-name&gt;"</span><span class="w">

</span><span class="n">ArrowFiles</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">createArrowFiles</span><span class="p">(</span><span class="w">
  </span><span class="n">inputFiles</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">inputFiles</span><span class="p">,</span><span class="w">
  </span><span class="n">minTSS</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w">
  </span><span class="n">minFrags</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">500</span><span class="p">,</span><span class="w"> 
  </span><span class="n">addTileMat</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">,</span><span class="w">
  </span><span class="n">addGeneScoreMat</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="w">
</span><span class="p">)</span><span class="w">

</span><span class="n">proj</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">ArchRProject</span><span class="p">(</span><span class="n">ArrowFiles</span><span class="p">)</span><span class="w">

</span><span class="n">seRNA</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">import10xFeatureMatrix</span><span class="p">(</span><span class="w">
  </span><span class="n">input</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s2">"data/pbmc_unsorted_10k_filtered_feature_bc_matrix.h5"</span><span class="p">),</span><span class="w">
  </span><span class="n">names</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s2">"PBMC_10k"</span><span class="p">)</span><span class="w">
</span><span class="p">)</span><span class="w">

</span><span class="n">proj</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">addGeneExpressionMatrix</span><span class="p">(</span><span class="n">input</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">proj</span><span class="p">,</span><span class="w"> </span><span class="n">seRNA</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">seRNA</span><span class="p">,</span><span class="w"> </span><span class="n">force</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">

</span><span class="c1"># Filter out NA Reads</span><span class="w">
</span><span class="n">proj</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">proj</span><span class="p">[</span><span class="o">!</span><span class="nf">is.na</span><span class="p">(</span><span class="n">proj</span><span class="o">$</span><span class="n">Gex_nGenes</span><span class="p">)</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> 
               </span><span class="o">!</span><span class="nf">is.na</span><span class="p">(</span><span class="n">proj</span><span class="o">$</span><span class="n">Gex_MitoRatio</span><span class="p">)]</span><span class="w">
</span></code></pre></div></div>

<h2 id="quality-control">Quality Control</h2>

<p>Then, I start my quality control pipeline. In this case, I want to set the <em>minTSS</em> to 12, <em>minFrags</em> to 1200, <em>minFeatures</em> to 600, <em>maxFeatures</em> to 4000 and <em>maxMT</em> to 0.019.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">minTSS</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="m">12</span><span class="w">
</span><span class="n">minFrags</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="m">1200</span><span class="w">

</span><span class="n">minFeatures</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="m">600</span><span class="w">
</span><span class="n">maxFeatures</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="m">4000</span><span class="w">
</span><span class="n">maxMT</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="m">0.019</span><span class="w">
</span></code></pre></div></div>

<h2 id="atac-quality-control">ATAC Quality Control</h2>

<p>In order to filter out ATAC cells that don’t pass these thresholds, I can index into the ArchR object like so:</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">proj</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">proj</span><span class="p">[</span><span class="n">proj</span><span class="o">$</span><span class="n">TSSEnrichment</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">minTSS</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="n">proj</span><span class="o">$</span><span class="n">nFrags</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">minFrags</span><span class="p">]</span><span class="w">
</span></code></pre></div></div>

<h2 id="rna-quality-control">RNA Quality Control</h2>

<p>I can then repeat the same process for the RNA data.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">proj</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">proj</span><span class="p">[</span><span class="n">proj</span><span class="o">$</span><span class="n">Gex_nGenes</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">minFeatures</span><span class="w">
             </span><span class="o">&amp;</span><span class="w"> </span><span class="n">proj</span><span class="o">$</span><span class="n">Gex_nGenes</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">maxFeatures</span><span class="w">
             </span><span class="o">&amp;</span><span class="w"> </span><span class="n">proj</span><span class="o">$</span><span class="n">Gex_MitoRatio</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">maxMT</span><span class="p">]</span><span class="w">
</span></code></pre></div></div>

<h1 id="conclusions">Conclusions</h1>

<p>This might be obvious for a lot of people, and it is after getting some experience with bioinformatics. I just wanted to make this short post to make the knowledge more accessible, as I don’t think that anyone should lose 30 minutes trying to figure this out, like I did.</p>]]></content><author><name>Alessandro Ferrari</name><email>alessandroferrari@gatech.edu</email></author><category term="bioinformatics" /><category term="single-cell" /><category term="scRNA" /><category term="scATAC" /><category term="archr" /><category term="seurat" /><category term="genomics" /><summary type="html"><![CDATA[Guide on how to do RNA quality control an ArchR object.]]></summary></entry><entry><title type="html">Building a CHIP-8 Emulator in Rust</title><link href="https://alessandroferrari.live/chip8-emulator-written-in-rust/" rel="alternate" type="text/html" title="Building a CHIP-8 Emulator in Rust" /><published>2023-08-15T22:53:00+00:00</published><updated>2023-08-15T22:53:00+00:00</updated><id>https://alessandroferrari.live/chip8-emulator-written-in-rust</id><content type="html" xml:base="https://alessandroferrari.live/chip8-emulator-written-in-rust/"><![CDATA[<p>In this brief writeup, I’ll show you how I wrote my first emulator–an emulator to the CHIP-8 programming language–in Rust.</p>

<h1 id="introduction">Introduction</h1>

<p>This post isn’t supposed to be a step-to-step guide, it may be treated as such, but you will probably find some better guides on the internet. I wrote this emulator a while ago and am just now(~1.5 years later) writing this post, so don’t lynch me for my errors–or better yet; fix them on <a href="https://github.com/Ferryistaken/CHIP8-rs/issues">github</a>.</p>

<p>Skip to the <a href="https://github.com/Ferryistaken/CHIP8-rs">code</a>.</p>

<h1 id="project-setup">Project setup</h1>

<h1 id="chip8">CHIP8</h1>

<h2 id="chip8-description">CHIP8 Description</h2>

<h3 id="16-8-bit-registers">16 8-bit registers</h3>

<p>Registers are small storage locations in the CPU for temporary data storage and operations.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">registers</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">16</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">;</span> <span class="mi">16</span><span class="p">];</span> <span class="c1">// Registers V0 to VF</span>
</code></pre></div></div>

<h3 id="4k-bytes-of-memory">4k bytes of memory</h3>

<p>Memory is the larger storage used for program instructions, long-term data, and short-term data.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">memory</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">4096</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">;</span> <span class="mi">4096</span><span class="p">];</span>
</code></pre></div></div>

<h3 id="16-bit-index-registers">16-bit index registers</h3>

<p>The Index Register holds memory addresses for certain operations.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">index_register</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="16-bit-program-counter">16-bit program counter</h3>

<p>The Program Counter keeps track of the address for the next instruction to execute.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">program_counter</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="mi">0x200</span><span class="p">;</span> <span class="c1">// The program starts at 0x200</span>
</code></pre></div></div>

<h3 id="16-level-stack">16-level stack</h3>

<p>The stack keeps track of return addresses when calling into functions.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">stack</span><span class="p">:</span> <span class="p">[</span><span class="nb">u16</span><span class="p">;</span> <span class="mi">16</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">;</span> <span class="mi">16</span><span class="p">];</span>
</code></pre></div></div>

<h3 id="8-bit-stack-pointer">8-bit stack pointer</h3>

<p>The Stack Pointer points to the top-most level of the stack.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">stack_pointer</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="8-bit-delay-timer">8-bit delay timer</h3>

<p>The delay timer in CHIP-8 decrements at a rate of 60Hz until it reaches zero.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 8-bit delay timer</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">delay_timer</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="8-bit-sound-timer">8-bit sound timer</h3>

<p>When the sound timer is set to a value greater than zero, a beep is produced and it decrements at a rate of 60Hz until it reaches zero.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 8-bit sound timer</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">sound_timer</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="16-input-keys">16 input keys</h3>

<p>CHIP-8 has 16 input keys, typically represented by the hexadecimal numbers 0 through F.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Keys 0x0 through 0xF.</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">keypad</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">16</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">;</span> <span class="mi">16</span><span class="p">];</span>
</code></pre></div></div>

<h3 id="64x32-monochrome-display-memory">64x32 monochrome display memory</h3>
<p>CHIP-8 has a monochrome display of 64x32 pixels.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Display, 64x32.</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">video</span><span class="p">:</span> <span class="p">[</span><span class="nb">u32</span><span class="p">;</span> <span class="mi">64</span> <span class="o">*</span> <span class="mi">32</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">;</span> <span class="mi">64</span> <span class="o">*</span> <span class="mi">32</span><span class="p">];</span>
</code></pre></div></div>

<h3 id="implementation-specific-variables">Implementation Specific Variables</h3>

<h4 id="opcode-function-tables">Opcode Function Tables</h4>

<p>For a CHIP-8 emulator, using function tables is a common and efficient way to handle opcodes. By mapping each opcode to a specific function that implements it, you can avoid a large switch or match statement.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Main opcode table</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">table</span><span class="p">:</span> <span class="p">[</span><span class="k">fn</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">Chip8</span><span class="p">);</span> <span class="mi">0xF</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nn">Chip8</span><span class="p">::</span><span class="n">OP_ERR</span><span class="p">;</span> <span class="mi">0xF</span><span class="o">+</span><span class="mi">1</span><span class="p">];</span>

<span class="c1">// Sub-tables for opcodes that begin with 0, 8, E, and F</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">table0</span><span class="p">:</span> <span class="p">[</span><span class="k">fn</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">Chip8</span><span class="p">);</span> <span class="mi">0xE</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nn">Chip8</span><span class="p">::</span><span class="n">OP_ERR</span><span class="p">;</span> <span class="mi">0xE</span><span class="o">+</span><span class="mi">1</span><span class="p">];</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">table8</span><span class="p">:</span> <span class="p">[</span><span class="k">fn</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">Chip8</span><span class="p">);</span> <span class="mi">0xE</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nn">Chip8</span><span class="p">::</span><span class="n">OP_ERR</span><span class="p">;</span> <span class="mi">0xE</span><span class="o">+</span><span class="mi">1</span><span class="p">];</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">tableE</span><span class="p">:</span> <span class="p">[</span><span class="k">fn</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">Chip8</span><span class="p">);</span> <span class="mi">0xE</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nn">Chip8</span><span class="p">::</span><span class="n">OP_ERR</span><span class="p">;</span> <span class="mi">0xE</span><span class="o">+</span><span class="mi">1</span><span class="p">];</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">tableF</span><span class="p">:</span> <span class="p">[</span><span class="k">fn</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">Chip8</span><span class="p">);</span> <span class="mi">0x65</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nn">Chip8</span><span class="p">::</span><span class="n">OP_ERR</span><span class="p">;</span> <span class="mi">0x65</span><span class="o">+</span><span class="mi">1</span><span class="p">];</span>
</code></pre></div></div>
<p><br /></p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">table</code>: This is the primary opcode table. Each index of this array corresponds to the first half-byte (nibble) of an opcode. For example, any opcode that starts with ‘8’ (like 8xy0, 8xy1, etc.) would be found at table[8].</li>
  <li><code class="language-plaintext highlighter-rouge">table0</code>: This is a sub-table for opcodes that begin with ‘0’. It helps differentiate between instructions like 00E0 and 00EE.</li>
  <li><code class="language-plaintext highlighter-rouge">table8</code>: A sub-table for opcodes that start with ‘8’. As the CHIP-8 has multiple instructions starting with ‘8’, this table distinguishes between them based on the last nibble.</li>
  <li><code class="language-plaintext highlighter-rouge">tableE</code>: Similarly, this table is for opcodes that begin with ‘E’, allowing for differentiation between instructions like ExA1 and Ex9E.</li>
  <li><code class="language-plaintext highlighter-rouge">tableF</code>: This table handles a range of opcodes that start with ‘F’, with their differentiation based on the second byte of the opcode.</li>
</ul>

<p>The <code class="language-plaintext highlighter-rouge">add_table</code> (shown below) function initializes these tables by associating each opcode with its respective function (or method). For instance, the opcode 8xy1 (OR operation between Vx and Vy) would be assigned to the Chip8::OP_8xy1 function.</p>

<h3 id="class-members">Class Members</h3>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">struct</span> <span class="n">Chip8</span> <span class="p">{</span>
    <span class="n">registers</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">16</span><span class="p">],</span>
    <span class="n">memory</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">4096</span><span class="p">],</span>
    <span class="n">index_register</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
    <span class="n">program_counter</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
    <span class="n">stack</span><span class="p">:</span> <span class="p">[</span><span class="nb">u16</span><span class="p">;</span> <span class="mi">16</span><span class="p">],</span>
    <span class="n">stack_pointer</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span>
    <span class="n">delay_timer</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span>
    <span class="n">sound_timer</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span>
    <span class="n">keypad</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">16</span><span class="p">],</span>
    <span class="k">pub</span> <span class="n">video</span><span class="p">:</span> <span class="p">[</span><span class="nb">u32</span><span class="p">;</span> <span class="mi">64</span> <span class="o">*</span> <span class="mi">32</span><span class="p">],</span>
    <span class="n">op_code</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
    <span class="n">table</span><span class="p">:</span> <span class="p">[</span><span class="k">fn</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">Chip8</span><span class="p">);</span> <span class="mi">0xF</span><span class="o">+</span><span class="mi">1</span><span class="p">],</span>
    <span class="n">table0</span><span class="p">:</span> <span class="p">[</span><span class="k">fn</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">Chip8</span><span class="p">);</span> <span class="mi">0xE</span><span class="o">+</span><span class="mi">1</span><span class="p">],</span>
    <span class="n">table8</span><span class="p">:</span> <span class="p">[</span><span class="k">fn</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">Chip8</span><span class="p">);</span> <span class="mi">0xE</span><span class="o">+</span><span class="mi">1</span><span class="p">],</span>
    <span class="n">tableE</span><span class="p">:</span> <span class="p">[</span><span class="k">fn</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">Chip8</span><span class="p">);</span> <span class="mi">0xE</span><span class="o">+</span><span class="mi">1</span><span class="p">],</span>
    <span class="n">tableF</span><span class="p">:</span> <span class="p">[</span><span class="k">fn</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">Chip8</span><span class="p">);</span> <span class="mi">0x65</span><span class="o">+</span><span class="mi">1</span><span class="p">],</span>
    <span class="n">debug_mode</span><span class="p">:</span> <span class="nb">bool</span><span class="p">,</span>
<span class="p">}</span>
</code></pre></div></div>

<h1 id="loading-a-rom">Loading a ROM</h1>

<p>In a CHIP-8 emulator, the most crucial task after initializing the system is loading a ROM (Read Only Memory) that contains the game or program we want to run. Let’s delve into how the load_rom function works.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cd">/// Loads a given rom into memory, starting from memory address 0x200</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">load_rom</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">path</span><span class="p">:</span> <span class="n">PathBuf</span><span class="p">)</span> <span class="p">{</span>
</code></pre></div></div>

<p><strong>Purpose</strong>:
This function is designed to load a provided ROM file into the emulator’s memory. It expects a PathBuf which is the path to the ROM file you want to load.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">start_address</span> <span class="o">=</span> <span class="mi">0x200</span><span class="p">;</span>
</code></pre></div></div>

<p><strong>Start Address</strong>:
In the CHIP-8 system, the memory address 0x200 is the conventional starting point for most ROMs. The memory before this address is typically reserved for the system’s use, like the CHIP-8 interpreter itself and the font set.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">buf</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">u8</span><span class="o">&gt;</span> <span class="o">=</span> <span class="nn">Vec</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
</code></pre></div></div>

<p><strong>Byte Buffer</strong>:
The buf vector will temporarily store the bytes read from the ROM file. It’s initialized as an empty vector of bytes (u8).</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">byte</span> <span class="k">in</span> <span class="n">file</span><span class="nf">.bytes</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">byte</span> <span class="o">=</span> <span class="k">match</span> <span class="n">byte</span> <span class="p">{</span>
        <span class="nf">Ok</span><span class="p">(</span><span class="n">byte</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">byte</span><span class="p">,</span>
        <span class="nf">Err</span><span class="p">(</span><span class="n">error</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="nd">panic!</span><span class="p">(</span><span class="s">"Provided rom is not a valid binary. {:?}"</span><span class="p">,</span> <span class="n">error</span><span class="p">),</span>
    <span class="p">};</span>
    <span class="n">buf</span><span class="nf">.push</span><span class="p">(</span><span class="n">byte</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Reading the ROM</strong>:
I then iterate over each byte in the ROM file. If a byte is successfully read, it’s added to the buf vector. However, if there’s any error while reading, the program will panic and provide an error message indicating that the ROM might not be a valid binary.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="n">buf</span><span class="nf">.len</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">self</span><span class="py">.memory</span><span class="p">[</span><span class="n">start_address</span> <span class="o">+</span> <span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">buf</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Loading into CHIP-8 Memory</strong>:
Once the ROM’s bytes are stored in the buffer, I proceed to load each byte into the CHIP-8’s memory, starting from the start_address (0x200). This loop efficiently transfers the program from our buffer to the emulator’s memory.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="k">self</span><span class="py">.debug_mode</span><span class="p">)</span> <span class="p">{</span>
    <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"ROM Loaded"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Completion Message</strong>:
Finally, if the debug_mode is enabled, a message indicating the successful loading of the ROM will be printed.</p>

<p>In conclusion, the load_rom function is essential for the emulator’s operation, ensuring that the game or program ROM is correctly loaded into memory and ready for execution.</p>

<h1 id="printing-the-video-buffer">Printing the Video Buffer</h1>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">pretty_print_video</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
</code></pre></div></div>

<p><strong>Purpose</strong>:
This function’s primary role is to render the video buffer of the CHIP-8 emulator in a more visually-pleasing manner on the console.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">print!</span><span class="p">(</span><span class="s">"</span><span class="se">\x1B</span><span class="s">[2J</span><span class="se">\x1B</span><span class="s">[1;1H"</span><span class="p">);</span>
</code></pre></div></div>

<p><strong>Console Clear and Reset</strong>:
This line employs ANSI escape codes to clear the console and move the cursor to the top-left position. This is done so that each frame from the video buffer is drawn on a fresh screen, preventing overlap and ensuring clarity.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">new_vec</span> <span class="o">=</span> <span class="k">self</span><span class="py">.video</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.peekable</span><span class="p">();</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">rows</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="n">_</span><span class="o">&gt;&gt;</span> <span class="o">=</span> <span class="nd">vec!</span><span class="p">[];</span>
</code></pre></div></div>

<p><strong>Initialization</strong>:
We first convert the video buffer into an iterator that also supports the peek method. We also create an empty rows vector that will later store the video data in row-wise chunks.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">while</span> <span class="n">new_vec</span><span class="nf">.peek</span><span class="p">()</span><span class="nf">.is_some</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">chunk</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">_</span><span class="o">&gt;</span> <span class="o">=</span> <span class="n">new_vec</span><span class="nf">.by_ref</span><span class="p">()</span><span class="nf">.take</span><span class="p">(</span><span class="mi">64</span><span class="p">)</span><span class="nf">.collect</span><span class="p">();</span>
    <span class="n">rows</span><span class="nf">.push</span><span class="p">(</span><span class="n">chunk</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Chunking Video Buffer</strong>:
CHIP-8 has a resolution of 64x32 pixels. Here, we take the linear video buffer and split it into rows of 64 pixels each. These rows are stored in the rows vector, making it easier to print them line by line.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">row</span> <span class="k">in</span> <span class="n">rows</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">current_row</span> <span class="o">=</span> <span class="s">""</span><span class="nf">.to_string</span><span class="p">();</span>
</code></pre></div></div>

<p><strong>Iterating Over Rows</strong>:
For each row in our rows vector, we initiate an empty string current_row that will represent the current line of pixels.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">pixel</span> <span class="k">in</span> <span class="n">row</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">pixel</span> <span class="o">==</span> <span class="o">&amp;</span><span class="p">(</span><span class="mi">0xFFFFFFFF</span> <span class="k">as</span> <span class="nb">u32</span><span class="p">))</span> <span class="p">{</span>
        <span class="n">current_row</span><span class="nf">.push</span><span class="p">(</span><span class="sc">'█'</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n">current_row</span><span class="nf">.push</span><span class="p">(</span><span class="sc">' '</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Pixel Representation</strong>:
For each pixel in the row, we check its value. If the pixel’s value is 0xFFFFFFFF (which typically represents a white or “on” pixel in CHIP-8), we append a ‘█’ character to the current_row string. This character provides a filled visual representation. If the pixel is not ‘on’, we append a space to represent the “off” state.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span> <span class="n">current_row</span><span class="p">);</span>
</code></pre></div></div>

<p><strong>Printing the Row</strong>:
Lastly, we print out the constructed current_row string. This process is repeated for all rows, thus rendering the entire frame from the video buffer.</p>

<h1 id="loading-the-characters">Loading the Characters</h1>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">load_fonts</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
</code></pre></div></div>

<p><strong>Purpose</strong>:
This function is designed to load the CHIP-8’s built-in fontset into the emulator’s memory. This fontset contains graphical representations for the hexadecimal numbers 0 through F.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">fontset</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">80</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span>
            <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x90</span><span class="p">,</span> <span class="mi">0x90</span><span class="p">,</span> <span class="mi">0x90</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="c1">// 0</span>
            <span class="mi">0x20</span><span class="p">,</span> <span class="mi">0x60</span><span class="p">,</span> <span class="mi">0x20</span><span class="p">,</span> <span class="mi">0x20</span><span class="p">,</span> <span class="mi">0x70</span><span class="p">,</span> <span class="c1">// 1</span>
            <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x10</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x80</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="c1">// 2</span>
            <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x10</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x10</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="c1">// 3</span>
            <span class="mi">0x90</span><span class="p">,</span> <span class="mi">0x90</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x10</span><span class="p">,</span> <span class="mi">0x10</span><span class="p">,</span> <span class="c1">// 4</span>
            <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x80</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x10</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="c1">// 5</span>
            <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x80</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x90</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="c1">// 6</span>
            <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x10</span><span class="p">,</span> <span class="mi">0x20</span><span class="p">,</span> <span class="mi">0x40</span><span class="p">,</span> <span class="mi">0x40</span><span class="p">,</span> <span class="c1">// 7</span>
            <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x90</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x90</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="c1">// 8</span>
            <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x90</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x10</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="c1">// 9</span>
            <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x90</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x90</span><span class="p">,</span> <span class="mi">0x90</span><span class="p">,</span> <span class="c1">// A</span>
            <span class="mi">0xE0</span><span class="p">,</span> <span class="mi">0x90</span><span class="p">,</span> <span class="mi">0xE0</span><span class="p">,</span> <span class="mi">0x90</span><span class="p">,</span> <span class="mi">0xE0</span><span class="p">,</span> <span class="c1">// B</span>
            <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x80</span><span class="p">,</span> <span class="mi">0x80</span><span class="p">,</span> <span class="mi">0x80</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="c1">// C</span>
            <span class="mi">0xE0</span><span class="p">,</span> <span class="mi">0x90</span><span class="p">,</span> <span class="mi">0x90</span><span class="p">,</span> <span class="mi">0x90</span><span class="p">,</span> <span class="mi">0xE0</span><span class="p">,</span> <span class="c1">// D</span>
            <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x80</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x80</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="c1">// E</span>
            <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x80</span><span class="p">,</span> <span class="mi">0xF0</span><span class="p">,</span> <span class="mi">0x80</span><span class="p">,</span> <span class="mi">0x80</span><span class="p">,</span> <span class="c1">// F];</span>
        <span class="p">];</span>
</code></pre></div></div>

<p><strong>Fontset Declaration</strong>:
The fontset array contains the binary representations of the 16 characters (0-F) used in CHIP-8. Each character is 5 bytes long and can be rendered on a 4x5 pixel grid.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">fontset_start_address</span> <span class="o">=</span> <span class="mi">0x50</span><span class="p">;</span>
</code></pre></div></div>

<p><strong>Fontset Memory Location</strong>:
The fontset is loaded into a predefined starting address in memory, which is 0x50 or 80 in decimal. This is the standard location for the fontset in a typical CHIP-8 implementation.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="k">self</span><span class="py">.debug_mode</span><span class="p">)</span> <span class="p">{</span>
    <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Loading fontset"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Debug Mode Check</strong>:
If the emulator is running in debug mode, it will print a message to the console indicating that the fontset loading process has begun.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="n">fontset</span><span class="nf">.len</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">self</span><span class="py">.memory</span><span class="p">[</span><span class="n">fontset_start_address</span> <span class="o">+</span> <span class="n">i</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="n">fontset</span><span class="p">[</span><span class="n">i</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Loading the Fontset into Memory</strong>:
This loop iterates through every byte in the fontset array and places each byte into the corresponding location in the emulator’s memory. It starts at fontset_start_address and continues until the entire fontset is loaded.</p>

<h1 id="the-instructions">The Instructions</h1>

<p><strong>OP_00E0 - Clear Screen</strong>
This opcode clears the screen by setting all pixels in the video buffer to zero.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">OP_00E0</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// set video buffer to zero</span>
        <span class="k">self</span><span class="py">.video</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">;</span> <span class="mi">2048</span><span class="p">];</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_00EE - Return from subroutine</strong>
This opcode handles the end of a subroutine call. It decrements the stack pointer and sets the program counter back to the address at the top of the stack, effectively returning to where the subroutine was called.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_00EE</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="py">.stack_pointer</span> <span class="o">=</span> <span class="k">self</span><span class="py">.stack_pointer</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>

        <span class="k">self</span><span class="py">.program_counter</span> <span class="o">=</span> <span class="k">self</span><span class="py">.stack</span><span class="p">[</span><span class="k">self</span><span class="py">.stack_pointer</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">];</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_1nnn - Jump to location NNN</strong>
This opcode sets the program counter directly to the address NNN, effectively making the program jump to this new address.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_1nnn</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// using 0x0FFF I can take the NNN from the opcode while leaving the one</span>
        <span class="k">let</span> <span class="n">address</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0FFF</span><span class="p">;</span>

        <span class="k">self</span><span class="py">.program_counter</span> <span class="o">=</span> <span class="n">address</span><span class="p">;</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_2nnn - Call subroutine at location NNN</strong>
This opcode calls a subroutine. The current program counter is saved to the stack, then the stack pointer is incremented, and the program counter is set to the address NNN.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_2nnn</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">address</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0FFF</span><span class="p">;</span>

        <span class="k">self</span><span class="py">.stack</span><span class="p">[</span><span class="k">self</span><span class="py">.stack_pointer</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="k">self</span><span class="py">.program_counter</span><span class="p">;</span>
        <span class="k">self</span><span class="py">.stack_pointer</span> <span class="o">=</span> <span class="k">self</span><span class="py">.stack_pointer</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
        <span class="k">self</span><span class="py">.program_counter</span> <span class="o">=</span> <span class="n">address</span><span class="p">;</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_3xkk - Skip next instruction if Vx = kk</strong>
This opcode checks if register Vx contains the value kk. If true, it skips the next instruction by incrementing the program counter by 2.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_3xkk</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">byte</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x00FF</span><span class="p">;</span>

        <span class="k">let</span> <span class="n">byte</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="k">match</span> <span class="nn">u8</span><span class="p">::</span><span class="nf">try_from</span><span class="p">(</span><span class="n">byte</span><span class="p">)</span> <span class="p">{</span>
            <span class="nf">Ok</span><span class="p">(</span><span class="n">number</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">number</span><span class="p">,</span>
            <span class="nf">Err</span><span class="p">(</span><span class="n">error</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="nd">panic!</span><span class="p">(</span>
                <span class="s">"Could not turn u16 into u8 in OPCODE: 3XKK. Error: {}"</span><span class="p">,</span>
                <span class="n">error</span>
            <span class="p">),</span>
        <span class="p">};</span>

        <span class="k">if</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">==</span> <span class="n">byte</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.program_counter</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_4xkk - Skip next instruction if Vx != kk</strong>
Similar to the opcode above, but this opcode checks if register Vx does not contain the value kk. If true, it skips the next instruction.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_4xkk</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">byte</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x00FF</span><span class="p">;</span>

        <span class="k">let</span> <span class="n">byte</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="k">match</span> <span class="nn">u8</span><span class="p">::</span><span class="nf">try_from</span><span class="p">(</span><span class="n">byte</span><span class="p">)</span> <span class="p">{</span>
            <span class="nf">Ok</span><span class="p">(</span><span class="n">number</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">number</span><span class="p">,</span>
            <span class="nf">Err</span><span class="p">(</span><span class="n">error</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="nd">panic!</span><span class="p">(</span>
                <span class="s">"Could not turn u16 into u8 in OPCODE: 3XKK. Error: {}"</span><span class="p">,</span>
                <span class="n">error</span>
            <span class="p">),</span>
        <span class="p">};</span>

        <span class="c1">// this != is the only difference from the function above</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">!=</span> <span class="n">byte</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.program_counter</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_5xy0 - Skip next instruction if Vx = Vy</strong>
This opcode compares the values of two registers, Vx and Vy. If their values are equal, the next instruction is skipped.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_5xy0</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">Vy</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x00F0</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">if</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">==</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vy</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.program_counter</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_6xkk - Set Vx = kk</strong>
This opcode directly sets the value of register Vx to kk.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_6xkk</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">byte</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x00FF</span><span class="p">;</span>

        <span class="k">let</span> <span class="n">byte</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="k">match</span> <span class="nn">u8</span><span class="p">::</span><span class="nf">try_from</span><span class="p">(</span><span class="n">byte</span><span class="p">)</span> <span class="p">{</span>
            <span class="nf">Ok</span><span class="p">(</span><span class="n">number</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">number</span><span class="p">,</span>
            <span class="nf">Err</span><span class="p">(</span><span class="n">error</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="nd">panic!</span><span class="p">(</span>
                <span class="s">"Could not turn u16 into u8 in OPCODE 6XKK. Error: {}"</span><span class="p">,</span>
                <span class="n">error</span>
            <span class="p">),</span>
        <span class="p">};</span>

        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="n">byte</span><span class="p">;</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>

    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_7xkk - Set Vx = Vx + kk</strong>
This opcode adds the value kk to register Vx and then stores the result back into Vx. If there’s an overflow, it wraps around.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_7xkk</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">byte</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="k">as</span> <span class="nb">u8</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mi">0x00FF</span><span class="p">;</span>

        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="p">(((</span><span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">)</span> <span class="o">+</span> <span class="n">byte</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">)</span> <span class="o">%</span> <span class="mi">256</span><span class="p">)</span> <span class="k">as</span> <span class="nb">u8</span><span class="p">;</span>

        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_8xy0 - Set Vx = Vy</strong>
This opcode copies the value from register Vy to register Vx.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_8xy0</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">Vy</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x00F0</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vy</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">];</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_8xy1 - Set Vx = Vx OR Vy</strong>
This opcode performs a bitwise OR operation between the values in registers Vx and Vy, then stores the result back into Vx.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_8xy1</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">Vy</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x00F0</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="p">|</span><span class="o">=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vy</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">];</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_8xy2</strong> - Set Vx = Vx AND Vy</p>

<p>Functionality: Bitwise AND of Vx and Vy.</p>

<p>Implementation Details: The values of registers Vx and Vy are obtained from the opcode. The value at register Vx is then bitwise AND-ed with the value at register Vy, and the result is stored back in Vx.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_8xy2</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">Vy</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x00F0</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">&amp;=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vy</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">];</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_8xy3</strong> - Set Vx = Vx XOR Vy</p>

<p>Functionality: Bitwise XOR of Vx and Vy.</p>

<p>Implementation Details: The values of registers Vx and Vy are obtained from the opcode. The value at register Vx is then bitwise XOR-ed with the value at register Vy, and the result is stored back in Vx.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_8xy3</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">Vy</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x00F0</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">^=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vy</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">];</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_8xy4</strong> - Set Vx = Vx + Vy, set VF = carry.</p>

<p>Functionality: Adds Vx and Vy. Checks for an overflow.</p>

<p>Implementation Details: If the result exceeds 255, the VF register is set to 1 (indicating a carry). Otherwise, it’s set to 0. Only the lowest 8 bits of the result are kept and stored back in Vx.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_8xy4</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">Vy</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x00F0</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">let</span> <span class="n">sum</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span> <span class="o">+</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vy</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">;</span>

        <span class="k">if</span> <span class="n">sum</span> <span class="o">&gt;</span> <span class="mi">255</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="mi">0xF</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="mi">0xF</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">sum</span> <span class="o">&amp;</span> <span class="mi">0xFF</span><span class="p">)</span> <span class="k">as</span> <span class="nb">u8</span><span class="p">;</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_8xy5</strong> - Set Vx = Vx - Vy, set VF = NOT borrow.</p>

<p>Functionality: Subtracts Vy from Vx. Checks if there’s a borrow.</p>

<p>Implementation Details: If Vx &gt; Vy, VF is set to 1 (no borrow). If Vy &gt; Vx, VF is set to 0 (indicates a borrow). The result of the subtraction is then stored back in Vx.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_8xy5</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">Vy</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x00F0</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">if</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">&gt;</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vy</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="mi">0xF</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="mi">0xF</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="p">}</span>


        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span><span class="nf">.wrapping_sub</span><span class="p">(</span><span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vy</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]);</span>

        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_8xy6</strong> - Set Vx = Vx SHR 1.</p>

<p>Functionality: Bitwise shift right of Vx.</p>

<p>Implementation Details: If the least-significant bit of Vx is 1, then VF is set to 1; otherwise, it’s 0. The value in Vx is then halved (shifted right by one bit).</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_8xy6</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="c1">// Save LSB in VF</span>
        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="mi">0xF</span><span class="p">]</span> <span class="o">=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">&amp;</span> <span class="mi">0x1</span><span class="p">;</span>

        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span><span class="nf">.shr_assign</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_8xy7</strong> - SUBN Vx, Vy</p>

<p>Functionality: Subtract Vx from Vy.</p>

<p>Implementation Details: If Vy &gt; Vx, VF is set to 1 (no borrow). If Vx &gt; Vy, VF is set to 0 (indicates a borrow). The result of Vy - Vx is then stored back in Vx.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_8xy7</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">Vy</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x00F0</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">if</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vy</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">&gt;</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="mi">0xF</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="mi">0xF</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="c1">//self.registers[Vx as usize] = self.registers[Vy as usize] - self.registers[Vx as usize];</span>
        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vy</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span><span class="nf">.wrapping_sub</span><span class="p">(</span><span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]);</span>

        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_8xyE</strong> - Set Vx = Vx SHL 1.</p>

<p>Functionality: Bitwise shift left of Vx.</p>

<p>Implementation Details: If the most-significant bit of Vx is 1, then VF is set to 1; otherwise, it’s 0. The value in Vx is then doubled (shifted left by one bit).</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_8xyE</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="c1">// save MSB in VF</span>
        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="mi">0xF</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">&amp;</span> <span class="mi">0x80</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">7</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span><span class="nf">.shl_assign</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_9xy0</strong> - Skip next instruction if Vx != Vy</p>

<p>Functionality: Conditional instruction skipping.</p>

<p>Implementation Details: If the values in registers Vx and Vy are not equal, the program counter is increased by 2, effectively skipping the next instruction.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_9xy0</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">Vy</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x00F0</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">if</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">!=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vy</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.program_counter</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_Annn</strong> - set I = nnn</p>

<p>Functionality: Sets the index register to the value nnn from the opcode.</p>

<p>Implementation Details: The value nnn from the opcode is directly assigned to the index register.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_Annn</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">address</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0FFF</span><span class="p">;</span>

        <span class="k">self</span><span class="py">.index_register</span> <span class="o">=</span> <span class="n">address</span><span class="p">;</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_Bnnn</strong> - Jump to location nnn + V0</p>

<p>Functionality: Sets the program counter to the address nnn + the value in register V0.</p>

<p>Implementation Details: The program counter is adjusted to the new address computed as the sum of nnn and the value in register V0.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_Bnnn</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">address</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0FFF</span><span class="p">;</span>

        <span class="k">self</span><span class="py">.program_counter</span> <span class="o">=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span> <span class="o">+</span> <span class="n">address</span><span class="p">;</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_Cxkk</strong> - Set Vx = random byte AND kk.</p>

<p>Functionality: Sets Vx to the result of a bitwise AND operation between a random byte and kk.</p>

<p>Implementation Details: A random byte is generated and bitwise AND-ed with the value kk. The result is then stored in register Vx.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_Cxkk</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">byte</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x00FF</span><span class="p">;</span>

        <span class="k">let</span> <span class="n">byte</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="k">match</span> <span class="nn">u8</span><span class="p">::</span><span class="nf">try_from</span><span class="p">(</span><span class="n">byte</span><span class="p">)</span> <span class="p">{</span>
            <span class="nf">Ok</span><span class="p">(</span><span class="n">number</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">number</span><span class="p">,</span>
            <span class="nf">Err</span><span class="p">(</span><span class="n">error</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="nd">panic!</span><span class="p">(</span>
                <span class="s">"Could not turn u16 into u8 in OPCODE CXKK. Error: {}"</span><span class="p">,</span>
                <span class="n">error</span>
            <span class="p">),</span>
        <span class="p">};</span>

        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="k">self</span><span class="nf">.rand_byte</span><span class="p">()</span> <span class="o">&amp;</span> <span class="n">byte</span><span class="p">;</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_Dxyn</strong> - Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision.</p>

<p>Functionality: Draws a sprite on the display.</p>

<p>Implementation Details: The sprite data starts at the memory location pointed to by the index register. The sprite is drawn at coordinates (Vx, Vy) and has a height of n bytes. If a sprite pixel collides with an existing pixel on the screen, VF is set to 1.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_Dxyn</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">Vy</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x00F0</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">height</span> <span class="o">=</span> <span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x000F</span><span class="p">;</span>
        <span class="k">let</span> <span class="n">VIDEO_WIDTH</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="mi">64</span><span class="p">;</span>
        <span class="k">let</span> <span class="n">VIDEO_HEIGHT</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="mi">32</span><span class="p">;</span>

        <span class="c1">// wrap if going over boundaries</span>
        <span class="k">let</span> <span class="n">x_pos</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">%</span> <span class="n">VIDEO_WIDTH</span><span class="p">;</span>
        <span class="k">let</span> <span class="n">y_pos</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vy</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">%</span> <span class="n">VIDEO_HEIGHT</span><span class="p">;</span>

        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="mi">0xF</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

        <span class="k">for</span> <span class="n">row</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="n">height</span> <span class="p">{</span>
            <span class="k">let</span> <span class="n">sprite_byte</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="k">self</span><span class="py">.memory</span><span class="p">[(</span><span class="k">self</span><span class="py">.index_register</span> <span class="o">+</span> <span class="n">row</span><span class="p">)</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">];</span>

            <span class="k">for</span> <span class="n">col</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="mi">8</span> <span class="p">{</span>
                <span class="k">let</span> <span class="n">sprite_pixel</span> <span class="o">=</span> <span class="n">sprite_byte</span> <span class="o">&amp;</span> <span class="p">((</span><span class="mi">0x80</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="n">col</span> <span class="k">as</span> <span class="nb">u32</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="k">as</span> <span class="nb">u8</span><span class="p">);</span>
                <span class="c1">// casting without error checking here is fine because col and raw wil alwyays be lower than 255(they are 64 and 32)</span>
                <span class="c1">//let mut screen_pixel = self.video[(((y_pos as u16 + row) * (VIDEO_WIDTH as u16) + (x_pos as u16) + col)) as usize];</span>

                <span class="c1">// TODO: Fix this, sometimes the index is out of bounds because rust doesn't wrap,</span>
                <span class="c1">// so all subtractions and all additions should be wrapping_sub() and wrapping_add()</span>
                <span class="c1">// instead of normal + and -.</span>
                <span class="k">let</span> <span class="n">video_index</span> <span class="o">=</span> <span class="p">((</span><span class="n">y_pos</span> <span class="k">as</span> <span class="nb">u16</span> <span class="o">+</span> <span class="n">row</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="n">VIDEO_WIDTH</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="n">x_pos</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">)</span> <span class="o">+</span> <span class="n">col</span><span class="p">)</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">;</span>

                <span class="c1">// sprite pixel is on</span>
                <span class="k">if</span> <span class="n">sprite_pixel</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
                    <span class="c1">// screen pixel also on - collision</span>
                    <span class="k">if</span> <span class="k">self</span><span class="py">.video</span><span class="p">[</span><span class="n">video_index</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0xFFFFFFFF</span> <span class="p">{</span>
                        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="mi">0xF</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
                    <span class="p">}</span>

                    <span class="c1">// Effectively XOR with the sprite pixel</span>
                    <span class="k">self</span><span class="py">.video</span><span class="p">[</span><span class="n">video_index</span><span class="p">]</span> <span class="o">^=</span> <span class="mi">0xFFFFFFFF</span><span class="p">;</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_Ex9E</strong> - Skip next instruction if key with the value of Vx is pressed.</p>

<p>Functionality: Conditional instruction skipping based on key press.</p>

<p>Implementation Details: If the key corresponding to the value in register Vx is currently pressed, the program counter is increased by 2, effectively skipping the next instruction.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_Ex9E</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">key</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">];</span>

        <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="n">key</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.program_counter</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_ExA1</strong> - Skip next instruction if key with the value of Vx is not pressed.</p>

<p>Functionality: Conditional instruction skipping based on key release.</p>

<p>Implementation Details: If the key corresponding to the value in register Vx is currently not pressed, the program counter is increased by 2, effectively skipping the next instruction.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_ExA1</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">key</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">];</span>

        <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="n">key</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.program_counter</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_Fx07</strong> - Set Vx = delay timer value</p>

<p>Functionality: Sets register Vx to the value of the delay timer.</p>

<p>Implementation Details: Vx is extracted from the opcode, and its value is set to the current value of the delay timer.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_Fx07</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="k">self</span><span class="py">.delay_timer</span><span class="p">;</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_Fx0A</strong> - Wait for a key press, store the value of the key in Vx</p>

<p>Functionality: Halts execution until a key press is detected, then stores the key value in Vx.</p>

<p>Implementation Details: The function checks each key in the keypad array. If a key is pressed (has a non-zero value), the corresponding key value is stored in Vx. If no keys are pressed, the program counter is decremented by 2, effectively halting the program and rerunning the same opcode until a key is pressed.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_Fx0A</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="mi">7</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="mi">8</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="mi">9</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="mi">10</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="mi">11</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="mi">11</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="mi">12</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="mi">12</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="mi">13</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="mi">13</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="mi">14</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="mi">14</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="k">self</span><span class="py">.keypad</span><span class="p">[</span><span class="mi">15</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="mi">15</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.program_counter</span> <span class="o">-=</span> <span class="mi">2</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_Fx15</strong> - Set delay timer = Vx</p>

<p>Functionality: Sets the delay timer to the value in Vx.</p>

<p>Implementation Details: Vx is extracted from the opcode, and the delay timer’s value is set to the value in Vx.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_Fx15</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">self</span><span class="py">.delay_timer</span> <span class="o">=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">];</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_Fx18</strong> - Set sound timer = Vx</p>

<p>Functionality: Sets the sound timer to the value in Vx.</p>

<p>Implementation Details: Vx is extracted from the opcode, and the sound timer’s value is set to the value in Vx.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_Fx18</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">self</span><span class="py">.sound_timer</span> <span class="o">=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">];</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_Fx1E</strong> - Set I = I + Vx</p>

<p>Functionality: Increments the index register I by the value in Vx.</p>

<p>Implementation Details: Vx is extracted from the opcode, and the index register’s value is increased by the value in Vx.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_Fx1E</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">self</span><span class="py">.index_register</span> <span class="o">+=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">;</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_Fx29</strong> - Set I = location of sprite for digit Vx</p>

<p>Functionality: Sets I to the starting address of the sprite data for a given digit in Vx.</p>

<p>Implementation Details: The function calculates the starting address of the sprite (5 bytes per sprite) and assigns it to the index register.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_Fx29</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="n">digit</span> <span class="o">=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">];</span>
        <span class="k">let</span> <span class="n">fontset_start_address</span> <span class="o">=</span> <span class="mi">0x50</span><span class="p">;</span>

        <span class="k">self</span><span class="py">.index_register</span> <span class="o">=</span> <span class="p">(</span><span class="n">fontset_start_address</span> <span class="o">+</span> <span class="p">(</span><span class="mi">5</span><span class="o">*</span><span class="n">digit</span><span class="p">))</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">;</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_Fx33</strong> - Store BCD representation of Vx in memory locations I, I+1, and I+2</p>

<p>Functionality: Converts Vx into its BCD (Binary-Coded Decimal) representation and stores the digits in memory.</p>

<p>Implementation Details: Vx is extracted and broken down into its ones, tens, and hundreds digits. These are then stored in consecutive memory locations starting at I.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_Fx33</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">let</span> <span class="k">mut</span> <span class="n">value</span><span class="p">:</span> <span class="nb">u8</span> <span class="o">=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">Vx</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">];</span>

        <span class="c1">// ones place</span>
        <span class="k">self</span><span class="py">.memory</span><span class="p">[(</span><span class="k">self</span><span class="py">.index_register</span> <span class="o">+</span> <span class="mi">2</span><span class="p">)</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span> <span class="o">%</span> <span class="mi">10</span><span class="p">;</span>
        <span class="n">value</span> <span class="o">/=</span> <span class="mi">10</span><span class="p">;</span>

        <span class="c1">// tens place</span>
        <span class="k">self</span><span class="py">.memory</span><span class="p">[(</span><span class="k">self</span><span class="py">.index_register</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span> <span class="o">%</span> <span class="mi">10</span><span class="p">;</span>
        <span class="n">value</span> <span class="o">/=</span> <span class="mi">10</span><span class="p">;</span>

        <span class="c1">// hundreds place</span>
        <span class="k">self</span><span class="py">.memory</span><span class="p">[</span><span class="k">self</span><span class="py">.index_register</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span> <span class="o">%</span> <span class="mi">10</span><span class="p">;</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_Fx55</strong> - Store registers V0 to VX in memory starting at location I</p>

<p>Functionality: Stores the values of registers V0 through Vx in memory starting at the address in I.</p>

<p>Implementation Details: For each register from V0 to Vx, the function stores its value in memory, beginning at the address specified by the index register.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_Fx55</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="p">(</span><span class="n">Vx</span> <span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.memory</span><span class="p">[(</span><span class="k">self</span><span class="py">.index_register</span> <span class="o">+</span> <span class="n">i</span><span class="p">)</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">i</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">];</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_Fx65</strong> - Read registers V0 through Vx from memory starting at location I</p>

<p>Functionality: Populates registers V0 through Vx with values from memory starting at the address in I.</p>

<p>Implementation Details: For each register from V0 to Vx, the function assigns it the value found in memory, starting at the address in the index register.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_Fx65</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">Vx</span><span class="p">:</span> <span class="nb">u16</span> <span class="o">=</span> <span class="p">(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x0F00</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>

        <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="p">(</span><span class="n">Vx</span> <span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">self</span><span class="py">.registers</span><span class="p">[</span><span class="n">i</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="o">=</span> <span class="k">self</span><span class="py">.memory</span><span class="p">[(</span><span class="k">self</span><span class="py">.index_register</span> <span class="o">+</span> <span class="n">i</span><span class="p">)</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">];</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p><strong>OP_ERR</strong> - Fallback opcode for errors</p>

<p>Functionality: Error-handling opcode for invalid opcodes.</p>

<p>Implementation Details: When an opcode does not match any of the known opcodes, this function is triggered. It prints an error message showing the invalid opcode.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">fn</span> <span class="nf">OP_ERR</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"[ERROR]: Opcode {} not valid"</span><span class="p">,</span> <span class="k">self</span><span class="py">.op_code</span><span class="p">);</span> 
        <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
            <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Ran opcode: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<h1 id="function-pointer-table">Function Pointer Table</h1>

<p>One of the unique characteristics of the CHIP-8 instruction set is that it is not strictly linear.</p>

<p>Some opcodes require multiple levels of decoding. Rather than having a monolithic function to handle every possible opcode, it’s more efficient and maintainable to use tables (or jump tables). These tables store function pointers, pointing to the relevant opcode implementation.</p>

<p>This design not only makes the code cleaner but also improves opcode lookup times.</p>

<h2 id="table0-function">Table0 Function</h2>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">Table0</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
        <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Running table: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
    <span class="p">}</span>
    <span class="k">self</span><span class="py">.table0</span><span class="p">[(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x000F</span><span class="p">)</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">](</span><span class="k">self</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Purpose: This function handles opcodes that begin with the hexadecimal 0.</p>

<p>Implementation Details: The opcode’s last nibble (4 bits) is extracted and used as an index to look up the corresponding function in the table0 array. This function pointer is then invoked with the emulator’s current instance as its argument.</p>

<h2 id="table8-function">Table8 Function</h2>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">Table8</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
        <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Running table: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
    <span class="p">}</span>
    <span class="k">self</span><span class="py">.table8</span><span class="p">[(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x000F</span><span class="p">)</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">](</span><span class="k">self</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Purpose: This function addresses opcodes that start with 8 and are followed by three more hexadecimal values, where the last nibble determines the exact operation (e.g., ADD, OR, AND).</p>

<p>Implementation Details: Similar to Table0, the last nibble of the opcode determines the exact function to call from the table8 array.</p>

<h2 id="tablee-function">TableE Function</h2>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">TableE</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
        <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Running table: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
    <span class="p">}</span>
    <span class="k">self</span><span class="py">.tableE</span><span class="p">[(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x000F</span><span class="p">)</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">](</span><span class="k">self</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Purpose: Manages opcodes beginning with E.</p>

<p>Implementation Details: The function uses the opcode’s last nibble to find the corresponding function from the tableE array.</p>

<h2 id="tablef-function">TableF Function</h2>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">TableF</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="k">self</span><span class="py">.debug_mode</span> <span class="p">{</span>
        <span class="nd">eprintln!</span><span class="p">(</span><span class="s">"Running table: {}"</span><span class="p">,</span> <span class="nd">function_name!</span><span class="p">());</span>
    <span class="p">}</span>
    <span class="k">self</span><span class="py">.tableF</span><span class="p">[(</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0x00FF</span><span class="p">)</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">](</span><span class="k">self</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Purpose: A handler for opcodes that start with F. Unlike the previous tables, the distinguishing feature for opcodes managed by this table is the last two hexadecimal values (byte).</p>

<p>Implementation Details: The function extracts the opcode’s last byte and uses it to fetch the relevant function from the tableF array.</p>

<h1 id="fetch-decode-execute">Fetch, Decode, Execute</h1>

<p>The main cycle in a CHIP-8 emulator represents the heart of its operation. Each iteration of this cycle is broken in 3 parts: <strong>fetch</strong> an opcode, <strong>decode</strong> it, and then <strong>execute</strong> the corresponding instruction. Let’s dissect each part of the Cycle function to understand its role.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">Cycle</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
</code></pre></div></div>

<p>This function defines the main operational cycle of the emulator. It’s called repeatedly to ensure the CHIP-8 system remains functional.
Fetching the Opcode</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">self</span><span class="py">.op_code</span> <span class="o">=</span> <span class="p">((</span><span class="k">self</span><span class="py">.memory</span><span class="p">[</span><span class="k">self</span><span class="py">.program_counter</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">)</span><span class="nf">.checked_shl</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span> <span class="p">|</span> <span class="k">self</span><span class="py">.memory</span><span class="p">[(</span><span class="k">self</span><span class="py">.program_counter</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">;</span>
</code></pre></div></div>

<p>Purpose: CHIP-8 opcodes are 2 bytes long. This section combines two consecutive bytes from the emulator’s memory to form a single opcode.</p>

<p>Implementation Details: The opcode is constructed by shifting the first byte to the left by 8 bits and then performing a bitwise OR with the second byte. This essentially merges the two bytes into one contiguous 16-bit opcode.</p>

<p><strong>Incrementing the Program Counter</strong></p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">self</span><span class="py">.program_counter</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>
</code></pre></div></div>

<p>Purpose: The program counter points to the memory location of the next opcode to be executed. Since each opcode is 2 bytes long, the program counter needs to be incremented by 2 to point to the next instruction.</p>

<p>Implementation Details: A simple addition operation increments the program counter by two.</p>

<p><strong>Decoding and Executing the Opcode</strong></p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">self</span><span class="py">.table</span><span class="p">[((</span><span class="k">self</span><span class="py">.op_code</span> <span class="o">&amp;</span> <span class="mi">0xF000</span><span class="p">)</span><span class="nf">.checked_shr</span><span class="p">(</span><span class="mi">12</span><span class="p">)</span><span class="nf">.unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">](</span><span class="k">self</span><span class="p">);</span>
</code></pre></div></div>

<p>Purpose: Determines which instruction the fetched opcode represents and then executes that instruction.</p>

<p>Implementation Details:
The most significant nibble (the first 4 bits) of the opcode is extracted. This value is then used as an index to fetch the corresponding function pointer from the table array.
The function pointer (which points to an opcode-handling function) is then invoked.</p>

<p><strong>Decrementing the Delay Timer</strong></p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="k">self</span><span class="py">.delay_timer</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">self</span><span class="py">.delay_timer</span> <span class="o">-=</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Purpose: CHIP-8 has a delay timer that counts down at 60Hz when set to a non-zero value. When this timer reaches zero, it stops counting down.</p>

<p>Implementation Details: If the delay timer is greater than 0, it’s decremented by 1.</p>

<p><strong>Decrementing the Sound Timer</strong></p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="k">self</span><span class="py">.sound_timer</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">self</span><span class="py">.sound_timer</span> <span class="o">-=</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Purpose: The CHIP-8 system also features a sound timer. When this timer is non-zero, a beep sounds, counting down at the same 60Hz frequency.</p>

<p>Implementation Details: Similar to the delay timer, if the sound timer’s value is above 0, it gets decremented by 1.</p>

<h1 id="results">Results</h1>

<style>
    .image-gallery {
        display: flex;
        flex-wrap: wrap;
        gap: 15px;  /* Adjust this for the minimal space between images */
        justify-content: space-between;
        align-items: flex-start;
        width: calc(100% + 20vw); /* Extend beyond parent width */
        margin: 0 -10vw; /* Adjust this value to offset the extended width */
        margin-top: 30px;
        margin-bottom: 30px;
    }

    .image-gallery .image-item {
        flex-grow: 1;
        min-width: 40%;  /* Ensure image is at least 60% of its original size */
        box-sizing: border-box;
    }

    .image-gallery .image-item:nth-child(6n+1),
    .image-gallery .image-item:nth-child(6n+2) {
        flex-basis: calc(50% - 1px);  /* for 2 items in the row */
    }

    .image-gallery .image-item:nth-child(6n+3),
    .image-gallery .image-item:nth-child(6n+4),
    .image-gallery .image-item:nth-child(6n+5) {
        flex-basis: calc(33.33% - 1px);  /* for 3 items in the row */
    }

    .image-gallery .image-item a {
        display: block;
        text-align: center;
        text-decoration: none;
        color: #777;
        width: 100%;
    }

    .image-gallery .image-item a img {
        max-width: 100%;
        height: auto;
        display: block;
    }
</style>

<div class="image-gallery">

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    
        
            
            
            <div class="image-item">
                <a href="/assets/posts/chip8/hello-ss.webp" title="hello-ss">
                    <img src="/assets/posts/chip8/hello-ss.webp" alt="hello-ss" title="hello-ss" />
                </a>
            </div>
        
    

    
        
            
            
            <div class="image-item">
                <a href="/assets/posts/chip8/ibm-logo-ss.webp" title="ibm-logo-ss">
                    <img src="/assets/posts/chip8/ibm-logo-ss.webp" alt="ibm-logo-ss" title="ibm-logo-ss" />
                </a>
            </div>
        
    

    
        
            
            
            <div class="image-item">
                <a href="/assets/posts/chip8/maze-ss.webp" title="maze-ss">
                    <img src="/assets/posts/chip8/maze-ss.webp" alt="maze-ss" title="maze-ss" />
                </a>
            </div>
        
    

    
        
            
            
            <div class="image-item">
                <a href="/assets/posts/chip8/opcode-test-ss.webp" title="opcode-test-ss">
                    <img src="/assets/posts/chip8/opcode-test-ss.webp" alt="opcode-test-ss" title="opcode-test-ss" />
                </a>
            </div>
        
    

    
        
            
            
            <div class="image-item">
                <a href="/assets/posts/chip8/plane-ss.webp" title="plane-ss">
                    <img src="/assets/posts/chip8/plane-ss.webp" alt="plane-ss" title="plane-ss" />
                </a>
            </div>
        
    

    
        
            
            
            <div class="image-item">
                <a href="/assets/posts/chip8/sqrt-ss.webp" title="sqrt-ss">
                    <img src="/assets/posts/chip8/sqrt-ss.webp" alt="sqrt-ss" title="sqrt-ss" />
                </a>
            </div>
        
    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

</div>

<h1 id="references--acknowledgments">References &amp; Acknowledgments</h1>

<p>When coding this emulator, I was around 15 years old. I took heavy inspiration from <a href="https://austinmorlan.com/posts/chip8_emulator/">this awesome guide</a> by Austin Morlan.</p>

<p>While the Rust code is 100% mine, his C++ code was a big inspiration while creating both the program and this writeup.</p>

<p>Make sure to checkout the code <a href="https://github.com/Ferryistaken/CHIP8-rs">here</a>.</p>]]></content><author><name>Alessandro Ferrari</name><email>alessandroferrari@gatech.edu</email></author><category term="coding" /><category term="rust" /><category term="software" /><category term="opensource" /><summary type="html"><![CDATA[In this brief writeup, I’ll show you how I wrote my first emulator–an emulator to the CHIP-8 programming language–in Rust.]]></summary></entry><entry><title type="html">How to create your own “smart” business card for free</title><link href="https://alessandroferrari.live/open-source-business-card/" rel="alternate" type="text/html" title="How to create your own “smart” business card for free" /><published>2022-09-14T20:54:00+00:00</published><updated>2022-09-14T20:54:00+00:00</updated><id>https://alessandroferrari.live/open-source-business-card</id><content type="html" xml:base="https://alessandroferrari.live/open-source-business-card/"><![CDATA[<h1 id="introduction">Introduction</h1>

<p>In this post, I will show you how to achieve 90% of the effect of a service like <a href="https://dotcards.net/">dotcards</a> for free.</p>

<h2 id="showcase">ShowCase</h2>

<p>At the end of this guide, your new business card will look like this:</p>

<table>
  <thead>
    <tr>
      <th>The Website</th>
      <th>The Native Contact Card</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><img src="/assets/posts/open-source-business-card/safari-ss.webp" alt="smart business card ss 1" /></td>
      <td><img src="/assets/posts/open-source-business-card/native-contact-ss-obfuscated.webp" alt="smart business card ss 2" /></td>
    </tr>
  </tbody>
</table>

<h2 id="tutorial">Tutorial</h2>

<p>There are 3 parts to this project:</p>

<ul>
  <li>A way to display your business card.</li>
  <li>A way to host the previously created business card on the internet.</li>
  <li>A way to share the business card in a <em>smooth</em>, catchy way.</li>
</ul>

<p>And this is how we will hit every check on our list.</p>

<ul>
  <li>We will use <a href="https://enbizcard.vishnuraghav.com/">enbizcard</a> to create our business card.</li>
  <li>The hosting service is up to the reader’s choice, I use <a href="https://www.netlify.com/">Netlify</a>.</li>
  <li>A basic way to share this is to use a QR code, but we can do better.</li>
</ul>

<h3 id="step-1-fill-out-your-details-on-enbizcard">Step 1: Fill out your details on enbizcard</h3>

<p>The first step is to go on the <a href="https://enbizcard.vishnuraghav.com/">enbizcard editor</a> and fill out your details. You can even add things like <a href="https://contact.alessandroferrari.live#Resume">your resume</a>.</p>

<p>You should also <strong>add your business card to a public <a href="https://Github.com">Github</a> repository</strong>.</p>

<h3 id="step-2-create-an-account-on-netlify-and-publish-your-business-card-to-the-internet">Step 2: Create an account on Netlify and publish your business card to the internet</h3>

<p>I have an <a href="/host-a-blog-for-free/#2-push-this-site-to-github">in depth guide on how to publish a website to Netlify</a>.</p>

<p>Once your business card is published, you might choose to <a href="https://docs.netlify.com/domains-https/custom-domains/">change your domain</a> as the default randomized domain isn’t well suited for a sleek introduction.</p>

<h3 id="step-3-share-the-qr-code-with-anyone">Step 3: Share the QR code with anyone</h3>

<p>Enbizcard should have generated a custom QR code that points to your contact card. All you need to do now is tell people to scan the QR code, and they will see your business card on their phones.</p>

<p>This isn’t as sleek as tapping a metal card however, so I added an optional fourth step to make the exchange of contact information <em>smoother</em>.</p>

<h4 id="optional-step-4-get-creative">(Optional) Step 4: Get creative</h4>

<p>There are multiple ways to catch the attention of the person that you’re trying to network with, using a <strong>metal card</strong> is just one of them.</p>

<p>You could:</p>

<ul>
  <li>🖨️ 3D Print a QR code using a service like <a href="https://printer.tools/qrcode2stl/">qrcode2stl</a>.</li>
  <li>CNC a metal card with a qr code on top, or order one from <a href="https://www.rockdesign.com/business-card-templates/simple-black-metal-business-cards-sophia-do">Rockdesign</a>.</li>
  <li>Buy an NFC card and write your website link onto it.</li>
</ul>

<p>Bottom line is: now you have a link pointing to your personal smart business card–find an innovative way to share that link, and it will be easier for people to remember you because of your creativity.</p>

<p>Since the business card is free and open source, you could even edit the HTML to expand it, adding new sections and functionality.</p>

<p>You can check out my business card <a href="https://contact.alessandroferrari.live">here</a></p>]]></content><author><name>Alessandro Ferrari</name><email>alessandroferrari@gatech.edu</email></author><category term="webdev" /><category term="blog" /><category term="software" /><summary type="html"><![CDATA[Introduction]]></summary></entry><entry><title type="html">Modeling the Covid-19 Pandemic using R and Jupyter</title><link href="https://alessandroferrari.live/model-covid19-epidemic/" rel="alternate" type="text/html" title="Modeling the Covid-19 Pandemic using R and Jupyter" /><published>2021-07-19T14:54:00+00:00</published><updated>2021-07-19T14:54:00+00:00</updated><id>https://alessandroferrari.live/model-covid19-epidemic</id><content type="html" xml:base="https://alessandroferrari.live/model-covid19-epidemic/"><![CDATA[<h5 id="---notebook-nbviewer">- 📓 Notebook: <a href="https://nbviewer.jupyter.org/github/Ferryistaken/Covid19-R-Modeling/blob/d4d5054f8b7f1e5f9a82b48ea3911eb0874dc62a/R/r-analysis.ipynb">nbviewer</a></h5>
<h5 id="---code-github">- 🔨 Code: <a href="https://github.com/Ferryistaken/Covid19-R-Modeling/blob/master/R/r-analysis.ipynb">github</a></h5>

<h1 id="table-of-contents">Table of contents:</h1>
<ol>
  <li><a href="/model-covid19-epidemic/#data-science-for-epidemic-investigation-and-modeling">Introduction</a></li>
  <li><a href="/model-covid19-epidemic/#tools-used">Tools Used</a>
    <ul>
      <li><a href="/model-covid19-epidemic/#my-setup">My Setup</a></li>
      <li><a href="/model-covid19-epidemic/#the-editor">The editor</a></li>
      <li><a href="/model-covid19-epidemic/#dynamic-graphs-with-dygraph">Dygraph</a></li>
    </ul>
  </li>
  <li><a href="/model-covid19-epidemic/#data">Data</a>
    <ul>
      <li><a href="/model-covid19-epidemic/#data-manipulation">Data Manipulation</a></li>
    </ul>
  </li>
  <li><a href="/model-covid19-epidemic/#analysis">Analysis</a>
    <ul>
      <li><a href="/model-covid19-epidemic/#used-models">Used Models</a>
        <ul>
          <li><a href="/model-covid19-epidemic/#sir-model">SIR Model</a></li>
          <li><a href="/model-covid19-epidemic/#seir-model">SEIR Model</a></li>
        </ul>
      </li>
    </ul>
  </li>
</ol>

<h1 id="data-science-for-epidemic-investigation-and-modeling">Data science for epidemic investigation and modeling</h1>

<p>I recently grew an interest in data science and artificial intelligence, and <em>we are still in a pandemic</em> (although hopefully at the end, fingers crossed for the <a href="https://www.yalemedicine.org/news/5-things-to-know-delta-variant-covid">Delta Variant</a>), so I chose to test out some models to work with data from Covid-19.</p>

<h2 id="tools-used">Tools used</h2>

<p>Here are the tools that I used:</p>

<ul>
  <li><strong>R:</strong> R is a programming language used for statistical computing and graphics. The industry standard in the <a href="https://www.gnu.org/philosophy/floss-and-foss.en.html">FLOSS</a> scene.</li>
  <li><strong>covid19.analytics:</strong> <a href="https://cran.r-project.org/web/packages/covid19.analytics/index.html">This</a> is an R package to pull data from the <a href="https://github.com/CSSEGISandData/COVID-19">John Hopkins Center for System Science and Engineering (CSSE)</a>. This source publishes data with a delay of <strong>just one day</strong>. Although they changed the structure of the data <a href="https://github.com/CSSEGISandData/COVID-19/issues/3464">a few times</a>, it’s very usable and mostly reliable.</li>
  <li><strong>dygraphs:</strong> <a href="https://dygraphs.com/">This</a> is another R package that is worth mentioning if you are doing anything in Jupyter (or even in RStudio). Instead of outputting graphs as images, <strong>it generates html and javascript graphs.</strong></li>
  <li><strong>Jupyterlab:</strong> JupyterLab is a “web-based interactive development environment for Jupyter notebooks, code, and data.”<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup></li>
</ul>

<h2 id="my-setup">My setup</h2>

<p>By using those tools I can come up with a setup like this:</p>

<h3 id="the-editor">The editor</h3>
<p><a href="/assets/posts/model-covid19-epidemic/jupyterlab-setup.webp"><img src="/assets/posts/model-covid19-epidemic/jupyterlab-setup.webp" alt="Jupyterlab Setup" /></a></p>
<blockquote>
  <p>I generally use the light theme for visibility of the graphs, here I used the dark theme because it looks better in screenshots.</p>
</blockquote>

<h3 id="dynamic-graphs-with-dygraph">Dynamic graphs with <code class="language-plaintext highlighter-rouge">dygraph</code>:</h3>
<p><a href="/assets/posts/model-covid19-epidemic/dygraph-showcase.gif"><img src="/assets/posts/model-covid19-epidemic/dygraph-showcase.gif" alt="Dygraph showcase" /></a></p>
<blockquote>
  <p>Using this library, we can produce graphs that react depending on cursor events.</p>
</blockquote>

<h2 id="data">Data</h2>

<p>The data comes from the Center for Systems Science and Engineering (CSSE) at Johns Hopkins University.</p>

<p>Here’s how the data is structured:
<a href="/assets/posts/model-covid19-epidemic/data-structure.webp"><img src="/assets/posts/model-covid19-epidemic/data-structure.webp" alt="Data" /></a></p>

<p>Each <strong>row</strong> is a <strong>country/province</strong>, while each <strong>column</strong> after column 4 is a <strong>day</strong>. This specific screenshot is taken from the confirmed cases csv file.</p>

<p>We can easily pull this data using the <code class="language-plaintext highlighter-rouge">covid19.analysis</code> package described above.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># reads time series data</span><span class="w">
</span><span class="n">all_confirmed_cases</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">covid19.data</span><span class="p">(</span><span class="s2">"ts-confirmed"</span><span class="p">)</span><span class="w">
</span><span class="n">all_confirmed_deaths</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">covid19.data</span><span class="p">(</span><span class="s2">"ts-deaths"</span><span class="p">)</span><span class="w">
</span><span class="n">all_confirmed_recoveries</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">covid19.data</span><span class="p">(</span><span class="s2">"ts-recovered"</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<h3 id="data-manipulation">Data manipulation</h3>

<p>We can easily build a cell to manipulate this data:</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">indexList</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">c</span><span class="p">()</span><span class="w">
</span><span class="n">countryList</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">c</span><span class="p">()</span><span class="w">

</span><span class="c1"># Get all rows</span><span class="w">
</span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">rownames</span><span class="p">(</span><span class="n">all_confirmed_cases</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="c1"># print(c(i, all_confirmed_cases[i, 2]))</span><span class="w">
    </span><span class="n">indexList</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">indexList</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w">
    </span><span class="n">countryList</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">countryList</span><span class="p">,</span><span class="w"> </span><span class="n">all_confirmed_cases</span><span class="p">[</span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="m">2</span><span class="p">])</span><span class="w">
</span><span class="p">}</span><span class="w">

</span><span class="n">country_index_list</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">as.data.frame</span><span class="p">(</span><span class="n">cbind</span><span class="p">(</span><span class="n">indexList</span><span class="p">,</span><span class="w"> </span><span class="n">countryList</span><span class="p">))</span><span class="w">

</span><span class="n">country_index_list</span><span class="p">[</span><span class="m">154</span><span class="p">,</span><span class="w"> </span><span class="p">]</span><span class="w">

</span><span class="c1"># We can see that Italy is index 154, so we are going to  use that</span><span class="w">
</span><span class="n">italy_index</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="m">154</span><span class="w">
</span></code></pre></div></div>

<p>After this, we’ll just extract the relevant rows.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">it_confirmed_cases</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">all_confirmed_cases</span><span class="p">[</span><span class="n">italy_index</span><span class="p">,</span><span class="w"> </span><span class="p">]</span><span class="w">
</span><span class="n">it_confirmed_deaths</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">all_confirmed_deaths</span><span class="p">[</span><span class="n">italy_index</span><span class="p">,</span><span class="w"> </span><span class="p">]</span><span class="w">
</span><span class="n">it_confirmed_recoveries</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">all_confirmed_recoveries</span><span class="p">[</span><span class="n">italy_index</span><span class="p">,</span><span class="w"> </span><span class="p">]</span><span class="w">

</span><span class="n">print</span><span class="p">(</span><span class="s2">"Cases:"</span><span class="p">)</span><span class="w">
</span><span class="n">View</span><span class="p">(</span><span class="n">it_confirmed_cases</span><span class="p">)</span><span class="w">
</span><span class="n">print</span><span class="p">(</span><span class="s2">"Deaths:"</span><span class="p">)</span><span class="w">
</span><span class="n">View</span><span class="p">(</span><span class="n">it_confirmed_deaths</span><span class="p">)</span><span class="w">
</span><span class="n">print</span><span class="p">(</span><span class="s2">"Recoveries:"</span><span class="p">)</span><span class="w">
</span><span class="n">View</span><span class="p">(</span><span class="n">it_confirmed_recoveries</span><span class="p">)</span><span class="w">

</span><span class="n">firstCaseDate</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="s2">"2020-01-31"</span><span class="w">
</span></code></pre></div></div>

<p>We will also need the day of the first case, and we will use that as Day 0 for our models.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Find index of first case</span><span class="w">
</span><span class="n">firstInfection</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="m">0</span><span class="w">

</span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="n">ncol</span><span class="p">(</span><span class="n">it_confirmed_cases</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nf">class</span><span class="p">(</span><span class="n">it_confirmed_cases</span><span class="p">[,</span><span class="w"> </span><span class="n">i</span><span class="p">])</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s1">'integer'</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="n">it_confirmed_cases</span><span class="p">[,</span><span class="w"> </span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="m">1</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="n">print</span><span class="p">(</span><span class="n">paste0</span><span class="p">(</span><span class="s2">"Index of the first infection is: "</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="s2">", Number of infections is: "</span><span class="p">,</span><span class="w"> </span><span class="n">it_confirmed_cases</span><span class="p">[,</span><span class="w"> </span><span class="n">i</span><span class="p">]))</span><span class="w">
        
        </span><span class="n">firstInfection</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">it_confirmed_cases</span><span class="p">[,</span><span class="w"> </span><span class="n">i</span><span class="p">]</span><span class="w">
        
        </span><span class="k">break</span><span class="w">
    </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h2 id="analysis">Analysis</h2>

<p>Let’s proceed to analyse this data.</p>

<p>First let’s define some model-agnostic variables, such as the time frame.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Days that I'm analyzing</span><span class="w">
</span><span class="n">analysis_days</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="m">365</span><span class="w">

</span><span class="c1"># Date list</span><span class="w">
</span><span class="n">dates</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">seq</span><span class="p">(</span><span class="n">as.Date</span><span class="p">(</span><span class="n">firstCaseDate</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"days"</span><span class="p">,</span><span class="w"> </span><span class="n">length.out</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">analysis_days</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<h3 id="used-models">Used Models</h3>

<h4 id="sir-model">SIR Model</h4>

<p>The <a href="https://www.google.com/search?q=Sir+model+&amp;sxsrf=ALeKk01PRPAIyua2TQjDfzCI2NbxVzoFZg%3A1626715569589&amp;ei=sbX1YLGiI7Cw5NoPweermAQ&amp;oq=Sir+model+&amp;gs_lcp=Cgdnd3Mtd2l6EAMyBAgjECcyBAgjECcyBAgjECcyBQgAEJECMgUIABCLAzIFCAAQiwMyBQgAEIsDMgUIABCLAzIFCAAQiwMyBQgAEIsDOgYIABAWEB46BQgAEIYDOgIIADoHCAAQhwIQFEoECEEYAFDjDFi6EGCXE2gAcAJ4AIABbIgBuQKSAQMzLjGYAQCgAQGqAQdnd3Mtd2l6uAEBwAEB&amp;sclient=gws-wiz&amp;ved=0ahUKEwjxvrPd0-_xAhUwGFkFHcHzCkMQ4dUDCA4&amp;uact=5#wptab=s:H4sIAAAAAAAAAONgVuLSz9U3qDAoTq8wfcRoyi3w8sc9YSmdSWtOXmNU4-IKzsgvd80rySypFJLgYoOy-KR4uJC08exiknRNKU1OLMnMz0vMcc7PS04tKHHLL8otzUlcxKqTnJ9bkFhUkpuaV5KYo5Cbn5KaU6yQmaeQWpCZkpqbmZ-Tn16pkAZRDgClBW2QkQAAAA">SIR</a> is one of the simplest <a href="https://en.wikipedia.org/wiki/Compartmental_models_in_epidemiology">compartmental models</a> used in epidemiology. You can read more about it <a href="https://en.wikipedia.org/wiki/Compartmental_models_in_epidemiology#The_SIR_model">here</a>, but simply put, the SIR model divides the population in 3 categories:</p>

<ul>
  <li><strong>S</strong>usceptible</li>
  <li><strong>I</strong>nfected</li>
  <li><strong>R</strong>ecovered (or dead)</li>
  <li><strong>N</strong> = the whole population, \(S + I + R\)</li>
</ul>

<p><a href="https://covid19.uclaml.org/figures/sir_illu.webp"><img src="https://covid19.uclaml.org/figures/sir_illu.webp" alt="SIR Model Graph" /></a></p>

<h5 id="the-math-behind-the-model">The Math Behind the Model</h5>

<p><br /></p>

\[\begin{eqnarray}
	\frac{dS}{dt} &amp; = &amp; - \frac{\beta S I}{N} \\
	\frac{dI}{dt} &amp; = &amp; \frac{\beta S I}{N} - \gamma I \\
	\frac{dR}{dt} &amp; = &amp; \gamma I \\
\end{eqnarray}\]

<p><br /></p>

<p>It can be described by these 3 differential equations, which will show the relations between the Susceptible \(S(t)\), Infected \(I(t)\) and Recovered \(R(t)\) as functions of time.</p>

<p>There are also two parameters, \(\beta\) and \(\gamma\), where beta is the <strong>effective transmission rate</strong>, and gamma is the <strong>effective recovery rate</strong>. We can use these two parameters to obtain \(R_0\), which some of you may have heard if you followed the news.</p>

\[R_0 = \frac{\beta}{\gamma}\]

<h5 id="the-code-for-the-model">The Code for the Model</h5>

<p>Now that we know the math behind the model, we can code it in R.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">susceptible</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="m">60e+06</span><span class="w"> </span><span class="c1"># Source: https://www.statista.com/statistics/786485/population-by-gender-in-italy/#:~:text=Population%20in%20Italy%20in%202020%2C%20by%20gender&amp;text=As%20of%20January%202020%2C%2060.2,roughly%2016%20million%20people%20lived.</span><span class="w">
</span><span class="n">infected</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">firstInfection</span><span class="w">
</span><span class="n">recovered</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="m">0</span><span class="w">

</span><span class="n">initial_state_values</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">S</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">susceptible</span><span class="p">,</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">infected</span><span class="p">,</span><span class="w"> </span><span class="n">R</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">recovered</span><span class="p">)</span><span class="w">

</span><span class="c1"># Parameters</span><span class="w">
</span><span class="c1"># The beta for covid is estimated to be ranging from 1.5 to 6.68. With median of 2.79. Source: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7751056/#:~:text=R0%20of%20COVID%2D19,-R0%20of&amp;text=compared%2012%20studies%20published%20from,an%20interquartile%20range%20of%201.16.</span><span class="w">
</span><span class="c1"># We can simulate this scenario by having our beta as 0.27 and our gamma as 0.1 </span><span class="w">
</span><span class="n">parameters</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">gamma</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0.1</span><span class="p">,</span><span class="w"> </span><span class="n">beta</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0.27</span><span class="p">)</span><span class="w">

</span><span class="c1"># Time points</span><span class="w">
</span><span class="n">time</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">seq</span><span class="p">(</span><span class="n">from</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">,</span><span class="n">to</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">analysis_days</span><span class="p">,</span><span class="w"> </span><span class="n">by</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">)</span><span class="w">

</span><span class="c1"># SIR model function </span><span class="w">
</span><span class="n">sir_model</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">time</span><span class="p">,</span><span class="n">state</span><span class="p">,</span><span class="n">parameters</span><span class="p">){</span><span class="w">
  </span><span class="n">with</span><span class="p">(</span><span class="n">as.list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">state</span><span class="p">,</span><span class="n">parameters</span><span class="p">)),{</span><span class="w">
    </span><span class="n">N</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">S</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">R</span><span class="w">
    </span><span class="n">lambda</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">beta</span><span class="o">*</span><span class="p">(</span><span class="n">I</span><span class="o">/</span><span class="n">N</span><span class="p">)</span><span class="w"> 
    </span><span class="n">dS</span><span class="w"> </span><span class="o">=-</span><span class="w"> </span><span class="n">lambda</span><span class="o">*</span><span class="n">S</span><span class="w">
    </span><span class="n">dI</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lambda</span><span class="o">*</span><span class="n">S</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">gamma</span><span class="o">*</span><span class="n">I</span><span class="w">
    </span><span class="n">dR</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">gamma</span><span class="o">*</span><span class="n">I</span><span class="w">
    
    </span><span class="nf">return</span><span class="p">(</span><span class="nf">list</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">dS</span><span class="p">,</span><span class="n">dI</span><span class="p">,</span><span class="n">dR</span><span class="p">)))</span><span class="w">
  </span><span class="p">}</span><span class="w">
  </span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">

</span><span class="c1">#Solving the differential equations</span><span class="w">
</span><span class="n">output</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">as.data.frame</span><span class="p">(</span><span class="n">ode</span><span class="p">(</span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">initial_state_values</span><span class="p">,</span><span class="w"> </span><span class="n">func</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">sir_model</span><span class="p">,</span><span class="w"> </span><span class="n">parms</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">parameters</span><span class="p">,</span><span class="w"> </span><span class="n">times</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">time</span><span class="p">))</span><span class="w">

</span><span class="n">out_long</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">melt</span><span class="p">(</span><span class="n">output</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"time"</span><span class="p">)</span><span class="w">

</span><span class="n">colnames</span><span class="p">(</span><span class="n">out_long</span><span class="p">)</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s2">"Time"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Variable"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Value"</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<h5 id="visualization">Visualization</h5>

<p>And let’s graph the model’s output.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Susceptible</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">out_long</span><span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="n">analysis_days</span><span class="p">,</span><span class="w"> </span><span class="m">3</span><span class="p">]</span><span class="w">
</span><span class="n">Infected</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">out_long</span><span class="p">[(</span><span class="n">analysis_days</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="m">1</span><span class="p">)</span><span class="o">:</span><span class="p">(</span><span class="n">analysis_days</span><span class="o">*</span><span class="m">2</span><span class="p">),</span><span class="w"> </span><span class="m">3</span><span class="p">]</span><span class="w">
</span><span class="n">Recovered</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">out_long</span><span class="p">[(</span><span class="n">analysis_days</span><span class="o">*</span><span class="m">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="m">1</span><span class="p">)</span><span class="o">:</span><span class="p">(</span><span class="n">analysis_days</span><span class="o">*</span><span class="m">3</span><span class="p">),</span><span class="w"> </span><span class="m">3</span><span class="p">]</span><span class="w">

</span><span class="n">plot_data</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">as.data.frame</span><span class="p">(</span><span class="n">cbind</span><span class="p">(</span><span class="n">Susceptible</span><span class="o">/</span><span class="m">1000000</span><span class="p">,</span><span class="w"> </span><span class="n">Infected</span><span class="o">/</span><span class="m">1000000</span><span class="p">,</span><span class="w"> </span><span class="n">Recovered</span><span class="o">/</span><span class="m">1000000</span><span class="p">))</span><span class="w">
</span><span class="n">colnames</span><span class="p">(</span><span class="n">plot_data</span><span class="p">)</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s2">"Susceptbile"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Infected"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Recovered"</span><span class="p">)</span><span class="w">
</span><span class="n">rownames</span><span class="p">(</span><span class="n">plot_data</span><span class="p">)</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">dates</span><span class="w">

</span><span class="n">plot_data</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">as.xts</span><span class="p">(</span><span class="n">plot_data</span><span class="p">)</span><span class="w">

</span><span class="c1"># head(plot_data)</span><span class="w">

</span><span class="n">dygraph</span><span class="p">(</span><span class="n">plot_data</span><span class="p">)</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
    </span><span class="n">dyAxis</span><span class="p">(</span><span class="s2">"y"</span><span class="p">,</span><span class="w"> </span><span class="n">label</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"People (Millions)"</span><span class="p">)</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
    </span><span class="n">dyAxis</span><span class="p">(</span><span class="s2">"x"</span><span class="p">,</span><span class="w"> </span><span class="n">label</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Date"</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<h4 id="seir-model">SEIR Model</h4>

<p>The <a href="">SEIR</a> model is an expansion on the SIR model. The E stands for <strong>Exposed.</strong> An exposed person is a person that was exposed to the virus, but isn’t <strong>Infectious</strong> yet.</p>

<ul>
  <li><strong>E</strong>xposed: someone who was infected but can’t spread the virus <em>yet</em>.</li>
  <li><strong>N</strong> = total population. This time \(N = S + E + I + R\).</li>
</ul>

<p><a href="https://covid19.uclaml.org/figures/seir_illu.webp"><img src="https://covid19.uclaml.org/figures/seir_illu.webp" alt="SIR Model Graph" /></a></p>

<h5 id="the-math-behind-the-model-1">The Math Behind the Model</h5>

\[\begin{eqnarray}
	\frac{dS}{dt} &amp; = &amp; - \frac{\beta S I}{N} \\
	\frac{dE}{dt} &amp; = &amp; \frac{\beta S i }{N} - \delta E \\
	\frac{dI}{dt} &amp; = &amp; \delta E - \gamma I \\
	\frac{dR}{dt} &amp; = &amp; \gamma I \\
\end{eqnarray}\]

<hr />

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1">
      <p>From their website: <a href="https://jupyter.org/">jupyter.org</a> <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Alessandro Ferrari</name><email>alessandroferrari@gatech.edu</email></author><category term="data" /><category term="coding" /><category term="ai" /><summary type="html"><![CDATA[- 📓 Notebook: nbviewer - 🔨 Code: github]]></summary></entry><entry><title type="html">Using Neural Networks to Predict Stock Prices</title><link href="https://alessandroferrari.live/machine-learning-stock-market/" rel="alternate" type="text/html" title="Using Neural Networks to Predict Stock Prices" /><published>2021-07-15T11:53:13+00:00</published><updated>2021-07-15T11:53:13+00:00</updated><id>https://alessandroferrari.live/machine-learning-stock-market</id><content type="html" xml:base="https://alessandroferrari.live/machine-learning-stock-market/"><![CDATA[<h5 id="---code-my-mirror-github">- 🔨 Code (my mirror): <a href="https://github.com/Ferryistaken/Capstone-mirror">github</a></h5>
<h5 id="---docker-dockerhub">- 🐳 Docker: <a href="https://hub.docker.com/r/u3ebmgske4udqutxkw8rkn/capstone-project">dockerhub</a></h5>

<h1 id="using-machine-learning-to-predict-stock-market-prices">Using machine learning to predict stock market prices</h1>

<p>I recently took part in the Columbia <a href="https://precollege.sps.columbia.edu/highschool/online/courses/3-week/big-data-machine-learning-and-their-real-world-applications">summer course</a>: “Big Data, Machine Learning, and their real world applications”, in which I learned about various machine learning models and how to apply them to analyze data and solve real life problems.</p>

<p>As our final project, me and other 3 people from my course chose to create various machine learning models in order to try and predict the direction and price of stocks on a day-to-day basis. Here’s how it went:</p>

<p><em><strong>Side note:</strong> if you’d just like to test the model without the description and explanation, go here: <a href="/machine-learning-stock-market/#how-to-use-the-model">instructions</a></em></p>

<blockquote>
  <p>First rule of Quantitative Finance:
“Everybody is a genius in a bull market.”</p>
</blockquote>

<h2 id="the-project">The project</h2>

<h3 id="description-aka-copying-the-github-readme">Description (AKA Copying the github README):</h3>

<div align="center">
	<img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/RB3572/Capstone/lint-project" />
	<img alt="Lines of code" src="https://img.shields.io/tokei/lines/github/RB3572/Capstone" />
	<img alt="GitHub" src="https://img.shields.io/github/license/RB3572/Capstone" />
	<img alt="GitHub repo file count" src="https://img.shields.io/github/directory-file-count/RB3572/Capstone" />
	<img alt="GitHub code size in bytes" src="https://img.shields.io/github/languages/code-size/RB3572/Capstone" />
	<img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/RB3572/Capstone" />
	<img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/RB3572/Capstone" />
	<img alt="GitHub contributors" src="https://img.shields.io/github/contributors/RB3572/Capstone" />
	<img alt="Docker Automated build" src="https://img.shields.io/docker/automated/u3ebmgske4udqutxkw8rkn/capstone-project" />
	<img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/u3ebmgske4udqutxkw8rkn/capstone-project" />
	<img alt="Docker Image Size (latest by date)" src="https://img.shields.io/docker/image-size/u3ebmgske4udqutxkw8rkn/capstone-project" />
</div>

<h4 id="machine-learning-stock-predictions">Machine Learning Stock Predictions</h4>
<p>Rakshit Kaushik, Alessandro Ferrari, Sergio Papa Estefano, Rishi Bhargava</p>

<h5 id="data">Data</h5>
<p>Past stock data will be obtained using the quantmod package. Quantmod stands for quantitative financial modeling framework, and it is used to “specify, build, trade, and analyse quantitative financial trading strategies.”<a href="https://cran.r-project.org/web/packages/quantmod/quantmod.pdf">(cran.r-project.org)</a> Opening, high, low, closing, and the adjusted closing prices of a stock can be obtained using the <code class="language-plaintext highlighter-rouge">getSymbols()</code> function. It provides data for every day from January 3, 2007 to the current date.</p>

<p><a href="https://i.ibb.co/DfHkKGf/ef221867-8547-4e7b-8a9c-8455011de2bb.png"><img src="https://i.ibb.co/DfHkKGf/ef221867-8547-4e7b-8a9c-8455011de2bb.png" alt="AMZN Price Graph" /></a></p>

<h5 id="importance-of-data">Importance of data:</h5>
<ul>
  <li>Stock Market Data(opening prices, closing prices, high/low prices) =&gt; technology: train an AI model using historical data to predict stock prices =&gt; if successful, we can deploy this application as a private option for our group to use when investing =&gt; less helpful (comparing with the next example)</li>
  <li>Stock Market Data(opening prices, closing prices, high/low prices) =&gt; technology: train an AI model using historical data to predict stock prices =&gt; if successful, we can deploy this application as an open source package for individuals to use when investing =&gt; more helpful (community impact)
    <h4 id="benchmark">Benchmark</h4>
    <p>Existing projects include:</p>
  </li>
  <li><a href="https://github.com/yiqiao-yin/Introduction-to-Machine-Learning-Big-Data-and-Application/blob/main/scripts/R/2021Summer/day_3.R">MCMC Simulation/MCTS</a>
    <ul>
      <li>MCMC randomly calculates paths that stock price could follow</li>
      <li>MCTS uses past data to tune the parameters used in the MCMC simulation
        <ul>
          <li>parameters: mean, standard deviation</li>
        </ul>
      </li>
      <li>Simulated data will accurately describe historical data =&gt; can be used to make predictions</li>
    </ul>
  </li>
  <li><a href="https://github.com/dineshdaultani/StockPredictions">Sentiment Analysis of Newspapers</a>
    <ul>
      <li>Uses past stock data and newspaper articles</li>
      <li>Sentiment of articles analyzed using Natural Language Toolkit package (NLTK)</li>
      <li>Stock prices and sentiment used as explanatory variables for neural network, stock prediction is the response variable</li>
    </ul>
  </li>
  <li><a href="https://github.com/yiqiao-yin/Introduction-to-Machine-Learning-Big-Data-and-Application/blob/main/scripts/R/2021Summer/day_4.R">Brownian Motion</a>
    <ul>
      <li>Uses the knowledge that plots of simulated particle movement match plots of stock returns (gif credit: <a href="https://github.com/yiqiao-yin/Introduction-to-Machine-Learning-Big-Data-and-Application/blob/main/docs/big-data-machine-learning/notes/Day3.md">yiqiao-yin</a>)</li>
      <li>Parameters for brownian motion can be tuned using past data to predict future stock trends</li>
    </ul>
  </li>
</ul>

<p><a href="https://raw.githubusercontent.com/yiqiao-yin/Introduction-to-Machine-Learning-Big-Data-and-Application/main/pics/brownian-motion.gif"><img src="https://raw.githubusercontent.com/yiqiao-yin/Introduction-to-Machine-Learning-Big-Data-and-Application/main/pics/brownian-motion.gif" alt="Brownian Motion" /></a></p>

<p><a href="https://raw.githubusercontent.com/yiqiao-yin/Introduction-to-Machine-Learning-Big-Data-and-Application/main/pics/cross-section-stock-returns.gif"><img src="https://raw.githubusercontent.com/yiqiao-yin/Introduction-to-Machine-Learning-Big-Data-and-Application/main/pics/cross-section-stock-returns.gif" alt="Stock Market Returns" /></a></p>

<h3 id="proposed-modelalgorithm">Proposed Model/Algorithm:</h3>
<p>1) <strong>Linear Regression</strong>: y=⍺+βx+ε | x = time, y = stock price, ⍺ = y intercept, ε = error. Linear regression is used to find a linear relationship between two variables, or in our case, time and stock price. While linear regression can reveal a trend in stock data, it’s not optimal for predicting stocks, as any sudden change in price can cause a user to lose money.</p>

<p><a href="https://raw.githubusercontent.com/yiqiao-yin/Introduction-to-Machine-Learning-Big-Data-and-Application/main/pics/cross-section-stock-returns.gif"><img src="https://i.ibb.co/XjS5Cqp/91cf0ec1-0a0e-4c28-9dff-ad554150d080.png" alt="Linear Regression" /></a></p>

<p>2) <strong>Recurrent Neural Network using stock returns</strong>: RNNs are designed for sequence prediction problems, making them ideal for predicting stock data. The neural network will use stock returns as both the explanatory and response variables. Another option for data would be to use the closing price. A recurrent neural network could learn from past stock prices and attempt to predict the future. But stock price trends vary from year to year, so training an AI to predict next year’s stock closing prices using last year’s closing price data is un-ideal. Stock returns don’t have as much variation and are better suited for making predictions with an RNN.</p>

<p><a href="https://i.ibb.co/fVWkHCZ/aapl-returns.png"><img src="https://i.ibb.co/fVWkHCZ/aapl-returns.png" alt="Price Return AAPL" /></a></p>

<p>3) <strong>Recurrent Neural Network using golden crosses</strong>: A golden cross occurs when the plotted line of a stock’s long term average crosses the line of its short term average. If the short term average starts below the long term average and crosses above it, the pattern is called a golden cross. Otherwise, it’s called a death cross. A golden cross is a signifier of a bull market. Our model attempts to predict the stock price outcome after a golden cross. Instead of stock returns, our explanatory variable is closing price data as well as the difference between short and long term averages. The response variable is closing prices after the golden cross.  When the two lines cross, the difference of their values is 0 which was represented in our data.</p>

<p><a href="https://i.ibb.co/rGDzzCW/Screen-Shot-2021-07-05-at-2-06-25-PM.png"><img src="https://i.ibb.co/rGDzzCW/Screen-Shot-2021-07-05-at-2-06-25-PM.png" alt="Golden Cross" /></a></p>

<p>4) <strong>Recurrent Neural Network using closing prices</strong>: Mentioned above is how stock price data isn’t great for making a accurate predictions with an RNN. To test this theory, we decided to try using closing prices for both explanatory and response variables in our RNN.</p>

<p><a href="https://i.ibb.co/qY0B1kP/aapl-price.png"><img src="https://i.ibb.co/qY0B1kP/aapl-price.png" alt="Real Price Prediction" /></a></p>

<h3 id="how-to-use-the-model">How to use the model</h3>

<p>To run our webapp, simply install a container engine for your operating system (such as <a href="https://www.docker.com/">Docker</a> or <a href="https://podman.io/">Podman</a>), and pull our container by running:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker pull u3ebmgske4udqutxkw8rkn/capstone-project
</code></pre></div></div>

<p>If this doesn’t work, just clone this repository, navigate into the ‘Docker’ directory, and run the <code class="language-plaintext highlighter-rouge">create-docker.sh</code> script (only tested on Unix-like operating systems). This will create a docker image called <code class="language-plaintext highlighter-rouge">capstone-project</code>, which can then be used by running:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run <span class="nt">--rm</span> <span class="nt">-p</span> 3838:3838 localhost/capstone-project:latest
</code></pre></div></div>

<p>This will start the shiny server on <code class="language-plaintext highlighter-rouge">http://127.0.0.1:3838</code></p>]]></content><author><name>Alessandro Ferrari</name><email>alessandroferrari@gatech.edu</email></author><category term="ai" /><category term="finance" /><category term="coding" /><category term="stocks" /><summary type="html"><![CDATA[My ideals]]></summary></entry></feed>