https:
eclass.yorku.ca/pluginfile.php/4300748/mod_resource/content/1/LabE_EECS2021_MixC_ASM_AVR_Student_VERSION_F2022
EECS 2021 – Lab E: Assembler & C on the ATMEGA Student VERSION F2021
Copyright James Andrew Smith; You do not have permission to distribute outside of
York University.
EECS 2021 – Lab E: A Beautiful Ensemble:
C & Assembler on the ATMEGA328PB
Dr. James Andrew Smith, PEng.
Figure 1 Summary of tasks for this lab. The demo should be done on ATMEGA hardware, but can be done in
simulation with a 25% penalty.
Summary: You will combine C programming and Assembler on the ATMEGA328P. In this lab,
with the ATMEGA328, you will see how to can write your work in C while also inserting assembler
operations “in-line”. (You need the Grove Beginner
Kit for Arduino hardware for this lab.)
Pre-Lab: You are to prepare for the lab by doing the
following
1. Finish Labs A through D
2. Watch any videos on eClasss
3. Review notes on XC8 and the ATMEGA328
https:
it.ly/3jB0DhB (Mix C &
Assembler)
There are three parts to this lab:
1. Part 1 of the lab.
• Demo to the TA with hardware (blinking light)
• No hardware? Simulate it.
2. Part 2: Inline Assembler to solve a simple math problem
• Demo to the TA in hardware (if you have it)
• … or in simulation demo if you don’t have working hardware
3. Part 3: Inline Assembler and return the result of a simple math problem to C.
• Demo to the TA in hardware (if you have it)
• … or in simulation demo if you don’t have working hardware
Figure 2 You can use Assembler in multiple ways
within a C or C++ project.
EECS 2021 – Lab E: Assembler & C on the ATMEGA Student VERSION F2021
Copyright James Andrew Smith; You do not have permission to distribute outside of
York University.
Marking:
• Demo Part 1. (Toggle LEDs via Assembler)
o 0.2 marks. 0.1 marks if you are only partially successful. 0 if you do not attempt.
o Lab demo required (webcam). You can show the LED changing while stepping
through the disassembled code.
o Three-quarter marks in you’re running in simulation. (i.e. non-functional hardware).
• Demo Part 2 (Show the Assembler math operation works)
o 0.4 marks. 0.2marks if you are only partially successful. 0 if you do not attempt.
o Lab demo req’d by sharing screen or recorded video. Run program on hardware,
show debug view.
o Three-quarter marks if you’re running in simulation. (i.e. non-functional hardware).
• Demo Part 3 (Show you can transfer Assembler math result back to C)
o 0.4 marks. 0.2 marks if you are only partially successful. 0 if you do not attempt.
o Lab demo req’d by sharing screen or recorded video. Run program on hardware,
show debug view.
o Three-quarter marks if you’re running in simulation (i.e. non-functional hardware).
It is important that the TA see the project settings for your program in the shared screen or video. It should
show that you have the Snap debugger connected to your hardware. It is up to you to make sure that this is
visible to the TA, otherwise it counts as non-hardware (simulated).
If you do not have working hardware:
o You can do the three demonstrations, but you’ll need to do so in simulation.
§ For Part 1, you’ll need to show that the PB5 bit changes.
§ For Parts 2 and 3, you’ll need to show how either a variable or a register
changes values. This can be done, for instance, using a watch option in
MPLAB X.
o Simulations, without working hardware, are worth three-quarters of the mark
associated with doing it with working hardware.
Figure 3 A regular program, written in C (1) can have inline Assembler commands (line 26) or can make function
calls on line 38 to stand-alone functions written either in C or Assembler (2). Even if you’re not writing anything in
Assembler, you can still request the “Disassembled” view of your entire project, as shown in (3). Combined with
memory and register views like (4) you can obtain a lot of insights into how your machine is actually working.
EECS 2021 – Lab E: Assembler & C on the ATMEGA Student VERSION F2021
Copyright James Andrew Smith; You do not have permission to distribute outside of
York University.
Introduction
To balance speed of development with efficient use of processor resources real-world engineers
and computer scientists combine Assembler and C in embedded systems like, ARM, RISC-V,
PIC32 or the ATMEGA328. This middle-of-the-road approach is very effective, and, in this lab,
you will see how to do so in very practical ways
In this lab, with the ATMEGA328, you will see how to can write your work in C while also
inserting assembler operations “in-line”.
In a future lab, you may see how a similar process can be followed but by having a main function
in C and then calling a special function written in Assembler, as previewed in
https:
youtu.be/iztabJQNMEw.
There are three major types of applications that require at least a superficial understanding of
Assembler and the interactions between your compiler and the machine under the hood: embedded
device developers, operating system & device driver developers and computer security
professionals.
To interact and understand the system “under
the hood” one typically develops an
understanding for, at minimum, being able to
ead the Assembler listings produced by your
C compiler. MPLAB X and MCUXpresso,
like most modern IDEs will provide you with
a “disassembly” tool that gives you a
epresentation of the machine codes, written
as Assembler calls, that the compiler
elieves represents the intention of your C
program.
A really convenient way of examining the
Assembler version of your high-level
program for a multitude of languages (C,
C++, Ada and many, many others),
compilers (e.g. gcc and clang) and computer
architectures (AVR, MIPS, ARM Cortex
m0+ 1 , x86, etc.) is Godbolt’s Compiler
Explorer, shown below. Your MPLAB X
IDE can also create disassembled code, as
shown in the videos:
https:
youtu.be/8_VLufBGIIs.
1 If you’re interested in use Compiler Explorer for examining chips like the Kinetis or SAMD or
STM32, including specific flavours like the ARM Cortex m0+ (ARM GCC 8.x) use the following
modifiers: -mcpu=cortex-m0plus -mthumb
Figure 4 Many compiler tools can produce "disassembled" views of your
program. This shows you the chip-specific commands that it implements as a
esult of the compiling process. Compiler Explorer is a very useful tool to
examine the difference in compilers for different architectures.
EECS 2021 – Lab E: Assembler & C on the ATMEGA Student VERSION F2021
Copyright James Andrew Smith; You do not have permission to distribute outside of
York University.
Background2
Simple Inline Assembler
Occasionally you’ll need to request a special low-level command that has no
equivalent in standard C. The “no operation” or “enable inte
upts” Assembler
commands (“mnemonics”) are commonly seen in embedded systems code. In
all of the architectures described in this book, their native Assemblers all refer
to “no operation” as “NOP” and an example would look something like this:
void main(void)
{
int my_variable = 1;
asm("nop");
a special function call in C to request
that compiler insert the assembler
mnemonic
NOP within the main function
}
If you wanted to have the same mnemonic called four times you could write
asm( "nop\n\t"
1st NOP
"nop\n\t"
2nd NOP
"nop\n\t"
3rd NOP
"nop\n\t");
4th NOP
Where the \n and \t mean “new line” and “tab” and are inserted by the C compiler into the Assembler program
it generates prior to sending it off to the Assembler program to create executable code.
Warning
When mixing Assembler and C solutions it is important to keep in mind that you cannot make assumptions
about the register usage, the stack, etc. as you transition from one to the other. The XC8 guides has a
particular warning that is worthwhile keeping in mind:
“When using in-line assembler code, it is extremely important that you do not interact with
compiler-generated code. The code generator cannot scan the assembler code for register
usage; so, it will remain unaware if registers are clo
ered or used by the assembly code.”
(http:
ww1.microchip.com/downloads/en/DeviceDoc/MPLAB_XC8_C_Compiler_User_Guide_for_PIC.pdf)
Boxing in any elaborate assembler routines within a callable function is often a good idea. You can see an
example of that in this video: https:
youtu.be/8_VLufBGIIs.
2 Material in this lab comes from an upcoming book by James Andrew Smith and Loren Wyard-Scott.
Figure 5 Adding a single inline assembler
instruction into a function otherwise completely
written in C. The original version is on the left
and the decompiled version is on the right.
Compiler Explorer (godbolt.org) was used to
illustrate this process.
EECS 2021 – Lab E: Assembler & C on the ATMEGA Student VERSION F2021
Copyright James Andrew Smith; You do not have permission to distribute outside of
York University.
Slightly More Complex Assembler & C
You will sometimes need to write entire functions in Assembler or you may wish to write functions in
Assembler but leave the epilogue and prologue to the C compiler.
While we can input inline assembler using mnemonics that don’t require additional information like literals
or register names:
asm ("nop");
no operation
__asm ("nop");
no operation
three "no operations", all declared volatile to
force compiler to keep.
asm volatile ("nop \n"
first no operation
"nop \n"
second no operation
"nop ");
third no operation
asm(“sei”);
enable inte
upts
asm(“cli”);
clear inte
upts
__asm(“sei);
enable inte
upts
Most assembler calls do, in fact, require you to name affected registers or literal values that are used. For
instance, you can represent an “immediate3 load value 18 into register 25” as
asm(“ldi r25, 18 \n”);
load value 18 into Register R25
Insert this into an MPLAB X C program or try Compiler Explorer, using the “Arduino Uno” setting (C or
C++ compiler) and you’ll see the Assembler operation appear in the disassembled listings.
Now, try a slightly more complex program that stores that value, 18, into SRAM, at a location defined by a
global variable (source: https:
tinyurl.com/y6t6psf3 or https:
it.ly/31e8c6N)
#include
#include
global variable. Will be located in SRAM,
e.g. address 0x100. (needs to be global)
char volatile my_var = 0;
int main(void) {
asm("nop \n");
no operation
asm("ldi r26, 42 \n");
load 42 into register R26
asm("sts (my_var), r26 \n");
store the contents of R26
@ the location of my_var
return (EXIT_SUCCESS);
}
Here, we used the parentheses (which I highlighted in blue) to denote a memory location. Which memory
location? The one where the global variable my_var’s value is stored. This is a “pointer”, which a term
commonly discussed in C or C++ programming.
3 “Immediate” operations mean ones that use constants.
EECS 2021 – Lab E: Assembler & C on the ATMEGA Student VERSION F2021
Copyright James Andrew Smith; You do not have permission to distribute outside of
York University.
Even More Complex Assembler & C
You can also call more elaborate, extended assembler instructions inline in C. Due to the limitations in C
the syntax is a little unwieldy, but is workable and maintainable. In the complier documentation and in online
sources you’ll find templates that look like this:
asm("template" [ : [ "constraint"(output-operand) [ , ... ] ] [ :
[ "constraint"(input-operand) [ , ... ] ]
[ "clo
er"