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

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

unix.superglobalmegacorp.com

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