Best way to structure the code of the vm translator(dependencies between modules).

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

Best way to structure the code of the vm translator(dependencies between modules).

Henoktes722
I'm following the apis defined in the book as I did in the assembler, I think the code writer modules needs more explanation.

Will the code-writer module only returns the hack assm of the given command using the two apis, writeArithmetic and writePushPop or it is also responsible to write the final hack assembly to the file?

I did just the code-writer module to return the hack assm of the given vm command. And the main module to march through the parser and pass them to the code writer like this way.

code-writer module


main module


So Am I doing on the correct way to translate for directory, which contain many vm files.


Reply | Threaded
Open this post in threaded view
|

Re: Best way to structure the code of the vm translator(dependencies between modules).

WBahn
Administrator
Henoktes722 wrote
I'm following the apis defined in the book as I did in the assembler, I think the code writer modules needs more explanation.

Will the code-writer module only returns the hack assm of the given command using the two apis, writeArithmetic and writePushPop or it is also responsible to write the final hack assembly to the file?
Well, let's look at the descriptions given for the CodeWriter module.

What does the constructor do? It says: "Opens the output file/stream and gets ready to write to it."

The WriteArithmetic and WritePushPop methods both state the each, "Writes the assembly code..."

Then the Close method then says that it, "Closes the output file."

So, with that in mind, is the CodeWriter module responsible for actually writing the assembly code to the output file or is some other module?


So if the CodeWriter module is the module that opens the output file,
Reply | Threaded
Open this post in threaded view
|

Re: Best way to structure the code of the vm translator(dependencies between modules).

Henoktes722
So what is the purpose of the main module. And if that is the case the code writer module needs the vm commands to translate, which in turn needs the parser module, is that right?
Reply | Threaded
Open this post in threaded view
|

Re: Best way to structure the code of the vm translator(dependencies between modules).

WBahn
Administrator
Henoktes722 wrote
So what is the purpose of the main module. And if that is the case the code writer module needs the vm commands to translate, which in turn needs the parser module, is that right?
The main module invokes the other two and controls the overall interaction between them.

So it creates a CodeWriter object for the VM program as a whole. It then creates a Parser object for each VM file as it gets to it and uses it's methods to find out information about the next command in the VM file. Based on the results, it then uses the CodeWriter's methods to output assembly code to the .asm file.
 
Reply | Threaded
Open this post in threaded view
|

Re: Best way to structure the code of the vm translator(dependencies between modules).

Henoktes722
Okay I got you. But there is a principle called SRP(Single Responsibility Principle), which states that a module must only do one thing.

So the code-writer module must only perform the translator part instead of saving to the file.
I think main module can do that.

And how to combine many .vm files into one hack assembly, will the order doesn't matter if so why?
Reply | Threaded
Open this post in threaded view
|

Re: Best way to structure the code of the vm translator(dependencies between modules).

WBahn
Administrator
Henoktes722 wrote
Okay I got you. But there is a principle called SRP(Single Responsibility Principle), which states that a module must only do one thing.

So the code-writer module must only perform the translator part instead of saving to the file.
I think main module can do that.
There are many ways to partition a large task into modules. The authors have provided a suggested API that is aimed at people that have limited programming experience. Consequently there a tradeoff between best software engineering practices and tractability for the target audience.

If you wish to apply more sophisticated programming paradigms you are certainly free to do so since their suggested API is just that -- suggested. You don't have to follow it at all. You are given the language specifications and can start with a clean sheet of paper and implement the translator using whatever structure you which as long as it implements the specifications.

And how to combine many .vm files into one hack assembly, will the order doesn't matter if so why?
The order does matter for the same reason that it doesn't matter what order you compile the files that make up projects in nearly any other programming language. Each VM file is it's own entity and any call to a function in another VM file is an unresolved external that is resolved at link time. For the Hack/VM, that resolution is taken care of implicitly by the naming conventions. Because nearly everything is local and stored in a local memory space on the stack, the only concerns are static variables and function calls. The naming convention for both incorporate the class name so that as long as no two classes have the same name, no collision is possible. Since the class names are the same as the file names and since the files are all in the same directory, no two classes can have the same name.

Reply | Threaded
Open this post in threaded view
|

Re: Best way to structure the code of the vm translator(dependencies between modules).

Henoktes722
Thank you. Just to be sure,

if sum.vm's assm is
@xa
@ya
D = D + A

and mult.vm's assm is
@xb
@yb
D = D * A

this is just an assumption. So the result will be

@xa
@ya
D = D + A
@xb
@yb
D = D * A .

right, what makes me vague is the stack and other RAM values are not clear, the first vm changes when running, when the second .vm is running??

Do you have tests for many .vm files?
Reply | Threaded
Open this post in threaded view
|

Re: Best way to structure the code of the vm translator(dependencies between modules).

WBahn
Administrator
Henoktes722 wrote
Thank you. Just to be sure,

if sum.vm's assm is
@xa
@ya
D = D + A
How is it that your code for sum.vm is generating an @xa assembly instruction in the first place?

Show the VM command sequence that you believe should result in this sequence of assembly instructions.

and mult.vm's assm is
@xb
@yb
D = D * A
I'm not aware of a Hack assembly instruction in which the comp portion is "D * A".

What would prevent mult.vm from generating an @xa assembly instruction, too?

Remember, in the VM language specification, ALL memory references are to index locations in one of the eight memory segments.

this is just an assumption. So the result will be

@xa
@ya
D = D + A
@xb
@yb
D = D * A .

right,
At least potentially -- assuming that your assumption was valid. But if I assume things that violate the language specification, I can get all kinds of things that don't make sense.

Instead, you need to focus on examples for which you don't have to assume things -- use examples that satisfy the language specifications.

what makes me vague is the stack and other RAM values are not clear, the first vm changes when running, when the second .vm is running??

Do you have tests for many .vm files?
I have no idea what you mean by first vm changing when the second .vm is running. At the end of the day you have a SINGLE assembly program that is running on the hardware.


Reply | Threaded
Open this post in threaded view
|

Re: Best way to structure the code of the vm translator(dependencies between modules).

Henoktes722
This post was updated on .
No those are just an assumption not a valid hack assembly code.
I have now a vm translator that I tested on the 5 test programs and are correct. So now what it left is to translate a directory, with many .vm files. But the combining phase is just still wrap my head around.
Sorry for the confusion I created so far, I'm not good at writing in english.
Reply | Threaded
Open this post in threaded view
|

Re: Best way to structure the code of the vm translator(dependencies between modules).

WBahn
Administrator
Henoktes722 wrote
No those are just an assumption not a valid hack assembly code. I have know a vm translator that I test on the 5 test programs and are correct. So know I left to translate a directory with many .vm files, I'll try it let you. But the combining phase is just still wrap my head around.
Sorry for the confusion, I'm not good at english.
So since you have a VM translator that you believe is correct, write some VM code snippets and post both the VM code and the output of your translator and use those as your examples. It's quite possible that your VM translator isn't meeting the specifications but that, if it is only used on a single file, that the failure to meet specifications isn't causing problems yet. I suspect that there is a very good change that this is the case.


Reply | Threaded
Open this post in threaded view
|

Re: Best way to structure the code of the vm translator(dependencies between modules).

Henoktes722
This post was updated on .
first.vm
push constant 3030
pop pointer 0

first.asm
@3030
D=A
@SP
A=M
M=D
@SP
M=M+1
@3
D=A
@0
A=A+D
D=A
@R13
M=D
@SP
M=M-1
@SP
A=M
D=M
@R13
A=M
M=D

second.vm
push constant 1
push constant 2
add

second.asm
@1
D=A
@SP
A=M
M=D
@SP
M=M+1
@2
D=A
@SP
A=M
M=D
@SP
M=M+1
@SP
M=M-1
@SP
A=M
D=M
@SP
M=M-1
@SP
A=M
A=M
D=D+A
@SP
A=M
M=D
@SP
M=M+1

So on the combine stage, can the output be like this way, first.asm then second.asm.
@3030
D=A
@SP
A=M
M=D
@SP
M=M+1
@3
D=A
@0
A=A+D
D=A
@R13
M=D
@SP
M=M-1
@SP
A=M
D=M
@R13
A=M
M=D
// second asm will continue then
@1
D=A
@SP
A=M
M=D
@SP
M=M+1
@2
D=A
@SP
A=M
M=D
@SP
M=M+1
@SP
M=M-1
@SP
A=M
D=M
@SP
M=M-1
@SP
A=M
A=M
D=D+A
@SP
A=M
M=D
@SP
M=M+1


Thank you anyway, I took an operating system course and I knew about linkers that create the main executable file from many compiled files. I thought that order of each asm files of .vm files in the main exe files matters. So my question is why not order matter?
Reply | Threaded
Open this post in threaded view
|

Re: Best way to structure the code of the vm translator(dependencies between modules).

WBahn
Administrator
Henoktes722 wrote
first.vm
push constant 3030
pop pointer 0
I would strongly recommend having your VM translator output comments to the .asm file to make analysis and debugging much easier. Perhaps something like:

first.asm

// FILE: first.vm

@3030   // push constant 3030
D=A
@SP
A=M
M=D
@SP
M=M+1
@3         // pop pointer 0
D=A
@0
A=A+D
D=A
@R13
M=D
@SP
M=M-1
@SP
A=M
D=M
@R13
A=M
M=D

Even better, have your output annotated with each logical step that is being done. As long as you do this in a generic way, this is a simple matter of adding static comments to the generated instructions. Perhaps

NOTE: Nabble uses a proportional spaced font, so the spacing is probably messed up on your display. I simply aligned things as best I could on mine.

// =========================
// FILE: first.vm
// =========================

//******* push constant 3030
@3030      // D = value
D=A
@SP          // place value on stack
A=M
M=D
@SP          // increment stack pointer
M=M+1

//******* pop pointer 0
@3            // base of pointer segment
D=A
@0            // add offset to base
A=A+D
D=A          // store target address in D
@R13
M=D          // store target address in R13
@SP          // decrement stack pointer
M=M-1
@SP          // store value on stack in D
A=M
D=M
@R13        // retrieve target address from R13
A=M
M=D          // store value at target address

// =========================
// END OF FILE: first.vm
// =========================

Your logic is pretty convoluted, but it appears to be valid. That's the thing that matters right now. You will suffer a pretty severe space and speed penalty, but you can always come back and tighten things up.

What does your translator produce for the following VM code:

bob.vm:

push static 3

sue.vm:

push static 3

Reply | Threaded
Open this post in threaded view
|

Re: Best way to structure the code of the vm translator(dependencies between modules).

Henoktes722
Yeah It seems complex. That is why I was asking you to show me some vm to assm mappings, so that I will do my vm translator following that mapping.

bob.vm
@bob.3
D=M
@SP
A=M    // dereference SP
M=D   // push value at memory location 16
@SP   // increment SP
M=M+1

sue.vm
@sue.3
D=M
@SP
A=M
M=D
@SP
M=M+1

Let me know what I can do to make my vm translator efficient.
Reply | Threaded
Open this post in threaded view
|

Re: Best way to structure the code of the vm translator(dependencies between modules).

WBahn
Administrator
Henoktes722 wrote
Yeah It seems complex. That is why I was asking you to show me some vm to assm mappings, so that I will do my vm translator following that mapping.
Actually, it's not as convoluted as I was first thinking. I've been working with a machine that has four registers and it's amazing how much more efficient you can make code when that's the case -- even just a single additional register makes a huge difference.

For your pop pointer command your basic approach is this:

Store the target address at R13
Pop the top of the stack into D
Store D into the target address

You are using 15 instructions to do this. There is some low-hanging fruit that can trim a couple of instructions, but to make serious headway you need to explore various options. The first way that we come up with is seldom optimal -- but it gives us a working solution to then tease improvements out of or to better identify even radically different alternatives by recognizing what parts of our current approach are the apparent bottlenecks.

There are several alternatives that could be considered. For instance, we could store the value to be written into a temporary register, adjust the stack pointer, get the target address into A, and then write the value from the temporary register into the target address. But since we need to do arithmetic on the pointer to get the address, we can't leave something in the D register while we do it. That's where having just a single additional register would help enormously -- and hence we've identified a major bottleneck: the need to do pointer arithmetic. So the next question is whether we can figure out a way to simply avoid doing the pointer arithmetic.

We should always consider what information the translator has at translation time and how it can exploit it.

Your code is having the Hack add the base of the pointer segment (which is always 3) to the index (which, while it varies from command to command, is known by the translator whenever it is translating a specific command). What if you have the translator do the arithmetic?

Also, remember that one thing the Hack can do that most real processors can't is write to multiple destinations with the same command. As a result, you can pop the top of the stack into the D register and decrement the stack pointer at the same time using a total of just three instructions.

If you leverage these two things you can perform a pop to the pointer segment using a total of just five assembly language instructions without using any of the temporary registers.

Turning the attention to the static segment stuff, you look like you are doing that right.

Do you see how, regardless of which order you translate bob.vm and sue.vm, you will get the same behavior? Sure, bob.3 and sue.3 will map to different memory locations depending on what order the files are translated in, but that's fine. All that we need to ensure is that whatever memory location bob.3 maps to that no other variable can map to that same address and that any value written to bob.3 from anywhere at anytime in the program will survive and be accessible by any later access to bob.3 from anywhere at anytime in the program.
Reply | Threaded
Open this post in threaded view
|

Re: Best way to structure the code of the vm translator(dependencies between modules).

WBahn
Administrator
In reply to this post by Henoktes722
Henoktes722 wrote
Let me know what I can do to make my vm translator efficient.
I don't what to just show you ways to make your translator more efficient because you will learn the most by figuring out ways on your own. But to prime the pump consider the following:

//******* push constant 3030
@3030      // D = value
D=A
@SP          // place value on stack
A=M
M=D
@SP          // increment stack pointer
M=M+1

This is 7 instructions. But do we really need to access the stack pointer twice?

What happens if we do

@SP
AM = M+1

This performs the increment on the stack pointer and stores the new stack pointer in A. But since this is 1 more than we want, we need to adjust it back down

@SP
AM = M+1
A = A-1

Now A is pointing at the location in memory where we need to write the value in the D register

@SP
AM = M+1
A = A-1
M = D

So our total is

//******* push constant 3030
@3030       // D = value
D=A
@SP           // Increment stack pointer
AM = M+1
A = A-1      // Point to target address on stack
M = D        // Write D to top of stack

It only shaves one instruction, but that's a speed improvement of nearly 17%. Now consider how common constants are in a typical program. If all we do is speed up that one operation by 17%, we would probably realize a noticeable improvement in code performance.