tcx.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. /*
  2. * QEMU TCX Frame buffer
  3. *
  4. * Copyright (c) 2003-2005 Fabrice Bellard
  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 "console.h"
  25. #include "pixel_ops.h"
  26. #include "sysbus.h"
  27. #include "qdev-addr.h"
  28. #define MAXX 1024
  29. #define MAXY 768
  30. #define TCX_DAC_NREGS 16
  31. #define TCX_THC_NREGS_8 0x081c
  32. #define TCX_THC_NREGS_24 0x1000
  33. #define TCX_TEC_NREGS 0x1000
  34. typedef struct TCXState {
  35. SysBusDevice busdev;
  36. target_phys_addr_t addr;
  37. DisplayState *ds;
  38. uint8_t *vram;
  39. uint32_t *vram24, *cplane;
  40. MemoryRegion vram_mem;
  41. MemoryRegion vram_8bit;
  42. MemoryRegion vram_24bit;
  43. MemoryRegion vram_cplane;
  44. MemoryRegion dac;
  45. MemoryRegion tec;
  46. MemoryRegion thc24;
  47. MemoryRegion thc8;
  48. ram_addr_t vram24_offset, cplane_offset;
  49. uint32_t vram_size;
  50. uint32_t palette[256];
  51. uint8_t r[256], g[256], b[256];
  52. uint16_t width, height, depth;
  53. uint8_t dac_index, dac_state;
  54. } TCXState;
  55. static void tcx_screen_dump(void *opaque, const char *filename);
  56. static void tcx24_screen_dump(void *opaque, const char *filename);
  57. static void tcx_set_dirty(TCXState *s)
  58. {
  59. unsigned int i;
  60. for (i = 0; i < MAXX * MAXY; i += TARGET_PAGE_SIZE) {
  61. memory_region_set_dirty(&s->vram_mem, i);
  62. }
  63. }
  64. static void tcx24_set_dirty(TCXState *s)
  65. {
  66. unsigned int i;
  67. for (i = 0; i < MAXX * MAXY * 4; i += TARGET_PAGE_SIZE) {
  68. memory_region_set_dirty(&s->vram_mem, s->vram24_offset + i);
  69. memory_region_set_dirty(&s->vram_mem, s->cplane_offset + i);
  70. }
  71. }
  72. static void update_palette_entries(TCXState *s, int start, int end)
  73. {
  74. int i;
  75. for(i = start; i < end; i++) {
  76. switch(ds_get_bits_per_pixel(s->ds)) {
  77. default:
  78. case 8:
  79. s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
  80. break;
  81. case 15:
  82. s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
  83. break;
  84. case 16:
  85. s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
  86. break;
  87. case 32:
  88. if (is_surface_bgr(s->ds->surface))
  89. s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
  90. else
  91. s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
  92. break;
  93. }
  94. }
  95. if (s->depth == 24) {
  96. tcx24_set_dirty(s);
  97. } else {
  98. tcx_set_dirty(s);
  99. }
  100. }
  101. static void tcx_draw_line32(TCXState *s1, uint8_t *d,
  102. const uint8_t *s, int width)
  103. {
  104. int x;
  105. uint8_t val;
  106. uint32_t *p = (uint32_t *)d;
  107. for(x = 0; x < width; x++) {
  108. val = *s++;
  109. *p++ = s1->palette[val];
  110. }
  111. }
  112. static void tcx_draw_line16(TCXState *s1, uint8_t *d,
  113. const uint8_t *s, int width)
  114. {
  115. int x;
  116. uint8_t val;
  117. uint16_t *p = (uint16_t *)d;
  118. for(x = 0; x < width; x++) {
  119. val = *s++;
  120. *p++ = s1->palette[val];
  121. }
  122. }
  123. static void tcx_draw_line8(TCXState *s1, uint8_t *d,
  124. const uint8_t *s, int width)
  125. {
  126. int x;
  127. uint8_t val;
  128. for(x = 0; x < width; x++) {
  129. val = *s++;
  130. *d++ = s1->palette[val];
  131. }
  132. }
  133. /*
  134. XXX Could be much more optimal:
  135. * detect if line/page/whole screen is in 24 bit mode
  136. * if destination is also BGR, use memcpy
  137. */
  138. static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
  139. const uint8_t *s, int width,
  140. const uint32_t *cplane,
  141. const uint32_t *s24)
  142. {
  143. int x, bgr, r, g, b;
  144. uint8_t val, *p8;
  145. uint32_t *p = (uint32_t *)d;
  146. uint32_t dval;
  147. bgr = is_surface_bgr(s1->ds->surface);
  148. for(x = 0; x < width; x++, s++, s24++) {
  149. if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) {
  150. // 24-bit direct, BGR order
  151. p8 = (uint8_t *)s24;
  152. p8++;
  153. b = *p8++;
  154. g = *p8++;
  155. r = *p8;
  156. if (bgr)
  157. dval = rgb_to_pixel32bgr(r, g, b);
  158. else
  159. dval = rgb_to_pixel32(r, g, b);
  160. } else {
  161. val = *s;
  162. dval = s1->palette[val];
  163. }
  164. *p++ = dval;
  165. }
  166. }
  167. static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24,
  168. ram_addr_t cpage)
  169. {
  170. int ret;
  171. unsigned int off;
  172. ret = memory_region_get_dirty(&s->vram_mem, page, DIRTY_MEMORY_VGA);
  173. for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
  174. ret |= memory_region_get_dirty(&s->vram_mem, page24 + off,
  175. DIRTY_MEMORY_VGA);
  176. ret |= memory_region_get_dirty(&s->vram_mem, cpage + off,
  177. DIRTY_MEMORY_VGA);
  178. }
  179. return ret;
  180. }
  181. static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
  182. ram_addr_t page_max, ram_addr_t page24,
  183. ram_addr_t cpage)
  184. {
  185. memory_region_reset_dirty(&ts->vram_mem,
  186. page_min, page_max + TARGET_PAGE_SIZE,
  187. DIRTY_MEMORY_VGA);
  188. memory_region_reset_dirty(&ts->vram_mem,
  189. page24 + page_min * 4,
  190. page24 + page_max * 4 + TARGET_PAGE_SIZE,
  191. DIRTY_MEMORY_VGA);
  192. memory_region_reset_dirty(&ts->vram_mem,
  193. cpage + page_min * 4,
  194. cpage + page_max * 4 + TARGET_PAGE_SIZE,
  195. DIRTY_MEMORY_VGA);
  196. }
  197. /* Fixed line length 1024 allows us to do nice tricks not possible on
  198. VGA... */
  199. static void tcx_update_display(void *opaque)
  200. {
  201. TCXState *ts = opaque;
  202. ram_addr_t page, page_min, page_max;
  203. int y, y_start, dd, ds;
  204. uint8_t *d, *s;
  205. void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
  206. if (ds_get_bits_per_pixel(ts->ds) == 0)
  207. return;
  208. page = 0;
  209. y_start = -1;
  210. page_min = -1;
  211. page_max = 0;
  212. d = ds_get_data(ts->ds);
  213. s = ts->vram;
  214. dd = ds_get_linesize(ts->ds);
  215. ds = 1024;
  216. switch (ds_get_bits_per_pixel(ts->ds)) {
  217. case 32:
  218. f = tcx_draw_line32;
  219. break;
  220. case 15:
  221. case 16:
  222. f = tcx_draw_line16;
  223. break;
  224. default:
  225. case 8:
  226. f = tcx_draw_line8;
  227. break;
  228. case 0:
  229. return;
  230. }
  231. for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
  232. if (memory_region_get_dirty(&ts->vram_mem, page, DIRTY_MEMORY_VGA)) {
  233. if (y_start < 0)
  234. y_start = y;
  235. if (page < page_min)
  236. page_min = page;
  237. if (page > page_max)
  238. page_max = page;
  239. f(ts, d, s, ts->width);
  240. d += dd;
  241. s += ds;
  242. f(ts, d, s, ts->width);
  243. d += dd;
  244. s += ds;
  245. f(ts, d, s, ts->width);
  246. d += dd;
  247. s += ds;
  248. f(ts, d, s, ts->width);
  249. d += dd;
  250. s += ds;
  251. } else {
  252. if (y_start >= 0) {
  253. /* flush to display */
  254. dpy_update(ts->ds, 0, y_start,
  255. ts->width, y - y_start);
  256. y_start = -1;
  257. }
  258. d += dd * 4;
  259. s += ds * 4;
  260. }
  261. }
  262. if (y_start >= 0) {
  263. /* flush to display */
  264. dpy_update(ts->ds, 0, y_start,
  265. ts->width, y - y_start);
  266. }
  267. /* reset modified pages */
  268. if (page_max >= page_min) {
  269. memory_region_reset_dirty(&ts->vram_mem,
  270. page_min, page_max + TARGET_PAGE_SIZE,
  271. DIRTY_MEMORY_VGA);
  272. }
  273. }
  274. static void tcx24_update_display(void *opaque)
  275. {
  276. TCXState *ts = opaque;
  277. ram_addr_t page, page_min, page_max, cpage, page24;
  278. int y, y_start, dd, ds;
  279. uint8_t *d, *s;
  280. uint32_t *cptr, *s24;
  281. if (ds_get_bits_per_pixel(ts->ds) != 32)
  282. return;
  283. page = 0;
  284. page24 = ts->vram24_offset;
  285. cpage = ts->cplane_offset;
  286. y_start = -1;
  287. page_min = -1;
  288. page_max = 0;
  289. d = ds_get_data(ts->ds);
  290. s = ts->vram;
  291. s24 = ts->vram24;
  292. cptr = ts->cplane;
  293. dd = ds_get_linesize(ts->ds);
  294. ds = 1024;
  295. for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
  296. page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
  297. if (check_dirty(ts, page, page24, cpage)) {
  298. if (y_start < 0)
  299. y_start = y;
  300. if (page < page_min)
  301. page_min = page;
  302. if (page > page_max)
  303. page_max = page;
  304. tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
  305. d += dd;
  306. s += ds;
  307. cptr += ds;
  308. s24 += ds;
  309. tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
  310. d += dd;
  311. s += ds;
  312. cptr += ds;
  313. s24 += ds;
  314. tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
  315. d += dd;
  316. s += ds;
  317. cptr += ds;
  318. s24 += ds;
  319. tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
  320. d += dd;
  321. s += ds;
  322. cptr += ds;
  323. s24 += ds;
  324. } else {
  325. if (y_start >= 0) {
  326. /* flush to display */
  327. dpy_update(ts->ds, 0, y_start,
  328. ts->width, y - y_start);
  329. y_start = -1;
  330. }
  331. d += dd * 4;
  332. s += ds * 4;
  333. cptr += ds * 4;
  334. s24 += ds * 4;
  335. }
  336. }
  337. if (y_start >= 0) {
  338. /* flush to display */
  339. dpy_update(ts->ds, 0, y_start,
  340. ts->width, y - y_start);
  341. }
  342. /* reset modified pages */
  343. if (page_max >= page_min) {
  344. reset_dirty(ts, page_min, page_max, page24, cpage);
  345. }
  346. }
  347. static void tcx_invalidate_display(void *opaque)
  348. {
  349. TCXState *s = opaque;
  350. tcx_set_dirty(s);
  351. qemu_console_resize(s->ds, s->width, s->height);
  352. }
  353. static void tcx24_invalidate_display(void *opaque)
  354. {
  355. TCXState *s = opaque;
  356. tcx_set_dirty(s);
  357. tcx24_set_dirty(s);
  358. qemu_console_resize(s->ds, s->width, s->height);
  359. }
  360. static int vmstate_tcx_post_load(void *opaque, int version_id)
  361. {
  362. TCXState *s = opaque;
  363. update_palette_entries(s, 0, 256);
  364. if (s->depth == 24) {
  365. tcx24_set_dirty(s);
  366. } else {
  367. tcx_set_dirty(s);
  368. }
  369. return 0;
  370. }
  371. static const VMStateDescription vmstate_tcx = {
  372. .name ="tcx",
  373. .version_id = 4,
  374. .minimum_version_id = 4,
  375. .minimum_version_id_old = 4,
  376. .post_load = vmstate_tcx_post_load,
  377. .fields = (VMStateField []) {
  378. VMSTATE_UINT16(height, TCXState),
  379. VMSTATE_UINT16(width, TCXState),
  380. VMSTATE_UINT16(depth, TCXState),
  381. VMSTATE_BUFFER(r, TCXState),
  382. VMSTATE_BUFFER(g, TCXState),
  383. VMSTATE_BUFFER(b, TCXState),
  384. VMSTATE_UINT8(dac_index, TCXState),
  385. VMSTATE_UINT8(dac_state, TCXState),
  386. VMSTATE_END_OF_LIST()
  387. }
  388. };
  389. static void tcx_reset(DeviceState *d)
  390. {
  391. TCXState *s = container_of(d, TCXState, busdev.qdev);
  392. /* Initialize palette */
  393. memset(s->r, 0, 256);
  394. memset(s->g, 0, 256);
  395. memset(s->b, 0, 256);
  396. s->r[255] = s->g[255] = s->b[255] = 255;
  397. update_palette_entries(s, 0, 256);
  398. memset(s->vram, 0, MAXX*MAXY);
  399. memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4),
  400. DIRTY_MEMORY_VGA);
  401. s->dac_index = 0;
  402. s->dac_state = 0;
  403. }
  404. static uint64_t tcx_dac_readl(void *opaque, target_phys_addr_t addr,
  405. unsigned size)
  406. {
  407. return 0;
  408. }
  409. static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint64_t val,
  410. unsigned size)
  411. {
  412. TCXState *s = opaque;
  413. switch (addr) {
  414. case 0:
  415. s->dac_index = val >> 24;
  416. s->dac_state = 0;
  417. break;
  418. case 4:
  419. switch (s->dac_state) {
  420. case 0:
  421. s->r[s->dac_index] = val >> 24;
  422. update_palette_entries(s, s->dac_index, s->dac_index + 1);
  423. s->dac_state++;
  424. break;
  425. case 1:
  426. s->g[s->dac_index] = val >> 24;
  427. update_palette_entries(s, s->dac_index, s->dac_index + 1);
  428. s->dac_state++;
  429. break;
  430. case 2:
  431. s->b[s->dac_index] = val >> 24;
  432. update_palette_entries(s, s->dac_index, s->dac_index + 1);
  433. s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
  434. default:
  435. s->dac_state = 0;
  436. break;
  437. }
  438. break;
  439. default:
  440. break;
  441. }
  442. return;
  443. }
  444. static const MemoryRegionOps tcx_dac_ops = {
  445. .read = tcx_dac_readl,
  446. .write = tcx_dac_writel,
  447. .endianness = DEVICE_NATIVE_ENDIAN,
  448. .valid = {
  449. .min_access_size = 4,
  450. .max_access_size = 4,
  451. },
  452. };
  453. static uint64_t dummy_readl(void *opaque, target_phys_addr_t addr,
  454. unsigned size)
  455. {
  456. return 0;
  457. }
  458. static void dummy_writel(void *opaque, target_phys_addr_t addr,
  459. uint64_t val, unsigned size)
  460. {
  461. }
  462. static const MemoryRegionOps dummy_ops = {
  463. .read = dummy_readl,
  464. .write = dummy_writel,
  465. .endianness = DEVICE_NATIVE_ENDIAN,
  466. .valid = {
  467. .min_access_size = 4,
  468. .max_access_size = 4,
  469. },
  470. };
  471. static int tcx_init1(SysBusDevice *dev)
  472. {
  473. TCXState *s = FROM_SYSBUS(TCXState, dev);
  474. ram_addr_t vram_offset = 0;
  475. int size;
  476. uint8_t *vram_base;
  477. memory_region_init_ram(&s->vram_mem, NULL, "tcx.vram",
  478. s->vram_size * (1 + 4 + 4));
  479. vram_base = memory_region_get_ram_ptr(&s->vram_mem);
  480. /* 8-bit plane */
  481. s->vram = vram_base;
  482. size = s->vram_size;
  483. memory_region_init_alias(&s->vram_8bit, "tcx.vram.8bit",
  484. &s->vram_mem, vram_offset, size);
  485. sysbus_init_mmio_region(dev, &s->vram_8bit);
  486. vram_offset += size;
  487. vram_base += size;
  488. /* DAC */
  489. memory_region_init_io(&s->dac, &tcx_dac_ops, s, "tcx.dac", TCX_DAC_NREGS);
  490. sysbus_init_mmio_region(dev, &s->dac);
  491. /* TEC (dummy) */
  492. memory_region_init_io(&s->tec, &dummy_ops, s, "tcx.tec", TCX_TEC_NREGS);
  493. sysbus_init_mmio_region(dev, &s->tec);
  494. /* THC: NetBSD writes here even with 8-bit display: dummy */
  495. memory_region_init_io(&s->thc24, &dummy_ops, s, "tcx.thc24",
  496. TCX_THC_NREGS_24);
  497. sysbus_init_mmio_region(dev, &s->thc24);
  498. if (s->depth == 24) {
  499. /* 24-bit plane */
  500. size = s->vram_size * 4;
  501. s->vram24 = (uint32_t *)vram_base;
  502. s->vram24_offset = vram_offset;
  503. memory_region_init_alias(&s->vram_24bit, "tcx.vram.24bit",
  504. &s->vram_mem, vram_offset, size);
  505. sysbus_init_mmio_region(dev, &s->vram_24bit);
  506. vram_offset += size;
  507. vram_base += size;
  508. /* Control plane */
  509. size = s->vram_size * 4;
  510. s->cplane = (uint32_t *)vram_base;
  511. s->cplane_offset = vram_offset;
  512. memory_region_init_alias(&s->vram_cplane, "tcx.vram.cplane",
  513. &s->vram_mem, vram_offset, size);
  514. sysbus_init_mmio_region(dev, &s->vram_cplane);
  515. s->ds = graphic_console_init(tcx24_update_display,
  516. tcx24_invalidate_display,
  517. tcx24_screen_dump, NULL, s);
  518. } else {
  519. /* THC 8 bit (dummy) */
  520. memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8",
  521. TCX_THC_NREGS_8);
  522. sysbus_init_mmio_region(dev, &s->thc8);
  523. s->ds = graphic_console_init(tcx_update_display,
  524. tcx_invalidate_display,
  525. tcx_screen_dump, NULL, s);
  526. }
  527. qemu_console_resize(s->ds, s->width, s->height);
  528. return 0;
  529. }
  530. static void tcx_screen_dump(void *opaque, const char *filename)
  531. {
  532. TCXState *s = opaque;
  533. FILE *f;
  534. uint8_t *d, *d1, v;
  535. int y, x;
  536. f = fopen(filename, "wb");
  537. if (!f)
  538. return;
  539. fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
  540. d1 = s->vram;
  541. for(y = 0; y < s->height; y++) {
  542. d = d1;
  543. for(x = 0; x < s->width; x++) {
  544. v = *d;
  545. fputc(s->r[v], f);
  546. fputc(s->g[v], f);
  547. fputc(s->b[v], f);
  548. d++;
  549. }
  550. d1 += MAXX;
  551. }
  552. fclose(f);
  553. return;
  554. }
  555. static void tcx24_screen_dump(void *opaque, const char *filename)
  556. {
  557. TCXState *s = opaque;
  558. FILE *f;
  559. uint8_t *d, *d1, v;
  560. uint32_t *s24, *cptr, dval;
  561. int y, x;
  562. f = fopen(filename, "wb");
  563. if (!f)
  564. return;
  565. fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
  566. d1 = s->vram;
  567. s24 = s->vram24;
  568. cptr = s->cplane;
  569. for(y = 0; y < s->height; y++) {
  570. d = d1;
  571. for(x = 0; x < s->width; x++, d++, s24++) {
  572. if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
  573. dval = *s24 & 0x00ffffff;
  574. fputc((dval >> 16) & 0xff, f);
  575. fputc((dval >> 8) & 0xff, f);
  576. fputc(dval & 0xff, f);
  577. } else {
  578. v = *d;
  579. fputc(s->r[v], f);
  580. fputc(s->g[v], f);
  581. fputc(s->b[v], f);
  582. }
  583. }
  584. d1 += MAXX;
  585. }
  586. fclose(f);
  587. return;
  588. }
  589. static SysBusDeviceInfo tcx_info = {
  590. .init = tcx_init1,
  591. .qdev.name = "SUNW,tcx",
  592. .qdev.size = sizeof(TCXState),
  593. .qdev.reset = tcx_reset,
  594. .qdev.vmsd = &vmstate_tcx,
  595. .qdev.props = (Property[]) {
  596. DEFINE_PROP_TADDR("addr", TCXState, addr, -1),
  597. DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1),
  598. DEFINE_PROP_UINT16("width", TCXState, width, -1),
  599. DEFINE_PROP_UINT16("height", TCXState, height, -1),
  600. DEFINE_PROP_UINT16("depth", TCXState, depth, -1),
  601. DEFINE_PROP_END_OF_LIST(),
  602. }
  603. };
  604. static void tcx_register_devices(void)
  605. {
  606. sysbus_register_withprop(&tcx_info);
  607. }
  608. device_init(tcx_register_devices)