1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-19 08:31:11 +00:00
CLK/InstructionSets/x86/Implementation/Repetition.hpp
2023-11-08 10:52:36 -05:00

181 lines
4.7 KiB
C++

//
// Repetition.hpp
// Clock Signal
//
// Created by Thomas Harte on 08/11/2023.
// Copyright © 2023 Thomas Harte. All rights reserved.
//
#ifndef Repetition_h
#define Repetition_h
#include "../AccessType.hpp"
namespace InstructionSet::x86::Primitive {
template <typename AddressT, Repetition repetition>
bool repetition_over(
const AddressT &eCX
) {
return repetition != Repetition::None && !eCX;
}
template <typename AddressT, Repetition repetition, typename ContextT>
void repeat(
AddressT &eCX,
ContextT &context
) {
if(
repetition == Repetition::None || // No repetition => stop.
!(--eCX) // [e]cx is zero after being decremented => stop.
) {
return;
}
if constexpr (repetition != Repetition::Rep) {
// If this is RepE or RepNE, also test the zero flag.
if((repetition == Repetition::RepNE) == context.flags.template flag<Flag::Zero>()) {
return;
}
}
context.flow_controller.repeat_last();
}
template <typename IntT, typename AddressT, Repetition repetition, typename InstructionT, typename ContextT>
void cmps(
const InstructionT &instruction,
AddressT &eCX,
AddressT &eSI,
AddressT &eDI,
ContextT &context
) {
if(repetition_over<AddressT, repetition>(eCX)) {
return;
}
IntT lhs = context.memory.template access<IntT, AccessType::Read>(instruction.data_segment(), eSI);
const IntT rhs = context.memory.template access<IntT, AccessType::Read>(Source::ES, eDI);
eSI += context.flags.template direction<AddressT>() * sizeof(IntT);
eDI += context.flags.template direction<AddressT>() * sizeof(IntT);
Primitive::sub<false, AccessType::Read, IntT>(lhs, rhs, context);
repeat<AddressT, repetition>(eCX, context);
}
template <typename IntT, typename AddressT, Repetition repetition, typename ContextT>
void scas(
AddressT &eCX,
AddressT &eDI,
IntT &eAX,
ContextT &context
) {
if(repetition_over<AddressT, repetition>(eCX)) {
return;
}
const IntT rhs = context.memory.template access<IntT, AccessType::Read>(Source::ES, eDI);
eDI += context.flags.template direction<AddressT>() * sizeof(IntT);
Primitive::sub<false, AccessType::Read, IntT>(eAX, rhs, context);
repeat<AddressT, repetition>(eCX, context);
}
template <typename IntT, typename AddressT, Repetition repetition, typename InstructionT, typename ContextT>
void lods(
const InstructionT &instruction,
AddressT &eCX,
AddressT &eSI,
IntT &eAX,
ContextT &context
) {
if(repetition_over<AddressT, repetition>(eCX)) {
return;
}
eAX = context.memory.template access<IntT, AccessType::Read>(instruction.data_segment(), eSI);
eSI += context.flags.template direction<AddressT>() * sizeof(IntT);
repeat<AddressT, repetition>(eCX, context);
}
template <typename IntT, typename AddressT, Repetition repetition, typename InstructionT, typename ContextT>
void movs(
const InstructionT &instruction,
AddressT &eCX,
AddressT &eSI,
AddressT &eDI,
ContextT &context
) {
if(repetition_over<AddressT, repetition>(eCX)) {
return;
}
context.memory.template access<IntT, AccessType::Write>(Source::ES, eDI) =
context.memory.template access<IntT, AccessType::Read>(instruction.data_segment(), eSI);
eSI += context.flags.template direction<AddressT>() * sizeof(IntT);
eDI += context.flags.template direction<AddressT>() * sizeof(IntT);
repeat<AddressT, repetition>(eCX, context);
}
template <typename IntT, typename AddressT, Repetition repetition, typename ContextT>
void stos(
AddressT &eCX,
AddressT &eDI,
IntT &eAX,
ContextT &context
) {
if(repetition_over<AddressT, repetition>(eCX)) {
return;
}
context.memory.template access<IntT, AccessType::Write>(Source::ES, eDI) = eAX;
eDI += context.flags.template direction<AddressT>() * sizeof(IntT);
repeat<AddressT, repetition>(eCX, context);
}
template <typename IntT, typename AddressT, Repetition repetition, typename InstructionT, typename ContextT>
void outs(
const InstructionT &instruction,
AddressT &eCX,
uint16_t port,
AddressT &eSI,
ContextT &context
) {
if(repetition_over<AddressT, repetition>(eCX)) {
return;
}
context.io.template out<IntT>(
port,
context.memory.template access<IntT, AccessType::Read>(instruction.data_segment(), eSI)
);
eSI += context.flags.template direction<AddressT>() * sizeof(IntT);
repeat<AddressT, repetition>(eCX, context);
}
template <typename IntT, typename AddressT, Repetition repetition, typename ContextT>
void ins(
AddressT &eCX,
uint16_t port,
AddressT &eDI,
ContextT &context
) {
if(repetition_over<AddressT, repetition>(eCX)) {
return;
}
context.memory.template access<IntT, AccessType::Write>(Source::ES, eDI) = context.io.template in<IntT>(port);
eDI += context.flags.template direction<AddressT>() * sizeof(IntT);
repeat<AddressT, repetition>(eCX, context);
}
}
#endif /* Repetition_h */