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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
static inline void ppu_tick(struct nes_state *state);
static uint8_t memory_read(struct nes_state *state, uint32_t offset);
static uint8_t memory_read_dma(struct nes_state *state, uint32_t offset);
// DMC frequency table (NTSC)
static const uint16_t dmc_rate_table[16] = {
428, 380, 340, 320, 286, 254, 226, 214,
190, 160, 142, 128, 106, 85, 72, 54
};
// $4015 write
static void apu_write4015(struct nes_state *state, uint8_t val) {
struct apu_state *apu = &state->apu;
if(val & 0x10) {
if(!apu->dmc_dma_enabled || apu->dmc_bytes_remaining == 0) {
apu->dmc_current_addr = 0xC000 + ((uint16_t)apu->dmc_sample_addr << 6);
apu->dmc_bytes_remaining = ((uint16_t)apu->dmc_sample_len << 4);
}
apu->dmc_dma_enabled = 1;
} else {
apu->dmc_dma_enabled = 0;
}
}
// $4015 read
static uint8_t apu_read4015(struct nes_state *state) {
struct apu_state *apu = &state->apu;
uint8_t result = 0;
if(apu->dmc_bytes_remaining > 0) {
result |= 0x10;
}
if(apu->irq_pending) {
result |= 0x40;
apu->irq_pending = 0;
}
return result;
}
// $4010–$4013, $4015 write
static void apu_write(struct nes_state *state, uint16_t addr, uint8_t val) {
struct apu_state *apu = &state->apu;
switch(addr) {
case 0x4010: {
apu->dmc_irq_enable = (val >> 7) & 1;
apu->dmc_loop_flag = (val >> 6) & 1;
apu->dmc_freq_index = val & 0x0F;
} break;
case 0x4011: {
// DAC write ignored
} break;
case 0x4012: {
apu->dmc_sample_addr = val;
} break;
case 0x4013: {
apu->dmc_sample_len = val;
} break;
case 0x4015: {
apu_write4015(state, val);
} break;
}
}
// APU tick
static inline void apu_tick(struct nes_state *state) {
struct apu_state *apu = &state->apu;
apu->frame_cycle++;
if(apu->mode == 0) {
if(apu->frame_cycle == 7457) {
// Quarter frame
} else if(apu->frame_cycle == 14913) {
// Quarter frame
// Half frame
} else if(apu->frame_cycle == 22371) {
// Quarter frame
} else if(apu->frame_cycle == 29829) {
// Half frame
if(!apu->irq_inhibit) {
apu->irq_pending = 1;
state->cpu.irq_pending = 1;
}
} else if(apu->frame_cycle >= 29830) {
apu->frame_cycle = 0;
}
} else {
if(apu->frame_cycle == 7457) {
// Quarter frame
} else if(apu->frame_cycle == 14913) {
// Quarter frame
// Half frame
} else if(apu->frame_cycle == 22371) {
// Quarter frame
} else if(apu->frame_cycle == 29829) {
// Half frame
} else if(apu->frame_cycle == 37281) {
// Quarter frame
} else if(apu->frame_cycle >= 37282) {
apu->frame_cycle = 0;
}
}
if(apu->dmc_dma_enabled && apu->dmc_bytes_remaining > 0) {
apu->dmc_sample_timer++;
if(apu->dmc_sample_timer >= dmc_rate_table[apu->dmc_freq_index]) {
apu->dmc_sample_timer = 0;
uint8_t val = memory_read(state, apu->dmc_current_addr);
(void)val;
apu->dmc_current_addr++;
if(apu->dmc_current_addr == 0x0000) {
apu->dmc_current_addr = 0x8000;
}
apu->dmc_bytes_remaining--;
if(apu->dmc_bytes_remaining == 0) {
if(apu->dmc_loop_flag) {
apu->dmc_current_addr = 0xc000 + ((uint16_t)apu->dmc_sample_addr << 6);
apu->dmc_bytes_remaining = ((uint16_t)apu->dmc_sample_len << 4);
} else {
if(apu->dmc_irq_enable) {
apu->irq_pending = 1;
state->cpu.irq_pending = 1;
}
apu->dmc_dma_enabled = 0;
}
}
for(uint32_t i = 0; i < 4; i++) {
state->cpu.cycles++;
ppu_tick(state);
}
}
}
}
|