mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-01 11:49:58 +00:00
Attempts properly to maintain interrupt flag; adds delegate.
This commit is contained in:
parent
ed9a5b0430
commit
7cb82fccc0
@ -8,10 +8,6 @@
|
|||||||
|
|
||||||
#include "6850.hpp"
|
#include "6850.hpp"
|
||||||
|
|
||||||
#define LOG_PREFIX "[6850] "
|
|
||||||
#define NDEBUG
|
|
||||||
#include "../../Outputs/Log.hpp"
|
|
||||||
|
|
||||||
using namespace Motorola::ACIA;
|
using namespace Motorola::ACIA;
|
||||||
|
|
||||||
const HalfCycles ACIA::SameAsTransmit;
|
const HalfCycles ACIA::SameAsTransmit;
|
||||||
@ -25,17 +21,16 @@ ACIA::ACIA(HalfCycles transmit_clock_rate, HalfCycles receive_clock_rate) :
|
|||||||
|
|
||||||
uint8_t ACIA::read(int address) {
|
uint8_t ACIA::read(int address) {
|
||||||
if(address&1) {
|
if(address&1) {
|
||||||
LOG("Read from receive register");
|
clear_interrupt_cause(ReceiveNeedsRead);
|
||||||
interrupt_request_ = false;
|
|
||||||
received_data_ |= NoValueMask;
|
received_data_ |= NoValueMask;
|
||||||
} else {
|
} else {
|
||||||
LOG("Read status");
|
clear_interrupt_cause(StatusNeedsRead);
|
||||||
return
|
return
|
||||||
((received_data_ & NoValueMask) ? 0x00 : 0x01) |
|
((received_data_ & NoValueMask) ? 0x00 : 0x01) |
|
||||||
((next_transmission_ == NoValueMask) ? 0x02 : 0x00) |
|
((next_transmission_ == NoValueMask) ? 0x02 : 0x00) |
|
||||||
(data_carrier_detect.read() ? 0x04 : 0x00) |
|
(data_carrier_detect.read() ? 0x04 : 0x00) |
|
||||||
(clear_to_send.read() ? 0x08 : 0x00) |
|
(clear_to_send.read() ? 0x08 : 0x00) |
|
||||||
(interrupt_request_ ? 0x80 : 0x00)
|
(interrupt_causes_ ? 0x80 : 0x00)
|
||||||
;
|
;
|
||||||
|
|
||||||
// b0: receive data full.
|
// b0: receive data full.
|
||||||
@ -54,7 +49,7 @@ void ACIA::write(int address, uint8_t value) {
|
|||||||
if(address&1) {
|
if(address&1) {
|
||||||
next_transmission_ = value;
|
next_transmission_ = value;
|
||||||
consider_transmission();
|
consider_transmission();
|
||||||
interrupt_request_ = false;
|
clear_interrupt_cause(TransmitNeedsWrite);
|
||||||
} else {
|
} else {
|
||||||
if((value&3) == 3) {
|
if((value&3) == 3) {
|
||||||
transmit.reset_writing();
|
transmit.reset_writing();
|
||||||
@ -114,7 +109,7 @@ void ACIA::run_for(HalfCycles length) {
|
|||||||
} else {
|
} else {
|
||||||
transmit.advance_writer(transmit_advance);
|
transmit.advance_writer(transmit_advance);
|
||||||
update_clocking_observer();
|
update_clocking_observer();
|
||||||
interrupt_request_ |= transmit_interrupt_enabled_;
|
if(transmit_interrupt_enabled_) add_interrupt_cause(TransmitNeedsWrite);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
transmit.advance_writer(transmit_advance);
|
transmit.advance_writer(transmit_advance);
|
||||||
@ -143,11 +138,7 @@ void ACIA::consider_transmission() {
|
|||||||
|
|
||||||
// Output all that.
|
// Output all that.
|
||||||
const int total_bits = expected_bits();
|
const int total_bits = expected_bits();
|
||||||
if(!next_transmission_) {
|
|
||||||
printf("");
|
|
||||||
}
|
|
||||||
transmit.write(divider_ * 2, total_bits, transmission);
|
transmit.write(divider_ * 2, total_bits, transmission);
|
||||||
printf("Transmitted %02x [%03x]\n", next_transmission_, transmission);
|
|
||||||
|
|
||||||
// Mark the transmit register as empty again.
|
// Mark the transmit register as empty again.
|
||||||
next_transmission_ = NoValueMask;
|
next_transmission_ = NoValueMask;
|
||||||
@ -168,7 +159,7 @@ ClockingHint::Preference ACIA::preferred_clocking() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ACIA::get_interrupt_line() const {
|
bool ACIA::get_interrupt_line() const {
|
||||||
return interrupt_request_;
|
return interrupt_causes_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ACIA::expected_bits() {
|
int ACIA::expected_bits() {
|
||||||
@ -193,7 +184,7 @@ bool ACIA::serial_line_did_produce_bit(Serial::Line *line, int bit) {
|
|||||||
if(bits_received_ >= bit_target) {
|
if(bits_received_ >= bit_target) {
|
||||||
bits_received_ = 0;
|
bits_received_ = 0;
|
||||||
received_data_ = uint8_t(bits_incoming_ >> (12 - bit_target));
|
received_data_ = uint8_t(bits_incoming_ >> (12 - bit_target));
|
||||||
interrupt_request_ |= receive_interrupt_enabled_;
|
if(receive_interrupt_enabled_) add_interrupt_cause(ReceiveNeedsRead);
|
||||||
update_clocking_observer();
|
update_clocking_observer();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -204,3 +195,21 @@ bool ACIA::serial_line_did_produce_bit(Serial::Line *line, int bit) {
|
|||||||
if(bits_received_ == 1) update_clocking_observer();
|
if(bits_received_ == 1) update_clocking_observer();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 | StatusNeedsRead;
|
||||||
|
if(interrupt_delegate_ && is_changing_state)
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
@ -65,6 +65,11 @@ class ACIA: public ClockingHint::Source, private Serial::Line::ReadDelegate {
|
|||||||
// ClockingHint::Source.
|
// ClockingHint::Source.
|
||||||
ClockingHint::Preference preferred_clocking() final;
|
ClockingHint::Preference preferred_clocking() final;
|
||||||
|
|
||||||
|
struct InterruptDelegate {
|
||||||
|
virtual void acia6850_did_change_interrupt_status(ACIA *acia) = 0;
|
||||||
|
};
|
||||||
|
void set_interrupt_delegate(InterruptDelegate *delegate);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int divider_ = 1;
|
int divider_ = 1;
|
||||||
enum class Parity {
|
enum class Parity {
|
||||||
@ -86,12 +91,20 @@ class ACIA: public ClockingHint::Source, private Serial::Line::ReadDelegate {
|
|||||||
bool receive_interrupt_enabled_ = false;
|
bool receive_interrupt_enabled_ = false;
|
||||||
bool transmit_interrupt_enabled_ = false;
|
bool transmit_interrupt_enabled_ = false;
|
||||||
|
|
||||||
bool interrupt_request_ = false;
|
|
||||||
|
|
||||||
HalfCycles transmit_clock_rate_;
|
HalfCycles transmit_clock_rate_;
|
||||||
HalfCycles receive_clock_rate_;
|
HalfCycles receive_clock_rate_;
|
||||||
|
|
||||||
bool serial_line_did_produce_bit(Serial::Line *line, int bit) final;
|
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);
|
||||||
|
InterruptDelegate *interrupt_delegate_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user