Initial
This commit is contained in:
commit
16d57bf64b
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.out
|
32
cpp/debug.h
Normal file
32
cpp/debug.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef DBG_H
|
||||||
|
#define DBG_H
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
#define DBG_INFO(_x_) \
|
||||||
|
do { \
|
||||||
|
printf("\t[*] "); \
|
||||||
|
printf _x_; \
|
||||||
|
} while (0)
|
||||||
|
#define DBG_WARN(_x_) \
|
||||||
|
do { \
|
||||||
|
printf("[!] "); \
|
||||||
|
printf _x_; \
|
||||||
|
} while (0)
|
||||||
|
#define DBG_ERROR(_x_) \
|
||||||
|
do { \
|
||||||
|
printf("[-] "); \
|
||||||
|
printf _x_; \
|
||||||
|
} while (0)
|
||||||
|
#define DBG_SUCC(_x_) \
|
||||||
|
do { \
|
||||||
|
printf("[+] "); \
|
||||||
|
printf _x_; \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define DBG_INFO(_x_)
|
||||||
|
#define DBG_WARN(_x_)
|
||||||
|
#define DBG_ERROR(_x_)
|
||||||
|
#define DBG_SUCC(_x_)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
26
cpp/emulator.cpp
Normal file
26
cpp/emulator.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include "instructions.h"
|
||||||
|
#include "vm.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
ifstream vmbytecode;
|
||||||
|
VM * vm;
|
||||||
|
uint8_t * data;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (vmbytecode != NULL) {
|
||||||
|
fread()
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Couldn't open bytecode!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
41
cpp/instructions.h
Normal file
41
cpp/instructions.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "vm.h"
|
||||||
|
#ifndef INS_H
|
||||||
|
#define INS_H
|
||||||
|
enum regs {
|
||||||
|
R0,
|
||||||
|
R1,
|
||||||
|
R2,
|
||||||
|
R3,
|
||||||
|
S0,
|
||||||
|
S1,
|
||||||
|
S2,
|
||||||
|
S3,
|
||||||
|
IP,
|
||||||
|
BP,
|
||||||
|
SP
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ins {
|
||||||
|
MOVI,
|
||||||
|
MOVR,
|
||||||
|
MOVM,
|
||||||
|
ADDI,
|
||||||
|
ADDR,
|
||||||
|
ADDM,
|
||||||
|
SUBI,
|
||||||
|
SUBR,
|
||||||
|
SUBM,
|
||||||
|
XORI,
|
||||||
|
XORR,
|
||||||
|
XORM,
|
||||||
|
MULI,
|
||||||
|
MULR,
|
||||||
|
MULM,
|
||||||
|
DIVI,
|
||||||
|
DIVR,
|
||||||
|
DIVM,
|
||||||
|
HALT,
|
||||||
|
NOPE
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
15
cpp/vm.cpp
Normal file
15
cpp/vm.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "vm.hh"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
void VM::VM(void) {
|
||||||
|
DBG_INFO(("Creating VM without code.\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VM::VM(uint8_t * code, uint32_t codesize) {
|
||||||
|
DBG_INFO(("Creating VM with code.\n"));
|
||||||
|
memcpy(&vm.as.code, code, codesize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VM::run(uint8_t * code) {
|
||||||
|
return;
|
||||||
|
}
|
20
cpp/vm.h
Normal file
20
cpp/vm.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef VM_H
|
||||||
|
#define VM_H
|
||||||
|
|
||||||
|
class VMAddrSpace {
|
||||||
|
uint8_t stack[0x100], code[0x300], data[0x500];
|
||||||
|
};
|
||||||
|
|
||||||
|
class VM {
|
||||||
|
uint16_t regs[0xb];
|
||||||
|
struct flags {
|
||||||
|
uint8_t zf:1;
|
||||||
|
uint8_t cf:1;
|
||||||
|
};
|
||||||
|
VMAddrSpace as;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void run(uint8_t * code);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
724
examples/VM.c
Normal file
724
examples/VM.c
Normal file
@ -0,0 +1,724 @@
|
|||||||
|
/*
|
||||||
|
VM by Souhail Hammou : custom instruction set
|
||||||
|
data space and stack space are customizable.
|
||||||
|
Important : In calculations the VM is using unsigned values.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <conio.h>
|
||||||
|
#define TRUE 1
|
||||||
|
#define FALSE 0
|
||||||
|
typedef unsigned char boolean;
|
||||||
|
typedef uint8_t BYTE;
|
||||||
|
typedef uint16_t WORD;
|
||||||
|
typedef uint32_t DWORD;
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/*data has also the code*/
|
||||||
|
BYTE data[4096];
|
||||||
|
/*stack space , size of one element is WORD in order to be able to push addresses*/
|
||||||
|
WORD stack[256];
|
||||||
|
}ADDRESS_SPACE,*PADDRESS_SPACE;
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/*General Purpose Registers R0 -> R3*/
|
||||||
|
WORD GPRs[4];
|
||||||
|
union
|
||||||
|
{
|
||||||
|
unsigned char Flags;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned char ZF:1;
|
||||||
|
unsigned char CF:1;
|
||||||
|
unsigned char Unused:6;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
WORD IP;
|
||||||
|
WORD SP;
|
||||||
|
}REGS,*PREGS;
|
||||||
|
void VmLoop(PADDRESS_SPACE AS,PREGS Regs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
boolean exit = FALSE;
|
||||||
|
BYTE opcode,byte_val,byte_val2,byte_val3;
|
||||||
|
WORD word_val,word_val2;
|
||||||
|
while(!exit)
|
||||||
|
{
|
||||||
|
/*read byte (opcode)*/
|
||||||
|
//printf("[+] IP : %.4X => ",Regs->IP);
|
||||||
|
opcode = AS->data[Regs->IP++];
|
||||||
|
/*opcodes switch*/
|
||||||
|
switch(opcode)
|
||||||
|
{
|
||||||
|
case 0x90 :
|
||||||
|
//printf("NOP\n");
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
Each nibble of the operand represents a General purpose register (GPR)
|
||||||
|
the highest nibble is the destination , the lowest one is the source.
|
||||||
|
Example:
|
||||||
|
10 12 => MOV R1,R2
|
||||||
|
10 11 => MOV R1,R1
|
||||||
|
10 01 => MOV R0,R1
|
||||||
|
*/
|
||||||
|
case 0x10 :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3)
|
||||||
|
{
|
||||||
|
Regs->GPRs[(byte_val & 0xF0)>>4] = Regs->GPRs[byte_val & 0x0F];
|
||||||
|
//printf("MOV R%d,R%d\n",(byte_val & 0xF0)>>4,byte_val & 0x0F);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto exception;
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
Move and extend byte from memory to register
|
||||||
|
Example:
|
||||||
|
12 03 50 00 => MOVX R3,BYTE [0050]
|
||||||
|
12 00 00 01 => MOVX R0,BYTE [0100]
|
||||||
|
*/
|
||||||
|
case 0x12 :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if(byte_val > 3)
|
||||||
|
goto exception;
|
||||||
|
word_val = *(WORD*)&AS->data[Regs->IP];
|
||||||
|
Regs->IP += 2;
|
||||||
|
if(word_val >= sizeof(AS->data))
|
||||||
|
goto exception;
|
||||||
|
Regs->GPRs[byte_val] = 0;
|
||||||
|
*(BYTE*)&Regs->GPRs[byte_val] = AS->data[word_val];
|
||||||
|
//printf("MOVX R%d, BYTE [%.4X]\n",byte_val,word_val);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
Move word from memory to register
|
||||||
|
14 03 50 00 => MOV R3,WORD [0050]
|
||||||
|
14 00 00 01 => MOV R0,WORD [0100]
|
||||||
|
*/
|
||||||
|
case 0x14 :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if(byte_val > 3)
|
||||||
|
goto exception;
|
||||||
|
word_val = *(WORD*)&AS->data[Regs->IP];
|
||||||
|
Regs->IP += 2;
|
||||||
|
if(word_val >= sizeof(AS->data))
|
||||||
|
goto exception;
|
||||||
|
Regs->GPRs[byte_val] = *(WORD*)&AS->data[word_val];
|
||||||
|
//printf("MOV R%d, WORD [%.4X]\n",byte_val,word_val);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
Move and extend byte to register
|
||||||
|
16 01 15 => MOVX R1,15h
|
||||||
|
*/
|
||||||
|
case 0x16 :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if(byte_val > 3)
|
||||||
|
goto exception;
|
||||||
|
Regs->GPRs[byte_val] = 0;
|
||||||
|
*(BYTE*)&Regs->GPRs[byte_val] = AS->data[Regs->IP++];
|
||||||
|
//printf("MOVX R%d,%.2Xh\n",byte_val,AS->data[Regs->IP - 1]);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
Move word to register
|
||||||
|
18 01 15 28 => MOV R1,2815h
|
||||||
|
*/
|
||||||
|
case 0x18 :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if(byte_val > 3)
|
||||||
|
goto exception;
|
||||||
|
Regs->GPRs[byte_val] = 0;
|
||||||
|
Regs->GPRs[byte_val] = *(WORD*)&AS->data[Regs->IP];
|
||||||
|
//printf("MOV R%d,%.4Xh\n",byte_val,*(WORD*)&AS->data[Regs->IP]);
|
||||||
|
Regs->IP += sizeof(WORD);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
Move byte from register to memory location
|
||||||
|
ex :
|
||||||
|
1C 01 20 01 => MOV BYTE [0120],R1
|
||||||
|
1C 03 50 03 => MOV BYTE [0350],R3
|
||||||
|
*/
|
||||||
|
case 0x1c :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if(byte_val > 3)
|
||||||
|
goto exception;
|
||||||
|
word_val = *(WORD*)&AS->data[Regs->IP];
|
||||||
|
Regs->IP += 2;
|
||||||
|
if(word_val >= sizeof(AS->data))
|
||||||
|
goto exception;
|
||||||
|
AS->data[word_val] = *(BYTE*)&Regs->GPRs[byte_val];
|
||||||
|
//printf("MOV BYTE [%.4X],R%d\n",word_val,byte_val);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
Move word from register to memory location
|
||||||
|
ex :
|
||||||
|
1F 01 20 01 => MOV WORD [0120],R1
|
||||||
|
1F 03 50 03 => MOV WORD [0350],R3
|
||||||
|
*/
|
||||||
|
case 0x1f :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if(byte_val > 3)
|
||||||
|
goto exception;
|
||||||
|
word_val = *(WORD*)&AS->data[Regs->IP];
|
||||||
|
Regs->IP += 2;
|
||||||
|
if(word_val >= sizeof(AS->data))
|
||||||
|
goto exception;
|
||||||
|
*(WORD*)&AS->data[word_val] = Regs->GPRs[byte_val];
|
||||||
|
//printf("MOV WORD [%.4X],R%d\n",word_val,byte_val);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
Unconditional Jump
|
||||||
|
example :
|
||||||
|
E0 10 00 => JMP 0010
|
||||||
|
E0 54 02 => JMP 0254
|
||||||
|
*/
|
||||||
|
case 0xE0 :
|
||||||
|
word_val = *(WORD*)&AS->data[Regs->IP];
|
||||||
|
Regs->IP += 2;
|
||||||
|
if(word_val > sizeof(AS->data))
|
||||||
|
goto exception;
|
||||||
|
Regs->IP = word_val;
|
||||||
|
//printf("JMP %.4X\n",word_val);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
JZ : Jump if equal
|
||||||
|
E2 54 01 =>JNZ 0154
|
||||||
|
*/
|
||||||
|
case 0xE2 :
|
||||||
|
word_val = *(WORD*)&AS->data[Regs->IP];
|
||||||
|
Regs->IP += 2;
|
||||||
|
if(word_val > sizeof(AS->data))
|
||||||
|
goto exception;
|
||||||
|
/*Jump if ZF is set*/
|
||||||
|
if(Regs->ZF)
|
||||||
|
Regs->IP = word_val;
|
||||||
|
//printf("JZ %.4X\n",word_val);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
JNZ : Jump if not equal
|
||||||
|
E3 54 01 => JNZ 0154
|
||||||
|
*/
|
||||||
|
case 0xE3 :
|
||||||
|
word_val = *(WORD*)&AS->data[Regs->IP];
|
||||||
|
Regs->IP += 2;
|
||||||
|
if(word_val > sizeof(AS->data))
|
||||||
|
goto exception;
|
||||||
|
if(! Regs->ZF)
|
||||||
|
Regs->IP = word_val;
|
||||||
|
//printf("JNZ %.4X\n",word_val);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
JAE : Jump if above or equal
|
||||||
|
E4 54 01 : JAE 0154
|
||||||
|
*/
|
||||||
|
case 0xE4 :
|
||||||
|
word_val = *(WORD*)&AS->data[Regs->IP];
|
||||||
|
Regs->IP += 2;
|
||||||
|
if(word_val > sizeof(AS->data))
|
||||||
|
goto exception;
|
||||||
|
if(Regs->ZF || ! Regs->CF)
|
||||||
|
Regs->IP = word_val;
|
||||||
|
//printf("JAE %.4X\n",word_val);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
JBE : Jump if below or equal
|
||||||
|
E6 54 01 : JBE 0154
|
||||||
|
*/
|
||||||
|
case 0xE6 :
|
||||||
|
word_val = *(WORD*)&AS->data[Regs->IP];
|
||||||
|
Regs->IP += 2;
|
||||||
|
if(word_val > sizeof(AS->data))
|
||||||
|
goto exception;
|
||||||
|
if(Regs->ZF || Regs->CF)
|
||||||
|
Regs->IP = word_val;
|
||||||
|
//printf("JBE %.4X\n",word_val);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
JB : Jump if below
|
||||||
|
E8 54 01 : JB 0154
|
||||||
|
*/
|
||||||
|
case 0xE8 :
|
||||||
|
word_val = *(WORD*)&AS->data[Regs->IP];
|
||||||
|
Regs->IP += 2;
|
||||||
|
if(word_val > sizeof(AS->data))
|
||||||
|
goto exception;
|
||||||
|
if(Regs->CF && ! Regs->ZF)
|
||||||
|
Regs->IP = word_val;
|
||||||
|
//printf("JB %.4X\n",word_val);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
JA : Jump if above
|
||||||
|
EC 54 01 => JA 0154
|
||||||
|
*/
|
||||||
|
case 0xEC :
|
||||||
|
word_val = *(WORD*)&AS->data[Regs->IP];
|
||||||
|
Regs->IP += 2;
|
||||||
|
if(word_val > sizeof(AS->data))
|
||||||
|
goto exception;
|
||||||
|
if( ! Regs->CF && ! Regs->ZF)
|
||||||
|
Regs->IP = word_val;
|
||||||
|
//printf("JA %.4X\n",word_val);
|
||||||
|
break;
|
||||||
|
/*=======================================================*/
|
||||||
|
/*ARITHMETIC OPERATIONS ON THE WHOLE REGISTER (WORD)*/
|
||||||
|
/*
|
||||||
|
ADD : Add value to register
|
||||||
|
AD 01 15 00 : ADD R1,15h
|
||||||
|
AD 01 01 50 : ADD R1,5001h
|
||||||
|
|
||||||
|
Updated flags :
|
||||||
|
ZF and CF
|
||||||
|
*/
|
||||||
|
case 0xAD :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if(byte_val > 3)
|
||||||
|
goto exception;
|
||||||
|
word_val = *(WORD*)&AS->data[Regs->IP];
|
||||||
|
Regs->IP += 2;
|
||||||
|
word_val2 = Regs->GPRs[byte_val] + word_val;
|
||||||
|
if(word_val2 == 0)
|
||||||
|
Regs->ZF = 1;
|
||||||
|
else
|
||||||
|
Regs->ZF = 0;
|
||||||
|
if(word_val2 < Regs->GPRs[byte_val])
|
||||||
|
Regs->CF = 1;
|
||||||
|
else
|
||||||
|
Regs->CF = 0;
|
||||||
|
Regs->GPRs[byte_val] = word_val2;
|
||||||
|
//printf("ADD R%d,%.4X\n",byte_val,word_val);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
ADD : Add 2 registers
|
||||||
|
A5 12 : ADD R1,R2
|
||||||
|
A5 30 : ADD R3,R0
|
||||||
|
*/
|
||||||
|
case 0xA5 :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3)
|
||||||
|
{
|
||||||
|
word_val = Regs->GPRs[(byte_val & 0xF0)>>4];
|
||||||
|
word_val2 = Regs->GPRs[(byte_val & 0xF0)>>4] += Regs->GPRs[byte_val & 0x0F];
|
||||||
|
if(word_val2 == 0)
|
||||||
|
Regs->ZF = 1;
|
||||||
|
else
|
||||||
|
Regs->ZF = 0;
|
||||||
|
if(word_val2 < word_val)
|
||||||
|
Regs->CF = 1;
|
||||||
|
else
|
||||||
|
Regs->CF = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto exception;
|
||||||
|
//printf("ADD R%d,R%d\n",(byte_val & 0xF0)>>4,byte_val & 0x0F);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
ADDL : Add 2 registers (low byte)
|
||||||
|
A2 12 => ADDL R1,R2
|
||||||
|
*/
|
||||||
|
case 0xA2 :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3)
|
||||||
|
{
|
||||||
|
byte_val2 = *(BYTE*)&Regs->GPRs[(byte_val & 0xF0)>>4];
|
||||||
|
byte_val3 = *(BYTE*)&Regs->GPRs[(byte_val & 0xF0)>>4] += *(BYTE*)&Regs->GPRs[byte_val & 0x0F];
|
||||||
|
if(byte_val3 == 0)
|
||||||
|
Regs->ZF = 1;
|
||||||
|
else
|
||||||
|
Regs->ZF = 0;
|
||||||
|
if(byte_val3 < byte_val2)
|
||||||
|
Regs->CF = 1;
|
||||||
|
else
|
||||||
|
Regs->CF = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto exception;
|
||||||
|
//printf("ADDL R%d,R%d\n",(byte_val & 0xF0)>>4,byte_val & 0x0F);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
SUB : substract value from register
|
||||||
|
5B 01 15 00 : SUB R1,15h
|
||||||
|
5B 01 01 50 : SUB R1,5001h
|
||||||
|
|
||||||
|
Updated flags :
|
||||||
|
ZF and CF
|
||||||
|
*/
|
||||||
|
case 0x5B :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if(byte_val > 3)
|
||||||
|
goto exception;
|
||||||
|
word_val = *(WORD*)&AS->data[Regs->IP];
|
||||||
|
Regs->IP += 2;
|
||||||
|
word_val2 = Regs->GPRs[byte_val] - word_val;
|
||||||
|
if(word_val2 == 0)
|
||||||
|
Regs->ZF = 1;
|
||||||
|
else
|
||||||
|
Regs->ZF = 0;
|
||||||
|
if(word_val2 > Regs->GPRs[byte_val])
|
||||||
|
Regs->CF = 1;
|
||||||
|
else
|
||||||
|
Regs->CF = 0;
|
||||||
|
Regs->GPRs[byte_val] = word_val2;
|
||||||
|
//printf("SUB R%d,%.4X\n",byte_val,word_val);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
SUB : substract registers (word)
|
||||||
|
5C 01 => SUB R0,R1
|
||||||
|
*/
|
||||||
|
case 0x5C :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3)
|
||||||
|
{
|
||||||
|
word_val = Regs->GPRs[(byte_val & 0xF0)>>4];
|
||||||
|
word_val2 = Regs->GPRs[(byte_val & 0xF0)>>4] -= Regs->GPRs[byte_val & 0x0F];
|
||||||
|
if(word_val2 == 0)
|
||||||
|
Regs->ZF = 1;
|
||||||
|
else
|
||||||
|
Regs->ZF = 0;
|
||||||
|
if(word_val2 > word_val)
|
||||||
|
Regs->CF = 1;
|
||||||
|
else
|
||||||
|
Regs->CF = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto exception;
|
||||||
|
//printf("SUB R%d,R%d",(byte_val & 0xF0)>>4,byte_val & 0x0F);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
SUBL : Substract 2 registers (low part)
|
||||||
|
5D 12 => SUBL R1,R2
|
||||||
|
*/
|
||||||
|
case 0x5D :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3)
|
||||||
|
{
|
||||||
|
byte_val2 = *(BYTE*)&Regs->GPRs[(byte_val & 0xF0)>>4];
|
||||||
|
byte_val3 = *(BYTE*)&Regs->GPRs[(byte_val & 0xF0)>>4] -= *(BYTE*)&Regs->GPRs[byte_val & 0x0F];
|
||||||
|
if(byte_val3 == 0)
|
||||||
|
Regs->ZF = 1;
|
||||||
|
else
|
||||||
|
Regs->ZF = 0;
|
||||||
|
if(byte_val3 > byte_val2)
|
||||||
|
Regs->CF = 1;
|
||||||
|
else
|
||||||
|
Regs->CF = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto exception;
|
||||||
|
//printf("SUBL R%d,R%d",(byte_val & 0xF0)>>4,byte_val & 0x0F);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
XOR : Xor 2 registers
|
||||||
|
(operand uses nibbles : high = dest , low = source)
|
||||||
|
F0 12 => XOR R1,R2
|
||||||
|
F0 01 => XOR R0,R1
|
||||||
|
*/
|
||||||
|
case 0xF0 :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3)
|
||||||
|
{
|
||||||
|
word_val = Regs->GPRs[(byte_val & 0xF0)>>4] ^= Regs->GPRs[byte_val & 0x0F];
|
||||||
|
if(word_val == 0)
|
||||||
|
Regs->ZF = 1;
|
||||||
|
else
|
||||||
|
Regs->ZF = 0;
|
||||||
|
Regs->CF = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto exception;
|
||||||
|
//printf("XOR R%d,R%d\n",(byte_val & 0xF0)>>4,byte_val & 0x0F);
|
||||||
|
break;
|
||||||
|
/*===============================================================*/
|
||||||
|
/*ARITHMETIC OPERATIONS ON THE LOWER BYTE OF THE REGISTER*/
|
||||||
|
/*
|
||||||
|
XORL : Xor the lower bytes of 2 registers
|
||||||
|
F1 12 : XORL R1,R2
|
||||||
|
F1 01 : XORL R0,R1
|
||||||
|
*/
|
||||||
|
case 0xF1 :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3)
|
||||||
|
{
|
||||||
|
byte_val2 = *(BYTE*)&Regs->GPRs[(byte_val & 0xF0)>>4] ^= *(BYTE*)&Regs->GPRs[byte_val & 0x0F];
|
||||||
|
if(byte_val2 == 0)
|
||||||
|
Regs->ZF = 1;
|
||||||
|
else
|
||||||
|
Regs->ZF = 0;
|
||||||
|
Regs->CF = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto exception;
|
||||||
|
//printf("XORL R%d,R%d\n",(byte_val & 0xF0)>>4,byte_val & 0x0F);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
ADDL : add only to the lower of the register
|
||||||
|
A1 03 20 => ADDL R3,20h
|
||||||
|
*/
|
||||||
|
case 0xA1:
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if(byte_val > 3)
|
||||||
|
goto exception;
|
||||||
|
byte_val2 = AS->data[Regs->IP++];
|
||||||
|
byte_val3 = *(BYTE*)&Regs->GPRs[byte_val] + byte_val2;
|
||||||
|
if(byte_val3 == 0)
|
||||||
|
Regs->ZF = 1;
|
||||||
|
else
|
||||||
|
Regs->ZF = 0;
|
||||||
|
if(byte_val3 < *(BYTE*)&Regs->GPRs[byte_val])
|
||||||
|
Regs->CF = 1;
|
||||||
|
else
|
||||||
|
Regs->CF = 0;
|
||||||
|
*(BYTE*)&Regs->GPRs[byte_val] = byte_val3;
|
||||||
|
//printf("ADDL R%d,%.2X\n",byte_val,byte_val2);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
SUBL : Substract only from the lower byte of the register
|
||||||
|
51 03 20 => SUBL R3,20h
|
||||||
|
*/
|
||||||
|
case 0x51:
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if(byte_val > 3)
|
||||||
|
goto exception;
|
||||||
|
byte_val2 = AS->data[Regs->IP++];
|
||||||
|
byte_val3 = *(BYTE*)&Regs->GPRs[byte_val] - byte_val2;
|
||||||
|
if(byte_val3 == 0)
|
||||||
|
Regs->ZF = 1;
|
||||||
|
else
|
||||||
|
Regs->ZF = 0;
|
||||||
|
if(byte_val3 > *(BYTE*)&Regs->GPRs[byte_val])
|
||||||
|
Regs->CF = 1;
|
||||||
|
else
|
||||||
|
Regs->CF = 0;
|
||||||
|
*(BYTE*)&Regs->GPRs[byte_val] = byte_val3;
|
||||||
|
//printf("SUBL R%d,%.2X\n",byte_val,byte_val2);
|
||||||
|
break;
|
||||||
|
/*===============================================================*/
|
||||||
|
/*
|
||||||
|
Store register (low byte) at [Rx].
|
||||||
|
55 21 => MOV BYTE [R2],R1
|
||||||
|
*/
|
||||||
|
case 0x55 :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3 && Regs->GPRs[(byte_val & 0xF0)>>4] < sizeof(AS->data))
|
||||||
|
AS->data[Regs->GPRs[(byte_val & 0xF0)>>4]] = *(BYTE*)&Regs->GPRs[byte_val & 0x0F];
|
||||||
|
else
|
||||||
|
goto exception;
|
||||||
|
//printf("MOV BYTE [R%d],R%d\n",(byte_val & 0xF0)>>4,byte_val & 0x0F);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
Load and extend low byte of register from memory pointed by a register
|
||||||
|
56 21 => MOV R2,BYTE [R1]
|
||||||
|
*/
|
||||||
|
case 0x56 :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3 && Regs->GPRs[(byte_val & 0x0F)] < sizeof(AS->data))
|
||||||
|
{
|
||||||
|
*(BYTE*)&Regs->GPRs[(byte_val & 0xF0)>>4] = AS->data[Regs->GPRs[byte_val & 0x0F]];
|
||||||
|
Regs->GPRs[(byte_val & 0xF0)>>4] &= 0xFF;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto exception;
|
||||||
|
//printf("MOVX R%d, BYTE [R%d]\n",(byte_val & 0xF0)>>4,byte_val & 0x0F);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
CMP : Compare 2 registers (word)
|
||||||
|
70 12 : CMP R1,R2
|
||||||
|
*/
|
||||||
|
case 0x70 :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3 && Regs->GPRs[(byte_val & 0x0F)] < sizeof(AS->data))
|
||||||
|
{
|
||||||
|
word_val = Regs->GPRs[(byte_val & 0xF0)>>4];
|
||||||
|
word_val2 = Regs->GPRs[byte_val & 0x0F];
|
||||||
|
if(word_val2 == word_val)
|
||||||
|
Regs->ZF = 1;
|
||||||
|
else
|
||||||
|
Regs->ZF = 0;
|
||||||
|
if(word_val2 > word_val)
|
||||||
|
Regs->CF = 1;
|
||||||
|
else
|
||||||
|
Regs->CF = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto exception;
|
||||||
|
//printf("CMP R%d,R%d\n",(byte_val & 0xF0)>>4,byte_val & 0x0F);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
CMPL : Compare 2 registers (lower byte)
|
||||||
|
71 12 : CMPL R1,R2
|
||||||
|
*/
|
||||||
|
case 0x71 :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if((byte_val & 0xF0) <= 0x30 && (byte_val & 0x0F) <= 3 && Regs->GPRs[(byte_val & 0x0F)] < sizeof(AS->data))
|
||||||
|
{
|
||||||
|
byte_val2 = *(BYTE*)&Regs->GPRs[(byte_val & 0xF0)>>4];
|
||||||
|
byte_val3 = *(BYTE*)&Regs->GPRs[byte_val & 0x0F];
|
||||||
|
if(byte_val3 == byte_val2)
|
||||||
|
Regs->ZF = 1;
|
||||||
|
else
|
||||||
|
Regs->ZF = 0;
|
||||||
|
if(byte_val3 > byte_val2)
|
||||||
|
Regs->CF = 1;
|
||||||
|
else
|
||||||
|
Regs->CF = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto exception;
|
||||||
|
//printf("CMP R%d,R%d\n",(byte_val & 0xF0)>>4,byte_val & 0x0F);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
Push register
|
||||||
|
example : AF 01 => PUSH R1
|
||||||
|
*/
|
||||||
|
case 0xAF :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if(byte_val > 3)
|
||||||
|
goto exception;
|
||||||
|
/*Decrement the stack pointer to store the new value*/
|
||||||
|
Regs->SP--;
|
||||||
|
/*Check for stack overflow*/
|
||||||
|
if(Regs->SP == 0xFFFF)
|
||||||
|
goto exception;
|
||||||
|
/*Push value */
|
||||||
|
AS->stack[Regs->SP] = Regs->GPRs[byte_val];
|
||||||
|
//printf("PUSH R%d\n",byte_val);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
Pop a register
|
||||||
|
AE 01 => POP R1
|
||||||
|
*/
|
||||||
|
case 0xAE :
|
||||||
|
byte_val = AS->data[Regs->IP++];
|
||||||
|
if(byte_val > 3)
|
||||||
|
goto exception;
|
||||||
|
/*
|
||||||
|
Check for stack underflow
|
||||||
|
*/
|
||||||
|
if(&AS->stack[Regs->SP] == &AS->stack[sizeof(AS->stack)/sizeof(WORD)])
|
||||||
|
goto exception;
|
||||||
|
/*Move the value into the register*/
|
||||||
|
Regs->GPRs[byte_val] = AS->stack[Regs->SP];
|
||||||
|
/*Value popped , increment SP*/
|
||||||
|
Regs->SP++;
|
||||||
|
//printf("POP R%d\n",byte_val);
|
||||||
|
break;
|
||||||
|
/*========================================================*/
|
||||||
|
/*User interaction operations (print and receive input)*/
|
||||||
|
/*
|
||||||
|
Print Word to user as integer, the value must be at the top of the stack and it is popped
|
||||||
|
C0 => print integer
|
||||||
|
*/
|
||||||
|
case 0xC0 :
|
||||||
|
/*read value then pop it*/
|
||||||
|
if(&AS->stack[Regs->SP] == &AS->stack[sizeof(AS->stack)/sizeof(WORD)])
|
||||||
|
goto exception;
|
||||||
|
word_val = AS->stack[Regs->SP++];
|
||||||
|
//printf("Print integer\n");
|
||||||
|
printf("%u\n",word_val);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
Print string to user, the pointer must be at the top of the stack and it is popped
|
||||||
|
C2 => print string
|
||||||
|
*/
|
||||||
|
case 0xC2 :
|
||||||
|
if(&AS->stack[Regs->SP] == &AS->stack[sizeof(AS->stack)/sizeof(WORD)])
|
||||||
|
goto exception;
|
||||||
|
/*read it and pop it*/
|
||||||
|
word_val = AS->stack[Regs->SP++];
|
||||||
|
if(word_val > sizeof(AS->data))
|
||||||
|
goto exception;
|
||||||
|
//printf("Print string\n");
|
||||||
|
printf("%s",&AS->data[word_val]);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
Scan string from user, the pointer where to store the integer must be on top of the stack
|
||||||
|
89
|
||||||
|
*/
|
||||||
|
case 0x89 :
|
||||||
|
if(&AS->stack[Regs->SP] == &AS->stack[sizeof(AS->stack)/sizeof(WORD)])
|
||||||
|
goto exception;
|
||||||
|
/*read it and pop it*/
|
||||||
|
word_val = AS->stack[Regs->SP++];
|
||||||
|
if(word_val > sizeof(AS->data))
|
||||||
|
goto exception;
|
||||||
|
//printf("Scan string\n");
|
||||||
|
//printf(" [+] Input : ");
|
||||||
|
gets((char*)&AS->data[word_val]);
|
||||||
|
break;
|
||||||
|
/*=======================================================*/
|
||||||
|
/*0xDB Debugging Only*/
|
||||||
|
/*
|
||||||
|
case 0xDB :
|
||||||
|
printf("\n===Debug Information Start===\n");
|
||||||
|
printf("+ Registers :\n");
|
||||||
|
for(i=0;i<=3;i++)
|
||||||
|
printf(" R%d : 0x%.4X\n",i,Regs->GPRs[i]);
|
||||||
|
printf(" IP : 0x%.4X\n",Regs->IP);
|
||||||
|
printf(" SP : 0x%.4X\n",Regs->SP*sizeof(WORD));
|
||||||
|
printf("+ Current Stack : (Top 4 values)\n");
|
||||||
|
if(Regs->SP == sizeof(AS->stack)/sizeof(WORD))
|
||||||
|
{
|
||||||
|
printf(" The stack is empty.\n");
|
||||||
|
goto loc;
|
||||||
|
}
|
||||||
|
for(i=0;i<4;i++)
|
||||||
|
{
|
||||||
|
if(Regs->SP + i < sizeof(AS->stack)/sizeof(WORD))
|
||||||
|
printf(" SP+%d => 0x%.4X : %.4X\n",i*2,(Regs->SP + i)*2,AS->stack[Regs->SP+i]);
|
||||||
|
}
|
||||||
|
loc:
|
||||||
|
printf("+Flags Information :\n");
|
||||||
|
printf(" Flags = 0x%.2X\n",Regs->Flags);
|
||||||
|
printf(" ZF = %d\n",Regs->ZF);
|
||||||
|
printf(" CF = %d\n",Regs->CF);
|
||||||
|
printf("===Debug Information End ===\n\n");
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
/*======================================================*/
|
||||||
|
case 0xED :
|
||||||
|
//printf("Exit\n");
|
||||||
|
exit = TRUE;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
exception:
|
||||||
|
//printf("\n==Exception : ...Exiting==\n");
|
||||||
|
exit = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
PADDRESS_SPACE AS;
|
||||||
|
PREGS Regs;
|
||||||
|
int size;
|
||||||
|
FILE* File;
|
||||||
|
//printf("DEBUG INFO :");
|
||||||
|
//printf("Allocating Address Space\n");
|
||||||
|
AS = (PADDRESS_SPACE) malloc(sizeof(ADDRESS_SPACE));
|
||||||
|
//printf("Allocating Registers\n");
|
||||||
|
Regs = (PREGS) malloc(sizeof(REGS));
|
||||||
|
//printf("Initializing Registers\n");
|
||||||
|
Regs->IP = 0;
|
||||||
|
Regs->SP = sizeof(AS->stack) / sizeof(WORD);
|
||||||
|
Regs->Flags = 0;
|
||||||
|
/*Open code and data file and read it into */
|
||||||
|
File = fopen("vm_file","rb");
|
||||||
|
if(!File)
|
||||||
|
{
|
||||||
|
printf("Found trouble opening the file");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*Check the file size*/
|
||||||
|
fseek(File,0,SEEK_END);
|
||||||
|
size = ftell(File);
|
||||||
|
if( size > sizeof(AS->data))
|
||||||
|
{
|
||||||
|
printf("File size is larger than the storage available for data and code");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rewind(File);
|
||||||
|
/*Copy the file to our VM address space*/
|
||||||
|
fread(AS->data,1,size,File);
|
||||||
|
fclose(File);
|
||||||
|
//printf("Starting Execution\n");
|
||||||
|
VmLoop(AS,Regs);
|
||||||
|
_getch();
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user