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