11 int vscreen_init(void);
12 void clean_vscreen(void);
13 int palette_init(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);
22 void dump_ppu_reg(void);
26 * hi bit > low bit order
27 * but gcc generates low > hi order for bit field
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));
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));
52 * but gcc generates low > hi order when bit field is used??
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));
62 struct ppu_vram_addr_reg {
73 /*ppu core register instances*/
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;
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;
87 //value set by the ctrl_reg1.
88 static unsigned char sprite_size_type;
89 static unsigned char vram_addr_inc;
91 #define SPR_STYPE_8x8 0
92 #define SPR_STYPE_8x16 1
94 static pthread_t ppucore_thread_id;
95 static int ppucore_end_loop;
99 * periodically update the display buffer.
101 static void *ppucore_loop(void* arg) {
102 //struct timespec ts = {CPU_CLOCK_SEC, CPU_CLOCK_NSEC / 10};
103 struct timespec begin, end;
106 #define NANOMAX (1000000000 - 1)
108 while (!ppucore_end_loop) {
112 status_reg.vblank = 0;
113 status_reg.vram_ignore = 1;
115 clock_gettime(CLOCK_REALTIME, &begin);
116 if (ctrl_reg2.show_sprite) {
120 if (ctrl_reg2.show_bg) {
122 updated |= show_background();
124 if (ctrl_reg2.show_sprite) {
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.
139 clock_gettime(CLOCK_REALTIME, &end);
141 //sleep rest of time...
142 if (end.tv_sec < begin.tv_sec )
143 sec = LONG_MAX - begin.tv_sec + end.tv_sec + 1;
145 sec = end.tv_sec - begin.tv_sec;
147 if (end.tv_nsec < begin.tv_nsec)
148 nsec = NANOMAX - begin.tv_nsec + end.tv_nsec + 1;
150 nsec = end.tv_nsec - begin.tv_nsec;
152 if (sec < NES_VIDEO_CLK_SEC || nsec < NES_VIDEO_CLK_NSEC) {
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;
157 //dprint("%d.%09d sec sleep\n", slp.tv_sec, slp.tv_nsec);
158 ret = nanosleep(&slp, NULL);
164 void ppu_ctrl1_set(unsigned char data) {
165 unsigned char old, diff_tmp;
166 struct ppu_ctrl_reg1 diff;
168 memcpy(&old, &ctrl_reg1, sizeof(ctrl_reg1));
169 memcpy(&ctrl_reg1, &data, sizeof(ctrl_reg1));
171 diff_tmp = old ^ data;
172 memcpy(&diff, &diff_tmp, sizeof(ctrl_reg1));
175 //if (diff.sprite_size)
176 // sprite_size = (ctrl_reg1.sprite_size == 0 ? 8 : 16);
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);
191 //dprint("ctrl1: %x\n", data);
195 void ppu_ctrl2_set(unsigned char data) {
196 struct ppu_ctrl_reg2 old = ctrl_reg2;
198 memcpy(&ctrl_reg2, &data, sizeof(ctrl_reg2));
199 //dprint("ppu_ctrl2_set %d, show_bg:%d\n", data, ctrl_reg2.show_bg);
201 if (old.color_mode != ctrl_reg2.color_mode)
202 set_monocolor(ctrl_reg2.color_mode);
204 //dprint("ctrl2 %x:\n", data);
208 unsigned char ppu_status_get(void) {
210 memcpy(&ret, &status_reg, sizeof(status_reg));
211 //dprint("ppu_status:%x\n", ret);
215 void sprite_addr_set(unsigned char addr) {
216 sprite_ram_addr_reg = addr;
219 void sprite_data_set(unsigned char data) {
220 sprite_ram_data_reg = data;
223 void ppu_scroll_set(unsigned char data) {
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;
232 vram_addr_reg.addr.b.low = half_addr;
235 void ppu_vram_data_set(unsigned char data) {
236 //check vram_ignore bit on write.
237 if (status_reg.vram_ignore)
240 //dprint("vram data:%04x\n", data);
241 vram_data_reg = data;
243 vram_data_set(vram_addr_reg.addr.s, data);
244 //vram addr increment.
245 vram_addr_reg.addr.s += vram_addr_inc;
248 unsigned char ppu_vram_data_get(void) {
249 return vram_data_reg;
252 int ppucore_init(void) {
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));
261 sprite_ram_addr_reg = 0;
262 sprite_ram_data_reg = 0;
263 sprite_ram_dma_reg = 0;
268 sprite_size_type = SPR_STYPE_8x8;
275 ret = vga_xfer_init();
279 ret = vscreen_init();
283 ret = palette_init();
287 ppucore_end_loop = FALSE;
288 ret = pthread_attr_init(&attr);
292 ppucore_thread_id = 0;
293 ret = pthread_create(&ppucore_thread_id, &attr, ppucore_loop, NULL);
302 void clean_ppucore(void) {
304 ppucore_end_loop = TRUE;
305 pthread_join(ppucore_thread_id, &ret);
306 dprint("ppucore thread joined.\n");
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);
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);
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);