1
0
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:
Thomas Harte
2025-11-05 15:27:11 -05:00
parent 62919e77d4
commit 2fe6e9c7fc
5 changed files with 67 additions and 49 deletions

View File

@@ -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); }
};
}

View File

@@ -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:

View File

@@ -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_;

View File

@@ -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;

View File

@@ -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_;