<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: sinhaparth5</title>
    <description>The latest articles on DEV Community by sinhaparth5 (@sinhaparth5).</description>
    <link>https://dev.to/sinhaparth5</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F638541%2Fd2936f94-63db-4f46-8027-3d462e4e76e7.jpeg</url>
      <title>DEV Community: sinhaparth5</title>
      <link>https://dev.to/sinhaparth5</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sinhaparth5"/>
    <language>en</language>
    <item>
      <title>I built a small RISC-V computer inside a Tang Nano 9K FPGA</title>
      <dc:creator>sinhaparth5</dc:creator>
      <pubDate>Fri, 13 Nov 2026 12:51:00 +0000</pubDate>
      <link>https://dev.to/sinhaparth5/i-built-a-small-risc-v-computer-inside-a-tang-nano-9k-fpga-5cbd</link>
      <guid>https://dev.to/sinhaparth5/i-built-a-small-risc-v-computer-inside-a-tang-nano-9k-fpga-5cbd</guid>
      <description>&lt;p&gt;I built a small RISC-V computer inside the Gowin GW1NR-9 FPGA on a Tang Nano 9K, a board that costs around $15 to $20, using only open-source tools: Yosys, nextpnr, Apicula and openFPGALoader. It ended up with a PicoRV32 CPU, 16 KB of RAM, a hand-written UART, a custom hardware accelerator and an HDMI text console. I wrote it up as five parts. Each one adds one block, explains the ideas it needs, and then shows what I built and measured.&lt;/p&gt;

&lt;h3&gt;
  
  
  The five parts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://edu.parthsinha.com/posts/riscv-soc-1-toolchain-and-blink/" rel="noopener noreferrer"&gt;Part 1: an open-source toolchain and a blinking counter&lt;/a&gt;. What synthesis, place and route, bitstreams and constraint files are, then a six-line counter that drives six LEDs. It uses 33 of the chip's 8,640 LUT4s.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://edu.parthsinha.com/posts/riscv-soc-2-uart/" rel="noopener noreferrer"&gt;Part 2: a UART from scratch&lt;/a&gt;. Baud rates, mid-bit sampling and synchronizers, then a transmitter and receiver in about 40 lines of Verilog, tested in simulation first and then echoing typed characters on the board.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://edu.parthsinha.com/posts/riscv-soc-3-picorv32/" rel="noopener noreferrer"&gt;Part 3: a PicoRV32 CPU running C&lt;/a&gt;. RV32IMC, memory-mapped I/O and linker scripts. The firmware is baked into the bitstream, so there's no bootloader. CPU, RAM and UART together take 47% of the LUTs and close timing at 51 MHz against a 27 MHz clock.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://edu.parthsinha.com/posts/riscv-soc-4-accelerator/" rel="noopener noreferrer"&gt;Part 4: a hardware accelerator, 46× faster than C&lt;/a&gt;. A memory-mapped xorshift32 block that runs one step per clock, plus a small shell with peek, poke and bench commands.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://edu.parthsinha.com/posts/riscv-soc-5-hdmi/" rel="noopener noreferrer"&gt;Part 5: an HDMI text console&lt;/a&gt;. Pixel clocks, video timing and TMDS encoding, then a 90×30 text display that mirrors the shell. It scrolls by changing one register instead of copying the screen.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The 46× number
&lt;/h3&gt;

&lt;p&gt;On the board, &lt;code&gt;bench 1000&lt;/code&gt; took 50,015 cycles in C and 1,066 cycles on the accelerator, with identical results. The accelerator itself does one step per clock, so about 66 of those cycles are the cost of talking to it over the bus. That also means a single step at a time would be slower in hardware than in software. The speedup only shows up when each call does enough work.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's not done yet
&lt;/h3&gt;

&lt;p&gt;Parts 1 to 4 run on the board. Part 5 passes its simulation tests and builds a bitstream, but I haven't connected it to a monitor yet, so how it looks on a real screen is still unknown.&lt;/p&gt;

&lt;h3&gt;
  
  
  Things that went wrong
&lt;/h3&gt;

&lt;p&gt;Each part has the problems I hit along the way. A few of them: on Linux, ModemManager kept probing the board's serial port, so the shell received its own output back as typed commands. A testbench passed even though the design was broken, and I only found out by feeding it bad input on purpose. And the first HDMI bitstream failed to pack until I switched from true LVDS buffers to emulated ones.&lt;/p&gt;

&lt;p&gt;The code is on GitHub, with one folder per part: &lt;a href="https://github.com/sinhaparth5/tangnano9k-riscv-soc" rel="noopener noreferrer"&gt;https://github.com/sinhaparth5/tangnano9k-riscv-soc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If LUTs and flip-flops are new to you, start with my notes on what's inside an FPGA: &lt;a href="https://edu.parthsinha.com/posts/understanding-fpga/" rel="noopener noreferrer"&gt;https://edu.parthsinha.com/posts/understanding-fpga/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've put a soft CPU on a small FPGA, what did you add after the UART?&lt;/p&gt;

</description>
      <category>riscv</category>
      <category>fpga</category>
      <category>verilog</category>
      <category>embedded</category>
    </item>
    <item>
      <title>What's inside an FPGA, explained with a Tang Nano 9K</title>
      <dc:creator>sinhaparth5</dc:creator>
      <pubDate>Fri, 13 Nov 2026 12:46:00 +0000</pubDate>
      <link>https://dev.to/sinhaparth5/whats-inside-an-fpga-explained-with-a-tang-nano-9k-14m8</link>
      <guid>https://dev.to/sinhaparth5/whats-inside-an-fpga-explained-with-a-tang-nano-9k-14m8</guid>
      <description>&lt;p&gt;Coming to FPGAs from an Arduino or ESP32, the hardest part is the change in mindset. You aren't writing a program for a CPU to run one line at a time. You're describing a circuit, and the tools build it out of blocks that are already sitting on the chip. I wrote up notes on what those blocks are, partly from EEVblog's "What Is An FPGA?" video, with the Tang Nano 9K as the running example.&lt;/p&gt;

&lt;h3&gt;
  
  
  The blocks
&lt;/h3&gt;

&lt;p&gt;IOBs (input/output blocks) sit behind each physical pin and form a ring around the edge of the chip. They set the pin's direction, drive strength, slew rate and voltage standard, and each one has its own flip-flops, so a signal can be latched right at the pin. Drive strength isn't voltage, though. A 3.3 V pin driving a 5 V part like a WS2812 LED strip still needs a level shifter.&lt;/p&gt;

&lt;p&gt;CLBs (configurable logic blocks) are where the logic happens, and there are no AND or OR gates in them as such. A LUT is a tiny truth table that stores the output for every input combination, so one LUT4 can implement any boolean function of four inputs. Next to the LUTs are D flip-flops for state and a carry chain that lets adders ripple between neighbouring cells without going out to the slower general routing.&lt;/p&gt;

&lt;p&gt;All of that configuration lives in SRAM, which forgets everything when the power goes off. The compiled bitstream is kept in flash and loaded into the SRAM at power-up. The Tang Nano 9K's Gowin GW1NR-9 has the flash built in, so a design is running almost as soon as the board gets power.&lt;/p&gt;

&lt;h3&gt;
  
  
  What a blinker turns into
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight verilog"&gt;&lt;code&gt;&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="nf"&gt;led_blink&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt;  &lt;span class="n"&gt;wire&lt;/span&gt; &lt;span class="n"&gt;clk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="n"&gt;reg&lt;/span&gt;  &lt;span class="n"&gt;led&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;reg&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;always&lt;/span&gt; @&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;posedge&lt;/span&gt; &lt;span class="n"&gt;clk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;begin&lt;/span&gt;
        &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="s1"&gt;'b1;
        led     &amp;lt;= counter[23];
    end
endmodule
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the tools synthesize this, &lt;code&gt;counter&lt;/code&gt; becomes 24 flip-flops, the &lt;code&gt;+ 1'b1&lt;/code&gt; becomes LUTs plus the carry chain, and &lt;code&gt;led&lt;/code&gt; is a register driving a pin, so it can go in that pin's IOB flip-flop. Which pin, and at what voltage, comes from a separate constraints file.&lt;/p&gt;

&lt;p&gt;The post also lists the GW1NR-9's resources (8,640 LUT4s, 6,480 flip-flops, 26 block RAMs and 10 DSP multipliers), links the two Gowin documents I used, and looks at what has changed since that EEVblog video came out in 2013: power, $15 to $20 boards, free and open-source tools such as Yosys and nextpnr, and hard IP in the silicon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://edu.parthsinha.com/posts/understanding-fpga/" rel="noopener noreferrer"&gt;https://edu.parthsinha.com/posts/understanding-fpga/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I later used the same board to build a small RISC-V computer, written up as a five-part series starting here: &lt;a href="https://edu.parthsinha.com/posts/riscv-soc-1-toolchain-and-blink/" rel="noopener noreferrer"&gt;https://edu.parthsinha.com/posts/riscv-soc-1-toolchain-and-blink/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you came to FPGAs from microcontrollers, what took you longest to unlearn?&lt;/p&gt;

</description>
      <category>fpga</category>
      <category>verilog</category>
      <category>hardware</category>
      <category>electronics</category>
    </item>
    <item>
      <title>Why AES does its byte math in GF(2 ), with a step-through multiplier</title>
      <dc:creator>sinhaparth5</dc:creator>
      <pubDate>Fri, 13 Nov 2026 11:50:46 +0000</pubDate>
      <link>https://dev.to/sinhaparth5/why-aes-does-its-byte-math-in-gf28-with-a-step-through-multiplier-1n5g</link>
      <guid>https://dev.to/sinhaparth5/why-aes-does-its-byte-math-in-gf28-with-a-step-through-multiplier-1n5g</guid>
      <description>&lt;p&gt;Most AES tutorials either wave at the math ("shift left and XOR with 0x1B") or jump straight into ring theory without tying it back to bytes. I wrote up notes from Christof Paar's AES lectures that try to sit in between.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why ordinary integer math doesn't work
&lt;/h3&gt;

&lt;p&gt;AES needs two things from byte arithmetic. Every result has to be another byte (0x00 to 0xFF), and every nonzero byte needs a multiplicative inverse, because the S-box is built from inverses. Integers mod 256 give you the first but not the second. No even number has an inverse mod 256, since 2·x is always even and so never equals 1.&lt;/p&gt;

&lt;p&gt;A field with 256 elements has both properties, and GF(2⁸) is that field.&lt;/p&gt;

&lt;h3&gt;
  
  
  What GF(2⁸) does with a byte
&lt;/h3&gt;

&lt;p&gt;Each byte is read as a polynomial whose coefficients are its bits. 0x57 = 01010111 is x⁶ + x⁴ + x² + x + 1.&lt;/p&gt;

&lt;p&gt;Addition works coefficient by coefficient mod 2, which is just XOR: 0xD1 + 0x15 = 0xC4, with no carries.&lt;/p&gt;

&lt;p&gt;Multiplication is polynomial multiplication followed by reduction modulo the AES polynomial x⁸ + x⁴ + x³ + x + 1 (0x11B). This is where xtime comes from. Multiplying by x shifts left one bit, and if a bit falls off the top, x⁸ gets replaced by x⁴ + x³ + x + 1, which means XOR with 0x1B.&lt;/p&gt;

&lt;p&gt;To multiply 0x57 by 0x83, you keep doubling 0x57 and XOR in the copies where 0x83 has a 1 bit:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;i&lt;/th&gt;
&lt;th&gt;bit i of 0x83&lt;/th&gt;
&lt;th&gt;0x57 · xⁱ&lt;/th&gt;
&lt;th&gt;running XOR&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0x57&lt;/td&gt;
&lt;td&gt;0x57&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0xAE&lt;/td&gt;
&lt;td&gt;0xF9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0x15C ⊕ 0x11B = 0x47&lt;/td&gt;
&lt;td&gt;0xF9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0x8E&lt;/td&gt;
&lt;td&gt;0xF9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0x11C ⊕ 0x11B = 0x07&lt;/td&gt;
&lt;td&gt;0xF9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0x0E&lt;/td&gt;
&lt;td&gt;0xF9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0x1C&lt;/td&gt;
&lt;td&gt;0xF9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0x38&lt;/td&gt;
&lt;td&gt;0xC1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So 0x57 · 0x83 = 0xC1. The two rows with ⊕ 0x11B are the reductions: the shift pushed a 1 into bit 8, and XORing with 0x11B clears it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1zdf2twsyo7c189htq8d.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1zdf2twsyo7c189htq8d.gif" alt="Step-through GF(2⁸) multiplier showing 0x57 · 0x83 one bit at a time" width="800" height="884"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The post has this as an interactive widget. You type any two bytes, then play it or step through one bit at a time, and a bit strip shows each shift, each XOR with 0x11B and each update to the result.&lt;/p&gt;

&lt;p&gt;The rest of the post builds groups and fields from scratch. It has GF(7) and GF(2³) tables you can check by hand, the 0x57 · 0x83 long division, extended Euclid for inverses (0x53⁻¹ = 0xCA), and a short Python gf_mul. Part 2 uses all of this to build AES-128 layer by layer and checks it against the FIPS 197 test vector.&lt;/p&gt;

&lt;p&gt;Part 1, Galois fields: &lt;a href="https://edu.parthsinha.com/posts/galois-fields-for-aes/" rel="noopener noreferrer"&gt;https://edu.parthsinha.com/posts/galois-fields-for-aes/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Part 2, AES layer by layer: &lt;a href="https://edu.parthsinha.com/posts/aes-structure-and-layers/" rel="noopener noreferrer"&gt;https://edu.parthsinha.com/posts/aes-structure-and-layers/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you learned AES, which took longer to click: MixColumns or the S-box?&lt;/p&gt;

</description>
      <category>cryptography</category>
      <category>aes</category>
      <category>math</category>
      <category>security</category>
    </item>
  </channel>
</rss>
