1 // license:BSD-3-Clause
2 // copyright-holders:Fabio Priuli
3 /***********************************************************************************************************
4
5
6 NES/Famicom cartridge emulation for FFE PCBs
7
8
9 Here we emulate the mappers used by available Far Front East copier hacked games [mappers 6, 8, 17]
10
11 TODO:
12 - investigate IRQ mechanism (current code is broken)
13 - replace this with proper copier emulation, using disk images...
14
15 ***********************************************************************************************************/
16
17
18 #include "emu.h"
19 #include "legacy.h"
20
21
22 #ifdef NES_PCB_DEBUG
23 #define VERBOSE 1
24 #else
25 #define VERBOSE 0
26 #endif
27
28 #define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
29
30
31 //-------------------------------------------------
32 // constructor
33 //-------------------------------------------------
34
35 DEFINE_DEVICE_TYPE(NES_FFE3, nes_ffe3_device, "nes_ff3", "NES Cart FFE-3 PCB")
36 DEFINE_DEVICE_TYPE(NES_FFE4, nes_ffe4_device, "nes_ff4", "NES Cart FFE-4 PCB")
37 DEFINE_DEVICE_TYPE(NES_FFE8, nes_ffe8_device, "nes_ff8", "NES Cart FFE-8 PCB")
38
39
nes_ffe3_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)40 nes_ffe3_device::nes_ffe3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
41 : nes_nrom_device(mconfig, NES_FFE3, tag, owner, clock)
42 {
43 }
44
nes_ffe4_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)45 nes_ffe4_device::nes_ffe4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
46 : nes_nrom_device(mconfig, type, tag, owner, clock), m_irq_count(0), m_irq_enable(0), irq_timer(nullptr), m_latch(0), m_exram_enabled(0), m_exram_bank(0)
47 {
48 }
49
nes_ffe4_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)50 nes_ffe4_device::nes_ffe4_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
51 : nes_ffe4_device(mconfig, NES_FFE4, tag, owner, clock)
52 {
53 }
54
nes_ffe8_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)55 nes_ffe8_device::nes_ffe8_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
56 : nes_ffe4_device(mconfig, NES_FFE8, tag, owner, clock)
57 {
58 }
59
60
61
device_start()62 void nes_ffe3_device::device_start()
63 {
64 common_start();
65 }
66
pcb_reset()67 void nes_ffe3_device::pcb_reset()
68 {
69 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
70 prg32(0);
71 chr8(0, m_chr_source);
72 }
73
74
device_start()75 void nes_ffe4_device::device_start()
76 {
77 common_start();
78 irq_timer = timer_alloc(TIMER_IRQ);
79 irq_timer->adjust(attotime::zero, 0, clocks_to_attotime(1));
80
81 save_item(NAME(m_exram));
82 save_item(NAME(m_exram_enabled));
83 save_item(NAME(m_exram_bank));
84
85 save_item(NAME(m_irq_enable));
86 save_item(NAME(m_irq_count));
87 save_item(NAME(m_latch));
88 }
89
pcb_reset()90 void nes_ffe4_device::pcb_reset()
91 {
92 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
93 prg16_89ab(0);
94 prg16_cdef(7);
95 chr8(0, m_chr_source);
96
97 m_exram_enabled = 0;
98 m_exram_bank = 0;
99
100 m_latch = 0;
101 m_irq_enable = 0;
102 m_irq_count = 0;
103 }
104
105
pcb_reset()106 void nes_ffe8_device::pcb_reset()
107 {
108 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
109 prg16_89ab(0);
110 prg16_cdef(0xff);
111 chr8(0, m_chr_source);
112
113 // extra vram is not used by this board, so these will remain always zero
114 m_exram_enabled = 0;
115 m_exram_bank = 0;
116
117 m_latch = 0;
118 m_irq_enable = 0;
119 m_irq_count = 0;
120 }
121
122
123
124 /*-------------------------------------------------
125 mapper specific handlers
126 -------------------------------------------------*/
127
128 /*-------------------------------------------------
129
130 Mapper 8
131
132 Known Boards: FFE3 Copier Board
133 Games: Hacked versions of games
134
135 In MESS: Supported? (I have no games to test this)
136
137 -------------------------------------------------*/
138
write_h(offs_t offset,uint8_t data)139 void nes_ffe3_device::write_h(offs_t offset, uint8_t data)
140 {
141 LOG_MMC(("mapper8 write_h, offset: %04x, data: %02x\n", offset, data));
142
143 chr8(data & 0x07, CHRROM);
144 prg16_89ab(data >> 3);
145 }
146
147 /*-------------------------------------------------
148
149 Mapper 6
150
151 Known Boards: FFE4 Copier Board
152 Games: Hacked versions of games
153
154 In MESS: Supported? Not sure if we could also have ExRAM or not...
155 However, priority is pretty low for this mapper.
156
157 -------------------------------------------------*/
158
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)159 void nes_ffe4_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
160 {
161 if (id == TIMER_IRQ)
162 {
163 if (m_irq_enable)
164 {
165 if (m_irq_count == 0xffff)
166 {
167 set_irq_line(ASSERT_LINE);
168 m_irq_count = 0;
169 m_irq_enable = 0;
170 }
171 else
172 m_irq_count++;
173 }
174 }
175 }
176
write_l(offs_t offset,uint8_t data)177 void nes_ffe4_device::write_l(offs_t offset, uint8_t data)
178 {
179 LOG_MMC(("mapper6 write_l, offset: %04x, data: %02x\n", offset, data));
180
181 switch (offset)
182 {
183 case 0x1fe:
184 m_latch = data & 0x80;
185 set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
186 break;
187 case 0x1ff:
188 set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
189 break;
190
191 case 0x401:
192 m_irq_enable = 0;
193 set_irq_line(CLEAR_LINE);
194 break;
195 case 0x402:
196 m_irq_count = (m_irq_count & 0xff00) | data;
197 break;
198 case 0x403:
199 m_irq_enable = 1;
200 m_irq_count = (m_irq_count & 0x00ff) | (data << 8);
201 break;
202 }
203 }
204
chr_w(offs_t offset,uint8_t data)205 void nes_ffe4_device::chr_w(offs_t offset, uint8_t data)
206 {
207 int bank = offset >> 10;
208 if (m_exram_enabled)
209 m_exram[(m_exram_bank * 0x2000) + (bank * 0x400) + (offset & 0x3ff)] = data;
210
211 if (m_chr_src[bank] == CHRRAM)
212 m_chr_access[bank][offset & 0x3ff] = data;
213 }
214
chr_r(offs_t offset)215 uint8_t nes_ffe4_device::chr_r(offs_t offset)
216 {
217 int bank = offset >> 10;
218 if (m_exram_enabled)
219 return m_exram[(m_exram_bank * 0x2000) + (bank * 0x400) + (offset & 0x3ff)];
220
221 return m_chr_access[bank][offset & 0x3ff];
222 }
223
224
write_h(offs_t offset,uint8_t data)225 void nes_ffe4_device::write_h(offs_t offset, uint8_t data)
226 {
227 LOG_MMC(("mapper6 write_h, offset: %04x, data: %02x\n", offset, data));
228
229 if (!m_latch) // when in "FFE mode" we are forced to use CHRRAM/EXRAM bank?
230 {
231 prg16_89ab(data >> 2);
232
233 // This part is not fully documented, so we proceed a bit blindly...
234 if ((data & 0x03) == 0)
235 {
236 m_exram_enabled = 0;
237 chr8(0, CHRRAM);
238 }
239 else
240 {
241 m_exram_enabled = 1;
242 m_exram_bank = data & 0x03;
243 }
244 }
245 else // otherwise, we use CHRROM (shall we check if it's present?)
246 chr8(data, CHRROM);
247 }
248
249 /*-------------------------------------------------
250
251 Mapper 17
252
253 Known Boards: FFE8 Copier Board
254 Games: Hacked versions of games
255
256 In MESS: Partially Supported.
257
258 -------------------------------------------------*/
259
write_l(offs_t offset,uint8_t data)260 void nes_ffe8_device::write_l(offs_t offset, uint8_t data)
261 {
262 LOG_MMC(("mapper17 write_l, offset: %04x, data: %02x\n", offset, data));
263
264 switch (offset)
265 {
266 case 0x1fe:
267 set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
268 break;
269 case 0x1ff:
270 set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
271 break;
272
273 case 0x401:
274 m_irq_enable = 0;
275 set_irq_line(CLEAR_LINE);
276 break;
277 case 0x402:
278 m_irq_count = (m_irq_count & 0xff00) | data;
279 break;
280 case 0x403:
281 m_irq_enable = 1;
282 m_irq_count = (m_irq_count & 0x00ff) | (data << 8);
283 break;
284
285 case 0x404:
286 prg8_89(data);
287 break;
288 case 0x405:
289 prg8_ab(data);
290 break;
291 case 0x406:
292 prg8_cd(data);
293 break;
294 case 0x407:
295 prg8_ef(data);
296 break;
297
298 case 0x410:
299 case 0x411:
300 case 0x412:
301 case 0x413:
302 case 0x414:
303 case 0x415:
304 case 0x416:
305 case 0x417:
306 chr1_x(offset & 7, data, CHRROM);
307 break;
308 }
309 }
310