|
1
|
/*
|
|
2
|
* QEMU TCX Frame buffer
|
ths
authored
|
3
|
*
|
|
4
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
ths
authored
|
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.
*/
|
|
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
|
|
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;
|
|
39
|
uint8_t *vram;
|
|
40
41
42
|
uint32_t *vram24, *cplane;
ram_addr_t vram_offset, vram24_offset, cplane_offset;
uint16_t width, height, depth;
|
|
43
|
uint8_t r[256], g[256], b[256];
|
|
44
|
uint32_t palette[256];
|
|
45
|
uint8_t dac_index, dac_state;
|
|
46
47
|
} TCXState;
|
|
48
|
static void tcx_screen_dump(void *opaque, const char *filename);
|
|
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
57
58
59
60
61
62
|
static void update_palette_entries(TCXState *s, int start, int end)
{
int i;
for(i = start; i < end; i++) {
switch(s->ds->depth) {
default:
case 8:
s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
break;
case 15:
|
|
63
64
65
66
|
if (s->ds->bgr)
s->palette[i] = rgb_to_pixel15bgr(s->r[i], s->g[i], s->b[i]);
else
s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
|
|
67
68
|
break;
case 16:
|
|
69
70
71
72
|
if (s->ds->bgr)
s->palette[i] = rgb_to_pixel16bgr(s->r[i], s->g[i], s->b[i]);
else
s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
|
|
73
74
|
break;
case 32:
|
|
75
76
77
78
|
if (s->ds->bgr)
s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
else
s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
|
|
79
80
81
|
break;
}
}
|
|
82
83
84
85
|
if (s->depth == 24)
tcx24_invalidate_display(s);
else
tcx_invalidate_display(s);
|
|
86
87
|
}
|
ths
authored
|
88
|
static void tcx_draw_line32(TCXState *s1, uint8_t *d,
|
|
89
|
const uint8_t *s, int width)
|
|
90
|
{
|
|
91
92
|
int x;
uint8_t val;
|
ths
authored
|
93
|
uint32_t *p = (uint32_t *)d;
|
|
94
95
|
for(x = 0; x < width; x++) {
|
|
96
|
val = *s++;
|
ths
authored
|
97
|
*p++ = s1->palette[val];
|
|
98
|
}
|
|
99
100
|
}
|
ths
authored
|
101
|
static void tcx_draw_line16(TCXState *s1, uint8_t *d,
|
|
102
|
const uint8_t *s, int width)
|
|
103
104
105
|
{
int x;
uint8_t val;
|
ths
authored
|
106
|
uint16_t *p = (uint16_t *)d;
|
|
107
|
|
|
108
|
for(x = 0; x < width; x++) {
|
|
109
|
val = *s++;
|
ths
authored
|
110
|
*p++ = s1->palette[val];
|
|
111
112
113
|
}
}
|
ths
authored
|
114
|
static void tcx_draw_line8(TCXState *s1, uint8_t *d,
|
|
115
|
const uint8_t *s, int width)
|
|
116
|
{
|
|
117
118
119
120
|
int x;
uint8_t val;
for(x = 0; x < width; x++) {
|
|
121
|
val = *s++;
|
|
122
|
*d++ = s1->palette[val];
|
|
123
124
125
|
}
}
|
|
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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
|
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)
{
int x;
uint8_t val;
uint32_t *p = (uint32_t *)d;
uint32_t dval;
for(x = 0; x < width; x++, s++, s24++) {
if ((bswap32(*cplane++) & 0xff000000) == 0x03000000) { // 24-bit direct
dval = bswap32(*s24) & 0x00ffffff;
} else {
val = *s;
dval = s1->palette[val];
}
*p++ = dval;
}
}
static inline int check_dirty(TCXState *ts, ram_addr_t page, ram_addr_t page24,
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);
}
|
|
177
178
|
/* Fixed line length 1024 allows us to do nice tricks not possible on
VGA... */
|
|
179
|
static void tcx_update_display(void *opaque)
|
|
180
|
{
|
|
181
|
TCXState *ts = opaque;
|
|
182
183
|
ram_addr_t page, page_min, page_max;
int y, y_start, dd, ds;
|
|
184
|
uint8_t *d, *s;
|
|
185
|
void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
|
|
186
187
|
if (ts->ds->depth == 0)
|
|
188
|
return;
|
|
189
|
page = ts->vram_offset;
|
|
190
|
y_start = -1;
|
|
191
192
|
page_min = 0xffffffff;
page_max = 0;
|
|
193
|
d = ts->ds->data;
|
|
194
|
s = ts->vram;
|
|
195
196
197
198
199
|
dd = ts->ds->linesize;
ds = 1024;
switch (ts->ds->depth) {
case 32:
|
|
200
201
|
f = tcx_draw_line32;
break;
|
|
202
203
|
case 15:
case 16:
|
|
204
205
|
f = tcx_draw_line16;
break;
|
|
206
207
|
default:
case 8:
|
|
208
209
|
f = tcx_draw_line8;
break;
|
|
210
|
case 0:
|
|
211
|
return;
|
|
212
|
}
|
ths
authored
|
213
|
|
|
214
|
for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
|
|
215
216
|
if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
if (y_start < 0)
|
|
217
218
219
220
221
|
y_start = y;
if (page < page_min)
page_min = page;
if (page > page_max)
page_max = page;
|
|
222
223
224
225
226
227
228
229
230
231
232
233
234
|
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 {
|
|
235
236
|
if (y_start >= 0) {
/* flush to display */
|
ths
authored
|
237
|
dpy_update(ts->ds, 0, y_start,
|
|
238
|
ts->width, y - y_start);
|
|
239
240
|
y_start = -1;
}
|
|
241
242
243
|
d += dd * 4;
s += ds * 4;
}
|
|
244
245
|
}
if (y_start >= 0) {
|
|
246
247
248
|
/* flush to display */
dpy_update(ts->ds, 0, y_start,
ts->width, y - y_start);
|
|
249
250
|
}
/* reset modified pages */
|
|
251
|
if (page_min <= page_max) {
|
|
252
253
|
cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
VGA_DIRTY_FLAG);
|
|
254
|
}
|
|
255
256
|
}
|
|
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
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
|
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;
if (ts->ds->depth != 32)
return;
page = ts->vram_offset;
page24 = ts->vram24_offset;
cpage = ts->cplane_offset;
y_start = -1;
page_min = 0xffffffff;
page_max = 0;
d = ts->ds->data;
s = ts->vram;
s24 = ts->vram24;
cptr = ts->cplane;
dd = ts->ds->linesize;
ds = 1024;
for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
if (check_dirty(ts, page, page24, cpage)) {
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);
}
}
|
|
333
|
static void tcx_invalidate_display(void *opaque)
|
|
334
|
{
|
|
335
336
337
338
|
TCXState *s = opaque;
int i;
for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) {
|
|
339
|
cpu_physical_memory_set_dirty(s->vram_offset + i);
|
|
340
|
}
|
|
341
342
|
}
|
|
343
344
345
346
347
348
349
350
351
352
353
354
|
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);
}
}
|
|
355
|
static void tcx_save(QEMUFile *f, void *opaque)
|
|
356
357
|
{
TCXState *s = opaque;
|
ths
authored
|
358
|
|
|
359
360
|
qemu_put_be16s(f, (uint16_t *)&s->height);
qemu_put_be16s(f, (uint16_t *)&s->width);
|
|
361
|
qemu_put_be16s(f, (uint16_t *)&s->depth);
|
|
362
363
364
|
qemu_put_buffer(f, s->r, 256);
qemu_put_buffer(f, s->g, 256);
qemu_put_buffer(f, s->b, 256);
|
|
365
366
|
qemu_put_8s(f, &s->dac_index);
qemu_put_8s(f, &s->dac_state);
|
|
367
368
|
}
|
|
369
|
static int tcx_load(QEMUFile *f, void *opaque, int version_id)
|
|
370
|
{
|
|
371
|
TCXState *s = opaque;
|
|
372
373
374
|
uint32_t dummy;
if (version_id != 3 && version_id != 4)
|
|
375
376
|
return -EINVAL;
|
|
377
378
379
380
381
|
if (version_id == 3) {
qemu_get_be32s(f, (uint32_t *)&dummy);
qemu_get_be32s(f, (uint32_t *)&dummy);
qemu_get_be32s(f, (uint32_t *)&dummy);
}
|
|
382
383
|
qemu_get_be16s(f, (uint16_t *)&s->height);
qemu_get_be16s(f, (uint16_t *)&s->width);
|
|
384
|
qemu_get_be16s(f, (uint16_t *)&s->depth);
|
|
385
386
387
|
qemu_get_buffer(f, s->r, 256);
qemu_get_buffer(f, s->g, 256);
qemu_get_buffer(f, s->b, 256);
|
|
388
389
|
qemu_get_8s(f, &s->dac_index);
qemu_get_8s(f, &s->dac_state);
|
|
390
|
update_palette_entries(s, 0, 256);
|
|
391
392
393
394
|
if (s->depth == 24)
tcx24_invalidate_display(s);
else
tcx_invalidate_display(s);
|
|
395
|
|
|
396
|
return 0;
|
|
397
398
|
}
|
|
399
|
static void tcx_reset(void *opaque)
|
|
400
|
{
|
|
401
402
403
404
405
406
407
|
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;
|
|
408
|
update_palette_entries(s, 0, 256);
|
|
409
|
memset(s->vram, 0, MAXX*MAXY);
|
|
410
411
|
cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset +
MAXX * MAXY * (1 + 4 + 4), VGA_DIRTY_FLAG);
|
|
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
|
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;
uint32_t saddr;
saddr = (addr & (TCX_DAC_NREGS - 1)) >> 2;
switch (saddr) {
case 0:
|
|
429
430
431
|
s->dac_index = val >> 24;
s->dac_state = 0;
break;
|
|
432
|
case 1:
|
|
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);
|
|
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);
|
|
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);
|
|
447
|
s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
|
|
448
449
450
451
452
|
default:
s->dac_state = 0;
break;
}
break;
|
|
453
|
default:
|
|
454
|
break;
|
|
455
456
|
}
return;
|
|
457
458
|
}
|
|
459
460
461
462
463
464
465
466
467
468
469
470
|
static CPUReadMemoryFunc *tcx_dac_read[3] = {
tcx_dac_readl,
tcx_dac_readl,
tcx_dac_readl,
};
static CPUWriteMemoryFunc *tcx_dac_write[3] = {
tcx_dac_writel,
tcx_dac_writel,
tcx_dac_writel,
};
|
|
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
|
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] = {
tcx_dummy_readl,
tcx_dummy_readl,
tcx_dummy_readl,
};
static CPUWriteMemoryFunc *tcx_dummy_write[3] = {
tcx_dummy_writel,
tcx_dummy_writel,
tcx_dummy_writel,
};
|
|
493
|
void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base,
|
|
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;
|
|
499
|
int size;
|
|
500
501
502
|
s = qemu_mallocz(sizeof(TCXState));
if (!s)
|
|
503
|
return;
|
|
504
|
s->ds = ds;
|
|
505
|
s->addr = addr;
|
|
506
|
s->vram_offset = vram_offset;
|
|
507
508
|
s->width = width;
s->height = height;
|
|
509
510
511
512
513
|
s->depth = depth;
// 8-bit plane
s->vram = vram_base;
size = vram_size;
|
|
514
|
cpu_register_physical_memory(addr + 0x00800000ULL, size, vram_offset);
|
|
515
516
|
vram_offset += size;
vram_base += size;
|
|
517
|
|
|
518
|
io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s);
|
|
519
|
cpu_register_physical_memory(addr + 0x00200000ULL, TCX_DAC_NREGS, io_memory);
|
|
520
|
|
|
521
522
|
dummy_memory = cpu_register_io_memory(0, tcx_dummy_read, tcx_dummy_write,
s);
|
|
523
|
cpu_register_physical_memory(addr + 0x00700000ULL, TCX_TEC_NREGS,
|
|
524
|
dummy_memory);
|
|
525
526
527
528
529
|
if (depth == 24) {
// 24-bit plane
size = vram_size * 4;
s->vram24 = (uint32_t *)vram_base;
s->vram24_offset = vram_offset;
|
|
530
|
cpu_register_physical_memory(addr + 0x02000000ULL, size, vram_offset);
|
|
531
532
533
534
535
536
537
|
vram_offset += size;
vram_base += size;
// Control plane
size = vram_size * 4;
s->cplane = (uint32_t *)vram_base;
s->cplane_offset = vram_offset;
|
|
538
|
cpu_register_physical_memory(addr + 0x0a000000ULL, size, vram_offset);
|
|
539
540
|
graphic_console_init(s->ds, tcx24_update_display,
tcx24_invalidate_display, tcx24_screen_dump, s);
|
|
541
|
} else {
|
|
542
|
cpu_register_physical_memory(addr + 0x00300000ULL, TCX_THC_NREGS_8,
|
|
543
|
dummy_memory);
|
|
544
545
546
|
graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display,
tcx_screen_dump, s);
}
|
|
547
|
// NetBSD writes here even with 8-bit display
|
|
548
|
cpu_register_physical_memory(addr + 0x00301000ULL, TCX_THC_NREGS_24,
|
|
549
|
dummy_memory);
|
|
550
|
|
|
551
|
register_savevm("tcx", addr, 4, tcx_save, tcx_load, s);
|
|
552
553
|
qemu_register_reset(tcx_reset, s);
tcx_reset(s);
|
|
554
|
dpy_resize(s->ds, width, height);
|
|
555
556
|
}
|
|
557
|
static void tcx_screen_dump(void *opaque, const char *filename)
|
|
558
|
{
|
|
559
|
TCXState *s = opaque;
|
|
560
|
FILE *f;
|
|
561
|
uint8_t *d, *d1, v;
|
|
562
563
564
565
|
int y, x;
f = fopen(filename, "wb");
if (!f)
|
|
566
|
return;
|
|
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++) {
|
|
570
|
d = d1;
|
|
571
|
for(x = 0; x < s->width; x++) {
|
|
572
|
v = *d;
|
|
573
574
575
|
fputc(s->r[v], f);
fputc(s->g[v], f);
fputc(s->b[v], f);
|
|
576
577
|
d++;
}
|
|
578
|
d1 += MAXX;
|
|
579
580
581
582
583
|
}
fclose(f);
return;
}
|
|
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;
|
|
591
|
|
|
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;
}
|