mirror of
https://github.com/TomHarte/CLK.git
synced 2025-04-21 18:37:11 +00:00
Takes a further step towards real timing.
This commit is contained in:
parent
c1df4d1c0b
commit
1502c4530e
Machines/Amiga
@ -61,27 +61,38 @@ class ConcreteMachine:
|
||||
// MARK: - MC68000::BusHandler.
|
||||
using Microcycle = CPU::MC68000::Microcycle;
|
||||
HalfCycles perform_bus_operation(const CPU::MC68000::Microcycle &cycle, int) {
|
||||
// Intended 1-2 step here is:
|
||||
//
|
||||
// (1) determine when this CPU access will be scheduled;
|
||||
// (2) do all the other actions prior to this CPU access being scheduled.
|
||||
// TODO: clean up below.
|
||||
//
|
||||
// (or at least enqueue them, JIT-wise).
|
||||
// Probably: let the Chipset own the CIAs, killing the need to pass hsyncs/vsyncs
|
||||
// and CIA interrupt lines back and forth. Then the two run_fors can return, at most,
|
||||
// an interrupt level and a duration. Possibly give the chipset a reference to the
|
||||
// 68k so it can set IPL directly?
|
||||
|
||||
// Advance time.
|
||||
|
||||
// Do a quick advance check for Chip RAM access; add a suitable delay if required.
|
||||
Chipset::Changes net_changes;
|
||||
HalfCycles access_delay;
|
||||
if(cycle.operation & Microcycle::NewAddress && *cycle.address < 0x20'0000) {
|
||||
// TODO: shouldn't delay if the overlay bit is set?
|
||||
net_changes = chipset_.run_until_cpu_slot();
|
||||
access_delay = net_changes.duration;
|
||||
}
|
||||
|
||||
// Compute total length.
|
||||
const HalfCycles total_length = cycle.length + access_delay;
|
||||
|
||||
// The CIAs are on the E clock.
|
||||
// TODO: so they probably should be behind VPA?
|
||||
cia_divider_ += cycle.length;
|
||||
cia_divider_ += total_length;
|
||||
const HalfCycles e_clocks = cia_divider_.divide(HalfCycles(20));
|
||||
if(e_clocks > HalfCycles(0)) {
|
||||
cia_a_.run_for(e_clocks);
|
||||
cia_b_.run_for(e_clocks);
|
||||
}
|
||||
|
||||
const auto changes = chipset_.run_for(cycle.length);
|
||||
cia_a_.advance_tod(changes.vsyncs);
|
||||
cia_b_.advance_tod(changes.hsyncs);
|
||||
net_changes += chipset_.run_for(total_length);
|
||||
cia_a_.advance_tod(net_changes.vsyncs);
|
||||
cia_b_.advance_tod(net_changes.hsyncs);
|
||||
|
||||
chipset_.set_cia_interrupts(cia_a_.get_interrupt_line(), cia_b_.get_interrupt_line());
|
||||
mc68000_.set_interrupt_level(chipset_.get_interrupt_level());
|
||||
@ -95,11 +106,11 @@ class ConcreteMachine:
|
||||
// Autovector interrupts.
|
||||
if(cycle.operation & Microcycle::InterruptAcknowledge) {
|
||||
mc68000_.set_is_peripheral_address(true);
|
||||
return HalfCycles(0);
|
||||
return access_delay;
|
||||
}
|
||||
|
||||
// Do nothing if no address is exposed.
|
||||
if(!(cycle.operation & (Microcycle::NewAddress | Microcycle::SameAddress))) return HalfCycles(0);
|
||||
if(!(cycle.operation & (Microcycle::NewAddress | Microcycle::SameAddress))) return access_delay;
|
||||
|
||||
// TODO: interrupt acknowledgement.
|
||||
|
||||
@ -186,7 +197,7 @@ class ConcreteMachine:
|
||||
// }
|
||||
}
|
||||
|
||||
return HalfCycles(0);
|
||||
return access_delay;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -53,12 +53,11 @@ Chipset::Changes Chipset::run_until_cpu_slot() {
|
||||
|
||||
void Chipset::set_cia_interrupts(bool cia_a, bool cia_b) {
|
||||
// TODO: are these really latched, or are they active live?
|
||||
if(cia_a || cia_b) {
|
||||
interrupt_requests_ |=
|
||||
(cia_a ? InterruptFlag::IOPortsAndTimers : 0) |
|
||||
(cia_b ? InterruptFlag::External : 0);
|
||||
update_interrupts();
|
||||
}
|
||||
interrupt_requests_ &= ~(InterruptFlag::IOPortsAndTimers | InterruptFlag::External);
|
||||
interrupt_requests_ |=
|
||||
(cia_a ? InterruptFlag::IOPortsAndTimers : 0) |
|
||||
(cia_b ? InterruptFlag::External : 0);
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
bool Chipset::Copper::advance(uint16_t position) {
|
||||
@ -220,11 +219,6 @@ template <int cycle> void Chipset::output() {
|
||||
}
|
||||
|
||||
template <int cycle, bool stop_if_cpu> bool Chipset::perform_cycle() {
|
||||
// TODO: actual CPU scheduling.
|
||||
if constexpr (stop_if_cpu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if constexpr (cycle & 1) {
|
||||
// Odd slot priority is:
|
||||
//
|
||||
@ -249,7 +243,7 @@ template <int cycle, bool stop_if_cpu> bool Chipset::perform_cycle() {
|
||||
// 4. CPU.
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <bool stop_on_cpu> int Chipset::advance_slots(int first_slot, int last_slot) {
|
||||
@ -303,15 +297,24 @@ template <bool stop_on_cpu> Chipset::Changes Chipset::run(HalfCycles length) {
|
||||
const int end_slot = (line_cycle_ + line_pixels) >> 2;
|
||||
const int actual_slots = advance_slots<stop_on_cpu>(start_slot, end_slot);
|
||||
|
||||
if(actual_slots >= 0) {
|
||||
// TODO: abbreviate run, prior to adding to totals below.
|
||||
assert(false);
|
||||
if(stop_on_cpu && actual_slots >= 0) {
|
||||
// Run until the end of the named slot.
|
||||
if(actual_slots) {
|
||||
const int actual_line_pixels =
|
||||
(4 - (line_cycle_ & 3)) + ((actual_slots - 1) << 2);
|
||||
line_cycle_ += actual_line_pixels;
|
||||
changes.duration += HalfCycles(actual_line_pixels);
|
||||
}
|
||||
|
||||
// Just ensure an exit.
|
||||
pixels_remaining = 0;
|
||||
} else {
|
||||
line_cycle_ += line_pixels;
|
||||
changes.duration += HalfCycles(line_pixels);
|
||||
pixels_remaining -= line_pixels;
|
||||
}
|
||||
|
||||
line_cycle_ += line_pixels;
|
||||
pixels_remaining -= line_pixels;
|
||||
|
||||
// Advance intraline counter and possibly ripple upwards into
|
||||
// Advance intraline counter and pcoossibly ripple upwards into
|
||||
// lines and fields.
|
||||
if(line_cycle_ == (line_length_ * 4)) {
|
||||
++changes.hsyncs;
|
||||
@ -334,7 +337,6 @@ template <bool stop_on_cpu> Chipset::Changes Chipset::run(HalfCycles length) {
|
||||
}
|
||||
|
||||
changes.interrupt_level = interrupt_level_;
|
||||
changes.duration = length;
|
||||
return changes;
|
||||
}
|
||||
|
||||
@ -389,7 +391,8 @@ void Chipset::perform(const CPU::MC68000::Microcycle &cycle) {
|
||||
cycle.set_value16(position);
|
||||
} break;
|
||||
case Read(0x006): {
|
||||
const uint16_t position = uint16_t(((line_cycle_ << 6) & 0xff00) | (y_ & 0x00ff));
|
||||
// const uint16_t position = uint16_t(((line_cycle_ << 6) & 0xff00) | (y_ & 0x00ff));
|
||||
const uint16_t position = 0xd1ef; // TODO: !!!
|
||||
LOG("Read position low " << PADHEX(4) << position);
|
||||
cycle.set_value16(position);
|
||||
} break;
|
||||
|
@ -23,15 +23,18 @@ class Chipset {
|
||||
public:
|
||||
Chipset(uint16_t *ram, size_t size);
|
||||
|
||||
/// @returns The duration from now until the beginning of the next
|
||||
/// available CPU slot for accessing chip memory.
|
||||
HalfCycles time_until_cpu_slot();
|
||||
|
||||
struct Changes {
|
||||
int hsyncs = 0;
|
||||
int vsyncs = 0;
|
||||
int interrupt_level = 0;
|
||||
HalfCycles duration;
|
||||
|
||||
Changes &operator += (const Changes &rhs) {
|
||||
hsyncs += rhs.hsyncs;
|
||||
vsyncs += rhs.vsyncs;
|
||||
duration += rhs.duration;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// Advances the stated amount of time.
|
||||
@ -68,7 +71,7 @@ class Chipset {
|
||||
|
||||
// MARK: - Scheduler.
|
||||
|
||||
template <bool stop_on_cpu> Changes run(HalfCycles duration = HalfCycles());
|
||||
template <bool stop_on_cpu> Changes run(HalfCycles duration = HalfCycles::max());
|
||||
template <bool stop_on_cpu> int advance_slots(int, int);
|
||||
template <int cycle, bool stop_if_cpu> bool perform_cycle();
|
||||
template <int cycle> void output();
|
||||
|
Loading…
x
Reference in New Issue
Block a user