Skip to contentSkip to conversation

Generalize Dallas/Maxim I2C RTC devices v3

PATCH In review Michael Davidsaver 3 participants 31 messages Jul 5, 2018 – Jul 17, 2018 1 message not in the archive

lore
Share & tools
lore
#0 lore raw

cover Generalize Dallas/Maxim I2C RTC devices v3

This series generalizes the ds1338 model to also support the ds1375. As previously, only the time of day registers are modeled. This series (v3) is a minor iteration on the previous v2.

No changes were made to the unittests.

Summary of changes by patch name in response to comments by Peter Maydell.

= timer: ds1338 use registerfields.h

Changed as requested to be more direct translation.

= timer: ds1338 persist 12-hour mode selection

Quoted 3 lines · Peter Maydell

The code change here looks like a reasonable no-behaviour-change simplification of the code, but it doesn't match up with the description in the commit message ?

While it isn't clear from the diff, the condtional involved has 3 arms, only two of these were updating 's->nvram[]'. The arm handling control register writes is the one which didn't. So attempts to set the 12 hour mode bit were ignored, and subsequent reads always returned 24 hour time.

So this is a behaviour change, and a minor bug fix.

= timer: ds1338 clarify HOUR handling
= timer: ds1338 fix wday_offset handling

These two are combined as requested.

= timer: generalize ds1338

The change to CTRL register handling is split out
as a seperate patch "timer: ds1338 remove vestige of un-modeled OSF"

= timer: ds-rtc handle CENTURY bit

Changed as suggested.

Michael Davidsaver (14):
tests: more thorough tests of ds1338
timer: ds1338 use registerfields.h
timer: ds1338 persist 12-hour mode selection
timer: ds1338 clarify HOUR handling
timer: ds1338 change write handling and fix wday_offset handling
tests: ds-rtc test 12 hour mode
tests: ds-rtc test wday offset
timer: rename ds1338 -> dsrtc
timer: rename file ds1338.c -> ds-rtc.c
timer: ds1338 remove vestige of un-modeled OSF
timer: generalize ds1338
timer: ds-rtc handle CENTURY bit
timer: ds-rtc model ds1375
tests: drop ds1338-test

 default-configs/arm-softmmu.mak |   2 +-
 hw/timer/Makefile.objs          |   2 +-
 hw/timer/ds-rtc.c               | 335 ++++++++++++++++++++++++++++++++++++++++
 hw/timer/ds1338.c               | 239 ----------------------------
 tests/Makefile.include          |   6 +-
 tests/ds-rtc-common.h           |  71 +++++++++
 tests/ds-rtc-current-test.c     |  66 ++++++++
 tests/ds-rtc-set-test.c         | 171 ++++++++++++++++++++
 tests/ds1338-test.c             |  75 ---------
 9 files changed, 649 insertions(+), 318 deletions(-)
 create mode 100644 hw/timer/ds-rtc.c
 delete mode 100644 hw/timer/ds1338.c
 create mode 100644 tests/ds-rtc-common.h
 create mode 100644 tests/ds-rtc-current-test.c
 create mode 100644 tests/ds-rtc-set-test.c
 delete mode 100644 tests/ds1338-test.c
Signature · 1 line
2.11.0
#1 lore raw

PATCH 1/14 tests: more thorough tests of ds1338

Test current time and set+get round trip.

Separate current time test from set/get tests to avoid test needing to impose order, or to have a magic handshaketo reset RTC to current time.

---
 tests/Makefile.include      |   4 ++
 tests/ds-rtc-common.h       |  67 +++++++++++++++++++++++++
 tests/ds-rtc-current-test.c |  59 ++++++++++++++++++++++
 tests/ds-rtc-set-test.c     | 117 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 247 insertions(+)
 create mode 100644 tests/ds-rtc-common.h
 create mode 100644 tests/ds-rtc-current-test.c
 create mode 100644 tests/ds-rtc-set-test.c
tests/Makefile.include +4 -0
index 8859e88ffb..6ce5a9ff4d 100644
@@ -378,6 +378,8 @@ check-qtest-sparc64-y += tests/boot-serial-test$(EXESUF)
 check-qtest-arm-y = tests/tmp105-test$(EXESUF)
 check-qtest-arm-y += tests/pca9552-test$(EXESUF)
 check-qtest-arm-y += tests/ds1338-test$(EXESUF)
+check-qtest-arm-y += tests/ds-rtc-current-test$(EXESUF)
+check-qtest-arm-y += tests/ds-rtc-set-test$(EXESUF)
 check-qtest-arm-y += tests/m25p80-test$(EXESUF)
 gcov-files-arm-y += hw/misc/tmp105.c
 check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
@@ -787,6 +789,8 @@ tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
 tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
 tests/pca9552-test$(EXESUF): tests/pca9552-test.o $(libqos-omap-obj-y)
 tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
+tests/ds-rtc-current-test$(EXESUF): tests/ds-rtc-current-test.o $(libqos-imx-obj-y)
+tests/ds-rtc-set-test$(EXESUF): tests/ds-rtc-set-test.o $(libqos-imx-obj-y)
 tests/m25p80-test$(EXESUF): tests/m25p80-test.o
 tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
 tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
tests/ds-rtc-common.h new file +67 -0

67 lines not on this page · raw message

tests/ds-rtc-current-test.c new file +59 -0

59 lines not on this page · raw message

tests/ds-rtc-set-test.c new file +117 -0

117 lines not on this page · raw message

Signature · 1 line
2.11.0
#2 lore raw

Re: [Qemu-devel] [PATCH 01/14] tests: more thorough tests of ds1338

Quoted 46 lines · Michael Davidsaver

Test current time and set+get round trip.

Separate current time test from set/get tests to avoid test needing to impose order, or to have a magic handshaketo reset RTC to current time.

---
 tests/Makefile.include      |   4 ++
 tests/ds-rtc-common.h       |  67 +++++++++++++++++++++++++
 tests/ds-rtc-current-test.c |  59 ++++++++++++++++++++++
 tests/ds-rtc-set-test.c     | 117 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 247 insertions(+)
 create mode 100644 tests/ds-rtc-common.h
 create mode 100644 tests/ds-rtc-current-test.c
 create mode 100644 tests/ds-rtc-set-test.c
tests/Makefile.include +4 -0
index 8859e88ffb..6ce5a9ff4d 100644
@@ -378,6 +378,8 @@ check-qtest-sparc64-y += tests/boot-serial-test$(EXESUF)
 check-qtest-arm-y = tests/tmp105-test$(EXESUF)
 check-qtest-arm-y += tests/pca9552-test$(EXESUF)
 check-qtest-arm-y += tests/ds1338-test$(EXESUF)
+check-qtest-arm-y += tests/ds-rtc-current-test$(EXESUF)
+check-qtest-arm-y += tests/ds-rtc-set-test$(EXESUF)
 check-qtest-arm-y += tests/m25p80-test$(EXESUF)
 gcov-files-arm-y += hw/misc/tmp105.c
 check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
@@ -787,6 +789,8 @@ tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
 tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
 tests/pca9552-test$(EXESUF): tests/pca9552-test.o $(libqos-omap-obj-y)
 tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
+tests/ds-rtc-current-test$(EXESUF): tests/ds-rtc-current-test.o $(libqos-imx-obj-y)
+tests/ds-rtc-set-test$(EXESUF): tests/ds-rtc-set-test.o $(libqos-imx-obj-y)
 tests/m25p80-test$(EXESUF): tests/m25p80-test.o
 tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
 tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
tests/ds-rtc-common.h new file +1 -0
new file mode 100644
index 0000000000..c8e6c2bc5b
@@ -0,0 +1,67 @@
+/* Common code for testing of Dallas/Maxim I2C bus RTC devices

tests/ds-rtc-common.h line 11

Quoted 10 lines
tests/ds-rtc-common.h new file +10 -0
+ *
+ * Copyright (c) 2018 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ */
+#ifndef DSRTCCOMMON_H
+#define DSRTCCOMMON_H
+
+#include "qemu/osdep.h"

Headers should never include osdep.h.

Quoted 62 lines
tests/ds-rtc-common.h new file +56 -0
+#include "qemu/cutils.h"
+#include "libqos/i2c.h"
+
+#define IMX25_I2C_0_BASE 0x43F80000
+#define DS1338_ADDR 0x68
+
+static I2CAdapter *i2c;
+static uint8_t addr;
+static bool use_century;
+
+/* input buffer must have at least 7 elements */
+static inline time_t rtc_parse(const uint8_t *buf)
+{
+    struct tm parts;
+
+    parts.tm_sec = from_bcd(buf[0]);
+    parts.tm_min = from_bcd(buf[1]);
+    if (buf[2] & 0x40) {
+        /* 12 hour */
+        /* HOUR register is 1-12. */
+        parts.tm_hour = from_bcd(buf[2] & 0x1f);
+        g_assert_cmpuint(parts.tm_hour, >=, 1);
+        g_assert_cmpuint(parts.tm_hour, <=, 12);
+        parts.tm_hour %= 12u; /* wrap 12 -> 0 */
+        if (buf[2] & 0x20) {
+            parts.tm_hour += 12u;
+        }
+    } else {
+        /* 24 hour */
+        parts.tm_hour = from_bcd(buf[2] & 0x3f);
+    }
+    parts.tm_wday = from_bcd(buf[3]);
+    parts.tm_mday = from_bcd(buf[4]);
+    parts.tm_mon =  from_bcd((buf[5] & 0x1f) - 1u);
+    parts.tm_year = from_bcd(buf[6]);
+    if (!use_century || (buf[5] & 0x80)) {
+        parts.tm_year += 100u;
+    }
+
+    return mktimegm(&parts);
+}
+
+static time_t rtc_gettime(void)
+{
+    uint8_t buf[7];
+
+    /* zero address pointer */
+    buf[0] = 0;
+    i2c_send(i2c, addr, buf, 1);
+    /* read back current time registers */
+    i2c_recv(i2c, addr, buf, 7);
+
+    return rtc_parse(buf);
+}
+
+#endif /* DSRTCCOMMON_H */
tests/ds-rtc-current-test.c new file +0 -0
new file mode 100644
index 0000000000..6acbbed9a6

tests/ds-rtc-current-test.c line 8

Quoted 8 lines
tests/ds-rtc-current-test.c new file +8 -0
@@ -0,0 +1,59 @@
+/* Testing of Dallas/Maxim I2C bus RTC devices
+ *
+ * Copyright (c) 2018 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ */
+#include <stdio.h>

This is included for you by osdep.h.

Quoted 26 lines
tests/ds-rtc-current-test.c new file +26 -0
+
+#include "qemu/osdep.h"
+#include "qemu/bcd.h"
+#include "qemu/cutils.h"
+#include "libqtest.h"
+#include "libqos/libqos.h"
+#include "libqos/i2c.h"
+
+#include "ds-rtc-common.h"
+
+/* read back and compare with current system time */
+static
+void test_rtc_current(void)
+{
+    time_t expected, actual;
+    /* relax test to limit false positives when host may be overloaded.
+     * Allow larger delta when running "-m quick"
+     */
+    time_t max_delta = g_test_slow() ? 1 : 30;
+
+    actual = time(NULL);
+    /* new second may start here */
+    expected = rtc_gettime();
+    g_assert_cmpuint(expected, <=, actual + max_delta);
+    g_assert_cmpuint(expected, >=, actual);
+}

tests/ds-rtc-current-test.c line 44

Quoted 10 lines
tests/ds-rtc-current-test.c new file +10 -0
+
+int main(int argc, char *argv[])
+{
+    int ret;
+    const char *arch = qtest_get_arch();
+    QTestState *s = NULL;
+
+    g_test_init(&argc, &argv, NULL);
+
+    if (strcmp(arch, "arm") == 0) {

The makefile changes add this to check-qtest-arm-y, so why do we need this if() ?

tests/ds-rtc-set-test.c

Quoted 18 lines
tests/ds-rtc-current-test.c new file +15 -0
+        s = qtest_start("-machine imx25-pdk");
+        i2c = imx_i2c_create(s, IMX25_I2C_0_BASE);
+        addr = DS1338_ADDR;
+        use_century = false;
+
+    }
+
+    qtest_add_func("/ds-rtc-i2c/current", test_rtc_current);
+
+    ret = g_test_run();
+
+    qtest_end();
+
+    return ret;
+}
tests/ds-rtc-set-test.c new file +0 -0
new file mode 100644
index 0000000000..35e1a36281

Same comments as above apply to this file too.

thanks
-- PMM

#3 lore raw

PATCH 2/14 timer: ds1338 use registerfields.h

In reply to Michael Davidsaver

Use names for registers and bits except
for R_CTRL which will be dealt with later,
and isn't modeled anyway.

---
 hw/timer/ds1338.c | 80 +++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 54 insertions(+), 26 deletions(-)
hw/timer/ds1338.c +54 -26
index 3849b74a68..7298c5af43 100644
@@ -13,6 +13,7 @@
 #include "qemu/osdep.h"
 #include "qemu-common.h"
 #include "hw/i2c/i2c.h"
+#include "hw/registerfields.h"
 #include "qemu/bcd.h"
 
 /* Size of NVRAM including both the user-accessible area and the
@@ -20,15 +21,42 @@
  */
 #define NVRAM_SIZE 64
 
-/* Flags definitions */
-#define SECONDS_CH 0x80
-#define HOURS_12   0x40
-#define HOURS_PM   0x20
 #define CTRL_OSF   0x20
 
 #define TYPE_DS1338 "ds1338"
 #define DS1338(obj) OBJECT_CHECK(DS1338State, (obj), TYPE_DS1338)
 
+/* values stored in BCD */
+/* 00-59 */
+#define R_SEC   (0x0)
+/* 00-59 */
+#define R_MIN   (0x1)
+#define R_HOUR  (0x2)
+/* 1-7 */
+#define R_WDAY  (0x3)
+/* 0-31 */
+#define R_DATE  (0x4)
+#define R_MONTH (0x5)
+/* 0-99 */
+#define R_YEAR  (0x6)
+
+#define R_CTRL  (0x7)
+
+/* use 12 hour mode when set */
+FIELD(HOUR, SET12, 6, 1)
+/* 00-23 */
+FIELD(HOUR, HOUR24, 0, 6)
+/* PM when set */
+FIELD(HOUR, AMPM, 5, 1)
+/* 1-12 (not 0-11!) */
+FIELD(HOUR, HOUR12, 0, 5)
+
+/* 1-12 */
+FIELD(MONTH, MONTH, 0, 5)
+FIELD(MONTH, CENTURY, 7, 1)
+
+FIELD(CTRL, OSF, 5, 1)
+
 typedef struct DS1338State {
     I2CSlave parent_obj;
 
@@ -61,25 +89,25 @@ static void capture_current_time(DS1338State *s)
      */
     struct tm now;
     qemu_get_timedate(&now, s->offset);
-    s->nvram[0] = to_bcd(now.tm_sec);
-    s->nvram[1] = to_bcd(now.tm_min);
-    if (s->nvram[2] & HOURS_12) {
+    s->nvram[R_SEC] = to_bcd(now.tm_sec);
+    s->nvram[R_MIN] = to_bcd(now.tm_min);
+    if (ARRAY_FIELD_EX32(s->nvram, HOUR, SET12)) {
         int tmp = now.tm_hour;
         if (tmp % 12 == 0) {
             tmp += 12;
         }
         if (tmp <= 12) {
-            s->nvram[2] = HOURS_12 | to_bcd(tmp);
+            s->nvram[R_HOUR] = R_HOUR_SET12_MASK | to_bcd(tmp);
         } else {
-            s->nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
+            s->nvram[R_HOUR] = R_HOUR_SET12_MASK | R_HOUR_AMPM_MASK | to_bcd(tmp - 12);
         }
     } else {
-        s->nvram[2] = to_bcd(now.tm_hour);
+        s->nvram[R_HOUR] = to_bcd(now.tm_hour);
     }
-    s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
-    s->nvram[4] = to_bcd(now.tm_mday);
-    s->nvram[5] = to_bcd(now.tm_mon + 1);
-    s->nvram[6] = to_bcd(now.tm_year - 100);
+    s->nvram[R_WDAY] = (now.tm_wday + s->wday_offset) % 7 + 1;
+    s->nvram[R_DATE] = to_bcd(now.tm_mday);
+    s->nvram[R_MONTH] = to_bcd(now.tm_mon + 1);
+    s->nvram[R_YEAR] = to_bcd(now.tm_year - 100);
 }
 
 static void inc_regptr(DS1338State *s)
@@ -141,17 +169,17 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
         struct tm now;
         qemu_get_timedate(&now, s->offset);
         switch(s->ptr) {
-        case 0:
+        case R_SEC:
             /* TODO: Implement CH (stop) bit.  */
             now.tm_sec = from_bcd(data & 0x7f);
             break;
-        case 1:
+        case R_MIN:
             now.tm_min = from_bcd(data & 0x7f);
             break;
-        case 2:
-            if (data & HOURS_12) {
-                int tmp = from_bcd(data & (HOURS_PM - 1));
-                if (data & HOURS_PM) {
+        case R_HOUR:
+            if (FIELD_EX32(data, HOUR, SET12)) {
+                int tmp = from_bcd(FIELD_EX32(data, HOUR, HOUR12));
+                if (FIELD_EX32(data, HOUR, AMPM)) {
                     tmp += 12;
                 }
                 if (tmp % 12 == 0) {
@@ -159,10 +187,10 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
                 }
                 now.tm_hour = tmp;
             } else {
-                now.tm_hour = from_bcd(data & (HOURS_12 - 1));
+                now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR24));
             }
             break;
-        case 3:
+        case R_WDAY:
             {
                 /* The day field is supposed to contain a value in
                    the range 1-7. Otherwise behavior is undefined.
@@ -171,18 +199,18 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
                 s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
             }
             break;
-        case 4:
+        case R_DATE:
             now.tm_mday = from_bcd(data & 0x3f);
             break;
-        case 5:
+        case R_MONTH:
             now.tm_mon = from_bcd(data & 0x1f) - 1;
             break;
-        case 6:
+        case R_YEAR:
             now.tm_year = from_bcd(data) + 100;
             break;
         }
         s->offset = qemu_timedate_diff(&now);
-    } else if (s->ptr == 7) {
+    } else if (s->ptr == R_CTRL) {
         /* Control register. */
 
         /* Ensure bits 2, 3 and 6 will read back as zero. */
Signature · 1 line
2.11.0
Reviewed-by on v1 2/14
#4 lore raw

Re: [Qemu-devel] [PATCH 02/14] timer: ds1338 use registerfields.h

Quoted 6 lines · Michael Davidsaver

Use names for registers and bits except
for R_CTRL which will be dealt with later,
and isn't modeled anyway.

Quoted 159 lines
---
 hw/timer/ds1338.c | 80 +++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 54 insertions(+), 26 deletions(-)
hw/timer/ds1338.c +54 -26
index 3849b74a68..7298c5af43 100644
@@ -13,6 +13,7 @@
 #include "qemu/osdep.h"
 #include "qemu-common.h"
 #include "hw/i2c/i2c.h"
+#include "hw/registerfields.h"
 #include "qemu/bcd.h"
 
 /* Size of NVRAM including both the user-accessible area and the
@@ -20,15 +21,42 @@
  */
 #define NVRAM_SIZE 64
 
-/* Flags definitions */
-#define SECONDS_CH 0x80
-#define HOURS_12   0x40
-#define HOURS_PM   0x20
 #define CTRL_OSF   0x20
 
 #define TYPE_DS1338 "ds1338"
 #define DS1338(obj) OBJECT_CHECK(DS1338State, (obj), TYPE_DS1338)
 
+/* values stored in BCD */
+/* 00-59 */
+#define R_SEC   (0x0)
+/* 00-59 */
+#define R_MIN   (0x1)
+#define R_HOUR  (0x2)
+/* 1-7 */
+#define R_WDAY  (0x3)
+/* 0-31 */
+#define R_DATE  (0x4)
+#define R_MONTH (0x5)
+/* 0-99 */
+#define R_YEAR  (0x6)
+
+#define R_CTRL  (0x7)
+
+/* use 12 hour mode when set */
+FIELD(HOUR, SET12, 6, 1)
+/* 00-23 */
+FIELD(HOUR, HOUR24, 0, 6)
+/* PM when set */
+FIELD(HOUR, AMPM, 5, 1)
+/* 1-12 (not 0-11!) */
+FIELD(HOUR, HOUR12, 0, 5)
+
+/* 1-12 */
+FIELD(MONTH, MONTH, 0, 5)
+FIELD(MONTH, CENTURY, 7, 1)
+
+FIELD(CTRL, OSF, 5, 1)
+
 typedef struct DS1338State {
     I2CSlave parent_obj;
 
@@ -61,25 +89,25 @@ static void capture_current_time(DS1338State *s)
      */
     struct tm now;
     qemu_get_timedate(&now, s->offset);
-    s->nvram[0] = to_bcd(now.tm_sec);
-    s->nvram[1] = to_bcd(now.tm_min);
-    if (s->nvram[2] & HOURS_12) {
+    s->nvram[R_SEC] = to_bcd(now.tm_sec);
+    s->nvram[R_MIN] = to_bcd(now.tm_min);
+    if (ARRAY_FIELD_EX32(s->nvram, HOUR, SET12)) {
         int tmp = now.tm_hour;
         if (tmp % 12 == 0) {
             tmp += 12;
         }
         if (tmp <= 12) {
-            s->nvram[2] = HOURS_12 | to_bcd(tmp);
+            s->nvram[R_HOUR] = R_HOUR_SET12_MASK | to_bcd(tmp);
         } else {
-            s->nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
+            s->nvram[R_HOUR] = R_HOUR_SET12_MASK | R_HOUR_AMPM_MASK | to_bcd(tmp - 12);
         }
     } else {
-        s->nvram[2] = to_bcd(now.tm_hour);
+        s->nvram[R_HOUR] = to_bcd(now.tm_hour);
     }
-    s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
-    s->nvram[4] = to_bcd(now.tm_mday);
-    s->nvram[5] = to_bcd(now.tm_mon + 1);
-    s->nvram[6] = to_bcd(now.tm_year - 100);
+    s->nvram[R_WDAY] = (now.tm_wday + s->wday_offset) % 7 + 1;
+    s->nvram[R_DATE] = to_bcd(now.tm_mday);
+    s->nvram[R_MONTH] = to_bcd(now.tm_mon + 1);
+    s->nvram[R_YEAR] = to_bcd(now.tm_year - 100);
 }
 
 static void inc_regptr(DS1338State *s)
@@ -141,17 +169,17 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
         struct tm now;
         qemu_get_timedate(&now, s->offset);
         switch(s->ptr) {
-        case 0:
+        case R_SEC:
             /* TODO: Implement CH (stop) bit.  */
             now.tm_sec = from_bcd(data & 0x7f);
             break;
-        case 1:
+        case R_MIN:
             now.tm_min = from_bcd(data & 0x7f);
             break;
-        case 2:
-            if (data & HOURS_12) {
-                int tmp = from_bcd(data & (HOURS_PM - 1));
-                if (data & HOURS_PM) {
+        case R_HOUR:
+            if (FIELD_EX32(data, HOUR, SET12)) {
+                int tmp = from_bcd(FIELD_EX32(data, HOUR, HOUR12));
+                if (FIELD_EX32(data, HOUR, AMPM)) {
                     tmp += 12;
                 }
                 if (tmp % 12 == 0) {
@@ -159,10 +187,10 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
                 }
                 now.tm_hour = tmp;
             } else {
-                now.tm_hour = from_bcd(data & (HOURS_12 - 1));
+                now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR24));
             }
             break;
-        case 3:
+        case R_WDAY:
             {
                 /* The day field is supposed to contain a value in
                    the range 1-7. Otherwise behavior is undefined.
@@ -171,18 +199,18 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
                 s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
             }
             break;
-        case 4:
+        case R_DATE:
             now.tm_mday = from_bcd(data & 0x3f);
             break;
-        case 5:
+        case R_MONTH:
             now.tm_mon = from_bcd(data & 0x1f) - 1;
             break;
-        case 6:
+        case R_YEAR:
             now.tm_year = from_bcd(data) + 100;
             break;
         }
         s->offset = qemu_timedate_diff(&now);
-    } else if (s->ptr == 7) {
+    } else if (s->ptr == R_CTRL) {
         /* Control register. */
 
         /* Ensure bits 2, 3 and 6 will read back as zero. */
Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
#5 lore raw

PATCH 3/14 timer: ds1338 persist 12-hour mode selection

In reply to Michael Davidsaver

Need to save HOUR[HOUR12] bit to keep track of guest selection of 12-hour mode. Write through current time registers to achieve this. Will be overwritten by the next read/latch.

This was only being done in two of three arms of this conditional block.

---
 hw/timer/ds1338.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
hw/timer/ds1338.c +1 -3
index 7298c5af43..b56db5852e 100644
@@ -220,10 +220,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
            value unchanged. */
         data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
 
-        s->nvram[s->ptr] = data;
-    } else {
-        s->nvram[s->ptr] = data;
     }
+    s->nvram[s->ptr] = data;
     inc_regptr(s);
     return 0;
 }
Signature · 1 line
2.11.0
#6 lore raw

Re: [Qemu-devel] [PATCH 03/14] timer: ds1338 persist 12-hour mode selection

On Thu, Jul 05, 2018 at 11:19:50AM -0700, Michael Davidsaver wrote:
11;rgb:ffff/ffff/ffff> Need to save HOUR[HOUR12] bit to keep

Quoted 9 lines

track of guest selection of 12-hour mode. Write through current time registers to achieve this. Will be overwritten by the next read/latch.

This was only being done in two of three arms of this conditional block.

This looks dubious to me, or at least the explanation of it does. The other branch of the conditional is covering different registers in the device, which are part of the RTC component, rather than the NVRAM area. I wouldn't necessarily expect them to persist data as a rule the way the rest of the block does, even if this specific bit does need to be preserved.

Quoted 20 lines
---
 hw/timer/ds1338.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
hw/timer/ds1338.c +1 -3
index 7298c5af43..b56db5852e 100644
@@ -220,10 +220,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
            value unchanged. */
         data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
 
-        s->nvram[s->ptr] = data;
-    } else {
-        s->nvram[s->ptr] = data;
     }
+    s->nvram[s->ptr] = data;
     inc_regptr(s);
     return 0;
 }
Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
#7 lore raw

Re: [Qemu-devel] [PATCH 03/14] timer: ds1338 persist 12-hour mode selection

Quoted 10 lines · David Gibson

On Thu, Jul 05, 2018 at 11:19:50AM -0700, Michael Davidsaver wrote:
11;rgb:ffff/ffff/ffff> Need to save HOUR[HOUR12] bit to keep

Quoted 8 lines

track of guest selection of 12-hour mode. Write through current time registers to achieve this. Will be overwritten by the next read/latch.

This was only being done in two of three arms of this conditional block.

Quoted 8 lines
Quoted 1 line

This looks dubious to me, or at least the explanation of it does. The other branch of the conditional is covering different registers in the device, which are part of the RTC component, rather than the NVRAM area. I wouldn't necessarily expect them to persist data as a rule the way the rest of the block does, even if this specific bit does need to be preserved.

The fact that the above capture_current_time() included the line

Quoted 1 line
    if (s->nvram[2] & HOURS_12) {

was enough to convince me that the original author intended to persist the 12/24 hour mode in this way. There are certainly other ways to accomplish this, but they would involved adding to the vmstate, which I've tried to avoid in this iteration.

Also, I though I had test coverage of this bug. That's actually how I noticed it to begin with. But it seems my later change to allow for a slow test runner also stopped testing readback of the 12/24 hour mode bit. It just silently uses whichever it reads. I'll be re-issuing an updated version which restores this check. Then you will be able to easily see the effect of reverting 'timer: ds1338 persist 12-hour mode selection'.

Quoted 21 lines
Quoted 20 lines
---
 hw/timer/ds1338.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
hw/timer/ds1338.c +1 -3
index 7298c5af43..b56db5852e 100644
@@ -220,10 +220,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
            value unchanged. */
         data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
 
-        s->nvram[s->ptr] = data;
-    } else {
-        s->nvram[s->ptr] = data;
     }
+    s->nvram[s->ptr] = data;
     inc_regptr(s);
     return 0;
 }
#8 lore raw

Re: [Qemu-devel] [PATCH 03/14] timer: ds1338 persist 12-hour mode selection

Quoted 6 lines · Michael Davidsaver

Also, I though I had test coverage of this bug. That's actually how I noticed it to begin with. But it seems my later change to allow for a slow test runner also stopped testing readback of the 12/24 hour mode bit. It just silently uses whichever it reads. I'll be re-issuing an updated version which restores this check. Then you will be able to easily see the effect of reverting 'timer: ds1338 persist 12-hour mode selection'.

I've posted revised versions of two of the three test patches #6 and #7 (which I've hopefully posted correctly...). #6 again tests for this issue. So you can demonstrate the problem by either applying 1,2,4-6, or just 1 and 6 to see that the issue is present in the original implementation.

The test failure should be:

Quoted 1 line

test_rtc_set: assertion failed (mode_expect == mode_actual): (1 == 0)

Which shows that a write with 12 hour mode is read back as 24 hour mode.

Similarly, omitting patch #5 will cause the tests added in #7 to fail.

Reviewed-by
#9 lore raw

Re: [Qemu-devel] [PATCH 03/14] timer: ds1338 persist 12-hour mode selection

In reply to Michael Davidsaver
Quoted 20 lines · Michael Davidsaver
Quoted 10 lines · David Gibson

On Thu, Jul 05, 2018 at 11:19:50AM -0700, Michael Davidsaver wrote:
11;rgb:ffff/ffff/ffff> Need to save HOUR[HOUR12] bit to keep

Quoted 8 lines

track of guest selection of 12-hour mode. Write through current time registers to achieve this. Will be overwritten by the next read/latch.

This was only being done in two of three arms of this conditional block.

Quoted 8 lines
Quoted 1 line

This looks dubious to me, or at least the explanation of it does. The other branch of the conditional is covering different registers in the device, which are part of the RTC component, rather than the NVRAM area. I wouldn't necessarily expect them to persist data as a rule the way the rest of the block does, even if this specific bit does need to be preserved.

Quoted 8 lines

The fact that the above capture_current_time() included the line

Quoted 1 line
    if (s->nvram[2] & HOURS_12) {

was enough to convince me that the original author intended to persist the 12/24 hour mode in this way. There are certainly other ways to accomplish this, but they would involved adding to the vmstate, which I've tried to avoid in this iteration.

Ah, yes, I see your point. I was more unsure about whether it was safe to also persist the other early bytes of the region, which this patch also does. But I can't really see how it would do any harm, so:

Quoted 34 lines

Also, I though I had test coverage of this bug. That's actually how I noticed it to begin with. But it seems my later change to allow for a slow test runner also stopped testing readback of the 12/24 hour mode bit. It just silently uses whichever it reads. I'll be re-issuing an updated version which restores this check. Then you will be able to easily see the effect of reverting 'timer: ds1338 persist 12-hour mode selection'.

Quoted 21 lines
Quoted 20 lines
---
 hw/timer/ds1338.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
hw/timer/ds1338.c +1 -3
index 7298c5af43..b56db5852e 100644
@@ -220,10 +220,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
            value unchanged. */
         data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
 
-        s->nvram[s->ptr] = data;
-    } else {
-        s->nvram[s->ptr] = data;
     }
+    s->nvram[s->ptr] = data;
     inc_regptr(s);
     return 0;
 }
Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
#10 lore raw

PATCH 4/14 timer: ds1338 clarify HOUR handling

In reply to Michael Davidsaver

Simplify and comment the translation between
registers and struct tm.

---
 hw/timer/ds1338.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)
hw/timer/ds1338.c +11 -6
index b56db5852e..637a0f4246 100644
@@ -89,9 +89,13 @@ static void capture_current_time(DS1338State *s)
      */
     struct tm now;
     qemu_get_timedate(&now, s->offset);
+
     s->nvram[R_SEC] = to_bcd(now.tm_sec);
     s->nvram[R_MIN] = to_bcd(now.tm_min);
     if (ARRAY_FIELD_EX32(s->nvram, HOUR, SET12)) {
+        /* 12 hour mode.
+         * map 0-23 to 1-12 am/pm
+         */
         int tmp = now.tm_hour;
         if (tmp % 12 == 0) {
             tmp += 12;
@@ -101,7 +105,9 @@ static void capture_current_time(DS1338State *s)
         } else {
             s->nvram[R_HOUR] = R_HOUR_SET12_MASK | R_HOUR_AMPM_MASK | to_bcd(tmp - 12);
         }
+
     } else {
+        /* 24 hour mode. */
         s->nvram[R_HOUR] = to_bcd(now.tm_hour);
     }
     s->nvram[R_WDAY] = (now.tm_wday + s->wday_offset) % 7 + 1;
@@ -178,14 +184,13 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
             break;
         case R_HOUR:
             if (FIELD_EX32(data, HOUR, SET12)) {
-                int tmp = from_bcd(FIELD_EX32(data, HOUR, HOUR12));
+                /* 12 hour (1-12) */
+                /* read and wrap 1-12 -> 0-11 */
+                now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR12)) % 12u;
                 if (FIELD_EX32(data, HOUR, AMPM)) {
-                    tmp += 12;
+                    now.tm_hour += 12;
                 }
-                if (tmp % 12 == 0) {
-                    tmp -= 12;
-                }
-                now.tm_hour = tmp;
+
             } else {
                 now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR24));
             }
Signature · 1 line
2.11.0
Reviewed-by on v1 4/14
#11 lore raw

Re: [Qemu-devel] [PATCH 04/14] timer: ds1338 clarify HOUR handling

Quoted 4 lines · Michael Davidsaver

Simplify and comment the translation between
registers and struct tm.

although..

[snip]

hw/timer/ds1338.c static void capture_current_time(DS1338State *s) · line 109

Quoted 6 lines
hw/timer/ds1338.c +1 -0
@@ -101,7 +105,9 @@ static void capture_current_time(DS1338State *s)
         } else {
             s->nvram[R_HOUR] = R_HOUR_SET12_MASK | R_HOUR_AMPM_MASK | to_bcd(tmp - 12);
         }
+
     } else {

I'm not real fond of blank lines before the ends of blocks.

Quoted 24 lines
hw/timer/ds1338.c +6 -6
+        /* 24 hour mode. */
         s->nvram[R_HOUR] = to_bcd(now.tm_hour);
     }
     s->nvram[R_WDAY] = (now.tm_wday + s->wday_offset) % 7 + 1;
@@ -178,14 +184,13 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
             break;
         case R_HOUR:
             if (FIELD_EX32(data, HOUR, SET12)) {
-                int tmp = from_bcd(FIELD_EX32(data, HOUR, HOUR12));
+                /* 12 hour (1-12) */
+                /* read and wrap 1-12 -> 0-11 */
+                now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR12)) % 12u;
                 if (FIELD_EX32(data, HOUR, AMPM)) {
-                    tmp += 12;
+                    now.tm_hour += 12;
                 }
-                if (tmp % 12 == 0) {
-                    tmp -= 12;
-                }
-                now.tm_hour = tmp;
+
             } else {
                 now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR24));
             }
Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
#12 lore raw

PATCH 5/14 timer: ds1338 change write handling and fix wday_offset handling

In reply to Michael Davidsaver

instead of a read-modify-write, do direct translation of device registers to struct tm members.

This new ds1338_update() is the reverse of the existing capture_current_time().

Simplifies later handling of CENTURY bit in similar Dallas RTC chips.

Correctly handle different real weekday in guest and host timezones.
Allow guest to use any day as start of week (day 1). eg. Monday instead of Sunday.

---
 hw/timer/ds1338.c | 95 ++++++++++++++++++++++++++++---------------------------
 1 file changed, 48 insertions(+), 47 deletions(-)
hw/timer/ds1338.c +48 -47
index 637a0f4246..0134ffd72a 100644
@@ -110,7 +110,10 @@ static void capture_current_time(DS1338State *s)
         /* 24 hour mode. */
         s->nvram[R_HOUR] = to_bcd(now.tm_hour);
     }
-    s->nvram[R_WDAY] = (now.tm_wday + s->wday_offset) % 7 + 1;
+    s->nvram[R_WDAY] = (now.tm_wday + s->wday_offset) % 7;
+    if (s->nvram[R_WDAY] == 0) {
+        s->nvram[R_WDAY] = 7;
+    }
     s->nvram[R_DATE] = to_bcd(now.tm_mday);
     s->nvram[R_MONTH] = to_bcd(now.tm_mon + 1);
     s->nvram[R_YEAR] = to_bcd(now.tm_year - 100);
@@ -161,6 +164,46 @@ static int ds1338_recv(I2CSlave *i2c)
     return res;
 }
 
+/* call after guest writes to current time registers
+ * to re-compute our offset from host time.
+ */
+static void ds1338_update(DS1338State *s)
+{
+
+    struct tm now = {};
+
+    /* TODO: Implement CH (stop) bit?  */
+    now.tm_sec = from_bcd(s->nvram[R_SEC] & 0x7f);
+    now.tm_min = from_bcd(s->nvram[R_MIN] & 0x7f);
+    if (ARRAY_FIELD_EX32(s->nvram, HOUR, SET12)) {
+        /* 12 hour (1-12) */
+        /* read and wrap 1-12 -> 0-11 */
+        now.tm_hour = from_bcd(ARRAY_FIELD_EX32(s->nvram, HOUR, HOUR12)) % 12u;
+        if (ARRAY_FIELD_EX32(s->nvram, HOUR, AMPM)) {
+            now.tm_hour += 12;
+        }
+
+    } else {
+        now.tm_hour = from_bcd(ARRAY_FIELD_EX32(s->nvram, HOUR, HOUR24));
+    }
+    now.tm_wday = from_bcd(s->nvram[R_WDAY]) - 1u;
+    now.tm_mday = from_bcd(s->nvram[R_DATE] & 0x3f);
+    now.tm_mon = from_bcd(s->nvram[R_MONTH] & 0x1f) - 1;
+    now.tm_year = from_bcd(s->nvram[R_YEAR]) + 100;
+    s->offset = qemu_timedate_diff(&now);
+
+    {
+        /* Round trip to get real wday_offset based on time delta and
+         * ref. timezone.
+         * Race if midnight (in ref. timezone) happens here.
+         */
+        int user_wday = now.tm_wday;
+        qemu_get_timedate(&now, s->offset);
+
+        s->wday_offset = (user_wday - now.tm_wday) % 7 + 1;
+    }
+}
+
 static int ds1338_send(I2CSlave *i2c, uint8_t data)
 {
     DS1338State *s = DS1338(i2c);
@@ -170,52 +213,7 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
         s->addr_byte = false;
         return 0;
     }
-    if (s->ptr < 7) {
-        /* Time register. */
-        struct tm now;
-        qemu_get_timedate(&now, s->offset);
-        switch(s->ptr) {
-        case R_SEC:
-            /* TODO: Implement CH (stop) bit.  */
-            now.tm_sec = from_bcd(data & 0x7f);
-            break;
-        case R_MIN:
-            now.tm_min = from_bcd(data & 0x7f);
-            break;
-        case R_HOUR:
-            if (FIELD_EX32(data, HOUR, SET12)) {
-                /* 12 hour (1-12) */
-                /* read and wrap 1-12 -> 0-11 */
-                now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR12)) % 12u;
-                if (FIELD_EX32(data, HOUR, AMPM)) {
-                    now.tm_hour += 12;
-                }
-
-            } else {
-                now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR24));
-            }
-            break;
-        case R_WDAY:
-            {
-                /* The day field is supposed to contain a value in
-                   the range 1-7. Otherwise behavior is undefined.
-                 */
-                int user_wday = (data & 7) - 1;
-                s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
-            }
-            break;
-        case R_DATE:
-            now.tm_mday = from_bcd(data & 0x3f);
-            break;
-        case R_MONTH:
-            now.tm_mon = from_bcd(data & 0x1f) - 1;
-            break;
-        case R_YEAR:
-            now.tm_year = from_bcd(data) + 100;
-            break;
-        }
-        s->offset = qemu_timedate_diff(&now);
-    } else if (s->ptr == R_CTRL) {
+    if (s->ptr == R_CTRL) {
         /* Control register. */
 
         /* Ensure bits 2, 3 and 6 will read back as zero. */
@@ -227,6 +225,9 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 
     }
     s->nvram[s->ptr] = data;
+    if (s->ptr <= R_YEAR) {
+        ds1338_update(s);
+    }
     inc_regptr(s);
     return 0;
 }
Signature · 1 line
2.11.0
#13 lore raw

Re: [Qemu-devel] [PATCH 05/14] timer: ds1338 change write handling and fix wday_offset handling

Quoted 24 lines · Michael Davidsaver

instead of a read-modify-write, do direct translation of device registers to struct tm members.

This new ds1338_update() is the reverse of the existing capture_current_time().

Simplifies later handling of CENTURY bit in similar Dallas RTC chips.

Correctly handle different real weekday in guest and host timezones.
Allow guest to use any day as start of week (day 1). eg. Monday instead of Sunday.

---
 hw/timer/ds1338.c | 95 ++++++++++++++++++++++++++++---------------------------
 1 file changed, 48 insertions(+), 47 deletions(-)
hw/timer/ds1338.c +0 -0
index 637a0f4246..0134ffd72a 100644

hw/timer/ds1338.c static void capture_current_time(DS1338State *s) · line 116

Quoted 8 lines
hw/timer/ds1338.c +4 -1
@@ -110,7 +110,10 @@ static void capture_current_time(DS1338State *s)
         /* 24 hour mode. */
         s->nvram[R_HOUR] = to_bcd(now.tm_hour);
     }
-    s->nvram[R_WDAY] = (now.tm_wday + s->wday_offset) % 7 + 1;
+    s->nvram[R_WDAY] = (now.tm_wday + s->wday_offset) % 7;
+    if (s->nvram[R_WDAY] == 0) {
+        s->nvram[R_WDAY] = 7;
+    }

This looks a bit odd - you've removed the + 1 here, but...

Quoted 20 lines
hw/timer/ds1338.c +13 -0
     s->nvram[R_DATE] = to_bcd(now.tm_mday);
     s->nvram[R_MONTH] = to_bcd(now.tm_mon + 1);
     s->nvram[R_YEAR] = to_bcd(now.tm_year - 100);
@@ -161,6 +164,46 @@ static int ds1338_recv(I2CSlave *i2c)
     return res;
 }
 
+/* call after guest writes to current time registers
+ * to re-compute our offset from host time.
+ */
+static void ds1338_update(DS1338State *s)
+{
+
+    struct tm now = {};
+
+    /* TODO: Implement CH (stop) bit?  */
+    now.tm_sec = from_bcd(s->nvram[R_SEC] & 0x7f);
+    now.tm_min = from_bcd(s->nvram[R_MIN] & 0x7f);
+    if (ARRAY_FIELD_EX32(s->nvram, HOUR, SET12)) {
+        /* 12 hour (1-12) */

hw/timer/ds1338.c static int ds1338_recv(I2CSlave *i2c) · line 189

Quoted 10 lines
hw/timer/ds1338.c +10 -0
+        /* read and wrap 1-12 -> 0-11 */
+        now.tm_hour = from_bcd(ARRAY_FIELD_EX32(s->nvram, HOUR, HOUR12)) % 12u;
+        if (ARRAY_FIELD_EX32(s->nvram, HOUR, AMPM)) {
+            now.tm_hour += 12;
+        }
+
+    } else {
+        now.tm_hour = from_bcd(ARRAY_FIELD_EX32(s->nvram, HOUR, HOUR24));
+    }
+    now.tm_wday = from_bcd(s->nvram[R_WDAY]) - 1u;

.. you still have the -1 here. Am I missing something?

Quoted 84 lines
hw/timer/ds1338.c +21 -46
+    now.tm_mday = from_bcd(s->nvram[R_DATE] & 0x3f);
+    now.tm_mon = from_bcd(s->nvram[R_MONTH] & 0x1f) - 1;
+    now.tm_year = from_bcd(s->nvram[R_YEAR]) + 100;
+    s->offset = qemu_timedate_diff(&now);
+
+    {
+        /* Round trip to get real wday_offset based on time delta and
+         * ref. timezone.
+         * Race if midnight (in ref. timezone) happens here.
+         */
+        int user_wday = now.tm_wday;
+        qemu_get_timedate(&now, s->offset);
+
+        s->wday_offset = (user_wday - now.tm_wday) % 7 + 1;
+    }
+}
+
 static int ds1338_send(I2CSlave *i2c, uint8_t data)
 {
     DS1338State *s = DS1338(i2c);
@@ -170,52 +213,7 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
         s->addr_byte = false;
         return 0;
     }
-    if (s->ptr < 7) {
-        /* Time register. */
-        struct tm now;
-        qemu_get_timedate(&now, s->offset);
-        switch(s->ptr) {
-        case R_SEC:
-            /* TODO: Implement CH (stop) bit.  */
-            now.tm_sec = from_bcd(data & 0x7f);
-            break;
-        case R_MIN:
-            now.tm_min = from_bcd(data & 0x7f);
-            break;
-        case R_HOUR:
-            if (FIELD_EX32(data, HOUR, SET12)) {
-                /* 12 hour (1-12) */
-                /* read and wrap 1-12 -> 0-11 */
-                now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR12)) % 12u;
-                if (FIELD_EX32(data, HOUR, AMPM)) {
-                    now.tm_hour += 12;
-                }
-
-            } else {
-                now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR24));
-            }
-            break;
-        case R_WDAY:
-            {
-                /* The day field is supposed to contain a value in
-                   the range 1-7. Otherwise behavior is undefined.
-                 */
-                int user_wday = (data & 7) - 1;
-                s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
-            }
-            break;
-        case R_DATE:
-            now.tm_mday = from_bcd(data & 0x3f);
-            break;
-        case R_MONTH:
-            now.tm_mon = from_bcd(data & 0x1f) - 1;
-            break;
-        case R_YEAR:
-            now.tm_year = from_bcd(data) + 100;
-            break;
-        }
-        s->offset = qemu_timedate_diff(&now);
-    } else if (s->ptr == R_CTRL) {
+    if (s->ptr == R_CTRL) {
         /* Control register. */
 
         /* Ensure bits 2, 3 and 6 will read back as zero. */
@@ -227,6 +225,9 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 
     }
     s->nvram[s->ptr] = data;
+    if (s->ptr <= R_YEAR) {
+        ds1338_update(s);
+    }
     inc_regptr(s);
     return 0;
 }
Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
#14 lore raw

PATCH 6/14 tests: ds-rtc test 12 hour mode

In reply to Michael Davidsaver
---
 tests/ds-rtc-set-test.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)
tests/ds-rtc-set-test.c +52 -0
index 35e1a36281..c48406ee2c 100644
@@ -29,6 +29,18 @@ static uint8_t test_time_24_12am[8] = {
     0x17,
 };
 
+static uint8_t test_time_12_12am[8] = {
+    0, /* address */
+    /* Wed, 22 Nov 2017 00:30:53 +0000 */
+    0x53,
+    0x30,
+    0x52, /* 12 AM in 12 hour mode */
+    0x03, /* monday is our day 1 */
+    0x22,
+    0x11 | 0x80,
+    0x17,
+};
+
 static uint8_t test_time_24_6am[8] = {
     0, /* address */
     /* Wed, 22 Nov 2017 06:30:53 +0000 */
@@ -41,6 +53,18 @@ static uint8_t test_time_24_6am[8] = {
     0x17,
 };
 
+static uint8_t test_time_12_6am[8] = {
+    0, /* address */
+    /* Wed, 22 Nov 2017 06:30:53 +0000 */
+    0x53,
+    0x30,
+    0x46, /* 6 AM in 12 hour mode */
+    0x03, /* monday is our day 1 */
+    0x22,
+    0x11 | 0x80,
+    0x17,
+};
+
 static uint8_t test_time_24_12pm[8] = {
     0, /* address */
     /* Wed, 22 Nov 2017 12:30:53 +0000 */
@@ -53,6 +77,18 @@ static uint8_t test_time_24_12pm[8] = {
     0x17,
 };
 
+static uint8_t test_time_12_12pm[8] = {
+    0, /* address */
+    /* Wed, 22 Nov 2017 12:30:53 +0000 */
+    0x53,
+    0x30,
+    0x72, /* 12 PM in 24 hour mode */
+    0x03, /* monday is our day 1 */
+    0x22,
+    0x11 | 0x80,
+    0x17,
+};
+
 static uint8_t test_time_24_6pm[8] = {
     0, /* address */
     /* Wed, 22 Nov 2017 18:30:53 +0000 */
@@ -65,6 +101,18 @@ static uint8_t test_time_24_6pm[8] = {
     0x17,
 };
 
+static uint8_t test_time_12_6pm[8] = {
+    0, /* address */
+    /* Wed, 22 Nov 2017 18:30:53 +0000 */
+    0x53,
+    0x30,
+    0x66, /* 6 PM in 12 hour mode */
+    0x03, /* monday is our day 1 */
+    0x22,
+    0x11 | 0x80,
+    0x17,
+};
+
 /* write in and read back known time */
 static
 void test_rtc_set(const void *raw)
@@ -108,6 +156,10 @@ int main(int argc, char *argv[])
     qtest_add_data_func("/ds-rtc-i2c/set24_6am", test_time_24_6am, test_rtc_set);
     qtest_add_data_func("/ds-rtc-i2c/set24_12pm", test_time_24_12pm, test_rtc_set);
     qtest_add_data_func("/ds-rtc-i2c/set24_6pm", test_time_24_6pm, test_rtc_set);
+    qtest_add_data_func("/ds-rtc-i2c/set12_12am", test_time_12_12am, test_rtc_set);
+    qtest_add_data_func("/ds-rtc-i2c/set12_6am", test_time_12_6am, test_rtc_set);
+    qtest_add_data_func("/ds-rtc-i2c/set12_12pm", test_time_12_12pm, test_rtc_set);
+    qtest_add_data_func("/ds-rtc-i2c/set12_6pm", test_time_12_6pm, test_rtc_set);
 
     ret = g_test_run();
 
Signature · 1 line
2.11.0
#15 lore raw

PATCH v2 6/14 tests: ds-rtc test 12 hour mode

---
 tests/ds-rtc-common.h       |  9 ++++---
 tests/ds-rtc-current-test.c |  2 +-
 tests/ds-rtc-set-test.c     | 58 +++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 63 insertions(+), 6 deletions(-)
tests/ds-rtc-common.h +6 -3
index c8e6c2bc5b..5bc7ab32a6 100644
@@ -20,12 +20,15 @@ static uint8_t addr;
 static bool use_century;
 
 /* input buffer must have at least 7 elements */
-static inline time_t rtc_parse(const uint8_t *buf)
+static inline time_t rtc_parse(const uint8_t *buf, int *mmode)
 {
     struct tm parts;
 
     parts.tm_sec = from_bcd(buf[0]);
     parts.tm_min = from_bcd(buf[1]);
+    if (mmode) {
+        *mmode = !!(buf[2] & 0x40);
+    }
     if (buf[2] & 0x40) {
         /* 12 hour */
         /* HOUR register is 1-12. */
@@ -51,7 +54,7 @@ static inline time_t rtc_parse(const uint8_t *buf)
     return mktimegm(&parts);
 }
 
-static time_t rtc_gettime(void)
+static time_t rtc_gettime(int *mmode)
 {
     uint8_t buf[7];
 
@@ -61,7 +64,7 @@ static time_t rtc_gettime(void)
     /* read back current time registers */
     i2c_recv(i2c, addr, buf, 7);
 
-    return rtc_parse(buf);
+    return rtc_parse(buf, mmode);
 }
 
 #endif /* DSRTCCOMMON_H */
tests/ds-rtc-current-test.c +1 -1
index 6acbbed9a6..3c15482a9d 100644
@@ -28,7 +28,7 @@ void test_rtc_current(void)
 
     actual = time(NULL);
     /* new second may start here */
-    expected = rtc_gettime();
+    expected = rtc_gettime(NULL);
     g_assert_cmpuint(expected, <=, actual + max_delta);
     g_assert_cmpuint(expected, >=, actual);
 }
tests/ds-rtc-set-test.c +56 -2

102 lines not on this page · raw message

Signature · 1 line
2.11.0
Reviewed-by on v2 6/14
#16 lore raw

Re: [Qemu-devel] [PATCH v2 06/14] tests: ds-rtc test 12 hour mode

Quoted 1 line · Michael Davidsaver
Quoted 170 lines
---
 tests/ds-rtc-common.h       |  9 ++++---
 tests/ds-rtc-current-test.c |  2 +-
 tests/ds-rtc-set-test.c     | 58 +++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 63 insertions(+), 6 deletions(-)
tests/ds-rtc-common.h +6 -3
index c8e6c2bc5b..5bc7ab32a6 100644
@@ -20,12 +20,15 @@ static uint8_t addr;
 static bool use_century;
 
 /* input buffer must have at least 7 elements */
-static inline time_t rtc_parse(const uint8_t *buf)
+static inline time_t rtc_parse(const uint8_t *buf, int *mmode)
 {
     struct tm parts;
 
     parts.tm_sec = from_bcd(buf[0]);
     parts.tm_min = from_bcd(buf[1]);
+    if (mmode) {
+        *mmode = !!(buf[2] & 0x40);
+    }
     if (buf[2] & 0x40) {
         /* 12 hour */
         /* HOUR register is 1-12. */
@@ -51,7 +54,7 @@ static inline time_t rtc_parse(const uint8_t *buf)
     return mktimegm(&parts);
 }
 
-static time_t rtc_gettime(void)
+static time_t rtc_gettime(int *mmode)
 {
     uint8_t buf[7];
 
@@ -61,7 +64,7 @@ static time_t rtc_gettime(void)
     /* read back current time registers */
     i2c_recv(i2c, addr, buf, 7);
 
-    return rtc_parse(buf);
+    return rtc_parse(buf, mmode);
 }
 
 #endif /* DSRTCCOMMON_H */
tests/ds-rtc-current-test.c +1 -1
index 6acbbed9a6..3c15482a9d 100644
@@ -28,7 +28,7 @@ void test_rtc_current(void)
 
     actual = time(NULL);
     /* new second may start here */
-    expected = rtc_gettime();
+    expected = rtc_gettime(NULL);
     g_assert_cmpuint(expected, <=, actual + max_delta);
     g_assert_cmpuint(expected, >=, actual);
 }
tests/ds-rtc-set-test.c +56 -2
index 35e1a36281..3a742e897f 100644
@@ -29,6 +29,18 @@ static uint8_t test_time_24_12am[8] = {
     0x17,
 };
 
+static uint8_t test_time_12_12am[8] = {
+    0, /* address */
+    /* Wed, 22 Nov 2017 00:30:53 +0000 */
+    0x53,
+    0x30,
+    0x52, /* 12 AM in 12 hour mode */
+    0x03, /* monday is our day 1 */
+    0x22,
+    0x11 | 0x80,
+    0x17,
+};
+
 static uint8_t test_time_24_6am[8] = {
     0, /* address */
     /* Wed, 22 Nov 2017 06:30:53 +0000 */
@@ -41,6 +53,18 @@ static uint8_t test_time_24_6am[8] = {
     0x17,
 };
 
+static uint8_t test_time_12_6am[8] = {
+    0, /* address */
+    /* Wed, 22 Nov 2017 06:30:53 +0000 */
+    0x53,
+    0x30,
+    0x46, /* 6 AM in 12 hour mode */
+    0x03, /* monday is our day 1 */
+    0x22,
+    0x11 | 0x80,
+    0x17,
+};
+
 static uint8_t test_time_24_12pm[8] = {
     0, /* address */
     /* Wed, 22 Nov 2017 12:30:53 +0000 */
@@ -53,6 +77,18 @@ static uint8_t test_time_24_12pm[8] = {
     0x17,
 };
 
+static uint8_t test_time_12_12pm[8] = {
+    0, /* address */
+    /* Wed, 22 Nov 2017 12:30:53 +0000 */
+    0x53,
+    0x30,
+    0x72, /* 12 PM in 24 hour mode */
+    0x03, /* monday is our day 1 */
+    0x22,
+    0x11 | 0x80,
+    0x17,
+};
+
 static uint8_t test_time_24_6pm[8] = {
     0, /* address */
     /* Wed, 22 Nov 2017 18:30:53 +0000 */
@@ -65,6 +101,18 @@ static uint8_t test_time_24_6pm[8] = {
     0x17,
 };
 
+static uint8_t test_time_12_6pm[8] = {
+    0, /* address */
+    /* Wed, 22 Nov 2017 18:30:53 +0000 */
+    0x53,
+    0x30,
+    0x66, /* 6 PM in 12 hour mode */
+    0x03, /* monday is our day 1 */
+    0x22,
+    0x11 | 0x80,
+    0x17,
+};
+
 /* write in and read back known time */
 static
 void test_rtc_set(const void *raw)
@@ -76,16 +124,18 @@ void test_rtc_set(const void *raw)
 
     const uint8_t *testtime = raw;
     time_t expected, actual;
+    int mode_expect, mode_actual;
 
     /* skip address pointer and parse remainder */
-    expected = rtc_parse(&testtime[1]);
+    expected = rtc_parse(&testtime[1], &mode_expect);
 
     i2c_send(i2c, addr, testtime, 8);
     /* host may start new second here */
-    actual = rtc_gettime();
+    actual = rtc_gettime(&mode_actual);
 
     g_assert_cmpuint(expected, <=, actual);
     g_assert_cmpuint(expected + max_delta, >=, actual);
+    g_assert_cmpint(mode_expect, ==, mode_actual);
 }
 
 int main(int argc, char *argv[])
@@ -108,6 +158,10 @@ int main(int argc, char *argv[])
     qtest_add_data_func("/ds-rtc-i2c/set24_6am", test_time_24_6am, test_rtc_set);
     qtest_add_data_func("/ds-rtc-i2c/set24_12pm", test_time_24_12pm, test_rtc_set);
     qtest_add_data_func("/ds-rtc-i2c/set24_6pm", test_time_24_6pm, test_rtc_set);
+    qtest_add_data_func("/ds-rtc-i2c/set12_12am", test_time_12_12am, test_rtc_set);
+    qtest_add_data_func("/ds-rtc-i2c/set12_6am", test_time_12_6am, test_rtc_set);
+    qtest_add_data_func("/ds-rtc-i2c/set12_12pm", test_time_12_12pm, test_rtc_set);
+    qtest_add_data_func("/ds-rtc-i2c/set12_6pm", test_time_12_6pm, test_rtc_set);
 
     ret = g_test_run();
 
Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
#17 lore raw

PATCH 7/14 tests: ds-rtc test wday offset

In reply to Michael Davidsaver
---
 tests/ds-rtc-common.h       | 10 +++++++---
 tests/ds-rtc-current-test.c |  9 ++++++++-
 tests/ds-rtc-set-test.c     |  6 ++++--
 3 files changed, 19 insertions(+), 6 deletions(-)
tests/ds-rtc-common.h +7 -3
index c8e6c2bc5b..633131c55f 100644
@@ -20,7 +20,7 @@ static uint8_t addr;
 static bool use_century;
 
 /* input buffer must have at least 7 elements */
-static inline time_t rtc_parse(const uint8_t *buf)
+static inline time_t rtc_parse(const uint8_t *buf, unsigned *wday)
 {
     struct tm parts;
 
@@ -48,10 +48,14 @@ static inline time_t rtc_parse(const uint8_t *buf)
         parts.tm_year += 100u;
     }
 
+    if (wday) {
+        *wday = parts.tm_wday;
+    }
+
     return mktimegm(&parts);
 }
 
-static time_t rtc_gettime(void)
+static time_t rtc_gettime(unsigned *wday)
 {
     uint8_t buf[7];
 
@@ -61,7 +65,7 @@ static time_t rtc_gettime(void)
     /* read back current time registers */
     i2c_recv(i2c, addr, buf, 7);
 
-    return rtc_parse(buf);
+    return rtc_parse(buf, wday);
 }
 
 #endif /* DSRTCCOMMON_H */
tests/ds-rtc-current-test.c +8 -1
index 6acbbed9a6..7dc3202261 100644
@@ -20,17 +20,24 @@
 static
 void test_rtc_current(void)
 {
+    struct tm tm_actual;
     time_t expected, actual;
     /* relax test to limit false positives when host may be overloaded.
      * Allow larger delta when running "-m quick"
      */
     time_t max_delta = g_test_slow() ? 1 : 30;
 
+    unsigned wday_expect;
+
     actual = time(NULL);
     /* new second may start here */
-    expected = rtc_gettime();
+    expected = rtc_gettime(&wday_expect);
+
+    gmtime_r(&actual, &tm_actual);
+
     g_assert_cmpuint(expected, <=, actual + max_delta);
     g_assert_cmpuint(expected, >=, actual);
+    g_assert_cmpuint(wday_expect, ==, tm_actual.tm_wday);
 }
 
 int main(int argc, char *argv[])
tests/ds-rtc-set-test.c +4 -2
index c48406ee2c..12aeb2580a 100644
@@ -124,16 +124,18 @@ void test_rtc_set(const void *raw)
 
     const uint8_t *testtime = raw;
     time_t expected, actual;
+    unsigned wday_expect, wday_actual;
 
     /* skip address pointer and parse remainder */
-    expected = rtc_parse(&testtime[1]);
+    expected = rtc_parse(&testtime[1], &wday_expect);
 
     i2c_send(i2c, addr, testtime, 8);
     /* host may start new second here */
-    actual = rtc_gettime();
+    actual = rtc_gettime(&wday_actual);
 
     g_assert_cmpuint(expected, <=, actual);
     g_assert_cmpuint(expected + max_delta, >=, actual);
+    g_assert_cmpuint(wday_expect, ==, wday_actual);
 }
 
 int main(int argc, char *argv[])
Signature · 1 line
2.11.0
#18 lore raw

PATCH v2 7/14 tests: ds-rtc test wday offset

---
 tests/ds-rtc-common.h       | 10 +++++++---
 tests/ds-rtc-current-test.c |  9 ++++++++-
 tests/ds-rtc-set-test.c     |  6 ++++--
 3 files changed, 19 insertions(+), 6 deletions(-)
tests/ds-rtc-common.h +7 -3
index 5bc7ab32a6..782ea60453 100644
@@ -20,7 +20,7 @@ static uint8_t addr;
 static bool use_century;
 
 /* input buffer must have at least 7 elements */
-static inline time_t rtc_parse(const uint8_t *buf, int *mmode)
+static inline time_t rtc_parse(const uint8_t *buf, unsigned *wday, int *mmode)
 {
     struct tm parts;
 
@@ -51,10 +51,14 @@ static inline time_t rtc_parse(const uint8_t *buf, int *mmode)
         parts.tm_year += 100u;
     }
 
+    if (wday) {
+        *wday = parts.tm_wday;
+    }
+
     return mktimegm(&parts);
 }
 
-static time_t rtc_gettime(int *mmode)
+static time_t rtc_gettime(unsigned *wday, int *mmode)
 {
     uint8_t buf[7];
 
@@ -64,7 +68,7 @@ static time_t rtc_gettime(int *mmode)
     /* read back current time registers */
     i2c_recv(i2c, addr, buf, 7);
 
-    return rtc_parse(buf, mmode);
+    return rtc_parse(buf, wday, mmode);
 }
 
 #endif /* DSRTCCOMMON_H */
tests/ds-rtc-current-test.c +8 -1
index 3c15482a9d..08d8411671 100644
@@ -20,17 +20,24 @@
 static
 void test_rtc_current(void)
 {
+    struct tm tm_actual;
     time_t expected, actual;
     /* relax test to limit false positives when host may be overloaded.
      * Allow larger delta when running "-m quick"
      */
     time_t max_delta = g_test_slow() ? 1 : 30;
 
+    unsigned wday_expect;
+
     actual = time(NULL);
     /* new second may start here */
-    expected = rtc_gettime(NULL);
+    expected = rtc_gettime(&wday_expect, NULL);
+
+    gmtime_r(&actual, &tm_actual);
+
     g_assert_cmpuint(expected, <=, actual + max_delta);
     g_assert_cmpuint(expected, >=, actual);
+    g_assert_cmpuint(wday_expect, ==, tm_actual.tm_wday);
 }
 
 int main(int argc, char *argv[])
tests/ds-rtc-set-test.c +4 -2
index 3a742e897f..1004470931 100644
@@ -124,17 +124,19 @@ void test_rtc_set(const void *raw)
 
     const uint8_t *testtime = raw;
     time_t expected, actual;
+    unsigned wday_expect, wday_actual;
     int mode_expect, mode_actual;
 
     /* skip address pointer and parse remainder */
-    expected = rtc_parse(&testtime[1], &mode_expect);
+    expected = rtc_parse(&testtime[1], &wday_expect, &mode_expect);
 
     i2c_send(i2c, addr, testtime, 8);
     /* host may start new second here */
-    actual = rtc_gettime(&mode_actual);
+    actual = rtc_gettime(&wday_actual, &mode_actual);
 
     g_assert_cmpuint(expected, <=, actual);
     g_assert_cmpuint(expected + max_delta, >=, actual);
+    g_assert_cmpuint(wday_expect, ==, wday_actual);
     g_assert_cmpint(mode_expect, ==, mode_actual);
 }
 
Signature · 1 line
2.11.0
Reviewed-by on v2 7/14
#19 lore raw

Re: [Qemu-devel] [PATCH v2 07/14] tests: ds-rtc test wday offset

Quoted 1 line · Michael Davidsaver
Quoted 100 lines
---
 tests/ds-rtc-common.h       | 10 +++++++---
 tests/ds-rtc-current-test.c |  9 ++++++++-
 tests/ds-rtc-set-test.c     |  6 ++++--
 3 files changed, 19 insertions(+), 6 deletions(-)
tests/ds-rtc-common.h +7 -3
index 5bc7ab32a6..782ea60453 100644
@@ -20,7 +20,7 @@ static uint8_t addr;
 static bool use_century;
 
 /* input buffer must have at least 7 elements */
-static inline time_t rtc_parse(const uint8_t *buf, int *mmode)
+static inline time_t rtc_parse(const uint8_t *buf, unsigned *wday, int *mmode)
 {
     struct tm parts;
 
@@ -51,10 +51,14 @@ static inline time_t rtc_parse(const uint8_t *buf, int *mmode)
         parts.tm_year += 100u;
     }
 
+    if (wday) {
+        *wday = parts.tm_wday;
+    }
+
     return mktimegm(&parts);
 }
 
-static time_t rtc_gettime(int *mmode)
+static time_t rtc_gettime(unsigned *wday, int *mmode)
 {
     uint8_t buf[7];
 
@@ -64,7 +68,7 @@ static time_t rtc_gettime(int *mmode)
     /* read back current time registers */
     i2c_recv(i2c, addr, buf, 7);
 
-    return rtc_parse(buf, mmode);
+    return rtc_parse(buf, wday, mmode);
 }
 
 #endif /* DSRTCCOMMON_H */
tests/ds-rtc-current-test.c +8 -1
index 3c15482a9d..08d8411671 100644
@@ -20,17 +20,24 @@
 static
 void test_rtc_current(void)
 {
+    struct tm tm_actual;
     time_t expected, actual;
     /* relax test to limit false positives when host may be overloaded.
      * Allow larger delta when running "-m quick"
      */
     time_t max_delta = g_test_slow() ? 1 : 30;
 
+    unsigned wday_expect;
+
     actual = time(NULL);
     /* new second may start here */
-    expected = rtc_gettime(NULL);
+    expected = rtc_gettime(&wday_expect, NULL);
+
+    gmtime_r(&actual, &tm_actual);
+
     g_assert_cmpuint(expected, <=, actual + max_delta);
     g_assert_cmpuint(expected, >=, actual);
+    g_assert_cmpuint(wday_expect, ==, tm_actual.tm_wday);
 }
 
 int main(int argc, char *argv[])
tests/ds-rtc-set-test.c +4 -2
index 3a742e897f..1004470931 100644
@@ -124,17 +124,19 @@ void test_rtc_set(const void *raw)
 
     const uint8_t *testtime = raw;
     time_t expected, actual;
+    unsigned wday_expect, wday_actual;
     int mode_expect, mode_actual;
 
     /* skip address pointer and parse remainder */
-    expected = rtc_parse(&testtime[1], &mode_expect);
+    expected = rtc_parse(&testtime[1], &wday_expect, &mode_expect);
 
     i2c_send(i2c, addr, testtime, 8);
     /* host may start new second here */
-    actual = rtc_gettime(&mode_actual);
+    actual = rtc_gettime(&wday_actual, &mode_actual);
 
     g_assert_cmpuint(expected, <=, actual);
     g_assert_cmpuint(expected + max_delta, >=, actual);
+    g_assert_cmpuint(wday_expect, ==, wday_actual);
     g_assert_cmpint(mode_expect, ==, mode_actual);
 }
 
Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
#20 lore raw

PATCH 8/14 timer: rename ds1338 -> dsrtc

In reply to Michael Davidsaver

Prepare to generalize with a more generic
name.

Keep device name and vmstate name "ds1338"
for compatibility.

---
 hw/timer/ds1338.c | 72 +++++++++++++++++++++++++++----------------------------
 1 file changed, 36 insertions(+), 36 deletions(-)
hw/timer/ds1338.c +36 -36
index 0134ffd72a..3c5781d53c 100644
@@ -23,8 +23,8 @@
 
 #define CTRL_OSF   0x20
 
-#define TYPE_DS1338 "ds1338"
-#define DS1338(obj) OBJECT_CHECK(DS1338State, (obj), TYPE_DS1338)
+#define TYPE_DSRTC "ds1338"
+#define DSRTC(obj) OBJECT_CHECK(DSRTCState, (obj), TYPE_DSRTC)
 
 /* values stored in BCD */
 /* 00-59 */
@@ -57,7 +57,7 @@ FIELD(MONTH, CENTURY, 7, 1)
 
 FIELD(CTRL, OSF, 5, 1)
 
-typedef struct DS1338State {
+typedef struct DSRTCState {
     I2CSlave parent_obj;
 
     int64_t offset;
@@ -65,24 +65,24 @@ typedef struct DS1338State {
     uint8_t nvram[NVRAM_SIZE];
     int32_t ptr;
     bool addr_byte;
-} DS1338State;
+} DSRTCState;
 
-static const VMStateDescription vmstate_ds1338 = {
+static const VMStateDescription vmstate_dsrtc = {
     .name = "ds1338",
     .version_id = 2,
     .minimum_version_id = 1,
     .fields = (VMStateField[]) {
-        VMSTATE_I2C_SLAVE(parent_obj, DS1338State),
-        VMSTATE_INT64(offset, DS1338State),
-        VMSTATE_UINT8_V(wday_offset, DS1338State, 2),
-        VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE),
-        VMSTATE_INT32(ptr, DS1338State),
-        VMSTATE_BOOL(addr_byte, DS1338State),
+        VMSTATE_I2C_SLAVE(parent_obj, DSRTCState),
+        VMSTATE_INT64(offset, DSRTCState),
+        VMSTATE_UINT8_V(wday_offset, DSRTCState, 2),
+        VMSTATE_UINT8_ARRAY(nvram, DSRTCState, NVRAM_SIZE),
+        VMSTATE_INT32(ptr, DSRTCState),
+        VMSTATE_BOOL(addr_byte, DSRTCState),
         VMSTATE_END_OF_LIST()
     }
 };
 
-static void capture_current_time(DS1338State *s)
+static void capture_current_time(DSRTCState *s)
 {
     /* Capture the current time into the secondary registers
      * which will be actually read by the data transfer operation.
@@ -119,7 +119,7 @@ static void capture_current_time(DS1338State *s)
     s->nvram[R_YEAR] = to_bcd(now.tm_year - 100);
 }
 
-static void inc_regptr(DS1338State *s)
+static void inc_regptr(DSRTCState *s)
 {
     /* The register pointer wraps around after 0x3F; wraparound
      * causes the current time/date to be retransferred into
@@ -131,9 +131,9 @@ static void inc_regptr(DS1338State *s)
     }
 }
 
-static int ds1338_event(I2CSlave *i2c, enum i2c_event event)
+static int dsrtc_event(I2CSlave *i2c, enum i2c_event event)
 {
-    DS1338State *s = DS1338(i2c);
+    DSRTCState *s = DSRTC(i2c);
 
     switch (event) {
     case I2C_START_RECV:
@@ -154,9 +154,9 @@ static int ds1338_event(I2CSlave *i2c, enum i2c_event event)
     return 0;
 }
 
-static int ds1338_recv(I2CSlave *i2c)
+static int dsrtc_recv(I2CSlave *i2c)
 {
-    DS1338State *s = DS1338(i2c);
+    DSRTCState *s = DSRTC(i2c);
     uint8_t res;
 
     res  = s->nvram[s->ptr];
@@ -167,7 +167,7 @@ static int ds1338_recv(I2CSlave *i2c)
 /* call after guest writes to current time registers
  * to re-compute our offset from host time.
  */
-static void ds1338_update(DS1338State *s)
+static void dsrtc_update(DSRTCState *s)
 {
 
     struct tm now = {};
@@ -204,9 +204,9 @@ static void ds1338_update(DS1338State *s)
     }
 }
 
-static int ds1338_send(I2CSlave *i2c, uint8_t data)
+static int dsrtc_send(I2CSlave *i2c, uint8_t data)
 {
-    DS1338State *s = DS1338(i2c);
+    DSRTCState *s = DSRTC(i2c);
 
     if (s->addr_byte) {
         s->ptr = data & (NVRAM_SIZE - 1);
@@ -226,15 +226,15 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
     }
     s->nvram[s->ptr] = data;
     if (s->ptr <= R_YEAR) {
-        ds1338_update(s);
+        dsrtc_update(s);
     }
     inc_regptr(s);
     return 0;
 }
 
-static void ds1338_reset(DeviceState *dev)
+static void dsrtc_reset(DeviceState *dev)
 {
-    DS1338State *s = DS1338(dev);
+    DSRTCState *s = DSRTC(dev);
 
     /* The clock is running and synchronized with the host */
     s->offset = 0;
@@ -244,28 +244,28 @@ static void ds1338_reset(DeviceState *dev)
     s->addr_byte = false;
 }
 
-static void ds1338_class_init(ObjectClass *klass, void *data)
+static void dsrtc_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
 
-    k->event = ds1338_event;
-    k->recv = ds1338_recv;
-    k->send = ds1338_send;
-    dc->reset = ds1338_reset;
-    dc->vmsd = &vmstate_ds1338;
+    k->event = dsrtc_event;
+    k->recv = dsrtc_recv;
+    k->send = dsrtc_send;
+    dc->reset = dsrtc_reset;
+    dc->vmsd = &vmstate_dsrtc;
 }
 
-static const TypeInfo ds1338_info = {
-    .name          = TYPE_DS1338,
+static const TypeInfo dsrtc_info = {
+    .name          = TYPE_DSRTC,
     .parent        = TYPE_I2C_SLAVE,
-    .instance_size = sizeof(DS1338State),
-    .class_init    = ds1338_class_init,
+    .instance_size = sizeof(DSRTCState),
+    .class_init    = dsrtc_class_init,
 };
 
-static void ds1338_register_types(void)
+static void dsrtc_register_types(void)
 {
-    type_register_static(&ds1338_info);
+    type_register_static(&dsrtc_info);
 }
 
-type_init(ds1338_register_types)
+type_init(dsrtc_register_types)
Signature · 1 line
2.11.0
#21 lore raw

PATCH 9/14 timer: rename file ds1338.c -> ds-rtc.c

In reply to Michael Davidsaver
---
 default-configs/arm-softmmu.mak | 2 +-
 hw/timer/Makefile.objs          | 2 +-
 hw/timer/{ds1338.c => ds-rtc.c} | 0
 3 files changed, 2 insertions(+), 2 deletions(-)
 rename hw/timer/{ds1338.c => ds-rtc.c} (100%)
default-configs/arm-softmmu.mak +1 -1
index 834d45cfaf..84f42b821b 100644
@@ -34,7 +34,7 @@ CONFIG_SMC91C111=y
 CONFIG_ALLWINNER_EMAC=y
 CONFIG_IMX_FEC=y
 CONFIG_FTGMAC100=y
-CONFIG_DS1338=y
+CONFIG_DSRTC=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_MICRODRIVE=y
hw/timer/Makefile.objs +1 -1
index e16b2b913c..b3d3b80232 100644
@@ -3,7 +3,7 @@ common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o
 common-obj-$(CONFIG_ARM_V7M) += armv7m_systick.o
 common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o
 common-obj-$(CONFIG_CADENCE) += cadence_ttc.o
-common-obj-$(CONFIG_DS1338) += ds1338.o
+common-obj-$(CONFIG_DSRTC) += ds-rtc.o
 common-obj-$(CONFIG_HPET) += hpet.o
 common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
 common-obj-$(CONFIG_M41T80) += m41t80.o
hw/timer/ds-rtc.c renamed from hw/timer/ds1338.c +0 -0
similarity index 100%
rename from hw/timer/ds1338.c
rename to hw/timer/ds-rtc.c
Signature · 1 line
2.11.0
#22 lore raw

PATCH 10/14 timer: ds1338 remove vestige of un-modeled OSF

In reply to Michael Davidsaver

Oscillator stop has never been modeled, so the
Oscillator Stop Flag can never be set.

---
 hw/timer/ds-rtc.c | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)
hw/timer/ds-rtc.c +5 -9
index 3c5781d53c..126566ce1f 100644
@@ -21,8 +21,6 @@
  */
 #define NVRAM_SIZE 64
 
-#define CTRL_OSF   0x20
-
 #define TYPE_DSRTC "ds1338"
 #define DSRTC(obj) OBJECT_CHECK(DSRTCState, (obj), TYPE_DSRTC)
 
@@ -216,13 +214,11 @@ static int dsrtc_send(I2CSlave *i2c, uint8_t data)
     if (s->ptr == R_CTRL) {
         /* Control register. */
 
-        /* Ensure bits 2, 3 and 6 will read back as zero. */
-        data &= 0xB3;
-
-        /* Attempting to write the OSF flag to logic 1 leaves the
-           value unchanged. */
-        data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
-
+        /* Allow guest to set no-op controls for clock out pin and
+         * rate select.  Ignore write 1 to clear OSF.  We don't model
+         * oscillator stop, so it is never set.
+         */
+        data = data & 0x93;
     }
     s->nvram[s->ptr] = data;
     if (s->ptr <= R_YEAR) {
Signature · 1 line
2.11.0
Reviewed-by on v1 10/14
#23 lore raw

Re: [Qemu-devel] [PATCH 10/14] timer: ds1338 remove vestige of un-modeled OSF

Quoted 4 lines · Michael Davidsaver

Oscillator stop has never been modeled, so the
Oscillator Stop Flag can never be set.

Quoted 36 lines
---
 hw/timer/ds-rtc.c | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)
hw/timer/ds-rtc.c +5 -9
index 3c5781d53c..126566ce1f 100644
@@ -21,8 +21,6 @@
  */
 #define NVRAM_SIZE 64
 
-#define CTRL_OSF   0x20
-
 #define TYPE_DSRTC "ds1338"
 #define DSRTC(obj) OBJECT_CHECK(DSRTCState, (obj), TYPE_DSRTC)
 
@@ -216,13 +214,11 @@ static int dsrtc_send(I2CSlave *i2c, uint8_t data)
     if (s->ptr == R_CTRL) {
         /* Control register. */
 
-        /* Ensure bits 2, 3 and 6 will read back as zero. */
-        data &= 0xB3;
-
-        /* Attempting to write the OSF flag to logic 1 leaves the
-           value unchanged. */
-        data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
-
+        /* Allow guest to set no-op controls for clock out pin and
+         * rate select.  Ignore write 1 to clear OSF.  We don't model
+         * oscillator stop, so it is never set.
+         */
+        data = data & 0x93;
     }
     s->nvram[s->ptr] = data;
     if (s->ptr <= R_YEAR) {
Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
#24 lore raw

PATCH 12/14 timer: ds-rtc handle CENTURY bit

In reply to Michael Davidsaver
---
 hw/timer/ds-rtc.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
hw/timer/ds-rtc.c +7 -1
index 6d3a8b5586..9abac38628 100644
@@ -70,6 +70,7 @@ typedef struct DSRTCState {
 typedef struct DSRTCClass {
     I2CSlaveClass parent_obj;
 
+    bool has_century;
     /* actual address space size must be <= NVRAM_SIZE */
     unsigned addr_size;
     unsigned ctrl_offset;
@@ -93,6 +94,7 @@ static const VMStateDescription vmstate_dsrtc = {
 
 static void capture_current_time(DSRTCState *s)
 {
+    DSRTCClass *k = DSRTC_GET_CLASS(s);
     /* Capture the current time into the secondary registers
      * which will be actually read by the data transfer operation.
      */
@@ -125,7 +127,10 @@ static void capture_current_time(DSRTCState *s)
     }
     s->nvram[R_DATE] = to_bcd(now.tm_mday);
     s->nvram[R_MONTH] = to_bcd(now.tm_mon + 1);
-    s->nvram[R_YEAR] = to_bcd(now.tm_year - 100);
+    s->nvram[R_YEAR] = to_bcd(now.tm_year % 100u);
+
+    ARRAY_FIELD_DP32(s->nvram, MONTH, CENTURY,
+                     k->has_century && now.tm_year >= 100)
 }
 
 static void inc_regptr(DSRTCState *s)
@@ -282,6 +287,7 @@ static void ds1338_class_init(ObjectClass *klass, void *data)
 {
     DSRTCClass *k = DSRTC_CLASS(klass);
 
+    k->has_century = false;
     k->addr_size = 0x40;
     k->ctrl_offset = R_DS1338_CTRL;
     k->ctrl_write = ds1338_control_write;
Signature · 1 line
2.11.0
Reviewed-by on v1 12/14
#25 lore raw

Re: [Qemu-devel] [PATCH 12/14] timer: ds-rtc handle CENTURY bit

Quoted 2 lines · Michael Davidsaver
Quoted 44 lines
---
 hw/timer/ds-rtc.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
hw/timer/ds-rtc.c +7 -1
index 6d3a8b5586..9abac38628 100644
@@ -70,6 +70,7 @@ typedef struct DSRTCState {
 typedef struct DSRTCClass {
     I2CSlaveClass parent_obj;
 
+    bool has_century;
     /* actual address space size must be <= NVRAM_SIZE */
     unsigned addr_size;
     unsigned ctrl_offset;
@@ -93,6 +94,7 @@ static const VMStateDescription vmstate_dsrtc = {
 
 static void capture_current_time(DSRTCState *s)
 {
+    DSRTCClass *k = DSRTC_GET_CLASS(s);
     /* Capture the current time into the secondary registers
      * which will be actually read by the data transfer operation.
      */
@@ -125,7 +127,10 @@ static void capture_current_time(DSRTCState *s)
     }
     s->nvram[R_DATE] = to_bcd(now.tm_mday);
     s->nvram[R_MONTH] = to_bcd(now.tm_mon + 1);
-    s->nvram[R_YEAR] = to_bcd(now.tm_year - 100);
+    s->nvram[R_YEAR] = to_bcd(now.tm_year % 100u);
+
+    ARRAY_FIELD_DP32(s->nvram, MONTH, CENTURY,
+                     k->has_century && now.tm_year >= 100)
 }
 
 static void inc_regptr(DSRTCState *s)
@@ -282,6 +287,7 @@ static void ds1338_class_init(ObjectClass *klass, void *data)
 {
     DSRTCClass *k = DSRTC_CLASS(klass);
 
+    k->has_century = false;
     k->addr_size = 0x40;
     k->ctrl_offset = R_DS1338_CTRL;
     k->ctrl_write = ds1338_control_write;
Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
#26 lore raw

PATCH 13/14 timer: ds-rtc model ds1375

In reply to Michael Davidsaver

differences from ds1338

* Has alarms (not modeled)
* different control register (not modeled)
* smaller address space (0x20 vs. 0x40)

---
 hw/timer/ds-rtc.c | 30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)
hw/timer/ds-rtc.c +28 -2
index 9abac38628..3a8ad1a00f 100644
@@ -1,8 +1,9 @@
 /*
- * MAXIM DS1338 I2C RTC+NVRAM
+ * MAXIM/Dallas DS1338 and DS1375 I2C RTC+NVRAM
  *
+ * Copyright (c) 2018 Michael Davidsaver
  * Copyright (c) 2009 CodeSourcery.
- * Written by Paul Brook
+ * Written by Paul Brook, Michael Davidsaver
  *
  * This code is licensed under the GNU GPL v2.
  *
@@ -41,6 +42,7 @@
 #define R_YEAR  (0x6)
 
 #define R_DS1338_CTRL (0x7)
+#define R_DS1375_CTRL (0xe)
 
 /* use 12 hour mode when set */
 FIELD(HOUR, SET12, 6, 1)
@@ -300,10 +302,34 @@ static const TypeInfo ds1338_info = {
     .class_init    = ds1338_class_init,
 };
 
+static void ds1375_control_write(DSRTCState *s, uint8_t data)
+{
+    /* just store it, we don't model any features */
+    s->nvram[R_DS1375_CTRL] = data;
+}
+
+static void ds1375_class_init(ObjectClass *klass, void *data)
+{
+    DSRTCClass *k = DSRTC_CLASS(klass);
+
+    k->has_century = true;
+    k->addr_size = 0x20;
+    k->ctrl_offset = R_DS1375_CTRL;
+    k->ctrl_write = ds1375_control_write;
+}
+
+static const TypeInfo ds1375_info = {
+    .name          = "ds1375",
+    .parent        = TYPE_DSRTC,
+    .class_size    = sizeof(DSRTCClass),
+    .class_init    = ds1375_class_init,
+};
+
 static void dsrtc_register_types(void)
 {
     type_register_static(&dsrtc_info);
     type_register_static(&ds1338_info);
+    type_register_static(&ds1375_info);
 }
 
 type_init(dsrtc_register_types)
Signature · 1 line
2.11.0
Reviewed-by on v1 13/14
#27 lore raw

Re: [Qemu-devel] [PATCH 13/14] timer: ds-rtc model ds1375

Quoted 8 lines · Michael Davidsaver

differences from ds1338

* Has alarms (not modeled)
* different control register (not modeled)
* smaller address space (0x20 vs. 0x40)

Quoted 63 lines
---
 hw/timer/ds-rtc.c | 30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)
hw/timer/ds-rtc.c +28 -2
index 9abac38628..3a8ad1a00f 100644
@@ -1,8 +1,9 @@
 /*
- * MAXIM DS1338 I2C RTC+NVRAM
+ * MAXIM/Dallas DS1338 and DS1375 I2C RTC+NVRAM
  *
+ * Copyright (c) 2018 Michael Davidsaver
  * Copyright (c) 2009 CodeSourcery.
- * Written by Paul Brook
+ * Written by Paul Brook, Michael Davidsaver
  *
  * This code is licensed under the GNU GPL v2.
  *
@@ -41,6 +42,7 @@
 #define R_YEAR  (0x6)
 
 #define R_DS1338_CTRL (0x7)
+#define R_DS1375_CTRL (0xe)
 
 /* use 12 hour mode when set */
 FIELD(HOUR, SET12, 6, 1)
@@ -300,10 +302,34 @@ static const TypeInfo ds1338_info = {
     .class_init    = ds1338_class_init,
 };
 
+static void ds1375_control_write(DSRTCState *s, uint8_t data)
+{
+    /* just store it, we don't model any features */
+    s->nvram[R_DS1375_CTRL] = data;
+}
+
+static void ds1375_class_init(ObjectClass *klass, void *data)
+{
+    DSRTCClass *k = DSRTC_CLASS(klass);
+
+    k->has_century = true;
+    k->addr_size = 0x20;
+    k->ctrl_offset = R_DS1375_CTRL;
+    k->ctrl_write = ds1375_control_write;
+}
+
+static const TypeInfo ds1375_info = {
+    .name          = "ds1375",
+    .parent        = TYPE_DSRTC,
+    .class_size    = sizeof(DSRTCClass),
+    .class_init    = ds1375_class_init,
+};
+
 static void dsrtc_register_types(void)
 {
     type_register_static(&dsrtc_info);
     type_register_static(&ds1338_info);
+    type_register_static(&ds1375_info);
 }
 
 type_init(dsrtc_register_types)
Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
#28 lore raw

PATCH 14/14 tests: drop ds1338-test

In reply to Michael Davidsaver

redundant to ds-rtc-*-test.c

---
 tests/Makefile.include |  2 --
 tests/ds1338-test.c    | 75 --------------------------------------------------
 2 files changed, 77 deletions(-)
 delete mode 100644 tests/ds1338-test.c
tests/Makefile.include +0 -2
index 6ce5a9ff4d..8cf438260b 100644
@@ -377,7 +377,6 @@ check-qtest-sparc64-y += tests/boot-serial-test$(EXESUF)
 
 check-qtest-arm-y = tests/tmp105-test$(EXESUF)
 check-qtest-arm-y += tests/pca9552-test$(EXESUF)
-check-qtest-arm-y += tests/ds1338-test$(EXESUF)
 check-qtest-arm-y += tests/ds-rtc-current-test$(EXESUF)
 check-qtest-arm-y += tests/ds-rtc-set-test$(EXESUF)
 check-qtest-arm-y += tests/m25p80-test$(EXESUF)
@@ -788,7 +787,6 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \
 tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
 tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
 tests/pca9552-test$(EXESUF): tests/pca9552-test.o $(libqos-omap-obj-y)
-tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
 tests/ds-rtc-current-test$(EXESUF): tests/ds-rtc-current-test.o $(libqos-imx-obj-y)
 tests/ds-rtc-set-test$(EXESUF): tests/ds-rtc-set-test.o $(libqos-imx-obj-y)
 tests/m25p80-test$(EXESUF): tests/m25p80-test.o
tests/ds1338-test.c deleted +0 -75

75 lines not on this page · raw message

Signature · 1 line
2.11.0
Reviewed-by on v1 14/14
#29 lore raw

Re: [Qemu-devel] [PATCH 14/14] tests: drop ds1338-test

Quoted 9 lines · Michael Davidsaver

redundant to ds-rtc-*-test.c

---
 tests/Makefile.include |  2 --
 tests/ds1338-test.c    | 75 --------------------------------------------------
 2 files changed, 77 deletions(-)
 delete mode 100644 tests/ds1338-test.c

thanks
-- PMM

A message that is not in the archive (sent off-list or not yet received): [email protected]

Reviewed-by
#31 lore raw

Re: [Qemu-devel] [PATCH 11/14] timer: generalize ds1338

Quoted 4 lines · Michael Davidsaver

Add class level handling for address space size
and control register.

Although I don't love the name "addr_size" - just "nvram_size" seems clearer.

Quoted 130 lines
---
 hw/timer/ds-rtc.c | 62 +++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 49 insertions(+), 13 deletions(-)
hw/timer/ds-rtc.c +49 -13
index 126566ce1f..6d3a8b5586 100644
@@ -21,8 +21,10 @@
  */
 #define NVRAM_SIZE 64
 
-#define TYPE_DSRTC "ds1338"
+#define TYPE_DSRTC "dsrtc"
 #define DSRTC(obj) OBJECT_CHECK(DSRTCState, (obj), TYPE_DSRTC)
+#define DSRTC_CLASS(klass) OBJECT_CLASS_CHECK(DSRTCClass, (klass), TYPE_DSRTC)
+#define DSRTC_GET_CLASS(obj) OBJECT_GET_CLASS(DSRTCClass, (obj), TYPE_DSRTC)
 
 /* values stored in BCD */
 /* 00-59 */
@@ -38,7 +40,7 @@
 /* 0-99 */
 #define R_YEAR  (0x6)
 
-#define R_CTRL  (0x7)
+#define R_DS1338_CTRL (0x7)
 
 /* use 12 hour mode when set */
 FIELD(HOUR, SET12, 6, 1)
@@ -65,6 +67,15 @@ typedef struct DSRTCState {
     bool addr_byte;
 } DSRTCState;
 
+typedef struct DSRTCClass {
+    I2CSlaveClass parent_obj;
+
+    /* actual address space size must be <= NVRAM_SIZE */
+    unsigned addr_size;
+    unsigned ctrl_offset;
+    void (*ctrl_write)(DSRTCState *s, uint8_t);
+} DSRTCClass;
+
 static const VMStateDescription vmstate_dsrtc = {
     .name = "ds1338",
     .version_id = 2,
@@ -119,11 +130,12 @@ static void capture_current_time(DSRTCState *s)
 
 static void inc_regptr(DSRTCState *s)
 {
-    /* The register pointer wraps around after 0x3F; wraparound
+    DSRTCClass *k = DSRTC_GET_CLASS(s);
+    /* The register pointer wraps around after k->addr_size-1; wraparound
      * causes the current time/date to be retransferred into
      * the secondary registers.
      */
-    s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
+    s->ptr = (s->ptr + 1) % k->addr_size;
     if (!s->ptr) {
         capture_current_time(s);
     }
@@ -205,20 +217,15 @@ static void dsrtc_update(DSRTCState *s)
 static int dsrtc_send(I2CSlave *i2c, uint8_t data)
 {
     DSRTCState *s = DSRTC(i2c);
+    DSRTCClass *k = DSRTC_GET_CLASS(s);
 
     if (s->addr_byte) {
-        s->ptr = data & (NVRAM_SIZE - 1);
+        s->ptr = data % k->addr_size;
         s->addr_byte = false;
         return 0;
     }
-    if (s->ptr == R_CTRL) {
-        /* Control register. */
-
-        /* Allow guest to set no-op controls for clock out pin and
-         * rate select.  Ignore write 1 to clear OSF.  We don't model
-         * oscillator stop, so it is never set.
-         */
-        data = data & 0x93;
+    if (s->ptr == k->ctrl_offset) {
+        (k->ctrl_write)(s, data);
     }
     s->nvram[s->ptr] = data;
     if (s->ptr <= R_YEAR) {
@@ -253,15 +260,44 @@ static void dsrtc_class_init(ObjectClass *klass, void *data)
 }
 
 static const TypeInfo dsrtc_info = {
+    .abstract      = true,
     .name          = TYPE_DSRTC,
     .parent        = TYPE_I2C_SLAVE,
     .instance_size = sizeof(DSRTCState),
     .class_init    = dsrtc_class_init,
 };
 
+static void ds1338_control_write(DSRTCState *s, uint8_t data)
+{
+    /* Control register. */
+
+    /* Allow guest to set no-op controls for clock out pin and
+     * rate select.  Ignore write 1 to clear OSF.  We don't model
+     * oscillator stop, so it is never set.
+     */
+    s->nvram[R_DS1338_CTRL] = data & 0x93;
+}
+
+static void ds1338_class_init(ObjectClass *klass, void *data)
+{
+    DSRTCClass *k = DSRTC_CLASS(klass);
+
+    k->addr_size = 0x40;
+    k->ctrl_offset = R_DS1338_CTRL;
+    k->ctrl_write = ds1338_control_write;
+}
+
+static const TypeInfo ds1338_info = {
+    .name          = "ds1338",
+    .parent        = TYPE_DSRTC,
+    .class_size    = sizeof(DSRTCClass),
+    .class_init    = ds1338_class_init,
+};
+
 static void dsrtc_register_types(void)
 {
     type_register_static(&dsrtc_info);
+    type_register_static(&ds1338_info);
 }
 
 type_init(dsrtc_register_types)
Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson