Assembly Programming
Let’s Write an Assembly Program
Let’s try out our new reading-the-manual skills to write an assembly program from scratch.
Our program will compute \( (34-13) \times 2 \).
We’ll implement the multiplication with a left shift, so our program will work like the C expression (34 - 13) << 1.
When writing assembly, it can help to start by writing out some pseudocode where each statement is roughly the complexity of an instruction and all the variables are named like registers. Here’s a Python-like reformatting of that expression:
a0 = 34
a1 = a0 - 13
a2 = a1 << 1
I’ve used three different registers just for illustrative purposes; we could definitely have just reused a0.
Let’s translate this program to assembly one line at a time:
- We need to put the constant value 34 into register
a0. Remember the add-immediate instruction? And remember the specialx0register that is always zero? We can combine these to do something likea0 = 0 + 34, which works just as well. The instruction isaddi a0, x0, 34. - Now we need to subtract 13.
Let’s look at the reference card.
There is no subtract-immediate instruction… but we can add a negative number.
Let’s try the instruction
addi a1, a0, -13. - Finally, let’s look for a left-shift instruction in the reference card.
We can find
slli, for shift left logical immediate. The final instruction we need isslli a2, a1, 1.
Here’s our complete program:
addi a0, x0, 34
addi a1, a0, -13
slli a2, a1, 1
Try It Out
We’d like to run this assembly program to test that it works how we want it to.
However, it’s awkward to print stuff out in assembly—we’d need to carefully craft a call to printf.
Let’s try two other options.
C Wrapper
One option is to write C code to do the printing, and then stitch our assembly code in. The key is to use a special feature in some C compilers called inline assembly, which lets you mix some assembly code in with your C code. The syntax for inline assembly is pretty arcane, but here’s a simple incantation that works for our example:
#include <stdio.h>
int main() {
asm(".include \"intro.s\"");
register int x asm("a2");
printf("result = %d\n", x);
return 0;
}
The upshot is that we get to write a C printf call as normal.
The first asm line includes our existing assembly code from the intro.s file.
The funky declaration of x tells the compiler to map that variable to the a2 register, which holds our result.
Compile and run this program to print out the value our assembly code puts into the a2 register.
I don’t really recommend learning a lot about inline assembly unless you’re really curious. Fortunately, there is an easier way.
In-Browser RISC-V Simulator
For CS 3410, we have developed a more convenient way to test RISC-V assembly programs. On [our RISC-V assembly resources page][rsrc-asm], you can find this online RISC-V simulator. You can enter a RISC-V assembly program and use the “Run” or “Step” buttons to execute it and see its effects on the registers.
Try pasting your assembly program into the web interface and running it.
See if we got it right:
i.e., check that the program puts the result \( (34-13) \times 2 \) into register a2.