1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-16 18:30:32 +00:00

Attempts to get a bit more systematic.

Spotted that interrupt_enable_ isn't being used properly while doing so, hopefully that's now correct.
This commit is contained in:
Thomas Harte 2019-10-29 23:07:03 -04:00
parent 1c154131f9
commit 4857ceb3eb

View File

@ -18,54 +18,37 @@ using namespace Motorola::MFP68901;
uint8_t MFP68901::read(int address) {
address &= 0x1f;
// Interrupt block: various bits of state can be read, all passively.
if(address >= 0x03 && address <= 0x0b) {
const int shift = (address&1) << 3;
switch(address) {
case 0x03: case 0x04: return uint8_t(interrupt_enable_ >> shift);
case 0x05: case 0x06: return uint8_t(interrupt_pending_ >> shift);
case 0x07: case 0x08: return uint8_t(interrupt_in_service_ >> shift);
case 0x09: case 0x0a: return uint8_t(interrupt_mask_ >> shift);
case 0x0b: return interrupt_vector_;
default: break;
}
}
switch(address) {
case 0x00:
LOG("Read: general purpose IO " << PADHEX(2) << ((gpip_input_ & ~gpip_direction_) | (gpip_output_ & gpip_direction_)));
return (gpip_input_ & ~gpip_direction_) | (gpip_output_ & gpip_direction_);
case 0x01:
LOG("Read: active edge " << PADHEX(2) << int(gpip_active_edge_));
return gpip_active_edge_;
case 0x02:
LOG("Read: data direction " << PADHEX(2) << int(gpip_direction_));
return gpip_direction_;
case 0x03:
LOG("Read: interrupt enable A");
return uint8_t(interrupt_enable_ >> 8);
case 0x04:
LOG("Read: interrupt enable B");
return uint8_t(interrupt_enable_);
case 0x05:
LOG("Read: interrupt pending A");
return uint8_t(interrupt_pending_ >> 8);
case 0x06:
LOG("Read: interrupt pending B");
return uint8_t(interrupt_pending_);
case 0x07:
LOG("Read: interrupt in-service A");
return uint8_t(interrupt_in_service_ >> 8);
case 0x08:
LOG("Read: interrupt in-service B");
return uint8_t(interrupt_in_service_);
case 0x09:
LOG("Read: interrupt mask A");
return uint8_t(interrupt_mask_ >> 8);
case 0x0a:
LOG("Read: interrupt mask B");
return uint8_t(interrupt_mask_);
case 0x0b:
LOG("Read: vector");
return interrupt_vector_;
case 0x0c:
LOG("Read: timer A control");
return timer_ab_control_[0];
case 0x0d:
LOG("Read: timer B control");
return timer_ab_control_[1];
case 0x0e:
LOG("Read: timers C/D control");
return timer_cd_control_;
case 0x0f: case 0x10: case 0x11: case 0x12:
return get_timer_data(address - 0xf);
// GPIP block: input, and configured active edge and direction values.
case 0x00: return (gpip_input_ & ~gpip_direction_) | (gpip_output_ & gpip_direction_);
case 0x01: return gpip_active_edge_;
case 0x02: return gpip_direction_;
/* Interrupt block dealt with above. */
default: break;
// Timer block: read back A, B and C/D control, and read current timer values.
case 0x0c: case 0x0d: return timer_ab_control_[address - 0xc];
case 0x0e: return timer_cd_control_;
case 0x0f: case 0x10:
case 0x11: case 0x12: return get_timer_data(address - 0xf);
// USART block: TODO.
case 0x13: LOG("Read: sync character generator"); break;
case 0x14: LOG("Read: USART control"); break;
case 0x15: LOG("Read: receiver status"); break;
@ -77,74 +60,61 @@ uint8_t MFP68901::read(int address) {
void MFP68901::write(int address, uint8_t value) {
address &= 0x1f;
// Interrupt block: enabled and masked interrupts can be set; pending and in-service interrupts can be masked.
if(address >= 0x03 && address <= 0x0b) {
const int shift = (address&1) << 3;
const int preserve = 0xff00 >> shift;
const int word_value = value << shift;
switch(address) {
default: break;
case 0x03: case 0x04: // Adjust enabled interrupts; disabled ones also cease to be pending.
interrupt_enable_ = (interrupt_enable_ & preserve) | word_value;
interrupt_pending_ &= interrupt_enable_;
break;
case 0x05: case 0x06: // Resolve pending interrupts.
interrupt_pending_ &= (preserve | word_value);
break;
case 0x07: case 0x08: // Resolve in-service interrupts.
interrupt_in_service_ &= (preserve | word_value);
break;
case 0x09: case 0x0a: // Adjust interrupt mask.
interrupt_mask_ = (interrupt_mask_ & preserve) | word_value;
break;
case 0x0b: // Set the interrupt vector, possibly changing end-of-interrupt mode.
interrupt_vector_ = value;
// If automatic end-of-interrupt mode has now been enabled, clear
// the in-process mask and re-evaluate.
if(interrupt_vector_ & 0x08) return;
interrupt_in_service_ = 0;
break;
}
// Whatever just happened may have affected the state of the interrupt line.
update_interrupts();
return;
}
switch(address) {
// GPIP block: output and configuration of active edge and direction values.
case 0x00:
LOG("Write: general purpose IO " << PADHEX(2) << int(value));
gpip_output_ = value;
break;
case 0x01:
LOG("Write: active edge " << PADHEX(2) << int(value));
gpip_active_edge_ = value;
reevaluate_gpip_interrupts();
break;
case 0x02:
LOG("Write: data direction " << PADHEX(2) << int(value));
gpip_direction_ = value;
reevaluate_gpip_interrupts();
break;
case 0x03:
LOG("Write: interrupt enable A " << PADHEX(2) << int(value));
interrupt_enable_ = (interrupt_enable_ & 0x00ff) | (value << 8);
interrupt_pending_ = (interrupt_enable_ & 0x00ff) | (value << 8);
update_interrupts();
break;
case 0x04:
LOG("Write: interrupt enable B " << PADHEX(2) << int(value));
interrupt_enable_ = (interrupt_enable_ & 0xff00) | value;
interrupt_pending_ = (interrupt_enable_ & 0xff00) | value;
update_interrupts();
break;
case 0x05:
LOG("Write: interrupt pending A " << PADHEX(2) << int(value));
interrupt_pending_ &= 0x00ff | (value << 8);
update_interrupts();
break;
case 0x06:
LOG("Write: interrupt pending B " << PADHEX(2) << int(value));
interrupt_pending_ &= 0xff00 | value;
update_interrupts();
break;
case 0x07:
LOG("Write: interrupt in-service A " << PADHEX(2) << int(value));
interrupt_in_service_ &= 0x00ff | (value << 8);
update_interrupts();
break;
case 0x08:
LOG("Write: interrupt in-service B " << PADHEX(2) << int(value));
interrupt_in_service_ &= 0xff00 | value;
update_interrupts();
break;
case 0x09:
LOG("Write: interrupt mask A " << PADHEX(2) << int(value));
interrupt_mask_ = (interrupt_mask_ & 0x00ff) | (value << 8);
update_interrupts();
break;
case 0x0a:
LOG("Write: interrupt mask B " << PADHEX(2) << int(value));
interrupt_mask_ = (interrupt_mask_ & 0xff00) | value;
update_interrupts();
break;
case 0x0b:
LOG("Write: vector " << PADHEX(2) << int(value));
interrupt_vector_ = value;
// If automatic end-of-interrupt mode has now been enabled, clear
// the in-process mask and re-evaluate.
if(!(interrupt_vector_ & 0x08)) {
interrupt_in_service_ = 0;
update_interrupts();
}
break;
/* Interrupt block dealt with above. */
default: break;
// Timer block.
case 0x0c:
case 0x0d: {
const auto timer = address - 0xc;
@ -195,6 +165,8 @@ void MFP68901::write(int address, uint8_t value) {
case 0x0f: case 0x10: case 0x11: case 0x12:
set_timer_data(address - 0xf, value);
break;
// USART block: TODO.
case 0x13: LOG("Write: sync character generator"); break;
case 0x14: LOG("Write: USART control"); break;
case 0x15: LOG("Write: receiver status"); break;
@ -282,7 +254,7 @@ uint8_t MFP68901::get_port_output() {
}
void MFP68901::reevaluate_gpip_interrupts() {
const uint8_t gpip_state = gpip_input_ ^ gpip_active_edge_;
const uint8_t gpip_state = (gpip_input_ & ~gpip_direction_) ^ gpip_active_edge_;
// An interrupt is detected on any falling edge.
const uint8_t new_interrupt_mask = (gpip_state ^ gpip_interrupt_state_) & gpip_interrupt_state_;
@ -299,7 +271,7 @@ void MFP68901::reevaluate_gpip_interrupts() {
// MARK: - Interrupts
void MFP68901::begin_interrupts(int interrupt) {
interrupt_pending_ |= interrupt;
interrupt_pending_ |= interrupt & interrupt_enable_;
update_interrupts();
}