diff options
Diffstat (limited to 'src/devices/cpu/h8/h8_adc.cpp')
-rw-r--r-- | src/devices/cpu/h8/h8_adc.cpp | 501 |
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(); +} |