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