summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/nes/rexsoft.cpp
blob: c10b88afe01972cb89b33fb4f4b91b24fc8a920d (plain) (blame)
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
// license:BSD-3-Clause
// copyright-holders:Fabio Priuli
/***********************************************************************************************************


 NES/Famicom cartridge emulation for Rex Soft PCBs


 Here we emulate the following PCBs

 * Rex Soft Dragon Ball Z V [mapper 12]
 * Rex Soft SL-1632 [mapper 14]

 TODO:
 - fix 0x6000-0x7fff accesses, write_m/read_m
 - check glitches in SL-1632

 ***********************************************************************************************************/


#include "emu.h"
#include "rexsoft.h"


#ifdef NES_PCB_DEBUG
#define VERBOSE 1
#else
#define VERBOSE 0
#endif

#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)


//-------------------------------------------------
//  constructor
//-------------------------------------------------

DEFINE_DEVICE_TYPE(NES_REX_DBZ5,   nes_rex_dbz5_device,   "nes_rex_dbz5",   "NES Cart Rex Soft Dragon Ball Z V PCB")
DEFINE_DEVICE_TYPE(NES_REX_SL1632, nes_rex_sl1632_device, "nes_rex_sl1632", "NES Cart Rex Soft SL-1632 PCB")


nes_rex_dbz5_device::nes_rex_dbz5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: nes_txrom_device(mconfig, NES_REX_DBZ5, tag, owner, clock)
	, m_extra(0)
{
}

nes_rex_sl1632_device::nes_rex_sl1632_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: nes_txrom_device(mconfig, NES_REX_SL1632, tag, owner, clock), m_mode(0), m_mirror(0)
{
}




void nes_rex_dbz5_device::device_start()
{
	mmc3_start();
	save_item(NAME(m_extra));
}

void nes_rex_dbz5_device::pcb_reset()
{
	m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
	m_extra = 0;
	mmc3_common_initialize(0xff, 0xff, 0);
}

void nes_rex_sl1632_device::device_start()
{
	mmc3_start();
	save_item(NAME(m_mode));
	save_item(NAME(m_mirror));
	save_item(NAME(m_extra_bank));
}

void nes_rex_sl1632_device::pcb_reset()
{
	m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;

	m_mode = 0;
	m_mirror = 0;
	memset(m_extra_bank, 0, sizeof(m_extra_bank));
	m_extra_bank[2] = 0xfe;
	m_extra_bank[3] = 0xff;
	mmc3_common_initialize(0xff, 0xff, 0);
}





/*-------------------------------------------------
 mapper specific handlers
 -------------------------------------------------*/

/*-------------------------------------------------

 Bootleg Board by Rex Soft

 Games: Dragon Ball Z 5, Dragon Ball Z Super

 MMC3 clone. Writes to 0x4100-0x5fff (or from 0x4020?)
 possibly select higher VROM pages (to allow up to
 512 banks instead of 256 only): bit0 selects the
 higher pages for PPU banks 0-3 (0x0000-0x0fff), while
 bit4 selects the higher pages for PPU banks 4-7 (0x1000-0x1fff)

 iNES: mapper 12

 In MESS: Supported

 -------------------------------------------------*/

void nes_rex_dbz5_device::write_l(offs_t offset, uint8_t data)
{
	LOG_MMC(("rex_dbz write_l, offset: %04x, data: %02x\n", offset, data));

	m_extra = data;
	set_chr(m_chr_source, m_chr_base, m_chr_mask);
}

/* we would need to use this read handler in 0x6000-0x7fff as well */
uint8_t nes_rex_dbz5_device::read_l(offs_t offset)
{
	LOG_MMC(("rex_dbz read_l, offset: %04x\n", offset));
	return 0x01;
}

void nes_rex_dbz5_device::chr_cb(int start, int bank, int source)
{
	int shift = (start < 4) ? 8 : 4;

	bank |= ((m_extra << shift) & 0x100);
	chr1_x(start, bank, source);
}

/*-------------------------------------------------

 Rex Soft SL1632 Board

 Games: Samurai Spirits

 MMC3 clone

 iNES: mapper 14

 In MESS: Supported

 -------------------------------------------------*/

void nes_rex_sl1632_device::set_prg(int prg_base, int prg_mask)
{
	if (m_mode & 0x02)
	{
		// here standard MMC3 bankswitch
		uint8_t prg_flip = (m_latch & 0x40) ? 2 : 0;

		prg_cb(0, prg_base | (m_mmc_prg_bank[0 ^ prg_flip] & prg_mask));
		prg_cb(1, prg_base | (m_mmc_prg_bank[1] & prg_mask));
		prg_cb(2, prg_base | (m_mmc_prg_bank[2 ^ prg_flip] & prg_mask));
		prg_cb(3, prg_base | (m_mmc_prg_bank[3] & prg_mask));
	}
	else
	{
		prg8_89(m_extra_bank[0]);
		prg8_ab(m_extra_bank[1]);
		prg8_cd(m_extra_bank[2]);
		prg8_ef(m_extra_bank[3]);
	}
}

void nes_rex_sl1632_device::set_chr(uint8_t chr, int chr_base, int chr_mask)
{
	static const uint8_t conv_table[8] = {5, 5, 5, 5, 3, 3, 1, 1};
	uint8_t chr_page = (m_latch & 0x80) >> 5;
	uint8_t bank[8];
	uint8_t chr_base2[8];

	if (m_mode & 0x02)
	{
		for (int i = 0; i < 8; i++)
		{
			// since the mapper acts on 1K CHR chunks, we have 8 banks which use the 6 m_mmc_vrom_bank from MMC3 base class
			if (i < 4)
				bank[i] = ((m_mmc_vrom_bank[i / 2] & 0xfe) | (i & 1));
			else
				bank[i] = m_mmc_vrom_bank[i - 2];
			chr_base2[i] = chr_base | ((m_mode << conv_table[i]) & 0x100);
		}
	}
	else
	{
		for (int i = 0; i < 8; i++)
		{
			bank[i] = m_extra_bank[i + 4];   // first 4 m_extra_banks are PRG
			chr_base2[i] = chr_base;
		}
	}

	chr1_x(chr_page ^ 0, chr_base2[0] | (bank[0] & chr_mask), chr);
	chr1_x(chr_page ^ 1, chr_base2[1] | (bank[1] & chr_mask), chr);
	chr1_x(chr_page ^ 2, chr_base2[2] | (bank[2] & chr_mask), chr);
	chr1_x(chr_page ^ 3, chr_base2[3] | (bank[3] & chr_mask), chr);
	chr1_x(chr_page ^ 4, chr_base2[4] | (bank[4] & chr_mask), chr);
	chr1_x(chr_page ^ 5, chr_base2[5] | (bank[5] & chr_mask), chr);
	chr1_x(chr_page ^ 6, chr_base2[6] | (bank[6] & chr_mask), chr);
	chr1_x(chr_page ^ 7, chr_base2[7] | (bank[7] & chr_mask), chr);
}

void nes_rex_sl1632_device::write_h(offs_t offset, uint8_t data)
{
	uint8_t helper1, helper2;
	LOG_MMC(("rex_sl1632 write_h, offset: %04x, data: %02x\n", offset, data));

	if (offset == 0x2131)
	{
		m_mode = data;
		set_prg(m_prg_base, m_prg_mask);
		set_chr(m_chr_source, m_chr_base, m_chr_mask);

		if (!(m_mode & 0x02))
			set_nt_mirroring(BIT(m_mirror, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
	}

	if (m_mode & 0x02)
	{
		switch (offset & 0x6001)
		{
			case 0x2000:
				set_nt_mirroring(BIT(m_mirror, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
				break;

			default:
				txrom_write(offset, data);
				break;
		}
	}
	else if (offset >= 0x3000 && offset <= 0x6003)
	{
		helper1 = (offset & 0x01) << 2;
		offset = ((offset & 0x02) | (offset >> 10)) >> 1;
		helper2 = ((offset + 2) & 0x07) + 4; // '+4' because first 4 m_extra_banks are for PRG!
		m_extra_bank[helper2] = (m_extra_bank[helper2] & (0xf0 >> helper1)) | ((data & 0x0f) << helper1);
		set_chr(m_chr_source, m_chr_base, m_chr_mask);
	}
	else
	{
		switch (offset & 0x7003)
		{
			case 0x0000:
			case 0x2000:
				m_extra_bank[offset >> 13] = data;
				set_prg(m_prg_base, m_prg_mask);
				break;

			case 0x1000:
				m_mirror = data;
				set_nt_mirroring(BIT(m_mirror, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
				break;
		}
	}
}