1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-09-25 08:25:09 +00:00

Attmept full ADC implementation.

This commit is contained in:
Thomas Harte
2025-09-18 12:21:25 -04:00
parent 26b1ef247b
commit 4c49ffe3d1
3 changed files with 69 additions and 11 deletions

View File

@@ -10,22 +10,61 @@
using namespace NEC;
uPD7002::uPD7002(HalfCycles) {
uPD7002::uPD7002(const HalfCycles clock_rate) {
// Per the BBC AUG: "8 bit conversions typically take 4 ms to complete whereas 10 bit
// conversions typically take 10 ms to complete".
fast_period_ = clock_rate / 250;
slow_period_ = clock_rate / 100;
}
void uPD7002::run_for(HalfCycles) {
void uPD7002::run_for(const HalfCycles count) {
if(!conversion_time_remaining_) {
return;
}
if(count >= conversion_time_remaining_) {
conversion_time_remaining_ = HalfCycles(0);
interrupt_ = true;
result_ = uint16_t(inputs_[channel_] * 65535.0f) & (high_precision_ ? 0xfff0 : 0xff00);
if(delegate_) delegate_->did_change_interrupt_status(*this);
return;
}
conversion_time_remaining_ -= count;
}
bool uPD7002::interrupt() const {
return false;
return interrupt_;
}
void uPD7002::write(const uint16_t address, const uint8_t value) {
(void)address;
(void)value;
if(!address) {
channel_ = value & 3;
high_precision_ = value & 8;
conversion_time_remaining_ = high_precision_ ? slow_period_ : fast_period_;
return;
}
}
uint8_t uPD7002::read(const uint16_t address) {
(void)address;
return 0xff;
if(!address) {
return status();
}
if(address & 1) {
interrupt_ = false;
if(delegate_) delegate_->did_change_interrupt_status(*this);
return uint8_t(result_ >> 8);
} else {
return uint8_t(result_);
}
}
uint8_t uPD7002::status() const {
return
channel_ |
(high_precision_ ? 8 : 0) |
((result_ >> 10) & 0x30) |
(conversion_time_remaining_ > HalfCycles(0) ? 0x00 : 0x40) |
(interrupt_ ? 0x00 : 0x80);
}

View File

@@ -18,13 +18,28 @@ public:
bool interrupt() const;
struct Delegate {
virtual void did_change_interrupt_status(uPD7002 &);
virtual void did_change_interrupt_status(uPD7002 &) = 0;
};
void set_delegate(Delegate *);
void write(uint16_t address, uint8_t value);
uint8_t read(uint16_t address);
void set_input(int channel, float value);
private:
float inputs_[4]{};
uint16_t result_ = 0;
bool interrupt_ = false;
uint8_t channel_ = 0;
bool high_precision_ = false;
HalfCycles conversion_time_remaining_;
HalfCycles fast_period_, slow_period_;
uint8_t status() const;
Delegate *delegate_ = nullptr;
};
}

View File

@@ -440,7 +440,8 @@ class ConcreteMachine:
public MachineTypes::MappedKeyboardMachine,
public MachineTypes::ScanProducer,
public MachineTypes::TimedMachine,
public MOS::MOS6522::IRQDelegatePortHandler::Delegate
public MOS::MOS6522::IRQDelegatePortHandler::Delegate,
public NEC::uPD7002::Delegate
{
public:
ConcreteMachine(
@@ -615,10 +616,8 @@ public:
}
} else if(address >= 0xfec0 && address < 0xfee0) {
if(is_read(operation)) {
// Logger::info().append("ACIA read");
*value = adc_.read(address);
} else {
// Logger::info().append("ACIA write: %02x", *value);
adc_.write(address, *value);
}
}
@@ -698,6 +697,11 @@ private:
update_irq_line();
}
// MARK: - uPD7002::Delegate.
void did_change_interrupt_status(NEC::uPD7002 &) override {
update_irq_line();
}
// MARK: - Clock phase.
int phase_ = 0;