OSDN Git Service

[INITIAL] Import 20141226 version of http://homepage3.nifty.com/takeda-toshiya/common...
[csp-qt/common_source_project-fm7.git] / source / src / vm / familybasic / ppu.cpp
1 /*\r
2         Nintendo Family BASIC Emulator 'eFamilyBASIC'\r
3 \r
4         Origin : nester\r
5         Author : Takeda.Toshiya\r
6         Date   : 2010.08.11-\r
7 \r
8         [ PPU ]\r
9 */\r
10 \r
11 #include "ppu.h"\r
12 #include "../../fileio.h"\r
13 \r
14 static const uint8 palette[64][3] = {\r
15         {0x75, 0x75, 0x75}, {0x27, 0x1b, 0x8f}, {0x00, 0x00, 0xab}, {0x47, 0x00, 0x9f},\r
16         {0x8f, 0x00, 0x77}, {0xab, 0x00, 0x13}, {0xa7, 0x00, 0x00}, {0x7f, 0x0b, 0x00},\r
17         {0x43, 0x2f, 0x00}, {0x00, 0x47, 0x00}, {0x00, 0x51, 0x00}, {0x00, 0x3f, 0x17},\r
18         {0x1b, 0x3f, 0x5f}, {0x00, 0x00, 0x00}, {0x05, 0x05, 0x05}, {0x05, 0x05, 0x05},\r
19         {0xbc, 0xbc, 0xbc}, {0x00, 0x73, 0xef}, {0x23, 0x3b, 0xef}, {0x83, 0x00, 0xf3},\r
20         {0xbf, 0x00, 0xbf}, {0xe7, 0x00, 0x5b}, {0xdb, 0x2b, 0x00}, {0xcb, 0x4f, 0x0f},\r
21         {0x8b, 0x73, 0x00}, {0x00, 0x97, 0x00}, {0x00, 0xab, 0x00}, {0x00, 0x93, 0x3b},\r
22         {0x00, 0x83, 0x8b}, {0x11, 0x11, 0x11}, {0x09, 0x09, 0x09}, {0x09, 0x09, 0x09},\r
23         {0xff, 0xff, 0xff}, {0x3f, 0xbf, 0xff}, {0x5f, 0x97, 0xff}, {0xa7, 0x8b, 0xfd},\r
24         {0xf7, 0x7b, 0xff}, {0xff, 0x77, 0xb7}, {0xff, 0x77, 0x63}, {0xff, 0x9b, 0x3b},\r
25         {0xf3, 0xbf, 0x3f}, {0x83, 0xd3, 0x13}, {0x4f, 0xdf, 0x4b}, {0x58, 0xf8, 0x98},\r
26         {0x00, 0xeb, 0xdb}, {0x66, 0x66, 0x66}, {0x0d, 0x0d, 0x0d}, {0x0d, 0x0d, 0x0d},\r
27         {0xff, 0xff, 0xff}, {0xab, 0xe7, 0xff}, {0xc7, 0xd7, 0xff}, {0xd7, 0xcb, 0xff},\r
28         {0xff, 0xc7, 0xff}, {0xff, 0xc7, 0xdb}, {0xff, 0xbf, 0xb3}, {0xff, 0xdb, 0xab},\r
29         {0xff, 0xe7, 0xa3}, {0xe3, 0xff, 0xa3}, {0xab, 0xf3, 0xbf}, {0xb3, 0xff, 0xcf},\r
30         {0x9f, 0xff, 0xf3}, {0xdd, 0xdd, 0xdd}, {0x11, 0x11, 0x11}, {0x11, 0x11, 0x11}\r
31 };\r
32 \r
33 #define VRAM(addr)      banks[((addr) >> 10) & 0x0f][(addr) & 0x3ff]\r
34 \r
35 #define NMI_enabled()   (regs[0] & 0x80)\r
36 #define sprites_8x16()  (regs[0] & 0x20)\r
37 #define spr_enabled()   (regs[1] & 0x10)\r
38 #define bg_enabled()    (regs[1] & 0x08)\r
39 #define spr_clip()      (!(regs[1] & 0x04))\r
40 #define bg_clip()       (!(regs[1] & 0x02))\r
41 #define monochrome()    (regs[1] & 0x01)\r
42 #define rgb_pal()       (regs[1] & 0xe0)\r
43 #define sprite0_hit()   (regs[2] & 0x40)\r
44 \r
45 #define LOOPY_SCANLINE_START(v, t) { \\r
46         v = (v & 0xfbe0) | (t & 0x041f); \\r
47 }\r
48 \r
49 #define LOOPY_NEXT_LINE(v) { \\r
50         if((v & 0x7000) == 0x7000) { \\r
51                 v &= 0x8fff; \\r
52                 if((v & 0x3e0) == 0x3a0) { \\r
53                         v ^= 0x0800; \\r
54                         v &= 0xfc1f; \\r
55                 } else { \\r
56                         if((v & 0x3e0) == 0x3e0) { \\r
57                                 v &= 0xfc1f; \\r
58                         } else { \\r
59                                 v += 0x20; \\r
60                         } \\r
61                 } \\r
62         } else { \\r
63                 v += 0x1000; \\r
64         } \\r
65 }\r
66 \r
67 #define LOOPY_NEXT_TILE(v) { \\r
68         if((v & 0x1f) == 0x1f) { \\r
69                 v ^= 0x0400; \\r
70                 v &= 0xffe0; \\r
71         } else { \\r
72                 v++; \\r
73         } \\r
74 }\r
75 \r
76 #define LOOPY_NEXT_PIXEL(v, x) { \\r
77         if(x == 7) { \\r
78                 LOOPY_NEXT_TILE(v); \\r
79                 x = 0; \\r
80         } else { \\r
81                 x++; \\r
82         } \\r
83 }\r
84 \r
85 void PPU::initialize()\r
86 {\r
87         // register event\r
88         register_vline_event(this);\r
89 }\r
90 \r
91 void PPU::load_rom_image(_TCHAR *file_name)\r
92 {\r
93         FILEIO* fio = new FILEIO();\r
94         bool file_open = false;\r
95         \r
96         if(fio->Fopen(emu->bios_path(file_name), FILEIO_READ_BINARY)) {\r
97                 file_open = true;\r
98         } else if(fio->Fopen(emu->bios_path(_T("BASIC.NES")), FILEIO_READ_BINARY)) {\r
99                 // for compatibility\r
100                 file_open = true;\r
101         }\r
102         if(file_open) {\r
103                 // read header\r
104                 fio->Fread(header, sizeof(header), 1);\r
105                 // skip program rom\r
106                 fio->Fseek(header[4] * 0x4000, FILEIO_SEEK_CUR);\r
107                 // read chr rom (max 8kb)\r
108                 fio->Fread(chr_rom, sizeof(chr_rom), 1);\r
109                 fio->Fclose();\r
110         } else {\r
111                 memset(header, 0, sizeof(header));\r
112                 memset(chr_rom, 0xff, sizeof(chr_rom));\r
113         }\r
114         delete fio;\r
115 }\r
116 \r
117 void PPU::reset()\r
118 {\r
119         // set up PPU memory space table\r
120         for(int i = 0; i < 8; i++) {\r
121                 banks[i] = chr_rom + 0x400 * i;\r
122         }\r
123         \r
124         // set mirroring\r
125 #if 0\r
126         if(header[6] & 8) {\r
127                 // 4 screen mirroring\r
128                 banks[ 8] = banks[12] = name_tables;\r
129                 banks[ 9] = banks[13] = name_tables + 0x400;\r
130                 banks[10] = banks[14] = name_tables + 0x800;\r
131                 banks[11] = banks[15] = name_tables + 0xc00;\r
132         } else if(header[6] & 1) {\r
133 #endif\r
134                 // vertical mirroring\r
135                 banks[ 8] = banks[10] = banks[12] = banks[14] = name_tables;\r
136                 banks[ 9] = banks[11] = banks[13] = banks[15] = name_tables + 0x400;\r
137 #if 0\r
138         } else {\r
139                 // horizontal mirroring\r
140                 banks[ 8] = banks[ 9] = banks[12] = banks[13] = name_tables;\r
141                 banks[10] = banks[11] = banks[14] = banks[15] = name_tables + 0x400;\r
142         }\r
143 #endif\r
144         \r
145         memset(bg_pal, 0, sizeof(bg_pal));\r
146         memset(spr_pal, 0, sizeof(spr_pal));\r
147         memset(solid_buf, 0, sizeof(solid_buf));\r
148         memset(name_tables, 0, sizeof(name_tables));\r
149         \r
150         memset(spr_ram, 0, sizeof(spr_ram));\r
151         spr_ram_rw_ptr = 0;\r
152         \r
153         memset(regs, 0, sizeof(regs));\r
154         bg_pattern_table_addr = 0;\r
155         spr_pattern_table_addr = 0;\r
156         ppu_addr_inc = 0;\r
157         rgb_bak = 0;\r
158         toggle_2005_2006 = false;\r
159         read_2007_buffer = 0;\r
160         \r
161         loopy_v = 0;\r
162         loopy_t = 0;\r
163         loopy_x = 0;\r
164         \r
165         // reset emphasised palette\r
166         update_palette();\r
167 }\r
168 \r
169 void PPU::write_data8(uint32 addr, uint32 data)\r
170 {\r
171         uint16 ofs;\r
172         \r
173         regs[addr & 7] = data;\r
174         \r
175         switch(addr & 0xe007) {\r
176         case 0x2000:\r
177                 bg_pattern_table_addr = (data & 0x10) ? 0x1000 : 0;\r
178                 spr_pattern_table_addr = (data & 0x08) ? 0x1000 : 0;\r
179                 ppu_addr_inc = (data & 0x04) ? 32 : 1;\r
180                 loopy_t = (loopy_t & 0xf3ff) | (((uint16)(data & 0x03)) << 10);\r
181                 break;\r
182         case 0x2001:\r
183                 if(rgb_bak != (data & 0xe0)) {\r
184                         update_palette();\r
185                         rgb_bak = data & 0xe0;\r
186                 }\r
187                 break;\r
188         case 0x2003:\r
189                 spr_ram_rw_ptr = data;\r
190                 break;\r
191         case 0x2004:\r
192                 spr_ram[spr_ram_rw_ptr++] = data;\r
193                 break;\r
194         case 0x2005:\r
195                 toggle_2005_2006 = !toggle_2005_2006;\r
196                 if(toggle_2005_2006) {\r
197                         // first write\r
198                         loopy_t = (loopy_t & 0xffe0) | (((uint16)(data & 0xf8)) >> 3);\r
199                         loopy_x = data & 0x07;\r
200                 } else {\r
201                         // second write\r
202                         loopy_t = (loopy_t & 0xfc1f) | (((uint16)(data & 0xf8)) << 2);\r
203                         loopy_t = (loopy_t & 0x8fff) | (((uint16)(data & 0x07)) << 12);\r
204                 }\r
205                 break;\r
206         case 0x2006:\r
207                 toggle_2005_2006 = !toggle_2005_2006;\r
208                 if(toggle_2005_2006) {\r
209                         // first write\r
210                         loopy_t = (loopy_t & 0x00ff) | (((uint16)(data & 0x3f)) << 8);\r
211                 } else {\r
212                         // second write\r
213                         loopy_t = (loopy_t & 0xff00) | ((uint16)data);\r
214                         loopy_v = loopy_t;\r
215                 }\r
216                 break;\r
217         case 0x2007:\r
218                 ofs = loopy_v & 0x3fff;\r
219                 loopy_v += ppu_addr_inc;\r
220                 if(ofs >= 0x3000) {\r
221                         // is it a palette entry?\r
222                         if(ofs >= 0x3f00) {\r
223                                 data &= 0x3f;\r
224                                 if(!(ofs & 0x000f)) {\r
225                                         bg_pal[0] = spr_pal[0] = data;\r
226                                 } else if(!(ofs & 0x10)) {\r
227                                         bg_pal[ofs & 0x000f] = data;\r
228                                 } else {\r
229                                         spr_pal[ofs & 0x000f] = data;\r
230                                 }\r
231                                 break;\r
232                         }\r
233                         // handle mirroring\r
234                         ofs &= 0xefff;\r
235                 }\r
236                 if(ofs >= 0x2000) {\r
237                         VRAM(ofs) = data;\r
238                 }\r
239                 break;\r
240         }\r
241 }\r
242 \r
243 uint32 PPU::read_data8(uint32 addr)\r
244 {\r
245         uint16 ofs;\r
246         uint8 val;\r
247         \r
248         switch(addr & 0xe007) {\r
249         case 0x2002:\r
250                 // clear toggle\r
251                 toggle_2005_2006 = false;\r
252                 val = regs[2];\r
253                 // clear v-blank flag\r
254                 regs[2] &= ~0x80;\r
255                 return val;\r
256         case 0x2007:\r
257                 ofs = loopy_v & 0x3fff;\r
258                 loopy_v += ppu_addr_inc;\r
259                 if(ofs >= 0x3000) {\r
260                         // is it a palette entry?\r
261                         if(ofs >= 0x3f00) {\r
262                                 if(!(ofs & 0x0010)) {\r
263                                         return bg_pal[ofs & 0x000f];\r
264                                 } else {\r
265                                         return spr_pal[ofs & 0x000f];\r
266                                 }\r
267                         }\r
268                         // handle mirroring\r
269                         ofs &= 0xefff;\r
270                 }\r
271                 val = read_2007_buffer;\r
272                 read_2007_buffer = VRAM(ofs);\r
273                 return val;\r
274         }\r
275         return regs[addr & 7];\r
276 }\r
277 \r
278 void PPU::event_vline(int v, int clock)\r
279 {\r
280         switch(v) {\r
281         case 0:\r
282                 if(spr_enabled() || bg_enabled()) {\r
283                         loopy_v = loopy_t;\r
284                 }\r
285                 break;\r
286         case 241:\r
287                 // set vblank register flag\r
288                 regs[2] |= 0x80;\r
289                 if(NMI_enabled()) {\r
290                         d_cpu->write_signal(SIG_CPU_NMI, 1, 1);\r
291                 }\r
292                 break;\r
293         case 261:\r
294                 // reset vblank register flag and sprite0 hit flag1\r
295                 regs[2] &= 0x3F;\r
296                 break;\r
297         }\r
298         if(v < 240) {\r
299                 render_scanline(v);\r
300         }\r
301 }\r
302 \r
303 void PPU::draw_screen()\r
304 {\r
305         \r
306         for(int y = 0; y < 240; y++) {\r
307                 scrntype* dest = emu->screen_buffer(y);\r
308                 uint8* src = screen[y];\r
309                 \r
310                 for(int x = 0; x < 256; x++) {\r
311                         dest[x] = palette_pc[src[x + 8] & 0x3f];\r
312                 }\r
313         }\r
314 }\r
315 \r
316 void PPU::update_palette()\r
317 {\r
318         for(int i = 0; i < 64; i++) {\r
319                 uint8 r = palette[i][0];\r
320                 uint8 g = palette[i][1];\r
321                 uint8 b = palette[i][2];\r
322                 \r
323                 switch(rgb_pal()) {\r
324                 case 0x20:\r
325                         g = (uint8)(g * 0.80);\r
326                         b = (uint8)(b * 0.73);\r
327                         break;\r
328                 case 0x40:\r
329                         r = (uint8)(r * 0.73);\r
330                         b = (uint8)(b * 0.70);\r
331                         break;\r
332                 case 0x60:\r
333                         r = (uint8)(r * 0.76);\r
334                         g = (uint8)(g * 0.78);\r
335                         b = (uint8)(b * 0.58);\r
336                         break;\r
337                 case 0x80:\r
338                         r = (uint8)(r * 0.86);\r
339                         g = (uint8)(g * 0.80);\r
340                         break;\r
341                 case 0xa0:\r
342                         r = (uint8)(r * 0.83);\r
343                         g = (uint8)(g * 0.68);\r
344                         b = (uint8)(b * 0.85);\r
345                         break;\r
346                 case 0xc0:\r
347                         r = (uint8)(r * 0.67);\r
348                         g = (uint8)(g * 0.77);\r
349                         b = (uint8)(b * 0.83);\r
350                         break;\r
351                 case 0xe0:\r
352                         r = (uint8)(r * 0.68);\r
353                         g = (uint8)(g * 0.68);\r
354                         b = (uint8)(b * 0.68);\r
355                         break;\r
356                 }\r
357                 palette_pc[i] = RGB_COLOR(r, g, b);\r
358         }\r
359 }\r
360 \r
361 void PPU::render_scanline(int v)\r
362 {\r
363         uint8* buf = screen[v];\r
364         \r
365         if(!bg_enabled()) {\r
366                 // set to background color\r
367                 memset(screen[v], bg_pal[0], 256 + 16);\r
368         }\r
369         if(spr_enabled() || bg_enabled()) {\r
370                 LOOPY_SCANLINE_START(loopy_v, loopy_t);\r
371                 if(bg_enabled()) {\r
372                         render_bg(v);\r
373                 } else {\r
374                         memset(solid_buf, 0, sizeof(solid_buf));\r
375                 }\r
376                 if(spr_enabled()) {\r
377                         // draw sprites\r
378                         render_spr(v);\r
379                 }\r
380                 LOOPY_NEXT_LINE(loopy_v);\r
381         }\r
382 }\r
383 \r
384 #define BG_WRITTEN_FLAG 1\r
385 #define SPR_WRITTEN_FLAG 2\r
386 \r
387 #define DRAW_BG_PIXEL() \\r
388         col = attrib_bits; \\r
389         if(pattern_lo & pattern_mask) { \\r
390                 col |= 1; \\r
391         } \\r
392         if(pattern_hi & pattern_mask) { \\r
393                 col |= 2; \\r
394         } \\r
395         *p++ = monochrome() ? (bg_pal[col] & 0xf0) : bg_pal[col]; \\r
396         *solid++ = (col & 3) ? BG_WRITTEN_FLAG : 0; \\r
397 \r
398 void PPU::render_bg(int v)\r
399 {\r
400         uint32 tile_x = (loopy_v & 0x001f);\r
401         uint32 tile_y = (loopy_v & 0x03e0) >> 5;\r
402         uint32 name_addr = 0x2000 + (loopy_v & 0x0fff);\r
403         uint32 attrib_addr = 0x2000 + (loopy_v & 0x0c00) + 0x03c0 + ((tile_y & 0xfffc) << 1) + (tile_x >> 2);\r
404         uint8 attrib_bits;\r
405         \r
406         if(!(tile_y & 2)) {\r
407                 if(!(tile_x & 2)) {\r
408                         attrib_bits = (VRAM(attrib_addr) & 0x03) << 2;\r
409                 } else {\r
410                         attrib_bits = (VRAM(attrib_addr) & 0x0C);\r
411                 }\r
412         } else {\r
413                 if(!(tile_x & 2)) {\r
414                         attrib_bits = (VRAM(attrib_addr) & 0x30) >> 2;\r
415                 } else {\r
416                         attrib_bits = (VRAM(attrib_addr) & 0xC0) >> 4;\r
417                 }\r
418         }\r
419         uint8 *p = screen[v] + (8 - loopy_x);\r
420         uint8 *solid = solid_buf + (8 - loopy_x);\r
421         \r
422         for(int i = 33; i; i--) {\r
423                 uint32 pattern_addr = bg_pattern_table_addr + ((int32)VRAM(name_addr) << 4) + ((loopy_v & 0x7000) >> 12);\r
424                 uint8 pattern_lo = VRAM(pattern_addr);\r
425                 uint8 pattern_hi = VRAM(pattern_addr + 8);\r
426                 uint8 pattern_mask = 0x80;\r
427                 uint8 col;\r
428                 \r
429                 DRAW_BG_PIXEL();\r
430                 pattern_mask >>= 1;\r
431                 DRAW_BG_PIXEL();\r
432                 pattern_mask >>= 1;\r
433                 DRAW_BG_PIXEL();\r
434                 pattern_mask >>= 1;\r
435                 DRAW_BG_PIXEL();\r
436                 pattern_mask >>= 1;\r
437                 DRAW_BG_PIXEL();\r
438                 pattern_mask >>= 1;\r
439                 DRAW_BG_PIXEL();\r
440                 pattern_mask >>= 1;\r
441                 DRAW_BG_PIXEL();\r
442                 pattern_mask >>= 1;\r
443                 DRAW_BG_PIXEL();\r
444                 \r
445                 tile_x++;\r
446                 name_addr++;\r
447                 \r
448                 if(!(tile_x & 1)) {\r
449                         if(!(tile_x & 3)) {\r
450                                 if(!(tile_x & 0x1f)) {\r
451                                         name_addr ^= 0x0400; // switch name tables\r
452                                         attrib_addr ^= 0x0400;\r
453                                         name_addr -= 0x0020;\r
454                                         attrib_addr -= 0x0008;\r
455                                         tile_x -= 0x0020;\r
456                                 }\r
457                                 attrib_addr++;\r
458                         }\r
459                         if(!(tile_y & 2)) {\r
460                                 if(!(tile_x & 2)) {\r
461                                         attrib_bits = (VRAM(attrib_addr) & 0x03) << 2;\r
462                                 } else {\r
463                                         attrib_bits = (VRAM(attrib_addr) & 0x0c);\r
464                                 }\r
465                         } else {\r
466                                 if(!(tile_x & 2)) {\r
467                                         attrib_bits = (VRAM(attrib_addr) & 0x30) >> 2;\r
468                                 } else {\r
469                                         attrib_bits = (VRAM(attrib_addr) & 0xc0) >> 4;\r
470                                 }\r
471                         }\r
472                 }\r
473         }\r
474         if(bg_clip()) {\r
475                 memset(&screen[v][8], bg_pal[0], 8);\r
476                 memset(solid + 8, 0, 8);\r
477         }\r
478 }\r
479 \r
480 void PPU::render_spr(int v)\r
481 {\r
482         int num_sprites = 0;\r
483         int spr_height = sprites_8x16() ? 16 : 8;\r
484         \r
485         for(int s = 0; s < 64; s++) {\r
486                 uint8* spr = &spr_ram[s << 2];\r
487                 int spr_y = spr[0] + 1;\r
488                 \r
489                 if(spr_y > v || (spr_y + spr_height) <= v) {\r
490                         continue;\r
491                 }\r
492                 num_sprites++;\r
493                 if(num_sprites > 8) {\r
494                         break;\r
495                 }\r
496                 int spr_x = spr[3];\r
497                 int start_x = 0;\r
498                 int end_x = 8;\r
499                 int inc_x = 1;\r
500                 \r
501                 if((spr_x + 7) > 255) {\r
502                         end_x -= ((spr_x + 7) - 255);\r
503                 }\r
504                 if((spr_x < 8) && (spr_clip())) {\r
505                         if(!spr_x) {\r
506                                 continue;\r
507                         }\r
508                         start_x += (8 - spr_x);\r
509                 }\r
510                 int y = v - spr_y;\r
511                 \r
512                 uint8 *p = &screen[v][8 + spr_x + start_x];\r
513                 uint8 *solid = &solid_buf[8 + spr_x + start_x];\r
514                 \r
515                 if(spr[2] & 0x40) {\r
516                         start_x = (8 - 1) - start_x;\r
517                         end_x = (8 - 1) - end_x;\r
518                         inc_x = -1;\r
519                 }\r
520                 if(spr[2] & 0x80) {\r
521                         y = (spr_height - 1) - y;\r
522                 }\r
523                 uint8 priority = spr[2] & 0x20;\r
524                 \r
525                 for(int x = start_x; x != end_x; x += inc_x) {\r
526                         uint8 col = 0;\r
527                         uint32 tile_addr;\r
528                         uint8 tile_mask;\r
529                         \r
530                         if(!((*solid) & SPR_WRITTEN_FLAG)) {\r
531                                 if(sprites_8x16()) {\r
532                                         tile_addr = spr[1] << 4;\r
533                                         if(spr[1] & 0x01) {\r
534                                                 tile_addr += 0x1000;\r
535                                                 if(y < 8) {\r
536                                                         tile_addr -= 16;\r
537                                                 }\r
538                                         } else {\r
539                                                 if(y >= 8) {\r
540                                                         tile_addr += 16;\r
541                                                 }\r
542                                         }\r
543                                         tile_addr += y & 0x07;\r
544                                         tile_mask = (0x80 >> (x & 0x07));\r
545                                 } else {\r
546                                         tile_addr = spr[1] << 4;\r
547                                         tile_addr += y & 0x07;\r
548                                         tile_addr += spr_pattern_table_addr;\r
549                                         tile_mask = (0x80 >> (x & 0x07));\r
550                                 }\r
551                                 if(VRAM(tile_addr) & tile_mask) {\r
552                                         col |= 1;\r
553                                 }\r
554                                 tile_addr += 8;\r
555                                 if(VRAM(tile_addr) & tile_mask) {\r
556                                         col |= 2;\r
557                                 }\r
558                                 if(spr[2] & 2) {\r
559                                         col |= 8;\r
560                                 }\r
561                                 if(spr[2] & 1) {\r
562                                         col |= 4;\r
563                                 }\r
564                                 if(col & 3) {\r
565                                         if(s && (*solid & BG_WRITTEN_FLAG)) {\r
566                                                 regs[2] |= 0x40;\r
567                                         }\r
568                                         if(priority) {\r
569                                                 *solid |= SPR_WRITTEN_FLAG;\r
570                                                 if(!(*solid & BG_WRITTEN_FLAG)) {\r
571                                                         *p = monochrome() ? (spr_pal[col] & 0xf0) : spr_pal[col];\r
572                                                 }\r
573                                         } else {\r
574                                                 if(!(*solid & SPR_WRITTEN_FLAG)) {\r
575                                                         *p = monochrome() ? (spr_pal[col] & 0xf0) : spr_pal[col];\r
576                                                         *solid |= SPR_WRITTEN_FLAG;\r
577                                                 }\r
578                                         }\r
579                                 }\r
580                         }\r
581                         p++;\r
582                         solid++;\r
583                 }\r
584         }\r
585         if(num_sprites >= 8) {\r
586                 regs[2] |= 0x20;\r
587         } else {\r
588                 regs[2] &= ~0x20;\r
589         }\r
590 }\r