mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
Merge branch 'master' into 65816StackAgain
This commit is contained in:
commit
7815d18676
@ -285,7 +285,7 @@ void Video::output_row(int row, int start, int end) {
|
|||||||
|
|
||||||
// Post an interrupt if requested.
|
// Post an interrupt if requested.
|
||||||
if(line_control_ & 0x40) {
|
if(line_control_ & 0x40) {
|
||||||
set_interrupts(0x20);
|
interrupts_.add(0x20);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up appropriately for fill mode (or not).
|
// Set up appropriately for fill mode (or not).
|
||||||
@ -498,19 +498,19 @@ uint8_t Video::get_new_video() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Video::clear_interrupts(uint8_t mask) {
|
void Video::clear_interrupts(uint8_t mask) {
|
||||||
set_interrupts(interrupts_ & ~(mask & 0x60));
|
interrupts_.clear(mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Video::set_interrupt_register(uint8_t mask) {
|
void Video::set_interrupt_register(uint8_t mask) {
|
||||||
set_interrupts(interrupts_ | (mask & 0x6));
|
interrupts_.set_control(mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Video::get_interrupt_register() {
|
uint8_t Video::get_interrupt_register() {
|
||||||
return interrupts_;
|
return interrupts_.status();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Video::get_interrupt_line() {
|
bool Video::get_interrupt_line() {
|
||||||
return (interrupts_&0x80) || (megaii_interrupt_mask_&megaii_interrupt_state_);
|
return interrupts_.active() || (megaii_interrupt_mask_ & megaii_interrupt_state_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Video::set_megaii_interrupts_enabled(uint8_t mask) {
|
void Video::set_megaii_interrupts_enabled(uint8_t mask) {
|
||||||
@ -526,13 +526,7 @@ void Video::clear_megaii_interrupts() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Video::notify_clock_tick() {
|
void Video::notify_clock_tick() {
|
||||||
set_interrupts(interrupts_ | 0x40);
|
interrupts_.add(0x40);
|
||||||
}
|
|
||||||
|
|
||||||
void Video::set_interrupts(uint8_t new_value) {
|
|
||||||
interrupts_ = new_value & 0x7f;
|
|
||||||
if((interrupts_ >> 4) & interrupts_ & 0x6)
|
|
||||||
interrupts_ |= 0x80;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Video::set_border_colour(uint8_t colour) {
|
void Video::set_border_colour(uint8_t colour) {
|
||||||
|
@ -123,8 +123,56 @@ class Video: public Apple::II::VideoSwitches<Cycles> {
|
|||||||
void advance(Cycles);
|
void advance(Cycles);
|
||||||
|
|
||||||
uint8_t new_video_ = 0x01;
|
uint8_t new_video_ = 0x01;
|
||||||
uint8_t interrupts_ = 0x00;
|
|
||||||
void set_interrupts(uint8_t);
|
class Interrupts {
|
||||||
|
public:
|
||||||
|
void add(uint8_t value) {
|
||||||
|
// Taken literally, status accumulates regardless of being enabled,
|
||||||
|
// potentially to be polled, it simply doesn't trigger an interrupt.
|
||||||
|
value_ |= value;
|
||||||
|
test();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear(uint8_t value) {
|
||||||
|
// Zeroes in bits 5 or 6 clear the respective interrupts.
|
||||||
|
value_ &= value | ~0x60;
|
||||||
|
test();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_control(uint8_t value) {
|
||||||
|
// Ones in bits 1 or 2 enable the respective interrupts.
|
||||||
|
value_ = (value_ & ~0x6) | (value & 0x6);
|
||||||
|
test();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t status() const {
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool active() const {
|
||||||
|
return value_ & 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void test() {
|
||||||
|
value_ &= 0x7f;
|
||||||
|
if((value_ >> 4) & value_ & 0x6) {
|
||||||
|
value_ |= 0x80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overall meaning of value is as per the VGC interrupt register, i.e.
|
||||||
|
//
|
||||||
|
// b7: interrupt status;
|
||||||
|
// b6: 1-second interrupt status;
|
||||||
|
// b5: scan-line interrupt status;
|
||||||
|
// b4: reserved;
|
||||||
|
// b3: reserved;
|
||||||
|
// b2: 1-second interrupt enable;
|
||||||
|
// b1: scan-line interrupt enable;
|
||||||
|
// b0: reserved.
|
||||||
|
uint8_t value_ = 0x00;
|
||||||
|
} interrupts_;
|
||||||
|
|
||||||
int cycles_into_frame_ = 0;
|
int cycles_into_frame_ = 0;
|
||||||
const uint8_t *ram_ = nullptr;
|
const uint8_t *ram_ = nullptr;
|
||||||
|
@ -14,20 +14,27 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "6502Selector.hpp"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct StopException {};
|
struct StopException {};
|
||||||
|
|
||||||
struct BusHandler: public CPU::MOS6502Esque::BusHandler<uint32_t> {
|
template <CPU::MOS6502Esque::Type type>
|
||||||
// Use a map to store RAM contents, in order to preserve initialised state.
|
struct BusHandler: public CPU::MOS6502Esque::BusHandlerT<type> {
|
||||||
std::unordered_map<uint32_t, uint8_t> ram;
|
using AddressType = typename CPU::MOS6502Esque::BusHandlerT<type>::AddressType;
|
||||||
std::unordered_map<uint32_t, uint8_t> inventions;
|
|
||||||
|
|
||||||
Cycles perform_bus_operation(CPU::MOS6502Esque::BusOperation operation, uint32_t address, uint8_t *value) {
|
// Use a map to store RAM contents, in order to preserve initialised state.
|
||||||
|
std::unordered_map<AddressType, uint8_t> ram;
|
||||||
|
std::unordered_map<AddressType, uint8_t> inventions;
|
||||||
|
|
||||||
|
Cycles perform_bus_operation(CPU::MOS6502Esque::BusOperation operation, AddressType address, uint8_t *value) {
|
||||||
// Record the basics of the operation.
|
// Record the basics of the operation.
|
||||||
auto &cycle = cycles.emplace_back();
|
auto &cycle = cycles.emplace_back();
|
||||||
cycle.operation = operation;
|
cycle.operation = operation;
|
||||||
|
if constexpr (has_extended_bus_output(type)) {
|
||||||
cycle.extended_bus = processor.get_extended_bus_output();
|
cycle.extended_bus = processor.get_extended_bus_output();
|
||||||
|
}
|
||||||
|
|
||||||
// Perform the operation, and fill in the cycle's value.
|
// Perform the operation, and fill in the cycle's value.
|
||||||
using BusOperation = CPU::MOS6502Esque::BusOperation;
|
using BusOperation = CPU::MOS6502Esque::BusOperation;
|
||||||
@ -92,25 +99,27 @@ struct BusHandler: public CPU::MOS6502Esque::BusHandler<uint32_t> {
|
|||||||
allow_pc_repetition = opcode == 0x54 || opcode == 0x44;
|
allow_pc_repetition = opcode == 0x54 || opcode == 0x44;
|
||||||
|
|
||||||
using Register = CPU::MOS6502Esque::Register;
|
using Register = CPU::MOS6502Esque::Register;
|
||||||
const uint32_t pc =
|
const auto pc =
|
||||||
|
AddressType(
|
||||||
processor.value_of(Register::ProgramCounter) |
|
processor.value_of(Register::ProgramCounter) |
|
||||||
(processor.value_of(Register::ProgramBank) << 16);
|
(processor.value_of(Register::ProgramBank) << 16)
|
||||||
|
);
|
||||||
inventions[pc] = ram[pc] = opcode;
|
inventions[pc] = ram[pc] = opcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pc_overshoot = 0;
|
int pc_overshoot = 0;
|
||||||
std::optional<uint32_t> initial_pc;
|
std::optional<AddressType> initial_pc;
|
||||||
bool allow_pc_repetition = false;
|
bool allow_pc_repetition = false;
|
||||||
|
|
||||||
struct Cycle {
|
struct Cycle {
|
||||||
CPU::MOS6502Esque::BusOperation operation;
|
CPU::MOS6502Esque::BusOperation operation;
|
||||||
std::optional<uint32_t> address;
|
std::optional<AddressType> address;
|
||||||
std::optional<uint8_t> value;
|
std::optional<uint8_t> value;
|
||||||
int extended_bus;
|
int extended_bus = 0;
|
||||||
};
|
};
|
||||||
std::vector<Cycle> cycles;
|
std::vector<Cycle> cycles;
|
||||||
|
|
||||||
CPU::WDC65816::Processor<BusHandler, false> processor;
|
CPU::MOS6502Esque::Processor<type, BusHandler<type>, false> processor;
|
||||||
|
|
||||||
BusHandler() : processor(*this) {
|
BusHandler() : processor(*this) {
|
||||||
// Never run the official reset procedure.
|
// Never run the official reset procedure.
|
||||||
@ -118,7 +127,7 @@ struct BusHandler: public CPU::MOS6502Esque::BusHandler<uint32_t> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Processor> void print_registers(FILE *file, const Processor &processor, int pc_offset) {
|
template <bool has_emulation, typename Processor> void print_registers(FILE *file, const Processor &processor, int pc_offset) {
|
||||||
using Register = CPU::MOS6502Esque::Register;
|
using Register = CPU::MOS6502Esque::Register;
|
||||||
fprintf(file, "\"pc\": %d, ", (processor.value_of(Register::ProgramCounter) + pc_offset) & 65535);
|
fprintf(file, "\"pc\": %d, ", (processor.value_of(Register::ProgramCounter) + pc_offset) & 65535);
|
||||||
fprintf(file, "\"s\": %d, ", processor.value_of(Register::StackPointer));
|
fprintf(file, "\"s\": %d, ", processor.value_of(Register::StackPointer));
|
||||||
@ -126,13 +135,16 @@ template <typename Processor> void print_registers(FILE *file, const Processor &
|
|||||||
fprintf(file, "\"a\": %d, ", processor.value_of(Register::A));
|
fprintf(file, "\"a\": %d, ", processor.value_of(Register::A));
|
||||||
fprintf(file, "\"x\": %d, ", processor.value_of(Register::X));
|
fprintf(file, "\"x\": %d, ", processor.value_of(Register::X));
|
||||||
fprintf(file, "\"y\": %d, ", processor.value_of(Register::Y));
|
fprintf(file, "\"y\": %d, ", processor.value_of(Register::Y));
|
||||||
|
if constexpr (has_emulation) {
|
||||||
fprintf(file, "\"dbr\": %d, ", processor.value_of(Register::DataBank));
|
fprintf(file, "\"dbr\": %d, ", processor.value_of(Register::DataBank));
|
||||||
fprintf(file, "\"d\": %d, ", processor.value_of(Register::Direct));
|
fprintf(file, "\"d\": %d, ", processor.value_of(Register::Direct));
|
||||||
fprintf(file, "\"pbr\": %d, ", processor.value_of(Register::ProgramBank));
|
fprintf(file, "\"pbr\": %d, ", processor.value_of(Register::ProgramBank));
|
||||||
fprintf(file, "\"e\": %d, ", processor.value_of(Register::EmulationFlag));
|
fprintf(file, "\"e\": %d, ", processor.value_of(Register::EmulationFlag));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_ram(FILE *file, const std::unordered_map<uint32_t, uint8_t> &data) {
|
template <typename IntT>
|
||||||
|
void print_ram(FILE *file, const std::unordered_map<IntT, uint8_t> &data) {
|
||||||
fprintf(file, "\"ram\": [");
|
fprintf(file, "\"ram\": [");
|
||||||
bool is_first = true;
|
bool is_first = true;
|
||||||
for(const auto &pair: data) {
|
for(const auto &pair: data) {
|
||||||
@ -143,22 +155,18 @@ void print_ram(FILE *file, const std::unordered_map<uint32_t, uint8_t> &data) {
|
|||||||
fprintf(file, "]");
|
fprintf(file, "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - New test generator.
|
// MARK: - New test generator.
|
||||||
|
|
||||||
@interface TestGenerator : NSObject
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation TestGenerator
|
template <CPU::MOS6502Esque::Type type> void generate() {
|
||||||
|
BusHandler<type> handler;
|
||||||
- (void)generate {
|
constexpr bool has_emulation = has(type, CPU::MOS6502Esque::Register::EmulationFlag);
|
||||||
BusHandler handler;
|
|
||||||
|
|
||||||
NSString *const tempDir = NSTemporaryDirectory();
|
NSString *const tempDir = NSTemporaryDirectory();
|
||||||
NSLog(@"Outputting to %@", tempDir);
|
NSLog(@"Outputting to %@", tempDir);
|
||||||
|
|
||||||
for(int operation = 0; operation < 512; operation++) {
|
for(int operation = 0; operation < (has_emulation ? 512 : 256); operation++) {
|
||||||
// Make tests repeatable, at least for any given instance of
|
// Make tests repeatable, at least for any given instance of
|
||||||
// the runtime.
|
// the runtime.
|
||||||
srand(65816 + operation);
|
srand(65816 + operation);
|
||||||
@ -166,7 +174,10 @@ void print_ram(FILE *file, const std::unordered_map<uint32_t, uint8_t> &data) {
|
|||||||
const bool is_emulated = operation & 256;
|
const bool is_emulated = operation & 256;
|
||||||
const uint8_t opcode = operation & 255;
|
const uint8_t opcode = operation & 255;
|
||||||
|
|
||||||
NSString *const targetName = [NSString stringWithFormat:@"%@%02x.%c.json", tempDir, opcode, is_emulated ? 'e' : 'n'];
|
NSString *const targetName =
|
||||||
|
has_emulation ?
|
||||||
|
[NSString stringWithFormat:@"%@%02x.%c.json", tempDir, opcode, is_emulated ? 'e' : 'n'] :
|
||||||
|
[NSString stringWithFormat:@"%@%02x.json", tempDir, opcode];
|
||||||
FILE *const target = fopen(targetName.UTF8String, "wt");
|
FILE *const target = fopen(targetName.UTF8String, "wt");
|
||||||
|
|
||||||
bool is_first_test = true;
|
bool is_first_test = true;
|
||||||
@ -186,6 +197,8 @@ void print_ram(FILE *file, const std::unordered_map<uint32_t, uint8_t> &data) {
|
|||||||
handler.processor.set_value_of(Register::Y, rand() >> 8);
|
handler.processor.set_value_of(Register::Y, rand() >> 8);
|
||||||
handler.processor.set_value_of(Register::ProgramCounter, rand() >> 8);
|
handler.processor.set_value_of(Register::ProgramCounter, rand() >> 8);
|
||||||
handler.processor.set_value_of(Register::StackPointer, rand() >> 8);
|
handler.processor.set_value_of(Register::StackPointer, rand() >> 8);
|
||||||
|
|
||||||
|
if(has_emulation) {
|
||||||
handler.processor.set_value_of(Register::DataBank, rand() >> 8);
|
handler.processor.set_value_of(Register::DataBank, rand() >> 8);
|
||||||
handler.processor.set_value_of(Register::ProgramBank, rand() >> 8);
|
handler.processor.set_value_of(Register::ProgramBank, rand() >> 8);
|
||||||
handler.processor.set_value_of(Register::Direct, rand() >> 8);
|
handler.processor.set_value_of(Register::Direct, rand() >> 8);
|
||||||
@ -193,14 +206,19 @@ void print_ram(FILE *file, const std::unordered_map<uint32_t, uint8_t> &data) {
|
|||||||
// ... except for emulation mode, which is a given.
|
// ... except for emulation mode, which is a given.
|
||||||
// And is set last to ensure proper internal state is applied.
|
// And is set last to ensure proper internal state is applied.
|
||||||
handler.processor.set_value_of(Register::EmulationFlag, is_emulated);
|
handler.processor.set_value_of(Register::EmulationFlag, is_emulated);
|
||||||
|
}
|
||||||
|
|
||||||
// Establish the opcode.
|
// Establish the opcode.
|
||||||
handler.setup(opcode);
|
handler.setup(opcode);
|
||||||
|
|
||||||
// Dump initial state.
|
// Dump initial state.
|
||||||
|
if(has_emulation) {
|
||||||
fprintf(target, "{ \"name\": \"%02x %c %d\", ", opcode, is_emulated ? 'e' : 'n', test + 1);
|
fprintf(target, "{ \"name\": \"%02x %c %d\", ", opcode, is_emulated ? 'e' : 'n', test + 1);
|
||||||
|
} else {
|
||||||
|
fprintf(target, "{ \"name\": \"%02x %d\", ", opcode, test + 1);
|
||||||
|
}
|
||||||
fprintf(target, "\"initial\": {");
|
fprintf(target, "\"initial\": {");
|
||||||
print_registers(target, handler.processor, 0);
|
print_registers<has_emulation>(target, handler.processor, 0);
|
||||||
|
|
||||||
// Run to the second opcode fetch.
|
// Run to the second opcode fetch.
|
||||||
try {
|
try {
|
||||||
@ -212,7 +230,7 @@ void print_ram(FILE *file, const std::unordered_map<uint32_t, uint8_t> &data) {
|
|||||||
|
|
||||||
// Dump final state.
|
// Dump final state.
|
||||||
fprintf(target, "}, \"final\": {");
|
fprintf(target, "}, \"final\": {");
|
||||||
print_registers(target, handler.processor, handler.pc_overshoot);
|
print_registers<has_emulation>(target, handler.processor, handler.pc_overshoot);
|
||||||
print_ram(target, handler.ram);
|
print_ram(target, handler.ram);
|
||||||
fprintf(target, "}, ");
|
fprintf(target, "}, ");
|
||||||
|
|
||||||
@ -247,12 +265,6 @@ void print_ram(FILE *file, const std::unordered_map<uint32_t, uint8_t> &data) {
|
|||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
using ExtendedBusOutput = CPU::WDC65816::ExtendedBusOutput;
|
|
||||||
const bool emulation = cycle.extended_bus & ExtendedBusOutput::Emulation;
|
|
||||||
const bool memory_size = cycle.extended_bus & ExtendedBusOutput::MemorySize;
|
|
||||||
const bool index_size = cycle.extended_bus & ExtendedBusOutput::IndexSize;
|
|
||||||
const bool memory_lock = cycle.extended_bus & ExtendedBusOutput::MemoryLock;
|
|
||||||
|
|
||||||
fprintf(target, "[");
|
fprintf(target, "[");
|
||||||
if(cycle.address) {
|
if(cycle.address) {
|
||||||
fprintf(target, "%d, ", *cycle.address);
|
fprintf(target, "%d, ", *cycle.address);
|
||||||
@ -264,6 +276,14 @@ void print_ram(FILE *file, const std::unordered_map<uint32_t, uint8_t> &data) {
|
|||||||
} else {
|
} else {
|
||||||
fprintf(target, "null, ");
|
fprintf(target, "null, ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(has_emulation) {
|
||||||
|
using ExtendedBusOutput = CPU::WDC65816::ExtendedBusOutput;
|
||||||
|
const bool emulation = cycle.extended_bus & ExtendedBusOutput::Emulation;
|
||||||
|
const bool memory_size = cycle.extended_bus & ExtendedBusOutput::MemorySize;
|
||||||
|
const bool index_size = cycle.extended_bus & ExtendedBusOutput::IndexSize;
|
||||||
|
const bool memory_lock = cycle.extended_bus & ExtendedBusOutput::MemoryLock;
|
||||||
|
|
||||||
fprintf(target, "\"%c%c%c%c%c%c%c%c\"]",
|
fprintf(target, "\"%c%c%c%c%c%c%c%c\"]",
|
||||||
vda ? 'd' : '-',
|
vda ? 'd' : '-',
|
||||||
vpa ? 'p' : '-',
|
vpa ? 'p' : '-',
|
||||||
@ -274,6 +294,13 @@ void print_ram(FILE *file, const std::unordered_map<uint32_t, uint8_t> &data) {
|
|||||||
wait ? '-' : (index_size ? 'x' : '-'),
|
wait ? '-' : (index_size ? 'x' : '-'),
|
||||||
wait ? '-' : (memory_lock ? 'l' : '-')
|
wait ? '-' : (memory_lock ? 'l' : '-')
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
if(read) {
|
||||||
|
fprintf(target, "\"read\"]");
|
||||||
|
} else {
|
||||||
|
fprintf(target, "\"write\"]");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Terminate object.
|
// Terminate object.
|
||||||
@ -285,7 +312,7 @@ void print_ram(FILE *file, const std::unordered_map<uint32_t, uint8_t> &data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
}
|
||||||
|
|
||||||
// MARK: - Existing test evaluator.
|
// MARK: - Existing test evaluator.
|
||||||
|
|
||||||
@ -296,7 +323,7 @@ void print_ram(FILE *file, const std::unordered_map<uint32_t, uint8_t> &data) {
|
|||||||
|
|
||||||
// A generator for tests; not intended to be a permanent fixture.
|
// A generator for tests; not intended to be a permanent fixture.
|
||||||
//- (void)testGenerate {
|
//- (void)testGenerate {
|
||||||
// [[[TestGenerator alloc] init] generate];
|
// generate<CPU::MOS6502Esque::Type::TWDC65816>();
|
||||||
//}
|
//}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -124,6 +124,12 @@ class ProcessorBase: public ProcessorStorage {
|
|||||||
@returns @c true if the 6502 is jammed; @c false otherwise.
|
@returns @c true if the 6502 is jammed; @c false otherwise.
|
||||||
*/
|
*/
|
||||||
inline bool is_jammed() const;
|
inline bool is_jammed() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
FOR TESTING PURPOSES ONLY: forces the processor into a state where
|
||||||
|
the next thing it intends to do is fetch a new opcode.
|
||||||
|
*/
|
||||||
|
inline void restart_operation_fetch();
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -728,3 +728,8 @@ void ProcessorBase::set_value_of(Register r, uint16_t value) {
|
|||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProcessorBase::restart_operation_fetch() {
|
||||||
|
scheduled_program_counter_ = nullptr;
|
||||||
|
next_bus_operation_ = BusOperation::None;
|
||||||
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#ifndef _502Selector_h
|
#ifndef _502Selector_h
|
||||||
#define _502Selector_h
|
#define _502Selector_h
|
||||||
|
|
||||||
|
#include "6502Esque.hpp"
|
||||||
#include "../6502/6502.hpp"
|
#include "../6502/6502.hpp"
|
||||||
#include "../65816/65816.hpp"
|
#include "../65816/65816.hpp"
|
||||||
|
|
||||||
@ -45,6 +46,32 @@ template <typename BusHandler, bool uses_ready_line> class Processor<Type::TWDC6
|
|||||||
template <Type processor_type> class BusHandlerT: public BusHandler<uint16_t> {};
|
template <Type processor_type> class BusHandlerT: public BusHandler<uint16_t> {};
|
||||||
template <> class BusHandlerT<Type::TWDC65816>: public BusHandler<uint32_t> {};
|
template <> class BusHandlerT<Type::TWDC65816>: public BusHandler<uint32_t> {};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Query for implemented registers.
|
||||||
|
*/
|
||||||
|
constexpr bool has(Type processor_type, Register r) {
|
||||||
|
switch(r) {
|
||||||
|
case Register::LastOperationAddress:
|
||||||
|
case Register::ProgramCounter:
|
||||||
|
case Register::StackPointer:
|
||||||
|
case Register::Flags:
|
||||||
|
case Register::A:
|
||||||
|
case Register::X:
|
||||||
|
case Register::Y:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Register::EmulationFlag:
|
||||||
|
case Register::DataBank:
|
||||||
|
case Register::ProgramBank:
|
||||||
|
case Register::Direct:
|
||||||
|
return processor_type == Type::TWDC65816;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool has_extended_bus_output(Type processor_type) {
|
||||||
|
return processor_type == Type::TWDC65816;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _502Selector_h */
|
#endif /* _502Selector_h */
|
||||||
|
@ -30,7 +30,10 @@ uint16_t ProcessorBase::value_of(Register r) const {
|
|||||||
void ProcessorBase::set_value_of(Register r, uint16_t value) {
|
void ProcessorBase::set_value_of(Register r, uint16_t value) {
|
||||||
switch (r) {
|
switch (r) {
|
||||||
case Register::ProgramCounter: registers_.pc = value; break;
|
case Register::ProgramCounter: registers_.pc = value; break;
|
||||||
case Register::StackPointer: registers_.s.full = value; break;
|
case Register::StackPointer:
|
||||||
|
registers_.s.full = value;
|
||||||
|
if(registers_.emulation_flag) registers_.s.halves.high = 1;
|
||||||
|
break;
|
||||||
case Register::Flags: set_flags(uint8_t(value)); break;
|
case Register::Flags: set_flags(uint8_t(value)); break;
|
||||||
case Register::A: registers_.a.full = value; break;
|
case Register::A: registers_.a.full = value; break;
|
||||||
case Register::X: registers_.x.full = value & registers_.x_mask; break;
|
case Register::X: registers_.x.full = value & registers_.x_mask; break;
|
||||||
|
Loading…
Reference in New Issue
Block a user