summaryrefslogtreecommitdiff
path: root/ppu.c
blob: 52837ad943942c95ed4f1afa0e22b5547c8f9958 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include "ppu.h"

struct ppu ppu = {0};

static void
vram_addr_inc(void)
{
	ppu.regs.v += (ppu.ctrl.inc_mode) ? 32 : 1;
}

static uint16_t
vram_addr_mirror(uint16_t addr)
{
	uint8_t nametable;

	addr &= 0x2fff;
	addr -= 0x2000;
	nametable = addr / 0x400;

	switch (ppu.rom->mirror) {
	case M_HORIZONTAL:
		if (nametable == 1 || nametable == 2)
			return addr - 0x400;
		else if (nametable == 3)
			return addr - 0x800;
		break;
	case M_VERTICAL:
		if (nametable == 2 || nametable == 3)
			return addr - 0x800;
	default:
		break;
	};

	return addr;
}

void
ppu_tick(void)
{
	ppu.cycles++;
	if (ppu.cycles >= 341) {
		ppu.cycles -= 341;
		ppu.scanlines++;
	}
	if (ppu.scanlines >= 262)
		ppu.scanlines -= 262;
}

uint8_t
ppu_read(uint16_t addr)
{
	uint8_t tmp;

	switch (addr) {
	case 0x2002:
		tmp = (ppu.status.vblank << 7)
		    | (ppu.status.sprite0_hit << 6)
		    | (ppu.status.sprite_overflow << 5);

		ppu.status.vblank = 0;
		ppu.regs.w = 0;

		return tmp;
	case 0x2004:
		return ppu.oam[ppu.oam_addr];
	case 0x2007:
		vram_addr_inc();

		if (addr <= 0x1fff) {
			tmp = ppu.last_read;
			ppu.last_read = ppu.rom->chr_rom[ppu.regs.v];
			return tmp;
		} else if (addr <= 0x2fff) {
			tmp = ppu.last_read;
			ppu.last_read = ppu.vram[vram_addr_mirror(addr)];
			return tmp;
		}
	default:
		fprintf(stderr, "Invalid PPU read at address $%04\n", addr);
		return 0;
	}
}

void
ppu_write(uint16_t addr, uint8_t byte)
{
	static uint8_t prev;

	prev = byte;
}