Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
vic3.c
Go to the documentation of this file.
1 /* Test-case for simple, work-in-progress Commodore 65 emulator.
2  Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
3  Copyright (C)2016-2020 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
4 
5  This is the VIC3 "emulation". Currently it does scanline based rendering,
6  though sprites are totally incorrect and rendered "at-once" after the
7  frame (very ugly! no sprite bg priority, no other tricks etc). Other
8  limitations: no DAT emulation, hardware attributes works only in col-80
9  (normal) text mode, no screen pisitioning, no H1280 mode, no V400 and
10  interlace mode, no chrome killer, no X/Y scroll and 28/24 column mode
11  (VIC-II stuff), no border is emulated. Timing is totally bad, but hey,
12  VIC-III wouldn't be compatible too much with VIC-II either for the
13  exact timing, so ...
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 02111-1307 USA */
28 
29 #include "xemu/emutools.h"
30 #include "commodore_65.h"
31 #include "xemu/cpu65.h"
32 #include "vic3.h"
33 #include "xemu/f011_core.h"
34 
35 
36 
37 #define RGB(r,g,b) rgb_palette[((r) << 8) | ((g) << 4) | (b)]
38 #define COLMEMPTR (memory + 0x1F800)
39 #define IS_H640 (vic3_registers[0x31] & 0x80)
40 #define IS_BPM (vic3_registers[0x31] & 0x10)
41 #define BLINK_COUNTER_INIT 25
42 
43 #ifdef VIC_CACHE_COLOURS
44 #define VIC_REG_COLOUR(n) vic_reg_palette_cache[(n) - 0x20]
45 #else
46 #define VIC_REG_COLOUR(n) palette[vic3_registers[n]]
47 #endif
48 
49 
50 #ifdef VIC_CACHE_COLOURS
51 #warning "VIC_CACHE_COLOURS feature has not been implemented, yet!"
52 static Uint32 vic_reg_palette_cache[15];
53 #endif
54 static Uint32 rgb_palette[4096]; // all the C65 palette, 4096 colours (SDL pixel format related form)
55 static Uint32 vic3_palette[0x100]; // VIC3 palette in SDL pixel format related form (can be written into the texture directly to be rendered)
56 static Uint32 vic3_rom_palette[0x100]; // the "ROM" palette, for C64 colours (with some ticks, ie colours above 15 are the same as the "normal" programmable palette)
57 static Uint32 *palette; // the selected palette ...
58 static Uint8 vic3_palette_nibbles[0x300];
59 static Uint32 red_colour, black_colour;
61 Uint8 vic3_registers[0x80]; // VIC-3 registers. It seems $47 is the last register. But to allow address the full VIC3 reg I/O space, we use $80 here
62 int vic_new_mode; // VIC3 "newVic" IO mode is activated flag
63 static int scanline; // current scan line number
65 static int compare_raster; // raster compare (9 bits width) data
66 static int interrupt_status; // Interrupt status of VIC
67 static int blink_phase; // blinking attribute helper: on/off phase of blink
68 static int blink_counter; // blinking attribute helper: counter for blink_phase change
69 static Uint8 attributes; // hardware attribute mode ($F0 ON, $00 OFF). NOTE: currently implemented for normal text mode only, which is not so correct!
70 
71 // (SDL) target texture rendering pointers
72 static Uint32 *pixel; // pixel pointer to the rendering target (one pixel: 32 bit)
73 static Uint32 *pixel_end, *pixel_start; // points to the end and start of the buffer
74 
75 int frameskip; // if non-zero: frameskip mode, do NOT render the frame, but maintain scanline counter
76 static int video_counter; // video counter ("VC") 0...1000 or 0...2000 (in H640 mode) Currently only the BEGINNING of lines, as it's scanline based emulation ...
77 static int video_counter_inc; // 40 or 80 based on H640 bit
78 static int row_counter; // character row counter ("RC") 0...7 (0=badline)
79 static int vic2_bank_number = 0; // vic-2 bank number written by CIA
80 static void (*renderer_func)(void); // the selected scanline renderer, modified on mode register writes automatically
81 
82 // Pointers of VIC base addresses. Not always used in all modes, of course.
83 // They're updated on register writes. So we can save re-calculation addresses all the time
84 static Uint8 *vicptr_video_40; // pointer to video matrix, only used in !H640 modes
85 static Uint8 *vicptr_video_80; // pointer to video matrix, only used in H640 modes
86 static Uint8 *vicptr_chargen; // pointer to chargen, can even point into the ROM! Used only in text modes
87 static Uint8 *vicptr_bank16k; // pointer to VIC-II 16K bank start address
88 static Uint8 *vicptr_bank32k; // pointer to VIC-III 32K bank start address (only used for H640 bitmap mode)
89 static Uint8 *vicptr_bitmap_320; // pointer to bitmap data, only used in !H640 bitmap modes
90 static Uint8 *vicptr_bitmap_640; // pointer to bitmap data, only used in H640 bitmap modes (the only one which is calculated from 32K bank!)
91 static Uint8 *vicptr_idlefetch_p; // IDLE-fetch pointer
92 // For bitplanes we don't use pointers, since there are just too many sources (max of 8 bitplanes)
93 // Instead we use integer values, as linear memory addresses.
94 static int bitplane_addr_320[8];
95 static int bitplane_addr_640[8];
96 
97 static int warn_sprites = 0, warn_ctrl_b_lo = 1;
98 
100 
101 
102 
103 
105 {
106  int tail_sdl;
107  pixel = pixel_start = xemu_start_pixel_buffer_access(&tail_sdl);
108  pixel_end = pixel + (SCREEN_WIDTH * SCREEN_HEIGHT);
109  if (tail_sdl)
110  FATAL("tail_sdl is not zero!");
111 }
112 
113 
114 
115 
116 static void vic3_interrupt_checker ( void )
117 {
118  int vic_irq_old = cpu65.irqLevel & 2;
119  int vic_irq_new;
120  if ((interrupt_status & vic3_registers[0x1A])) {
121  interrupt_status |= 128;
122  vic_irq_new = 2;
123  } else {
124  interrupt_status &= 127;
125  vic_irq_new = 0;
126  }
127  if (vic_irq_old != vic_irq_new) {
128  DEBUG("VIC3: interrupt change %s -> %s" NL, vic_irq_old ? "active" : "inactive", vic_irq_new ? "active" : "inactive");
129  if (vic_irq_new)
130  cpu65.irqLevel |= 2;
131  else
132  cpu65.irqLevel &= ~2;
133  }
134 }
135 
136 
137 
139 {
140  if (scanline == compare_raster)
141  interrupt_status |= 1;
142  else
143  interrupt_status &= 0xFE;
144  vic3_interrupt_checker();
145 }
146 
147 
148 #define STATIC_COLOUR_RENDERER(colour, size) do { \
149  register int a = size; \
150  while (a--) \
151  *(pixel++) = colour; \
152 } while(0)
153 
154 
155 static void renderer_disabled_screen ( void )
156 {
158 }
159 
160 
161 static void renderer_invalid_mode ( void )
162 {
163  STATIC_COLOUR_RENDERER(rgb_palette[0], SCREEN_WIDTH); // invalid modes renders only blackness
164 }
165 
166 
167 
168 // FIXME: hardware attributes are supported now for only 40/80-col text mode!
169 // FIXME: for real, it's supported for everything, _even_ for bitplane mode .......... (surprisingly ...)
170 #define VIC3_ADJUST_BY_HARDWARE_ATTRIBUTES( has_attrib_condition, colour_var, vdata_var ) do { \
171  if (has_attrib_condition) { \
172  if ((colour_var & 0xF0) == 0x10) { /* only the blink bit for the character is set */ \
173  if (blink_phase) \
174  vdata_var = 0; /* blinking character, in one phase, the character "disappears", ie blinking */ \
175  colour_var &= 15; \
176  } else if ((!(colour_var & 0x10)) || blink_phase) { \
177  if ((colour_var & 0x80) && (row_counter == 7)) /* underline (must be before reverse, as underline can be reversed as well!) */ \
178  vdata_var = 0xFF; /* the underline */ \
179  if (colour_var & 0x20) /* reverse bit for char */ \
180  vdata_var ^= 0xFF; \
181  if (colour_var & 0x40) /* highlight, this must be the LAST, since it sets the low nibble of coldata ... */ \
182  colour_var = 0x10 | (colour_var & 15); \
183  else \
184  colour_var &= 15; \
185  } else \
186  colour_var &= 15; \
187  } else \
188  colour_var &= 15; \
189 } while (0)
190 
191 
192 
193 static void renderer_text_40 ( void )
194 {
195  Uint8 *vp = vicptr_video_40 + video_counter;
196  Uint8 *cp = COLMEMPTR + video_counter;
197  Uint8 *chargen = vicptr_chargen + row_counter;
198  Uint32 bg_colour = VIC_REG_COLOUR(0x21);
199  int a;
201  for (a = 0; a < 40; a++) {
202  Uint8 vdata = chargen[(*(vp++)) << 3];
203  Uint32 colour = *(cp++);
204  Uint32 fg_colour;
206  fg_colour = palette[colour];
207  pixel[ 0] = pixel[ 1] = vdata & 0x80 ? fg_colour : bg_colour;
208  pixel[ 2] = pixel[ 3] = vdata & 0x40 ? fg_colour : bg_colour;
209  pixel[ 4] = pixel[ 5] = vdata & 0x20 ? fg_colour : bg_colour;
210  pixel[ 6] = pixel[ 7] = vdata & 0x10 ? fg_colour : bg_colour;
211  pixel[ 8] = pixel[ 9] = vdata & 0x08 ? fg_colour : bg_colour;
212  pixel[10] = pixel[11] = vdata & 0x04 ? fg_colour : bg_colour;
213  pixel[12] = pixel[13] = vdata & 0x02 ? fg_colour : bg_colour;
214  pixel[14] = pixel[15] = vdata & 0x01 ? fg_colour : bg_colour;
215  pixel += 16;
216  }
218 }
219 
220 
221 static void renderer_text_80 ( void )
222 {
223  Uint8 *vp = vicptr_video_80 + video_counter;
224  Uint8 *cp = COLMEMPTR + video_counter;
225  Uint8 *chargen = vicptr_chargen + row_counter;
226  Uint32 bg_colour = VIC_REG_COLOUR(0x21);
227  int a;
229  for (a = 0; a < 80; a++) {
230  Uint8 vdata = chargen[(*(vp++)) << 3];
231  Uint8 colour = *(cp++);
232  Uint32 fg_colour;
234  fg_colour = palette[colour];
235  *(pixel++) = vdata & 0x80 ? fg_colour : bg_colour;
236  *(pixel++) = vdata & 0x40 ? fg_colour : bg_colour;
237  *(pixel++) = vdata & 0x20 ? fg_colour : bg_colour;
238  *(pixel++) = vdata & 0x10 ? fg_colour : bg_colour;
239  *(pixel++) = vdata & 0x08 ? fg_colour : bg_colour;
240  *(pixel++) = vdata & 0x04 ? fg_colour : bg_colour;
241  *(pixel++) = vdata & 0x02 ? fg_colour : bg_colour;
242  *(pixel++) = vdata & 0x01 ? fg_colour : bg_colour;
243  }
245 }
246 
247 
248 static void renderer_ecmtext_40 ( void )
249 {
250  Uint8 *vp = vicptr_video_40 + video_counter;
251  Uint8 *cp = COLMEMPTR + video_counter;
252  Uint8 *chargen = vicptr_chargen + row_counter;
253  Uint32 bg_colours[4] = {
254  VIC_REG_COLOUR(0x21),
255  VIC_REG_COLOUR(0x22),
256  VIC_REG_COLOUR(0x23),
257  VIC_REG_COLOUR(0x24)
258  };
259  int a;
261  for (a = 0; a < 40; a++) {
262  Uint8 vdata = *(vp++);
263  Uint8 data = chargen[(vdata & 63) << 3];
264  Uint32 fg_colour = palette[*(cp++) & 15];
265  vdata >>= 6;
266  pixel[ 0] = pixel[ 1] = data & 0x80 ? fg_colour : bg_colours[vdata];
267  pixel[ 2] = pixel[ 3] = data & 0x40 ? fg_colour : bg_colours[vdata];
268  pixel[ 4] = pixel[ 5] = data & 0x20 ? fg_colour : bg_colours[vdata];
269  pixel[ 6] = pixel[ 7] = data & 0x10 ? fg_colour : bg_colours[vdata];
270  pixel[ 8] = pixel[ 9] = data & 0x08 ? fg_colour : bg_colours[vdata];
271  pixel[10] = pixel[11] = data & 0x04 ? fg_colour : bg_colours[vdata];
272  pixel[12] = pixel[13] = data & 0x02 ? fg_colour : bg_colours[vdata];
273  pixel[14] = pixel[15] = data & 0x01 ? fg_colour : bg_colours[vdata];
274  pixel += 16;
275  }
277 }
278 
279 
280 static void renderer_ecmtext_80 ( void )
281 {
282  Uint8 *vp = vicptr_video_80 + video_counter;
283  Uint8 *cp = COLMEMPTR + video_counter;
284  Uint8 *chargen = vicptr_chargen + row_counter;
285  Uint32 bg_colours[4] = {
286  VIC_REG_COLOUR(0x21),
287  VIC_REG_COLOUR(0x22),
288  VIC_REG_COLOUR(0x23),
289  VIC_REG_COLOUR(0x24)
290  };
291  int a;
293  for (a = 0; a < 80; a++) {
294  Uint8 vdata = *(vp++);
295  Uint8 data = chargen[(vdata & 63) << 3];
296  Uint32 fg_colour = palette[*(cp++) & 15];
297  vdata >>= 6;
298  pixel[0] = data & 0x80 ? fg_colour : bg_colours[vdata];
299  pixel[1] = data & 0x40 ? fg_colour : bg_colours[vdata];
300  pixel[2] = data & 0x20 ? fg_colour : bg_colours[vdata];
301  pixel[3] = data & 0x10 ? fg_colour : bg_colours[vdata];
302  pixel[4] = data & 0x08 ? fg_colour : bg_colours[vdata];
303  pixel[5] = data & 0x04 ? fg_colour : bg_colours[vdata];
304  pixel[6] = data & 0x02 ? fg_colour : bg_colours[vdata];
305  pixel[7] = data & 0x01 ? fg_colour : bg_colours[vdata];
306  pixel += 8;
307  }
309 }
310 
311 
312 static void renderer_mcmtext_40 ( void )
313 {
314  Uint8 *vp = vicptr_video_40 + video_counter;
315  Uint8 *cp = COLMEMPTR + video_counter;
316  Uint8 *chargen = vicptr_chargen + row_counter;
317  Uint32 colours[4] = {
318  VIC_REG_COLOUR(0x21),
319  VIC_REG_COLOUR(0x22),
320  VIC_REG_COLOUR(0x23),
321  0 // to be filled during colour fetch ...
322  };
323  int a;
325  for (a = 0; a < 40; a++) {
326  Uint8 vdata = chargen[(*(vp++)) << 3];
327  Uint8 coldata = (*(cp++));
328  if (coldata & 8) {
329  // MCM character
330  colours[3] = palette[coldata & 7];
331  pixel[ 0] = pixel[ 1] = pixel[ 2] = pixel[ 3] = colours[ vdata >> 6 ];
332  pixel[ 4] = pixel[ 5] = pixel[ 6] = pixel[ 7] = colours[(vdata >> 4) & 3];
333  pixel[ 8] = pixel[ 9] = pixel[10] = pixel[11] = colours[(vdata >> 2) & 3];
334  pixel[12] = pixel[13] = pixel[14] = pixel[15] = colours[ vdata & 3];
335  } else {
336  // non-MCM character
337  colours[3] = palette[coldata & 7];
338  pixel[ 0] = pixel[ 1] = vdata & 0x80 ? colours[3] : colours[0];
339  pixel[ 2] = pixel[ 3] = vdata & 0x40 ? colours[3] : colours[0];
340  pixel[ 4] = pixel[ 5] = vdata & 0x20 ? colours[3] : colours[0];
341  pixel[ 6] = pixel[ 7] = vdata & 0x10 ? colours[3] : colours[0];
342  pixel[ 8] = pixel[ 9] = vdata & 0x08 ? colours[3] : colours[0];
343  pixel[10] = pixel[11] = vdata & 0x04 ? colours[3] : colours[0];
344  pixel[12] = pixel[13] = vdata & 0x02 ? colours[3] : colours[0];
345  pixel[14] = pixel[15] = vdata & 0x01 ? colours[3] : colours[0];
346  }
347  pixel += 16;
348  }
350 }
351 
352 
353 static void renderer_mcmtext_80 ( void )
354 {
355  Uint8 *vp = vicptr_video_80 + video_counter;
356  Uint8 *cp = COLMEMPTR + video_counter;
357  Uint8 *chargen = vicptr_chargen + row_counter;
358  Uint32 colours[4] = {
359  VIC_REG_COLOUR(0x21),
360  VIC_REG_COLOUR(0x22),
361  VIC_REG_COLOUR(0x23),
362  0 // to be filled during colour fetch ...
363  };
364  int a;
366  for (a = 0; a < 80; a++) {
367  Uint8 vdata = chargen[(*(vp++)) << 3];
368  Uint8 coldata = (*(cp++));
369  if (coldata & 8) {
370  // MCM character
371  colours[3] = palette[coldata & 7];
372  pixel[0] = pixel[1] = colours[ vdata >> 6 ];
373  pixel[2] = pixel[3] = colours[(vdata >> 4) & 3];
374  pixel[4] = pixel[5] = colours[(vdata >> 2) & 3];
375  pixel[6] = pixel[7] = colours[ vdata & 3];
376  } else {
377  // non-MCM character
378  colours[3] = palette[coldata & 7];
379  pixel[0] = vdata & 0x80 ? colours[3] : colours[0];
380  pixel[1] = vdata & 0x40 ? colours[3] : colours[0];
381  pixel[2] = vdata & 0x20 ? colours[3] : colours[0];
382  pixel[3] = vdata & 0x10 ? colours[3] : colours[0];
383  pixel[4] = vdata & 0x08 ? colours[3] : colours[0];
384  pixel[5] = vdata & 0x04 ? colours[3] : colours[0];
385  pixel[6] = vdata & 0x02 ? colours[3] : colours[0];
386  pixel[7] = vdata & 0x01 ? colours[3] : colours[0];
387  }
388  pixel += 8;
389  }
391 }
392 
393 
394 static void renderer_bitmap_320 ( void )
395 {
396  Uint8 *vp = vicptr_video_40 + video_counter;
397  Uint8 *bp = vicptr_bitmap_320 + (video_counter << 3) + row_counter;
398  int a;
400  for (a = 0; a < 40; a++) {
401  Uint8 data = *(vp++);
402  Uint32 fg_colour = palette[data >> 4];
403  Uint32 bg_colour = palette[data & 15];
404  data = *bp;
405  pixel[ 0] = pixel[ 1] = data & 0x80 ? fg_colour : bg_colour;
406  pixel[ 2] = pixel[ 3] = data & 0x40 ? fg_colour : bg_colour;
407  pixel[ 4] = pixel[ 5] = data & 0x20 ? fg_colour : bg_colour;
408  pixel[ 6] = pixel[ 7] = data & 0x10 ? fg_colour : bg_colour;
409  pixel[ 8] = pixel[ 9] = data & 0x08 ? fg_colour : bg_colour;
410  pixel[10] = pixel[11] = data & 0x04 ? fg_colour : bg_colour;
411  pixel[12] = pixel[13] = data & 0x02 ? fg_colour : bg_colour;
412  pixel[14] = pixel[15] = data & 0x01 ? fg_colour : bg_colour;
413  bp += 8;
414  pixel += 16;
415  }
417 }
418 
419 
420 static void renderer_bitmap_640 ( void )
421 {
422  Uint8 *vp = vicptr_video_80 + video_counter;
423  Uint8 *bp = vicptr_bitmap_640 + (video_counter << 3) + row_counter;
424  int a;
426  for (a = 0; a < 80; a++) {
427  Uint8 data = *(vp++);
428  Uint32 fg_colour = palette[data >> 4];
429  Uint32 bg_colour = palette[data & 15];
430  data = *bp;
431  pixel[0] = data & 0x80 ? fg_colour : bg_colour;
432  pixel[1] = data & 0x40 ? fg_colour : bg_colour;
433  pixel[2] = data & 0x20 ? fg_colour : bg_colour;
434  pixel[3] = data & 0x10 ? fg_colour : bg_colour;
435  pixel[4] = data & 0x08 ? fg_colour : bg_colour;
436  pixel[5] = data & 0x04 ? fg_colour : bg_colour;
437  pixel[6] = data & 0x02 ? fg_colour : bg_colour;
438  pixel[7] = data & 0x01 ? fg_colour : bg_colour;
439  bp += 8;
440  pixel += 8;
441  }
443 }
444 
445 
446 static void renderer_mcmbitmap_320 ( void )
447 {
448  Uint8 *vp = vicptr_video_40 + video_counter;
449  Uint8 *bp = vicptr_bitmap_320 + (video_counter << 3) + row_counter;
450  Uint8 *cp = COLMEMPTR + video_counter;
451  Uint32 colours[4];
452  int a;
453  colours[0] = VIC_REG_COLOUR(0x21);
455  for (a = 0; a < 40; a++) {
456  Uint8 data = *(vp++);
457  colours[1] = palette[data >> 4];
458  colours[2] = palette[data & 15];
459  colours[3] = palette[(*(cp++)) & 15];
460  data = *bp;
461  pixel[ 0] = pixel[ 1] = pixel[ 2] = pixel[ 3] = colours[ data >> 6 ];
462  pixel[ 4] = pixel[ 5] = pixel[ 6] = pixel[ 7] = colours[(data >> 4) & 3];
463  pixel[ 8] = pixel[ 9] = pixel[10] = pixel[11] = colours[(data >> 2) & 3];
464  pixel[12] = pixel[13] = pixel[14] = pixel[15] = colours[ data & 3];
465  bp += 8;
466  pixel += 16;
467  }
469 }
470 
471 
472 static void renderer_mcmbitmap_640 ( void )
473 {
474  Uint8 *vp = vicptr_video_80 + video_counter;
475  Uint8 *bp = vicptr_bitmap_640 + (video_counter << 3) + row_counter;
476  Uint8 *cp = COLMEMPTR + video_counter;
477  Uint32 colours[4];
478  int a;
479  colours[0] = VIC_REG_COLOUR(0x21);
481  for (a = 0; a < 80; a++) {
482  Uint8 data = *(vp++);
483  colours[1] = palette[data >> 4];
484  colours[2] = palette[data & 15];
485  colours[3] = palette[(*(cp++)) & 15];
486  data = *bp;
487  pixel[0] = pixel[1] = colours[ data >> 6 ];
488  pixel[2] = pixel[3] = colours[(data >> 4) & 3];
489  pixel[4] = pixel[5] = colours[(data >> 2) & 3];
490  pixel[6] = pixel[7] = colours[ data & 3];
491  bp += 8;
492  pixel += 8;
493  }
495 }
496 
497 
498 static void renderer_bitplane_320 ( void )
499 {
500  Uint8 *bp = memory + (video_counter << 3) + row_counter;
501  int a;
503  for (a = 0; a < 40; a++) {
504  int bitpos;
505  Uint8 fetch[8] = {
506  bp[bitplane_addr_320[0]], bp[bitplane_addr_320[1]], bp[bitplane_addr_320[2]], bp[bitplane_addr_320[3]],
507  bp[bitplane_addr_320[4]], bp[bitplane_addr_320[5]], bp[bitplane_addr_320[6]], bp[bitplane_addr_320[7]]
508  };
509  for (bitpos = 128; bitpos; bitpos >>= 1) {
510  // Do not try this at home ...
511  pixel[0] = pixel[1] = palette[((
512  ((fetch[0] & bitpos) ? 1 : 0) |
513  ((fetch[1] & bitpos) ? 2 : 0) |
514  ((fetch[2] & bitpos) ? 4 : 0) |
515  ((fetch[3] & bitpos) ? 8 : 0) |
516  ((fetch[4] & bitpos) ? 16 : 0) |
517  ((fetch[5] & bitpos) ? 32 : 0) |
518  ((fetch[6] & bitpos) ? 64 : 0) |
519  ((fetch[7] & bitpos) ? 128 : 0)
520  ) & vic3_registers[0x32]) ^ vic3_registers[0x3B]];
521  pixel += 2;
522  }
523  bp += 8;
524  }
526 }
527 
528 
529 static void renderer_bitplane_640 ( void )
530 {
531  Uint8 *bp = memory + (video_counter << 3) + row_counter;
532  int a, enable = vic3_registers[0x32] & 15; // in H640 bitplane modes, only lower 4 bitplanes can be used (TODO: is that true? check it!)
534  for (a = 0; a < 80; a++) {
535  int bitpos;
536  Uint8 fetch[8] = {
537  bp[bitplane_addr_640[0]], bp[bitplane_addr_640[1]], bp[bitplane_addr_640[2]], bp[bitplane_addr_640[3]],
538  bp[bitplane_addr_640[4]], bp[bitplane_addr_640[5]], bp[bitplane_addr_640[6]], bp[bitplane_addr_640[7]]
539  };
540  for (bitpos = 128; bitpos; bitpos >>= 1)
541  // Do not try this at home ...
542  *(pixel++) = palette[((
543  ((fetch[0] & bitpos) ? 1 : 0) |
544  ((fetch[1] & bitpos) ? 2 : 0) |
545  ((fetch[2] & bitpos) ? 4 : 0) |
546  ((fetch[3] & bitpos) ? 8 : 0) |
547  ((fetch[4] & bitpos) ? 16 : 0) |
548  ((fetch[5] & bitpos) ? 32 : 0) |
549  ((fetch[6] & bitpos) ? 64 : 0) |
550  ((fetch[7] & bitpos) ? 128 : 0)
551  ) & enable) ^ vic3_registers[0x3B]];
552  bp += 8;
553  }
555 }
556 
557 
558 
559 static void sprite_renderer ( void );
560 
561 
562 static inline void drive_led_renderer ( void )
563 {
565  for (int y = 0; y < 8; y++)
566  for (int x = 0; x < 8; x++)
567  *(pixel_start + (SCREEN_WIDTH) - 10 + x + (y + 2) * (SCREEN_WIDTH)) = x > 1 && x < 7 && y > 1 && y < 7 ? red_colour : black_colour;
568 }
569 
570 
572 {
573  if (scanline < 50 - TOP_BORDER_SIZE) {
574  scanline++;
575  return 0;
576  } else if (scanline < 50) {
577  if (!frameskip)
578  renderer_disabled_screen();
579  scanline++;
580  return 0;
581  } else if (scanline < 250) {
582  if (!frameskip) {
583  scanline_render_debug_info[scanline] = (((vic3_registers[0x11] & 0x60) | (vic3_registers[0x16] & 0x10)) >> 4) + 'a';
584  renderer_func(); // call the scanline renderer for the current video mode, a function pointer
585  if (row_counter == 7) {
586  row_counter = 0;
587  video_counter += video_counter_inc;
588  } else
589  row_counter++;
590  }
591  scanline++;
592  return 0;
593  } else if (scanline < 250 + BOTTOM_BORDER_SIZE) {
594  if (!frameskip)
595  renderer_disabled_screen();
596  scanline++;
597  return 0;
598  } else if (scanline == 311) {
599  scanline = 0;
600  video_counter = 0;
601  row_counter = 0;
602  if (blink_counter)
603  blink_counter--;
604  else {
605  blink_counter = BLINK_COUNTER_INIT;
606  blink_phase = ~blink_phase;
607  }
608  if (!frameskip) {
609  if (XEMU_UNLIKELY(pixel != pixel_end))
610  FATAL("Renderer failure: pixel=%p != end=%p (diff=%d) height=%d", pixel, pixel_end, (int)(pixel_end - pixel), SCREEN_HEIGHT);
611  // FIXME: Highly incorrect, rendering sprites once *AFTER* the screen content ...
612  sprite_renderer();
613  drive_led_renderer();
614  } else {
615  if (XEMU_UNLIKELY(pixel != pixel_start))
616  FATAL("Renderer failure: pixel=%p != start=%p", pixel, pixel_start);
617  }
618  return 1; // return value non-zero: end-of-frame, emulator should update the SDL rendering context, then call vic3_open_frame_access()
619  }
620  // else ...
621  scanline++;
622  return 0;
623 }
624 
625 
626 
627 // write register functions should call this on any register change which may affect display mode with settings already stored in vic3_registers[]!
628 static void select_renderer_func ( void )
629 {
630  // Ugly, but I really don't have idea what happens in VIC-III internally when you
631  // switch H640 bit within a frame ... Currently I just limit video counter to be
632  // within 1K if H640 is not set. That's certainly incorrect, but it should be tested
633  // on a real C65 what happens (eg in text mode) if H640 bit is flipped at the middle
634  // of a screen.
635  // Also FIXME: where are the sprites in bitplane mode?!
636  if (!IS_H640) {
637  video_counter &= 1023;
638  video_counter_inc = 40;
639  } else {
640  video_counter_inc = 80;
641  }
642  // if DEN (Display Enable) bit is zero, then you won't see anything (border colour is rendered!)
643  if (!(vic3_registers[0x11] & 0x10)) {
644  renderer_func = renderer_disabled_screen;
645  return;
646  }
647  // if BPM bit is set, it's bitplane mode (VIC-III)
648  if (IS_BPM) {
649  renderer_func = IS_H640 ? renderer_bitplane_640 : renderer_bitplane_320;
650  return;
651  }
652  // Otherwise, classic VIC-II modes, select one, from the possible 8 modes (note: some of them are INVALID!)
653  // the pattern: ECM - BMM - MCM
654  switch (((vic3_registers[0x11] & 0x60) | (vic3_registers[0x16] & 0x10)) >> 4) {
655  case 0: // Standard text mode (ECM/BMM/MCM=0/0/0)
656  renderer_func = IS_H640 ? renderer_text_80 : renderer_text_40;
657  break;
658  case 1: // Multicolor text mode (ECM/BMM/MCM=0/0/1)
659  renderer_func = IS_H640 ? renderer_mcmtext_80 : renderer_mcmtext_40;
660  break;
661  case 2: // Standard bitmap mode (ECM/BMM/MCM=0/1/0)
662  renderer_func = IS_H640 ? renderer_bitmap_640 : renderer_bitmap_320;
663  break;
664  case 3: // Multicolor bitmap mode (ECM/BMM/MCM=0/1/1)
665  renderer_func = IS_H640 ? renderer_mcmbitmap_640 : renderer_mcmbitmap_320;
666  break;
667  case 4: // ECM text mode (ECM/BMM/MCM=1/0/0)
668  renderer_func = IS_H640 ? renderer_ecmtext_80 : renderer_ecmtext_40;
669  break;
670  case 5: // Invalid text mode (ECM/BMM/MCM=1/0/1)
671  case 6: // Invalid bitmap mode 1 (ECM/BMM/MCM=1/1/0)
672  case 7: // Invalid bitmap mode 2 (ECM/BMM/MCM=1/1/1)
673  // Invalid modes generate only "blackness"
674  renderer_func = renderer_invalid_mode;
675  break;
676  }
677 }
678 
679 
680 // Must be called if register 0x18 is written, or bank set, or CROM VIC-III setting changed
681 static void select_chargen ( void )
682 {
683  // TODO: incorrect implementation. Currently we handle the situation of "char ROM" in certain banks
684  // only for character generator info. That's not so correct, as VIC always see that memory in those
685  // banks not only for chargen info! However, it's much easier and faster to do this way ...
686  if ((!(vic2_bank_number & 1)) && ((vic3_registers[0x18] & 0x0C) == 4)) {
687  // FIXME: I am really lost with this CROM bit, and the layout of C65 ROM on charsets, sorry. Maybe this is totally wrong!
688  // The problem, for my eye, the two charsets (C64/C65?!) seems to be the very same :-/
689  // BUT, it seems, C65 mode *SETS* CROM bit. While for C64 mode it is CLEARED.
690  if (vic3_registers[0x30] & 64) // the CROM bit
691  vicptr_chargen = memory + 0x29000 + ((vic3_registers[0x18] & 0x0E) << 10) - 0x1000; // ... so this should be the C65 charset ...
692  else
693  vicptr_chargen = memory + 0x2D000 + ((vic3_registers[0x18] & 0x0E) << 10) - 0x1000; // ... and this should be the C64
694  } else
695  vicptr_chargen = vicptr_bank16k + ((vic3_registers[0x18] & 0x0E) << 10); // otherwise, chargen is in RAM
696 }
697 
698 
699 
700 // Must be called if any memory ptr is changed (not the bitplane related of VIC-III though!)
701 // Also, if VIC-II bank is changed (that's done by vic3_select_bank function)
702 static void select_vic2_memory ( void )
703 {
704  // 24| $d018 |VM13|VM12|VM11|VM10|CB13|CB12|CB11| - | Memory pointers
705  vicptr_video_40 = vicptr_bank16k + ((vic3_registers[0x18] & 0xF0) << 6);
706  vicptr_video_80 = vicptr_bank16k + ((vic3_registers[0x18] & 0xE0) << 6);
707  //sprite_pointers = IS_H640 ? vicptr_video_80 + 0x7F8 : vicptr_video_40 + 0x3F8;
708  select_chargen();
709  vicptr_bitmap_320 = vicptr_bank16k + ((vic3_registers[0x18] & 8) << 10);
710  // Interestingly, VIC-III has a notion of "32K sized bank" as well, over VIC-II but
711  // used only for H640 bit set with bitmap modes (the video matrix is still fetched
712  // from the 16K bank though). There is no other reason for the bank, other VIC-II
713  // modes use 16K bank and VIC-III bitplanes don't use the bank notion at all.
714  vicptr_bitmap_640 = vicptr_bank32k + ((vic3_registers[0x18] & 8) << 11);
715 }
716 
717 
718 // Called by the emulator on VIC bank selection
719 // Parameter must be in range of 0-3, with 0 meaning the lowest addressed bank
720 void vic3_select_bank ( int bank )
721 {
722  bank &= 3;
723  // to avoid of pointer rebuilding on all writes, we do this only, if bank is changed
724  if (bank != vic2_bank_number) {
725  vic2_bank_number = bank;
726  bank <<= 14;
727  vicptr_bank16k = memory + bank;
728  vicptr_idlefetch_p = vicptr_bank16k + 0x3FFF;
729  vicptr_bank32k = memory + (bank & 0x8000); // VIC-III also has 32K VIC bank if H640 is used with bitmap mode
730  select_vic2_memory();
731  }
732 }
733 
734 
735 static XEMU_INLINE int get_dat_addr ( int bpn )
736 {
737  int x = vic3_registers[0x3C];
738  int y = vic3_registers[0x3D] + ((x << 1) & 0x100);
739  x &= 0x7F;
740  return (x << 3) + (y & 7) + (IS_H640 ? bitplane_addr_640[bpn] + (y >> 3) * 640 : bitplane_addr_320[bpn] + (y >> 3) * 320);
741 }
742 
743 
744 // Caller should give only 0-$3F or 0-$7F addresses
746 {
747  DEBUG("VIC3: write reg $%02X with data $%02X" NL, addr, data);
748  if (addr == 0x2F) {
749  if (!vic_new_mode && data == 0x96 && vic3_registers[0x2F] == 0xA5) {
751  DEBUG("VIC3: switched into NEW I/O access mode :)" NL);
752  } else if (vic_new_mode) {
753  vic_new_mode = 0;
754  DEBUG("VIC3: switched into OLD I/O access mode :(" NL);
755  }
756  }
757  if (!vic_new_mode && addr > 0x2F) {
758  DEBUG("VIC3: ignoring writing register $%02X (with data $%02X) because of old I/O access mode selected" NL, addr, data);
759  return;
760  }
761  switch (addr) {
762  case 0x11:
763  vic3_registers[0x11] = data;
764  select_renderer_func();
765  compare_raster = (compare_raster & 0xFF) | ((data & 0x80) << 1);
766  DEBUG("VIC3: compare raster is now %d" NL, compare_raster);
767  break;
768  case 0x12:
769  compare_raster = (compare_raster & 0xFF00) | data;
770  DEBUG("VIC3: compare raster is now %d" NL, compare_raster);
771  break;
772  case 0x16:
773  vic3_registers[0x16] = data;
774  select_renderer_func();
775  break;
776  case 0x18:
777  vic3_registers[0x18] = data;
778  select_vic2_memory();
779  break;
780  case 0x19:
781  interrupt_status = interrupt_status & (~data) & 15;
782  vic3_interrupt_checker();
783  break;
784  case 0x1A:
785  data &= 15;
786  break;
787  case 0x30:
788  // Save some un-needed memory translating table rebuilds, if there is important bits (for us) changed.
789  // CRAM@DC00 is not handled by the translator directly, so bit0 does not apply here!
790  if (
791  (data & 0xB8) != (vic3_registers[0x30] & 0xB8)
792  ) {
793  DEBUG("MEM: applying new memory configuration because of VIC3 $30 is written" NL);
794  vic3_registers[0x30] = data; // early write because of apply_memory_config() needs it
796  } else {
797  vic3_registers[0x30] = data; // we need this for select_chargen() below
798  DEBUG("MEM: no need for new memory configuration (because of VIC3 $30 is written): same ROM bit values are set" NL);
799  }
800  select_chargen();
801  palette = (data & 4) ? vic3_palette : vic3_rom_palette;
802  break;
803  case 0x31:
804  vic3_registers[0x31] = data;
805  attributes = (data & 32) ? 0xF0 : 0x00; // currently, I use $F0 for on, 00 off, to be able to use as an attrib mask directly for upper 4 bits
806  select_renderer_func();
807  if ((data & 64)) {
809  cpu65_set_timing(1);
810  strcpy(emulator_speed_title, "3.5MHz");
811  } else {
813  cpu65_set_timing(0);
814  strcpy(emulator_speed_title, "1MHz");
815  }
816  if ((data & 15) && warn_ctrl_b_lo) {
817  INFO_WINDOW("VIC3 control-B register V400, H1280, MONO and INT features are not emulated yet!\nThere will be no further warnings on this issue.");
818  warn_ctrl_b_lo = 0;
819  }
820  break;
821  case 0x33:
822  case 0x34:
823  case 0x35:
824  case 0x36:
825  case 0x37:
826  case 0x38:
827  case 0x39:
828  case 0x3A:
829  bitplane_addr_320[addr - 0x33] = ((data & 14) << 12) + (addr & 1 ? 0 : 0x10000);
830  bitplane_addr_640[addr - 0x33] = ((data & 12) << 12) + (addr & 1 ? 0 : 0x10000);
831  break;
832  case 0x40:
833  case 0x41:
834  case 0x42:
835  case 0x43:
836  case 0x44:
837  case 0x45:
838  case 0x46:
839  case 0x47:
840  // Write data through VIC-III DAT
841  memory[get_dat_addr(addr - 0x40)] = data;
842  break;
843  default:
844  if (addr >= 0x20 && addr < 0x2F)
845  data &= 15;
846  break;
847  }
849 }
850 
851 
852 
853 // Caller should give only 0-$3F or 0-$7F addresses
855 {
856  Uint8 result;
857  if (!vic_new_mode && addr > 0x2F) {
858  DEBUG("VIC3: ignoring reading register $%02X because of old I/O access mode selected, answer is $FF" NL, addr);
859  return 0xFF;
860  }
861  switch (addr) {
862  case 0x11:
863  result = (vic3_registers[0x11] & 0x7F) | ((scanline >> 1) & 0x80);
864  break;
865  case 0x12:
866  result = scanline & 0xFF;
867  break;
868  case 0x16:
869  result = vic3_registers[addr] | (128 + 64); // unused bits [TODO: also on VIC3?]
870  break;
871  case 0x19:
872  result = interrupt_status | (64 + 32 + 16); // unused bits [TODO: also on VIC3?]
873  break;
874  case 0x1A:
875  result = vic3_registers[addr] | 0xF0; // unused bits [TODO: also on VIC3?]
876  break;
877  case 0x18:
878  result = vic3_registers[addr] | 1; // unused bit [TODO: also on VIC3?]
879  break;
880  case 0x40:
881  case 0x41:
882  case 0x42:
883  case 0x43:
884  case 0x44:
885  case 0x45:
886  case 0x46:
887  case 0x47:
888  // Read data through VIC-III DAT
889  result = memory[get_dat_addr(addr - 0x40)];
890  break;
891  default:
892  result = vic3_registers[addr];
893  if (addr >= 0x20 && addr < 0x2F)
894  result |= 0xF0; // unused bits [TODO: also on VIC3?]
895  break;
896  }
897  DEBUG("VIC3: read reg $%02X with result $%02X" NL, addr, result);
898  return result;
899 }
900 
901 
902 
903 
904 
905 // "num" is 0-$ff for red, $100-$1ff for green and $200-$2ff for blue nibbles
907 {
908  vic3_palette_nibbles[num] = data & 15;
909  // recalculate the given RGB entry based on the new data as well
910  vic3_palette[num & 0xFF] = RGB(
911  vic3_palette_nibbles[ num & 0xFF],
912  vic3_palette_nibbles[(num & 0xFF) | 0x100],
913  vic3_palette_nibbles[(num & 0xFF) | 0x200]
914  );
915  // Also, update the "ROM based" palette struct, BUT only colours above 15,
916  // since the lower 16 are "ROM based"! This is only a trick to be able
917  // to have full 256 colours for ROMPAL sel and without that too!
918  // The low 16 colours are the one which are ROM based for real, that's why
919  // we don't want to update them here!
920  if ((num & 0xF0))
921  vic3_rom_palette[num & 0xFF] = vic3_palette[num & 0xFF];
922 }
923 
924 
925 
926 void vic3_init ( void )
927 {
928  int r, g, b, i;
929  // *** Init 4096 element palette with RGB components for faster access later on palette register changes (avoid SDL calls to convert)
930  for (r = 0, i = 0; r < 16; r++)
931  for (g = 0; g < 16; g++)
932  for (b = 0; b < 16; b++)
933  rgb_palette[i++] = SDL_MapRGBA(sdl_pix_fmt, r * 17, g * 17, b * 17, 0xFF); // 15*17=255, last arg 0xFF: alpha channel for SDL
934  red_colour = SDL_MapRGBA(sdl_pix_fmt, 0xFF, 0x00, 0x00, 0xFF);
935  black_colour = SDL_MapRGBA(sdl_pix_fmt, 0x00, 0x00, 0x00, 0xFF);
936  // *** Init VIC3 registers and palette
939  vic_new_mode = 0;
940  blink_counter = 0;
941  blink_phase = 0;
942  attributes = 0;
943  interrupt_status = 0;
944  palette = vic3_rom_palette;
945  frameskip = 0;
946  scanline = 0;
947  compare_raster = 0;
949  strcpy(emulator_speed_title, "3.5MHz");
950  video_counter = 0;
951  row_counter = 0;
952  for (i = 0; i < 0x100; i++) { // Initialize all palette registers to zero, initially, to have something ...
953  if (i < sizeof vic3_registers)
954  vic3_registers[i] = 0; // Also the VIC3 registers ...
955  vic3_rom_palette[i] = vic3_palette[i] = rgb_palette[0];
956  vic3_palette_nibbles[i] = 0;
957  vic3_palette_nibbles[i + 0x100] = 0;
958  vic3_palette_nibbles[i + 0x200] = 0;
959  }
960  // *** the ROM palette "fixed" colours
961  vic3_rom_palette[ 0] = RGB( 0, 0, 0); // black
962  vic3_rom_palette[ 1] = RGB(15, 15, 15); // white
963  vic3_rom_palette[ 2] = RGB(15, 0, 0); // red
964  vic3_rom_palette[ 3] = RGB( 0, 15, 15); // cyan
965  vic3_rom_palette[ 4] = RGB(15, 0, 15); // magenta
966  vic3_rom_palette[ 5] = RGB( 0, 15, 0); // green
967  vic3_rom_palette[ 6] = RGB( 0, 0, 15); // blue
968  vic3_rom_palette[ 7] = RGB(15, 15, 0); // yellow
969  vic3_rom_palette[ 8] = RGB(15, 6, 0); // orange
970  vic3_rom_palette[ 9] = RGB(10, 4, 0); // brown
971  vic3_rom_palette[10] = RGB(15, 7, 7); // pink
972  vic3_rom_palette[11] = RGB( 5, 5, 5); // dark grey
973  vic3_rom_palette[12] = RGB( 8, 8, 8); // medium grey
974  vic3_rom_palette[13] = RGB( 9, 15, 9); // light green
975  vic3_rom_palette[14] = RGB( 9, 9, 15); // light blue
976  vic3_rom_palette[15] = RGB(11, 11, 11); // light grey
977  // bitplanes
978  bitplane_addr_320[0] = bitplane_addr_320[2] = bitplane_addr_320[4] = bitplane_addr_320[6] =
979  bitplane_addr_640[0] = bitplane_addr_640[2] = bitplane_addr_640[4] = bitplane_addr_640[6] = 0;
980  bitplane_addr_320[1] = bitplane_addr_320[3] = bitplane_addr_320[5] = bitplane_addr_320[7] =
981  bitplane_addr_640[1] = bitplane_addr_640[3] = bitplane_addr_640[5] = bitplane_addr_640[7] = 0x10000;
982  // To force bank selection, and pointer re-calculations
983  vic2_bank_number = -1; // invalid, faked one, so vic3_select_bank() will surely not use the "cached" result initially
984  vic3_select_bank(0);
985  // To force select _some_ renderer
986  select_renderer_func();
987  DEBUG("VIC3: has been initialized." NL);
988 }
989 
990 
991 #define SPRITE_X_START_SCREEN 24
992 #define SPRITE_Y_START_SCREEN 50
993 
994 
995 /* Extremely incorrect sprite emulation! BUGS:
996  * Sprites cannot be behind the background (sprite priority)
997  * No sprite-background collision detection
998  * No sprite-sprite collision detection
999  * This is a simple, after-the-rendered-frame render-sprites one-by-one algorithm
1000  * Very ugly, quick&dirty hack, not so optimal either, even without the other mentioned bugs ...
1001 */
1002 static void render_one_sprite ( int sprite_no, int sprite_mask, Uint8 *data, Uint32 *p )
1003 {
1004  Uint32 colours[4];
1005  int sprite_y = vic3_registers[sprite_no * 2 + 1] - SPRITE_Y_START_SCREEN;
1006  int sprite_x = ((vic3_registers[sprite_no * 2] | ((vic3_registers[16] & sprite_mask) ? 0x100 : 0)) - SPRITE_X_START_SCREEN) * 2;
1007  int expand_x = vic3_registers[29] & sprite_mask;
1008  int expand_y = vic3_registers[23] & sprite_mask;
1009  int lim_y = sprite_y + ((expand_y) ? 42 : 21);
1010  int mcm = vic3_registers[0x1C] & sprite_mask;
1011  int y;
1012  colours[2] = VIC_REG_COLOUR(39 + sprite_no);
1013  if (mcm) {
1014  colours[0] = 0; // transparent, not a real colour, just signaling of transparency
1015  colours[1] = VIC_REG_COLOUR(0x25);
1016  colours[3] = VIC_REG_COLOUR(0x26);
1017  }
1018  p += SCREEN_WIDTH * (sprite_y + TOP_BORDER_SIZE) + LEFT_BORDER_SIZE;
1019  for (y = sprite_y; y < lim_y; y += (expand_y ? 2 : 1), p += SCREEN_WIDTH * (expand_y ? 2 : 1))
1020  if (y < 0 || y >= 200)
1021  data += 3; // skip one line (three bytes) of sprite data if outside of screen
1022  else {
1023  int mask, a, x = sprite_x;
1024  for (a = 0; a < 3; a++) {
1025  if (mcm) {
1026  for (mask = 6; mask >=0; mask -= 2) {
1027  Uint32 col = colours[(*data >> mask) & 3];
1028  if (col) {
1029  if (x >= 0 && x < 640) {
1030  p[x] = p[x + 1] = p[x + 2] = p[x + 3] = col;
1031  if (expand_y && y < 200)
1032  p[x + SCREEN_WIDTH] = p[x + SCREEN_WIDTH + 1] = p[x + SCREEN_WIDTH + 2] = p[x + SCREEN_WIDTH + 3] = col;
1033  }
1034  x += 4;
1035  if (expand_x && x >= 0 && x < 640) {
1036  p[x] = p[x + 1] = p[x + 2] = p[x + 3] = col;
1037  if (expand_y && y < 200)
1038  p[x + SCREEN_WIDTH] = p[x + SCREEN_WIDTH + 1] = p[x + SCREEN_WIDTH + 2] = p[x + SCREEN_WIDTH + 3] = col;
1039  x += 4;
1040  }
1041  } else
1042  x += expand_x ? 8 : 4;
1043  }
1044  } else {
1045  for (mask = 128; mask; mask >>= 1) {
1046  if (*data & mask) {
1047  if (x >= 0 && x < 640) {
1048  p[x] = p[x + 1] = colours[2];
1049  if (expand_y && y < 200)
1050  p[x + SCREEN_WIDTH] = p[x + SCREEN_WIDTH + 1] = colours[2];
1051  }
1052  x += 2;
1053  if (expand_x && x >= 0 && x < 640) {
1054  p[x] = p[x + 1] = colours[2];
1055  if (expand_y && y < 200)
1056  p[x + SCREEN_WIDTH] = p[x + SCREEN_WIDTH + 1] = colours[2];
1057  x += 2;
1058  }
1059  } else
1060  x += expand_x ? 4 : 2;
1061  }
1062  }
1063  data++;
1064  }
1065  }
1066 }
1067 
1068 
1069 
1070 
1071 /* This is the one-frame-at-once (highly incorrect implementation, that is)
1072  renderer for sprites. */
1073 static void sprite_renderer ( void )
1074 {
1075 #if 0
1076  // DEBUG code for K2 demo!!!
1077  static const char search_this[] = "SYMMEK";
1078  for (int a = 0; a < 128000; a++) {
1079  int d1 = memory[a + 0] - search_this[5];
1080  int d2 = memory[a + 1] - search_this[4];
1081  int d3 = memory[a + 2] - search_this[3];
1082  int d4 = memory[a + 3] - search_this[2];
1083  int d5 = memory[a + 4] - search_this[1];
1084  int d6 = memory[a + 5] - search_this[0];
1085  if (d1 == d2 && d2 == d3 && d3 == d4 && d4 == d5 && d5 == d6) {
1086  DEBUGPRINT("YAY-FOUND: $%05X first-char: $%02X D018=$%02X D031=$%02X" NL, a, memory[a], vic3_registers[0x18], vic3_registers[0x31]);
1087  }
1088  }
1089 #endif
1090 
1091  int sprites_enabled = vic3_registers[0x15];
1092  if (sprites_enabled) { // Render sprites. VERY BAD. We ignore sprite priority as well (cannot be behind the background)
1093  if (warn_sprites) {
1094  INFO_WINDOW("WARNING: Sprite emulation is really bad! (enabled_mask=$%02X)", sprites_enabled);
1095  warn_sprites = 0;
1096  }
1097  Uint8 *sprite_bank, *sprite_pointers;
1098  // IT *SEEMS* (must be confirmed yet) that in bitplane mode (BPM) the sprite pointers are always
1099  // (regardless of H640 bit) at end of the 2K video matrix (even that video matrix is not used in BPM ...)
1100  if (IS_H640) {
1101  if (IS_BPM) {
1102  sprite_pointers = memory + bitplane_addr_640[2] + 0x4000 - 8;
1103  sprite_bank = memory;
1104  } else {
1105  sprite_pointers = vicptr_video_80 + 0x7F8;
1106  sprite_bank = vicptr_bank16k;
1107  }
1108  } else {
1109  if (IS_BPM) {
1110  sprite_pointers = memory + bitplane_addr_320[2] + 0x2000 - 8;
1111  sprite_bank = memory;
1112  } else {
1113  sprite_pointers = vicptr_video_40 + 0x3F8;
1114  sprite_bank = vicptr_bank16k;
1115  }
1116  }
1117  if (IS_BPM) {
1118  // I am really not sure if it's true for bitplane mode ... Just for testing, overriding the things above if bitplane mode is used
1119  sprite_pointers = memory + 0x07f8; // I would guess $107f8 or $10ff8
1120  sprite_bank = memory;
1121  }
1122 #if 0
1123  // TEST ONLY: BEGIN
1124  // DEBUG code
1125  DEBUGPRINT("YAY-FOUND: sprite pointers are: %02X %02X %02X %02X %02X %02X %02X %02X" NL,
1126  sprite_pointers[0],
1127  sprite_pointers[1],
1128  sprite_pointers[2],
1129  sprite_pointers[3],
1130  sprite_pointers[4],
1131  sprite_pointers[5],
1132  sprite_pointers[6],
1133  sprite_pointers[7]
1134  );
1135  // TEST ONLY: END
1136 #endif
1137  for (int a = 7; a >= 0; a--) {
1138  int mask = 1 << a;
1139  if ((sprites_enabled & mask))
1140  render_one_sprite(a, mask, sprite_bank + (sprite_pointers[a] << 6), pixel_start); // sprite_pointers are set by the renderer functions above!
1141  }
1142  }
1143 }
1144 
1145 
1146 /* --- SNAPSHOT RELATED --- */
1147 
1148 
1149 #ifdef XEMU_SNAPSHOT_SUPPORT
1150 
1151 #include <string.h>
1152 
1153 #define SNAPSHOT_VIC3_BLOCK_VERSION 0
1154 #define SNAPSHOT_VIC3_BLOCK_SIZE 0x400
1155 
1156 int vic3_snapshot_load_state ( const struct xemu_snapshot_definition_st *def, struct xemu_snapshot_block_st *block )
1157 {
1158  Uint8 buffer[SNAPSHOT_VIC3_BLOCK_SIZE];
1159  int a;
1160  if (block->block_version != SNAPSHOT_VIC3_BLOCK_VERSION || block->sub_counter || block->sub_size != sizeof buffer)
1161  RETURN_XSNAPERR_USER("Bad VIC3 block syntax");
1162  a = xemusnap_read_file(buffer, sizeof buffer);
1163  if (a) return a;
1164  /* loading state ... */
1165  for (a = 0; a < 0x80; a++) {
1167  vic3_write_reg(a, buffer[a + 0x80]);
1168  }
1169  for (a = 0; a < 0x300; a++)
1170  vic3_write_palette_reg(a, buffer[a + 0x100]);
1171  vic_new_mode = buffer[128];
1172  interrupt_status = (int)P_AS_BE32(buffer + 129);
1173  return 0;
1174 }
1175 
1176 
1177 int vic3_snapshot_save_state ( const struct xemu_snapshot_definition_st *def )
1178 {
1179  Uint8 buffer[SNAPSHOT_VIC3_BLOCK_SIZE];
1180  int a = xemusnap_write_block_header(def->idstr, SNAPSHOT_VIC3_BLOCK_VERSION);
1181  if (a) return a;
1182  memset(buffer, 0xFF, sizeof buffer);
1183  /* saving state ... */
1184  memcpy(buffer + 0x80, vic3_registers, 0x80); // $80 bytes
1185  memcpy(buffer + 0x100, vic3_palette_nibbles, 0x300); // $300 bytes
1186  buffer[128] = vic_new_mode;
1187  U32_AS_BE(buffer + 129, interrupt_status);
1188  return xemusnap_write_sub_block(buffer, sizeof buffer);
1189 }
1190 
1191 #endif
show_drive_led
int show_drive_led
Definition: vic3.c:60
LEFT_BORDER_SIZE
#define LEFT_BORDER_SIZE
Definition: vic3.h:24
VIC_REG_COLOUR
#define VIC_REG_COLOUR(n)
Definition: vic3.c:46
SLOW_CPU_CYCLES_PER_SCANLINE
#define SLOW_CPU_CYCLES_PER_SCANLINE
Definition: commodore_65.h:30
emutools.h
f011_core.h
FAST_CPU_CYCLES_PER_SCANLINE
#define FAST_CPU_CYCLES_PER_SCANLINE
Definition: commodore_65.h:29
RIGHT_BORDER_SIZE
#define RIGHT_BORDER_SIZE
Definition: vic3.h:25
vic3.h
cpu_cycles_per_scanline
int cpu_cycles_per_scanline
Definition: vic3.c:64
COLMEMPTR
#define COLMEMPTR
Definition: vic3.c:38
SCREEN_WIDTH
#define SCREEN_WIDTH
Definition: vic3.h:29
colour
Uint32 colour
Definition: vera.c:67
vic3_init
void vic3_init(void)
Definition: vic3.c:926
BOTTOM_BORDER_SIZE
#define BOTTOM_BORDER_SIZE
Definition: vic3.h:27
INFO_WINDOW
#define INFO_WINDOW(...)
Definition: xep128.h:114
addr
int addr
Definition: dma65.c:81
sdl_pix_fmt
SDL_PixelFormat * sdl_pix_fmt
Definition: emutools.c:80
BLINK_COUNTER_INIT
#define BLINK_COUNTER_INIT
Definition: vic3.c:41
IS_H640
#define IS_H640
Definition: vic3.c:39
XEMU_INLINE
#define XEMU_INLINE
Definition: emutools_basicdefs.h:126
m65-memcontent-generator.data
data
Definition: m65-memcontent-generator.py:119
Uint32
uint32_t Uint32
Definition: fat32.c:49
Uint8
uint8_t Uint8
Definition: fat32.c:51
block
Uint32 block
Definition: fat32.c:156
x
int x
Definition: console.c:27
vic3_write_palette_reg
void vic3_write_palette_reg(int num, Uint8 data)
Definition: vic3.c:906
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
SPRITE_X_START_SCREEN
#define SPRITE_X_START_SCREEN
Definition: vic3.c:991
vic3_registers
Uint8 vic3_registers[0x80]
Definition: vic3.c:61
xemu_start_pixel_buffer_access
Uint32 * xemu_start_pixel_buffer_access(int *texture_tail)
Definition: emutools.c:1153
fdc_get_led_state
int fdc_get_led_state(int blink_inc)
Definition: f011_core.c:161
IS_BPM
#define IS_BPM
Definition: vic3.c:40
vic_new_mode
int vic_new_mode
Definition: vic3.c:62
NL
#define NL
Definition: fat32.c:37
vic3_render_scanline
int vic3_render_scanline(void)
Definition: vic3.c:571
compress_sd_image.r
def r
Definition: compress_sd_image.py:76
commodore_65.h
TOP_BORDER_SIZE
#define TOP_BORDER_SIZE
Definition: vic3.h:26
memory
Uint8 memory[0x100000]
Definition: commodore_65.c:43
emulator_speed_title
char emulator_speed_title[]
Definition: commodore_65.c:78
VIC3_ADJUST_BY_HARDWARE_ATTRIBUTES
#define VIC3_ADJUST_BY_HARDWARE_ATTRIBUTES(has_attrib_condition, colour_var, vdata_var)
Definition: vic3.c:170
cpu65.h
STATIC_COLOUR_RENDERER
#define STATIC_COLOUR_RENDERER(colour, size)
Definition: vic3.c:148
apply_memory_config
void apply_memory_config(void)
Definition: commodore_65.c:94
vic3_read_reg
Uint8 vic3_read_reg(int addr)
Definition: vic3.c:854
vic3_select_bank
void vic3_select_bank(int bank)
Definition: vic3.c:720
SCREEN_HEIGHT
#define SCREEN_HEIGHT
Definition: vic3.h:30
colours
Uint32 colours[0x100]
Definition: vera.c:83
y
int y
Definition: console.c:27
VIC_NEW_MODE
#define VIC_NEW_MODE
Definition: vic3.h:22
RGB
#define RGB(r, g, b)
Definition: vic3.c:37
mask
int mask
Definition: dma65.c:83
vic3_open_frame_access
void vic3_open_frame_access(void)
Definition: vic3.c:104
SPRITE_Y_START_SCREEN
#define SPRITE_Y_START_SCREEN
Definition: vic3.c:992
row_counter
int row_counter
Definition: dma65.c:90
DEBUG
#define DEBUG(...)
Definition: emutools_basicdefs.h:167
scanline_render_debug_info
char scanline_render_debug_info[320]
Definition: vic3.c:99
FATAL
#define FATAL(...)
Definition: xep128.h:117
vic3_write_reg
void vic3_write_reg(int addr, Uint8 data)
Definition: vic3.c:745
XEMU_UNLIKELY
#define XEMU_UNLIKELY(__x__)
Definition: emutools_basicdefs.h:125
frameskip
int frameskip
Definition: vic3.c:75
vic3_check_raster_interrupt
void vic3_check_raster_interrupt(void)
Definition: vic3.c:138