1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-30 07:29:06 +00:00

Merge pull request #163 from TomHarte/WaitSampling

Adjusts the timing of the Z80's wait line sampling to be on a half clock and better regularises 'action' partial bus cycles
This commit is contained in:
Thomas Harte 2017-07-27 21:19:29 -04:00 committed by GitHub
commit b9f4f7a530
13 changed files with 62 additions and 48 deletions

View File

@ -99,8 +99,12 @@ HalfCycles Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &c
} break; } break;
case CPU::Z80::PartialMachineCycle::Interrupt: case CPU::Z80::PartialMachineCycle::Interrupt:
// resetting event is M1 and IOREQ both simultaneously having leading edges;
// that happens 2 cycles before the end of INTACK. So the timer was reset and
// now has advanced twice.
horizontal_counter_ = HalfCycles(2);
*cycle.value = 0xff; *cycle.value = 0xff;
horizontal_counter_ = 0;
break; break;
case CPU::Z80::PartialMachineCycle::Refresh: case CPU::Z80::PartialMachineCycle::Refresh:
@ -109,7 +113,7 @@ HalfCycles Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &c
// final two cycles of an opcode fetch. Therefore communicate a transient signalling // final two cycles of an opcode fetch. Therefore communicate a transient signalling
// of the IRQ line if necessary. // of the IRQ line if necessary.
if(!(address & 0x40)) { if(!(address & 0x40)) {
set_interrupt_line(true, -2); set_interrupt_line(true, Cycles(-2));
set_interrupt_line(false); set_interrupt_line(false);
} }
if(has_latched_video_byte_) { if(has_latched_video_byte_) {
@ -126,8 +130,7 @@ HalfCycles Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &c
} }
break; break;
case CPU::Z80::PartialMachineCycle::ReadOpcodeStart: case CPU::Z80::PartialMachineCycle::ReadOpcode:
case CPU::Z80::PartialMachineCycle::ReadOpcodeWait:
// Check for use of the fast tape hack. // Check for use of the fast tape hack.
if(use_fast_tape_hack_ && address == tape_trap_address_ && tape_player_.has_tape()) { if(use_fast_tape_hack_ && address == tape_trap_address_ && tape_player_.has_tape()) {
uint64_t prior_offset = tape_player_.get_tape()->get_offset(); uint64_t prior_offset = tape_player_.get_tape()->get_offset();

View File

@ -34,6 +34,7 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineTrapHandler {
0xbd, 0x00, 0x00, // [4] LDA $0000, x (no wrap) 0xbd, 0x00, 0x00, // [4] LDA $0000, x (no wrap)
0xbd, 0x02, 0x00, // [5] LDA $0002, x (wrap) 0xbd, 0x02, 0x00, // [5] LDA $0002, x (wrap)
0xb9, 0x00, 0x00, // [4] LDA $0000, y (no wrap) 0xb9, 0x00, 0x00, // [4] LDA $0000, y (no wrap)
0xb9, 0x10, 0x00, // [5] LDA $0010, y (wrap) 0xb9, 0x10, 0x00, // [5] LDA $0010, y (wrap)
0xa1, 0x44, // [6] LDA ($44, x) 0xa1, 0x44, // [6] LDA ($44, x)
0xb1, 0x00, // [5] LDA ($00), y (no wrap) 0xb1, 0x00, // [5] LDA ($00), y (no wrap)
@ -222,7 +223,7 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineTrapHandler {
func testMachine(_ testMachine: CSTestMachine, didTrapAtAddress address: UInt16) { func testMachine(_ testMachine: CSTestMachine, didTrapAtAddress address: UInt16) {
if self.endTime == 0 { if self.endTime == 0 {
self.endTime = machine.timestamp - 1 self.endTime = (machine.timestamp / 2) - 1
} }
} }
} }

View File

@ -78,7 +78,7 @@ static CPU::MOS6502::Register registerForRegister(CSTestMachine6502Register reg)
} }
- (uint32_t)timestamp { - (uint32_t)timestamp {
return _processor->get_timestamp(); return _processor->get_timestamp().as_int();
} }
- (void)setIrqLine:(BOOL)irqLine { - (void)setIrqLine:(BOOL)irqLine {

View File

@ -61,7 +61,7 @@ typedef NS_ENUM(NSInteger, CSTestMachineZ80Register) {
@property(nonatomic, readonly, nonnull) NSArray<CSTestMachineZ80BusOperationCapture *> *busOperationCaptures; @property(nonatomic, readonly, nonnull) NSArray<CSTestMachineZ80BusOperationCapture *> *busOperationCaptures;
@property(nonatomic, readonly) BOOL isHalted; @property(nonatomic, readonly) BOOL isHalted;
@property(nonatomic, readonly) int completedCycles; @property(nonatomic, readonly) int completedHalfCycles;
@property(nonatomic) BOOL nmiLine; @property(nonatomic) BOOL nmiLine;
@property(nonatomic) BOOL irqLine; @property(nonatomic) BOOL irqLine;

View File

@ -14,7 +14,7 @@
- (void)testMachineDidPerformBusOperation:(CPU::Z80::PartialMachineCycle::Operation)operation - (void)testMachineDidPerformBusOperation:(CPU::Z80::PartialMachineCycle::Operation)operation
address:(uint16_t)address address:(uint16_t)address
value:(uint8_t)value value:(uint8_t)value
timeStamp:(int)time_stamp; timeStamp:(HalfCycles)time_stamp;
@end @end
#pragma mark - C++ delegate handlers #pragma mark - C++ delegate handlers
@ -23,7 +23,7 @@ class BusOperationHandler: public CPU::Z80::AllRAMProcessor::MemoryAccessDelegat
public: public:
BusOperationHandler(CSTestMachineZ80 *targetMachine) : target_(targetMachine) {} BusOperationHandler(CSTestMachineZ80 *targetMachine) : target_(targetMachine) {}
void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::PartialMachineCycle::Operation operation, uint16_t address, uint8_t value, int time_stamp) { void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::PartialMachineCycle::Operation operation, uint16_t address, uint8_t value, HalfCycles time_stamp) {
[target_ testMachineDidPerformBusOperation:operation address:address value:value timeStamp:time_stamp]; [target_ testMachineDidPerformBusOperation:operation address:address value:value timeStamp:time_stamp];
} }
@ -154,8 +154,8 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
return _processor->get_halt_line() ? YES : NO; return _processor->get_halt_line() ? YES : NO;
} }
- (int)completedCycles { - (int)completedHalfCycles {
return _processor->get_timestamp(); return _processor->get_timestamp().as_int();
} }
- (void)setNmiLine:(BOOL)nmiLine { - (void)setNmiLine:(BOOL)nmiLine {
@ -184,7 +184,7 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
_processor->set_memory_access_delegate(captureBusActivity ? _busOperationHandler : nullptr); _processor->set_memory_access_delegate(captureBusActivity ? _busOperationHandler : nullptr);
} }
- (void)testMachineDidPerformBusOperation:(CPU::Z80::PartialMachineCycle::Operation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)timeStamp { - (void)testMachineDidPerformBusOperation:(CPU::Z80::PartialMachineCycle::Operation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(HalfCycles)timeStamp {
if(self.captureBusActivity) { if(self.captureBusActivity) {
CSTestMachineZ80BusOperationCapture *capture = [[CSTestMachineZ80BusOperationCapture alloc] init]; CSTestMachineZ80BusOperationCapture *capture = [[CSTestMachineZ80BusOperationCapture alloc] init];
switch(operation) { switch(operation) {
@ -216,7 +216,7 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
} }
capture.address = address; capture.address = address;
capture.value = value; capture.value = value;
capture.timeStamp = timeStamp; capture.timeStamp = timeStamp.as_int();
[_busOperationCaptures addObject:capture]; [_busOperationCaptures addObject:capture];
} }

View File

@ -195,8 +195,8 @@ class FUSETests: XCTestCase {
machine.runForNumber(ofCycles: Int32(targetState.tStates)) machine.runForNumber(ofCycles: Int32(targetState.tStates))
// Verify that exactly the right number of cycles was hit; this is a primitive cycle length tester. // Verify that exactly the right number of cycles was hit; this is a primitive cycle length tester.
let cyclesRun = machine.completedCycles let halfCyclesRun = machine.completedHalfCycles
XCTAssert(cyclesRun == Int32(targetState.tStates), "Instruction length off; was \(machine.completedCycles) but should be \(targetState.tStates): \(name)") XCTAssert(halfCyclesRun == Int32(targetState.tStates) * 2, "Instruction length off; was \(machine.completedHalfCycles) but should be \(targetState.tStates * 2): \(name)")
let finalState = RegisterState(machine: machine) let finalState = RegisterState(machine: machine)

View File

@ -61,7 +61,9 @@ class Z80MachineCycleTests: XCTestCase {
// array access // array access
break break
} else { } else {
if length != busCycles[index].length || cycle.operation != busCycles[index].operation { XCTAssert(length & Int32(1) == 0, "While performing \(machine.busOperationCaptures) Z80 ended on a half cycle")
if length != busCycles[index].length*2 || cycle.operation != busCycles[index].operation {
matches = false matches = false
break; break;
} }

View File

@ -21,7 +21,7 @@ class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor<Concrete
} }
inline Cycles perform_bus_operation(BusOperation operation, uint16_t address, uint8_t *value) { inline Cycles perform_bus_operation(BusOperation operation, uint16_t address, uint8_t *value) {
timestamp_++; timestamp_ += Cycles(1);
if(operation == BusOperation::ReadOpcode) { if(operation == BusOperation::ReadOpcode) {
check_address_for_trap(address); check_address_for_trap(address);

View File

@ -25,7 +25,7 @@ void AllRAMProcessor::get_data_at_address(uint16_t startAddress, size_t length,
memcpy(data, &memory_[startAddress], endAddress - startAddress); memcpy(data, &memory_[startAddress], endAddress - startAddress);
} }
uint32_t AllRAMProcessor::get_timestamp() { HalfCycles AllRAMProcessor::get_timestamp() {
return timestamp_; return timestamp_;
} }

View File

@ -13,12 +13,14 @@
#include <set> #include <set>
#include <vector> #include <vector>
#include "../ClockReceiver/ClockReceiver.hpp"
namespace CPU { namespace CPU {
class AllRAMProcessor { class AllRAMProcessor {
public: public:
AllRAMProcessor(size_t memory_size); AllRAMProcessor(size_t memory_size);
virtual uint32_t get_timestamp(); HalfCycles get_timestamp();
void set_data_at_address(uint16_t startAddress, size_t length, const uint8_t *data); void set_data_at_address(uint16_t startAddress, size_t length, const uint8_t *data);
void get_data_at_address(uint16_t startAddress, size_t length, uint8_t *data); void get_data_at_address(uint16_t startAddress, size_t length, uint8_t *data);
@ -31,7 +33,7 @@ class AllRAMProcessor {
protected: protected:
std::vector<uint8_t> memory_; std::vector<uint8_t> memory_;
uint32_t timestamp_; HalfCycles timestamp_;
inline void check_address_for_trap(uint16_t address) { inline void check_address_for_trap(uint16_t address) {
if(traps_[address]) { if(traps_[address]) {

View File

@ -67,8 +67,7 @@ enum Flag: uint8_t {
*/ */
struct PartialMachineCycle { struct PartialMachineCycle {
enum Operation { enum Operation {
ReadOpcodeStart = 0, ReadOpcode = 0,
ReadOpcodeWait,
Read, Read,
Write, Write,
Input, Input,
@ -79,16 +78,19 @@ struct PartialMachineCycle {
Internal, Internal,
BusAcknowledge, BusAcknowledge,
ReadOpcodeWait,
ReadWait, ReadWait,
WriteWait, WriteWait,
InputWait, InputWait,
OutputWait, OutputWait,
InterruptWait, InterruptWait,
ReadOpcodeStart,
ReadStart, ReadStart,
WriteStart, WriteStart,
InputStart, InputStart,
OutputStart, OutputStart,
InterruptStart,
} operation; } operation;
HalfCycles length; HalfCycles length;
uint16_t *address; uint16_t *address;
@ -102,33 +104,37 @@ struct PartialMachineCycle {
return operation <= Operation::BusAcknowledge; return operation <= Operation::BusAcknowledge;
} }
inline bool is_wait() const { inline bool is_wait() const {
return operation >= Operation::ReadWait && operation <= Operation::InterruptWait; return operation >= Operation::ReadOpcodeWait && operation <= Operation::InterruptWait;
} }
}; };
// Elemental bus operations // Elemental bus operations
#define ReadOpcodeStart() {PartialMachineCycle::ReadOpcodeStart, HalfCycles(4), &pc_.full, &operation_, false} #define ReadOpcodeStart() {PartialMachineCycle::ReadOpcodeStart, HalfCycles(3), &pc_.full, &operation_, false}
#define ReadOpcodeWait(f) {PartialMachineCycle::ReadOpcodeWait, HalfCycles(2), &pc_.full, &operation_, f} #define ReadOpcodeWait(f) {PartialMachineCycle::ReadOpcodeWait, HalfCycles(2), &pc_.full, &operation_, f}
#define ReadOpcodeEnd() {PartialMachineCycle::ReadOpcode, HalfCycles(1), &pc_.full, &operation_, false}
#define Refresh(len) {PartialMachineCycle::Refresh, HalfCycles(len), &refresh_addr_.full, nullptr, false} #define Refresh(len) {PartialMachineCycle::Refresh, HalfCycles(len), &refresh_addr_.full, nullptr, false}
#define ReadStart(addr, val) {PartialMachineCycle::ReadStart, HalfCycles(4), &addr.full, &val, false} #define ReadStart(addr, val) {PartialMachineCycle::ReadStart, HalfCycles(3), &addr.full, &val, false}
#define ReadWait(l, addr, val, f) {PartialMachineCycle::ReadWait, HalfCycles(l), &addr.full, &val, f} #define ReadWait(l, addr, val, f) {PartialMachineCycle::ReadWait, HalfCycles(l), &addr.full, &val, f}
#define ReadEnd(addr, val) {PartialMachineCycle::Read, HalfCycles(2), &addr.full, &val, false} #define ReadEnd(addr, val) {PartialMachineCycle::Read, HalfCycles(3), &addr.full, &val, false}
#define WriteStart(addr, val) {PartialMachineCycle::WriteStart,HalfCycles(4), &addr.full, &val, false} #define WriteStart(addr, val) {PartialMachineCycle::WriteStart,HalfCycles(3), &addr.full, &val, false}
#define WriteWait(l, addr, val, f) {PartialMachineCycle::WriteWait, HalfCycles(l), &addr.full, &val, f} #define WriteWait(l, addr, val, f) {PartialMachineCycle::WriteWait, HalfCycles(l), &addr.full, &val, f}
#define WriteEnd(addr, val) {PartialMachineCycle::Write, HalfCycles(2), &addr.full, &val, false} #define WriteEnd(addr, val) {PartialMachineCycle::Write, HalfCycles(3), &addr.full, &val, false}
#define InputStart(addr, val) {PartialMachineCycle::InputStart, HalfCycles(4), &addr.full, &val, false} #define InputStart(addr, val) {PartialMachineCycle::InputStart, HalfCycles(3), &addr.full, &val, false}
#define InputWait(addr, val, f) {PartialMachineCycle::InputWait, HalfCycles(2), &addr.full, &val, f} #define InputWait(addr, val, f) {PartialMachineCycle::InputWait, HalfCycles(2), &addr.full, &val, f}
#define InputEnd(addr, val) {PartialMachineCycle::Input, HalfCycles(2), &addr.full, &val, false} #define InputEnd(addr, val) {PartialMachineCycle::Input, HalfCycles(3), &addr.full, &val, false}
#define OutputStart(addr, val) {PartialMachineCycle::OutputStart, HalfCycles(4), &addr.full, &val, false} #define OutputStart(addr, val) {PartialMachineCycle::OutputStart, HalfCycles(3), &addr.full, &val, false}
#define OutputWait(addr, val, f) {PartialMachineCycle::OutputWait, HalfCycles(2), &addr.full, &val, f} #define OutputWait(addr, val, f) {PartialMachineCycle::OutputWait, HalfCycles(2), &addr.full, &val, f}
#define OutputEnd(addr, val) {PartialMachineCycle::Output, HalfCycles(2), &addr.full, &val, false} #define OutputEnd(addr, val) {PartialMachineCycle::Output, HalfCycles(3), &addr.full, &val, false}
#define IntAck(length, val) {PartialMachineCycle::Interrupt, HalfCycles(length), nullptr, &val, false} #define IntAckStart(length, val) {PartialMachineCycle::InterruptStart, HalfCycles(length), nullptr, &val, false}
#define IntWait(val) {PartialMachineCycle::InterruptWait, HalfCycles(2), nullptr, &val, true} #define IntWait(val) {PartialMachineCycle::InterruptWait, HalfCycles(2), nullptr, &val, true}
#define IntAckEnd(val) {PartialMachineCycle::Interrupt, HalfCycles(3), nullptr, &val, false}
// A wrapper to express a bus operation as a micro-op // A wrapper to express a bus operation as a micro-op
#define BusOp(op) {MicroOp::BusOperation, nullptr, nullptr, op} #define BusOp(op) {MicroOp::BusOperation, nullptr, nullptr, op}
@ -741,12 +747,14 @@ template <class T> class Processor {
const MicroOp normal_fetch_decode_execute[] = { const MicroOp normal_fetch_decode_execute[] = {
BusOp(ReadOpcodeStart()), BusOp(ReadOpcodeStart()),
BusOp(ReadOpcodeWait(true)), BusOp(ReadOpcodeWait(true)),
BusOp(ReadOpcodeEnd()),
{ MicroOp::DecodeOperation } { MicroOp::DecodeOperation }
}; };
const MicroOp short_fetch_decode_execute[] = { const MicroOp short_fetch_decode_execute[] = {
BusOp(ReadOpcodeStart()), BusOp(ReadOpcodeStart()),
BusOp(ReadOpcodeWait(false)), BusOp(ReadOpcodeWait(false)),
BusOp(ReadOpcodeWait(true)), BusOp(ReadOpcodeWait(true)),
BusOp(ReadOpcodeEnd()),
{ MicroOp::DecodeOperation } { MicroOp::DecodeOperation }
}; };
copy_program((length == 4) ? normal_fetch_decode_execute : short_fetch_decode_execute, target.fetch_decode_execute); copy_program((length == 4) ? normal_fetch_decode_execute : short_fetch_decode_execute, target.fetch_decode_execute);
@ -813,6 +821,7 @@ template <class T> class Processor {
{ MicroOp::BeginNMI }, { MicroOp::BeginNMI },
BusOp(ReadOpcodeStart()), BusOp(ReadOpcodeStart()),
BusOp(ReadOpcodeWait(true)), BusOp(ReadOpcodeWait(true)),
BusOp(ReadOpcodeEnd()),
BusOp(Refresh(6)), BusOp(Refresh(6)),
Push(pc_), Push(pc_),
{ MicroOp::JumpTo66, nullptr, nullptr}, { MicroOp::JumpTo66, nullptr, nullptr},
@ -820,14 +829,16 @@ template <class T> class Processor {
}; };
MicroOp irq_mode0_program[] = { MicroOp irq_mode0_program[] = {
{ MicroOp::BeginIRQMode0 }, { MicroOp::BeginIRQMode0 },
BusOp(IntAck(8, operation_)), BusOp(IntAckStart(5, operation_)),
BusOp(IntWait(operation_)), BusOp(IntWait(operation_)),
BusOp(IntAckEnd(operation_)),
{ MicroOp::DecodeOperationNoRChange } { MicroOp::DecodeOperationNoRChange }
}; };
MicroOp irq_mode1_program[] = { MicroOp irq_mode1_program[] = {
{ MicroOp::BeginIRQ }, { MicroOp::BeginIRQ },
BusOp(IntAck(10, operation_)), BusOp(IntAckStart(7, operation_)),
BusOp(IntWait(operation_)), BusOp(IntWait(operation_)),
BusOp(IntAckEnd(operation_)),
BusOp(Refresh(4)), BusOp(Refresh(4)),
Push(pc_), Push(pc_),
{ MicroOp::Move16, &temp16_.full, &pc_.full }, { MicroOp::Move16, &temp16_.full, &pc_.full },
@ -835,8 +846,9 @@ template <class T> class Processor {
}; };
MicroOp irq_mode2_program[] = { MicroOp irq_mode2_program[] = {
{ MicroOp::BeginIRQ }, { MicroOp::BeginIRQ },
BusOp(IntAck(10, temp16_.bytes.low)), BusOp(IntAckStart(7, temp16_.bytes.low)),
BusOp(IntWait(temp16_.bytes.low)), BusOp(IntWait(temp16_.bytes.low)),
BusOp(IntAckEnd(temp16_.bytes.low)),
BusOp(Refresh(4)), BusOp(Refresh(4)),
Push(pc_), Push(pc_),
{ MicroOp::Move8, &ir_.bytes.high, &temp16_.bytes.high }, { MicroOp::Move8, &ir_.bytes.high, &temp16_.bytes.high },
@ -1882,7 +1894,7 @@ template <class T> class Processor {
how many cycles before now the line changed state. The value may not be longer than the how many cycles before now the line changed state. The value may not be longer than the
current machine cycle. If called at any other time, this must be zero. current machine cycle. If called at any other time, this must be zero.
*/ */
void set_interrupt_line(bool value, int offset = 0) { void set_interrupt_line(bool value, HalfCycles offset = 0) {
if(irq_line_ == value) return; if(irq_line_ == value) return;
// IRQ requests are level triggered and masked. // IRQ requests are level triggered and masked.
@ -1896,7 +1908,7 @@ template <class T> class Processor {
// If this change happened at least one cycle ago then: (i) we're promised that this is a machine // If this change happened at least one cycle ago then: (i) we're promised that this is a machine
// cycle per the contract on supplying an offset; and (ii) that means it happened before the lines // cycle per the contract on supplying an offset; and (ii) that means it happened before the lines
// were sampled. So adjust the most recent sample. // were sampled. So adjust the most recent sample.
if(offset < 0) { if(offset <= HalfCycles(-2)) {
last_request_status_ = (last_request_status_ & ~Interrupt::IRQ) | (request_status_ & Interrupt::IRQ); last_request_status_ = (last_request_status_ & ~Interrupt::IRQ) | (request_status_ & Interrupt::IRQ);
} }
} }

View File

@ -17,14 +17,14 @@ class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor<Concrete
ConcreteAllRAMProcessor() : AllRAMProcessor() {} ConcreteAllRAMProcessor() : AllRAMProcessor() {}
inline Cycles perform_machine_cycle(const PartialMachineCycle &cycle) { inline Cycles perform_machine_cycle(const PartialMachineCycle &cycle) {
timestamp_ += cycle.length.as_int(); timestamp_ += cycle.length;
if(!cycle.is_terminal()) { if(!cycle.is_terminal()) {
return Cycles(0); return Cycles(0);
} }
uint16_t address = cycle.address ? *cycle.address : 0x0000; uint16_t address = cycle.address ? *cycle.address : 0x0000;
switch(cycle.operation) { switch(cycle.operation) {
case PartialMachineCycle::ReadOpcodeStart: case PartialMachineCycle::ReadOpcode:
check_address_for_trap(address); check_address_for_trap(address);
case PartialMachineCycle::Read: case PartialMachineCycle::Read:
*cycle.value = memory_[address]; *cycle.value = memory_[address];
@ -57,7 +57,7 @@ class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor<Concrete
} }
if(delegate_ != nullptr) { if(delegate_ != nullptr) {
delegate_->z80_all_ram_processor_did_perform_bus_operation(*this, cycle.operation, address, cycle.value ? *cycle.value : 0x00, timestamp_ >> 1); delegate_->z80_all_ram_processor_did_perform_bus_operation(*this, cycle.operation, address, cycle.value ? *cycle.value : 0x00, timestamp_);
} }
return Cycles(0); return Cycles(0);
@ -94,10 +94,6 @@ class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor<Concrete
void set_wait_line(bool value) { void set_wait_line(bool value) {
CPU::Z80::Processor<ConcreteAllRAMProcessor>::set_wait_line(value); CPU::Z80::Processor<ConcreteAllRAMProcessor>::set_wait_line(value);
} }
uint32_t get_timestamp() {
return timestamp_ >> 1;
}
}; };
} }

View File

@ -22,7 +22,7 @@ class AllRAMProcessor:
static AllRAMProcessor *Processor(); static AllRAMProcessor *Processor();
struct MemoryAccessDelegate { struct MemoryAccessDelegate {
virtual void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::PartialMachineCycle::Operation operation, uint16_t address, uint8_t value, int time_stamp) = 0; virtual void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::PartialMachineCycle::Operation operation, uint16_t address, uint8_t value, HalfCycles time_stamp) = 0;
}; };
inline void set_memory_access_delegate(MemoryAccessDelegate *delegate) { inline void set_memory_access_delegate(MemoryAccessDelegate *delegate) {
delegate_ = delegate; delegate_ = delegate;
@ -38,8 +38,6 @@ class AllRAMProcessor:
virtual void set_non_maskable_interrupt_line(bool value) = 0; virtual void set_non_maskable_interrupt_line(bool value) = 0;
virtual void set_wait_line(bool value) = 0; virtual void set_wait_line(bool value) = 0;
virtual uint32_t get_timestamp() = 0;
protected: protected:
MemoryAccessDelegate *delegate_; MemoryAccessDelegate *delegate_;
AllRAMProcessor() : ::CPU::AllRAMProcessor(65536), delegate_(nullptr) {} AllRAMProcessor() : ::CPU::AllRAMProcessor(65536), delegate_(nullptr) {}