The bootstrap code(starting at ROM) should do this:
Set SP to 256
Fair enough. SP is easy.
Next, let's call Sys.init. Well this is just like calling any other function right?
We have to abide by these rules:
push return-address // (Using the label declared below)
push LCL // Save LCL of the calling function
push ARG // Save ARG of the calling function
push THIS // Save THIS of the calling function
push THAT // Save THAT of the calling function
ARG = SP-n-5 // Reposition ARG (n = number of args.)
LCL = SP // Reposition LCL
goto f // Transfer control
(return-address) // Declare a label for the return-address
So the return address is generated by the assembler. In my case, it maps to 48. But we don't care. Sys.init should never return(right?).
So RAM = 48.
Is this alright?
If I run the VM emulator, the stack looks much differently than mine.
The VM emulator does not show call Sys.init, only funciton Sys.init.
So if we observe the state of RAM before funciton Sys.init runs, I notice that their RAM[SP] = 256.
That's fine. But their RAM = 0 while mine is RAM = 48. That's different than what I have.
At this point, I am thinking maybe it doesn't matter and the VM emulator defaults the return address to 0.
Let's move on. Next let's push LCL, ARG, THIS, THAT, ARG=SP-n-5, LCL=SP
My RAM looks like this now:
Now goto Sys.init.
At this point, my RAM should match the VM emulator. But it does not. The VM emulator(before function Sys.init runs) is:
Apparently, call sys.init does not behave like a normal call.
So am I missing some type of initialization? I noticed in the thread I linked to, he said he initialized some values. But, the book doesn't mention that. The book says initialize SP to 256 and then call Sys.init.
Does call Sys.init not act like a normal call?
I am sure I am missing something dumb. Thanks for the advice.
As you noted, Sys.init() should never return, so the details of what happens should it return really don't matter and are therefore not clearly laid out. Some people take a more purist approach and make an actual call to Sys.init including having a stack frame that stores all of the state information for when it returns. Others note that this is just wasting stack space and so let the bottom stack frame actually be for what Sys.init() actually requires instead of the phantom function that called it.
The VM Emulator is emulating the VM commands and not assembler instructions, so there isn't a strong mapping between executing a command and what it appears to show happing in RAM -- especially when built-in functions are being used. It really shouldn't show physical RAM addresses at all -- but they are helpful in visualizing what is basically happening under the hood. But take them with a grain of salt.
Glad to hear you figured it out. As with many things in life, we can easily get ourselves so focused on what we think the problem is that we overlook the real problem for quite some time. The good news is that every time we do it we learn a little bit more so that we don't do it as bad in the future.