Can't get the same output with the .cmp file.

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

Can't get the same output with the .cmp file.

Henoktes722
This post was updated on .
All tests except nested call passed.

As you recommended in return command, I store FRAME at temp, memory address 5 and RET at temp + 1 which is at memory address 6. Let me know if this is not correct?

NestedCall.cmp
| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] | RAM[5] | RAM[6] |
|    261   |    261   |    256    |   4000  |   5000   |    135   |    246   |

My vm translator test output, NestedCall.out
| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] | RAM[5] | RAM[6] |
|    261   |    261   |    256    |   4000  |   5000   |    266   |    246   |
 
As you can see here, my output differs from the expected in one filed, RAM[5].

I did all the instructions in a paper and I got the same result with mine.

Snippet from the vm instructions.
"
....
call Sys.add12 1
pop temp 0
...
return
"

So when Sys.add12 returns it return a value of 135, then the instruction pop temp 0 executed and assigns a value 135 at RAM[5] as in your NestedCall.cmp. But when return command is executed it re assign the value of LCL to FRAME, which means RAM[5] or FRAME is overwritten and holds a value of the current LCL which is 266 in my case.
Reply | Threaded
Open this post in threaded view
|

Re: Can't get the same output with the .cmp file.

WBahn
Administrator
Henoktes722 wrote
All tests except nested call passed.

As you recommended in return command, I store FRAME at temp, memory address 5 and RET at temp + 1 which is at memory address 6. Let me know if this is not correct?
The temp memory segment is not for VM use, it is for compiler use. The VM has registers R13, R14, and R15 for its use. Since the compiler can only generate VM commands, it can easily use the temp memory segment, but using those three registers requires trickery.

That may or may not be your problem in what you are seeing now, but there's no point looking further until this issue is fixed.
Reply | Threaded
Open this post in threaded view
|

Re: Can't get the same output with the .cmp file.

Henoktes722
Okay, so I won't use Temp for FRAME and RET instead I'll use M[13] and M[14] for FRAME and RET respectively. Can you tell me the trick thing?

On Sun, Sep 1, 2019, 5:42 PM WBahn [via Nand2Tetris Questions and Answers Forum] <[hidden email]> wrote:
Henoktes722 wrote
All tests except nested call passed.

As you recommended in return command, I store FRAME at temp, memory address 5 and RET at temp + 1 which is at memory address 6. Let me know if this is not correct?
The temp memory segment is not for VM use, it is for compiler use. The VM has registers R13, R14, and R15 for its use. Since the compiler can only generate VM commands, it can easily use the temp memory segment, but using those three registers requires trickery.

That may or may not be your problem in what you are seeing now, but there's no point looking further until this issue is fixed.


To unsubscribe from Can't get the same output with the .cmp file., click here.
NAML
Reply | Threaded
Open this post in threaded view
|

Re: Can't get the same output with the .cmp file.

Henoktes722
This post was updated on .
In reply to this post by WBahn
Finally, I found optimized code for return command. And as you said I didn't use TEMP[5-12] for my temporary variables like FRAME and RET in return, they are only used for operations in a temp segment.

My first assumption was correct, but when I see the text for FRAME=LCL in figure 8.5, It says FRAME is a temporary variable. So I decided to store it in TEMP which is not correct. So please change that description since it makes students uncertain.

Thanks! All tests passed after 3 days. I highly recommend to add description to the writeIf api, when I wrote the translator first I implement api writeIf like this one

// decrement stack pointer
@SP
M=M-1

// get top of the stack
@SP
A=M
D=M

// jump to label, which is the first argument of if-goto command
@{Label}
D;JGT

But this code has a logical error, and I spent literally a day to debug the error. So the error was if-goto command is not always jump to label on greater than 0 or JGT. It may also jump to the label on Less than, which is in Logical commands. Because in logical command true is all bits 1, value of -1, so if the previous command is logical like eq, gt and lt if-goto must jump on less than.

Here is my modified api and its implementation in typescript

  writeIf(label: string, wasPrevCommandLogical: boolean) {
    let assm: string = this.decSP();
    assm += this.getTop("D");
    assm += `@${label}\nD;${wasPrevCommandLogical ? "JLT" : "JGT"}\n`;

    return assm;
  }

Reply | Threaded
Open this post in threaded view
|

Re: Can't get the same output with the .cmp file.

WBahn
Administrator
Henoktes722 wrote
Finally, I found optimized code for return command.
You're actually cheating yourself out of some really valuable learning if you are going out and finding code that someone else wrote before getting code that you wrote at least working first. But to each their own.

And as you said I didn't use TEMP[5-12] for my temporary variables like FRAME and RET in return, they are only used for operations in a temp segment.

My first assumption was correct, but when I see the text for FRAME=LCL in figure 8.5, It says FRAME is a temporary variable. So I decided to store it in TEMP which is not correct. So please change that description since it makes students uncertain.
You'll have to take that up with the authors, but they were actually pretty explicit. They stated that the temp memory segment is for use by any VM function for any purpose and that it is shared by all functions in the program. They also stated that RAM[13-15] can be used by the VM implementation as general-purpose registers.

Thanks! All tests passed after 3 days. I highly recommend to add description to the writeIf api, when I wrote the translator first I implement api writeIf like this one
Are we shifting gears and talking about something else now? Or are we still talking about returning from a VM function call? It looks like now you are talking about implementing the if-goto command.

// decrement stack pointer
@SP
M=M-1

// get top of the stack
@SP
A=M
D=M
You will want to really work on tightening things up. Yes, what is by far most important is getting something that works correctly, but you also want to try to minimize the amount of code needed to do something. Keep in mind that most of the VM commands will get executed over and over and over in a typical program, so trimming out even a single instruction can make a noticeable difference, both in terms of program execution and also program size.

Your code above uses five instructions to pop the top of the stack into the D register (something that is going to need to be done a lot by a number of instructions). Consider the following:

@SP
AM = M-1
D = M

That's only three instructions. Notice the trick that exploits the ability of the Hack to write to multiple destinations at the same time (something most processors can't do).
// jump to label, which is the first argument of if-goto command
@{Label}
D;JGT
Look at the specifications for this command: "if the value is not zero, execution continues from the location marked by the label." This is in keeping with the general definition that a zero is treated as false (so don't jump in this case) while ANYTHING else is a true.

But this code has a logical error, and I spent literally a day to debug the error. So the error was if-goto command is not always jump to label on greater than 0 or JGT. It may also jump to the label on Less than, which is in Logical commands. Because in logical command true is all bits 1, value of -1, so if the previous command is logical like eq, gt and lt if-goto must jump on less than.

Here is my modified api and its implementation in typescript

  writeIf(label: string, wasPrevCommandLogical: boolean) {
    let assm: string = this.decSP();
    assm += this.getTop("D");
    assm += `@${label}\nD;${wasPrevCommandLogical ? "JLT" : "JGT"}\n`;

    return assm;
  }
It has NOTHING to do with whether the previous command was a logical command or not. The specification is quite specific and is completely independent of how the value on the top of the stack got there. If the value on the top of the stack IS NOT ZERO, then take the jump. It doesn't matter if the value on the stack is +385 or -812, the jump is to be take in either case. The ONLY time that the jump is not take is if the value on the top of the stack is EXACTLY zero.
Reply | Threaded
Open this post in threaded view
|

Re: Can't get the same output with the .cmp file.

Henoktes722
This post was updated on .
No I didn't cheat any code. I got the optimized code when I check my code, which was not working.

That is great optimization, writing to multiple destination in a single command is great for optimization. But I had an experience  on x86 which is not allowing writing to multiple destination at a time, anyways, I'll try to update the code.  NestedCall.asm refactor from 700 asm instructions to 600 instructions by only using your refactor method.

So you are saying that, this type of instruction is not present in the vm code.

push constant 1
push constant 4
sub
if-goto IF_TRUE

Here top of the stack for if-goto command is -3, so in your case it is not equal to 0 then, the code jumps to IF_TRUE, is that true???
Reply | Threaded
Open this post in threaded view
|

Re: Can't get the same output with the .cmp file.

WBahn
Administrator
Henoktes722 wrote
That is great optimization, writing to multiple destination in a single command is great for optimization. But I had an experience  on x86 which is not allowing writing to multiple destination at a time, anyways, I'll try to update the code.  NestedCall.asm refactor from 700 asm instructions to 600 instructions by only using your refactor method.
This is the power of targeted optimization. Identify structures that are used frequently and put effort into optimizing them first and foremost. Fortunately, most of the VM commands qualify because they are highly foundational to everything that run on top of them.

So you are saying that, this type of instruction is not present in the vm code.

push constant 1
push constant 4
sub
if-goto IF_TRUE

Here top of the stack for if-goto command is -3, so in your case it is not equal to 0 then, the code jumps to IF_TRUE, is that true???
Sure. Since -3 is not zero and zero is the ONLY value that is treated as a logical false, then -3 is a logical true and it should take the jump. This is exactly the same behavior as in C and many other languages.

Reply | Threaded
Open this post in threaded view
|

Re: Can't get the same output with the .cmp file.

Henoktes722
Okay I see. I don't know what makes me vague, this is patently correct.

Yeah I took a course on C programming.  And I use this type of conditional logic.

if(n) { }

and the code inside the if block executes if n is not equal to 0, which is false in C.