1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-08-08 14:25:05 +00:00

Output to files, at volume, with extended bus flags.

This commit is contained in:
Thomas Harte
2022-06-18 22:00:50 -04:00
parent 0c24a27ba6
commit 15ac2c3e5a

View File

@@ -28,6 +28,7 @@ struct BusHandler: public CPU::MOS6502Esque::BusHandler<uint32_t> {
cycle.address = address; cycle.address = address;
cycle.operation = operation; cycle.operation = operation;
cycle.value = 0xff; cycle.value = 0xff;
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;
@@ -61,7 +62,7 @@ struct BusHandler: public CPU::MOS6502Esque::BusHandler<uint32_t> {
return Cycles(1); return Cycles(1);
} }
template <typename Processor> void setup(Processor &processor, uint8_t opcode) { void setup(uint8_t opcode) {
ram.clear(); ram.clear();
inventions.clear(); inventions.clear();
cycles.clear(); cycles.clear();
@@ -79,33 +80,42 @@ struct BusHandler: public CPU::MOS6502Esque::BusHandler<uint32_t> {
CPU::MOS6502Esque::BusOperation operation; CPU::MOS6502Esque::BusOperation operation;
uint32_t address; uint32_t address;
uint8_t value; uint8_t value;
int extended_bus;
}; };
std::vector<Cycle> cycles; std::vector<Cycle> cycles;
CPU::WDC65816::Processor<BusHandler, false> processor;
BusHandler() : processor(*this) {
// Never run the official reset procedure.
processor.set_power_on(false);
}
}; };
template <typename Processor> void print_registers(const Processor &processor, int pc_offset) { template <typename Processor> void print_registers(FILE *file, const Processor &processor, int pc_offset) {
using Register = CPU::MOS6502Esque::Register; using Register = CPU::MOS6502Esque::Register;
printf("\"pc\": %d, ", (processor.get_value_of_register(Register::ProgramCounter) + pc_offset) & 65535); fprintf(file, "\"pc\": %d, ", (processor.get_value_of_register(Register::ProgramCounter) + pc_offset) & 65535);
printf("\"s\": %d, ", processor.get_value_of_register(Register::StackPointer)); fprintf(file, "\"s\": %d, ", processor.get_value_of_register(Register::StackPointer));
printf("\"p\": %d, ", processor.get_value_of_register(Register::Flags)); fprintf(file, "\"p\": %d, ", processor.get_value_of_register(Register::Flags));
printf("\"a\": %d, ", processor.get_value_of_register(Register::A)); fprintf(file, "\"a\": %d, ", processor.get_value_of_register(Register::A));
printf("\"x\": %d, ", processor.get_value_of_register(Register::X)); fprintf(file, "\"x\": %d, ", processor.get_value_of_register(Register::X));
printf("\"y\": %d, ", processor.get_value_of_register(Register::Y)); fprintf(file, "\"y\": %d, ", processor.get_value_of_register(Register::Y));
printf("\"dbr\": %d, ", processor.get_value_of_register(Register::DataBank)); fprintf(file, "\"dbr\": %d, ", processor.get_value_of_register(Register::DataBank));
printf("\"d\": %d, ", processor.get_value_of_register(Register::Direct)); fprintf(file, "\"d\": %d, ", processor.get_value_of_register(Register::Direct));
printf("\"pbr\": %d, ", processor.get_value_of_register(Register::ProgramBank)); fprintf(file, "\"pbr\": %d, ", processor.get_value_of_register(Register::ProgramBank));
printf("\"e\": %d, ", processor.get_value_of_register(Register::EmulationFlag)); fprintf(file, "\"e\": %d, ", processor.get_value_of_register(Register::EmulationFlag));
} }
void print_ram(const std::unordered_map<uint32_t, uint8_t> &data) { void print_ram(FILE *file, const std::unordered_map<uint32_t, uint8_t> &data) {
printf("\"ram\": ["); fprintf(file, "\"ram\": [");
bool is_first = true; bool is_first = true;
for(const auto &pair: data) { for(const auto &pair: data) {
if(!is_first) printf(", "); if(!is_first) fprintf(file, ", ");
is_first = false; is_first = false;
printf("[%d, %d]", pair.first, pair.second); fprintf(file, "[%d, %d]", pair.first, pair.second);
} }
printf("]"); fprintf(file, "]");
} }
} }
@@ -119,69 +129,76 @@ void print_ram(const std::unordered_map<uint32_t, uint8_t> &data) {
- (void)generate { - (void)generate {
BusHandler handler; BusHandler handler;
CPU::WDC65816::Processor<BusHandler, false> processor(handler);
// Never run the official reset procedure.
processor.set_power_on(false);
// 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); srand(65816);
NSString *const tempDir = NSTemporaryDirectory();
NSLog(@"Outputting to %@", tempDir);
for(int operation = 0; operation < 512; operation++) { for(int operation = 0; operation < 512; operation++) {
const bool is_emulated = operation & 256; const bool is_emulated = operation & 256;
const uint8_t opcode = operation & 255; const uint8_t opcode = operation & 255;
for(int test = 0; test < 1; test++) { NSString *const targetName = [NSString stringWithFormat:@"%@%02x.%c.json", tempDir, opcode, is_emulated ? 'e' : 'n'];
FILE *const target = fopen(targetName.UTF8String, "wt");
bool is_first_test = true;
fprintf(target, "[");
for(int test = 0; test < 10'000; test++) {
if(!is_first_test) fprintf(target, ",\n");
is_first_test = false;
// Ensure processor's next action is an opcode fetch. // Ensure processor's next action is an opcode fetch.
processor.restart_operation_fetch(); handler.processor.restart_operation_fetch();
// Randomise most of the processor state... // Randomise most of the processor state...
using Register = CPU::MOS6502Esque::Register; using Register = CPU::MOS6502Esque::Register;
processor.set_value_of_register(Register::A, rand() >> 8); handler.processor.set_value_of_register(Register::A, rand() >> 8);
processor.set_value_of_register(Register::Flags, rand() >> 8); handler.processor.set_value_of_register(Register::Flags, rand() >> 8);
processor.set_value_of_register(Register::X, rand() >> 8); handler.processor.set_value_of_register(Register::X, rand() >> 8);
processor.set_value_of_register(Register::Y, rand() >> 8); handler.processor.set_value_of_register(Register::Y, rand() >> 8);
processor.set_value_of_register(Register::ProgramCounter, rand() >> 8); handler.processor.set_value_of_register(Register::ProgramCounter, rand() >> 8);
processor.set_value_of_register(Register::StackPointer, rand() >> 8); handler.processor.set_value_of_register(Register::StackPointer, rand() >> 8);
processor.set_value_of_register(Register::DataBank, rand() >> 8); handler.processor.set_value_of_register(Register::DataBank, rand() >> 8);
processor.set_value_of_register(Register::ProgramBank, rand() >> 8); handler.processor.set_value_of_register(Register::ProgramBank, rand() >> 8);
processor.set_value_of_register(Register::Direct, rand() >> 8); handler.processor.set_value_of_register(Register::Direct, rand() >> 8);
// ... 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.
processor.set_value_of_register(Register::EmulationFlag, is_emulated); handler.processor.set_value_of_register(Register::EmulationFlag, is_emulated);
// Establish the opcode. // Establish the opcode.
handler.setup(processor, opcode); handler.setup(opcode);
// Dump initial state. // Dump initial state.
printf("{ \"name\": \"%02x %c %d\", ", opcode, is_emulated ? 'e' : 'n', test + 1); fprintf(target, "{ \"name\": \"%02x %c %d\", ", opcode, is_emulated ? 'e' : 'n', test + 1);
printf("\"initial\": {"); fprintf(target, "\"initial\": {");
print_registers(processor, 0); print_registers(target, handler.processor, 0);
// Run to the second opcode fetch. // Run to the second opcode fetch.
handler.opcodes_remaining = 2; handler.opcodes_remaining = 2;
try { try {
processor.run_for(Cycles(100)); handler.processor.run_for(Cycles(100));
} catch (const StopException &) {} } catch (const StopException &) {}
// Dump all inventions as initial memory state. // Dump all inventions as initial memory state.
print_ram(handler.inventions); print_ram(target, handler.inventions);
// Dump final state. // Dump final state.
printf("}, \"final\": {"); fprintf(target, "}, \"final\": {");
print_registers(processor, -1); print_registers(target, handler.processor, -1);
print_ram(handler.ram); print_ram(target, handler.ram);
printf("}, "); fprintf(target, "}, ");
// Append cycles. // Append cycles.
printf("\"cycles\": ["); fprintf(target, "\"cycles\": [");
bool is_first = true; bool is_first_cycle = true;
for(const auto &cycle: handler.cycles) { for(const auto &cycle: handler.cycles) {
if(!is_first) printf(","); if(!is_first_cycle) fprintf(target, ",");
is_first = false; is_first_cycle = false;
bool vda = false; bool vda = false;
bool vpa = false; bool vpa = false;
@@ -206,18 +223,32 @@ void print_ram(const std::unordered_map<uint32_t, uint8_t> &data) {
assert(false); assert(false);
} }
printf("[%d, %d, %c%c%c%c]", 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, "[%d, %d, \"%c%c%c%c%c%c%c%c\"]",
cycle.address, cycle.address,
cycle.value, cycle.value,
vda ? 'd' : '-', vda ? 'd' : '-',
vpa ? 'p' : '-', vpa ? 'p' : '-',
vpb ? 'v' : '-', vpb ? 'v' : '-',
wait ? '-' : (read ? 'r' : 'w')); wait ? '-' : (read ? 'r' : 'w'),
wait ? '-' : (emulation ? 'e' : '-'),
wait ? '-' : (memory_size ? 'm' : '-'),
wait ? '-' : (index_size ? 'i' : '-'),
wait ? '-' : (memory_lock ? 'l' : '-')
);
} }
// Terminate object. // Terminate object.
printf("]},\n"); fprintf(target, "]}");
} }
fprintf(target, "]");
fclose(target);
} }
} }