1 /*
2  * vicii-cycle.c - Cycle based VIC-II emulation.
3  *
4  * Written by
5  *  Hannu Nuotio <hannu.nuotio@tut.fi>
6  *  Daniel Kahlin <daniel@kahlin.net>
7  *
8  * Based on code by
9  *  Ettore Perazzoli <ettore@comm2000.it>
10  *  Andreas Boose <viceteam@t-online.de>
11  *
12  * This file is part of VICE, the Versatile Commodore Emulator.
13  * See README for copyright notice.
14  *
15  *  This program is free software; you can redistribute it and/or modify
16  *  it under the terms of the GNU General Public License as published by
17  *  the Free Software Foundation; either version 2 of the License, or
18  *  (at your option) any later version.
19  *
20  *  This program is distributed in the hope that it will be useful,
21  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  *  GNU General Public License for more details.
24  *
25  *  You should have received a copy of the GNU General Public License
26  *  along with this program; if not, write to the Free Software
27  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28  *  02111-1307  USA.
29  *
30  */
31 
32 #include "vice.h"
33 
34 #include "debug.h"
35 #include "lib.h"
36 #include "log.h"
37 #include "maincpu.h"
38 #include "types.h"
39 #include "vicii-chip-model.h"
40 #include "vicii-cycle.h"
41 #include "vicii-draw-cycle.h"
42 #include "vicii-fetch.h"
43 #include "vicii-irq.h"
44 #include "vicii-lightpen.h"
45 #include "vicii-resources.h"
46 #include "vicii.h"
47 #include "viciitypes.h"
48 
check_badline(void)49 static inline void check_badline(void)
50 {
51     /* Check badline condition (line range and "allow bad lines" handled outside */
52     if ((vicii.raster_line & 7) == vicii.ysmooth) {
53         vicii.bad_line = 1;
54         vicii.idle_state = 0;
55     } else {
56         vicii.bad_line = 0;
57     }
58 }
59 
check_sprite_display(void)60 static inline void check_sprite_display(void)
61 {
62     int i, b;
63     int enable = vicii.regs[0x15];
64 
65     for (i = 0, b = 1; i < VICII_NUM_SPRITES; i++, b <<= 1) {
66         unsigned int y = vicii.regs[i * 2 + 1];
67         vicii.sprite[i].mc = vicii.sprite[i].mcbase;
68 
69         if (vicii.sprite_dma & b) {
70             if ((enable & b) && (y == (vicii.raster_line & 0xff))) {
71                 vicii.sprite_display_bits |= b;
72             }
73         } else {
74             vicii.sprite_display_bits &= ~b;
75         }
76     }
77 }
78 
sprite_mcbase_update(void)79 static inline void sprite_mcbase_update(void)
80 {
81     int i;
82 
83     for (i = 0; i < VICII_NUM_SPRITES; i++) {
84         if (vicii.sprite[i].exp_flop) {
85             vicii.sprite[i].mcbase = vicii.sprite[i].mc;
86             if (vicii.sprite[i].mcbase == 63) {
87                 vicii.sprite_dma &= ~(1 << i);
88             }
89         }
90     }
91 }
92 
check_exp(void)93 static inline void check_exp(void)
94 {
95     int i, b;
96     int y_exp = vicii.regs[0x17];
97 
98     for (i = 0, b = 1; i < VICII_NUM_SPRITES; i++, b <<= 1) {
99         if ((vicii.sprite_dma & b) && (y_exp & b)) {
100             vicii.sprite[i].exp_flop ^= 1;
101         }
102     }
103 }
104 
105 /* Enable DMA for sprite i.  */
turn_sprite_dma_on(unsigned int i,int y_exp)106 static inline void turn_sprite_dma_on(unsigned int i, int y_exp)
107 {
108     vicii.sprite_dma |= 1 << i;
109     vicii.sprite[i].mcbase = 0;
110     vicii.sprite[i].exp_flop = 1;
111 }
112 
check_sprite_dma(void)113 static inline void check_sprite_dma(void)
114 {
115     int i, b;
116     int enable = vicii.regs[0x15];
117     int y_exp = vicii.regs[0x17];
118 
119     for (i = 0, b = 1; i < VICII_NUM_SPRITES; i++, b <<= 1) {
120         unsigned int y = vicii.regs[i * 2 + 1];
121 
122         if ((enable & b) && (y == (vicii.raster_line & 0xff)) && !(vicii.sprite_dma & b)) {
123             turn_sprite_dma_on(i, y_exp & b);
124         }
125     }
126 }
127 
cycle_phi1_fetch(unsigned int cycle_flags)128 static inline uint8_t cycle_phi1_fetch(unsigned int cycle_flags)
129 {
130     uint8_t data;
131     int s;
132 
133     if (cycle_is_fetch_g(cycle_flags)) {
134         if (!vicii.idle_state) {
135             data = vicii_fetch_graphics();
136         } else {
137             data = vicii_fetch_idle_gfx();
138         }
139         return data;
140     }
141 
142     if (cycle_is_sprite_ptr_dma0(cycle_flags)) {
143         s = cycle_get_sprite_num(cycle_flags);
144         data = vicii_fetch_sprite_pointer(s);
145         return data;
146     }
147     if (cycle_is_sprite_dma1_dma2(cycle_flags)) {
148         s = cycle_get_sprite_num(cycle_flags);
149         data = vicii_fetch_sprite_dma_1(s);
150         return data;
151     }
152 
153     if (cycle_is_refresh(cycle_flags)) {
154         data = vicii_fetch_refresh();
155         return data;
156     }
157 
158     data = vicii_fetch_idle();
159 
160     return data;
161 }
162 
check_vborder_top(int line)163 static inline void check_vborder_top(int line)
164 {
165     int rsel = vicii.regs[0x11] & 0x08;
166 
167     if ((line == (rsel ? VICII_25ROW_START_LINE : VICII_24ROW_START_LINE)) && (vicii.regs[0x11] & 0x10)) {
168         vicii.vborder = 0;
169         vicii.set_vborder = 0;
170     }
171 }
172 
check_vborder_bottom(int line)173 static inline void check_vborder_bottom(int line)
174 {
175     int rsel = vicii.regs[0x11] & 0x08;
176 
177     if (line == (rsel ? VICII_25ROW_STOP_LINE : VICII_24ROW_STOP_LINE)) {
178         vicii.set_vborder = 1;
179     }
180 }
181 
check_hborder(unsigned int cycle_flags)182 static inline void check_hborder(unsigned int cycle_flags)
183 {
184     int csel = vicii.regs[0x16] & 0x08;
185 
186     /* Left border ends at cycles 17 (csel=1) or 18 (csel=0) on PAL. */
187     if (cycle_is_check_border_l(cycle_flags, csel)) {
188         check_vborder_bottom(vicii.raster_line);
189         vicii.vborder = vicii.set_vborder;
190         if (vicii.vborder == 0) {
191             vicii.main_border = 0;
192         }
193     }
194     /* Right border starts at cycles 56 (csel=0) or 57 (csel=1) on PAL. */
195     if (cycle_is_check_border_r(cycle_flags, csel)) {
196         vicii.main_border = 1;
197     }
198 }
199 
vicii_cycle_start_of_frame(void)200 static inline void vicii_cycle_start_of_frame(void)
201 {
202     vicii.start_of_frame = 0;
203     vicii.raster_line = 0;
204     vicii.refresh_counter = 0xff;
205     vicii.allow_bad_lines = 0;
206     vicii.vcbase = 0;
207     vicii.vc = 0;
208     vicii.light_pen.triggered = 0;
209 
210     /* Retrigger light pen if line is still held low */
211     if (vicii.light_pen.state) {
212         /* add offset depending on chip model (FIXME use proper variable) */
213         vicii.light_pen.x_extra_bits = (vicii.color_latency ? 2 : 1);
214         vicii_trigger_light_pen_internal(1);
215     }
216 }
217 
vicii_cycle_end_of_line(void)218 static inline void vicii_cycle_end_of_line(void)
219 {
220     vicii_raster_draw_handler();
221     if (vicii.raster_line == vicii.screen_height - 1) {
222         vicii.start_of_frame = 1;
223     }
224 }
225 
vicii_cycle_start_of_line(void)226 static inline void vicii_cycle_start_of_line(void)
227 {
228     /* Check DEN bit on first cycle of the line following the first DMA line  */
229     if ((vicii.raster_line == VICII_FIRST_DMA_LINE) && !vicii.allow_bad_lines && (vicii.regs[0x11] & 0x10)) {
230         vicii.allow_bad_lines = 1;
231     }
232 
233     /* Disallow bad lines after the last possible one has passed */
234     if (vicii.raster_line == VICII_LAST_DMA_LINE) {
235         vicii.allow_bad_lines = 0;
236     }
237 
238     vicii.bad_line = 0;
239 }
240 
241 
next_vicii_cycle(void)242 static inline void next_vicii_cycle(void)
243 {
244     /* Next cycle */
245     vicii.raster_cycle++;
246 
247     /* Handle wrapping */
248     if (vicii.raster_cycle == (unsigned int)vicii.cycles_per_line) {
249         vicii.raster_cycle = 0;
250     }
251 }
252 
vicii_cycle(void)253 int vicii_cycle(void)
254 {
255     int ba_low = 0;
256     int can_sprite_sprite, can_sprite_background;
257     int may_crash;
258 
259     /*VICII_DEBUG_CYCLE(("cycle: line %i, clk %i", vicii.raster_line, vicii.raster_cycle));*/
260 
261     /* perform phi2 fetch after the cpu has executed */
262     vicii_fetch_sprites(vicii.cycle_flags);
263 
264     /*
265      *
266      * End of Phi2
267      *
268      ******/
269 
270     /* Next cycle */
271     next_vicii_cycle();
272     vicii.cycle_flags = vicii.cycle_table[vicii.raster_cycle];
273 
274     /******
275      *
276      * Start of Phi1
277      *
278      */
279 
280     /* Phi1 fetch */
281     vicii.last_read_phi1 = cycle_phi1_fetch(vicii.cycle_flags);
282 
283     /* Check horizontal border flag */
284     check_hborder(vicii.cycle_flags);
285 
286     can_sprite_sprite = (vicii.sprite_sprite_collisions == 0);
287     can_sprite_background = (vicii.sprite_background_collisions == 0);
288 
289     /* Draw one cycle of pixels */
290     vicii_draw_cycle();
291 
292     /* clear any collision registers as initiated by $d01e or $d01f reads */
293     switch (vicii.clear_collisions) {
294         case 0x1e:
295             vicii.sprite_sprite_collisions = 0;
296             vicii.clear_collisions = 0;
297             break;
298         case 0x1f:
299             vicii.sprite_background_collisions = 0;
300             vicii.clear_collisions = 0;
301             break;
302         default:
303             break;
304     }
305 
306     /* Trigger collision IRQs */
307     if (can_sprite_sprite && vicii.sprite_sprite_collisions) {
308         vicii_irq_sscoll_set();
309     }
310     if (can_sprite_background && vicii.sprite_background_collisions) {
311         vicii_irq_sbcoll_set();
312     }
313 
314     /*
315      *
316      * End of Phi1
317      *
318      ******/
319 
320     /******
321      *
322      * Start of Phi2
323      *
324      */
325 
326     /* Handle end of line/start of new line */
327     if (vicii.raster_cycle == VICII_PAL_CYCLE(1)) {
328         vicii_cycle_end_of_line();
329         vicii_cycle_start_of_line();
330     }
331 
332     if (vicii.start_of_frame) {
333         if (vicii.raster_cycle == VICII_PAL_CYCLE(2)) {
334             vicii_cycle_start_of_frame();
335         }
336     } else {
337         if (vicii.raster_cycle == VICII_PAL_CYCLE(1)) {
338             vicii.raster_line++;
339         }
340     }
341 
342     /*
343      * Trigger a raster IRQ if the raster comparison goes from
344      * non-match to match.
345      */
346     if (vicii.raster_line == vicii.raster_irq_line) {
347         if (!vicii.raster_irq_triggered) {
348             vicii_irq_raster_trigger();
349             vicii.raster_irq_triggered = 1;
350         }
351     } else {
352         vicii.raster_irq_triggered = 0;
353     }
354 
355     /* Check vertical border flag */
356     check_vborder_top(vicii.raster_line);
357     /* Check vertical border flag */
358     check_vborder_bottom(vicii.raster_line);
359     if (vicii.raster_cycle == VICII_PAL_CYCLE(1)) {
360         vicii.vborder = vicii.set_vborder;
361     }
362 
363     /******
364      *
365      * Sprite logic
366      *
367      */
368 
369     /* Update sprite mcbase (Cycle 16 on PAL) */
370     /* if (vicii.raster_cycle == VICII_PAL_CYCLE(16)) { */
371     if (cycle_is_update_mcbase(vicii.cycle_flags)) {
372         sprite_mcbase_update();
373     }
374 
375     /* Check sprite DMA (Cycles 55 & 56 on PAL) */
376     /* if (vicii.raster_cycle == VICII_PAL_CYCLE(55)
377        || vicii.raster_cycle == VICII_PAL_CYCLE(56) ) { */
378     if (cycle_is_check_spr_dma(vicii.cycle_flags)) {
379         check_sprite_dma();
380     }
381 
382     /* Check sprite expansion flags (Cycle 56 on PAL) */
383     /* if (vicii.raster_cycle == VICII_PAL_CYCLE(56)) { */
384     if (cycle_is_check_spr_exp(vicii.cycle_flags)) {
385         check_exp();
386     }
387 
388     /* Check sprite display (Cycle 58 on PAL) */
389     /* if (vicii.raster_cycle == VICII_PAL_CYCLE(58)) { */
390     if (cycle_is_check_spr_disp(vicii.cycle_flags)) {
391         check_sprite_display();
392     }
393 
394     /******
395      *
396      * Graphics logic
397      *
398      */
399 
400     may_crash = !vicii.bad_line && vicii.idle_state; /* flag for "VSP bug" simulation */
401 
402     /* Check DEN bit on first DMA line */
403     if ((vicii.raster_line == VICII_FIRST_DMA_LINE) && !vicii.allow_bad_lines) {
404         vicii.allow_bad_lines = (vicii.regs[0x11] & 0x10) ? 1 : 0;
405     }
406 
407     /* Check badline condition, trigger fetches */
408     if (vicii.allow_bad_lines) {
409         check_badline();
410     }
411 
412     /* simulate the "VSP bug" problem */
413     if(vicii_resources.vsp_bug_enabled) {
414         /* FIXME: no support for "vsp channels", see VSP Lab (http://csdb.dk/release/?id=120810) */
415         if(vicii.bad_line && may_crash && (vicii.raster_cycle >= VICII_PAL_CYCLE(16)) &&
416            (vicii.raster_cycle < VICII_PAL_CYCLE(55))) {
417             int page, row;
418             for(page = 0; page < 256; page++) {
419                 int seen0 = 0, seen1 = 0, fragile, result;
420                 int firstrow = 7;
421                 for(row = firstrow; row <= 0xff; row += 8) {
422                     seen0 |= vicii.ram_base_phi1[(page << 8) | row] ^ 255;
423                     seen1 |= vicii.ram_base_phi1[(page << 8) | row];
424                 }
425                 fragile = seen0 & seen1;
426                 if(fragile && (lib_unsigned_rand(0, 0xff) < 10)) {
427                     result = fragile & lib_unsigned_rand(0, 0xff);
428                     for(row = firstrow; row <= 0xff; row += 8) {
429                         log_message(vicii.log, "VSP Bug: Corrupting %04x, fragile %02x, new bits %02x", (page << 8) | row, fragile, result);
430                         vicii.ram_base_phi1[(page << 8) | row] &= ~fragile;
431                         vicii.ram_base_phi1[(page << 8) | row] |= result;
432                     }
433                 }
434             }
435         }
436     }
437 
438     /* Update VC (Cycle 14 on PAL) */
439     /*  if (vicii.raster_cycle == VICII_PAL_CYCLE(14)) { */
440     if (cycle_is_update_vc(vicii.cycle_flags)) {
441         vicii.vc = vicii.vcbase;
442         vicii.vmli = 0;
443         if (vicii.bad_line) {
444             vicii.rc = 0;
445         }
446     }
447 
448     /* Update RC (Cycle 58 on PAL) */
449     /* if (vicii.raster_cycle == VICII_PAL_CYCLE(58)) { */
450     if (cycle_is_update_rc(vicii.cycle_flags)) {
451         /* `rc' makes the chip go to idle state when it reaches the
452            maximum value.  */
453         if (vicii.rc == 7) {
454             vicii.idle_state = 1;
455             vicii.vcbase = vicii.vc;
456         }
457         if (!vicii.idle_state || vicii.bad_line) {
458             vicii.rc = (vicii.rc + 1) & 0x7;
459             vicii.idle_state = 0;
460         }
461     }
462 
463     /******
464      *
465      * BA logic
466      *
467      */
468 
469     /* Check BA for matrix fetch */
470     if (vicii.bad_line && cycle_is_fetch_ba(vicii.cycle_flags)) {
471         ba_low = 1;
472     }
473 
474     /* Check BA for Sprite Phi2 fetch */
475     ba_low |= vicii_check_sprite_ba(vicii.cycle_flags);
476 
477     /* if ba_low transitioning from non-active to active, always count
478        3 cycles before allowing any Phi2 accesses. */
479     if (ba_low) {
480         /* count down prefetch cycles */
481         if (vicii.prefetch_cycles) {
482             vicii.prefetch_cycles--;
483         }
484     } else {
485         /* this needs to be +1 because it gets decremented already in the
486            first ba cycle */
487         vicii.prefetch_cycles = 3 + 1;
488     }
489 
490 
491     /* Matrix fetch */
492     if (vicii.bad_line && cycle_may_fetch_c(vicii.cycle_flags)) {
493 #ifdef DEBUG
494         if (debug.maincpu_traceflg) {
495             log_debug("DMA at cycle %d   %d", vicii.raster_cycle, maincpu_clk);
496         }
497 #endif
498         vicii_fetch_matrix();
499     }
500 
501     /* clear internal bus (may get set by a VIC-II read or write) */
502     vicii.last_bus_phi2 = 0xff;
503 
504     /* delay video mode for fetches by one cycle */
505     vicii.reg11_delay = vicii.regs[0x11];
506 
507     /* trigger light pen if scheduled */
508     if (vicii.light_pen.trigger_cycle == maincpu_clk) {
509         vicii_trigger_light_pen_internal(0);
510     }
511 
512     return ba_low;
513 }
514 
515 /* The REU can use an additional cycle at the point where the dma of sprite 0 is turned on */
516 /* this is because of late setting of BA due to internal delays */
517 /* The CPU can't use this cycle as it checks the state later */
vicii_cycle_reu(void)518 int vicii_cycle_reu(void)
519 {
520     int check = vicii.raster_cycle == VICII_PAL_CYCLE(54) && (vicii.regs[0x15] & 1) && (vicii.regs[1] == (vicii.raster_line & 0xff)) && !(vicii.sprite_dma & 1);
521     return vicii_cycle() && !check;
522 }
523 
524 /* Steal cycles from CPU  */
vicii_steal_cycles(void)525 void vicii_steal_cycles(void)
526 {
527     int ba_low;
528 
529     do {
530         maincpu_clk++;
531         ba_low = vicii_cycle();
532     } while (ba_low);
533 }
534