Functions in Hmmm Assembly

Slides:



Advertisements
Similar presentations
Week 8 Stack and Subroutines. Stack  The stack is a section of data memory (or RAM) that is reserved for storage of temporary data  The data may represent.
Advertisements

CPU Review and Programming Models CT101 – Computing Systems.
Chapter 9 TRAP Routines and Subroutines. Copyright © The McGraw-Hill Companies, Inc. Permission required for reproduction or display. 9-2 Subroutines.
ISA Issues; Performance Considerations. Testing / System Verilog: ECE385.
 Suppose for a moment that you were asked to perform a task and were given the following list of instructions to perform:
CPS3340 COMPUTER ARCHITECTURE Fall Semester, /17/2013 Lecture 12: Procedures Instructor: Ashraf Yaseen DEPARTMENT OF MATH & COMPUTER SCIENCE CENTRAL.
Ch. 8 Functions.
EECC250 - Shaaban #1 Lec # 6 Winter Stack-Related Instructions PEA Push Effective Address Calculates an effective address and pushes it.
Functions Functions and Parameters. History A function call needs to save the registers in use The called function will use the registers The registers.
Instruction Set Architecture
CS 536 Spring Code generation I Lecture 20.
CSCE 121, Sec 200, 507, 508 Fall 2010 Prof. Jennifer L. Welch.
Chapter 5 The LC-3 LC-3 Computer Architecture Memory Map
Run-time Environment and Program Organization
Web siteWeb site ExamplesExamples Irvine, Kip R. Assembly Language for Intel-Based Computers, Stack Operations Runtime Stack PUSH Operation POP.
Stacks and Frames Demystified CSCI 3753 Operating Systems Spring 2005 Prof. Rick Han.
Programming Models CT213 – Computing Systems Organization.
Computer Organization CS345 David Monismith Based upon notes by Dr. Bill Siever and notes from the Patterson and Hennessy Text.
Discussion of Assignment 9 1 CSE 2312 Computer Organization and Assembly Language Programming Vassilis Athitsos University of Texas at Arlington.
Today’s topics Parameter passing on the system stack Parameter passing on the system stack Register indirect and base-indexed addressing modes Register.
Microcode Source: Digital Computer Electronics (Malvino and Brown)
Today’s topics Procedures Procedures Passing values to/from procedures Passing values to/from procedures Saving registers Saving registers Documenting.
Prof. Fateman CS 164 Lecture 281 Virtual Machine Structure Lecture 28.
ITCS 3181 Logic and Computer Systems 2015 B. Wilkinson Slides4-2.ppt Modification date: March 23, Procedures Essential ingredient of high level.
Functions. Motivation What is a function? A function is a self-contained unit of program code designed to accomplish a particular task. We already used.
Representation of Data - Instructions Start of the lesson: Open this PowerPoint from the A451 page – Representation of Data/ Instructions How confident.
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson Education, Inc. All rights reserved Recursion,
Computer Organization CS345 David Monismith Based upon notes by Dr. Bill Siever and notes from the Patternson and Hennessy Text.
Computer Science 210 Computer Organization
Function Calls in Assembly MIPS R3000 Language (extensive use of stack) Updated 7/11/2013.
CMSC201 Computer Science I for Majors Lecture 19 – Recursion
Lecture 3 Translation.
Tail Recursion.
Assembly Language Programming of 8085
© Craig Zilles (adapted from slides by Howard Huang)
CSE 341 Lecture 5 efficiency issues; tail recursion; print
CMSC201 Computer Science I for Majors Lecture 18 – Recursion
Run-time organization
CS5 Stylin' !.
Chapter 4 Addressing modes
Chapter 10 And, Finally... The Stack
Microcomputer Programming
CS41B recursion David Kauchak CS 52 – Fall 2015.
Functions and Procedures
Chapter 10 The Stack.
The CS 5 Times Penguin/Pig Gang Fight Brings Violence to Claremont
Hmmm Assembly Language
Sports: HMC CS Professor to coach 2020 U. S
CSCE Fall 2013 Prof. Jennifer L. Welch.
Fundamentals of Programming
CSCE 121: Simple Computer Model Spring 2015
CMSC201 Computer Science I for Majors Lecture 19 – Recursion
The University of Adelaide, School of Computer Science
Instruction encoding We’ve already seen some important aspects of processor design. A datapath contains an ALU, registers and memory. Programmers and compilers.
by Richard P. Paul, 2nd edition, 2000.
von Neumann Architecture CPU
Chapter 6 - Procedures and Macros
Computer Science 210 Computer Organization
CSCE Fall 2012 Prof. Jennifer L. Welch.
Problem: ! bell ! help ! ! 1 ! 2 ! ! Bal help ! ! ! !
Mastering Memory Modes
Problem: ! bell ! help ! ! 1 ! 2 ! ! Bal help ! ! ! !
Yan Shi CS/SE 2630 Lecture Notes
Process.
Some Assembly (Part 2) set.html.
Computer Organization and Assembly Language
Hmmm Assembly Language
© Craig Zilles (adapted from slides by Howard Huang)
Functions in Hmmm Assembly
Functions in Hmmm Assembly
Presentation transcript:

Functions in Hmmm Assembly

Functions in Python vs. assembly r1 = int(input()) r13 = f(r1) print(r13) def f(r1): r13 = r1*(r1-1) return r13 0 read r1 1 calln r14, 4 2 write r13 3 halt 4 copy r13, r1 5 addn r13, -1 6 mul r13,r1,r13 7 jumpr r14 Write a NEW FUNCTION that returns 1 if the input is > 0 and 2 if the input is <= 0

Why Functions? Function is just a block of computation, no real magic. We can use “jumpn” to accomplish the same goal. # computes n*(n-1) without function 0 read r1 jumpn 4 write r13 halt copy r13, r1 addn r13, -1 mul r13,r1,r13 jumpn 2 This program does exactly the same as the function before without function (“calln”). We “hard-coded” the return address “jumpn 2.” But, what if another place in the program needs this part of the computation??? “jumpn 2” will lead to a wrong place! “jumpr r14” (thus function) will be needed!

Hmmm function exercises See the problem set on the course website. Hmmm function exercises

We need to "push" (save) everything that we need to protect: What about recursive functions? We need to "push" (save) everything that we need to protect: x the parameter Every call needs its own copy The return address Calls may occur from different places! So, where do we STORE and LOAD data that we want to protect? x = int(input()) y = fac(x) print(y) def fac(x): if x == 0: return 1 else: res = fac(x-1) return x * res

Functions with storer + loadr Memory ("the stack") fac(3) 3 x, the input x = int(input()) y = fac(x) print(y) def fac(x): if x==0: return 1 else: res = fac(x-1) return x*res ? ret. value main ret. address A "stack frame" stores all of the important data that might get destroyed during a function call (modified by the function called) base case factorial recursive step

Functions with storer + loadr Memory ("the stack") fac(3) 3 x, the input x = int(input()) y = fac(x) print(y) def fac(x): if x==0: return 1 else: res = fac(x-1) return x*res ? ret. value main ret. address THE STACK fac(2) 2 x, the input ? ret. value ret. address base case factorial growing downward Each stack frame stores a potentially different input and return address! recursive step

Functions with storer + loadr Memory ("the stack") fac(3) 3 x, the input x = int(input()) y = fac(x) print(y) def fac(x): if x==0: return 1 else: res = fac(x-1) return x*res ? ret. value main ret. address THE STACK fac(2) 2 x, the input ? ret. value ret. address base case fac(1) 1 x, the input factorial ? ret. value recursive step ret. address growing downward One stack frame per function call

Functions with storer + loadr Memory ("the stack") fac(3) 3 x, the input x = int(input()) y = fac(x) print(y) def fac(x): if x==0: return 1 else: res = fac(x-1) return x*res ? ret. value main ret. address fac(2) 2 x, the input ? ret. value ret. address base case fac(1) 1 x, the input factorial ? ret. value recursive step ret. address fac(0) x, the input 1 Aha! ret. value ret. address

Functions with storer + loadr Memory ("the stack") fac(3) 3 x, the input x = int(input()) y = fac(x) print(y) def fac(x): if x==0: return 1 else: res = fac(x-1) return x*res ? ret. value main ret. address fac(2) 2 x, the input ? ret. value ret. address base case fac(1) 1 x, the input factorial 1 ? ret. value recursive step ret. address this Stack Frame is now gone!

Functions with storer + loadr Memory ("the stack") fac(3) 3 x, the input x = int(input()) y = fac(x) print(y) def fac(x): if x==0: return 1 else: res = fac(x-1) return x*res ? ret. value main ret. address fac(2) 2 x, the input ? ret. value ret. address base case fac(1) 1 x, the input factorial 1 ret. value recursive step ret. address

Functions with storer + loadr Memory ("the stack") fac(3) 3 x, the input x = int(input()) y = fac(x) print(y) def fac(x): if x==0: return 1 else: res = fac(x-1) return x*res ? ret. value main ret. address fac(2) 2 x, the input ? ret. value ret. address base case factorial another Stack Frame is gone 1 recursive step

Functions with storer + loadr Memory ("the stack") fac(3) 3 x, the input x = int(input()) y = fac(x) print(y) def fac(x): if x==0: return 1 else: res = fac(x-1) return x*res ? ret. value main ret. address fac(2) 2 x, the input 2 ret. value ret. address base case factorial recursive step

Functions with storer + loadr Memory ("the stack") fac(3) 3 x, the input x = int(input()) y = fac(x) print(y) def fac(x): if x==0: return 1 else: res = fac(x-1) return x*res ? ret. value main ret. address another Stack Frame is gone base case factorial 2 recursive step

Functions with storer + loadr Memory ("the stack") fac(3) 3 x, the input x = int(input()) y = fac(x) print(y) def fac(x): if x==0: return 1 else: res = fac(x-1) return x*res 6 ret. value main ret. address base case factorial recursive step

6 Functions with storer + loadr The Stack is Empty. x = int(input()) y = fac(x) print(y) def fac(x): if x==0: return 1 else: res = fac(x-1) return x*res The Stack is Empty. 6 main 6 base case factorial recursive step

storer stores TO memory Hmmm RAM Hmmm CPU setn r1 42 r0 1 setn r15 70 42 stores r1 into r15's MEMORY LOCATION (not into r15 itself!) r1 2 storer r1 r15 3 write r0 70 r15 They have it in the handout. Have them step through the code. 4 write r1 points to a location in memory 5 halt storer r1 r15 . 70

loadr loads FROM memory Hmmm CPU Hmmm RAM nop r0 1 setn r15 70 r1 loads data into r1 from r15's MEMORY LOCATION (not r15 itself) 2 loadr r1 r15 3 write r0 70 r15 4 write r1 points to a location in memory 5 halt . loadr r1 r15 70 42

A function example 0 read r1 # Get the "x" for our function 1 setn r15, 70 # Set the stack pointer, (i.e., # load address of stack into r15) 2 storer r1, r15 # Store r1, since f overwrites it 3 calln r14, 7 # Call our function f(x) 4 loadr r1, r15 # Load r1 back in place write r13 # Print result halt # Stop the program 7 addn r1, 1 # Compute f(x) = x + 1 8 copy r13,r1 # Save result into r13 9 jumpr r14 # Finished function, jump back

Are there any difference between instructions and values (numbers)? From computers’ point of view, the memory has separate dedicated area for data and instructions. So the computer knows which piece is data, which piece is instruction. But human beings can’t tell data from instructions just from its form. The program on the previous pages are compiled into machine form in red. 0 : 0110 0000 0000 0000 # 0 nop 1 : 0001 1111 0100 0110 # 1 setn r15, 70 2 : 0100 0001 1111 0000 # 2 loadr r1, r15 3 : 0000 0000 0000 0010 # 3 write r0 4 : 0000 0001 0000 0010 # 4 write r1 5 : 0000 0000 0000 0000 # 5 halt ... 70: 0000 0000 0010 1010 # 70: integer 42

Jumps in Hmmm Unconditional jump Conditional jumps Indirect jump jumpn n # jump to line n (set PC to n) Conditional jumps jeqzn rx n # if reg x == 0, jump to line n jnezn rx n # if reg x != 0, jump to line n jltzn rx n # if reg x < 0, jump to line n jgtzn # if reg x > 0, jump to line n Indirect jump jumpr rx # jump to the value in reg x

Use jump to repeat work In many computational tasks, we need to repeat certain work. For example, count the number of letter ‘c’ in a string (we’ve done this…) In Python, we have ready structures to accomplish this, we can either do it using recursion, or using a loop (we’ll learn Python loop soon.) Let’s first consider how we do it in Hmmm assembly …

What does the following do? Discuss it with your neighbor(s) … 0 read r1 1 setn r3, 0 2 jeqz r1, 6 3 add r3, r3, r1 4 addn r1, -1 5 jumpn 2 6 write r3 7 halt Compute sum = 1 + 2 + 3 + … + n

Functions revisit … Suppose we want to do the summation function many different times. In Python syntax: In Hmmm syntax: def sum(n): if n == 1: return 1 else: return n + sum(n-1) print(sum(10)) print(sum(5)) 0 setn r1, 10 1 calln r14,7 2 write r13 3 setn r1, 5 4 calln r14,7 5 write r13 6 halt # function code … 7 …

Functions revisit We put the code for sum(n) we wrote before into use. The sum program we had before 0 setn r1, 10 1 calln r14,7 2 write r13 3 setn r1, 5 4 calln r14,7 5 write r13 6 halt # function code … 7 … 0 read r1 1 setn r3, 0 2 jeqz r1, 6 3 add r3, r3, r1 4 addn r1, -1 5 jumpn 2 6 write r3 7 halt The code in red can be readily used.

Will this work ? The line numbers must be changed!!! Need to change the result register. 0 setn r1, 10 1 calln r14,7 2 write r13 3 setn r1, 5 4 calln r14,7 5 write r13 6 halt # function code … 7 setn r3, 0 2 jeqz r1, 6 3 add r3, r3, r1 4 addn r1, -1 5 jumpn 2 0 setn r1, 10 1 calln r14,7 2 write r13 3 setn r1, 5 4 calln r14,7 5 write r13 6 halt # function code … 7 setn r13, 0 8 jeqz r1, 6 #??? 9 add r13, r13, r1 10 addn r1, -1 11 jumpn 8 Where should we jump to when finished (Line 8)?

Where to jump? Where should we jump to when finished (Line 8)? 0 setn r1, 10 1 calln r14,7 2 write r13 3 setn r1, 5 4 calln r14,7 5 write r13 6 halt # function code … 7 setn r13, 0 8 jeqz r1, 12 # end 9 add r13, r13, r1 10 addn r1, -1 11 jumpn 8 12 jumpn # 2 or 5???

jumpr The jumpr instruction allows program to jump to an address that is stored in a register, not a fixed number (address). jumpr r14 # jump to the address specified in r14 The value in r14 (or whichever register is used) was set when the function is called with calln.

Now we know 0 setn r1, 10 1 calln r14,7 2 write r13 3 setn r1, 5 6 halt # function code … 7 setn r13, 0 8 jeqz r1, 12 # end 9 add r13, r13, r1 10 addn r1, -1 11 jumpn 8 12 jumpr r14 Run the actual program to show the result.

What if we want to read (or set) the two numbers, n and m, before calling the function? 0 setn r1, 10 1 setn r1, 5 2 calln r14,7 3 write r13 4 calln r14,7 5 write r13 6 halt # function code … 7 setn r13, 0 8 jeqz r1, 12 # end 9 add r13, r13, r1 10 addn r1, -1 11 jumpn 8 12 jumpr r14 The program obviously will generate wrong result!!!! Last time we saw 55 and 15 were printed. What would be printed now? 15 ?????? We need to save certain values when calling functions!!!

How and where to save values? The answer is “stack”! Essentially, set an area of memory where the values can be stored. Save selected values in that area of memory (stack) when function is called. When function is finished, restore these values from the stack. The reason we call it a “stack” is that it “grows” in one direction, “shrinks” when reversing.

Recall the Hmmm architecture 16 registers CPU Registers Random Access Memory (RAM) 0000010100110000 Control Unit ALU 0110100111100001 Program Counter 1011100110001100 00000011 0100000000000111 Instruction Register 0000000000011110 00110100 0000100000010000 Control Processing Unit (CPU) 0000000000000001 256 memory units

Use a portion of memory for stack A stack pointer register specifies where in memory is the beginning of the stack. Random Access Memory (RAM) Mem address 255 … Stack pointer register, e.g., r15 99 99 … r15 2 Which means the stack starts at address 99 1 256 memory units

Now let’s go back to the function call 0 setn r1, 10 1 setn r2, 5 2 setn r15,99 # stack pointer 3 calln r14,9 # r14 contains the value 4 after calln 4 write r13 5 copy r1, r2 # function takes r1 as parameter! 6 calln r14,9 # r14 contains the value 7 after calln 7 write r13 8 halt # function code … 9 addn r15, -1 # stack grows downwards # store value of r1 to memory specified by r15 10 storer r1, r15 11 setn r13, 0 # initialize result 12 jeqz r1, 16 # if n == 0, finished 13 add r13, r13, r1 # add n to the sum 14 addn r1, -1 # decrement n by 1 15 jumpn 12 # repeat 16 loadr r1, r15 # restore r1 17 addn r15, 1 # pop stack 18 jumpr r14

What if we need to call another function? Our original program New requirement def sum(n): total = 0 for (i in range(n+1)): total = total + i return total n = 10 m = 5 s = sum(n) print(s) s = sum(m) def sum(n): total = 0 for (i in range(n+1)): total = total + i write_partial(total, i) return total n = 10 m = 5 s = sum(n) print(s) s = sum(m)

New requirement def write_partial(i, p): print(i) print(p) def sum(n): total = 0 for (i in range(n+1)): total = total + i write_partial(i, total) return total n = 10 m = 5 s = sum(n) print(s) s = sum(m)

Hmmm version 0 setn r1, 10 1 setn r2, 5 2 setn r15,99 # stack pointer 3 calln r14,9 # r14 contains the value 4 after calln 4 write r13 5 copy r1, r2 # function takes r1 as parameter! 6 calln r14,9 # r14 contains the value 7 after calln 7 write r13 8 halt # function code … 9 addn r15, -1 # stack grows downwards # store value of r1 to memory specified by r15 10 storer r1, r15 11 setn r13, 0 # initialize result 12 jeqz r1, 16 # if n == 0, finished 13 add r13, r13, r1 # add n to the sum 14 calln r14, 22 # call the write_partial function 15 addn r1, -1 # decrement n by 1 16 jumpn 12 # repeat 17 loadr r1, r15 # restore r1 18 addn r15, 1 # pop stack 19 jumpr r14

The “write_partial” function # function write_partial 22 write r1 # first parameter in r1, i 23 write r2 # second parameter in r2, total 24 jumpr r14 # return to the calling function This code looks decent, but we have two issues We didn’t quite set the parameters r1 and r2 When the function returns using jumpr r14 on line 24, where does it jump to?

Setting up r1 and r2 # function write_partial 22 write r1 # first parameter in r1, i 23 write r2 # second parameter in r2, total 24 jumpr r14 # return to the calling function This issue is slightly easier to resolve. In real assembly program, you’d have to save all parameters. Here we take a bit “short-cut.” We changed the r2 in main program to be r3 (Line 1), and copy r13 to r2 (Line 13, before calln r14, 22).

Setting up r1 and r2 0 setn r1, 10 1 setn r3, 5 2 setn r15,99 # stack pointer 3 calln r14,9 # r14 contains the value 4 after calln 4 write r13 5 copy r1, r3 # function takes r1 as parameter! 6 calln r14,9 # r14 contains the value 7 after calln 7 write r13 8 halt # function code … 9 addn r15, -1 # stack grows downwards # store value of r1 to memory specified by r15 …… 13 add r13, r13, r1 # add n to the sum 14 copy r2, r13 # copy partial total to r2 15 calln r14, 22 # call the write_partial function 16 addn r1, -1 # decrement n by 1

Where do we return in write_partial? The second issue, where do we return after write_partial, is bit more challenge! As it is, what is the value in r14? # function write_partial 22 write r1 # first parameter in r1, i 23 write r2 # second parameter in r2, total 24 jumpr r14 # return to the calling function r14 == 16. The line right after calln r14, 22. This is correct. But when the function sum() completes at Line 19 (Slide 37), what is the value r14? Still 16!!! We’d jump to a wrong place.

Save return address! When making a function call, the programmer must save the return address, typically r14 in memory (stack), so the program returns to the correct place. A typical pattern is listed below. Note that it is most likely other parameters have to be saved as well in a similar fashion. … n addn r15, -1 # increase stack space n+1 storer r14, r15 # store r14 in mem(r15) n+2 calln r14, x # call function at x n+3 loadr r14, r15 # restore r14 n+4 addn r15, 1 # pop the stack

Revised, complete program (1) 0 setn r1, 10 1 setn r3, 5 2 setn r15,99 # stack pointer 3 calln r14,9 # r14 contains the value 4 after calln 4 write r13 5 copy r1, r3 # function takes r1 as parameter! 6 calln r14,9 # r14 contains the value 7 after calln 7 write r13 8 halt # function code … 9 addn r15, -1 # stack grows downwards # store value of r1 to memory specified by r15 10 storer r1, r15 11 setn r13, 0 # initialize result 12 jeqz r1, 24 # if n == 0, finished 13 add r13, r13, r1 # add n to the sum 14 copy r2, r13 # copy the 2nd parameter, first is in r1 15 addn r15, -1 # increment stack pointer 16 storer r14, r15 # save return address 17 calln r14, 30 # call the write_partial function 18 loadr r14, r15 # restore return address 19 addn r15, 1 # pop stack

Revised, complete program (2) 20 addn r1, -1 # decrement n by 1 21 jumpn 12 # repeat 22 loadr r1, r15 # restore r1 23 addn r15, 1 # pop stack 24 jumpr r14 25 nop 26 nop 27 nop 28 nop 29 nop # function write_partial 30 write r1 # first parameter in r1, i 31 write r2 # second parameter in r2, total 32 jumpr r14 # return to the calling function Demonstrate the program (nested_func.hmmm). This program has the storer/loadr pair within the loop. This is very inefficient. Try to move the pair outside loop. (Your exercise.)