2017-05-17 01:19:17 +00:00
|
|
|
//
|
|
|
|
// Z80AllRAM.cpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 16/05/2017.
|
2018-05-13 19:19:52 +00:00
|
|
|
// Copyright 2017 Thomas Harte. All rights reserved.
|
2017-05-17 01:19:17 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
#include "Z80AllRAM.hpp"
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
using namespace CPU::Z80;
|
2017-05-31 02:41:23 +00:00
|
|
|
namespace {
|
2017-05-17 01:19:17 +00:00
|
|
|
|
2017-08-03 02:09:59 +00:00
|
|
|
class ConcreteAllRAMProcessor: public AllRAMProcessor, public BusHandler {
|
2017-05-31 02:41:23 +00:00
|
|
|
public:
|
2017-08-03 02:09:59 +00:00
|
|
|
ConcreteAllRAMProcessor() : AllRAMProcessor(), z80_(*this) {}
|
2017-05-31 02:41:23 +00:00
|
|
|
|
2017-07-28 01:38:50 +00:00
|
|
|
inline HalfCycles perform_machine_cycle(const PartialMachineCycle &cycle) {
|
2017-07-28 00:17:13 +00:00
|
|
|
timestamp_ += cycle.length;
|
2017-06-22 00:32:08 +00:00
|
|
|
if(!cycle.is_terminal()) {
|
2017-07-28 01:38:50 +00:00
|
|
|
return HalfCycles(0);
|
2017-06-22 00:32:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t address = cycle.address ? *cycle.address : 0x0000;
|
|
|
|
switch(cycle.operation) {
|
2017-07-28 00:17:13 +00:00
|
|
|
case PartialMachineCycle::ReadOpcode:
|
2017-06-22 00:32:08 +00:00
|
|
|
check_address_for_trap(address);
|
2017-06-22 00:38:08 +00:00
|
|
|
case PartialMachineCycle::Read:
|
2017-06-22 00:32:08 +00:00
|
|
|
*cycle.value = memory_[address];
|
|
|
|
break;
|
2017-06-22 00:38:08 +00:00
|
|
|
case PartialMachineCycle::Write:
|
2017-06-22 00:32:08 +00:00
|
|
|
memory_[address] = *cycle.value;
|
|
|
|
break;
|
|
|
|
|
2017-06-22 00:38:08 +00:00
|
|
|
case PartialMachineCycle::Output:
|
2017-06-22 00:32:08 +00:00
|
|
|
break;
|
2017-06-22 00:38:08 +00:00
|
|
|
case PartialMachineCycle::Input:
|
2020-02-23 21:12:28 +00:00
|
|
|
*cycle.value = port_delegate_ ? port_delegate_->z80_all_ram_processor_input(address) : 0xff;
|
2017-06-22 00:32:08 +00:00
|
|
|
break;
|
|
|
|
|
2017-06-22 00:38:08 +00:00
|
|
|
case PartialMachineCycle::Internal:
|
|
|
|
case PartialMachineCycle::Refresh:
|
2017-06-22 00:32:08 +00:00
|
|
|
break;
|
|
|
|
|
2017-06-22 00:38:08 +00:00
|
|
|
case PartialMachineCycle::Interrupt:
|
2017-06-22 00:32:08 +00:00
|
|
|
// A pick that means LD HL, (nn) if interpreted as an instruction but is otherwise
|
|
|
|
// arbitrary.
|
|
|
|
*cycle.value = 0x21;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2017-05-31 02:41:23 +00:00
|
|
|
|
2020-02-23 21:12:28 +00:00
|
|
|
if(memory_delegate_ != nullptr) {
|
|
|
|
memory_delegate_->z80_all_ram_processor_did_perform_bus_operation(*this, cycle.operation, address, cycle.value ? *cycle.value : 0x00, timestamp_);
|
2017-05-31 02:41:23 +00:00
|
|
|
}
|
|
|
|
|
2017-07-28 01:38:50 +00:00
|
|
|
return HalfCycles(0);
|
2017-05-31 02:41:23 +00:00
|
|
|
}
|
|
|
|
|
2020-02-25 04:31:42 +00:00
|
|
|
void run_for(const Cycles cycles) final {
|
2017-08-03 02:09:59 +00:00
|
|
|
z80_.run_for(cycles);
|
2017-05-31 02:41:23 +00:00
|
|
|
}
|
|
|
|
|
2020-02-25 04:31:42 +00:00
|
|
|
void run_for_instruction() final {
|
|
|
|
int toggles = 0;
|
|
|
|
int cycles = 0;
|
|
|
|
|
|
|
|
// Run:
|
|
|
|
// (1) until is_starting_new_instruction is true;
|
|
|
|
// (2) until it is false again; and
|
|
|
|
// (3) until it is true again.
|
|
|
|
while(true) {
|
|
|
|
if(z80_.is_starting_new_instruction() != (toggles&1)) {
|
|
|
|
++toggles;
|
|
|
|
if(toggles == 3) break;
|
|
|
|
}
|
|
|
|
z80_.run_for(Cycles(1));
|
|
|
|
++cycles;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t get_value_of_register(Register r) final {
|
2017-08-03 02:09:59 +00:00
|
|
|
return z80_.get_value_of_register(r);
|
2017-05-31 02:41:23 +00:00
|
|
|
}
|
|
|
|
|
2020-02-25 04:31:42 +00:00
|
|
|
void set_value_of_register(Register r, uint16_t value) final {
|
2017-08-03 02:09:59 +00:00
|
|
|
z80_.set_value_of_register(r, value);
|
2017-05-31 02:41:23 +00:00
|
|
|
}
|
|
|
|
|
2020-02-25 04:31:42 +00:00
|
|
|
bool get_halt_line() final {
|
2017-08-03 02:09:59 +00:00
|
|
|
return z80_.get_halt_line();
|
2017-05-31 02:41:23 +00:00
|
|
|
}
|
2017-06-02 02:33:05 +00:00
|
|
|
|
2020-02-25 04:31:42 +00:00
|
|
|
void reset_power_on() final {
|
2017-08-03 02:09:59 +00:00
|
|
|
return z80_.reset_power_on();
|
2017-06-02 02:33:05 +00:00
|
|
|
}
|
2017-06-03 21:41:45 +00:00
|
|
|
|
2020-02-25 04:31:42 +00:00
|
|
|
void set_interrupt_line(bool value) final {
|
2017-08-03 02:09:59 +00:00
|
|
|
z80_.set_interrupt_line(value);
|
2017-06-03 21:41:45 +00:00
|
|
|
}
|
|
|
|
|
2020-02-25 04:31:42 +00:00
|
|
|
void set_non_maskable_interrupt_line(bool value) final {
|
2017-08-03 02:09:59 +00:00
|
|
|
z80_.set_non_maskable_interrupt_line(value);
|
2017-06-03 21:41:45 +00:00
|
|
|
}
|
2017-06-23 01:09:26 +00:00
|
|
|
|
2020-02-25 04:31:42 +00:00
|
|
|
void set_wait_line(bool value) final {
|
2017-08-03 02:09:59 +00:00
|
|
|
z80_.set_wait_line(value);
|
2017-06-23 01:09:26 +00:00
|
|
|
}
|
2017-08-03 02:09:59 +00:00
|
|
|
|
|
|
|
private:
|
2017-08-27 03:18:11 +00:00
|
|
|
CPU::Z80::Processor<ConcreteAllRAMProcessor, false, true> z80_;
|
2020-02-25 04:31:42 +00:00
|
|
|
bool was_m1_ = false;
|
2017-05-31 02:41:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
AllRAMProcessor *AllRAMProcessor::Processor() {
|
|
|
|
return new ConcreteAllRAMProcessor;
|
2017-05-17 01:19:17 +00:00
|
|
|
}
|