]>
Commit | Line | Data |
---|---|---|
31211df1 TS |
1 | /* |
2 | * QEMU JAZZ LED emulator. | |
5fafdf24 | 3 | * |
bcc4e41f | 4 | * Copyright (c) 2007 Hervé Poussineau |
5fafdf24 | 5 | * |
31211df1 TS |
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 | ||
87ecb68b PB |
25 | #include "hw.h" |
26 | #include "mips.h" | |
27 | #include "console.h" | |
31211df1 | 28 | #include "pixel_ops.h" |
63b9932d | 29 | #include "trace.h" |
14414da4 | 30 | |
31211df1 TS |
31 | typedef enum { |
32 | REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2, | |
c227f099 | 33 | } screen_state_t; |
31211df1 TS |
34 | |
35 | typedef struct LedState { | |
c6017850 | 36 | MemoryRegion iomem; |
31211df1 TS |
37 | uint8_t segments; |
38 | DisplayState *ds; | |
c227f099 | 39 | screen_state_t state; |
31211df1 TS |
40 | } LedState; |
41 | ||
c227f099 | 42 | static uint32_t led_readb(void *opaque, target_phys_addr_t addr) |
31211df1 TS |
43 | { |
44 | LedState *s = opaque; | |
63b9932d | 45 | uint8_t val; |
31211df1 | 46 | |
8da3ff18 | 47 | switch (addr) { |
31211df1 TS |
48 | case 0: |
49 | val = s->segments; | |
50 | break; | |
51 | default: | |
63b9932d | 52 | error_report("invalid read at [" TARGET_FMT_plx "]\n", addr); |
31211df1 TS |
53 | val = 0; |
54 | } | |
55 | ||
63b9932d | 56 | trace_jazz_led_read(addr, val); |
14414da4 | 57 | |
31211df1 TS |
58 | return val; |
59 | } | |
60 | ||
c227f099 | 61 | static uint32_t led_readw(void *opaque, target_phys_addr_t addr) |
31211df1 TS |
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 | ||
c227f099 | 74 | static uint32_t led_readl(void *opaque, target_phys_addr_t addr) |
31211df1 TS |
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 | ||
c227f099 | 91 | static void led_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
31211df1 TS |
92 | { |
93 | LedState *s = opaque; | |
63b9932d | 94 | uint8_t new_val = val & 0xff; |
31211df1 | 95 | |
63b9932d | 96 | trace_jazz_led_write(addr, new_val); |
14414da4 | 97 | |
8da3ff18 | 98 | switch (addr) { |
31211df1 | 99 | case 0: |
63b9932d | 100 | s->segments = new_val; |
31211df1 TS |
101 | s->state |= REDRAW_SEGMENTS; |
102 | break; | |
103 | default: | |
63b9932d HP |
104 | error_report("invalid write of 0x%x at [" TARGET_FMT_plx "]\n", |
105 | new_val, addr); | |
31211df1 TS |
106 | break; |
107 | } | |
108 | } | |
109 | ||
c227f099 | 110 | static void led_writew(void *opaque, target_phys_addr_t addr, uint32_t val) |
31211df1 TS |
111 | { |
112 | #ifdef TARGET_WORDS_BIGENDIAN | |
113 | led_writeb(opaque, addr, (val >> 8) & 0xff); | |
114 | led_writeb(opaque, addr + 1, val & 0xff); | |
115 | #else | |
116 | led_writeb(opaque, addr, val & 0xff); | |
117 | led_writeb(opaque, addr + 1, (val >> 8) & 0xff); | |
118 | #endif | |
119 | } | |
120 | ||
c227f099 | 121 | static void led_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
31211df1 TS |
122 | { |
123 | #ifdef TARGET_WORDS_BIGENDIAN | |
124 | led_writeb(opaque, addr, (val >> 24) & 0xff); | |
125 | led_writeb(opaque, addr + 1, (val >> 16) & 0xff); | |
126 | led_writeb(opaque, addr + 2, (val >> 8) & 0xff); | |
127 | led_writeb(opaque, addr + 3, val & 0xff); | |
128 | #else | |
129 | led_writeb(opaque, addr, val & 0xff); | |
130 | led_writeb(opaque, addr + 1, (val >> 8) & 0xff); | |
131 | led_writeb(opaque, addr + 2, (val >> 16) & 0xff); | |
132 | led_writeb(opaque, addr + 3, (val >> 24) & 0xff); | |
133 | #endif | |
134 | } | |
135 | ||
c6017850 AK |
136 | static const MemoryRegionOps led_ops = { |
137 | .old_mmio = { | |
138 | .read = { led_readb, led_readw, led_readl, }, | |
139 | .write = { led_writeb, led_writew, led_writel, }, | |
140 | }, | |
141 | .endianness = DEVICE_NATIVE_ENDIAN, | |
31211df1 TS |
142 | }; |
143 | ||
144 | /***********************************************************/ | |
145 | /* jazz_led display */ | |
146 | ||
147 | static void draw_horizontal_line(DisplayState *ds, int posy, int posx1, int posx2, uint32_t color) | |
148 | { | |
149 | uint8_t *d; | |
150 | int x, bpp; | |
151 | ||
0e1f5a0c AL |
152 | bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; |
153 | d = ds_get_data(ds) + ds_get_linesize(ds) * posy + bpp * posx1; | |
31211df1 TS |
154 | switch(bpp) { |
155 | case 1: | |
156 | for (x = posx1; x <= posx2; x++) { | |
157 | *((uint8_t *)d) = color; | |
158 | d++; | |
159 | } | |
160 | break; | |
161 | case 2: | |
162 | for (x = posx1; x <= posx2; x++) { | |
163 | *((uint16_t *)d) = color; | |
164 | d += 2; | |
165 | } | |
166 | break; | |
167 | case 4: | |
168 | for (x = posx1; x <= posx2; x++) { | |
169 | *((uint32_t *)d) = color; | |
170 | d += 4; | |
171 | } | |
172 | break; | |
173 | } | |
174 | } | |
175 | ||
176 | static void draw_vertical_line(DisplayState *ds, int posx, int posy1, int posy2, uint32_t color) | |
177 | { | |
178 | uint8_t *d; | |
179 | int y, bpp; | |
180 | ||
0e1f5a0c AL |
181 | bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; |
182 | d = ds_get_data(ds) + ds_get_linesize(ds) * posy1 + bpp * posx; | |
31211df1 TS |
183 | switch(bpp) { |
184 | case 1: | |
185 | for (y = posy1; y <= posy2; y++) { | |
186 | *((uint8_t *)d) = color; | |
0e1f5a0c | 187 | d += ds_get_linesize(ds); |
31211df1 TS |
188 | } |
189 | break; | |
190 | case 2: | |
191 | for (y = posy1; y <= posy2; y++) { | |
192 | *((uint16_t *)d) = color; | |
0e1f5a0c | 193 | d += ds_get_linesize(ds); |
31211df1 TS |
194 | } |
195 | break; | |
196 | case 4: | |
197 | for (y = posy1; y <= posy2; y++) { | |
198 | *((uint32_t *)d) = color; | |
0e1f5a0c | 199 | d += ds_get_linesize(ds); |
31211df1 TS |
200 | } |
201 | break; | |
202 | } | |
203 | } | |
204 | ||
205 | static void jazz_led_update_display(void *opaque) | |
206 | { | |
207 | LedState *s = opaque; | |
208 | DisplayState *ds = s->ds; | |
209 | uint8_t *d1; | |
210 | uint32_t color_segment, color_led; | |
211 | int y, bpp; | |
212 | ||
213 | if (s->state & REDRAW_BACKGROUND) { | |
214 | /* clear screen */ | |
0e1f5a0c AL |
215 | bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; |
216 | d1 = ds_get_data(ds); | |
217 | for (y = 0; y < ds_get_height(ds); y++) { | |
218 | memset(d1, 0x00, ds_get_width(ds) * bpp); | |
219 | d1 += ds_get_linesize(ds); | |
31211df1 TS |
220 | } |
221 | } | |
222 | ||
223 | if (s->state & REDRAW_SEGMENTS) { | |
224 | /* set colors according to bpp */ | |
0e1f5a0c | 225 | switch (ds_get_bits_per_pixel(ds)) { |
31211df1 TS |
226 | case 8: |
227 | color_segment = rgb_to_pixel8(0xaa, 0xaa, 0xaa); | |
228 | color_led = rgb_to_pixel8(0x00, 0xff, 0x00); | |
229 | break; | |
230 | case 15: | |
231 | color_segment = rgb_to_pixel15(0xaa, 0xaa, 0xaa); | |
232 | color_led = rgb_to_pixel15(0x00, 0xff, 0x00); | |
233 | break; | |
234 | case 16: | |
235 | color_segment = rgb_to_pixel16(0xaa, 0xaa, 0xaa); | |
236 | color_led = rgb_to_pixel16(0x00, 0xff, 0x00); | |
237 | case 24: | |
238 | color_segment = rgb_to_pixel24(0xaa, 0xaa, 0xaa); | |
239 | color_led = rgb_to_pixel24(0x00, 0xff, 0x00); | |
240 | break; | |
241 | case 32: | |
242 | color_segment = rgb_to_pixel32(0xaa, 0xaa, 0xaa); | |
243 | color_led = rgb_to_pixel32(0x00, 0xff, 0x00); | |
244 | break; | |
245 | default: | |
246 | return; | |
247 | } | |
248 | ||
249 | /* display segments */ | |
250 | draw_horizontal_line(ds, 40, 10, 40, (s->segments & 0x02) ? color_segment : 0); | |
251 | draw_vertical_line(ds, 10, 10, 40, (s->segments & 0x04) ? color_segment : 0); | |
252 | draw_vertical_line(ds, 10, 40, 70, (s->segments & 0x08) ? color_segment : 0); | |
253 | draw_horizontal_line(ds, 70, 10, 40, (s->segments & 0x10) ? color_segment : 0); | |
254 | draw_vertical_line(ds, 40, 40, 70, (s->segments & 0x20) ? color_segment : 0); | |
255 | draw_vertical_line(ds, 40, 10, 40, (s->segments & 0x40) ? color_segment : 0); | |
256 | draw_horizontal_line(ds, 10, 10, 40, (s->segments & 0x80) ? color_segment : 0); | |
257 | ||
258 | /* display led */ | |
259 | if (!(s->segments & 0x01)) | |
260 | color_led = 0; /* black */ | |
261 | draw_horizontal_line(ds, 68, 50, 50, color_led); | |
262 | draw_horizontal_line(ds, 69, 49, 51, color_led); | |
263 | draw_horizontal_line(ds, 70, 48, 52, color_led); | |
264 | draw_horizontal_line(ds, 71, 49, 51, color_led); | |
265 | draw_horizontal_line(ds, 72, 50, 50, color_led); | |
266 | } | |
267 | ||
268 | s->state = REDRAW_NONE; | |
0e1f5a0c | 269 | dpy_update(ds, 0, 0, ds_get_width(ds), ds_get_height(ds)); |
31211df1 TS |
270 | } |
271 | ||
272 | static void jazz_led_invalidate_display(void *opaque) | |
273 | { | |
274 | LedState *s = opaque; | |
275 | s->state |= REDRAW_SEGMENTS | REDRAW_BACKGROUND; | |
276 | } | |
277 | ||
278 | static void jazz_led_screen_dump(void *opaque, const char *filename) | |
279 | { | |
280 | printf("jazz_led_screen_dump() not implemented\n"); | |
281 | } | |
282 | ||
c227f099 | 283 | static void jazz_led_text_update(void *opaque, console_ch_t *chardata) |
4d3b6f6e AZ |
284 | { |
285 | LedState *s = opaque; | |
286 | char buf[2]; | |
287 | ||
288 | dpy_cursor(s->ds, -1, -1); | |
3023f332 | 289 | qemu_console_resize(s->ds, 2, 1); |
4d3b6f6e AZ |
290 | |
291 | /* TODO: draw the segments */ | |
292 | snprintf(buf, 2, "%02hhx\n", s->segments); | |
293 | console_write_ch(chardata++, 0x00200100 | buf[0]); | |
294 | console_write_ch(chardata++, 0x00200100 | buf[1]); | |
295 | ||
296 | dpy_update(s->ds, 0, 0, 2, 1); | |
297 | } | |
298 | ||
c6017850 | 299 | void jazz_led_init(MemoryRegion *address_space, target_phys_addr_t base) |
31211df1 TS |
300 | { |
301 | LedState *s; | |
31211df1 | 302 | |
7267c094 | 303 | s = g_malloc0(sizeof(LedState)); |
31211df1 | 304 | |
31211df1 TS |
305 | s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND; |
306 | ||
c6017850 AK |
307 | memory_region_init_io(&s->iomem, &led_ops, s, "led", 1); |
308 | memory_region_add_subregion(address_space, base, &s->iomem); | |
31211df1 | 309 | |
3023f332 AL |
310 | s->ds = graphic_console_init(jazz_led_update_display, |
311 | jazz_led_invalidate_display, | |
312 | jazz_led_screen_dump, | |
313 | jazz_led_text_update, s); | |
314 | qemu_console_resize(s->ds, 60, 80); | |
31211df1 | 315 | } |