13 int init_vscreen(void);
14 void clean_vscreen(void);
15 int init_palette(void);
16 void set_monocolor (int mono);
17 void set_nmi_pin(int val);
18 void set_bg_pattern_bank(unsigned char bank);
19 void set_spr_pattern_bank(unsigned char bank);
20 void set_bg_name_tbl_base(unsigned char sw);
21 void spr_ram_tbl_set(unsigned short offset, unsigned char data);
23 void set_vscreen_pos(int x, int y);
24 int sprite_prefetch1(int srch_line);
25 int sprite_prefetch2(int srch_line);
26 int load_sprite(int background, int x, int y);
27 int load_background(int x, int y);
28 void vga_xfer(int x, int y);
29 void vga_posinit(void);
31 void dump_ppu_reg(void);
35 * hi bit > low bit order
36 * but gcc generates low > hi order for bit field
38 struct ppu_ctrl_reg1 {
39 unsigned int name_tbl_sel :2;
40 unsigned int addr_inc_size :1;
41 unsigned int sprite_ptn_sel :1;
42 unsigned int bg_ptn_addr_sel :1;
43 unsigned int sprite_size :1;
44 unsigned int ppu_mode :1;
45 unsigned int nmi_vblank :1;
46 } __attribute__ ((packed));
48 struct ppu_ctrl_reg2 {
49 unsigned int color_mode :1;
50 unsigned int show_left_8bg :1;
51 unsigned int show_left_8sprite :1;
52 unsigned int show_bg :1;
53 unsigned int show_sprite :1;
54 unsigned int intense_b :1;
55 unsigned int intense_g :1;
56 unsigned int intense_r :1;
57 } __attribute__ ((packed));
61 * but gcc generates low > hi order when bit field is used??
63 struct ppu_status_reg {
64 unsigned int nouse :4;
65 unsigned int vram_ignore :1;
66 unsigned int sprite_overflow :1;
67 unsigned int sprite0_hit :1;
68 unsigned int vblank :1;
69 } __attribute__ ((packed));
71 struct ppu_vram_addr_reg {
82 struct ppu_scroll_reg {
87 /*ppu core register instances*/
89 static struct ppu_ctrl_reg1 ctrl_reg1;
90 static struct ppu_ctrl_reg2 ctrl_reg2;
91 static struct ppu_status_reg status_reg;
92 static struct ppu_vram_addr_reg vram_addr_reg;
93 static struct ppu_scroll_reg scroll_reg;
94 static struct ppu_sprite_reg sprite_reg;
96 static unsigned char sprite_ram_addr_reg;
97 static unsigned char sprite_ram_dma_reg;
98 static unsigned char vram_data_reg;
99 static unsigned char vram_dma_reg;
101 //value set by the ctrl_reg1.
102 static unsigned char sprite_size_type;
103 static unsigned char vram_addr_inc;
104 static unsigned int vram_read_cnt;
106 #define SPR_STYPE_8x8 0
107 #define SPR_STYPE_8x16 1
109 #define SCAN_LINE (V_SCREEN_TILE_SIZE * TILE_DOT_SIZE)
114 static int scan_recovery(void) {
115 if (scan_y == VSCREEN_HEIGHT)
120 * Stores the y-coordinate of the top left of the sprite minus 1
122 if (scan_x == HSCAN_MAX - 1 && scan_y < VSCREEN_HEIGHT) {
123 int next_line = (scan_y == VSCAN_MAX - 1 ? 0 : scan_y + 1);
124 sprite_prefetch1(next_line);
125 sprite_prefetch2(next_line);
131 static int clock_ppu(void) {
132 // dprint("ppu x:%d, y:%d...\n", scan_x, scan_y);
134 if (scan_x < VSCREEN_WIDTH && scan_y < VSCREEN_HEIGHT) {
136 status_reg.sprite0_hit = 0;
137 status_reg.sprite_overflow = 0;
140 status_reg.vblank = 0;
144 set_vscreen_pos(scan_x, scan_y);
145 if (ctrl_reg2.show_sprite) {
147 load_sprite(TRUE, scan_x, scan_y);
149 if (ctrl_reg2.show_bg/**/) {
150 //back ground image is pre-loaded. load 1 line ahead of drawline.
151 load_background(scan_x + scroll_reg.x, scan_y + scroll_reg.y);
153 if (ctrl_reg2.show_sprite) {
155 load_sprite(FALSE, scan_x, scan_y);
157 vga_xfer(scan_x, scan_y);
161 if (scan_x == 0 && scan_y == VSCREEN_HEIGHT) {
162 //printing display done.
163 status_reg.vblank = 1;
164 if (ctrl_reg1.nmi_vblank) {
165 //generate nmi interrupt to the cpu.
173 if (scan_x == HSCAN_MAX) {
177 if (scan_y == VSCAN_MAX) {
183 void ppu_ctrl1_set(unsigned char data) {
184 unsigned char old, diff_tmp;
185 struct ppu_ctrl_reg1 diff;
187 memcpy(&old, &ctrl_reg1, sizeof(ctrl_reg1));
188 memcpy(&ctrl_reg1, &data, sizeof(ctrl_reg1));
190 diff_tmp = old ^ data;
191 memcpy(&diff, &diff_tmp, sizeof(ctrl_reg1));
194 //if (diff.sprite_size)
195 // sprite_size = (ctrl_reg1.sprite_size == 0 ? 8 : 16);
197 //set bg base tbl addr
198 if (diff.bg_ptn_addr_sel)
199 set_bg_pattern_bank(ctrl_reg1.bg_ptn_addr_sel);
200 //set sprite base tbl addr
201 if (diff.sprite_ptn_sel)
202 set_spr_pattern_bank(ctrl_reg1.sprite_ptn_sel);
203 //set vram address increase unit
204 if (diff.addr_inc_size)
205 vram_addr_inc = (ctrl_reg1.addr_inc_size == 0 ? 1 : 32);
206 //set main screen addr
207 if (diff.name_tbl_sel)
208 set_bg_name_tbl_base(ctrl_reg1.name_tbl_sel);
210 //dprint("ctrl1: %x\n", data);
214 void ppu_ctrl2_set(unsigned char data) {
215 struct ppu_ctrl_reg2 old = ctrl_reg2;
217 memcpy(&ctrl_reg2, &data, sizeof(ctrl_reg2));
218 //dprint("ppu_ctrl2_set %d, show_bg:%d\n", data, ctrl_reg2.show_bg);
220 if (old.color_mode != ctrl_reg2.color_mode)
221 set_monocolor(ctrl_reg2.color_mode);
223 //dprint("ctrl2 %x:\n", data);
227 unsigned char ppu_status_get(void) {
229 memcpy(&ret, &status_reg, sizeof(status_reg));
231 //if read status reg, vram addr register counter is reset
232 vram_addr_reg.cnt = 0;
233 //dprint("ppu_status:%02x\n", ret);
235 //reading status resets the vblank flg.
236 status_reg.vblank = 0;
240 void sprite_addr_set(unsigned char addr) {
241 //dprint("sprite_addr_set addr=%02x\n", addr);
242 sprite_ram_addr_reg = addr;
246 void sprite_data_set(unsigned char data) {
247 //dprint("sprite_data_set addr=%02x, data=%02x, cnt:%d\n",
248 // sprite_ram_addr_reg, data, sprite_reg.cnt);
249 switch (sprite_reg.cnt) {
255 sprite_reg.index = data;
258 memcpy(&sprite_reg.sa, &data, sizeof(struct sprite_attr));
264 spr_ram_tbl_set(sprite_ram_addr_reg + sprite_reg.cnt, data);
268 void ppu_scroll_set(unsigned char data) {
269 //dprint("scroll set %s = %02x\n", (scroll_reg.cnt == 0 ? "x" : "y"), data);
270 if (scroll_reg.cnt++ == 0)
276 void ppu_vram_addr_set(unsigned char half_addr) {
277 //dprint("vram addr:%04x\n", half_addr);
278 if (vram_addr_reg.cnt++ == 0)
279 vram_addr_reg.addr.b.hi = half_addr;
281 vram_addr_reg.addr.b.low = half_addr;
283 //when setting the addr, read cnt is reset.
287 void ppu_vram_data_set(unsigned char data) {
288 //check vram_ignore bit on write.
290 * TODO ignore bit set timing is unknown.
292 if (status_reg.vram_ignore)
295 //dprint("vram data:%04x\n", data);
296 vram_data_reg = data;
298 vram_data_set(vram_addr_reg.addr.s, data);
299 //vram addr increment.
300 vram_addr_reg.addr.s += vram_addr_inc;
303 unsigned char ppu_vram_data_get(void) {
304 if (vram_read_cnt++ == 0) {
305 //first read always fail.
309 vram_data_reg = vram_data_get(vram_addr_reg.addr.s);
310 //vram addr increment.
311 vram_addr_reg.addr.s += vram_addr_inc;
312 return vram_data_reg;
315 void sprite0_hit_set(void) {
316 //dprint("sprite0 set...\n");
317 status_reg.sprite0_hit = 1;
320 void sprite_overflow_set(void) {
321 //dprint("sprite0 set...\n");
322 status_reg.sprite_overflow = 1;
325 int init_ppucore(void) {
328 memset(&ctrl_reg1, 0, sizeof(ctrl_reg1));
329 memset(&ctrl_reg2, 0, sizeof(ctrl_reg1));
330 memset(&status_reg, 0, sizeof(status_reg));
331 memset(&vram_addr_reg, 0, sizeof(vram_addr_reg));
332 memset(&scroll_reg, 0, sizeof(scroll_reg));
333 memset(&sprite_reg, 0, sizeof(sprite_reg));
335 sprite_ram_addr_reg = 0;
336 sprite_ram_dma_reg = 0;
341 sprite_size_type = SPR_STYPE_8x8;
347 ret = init_vga_xfer();
355 ret = init_vscreen();
359 ret = init_palette();
366 ret = register_clock_hander(clock_ppu, PPU_DEVIDER);
376 void clean_ppucore(void) {
385 void dump_ppu_reg(void) {
386 printf("control reg1\n");
387 printf(" nmi_vblank:%d\n", ctrl_reg1.nmi_vblank);
388 printf(" sprite_size:%d\n", ctrl_reg1.sprite_size);
389 printf(" bg_ptn:%d\n", ctrl_reg1.bg_ptn_addr_sel);
390 printf(" spr_ptn:%d\n", ctrl_reg1.sprite_ptn_sel);
391 printf(" inc size:%d\n", ctrl_reg1.addr_inc_size);
392 printf(" name tbl:%d\n", ctrl_reg1.name_tbl_sel);
394 printf("\ncontrol reg2\n");
395 printf(" intense r:%d\n", ctrl_reg2.intense_r);
396 printf(" intense g:%d\n", ctrl_reg2.intense_g);
397 printf(" intense b:%d\n", ctrl_reg2.intense_b);
399 printf(" show spr:%d\n", ctrl_reg2.show_sprite);
400 printf(" show bg:%d\n", ctrl_reg2.show_bg);
401 printf(" left 8 pix spr:%d\n", ctrl_reg2.show_left_8sprite);
402 printf(" left 8 pix bg:%d\n", ctrl_reg2.show_left_8bg);
403 printf(" col mode:%d\n", ctrl_reg2.color_mode);
405 printf("\nstatus reg\n");
406 printf(" vram_ignore:%d\n", status_reg.vram_ignore);
407 printf(" sprite_overflow:%d\n", status_reg.sprite_overflow);
408 printf(" sprite0_hit:%d\n", status_reg.sprite0_hit);
409 printf(" vblank:%d\n", status_reg.vblank);
411 printf("\nvram_addr_reg:%04x\n", vram_addr_reg.addr.s);
412 printf("vram_data_reg:%02x\n", vram_data_reg);
413 printf("\nscroll_reg:\n");
414 printf(" x:%d\n", scroll_reg.x);
415 printf(" y:%d\n", scroll_reg.y);