OSDN Git Service

deallocate shared memory after using it.
[motonesemu/motonesemu.git] / emulator / ppucore / vram.c
1 #include <stddef.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <time.h>
6
7 #include "tools.h"
8 #include "ppucore.h"
9 #include "vram.h"
10 #include "sprite.h"
11
12 void palette_index_to_rgb15(unsigned char index, struct rgb15* rgb);
13 void dump_mem(const char* msg, unsigned short base, 
14         unsigned short offset, unsigned char* buf, int size);
15 void set_bgtile(int tile_id);
16
17 /*vram definition*/
18
19 static unsigned char * bg_palette_tbl;
20 static unsigned char * spr_palette_tbl;
21
22 static unsigned char * name_tbl0;
23 static unsigned char * name_tbl1;
24 static unsigned char * name_tbl2;
25 static unsigned char * name_tbl3;
26
27 static unsigned char * attr_tbl0;
28 static unsigned char * attr_tbl1;
29 static unsigned char * attr_tbl2;
30 static unsigned char * attr_tbl3;
31
32 static unsigned char * pattern_tbl0;
33 static unsigned char * pattern_tbl1;
34
35 //#define PPU_TEST
36 #ifdef PPU_TEST
37 static int first_time = TRUE;
38 #endif /* PPU_TEST */
39
40 extern int debug_mode;
41 static void (*vram_log_level4)(unsigned short, unsigned char);
42 static void dump_vram_write (unsigned short addr, unsigned char data);
43 void d4_set(int on_off);
44
45 /*
46  * VRAM get/set functions....
47  *
48  * */
49
50 static unsigned char pattern_tbl_get(unsigned char bank, unsigned short offset) {
51     if (bank == 0)
52         return pattern_tbl0[offset];
53     else
54         return pattern_tbl1[offset];
55 }
56
57 static unsigned char name_tbl_get(unsigned char bank, unsigned short offset) {
58     if (bank == 0)
59         return name_tbl0[offset];
60     else if (bank == 1)
61         return name_tbl1[offset];
62     else if (bank == 2)
63         return name_tbl2[offset];
64     else
65         return name_tbl3[offset];
66 }
67
68 static void name_tbl_set(unsigned char bank, unsigned short offset, unsigned char data) {
69     if (bank == 0)
70         name_tbl0[offset] = data;
71     else if (bank == 1)
72         name_tbl1[offset] = data;
73     else if (bank == 2)
74         name_tbl2[offset] = data;
75     else
76         name_tbl3[offset] = data;
77 }
78
79
80 static unsigned char attr_tbl_get(unsigned char bank, unsigned short offset) {
81     if (bank == 0)
82         return attr_tbl0[offset];
83     else if (bank == 1)
84         return attr_tbl1[offset];
85     else if (bank == 2)
86         return attr_tbl2[offset];
87     else
88         return attr_tbl3[offset];
89 }
90
91 static void attr_tbl_set(unsigned char bank, unsigned short offset, unsigned char data) {
92     if (bank == 0)
93         attr_tbl0[offset] = data;
94     else if (bank == 1)
95         attr_tbl1[offset] = data;
96     else if (bank == 2)
97         attr_tbl2[offset] = data;
98     else
99         attr_tbl3[offset] = data;
100 }
101
102
103 static unsigned char spr_palette_tbl_get(unsigned short offset) {
104     return spr_palette_tbl[offset];
105 }
106
107 static void spr_palette_tbl_set(unsigned short offset, unsigned char data) {
108     spr_palette_tbl[offset] = data;
109 }
110
111 static unsigned char bg_palette_tbl_get(unsigned short offset) {
112     return bg_palette_tbl[offset];
113 }
114
115 static void bg_palette_tbl_set(unsigned short offset, unsigned char data) {
116     bg_palette_tbl[offset] = data;
117 }
118
119 void vram_data_set(unsigned short addr, unsigned char data) {
120 #ifdef PPU_TEST
121     if (!first_time)
122         return;
123 #endif /* PPU_TEST */
124
125     vram_log_level4 (addr, data);
126
127     //mirror 0x4000 up addr.
128     addr &= PPU_ADDR_MASK;
129
130     if (addr < 2 * PATTERN_TBL_SIZE) {
131         //dprint("invalid vram write addr:%04x, data:%2x\n", addr, data);
132         //do nothing. pattern table is read only.
133         extern int critical_error;
134         dprint("invalid vram write!!!!\n");
135         critical_error = TRUE;
136     }
137     else if (addr >= PALETTE_START) {
138         // bg/sprite palette table.
139         if (addr & PALETTE_SPRITE_BIT)
140             spr_palette_tbl_set(addr & PALETTE_TBL_ADDR_MASK, data);
141         else 
142             bg_palette_tbl_set(addr & PALETTE_TBL_ADDR_MASK, data);
143     }
144     else {
145         // name/attr table.
146         // mask 0x3000 up addr.
147         addr &= NAME_ATTR_MASK;
148         if (addr < ATTR0_START) {
149             name_tbl_set(0, addr - NAME0_START, data);
150         }
151         else if (addr < NAME1_START) {
152             attr_tbl_set(0, addr - ATTR0_START, data);
153         }
154         else if (addr < ATTR1_START) {
155             name_tbl_set(1, addr - NAME1_START, data);
156         }
157         else if (addr < NAME2_START) {
158             attr_tbl_set(1, addr - ATTR1_START, data);
159         }
160         else if (addr < ATTR2_START) {
161             name_tbl_set(2, addr - NAME2_START, data);
162         }
163         else if (addr < NAME3_START) {
164             attr_tbl_set(2, addr - ATTR2_START, data);
165         }
166         else if (addr < ATTR3_START) {
167             name_tbl_set(3, addr - NAME3_START, data);
168         }
169         else {
170             attr_tbl_set(3, addr - ATTR3_START, data);
171         }
172     }
173 }
174
175 unsigned char vram_data_get(unsigned short addr) {
176
177     addr &= PPU_ADDR_MASK;
178
179     if (addr < PATTERN_TBL_SIZE) {
180         return pattern_tbl_get(0, addr & PATTERN_ADDR_MASK);
181     }
182     if (addr < 2 * PATTERN_TBL_SIZE) {
183         return pattern_tbl_get(1, addr & PATTERN_ADDR_MASK);
184     }
185     else if (addr >= PALETTE_START) {
186         if (addr & PALETTE_SPRITE_BIT)
187             return spr_palette_tbl_get(addr & PALETTE_TBL_ADDR_MASK);
188         else 
189             return bg_palette_tbl_get(addr & PALETTE_TBL_ADDR_MASK);
190     }
191     else {
192         addr &= NAME_ATTR_MASK;
193         if (addr < ATTR0_START) {
194             return name_tbl_get(0, addr - NAME0_START);
195         }
196         else if (addr < NAME1_START) {
197             return attr_tbl_get(0, addr - ATTR0_START);
198         }
199         else if (addr < ATTR1_START) {
200             return name_tbl_get(1, addr - NAME1_START);
201         }
202         else if (addr < NAME2_START) {
203             return attr_tbl_get(1, addr - ATTR1_START);
204         }
205         else if (addr < ATTR2_START) {
206             return name_tbl_get(2, addr - NAME2_START);
207         }
208         else if (addr < NAME3_START) {
209             return attr_tbl_get(2, addr - ATTR2_START);
210         }
211         else if (addr < ATTR3_START) {
212             return name_tbl_get(3, addr - NAME3_START);
213         }
214         else {
215             return attr_tbl_get(3, addr - ATTR3_START);
216         }
217     }
218     return 0;
219 }
220
221 /* VRAM manipulation... */
222
223 #ifdef PPU_TEST
224 /*
225  * ppu test function
226  * */
227 static void test_ppu(void) {
228     int i;
229     unsigned char plt[32] = {
230             0x0f, 0x00, 0x10, 0x20,
231             0x0f, 0x06, 0x16, 0x26,
232             0x0f, 0x08, 0x18, 0x28,
233             0x0f, 0x0a, 0x1a, 0x2a,
234
235             0x0f, 0x00, 0x10, 0x20,
236             0x0f, 0x06, 0x16, 0x26,
237             0x0f, 0x08, 0x18, 0x28,
238             0x0f, 0x0a, 0x1a, 0x2a,
239     };
240
241     //bg character base addr set to 0x1000.
242     ppu_ctrl1_set(0x00);
243
244 /*
245 */
246     //palette tbl
247     for (i = 0; i < 16; i++)
248         vram_data_set(0x3f00 + i, plt[i]);
249     for (i = 0; i < 16; i++)
250         vram_data_set(0x3f10 + i, plt[i + 16]);
251
252     //name tbl
253     for (i = 0; i < 960; i++) 
254         vram_data_set(0x2000 + i, i %255);
255
256 /*
257 */
258     //attr tbl
259     for (i = 0; i < 64; i++) 
260         vram_data_set(0x23c0 + i, i%16);
261
262     /*
263     vram_data_set(0x2000 + 205, 'D');
264     vram_data_set(0x2000 + 206, 'e');
265     vram_data_set(0x2000 + 207, 'e');
266     vram_data_set(0x2000 + 208, '!');
267     vram_data_set(0x2000 + 209, '!');
268     //205 = palette gp2 00011011b 
269     //205 = 11
270     vram_data_set(0x23c0 + 11, 0x1b);
271
272     //other test.
273     vram_data_set(0x2000 + 300, 1);
274     vram_data_set(0x2000 + 0, 0x65);
275 */
276
277     /*
278     set_monocolor(FALSE);
279      * */
280
281     for (i = 0; i < 960; i++) 
282         set_bgtile(i);
283
284     /*
285     //sprite test
286     struct sprite_attr sa;
287     sa.palette = 2;
288     sa.priority = 1;
289     sa.flip_h = 0;
290     sa.flip_v = 0;
291     set_sprite(30, 100, 'd', sa);
292     sa.flip_h = 1;
293     set_sprite(50, 100, 'd', sa);
294     sa.flip_v = 1;
295     set_sprite(70, 105, 'd', sa);
296      * */
297
298     //bg&sprite show
299     ppu_ctrl2_set(0x18);
300
301     /*
302     vga_xfer();
303 */
304
305 //void dump_vram(int type, int bank, unsigned short addr, int size);
306 /*
307     dump_vram(VRAM_DUMP_TYPE_PTN, 0, 0, 0x100);
308     dump_vram(VRAM_DUMP_TYPE_NAME, 0, 0, 300);
309     dump_vram(VRAM_DUMP_TYPE_ATTR, 0, 0, 64);
310     dump_vram(VRAM_DUMP_TYPE_PLT, 0, 0, 16);
311 */
312 }
313 #endif /* PPU_TEST */
314
315 static int attr_index_to_gp(int tile_index) {
316     int tile_x, tile_y, gp_x, gp_y;
317
318     tile_x = tile_index % H_SCREEN_TILE_SIZE;
319     tile_y = tile_index / H_SCREEN_TILE_SIZE;
320
321     gp_x = tile_x / ATTR_GROUP_UNIT;
322     gp_y = tile_y / ATTR_GROUP_UNIT;
323     //dprint("tile_x:%d, y:%d, gp_x:%d, y:%d\n", tile_x, tile_y, gp_x, gp_y);
324
325     return gp_x + gp_y * 8;
326 }
327
328 void load_attribute(unsigned char bank, int tile_index, struct palette *plt) {
329     int gp_index;
330     unsigned char data;
331     struct palette_unit pu;
332     int palette_group;
333     unsigned short palette_addr;
334     unsigned char pi;
335     int tile_x, tile_y;
336     int in_x, in_y;
337
338     gp_index = attr_index_to_gp(tile_index);
339     data = attr_tbl_get(bank, gp_index);
340     memcpy(&pu, &data, sizeof(pu));
341
342     tile_x = tile_index % H_SCREEN_TILE_SIZE;
343     tile_y = tile_index / H_SCREEN_TILE_SIZE;
344     in_x = tile_x % (ATTR_GROUP_UNIT);
345     in_y = tile_y % (ATTR_GROUP_UNIT);
346     if (in_y < 2) {
347         if (in_x < 2) {
348             palette_group = pu.bit01;
349         }
350         else {
351             palette_group = pu.bit23;
352         }
353     }
354     else {
355         if (in_x < 2) {
356             palette_group = pu.bit45;
357         }
358         else {
359             palette_group = pu.bit67;
360         }
361     }
362     /*
363     dprint("tile_index: %d, gp_index: %d\n", tile_index, gp_index);
364     dprint("in_x: %d, in_y: %d\n", in_x, in_y);
365     dprint("pu bit01:%d, bit23:%d, bit45:%d, bit67:%d\n", pu.bit01, pu.bit23, pu.bit45, pu.bit67);
366     dprint("palette_gp: %d\n", palette_group);
367     */
368
369     /*load bg rgb palette color*/
370     palette_addr = palette_group * 4;
371     pi = bg_palette_tbl_get(palette_addr++);
372     palette_index_to_rgb15(pi, &plt->col[0]);
373     /*
374     dprint("palette 0: index:%02d, %02x %02x %02x\n", pi, 
375             colto8bit(plt->col[0].r), colto8bit(plt->col[0].g), colto8bit(plt->col[0].b));
376             */
377
378     pi = bg_palette_tbl_get(palette_addr++);
379     palette_index_to_rgb15(pi, &plt->col[1]);
380     /*
381     dprint("palette 1: index:%02d, %02x %02x %02x\n", pi, 
382             colto8bit(plt->col[1].r), colto8bit(plt->col[1].g), colto8bit(plt->col[1].b));
383             */
384
385     pi = bg_palette_tbl_get(palette_addr++);
386     palette_index_to_rgb15(pi, &plt->col[2]);
387     /*
388     dprint("palette 2: index:%02d, %02x %02x %02x\n", pi, 
389             colto8bit(plt->col[2].r), colto8bit(plt->col[2].g), colto8bit(plt->col[2].b));
390             */
391
392     pi = bg_palette_tbl_get(palette_addr);
393     palette_index_to_rgb15(pi, &plt->col[3]);
394     /*
395     dprint("palette 3: index:%02d, %02x %02x %02x\n", pi, 
396             colto8bit(plt->col[3].r), colto8bit(plt->col[3].g), colto8bit(plt->col[3].b));
397             */
398
399 }
400
401 void load_spr_attribute(struct sprite_attr sa, struct palette *plt) {
402     unsigned short palette_addr;
403     unsigned char pi;
404
405     /*load bg rgb palette color*/
406     palette_addr = sa.palette * 4;
407     pi = bg_palette_tbl_get(palette_addr++);
408     palette_index_to_rgb15(pi, &plt->col[0]);
409
410     pi = bg_palette_tbl_get(palette_addr++);
411     palette_index_to_rgb15(pi, &plt->col[1]);
412
413     pi = bg_palette_tbl_get(palette_addr++);
414     palette_index_to_rgb15(pi, &plt->col[2]);
415
416     pi = bg_palette_tbl_get(palette_addr);
417     palette_index_to_rgb15(pi, &plt->col[3]);
418 }
419
420 /*
421  * pattern index: 0 - 255
422  * */
423 void load_pattern(unsigned char bank, unsigned char ptn_index, struct tile_2* pattern) {
424     int i;
425     unsigned char *p;
426     unsigned short addr;
427
428     //load character pattern
429     p = (unsigned char*)pattern;
430     addr = ptn_index * sizeof(struct tile_2);
431     for (i = 0; i < sizeof(struct tile_2); i++) {
432         *p = pattern_tbl_get(bank, addr);
433         p++;
434         addr++;
435     }
436 }
437
438 int load_chr_rom(FILE* cartridge, int num_rom_bank) {
439     int len;
440
441     len = fread(pattern_tbl0, 1, PATTERN_TBL_SIZE, cartridge);
442     if (len != PATTERN_TBL_SIZE)
443         return FALSE;
444
445     len = fread(pattern_tbl1, 1, PATTERN_TBL_SIZE, cartridge);
446     if (len != PATTERN_TBL_SIZE)
447         return FALSE;
448
449     return TRUE;
450 }
451
452 int vram_init(void) {
453
454     pattern_tbl0 = malloc(PATTERN_TBL_SIZE);
455     if (pattern_tbl0 == NULL)
456         return FALSE;
457
458     pattern_tbl1 = malloc(PATTERN_TBL_SIZE);
459     if (pattern_tbl1 == NULL)
460         return FALSE;
461
462     name_tbl0 = malloc(NAME_TBL_SIZE);
463     if (name_tbl0 == NULL)
464         return FALSE;
465
466     name_tbl1 = malloc(NAME_TBL_SIZE);
467     if (name_tbl1 == NULL)
468         return FALSE;
469
470     attr_tbl0 = malloc(ATTR_TBL_SIZE);
471     if (attr_tbl0 == NULL)
472         return FALSE;
473
474     attr_tbl1 = malloc(ATTR_TBL_SIZE);
475     if (attr_tbl1 == NULL)
476         return FALSE;
477
478     name_tbl2 = name_tbl0;
479     name_tbl3 = name_tbl1;
480
481     attr_tbl2 = attr_tbl0;
482     attr_tbl3 = attr_tbl1;
483     
484     bg_palette_tbl = malloc(PALETTE_TBL_SIZE);
485     if (bg_palette_tbl == NULL)
486         return FALSE;
487
488     spr_palette_tbl = malloc(PALETTE_TBL_SIZE);
489     if (spr_palette_tbl == NULL)
490         return FALSE;
491
492     memset(pattern_tbl0, 0, PATTERN_TBL_SIZE);
493     memset(pattern_tbl1, 0, PATTERN_TBL_SIZE);
494     memset(name_tbl0, 0, NAME_TBL_SIZE);
495     memset(name_tbl1, 0, NAME_TBL_SIZE);
496     memset(attr_tbl0, 0, ATTR_TBL_SIZE);
497     memset(attr_tbl1, 0, ATTR_TBL_SIZE);
498     memset(bg_palette_tbl, 0, PALETTE_TBL_SIZE);
499     memset(spr_palette_tbl, 0, PALETTE_TBL_SIZE);
500
501     //d4_set(debug_mode);
502     d4_set(FALSE);
503
504     return TRUE;
505 }
506
507 void clean_vram(void) {
508
509     free(pattern_tbl0);
510     free(pattern_tbl1);
511
512     free(name_tbl0);
513     free(name_tbl1);
514
515     free(attr_tbl0);
516     free(attr_tbl1);
517
518     free(bg_palette_tbl);
519     free(spr_palette_tbl);
520
521 }
522
523 static void null_write (unsigned short addr, unsigned char data) {}
524 static void dump_vram_write (unsigned short addr, unsigned char data) {
525     dprint("                                  ");
526     dprint("vram_data_set addr:%04x, data:%2x\n", addr, data);
527 }
528
529 void d4_set(int on_off) {
530     if (on_off) {
531         vram_log_level4 = dump_vram_write;
532     }
533     else {
534         vram_log_level4 = null_write;
535     }
536 }