1 /*
2 * VIC.cpp - 6569R5 emulation (line based)
3 *
4 * Frodo (C) 1994-1997,2002 Christian Bauer
5 *
6
7 *
8 * Notes:
9 * ------
10 *
11 * - The EmulateLine() function is called for every emulated
12 * raster line. It computes one pixel row of the graphics
13 * according to the current VIC register settings and returns
14 * the number of cycles available for the CPU in that line.
15 * - The graphics are output into an 8 bit chunky bitmap
16 * - The sprite-graphics priority handling and collision
17 * detection is done in a bit-oriented way with masks.
18 * The foreground/background pixel mask for the graphics
19 * is stored in the fore_mask_buf[] array. Multicolor
20 * sprites are converted from their original chunky format
21 * to a bitplane representation (two bit masks) for easier
22 * handling of priorities and collisions.
23 * - The sprite-sprite priority handling and collision
24 * detection is done in with the byte array spr_coll_buf[],
25 * that is used to keep track of which sprites are already
26 * visible at certain X positions.
27 *
28 * Incompatibilities:
29 * ------------------
30 *
31 * - Raster effects that are achieved by modifying VIC registers
32 * in the middle of a raster line cannot be emulated
33 * - Sprite collisions are only detected within the visible
34 * screen area (excluding borders)
35 * - Sprites are only drawn if they completely fit within the
36 * left/right limits of the chunky bitmap
37 * - The Char ROM is not visible in the bitmap displays at
38 * addresses $0000 and $8000
39 * - The IRQ is cleared on every write access to the flag
40 * register. This is a hack for the RMW instructions of the
41 * 6510 that first write back the original value.
42 */
43
44 #include "sysdeps.h"
45
46 #include "VIC.h"
47 #include "C64.h"
48 #include "CPUC64.h"
49 #include "Display.h"
50 #include "Prefs.h"
51
52
53 // Test alignment on run-time for processors that can't access unaligned:
54 #ifdef __riscos__
55 #define ALIGNMENT_CHECK
56 #endif
57
58 // First and last displayed line
59 const unsigned FIRST_DISP_LINE = 0x10;
60 const unsigned LAST_DISP_LINE = 0x11f;
61
62 // First and last possible line for Bad Lines
63 const unsigned FIRST_DMA_LINE = 0x30;
64 const unsigned LAST_DMA_LINE = 0xf7;
65
66 // Display window coordinates
67 const int ROW25_YSTART = 0x33;
68 const int ROW25_YSTOP = 0xfb;
69 const int ROW24_YSTART = 0x37;
70 const int ROW24_YSTOP = 0xf7;
71
72 #if defined(SMALL_DISPLAY)
73 /* This does not work yet, the sprite code doesn't know about it. */
74 const int COL40_XSTART = 0x14;
75 const int COL40_XSTOP = 0x154;
76 const int COL38_XSTART = 0x1B;
77 const int COL38_XSTOP = 0x14B;
78 #else
79 const int COL40_XSTART = 0x20;
80 const int COL40_XSTOP = 0x160;
81 const int COL38_XSTART = 0x27;
82 const int COL38_XSTOP = 0x157;
83 #endif
84
85
86 // Tables for sprite X expansion
87 uint16 ExpTable[256] = {
88 0x0000, 0x0003, 0x000C, 0x000F, 0x0030, 0x0033, 0x003C, 0x003F,
89 0x00C0, 0x00C3, 0x00CC, 0x00CF, 0x00F0, 0x00F3, 0x00FC, 0x00FF,
90 0x0300, 0x0303, 0x030C, 0x030F, 0x0330, 0x0333, 0x033C, 0x033F,
91 0x03C0, 0x03C3, 0x03CC, 0x03CF, 0x03F0, 0x03F3, 0x03FC, 0x03FF,
92 0x0C00, 0x0C03, 0x0C0C, 0x0C0F, 0x0C30, 0x0C33, 0x0C3C, 0x0C3F,
93 0x0CC0, 0x0CC3, 0x0CCC, 0x0CCF, 0x0CF0, 0x0CF3, 0x0CFC, 0x0CFF,
94 0x0F00, 0x0F03, 0x0F0C, 0x0F0F, 0x0F30, 0x0F33, 0x0F3C, 0x0F3F,
95 0x0FC0, 0x0FC3, 0x0FCC, 0x0FCF, 0x0FF0, 0x0FF3, 0x0FFC, 0x0FFF,
96 0x3000, 0x3003, 0x300C, 0x300F, 0x3030, 0x3033, 0x303C, 0x303F,
97 0x30C0, 0x30C3, 0x30CC, 0x30CF, 0x30F0, 0x30F3, 0x30FC, 0x30FF,
98 0x3300, 0x3303, 0x330C, 0x330F, 0x3330, 0x3333, 0x333C, 0x333F,
99 0x33C0, 0x33C3, 0x33CC, 0x33CF, 0x33F0, 0x33F3, 0x33FC, 0x33FF,
100 0x3C00, 0x3C03, 0x3C0C, 0x3C0F, 0x3C30, 0x3C33, 0x3C3C, 0x3C3F,
101 0x3CC0, 0x3CC3, 0x3CCC, 0x3CCF, 0x3CF0, 0x3CF3, 0x3CFC, 0x3CFF,
102 0x3F00, 0x3F03, 0x3F0C, 0x3F0F, 0x3F30, 0x3F33, 0x3F3C, 0x3F3F,
103 0x3FC0, 0x3FC3, 0x3FCC, 0x3FCF, 0x3FF0, 0x3FF3, 0x3FFC, 0x3FFF,
104 0xC000, 0xC003, 0xC00C, 0xC00F, 0xC030, 0xC033, 0xC03C, 0xC03F,
105 0xC0C0, 0xC0C3, 0xC0CC, 0xC0CF, 0xC0F0, 0xC0F3, 0xC0FC, 0xC0FF,
106 0xC300, 0xC303, 0xC30C, 0xC30F, 0xC330, 0xC333, 0xC33C, 0xC33F,
107 0xC3C0, 0xC3C3, 0xC3CC, 0xC3CF, 0xC3F0, 0xC3F3, 0xC3FC, 0xC3FF,
108 0xCC00, 0xCC03, 0xCC0C, 0xCC0F, 0xCC30, 0xCC33, 0xCC3C, 0xCC3F,
109 0xCCC0, 0xCCC3, 0xCCCC, 0xCCCF, 0xCCF0, 0xCCF3, 0xCCFC, 0xCCFF,
110 0xCF00, 0xCF03, 0xCF0C, 0xCF0F, 0xCF30, 0xCF33, 0xCF3C, 0xCF3F,
111 0xCFC0, 0xCFC3, 0xCFCC, 0xCFCF, 0xCFF0, 0xCFF3, 0xCFFC, 0xCFFF,
112 0xF000, 0xF003, 0xF00C, 0xF00F, 0xF030, 0xF033, 0xF03C, 0xF03F,
113 0xF0C0, 0xF0C3, 0xF0CC, 0xF0CF, 0xF0F0, 0xF0F3, 0xF0FC, 0xF0FF,
114 0xF300, 0xF303, 0xF30C, 0xF30F, 0xF330, 0xF333, 0xF33C, 0xF33F,
115 0xF3C0, 0xF3C3, 0xF3CC, 0xF3CF, 0xF3F0, 0xF3F3, 0xF3FC, 0xF3FF,
116 0xFC00, 0xFC03, 0xFC0C, 0xFC0F, 0xFC30, 0xFC33, 0xFC3C, 0xFC3F,
117 0xFCC0, 0xFCC3, 0xFCCC, 0xFCCF, 0xFCF0, 0xFCF3, 0xFCFC, 0xFCFF,
118 0xFF00, 0xFF03, 0xFF0C, 0xFF0F, 0xFF30, 0xFF33, 0xFF3C, 0xFF3F,
119 0xFFC0, 0xFFC3, 0xFFCC, 0xFFCF, 0xFFF0, 0xFFF3, 0xFFFC, 0xFFFF
120 };
121
122 uint16 MultiExpTable[256] = {
123 0x0000, 0x0005, 0x000A, 0x000F, 0x0050, 0x0055, 0x005A, 0x005F,
124 0x00A0, 0x00A5, 0x00AA, 0x00AF, 0x00F0, 0x00F5, 0x00FA, 0x00FF,
125 0x0500, 0x0505, 0x050A, 0x050F, 0x0550, 0x0555, 0x055A, 0x055F,
126 0x05A0, 0x05A5, 0x05AA, 0x05AF, 0x05F0, 0x05F5, 0x05FA, 0x05FF,
127 0x0A00, 0x0A05, 0x0A0A, 0x0A0F, 0x0A50, 0x0A55, 0x0A5A, 0x0A5F,
128 0x0AA0, 0x0AA5, 0x0AAA, 0x0AAF, 0x0AF0, 0x0AF5, 0x0AFA, 0x0AFF,
129 0x0F00, 0x0F05, 0x0F0A, 0x0F0F, 0x0F50, 0x0F55, 0x0F5A, 0x0F5F,
130 0x0FA0, 0x0FA5, 0x0FAA, 0x0FAF, 0x0FF0, 0x0FF5, 0x0FFA, 0x0FFF,
131 0x5000, 0x5005, 0x500A, 0x500F, 0x5050, 0x5055, 0x505A, 0x505F,
132 0x50A0, 0x50A5, 0x50AA, 0x50AF, 0x50F0, 0x50F5, 0x50FA, 0x50FF,
133 0x5500, 0x5505, 0x550A, 0x550F, 0x5550, 0x5555, 0x555A, 0x555F,
134 0x55A0, 0x55A5, 0x55AA, 0x55AF, 0x55F0, 0x55F5, 0x55FA, 0x55FF,
135 0x5A00, 0x5A05, 0x5A0A, 0x5A0F, 0x5A50, 0x5A55, 0x5A5A, 0x5A5F,
136 0x5AA0, 0x5AA5, 0x5AAA, 0x5AAF, 0x5AF0, 0x5AF5, 0x5AFA, 0x5AFF,
137 0x5F00, 0x5F05, 0x5F0A, 0x5F0F, 0x5F50, 0x5F55, 0x5F5A, 0x5F5F,
138 0x5FA0, 0x5FA5, 0x5FAA, 0x5FAF, 0x5FF0, 0x5FF5, 0x5FFA, 0x5FFF,
139 0xA000, 0xA005, 0xA00A, 0xA00F, 0xA050, 0xA055, 0xA05A, 0xA05F,
140 0xA0A0, 0xA0A5, 0xA0AA, 0xA0AF, 0xA0F0, 0xA0F5, 0xA0FA, 0xA0FF,
141 0xA500, 0xA505, 0xA50A, 0xA50F, 0xA550, 0xA555, 0xA55A, 0xA55F,
142 0xA5A0, 0xA5A5, 0xA5AA, 0xA5AF, 0xA5F0, 0xA5F5, 0xA5FA, 0xA5FF,
143 0xAA00, 0xAA05, 0xAA0A, 0xAA0F, 0xAA50, 0xAA55, 0xAA5A, 0xAA5F,
144 0xAAA0, 0xAAA5, 0xAAAA, 0xAAAF, 0xAAF0, 0xAAF5, 0xAAFA, 0xAAFF,
145 0xAF00, 0xAF05, 0xAF0A, 0xAF0F, 0xAF50, 0xAF55, 0xAF5A, 0xAF5F,
146 0xAFA0, 0xAFA5, 0xAFAA, 0xAFAF, 0xAFF0, 0xAFF5, 0xAFFA, 0xAFFF,
147 0xF000, 0xF005, 0xF00A, 0xF00F, 0xF050, 0xF055, 0xF05A, 0xF05F,
148 0xF0A0, 0xF0A5, 0xF0AA, 0xF0AF, 0xF0F0, 0xF0F5, 0xF0FA, 0xF0FF,
149 0xF500, 0xF505, 0xF50A, 0xF50F, 0xF550, 0xF555, 0xF55A, 0xF55F,
150 0xF5A0, 0xF5A5, 0xF5AA, 0xF5AF, 0xF5F0, 0xF5F5, 0xF5FA, 0xF5FF,
151 0xFA00, 0xFA05, 0xFA0A, 0xFA0F, 0xFA50, 0xFA55, 0xFA5A, 0xFA5F,
152 0xFAA0, 0xFAA5, 0xFAAA, 0xFAAF, 0xFAF0, 0xFAF5, 0xFAFA, 0xFAFF,
153 0xFF00, 0xFF05, 0xFF0A, 0xFF0F, 0xFF50, 0xFF55, 0xFF5A, 0xFF5F,
154 0xFFA0, 0xFFA5, 0xFFAA, 0xFFAF, 0xFFF0, 0xFFF5, 0xFFFA, 0xFFFF
155 };
156
157 #ifdef __POWERPC__
158 static union {
159 struct {
160 uint8 a,b,c,d,e,f,g,h;
161 } a;
162 double b;
163 } TextColorTable[16][16][256];
164 #else
165 static union {
166 struct {
167 uint8 a,b,c,d;
168 } a;
169 uint32 b;
170 } TextColorTable[16][16][256][2];
171 #endif
172
173 #ifdef GLOBAL_VARS
174 static uint16 mc_color_lookup[4];
175 #ifndef CAN_ACCESS_UNALIGNED
176 static uint8 text_chunky_buf[40*8];
177 #endif
178 static uint16 mx[8]; // VIC registers
179 static uint8 mx8;
180 static uint8 my[8];
181 static uint8 ctrl1, ctrl2;
182 static uint8 lpx, lpy;
183 static uint8 me, mxe, mye, mdp, mmc;
184 static uint8 vbase;
185 static uint8 irq_flag, irq_mask;
186 static uint8 clx_spr, clx_bgr;
187 static uint8 ec, b0c, b1c, b2c, b3c, mm0, mm1;
188 static uint8 sc[8];
189
190 static uint8 *ram, *char_rom, *color_ram; // Pointers to RAM and ROM
191 static C64 *the_c64; // Pointer to C64
192 static C64Display *the_display; // Pointer to C64Display
193 static MOS6510 *the_cpu; // Pointer to 6510
194
195 static uint8 colors[256]; // Indices of the 16 C64 colors (16 times mirrored to avoid "& 0x0f")
196
197 static uint8 ec_color, b0c_color, b1c_color, b2c_color, b3c_color; // Indices for exterior/background colors
198 static uint8 mm0_color, mm1_color; // Indices for MOB multicolors
199 static uint8 spr_color[8]; // Indices for MOB colors
200
201 static uint32 ec_color_long; // ec_color expanded to 32 bits
202
203 static uint8 matrix_line[40]; // Buffer for video line, read in Bad Lines
204 static uint8 color_line[40]; // Buffer for color line, read in Bad Lines
205
206 #ifdef __POWERPC__
207 static double chunky_tmp[DISPLAY_X/8]; // Temporary line buffer for GameKit speedup
208 #endif
209 static uint8 *chunky_line_start; // Pointer to start of current line in bitmap buffer
210 static int xmod; // Number of bytes per row
211
212 static uint8 *matrix_base; // Video matrix base
213 static uint8 *char_base; // Character generator base
214 static uint8 *bitmap_base; // Bitmap base
215
216 static uint16 raster_y; // Current raster line
217 static uint16 irq_raster; // Interrupt raster line
218 static uint16 dy_start; // Comparison values for border logic
219 static uint16 dy_stop;
220 static uint16 rc; // Row counter
221 static uint16 vc; // Video counter
222 static uint16 vc_base; // Video counter base
223 static uint16 x_scroll; // X scroll value
224 static uint16 y_scroll; // Y scroll value
225 static uint16 cia_vabase; // CIA VA14/15 video base
226
227 static int display_idx; // Index of current display mode
228 static int skip_counter; // Counter for frame-skipping
229
230 static uint16 mc[8]; // Sprite data counters
231 static uint8 sprite_on; // 8 Flags: Sprite display/DMA active
232
233 static uint8 spr_coll_buf[0x180]; // Buffer for sprite-sprite collisions and priorities
234 static uint8 fore_mask_buf[0x180/8]; // Foreground mask for sprite-graphics collisions and priorities
235
236 static bool display_state; // true: Display state, false: Idle state
237 static bool border_on; // Flag: Upper/lower border on
238 static bool border_40_col; // Flag: 40 column border
239 static bool frame_skipped; // Flag: Frame is being skipped
240 static uint8 bad_lines_enabled; // Flag: Bad Lines enabled for this frame
241 static bool lp_triggered; // Flag: Lightpen was triggered in this frame
242 #endif
243
244
245 /*
246 * Constructor: Initialize variables
247 */
248
init_text_color_table(uint8 * colors)249 static void init_text_color_table(uint8 *colors)
250 {
251 for (int i = 0; i < 16; i++)
252 for (int j = 0; j < 16; j++)
253 for (int k = 0; k < 256; k++) {
254 #ifdef __POWERPC__
255 TextColorTable[i][j][k].a.a = colors[k & 128 ? i : j];
256 TextColorTable[i][j][k].a.b = colors[k & 64 ? i : j];
257 TextColorTable[i][j][k].a.c = colors[k & 32 ? i : j];
258 TextColorTable[i][j][k].a.d = colors[k & 16 ? i : j];
259 TextColorTable[i][j][k].a.e = colors[k & 8 ? i : j];
260 TextColorTable[i][j][k].a.f = colors[k & 4 ? i : j];
261 TextColorTable[i][j][k].a.g = colors[k & 2 ? i : j];
262 TextColorTable[i][j][k].a.h = colors[k & 1 ? i : j];
263 #else
264 TextColorTable[i][j][k][0].a.a = colors[k & 128 ? i : j];
265 TextColorTable[i][j][k][0].a.b = colors[k & 64 ? i : j];
266 TextColorTable[i][j][k][0].a.c = colors[k & 32 ? i : j];
267 TextColorTable[i][j][k][0].a.d = colors[k & 16 ? i : j];
268 TextColorTable[i][j][k][1].a.a = colors[k & 8 ? i : j];
269 TextColorTable[i][j][k][1].a.b = colors[k & 4 ? i : j];
270 TextColorTable[i][j][k][1].a.c = colors[k & 2 ? i : j];
271 TextColorTable[i][j][k][1].a.d = colors[k & 1 ? i : j];
272 #endif
273 }
274 }
275
MOS6569(C64 * c64,C64Display * disp,MOS6510 * CPU,uint8 * RAM,uint8 * Char,uint8 * Color)276 MOS6569::MOS6569(C64 *c64, C64Display *disp, MOS6510 *CPU, uint8 *RAM, uint8 *Char, uint8 *Color)
277 #ifndef GLOBAL_VARS
278 : ram(RAM), char_rom(Char), color_ram(Color), the_c64(c64), the_display(disp), the_cpu(CPU)
279 #endif
280 {
281 int i;
282
283 // Set pointers
284 #ifdef GLOBAL_VARS
285 the_c64 = c64;
286 the_display = disp;
287 the_cpu = CPU;
288 ram = RAM;
289 char_rom = Char;
290 color_ram = Color;
291 #endif
292 matrix_base = RAM;
293 char_base = RAM;
294 bitmap_base = RAM;
295
296 // Get bitmap info
297 chunky_line_start = disp->BitmapBase();
298 xmod = disp->BitmapXMod();
299
300 // Initialize VIC registers
301 mx8 = 0;
302 ctrl1 = ctrl2 = 0;
303 lpx = lpy = 0;
304 me = mxe = mye = mdp = mmc = 0;
305 vbase = irq_flag = irq_mask = 0;
306 clx_spr = clx_bgr = 0;
307 cia_vabase = 0;
308 ec = b0c = b1c = b2c = b3c = mm0 = mm1 = 0;
309 for (i=0; i<8; i++) mx[i] = my[i] = sc[i] = 0;
310
311 // Initialize other variables
312 raster_y = 0xffff;
313 rc = 7;
314 irq_raster = vc = vc_base = x_scroll = y_scroll = 0;
315 dy_start = ROW24_YSTART;
316 dy_stop = ROW24_YSTOP;
317
318 display_idx = 0;
319 display_state = false;
320 border_on = false;
321 lp_triggered = false;
322
323 sprite_on = 0;
324 for (i=0; i<8; i++)
325 mc[i] = 63;
326
327 frame_skipped = false;
328 skip_counter = 1;
329
330 // Clear foreground mask
331 memset(fore_mask_buf, 0, DISPLAY_X/8);
332
333 // Preset colors to black
334 disp->InitColors(colors);
335 init_text_color_table(colors);
336 ec_color = b0c_color = b1c_color = b2c_color = b3c_color = mm0_color = mm1_color = colors[0];
337 ec_color_long = (ec_color << 24) | (ec_color << 16) | (ec_color << 8) | ec_color;
338 for (i=0; i<8; i++) spr_color[i] = colors[0];
339 }
340
341
342 /*
343 * Reinitialize the colors table for when the palette has changed
344 */
345
ReInitColors(void)346 void MOS6569::ReInitColors(void)
347 {
348 int i;
349
350 // Build inverse color table.
351 uint8 xlate_colors[256];
352 memset(xlate_colors, 0, sizeof(xlate_colors));
353 for (i = 0; i < 16; i++)
354 xlate_colors[colors[i]] = i;
355
356 // Get the new colors.
357 the_display->InitColors(colors);
358 init_text_color_table(colors);
359
360 // Build color translation table.
361 for (i = 0; i < 256; i++)
362 xlate_colors[i] = colors[xlate_colors[i]];
363
364 // Translate all the old colors variables.
365 ec_color = colors[ec];
366 ec_color_long = ec_color | (ec_color << 8) | (ec_color << 16) | (ec_color << 24);
367 b0c_color = colors[b0c];
368 b1c_color = colors[b1c];
369 b2c_color = colors[b2c];
370 b3c_color = colors[b3c];
371 mm0_color = colors[mm0];
372 mm1_color = colors[mm1];
373 for (i = 0; i < 8; i++)
374 spr_color[i] = colors[sc[i]];
375 mc_color_lookup[0] = b0c_color | (b0c_color << 8);
376 mc_color_lookup[1] = b1c_color | (b1c_color << 8);
377 mc_color_lookup[2] = b2c_color | (b2c_color << 8);
378
379 // Translate the chunky buffer.
380 uint8 *scanline = the_display->BitmapBase();
381 for (int y = 0; y < DISPLAY_Y; y++) {
382 for (int x = 0; x < DISPLAY_X; x++)
383 scanline[x] = xlate_colors[scanline[x]];
384 scanline += xmod;
385 }
386 }
387
388 #ifdef GLOBAL_VARS
make_mc_table(void)389 static void make_mc_table(void)
390 #else
391 void MOS6569::make_mc_table(void)
392 #endif
393 {
394 mc_color_lookup[0] = b0c_color | (b0c_color << 8);
395 mc_color_lookup[1] = b1c_color | (b1c_color << 8);
396 mc_color_lookup[2] = b2c_color | (b2c_color << 8);
397 }
398
399
400 /*
401 * Convert video address to pointer
402 */
403
404 #ifdef GLOBAL_VARS
get_physical(uint16 adr)405 static inline uint8 *get_physical(uint16 adr)
406 #else
407 inline uint8 *MOS6569::get_physical(uint16 adr)
408 #endif
409 {
410 int va = adr | cia_vabase;
411 if ((va & 0x7000) == 0x1000)
412 return char_rom + (va & 0x0fff);
413 else
414 return ram + va;
415 }
416
417
418 /*
419 * Get VIC state
420 */
421
GetState(MOS6569State * vd)422 void MOS6569::GetState(MOS6569State *vd)
423 {
424 int i;
425
426 vd->m0x = mx[0] & 0xff; vd->m0y = my[0];
427 vd->m1x = mx[1] & 0xff; vd->m1y = my[1];
428 vd->m2x = mx[2] & 0xff; vd->m2y = my[2];
429 vd->m3x = mx[3] & 0xff; vd->m3y = my[3];
430 vd->m4x = mx[4] & 0xff; vd->m4y = my[4];
431 vd->m5x = mx[5] & 0xff; vd->m5y = my[5];
432 vd->m6x = mx[6] & 0xff; vd->m6y = my[6];
433 vd->m7x = mx[7] & 0xff; vd->m7y = my[7];
434 vd->mx8 = mx8;
435
436 vd->ctrl1 = (ctrl1 & 0x7f) | ((raster_y & 0x100) >> 1);
437 vd->raster = raster_y & 0xff;
438 vd->lpx = lpx; vd->lpy = lpy;
439 vd->ctrl2 = ctrl2;
440 vd->vbase = vbase;
441 vd->irq_flag = irq_flag;
442 vd->irq_mask = irq_mask;
443
444 vd->me = me; vd->mxe = mxe; vd->mye = mye; vd->mdp = mdp; vd->mmc = mmc;
445 vd->mm = clx_spr; vd->md = clx_bgr;
446
447 vd->ec = ec;
448 vd->b0c = b0c; vd->b1c = b1c; vd->b2c = b2c; vd->b3c = b3c;
449 vd->mm0 = mm0; vd->mm1 = mm1;
450 vd->m0c = sc[0]; vd->m1c = sc[1];
451 vd->m2c = sc[2]; vd->m3c = sc[3];
452 vd->m4c = sc[4]; vd->m5c = sc[5];
453 vd->m6c = sc[6]; vd->m7c = sc[7];
454
455 vd->pad0 = 0;
456 vd->irq_raster = irq_raster;
457 vd->vc = vc;
458 vd->vc_base = vc_base;
459 vd->rc = rc;
460 vd->spr_dma = vd->spr_disp = sprite_on;
461 for (i=0; i<8; i++)
462 vd->mc[i] = vd->mc_base[i] = mc[i];
463 vd->display_state = display_state;
464 vd->bad_line = raster_y >= FIRST_DMA_LINE && raster_y <= LAST_DMA_LINE && ((raster_y & 7) == y_scroll) && bad_lines_enabled;
465 vd->bad_line_enable = bad_lines_enabled;
466 vd->lp_triggered = lp_triggered;
467 vd->border_on = border_on;
468
469 vd->bank_base = cia_vabase;
470 vd->matrix_base = ((vbase & 0xf0) << 6) | cia_vabase;
471 vd->char_base = ((vbase & 0x0e) << 10) | cia_vabase;
472 vd->bitmap_base = ((vbase & 0x08) << 10) | cia_vabase;
473 for (i=0; i<8; i++)
474 vd->sprite_base[i] = (matrix_base[0x3f8 + i] << 6) | cia_vabase;
475
476 vd->cycle = 1;
477 vd->raster_x = 0;
478 vd->ml_index = 0;
479 vd->ref_cnt = 0xff;
480 vd->last_vic_byte = 0;
481 vd->ud_border_on = border_on;
482 }
483
484
485 /*
486 * Set VIC state (only works if in VBlank)
487 */
488
SetState(MOS6569State * vd)489 void MOS6569::SetState(MOS6569State *vd)
490 {
491 int i, j;
492
493 mx[0] = vd->m0x; my[0] = vd->m0y;
494 mx[1] = vd->m1x; my[1] = vd->m1y;
495 mx[2] = vd->m2x; my[2] = vd->m2y;
496 mx[3] = vd->m3x; my[3] = vd->m3y;
497 mx[4] = vd->m4x; my[4] = vd->m4y;
498 mx[5] = vd->m5x; my[5] = vd->m5y;
499 mx[6] = vd->m6x; my[6] = vd->m6y;
500 mx[7] = vd->m7x; my[7] = vd->m7y;
501 mx8 = vd->mx8;
502 for (i=0, j=1; i<8; i++, j<<=1) {
503 if (mx8 & j)
504 mx[i] |= 0x100;
505 else
506 mx[i] &= 0xff;
507 }
508
509 ctrl1 = vd->ctrl1;
510 ctrl2 = vd->ctrl2;
511 x_scroll = ctrl2 & 7;
512 y_scroll = ctrl1 & 7;
513 if (ctrl1 & 8) {
514 dy_start = ROW25_YSTART;
515 dy_stop = ROW25_YSTOP;
516 } else {
517 dy_start = ROW24_YSTART;
518 dy_stop = ROW24_YSTOP;
519 }
520 border_40_col = ctrl2 & 8;
521 display_idx = ((ctrl1 & 0x60) | (ctrl2 & 0x10)) >> 4;
522
523 raster_y = 0;
524 lpx = vd->lpx; lpy = vd->lpy;
525
526 vbase = vd->vbase;
527 cia_vabase = vd->bank_base;
528 matrix_base = get_physical((vbase & 0xf0) << 6);
529 char_base = get_physical((vbase & 0x0e) << 10);
530 bitmap_base = get_physical((vbase & 0x08) << 10);
531
532 irq_flag = vd->irq_flag;
533 irq_mask = vd->irq_mask;
534
535 me = vd->me; mxe = vd->mxe; mye = vd->mye; mdp = vd->mdp; mmc = vd->mmc;
536 clx_spr = vd->mm; clx_bgr = vd->md;
537
538 ec = vd->ec;
539 ec_color = colors[ec];
540 ec_color_long = (ec_color << 24) | (ec_color << 16) | (ec_color << 8) | ec_color;
541
542 b0c = vd->b0c; b1c = vd->b1c; b2c = vd->b2c; b3c = vd->b3c;
543 b0c_color = colors[b0c];
544 b1c_color = colors[b1c];
545 b2c_color = colors[b2c];
546 b3c_color = colors[b3c];
547 make_mc_table();
548
549 mm0 = vd->mm0; mm1 = vd->mm1;
550 mm0_color = colors[mm0];
551 mm1_color = colors[mm1];
552
553 sc[0] = vd->m0c; sc[1] = vd->m1c;
554 sc[2] = vd->m2c; sc[3] = vd->m3c;
555 sc[4] = vd->m4c; sc[5] = vd->m5c;
556 sc[6] = vd->m6c; sc[7] = vd->m7c;
557 for (i=0; i<8; i++)
558 spr_color[i] = colors[sc[i]];
559
560 irq_raster = vd->irq_raster;
561 vc = vd->vc;
562 vc_base = vd->vc_base;
563 rc = vd->rc;
564 sprite_on = vd->spr_dma;
565 for (i=0; i<8; i++)
566 mc[i] = vd->mc[i];
567 display_state = vd->display_state;
568 bad_lines_enabled = vd->bad_line_enable;
569 lp_triggered = vd->lp_triggered;
570 border_on = vd->border_on;
571 }
572
573
574 /*
575 * Trigger raster IRQ
576 */
577
578 #ifdef GLOBAL_VARS
raster_irq(void)579 static inline void raster_irq(void)
580 #else
581 inline void MOS6569::raster_irq(void)
582 #endif
583 {
584 irq_flag |= 0x01;
585 if (irq_mask & 0x01) {
586 irq_flag |= 0x80;
587 the_cpu->TriggerVICIRQ();
588 }
589 }
590
591
592 /*
593 * Read from VIC register
594 */
595
ReadRegister(uint16 adr)596 uint8 MOS6569::ReadRegister(uint16 adr)
597 {
598 switch (adr) {
599 case 0x00: case 0x02: case 0x04: case 0x06:
600 case 0x08: case 0x0a: case 0x0c: case 0x0e:
601 return mx[adr >> 1];
602
603 case 0x01: case 0x03: case 0x05: case 0x07:
604 case 0x09: case 0x0b: case 0x0d: case 0x0f:
605 return my[adr >> 1];
606
607 case 0x10: // Sprite X position MSB
608 return mx8;
609
610 case 0x11: // Control register 1
611 return (ctrl1 & 0x7f) | ((raster_y & 0x100) >> 1);
612
613 case 0x12: // Raster counter
614 return raster_y;
615
616 case 0x13: // Light pen X
617 return lpx;
618
619 case 0x14: // Light pen Y
620 return lpy;
621
622 case 0x15: // Sprite enable
623 return me;
624
625 case 0x16: // Control register 2
626 return ctrl2 | 0xc0;
627
628 case 0x17: // Sprite Y expansion
629 return mye;
630
631 case 0x18: // Memory pointers
632 return vbase | 0x01;
633
634 case 0x19: // IRQ flags
635 return irq_flag | 0x70;
636
637 case 0x1a: // IRQ mask
638 return irq_mask | 0xf0;
639
640 case 0x1b: // Sprite data priority
641 return mdp;
642
643 case 0x1c: // Sprite multicolor
644 return mmc;
645
646 case 0x1d: // Sprite X expansion
647 return mxe;
648
649 case 0x1e:{ // Sprite-sprite collision
650 uint8 ret = clx_spr;
651 clx_spr = 0; // Read and clear
652 return ret;
653 }
654
655 case 0x1f:{ // Sprite-background collision
656 uint8 ret = clx_bgr;
657 clx_bgr = 0; // Read and clear
658 return ret;
659 }
660
661 case 0x20: return ec | 0xf0;
662 case 0x21: return b0c | 0xf0;
663 case 0x22: return b1c | 0xf0;
664 case 0x23: return b2c | 0xf0;
665 case 0x24: return b3c | 0xf0;
666 case 0x25: return mm0 | 0xf0;
667 case 0x26: return mm1 | 0xf0;
668
669 case 0x27: case 0x28: case 0x29: case 0x2a:
670 case 0x2b: case 0x2c: case 0x2d: case 0x2e:
671 return sc[adr - 0x27] | 0xf0;
672
673 default:
674 return 0xff;
675 }
676 }
677
678
679 /*
680 * Write to VIC register
681 */
682
WriteRegister(uint16 adr,uint8 byte)683 void MOS6569::WriteRegister(uint16 adr, uint8 byte)
684 {
685 switch (adr) {
686 case 0x00: case 0x02: case 0x04: case 0x06:
687 case 0x08: case 0x0a: case 0x0c: case 0x0e:
688 mx[adr >> 1] = (mx[adr >> 1] & 0xff00) | byte;
689 break;
690
691 case 0x10:{
692 int i, j;
693 mx8 = byte;
694 for (i=0, j=1; i<8; i++, j<<=1) {
695 if (mx8 & j)
696 mx[i] |= 0x100;
697 else
698 mx[i] &= 0xff;
699 }
700 break;
701 }
702
703 case 0x01: case 0x03: case 0x05: case 0x07:
704 case 0x09: case 0x0b: case 0x0d: case 0x0f:
705 my[adr >> 1] = byte;
706 break;
707
708 case 0x11:{ // Control register 1
709 ctrl1 = byte;
710 y_scroll = byte & 7;
711
712 uint16 new_irq_raster = (irq_raster & 0xff) | ((byte & 0x80) << 1);
713 if (irq_raster != new_irq_raster && raster_y == new_irq_raster)
714 raster_irq();
715 irq_raster = new_irq_raster;
716
717 if (byte & 8) {
718 dy_start = ROW25_YSTART;
719 dy_stop = ROW25_YSTOP;
720 } else {
721 dy_start = ROW24_YSTART;
722 dy_stop = ROW24_YSTOP;
723 }
724
725 display_idx = ((ctrl1 & 0x60) | (ctrl2 & 0x10)) >> 4;
726 break;
727 }
728
729 case 0x12:{ // Raster counter
730 uint16 new_irq_raster = (irq_raster & 0xff00) | byte;
731 if (irq_raster != new_irq_raster && raster_y == new_irq_raster)
732 raster_irq();
733 irq_raster = new_irq_raster;
734 break;
735 }
736
737 case 0x15: // Sprite enable
738 me = byte;
739 break;
740
741 case 0x16: // Control register 2
742 ctrl2 = byte;
743 x_scroll = byte & 7;
744 border_40_col = byte & 8;
745 display_idx = ((ctrl1 & 0x60) | (ctrl2 & 0x10)) >> 4;
746 break;
747
748 case 0x17: // Sprite Y expansion
749 mye = byte;
750 break;
751
752 case 0x18: // Memory pointers
753 vbase = byte;
754 matrix_base = get_physical((byte & 0xf0) << 6);
755 char_base = get_physical((byte & 0x0e) << 10);
756 bitmap_base = get_physical((byte & 0x08) << 10);
757 break;
758
759 case 0x19: // IRQ flags
760 irq_flag = irq_flag & (~byte & 0x0f);
761 the_cpu->ClearVICIRQ(); // Clear interrupt (hack!)
762 if (irq_flag & irq_mask) // Set master bit if allowed interrupt still pending
763 irq_flag |= 0x80;
764 break;
765
766 case 0x1a: // IRQ mask
767 irq_mask = byte & 0x0f;
768 if (irq_flag & irq_mask) { // Trigger interrupt if pending and now allowed
769 irq_flag |= 0x80;
770 the_cpu->TriggerVICIRQ();
771 } else {
772 irq_flag &= 0x7f;
773 the_cpu->ClearVICIRQ();
774 }
775 break;
776
777 case 0x1b: // Sprite data priority
778 mdp = byte;
779 break;
780
781 case 0x1c: // Sprite multicolor
782 mmc = byte;
783 break;
784
785 case 0x1d: // Sprite X expansion
786 mxe = byte;
787 break;
788
789 case 0x20:
790 ec_color = colors[ec = byte];
791 ec_color_long = (ec_color << 24) | (ec_color << 16) | (ec_color << 8) | ec_color;
792 break;
793
794 case 0x21:
795 if (b0c != byte) {
796 b0c_color = colors[b0c = byte & 0xF];
797 make_mc_table();
798 }
799 break;
800
801 case 0x22:
802 if (b1c != byte) {
803 b1c_color = colors[b1c = byte & 0xF];
804 make_mc_table();
805 }
806 break;
807
808 case 0x23:
809 if (b2c != byte) {
810 b2c_color = colors[b2c = byte & 0xF];
811 make_mc_table();
812 }
813 break;
814
815 case 0x24: b3c_color = colors[b3c = byte & 0xF]; break;
816 case 0x25: mm0_color = colors[mm0 = byte]; break;
817 case 0x26: mm1_color = colors[mm1 = byte]; break;
818
819 case 0x27: case 0x28: case 0x29: case 0x2a:
820 case 0x2b: case 0x2c: case 0x2d: case 0x2e:
821 spr_color[adr - 0x27] = colors[sc[adr - 0x27] = byte];
822 break;
823 }
824 }
825
826
827 /*
828 * CIA VA14/15 has changed
829 */
830
ChangedVA(uint16 new_va)831 void MOS6569::ChangedVA(uint16 new_va)
832 {
833 cia_vabase = new_va << 14;
834 WriteRegister(0x18, vbase); // Force update of memory pointers
835 }
836
837
838 /*
839 * Trigger lightpen interrupt, latch lightpen coordinates
840 */
841
TriggerLightpen(void)842 void MOS6569::TriggerLightpen(void)
843 {
844 if (!lp_triggered) { // Lightpen triggers only once per frame
845 lp_triggered = true;
846
847 lpx = 0; // Latch current coordinates
848 lpy = raster_y;
849
850 irq_flag |= 0x08; // Trigger IRQ
851 if (irq_mask & 0x08) {
852 irq_flag |= 0x80;
853 the_cpu->TriggerVICIRQ();
854 }
855 }
856 }
857
858
859 /*
860 * VIC vertical blank: Reset counters and redraw screen
861 */
862
863 #ifdef GLOBAL_VARS
vblank(void)864 static inline void vblank(void)
865 #else
866 inline void MOS6569::vblank(void)
867 #endif
868 {
869 raster_y = vc_base = 0;
870 lp_triggered = false;
871
872 if (!(frame_skipped = --skip_counter))
873 skip_counter = ThePrefs.SkipFrames;
874
875 the_c64->VBlank(!frame_skipped);
876
877 // Get bitmap pointer for next frame. This must be done
878 // after calling the_c64->VBlank() because the preferences
879 // and screen configuration may have been changed there
880 chunky_line_start = the_display->BitmapBase();
881 xmod = the_display->BitmapXMod();
882 }
883
884
885 #ifdef __riscos__
886 #include "el_Acorn.i"
887 #else
888
889 #ifdef GLOBAL_VARS
el_std_text(uint8 * p,uint8 * q,uint8 * r)890 static inline void el_std_text(uint8 *p, uint8 *q, uint8 *r)
891 #else
892 inline void MOS6569::el_std_text(uint8 *p, uint8 *q, uint8 *r)
893 #endif
894 {
895 unsigned int b0cc = b0c;
896 #ifdef __POWERPC__
897 double *dp = (double *)p - 1;
898 #else
899 uint32 *lp = (uint32 *)p;
900 #endif
901 uint8 *cp = color_line;
902 uint8 *mp = matrix_line;
903
904 // Loop for 40 characters
905 for (int i=0; i<40; i++) {
906 uint8 color = cp[i];
907 uint8 data = r[i] = q[mp[i] << 3];
908
909 #ifdef __POWERPC__
910 *++dp = TextColorTable[color][b0cc][data].b;
911 #else
912 *lp++ = TextColorTable[color][b0cc][data][0].b;
913 *lp++ = TextColorTable[color][b0cc][data][1].b;
914 #endif
915 }
916 }
917
918
919 #ifdef GLOBAL_VARS
el_mc_text(uint8 * p,uint8 * q,uint8 * r)920 static inline void el_mc_text(uint8 *p, uint8 *q, uint8 *r)
921 #else
922 inline void MOS6569::el_mc_text(uint8 *p, uint8 *q, uint8 *r)
923 #endif
924 {
925 uint16 *wp = (uint16 *)p;
926 uint8 *cp = color_line;
927 uint8 *mp = matrix_line;
928 uint16 *mclp = mc_color_lookup;
929
930 // Loop for 40 characters
931 for (int i=0; i<40; i++) {
932 uint8 data = q[mp[i] << 3];
933
934 if (cp[i] & 8) {
935 uint8 color = colors[cp[i] & 7];
936 r[i] = (data & 0xaa) | (data & 0xaa) >> 1;
937 mclp[3] = color | (color << 8);
938 *wp++ = mclp[(data >> 6) & 3];
939 *wp++ = mclp[(data >> 4) & 3];
940 *wp++ = mclp[(data >> 2) & 3];
941 *wp++ = mclp[(data >> 0) & 3];
942
943 } else { // Standard mode in multicolor mode
944 uint8 color = cp[i];
945 r[i] = data;
946 #ifdef __POWERPC__
947 *(double *)wp = TextColorTable[color][b0c][data].b;
948 wp += 4;
949 #else
950 *(uint32 *)wp = TextColorTable[color][b0c][data][0].b;
951 wp += 2;
952 *(uint32 *)wp = TextColorTable[color][b0c][data][1].b;
953 wp += 2;
954 #endif
955 }
956 }
957 }
958
959
960 #ifdef GLOBAL_VARS
el_std_bitmap(uint8 * p,uint8 * q,uint8 * r)961 static inline void el_std_bitmap(uint8 *p, uint8 *q, uint8 *r)
962 #else
963 inline void MOS6569::el_std_bitmap(uint8 *p, uint8 *q, uint8 *r)
964 #endif
965 {
966 #ifdef __POWERPC__
967 double *dp = (double *)p-1;
968 #else
969 uint32 *lp = (uint32 *)p;
970 #endif
971 uint8 *mp = matrix_line;
972
973 // Loop for 40 characters
974 for (int i=0; i<40; i++, q+=8) {
975 uint8 data = r[i] = *q;
976 uint8 color = mp[i] >> 4;
977 uint8 bcolor = mp[i] & 15;
978
979 #ifdef __POWERPC__
980 *++dp = TextColorTable[color][bcolor][data].b;
981 #else
982 *lp++ = TextColorTable[color][bcolor][data][0].b;
983 *lp++ = TextColorTable[color][bcolor][data][1].b;
984 #endif
985 }
986 }
987
988
989 #ifdef GLOBAL_VARS
el_mc_bitmap(uint8 * p,uint8 * q,uint8 * r)990 static inline void el_mc_bitmap(uint8 *p, uint8 *q, uint8 *r)
991 #else
992 inline void MOS6569::el_mc_bitmap(uint8 *p, uint8 *q, uint8 *r)
993 #endif
994 {
995 uint16 lookup[4];
996 uint16 *wp = (uint16 *)p - 1;
997 uint8 *cp = color_line;
998 uint8 *mp = matrix_line;
999
1000 #ifdef __GNU_C__
1001 &lookup; /* Statement with no effect other than preventing GCC from
1002 * putting the array in a register, which generates
1003 * spectacularly bad code. */
1004 #endif
1005
1006 lookup[0] = (b0c_color << 8) | b0c_color;
1007
1008 // Loop for 40 characters
1009 for (int i=0; i<40; i++, q+=8) {
1010 uint8 color, acolor, bcolor;
1011
1012 color = colors[mp[i] >> 4];
1013 lookup[1] = (color << 8) | color;
1014 bcolor = colors[mp[i]];
1015 lookup[2] = (bcolor << 8) | bcolor;
1016 acolor = colors[cp[i]];
1017 lookup[3] = (acolor << 8) | acolor;
1018
1019 uint8 data = *q;
1020 r[i] = (data & 0xaa) | (data & 0xaa) >> 1;
1021
1022 *++wp = lookup[(data >> 6) & 3];
1023 *++wp = lookup[(data >> 4) & 3];
1024 *++wp = lookup[(data >> 2) & 3];
1025 *++wp = lookup[(data >> 0) & 3];
1026 }
1027 }
1028
1029
1030 #ifdef GLOBAL_VARS
el_ecm_text(uint8 * p,uint8 * q,uint8 * r)1031 static inline void el_ecm_text(uint8 *p, uint8 *q, uint8 *r)
1032 #else
1033 inline void MOS6569::el_ecm_text(uint8 *p, uint8 *q, uint8 *r)
1034 #endif
1035 {
1036 #ifdef __POWERPC__
1037 double *dp = (double *)p - 1;
1038 #else
1039 uint32 *lp = (uint32 *)p;
1040 #endif
1041 uint8 *cp = color_line;
1042 uint8 *mp = matrix_line;
1043 uint8 *bcp = &b0c;
1044
1045 // Loop for 40 characters
1046 for (int i=0; i<40; i++) {
1047 uint8 data = r[i] = mp[i];
1048 uint8 color = cp[i];
1049 uint8 bcolor = bcp[(data >> 6) & 3];
1050
1051 data = q[(data & 0x3f) << 3];
1052 #ifdef __POWERPC__
1053 *++dp = TextColorTable[color][bcolor][data].b;
1054 #else
1055 *lp++ = TextColorTable[color][bcolor][data][0].b;
1056 *lp++ = TextColorTable[color][bcolor][data][1].b;
1057 #endif
1058 }
1059 }
1060
1061
1062 #ifdef GLOBAL_VARS
el_std_idle(uint8 * p,uint8 * r)1063 static inline void el_std_idle(uint8 *p, uint8 *r)
1064 #else
1065 inline void MOS6569::el_std_idle(uint8 *p, uint8 *r)
1066 #endif
1067 {
1068 #ifdef __POWERPC__
1069 uint8 data = *get_physical(ctrl1 & 0x40 ? 0x39ff : 0x3fff);
1070 double *dp = (double *)p - 1;
1071 double conv = TextColorTable[0][b0c][data].b;
1072 r--;
1073
1074 for (int i=0; i<40; i++) {
1075 *++dp = conv;
1076 *++r = data;
1077 }
1078 #else
1079 uint8 data = *get_physical(ctrl1 & 0x40 ? 0x39ff : 0x3fff);
1080 uint32 *lp = (uint32 *)p;
1081 uint32 conv0 = TextColorTable[0][b0c][data][0].b;
1082 uint32 conv1 = TextColorTable[0][b0c][data][1].b;
1083
1084 for (int i=0; i<40; i++) {
1085 *lp++ = conv0;
1086 *lp++ = conv1;
1087 *r++ = data;
1088 }
1089 #endif
1090 }
1091
1092
1093 #ifdef GLOBAL_VARS
el_mc_idle(uint8 * p,uint8 * r)1094 static inline void el_mc_idle(uint8 *p, uint8 *r)
1095 #else
1096 inline void MOS6569::el_mc_idle(uint8 *p, uint8 *r)
1097 #endif
1098 {
1099 uint8 data = *get_physical(0x3fff);
1100 uint32 *lp = (uint32 *)p - 1;
1101 r--;
1102
1103 uint16 lookup[4];
1104 lookup[0] = (b0c_color << 8) | b0c_color;
1105 lookup[1] = lookup[2] = lookup[3] = colors[0];
1106
1107 uint16 conv0 = (lookup[(data >> 6) & 3] << 16) | lookup[(data >> 4) & 3];
1108 uint16 conv1 = (lookup[(data >> 2) & 3] << 16) | lookup[(data >> 0) & 3];
1109
1110 for (int i=0; i<40; i++) {
1111 *++lp = conv0;
1112 *++lp = conv1;
1113 *++r = data;
1114 }
1115 }
1116
1117 #endif //__riscos__
1118
1119
1120 #ifdef GLOBAL_VARS
el_sprites(uint8 * chunky_ptr)1121 static inline void el_sprites(uint8 *chunky_ptr)
1122 #else
1123 inline void MOS6569::el_sprites(uint8 *chunky_ptr)
1124 #endif
1125 {
1126 int i;
1127 int snum, sbit; // Sprite number/bit mask
1128 int spr_coll=0, gfx_coll=0;
1129
1130 // Draw each active sprite
1131 for (snum=0, sbit=1; snum<8; snum++, sbit<<=1)
1132 if ((sprite_on & sbit) && mx[snum] < DISPLAY_X-32) {
1133 int spr_mask_pos; // Sprite bit position in fore_mask_buf
1134 uint32 sdata, fore_mask;
1135
1136 uint8 *p = chunky_ptr + mx[snum] + 8;
1137 uint8 *q = spr_coll_buf + mx[snum] + 8;
1138
1139 uint8 *sdatap = get_physical(matrix_base[0x3f8 + snum] << 6 | mc[snum]);
1140 sdata = (*sdatap << 24) | (*(sdatap+1) << 16) | (*(sdatap+2) << 8);
1141
1142 uint8 color = spr_color[snum];
1143
1144 spr_mask_pos = mx[snum] + 8 - x_scroll;
1145
1146 uint8 *fmbp = fore_mask_buf + (spr_mask_pos / 8);
1147 int sshift = spr_mask_pos & 7;
1148 fore_mask = (((*(fmbp+0) << 24) | (*(fmbp+1) << 16) | (*(fmbp+2) << 8)
1149 | (*(fmbp+3))) << sshift) | (*(fmbp+4) >> (8-sshift));
1150
1151 if (mxe & sbit) { // X-expanded
1152 if (mx[snum] >= DISPLAY_X-56)
1153 continue;
1154
1155 uint32 sdata_l = 0, sdata_r = 0, fore_mask_r;
1156 fore_mask_r = (((*(fmbp+4) << 24) | (*(fmbp+5) << 16) | (*(fmbp+6) << 8)
1157 | (*(fmbp+7))) << sshift) | (*(fmbp+8) >> (8-sshift));
1158
1159 if (mmc & sbit) { // Multicolor mode
1160 uint32 plane0_l, plane0_r, plane1_l, plane1_r;
1161
1162 // Expand sprite data
1163 sdata_l = MultiExpTable[sdata >> 24 & 0xff] << 16 | MultiExpTable[sdata >> 16 & 0xff];
1164 sdata_r = MultiExpTable[sdata >> 8 & 0xff] << 16;
1165
1166 // Convert sprite chunky pixels to bitplanes
1167 plane0_l = (sdata_l & 0x55555555) | (sdata_l & 0x55555555) << 1;
1168 plane1_l = (sdata_l & 0xaaaaaaaa) | (sdata_l & 0xaaaaaaaa) >> 1;
1169 plane0_r = (sdata_r & 0x55555555) | (sdata_r & 0x55555555) << 1;
1170 plane1_r = (sdata_r & 0xaaaaaaaa) | (sdata_r & 0xaaaaaaaa) >> 1;
1171
1172 // Collision with graphics?
1173 if ((fore_mask & (plane0_l | plane1_l)) || (fore_mask_r & (plane0_r | plane1_r))) {
1174 gfx_coll |= sbit;
1175 if (mdp & sbit) {
1176 plane0_l &= ~fore_mask; // Mask sprite if in background
1177 plane1_l &= ~fore_mask;
1178 plane0_r &= ~fore_mask_r;
1179 plane1_r &= ~fore_mask_r;
1180 }
1181 }
1182
1183 // Paint sprite
1184 for (i=0; i<32; i++, plane0_l<<=1, plane1_l<<=1) {
1185 uint8 col;
1186 if (plane1_l & 0x80000000) {
1187 if (plane0_l & 0x80000000)
1188 col = mm1_color;
1189 else
1190 col = color;
1191 } else {
1192 if (plane0_l & 0x80000000)
1193 col = mm0_color;
1194 else
1195 continue;
1196 }
1197 if (q[i])
1198 spr_coll |= q[i] | sbit;
1199 else {
1200 p[i] = col;
1201 q[i] = sbit;
1202 }
1203 }
1204 for (; i<48; i++, plane0_r<<=1, plane1_r<<=1) {
1205 uint8 col;
1206 if (plane1_r & 0x80000000) {
1207 if (plane0_r & 0x80000000)
1208 col = mm1_color;
1209 else
1210 col = color;
1211 } else {
1212 if (plane0_r & 0x80000000)
1213 col = mm0_color;
1214 else
1215 continue;
1216 }
1217 if (q[i])
1218 spr_coll |= q[i] | sbit;
1219 else {
1220 p[i] = col;
1221 q[i] = sbit;
1222 }
1223 }
1224
1225 } else { // Standard mode
1226
1227 // Expand sprite data
1228 sdata_l = ExpTable[sdata >> 24 & 0xff] << 16 | ExpTable[sdata >> 16 & 0xff];
1229 sdata_r = ExpTable[sdata >> 8 & 0xff] << 16;
1230
1231 // Collision with graphics?
1232 if ((fore_mask & sdata_l) || (fore_mask_r & sdata_r)) {
1233 gfx_coll |= sbit;
1234 if (mdp & sbit) {
1235 sdata_l &= ~fore_mask; // Mask sprite if in background
1236 sdata_r &= ~fore_mask_r;
1237 }
1238 }
1239
1240 // Paint sprite
1241 for (i=0; i<32; i++, sdata_l<<=1)
1242 if (sdata_l & 0x80000000) {
1243 if (q[i]) // Collision with sprite?
1244 spr_coll |= q[i] | sbit;
1245 else { // Draw pixel if no collision
1246 p[i] = color;
1247 q[i] = sbit;
1248 }
1249 }
1250 for (; i<48; i++, sdata_r<<=1)
1251 if (sdata_r & 0x80000000) {
1252 if (q[i]) // Collision with sprite?
1253 spr_coll |= q[i] | sbit;
1254 else { // Draw pixel if no collision
1255 p[i] = color;
1256 q[i] = sbit;
1257 }
1258 }
1259 }
1260
1261 } else // Unexpanded
1262
1263 if (mmc & sbit) { // Multicolor mode
1264 uint32 plane0, plane1;
1265
1266 // Convert sprite chunky pixels to bitplanes
1267 plane0 = (sdata & 0x55555555) | (sdata & 0x55555555) << 1;
1268 plane1 = (sdata & 0xaaaaaaaa) | (sdata & 0xaaaaaaaa) >> 1;
1269
1270 // Collision with graphics?
1271 if (fore_mask & (plane0 | plane1)) {
1272 gfx_coll |= sbit;
1273 if (mdp & sbit) {
1274 plane0 &= ~fore_mask; // Mask sprite if in background
1275 plane1 &= ~fore_mask;
1276 }
1277 }
1278
1279 // Paint sprite
1280 for (i=0; i<24; i++, plane0<<=1, plane1<<=1) {
1281 uint8 col;
1282 if (plane1 & 0x80000000) {
1283 if (plane0 & 0x80000000)
1284 col = mm1_color;
1285 else
1286 col = color;
1287 } else {
1288 if (plane0 & 0x80000000)
1289 col = mm0_color;
1290 else
1291 continue;
1292 }
1293 if (q[i])
1294 spr_coll |= q[i] | sbit;
1295 else {
1296 p[i] = col;
1297 q[i] = sbit;
1298 }
1299 }
1300
1301 } else { // Standard mode
1302
1303 // Collision with graphics?
1304 if (fore_mask & sdata) {
1305 gfx_coll |= sbit;
1306 if (mdp & sbit)
1307 sdata &= ~fore_mask; // Mask sprite if in background
1308 }
1309
1310 // Paint sprite
1311 for (i=0; i<24; i++, sdata<<=1)
1312 if (sdata & 0x80000000) {
1313 if (q[i]) { // Collision with sprite?
1314 spr_coll |= q[i] | sbit;
1315 } else { // Draw pixel if no collision
1316 p[i] = color;
1317 q[i] = sbit;
1318 }
1319 }
1320
1321 }
1322 }
1323
1324 if (ThePrefs.SpriteCollisions) {
1325
1326 // Check sprite-sprite collisions
1327 if (clx_spr)
1328 clx_spr |= spr_coll;
1329 else {
1330 clx_spr |= spr_coll;
1331 irq_flag |= 0x04;
1332 if (irq_mask & 0x04) {
1333 irq_flag |= 0x80;
1334 the_cpu->TriggerVICIRQ();
1335 }
1336 }
1337
1338 // Check sprite-background collisions
1339 if (clx_bgr)
1340 clx_bgr |= gfx_coll;
1341 else {
1342 clx_bgr |= gfx_coll;
1343 irq_flag |= 0x02;
1344 if (irq_mask & 0x02) {
1345 irq_flag |= 0x80;
1346 the_cpu->TriggerVICIRQ();
1347 }
1348 }
1349 }
1350 }
1351
1352
1353 #ifdef GLOBAL_VARS
el_update_mc(int raster)1354 static inline int el_update_mc(int raster)
1355 #else
1356 inline int MOS6569::el_update_mc(int raster)
1357 #endif
1358 {
1359 int i, j;
1360 int cycles_used = 0;
1361 uint8 spron = sprite_on;
1362 uint8 spren = me;
1363 uint8 sprye = mye;
1364 uint8 raster8bit = raster;
1365 uint16 *mcp = mc;
1366 uint8 *myp = my;
1367
1368 // Increment sprite data counters
1369 for (i=0, j=1; i<8; i++, j<<=1, mcp++, myp++) {
1370
1371 // Sprite enabled?
1372 if (spren & j)
1373
1374 // Yes, activate if Y position matches raster counter
1375 if (*myp == (raster8bit & 0xff)) {
1376 *mcp = 0;
1377 spron |= j;
1378 } else
1379 goto spr_off;
1380 else
1381 spr_off:
1382 // No, turn sprite off when data counter exceeds 60
1383 // and increment counter
1384 if (*mcp != 63) {
1385 if (sprye & j) { // Y expansion
1386 if (!((*myp ^ raster8bit) & 1)) {
1387 *mcp += 3;
1388 cycles_used += 2;
1389 if (*mcp == 63)
1390 spron &= ~j;
1391 }
1392 } else {
1393 *mcp += 3;
1394 cycles_used += 2;
1395 if (*mcp == 63)
1396 spron &= ~j;
1397 }
1398 }
1399 }
1400
1401 sprite_on = spron;
1402 return cycles_used;
1403 }
1404
1405
1406 #ifdef __POWERPC__
1407 static asm void fastcopy(register uchar *dst, register uchar *src);
fastcopy(register uchar * dst,register uchar * src)1408 static asm void fastcopy(register uchar *dst, register uchar *src)
1409 {
1410 lfd fp0,0(src)
1411 lfd fp1,8(src)
1412 lfd fp2,16(src)
1413 lfd fp3,24(src)
1414 lfd fp4,32(src)
1415 lfd fp5,40(src)
1416 lfd fp6,48(src)
1417 lfd fp7,56(src)
1418 addi src,src,64
1419 stfd fp0,0(dst)
1420 stfd fp1,8(dst)
1421 stfd fp2,16(dst)
1422 stfd fp3,24(dst)
1423 stfd fp4,32(dst)
1424 stfd fp5,40(dst)
1425 stfd fp6,48(dst)
1426 stfd fp7,56(dst)
1427 addi dst,dst,64
1428
1429 lfd fp0,0(src)
1430 lfd fp1,8(src)
1431 lfd fp2,16(src)
1432 lfd fp3,24(src)
1433 lfd fp4,32(src)
1434 lfd fp5,40(src)
1435 lfd fp6,48(src)
1436 lfd fp7,56(src)
1437 addi src,src,64
1438 stfd fp0,0(dst)
1439 stfd fp1,8(dst)
1440 stfd fp2,16(dst)
1441 stfd fp3,24(dst)
1442 stfd fp4,32(dst)
1443 stfd fp5,40(dst)
1444 stfd fp6,48(dst)
1445 stfd fp7,56(dst)
1446 addi dst,dst,64
1447
1448 lfd fp0,0(src)
1449 lfd fp1,8(src)
1450 lfd fp2,16(src)
1451 lfd fp3,24(src)
1452 lfd fp4,32(src)
1453 lfd fp5,40(src)
1454 lfd fp6,48(src)
1455 lfd fp7,56(src)
1456 addi src,src,64
1457 stfd fp0,0(dst)
1458 stfd fp1,8(dst)
1459 stfd fp2,16(dst)
1460 stfd fp3,24(dst)
1461 stfd fp4,32(dst)
1462 stfd fp5,40(dst)
1463 stfd fp6,48(dst)
1464 stfd fp7,56(dst)
1465 addi dst,dst,64
1466
1467 lfd fp0,0(src)
1468 lfd fp1,8(src)
1469 lfd fp2,16(src)
1470 lfd fp3,24(src)
1471 lfd fp4,32(src)
1472 lfd fp5,40(src)
1473 lfd fp6,48(src)
1474 lfd fp7,56(src)
1475 addi src,src,64
1476 stfd fp0,0(dst)
1477 stfd fp1,8(dst)
1478 stfd fp2,16(dst)
1479 stfd fp3,24(dst)
1480 stfd fp4,32(dst)
1481 stfd fp5,40(dst)
1482 stfd fp6,48(dst)
1483 stfd fp7,56(dst)
1484 addi dst,dst,64
1485
1486 lfd fp0,0(src)
1487 lfd fp1,8(src)
1488 lfd fp2,16(src)
1489 lfd fp3,24(src)
1490 lfd fp4,32(src)
1491 lfd fp5,40(src)
1492 lfd fp6,48(src)
1493 lfd fp7,56(src)
1494 addi src,src,64
1495 stfd fp0,0(dst)
1496 stfd fp1,8(dst)
1497 stfd fp2,16(dst)
1498 stfd fp3,24(dst)
1499 stfd fp4,32(dst)
1500 stfd fp5,40(dst)
1501 stfd fp6,48(dst)
1502 stfd fp7,56(dst)
1503 addi dst,dst,64
1504
1505 lfd fp0,0(src)
1506 lfd fp1,8(src)
1507 lfd fp2,16(src)
1508 lfd fp3,24(src)
1509 lfd fp4,32(src)
1510 lfd fp5,40(src)
1511 lfd fp6,48(src)
1512 lfd fp7,56(src)
1513 addi src,src,64
1514 stfd fp0,0(dst)
1515 stfd fp1,8(dst)
1516 stfd fp2,16(dst)
1517 stfd fp3,24(dst)
1518 stfd fp4,32(dst)
1519 stfd fp5,40(dst)
1520 stfd fp6,48(dst)
1521 stfd fp7,56(dst)
1522 addi dst,dst,64
1523 blr
1524 }
1525 #endif
1526
1527
1528 /*
1529 * Emulate one raster line
1530 */
1531
EmulateLine(void)1532 int MOS6569::EmulateLine(void)
1533 {
1534 int cycles_left = ThePrefs.NormalCycles; // Cycles left for CPU
1535 bool is_bad_line = false;
1536
1537 // Get raster counter into local variable for faster access and increment
1538 unsigned int raster = raster_y+1;
1539
1540 // End of screen reached?
1541 if (raster != TOTAL_RASTERS)
1542 raster_y = raster;
1543 else {
1544 vblank();
1545 raster = 0;
1546 }
1547
1548 // Trigger raster IRQ if IRQ line reached
1549 if (raster == irq_raster)
1550 raster_irq();
1551
1552 // In line $30, the DEN bit controls if Bad Lines can occur
1553 if (raster == 0x30)
1554 bad_lines_enabled = ctrl1 & 0x10;
1555
1556 // Skip frame? Only calculate Bad Lines then
1557 if (frame_skipped) {
1558 if (raster >= FIRST_DMA_LINE && raster <= LAST_DMA_LINE && ((raster & 7) == y_scroll) && bad_lines_enabled) {
1559 is_bad_line = true;
1560 cycles_left = ThePrefs.BadLineCycles;
1561 }
1562 goto VIC_nop;
1563 }
1564
1565 // Within the visible range?
1566 if (raster >= FIRST_DISP_LINE && raster <= LAST_DISP_LINE) {
1567
1568 // Our output goes here
1569 #ifdef __POWERPC__
1570 uint8 *chunky_ptr = (uint8 *)chunky_tmp;
1571 #else
1572 uint8 *chunky_ptr = chunky_line_start;
1573 #endif
1574
1575 // Set video counter
1576 vc = vc_base;
1577
1578 // Bad Line condition?
1579 if (raster >= FIRST_DMA_LINE && raster <= LAST_DMA_LINE && ((raster & 7) == y_scroll) && bad_lines_enabled) {
1580
1581 // Turn on display
1582 display_state = is_bad_line = true;
1583 cycles_left = ThePrefs.BadLineCycles;
1584 rc = 0;
1585
1586 // Read and latch 40 bytes from video matrix and color RAM
1587 uint8 *mp = matrix_line - 1;
1588 uint8 *cp = color_line - 1;
1589 int vc1 = vc - 1;
1590 uint8 *mbp = matrix_base + vc1;
1591 uint8 *crp = color_ram + vc1;
1592 for (int i=0; i<40; i++) {
1593 *++mp = *++mbp;
1594 *++cp = *++crp;
1595 }
1596 }
1597
1598 // Handler upper/lower border
1599 if (raster == dy_stop)
1600 border_on = true;
1601 if (raster == dy_start && (ctrl1 & 0x10)) // Don't turn off border if DEN bit cleared
1602 border_on = false;
1603
1604 if (!border_on) {
1605
1606 // Display window contents
1607 uint8 *p = chunky_ptr + COL40_XSTART; // Pointer in chunky display buffer
1608 uint8 *r = fore_mask_buf + COL40_XSTART/8; // Pointer in foreground mask buffer
1609 #ifdef ALIGNMENT_CHECK
1610 uint8 *use_p = ((((int)p) & 3) == 0) ? p : text_chunky_buf;
1611 #endif
1612
1613 {
1614 p--;
1615 uint8 b0cc = b0c_color;
1616 int limit = x_scroll;
1617 for (int i=0; i<limit; i++) // Background on the left if XScroll>0
1618 *++p = b0cc;
1619 p++;
1620 }
1621
1622 if (display_state) {
1623 switch (display_idx) {
1624
1625 case 0: // Standard text
1626 #ifndef CAN_ACCESS_UNALIGNED
1627 #ifdef ALIGNMENT_CHECK
1628 el_std_text(use_p, char_base + rc, r);
1629 if (use_p != p)
1630 memcpy(p, use_p, 8*40);
1631 #else
1632 if (x_scroll) {
1633 el_std_text(text_chunky_buf, char_base + rc, r);
1634 memcpy(p, text_chunky_buf, 8*40);
1635 } else
1636 el_std_text(p, char_base + rc, r);
1637 #endif
1638 #else
1639 el_std_text(p, char_base + rc, r);
1640 #endif
1641 break;
1642
1643 case 1: // Multicolor text
1644 #ifndef CAN_ACCESS_UNALIGNED
1645 #ifdef ALIGNMENT_CHECK
1646 el_mc_text(use_p, char_base + rc, r);
1647 if (use_p != p)
1648 memcpy(p, use_p, 8*40);
1649 #else
1650 if (x_scroll) {
1651 el_mc_text(text_chunky_buf, char_base + rc, r);
1652 memcpy(p, text_chunky_buf, 8*40);
1653 } else
1654 el_mc_text(p, char_base + rc, r);
1655 #endif
1656 #else
1657 el_mc_text(p, char_base + rc, r);
1658 #endif
1659 break;
1660
1661 case 2: // Standard bitmap
1662 #ifndef CAN_ACCESS_UNALIGNED
1663 #ifdef ALIGNMENT_CHECK
1664 el_std_bitmap(use_p, bitmap_base + (vc << 3) + rc, r);
1665 if (use_p != p)
1666 memcpy(p, use_p, 8*40);
1667 #else
1668 if (x_scroll) {
1669 el_std_bitmap(text_chunky_buf, bitmap_base + (vc << 3) + rc, r);
1670 memcpy(p, text_chunky_buf, 8*40);
1671 } else
1672 el_std_bitmap(p, bitmap_base + (vc << 3) + rc, r);
1673 #endif
1674 #else
1675 el_std_bitmap(p, bitmap_base + (vc << 3) + rc, r);
1676 #endif
1677 break;
1678
1679 case 3: // Multicolor bitmap
1680 #ifndef CAN_ACCESS_UNALIGNED
1681 #ifdef ALIGNMENT_CHECK
1682 el_mc_bitmap(use_p, bitmap_base + (vc << 3) + rc, r);
1683 if (use_p != p)
1684 memcpy(p, use_p, 8*40);
1685 #else
1686 if (x_scroll) {
1687 el_mc_bitmap(text_chunky_buf, bitmap_base + (vc << 3) + rc, r);
1688 memcpy(p, text_chunky_buf, 8*40);
1689 } else
1690 el_mc_bitmap(p, bitmap_base + (vc << 3) + rc, r);
1691 #endif
1692 #else
1693 el_mc_bitmap(p, bitmap_base + (vc << 3) + rc, r);
1694 #endif
1695 break;
1696
1697 case 4: // ECM text
1698 #ifndef CAN_ACCESS_UNALIGNED
1699 #ifdef ALIGNMENT_CHECK
1700 el_ecm_text(use_p, char_base + rc, r);
1701 if (use_p != p)
1702 memcpy(p, use_p, 8*40);
1703 #else
1704 if (x_scroll) {
1705 el_ecm_text(text_chunky_buf, char_base + rc, r);
1706 memcpy(p, text_chunky_buf, 8*40);
1707 } else
1708 el_ecm_text(p, char_base + rc, r);
1709 #endif
1710 #else
1711 el_ecm_text(p, char_base + rc, r);
1712 #endif
1713 break;
1714
1715 default: // Invalid mode (all black)
1716 memset(p, colors[0], 320);
1717 memset(r, 0, 40);
1718 break;
1719 }
1720 vc += 40;
1721
1722 } else { // Idle state graphics
1723 switch (display_idx) {
1724
1725 case 0: // Standard text
1726 case 1: // Multicolor text
1727 case 4: // ECM text
1728 #ifndef CAN_ACCESS_UNALIGNED
1729 #ifdef ALIGNMENT_CHECK
1730 el_std_idle(use_p, r);
1731 if (use_p != p) {memcpy(p, use_p, 8*40);}
1732 #else
1733 if (x_scroll) {
1734 el_std_idle(text_chunky_buf, r);
1735 memcpy(p, text_chunky_buf, 8*40);
1736 } else
1737 el_std_idle(p, r);
1738 #endif
1739 #else
1740 el_std_idle(p, r);
1741 #endif
1742 break;
1743
1744 case 3: // Multicolor bitmap
1745 #ifndef CAN_ACCESS_UNALIGNED
1746 #ifdef ALIGNMENT_CHECK
1747 el_mc_idle(use_p, r);
1748 if (use_p != p) {memcpy(p, use_p, 8*40);}
1749 #else
1750 if (x_scroll) {
1751 el_mc_idle(text_chunky_buf, r);
1752 memcpy(p, text_chunky_buf, 8*40);
1753 } else
1754 el_mc_idle(p, r);
1755 #endif
1756 #else
1757 el_mc_idle(p, r);
1758 #endif
1759 break;
1760
1761 default: // Invalid mode (all black)
1762 memset(p, colors[0], 320);
1763 memset(r, 0, 40);
1764 break;
1765 }
1766 }
1767
1768 // Draw sprites
1769 if (sprite_on && ThePrefs.SpritesOn) {
1770
1771 // Clear sprite collision buffer
1772 uint32 *lp = (uint32 *)spr_coll_buf - 1;
1773 for (int i=0; i<DISPLAY_X/4; i++)
1774 *++lp = 0;
1775
1776 el_sprites(chunky_ptr);
1777 }
1778
1779 // Handle left/right border
1780 uint32 *lp = (uint32 *)chunky_ptr - 1;
1781 uint32 c = ec_color_long;
1782 for (int i=0; i<COL40_XSTART/4; i++)
1783 *++lp = c;
1784 lp = (uint32 *)(chunky_ptr + COL40_XSTOP) - 1;
1785 for (int i=0; i<(DISPLAY_X-COL40_XSTOP)/4; i++)
1786 *++lp = c;
1787 if (!border_40_col) {
1788 c = ec_color;
1789 p = chunky_ptr + COL40_XSTART - 1;
1790 for (int i=0; i<COL38_XSTART-COL40_XSTART; i++)
1791 *++p = c;
1792 p = chunky_ptr + COL38_XSTOP - 1;
1793 for (int i=0; i<COL40_XSTOP-COL38_XSTOP; i++)
1794 *++p = c;
1795 }
1796
1797 #if 0
1798 if (is_bad_line) {
1799 chunky_ptr[DISPLAY_X-2] = colors[7];
1800 chunky_ptr[DISPLAY_X-3] = colors[7];
1801 }
1802 if (rc & 1) {
1803 chunky_ptr[DISPLAY_X-4] = colors[1];
1804 chunky_ptr[DISPLAY_X-5] = colors[1];
1805 }
1806 if (rc & 2) {
1807 chunky_ptr[DISPLAY_X-6] = colors[1];
1808 chunky_ptr[DISPLAY_X-7] = colors[1];
1809 }
1810 if (rc & 4) {
1811 chunky_ptr[DISPLAY_X-8] = colors[1];
1812 chunky_ptr[DISPLAY_X-9] = colors[1];
1813 }
1814 if (ctrl1 & 0x40) {
1815 chunky_ptr[DISPLAY_X-10] = colors[5];
1816 chunky_ptr[DISPLAY_X-11] = colors[5];
1817 }
1818 if (ctrl1 & 0x20) {
1819 chunky_ptr[DISPLAY_X-12] = colors[3];
1820 chunky_ptr[DISPLAY_X-13] = colors[3];
1821 }
1822 if (ctrl2 & 0x10) {
1823 chunky_ptr[DISPLAY_X-14] = colors[2];
1824 chunky_ptr[DISPLAY_X-15] = colors[2];
1825 }
1826 #endif
1827 } else {
1828
1829 // Display border
1830 uint32 *lp = (uint32 *)chunky_ptr - 1;
1831 uint32 c = ec_color_long;
1832 for (int i=0; i<DISPLAY_X/4; i++)
1833 *++lp = c;
1834 }
1835
1836 #ifdef __POWERPC__
1837 // Copy temporary buffer to bitmap
1838 fastcopy(chunky_line_start, (uint8 *)chunky_tmp);
1839 #endif
1840
1841 // Increment pointer in chunky buffer
1842 chunky_line_start += xmod;
1843
1844 // Increment row counter, go to idle state on overflow
1845 if (rc == 7) {
1846 display_state = false;
1847 vc_base = vc;
1848 } else
1849 rc++;
1850
1851 if (raster >= FIRST_DMA_LINE-1 && raster <= LAST_DMA_LINE-1 && (((raster+1) & 7) == y_scroll) && bad_lines_enabled)
1852 rc = 0;
1853 }
1854
1855 VIC_nop:
1856 // Skip this if all sprites are off
1857 if (me | sprite_on)
1858 cycles_left -= el_update_mc(raster);
1859
1860 return cycles_left;
1861 }
1862