ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/VIC_SC.cpp
Revision: 1.2
Committed: 2003-07-01T17:51:17Z (21 years, 4 months ago) by cebix
Branch: MAIN
Changes since 1.1: +1 -1 lines
Log Message:
updated copyright date

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * VIC_SC.cpp - 6569R5 emulation (cycle based)
3     *
4 cebix 1.2 * Frodo (C) 1994-1997,2002-2003 Christian Bauer
5 cebix 1.1 *
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))
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     }