syborg_rtc.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /*
  2. * Syborg RTC
  3. *
  4. * Copyright (c) 2008 CodeSourcery
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "sysbus.h"
  25. #include "qemu-timer.h"
  26. #include "syborg.h"
  27. enum {
  28. RTC_ID = 0,
  29. RTC_LATCH = 1,
  30. RTC_DATA_LOW = 2,
  31. RTC_DATA_HIGH = 3
  32. };
  33. typedef struct {
  34. SysBusDevice busdev;
  35. int64_t offset;
  36. int64_t data;
  37. qemu_irq irq;
  38. } SyborgRTCState;
  39. static uint32_t syborg_rtc_read(void *opaque, target_phys_addr_t offset)
  40. {
  41. SyborgRTCState *s = (SyborgRTCState *)opaque;
  42. offset &= 0xfff;
  43. switch (offset >> 2) {
  44. case RTC_ID:
  45. return SYBORG_ID_RTC;
  46. case RTC_DATA_LOW:
  47. return (uint32_t)s->data;
  48. case RTC_DATA_HIGH:
  49. return (uint32_t)(s->data >> 32);
  50. default:
  51. cpu_abort(cpu_single_env, "syborg_rtc_read: Bad offset %x\n",
  52. (int)offset);
  53. return 0;
  54. }
  55. }
  56. static void syborg_rtc_write(void *opaque, target_phys_addr_t offset, uint32_t value)
  57. {
  58. SyborgRTCState *s = (SyborgRTCState *)opaque;
  59. uint64_t now;
  60. offset &= 0xfff;
  61. switch (offset >> 2) {
  62. case RTC_LATCH:
  63. now = qemu_get_clock_ns(vm_clock);
  64. if (value >= 4) {
  65. s->offset = s->data - now;
  66. } else {
  67. s->data = now + s->offset;
  68. while (value) {
  69. s->data /= 1000;
  70. value--;
  71. }
  72. }
  73. break;
  74. case RTC_DATA_LOW:
  75. s->data = (s->data & ~(uint64_t)0xffffffffu) | value;
  76. break;
  77. case RTC_DATA_HIGH:
  78. s->data = (s->data & 0xffffffffu) | ((uint64_t)value << 32);
  79. break;
  80. default:
  81. cpu_abort(cpu_single_env, "syborg_rtc_write: Bad offset %x\n",
  82. (int)offset);
  83. break;
  84. }
  85. }
  86. static CPUReadMemoryFunc * const syborg_rtc_readfn[] = {
  87. syborg_rtc_read,
  88. syborg_rtc_read,
  89. syborg_rtc_read
  90. };
  91. static CPUWriteMemoryFunc * const syborg_rtc_writefn[] = {
  92. syborg_rtc_write,
  93. syborg_rtc_write,
  94. syborg_rtc_write
  95. };
  96. static const VMStateDescription vmstate_syborg_rtc = {
  97. .name = "syborg_keyboard",
  98. .version_id = 1,
  99. .minimum_version_id = 1,
  100. .minimum_version_id_old = 1,
  101. .fields = (VMStateField[]) {
  102. VMSTATE_INT64(offset, SyborgRTCState),
  103. VMSTATE_INT64(data, SyborgRTCState),
  104. VMSTATE_END_OF_LIST()
  105. }
  106. };
  107. static int syborg_rtc_init(SysBusDevice *dev)
  108. {
  109. SyborgRTCState *s = FROM_SYSBUS(SyborgRTCState, dev);
  110. struct tm tm;
  111. int iomemtype;
  112. iomemtype = cpu_register_io_memory(syborg_rtc_readfn,
  113. syborg_rtc_writefn, s,
  114. DEVICE_NATIVE_ENDIAN);
  115. sysbus_init_mmio(dev, 0x1000, iomemtype);
  116. qemu_get_timedate(&tm, 0);
  117. s->offset = (uint64_t)mktime(&tm) * 1000000000;
  118. vmstate_register(&dev->qdev, -1, &vmstate_syborg_rtc, s);
  119. return 0;
  120. }
  121. static void syborg_rtc_register_devices(void)
  122. {
  123. sysbus_register_dev("syborg,rtc", sizeof(SyborgRTCState), syborg_rtc_init);
  124. }
  125. device_init(syborg_rtc_register_devices)