2010/5/29 Bob Breuer <breu...@mc.net>: > Artyom Tarasenko wrote: >> 2010/5/28 Blue Swirl <blauwir...@gmail.com>: >> >>> On Fri, May 28, 2010 at 7:54 AM, Bob Breuer <breu...@mc.net> wrote: >>> >>>> Artyom Tarasenko wrote: >>>> >>>>> 2010/5/27 Bob Breuer <breu...@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.
The few SS-10 OBP versions I have probe for VSIMMs. So we need to put either empty_slot (when the -nographics option is used) or VSIMMs there. > 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. I have a trivial hack which allows booting. It wasn't interesting before, but now it is, cause with the hack Solaris 2.3 - 2.5.1 can be started in a single user mode. Didn't check the multi-user yet. Will submit the patch. > 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. Yes, one MXCC register is missing in qemu SuperSPARCs with MXCC. So, I prefer using CPUs without MXCC: "Ross RT620" and "TI SuperSparc 50". -- Regards, Artyom Tarasenko solaris/sparc under qemu blog: http://tyom.blogspot.com/