MIPS: Upgrade G364 emulation
PATCH 1/1 MIPS: Upgrade G364 emulation
Hi,
Attached patch greatly increases correctness of the G364 graphic card emulation.
Documentation I was able to find gives corrects offsets for registers.
Patch also adds load/save capability and displays an error message each time an invalid operation or an unimplemented feature is performed.
Please apply
Hervé
g364fb.c +282 -173
@@ -1,7 +1,7 @@/* * QEMU G364 framebuffer Emulator. * -* Copyright (c) 2007-2008 Hervé Poussineau +* Copyright (c) 2007-2008 Herve Poussineau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as
@@ -15,8 +15,8 @@* * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, -* MA 02111-1307 USA +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +* MA 02110-1301 USA */ #include "hw.h"
@@ -24,83 +24,93 @@#include "pixel_ops.h" //#define DEBUG_G364 - + +#ifdef DEBUG_G364 +#define DPRINTF(fmt, args...) \ +do { printf("g364: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) do {} while (0) +#endif +#define BADF(fmt, args...) \ +do { fprintf(stderr, "g364 ERROR: " fmt , ##args);} while (0) +typedef struct G364State { +/* hardware */ target_phys_addr_t vram_base; -unsigned int vram_size; -uint8_t *vram_buffer; -uint32_t ctla; -uint8_t palette[256 ][3 ]; +int vram_size; +uint8_t *vram_buffer; +/* registers */ +uint8_t color_palette[256 ][3 ]; +uint8_t cursor_palette[3 ][3 ]; +uint16_t cursor[512 ]; +uint32_t cursor_position; +uint32_t ctla; +uint32_t top_of_screen; +uint32_t scr_width, scr_height;/* in pixels */ /* display refresh support */ DisplayState *ds; -QEMUConsole *console; -int graphic_mode; -uint32_t scr_width, scr_height;/* in pixels */ +QEMUConsole *console; +int invalidated; +int depth; }G364State ; + +#define REG_ID 0x000000 +#define REG_DISPLAY 0x080118 +#define REG_VDISPLAY 0x080150 +#define REG_CTLA 0x080300 +#define REG_TOP 0x080400 +#define REG_CURS_PAL 0x080508 +#define REG_CURS_POS 0x080638 +#define REG_CLR_PAL 0x080800 +#define REG_CURS_PAT 0x081000 +#define REG_RESET 0x180000 + +#define CTLA_FORCE_BLANK 0x00000400 +#define CTLA_NO_CURSOR 0x00800000/* * graphic modes -*/ -#define BPP 8 -#define PIXEL_WIDTH 8 -#include "g364fb_template.h" -#undef BPP -#undef PIXEL_WIDTH +*/ +#define DEPTH 8 +#include "g364fb_template.h" + +#define DEPTH 15 +#include "g364fb_template.h" + +#define DEPTH 16 +#include "g364fb_template.h" + +#define DEPTH 32 +#include "g364fb_template.h" -#define BPP 15 -#define PIXEL_WIDTH 16 -#include "g364fb_template.h" -#undef BPP -#undef PIXEL_WIDTH - -#define BPP 16 -#define PIXEL_WIDTH 16 -#include "g364fb_template.h" -#undef BPP -#undef PIXEL_WIDTH - -#define BPP 32 -#define PIXEL_WIDTH 32 -#include "g364fb_template.h" -#undef BPP -#undef PIXEL_WIDTH - -#define REG_DISPLAYX 0x0918 -#define REG_DISPLAYY 0x0940 - -#define CTLA_FORCE_BLANK 0x400 - -static void g364fb_draw_graphic (G364State *s,int full_update) -{ +static void g364fb_draw_graphic (G364State *s) +{switch (s->ds->depth) {case 8 : -g364fb_draw_graphic8 (s, full_update); +g364fb_draw_graphic_8 (s);break ;case 15 : -g364fb_draw_graphic15 (s, full_update); +g364fb_draw_graphic_15 (s);break ;case 16 : -g364fb_draw_graphic16 (s, full_update); +g364fb_draw_graphic_16 (s);break ;case 32 : -g364fb_draw_graphic32 (s, full_update); +g364fb_draw_graphic_32 (s);break ;default : -printf ("g364fb: unknown depth %d\n" , s->ds->depth); +BADF ("unknown depth %d\n" , s->ds->depth);return ; - } + }dpy_update (s->ds,0 ,0 , s->scr_width, s->scr_height); } -static void g364fb_draw_blank (G364State *s,int full_update) +static void g364fb_draw_blank (G364State *s) {int i, w;uint8_t *d; -if (!full_update) -return ; - w = s->scr_width * ((s->ds->depth +7 ) >>3 ); d = s->ds->data;for (i =0 ; i < s->scr_height; i++) {
@@ -111,56 +121,46 @@dpy_update (s->ds,0 ,0 , s->scr_width, s->scr_height); } -#define GMODE_GRAPH 0 -#define GMODE_BLANK 1 -static void g364fb_update_display (void *opaque) {G364State *s = opaque; -int full_update, graphic_mode;if (s->scr_width ==0 || s->scr_height ==0 )return ; -if (s->ctla &CTLA_FORCE_BLANK ) - graphic_mode =GMODE_BLANK ; -else - graphic_mode =GMODE_GRAPH ; - full_update =0 ; -if (graphic_mode != s->graphic_mode) { - s->graphic_mode = graphic_mode; - full_update =1 ; - }if (s->scr_width != s->ds->width || s->scr_height != s->ds->height) {qemu_console_resize (s->console, s->scr_width, s->scr_height); - full_update =1 ; - } -switch (graphic_mode) { -case GMODE_GRAPH : -g364fb_draw_graphic (s, full_update); -break ; -case GMODE_BLANK : -default : -g364fb_draw_blank (s, full_update); -break ; - } + }else if (!s->invalidated) +return ; + +if (s->ctla &CTLA_FORCE_BLANK ) { +g364fb_draw_blank (s); + }else { +g364fb_draw_graphic (s); + } + + s->invalidated =0 ; } -/* force a full display refresh */ -static void g364fb_invalidate_display (void *opaque) -{ -G364State *s = opaque; - s->graphic_mode =-1 ;/* force full update */ +static void inline g364fb_invalidate_display (void *opaque) +{ +G364State *s = opaque; + s->invalidated =1 ; }static void g364fb_reset (void *opaque) {G364State *s = opaque; -memset (s->palette,0 ,sizeof (s->palette)); +memset (s->color_palette,0 ,sizeof (s->color_palette)); +memset (s->cursor_palette,0 ,sizeof (s->cursor_palette)); +memset (s->cursor,0 ,sizeof (s->cursor)); + s->cursor_position =0 ; + s->ctla =0 ; + s->top_of_screen =0 ; s->scr_width = s->scr_height =0 ; -memset (s->vram_buffer,0 , s->vram_size); - s->graphic_mode =-1 ;/* force full update */ +memset (s->vram_buffer,0 , s->vram_size); +g364fb_invalidate_display (opaque); }static void g364fb_screen_dump (void *opaque,const char *filename)
@@ -181,109 +181,165 @@for (y =0 ; y < s->scr_height; y++)for (x =0 ; x < s->scr_width; x++, data_buffer++) { index = *data_buffer; -fputc (s->palette[index][0 ], f); -fputc (s->palette[index][1 ], f); -fputc (s->palette[index][2 ], f); +fputc (s->color_palette[index][0 ], f); +fputc (s->color_palette[index][1 ], f); +fputc (s->color_palette[index][2 ], f); }fclose (f); } - +/* called for accesses to io ports */ -static uint32_t g364fb_ctrl_readb (void *opaque,target_phys_addr_t addr) -{ +static uint32_t g364fb_ctrl_readl (void *opaque,target_phys_addr_t addr) +{//G364State *s = opaque; -uint32_t val; - - addr &=0xffff ; - -switch (addr) { -default : -#ifdef DEBUG_G364 -printf ("g364fb/ctrl: invalid read at [" TARGET_FMT_lx"]\n" , addr); -#endif - val =0 ; -break ; +uint32_t val; + + addr &=0xffffff ; + +switch (addr) { +case REG_ID : + val =1 ;/* must not be 0 */ +break ; +default : + { +BADF ("invalid read at [" TARGET_FMT_lx"]\n" , addr); + val =0 ; +break ; + } } -#ifdef DEBUG_G364 -printf ("g364fb/ctrl: read 0x%02x at [" TARGET_FMT_lx"]\n" , val, addr); -#endif +DPRINTF ("read 0x%08x at [" TARGET_FMT_lx"]\n" , val, addr);return val; }static uint32_t g364fb_ctrl_readw (void *opaque,target_phys_addr_t addr) { -uint32_t v; - v =g364fb_ctrl_readb (opaque, addr); - v |=g364fb_ctrl_readb (opaque, addr +1 ) <<8 ; -return v; +uint32_t v =g364fb_ctrl_readl (opaque, addr & ~0x3 ); +if (addr &0x2 ) +return v >>16 ; +else +return v &0xffff ; } -static uint32_t g364fb_ctrl_readl (void *opaque,target_phys_addr_t addr) +static uint32_t g364fb_ctrl_readb (void *opaque,target_phys_addr_t addr) { -uint32_t v; - v =g364fb_ctrl_readb (opaque, addr); - v |=g364fb_ctrl_readb (opaque, addr +1 ) <<8 ; - v |=g364fb_ctrl_readb (opaque, addr +2 ) <<16 ; - v |=g364fb_ctrl_readb (opaque, addr +3 ) <<24 ; -return v; +uint32_t v =g364fb_ctrl_readl (opaque, addr & ~0x3 ); +return (v >> (8 * (addr &0x3 ))) &0xff ; } + +static void g364fb_update_depth (G364State *s) +{ +const static int depths[8 ] = {1 ,2 ,4 ,8 ,15 ,16 ,0 }; + s->depth = depths[(s->ctla &0x00700000 ) >>20 ]; +} -static void g364fb_ctrl_writeb (void *opaque,target_phys_addr_t addr,uint32_t val) -{ -G364State *s = opaque; - - addr &=0xffff ; - -#ifdef DEBUG_G364 -printf ("g364fb/ctrl: write 0x%02x at [" TARGET_FMT_lx"]\n" , val, addr); -#endif - -if (addr <0x0800 ) { -/* color palette */ -int idx = addr >>3 ; -int c = addr &7 ; -if (c <3 ) - s->palette[idx][c] = (uint8_t )val; - }else { -switch (addr) { -case REG_DISPLAYX : - s->scr_width = (s->scr_width &0xfffffc03 ) | (val <<2 ); -break ; -case REG_DISPLAYX +1 : - s->scr_width = (s->scr_width &0xfffc03ff ) | (val <<10 ); -break ; -case REG_DISPLAYY : - s->scr_height = (s->scr_height &0xffffff80 ) | (val >>1 ); -break ; -case REG_DISPLAYY +1 : - s->scr_height = (s->scr_height &0xffff801f ) | (val <<7 ); -break ; -default : -#ifdef DEBUG_G364 -printf ("g364fb/ctrl: invalid write of 0x%02x at [" TARGET_FMT_lx"]\n" , val, addr); -#endif -break ; - } +static void g364fb_ctrl_writel (void *opaque,target_phys_addr_t addr,uint32_t val) +{ +G364State *s = opaque; + + addr &=0xffffff ; + +DPRINTF ("write 0x%08x at [" TARGET_FMT_lx"]\n" , val, addr); + +if (addr >=REG_CLR_PAL && addr <REG_CLR_PAL +0x800 ) { +/* color palette */ +int idx = (addr -REG_CLR_PAL ) >>3 ; + s->color_palette[idx][0 ] = (val >>16 ) &0xff ; + s->color_palette[idx][1 ] = (val >>8 ) &0xff ; + s->color_palette[idx][2 ] = val &0xff ; +g364fb_invalidate_display (s); + }else if (addr >=REG_CURS_PAT && addr <REG_CURS_PAT +0x1000 ) { +/* cursor pattern */ +int idx = (addr -REG_CURS_PAT ) >>3 ; + s->cursor[idx] = val; +g364fb_invalidate_display (s); + }else if (addr >=REG_CURS_PAL && addr <REG_CURS_PAL +0x18 ) { +/* cursor palette */ +int idx = (addr -REG_CURS_PAL ) >>3 ; + s->cursor_palette[idx][0 ] = (val >>16 ) &0xff ; + s->cursor_palette[idx][1 ] = (val >>8 ) &0xff ; + s->cursor_palette[idx][2 ] = val &0xff ; +g364fb_invalidate_display (s); + }else { +switch (addr) { +case REG_ID :/* Card identifier; read-only */ +case 0x80108 :/* Line timing: half sync */ +case 0x80110 :/* Line timing: back porch */ +case 0x80120 :/* Line timing: short display */ +case 0x80128 :/* Frame timing: broad pulse */ +case 0x80130 :/* Frame timing: v sync */ +case 0x80138 :/* Frame timing: v preequalise */ +case 0x80140 :/* Frame timing: v postequalise */ +case 0x80148 :/* Frame timing: v blank */ +case 0x80158 :/* Line timing: line time */ +case 0x80160 :/* Frame store: line start */ +case 0x80168 :/* vram cycle: mem init */ +case 0x80170 :/* vram cycle: transfer delay */ +case 0x80200 :/* vram cycle: mask register */ +/* ignore */ +break ; +case REG_TOP : + s->top_of_screen = val; +g364fb_invalidate_display (s); +break ; +case REG_DISPLAY : + s->scr_width = val *4 ; +break ; +case REG_VDISPLAY : + s->scr_height = val /2 ; +break ; +case REG_CTLA : + s->ctla = val; +g364fb_update_depth (s); +g364fb_invalidate_display (s); +break ; +case REG_CURS_POS : + s->cursor_position = val; +g364fb_invalidate_display (s); +break ; +case REG_RESET : +g364fb_reset (s); +break ; +default : +BADF ("invalid write of 0x%08x at [" TARGET_FMT_lx"]\n" , val, addr); +break ; + } } - s->graphic_mode =-1 ;/* force full update */ } + +static void g364fb_ctrl_writew (void *opaque,target_phys_addr_t addr,uint32_t val) +{ +uint32_t old_val =g364fb_ctrl_readl (opaque, addr & ~0x3 ); + +if (addr &0x2 ) + val = (val <<16 ) | (old_val &0x0000ffff ); +else + val = val | (old_val &0xffff0000 ); +g364fb_ctrl_writel (opaque, addr & ~0x3 , val); +} + +static void g364fb_ctrl_writeb (void *opaque,target_phys_addr_t addr,uint32_t val) +{ +uint32_t old_val =g364fb_ctrl_readl (opaque, addr & ~0x3 ); + +switch (addr &3 ) { +case 0 : + val = val | (old_val &0xffffff00 ); +break ; +case 1 : + val = (val <<8 ) | (old_val &0xffff00ff ); +break ; +case 2 : + val = (val <<16 ) | (old_val &0xff00ffff ); +break ; +case 3 : + val = (val <<24 ) | (old_val &0x00ffffff ); +break ; + } +g364fb_ctrl_writel (opaque, addr & ~0x3 , val); +} -static void g364fb_ctrl_writew (void *opaque,target_phys_addr_t addr,uint32_t val) -{ -g364fb_ctrl_writeb (opaque, addr, val &0xff ); -g364fb_ctrl_writeb (opaque, addr +1 , (val >>8 ) &0xff ); -} - -static void g364fb_ctrl_writel (void *opaque,target_phys_addr_t addr,uint32_t val) -{ -g364fb_ctrl_writeb (opaque, addr, val &0xff ); -g364fb_ctrl_writeb (opaque, addr +1 , (val >>8 ) &0xff ); -g364fb_ctrl_writeb (opaque, addr +2 , (val >>16 ) &0xff ); -g364fb_ctrl_writeb (opaque, addr +3 , (val >>24 ) &0xff ); -} -static CPUReadMemoryFunc *g364fb_ctrl_read[3 ] = { g364fb_ctrl_readb, g364fb_ctrl_readw,
@@ -328,7 +384,8 @@G364State *s = opaque;target_phys_addr_t relative_addr = addr - s->vram_base; - s->vram_buffer[relative_addr] = val; + s->vram_buffer[relative_addr] = val; +g364fb_invalidate_display (s); }static void g364fb_mem_writew (void *opaque,target_phys_addr_t addr,uint32_t val)
@@ -356,14 +413,65 @@ g364fb_mem_writew, g364fb_mem_writel, }; + +static int g364fb_load (QEMUFile *f,void *opaque,int version_id) +{ +G364State *s = opaque; +unsigned int i, vram_size; + +if (version_id !=1 ) +return -EINVAL ; + + s->vram_base =qemu_get_betl (f); + vram_size =qemu_get_be32 (f); +if (vram_size != s->vram_size) +return -EINVAL ; +qemu_get_buffer (f, s->vram_buffer, s->vram_size); +for (i =0 ; i <256 ; i++) +qemu_get_buffer (f, s->color_palette[i],3 ); +for (i =0 ; i <3 ; i++) +qemu_get_buffer (f, s->cursor_palette[i],3 ); +qemu_get_buffer (f, (uint8_t *)s->cursor,sizeof (s->cursor)); + s->cursor_position =qemu_get_be32 (f); + s->ctla =qemu_get_be32 (f); + s->top_of_screen =qemu_get_be32 (f); + s->scr_width =qemu_get_be32 (f); + s->scr_height =qemu_get_be32 (f); + +/* force refresh */ +g364fb_update_depth (s); +g364fb_invalidate_display (s); + +return 0 ; +} + +static void g364fb_save (QEMUFile *f,void *opaque) +{ +G364State *s = opaque; +int i; + +qemu_put_betl (f, s->vram_base); +qemu_put_be32 (f, s->vram_size); +qemu_put_buffer (f, s->vram_buffer, s->vram_size); +for (i =0 ; i <256 ; i++) +qemu_put_buffer (f, s->color_palette[i],3 ); +for (i =0 ; i <3 ; i++) +qemu_put_buffer (f, s->cursor_palette[i],3 ); +qemu_put_buffer (f, (uint8_t *)s->cursor,sizeof (s->cursor)); +qemu_put_be32 (f, s->cursor_position); +qemu_put_be32 (f, s->ctla); +qemu_put_be32 (f, s->top_of_screen); +qemu_put_be32 (f, s->scr_width); +qemu_put_be32 (f, s->scr_height); +}int g364fb_mm_init (DisplayState *ds,int vram_size,int it_shift,target_phys_addr_t vram_base,target_phys_addr_t ctrl_base) {G364State *s; -int io_vram, io_ctrl; - +int io_vram, io_ctrl; + s =qemu_mallocz (sizeof (G364State));if (!s)return -1 ;
@@ -371,7 +479,8 @@ s->vram_size = vram_size; s->vram_buffer =qemu_mallocz (s->vram_size); -qemu_register_reset (g364fb_reset, s); +qemu_register_reset (g364fb_reset, s); +register_savevm ("g364fb" ,0 ,1 , g364fb_save, g364fb_load, s);g364fb_reset (s); s->ds = ds;
@@ -383,9 +492,9 @@ io_vram =cpu_register_io_memory (0 , g364fb_mem_read, g364fb_mem_write, s);cpu_register_physical_memory (s->vram_base, vram_size, io_vram); + + io_ctrl =cpu_register_io_memory (0 , g364fb_ctrl_read, g364fb_ctrl_write, s); +cpu_register_physical_memory (ctrl_base,0x200000 , io_ctrl); - io_ctrl =cpu_register_io_memory (0 , g364fb_ctrl_read, g364fb_ctrl_write, s); -cpu_register_physical_memory (ctrl_base,0x10000 , io_ctrl); -return 0 ; }
g364fb_template.h +92 -11
128 lines not on this page · raw message