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