1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-19 08:31:11 +00:00

Attempts a complete wiring of 68901 interrupts.

This commit is contained in:
Thomas Harte 2019-10-25 22:36:01 -04:00
parent 51b4b5551d
commit 872897029e
3 changed files with 66 additions and 9 deletions

View File

@ -50,7 +50,9 @@ uint8_t MFP68901::read(int address) {
case 0x0a:
LOG("Read: interrupt mask B");
return uint8_t(interrupt_mask_);
case 0x0b: LOG("Read: vector"); break;
case 0x0b:
LOG("Read: vector");
return interrupt_vector_;
case 0x0c: LOG("Read: timer A control"); break;
case 0x0d: LOG("Read: timer B control"); break;
case 0x0e: LOG("Read: timers C/D control"); break;
@ -106,7 +108,10 @@ void MFP68901::write(int address, uint8_t value) {
interrupt_mask_ = (interrupt_mask_ & 0xff00) | value;
update_interrupts();
break;
case 0x0b: LOG("Write: vector " << PADHEX(2) << int(value)); break;
case 0x0b:
LOG("Write: vector " << PADHEX(2) << int(value));
interrupt_vector_ = value;
break;
case 0x0c:
case 0x0d: {
const auto timer = address - 0xc;
@ -261,11 +266,12 @@ void MFP68901::end_interrupts(int interrupt) {
}
void MFP68901::update_interrupts() {
const bool old_interrupt_line = interrupt_line_;
interrupt_pending_ = interrupt_in_service_ & interrupt_enable_;
interrupt_line_ = interrupt_pending_ & interrupt_mask_;
if(interrupt_line_) {
LOG("Should produce interrupt...");
if(interrupt_delegate_ && interrupt_line_ != old_interrupt_line) {
interrupt_delegate_->mfp68901_did_change_interrupt_status(this);
}
}
@ -273,7 +279,17 @@ bool MFP68901::get_interrupt_line() {
return interrupt_line_;
}
uint16_t MFP68901::acknowledge_interrupt() {
// TODO.
return 0;
uint8_t MFP68901::acknowledge_interrupt() {
uint8_t selected_interrupt = 15;
uint16_t interrupt_mask = 0x8000;
while(!(interrupt_pending_ & interrupt_mask) && interrupt_mask) {
interrupt_mask >>= 1;
--selected_interrupt;
}
end_interrupts(interrupt_mask);
return (interrupt_vector_ & 0xf0) | selected_interrupt;
}
void MFP68901::set_interrupt_delegate(InterruptDelegate *delegate) {
interrupt_delegate_ = delegate;
}

View File

@ -35,7 +35,12 @@ class MFP68901 {
uint8_t get_port_output();
bool get_interrupt_line();
uint16_t acknowledge_interrupt();
uint8_t acknowledge_interrupt();
struct InterruptDelegate {
virtual void mfp68901_did_change_interrupt_status(MFP68901 *) = 0;
};
void set_interrupt_delegate(InterruptDelegate *delegate);
private:
// MARK: - Timers
@ -69,6 +74,8 @@ class MFP68901 {
// MARK: - Interrupts
InterruptDelegate *interrupt_delegate_ = nullptr;
// Ad hoc documentation: there seems to be a four-stage process here.
// This is my current understanding:
//
@ -88,6 +95,7 @@ class MFP68901 {
int interrupt_pending_ = 0;
int interrupt_mask_ = 0;
bool interrupt_line_ = false;
uint8_t interrupt_vector_ = 0;
enum Interrupt {
GPIP0 = (1 << 0),

View File

@ -215,7 +215,8 @@ class ConcreteMachine:
public CPU::MC68000::BusHandler,
public CRTMachine::Machine,
public ClockingHint::Observer,
public Motorola::ACIA::ACIA::InterruptDelegate {
public Motorola::ACIA::ACIA::InterruptDelegate,
public Motorola::MFP68901::MFP68901::InterruptDelegate {
public:
ConcreteMachine(const Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
mc68000_(*this),
@ -259,6 +260,8 @@ class ConcreteMachine:
keyboard_acia_->set_clocking_hint_observer(this);
ikbd_.set_clocking_hint_observer(this);
mfp_->set_interrupt_delegate(this);
set_gpip_input();
}
@ -290,6 +293,23 @@ class ConcreteMachine:
/* TODO: DTack, bus error, VPA. */
// An interrupt acknowledge, perhaps?
if(cycle.operation & Microcycle::InterruptAcknowledge) {
// Current implementation: everything other than 6 (i.e. the MFP is autovectored.
if((cycle.word_address()&7) != 6) {
mc68000_.set_is_peripheral_address(true);
return HalfCycles(0);
} else {
if(cycle.operation & Microcycle::SelectByte) {
cycle.value->halves.low = mfp_->acknowledge_interrupt();
}
return HalfCycles(0);
}
}
// Just in case the last cycle was an interrupt acknowledge. TODO: find a better solution?
mc68000_.set_is_peripheral_address(false);
auto address = cycle.word_address();
// if(cycle.data_select_active()) printf("%c %06x\n", (cycle.operation & Microcycle::Read) ? 'r' : 'w', *cycle.address & 0xffffff);
uint16_t *memory;
@ -612,6 +632,19 @@ class ConcreteMachine:
((keyboard_acia_->get_interrupt_line() || midi_acia_->get_interrupt_line()) ? 0x0 : 0x10) // Interrupts are active low.
);
}
// MARK - MFP input.
void mfp68901_did_change_interrupt_status(Motorola::MFP68901::MFP68901 *mfp) final {
update_interrupt_input();
}
void update_interrupt_input() {
if(mfp_->get_interrupt_line()) {
mc68000_.set_interrupt_level(6);
} else {
mc68000_.set_interrupt_level(0);
}
}
};
}