below is an old core to one of my interpreters.
it was a register based machine.
basically it used a 32bit number
top 8 bits were opcode, next 8 were register 1, then next8 were register 2. the remaing were some status bits.
all opcodes ran on register to register with the exception of the load/store opcode.
it ran 'compiled' scripts in a 64kb data block (all code/text etc must sit inside 64kb. that was my restriction, since this version didnt have a VM doing memory interfacing in it, which my current one has).
anyway, gives you an idea of what code my compiler output. (I cut some commands out, since my message was too long)
Code:
void run_opcode(vContext *vCPU)
{
UINT32 op;
UINT32 r1, r2, r3, r4;
op = (UINT32)( ((UINT8*)vCPU->ptrMem)[ vCPU->cpu.reg[ REG_IP ] ] );
switch(GET_OPCODE(op))
{
case op_NULL:
vCPU->cpu.reg[ REG_IP ] += sizeof(UINT32);
break;
case op_ADD:
r1 = vCPU->cpu.reg[ GET_REGA(op) ];
r2 = vCPU->cpu.reg[ GET_REGB(op) ];
vCPU->cpu.reg[ GET_REGA(op) ] = r1 + r2;
if( r1 > vCPU->cpu.reg[ GET_REGA(op) ])
vCPU->cpu.reg[ REG_FLAGS ] |= FLAG_OVERFLOW;
else
vCPU->cpu.reg[ REG_FLAGS ] &= ~FLAG_OVERFLOW;
vCPU->cpu.reg[ REG_IP ] += sizeof(UINT32);
break;
case op_SUB:
r1 = vCPU->cpu.reg[ GET_REGA(op) ];
r2 = vCPU->cpu.reg[ GET_REGB(op) ];
vCPU->cpu.reg[ GET_REGA(op) ] = r1 - r2;
if( r1 < vCPU->cpu.reg[ GET_REGA(op) ])
vCPU->cpu.reg[ REG_FLAGS ] |= FLAG_OVERFLOW;
else
vCPU->cpu.reg[ REG_FLAGS ] &= ~FLAG_OVERFLOW;
vCPU->cpu.reg[ REG_IP ] += sizeof(UINT32);
break;
case op_MUL:
r1 = vCPU->cpu.reg[ GET_REGA(op) ];
r2 = vCPU->cpu.reg[ GET_REGB(op) ];
vCPU->cpu.reg[ GET_REGA(op) ] = r1 * r2;
/* compute if overflow */
break;
case op_DIV:
r1 = vCPU->cpu.reg[ GET_REGA(op) ];
r2 = vCPU->cpu.reg[ GET_REGB(op) ];
vCPU->cpu.reg[ GET_REGA(op) ] = r1 / r2;
vCPU->cpu.reg[ GET_REGB(op) ] = r1 % r2;
/* compute if overflow */
vCPU->cpu.reg[ REG_IP ] += sizeof(UINT32);
break;
case op_CMP:
if( vCPU->cpu.reg[ GET_REGA(op) ] == vCPU->cpu.reg[ GET_REGB(op) ] )
vCPU->cpu.reg[ REG_FLAGS ] |= FLAG_EQUAL;
else
vCPU->cpu.reg[ REG_FLAGS ] &= ~FLAG_EQUAL;
vCPU->cpu.reg[ REG_IP ] += sizeof(UINT32);
break;
case op_MOV:
// dont change reg0!
if( GET_REGA(op) == 0)
break;
r1 = vCPU->cpu.reg[ GET_REGA(op) ]; // dest
r2 = vCPU->cpu.reg[ GET_REGB(op) ]; // source
vCPU->cpu.reg[ REG_IP ] += sizeof(UINT32);
// source
switch( GET_MOD1(op) )
{
// mov r1, r2
case 0:
r4 = r2;
break;
// mov r1, [r4]
case MOD_MEM:
r4 = ( ((UINT32*)vCPU->ptrMem)[ r2 ] );
break;
// mov r1, 0xDEADBEEF
case MOD_NUM:
r4 = ( ((UINT32*)vCPU->ptrMem)[ vCPU->cpu.reg[ REG_IP ] ] );
vCPU->cpu.reg[ REG_IP ] += sizeof(UINT32);
break;
// mov r1, [0xDEADBEEF]
case MOD_MEM+MOD_NUM:
r4 = ( ((UINT32*)vCPU->ptrMem)[ vCPU->cpu.reg[ REG_IP ] ] );
vCPU->cpu.reg[ REG_IP ] += sizeof(UINT32);
r4 = ( ((UINT32*)vCPU->ptrMem)[ r4] );
break;
}
// move r4 into { r1|[r1]|[xx] }
// destination
switch( GET_MOD1(op) )
{
// mov r1, r4
case 0:
vCPU->cpu.reg[ r1 ] = r4;
break;
// mov [r1], r4
case MOD_MEM:
r3 = ( ((UINT32*)vCPU->ptrMem)[ r1 ] );
((UINT32*)vCPU->ptrMem)[ r3 ] = r4;
break;
// mov 0xDEADBEEF, r4
// illegal!
case MOD_NUM:
//r3 = ( ((UINT32*)vCPU->ptrMem)[ vCPU->cpu.reg[ REG_IP ] ] );
//vCPU->cpu.reg[ REG_IP ] += sizeof(UINT32);
// signal illegal!
break;
// mov [0xDEADBEEF], r4
case MOD_MEM+MOD_NUM:
r3 = ( ((UINT32*)vCPU->ptrMem)[ vCPU->cpu.reg[ REG_IP ] ] );
vCPU->cpu.reg[ REG_IP ] += sizeof(UINT32);
((UINT32*)vCPU->ptrMem)[ r3 ] = r4;
break;
}
break;
case op_JE:
r1 = vCPU->cpu.reg[ GET_REGA(op) ];
vCPU->cpu.reg[ REG_IP ] += sizeof(UINT32);
if( (vCPU->cpu.reg[ REG_FLAGS ]&=FLAG_EQUAL)==FLAG_EQUAL )
vCPU->cpu.reg[ REG_IP ] = r1;
break;
}
}