qemu/hw/jazz_led.c
<<
>>
Prefs
   1/*
   2 * QEMU JAZZ LED emulator.
   3 *
   4 * Copyright (c) 2007 Hervé Poussineau
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "hw.h"
  26#include "mips.h"
  27#include "console.h"
  28#include "pixel_ops.h"
  29
  30//#define DEBUG_LED
  31
  32typedef enum {
  33    REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2,
  34} screen_state_t;
  35
  36typedef struct LedState {
  37    uint8_t segments;
  38    DisplayState *ds;
  39    screen_state_t state;
  40} LedState;
  41
  42static uint32_t led_readb(void *opaque, target_phys_addr_t addr)
  43{
  44    LedState *s = opaque;
  45    uint32_t val;
  46
  47    switch (addr) {
  48        case 0:
  49            val = s->segments;
  50            break;
  51        default:
  52#ifdef DEBUG_LED
  53            printf("jazz led: invalid read [0x%x]\n", relative_addr);
  54#endif
  55            val = 0;
  56    }
  57
  58    return val;
  59}
  60
  61static uint32_t led_readw(void *opaque, target_phys_addr_t addr)
  62{
  63    uint32_t v;
  64#ifdef TARGET_WORDS_BIGENDIAN
  65    v = led_readb(opaque, addr) << 8;
  66    v |= led_readb(opaque, addr + 1);
  67#else
  68    v = led_readb(opaque, addr);
  69    v |= led_readb(opaque, addr + 1) << 8;
  70#endif
  71    return v;
  72}
  73
  74static uint32_t led_readl(void *opaque, target_phys_addr_t addr)
  75{
  76    uint32_t v;
  77#ifdef TARGET_WORDS_BIGENDIAN
  78    v = led_readb(opaque, addr) << 24;
  79    v |= led_readb(opaque, addr + 1) << 16;
  80    v |= led_readb(opaque, addr + 2) << 8;
  81    v |= led_readb(opaque, addr + 3);
  82#else
  83    v = led_readb(opaque, addr);
  84    v |= led_readb(opaque, addr + 1) << 8;
  85    v |= led_readb(opaque, addr + 2) << 16;
  86    v |= led_readb(opaque, addr + 3) << 24;
  87#endif
  88    return v;
  89}
  90
  91static void led_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
  92{
  93    LedState *s = opaque;
  94
  95    switch (addr) {
  96        case 0:
  97            s->segments = val;
  98            s->state |= REDRAW_SEGMENTS;
  99            break;
 100        default:
 101#ifdef DEBUG_LED
 102            printf("jazz led: invalid write of 0x%02x at [0x%x]\n", val, relative_addr);
 103#endif
 104            break;
 105    }
 106}
 107
 108static void led_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
 109{
 110#ifdef TARGET_WORDS_BIGENDIAN
 111    led_writeb(opaque, addr, (val >> 8) & 0xff);
 112    led_writeb(opaque, addr + 1, val & 0xff);
 113#else
 114    led_writeb(opaque, addr, val & 0xff);
 115    led_writeb(opaque, addr + 1, (val >> 8) & 0xff);
 116#endif
 117}
 118
 119static void led_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 120{
 121#ifdef TARGET_WORDS_BIGENDIAN
 122    led_writeb(opaque, addr, (val >> 24) & 0xff);
 123    led_writeb(opaque, addr + 1, (val >> 16) & 0xff);
 124    led_writeb(opaque, addr + 2, (val >> 8) & 0xff);
 125    led_writeb(opaque, addr + 3, val & 0xff);
 126#else
 127    led_writeb(opaque, addr, val & 0xff);
 128    led_writeb(opaque, addr + 1, (val >> 8) & 0xff);
 129    led_writeb(opaque, addr + 2, (val >> 16) & 0xff);
 130    led_writeb(opaque, addr + 3, (val >> 24) & 0xff);
 131#endif
 132}
 133
 134static CPUReadMemoryFunc *led_read[3] = {
 135    led_readb,
 136    led_readw,
 137    led_readl,
 138};
 139
 140static CPUWriteMemoryFunc *led_write[3] = {
 141    led_writeb,
 142    led_writew,
 143    led_writel,
 144};
 145
 146/***********************************************************/
 147/* jazz_led display */
 148
 149static void draw_horizontal_line(DisplayState *ds, int posy, int posx1, int posx2, uint32_t color)
 150{
 151    uint8_t *d;
 152    int x, bpp;
 153
 154    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
 155    d = ds_get_data(ds) + ds_get_linesize(ds) * posy + bpp * posx1;
 156    switch(bpp) {
 157        case 1:
 158            for (x = posx1; x <= posx2; x++) {
 159                *((uint8_t *)d) = color;
 160                d++;
 161            }
 162            break;
 163        case 2:
 164            for (x = posx1; x <= posx2; x++) {
 165                *((uint16_t *)d) = color;
 166                d += 2;
 167            }
 168            break;
 169        case 4:
 170            for (x = posx1; x <= posx2; x++) {
 171                *((uint32_t *)d) = color;
 172                d += 4;
 173            }
 174            break;
 175    }
 176}
 177
 178static void draw_vertical_line(DisplayState *ds, int posx, int posy1, int posy2, uint32_t color)
 179{
 180    uint8_t *d;
 181    int y, bpp;
 182
 183    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
 184    d = ds_get_data(ds) + ds_get_linesize(ds) * posy1 + bpp * posx;
 185    switch(bpp) {
 186        case 1:
 187            for (y = posy1; y <= posy2; y++) {
 188                *((uint8_t *)d) = color;
 189                d += ds_get_linesize(ds);
 190            }
 191            break;
 192        case 2:
 193            for (y = posy1; y <= posy2; y++) {
 194                *((uint16_t *)d) = color;
 195                d += ds_get_linesize(ds);
 196            }
 197            break;
 198        case 4:
 199            for (y = posy1; y <= posy2; y++) {
 200                *((uint32_t *)d) = color;
 201                d += ds_get_linesize(ds);
 202            }
 203            break;
 204    }
 205}
 206
 207static void jazz_led_update_display(void *opaque)
 208{
 209    LedState *s = opaque;
 210    DisplayState *ds = s->ds;
 211    uint8_t *d1;
 212    uint32_t color_segment, color_led;
 213    int y, bpp;
 214
 215    if (s->state & REDRAW_BACKGROUND) {
 216        /* clear screen */
 217        bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
 218        d1 = ds_get_data(ds);
 219        for (y = 0; y < ds_get_height(ds); y++) {
 220            memset(d1, 0x00, ds_get_width(ds) * bpp);
 221            d1 += ds_get_linesize(ds);
 222        }
 223    }
 224
 225    if (s->state & REDRAW_SEGMENTS) {
 226        /* set colors according to bpp */
 227        switch (ds_get_bits_per_pixel(ds)) {
 228            case 8:
 229                color_segment = rgb_to_pixel8(0xaa, 0xaa, 0xaa);
 230                color_led = rgb_to_pixel8(0x00, 0xff, 0x00);
 231                break;
 232            case 15:
 233                color_segment = rgb_to_pixel15(0xaa, 0xaa, 0xaa);
 234                color_led = rgb_to_pixel15(0x00, 0xff, 0x00);
 235                break;
 236            case 16:
 237                color_segment = rgb_to_pixel16(0xaa, 0xaa, 0xaa);
 238                color_led = rgb_to_pixel16(0x00, 0xff, 0x00);
 239            case 24:
 240                color_segment = rgb_to_pixel24(0xaa, 0xaa, 0xaa);
 241                color_led = rgb_to_pixel24(0x00, 0xff, 0x00);
 242                break;
 243            case 32:
 244                color_segment = rgb_to_pixel32(0xaa, 0xaa, 0xaa);
 245                color_led = rgb_to_pixel32(0x00, 0xff, 0x00);
 246                break;
 247            default:
 248                return;
 249        }
 250
 251        /* display segments */
 252        draw_horizontal_line(ds, 40, 10, 40, (s->segments & 0x02) ? color_segment : 0);
 253        draw_vertical_line(ds, 10, 10, 40, (s->segments & 0x04) ? color_segment : 0);
 254        draw_vertical_line(ds, 10, 40, 70, (s->segments & 0x08) ? color_segment : 0);
 255        draw_horizontal_line(ds, 70, 10, 40, (s->segments & 0x10) ? color_segment : 0);
 256        draw_vertical_line(ds, 40, 40, 70, (s->segments & 0x20) ? color_segment : 0);
 257        draw_vertical_line(ds, 40, 10, 40, (s->segments & 0x40) ? color_segment : 0);
 258        draw_horizontal_line(ds, 10, 10, 40, (s->segments & 0x80) ? color_segment : 0);
 259
 260        /* display led */
 261        if (!(s->segments & 0x01))
 262            color_led = 0; /* black */
 263        draw_horizontal_line(ds, 68, 50, 50, color_led);
 264        draw_horizontal_line(ds, 69, 49, 51, color_led);
 265        draw_horizontal_line(ds, 70, 48, 52, color_led);
 266        draw_horizontal_line(ds, 71, 49, 51, color_led);
 267        draw_horizontal_line(ds, 72, 50, 50, color_led);
 268    }
 269
 270    s->state = REDRAW_NONE;
 271    dpy_update(ds, 0, 0, ds_get_width(ds), ds_get_height(ds));
 272}
 273
 274static void jazz_led_invalidate_display(void *opaque)
 275{
 276    LedState *s = opaque;
 277    s->state |= REDRAW_SEGMENTS | REDRAW_BACKGROUND;
 278}
 279
 280static void jazz_led_screen_dump(void *opaque, const char *filename)
 281{
 282    printf("jazz_led_screen_dump() not implemented\n");
 283}
 284
 285static void jazz_led_text_update(void *opaque, console_ch_t *chardata)
 286{
 287    LedState *s = opaque;
 288    char buf[2];
 289
 290    dpy_cursor(s->ds, -1, -1);
 291    qemu_console_resize(s->ds, 2, 1);
 292
 293    /* TODO: draw the segments */
 294    snprintf(buf, 2, "%02hhx\n", s->segments);
 295    console_write_ch(chardata++, 0x00200100 | buf[0]);
 296    console_write_ch(chardata++, 0x00200100 | buf[1]);
 297
 298    dpy_update(s->ds, 0, 0, 2, 1);
 299}
 300
 301void jazz_led_init(target_phys_addr_t base)
 302{
 303    LedState *s;
 304    int io;
 305
 306    s = qemu_mallocz(sizeof(LedState));
 307
 308    s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND;
 309
 310    io = cpu_register_io_memory(led_read, led_write, s);
 311    cpu_register_physical_memory(base, 1, io);
 312
 313    s->ds = graphic_console_init(jazz_led_update_display,
 314                                 jazz_led_invalidate_display,
 315                                 jazz_led_screen_dump,
 316                                 jazz_led_text_update, s);
 317    qemu_console_resize(s->ds, 60, 80);
 318}
 319