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