summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/h8/h8_adc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/h8/h8_adc.cpp')
-rw-r--r--src/devices/cpu/h8/h8_adc.cpp501
1 files changed, 501 insertions, 0 deletions
diff --git a/src/devices/cpu/h8/h8_adc.cpp b/src/devices/cpu/h8/h8_adc.cpp
new file mode 100644
index 00000000000..b1f02f83ca7
--- /dev/null
+++ b/src/devices/cpu/h8/h8_adc.cpp
@@ -0,0 +1,501 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+#include "emu.h"
+#include "h8_adc.h"
+
+const device_type H8_ADC_3337 = &device_creator<h8_adc_3337_device>;
+const device_type H8_ADC_3006 = &device_creator<h8_adc_3006_device>;
+const device_type H8_ADC_2245 = &device_creator<h8_adc_2245_device>;
+const device_type H8_ADC_2320 = &device_creator<h8_adc_2320_device>;
+const device_type H8_ADC_2357 = &device_creator<h8_adc_2357_device>;
+const device_type H8_ADC_2655 = &device_creator<h8_adc_2655_device>;
+
+h8_adc_device::h8_adc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ cpu(*this, DEVICE_SELF_OWNER)
+{
+ suspend_on_interrupt = false;
+ analog_power_control = false;
+}
+
+void h8_adc_device::set_info(const char *_intc_tag, int _intc_vector)
+{
+ intc_tag = _intc_tag;
+ intc_vector = _intc_vector;
+}
+
+READ8_MEMBER(h8_adc_device::addr8_r)
+{
+ logerror("%s: addr8_r %d %03x\n", tag(), offset, addr[offset >> 1]);
+ return offset & 1 ? addr[offset >> 1] >> 2 : addr[offset >> 1] << 6;
+}
+
+READ16_MEMBER(h8_adc_device::addr16_r)
+{
+ logerror("%s: addr16_r %d %03x\n", tag(), offset, addr[offset]);
+ return addr[offset];
+}
+
+READ8_MEMBER(h8_adc_device::adcsr_r)
+{
+ logerror("%s: adcsr_r %02x\n", tag(), adcsr);
+ return adcsr;
+}
+
+READ8_MEMBER(h8_adc_device::adcr_r)
+{
+ logerror("%s: adcr_r %02x\n", tag(), adcr);
+ return adcr;
+}
+
+WRITE8_MEMBER(h8_adc_device::adcsr_w)
+{
+ logerror("%s: adcsr_w %02x\n", tag(), data);
+ UINT8 prev = adcsr;
+ adcsr = (data & 0x7f) | (adcsr & data & F_ADF);
+ mode_update();
+ if((prev & F_ADF) && !(adcsr & F_ADF)) {
+ if(mode & HALTED) {
+ mode &= ~HALTED;
+ if(!(adcsr & F_ADST)) {
+ sampling();
+ conversion_wait(false, false);
+ } else
+ done();
+ }
+ }
+
+ if(!(prev & F_ADST) && (adcsr & F_ADST))
+ start_conversion();
+}
+
+WRITE8_MEMBER(h8_adc_device::adcr_w)
+{
+ logerror("%s: adcr_w %02x\n", tag(), data);
+ adcr = data;
+ mode_update();
+}
+
+WRITE_LINE_MEMBER(h8_adc_device::adtrg_w)
+{
+ if(state != adtrg) {
+ adtrg = state;
+ if(!adtrg && (trigger & T_EXT) && !(adcsr & F_ADST)) {
+ adcsr |= F_ADST;
+ start_conversion();
+ }
+ }
+}
+
+void h8_adc_device::set_suspend(bool suspend)
+{
+}
+
+void h8_adc_device::device_start()
+{
+ io = &cpu->space(AS_IO);
+ intc = siblingdevice<h8_intc_device>(intc_tag);
+ save_item(NAME(addr));
+ save_item(NAME(buf));
+ save_item(NAME(adcsr));
+ save_item(NAME(adcr));
+ save_item(NAME(trigger));
+ save_item(NAME(start_mode));
+ save_item(NAME(start_channel));
+ save_item(NAME(end_channel));
+ save_item(NAME(start_count));
+ save_item(NAME(suspend_on_interrupt));
+ save_item(NAME(analog_power_control));
+ save_item(NAME(mode));
+ save_item(NAME(channel));
+ save_item(NAME(count));
+ save_item(NAME(analog_powered));
+ save_item(NAME(next_event));
+ save_item(NAME(adtrg));
+}
+
+void h8_adc_device::device_reset()
+{
+ memset(addr, 0, sizeof(addr));
+ memset(buf, 0, sizeof(buf));
+ adcsr = adcr = 0;
+ trigger = T_SOFT;
+ start_mode = IDLE;
+ start_channel = end_channel = 0;
+ start_count = 1;
+ mode = IDLE;
+ channel = 0;
+ count = 0;
+ next_event = 0;
+ mode_update();
+ analog_powered = !analog_power_control;
+ adtrg = true;
+}
+
+void h8_adc_device::done()
+{
+ mode = IDLE;
+ adcsr &= ~F_ADST;
+ if(analog_power_control)
+ analog_powered = false;
+}
+
+UINT64 h8_adc_device::internal_update(UINT64 current_time)
+{
+ if(next_event && next_event <= current_time) {
+ next_event = 0;
+ timeout(current_time);
+ }
+ return next_event;
+}
+
+void h8_adc_device::conversion_wait(bool first, bool poweron, UINT64 current_time)
+{
+ if(current_time)
+ next_event = current_time + conversion_time(first, poweron);
+ else {
+ next_event = cpu->total_cycles() + conversion_time(first, poweron);
+ cpu->internal_update();
+ }
+}
+
+void h8_adc_device::buffer_value(int port, int buffer)
+{
+ buf[buffer] = io->read_word(2*(h8_device::ADC_0 + port));
+ logerror("%s: adc buffer %d -> %d:%03x\n", tag(), port, buffer, buf[buffer]);
+}
+
+void h8_adc_device::commit_value(int reg, int buffer)
+{
+ reg &= register_mask;
+ logerror("%s: adc commit %d -> %d:%03x\n", tag(), buffer, reg, buf[buffer]);
+ addr[reg] = buf[buffer];
+}
+
+void h8_adc_device::sampling()
+{
+ if(mode & COUNTED)
+ channel = get_channel_index(start_count - count);
+ if(mode & DUAL) {
+ buffer_value(channel, 0);
+ buffer_value(channel+1, 1);
+ } else
+ buffer_value(channel);
+}
+
+void h8_adc_device::start_conversion()
+{
+ mode = start_mode;
+ channel = start_channel;
+ count = start_count;
+ sampling();
+ conversion_wait(true, !analog_powered);
+ analog_powered = true;
+}
+
+void h8_adc_device::timeout(UINT64 current_time)
+{
+ if(mode & BUFFER) {
+ do_buffering((mode & DUAL) && (channel & 1));
+ if((mode & DUAL) && !(channel & 1)) {
+ channel++;
+ conversion_wait(false, false, current_time);
+ return;
+ }
+ } else {
+ if(mode & DUAL) {
+ if(channel & 1)
+ commit_value(channel, 1);
+ else {
+ commit_value(channel, 0);
+ channel++;
+ conversion_wait(false, false, current_time);
+ return;
+ }
+ } else
+ commit_value(channel);
+ }
+
+ if(mode & ROTATE) {
+ if(channel != end_channel) {
+ channel++;
+ sampling();
+ conversion_wait(false, false, current_time);
+ return;
+ }
+ channel = start_channel;
+ }
+
+ if(mode & COUNTED) {
+ count--;
+ if(count) {
+ sampling();
+ conversion_wait(false, false, current_time);
+ return;
+ }
+ }
+
+ adcsr |= F_ADF;
+ if(adcsr & F_ADIE)
+ intc->internal_interrupt(intc_vector);
+
+ if(mode & REPEAT) {
+ if(suspend_on_interrupt && (adcsr & F_ADIE)) {
+ mode |= HALTED;
+ return;
+ }
+ channel = start_channel;
+ count = start_count;
+ sampling();
+ conversion_wait(false, false, current_time);
+ return;
+ }
+
+ done();
+}
+
+void h8_adc_device::do_buffering(int buffer)
+{
+ throw emu_fatalerror("%s: Buffering requested but unimplemented for this device\n", tag());
+}
+
+int h8_adc_device::get_channel_index(int count)
+{
+ throw emu_fatalerror("%s: Indexing requested but unimplemented for this device\n", tag());
+}
+
+
+h8_adc_3337_device::h8_adc_3337_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ h8_adc_device(mconfig, H8_ADC_3337, "H8 ADC 3337", tag, owner, clock, "h8_adc_3337", __FILE__)
+{
+ register_mask = 3;
+}
+
+int h8_adc_3337_device::conversion_time(bool first, bool poweron)
+{
+ int tm;
+ if(first)
+ tm = adcsr & 0x08 ? 134 : 266;
+ else
+ tm = adcsr & 0x08 ? 128 : 256;
+ return tm;
+}
+
+void h8_adc_3337_device::mode_update()
+{
+ trigger = adcr & 0x80 ? T_EXT : T_SOFT;
+
+ if(adcsr & 0x10) {
+ start_mode = ACTIVE | ROTATE;
+ start_channel = adcsr & 4;
+ end_channel = adcsr & 7;
+ } else {
+ start_mode = ACTIVE;
+ start_channel = end_channel = adcsr & 7;
+ }
+}
+
+
+h8_adc_3006_device::h8_adc_3006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ h8_adc_device(mconfig, H8_ADC_3006, "H8 ADC 3006", tag, owner, clock, "h8_adc_3006", __FILE__)
+{
+ register_mask = 3;
+}
+
+int h8_adc_3006_device::conversion_time(bool first, bool poweron)
+{
+ int tm;
+ if(first)
+ tm = adcsr & 0x08 ? 70 : 134;
+ else
+ tm = adcsr & 0x08 ? 66 : 128;
+ return tm;
+}
+
+void h8_adc_3006_device::mode_update()
+{
+ trigger = adcr & 0x80 ? T_EXT|T_TIMER : T_SOFT;
+
+ if(adcsr & 0x10) {
+ start_mode = ACTIVE | ROTATE;
+ start_channel = adcsr & 4;
+ end_channel = adcsr & 7;
+ } else {
+ start_mode = ACTIVE;
+ start_channel = end_channel = adcsr & 7;
+ }
+}
+
+
+h8_adc_2245_device::h8_adc_2245_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ h8_adc_device(mconfig, H8_ADC_2245, "H8 ADC 2245", tag, owner, clock, "h8_adc_2245", __FILE__)
+{
+ register_mask = 3;
+}
+
+int h8_adc_2245_device::conversion_time(bool first, bool poweron)
+{
+ int tm;
+ if(first)
+ tm = adcsr & 0x08 ? 134 : 266;
+ else
+ tm = adcsr & 0x08 ? 128 : 256;
+ return tm;
+}
+
+void h8_adc_2245_device::mode_update()
+{
+ trigger = 1 << ((adcr >> 6) & 3);
+
+ if(adcsr & 0x10) {
+ start_mode = ACTIVE | ROTATE;
+ start_channel = 0;
+ end_channel = adcsr & 3;
+ } else {
+ start_mode = ACTIVE;
+ start_channel = end_channel = adcsr & 3;
+ }
+}
+
+
+h8_adc_2320_device::h8_adc_2320_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ h8_adc_device(mconfig, H8_ADC_2320, "H8 ADC 2320", tag, owner, clock, "h8_adc_2320", __FILE__)
+{
+ register_mask = 3;
+}
+
+int h8_adc_2320_device::conversion_time(bool first, bool poweron)
+{
+ int tm;
+ if(first)
+ if(adcr & 0x04)
+ tm = adcsr & 0x08 ? 134 : 266;
+ else
+ tm = adcsr & 0x08 ? 68 : 580;
+ else
+ if(adcr & 0x04)
+ tm = adcsr & 0x08 ? 128 : 256;
+ else
+ tm = adcsr & 0x08 ? 64 : 512;
+ return tm;
+}
+
+void h8_adc_2320_device::mode_update()
+{
+ trigger = 1 << ((adcr >> 6) & 3);
+
+ if(adcsr & 0x10) {
+ start_mode = ACTIVE | ROTATE;
+ start_channel = adcsr & 4;
+ end_channel = adcsr & 7;
+ } else {
+ start_mode = ACTIVE;
+ start_channel = end_channel = adcsr & 7;
+ }
+}
+
+
+h8_adc_2357_device::h8_adc_2357_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ h8_adc_device(mconfig, H8_ADC_2357, "H8 ADC 2357", tag, owner, clock, "h8_adc_2357", __FILE__)
+{
+ register_mask = 3;
+}
+
+int h8_adc_2357_device::conversion_time(bool first, bool poweron)
+{
+ int tm;
+ if(first)
+ tm = adcsr & 0x08 ? 134 : 266;
+ else
+ tm = adcsr & 0x08 ? 128 : 256;
+ return tm;
+}
+
+void h8_adc_2357_device::mode_update()
+{
+ trigger = 1 << ((adcr >> 6) & 3);
+
+ if(adcsr & 0x10) {
+ start_mode = ACTIVE | ROTATE;
+ start_channel = adcsr & 4;
+ end_channel = adcsr & 7;
+ } else {
+ start_mode = ACTIVE;
+ start_channel = end_channel = adcsr & 7;
+ }
+}
+
+
+h8_adc_2655_device::h8_adc_2655_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ h8_adc_device(mconfig, H8_ADC_2655, "H8 ADC 2655", tag, owner, clock, "h8_adc_2655", __FILE__)
+{
+ suspend_on_interrupt = true;
+ register_mask = 7;
+}
+
+int h8_adc_2655_device::conversion_time(bool first, bool poweron)
+{
+ int tm = adcsr & 0x10 ? 44 : 24;
+ if(first)
+ tm += adcsr & 0x10 ? 20 : 10;
+ if(poweron)
+ tm += 200;
+ return tm;
+}
+
+void h8_adc_2655_device::mode_update()
+{
+ trigger = 1 << ((adcr >> 4) & 3);
+ analog_power_control = !(adcr & 0x40);
+
+ mode = ACTIVE | (adcr & 0x08 ? REPEAT : 0);
+
+ if(adcsr & 0x03) {
+ mode |= BUFFER;
+
+ }
+
+ if(adcsr & 0x08) {
+ mode |= ROTATE;
+ start_channel = 0;
+ if(adcr & 0x04) {
+ mode |= DUAL;
+ end_channel = (adcsr & 6)+1;
+ } else
+ end_channel = adcsr & 7;
+ } else
+ start_channel = end_channel = adcsr & 7;
+
+}
+
+void h8_adc_2655_device::do_buffering(int buffer)
+{
+ if((mode & COUNTED) && channel >= 2) {
+ commit_value(channel, buffer);
+ return;
+ }
+ switch(adcsr & 3) {
+ case 0:
+ commit_value(channel, buffer);
+ break;
+ case 1:
+ addr[1] = addr[0];
+ commit_value(0, buffer);
+ break;
+ case 2:
+ addr[2+buffer] = addr[buffer];
+ commit_value(buffer, buffer);
+ break;
+ case 3:
+ addr[3] = addr[2];
+ addr[2] = addr[1];
+ addr[1] = addr[0];
+ commit_value(0, buffer);
+ break;
+ }
+}
+
+int h8_adc_2655_device::get_channel_index(int count)
+{
+ abort();
+}