mirror of
https://github.com/TomHarte/CLK.git
synced 2026-01-24 08:16:12 +00:00
Reformulate to give ULA full IRQ/NMI/reset signalling duties.
This commit is contained in:
@@ -899,7 +899,7 @@ public:
|
||||
// The WD1770 is nominally clocked at 8Mhz.
|
||||
wd1770_.run_for(duration * 4);
|
||||
}
|
||||
if constexpr (tube_processor != TubeProcessor::None) {
|
||||
if constexpr (requires {tube_.processor;}) {
|
||||
tube_.processor.run_for(duration);
|
||||
}
|
||||
|
||||
@@ -961,17 +961,15 @@ public:
|
||||
}
|
||||
}
|
||||
} else if(address >= 0xfee0 && address < 0xfee8) {
|
||||
if constexpr (tube_processor == TubeProcessor::None) {
|
||||
if constexpr (requires {tube_.ula;}) {
|
||||
if constexpr (is_read(operation)) {
|
||||
value = address == 0xfee0 ? 0xfe : 0xff;
|
||||
value = tube_.ula.host_read(address);
|
||||
} else {
|
||||
tube_.ula.host_write(address, value);
|
||||
}
|
||||
} else {
|
||||
if constexpr (is_read(operation)) {
|
||||
const uint8_t result = tube_.ula.host_read(address);
|
||||
value = result;
|
||||
} else {
|
||||
tube_.ula.host_write(address, value);
|
||||
tube_.processor.set_reset(tube_.ula.parasite_reset());
|
||||
value = address == 0xfee0 ? 0xfe : 0xff;
|
||||
}
|
||||
}
|
||||
} else if(address >= 0xfe08 && address < 0xfe10) {
|
||||
@@ -1108,9 +1106,8 @@ private:
|
||||
|
||||
void set_reset(const bool reset) {
|
||||
m6502_.template set<CPU::MOS6502Mk2::Line::Reset>(reset);
|
||||
if constexpr (tube_processor != TubeProcessor::None) {
|
||||
if constexpr (requires {tube_.ula;}) {
|
||||
tube_.ula.set_reset(reset);
|
||||
tube_.processor.set_reset(reset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1219,7 +1216,7 @@ private:
|
||||
void update_irq_line() {
|
||||
const bool tube_irq =
|
||||
[&] {
|
||||
if constexpr (tube_processor != TubeProcessor::None) {
|
||||
if constexpr (requires {tube_.ula;}) {
|
||||
return tube_.ula.has_host_irq();
|
||||
} else {
|
||||
return false;
|
||||
@@ -1274,9 +1271,10 @@ private:
|
||||
Tube<ConcreteMachine, tube_processor> tube_;
|
||||
|
||||
public:
|
||||
void set_host_tube_irq() { update_irq_line(); }
|
||||
void set_parasite_tube_irq() { tube_.processor.set_irq(); }
|
||||
void set_parasite_tube_nmi() { tube_.processor.set_nmi(); }
|
||||
void set_host_tube_irq(bool) { update_irq_line(); }
|
||||
void set_parasite_tube_irq(const bool active) { tube_.processor.set_irq(active); }
|
||||
void set_parasite_tube_nmi(const bool active) { tube_.processor.set_nmi(active); }
|
||||
void set_parasite_reset(const bool active) { tube_.processor.set_reset(active); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -42,12 +42,16 @@ struct FIFO {
|
||||
uint8_t read() {
|
||||
const uint8_t result = buffer_[read_ % length];
|
||||
if(write_ != read_) ++read_;
|
||||
if(write_ == read_) {
|
||||
ula_.fifo_is_empty(mask_);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Empties the FIFO.
|
||||
void reset() {
|
||||
read_ = write_ = 0;
|
||||
ula_.fifo_is_empty(mask_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -38,9 +38,7 @@ public:
|
||||
if(address >= 0xfef8 && address < 0xff00) {
|
||||
rom_visible_ = false;
|
||||
if constexpr (is_read(operation)) {
|
||||
const uint8_t result = ula_.parasite_read(address);
|
||||
value = result;
|
||||
update_interrupts();
|
||||
value = ula_.parasite_read(address);
|
||||
} else {
|
||||
ula_.parasite_write(address, value);
|
||||
}
|
||||
@@ -55,20 +53,14 @@ public:
|
||||
return Cycles(1);
|
||||
}
|
||||
|
||||
void set_irq() { m6502_.template set<CPU::MOS6502Mk2::Line::IRQ>(true); }
|
||||
void set_nmi() { m6502_.template set<CPU::MOS6502Mk2::Line::NMI>(true); }
|
||||
void set_irq(const bool active) { m6502_.template set<CPU::MOS6502Mk2::Line::IRQ>(active); }
|
||||
void set_nmi(const bool active) { m6502_.template set<CPU::MOS6502Mk2::Line::NMI>(active); }
|
||||
void set_reset(const bool reset) {
|
||||
m6502_.template set<CPU::MOS6502Mk2::Line::Reset>(reset);
|
||||
rom_visible_ |= reset;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
private:
|
||||
void update_interrupts() {
|
||||
m6502_.template set<CPU::MOS6502Mk2::Line::IRQ>(ula_.has_parasite_irq());
|
||||
m6502_.template set<CPU::MOS6502Mk2::Line::NMI>(ula_.has_parasite_nmi());
|
||||
}
|
||||
|
||||
uint8_t rom_[2048];
|
||||
uint8_t ram_[65536];
|
||||
Cycles cycles_modulo_;
|
||||
|
||||
@@ -31,12 +31,11 @@ public:
|
||||
z80_.run_for(cycles * 3);
|
||||
}
|
||||
|
||||
void set_irq() { z80_.set_interrupt_line(true); }
|
||||
void set_nmi() { z80_.set_non_maskable_interrupt_line(true); }
|
||||
void set_irq(const bool active) { z80_.set_interrupt_line(active); }
|
||||
void set_nmi(const bool active) { z80_.set_non_maskable_interrupt_line(active); }
|
||||
void set_reset(const bool reset) {
|
||||
z80_.set_reset_line(reset);
|
||||
rom_visible_ |= reset;
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
HalfCycles perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) {
|
||||
@@ -71,7 +70,6 @@ public:
|
||||
|
||||
case CPU::Z80::PartialMachineCycle::Input:
|
||||
*cycle.value = ula_.parasite_read(address);
|
||||
update_interrupts();
|
||||
break;
|
||||
|
||||
case CPU::Z80::PartialMachineCycle::Output:
|
||||
@@ -85,10 +83,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void update_interrupts() {
|
||||
z80_.set_interrupt_line(ula_.has_parasite_irq());
|
||||
z80_.set_non_maskable_interrupt_line(ula_.has_parasite_nmi());
|
||||
}
|
||||
|
||||
CPU::Z80::Processor<TubeZ80, false, false> z80_;
|
||||
bool rom_visible_ = true;
|
||||
|
||||
@@ -29,24 +29,15 @@ struct ULA {
|
||||
to_host4_(*this, 0x01)
|
||||
{}
|
||||
|
||||
/// @returns @c true if the parasite's reset line should be active.
|
||||
bool parasite_reset() const {
|
||||
return flags_ & 0x20;
|
||||
}
|
||||
|
||||
/// Call-in for the FIFOs; indicates that a FIFO just went from empty to not-empty,
|
||||
/// which might cause an interrupt elsewhere depending on the mask and on whether
|
||||
/// that interrupt is enabled.
|
||||
void fifo_has_data(const uint8_t mask) {
|
||||
if(!(flags_ & mask)) return;
|
||||
apply_fifo_mask(mask, 0xff);
|
||||
}
|
||||
|
||||
switch(mask) {
|
||||
default: __builtin_unreachable();
|
||||
case 0x01: host_.set_host_tube_irq(); break;
|
||||
case 0x02:
|
||||
case 0x04: host_.set_parasite_tube_irq(); break;
|
||||
case 0x08: host_.set_parasite_tube_nmi(); break;
|
||||
}
|
||||
void fifo_is_empty(const uint8_t mask) {
|
||||
apply_fifo_mask(0x00, ~mask);
|
||||
}
|
||||
|
||||
bool has_host_irq() const {
|
||||
@@ -115,9 +106,14 @@ struct ULA {
|
||||
}
|
||||
|
||||
void set_reset(const bool reset) {
|
||||
// This attempts the software
|
||||
if(!reset && reset_) {
|
||||
// flags_ = 0x01;
|
||||
if(reset_ == reset) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This is a software approximtion of holding the reset state for as long
|
||||
// as it is signalled.
|
||||
if(!reset) {
|
||||
flags_ = 0x01;
|
||||
to_parasite1_.reset();
|
||||
to_parasite2_.reset();
|
||||
to_parasite3_.reset();
|
||||
@@ -128,20 +124,53 @@ struct ULA {
|
||||
to_host4_.reset();
|
||||
}
|
||||
reset_ = reset;
|
||||
|
||||
update_parasite_reset();
|
||||
}
|
||||
|
||||
private:
|
||||
void signal_changes(const uint8_t changes) {
|
||||
if(changes & 0x01) {
|
||||
host_.set_host_tube_irq(interrupt_sources_ & 0x01);
|
||||
}
|
||||
if(changes & 0x06) {
|
||||
host_.set_parasite_tube_irq(interrupt_sources_ & 0x06);
|
||||
}
|
||||
if(changes & 0x08) {
|
||||
host_.set_parasite_tube_nmi(interrupt_sources_ & 0x08);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t signalling_fifos() const {
|
||||
return interrupt_sources_ & flags_;
|
||||
}
|
||||
|
||||
void apply_fifo_mask(const uint8_t or_, const uint8_t and_) {
|
||||
const auto signalling = signalling_fifos();
|
||||
interrupt_sources_ = (interrupt_sources_ | or_) & and_;
|
||||
signal_changes(signalling_fifos() ^ signalling);
|
||||
}
|
||||
|
||||
void update_parasite_reset() {
|
||||
host_.set_parasite_reset((flags_ & 0x20) || reset_);
|
||||
}
|
||||
|
||||
uint8_t status() const {
|
||||
return flags_;
|
||||
}
|
||||
|
||||
void set_status(const uint8_t value) {
|
||||
const auto signalling = signalling_fifos();
|
||||
const uint8_t bits = value & 0x3f;
|
||||
if(value & 0x80) {
|
||||
flags_ |= bits;
|
||||
} else {
|
||||
flags_ &= ~bits;
|
||||
}
|
||||
signal_changes(signalling_fifos() ^ signalling);
|
||||
if(value & 0x20) {
|
||||
update_parasite_reset();
|
||||
}
|
||||
|
||||
// TODO: understand meaning of bits 4 and 6.
|
||||
}
|
||||
@@ -149,6 +178,7 @@ private:
|
||||
HostT &host_;
|
||||
uint8_t flags_ = 0x01;
|
||||
bool reset_ = false;
|
||||
uint8_t interrupt_sources_ = 0x00;
|
||||
|
||||
FIFO<1, ULA> to_parasite1_;
|
||||
FIFO<1, ULA> to_parasite2_;
|
||||
|
||||
Reference in New Issue
Block a user