VM translator generate x86 windows assembly

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

VM translator generate x86 windows assembly

jacklack
While looking on how to generate windows executable from Jack source, I tried to understand how the PE executable format works.

Instead of going this route, I now go through a most logical and layered route, which is make the VM translator generate x86 win 32 asm code instead of hack code!
This is what I should have done instead of looking into PE stuff. As first you get an assembly file then you can use a windows assembler (there are many) to generate a windows executable.

I am doing this now, trying to get the vmtranslator generate masm style x86 win 32 assembler code.

In the process, it looks to be easier than generating hack....one of the reason is that x86 has a push and pop functions built in.

I am on it, and hopefully will get jack breakout working on a windows console.
Reply | Threaded
Open this post in threaded view
|

Re: VM translator generate x86 windows assembly

jacklack
I made a new code generator that generates x86 code instead of Hack.

It turned out to be easier to implement than Hack, or maybe I found it easier because of the experience I already had with Hack...and the 8 register of the x86 help a lot too. (I wonder why there is only 8 registers, more would have been even more better ).

The os files need to be modified for use with the x86 windows platform. For example, the os file Memory need to allocate using windows libraries in assembly code.

I am planning to add an asm{ code } or similar style keyword that will tell the compiler to bypass the compilation of the block, and make the virtual machine just stick that block in the generated x86 code. If there is a better way to handle this issue, please tell me.

Reply | Threaded
Open this post in threaded view
|

Re: VM translator generate x86 windows assembly

cadet1620
Administrator
One thing that you might consider is writing your Jack OS classes in C (not C++).

C has a simple calling convention (cdecl [1]) that should be compatible with Jack.  Have your VM use something like "_ _ _" [2] instead of "." when generating identifier names in the ASM, and use the C calling convention for all calls generated by the VM.

Then your VM ASM can be directly linked to C.  Example Memory.alloc and deAllc would look something like
#include <stdint.h>
#include <stdlib.h>
#include "JackClass.h"

int16_t Memory___alloc(int16_t size)
{
    char * p;

    p = malloc(size);
    if ( ! p)
        Sys___error(6);     // does not return

    return allocJackPointer(p);
}

int16_t Memory___deAlloc(int16_t this)
{
    char * p;

    p = derefJackPointer(this);     // returns NULL if 'this' not in map
    free(p);
    removeJackPointer(this);

    return 0;
}
etcJackPointer functions would need to translate between 32-bit system memory pointers and 16-bit memory "handles" that the OS code would use to access system.

[Stream of conscience writing...]
How do you handle vm references to 'this' and 'that'? The pointer registers are only 16-bit so they can't hold a 32-bit system pointers, but accessing handle+offset is invalid.

Calling Memory___Peek and ___Poke for all this and that references could really slow things down.
Maybe Windows Jack should have all types be 32-bit. Then you wouldn't need to translate pointers <-> handles.

You might want to download the n2t source disto and look at the java in BuiltinVMClasses. They work similarly to the above.

--Mark

----------
[1] http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl
[2] I don't know if any libraries the use 3 underscores in a row in identifier names.
Reply | Threaded
Open this post in threaded view
|

Re: VM translator generate x86 windows assembly

jacklack
Hi Cadet, thanks for the suggestion;

It's one way to solve this issue...I'll take it into account.

As for the word size issue, the virtual machine is word agnostic, and that's what's great about the nandtotetris layered approach. I use 32 bits for this, that etc on the x86 win32.

For now, I changed the Memory.jack look like this:
class Memory
{

        static int s_HeapHandle;
        static int s_Variable;
       
    /** Initializes memory parameters. */
    function void init()
        {
                asm
                {
                        INVOKE GetProcessHeap ; get handle heap
                        mov Memory@0, eax     ; s_HeapHandle = 0
                }
       
                return;
    }

        /** finds and allocates from the heap a memory block of the
        *  specified size and returns a reference to its base address. */
    function int alloc(int size)
        {
                let s_Variable = size;
                asm
                {
                        push Memory@1 ; s_Variable
                        push 0
                        push Memory@0 ; s_HeapHandle
                       
                        call HeapAlloc
                       
                        mov  Memory@1, eax ;variable has pointer to allocated memory or null
                }
                return s_Variable;
    }
       
        /** De-allocates the given object and frees its space. */
    function void deAlloc(int objectAddress)
        {
                let s_Variable = objectAddress;
                asm
                {
                        push Memory@1 ; s_Variable
                        push 0
                        push Memory@0 ; s_HeapHandle
                       
                        call HeapFree
                }
               
                return;
    }  
}

One advantage of using the c code is that it will work as is  whether it's on windows or linux etc...
whereas the asm code calls are for windows in the example above...
cadet1620 wrote
One thing that you might consider is writing your Jack OS classes in C (not C++).

C has a simple calling convention (cdecl [1]) that should be compatible with Jack.  Have your VM use something like "_ _ _" [2] instead of "." when generating identifier names in the ASM, and use the C calling convention for all calls generated by the VM.

Then your VM ASM can be directly linked to C.  Example Memory.alloc and deAllc would look something like
#include <stdint.h>
#include <stdlib.h>
#include "JackClass.h"

int16_t Memory___alloc(int16_t size)
{
    char * p;

    p = malloc(size);
    if ( ! p)
        Sys___error(6);     // does not return

    return allocJackPointer(p);
}

int16_t Memory___deAlloc(int16_t this)
{
    char * p;

    p = derefJackPointer(this);     // returns NULL if 'this' not in map
    free(p);
    removeJackPointer(this);

    return 0;
}
etcJackPointer functions would need to translate between 32-bit system memory pointers and 16-bit memory "handles" that the OS code would use to access system.

[Stream of conscience writing...]
How do you handle vm references to 'this' and 'that'? The pointer registers are only 16-bit so they can't hold a 32-bit system pointers, but accessing handle+offset is invalid.

Calling Memory___Peek and ___Poke for all this and that references could really slow things down.
Maybe Windows Jack should have all types be 32-bit. Then you wouldn't need to translate pointers <-> handles.

You might want to download the n2t source disto and look at the java in BuiltinVMClasses. They work similarly to the above.

--Mark

----------
[1] http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl
[2] I don't know if any libraries the use 3 underscores in a row in identifier names.
Reply | Threaded
Open this post in threaded view
|

Re: VM translator generate x86 windows assembly

jacklack
In reply to this post by jacklack
I went for now with the embeded asm route, and it looks to be working fine.
I get programs executing on the windows machine in the same way as in the hack architecture.

Now is the problem of input/output, as I need a way to handle the keyboard and screen, In hack it's memory mapped, but in windows, there is no direct access to memory...

I've been looking at some solutions, I need to use a library for this (directx, or gdi or other). gdi seems to be the easiest so I'll try to get something out of it...
Reply | Threaded
Open this post in threaded view
|

Re: VM translator generate x86 windows assembly

jacklack
In reply to this post by jacklack
Have the gdi output part working (slow for now, for some reason).
I'll be doing the keyboard part next (but need to fix the slow gdi part first)
Reply | Threaded
Open this post in threaded view
|

Re: VM translator generate x86 windows assembly

jacklack
In reply to this post by jacklack
Output working fine now. Used gdi and double buffering this time for quicker graphics.
Here is a picture showing compiled pong game on windows:


Next now is the keyboard...
Reply | Threaded
Open this post in threaded view
|

Re: VM translator generate x86 windows assembly

jacklack
In reply to this post by jacklack
I got the keyboard part working.
I am looking now on how to write a debugger for it...
Reply | Threaded
Open this post in threaded view
|

Re: VM translator generate x86 windows assembly

attachedy
This is an amazing work. I would very much like to see a video of pong running under windows!

I will try to rewrite the JackOS in C (as has been suggested above). Since you both are most likely a lot more experienced in this stuff, I would like you to review the steps that came to my mind for realizing the project:

1) Rewrite the Jack-VM to output x86-assembly. Function calls must meet the C-calling conventions for linking in step (6).
2) Compile the Jack program VM-code-files (e.g. for "pong") to .asm with the new Jack-VM.
3) Generate obj-files from the .asm-files, e.g. using nasm/masm.
4) Rewrite the JackOS classes using C. The OS-classes would have to include windows.h to call into the win32api (e.g., gdi32 for drawing on the screen).
5) Compile the JackOS C-classes to obj-files, e.g. using gcc.
6) Statically link all files generated in (3) and (5).

Does this make sense or am I off somehow?

Due to my little to no experience in C programming, the win32api and the whole building and linking process, this will be some hard route to go for me. However, having the goal in mind to see Jack programs running "natively" in windows would keep me on track on learning all of this.
Reply | Threaded
Open this post in threaded view
|

Re: VM translator generate x86 windows assembly

Lozminda
That looks like a great project. However I know nothing about windows (am assuming you're talking about the microsoft ones)

C's pretty easy (i think compared to C++) get a good debugging system to track down those memory leaks !!
If you get stuck with the C, I Might be able to give you a hand, "Might" being the important word..I've only got a few years programming experience and although I've written a few things in C, most of my experience is in C++

Sorry I can't give you any constructive advice. Be interested to hear how you get on though !

Good luck!

Lozminda
Reply | Threaded
Open this post in threaded view
|

Re: VM translator generate x86 windows assembly

jacklack
In reply to this post by attachedy
@attachedy

Hope it's not too late, just checked in here.
It's been some time I didn't work on this, but the idea was that the VM translator output x86 asm, and then using MASM to compile and generate the exe.

Here the repo for this:
https://github.com/designerjgames/Jack

Check the X86 files, there is the JackX86 os inside the compiler folder, and then VM x86 files inside the VM folder.

Hope it helps.