[Qemu-devel] [PATCH] hw/ds1338.c: implement clock enable/disable (CH bit)

2013-02-16 Thread Antoine Mathys

Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |  156 ---
 1 file changed, 95 insertions(+), 61 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index 1da0f96..5a93fb6 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -48,17 +48,32 @@ static const VMStateDescription vmstate_ds1338 = {
 }
 };
 
-static void capture_current_time(DS1338State *s)
+/* This mask is used to clear the read as zero bits in the RTC registers */
+static const uint8_t nvram_mask[8] = {
+0xff, 0x7f, 0x7f, 0x7, 0x3f, 0x1f, 0xff, 0xb3
+};
+
+
+static int compute_wday(int y, int m, int d)
 {
-/* Capture the current time into the secondary registers
- * which will be actually read by the data transfer operation.
- */
-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);
+static int t[12] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
+
+if (m  2) {
+y--;
+}
+return (y + y/4 - y/100 + y/400 + t[m] + d) % 7;
+}
+
+/* Write TM to the RTC registers. */
+static void write_time(DS1338State *s, const struct tm *tm)
+{
+/* Preserve the CH flag. */
+s-nvram[0] = SECONDS_CH;
+s-nvram[0] |= to_bcd(tm-tm_sec);
+
+s-nvram[1] = to_bcd(tm-tm_min);
 if (s-nvram[2]  HOURS_12) {
-int tmp = now.tm_hour;
+int tmp = tm-tm_hour;
 if (tmp % 12 == 0) {
 tmp += 12;
 }
@@ -68,12 +83,50 @@ static void capture_current_time(DS1338State *s)
 s-nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
 }
 } else {
-s-nvram[2] = to_bcd(now.tm_hour);
+s-nvram[2] = to_bcd(tm-tm_hour);
+}
+s-nvram[3] = (tm-tm_wday + s-wday_offset) % 7 + 1;
+s-nvram[4] = to_bcd(tm-tm_mday);
+s-nvram[5] = to_bcd(tm-tm_mon + 1);
+s-nvram[6] = to_bcd(tm-tm_year - 100);
+}
+
+/* Read TM from the RTC registers. */
+static void read_time(DS1338State *s, struct tm *tm)
+{
+tm-tm_sec = from_bcd(s-nvram[0]  0x7f);
+tm-tm_min = from_bcd(s-nvram[1]  0x7f);
+if (s-nvram[2]  HOURS_12) {
+int tmp = from_bcd(s-nvram[2]  (HOURS_PM - 1));
+if (s-nvram[2]  HOURS_PM) {
+tmp += 12;
+}
+if (tmp % 12 == 0) {
+tmp -= 12;
+}
+tm-tm_hour = tmp;
+} else {
+tm-tm_hour = from_bcd(s-nvram[2]  (HOURS_12 - 1));
+}
+tm-tm_mday = from_bcd(s-nvram[4]  0x3f);
+tm-tm_mon = from_bcd(s-nvram[5]  0x1f) - 1;
+tm-tm_year = from_bcd(s-nvram[6]) + 100;
+tm-tm_wday = compute_wday(tm-tm_year + 1900, tm-tm_mon, tm-tm_mday);
+}
+
+static bool clock_running(DS1338State *s)
+{
+return !(s-nvram[0]  SECONDS_CH);
+}
+
+static void capture_current_time(DS1338State *s)
+{
+if (clock_running(s)) {
+/* Write current time. */
+struct tm tmp;
+qemu_get_timedate(tmp, s-offset);
+write_time(s, tmp);
 }
-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);
 }
 
 static void inc_regptr(DS1338State *s)
@@ -129,65 +182,46 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 }
 if (s-ptr  7) {
 /* Time register. */
-struct tm now;
-qemu_get_timedate(now, s-offset);
-switch(s-ptr) {
-case 0:
-/* TODO: Implement CH (stop) bit.  */
-now.tm_sec = from_bcd(data  0x7f);
-break;
-case 1:
-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) {
-tmp += 12;
-}
-if (tmp % 12 == 0) {
-tmp -= 12;
-}
-now.tm_hour = tmp;
-} else {
-now.tm_hour = from_bcd(data  (HOURS_12 - 1));
-}
-break;
-case 3:
-{
-/* 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;
+bool was_running = clock_running(s);
+
+capture_current_time(s);
+
+s-nvram[s-ptr] = data  nvram_mask[s-ptr];
+
+if (clock_running(s)) {
+/* Read the new time */
+struct tm tmp;
+int user_wday;
+
+read_time(s, tmp);
+s-offset = qemu_timedate_diff(tmp);
+
+/* The day field is supposed to contain a value in
+   the range 1-7. Otherwise behavior is undefined.
+*/
+user_wday = (s-nvram[3]  7) - 1;
+s-wday_offset = (user_wday - tmp.tm_wday + 7

Re: [Qemu-devel] [PATCH] Fix conversion between 12 hours and 24 hours modes.

2013-02-15 Thread Antoine Mathys

On 02/15/2013 12:24 PM, Andreas Färber wrote:

The expected answer would've been take guest X and do Y to see Z, or
better to extend the existing qtest cases to prove something was broken
before and fixed afterwards and to avoid the same bug being reintroduced
later.


If we are talking about adding a test case in order to have some guarantee that 
what works after a fix keeps working in the future, that's fine. And I am 
willing to add such tests for the DS1338 implementation (once it is finished).

But demanding a test case that the code passes with the fix but fails without, 
in order to prove that something was broken before, is only reasonable if the 
bug was found through testing in the first place.

It is inappropriate for a bug found in a code review. Not only do you not need 
a test case to prove the bug exists, but reverse-engineering a test-case can be 
a significant undertaking. Paolo tried to do that unsuccessfully in the case of 
bug 1090558 and I had no reason to think I could do better. This does not 
strike me as a very productive use of developer time anyway.

And your suggestion that it is better to leave a known bug unpatched until 
someone can conjure up a test case is ridiculous. I don't see how that attitude 
help users, in the short or long term.

If you don't nuance your position you are only going to discourage much needed 
code reviews. I don't see what good can come of that.





Re: [Qemu-devel] [PATCH] hw/mc146818rtc.c: Fix reading and writing of time registers

2013-02-14 Thread Antoine Mathys

On 02/14/2013 10:30 AM, Paolo Bonzini wrote:

Nice. Do you have a testcase?

No, but the refactoring makes the code very easy to audit.
Please also test this patch with the two rtc-test patches at 
http://thread.gmane.org/gmane.comp.emulators.qemu/188244.

I did and the tests pass.




Re: [Qemu-devel] [PATCH] Fix conversion between 12 hours and 24 hours modes.

2013-02-14 Thread Antoine Mathys
First, the ds1338 code was in a poor state and never handled the 12 hour 
clock correctly. My first patch failed to fully fix the problem so I had 
to write a second one, but at no point did Peter or I introduce a 
regression, quite the opposite.


Second, I don't know where you got the idea that I refuse to write test 
cases. I just didn't have one ready or in the works at the time.


Third, bug 1090558 in mc146818rtc is a good example of a bug which was 
not due to insufficient testing, but to poorly structured code.


There is no point worrying about unit testing if you accept code of such 
low quality. This goes for the tests too. For instance 
cmos_get_date_time() in tests/rtc-test.c doesn't work correctly in 12 
hour mode.


Fourth, I am not interested in the PC architecture, I only wrote a fix 
for bug 1090558 because Paolo asked me to. It is nice to see that fixing 
your crappy code makes me not a nice guy who is making things worse. 
But don't worry, I'll focus on ARM from now on.





[Qemu-devel] [PATCH] hw/mc146818rtc.c: Fix reading and writing of time registers

2013-02-13 Thread Antoine Mathys
This patch consolidates the bit twidling involved in reading and
writing the time registers to four functions that are used consistently.

This also has the effect of fixing bug 1090558.

Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/mc146818rtc.c |  163 +-
 1 file changed, 99 insertions(+), 64 deletions(-)

diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 2fb11f6..646cbd0 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -86,8 +86,14 @@ typedef struct RTCState {
 
 static void rtc_set_time(RTCState *s);
 static void rtc_update_time(RTCState *s);
+
+/* data encoding / decoding */
+static inline uint8_t rtc_encode(RTCState *s, uint8_t a);
+static inline int rtc_decode(RTCState *s, uint8_t a);
+static inline uint8_t rtc_hour_encode(RTCState *s, uint8_t hour);
+static inline int rtc_hour_decode(RTCState *s, uint8_t a);
+
 static void rtc_set_cmos(RTCState *s, const struct tm *tm);
-static inline int rtc_from_bcd(RTCState *s, int a);
 static uint64_t get_next_alarm(RTCState *s);
 
 static inline bool rtc_running(RTCState *s)
@@ -254,17 +260,84 @@ static void check_update_timer(RTCState *s)
 }
 }
 
-static inline uint8_t convert_hour(RTCState *s, uint8_t hour)
+/* data encoding / decoding */
+
+static inline uint8_t rtc_encode(RTCState *s, uint8_t a)
+{
+if (s-cmos_data[RTC_REG_B]  REG_B_DM) {
+return a;
+} else {
+return to_bcd(a);
+}
+}
+
+static inline int rtc_decode(RTCState *s, uint8_t a)
+{
+if ((a  0xc0) == 0xc0) {
+return -1;
+}
+if (s-cmos_data[RTC_REG_B]  REG_B_DM) {
+return a;
+} else {
+return from_bcd(a);
+}
+}
+
+/*
+  Note: The next two functions implement the following mapping between
+  the 12 hour and 24 hour formats:
+
+  0-12 AM
+  1-11 -1 - 11 AM
+  12   -12 PM
+  13-23-1 - 11 PM
+*/
+
+static inline uint8_t rtc_hour_encode(RTCState *s, uint8_t hour)
+{
+uint8_t tmp;
+
+if (s-cmos_data[RTC_REG_B]  REG_B_24H) {
+/* 24 hour format */
+tmp = rtc_encode(s, hour);
+} else {
+/* 12 hour format */
+uint8_t h = (hour % 12) ? (hour % 12) : 12;
+tmp = rtc_encode(s, h);
+if (hour = 12) {
+tmp |= 0x80;
+}
+}
+return tmp;
+}
+
+static inline int rtc_hour_decode(RTCState *s, uint8_t a)
 {
-if (!(s-cmos_data[RTC_REG_B]  REG_B_24H)) {
+uint8_t hour;
+
+/* Note: in 12 hour mode we clear bit 7 before calling
+   rtc_decode(), hence we cannot rely on the later to check the
+   don't care condition. While we could skip this check in 24 hour
+   mode it is simpler to do it in any case. */
+if ((a  0xc0) == 0xc0) {
+return -1;
+}
+
+if (s-cmos_data[RTC_REG_B]  REG_B_24H) {
+/* 24 hour format */
+hour = rtc_decode(s, a);
+} else {
+/* 12 hour format */
+hour = rtc_decode(s, a  0x7f);
 hour %= 12;
-if (s-cmos_data[RTC_HOURS]  0x80) {
+if (a  0x80) {
 hour += 12;
 }
 }
 return hour;
 }
 
+
 static uint64_t get_next_alarm(RTCState *s)
 {
 int32_t alarm_sec, alarm_min, alarm_hour, cur_hour, cur_min, cur_sec;
@@ -272,15 +345,13 @@ static uint64_t get_next_alarm(RTCState *s)
 
 rtc_update_time(s);
 
-alarm_sec = rtc_from_bcd(s, s-cmos_data[RTC_SECONDS_ALARM]);
-alarm_min = rtc_from_bcd(s, s-cmos_data[RTC_MINUTES_ALARM]);
-alarm_hour = rtc_from_bcd(s, s-cmos_data[RTC_HOURS_ALARM]);
-alarm_hour = alarm_hour == -1 ? -1 : convert_hour(s, alarm_hour);
+alarm_sec = rtc_decode(s, s-cmos_data[RTC_SECONDS_ALARM]);
+alarm_min = rtc_decode(s, s-cmos_data[RTC_MINUTES_ALARM]);
+alarm_hour = rtc_hour_decode(s, s-cmos_data[RTC_HOURS_ALARM]);
 
-cur_sec = rtc_from_bcd(s, s-cmos_data[RTC_SECONDS]);
-cur_min = rtc_from_bcd(s, s-cmos_data[RTC_MINUTES]);
-cur_hour = rtc_from_bcd(s, s-cmos_data[RTC_HOURS]);
-cur_hour = convert_hour(s, cur_hour);
+cur_sec = rtc_decode(s, s-cmos_data[RTC_SECONDS]);
+cur_min = rtc_decode(s, s-cmos_data[RTC_MINUTES]);
+cur_hour = rtc_hour_decode(s, s-cmos_data[RTC_HOURS]);
 
 if (alarm_hour == -1) {
 alarm_hour = cur_hour;
@@ -486,44 +557,17 @@ static void cmos_ioport_write(void *opaque, hwaddr addr,
 }
 }
 
-static inline int rtc_to_bcd(RTCState *s, int a)
-{
-if (s-cmos_data[RTC_REG_B]  REG_B_DM) {
-return a;
-} else {
-return ((a / 10)  4) | (a % 10);
-}
-}
-
-static inline int rtc_from_bcd(RTCState *s, int a)
-{
-if ((a  0xc0) == 0xc0) {
-return -1;
-}
-if (s-cmos_data[RTC_REG_B]  REG_B_DM) {
-return a;
-} else {
-return ((a  4) * 10) + (a  0x0f);
-}
-}
-
 static void rtc_get_time(RTCState *s, struct tm *tm)
 {
-tm-tm_sec = rtc_from_bcd(s, s-cmos_data[RTC_SECONDS]);
-tm-tm_min = rtc_from_bcd(s, s-cmos_data[RTC_MINUTES]);
-tm-tm_hour

Re: [Qemu-devel] [PATCH v4 0/6] hw/ds1338.c

2012-12-14 Thread Antoine Mathys

On 12/13/2012 03:09 PM, Peter Maydell wrote:



I certainly will send further patches.

As you noticed I am new to git. Thanks for your patience and advice.



[Qemu-devel] [Bug 1090558] [NEW] hw/mc146818: error reading RTC_HOURS_ALARM

2012-12-14 Thread Antoine Mathys
Public bug reported:

get_next_alarm() doesn't read the RTC_HOURS_ALARM field correctly.

- Bit 7 must be masked before conversion from BCD.
- Care must be taken to check the don't care condition before masking.
- The PM bit must be read from RTC_HOURS_ALARM, not from RTC_HOURS (as is done 
in convert_hour()).

Seen in commit e376a788ae130454ad5e797f60cb70d0308babb6.

** Affects: qemu
 Importance: Undecided
 Status: New

-- 
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1090558

Title:
  hw/mc146818: error reading RTC_HOURS_ALARM

Status in QEMU:
  New

Bug description:
  get_next_alarm() doesn't read the RTC_HOURS_ALARM field correctly.

  - Bit 7 must be masked before conversion from BCD.
  - Care must be taken to check the don't care condition before masking.
  - The PM bit must be read from RTC_HOURS_ALARM, not from RTC_HOURS (as is 
done in convert_hour()).

  Seen in commit e376a788ae130454ad5e797f60cb70d0308babb6.

To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1090558/+subscriptions



[Qemu-devel] [PATCH] Fix conversion between 12 hours and 24 hours modes.

2012-12-14 Thread Antoine Mathys
The proper mapping between 24 hours and 12 hours modes is:
0   12 AM
1-111-11 AM
12  12 PM
13-23   1-11 PM
Fix code accordingly.

Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index 1aefa3b..9e6b490 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -59,8 +59,8 @@ static void capture_current_time(DS1338State *s)
 s-nvram[1] = to_bcd(now.tm_min);
 if (s-nvram[2]  HOURS_12) {
 int tmp = now.tm_hour;
-if (tmp == 0) {
-tmp = 24;
+if (tmp % 12 == 0) {
+tmp += 12;
 }
 if (tmp = 12) {
 s-nvram[2] = HOURS_12 | to_bcd(tmp);
@@ -145,8 +145,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 if (data  HOURS_PM) {
 tmp += 12;
 }
-if (tmp == 24) {
-tmp = 0;
+if (tmp % 12 == 0) {
+tmp -= 12;
 }
 now.tm_hour = tmp;
 } else {
-- 
1.7.10.4




Re: [Qemu-devel] [PATCH v2 4/6] hw/ds1338.c: Ensure state is properly initialized.

2012-12-12 Thread Antoine Mathys

On 12/12/2012 01:05 PM, Peter Maydell wrote:

I think we need to reset ptr and addr_byte too...

The initial value of the register pointer is unspecified.

addr_byte is only used when receiving user data. It is written in 
ds1338_event() then read in ds1338_send(). Setting it in ds1338_reset() 
is unnecessary and would break encapsulation.




Re: [Qemu-devel] [PATCH v2 4/6] hw/ds1338.c: Ensure state is properly initialized.

2012-12-12 Thread Antoine Mathys



It's true that it probably doesn't make much difference, but
both the addr_byte and ptr are part of the migration state
listed in the vmstate struct. I think it is cleaner and
more straightforward to reason about if resetting the
device returns it to an exact known state. The state may be
undefined according to the specification but that doesn't
mean that our implementation has to leave it undefined.

I don't understand your point about encapsulation -- these
are both fields of the device state, and ds1338_reset()
is a method of the device and has every right to access
them.


You are right. While it is not strictly necessary it is cleaner (and 
safer) to set every field to a reasonable value. In addition some guest 
code probably incorrectly assumes that the pointer is initially at zero 
so that wouldn't hurt.


Would it be ok to reply with a new version of this patch only, instead 
of resending the whole series ?





[Qemu-devel] [PATCH v3 0/6] hw/ds1338.c

2012-12-12 Thread Antoine Mathys





Re: [Qemu-devel] [PATCH v3 2/6] hw/ds1338.c: Add definitions for various flags in, the RTC registers.

2012-12-12 Thread Antoine Mathys


Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |6 ++
 1 file changed, 6 insertions(+)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index faaa4a0..69018bc 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -17,6 +17,12 @@
  */
 #define NVRAM_SIZE 64

+/* Flags definitions */
+#define SECONDS_CH 0x80
+#define HOURS_12   0x40
+#define HOURS_PM   0x20
+#define CTRL_OSF   0x20
+
 typedef struct {
 I2CSlave i2c;
 int64_t offset;
--
1.7.10.4




Re: [Qemu-devel] [PATCH v3 1/6] hw/ds1338.c: Correct bug in conversion to BCD.

2012-12-12 Thread Antoine Mathys


Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index b576d56..faaa4a0 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -57,9 +57,9 @@ static void capture_current_time(DS1338State *s)
 } else {
 s-nvram[2] = to_bcd(now.tm_hour);
 }
-s-nvram[3] = to_bcd(now.tm_wday) + 1;
+s-nvram[3] = to_bcd(now.tm_wday + 1);
 s-nvram[4] = to_bcd(now.tm_mday);
-s-nvram[5] = to_bcd(now.tm_mon) + 1;
+s-nvram[5] = to_bcd(now.tm_mon + 1);
 s-nvram[6] = to_bcd(now.tm_year - 100);
 }

--
1.7.10.4




Re: [Qemu-devel] [PATCH v3 5/6] hw/ds1338.c: Implement support for the control register.

2012-12-12 Thread Antoine Mathys


Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |   17 +
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index d2f52fc..94a2f54 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -125,7 +125,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 s-addr_byte = false;
 return 0;
 }
-if (s-ptr  8) {
+if (s-ptr  7) {
+/* Time register. */
 struct tm now;
 qemu_get_timedate(now, s-offset);
 switch(s-ptr) {
@@ -162,11 +163,19 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 case 6:
 now.tm_year = from_bcd(data) + 100;
 break;
-case 7:
-/* Control register. Currently ignored.  */
-break;
 }
 s-offset = qemu_timedate_diff(now);
+} else if (s-ptr == 7) {
+/* 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);
+
+s-nvram[s-ptr] = data;
 } else {
 s-nvram[s-ptr] = data;
 }
--
1.7.10.4




Re: [Qemu-devel] [PATCH v3 3/6] hw/ds1338.c: Fix handling of HOURS register.

2012-12-12 Thread Antoine Mathys

 Per the datasheet, the mapping between 12 and 24 hours modes is:
  0  -  12   PM
  1-12   -  1-12 AM
  13-23  -  1-11 PM

Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |   29 ++---
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index 69018bc..0f88720 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -55,10 +55,15 @@ static void capture_current_time(DS1338State *s)
 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]  0x40) {
-s-nvram[2] = (to_bcd((now.tm_hour % 12)) + 1) | 0x40;
-if (now.tm_hour = 12) {
-s-nvram[2] |= 0x20;
+if (s-nvram[2]  HOURS_12) {
+int tmp = now.tm_hour;
+if (tmp == 0) {
+tmp = 24;
+}
+if (tmp = 12) {
+s-nvram[2] = HOURS_12 | to_bcd(tmp);
+} else {
+s-nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
 }
 } else {
 s-nvram[2] = to_bcd(now.tm_hour);
@@ -132,16 +137,18 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 now.tm_min = from_bcd(data  0x7f);
 break;
 case 2:
-if (data  0x40) {
-if (data  0x20) {
-data = from_bcd(data  0x4f) + 11;
-} else {
-data = from_bcd(data  0x1f) - 1;
+if (data  HOURS_12) {
+int tmp = from_bcd(data  (HOURS_PM - 1));
+if (data  HOURS_PM) {
+tmp += 12;
+}
+if (tmp == 24) {
+tmp = 0;
 }
+now.tm_hour = tmp;
 } else {
-data = from_bcd(data);
+now.tm_hour = from_bcd(data  (HOURS_12 - 1));
 }
-now.tm_hour = data;
 break;
 case 3:
 now.tm_wday = from_bcd(data  7) - 1;
--
1.7.10.4




Re: [Qemu-devel] [PATCH v3 6/6] hw/ds1338.c: Fix handling of DAY (wday) register.

2012-12-12 Thread Antoine Mathys

Per the datasheet, the DAY (wday) register is user defined. Implement this.

Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |   15 ---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index 94a2f54..1aefa3b 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -26,6 +26,7 @@
 typedef struct {
 I2CSlave i2c;
 int64_t offset;
+uint8_t wday_offset;
 uint8_t nvram[NVRAM_SIZE];
 int32_t ptr;
 bool addr_byte;
@@ -33,12 +34,13 @@ typedef struct {

 static const VMStateDescription vmstate_ds1338 = {
 .name = ds1338,
-.version_id = 1,
+.version_id = 2,
 .minimum_version_id = 1,
 .minimum_version_id_old = 1,
 .fields = (VMStateField[]) {
 VMSTATE_I2C_SLAVE(i2c, 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),
@@ -68,7 +70,7 @@ static void capture_current_time(DS1338State *s)
 } else {
 s-nvram[2] = to_bcd(now.tm_hour);
 }
-s-nvram[3] = to_bcd(now.tm_wday + 1);
+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);
@@ -152,7 +154,13 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 }
 break;
 case 3:
-now.tm_wday = from_bcd(data  7) - 1;
+{
+/* 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 4:
 now.tm_mday = from_bcd(data  0x3f);
@@ -194,6 +202,7 @@ static void ds1338_reset(DeviceState *dev)

 /* The clock is running and synchronized with the host */
 s-offset = 0;
+s-wday_offset = 0;
 memset(s-nvram, 0, NVRAM_SIZE);
 s-ptr = 0;
 s-addr_byte = false;
--
1.7.10.4




Re: [Qemu-devel] [PATCH v3 4/6] hw/ds1338.c: Ensure state is properly initialized.

2012-12-12 Thread Antoine Mathys


Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |   51 ++-
 1 file changed, 38 insertions(+), 13 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index b576d56..d2f52fc 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -17,6 +17,12 @@
  */
 #define NVRAM_SIZE 64

+/* Flags definitions */
+#define SECONDS_CH 0x80
+#define HOURS_12   0x40
+#define HOURS_PM   0x20
+#define CTRL_OSF   0x20
+
 typedef struct {
 I2CSlave i2c;
 int64_t offset;
@@ -49,17 +55,22 @@ static void capture_current_time(DS1338State *s)
 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]  0x40) {
-s-nvram[2] = (to_bcd((now.tm_hour % 12)) + 1) | 0x40;
-if (now.tm_hour = 12) {
-s-nvram[2] |= 0x20;
+if (s-nvram[2]  HOURS_12) {
+int tmp = now.tm_hour;
+if (tmp == 0) {
+tmp = 24;
+}
+if (tmp = 12) {
+s-nvram[2] = HOURS_12 | to_bcd(tmp);
+} else {
+s-nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
 }
 } else {
 s-nvram[2] = to_bcd(now.tm_hour);
 }
-s-nvram[3] = to_bcd(now.tm_wday) + 1;
+s-nvram[3] = to_bcd(now.tm_wday + 1);
 s-nvram[4] = to_bcd(now.tm_mday);
-s-nvram[5] = to_bcd(now.tm_mon) + 1;
+s-nvram[5] = to_bcd(now.tm_mon + 1);
 s-nvram[6] = to_bcd(now.tm_year - 100);
 }

@@ -126,16 +137,18 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 now.tm_min = from_bcd(data  0x7f);
 break;
 case 2:
-if (data  0x40) {
-if (data  0x20) {
-data = from_bcd(data  0x4f) + 11;
-} else {
-data = from_bcd(data  0x1f) - 1;
+if (data  HOURS_12) {
+int tmp = from_bcd(data  (HOURS_PM - 1));
+if (data  HOURS_PM) {
+tmp += 12;
 }
+if (tmp == 24) {
+tmp = 0;
+}
+now.tm_hour = tmp;
 } else {
-data = from_bcd(data);
+now.tm_hour = from_bcd(data  (HOURS_12 - 1));
 }
-now.tm_hour = data;
 break;
 case 3:
 now.tm_wday = from_bcd(data  7) - 1;
@@ -166,6 +179,17 @@ static int ds1338_init(I2CSlave *i2c)
 return 0;
 }

+static void ds1338_reset(DeviceState *dev)
+{
+DS1338State *s = FROM_I2C_SLAVE(DS1338State, I2C_SLAVE_FROM_QDEV(dev));
+
+/* The clock is running and synchronized with the host */
+s-offset = 0;
+memset(s-nvram, 0, NVRAM_SIZE);
+s-ptr = 0;
+s-addr_byte = false;
+}
+
 static void ds1338_class_init(ObjectClass *klass, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(klass);
@@ -175,6 +199,7 @@ static void ds1338_class_init(ObjectClass *klass, 
void *data)

 k-event = ds1338_event;
 k-recv = ds1338_recv;
 k-send = ds1338_send;
+dc-reset = ds1338_reset;
 dc-vmsd = vmstate_ds1338;
 }

--
1.7.10.4




Re: [Qemu-devel] [PATCH v3 4/6] hw/ds1338.c: Ensure state is properly initialized.

2012-12-12 Thread Antoine Mathys

Oops. There was a problem in the patch. Resending the series.



[Qemu-devel] [PATCH v4 0/6] hw/ds1338.c

2012-12-12 Thread Antoine Mathys





[Qemu-devel] [PATCH v4 1/6] hw/ds1338.c: Correct bug in conversion to BCD.

2012-12-12 Thread Antoine Mathys


Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index b576d56..faaa4a0 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -57,9 +57,9 @@ static void capture_current_time(DS1338State *s)
 } else {
 s-nvram[2] = to_bcd(now.tm_hour);
 }
-s-nvram[3] = to_bcd(now.tm_wday) + 1;
+s-nvram[3] = to_bcd(now.tm_wday + 1);
 s-nvram[4] = to_bcd(now.tm_mday);
-s-nvram[5] = to_bcd(now.tm_mon) + 1;
+s-nvram[5] = to_bcd(now.tm_mon + 1);
 s-nvram[6] = to_bcd(now.tm_year - 100);
 }

--
1.7.10.4




[Qemu-devel] [PATCH v4 2/6] hw/ds1338.c: Add definitions for various flags in the RTC registers.

2012-12-12 Thread Antoine Mathys


Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |6 ++
 1 file changed, 6 insertions(+)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index faaa4a0..69018bc 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -17,6 +17,12 @@
  */
 #define NVRAM_SIZE 64

+/* Flags definitions */
+#define SECONDS_CH 0x80
+#define HOURS_12   0x40
+#define HOURS_PM   0x20
+#define CTRL_OSF   0x20
+
 typedef struct {
 I2CSlave i2c;
 int64_t offset;
--
1.7.10.4




[Qemu-devel] [PATCH v4 3/6] hw/ds1338.c: Fix handling of HOURS register.

2012-12-12 Thread Antoine Mathys

Per the datasheet, the mapping between 12 and 24 hours modes is:
  0  -  12   PM
  1-12   -  1-12 AM
  13-23  -  1-11 PM

Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |   29 ++---
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index 69018bc..0f88720 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -55,10 +55,15 @@ static void capture_current_time(DS1338State *s)
 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]  0x40) {
-s-nvram[2] = (to_bcd((now.tm_hour % 12)) + 1) | 0x40;
-if (now.tm_hour = 12) {
-s-nvram[2] |= 0x20;
+if (s-nvram[2]  HOURS_12) {
+int tmp = now.tm_hour;
+if (tmp == 0) {
+tmp = 24;
+}
+if (tmp = 12) {
+s-nvram[2] = HOURS_12 | to_bcd(tmp);
+} else {
+s-nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
 }
 } else {
 s-nvram[2] = to_bcd(now.tm_hour);
@@ -132,16 +137,18 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 now.tm_min = from_bcd(data  0x7f);
 break;
 case 2:
-if (data  0x40) {
-if (data  0x20) {
-data = from_bcd(data  0x4f) + 11;
-} else {
-data = from_bcd(data  0x1f) - 1;
+if (data  HOURS_12) {
+int tmp = from_bcd(data  (HOURS_PM - 1));
+if (data  HOURS_PM) {
+tmp += 12;
+}
+if (tmp == 24) {
+tmp = 0;
 }
+now.tm_hour = tmp;
 } else {
-data = from_bcd(data);
+now.tm_hour = from_bcd(data  (HOURS_12 - 1));
 }
-now.tm_hour = data;
 break;
 case 3:
 now.tm_wday = from_bcd(data  7) - 1;
--
1.7.10.4




[Qemu-devel] [PATCH v4 4/6] hw/ds1338.c: Ensure state is properly initialized.

2012-12-12 Thread Antoine Mathys


Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |   12 
 1 file changed, 12 insertions(+)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index 0f88720..d2f52fc 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -179,6 +179,17 @@ static int ds1338_init(I2CSlave *i2c)
 return 0;
 }

+static void ds1338_reset(DeviceState *dev)
+{
+DS1338State *s = FROM_I2C_SLAVE(DS1338State, I2C_SLAVE_FROM_QDEV(dev));
+
+/* The clock is running and synchronized with the host */
+s-offset = 0;
+memset(s-nvram, 0, NVRAM_SIZE);
+s-ptr = 0;
+s-addr_byte = false;
+}
+
 static void ds1338_class_init(ObjectClass *klass, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(klass);
@@ -188,6 +199,7 @@ static void ds1338_class_init(ObjectClass *klass, 
void *data)

 k-event = ds1338_event;
 k-recv = ds1338_recv;
 k-send = ds1338_send;
+dc-reset = ds1338_reset;
 dc-vmsd = vmstate_ds1338;
 }

--
1.7.10.4




[Qemu-devel] [PATCH v4 6/6] hw/ds1338.c: Fix handling of DAY (wday) register.

2012-12-12 Thread Antoine Mathys

Per the datasheet, the DAY (wday) register is user defined. Implement this.

Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |   15 ---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index 94a2f54..1aefa3b 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -26,6 +26,7 @@
 typedef struct {
 I2CSlave i2c;
 int64_t offset;
+uint8_t wday_offset;
 uint8_t nvram[NVRAM_SIZE];
 int32_t ptr;
 bool addr_byte;
@@ -33,12 +34,13 @@ typedef struct {

 static const VMStateDescription vmstate_ds1338 = {
 .name = ds1338,
-.version_id = 1,
+.version_id = 2,
 .minimum_version_id = 1,
 .minimum_version_id_old = 1,
 .fields = (VMStateField[]) {
 VMSTATE_I2C_SLAVE(i2c, 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),
@@ -68,7 +70,7 @@ static void capture_current_time(DS1338State *s)
 } else {
 s-nvram[2] = to_bcd(now.tm_hour);
 }
-s-nvram[3] = to_bcd(now.tm_wday + 1);
+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);
@@ -152,7 +154,13 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 }
 break;
 case 3:
-now.tm_wday = from_bcd(data  7) - 1;
+{
+/* 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 4:
 now.tm_mday = from_bcd(data  0x3f);
@@ -194,6 +202,7 @@ static void ds1338_reset(DeviceState *dev)

 /* The clock is running and synchronized with the host */
 s-offset = 0;
+s-wday_offset = 0;
 memset(s-nvram, 0, NVRAM_SIZE);
 s-ptr = 0;
 s-addr_byte = false;
--
1.7.10.4




[Qemu-devel] [PATCH v4 5/6] hw/ds1338.c: Implement support for the control register.

2012-12-12 Thread Antoine Mathys


Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |   17 +
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index d2f52fc..94a2f54 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -125,7 +125,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 s-addr_byte = false;
 return 0;
 }
-if (s-ptr  8) {
+if (s-ptr  7) {
+/* Time register. */
 struct tm now;
 qemu_get_timedate(now, s-offset);
 switch(s-ptr) {
@@ -162,11 +163,19 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 case 6:
 now.tm_year = from_bcd(data) + 100;
 break;
-case 7:
-/* Control register. Currently ignored.  */
-break;
 }
 s-offset = qemu_timedate_diff(now);
+} else if (s-ptr == 7) {
+/* 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);
+
+s-nvram[s-ptr] = data;
 } else {
 s-nvram[s-ptr] = data;
 }
--
1.7.10.4




[Qemu-devel] [PATCH v2 0/6] hw/ds1338.c

2012-12-11 Thread Antoine Mathys

This is the second version of my series of patch to hw/ds1338.c
It should address the various points that were made. The main difference 
with the previous version is that I dropped some stuff that will only be 
useful once we implement clock enable/disable.




[Qemu-devel] [PATCH v2 1/6] hw/ds1338.c: Correct bug in conversion to BCD.

2012-12-11 Thread Antoine Mathys

Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index b576d56..faaa4a0 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -57,9 +57,9 @@ static void capture_current_time(DS1338State *s)
 } else {
 s-nvram[2] = to_bcd(now.tm_hour);
 }
-s-nvram[3] = to_bcd(now.tm_wday) + 1;
+s-nvram[3] = to_bcd(now.tm_wday + 1);
 s-nvram[4] = to_bcd(now.tm_mday);
-s-nvram[5] = to_bcd(now.tm_mon) + 1;
+s-nvram[5] = to_bcd(now.tm_mon + 1);
 s-nvram[6] = to_bcd(now.tm_year - 100);
 }

--
1.7.10.4




[Qemu-devel] [PATCH v2 2/6] hw/ds1338.c: Add definitions for various flags in the RTC registers.

2012-12-11 Thread Antoine Mathys

Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |6 ++
 1 file changed, 6 insertions(+)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index faaa4a0..69018bc 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -17,6 +17,12 @@
  */
 #define NVRAM_SIZE 64

+/* Flags definitions */
+#define SECONDS_CH 0x80
+#define HOURS_12   0x40
+#define HOURS_PM   0x20
+#define CTRL_OSF   0x20
+
 typedef struct {
 I2CSlave i2c;
 int64_t offset;
--
1.7.10.4




[Qemu-devel] [PATCH v2 3/6] hw/ds1338.c: Fix handling of HOURS register.

2012-12-11 Thread Antoine Mathys

Per the datasheet, the mapping between 12 and 24 hours modes is:
 0  -  12   PM
 1-12   -  1-12 AM
 13-23  -  1-11 PM

Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |   29 ++---
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index 69018bc..0f88720 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -55,10 +55,15 @@ static void capture_current_time(DS1338State *s)
 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]  0x40) {
-s-nvram[2] = (to_bcd((now.tm_hour % 12)) + 1) | 0x40;
-if (now.tm_hour = 12) {
-s-nvram[2] |= 0x20;
+if (s-nvram[2]  HOURS_12) {
+int tmp = now.tm_hour;
+if (tmp == 0) {
+tmp = 24;
+}
+if (tmp = 12) {
+s-nvram[2] = HOURS_12 | to_bcd(tmp);
+} else {
+s-nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
 }
 } else {
 s-nvram[2] = to_bcd(now.tm_hour);
@@ -132,16 +137,18 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 now.tm_min = from_bcd(data  0x7f);
 break;
 case 2:
-if (data  0x40) {
-if (data  0x20) {
-data = from_bcd(data  0x4f) + 11;
-} else {
-data = from_bcd(data  0x1f) - 1;
+if (data  HOURS_12) {
+int tmp = from_bcd(data  (HOURS_PM - 1));
+if (data  HOURS_PM) {
+tmp += 12;
+}
+if (tmp == 24) {
+tmp = 0;
 }
+now.tm_hour = tmp;
 } else {
-data = from_bcd(data);
+now.tm_hour = from_bcd(data  (HOURS_12 - 1));
 }
-now.tm_hour = data;
 break;
 case 3:
 now.tm_wday = from_bcd(data  7) - 1;
--
1.7.10.4




[Qemu-devel] [PATCH v2 4/6] hw/ds1338.c: Ensure state is properly initialized.

2012-12-11 Thread Antoine Mathys

Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |   10 ++
 1 file changed, 10 insertions(+)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index 0f88720..b4d5b74 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -179,6 +179,15 @@ static int ds1338_init(I2CSlave *i2c)
 return 0;
 }

+static void ds1338_reset(DeviceState *dev)
+{
+DS1338State *s = FROM_I2C_SLAVE(DS1338State, I2C_SLAVE_FROM_QDEV(dev));
+
+/* The clock is running and synchronized with the host */
+s-offset = 0;
+memset(s-nvram, 0, NVRAM_SIZE);
+}
+
 static void ds1338_class_init(ObjectClass *klass, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(klass);
@@ -188,6 +197,7 @@ static void ds1338_class_init(ObjectClass *klass, 
void *data)

 k-event = ds1338_event;
 k-recv = ds1338_recv;
 k-send = ds1338_send;
+dc-reset = ds1338_reset;
 dc-vmsd = vmstate_ds1338;
 }

--
1.7.10.4




[Qemu-devel] [PATCH v2 5/6] hw/ds1338.c: Implement support for the control register.

2012-12-11 Thread Antoine Mathys
The previous patch has the side effect of clearing the control register. 
That's already its proper power-on-reset value.


Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |   17 +
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index 5a6234b..319c341 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -125,7 +125,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 s-addr_byte = false;
 return 0;
 }
-if (s-ptr  8) {
+if (s-ptr  7) {
+/* Time register. */
 struct tm now;
 qemu_get_timedate(now, s-offset);
 switch(s-ptr) {
@@ -162,11 +163,19 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 case 6:
 now.tm_year = from_bcd(data) + 100;
 break;
-case 7:
-/* Control register. Currently ignored.  */
-break;
 }
 s-offset = qemu_timedate_diff(now);
+} else if (s-ptr == 7) {
+/* 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);
+
+s-nvram[s-ptr] = data;
 } else {
 s-nvram[s-ptr] = data;
 }
--
1.7.10.4




[Qemu-devel] [PATCH v2 6/6] hw/ds1338.c: Fix handling of DAY (wday) register.

2012-12-11 Thread Antoine Mathys

Per the datasheet, the DAY (wday) register is user defined. Implement this.

Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |   15 ---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index 319c341..c5cee99 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -26,6 +26,7 @@
 typedef struct {
 I2CSlave i2c;
 int64_t offset;
+uint8_t wday_offset;
 uint8_t nvram[NVRAM_SIZE];
 int32_t ptr;
 bool addr_byte;
@@ -33,12 +34,13 @@ typedef struct {

 static const VMStateDescription vmstate_ds1338 = {
 .name = ds1338,
-.version_id = 1,
+.version_id = 2,
 .minimum_version_id = 1,
 .minimum_version_id_old = 1,
 .fields = (VMStateField[]) {
 VMSTATE_I2C_SLAVE(i2c, 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),
@@ -68,7 +70,7 @@ static void capture_current_time(DS1338State *s)
 } else {
 s-nvram[2] = to_bcd(now.tm_hour);
 }
-s-nvram[3] = to_bcd(now.tm_wday + 1);
+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);
@@ -152,7 +154,13 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 }
 break;
 case 3:
-now.tm_wday = from_bcd(data  7) - 1;
+{
+/* 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 4:
 now.tm_mday = from_bcd(data  0x3f);
@@ -194,6 +202,7 @@ static void ds1338_reset(DeviceState *dev)

 /* The clock is running and synchronized with the host */
 s-offset = 0;
+s-wday_offset = 0;
 memset(s-nvram, 0, NVRAM_SIZE);
 }

--
1.7.10.4




Re: [Qemu-devel] [PATCH 1/4] hw/ds1338.c: Fix handling of HOURS register.

2012-12-04 Thread Antoine Mathys

On 12/04/2012 06:42 PM, Peter Maydell wrote:
This looks good as far as the logic goes, but I think we could use 
some symbolic constants for the 12-hour and PM bits rather than all 
the literal 0x20 0x40 0x60. thanks -- PMM 

I refrained from using symbolic constants for three reasons:
1. You need to refer to the datasheet anyway to understand what is going on.
2. The code is short and it is easy to keep track of a few constants.
3. Symbolic names, which can be quite long, tend to make the code harder 
rather than easier to read


It is largely a matter of preference though and I'm not opposed to the 
idea. I would appreciate naming suggestions though.


I propose not to have symbolic constants for the registers and to use 
CH, OSF, MODE12, PM for the various bits, provided such short names are 
acceptable. I'd really hate something like REG_HOURS_MODE12.





[Qemu-devel] [PATCH 5/?] hw/ds1338.c: Fix handling of DATE (wday) register

2012-12-03 Thread Antoine Mathys

Per the datasheet, the DATE (wday) register is user defined. Implement this.

Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |   14 --
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index 8f85635..c502934 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -20,6 +20,7 @@
 typedef struct {
 I2CSlave i2c;
 int64_t offset;
+uint8_t wday_offset;
 uint8_t nvram[NVRAM_SIZE];
 int32_t ptr;
 bool addr_byte;
@@ -33,6 +34,7 @@ static const VMStateDescription vmstate_ds1338 = {
 .fields = (VMStateField[]) {
 VMSTATE_I2C_SLAVE(i2c, DS1338State),
 VMSTATE_INT64(offset, DS1338State),
+VMSTATE_UINT8(wday_offset, DS1338State),
 VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE),
 VMSTATE_INT32(ptr, DS1338State),
 VMSTATE_BOOL(addr_byte, DS1338State),
@@ -62,7 +64,7 @@ static void write_time(DS1338State *s, const struct tm 
*tm)

 } else {
 s-nvram[2] = to_bcd(tm-tm_hour);
 }
-s-nvram[3] = to_bcd(tm-tm_wday + 1);
+s-nvram[3] = to_bcd((tm-tm_wday + s-wday_offset) % 7 + 1);
 s-nvram[4] = to_bcd(tm-tm_mday);
 s-nvram[5] = to_bcd(tm-tm_mon + 1);
 s-nvram[6] = to_bcd(tm-tm_year - 100);
@@ -164,7 +166,12 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 }
 break;
 case 3:
-now.tm_wday = from_bcd(data  0x07) - 1;
+{
+int user_wday = from_bcd(data  0x07) - 1;
+if ((user_wday = 0)  (user_wday = 6)) {
+s-wday_offset = (user_wday - now.tm_wday + 7) % 7;
+}
+}
 break;
 case 4:
 now.tm_mday = from_bcd(data  0x3f);
@@ -194,6 +201,9 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)

 static int ds1338_init(I2CSlave *i2c)
 {
+DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
+s-wday_offset = 0;
+
 return 0;
 }

--
1.7.10.4




[Qemu-devel] [PATCH 1/4] hw/ds1338.c: Fix handling of HOURS register.

2012-12-02 Thread Antoine Mathys

Per the datasheet, the mapping between 12 and 24 hours modes is:
0  -  12   PM
1-12   -  1-12 AM
13-23  -  1-11 PM

Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |   23 +++
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index b576d56..1274b22 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -50,9 +50,14 @@ static void capture_current_time(DS1338State *s)
 s-nvram[0] = to_bcd(now.tm_sec);
 s-nvram[1] = to_bcd(now.tm_min);
 if (s-nvram[2]  0x40) {
-s-nvram[2] = (to_bcd((now.tm_hour % 12)) + 1) | 0x40;
-if (now.tm_hour = 12) {
-s-nvram[2] |= 0x20;
+int tmp = now.tm_hour;
+if (tmp == 0) {
+tmp = 24;
+}
+if (tmp = 12) {
+s-nvram[2] = 0x40 | to_bcd(tmp);
+} else {
+s-nvram[2] = 0x60 | to_bcd(tmp - 12);
 }
 } else {
 s-nvram[2] = to_bcd(now.tm_hour);
@@ -127,15 +132,17 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 break;
 case 2:
 if (data  0x40) {
+int tmp = from_bcd(data  0x1f);
 if (data  0x20) {
-data = from_bcd(data  0x4f) + 11;
-} else {
-data = from_bcd(data  0x1f) - 1;
+tmp += 12;
+}
+if (tmp == 24) {
+tmp = 0;
 }
+now.tm_hour = tmp;
 } else {
-data = from_bcd(data);
+now.tm_hour = from_bcd(data  0x3f);
 }
-now.tm_hour = data;
 break;
 case 3:
 now.tm_wday = from_bcd(data  7) - 1;
--
1.7.10.4




[Qemu-devel] [PATCH 2/4] hw/ds1338.c: Minor fixes

2012-12-02 Thread Antoine Mathys

Minor fixes in the handling of the RTC registers.

Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |   15 ---
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index 1274b22..1fb152e 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -62,9 +62,9 @@ static void capture_current_time(DS1338State *s)
 } else {
 s-nvram[2] = to_bcd(now.tm_hour);
 }
-s-nvram[3] = to_bcd(now.tm_wday) + 1;
+s-nvram[3] = to_bcd(now.tm_wday + 1);
 s-nvram[4] = to_bcd(now.tm_mday);
-s-nvram[5] = to_bcd(now.tm_mon) + 1;
+s-nvram[5] = to_bcd(now.tm_mon + 1);
 s-nvram[6] = to_bcd(now.tm_year - 100);
 }

@@ -119,7 +119,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 s-addr_byte = false;
 return 0;
 }
-if (s-ptr  8) {
+if (s-ptr  7) {
+/* Time register. */
 struct tm now;
 qemu_get_timedate(now, s-offset);
 switch(s-ptr) {
@@ -145,7 +146,7 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 }
 break;
 case 3:
-now.tm_wday = from_bcd(data  7) - 1;
+now.tm_wday = from_bcd(data  0x07) - 1;
 break;
 case 4:
 now.tm_mday = from_bcd(data  0x3f);
@@ -156,11 +157,11 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 case 6:
 now.tm_year = from_bcd(data) + 100;
 break;
-case 7:
-/* Control register. Currently ignored.  */
-break;
 }
 s-offset = qemu_timedate_diff(now);
+} else if (s-ptr == 7) {
+/* Control register. Currently ignored.  */
+s-nvram[s-ptr] = data;
 } else {
 s-nvram[s-ptr] = data;
 }
--
1.7.10.4




[Qemu-devel] [PATCH 3/4] hw/ds1338.c: ensure OSF can only be cleared

2012-12-02 Thread Antoine Mathys
Per the datasheet, the OSF bit in the control register can only be 
cleared. Attempts to set it have no effect. Implement this.


Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index 1fb152e..f3c6bc5 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -160,7 +160,12 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 }
 s-offset = qemu_timedate_diff(now);
 } else if (s-ptr == 7) {
-/* Control register. Currently ignored.  */
+/* Control register. */
+
+/* Attempting to write the OSF flag to logic 1 leaves the
+   value unchanged. */
+data = (data  0xDF) | (data  s-nvram[s-ptr]  0x20);
+
 s-nvram[s-ptr] = data;
 } else {
 s-nvram[s-ptr] = data;
--
1.7.10.4




[Qemu-devel] [PATCH 4/4] hw/ds1338.c: Handle stuck bits and preserve CH

2012-12-02 Thread Antoine Mathys

Preserve the CH bit when updating the time.

Per the datasheet, some bits in the first eight registers must always 
read back as zero. These registers can be written in two ways:

1. By ourselves when we update the registers with the current time.
2. By user request
Even though (1) is not supposed to set these bits it is safer to check 
anyway. In order not to duplicate this logic I thus chose to enforce it 
at read time.
Note that currently we don't preserve what the user sends in (2). We 
will have to once we support stopping the clock (CH bit).


Signed-off-by: Antoine Mathys barsa...@gmail.com
---
 hw/ds1338.c |   50 ++
 1 file changed, 34 insertions(+), 16 deletions(-)

diff --git a/hw/ds1338.c b/hw/ds1338.c
index f3c6bc5..8f85635 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -40,17 +40,17 @@ static const VMStateDescription vmstate_ds1338 = {
 }
 };

-static void capture_current_time(DS1338State *s)
+/* Write TM to the RTC registers. */
+static void write_time(DS1338State *s, const struct tm *tm)
 {
-/* Capture the current time into the secondary registers
- * which will be actually read by the data transfer operation.
- */
-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);
+/* Preserve the CH flag. */
+s-nvram[0] = 0x80;
+s-nvram[0] |= to_bcd(tm-tm_sec);
+
+s-nvram[1] = to_bcd(tm-tm_min);
+
 if (s-nvram[2]  0x40) {
-int tmp = now.tm_hour;
+int tmp = tm-tm_hour;
 if (tmp == 0) {
 tmp = 24;
 }
@@ -60,12 +60,30 @@ static void capture_current_time(DS1338State *s)
 s-nvram[2] = 0x60 | to_bcd(tmp - 12);
 }
 } else {
-s-nvram[2] = to_bcd(now.tm_hour);
+s-nvram[2] = to_bcd(tm-tm_hour);
 }
-s-nvram[3] = to_bcd(now.tm_wday + 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[3] = to_bcd(tm-tm_wday + 1);
+s-nvram[4] = to_bcd(tm-tm_mday);
+s-nvram[5] = to_bcd(tm-tm_mon + 1);
+s-nvram[6] = to_bcd(tm-tm_year - 100);
+}
+
+static void update_read_buffer(DS1338State *s)
+{
+/* Capture the current time into the secondary registers
+ * which will be actually read by the data transfer operation.
+ */
+struct tm now;
+qemu_get_timedate(now, s-offset);
+write_time(s, now);
+
+/* Ensure specified bits read as zero. */
+s-nvram[1] = 0x7F;
+s-nvram[2] = 0x7F;
+s-nvram[3] = 0x07;
+s-nvram[4] = 0x3F;
+s-nvram[5] = 0x1F;
+s-nvram[7] = 0xB3;
 }

 static void inc_regptr(DS1338State *s)
@@ -76,7 +94,7 @@ static void inc_regptr(DS1338State *s)
  */
 s-ptr = (s-ptr + 1)  (NVRAM_SIZE - 1);
 if (!s-ptr) {
-capture_current_time(s);
+update_read_buffer(s);
 }
 }

@@ -91,7 +109,7 @@ static void ds1338_event(I2CSlave *i2c, enum 
i2c_event event)

  * START_SEND, because the guest can't get at that data
  * without going through a START_RECV which would overwrite it.
  */
-capture_current_time(s);
+update_read_buffer(s);
 break;
 case I2C_START_SEND:
 s-addr_byte = true;
--
1.7.10.4