ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/VIC_SC.cpp
Revision: 1.5
Committed: 2005-06-27T19:55:48Z (18 years, 9 months ago) by cebix
Branch: MAIN
CVS Tags: VERSION_4_2
Changes since 1.4: +1 -1 lines
Log Message:
updated copyright dates

File Contents

# Content
1 /*
2 * VIC_SC.cpp - 6569R5 emulation (cycle based)
3 *
4 * Frodo (C) 1994-1997,2002-2005 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
290 spr_dma_on = spr_disp_on = 0;
291 for (i=0; i<8; i++) {
292 mc[i] = 63;
293 spr_ptr[i] = 0;
294 }
295
296 frame_skipped = false;
297 skip_counter = 1;
298
299 memset(spr_coll_buf, 0, 0x180);
300 memset(fore_mask_buf, 0, 0x180/8);
301
302 // Preset colors to black
303 disp->InitColors(colors);
304 ec_color = b0c_color = b1c_color = b2c_color = b3c_color = mm0_color = mm1_color = colors[0];
305 for (i=0; i<8; i++) spr_color[i] = colors[0];
306 }
307
308
309 /*
310 * Reinitialize the colors table for when the palette has changed
311 */
312
313 void MOS6569::ReInitColors(void)
314 {
315 int i;
316
317 // Build inverse color table.
318 uint8 xlate_colors[256];
319 memset(xlate_colors, 0, sizeof(xlate_colors));
320 for (i=0; i<16; i++)
321 xlate_colors[colors[i]] = i;
322
323 // Get the new colors.
324 the_display->InitColors(colors);
325
326 // Build color translation table.
327 for (i=0; i<256; i++)
328 xlate_colors[i] = colors[xlate_colors[i]];
329
330 // Translate all the old colors variables.
331 ec_color = colors[ec];
332 b0c_color = colors[b0c];
333 b1c_color = colors[b1c];
334 b2c_color = colors[b2c];
335 b3c_color = colors[b3c];
336 mm0_color = colors[mm0];
337 mm1_color = colors[mm1];
338 for (i=0; i<8; i++)
339 spr_color[i] = colors[sc[i]];
340
341 // Translate the border color sample buffer.
342 for (unsigned x = 0; x < sizeof(border_color_sample); x++)
343 border_color_sample[x] = xlate_colors[border_color_sample[x]];
344
345 // Translate the chunky buffer.
346 uint8 *scanline = the_display->BitmapBase();
347 for (int y=0; y<DISPLAY_Y; y++) {
348 for (int x=0; x<DISPLAY_X; x++)
349 scanline[x] = xlate_colors[scanline[x]];
350 scanline += xmod;
351 }
352 }
353
354
355 /*
356 * Get VIC state
357 */
358
359 void MOS6569::GetState(MOS6569State *vd)
360 {
361 int i;
362
363 vd->m0x = mx[0] & 0xff; vd->m0y = my[0];
364 vd->m1x = mx[1] & 0xff; vd->m1y = my[1];
365 vd->m2x = mx[2] & 0xff; vd->m2y = my[2];
366 vd->m3x = mx[3] & 0xff; vd->m3y = my[3];
367 vd->m4x = mx[4] & 0xff; vd->m4y = my[4];
368 vd->m5x = mx[5] & 0xff; vd->m5y = my[5];
369 vd->m6x = mx[6] & 0xff; vd->m6y = my[6];
370 vd->m7x = mx[7] & 0xff; vd->m7y = my[7];
371 vd->mx8 = mx8;
372
373 vd->ctrl1 = (ctrl1 & 0x7f) | ((raster_y & 0x100) >> 1);
374 vd->raster = raster_y & 0xff;
375 vd->lpx = lpx; vd->lpy = lpy;
376 vd->ctrl2 = ctrl2;
377 vd->vbase = vbase;
378 vd->irq_flag = irq_flag;
379 vd->irq_mask = irq_mask;
380
381 vd->me = me; vd->mxe = mxe; vd->mye = mye; vd->mdp = mdp; vd->mmc = mmc;
382 vd->mm = clx_spr; vd->md = clx_bgr;
383
384 vd->ec = ec;
385 vd->b0c = b0c; vd->b1c = b1c; vd->b2c = b2c; vd->b3c = b3c;
386 vd->mm0 = mm0; vd->mm1 = mm1;
387 vd->m0c = sc[0];
388 vd->m1c = sc[1];
389 vd->m2c = sc[2];
390 vd->m3c = sc[3];
391 vd->m4c = sc[4];
392 vd->m5c = sc[5];
393 vd->m6c = sc[6];
394 vd->m7c = sc[7];
395
396 vd->pad0 = 0;
397 vd->irq_raster = irq_raster;
398 vd->vc = vc;
399 vd->vc_base = vc_base;
400 vd->rc = rc;
401 vd->spr_dma = spr_dma_on;
402 vd->spr_disp = spr_disp_on;
403 for (i=0; i<8; i++) {
404 vd->mc[i] = mc[i];
405 vd->mc_base[i] = mc_base[i];
406 }
407 vd->display_state = display_state;
408 vd->bad_line = raster_y >= FIRST_DMA_LINE && raster_y <= LAST_DMA_LINE && ((raster_y & 7) == y_scroll) && bad_lines_enabled;
409 vd->bad_line_enable = bad_lines_enabled;
410 vd->lp_triggered = lp_triggered;
411 vd->border_on = border_on;
412
413 vd->bank_base = cia_vabase;
414 vd->matrix_base = ((vbase & 0xf0) << 6) | cia_vabase;
415 vd->char_base = ((vbase & 0x0e) << 10) | cia_vabase;
416 vd->bitmap_base = ((vbase & 0x08) << 10) | cia_vabase;
417 for (i=0; i<8; i++)
418 vd->sprite_base[i] = spr_ptr[i] | cia_vabase;
419
420 vd->cycle = cycle;
421 vd->raster_x = raster_x;
422 vd->ml_index = ml_index;
423 vd->ref_cnt = ref_cnt;
424 vd->last_vic_byte = LastVICByte;
425 vd->ud_border_on = ud_border_on;
426 }
427
428
429 /*
430 * Set VIC state (only works if in VBlank)
431 */
432
433 void MOS6569::SetState(MOS6569State *vd)
434 {
435 int i, j;
436
437 mx[0] = vd->m0x; my[0] = vd->m0y;
438 mx[1] = vd->m1x; my[1] = vd->m1y;
439 mx[2] = vd->m2x; my[2] = vd->m2y;
440 mx[3] = vd->m3x; my[3] = vd->m3y;
441 mx[4] = vd->m4x; my[4] = vd->m4y;
442 mx[5] = vd->m5x; my[5] = vd->m5y;
443 mx[6] = vd->m6x; my[6] = vd->m6y;
444 mx[7] = vd->m7x; my[7] = vd->m7y;
445 mx8 = vd->mx8;
446 for (i=0, j=1; i<8; i++, j<<=1) {
447 if (mx8 & j)
448 mx[i] |= 0x100;
449 else
450 mx[i] &= 0xff;
451 }
452
453 ctrl1 = vd->ctrl1;
454 ctrl2 = vd->ctrl2;
455 x_scroll = ctrl2 & 7;
456 y_scroll = ctrl1 & 7;
457 if (ctrl1 & 8) {
458 dy_start = ROW25_YSTART;
459 dy_stop = ROW25_YSTOP;
460 } else {
461 dy_start = ROW24_YSTART;
462 dy_stop = ROW24_YSTOP;
463 }
464 display_idx = ((ctrl1 & 0x60) | (ctrl2 & 0x10)) >> 4;
465
466 raster_y = 0;
467 lpx = vd->lpx; lpy = vd->lpy;
468
469 vbase = vd->vbase;
470 cia_vabase = vd->bank_base;
471 matrix_base = (vbase & 0xf0) << 6;
472 char_base = (vbase & 0x0e) << 10;
473 bitmap_base = (vbase & 0x08) << 10;
474
475 irq_flag = vd->irq_flag;
476 irq_mask = vd->irq_mask;
477
478 me = vd->me; mxe = vd->mxe; mye = vd->mye; mdp = vd->mdp; mmc = vd->mmc;
479 clx_spr = vd->mm; clx_bgr = vd->md;
480
481 ec = vd->ec;
482 ec_color = colors[ec];
483
484 b0c = vd->b0c; b1c = vd->b1c; b2c = vd->b2c; b3c = vd->b3c;
485 b0c_color = colors[b0c];
486 b1c_color = colors[b1c];
487 b2c_color = colors[b2c];
488 b3c_color = colors[b3c];
489
490 mm0 = vd->mm0; mm1 = vd->mm1;
491 mm0_color = colors[mm0];
492 mm1_color = colors[mm1];
493
494 sc[0] = vd->m0c; sc[1] = vd->m1c;
495 sc[2] = vd->m2c; sc[3] = vd->m3c;
496 sc[4] = vd->m4c; sc[5] = vd->m5c;
497 sc[6] = vd->m6c; sc[7] = vd->m7c;
498 for (i=0; i<8; i++)
499 spr_color[i] = colors[sc[i]];
500
501 irq_raster = vd->irq_raster;
502 vc = vd->vc;
503 vc_base = vd->vc_base;
504 rc = vd->rc;
505 spr_dma_on = vd->spr_dma;
506 spr_disp_on = vd->spr_disp;
507 for (i=0; i<8; i++) {
508 mc[i] = vd->mc[i];
509 mc_base[i] = vd->mc_base[i];
510 spr_ptr[i] = vd->sprite_base[i] & 0x3fff;
511 }
512 display_state = vd->display_state;
513 bad_lines_enabled = vd->bad_line_enable;
514 lp_triggered = vd->lp_triggered;
515 border_on = vd->border_on;
516
517 cycle = vd->cycle;
518 raster_x = vd->raster_x;
519 ml_index = vd->ml_index;
520 ref_cnt = vd->ref_cnt;
521 LastVICByte = vd->last_vic_byte;
522 ud_border_on = vd->ud_border_on;
523 }
524
525
526 /*
527 * Trigger raster IRQ
528 */
529
530 #ifdef GLOBAL_VARS
531 static inline void raster_irq(void)
532 #else
533 inline void MOS6569::raster_irq(void)
534 #endif
535 {
536 irq_flag |= 0x01;
537 if (irq_mask & 0x01) {
538 irq_flag |= 0x80;
539 the_cpu->TriggerVICIRQ();
540 }
541 }
542
543
544 /*
545 * Read from VIC register
546 */
547
548 uint8 MOS6569::ReadRegister(uint16 adr)
549 {
550 switch (adr) {
551 case 0x00: case 0x02: case 0x04: case 0x06:
552 case 0x08: case 0x0a: case 0x0c: case 0x0e:
553 return mx[adr >> 1];
554
555 case 0x01: case 0x03: case 0x05: case 0x07:
556 case 0x09: case 0x0b: case 0x0d: case 0x0f:
557 return my[adr >> 1];
558
559 case 0x10: // Sprite X position MSB
560 return mx8;
561
562 case 0x11: // Control register 1
563 return (ctrl1 & 0x7f) | ((raster_y & 0x100) >> 1);
564
565 case 0x12: // Raster counter
566 return raster_y;
567
568 case 0x13: // Light pen X
569 return lpx;
570
571 case 0x14: // Light pen Y
572 return lpy;
573
574 case 0x15: // Sprite enable
575 return me;
576
577 case 0x16: // Control register 2
578 return ctrl2 | 0xc0;
579
580 case 0x17: // Sprite Y expansion
581 return mye;
582
583 case 0x18: // Memory pointers
584 return vbase | 0x01;
585
586 case 0x19: // IRQ flags
587 return irq_flag | 0x70;
588
589 case 0x1a: // IRQ mask
590 return irq_mask | 0xf0;
591
592 case 0x1b: // Sprite data priority
593 return mdp;
594
595 case 0x1c: // Sprite multicolor
596 return mmc;
597
598 case 0x1d: // Sprite X expansion
599 return mxe;
600
601 case 0x1e:{ // Sprite-sprite collision
602 uint8 ret = clx_spr;
603 clx_spr = 0; // Read and clear
604 return ret;
605 }
606
607 case 0x1f:{ // Sprite-background collision
608 uint8 ret = clx_bgr;
609 clx_bgr = 0; // Read and clear
610 return ret;
611 }
612
613 case 0x20: return ec | 0xf0;
614 case 0x21: return b0c | 0xf0;
615 case 0x22: return b1c | 0xf0;
616 case 0x23: return b2c | 0xf0;
617 case 0x24: return b3c | 0xf0;
618 case 0x25: return mm0 | 0xf0;
619 case 0x26: return mm1 | 0xf0;
620
621 case 0x27: case 0x28: case 0x29: case 0x2a:
622 case 0x2b: case 0x2c: case 0x2d: case 0x2e:
623 return sc[adr - 0x27] | 0xf0;
624
625 default:
626 return 0xff;
627 }
628 }
629
630
631 /*
632 * Write to VIC register
633 */
634
635 void MOS6569::WriteRegister(uint16 adr, uint8 byte)
636 {
637 switch (adr) {
638 case 0x00: case 0x02: case 0x04: case 0x06:
639 case 0x08: case 0x0a: case 0x0c: case 0x0e:
640 mx[adr >> 1] = (mx[adr >> 1] & 0xff00) | byte;
641 break;
642
643 case 0x10:{
644 int i, j;
645 mx8 = byte;
646 for (i=0, j=1; i<8; i++, j<<=1) {
647 if (mx8 & j)
648 mx[i] |= 0x100;
649 else
650 mx[i] &= 0xff;
651 }
652 break;
653 }
654
655 case 0x01: case 0x03: case 0x05: case 0x07:
656 case 0x09: case 0x0b: case 0x0d: case 0x0f:
657 my[adr >> 1] = byte;
658 break;
659
660 case 0x11:{ // Control register 1
661 ctrl1 = byte;
662 y_scroll = byte & 7;
663
664 uint16 new_irq_raster = (irq_raster & 0xff) | ((byte & 0x80) << 1);
665 if (irq_raster != new_irq_raster && raster_y == new_irq_raster)
666 raster_irq();
667 irq_raster = new_irq_raster;
668
669 if (byte & 8) {
670 dy_start = ROW25_YSTART;
671 dy_stop = ROW25_YSTOP;
672 } else {
673 dy_start = ROW24_YSTART;
674 dy_stop = ROW24_YSTOP;
675 }
676
677 // In line $30, the DEN bit controls if Bad Lines can occur
678 if (raster_y == 0x30 && byte & 0x10)
679 bad_lines_enabled = true;
680
681 // Bad Line condition?
682 is_bad_line = (raster_y >= FIRST_DMA_LINE && raster_y <= LAST_DMA_LINE && ((raster_y & 7) == y_scroll) && bad_lines_enabled);
683
684 display_idx = ((ctrl1 & 0x60) | (ctrl2 & 0x10)) >> 4;
685 break;
686 }
687
688 case 0x12:{ // Raster counter
689 uint16 new_irq_raster = (irq_raster & 0xff00) | byte;
690 if (irq_raster != new_irq_raster && raster_y == new_irq_raster)
691 raster_irq();
692 irq_raster = new_irq_raster;
693 break;
694 }
695
696 case 0x15: // Sprite enable
697 me = byte;
698 break;
699
700 case 0x16: // Control register 2
701 ctrl2 = byte;
702 x_scroll = byte & 7;
703 display_idx = ((ctrl1 & 0x60) | (ctrl2 & 0x10)) >> 4;
704 break;
705
706 case 0x17: // Sprite Y expansion
707 mye = byte;
708 spr_exp_y |= ~byte;
709 break;
710
711 case 0x18: // Memory pointers
712 vbase = byte;
713 matrix_base = (byte & 0xf0) << 6;
714 char_base = (byte & 0x0e) << 10;
715 bitmap_base = (byte & 0x08) << 10;
716 break;
717
718 case 0x19: // IRQ flags
719 irq_flag = irq_flag & (~byte & 0x0f);
720 if (irq_flag & irq_mask) // Set master bit if allowed interrupt still pending
721 irq_flag |= 0x80;
722 else
723 the_cpu->ClearVICIRQ(); // Else clear interrupt
724 break;
725
726 case 0x1a: // IRQ mask
727 irq_mask = byte & 0x0f;
728 if (irq_flag & irq_mask) { // Trigger interrupt if pending and now allowed
729 irq_flag |= 0x80;
730 the_cpu->TriggerVICIRQ();
731 } else {
732 irq_flag &= 0x7f;
733 the_cpu->ClearVICIRQ();
734 }
735 break;
736
737 case 0x1b: // Sprite data priority
738 mdp = byte;
739 break;
740
741 case 0x1c: // Sprite multicolor
742 mmc = byte;
743 break;
744
745 case 0x1d: // Sprite X expansion
746 mxe = byte;
747 break;
748
749 case 0x20: ec_color = colors[ec = byte]; break;
750 case 0x21: b0c_color = colors[b0c = byte]; break;
751 case 0x22: b1c_color = colors[b1c = byte]; break;
752 case 0x23: b2c_color = colors[b2c = byte]; break;
753 case 0x24: b3c_color = colors[b3c = byte]; break;
754 case 0x25: mm0_color = colors[mm0 = byte]; break;
755 case 0x26: mm1_color = colors[mm1 = byte]; break;
756
757 case 0x27: case 0x28: case 0x29: case 0x2a:
758 case 0x2b: case 0x2c: case 0x2d: case 0x2e:
759 spr_color[adr - 0x27] = colors[sc[adr - 0x27] = byte];
760 break;
761 }
762 }
763
764
765 /*
766 * CIA VA14/15 has changed
767 */
768
769 void MOS6569::ChangedVA(uint16 new_va)
770 {
771 cia_vabase = new_va << 14;
772 WriteRegister(0x18, vbase); // Force update of memory pointers
773 }
774
775
776 /*
777 * Trigger lightpen interrupt, latch lightpen coordinates
778 */
779
780 void MOS6569::TriggerLightpen(void)
781 {
782 if (!lp_triggered) { // Lightpen triggers only once per frame
783 lp_triggered = true;
784
785 lpx = raster_x >> 1; // Latch current coordinates
786 lpy = raster_y;
787
788 irq_flag |= 0x08; // Trigger IRQ
789 if (irq_mask & 0x08) {
790 irq_flag |= 0x80;
791 the_cpu->TriggerVICIRQ();
792 }
793 }
794 }
795
796
797 /*
798 * Read a byte from the VIC's address space
799 */
800
801 #ifdef GLOBAL_VARS
802 static inline uint8 read_byte(uint16 adr)
803 #else
804 inline uint8 MOS6569::read_byte(uint16 adr)
805 #endif
806 {
807 uint16 va = adr | cia_vabase;
808 if ((va & 0x7000) == 0x1000)
809 #ifdef GLOBAL_VARS
810 return the_vic->LastVICByte = char_rom[va & 0x0fff];
811 #else
812 return LastVICByte = char_rom[va & 0x0fff];
813 #endif
814 else
815 #ifdef GLOBAL_VARS
816 return the_vic->LastVICByte = ram[va];
817 #else
818 return LastVICByte = ram[va];
819 #endif
820 }
821
822
823 /*
824 * Quick memset of 8 bytes
825 */
826
827 inline void memset8(uint8 *p, uint8 c)
828 {
829 p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = c;
830 }
831
832
833 /*
834 * Video matrix access
835 */
836
837 #ifdef __i386
838 inline
839 #endif
840 #ifdef GLOBAL_VARS
841 static void matrix_access(void)
842 #else
843 void MOS6569::matrix_access(void)
844 #endif
845 {
846 if (the_cpu->BALow) {
847 if (the_c64->CycleCounter-first_ba_cycle < 3)
848 matrix_line[ml_index] = color_line[ml_index] = 0xff;
849 else {
850 uint16 adr = (vc & 0x03ff) | matrix_base;
851 matrix_line[ml_index] = read_byte(adr);
852 color_line[ml_index] = color_ram[adr & 0x03ff];
853 }
854 }
855 }
856
857
858 /*
859 * Graphics data access
860 */
861
862 #ifdef __i386
863 inline
864 #endif
865 #ifdef GLOBAL_VARS
866 static void graphics_access(void)
867 #else
868 void MOS6569::graphics_access(void)
869 #endif
870 {
871 if (display_state) {
872
873 uint16 adr;
874 if (ctrl1 & 0x20) // Bitmap
875 adr = ((vc & 0x03ff) << 3) | bitmap_base | rc;
876 else // Text
877 adr = (matrix_line[ml_index] << 3) | char_base | rc;
878 if (ctrl1 & 0x40) // ECM
879 adr &= 0xf9ff;
880 gfx_data = read_byte(adr);
881 char_data = matrix_line[ml_index];
882 color_data = color_line[ml_index];
883 ml_index++;
884 vc++;
885
886 } else {
887
888 // Display is off
889 gfx_data = read_byte(ctrl1 & 0x40 ? 0x39ff : 0x3fff);
890 char_data = color_data = 0;
891 }
892 }
893
894
895 /*
896 * Background display (8 pixels)
897 */
898
899 #ifdef GLOBAL_VARS
900 static void draw_background(void)
901 #else
902 void MOS6569::draw_background(void)
903 #endif
904 {
905 uint8 *p = chunky_ptr;
906 uint8 c;
907
908 if (!draw_this_line)
909 return;
910
911 switch (display_idx) {
912 case 0: // Standard text
913 case 1: // Multicolor text
914 case 3: // Multicolor bitmap
915 c = b0c_color;
916 break;
917 case 2: // Standard bitmap
918 c = colors[last_char_data];
919 break;
920 case 4: // ECM text
921 if (last_char_data & 0x80)
922 if (last_char_data & 0x40)
923 c = b3c_color;
924 else
925 c = b2c_color;
926 else
927 if (last_char_data & 0x40)
928 c = b1c_color;
929 else
930 c = b0c_color;
931 break;
932 default:
933 c = colors[0];
934 break;
935 }
936 memset8(p, c);
937 }
938
939
940 /*
941 * Graphics display (8 pixels)
942 */
943
944 #ifdef __i386
945 inline
946 #endif
947 #ifdef GLOBAL_VARS
948 static void draw_graphics(void)
949 #else
950 void MOS6569::draw_graphics(void)
951 #endif
952 {
953 uint8 *p = chunky_ptr + x_scroll;
954 uint8 c[4], data;
955
956 if (!draw_this_line)
957 return;
958 if (ud_border_on) {
959 draw_background();
960 return;
961 }
962
963 switch (display_idx) {
964
965 case 0: // Standard text
966 c[0] = b0c_color;
967 c[1] = colors[color_data];
968 goto draw_std;
969
970 case 1: // Multicolor text
971 if (color_data & 8) {
972 c[0] = b0c_color;
973 c[1] = b1c_color;
974 c[2] = b2c_color;
975 c[3] = colors[color_data & 7];
976 goto draw_multi;
977 } else {
978 c[0] = b0c_color;
979 c[1] = colors[color_data];
980 goto draw_std;
981 }
982
983 case 2: // Standard bitmap
984 c[0] = colors[char_data];
985 c[1] = colors[char_data >> 4];
986 goto draw_std;
987
988 case 3: // Multicolor bitmap
989 c[0]= b0c_color;
990 c[1] = colors[char_data >> 4];
991 c[2] = colors[char_data];
992 c[3] = colors[color_data];
993 goto draw_multi;
994
995 case 4: // ECM text
996 if (char_data & 0x80)
997 if (char_data & 0x40)
998 c[0] = b3c_color;
999 else
1000 c[0] = b2c_color;
1001 else
1002 if (char_data & 0x40)
1003 c[0] = b1c_color;
1004 else
1005 c[0] = b0c_color;
1006 c[1] = colors[color_data];
1007 goto draw_std;
1008
1009 case 5: // Invalid multicolor text
1010 memset8(p, colors[0]);
1011 if (color_data & 8) {
1012 fore_mask_ptr[0] |= ((gfx_data & 0xaa) | (gfx_data & 0xaa) >> 1) >> x_scroll;
1013 fore_mask_ptr[1] |= ((gfx_data & 0xaa) | (gfx_data & 0xaa) >> 1) << (8-x_scroll);
1014 } else {
1015 fore_mask_ptr[0] |= gfx_data >> x_scroll;
1016 fore_mask_ptr[1] |= gfx_data << (7-x_scroll);
1017 }
1018 return;
1019
1020 case 6: // Invalid standard bitmap
1021 memset8(p, colors[0]);
1022 fore_mask_ptr[0] |= gfx_data >> x_scroll;
1023 fore_mask_ptr[1] |= gfx_data << (7-x_scroll);
1024 return;
1025
1026 case 7: // Invalid multicolor bitmap
1027 memset8(p, colors[0]);
1028 fore_mask_ptr[0] |= ((gfx_data & 0xaa) | (gfx_data & 0xaa) >> 1) >> x_scroll;
1029 fore_mask_ptr[1] |= ((gfx_data & 0xaa) | (gfx_data & 0xaa) >> 1) << (8-x_scroll);
1030 return;
1031
1032 default: // Can't happen
1033 return;
1034 }
1035
1036 draw_std:
1037
1038 fore_mask_ptr[0] |= gfx_data >> x_scroll;
1039 fore_mask_ptr[1] |= gfx_data << (7-x_scroll);
1040
1041 data = gfx_data;
1042 p[7] = c[data & 1]; data >>= 1;
1043 p[6] = c[data & 1]; data >>= 1;
1044 p[5] = c[data & 1]; data >>= 1;
1045 p[4] = c[data & 1]; data >>= 1;
1046 p[3] = c[data & 1]; data >>= 1;
1047 p[2] = c[data & 1]; data >>= 1;
1048 p[1] = c[data & 1]; data >>= 1;
1049 p[0] = c[data];
1050 return;
1051
1052 draw_multi:
1053
1054 fore_mask_ptr[0] |= ((gfx_data & 0xaa) | (gfx_data & 0xaa) >> 1) >> x_scroll;
1055 fore_mask_ptr[1] |= ((gfx_data & 0xaa) | (gfx_data & 0xaa) >> 1) << (8-x_scroll);
1056
1057 data = gfx_data;
1058 p[7] = p[6] = c[data & 3]; data >>= 2;
1059 p[5] = p[4] = c[data & 3]; data >>= 2;
1060 p[3] = p[2] = c[data & 3]; data >>= 2;
1061 p[1] = p[0] = c[data];
1062 return;
1063 }
1064
1065
1066 /*
1067 * Sprite display
1068 */
1069
1070 #ifdef GLOBAL_VARS
1071 inline static void draw_sprites(void)
1072 #else
1073 inline void MOS6569::draw_sprites(void)
1074 #endif
1075 {
1076 int i;
1077 int snum, sbit; // Sprite number/bit mask
1078 int spr_coll=0, gfx_coll=0;
1079
1080 // Clear sprite collision buffer
1081 {
1082 uint32 *lp = (uint32 *)spr_coll_buf - 1;
1083 for (i=0; i<DISPLAY_X/4; i++)
1084 *++lp = 0;
1085 }
1086
1087 // Loop for all sprites
1088 for (snum=0, sbit=1; snum<8; snum++, sbit<<=1) {
1089
1090 // Is sprite visible?
1091 if ((spr_draw & sbit) && mx[snum] <= DISPLAY_X-32) {
1092 #ifdef __POWERPC__
1093 uint8 *p = (uint8 *)chunky_tmp + mx[snum] + 8;
1094 #else
1095 uint8 *p = chunky_line_start + mx[snum] + 8;
1096 #endif
1097 uint8 *q = spr_coll_buf + mx[snum] + 8;
1098 uint8 color = spr_color[snum];
1099
1100 // Fetch sprite data and mask
1101 uint32 sdata = (spr_draw_data[snum][0] << 24) | (spr_draw_data[snum][1] << 16) | (spr_draw_data[snum][2] << 8);
1102
1103 int spr_mask_pos = mx[snum] + 8; // Sprite bit position in fore_mask_buf
1104
1105 uint8 *fmbp = fore_mask_buf + (spr_mask_pos / 8);
1106 int sshift = spr_mask_pos & 7;
1107 uint32 fore_mask = (((*(fmbp+0) << 24) | (*(fmbp+1) << 16) | (*(fmbp+2) << 8)
1108 | (*(fmbp+3))) << sshift) | (*(fmbp+4) >> (8-sshift));
1109
1110 if (mxe & sbit) { // X-expanded
1111 if (mx[snum] > DISPLAY_X-56)
1112 continue;
1113
1114 uint32 sdata_l = 0, sdata_r = 0, fore_mask_r;
1115 fore_mask_r = (((*(fmbp+4) << 24) | (*(fmbp+5) << 16) | (*(fmbp+6) << 8)
1116 | (*(fmbp+7))) << sshift) | (*(fmbp+8) >> (8-sshift));
1117
1118 if (mmc & sbit) { // Multicolor mode
1119 uint32 plane0_l, plane0_r, plane1_l, plane1_r;
1120
1121 // Expand sprite data
1122 sdata_l = MultiExpTable[sdata >> 24 & 0xff] << 16 | MultiExpTable[sdata >> 16 & 0xff];
1123 sdata_r = MultiExpTable[sdata >> 8 & 0xff] << 16;
1124
1125 // Convert sprite chunky pixels to bitplanes
1126 plane0_l = (sdata_l & 0x55555555) | (sdata_l & 0x55555555) << 1;
1127 plane1_l = (sdata_l & 0xaaaaaaaa) | (sdata_l & 0xaaaaaaaa) >> 1;
1128 plane0_r = (sdata_r & 0x55555555) | (sdata_r & 0x55555555) << 1;
1129 plane1_r = (sdata_r & 0xaaaaaaaa) | (sdata_r & 0xaaaaaaaa) >> 1;
1130
1131 // Collision with graphics?
1132 if ((fore_mask & (plane0_l | plane1_l)) || (fore_mask_r & (plane0_r | plane1_r))) {
1133 gfx_coll |= sbit;
1134 if (mdp & sbit) {
1135 plane0_l &= ~fore_mask; // Mask sprite if in background
1136 plane1_l &= ~fore_mask;
1137 plane0_r &= ~fore_mask_r;
1138 plane1_r &= ~fore_mask_r;
1139 }
1140 }
1141
1142 // Paint sprite
1143 for (i=0; i<32; i++, plane0_l<<=1, plane1_l<<=1) {
1144 uint8 col;
1145 if (plane1_l & 0x80000000) {
1146 if (plane0_l & 0x80000000)
1147 col = mm1_color;
1148 else
1149 col = color;
1150 } else {
1151 if (plane0_l & 0x80000000)
1152 col = mm0_color;
1153 else
1154 continue;
1155 }
1156 if (q[i])
1157 spr_coll |= q[i] | sbit;
1158 else {
1159 p[i] = col;
1160 q[i] = sbit;
1161 }
1162 }
1163 for (; i<48; i++, plane0_r<<=1, plane1_r<<=1) {
1164 uint8 col;
1165 if (plane1_r & 0x80000000) {
1166 if (plane0_r & 0x80000000)
1167 col = mm1_color;
1168 else
1169 col = color;
1170 } else {
1171 if (plane0_r & 0x80000000)
1172 col = mm0_color;
1173 else
1174 continue;
1175 }
1176 if (q[i])
1177 spr_coll |= q[i] | sbit;
1178 else {
1179 p[i] = col;
1180 q[i] = sbit;
1181 }
1182 }
1183
1184 } else { // Standard mode
1185
1186 // Expand sprite data
1187 sdata_l = ExpTable[sdata >> 24 & 0xff] << 16 | ExpTable[sdata >> 16 & 0xff];
1188 sdata_r = ExpTable[sdata >> 8 & 0xff] << 16;
1189
1190 // Collision with graphics?
1191 if ((fore_mask & sdata_l) || (fore_mask_r & sdata_r)) {
1192 gfx_coll |= sbit;
1193 if (mdp & sbit) {
1194 sdata_l &= ~fore_mask; // Mask sprite if in background
1195 sdata_r &= ~fore_mask_r;
1196 }
1197 }
1198
1199 // Paint sprite
1200 for (i=0; i<32; i++, sdata_l<<=1)
1201 if (sdata_l & 0x80000000) {
1202 if (q[i]) // Collision with sprite?
1203 spr_coll |= q[i] | sbit;
1204 else { // Draw pixel if no collision
1205 p[i] = color;
1206 q[i] = sbit;
1207 }
1208 }
1209 for (; i<48; i++, sdata_r<<=1)
1210 if (sdata_r & 0x80000000) {
1211 if (q[i]) // Collision with sprite?
1212 spr_coll |= q[i] | sbit;
1213 else { // Draw pixel if no collision
1214 p[i] = color;
1215 q[i] = sbit;
1216 }
1217 }
1218 }
1219
1220 } else { // Unexpanded
1221
1222 if (mmc & sbit) { // Multicolor mode
1223 uint32 plane0, plane1;
1224
1225 // Convert sprite chunky pixels to bitplanes
1226 plane0 = (sdata & 0x55555555) | (sdata & 0x55555555) << 1;
1227 plane1 = (sdata & 0xaaaaaaaa) | (sdata & 0xaaaaaaaa) >> 1;
1228
1229 // Collision with graphics?
1230 if (fore_mask & (plane0 | plane1)) {
1231 gfx_coll |= sbit;
1232 if (mdp & sbit) {
1233 plane0 &= ~fore_mask; // Mask sprite if in background
1234 plane1 &= ~fore_mask;
1235 }
1236 }
1237
1238 // Paint sprite
1239 for (i=0; i<24; i++, plane0<<=1, plane1<<=1) {
1240 uint8 col;
1241 if (plane1 & 0x80000000) {
1242 if (plane0 & 0x80000000)
1243 col = mm1_color;
1244 else
1245 col = color;
1246 } else {
1247 if (plane0 & 0x80000000)
1248 col = mm0_color;
1249 else
1250 continue;
1251 }
1252 if (q[i])
1253 spr_coll |= q[i] | sbit;
1254 else {
1255 p[i] = col;
1256 q[i] = sbit;
1257 }
1258 }
1259
1260 } else { // Standard mode
1261
1262 // Collision with graphics?
1263 if (fore_mask & sdata) {
1264 gfx_coll |= sbit;
1265 if (mdp & sbit)
1266 sdata &= ~fore_mask; // Mask sprite if in background
1267 }
1268
1269 // Paint sprite
1270 for (i=0; i<24; i++, sdata<<=1)
1271 if (sdata & 0x80000000) {
1272 if (q[i]) { // Collision with sprite?
1273 spr_coll |= q[i] | sbit;
1274 } else { // Draw pixel if no collision
1275 p[i] = color;
1276 q[i] = sbit;
1277 }
1278 }
1279 }
1280 }
1281 }
1282 }
1283
1284 if (ThePrefs.SpriteCollisions) {
1285
1286 // Check sprite-sprite collisions
1287 if (clx_spr)
1288 clx_spr |= spr_coll;
1289 else {
1290 clx_spr |= spr_coll;
1291 irq_flag |= 0x04;
1292 if (irq_mask & 0x04) {
1293 irq_flag |= 0x80;
1294 the_cpu->TriggerVICIRQ();
1295 }
1296 }
1297
1298 // Check sprite-background collisions
1299 if (clx_bgr)
1300 clx_bgr |= gfx_coll;
1301 else {
1302 clx_bgr |= gfx_coll;
1303 irq_flag |= 0x02;
1304 if (irq_mask & 0x02) {
1305 irq_flag |= 0x80;
1306 the_cpu->TriggerVICIRQ();
1307 }
1308 }
1309 }
1310 }
1311
1312
1313 #ifdef __POWERPC__
1314 static asm void fastcopy(register uchar *dst, register uchar *src);
1315 static asm void fastcopy(register uchar *dst, register uchar *src)
1316 {
1317 lfd fp0,0(src)
1318 lfd fp1,8(src)
1319 lfd fp2,16(src)
1320 lfd fp3,24(src)
1321 lfd fp4,32(src)
1322 lfd fp5,40(src)
1323 lfd fp6,48(src)
1324 lfd fp7,56(src)
1325 addi src,src,64
1326 stfd fp0,0(dst)
1327 stfd fp1,8(dst)
1328 stfd fp2,16(dst)
1329 stfd fp3,24(dst)
1330 stfd fp4,32(dst)
1331 stfd fp5,40(dst)
1332 stfd fp6,48(dst)
1333 stfd fp7,56(dst)
1334 addi dst,dst,64
1335
1336 lfd fp0,0(src)
1337 lfd fp1,8(src)
1338 lfd fp2,16(src)
1339 lfd fp3,24(src)
1340 lfd fp4,32(src)
1341 lfd fp5,40(src)
1342 lfd fp6,48(src)
1343 lfd fp7,56(src)
1344 addi src,src,64
1345 stfd fp0,0(dst)
1346 stfd fp1,8(dst)
1347 stfd fp2,16(dst)
1348 stfd fp3,24(dst)
1349 stfd fp4,32(dst)
1350 stfd fp5,40(dst)
1351 stfd fp6,48(dst)
1352 stfd fp7,56(dst)
1353 addi dst,dst,64
1354
1355 lfd fp0,0(src)
1356 lfd fp1,8(src)
1357 lfd fp2,16(src)
1358 lfd fp3,24(src)
1359 lfd fp4,32(src)
1360 lfd fp5,40(src)
1361 lfd fp6,48(src)
1362 lfd fp7,56(src)
1363 addi src,src,64
1364 stfd fp0,0(dst)
1365 stfd fp1,8(dst)
1366 stfd fp2,16(dst)
1367 stfd fp3,24(dst)
1368 stfd fp4,32(dst)
1369 stfd fp5,40(dst)
1370 stfd fp6,48(dst)
1371 stfd fp7,56(dst)
1372 addi dst,dst,64
1373
1374 lfd fp0,0(src)
1375 lfd fp1,8(src)
1376 lfd fp2,16(src)
1377 lfd fp3,24(src)
1378 lfd fp4,32(src)
1379 lfd fp5,40(src)
1380 lfd fp6,48(src)
1381 lfd fp7,56(src)
1382 addi src,src,64
1383 stfd fp0,0(dst)
1384 stfd fp1,8(dst)
1385 stfd fp2,16(dst)
1386 stfd fp3,24(dst)
1387 stfd fp4,32(dst)
1388 stfd fp5,40(dst)
1389 stfd fp6,48(dst)
1390 stfd fp7,56(dst)
1391 addi dst,dst,64
1392
1393 lfd fp0,0(src)
1394 lfd fp1,8(src)
1395 lfd fp2,16(src)
1396 lfd fp3,24(src)
1397 lfd fp4,32(src)
1398 lfd fp5,40(src)
1399 lfd fp6,48(src)
1400 lfd fp7,56(src)
1401 addi src,src,64
1402 stfd fp0,0(dst)
1403 stfd fp1,8(dst)
1404 stfd fp2,16(dst)
1405 stfd fp3,24(dst)
1406 stfd fp4,32(dst)
1407 stfd fp5,40(dst)
1408 stfd fp6,48(dst)
1409 stfd fp7,56(dst)
1410 addi dst,dst,64
1411
1412 lfd fp0,0(src)
1413 lfd fp1,8(src)
1414 lfd fp2,16(src)
1415 lfd fp3,24(src)
1416 lfd fp4,32(src)
1417 lfd fp5,40(src)
1418 lfd fp6,48(src)
1419 lfd fp7,56(src)
1420 addi src,src,64
1421 stfd fp0,0(dst)
1422 stfd fp1,8(dst)
1423 stfd fp2,16(dst)
1424 stfd fp3,24(dst)
1425 stfd fp4,32(dst)
1426 stfd fp5,40(dst)
1427 stfd fp6,48(dst)
1428 stfd fp7,56(dst)
1429 addi dst,dst,64
1430 blr
1431 }
1432 #endif
1433
1434
1435 /*
1436 * Emulate one clock cycle, returns true if new raster line has started
1437 */
1438
1439 // Set BA low
1440 #define SetBALow \
1441 if (!the_cpu->BALow) { \
1442 first_ba_cycle = the_c64->CycleCounter; \
1443 the_cpu->BALow = true; \
1444 }
1445
1446 // Turn on display if Bad Line
1447 #define DisplayIfBadLine \
1448 if (is_bad_line) \
1449 display_state = true;
1450
1451 // Turn on display and matrix access if Bad Line
1452 #define FetchIfBadLine \
1453 if (is_bad_line) { \
1454 display_state = true; \
1455 SetBALow; \
1456 }
1457
1458 // Turn on display and matrix access and reset RC if Bad Line
1459 #define RCIfBadLine \
1460 if (is_bad_line) { \
1461 display_state = true; \
1462 rc = 0; \
1463 SetBALow; \
1464 }
1465
1466 // Idle access
1467 #define IdleAccess \
1468 read_byte(0x3fff)
1469
1470 // Refresh access
1471 #define RefreshAccess \
1472 read_byte(0x3f00 | ref_cnt--)
1473
1474 // Turn on sprite DMA if necessary
1475 #define CheckSpriteDMA \
1476 mask = 1; \
1477 for (i=0; i<8; i++, mask<<=1) \
1478 if ((me & mask) && (raster_y & 0xff) == my[i]) { \
1479 spr_dma_on |= mask; \
1480 mc_base[i] = 0; \
1481 if (mye & mask) \
1482 spr_exp_y &= ~mask; \
1483 }
1484
1485 // Fetch sprite data pointer
1486 #define SprPtrAccess(num) \
1487 spr_ptr[num] = read_byte(matrix_base | 0x03f8 | num) << 6;
1488
1489 // Fetch sprite data, increment data counter
1490 #define SprDataAccess(num, bytenum) \
1491 if (spr_dma_on & (1 << num)) { \
1492 spr_data[num][bytenum] = read_byte(mc[num] & 0x3f | spr_ptr[num]); \
1493 mc[num]++; \
1494 } else if (bytenum == 1) \
1495 IdleAccess;
1496
1497 // Sample border color and increment chunky_ptr and fore_mask_ptr
1498 #define SampleBorder \
1499 if (draw_this_line) { \
1500 if (border_on) \
1501 border_color_sample[cycle-13] = ec_color; \
1502 chunky_ptr += 8; \
1503 fore_mask_ptr++; \
1504 }
1505
1506
1507 bool MOS6569::EmulateCycle(void)
1508 {
1509 uint8 mask;
1510 int i;
1511
1512 switch (cycle) {
1513
1514 // Fetch sprite pointer 3, increment raster counter, trigger raster IRQ,
1515 // test for Bad Line, reset BA if sprites 3 and 4 off, read data of sprite 3
1516 case 1:
1517 if (raster_y == TOTAL_RASTERS-1)
1518
1519 // Trigger VBlank in cycle 2
1520 vblanking = true;
1521
1522 else {
1523
1524 // Increment raster counter
1525 raster_y++;
1526
1527 // Trigger raster IRQ if IRQ line reached
1528 if (raster_y == irq_raster)
1529 raster_irq();
1530
1531 // In line $30, the DEN bit controls if Bad Lines can occur
1532 if (raster_y == 0x30)
1533 bad_lines_enabled = ctrl1 & 0x10;
1534
1535 // Bad Line condition?
1536 is_bad_line = (raster_y >= FIRST_DMA_LINE && raster_y <= LAST_DMA_LINE && ((raster_y & 7) == y_scroll) && bad_lines_enabled);
1537
1538 // Don't draw all lines, hide some at the top and bottom
1539 draw_this_line = (raster_y >= FIRST_DISP_LINE && raster_y <= LAST_DISP_LINE && !frame_skipped);
1540 }
1541
1542 // First sample of border state
1543 border_on_sample[0] = border_on;
1544
1545 SprPtrAccess(3);
1546 SprDataAccess(3, 0);
1547 DisplayIfBadLine;
1548 if (!(spr_dma_on & 0x18))
1549 the_cpu->BALow = false;
1550 break;
1551
1552 // Set BA for sprite 5, read data of sprite 3
1553 case 2:
1554 if (vblanking) {
1555
1556 // Vertical blank, reset counters
1557 raster_y = vc_base = 0;
1558 ref_cnt = 0xff;
1559 lp_triggered = vblanking = false;
1560
1561 if (!(frame_skipped = --skip_counter))
1562 skip_counter = ThePrefs.SkipFrames;
1563
1564 the_c64->VBlank(!frame_skipped);
1565
1566 // Get bitmap pointer for next frame. This must be done
1567 // after calling the_c64->VBlank() because the preferences
1568 // and screen configuration may have been changed there
1569 chunky_line_start = the_display->BitmapBase();
1570 xmod = the_display->BitmapXMod();
1571
1572 // Trigger raster IRQ if IRQ in line 0
1573 if (irq_raster == 0)
1574 raster_irq();
1575
1576 }
1577
1578 // Our output goes here
1579 #ifdef __POWERPC__
1580 chunky_ptr = (uint8 *)chunky_tmp;
1581 #else
1582 chunky_ptr = chunky_line_start;
1583 #endif
1584
1585 // Clear foreground mask
1586 memset(fore_mask_buf, 0, DISPLAY_X/8);
1587 fore_mask_ptr = fore_mask_buf;
1588
1589 SprDataAccess(3,1);
1590 SprDataAccess(3,2);
1591 DisplayIfBadLine;
1592 if (spr_dma_on & 0x20)
1593 SetBALow;
1594 break;
1595
1596 // Fetch sprite pointer 4, reset BA is sprite 4 and 5 off
1597 case 3:
1598 SprPtrAccess(4);
1599 SprDataAccess(4, 0);
1600 DisplayIfBadLine;
1601 if (!(spr_dma_on & 0x30))
1602 the_cpu->BALow = false;
1603 break;
1604
1605 // Set BA for sprite 6, read data of sprite 4
1606 case 4:
1607 SprDataAccess(4, 1);
1608 SprDataAccess(4, 2);
1609 DisplayIfBadLine;
1610 if (spr_dma_on & 0x40)
1611 SetBALow;
1612 break;
1613
1614 // Fetch sprite pointer 5, reset BA if sprite 5 and 6 off
1615 case 5:
1616 SprPtrAccess(5);
1617 SprDataAccess(5, 0);
1618 DisplayIfBadLine;
1619 if (!(spr_dma_on & 0x60))
1620 the_cpu->BALow = false;
1621 break;
1622
1623 // Set BA for sprite 7, read data of sprite 5
1624 case 6:
1625 SprDataAccess(5, 1);
1626 SprDataAccess(5, 2);
1627 DisplayIfBadLine;
1628 if (spr_dma_on & 0x80)
1629 SetBALow;
1630 break;
1631
1632 // Fetch sprite pointer 6, reset BA if sprite 6 and 7 off
1633 case 7:
1634 SprPtrAccess(6);
1635 SprDataAccess(6, 0);
1636 DisplayIfBadLine;
1637 if (!(spr_dma_on & 0xc0))
1638 the_cpu->BALow = false;
1639 break;
1640
1641 // Read data of sprite 6
1642 case 8:
1643 SprDataAccess(6, 1);
1644 SprDataAccess(6, 2);
1645 DisplayIfBadLine;
1646 break;
1647
1648 // Fetch sprite pointer 7, reset BA if sprite 7 off
1649 case 9:
1650 SprPtrAccess(7);
1651 SprDataAccess(7, 0);
1652 DisplayIfBadLine;
1653 if (!(spr_dma_on & 0x80))
1654 the_cpu->BALow = false;
1655 break;
1656
1657 // Read data of sprite 7
1658 case 10:
1659 SprDataAccess(7, 1);
1660 SprDataAccess(7, 2);
1661 DisplayIfBadLine;
1662 break;
1663
1664 // Refresh, reset BA
1665 case 11:
1666 RefreshAccess;
1667 DisplayIfBadLine;
1668 the_cpu->BALow = false;
1669 break;
1670
1671 // Refresh, turn on matrix access if Bad Line
1672 case 12:
1673 RefreshAccess;
1674 FetchIfBadLine;
1675 break;
1676
1677 // Refresh, turn on matrix access if Bad Line, reset raster_x, graphics display starts here
1678 case 13:
1679 draw_background();
1680 SampleBorder;
1681 RefreshAccess;
1682 FetchIfBadLine;
1683 raster_x = 0xfffc;
1684 break;
1685
1686 // Refresh, VCBASE->VCCOUNT, turn on matrix access and reset RC if Bad Line
1687 case 14:
1688 draw_background();
1689 SampleBorder;
1690 RefreshAccess;
1691 RCIfBadLine;
1692 vc = vc_base;
1693 break;
1694
1695 // Refresh and matrix access, increment mc_base by 2 if y expansion flipflop is set
1696 case 15:
1697 draw_background();
1698 SampleBorder;
1699 RefreshAccess;
1700 FetchIfBadLine;
1701
1702 for (i=0; i<8; i++)
1703 if (spr_exp_y & (1 << i))
1704 mc_base[i] += 2;
1705
1706 ml_index = 0;
1707 matrix_access();
1708 break;
1709
1710 // Graphics and matrix access, increment mc_base by 1 if y expansion flipflop is set
1711 // and check if sprite DMA can be turned off
1712 case 16:
1713 draw_background();
1714 SampleBorder;
1715 graphics_access();
1716 FetchIfBadLine;
1717
1718 mask = 1;
1719 for (i=0; i<8; i++, mask<<=1) {
1720 if (spr_exp_y & mask)
1721 mc_base[i]++;
1722 if ((mc_base[i] & 0x3f) == 0x3f)
1723 spr_dma_on &= ~mask;
1724 }
1725
1726 matrix_access();
1727 break;
1728
1729 // Graphics and matrix access, turn off border in 40 column mode, display window starts here
1730 case 17:
1731 if (ctrl2 & 8) {
1732 if (raster_y == dy_stop)
1733 ud_border_on = true;
1734 else {
1735 if (ctrl1 & 0x10) {
1736 if (raster_y == dy_start)
1737 border_on = ud_border_on = false;
1738 else
1739 if (!ud_border_on)
1740 border_on = false;
1741 } else
1742 if (!ud_border_on)
1743 border_on = false;
1744 }
1745 }
1746
1747 // Second sample of border state
1748 border_on_sample[1] = border_on;
1749
1750 draw_background();
1751 draw_graphics();
1752 SampleBorder;
1753 graphics_access();
1754 FetchIfBadLine;
1755 matrix_access();
1756 break;
1757
1758 // Turn off border in 38 column mode
1759 case 18:
1760 if (!(ctrl2 & 8)) {
1761 if (raster_y == dy_stop)
1762 ud_border_on = true;
1763 else {
1764 if (ctrl1 & 0x10) {
1765 if (raster_y == dy_start)
1766 border_on = ud_border_on = false;
1767 else
1768 if (!ud_border_on)
1769 border_on = false;
1770 } else
1771 if (!ud_border_on)
1772 border_on = false;
1773 }
1774 }
1775
1776 // Third sample of border state
1777 border_on_sample[2] = border_on;
1778
1779 // Falls through
1780
1781 // Graphics and matrix access
1782 case 19: case 20: case 21: case 22: case 23: case 24:
1783 case 25: case 26: case 27: case 28: case 29: case 30:
1784 case 31: case 32: case 33: case 34: case 35: case 36:
1785 case 37: case 38: case 39: case 40: case 41: case 42:
1786 case 43: case 44: case 45: case 46: case 47: case 48:
1787 case 49: case 50: case 51: case 52: case 53: case 54: // Gnagna...
1788 draw_graphics();
1789 SampleBorder;
1790 graphics_access();
1791 FetchIfBadLine;
1792 matrix_access();
1793 last_char_data = char_data;
1794 break;
1795
1796 // Last graphics access, turn off matrix access, turn on sprite DMA if Y coordinate is
1797 // right and sprite is enabled, handle sprite y expansion, set BA for sprite 0
1798 case 55:
1799 draw_graphics();
1800 SampleBorder;
1801 graphics_access();
1802 DisplayIfBadLine;
1803
1804 // Invert y expansion flipflop if bit in MYE is set
1805 mask = 1;
1806 for (i=0; i<8; i++, mask<<=1)
1807 if (mye & mask)
1808 spr_exp_y ^= mask;
1809 CheckSpriteDMA;
1810
1811 if (spr_dma_on & 0x01) { // Don't remove these braces!
1812 SetBALow;
1813 } else
1814 the_cpu->BALow = false;
1815 break;
1816
1817 // Turn on border in 38 column mode, turn on sprite DMA if Y coordinate is right and
1818 // sprite is enabled, set BA for sprite 0, display window ends here
1819 case 56:
1820 if (!(ctrl2 & 8))
1821 border_on = true;
1822
1823 // Fourth sample of border state
1824 border_on_sample[3] = border_on;
1825
1826 draw_graphics();
1827 SampleBorder;
1828 IdleAccess;
1829 DisplayIfBadLine;
1830 CheckSpriteDMA;
1831
1832 if (spr_dma_on & 0x01)
1833 SetBALow;
1834 break;
1835
1836 // Turn on border in 40 column mode, set BA for sprite 1, paint sprites
1837 case 57:
1838 if (ctrl2 & 8)
1839 border_on = true;
1840
1841 // Fifth sample of border state
1842 border_on_sample[4] = border_on;
1843
1844 // Sample spr_disp_on and spr_data for sprite drawing
1845 if ((spr_draw = spr_disp_on) != 0)
1846 memcpy(spr_draw_data, spr_data, 8*4);
1847
1848 // Turn off sprite display if DMA is off
1849 mask = 1;
1850 for (i=0; i<8; i++, mask<<=1)
1851 if ((spr_disp_on & mask) && !(spr_dma_on & mask))
1852 spr_disp_on &= ~mask;
1853
1854 draw_background();
1855 SampleBorder;
1856 IdleAccess;
1857 DisplayIfBadLine;
1858 if (spr_dma_on & 0x02)
1859 SetBALow;
1860 break;
1861
1862 // Fetch sprite pointer 0, mc_base->mc, turn on sprite display if necessary,
1863 // turn off display if RC=7, read data of sprite 0
1864 case 58:
1865 draw_background();
1866 SampleBorder;
1867
1868 mask = 1;
1869 for (i=0; i<8; i++, mask<<=1) {
1870 mc[i] = mc_base[i];
1871 if ((spr_dma_on & mask) && (raster_y & 0xff) == my[i])
1872 spr_disp_on |= mask;
1873 }
1874 SprPtrAccess(0);
1875 SprDataAccess(0, 0);
1876
1877 if (rc == 7) {
1878 vc_base = vc;
1879 display_state = false;
1880 }
1881 if (is_bad_line || display_state) {
1882 display_state = true;
1883 rc = (rc + 1) & 7;
1884 }
1885 break;
1886
1887 // Set BA for sprite 2, read data of sprite 0
1888 case 59:
1889 draw_background();
1890 SampleBorder;
1891 SprDataAccess(0, 1);
1892 SprDataAccess(0, 2);
1893 DisplayIfBadLine;
1894 if (spr_dma_on & 0x04)
1895 SetBALow;
1896 break;
1897
1898 // Fetch sprite pointer 1, reset BA if sprite 1 and 2 off, graphics display ends here
1899 case 60:
1900 draw_background();
1901 SampleBorder;
1902
1903 if (draw_this_line) {
1904
1905 // Draw sprites
1906 if (spr_draw && ThePrefs.SpritesOn)
1907 draw_sprites();
1908
1909 // Draw border
1910 #ifdef __POWERPC__
1911 if (border_on_sample[0])
1912 for (i=0; i<4; i++)
1913 memset8((uint8 *)chunky_tmp+i*8, border_color_sample[i]);
1914 if (border_on_sample[1])
1915 memset8((uint8 *)chunky_tmp+4*8, border_color_sample[4]);
1916 if (border_on_sample[2])
1917 for (i=5; i<43; i++)
1918 memset8((uint8 *)chunky_tmp+i*8, border_color_sample[i]);
1919 if (border_on_sample[3])
1920 memset8((uint8 *)chunky_tmp+43*8, border_color_sample[43]);
1921 if (border_on_sample[4])
1922 for (i=44; i<DISPLAY_X/8; i++)
1923 memset8((uint8 *)chunky_tmp+i*8, border_color_sample[i]);
1924 #else
1925 if (border_on_sample[0])
1926 for (i=0; i<4; i++)
1927 memset8(chunky_line_start+i*8, border_color_sample[i]);
1928 if (border_on_sample[1])
1929 memset8(chunky_line_start+4*8, border_color_sample[4]);
1930 if (border_on_sample[2])
1931 for (i=5; i<43; i++)
1932 memset8(chunky_line_start+i*8, border_color_sample[i]);
1933 if (border_on_sample[3])
1934 memset8(chunky_line_start+43*8, border_color_sample[43]);
1935 if (border_on_sample[4])
1936 for (i=44; i<DISPLAY_X/8; i++)
1937 memset8(chunky_line_start+i*8, border_color_sample[i]);
1938 #endif
1939
1940 #ifdef __POWERPC__
1941 // Copy temporary buffer to bitmap
1942 fastcopy(chunky_line_start, (uint8 *)chunky_tmp);
1943 #endif
1944
1945 // Increment pointer in chunky buffer
1946 chunky_line_start += xmod;
1947 }
1948
1949 SprPtrAccess(1);
1950 SprDataAccess(1, 0);
1951 DisplayIfBadLine;
1952 if (!(spr_dma_on & 0x06))
1953 the_cpu->BALow = false;
1954 break;
1955
1956 // Set BA for sprite 3, read data of sprite 1
1957 case 61:
1958 SprDataAccess(1, 1);
1959 SprDataAccess(1, 2);
1960 DisplayIfBadLine;
1961 if (spr_dma_on & 0x08)
1962 SetBALow;
1963 break;
1964
1965 // Read sprite pointer 2, reset BA if sprite 2 and 3 off, read data of sprite 2
1966 case 62:
1967 SprPtrAccess(2);
1968 SprDataAccess(2, 0);
1969 DisplayIfBadLine;
1970 if (!(spr_dma_on & 0x0c))
1971 the_cpu->BALow = false;
1972 break;
1973
1974 // Set BA for sprite 4, read data of sprite 2
1975 case 63:
1976 SprDataAccess(2, 1);
1977 SprDataAccess(2, 2);
1978 DisplayIfBadLine;
1979
1980 if (raster_y == dy_stop)
1981 ud_border_on = true;
1982 else
1983 if (ctrl1 & 0x10 && raster_y == dy_start)
1984 ud_border_on = false;
1985
1986 if (spr_dma_on & 0x10)
1987 SetBALow;
1988
1989 // Last cycle
1990 raster_x += 8;
1991 cycle = 1;
1992 return true;
1993 }
1994
1995 // Next cycle
1996 raster_x += 8;
1997 cycle++;
1998 return false;
1999 }