2020-09-24 02:14:42 +00:00
|
|
|
|
//
|
|
|
|
|
// 65816Implementation.hpp
|
|
|
|
|
// Clock Signal
|
|
|
|
|
//
|
|
|
|
|
// Created by Thomas Harte on 23/09/2020.
|
|
|
|
|
// Copyright © 2020 Thomas Harte. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
2020-09-25 02:27:20 +00:00
|
|
|
|
enum MicroOp: uint8_t {
|
|
|
|
|
/// Fetches a byte from the program counter to the instruction buffer and increments the program counter.
|
|
|
|
|
CycleFetchIncrementPC,
|
2020-10-08 00:06:27 +00:00
|
|
|
|
/// Fetches a byte from the program counter without incrementing it.
|
2020-09-25 02:27:20 +00:00
|
|
|
|
CycleFetchPC,
|
2020-10-08 00:06:27 +00:00
|
|
|
|
/// Fetches a byte from the program counter without incrementing it, and throws it away.
|
|
|
|
|
CycleFetchPCThrowaway,
|
2022-06-21 15:41:05 +00:00
|
|
|
|
/// Fetches a byte from (PC - 1), and throws it away; useful for IO cycles that immediately follow incremented PCs.
|
|
|
|
|
CycleFetchPreviousPCThrowaway,
|
2022-06-24 18:00:03 +00:00
|
|
|
|
/// Fetches from whichever address was used in the last bus cycle, and throws away the result.
|
|
|
|
|
CycleFetchPreviousThrowaway,
|
2020-10-02 21:08:30 +00:00
|
|
|
|
/// The same as CycleFetchIncrementPC but indicates valid program address rather than valid data address.
|
|
|
|
|
CycleFetchOpcode,
|
2020-09-25 02:27:20 +00:00
|
|
|
|
|
|
|
|
|
/// Fetches a byte from the data address to the data buffer.
|
|
|
|
|
CycleFetchData,
|
|
|
|
|
/// Fetches a byte from the data address to the data buffer and increments the data address.
|
|
|
|
|
CycleFetchIncrementData,
|
2020-09-26 01:16:36 +00:00
|
|
|
|
/// Fetches from the address formed by the low byte of the data address and the high byte
|
|
|
|
|
/// of the instruction buffer, throwing the result away.
|
|
|
|
|
CycleFetchIncorrectDataAddress,
|
2020-10-12 22:36:09 +00:00
|
|
|
|
/// Fetches a byte from the data address and throws it away.
|
|
|
|
|
CycleFetchDataThrowaway,
|
2020-10-17 01:56:20 +00:00
|
|
|
|
/// Fetches a byte from the data address to the data buffer, signalling VPB .
|
|
|
|
|
CycleFetchVector,
|
|
|
|
|
/// Fetches a byte from the data address to the data buffer and increments the data address, signalling VPB.
|
|
|
|
|
CycleFetchIncrementVector,
|
2020-09-25 02:27:20 +00:00
|
|
|
|
|
2020-09-26 01:49:03 +00:00
|
|
|
|
// Dedicated block-move cycles; these use the data buffer as an intermediary.
|
|
|
|
|
CycleFetchBlockX,
|
|
|
|
|
CycleFetchBlockY,
|
|
|
|
|
CycleStoreBlockY,
|
|
|
|
|
|
2020-09-25 02:27:20 +00:00
|
|
|
|
/// Stores a byte from the data buffer.
|
|
|
|
|
CycleStoreData,
|
2022-06-21 18:33:06 +00:00
|
|
|
|
/// Emulated mode: stores the most recent byte placed into the data buffer without removing it;
|
|
|
|
|
/// Native mode: performs CycleFetchDataThrowaway.
|
|
|
|
|
CycleStoreOrFetchDataThrowaway,
|
2020-09-25 02:27:20 +00:00
|
|
|
|
/// Stores a byte to the data address from the data buffer and increments the data address.
|
|
|
|
|
CycleStoreIncrementData,
|
|
|
|
|
/// Stores a byte to the data address from the data buffer and decrements the data address.
|
|
|
|
|
CycleStoreDecrementData,
|
|
|
|
|
|
|
|
|
|
/// Pushes a single byte from the data buffer to the stack.
|
|
|
|
|
CyclePush,
|
2020-09-25 22:35:00 +00:00
|
|
|
|
/// Fetches from the current stack location and throws the result away.
|
|
|
|
|
CycleAccessStack,
|
2020-09-27 00:38:29 +00:00
|
|
|
|
/// Pulls a single byte to the data buffer from the stack.
|
|
|
|
|
CyclePull,
|
2020-10-11 19:25:13 +00:00
|
|
|
|
/// Performs as CyclePull if the 65816 is not in emulation mode; otherwise skips itself.
|
|
|
|
|
CyclePullIfNotEmulation,
|
2020-09-25 02:27:20 +00:00
|
|
|
|
|
2020-10-11 21:56:55 +00:00
|
|
|
|
/// Issues a BusOperation::None and regresses the micro-op counter until an established
|
|
|
|
|
/// STP or WAI condition is satisfied.
|
|
|
|
|
CycleRepeatingNone,
|
|
|
|
|
|
2020-10-05 21:04:57 +00:00
|
|
|
|
/// Sets the data address by copying the final two bytes of the instruction buffer and
|
|
|
|
|
/// using the data register as a high byte.
|
2020-09-25 02:27:20 +00:00
|
|
|
|
OperationConstructAbsolute,
|
2020-10-05 21:04:57 +00:00
|
|
|
|
|
2020-10-14 01:38:30 +00:00
|
|
|
|
/// Constructs a strictly 16-bit address from the instruction buffer.
|
|
|
|
|
OperationConstructAbsolute16,
|
|
|
|
|
|
2020-10-12 02:02:46 +00:00
|
|
|
|
/// Sets the data address by copying the entire instruction buffer.
|
|
|
|
|
OperationConstructAbsoluteLong,
|
|
|
|
|
|
2020-10-05 21:04:57 +00:00
|
|
|
|
/// Sets the data address to the 16-bit result of adding x to the value in the instruction buffer.
|
2020-09-25 02:27:20 +00:00
|
|
|
|
OperationConstructAbsoluteIndexedIndirect,
|
2020-10-05 21:04:57 +00:00
|
|
|
|
|
|
|
|
|
/// Sets the data address to the 24-bit result of adding x to the low 16-bits of the value in the
|
|
|
|
|
/// instruction buffer and retaining the highest 8-bits as specified.
|
2020-09-25 23:27:17 +00:00
|
|
|
|
OperationConstructAbsoluteLongX,
|
2020-09-25 02:27:20 +00:00
|
|
|
|
|
2020-09-26 01:16:36 +00:00
|
|
|
|
/// Calculates an a, x address; if:
|
|
|
|
|
/// there was no carry into the top byte of the address; and
|
|
|
|
|
/// the process or in emulation or 8-bit index mode;
|
|
|
|
|
/// then it also skips the next micro-op.
|
|
|
|
|
OperationConstructAbsoluteXRead,
|
|
|
|
|
|
|
|
|
|
/// Calculates an a, x address.
|
|
|
|
|
OperationConstructAbsoluteX,
|
|
|
|
|
|
|
|
|
|
// These are analogous to the X versions above.
|
|
|
|
|
OperationConstructAbsoluteY,
|
|
|
|
|
OperationConstructAbsoluteYRead,
|
|
|
|
|
|
2020-09-26 02:01:36 +00:00
|
|
|
|
/// Constructs the current direct address using the value in the instruction buffer.
|
|
|
|
|
/// Skips the next micro-op if the low byte of the direct register is 0.
|
|
|
|
|
OperationConstructDirect,
|
|
|
|
|
|
2020-10-15 01:26:20 +00:00
|
|
|
|
/// Exactly like OperationConstructDirect, but doesn't retain any single-byte wrapping
|
|
|
|
|
/// behaviour in emulation mode.
|
|
|
|
|
OperationConstructDirectLong,
|
|
|
|
|
|
2020-10-05 21:04:57 +00:00
|
|
|
|
/// Constructs the current direct indexed indirect address using the data bank,
|
|
|
|
|
/// direct and x registers plus the value currently in the instruction buffer.
|
|
|
|
|
/// Skips the next micro-op if the low byte of the direct register is 0.
|
2020-09-26 02:22:30 +00:00
|
|
|
|
OperationConstructDirectIndexedIndirect,
|
2020-10-05 21:04:57 +00:00
|
|
|
|
|
2020-10-14 00:21:53 +00:00
|
|
|
|
/// Constructs the current direct indexed indirect address using the value
|
|
|
|
|
/// currently in the data buffer.
|
2020-09-26 02:22:30 +00:00
|
|
|
|
OperationConstructDirectIndirect,
|
2020-10-05 21:04:57 +00:00
|
|
|
|
|
|
|
|
|
/// Adds y to the low 16-bits currently in the instruction buffer and appends a high 8-bits
|
|
|
|
|
/// also from the instruction buffer.
|
2020-09-26 20:55:58 +00:00
|
|
|
|
OperationConstructDirectIndirectIndexedLong,
|
2020-10-05 21:04:57 +00:00
|
|
|
|
|
|
|
|
|
/// Uses the 24-bit address currently in the instruction buffer.
|
2020-09-26 20:55:58 +00:00
|
|
|
|
OperationConstructDirectIndirectLong,
|
2020-10-05 21:04:57 +00:00
|
|
|
|
|
|
|
|
|
/// Adds the x register to the direct register to produce a 16-bit address;
|
|
|
|
|
/// skips the next micro-op if the low byte of the direct register is 0.
|
2020-09-26 21:26:17 +00:00
|
|
|
|
OperationConstructDirectX,
|
2020-10-05 21:04:57 +00:00
|
|
|
|
|
|
|
|
|
/// Adds the y register to the direct register to produce a 16-bit address;
|
|
|
|
|
/// skips the next micro-op if the low byte of the direct register is 0.
|
2020-09-26 21:26:17 +00:00
|
|
|
|
OperationConstructDirectY,
|
2020-09-26 02:22:30 +00:00
|
|
|
|
|
2020-10-05 21:04:57 +00:00
|
|
|
|
/// Adds the instruction buffer to the program counter, making a 16-bit result,
|
|
|
|
|
/// *and stores it into the data buffer*.
|
2020-09-27 00:57:24 +00:00
|
|
|
|
OperationConstructPER,
|
|
|
|
|
|
2020-10-05 21:04:57 +00:00
|
|
|
|
/// Adds the stack pointer to the instruction buffer to produce a 16-bit address.
|
2020-09-27 01:35:31 +00:00
|
|
|
|
OperationConstructStackRelative,
|
2020-10-05 21:04:57 +00:00
|
|
|
|
|
|
|
|
|
/// Adds y to the value in the instruction buffer to produce a 16-bit result and
|
|
|
|
|
/// prefixes the current data bank.
|
2020-09-27 01:35:31 +00:00
|
|
|
|
OperationConstructStackRelativeIndexedIndirect,
|
|
|
|
|
|
2020-09-25 02:27:20 +00:00
|
|
|
|
/// Performs whatever operation goes with this program.
|
|
|
|
|
OperationPerform,
|
|
|
|
|
|
2020-09-25 02:37:31 +00:00
|
|
|
|
/// Copies the current program counter to the data buffer.
|
|
|
|
|
OperationCopyPCToData,
|
2020-10-07 01:24:43 +00:00
|
|
|
|
OperationCopyDataToPC,
|
2020-10-09 02:15:19 +00:00
|
|
|
|
OperationCopyInstructionToData,
|
|
|
|
|
OperationCopyDataToInstruction,
|
2020-09-25 02:37:31 +00:00
|
|
|
|
|
2020-09-25 22:35:00 +00:00
|
|
|
|
/// Copies the current PBR to the data buffer.
|
|
|
|
|
OperationCopyPBRToData,
|
|
|
|
|
|
2020-10-05 21:04:57 +00:00
|
|
|
|
/// Copies A to the data buffer.
|
2020-09-26 01:16:36 +00:00
|
|
|
|
OperationCopyAToData,
|
2020-10-05 21:04:57 +00:00
|
|
|
|
|
|
|
|
|
/// Copies the data buffer to A.
|
2020-09-26 01:16:36 +00:00
|
|
|
|
OperationCopyDataToA,
|
|
|
|
|
|
2020-12-08 23:46:30 +00:00
|
|
|
|
/// Clears the data buffer.
|
|
|
|
|
OperationClearDataBuffer,
|
|
|
|
|
|
2020-09-27 00:38:29 +00:00
|
|
|
|
/// Fills the data buffer with three or four bytes, depending on emulation mode, containing the program
|
2020-12-08 23:46:30 +00:00
|
|
|
|
/// counter, flags and possibly the program bank. Skips the next operation if only three are filled.
|
2020-09-27 00:38:29 +00:00
|
|
|
|
OperationPrepareException,
|
|
|
|
|
|
2020-12-08 23:46:30 +00:00
|
|
|
|
/// Picks the appropriate vector address to service the current exception and places it into
|
|
|
|
|
/// the data address register.
|
|
|
|
|
OperationPickExceptionVector,
|
|
|
|
|
|
2020-10-17 01:05:42 +00:00
|
|
|
|
/// Sets the memory lock output for the rest of this instruction.
|
|
|
|
|
OperationSetMemoryLock,
|
|
|
|
|
|
2020-09-25 02:27:20 +00:00
|
|
|
|
/// Complete this set of micr-ops.
|
2020-09-28 02:20:58 +00:00
|
|
|
|
OperationMoveToNextProgram,
|
|
|
|
|
|
|
|
|
|
/// Inspects the instruction buffer and thereby selects the next set of micro-ops to schedule.
|
|
|
|
|
OperationDecode,
|
2020-09-25 02:27:20 +00:00
|
|
|
|
};
|
2020-09-24 02:23:23 +00:00
|
|
|
|
|
2020-09-25 21:18:25 +00:00
|
|
|
|
enum Operation: uint8_t {
|
|
|
|
|
// These perform the named operation using the value in the data buffer;
|
|
|
|
|
// they are implicitly AccessType::Read.
|
2020-10-07 22:15:18 +00:00
|
|
|
|
ADC, AND, BIT, CMP, CPX, CPY, EOR, ORA, SBC, BITimm,
|
2020-09-25 21:18:25 +00:00
|
|
|
|
|
|
|
|
|
// These load the respective register from the data buffer;
|
|
|
|
|
// they are implicitly AccessType::Read.
|
|
|
|
|
LDA, LDX, LDY,
|
2020-09-27 00:38:29 +00:00
|
|
|
|
PLB, PLD, PLP, // LDA, LDX and LDY can be used for PLA, PLX, PLY.
|
2020-09-25 21:18:25 +00:00
|
|
|
|
|
|
|
|
|
// These move the respective register (or value) to the data buffer;
|
|
|
|
|
// they are implicitly AccessType::Write.
|
|
|
|
|
STA, STX, STY, STZ,
|
2020-09-27 00:38:29 +00:00
|
|
|
|
PHB, PHP, PHD, PHK,
|
2020-09-25 21:18:25 +00:00
|
|
|
|
|
2020-09-26 01:16:36 +00:00
|
|
|
|
// These modify the value in the data buffer as part of a read-modify-write.
|
2020-10-06 23:12:19 +00:00
|
|
|
|
INC, DEC, ASL, LSR, ROL, ROR, TRB, TSB,
|
2020-09-26 01:16:36 +00:00
|
|
|
|
|
2020-09-26 01:49:03 +00:00
|
|
|
|
// These merely decrement A, increment or decrement X and Y, and regress
|
|
|
|
|
// the program counter only if appropriate.
|
|
|
|
|
MVN, MVP,
|
|
|
|
|
|
2020-09-26 21:42:42 +00:00
|
|
|
|
// These use a value straight from the instruction buffer.
|
|
|
|
|
REP, SEP,
|
|
|
|
|
|
2020-09-27 00:24:50 +00:00
|
|
|
|
BCC, BCS, BEQ, BMI, BNE, BPL, BRA, BVC, BVS, BRL,
|
|
|
|
|
|
2020-09-26 21:42:42 +00:00
|
|
|
|
// These are all implicit.
|
|
|
|
|
CLC, CLD, CLI, CLV, DEX, DEY, INX, INY, NOP, SEC, SED, SEI,
|
|
|
|
|
TAX, TAY, TCD, TCS, TDC, TSC, TSX, TXA, TXS, TXY, TYA, TYX,
|
2020-11-04 01:01:02 +00:00
|
|
|
|
XCE, XBA, WDM,
|
2020-09-26 21:42:42 +00:00
|
|
|
|
|
2020-09-27 00:18:30 +00:00
|
|
|
|
STP, WAI,
|
|
|
|
|
|
2020-09-27 01:20:01 +00:00
|
|
|
|
// These unpack values from the data buffer, which has been filled
|
|
|
|
|
// from the stack.
|
2020-10-11 02:16:35 +00:00
|
|
|
|
RTI,
|
2020-09-27 01:20:01 +00:00
|
|
|
|
|
2020-10-08 20:48:46 +00:00
|
|
|
|
/// Loads the PC with the contents of the data buffer.
|
|
|
|
|
JMPind,
|
|
|
|
|
|
|
|
|
|
/// Loads the PC with the contents of the instruction bufer.
|
2020-09-25 21:18:25 +00:00
|
|
|
|
JMP,
|
|
|
|
|
|
2020-10-08 20:48:46 +00:00
|
|
|
|
/// Loads the PC and PBR with the operand from the instruction buffer.
|
2020-09-25 22:00:02 +00:00
|
|
|
|
JML,
|
|
|
|
|
|
2020-10-08 20:48:46 +00:00
|
|
|
|
/// Loads the PC with the operand from the instruction buffer, placing
|
|
|
|
|
/// the current PC into the data buffer.
|
2020-09-25 21:18:25 +00:00
|
|
|
|
JSR,
|
2020-09-25 22:35:00 +00:00
|
|
|
|
|
2020-10-08 20:48:46 +00:00
|
|
|
|
/// Loads the PC and the PBR with the operand from the instruction buffer,
|
|
|
|
|
/// placing the old PC into the data buffer (and only the PC; PBR not included).
|
2020-09-25 22:35:00 +00:00
|
|
|
|
JSL,
|
2020-09-27 01:20:01 +00:00
|
|
|
|
|
2020-10-08 20:55:45 +00:00
|
|
|
|
/// Loads the PC with the contents of the data buffer + 1.
|
|
|
|
|
RTS,
|
2020-10-28 21:25:40 +00:00
|
|
|
|
|
|
|
|
|
/// Loads the PC and program bank with the contents of the data buffer + 1.
|
|
|
|
|
RTL,
|
2020-09-25 02:27:20 +00:00
|
|
|
|
};
|
2020-09-24 02:14:42 +00:00
|
|
|
|
|
2020-10-16 01:09:22 +00:00
|
|
|
|
struct ProcessorStorageConstructor;
|
2020-09-24 02:14:42 +00:00
|
|
|
|
|
2020-09-28 02:20:58 +00:00
|
|
|
|
struct ProcessorStorage {
|
|
|
|
|
ProcessorStorage();
|
|
|
|
|
|
|
|
|
|
// Frustratingly, there is not quite enough space in 16 bits to store both
|
|
|
|
|
// the program offset and the operation as currently defined.
|
|
|
|
|
struct Instruction {
|
2020-10-02 21:08:30 +00:00
|
|
|
|
/// Pointers into micro_ops_ for: [0] = 16-bit operation; [1] = 8-bit operation.
|
|
|
|
|
uint16_t program_offsets[2] = {0xffff, 0xffff};
|
|
|
|
|
/// The operation to perform upon an OperationPerform.
|
|
|
|
|
Operation operation = NOP;
|
2020-10-31 14:21:13 +00:00
|
|
|
|
/// An index into the mx field indicating which of M or X affects whether this is an 8-bit or 16-bit field;
|
|
|
|
|
/// if this is 0 then this instruction picks its size based on the M flag; otherwise it does so based on X.
|
|
|
|
|
/// So the program to perform is that at @c program_offsets[mx_flags[size_field]] .
|
2020-10-02 21:08:30 +00:00
|
|
|
|
uint8_t size_field = 0;
|
2020-09-28 02:20:58 +00:00
|
|
|
|
};
|
2020-10-29 01:23:35 +00:00
|
|
|
|
Instruction instructions[256 + 3]; // Arranged as:
|
2020-10-02 21:08:30 +00:00
|
|
|
|
// 256 entries: instructions;
|
2020-10-29 01:23:35 +00:00
|
|
|
|
// the entry for 'exceptions' (i.e. reset, irq, nmi);
|
|
|
|
|
// a duplicate entry for the final part of exceptions if the selected exception is a reset; and
|
2020-10-02 21:08:30 +00:00
|
|
|
|
// the entry for fetch-decode-execute.
|
2020-09-28 02:20:58 +00:00
|
|
|
|
|
|
|
|
|
enum class OperationSlot {
|
2020-10-02 21:08:30 +00:00
|
|
|
|
Exception = 256,
|
2020-12-08 23:46:30 +00:00
|
|
|
|
Reset,
|
2020-10-29 01:23:35 +00:00
|
|
|
|
FetchDecodeExecute,
|
2020-09-28 02:20:58 +00:00
|
|
|
|
};
|
|
|
|
|
|
2020-09-29 22:42:07 +00:00
|
|
|
|
// A helper for testing.
|
|
|
|
|
uint16_t last_operation_pc_;
|
2021-02-20 01:06:12 +00:00
|
|
|
|
uint8_t last_operation_program_bank_;
|
2020-09-29 22:42:07 +00:00
|
|
|
|
Instruction *active_instruction_;
|
|
|
|
|
Cycles cycles_left_to_run_;
|
|
|
|
|
|
2020-10-15 22:42:38 +00:00
|
|
|
|
// All registers are boxed up into a struct so that they can be stored and restored in support of abort.
|
|
|
|
|
struct Registers {
|
|
|
|
|
// Registers.
|
|
|
|
|
RegisterPair16 a;
|
|
|
|
|
RegisterPair16 x, y;
|
2022-06-24 18:00:03 +00:00
|
|
|
|
RegisterPair16 s;
|
2020-10-15 22:42:38 +00:00
|
|
|
|
uint16_t pc;
|
|
|
|
|
|
|
|
|
|
// Flags aplenty.
|
|
|
|
|
MOS6502Esque::LazyFlags flags;
|
2020-11-05 01:35:41 +00:00
|
|
|
|
uint8_t mx_flags[2] = {1, 1}; // [0] = m; [1] = x. In both cases either `0` or `1`; `1` => 8-bit.
|
2021-03-04 01:33:28 +00:00
|
|
|
|
uint16_t m_masks[2] = {0xff00, 0x00ff}; // [0] = src mask (i.e. that which is unaffected by an operation); [1] = dst mask (i.e. 0xffff ^ src mask).
|
|
|
|
|
uint16_t x_mask = 0x00ff; // A mask representing the current size of the index registers. Equivalent to m_masks[1].
|
|
|
|
|
uint16_t e_masks[2] = {0xff00, 0x00ff}; // Akin to m_masks, but set as per emulation mode.
|
|
|
|
|
int m_shift = 0; // How far to shift memory/A to align its sign bit with that of the flags register. i.e. 8 for 16-bit mode, 0 for 8-bit mode.
|
|
|
|
|
int x_shift = 0; // m_shift equivalent for X and Y.
|
|
|
|
|
bool emulation_flag = true; // The emulation flag; true = in emulation mode.
|
|
|
|
|
|
|
|
|
|
// The offset for direct addressing (i.e. outside of emulation mode).
|
2020-10-15 22:42:38 +00:00
|
|
|
|
uint16_t direct = 0;
|
|
|
|
|
|
|
|
|
|
// Banking registers are all stored with the relevant byte
|
|
|
|
|
// shifted up bits 16–23.
|
|
|
|
|
uint32_t data_bank = 0; // i.e. DBR.
|
|
|
|
|
uint32_t program_bank = 0; // i.e. PBR.
|
|
|
|
|
} registers_, abort_registers_copy_;
|
|
|
|
|
|
|
|
|
|
// The next bus transaction.
|
|
|
|
|
uint32_t bus_address_ = 0;
|
|
|
|
|
uint8_t *bus_value_ = nullptr;
|
|
|
|
|
static inline uint8_t bus_throwaway_ = 0;
|
|
|
|
|
BusOperation bus_operation_ = BusOperation::None;
|
|
|
|
|
|
|
|
|
|
// A bitfield for various exceptions.
|
2020-09-28 02:20:58 +00:00
|
|
|
|
static constexpr int PowerOn = 1 << 0;
|
|
|
|
|
static constexpr int Reset = 1 << 1;
|
2020-10-12 01:10:44 +00:00
|
|
|
|
static constexpr int IRQ = Flag::Interrupt; // This makes masking a lot easier later on; this is 1 << 2.
|
2020-09-28 02:20:58 +00:00
|
|
|
|
static constexpr int NMI = 1 << 3;
|
2020-10-15 22:42:38 +00:00
|
|
|
|
static constexpr int Abort = 1 << 4;
|
2020-10-18 18:43:47 +00:00
|
|
|
|
|
|
|
|
|
static constexpr int default_exceptions = PowerOn;
|
|
|
|
|
int pending_exceptions_ = default_exceptions;
|
|
|
|
|
int selected_exceptions_ = default_exceptions;
|
2020-12-08 23:46:30 +00:00
|
|
|
|
bool exception_is_interrupt_ = false;
|
2020-10-12 01:10:44 +00:00
|
|
|
|
|
2020-10-15 22:42:38 +00:00
|
|
|
|
bool ready_line_ = false;
|
2020-10-17 01:05:42 +00:00
|
|
|
|
bool memory_lock_ = false;
|
2020-10-15 22:42:38 +00:00
|
|
|
|
|
2020-10-12 01:10:44 +00:00
|
|
|
|
// Just to be safe.
|
|
|
|
|
static_assert(PowerOn != IRQ);
|
|
|
|
|
static_assert(Reset != IRQ);
|
|
|
|
|
static_assert(NMI != IRQ);
|
2020-10-15 22:42:38 +00:00
|
|
|
|
static_assert(Abort != IRQ);
|
2020-09-28 02:20:58 +00:00
|
|
|
|
|
2020-10-11 21:56:55 +00:00
|
|
|
|
/// Sets the required exception flags necessary to exit a STP or WAI.
|
|
|
|
|
int required_exceptions_ = 0;
|
2020-10-15 22:42:38 +00:00
|
|
|
|
BusOperation stp_wai_bus_operation_ = BusOperation::None;
|
2020-10-11 21:56:55 +00:00
|
|
|
|
|
2020-09-28 22:43:53 +00:00
|
|
|
|
/// Defines a four-byte buffer which can be cleared or filled in single-byte increments from least significant byte
|
|
|
|
|
/// to most significant.
|
|
|
|
|
struct Buffer {
|
|
|
|
|
uint32_t value = 0;
|
|
|
|
|
int size = 0;
|
2020-10-04 01:30:24 +00:00
|
|
|
|
int read = 0;
|
2020-09-28 22:43:53 +00:00
|
|
|
|
|
|
|
|
|
void clear() {
|
|
|
|
|
value = 0;
|
|
|
|
|
size = 0;
|
2020-10-04 01:30:24 +00:00
|
|
|
|
read = 0;
|
2020-09-28 22:43:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-04 01:30:24 +00:00
|
|
|
|
uint8_t *next_input() {
|
|
|
|
|
uint8_t *const next = byte(size);
|
2020-09-28 22:43:53 +00:00
|
|
|
|
++size;
|
2020-10-04 01:30:24 +00:00
|
|
|
|
return next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t *next_output() {
|
|
|
|
|
uint8_t *const next = byte(read);
|
|
|
|
|
++read;
|
|
|
|
|
return next;
|
2020-09-28 22:43:53 +00:00
|
|
|
|
}
|
2020-10-04 01:30:24 +00:00
|
|
|
|
|
2020-10-10 02:14:42 +00:00
|
|
|
|
uint8_t *preview_output() {
|
|
|
|
|
return byte(read);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-12 22:36:09 +00:00
|
|
|
|
uint8_t *next_output_descending() {
|
2020-10-04 01:30:24 +00:00
|
|
|
|
--size;
|
|
|
|
|
return byte(size);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-04 23:21:04 +00:00
|
|
|
|
uint8_t *any_byte() {
|
|
|
|
|
return reinterpret_cast<uint8_t *>(&value);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-04 01:30:24 +00:00
|
|
|
|
private:
|
|
|
|
|
uint8_t *byte(int pointer) {
|
2020-10-15 02:00:52 +00:00
|
|
|
|
assert(pointer >= 0 && pointer < 4);
|
2020-10-04 01:30:24 +00:00
|
|
|
|
#if TARGET_RT_BIG_ENDIAN
|
|
|
|
|
return reinterpret_cast<uint8_t *>(&value) + (3 ^ pointer);
|
|
|
|
|
#else
|
|
|
|
|
return reinterpret_cast<uint8_t *>(&value) + pointer;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2020-09-28 22:43:53 +00:00
|
|
|
|
};
|
|
|
|
|
Buffer instruction_buffer_, data_buffer_;
|
2020-10-04 01:30:24 +00:00
|
|
|
|
uint32_t data_address_;
|
2020-10-13 02:33:43 +00:00
|
|
|
|
uint32_t data_address_increment_mask_ = 0xffff;
|
2020-10-04 23:02:47 +00:00
|
|
|
|
uint32_t incorrect_data_address_;
|
2020-09-28 22:43:53 +00:00
|
|
|
|
|
2020-09-28 02:20:58 +00:00
|
|
|
|
std::vector<MicroOp> micro_ops_;
|
|
|
|
|
MicroOp *next_op_ = nullptr;
|
2020-10-11 01:23:59 +00:00
|
|
|
|
|
|
|
|
|
void set_reset_state();
|
|
|
|
|
void set_emulation_mode(bool);
|
|
|
|
|
void set_m_x_flags(bool m, bool x);
|
2020-10-11 01:33:56 +00:00
|
|
|
|
uint8_t get_flags() const;
|
2020-10-11 01:23:59 +00:00
|
|
|
|
void set_flags(uint8_t);
|
2020-09-24 02:14:42 +00:00
|
|
|
|
};
|