Blame view

hw/tcx.c 17.1 KB
1
/*
bellard authored
2
 * QEMU TCX Frame buffer
3
 *
bellard authored
4
 * Copyright (c) 2003-2005 Fabrice Bellard
5
 *
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
pbrook authored
24
25
26
#include "hw.h"
#include "sun4m.h"
#include "console.h"
27
#include "pixel_ops.h"
28
29
30

#define MAXX 1024
#define MAXY 768
bellard authored
31
#define TCX_DAC_NREGS 16
32
33
34
#define TCX_THC_NREGS_8  0x081c
#define TCX_THC_NREGS_24 0x1000
#define TCX_TEC_NREGS    0x1000
35
36

typedef struct TCXState {
37
    target_phys_addr_t addr;
38
    DisplayState *ds;
bellard authored
39
    uint8_t *vram;
blueswir1 authored
40
41
42
    uint32_t *vram24, *cplane;
    ram_addr_t vram_offset, vram24_offset, cplane_offset;
    uint16_t width, height, depth;
bellard authored
43
    uint8_t r[256], g[256], b[256];
44
    uint32_t palette[256];
bellard authored
45
    uint8_t dac_index, dac_state;
46
47
} TCXState;
48
static void tcx_screen_dump(void *opaque, const char *filename);
blueswir1 authored
49
static void tcx24_screen_dump(void *opaque, const char *filename);
50
51
static void tcx_invalidate_display(void *opaque);
static void tcx24_invalidate_display(void *opaque);
52
53
54
55
56
static void update_palette_entries(TCXState *s, int start, int end)
{
    int i;
    for(i = start; i < end; i++) {
57
        switch(ds_get_bits_per_pixel(s->ds)) {
58
59
60
61
62
        default:
        case 8:
            s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
            break;
        case 15:
63
            s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
64
65
            break;
        case 16:
66
            s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
67
68
            break;
        case 32:
69
            s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
70
71
72
            break;
        }
    }
73
74
75
76
    if (s->depth == 24)
        tcx24_invalidate_display(s);
    else
        tcx_invalidate_display(s);
77
78
}
79
static void tcx_draw_line32(TCXState *s1, uint8_t *d,
blueswir1 authored
80
                            const uint8_t *s, int width)
81
{
bellard authored
82
83
    int x;
    uint8_t val;
84
    uint32_t *p = (uint32_t *)d;
bellard authored
85
86

    for(x = 0; x < width; x++) {
blueswir1 authored
87
        val = *s++;
88
        *p++ = s1->palette[val];
bellard authored
89
    }
90
91
}
92
static void tcx_draw_line16(TCXState *s1, uint8_t *d,
blueswir1 authored
93
                            const uint8_t *s, int width)
bellard authored
94
95
96
{
    int x;
    uint8_t val;
97
    uint16_t *p = (uint16_t *)d;
bellard authored
98
bellard authored
99
    for(x = 0; x < width; x++) {
blueswir1 authored
100
        val = *s++;
101
        *p++ = s1->palette[val];
bellard authored
102
103
104
    }
}
105
static void tcx_draw_line8(TCXState *s1, uint8_t *d,
blueswir1 authored
106
                           const uint8_t *s, int width)
107
{
bellard authored
108
109
110
111
    int x;
    uint8_t val;

    for(x = 0; x < width; x++) {
blueswir1 authored
112
        val = *s++;
113
        *d++ = s1->palette[val];
114
115
116
    }
}
blueswir1 authored
117
118
119
120
121
/*
  XXX Could be much more optimal:
  * detect if line/page/whole screen is in 24 bit mode
  * if destination is also BGR, use memcpy
  */
blueswir1 authored
122
123
124
125
126
static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
                                     const uint8_t *s, int width,
                                     const uint32_t *cplane,
                                     const uint32_t *s24)
{
127
    int x, r, g, b;
blueswir1 authored
128
    uint8_t val, *p8;
blueswir1 authored
129
130
131
132
    uint32_t *p = (uint32_t *)d;
    uint32_t dval;

    for(x = 0; x < width; x++, s++, s24++) {
blueswir1 authored
133
134
135
136
137
138
139
        if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) {
            // 24-bit direct, BGR order
            p8 = (uint8_t *)s24;
            p8++;
            b = *p8++;
            g = *p8++;
            r = *p8++;
140
            dval = rgb_to_pixel32(r, g, b);
blueswir1 authored
141
142
143
144
145
146
147
148
        } else {
            val = *s;
            dval = s1->palette[val];
        }
        *p++ = dval;
    }
}
blueswir1 authored
149
static inline int check_dirty(ram_addr_t page, ram_addr_t page24,
blueswir1 authored
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
                              ram_addr_t cpage)
{
    int ret;
    unsigned int off;

    ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
    for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
        ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG);
        ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG);
    }
    return ret;
}

static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
                               ram_addr_t page_max, ram_addr_t page24,
                              ram_addr_t cpage)
{
    cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
                                    VGA_DIRTY_FLAG);
    page_min -= ts->vram_offset;
    page_max -= ts->vram_offset;
    cpu_physical_memory_reset_dirty(page24 + page_min * 4,
                                    page24 + page_max * 4 + TARGET_PAGE_SIZE,
                                    VGA_DIRTY_FLAG);
    cpu_physical_memory_reset_dirty(cpage + page_min * 4,
                                    cpage + page_max * 4 + TARGET_PAGE_SIZE,
                                    VGA_DIRTY_FLAG);
}
bellard authored
179
180
/* Fixed line length 1024 allows us to do nice tricks not possible on
   VGA... */
181
static void tcx_update_display(void *opaque)
182
{
bellard authored
183
    TCXState *ts = opaque;
184
185
    ram_addr_t page, page_min, page_max;
    int y, y_start, dd, ds;
bellard authored
186
    uint8_t *d, *s;
187
    void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
bellard authored
188
189
    if (ds_get_bits_per_pixel(ts->ds) == 0)
blueswir1 authored
190
        return;
bellard authored
191
    page = ts->vram_offset;
bellard authored
192
    y_start = -1;
193
194
    page_min = 0xffffffff;
    page_max = 0;
195
    d = ds_get_data(ts->ds);
bellard authored
196
    s = ts->vram;
197
    dd = ds_get_linesize(ts->ds);
bellard authored
198
199
    ds = 1024;
200
    switch (ds_get_bits_per_pixel(ts->ds)) {
bellard authored
201
    case 32:
blueswir1 authored
202
203
        f = tcx_draw_line32;
        break;
204
205
    case 15:
    case 16:
blueswir1 authored
206
207
        f = tcx_draw_line16;
        break;
bellard authored
208
209
    default:
    case 8:
blueswir1 authored
210
211
        f = tcx_draw_line8;
        break;
bellard authored
212
    case 0:
blueswir1 authored
213
        return;
bellard authored
214
    }
215
bellard authored
216
    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
blueswir1 authored
217
218
        if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
            if (y_start < 0)
bellard authored
219
220
221
222
223
                y_start = y;
            if (page < page_min)
                page_min = page;
            if (page > page_max)
                page_max = page;
blueswir1 authored
224
225
226
227
228
229
230
231
232
233
234
235
236
            f(ts, d, s, ts->width);
            d += dd;
            s += ds;
            f(ts, d, s, ts->width);
            d += dd;
            s += ds;
            f(ts, d, s, ts->width);
            d += dd;
            s += ds;
            f(ts, d, s, ts->width);
            d += dd;
            s += ds;
        } else {
bellard authored
237
238
            if (y_start >= 0) {
                /* flush to display */
239
                dpy_update(ts->ds, 0, y_start,
bellard authored
240
                           ts->width, y - y_start);
bellard authored
241
242
                y_start = -1;
            }
blueswir1 authored
243
244
245
            d += dd * 4;
            s += ds * 4;
        }
bellard authored
246
247
    }
    if (y_start >= 0) {
blueswir1 authored
248
249
250
        /* flush to display */
        dpy_update(ts->ds, 0, y_start,
                   ts->width, y - y_start);
bellard authored
251
252
    }
    /* reset modified pages */
253
    if (page_min <= page_max) {
bellard authored
254
255
        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
                                        VGA_DIRTY_FLAG);
bellard authored
256
    }
257
258
}
blueswir1 authored
259
260
261
262
263
264
265
266
static void tcx24_update_display(void *opaque)
{
    TCXState *ts = opaque;
    ram_addr_t page, page_min, page_max, cpage, page24;
    int y, y_start, dd, ds;
    uint8_t *d, *s;
    uint32_t *cptr, *s24;
267
    if (ds_get_bits_per_pixel(ts->ds) != 32)
blueswir1 authored
268
269
270
271
272
273
274
            return;
    page = ts->vram_offset;
    page24 = ts->vram24_offset;
    cpage = ts->cplane_offset;
    y_start = -1;
    page_min = 0xffffffff;
    page_max = 0;
275
    d = ds_get_data(ts->ds);
blueswir1 authored
276
277
278
    s = ts->vram;
    s24 = ts->vram24;
    cptr = ts->cplane;
279
    dd = ds_get_linesize(ts->ds);
blueswir1 authored
280
281
282
283
    ds = 1024;

    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
            page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
blueswir1 authored
284
        if (check_dirty(page, page24, cpage)) {
blueswir1 authored
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
            if (y_start < 0)
                y_start = y;
            if (page < page_min)
                page_min = page;
            if (page > page_max)
                page_max = page;
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
            d += dd;
            s += ds;
            cptr += ds;
            s24 += ds;
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
            d += dd;
            s += ds;
            cptr += ds;
            s24 += ds;
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
            d += dd;
            s += ds;
            cptr += ds;
            s24 += ds;
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
            d += dd;
            s += ds;
            cptr += ds;
            s24 += ds;
        } else {
            if (y_start >= 0) {
                /* flush to display */
                dpy_update(ts->ds, 0, y_start,
                           ts->width, y - y_start);
                y_start = -1;
            }
            d += dd * 4;
            s += ds * 4;
            cptr += ds * 4;
            s24 += ds * 4;
        }
    }
    if (y_start >= 0) {
        /* flush to display */
        dpy_update(ts->ds, 0, y_start,
                   ts->width, y - y_start);
    }
    /* reset modified pages */
    if (page_min <= page_max) {
        reset_dirty(ts, page_min, page_max, page24, cpage);
    }
}
335
static void tcx_invalidate_display(void *opaque)
336
{
bellard authored
337
338
339
340
    TCXState *s = opaque;
    int i;

    for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) {
blueswir1 authored
341
        cpu_physical_memory_set_dirty(s->vram_offset + i);
bellard authored
342
    }
343
344
}
blueswir1 authored
345
346
347
348
349
350
351
352
353
354
355
356
static void tcx24_invalidate_display(void *opaque)
{
    TCXState *s = opaque;
    int i;

    tcx_invalidate_display(s);
    for (i = 0; i < MAXX*MAXY * 4; i += TARGET_PAGE_SIZE) {
        cpu_physical_memory_set_dirty(s->vram24_offset + i);
        cpu_physical_memory_set_dirty(s->cplane_offset + i);
    }
}
bellard authored
357
static void tcx_save(QEMUFile *f, void *opaque)
358
359
{
    TCXState *s = opaque;
360
361
362
363
    qemu_put_be16s(f, &s->height);
    qemu_put_be16s(f, &s->width);
    qemu_put_be16s(f, &s->depth);
bellard authored
364
365
366
    qemu_put_buffer(f, s->r, 256);
    qemu_put_buffer(f, s->g, 256);
    qemu_put_buffer(f, s->b, 256);
bellard authored
367
368
    qemu_put_8s(f, &s->dac_index);
    qemu_put_8s(f, &s->dac_state);
369
370
}
bellard authored
371
static int tcx_load(QEMUFile *f, void *opaque, int version_id)
372
{
bellard authored
373
    TCXState *s = opaque;
blueswir1 authored
374
375
376
    uint32_t dummy;

    if (version_id != 3 && version_id != 4)
bellard authored
377
378
        return -EINVAL;
blueswir1 authored
379
    if (version_id == 3) {
380
381
382
        qemu_get_be32s(f, &dummy);
        qemu_get_be32s(f, &dummy);
        qemu_get_be32s(f, &dummy);
blueswir1 authored
383
    }
384
385
386
    qemu_get_be16s(f, &s->height);
    qemu_get_be16s(f, &s->width);
    qemu_get_be16s(f, &s->depth);
bellard authored
387
388
389
    qemu_get_buffer(f, s->r, 256);
    qemu_get_buffer(f, s->g, 256);
    qemu_get_buffer(f, s->b, 256);
bellard authored
390
391
    qemu_get_8s(f, &s->dac_index);
    qemu_get_8s(f, &s->dac_state);
392
    update_palette_entries(s, 0, 256);
393
394
395
396
    if (s->depth == 24)
        tcx24_invalidate_display(s);
    else
        tcx_invalidate_display(s);
397
bellard authored
398
    return 0;
399
400
}
bellard authored
401
static void tcx_reset(void *opaque)
402
{
bellard authored
403
404
405
406
407
408
409
    TCXState *s = opaque;

    /* Initialize palette */
    memset(s->r, 0, 256);
    memset(s->g, 0, 256);
    memset(s->b, 0, 256);
    s->r[255] = s->g[255] = s->b[255] = 255;
410
    update_palette_entries(s, 0, 256);
bellard authored
411
    memset(s->vram, 0, MAXX*MAXY);
blueswir1 authored
412
413
    cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset +
                                    MAXX * MAXY * (1 + 4 + 4), VGA_DIRTY_FLAG);
bellard authored
414
415
416
417
418
419
420
421
422
423
424
425
426
    s->dac_index = 0;
    s->dac_state = 0;
}

static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
{
    return 0;
}

static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
    TCXState *s = opaque;
blueswir1 authored
427
    switch (addr) {
bellard authored
428
    case 0:
blueswir1 authored
429
430
431
        s->dac_index = val >> 24;
        s->dac_state = 0;
        break;
blueswir1 authored
432
    case 4:
blueswir1 authored
433
434
435
        switch (s->dac_state) {
        case 0:
            s->r[s->dac_index] = val >> 24;
436
            update_palette_entries(s, s->dac_index, s->dac_index + 1);
blueswir1 authored
437
438
439
440
            s->dac_state++;
            break;
        case 1:
            s->g[s->dac_index] = val >> 24;
441
            update_palette_entries(s, s->dac_index, s->dac_index + 1);
blueswir1 authored
442
443
444
445
            s->dac_state++;
            break;
        case 2:
            s->b[s->dac_index] = val >> 24;
446
            update_palette_entries(s, s->dac_index, s->dac_index + 1);
blueswir1 authored
447
            s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
blueswir1 authored
448
449
450
451
452
        default:
            s->dac_state = 0;
            break;
        }
        break;
bellard authored
453
    default:
blueswir1 authored
454
        break;
bellard authored
455
456
    }
    return;
457
458
}
bellard authored
459
static CPUReadMemoryFunc *tcx_dac_read[3] = {
460
461
    NULL,
    NULL,
bellard authored
462
463
464
465
    tcx_dac_readl,
};

static CPUWriteMemoryFunc *tcx_dac_write[3] = {
466
467
    NULL,
    NULL,
bellard authored
468
469
470
    tcx_dac_writel,
};
471
472
473
474
475
476
477
478
479
480
481
static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr)
{
    return 0;
}

static void tcx_dummy_writel(void *opaque, target_phys_addr_t addr,
                             uint32_t val)
{
}

static CPUReadMemoryFunc *tcx_dummy_read[3] = {
482
483
    NULL,
    NULL,
484
485
486
487
    tcx_dummy_readl,
};

static CPUWriteMemoryFunc *tcx_dummy_write[3] = {
488
489
    NULL,
    NULL,
490
491
492
    tcx_dummy_writel,
};
493
void tcx_init(target_phys_addr_t addr, uint8_t *vram_base,
blueswir1 authored
494
495
              unsigned long vram_offset, int vram_size, int width, int height,
              int depth)
496
497
{
    TCXState *s;
498
    int io_memory, dummy_memory;
blueswir1 authored
499
    int size;
500
501

    s = qemu_mallocz(sizeof(TCXState));
bellard authored
502
    s->addr = addr;
bellard authored
503
    s->vram_offset = vram_offset;
bellard authored
504
505
    s->width = width;
    s->height = height;
blueswir1 authored
506
507
508
509
510
    s->depth = depth;

    // 8-bit plane
    s->vram = vram_base;
    size = vram_size;
511
    cpu_register_physical_memory(addr + 0x00800000ULL, size, vram_offset);
blueswir1 authored
512
513
    vram_offset += size;
    vram_base += size;
bellard authored
514
bellard authored
515
    io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s);
blueswir1 authored
516
517
    cpu_register_physical_memory(addr + 0x00200000ULL, TCX_DAC_NREGS,
                                 io_memory);
blueswir1 authored
518
519
520
    dummy_memory = cpu_register_io_memory(0, tcx_dummy_read, tcx_dummy_write,
                                          s);
521
    cpu_register_physical_memory(addr + 0x00700000ULL, TCX_TEC_NREGS,
522
                                 dummy_memory);
blueswir1 authored
523
524
525
526
527
    if (depth == 24) {
        // 24-bit plane
        size = vram_size * 4;
        s->vram24 = (uint32_t *)vram_base;
        s->vram24_offset = vram_offset;
528
        cpu_register_physical_memory(addr + 0x02000000ULL, size, vram_offset);
blueswir1 authored
529
530
531
532
533
534
535
        vram_offset += size;
        vram_base += size;

        // Control plane
        size = vram_size * 4;
        s->cplane = (uint32_t *)vram_base;
        s->cplane_offset = vram_offset;
536
        cpu_register_physical_memory(addr + 0x0a000000ULL, size, vram_offset);
537
538
539
        s->ds = graphic_console_init(tcx24_update_display,
                                     tcx24_invalidate_display,
                                     tcx24_screen_dump, NULL, s);
blueswir1 authored
540
    } else {
541
        cpu_register_physical_memory(addr + 0x00300000ULL, TCX_THC_NREGS_8,
542
                                     dummy_memory);
543
544
545
        s->ds = graphic_console_init(tcx_update_display,
                                     tcx_invalidate_display,
                                     tcx_screen_dump, NULL, s);
blueswir1 authored
546
    }
547
    // NetBSD writes here even with 8-bit display
548
    cpu_register_physical_memory(addr + 0x00301000ULL, TCX_THC_NREGS_24,
549
                                 dummy_memory);
bellard authored
550
blueswir1 authored
551
    register_savevm("tcx", addr, 4, tcx_save, tcx_load, s);
bellard authored
552
553
    qemu_register_reset(tcx_reset, s);
    tcx_reset(s);
554
    qemu_console_resize(s->ds, width, height);
555
556
}
557
static void tcx_screen_dump(void *opaque, const char *filename)
bellard authored
558
{
bellard authored
559
    TCXState *s = opaque;
bellard authored
560
    FILE *f;
bellard authored
561
    uint8_t *d, *d1, v;
bellard authored
562
563
564
565
    int y, x;

    f = fopen(filename, "wb");
    if (!f)
bellard authored
566
        return;
bellard authored
567
568
569
    fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
    d1 = s->vram;
    for(y = 0; y < s->height; y++) {
bellard authored
570
        d = d1;
bellard authored
571
        for(x = 0; x < s->width; x++) {
bellard authored
572
            v = *d;
bellard authored
573
574
575
            fputc(s->r[v], f);
            fputc(s->g[v], f);
            fputc(s->b[v], f);
bellard authored
576
577
            d++;
        }
bellard authored
578
        d1 += MAXX;
bellard authored
579
580
581
582
583
    }
    fclose(f);
    return;
}
blueswir1 authored
584
585
586
587
588
589
590
static void tcx24_screen_dump(void *opaque, const char *filename)
{
    TCXState *s = opaque;
    FILE *f;
    uint8_t *d, *d1, v;
    uint32_t *s24, *cptr, dval;
    int y, x;
bellard authored
591
blueswir1 authored
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
    f = fopen(filename, "wb");
    if (!f)
        return;
    fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
    d1 = s->vram;
    s24 = s->vram24;
    cptr = s->cplane;
    for(y = 0; y < s->height; y++) {
        d = d1;
        for(x = 0; x < s->width; x++, d++, s24++) {
            if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
                dval = *s24 & 0x00ffffff;
                fputc((dval >> 16) & 0xff, f);
                fputc((dval >> 8) & 0xff, f);
                fputc(dval & 0xff, f);
            } else {
                v = *d;
                fputc(s->r[v], f);
                fputc(s->g[v], f);
                fputc(s->b[v], f);
            }
        }
        d1 += MAXX;
    }
    fclose(f);
    return;
}