qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

cg3.c (10971B)


      1 /*
      2  * QEMU CG3 Frame buffer
      3  *
      4  * Copyright (c) 2012 Bob Breuer
      5  * Copyright (c) 2013 Mark Cave-Ayland
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a copy
      8  * of this software and associated documentation files (the "Software"), to deal
      9  * in the Software without restriction, including without limitation the rights
     10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11  * copies of the Software, and to permit persons to whom the Software is
     12  * furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included in
     15  * all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     23  * THE SOFTWARE.
     24  */
     25 
     26 #include "qemu/osdep.h"
     27 #include "qemu/datadir.h"
     28 #include "qapi/error.h"
     29 #include "qemu/error-report.h"
     30 #include "ui/console.h"
     31 #include "hw/sysbus.h"
     32 #include "migration/vmstate.h"
     33 #include "hw/irq.h"
     34 #include "hw/loader.h"
     35 #include "hw/qdev-properties.h"
     36 #include "qemu/log.h"
     37 #include "qemu/module.h"
     38 #include "trace.h"
     39 #include "qom/object.h"
     40 
     41 /* Change to 1 to enable debugging */
     42 #define DEBUG_CG3 0
     43 
     44 #define CG3_ROM_FILE  "QEMU,cgthree.bin"
     45 #define FCODE_MAX_ROM_SIZE 0x10000
     46 
     47 #define CG3_REG_SIZE            0x20
     48 
     49 #define CG3_REG_BT458_ADDR      0x0
     50 #define CG3_REG_BT458_COLMAP    0x4
     51 #define CG3_REG_FBC_CTRL        0x10
     52 #define CG3_REG_FBC_STATUS      0x11
     53 #define CG3_REG_FBC_CURSTART    0x12
     54 #define CG3_REG_FBC_CUREND      0x13
     55 #define CG3_REG_FBC_VCTRL       0x14
     56 
     57 /* Control register flags */
     58 #define CG3_CR_ENABLE_INTS      0x80
     59 
     60 /* Status register flags */
     61 #define CG3_SR_PENDING_INT      0x80
     62 #define CG3_SR_1152_900_76_B    0x60
     63 #define CG3_SR_ID_COLOR         0x01
     64 
     65 #define CG3_VRAM_SIZE 0x100000
     66 #define CG3_VRAM_OFFSET 0x800000
     67 
     68 #define TYPE_CG3 "cgthree"
     69 OBJECT_DECLARE_SIMPLE_TYPE(CG3State, CG3)
     70 
     71 struct CG3State {
     72     SysBusDevice parent_obj;
     73 
     74     QemuConsole *con;
     75     qemu_irq irq;
     76     hwaddr prom_addr;
     77     MemoryRegion vram_mem;
     78     MemoryRegion rom;
     79     MemoryRegion reg;
     80     uint32_t vram_size;
     81     int full_update;
     82     uint8_t regs[16];
     83     uint8_t r[256], g[256], b[256];
     84     uint16_t width, height, depth;
     85     uint8_t dac_index, dac_state;
     86 };
     87 
     88 static void cg3_update_display(void *opaque)
     89 {
     90     CG3State *s = opaque;
     91     DisplaySurface *surface = qemu_console_surface(s->con);
     92     const uint8_t *pix;
     93     uint32_t *data;
     94     uint32_t dval;
     95     int x, y, y_start;
     96     unsigned int width, height;
     97     ram_addr_t page;
     98     DirtyBitmapSnapshot *snap = NULL;
     99 
    100     if (surface_bits_per_pixel(surface) != 32) {
    101         return;
    102     }
    103     width = s->width;
    104     height = s->height;
    105 
    106     y_start = -1;
    107     pix = memory_region_get_ram_ptr(&s->vram_mem);
    108     data = (uint32_t *)surface_data(surface);
    109 
    110     if (!s->full_update) {
    111         snap = memory_region_snapshot_and_clear_dirty(&s->vram_mem, 0x0,
    112                                               memory_region_size(&s->vram_mem),
    113                                               DIRTY_MEMORY_VGA);
    114     }
    115 
    116     for (y = 0; y < height; y++) {
    117         int update;
    118 
    119         page = (ram_addr_t)y * width;
    120 
    121         if (s->full_update) {
    122             update = 1;
    123         } else {
    124             update = memory_region_snapshot_get_dirty(&s->vram_mem, snap, page,
    125                                                       width);
    126         }
    127 
    128         if (update) {
    129             if (y_start < 0) {
    130                 y_start = y;
    131             }
    132 
    133             for (x = 0; x < width; x++) {
    134                 dval = *pix++;
    135                 dval = (s->r[dval] << 16) | (s->g[dval] << 8) | s->b[dval];
    136                 *data++ = dval;
    137             }
    138         } else {
    139             if (y_start >= 0) {
    140                 dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
    141                 y_start = -1;
    142             }
    143             pix += width;
    144             data += width;
    145         }
    146     }
    147     s->full_update = 0;
    148     if (y_start >= 0) {
    149         dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
    150     }
    151     /* vsync interrupt? */
    152     if (s->regs[0] & CG3_CR_ENABLE_INTS) {
    153         s->regs[1] |= CG3_SR_PENDING_INT;
    154         qemu_irq_raise(s->irq);
    155     }
    156     g_free(snap);
    157 }
    158 
    159 static void cg3_invalidate_display(void *opaque)
    160 {
    161     CG3State *s = opaque;
    162 
    163     memory_region_set_dirty(&s->vram_mem, 0, CG3_VRAM_SIZE);
    164 }
    165 
    166 static uint64_t cg3_reg_read(void *opaque, hwaddr addr, unsigned size)
    167 {
    168     CG3State *s = opaque;
    169     int val;
    170 
    171     switch (addr) {
    172     case CG3_REG_BT458_ADDR:
    173     case CG3_REG_BT458_COLMAP:
    174         val = 0;
    175         break;
    176     case CG3_REG_FBC_CTRL:
    177         val = s->regs[0];
    178         break;
    179     case CG3_REG_FBC_STATUS:
    180         /* monitor ID 6, board type = 1 (color) */
    181         val = s->regs[1] | CG3_SR_1152_900_76_B | CG3_SR_ID_COLOR;
    182         break;
    183     case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE - 1:
    184         val = s->regs[addr - 0x10];
    185         break;
    186     default:
    187         qemu_log_mask(LOG_UNIMP,
    188                   "cg3: Unimplemented register read "
    189                   "reg 0x%" HWADDR_PRIx " size 0x%x\n",
    190                   addr, size);
    191         val = 0;
    192         break;
    193     }
    194     trace_cg3_read(addr, val, size);
    195 
    196     return val;
    197 }
    198 
    199 static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val,
    200                           unsigned size)
    201 {
    202     CG3State *s = opaque;
    203     uint8_t regval;
    204     int i;
    205 
    206     trace_cg3_write(addr, val, size);
    207     switch (addr) {
    208     case CG3_REG_BT458_ADDR:
    209         s->dac_index = val;
    210         s->dac_state = 0;
    211         break;
    212     case CG3_REG_BT458_COLMAP:
    213         /* This register can be written to as either a long word or a byte */
    214         if (size == 1) {
    215             val <<= 24;
    216         }
    217 
    218         for (i = 0; i < size; i++) {
    219             regval = val >> 24;
    220 
    221             switch (s->dac_state) {
    222             case 0:
    223                 s->r[s->dac_index] = regval;
    224                 s->dac_state++;
    225                 break;
    226             case 1:
    227                 s->g[s->dac_index] = regval;
    228                 s->dac_state++;
    229                 break;
    230             case 2:
    231                 s->b[s->dac_index] = regval;
    232                 /* Index autoincrement */
    233                 s->dac_index = (s->dac_index + 1) & 0xff;
    234                 /* fall through */
    235             default:
    236                 s->dac_state = 0;
    237                 break;
    238             }
    239             val <<= 8;
    240         }
    241         s->full_update = 1;
    242         break;
    243     case CG3_REG_FBC_CTRL:
    244         s->regs[0] = val;
    245         break;
    246     case CG3_REG_FBC_STATUS:
    247         if (s->regs[1] & CG3_SR_PENDING_INT) {
    248             /* clear interrupt */
    249             s->regs[1] &= ~CG3_SR_PENDING_INT;
    250             qemu_irq_lower(s->irq);
    251         }
    252         break;
    253     case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE - 1:
    254         s->regs[addr - 0x10] = val;
    255         break;
    256     default:
    257         qemu_log_mask(LOG_UNIMP,
    258                   "cg3: Unimplemented register write "
    259                   "reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n",
    260                   addr, size, val);
    261         break;
    262     }
    263 }
    264 
    265 static const MemoryRegionOps cg3_reg_ops = {
    266     .read = cg3_reg_read,
    267     .write = cg3_reg_write,
    268     .endianness = DEVICE_NATIVE_ENDIAN,
    269     .valid = {
    270         .min_access_size = 1,
    271         .max_access_size = 4,
    272     },
    273 };
    274 
    275 static const GraphicHwOps cg3_ops = {
    276     .invalidate = cg3_invalidate_display,
    277     .gfx_update = cg3_update_display,
    278 };
    279 
    280 static void cg3_initfn(Object *obj)
    281 {
    282     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    283     CG3State *s = CG3(obj);
    284 
    285     memory_region_init_rom_nomigrate(&s->rom, obj, "cg3.prom",
    286                                      FCODE_MAX_ROM_SIZE, &error_fatal);
    287     sysbus_init_mmio(sbd, &s->rom);
    288 
    289     memory_region_init_io(&s->reg, obj, &cg3_reg_ops, s, "cg3.reg",
    290                           CG3_REG_SIZE);
    291     sysbus_init_mmio(sbd, &s->reg);
    292 }
    293 
    294 static void cg3_realizefn(DeviceState *dev, Error **errp)
    295 {
    296     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    297     CG3State *s = CG3(dev);
    298     int ret;
    299     char *fcode_filename;
    300 
    301     /* FCode ROM */
    302     vmstate_register_ram_global(&s->rom);
    303     fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, CG3_ROM_FILE);
    304     if (fcode_filename) {
    305         ret = load_image_mr(fcode_filename, &s->rom);
    306         g_free(fcode_filename);
    307         if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) {
    308             warn_report("cg3: could not load prom '%s'", CG3_ROM_FILE);
    309         }
    310     }
    311 
    312     memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size,
    313                            &error_fatal);
    314     memory_region_set_log(&s->vram_mem, true, DIRTY_MEMORY_VGA);
    315     sysbus_init_mmio(sbd, &s->vram_mem);
    316 
    317     sysbus_init_irq(sbd, &s->irq);
    318 
    319     s->con = graphic_console_init(dev, 0, &cg3_ops, s);
    320     qemu_console_resize(s->con, s->width, s->height);
    321 }
    322 
    323 static int vmstate_cg3_post_load(void *opaque, int version_id)
    324 {
    325     CG3State *s = opaque;
    326 
    327     cg3_invalidate_display(s);
    328 
    329     return 0;
    330 }
    331 
    332 static const VMStateDescription vmstate_cg3 = {
    333     .name = "cg3",
    334     .version_id = 1,
    335     .minimum_version_id = 1,
    336     .post_load = vmstate_cg3_post_load,
    337     .fields = (VMStateField[]) {
    338         VMSTATE_UINT16(height, CG3State),
    339         VMSTATE_UINT16(width, CG3State),
    340         VMSTATE_UINT16(depth, CG3State),
    341         VMSTATE_BUFFER(r, CG3State),
    342         VMSTATE_BUFFER(g, CG3State),
    343         VMSTATE_BUFFER(b, CG3State),
    344         VMSTATE_UINT8(dac_index, CG3State),
    345         VMSTATE_UINT8(dac_state, CG3State),
    346         VMSTATE_END_OF_LIST()
    347     }
    348 };
    349 
    350 static void cg3_reset(DeviceState *d)
    351 {
    352     CG3State *s = CG3(d);
    353 
    354     /* Initialize palette */
    355     memset(s->r, 0, 256);
    356     memset(s->g, 0, 256);
    357     memset(s->b, 0, 256);
    358 
    359     s->dac_state = 0;
    360     s->full_update = 1;
    361     qemu_irq_lower(s->irq);
    362 }
    363 
    364 static Property cg3_properties[] = {
    365     DEFINE_PROP_UINT32("vram-size",    CG3State, vram_size, -1),
    366     DEFINE_PROP_UINT16("width",        CG3State, width,     -1),
    367     DEFINE_PROP_UINT16("height",       CG3State, height,    -1),
    368     DEFINE_PROP_UINT16("depth",        CG3State, depth,     -1),
    369     DEFINE_PROP_END_OF_LIST(),
    370 };
    371 
    372 static void cg3_class_init(ObjectClass *klass, void *data)
    373 {
    374     DeviceClass *dc = DEVICE_CLASS(klass);
    375 
    376     dc->realize = cg3_realizefn;
    377     dc->reset = cg3_reset;
    378     dc->vmsd = &vmstate_cg3;
    379     device_class_set_props(dc, cg3_properties);
    380 }
    381 
    382 static const TypeInfo cg3_info = {
    383     .name          = TYPE_CG3,
    384     .parent        = TYPE_SYS_BUS_DEVICE,
    385     .instance_size = sizeof(CG3State),
    386     .instance_init = cg3_initfn,
    387     .class_init    = cg3_class_init,
    388 };
    389 
    390 static void cg3_register_types(void)
    391 {
    392     type_register_static(&cg3_info);
    393 }
    394 
    395 type_init(cg3_register_types)