1 /*
2  * vicii-fetch.c - Phi2 data fetch for the MOS 6569 (VIC-II) emulation.
3  *
4  * Written by
5  *  Andreas Boose <viceteam@t-online.de>
6  *  Ettore Perazzoli <ettore@comm2000.it>
7  *
8  * DTV sections written by
9  *  Hannu Nuotio <hannu.nuotio@tut.fi>
10  *  Daniel Kahlin <daniel@kahlin.net>
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 <string.h>
35 
36 #include "alarm.h"
37 #include "debug.h"
38 #include "c64cart.h"
39 #include "c64cartmem.h"
40 #include "dma.h"
41 #include "log.h"
42 #include "maincpu.h"
43 #include "mem.h"
44 #include "raster-changes.h"
45 #include "raster-sprite-status.h"
46 #include "raster-sprite.h"
47 #include "raster.h"
48 #include "types.h"
49 #include "vicii-fetch.h"
50 #include "vicii-irq.h"
51 #include "vicii-sprites.h"
52 #include "viciitypes.h"
53 
54 
55 /* Emulate a matrix line fetch, `num' bytes starting from `offs'.  This takes
56    care of the 10-bit counter wraparound.  */
vicii_fetch_matrix(int offs,int num,int num_0xff,int cycle)57 void vicii_fetch_matrix(int offs, int num, int num_0xff, int cycle)
58 {
59     int start_char;
60     int c;
61     uint8_t *colorram = NULL;
62 
63     /*log_debug("OFF %02i NUM %02i NFF %02i",offs,num,num_0xff);*/
64 
65     if (vicii.viciidtv) {
66         num_0xff = 0;
67         colorram = vicii.color_ram_ptr;
68     } else {
69         colorram = mem_color_ram_vicii;
70     }
71 
72     if (num_0xff > 0) {
73         if (num <= num_0xff) {
74             memset(vicii.vbuf + offs, 0xff, num);
75             memset(vicii.cbuf + offs, vicii.ram_base_phi2[reg_pc] & 0xf, num);
76             /* FIXME: Crunch table in Multiplexer part of Krestage */
77             vicii.background_color_source = 0xff;
78         } else {
79             memset(vicii.vbuf + offs, 0xff, num_0xff);
80             memset(vicii.cbuf + offs, vicii.ram_base_phi2[reg_pc] & 0xf, num_0xff);
81         }
82     }
83 
84     if (num > num_0xff) {
85         offs += num_0xff;
86         num -= num_0xff;
87 
88         /* Matrix fetches are done during Phi2, the fabulous "bad lines" */
89         start_char = (vicii.mem_counter + offs) & 0x3ff;
90         c = 0x3ff - start_char + 1;
91 
92         if (c >= num) {
93             memcpy(vicii.vbuf + offs, vicii.screen_base_phi2 + start_char, num);
94             if (!vicii.colorfetch_disable) {
95                 memcpy(vicii.cbuf + offs, colorram + start_char, num);
96             }
97         } else {
98             memcpy(vicii.vbuf + offs, vicii.screen_base_phi2 + start_char, c);
99             memcpy(vicii.vbuf + offs + c, vicii.screen_base_phi2, num - c);
100 
101             if (!vicii.colorfetch_disable) {
102                 memcpy(vicii.cbuf + offs, colorram + start_char, c);
103             }
104 
105             if (!vicii.colorfetch_disable) {
106                 memcpy(vicii.cbuf + offs + c, colorram, num - c);
107             }
108         }
109         vicii.background_color_source = vicii.vbuf[VICII_SCREEN_TEXTCOLS - 1 /*- vicii.buf_offset*/];
110     }
111 
112     /* Set correct background color in in the xsmooth area.
113        As this only affects the next line, the xsmooth color is immediately
114        set if the right border is opened.  */
115     if (offs + num >= VICII_SCREEN_TEXTCOLS) {
116         switch (vicii.get_background_from_vbuf) {
117             case VICII_HIRES_BITMAP_MODE:
118                 raster_changes_next_line_add_int(
119                     &vicii.raster,
120                     &vicii.raster.xsmooth_color,
121                     vicii.background_color_source & 0x0f);
122                 break;
123             case VICII_EXTENDED_TEXT_MODE:
124                 raster_changes_next_line_add_int(
125                     &vicii.raster,
126                     &vicii.raster.xsmooth_color,
127                     vicii.regs[0x21 + (vicii.background_color_source >> 6)]);
128                 break;
129         }
130     }
131 }
132 
133 /* If we are on a bad line, do the DMA.  Return nonzero if cycles have been
134    stolen.  */
do_matrix_fetch(CLOCK sub)135 inline static int do_matrix_fetch(CLOCK sub)
136 {
137     if (!vicii.memory_fetch_done) {
138         raster_t *raster;
139 
140         raster = &vicii.raster;
141 
142         vicii.memory_fetch_done = 1;
143         vicii.mem_counter = vicii.memptr;
144 
145         if ((raster->current_line & 7) == (unsigned int)raster->ysmooth
146             && vicii.allow_bad_lines
147             && raster->current_line >= vicii.first_dma_line
148             && raster->current_line <= vicii.last_dma_line) {
149             vicii_fetch_matrix(0, VICII_SCREEN_TEXTCOLS, 0, VICII_FETCH_CYCLE);
150 
151             raster->draw_idle_state = 0;
152             raster->ycounter = 0;
153 
154             vicii.idle_state = 0;
155             vicii.idle_data_location = IDLE_NONE;
156             vicii.ycounter_reset_checked = 1;
157             vicii.memory_fetch_done = 2;
158 
159             if ((vicii.fastmode == 0) && !vicii.badline_disable && !vicii.colorfetch_disable) {
160                 dma_maincpu_steal_cycles(vicii.fetch_clk,
161                                          VICII_SCREEN_TEXTCOLS + 3 - sub, sub);
162             } else if (vicii.viciidtv && !vicii.colorfetch_disable) {
163                 /* Steal cycles from DMA/Blitter */
164                 dtvclockneg += VICII_SCREEN_TEXTCOLS + 3;
165             }
166             vicii.bad_line = 1;
167             return 1;
168         }
169     }
170 
171     return 0;
172 }
173 
handle_fetch_matrix(long offset,CLOCK sub,CLOCK * write_offset)174 inline static int handle_fetch_matrix(long offset, CLOCK sub,
175                                       CLOCK *write_offset)
176 {
177     raster_t *raster;
178     raster_sprite_status_t *sprite_status;
179 
180     *write_offset = 0;
181 
182     raster = &vicii.raster;
183     sprite_status = raster->sprite_status;
184 
185     if (sprite_status->visible_msk == 0 && sprite_status->dma_msk == 0) {
186         do_matrix_fetch(sub);
187 
188         /* As sprites are all turned off, there is no need for a sprite DMA
189            check; next time we will VICII_FETCH_MATRIX again.  This works
190            because a VICII_CHECK_SPRITE_DMA is forced in `vic_store()'
191            whenever the mask becomes nonzero.  */
192 
193         /* This makes sure we only create VICII_FETCH_MATRIX events in the bad
194            line range.  These checks are (a little) redundant for safety.  */
195         if (raster->current_line < vicii.first_dma_line) {
196             vicii.fetch_clk += ((vicii.first_dma_line - raster->current_line) * vicii.cycles_per_line);
197         } else {
198             if (raster->current_line >= vicii.last_dma_line) {
199                 vicii.fetch_clk += ((vicii.screen_height
200                                      - raster->current_line
201                                      + vicii.first_dma_line)
202                                     * vicii.cycles_per_line);
203             } else {
204                 vicii.fetch_clk += vicii.cycles_per_line;
205             }
206         }
207 
208         alarm_set(vicii.raster_fetch_alarm, vicii.fetch_clk);
209         return 1;
210     } else {
211         int fetch_done;
212 
213         fetch_done = do_matrix_fetch(sub);
214 
215         /* Sprites might be turned on, check for sprite DMA next
216            time.  */
217         vicii.fetch_idx = VICII_CHECK_SPRITE_DMA;
218 
219         /* Calculate time for next event.  */
220         vicii.fetch_clk = VICII_LINE_START_CLK(maincpu_clk)
221                           + vicii.sprite_fetch_cycle;
222 
223         if (vicii.fetch_clk > maincpu_clk || offset == 0) {
224             /* Prepare the next fetch event.  */
225             alarm_set(vicii.raster_fetch_alarm, vicii.fetch_clk);
226             return 1;
227         }
228 
229         if (fetch_done && sub == 0) {
230             *write_offset = VICII_SCREEN_TEXTCOLS + 3;
231         }
232     }
233 
234     return 0;
235 }
236 
237 /*-----------------------------------------------------------------------*/
238 
swap_sprite_data_buffers(void)239 inline static void swap_sprite_data_buffers(void)
240 {
241     uint32_t *tmp;
242     raster_sprite_status_t *sprite_status;
243 
244     /* Swap sprite data buffers.  */
245     sprite_status = vicii.raster.sprite_status;
246     tmp = sprite_status->sprite_data;
247     sprite_status->sprite_data = sprite_status->new_sprite_data;
248     sprite_status->new_sprite_data = tmp;
249 }
250 
251 /* Enable DMA for sprite `num'.  */
turn_sprite_dma_on(unsigned int num)252 inline static void turn_sprite_dma_on(unsigned int num)
253 {
254     raster_sprite_status_t *sprite_status;
255     raster_sprite_t *sprite;
256 
257     sprite_status = vicii.raster.sprite_status;
258     sprite = sprite_status->sprites + num;
259 
260     sprite_status->new_dma_msk |= 1 << num;
261     sprite->dma_flag = 1;
262     sprite->memptr = 0;
263     sprite->exp_flag = sprite->y_expanded ? 0 : 1;
264     sprite->memptr_inc = sprite->exp_flag ? 3 : 0;
265 }
266 
check_sprite_dma(void)267 inline static void check_sprite_dma(void)
268 {
269     raster_sprite_status_t *sprite_status;
270     int i, b;
271 
272     sprite_status = vicii.raster.sprite_status;
273 
274     if (!sprite_status->visible_msk && !sprite_status->dma_msk) {
275         return;
276     }
277 
278     sprite_status->new_dma_msk = sprite_status->dma_msk;
279 
280     for (i = 0, b = 1; i < VICII_NUM_SPRITES; i++, b <<= 1) {
281         raster_sprite_t *sprite;
282 
283         sprite = sprite_status->sprites + i;
284 
285         if ((sprite_status->visible_msk & b)
286             && sprite->y == ((int)vicii.raster.current_line & 0xff)
287             && !sprite->dma_flag) {
288             turn_sprite_dma_on(i);
289         } else if (sprite->dma_flag) {
290             sprite->memptr = (sprite->memptr + sprite->memptr_inc) & 0x3f;
291 
292             if (sprite->y_expanded) {
293                 sprite->exp_flag = !sprite->exp_flag;
294             }
295 
296             sprite->memptr_inc = sprite->exp_flag ? 3 : 0;
297 
298             if (sprite->memptr == 63) {
299                 sprite->dma_flag = 0;
300                 sprite_status->new_dma_msk &= ~b;
301 
302                 if ((sprite_status->visible_msk & b)
303                     && sprite->y == ((int)vicii.raster.current_line & 0xff)) {
304                     turn_sprite_dma_on(i);
305                 }
306             }
307         }
308     }
309 }
310 
handle_check_sprite_dma(long offset,CLOCK sub)311 inline static int handle_check_sprite_dma(long offset, CLOCK sub)
312 {
313     swap_sprite_data_buffers();
314 
315     check_sprite_dma();
316 
317     if (vicii.raster.sprite_status->dma_msk || vicii.raster.sprite_status->new_dma_msk) {
318         vicii_sprites_reset_sprline();
319     }
320 
321     /* FIXME?  Slow!  */
322     vicii.sprite_fetch_clk = (VICII_LINE_START_CLK(maincpu_clk) + vicii.sprite_fetch_cycle);
323     vicii.sprite_fetch_msk = vicii.raster.sprite_status->new_dma_msk;
324 
325     if (vicii_sprites_fetch_table[vicii.sprite_fetch_msk][0].cycle == -1) {
326         if (vicii.raster.current_line >= vicii.first_dma_line - 1
327             && vicii.raster.current_line <= vicii.last_dma_line + 1) {
328             vicii.fetch_idx = VICII_FETCH_MATRIX;
329             vicii.fetch_clk = (vicii.sprite_fetch_clk
330                                - vicii.sprite_fetch_cycle
331                                + VICII_FETCH_CYCLE
332                                + vicii.cycles_per_line);
333         } else {
334             vicii.fetch_idx = VICII_CHECK_SPRITE_DMA;
335             vicii.fetch_clk = (vicii.sprite_fetch_clk + vicii.cycles_per_line);
336         }
337     } else {
338         /* Next time, fetch sprite data.  */
339         vicii.fetch_idx = VICII_FETCH_SPRITE;
340         vicii.sprite_fetch_idx = 0;
341         vicii.fetch_clk = (vicii.sprite_fetch_clk + vicii_sprites_fetch_table[vicii.sprite_fetch_msk][0].cycle);
342     }
343 
344     /*log_debug("HCSD SCLK %i FCLK %i CLK %i OFFSET %li SUB %i",
345                 vicii.store_clk, vicii.fetch_clk, clk, offset, sub);*/
346 
347     if (vicii.store_clk != CLOCK_MAX) {
348         if (vicii.store_clk + offset - 3 < vicii.fetch_clk) {
349             vicii.ram_base_phi2[vicii.store_addr] = vicii.store_value;
350         }
351         vicii.store_clk = CLOCK_MAX;
352     }
353 
354     vicii.num_idle_3fff_old = vicii.num_idle_3fff;
355     if (vicii.num_idle_3fff > 0) {
356         memcpy(vicii.idle_3fff_old, vicii.idle_3fff,
357                sizeof(idle_3fff_t) * vicii.num_idle_3fff);
358     }
359     vicii.num_idle_3fff = 0;
360 
361     if (vicii.fetch_clk > maincpu_clk || offset == 0) {
362         alarm_set(vicii.raster_fetch_alarm, vicii.fetch_clk);
363         return 1;
364     }
365 
366     return 0;
367 }
368 
369 /*-----------------------------------------------------------------------*/
370 
handle_fetch_sprite(long offset,CLOCK sub,CLOCK * write_offset)371 inline static int handle_fetch_sprite(long offset, CLOCK sub,
372                                       CLOCK *write_offset)
373 {
374     const vicii_sprites_fetch_t *sf;
375     unsigned int i;
376     int next_cycle, num_cycles;
377     raster_sprite_status_t *sprite_status;
378     uint8_t *bank_phi1, *bank_phi2, *spr_base;
379 
380     sf = &vicii_sprites_fetch_table[vicii.sprite_fetch_msk][vicii.sprite_fetch_idx];
381 
382     sprite_status = vicii.raster.sprite_status;
383     /* FIXME: the 3 byte sprite data is instead taken during a Ph1/Ph2/Ph1
384        sequence. This is of minor interest, though, only for CBM-II... */
385     bank_phi1 = vicii.ram_base_phi1 + vicii.vbank_phi1;
386     bank_phi2 = vicii.ram_base_phi2 + vicii.vbank_phi2;
387     spr_base = vicii.screen_base_phi1 + 0x3f8 + sf->first;
388     if (vicii.viciidtv) {
389         spr_base += (vicii.regs[0x4d] << 16);
390     }
391 
392     /* Fetch sprite data.  */
393     for (i = sf->first; i <= sf->last; i++, spr_base++) {
394         if (vicii.sprite_fetch_msk & (1 << i)) {
395             uint8_t *src_phi1, *src_phi2;
396             uint8_t *dest;
397             int my_memptr;
398 
399 #ifdef DEBUG
400             if (debug.maincpu_traceflg) {
401                 log_debug("SDMA %i", i);
402             }
403 #endif
404 
405             src_phi1 = bank_phi1 + (*spr_base << 6);
406             src_phi2 = bank_phi2 + (*spr_base << 6);
407             my_memptr = sprite_status->sprites[i].memptr;
408             dest = (uint8_t *)(sprite_status->new_sprite_data + i);
409 
410             if (export.ultimax_phi1) {
411                 /* phi1 fetch from expansion port in ultimax mode */
412 #if 0
413                 if (*spr_base >= 0xc0) {
414                     /* src_phi1 = (romh_banks + 0x1000 + (romh_bank << 13)
415                                + ((*spr_base - 0xc0) << 6)); */
416                     src_phi1 = ultimax_romh_phi1_ptr((uint16_t)(0x1000 + ((*spr_base - 0xc0) << 6)));
417                 }
418 #endif
419                 uint8_t *ptr;
420                 if ((ptr = ultimax_romh_phi1_ptr((uint16_t)(0x1000 + ((*spr_base - 0xc0) << 6))))) {
421                     if (*spr_base >= 0xc0) {
422                         src_phi1 = ptr;
423                     }
424                 } else {
425                     goto phi1noultimax;
426                 }
427             } else {
428 phi1noultimax:
429                 if (((vicii.vbank_phi1 + (*spr_base << 6)) & vicii.vaddr_chargen_mask_phi1) == vicii.vaddr_chargen_value_phi1) {
430                     src_phi1 = mem_chargen_rom_ptr + ((*spr_base & 0x3f) << 6);
431                 }
432             }
433 
434             if (export.ultimax_phi2) {
435                 /* phi2 fetch from expansion port in ultimax mode */
436 #if 0
437                 if (*spr_base >= 0xc0) {
438                     /* src_phi2 = (romh_banks + 0x1000 + (romh_bank << 13)
439                                + ((*spr_base - 0xc0) << 6)); */
440                     src_phi2 = ultimax_romh_phi2_ptr((uint16_t)(0x1000 + ((*spr_base - 0xc0) << 6)));
441                 }
442 #endif
443                 uint8_t *ptr;
444                 if ((ptr = ultimax_romh_phi2_ptr((uint16_t)(0x1000 + ((*spr_base - 0xc0) << 6))))) {
445                     if (*spr_base >= 0xc0) {
446                         src_phi2 = ptr;
447                     }
448                 } else {
449                     goto phi2noultimax;
450                 }
451             } else {
452 phi2noultimax:
453                 if (((vicii.vbank_phi2 + (*spr_base << 6)) & vicii.vaddr_chargen_mask_phi2) == vicii.vaddr_chargen_value_phi2) {
454                     src_phi2 = mem_chargen_rom_ptr + ((*spr_base & 0x3f) << 6);
455                 }
456             }
457 
458             if (vicii.viciidtv) {
459                 src_phi1 += (vicii.regs[0x4d] << 16);
460                 src_phi2 += (vicii.regs[0x4d] << 16);
461             }
462 
463             dest[0] = src_phi2[my_memptr];
464             dest[1] = src_phi1[++my_memptr & 0x3f];
465             dest[2] = src_phi2[++my_memptr & 0x3f];
466         }
467     }
468 
469     num_cycles = sf->num;
470 
471     /*log_debug("SF %i VBL %i SUB %i",sf->num,vicii.bad_line,sub);*/
472 
473     if ((vicii.fastmode == 0) && !vicii.badline_disable) {
474         dma_maincpu_steal_cycles(vicii.fetch_clk, num_cycles - sub, sub);
475     } else if (vicii.viciidtv) {
476         /* Steal cycles from DMA/Blitter */
477         dtvclockneg += num_cycles;
478     }
479 
480     *write_offset = sub == 0 ? num_cycles : 0;
481 
482     next_cycle = (sf + 1)->cycle;
483     vicii.sprite_fetch_idx++;
484 
485     if (next_cycle == -1) {
486         /* Next time, handle bad lines.  */
487         if (vicii.raster.current_line >= vicii.first_dma_line - 1
488             && vicii.raster.current_line <= vicii.last_dma_line + 1) {
489             vicii.fetch_idx = VICII_FETCH_MATRIX;
490             vicii.fetch_clk = (vicii.sprite_fetch_clk
491                                - vicii.sprite_fetch_cycle
492                                + VICII_FETCH_CYCLE
493                                + vicii.cycles_per_line);
494         } else {
495             vicii.fetch_idx = VICII_CHECK_SPRITE_DMA;
496             vicii.fetch_clk = (vicii.sprite_fetch_clk + vicii.cycles_per_line);
497         }
498     } else {
499         vicii.fetch_clk = vicii.sprite_fetch_clk + next_cycle;
500     }
501 
502     if (maincpu_clk >= vicii.draw_clk) {
503         vicii_raster_draw_alarm_handler(maincpu_clk - vicii.draw_clk, NULL);
504     }
505 
506     if (vicii.fetch_clk > maincpu_clk || offset == 0) {
507         alarm_set(vicii.raster_fetch_alarm, vicii.fetch_clk);
508         return 1;
509     }
510 
511     if (maincpu_clk >= vicii.raster_irq_clk) {
512         vicii_irq_alarm_handler(maincpu_clk - vicii.raster_irq_clk, NULL);
513     }
514 
515     return 0;
516 }
517 
518 /*-----------------------------------------------------------------------*/
519 
520 /* Handle sprite/matrix fetch events.  FIXME: could be made slightly
521    faster.  */
vicii_fetch_alarm_handler(CLOCK offset,void * data)522 void vicii_fetch_alarm_handler(CLOCK offset, void *data)
523 {
524     CLOCK last_opcode_first_write_clk, last_opcode_last_write_clk;
525 
526     /* This kludgy thing is used to emulate the behavior of the 6510 when BA
527        goes low.  When BA goes low, every read access stops the processor
528        until BA is high again; write accesses happen as usual instead.  */
529 
530     if (offset > 0) {
531         switch (OPINFO_NUMBER(last_opcode_info)) {
532             case 0:
533                 /* In BRK, IRQ and NMI the 3rd, 4th and 5th cycles are write
534                    accesses, while the 1st, 2nd, 6th and 7th are read accesses.  */
535                 last_opcode_first_write_clk = maincpu_clk - 5;
536                 last_opcode_last_write_clk = maincpu_clk - 3;
537                 break;
538 
539             case 0x20:
540                 /* In JSR, the 4th and 5th cycles are write accesses, while the
541                    1st, 2nd, 3rd and 6th are read accesses.  */
542                 last_opcode_first_write_clk = maincpu_clk - 3;
543                 last_opcode_last_write_clk = maincpu_clk - 2;
544                 break;
545 
546             default:
547                 /* In all the other opcodes, all the write accesses are the last
548                    ones.  */
549                 if (maincpu_num_write_cycles() != 0) {
550                     last_opcode_last_write_clk = maincpu_clk - 1;
551                     last_opcode_first_write_clk = maincpu_clk
552                                                   - maincpu_num_write_cycles();
553                 } else {
554                     last_opcode_first_write_clk = (CLOCK)0;
555                     last_opcode_last_write_clk = last_opcode_first_write_clk;
556                 }
557                 break;
558         }
559     } else { /* offset <= 0, i.e. offset == 0 */
560         /* If we are called with no offset, we don't have to care about write
561            accesses.  */
562         last_opcode_first_write_clk = last_opcode_last_write_clk = 0;
563     }
564 
565     while (1) {
566         CLOCK sub;
567         CLOCK write_offset;
568         int leave;
569 
570         if (vicii.fetch_clk < last_opcode_first_write_clk || vicii.fetch_clk > last_opcode_last_write_clk) {
571             sub = 0;
572         } else {
573             sub = last_opcode_last_write_clk - vicii.fetch_clk + 1;
574         }
575 
576         switch (vicii.fetch_idx) {
577             case VICII_FETCH_MATRIX:
578                 leave = handle_fetch_matrix(offset, sub, &write_offset);
579                 last_opcode_first_write_clk += write_offset;
580                 last_opcode_last_write_clk += write_offset;
581                 break;
582 
583             case VICII_CHECK_SPRITE_DMA:
584                 leave = handle_check_sprite_dma(offset, sub);
585                 break;
586 
587             case VICII_FETCH_SPRITE:
588             default:              /* Make compiler happy.  */
589                 leave = handle_fetch_sprite(offset, sub, &write_offset);
590                 last_opcode_first_write_clk += write_offset;
591                 last_opcode_last_write_clk += write_offset;
592                 break;
593         }
594 
595         if (leave) {
596             break;
597         }
598     }
599 }
600 
vicii_fetch_init(void)601 void vicii_fetch_init(void)
602 {
603     vicii.raster_fetch_alarm = alarm_new(maincpu_alarm_context,
604                                          "VicIIRasterFetch",
605                                          vicii_fetch_alarm_handler, NULL);
606 }
607