mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-29 12:50:28 +00:00
Makes a first attempt at some sort of interrupt functionality.
This commit is contained in:
parent
e671cc6056
commit
87dcd82f69
@ -82,6 +82,7 @@ class ConcreteMachine:
|
|||||||
const auto changes = chipset_.run_for(cycle.length);
|
const auto changes = chipset_.run_for(cycle.length);
|
||||||
cia_a_.advance_tod(changes.vsyncs);
|
cia_a_.advance_tod(changes.vsyncs);
|
||||||
cia_b_.advance_tod(changes.hsyncs);
|
cia_b_.advance_tod(changes.hsyncs);
|
||||||
|
mc68000_.set_interrupt_level(changes.interrupt_level);
|
||||||
|
|
||||||
// Check for assertion of reset.
|
// Check for assertion of reset.
|
||||||
if(cycle.operation & Microcycle::Reset) {
|
if(cycle.operation & Microcycle::Reset) {
|
||||||
@ -89,6 +90,13 @@ class ConcreteMachine:
|
|||||||
LOG("Reset; PC is around " << PADHEX(8) << mc68000_.get_state().program_counter);
|
LOG("Reset; PC is around " << PADHEX(8) << mc68000_.get_state().program_counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Autovector interrupts.
|
||||||
|
if(cycle.operation & Microcycle::InterruptAcknowledge) {
|
||||||
|
mc68000_.set_is_peripheral_address(true);
|
||||||
|
} else {
|
||||||
|
mc68000_.set_is_peripheral_address(false);
|
||||||
|
}
|
||||||
|
|
||||||
// Do nothing if no address is exposed.
|
// 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 HalfCycles(0);
|
||||||
|
|
||||||
|
@ -16,6 +16,27 @@
|
|||||||
|
|
||||||
using namespace Amiga;
|
using namespace Amiga;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
enum InterruptFlag: uint16_t {
|
||||||
|
SerialPortTransmit = 1 << 0,
|
||||||
|
DiskBlock = 1 << 1,
|
||||||
|
Software = 1 << 2,
|
||||||
|
IOPortsAndTimers = 1 << 3,
|
||||||
|
Copper = 1 << 4,
|
||||||
|
VerticalBlank = 1 << 5,
|
||||||
|
Blitter = 1 << 6,
|
||||||
|
AudioChannel0 = 1 << 7,
|
||||||
|
AudioChannel1 = 1 << 8,
|
||||||
|
AudioChannel2 = 1 << 9,
|
||||||
|
AudioChannel3 = 1 << 10,
|
||||||
|
SerialPortReceive = 1 << 11,
|
||||||
|
DiskSyncMatch = 1 << 12,
|
||||||
|
External = 1 << 13,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Chipset::Chipset(uint16_t *ram, size_t size) :
|
Chipset::Chipset(uint16_t *ram, size_t size) :
|
||||||
blitter_(ram, size) {
|
blitter_(ram, size) {
|
||||||
}
|
}
|
||||||
@ -33,9 +54,37 @@ Chipset::Changes Chipset::run_for(HalfCycles length) {
|
|||||||
changes.vsyncs = y_ / 312;
|
changes.vsyncs = y_ / 312;
|
||||||
y_ %= 312;
|
y_ %= 312;
|
||||||
|
|
||||||
|
// y = 0 => start of vertical blank.
|
||||||
|
if(changes.vsyncs) {
|
||||||
|
interrupt_requests_ |= InterruptFlag::VerticalBlank;
|
||||||
|
update_interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
changes.interrupt_level = interrupt_level_;
|
||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Chipset::update_interrupts() {
|
||||||
|
interrupt_level_ = 0;
|
||||||
|
|
||||||
|
const uint16_t enabled_requests = interrupt_enable_ & interrupt_requests_ & 0x3fff;
|
||||||
|
if(enabled_requests && (interrupt_enable_ & 0x4000)) {
|
||||||
|
if(enabled_requests & (InterruptFlag::External)) {
|
||||||
|
interrupt_level_ = 6;
|
||||||
|
} else if(enabled_requests & (InterruptFlag::SerialPortReceive | InterruptFlag::DiskSyncMatch)) {
|
||||||
|
interrupt_level_ = 5;
|
||||||
|
} else if(enabled_requests & (InterruptFlag::AudioChannel0 | InterruptFlag::AudioChannel1 | InterruptFlag::AudioChannel2 | InterruptFlag::AudioChannel3)) {
|
||||||
|
interrupt_level_ = 4;
|
||||||
|
} else if(enabled_requests & (InterruptFlag::Copper | InterruptFlag::VerticalBlank | InterruptFlag::Blitter)) {
|
||||||
|
interrupt_level_ = 3;
|
||||||
|
} else if(enabled_requests & (InterruptFlag::External)) {
|
||||||
|
interrupt_level_ = 2;
|
||||||
|
} else if(enabled_requests & (InterruptFlag::SerialPortTransmit | InterruptFlag::DiskBlock | InterruptFlag::Software)) {
|
||||||
|
interrupt_level_ = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Chipset::perform(const CPU::MC68000::Microcycle &cycle) {
|
void Chipset::perform(const CPU::MC68000::Microcycle &cycle) {
|
||||||
using Microcycle = CPU::MC68000::Microcycle;
|
using Microcycle = CPU::MC68000::Microcycle;
|
||||||
|
|
||||||
@ -119,11 +168,18 @@ void Chipset::perform(const CPU::MC68000::Microcycle &cycle) {
|
|||||||
update_interrupts();
|
update_interrupts();
|
||||||
LOG("Interrupt enable mask modified by " << PADHEX(4) << cycle.value16() << "; is now " << std::bitset<16>{interrupt_enable_});
|
LOG("Interrupt enable mask modified by " << PADHEX(4) << cycle.value16() << "; is now " << std::bitset<16>{interrupt_enable_});
|
||||||
break;
|
break;
|
||||||
|
case Read(0x01c):
|
||||||
|
cycle.set_value16(interrupt_enable_);
|
||||||
|
break;
|
||||||
|
|
||||||
case Write(0x09c):
|
case Write(0x09c):
|
||||||
ApplySetClear(interrupt_requests_);
|
ApplySetClear(interrupt_requests_);
|
||||||
update_interrupts();
|
update_interrupts();
|
||||||
LOG("Interrupt request modified by " << PADHEX(4) << cycle.value16() << "; is now " << std::bitset<16>{interrupt_requests_});
|
LOG("Interrupt request modified by " << PADHEX(4) << cycle.value16() << "; is now " << std::bitset<16>{interrupt_requests_});
|
||||||
break;
|
break;
|
||||||
|
case Read(0x01e):
|
||||||
|
cycle.set_value16(interrupt_requests_);
|
||||||
|
break;
|
||||||
|
|
||||||
// Display management.
|
// Display management.
|
||||||
case Write(0x08e): {
|
case Write(0x08e): {
|
||||||
|
@ -29,7 +29,7 @@ class Chipset {
|
|||||||
struct Changes {
|
struct Changes {
|
||||||
int hsyncs = 0;
|
int hsyncs = 0;
|
||||||
int vsyncs = 0;
|
int vsyncs = 0;
|
||||||
// TODO: interrupt change?
|
int interrupt_level = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Advances the stated amount of time.
|
/// Advances the stated amount of time.
|
||||||
@ -38,15 +38,19 @@ class Chipset {
|
|||||||
/// Performs the provided microcycle, which the caller guarantees to be a memory access.
|
/// Performs the provided microcycle, which the caller guarantees to be a memory access.
|
||||||
void perform(const CPU::MC68000::Microcycle &);
|
void perform(const CPU::MC68000::Microcycle &);
|
||||||
|
|
||||||
|
/// Provides the chipset's current interrupt level.
|
||||||
|
int get_interrupt_level() {
|
||||||
|
return interrupt_level_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// MARK: - Interrupts.
|
// MARK: - Interrupts.
|
||||||
|
|
||||||
uint16_t interrupt_enable_ = 0;
|
uint16_t interrupt_enable_ = 0;
|
||||||
uint16_t interrupt_requests_ = 0;
|
uint16_t interrupt_requests_ = 0;
|
||||||
|
int interrupt_level_ = 0;
|
||||||
|
|
||||||
void update_interrupts() {
|
void update_interrupts();
|
||||||
// TODO.
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - DMA Control and Blitter.
|
// MARK: - DMA Control and Blitter.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user