6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Aug 03, 2024 11:53 am

All times are UTC




Post new topic Reply to topic  [ 9 posts ] 
Author Message
PostPosted: Thu May 03, 2012 1:20 am 
Offline
User avatar

Joined: Mon Aug 08, 2011 2:48 pm
Posts: 808
Location: Croatia
Hi!
Since i am a student, i go home for holidays, and usually i don't carry all my stuff all around the country, so home i only have left an old pc.
This time i tried to do something that might be helpful with programing mcu's, sbc, ect... Something like mini Java for mcu, and other platforms with little memory and low processing power.
My idea was to create a program that reads a bytecode program from a file, and executes the instructions.To make this bytecode execution as fast as possible, I made an array of pointers, so when the opcode is fetched, it loads the pointer from the array, and jumps to it(the opcode function is located at the pointer destination).

This should be a simple program, since it should be able to run on mcu, sbc, and other platforms...

Here is the code that i made so far(for x86 only(Dev C++)):
Code:
#include<stdio.h>
#include<stdlib.h>

#define ret() asm("jmp opscangtp")
//returns, fetches next instruction
#define fetch() tmp=pmem[pc++]
//loads next argument into the tmp variable
#define setop(N,O) (optable[N]=O)
//sets the operation label, to the selected opcode number[0-255]

int main()
{
    unsigned char tmp;
    int i,temp=0;
    void *optable[256];
    int retv=1;
    char *pmem=(char*)malloc(65536);
    char *retval=(char*)malloc(16);
    unsigned long pc=0;
    for(i=0;i<256;i++)setop(i,&&op_en);

    setop(0,&&op_add);
    setop(1,&&op_lol);
    setop(2,&&op_and);
    setop(3,&&op_or);
    setop(4,&&op_scanf);
    setop(5,&&op_if);
    setop(6,&&op_sub);
    setop(7,&&op_printretval);
    setop(8,&&op_settemp);
   

    void *v;
    FILE * pFile;
    pFile = fopen("myfile.bin","rb");
    for(i=0;i<65536&&retv==1;i++)retv=fread(pmem+i,1,1,pFile);//loads the simulated 64k rom
    fclose(pFile);
   
    asm("opscangtp:   ");
    asm ("movl %1, %%eax;\n\rjmp *%%eax"
         :"=r"(v)        /* output */
         :"r"(v=optable[pmem[pc++]])         /* input */
         :"%eax"         /* clobbered register */
         );



    op_add:
    {
        fetch();
        *retval=temp+=tmp;
    }ret();
   
    op_lol:
    {
        printf("LOL\n");
    }ret();
   
    op_and:
    {
        fetch();
        *retval=temp=temp&tmp;
    }ret();
   
    op_or:
    {
        fetch();
        *retval=temp=temp|tmp;
    }ret();
   
    op_scanf:
    {
        scanf("%d",retval);
    }ret();
   
    op_if:
    {
        fetch();
        if(temp)pc=tmp;
    }ret();
   
    op_sub:
    {
        fetch();
        *retval=temp-=tmp;
    }ret();
   
   
    op_printretval:
    {
        printf("retval=%d\n", *retval);
    }ret();
   
    op_settemp:
    {
        temp=*retval;
    }ret();
   
op_en:
   
    free(pmem);
    free(retval);
    system("pause");
   
    return 0;   
}


Here is the content of the bytecode file myfile.bin (in hexadecimal)
Code:
04 08 01 07 06 01 05 02 70


The example will ask an input number(type 5).


This can't get too complex, because it won't fit in the small mcu/sbc rom, and i still don't know how the variables could be implemented. Any ideas?

And can this be modified to work with cc65?


Top
 Profile  
Reply with quote  
PostPosted: Thu May 03, 2012 7:36 am 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
You really should try and avoid GNU extensions to C (like taking the address of a label). Run the compiler in strict ANSI mode or your code will not be portable to other compilers.

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
PostPosted: Thu May 03, 2012 1:26 pm 
Offline
User avatar

Joined: Mon Aug 08, 2011 2:48 pm
Posts: 808
Location: Croatia
How could i then get the address of a code segment without getting the label's address?


Top
 Profile  
Reply with quote  
PostPosted: Thu May 03, 2012 1:58 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
You could make a big switch statement. This would also avoid the non-portable asm.
Code:
switch( opcode )
{
    case 0:
    case 1:
    ..
    case 255:
}


Top
 Profile  
Reply with quote  
PostPosted: Thu May 03, 2012 5:50 pm 
Offline
User avatar

Joined: Mon Aug 08, 2011 2:48 pm
Posts: 808
Location: Croatia
Yes, that would simplify a lot, but how much time would be consumed on testing each case when executing?


Top
 Profile  
Reply with quote  
PostPosted: Thu May 03, 2012 6:22 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Dajgoro wrote:
Yes, that would simplify a lot, but how much time would be consumed on testing each case when executing?


GCC is smart enough to implement a jump table, so you'd get something very similar to your code.


Top
 Profile  
Reply with quote  
PostPosted: Thu May 03, 2012 6:50 pm 
Offline
User avatar

Joined: Mon Aug 08, 2011 2:48 pm
Posts: 808
Location: Croatia
GCC might be, but what about cc65, how would this work there, or on avr?
Anyway worst case scenario is the case switch.


Top
 Profile  
Reply with quote  
PostPosted: Thu May 03, 2012 7:00 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Dajgoro wrote:
GCC might be, but what about cc65, how would this work there, or on avr?
Anyway worst case scenario is the case switch.

All decent compilers would use a jump table for a dense case statement. I don't know about cc65, but for the 6502, it would probably be worth it to write the interpreter in assembly language.


Top
 Profile  
Reply with quote  
PostPosted: Thu May 03, 2012 7:13 pm 
Offline
User avatar

Joined: Mon Aug 08, 2011 2:48 pm
Posts: 808
Location: Croatia
Here is the same program, but without the assembly:
Code:
#include<stdio.h>
#include<stdlib.h>

#define fetch() tmp=pmem[pc++]
//loads next argument into the tmp variable
#define setop(N,O) (optable[N]=O)
//sets the operation label, to the selected opcode number[0-255]

    typedef void (*Handler)(void);
    unsigned char tmp;
    int i,temp=0;
    Handler optable[256];
    int retv=1;
    char *pmem=(char*)malloc(65536);
    char *retval=(char*)malloc(16);
    unsigned long pc=0;

    void op_add()
    {
        fetch();
        *retval=temp+=tmp;
    }
   
    void op_lol()
    {
        printf("LOL\n");
    }
   
    void op_and()
    {
        fetch();
        *retval=temp=temp&tmp;
    }
   
    void op_or()
    {
        fetch();
        *retval=temp=temp|tmp;
    }
   
    void op_scanf()
    {
        scanf("%d",retval);
    }
   
    void op_if()
    {
        fetch();
        if(temp)pc=tmp;
    }
   
    void op_sub()
    {
        fetch();
        *retval=temp-=tmp;
    }
   
   
    void op_printretval()
    {
        printf("retval=%d\n", *retval);
    }
   
    void op_settemp()
    {
        temp=*retval;
    }
   
    void op_en()
    {
        free(pmem);
        free(retval);
        system("pause");
        exit(0);
    }

int main()
{
   
    for(i=0;i<256;i++)setop(i,op_en);

    setop(0,op_add);
    setop(1,op_lol);
    setop(2,op_and);
    setop(3,op_or);
    setop(4,op_scanf);
    setop(5,op_if);
    setop(6,op_sub);
    setop(7,op_printretval);
    setop(8,op_settemp);
   
    void *v;
    FILE * pFile;
    pFile = fopen("myfile.bin","rb");
    for(i=0;i<65536&&retv==1;i++)retv=fread(pmem+i,1,1,pFile);
    fclose(pFile);
    do{
    optable[pmem[pc++]]();
    }while(1);
    return 0;
}


This code works like that i posted before. For now i think it is best to get this working on normal GCC, and then transfer it to cc65...

AS for the variables, for now the return value is 16 byte long, so it can hold any kind of variable, form char to double, and more. But what about variables, i see 2 solutions, first is to make a system where you could create integers, characters, floats, arrays, ect... and then when you arithmetic operations, it would automatically detect if it is char, int or float. Or the other solution is just to allocate n bytes of ram, and pretend that it is a char, int, float, and when you do some arithmetic operations, you would need to know what kind of variables are you working with.
Any suggestions?


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 9 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 30 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: