1 /*
2  * viciivsid-draw.c - Rendering for the MOS6569 (VIC-II) emulation.
3  *
4  * Written by
5  *  Andreas Boose <viceteam@t-online.de>
6  *  Ettore Perazzoli <ettore@comm2000.it>
7  *
8  * This file is part of VICE, the Versatile Commodore Emulator.
9  * See README for copyright notice.
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24  *  02111-1307  USA.
25  *
26  */
27 
28 #include "vice.h"
29 
30 #include <string.h>
31 
32 #include "raster-cache-fill.h"
33 #include "raster-cache-fill-1fff.h"
34 #include "raster-cache-fill-39ff.h"
35 #include "raster-cache-text-ext.h"
36 #include "raster-cache-text-std.h"
37 #include "raster-cache.h"
38 #include "raster-modes.h"
39 #include "raster.h"
40 #include "types.h"
41 #include "vicii-draw.h"
42 #include "viciitypes.h"
43 #include "viewport.h"
44 
45 
46 #define GFX_MSK_LEFTBORDER_SIZE ((VICII_MAX_SPRITE_WIDTH - VICII_RASTER_X(0) \
47                                   + vicii.screen_leftborderwidth ) / 8 + 1)
48 
49 /* The following tables are used to speed up the drawing.  We do not use
50    multi-dimensional arrays as we can optimize better this way...  */
51 
52 /* foreground(4) | background(4) | nibble(4) -> 4 pixels.  */
53 static uint32_t hr_table[16 * 16 * 16];
54 
55 /* mc flag(1) | idx(2) | byte(8) -> index into double-pixel table.  */
56 static uint8_t mc_table[3 * 256];
57 static uint8_t mcmsktable[256];
58 
59 
60 /* These functions draw the background from `start_pixel' to `end_pixel'.  */
61 
draw_std_background(unsigned int start_pixel,unsigned int end_pixel)62 static void draw_std_background(unsigned int start_pixel,
63                                 unsigned int end_pixel)
64 {
65     uint8_t background_color;
66     unsigned int gfxstart, gfxend;
67 
68     background_color = (uint8_t)vicii.raster.background_color;
69 
70     if (VICII_IS_ILLEGAL_MODE(vicii.raster.video_mode)) {
71         background_color = 0;
72     }
73 
74     gfxstart = vicii.raster.geometry->gfx_position.x + vicii.raster.xsmooth;
75     gfxend = gfxstart + vicii.raster.geometry->gfx_size.width;
76 
77     if (start_pixel < gfxstart) {
78         if (end_pixel < gfxstart) {
79             memset(vicii.raster.draw_buffer_ptr + start_pixel,
80                    vicii.raster.xsmooth_color,
81                    end_pixel - start_pixel + 1);
82         } else {
83             if (end_pixel < gfxend) {
84                 memset(vicii.raster.draw_buffer_ptr + start_pixel,
85                        vicii.raster.xsmooth_color,
86                        gfxstart - start_pixel);
87                 memset(vicii.raster.draw_buffer_ptr + gfxstart,
88                        background_color,
89                        end_pixel - gfxstart + 1);
90             } else {
91                 memset(vicii.raster.draw_buffer_ptr + start_pixel,
92                        vicii.raster.xsmooth_color,
93                        gfxstart - start_pixel);
94                 memset(vicii.raster.draw_buffer_ptr + gfxstart,
95                        background_color,
96                        gfxend - gfxstart);
97                 memset(vicii.raster.draw_buffer_ptr + gfxend,
98                        vicii.raster.xsmooth_color,
99                        end_pixel - gfxend + 1);
100             }
101         }
102     } else {
103         if (start_pixel < gfxend) {
104             if (end_pixel < gfxend) {
105                 memset(vicii.raster.draw_buffer_ptr + start_pixel,
106                        background_color,
107                        end_pixel - start_pixel + 1);
108             } else {
109                 memset(vicii.raster.draw_buffer_ptr + start_pixel,
110                        background_color,
111                        gfxend - start_pixel);
112                 memset(vicii.raster.draw_buffer_ptr + gfxend,
113                        vicii.raster.xsmooth_color,
114                        end_pixel - gfxend + 1);
115             }
116         } else {
117             memset(vicii.raster.draw_buffer_ptr + start_pixel,
118                    vicii.raster.xsmooth_color,
119                    end_pixel - start_pixel + 1);
120         }
121     }
122 
123     if (vicii.raster.xsmooth_shift_right) {
124         int pos;
125 
126         pos = (start_pixel - vicii.raster.geometry->gfx_position.x) / 8;
127 
128         if (pos >= 0 && pos < VICII_SCREEN_TEXTCOLS) {
129             if (vicii.raster.video_mode == VICII_HIRES_BITMAP_MODE) {
130                 background_color = vicii.vbuf[pos] & 0xf;
131             }
132             if (vicii.raster.video_mode == VICII_EXTENDED_TEXT_MODE) {
133                 int bg_idx;
134 
135                 bg_idx = vicii.vbuf[pos] >> 6;
136 
137                 if (bg_idx > 0) {
138                     background_color = vicii.ext_background_color[bg_idx - 1];
139                 }
140             }
141             if (VICII_IS_ILLEGAL_MODE(vicii.raster.video_mode)) {
142                 background_color = 0;
143             }
144             memset(vicii.raster.draw_buffer_ptr + start_pixel + 8,
145                    background_color, vicii.raster.xsmooth_shift_right);
146         }
147         vicii.raster.xsmooth_shift_right = 0;
148     }
149 }
150 
draw_idle_std_background(unsigned int start_pixel,unsigned int end_pixel)151 static void draw_idle_std_background(unsigned int start_pixel,
152                                      unsigned int end_pixel)
153 {
154     memset(vicii.raster.draw_buffer_ptr + start_pixel,
155            vicii.raster.idle_background_color,
156            end_pixel - start_pixel + 1);
157 }
158 
159 /* If unaligned 32-bit access is not allowed, the graphics is stored in a
160    temporary aligned buffer, and later copied to the real frame buffer.  This
161    is ugly, but should be hopefully faster than accessing 8 bits at a time
162    anyway.  */
163 
164 #ifndef ALLOW_UNALIGNED_ACCESS
165 static uint32_t _aligned_line_buffer[VICII_SCREEN_XPIX / 2 + 1];
166 static uint8_t *const aligned_line_buffer = (uint8_t *)_aligned_line_buffer;
167 #endif
168 
169 
170 /* Pointer to the start of the graphics area on the frame buffer.  */
171 #define GFX_PTR()                 \
172     (vicii.raster.draw_buffer_ptr \
173      + (vicii.screen_leftborderwidth + vicii.raster.xsmooth))
174 
175 #ifdef ALLOW_UNALIGNED_ACCESS
176 #define ALIGN_DRAW_FUNC(name, xs, xe, gfx_msk_ptr) \
177     name(GFX_PTR(), (xs), (xe), (gfx_msk_ptr))
178 #else
179 #define ALIGN_DRAW_FUNC(name, xs, xe, gfx_msk_ptr)           \
180     do {                                                      \
181         name(aligned_line_buffer, (xs), (xe), (gfx_msk_ptr)); \
182         memcpy(GFX_PTR() + (xs) * 8,                          \
183                aligned_line_buffer + (xs) * 8,                \
184                ((xe) - (xs) + 1) * 8);                        \
185     } while (0)
186 #endif
187 
188 
189 /* Standard text mode.  */
190 
get_std_text(raster_cache_t * cache,unsigned int * xs,unsigned int * xe,int rr)191 static int get_std_text(raster_cache_t *cache, unsigned int *xs,
192                         unsigned int *xe, int rr)
193 {
194     int r;
195 
196     if (cache->background_data[0] != vicii.raster.background_color
197         || cache->chargen_ptr != vicii.chargen_ptr) {
198         cache->background_data[0] = vicii.raster.background_color;
199         cache->chargen_ptr = vicii.chargen_ptr;
200         rr = 1;
201     }
202 
203     r = raster_cache_data_fill_text(cache->foreground_data,
204                                     vicii.vbuf,
205                                     vicii.chargen_ptr + vicii.raster.ycounter,
206                                     VICII_SCREEN_TEXTCOLS,
207                                     xs, xe,
208                                     rr);
209 
210     r |= raster_cache_data_fill(cache->color_data_1,
211                                 vicii.cbuf,
212                                 VICII_SCREEN_TEXTCOLS,
213                                 xs, xe,
214                                 rr);
215     return r;
216 }
217 
_draw_std_text(uint8_t * p,unsigned int xs,unsigned int xe,uint8_t * gfx_msk_ptr)218 inline static void _draw_std_text(uint8_t *p, unsigned int xs, unsigned int xe,
219                                   uint8_t *gfx_msk_ptr)
220 {
221     uint32_t *table_ptr;
222     uint8_t *char_ptr, *msk_ptr;
223     unsigned int i;
224 
225     table_ptr = hr_table + (vicii.raster.background_color << 4);
226     char_ptr = vicii.chargen_ptr + vicii.raster.ycounter;
227     msk_ptr = gfx_msk_ptr + GFX_MSK_LEFTBORDER_SIZE;
228 
229     for (i = xs; i <= xe; i++) {
230         uint32_t *ptr = table_ptr + (vicii.cbuf[i] << 8);
231         int d = msk_ptr[i] = char_ptr[vicii.vbuf[i] * 8];
232 
233         *((uint32_t *)p + i * 2) = ptr[d >> 4];
234         *((uint32_t *)p + i * 2 + 1) = ptr[d & 0xf];
235     }
236 }
237 
_draw_std_text_cached(uint8_t * p,unsigned int xs,unsigned int xe,raster_cache_t * cache)238 inline static void _draw_std_text_cached(uint8_t *p, unsigned int xs,
239                                          unsigned int xe,
240                                          raster_cache_t *cache)
241 {
242     uint32_t *table_ptr;
243     uint8_t *msk_ptr, *foreground_data, *color_data;
244     unsigned int i;
245 
246     table_ptr = hr_table + (cache->background_data[0] << 4);
247     msk_ptr = cache->gfx_msk + GFX_MSK_LEFTBORDER_SIZE;
248     foreground_data = cache->foreground_data;
249     color_data = cache->color_data_1;
250 
251     for (i = xs; i <= xe; i++) {
252         uint32_t *ptr = table_ptr + (color_data[i] << 8);
253         int d = msk_ptr[i] = foreground_data[i];
254 
255         *((uint32_t *)p + i * 2) = ptr[d >> 4];
256         *((uint32_t *)p + i * 2 + 1) = ptr[d & 0xf];
257     }
258 }
259 
draw_std_text_cached(raster_cache_t * cache,unsigned int xs,unsigned int xe)260 static void draw_std_text_cached(raster_cache_t *cache, unsigned int xs,
261                                  unsigned int xe)
262 {
263     ALIGN_DRAW_FUNC(_draw_std_text_cached, xs, xe, cache);
264 }
265 
draw_std_text(void)266 static void draw_std_text(void)
267 {
268     ALIGN_DRAW_FUNC(_draw_std_text, 0, VICII_SCREEN_TEXTCOLS - 1,
269                     vicii.raster.gfx_msk);
270 }
271 
272 #define DRAW_STD_TEXT_BYTE(p, b, f) \
273     do {                            \
274         if ((b) & 0x80) {           \
275             *(p) = (f);             \
276         }                           \
277         if ((b) & 0x40) {           \
278             *((p) + 1) = (f);       \
279         }                           \
280         if ((b) & 0x20) {           \
281             *((p) + 2) = (f);       \
282         }                           \
283         if ((b) & 0x10) {           \
284             *((p) + 3) = (f);       \
285         }                           \
286         if ((b) & 0x08) {           \
287             *((p) + 4) = (f);       \
288         }                           \
289         if ((b) & 0x04) {           \
290             *((p) + 5) = (f);       \
291         }                           \
292         if ((b) & 0x02) {           \
293             *((p) + 6) = (f);       \
294         }                           \
295         if ((b) & 0x01) {           \
296             *((p) + 7) = (f);       \
297         }                           \
298     } while (0)
299 
draw_std_text_foreground(unsigned int start_char,unsigned int end_char)300 static void draw_std_text_foreground(unsigned int start_char, unsigned int end_char)
301 {
302     unsigned int i;
303     uint8_t *char_ptr, *msk_ptr, *p;
304 
305     char_ptr = vicii.chargen_ptr + vicii.raster.ycounter;
306     msk_ptr = vicii.raster.gfx_msk + GFX_MSK_LEFTBORDER_SIZE;
307     p = GFX_PTR() + 8 * start_char;
308 
309     for (i = start_char; i <= end_char; i++, p += 8) {
310         uint8_t b, f;
311 
312         b = char_ptr[vicii.vbuf[i - vicii.buf_offset] * 8];
313 
314         if (vicii.raster.last_video_mode == VICII_EXTENDED_TEXT_MODE) {
315             b = char_ptr[(vicii.vbuf[i - vicii.buf_offset] & 0x3f) * 8];
316         }
317 
318         if (vicii.raster.last_video_mode == VICII_HIRES_BITMAP_MODE) {
319             unsigned int j = ((vicii.memptr << 3) + vicii.raster.ycounter + i * 8) & 0x1fff;
320             if (j & 0x1000) {
321                 b = vicii.bitmap_high_ptr[j & 0xfff];
322             } else {
323                 b = vicii.bitmap_low_ptr[j];
324             }
325         }
326 
327         f = vicii.cbuf[i - vicii.buf_offset];
328 
329         if (vicii.raster.xsmooth_shift_left > 0) {
330             b = (b >> vicii.raster.xsmooth_shift_left) << vicii.raster.xsmooth_shift_left;
331         }
332 
333         msk_ptr[i] = b;
334         DRAW_STD_TEXT_BYTE(p, b, f);
335     }
336 }
337 
338 /* Hires Bitmap mode.  */
339 
get_hires_bitmap(raster_cache_t * cache,unsigned int * xs,unsigned int * xe,int rr)340 static int get_hires_bitmap(raster_cache_t *cache, unsigned int *xs, unsigned int *xe, int rr)
341 {
342     int r;
343 
344     r = raster_cache_data_fill(cache->background_data,
345                                vicii.vbuf,
346                                VICII_SCREEN_TEXTCOLS,
347                                xs, xe,
348                                rr);
349     r |= raster_cache_data_fill_1fff(cache->foreground_data,
350                                      vicii.bitmap_low_ptr,
351                                      vicii.bitmap_high_ptr,
352                                      vicii.memptr * 8 + vicii.raster.ycounter,
353                                      VICII_SCREEN_TEXTCOLS,
354                                      xs, xe,
355                                      rr);
356     return r;
357 }
358 
_draw_hires_bitmap(uint8_t * p,unsigned int xs,unsigned int xe,uint8_t * gfx_msk_ptr)359 inline static void _draw_hires_bitmap(uint8_t *p, unsigned int xs,
360                                       unsigned int xe, uint8_t *gfx_msk_ptr)
361 {
362     uint8_t *bmptr_low, *bmptr_high, *msk_ptr;
363     uint8_t bmval;
364     unsigned int i, j;
365 
366     bmptr_low = vicii.bitmap_low_ptr;
367     bmptr_high = vicii.bitmap_high_ptr;
368     msk_ptr = gfx_msk_ptr + GFX_MSK_LEFTBORDER_SIZE;
369 
370     for (j = ((vicii.memptr << 3) + vicii.raster.ycounter + xs * 8) & 0x1fff, i = xs;
371          i <= xe; i++, j = (j + 8) & 0x1fff) {
372         uint32_t *ptr = hr_table + (vicii.vbuf[i] << 4);
373         int d;
374 
375         if (j & 0x1000) {
376             bmval = bmptr_high[j & 0xfff];
377         } else {
378             bmval = bmptr_low[j];
379         }
380 
381         d = msk_ptr[i] = bmval;
382         *((uint32_t *)p + i * 2) = ptr[d >> 4];
383         *((uint32_t *)p + i * 2 + 1) = ptr[d & 0xf];
384     }
385 }
386 
_draw_hires_bitmap_cached(uint8_t * p,unsigned int xs,unsigned int xe,raster_cache_t * cache)387 inline static void _draw_hires_bitmap_cached(uint8_t *p, unsigned int xs,
388                                              unsigned int xe,
389                                              raster_cache_t *cache)
390 {
391     uint8_t *foreground_data, *background_data, *msk_ptr;
392     unsigned int i;
393 
394     foreground_data = cache->foreground_data;
395     background_data = cache->background_data;
396     msk_ptr = cache->gfx_msk + GFX_MSK_LEFTBORDER_SIZE;
397 
398     for (i = xs; i <= xe; i++) {
399         uint32_t *ptr = hr_table + (background_data[i] << 4);
400         int d;
401 
402         d = msk_ptr[i] = foreground_data[i];
403         *((uint32_t *)p + i * 2) = ptr[d >> 4];
404         *((uint32_t *)p + i * 2 + 1) = ptr[d & 0xf];
405     }
406 }
407 
draw_hires_bitmap(void)408 static void draw_hires_bitmap(void)
409 {
410     ALIGN_DRAW_FUNC(_draw_hires_bitmap, 0, VICII_SCREEN_TEXTCOLS - 1,
411                     vicii.raster.gfx_msk);
412 }
413 
draw_hires_bitmap_cached(raster_cache_t * cache,unsigned int xs,unsigned int xe)414 static void draw_hires_bitmap_cached(raster_cache_t *cache, unsigned int xs,
415                                      unsigned int xe)
416 {
417     ALIGN_DRAW_FUNC(_draw_hires_bitmap_cached, xs, xe, cache);
418 }
419 
_draw_hires_bitmap_foreground(uint8_t * p,unsigned int xs,unsigned int xe,uint8_t * gfx_msk_ptr)420 inline static void _draw_hires_bitmap_foreground(uint8_t *p, unsigned int xs,
421                                                  unsigned int xe,
422                                                  uint8_t *gfx_msk_ptr)
423 {
424     uint8_t *bmptr_low, *bmptr_high, *msk_ptr;
425     uint8_t bmval;
426     unsigned int i, j;
427 
428     bmptr_low = vicii.bitmap_low_ptr;
429     bmptr_high = vicii.bitmap_high_ptr;
430     msk_ptr = gfx_msk_ptr + GFX_MSK_LEFTBORDER_SIZE;
431 
432     for (j = ((vicii.memptr << 3) + vicii.raster.ycounter + xs * 8) & 0x1fff, i = xs;
433          i <= xe; i++, j = (j + 8) & 0x1fff) {
434         uint32_t *ptr = hr_table + (vicii.vbuf[i - vicii.buf_offset] << 4);
435         int d;
436 
437         if (vicii.raster.last_video_mode == VICII_ILLEGAL_BITMAP_MODE_1) {
438             j &= 0x19ff;
439         }
440 
441         if (j & 0x1000) {
442             bmval = bmptr_high[j & 0xfff];
443         } else {
444             bmval = bmptr_low[j];
445         }
446 
447         if (vicii.raster.last_video_mode == VICII_NORMAL_TEXT_MODE) {
448             uint8_t *char_ptr = vicii.chargen_ptr + vicii.raster.ycounter;
449             bmval = char_ptr[vicii.vbuf[i - vicii.buf_offset] * 8];
450         }
451 
452         d = msk_ptr[i] = bmval;
453 
454         *((uint32_t *)p + i * 2) = ptr[d >> 4];
455         *((uint32_t *)p + i * 2 + 1) = ptr[d & 0xf];
456     }
457 }
458 
draw_hires_bitmap_foreground(unsigned int start_char,unsigned int end_char)459 static void draw_hires_bitmap_foreground(unsigned int start_char,
460                                          unsigned int end_char)
461 {
462     ALIGN_DRAW_FUNC(_draw_hires_bitmap_foreground, start_char, end_char,
463                     vicii.raster.gfx_msk);
464 }
465 
466 /* Multicolor text mode.  */
467 
get_mc_text(raster_cache_t * cache,unsigned int * xs,unsigned int * xe,int rr)468 static int get_mc_text(raster_cache_t *cache, unsigned int *xs,
469                        unsigned int *xe, int rr)
470 {
471     int r;
472 
473     if (cache->background_data[0] != vicii.raster.background_color
474         || cache->color_data_1[0] != vicii.ext_background_color[0]
475         || cache->color_data_1[1] != vicii.ext_background_color[1]
476         || cache->chargen_ptr != vicii.chargen_ptr) {
477         cache->background_data[0] = vicii.raster.background_color;
478         cache->color_data_1[0] = vicii.ext_background_color[0];
479         cache->color_data_1[1] = vicii.ext_background_color[1];
480         cache->chargen_ptr = vicii.chargen_ptr;
481         rr = 1;
482     }
483 
484     r = raster_cache_data_fill_text(cache->foreground_data,
485                                     vicii.vbuf,
486                                     vicii.chargen_ptr + vicii.raster.ycounter,
487                                     VICII_SCREEN_TEXTCOLS,
488                                     xs, xe,
489                                     rr);
490     r |= raster_cache_data_fill(cache->color_data_3,
491                                 vicii.cbuf,
492                                 VICII_SCREEN_TEXTCOLS,
493                                 xs, xe,
494                                 rr);
495     return r;
496 }
497 
_draw_mc_text(uint8_t * p,unsigned int xs,unsigned int xe,uint8_t * gfx_msk_ptr)498 inline static void _draw_mc_text(uint8_t *p, unsigned int xs, unsigned int xe,
499                                  uint8_t *gfx_msk_ptr)
500 {
501     uint8_t c[8];
502     uint32_t *table_ptr;
503     uint8_t *char_ptr, *msk_ptr;
504     uint16_t *ptmp;
505     unsigned int i;
506 
507     table_ptr = hr_table + (vicii.raster.background_color << 4);
508     char_ptr = vicii.chargen_ptr + vicii.raster.ycounter;
509     msk_ptr = gfx_msk_ptr + GFX_MSK_LEFTBORDER_SIZE;
510 
511     c[1] = c[0] = vicii.raster.background_color;
512     c[3] = c[2] = vicii.ext_background_color[0];
513     c[5] = c[4] = vicii.ext_background_color[1];
514 
515     ptmp = (uint16_t *)(p + xs * 8);
516 
517     for (i = xs; i <= xe; i++) {
518         if (vicii.cbuf[i] & 0x8) {
519             unsigned int d;
520 
521             c[7] = c[6] = vicii.cbuf[i] & 0x7;
522 
523             d = char_ptr[vicii.vbuf[i] * 8];
524 
525             msk_ptr[i] = mcmsktable[d];
526 
527             ptmp[0] = ((uint16_t *)c)[mc_table[d]];
528             ptmp[1] = ((uint16_t *)c)[mc_table[0x100 + d]];
529             ptmp[2] = ((uint16_t *)c)[mc_table[0x200 + d]];
530             ptmp[3] = ((uint16_t *)c)[d & 3];
531             ptmp += 4;
532         } else {
533             uint32_t *ptr = table_ptr + (vicii.cbuf[i] << 8);
534             int d = msk_ptr[i] = char_ptr[vicii.vbuf[i] * 8];
535 
536             *((uint32_t *)ptmp) = ptr[d >> 4];
537             *((uint32_t *)(ptmp + 2)) = ptr[d & 0xf];
538             ptmp += 4;
539         }
540     }
541 }
542 
_draw_mc_text_cached(uint8_t * p,unsigned int xs,unsigned int xe,raster_cache_t * cache)543 inline static void _draw_mc_text_cached(uint8_t *p, unsigned int xs, unsigned int xe, raster_cache_t *cache)
544 {
545     uint8_t c[8];
546     uint32_t *table_ptr;
547     uint8_t *foreground_data, *color_data_3, *msk_ptr;
548     uint16_t *ptmp;
549     unsigned int i;
550 
551     foreground_data = cache->foreground_data;
552     color_data_3 = cache->color_data_3;
553     table_ptr = hr_table + (cache->background_data[0] << 4);
554     msk_ptr = cache->gfx_msk + GFX_MSK_LEFTBORDER_SIZE;
555 
556     c[1] = c[0] = cache->background_data[0];
557     c[3] = c[2] = cache->color_data_1[0];
558     c[5] = c[4] = cache->color_data_1[1];
559 
560     ptmp = (uint16_t *)(p + xs * 8);
561 
562     for (i = xs; i <= xe; i++) {
563         if (color_data_3[i] & 0x8) {
564             unsigned int d;
565 
566             c[7] = c[6] = color_data_3[i] & 0x7;
567 
568             d = foreground_data[i];
569 
570             msk_ptr[i] = mcmsktable[d];
571 
572             ptmp[0] = ((uint16_t *)c)[mc_table[d]];
573             ptmp[1] = ((uint16_t *)c)[mc_table[0x100 + d]];
574             ptmp[2] = ((uint16_t *)c)[mc_table[0x200 + d]];
575             ptmp[3] = ((uint16_t *)c)[d & 3];
576             ptmp += 4;
577         } else {
578             uint32_t *ptr = table_ptr + (color_data_3[i] << 8);
579             int d = msk_ptr[i] = foreground_data[i];
580 
581             *((uint32_t *)ptmp) = ptr[d >> 4];
582             *((uint32_t *)(ptmp + 2)) = ptr[d & 0xf];
583             ptmp += 4;
584         }
585     }
586 }
587 
draw_mc_text(void)588 static void draw_mc_text(void)
589 {
590     ALIGN_DRAW_FUNC(_draw_mc_text, 0, VICII_SCREEN_TEXTCOLS - 1,
591                     vicii.raster.gfx_msk);
592 }
593 
draw_mc_text_cached(raster_cache_t * cache,unsigned int xs,unsigned int xe)594 static void draw_mc_text_cached(raster_cache_t *cache, unsigned int xs,
595                                 unsigned int xe)
596 {
597     ALIGN_DRAW_FUNC(_draw_mc_text_cached, xs, xe, cache);
598 }
599 
600 /* FIXME: aligned/unaligned versions.  */
601 #define DRAW_MC_BYTE(p, b, f1, f2, f3)          \
602     do {                                        \
603         if ((b) & 0x80) {                       \
604             if ((b) & 0x40) {                   \
605                 *(p) = *((p) + 1) = (f3);       \
606             } else {                            \
607                 *(p) = *((p) + 1) = (f2);       \
608             }                                   \
609         } else if ((b) & 0x40) {                \
610             *(p) = *((p) + 1) = (f1);           \
611         }                                       \
612                                                 \
613         if ((b) & 0x20) {                       \
614             if ((b) & 0x10) {                   \
615                 *((p) + 2) = *((p) + 3) = (f3); \
616             } else {                            \
617                 *((p) + 2) = *((p) + 3) = (f2); \
618             }                                   \
619         } else if ((b) & 0x10) {                \
620             *((p) + 2) = *((p) + 3) = (f1);     \
621         }                                       \
622                                                 \
623         if ((b) & 0x08) {                       \
624             if ((b) & 0x04) {                   \
625                 *((p) + 4) = *((p) + 5) = (f3); \
626             } else {                            \
627                 *((p) + 4) = *((p) + 5) = (f2); \
628             }                                   \
629         } else if ((b) & 0x04) {                \
630             *((p) + 4) = *((p) + 5) = (f1);     \
631         }                                       \
632                                                 \
633         if ((b) & 0x02) {                       \
634             if ((b) & 0x01) {                   \
635                 *((p) + 6) = *((p) + 7) = (f3); \
636             } else {                            \
637                 *((p) + 6) = *((p) + 7) = (f2); \
638             }                                   \
639         } else if ((b) & 0x01) {                \
640             *((p) + 6) = *((p) + 7) = (f1);     \
641         }                                       \
642     } while (0)
643 
draw_mc_text_foreground(unsigned int start_char,unsigned int end_char)644 static void draw_mc_text_foreground(unsigned int start_char, unsigned int end_char)
645 {
646     uint8_t *char_ptr, *msk_ptr;
647     uint8_t c1, c2;
648     uint8_t *p;
649     unsigned int i;
650 
651     char_ptr = vicii.chargen_ptr + vicii.raster.ycounter;
652     msk_ptr = vicii.raster.gfx_msk + GFX_MSK_LEFTBORDER_SIZE;
653     c1 = vicii.ext_background_color[0];
654     c2 = vicii.ext_background_color[1];
655     p = GFX_PTR() + 8 * start_char;
656 
657     for (i = start_char; i <= end_char; i++, p += 8) {
658         uint8_t b, c;
659 
660         c = vicii.cbuf[i - vicii.buf_offset];
661         if (vicii.raster.last_video_mode == VICII_MULTICOLOR_BITMAP_MODE) {
662             unsigned int j = ((vicii.memptr << 3) + vicii.raster.ycounter + i * 8) & 0x1fff;
663             if (j & 0x1000) {
664                 b = vicii.bitmap_high_ptr[j & 0xfff];
665             } else {
666                 b = vicii.bitmap_low_ptr[j];
667             }
668         } else {
669             b = char_ptr[vicii.vbuf[i - vicii.buf_offset] * 8];
670         }
671 
672         if (c & 0x8) {
673             uint8_t c3;
674             uint8_t orig_background = *p;
675 
676             c3 = c & 0x7;
677             DRAW_MC_BYTE(p, b, c1, c2, c3);
678             msk_ptr[i] = mcmsktable[b];
679 
680             if (vicii.raster.xsmooth_shift_left > 0) {
681                 int j;
682 
683                 for (j = 0; j < vicii.raster.xsmooth_shift_left; j++) {
684                     p[7 - j] = orig_background;
685                 }
686 
687                 msk_ptr[i] = (uint8_t)((mcmsktable[b]
688                                      >> vicii.raster.xsmooth_shift_left)
689                                     << vicii.raster.xsmooth_shift_left);
690             }
691         } else {
692             uint8_t c3;
693 
694             if (vicii.raster.xsmooth_shift_left > 0) {
695                 b = (b >> vicii.raster.xsmooth_shift_left) << vicii.raster.xsmooth_shift_left;
696             }
697 
698             c3 = c;
699             DRAW_STD_TEXT_BYTE(p, b, c3);
700             msk_ptr[i] = b;
701         }
702     }
703 }
704 
705 /* Multicolor Bitmap Mode.  */
706 
get_mc_bitmap(raster_cache_t * cache,unsigned int * xs,unsigned int * xe,int rr)707 static int get_mc_bitmap(raster_cache_t *cache, unsigned int *xs,
708                          unsigned int *xe, int rr)
709 {
710     int r;
711 
712     if (cache->background_data[0] != vicii.raster.background_color) {
713         cache->background_data[0] = vicii.raster.background_color;
714         rr = 1;
715     }
716 
717     r = raster_cache_data_fill(cache->color_data_1,
718                                vicii.vbuf,
719                                VICII_SCREEN_TEXTCOLS,
720                                xs, xe,
721                                rr);
722     r |= raster_cache_data_fill(cache->color_data_3,
723                                 vicii.cbuf,
724                                 VICII_SCREEN_TEXTCOLS,
725                                 xs, xe,
726                                 rr);
727     r |= raster_cache_data_fill_1fff(cache->foreground_data,
728                                      vicii.bitmap_low_ptr,
729                                      vicii.bitmap_high_ptr,
730                                      8 * vicii.memptr + vicii.raster.ycounter,
731                                      VICII_SCREEN_TEXTCOLS,
732                                      xs, xe,
733                                      rr);
734     return r;
735 }
736 
_draw_mc_bitmap(uint8_t * p,unsigned int xs,unsigned int xe,uint8_t * gfx_msk_ptr)737 inline static void _draw_mc_bitmap(uint8_t *p, unsigned int xs, unsigned int xe,
738                                    uint8_t *gfx_msk_ptr)
739 {
740     uint8_t *colptr, *bmptr_low, *bmptr_high, *msk_ptr, *ptmp;
741     uint8_t c[4];
742     unsigned int i, j;
743 
744     colptr = vicii.cbuf;
745     bmptr_low = vicii.bitmap_low_ptr;
746     bmptr_high = vicii.bitmap_high_ptr;
747     msk_ptr = gfx_msk_ptr + GFX_MSK_LEFTBORDER_SIZE;
748 
749     c[0] = vicii.raster.background_color;
750 
751     ptmp = p + xs * 8;
752 
753     for (j = ((vicii.memptr << 3) + vicii.raster.ycounter + xs * 8) & 0x1fff,
754          i = xs; i <= xe; i++, j = (j + 8) & 0x1fff) {
755         unsigned int d;
756 
757         if (j & 0x1000) {
758             d = bmptr_high[j & 0xfff];
759         } else {
760             d = bmptr_low[j];
761         }
762 
763         msk_ptr[i] = mcmsktable[d];
764 
765         c[1] = vicii.vbuf[i] >> 4;
766         c[2] = vicii.vbuf[i] & 0xf;
767         c[3] = colptr[i];
768 
769         ptmp[1] = ptmp[0] = c[mc_table[d]];
770         ptmp[3] = ptmp[2] = c[mc_table[0x100 + d]];
771         ptmp[5] = ptmp[4] = c[mc_table[0x200 + d]];
772         ptmp[7] = ptmp[6] = c[d & 3];
773         ptmp += 8;
774     }
775 }
776 
_draw_mc_bitmap_cached(uint8_t * p,unsigned int xs,unsigned int xe,raster_cache_t * cache)777 inline static void _draw_mc_bitmap_cached(uint8_t *p, unsigned int xs,
778                                           unsigned int xe,
779                                           raster_cache_t *cache)
780 {
781     uint8_t *foreground_data, *color_data_1, *color_data_3;
782     uint8_t *msk_ptr, *ptmp;
783     uint8_t c[4];
784     unsigned int i;
785 
786     foreground_data = cache->foreground_data;
787     color_data_1 = cache->color_data_1;
788     color_data_3 = cache->color_data_3;
789     msk_ptr = cache->gfx_msk + GFX_MSK_LEFTBORDER_SIZE;
790 
791     c[0] = cache->background_data[0];
792 
793     ptmp = p + xs * 8;
794 
795     for (i = xs; i <= xe; i++) {
796         unsigned int d;
797 
798         d = foreground_data[i];
799 
800         msk_ptr[i] = mcmsktable[d];
801 
802         c[1] = color_data_1[i] >> 4;
803         c[2] = color_data_1[i] & 0xf;
804         c[3] = color_data_3[i];
805 
806         ptmp[1] = ptmp[0] = c[mc_table[d]];
807         ptmp[3] = ptmp[2] = c[mc_table[0x100 + d]];
808         ptmp[5] = ptmp[4] = c[mc_table[0x200 + d]];
809         ptmp[7] = ptmp[6] = c[d & 3];
810         ptmp += 8;
811     }
812 }
813 
draw_mc_bitmap(void)814 static void draw_mc_bitmap(void)
815 {
816     _draw_mc_bitmap(GFX_PTR(), 0, VICII_SCREEN_TEXTCOLS - 1,
817                     vicii.raster.gfx_msk);
818 }
819 
draw_mc_bitmap_cached(raster_cache_t * cache,unsigned int xs,unsigned int xe)820 static void draw_mc_bitmap_cached(raster_cache_t *cache, unsigned int xs,
821                                   unsigned int xe)
822 {
823     _draw_mc_bitmap_cached(GFX_PTR(), xs, xe, cache);
824 }
825 
draw_mc_bitmap_foreground(unsigned int start_char,unsigned int end_char)826 static void draw_mc_bitmap_foreground(unsigned int start_char,
827                                       unsigned int end_char)
828 {
829     uint8_t *p, *bmptr_low, *bmptr_high, *msk_ptr;
830     unsigned int i, j;
831 
832     p = GFX_PTR() + 8 * start_char;
833     bmptr_low = vicii.bitmap_low_ptr;
834     bmptr_high = vicii.bitmap_high_ptr;
835     msk_ptr = vicii.raster.gfx_msk + GFX_MSK_LEFTBORDER_SIZE;
836 
837     for (j = ((vicii.memptr << 3) + vicii.raster.ycounter + 8 * start_char) & 0x1fff,
838          i = start_char; i <= end_char; j = (j + 8) & 0x1fff, i++, p += 8) {
839         uint8_t c1, c2, c3;
840         uint8_t b;
841         uint8_t orig_background = *p;
842 
843         c1 = vicii.vbuf[i - vicii.buf_offset] >> 4;
844         c2 = vicii.vbuf[i - vicii.buf_offset] & 0xf;
845         c3 = vicii.cbuf[i - vicii.buf_offset];
846 
847         if (vicii.raster.last_video_mode == VICII_ILLEGAL_BITMAP_MODE_2) {
848             j &= 0x19ff;
849         }
850 
851         if (j & 0x1000) {
852             b = bmptr_high[j & 0xfff];
853         } else {
854             b = bmptr_low[j];
855         }
856 
857         if (vicii.raster.last_video_mode == VICII_MULTICOLOR_TEXT_MODE
858             || vicii.raster.last_video_mode == VICII_ILLEGAL_TEXT_MODE) {
859             uint8_t *char_ptr = vicii.chargen_ptr + vicii.raster.ycounter;
860             b = char_ptr[vicii.vbuf[i - vicii.buf_offset] * 8];
861         }
862 
863         msk_ptr[i] = mcmsktable[b];
864         DRAW_MC_BYTE(p, b, c1, c2, c3);
865 
866         if (vicii.raster.xsmooth_shift_left > 0) {
867             int k;
868 
869             for (k = 0; k < vicii.raster.xsmooth_shift_left; k++) {
870                 p[7 - k] = orig_background;
871             }
872 
873             msk_ptr[i] = (uint8_t)((mcmsktable[b]
874                                  >> vicii.raster.xsmooth_shift_left)
875                                 << vicii.raster.xsmooth_shift_left);
876         }
877     }
878 }
879 
880 /* Extended Text Mode.  */
881 
get_ext_text(raster_cache_t * cache,unsigned int * xs,unsigned int * xe,int rr)882 static int get_ext_text(raster_cache_t *cache, unsigned int *xs,
883                         unsigned int *xe, int rr)
884 {
885     int r;
886 
887     if (cache->color_data_2[0] != vicii.raster.background_color
888         || cache->color_data_2[1] != vicii.ext_background_color[0]
889         || cache->color_data_2[2] != vicii.ext_background_color[1]
890         || cache->color_data_2[3] != vicii.ext_background_color[2]
891         || cache->chargen_ptr != vicii.chargen_ptr) {
892         cache->color_data_2[0] = vicii.raster.background_color;
893         cache->color_data_2[1] = vicii.ext_background_color[0];
894         cache->color_data_2[2] = vicii.ext_background_color[1];
895         cache->color_data_2[3] = vicii.ext_background_color[2];
896         cache->chargen_ptr = vicii.chargen_ptr;
897         rr = 1;
898     }
899 
900     r = raster_cache_data_fill_text_ext(cache->foreground_data,
901                                         cache->color_data_3,
902                                         vicii.vbuf,
903                                         vicii.chargen_ptr,
904                                         8,
905                                         VICII_SCREEN_TEXTCOLS,
906                                         vicii.raster.ycounter,
907                                         xs, xe,
908                                         rr);
909 
910     r |= raster_cache_data_fill(cache->color_data_1,
911                                 vicii.cbuf,
912                                 VICII_SCREEN_TEXTCOLS,
913                                 xs, xe,
914                                 rr);
915     return r;
916 }
917 
_draw_ext_text(uint8_t * p,unsigned int xs,unsigned int xe,uint8_t * gfx_msk_ptr)918 inline static void _draw_ext_text(uint8_t *p, unsigned int xs, unsigned int xe,
919                                   uint8_t *gfx_msk_ptr)
920 {
921     uint8_t *char_ptr, *msk_ptr;
922     unsigned int i;
923 
924     char_ptr = vicii.chargen_ptr + vicii.raster.ycounter;
925     msk_ptr = gfx_msk_ptr + GFX_MSK_LEFTBORDER_SIZE;
926 
927     for (i = xs; i <= xe; i++) {
928         uint32_t *ptr;
929         int bg_idx;
930         int d;
931 
932         ptr = hr_table + (vicii.cbuf[i] << 8);
933         bg_idx = vicii.vbuf[i] >> 6;
934         d = char_ptr[(vicii.vbuf[i] & 0x3f) * 8];
935 
936         if (bg_idx == 0) {
937             ptr += vicii.raster.background_color << 4;
938         } else {
939             ptr += vicii.ext_background_color[bg_idx - 1] << 4;
940         }
941 
942         msk_ptr[i] = d;
943         *((uint32_t *)p + 2 * i) = ptr[d >> 4];
944         *((uint32_t *)p + 2 * i + 1) = ptr[d & 0xf];
945     }
946 }
947 
_draw_ext_text_cached(uint8_t * p,unsigned int xs,unsigned int xe,raster_cache_t * cache)948 inline static void _draw_ext_text_cached(uint8_t *p, unsigned int xs,
949                                          unsigned int xe,
950                                          raster_cache_t *cache)
951 {
952     uint8_t *foreground_data, *color_data_1, *color_data_2, *color_data_3;
953     uint8_t *msk_ptr;
954     unsigned int i;
955 
956     foreground_data = cache->foreground_data;
957     color_data_1 = cache->color_data_1;
958     color_data_2 = cache->color_data_2;
959     color_data_3 = cache->color_data_3;
960     msk_ptr = cache->gfx_msk + GFX_MSK_LEFTBORDER_SIZE;
961 
962     for (i = xs; i <= xe; i++) {
963         uint32_t *ptr;
964         int d;
965 
966         ptr = hr_table + (color_data_1[i] << 8);
967         d = foreground_data[i];
968 
969         ptr += color_data_2[color_data_3[i]] << 4;
970 
971         msk_ptr[i] = d;
972         *((uint32_t *)p + 2 * i) = ptr[d >> 4];
973         *((uint32_t *)p + 2 * i + 1) = ptr[d & 0xf];
974     }
975 }
976 
draw_ext_text(void)977 static void draw_ext_text(void)
978 {
979     ALIGN_DRAW_FUNC(_draw_ext_text, 0, VICII_SCREEN_TEXTCOLS - 1,
980                     vicii.raster.gfx_msk);
981 }
982 
draw_ext_text_cached(raster_cache_t * cache,unsigned int xs,unsigned int xe)983 static void draw_ext_text_cached(raster_cache_t *cache, unsigned int xs,
984                                  unsigned int xe)
985 {
986     ALIGN_DRAW_FUNC(_draw_ext_text_cached, xs, xe, cache);
987 }
988 
draw_ext_text_foreground(unsigned int start_char,unsigned int end_char)989 static void draw_ext_text_foreground(unsigned int start_char,
990                                      unsigned int end_char)
991 {
992     unsigned int i;
993     uint8_t *char_ptr, *msk_ptr, *p;
994 
995     char_ptr = vicii.chargen_ptr + vicii.raster.ycounter;
996     msk_ptr = vicii.raster.gfx_msk + GFX_MSK_LEFTBORDER_SIZE;
997     p = GFX_PTR() + 8 * start_char;
998 
999     for (i = start_char; i <= end_char; i++, p += 8) {
1000         uint8_t b, f;
1001         int bg_idx;
1002 
1003         b = char_ptr[(vicii.vbuf[i - vicii.buf_offset] & 0x3f) * 8];
1004 
1005         if (vicii.raster.last_video_mode == VICII_ILLEGAL_BITMAP_MODE_1) {
1006             unsigned int j = ((vicii.memptr << 3) + vicii.raster.ycounter + i * 8) & 0x19ff;
1007             if (j & 0x1000) {
1008                 b = vicii.bitmap_high_ptr[j & 0xfff];
1009             } else {
1010                 b = vicii.bitmap_low_ptr[j];
1011             }
1012         }
1013 
1014         f = vicii.cbuf[i - vicii.buf_offset];
1015         bg_idx = vicii.vbuf[i - vicii.buf_offset] >> 6;
1016 
1017         if (vicii.raster.xsmooth_shift_left > 0) {
1018             b = (b >> vicii.raster.xsmooth_shift_left) << vicii.raster.xsmooth_shift_left;
1019         }
1020 
1021         if (bg_idx > 0) {
1022             p[7] = p[6] = p[5] = p[4] = p[3] = p[2] = p[1] = p[0] = vicii.ext_background_color[bg_idx - 1];
1023         }
1024 
1025         msk_ptr[i] = b;
1026         DRAW_STD_TEXT_BYTE(p, b, f);
1027     }
1028 }
1029 
1030 /* Illegal text mode.  */
1031 
get_illegal_text(raster_cache_t * cache,unsigned int * xs,unsigned int * xe,int rr)1032 static int get_illegal_text(raster_cache_t *cache, unsigned int *xs,
1033                             unsigned int *xe, int rr)
1034 {
1035     int r;
1036 
1037     if (cache->chargen_ptr != vicii.chargen_ptr) {
1038         cache->chargen_ptr = vicii.chargen_ptr;
1039         rr = 1;
1040     }
1041 
1042     r = raster_cache_data_fill_text_ext(cache->foreground_data,
1043                                         cache->color_data_3,
1044                                         vicii.vbuf,
1045                                         vicii.chargen_ptr,
1046                                         8,
1047                                         VICII_SCREEN_TEXTCOLS,
1048                                         vicii.raster.ycounter,
1049                                         xs, xe,
1050                                         rr);
1051 
1052     r |= raster_cache_data_fill(cache->color_data_1,
1053                                 vicii.cbuf,
1054                                 VICII_SCREEN_TEXTCOLS,
1055                                 xs, xe,
1056                                 rr);
1057     return r;
1058 }
1059 
_draw_illegal_text(uint8_t * p,unsigned int xs,unsigned int xe,uint8_t * gfx_msk_ptr)1060 inline static void _draw_illegal_text(uint8_t *p, unsigned int xs,
1061                                       unsigned int xe, uint8_t *gfx_msk_ptr)
1062 {
1063     uint8_t *char_ptr, *msk_ptr;
1064     unsigned int i;
1065 
1066     char_ptr = vicii.chargen_ptr + vicii.raster.ycounter;
1067     msk_ptr = gfx_msk_ptr + GFX_MSK_LEFTBORDER_SIZE;
1068 
1069     memset(p + 8 * xs, 0, (xe - xs + 1) * 8);
1070 
1071     for (i = xs; i <= xe; i++) {
1072         unsigned int d;
1073 
1074         d = char_ptr[(vicii.vbuf[i] & 0x3f) * 8];
1075 
1076         msk_ptr[i] = (vicii.cbuf[i] & 0x8) ? mcmsktable[d] : d;
1077     }
1078 }
1079 
_draw_illegal_text_cached(uint8_t * p,unsigned int xs,unsigned int xe,raster_cache_t * cache)1080 inline static void _draw_illegal_text_cached(uint8_t *p, unsigned int xs,
1081                                              unsigned int xe,
1082                                              raster_cache_t *cache)
1083 {
1084     uint8_t *foreground_data, *color_data_1, *msk_ptr;
1085     unsigned int i;
1086 
1087     foreground_data = cache->foreground_data;
1088     color_data_1 = cache->color_data_1;
1089     msk_ptr = cache->gfx_msk + GFX_MSK_LEFTBORDER_SIZE;
1090 
1091     memset(p + 8 * xs, 0, (xe - xs + 1) * 8);
1092 
1093     for (i = xs; i <= xe; i++) {
1094         unsigned int d;
1095 
1096         d = foreground_data[i];
1097 
1098         msk_ptr[i] = (color_data_1[i] & 0x8) ? mcmsktable[d] : d;
1099     }
1100 }
1101 
draw_illegal_text(void)1102 static void draw_illegal_text(void)
1103 {
1104     _draw_illegal_text(GFX_PTR(), 0, VICII_SCREEN_TEXTCOLS - 1,
1105                        vicii.raster.gfx_msk);
1106 }
1107 
draw_illegal_text_cached(raster_cache_t * cache,unsigned int xs,unsigned int xe)1108 static void draw_illegal_text_cached(raster_cache_t *cache, unsigned int xs,
1109                                      unsigned int xe)
1110 {
1111     _draw_illegal_text_cached(GFX_PTR(), xs, xe, cache);
1112 }
1113 
draw_illegal_text_foreground(unsigned int start_char,unsigned int end_char)1114 static void draw_illegal_text_foreground(unsigned int start_char,
1115                                          unsigned int end_char)
1116 {
1117     uint8_t *char_ptr, *msk_ptr, *p;
1118     unsigned int i;
1119 
1120     char_ptr = vicii.chargen_ptr + vicii.raster.ycounter;
1121     msk_ptr = vicii.raster.gfx_msk + GFX_MSK_LEFTBORDER_SIZE;
1122     p = GFX_PTR() + 8 * start_char;
1123 
1124     memset(p, 0, (end_char - start_char + 1) * 8);
1125 
1126     for (i = start_char; i <= end_char; i++) {
1127         unsigned int d;
1128 
1129         d = char_ptr[(vicii.vbuf[i - vicii.buf_offset] & 0x3f) * 8];
1130 
1131         msk_ptr[i] = (vicii.cbuf[i - vicii.buf_offset] & 0x8) ? mcmsktable[d] : d;
1132     }
1133 }
1134 
1135 /* Illegal bitmap mode 1.  */
1136 
get_illegal_bitmap_mode1(raster_cache_t * cache,unsigned int * xs,unsigned int * xe,int rr)1137 static int get_illegal_bitmap_mode1(raster_cache_t *cache, unsigned int *xs,
1138                                     unsigned int *xe, int rr)
1139 {
1140     int r;
1141 
1142     r = raster_cache_data_fill(cache->background_data,
1143                                vicii.vbuf,
1144                                VICII_SCREEN_TEXTCOLS,
1145                                xs, xe,
1146                                rr);
1147     r |= raster_cache_data_fill_39ff(cache->foreground_data,
1148                                      vicii.bitmap_low_ptr,
1149                                      vicii.bitmap_high_ptr,
1150                                      vicii.memptr * 8
1151                                      + vicii.raster.ycounter,
1152                                      VICII_SCREEN_TEXTCOLS,
1153                                      8,
1154                                      xs, xe,
1155                                      rr);
1156     return r;
1157 }
1158 
_draw_illegal_bitmap_mode1(uint8_t * p,unsigned int xs,unsigned int xe,uint8_t * gfx_msk_ptr)1159 inline static void _draw_illegal_bitmap_mode1(uint8_t *p, unsigned int xs,
1160                                               unsigned int xe,
1161                                               uint8_t *gfx_msk_ptr)
1162 {
1163     uint8_t *bmptr_low, *bmptr_high, *msk_ptr;
1164     uint8_t bmval;
1165     unsigned int i, j;
1166 
1167     bmptr_low = vicii.bitmap_low_ptr;
1168     bmptr_high = vicii.bitmap_high_ptr;
1169     msk_ptr = gfx_msk_ptr + GFX_MSK_LEFTBORDER_SIZE;
1170 
1171     memset(p + 8 * xs, 0, (xe - xs + 1) * 8);
1172 
1173     for (j = ((vicii.memptr << 3) + vicii.raster.ycounter + xs * 8) & 0x1fff, i = xs;
1174          i <= xe; i++, j = (j + 8) & 0x1fff) {
1175         if (j & 0x1000) {
1176             bmval = bmptr_low[j & 0x9ff];
1177         } else {
1178             bmval = bmptr_high[j & 0x9ff];
1179         }
1180 
1181         msk_ptr[i] = bmval;
1182     }
1183 }
1184 
_draw_illegal_bitmap_mode1_cached(uint8_t * p,unsigned int xs,unsigned int xe,raster_cache_t * cache)1185 inline static void _draw_illegal_bitmap_mode1_cached(uint8_t *p, unsigned int xs,
1186                                                      unsigned int xe,
1187                                                      raster_cache_t *cache)
1188 {
1189     uint8_t *foreground_data, *msk_ptr;
1190 
1191     foreground_data = cache->foreground_data;
1192     msk_ptr = cache->gfx_msk + GFX_MSK_LEFTBORDER_SIZE;
1193 
1194     memset(p + 8 * xs, 0, (xe - xs + 1) * 8);
1195     memcpy(msk_ptr + xs, foreground_data + xs, xe - xs + 1);
1196 }
1197 
draw_illegal_bitmap_mode1(void)1198 static void draw_illegal_bitmap_mode1(void)
1199 {
1200     _draw_illegal_bitmap_mode1(GFX_PTR(), 0, VICII_SCREEN_TEXTCOLS - 1,
1201                                vicii.raster.gfx_msk);
1202 }
1203 
draw_illegal_bitmap_mode1_cached(raster_cache_t * cache,unsigned int xs,unsigned int xe)1204 static void draw_illegal_bitmap_mode1_cached(raster_cache_t *cache,
1205                                              unsigned int xs, unsigned int xe)
1206 {
1207     _draw_illegal_bitmap_mode1_cached(GFX_PTR(), xs, xe, cache);
1208 }
1209 
draw_illegal_bitmap_mode1_foreground(unsigned int start_char,unsigned int end_char)1210 static void draw_illegal_bitmap_mode1_foreground(unsigned int start_char,
1211                                                  unsigned int end_char)
1212 {
1213     _draw_illegal_bitmap_mode1(GFX_PTR(), start_char, end_char,
1214                                vicii.raster.gfx_msk);
1215 }
1216 
1217 /* Illegal bitmap mode 2.  */
1218 
get_illegal_bitmap_mode2(raster_cache_t * cache,unsigned int * xs,unsigned int * xe,int rr)1219 static int get_illegal_bitmap_mode2(raster_cache_t *cache, unsigned int *xs,
1220                                     unsigned int *xe, int rr)
1221 {
1222     int r;
1223 
1224     r = raster_cache_data_fill(cache->color_data_1,
1225                                vicii.vbuf,
1226                                VICII_SCREEN_TEXTCOLS,
1227                                xs, xe,
1228                                rr);
1229     r |= raster_cache_data_fill(cache->color_data_3,
1230                                 vicii.cbuf,
1231                                 VICII_SCREEN_TEXTCOLS,
1232                                 xs, xe,
1233                                 rr);
1234     r |= raster_cache_data_fill_39ff(cache->foreground_data,
1235                                      vicii.bitmap_low_ptr,
1236                                      vicii.bitmap_high_ptr,
1237                                      vicii.memptr * 8
1238                                      + vicii.raster.ycounter,
1239                                      VICII_SCREEN_TEXTCOLS,
1240                                      8,
1241                                      xs, xe,
1242                                      rr);
1243     return r;
1244 }
1245 
_draw_illegal_bitmap_mode2(uint8_t * p,unsigned int xs,unsigned int xe,uint8_t * gfx_msk_ptr)1246 inline static void _draw_illegal_bitmap_mode2(uint8_t *p, unsigned int xs,
1247                                               unsigned int xe,
1248                                               uint8_t *gfx_msk_ptr)
1249 {
1250     uint8_t *bmptr_low, *bmptr_high, *msk_ptr;
1251     uint8_t bmval;
1252     unsigned int i, j;
1253 
1254     bmptr_low = vicii.bitmap_low_ptr;
1255     bmptr_high = vicii.bitmap_high_ptr;
1256     msk_ptr = gfx_msk_ptr + GFX_MSK_LEFTBORDER_SIZE;
1257 
1258     memset(p + 8 * xs, 0, (xe - xs + 1) * 8);
1259 
1260     for (j = ((vicii.memptr << 3) + vicii.raster.ycounter + xs * 8) & 0x1fff, i = xs;
1261          i <= xe; i++, j = (j + 8) & 0x1fff) {
1262         if (j & 0x1000) {
1263             bmval = bmptr_high[j & 0x9ff];
1264         } else {
1265             bmval = bmptr_low[j & 0x9ff];
1266         }
1267 
1268         msk_ptr[i] = mcmsktable[bmval];
1269     }
1270 }
1271 
_draw_illegal_bitmap_mode2_cached(uint8_t * p,unsigned int xs,unsigned int xe,raster_cache_t * cache)1272 inline static void _draw_illegal_bitmap_mode2_cached(uint8_t *p, unsigned int xs,
1273                                                      unsigned int xe,
1274                                                      raster_cache_t *cache)
1275 {
1276     uint8_t *foreground_data, *msk_ptr;
1277     unsigned int i;
1278 
1279     foreground_data = cache->foreground_data;
1280     msk_ptr = cache->gfx_msk + GFX_MSK_LEFTBORDER_SIZE;
1281 
1282     memset(p + 8 * xs, 0, (xe - xs + 1) * 8);
1283 
1284     for (i = xs; i <= xe; i++) {
1285         msk_ptr[i] = mcmsktable[foreground_data[i]];
1286     }
1287 }
1288 
draw_illegal_bitmap_mode2(void)1289 static void draw_illegal_bitmap_mode2(void)
1290 {
1291     _draw_illegal_bitmap_mode2(GFX_PTR(), 0, VICII_SCREEN_TEXTCOLS - 1,
1292                                vicii.raster.gfx_msk);
1293 }
1294 
draw_illegal_bitmap_mode2_cached(raster_cache_t * cache,unsigned int xs,unsigned int xe)1295 static void draw_illegal_bitmap_mode2_cached(raster_cache_t *cache,
1296                                              unsigned int xs, unsigned int xe)
1297 {
1298     _draw_illegal_bitmap_mode2_cached(GFX_PTR(), xs, xe, cache);
1299 }
1300 
draw_illegal_bitmap_mode2_foreground(unsigned int start_char,unsigned int end_char)1301 static void draw_illegal_bitmap_mode2_foreground(unsigned int start_char,
1302                                                  unsigned int end_char)
1303 {
1304     _draw_illegal_bitmap_mode2(GFX_PTR(), start_char, end_char,
1305                                vicii.raster.gfx_msk);
1306 }
1307 
1308 /* Idle state.  */
1309 
get_idle(raster_cache_t * cache,unsigned int * xs,unsigned int * xe,int rr)1310 static int get_idle(raster_cache_t *cache, unsigned int *xs, unsigned int *xe,
1311                     int rr)
1312 {
1313     if (rr
1314         || cache->foreground_data[0] != vicii.idle_data
1315         || cache->color_data_1[0] != vicii.raster.background_color
1316         || cache->color_data_1[1] != vicii.raster.idle_background_color
1317         || cache->color_data_1[2] != vicii.raster.video_mode) {
1318         cache->foreground_data[0] = (uint8_t)vicii.idle_data;
1319         cache->color_data_1[0] = vicii.raster.background_color;
1320         cache->color_data_1[1] = vicii.raster.idle_background_color;
1321         cache->color_data_1[2] = vicii.raster.video_mode;
1322         *xs = 0;
1323         *xe = VICII_SCREEN_TEXTCOLS - 1;
1324         return 1;
1325     } else {
1326         return 0;
1327     }
1328 }
1329 
_draw_idle(uint8_t * p,unsigned int xs,unsigned int xe,uint8_t * gfx_msk_ptr)1330 inline static void _draw_idle(uint8_t *p, unsigned int xs, unsigned int xe,
1331                               uint8_t *gfx_msk_ptr)
1332 {
1333     uint8_t *msk_ptr;
1334     uint8_t d = 0;
1335     unsigned int i;
1336 
1337     if (!vicii.raster.blank_enabled) {
1338         d = (uint8_t)vicii.idle_data;
1339     }
1340 
1341     msk_ptr = gfx_msk_ptr + GFX_MSK_LEFTBORDER_SIZE;
1342 
1343     if (VICII_IS_TEXT_MODE(vicii.raster.video_mode)) {
1344         /* The foreground color is always black (0).  */
1345         unsigned int offs;
1346         uint32_t c1, c2;
1347 
1348         offs = vicii.raster.idle_background_color << 4;
1349         c1 = hr_table[offs + (d >> 4)];
1350         c2 = hr_table[offs + (d & 0xf)];
1351 
1352         for (i = xs * 8; i <= xe * 8; i += 8) {
1353             *((uint32_t *)(p + i)) = c1;
1354             *((uint32_t *)(p + i + 4)) = c2;
1355         }
1356         memset(msk_ptr + xs, d, xe + 1 - xs);
1357     } else {
1358         if (vicii.raster.video_mode == VICII_MULTICOLOR_BITMAP_MODE) {
1359             /* FIXME: Could be optimized */
1360             uint8_t *ptmp;
1361             uint8_t c[4];
1362 
1363             c[0] = vicii.raster.background_color;
1364             c[1] = 0;
1365             c[2] = 0;
1366             c[3] = 0;
1367 
1368             ptmp = p + xs * 8;
1369 
1370             for (i = xs; i <= xe; i++) {
1371                 msk_ptr[i] = mcmsktable[d];
1372 
1373                 ptmp[1] = ptmp[0] = c[mc_table[d]];
1374                 ptmp[3] = ptmp[2] = c[mc_table[0x100 + d]];
1375                 ptmp[5] = ptmp[4] = c[mc_table[0x200 + d]];
1376                 ptmp[7] = ptmp[6] = c[d & 3];
1377                 ptmp += 8;
1378             }
1379         } else {
1380             memset(p + xs * 8, 0, (xe + 1 - xs) * 8);
1381             if (vicii.raster.video_mode == VICII_ILLEGAL_BITMAP_MODE_2) {
1382                 memset(msk_ptr + xs, mcmsktable[d], xe + 1 - xs);
1383             } else {
1384                 memset(msk_ptr + xs, d, xe + 1 - xs);
1385             }
1386         }
1387     }
1388 }
1389 
draw_idle(void)1390 static void draw_idle(void)
1391 {
1392     ALIGN_DRAW_FUNC(_draw_idle, 0, VICII_SCREEN_TEXTCOLS - 1,
1393                     vicii.raster.gfx_msk);
1394 }
1395 
draw_idle_cached(raster_cache_t * cache,unsigned int xs,unsigned int xe)1396 static void draw_idle_cached(raster_cache_t *cache, unsigned int xs,
1397                              unsigned int xe)
1398 {
1399     ALIGN_DRAW_FUNC(_draw_idle, xs, xe, cache->gfx_msk);
1400 }
1401 
draw_idle_foreground(unsigned int start_char,unsigned int end_char)1402 static void draw_idle_foreground(unsigned int start_char,
1403                                  unsigned int end_char)
1404 {
1405     uint8_t *p, *msk_ptr;
1406     uint8_t d = 0;
1407     unsigned int i;
1408 
1409     p = GFX_PTR();
1410     msk_ptr = vicii.raster.gfx_msk + GFX_MSK_LEFTBORDER_SIZE;
1411     if (!vicii.raster.blank_enabled) {
1412         d = (uint8_t)vicii.idle_data;
1413     }
1414 
1415     if (vicii.raster.xsmooth_shift_left > 0) {
1416         d = (d >> vicii.raster.xsmooth_shift_left) << vicii.raster.xsmooth_shift_left;
1417     }
1418 
1419     for (i = start_char; i <= end_char; i++) {
1420         DRAW_STD_TEXT_BYTE(p + i * 8, d, 0);
1421         msk_ptr[i] = d;
1422     }
1423 }
1424 
setup_modes(void)1425 static void setup_modes(void)
1426 {
1427     raster_modes_set(vicii.raster.modes, VICII_NORMAL_TEXT_MODE,
1428                      get_std_text,
1429                      draw_std_text_cached,
1430                      draw_std_text,
1431                      draw_std_background,
1432                      draw_std_text_foreground);
1433 
1434     raster_modes_set(vicii.raster.modes, VICII_MULTICOLOR_TEXT_MODE,
1435                      get_mc_text,
1436                      draw_mc_text_cached,
1437                      draw_mc_text,
1438                      draw_std_background,
1439                      draw_mc_text_foreground);
1440 
1441     raster_modes_set(vicii.raster.modes, VICII_HIRES_BITMAP_MODE,
1442                      get_hires_bitmap,
1443                      draw_hires_bitmap_cached,
1444                      draw_hires_bitmap,
1445                      draw_std_background,
1446                      draw_hires_bitmap_foreground);
1447 
1448     raster_modes_set(vicii.raster.modes, VICII_MULTICOLOR_BITMAP_MODE,
1449                      get_mc_bitmap,
1450                      draw_mc_bitmap_cached,
1451                      draw_mc_bitmap,
1452                      draw_std_background,
1453                      draw_mc_bitmap_foreground);
1454 
1455     raster_modes_set(vicii.raster.modes, VICII_EXTENDED_TEXT_MODE,
1456                      get_ext_text,
1457                      draw_ext_text_cached,
1458                      draw_ext_text,
1459                      draw_std_background,
1460                      draw_ext_text_foreground);
1461 
1462     raster_modes_set(vicii.raster.modes, VICII_IDLE_MODE,
1463                      get_idle,
1464                      draw_idle_cached,
1465                      draw_idle,
1466                      draw_idle_std_background,
1467                      draw_idle_foreground);
1468 
1469     raster_modes_set(vicii.raster.modes, VICII_ILLEGAL_TEXT_MODE,
1470                      get_illegal_text,
1471                      draw_illegal_text_cached,
1472                      draw_illegal_text,
1473                      draw_std_background,
1474                      draw_illegal_text_foreground);
1475 
1476     raster_modes_set(vicii.raster.modes, VICII_ILLEGAL_BITMAP_MODE_1,
1477                      get_illegal_bitmap_mode1,
1478                      draw_illegal_bitmap_mode1_cached,
1479                      draw_illegal_bitmap_mode1,
1480                      draw_std_background,
1481                      draw_illegal_bitmap_mode1_foreground);
1482 
1483     raster_modes_set(vicii.raster.modes, VICII_ILLEGAL_BITMAP_MODE_2,
1484                      get_illegal_bitmap_mode2,
1485                      draw_illegal_bitmap_mode2_cached,
1486                      draw_illegal_bitmap_mode2,
1487                      draw_std_background,
1488                      draw_illegal_bitmap_mode2_foreground);
1489 }
1490 
1491 /* Initialize the drawing tables.  */
init_drawing_tables(void)1492 static void init_drawing_tables(void)
1493 {
1494     uint32_t i;
1495     unsigned int f, b;
1496 
1497     for (i = 0; i <= 0xf; i++) {
1498         for (f = 0; f <= 0xf; f++) {
1499             for (b = 0; b <= 0xf; b++) {
1500                 uint8_t fp, bp;
1501                 uint8_t *p;
1502                 int offset;
1503 
1504                 fp = f;
1505                 bp = b;
1506                 offset = (f << 8) | (b << 4);
1507                 p = (uint8_t *)(hr_table + offset + i);
1508 
1509                 p[0] = i & 0x8 ? fp : bp;
1510                 p[1] = i & 0x4 ? fp : bp;
1511                 p[2] = i & 0x2 ? fp : bp;
1512                 p[3] = i & 0x1 ? fp : bp;
1513             }
1514         }
1515     }
1516 
1517     for (i = 0; i <= 0xff; i++) {
1518         mc_table[i] = (uint8_t)(i >> 6);
1519         mc_table[i + 0x100] = (uint8_t)((i >> 4) & 0x3);
1520         mc_table[i + 0x200] = (uint8_t)((i >> 2) & 0x3);
1521         mcmsktable[i] = (uint8_t)((i & 0xaa) | ((i & 0xaa) >> 1));
1522     }
1523 }
1524 
vicii_draw_init(void)1525 void vicii_draw_init(void)
1526 {
1527     init_drawing_tables();
1528 
1529     setup_modes();
1530 }
1531