forked from ulfalizer/nesalizer
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmapper_4.cpp
More file actions
157 lines (127 loc) · 4.36 KB
/
mapper_4.cpp
File metadata and controls
157 lines (127 loc) · 4.36 KB
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include "common.h"
#include "cpu.h"
#include "mapper.h"
#include "ppu.h"
#include "rom.h"
static unsigned reg_8000;
// regs[0-5] define CHR mappings, regs[6-7] PRG mappings
static unsigned regs[8];
// IRQs
static uint8_t irq_period;
static uint8_t irq_period_cnt;
static bool irq_enabled;
static void make_effective() {
// Second 8K PRG bank fixed to regs[7]
set_prg_8k_bank(1, regs[7]);
if (!(reg_8000 & 0x40)) {
// [ regs[6] | regs[7] | {-2} | {-1} ]
set_prg_8k_bank(0, regs[6]);
set_prg_8k_bank(2, 2*prg_16k_banks - 2);
}
else {
// [ {-2} | regs[7] | regs[6] | {-1} ]
set_prg_8k_bank(0, 2*prg_16k_banks - 2);
set_prg_8k_bank(2, regs[6]);
}
if (!(reg_8000 & 0x80)) {
// [ <regs[0]> | <regs[1]> | regs[2..5] ]
set_chr_2k_bank(0, regs[0] >> 1);
set_chr_2k_bank(1, regs[1] >> 1);
for (unsigned i = 0; i < 4; ++i)
set_chr_1k_bank(4 + i, regs[2 + i]);
}
else {
// [ regs[2..5] | <regs[0]> | <regs[1]> ]
for (unsigned i = 0; i < 4; ++i)
set_chr_1k_bank(i, regs[2 + i]);
set_chr_2k_bank(2, regs[0] >> 1);
set_chr_2k_bank(3, regs[1] >> 1);
}
}
void mapper_4_init() {
init_array(regs, (unsigned)0);
set_mirroring(HORIZONTAL); // Guess
// Last PRG 8K page fixed
set_prg_8k_bank(3, 2*prg_16k_banks - 1);
make_effective();
}
void mapper_4_write(uint8_t value, uint16_t addr) {
LOG_MAPPER("MMC3: Writing %02X to $%04X, at (%u,%u)\n", value, addr, scanline, dot);
switch (((addr >> 12) & 6) | (addr & 1)) {
case 0: // 0x8000
LOG_MAPPER("8000\n");
reg_8000 = value;
break;
case 1: // 0x8001
LOG_MAPPER("8001\n");
regs[reg_8000 & 7] = value;
break;
case 2: // 0xA000 ("Ignore when 4-screen")
LOG_MAPPER("A000\n");
set_mirroring(value & 1 ? HORIZONTAL : VERTICAL);
break;
case 3: // 0xA001
LOG_MAPPER("A001\n");
// WRAM stuff...
// Is PRG-RAM and WRAM/SRAM always into the same region?
break;
case 4: // 0xC000
LOG_MAPPER("MMC3: Setting IRQ period to %d, at scanline = %u, dot = %u\n", value, scanline, dot);
irq_period = value;
break;
case 5: // 0xC001
LOG_MAPPER("MMC3: Setting IRQ period counter to 0, at scanline = %u, dot = %u\n", scanline, dot);
// This causes the period to be reloaded at the next rising edge
irq_period_cnt = 0;
break;
case 6: // 0xE000
LOG_MAPPER("MMC3: Clearing IRQ enabled flag and IRQ line, at scanline = %u, dot = %u\n", scanline, dot);
cart_irq = irq_enabled = false;
update_irq_status();
break;
case 7: // 0xE001
LOG_MAPPER("MMC3: Enabling IRQs, at scanline = %u, dot = %u\n", scanline, dot);
irq_enabled = true;
break;
default: UNREACHABLE
}
make_effective();
}
// There is a short delay after A12 rises till IRQ is asserted, but it probably
// only matters for certain CPU/PPU alignments, if ever:
// http://forums.nesdev.com/viewtopic.php?f=3&t=10340&p=115998#p115996
//static unsigned delayed_irq;
static void clock_scanline_counter() {
// Revision A: assert IRQ when transitioning from non-zero to zero
// Revision B: assert IRQ when is zero
// Revision B implemented here
if (irq_period_cnt == 0) {
LOG_MAPPER("MMC3: Reloading IRQ period counter with %u, at scanline = %u, dot = %u\n", irq_period, scanline, dot);
irq_period_cnt = irq_period;
}
else {
LOG_MAPPER("MMC3: Decrementing IRQ period counter from %u to %u, at scanline = %u, dot = %u\n", irq_period_cnt, irq_period_cnt - 1, scanline, dot);
--irq_period_cnt;
}
if (irq_period_cnt == 0 && irq_enabled) {
LOG_MAPPER("MMC3: Asserting IRQ at scanline = %u, dot = %u\n", scanline, dot);
//delayed_irq = 3;
cart_irq = true;
update_irq_status();
}
}
static uint64_t last_a12_high_cycle;
unsigned const min_a12_rise_diff = 16;
void mmc3_ppu_tick_callback() {
//if (delayed_irq > 0) {
//if (--delayed_irq == 0) {
//cart_irq = true;
//update_irq_status();
//}
//}
if (ppu_addr_bus & 0x1000) {
if (ppu_cycle - last_a12_high_cycle >= min_a12_rise_diff)
clock_scanline_counter();
last_a12_high_cycle = ppu_cycle;
}
}