|
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 "mips.h" |
|
24 #include "console.h" |
|
25 #include "pixel_ops.h" |
|
26 |
|
27 //#define DEBUG_G364 |
|
28 |
|
29 typedef struct G364State { |
|
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 QEMUConsole *console; |
|
37 int graphic_mode; |
|
38 uint32_t scr_width, 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 switch (ds_get_bits_per_pixel(s->ds)) { |
|
76 case 8: |
|
77 g364fb_draw_graphic8(s, full_update); |
|
78 break; |
|
79 case 15: |
|
80 g364fb_draw_graphic15(s, full_update); |
|
81 break; |
|
82 case 16: |
|
83 g364fb_draw_graphic16(s, full_update); |
|
84 break; |
|
85 case 32: |
|
86 g364fb_draw_graphic32(s, full_update); |
|
87 break; |
|
88 default: |
|
89 printf("g364fb: unknown depth %d\n", ds_get_bits_per_pixel(s->ds)); |
|
90 return; |
|
91 } |
|
92 |
|
93 dpy_update(s->ds, 0, 0, s->scr_width, s->scr_height); |
|
94 } |
|
95 |
|
96 static void g364fb_draw_blank(G364State *s, int full_update) |
|
97 { |
|
98 int i, w; |
|
99 uint8_t *d; |
|
100 |
|
101 if (!full_update) |
|
102 return; |
|
103 |
|
104 w = s->scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); |
|
105 d = ds_get_data(s->ds); |
|
106 for(i = 0; i < s->scr_height; i++) { |
|
107 memset(d, 0, w); |
|
108 d += ds_get_linesize(s->ds); |
|
109 } |
|
110 |
|
111 dpy_update(s->ds, 0, 0, s->scr_width, s->scr_height); |
|
112 } |
|
113 |
|
114 #define GMODE_GRAPH 0 |
|
115 #define GMODE_BLANK 1 |
|
116 |
|
117 static void g364fb_update_display(void *opaque) |
|
118 { |
|
119 G364State *s = opaque; |
|
120 int full_update, graphic_mode; |
|
121 |
|
122 if (s->scr_width == 0 || s->scr_height == 0) |
|
123 return; |
|
124 |
|
125 if (s->ctla & CTLA_FORCE_BLANK) |
|
126 graphic_mode = GMODE_BLANK; |
|
127 else |
|
128 graphic_mode = GMODE_GRAPH; |
|
129 full_update = 0; |
|
130 if (graphic_mode != s->graphic_mode) { |
|
131 s->graphic_mode = graphic_mode; |
|
132 full_update = 1; |
|
133 } |
|
134 if (s->scr_width != ds_get_width(s->ds) || s->scr_height != ds_get_height(s->ds)) { |
|
135 qemu_console_resize(s->console, s->scr_width, s->scr_height); |
|
136 full_update = 1; |
|
137 } |
|
138 switch(graphic_mode) { |
|
139 case GMODE_GRAPH: |
|
140 g364fb_draw_graphic(s, full_update); |
|
141 break; |
|
142 case GMODE_BLANK: |
|
143 default: |
|
144 g364fb_draw_blank(s, full_update); |
|
145 break; |
|
146 } |
|
147 } |
|
148 |
|
149 /* force a full display refresh */ |
|
150 static void g364fb_invalidate_display(void *opaque) |
|
151 { |
|
152 G364State *s = opaque; |
|
153 s->graphic_mode = -1; /* force full update */ |
|
154 } |
|
155 |
|
156 static void g364fb_reset(void *opaque) |
|
157 { |
|
158 G364State *s = opaque; |
|
159 |
|
160 memset(s->palette, 0, sizeof(s->palette)); |
|
161 s->scr_width = s->scr_height = 0; |
|
162 memset(s->vram_buffer, 0, s->vram_size); |
|
163 s->graphic_mode = -1; /* force full update */ |
|
164 } |
|
165 |
|
166 static void g364fb_screen_dump(void *opaque, const char *filename) |
|
167 { |
|
168 G364State *s = opaque; |
|
169 int y, x; |
|
170 uint8_t index; |
|
171 uint8_t *data_buffer; |
|
172 FILE *f; |
|
173 |
|
174 f = fopen(filename, "wb"); |
|
175 if (!f) |
|
176 return; |
|
177 |
|
178 data_buffer = s->vram_buffer; |
|
179 fprintf(f, "P6\n%d %d\n%d\n", |
|
180 s->scr_width, s->scr_height, 255); |
|
181 for(y = 0; y < s->scr_height; y++) |
|
182 for(x = 0; x < s->scr_width; x++, data_buffer++) { |
|
183 index = *data_buffer; |
|
184 fputc(s->palette[index][0], f); |
|
185 fputc(s->palette[index][1], f); |
|
186 fputc(s->palette[index][2], f); |
|
187 } |
|
188 fclose(f); |
|
189 } |
|
190 |
|
191 /* called for accesses to io ports */ |
|
192 static uint32_t g364fb_ctrl_readb(void *opaque, target_phys_addr_t addr) |
|
193 { |
|
194 //G364State *s = opaque; |
|
195 uint32_t val; |
|
196 |
|
197 addr &= 0xffff; |
|
198 |
|
199 switch (addr) { |
|
200 default: |
|
201 #ifdef DEBUG_G364 |
|
202 printf("g364fb/ctrl: invalid read at [" TARGET_FMT_lx "]\n", addr); |
|
203 #endif |
|
204 val = 0; |
|
205 break; |
|
206 } |
|
207 |
|
208 #ifdef DEBUG_G364 |
|
209 printf("g364fb/ctrl: read 0x%02x at [" TARGET_FMT_lx "]\n", val, addr); |
|
210 #endif |
|
211 |
|
212 return val; |
|
213 } |
|
214 |
|
215 static uint32_t g364fb_ctrl_readw(void *opaque, target_phys_addr_t addr) |
|
216 { |
|
217 uint32_t v; |
|
218 v = g364fb_ctrl_readb(opaque, addr); |
|
219 v |= g364fb_ctrl_readb(opaque, addr + 1) << 8; |
|
220 return v; |
|
221 } |
|
222 |
|
223 static uint32_t g364fb_ctrl_readl(void *opaque, target_phys_addr_t addr) |
|
224 { |
|
225 uint32_t v; |
|
226 v = g364fb_ctrl_readb(opaque, addr); |
|
227 v |= g364fb_ctrl_readb(opaque, addr + 1) << 8; |
|
228 v |= g364fb_ctrl_readb(opaque, addr + 2) << 16; |
|
229 v |= g364fb_ctrl_readb(opaque, addr + 3) << 24; |
|
230 return v; |
|
231 } |
|
232 |
|
233 static void g364fb_ctrl_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
234 { |
|
235 G364State *s = opaque; |
|
236 |
|
237 addr &= 0xffff; |
|
238 |
|
239 #ifdef DEBUG_G364 |
|
240 printf("g364fb/ctrl: write 0x%02x at [" TARGET_FMT_lx "]\n", val, addr); |
|
241 #endif |
|
242 |
|
243 if (addr < 0x0800) { |
|
244 /* color palette */ |
|
245 int idx = addr >> 3; |
|
246 int c = addr & 7; |
|
247 if (c < 3) |
|
248 s->palette[idx][c] = (uint8_t)val; |
|
249 } else { |
|
250 switch (addr) { |
|
251 case REG_DISPLAYX: |
|
252 s->scr_width = (s->scr_width & 0xfffffc03) | (val << 2); |
|
253 break; |
|
254 case REG_DISPLAYX + 1: |
|
255 s->scr_width = (s->scr_width & 0xfffc03ff) | (val << 10); |
|
256 break; |
|
257 case REG_DISPLAYY: |
|
258 s->scr_height = (s->scr_height & 0xffffff80) | (val >> 1); |
|
259 break; |
|
260 case REG_DISPLAYY + 1: |
|
261 s->scr_height = (s->scr_height & 0xffff801f) | (val << 7); |
|
262 break; |
|
263 default: |
|
264 #ifdef DEBUG_G364 |
|
265 printf("g364fb/ctrl: invalid write of 0x%02x at [" TARGET_FMT_lx "]\n", val, addr); |
|
266 #endif |
|
267 break; |
|
268 } |
|
269 } |
|
270 s->graphic_mode = -1; /* force full update */ |
|
271 } |
|
272 |
|
273 static void g364fb_ctrl_writew(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
274 { |
|
275 g364fb_ctrl_writeb(opaque, addr, val & 0xff); |
|
276 g364fb_ctrl_writeb(opaque, addr + 1, (val >> 8) & 0xff); |
|
277 } |
|
278 |
|
279 static void g364fb_ctrl_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
280 { |
|
281 g364fb_ctrl_writeb(opaque, addr, val & 0xff); |
|
282 g364fb_ctrl_writeb(opaque, addr + 1, (val >> 8) & 0xff); |
|
283 g364fb_ctrl_writeb(opaque, addr + 2, (val >> 16) & 0xff); |
|
284 g364fb_ctrl_writeb(opaque, addr + 3, (val >> 24) & 0xff); |
|
285 } |
|
286 |
|
287 static CPUReadMemoryFunc *g364fb_ctrl_read[3] = { |
|
288 g364fb_ctrl_readb, |
|
289 g364fb_ctrl_readw, |
|
290 g364fb_ctrl_readl, |
|
291 }; |
|
292 |
|
293 static CPUWriteMemoryFunc *g364fb_ctrl_write[3] = { |
|
294 g364fb_ctrl_writeb, |
|
295 g364fb_ctrl_writew, |
|
296 g364fb_ctrl_writel, |
|
297 }; |
|
298 |
|
299 /* called for accesses to video ram */ |
|
300 static uint32_t g364fb_mem_readb(void *opaque, target_phys_addr_t addr) |
|
301 { |
|
302 G364State *s = opaque; |
|
303 |
|
304 return s->vram_buffer[addr]; |
|
305 } |
|
306 |
|
307 static uint32_t g364fb_mem_readw(void *opaque, target_phys_addr_t addr) |
|
308 { |
|
309 uint32_t v; |
|
310 v = g364fb_mem_readb(opaque, addr); |
|
311 v |= g364fb_mem_readb(opaque, addr + 1) << 8; |
|
312 return v; |
|
313 } |
|
314 |
|
315 static uint32_t g364fb_mem_readl(void *opaque, target_phys_addr_t addr) |
|
316 { |
|
317 uint32_t v; |
|
318 v = g364fb_mem_readb(opaque, addr); |
|
319 v |= g364fb_mem_readb(opaque, addr + 1) << 8; |
|
320 v |= g364fb_mem_readb(opaque, addr + 2) << 16; |
|
321 v |= g364fb_mem_readb(opaque, addr + 3) << 24; |
|
322 return v; |
|
323 } |
|
324 |
|
325 static void g364fb_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
326 { |
|
327 G364State *s = opaque; |
|
328 |
|
329 s->vram_buffer[addr] = val; |
|
330 } |
|
331 |
|
332 static void g364fb_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
333 { |
|
334 g364fb_mem_writeb(opaque, addr, val & 0xff); |
|
335 g364fb_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); |
|
336 } |
|
337 |
|
338 static void g364fb_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
339 { |
|
340 g364fb_mem_writeb(opaque, addr, val & 0xff); |
|
341 g364fb_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); |
|
342 g364fb_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff); |
|
343 g364fb_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff); |
|
344 } |
|
345 |
|
346 static CPUReadMemoryFunc *g364fb_mem_read[3] = { |
|
347 g364fb_mem_readb, |
|
348 g364fb_mem_readw, |
|
349 g364fb_mem_readl, |
|
350 }; |
|
351 |
|
352 static CPUWriteMemoryFunc *g364fb_mem_write[3] = { |
|
353 g364fb_mem_writeb, |
|
354 g364fb_mem_writew, |
|
355 g364fb_mem_writel, |
|
356 }; |
|
357 |
|
358 int g364fb_mm_init(DisplayState *ds, |
|
359 int vram_size, int it_shift, |
|
360 target_phys_addr_t vram_base, target_phys_addr_t ctrl_base) |
|
361 { |
|
362 G364State *s; |
|
363 int io_vram, io_ctrl; |
|
364 |
|
365 s = qemu_mallocz(sizeof(G364State)); |
|
366 if (!s) |
|
367 return -1; |
|
368 |
|
369 s->vram_size = vram_size; |
|
370 s->vram_buffer = qemu_mallocz(s->vram_size); |
|
371 |
|
372 qemu_register_reset(g364fb_reset, s); |
|
373 g364fb_reset(s); |
|
374 |
|
375 s->ds = ds; |
|
376 |
|
377 s->console = graphic_console_init(ds, g364fb_update_display, |
|
378 g364fb_invalidate_display, |
|
379 g364fb_screen_dump, NULL, s); |
|
380 |
|
381 io_vram = cpu_register_io_memory(0, g364fb_mem_read, g364fb_mem_write, s); |
|
382 cpu_register_physical_memory(vram_base, vram_size, io_vram); |
|
383 |
|
384 io_ctrl = cpu_register_io_memory(0, g364fb_ctrl_read, g364fb_ctrl_write, s); |
|
385 cpu_register_physical_memory(ctrl_base, 0x10000, io_ctrl); |
|
386 |
|
387 return 0; |
|
388 } |