1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-08-07 08:26:28 +00:00

Improve constness, formatting.

This commit is contained in:
Thomas Harte
2024-12-01 17:51:20 -05:00
parent 8b88d1294d
commit 3a0f4a0bfc
34 changed files with 857 additions and 778 deletions

View File

@@ -50,7 +50,7 @@ struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Ta
}
};
constexpr bool is_iie(Target::Model model) {
constexpr bool is_iie(const Target::Model model) {
return model == Target::Model::IIe || model == Target::Model::EnhancedIIe;
}

View File

@@ -43,7 +43,7 @@ enum class Personality {
EGA, // Extended EGA-style CRTC; uses 16-bit addressing throughout.
};
constexpr bool is_egavga(Personality p) {
constexpr bool is_egavga(const Personality p) {
return p >= Personality::EGA;
}

View File

@@ -13,7 +13,7 @@
namespace InstructionSet {
namespace M50740 {
Instruction Decoder::instrucion_for_opcode(uint8_t opcode) {
Instruction Decoder::instrucion_for_opcode(const uint8_t opcode) {
switch(opcode) {
default: return Instruction(opcode);
@@ -231,7 +231,7 @@ Instruction Decoder::instrucion_for_opcode(uint8_t opcode) {
}
}
std::pair<int, InstructionSet::M50740::Instruction> Decoder::decode(const uint8_t *source, size_t length) {
std::pair<int, InstructionSet::M50740::Instruction> Decoder::decode(const uint8_t *source, const size_t length) {
const uint8_t *const end = source + length;
if(phase_ == Phase::Instruction && source != end) {

View File

@@ -16,11 +16,11 @@
namespace InstructionSet::M50740 {
class Decoder {
public:
std::pair<int, Instruction> decode(const uint8_t *source, size_t length);
Instruction instrucion_for_opcode(uint8_t opcode);
public:
std::pair<int, Instruction> decode(const uint8_t *, size_t length);
Instruction instrucion_for_opcode(uint8_t);
private:
private:
enum class Phase {
Instruction,
AwaitingOperand,

View File

@@ -49,7 +49,7 @@ void Executor::set_rom(const std::vector<uint8_t> &rom) {
reset();
}
void Executor::run_for(Cycles cycles) {
void Executor::run_for(const Cycles cycles) {
// The incoming clock is divided by four; the local cycles_ count
// ensures that fractional parts are kept track of.
cycles_ += cycles;
@@ -61,7 +61,7 @@ void Executor::reset() {
set_program_counter(uint16_t(memory_[0x1ffe] | (memory_[0x1fff] << 8)));
}
void Executor::set_interrupt_line(bool line) {
void Executor::set_interrupt_line(const bool line) {
// Super hack: interrupt now, if permitted. Otherwise do nothing.
// So this will fail to catch enabling of interrupts while the line
// is active, amongst other things.
@@ -117,12 +117,12 @@ uint8_t Executor::read(uint16_t address) {
}
}
void Executor::set_port_output(int port) {
void Executor::set_port_output(const int port) {
// Force 'output' to a 1 anywhere that a bit is set as input.
port_handler_.set_port_output(port, port_outputs_[port] | ~port_directions_[port]);
}
void Executor::write(uint16_t address, uint8_t value) {
void Executor::write(uint16_t address, const uint8_t value) {
address &= 0x1fff;
// RAM writes are easy.
@@ -182,7 +182,7 @@ void Executor::write(uint16_t address, uint8_t value) {
}
}
void Executor::push(uint8_t value) {
void Executor::push(const uint8_t value) {
write(s_, value);
--s_;
}
@@ -192,7 +192,7 @@ uint8_t Executor::pull() {
return read(s_);
}
void Executor::set_flags(uint8_t flags) {
void Executor::set_flags(const uint8_t flags) {
negative_result_ = flags;
overflow_result_ = uint8_t(flags << 1);
index_mode_ = flags & 0x20;
@@ -213,7 +213,7 @@ uint8_t Executor::flags() {
carry_flag_;
}
template<bool is_brk> inline void Executor::perform_interrupt(uint16_t vector) {
template<bool is_brk> inline void Executor::perform_interrupt(const uint16_t vector) {
// BRK has an unused operand.
++program_counter_;
push(uint8_t(program_counter_ >> 8));
@@ -222,7 +222,7 @@ template<bool is_brk> inline void Executor::perform_interrupt(uint16_t vector) {
set_program_counter(uint16_t(memory_[vector] | (memory_[vector+1] << 8)));
}
void Executor::set_interrupt_request(uint8_t &reg, uint8_t value, uint16_t vector) {
void Executor::set_interrupt_request(uint8_t &reg, const uint8_t value, const uint16_t vector) {
// TODO: this allows interrupts through only if fully enabled at the time they
// signal. Which isn't quite correct, albeit that it seems sufficient for the
// IIgs ADB controller.
@@ -797,7 +797,7 @@ template <Operation operation> void Executor::perform(uint8_t *operand [[maybe_u
}
}
inline void Executor::subtract_duration(int duration) {
inline void Executor::subtract_duration(const int duration) {
// Pass along.
CachingExecutor::subtract_duration(duration);
@@ -846,7 +846,7 @@ inline void Executor::subtract_duration(int duration) {
}
}
inline int Executor::update_timer(Timer &timer, int count) {
inline int Executor::update_timer(Timer &timer, const int count) {
const int next_value = timer.value - count;
if(next_value < 0) {
// Determine how many reloads were required to get above zero.
@@ -859,6 +859,6 @@ inline int Executor::update_timer(Timer &timer, int count) {
return 0;
}
uint8_t Executor::get_output_mask(int port) {
uint8_t Executor::get_output_mask(const int port) {
return port_directions_[port];
}

View File

@@ -35,7 +35,7 @@ struct PortHandler {
* timing is correct to whole-opcode boundaries only.
*/
class Executor: public CachingExecutor {
public:
public:
Executor(PortHandler &);
void set_rom(const std::vector<uint8_t> &rom);
@@ -47,9 +47,9 @@ class Executor: public CachingExecutor {
/*!
Runs, in discrete steps, the minimum number of instructions as it takes to complete at least @c cycles.
*/
void run_for(Cycles cycles);
void run_for(Cycles);
private:
private:
// MARK: - CachingExecutor-facing interface.
friend CachingExecutor;
@@ -57,7 +57,7 @@ class Executor: public CachingExecutor {
/*!
Maps instructions to performers; called by the CachingExecutor and for this instruction set, extremely trivial.
*/
inline PerformerIndex action_for(Instruction instruction) {
inline PerformerIndex action_for(const Instruction instruction) {
// This is a super-simple processor, so the opcode can be used directly to index the performers.
return instruction.opcode;
}
@@ -65,12 +65,11 @@ class Executor: public CachingExecutor {
/*!
Parses from @c start and no later than @c max_address, using the CachingExecutor as a target.
*/
inline void parse(uint16_t start, uint16_t closing_bound) {
inline void parse(const uint16_t start, const uint16_t closing_bound) {
Parser<Executor, false> parser;
parser.parse(*this, &memory_[0], start & 0x1fff, closing_bound);
}
private:
// MARK: - Internal framework for generator performers.
/*!
@@ -82,7 +81,7 @@ class Executor: public CachingExecutor {
fill<int(MinOperation)>(performers_);
}
Performer performer(Operation operation, AddressingMode addressing_mode) {
Performer performer(const Operation operation, const AddressingMode addressing_mode) {
const auto index =
(int(operation) - MinOperation) * (1 + MaxAddressingMode - MinAddressingMode) +
(int(addressing_mode) - MinAddressingMode);
@@ -121,7 +120,7 @@ class Executor: public CachingExecutor {
*/
template <Operation operation, AddressingMode addressing_mode> void perform();
private:
private:
// MARK: - Instruction set state.
// Memory.
@@ -157,7 +156,7 @@ class Executor: public CachingExecutor {
// Access helpers.
inline uint8_t read(uint16_t address);
inline void write(uint16_t address, uint8_t value);
inline void push(uint8_t value);
inline void push(uint8_t);
inline uint8_t pull();
inline void set_flags(uint8_t);
inline uint8_t flags();
@@ -171,7 +170,7 @@ class Executor: public CachingExecutor {
Cycles cycles_;
Cycles cycles_since_port_handler_;
PortHandler &port_handler_;
inline void subtract_duration(int duration);
inline void subtract_duration(int);
};
}

View File

@@ -31,7 +31,7 @@ enum class AddressingMode {
static constexpr auto MaxAddressingMode = int(AddressingMode::ZeroPageRelative);
static constexpr auto MinAddressingMode = int(AddressingMode::Implied);
constexpr int size(AddressingMode mode) {
constexpr int size(const AddressingMode mode) {
// This is coupled to the AddressingMode list above; be careful!
constexpr int sizes[] = {
0, 0, 1,
@@ -92,14 +92,14 @@ enum class Operation: uint8_t {
static constexpr auto MaxOperation = int(Operation::STY);
static constexpr auto MinOperation = int(Operation::BBC0);
constexpr AccessType access_type(Operation operation) {
constexpr AccessType access_type(const Operation operation) {
if(operation < Operation::ADC) return AccessType::None;
if(operation < Operation::ASL) return AccessType::Read;
if(operation < Operation::LDM) return AccessType::ReadModifyWrite;
return AccessType::Write;
}
constexpr bool uses_index_mode(Operation operation) {
constexpr bool uses_index_mode(const Operation operation) {
return
operation == Operation::ADC || operation == Operation::AND ||
operation == Operation::CMP || operation == Operation::EOR ||
@@ -110,7 +110,7 @@ constexpr bool uses_index_mode(Operation operation) {
/*!
@returns The name of @c operation.
*/
inline constexpr const char *operation_name(Operation operation) {
inline constexpr const char *operation_name(const Operation operation) {
#define MAP(x) case Operation::x: return #x;
switch(operation) {
default: break;
@@ -133,7 +133,7 @@ inline constexpr const char *operation_name(Operation operation) {
return "???";
}
inline std::ostream &operator <<(std::ostream &stream, Operation operation) {
inline std::ostream &operator <<(std::ostream &stream, const Operation operation) {
stream << operation_name(operation);
return stream;
}
@@ -141,7 +141,7 @@ inline std::ostream &operator <<(std::ostream &stream, Operation operation) {
/*!
@returns The name of @c addressing_mode.
*/
inline constexpr const char *addressing_mode_name(AddressingMode addressing_mode) {
inline constexpr const char *addressing_mode_name(const AddressingMode addressing_mode) {
switch(addressing_mode) {
default: break;
case AddressingMode::Implied: return "";
@@ -167,7 +167,7 @@ inline constexpr const char *addressing_mode_name(AddressingMode addressing_mode
return "???";
}
inline std::ostream &operator <<(std::ostream &stream, AddressingMode mode) {
inline std::ostream &operator <<(std::ostream &stream, const AddressingMode mode) {
stream << addressing_mode_name(mode);
return stream;
}
@@ -177,7 +177,11 @@ inline std::ostream &operator <<(std::ostream &stream, AddressingMode mode) {
would appear in an assembler. E.g. '$5a' for that zero page address, or '$5a, x' for zero-page indexed from $5a. This function
may access up to three bytes from @c operation onwards.
*/
inline std::string address(AddressingMode addressing_mode, const uint8_t *operation, uint16_t program_counter) {
inline std::string address(
const AddressingMode addressing_mode,
const uint8_t *operation,
const uint16_t program_counter
) {
std::stringstream output;
output << std::hex;
@@ -220,7 +224,8 @@ struct Instruction {
AddressingMode addressing_mode = AddressingMode::Implied;
uint8_t opcode = 0;
Instruction(Operation operation, AddressingMode addressing_mode, uint8_t opcode) : operation(operation), addressing_mode(addressing_mode), opcode(opcode) {}
Instruction(const Operation operation, const AddressingMode addressing_mode, const uint8_t opcode) :
operation(operation), addressing_mode(addressing_mode), opcode(opcode) {}
Instruction(uint8_t opcode) : opcode(opcode) {}
Instruction() = default;
};

View File

@@ -15,7 +15,7 @@
namespace InstructionSet::M50740 {
template<typename Target, bool include_entries_and_accesses> struct Parser {
void parse(Target &target, const uint8_t *storage, uint16_t start, uint16_t closing_bound) {
void parse(Target &target, const uint8_t *storage, uint16_t start, const uint16_t closing_bound) {
Decoder decoder;
while(start <= closing_bound) {
@@ -97,7 +97,10 @@ template<typename Target, bool include_entries_and_accesses> struct Parser {
// Provide any fixed address accesses.
switch(next.second.addressing_mode) {
case AddressingMode::Absolute:
target.add_access(uint16_t(storage[start + 1] | (storage[start + 2] << 8)), access_type(next.second.operation));
target.add_access(
uint16_t(storage[start + 1] | (storage[start + 2] << 8)),
access_type(next.second.operation)
);
break;
case AddressingMode::ZeroPage: case AddressingMode::ZeroPageRelative:
target.add_access(storage[start + 1], access_type(next.second.operation));

View File

@@ -12,7 +12,8 @@ using namespace InstructionSet::PowerPC;
namespace {
template <Model model, bool validate_reserved_bits, Operation operation> Instruction instruction(uint32_t opcode, bool is_supervisor = false) {
template <Model model, bool validate_reserved_bits, Operation operation>
Instruction instruction(const uint32_t opcode, const bool is_supervisor = false) {
// If validation isn't required, there's nothing to do here.
if constexpr (!validate_reserved_bits) {
return Instruction(operation, opcode, is_supervisor);
@@ -243,7 +244,7 @@ template <Model model, bool validate_reserved_bits, Operation operation> Instruc
}
template <Model model, bool validate_reserved_bits>
Instruction Decoder<model, validate_reserved_bits>::decode(uint32_t opcode) {
Instruction Decoder<model, validate_reserved_bits>::decode(const uint32_t opcode) {
// Quick bluffer's guide to PowerPC instruction encoding:
//
// There is a six-bit field at the very top of the instruction.
@@ -332,23 +333,29 @@ Instruction Decoder<model, validate_reserved_bits>::decode(uint32_t opcode) {
default: break;
// 64-bit instructions.
BindConditional(is64bit, SixTen(0b011111, 0b0000001001), mulhdux); BindConditional(is64bit, SixTen(0b011111, 0b1000001001), mulhdux);
BindConditional(is64bit, SixTen(0b011111, 0b0000001001), mulhdux);
BindConditional(is64bit, SixTen(0b011111, 0b1000001001), mulhdux);
BindConditional(is64bit, SixTen(0b011111, 0b0000010101), ldx);
BindConditional(is64bit, SixTen(0b011111, 0b0000011011), sldx);
BindConditional(is64bit, SixTen(0b011111, 0b0000110101), ldux);
BindConditional(is64bit, SixTen(0b011111, 0b0000111010), cntlzdx);
BindConditional(is64bit, SixTen(0b011111, 0b0001000100), td);
BindConditional(is64bit, SixTen(0b011111, 0b0001001001), mulhdx); BindConditional(is64bit, SixTen(0b011111, 0b1001001001), mulhdx);
BindConditional(is64bit, SixTen(0b011111, 0b0001001001), mulhdx);
BindConditional(is64bit, SixTen(0b011111, 0b1001001001), mulhdx);
BindConditional(is64bit, SixTen(0b011111, 0b0001010100), ldarx);
BindConditional(is64bit, SixTen(0b011111, 0b0010010101), stdx);
BindConditional(is64bit, SixTen(0b011111, 0b0010110101), stdux);
BindConditional(is64bit, SixTen(0b011111, 0b0011101001), mulldx); BindConditional(is64bit, SixTen(0b011111, 0b1011101001), mulldx);
BindConditional(is64bit, SixTen(0b011111, 0b0011101001), mulldx);
BindConditional(is64bit, SixTen(0b011111, 0b1011101001), mulldx);
BindConditional(is64bit, SixTen(0b011111, 0b0101010101), lwax);
BindConditional(is64bit, SixTen(0b011111, 0b0101110101), lwaux);
BindConditional(is64bit, SixTen(0b011111, 0b1100111011), sradix); BindConditional(is64bit, SixTen(0b011111, 0b1100111010), sradix);
BindConditional(is64bit, SixTen(0b011111, 0b1100111011), sradix);
BindConditional(is64bit, SixTen(0b011111, 0b1100111010), sradix);
BindConditional(is64bit, SixTen(0b011111, 0b0110110010), slbie);
BindConditional(is64bit, SixTen(0b011111, 0b0111001001), divdux); BindConditional(is64bit, SixTen(0b011111, 0b1111001001), divdux);
BindConditional(is64bit, SixTen(0b011111, 0b0111101001), divdx); BindConditional(is64bit, SixTen(0b011111, 0b1111101001), divdx);
BindConditional(is64bit, SixTen(0b011111, 0b0111001001), divdux);
BindConditional(is64bit, SixTen(0b011111, 0b1111001001), divdux);
BindConditional(is64bit, SixTen(0b011111, 0b0111101001), divdx);
BindConditional(is64bit, SixTen(0b011111, 0b1111101001), divdx);
BindConditional(is64bit, SixTen(0b011111, 0b1000011011), srdx);
BindConditional(is64bit, SixTen(0b011111, 0b1100011010), sradx);
BindConditional(is64bit, SixTen(0b111111, 0b1111011010), extswx);
@@ -356,16 +363,22 @@ Instruction Decoder<model, validate_reserved_bits>::decode(uint32_t opcode) {
// Power instructions; these are all taken from the MPC601 manual rather than
// the PowerPC Programmer's Reference Guide, hence the decimal encoding of the
// ten-bit field.
BindConditional(is601, SixTen(0b011111, 360), absx); BindConditional(is601, SixTen(0b011111, 512 + 360), absx);
BindConditional(is601, SixTen(0b011111, 360), absx);
BindConditional(is601, SixTen(0b011111, 512 + 360), absx);
BindConditional(is601, SixTen(0b011111, 531), clcs);
BindConditional(is601, SixTen(0b011111, 331), divx); BindConditional(is601, SixTen(0b011111, 512 + 331), divx);
BindConditional(is601, SixTen(0b011111, 363), divsx); BindConditional(is601, SixTen(0b011111, 512 + 363), divsx);
BindConditional(is601, SixTen(0b011111, 264), dozx); BindConditional(is601, SixTen(0b011111, 512 + 264), dozx);
BindConditional(is601, SixTen(0b011111, 331), divx);
BindConditional(is601, SixTen(0b011111, 512 + 331), divx);
BindConditional(is601, SixTen(0b011111, 363), divsx);
BindConditional(is601, SixTen(0b011111, 512 + 363), divsx);
BindConditional(is601, SixTen(0b011111, 264), dozx);
BindConditional(is601, SixTen(0b011111, 512 + 264), dozx);
BindConditional(is601, SixTen(0b011111, 277), lscbxx);
BindConditional(is601, SixTen(0b011111, 29), maskgx);
BindConditional(is601, SixTen(0b011111, 541), maskirx);
BindConditional(is601, SixTen(0b011111, 107), mulx); BindConditional(is601, SixTen(0b011111, 512 + 107), mulx);
BindConditional(is601, SixTen(0b011111, 488), nabsx); BindConditional(is601, SixTen(0b011111, 512 + 488), nabsx);
BindConditional(is601, SixTen(0b011111, 107), mulx);
BindConditional(is601, SixTen(0b011111, 512 + 107), mulx);
BindConditional(is601, SixTen(0b011111, 488), nabsx);
BindConditional(is601, SixTen(0b011111, 512 + 488), nabsx);
BindConditional(is601, SixTen(0b011111, 537), rribx);
BindConditional(is601, SixTen(0b011111, 153), slex);
BindConditional(is601, SixTen(0b011111, 217), sleqx);
@@ -553,17 +566,22 @@ Instruction Decoder<model, validate_reserved_bits>::decode(uint32_t opcode) {
if(is64bit(model)) {
switch(opcode & 0b111111'00000'00000'00000'000000'111'00) {
default: break;
case 0b011110'00000'00000'00000'000000'000'00: return instruction<model, validate_reserved_bits, Operation::rldiclx>(opcode);
case 0b011110'00000'00000'00000'000000'001'00: return instruction<model, validate_reserved_bits, Operation::rldicrx>(opcode);
case 0b011110'00000'00000'00000'000000'010'00: return instruction<model, validate_reserved_bits, Operation::rldicx>(opcode);
case 0b011110'00000'00000'00000'000000'011'00: return instruction<model, validate_reserved_bits, Operation::rldimix>(opcode);
case 0b011110'00000'00000'00000'000000'000'00:
return instruction<model, validate_reserved_bits, Operation::rldiclx>(opcode);
case 0b011110'00000'00000'00000'000000'001'00:
return instruction<model, validate_reserved_bits, Operation::rldicrx>(opcode);
case 0b011110'00000'00000'00000'000000'010'00:
return instruction<model, validate_reserved_bits, Operation::rldicx>(opcode);
case 0b011110'00000'00000'00000'000000'011'00:
return instruction<model, validate_reserved_bits, Operation::rldimix>(opcode);
}
}
// stwcx. and stdcx.
switch(opcode & 0b111111'0000'0000'0000'0000'111111111'1) {
default: break;
case 0b011111'0000'0000'0000'0000'010010110'1: return instruction<model, validate_reserved_bits, Operation::stwcx_>(opcode);
case 0b011111'0000'0000'0000'0000'010010110'1:
return instruction<model, validate_reserved_bits, Operation::stwcx_>(opcode);
case 0b011111'0000'0000'0000'0000'011010110'1:
if(is64bit(model)) return instruction<model, validate_reserved_bits, Operation::stdcx_>(opcode);
return Instruction(opcode);
@@ -573,11 +591,16 @@ Instruction Decoder<model, validate_reserved_bits>::decode(uint32_t opcode) {
if(is64bit(model)) {
switch(opcode & 0b111111'00'00000000'00000000'000000'11) {
default: break;
case 0b111010'00'00000000'00000000'000000'00: return instruction<model, validate_reserved_bits, Operation::ld>(opcode);
case 0b111010'00'00000000'00000000'000000'01: return instruction<model, validate_reserved_bits, Operation::ldu>(opcode);
case 0b111010'00'00000000'00000000'000000'10: return instruction<model, validate_reserved_bits, Operation::lwa>(opcode);
case 0b111110'00'00000000'00000000'000000'00: return instruction<model, validate_reserved_bits, Operation::std>(opcode);
case 0b111110'00'00000000'00000000'000000'01: return instruction<model, validate_reserved_bits, Operation::stdu>(opcode);
case 0b111010'00'00000000'00000000'000000'00:
return instruction<model, validate_reserved_bits, Operation::ld>(opcode);
case 0b111010'00'00000000'00000000'000000'01:
return instruction<model, validate_reserved_bits, Operation::ldu>(opcode);
case 0b111010'00'00000000'00000000'000000'10:
return instruction<model, validate_reserved_bits, Operation::lwa>(opcode);
case 0b111110'00'00000000'00000000'000000'00:
return instruction<model, validate_reserved_bits, Operation::std>(opcode);
case 0b111110'00'00000000'00000000'000000'01:
return instruction<model, validate_reserved_bits, Operation::stdu>(opcode);
}
}

View File

@@ -21,15 +21,15 @@ enum class Model {
MPC620,
};
constexpr bool is64bit(Model model) {
constexpr bool is64bit(const Model model) {
return model == Model::MPC620;
}
constexpr bool is32bit(Model model) {
constexpr bool is32bit(const Model model) {
return !is64bit(model);
}
constexpr bool is601(Model model) {
constexpr bool is601(const Model model) {
return model == Model::MPC601;
}
@@ -45,7 +45,7 @@ constexpr bool is601(Model model) {
TODO: determine what specific models of PowerPC do re: reserved bits.
*/
template <Model model, bool validate_reserved_bits = false> struct Decoder {
Instruction decode(uint32_t opcode);
Instruction decode(uint32_t);
};
}

View File

@@ -1363,8 +1363,9 @@ struct Instruction {
uint32_t opcode = 0;
constexpr Instruction() noexcept = default;
constexpr Instruction(uint32_t opcode) noexcept : opcode(opcode) {}
constexpr Instruction(Operation operation, uint32_t opcode, bool is_supervisor = false) noexcept : operation(operation), is_supervisor(is_supervisor), opcode(opcode) {}
constexpr Instruction(const uint32_t opcode) noexcept : opcode(opcode) {}
constexpr Instruction(const Operation operation, const uint32_t opcode, const bool is_supervisor = false) noexcept :
operation(operation), is_supervisor(is_supervisor), opcode(opcode) {}
// Instruction fields are decoded below; naming is a compromise between
// Motorola's documentation and IBM's.

View File

@@ -30,23 +30,23 @@ enum class AccessType {
PreauthorisedRead,
};
constexpr bool is_writeable(AccessType type) {
constexpr bool is_writeable(const AccessType type) {
return type == AccessType::ReadModifyWrite || type == AccessType::Write;
}
template <typename IntT, AccessType type> struct Accessor;
// Reads: return a value directly.
template <typename IntT> struct Accessor<IntT, AccessType::Read> { using type = IntT; };
template <typename IntT> struct Accessor<IntT, AccessType::PreauthorisedRead> { using type = IntT; };
template <typename IntT> struct Accessor<IntT, AccessType::Read> { using type = const IntT; };
template <typename IntT> struct Accessor<IntT, AccessType::PreauthorisedRead> { using type = const IntT; };
// Writes: return a custom type that can be written but not read.
template <typename IntT>
class Writeable {
public:
public:
Writeable(IntT &target) : target_(target) {}
IntT operator=(IntT value) { return target_ = value; }
private:
private:
IntT &target_;
};
template <typename IntT> struct Accessor<IntT, AccessType::Write> { using type = Writeable<IntT>; };

View File

@@ -15,7 +15,10 @@
using namespace InstructionSet::x86;
template <Model model>
std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(const uint8_t *source, std::size_t length) {
std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(
const uint8_t *source,
const std::size_t length
) {
// Instruction length limits:
//
// 8086/80186: none*
@@ -1124,6 +1127,6 @@ template class InstructionSet::x86::Decoder<InstructionSet::x86::Model::i80186>;
template class InstructionSet::x86::Decoder<InstructionSet::x86::Model::i80286>;
template class InstructionSet::x86::Decoder<InstructionSet::x86::Model::i80386>;
std::pair<int, Instruction<false>> Decoder8086::decode(const uint8_t *source, std::size_t length) {
std::pair<int, Instruction<false>> Decoder8086::decode(const uint8_t *const source, const std::size_t length) {
return decoder.decode(source, length);
}

View File

@@ -22,7 +22,7 @@ namespace InstructionSet::x86 {
This is an experimental implementation; it has not yet undergone significant testing.
*/
template <Model model> class Decoder {
public:
public:
using InstructionT = Instruction<is_32bit(model)>;
/*!
@@ -49,7 +49,7 @@ template <Model model> class Decoder {
*/
void set_32bit_protected_mode(bool);
private:
private:
enum class Phase {
/// Captures all prefixes and continues until an instruction byte is encountered.
Instruction,

View File

@@ -77,7 +77,7 @@ enum class Condition {
};
class Flags {
public:
public:
using FlagT = uint32_t;
// Flag getters.
@@ -121,7 +121,7 @@ class Flags {
/// • Flag::Interrupt: sets interrupt if @c value is non-zero;
/// • Flag::Trap: sets interrupt if @c value is non-zero;
/// • Flag::Direction: sets direction if @c value is non-zero.
template <typename IntT, Flag... flags> void set_from(IntT value) {
template <typename IntT, Flag... flags> void set_from(const IntT value) {
for(const auto flag: {flags...}) {
switch(flag) {
default: break;
@@ -137,7 +137,7 @@ class Flags {
}
}
}
template <Flag... flags> void set_from(FlagT value) {
template <Flag... flags> void set_from(const FlagT value) {
set_from<FlagT, flags...>(value);
}
@@ -207,7 +207,7 @@ class Flags {
return get() == rhs.get();
}
private:
private:
// Non-zero => set; zero => unset.
uint32_t carry_;
uint32_t auxiliary_carry_;

View File

@@ -240,7 +240,8 @@ void idiv(
IF OperandSize = 8 (* word/byte operation *)
THEN
temp ← AX / SRC; (* signed division *)
IF (temp > 7FH) OR (temp < 80H) (* if a positive result is greater than 7FH or a negative result is less than 80H *)
IF (temp > 7FH) OR (temp < 80H) (* if a positive result is greater than
7FH or a negative result is less than 80H *)
THEN #DE; (* divide error *) ;
ELSE
AL ← temp;
@@ -250,7 +251,8 @@ void idiv(
IF OperandSize = 16 (* doubleword/word operation *)
THEN
temp ← DX:AX / SRC; (* signed division *)
IF (temp > 7FFFH) OR (temp < 8000H) (* if a positive result is greater than 7FFFH or a negative result is less than 8000H *)
IF (temp > 7FFFH) OR (temp < 8000H) (* if a positive result is greater than 7FFFH or a
negative result is less than 8000H *)
THEN #DE; (* divide error *) ;
ELSE
AX ← temp;
@@ -258,7 +260,8 @@ void idiv(
FI;
ELSE (* quadword/doubleword operation *)
temp ← EDX:EAX / SRC; (* signed division *)
IF (temp > 7FFFFFFFH) OR (temp < 80000000H) (* if a positive result is greater than 7FFFFFFFH or a negative result is less than 80000000H *)
IF (temp > 7FFFFFFFH) OR (temp < 80000000H) (* if a positive result is greater than 7FFFFFFFH
or a negative result is less than 80000000H *)
THEN #DE; (* divide error *) ;
ELSE
EAX ← temp;
@@ -350,7 +353,11 @@ void neg(
The CF flag cleared to 0 if the source operand is 0; otherwise it is set to 1.
The OF, SF, ZF, AF, and PF flags are set according to the result.
*/
context.flags.template set_from<Flag::AuxiliaryCarry>(Numeric::carried_in<4>(IntT(0), destination, IntT(-destination)));
context.flags.template set_from<Flag::AuxiliaryCarry>(Numeric::carried_in<4>(
IntT(0),
destination,
IntT(-destination))
);
destination = -destination;

View File

@@ -38,7 +38,7 @@ void aaas(
template <typename ContextT>
void aad(
CPU::RegisterPair16 &ax,
uint8_t imm,
const uint8_t imm,
ContextT &context
) {
/*
@@ -59,7 +59,7 @@ void aad(
template <typename ContextT>
void aam(
CPU::RegisterPair16 &ax,
uint8_t imm,
const uint8_t imm,
ContextT &context
) {
/*

View File

@@ -18,8 +18,8 @@ namespace InstructionSet::x86::Primitive {
template <typename IntT, typename ContextT>
void jump(
bool condition,
IntT displacement,
const bool condition,
const IntT displacement,
ContextT &context
) {
/*
@@ -42,7 +42,7 @@ void jump(
template <typename IntT, typename OffsetT, typename ContextT>
void loop(
modify_t<IntT> counter,
OffsetT displacement,
const OffsetT displacement,
ContextT &context
) {
--counter;
@@ -54,7 +54,7 @@ void loop(
template <typename IntT, typename OffsetT, typename ContextT>
void loope(
modify_t<IntT> counter,
OffsetT displacement,
const OffsetT displacement,
ContextT &context
) {
--counter;
@@ -66,7 +66,7 @@ void loope(
template <typename IntT, typename OffsetT, typename ContextT>
void loopne(
modify_t<IntT> counter,
OffsetT displacement,
const OffsetT displacement,
ContextT &context
) {
--counter;
@@ -125,20 +125,28 @@ void call_far(
return;
case Source::Indirect:
source_address = uint16_t(address<Source::Indirect, uint16_t, AccessType::Read>(instruction, pointer, context));
source_address = uint16_t(
address<Source::Indirect, uint16_t, AccessType::Read>(instruction, pointer, context)
);
break;
case Source::IndirectNoBase:
source_address = uint16_t(address<Source::IndirectNoBase, uint16_t, AccessType::Read>(instruction, pointer, context));
source_address = uint16_t(
address<Source::IndirectNoBase, uint16_t, AccessType::Read>(instruction, pointer, context)
);
break;
case Source::DirectAddress:
source_address = uint16_t(address<Source::DirectAddress, uint16_t, AccessType::Read>(instruction, pointer, context));
source_address = uint16_t(
address<Source::DirectAddress, uint16_t, AccessType::Read>(instruction, pointer, context)
);
break;
}
context.memory.preauthorise_read(source_segment, source_address, sizeof(uint16_t) * 2);
const uint16_t offset = context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(source_segment, source_address);
const auto offset =
context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(source_segment, source_address);
source_address += 2;
const uint16_t segment = context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(source_segment, source_address);
const auto segment =
context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(source_segment, source_address);
// At least on an 8086, the stack writes occur after the target address read.
push<uint16_t, true>(context.registers.cs(), context);
@@ -157,25 +165,35 @@ void jump_far(
const auto pointer = instruction.destination();
switch(pointer.source()) {
default:
case Source::Immediate: context.flow_controller.template jump<uint16_t>(instruction.segment(), instruction.offset()); return;
case Source::Immediate:
context.flow_controller.template jump<uint16_t>(instruction.segment(), instruction.offset());
return;
case Source::Indirect:
source_address = uint16_t(address<Source::Indirect, uint16_t, AccessType::Read>(instruction, pointer, context));
source_address = uint16_t(
address<Source::Indirect, uint16_t, AccessType::Read>(instruction, pointer, context)
);
break;
case Source::IndirectNoBase:
source_address = uint16_t(address<Source::IndirectNoBase, uint16_t, AccessType::Read>(instruction, pointer, context));
source_address = uint16_t(
address<Source::IndirectNoBase, uint16_t, AccessType::Read>(instruction, pointer, context)
);
break;
case Source::DirectAddress:
source_address = uint16_t(address<Source::DirectAddress, uint16_t, AccessType::Read>(instruction, pointer, context));
source_address = uint16_t(
address<Source::DirectAddress, uint16_t, AccessType::Read>(instruction, pointer, context)
);
break;
}
const Source source_segment = instruction.data_segment();
context.memory.preauthorise_read(source_segment, source_address, sizeof(uint16_t) * 2);
const uint16_t offset = context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(source_segment, source_address);
const auto offset =
context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(source_segment, source_address);
source_address += 2;
const uint16_t segment = context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(source_segment, source_address);
const auto segment =
context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(source_segment, source_address);
context.flow_controller.template jump<uint16_t>(segment, offset);
}
@@ -193,7 +211,7 @@ void iret(
template <typename InstructionT, typename ContextT>
void ret_near(
InstructionT instruction,
const InstructionT instruction,
ContextT &context
) {
const auto ip = pop<uint16_t, false>(context);
@@ -203,7 +221,7 @@ void ret_near(
template <typename InstructionT, typename ContextT>
void ret_far(
InstructionT instruction,
const InstructionT instruction,
ContextT &context
) {
context.memory.preauthorise_stack_read(sizeof(uint16_t) * 2);
@@ -233,9 +251,11 @@ void bound(
const auto source_segment = instruction.data_segment();
context.memory.preauthorise_read(source_segment, source, 2*sizeof(IntT));
const sIntT lower_bound = sIntT(context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(source_segment, source));
const auto lower_bound =
sIntT(context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(source_segment, source));
source += 2;
const sIntT upper_bound = sIntT(context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(source_segment, source));
const auto upper_bound =
sIntT(context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(source_segment, source));
if(sIntT(destination) < lower_bound || sIntT(destination) > upper_bound) {
interrupt(Interrupt::BoundRangeExceeded, context);

View File

@@ -14,7 +14,7 @@ namespace InstructionSet::x86::Primitive {
template <typename IntT, typename ContextT>
void out(
uint16_t port,
const uint16_t port,
read_t<IntT> value,
ContextT &context
) {
@@ -23,7 +23,7 @@ void out(
template <typename IntT, typename ContextT>
void in(
uint16_t port,
const uint16_t port,
write_t<IntT> value,
ContextT &context
) {

View File

@@ -99,7 +99,7 @@ void cbw(
template <typename IntT>
void cwd(
IntT &dx,
IntT ax
const IntT ax
) {
dx = ax & Numeric::top_bit<IntT>() ? IntT(~0) : IntT(0);
}

View File

@@ -176,8 +176,12 @@ template <
case Operation::ESC:
case Operation::NOP: return;
case Operation::AAM: Primitive::aam(context.registers.axp(), uint8_t(instruction.operand()), context); return;
case Operation::AAD: Primitive::aad(context.registers.axp(), uint8_t(instruction.operand()), context); return;
case Operation::AAM:
Primitive::aam(context.registers.axp(), uint8_t(instruction.operand()), context);
return;
case Operation::AAD:
Primitive::aad(context.registers.axp(), uint8_t(instruction.operand()), context);
return;
case Operation::AAA: Primitive::aaas<true>(context.registers.axp(), context); return;
case Operation::AAS: Primitive::aaas<false>(context.registers.axp(), context); return;
case Operation::DAA: Primitive::daas<true>(context.registers.al(), context); return;
@@ -417,10 +421,12 @@ template <
break;
case Operation::OUTS:
Primitive::outs<IntT, AddressT, Repetition::None>(instruction, eCX(), context.registers.dx(), eSI(), context);
Primitive::outs<IntT, AddressT, Repetition::None>(
instruction, eCX(), context.registers.dx(), eSI(), context);
return;
case Operation::OUTS_REP:
Primitive::outs<IntT, AddressT, Repetition::Rep>(instruction, eCX(), context.registers.dx(), eSI(), context);
Primitive::outs<IntT, AddressT, Repetition::Rep>(
instruction, eCX(), context.registers.dx(), eSI(), context);
return;
case Operation::INS:
@@ -453,7 +459,7 @@ template <
const InstructionT &instruction,
ContextT &context
) {
auto size = [](DataSize operation_size, AddressSize address_size) constexpr -> int {
const auto size = [](DataSize operation_size, AddressSize address_size) constexpr -> int {
return int(operation_size) + (int(address_size) << 2);
};
@@ -508,7 +514,7 @@ template <
template <
typename ContextT
> void interrupt(
int index,
const int index,
ContextT &context
) {
const uint32_t address = static_cast<uint32_t>(index) << 2;

View File

@@ -21,9 +21,9 @@ namespace InstructionSet::x86 {
/// is copied to @c *immediate and @c immediate is returned.
template <typename IntT, AccessType access, typename InstructionT, typename ContextT>
typename Accessor<IntT, access>::type resolve(
InstructionT &instruction,
Source source,
DataPointer pointer,
const InstructionT &instruction,
const Source source,
const DataPointer pointer,
ContextT &context,
IntT *none = nullptr,
IntT *immediate = nullptr
@@ -67,7 +67,8 @@ IntT *register_(ContextT &context) {
// Slightly contorted if chain here and below:
//
// (i) does the `constexpr` version of a `switch`; and
// (i) ensures .eax() etc aren't called on @c registers for 16-bit processors, so they need not implement 32-bit storage.
// (i) ensures .eax() etc aren't called on @c registers for 16-bit processors,
// so they need not implement 32-bit storage.
if constexpr (supports_dword && std::is_same_v<IntT, uint32_t>) { return &context.registers.eax(); }
else if constexpr (std::is_same_v<IntT, uint16_t>) { return &context.registers.ax(); }
else if constexpr (std::is_same_v<IntT, uint8_t>) { return &context.registers.al(); }
@@ -150,12 +151,12 @@ uint32_t address(
// See forward declaration, above, for details.
template <typename IntT, AccessType access, typename InstructionT, typename ContextT>
typename Accessor<IntT, access>::type resolve(
InstructionT &instruction,
Source source,
DataPointer pointer,
const InstructionT &instruction,
const Source source,
const DataPointer pointer,
ContextT &context,
IntT *none,
IntT *immediate
IntT *const immediate
) {
// Rules:
//

View File

@@ -15,7 +15,7 @@ namespace InstructionSet::x86::Primitive {
template <typename IntT, typename ContextT>
void rcl(
modify_t<IntT> destination,
uint8_t count,
const uint8_t count,
ContextT &context
) {
/*
@@ -76,7 +76,7 @@ void rcl(
template <typename IntT, typename ContextT>
void rcr(
modify_t<IntT> destination,
uint8_t count,
const uint8_t count,
ContextT &context
) {
/*
@@ -123,7 +123,7 @@ void rcr(
template <typename IntT, typename ContextT>
void rol(
modify_t<IntT> destination,
uint8_t count,
const uint8_t count,
ContextT &context
) {
/*
@@ -175,7 +175,7 @@ void rol(
template <typename IntT, typename ContextT>
void ror(
modify_t<IntT> destination,
uint8_t count,
const uint8_t count,
ContextT &context
) {
/*
@@ -283,7 +283,7 @@ void ror(
template <typename IntT, typename ContextT>
void sal(
modify_t<IntT> destination,
uint8_t count,
const uint8_t count,
ContextT &context
) {
switch(count) {
@@ -314,7 +314,7 @@ void sal(
template <typename IntT, typename ContextT>
void sar(
modify_t<IntT> destination,
uint8_t count,
const uint8_t count,
ContextT &context
) {
if(!count) {
@@ -337,7 +337,7 @@ void sar(
template <typename IntT, typename ContextT>
void shr(
modify_t<IntT> destination,
uint8_t count,
const uint8_t count,
ContextT &context
) {
if(!count) {

View File

@@ -499,10 +499,10 @@ enum class Source: uint8_t {
/// getter is used).
IndirectNoBase = Indirect - 1,
};
constexpr bool is_register(Source source) {
constexpr bool is_register(const Source source) {
return source < Source::None;
}
constexpr bool is_segment_register(Source source) {
constexpr bool is_segment_register(const Source source) {
return is_register(source) && source >= Source::ES;
}
@@ -698,14 +698,25 @@ class DataPointer {
};
template<bool is_32bit> class Instruction {
public:
public:
using DisplacementT = typename std::conditional<is_32bit, int32_t, int16_t>::type;
using ImmediateT = typename std::conditional<is_32bit, uint32_t, uint16_t>::type;
using AddressT = ImmediateT;
constexpr Instruction() noexcept = default;
constexpr Instruction(Operation operation) noexcept :
Instruction(operation, Source::None, Source::None, ScaleIndexBase(), false, AddressSize::b16, Source::None, DataSize::None, 0, 0) {}
Instruction(
operation,
Source::None,
Source::None,
ScaleIndexBase(),
false,
AddressSize::b16,
Source::None,
DataSize::None,
0,
0
) {}
constexpr Instruction(
Operation operation,
Source source,
@@ -860,7 +871,7 @@ template<bool is_32bit> class Instruction {
return true;
}
private:
private:
Operation operation_ = Operation::Invalid;
// Packing and encoding of fields is admittedly somewhat convoluted; what this
@@ -907,7 +918,6 @@ template<bool is_32bit> class Instruction {
static constexpr uint8_t sib_masks[] = {
0x1f, 0x1f, 0x1f, 0x18
};
};
static_assert(sizeof(Instruction<true>) <= 16);
@@ -962,5 +972,4 @@ std::string to_string(
Model model,
int offset_length = 0,
int immediate_length = 0);
}

View File

@@ -19,7 +19,7 @@ enum class Model {
i80386,
};
static constexpr bool is_32bit(Model model) { return model >= Model::i80386; }
static constexpr bool is_32bit(const Model model) { return model >= Model::i80386; }
template <bool is_32bit> struct AddressT { using type = uint16_t; };
template <> struct AddressT<true> { using type = uint32_t; };

View File

@@ -35,7 +35,7 @@ enum Key: uint16_t {
KeyBreak = 0xfffd,
};
constexpr bool is_modifier(Key key) {
constexpr bool is_modifier(const Key key) {
return (key == KeyShift) || (key == KeyControl) || (key == KeyFunc);
}

View File

@@ -25,8 +25,8 @@ enum class GraphicsMode {
/// Fat low res mode is regular low res mode, but clocked out at 7Mhz rather than 14, leading to improper colours.
FatLowRes
};
constexpr bool is_text_mode(GraphicsMode m) { return m <= GraphicsMode::DoubleText; }
constexpr bool is_double_mode(GraphicsMode m) { return int(m) & 1; }
constexpr bool is_text_mode(const GraphicsMode m) { return m <= GraphicsMode::DoubleText; }
constexpr bool is_double_mode(const GraphicsMode m) { return int(m) & 1; }
template <typename TimeUnit> class VideoSwitches {
public:

View File

@@ -86,7 +86,9 @@ class Video: public Apple::II::VideoSwitches<Cycles> {
DoubleHighResMono,
SuperHighRes
};
constexpr bool is_colour_ntsc(GraphicsMode m) { return m >= GraphicsMode::HighRes && m <= GraphicsMode::FatLowRes; }
constexpr bool is_colour_ntsc(const GraphicsMode m) {
return m >= GraphicsMode::HighRes && m <= GraphicsMode::FatLowRes;
}
GraphicsMode graphics_mode(int row) const {
if(new_video_ & 0x80) {

View File

@@ -59,7 +59,7 @@ enum class Source {
WDFDC,
};
constexpr bool is_enabled(Source source) {
constexpr bool is_enabled(const Source source) {
#ifdef NDEBUG
return false;
#endif
@@ -133,12 +133,12 @@ constexpr const char *prefix(Source source) {
template <Source source>
class Logger {
public:
public:
static constexpr bool enabled = is_enabled(source);
struct LogLine {
public:
LogLine(FILE *stream) : stream_(stream) {
LogLine(FILE *const stream) : stream_(stream) {
if constexpr (!enabled) return;
const auto source_prefix = prefix(source);
@@ -152,7 +152,7 @@ class Logger {
fprintf(stream_, "\n");
}
void append(const char *format, ...) {
void append(const char *const format, ...) {
if constexpr (!enabled) return;
va_list args;
va_start(args, format);

View File

@@ -50,7 +50,7 @@ enum class DisplayType {
CompositeMonochrome
};
constexpr bool is_composite(DisplayType type) {
constexpr bool is_composite(const DisplayType type) {
return type == DisplayType::CompositeColour || type == DisplayType::CompositeMonochrome;
}

View File

@@ -38,10 +38,10 @@ enum Personality {
PWDC65C02, // like the Rockwell, but with STP and WAI
};
constexpr bool has_decimal_mode(Personality p) { return p >= Personality::P6502; }
constexpr bool is_65c02(Personality p) { return p >= Personality::PSynertek65C02; }
constexpr bool has_bbrbbsrmbsmb(Personality p) { return p >= Personality::PRockwell65C02; }
constexpr bool has_stpwai(Personality p) { return p >= Personality::PWDC65C02; }
constexpr bool has_decimal_mode(const Personality p) { return p >= Personality::P6502; }
constexpr bool is_65c02(const Personality p) { return p >= Personality::PSynertek65C02; }
constexpr bool has_bbrbbsrmbsmb(const Personality p) { return p >= Personality::PRockwell65C02; }
constexpr bool has_stpwai(const Personality p) { return p >= Personality::PWDC65C02; }
/*!
An opcode that is guaranteed to cause a 6502 to jam.

View File

@@ -48,7 +48,7 @@ template <> class BusHandlerT<Type::TWDC65816>: public BusHandler<uint32_t> {};
/*
Query for implemented registers.
*/
constexpr bool has(Type processor_type, Register r) {
constexpr bool has(const Type processor_type, const Register r) {
switch(r) {
case Register::LastOperationAddress:
case Register::ProgramCounter:
@@ -67,7 +67,7 @@ constexpr bool has(Type processor_type, Register r) {
}
}
constexpr bool has_extended_bus_output(Type processor_type) {
constexpr bool has_extended_bus_output(const Type processor_type) {
return processor_type == Type::TWDC65816;
}

View File

@@ -115,7 +115,7 @@ class ProcessorStorage {
void *destination = nullptr;
PartialMachineCycle machine_cycle{};
};
static constexpr bool is_terminal(MicroOp::Type type) {
static constexpr bool is_terminal(const MicroOp::Type type) {
return type == MicroOp::MoveToNextProgram || type == MicroOp::DecodeOperation;
}

View File

@@ -16,7 +16,7 @@ enum class Density {
Single, Double, High
};
constexpr bool is_mfm(Density density) {
constexpr bool is_mfm(const Density density) {
return density != Density::Single;
}