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 32 typedef enum { 33 REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2, 34 } screen_state_t; 35 36 typedef struct LedState { 37 target_phys_addr_t base; 38 uint8_t segments; 39 DisplayState *ds; 40 QEMUConsole *console; 41 screen_state_t state; 42 } LedState; 43 44 static uint32_t led_readb(void *opaque, target_phys_addr_t addr) 45 { 46 LedState *s = opaque; 47 int relative_addr = addr - s->base; 48 uint32_t val; 49 50 switch (relative_addr) { 51 case 0: 52 val = s->segments; 53 break; 54 default: 55 #ifdef DEBUG_LED 56 printf("jazz led: invalid read [0x%x]\n", relative_addr); 57 #endif 58 val = 0; 59 } 60 61 return val; 62 } 63 64 static uint32_t led_readw(void *opaque, target_phys_addr_t addr) 65 { 66 uint32_t v; 67 #ifdef TARGET_WORDS_BIGENDIAN 68 v = led_readb(opaque, addr) << 8; 69 v |= led_readb(opaque, addr + 1); 70 #else 71 v = led_readb(opaque, addr); 72 v |= led_readb(opaque, addr + 1) << 8; 73 #endif 74 return v; 75 } 76 77 static uint32_t led_readl(void *opaque, target_phys_addr_t addr) 78 { 79 uint32_t v; 80 #ifdef TARGET_WORDS_BIGENDIAN 81 v = led_readb(opaque, addr) << 24; 82 v |= led_readb(opaque, addr + 1) << 16; 83 v |= led_readb(opaque, addr + 2) << 8; 84 v |= led_readb(opaque, addr + 3); 85 #else 86 v = led_readb(opaque, addr); 87 v |= led_readb(opaque, addr + 1) << 8; 88 v |= led_readb(opaque, addr + 2) << 16; 89 v |= led_readb(opaque, addr + 3) << 24; 90 #endif 91 return v; 92 } 93 94 static void led_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) 95 { 96 LedState *s = opaque; 97 int relative_addr = addr - s->base; 98 99 switch (relative_addr) { 100 case 0: 101 s->segments = val; 102 s->state |= REDRAW_SEGMENTS; 103 break; 104 default: 105 #ifdef DEBUG_LED 106 printf("jazz led: invalid write of 0x%02x at [0x%x]\n", val, relative_addr); 107 #endif 108 break; 109 } 110 } 111 112 static void led_writew(void *opaque, target_phys_addr_t addr, uint32_t val) 113 { 114 #ifdef TARGET_WORDS_BIGENDIAN 115 led_writeb(opaque, addr, (val >> 8) & 0xff); 116 led_writeb(opaque, addr + 1, val & 0xff); 117 #else 118 led_writeb(opaque, addr, val & 0xff); 119 led_writeb(opaque, addr + 1, (val >> 8) & 0xff); 120 #endif 121 } 122 123 static void led_writel(void *opaque, target_phys_addr_t addr, uint32_t val) 124 { 125 #ifdef TARGET_WORDS_BIGENDIAN 126 led_writeb(opaque, addr, (val >> 24) & 0xff); 127 led_writeb(opaque, addr + 1, (val >> 16) & 0xff); 128 led_writeb(opaque, addr + 2, (val >> 8) & 0xff); 129 led_writeb(opaque, addr + 3, val & 0xff); 130 #else 131 led_writeb(opaque, addr, val & 0xff); 132 led_writeb(opaque, addr + 1, (val >> 8) & 0xff); 133 led_writeb(opaque, addr + 2, (val >> 16) & 0xff); 134 led_writeb(opaque, addr + 3, (val >> 24) & 0xff); 135 #endif 136 } 137 138 static CPUReadMemoryFunc *led_read[3] = { 139 led_readb, 140 led_readw, 141 led_readl, 142 }; 143 144 static CPUWriteMemoryFunc *led_write[3] = { 145 led_writeb, 146 led_writew, 147 led_writel, 148 }; 149 150 /***********************************************************/ 151 /* jazz_led display */ 152 153 static void draw_horizontal_line(DisplayState *ds, int posy, int posx1, int posx2, uint32_t color) 154 { 155 uint8_t *d; 156 int x, bpp; 157 158 bpp = (ds->depth + 7) >> 3; 159 d = ds->data + ds->linesize * posy + bpp * posx1; 160 switch(bpp) { 161 case 1: 162 for (x = posx1; x <= posx2; x++) { 163 *((uint8_t *)d) = color; 164 d++; 165 } 166 break; 167 case 2: 168 for (x = posx1; x <= posx2; x++) { 169 *((uint16_t *)d) = color; 170 d += 2; 171 } 172 break; 173 case 4: 174 for (x = posx1; x <= posx2; x++) { 175 *((uint32_t *)d) = color; 176 d += 4; 177 } 178 break; 179 } 180 } 181 182 static void draw_vertical_line(DisplayState *ds, int posx, int posy1, int posy2, uint32_t color) 183 { 184 uint8_t *d; 185 int y, bpp; 186 187 bpp = (ds->depth + 7) >> 3; 188 d = ds->data + ds->linesize * posy1 + bpp * posx; 189 switch(bpp) { 190 case 1: 191 for (y = posy1; y <= posy2; y++) { 192 *((uint8_t *)d) = color; 193 d += ds->linesize; 194 } 195 break; 196 case 2: 197 for (y = posy1; y <= posy2; y++) { 198 *((uint16_t *)d) = color; 199 d += ds->linesize; 200 } 201 break; 202 case 4: 203 for (y = posy1; y <= posy2; y++) { 204 *((uint32_t *)d) = color; 205 d += ds->linesize; 206 } 207 break; 208 } 209 } 210 211 static void jazz_led_update_display(void *opaque) 212 { 213 LedState *s = opaque; 214 DisplayState *ds = s->ds; 215 uint8_t *d1; 216 uint32_t color_segment, color_led; 217 int y, bpp; 218 219 if (s->state & REDRAW_BACKGROUND) { 220 /* clear screen */ 221 bpp = (ds->depth + 7) >> 3; 222 d1 = ds->data; 223 for (y = 0; y < ds->height; y++) { 224 memset(d1, 0x00, ds->width * bpp); 225 d1 += ds->linesize; 226 } 227 } 228 229 if (s->state & REDRAW_SEGMENTS) { 230 /* set colors according to bpp */ 231 switch (ds->depth) { 232 case 8: 233 color_segment = rgb_to_pixel8(0xaa, 0xaa, 0xaa); 234 color_led = rgb_to_pixel8(0x00, 0xff, 0x00); 235 break; 236 case 15: 237 color_segment = rgb_to_pixel15(0xaa, 0xaa, 0xaa); 238 color_led = rgb_to_pixel15(0x00, 0xff, 0x00); 239 break; 240 case 16: 241 color_segment = rgb_to_pixel16(0xaa, 0xaa, 0xaa); 242 color_led = rgb_to_pixel16(0x00, 0xff, 0x00); 243 case 24: 244 color_segment = rgb_to_pixel24(0xaa, 0xaa, 0xaa); 245 color_led = rgb_to_pixel24(0x00, 0xff, 0x00); 246 break; 247 case 32: 248 color_segment = rgb_to_pixel32(0xaa, 0xaa, 0xaa); 249 color_led = rgb_to_pixel32(0x00, 0xff, 0x00); 250 break; 251 default: 252 return; 253 } 254 255 /* display segments */ 256 draw_horizontal_line(ds, 40, 10, 40, (s->segments & 0x02) ? color_segment : 0); 257 draw_vertical_line(ds, 10, 10, 40, (s->segments & 0x04) ? color_segment : 0); 258 draw_vertical_line(ds, 10, 40, 70, (s->segments & 0x08) ? color_segment : 0); 259 draw_horizontal_line(ds, 70, 10, 40, (s->segments & 0x10) ? color_segment : 0); 260 draw_vertical_line(ds, 40, 40, 70, (s->segments & 0x20) ? color_segment : 0); 261 draw_vertical_line(ds, 40, 10, 40, (s->segments & 0x40) ? color_segment : 0); 262 draw_horizontal_line(ds, 10, 10, 40, (s->segments & 0x80) ? color_segment : 0); 263 264 /* display led */ 265 if (!(s->segments & 0x01)) 266 color_led = 0; /* black */ 267 draw_horizontal_line(ds, 68, 50, 50, color_led); 268 draw_horizontal_line(ds, 69, 49, 51, color_led); 269 draw_horizontal_line(ds, 70, 48, 52, color_led); 270 draw_horizontal_line(ds, 71, 49, 51, color_led); 271 draw_horizontal_line(ds, 72, 50, 50, color_led); 272 } 273 274 s->state = REDRAW_NONE; 275 dpy_update(ds, 0, 0, ds->width, ds->height); 276 } 277 278 static void jazz_led_invalidate_display(void *opaque) 279 { 280 LedState *s = opaque; 281 s->state |= REDRAW_SEGMENTS | REDRAW_BACKGROUND; 282 } 283 284 static void jazz_led_screen_dump(void *opaque, const char *filename) 285 { 286 printf("jazz_led_screen_dump() not implemented\n"); 287 } 288 289 static void jazz_led_text_update(void *opaque, console_ch_t *chardata) 290 { 291 LedState *s = opaque; 292 char buf[2]; 293 294 dpy_cursor(s->ds, -1, -1); 295 qemu_console_resize(s->console, 2, 1); 296 297 /* TODO: draw the segments */ 298 snprintf(buf, 2, "%02hhx\n", s->segments); 299 console_write_ch(chardata++, 0x00200100 | buf[0]); 300 console_write_ch(chardata++, 0x00200100 | buf[1]); 301 302 dpy_update(s->ds, 0, 0, 2, 1); 303 } 304 305 void jazz_led_init(DisplayState *ds, target_phys_addr_t base) 306 { 307 LedState *s; 308 int io; 309 310 s = qemu_mallocz(sizeof(LedState)); 311 if (!s) 312 return; 313 314 s->base = base; 315 s->ds = ds; 316 s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND; 317 318 io = cpu_register_io_memory(0, led_read, led_write, s); 319 cpu_register_physical_memory(s->base, 1, io); 320 321 s->console = graphic_console_init(ds, jazz_led_update_display, 322 jazz_led_invalidate_display, 323 jazz_led_screen_dump, 324 jazz_led_text_update, s); 325 qemu_console_resize(s->console, 60, 80); 326 } 327