mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-24 10:31:15 +00:00
238 lines
6.6 KiB
C++
238 lines
6.6 KiB
C++
//
|
|
// Z80Storage.hpp
|
|
// Clock Signal
|
|
//
|
|
// Created by Thomas Harte on 01/09/2017.
|
|
// Copyright 2017 Thomas Harte. All rights reserved.
|
|
//
|
|
|
|
/*!
|
|
A repository for all the internal state of a CPU::Z80::Processor; extracted into a separate base
|
|
class in order to remove it from visibility within the main Z80.hpp.
|
|
*/
|
|
|
|
class ProcessorStorage {
|
|
protected:
|
|
struct MicroOp {
|
|
enum Type {
|
|
BusOperation,
|
|
IncrementR,
|
|
DecodeOperation,
|
|
MoveToNextProgram,
|
|
|
|
Increment8NoFlags,
|
|
Increment8,
|
|
Increment16,
|
|
Decrement8,
|
|
Decrement16,
|
|
Move8,
|
|
Move16,
|
|
|
|
IncrementPC,
|
|
|
|
AssembleAF,
|
|
DisassembleAF,
|
|
|
|
And,
|
|
Or,
|
|
Xor,
|
|
|
|
TestNZ,
|
|
TestZ,
|
|
TestNC,
|
|
TestC,
|
|
TestPO,
|
|
TestPE,
|
|
TestP,
|
|
TestM,
|
|
|
|
ADD16, ADC16, SBC16,
|
|
CP8, SUB8, SBC8, ADD8, ADC8,
|
|
NEG,
|
|
|
|
ExDEHL, ExAFAFDash, EXX,
|
|
|
|
EI, DI, IM,
|
|
|
|
LDI, LDIR, LDD, LDDR,
|
|
CPI, CPIR, CPD, CPDR,
|
|
INI, INIR, IND, INDR,
|
|
OUTI, OUTD, OUT_R,
|
|
|
|
RLA, RLCA, RRA, RRCA,
|
|
RLC, RRC, RL, RR,
|
|
SLA, SRA, SLL, SRL,
|
|
RLD, RRD,
|
|
|
|
SetInstructionPage,
|
|
CalculateIndexAddress,
|
|
|
|
BeginNMI,
|
|
BeginIRQ,
|
|
BeginIRQMode0,
|
|
RETN,
|
|
JumpTo66,
|
|
HALT,
|
|
|
|
/// Decrements BC; if BC is 0 then moves to the next instruction. Otherwise allows this instruction to finish.
|
|
DJNZ,
|
|
|
|
DAA,
|
|
CPL,
|
|
SCF,
|
|
CCF,
|
|
|
|
/// Resets the bit in @c source implied by @c operation_ .
|
|
RES,
|
|
/// Tests the bit in @c source implied by @c operation_ .
|
|
BIT,
|
|
/// Sets the bit in @c source implied by @c operation_ .
|
|
SET,
|
|
|
|
/// Sets @c memptr_ to the target address implied by @c operation_ .
|
|
CalculateRSTDestination,
|
|
|
|
/// Resets subtract and carry, sets sign, zero, five and three according to the value of @c a_ and sets parity to the value of @c IFF2 .
|
|
SetAFlags,
|
|
/// Resets subtract and carry, sets sign, zero, five and three according to the value of @c operation and sets parity the same as sign.
|
|
SetInFlags,
|
|
/// Sets @c memptr_ to @c bc_.full+1 .
|
|
SetOutFlags,
|
|
/// Sets @c temp8_ to 0.
|
|
SetZero,
|
|
|
|
/// A no-op; used in instruction lists to indicate where an index calculation should go if this is an I[X/Y]+d operation.
|
|
IndexedPlaceHolder,
|
|
|
|
/// Sets @c memptr_ to (a_ << 8) + ((source_ + 1) & 0xff)
|
|
SetAddrAMemptr,
|
|
|
|
/// Resets: IFF1, IFF2, interrupt mode, the PC, I and R; sets all flags, the SP to 0xffff and a_ to 0xff.
|
|
Reset
|
|
};
|
|
Type type = Type::Reset;
|
|
void *source = nullptr;
|
|
void *destination = nullptr;
|
|
PartialMachineCycle machine_cycle{};
|
|
};
|
|
static constexpr bool is_terminal(MicroOp::Type type) {
|
|
return type == MicroOp::MoveToNextProgram || type == MicroOp::DecodeOperation;
|
|
}
|
|
|
|
struct InstructionPage {
|
|
std::vector<MicroOp *> instructions;
|
|
std::vector<MicroOp> all_operations;
|
|
std::vector<MicroOp> fetch_decode_execute;
|
|
MicroOp *fetch_decode_execute_data = nullptr;
|
|
bool is_indexed = false;
|
|
};
|
|
|
|
ProcessorStorage();
|
|
void install_default_instruction_set();
|
|
|
|
uint8_t a_;
|
|
RegisterPair16 bc_, de_, hl_;
|
|
RegisterPair16 af_dash_, bc_dash_, de_dash_, hl_dash_;
|
|
RegisterPair16 ix_, iy_, pc_, sp_;
|
|
RegisterPair16 ir_, refresh_addr_;
|
|
bool iff1_ = false, iff2_ = false;
|
|
int interrupt_mode_ = 0;
|
|
uint16_t pc_increment_ = 1;
|
|
uint8_t sign_result_; // the sign flag is set if the value in sign_result_ is negative
|
|
uint8_t zero_result_; // the zero flag is set if the value in zero_result_ is zero
|
|
uint8_t half_carry_result_; // the half-carry flag is set if bit 4 of half_carry_result_ is set
|
|
uint8_t bit53_result_; // the bit 3 and 5 flags are set if the corresponding bits of bit53_result_ are set
|
|
uint8_t parity_overflow_result_; // the parity/overflow flag is set if the corresponding bit of parity_overflow_result_ is set
|
|
uint8_t subtract_flag_; // contains a copy of the subtract flag in isolation
|
|
uint8_t carry_result_; // the carry flag is set if bit 0 of carry_result_ is set
|
|
uint8_t halt_mask_ = 0xff;
|
|
|
|
unsigned int flag_adjustment_history_ = 0; // a shifting record of whether each opcode set any flags; it turns out
|
|
// that knowledge of what the last opcode did is necessary to get bits 5 & 3
|
|
// correct for SCF and CCF.
|
|
|
|
uint16_t last_address_bus_ = 0; // The value most recently put out on the address bus.
|
|
|
|
HalfCycles number_of_cycles_;
|
|
|
|
enum Interrupt: uint8_t {
|
|
IRQ = 0x01,
|
|
NMI = 0x02,
|
|
Reset = 0x04,
|
|
PowerOn = 0x08
|
|
};
|
|
uint8_t request_status_ = Interrupt::PowerOn;
|
|
uint8_t last_request_status_ = Interrupt::PowerOn;
|
|
bool irq_line_ = false, nmi_line_ = false;
|
|
bool bus_request_line_ = false;
|
|
bool wait_line_ = false;
|
|
|
|
uint8_t operation_;
|
|
RegisterPair16 temp16_, memptr_;
|
|
uint8_t temp8_;
|
|
|
|
const MicroOp *scheduled_program_counter_ = nullptr;
|
|
|
|
std::vector<MicroOp> conditional_call_untaken_program_;
|
|
std::vector<MicroOp> reset_program_;
|
|
std::vector<MicroOp> irq_program_[3];
|
|
std::vector<MicroOp> nmi_program_;
|
|
InstructionPage *current_instruction_page_;
|
|
|
|
InstructionPage base_page_;
|
|
InstructionPage ed_page_;
|
|
InstructionPage fd_page_;
|
|
InstructionPage dd_page_;
|
|
|
|
InstructionPage cb_page_;
|
|
InstructionPage fdcb_page_;
|
|
InstructionPage ddcb_page_;
|
|
|
|
/*!
|
|
Gets the flags register.
|
|
|
|
@see set_flags
|
|
|
|
@returns The current value of the flags register.
|
|
*/
|
|
uint8_t get_flags() const {
|
|
return
|
|
(sign_result_ & Flag::Sign) |
|
|
(zero_result_ ? 0 : Flag::Zero) |
|
|
(bit53_result_ & (Flag::Bit5 | Flag::Bit3)) |
|
|
(half_carry_result_ & Flag::HalfCarry) |
|
|
(parity_overflow_result_ & Flag::Parity) |
|
|
subtract_flag_ |
|
|
(carry_result_ & Flag::Carry);
|
|
}
|
|
|
|
/*!
|
|
Sets the flags register.
|
|
|
|
@see set_flags
|
|
|
|
@param flags The new value of the flags register.
|
|
*/
|
|
void set_flags(uint8_t flags) {
|
|
sign_result_ = flags;
|
|
zero_result_ = (flags & Flag::Zero) ^ Flag::Zero;
|
|
bit53_result_ = flags;
|
|
half_carry_result_ = flags;
|
|
parity_overflow_result_ = flags;
|
|
subtract_flag_ = flags & Flag::Subtract;
|
|
carry_result_ = flags;
|
|
}
|
|
|
|
typedef MicroOp InstructionTable[256][30];
|
|
virtual void assemble_page(InstructionPage &target, InstructionTable &table, bool add_offsets) = 0;
|
|
virtual void copy_program(const MicroOp *source, std::vector<MicroOp> &destination) = 0;
|
|
|
|
void assemble_fetch_decode_execute(InstructionPage &target, int length);
|
|
void assemble_ed_page(InstructionPage &target);
|
|
void assemble_cb_page(InstructionPage &target, RegisterPair16 &index, bool add_offsets);
|
|
void assemble_base_page(InstructionPage &target, RegisterPair16 &index, bool add_offsets, InstructionPage &cb_page);
|
|
|
|
// Allow state objects to capture and apply state.
|
|
friend struct State;
|
|
};
|