2016-08-17 15:53:36 +01:00
|
|
|
/* This file is part of the dynarmic project.
|
|
|
|
* Copyright (c) 2016 MerryMage
|
|
|
|
* This software may be used and distributed according to the terms of the GNU
|
|
|
|
* General Public License version 2 or any later version.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <boost/variant.hpp>
|
|
|
|
|
|
|
|
#include "common/common_types.h"
|
2018-01-01 15:23:56 +00:00
|
|
|
#include "frontend/ir/cond.h"
|
2016-09-05 11:54:09 +01:00
|
|
|
#include "frontend/ir/location_descriptor.h"
|
2016-08-17 15:53:36 +01:00
|
|
|
|
|
|
|
namespace Dynarmic {
|
|
|
|
namespace IR {
|
|
|
|
namespace Term {
|
|
|
|
|
|
|
|
struct Invalid {};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This terminal instruction calls the interpreter, starting at `next`.
|
|
|
|
* The interpreter must interpret exactly one instruction.
|
|
|
|
*/
|
|
|
|
struct Interpret {
|
2016-09-05 11:54:09 +01:00
|
|
|
explicit Interpret(const LocationDescriptor& next_) : next(next_) {}
|
|
|
|
LocationDescriptor next; ///< Location at which interpretation starts.
|
2016-08-17 15:53:36 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This terminal instruction returns control to the dispatcher.
|
|
|
|
* The dispatcher will use the value in R15 to determine what comes next.
|
|
|
|
*/
|
|
|
|
struct ReturnToDispatch {};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This terminal instruction jumps to the basic block described by `next` if we have enough
|
|
|
|
* cycles remaining. If we do not have enough cycles remaining, we return to the
|
|
|
|
* dispatcher, which will return control to the host.
|
|
|
|
*/
|
|
|
|
struct LinkBlock {
|
2016-09-05 11:54:09 +01:00
|
|
|
explicit LinkBlock(const LocationDescriptor& next_) : next(next_) {}
|
|
|
|
LocationDescriptor next; ///< Location descriptor for next block.
|
2016-08-17 15:53:36 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This terminal instruction jumps to the basic block described by `next` unconditionally.
|
|
|
|
* This is an optimization and MUST only be emitted when this is guaranteed not to result
|
|
|
|
* in hanging, even in the face of other optimizations. (In practice, this means that only
|
|
|
|
* forward jumps to short-ish blocks would use this instruction.)
|
|
|
|
* A backend that doesn't support this optimization may choose to implement this exactly
|
|
|
|
* as LinkBlock.
|
|
|
|
*/
|
|
|
|
struct LinkBlockFast {
|
2016-09-05 11:54:09 +01:00
|
|
|
explicit LinkBlockFast(const LocationDescriptor& next_) : next(next_) {}
|
|
|
|
LocationDescriptor next; ///< Location descriptor for next block.
|
2016-08-17 15:53:36 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This terminal instruction checks the top of the Return Stack Buffer against R15.
|
|
|
|
* If RSB lookup fails, control is returned to the dispatcher.
|
|
|
|
* This is an optimization for faster function calls. A backend that doesn't support
|
|
|
|
* this optimization or doesn't have a RSB may choose to implement this exactly as
|
|
|
|
* ReturnToDispatch.
|
|
|
|
*/
|
|
|
|
struct PopRSBHint {};
|
|
|
|
|
|
|
|
struct If;
|
2018-01-07 16:33:02 +00:00
|
|
|
struct CheckBit;
|
2016-08-17 15:53:36 +01:00
|
|
|
struct CheckHalt;
|
|
|
|
/// A Terminal is the terminal instruction in a MicroBlock.
|
|
|
|
using Terminal = boost::variant<
|
|
|
|
Invalid,
|
|
|
|
Interpret,
|
|
|
|
ReturnToDispatch,
|
|
|
|
LinkBlock,
|
|
|
|
LinkBlockFast,
|
|
|
|
PopRSBHint,
|
|
|
|
boost::recursive_wrapper<If>,
|
2018-01-07 16:33:02 +00:00
|
|
|
boost::recursive_wrapper<CheckBit>,
|
2016-08-17 15:53:36 +01:00
|
|
|
boost::recursive_wrapper<CheckHalt>
|
|
|
|
>;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This terminal instruction conditionally executes one terminal or another depending
|
|
|
|
* on the run-time state of the ARM flags.
|
|
|
|
*/
|
|
|
|
struct If {
|
2018-01-01 15:23:56 +00:00
|
|
|
If(Cond if_, Terminal then_, Terminal else_) : if_(if_), then_(then_), else_(else_) {}
|
|
|
|
Cond if_;
|
2016-08-17 15:53:36 +01:00
|
|
|
Terminal then_;
|
|
|
|
Terminal else_;
|
|
|
|
};
|
|
|
|
|
2018-01-07 16:33:02 +00:00
|
|
|
/**
|
|
|
|
* This terminal instruction conditionally executes one terminal or another depending
|
|
|
|
* on the run-time state of the check bit.
|
|
|
|
* then_ is executed if the check bit is non-zero, otherwise else_ is executed.
|
|
|
|
*/
|
|
|
|
struct CheckBit {
|
|
|
|
CheckBit(Terminal then_, Terminal else_) : then_(then_), else_(else_) {}
|
|
|
|
Terminal then_;
|
|
|
|
Terminal else_;
|
|
|
|
};
|
|
|
|
|
2016-08-17 15:53:36 +01:00
|
|
|
/**
|
|
|
|
* This terminal instruction checks if a halt was requested. If it wasn't, else_ is
|
|
|
|
* executed.
|
|
|
|
*/
|
|
|
|
struct CheckHalt {
|
2016-09-07 12:08:48 +01:00
|
|
|
explicit CheckHalt(Terminal else_) : else_(else_) {}
|
2016-08-17 15:53:36 +01:00
|
|
|
Terminal else_;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace Term
|
|
|
|
|
|
|
|
using Term::Terminal;
|
|
|
|
|
|
|
|
} // namespace IR
|
|
|
|
} // namespace Dynarmic
|