summaryrefslogtreecommitdiff
path: root/src/pim/Machine.cpp
diff options
context:
space:
mode:
authorSimon Robertshaw <simon@hardwired.org.uk>2012-11-17 19:44:09 (GMT)
committer Simon Robertshaw <simon@hardwired.org.uk>2012-11-17 19:44:09 (GMT)
commit058a2edd75debbd0297f92572316daa704bd379f (patch)
treead303f091f9a08b209b91eb34a9fcad996a3de69 /src/pim/Machine.cpp
parente3594aba9e05c6865d396418c028049cda92c2f3 (diff)
parent7a21ae192fe19868539956f3fe28e62b2c7c4429 (diff)
downloadpowder-058a2edd75debbd0297f92572316daa704bd379f.zip
powder-058a2edd75debbd0297f92572316daa704bd379f.tar.gz
Merge branch 'master' of github.com:FacialTurd/PowderToypp
Diffstat (limited to 'src/pim/Machine.cpp')
-rw-r--r--src/pim/Machine.cpp637
1 files changed, 637 insertions, 0 deletions
diff --git a/src/pim/Machine.cpp b/src/pim/Machine.cpp
new file mode 100644
index 0000000..a954d31
--- /dev/null
+++ b/src/pim/Machine.cpp
@@ -0,0 +1,637 @@
+//Virtual machine
+
+#include <iostream>
+#include "Machine.h"
+#include "Opcodes.h"
+#include "simulation/Simulation.h"
+namespace pim
+{
+ /*unsigned char * rom;
+ int romSize;
+ int romMask;
+
+ unsigned char * ram;
+ int ramSize;
+ int ramMask;
+
+ int programStack;
+ int callStack;*/
+
+ VirtualMachine::VirtualMachine(Simulation * simulation) :
+ rom(NULL),
+ ram(NULL),
+ sim(simulation)
+ {
+
+ }
+
+ void VirtualMachine::LoadProgram(std::vector<unsigned char> fileData)
+ {
+ int lastBit = 0;
+
+ if(!(fileData[0] == 'P' && fileData[1] == 'V' && fileData[2] == 'M' && fileData[3] == '1' && fileData.size() >= 16))
+ {
+ throw InvalidProgramException();
+ }
+
+ int macroSize = 0, propSize = 0, codeSize = 0;
+ macroSize = fileData[4];
+ macroSize |= fileData[5] << 8;
+ macroSize |= fileData[6] << 16;
+ macroSize |= fileData[7] << 24;
+
+ propSize = fileData[8];
+ propSize |= fileData[9] << 8;
+ propSize |= fileData[10] << 16;
+ propSize |= fileData[11] << 24;
+
+ codeSize = fileData[12];
+ codeSize |= fileData[13] << 8;
+ codeSize |= fileData[14] << 16;
+ codeSize |= fileData[15] << 24;
+
+ if(fileData.size() < 16 + macroSize + propSize + codeSize)
+ {
+ throw InvalidProgramException();
+ }
+
+ //std::vector<std::pair<int, int> > insertions;
+
+ int macroOffset = 16;
+ int propOffset = macroOffset+macroSize;
+ int codeOffset = propOffset+propSize;
+
+
+ int filePosition = macroOffset;
+ while(filePosition + 4 < macroSize + macroOffset)
+ {
+ std::string macro;
+ int macroPosition;
+ int macroValue;
+
+ macroPosition = fileData[filePosition++];
+ macroPosition |= fileData[filePosition++] << 8;
+ macroPosition |= fileData[filePosition++] << 16;
+ macroPosition |= fileData[filePosition++] << 24;
+
+ int stringLength = fileData[filePosition++];
+ if(filePosition + stringLength > macroSize + macroOffset)
+ {
+ throw InvalidProgramException();
+ }
+
+ macro.insert(macro.begin(), fileData.begin()+filePosition, fileData.begin()+filePosition+stringLength);
+ filePosition += stringLength;
+
+ bool resolved = false;
+ for(int i = 0; i < PT_NUM; i++)
+ {
+ if(sim->elements[i].Enabled && sim->elements[i].Identifier == macro)
+ {
+ macroValue = i;
+ resolved = true;
+ }
+ }
+ if(!resolved)
+ {
+ throw UnresolvedValueException(macro);
+ }
+
+ if(macroPosition + 3 >= codeSize)
+ {
+ throw InvalidProgramException();
+ }
+
+ std::cout << "Macro insertion [" << macro << "] at " << macroPosition << " with " << macroValue << std::endl;
+
+ fileData[codeOffset+macroPosition] = macroValue & 0xFF;
+ fileData[codeOffset+macroPosition+1] = (macroValue >> 8) & 0xFF;
+ fileData[codeOffset+macroPosition+2] = (macroValue >> 16) & 0xFF;
+ fileData[codeOffset+macroPosition+3] = (macroValue >> 24) & 0xFF;
+ //insertions.push_back(std::pair<int, int>(macroPosition, macroValue));
+ }
+
+ filePosition = propOffset;
+ while(filePosition + 4 < propSize + propOffset)
+ {
+ std::string prop;
+ int propPosition;
+ int propValue;
+
+ propPosition = fileData[filePosition++];
+ propPosition |= fileData[filePosition++] << 8;
+ propPosition |= fileData[filePosition++] << 16;
+ propPosition |= fileData[filePosition++] << 24;
+
+ int stringLength = fileData[filePosition++];
+ if(filePosition + stringLength > propSize + propOffset)
+ {
+ throw InvalidProgramException();
+ }
+
+ prop.insert(prop.begin(), fileData.begin()+filePosition, fileData.begin()+filePosition+stringLength);
+ filePosition += stringLength;
+
+ bool resolved = false;
+
+ std::vector<StructProperty> properties = Particle::GetProperties();
+ for(std::vector<StructProperty>::iterator iter = properties.begin(), end = properties.end(); iter != end; ++iter)
+ {
+ StructProperty property = *iter;
+ std::cout << property.Offset << std::endl;
+ if(property.Name == prop &&
+ (property.Type == StructProperty::ParticleType ||
+ property.Type == StructProperty::Colour ||
+ property.Type == StructProperty::Integer ||
+ property.Type == StructProperty::UInteger ||
+ property.Type == StructProperty::Float)
+ )
+ {
+ propValue = property.Offset;
+ resolved = true;
+ break;
+ }
+ }
+ if(!resolved)
+ {
+ throw UnresolvedValueException(prop);
+ }
+
+ if(propPosition + 3 >= codeSize)
+ {
+ throw InvalidProgramException();
+ }
+
+ std::cout << "Property insertion [" << prop << "] at " << propPosition << " with " << propValue << std::endl;
+
+ fileData[codeOffset+propPosition] = propValue & 0xFF;
+ fileData[codeOffset+propPosition+1] = (propValue >> 8) & 0xFF;
+ fileData[codeOffset+propPosition+2] = (propValue >> 16) & 0xFF;
+ fileData[codeOffset+propPosition+3] = (propValue >> 24) & 0xFF;
+ //insertions.push_back(std::pair<int, int>(macroPosition, macroValue));
+ }
+
+ std::vector<unsigned char> programData;
+ programData.insert(programData.begin(), fileData.begin()+codeOffset, fileData.begin()+codeOffset+codeSize);
+
+ romSize = programData.size();
+
+ for (lastBit = 0; romSize > (1 << lastBit); lastBit++ ) { }
+ romSize = 1 << lastBit;
+ romMask = romSize - 1;
+
+ rom = new Instruction[romSize];
+
+ int pc = 0;
+ int programPosition = 0;
+
+ while(programPosition < programData.size())
+ {
+ int argSize = 0;
+ Instruction instruction;
+ instruction.Opcode = programData[programPosition++];
+ if(argSize = OpcodeArgSize(instruction.Opcode))
+ {
+ if(argSize == 4 && programPosition+3 < programData.size())
+ {
+ int tempInt = 0;
+ tempInt |= programData[programPosition];
+ tempInt |= programData[programPosition+1] << 8;
+ tempInt |= programData[programPosition+2] << 16;
+ tempInt |= programData[programPosition+3] << 24;
+
+
+ std::cout << "Got integer " << tempInt << std::endl;
+
+ if(instruction.Opcode == Opcode::LoadProperty || instruction.Opcode == Opcode::StoreProperty)
+ {
+ if(tempInt > offsetof(Particle, dcolour))
+ throw InvalidProgramException();
+ }
+
+ instruction.Parameter.Integer = tempInt;
+
+ programPosition += 4;
+ }
+ }
+ else
+ {
+ instruction.Parameter.Integer = 0;
+ }
+ rom[pc++] = instruction;
+ }
+ romSize = pc;
+
+ ramSize = 1024;
+ ramMask = ramSize - 1;
+
+ ram = new unsigned char[ramSize];
+ programStack = ramSize-1;
+ callStack = ramSize-260;
+
+ framePointer = callStack;
+ callStack += WORDSIZE; //Since there's nothing on the stack, it shouldn't point to the item on the bottom
+ }
+
+ int VirtualMachine::OpcodeArgSize(int opcode)
+ {
+ switch(opcode)
+ {
+ case Opcode::Load:
+ case Opcode::Store:
+ case Opcode::Constant:
+ case Opcode::Increment:
+ case Opcode::JumpEqual:
+ case Opcode::JumpNotEqual:
+ case Opcode::JumpGreater:
+ case Opcode::JumpGreaterEqual:
+ case Opcode::JumpLess:
+ case Opcode::JumpLessEqual:
+ case Opcode::Jump:
+ case Opcode::Return:
+ case Opcode::LocalEnter:
+ case Opcode::LoadProperty:
+ case Opcode::StoreProperty:
+ return 4;
+ case Opcode::Discard:
+ case Opcode::Duplicate:
+ case Opcode::Add:
+ case Opcode::Subtract:
+ case Opcode::Multiply:
+ case Opcode::Divide:
+ case Opcode::Modulus:
+ case Opcode::Negate:
+ case Opcode::Create:
+ case Opcode::Transform:
+ case Opcode::Get:
+ case Opcode::Position:
+ case Opcode::Kill:
+ return 0;
+ }
+ }
+
+ void VirtualMachine::Run()
+ {
+ //std::cout << "CS: " << callStack << " PS: " << programStack << std::endl;
+ //std::string names[] = { "Load", "Store", "Constant", "Increment", "Discard", "Duplicate", "Add", "Subtract", "Multiply", "Divide", "Modulus", "Negate", "Create", "Transform", "Get", "Position", "Kill", "JumpEqual", "JumpNotEqual", "JumpGreater", "JumpGreaterEqual", "JumpLess", "JumpLessEqual", "Jump", "Return", "LocalEnter"};
+
+ Word temp1;
+ Word temp2;
+ Word temp3;
+ Word temp4;
+ int temp;
+ while(programCounter < romSize)
+ {
+ Word argument = rom[programCounter].Parameter;
+ //std::cerr << programCounter << "\t" << names[rom[programCounter].Opcode] << "\t" << argument.Integer << std::endl;//"\t";
+ switch(rom[programCounter].Opcode)
+ {
+ case Opcode::Load:
+ PSPush(CSA(argument.Integer));
+ break;
+ case Opcode::Store:
+ CSA(argument.Integer) = PSPop();
+ break;
+ case Opcode::Constant:
+ PSPush(argument);
+ break;
+ case Opcode::Increment:
+ PS().Integer += argument.Integer;
+ break;
+ case Opcode::Discard:
+ programStack += WORDSIZE;
+ break;
+ case Opcode::Duplicate:
+ PSPush(PS());
+ break;
+ case Opcode::Add:
+ PSPush(PSPop().Integer + PSPop().Integer);
+ break;
+ case Opcode::Subtract:
+ temp1 = PSPop();
+ PSPush(PSPop().Integer - temp1.Integer);
+ break;
+ case Opcode::Multiply:
+ PSPush(PSPop().Integer * PSPop().Integer);
+ break;
+ case Opcode::Divide:
+ temp1 = PSPop();
+ PSPush(PSPop().Integer / temp1.Integer);
+ break;
+ case Opcode::Modulus:
+ temp1 = PSPop();
+ PSPush(PSPop().Integer % temp1.Integer);
+ break;
+ case Opcode::Negate:
+ PS().Integer = -PS().Integer;
+ break;
+ case Opcode::Create:
+ temp1 = PSPop();
+ temp2 = PSPop();
+ temp3 = PSPop();
+ PSPush(sim->create_part(PSPop().Integer, temp3.Integer, temp2.Integer, temp1.Integer));
+ break;
+ case Opcode::Transform:
+ PSPop();
+ PSPop();
+ PSPush((Word)-1);
+ break;
+ case Opcode::Get:
+ temp1 = PSPop();
+ temp2 = PSPop();
+ if(temp1.Integer < 0 || temp1.Integer >= YRES || temp2.Integer < 0 || temp2.Integer >= XRES || !(temp = sim->pmap[temp1.Integer][temp2.Integer]))
+ {
+ PSPush(-1);
+ break;
+ }
+ PSPush(temp>>8);
+ break;
+ case Opcode::Position:
+ temp1 = PSPop();
+ if(temp1.Integer < 0 || temp1.Integer >= NPART || !sim->parts[temp1.Integer].type)
+ {
+ PSPush(-1);
+ PSPush(-1);
+ break;
+ }
+ PSPush((int)sim->parts[temp1.Integer].x);
+ PSPush((int)sim->parts[temp1.Integer].y);
+ break;
+ case Opcode::Kill:
+ sim->kill_part(PSPop().Integer);
+ PSPush((Word)0);
+ break;
+ case Opcode::LoadProperty:
+ PSPush(PPROP(PSPop().Integer, argument.Integer));
+ break;
+ case Opcode::StoreProperty:
+ temp1 = PSPop();
+ PPROP(temp1.Integer, argument.Integer) = PSPop();
+ break;
+ case Opcode::JumpEqual:
+ if(PSPop().Integer == PSPop().Integer)
+ programCounter = argument.Integer-1;
+ break;
+ case Opcode::JumpNotEqual:
+ if(PSPop().Integer != PSPop().Integer)
+ programCounter = argument.Integer-1;
+ break;
+ case Opcode::JumpGreater:
+ temp1 = PSPop();
+ if(PSPop().Integer > temp1.Integer)
+ programCounter = argument.Integer-1;
+ break;
+ case Opcode::JumpGreaterEqual:
+ temp1 = PSPop();
+ if(PSPop().Integer >= temp1.Integer)
+ programCounter = argument.Integer-1;
+ break;
+ case Opcode::JumpLess:
+ temp1 = PSPop();
+ if(PSPop().Integer < temp1.Integer)
+ programCounter = argument.Integer-1;
+ break;
+ case Opcode::JumpLessEqual:
+ temp1 = PSPop();
+ if(PSPop().Integer <= temp1.Integer)
+ programCounter = argument.Integer-1;
+ break;
+ case Opcode::Jump:
+ programCounter = argument.Integer-1;
+ break;
+ case Opcode::Return:
+ callStack += argument.Integer;
+ break;
+ case Opcode::LocalEnter:
+ callStack -= argument.Integer;
+ break;
+ }
+ //std::cout << programStack << std::endl;
+ programCounter++;
+ }
+ //std::cout << "CS: " << callStack << " PS: " << programStack << std::endl;
+ }
+
+ void VirtualMachine::Compile()
+ {
+ while(programCounter < romSize)
+ {
+ Word argument = rom[programCounter].Parameter;
+ switch(rom[programCounter].Opcode)
+ {
+ case Opcode::Load:
+ emit("83 EF 04"); //sub edi 4
+
+ //Load value at base stack + offset into eax
+ emit("8B 85"); //mov eax [ebp+ram+offset]
+ emit((intptr_t) (ram - argument.Integer));
+
+ //Store value in eax onto top of program stack
+ emit("89 07"); //mov [edi], eax
+ emit((intptr_t) (ram));
+ break;
+ case Opcode::Store:
+ //Load value on top of the program stack into eax
+ emit("8B 07"); //mov eax [edi]
+ emit((intptr_t) (ram));
+
+ //Load value in eax onto top of program stack
+ emit("89 85"); //mov [ebp+ram+offset], eax
+ emit((intptr_t) (ram - argument.Integer));
+
+ emit("83 C7 04"); //add edi 4
+ break;
+ case Opcode::Constant:
+ emit("83 EF 04"); //sub edi 4
+
+ emit("C7 07"); //mov [edi] constant
+ emit((int) (argument.Integer));
+ break;
+ case Opcode::Increment:
+ emit("81 07"); //add [edi] constant
+ emit((int) (argument.Integer));
+ break;
+ case Opcode::Discard:
+ emit("83 C7 04"); //add edi 4
+ break;
+ case Opcode::Duplicate:
+ //Copy value on stack into register
+ emit("8B 07"); //mov eax [edi]
+ //Adjust program stack pointer
+ emit("83 EF 04"); //sub edi 4
+ //Move value in eax into program stack
+ emit("89 07"); //mov [edi], eax
+ break;
+ case Opcode::Add:
+ emit("8B 07"); //mov eax [edi]
+ emit("01 47 04"); //add [edi+4] eax
+ emit("83 C7 04"); //add edi 4
+ break;
+ case Opcode::Subtract:
+ emit("8B 07"); //mov eax [edi]
+ emit("29 47 04"); //sub [edi+4] eax
+ emit("83 C7 04"); //add edi 4
+ break;
+ case Opcode::Multiply:
+ emit("8B 47 04"); //mov eax [edi+4]
+ emit("F7 2F"); //imul [edi]
+ emit("89 47 04"); //mov [edi+4] eax
+ emit("83 C7 04"); //add edi 4
+ break;
+ case Opcode::Divide:
+ emit("8B 47 04");//mov eax [edi+4]
+ emit("99"); //cdq
+ emit("F7 3F"); //idiv [edi]
+ emit("89 47 04"); //mov [edi+4] eax
+ emit("83 C7 04"); //add edi 4
+ break;
+ case Opcode::Modulus:
+ emit("8B 47 04"); // mov eax [edi+4]
+ emit("99"); // cdq
+ emit("F7 3F"); // idiv [edi]
+ emit("89 57 04"); // mov [edi+4] edx
+ emit("83 C7 04"); //add edi 4
+ break;
+ case Opcode::Negate:
+ emit("F7 1F"); //neg [edi]
+ break;
+ case Opcode::Create:
+ //temp1 = PSPop();
+ //temp2 = PSPop();
+ //temp3 = PSPop();
+ //PSPush(sim->create_part(PSPop().Integer, temp3.Integer, temp2.Integer, temp1.Integer));
+ break;
+ case Opcode::Transform:
+ //PSPop();
+ //PSPop();
+ //PSPush((Word)-1);
+ break;
+ case Opcode::Get:
+ //temp1 = PSPop();
+ //temp2 = PSPop();
+ //if(temp1.Integer < 0 || temp1.Integer >= YRES || temp2.Integer < 0 || temp2.Integer >= XRES || !(temp = sim->pmap[temp1.Integer][temp2.Integer]))
+ //{
+ // PSPush(-1);
+ // break;
+ //}
+ //PSPush(temp>>8);
+ break;
+ case Opcode::Position:
+ //temp1 = PSPop();
+ //if(temp1.Integer < 0 || temp1.Integer >= NPART || !sim->parts[temp1.Integer].type)
+ //{
+ // PSPush(-1);
+ // PSPush(-1);
+ // break;
+ //}
+ //PSPush((int)sim->parts[temp1.Integer].x);
+ //PSPush((int)sim->parts[temp1.Integer].y);
+ break;
+ case Opcode::Kill:
+ //sim->kill_part(PSPop().Integer);
+ //PSPush((Word)0);
+ break;
+ case Opcode::LoadProperty:
+ //PSPush(PPROP(PSPop().Integer, argument.Integer));
+ break;
+ case Opcode::StoreProperty:
+ //temp1 = PSPop();
+ //PPROP(temp1.Integer, argument.Integer) = PSPop();
+ break;
+ case Opcode::JumpEqual:
+ emit("83 C7 04"); //add edi 8
+ emit("8B 47 FC"); //mov eax, dword ptr [edi-4]
+ emit("3B 47 F7"); //cmp eax, dword ptr [edi-8]
+ emit("75 06"); //jne +6
+ emit("FF 25"); //jmp [0x12345678]
+ emit(0);
+ break;
+ case Opcode::JumpNotEqual:
+ emit("83 C7 04"); //add edi 8
+ emit("8B 47 FC"); //mov eax, dword ptr [edi-4]
+ emit("3B 47 F7"); //cmp eax, dword ptr [edi-8]
+ emit("74 06"); //je +6
+ emit("FF 25"); //jmp [0x12345678]
+ emit(0);
+ break;
+ case Opcode::JumpGreater:
+ emit("83 C7 04"); //add edi 8
+ emit("8B 47 FC"); //mov eax, dword ptr [edi-4]
+ emit("3B 47 F7"); //cmp eax, dword ptr [edi-8]
+ emit("7E 06"); //jng +6
+ emit("FF 25"); //jmp [0x12345678]
+ emit(0);
+ break;
+ case Opcode::JumpGreaterEqual:
+ emit("83 C7 04"); //add edi 8
+ emit("8B 47 FC"); //mov eax, dword ptr [edi-4]
+ emit("3B 47 F7"); //cmp eax, dword ptr [edi-8]
+ emit("7C 06"); //jnge +6
+ emit("FF 25"); //jmp [0x12345678]
+ emit(0);
+ break;
+ case Opcode::JumpLess:
+ emit("83 C7 04"); //add edi 8
+ emit("8B 47 FC"); //mov eax, dword ptr [edi-4]
+ emit("3B 47 F7"); //cmp eax, dword ptr [edi-8]
+ emit("7D 06"); //jnl +6
+ emit("FF 25"); //jmp [0x12345678]
+ emit(0);
+ break;
+ case Opcode::JumpLessEqual:
+ emit("83 C7 04"); //add edi 8
+ emit("8B 47 FC"); //mov eax, dword ptr [edi-4]
+ emit("3B 47 F7"); //cmp eax, dword ptr [edi-8]
+ emit("7F 06"); //jnle +6
+ emit("FF 25"); //jmp [0x12345678]
+ emit(0);
+ break;
+ case Opcode::Jump:
+ //programCounter = argument.Integer-1;
+ break;
+ case Opcode::Return:
+ emit("81 C6"); //add esi constant
+ emit(argument.Integer);
+ break;
+ case Opcode::LocalEnter:
+ emit("81 EE"); //sub esi constant
+ emit(argument.Integer);
+ break;
+ }
+ //std::cout << programStack << std::endl;
+ programCounter++;
+ }
+ //std::cout << "CS: " << callStack << " PS: " << programStack << std::endl;
+ }
+
+ void VirtualMachine::emit(std::string opcode)
+ {
+
+ }
+
+ void VirtualMachine::emit(int constant)
+ {
+
+ }
+
+ void VirtualMachine::CallCompiled(std::string entryPoint)
+ {
+
+ }
+
+ void VirtualMachine::CallCompiled(int entryPoint)
+ {
+
+ }
+
+ void VirtualMachine::Call(std::string entryPoint)
+ {
+
+ }
+
+ void VirtualMachine::Call(int entryPoint)
+ {
+ programCounter = entryPoint;
+ Run();
+ }
+}