Intro to Computer Engineering

Studio 10 - Memory Model

========

Click here to access the Canvas page with the repository for this studio.

========

Introduction

Now that we’ve had some experience with working in assembly, we’ll use assembly to perform some more complicated tasks that work with references and get more experience with the C memory model.

Objectives

By the end of this studio, you should:

========

Around the globe

We’ll start out by taking a look at how to use global variables. We will do this while exploring two addressing modes: data direct and data indirect, both of which can be used to read and write main memory (i.e., load a memory value into a register or store a register value into memory).

  1. Set up your repository. We have written a bare bones project, memoryModel. In the assembly.S file are assembly stubs for three functions. Let’s start by looking at increment and decrement.

  2. The goal of increment and decrement is simple: we want to add one or subtract one from a global variable. First, define a global variable in your assembly code. We wish to use a single byte for our counter. This counter should have an initial value of 0.

  3. Complete the increment function. This function should add one to the global counter variable that you created. Notice that there are no input parameters for this function. To access the global variable, you will use the data direct addressing mode (here is it’s description) associated with the lds (load) and sts (store) instructions. Use the name of the global variable for the memory address in the load and store instructions. After loading the value of the global counter variable into a register, increment it and store it back in the global variable. Make sure you are properly using a caller-saved register (or save the register before using it and restore it before the return instruction).

  4. Next complete the decrement function. This function should subtract one from the global counter variable that you created above. Again, there are no input parameters for this function. For decrement, you will use the data indirect addressing mode (here is its description). With indirect addressing, to access the global variable, you will need to get a reference to it, which you can do using the hi8() and lo8() functions, as explained in the prep work. You will then need to copy this reference into the appropriate registers (called indirect address registers in the documentation, we typically just say address registers) so you can access it using ld or st. Make sure you are properly using these registers (i.e. pay attention to whether they are caller-saved or callee-saved). After you decrement the value, store the updated value back to the global variable.

  5. The return value of both these functions should be the value of the global variable after the increment/decrement has taken place. You can check your work by running the tests provided in memoryModel.ino.

========

Arrays

Now that you have some practice using global variables, let’s switch to arrays. There’s just one assembly function to complete here:

Before you start on these functions, it will be helpful to get some practice using pointers in C to understand how they will work in your assembly functions. Complete the C function sumArrayPointers(uint8_t *a, uint8_t length). Notice that this function takes in a pointer (reference). You should use this pointer to access the array values and sum up the array.

Some notes to help you with this:

Note that in practice, we typically would not write sumArray using pointers in C. The use of brackets [] makes array access much more convenient for us and there is nothing wrong with using arrays in that fashion. We are asking you to write your function using pointers because it is much closer to how the assembly code will operate.

Once you have finished sumArrayPointers, complete the assembly functions sumArray. Some notes to help you with these functions:

========

Debugging

In addition to the printRegs() function from the previous assignment, the studio also contains a file called asmMacros.S. This file includes macros. A macro is a set of assembly language instructions that can be added to a file in place of a simple name. This file defines two macros, one named print and another named printAReg. When either word is used assembly.S, many instructions will be inserted in place of the name. As the names imply, they are intended to print out things, which may help you debug your code.

print is for printing single words or groups of words. To print a single word, print WORD. To print multiple words, print [MULTIPLE WORDS], which will print the brackets and the words within. Note that print does not work well with symbols, like =.

printAReg will print the contents of a single register. For example, printAReg 22 will print r22 = 0xXX. Note that it prints the value in hex and only the number is used for the register (22 rather than r22).

These macros and printRegs can be used to study how individual values change as your assembly code executes.

========

Demo

When done, your code should run all test cases without error.

  1. Commit your code and get checked out by a TA.

========

Key Concepts

This is a mental checklist for you to see what the Studio is designed to teach you.

Generated at 2024-07-01 15:58:42 +0000.
Page written by Doug Shook & Roger Chamberlain.