Statistics
| Branch: | Revision:

root / hw / g364fb.c @ bf5b7423

History | View | Annotate | Download (10.3 kB)

1
/*
2
 * QEMU G364 framebuffer Emulator.
3
 *
4
 * Copyright (c) 2007-2008 Hervé Poussineau
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License as
8
 * published by the Free Software Foundation; either version 2 of
9
 * the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19
 * MA 02111-1307 USA
20
 */
21

    
22
#include "hw.h"
23
#include "console.h"
24
#include "pixel_ops.h"
25

    
26
//#define DEBUG_G364
27

    
28
typedef struct G364State {
29
    target_phys_addr_t vram_base;
30
    unsigned int vram_size;
31
    uint8_t *vram_buffer;
32
    uint32_t ctla;
33
    uint8_t palette[256][3];
34
    /* display refresh support */
35
    DisplayState *ds;
36
    int graphic_mode;
37
    uint32_t scr_width, scr_height; /* in pixels */
38
    uint32_t last_scr_width, last_scr_height; /* in pixels */
39
} G364State;
40

    
41
/*
42
 * graphic modes
43
 */
44
#define BPP 8
45
#define PIXEL_WIDTH 8
46
#include "g364fb_template.h"
47
#undef BPP
48
#undef PIXEL_WIDTH
49

    
50
#define BPP 15
51
#define PIXEL_WIDTH 16
52
#include "g364fb_template.h"
53
#undef BPP
54
#undef PIXEL_WIDTH
55

    
56
#define BPP 16
57
#define PIXEL_WIDTH 16
58
#include "g364fb_template.h"
59
#undef BPP
60
#undef PIXEL_WIDTH
61

    
62
#define BPP 32
63
#define PIXEL_WIDTH 32
64
#include "g364fb_template.h"
65
#undef BPP
66
#undef PIXEL_WIDTH
67

    
68
#define REG_DISPLAYX 0x0918
69
#define REG_DISPLAYY 0x0940
70

    
71
#define CTLA_FORCE_BLANK 0x400
72

    
73
static void g364fb_draw_graphic(G364State *s, int full_update)
74
{
75
    if (s->scr_width == 0 || s->scr_height == 0)
76
        return;
77
    if (s->scr_width != s->last_scr_width
78
     || s->scr_height != s->last_scr_height) {
79
        s->last_scr_width = s->scr_width;
80
        s->last_scr_height = s->scr_height;
81
        dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
82
        full_update = 1;
83
    }
84

    
85
    switch (s->ds->depth) {
86
        case 8:
87
            g364fb_draw_graphic8(s, full_update);
88
            break;
89
        case 15:
90
            g364fb_draw_graphic15(s, full_update);
91
            break;
92
        case 16:
93
            g364fb_draw_graphic16(s, full_update);
94
            break;
95
        case 32:
96
            g364fb_draw_graphic32(s, full_update);
97
            break;
98
        default:
99
            printf("g364fb: unknown depth %d\n", s->ds->depth);
100
            return;
101
    }
102

    
103
    dpy_update(s->ds, 0, 0, s->last_scr_width, s->last_scr_height);
104
}
105

    
106
static void g364fb_draw_blank(G364State *s, int full_update)
107
{
108
    int i, w;
109
    uint8_t *d;
110

    
111
    if (!full_update)
112
        return;
113
    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
114
        return;
115

    
116
    w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
117
    d = s->ds->data;
118
    for(i = 0; i < s->last_scr_height; i++) {
119
        memset(d, 0, w);
120
        d += s->ds->linesize;
121
    }
122
    dpy_update(s->ds, 0, 0,
123
               s->last_scr_width, s->last_scr_height);
124
}
125

    
126
#define GMODE_GRAPH 0
127
#define GMODE_BLANK 1
128

    
129
static void g364fb_update_display(void *opaque)
130
{
131
    G364State *s = opaque;
132
    int full_update, graphic_mode;
133

    
134
    if (s->ctla & CTLA_FORCE_BLANK)
135
        graphic_mode = GMODE_BLANK;
136
    else
137
        graphic_mode = GMODE_GRAPH;
138
    full_update = 0;
139
    if (graphic_mode != s->graphic_mode) {
140
        s->graphic_mode = graphic_mode;
141
        full_update = 1;
142
    }
143
    switch(graphic_mode) {
144
        case GMODE_GRAPH:
145
            g364fb_draw_graphic(s, full_update);
146
            break;
147
        case GMODE_BLANK:
148
        default:
149
            g364fb_draw_blank(s, full_update);
150
            break;
151
    }
152
}
153

    
154
/* force a full display refresh */
155
static void g364fb_invalidate_display(void *opaque)
156
{
157
    G364State *s = opaque;
158
    s->graphic_mode = -1; /* force full update */
159
}
160

    
161
static void g364fb_reset(void *opaque)
162
{
163
    G364State *s = opaque;
164

    
165
    memset(s->palette, 0, sizeof(s->palette));
166
    s->scr_width = s->scr_height = 0;
167
    s->last_scr_width = s->last_scr_height = 0;
168
    memset(s->vram_buffer, 0, s->vram_size);
169
    s->graphic_mode = -1; /* force full update */
170
}
171

    
172
static void g364fb_screen_dump(void *opaque, const char *filename)
173
{
174
    G364State *s = opaque;
175
    int y, x;
176
    uint8_t index;
177
    uint8_t *data_buffer;
178
    FILE *f;
179

    
180
    f = fopen(filename, "wb");
181
    if (!f)
182
        return;
183

    
184
    data_buffer = s->vram_buffer;
185
    fprintf(f, "P6\n%d %d\n%d\n",
186
        s->scr_width, s->scr_height, 255);
187
    for(y = 0; y < s->scr_height; y++)
188
        for(x = 0; x < s->scr_width; x++, data_buffer++) {
189
            index = *data_buffer;
190
            fputc(s->palette[index][0], f);
191
            fputc(s->palette[index][1], f);
192
            fputc(s->palette[index][2], f);
193
        }
194
    fclose(f);
195
}
196

    
197
/* called for accesses to io ports */
198
static uint32_t g364fb_ctrl_readb(void *opaque, target_phys_addr_t addr)
199
{
200
    //G364State *s = opaque;
201
    uint32_t val;
202

    
203
    addr &= 0xffff;
204

    
205
    switch (addr) {
206
        default:
207
#ifdef DEBUG_G364
208
            printf("g364fb/ctrl: invalid read at [" TARGET_FMT_lx "]\n", addr);
209
#endif
210
            val = 0;
211
            break;
212
    }
213

    
214
#ifdef DEBUG_G364
215
    printf("g364fb/ctrl: read 0x%02x at [" TARGET_FMT_lx "]\n", val, addr);
216
#endif
217

    
218
    return val;
219
}
220

    
221
static uint32_t g364fb_ctrl_readw(void *opaque, target_phys_addr_t addr)
222
{
223
    uint32_t v;
224
    v = g364fb_ctrl_readb(opaque, addr);
225
    v |= g364fb_ctrl_readb(opaque, addr + 1) << 8;
226
    return v;
227
}
228

    
229
static uint32_t g364fb_ctrl_readl(void *opaque, target_phys_addr_t addr)
230
{
231
    uint32_t v;
232
    v = g364fb_ctrl_readb(opaque, addr);
233
    v |= g364fb_ctrl_readb(opaque, addr + 1) << 8;
234
    v |= g364fb_ctrl_readb(opaque, addr + 2) << 16;
235
    v |= g364fb_ctrl_readb(opaque, addr + 3) << 24;
236
    return v;
237
}
238

    
239
static void g364fb_ctrl_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
240
{
241
    G364State *s = opaque;
242

    
243
    addr &= 0xffff;
244

    
245
#ifdef DEBUG_G364
246
    printf("g364fb/ctrl: write 0x%02x at [" TARGET_FMT_lx "]\n", val, addr);
247
#endif
248

    
249
    if (addr < 0x0800) {
250
        /* color palette */
251
        int idx = addr >> 3;
252
        int c = addr & 7;
253
        if (c < 3)
254
            s->palette[idx][c] = (uint8_t)val;
255
    } else {
256
        switch (addr) {
257
            case REG_DISPLAYX:
258
                s->scr_width = (s->scr_width & 0xfffffc03) | (val << 2);
259
                break;
260
            case REG_DISPLAYX + 1:
261
                s->scr_width = (s->scr_width & 0xfffc03ff) | (val << 10);
262
                break;
263
            case REG_DISPLAYY:
264
                s->scr_height = (s->scr_height & 0xffffff80) | (val >> 1);
265
                break;
266
            case REG_DISPLAYY + 1:
267
                s->scr_height = (s->scr_height & 0xffff801f) | (val << 7);
268
                break;
269
            default:
270
#ifdef DEBUG_G364
271
                printf("g364fb/ctrl: invalid write of 0x%02x at [" TARGET_FMT_lx "]\n", val, addr);
272
#endif
273
                break;
274
        }
275
    }
276
}
277

    
278
static void g364fb_ctrl_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
279
{
280
    g364fb_ctrl_writeb(opaque, addr, val & 0xff);
281
    g364fb_ctrl_writeb(opaque, addr + 1, (val >> 8) & 0xff);
282
}
283

    
284
static void g364fb_ctrl_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
285
{
286
    g364fb_ctrl_writeb(opaque, addr, val & 0xff);
287
    g364fb_ctrl_writeb(opaque, addr + 1, (val >> 8) & 0xff);
288
    g364fb_ctrl_writeb(opaque, addr + 2, (val >> 16) & 0xff);
289
    g364fb_ctrl_writeb(opaque, addr + 3, (val >> 24) & 0xff);
290
}
291

    
292
static CPUReadMemoryFunc *g364fb_ctrl_read[3] = {
293
    g364fb_ctrl_readb,
294
    g364fb_ctrl_readw,
295
    g364fb_ctrl_readl,
296
};
297

    
298
static CPUWriteMemoryFunc *g364fb_ctrl_write[3] = {
299
    g364fb_ctrl_writeb,
300
    g364fb_ctrl_writew,
301
    g364fb_ctrl_writel,
302
};
303

    
304
/* called for accesses to video ram */
305
static uint32_t g364fb_mem_readb(void *opaque, target_phys_addr_t addr)
306
{
307
    G364State *s = opaque;
308
    target_phys_addr_t relative_addr = addr - s->vram_base;
309

    
310
    return s->vram_buffer[relative_addr];
311
}
312

    
313
static uint32_t g364fb_mem_readw(void *opaque, target_phys_addr_t addr)
314
{
315
    uint32_t v;
316
    v = g364fb_mem_readb(opaque, addr);
317
    v |= g364fb_mem_readb(opaque, addr + 1) << 8;
318
    return v;
319
}
320

    
321
static uint32_t g364fb_mem_readl(void *opaque, target_phys_addr_t addr)
322
{
323
    uint32_t v;
324
    v = g364fb_mem_readb(opaque, addr);
325
    v |= g364fb_mem_readb(opaque, addr + 1) << 8;
326
    v |= g364fb_mem_readb(opaque, addr + 2) << 16;
327
    v |= g364fb_mem_readb(opaque, addr + 3) << 24;
328
    return v;
329
}
330

    
331
static void g364fb_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
332
{
333
    G364State *s = opaque;
334
    target_phys_addr_t relative_addr = addr - s->vram_base;
335

    
336
    s->vram_buffer[relative_addr] = val;
337
}
338

    
339
static void g364fb_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
340
{
341
    g364fb_mem_writeb(opaque, addr, val & 0xff);
342
    g364fb_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
343
}
344

    
345
static void g364fb_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
346
{
347
    g364fb_mem_writeb(opaque, addr, val & 0xff);
348
    g364fb_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
349
    g364fb_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
350
    g364fb_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
351
}
352

    
353
static CPUReadMemoryFunc *g364fb_mem_read[3] = {
354
    g364fb_mem_readb,
355
    g364fb_mem_readw,
356
    g364fb_mem_readl,
357
};
358

    
359
static CPUWriteMemoryFunc *g364fb_mem_write[3] = {
360
    g364fb_mem_writeb,
361
    g364fb_mem_writew,
362
    g364fb_mem_writel,
363
};
364

    
365
int g364fb_mm_init(DisplayState *ds,
366
                   int vram_size, int it_shift,
367
                   target_phys_addr_t vram_base, target_phys_addr_t ctrl_base)
368
{
369
    G364State *s;
370
    int io_vram, io_ctrl;
371

    
372
    s = qemu_mallocz(sizeof(G364State));
373
    if (!s)
374
        return -1;
375

    
376
    s->vram_size = vram_size;
377
    s->vram_buffer = qemu_mallocz(s->vram_size);
378

    
379
    qemu_register_reset(g364fb_reset, s);
380
    g364fb_reset(s);
381

    
382
    s->ds = ds;
383
    s->vram_base = vram_base;
384

    
385
    graphic_console_init(ds, g364fb_update_display,
386
                         g364fb_invalidate_display, g364fb_screen_dump,
387
                         NULL, s);
388

    
389
    io_vram = cpu_register_io_memory(0, g364fb_mem_read, g364fb_mem_write, s);
390
    cpu_register_physical_memory(s->vram_base, vram_size, io_vram);
391

    
392
    io_ctrl = cpu_register_io_memory(0, g364fb_ctrl_read, g364fb_ctrl_write, s);
393
    cpu_register_physical_memory(ctrl_base, 0x10000, io_ctrl);
394

    
395
    return 0;
396
}