From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1KwTd3-0003E9-MQ for qemu-devel@nongnu.org; Sat, 01 Nov 2008 23:27:53 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1KwTd2-0003Dv-Sv for qemu-devel@nongnu.org; Sat, 01 Nov 2008 23:27:53 -0400 Received: from [199.232.76.173] (port=52368 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KwTd2-0003Ds-Lw for qemu-devel@nongnu.org; Sat, 01 Nov 2008 23:27:52 -0400 Received: from rv-out-0708.google.com ([209.85.198.250]:20522) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1KwTd2-0008Oh-5u for qemu-devel@nongnu.org; Sat, 01 Nov 2008 23:27:52 -0400 Received: by rv-out-0708.google.com with SMTP id f25so1770785rvb.22 for ; Sat, 01 Nov 2008 20:27:50 -0700 (PDT) Message-ID: Date: Sun, 2 Nov 2008 04:27:50 +0100 From: "andrzej zaborowski" Subject: Re: [Qemu-devel] [PATCH] SM501 emulation for R2D-SH4 In-Reply-To: <490D0C8F.9010601@juno.dti.ne.jp> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit Content-Disposition: inline References: <490D0C8F.9010601@juno.dti.ne.jp> Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Hi, 2008/11/2 Shin-ichiro KAWASAKI : > 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 > > 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 > +#include > +#include "hw.h" > +#include "console.h" > +#include "vga_int.h" I think 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