Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

1Learning Outcomes

No video. We recommend pulling up the memory section of the RISC-V Green Card.

2Local variables on the stack

So far, we have been able to translate very tiny amounts of C code to fit into registers. If we have too many (data) words to fit into registers, we must use memory.

3Register Conventions and Register Names

As mentioned earlier, a register can also be referred to by its register name. Register names define convention—that is, specifying how assemblers should use specific registers for specific common functions. These restrictions help build “agreement” upon how to translate separate components of a program so that the assembly instructions slot together.

The RISC-V green card lists all register names; we begin introducing and using them in this example.

4Problem Description

Translate the below C program by only using the temporary registers t0, t1, t2, and the stack pointer sp . You may access memory as needed.

1
2
3
4
5
6
int a = 5;
char b[] = "string"; // Array will get stored on stack
int c[10];
uint8_t d = b[3];
c[4] = a+d;
c[a] = 20;

5Setup

We will use temporary registers to store addresses, arithmetic data, and so on.We will store local variable on the stack by assigning each variable to some offset from our stack pointer sp.

The exact addresses of these local variables don’t matter, so long as we’re consistent. In this example, we’ll use the following assignment:

a: 0(sp)
b: 4(sp)
c: 12(sp)
d: 52(sp)

This notation is not conventional, but we use it to denote that all memory will be relative to the stack pointer sp. int a is at address R[sp], C string b is at address R[sp] + 4, 10-int array c is at R[sp] + 12, and uint8_t d is at address R[sp] + 52.

6Solution

Here is the full assembly translation of the original C code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
li t0 5            # R[t0] = 5
sw t0 0(sp)        # store int a on stack
li t0 0x69727473   # load "stri"
sw t0 4(sp)        # store first part of string
li t1 0x0000676E   # load rest of string
sw t1 8(sp)        # store rest of string
lb t0 7(sp)        # 4(sp) from b, 3(sp) from [3] 
sb t0 52(sp)       # store into d
lw t0 0(sp)        # load a 
lbu t1 52(sp)      # load d
add t2 t0 t1       # R[t2] = a+d
sw t2 28(sp)       # 12(sp) from c, 16(sp) from [4] 
li t0 20           # R[t0] = 20
lw t1 0(sp)        # R[t1] = a
slli t1 t1 2       # 5*sizeof(int) = 5*4 = 5<<2
addi t1 t1 12      # t1 from [a], 12 from c  
add t1 t1 sp       # compute &c[a]
sw t0 0(t1)        # c[a] = 20

We discuss line-by-line translation below. For each section, try to use the image to interpret why we specified the corresponding assembly instructions. Then, check your reasoning.

6.1Line 2: int a = 5;

1
2
li t0 5            # R[t0] = 5
sw t0 0(sp)        # store int a on stack
"TODO"

Figure 1:Line 1 of Stack Pointer Example.

6.2Line 3: Initialize string char b[] = "string";

We would like to store the bytes of "string" onto our stack, starting at location 4(sp). There is a straightforward but tedious way to do so, and a concise way that requires a bit of cleverness.

One approach (straightforward but tedious):

1
2
3
4
5
6
7
8
9
10
11
12
13
li t0 0x73
sb t0 4(sp)
li t0 0x74
sb t0 5(sp)
li t0 0x72
sb t0 6(sp)
li t0 0x69
sb t0 7(sp)
li t0 0x6E
sb t0 8(sp)
li t0 0x67
sb t0 9(sp)
sb x0 10(sp)
"TODO"

Figure 2:Line 2 of Stack Pointer Example.

Alternate approach with much fewer instructions:

1
2
3
4
li t0 0x69727473   # load "stri"
sw t0 4(sp)        # store first part of string
li t1 0x0000676E   # load rest of string
sw t1 8(sp)        # store rest of string
"TODO"

Figure 3:Line 2 of Stack Pointer Example, concise version.

6.3Line 4: Uninitialized array int c[10];

No instructions needed.

"TODO"

Figure 4:Line 3 of Stack Pointer Example.

6.4Line 4: Read array element uint8_t d = b[3];

1
2
lb t0 7(sp)        # 4(sp) from b, 3(sp) from [3] 
sb t0 52(sp)       # store into d
"TODO"

Figure 5:Line 4 of Stack Pointer Example.

6.5Line 5: Store array element c[4] = a + d;

1
2
3
4
lw t0 0(sp)        # load a 
lbu t1 52(sp)      # load d
add t2 t0 t1       # R[t2] = a+d
sw t2 28(sp)       # 12(sp) from c, 16(sp) from [4]
"TODO"

Figure 6:Line 5 of Stack Pointer Example.

6.6Line 6: Variable array indexing c[a] = 20;

This line is the most challenging of the bunch, so we recommend working it out via Venus once you learn how to use Venus in lab.

1
2
3
4
5
6
li t0 20           # R[t0] = 20
lw t1 0(sp)        # R[t1] = a
slli t1 t1 2       # 5*sizeof(int) = 5*4 = 5<<2
addi t1 t1 12      # t1 from [a], 12 from c  
add t1 t1 sp       # compute &c[a]
sw t0 0(t1)        # c[a] = 20

7Quick Checks