ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/VIC.cpp
Revision: 1.5
Committed: 2010-04-21T20:42:09Z (12 years, 7 months ago) by cebix
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +3 -2 lines
Log Message:
added missing initialization

File Contents

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