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:
parent
51b4b5551d
commit
872897029e
@ -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;
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user