From patchwork Fri Jan 1 06:59:39 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shin-ichiro KAWASAKI X-Patchwork-Id: 41984 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id C9ACD1007D1 for ; Fri, 1 Jan 2010 18:00:34 +1100 (EST) Received: from localhost ([127.0.0.1]:42397 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NQbUr-0008P8-US for incoming@patchwork.ozlabs.org; Fri, 01 Jan 2010 02:00:29 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NQbUE-0008Ov-7q for qemu-devel@nongnu.org; Fri, 01 Jan 2010 01:59:50 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NQbU8-0008OJ-Ey for qemu-devel@nongnu.org; Fri, 01 Jan 2010 01:59:48 -0500 Received: from [199.232.76.173] (port=42625 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NQbU8-0008OG-4r for qemu-devel@nongnu.org; Fri, 01 Jan 2010 01:59:44 -0500 Received: from vsmtp05.dti.ne.jp ([202.216.231.140]:53886) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1NQbU7-00024I-82 for qemu-devel@nongnu.org; Fri, 01 Jan 2010 01:59:43 -0500 Received: from [192.168.1.22] (PPPa96.e11.eacc.dti.ne.jp [124.255.86.97]) by vsmtp05.dti.ne.jp (3.11v) with ESMTP AUTH id o016xb7U016220 for ; Fri, 1 Jan 2010 15:59:38 +0900 (JST) Message-ID: <4B3D9D5B.6080501@juno.dti.ne.jp> Date: Fri, 01 Jan 2010 15:59:39 +0900 From: Shin-ichiro KAWASAKI User-Agent: Thunderbird 2.0.0.23 (Windows/20090812) MIME-Version: 1.0 To: qemu-devel@nongnu.org X-detected-operating-system: by monty-python.gnu.org: Solaris 9 Subject: [Qemu-devel] [PATCH] sh: sm501: Add hardware cursor feature X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch adds hardware cursor feature to SM501 graphics chip emulation, to make the graphic console more useful for QEMU SH4 users. Signed-off-by: Shin-ichiro KAWASAKI hw/sm501.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++---- hw/sm501_template.h | 42 ++++++++++++++ 2 files changed, 185 insertions(+), 11 deletions(-) diff --git a/hw/sm501.c b/hw/sm501.c index 612a8e5..cd1f595 100644 --- a/hw/sm501.c +++ b/hw/sm501.c @@ -434,6 +434,8 @@ /* end of register definitions */ +#define SM501_HWC_WIDTH (64) +#define SM501_HWC_HEIGHT (64) /* SM501 local memory size taken from "linux/drivers/mfd/sm501.c" */ static const uint32_t sm501_mem_local_size[] = { @@ -526,6 +528,95 @@ static uint32_t get_local_mem_size_index(uint32_t size) return index; } +/** + * Check the availability of hardware cursor. + * @param crt 0 for PANEL, 1 for CRT. + */ +static inline int is_hwc_enabled(SM501State *state, int crt) +{ + uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr; + return addr & 0x80000000; +} + +/** + * Get the address which holds cursor pattern data. + * @param crt 0 for PANEL, 1 for CRT. + */ +static inline uint32_t get_hwc_address(SM501State *state, int crt) +{ + uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr; + return (addr & 0x03FFFFF0)/* >> 4*/; +} + +/** + * Get the cursor position in y coordinate. + * @param crt 0 for PANEL, 1 for CRT. + */ +static inline uint32_t get_hwc_y(SM501State *state, int crt) +{ + uint32_t location = crt ? state->dc_crt_hwc_location + : state->dc_panel_hwc_location; + return (location & 0x07FF0000) >> 16; +} + +/** + * Get the cursor position in x coordinate. + * @param crt 0 for PANEL, 1 for CRT. + */ +static inline uint32_t get_hwc_x(SM501State *state, int crt) +{ + uint32_t location = crt ? state->dc_crt_hwc_location + : state->dc_panel_hwc_location; + return location & 0x000007FF; +} + +/** + * Get the cursor position in x coordinate. + * @param crt 0 for PANEL, 1 for CRT. + * @param index 0, 1, 2 or 3 which specifies color of corsor dot. + */ +static inline uint16_t get_hwc_color(SM501State *state, int crt, int index) +{ + uint16_t color_reg = 0; + uint16_t color_565 = 0; + + if (index == 0) { + return 0; + } + + switch (index) { + case 1: + case 2: + color_reg = crt ? state->dc_crt_hwc_color_1_2 + : state->dc_panel_hwc_color_1_2; + break; + case 3: + color_reg = crt ? state->dc_crt_hwc_color_3 + : state->dc_panel_hwc_color_3; + break; + default: + printf("invalid hw cursor color.\n"); + assert(0); + } + + switch (index) { + case 1: + case 3: + color_565 = (uint16_t)(color_reg & 0xFFFF); + break; + case 2: + color_565 = (uint16_t)((color_reg >> 16) & 0xFFFF); + break; + } + return color_565; +} + +static int within_hwc_y_range(SM501State *state, int y, int crt) +{ + int hwc_y = get_hwc_y(state, crt); + return (hwc_y <= y && y < hwc_y + SM501_HWC_HEIGHT); +} + static uint32_t sm501_system_config_read(void *opaque, target_phys_addr_t addr) { SM501State * s = (SM501State *)opaque; @@ -736,13 +827,13 @@ static uint32_t sm501_disp_ctrl_read(void *opaque, target_phys_addr_t addr) ret = s->dc_crt_hwc_addr; break; case SM501_DC_CRT_HWC_LOC: - ret = s->dc_crt_hwc_addr; + ret = s->dc_crt_hwc_location; break; case SM501_DC_CRT_HWC_COLOR_1_2: - ret = s->dc_crt_hwc_addr; + ret = s->dc_crt_hwc_color_1_2; break; case SM501_DC_CRT_HWC_COLOR_3: - ret = s->dc_crt_hwc_addr; + ret = s->dc_crt_hwc_color_3; break; case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4: @@ -809,13 +900,13 @@ static void sm501_disp_ctrl_write(void *opaque, s->dc_panel_hwc_addr = value & 0x8FFFFFF0; break; case SM501_DC_PANEL_HWC_LOC: - s->dc_panel_hwc_addr = value & 0x0FFF0FFF; + s->dc_panel_hwc_location = value & 0x0FFF0FFF; break; case SM501_DC_PANEL_HWC_COLOR_1_2: - s->dc_panel_hwc_addr = value; + s->dc_panel_hwc_color_1_2 = value; break; case SM501_DC_PANEL_HWC_COLOR_3: - s->dc_panel_hwc_addr = value & 0x0000FFFF; + s->dc_panel_hwc_color_3 = value & 0x0000FFFF; break; case SM501_DC_CRT_CONTROL: @@ -844,13 +935,13 @@ static void sm501_disp_ctrl_write(void *opaque, s->dc_crt_hwc_addr = value & 0x8FFFFFF0; break; case SM501_DC_CRT_HWC_LOC: - s->dc_crt_hwc_addr = value & 0x0FFF0FFF; + s->dc_crt_hwc_location = value & 0x0FFF0FFF; break; case SM501_DC_CRT_HWC_COLOR_1_2: - s->dc_crt_hwc_addr = value; + s->dc_crt_hwc_color_1_2 = value; break; case SM501_DC_CRT_HWC_COLOR_3: - s->dc_crt_hwc_addr = value & 0x0000FFFF; + s->dc_crt_hwc_color_3 = value & 0x0000FFFF; break; case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4: @@ -883,6 +974,9 @@ static CPUWriteMemoryFunc * const sm501_disp_ctrl_writefn[] = { typedef void draw_line_func(uint8_t *d, const uint8_t *s, int width, const uint32_t *pal); +typedef void draw_hwc_line_func(SM501State * s, int crt, uint8_t * palette, + int c_y, uint8_t *d, int width); + #define DEPTH 8 #include "sm501_template.h" @@ -937,6 +1031,16 @@ static draw_line_func * draw_line32_funcs[] = { draw_line32_16bgr, }; +static draw_hwc_line_func * draw_hwc_line_funcs[] = { + draw_hwc_line_8, + draw_hwc_line_15, + draw_hwc_line_16, + draw_hwc_line_32, + draw_hwc_line_32bgr, + draw_hwc_line_15bgr, + draw_hwc_line_16bgr, +}; + static inline int get_depth_index(DisplayState *s) { switch(ds_get_bits_per_pixel(s)) { @@ -966,8 +1070,10 @@ static void sm501_draw_crt(SM501State * s) int dst_bpp = ds_get_bytes_per_pixel(s->ds) + (ds_get_bits_per_pixel(s->ds) % 8 ? 1 : 0); uint32_t * palette = (uint32_t *)&s->dc_palette[SM501_DC_CRT_PALETTE - SM501_DC_PANEL_PALETTE]; + uint8_t hwc_palette[3 * 3]; int ds_depth_index = get_depth_index(s->ds); draw_line_func * draw_line = NULL; + draw_hwc_line_func * draw_hwc_line = NULL; int full_update = 0; int y_start = -1; int page_min = 0x7fffffff; @@ -995,6 +1101,22 @@ static void sm501_draw_crt(SM501State * s) break; } + /* set up to draw hardware cursor */ + if (is_hwc_enabled(s, 1)) { + int i; + + /* get cursor palette */ + for (i = 0; i < 3; i++) { + uint16_t rgb565 = get_hwc_color(s, 1, i + 1); + hwc_palette[i * 3 + 0] = (rgb565 & 0xf800) >> 8; /* red */ + hwc_palette[i * 3 + 1] = (rgb565 & 0x07e0) >> 3; /* green */ + hwc_palette[i * 3 + 2] = (rgb565 & 0x001f) << 3; /* blue */ + } + + /* choose cursor draw line function */ + draw_hwc_line = draw_hwc_line_funcs[ds_depth_index]; + } + /* adjust console size */ if (s->last_width != width || s->last_height != height) { qemu_console_resize(s->ds, width, height); @@ -1005,7 +1127,8 @@ static void sm501_draw_crt(SM501State * s) /* draw each line according to conditions */ for (y = 0; y < height; y++) { - int update = full_update; + int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0; + int update = full_update || update_hwc; ram_addr_t page0 = offset & TARGET_PAGE_MASK; ram_addr_t page1 = (offset + width * src_bpp - 1) & TARGET_PAGE_MASK; ram_addr_t page; @@ -1017,7 +1140,16 @@ static void sm501_draw_crt(SM501State * s) /* draw line and change status */ if (update) { - draw_line(&(ds_get_data(s->ds)[y * width * dst_bpp]), src, width, palette); + uint8_t * d = &(ds_get_data(s->ds)[y * width * dst_bpp]); + + /* draw graphics layer */ + draw_line(d, src, width, palette); + + /* draw haredware cursor */ + if (update_hwc) { + draw_hwc_line(s, 1, hwc_palette, y - get_hwc_y(s, 1), d, width); + } + if (y_start < 0) y_start = y; if (page0 < page_min) diff --git a/hw/sm501_template.h b/hw/sm501_template.h index 1679df7..d1ceef9 100644 --- a/hw/sm501_template.h +++ b/hw/sm501_template.h @@ -96,6 +96,48 @@ static void glue(draw_line32_, PIXEL_NAME)( } while (-- width != 0); } +/** + * Draw hardware cursor image on the given line. + */ +static void glue(draw_hwc_line_, PIXEL_NAME)(SM501State * s, int crt, + uint8_t * palette, int c_y, uint8_t *d, int width) +{ + int x, i; + uint8_t bitset = 0; + + /* get hardware cursor pattern */ + uint32_t cursor_addr = get_hwc_address(s, crt); + assert(0 <= c_y && c_y < SM501_HWC_HEIGHT); + cursor_addr += 64 * c_y / 4; /* 4 pixels per byte */ + cursor_addr += s->base; + + /* get cursor position */ + x = get_hwc_x(s, crt); + d += x * BPP; + + for (i = 0; i < SM501_HWC_WIDTH && x + i < width; i++) { + uint8_t v; + + /* get pixel value */ + if (i % 4 == 0) { + cpu_physical_memory_rw(cursor_addr, &bitset, 1, 0); + cursor_addr++; + } + v = bitset & 3; + bitset >>= 2; + + /* write pixel */ + if (v) { + v--; + uint8_t r = palette[v * 3 + 0]; + uint8_t g = palette[v * 3 + 1]; + uint8_t b = palette[v * 3 + 2]; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); + } + d += BPP; + } +} + #undef DEPTH #undef BPP #undef PIXEL_TYPE