Bit 7 of the seconds register disables the oscillator, and the guest is expected to clear it before trusting the time. The bit was masked away on every write, so it always read back zero and the clock never stopped.
The reset value stays clear rather than set as on real hardware, keeping the model's convention that the clock comes up running and synchronised with the host. Signed-off-by: Emmanuel Blot <[email protected]> --- hw/rtc/ds1338.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/hw/rtc/ds1338.c b/hw/rtc/ds1338.c index 862e03bd32..79bcff4599 100644 --- a/hw/rtc/ds1338.c +++ b/hw/rtc/ds1338.c @@ -14,6 +14,7 @@ * so the sub-second phase of the clock is not modelled. * - Leap years follow the Gregorian rule, where the parts stop at 2100: they * derive the leap year from the two-digit year alone. + * - The model comes up with the clock running; real hardware comes up halted. */ #include "qemu/osdep.h" @@ -53,6 +54,7 @@ struct DS1338State { uint8_t nvram[NVRAM_SIZE]; int32_t ptr; bool addr_byte; + bool osc_stopped; /* oscillator halted: time is frozen */ }; struct DS1338Class { @@ -64,11 +66,12 @@ struct DS1338Class { uint8_t osf_addr; /* register holding the OSF flag */ uint8_t osf_mask; /* OSF bit within osf_addr */ uint8_t ctrl_reset; /* control-register power-on value */ + uint8_t ch_mask; /* Clock-halt bit in the seconds reg */ }; static const VMStateDescription vmstate_ds1338 = { .name = "ds1338", - .version_id = 2, + .version_id = 3, .minimum_version_id = 1, .fields = (const VMStateField[]) { VMSTATE_I2C_SLAVE(parent_obj, DS1338State), @@ -77,6 +80,7 @@ static const VMStateDescription vmstate_ds1338 = { VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE), VMSTATE_INT32(ptr, DS1338State), VMSTATE_BOOL(addr_byte, DS1338State), + VMSTATE_BOOL_V(osc_stopped, DS1338State, 3), VMSTATE_END_OF_LIST() } }; @@ -122,6 +126,11 @@ static void ds1338_capture_current_time(DS1338State *s) * which will be actually read by the data transfer operation. */ struct tm now; + + if (s->osc_stopped) { + return; + } + qemu_get_timedate(&now, s->offset); s->nvram[0] = to_bcd(now.tm_sec); s->nvram[1] = to_bcd(now.tm_min); @@ -213,15 +222,30 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data) * is then rebuilt from it as a whole: a transfer that programs the * date before the month it belongs to must not be normalised away * against the month still held from the previous date. - * - * TODO: Implement CH (stop) bit. */ static const uint8_t valid[7] = { 0x7f, 0x7f, 0x7f, 0x07, 0x3f, 0x1f, 0xff }; + uint8_t mask = valid[s->ptr]; + bool halt = s->osc_stopped; - s->nvram[s->ptr] = data & valid[s->ptr]; - ds1338_resync_from_regs(s); + if (s->ptr == 0) { + mask |= k->ch_mask; + if (k->ch_mask) { + halt = data & k->ch_mask; + } + } + + if (halt && !s->osc_stopped) { + /* CH set: freeze the counters before the register is stored. */ + ds1338_capture_current_time(s); + s->nvram[k->osf_addr] |= k->osf_mask; + } + s->nvram[s->ptr] = data & mask; + s->osc_stopped = halt; + if (!halt) { + ds1338_resync_from_regs(s); + } } else { if (s->ptr == k->ctrl_addr) { /* Control register: reserved bits read back as zero. */ @@ -253,6 +277,7 @@ static void ds1338_reset_hold(Object *obj, ResetType type) s->nvram[k->ctrl_addr] = k->ctrl_reset; s->ptr = 0; s->addr_byte = false; + s->osc_stopped = false; } static void ds1338_class_init(ObjectClass *klass, const void *data) @@ -275,6 +300,7 @@ static void ds1338_class_init(ObjectClass *klass, const void *data) dsc->osf_addr = DS1338_CONTROL; dsc->osf_mask = CTRL_OSF; dsc->ctrl_reset = DS1338_CTRL_RESET; + dsc->ch_mask = SECONDS_CH; } static const TypeInfo ds1338_types[] = { -- 2.50.1
