1 // license:BSD-3-Clause
2 // copyright-holders:Fabio Priuli
3 /***********************************************************************************************************
4 
5 
6  PC-Engine & Turbografx-16 cart emulation
7 
8 
9  ***********************************************************************************************************/
10 
11 
12 #include "emu.h"
13 #include "pce_rom.h"
14 
15 
16 //-------------------------------------------------
17 //  pce_rom_device - constructor
18 //-------------------------------------------------
19 
20 DEFINE_DEVICE_TYPE(PCE_ROM_STD,      pce_rom_device,      "pce_rom",      "PCE/TG16 Carts")
21 DEFINE_DEVICE_TYPE(PCE_ROM_CDSYS3,   pce_cdsys3_device,   "pce_cdsys3",   "PCE/TG16 CD-System Cart v3.00")
22 DEFINE_DEVICE_TYPE(PCE_ROM_POPULOUS, pce_populous_device, "pce_populous", "PCE Populous Cart")
23 DEFINE_DEVICE_TYPE(PCE_ROM_SF2,      pce_sf2_device,      "pce_sf2",      "PCE Street Fighter 2 CE Cart")
24 DEFINE_DEVICE_TYPE(PCE_ROM_TENNOKOE, pce_tennokoe_device, "pce_tennokoe", "PCE Tennokoe Bank Cart")
25 
26 
pce_rom_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)27 pce_rom_device::pce_rom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
28 	: device_t(mconfig, type, tag, owner, clock)
29 	, device_pce_cart_interface( mconfig, *this )
30 {
31 }
32 
pce_rom_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)33 pce_rom_device::pce_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
34 	: pce_rom_device(mconfig, PCE_ROM_STD, tag, owner, clock)
35 {
36 }
37 
pce_cdsys3_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)38 pce_cdsys3_device::pce_cdsys3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
39 	: pce_rom_device(mconfig, PCE_ROM_CDSYS3, tag, owner, clock)
40 {
41 }
42 
pce_populous_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)43 pce_populous_device::pce_populous_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
44 	: pce_rom_device(mconfig, PCE_ROM_POPULOUS, tag, owner, clock)
45 {
46 }
47 
pce_sf2_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)48 pce_sf2_device::pce_sf2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
49 	: pce_rom_device(mconfig, PCE_ROM_SF2, tag, owner, clock), m_bank_base(0)
50 {
51 }
52 
pce_tennokoe_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)53 pce_tennokoe_device::pce_tennokoe_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
54 	: pce_rom_device(mconfig, PCE_ROM_TENNOKOE, tag, owner, clock),
55 	device_nvram_interface(mconfig, *this)
56 {
57 }
58 
59 
60 //-------------------------------------------------
61 //  mapper specific start/reset
62 //-------------------------------------------------
63 
64 
device_start()65 void pce_sf2_device::device_start()
66 {
67 	save_item(NAME(m_bank_base));
68 }
69 
device_reset()70 void pce_sf2_device::device_reset()
71 {
72 	m_bank_base = 0;
73 }
74 
device_start()75 void pce_tennokoe_device::device_start()
76 {
77 	save_item(NAME(m_bram));
78 	save_item(NAME(m_bram_locked));
79 }
80 
device_reset()81 void pce_tennokoe_device::device_reset()
82 {
83 	m_bram_locked = 1;
84 }
85 
86 // Tennokoe Bank is a special HuCard containing x4 Backup RAM banks,
87 // the software can transfer
nvram_default()88 void pce_tennokoe_device::nvram_default()
89 {
90 	memset(m_bram, 0xff, m_bram_size);
91 	// easter egg: load copy of a BRAM (debug leftover?) inside bank 4.
92 	// Contains 14 save blocks, mostly at the end of the various games.
93 	// Not entirely correct but not incorrect as well to just unlock these saves for public use,
94 	// for testing reasons and for a slim chance of actually be supposed as default data in the bank(s)
95 	// File list:
96 	// 001 NEUTOPIA1
97 	// 002 MOTURBO-1
98 	// 003 MOMODE2-1
99 	// 004 MOMOKATSU.
100 	// 005 BOMBERMAN1
101 	// 006 POPULOUS.
102 	// 007 ADVENTURE1 (Starts in HuMan form at the village with 983040 gold, basically before the last dungeon);
103 	// 008 TENGAI1
104 	// 009 COBRA1
105 	// 010 YS.DATA.01 (right before the switch between Ys 1 and 2, read book to move on);
106 	// 011 YS.DATA.02
107 	// 012 YS3.DAT.01 (right before the end, go to the right bridge for the ending);
108 	// 013 URUSEI1
109 	// 014 MITUBATI1
110 	// TODO: document the other saves.
111 	memcpy(m_bram + 0x1800, m_rom + 0x8800, 0x800);
112 }
113 
nvram_read(emu_file & file)114 void pce_tennokoe_device::nvram_read(emu_file &file)
115 {
116 	file.read(m_bram, m_bram_size);
117 }
118 
nvram_write(emu_file & file)119 void pce_tennokoe_device::nvram_write(emu_file &file)
120 {
121 	file.write(m_bram, m_bram_size);
122 }
123 
124 /*-------------------------------------------------
125  mapper specific handlers
126  -------------------------------------------------*/
127 
read_cart(offs_t offset)128 uint8_t pce_rom_device::read_cart(offs_t offset)
129 {
130 	int bank = offset / 0x20000;
131 	return m_rom[rom_bank_map[bank] * 0x20000 + (offset & 0x1ffff)];
132 }
133 
134 
read_cart(offs_t offset)135 uint8_t pce_cdsys3_device::read_cart(offs_t offset)
136 {
137 	int bank = offset / 0x20000;
138 	if (!m_ram.empty() && offset >= 0xd0000)
139 		return m_ram[offset - 0xd0000];
140 
141 	return m_rom[rom_bank_map[bank] * 0x20000 + (offset & 0x1ffff)];
142 }
143 
write_cart(offs_t offset,uint8_t data)144 void pce_cdsys3_device::write_cart(offs_t offset, uint8_t data)
145 {
146 	if (!m_ram.empty() && offset >= 0xd0000)
147 		m_ram[offset - 0xd0000] = data;
148 }
149 
150 
read_cart(offs_t offset)151 uint8_t pce_populous_device::read_cart(offs_t offset)
152 {
153 	int bank = offset / 0x20000;
154 	if (!m_ram.empty() && offset >= 0x80000 && offset < 0x88000)
155 		return m_ram[offset & 0x7fff];
156 
157 	return m_rom[rom_bank_map[bank] * 0x20000 + (offset & 0x1ffff)];
158 }
159 
write_cart(offs_t offset,uint8_t data)160 void pce_populous_device::write_cart(offs_t offset, uint8_t data)
161 {
162 	if (!m_ram.empty() && offset >= 0x80000 && offset < 0x88000)
163 		m_ram[offset & 0x7fff] = data;
164 }
165 
166 
read_cart(offs_t offset)167 uint8_t pce_sf2_device::read_cart(offs_t offset)
168 {
169 	if (offset < 0x80000)
170 		return m_rom[offset];
171 	else
172 		return m_rom[0x80000 + m_bank_base * 0x80000 + (offset & 0x7ffff)];
173 }
174 
write_cart(offs_t offset,uint8_t data)175 void pce_sf2_device::write_cart(offs_t offset, uint8_t data)
176 {
177 	if (offset >= 0x1ff0 && offset < 0x1ff4)
178 		m_bank_base = offset & 3;
179 }
180 
read_cart(offs_t offset)181 uint8_t pce_tennokoe_device::read_cart(offs_t offset)
182 {
183 	switch((offset & 0xf0000) >> 16)
184 	{
185 		case 0:
186 		case 1:
187 		case 2:
188 		case 3:
189 		case 4:
190 		case 5:
191 		case 6:
192 		case 7:
193 			return m_rom[offset];
194 		case 8:
195 			if (m_bram_locked)
196 				return 0xff;
197 			else
198 				return m_bram[offset & (m_bram_size-1)];
199 	}
200 
201 	logerror("tennokoe: ROM reading at %06x\n",offset);
202 	return 0xff;
203 }
204 
write_cart(offs_t offset,uint8_t data)205 void pce_tennokoe_device::write_cart(offs_t offset, uint8_t data)
206 {
207 	switch((offset & 0xf0000) >> 16)
208 	{
209 		case 8:
210 			if(!m_bram_locked)
211 				m_bram[offset & (m_bram_size-1)] = data;
212 			break;
213 		case 0xf:
214 			// TODO: lock/unlock mechanism is a complete guess, needs real HW study
215 			// (writes to ports $c0000, $d0000, $f0000)
216 			m_bram_locked = (data == 0);
217 		default:
218 			logerror("tennokoe: ROM writing at %06x %02x\n",offset,data);
219 			break;
220 	}
221 }
222