1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-06 00:55:50 +00:00
OpenMW/components/interpreter/interpreter.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

132 lines
3.1 KiB
C++
Raw Normal View History

2010-06-28 17:20:45 +00:00
#include "interpreter.hpp"
2010-06-28 18:46:15 +00:00
#include <cassert>
#include <stdexcept>
2022-05-21 10:00:15 +00:00
#include <string>
2010-06-28 18:46:15 +00:00
#include "opcodes.hpp"
#include "program.hpp"
2010-06-28 18:46:15 +00:00
2010-06-28 17:20:45 +00:00
namespace Interpreter
{
2022-01-27 19:18:57 +00:00
[[noreturn]] static void abortUnknownCode(int segment, int opcode)
{
const std::string error = "unknown opcode " + std::to_string(opcode) + " in segment " + std::to_string(segment);
throw std::runtime_error(error);
}
[[noreturn]] static void abortUnknownSegment(Type_Code code)
{
const std::string error = "opcode outside of the allocated segment range: " + std::to_string(code);
throw std::runtime_error(error);
}
template <typename T>
auto& getDispatcher(const T& segment, unsigned int seg, int opcode)
{
auto it = segment.find(opcode);
if (it == segment.end())
{
abortUnknownCode(seg, opcode);
}
return it->second;
}
2010-06-28 18:46:15 +00:00
void Interpreter::execute(Type_Code code)
{
2022-01-27 19:18:57 +00:00
unsigned int segSpec = code >> 30;
2010-06-28 18:46:15 +00:00
switch (segSpec)
{
case 0:
{
2022-01-27 19:18:57 +00:00
const int opcode = code >> 24;
const unsigned int arg0 = code & 0xffffff;
2022-01-27 19:18:57 +00:00
return getDispatcher(mSegment0, 0, opcode)->execute(mRuntime, arg0);
2010-06-28 18:46:15 +00:00
}
2010-06-28 18:46:15 +00:00
case 2:
{
2022-01-27 19:18:57 +00:00
const int opcode = (code >> 20) & 0x3ff;
const unsigned int arg0 = code & 0xfffff;
2022-01-27 19:18:57 +00:00
return getDispatcher(mSegment2, 2, opcode)->execute(mRuntime, arg0);
}
2010-06-28 18:46:15 +00:00
}
2022-01-27 19:18:57 +00:00
segSpec = code >> 26;
2010-06-28 18:46:15 +00:00
switch (segSpec)
{
2010-06-28 18:46:15 +00:00
case 0x30:
{
2022-01-27 19:18:57 +00:00
const int opcode = (code >> 8) & 0x3ffff;
const unsigned int arg0 = code & 0xff;
2022-01-27 19:18:57 +00:00
return getDispatcher(mSegment3, 3, opcode)->execute(mRuntime, arg0);
}
2010-06-28 18:46:15 +00:00
case 0x32:
{
2022-01-27 19:18:57 +00:00
const int opcode = code & 0x3ffffff;
2022-01-27 19:18:57 +00:00
return getDispatcher(mSegment5, 5, opcode)->execute(mRuntime);
2010-06-28 18:46:15 +00:00
}
}
2010-06-28 18:46:15 +00:00
abortUnknownSegment(code);
}
void Interpreter::begin()
{
if (mRunning)
{
mCallstack.push(mRuntime);
mRuntime.clear();
}
else
{
mRunning = true;
}
}
void Interpreter::end()
{
if (mCallstack.empty())
{
mRuntime.clear();
mRunning = false;
}
else
{
mRuntime = mCallstack.top();
mCallstack.pop();
}
}
void Interpreter::run(const Program& program, Context& context)
2010-06-28 17:20:45 +00:00
{
begin();
try
{
mRuntime.configure(program, context);
while (mRuntime.getPC() >= 0 && static_cast<std::size_t>(mRuntime.getPC()) < program.mInstructions.size())
{
const Type_Code instruction = program.mInstructions[mRuntime.getPC()];
mRuntime.setPC(mRuntime.getPC() + 1);
execute(instruction);
}
}
catch (...)
2010-06-28 18:46:15 +00:00
{
end();
throw;
2010-06-28 18:46:15 +00:00
}
end();
2010-06-28 17:20:45 +00:00
}
}