Synchronising the user buffers when the register pointer rolls over to zero is a property of reading them; hardware routes a write to the counters themselves. Doing it from the shared pointer increment meant a write transfer long enough to wrap overwrote the bytes the guest had just sent with the current time.
Move the refresh to the read path. Signed-off-by: Emmanuel Blot <[email protected]> --- hw/rtc/ds1338.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/hw/rtc/ds1338.c b/hw/rtc/ds1338.c index 79bcff4599..c5fc74e6ca 100644 --- a/hw/rtc/ds1338.c +++ b/hw/rtc/ds1338.c @@ -12,6 +12,8 @@ * Limitations: * - Writing the seconds register does not reset the internal countdown chain, * so the sub-second phase of the clock is not modelled. + * - The user registers are refreshed on a START and on a read that wraps the + * register pointer, but not on a STOP. * - 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. @@ -157,15 +159,7 @@ static void ds1338_inc_regptr(DS1338State *s) { DS1338Class *k = DS1338_GET_CLASS(s); - /* - * The register pointer wraps around after the last register; wraparound - * causes the current time/date to be retransferred into the secondary - * registers. - */ s->ptr = (s->ptr + 1) % k->num_regs; - if (!s->ptr) { - ds1338_capture_current_time(s); - } } static int ds1338_event(I2CSlave *i2c, enum i2c_event event) @@ -201,6 +195,10 @@ static uint8_t ds1338_recv(I2CSlave *i2c) trace_ds1338_recv(s->ptr, res); ds1338_inc_regptr(s); + if (!s->ptr) { + /* Read-only: a wrapping write must keep the bytes it just sent. */ + ds1338_capture_current_time(s); + } return res; } -- 2.50.1
