Intro to Computer Engineering

Assignment 9 - Assembly Puzzles Part 2

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

========

Overview

In this assignment you’re tasked with creating more functions using assembly language. There are two big differences between this assignment and the last:

As before, you will likely want to keep the AVR Assembly Reference handy as well as the rules for register usage. Make sure you are using registers appropriately - we will be checking for this when you demo. Some of the functions you have to complete are both called and call another function — they need to follow both the caller-saved and the callee-saved conventions!!! Use the stack!

========

Goals

The goal of this assignment is to implement basic functions in assembly language. The functions chosen are examples that may actually be implemented in assembly rather than a higher level language.

The main concepts are:

To keep things as simple as possible all values are unsigned. In C the 8-bit values are uint8_t (which is the same as a byte and 16-bit values are uint16_t.

========

The Assignment

In your repository you will find an assignment09 Arduino project. This project contains the prototypes for the functions we are asking you to write as well as code to test your work.

The Assembly language functions may be easier to write if you have already tested the logic using C. There are four C-functions you’ll need to complete in assignment09.ino:

There are five functions to complete entirely in assembly language:

========

Getting Started

Assembly language can be challenging. The provided files include several test cases to help you with your work. Here’s the approach we suggest:

  1. assignment09.ino includes a lot of code to help you with testing. The setup() includes calls to all test cases. There are two styles of tests:
    1. Standalone test cases, like:

       uint8_t dividend8 = 175;
       uint8_t divisor8 = 26;
       uint8_t quotient8ASM = slowDivisionUint8(dividend8,divisor8);
       uint8_t quotient8Alg = slowDivisionAlgorithm8(dividend8,divisor8);
       pprintf("slowDivisionAlgorithm8(%u,%u) is %u (algorithm) and %u (assembly); Should be %u\n", dividend8, divisor8, quotient8Alg, quotient8ASM, dividend8/divisor8);
      

      These tests will run just a single test case, which is probably what you need to do when debugging.

    2. More rigorous tests are included in “test functions”, like on Assignment 10. They can be run via function call, like:

       // Full Test:
       testSlowDivisionUint8();
      

      You will want to comment/un-comment test cases so you can focus on each part independently.

  2. It’s probably best start with the C-code version of 8-bit division. I.e., complete slowDivisionAlgorithm8() in assignment09.ino. Use the test functions to test it (they will indicate the values printed by both the algorithm, which should be correct when you’re done with the C-code, and the assembly language, which will still be incorrect)

  3. Write and test the assembly language version of 8-bit division: slowDivisionUint8 in assignment09.S.

  4. Try the assembly language version of comparisons — do greaterThanOrEqualUInt16 in assignment09.S. Again, test your work.

  5. Do the C version of 16-bit division. CompleteslowDivisionAlgorithm16() in assignment09.ino.

  6. Now try the assembly language version of 16-bit division: slowDivisionUint16 in assignment09.S. This may be the most difficult part of the assignment. (Hint: 16-bit subtraction can be done with just two instructions)

  7. Complete the two modulus functions: slowModulusAlgorithm and slowModulusUint8. Don’t forget to use your division functions in your solution - we will be checking for this.

  8. Complete the two functions for summing odd numbers within a given range. Keep in mind that the range is inclusive, so if the min or max is an odd number it should be included in the sum. You may assume that the first argument will always be less than or equal to the second argument (you do not have to check for this in your code).

========

Hints

  1. If you do not get the message Done with tests!!! at the end of your testing functions, you did not successfully finish all tests. You are probably caught in an infinite loop somewhere…

  2. If you call another function from within the function you are writing, keep in mind that the two functions may use the same registers. Be careful not to overwrite data you may need later. Convention is to save all caller-saved registers before calling another function. This can be done using the push and pop instructions.

  3. Pay attention to which test cases are failing. For example, does sumOddsUInt8 only fail when the minimum value is even? Think about the actual binary of the bytes stored in each register; it can help guide you to a solution.

========

A Word on Multiplication

It is in your best interest to read up on the AVR Multiplication Instruction before attempting to complete the modulus function.

Note that the multiplication instruction is expecting two unsigned 8-bit values as input, producing a 16 bit result. This does not quite match up with what we will have since one of our values will be an 8-bit unsigned integer (the divisor), but one of them will be a 16-bit unsigned integer (the output from the slowDivision function). For the purposes of this function, you may simply ignore the most significant byte of the 16-bit value and perform the multiplication with the least significant byte.

The output of the multiplication instruction will be placed in r0 and r1. Note, however, that r1 is a special register that is expected to contain zero. What this means is that if you use a multiplication instruction, you must read the value out of r1 and set it back to zero as soon as possible.

========

Checkout

  1. Commit your code and verify in your web browser that is is all there.
  2. Check out with a TA.

The rubric

Generated at 2022-07-20 19:49:20 +0000.
Page written by Bill Siever and Doug Shook.