xref: /openbmc/qemu/hw/display/dm163.c (revision a53b931645183bd0c15dd19ae0708fc3c81ecf1d)
1c771f883SInès Varhol /*
2c771f883SInès Varhol  * QEMU DM163 8x3-channel constant current led driver
3c771f883SInès Varhol  * driving columns of associated 8x8 RGB matrix.
4c771f883SInès Varhol  *
5c771f883SInès Varhol  * Copyright (C) 2024 Samuel Tardieu <sam@rfc1149.net>
6c771f883SInès Varhol  * Copyright (C) 2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
7c771f883SInès Varhol  * Copyright (C) 2024 Inès Varhol <ines.varhol@telecom-paris.fr>
8c771f883SInès Varhol  *
9c771f883SInès Varhol  * SPDX-License-Identifier: GPL-2.0-or-later
10c771f883SInès Varhol  */
11c771f883SInès Varhol 
12c771f883SInès Varhol /*
13c771f883SInès Varhol  * The reference used for the DM163 is the following :
14c771f883SInès Varhol  * http://www.siti.com.tw/product/spec/LED/DM163.pdf
15c771f883SInès Varhol  */
16c771f883SInès Varhol 
17c771f883SInès Varhol #include "qemu/osdep.h"
18c771f883SInès Varhol #include "qapi/error.h"
19c771f883SInès Varhol #include "migration/vmstate.h"
20c771f883SInès Varhol #include "hw/irq.h"
21c771f883SInès Varhol #include "hw/qdev-properties.h"
22c771f883SInès Varhol #include "hw/display/dm163.h"
23c771f883SInès Varhol #include "ui/console.h"
24c771f883SInès Varhol #include "trace.h"
25c771f883SInès Varhol 
26c771f883SInès Varhol #define LED_SQUARE_SIZE 100
27c771f883SInès Varhol /* Number of frames a row stays visible after being turned off. */
28c771f883SInès Varhol #define ROW_PERSISTENCE 3
29c771f883SInès Varhol #define TURNED_OFF_ROW (COLOR_BUFFER_SIZE - 1)
30c771f883SInès Varhol 
31c771f883SInès Varhol static const VMStateDescription vmstate_dm163 = {
32c771f883SInès Varhol     .name = TYPE_DM163,
33c771f883SInès Varhol     .version_id = 1,
34c771f883SInès Varhol     .minimum_version_id = 1,
35c771f883SInès Varhol     .fields = (const VMStateField[]) {
36c771f883SInès Varhol         VMSTATE_UINT64_ARRAY(bank0_shift_register, DM163State, 3),
37c771f883SInès Varhol         VMSTATE_UINT64_ARRAY(bank1_shift_register, DM163State, 3),
38c771f883SInès Varhol         VMSTATE_UINT16_ARRAY(latched_outputs, DM163State, DM163_NUM_LEDS),
39c771f883SInès Varhol         VMSTATE_UINT16_ARRAY(outputs, DM163State, DM163_NUM_LEDS),
40c771f883SInès Varhol         VMSTATE_UINT8(dck, DM163State),
41c771f883SInès Varhol         VMSTATE_UINT8(en_b, DM163State),
42c771f883SInès Varhol         VMSTATE_UINT8(lat_b, DM163State),
43c771f883SInès Varhol         VMSTATE_UINT8(rst_b, DM163State),
44c771f883SInès Varhol         VMSTATE_UINT8(selbk, DM163State),
45c771f883SInès Varhol         VMSTATE_UINT8(sin, DM163State),
46c771f883SInès Varhol         VMSTATE_UINT8(activated_rows, DM163State),
47c771f883SInès Varhol         VMSTATE_UINT32_2DARRAY(buffer, DM163State, COLOR_BUFFER_SIZE,
48c771f883SInès Varhol                                RGB_MATRIX_NUM_COLS),
49c771f883SInès Varhol         VMSTATE_UINT8(last_buffer_idx, DM163State),
50c771f883SInès Varhol         VMSTATE_UINT8_ARRAY(buffer_idx_of_row, DM163State, RGB_MATRIX_NUM_ROWS),
51c771f883SInès Varhol         VMSTATE_UINT8_ARRAY(row_persistence_delay, DM163State,
52c771f883SInès Varhol                             RGB_MATRIX_NUM_ROWS),
53c771f883SInès Varhol         VMSTATE_END_OF_LIST()
54c771f883SInès Varhol     }
55c771f883SInès Varhol };
56c771f883SInès Varhol 
dm163_reset_hold(Object * obj,ResetType type)57c771f883SInès Varhol static void dm163_reset_hold(Object *obj, ResetType type)
58c771f883SInès Varhol {
59c771f883SInès Varhol     DM163State *s = DM163(obj);
60c771f883SInès Varhol 
61c771f883SInès Varhol     s->sin = 0;
62c771f883SInès Varhol     s->dck = 0;
63c771f883SInès Varhol     s->rst_b = 0;
64c771f883SInès Varhol     /* Ensuring the first falling edge of lat_b isn't missed */
65c771f883SInès Varhol     s->lat_b = 1;
66c771f883SInès Varhol     s->selbk = 0;
67c771f883SInès Varhol     s->en_b = 0;
68c771f883SInès Varhol     /* Reset stops the PWM, not the shift and latched registers. */
69c771f883SInès Varhol     memset(s->outputs, 0, sizeof(s->outputs));
70c771f883SInès Varhol 
71c771f883SInès Varhol     s->activated_rows = 0;
72c771f883SInès Varhol     s->redraw = 0;
73c771f883SInès Varhol     trace_dm163_redraw(s->redraw);
74c771f883SInès Varhol     for (unsigned i = 0; i < COLOR_BUFFER_SIZE; i++) {
75c771f883SInès Varhol         memset(s->buffer[i], 0, sizeof(s->buffer[0]));
76c771f883SInès Varhol     }
77c771f883SInès Varhol     s->last_buffer_idx = 0;
78c771f883SInès Varhol     memset(s->buffer_idx_of_row, TURNED_OFF_ROW, sizeof(s->buffer_idx_of_row));
79c771f883SInès Varhol     memset(s->row_persistence_delay, 0, sizeof(s->row_persistence_delay));
80c771f883SInès Varhol }
81c771f883SInès Varhol 
dm163_dck_gpio_handler(void * opaque,int line,int new_state)82c771f883SInès Varhol static void dm163_dck_gpio_handler(void *opaque, int line, int new_state)
83c771f883SInès Varhol {
84c771f883SInès Varhol     DM163State *s = opaque;
85c771f883SInès Varhol 
86c771f883SInès Varhol     if (new_state && !s->dck) {
87c771f883SInès Varhol         /*
88c771f883SInès Varhol          * On raising dck, sample selbk to get the bank to use, and
89c771f883SInès Varhol          * sample sin for the bit to enter into the bank shift buffer.
90c771f883SInès Varhol          */
91c771f883SInès Varhol         uint64_t *sb =
92c771f883SInès Varhol             s->selbk ? s->bank1_shift_register : s->bank0_shift_register;
93c771f883SInès Varhol         /* Output the outgoing bit on sout */
94c771f883SInès Varhol         const bool sout = (s->selbk ? sb[2] & MAKE_64BIT_MASK(63, 1) :
95c771f883SInès Varhol                            sb[2] & MAKE_64BIT_MASK(15, 1)) != 0;
96c771f883SInès Varhol         qemu_set_irq(s->sout, sout);
97c771f883SInès Varhol         /* Enter sin into the shift buffer */
98c771f883SInès Varhol         sb[2] = (sb[2] << 1) | ((sb[1] >> 63) & 1);
99c771f883SInès Varhol         sb[1] = (sb[1] << 1) | ((sb[0] >> 63) & 1);
100c771f883SInès Varhol         sb[0] = (sb[0] << 1) | s->sin;
101c771f883SInès Varhol     }
102c771f883SInès Varhol 
103c771f883SInès Varhol     s->dck = new_state;
104c771f883SInès Varhol     trace_dm163_dck(new_state);
105c771f883SInès Varhol }
106c771f883SInès Varhol 
dm163_propagate_outputs(DM163State * s)107c771f883SInès Varhol static void dm163_propagate_outputs(DM163State *s)
108c771f883SInès Varhol {
109c771f883SInès Varhol     s->last_buffer_idx = (s->last_buffer_idx + 1) % RGB_MATRIX_NUM_ROWS;
110c771f883SInès Varhol     /* Values are output when reset is high and enable is low. */
111c771f883SInès Varhol     if (s->rst_b && !s->en_b) {
112c771f883SInès Varhol         memcpy(s->outputs, s->latched_outputs, sizeof(s->outputs));
113c771f883SInès Varhol     } else {
114c771f883SInès Varhol         memset(s->outputs, 0, sizeof(s->outputs));
115c771f883SInès Varhol     }
116c771f883SInès Varhol     for (unsigned x = 0; x < RGB_MATRIX_NUM_COLS; x++) {
117c771f883SInès Varhol         /* Grouping the 3 RGB channels in a pixel value */
118c771f883SInès Varhol         const uint16_t b = extract16(s->outputs[3 * x + 0], 6, 8);
119c771f883SInès Varhol         const uint16_t g = extract16(s->outputs[3 * x + 1], 6, 8);
120c771f883SInès Varhol         const uint16_t r = extract16(s->outputs[3 * x + 2], 6, 8);
121c771f883SInès Varhol         uint32_t rgba = 0;
122c771f883SInès Varhol 
123c771f883SInès Varhol         trace_dm163_channels(3 * x + 2, r);
124c771f883SInès Varhol         trace_dm163_channels(3 * x + 1, g);
125c771f883SInès Varhol         trace_dm163_channels(3 * x + 0, b);
126c771f883SInès Varhol 
127c771f883SInès Varhol         rgba = deposit32(rgba,  0, 8, r);
128c771f883SInès Varhol         rgba = deposit32(rgba,  8, 8, g);
129c771f883SInès Varhol         rgba = deposit32(rgba, 16, 8, b);
130c771f883SInès Varhol 
131c771f883SInès Varhol         /* Led values are sent from the last one to the first one */
132c771f883SInès Varhol         s->buffer[s->last_buffer_idx][RGB_MATRIX_NUM_COLS - x - 1] = rgba;
133c771f883SInès Varhol     }
134c771f883SInès Varhol     for (unsigned row = 0; row < RGB_MATRIX_NUM_ROWS; row++) {
135c771f883SInès Varhol         if (s->activated_rows & (1 << row)) {
136c771f883SInès Varhol             s->buffer_idx_of_row[row] = s->last_buffer_idx;
137c771f883SInès Varhol             s->redraw |= (1 << row);
138c771f883SInès Varhol             trace_dm163_redraw(s->redraw);
139c771f883SInès Varhol         }
140c771f883SInès Varhol     }
141c771f883SInès Varhol }
142c771f883SInès Varhol 
dm163_en_b_gpio_handler(void * opaque,int line,int new_state)143c771f883SInès Varhol static void dm163_en_b_gpio_handler(void *opaque, int line, int new_state)
144c771f883SInès Varhol {
145c771f883SInès Varhol     DM163State *s = opaque;
146c771f883SInès Varhol 
147c771f883SInès Varhol     s->en_b = new_state;
148c771f883SInès Varhol     dm163_propagate_outputs(s);
149c771f883SInès Varhol     trace_dm163_en_b(new_state);
150c771f883SInès Varhol }
151c771f883SInès Varhol 
dm163_bank0(const DM163State * s,uint8_t led)152c771f883SInès Varhol static uint8_t dm163_bank0(const DM163State *s, uint8_t led)
153c771f883SInès Varhol {
154c771f883SInès Varhol     /*
155c771f883SInès Varhol      * Bank 0 uses 6 bits per led, so a value may be stored accross
156c771f883SInès Varhol      * two uint64_t entries.
157c771f883SInès Varhol      */
158c771f883SInès Varhol     const uint8_t low_bit = 6 * led;
159c771f883SInès Varhol     const uint8_t low_word = low_bit / 64;
160c771f883SInès Varhol     const uint8_t high_word = (low_bit + 5) / 64;
161c771f883SInès Varhol     const uint8_t low_shift = low_bit % 64;
162c771f883SInès Varhol 
163c771f883SInès Varhol     if (low_word == high_word) {
164c771f883SInès Varhol         /* Simple case: the value belongs to one entry. */
165c771f883SInès Varhol         return extract64(s->bank0_shift_register[low_word], low_shift, 6);
166c771f883SInès Varhol     }
167c771f883SInès Varhol 
168c771f883SInès Varhol     const uint8_t nb_bits_in_low_word = 64 - low_shift;
169c771f883SInès Varhol     const uint8_t nb_bits_in_high_word = 6 - nb_bits_in_low_word;
170c771f883SInès Varhol 
171c771f883SInès Varhol     const uint64_t bits_in_low_word = \
172c771f883SInès Varhol         extract64(s->bank0_shift_register[low_word], low_shift,
173c771f883SInès Varhol                   nb_bits_in_low_word);
174c771f883SInès Varhol     const uint64_t bits_in_high_word = \
175c771f883SInès Varhol         extract64(s->bank0_shift_register[high_word], 0,
176c771f883SInès Varhol                   nb_bits_in_high_word);
177c771f883SInès Varhol     uint8_t val = 0;
178c771f883SInès Varhol 
179c771f883SInès Varhol     val = deposit32(val, 0, nb_bits_in_low_word, bits_in_low_word);
180c771f883SInès Varhol     val = deposit32(val, nb_bits_in_low_word, nb_bits_in_high_word,
181c771f883SInès Varhol                     bits_in_high_word);
182c771f883SInès Varhol 
183c771f883SInès Varhol     return val;
184c771f883SInès Varhol }
185c771f883SInès Varhol 
dm163_bank1(const DM163State * s,uint8_t led)186c771f883SInès Varhol static uint8_t dm163_bank1(const DM163State *s, uint8_t led)
187c771f883SInès Varhol {
188c771f883SInès Varhol     const uint64_t entry = s->bank1_shift_register[led / RGB_MATRIX_NUM_COLS];
189c771f883SInès Varhol     return extract64(entry, 8 * (led % RGB_MATRIX_NUM_COLS), 8);
190c771f883SInès Varhol }
191c771f883SInès Varhol 
dm163_lat_b_gpio_handler(void * opaque,int line,int new_state)192c771f883SInès Varhol static void dm163_lat_b_gpio_handler(void *opaque, int line, int new_state)
193c771f883SInès Varhol {
194c771f883SInès Varhol     DM163State *s = opaque;
195c771f883SInès Varhol 
196c771f883SInès Varhol     if (s->lat_b && !new_state) {
197c771f883SInès Varhol         for (int led = 0; led < DM163_NUM_LEDS; led++) {
198c771f883SInès Varhol             s->latched_outputs[led] = dm163_bank0(s, led) * dm163_bank1(s, led);
199c771f883SInès Varhol         }
200c771f883SInès Varhol         dm163_propagate_outputs(s);
201c771f883SInès Varhol     }
202c771f883SInès Varhol 
203c771f883SInès Varhol     s->lat_b = new_state;
204c771f883SInès Varhol     trace_dm163_lat_b(new_state);
205c771f883SInès Varhol }
206c771f883SInès Varhol 
dm163_rst_b_gpio_handler(void * opaque,int line,int new_state)207c771f883SInès Varhol static void dm163_rst_b_gpio_handler(void *opaque, int line, int new_state)
208c771f883SInès Varhol {
209c771f883SInès Varhol     DM163State *s = opaque;
210c771f883SInès Varhol 
211c771f883SInès Varhol     s->rst_b = new_state;
212c771f883SInès Varhol     dm163_propagate_outputs(s);
213c771f883SInès Varhol     trace_dm163_rst_b(new_state);
214c771f883SInès Varhol }
215c771f883SInès Varhol 
dm163_selbk_gpio_handler(void * opaque,int line,int new_state)216c771f883SInès Varhol static void dm163_selbk_gpio_handler(void *opaque, int line, int new_state)
217c771f883SInès Varhol {
218c771f883SInès Varhol     DM163State *s = opaque;
219c771f883SInès Varhol 
220c771f883SInès Varhol     s->selbk = new_state;
221c771f883SInès Varhol     trace_dm163_selbk(new_state);
222c771f883SInès Varhol }
223c771f883SInès Varhol 
dm163_sin_gpio_handler(void * opaque,int line,int new_state)224c771f883SInès Varhol static void dm163_sin_gpio_handler(void *opaque, int line, int new_state)
225c771f883SInès Varhol {
226c771f883SInès Varhol     DM163State *s = opaque;
227c771f883SInès Varhol 
228c771f883SInès Varhol     s->sin = new_state;
229c771f883SInès Varhol     trace_dm163_sin(new_state);
230c771f883SInès Varhol }
231c771f883SInès Varhol 
dm163_rows_gpio_handler(void * opaque,int line,int new_state)232c771f883SInès Varhol static void dm163_rows_gpio_handler(void *opaque, int line, int new_state)
233c771f883SInès Varhol {
234c771f883SInès Varhol     DM163State *s = opaque;
235c771f883SInès Varhol 
236c771f883SInès Varhol     if (new_state) {
237c771f883SInès Varhol         s->activated_rows |= (1 << line);
238c771f883SInès Varhol         s->buffer_idx_of_row[line] = s->last_buffer_idx;
239c771f883SInès Varhol         s->redraw |= (1 << line);
240c771f883SInès Varhol         trace_dm163_redraw(s->redraw);
241c771f883SInès Varhol     } else {
242c771f883SInès Varhol         s->activated_rows &= ~(1 << line);
243c771f883SInès Varhol         s->row_persistence_delay[line] = ROW_PERSISTENCE;
244c771f883SInès Varhol     }
245c771f883SInès Varhol     trace_dm163_activated_rows(s->activated_rows);
246c771f883SInès Varhol }
247c771f883SInès Varhol 
dm163_invalidate_display(void * opaque)248c771f883SInès Varhol static void dm163_invalidate_display(void *opaque)
249c771f883SInès Varhol {
250c771f883SInès Varhol     DM163State *s = (DM163State *)opaque;
251c771f883SInès Varhol     s->redraw = 0xFF;
252c771f883SInès Varhol     trace_dm163_redraw(s->redraw);
253c771f883SInès Varhol }
254c771f883SInès Varhol 
update_row_persistence_delay(DM163State * s,unsigned row)255c771f883SInès Varhol static void update_row_persistence_delay(DM163State *s, unsigned row)
256c771f883SInès Varhol {
257c771f883SInès Varhol     if (s->row_persistence_delay[row]) {
258c771f883SInès Varhol         s->row_persistence_delay[row]--;
259c771f883SInès Varhol     } else {
260c771f883SInès Varhol         /*
261c771f883SInès Varhol          * If the ROW_PERSISTENCE delay is up,
262c771f883SInès Varhol          * the row is turned off.
263c771f883SInès Varhol          */
264c771f883SInès Varhol         s->buffer_idx_of_row[row] = TURNED_OFF_ROW;
265c771f883SInès Varhol         s->redraw |= (1 << row);
266c771f883SInès Varhol         trace_dm163_redraw(s->redraw);
267c771f883SInès Varhol     }
268c771f883SInès Varhol }
269c771f883SInès Varhol 
update_display_of_row(DM163State * s,uint32_t * dest,unsigned row)270c771f883SInès Varhol static uint32_t *update_display_of_row(DM163State *s, uint32_t *dest,
271c771f883SInès Varhol                                        unsigned row)
272c771f883SInès Varhol {
273c771f883SInès Varhol     for (unsigned _ = 0; _ < LED_SQUARE_SIZE; _++) {
274*d524be28SInès Varhol         for (int x = RGB_MATRIX_NUM_COLS * LED_SQUARE_SIZE - 1; x >= 0; x--) {
275c771f883SInès Varhol             /* UI layer guarantees that there's 32 bits per pixel (Mar 2024) */
276c771f883SInès Varhol             *dest++ = s->buffer[s->buffer_idx_of_row[row]][x / LED_SQUARE_SIZE];
277c771f883SInès Varhol         }
278c771f883SInès Varhol     }
279c771f883SInès Varhol 
280c771f883SInès Varhol     dpy_gfx_update(s->console, 0, LED_SQUARE_SIZE * row,
281c771f883SInès Varhol                     RGB_MATRIX_NUM_COLS * LED_SQUARE_SIZE, LED_SQUARE_SIZE);
282c771f883SInès Varhol     s->redraw &= ~(1 << row);
283c771f883SInès Varhol     trace_dm163_redraw(s->redraw);
284c771f883SInès Varhol 
285c771f883SInès Varhol     return dest;
286c771f883SInès Varhol }
287c771f883SInès Varhol 
dm163_update_display(void * opaque)288c771f883SInès Varhol static void dm163_update_display(void *opaque)
289c771f883SInès Varhol {
290c771f883SInès Varhol     DM163State *s = (DM163State *)opaque;
291c771f883SInès Varhol     DisplaySurface *surface = qemu_console_surface(s->console);
292c771f883SInès Varhol     uint32_t *dest;
293c771f883SInès Varhol 
294c771f883SInès Varhol     dest = surface_data(surface);
295c771f883SInès Varhol     for (unsigned row = 0; row < RGB_MATRIX_NUM_ROWS; row++) {
296c771f883SInès Varhol         update_row_persistence_delay(s, row);
297c771f883SInès Varhol         if (!extract8(s->redraw, row, 1)) {
298c771f883SInès Varhol             dest += LED_SQUARE_SIZE * LED_SQUARE_SIZE * RGB_MATRIX_NUM_COLS;
299c771f883SInès Varhol             continue;
300c771f883SInès Varhol         }
301c771f883SInès Varhol         dest = update_display_of_row(s, dest, row);
302c771f883SInès Varhol     }
303c771f883SInès Varhol }
304c771f883SInès Varhol 
305c771f883SInès Varhol static const GraphicHwOps dm163_ops = {
306c771f883SInès Varhol     .invalidate  = dm163_invalidate_display,
307c771f883SInès Varhol     .gfx_update  = dm163_update_display,
308c771f883SInès Varhol };
309c771f883SInès Varhol 
dm163_realize(DeviceState * dev,Error ** errp)310c771f883SInès Varhol static void dm163_realize(DeviceState *dev, Error **errp)
311c771f883SInès Varhol {
312c771f883SInès Varhol     DM163State *s = DM163(dev);
313c771f883SInès Varhol 
314c771f883SInès Varhol     qdev_init_gpio_in(dev, dm163_rows_gpio_handler, RGB_MATRIX_NUM_ROWS);
315c771f883SInès Varhol     qdev_init_gpio_in(dev, dm163_sin_gpio_handler, 1);
316c771f883SInès Varhol     qdev_init_gpio_in(dev, dm163_dck_gpio_handler, 1);
317c771f883SInès Varhol     qdev_init_gpio_in(dev, dm163_rst_b_gpio_handler, 1);
318c771f883SInès Varhol     qdev_init_gpio_in(dev, dm163_lat_b_gpio_handler, 1);
319c771f883SInès Varhol     qdev_init_gpio_in(dev, dm163_selbk_gpio_handler, 1);
320c771f883SInès Varhol     qdev_init_gpio_in(dev, dm163_en_b_gpio_handler, 1);
321c771f883SInès Varhol     qdev_init_gpio_out_named(dev, &s->sout, "sout", 1);
322c771f883SInès Varhol 
323c771f883SInès Varhol     s->console = graphic_console_init(dev, 0, &dm163_ops, s);
324c771f883SInès Varhol     qemu_console_resize(s->console, RGB_MATRIX_NUM_COLS * LED_SQUARE_SIZE,
325c771f883SInès Varhol                         RGB_MATRIX_NUM_ROWS * LED_SQUARE_SIZE);
326c771f883SInès Varhol }
327c771f883SInès Varhol 
dm163_class_init(ObjectClass * klass,void * data)328c771f883SInès Varhol static void dm163_class_init(ObjectClass *klass, void *data)
329c771f883SInès Varhol {
330c771f883SInès Varhol     DeviceClass *dc = DEVICE_CLASS(klass);
331c771f883SInès Varhol     ResettableClass *rc = RESETTABLE_CLASS(klass);
332c771f883SInès Varhol 
333c771f883SInès Varhol     dc->desc = "DM163";
334c771f883SInès Varhol     dc->vmsd = &vmstate_dm163;
335c771f883SInès Varhol     dc->realize = dm163_realize;
336c771f883SInès Varhol     rc->phases.hold = dm163_reset_hold;
337c771f883SInès Varhol     set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
338c771f883SInès Varhol }
339c771f883SInès Varhol 
340c771f883SInès Varhol static const TypeInfo dm163_types[] = {
341c771f883SInès Varhol     {
342c771f883SInès Varhol         .name = TYPE_DM163,
343c771f883SInès Varhol         .parent = TYPE_DEVICE,
344c771f883SInès Varhol         .instance_size = sizeof(DM163State),
345c771f883SInès Varhol         .class_init = dm163_class_init
346c771f883SInès Varhol     }
347c771f883SInès Varhol };
348c771f883SInès Varhol 
349c771f883SInès Varhol DEFINE_TYPES(dm163_types)
350