summaryrefslogblamecommitdiffstats
path: root/hw/tcx.c
blob: ccac0bffa6dd9c0fdafb51ebb6a536f133987c60 (plain) (tree)
























                                                                                

                 





                                                                    



                       





                
 
                         
                  
                     
                  

                                   

           

                                                        
 









                                

 




                                                        
 









                                                       
 






                                             
     

 


                                                                     
 









                                                                     
     
                                
      






























































                                                                               

 
                                         
 





                                                          
     
                                                   
      
     

 
                                               

                         





                                            

 
                                                              
 










                                            

 
                                   
 









                                                                                    


      

                                                                   




                                       
                    
               
                   







                                                               
                                
             

 
                                                        
 
                         
            
                       



                              


                                                 



                                  


                              

                
                   






              
/*
 * QEMU Sun4m System Emulator
 * 
 * Copyright (c) 2003-2004 Fabrice Bellard
 * 
 * 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.
 */
#include "vl.h"

#define MAXX 1024
#define MAXY 768
/*
 * Proll uses only small part of display, we need to switch to full
 * display when we get linux framebuffer console or X11 running. For
 * now it's just slower and awkward.
*/
#if 1
#define XSZ (8*80)
#define YSZ (24*11)
#define XOFF (MAXX-XSZ)
#define YOFF (MAXY-YSZ)
#else
#define XSZ MAXX
#define YSZ MAXY
#define XOFF 0
#define YOFF 0
#endif

typedef struct TCXState {
    uint32_t addr;
    DisplayState *ds;
    uint8_t *vram;
    unsigned long vram_offset;
    uint8_t r[256], g[256], b[256];
} TCXState;

static void tcx_draw_line32(TCXState *s1, uint8_t *d, 
			    const uint8_t *s, int width)
{
    int x;
    uint8_t val;

    for(x = 0; x < width; x++) {
	val = *s++;
	*d++ = s1->r[val];
	*d++ = s1->g[val];
	*d++ = s1->b[val];
	d++;
    }
}

static void tcx_draw_line24(TCXState *s1, uint8_t *d, 
			    const uint8_t *s, int width)
{
    int x;
    uint8_t val;

    for(x = 0; x < width; x++) {
	val = *s++;
	*d++ = s1->r[val];
	*d++ = s1->g[val];
	*d++ = s1->b[val];
    }
}

static void tcx_draw_line8(TCXState *s1, uint8_t *d, 
			   const uint8_t *s, int width)
{
    int x;
    uint8_t val;

    for(x = 0; x < width; x++) {
	val = *s++;
	/* XXX translate between palettes? */
	*d++ = val;
    }
}

/* Fixed line length 1024 allows us to do nice tricks not possible on
   VGA... */
void tcx_update_display(void *opaque)
{
    TCXState *ts = opaque;
    uint32_t page;
    int y, page_min, page_max, y_start, dd, ds;
    uint8_t *d, *s;
    void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width);

    if (ts->ds->depth == 0)
	return;
#ifdef LD_BYPASS_OK
    page = ts->vram_offset + YOFF*MAXX;
#else
    page = ts->addr + YOFF*MAXX;
#endif
    y_start = -1;
    page_min = 0x7fffffff;
    page_max = -1;
    d = ts->ds->data;
    s = ts->vram + YOFF*MAXX + XOFF;
    dd = ts->ds->linesize;
    ds = 1024;

    switch (ts->ds->depth) {
    case 32:
	f = tcx_draw_line32;
	break;
    case 24:
	f = tcx_draw_line24;
	break;
    default:
    case 8:
	f = tcx_draw_line8;
	break;
    case 0:
	return;
    }

    for(y = 0; y < YSZ; y += 4, page += TARGET_PAGE_SIZE) {
	if (cpu_physical_memory_is_dirty(page)) {
	    if (y_start < 0)
                y_start = y;
            if (page < page_min)
                page_min = page;
            if (page > page_max)
                page_max = page;
	    f(ts, d, s, XSZ);
	    d += dd;
	    s += ds;
	    f(ts, d, s, XSZ);
	    d += dd;
	    s += ds;
	    f(ts, d, s, XSZ);
	    d += dd;
	    s += ds;
	    f(ts, d, s, XSZ);
	    d += dd;
	    s += ds;
	} else {
            if (y_start >= 0) {
                /* flush to display */
                dpy_update(ts->ds, 0, y_start, 
                           XSZ, y - y_start);
                y_start = -1;
            }
	    d += dd * 4;
	    s += ds * 4;
	}
    }
    if (y_start >= 0) {
	/* flush to display */
	dpy_update(ts->ds, 0, y_start, 
		   XSZ, y - y_start);
    }
    /* reset modified pages */
    if (page_max != -1) {
        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
    }
}

void tcx_invalidate_display(void *opaque)
{
    TCXState *s = opaque;
    int i;

    for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) {
#ifdef LD_BYPASS_OK
	cpu_physical_memory_set_dirty(s->vram_offset + i);
#else
	cpu_physical_memory_set_dirty(s->addr + i);
#endif
    }
}

static void tcx_save(QEMUFile *f, void *opaque)
{
    TCXState *s = opaque;
    
    qemu_put_be32s(f, (uint32_t *)&s->addr);
    qemu_put_be32s(f, (uint32_t *)&s->vram);
    qemu_put_buffer(f, s->r, 256);
    qemu_put_buffer(f, s->g, 256);
    qemu_put_buffer(f, s->b, 256);
}

static int tcx_load(QEMUFile *f, void *opaque, int version_id)
{
    TCXState *s = opaque;
    
    if (version_id != 1)
        return -EINVAL;

    qemu_get_be32s(f, (uint32_t *)&s->addr);
    qemu_get_be32s(f, (uint32_t *)&s->vram);
    qemu_get_buffer(f, s->r, 256);
    qemu_get_buffer(f, s->g, 256);
    qemu_get_buffer(f, s->b, 256);
    return 0;
}

static void tcx_reset(void *opaque)
{
    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;
    memset(s->vram, 0, MAXX*MAXY);
#ifdef LD_BYPASS_OK
    cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY - 1);
#endif
}

void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
	      unsigned long vram_offset, int vram_size)
{
    TCXState *s;

    s = qemu_mallocz(sizeof(TCXState));
    if (!s)
        return NULL;
    s->ds = ds;
    s->addr = addr;
    s->vram = vram_base;
    s->vram_offset = vram_offset;

    cpu_register_physical_memory(addr, vram_size, vram_offset);

    register_savevm("tcx", addr, 1, tcx_save, tcx_load, s);
    qemu_register_reset(tcx_reset, s);
    tcx_reset(s);
    dpy_resize(s->ds, XSZ, YSZ);
    return s;
}

void tcx_screen_dump(void *opaque, const char *filename)
{
    TCXState *s = opaque;
    FILE *f;
    uint8_t *d, *d1, v;
    int y, x;

    f = fopen(filename, "wb");
    if (!f)
        return;
    fprintf(f, "P6\n%d %d\n%d\n", XSZ, YSZ, 255);
    d1 = s->vram + YOFF*MAXX + XOFF;
    for(y = 0; y < YSZ; y++) {
        d = d1;
        for(x = 0; x < XSZ; x++) {
            v = *d;
            fputc(s->r[v], f);
            fputc(s->g[v], f);
            fputc(s->b[v], f);
            d++;
        }
        d1 += MAXX;
    }
    fclose(f);
    return;
}