summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSimon Robertshaw <simon@hardwired.org.uk>2012-09-14 21:03:14 (GMT)
committer Simon Robertshaw <simon@hardwired.org.uk>2012-09-14 21:03:14 (GMT)
commit486b34ebe581cf41b67145911a64ce2ea7b8932a (patch)
tree6752bc0bb7245bbd5009061b504f03b02790b58b /src
parent685be24ffa1eba28aa378b8a9b4fd52dbe238756 (diff)
downloadpowder-486b34ebe581cf41b67145911a64ce2ea7b8932a.zip
powder-486b34ebe581cf41b67145911a64ce2ea7b8932a.tar.gz
Fixes invalid text pasting, Adds API to VM, allow program loading in Lua and assigning to update function
Diffstat (limited to 'src')
-rw-r--r--src/cat/LuaScriptInterface.cpp78
-rw-r--r--src/cat/LuaScriptInterface.h13
-rw-r--r--src/interface/Textbox.cpp15
-rw-r--r--src/virtualmachine/Exceptions.h11
-rw-r--r--src/virtualmachine/Syscalls.cpp4
-rw-r--r--src/virtualmachine/VirtualMachine.cpp167
-rw-r--r--src/virtualmachine/VirtualMachine.h6
7 files changed, 265 insertions, 29 deletions
diff --git a/src/cat/LuaScriptInterface.cpp b/src/cat/LuaScriptInterface.cpp
index f5b69ee..87496ec 100644
--- a/src/cat/LuaScriptInterface.cpp
+++ b/src/cat/LuaScriptInterface.cpp
@@ -20,6 +20,7 @@
#include "dialogues/TextPrompt.h"
#include "dialogues/ConfirmPrompt.h"
#include "simulation/Simulation.h"
+#include "virtualmachine/VirtualMachine.h"
#include "game/GameModel.h"
#include "LuaScriptHelper.h"
#include "client/HTTP.h"
@@ -63,6 +64,7 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
initInterfaceAPI();
initRendererAPI();
initElementsAPI();
+ initVirtualMachineAPI();
//Old TPT API
int i = 0, j;
@@ -651,6 +653,42 @@ void LuaScriptInterface::initElementsAPI()
}
}
+vm::VirtualMachine * LuaScriptInterface::updateVirtualMachines[PT_NUM];
+
+int LuaScriptInterface::updateVM(UPDATE_FUNC_ARGS)
+{
+ vm::VirtualMachine * vMachine = updateVirtualMachines[parts[i].type];
+
+ vm::word w;
+ int argAddr = 0, argCount = 5;
+ vMachine->sim = sim;
+
+ /* Set up call. */
+ vMachine->OpPUSH(w); //Pointless null in stack
+ w.int4 = (argCount + 2) * sizeof(vm::word);
+ vMachine->OpENTER(w);
+ argAddr = 8;
+
+ //Arguments
+ w.int4 = i; vMachine->Marshal(argAddr, w); argAddr += 4;
+ w.int4 = x; vMachine->Marshal(argAddr, w); argAddr += 4;
+ w.int4 = y; vMachine->Marshal(argAddr, w); argAddr += 4;
+ w.int4 = nt; vMachine->Marshal(argAddr, w); argAddr += 4;
+ w.int4 = surround_space; vMachine->Marshal(argAddr, w); argAddr += 4;
+
+ w.int4 = 0;
+ vMachine->Push(w);
+
+ vMachine->OpCALL(w);
+ vMachine->Run();
+ w.int4 = (argCount + 2) * sizeof(vm::word);
+ vMachine->OpLEAVE(w);
+ vMachine->OpPOP(w); //Pop pointless null
+ vMachine->End();
+
+ return 0;
+}
+
int LuaScriptInterface::elements_loadDefault(lua_State * l)
{
int args = lua_gettop(l);
@@ -957,6 +995,11 @@ int LuaScriptInterface::elements_property(lua_State * l)
lua_el_func[id] = luaL_ref(l, LUA_REGISTRYINDEX);
luacon_sim->elements[id].Update = &luacon_elementReplacement;
}
+ else if(lua_type(l, 3) == LUA_TLIGHTUSERDATA)
+ {
+ updateVirtualMachines[id] = (vm::VirtualMachine*)lua_touserdata(l, 3);
+ luacon_sim->elements[id].Update = &updateVM;
+ }
else if(lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
{
lua_el_func[id] = 0;
@@ -1061,6 +1104,41 @@ int LuaScriptInterface::elements_free(lua_State * l)
return 0;
}
+void LuaScriptInterface::initVirtualMachineAPI()
+{
+ //Methods
+ struct luaL_reg vmAPIMethods [] = {
+ {"loadProgram", virtualMachine_loadProgram},
+ {NULL, NULL}
+ };
+ luaL_register(l, "virtualMachine", vmAPIMethods);
+
+ //elem shortcut
+ lua_getglobal(l, "virtualMachine");
+ lua_setglobal(l, "vm");
+
+ int vmAPI = lua_gettop(l);
+}
+
+int LuaScriptInterface::virtualMachine_loadProgram(lua_State * l)
+{
+ luaL_checktype(l, 1, LUA_TSTRING);
+
+ vm::VirtualMachine * newVM = new vm::VirtualMachine(1);
+ try
+ {
+ const char * tempString = lua_tostring(l, 1);
+ int tempStringLength = lua_strlen(l, 1);
+ std::vector<char> programData(tempString, tempString+tempStringLength);
+ newVM->LoadProgram(programData);
+ }
+ catch(std::exception & e)
+ {
+ return luaL_error(l, "Unable to load program");
+ }
+ lua_pushlightuserdata(l, newVM);
+ return 1;
+}
bool LuaScriptInterface::OnBrushChanged(int brushType, int rx, int ry)
{
diff --git a/src/cat/LuaScriptInterface.h b/src/cat/LuaScriptInterface.h
index 5bee8e1..c40728c 100644
--- a/src/cat/LuaScriptInterface.h
+++ b/src/cat/LuaScriptInterface.h
@@ -23,6 +23,12 @@ namespace ui
class Window;
}
+namespace vm
+{
+ class VirtualMachine;
+}
+
+
//Because lua only has bindings for C, we're going to have to go outside "outside" the LuaScriptInterface, this means we can only have one instance :(
#define LOCAL_LUA_DIR "Lua"
@@ -59,6 +65,9 @@ class LuaScriptInterface: public CommandInterface {
static int renderer_colourMode(lua_State * l);
//Elements
+ static vm::VirtualMachine * updateVirtualMachines[PT_NUM];
+ static int updateVM(UPDATE_FUNC_ARGS);
+ //
void initElementsAPI();
static int elements_allocate(lua_State * l);
static int elements_element(lua_State * l);
@@ -71,6 +80,10 @@ class LuaScriptInterface: public CommandInterface {
static int interface_showWindow(lua_State * l);
static int interface_closeWindow(lua_State * l);
static int interface_addComponent(lua_State * l);
+
+ //VM
+ void initVirtualMachineAPI();
+ static int virtualMachine_loadProgram(lua_State * l);
public:
ui::Window * Window;
lua_State *l;
diff --git a/src/interface/Textbox.cpp b/src/interface/Textbox.cpp
index 603fa23..ab4d907 100644
--- a/src/interface/Textbox.cpp
+++ b/src/interface/Textbox.cpp
@@ -191,6 +191,21 @@ void Textbox::pasteIntoSelection()
backingText.erase(backingText.begin()+getLowerSelectionBound(), backingText.begin()+getHigherSelectionBound());
cursor = getLowerSelectionBound();
}
+ for(std::string::iterator iter = newText.begin(), end = newText.end(); iter != end; ++iter)
+ {
+ if(!CharacterValid(*iter))
+ {
+ if(inputType == All)
+ {
+ if(*iter == '\n' || *iter == '\r')
+ *iter = ' ';
+ else
+ *iter = '?';
+ }
+ else
+ *iter = '0';
+ }
+ }
backingText.insert(cursor, newText);
cursor = cursor+newText.length();
ClearSelection();
diff --git a/src/virtualmachine/Exceptions.h b/src/virtualmachine/Exceptions.h
index fbc4341..9628d10 100644
--- a/src/virtualmachine/Exceptions.h
+++ b/src/virtualmachine/Exceptions.h
@@ -86,4 +86,15 @@ namespace vm
}
~OutOfMemoryException() throw() {};
};
+
+ class InvalidProgramException: public RuntimeException
+ {
+ public:
+ InvalidProgramException() {}
+ const char * what() const throw()
+ {
+ return "Could not load program";
+ }
+ ~InvalidProgramException() throw() {};
+ };
} \ No newline at end of file
diff --git a/src/virtualmachine/Syscalls.cpp b/src/virtualmachine/Syscalls.cpp
index b9f9211..642e763 100644
--- a/src/virtualmachine/Syscalls.cpp
+++ b/src/virtualmachine/Syscalls.cpp
@@ -61,9 +61,9 @@ namespace vm
TRAPDEF(partCreate)
{
- //Push<int4_t>(sim->create_part(ARG(0).int4, ARG(1).int4, ARG(2).int4, ARG(3).int4));
- printf("create_part(%d, %d, %d, %d)\n", ARG(0).int4, ARG(1).int4, ARG(2).int4, ARG(3).int4);
+ printf("%d, %d, %d, %d\n", ARG(0).int4, ARG(1).int4, ARG(2).int4, ARG(3).int4);
Push<int4_t>(0);
+ //Push<int4_t>(sim->create_part(ARG(0).int4, ARG(1).int4, ARG(2).int4, ARG(3).int4));
}
TRAPDEF(partChangeType)
diff --git a/src/virtualmachine/VirtualMachine.cpp b/src/virtualmachine/VirtualMachine.cpp
index 9de822d..7d1af8e 100644
--- a/src/virtualmachine/VirtualMachine.cpp
+++ b/src/virtualmachine/VirtualMachine.cpp
@@ -74,46 +74,167 @@ namespace vm
}
/* Read one octet from file. */
- int VirtualMachine::readByte(FILE *qvmfile)
+ int VirtualMachine::readByte(std::istream & input)
{
int o;
- o = fgetc(qvmfile);
+ o = input.get();
if (o < 0) o = 0; /* EOF (hack) */
return o;
}
/* Read little-endian 32-bit integer from file. */
- int VirtualMachine::readInt(FILE *qvmfile)
+ int VirtualMachine::readInt(std::istream & input)
{
int a, b, c, d, n;
- a = readByte(qvmfile);
- b = readByte(qvmfile);
- c = readByte(qvmfile);
- d = readByte(qvmfile);
+ a = readByte(input);
+ b = readByte(input);
+ c = readByte(input);
+ d = readByte(input);
n = (a) | (b << 8) | (c << 16) | (d << 24);
return n;
}
+ int VirtualMachine::readProgram(std::istream & input)
+ {
+ qvm_header_t qvminfo;
+ int i, n;
+ uint1_t x[4];
+ word w;
+
+ DEBUGTRACE("Loading file...\n");
+ qvminfo.magic = readInt(input); /* magic. */
+ if (qvminfo.magic != QVM_MAGIC)
+ {
+ DEBUGTRACE("Invalid magic");
+ throw InvalidProgramException();
+ //q3vm_error("Does not appear to be a QVM file.");
+ /* XXX: option to force continue. */
+ return 0;
+ }
+ DEBUGTRACE("Magic OK\n");
+ /* variable-length instructions mean instruction count != code length */
+ qvminfo.inscount = readInt(input);
+ qvminfo.codeoff = readInt(input);
+ qvminfo.codelen = readInt(input);
+ qvminfo.dataoff = readInt(input);
+ qvminfo.datalen = readInt(input);
+ qvminfo.litlen = readInt(input);
+ qvminfo.bsslen = readInt(input);
+
+ /* Code segment should follow... */
+ /* XXX: use fseek with SEEK_CUR? */
+ DEBUGTRACE("Searching for .code @ %d from %d\n", qvminfo.codeoff, input.tellg());
+
+ // rom = (q3vm_rom_t*)(hunk); /* ROM-in-hunk */
+ rom = (Instruction*)calloc(qvminfo.inscount, sizeof(rom[0]));
+ while (input.tellg() < qvminfo.codeoff)
+ readByte(input);
+ while (romSize < qvminfo.inscount)
+ {
+ n = readByte(input);
+ w.int4 = 0;
+ if ((i = opcodeParameterSize(n)))
+ {
+ x[0] = x[1] = x[2] = x[3] = 0;
+ input.readsome((char*)x, 4);
+ w.uint4 = (x[0]) | (x[1] << 8) | (x[2] << 16) | (x[3] << 24);
+ }
+ rom[romSize].Operation = n;
+ rom[romSize].Parameter = w;
+ romSize++;
+ }
+ DEBUGTRACE("After loading code: at %d, should be %d\n", input.tellg(), qvminfo.codeoff + qvminfo.codelen);
+
+ /* Then data segment. */
+ // ram = hunk + ((romlen + 3) & ~3); /* RAM-in-hunk */
+ ram = hunk;
+ DEBUGTRACE("Searching for .data @ %d from %d\n", qvminfo.dataoff, input.tellg());
+ while (input.tellg() < qvminfo.dataoff)
+ readByte(input);
+ for (n = 0; n < (qvminfo.datalen / sizeof(uint1_t)); n++)
+ {
+ i = input.readsome((char*)x, sizeof(x));
+ w.uint4 = (x[0]) | (x[1] << 8) | (x[2] << 16) | (x[3] << 24);
+ *((word*)(ram + ramSize)) = w;
+ ramSize += sizeof(word);
+ }
+
+ /* lit segment follows data segment. */
+ /* Assembler should have already padded properly. */
+ DEBUGTRACE("Loading .lit\n");
+ for (n = 0; n < (qvminfo.litlen / sizeof(uint1_t)); n++)
+ {
+ i = input.readsome((char*)x, sizeof(x));
+ memcpy(&(w.uint1), &x, sizeof(x)); /* no byte-swapping. */
+ *((word*)(ram + ramSize)) = w;
+ ramSize += sizeof(word);
+ }
+ /* bss segment. */
+ DEBUGTRACE("Allocating .bss %d (%X) bytes\n", qvminfo.bsslen, qvminfo.bsslen);
+ /* huge empty chunk. */
+ ramSize += qvminfo.bsslen;
+
+ hunkFree = hunkSize - ((ramSize * sizeof(uint1_t)) + 4);
+
+ DEBUGTRACE("VM hunk has %d of %d bytes free (RAM = %d B).\n", hunkFree, hunkSize, ramSize);
+ if (ramSize > hunkSize)
+ {
+ throw OutOfMemoryException();
+ return 0;
+ }
+
+ /* set up stack. */
+ {
+ int stacksize = 0x10000;
+ dataStack = ramSize - (stacksize / 2);
+ returnStack = ramSize;
+ //returnStack = dataStack+4;
+ RP = returnStack;
+ DP = dataStack;
+ }
+
+ /* set up PC for return-to-termination. */
+ PC = romSize + 1;
+
+ ramMask = ramSize;
+
+ return 1;
+ }
+
+ int VirtualMachine::LoadProgram(std::vector<char> data)
+ {
+ /*class vectorwrapbuf : public std::basic_streambuf<char, std::char_traits<char> >
+ {
+ public:
+ vectorwrapbuf(std::vector<char> &vec) {
+ setg(vec.data(), vec.data(), vec.data() + vec.size());
+ }
+ };
+ vectorwrapbuf databuf(data);
+ std::istream is(&databuf);
+ return readProgram(is);*/
+ std::stringstream ss(std::string(data.begin(), data.end()));
+ return readProgram((std::istream &)ss);
+ }
+
int VirtualMachine::LoadProgram(char * filename)
{
- FILE * qvmfile = fopen(filename, "rb");
+ /*FILE * qvmfile = fopen(filename, "rb");
qvm_header_t qvminfo;
int i, n;
uint1_t x[4];
word w;
DEBUGTRACE("Loading file...\n");
- qvminfo.magic = readInt(qvmfile); /* magic. */
+ qvminfo.magic = readInt(qvmfile);
if (qvminfo.magic != QVM_MAGIC)
{
DEBUGTRACE("Invalid magic");
- //q3vm_error("Does not appear to be a QVM file.");
- /* XXX: option to force continue. */
return 0;
}
DEBUGTRACE("Magic OK\n");
- /* variable-length instructions mean instruction count != code length */
+
qvminfo.inscount = readInt(qvmfile);
qvminfo.codeoff = readInt(qvmfile);
qvminfo.codelen = readInt(qvmfile);
@@ -122,10 +243,9 @@ namespace vm
qvminfo.litlen = readInt(qvmfile);
qvminfo.bsslen = readInt(qvmfile);
- /* Code segment should follow... */
- /* XXX: use fseek with SEEK_CUR? */
+
DEBUGTRACE("Searching for .code @ %d from %d\n", qvminfo.codeoff, ftell(qvmfile));
- // rom = (q3vm_rom_t*)(hunk); /* ROM-in-hunk */
+
rom = (Instruction*)calloc(qvminfo.inscount, sizeof(rom[0]));
while (ftell(qvmfile) < qvminfo.codeoff)
readByte(qvmfile);
@@ -145,8 +265,7 @@ namespace vm
}
DEBUGTRACE("After loading code: at %d, should be %d\n", ftell(qvmfile), qvminfo.codeoff + qvminfo.codelen);
- /* Then data segment. */
- // ram = hunk + ((romlen + 3) & ~3); /* RAM-in-hunk */
+
ram = hunk;
DEBUGTRACE("Searching for .data @ %d from %d\n", qvminfo.dataoff, ftell(qvmfile));
while (ftell(qvmfile) < qvminfo.dataoff)
@@ -159,19 +278,17 @@ namespace vm
ramSize += sizeof(word);
}
- /* lit segment follows data segment. */
- /* Assembler should have already padded properly. */
+
DEBUGTRACE("Loading .lit\n");
for (n = 0; n < (qvminfo.litlen / sizeof(uint1_t)); n++)
{
i = fread(&x, 1, sizeof(x), qvmfile);
- memcpy(&(w.uint1), &x, sizeof(x)); /* no byte-swapping. */
+ memcpy(&(w.uint1), &x, sizeof(x));
*((word*)(ram + ramSize)) = w;
ramSize += sizeof(word);
}
- /* bss segment. */
+
DEBUGTRACE("Allocating .bss %d (%X) bytes\n", qvminfo.bsslen, qvminfo.bsslen);
- /* huge empty chunk. */
ramSize += qvminfo.bsslen;
hunkFree = hunkSize - ((ramSize * sizeof(uint1_t)) + 4);
@@ -183,7 +300,7 @@ namespace vm
return 0;
}
- /* set up stack. */
+
{
int stacksize = 0x10000;
dataStack = ramSize - (stacksize / 2);
@@ -193,12 +310,12 @@ namespace vm
DP = dataStack;
}
- /* set up PC for return-to-termination. */
+
PC = romSize + 1;
ramMask = ramSize;
- return 1;
+ return 1;*/
}
void VirtualMachine::End()
diff --git a/src/virtualmachine/VirtualMachine.h b/src/virtualmachine/VirtualMachine.h
index 1f5b088..04dd400 100644
--- a/src/virtualmachine/VirtualMachine.h
+++ b/src/virtualmachine/VirtualMachine.h
@@ -117,8 +117,9 @@ namespace vm
};
#undef OPDEF
- int readByte(FILE *qvmfile);
- int readInt(FILE *qvmfile);
+ int readProgram(std::istream & input);
+ int readByte(std::istream & input);
+ int readInt(std::istream & input);
int opcodeParameterSize(int opcode);
int syscall(int programCounter);
@@ -153,6 +154,7 @@ public:
virtual ~VirtualMachine();
int LoadProgram(char * filename);
+ int LoadProgram(std::vector<char> fileData);
int Run();
int CallInterpreted(int address);
void End();