13 int vscreen_init(void);
14 void clean_vscreen(void);
15 int palette_init(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 int sprite_prefetch1(int srch_line);
24 int sprite_prefetch2(int srch_line);
25 int load_sprite(int background, int x, int y);
26 int load_background(int x, int y);
27 void vga_xfer(int x, int y);
28 void vga_posinit(void);
30 void dump_ppu_reg(void);
34 * hi bit > low bit order
35 * but gcc generates low > hi order for bit field
37 struct ppu_ctrl_reg1 {
38 unsigned int name_tbl_sel :2;
39 unsigned int addr_inc_size :1;
40 unsigned int sprite_ptn_sel :1;
41 unsigned int bg_ptn_addr_sel :1;
42 unsigned int sprite_size :1;
43 unsigned int ppu_mode :1;
44 unsigned int nmi_vblank :1;
45 } __attribute__ ((packed));
47 struct ppu_ctrl_reg2 {
48 unsigned int color_mode :1;
49 unsigned int show_left_8bg :1;
50 unsigned int show_left_8sprite :1;
51 unsigned int show_bg :1;
52 unsigned int show_sprite :1;
53 unsigned int intense_b :1;
54 unsigned int intense_g :1;
55 unsigned int intense_r :1;
56 } __attribute__ ((packed));
60 * but gcc generates low > hi order when bit field is used??
62 struct ppu_status_reg {
63 unsigned int nouse :4;
64 unsigned int vram_ignore :1;
65 unsigned int sprite_overflow :1;
66 unsigned int sprite0_hit :1;
67 unsigned int vblank :1;
68 } __attribute__ ((packed));
70 struct ppu_vram_addr_reg {
81 struct ppu_scroll_reg {
86 /*ppu core register instances*/
88 static struct ppu_ctrl_reg1 ctrl_reg1;
89 static struct ppu_ctrl_reg2 ctrl_reg2;
90 static struct ppu_status_reg status_reg;
91 static struct ppu_vram_addr_reg vram_addr_reg;
92 static struct ppu_scroll_reg scroll_reg;
93 static struct ppu_sprite_reg sprite_reg;
95 static unsigned char sprite_ram_addr_reg;
96 static unsigned char sprite_ram_dma_reg;
97 static unsigned char vram_data_reg;
98 static unsigned char vram_dma_reg;
100 //value set by the ctrl_reg1.
101 static unsigned char sprite_size_type;
102 static unsigned char vram_addr_inc;
103 static unsigned int vram_read_cnt;
105 #define SPR_STYPE_8x8 0
106 #define SPR_STYPE_8x16 1
108 #define SCAN_LINE (V_SCREEN_TILE_SIZE * TILE_DOT_SIZE)
113 static int scan_recovery(void) {
114 if (scan_y == VSCREEN_HEIGHT)
119 * Stores the y-coordinate of the top left of the sprite minus 1
121 if (scan_x == VSCREEN_WIDTH && scan_y < VSCREEN_HEIGHT) {
122 int next_line = (scan_y == VSCAN_MAX - 1 ? 0 : scan_y + 1);
123 sprite_prefetch1(next_line);
124 sprite_prefetch2(next_line);
130 static int clock_ppu(void) {
131 // dprint("ppu x:%d, y:%d...\n", scan_x, scan_y);
133 if (scan_x < VSCREEN_WIDTH && scan_y < VSCREEN_HEIGHT) {
135 status_reg.sprite0_hit = 0;
138 status_reg.vblank = 0;
139 status_reg.vram_ignore = 1;
143 if (ctrl_reg2.show_sprite) {
145 load_sprite(TRUE, scan_x, scan_y);
147 if (ctrl_reg2.show_bg/**/) {
148 //back ground image is pre-loaded. load 1 line ahead of drawline.
149 load_background(scan_x, scan_y);
151 if (ctrl_reg2.show_sprite) {
153 load_sprite(FALSE, scan_x, scan_y);
155 vga_xfer(scan_x, scan_y);
159 if (scan_x == 0 && scan_y == VSCREEN_HEIGHT) {
160 //printing display done.
161 status_reg.vblank = 1;
162 status_reg.vram_ignore = 0;
163 if (ctrl_reg1.nmi_vblank) {
164 //generate nmi interrupt to the cpu.
172 if (scan_x == HSCAN_MAX) {
176 if (scan_y == VSCAN_MAX) {
182 void ppu_ctrl1_set(unsigned char data) {
183 unsigned char old, diff_tmp;
184 struct ppu_ctrl_reg1 diff;
186 memcpy(&old, &ctrl_reg1, sizeof(ctrl_reg1));
187 memcpy(&ctrl_reg1, &data, sizeof(ctrl_reg1));
189 diff_tmp = old ^ data;
190 memcpy(&diff, &diff_tmp, sizeof(ctrl_reg1));
193 //if (diff.sprite_size)
194 // sprite_size = (ctrl_reg1.sprite_size == 0 ? 8 : 16);
196 //set bg base tbl addr
197 if (diff.bg_ptn_addr_sel)
198 set_bg_pattern_bank(ctrl_reg1.bg_ptn_addr_sel);
199 //set sprite base tbl addr
200 if (diff.sprite_ptn_sel)
201 set_spr_pattern_bank(ctrl_reg1.sprite_ptn_sel);
202 //set vram address increase unit
203 if (diff.addr_inc_size)
204 vram_addr_inc = (ctrl_reg1.addr_inc_size == 0 ? 1 : 32);
205 //set main screen addr
206 if (diff.name_tbl_sel)
207 set_bg_name_tbl_base(ctrl_reg1.name_tbl_sel);
209 //dprint("ctrl1: %x\n", data);
213 void ppu_ctrl2_set(unsigned char data) {
214 struct ppu_ctrl_reg2 old = ctrl_reg2;
216 memcpy(&ctrl_reg2, &data, sizeof(ctrl_reg2));
217 //dprint("ppu_ctrl2_set %d, show_bg:%d\n", data, ctrl_reg2.show_bg);
219 if (old.color_mode != ctrl_reg2.color_mode)
220 set_monocolor(ctrl_reg2.color_mode);
222 //dprint("ctrl2 %x:\n", data);
226 unsigned char ppu_status_get(void) {
228 memcpy(&ret, &status_reg, sizeof(status_reg));
230 //if read status reg, vram addr register counter is reset
231 vram_addr_reg.cnt = 0;
232 //dprint("ppu_status:%02x\n", ret);
236 void sprite_addr_set(unsigned char addr) {
237 //dprint("sprite_addr_set addr=%02x\n", addr);
238 sprite_ram_addr_reg = addr;
242 void sprite_data_set(unsigned char data) {
243 //dprint("sprite_data_set addr=%02x, data=%02x, cnt:%d\n",
244 // sprite_ram_addr_reg, data, sprite_reg.cnt);
245 switch (sprite_reg.cnt) {
251 sprite_reg.index = data;
254 memcpy(&sprite_reg.sa, &data, sizeof(struct sprite_attr));
260 spr_ram_tbl_set(sprite_ram_addr_reg + sprite_reg.cnt, data);
264 void ppu_scroll_set(unsigned char data) {
265 //dprint("scroll set %s = %02x\n", (scroll_reg.cnt == 0 ? "x" : "y"), data);
266 if (scroll_reg.cnt++ == 0)
272 void ppu_vram_addr_set(unsigned char half_addr) {
273 //dprint("vram addr:%04x\n", half_addr);
274 if (vram_addr_reg.cnt++ == 0)
275 vram_addr_reg.addr.b.hi = half_addr;
277 vram_addr_reg.addr.b.low = half_addr;
279 //when setting the addr, read cnt is reset.
283 void ppu_vram_data_set(unsigned char data) {
284 //check vram_ignore bit on write.
287 if (status_reg.vram_ignore)
290 //dprint("vram data:%04x\n", data);
291 vram_data_reg = data;
293 vram_data_set(vram_addr_reg.addr.s, data);
294 //vram addr increment.
295 vram_addr_reg.addr.s += vram_addr_inc;
298 unsigned char ppu_vram_data_get(void) {
299 if (vram_read_cnt++ == 0) {
300 //first read always fail.
304 vram_data_reg = vram_data_get(vram_addr_reg.addr.s);
305 //vram addr increment.
306 vram_addr_reg.addr.s += vram_addr_inc;
307 return vram_data_reg;
310 void sprite0_hit_set(void) {
311 //dprint("sprite0 set...\n");
312 status_reg.sprite0_hit = 1;
315 int ppucore_init(void) {
318 memset(&ctrl_reg1, 0, sizeof(ctrl_reg1));
319 memset(&ctrl_reg2, 0, sizeof(ctrl_reg1));
320 memset(&status_reg, 0, sizeof(status_reg));
321 memset(&vram_addr_reg, 0, sizeof(vram_addr_reg));
322 memset(&scroll_reg, 0, sizeof(scroll_reg));
323 memset(&sprite_reg, 0, sizeof(sprite_reg));
325 sprite_ram_addr_reg = 0;
326 sprite_ram_dma_reg = 0;
331 sprite_size_type = SPR_STYPE_8x8;
337 ret = vga_xfer_init();
345 ret = vscreen_init();
349 ret = palette_init();
356 ret = register_clock_hander(clock_ppu, PPU_DEVIDER);
366 void clean_ppucore(void) {
375 void dump_ppu_reg(void) {
376 printf("control reg1\n");
377 printf(" nmi_vblank:%d\n", ctrl_reg1.nmi_vblank);
378 printf(" sprite_size:%d\n", ctrl_reg1.sprite_size);
379 printf(" bg_ptn:%d\n", ctrl_reg1.bg_ptn_addr_sel);
380 printf(" spr_ptn:%d\n", ctrl_reg1.sprite_ptn_sel);
381 printf(" inc size:%d\n", ctrl_reg1.addr_inc_size);
382 printf(" name tbl:%d\n", ctrl_reg1.name_tbl_sel);
384 printf("\ncontrol reg2\n");
385 printf(" intense r:%d\n", ctrl_reg2.intense_r);
386 printf(" intense g:%d\n", ctrl_reg2.intense_g);
387 printf(" intense b:%d\n", ctrl_reg2.intense_b);
389 printf(" show spr:%d\n", ctrl_reg2.show_sprite);
390 printf(" show bg:%d\n", ctrl_reg2.show_bg);
391 printf(" left 8 pix spr:%d\n", ctrl_reg2.show_left_8sprite);
392 printf(" left 8 pix bg:%d\n", ctrl_reg2.show_left_8bg);
393 printf(" col mode:%d\n", ctrl_reg2.color_mode);