diff options
Diffstat (limited to 'src/devices/machine/bq4847.cpp')
-rw-r--r-- | src/devices/machine/bq4847.cpp | 502 |
1 files changed, 230 insertions, 272 deletions
diff --git a/src/devices/machine/bq4847.cpp b/src/devices/machine/bq4847.cpp index 7dd9031c814..d2618f03f53 100644 --- a/src/devices/machine/bq4847.cpp +++ b/src/devices/machine/bq4847.cpp @@ -21,16 +21,17 @@ #include "emu.h" #include "bq4847.h" -#define LOG_WARN (1U<<1) // Warnings -#define LOG_CLOCK (1U<<2) // Clock operation -#define LOG_REG (1U<<3) // Register write -#define LOG_WATCHDOG (1U<<4) // Watchdog -#define LOG_TRANSFER (1U<<5) // Transfer +#define LOG_WARN (1U << 1) // Warnings +#define LOG_CLOCK (1U << 2) // Clock operation +#define LOG_REG (1U << 3) // Register write +#define LOG_WATCHDOG (1U << 4) // Watchdog +#define LOG_TRANSFER (1U << 5) // Transfer -#define VERBOSE ( LOG_GENERAL | LOG_WARN ) +#define VERBOSE (LOG_GENERAL | LOG_WARN) #include "logmacro.h" // device type definition +DEFINE_DEVICE_TYPE(BQ4845, bq4845_device, "bq4845", "Benchmarq BQ4845 RTC") DEFINE_DEVICE_TYPE(BQ4847, bq4847_device, "bq4847", "Benchmarq BQ4847 RTC") enum @@ -55,60 +56,84 @@ enum enum { - FLAG_AIE = 0x08, - FLAG_PIE = 0x04, - FLAG_PWRIE = 0x02, - FLAG_ABE = 0x01, + INTERRUPT_AIE = 0x08, + INTERRUPT_PIE = 0x04, + INTERRUPT_PWRIE = 0x02, + INTERRUPT_ABE = 0x01, FLAG_AF = 0x08, FLAG_PF = 0x04, FLAG_PWRF = 0x02, FLAG_BVF = 0x01, - FLAG_UTI = 0x08, - FLAG_STOP = 0x04, - FLAG_24 = 0x02, - FLAG_DSE = 0x01 + CONTROL_UTI = 0x08, + CONTROL_STOP = 0x04, + CONTROL_24 = 0x02, + CONTROL_DSE = 0x01 }; //------------------------------------------------- // Constructors for basetype //------------------------------------------------- -bq4847_device::bq4847_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, BQ4847, tag, owner, clock), - device_nvram_interface(mconfig, *this), - device_rtc_interface(mconfig, *this), - m_interrupt_cb(*this), - m_wdout_cb(*this), - m_watchdog_active(false), - m_writing(false) +bq4847_device::bq4847_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock), + device_nvram_interface(mconfig, *this), + device_rtc_interface(mconfig, *this), + m_region(*this, DEVICE_SELF), + m_wdo_handler(*this), + m_int_handler(*this), + m_rst_handler(*this), + m_periodic_timer(nullptr), + m_watchdog_timer(nullptr), + m_wdo_state(1), + m_int_state(1), + m_rst_state(1), + m_wdi_state(-1), + m_writing(false) { } -/* - Inherited from device_rtc_interface. The date and time is given as integer - and must be converted to BCD. -*/ +bq4847_device::bq4847_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) + : bq4847_device(mconfig, BQ4847, tag, owner, clock) +{ +} + +bq4845_device::bq4845_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) + : bq4847_device(mconfig, BQ4845, tag, owner, clock) +{ +} + +// device_rtc_interface + void bq4847_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) { - m_intreg[reg_hours] = convert_to_bcd(hour); - m_intreg[reg_minutes] = convert_to_bcd(minute); - m_intreg[reg_seconds] = convert_to_bcd(second); - m_intreg[reg_year] = convert_to_bcd(year); - m_intreg[reg_month] = convert_to_bcd(month); - m_intreg[reg_date] = convert_to_bcd(day); - m_intreg[reg_days] = convert_to_bcd(day_of_week); + if ((m_register[reg_control] & CONTROL_STOP) != 0) + { + m_register[reg_hours] = ((m_register[reg_control] & CONTROL_24) != 0) ? convert_to_bcd(hour) : + (((hour % 24) >= 12) ? 0x80 : 0x00) | convert_to_bcd((hour % 12) ? (hour % 12) : 12); + m_register[reg_minutes] = convert_to_bcd(minute); + m_register[reg_seconds] = convert_to_bcd(second); + m_register[reg_year] = convert_to_bcd(year); + m_register[reg_month] = convert_to_bcd(month); + m_register[reg_date] = convert_to_bcd(day); + m_register[reg_days] = convert_to_bcd(day_of_week); + } + + // Clear the saved flags (TODO: check that flags set before power down, or during battery backup are lost) + m_register[reg_flags] = 0x00; + + // Interrupts must be re-enabled on power-up (TODO: check, datasheet does not explicitly say ABE & PIE are cleared) + m_register[reg_interrupts] = 0x00; + + // TODO: check if user buffer is battery backed + // TODO: What if UTI is set? + std::copy_n(m_register, std::size(m_register), m_userbuffer); + // What about the DSE flag? } bool bq4847_device::increment_bcd(uint8_t& bcdnumber, uint8_t limit, uint8_t min) { -/* if (!valid_bcd(bcdnumber, min, limit)) - { - bcdnumber = min; - return false; - } -*/ - if (bcdnumber>=limit) + if (bcdnumber >= limit) { bcdnumber = min; return true; @@ -118,7 +143,7 @@ bool bq4847_device::increment_bcd(uint8_t& bcdnumber, uint8_t limit, uint8_t min uint8_t dig0 = bcdnumber & 0x0f; uint8_t dig1 = bcdnumber & 0xf0; - if (dig0==9) + if (dig0 == 9) { bcdnumber = dig1 + 0x10; } @@ -127,16 +152,6 @@ bool bq4847_device::increment_bcd(uint8_t& bcdnumber, uint8_t limit, uint8_t min return false; } -// TODO: Remove; the real clock cannot verify BCD numbers. -bool bq4847_device::valid_bcd(uint8_t value, uint8_t min, uint8_t max) -{ - bool valid = ((value>=min) && (value<=max) && ((value&0x0f)<=9)); - if (!valid) LOGMASKED(LOG_WARN, "Invalid BCD number %02x\n", value); - return valid; -} - -// ---------------------------------------------------- - /* Update cycle, called every second The BQ RTCs use BCD representation @@ -144,7 +159,7 @@ bool bq4847_device::valid_bcd(uint8_t value, uint8_t min, uint8_t max) TODO: We may not be able to use the parent class advance methods, since we have to work with BCD (even with invalid values). Check this. */ -TIMER_CALLBACK_MEMBER(bq4847_device::rtc_clock_cb) +TIMER_CALLBACK_MEMBER(bq4847_device::update_callback) { // Just for debugging static const char* dow[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; @@ -154,43 +169,41 @@ TIMER_CALLBACK_MEMBER(bq4847_device::rtc_clock_cb) if (carry) { - carry = increment_bcd(m_intreg[reg_seconds], 0x59, 0); + carry = increment_bcd(m_register[reg_seconds], 0x59, 0); newsec = true; } if (carry) - carry = increment_bcd(m_intreg[reg_minutes], 0x59, 0); + carry = increment_bcd(m_register[reg_minutes], 0x59, 0); if (carry) - { carry = advance_hours_bcd(); - } if (carry) - { advance_days_bcd(); - } LOGMASKED(LOG_CLOCK, "%s 20%02x-%02x-%02x %02x:%02x:%02x\n", - dow[m_intreg[reg_days]-1], m_intreg[reg_year], m_intreg[reg_month], m_intreg[reg_date], - m_intreg[reg_hours], m_intreg[reg_minutes], m_intreg[reg_seconds]); + dow[m_register[reg_days] - 1], m_register[reg_year], m_register[reg_month], m_register[reg_date], + m_register[reg_hours], m_register[reg_minutes], m_register[reg_seconds]); - // Copy into memory registers if the UTI bit is reset if (newsec) { - if (!is_set(reg_control, FLAG_UTI)) + if ((m_register[reg_control] & CONTROL_UTI) == 0) { - // Copy values from internal registers to accessible registers - transfer_to_access(); + LOGMASKED(LOG_TRANSFER, "Transfer to external regs\n"); + for (int i = reg_seconds; i < reg_unused; i++) + { + if (is_clock_register(i)) m_userbuffer[i] = m_register[i]; + } } - if (check_match(reg_date, reg_alarmdate) && - check_match(reg_hours, reg_alarmhours) && - check_match(reg_minutes, reg_alarmminutes) && - check_match(reg_seconds, reg_alarmseconds)) + if (check_alarm(reg_date, reg_alarmdate) && + check_alarm(reg_hours, reg_alarmhours) && + check_alarm(reg_minutes, reg_alarmminutes) && + check_alarm(reg_seconds, reg_alarmseconds)) { - set_register(reg_flags, FLAG_AF, true); - m_interrupt_cb(intrq_r()); + m_userbuffer[reg_flags] |= FLAG_AF; + update_int(); } } } @@ -199,46 +212,45 @@ bool bq4847_device::advance_hours_bcd() { bool carry = false; // Handle DST - if (is_set(reg_control, FLAG_DSE) - && (m_intreg[reg_month]==4) && (m_intreg[reg_days]==0) && (m_intreg[reg_date] < 8) // first Sunday in April - && (m_intreg[reg_hours]==0x01)) - m_intreg[reg_hours] = 0x03; + if ((m_register[reg_control] & CONTROL_DSE) != 0 + && (m_register[reg_month] == 4) && (m_register[reg_days] == 0) && (m_register[reg_date] < 8) // first Sunday in April + && (m_register[reg_hours] == 0x01)) + m_register[reg_hours] = 0x03; else { // Increment hour unless the DSE bit is set and we are at 1:59 on the last Sunday in October - if (!is_set(reg_control, FLAG_DSE) - || (m_intreg[reg_month]!=10) || (m_intreg[reg_days]!=0) || (m_intreg[reg_date] <= 23) // last Sunday in October - || (m_intreg[reg_hours]!=0x01)) + if ((m_register[reg_control] & CONTROL_DSE) == 0 + || (m_register[reg_month] != 10) || (m_register[reg_days] != 0) || (m_register[reg_date] <= 23) // last Sunday in October + || (m_register[reg_hours] != 0x01)) { - if (is_set(reg_control, FLAG_24)) + if ((m_register[reg_control] & CONTROL_24) != 0) { // 24h: 0->1->...->23->0(+1) - increment_bcd(m_intreg[reg_hours], 0xff, 0); - if (m_intreg[reg_hours] == 0x24) + increment_bcd(m_register[reg_hours], 0xff, 0); + if (m_register[reg_hours] == 0x24) { - m_intreg[reg_hours] = 0; + m_register[reg_hours] = 0; carry = true; } } - else { // 12h: 12->1->2->...->11->12'->1'->...->11'->12(+1) - increment_bcd(m_intreg[reg_hours], 0xff, 0); - switch (m_intreg[reg_hours]) + increment_bcd(m_register[reg_hours], 0xff, 0); + switch (m_register[reg_hours]) { case 0x12: - m_intreg[reg_hours]=0x92; // 11:59 am -> 12:00 pm + m_register[reg_hours] = 0x92; // 11:59 am -> 12:00 pm break; case 0x93: - m_intreg[reg_hours]=0x81; // 12:59 pm -> 01:00 pm + m_register[reg_hours] = 0x81; // 12:59 pm -> 01:00 pm break; case 0x92: - m_intreg[reg_hours]=0x12; // 11:59 pm -> 12:00 am + m_register[reg_hours] = 0x12; // 11:59 pm -> 12:00 am carry = true; break; case 0x13: - m_intreg[reg_hours]=0x01; // 12:59 am -> 01:00 am + m_register[reg_hours] = 0x01; // 12:59 am -> 01:00 am break; } } @@ -258,64 +270,55 @@ void bq4847_device::advance_days_bcd() 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 }; - uint8_t month = bcd_to_integer(m_intreg[reg_month]); + uint8_t month = bcd_to_integer(m_register[reg_month]); if (month > 12) month = 12; - // if (!valid_bcd(month, 0x01, 0x12)) month = 1; - uint8_t days = days_in_month_table[month-1]; + uint8_t days = days_in_month_table[month - 1]; // Leap years are indeed handled (but the year is only 2-digit) - if ((month==2) && ((m_intreg[reg_year]%4)==0)) + if ((month == 2) && ((bcd_to_integer(m_register[reg_year]) % 4) == 0)) days = 0x29; - increment_bcd(m_intreg[reg_days], 7, 1); // Increment the day-of-week (without carry) - carry = increment_bcd(m_intreg[reg_date], days, 1); + increment_bcd(m_register[reg_days], 7, 1); // Increment the day-of-week (without carry) + carry = increment_bcd(m_register[reg_date], days, 1); if (carry) { - increment_bcd(m_intreg[reg_month], 0xff, 1); - if (m_intreg[reg_month] == 0x13) + increment_bcd(m_register[reg_month], 0xff, 1); + if (m_register[reg_month] == 0x13) { - m_intreg[reg_month] = 0x01; - increment_bcd(m_intreg[reg_year], 0xff, 0); + m_register[reg_month] = 0x01; + increment_bcd(m_register[reg_year], 0xff, 0); } } } -bool bq4847_device::check_match(int now, int alarm) +bool bq4847_device::check_alarm(int now, int alarm) { - // The ignore feature is active once the alarm has set in - // Will lead to a periodic alarm - bool ignore = (is_set(m_reg[alarm], 0x80) && is_set(m_reg[alarm], 0x40)) && is_set(reg_flags, FLAG_AF); - return ignore || (m_intreg[now] == (m_reg[alarm] & 0x3f)); + return (m_register[alarm] & 0xc0) == 0xc0 || (m_register[alarm] == m_register[now]); } -// ========================================================= - -/* - Read from registers -*/ uint8_t bq4847_device::read(offs_t address) { int regnum = address & 0x0f; - uint8_t value = m_reg[regnum]; + uint8_t value = m_userbuffer[regnum]; if (regnum == reg_flags) { - set_register(reg_flags, 0xff, false); - m_interrupt_cb(intrq_r()); + value &= 0x7f; + m_userbuffer[reg_flags] = 0x00; + update_int(); } - else - if (regnum == reg_unused) value = 0; // Reg 15 is locked to 0 in BQ4847 + else if (regnum >= reg_interrupts && regnum <= reg_control) + value &= 0xf; + else if (regnum == reg_unused) + value = 0; // Reg 15 is locked to 0 in BQ4847 LOGMASKED(LOG_REG, "Reg %d -> %02x\n", regnum, value); return value; } -/* - Write to the registers -*/ void bq4847_device::write(offs_t address, uint8_t data) { int regnum = address & 0x0f; @@ -328,226 +331,181 @@ void bq4847_device::write(offs_t address, uint8_t data) return; } - bool uti_set = is_set(reg_control, FLAG_UTI); // Get it before we change the flag + bool uti_set = (m_register[reg_control] & CONTROL_UTI) != 0; - m_reg[regnum] = data; + m_userbuffer[regnum] = data; + + // If inhibit is not set, any write to the time/date registers + // is immediately set + if (uti_set && is_clock_register(regnum)) + m_writing = true; + else + m_register[regnum] = m_userbuffer[regnum]; if (regnum == reg_rates) { - set_watchdog_timer(true); + set_watchdog_timer(); set_periodic_timer(); } - else + else if (regnum == reg_control) { - if (regnum == reg_control) - { - LOGMASKED(LOG_TRANSFER, "Update transfer %s\n", ((data & FLAG_UTI)!=0)? "inhibit" : "enable"); - - // After we have written to the registers, transfer to the internal regs - if (uti_set && ((data & FLAG_UTI)==0) && m_writing) - { - LOGMASKED(LOG_TRANSFER, "Transfer to internal regs\n"); - for (int i=reg_seconds; i < reg_unused; i++) - { - if (is_internal_register(i)) m_intreg[i] = m_reg[i]; - } - // The real device does not auto-convert hours according to AM/PM - } + bool uti_set_now = (m_register[reg_control] & CONTROL_UTI) != 0; + LOGMASKED(LOG_TRANSFER, "Update transfer %s\n", uti_set_now ? "inhibit" : "enable"); - // We ignore the STOP* flag, since it only covers behaviour on power-off - // We ignore the 24h/12h flag here; it requires reloading the registers anyway - // The DSE flag will have effect on update - } - else + // After we have written to the registers, transfer to the internal regs + if (uti_set && !uti_set_now && m_writing) { - m_writing = true; - // If inhibit is not set, any write to the time/date registers - // is immediately set - if (!uti_set && is_internal_register(regnum)) + LOGMASKED(LOG_TRANSFER, "Transfer to internal regs\n"); + for (int i = reg_seconds; i < reg_unused; i++) { - m_intreg[regnum] = m_reg[regnum]; + if (is_clock_register(i)) m_register[i] = m_userbuffer[i]; } + + m_writing = false; } } } -bool bq4847_device::is_internal_register(int regnum) +bool bq4847_device::is_clock_register(int regnum) { return (regnum == reg_seconds || regnum == reg_minutes || regnum == reg_hours || - regnum == reg_date || regnum == reg_days || regnum == reg_month - || regnum == reg_year); + regnum == reg_date || regnum == reg_days || regnum == reg_month + || regnum == reg_year); } -void bq4847_device::set_register(int number, uint8_t bits, bool set) +void bq4847_device::set_periodic_timer() { - if (set) - m_reg[number] |= bits; - else - m_reg[number] &= ~bits; -} + uint8_t rs = m_register[reg_rates] & 0x0f; + attotime period = rs ? clocks_to_attotime(1 << (rs - 1)) : attotime::never; -bool bq4847_device::is_set(int number, uint8_t flag) -{ - return (m_reg[number] & flag)!=0; + if (m_periodic_timer) + m_periodic_timer->adjust(period, 0, period); } -void bq4847_device::transfer_to_access() +void bq4847_device::set_watchdog_timer(int rst_state) { - LOGMASKED(LOG_TRANSFER, "Transfer to external regs\n"); - for (int i=reg_seconds; i < reg_unused; i++) + if (m_rst_state == rst_state) { - if (is_internal_register(i)) m_reg[i] = m_intreg[i]; + int wd = (m_register[reg_rates] & 0x70) >> 4; + u32 t = (wd == 7) ? 16384 : (wd == 0) ? 8192 : 64 << wd; + if (m_rst_state) t *= 6; + attotime timeout = m_wdi_state >= 0 ? clocks_to_attotime(t) : attotime::never; + + if (m_watchdog_timer) + m_watchdog_timer->adjust(timeout); } - // Clear the flag - m_writing = false; } -void bq4847_device::set_periodic_timer() +void bq4847_device::set_wdo(int state) { - uint8_t rateval = m_reg[reg_rates] & 0x0f; - int rate = 1<<(16-rateval); - - if (rateval == 0) - m_periodic_timer->reset(); - else - m_periodic_timer->adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate)); + if (m_wdo_state != state) + { + m_wdo_state = state; + m_wdo_handler(m_wdo_state); + } } -void bq4847_device::set_watchdog_timer(bool on) +void bq4847_device::write_wdi(int state) { - int val = (m_reg[reg_rates] & 0x70)>>4; - - // val = 0 -> 1.5 sec - // val = 1 -> 3/128 sec - // val = 2 -> 3/64 sec - // ... - // val = 6 -> 3/4 sec - // val = 7 -> 3 sec - - s64 time = 250000000L; // 250 ms - if (val > 0) + if (m_wdi_state != state) { - time <<= 1; - if (val < 7) - time = time / (4<<(6-val)); - } - - if (on) time *= 6; // delay to on is 6 times the delay to off + m_wdi_state = state; - if (m_watchdog_active) - m_watchdog_timer->adjust(attotime::from_nsec(time)); // single shot + set_wdo(1); + set_watchdog_timer(); + } } -void bq4847_device::set_watchdog_active(bool active) +TIMER_CALLBACK_MEMBER(bq4847_device::periodic_callback) { - m_watchdog_active = active; + m_userbuffer[reg_flags] |= FLAG_PF; + update_int(); } -void bq4847_device::retrigger_watchdog() +TIMER_CALLBACK_MEMBER(bq4847_device::watchdog_callback) { - m_wdout_cb(CLEAR_LINE); - m_watchdog_asserted = false; - set_watchdog_timer(true); -} + m_rst_state = !m_rst_state; + set_watchdog_timer(m_rst_state); // force timer update during reset -/* - Periodic cycle (called at defined intervals) -*/ -TIMER_CALLBACK_MEMBER(bq4847_device::rtc_periodic_cb) -{ - set_register(reg_flags, FLAG_PF, true); - if (intrq_r()) - m_interrupt_cb(ASSERT_LINE); + m_rst_handler(m_rst_state); + + if (!m_rst_state) + set_wdo(0); + + LOGMASKED(LOG_WATCHDOG, "wdo %s rst %s\n", !m_wdo_state ? "asserted" : "cleared", !m_rst_state ? "asserted" : "cleared"); } -/* - Watchdog callback (BQ4847) -*/ -TIMER_CALLBACK_MEMBER(bq4847_device::rtc_watchdog_cb) +void bq4847_device::update_int() { - if (m_watchdog_active) + // TODO: check what happens if reg_interrupts is changed after the flag is set. + int int_state = !(m_register[reg_interrupts] & m_userbuffer[reg_flags] & (FLAG_AF | FLAG_PF | FLAG_PWRF)); + if (m_int_state != int_state) { - m_wdout_cb(m_watchdog_asserted? CLEAR_LINE : ASSERT_LINE); - set_watchdog_timer(!m_watchdog_asserted); - m_watchdog_asserted = !m_watchdog_asserted; - LOGMASKED(LOG_WATCHDOG, "Watchdog %s\n", m_watchdog_asserted? "asserted" : "cleared"); + m_int_state = int_state; + m_int_handler(m_int_state); } } -READ_LINE_MEMBER(bq4847_device::intrq_r) -{ - bool alarm = is_set(reg_interrupts, FLAG_AIE) && is_set(reg_flags, FLAG_AF); - bool period = is_set(reg_interrupts, FLAG_PIE) && is_set(reg_flags, FLAG_PF); +// device_t - // We ignore interrupts from power fail or battery low - return (alarm || period)? ASSERT_LINE : CLEAR_LINE; +void bq4847_device::device_start() +{ + m_update_timer = timer_alloc(FUNC(bq4847_device::update_callback), this); + m_periodic_timer = timer_alloc(FUNC(bq4847_device::periodic_callback), this); + m_watchdog_timer = timer_alloc(FUNC(bq4847_device::watchdog_callback), this); + + m_wdo_handler(m_wdo_state); + m_int_handler(m_int_state); + m_rst_handler(m_rst_state); + + save_pointer(NAME(m_userbuffer), 16); + save_pointer(NAME(m_register), 16); + save_item(NAME(m_wdo_state)); + save_item(NAME(m_int_state)); + save_item(NAME(m_rst_state)); + save_item(NAME(m_wdi_state)); + save_item(NAME(m_writing)); } -void bq4847_device::connect_osc(bool conn) +void bq4847_device::device_reset() { - if (conn) - { - // The internal update cycle is 1 sec - m_clock_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1)); - set_periodic_timer(); - } - else - { - // Turn off completely - m_clock_timer->reset(); - m_watchdog_timer->reset(); - m_periodic_timer->reset(); - } + device_clock_changed(); } -void bq4847_device::device_start() +void bq4847_device::device_clock_changed() { - m_clock_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(bq4847_device::rtc_clock_cb), this)); - - // Periodic timer - m_periodic_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(bq4847_device::rtc_periodic_cb), this)); - - // Watchdog timer - m_watchdog_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(bq4847_device::rtc_watchdog_cb), this)); - - // Interrupt line - m_interrupt_cb.resolve_safe(); - - // Watchdog output - m_wdout_cb.resolve_safe(); - - // Interrupt enables are cleared on powerup - set_register(reg_interrupts, 0xff, false); - - // State save - save_pointer(NAME(m_reg), 16); - save_pointer(NAME(m_intreg), 16); - - // Start clock - connect_osc(true); + m_update_timer->adjust(clocks_to_attotime(32768), 0, clocks_to_attotime(32768)); + set_watchdog_timer(); + set_periodic_timer(); } -// ---------------------------------------------------- +// device_nvram_interface void bq4847_device::nvram_default() { - std::fill_n(m_reg, 16, 0); -} + if (m_region.found()) + { + if (m_region->bytes() != std::size(m_register)) + fatalerror("%s incorrect region size", tag()); -void bq4847_device::nvram_read(emu_file &file) -{ - file.read(m_reg, 16); - transfer_to_access(); + std::copy_n(m_region->base(), std::size(m_register), m_register); + } + else + { + std::fill_n(m_register, std::size(m_register), 0); - // Clear the saved flags - set_register(reg_flags, 0xff, false); + m_register[reg_control] = CONTROL_STOP | CONTROL_24; + } +} - // Interrupts must be re-enabled on power-up - set_register(reg_interrupts, 0xff, false); +bool bq4847_device::nvram_read(util::read_stream& file) +{ + auto const [err, actual] = util::read(file, m_register, std::size(m_register)); + return !err && (actual == std::size(m_register)); } -void bq4847_device::nvram_write(emu_file &file) +bool bq4847_device::nvram_write(util::write_stream& file) { - transfer_to_access(); - file.write(m_reg, 16); + auto const [err, actual] = util::write(file, m_register, std::size(m_register)); + return !err; } |