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

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: 
                     40: static void tcx_draw_line32(TCXState *s1, uint8_t *d, 
                     41:                            const uint8_t *s, int width)
                     42: {
                     43:     int x;
                     44:     uint8_t val;
                     45: 
                     46:     for(x = 0; x < width; x++) {
                     47:        val = *s++;
                     48:        *d++ = s1->b[val];
                     49:        *d++ = s1->g[val];
                     50:        *d++ = s1->r[val];
                     51:        d++;
                     52:     }
                     53: }
                     54: 
                     55: static void tcx_draw_line24(TCXState *s1, uint8_t *d, 
                     56:                            const uint8_t *s, int width)
                     57: {
                     58:     int x;
                     59:     uint8_t val;
                     60: 
                     61:     for(x = 0; x < width; x++) {
                     62:        val = *s++;
                     63:        *d++ = s1->b[val];
                     64:        *d++ = s1->g[val];
                     65:        *d++ = s1->r[val];
                     66:     }
                     67: }
                     68: 
                     69: static void tcx_draw_line8(TCXState *s1, uint8_t *d, 
                     70:                           const uint8_t *s, int width)
                     71: {
                     72:     int x;
                     73:     uint8_t val;
                     74: 
                     75:     for(x = 0; x < width; x++) {
                     76:        val = *s++;
                     77:        /* XXX translate between palettes? */
                     78:        *d++ = val;
                     79:     }
                     80: }
                     81: 
                     82: /* Fixed line length 1024 allows us to do nice tricks not possible on
                     83:    VGA... */
                     84: void tcx_update_display(void *opaque)
                     85: {
                     86:     TCXState *ts = opaque;
                     87:     uint32_t page;
                     88:     int y, page_min, page_max, y_start, dd, ds;
                     89:     uint8_t *d, *s;
                     90:     void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width);
                     91: 
                     92:     if (ts->ds->depth == 0)
                     93:        return;
                     94:     page = ts->vram_offset;
                     95:     y_start = -1;
                     96:     page_min = 0x7fffffff;
                     97:     page_max = -1;
                     98:     d = ts->ds->data;
                     99:     s = ts->vram;
                    100:     dd = ts->ds->linesize;
                    101:     ds = 1024;
                    102: 
                    103:     switch (ts->ds->depth) {
                    104:     case 32:
                    105:        f = tcx_draw_line32;
                    106:        break;
                    107:     case 24:
                    108:        f = tcx_draw_line24;
                    109:        break;
                    110:     default:
                    111:     case 8:
                    112:        f = tcx_draw_line8;
                    113:        break;
                    114:     case 0:
                    115:        return;
                    116:     }
                    117:     
                    118:     for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
                    119:        if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
                    120:            if (y_start < 0)
                    121:                 y_start = y;
                    122:             if (page < page_min)
                    123:                 page_min = page;
                    124:             if (page > page_max)
                    125:                 page_max = page;
                    126:            f(ts, d, s, ts->width);
                    127:            d += dd;
                    128:            s += ds;
                    129:            f(ts, d, s, ts->width);
                    130:            d += dd;
                    131:            s += ds;
                    132:            f(ts, d, s, ts->width);
                    133:            d += dd;
                    134:            s += ds;
                    135:            f(ts, d, s, ts->width);
                    136:            d += dd;
                    137:            s += ds;
                    138:        } else {
                    139:             if (y_start >= 0) {
                    140:                 /* flush to display */
                    141:                 dpy_update(ts->ds, 0, y_start, 
                    142:                            ts->width, y - y_start);
                    143:                 y_start = -1;
                    144:             }
                    145:            d += dd * 4;
                    146:            s += ds * 4;
                    147:        }
                    148:     }
                    149:     if (y_start >= 0) {
                    150:        /* flush to display */
                    151:        dpy_update(ts->ds, 0, y_start, 
                    152:                   ts->width, y - y_start);
                    153:     }
                    154:     /* reset modified pages */
                    155:     if (page_max != -1) {
                    156:         cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
                    157:                                         VGA_DIRTY_FLAG);
                    158:     }
                    159: }
                    160: 
                    161: void tcx_invalidate_display(void *opaque)
                    162: {
                    163:     TCXState *s = opaque;
                    164:     int i;
                    165: 
                    166:     for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) {
                    167:        cpu_physical_memory_set_dirty(s->vram_offset + i);
                    168:     }
                    169: }
                    170: 
                    171: static void tcx_save(QEMUFile *f, void *opaque)
                    172: {
                    173:     TCXState *s = opaque;
                    174:     
                    175:     qemu_put_be32s(f, (uint32_t *)&s->addr);
                    176:     qemu_put_be32s(f, (uint32_t *)&s->vram);
                    177:     qemu_put_be16s(f, (uint16_t *)&s->height);
                    178:     qemu_put_be16s(f, (uint16_t *)&s->width);
                    179:     qemu_put_buffer(f, s->r, 256);
                    180:     qemu_put_buffer(f, s->g, 256);
                    181:     qemu_put_buffer(f, s->b, 256);
                    182:     qemu_put_8s(f, &s->dac_index);
                    183:     qemu_put_8s(f, &s->dac_state);
                    184: }
                    185: 
                    186: static int tcx_load(QEMUFile *f, void *opaque, int version_id)
                    187: {
                    188:     TCXState *s = opaque;
                    189:     
                    190:     if (version_id != 1)
                    191:         return -EINVAL;
                    192: 
                    193:     qemu_get_be32s(f, (uint32_t *)&s->addr);
                    194:     qemu_get_be32s(f, (uint32_t *)&s->vram);
                    195:     qemu_get_be16s(f, (uint16_t *)&s->height);
                    196:     qemu_get_be16s(f, (uint16_t *)&s->width);
                    197:     qemu_get_buffer(f, s->r, 256);
                    198:     qemu_get_buffer(f, s->g, 256);
                    199:     qemu_get_buffer(f, s->b, 256);
                    200:     qemu_get_8s(f, &s->dac_index);
                    201:     qemu_get_8s(f, &s->dac_state);
                    202:     return 0;
                    203: }
                    204: 
                    205: static void tcx_reset(void *opaque)
                    206: {
                    207:     TCXState *s = opaque;
                    208: 
                    209:     /* Initialize palette */
                    210:     memset(s->r, 0, 256);
                    211:     memset(s->g, 0, 256);
                    212:     memset(s->b, 0, 256);
                    213:     s->r[255] = s->g[255] = s->b[255] = 255;
                    214:     memset(s->vram, 0, MAXX*MAXY);
                    215:     cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY,
                    216:                                     VGA_DIRTY_FLAG);
                    217:     s->dac_index = 0;
                    218:     s->dac_state = 0;
                    219: }
                    220: 
                    221: static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
                    222: {
                    223:     return 0;
                    224: }
                    225: 
                    226: static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
                    227: {
                    228:     TCXState *s = opaque;
                    229:     uint32_t saddr;
                    230: 
                    231:     saddr = (addr & (TCX_DAC_NREGS - 1)) >> 2;
                    232:     switch (saddr) {
                    233:     case 0:
                    234:        s->dac_index = val >> 24;
                    235:        s->dac_state = 0;
                    236:        break;
                    237:     case 1:
                    238:        switch (s->dac_state) {
                    239:        case 0:
                    240:            s->r[s->dac_index] = val >> 24;
                    241:            s->dac_state++;
                    242:            break;
                    243:        case 1:
                    244:            s->g[s->dac_index] = val >> 24;
                    245:            s->dac_state++;
                    246:            break;
                    247:        case 2:
                    248:            s->b[s->dac_index] = val >> 24;
                    249:        default:
                    250:            s->dac_state = 0;
                    251:            break;
                    252:        }
                    253:        break;
                    254:     default:
                    255:        break;
                    256:     }
                    257:     return;
                    258: }
                    259: 
                    260: static CPUReadMemoryFunc *tcx_dac_read[3] = {
                    261:     tcx_dac_readl,
                    262:     tcx_dac_readl,
                    263:     tcx_dac_readl,
                    264: };
                    265: 
                    266: static CPUWriteMemoryFunc *tcx_dac_write[3] = {
                    267:     tcx_dac_writel,
                    268:     tcx_dac_writel,
                    269:     tcx_dac_writel,
                    270: };
                    271: 
                    272: void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
                    273:               unsigned long vram_offset, int vram_size, int width, int height)
                    274: {
                    275:     TCXState *s;
                    276:     int io_memory;
                    277: 
                    278:     s = qemu_mallocz(sizeof(TCXState));
                    279:     if (!s)
                    280:         return NULL;
                    281:     s->ds = ds;
                    282:     s->addr = addr;
                    283:     s->vram = vram_base;
                    284:     s->vram_offset = vram_offset;
                    285:     s->width = width;
                    286:     s->height = height;
                    287: 
                    288:     cpu_register_physical_memory(addr + 0x800000, vram_size, vram_offset);
                    289:     io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s);
                    290:     cpu_register_physical_memory(addr + 0x200000, TCX_DAC_NREGS, io_memory);
                    291: 
                    292:     register_savevm("tcx", addr, 1, tcx_save, tcx_load, s);
                    293:     qemu_register_reset(tcx_reset, s);
                    294:     tcx_reset(s);
                    295:     dpy_resize(s->ds, width, height);
                    296:     return s;
                    297: }
                    298: 
                    299: void tcx_screen_dump(void *opaque, const char *filename)
                    300: {
                    301:     TCXState *s = opaque;
                    302:     FILE *f;
                    303:     uint8_t *d, *d1, v;
                    304:     int y, x;
                    305: 
                    306:     f = fopen(filename, "wb");
                    307:     if (!f)
                    308:         return;
                    309:     fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
                    310:     d1 = s->vram;
                    311:     for(y = 0; y < s->height; y++) {
                    312:         d = d1;
                    313:         for(x = 0; x < s->width; x++) {
                    314:             v = *d;
                    315:             fputc(s->r[v], f);
                    316:             fputc(s->g[v], f);
                    317:             fputc(s->b[v], f);
                    318:             d++;
                    319:         }
                    320:         d1 += MAXX;
                    321:     }
                    322:     fclose(f);
                    323:     return;
                    324: }
                    325: 
                    326: 
                    327: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.