mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-17 10:06:21 +00:00
Take a swing at ENTER.
This commit is contained in:
parent
a22ac2f88b
commit
f83d2a8740
@ -317,8 +317,8 @@ template <
|
||||
Primitive::setmo<IntT>(destination_w(), context);
|
||||
break;
|
||||
} else {
|
||||
// TODO: perform ENTER as of the 80186.
|
||||
static_assert(int(Operation::SETMO) == int(Operation::ENTER));
|
||||
Primitive::enter<IntT>(instruction, context);
|
||||
}
|
||||
return;
|
||||
case Operation::SETMOC:
|
||||
|
@ -22,13 +22,13 @@ void push(
|
||||
IntT &value,
|
||||
ContextT &context
|
||||
) {
|
||||
context.registers.sp_ -= sizeof(IntT);
|
||||
context.registers.sp() -= sizeof(IntT);
|
||||
if constexpr (preauthorised) {
|
||||
context.memory.template preauthorised_write<IntT>(Source::SS, context.registers.sp_, value);
|
||||
context.memory.template preauthorised_write<IntT>(Source::SS, context.registers.sp(), value);
|
||||
} else {
|
||||
context.memory.template access<IntT, AccessType::Write>(
|
||||
Source::SS,
|
||||
context.registers.sp_) = value;
|
||||
context.registers.sp()) = value;
|
||||
}
|
||||
context.memory.template write_back<IntT>();
|
||||
}
|
||||
@ -39,8 +39,8 @@ IntT pop(
|
||||
) {
|
||||
const auto value = context.memory.template access<IntT, preauthorised ? AccessType::PreauthorisedRead : AccessType::Read>(
|
||||
Source::SS,
|
||||
context.registers.sp_);
|
||||
context.registers.sp_ += sizeof(IntT);
|
||||
context.registers.sp());
|
||||
context.registers.sp() += sizeof(IntT);
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -144,12 +144,49 @@ void pusha(
|
||||
}
|
||||
}
|
||||
|
||||
template <typename IntT, typename InstructionT, typename ContextT>
|
||||
void enter(
|
||||
const InstructionT &instruction,
|
||||
ContextT &context
|
||||
) {
|
||||
// TODO: all non-16bit address sizes.
|
||||
const auto alloc_size = instruction.dynamic_storage_size();
|
||||
const auto nesting_level = instruction.nesting_level() & 0x1f;
|
||||
|
||||
// Preauthorse contents that'll be fetched via BP.
|
||||
const auto copied_pointers = nesting_level - 2;
|
||||
if(copied_pointers > 0) {
|
||||
context.memory.preauthorise_read(
|
||||
Source::SS,
|
||||
context.registers.bp() - copied_pointers * sizeof(uint16_t),
|
||||
copied_pointers * sizeof(uint16_t)
|
||||
);
|
||||
}
|
||||
|
||||
// Preauthorse stack activity.
|
||||
context.memory.preauthorise_stack_write((1 + copied_pointers) * sizeof(uint16_t));
|
||||
|
||||
// Push BP and grab the end of frame.
|
||||
push<uint16_t, true>(context.registers.bp(), context);
|
||||
const auto frame = context.registers.sp();
|
||||
|
||||
// Copy data as per the nesting level.
|
||||
for(int c = 1; c < nesting_level; c++) {
|
||||
context.registers.bp() -= 2;
|
||||
|
||||
const auto value = context.memory.template preauthorised_read<uint16_t>(Source::SS, context.registers.bp());
|
||||
push<uint16_t, true>(value);
|
||||
}
|
||||
|
||||
// Set final BP.
|
||||
context.registers.bp() = frame;
|
||||
}
|
||||
|
||||
template <typename IntT, typename ContextT>
|
||||
void leave(
|
||||
ContextT &context
|
||||
) {
|
||||
// TODO: should use StackAddressSize to determine assignment of bp to sp.
|
||||
// Probably make that a static constexpr on registers.
|
||||
if constexpr (std::is_same_v<IntT, uint32_t>) {
|
||||
context.registers.esp() = context.registers.ebp();
|
||||
context.registers.ebp() = pop<uint32_t, false>(context);
|
||||
|
@ -245,8 +245,8 @@ enum class Operation: uint8_t {
|
||||
/// Raises a bounds exception if not.
|
||||
BOUND = SETMOC,
|
||||
|
||||
/// Create stack frame. See operand() for the nesting level and offset()
|
||||
/// for the dynamic storage size.
|
||||
/// Create stack frame. See the Instruction getters `nesting_level()`
|
||||
/// and `dynamic_storage_size()`.
|
||||
ENTER,
|
||||
/// Procedure exit; copies BP to SP, then pops a new BP from the stack.
|
||||
LEAVE,
|
||||
@ -815,6 +815,11 @@ template<bool is_32bit> class Instruction {
|
||||
return ops[has_operand()];
|
||||
}
|
||||
|
||||
/// @returns The nesting level argument supplied to an ENTER.
|
||||
constexpr ImmediateT nesting_level() const {
|
||||
return operand();
|
||||
}
|
||||
|
||||
/// @returns The immediate segment value provided with this instruction, if any. Relevant for far calls and jumps; e.g. `JMP 1234h:5678h` will
|
||||
/// have a segment value of `1234h`.
|
||||
constexpr uint16_t segment() const {
|
||||
@ -833,6 +838,11 @@ template<bool is_32bit> class Instruction {
|
||||
return DisplacementT(offset());
|
||||
}
|
||||
|
||||
/// @returns The dynamic storage size argument supplied to an ENTER.
|
||||
constexpr ImmediateT dynamic_storage_size() const {
|
||||
return displacement();
|
||||
}
|
||||
|
||||
// Standard comparison operator.
|
||||
constexpr bool operator ==(const Instruction<is_32bit> &rhs) const {
|
||||
if( operation_ != rhs.operation_ ||
|
||||
|
Loading…
Reference in New Issue
Block a user