From: Bob Breuer <breuerr@mc.net>
To: Artyom Tarasenko <atar4qemu@googlemail.com>
Cc: Blue Swirl <blauwirbel@gmail.com>, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] cg14
Date: Sat, 29 May 2010 00:15:46 -0500 [thread overview]
Message-ID: <4C00A302.3090409@mc.net> (raw)
In-Reply-To: <AANLkTimaOzNs2VUSMmo2aohfhGz9C25Hdbss8RenaCLq@mail.gmail.com>
Artyom Tarasenko wrote:
> 2010/5/28 Blue Swirl <blauwirbel@gmail.com>:
>
>> On Fri, May 28, 2010 at 7:54 AM, Bob Breuer <breuerr@mc.net> wrote:
>>
>>> Artyom Tarasenko wrote:
>>>
>>>> 2010/5/27 Bob Breuer <breuerr@mc.net>:
>>>>
>>>>
>>>>> Artyom Tarasenko wrote:
>>>>>
>>>>>
>>>>>> Was going to put some more empty slots into SS-10/20 (VSIMMs, SX)
>>>>>> after we are done with SS-5 (due to technical limitations I can switch
>>>>>> access from one real SS model to another one once a few days only).
>>>>>>
>>>>>>
>>>>>>
>>>>> I have a partial implementation of the SS-20 VSIMM (cg14) that I've been
>>>>> working on. With the Sun firmware, I have working text console, color
>>>>> boot logo, and programmable video resolutions up to 1600x1280.
>>>>>
>>>>>
>>>> Great news! This would allow qemu booting NeXTStep! Are you planning
>>>> to submit the patches any time soon?
>>>>
>>>>
>>>>
>>> It's not in a state to be submitted yet, but I've attached a working
>>> patch if you want to give it a try. I need to hook it up to qdev and
>>> fill in some more of the obviously incomplete switch cases before I'd
>>> sign off on it.
>>>
>> Nice work. I have a few comments below.
>>
>> This probably needs support from OpenBIOS to be usable without OBP.
>>
>
> Maybe it can be used as a second adapter without OpenBIOS support? At
> least under some OSes?
>
>
Probably won't be used without at least being in the firmware device
tree. One area that OpenBIOS could enhance would be a larger memory
size option. The real hardware was only available in 4M and 8M options,
but the memory map allows for 16M. OBP will identify a 16M VSIMM but
won't do anything else with it, and with 16M of vram it would allow for
a potential 2560x1600 32bit resolution.
>>> Bob
>>>
>>>
>>> diff --git a/Makefile.target b/Makefile.target
>>> index fda5bf3..b17b3af 100644
>>> --- a/Makefile.target
>>> +++ b/Makefile.target
>>> @@ -250,6 +250,7 @@ else
>>> obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o
>>> obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o
>>> obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
>>> +obj-sparc-y += cg14.o
>>> endif
>>>
>>> obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
>>> diff --git a/hw/sun4m.c b/hw/sun4m.c
>>> index 7ba0f76..8b23c9b 100644
>>> --- a/hw/sun4m.c
>>> +++ b/hw/sun4m.c
>>> @@ -864,6 +864,13 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
>>> fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
>>> exit (1);
>>> }
>>> + if (hwdef->machine_id == 65) { /* SS-20 */
>>>
>> hwdef structure should contain a field for cg14. If non-zero, install
>> cg14. Was cg14 only available for SS-20? Was it always included? This
>> is also interesting for OpenBIOS, we need to detect cg14 vs. TCX.
>>
The cg14 was only an option for SS-20 and the rare SS-10SX, but not the
regular SS-10, though the SS-10 chipset may have been capable of
supporting it. Each cg14 vsimm takes the place of a stick of memory
with 2 slots physically capable of holding a vsimm.
Is there a way to pass the framebuffer type and/or address to OpenBIOS?
I would be inclined to have the SS-20 machine default to cg14 instead of
TCX, but it will blow a hole in the support of more than 2G of emulated
system ram.
>>> + /* cg14.c */
>>> + void cg14_init(target_phys_addr_t ctrl_base, target_phys_addr_t vram_base,
>>> + uint32_t vram_size);
>>>
>> This should go to sun4m.h or cg14.h.
>>
>>
>>> +
>>> + cg14_init(0x09c000000ULL, 0x0fc000000ULL, 8<<20);
>>> + } else
>>>
>> Please add braces and reindent.
>>
>>
>>> tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
>>> graphic_depth);
>>>
>>> --- /dev/null Fri May 28 02:08:36 2010
>>> +++ hw/cg14.c Fri May 28 01:58:49 2010
>>> @@ -0,0 +1,785 @@
>>> +/*
>>> + * QEMU CG14 Frame buffer
>>> + *
>>> + * Copyright (c) 2010 Bob Breuer
>>> + *
>>> + * 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 "console.h"
>>> +#include "sysbus.h"
>>> +
>>> +#ifdef DEBUG
>>>
>
> DEBUG_CG14 ?
>
>
>>> +#define DPRINTF(fmt, ...) \
>>> + do { printf("CG14: " fmt , ## __VA_ARGS__); } while (0)
>>> +#else
>>> +#define DPRINTF(fmt, ...)
>>> +#endif
>>> +
>>> +#define CG14_INFO(fmt, ...) \
>>> + do { printf("CG14: " fmt , ## __VA_ARGS__); } while (0)
>>> +#define CG14_ERROR(fmt, ...) \
>>> + do { printf("CG14: " fmt , ## __VA_ARGS__); } while (0)
>>> +
>>> +/*
>>> + * A[28:26] = slot number (4 to 7)
>>> + * regs: size 0x10000 @ 0x09c000000 (0x80000000 + slot * 64M)
>>> + * vmem: size upto 16MB @ 0x0fc000000 (0xE0000000 + slot * 64M)
>>> + */
>>>
>> If you have any links to chipset docs, it would be nice to mention those here.
>>
Chipset docs are hard to come by. But here's what I've found:
"Sun-4M System Architecture" section A.II.3 briefly covers VSIMM and
DSIMM size detection.
Linux kernel 2.6 drivers/video/cg14.c has most of the registers named.
US Patent 5815137 covers the cursor implementation, but it includes
drawings which show the various color and lookup table muxing and
blending capability. I will not be implementing the cursor functionality.
>>> +
>>> +/*
>>> + * memory map:
>>> + * reg+0x0000 = control registers
>>> + * reg+0x1000 = cursor registers
>>> + * reg+0x2000 = dac registers (ADV7152)
>>> + * reg+0x3000 = xlut
>>> + * reg+0x4000 = clut1
>>> + * reg+0x5000 = clut2
>>> + * reg+0x6000 = clut3 (if implemented)
>>> + *
>>> + * mem+0x0000000 = XBGR (01234567)
>>> + * mem+0x1000000 = BGR (.123.567)
>>> + * mem+0x2000000 = X16 (0246)
>>> + * mem+0x2800000 = C16 (1357)
>>> + * mem+0x3000000 = X32 (04)
>>> + * mem+0x3400000 = B32 (15)
>>> + * mem+0x3800000 = G32 (26)
>>> + * mem+0x3c00000 = R32 (37)
>>>
>> Interesting device. You could increase the performance a lot by making
>> the XBGR area ordinary memory and detecting the dirtyness with
>> VGA_DIRTY_FLAG like TCX. The other areas could use multiple byte
>> stores to the memory so dirty information would be updated.
>>
Hmm, interesting. Might be cumbersome if the width isn't 1024 though.
>>> + */
>>> +
>>> +#define CG14_REG_SIZE 0x10000
>>> +#define CG14_VMEM_SLOTSIZE (64<<20)
>>> +
>>> +#define CG14_MONID_1024x768 0
>>> +#define CG14_MONID_1600x1280 1
>>> +#define CG14_MONID_1280x1024 2
>>> +#define CG14_MONID_1152x900 7
>>> +
>>> +#define CG14_MONID_DEFAULT CG14_MONID_1024x768
>>> +
>>> +#define MCR_PIXMODE_MASK 0x30
>>> +#define MCR_PIXMODE_8 0x00
>>> +#define MCR_PIXMODE_16 0x20 /* 8+8 (X16,C16) */
>>> +#define MCR_PIXMODE_32 0x30 /* XBGR */
>>> +
>>> +
>>> +struct ADV7152_state {
>>> + uint8_t mode;
>>> + uint8_t address;
>>> + int rgb_seq;
>>> +};
>>> +
>>> +typedef struct CG14State {
>>> + SysBusDevice busdev;
>>> + DisplayState *ds;
>>> +
>>> + uint8_t *vram;
>>> + uint32_t vram_amask;
>>> + int width, height;
>>> + int dirty, size_changed;
>>> + struct {
>>> + uint8_t mcr;
>>> + uint8_t ppr;
>>> + } ctrl;
>>> + struct ADV7152_state dac;
>>> + struct {
>>> + uint16_t hblank_start;
>>> + uint16_t hblank_clear;
>>> + uint16_t vblank_start;
>>> + uint16_t vblank_clear;
>>> + } timing;
>>> + uint8_t xlut[256];
>>> + uint32_t clut1[256];
>>> + uint32_t clut2[256];
>>> +} CG14State;
>>> +
>>> +static void cg14_screen_dump(void *opaque, const char *filename);
>>> +static void cg14_invalidate_display(void *opaque);
>>> +
>>> +static inline uint32_t bgr_to_rgb(uint32_t bgr)
>>> +{
>>> + uint32_t rgb;
>>> +
>>> + /* swap r & b */
>>> + rgb = (bgr & 0x00FF00)
>>> + | (bgr & 0x0000FF) << 16
>>> + | (bgr & 0xFF0000) >> 16;
>>> + return rgb;
>>> +}
>>> +
>>> +static void cg14_draw_line32(const CG14State *s, void *dst, const uint8_t *src, int pixmode, int is_bgr)
>>> +{
>>> + int i;
>>> + int x, r, g, b;
>>> + uint8_t xlut_val;
>>> + uint32_t dval;
>>> + uint32_t abgr;
>>> +
>>> + xlut_val = s->ctrl.ppr;
>>> +
>>> + for (i=0; i<s->width; i++) {
>>> + x = *src++;
>>> + if (pixmode == 8) {
>>>
>> To increase performance, pixmode should not be passed at all but
>> instead separate functions should be added for each mode and the
>> function should be selected before the line loop.
>>
Yes, at least for 8bit mode. The per-pixel xlut value offers a lot of
flexibility that may be hard to speed up when fully implemented. The
hardware supports simultaneous true-color and palette lookups to
generate 2 color values to blend together for every displayed pixel.
>>> + b = x;
>>> + } else {
>>> + b = *src++;
>>> + xlut_val = s->xlut[x];
>>> + }
>>> + if (pixmode != 32) {
>>> + r = g = b;
>>> + } else {
>>> + g = *src++;
>>> + r = *src++;
>>> + }
>>> + if (xlut_val == 0) {
>>> + abgr = b << 16 | g << 8 | r;
>>> + } else if (xlut_val == 0x40) {
>>> + abgr = s->clut1[x];
>>> + } else {
>>> + abgr = 0;
>>> + }
>>> + /* dac lookup ? */
>>> +
>>> + /* to surface format */
>>> + dval = is_bgr ? (abgr & 0xFFFFFF) : bgr_to_rgb(abgr);
>>> + ((uint32_t*)dst)[i] = dval;
>>> + }
>>> +}
>>> +
>>> +static void cg14_update_display(void *opaque)
>>> +{
>>> + CG14State *s = opaque;
>>> + int h, pixmode;
>>> + uint8_t *pix;
>>> + uint8_t *data;
>>> + int new_width, new_height;
>>> +
>>> + if (s->size_changed) {
>>> + new_width = 4 * (s->timing.hblank_start - s->timing.hblank_clear);
>>> + new_height = s->timing.vblank_start - s->timing.vblank_clear;
>>> + s->size_changed = 0;
>>> + if ((new_width != s->width || new_height != s->height) && new_width > 0 && new_height > 0) {
>>> + s->width = new_width;
>>> + s->height = new_height;
>>> + CG14_INFO("new resolution = %d x %d\n", new_width, new_height);
>>> + qemu_console_resize(s->ds, s->width, s->height);
>>> + s->dirty = 1;
>>> + }
>>> + }
>>> +
>>> + if (!s->dirty || !s->width || !s->height) {
>>> + return;
>>> + }
>>> +
>>> + if (ds_get_bits_per_pixel(s->ds) != 32) {
>>> + CG14_ERROR("cg14_update: FIXME: bpp (%d) != 32, linesize %d\n",
>>> + ds_get_bits_per_pixel(s->ds), ds_get_linesize(s->ds));
>>> + return;
>>> + }
>>> +
>>> + switch (s->ctrl.mcr & MCR_PIXMODE_MASK) {
>>> + case MCR_PIXMODE_32:
>>> + pixmode = 32;
>>> + break;
>>> + case MCR_PIXMODE_16:
>>> + pixmode = 16;
>>> + break;
>>> + case MCR_PIXMODE_8:
>>> + default:
>>> + pixmode = 8;
>>> + break;
>>> + }
>>> +
>>> + pix = s->vram;
>>> + data = ds_get_data(s->ds);
>>> +
>>> + for (h=0; h<s->height; h++) {
>>> + cg14_draw_line32(s, data, pix, pixmode, is_surface_bgr(s->ds->surface));
>>> + pix += s->width * (pixmode / 8);
>>> + data += ds_get_linesize(s->ds);
>>> + }
>>> + dpy_update(s->ds, 0, 0, s->width, s->height);
>>> + s->dirty = 0;
>>> +}
>>> +
>>> +static void cg14_invalidate_display(void *opaque)
>>> +{
>>> + CG14State *s = opaque;
>>> +
>>> + s->dirty = 1;
>>> +}
>>> +
>>> +static void ADV7152_write(struct ADV7152_state *s, unsigned int reg, unsigned int val)
>>> +{
>>> + switch (reg) {
>>> + case 0: /* address register */
>>> + DPRINTF("ADV7152 Write address %02x\n", val);
>>> + s->address = val;
>>> + s->rgb_seq = 0;
>>> + break;
>>> + case 1: /* look up table */
>>> + DPRINTF("ADV7152 Write %02x to lookup table\n", val);
>>> + s->rgb_seq++;
>>> + break;
>>> + case 2: /* control registers */
>>> + DPRINTF("ADV7152 Write %02x to control reg %d\n", val, s->address);
>>> + switch (s->address) {
>>> + default:
>>> + break;
>>> + }
>>> + break;
>>> + case 3: /* mode register */
>>> + CG14_INFO("ADV7152 Write mode %02x (%d bit DAC, %d bit bus)\n",
>>> + val, (val & 2) ? 10 : 8, (val & 4) ? 10 : 8);
>>> + if (!val & 0x01) {
>>> + // reset the dac
>>> + s->rgb_seq = 0;
>>> + }
>>> + s->mode = val;
>>> + break;
>>> + }
>>> +}
>>> +
>>> +static uint32_t cg14_reg_readb(void *opaque, target_phys_addr_t addr)
>>> +{
>>> + CG14State *s = opaque;
>>> + unsigned int val;
>>> +
>>> + switch (addr & 0xffff) {
>>> + case 0x0000:
>>> + val = s->ctrl.mcr;
>>> + break;
>>> + case 0x0001:
>>> + val = s->ctrl.ppr;
>>> + break;
>>> + case 0x0004: /* status ? */
>>> + /* monitor code in bits 1..3 */
>>> + val = CG14_MONID_DEFAULT << 1;
>>> + break;
>>> + case 0x0006: /* hw version */
>>> + //val = 0x00; /* old version */
>>> + val = 0x30;
>>> + break;
>>> + default:
>>> + val = 0;
>>> + break;
>>> + }
>>> + CG14_INFO("readb %02x from reg %x\n", val, (int)addr);
>>> +
>>> + return val;
>>> +}
>>> +
>>> +static void cg14_reg_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
>>> +{
>>> + CG14State *s = opaque;
>>> + uint32_t i;
>>> +
>>> + if ((addr & 0xfcff) == 0x2000) {
>>> + i = (addr & 0x300) >> 8;
>>> + ADV7152_write(&s->dac, i, val);
>>> + return;
>>> + }
>>> + if ((addr & 0xff00) == 0x3000) {
>>> + /* xlut */
>>> + i = addr & 0xff;
>>> + if (s->xlut[i] != val) {
>>> + s->dirty = 1;
>>> + s->xlut[i] = val;
>>> + if (val && val != 0x40)
>>> + CG14_ERROR("writeb xlut[%d] = %02x\n", i, val);
>>> + }
>>> + return;
>>> + }
>>> +
>>> + s->dirty = 1;
>>> +
>>> + switch (addr & 0xffff) {
>>> + case 0x0000:
>>> + s->ctrl.mcr = val;
>>> + break;
>>> + case 0x0001:
>>> + s->ctrl.ppr = val & 0xF0;
>>> + break;
>>> + case 0x0007:
>>> + /* clock control (ICS1562AM-001) */
>>> + DPRINTF("write %02x to clock control\n", val);
>>> + break;
>>> + default:
>>> + CG14_ERROR("writeb %02x to reg %x\n", val, (int)addr);
>>> + break;
>>> + }
>>> +}
>>> +
>>> +static uint32_t cg14_reg_readw(void *opaque, target_phys_addr_t addr)
>>> +{
>>> + CG14State *s = opaque;
>>> + unsigned int val;
>>> +
>>> + switch (addr & 0xffff) {
>>> + case 0x0018:
>>> + val = s->timing.hblank_start;
>>> + break;
>>> + case 0x001a:
>>> + val = s->timing.hblank_clear;
>>> + break;
>>> + case 0x0022:
>>> + val = s->timing.vblank_start;
>>> + break;
>>> + case 0x0024:
>>> + val = s->timing.vblank_clear;
>>> + break;
>>> + default:
>>> + val = 0;
>>> + break;
>>> + }
>>> + CG14_INFO("readw 0x%08x from reg %x\n", val, (int)addr);
>>> +
>>> + return val;
>>> +}
>>> +
>>> +static void cg14_reg_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
>>> +{
>>> + CG14State *s = opaque;
>>> +
>>> + CG14_INFO("writew %04x to reg %x\n", val, (int)addr);
>>> +
>>> + /* timing registers are 16bit */
>>> +
>>> + switch (addr & 0xffff) {
>>> + case 0x0018:
>>> + s->timing.hblank_start = val;
>>> + break;
>>> + case 0x001a:
>>> + s->timing.hblank_clear = val;
>>> + s->size_changed = 1;
>>> + break;
>>> + case 0x0022:
>>> + s->timing.vblank_start = val;
>>> + break;
>>> + case 0x0024:
>>> + s->timing.vblank_clear = val;
>>> + s->size_changed = 1;
>>> + break;
>>> + case 0x001c: /* hsync_start */
>>> + case 0x001e: /* hsync_clear */
>>> + case 0x0020: /* csync_clear */
>>> + case 0x0026: /* vsync_start */
>>> + case 0x0028: /* vsync_clear */
>>> + default:
>>> + break;
>>> + }
>>> +}
>>> +
>>> +static uint32_t cg14_reg_readl(void *opaque, target_phys_addr_t addr)
>>> +{
>>> + CG14State *s = opaque;
>>> + uint32_t val;
>>> + uint32_t i;
>>> +
>>> + i = (addr & 0x3ff) >> 2;
>>> + switch (addr & 0xfc00) {
>>> + case 0x4000:
>>> + val = s->clut1[i];
>>> + break;
>>> + case 0x5000:
>>> + val = s->clut2[i];
>>> + break;
>>> + default:
>>> + val = 0;
>>> + CG14_ERROR("readl %08x from reg %x\n", val, (int)addr);
>>> + break;
>>> + }
>>> +
>>> + return val;
>>> +}
>>> +
>>> +static void cg14_reg_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
>>> +{
>>> + CG14State *s = opaque;
>>> + uint32_t i;
>>> +
>>> + s->dirty = 1;
>>> +
>>> + i = (addr & 0x3ff) >> 2;
>>> + switch (addr & 0xfc00) {
>>> + case 0x4000:
>>> + s->clut1[i] = val;
>>> + break;
>>> + case 0x5000:
>>> + s->clut2[i] = val;
>>> + break;
>>> + default:
>>> + CG14_ERROR("writel %08x to reg %x\n", val, (int)addr);
>>> + break;
>>> + }
>>> +}
>>> +
>>> +static CPUReadMemoryFunc *cg14_reg_read[3] = {
>>> + cg14_reg_readb,
>>> + cg14_reg_readw,
>>> + cg14_reg_readl,
>>> +};
>>> +
>>> +static CPUWriteMemoryFunc *cg14_reg_write[3] = {
>>> + cg14_reg_writeb,
>>> + cg14_reg_writew,
>>> + cg14_reg_writel,
>>> +};
>>> +
>>> +static uint32_t cg14_vram_readb(void *opaque, target_phys_addr_t addr)
>>> +{
>>> + CG14State *s = opaque;
>>> + uint32_t offset;
>>> + uint32_t val = 0;
>>> +
>>> + switch (addr & 0x3000000) {
>>> + case 0x0000000:
>>> + offset = addr & s->vram_amask;
>>> + val = ldub_p(s->vram+offset);
>>> + break;
>>> + case 0x1000000:
>>> + offset = addr & s->vram_amask;
>>> + val = 0; // FIXME
>>> + break;
>>> + case 0x2000000:
>>> + offset = ((addr << 1) & s->vram_amask) + ((addr >> 23) & 1);
>>> + val = ldub_p(s->vram+offset);
>>> + break;
>>> + case 0x3000000:
>>> + offset = ((addr << 2) & s->vram_amask) + ((addr >> 22) & 3);
>>> + val = ldub_p(s->vram+offset);
>>> + break;
>>> + }
>>> + CG14_INFO("readb %02x from vram %x\n", val, (int)addr);
>>> +
>>> + return val;
>>> +}
>>> +
>>> +static void cg14_vram_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
>>> +{
>>> + CG14State *s = opaque;
>>> + uint32_t offset;
>>> +
>>> + switch (addr & 0x3000000) {
>>> + case 0x0000000:
>>> + offset = addr & s->vram_amask;
>>> + stb_p(s->vram+offset, val);
>>> + if (offset < 4 * s->width * s->height) {
>>> + s->dirty = 1;
>>> + }
>>> + break;
>>> + default:
>>> + CG14_ERROR("writeb %02x to vram %x\n", val, (int)addr);
>>> + break;
>>> + }
>>> +}
>>> +
>>> +static uint32_t cg14_vram_readw(void *opaque, target_phys_addr_t addr)
>>> +{
>>> + CG14State *s = opaque;
>>> + uint32_t offset;
>>> + uint32_t val;
>>> +
>>> + switch (addr & 0x3000000) {
>>> + default:
>>> + offset = addr & s->vram_amask;
>>> + val = 0;
>>> + break;
>>> + }
>>> + CG14_ERROR("readw %04x from vram %x\n", val, (int)addr);
>>> +
>>> + return val;
>>> +}
>>> +
>>> +static void cg14_vram_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
>>> +{
>>> + CG14State *s = opaque;
>>> +
>>> + CG14_ERROR("writew %04x to vram %x\n", val, (int)addr);
>>> +
>>> + s->dirty = 1;
>>> +
>>> + switch (addr & 0x3000000) {
>>> + default:
>>> + break;
>>> + }
>>> +}
>>> +
>>> +static uint32_t cg14_vram_readl(void *opaque, target_phys_addr_t addr)
>>> +{
>>> + CG14State *s = opaque;
>>> + uint32_t offset;
>>> + uint32_t val = 0;
>>> +
>>> + switch (addr & 0x3000000) {
>>> + case 0x0000000:
>>> + offset = addr & s->vram_amask;
>>> + val = ldl_be_p(s->vram+offset);
>>> + break;
>>> + case 0x1000000:
>>> + case 0x2000000:
>>> + case 0x3000000:
>>> + CG14_ERROR("readl %08x from vram %x\n", val, (int)addr);
>>> + break;
>>> + }
>>> +
>>> + return val;
>>> +}
>>> +
>>> +static void cg14_vram_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
>>> +{
>>> + CG14State *s = opaque;
>>> + uint32_t offset;
>>> +
>>> + switch (addr & 0x3000000) {
>>> + case 0x0000000:
>>> + offset = addr & s->vram_amask;
>>> + stl_be_p(s->vram+offset, val);
>>> + if (offset < 4 * s->width * s->height) {
>>> + s->dirty = 1;
>>> + }
>>> + break;
>>> + case 0x1000000:
>>> + case 0x2000000:
>>> + case 0x3000000:
>>> + CG14_ERROR("writel %08x to vram %x\n", val, (int)addr);
>>> + break;
>>> + }
>>> +}
>>> +
>>> +static CPUReadMemoryFunc *cg14_vram_read[3] = {
>>> + cg14_vram_readb,
>>> + cg14_vram_readw,
>>> + cg14_vram_readl,
>>> +};
>>> +
>>> +static CPUWriteMemoryFunc *cg14_vram_write[3] = {
>>> + cg14_vram_writeb,
>>> + cg14_vram_writew,
>>> + cg14_vram_writel,
>>> +};
>>> +
>>> +
>>> +/******** SX *********/
>>> +
>>> +static uint32_t sx_reg_readb(void *opaque, target_phys_addr_t addr)
>>> +{
>>> + //CG14State *s = opaque;
>>> + int val;
>>> +
>>> + printf("SX readb reg " TARGET_FMT_plx "\n", addr);
>>> +
>>> + switch (addr & 0xffff) {
>>> + default:
>>> + val = 0;
>>> + break;
>>> + }
>>> + return val;
>>> +}
>>> +
>>> +static void sx_reg_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
>>> +{
>>> + //CG14State *s = opaque;
>>> +
>>> + printf("SX writeb %02x to reg " TARGET_FMT_plx "\n", val, addr);
>>> +
>>> + switch (addr & 0xffff) {
>>> + default:
>>> + break;
>>> + }
>>> +}
>>> +
>>> +static uint32_t sx_reg_readw(void *opaque, target_phys_addr_t addr)
>>> +{
>>> + //CG14State *s = opaque;
>>> + int val;
>>> +
>>> + printf("SX readw reg " TARGET_FMT_plx "\n", addr);
>>> +
>>> + switch (addr & 0xffff) {
>>> + default:
>>> + val = 0;
>>> + break;
>>> + }
>>> + return val;
>>> +}
>>> +
>>> +static void sx_reg_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
>>> +{
>>> + //CG14State *s = opaque;
>>> +
>>> + printf("SX writew %04x to reg " TARGET_FMT_plx "\n", val, addr);
>>> +
>>> + switch (addr & 0xffff) {
>>> + default:
>>> + break;
>>> + }
>>> +}
>>> +
>>> +static uint32_t sx_reg_readl(void *opaque, target_phys_addr_t addr)
>>> +{
>>> + //CG14State *s = opaque;
>>> + int val;
>>> +
>>> + printf("SX readl reg " TARGET_FMT_plx "\n", addr);
>>> +
>>> + switch (addr & 0xffff) {
>>> + default:
>>> + val = 0;
>>> + break;
>>> + }
>>> + return val;
>>> +}
>>> +
>>> +static void sx_reg_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
>>> +{
>>> + //CG14State *s = opaque;
>>> +
>>> + printf("SX writel %08x to reg " TARGET_FMT_plx "\n", val, addr);
>>> +
>>> + switch (addr & 0xffff) {
>>> + default:
>>> + break;
>>> + }
>>> +}
>>> +
>>> +static CPUReadMemoryFunc *sx_reg_read[3] = {
>>> + sx_reg_readb,
>>> + sx_reg_readw,
>>> + sx_reg_readl,
>>> +};
>>> +
>>> +static CPUWriteMemoryFunc *sx_reg_write[3] = {
>>> + sx_reg_writeb,
>>> + sx_reg_writew,
>>> + sx_reg_writel,
>>> +};
>>> +
>>> +/*********************/
>>> +
>>> +static uint32_t bad_mem_read(void *opaque, target_phys_addr_t addr)
>>> +{
>>> + printf("Bad read from " TARGET_FMT_plx "\n", addr);
>>> + //cpu_abort(cpu_single_env, "bad ram read access at " TARGET_FMT_plx "\n", addr);
>>> + return 0;
>>> +}
>>> +static void bad_mem_write(void *opaque, target_phys_addr_t addr, uint32_t val)
>>> +{
>>> + printf("Bad write of 0x%02x to " TARGET_FMT_plx "\n", val, addr);
>>> + //cpu_abort(cpu_single_env, "bad ram write access at " TARGET_FMT_plx "\n", addr);
>>> +}
>>> +static CPUReadMemoryFunc *bad_memr[3] = { bad_mem_read, bad_mem_read, bad_mem_read };
>>> +static CPUWriteMemoryFunc *bad_memw[3] = { bad_mem_write, bad_mem_write, bad_mem_write };
>>> +
>>> +void cg14_init(target_phys_addr_t ctrl_base, target_phys_addr_t vram_base,
>>> + uint32_t vram_size)
>>> +{
>>> +// DeviceState *dev;
>>> +// SysBusDevice *s;
>>> +
>>> +// dev = qdev_create(NULL, "SUNW,cg14");
>>> +// qdev_init(dev);
>>> +// s = sysbus_from_qdev(dev);
>>> +//}
>>> +
>>> +//static void cg14_init1(SysBusDevice *dev)
>>> +//{
>>> + CG14State *s;// = FROM_SYSBUS(CG14State, dev);
>>> + ram_addr_t vram_offset;
>>> + uint8_t *vram;
>>> + int ctrl_memory, vram_memory;
>>> + int sx_registers;
>>> + int bad_mem;
>>> +
>>> + s = qemu_mallocz(sizeof(CG14State));
>>> +
>>> + vram_offset = qemu_ram_alloc(vram_size);
>>> + vram = qemu_get_ram_ptr(vram_offset);
>>> +
>>> + s->vram = vram;
>>> + s->vram_amask = vram_size - 1;
>>> +
>>> + ctrl_memory = cpu_register_io_memory(cg14_reg_read, cg14_reg_write, s);
>>> + cpu_register_physical_memory_offset(ctrl_base, CG14_REG_SIZE, ctrl_memory, ctrl_base);
>>> +
>>> + vram_memory = cpu_register_io_memory(cg14_vram_read, cg14_vram_write, s);
>>> + cpu_register_physical_memory_offset(vram_base, CG14_VMEM_SLOTSIZE, vram_memory, vram_base);
>>> +
>>> + s->ds = graphic_console_init(cg14_update_display,
>>> + cg14_invalidate_display,
>>> + cg14_screen_dump, NULL, s);
>>> +
>>> + s->width = 640;
>>> + s->height = 480;
>>> + qemu_console_resize(s->ds, s->width, s->height);
>>> +
>>> + /* SX or SPAM (Sun Pixel Arithmetic Memory) */
>>> + sx_registers = cpu_register_io_memory(sx_reg_read, sx_reg_write, s);
>>> + cpu_register_physical_memory(0xf80000000ULL, 0x2000, sx_registers);
>>> +
>>> + bad_mem = cpu_register_io_memory(bad_memr, bad_memw, s);
>>> + /* missing vsimms */
>>> + cpu_register_physical_memory_offset(0x90000000, 0x2000, bad_mem, 0x90000000);
>>> + cpu_register_physical_memory_offset(0x94000000, 0x2000, bad_mem, 0x94000000);
>>> + cpu_register_physical_memory_offset(0x98000000, 0x2000, bad_mem, 0x98000000);
>>>
>> Can't we just have more VSIMMS? The empty_slot device may be useful here.
>>
Each VSIMM would have it's own monitor attached. Does Qemu and/or
OpenBIOS support multiple displays? I think the limit for a real SS-20
is 5 displays - 2 VSIMMs and 3 GX/TGX cards. I'll just go with
empty_slot for the extras.
>
> And btw, VSIMMs addresses may currently overlap with RAM. Maybe we
> should keep "SS-20" (and SS-10) compatible with original, and rename
> the current machine definition to "SS-20qemu" or SS-20-60G?
>
Well, the real machines are limited to 512M, so dropping the framebuffer
registers into the middle of the first 4G wasn't an issue back then. I
think the SX accelerator also limits the system and video memory to the
lower 4G of address space.
>>> + /* DBRI (audio) */
>>> + cpu_register_physical_memory_offset(0xEE0001000ULL, 0x10000, bad_mem, 0xE0001000);
>>>
>> Please add a new DBRI device ;-).
>>
>
> Or maybe just a field in hwdef + empty_slot? :-)
>
Yes, empty_slot should work fine. I was trying to hack in enough to get
it to boot, but no luck yet. The cpu models are still lacking - with
the SS-20 v2.25 rom, SuperSparc 61 fails before initializing the
display, SuperSparc 60 has a data access error when trying to boot, and
Ross 625 is mis-detected as an incompatible cpu type.
>>> +}
>>> +
>>> +/* save to file */
>>> +static void cg14_screen_dump(void *opaque, const char *filename)
>>> +{
>>> + CG14State *s = opaque;
>>> + FILE *f;
>>> + int y, pixmode, linesize;
>>> + void *buf;
>>> + uint8_t *pix;
>>> +
>>> + f = fopen(filename, "wb");
>>> + if (!f) {
>>> + return;
>>> + }
>>> + fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
>>> +
>>> + linesize = s->width * 3;
>>> + buf = qemu_mallocz(linesize);
>>> + pix = s->vram;
>>> +
>>> + switch (s->ctrl.mcr & MCR_PIXMODE_MASK) {
>>> + case MCR_PIXMODE_32:
>>> + pixmode = 32;
>>> + break;
>>> + case MCR_PIXMODE_16:
>>> + pixmode = 16;
>>> + break;
>>> + case MCR_PIXMODE_8:
>>> + default:
>>> + pixmode = 8;
>>> + break;
>>> + }
>>> +
>>> + for (y=0; y<s->height; y++) {
>>> + // cg14_draw_line24_bgr(s, buf, pix, pixmode);
>>> + fwrite(buf, 1, linesize, f);
>>> + pix += s->width * (pixmode / 8);
>>> + }
>>> +
>>> + qemu_free(buf);
>>> + fclose(f);
>>> +}
>>>
>>>
next prev parent reply other threads:[~2010-05-29 15:53 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-05-27 21:57 [Qemu-devel] cg14 Artyom Tarasenko
2010-05-28 7:54 ` Bob Breuer
2010-05-28 21:06 ` Blue Swirl
2010-05-28 22:48 ` Artyom Tarasenko
2010-05-29 5:15 ` Bob Breuer [this message]
2010-05-29 8:55 ` Blue Swirl
2010-07-13 16:26 ` Bob Breuer
2010-07-13 20:34 ` Artyom Tarasenko
2010-07-20 21:39 ` Blue Swirl
2010-05-29 13:26 ` Artyom Tarasenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4C00A302.3090409@mc.net \
--to=breuerr@mc.net \
--cc=atar4qemu@googlemail.com \
--cc=blauwirbel@gmail.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.