SimpleFunction stack questions

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

SimpleFunction stack questions

gs99
I find several definitions of a function stack.
S1. Figure 8.4 page 162.
S2. Figure 8.5 page 163.
S3. A forum post refers to SimpleFunction:
“The script then sets up a stack frame as if SimpleFunction had been called.”
“In the case of the CPU Emulator test, SimpleFunction returns to 1000.”
http://nand2tetris-questions-and-answers-forum.32033.n3.nabble.com/error-in-SimpleFunction-test-scripts-td977524.html

SimpleFunction.tst file includes:
set RAM[0] 317,
set RAM[1] 317,
set RAM[2] 310,
set RAM[3] 3000,
set RAM[4] 4000,
set RAM[310] 1234,
set RAM[311] 37,
set RAM[312] 1000,
set RAM[313] 305,
set RAM[314] 300,
set RAM[315] 3010,
set RAM[316] 4010,

Q1. How is RAM[312] in this case designated to have the return address 1000?

Q2. How can I relate the “stack frame” set up by SimpleFunction.tst to what is described in Figure 8.4 “the global stack structure”? Which parts of the .tst file settings are identified as the four parts in that picture? Are the four parts not to be done in the sequence shown in Figure 8.4?

Q3. Section 8.3.1: “Each time a function is called, a new block is added to the global stack. The block consists of…”
Is “block” here the same as “frame”?

Q4. What significance (if any) is there to the various settings in SimpleFunction? Which ones are important for this project?
Reply | Threaded
Open this post in threaded view
|

Re: SimpleFunction stack questions

ybakos
gs99 wrote
Q1. How is RAM[312] in this case designated to have the return address 1000?
By design. Look at the visual picture of the stack frame in the lecture slides (slide 17). The test script is setting the stack pointer to 317, LCL to 317, ARG to 310, THIS to 3000, and THAT to 4000. Note how ARG points to address 310, and notice how the next set command sets address 310 to 1234, and 311 to 37. These are the values of the two arguments passed to the function.

After the args on the stack come the "bookkeeping" information: the previous values of LCL, ARG, THIS, THAT, and the return address. Look at slide 17 again. What is the first element of bookkeeping information? The return address. This is why it is stored in 312.

gs99 wrote
Q2. How can I relate the “stack frame” set up by SimpleFunction.tst to what is described in Figure 8.4 “the global stack structure”? Which parts of the .tst file settings are identified as the four parts in that picture? Are the four parts not to be done in the sequence shown in Figure 8.4?
Not to be flippant, but I think if you stare at the diagram on slide 17 and the lines set RAM[310] ... set RAM[316] a little longer, you'll get it.

gs99 wrote
Q3. Section 8.3.1: “Each time a function is called, a new block is added to the global stack. The block consists of…”
Is “block” here the same as “frame”?
Put simply, yes.

gs99 wrote
Q4. What significance (if any) is there to the various settings in SimpleFunction? Which ones are important for this project?
Don't get too carried away with the test script itself; rather, look at the vm instructions themselves, the call-return protocol (it's very explicit in the book) and think about how scope and function calls must work when you're programming in a high level language.

Keep it up! Once you get this, local scope, how functions "receive" their arguments, and and how function calling works will no longer be mysteries.
Reply | Threaded
Open this post in threaded view
|

Re: SimpleFunction stack questions

gs99
ybakos wrote
By design. Look at the visual picture of the stack frame in the lecture slides (slide 17).
Thanks for your reply. Please clarify "lecture slides".
Reply | Threaded
Open this post in threaded view
|

Re: SimpleFunction stack questions

cadet1620
Administrator
This post was updated on .
The lecture slides for the Nand2Tetris course can be found on the Course Page. The link to each chapter's slides is the Adobe PDF icon in the "lecture" column.

--Mark
Reply | Threaded
Open this post in threaded view
|

Re: SimpleFunction stack questions

gs99
In reply to this post by gs99
Figure 8.4 shows the four parts of a new stack as explained in Section 8.3.1:
.1- Arguments for called function
.2- Pointers to save state of calling function
.3- Local variables of called function
.4- Working stack for called function
When Mark said “The script then sets up a stack frame as if SimpleFunction had been called.”
I expected that stack frame to resemble what is presented in Figure 8.4.

Look at this from the standpoint of someone learning it for the first time.  
Is Figure 8.4 not showing a stack frame as a section of RAM with values starting with argument 0 in the lowest address and SP in the highest address?

Compare with FibonacciElement Sys.vm:
function Sys.init 0
push constant 4
call Main.fibonacci 1   // Compute the 4'th fibonacci element

The  script sets SP to 261.
Push constant 4 to 261.
Return-address 24 is pushed to 262.
LCL is pushed to 263.
ARG is pushed to 264.
THIS is pushed to 265.
THAT is pushed to 266.
SP is 267.

This action appears much closer to Figure 8.4 than what I see in SimpleFunction.

Although I have 2 questions:
Q1. Where does VM Emulator get address 24?
Q2. Does this function not have local variables? When would this part of the new stack (“local variables of the current function”) have any data?
 
For a simple introduction to functions, why doesn’t SimpleFunction follow the organization shown in Figure 8.4?
It would be something like this, starting with SP = 261:
Part 1
set RAM[261] 1234, // first arg
set RAM[262] 37, // second arg

Part 2
set RAM[263] 999, // return-address; whatever
set RAM[264] 0, // LCL
set RAM[265] 0, // ARG
set RAM[266] 0, // THIS
set RAM[267] 0, // THAT

Part 3
(empty)

Part 4
SP is 268

To me, SimpleFunction is not a good demo of what the book explains.  

ps. I found slide 17. It seems to be the same information as in Figure 8.4, correct?
Reply | Threaded
Open this post in threaded view
|

Re: SimpleFunction stack questions

cadet1620
Administrator
gs99 wrote
Although I have 2 questions:
Q1. Where does VM Emulator get address 24?
Q2. Does this function not have local variables? When would this part of the new stack (“local variables of the current function”) have any data?
Since the VM emulator does not generate machine code it cannot use a ROM address as the RIP. It uses some arbitrary number that means something to the emulator but has no relationship to assembly language code generated by a VM translator.

Local variables are the result of var statements in Jack programs. It's quite possible for a function to require no local variables.
 
For a simple introduction to functions, why doesn’t SimpleFunction follow the organization shown in Figure 8.4?
It would be something like this, starting with SP = 261:
Part 1
set RAM[261] 1234, // first arg
set RAM[262] 37, // second arg

Part 2
set RAM[263] 999, // return-address; whatever
set RAM[264] 0, // LCL
set RAM[265] 0, // ARG
set RAM[266] 0, // THIS
set RAM[267] 0, // THAT

Part 3
(empty)

Part 4
SP is 268
How is this any different from the setup in the SimpleFunction test file, other than the completely arbitrary location of the stack frame, and values of LCL, ARG, THIS and THAT. Having these values all 0 implies that there was NO previous stack frame, which would not be the case if SimpleFunction was called from another function.

The values in the SimpleFunction test file imply that there is a preceding stack frame that begins at 300, has no arguments, and does have 5 local variables allocated starting at 305.

--Mark

Reply | Threaded
Open this post in threaded view
|

Re: SimpleFunction stack questions

gs99
Thanks for providing information I did not find in the book.
My starting SP 261 was based on the example from FibonacciElement. I assumed that SimpleFunction would also be the initial function (simple?).

If I understand correctly, the previous stack frame would be (in terms of Figure 8.4 parts):
P1. ARG – none
See Note(vacant) below.

P2. Saved state of calling function
300 return address  
301 saved LCL
302 saved ARG
303 saved THIS
304 saved THAT

P3. LCL
305 local 0
306 local 1
307 local 2
308 local 3
309 local 4

P4. SP
310

Is that correct?

According to Figure 8.5, the following should occur to emulate a “call SimpleFunction x”:
(Note : How is it known how many arguments are to be passed to this function?
SimpleFunction.vm has “function SimpleFunction.test 2” which indicates there are 2 local variables.)

310 push local 0 (first argument, value 1234: could be from any local variable)
311 push local 1 (second argument, value 37: same)
312 push return-address
313 push saved LCL
314 push saved ARG
315 push saved THIS
316 push saved THAT
317 SP
Reposition ARG to 310
Reposition LCL to SP  317
Goto SimpleFunction.test
(return-address)

So then, I expected to see this in the SimpleFunction.tst file - in this sequence - to reflect what is taught in the book (give the student a break...):

<1> push arguments
set RAM[310] 1234,  
set RAM[311] 37,  
<2> push return-address>
set RAM[312] 1000,
<3> push other saved state  
set RAM[313] 305,  
set RAM[314] 300,
set RAM[315] 0,  
set RAM[316] 0,  
<new SP> 
set RAM[0] 317,

<reposition>
set RAM[2] 310, // ARG
set RAM[1] 317, // LCL

Isn’t that all that’s needed?

What’s the basis for setting these values for THIS and THAT?
set RAM[3] 3000,
set RAM[4] 4000,
set RAM[315] 3010,
set RAM[316] 4010,

Note(vacant): Section 8.3.1 and Figure 8.4 (pp. 161, 162) present four parts of the stack frame, not mentioning the possibility that some parts may be missing at times (ARG and LCL). When calling SimpleFunction, the calling function has no arguments so address 300 is used for the saved state of ARG. I haven’t worked out examples, but isn’t that risky – saying that the same address value refers to 2 different things upon return (ARG and return-address)?  

I had skipped ahead to FibonacciElement to get an overview. It provides a much simpler scenario in which function Sys.init calls another function. No previous stack frame; all saved state (LCL –THAT) = 0. Isn’t that an easier introduction to calling a function?
   
Reply | Threaded
Open this post in threaded view
|

Re: SimpleFunction stack questions

cadet1620
Administrator
gs99 wrote
Thanks for providing information I did not find in the book.
My starting SP 261 was based on the example from FibonacciElement. I assumed that SimpleFunction would also be the initial function (simple?).

If I understand correctly, the previous stack frame would be (in terms of Figure 8.4 parts):
P1. ARG – none
See Note(vacant) below.

P2. Saved state of calling function
300 return address  
301 saved LCL
302 saved ARG
303 saved THIS
304 saved THAT

P3. LCL
305 local 0
306 local 1
307 local 2
308 local 3
309 local 4

P4. SP
310

Is that correct?
Yes, that is correct.
According to Figure 8.5, the following should occur to emulate a “call SimpleFunction x”:
(Note : How is it known how many arguments are to be passed to this function?
The x value is the number of arguments.  The compiler that generated the vm code knows the number of arguments that it pushed onto the stack.
What’s the basis for setting these values for THIS and THAT?
set RAM[3] 3000,
set RAM[4] 4000,
set RAM[315] 3010,
set RAM[316] 4010,
Arbitrary, probably came from the setup for some other test program.

Don't read too much into the test setups. Test setups need to be sufficient to run the test; the do not need to be minimally sufficient.

In a test scenario like this, one advantage of having different, non-zero, values in every "arbitrary value" location in the stack frame in that it aids detection of reads from wrong addresses.
Note(vacant): Section 8.3.1 and Figure 8.4 (pp. 161, 162) present four parts of the stack frame, not mentioning the possibility that some parts may be missing at times (ARG and LCL). When calling SimpleFunction, the calling function has no arguments so address 300 is used for the saved state of ARG. I haven’t worked out examples, but isn’t that risky – saying that the same address value refers to 2 different things upon return (ARG and return-address)?  
It might help to think of the segments always being present, but they sometimes have 0 length.

If a computer has more registers available, then one of those registers can be designated to hold function return values. Since the Hack computer only has the A and D registers, which are very busy during stack manipulations, the return value must be somewhere else. For instance, REG15 could have been designated to hold return values. Making a change like that would have far reaching implications, in particular to the code generated by the compiler.

The way the return value is currently handled is tricky, but not risky.

--Mark