From f9101de956148d2a54cb5f1ae6fb4a9f02297e60 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 14 Mar 2019 19:32:15 -0400 Subject: [PATCH] This might very well be the 68000's first real gasp: performing an ABCD. --- .../Clock Signal.xcodeproj/project.pbxproj | 4 + .../Mac/Clock SignalTests/68000Tests.mm | 87 +++++++++++++++++++ .../Implementation/68000Implementation.hpp | 49 +++++++++-- .../68000/Implementation/68000Storage.cpp | 6 +- .../68000/Implementation/68000Storage.hpp | 9 +- 5 files changed, 142 insertions(+), 13 deletions(-) create mode 100644 OSBindings/Mac/Clock SignalTests/68000Tests.mm diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 060a2356a..f2e92e1dc 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -616,6 +616,7 @@ 4BCF1FA41DADC3DD0039D2E7 /* Oric.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCF1FA21DADC3DD0039D2E7 /* Oric.cpp */; }; 4BD191F42191180E0042E144 /* ScanTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD191F22191180E0042E144 /* ScanTarget.cpp */; }; 4BD191F52191180E0042E144 /* ScanTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD191F22191180E0042E144 /* ScanTarget.cpp */; }; + 4BD388882239E198002D14B5 /* 68000Tests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BD388872239E198002D14B5 /* 68000Tests.mm */; }; 4BD3A30B1EE755C800B5B501 /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD3A3091EE755C800B5B501 /* Video.cpp */; }; 4BD424DF2193B5340097291A /* TextureTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD424DD2193B5340097291A /* TextureTarget.cpp */; }; 4BD424E02193B5340097291A /* TextureTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD424DD2193B5340097291A /* TextureTarget.cpp */; }; @@ -1375,6 +1376,7 @@ 4BD191F22191180E0042E144 /* ScanTarget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ScanTarget.cpp; sourceTree = ""; }; 4BD191F32191180E0042E144 /* ScanTarget.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ScanTarget.hpp; sourceTree = ""; }; 4BD388411FE34E010042B588 /* 9918Base.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = 9918Base.hpp; path = 9918/Implementation/9918Base.hpp; sourceTree = ""; }; + 4BD388872239E198002D14B5 /* 68000Tests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = 68000Tests.mm; sourceTree = ""; }; 4BD3A3091EE755C800B5B501 /* Video.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Video.cpp; path = ZX8081/Video.cpp; sourceTree = ""; }; 4BD3A30A1EE755C800B5B501 /* Video.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Video.hpp; path = ZX8081/Video.hpp; sourceTree = ""; }; 4BD424DD2193B5340097291A /* TextureTarget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextureTarget.cpp; sourceTree = ""; }; @@ -2822,6 +2824,7 @@ 4BB73EB51B587A5100552FC2 /* Clock SignalTests */ = { isa = PBXGroup; children = ( + 4BD388872239E198002D14B5 /* 68000Tests.mm */, 4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */, 4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */, 4BFF1D3C2235C3C100838EA1 /* EmuTOSTests.mm */, @@ -4024,6 +4027,7 @@ 4BB73EB71B587A5100552FC2 /* AllSuiteATests.swift in Sources */, 4B01A6881F22F0DB001FD6E3 /* Z80MemptrTests.swift in Sources */, 4B121F9B1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm in Sources */, + 4BD388882239E198002D14B5 /* 68000Tests.mm in Sources */, 4BA91E1D216D85BA00F79557 /* MasterSystemVDPTests.mm in Sources */, 4B98A0611FFADCDE00ADF63B /* MSXStaticAnalyserTests.mm in Sources */, 4BEF6AAC1D35D1C400E73575 /* DPLLTests.swift in Sources */, diff --git a/OSBindings/Mac/Clock SignalTests/68000Tests.mm b/OSBindings/Mac/Clock SignalTests/68000Tests.mm new file mode 100644 index 000000000..732987787 --- /dev/null +++ b/OSBindings/Mac/Clock SignalTests/68000Tests.mm @@ -0,0 +1,87 @@ +// +// 68000Tests.m +// Clock SignalTests +// +// Created by Thomas Harte on 13/03/2019. +// Copyright © 2019 Thomas Harte. All rights reserved. +// + +#import + +#include +#include + +#include "68000.hpp" + +/*! + Provides a 68000 with 64kb of RAM in its low address space; + /RESET will put the supervisor stack pointer at 0xFFFF and + begin execution at 0x0400. +*/ +class RAM68000: public CPU::MC68000::BusHandler { + public: + RAM68000() : m68000_(*this) { + ram_.resize(32768); + + // Setup the /RESET vector. + ram_[0] = 0; + ram_[1] = 0xffff; + ram_[2] = 0; + ram_[3] = 0x0400; + } + + void set_program(const std::vector &program) { + memcpy(&ram_[512], program.data(), program.size() * sizeof(uint16_t)); + } + + void run_for(HalfCycles cycles) { + m68000_.run_for(cycles); + } + + HalfCycles perform_bus_operation(const CPU::MC68000::Microcycle &cycle, int is_supervisor) { + uint32_t address = cycle.address ? (*cycle.address) & 0x00fffffe : 0; + + switch(cycle.operation & (CPU::MC68000::Microcycle::LowerData | CPU::MC68000::Microcycle::UpperData)) { + case 0: break; + case CPU::MC68000::Microcycle::LowerData: + cycle.value->halves.low = ram_[address >> 1] >> 8; + break; + case CPU::MC68000::Microcycle::UpperData: + cycle.value->halves.high = ram_[address >> 1] & 0xff; + break; + case CPU::MC68000::Microcycle::UpperData | CPU::MC68000::Microcycle::LowerData: + cycle.value->full = ram_[address >> 1]; + break; + } + + return HalfCycles(0); + } + + private: + CPU::MC68000::Processor m68000_; + std::vector ram_; +}; + +@interface M68000Tests : XCTestCase +@end + +@implementation M68000Tests { + std::unique_ptr _machine; +} + +- (void)setUp { + _machine.reset(new RAM68000()); +} + +- (void)tearDown { + _machine.reset(); +} + +- (void)testABCD { + _machine->set_program({ + 0xc100 // ABCD D0, D0 + }); + _machine->run_for(HalfCycles(400)); +} + +@end diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index 7040afcb1..fa2bc0806 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -15,12 +15,36 @@ template void Processor: // for interrupts). if(active_step_->action == BusStep::Action::ScheduleNextProgram) { if(active_micro_op_) { - ++active_micro_op_; switch(active_micro_op_->action) { case MicroOp::Action::None: break; case MicroOp::Action::PerformOperation: - std::cerr << "Should do something with program operation " << int(active_program_->operation) << std::endl; + switch(active_program_->operation) { + case Operation::ABCD: { + // Pull out the two halves, for simplicity. + const uint8_t source = active_program_->source->halves.low.halves.low; + const uint8_t destination = active_program_->destination->halves.low.halves.low; + + // Perform the BCD add by evaluating the two nibbles separately. + int result = (source & 0xf) + (destination & 0xf) + (extend_flag_ ? 1 : 0); + if(result > 0x9) result += 0x06; + result += (source & 0xf0) + (destination & 0xf0); + if(result > 0x90) result += 0x60; + + // Set all flags essentially as if this were normal addition. + zero_flag_ |= result & 0xff; + extend_flag_ = carry_flag_ = result & ~0xff; + negative_flag_ = result & 0x80; + overflow_flag_ = ~(source ^ destination) & (source ^ result) & 0x80; + + // Store the result. + active_program_->destination->halves.low.halves.low = uint8_t(result); + } break; + + default: + std::cerr << "Should do something with program operation " << int(active_program_->operation) << std::endl; + break; + } break; case MicroOp::Action::PredecrementSourceAndDestination1: @@ -28,22 +52,33 @@ template void Processor: -- active_program_->destination->full; break; - case MicroOp::Action::PredecrementSourceAndDestination1: + case MicroOp::Action::PredecrementSourceAndDestination2: active_program_->source->full -= 2; active_program_->destination->full -= 2; break; - case MicroOp::Action::PredecrementSourceAndDestination1: + case MicroOp::Action::PredecrementSourceAndDestination4: active_program_->source->full -= 4; active_program_->destination->full -= 4; break; } + } + + if(active_micro_op_) { + ++active_micro_op_; active_step_ = active_micro_op_->bus_program; } - if(!active_step_) { - std::cerr << "68000 Abilities exhausted; should schedule an instruction or something?" << std::endl; - return; + if(!active_step_ || !active_micro_op_) { + const uint16_t next_instruction = prefetch_queue_[0].full; + if(!instructions[next_instruction].micro_operations) { + std::cerr << "68000 Abilities exhausted; should schedule an instruction or something?" << std::endl; + return; + } + + active_program_ = &instructions[next_instruction]; + active_micro_op_ = active_program_->micro_operations; + active_step_ = active_micro_op_->bus_program; } } diff --git a/Processors/68000/Implementation/68000Storage.cpp b/Processors/68000/Implementation/68000Storage.cpp index 64d95d643..8bbbcc7ec 100644 --- a/Processors/68000/Implementation/68000Storage.cpp +++ b/Processors/68000/Implementation/68000Storage.cpp @@ -219,7 +219,7 @@ void ProcessorStorage::install_instructions(const BusStepCollection &bus_step_co std::vector micro_op_pointers(65536, std::numeric_limits::max()); // Perform a linear search of the mappings above for this instruction. - for(size_t instruction = 0; instruction < 65536; ++instruction) { + for(size_t instruction = 0; instruction < 65536; ++instruction) { for(const auto &mapping: mappings) { if((instruction & mapping.mask) == mapping.value) { // Install the operation and make a note of where micro-ops begin. @@ -228,11 +228,9 @@ void ProcessorStorage::install_instructions(const BusStepCollection &bus_step_co switch(mapping.decoder) { case Decoder::Decimal: { - const int destination = (instruction >> 8) & 7; + const int destination = (instruction >> 9) & 7; const int source = instruction & 7; - all_micro_ops_.emplace_back(); - if(instruction & 8) { // Install source and destination. instructions[instruction].source = &bus_data_[0]; diff --git a/Processors/68000/Implementation/68000Storage.hpp b/Processors/68000/Implementation/68000Storage.hpp index 8ebec8a9b..4d4732e9d 100644 --- a/Processors/68000/Implementation/68000Storage.hpp +++ b/Processors/68000/Implementation/68000Storage.hpp @@ -26,6 +26,11 @@ class ProcessorStorage { // Various status bits. int is_supervisor_; + int zero_flag_; // The zero flag is set if this value is zero. + int carry_flag_; // The carry flag is set if this value is non-zero. + int extend_flag_; // The extend flag is set if this value is non-zero. + int overflow_flag_; // The overflow flag is set if this value is non-zero. + int negative_flag_; // The negative flag is set if this value is non-zero. // Generic sources and targets for memory operations. uint32_t effective_address_; @@ -88,8 +93,8 @@ class ProcessorStorage { */ struct Program { MicroOp *micro_operations = nullptr; - RegisterPair32 *source; - RegisterPair32 *destination; + RegisterPair32 *source = nullptr; + RegisterPair32 *destination = nullptr; Operation operation; };