Home

About

Blog

Projects

Assembly: A bridge to understanding CS topics

People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird." ~ Donald Knuth

I'll admit, all this low-level stuff was pretty daunting as a self-taught web developer trying to dig into the CS fundamentals. You've got bits, bytes, physical memory, virtual memory, I/O buffers, registers, ALUs, and more. Learning about hardware, more specifically Computer Architecture, was a key piece to understanding some of that better, but learning to write some basic programs in Assembly (ASM), was the real ticket to making sense of most of this.

Having wrapped up my first foray into [Computer Architecture](/blog/q2-study-updates/) I've been working on learning an Assembly language for about the past month now. In a [post on Mastodon](https://tech.lgbt/@bugwhisperer/112810346905099112) at the start of my studying, I noted that it's been equally the most enlightening and frustrating learning I've undertaking so far on this journey. Assembly has forced me to confront weak areas and requires rigor when approaching programming that was totally new to me. So let's dive in a little more as to why, a few weeks after posting that, I have come around to really appreciating it.

Computer Architecture was an incredibly helpful course of study to understand how the hardware worked inside those boxes. The difficulty I had with it was that it was all a bit theoretical, a bit lacking in the hands-on sense of things. I didn't have access to an electronics lab (something I'm working on to get setup with at home starting #homelab) to test out circuits and logic gates. Regardless, there would still have been a gap between the "real" computer hardware and the basic 8-bit setup I'd hoped to build at best.

Enter Assembly Language

Assembly comes in many flavors. This is due to the fact that they are designed to run a specific CPU's instruction set architecture (ISA). The "main" ones (Intel vs AMD) are older, battle-tested, and most likely what you have running on your computer/mobile device. These two are easier to get started with and have LOTs of resources. So why the heck did I choose RISC-V you may ask? It's a relatively newer, less used, ISA. It came down to the fact that it was a vastly smaller, simpler ISA and that the project was fully open-source, meaning anyone can contribute and help develop it further.

This came with the drawback that getting to the point where I could compile and run my programs was much harder, but NOT impossible! I spent about a day working on getting [QEMU](https://www.qemu.org/) and the [riscv-gnu-toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain) installed locally. Connecting those pieces to the `build` and `run` commands inside my hacked-together Makefile was the final touch.

Guided to the promised land

Assembly was the missing link I needed. Like the Greek goddess Iris, it guided me from the high-level programming code I might normally write (like C or Rust) to the computer hardware level, carefully transporting me between these realms. It helped me to better understand how the hardware instructions were being generated to be executed by the CPU from my programs. This in turn allowed me to think from the CPU and compiler's point of view when thinking about problems and best approaches in higher-level languages. For example, understanding how my code will get optimized by the compiler. Or the idea that my `for` loops and `while` loops will both, at times, resolve into some temporary register variable (in the case of a simple counter), do a comparison and jump to the top if comparison is not met. All of that "clever" code boils down into simple register shuffling and memory address store/load calls. It's a good reminder of a line from the Zen of Python (https://en.wikipedia.org/wiki/Zen_of_Python):

Simple is better than complex.

Assembly, quite harshly at times I must say, pointed out weak spots in my understanding of code execution, bitwise shifts, etc. Like a stern headmaster, it forced me to work on these areas until a particular ASM code example made sense, until a bug was finally fixed, or until I figured out how ASM needed things to arranged to implement some features for my little projects. It was a struggle, but one that I would wholeheartedly recommend all programmers go through, even if you never need to write a single line of ASM for work or personal projects after that. It will give you a much better understanding of the computer and how high-level programs run every day.

With Assembly finally tamed, it's time for me to start digging into Operating System workings! Super excited!!

If you have topics that you'd like me to go into deeper, like a walkthrough of a basic RISC-V ASM program or something you want to read about don't hesitate to reach out on Mastodon with suggestions and comments! Hugs!

© 2024-present by Katie Keller.

Content of this website is licensed under CC BY-NC-SA 4.0.

Crafted with 💖. Built with gempost.