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 } e_screen_state; 35 36 typedef struct LedState { 37 uint8_t segments; 38 DisplayState *ds; 39 e_screen_state state; 40 } LedState; 41 42 static uint32_t led_readb(void *opaque, a_target_phys_addr 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 61 static uint32_t led_readw(void *opaque, a_target_phys_addr 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 74 static uint32_t led_readl(void *opaque, a_target_phys_addr 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 91 static void led_writeb(void *opaque, a_target_phys_addr 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 108 static void led_writew(void *opaque, a_target_phys_addr 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 119 static void led_writel(void *opaque, a_target_phys_addr 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 134 static CPUReadMemoryFunc * const led_read[3] = { 135 led_readb, 136 led_readw, 137 led_readl, 138 }; 139 140 static CPUWriteMemoryFunc * const led_write[3] = { 141 led_writeb, 142 led_writew, 143 led_writel, 144 }; 145 146 /***********************************************************/ 147 /* jazz_led display */ 148 149 static 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 178 static 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 207 static 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 274 static void jazz_led_invalidate_display(void *opaque) 275 { 276 LedState *s = opaque; 277 s->state |= REDRAW_SEGMENTS | REDRAW_BACKGROUND; 278 } 279 280 static void jazz_led_screen_dump(void *opaque, const char *filename) 281 { 282 printf("jazz_led_screen_dump() not implemented\n"); 283 } 284 285 static void jazz_led_text_update(void *opaque, a_console_ch *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 301 void jazz_led_init(a_target_phys_addr 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