diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm index 225e7ac32..2dd3109a0 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm @@ -80,6 +80,11 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { #pragma mark - Capture class @implementation CSTestMachineZ80BusOperationCapture + +- (NSString *)description { + return [NSString stringWithFormat:@"%c %04x %02x [%d]", (self.operation == CSTestMachineZ80BusOperationCaptureOperationRead) ? 'r' : 'w', self.address, self.value, self.timeStamp]; +} + @end #pragma mark - Test class @@ -91,6 +96,8 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { NSMutableArray *_busOperationCaptures; BOOL _isAtReadOpcode; + int _timeSeekingReadOpcode; + int _lastOpcodeTime; } #pragma mark - Lifecycle @@ -150,16 +157,21 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { #pragma mark - Z80-specific Runner - (void)runToNextInstruction { - _isAtReadOpcode = false; + _isAtReadOpcode = NO; + _timeSeekingReadOpcode = 0; while(!_isAtReadOpcode) { + _timeSeekingReadOpcode++; _processor.run_for_cycles(1); } } #pragma mark - Bus operation accumulation -- (void)testMachineDidPerformBusOperation:(CPU::Z80::BusOperation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)time_stamp { - _isAtReadOpcode |= (operation == CPU::Z80::BusOperation::ReadOpcode); +- (void)testMachineDidPerformBusOperation:(CPU::Z80::BusOperation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)timeStamp { + int length = timeStamp - _lastOpcodeTime; + _lastOpcodeTime = timeStamp; + if(operation == CPU::Z80::BusOperation::ReadOpcode && length < _timeSeekingReadOpcode) + _isAtReadOpcode = YES; if(self.captureBusActivity) { if(!_busOperationCaptures) _busOperationCaptures = [[NSMutableArray alloc] init]; @@ -169,7 +181,7 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { capture.operation = (operation == CPU::Z80::BusOperation::Write) ? CSTestMachineZ80BusOperationCaptureOperationWrite : CSTestMachineZ80BusOperationCaptureOperationRead; capture.address = address; capture.value = value; - capture.timeStamp = time_stamp; + capture.timeStamp = timeStamp; [_busOperationCaptures addObject:capture]; } diff --git a/OSBindings/Mac/Clock SignalTests/FUSETests.swift b/OSBindings/Mac/Clock SignalTests/FUSETests.swift index 01448f450..558c8eb74 100644 --- a/OSBindings/Mac/Clock SignalTests/FUSETests.swift +++ b/OSBindings/Mac/Clock SignalTests/FUSETests.swift @@ -21,82 +21,84 @@ class FUSETests: XCTestCase { let outputScanner = Scanner(string: output) while !inputScanner.isAtEnd { - var name: NSString? - inputScanner.scanUpToCharacters(from: CharacterSet.newlines, into: &name) - if let name = name { - let machine = CSTestMachineZ80() + autoreleasepool { + var name: NSString? + inputScanner.scanUpToCharacters(from: CharacterSet.newlines, into: &name) + if let name = name { + let machine = CSTestMachineZ80() - var af: UInt32 = 0, bc: UInt32 = 0, de: UInt32 = 0, hl: UInt32 = 0 - var afDash: UInt32 = 0, bcDash: UInt32 = 0, deDash: UInt32 = 0, hlDash: UInt32 = 0 - var ix: UInt32 = 0, iy: UInt32 = 0, sp: UInt32 = 0, pc: UInt32 = 0 - var i: UInt32 = 0, r: UInt32 = 0, iff1: UInt32 = 0, iff2: UInt32 = 0, interruptMode: UInt32 = 0 - var isHalted: UInt32 = 0, tStates: UInt32 = 0 + var af: UInt32 = 0, bc: UInt32 = 0, de: UInt32 = 0, hl: UInt32 = 0 + var afDash: UInt32 = 0, bcDash: UInt32 = 0, deDash: UInt32 = 0, hlDash: UInt32 = 0 + var ix: UInt32 = 0, iy: UInt32 = 0, sp: UInt32 = 0, pc: UInt32 = 0 + var i: UInt32 = 0, r: UInt32 = 0, iff1: UInt32 = 0, iff2: UInt32 = 0, interruptMode: UInt32 = 0 + var isHalted: UInt32 = 0, tStates: UInt32 = 0 - inputScanner.scanHexInt32(&af) - inputScanner.scanHexInt32(&bc) - inputScanner.scanHexInt32(&de) - inputScanner.scanHexInt32(&hl) - inputScanner.scanHexInt32(&afDash) - inputScanner.scanHexInt32(&bcDash) - inputScanner.scanHexInt32(&deDash) - inputScanner.scanHexInt32(&hlDash) - inputScanner.scanHexInt32(&ix) - inputScanner.scanHexInt32(&iy) - inputScanner.scanHexInt32(&sp) - inputScanner.scanHexInt32(&pc) - inputScanner.scanHexInt32(&i) - inputScanner.scanHexInt32(&r) - inputScanner.scanHexInt32(&iff1) - inputScanner.scanHexInt32(&iff2) - inputScanner.scanHexInt32(&interruptMode) - inputScanner.scanHexInt32(&isHalted) - inputScanner.scanHexInt32(&tStates) + inputScanner.scanHexInt32(&af) + inputScanner.scanHexInt32(&bc) + inputScanner.scanHexInt32(&de) + inputScanner.scanHexInt32(&hl) + inputScanner.scanHexInt32(&afDash) + inputScanner.scanHexInt32(&bcDash) + inputScanner.scanHexInt32(&deDash) + inputScanner.scanHexInt32(&hlDash) + inputScanner.scanHexInt32(&ix) + inputScanner.scanHexInt32(&iy) + inputScanner.scanHexInt32(&sp) + inputScanner.scanHexInt32(&pc) + inputScanner.scanHexInt32(&i) + inputScanner.scanHexInt32(&r) + inputScanner.scanHexInt32(&iff1) + inputScanner.scanHexInt32(&iff2) + inputScanner.scanHexInt32(&interruptMode) + inputScanner.scanHexInt32(&isHalted) + inputScanner.scanHexInt32(&tStates) - print("\(name)") - machine.setValue(UInt16(af), for: .AF) - machine.setValue(UInt16(bc), for: .BC) - machine.setValue(UInt16(de), for: .DE) - machine.setValue(UInt16(hl), for: .HL) - machine.setValue(UInt16(afDash), for: .afDash) - machine.setValue(UInt16(bcDash), for: .bcDash) - machine.setValue(UInt16(deDash), for: .deDash) - machine.setValue(UInt16(hlDash), for: .hlDash) - machine.setValue(UInt16(ix), for: .IX) - machine.setValue(UInt16(iy), for: .IY) - machine.setValue(UInt16(sp), for: .stackPointer) - machine.setValue(UInt16(pc), for: .programCounter) - machine.setValue(UInt16(i), for: .I) - machine.setValue(UInt16(r), for: .R) - machine.setValue(UInt16(iff1), for: .IFF1) - machine.setValue(UInt16(iff2), for: .IFF2) - machine.setValue(UInt16(interruptMode), for: .IM) - // TODO: isHalted + print("\(name)") + machine.setValue(UInt16(af), for: .AF) + machine.setValue(UInt16(bc), for: .BC) + machine.setValue(UInt16(de), for: .DE) + machine.setValue(UInt16(hl), for: .HL) + machine.setValue(UInt16(afDash), for: .afDash) + machine.setValue(UInt16(bcDash), for: .bcDash) + machine.setValue(UInt16(deDash), for: .deDash) + machine.setValue(UInt16(hlDash), for: .hlDash) + machine.setValue(UInt16(ix), for: .IX) + machine.setValue(UInt16(iy), for: .IY) + machine.setValue(UInt16(sp), for: .stackPointer) + machine.setValue(UInt16(pc), for: .programCounter) + machine.setValue(UInt16(i), for: .I) + machine.setValue(UInt16(r), for: .R) + machine.setValue(UInt16(iff1), for: .IFF1) + machine.setValue(UInt16(iff2), for: .IFF2) + machine.setValue(UInt16(interruptMode), for: .IM) + // TODO: isHalted - while true { - var address: UInt32 = 0 - var negative: Int = 0 - if inputScanner.scanHexInt32(&address) { - while true { - var value: UInt32 = 0 - if inputScanner.scanHexInt32(&value) { - machine.setValue(UInt8(value), atAddress: UInt16(address)) - address = address + 1 - } else { - inputScanner.scanInt(&negative) - break + while true { + var address: UInt32 = 0 + var negative: Int = 0 + if inputScanner.scanHexInt32(&address) { + while true { + var value: UInt32 = 0 + if inputScanner.scanHexInt32(&value) { + machine.setValue(UInt8(value), atAddress: UInt16(address)) + address = address + 1 + } else { + inputScanner.scanInt(&negative) + break + } } + } else { + inputScanner.scanInt(&negative) + break } - } else { - inputScanner.scanInt(&negative) - break } + + machine.captureBusActivity = true + machine.runForNumber(ofCycles: Int32(tStates)) + machine.runToNextInstruction() + + print("\(machine.busOperationCaptures)") } - - machine.captureBusActivity = true - machine.runForNumber(ofCycles: Int32(tStates)) - machine.runToNextInstruction() - - print("\(machine.busOperationCaptures)") } } } diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index ae162af93..a9557a929 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -161,6 +161,7 @@ template class Processor: public MicroOpScheduler { RegisterPair temp16_; uint8_t temp8_; + MicroOp *fetch_decode_execute_; MicroOp **current_instruction_page_; struct InstructionPage { MicroOp *instructions[256]; @@ -484,22 +485,39 @@ template class Processor: public MicroOpScheduler { assemble_page(target, base_program_table); } + void assemble_fetch_decode_execute() { + // TODO: this can't legitimately be static and contain references to this via pc_ and operation_; + // make it something else that is built at instance construction. + const MicroOp fetch_decode_execute[] = { + { MicroOp::BusOperation, nullptr, nullptr, {ReadOpcode, 4, &pc_.full, &operation_}}, + { MicroOp::DecodeOperation }, + { MicroOp::MoveToNextProgram } + }; + fetch_decode_execute_ = new MicroOp[3]; + fetch_decode_execute_[0] = fetch_decode_execute[0]; + fetch_decode_execute_[1] = fetch_decode_execute[1]; + fetch_decode_execute_[2] = fetch_decode_execute[2]; + } + void decode_operation(uint8_t operation) { if(current_instruction_page_[operation]->type == MicroOp::None) { uint8_t page = 0x00; if(current_instruction_page_ == ed_page_.instructions) page = 0xed; if(current_instruction_page_ == fd_page_.instructions) page = 0xfd; printf("Unknown Z80 operation %02x %02x!!!\n", page, operation); - } - schedule_program(current_instruction_page_[operation]); + } else schedule_program(current_instruction_page_[operation]); } public: - Processor() { + Processor() : MicroOpScheduler() { assemble_base_page(base_page_, hl_, false); assemble_base_page(dd_page_, ix_, false); assemble_base_page(fd_page_, iy_, false); assemble_ed_page(ed_page_); + assemble_fetch_decode_execute(); + } + ~Processor() { + delete[] fetch_decode_execute_; } /*! @@ -512,18 +530,11 @@ template class Processor: public MicroOpScheduler { @param number_of_cycles The number of cycles to run the Z80 for. */ void run_for_cycles(int number_of_cycles) { - // TODO: this can't legitimately be static and contain references to this via pc_ and operation_; - // make it something else that is built at instance construction. - static const MicroOp fetch_decode_execute[] = { - { MicroOp::BusOperation, nullptr, nullptr, {ReadOpcode, 4, &pc_.full, &operation_}}, - { MicroOp::DecodeOperation }, - { MicroOp::MoveToNextProgram } - }; #define checkSchedule() \ if(!scheduled_programs_[schedule_programs_read_pointer_]) {\ current_instruction_page_ = base_page_.instructions;\ - schedule_program(fetch_decode_execute);\ + schedule_program(fetch_decode_execute_);\ } number_of_cycles_ += number_of_cycles; @@ -535,11 +546,10 @@ template class Processor: public MicroOpScheduler { switch(operation->type) { case MicroOp::BusOperation: - if(number_of_cycles_ < operation->machine_cycle.length) { - return; - } + if(number_of_cycles_ < operation->machine_cycle.length) { schedule_program_program_counter_--; return; } number_of_cycles_ -= operation->machine_cycle.length; number_of_cycles_ -= static_cast(this)->perform_machine_cycle(&operation->machine_cycle); + if(number_of_cycles_ <= 0) return; break; case MicroOp::MoveToNextProgram: move_to_next_program(); @@ -872,7 +882,7 @@ template class Processor: public MicroOpScheduler { #pragma mark - Internal bookkeeping case MicroOp::SetInstructionPage: - schedule_program(fetch_decode_execute); + schedule_program(fetch_decode_execute_); current_instruction_page_ = ((InstructionPage *)operation->source)->instructions; // printf("+ "); break; diff --git a/Processors/Z80/Z80AllRAM.cpp b/Processors/Z80/Z80AllRAM.cpp index c6430f191..0e7c8297e 100644 --- a/Processors/Z80/Z80AllRAM.cpp +++ b/Processors/Z80/Z80AllRAM.cpp @@ -37,7 +37,7 @@ int AllRAMProcessor::perform_machine_cycle(const MachineCycle *cycle) { timestamp_ += cycle->length; if(delegate_ != nullptr) { - delegate_->z80_all_ram_processor_did_perform_bus_operation(*this, cycle->operation, *cycle->address, *cycle->value, timestamp_); + delegate_->z80_all_ram_processor_did_perform_bus_operation(*this, cycle->operation, cycle->address ? *cycle->address : 0x0000, cycle->value ? *cycle->value : 0x00, timestamp_); } return 0;