qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] SM501 emulation for R2D-SH4


From: andrzej zaborowski
Subject: Re: [Qemu-devel] [PATCH] SM501 emulation for R2D-SH4
Date: Sun, 2 Nov 2008 04:27:50 +0100

Hi,

2008/11/2 Shin-ichiro KAWASAKI <address@hidden>:
> This patch adds minimum emulation of SM501 multifunction device,
> whose main feature is 2D graphics.  It is one of the peripheral
> of R2D, the SH4 evaluation board.  We can see TUX printed on the
> QEMU console.
>
> Review on the patch and merging it to the trunk will be appreciated.
> I'm not sure about following two points.
>
>  - Register definitions were copied from Linux : include/linux/sm501-regs.h

I'd try to suck it into the .c file because the definitions are not
going to be used anywhere else in qemu.

>  - Function prototype is put into "into hw/devices.h".  Is it right place?

It's okay I think.

>
> Regards,
> Shin-ichiro KAWASAKI
>
> Signed-off-by: Shin-ichiro KAWASAKI <address@hidden>
>
> Index: trunk/Makefile.target
> ===================================================================
> --- trunk/Makefile.target       (revision 5594)
> +++ trunk/Makefile.target       (working copy)
> @@ -725,7 +725,7 @@
>  endif
>  ifeq ($(TARGET_BASE_ARCH), sh4)
>  OBJS+= shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
> -OBJS+= sh_timer.o ptimer.o sh_serial.o sh_intc.o
> +OBJS+= sh_timer.o ptimer.o sh_serial.o sh_intc.o sm501.o
>  endif
>  ifeq ($(TARGET_BASE_ARCH), m68k)
>  OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
> Index: trunk/hw/r2d.c
> ===================================================================
> --- trunk/hw/r2d.c      (revision 5594)
> +++ trunk/hw/r2d.c      (working copy)
> @@ -25,6 +25,7 @@
>
>  #include "hw.h"
>  #include "sh.h"
> +#include "devices.h"
>  #include "sysemu.h"
>  #include "boards.h"
>
> @@ -148,6 +149,7 @@
>     /* Register peripherals */
>     r2d_fpga_init(0x04000000);
>     s = sh7750_init(env);
> +    sm501_init(ds, 0x10000000, (8*1024*1024));
>     /* Todo: register on board registers */
>     {
>       int kernel_size;
> Index: trunk/hw/sm501.c
> ===================================================================
> --- trunk/hw/sm501.c    (revision 0)
> +++ trunk/hw/sm501.c    (revision 0)
> @@ -0,0 +1,702 @@
> +/*
> + * QEMU SM501 Device
> + *
> + * Copyright (c) 2008 Shin-ichiro KAWASAKI
> + *
> + * 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 <stdio.h>
> +#include <assert.h>
> +#include "hw.h"
> +#include "console.h"
> +#include "vga_int.h"

I think <vga_int.h> isn't needed?

> +#include "sm501-regs.h"
> +
> +/*
> + * Status: 2008/11/02
> + *   - Minimum implementation for Linux console : mmio regs and CRT layer.
> + *   - Always updates full screen.
> + *
> + * TODO:
> + *   - Panel support
> + *   - Hardware cursor support
> + *   - Touch panel support
> + *   - USB support
> + *   - UART support
> + *   - Performance tuning
> + */
> +
> +//#define DEBUG_SM501
> +//#define DEBUG_BITBLT
> +
> +#ifdef DEBUG_SM501
> +#define SM501_DPRINTF(fmt...) printf(fmt)
> +#else
> +#define SM501_DPRINTF(fmt...) do {} while(0)
> +#endif
> +
> +
> +#define MMIO_BASE_OFFSET 0x3e00000
> +
> +#define UART_RX_OFFSET  0x00
> +#define UART_TX_OFFSET  0x00
> +#define UART_IER_OFFSET 0x04
> +#define UART_IIR_OFFSET 0x08
> +#define UART_FCR_OFFSET 0x08
> +#define UART_LCR_OFFSET 0x0C
> +#define UART_MCR_OFFSET 0x10
> +#define UART_LSR_OFFSET 0x14
> +#define UART_MSR_OFFSET 0x18
> +#define UART_SCR_OFFSET 0x1C
> +
> +/* taken from "linux/drivers/mfd/sm501.c" */
> +static uint32_t sm501_mem_local_size[] = {
> +       [0]     = 4*1024*1024,
> +       [1]     = 8*1024*1024,
> +       [2]     = 16*1024*1024,
> +       [3]     = 32*1024*1024,
> +       [4]     = 64*1024*1024,
> +       [5]     = 2*1024*1024,
> +};
> +#define get_local_mem_size(s) sm501_mem_local_size[(s)->local_mem_size_index]
> +
> +typedef struct SM501State {
> +    /* graphic console status */
> +    DisplayState *ds;
> +    QEMUConsole *console;
> +
> +    /* status & internal resources */
> +    target_phys_addr_t base;
> +    uint32_t local_mem_size_index;
> +    uint8_t * local_mem;
> +    uint32_t last_width;
> +    uint32_t last_height;
> +
> +    /* mmio registers */
> +    uint32_t system_control;
> +    uint32_t misc_control;
> +    uint32_t gpio_31_0_control;
> +    uint32_t gpio_63_32_control;
> +    uint32_t dram_control;
> +    uint32_t irq_mask;
> +    uint32_t misc_timing;
> +    uint32_t power_mode_control;
> +
> +    uint32_t uart0_ier;
> +    uint32_t uart0_lcr;
> +    uint32_t uart0_mcr;
> +    uint32_t uart0_scr;
> +
> +    uint8_t dc_panel_palette[0x400];
> +    uint8_t dc_video_palette[0x400];
> +    uint8_t dc_crt_palette[0x400];
> +
> +    uint32_t dc_panel_control;
> +    uint32_t dc_panel_panning_control;
> +    uint32_t dc_panel_fb_addr;
> +    uint32_t dc_panel_fb_offset;
> +    uint32_t dc_panel_fb_width;
> +    uint32_t dc_panel_fb_height;
> +    uint32_t dc_panel_tl_location;
> +    uint32_t dc_panel_br_location;
> +    uint32_t dc_panel_h_total;
> +    uint32_t dc_panel_h_sync;
> +    uint32_t dc_panel_v_total;
> +    uint32_t dc_panel_v_sync;
> +
> +    uint32_t dc_panel_hwc_addr;
> +    uint32_t dc_panel_hwc_location;
> +    uint32_t dc_panel_hwc_color_1_2;
> +    uint32_t dc_panel_hwc_color_3;
> +
> +    uint32_t dc_crt_control;
> +    uint32_t dc_crt_fb_addr;
> +    uint32_t dc_crt_fb_offset;
> +    uint32_t dc_crt_h_total;
> +    uint32_t dc_crt_h_sync;
> +    uint32_t dc_crt_v_total;
> +    uint32_t dc_crt_v_sync;
> +
> +    uint32_t dc_crt_hwc_addr;
> +    uint32_t dc_crt_hwc_location;
> +    uint32_t dc_crt_hwc_color_1_2;
> +    uint32_t dc_crt_hwc_color_3;
> +
> +} SM501State;
> +
> +static uint32_t get_local_mem_size_index(uint32_t size)
> +{
> +    uint32_t norm_size = 0;
> +    int i, index = 0;
> +
> +    for (i = 0; i < sizeof(sm501_mem_local_size)/sizeof(uint32_t); i++) {
> +       uint32_t new_size = sm501_mem_local_size[i];
> +       if (new_size >= size) {
> +           if (norm_size == 0 || norm_size > new_size) {
> +               norm_size = new_size;
> +               index = i;
> +           }
> +       }
> +    }
> +
> +    return index;
> +}
> +
> +static uint32_t sm501_mmio_read(void *opaque, target_phys_addr_t addr)
> +{
> +    SM501State * s = (SM501State *)opaque;
> +    uint32_t offset = addr - (s->base + MMIO_BASE_OFFSET);
> +    uint32_t ret = 0;
> +    SM501_DPRINTF("sm501 read addr=%x, offset=%x\n", addr, offset);
> +
> +    if (SM501_DC + SM501_DC_PANEL_PALETTE <= offset
> +       && offset < SM501_DC + SM501_DC_VIDEO_PALETTE) {
> +       offset -= SM501_DC + SM501_DC_PANEL_PALETTE;
> +       /* TODO : consider BYTE/WORD access */
> +       /* TODO : consider endian */
> +       ret = *(uint32_t*)&s->dc_panel_palette[offset];
> +    } else if (SM501_DC + SM501_DC_VIDEO_PALETTE <= offset
> +              && offset < SM501_DC + SM501_DC_CRT_PALETTE) {
> +       offset -= SM501_DC + SM501_DC_VIDEO_PALETTE;
> +       /* TODO : consider BYTE/WORD access */
> +       /* TODO : consider endian */
> +       ret = *(uint32_t*)&s->dc_video_palette[offset];
> +    } else if (SM501_DC + SM501_DC_CRT_PALETTE <= offset
> +              && offset < SM501_DC + SM501_DC_CRT_PALETTE + 0x400) {
> +       offset -= SM501_DC + SM501_DC_CRT_PALETTE;
> +       /* TODO : consider BYTE/WORD access */
> +       /* TODO : consider endian */
> +       ret = *(uint32_t*)&s->dc_crt_palette[offset];
> +    } else {
> +       switch(offset) {
> +       case SM501_SYSTEM_CONTROL:
> +           ret = s->system_control;
> +           break;
> +       case SM501_MISC_CONTROL:
> +           ret = s->misc_control;
> +           break;
> +       case SM501_GPIO31_0_CONTROL:
> +           ret = s->gpio_31_0_control;
> +           break;
> +       case SM501_GPIO63_32_CONTROL:
> +           ret = s->gpio_63_32_control;
> +           break;
> +       case SM501_DEVICEID:
> +           ret = 0x050100A0;
> +           break;
> +       case SM501_DRAM_CONTROL:
> +           ret = (s->dram_control & 0x07F107C0)
> +             | s->local_mem_size_index << 13;
> +           break;
> +       case SM501_IRQ_MASK:
> +           ret = s->irq_mask;
> +           break;
> +       case SM501_MISC_TIMING:
> +           /* TODO : simulate gate control */
> +           ret = s->misc_timing;
> +           break;
> +       case SM501_CURRENT_GATE:
> +           /* TODO : simulate gate control */
> +           ret = 0x00021807;
> +           break;
> +       case SM501_CURRENT_CLOCK:
> +           ret = 0x2A1A0A09;
> +           break;
> +       case SM501_POWER_MODE_CONTROL:
> +           ret = s->power_mode_control;
> +           break;
> +
> +       /* TODO : implement SM501 UART */
> +       case SM501_UART0 + UART_RX_OFFSET:
> +           ret = 0;
> +           break;
> +       case SM501_UART0 + UART_IER_OFFSET:
> +           ret = s->uart0_ier;
> +           break;
> +       case SM501_UART0 + UART_IIR_OFFSET:
> +           ret = 0x01;
> +           break;
> +       case SM501_UART0 + UART_LCR_OFFSET:
> +           ret = s->uart0_lcr;
> +           break;
> +       case SM501_UART0 + UART_MCR_OFFSET:
> +           ret = s->uart0_mcr;
> +           break;
> +       case SM501_UART0 + UART_SCR_OFFSET:
> +           ret = s->uart0_scr;
> +           break;
> +
> +       case SM501_DC + SM501_DC_PANEL_CONTROL:
> +           ret = s->dc_panel_control;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_PANNING_CONTROL:
> +           ret = s->dc_panel_panning_control;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_FB_ADDR:
> +           ret = s->dc_panel_fb_addr;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_FB_OFFSET:
> +           ret = s->dc_panel_fb_offset;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_FB_WIDTH:
> +           ret = s->dc_panel_fb_width;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_FB_HEIGHT:
> +           ret = s->dc_panel_fb_height;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_TL_LOC:
> +           ret = s->dc_panel_tl_location;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_BR_LOC:
> +           ret = s->dc_panel_br_location;
> +           break;
> +
> +       case SM501_DC + SM501_DC_PANEL_H_TOT:
> +           ret = s->dc_panel_h_total;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_H_SYNC:
> +           ret = s->dc_panel_h_sync;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_V_TOT:
> +           ret = s->dc_panel_v_total;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_V_SYNC:
> +           ret = s->dc_panel_v_sync;
> +           break;
> +
> +       case SM501_DC + SM501_DC_CRT_CONTROL:
> +           ret = s->dc_crt_control;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_FB_ADDR:
> +           ret = s->dc_crt_fb_addr;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_FB_OFFSET:
> +           ret = s->dc_crt_fb_offset;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_H_TOT:
> +           ret = s->dc_crt_h_total;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_H_SYNC:
> +           ret = s->dc_crt_h_sync;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_V_TOT:
> +           ret = s->dc_crt_v_total;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_V_SYNC:
> +           ret = s->dc_crt_v_sync;
> +           break;
> +
> +       case SM501_DC + SM501_DC_CRT_HWC_ADDR:
> +           ret = s->dc_crt_hwc_addr;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_HWC_LOC:
> +           ret = s->dc_crt_hwc_addr;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_HWC_COLOR_1_2:
> +           ret = s->dc_crt_hwc_addr;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_HWC_COLOR_3:
> +           ret = s->dc_crt_hwc_addr;
> +           break;
> +
> +       default:
> +           printf("sm501 not implement read addr=%x, offset=%x\n",
> +                  addr, offset);
> +           assert(0);
> +       }
> +    }
> +    return ret;
> +}
> +
> +static uint32_t sm501_mmio_readb(void *opaque, target_phys_addr_t addr)
> +{
> +    return sm501_mmio_read(opaque, addr);
> +}
> +
> +static uint32_t sm501_mmio_readw(void *opaque, target_phys_addr_t addr)
> +{
> +    return sm501_mmio_read(opaque, addr);
> +}
> +
> +static uint32_t sm501_mmio_readl(void *opaque, target_phys_addr_t addr)
> +{
> +    return sm501_mmio_read(opaque, addr);
> +}
> +
> +static void sm501_mmio_write(void *opaque,
> +                            target_phys_addr_t addr, uint32_t value)
> +{
> +    SM501State * s = (SM501State *)opaque;
> +    uint32_t offset = addr - (s->base + MMIO_BASE_OFFSET);
> +    SM501_DPRINTF("sm501 write addr=%x, ofs=%x, val=%x\n",
> +                 addr, offset, value);
> +
> +    if (SM501_DC + SM501_DC_PANEL_PALETTE <= offset
> +       && offset < SM501_DC + SM501_DC_VIDEO_PALETTE) {
> +       offset -= SM501_DC + SM501_DC_PANEL_PALETTE;
> +       /* TODO : consider BYTE/WORD access */
> +       /* TODO : consider endian */
> +       *(uint32_t*)&s->dc_panel_palette[offset] = value;
> +    } else if (SM501_DC + SM501_DC_VIDEO_PALETTE <= offset
> +       && offset < SM501_DC + SM501_DC_CRT_PALETTE) {
> +       offset -= SM501_DC + SM501_DC_VIDEO_PALETTE;
> +       /* TODO : consider BYTE/WORD access */
> +       /* TODO : consider endian */
> +       *(uint32_t*)&s->dc_video_palette[offset] = value;
> +    } else if (SM501_DC + SM501_DC_CRT_PALETTE <= offset
> +       && offset < SM501_DC + SM501_DC_CRT_PALETTE + 0x400) {
> +       offset -= SM501_DC + SM501_DC_CRT_PALETTE;
> +       /* TODO : consider BYTE/WORD access */
> +       /* TODO : consider endian */
> +       *(uint32_t*)&s->dc_crt_palette[offset] = value;
> +    } else {
> +       switch(offset) {
> +       case SM501_SYSTEM_CONTROL:
> +           s->system_control = value & 0xE300B8F7;
> +           break;
> +       case SM501_MISC_CONTROL:
> +           s->misc_control = value & 0xFF7FFF20;
> +           break;
> +       case SM501_GPIO31_0_CONTROL:
> +           s->gpio_31_0_control = value;
> +           break;
> +       case SM501_GPIO63_32_CONTROL:
> +           s->gpio_63_32_control = value;
> +           break;
> +       case SM501_DRAM_CONTROL:
> +           s->local_mem_size_index = (value >> 13) & 0x7;
> +           /* TODO : check validity of size change */
> +           s->dram_control |=  value & 0x7FFFFFC3;
> +           break;
> +       case SM501_IRQ_MASK:
> +           s->irq_mask = value;
> +           break;
> +       case SM501_MISC_TIMING:
> +           s->misc_timing = value & 0xF31F1FFF;
> +           break;
> +       case SM501_POWER_MODE_0_GATE:
> +       case SM501_POWER_MODE_1_GATE:
> +       case SM501_POWER_MODE_0_CLOCK:
> +       case SM501_POWER_MODE_1_CLOCK:
> +           /* TODO : simulate gate & clock control */
> +           break;
> +       case SM501_POWER_MODE_CONTROL:
> +           s->power_mode_control = value & 0x00000003;
> +           break;
> +
> +       /* TODO : implement SM501 UART */
> +       case SM501_UART0 + UART_IER_OFFSET:
> +           s->uart0_ier = value & 0xef;
> +           break;
> +       case SM501_UART0 + UART_FCR_OFFSET:
> +           /* throw it away */
> +           break;
> +       case SM501_UART0 + UART_LCR_OFFSET:
> +           s->uart0_lcr = value & 0xff;
> +           break;
> +       case SM501_UART0 + UART_MCR_OFFSET:
> +           s->uart0_mcr = value & 0x5f;
> +           break;
> +       case SM501_UART0 + UART_SCR_OFFSET:
> +           s->uart0_scr = value & 0xff;
> +           break;
> +
> +       case SM501_DC + SM501_DC_PANEL_CONTROL:
> +           s->dc_panel_control = value & 0x0FFF73FF;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_PANNING_CONTROL:
> +           s->dc_panel_panning_control = value & 0xFF3FFF3F;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_FB_ADDR:
> +           s->dc_panel_fb_addr = value & 0x8FFFFFF0;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_FB_OFFSET:
> +           s->dc_panel_fb_offset = value & 0x3FF03FF0;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_FB_WIDTH:
> +           s->dc_panel_fb_width = value & 0x0FFF0FFF;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_FB_HEIGHT:
> +           s->dc_panel_fb_height = value & 0x0FFF0FFF;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_TL_LOC:
> +           s->dc_panel_tl_location = value & 0x07FF07FF;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_BR_LOC:
> +           s->dc_panel_br_location = value & 0x07FF07FF;
> +           break;
> +
> +       case SM501_DC + SM501_DC_PANEL_H_TOT:
> +           s->dc_panel_h_total = value & 0x0FFF0FFF;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_H_SYNC:
> +           s->dc_panel_h_sync = value & 0x00FF0FFF;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_V_TOT:
> +           s->dc_panel_v_total = value & 0x0FFF0FFF;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_V_SYNC:
> +           s->dc_panel_v_sync = value & 0x003F0FFF;
> +           break;
> +
> +       case SM501_DC + SM501_DC_PANEL_HWC_ADDR:
> +           s->dc_panel_hwc_addr = value & 0x8FFFFFF0;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_HWC_LOC:
> +           s->dc_panel_hwc_addr = value & 0x0FFF0FFF;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_HWC_COLOR_1_2:
> +           s->dc_panel_hwc_addr = value;
> +           break;
> +       case SM501_DC + SM501_DC_PANEL_HWC_COLOR_3:
> +           s->dc_panel_hwc_addr = value & 0x0000FFFF;
> +           break;
> +
> +       case SM501_DC + SM501_DC_CRT_CONTROL:
> +           s->dc_crt_control = value & 0x0003FFFF;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_FB_ADDR:
> +           s->dc_crt_fb_addr = value & 0x8FFFFFF0;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_FB_OFFSET:
> +           s->dc_crt_fb_offset = value & 0x3FF03FF0;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_H_TOT:
> +           s->dc_crt_h_total = value & 0x0FFF0FFF;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_H_SYNC:
> +           s->dc_crt_h_sync = value & 0x00FF0FFF;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_V_TOT:
> +           s->dc_crt_v_total = value & 0x0FFF0FFF;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_V_SYNC:
> +           s->dc_crt_v_sync = value & 0x003F0FFF;
> +           break;
> +
> +       case SM501_DC + SM501_DC_CRT_HWC_ADDR:
> +           s->dc_crt_hwc_addr = value & 0x8FFFFFF0;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_HWC_LOC:
> +           s->dc_crt_hwc_addr = value & 0x0FFF0FFF;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_HWC_COLOR_1_2:
> +           s->dc_crt_hwc_addr = value;
> +           break;
> +       case SM501_DC + SM501_DC_CRT_HWC_COLOR_3:
> +           s->dc_crt_hwc_addr = value & 0x0000FFFF;
> +           break;
> +
> +       default:
> +           printf("sm501 not implement write addr=%x, val=%x\n",
> +                  addr, value);
> +           assert(0);
> +       }
> +    }
> +}
> +
> +static void sm501_mmio_writeb(void *opaque,
> +                             target_phys_addr_t addr, uint32_t value)
> +{
> +    sm501_mmio_write(opaque, addr, value);
> +}
> +
> +static void sm501_mmio_writew(void *opaque,
> +                             target_phys_addr_t addr, uint32_t value)
> +{
> +    sm501_mmio_write(opaque, addr, value);
> +}
> +
> +static void sm501_mmio_writel(void *opaque,
> +                             target_phys_addr_t addr, uint32_t value)
> +{
> +    sm501_mmio_write(opaque, addr, value);
> +}
> +
> +static CPUReadMemoryFunc *sm501_mmio_readfn[] = {
> +    &sm501_mmio_readb,
> +    &sm501_mmio_readw,
> +    &sm501_mmio_readl,
> +};
> +
> +static CPUWriteMemoryFunc *sm501_mmio_writefn[] = {
> +    &sm501_mmio_writeb,
> +    &sm501_mmio_writew,
> +    &sm501_mmio_writel,
> +};
> +
> +static uint32_t sm501_lm_read(void *opaque, target_phys_addr_t addr)
> +{
> +    SM501State * s = (SM501State *)opaque;
> +    uint32_t offset = addr - s->base;
> +    return *(uint32_t*)&s->local_mem[offset];
> +}
> +
> +static uint32_t sm501_lm_readb(void *opaque, target_phys_addr_t addr)
> +{
> +    return sm501_lm_read(opaque, addr);
> +}
> +
> +static uint32_t sm501_lm_readw(void *opaque, target_phys_addr_t addr)
> +{
> +    return sm501_lm_read(opaque, addr);
> +}
> +
> +static uint32_t sm501_lm_readl(void *opaque, target_phys_addr_t addr)
> +{
> +    return sm501_lm_read(opaque, addr);
> +}
> +
> +static void sm501_lm_write(void *opaque,
> +                          target_phys_addr_t addr, uint32_t value)
> +{
> +    SM501State * s = (SM501State *)opaque;
> +    uint32_t offset = addr - s->base;
> +    *(uint32_t*)&s->local_mem[offset] = value;
> +}
> +
> +static void sm501_lm_writeb(void *opaque,
> +                             target_phys_addr_t addr, uint32_t value)
> +{
> +    sm501_lm_write(opaque, addr, value);
> +}
> +
> +static void sm501_lm_writew(void *opaque,
> +                             target_phys_addr_t addr, uint32_t value)
> +{
> +    sm501_lm_write(opaque, addr, value);
> +}
> +
> +static void sm501_lm_writel(void *opaque,
> +                             target_phys_addr_t addr, uint32_t value)
> +{
> +    sm501_lm_write(opaque, addr, value);
> +}
> +
> +static CPUReadMemoryFunc *sm501_lm_readfn[] = {
> +    &sm501_lm_readb,
> +    &sm501_lm_readw,
> +    &sm501_lm_readl,
> +};
> +
> +static CPUWriteMemoryFunc *sm501_lm_writefn[] = {
> +    &sm501_lm_writeb,
> +    &sm501_lm_writew,
> +    &sm501_lm_writel,
> +};
> +
> +static void sm501_draw_crt(SM501State * s)
> +{
> +    int x, y;
> +    uint32_t crt_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
> +    uint32_t crt_height = (s->dc_crt_v_total & 0x00000FFF) + 1;
> +    uint8_t  * buf = s->local_mem;
> +    uint32_t * palette = (uint32_t *)s->dc_crt_palette;
> +
> +    /* adjust console size */
> +    if (s->last_width != crt_width || s->last_height != crt_height) {
> +       qemu_console_resize(s->console, crt_width, crt_height);
> +       s->last_width = crt_width;
> +       s->last_height = crt_height;
> +    }
> +
> +    switch (s->dc_crt_control & 3) {
> +    case SM501_DC_CRT_CONTROL_8BPP:
> +       for (y = 0; y < crt_height; y++) {
> +           for (x = 0; x < crt_width; x++) {
> +               int i = (y * crt_width + x) * 4;
> +               *(uint32_t *)&s->ds->data[i] = palette[*buf];
> +               buf++;
> +           }
> +       }
> +       break;
> +    case SM501_DC_CRT_CONTROL_16BPP:
> +       for (y = 0; y < crt_height; y++) {
> +           for (x = 0; x < crt_width; x++) {
> +               int i = (y * crt_width + x) * 4;
> +               uint32_t rgb565 = *(uint16_t*)buf;
> +               int r = ((rgb565 >> 11) & 0x1f) << 3;
> +               int g = ((rgb565 >>  5) & 0x3f) << 2;
> +               int b = ((rgb565 >>  0) & 0x1f) << 3;
> +               s->ds->data[i + 0] = b;
> +               s->ds->data[i + 1] = g;
> +               s->ds->data[i + 2] = r;
> +               s->ds->data[i + 3] = 0;
> +               buf += 2;
> +           }
> +       }
> +       break;
> +    case SM501_DC_CRT_CONTROL_32BPP:
> +       for (y = 0; y < crt_height; y++) {
> +           for (x = 0; x < crt_width; x++) {
> +               int i = (y * crt_width + x) * 4;
> +               *(uint32_t *)&s->ds->data[i] = *(uint32_t*)buf;
> +               buf += 4;
> +           }
> +       }
> +       break;

All the cases assume the host is using 32 bpp colours, which is rare I
think.  Because s->ds->depth is not checked, it will likely segfault.

Cheers




reply via email to

[Prev in Thread] Current Thread [Next in Thread]