cuda.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. /*
  2. * QEMU PowerMac CUDA device support
  3. *
  4. * Copyright (c) 2004-2007 Fabrice Bellard
  5. * Copyright (c) 2007 Jocelyn Mayer
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. * THE SOFTWARE.
  24. */
  25. #include "qemu/osdep.h"
  26. #include "qemu-common.h"
  27. #include "hw/ppc/mac.h"
  28. #include "hw/qdev-properties.h"
  29. #include "migration/vmstate.h"
  30. #include "hw/input/adb.h"
  31. #include "hw/misc/mos6522.h"
  32. #include "hw/misc/macio/cuda.h"
  33. #include "qapi/error.h"
  34. #include "qemu/timer.h"
  35. #include "sysemu/runstate.h"
  36. #include "qapi/error.h"
  37. #include "qemu/cutils.h"
  38. #include "qemu/log.h"
  39. #include "qemu/module.h"
  40. #include "trace.h"
  41. /* Bits in B data register: all active low */
  42. #define TREQ 0x08 /* Transfer request (input) */
  43. #define TACK 0x10 /* Transfer acknowledge (output) */
  44. #define TIP 0x20 /* Transfer in progress (output) */
  45. /* commands (1st byte) */
  46. #define ADB_PACKET 0
  47. #define CUDA_PACKET 1
  48. #define ERROR_PACKET 2
  49. #define TIMER_PACKET 3
  50. #define POWER_PACKET 4
  51. #define MACIIC_PACKET 5
  52. #define PMU_PACKET 6
  53. #define CUDA_TIMER_FREQ (4700000 / 6)
  54. /* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */
  55. #define RTC_OFFSET 2082844800
  56. static void cuda_receive_packet_from_host(CUDAState *s,
  57. const uint8_t *data, int len);
  58. /* MacOS uses timer 1 for calibration on startup, so we use
  59. * the timebase frequency and cuda_get_counter_value() with
  60. * cuda_get_load_time() to steer MacOS to calculate calibrate its timers
  61. * correctly for both TCG and KVM (see commit b981289c49 "PPC: Cuda: Use cuda
  62. * timer to expose tbfreq to guest" for more information) */
  63. static uint64_t cuda_get_counter_value(MOS6522State *s, MOS6522Timer *ti)
  64. {
  65. MOS6522CUDAState *mcs = container_of(s, MOS6522CUDAState, parent_obj);
  66. CUDAState *cs = container_of(mcs, CUDAState, mos6522_cuda);
  67. /* Reverse of the tb calculation algorithm that Mac OS X uses on bootup */
  68. uint64_t tb_diff = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
  69. cs->tb_frequency, NANOSECONDS_PER_SECOND) -
  70. ti->load_time;
  71. return (tb_diff * 0xBF401675E5DULL) / (cs->tb_frequency << 24);
  72. }
  73. static uint64_t cuda_get_load_time(MOS6522State *s, MOS6522Timer *ti)
  74. {
  75. MOS6522CUDAState *mcs = container_of(s, MOS6522CUDAState, parent_obj);
  76. CUDAState *cs = container_of(mcs, CUDAState, mos6522_cuda);
  77. uint64_t load_time = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
  78. cs->tb_frequency, NANOSECONDS_PER_SECOND);
  79. return load_time;
  80. }
  81. static void cuda_set_sr_int(void *opaque)
  82. {
  83. CUDAState *s = opaque;
  84. MOS6522CUDAState *mcs = &s->mos6522_cuda;
  85. MOS6522State *ms = MOS6522(mcs);
  86. MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(ms);
  87. mdc->set_sr_int(ms);
  88. }
  89. static void cuda_delay_set_sr_int(CUDAState *s)
  90. {
  91. int64_t expire;
  92. trace_cuda_delay_set_sr_int();
  93. expire = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->sr_delay_ns;
  94. timer_mod(s->sr_delay_timer, expire);
  95. }
  96. /* NOTE: TIP and TREQ are negated */
  97. static void cuda_update(CUDAState *s)
  98. {
  99. MOS6522CUDAState *mcs = &s->mos6522_cuda;
  100. MOS6522State *ms = MOS6522(mcs);
  101. ADBBusState *adb_bus = &s->adb_bus;
  102. int packet_received, len;
  103. packet_received = 0;
  104. if (!(ms->b & TIP)) {
  105. /* transfer requested from host */
  106. if (ms->acr & SR_OUT) {
  107. /* data output */
  108. if ((ms->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
  109. if (s->data_out_index < sizeof(s->data_out)) {
  110. if (s->data_out_index == 0) {
  111. adb_autopoll_block(adb_bus);
  112. }
  113. trace_cuda_data_send(ms->sr);
  114. s->data_out[s->data_out_index++] = ms->sr;
  115. cuda_delay_set_sr_int(s);
  116. }
  117. }
  118. } else {
  119. if (s->data_in_index < s->data_in_size) {
  120. /* data input */
  121. if ((ms->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
  122. ms->sr = s->data_in[s->data_in_index++];
  123. trace_cuda_data_recv(ms->sr);
  124. /* indicate end of transfer */
  125. if (s->data_in_index >= s->data_in_size) {
  126. ms->b = (ms->b | TREQ);
  127. adb_autopoll_unblock(adb_bus);
  128. }
  129. cuda_delay_set_sr_int(s);
  130. }
  131. }
  132. }
  133. } else {
  134. /* no transfer requested: handle sync case */
  135. if ((s->last_b & TIP) && (ms->b & TACK) != (s->last_b & TACK)) {
  136. /* update TREQ state each time TACK change state */
  137. if (ms->b & TACK) {
  138. ms->b = (ms->b | TREQ);
  139. } else {
  140. ms->b = (ms->b & ~TREQ);
  141. }
  142. cuda_delay_set_sr_int(s);
  143. } else {
  144. if (!(s->last_b & TIP)) {
  145. /* handle end of host to cuda transfer */
  146. packet_received = (s->data_out_index > 0);
  147. /* always an IRQ at the end of transfer */
  148. cuda_delay_set_sr_int(s);
  149. }
  150. /* signal if there is data to read */
  151. if (s->data_in_index < s->data_in_size) {
  152. ms->b = (ms->b & ~TREQ);
  153. }
  154. }
  155. }
  156. s->last_acr = ms->acr;
  157. s->last_b = ms->b;
  158. /* NOTE: cuda_receive_packet_from_host() can call cuda_update()
  159. recursively */
  160. if (packet_received) {
  161. len = s->data_out_index;
  162. s->data_out_index = 0;
  163. cuda_receive_packet_from_host(s, s->data_out, len);
  164. }
  165. }
  166. static void cuda_send_packet_to_host(CUDAState *s,
  167. const uint8_t *data, int len)
  168. {
  169. int i;
  170. trace_cuda_packet_send(len);
  171. for (i = 0; i < len; i++) {
  172. trace_cuda_packet_send_data(i, data[i]);
  173. }
  174. memcpy(s->data_in, data, len);
  175. s->data_in_size = len;
  176. s->data_in_index = 0;
  177. cuda_update(s);
  178. cuda_delay_set_sr_int(s);
  179. }
  180. static void cuda_adb_poll(void *opaque)
  181. {
  182. CUDAState *s = opaque;
  183. ADBBusState *adb_bus = &s->adb_bus;
  184. uint8_t obuf[ADB_MAX_OUT_LEN + 2];
  185. int olen;
  186. olen = adb_poll(adb_bus, obuf + 2, adb_bus->autopoll_mask);
  187. if (olen > 0) {
  188. obuf[0] = ADB_PACKET;
  189. obuf[1] = 0x40; /* polled data */
  190. cuda_send_packet_to_host(s, obuf, olen + 2);
  191. }
  192. }
  193. /* description of commands */
  194. typedef struct CudaCommand {
  195. uint8_t command;
  196. const char *name;
  197. bool (*handler)(CUDAState *s,
  198. const uint8_t *in_args, int in_len,
  199. uint8_t *out_args, int *out_len);
  200. } CudaCommand;
  201. static bool cuda_cmd_autopoll(CUDAState *s,
  202. const uint8_t *in_data, int in_len,
  203. uint8_t *out_data, int *out_len)
  204. {
  205. ADBBusState *adb_bus = &s->adb_bus;
  206. bool autopoll;
  207. if (in_len != 1) {
  208. return false;
  209. }
  210. autopoll = (in_data[0] != 0) ? true : false;
  211. adb_set_autopoll_enabled(adb_bus, autopoll);
  212. return true;
  213. }
  214. static bool cuda_cmd_set_autorate(CUDAState *s,
  215. const uint8_t *in_data, int in_len,
  216. uint8_t *out_data, int *out_len)
  217. {
  218. ADBBusState *adb_bus = &s->adb_bus;
  219. if (in_len != 1) {
  220. return false;
  221. }
  222. /* we don't want a period of 0 ms */
  223. /* FIXME: check what real hardware does */
  224. if (in_data[0] == 0) {
  225. return false;
  226. }
  227. adb_set_autopoll_rate_ms(adb_bus, in_data[0]);
  228. return true;
  229. }
  230. static bool cuda_cmd_set_device_list(CUDAState *s,
  231. const uint8_t *in_data, int in_len,
  232. uint8_t *out_data, int *out_len)
  233. {
  234. ADBBusState *adb_bus = &s->adb_bus;
  235. uint16_t mask;
  236. if (in_len != 2) {
  237. return false;
  238. }
  239. mask = (((uint16_t)in_data[0]) << 8) | in_data[1];
  240. adb_set_autopoll_mask(adb_bus, mask);
  241. return true;
  242. }
  243. static bool cuda_cmd_powerdown(CUDAState *s,
  244. const uint8_t *in_data, int in_len,
  245. uint8_t *out_data, int *out_len)
  246. {
  247. if (in_len != 0) {
  248. return false;
  249. }
  250. qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
  251. return true;
  252. }
  253. static bool cuda_cmd_reset_system(CUDAState *s,
  254. const uint8_t *in_data, int in_len,
  255. uint8_t *out_data, int *out_len)
  256. {
  257. if (in_len != 0) {
  258. return false;
  259. }
  260. qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
  261. return true;
  262. }
  263. static bool cuda_cmd_set_file_server_flag(CUDAState *s,
  264. const uint8_t *in_data, int in_len,
  265. uint8_t *out_data, int *out_len)
  266. {
  267. if (in_len != 1) {
  268. return false;
  269. }
  270. qemu_log_mask(LOG_UNIMP,
  271. "CUDA: unimplemented command FILE_SERVER_FLAG %d\n",
  272. in_data[0]);
  273. return true;
  274. }
  275. static bool cuda_cmd_set_power_message(CUDAState *s,
  276. const uint8_t *in_data, int in_len,
  277. uint8_t *out_data, int *out_len)
  278. {
  279. if (in_len != 1) {
  280. return false;
  281. }
  282. qemu_log_mask(LOG_UNIMP,
  283. "CUDA: unimplemented command SET_POWER_MESSAGE %d\n",
  284. in_data[0]);
  285. return true;
  286. }
  287. static bool cuda_cmd_get_time(CUDAState *s,
  288. const uint8_t *in_data, int in_len,
  289. uint8_t *out_data, int *out_len)
  290. {
  291. uint32_t ti;
  292. if (in_len != 0) {
  293. return false;
  294. }
  295. ti = s->tick_offset + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
  296. / NANOSECONDS_PER_SECOND);
  297. out_data[0] = ti >> 24;
  298. out_data[1] = ti >> 16;
  299. out_data[2] = ti >> 8;
  300. out_data[3] = ti;
  301. *out_len = 4;
  302. return true;
  303. }
  304. static bool cuda_cmd_set_time(CUDAState *s,
  305. const uint8_t *in_data, int in_len,
  306. uint8_t *out_data, int *out_len)
  307. {
  308. uint32_t ti;
  309. if (in_len != 4) {
  310. return false;
  311. }
  312. ti = (((uint32_t)in_data[0]) << 24) + (((uint32_t)in_data[1]) << 16)
  313. + (((uint32_t)in_data[2]) << 8) + in_data[3];
  314. s->tick_offset = ti - (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
  315. / NANOSECONDS_PER_SECOND);
  316. return true;
  317. }
  318. static const CudaCommand handlers[] = {
  319. { CUDA_AUTOPOLL, "AUTOPOLL", cuda_cmd_autopoll },
  320. { CUDA_SET_AUTO_RATE, "SET_AUTO_RATE", cuda_cmd_set_autorate },
  321. { CUDA_SET_DEVICE_LIST, "SET_DEVICE_LIST", cuda_cmd_set_device_list },
  322. { CUDA_POWERDOWN, "POWERDOWN", cuda_cmd_powerdown },
  323. { CUDA_RESET_SYSTEM, "RESET_SYSTEM", cuda_cmd_reset_system },
  324. { CUDA_FILE_SERVER_FLAG, "FILE_SERVER_FLAG",
  325. cuda_cmd_set_file_server_flag },
  326. { CUDA_SET_POWER_MESSAGES, "SET_POWER_MESSAGES",
  327. cuda_cmd_set_power_message },
  328. { CUDA_GET_TIME, "GET_TIME", cuda_cmd_get_time },
  329. { CUDA_SET_TIME, "SET_TIME", cuda_cmd_set_time },
  330. };
  331. static void cuda_receive_packet(CUDAState *s,
  332. const uint8_t *data, int len)
  333. {
  334. uint8_t obuf[16] = { CUDA_PACKET, 0, data[0] };
  335. int i, out_len = 0;
  336. for (i = 0; i < ARRAY_SIZE(handlers); i++) {
  337. const CudaCommand *desc = &handlers[i];
  338. if (desc->command == data[0]) {
  339. trace_cuda_receive_packet_cmd(desc->name);
  340. out_len = 0;
  341. if (desc->handler(s, data + 1, len - 1, obuf + 3, &out_len)) {
  342. cuda_send_packet_to_host(s, obuf, 3 + out_len);
  343. } else {
  344. qemu_log_mask(LOG_GUEST_ERROR,
  345. "CUDA: %s: wrong parameters %d\n",
  346. desc->name, len);
  347. obuf[0] = ERROR_PACKET;
  348. obuf[1] = 0x5; /* bad parameters */
  349. obuf[2] = CUDA_PACKET;
  350. obuf[3] = data[0];
  351. cuda_send_packet_to_host(s, obuf, 4);
  352. }
  353. return;
  354. }
  355. }
  356. qemu_log_mask(LOG_GUEST_ERROR, "CUDA: unknown command 0x%02x\n", data[0]);
  357. obuf[0] = ERROR_PACKET;
  358. obuf[1] = 0x2; /* unknown command */
  359. obuf[2] = CUDA_PACKET;
  360. obuf[3] = data[0];
  361. cuda_send_packet_to_host(s, obuf, 4);
  362. }
  363. static void cuda_receive_packet_from_host(CUDAState *s,
  364. const uint8_t *data, int len)
  365. {
  366. int i;
  367. trace_cuda_packet_receive(len);
  368. for (i = 0; i < len; i++) {
  369. trace_cuda_packet_receive_data(i, data[i]);
  370. }
  371. switch(data[0]) {
  372. case ADB_PACKET:
  373. {
  374. uint8_t obuf[ADB_MAX_OUT_LEN + 3];
  375. int olen;
  376. olen = adb_request(&s->adb_bus, obuf + 2, data + 1, len - 1);
  377. if (olen > 0) {
  378. obuf[0] = ADB_PACKET;
  379. obuf[1] = 0x00;
  380. cuda_send_packet_to_host(s, obuf, olen + 2);
  381. } else {
  382. /* error */
  383. obuf[0] = ADB_PACKET;
  384. obuf[1] = -olen;
  385. obuf[2] = data[1];
  386. olen = 0;
  387. cuda_send_packet_to_host(s, obuf, olen + 3);
  388. }
  389. }
  390. break;
  391. case CUDA_PACKET:
  392. cuda_receive_packet(s, data + 1, len - 1);
  393. break;
  394. }
  395. }
  396. static uint64_t mos6522_cuda_read(void *opaque, hwaddr addr, unsigned size)
  397. {
  398. CUDAState *s = opaque;
  399. MOS6522CUDAState *mcs = &s->mos6522_cuda;
  400. MOS6522State *ms = MOS6522(mcs);
  401. addr = (addr >> 9) & 0xf;
  402. return mos6522_read(ms, addr, size);
  403. }
  404. static void mos6522_cuda_write(void *opaque, hwaddr addr, uint64_t val,
  405. unsigned size)
  406. {
  407. CUDAState *s = opaque;
  408. MOS6522CUDAState *mcs = &s->mos6522_cuda;
  409. MOS6522State *ms = MOS6522(mcs);
  410. addr = (addr >> 9) & 0xf;
  411. mos6522_write(ms, addr, val, size);
  412. }
  413. static const MemoryRegionOps mos6522_cuda_ops = {
  414. .read = mos6522_cuda_read,
  415. .write = mos6522_cuda_write,
  416. .endianness = DEVICE_BIG_ENDIAN,
  417. .valid = {
  418. .min_access_size = 1,
  419. .max_access_size = 1,
  420. },
  421. };
  422. static const VMStateDescription vmstate_cuda = {
  423. .name = "cuda",
  424. .version_id = 6,
  425. .minimum_version_id = 6,
  426. .fields = (VMStateField[]) {
  427. VMSTATE_STRUCT(mos6522_cuda.parent_obj, CUDAState, 0, vmstate_mos6522,
  428. MOS6522State),
  429. VMSTATE_UINT8(last_b, CUDAState),
  430. VMSTATE_UINT8(last_acr, CUDAState),
  431. VMSTATE_INT32(data_in_size, CUDAState),
  432. VMSTATE_INT32(data_in_index, CUDAState),
  433. VMSTATE_INT32(data_out_index, CUDAState),
  434. VMSTATE_BUFFER(data_in, CUDAState),
  435. VMSTATE_BUFFER(data_out, CUDAState),
  436. VMSTATE_UINT32(tick_offset, CUDAState),
  437. VMSTATE_TIMER_PTR(sr_delay_timer, CUDAState),
  438. VMSTATE_END_OF_LIST()
  439. }
  440. };
  441. static void cuda_reset(DeviceState *dev)
  442. {
  443. CUDAState *s = CUDA(dev);
  444. ADBBusState *adb_bus = &s->adb_bus;
  445. s->data_in_size = 0;
  446. s->data_in_index = 0;
  447. s->data_out_index = 0;
  448. adb_set_autopoll_enabled(adb_bus, false);
  449. }
  450. static void cuda_realize(DeviceState *dev, Error **errp)
  451. {
  452. CUDAState *s = CUDA(dev);
  453. SysBusDevice *sbd;
  454. ADBBusState *adb_bus = &s->adb_bus;
  455. struct tm tm;
  456. if (!sysbus_realize(SYS_BUS_DEVICE(&s->mos6522_cuda), errp)) {
  457. return;
  458. }
  459. /* Pass IRQ from 6522 */
  460. sbd = SYS_BUS_DEVICE(s);
  461. sysbus_pass_irq(sbd, SYS_BUS_DEVICE(&s->mos6522_cuda));
  462. qemu_get_timedate(&tm, 0);
  463. s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
  464. s->sr_delay_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_set_sr_int, s);
  465. s->sr_delay_ns = 20 * SCALE_US;
  466. adb_register_autopoll_callback(adb_bus, cuda_adb_poll, s);
  467. }
  468. static void cuda_init(Object *obj)
  469. {
  470. CUDAState *s = CUDA(obj);
  471. SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
  472. object_initialize_child(obj, "mos6522-cuda", &s->mos6522_cuda,
  473. TYPE_MOS6522_CUDA);
  474. memory_region_init_io(&s->mem, obj, &mos6522_cuda_ops, s, "cuda", 0x2000);
  475. sysbus_init_mmio(sbd, &s->mem);
  476. qbus_create_inplace(&s->adb_bus, sizeof(s->adb_bus), TYPE_ADB_BUS,
  477. DEVICE(obj), "adb.0");
  478. }
  479. static Property cuda_properties[] = {
  480. DEFINE_PROP_UINT64("timebase-frequency", CUDAState, tb_frequency, 0),
  481. DEFINE_PROP_END_OF_LIST()
  482. };
  483. static void cuda_class_init(ObjectClass *oc, void *data)
  484. {
  485. DeviceClass *dc = DEVICE_CLASS(oc);
  486. dc->realize = cuda_realize;
  487. dc->reset = cuda_reset;
  488. dc->vmsd = &vmstate_cuda;
  489. device_class_set_props(dc, cuda_properties);
  490. set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
  491. }
  492. static const TypeInfo cuda_type_info = {
  493. .name = TYPE_CUDA,
  494. .parent = TYPE_SYS_BUS_DEVICE,
  495. .instance_size = sizeof(CUDAState),
  496. .instance_init = cuda_init,
  497. .class_init = cuda_class_init,
  498. };
  499. static void mos6522_cuda_portB_write(MOS6522State *s)
  500. {
  501. MOS6522CUDAState *mcs = container_of(s, MOS6522CUDAState, parent_obj);
  502. CUDAState *cs = container_of(mcs, CUDAState, mos6522_cuda);
  503. cuda_update(cs);
  504. }
  505. static void mos6522_cuda_reset(DeviceState *dev)
  506. {
  507. MOS6522State *ms = MOS6522(dev);
  508. MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(ms);
  509. mdc->parent_reset(dev);
  510. ms->timers[0].frequency = CUDA_TIMER_FREQ;
  511. ms->timers[1].frequency = (SCALE_US * 6000) / 4700;
  512. }
  513. static void mos6522_cuda_class_init(ObjectClass *oc, void *data)
  514. {
  515. DeviceClass *dc = DEVICE_CLASS(oc);
  516. MOS6522DeviceClass *mdc = MOS6522_DEVICE_CLASS(oc);
  517. dc->reset = mos6522_cuda_reset;
  518. mdc->portB_write = mos6522_cuda_portB_write;
  519. mdc->get_timer1_counter_value = cuda_get_counter_value;
  520. mdc->get_timer2_counter_value = cuda_get_counter_value;
  521. mdc->get_timer1_load_time = cuda_get_load_time;
  522. mdc->get_timer2_load_time = cuda_get_load_time;
  523. }
  524. static const TypeInfo mos6522_cuda_type_info = {
  525. .name = TYPE_MOS6522_CUDA,
  526. .parent = TYPE_MOS6522,
  527. .instance_size = sizeof(MOS6522CUDAState),
  528. .class_init = mos6522_cuda_class_init,
  529. };
  530. static void cuda_register_types(void)
  531. {
  532. type_register_static(&mos6522_cuda_type_info);
  533. type_register_static(&cuda_type_info);
  534. }
  535. type_init(cuda_register_types)