Lab 3: 8/16 Bit Assembly Language Programming
This lab has you convert a C program that performs 8/16-bit unsigned operations into PIC24 assembly language.
Basics
Download the ZIP archive which contains the lab files and extract it directly into C:\ece3724. You should now have a folder called C:\ece3724\lab_assem1.
Inside this folder, there are three different exercises, called case1, case2 and case3. You only need to complete one of these. There is also an example exercise that's already been completed.
If the last digit of your MSU student ID number is:
0,1,2, then you will be doing case1
3,4,5, then you will be doing case2
6,7,8,9, then you will be doing case3
Be sure:
You're using your MSU ID number. It is on the front of your ID card, has nine digits, and starts with a "9".
You're not using your NetID (your email address).
You do the correct case or you won't get credit for the lab.
For each case, there's a folder containing MPLAB files, an assembly file for you to complete (case#.s), and a C file (case#_check.c) which contains the C code you'll be translating and also automatically checks your results.
The C code is just a series of arbitrary computations. For instance, from example_check.c:
if (u16_b & 0x0100) {
u16_a = u16_b + u8_c;
u16_b = u16_a - u16_b;
} else {
u16_b = u16_a - u16_b;
u16_a = ~u16_b;
}
u8_c = u8_c + 0x5;
u8_e++;
}
These computations will run in a loop for 100 iterations. The computations are not meaningful in themselves; we are only interested in the variable values that are produced on each iteration.
The assembly code you write (in case#.s) needs to perform the same computations. The assembly language program is a loop that calls a C function named check to compare the variables in your assembly language program with the correct variable values during each loop iteration. The check function implements the same C code that you are supposed to implement in your assembly language file.
When you compile and run your case project for the first time, you will see something like this in the UART 1 Output tab:
Test started.
a:34af, b:29fe, c: a458, d:45, e:00 is correct; saw
a1:0000, b1:0d60, c1: 0000, d1:00, e1:00 FAIL
a:34af, b:0d70, c: 522c, d:45, e:01 is correct; saw
a1:5201, b1:0d64, c1: 0001, d1:58, e1:01 FAIL
...
The FAIL messages are because you have not written the assembly code that computes the new variable values yet.
Your task is to manually convert the C code fragments in the comments of your case#.s file to PIC24 assembly language. Once you have implemented the assembly code correctly, the messages printed out by the check function will say 'PASS' instead of 'FAIL'.
Prelab (20 points)
Gather your materials. To complete the lab, you'll want to refer to:
The Chapter 4 lecture slides from Canvas, "8/16-bit Operations in PIC24 Assembly Language"
Sections 1.1, 1.2.1-7, and 1.2.10-11 of the ebook, Interacting with the PIC24 Family in Assembly and C.
The file example.s -- this is a solved problem and will give you hints on how to do your assigned case. It also shows the correct way to comment your assembly code.
Watch the 'lab3_howto' video, which shows Dr. Robert B. Reese, the creator of the Number Sequencing Computer, solving the example exercise from beginning to end.
Load the example project, example.X. Run it (Debug -> Debug Project). Examine the output in the UART 1 Output tab. Stop execution (Debug ->Finish Debugger Session). Clear the UART 1 Output tab (right-click, Clear).
Load your own project, case#.X. Run it, examine the output, stop execution and clear the output.
Open your case#_check.c file. Copy the code at the bottom that's under the comment "Execute body of loop". Paste it into your case#.s file at the very top and surround it with the block comment characters /* */. This will be a handy reference to see the overall structure of the program in one place without having to switch between files:
Like this (for example.s)
Complete the first "TO DO," by declaring your variables:
Variable declarations from example.s
Change NUM_LOOPS to 10 and debug the program. Now go back to your case#_check.c. Copy the variables that you'll need to initialize (found near the top) into your program under the second TO DO (again as a block comment):
From example.s
Initialize your variables. Debug your program and make sure it still runs. If not, make sure you've prefixed literals with # and are using W0/WREG/mov.b properly for 8-bit variables.
Pre-lab checkoff
Variable declaration (first TO DO) completed. (10 pts)
Variable initialization (second TO DO) completed. (10 pts)
Task 1 (60 points)
Next, complete the third TO DO in your case#.s file. This places the variables into certain registers at the beginning of each loop so that the C program can check them. If it's not done, even if the rest of your assembly is written correctly, you'll still get FAILs.
From case3.s. At the top, u8_e has been moved into W4. You'll need to put the other variables into the designated registers. Replace the highlighted line that says "Your code goes here". HINT: You might want to do your 8-bit variables first.
Debug your program. Clear your UART 1 Output window. (Get into the habit of doing this every time or you might be passing the tests without even knowing about it!). You should have one PASS now:
In addition, u8_e should always be correct, that is, e=e1 for every iteration. If you ever notice that this is not the case, it means you've changed something you shouldn't have (probably at the bottom of the program).
Now for the meat of the task, "Implementing the code fragment(s) below". Before you begin, go back to the C code at the top and stare at it until you figure out where it branches. Then note in it where your labels should go. You only need a few, and you don't need one to jump back to the beginning of the program:
From example.s. You only need two labels for this code.
Add each label into your assembly code between the lines of C that precede and follow it:
HINT: If you put your labels all the way to the left, they'll be easier to find.
The best source for the code is example.s. Find a line of C that looks similar to what you need to translate, then copy the assembly below it into your code and change it.
Other good references are the lecture slides, the ebook, and the PIC24 instruction set summary.
Write the register assignments and sort your code into Input/Process/Output as you go along. This is a requirement of the lab. You can add extra comments if it helps you keep things straight, but they are not required.
Debug your code after writing each fragment. Don't worry about if it passes or not, just make sure it runs.
You may not ‘optimize’ away any statements – you are to implement the C code exactly as shown.
For every code fragment, move the variables into registers during the Input phase. Do not count on values you need still being in registers from some previous part of the code!
Be careful of mixed unsigned 8-bit and 16-bit operations -- be sure to zero-extend the 8-bit value.
SL = shift left. LSR = (logical) shift right. You can (only) shift a variable in memory by one bit at a time.
You can do a conditional branch with three lines of code and one register assignment:
Note that we're actually checking if A is not greater than B. If A>B, we want to keep going, so we don't need another branch and another label.
PASSing the tests
Once you have all your assembly written, and gotten your program to build without errors, now is the time to examine the UART Output Window. Probably you're seeing a lot of FAIL. Don't worry.
Double check that you've got at least one PASS and that e is correct for all 10 iterations.
If you only pass that first test and all your values besides e are wrong after the first iteration, you probably branched wrong:
Set a breakpoint in your case#_check.c program on the first line after "Execute body of loop" (which should be an if-statement).
Debug and step through the code (F8), watching which lines execute and which branches the C code takes.
Continue pressing F8. Your assembly code should be taking the same branches. If not, fix it. A very common mistake is to forget to jump to the ENDIF (or whatever you called your label to the code right before e increments) and running both branches of an if/else.
If you pass a few tests and then start to fail, see which variables are wrong on the first FAIL.
Check the branches that alter those variables and look there for errors.
If you can't find any, you probably are going into one of those branches by mistake. Check and recheck your conditionals.
This hints video provides some advanced debugging approaches:
inserting additional printf statements into the C check function to determine when each particular if or else clause is executed
having two MPLAB instances running
using Watch windows to compare the variables in your assembly language with the variables in the C check function during single stepping.
Once you pass 10 iterations, you're almost done! Slyet NUM_LOOPS to 100 and debug again. If you still get all passes take a screenshot of your UART1 tab (be sure to show e1:63 PASS in the screenshot), raise your hand, and a TA will come check you off (unless you're doing the lab at home).
TA Checkoff
Show the TA something like this for your assigned case (60 pts):
FINALLY
Once you've been checked off:
Change NUM_LOOPS to 99.
Set watches for your variables.
Set a breakpoint near the end of your case#.s file, on the line "bra GEU, do_end"
4. Debug and get a screenshot of your watched variables. They should contain the same values as in the last iteration of your program from the previous screenshot.
Report
Write a few sentences about what you did in the lab so that an outside reader could understand, e.g. "I translated the following C code into PIC24 assembly..." not "I did case3.s"
Copy/paste the C code you translated (using a monospace font) or include a screenshot of it in the report.
Include the screenshots of your UART window and your variables. Write a few sentences about what they mean.
Look over your report and be sure:
It has a neat, professional appearance (Legible screenshots, no blank pages, etc).
It includes the aforementioned text.
It includes the required 2-3 screenshots, but not extraneous ones (like screenshots of your entire case#.s file).
It has a title page.
Clean up your case#.s file:
Put a header on it that includes your name, the filename, and lab section number:
Make sure your code has register assignments and correctly uses the Input/Process/Output format (see example.s)
Remove or replace all lines that say:
Replace this line with your register assigments.
Your code goes here
Code may go here...
...and may also go here.
Tidy it so there's not blank lines and random indentations everywhere:
0.
Submit:
PDF file with report, including title page, screenshots, and appropriate text (10 pts)
Formatted case#.s file with header and comments (10 pts)