ENGR 478 Lab 3: Introduction to the Keil MDK Development Tool and Assembly Programming Xiaorong Zhang Preparation Install and run Keil uVision on your personal computer. The software installation instruction can be downloaded from the Required Lab kit and Software section on Canvas. Objectives The general purpose of this lab is to familiarize you with the ARM Cotex-M4 instruction set architecture (ISA) and the software development steps using the Keil MDK simulator. Starting with Lab 3, we will use Keil MDK for both simulation and debugging on the real board, but for this lab, we will use just the simulator. You will learn how to develop and simulate assembly programs using Keil MDK. Through a graphical user interface, the programmer can monitor program execution and the status of the simulated microcontroller including the CPU registers and memory. Software skills you will learn include variable initialization, memory access instructions, arithmetic operations, condition code flags, and branching. References ➢ ARM Assembler Directives ➢ Textbook Appendix B: Cortex-M3/M4 Instructions ➢ Cortex-M3/M4F Instruction Set Technical User’s Manual (Canvas ->Other Reference Materials) ➢ Thumb-2 Instruction Set Quick Reference Card (Canvas-> Other Reference Materials) Demonstration and Submission You will have one week to complete the lab. You can discuss with your group members and complete the lab work together. The weekly lab work is done within student groups of no more than three individuals. A post-lab report is required to be submitted individually for each lab. While the lab demo is evaluated on a group basis, the post-lab report is evaluated on an individual basis. Every student will need to write and submit a lab report to Canvas->Labs->Lab3 report submission. The lab report should include • • • • Your name, email and SFSU ID Your lab group members’ names The answers to all the questions listed on Page 9 Reflection: 1. Do you feel you achieved the objectives of this lab? 2. What skills do you feel you developed during this lab? 3. Were there any unexpected issues or obstacles that arose during the lab? How did you address them? 4. If you worked in a group, how did team dynamics affect your performance and understanding of the lab material? 5. Are there questions you still have or concepts you're not entirely clear on after completing the lab? 6. Do you have any recommendations for how the lab could be improved in terms of structure, content, or delivery? If you finish the lab experiments during the lab time, please demonstrate your results to the instructor. The instructor may ask questions regarding your program. The latest demonstration time will be the beginning of next lab. The lab report is due the Sunday following the lab demo deadline. ENGR 478 Procedure Before you start the tutorial, make sure you have installed all the software tools. 1. Download the project M1M2.zip from Canvas->Labs->Lab3->M1M2. This project serves as an illustrative Assembly project for our simulation using the Keil MDK during this lab. To organize your work effectively, establish an ENGR 478 work folder on your local computer. Store the M1M2 sample project archive within this designated work folder and then extract its contents. 2. Navigate to the extracted M1M2 folder and then double-click on the M1M2 uVision5 Project file (see Figure 1). Figure 1 3. The M1M2 project will load in the Keil MDK (see Figure 2). In the Project window on the left side, there are three .s files under Source Group 1. Specifically, the files named "startup_stm32l476xx.s" and "stm32l476xx_constants.s" encompass assembly source code that defines crucial elements such as the stack, reset vector, and interrupt vectors. It's important to note that every project within this course will incorporate a "startup_stm32l476xx.s" file, and for the purposes of this lab, there is no requirement to modify this particular file. The third file, titled "main.s," contains the essential source code for the main routine of the M1M2 project. This file encompasses the core functionality that drives the operations of the M1M2 project. Figure 2 ENGR 478 4. Compile the project by selecting Project->Rebuild all target files or directly clicking on the Rebuild button as shown in Figure 3. Upon performing this action, the Build Output window should display a count of 0 errors and 0 warnings, signifying a successful compilation process. Figure 3 5. Prior to initiating the program simulation, it is necessary to configure the Debug settings. To proceed with this, navigate to the "Project" menu, then opt for "Options for Target 'Target 1'." Alternatively, you can directly click on the designated button, as denoted in Figure 4. A new window will appear; within this pop-up window, select the "Debug" tab and ensure to select the checkbox labeled "Use Simulator," as shown in Figure 4. Figure 4 ENGR 478 6. You are now ready to start program simulation. Select Debug->Start/Stop Debug Session to trigger the initiation of the simulation (see Figure 5). As the simulation begins, several essential monitor windows will become visible, as shown in Figure 6. These monitor windows include the Registers Window, Disassembly Window, Source Code window, and Memory 1 Window. Each of these windows contributes to providing a comprehensive view of the simulation or debugging process and its various components. Figure 5 7. In the source code editing window, you will see the symbol points to the instruction “LDR r0, =|Load$$RW_IRAM1$$Base|” in the "startup_stm32l476xx.s” file. This symbol serves as a marker always highlighting the next instruction that the CPU will execute. After a reset operation, the symbol signifies the initial instruction that will be executed within the project. In this project, the instruction “LDR r0, =|Load$$RW_IRAM1$$Base|” is the first instruction in the system’s Reset Handler, which defines the procedure to initialize the system after a reset event. Figure 6 ENGR 478 8. To simulate the program step by step, click Debug->Step or the button. Upon each click, a single instruction will be executed, subsequently updating both the registers and memory to reflect the execution outcomes. The program counter R15(PC) (displayed in the Registers window on the left panel) always points to the next instruction to be executed. As you run the “Step” command for a few times, you will see the symbol traverse the sequence of instructions outlined within the Reset_Handler process in the "startup_stm32l476xx.s” file. Given that this lab focuses on the simulation and observation of the main routine residing in the "main.s" file, the instruction-by-instruction simulation of the Reset_Handler process can be bypassed. Instead, you can set up a breakpointer at the instruction you intend to simulate, which in this case is the first instruction within "main.s." Subsequently, click the "Run" button to directly progress to the breakpointer. To insert a breakpointer, a simple click to the left of the relevant line number (as demonstrated in Figure 7) is sufficient. A red dot will then appear next to the targeted instruction. Subsequent to this setup, execute the "Run" command. As a result, the simulator will immediately transition from the prior simulated instruction to the instruction indicated by the breakpointer, specifically the "LDR R1, =M1" instruction within "main.s." By subsequently clicking the "step" button, you can simulate the instructions line by line within the main routine. If you want to reset the simulation process, you can click Debug->Reset CPU or the designated button. If you have made any changes to your program and wish to simulate the changed program, you must exit the debug mode, rebuild the project, and start the debug session again. Reset CPU button Run button Figure 7 9. The Keil MDK uVision Debugger offers robust capabilities to developers. During the debugging process, developers can access the source code, and can control and analyze program execution at both high-level (C/C++) and Assembly levels. To learn more about the debug menu and commands, you can refer to the uVision Help documentation (accessible via Help -> uVision Help -> uVision User’s Guide). In this particular activity, your focus will be on utilizing the "Step" command. This command facilitates the execution of the assembly program instruction by instruction. Simultaneously, you will closely monitor changes in CPU register values and memory content. ENGR 478 Your objective will be to observe and document the alterations in registers and memory locations that are pertinent to each step of the program's execution. Further detailed explanations regarding the Registers window, Disassembly window, and Memory window are provided below: a. Registers Window (Figure 8): The Registers window shows the content of registers, microcontroller operation modes, and system and internal states. Through this window, you can closely monitor the contents stored within both general-purpose registers (R0-R12) and special registers (SP, LR, PC, and PSR) during the execution of the software program. Additionally, the ability to expand the xPSR register allows for a granular view of individual bits within the program status register. The condition flags—N, Z, C, and V—are established through arithmetic and logical instructions, subsequently influencing conditional code execution. Figure 8 b. Disassembly Window: The Disassembly Window provides a visual representation of the program's execution in assembly code. Within this window, you gain insight into crucial details such as memory addresses, machine code representations, and the corresponding assembly code for each instruction. Notably, the currently executing instruction is always highlighted for clarity and focus. In Figure 9, an illustrative example showcases the program counter (R15 PC) pointing to the initial instruction to execute within the "main.s" file: " LDR R1, =M1". Correspondingly, the ENGR 478 Registers Window displays the content in the PC register as 0x0800.0220, signifying the memory address of the upcoming instruction. The Disassembly Window further reinforces this by highlighting the line starting with 0x0800.0220, signifying the impending execution of the highlighted instruction. The sequence "4904" is the 16-bit machine code associated with the instruction " LDR R1, =M1", encompassing the content stored at memory addresses 0x0800.0220 and 0x0800.0221. This machine code aligns with the assembly instruction "LDR r1, [pc, #16]," presenting an alternative format to express "LDR R1, =M1." This particular format sheds light on the instruction's addressing mode, identified here as PC relative addressing. Figure 9 c. Memory Windows: The Memory Windows serve as a visualization of memory areas' contents. To access a Memory window, navigate to View -> Memory Windows -> Memory 1, as shown in Figure 10. Upon doing so, you gain the capability to input a specific memory address and subsequently view the content residing within that designated address. For instance, consider the 32-bit data "M1" within the sample program; its address is 0x2000.0000, as it stands as the foremost variable defined in SRAM. To explore its content, simply enter 0x20000000 (ensuring the "0x" prefix) within the Memory 1 Window, as shown in Figure 11. Upon executing this action, the value attributed to "M1" and stored within the memory range of 0x20000000 to 0x20000003 will be showcased. At the outset, this value might be represented as "00 00 00 00" in hex. In essence, the Memory Windows provide an insightful perspective into the information stored within different memory addresses including flash memory, SRAM, IO registers, and internal system peripherals, facilitating a comprehensive understanding of program memory utilization. ENGR 478 Figure 10 Figure 11 11. At this point, you should be familiar with the process of simulating and observing the program's execution step by step. Before moving forward, take a moment to review the list of questions outlined on Page 9, which you are expected to address within your forthcoming lab demo and report. To proceed, your next objective is to simulate the program within the "main.s" file line by line until the program concludes. Throughout this process, maintain a record of the values attributed to related registers and memory locations and answer the questions specified on Page 9. This procedure will allow you to engage in a comprehensive analysis of the program's behavior and outcomes. ENGR 478 Questions 1. Construct a table in the format shown below to document the values associated with relevant registers and data during the progressive simulation of the program within the "main.s" file. Please note that PC, NZCV, R1-R4 represent information within the CPU registers. M1 and M2 are two specific data entities allocated in the memory. Steps PC NZCV R1 R2 R3 R4 M1 M2 1 2 … 2. The program within the "main.s" file consists of 1) assembler directives, which provide instructions for the assembler to perform certain tasks without being converted into machine code or stored in memory; and 2) assembly instructions are converted into machine instructions by the assembler. List all the assembly instructions of this program that are converted into machine instructions. 3. What are the specific functions of the instructions "M1 SPACE 4" and "NUM DCD 6," respectively? Referencing the ARM Assembler Directives, clarify the roles these instructions play. If the objective is to define a 16-bit constant data labeled "NUM1" with an initial value of 12, write the code required to achieve this. 4. What memory addresses are assigned to the data entities "M1" and "M2"? Upon completion of the simulation, what values are stored at these respective memory addresses? 5. Within this program, consider the following components—M1, M2, NUM, and all the assembly instructions. Identify the specific memory storage categories for storing each of these elements (e.g., flash memory, SRAM) using the reference "STM32L47xxx Reference Manual - Chapter 2," which defines the memory address space for various memory categories. 6. After executing “SUBS R4, R3, #5”, what are the values of the condition code flags? Why? 7. What is the address of instruction “BGT S_2” in memory? What does this instruction do? After executing this instruction, what is the value stored in the program counter (PC)? Why? 8. Adjust the value of "NUM" to be 3 within the "main.s" file, then simulate the program again. Upon completion of the simulation, what are the values stored in the memory locations of "M1" and "M2"? 9. What underlying functionality or logic does this program implement? If you were to implement this logic utilizing a high-level programming language such as C, illustrate how the code might be written. You are welcome to utilize any high-level programming language you are familiar with, or even provide pseudocode to articulate the logic.