On Sun, Feb 9, 2014 at 2:38 AM, Mark Cave-Ayland <mark.cave-ayl...@ilande.co.uk> wrote: > The CG3 framebuffer is a simple 8-bit framebuffer for use with operating > systems such as early Solaris that do not have drivers for TCX. > > Signed-off-by: Mark Cave-Ayland <mark.cave-ayl...@ilande.co.uk> > CC: Blue Swirl <blauwir...@gmail.com> > CC: Anthony Liguori <aligu...@amazon.com> > CC: Peter Maydell <peter.mayd...@linaro.org> > CC: Bob Breuer <breu...@mc.net> > CC: Artyom Tarasenko <atar4q...@gmail.com> > --- > Makefile | 2 +- > default-configs/sparc-softmmu.mak | 1 + > hw/display/Makefile.objs | 1 + > hw/display/cg3.c | 358 > +++++++++++++++++++++++++++++++++++++ > pc-bios/QEMU,cgthree.bin | Bin 0 -> 850 bytes > pc-bios/README | 4 +- > 6 files changed, 363 insertions(+), 3 deletions(-) > create mode 100644 hw/display/cg3.c > create mode 100644 pc-bios/QEMU,cgthree.bin > > diff --git a/Makefile b/Makefile > index 807054b..c3c7ccc 100644 > --- a/Makefile > +++ b/Makefile > @@ -293,7 +293,7 @@ ifdef INSTALL_BLOBS > BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \ > vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \ > acpi-dsdt.aml q35-acpi-dsdt.aml \ > -ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin \ > +ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin > QEMU,cgthree.bin \ > pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \ > pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \ > efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \ > diff --git a/default-configs/sparc-softmmu.mak > b/default-configs/sparc-softmmu.mak > index 8fc93dd..ab796b3 100644 > --- a/default-configs/sparc-softmmu.mak > +++ b/default-configs/sparc-softmmu.mak > @@ -10,6 +10,7 @@ CONFIG_EMPTY_SLOT=y > CONFIG_PCNET_COMMON=y > CONFIG_LANCE=y > CONFIG_TCX=y > +CONFIG_CG3=y > CONFIG_SLAVIO=y > CONFIG_CS4231=y > CONFIG_GRLIB=y > diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs > index 540df82..7ed76a9 100644 > --- a/hw/display/Makefile.objs > +++ b/hw/display/Makefile.objs > @@ -28,6 +28,7 @@ obj-$(CONFIG_OMAP) += omap_lcdc.o > obj-$(CONFIG_PXA2XX) += pxa2xx_lcd.o > obj-$(CONFIG_SM501) += sm501.o > obj-$(CONFIG_TCX) += tcx.o > +obj-$(CONFIG_CG3) += cg3.o > > obj-$(CONFIG_VGA) += vga.o > > diff --git a/hw/display/cg3.c b/hw/display/cg3.c > new file mode 100644 > index 0000000..3e96356 > --- /dev/null > +++ b/hw/display/cg3.c > @@ -0,0 +1,358 @@ > +/* > + * QEMU CG3 Frame buffer > + * > + * Copyright (c) 2012 Bob Breuer > + * Copyright (c) 2013 Mark Cave-Ayland > + * > + * 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 "qemu-common.h" > +#include "ui/console.h" > +#include "hw/sysbus.h" > +#include "hw/loader.h" > + > +/* #define DEBUG_CG3 */ > + > +#define CG3_ROM_FILE "QEMU,cgthree.bin" > +#define FCODE_MAX_ROM_SIZE 0x10000 > + > +#define CG3_REG_SIZE 0x20 > +#define CG3_VRAM_SIZE 0x100000 > +#define CG3_VRAM_OFFSET 0x800000 > + > +#ifdef DEBUG_CG3 > +#define DPRINTF(fmt, ...) \ > + printf("CG3: " fmt , ## __VA_ARGS__) > +#else > +#define DPRINTF(fmt, ...) > +#endif > +
With debug macros its better to use a regular if. Something like: #ifndef DEBUG_CG3 #define DEBUG_CG3 0 #endif #define DPRINTF(...) do { \ if (DEBUG_CG3) { \ printf(...) \ } \ } while (0); The reason being your debug code will always be compile checked allowing contributors to apply type changes without breaking your debug code accidently. > +#define TYPE_CG3 "SUNW,cgthree" > +#define CG3(obj) OBJECT_CHECK(CG3State, (obj), TYPE_CG3) > + > +typedef struct CG3State { > + SysBusDevice parent_obj; > + > + QemuConsole *con; > + qemu_irq irq; > + hwaddr prom_addr; > + MemoryRegion vram_mem; > + MemoryRegion rom; > + MemoryRegion reg; > + uint32_t vram_size; > + int full_update; > + uint8_t regs[16]; > + uint8_t r[256], g[256], b[256]; > + uint16_t width, height, depth; > + uint8_t dac_index, dac_state; > +} CG3State; > + > +static void cg3_update_display(void *opaque) > +{ > + CG3State *s = opaque; > + DisplaySurface *surface = qemu_console_surface(s->con); > + const uint8_t *pix; > + uint32_t *data; > + uint32_t dval; > + int x, y, y_start; > + unsigned int width, height; > + ram_addr_t page, page_min, page_max; > + > + if (surface_bits_per_pixel(surface) != 32) { > + return; > + } > + width = s->width; > + height = s->height; > + > + y_start = -1; > + page_min = -1; > + page_max = 0; > + page = 0; > + pix = memory_region_get_ram_ptr(&s->vram_mem); > + data = (uint32_t *)surface_data(surface); > + > + for (y = 0; y < height; y++) { > + int update = s->full_update; > + > + page = (y * width) & TARGET_PAGE_MASK; > + update |= memory_region_get_dirty(&s->vram_mem, page, page + width, > + DIRTY_MEMORY_VGA); > + if (update) { > + if (y_start < 0) { > + y_start = y; > + } > + if (page < page_min) { > + page_min = page; > + } > + if (page > page_max) { > + page_max = page; > + } > + > + for (x = 0; x < width; x++) { > + dval = *pix++; > + dval = (s->r[dval] << 16) | (s->g[dval] << 8) | s->b[dval]; > + *data++ = dval; > + } > + } else { > + if (y_start >= 0) { > + dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start); > + y_start = -1; > + } > + pix += width; > + data += width; > + } > + } > + s->full_update = 0; > + if (y_start >= 0) { > + dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start); > + } > + if (page_max >= page_min) { > + memory_region_reset_dirty(&s->vram_mem, > + page_min, page_max - page_min + > TARGET_PAGE_SIZE, > + DIRTY_MEMORY_VGA); > + } > + /* vsync interrupt? */ > + if (s->regs[0] & 0x80) { > + s->regs[1] |= 0x80; > + qemu_irq_raise(s->irq); > + } > +} > + > +static void cg3_invalidate_display(void *opaque) > +{ > + CG3State *s = opaque; > + > + memory_region_set_dirty(&s->vram_mem, 0, CG3_VRAM_SIZE); > +} > + > +static uint64_t cg3_reg_read(void *opaque, hwaddr addr, unsigned size) > +{ > + CG3State *s = opaque; > + int val; > + > + switch (addr) { > + case 0x10: What are these magic numbers? You should define macros matching the names in your register specs. > + val = s->regs[0]; Same for these hardcoded indicies into regs[]. > + break; > + case 0x11: > + val = s->regs[1] | 0x71; /* monitor ID 7, board type = 1 (color) */ > + break; > + case 0x12 ... 0x1f: > + val = s->regs[addr - 0x10]; > + break; > + default: > + val = 0; > + break; Is this guest error or unimplemented behaviour? You should qemu_log_mask( accordingly. > + } > + DPRINTF("read %02x from reg %x\n", val, (int)addr); > + return val; > +} > + > +static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val, > + unsigned size) > +{ > + CG3State *s = opaque; > + uint8_t regval; > + int i; > + > + DPRINTF("write %02lx to reg %x size %d\n", val, (int)addr, size); > + > + switch (addr) { > + case 0: > + s->dac_index = val; > + s->dac_state = 0; > + break; > + case 4: > + /* This register can be written to as either a long word or a byte. > + * According to the SBus specification, byte transfers are placed > + * in bits 31-28 */ Very strange. Is it not just a case of generic big-endian accessible rather than just such a very specific exception here? > + if (size == 1) { > + val <<= 24; > + } > + > + for (i = 0; i < size; i++) { > + regval = val >> 24; > + > + switch (s->dac_state) { > + case 0: > + s->r[s->dac_index] = regval; > + s->dac_state++; > + break; > + case 1: > + s->g[s->dac_index] = regval; > + s->dac_state++; > + break; > + case 2: > + s->b[s->dac_index] = regval; > + /* Index autoincrement */ > + s->dac_index = (s->dac_index + 1) & 255; > + default: > + s->dac_state = 0; > + break; > + } > + val <<= 8; > + } > + s->full_update = 1; > + break; > + case 0x10: > + s->regs[0] = val; > + break; > + case 0x11: > + if (s->regs[1] & 0x80) { Define macros for register field bits. > + /* clear interrupt */ > + s->regs[1] &= ~0x80; > + qemu_irq_lower(s->irq); > + } > + break; > + case 0x12 ... 0x1f: > + s->regs[addr - 0x10] = val; > + break; > + default: > + break; > + } > +} > + > +static const MemoryRegionOps cg3_reg_ops = { > + .read = cg3_reg_read, > + .write = cg3_reg_write, > + .endianness = DEVICE_NATIVE_ENDIAN, > + .valid = { > + .min_access_size = 1, > + .max_access_size = 4, Your hander switch statements stride in 4, are you only doing this for your one exception case of that one-byte big-endian access I commented earlier. > + }, > +}; > + > +static const GraphicHwOps cg3_ops = { > + .invalidate = cg3_invalidate_display, > + .gfx_update = cg3_update_display, > +}; > + > +static int cg3_init1(SysBusDevice *dev) Use of SysBusDevice::init functions is depracated. Please use object init fns or Device::Realize functions instead. Regards, Peter > +{ > + CG3State *s = CG3(dev); > + int ret; > + char *fcode_filename; > + > + /* FCode ROM */ > + memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE); > + vmstate_register_ram_global(&s->rom); > + memory_region_set_readonly(&s->rom, true); > + sysbus_init_mmio(dev, &s->rom); > + > + fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, CG3_ROM_FILE); > + if (fcode_filename) { > + ret = load_image_targphys(fcode_filename, s->prom_addr, > + FCODE_MAX_ROM_SIZE); > + if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) { > + fprintf(stderr, "cg3: could not load prom '%s'\n", CG3_ROM_FILE); > + return -1; > + } > + } > + > + memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg", > + CG3_REG_SIZE); > + sysbus_init_mmio(dev, &s->reg); > + > + memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size); > + vmstate_register_ram_global(&s->vram_mem); > + sysbus_init_mmio(dev, &s->vram_mem); > + > + sysbus_init_irq(dev, &s->irq); > + > + s->con = graphic_console_init(DEVICE(dev), &cg3_ops, s); > + qemu_console_resize(s->con, s->width, s->height); > + > + return 0; > +} > + > +static int vmstate_cg3_post_load(void *opaque, int version_id) > +{ > + CG3State *s = opaque; > + > + cg3_invalidate_display(s); > + > + return 0; > +} > + > +static const VMStateDescription vmstate_cg3 = { > + .name = "cg3", > + .version_id = 1, > + .minimum_version_id = 1, > + .post_load = vmstate_cg3_post_load, > + .fields = (VMStateField[]) { > + VMSTATE_UINT16(height, CG3State), > + VMSTATE_UINT16(width, CG3State), > + VMSTATE_UINT16(depth, CG3State), > + VMSTATE_BUFFER(r, CG3State), > + VMSTATE_BUFFER(g, CG3State), > + VMSTATE_BUFFER(b, CG3State), > + VMSTATE_UINT8(dac_index, CG3State), > + VMSTATE_UINT8(dac_state, CG3State), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static void cg3_reset(DeviceState *d) > +{ > + CG3State *s = CG3(d); > + > + /* Initialize palette */ > + memset(s->r, 0, 256); > + memset(s->g, 0, 256); > + memset(s->b, 0, 256); > + > + s->dac_state = 0; > + s->full_update = 1; > + qemu_irq_lower(s->irq); > +} > + > +static Property cg3_properties[] = { > + DEFINE_PROP_HEX32("vram_size", CG3State, vram_size, -1), > + DEFINE_PROP_UINT16("width", CG3State, width, -1), > + DEFINE_PROP_UINT16("height", CG3State, height, -1), > + DEFINE_PROP_UINT16("depth", CG3State, depth, -1), > + DEFINE_PROP_HEX64("prom_addr", CG3State, prom_addr, -1), > + DEFINE_PROP_END_OF_LIST(), > +}; > + > +static void cg3_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); > + > + k->init = cg3_init1; > + dc->reset = cg3_reset; > + dc->vmsd = &vmstate_cg3; > + dc->props = cg3_properties; > +} > + > +static const TypeInfo cg3_info = { > + .name = TYPE_CG3, > + .parent = TYPE_SYS_BUS_DEVICE, > + .instance_size = sizeof(CG3State), > + .class_init = cg3_class_init, > +}; > + > +static void cg3_register_types(void) > +{ > + type_register_static(&cg3_info); > +} > + > +type_init(cg3_register_types) > diff --git a/pc-bios/QEMU,cgthree.bin b/pc-bios/QEMU,cgthree.bin > new file mode 100644 > index > 0000000000000000000000000000000000000000..6fec9462070bf9a0f88024c7bf66f444d1d11d61 > GIT binary patch > literal 850 > zcmZ{i&2HL25XX10!NXT-76XB#Rk_y^s6|SoR%&la53Q7_>KX6`yTvxLO)GA>_ch=J > zP_0Ed5~+vw1^OC&f^?RT1C@IDd*?SZ|5@Af2Y<wjX;&#S`O9L)^D4_Nujb2jiXgca > zPDC*9!r1=eIU=;bdQRdZo4=yUd6i|Ci{<)%MIyz_ir4;eaD_K=6J(UtR=nVdN#fcA > zFNrruCp7i~VGm}B*rM#FYA_wy$!sE!rI=f#Xh;N$<uT(|S$=6UrZaVA++l5xwGGbi > zu)fC(Rdr#9vwOTXDN4*eUYqPSqhX~xGG|XyEYsmuks~^k)Zx)xil*!=AoCkEsCJ<O > zoLnnXbubf1(BxVqMqm=>vIAO|=luS}_JT~FP*rk6h2b=zc%GuQBB{~))g@X_rt6=% > zVK@$>Ha6q}>z8kpvySz{2N@kpEMXb>Jz5ksB_3_=s6dTCOX4v$*W4J65;qbe1Ke=D > zcrxzKpvBAAAKra@*6Vcb?u%{@nkk;p^!ZDR`PfpU9u9?JLjiUu4_oRe`bNojC4ddA > z-NOJr!DrG6H~Nkfi8uxm4a5uZ+ZQly!#DLmP9;_lsVKMI5>-P{cC&R96e!56_1J6& > zm}<Z|R2J&PbKMJ)NOcg^Z|U+yl{R+kL90s5Wj_qOB#i7>1hD{<>+03P;w8TyOmF(b > yWEu%F;rYw!_h)ClbGu8)^3d%^loP5i*^VudTX8sz;xLL`?}lgvPvCTor|d5SYsmWm > > literal 0 > HcmV?d00001 > > diff --git a/pc-bios/README b/pc-bios/README > index f190068..af6250a 100644 > --- a/pc-bios/README > +++ b/pc-bios/README > @@ -11,8 +11,8 @@ > firmware implementation. The goal is to implement a 100% IEEE > 1275-1994 (referred to as Open Firmware) compliant firmware. > The included images for PowerPC (for 32 and 64 bit PPC CPUs), > - Sparc32 (including QEMU,tcx.bin) and Sparc64 are built from OpenBIOS SVN > - revision 1246. > + Sparc32 (including QEMU,tcx.bin and QEMU,cgthree.bin) and Sparc64 are built > + from OpenBIOS SVN revision 1246. > > - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware > implementation for certain IBM POWER hardware. The sources are at > -- > 1.7.10.4 > >