Nested call output is incorrect, most likely because of pointer scew

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

Nested call output is incorrect, most likely because of pointer scew

fishboy1887
This post was updated on .
When testing my generated ASM code for NestedCall, it has the correct output right up until "call Sys.main 0" is executed. Specifically the output is all correct (everything is pushed onto the stack correctly and ARG/LCL are correctly repositioned) until writeCall jumps to Sys.main. When it jumps to Sys.main the SP value becomes 271 when it should be 266, by stepping through this I can see it happens when the SP is incremented each time 0 is pushed onto the stack nVars times (which in this particular instance it is 5).



The RAM segments in the stack are correct as well:



Becuase it is 5 more than 266 I am assuming this has something to do with pointer skew. What I am finding really confusing is my ASM code is correct for writeCall as well as writeFunction. For instance my code for "function Sys.main 5" is this:

 // ------------------------- writeFunction ---------------------
(Sys.Sys.main)
@SP
A=M
M=0
@SP
M=M+1
@SP
A=M
M=0
@SP
M=M+1
@SP
A=M
M=0
@SP
M=M+1
@SP
A=M
M=0
@SP
M=M+1
@SP
A=M
M=0
@SP
M=M+1
 // ------------------------- writeFunction ---------------------

As you can see, it has correctly pushed 5 onto the stack 5 times. My code for write call as mentioned before appears to be correct, as SP is 266 (the correct value) right up until the goto f:

// -------------------- writeCall -------------------
@Sys.Sys.main$ret.0
D=A
@SP
A=M
M=D
@SP
M=M+1
@LCL
D=M
@SP
A=M
M=D
@SP
M=M+1
@ARG
D=M
@SP
A=M
M=D
@SP
M=M+1
@THIS
D=M
@SP
A=M
M=D
@SP
M=M+1
@THAT
D=M
@SP
A=M
M=D
@SP
M=M+1
@SP
D=M
@5
D=D-A
@ARG
M=D
@SP
D=M
@LCL
M=D
@Sys.Sys.main
// -------------------- writeCall -------------------
0;JMP
(Sys.Sys.main$ret.0)

I am really not sure what to do at this point, but my assumption is that writeCall is most likely incorrect. If it would be possible, could I email someone my code, or could someone take a look at the repository so they can see if I have realised the methods correctly? This is my code for writeCall (C++):

void CodeWriter::writeCall(const std::string &functionName, const int &nVars) {
    // writeDebugMarker();
    static int runningInt = 0;
    std::string returnLabel = currentFileName + "." + functionName + "$ret." + std::to_string(runningInt);
    std::string push =
        "@SP\n"
        "A=M\n"
        "M=D\n"
        "@SP\n"
        "M=M+1\n";
    std::string writeCallASM =  
        "// -------------------- writeCall -------------------\n"
        "@" + returnLabel + "\n"
        "D=A\n" + push +
        "@LCL\n"
        "D=M\n" + push +
        "@ARG\n"
        "D=M\n" + push +
        "@THIS\n"
        "D=M\n" + push +
        "@THAT\n"
        "D=M\n" + push +
        // ARG = SP - 5 - nArgs
        "@SP\n"
        "D=M\n"
        "@" + std::to_string(nVars + 5) + "\n"
        "D=D-A\n"
        "@ARG\n"
        "M=D\n"
        // LCL = SP
        "@SP\n"
        "D=M\n"
        "@LCL\n"
        "M=D\n"
        // goto f
        "@" + currentFileName + "." + functionName + "\n"
        "// -------------------- writeCall -------------------\n"
        "0;JMP\n"
        "(" + returnLabel + ")\n";
    asmFile << writeCallASM << std::endl;
    runningInt++;
}

And this is my code for writeFunction:

void CodeWriter::writeFunction(const std::string &functionName, const int &nVars) {
    // writeDebugMarker();
    currentFuncName = functionName;
    std::string writeFunctionASM =
        " // ------------------------- writeFunction ---------------------\n"
        "(" + currentFileName + "." + functionName + ")\n";
    for (int i = 0; i < nVars; i++) {
        writeFunctionASM +=
            "@SP\n"
            "A=M\n"
            "M=0\n"
            "@SP\n"
            "M=M+1\n";
    }
    writeFunctionASM +=
        " // ------------------------- writeFunction ---------------------\n";

    asmFile << writeFunctionASM << std::endl;
}

For reference, this is the .out file with comp failure on line 2:

| RAM[0] | RAM[1] | RAM[2] | RAM[3] | RAM[4] | RAM[5] | RAM[6] |
|    261 |    261 |    256 |   4000 |   5000 |    246 |     -1 |
Reply | Threaded
Open this post in threaded view
|

Re: Nested call output is incorrect, most likely because of pointer scew

pm100
Note that the argument to  writeCall is nargs not nvars. Its the number of arguments (0 for Sys.main) not 5 which is the number of locals. Having said that you seem to have generated the correct code value % in this case. Although tis very suspicious that  you are out by 5.

My code is slightly different because I made a common call and return 'function' because that code is so large. I am still working through it comparing to yours.
Reply | Threaded
Open this post in threaded view
|

Re: Nested call output is incorrect, most likely because of pointer scew

fishboy1887
Thanks for the quick reply, I appreciate you helping me. I just changed it to nArgs for writeCall, but regardless and similar to what you said, it does not have an effect on the functionality, it is just the name of the paramater.
Reply | Threaded
Open this post in threaded view
|

Re: Nested call output is incorrect, most likely because of pointer scew

pm100
I tried to email my workong code to you from here. gmail rejected it, so I will post it here.

Note the common call and return code at the end. The return is always the same, the call required 3 things to be loaded before its called

D ->  return address
R13 -> arg count
R14 -> call address



// function Sys.init 0
(Sys.init)
// push constant 4000
@4000
D=A
@SP
A=M
M=D
@SP
M=M+1
// pop pointer 0
@SP
M=M-1
A=M
D=M
@3
M=D
// push constant 5000
@5000
D=A
@SP
A=M
M=D
@SP
M=M+1
// pop pointer 1
@SP
M=M-1
A=M
D=M
@4
M=D
// call Sys.main 0
@0
D=A
@R13
M=D
@Sys.main
D=A
@R14
M=D
@L_Sys_1
D=A
@FW__CALL
0;JMP
(L_Sys_1)
// pop temp 1
@SP
M=M-1
A=M
D=M
@6
M=D
// label LOOP
(Sys.Sys.init$LOOP)
// goto LOOP
@Sys.Sys.init$LOOP
0;JMP
// function Sys.main 5
(Sys.main)
@0
D=A
@SP
A=M
M=D
@SP
M=M+1
@0
D=A
@SP
A=M
M=D
@SP
M=M+1
@0
D=A
@SP
A=M
M=D
@SP
M=M+1
@0
D=A
@SP
A=M
M=D
@SP
M=M+1
@0
D=A
@SP
A=M
M=D
@SP
M=M+1
// push constant 4001
@4001
D=A
@SP
A=M
M=D
@SP
M=M+1
// pop pointer 0
@SP
M=M-1
A=M
D=M
@3
M=D
// push constant 5001
@5001
D=A
@SP
A=M
M=D
@SP
M=M+1
// pop pointer 1
@SP
M=M-1
A=M
D=M
@4
M=D
// push constant 200
@200
D=A
@SP
A=M
M=D
@SP
M=M+1
// pop local 1
@1
D=M
@1
D=D+A
@R13
M=D
@SP
M=M-1
A=M
D=M
@R13
A=M
M=D
// push constant 40
@40
D=A
@SP
A=M
M=D
@SP
M=M+1
// pop local 2
@1
D=M
@2
D=D+A
@R13
M=D
@SP
M=M-1
A=M
D=M
@R13
A=M
M=D
// push constant 6
@6
D=A
@SP
A=M
M=D
@SP
M=M+1
// pop local 3
@1
D=M
@3
D=D+A
@R13
M=D
@SP
M=M-1
A=M
D=M
@R13
A=M
M=D
// push constant 123
@123
D=A
@SP
A=M
M=D
@SP
M=M+1
// call Sys.add12 1
@1
D=A
@R13
M=D
@Sys.add12
D=A
@R14
M=D
@L_Sys_2
D=A
@FW__CALL
0;JMP
(L_Sys_2)
// pop temp 0
@SP
M=M-1
A=M
D=M
@5
M=D
// push local 0
@1
D=M
@0
A=D+A
D=M
@SP
A=M
M=D
@SP
M=M+1
// push local 1
@1
D=M
@1
A=D+A
D=M
@SP
A=M
M=D
@SP
M=M+1
// push local 2
@1
D=M
@2
A=D+A
D=M
@SP
A=M
M=D
@SP
M=M+1
// push local 3
@1
D=M
@3
A=D+A
D=M
@SP
A=M
M=D
@SP
M=M+1
// push local 4
@1
D=M
@4
A=D+A
D=M
@SP
A=M
M=D
@SP
M=M+1
// add
@SP
M=M-1
A=M
D=M
@SP
M=M-1
A=M
M=D+M
@SP
M=M+1
// add
@SP
M=M-1
A=M
D=M
@SP
M=M-1
A=M
M=D+M
@SP
M=M+1
// add
@SP
M=M-1
A=M
D=M
@SP
M=M-1
A=M
M=D+M
@SP
M=M+1
// add
@SP
M=M-1
A=M
D=M
@SP
M=M-1
A=M
M=D+M
@SP
M=M+1
// return
@FW__RETURN
0;JMP
// function Sys.add12 0
(Sys.add12)
// push constant 4002
@4002
D=A
@SP
A=M
M=D
@SP
M=M+1
// pop pointer 0
@SP
M=M-1
A=M
D=M
@3
M=D
// push constant 5002
@5002
D=A
@SP
A=M
M=D
@SP
M=M+1
// pop pointer 1
@SP
M=M-1
A=M
D=M
@4
M=D
// push argument 0
@2
D=M
@0
A=D+A
D=M
@SP
A=M
M=D
@SP
M=M+1
// push constant 12
@12
D=A
@SP
A=M
M=D
@SP
M=M+1
// add
@SP
M=M-1
A=M
D=M
@SP
M=M-1
A=M
M=D+M
@SP
M=M+1
// return
@FW__RETURN
0;JMP
//
(FW__RETURN)
@LCL
D=M
@R13
M=D
@5
A=D-A
D=M
@R14
M=D
@SP
M=M-1
A=M
D=M
@ARG
A=M
M=D
@ARG
D=M+1
@SP
M=D
@R13
D=M
A=D-1
D=M
@THAT
M=D
@2
D=A
@R13
A=M-D
D=M
@THIS
M=D
@3
D=A
@R13
A=M-D
D=M
@ARG
M=D
@4
D=A
@R13
A=M-D
D=M
@LCL
M=D
@R14
A=M
0;JMP
(FW__CALL)
@SP
A=M
M=D
@SP
M=M+1
@LCL
D=M
@SP
A=M
M=D
@SP
M=M+1
@ARG
D=M
@SP
A=M
M=D
@SP
M=M+1
@THIS
D=M
@SP
A=M
M=D
@SP
M=M+1
@THAT
D=M
@SP
A=M
M=D
@SP
M=M+1
@SP
D=M
@5
D=D-A
@R13
D=D-M
@ARG
M=D
@SP
D=M
@LCL
M=D
@R14
A=M
0;JMP

Reply | Threaded
Open this post in threaded view
|

Re: Nested call output is incorrect, most likely because of pointer scew

pm100
In reply to this post by fishboy1887
FYI, here is my complete solution set written in rust

https://github.com/pm100/hack

I am now working on
- an FPGA implementation - working
- a much better debugger/ emulator, needed for...
- I want to get mini-unix running. This ran on the original PDP11 and the hack system is about the same size / capabilties as that machine. pdp11 had 64k ram, no memory protection , no virtual memory, memory mapped IO
- This needs a c compiler, I am mid way (maybe 25%) through adding hack cpu backend to tinycc
Reply | Threaded
Open this post in threaded view
|

Re: Nested call output is incorrect, most likely because of pointer scew

fishboy1887
Thanks for the code. I fixed it now, it was something to do with my temp segments. Now I am working on getting fibonacci element to pass.