[Top][All Lists]
[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
- [Qemu-devel] [PATCH] SM501 emulation for R2D-SH4, Shin-ichiro KAWASAKI, 2008/11/01
- Re: [Qemu-devel] [PATCH] SM501 emulation for R2D-SH4,
andrzej zaborowski <=
- Re: [Qemu-devel] [PATCH] SM501 emulation for R2D-SH4, Blue Swirl, 2008/11/02
- Re: [Qemu-devel] [PATCH] SM501 emulation for R2D-SH4, Shin-ichiro KAWASAKI, 2008/11/04
- Re: [Qemu-devel] [PATCH] SM501 emulation for R2D-SH4, Blue Swirl, 2008/11/04
- [Qemu-devel] [PATCH] [RESEND] SM501 emulation for R2D-SH4, Shin-ichiro KAWASAKI, 2008/11/05
- Re: [Qemu-devel] [PATCH] [RESEND] SM501 emulation for R2D-SH4, Blue Swirl, 2008/11/05
- Re: [Qemu-devel] [PATCH] [RESEND] SM501 emulation for R2D-SH4, andrzej zaborowski, 2008/11/05
- Re: [Qemu-devel] [PATCH] [RESEND] SM501 emulation for R2D-SH4, Blue Swirl, 2008/11/05
[Qemu-devel] When should I use qemu_ram_alloc(), and how?, takasi-y, 2008/11/04