1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-25 18:30:21 +00:00

Merge pull request #674 from TomHarte/LessACIAState

Reduces redundant ACIA state.
This commit is contained in:
Thomas Harte 2019-11-12 22:32:47 -05:00 committed by GitHub
commit b019c6f8dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 38 deletions

View File

@ -21,26 +21,11 @@ ACIA::ACIA(HalfCycles transmit_clock_rate, HalfCycles receive_clock_rate) :
uint8_t ACIA::read(int address) {
if(address&1) {
clear_interrupt_cause(ReceiveNeedsRead);
received_data_ |= NoValueMask;
update_interrupt_line();
return uint8_t(received_data_);
} else {
return
((received_data_ & NoValueMask) ? 0x00 : 0x01) |
((next_transmission_ == NoValueMask) ? 0x02 : 0x00) |
(data_carrier_detect.read() ? 0x04 : 0x00) |
(clear_to_send.read() ? 0x08 : 0x00) |
(interrupt_causes_ ? 0x80 : 0x00)
;
// b0: receive data full.
// b1: transmit data empty.
// b2: DCD.
// b3: CTS.
// b4: framing error (i.e. no first stop bit where expected).
// b5: receiver overran.
// b6: parity error.
// b7: IRQ state.
return get_status();
}
}
@ -48,7 +33,7 @@ void ACIA::write(int address, uint8_t value) {
if(address&1) {
next_transmission_ = value;
consider_transmission();
clear_interrupt_cause(TransmitNeedsWrite);
update_interrupt_line();
} else {
if((value&3) == 3) {
transmit.reset_writing();
@ -85,6 +70,8 @@ void ACIA::write(int address, uint8_t value) {
}
receive.set_read_delegate(this, Storage::Time(divider_ * 2, int(receive_clock_rate_.as_integral())));
receive_interrupt_enabled_ = value & 0x80;
update_interrupt_line();
}
}
update_clocking_observer();
@ -132,7 +119,7 @@ ClockingHint::Preference ACIA::preferred_clocking() {
}
bool ACIA::get_interrupt_line() const {
return interrupt_causes_;
return interrupt_line_;
}
int ACIA::expected_bits() {
@ -157,7 +144,7 @@ bool ACIA::serial_line_did_produce_bit(Serial::Line *line, int bit) {
if(bits_received_ >= bit_target) {
bits_received_ = 0;
received_data_ = uint8_t(bits_incoming_ >> (12 - bit_target));
if(receive_interrupt_enabled_) add_interrupt_cause(ReceiveNeedsRead);
update_interrupt_line();
update_clocking_observer();
return false;
}
@ -173,16 +160,51 @@ void ACIA::set_interrupt_delegate(InterruptDelegate *delegate) {
interrupt_delegate_ = delegate;
}
void ACIA::add_interrupt_cause(int cause) {
const bool is_changing_state = !interrupt_causes_;
interrupt_causes_ |= cause;
if(interrupt_delegate_ && is_changing_state)
void ACIA::update_interrupt_line() {
const bool old_line = interrupt_line_;
/*
"Bit 7 of the control register is the rie bit. When the rie bit is high, the rdrf, ndcd,
and ovr bits will assert the nirq output. When the rie bit is low, nirq generation is disabled."
rie = read interrupt enable
rdrf = receive data register full (status word bit 0)
ndcd = data carrier detect (status word bit 2)
over = receiver overrun (status word bit 5)
"Bit 1 of the status register is the tdre bit. When high, the tdre bit indicates that data has been
transferred from the transmitter data register to the output shift register. At this point, the a6850
is ready to accept a new transmit data byte. However, if the ncts signal is high, the tdre bit remains
low regardless of the status of the transmitter data register. Also, if transmit interrupt is enabled,
the nirq output is asserted."
tdre = transmitter data register empty
ncts = clear to send
*/
const auto status = get_status();
interrupt_line_ =
(receive_interrupt_enabled_ && (status & 0x25)) ||
(transmit_interrupt_enabled_ && (status & 0x02));
if(interrupt_delegate_ && old_line != interrupt_line_)
interrupt_delegate_->acia6850_did_change_interrupt_status(this);
}
void ACIA::clear_interrupt_cause(int cause) {
const bool was_set = interrupt_causes_;
interrupt_causes_ &= ~cause;
if(interrupt_delegate_ && was_set && !interrupt_causes_)
interrupt_delegate_->acia6850_did_change_interrupt_status(this);
uint8_t ACIA::get_status() {
return
((received_data_ & NoValueMask) ? 0x00 : 0x01) |
((next_transmission_ == NoValueMask) ? 0x02 : 0x00) |
// (data_carrier_detect.read() ? 0x04 : 0x00) |
// (clear_to_send.read() ? 0x08 : 0x00) |
(interrupt_line_ ? 0x80 : 0x00)
;
// b0: receive data full.
// b1: transmit data empty.
// b2: DCD.
// b3: CTS.
// b4: framing error (i.e. no first stop bit where expected).
// b5: receiver overran.
// b6: parity error.
// b7: IRQ state.
}

View File

@ -65,7 +65,7 @@ class ACIA: public ClockingHint::Source, private Serial::Line::ReadDelegate {
} else {
transmit.advance_writer(transmission_cycles);
update_clocking_observer();
if(transmit_interrupt_enabled_) add_interrupt_cause(TransmitNeedsWrite);
update_interrupt_line();
}
} else {
transmit.advance_writer(transmission_cycles);
@ -118,15 +118,10 @@ class ACIA: public ClockingHint::Source, private Serial::Line::ReadDelegate {
bool serial_line_did_produce_bit(Serial::Line *line, int bit) final;
enum InterruptCause: int {
TransmitNeedsWrite = 1 << 0,
ReceiveNeedsRead = 1 << 1,
StatusNeedsRead = 1 << 2
};
int interrupt_causes_ = 0;
void add_interrupt_cause(int cause);
void clear_interrupt_cause(int cause);
bool interrupt_line_ = false;
void update_interrupt_line();
InterruptDelegate *interrupt_delegate_ = nullptr;
uint8_t get_status();
};
}