SM501 emulation for R2D-SH4
PATCH 1/1 SM501 emulation for R2D-SH4
Hi, all!
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
- Function prototype is put into "into hw/devices.h". Is it right place?
Regards,
Shin-ichiro KAWASAKI
Makefile.target +1 -1
@@ -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
hw/r2d.c +2 -0
@@ -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;
hw/sm501.c +702 -0
702 lines not on this page · raw message
hw/sm501-regs.h +386 -0
386 lines not on this page · raw message
hw/devices.h +3 -0
@@ -71,4 +71,7 @@ qemu_irq handler);qemu_irq *tc6393xb_gpio_in_get (struct tc6393xb_s *s); +/* sm501.c */ +void sm501_init (DisplayState *ds,uint32_t base,uint32_t local_mem_bytes); +#endif
Hi,
2008/11/2 Shin-ichiro KAWASAKI <[email protected]>:
Quoted 9 lines
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.
Quoted 1 line
- Function prototype is put into "into
hw/devices.h". Is it right place?
It's okay I think.
Quoted 63 lines
Regards,
Shin-ichiro KAWASAKISigned-off-by Shin-ichiro KAWASAKI <[email protected]>Index: trunk/Makefile.target
===================================================================Makefile.target (working copy) renamed from Makefile.target (revision 5594) +1
-1@@ -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.oIndex:
trunk/hw/r2d.c
===================================================================hw/r2d.c (working copy) renamed from hw/r2d.c (revision 5594) +2
-0@@ -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
===================================================================hw/sm501.c (revision 0) +19
-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
hw/sm501.c (revision 0) line 29
Quoted 10 lines
hw/sm501.c (revision 0) +10
-0+ * 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?
Quoted 615 lines
hw/sm501.c (revision 0) +615
-0+#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; + } + }
hw/sm501.c (revision 0) line 654
Quoted 10 lines
hw/sm501.c (revision 0) +10
-0+ 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
Thank you for your review!
Quoted 6 lines
Quoted 3 lines
I'm not sure about following two points.
- Register definitions were copied from Linux :
include/linux/sm501-regs.hI'd try to suck it into the .c file because the definitions are not going to be used anywhere else in qemu.
OK. I'll include it in sm501.c.
Quoted 3 lines
Quoted 1 line
+#include "
vga_int.h"I think <
vga_int.h> isn't needed?
Right. Will be deleted.
Quoted 45 lines
Quoted 45 lines
hw/sm501.c +45
-0+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 ;
Quoted 8 lines
hw/sm501.c line 654
Quoted 5 lines
hw/sm501.c +5
-0+ *(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->depthis not checked, it will likely segfault.
Right. I will introduce templates like hw/vga_template.h to fit s->ds->depth variety.
Thanks!
Shin-ichiro KAWASAKI
Quoted 7 lines · Shin-ichiro KAWASAKI
Hi, all!
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.
Quoted 10 lines
+#define
UART_RX_OFFSET0x00
+#defineUART_TX_OFFSET0x00
+#defineUART_IER_OFFSET0x04
+#defineUART_IIR_OFFSET0x08
+#defineUART_FCR_OFFSET0x08
+#defineUART_LCR_OFFSET0x0C
+#defineUART_MCR_OFFSET0x10
+#defineUART_LSR_OFFSET0x14
+#defineUART_MSR_OFFSET0x18
+#defineUART_SCR_OFFSET0x1C
Looks like standard 16550-like UART. Maybe you could use the version in serial.c and map that to this location?
Quoted 2 lines
+/* taken from "
linux/drivers/mfd/sm501.c" */
+staticuint32_tsm501_mem_local_size[] = {
"const"?
Quoted 18 lines
+ 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];
Quoted 1 line
+ } else {
The above should be cleaner and faster if you registered different access routines for each area.
Quoted 6 lines
+static
uint32_tsm501_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];+}
It would be much faster to register normal RAM for this area and check for updated pages asynchronously using VGA_DIRTY_FLAG (see vga.c or tcx.c).
Quoted 2 lines
+ /* allocate local memory */
+s->local_mem= qemu_mallocz(get_local_mem_size(s));
The display buffer should be allocated using machine definition .ram_require.
Thank you for reviewing!
I add the new version of patch to this mail, which reflects you and andrzej's comments. Some more comments on it will be appreciated. Especially advice on VRAM implementation with normal RAM will be useful for me.
Quoted 11 lines
Quoted 10 lines
+#define
UART_RX_OFFSET0x00
+#defineUART_TX_OFFSET0x00
+#defineUART_IER_OFFSET0x04
+#defineUART_IIR_OFFSET0x08
+#defineUART_FCR_OFFSET0x08
+#defineUART_LCR_OFFSET0x0C
+#defineUART_MCR_OFFSET0x10
+#defineUART_LSR_OFFSET0x14
+#defineUART_MSR_OFFSET0x18
+#defineUART_SCR_OFFSET0x1C
Quoted 2 lines
Looks like standard 16550-like UART. Maybe you could use the version in
serial.cand map that to this location?
Right, I did so in the new patch.
Quoted 4 lines
Quoted 2 lines
+/* taken from "
linux/drivers/mfd/sm501.c" */
+staticuint32_tsm501_mem_local_size[] = {"const"?
It should be.
Quoted 20 lines
Quoted 18 lines
+ 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];Quoted 1 line
+ } else {
Quoted 2 lines
The above should be cleaner and faster if you registered different access routines for each area.
Right. I divided SM501 registers into some parts and registered each of them. To say it correctly about the palettes, I merged these three palettes into one memory region to avoid messy codes.
Quoted 10 lines
Quoted 6 lines
+static
uint32_tsm501_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];+}
It would be much faster to register normal RAM for this area and check for updated pages asynchronously using
VGA_DIRTY_FLAG(seevga.cortcx.c).
Thanks for the advice, but following problem blocks to realize it.
Quoted 4 lines
Quoted 2 lines
+ /* allocate local memory */
+s->local_mem= qemu_mallocz(get_local_mem_size(s));The display buffer should be allocated using machine definition .ram_require.
I tried normal RAM implementation : "#define USE_NORMAL_RAM" in the patch will turn the new implementation on. But it causes system hang during SH-Linux boot up. The initial VRAM clearance seems to cause the hang.
The reason might be my wrong implementation, or any MMU problem of SH4.
I did,
- added VRAM size to .ram_require
- invoked qemu_ram_alloc() with the VRAM size parameter,
- and invoked cpu_register_physical_memory(), passing the return value of qemu_ram_alloc() as third parameter.
Is this sequence correct?
Regards,
Shin-ichiro KAWASAKI
Makefile.target +0 -0
@@ -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 serial.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
hw/r2d.c +0 -0
@@ -25,12 +25,15 @@
#include "hw.h"
#include "sh.h"
+#include "devices.h"
#include "sysemu.h"
#include "boards.h"
#define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */ #define SDRAM_SIZE 0x04000000
+#define SM501_VRAM_SIZE 0x800000
+
#define PA_POWOFF 0x30
#define PA_VERREG 0x32
#define PA_OUTPORT 0x36
@@ -133,6 +136,7 @@
{
CPUState *env;
struct SH7750State *s;+ ram_addr_t sm501_vga_ram_addr;
if (!cpu_model)
cpu_model = "SH7751R";
@@ -148,6 +152,9 @@
/* Register peripherals */
r2d_fpga_init(0x04000000);
s = sh7750_init(env);
+ sm501_vga_ram_addr = qemu_ram_alloc(SM501_VRAM_SIZE);
+ sm501_init(ds, 0x10000000, sm501_vga_ram_addr, SM501_VRAM_SIZE,
+ serial_hds[2]);
/* Todo: register on board registers */
{
int kernel_size;
@@ -167,5 +174,5 @@
.name = "r2d",
.desc = "r2d-plus board",
.init = r2d_init,- .ram_require = SDRAM_SIZE | RAMSIZE_FIXED,
+ .ram_require = (SDRAM_SIZE + SM501_VRAM_SIZE) | RAMSIZE_FIXED,
};
hw/sm501.c +1164 -0
1,164 lines not on this page · raw message
hw/sm501_template.h +99 -0
99 lines not on this page · raw message
hw/devices.h +0 -0
@@ -71,4 +71,7 @@ qemu_irq handler);
qemu_irq *tc6393xb_gpio_in_get(struct tc6393xb_s *s);
+/* sm501.c */
+void sm501_init(DisplayState *ds, uint32_t base, unsigned long local_mem_base,
+ uint32_t local_mem_bytes, CharDriverState *chr);
#endif
Quoted 17 lines · Shin-ichiro KAWASAKI
Thank you for reviewing!
I add the new version of patch to this mail, which reflects you and andrzej's comments. Some more comments on it will be appreciated. Especially advice on VRAM implementation with normal RAM will be useful for me.
Quoted 1 line
The display buffer should be allocated using machine definition
.ram_require.
Quoted 1 line
I tried normal RAM implementation : "#define
USE_NORMAL_RAM" in the patch
will
turn the new implementation on. But it causes system hang during SH-Linux
boot up.
The initial VRAM clearance seems to cause the hang.
The reason might be my wrong implementation, or any MMU problem of SH4.
Quoted 8 lines
I did,
- added VRAM size to .ram_require
- invokedqemu_ram_alloc()with the VRAM size parameter,
- and invokedcpu_register_physical_memory(), passing the
return value of
qemu_ram_alloc()as third parameter.Is this sequence correct?
Yes, but the system RAM is not allocated using qemu_ram_alloc. Now qemu_ram_alloc gives the same area (0 to VRAM_SIZE) the second time.
So the following:
/* Allocate memory space */
cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, 0);
should be changed to:
ram_addr = qemu_ram_alloc(SDRAM_SIZE);
cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, ram_addr);Maybe that helps?
PATCH RESEND 1/1 SM501 emulation for R2D-SH4
Quoted 28 lines · Blue Swirl
Quoted 15 lines · Shin-ichiro KAWASAKI
Thank you for reviewing!
I add the new version of patch to this mail, which reflects you and andrzej's comments. Some more comments on it will be appreciated. Especially advice on VRAM implementation with normal RAM will be useful for me.
Quoted 1 line
The display buffer should be allocated using machine definition
.ram_require.
I tried normal RAM implementation : "#defineUSE_NORMAL_RAM" in the patch
will
turn the new implementation on. But it causes system hang during SH-Linux
boot up.
The initial VRAM clearance seems to cause the hang.
The reason might be my wrong implementation, or any MMU problem of SH4.Quoted 8 lines
I did,
- added VRAM size to .ram_require
- invokedqemu_ram_alloc()with the VRAM size parameter,
- and invokedcpu_register_physical_memory(), passing the
return value of
qemu_ram_alloc()as third parameter.Is this sequence correct?
Yes, but the system RAM is not allocated using
qemu_ram_alloc. Nowqemu_ram_allocgives the same area (0 toVRAM_SIZE) the second time.
Quoted 8 lines
So the following:
/* Allocate memory space */ cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, 0); should be changed to: ram_addr = qemu_ram_alloc(SDRAM_SIZE); cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, ram_addr);Maybe that helps?
Yes, it helps. Thank you!
Here's the new patch which uses normal RAM as the VRAM, and checks VGA_DIRTY_FLAG for partial update.
I think it is ready for merge to the trunk.
Could anyone help it?
Regards,
Shin-ichiro KAWASAKI
Makefile.target +0 -0
@@ -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 serial.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
hw/r2d.c +0 -0
@@ -25,12 +25,15 @@
#include "hw.h"
#include "sh.h"
+#include "devices.h"
#include "sysemu.h"
#include "boards.h"
#define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */ #define SDRAM_SIZE 0x04000000
+#define SM501_VRAM_SIZE 0x800000
+
#define PA_POWOFF 0x30
#define PA_VERREG 0x32
#define PA_OUTPORT 0x36
@@ -133,6 +136,7 @@
{
CPUState *env;
struct SH7750State *s;+ ram_addr_t sdram_addr, sm501_vga_ram_addr;
if (!cpu_model)
cpu_model = "SH7751R";
@@ -144,10 +148,14 @@
}
/* Allocate memory space */
- cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, 0);
+ sdram_addr = qemu_ram_alloc(SDRAM_SIZE);
+ cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, sdram_addr);
/* Register peripherals */
r2d_fpga_init(0x04000000);
s = sh7750_init(env);
+ sm501_vga_ram_addr = qemu_ram_alloc(SM501_VRAM_SIZE);
+ sm501_init(ds, 0x10000000, sm501_vga_ram_addr, SM501_VRAM_SIZE,
+ serial_hds[2]);
/* Todo: register on board registers */
{
int kernel_size;
@@ -167,5 +175,5 @@
.name = "r2d",
.desc = "r2d-plus board",
.init = r2d_init,- .ram_require = SDRAM_SIZE | RAMSIZE_FIXED,
+ .ram_require = (SDRAM_SIZE + SM501_VRAM_SIZE) | RAMSIZE_FIXED,
};
hw/sm501.c +1129 -0
1,129 lines not on this page · raw message
hw/sm501_template.h +104 -0
104 lines not on this page · raw message
hw/devices.h +0 -0
@@ -71,4 +71,7 @@ qemu_irq handler);
qemu_irq *tc6393xb_gpio_in_get(struct tc6393xb_s *s);
+/* sm501.c */
+void sm501_init(DisplayState *ds, uint32_t base, unsigned long local_mem_base,
+ uint32_t local_mem_bytes, CharDriverState *chr);
#endif
Quoted 49 lines · Shin-ichiro KAWASAKI
Quoted 9 lines · Blue Swirl
Quoted 7 lines · Shin-ichiro KAWASAKI
Thank you for reviewing!
I add the new version of patch to this mail, which reflects you and andrzej's comments. Some more comments on it will be appreciated. Especially advice on VRAM implementation with normal RAM will be useful for me.
Quoted 4 lines
Quoted 4 lines
Quoted 2 lines
The display buffer should be allocated using machine definition
.ram_require.
I tried normal RAM implementation : "#defineUSE_NORMAL_RAM" in thepatch
Quoted 2 lines
Quoted 2 lines
will
turn the new implementation on. But it causes system hang duringSH-Linux
Quoted 8 lines
Quoted 8 lines
boot up.
The initial VRAM clearance seems to cause the hang.
The reason might be my wrong implementation, or any MMU problem of SH4.I did,
- added VRAM size to .ram_require
- invokedqemu_ram_alloc()with the VRAM size parameter,
- and invokedcpu_register_physical_memory(), passingthe
Quoted 6 lines
Quoted 5 lines
return value of
qemu_ram_alloc()as third parameter.Is this sequence correct?
Quoted 6 lines
Yes, but the system RAM is not allocated using
qemu_ram_alloc. Nowqemu_ram_allocgives the same area (0 toVRAM_SIZE) the second time.So the following:
/* Allocate memory space */ cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE,0);
Quoted 3 lines
should be changed to:
ram_addr = qemu_ram_alloc(SDRAM_SIZE); cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE,
ram_addr);Quoted 3 lines
Maybe that helps?
Quoted 7 lines
Yes, it helps. Thank you!
Here's the new patch which uses normal RAM as the VRAM, and checks
VGA_DIRTY_FLAGfor partial update.I think it is ready for merge to the trunk.
Could anyone help it?
Looks good to me. What about you, Andrzej?
2008/11/5 Blue Swirl <[email protected]>:
Quoted 52 lines · Shin-ichiro KAWASAKI
Quoted 51 lines
Quoted 9 lines · Blue Swirl
Quoted 7 lines · Shin-ichiro KAWASAKI
Thank you for reviewing!
I add the new version of patch to this mail, which reflects you and andrzej's comments. Some more comments on it will be appreciated. Especially advice on VRAM implementation with normal RAM will be useful for me.
Quoted 4 lines
Quoted 4 lines
Quoted 2 lines
The display buffer should be allocated using machine definition
.ram_require.
I tried normal RAM implementation : "#defineUSE_NORMAL_RAM" in thepatch
Quoted 2 lines
Quoted 2 lines
will
turn the new implementation on. But it causes system hang duringSH-Linux
Quoted 8 lines
Quoted 8 lines
boot up.
The initial VRAM clearance seems to cause the hang.
The reason might be my wrong implementation, or any MMU problem of SH4.I did,
- added VRAM size to .ram_require
- invokedqemu_ram_alloc()with the VRAM size parameter,
- and invokedcpu_register_physical_memory(), passingthe
Quoted 6 lines
Quoted 5 lines
return value of
qemu_ram_alloc()as third parameter.Is this sequence correct?
Quoted 6 lines
Yes, but the system RAM is not allocated using
qemu_ram_alloc. Nowqemu_ram_allocgives the same area (0 toVRAM_SIZE) the second time.So the following:
/* Allocate memory space */ cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE,0);
Quoted 3 lines
should be changed to:
ram_addr = qemu_ram_alloc(SDRAM_SIZE); cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE,
ram_addr);Quoted 3 lines
Maybe that helps?
Yes, it helps. Thank you!
Quoted 7 lines
Quoted 5 lines
Here's the new patch which uses normal RAM as the VRAM, and checks
VGA_DIRTY_FLAGfor partial update.I think it is ready for merge to the trunk.
Could anyone help it?Looks good to me. What about you, Andrzej?
While I don't know the hardware, it looks correct to me, feel free to merge.
One nit is that qemu_ram_alloc() makes it possible for ram to be allocked inside devices, so for example the local_mem_base and local_mem_bytes parameters can be removed.
Cheers
Quoted 57 lines · andrzej zaborowski
2008/11/5 Blue Swirl <[email protected]>:
Quoted 55 lines · Shin-ichiro KAWASAKI
Quoted 54 lines
Quoted 9 lines · Blue Swirl
Quoted 7 lines · Shin-ichiro KAWASAKI
Thank you for reviewing!
I add the new version of patch to this mail, which reflects you and andrzej's comments. Some more comments on it will be appreciated. Especially advice on VRAM implementation with normal RAM will be useful for me.
Quoted 4 lines
Quoted 4 lines
Quoted 2 lines
The display buffer should be allocated using machine definition
.ram_require.
I tried normal RAM implementation : "#defineUSE_NORMAL_RAM" in thepatch
Quoted 2 lines
Quoted 2 lines
will
turn the new implementation on. But it causes system hang duringSH-Linux
Quoted 8 lines
Quoted 8 lines
boot up.
The initial VRAM clearance seems to cause the hang.
The reason might be my wrong implementation, or any MMU problem of SH4.I did,
- added VRAM size to .ram_require
- invokedqemu_ram_alloc()with the VRAM size parameter,
- and invokedcpu_register_physical_memory(), passingthe
Quoted 6 lines
Quoted 5 lines
return value of
qemu_ram_alloc()as third parameter.Is this sequence correct?
Quoted 6 lines
Yes, but the system RAM is not allocated using
qemu_ram_alloc. Nowqemu_ram_allocgives the same area (0 toVRAM_SIZE) the second time.So the following:
/* Allocate memory space */ cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE,0);
Quoted 3 lines
should be changed to:
ram_addr = qemu_ram_alloc(SDRAM_SIZE); cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE,
ram_addr);Quoted 3 lines
Maybe that helps?
Yes, it helps. Thank you!
Here's the new patch which uses normal RAM as the VRAM, and checks
VGA_DIRTY_FLAGfor partial update.
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
I think it is ready for merge to the trunk.
Could anyone help it?Looks good to me. What about you, Andrzej?
While I don't know the hardware, it looks correct to me, feel free to merge.
Committed as r5632. Thanks!
[Qemu-devel] When should I use qemu_ram_alloc(), and how?
In reply to Blue SwirlHi,
# Reusing thread, to video memory allocation related question. Could you please give me answer to my question ?
Attached diff is for adding cirrus_vga onto r2d, for explanatin. The point is here.
- cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, 0); + r = qemu_ram_alloc(SDRAM_SIZE); + cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, r);
Apparently, r2d had not used qemu_ram_alloc() (it is working, though). I added it here without knowing well about qemu memory system (this one is working fine, too).
Maybe, allocation is needed always(even when without VGA), isn't it?
Are there any restriction between alloced address and register address? I am worried about it because PC seems to make them equal.
Cheers,
/yoshii
# This patch is not for being merged to the repository.
SH: r2d Add cirrus_vga support.
r2d doesn't have cirrus VGA on board, imagine it is in PCI slot. I have to reduce cirrus_vga PCI memory window size 32M to 8M, because SH has only 16MB linear space for PCI.
--- Makefile.target | 2 +- hw/cirrus_vga.c | 2 +- hw/r2d.c | 9 +++++++-- 3 files changed, 9 insertions(+), 4 deletions(-)
Makefile.target +1 -1
@@ -726,7 +726,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 sh_pci.o -OBJS+= ide.o +OBJS+= ide.o vga.o cirrus_vga.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
hw/cirrus_vga.c +1 -1
@@ -3311,7 +3311,7 @@ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,/* memory #0 LFB */ /* memory #1 memory-mapped I/O */ /* XXX: s->vram_size must be a power of two */ -pci_register_io_region ((PCIDevice *)d,0 ,0x2000000 , +pci_register_io_region ((PCIDevice *)d,0 , vga_ram_size,PCI_ADDRESS_SPACE_MEM_PREFETCH , cirrus_pci_lfb_map);if (device_id ==CIRRUS_ID_CLGD5446 ) { pci_register_io_region((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE,
hw/r2d.c +7 -2
@@ -207,6 +207,7 @@ static void r2d_init(ram_addr_t ram_size, int vga_ram_size,qemu_irq *irq;PCIBus *pci;int i; +ram_addr_t r;if (!cpu_model) cpu_model ="SH7751R" ;
@@ -218,11 +219,15 @@ static void r2d_init(ram_addr_t ram_size, int vga_ram_size, }/* Allocate memory space */ -cpu_register_physical_memory (SDRAM_BASE ,SDRAM_SIZE ,0 ); + r =qemu_ram_alloc (SDRAM_SIZE ); +cpu_register_physical_memory (SDRAM_BASE ,SDRAM_SIZE , r);/* Register peripherals */ s =sh7750_init (env); irq =r2d_fpga_init (0x04000000 ,sh7750_irl (s)); pci =sh_pci_register_bus (r2d_pci_set_irq, r2d_pci_map_irq, irq,0 ,4 ); +/* VGA : Just after SDRAM in memory space. Top in PCI space. */ + r =qemu_ram_alloc (vga_ram_size); +pci_cirrus_vga_init (pci, ds, phys_ram_base + r, r, vga_ram_size);/* onboard CF (True IDE mode, Master only). */ mmio_ide_init(0x14001000, 0x1400080c, irq[CF_IDE], 1,
@@ -256,5 +261,5 @@ QEMUMachine r2d_machine = { .name = "r2d", .desc = "r2d-plus board", .init = r2d_init, - .ram_require = SDRAM_SIZE | RAMSIZE_FIXED, + .ram_require = (SDRAM_SIZE + 8*1024*1024) | RAMSIZE_FIXED, };
Signature · 1 line
1.5.6.3
[Qemu-devel] Re: When should I use qemu_ram_alloc(), and how?
Quoted 9 lines · On 11/4/08, [email protected] <[email protected]> wrote:
Hi,
# Reusing thread, to video memory allocation related question. Could you please give me answer to my question ?Attached diff is for adding
cirrus_vgaonto r2d, for explanatin. The point is here.- cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, 0); + r = qemu_ram_alloc(SDRAM_SIZE); + cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, r);
Well, I haven't been using qemu_ram_alloc on Sparc but instead used direct offsets. Maybe I should convert. Also, all ram allocation should be done using qemu_ram_alloc (especially system RAM), not just some devices.
Quoted 5 lines
Apparently, r2d had not used
qemu_ram_alloc()(it is working, though). I added it here without knowing well about qemu memory system (this one is working fine, too).Maybe, allocation is needed always(even when without VGA), isn't it?
I don't think so, unallocated memory will be just unused.
Quoted 2 lines
Are there any restriction between alloced address and register address? I am worried about it because PC seems to make them equal.
There are some code that assumes that CPU address for RAM can be converted to host address using phys_ram_base + CPU address.
Quoted 2 lines
- pci_register_io_region((PCIDevice *)d, 0,
0x2000000,
+ pci_register_io_region((PCIDevice *)d, 0,vga_ram_size,
To me this change looks OK, but I think it should be separate and the PC folks should consider if it breaks something.
Re: [Qemu-devel] Re: When should I use qemu_ram_alloc(), and how?
Quoted 5 lines · Blue Swirl
Quoted 2 lines · On 11/4/08, [email protected] <[email protected]> wrote:
- pci_register_io_region((PCIDevice *)d, 0,
0x2000000,
+ pci_register_io_region((PCIDevice *)d, 0,vga_ram_size,
No, I think this is wrong. The PCI IO region is independent of vga_ram_size.
Regards,
Anthony Liguori
[Qemu-devel] Re: When should I use qemu_ram_alloc(), and how?
In reply to Blue SwirlThank you!
Quoted 4 lines
Well, I haven't been using
qemu_ram_allocon Sparc but instead used direct offsets. Maybe I should convert. Also, all ram allocation should be done usingqemu_ram_alloc(especially system RAM), not just some devices.
I come to know why yours and my case worked fine even without using
qemu_ram_alloc(). What important was offset(phys_ram_alloc_offset).
Anyway I will use qemu_ram_alloc() to maintain the offset.
Quoted 9 lines
Quoted 1 line
Maybe, allocation is needed always(even when without VGA), isn't it?
I don't think so, unallocated memory will be just unused.
Quoted 2 lines
Are there any restriction between alloced address and register address? I am worried about it because PC seems to make them equal.
There are some code that assumes that CPU address for RAM can be converted to host address using
phys_ram_base+ CPU address.
Ah, finally I came to know what a comment at allocating BIOS in pc.c says. It means that When memory layout is like "32M(ROM)+32M(blank)+64M(RAM)" I have to allocate 32M blank(without registering) to keep offset between host and (emulated)CPU address consistent.
Quoted 5 lines
Quoted 2 lines
- pci_register_io_region((PCIDevice *)d, 0,
0x2000000,
+ pci_register_io_region((PCIDevice *)d, 0,vga_ram_size,To me this change looks OK, but I think it should be separate and the PC folks should consider if it breaks something.
Ah, sorry. I have attached the patch to aid explanation. But I think it can not be merged into main repository. (Unfortunately?) real cirrus VGA claims 32M memory regardless with VRAM size. So, if I modified the code, it will be an emulation of something not really exists.
/yoshii