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