ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/VIC_SC.cpp
Revision: 1.6
Committed: 2010-04-21T19:53:28Z (13 years, 11 months ago) by cebix
Branch: MAIN
CVS Tags: HEAD
Changes since 1.5: +6 -4 lines
Log Message:
added missing initializations

File Contents

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