mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-19 08:31:11 +00:00
181 lines
4.7 KiB
C++
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 */
|