When I run the VM file in the VMEmulator, I find that RAM is set to 28.
I interpret RAM = 28 to be the return address of bootstrap code 'Call Sys.init'.
This all makes some sense to me because, based on my current understanding of bootstrap code, I think that the VM Emulator implicitly tacks a few lines of VM code to the end of this particular VM program because Sys.init is not explicitly defined.
According to my understanding, this implicit code should include:
'Call Sys.init' // Call Sys.init, which calls Main.main as well as calls other OS functions(the saved, overlapping frames of the latter are seen in RAM - RAM).
'label WHILE' // infinite loop to terminate VM program. This should be the return address of 'Call Sys.init'.
I think that 'label WHILE' should be line 28 of the program when taking into account the bootstrap code. Thus, the entire VM program, when taking bootstrap code into account, should look something like this:
You are making the mistake of trying to equate a value on the stack in RAM with a VM line number. These are totally separate things.
Consider how many Hack assembly instructions are required for even the simple VM commands. The location of the labels in the ROM will all be much, much higher than the VM line numbers on which they reside.
When you use built-in OS functions, pretty much all bets are off as far as where things will end up or how they will work. The Global Stack and RAM windows in the VM Emulator are really only useful once you are running all of your own code (at which point it can be very useful).
In principle, the VM Emulator is unaware of any details of the underlying hardware. It needs a Global Stack, which could (and arguably should) start at index (as opposed to address) 0. It needs a stack pointer and it needs a means of keeping track of all of the memory segments (including the ones not currently visible) and a means of switching contexts between them. The VM Emulator could (and, again, arguably should) hide all of those details.