ECE 382 Lesson 22 Readings Lesson Outline Writing Clean Code

Slides:



Advertisements
Similar presentations
1 Lecture 3: MIPS Instruction Set Today’s topic:  More MIPS instructions  Procedure call/return Reminder: Assignment 1 is on the class web-page (due.
Advertisements

Deeper Assembly: Addressing, Conditions, Branching, and Loops
Computer Architecture CSCE 350
Procedures II (1) Fall 2005 Lecture 07: Procedure Calls (Part 2)
Apr. 12, 2000Systems Architecture I1 Systems Architecture I (CS ) Lecture 6: Branching and Procedures in MIPS* Jeremy R. Johnson Wed. Apr. 12, 2000.
The University of Adelaide, School of Computer Science
Chapter 7: User-Defined Functions II
Memory Image of Running Programs Executable file on disk, running program in memory, activation record, C-style and Pascal-style parameter passing.
Accessing parameters from the stack and calling functions.
Runtime Environments Compiler Construction Chapter 7.
Programming Language Principles Lecture 24 Prepared by Manuel E. Bermúdez, Ph.D. Associate Professor University of Florida Subroutines.
Chapter 14 Functions.
Procedure Basics Computer Organization I 1 October 2009 © McQuain, Feng & Ribbens Procedure Support From previous study of high-level languages,
ITCS 3181 Logic and Computer Systems 2015 B. Wilkinson Slides4-2.ppt Modification date: March 23, Procedures Essential ingredient of high level.
CE-2810 Dr. Mark L. Hornick 1 Mixing C and assembly Safety goggles on!
4-1 Embedded Systems C Programming Language Review and Dissection II Lecture 4.
October 1, 2003Serguei A. Mokhov, 1 SOEN228, Winter 2003 Revision 1.2 Date: October 25, 2003.
1 Scope Lifetime Functions (the Sequel) Chapter 8.
Calling Procedures C calling conventions. Outline Procedures Procedure call mechanism Passing parameters Local variable storage C-Style procedures Recursion.
Function Calling. Mips Assembly Call and Return Steps for procedure calling –Save the return address –Jump to the procedure (function) –Execute the procedure.
Practical Session 3.
Lecture 3 Translation.
Deeper Assembly: Addressing, Conditions, Branching, and Loops
Reading Condition Codes (Cont.)
Storage Allocation Mechanisms
Storage Classes There are three places in memory where data may be placed: In Data section declared with .data in assembly language in C - Static) On the.
ECE 382 Lesson 21 Readings Lesson Outline
Popping Items Off a Stack Using a Function Lesson xx
ECE 3430 – Intro to Microcomputer Systems
Format of Assembly language
ECE 382 Lesson 8 Lesson Outline Miniquiz Assignment 3
Lesson Outline Interrupts Admin Assignment #9 due next lesson
ECE 382 Lesson 6 Lesson Outline Status Register Flow of Control
ECE 3430 – Intro to Microcomputer Systems
© Craig Zilles (adapted from slides by Howard Huang)
Lesson Outline Peripherals Memory-Mapped IO Ports GPIO Multiplexing
C Programming Tutorial – Part I
Lecture 4: MIPS Instruction Set
143A: Principles of Operating Systems Lecture 4: Calling conventions
In this lecture Global variables Local variables System stack
CS 11 C track: lecture 8 Last week: hash tables, C preprocessor
Stack Lesson xx   This module shows you the basic elements of a type of linked list called a stack.
Chapter 9 :: Subroutines and Control Abstraction
Arrays & Functions Lesson xx
Lecture 4: MIPS Instruction Set
ECE 3430 – Intro to Microcomputer Systems
Popping Items Off a Stack Lesson xx
Handling Arrays Completion of ideas needed for a general and complete program Final concepts needed for Final.
Given the code to the left:
EECE.3170 Microprocessor Systems Design I
Coding Concepts (Basics)
EECE.3170 Microprocessor Systems Design I
EECE.3170 Microprocessor Systems Design I
Using Arrays Completion of ideas needed for a general and complete program Final concepts needed for Final.
Multi-modules programming
Handling Arrays Completion of ideas needed for a general and complete program Final concepts needed for Final.
Lecture 2 SCOPE – Local and Global variables
EECE.3170 Microprocessor Systems Design I
ECE 3430 – Intro to Microcomputer Systems
Handling Arrays Completion of ideas needed for a general and complete program Final concepts needed for Final.
X86 Assembly Review.
COMP3221: Microprocessors and Embedded Systems
Some Assembly (Part 2) set.html.
Computer Architecture
Where is all the knowledge we lost with information? T. S. Eliot
Variables in C Topics Naming Variables Declaring Variables
© Craig Zilles (adapted from slides by Howard Huang)
Procedure Support From previous study of high-level languages, we know the basic issues: - declaration: header, body, local variables - call and return.
ECE511: Digital System & Microprocessor
An Introduction to the ARM CORTEX M0+ Instructions
Presentation transcript:

ECE 382 Lesson 22 Readings Lesson Outline Writing Clean Code Mapping C Programming Constructs to MSP430 Assembly Lesson Outline Writing Clean Code Mapping C to Assembly Calling Assembly from C Lab#4 Intro Admin Assignment 8 due BOC today Lab#4 Prelab due BOC next lesson

Writing Clean Code Okay to use i, j, k for loop counters Meaningful Names Use intention-revealing names ("self-documenting") int d, temp; // elapsed time in days, a temporary variable int elapsedTimeInDays, daysSinceModification; Make meaningful distinctions void copyChars(char* a1, char* a2) void copyChars(char* source, char* destination) Use pronounceable names DtaRcrd DataRecord Use searchable names MAX MAX_STUDENTS Functions: use verbs! forward() moveForward() Don't be cute holyHandGrenade() deleteItem() Pick one word per concept Bad: fetch(), retrieve(), get() Okay to use i, j, k for loop counters

Clean Functions Small - ideally less than 10 lines long Do one thing Use descriptive names Parameters: rarely need more than two or three Side effects - function should only do what you say it does Do not use static or global variables Only depend on local variables / parameters Don't repeat yourself - write a function instead of copy / paste Only one entry / exit point Indent correctly!

Clean Comments Comment on "big picture" items Head of each file Definition of each function Beginning of each major block of code As you move deeper in the hierarchy, the comments are more specific Try writing functions / meaningful names if ((employeeFlags & HOURLY_FLAGS) && (employeeAge > 65)) ... if (isEligibleForFullBenefits(employee)) ... TODO comments // TODO: Make this into a function // TODO: Write new header file to group these functions Bad comments Restating your code (a = 1; // Setting a to 1) Commented-Out code Too much information Don't comment bad code - rewrite it.

Mapping C to Assembly Assembly Version: bis.b #BIT0|BIT6, &P1DIR bic.b #BIT3, &P1DIR bis.b #BIT3, &P1REN bis.b #BIT3, &P1OUT check_btn: bit.b #BIT3, &P1IN jz set_lights bic.b #BIT0|BIT6, &P1OUT jmp check_btn set_lights: bis.b #BIT0|BIT6, &P1OUT C Version: #include <msp430g2553.h> #define TRUE 1 void main(void) { P1DIR |= BIT0|BIT6; P1DIR &= ~BIT3; P1REN |= BIT3; P1OUT |= BIT3; while (TRUE) if (P1IN & BIT3) P1OUT &= ~(BIT0|BIT6); else P1OUT |= BIT0|BIT6; }

Mapping C to Assembly C Version: #include <msp430g2553.h> Typedef unsigned short int16; int16 func(int16 w, int16 x, int16 y, int16 z); void main() { Int16 a,b,c,d,e; a=1;b=2;c=3;d=4; while(1) { e = func(a,b,c,d); } int16 func(int16 w, int16 x, int16 y, int16 z) { int16 sum; sum = w+x+y+z; return(sum); Generated Assembly Code: 11 e = func(a,b,c,d); $C$L1: c074: MOV.W @SP,R12 c076: MOV.W 0x0002(SP),R13 c07a: MOV.W 0x0004(SP),R14 c07e: MOV.W 0x0006(SP),R15 c082: CALL #func c086: MOV.W R12,0x0008(SP) 10 while(1) { c08a: JMP ($C$L1) int16 func(int16 w, int16 x, int16 y, int16 z) { func(): c08c: SUB.W #0x000a,SP c090: MOV.W R15,0x0006(SP) c094: MOV.W R14,0x0004(SP) c098: MOV.W R13,0x0002(SP) c09c: MOV.W R12,0x0000(SP) 17 sum = w+x+y+z; c0a0: MOV.W R13,R12 c0a2: ADD.W @SP,R12 c0a4: ADD.W 0x0004(SP),R12 c0a8: ADD.W 0x0006(SP),R12 c0ac: MOV.W R12,0x0008(SP) 19 } c0b0: ADD.W #0x000a,SP c0b4: RET Let's examine what's going on here. The first line of code moves r1 (the stack pointer) into r4. The compiler is using r4 as the frame pointer. When you call a function (main() in this case), all of its local variables are allocated on the stack. We call the space on the stack used by a function a stack frame. However, the stack pointer changes as you allocate more variables on the stack. So a variable that was at 4(r1) at one point in your function could later be at 8(r1) if the stack pointer changes. The frame pointer ensures a consistent address for the same variable throughout the function. If we store the address of the base of the stack frame in the frame pointer, each variable will always be stored at the same place relative to the frame pointer - so a variable at 4(r4) will always be accessible at 4(r4). So the first line of code is setting the frame pointer. Next, the compiler adds 2 to the frame pointer. In most functions, the first thing you do is push the frame pointer onto the stack via push r4 - main is the exception. Adding two puts the base of the stack frame below this value, which is what we want. Next, the compiler subtracts two from the stack pointer. This is because we're allocating our int variable on the stack, so we're giving it two bytes. If we allocated two ints, the compiler would subtract 4 from the stack pointer. Our first four instructions are identical to our first sample program. We're setting up the frame pointer and allocating our variable on the stack. Next, we're moving our variable into r15. Remember, our ABI says that the first parameter to a function should be passed in through r15 - so we move our there. Next, we call the recursiveSummation subroutine the compiler has created. Once inside the recursiveSummation subroutine, we push the framePointer onto the stack so we don't destroy it. Then, we establish a new frame pointer and allocate a variable on the stack - just like we did in main. Next, the compiler moves the parameter we passed in r15 into the variable we established. It compares the variable to 1. If it's greater than or equal to 1, we jump to .L3 - the label that holds the code in our else case. We move our parameter into r15 (the register that holds the first parameter we pass to functions), subtract one, and call our recursiveSummation subroutine again. This code is the recursiveSummation(numberToSum - 1) piece of our code. The final instruction adds the current parameter to the result passed back in r15. This code is the return numberToSum + piece of our code. If it's less than 1, we're finished. We move 0 into r15, deallocate our variable from the stack, retrieve the frame pointer we pushed initially, and return. If you're interested in learning more, check out this Wikipedia reading on the Call Stack. After we're done, we'll add 2 to the stack pointer to deallocate int variable since we're done using it.

Calling Assembly Functions from C For our compiler, it follows the this convention for passing parameters when calling an assembly function from C First input R12 Second input R13 Third input R14 Fourth input R15 Fifth and beyond Stack return

Example Calling Assembly from C Main.c #include <msp430g2553.h> typedef unsigned short int16; extern int16 func(int16 w, int16 x, int16 y, int16 z); /* Function Prototype for asm function */ void main(void) { int16 a,b,c,d; WDTCTL=WDTPW+WDTHOLD; /* stop WD */ a=1; b=2; c=3; d=4; while(1) { b = func(a,b,c,d); } } math.asm .cdecls C,LIST,"msp430.h" .text .retain .retainrefs .global func  func:                 ; implement sum = w+x+y+z;        add R13, R12  ; r12 = w [r12] + x [r13]        add R14, R12 ; r12 = y [r14] + (w+x) [r12]        add R15, R12 ; r12 = z [r15] + (w+x+y) [r12]        ret             ; r12 is return parameter (sum) Let's examine what's going on here. The first line of code moves r1 (the stack pointer) into r4. The compiler is using r4 as the frame pointer. When you call a function (main() in this case), all of its local variables are allocated on the stack. We call the space on the stack used by a function a stack frame. However, the stack pointer changes as you allocate more variables on the stack. So a variable that was at 4(r1) at one point in your function could later be at 8(r1) if the stack pointer changes. The frame pointer ensures a consistent address for the same variable throughout the function. If we store the address of the base of the stack frame in the frame pointer, each variable will always be stored at the same place relative to the frame pointer - so a variable at 4(r4) will always be accessible at 4(r4). So the first line of code is setting the frame pointer. Next, the compiler adds 2 to the frame pointer. In most functions, the first thing you do is push the frame pointer onto the stack via push r4 - main is the exception. Adding two puts the base of the stack frame below this value, which is what we want. Next, the compiler subtracts two from the stack pointer. This is because we're allocating our int variable on the stack, so we're giving it two bytes. If we allocated two ints, the compiler would subtract 4 from the stack pointer. Our first four instructions are identical to our first sample program. We're setting up the frame pointer and allocating our variable on the stack. Next, we're moving our variable into r15. Remember, our ABI says that the first parameter to a function should be passed in through r15 - so we move our there. Next, we call the recursiveSummation subroutine the compiler has created. Once inside the recursiveSummation subroutine, we push the framePointer onto the stack so we don't destroy it. Then, we establish a new frame pointer and allocate a variable on the stack - just like we did in main. Next, the compiler moves the parameter we passed in r15 into the variable we established. It compares the variable to 1. If it's greater than or equal to 1, we jump to .L3 - the label that holds the code in our else case. We move our parameter into r15 (the register that holds the first parameter we pass to functions), subtract one, and call our recursiveSummation subroutine again. This code is the recursiveSummation(numberToSum - 1) piece of our code. The final instruction adds the current parameter to the result passed back in r15. This code is the return numberToSum + piece of our code. If it's less than 1, we're finished. We move 0 into r15, deallocate our variable from the stack, retrieve the frame pointer we pushed initially, and return. If you're interested in learning more, check out this Wikipedia reading on the Call Stack. After we're done, we'll add 2 to the stack pointer to deallocate int variable since we're done using it.

Lab#4 Intro Lab#4 Assignment: Mixing C and Assembly Etch-a-sketch/paint program on the LCD display

Todd’s old GCC example

Mapping C to Assembly (gcc compiler) C Version: #include <msp430g2553.h> int recursiveSummation(int numberToSum); void main(void) { int my_number = 10; my_number = recursiveSummation(my_number); } int recursiveSummation(int numberToSum) if (numberToSum <= 0) return 0; else return numberToSum + recursiveSummation(numberToSum - 1); Generated Assembly Code: main: mov r1, r4 add #2, r4 sub #2, r1 mov #10, -4(r4) mov -4(r4), r15 call #recursiveSummation mov r15, -4(r4) add #2, r1 recursiveSummation: push r4 cmp #1, -4(r4) jge .L3 mov #0, r15 jmp .L4 .L3: sub #1, r15 add -4(r4), r15 .L4: pop r4 ret Let's examine what's going on here. The first line of code moves r1 (the stack pointer) into r4. The compiler is using r4 as the frame pointer. When you call a function (main() in this case), all of its local variables are allocated on the stack. We call the space on the stack used by a function a stack frame. However, the stack pointer changes as you allocate more variables on the stack. So a variable that was at 4(r1) at one point in your function could later be at 8(r1) if the stack pointer changes. The frame pointer ensures a consistent address for the same variable throughout the function. If we store the address of the base of the stack frame in the frame pointer, each variable will always be stored at the same place relative to the frame pointer - so a variable at 4(r4) will always be accessible at 4(r4). So the first line of code is setting the frame pointer. Next, the compiler adds 2 to the frame pointer. In most functions, the first thing you do is push the frame pointer onto the stack via push r4 - main is the exception. Adding two puts the base of the stack frame below this value, which is what we want. Next, the compiler subtracts two from the stack pointer. This is because we're allocating our int variable on the stack, so we're giving it two bytes. If we allocated two ints, the compiler would subtract 4 from the stack pointer. Our first four instructions are identical to our first sample program. We're setting up the frame pointer and allocating our variable on the stack. Next, we're moving our variable into r15. Remember, our ABI says that the first parameter to a function should be passed in through r15 - so we move our there. Next, we call the recursiveSummation subroutine the compiler has created. Once inside the recursiveSummation subroutine, we push the framePointer onto the stack so we don't destroy it. Then, we establish a new frame pointer and allocate a variable on the stack - just like we did in main. Next, the compiler moves the parameter we passed in r15 into the variable we established. It compares the variable to 1. If it's greater than or equal to 1, we jump to .L3 - the label that holds the code in our else case. We move our parameter into r15 (the register that holds the first parameter we pass to functions), subtract one, and call our recursiveSummation subroutine again. This code is the recursiveSummation(numberToSum - 1) piece of our code. The final instruction adds the current parameter to the result passed back in r15. This code is the return numberToSum + piece of our code. If it's less than 1, we're finished. We move 0 into r15, deallocate our variable from the stack, retrieve the frame pointer we pushed initially, and return. If you're interested in learning more, check out this Wikipedia reading on the Call Stack. After we're done, we'll add 2 to the stack pointer to deallocate int variable since we're done using it.