Annotation of qemu/hw/tcx.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  * QEMU TCX Frame buffer
                      3:  * 
                      4:  * Copyright (c) 2003-2005 Fabrice Bellard
                      5:  * 
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
                     24: #include "vl.h"
                     25: 
                     26: #define MAXX 1024
                     27: #define MAXY 768
                     28: #define TCX_DAC_NREGS 16
                     29: 
                     30: typedef struct TCXState {
                     31:     uint32_t addr;
                     32:     DisplayState *ds;
                     33:     uint8_t *vram;
                     34:     unsigned long vram_offset;
                     35:     uint16_t width, height;
                     36:     uint8_t r[256], g[256], b[256];
                     37:     uint8_t dac_index, dac_state;
                     38: } TCXState;
                     39: 
1.1.1.2 ! root       40: static void tcx_screen_dump(void *opaque, const char *filename);
        !            41: 
1.1       root       42: static void tcx_draw_line32(TCXState *s1, uint8_t *d, 
                     43:                            const uint8_t *s, int width)
                     44: {
                     45:     int x;
                     46:     uint8_t val;
                     47: 
                     48:     for(x = 0; x < width; x++) {
                     49:        val = *s++;
                     50:        *d++ = s1->b[val];
                     51:        *d++ = s1->g[val];
                     52:        *d++ = s1->r[val];
                     53:        d++;
                     54:     }
                     55: }
                     56: 
                     57: static void tcx_draw_line24(TCXState *s1, uint8_t *d, 
                     58:                            const uint8_t *s, int width)
                     59: {
                     60:     int x;
                     61:     uint8_t val;
                     62: 
                     63:     for(x = 0; x < width; x++) {
                     64:        val = *s++;
                     65:        *d++ = s1->b[val];
                     66:        *d++ = s1->g[val];
                     67:        *d++ = s1->r[val];
                     68:     }
                     69: }
                     70: 
                     71: static void tcx_draw_line8(TCXState *s1, uint8_t *d, 
                     72:                           const uint8_t *s, int width)
                     73: {
                     74:     int x;
                     75:     uint8_t val;
                     76: 
                     77:     for(x = 0; x < width; x++) {
                     78:        val = *s++;
                     79:        /* XXX translate between palettes? */
                     80:        *d++ = val;
                     81:     }
                     82: }
                     83: 
                     84: /* Fixed line length 1024 allows us to do nice tricks not possible on
                     85:    VGA... */
1.1.1.2 ! root       86: static void tcx_update_display(void *opaque)
1.1       root       87: {
                     88:     TCXState *ts = opaque;
                     89:     uint32_t page;
                     90:     int y, page_min, page_max, y_start, dd, ds;
                     91:     uint8_t *d, *s;
                     92:     void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width);
                     93: 
                     94:     if (ts->ds->depth == 0)
                     95:        return;
                     96:     page = ts->vram_offset;
                     97:     y_start = -1;
                     98:     page_min = 0x7fffffff;
                     99:     page_max = -1;
                    100:     d = ts->ds->data;
                    101:     s = ts->vram;
                    102:     dd = ts->ds->linesize;
                    103:     ds = 1024;
                    104: 
                    105:     switch (ts->ds->depth) {
                    106:     case 32:
                    107:        f = tcx_draw_line32;
                    108:        break;
                    109:     case 24:
                    110:        f = tcx_draw_line24;
                    111:        break;
                    112:     default:
                    113:     case 8:
                    114:        f = tcx_draw_line8;
                    115:        break;
                    116:     case 0:
                    117:        return;
                    118:     }
                    119:     
                    120:     for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
                    121:        if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
                    122:            if (y_start < 0)
                    123:                 y_start = y;
                    124:             if (page < page_min)
                    125:                 page_min = page;
                    126:             if (page > page_max)
                    127:                 page_max = page;
                    128:            f(ts, d, s, ts->width);
                    129:            d += dd;
                    130:            s += ds;
                    131:            f(ts, d, s, ts->width);
                    132:            d += dd;
                    133:            s += ds;
                    134:            f(ts, d, s, ts->width);
                    135:            d += dd;
                    136:            s += ds;
                    137:            f(ts, d, s, ts->width);
                    138:            d += dd;
                    139:            s += ds;
                    140:        } else {
                    141:             if (y_start >= 0) {
                    142:                 /* flush to display */
                    143:                 dpy_update(ts->ds, 0, y_start, 
                    144:                            ts->width, y - y_start);
                    145:                 y_start = -1;
                    146:             }
                    147:            d += dd * 4;
                    148:            s += ds * 4;
                    149:        }
                    150:     }
                    151:     if (y_start >= 0) {
                    152:        /* flush to display */
                    153:        dpy_update(ts->ds, 0, y_start, 
                    154:                   ts->width, y - y_start);
                    155:     }
                    156:     /* reset modified pages */
                    157:     if (page_max != -1) {
                    158:         cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
                    159:                                         VGA_DIRTY_FLAG);
                    160:     }
                    161: }
                    162: 
1.1.1.2 ! root      163: static void tcx_invalidate_display(void *opaque)
1.1       root      164: {
                    165:     TCXState *s = opaque;
                    166:     int i;
                    167: 
                    168:     for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) {
                    169:        cpu_physical_memory_set_dirty(s->vram_offset + i);
                    170:     }
                    171: }
                    172: 
                    173: static void tcx_save(QEMUFile *f, void *opaque)
                    174: {
                    175:     TCXState *s = opaque;
                    176:     
                    177:     qemu_put_be32s(f, (uint32_t *)&s->addr);
                    178:     qemu_put_be32s(f, (uint32_t *)&s->vram);
                    179:     qemu_put_be16s(f, (uint16_t *)&s->height);
                    180:     qemu_put_be16s(f, (uint16_t *)&s->width);
                    181:     qemu_put_buffer(f, s->r, 256);
                    182:     qemu_put_buffer(f, s->g, 256);
                    183:     qemu_put_buffer(f, s->b, 256);
                    184:     qemu_put_8s(f, &s->dac_index);
                    185:     qemu_put_8s(f, &s->dac_state);
                    186: }
                    187: 
                    188: static int tcx_load(QEMUFile *f, void *opaque, int version_id)
                    189: {
                    190:     TCXState *s = opaque;
                    191:     
                    192:     if (version_id != 1)
                    193:         return -EINVAL;
                    194: 
                    195:     qemu_get_be32s(f, (uint32_t *)&s->addr);
                    196:     qemu_get_be32s(f, (uint32_t *)&s->vram);
                    197:     qemu_get_be16s(f, (uint16_t *)&s->height);
                    198:     qemu_get_be16s(f, (uint16_t *)&s->width);
                    199:     qemu_get_buffer(f, s->r, 256);
                    200:     qemu_get_buffer(f, s->g, 256);
                    201:     qemu_get_buffer(f, s->b, 256);
                    202:     qemu_get_8s(f, &s->dac_index);
                    203:     qemu_get_8s(f, &s->dac_state);
                    204:     return 0;
                    205: }
                    206: 
                    207: static void tcx_reset(void *opaque)
                    208: {
                    209:     TCXState *s = opaque;
                    210: 
                    211:     /* Initialize palette */
                    212:     memset(s->r, 0, 256);
                    213:     memset(s->g, 0, 256);
                    214:     memset(s->b, 0, 256);
                    215:     s->r[255] = s->g[255] = s->b[255] = 255;
                    216:     memset(s->vram, 0, MAXX*MAXY);
                    217:     cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY,
                    218:                                     VGA_DIRTY_FLAG);
                    219:     s->dac_index = 0;
                    220:     s->dac_state = 0;
                    221: }
                    222: 
                    223: static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
                    224: {
                    225:     return 0;
                    226: }
                    227: 
                    228: static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
                    229: {
                    230:     TCXState *s = opaque;
                    231:     uint32_t saddr;
                    232: 
                    233:     saddr = (addr & (TCX_DAC_NREGS - 1)) >> 2;
                    234:     switch (saddr) {
                    235:     case 0:
                    236:        s->dac_index = val >> 24;
                    237:        s->dac_state = 0;
                    238:        break;
                    239:     case 1:
                    240:        switch (s->dac_state) {
                    241:        case 0:
                    242:            s->r[s->dac_index] = val >> 24;
                    243:            s->dac_state++;
                    244:            break;
                    245:        case 1:
                    246:            s->g[s->dac_index] = val >> 24;
                    247:            s->dac_state++;
                    248:            break;
                    249:        case 2:
                    250:            s->b[s->dac_index] = val >> 24;
                    251:        default:
                    252:            s->dac_state = 0;
                    253:            break;
                    254:        }
                    255:        break;
                    256:     default:
                    257:        break;
                    258:     }
                    259:     return;
                    260: }
                    261: 
                    262: static CPUReadMemoryFunc *tcx_dac_read[3] = {
                    263:     tcx_dac_readl,
                    264:     tcx_dac_readl,
                    265:     tcx_dac_readl,
                    266: };
                    267: 
                    268: static CPUWriteMemoryFunc *tcx_dac_write[3] = {
                    269:     tcx_dac_writel,
                    270:     tcx_dac_writel,
                    271:     tcx_dac_writel,
                    272: };
                    273: 
1.1.1.2 ! root      274: void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
        !           275:              unsigned long vram_offset, int vram_size, int width, int height)
1.1       root      276: {
                    277:     TCXState *s;
                    278:     int io_memory;
                    279: 
                    280:     s = qemu_mallocz(sizeof(TCXState));
                    281:     if (!s)
1.1.1.2 ! root      282:         return;
1.1       root      283:     s->ds = ds;
                    284:     s->addr = addr;
                    285:     s->vram = vram_base;
                    286:     s->vram_offset = vram_offset;
                    287:     s->width = width;
                    288:     s->height = height;
                    289: 
                    290:     cpu_register_physical_memory(addr + 0x800000, vram_size, vram_offset);
                    291:     io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s);
                    292:     cpu_register_physical_memory(addr + 0x200000, TCX_DAC_NREGS, io_memory);
                    293: 
1.1.1.2 ! root      294:     graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display,
        !           295:                          tcx_screen_dump, s);
1.1       root      296:     register_savevm("tcx", addr, 1, tcx_save, tcx_load, s);
                    297:     qemu_register_reset(tcx_reset, s);
                    298:     tcx_reset(s);
                    299:     dpy_resize(s->ds, width, height);
                    300: }
                    301: 
1.1.1.2 ! root      302: static void tcx_screen_dump(void *opaque, const char *filename)
1.1       root      303: {
                    304:     TCXState *s = opaque;
                    305:     FILE *f;
                    306:     uint8_t *d, *d1, v;
                    307:     int y, x;
                    308: 
                    309:     f = fopen(filename, "wb");
                    310:     if (!f)
                    311:         return;
                    312:     fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
                    313:     d1 = s->vram;
                    314:     for(y = 0; y < s->height; y++) {
                    315:         d = d1;
                    316:         for(x = 0; x < s->width; x++) {
                    317:             v = *d;
                    318:             fputc(s->r[v], f);
                    319:             fputc(s->g[v], f);
                    320:             fputc(s->b[v], f);
                    321:             d++;
                    322:         }
                    323:         d1 += MAXX;
                    324:     }
                    325:     fclose(f);
                    326:     return;
                    327: }
                    328: 
                    329: 
                    330: 

unix.superglobalmegacorp.com