OSDN Git Service

ppu reg update
[motonesemu/motonesemu.git] / emulator / ppucore / ppucore.c
1 #include <string.h>
2 #include <pthread.h>
3 #include <limits.h>
4 #include <stdio.h>
5
6 #include "tools.h"
7 #include "vram.h"
8 #include "ppucore.h"
9 #include "vga_xfer.h"
10
11 int vscreen_init(void);
12 void clean_vscreen(void);
13 int palette_init(void);
14 void vga_xfer(void);
15 void set_monocolor (int mono);
16 void set_nmi_pin(int val);
17 void set_bg_pattern_bank(unsigned char bank);
18 void set_spr_pattern_bank(unsigned char bank);
19 void set_bg_name_tbl_base(unsigned char sw);
20
21
22 void dump_ppu_reg(void);
23
24 /*
25  * 6502 little endian
26  * hi bit > low bit order
27  * but gcc generates low > hi order for bit field
28  * */
29 struct ppu_ctrl_reg1 {
30     unsigned int name_tbl_sel   :2;
31     unsigned int addr_inc_size  :1;
32     unsigned int sprite_ptn_sel :1;
33     unsigned int bg_ptn_addr_sel :1;
34     unsigned int sprite_size    :1;
35     unsigned int ppu_mode       :1;
36     unsigned int nmi_vblank     :1;
37 } __attribute__ ((packed));
38
39 struct ppu_ctrl_reg2 {
40     unsigned int color_mode     :1;
41     unsigned int show_left_8bg  :1;
42     unsigned int show_left_8sprite  :1;
43     unsigned int show_bg        :1;
44     unsigned int show_sprite    :1;
45     unsigned int intense_b      :1;
46     unsigned int intense_g      :1;
47     unsigned int intense_r      :1;
48 } __attribute__ ((packed));
49
50 /*
51  * 6502 little endian
52  * but gcc generates low > hi order when bit field is used??
53  * */
54 struct ppu_status_reg {
55     unsigned int nouse          :4;
56     unsigned int vram_ignore    :1;
57     unsigned int sprite_overflow    :1;
58     unsigned int sprite_0_hit   :1;
59     unsigned int vblank         :1;
60 } __attribute__ ((packed));
61
62 struct ppu_vram_addr_reg {
63     union {
64         struct {
65             unsigned char low;
66             unsigned char hi;
67         } b;
68         unsigned short s;
69     } addr;
70     unsigned int cnt :1;
71 };
72
73 /*ppu core register instances*/
74
75 static struct ppu_ctrl_reg1 ctrl_reg1;
76 static struct ppu_ctrl_reg2 ctrl_reg2;
77 static struct ppu_status_reg status_reg;
78 static struct ppu_vram_addr_reg vram_addr_reg;
79
80 static unsigned char sprite_ram_addr_reg;
81 static unsigned char sprite_ram_data_reg;
82 static unsigned char sprite_ram_dma_reg;
83 static unsigned char vram_data_reg;
84 static unsigned char scroll_reg;
85 static unsigned char vram_dma_reg;
86
87 //value set by the ctrl_reg1.
88 static unsigned char    sprite_size_type;
89 static unsigned char    vram_addr_inc;
90
91 #define SPR_STYPE_8x8   0 
92 #define SPR_STYPE_8x16  1
93
94 static pthread_t ppucore_thread_id;
95 static int ppucore_end_loop;
96
97 /*
98  * ppucore main loop.
99  * periodically update the display buffer.
100  * */
101 static void *ppucore_loop(void* arg) {
102     //struct timespec ts = {CPU_CLOCK_SEC, CPU_CLOCK_NSEC / 10};
103     struct timespec begin, end;
104     struct timespec slp;
105     long sec, nsec;
106 #define NANOMAX (1000000000 - 1)
107
108     while (!ppucore_end_loop) {
109         int updated = FALSE;
110
111         //start displaying
112         status_reg.vblank = 0;
113         status_reg.vram_ignore = 1;
114
115         clock_gettime(CLOCK_REALTIME, &begin);
116         if (ctrl_reg2.show_sprite) {
117             //sprite in the back
118             ;
119         }
120         if (ctrl_reg2.show_bg) {
121             //back ground image
122             updated |= show_background();
123         }
124         if (ctrl_reg2.show_sprite) {
125             //foreground sprite
126             ;
127         }
128         if (updated) 
129             vga_xfer();
130
131         //printing display done.
132         status_reg.vblank = 1;
133         status_reg.vram_ignore = 0;
134         if (ctrl_reg1.nmi_vblank) {
135             //generate nmi interrupt to the cpu.
136             set_nmi_pin(TRUE);
137         }
138
139         clock_gettime(CLOCK_REALTIME, &end);
140
141         //sleep rest of time...
142         if (end.tv_sec < begin.tv_sec )
143             sec = LONG_MAX - begin.tv_sec + end.tv_sec + 1;
144         else
145             sec = end.tv_sec - begin.tv_sec;
146
147         if (end.tv_nsec < begin.tv_nsec)
148             nsec = NANOMAX - begin.tv_nsec + end.tv_nsec + 1;
149         else
150             nsec = end.tv_nsec - begin.tv_nsec;
151
152         if (sec < NES_VIDEO_CLK_SEC || nsec < NES_VIDEO_CLK_NSEC) {
153             int ret;
154             slp.tv_sec = sec > NES_VIDEO_CLK_SEC ? 0 : NES_VIDEO_CLK_SEC - sec;
155             slp.tv_nsec = nsec > NES_VIDEO_CLK_NSEC ? 0 : NES_VIDEO_CLK_NSEC - nsec;
156
157             //dprint("%d.%09d sec sleep\n", slp.tv_sec, slp.tv_nsec);
158             ret = nanosleep(&slp, NULL);
159         }
160     }
161     return NULL;
162 }
163
164 void ppu_ctrl1_set(unsigned char data) {
165     unsigned char old, diff_tmp; 
166     struct ppu_ctrl_reg1 diff; 
167
168     memcpy(&old, &ctrl_reg1, sizeof(ctrl_reg1));
169     memcpy(&ctrl_reg1, &data, sizeof(ctrl_reg1));
170
171     diff_tmp = old ^ data;
172     memcpy(&diff, &diff_tmp, sizeof(ctrl_reg1));
173
174     //set sprite_size
175     //if (diff.sprite_size)
176     //    sprite_size = (ctrl_reg1.sprite_size == 0 ? 8 : 16);
177
178     //set bg base tbl addr
179     if (diff.bg_ptn_addr_sel)
180         set_bg_pattern_bank(ctrl_reg1.bg_ptn_addr_sel);
181     //set sprite base tbl addr
182     if (diff.sprite_ptn_sel) 
183         set_spr_pattern_bank(ctrl_reg1.sprite_ptn_sel);
184     //set vram address increase unit
185     if (diff.addr_inc_size) 
186         vram_addr_inc = (ctrl_reg1.addr_inc_size == 0 ? 1 : 32);
187     //set main screen addr
188     if (diff.name_tbl_sel)
189         set_bg_name_tbl_base(ctrl_reg1.name_tbl_sel);
190
191     //dprint("ctrl1: %x\n", data);
192     //dump_ppu_reg();
193 }
194
195 void ppu_ctrl2_set(unsigned char data) {
196     struct ppu_ctrl_reg2 old = ctrl_reg2;
197
198     memcpy(&ctrl_reg2, &data, sizeof(ctrl_reg2));
199     //dprint("ppu_ctrl2_set %d, show_bg:%d\n", data, ctrl_reg2.show_bg);
200
201     if (old.color_mode != ctrl_reg2.color_mode)
202         set_monocolor(ctrl_reg2.color_mode);
203
204     //dprint("ctrl2 %x:\n", data);
205     //dump_ppu_reg();
206 }
207
208 unsigned char ppu_status_get(void) {
209     unsigned char ret;
210     memcpy(&ret, &status_reg, sizeof(status_reg));
211     //dprint("ppu_status:%x\n", ret);
212     return ret;
213 }
214
215 void sprite_addr_set(unsigned char addr) {
216     sprite_ram_addr_reg = addr;
217 }
218
219 void sprite_data_set(unsigned char data) {
220     sprite_ram_data_reg = data;
221 }
222
223 void ppu_scroll_set(unsigned char data) {
224     scroll_reg = data;
225 }
226
227 void ppu_vram_addr_set(unsigned char half_addr) {
228     //dprint("vram addr:%04x\n", half_addr);
229     if (vram_addr_reg.cnt++ == 0)
230         vram_addr_reg.addr.b.hi = half_addr;
231     else
232         vram_addr_reg.addr.b.low = half_addr;
233 }
234
235 void ppu_vram_data_set(unsigned char data) {
236     //check vram_ignore bit on write.
237     if (status_reg.vram_ignore)
238         return;
239
240     //dprint("vram data:%04x\n", data);
241     vram_data_reg = data;
242
243     vram_data_set(vram_addr_reg.addr.s, data);
244     //vram addr increment.
245     vram_addr_reg.addr.s += vram_addr_inc;
246 }
247
248 unsigned char ppu_vram_data_get(void) {
249     return vram_data_reg;
250 }
251
252 int ppucore_init(void) {
253     int ret;
254     pthread_attr_t attr;
255
256     memset(&ctrl_reg1, 0, sizeof(ctrl_reg1));
257     memset(&ctrl_reg2, 0,  sizeof(ctrl_reg1));
258     memset(&status_reg, 0, sizeof(status_reg));
259     memset(&vram_addr_reg, 0, sizeof(vram_addr_reg));
260
261     sprite_ram_addr_reg = 0;
262     sprite_ram_data_reg = 0;
263     sprite_ram_dma_reg = 0;
264     vram_data_reg = 0;
265     scroll_reg = 0;
266     vram_dma_reg = 0;
267
268     sprite_size_type = SPR_STYPE_8x8;
269     vram_addr_inc = 1;
270
271     ret = vram_init();
272     if (!ret)
273         return FALSE;
274
275     ret = vga_xfer_init();
276     if (!ret)
277         return FALSE;
278
279     ret = vscreen_init();
280     if (!ret)
281         return FALSE;
282
283     ret = palette_init();
284     if (!ret)
285         return FALSE;
286
287     ppucore_end_loop = FALSE;
288     ret = pthread_attr_init(&attr);
289     if (ret != RT_OK) {
290         return FALSE;
291     }
292     ppucore_thread_id = 0;
293     ret = pthread_create(&ppucore_thread_id, &attr, ppucore_loop, NULL);
294     if (ret != RT_OK) {
295         return FALSE;
296     }
297
298
299     return TRUE;
300 }
301
302 void clean_ppucore(void) {
303     void* ret;
304     ppucore_end_loop = TRUE;
305     pthread_join(ppucore_thread_id, &ret);
306     dprint("ppucore thread joined.\n");
307
308     clean_vram();
309     clean_vscreen();
310 }
311
312 /*
313  * for debug.c
314  * */
315 void dump_ppu_reg(void) {
316     printf("control reg1\n");
317     printf(" nmi_vblank:%d\n", ctrl_reg1.nmi_vblank);
318     printf(" sprite_size:%d\n", ctrl_reg1.sprite_size);
319     printf(" bg_ptn:%d\n", ctrl_reg1.bg_ptn_addr_sel);
320     printf(" spr_ptn:%d\n", ctrl_reg1.sprite_ptn_sel);
321     printf(" inc size:%d\n", ctrl_reg1.addr_inc_size);
322     printf(" name tbl:%d\n", ctrl_reg1.name_tbl_sel);
323
324     printf("\ncontrol reg2\n");
325     printf(" intense r:%d\n", ctrl_reg2.intense_r);
326     printf(" intense g:%d\n", ctrl_reg2.intense_g);
327     printf(" intense b:%d\n", ctrl_reg2.intense_b);
328
329     printf(" show spr:%d\n", ctrl_reg2.show_sprite);
330     printf(" show bg:%d\n", ctrl_reg2.show_bg);
331     printf(" left 8 pix spr:%d\n", ctrl_reg2.show_left_8sprite);
332     printf(" left 8 pix bg:%d\n", ctrl_reg2.show_left_8bg);
333     printf(" col mode:%d\n", ctrl_reg2.color_mode);
334
335 }
336