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
264
265
266
267
268
269
|
// license:BSD-3-Clause
// copyright-holders:Vas Crabb, Wilbert Pol
/***************************************************************************
TAMA5 Mapper (Used by Tamagotchi 3)
============
Cartridge contains the following chips:
* TAMA5 Game Boy bus interface
* TAMA6 Toshiba TMP47C243M TLCS-47 microcontroller
* TAMA7 mask ROM
* Toshiba TC8521AM real-time clock
* Toshiba M62021P system reset IC with switch for memory backup
The MCU acts as an interface between the TAMA5 and the RTC. The MCU can
drive a piezo speaker (in response to alarms from the RTC). There is a
mechanical switch that disconnects power from the piezo speaker. The RTC,
MCU and piezo speaker have backup power supplied by a user-replaceable
CR2016 coin cell.
The TAMA5 chip only responds to A15, A14, A0, and D3-D0, i.e. addresses are
effectively masked with 0xC001, and data is effectively masked with 0x0F.
Status: partially supported.
The TAMA5 mapper includes a special RTC chip which communicates through the
RAM area (0xA000-0xBFFF); most notably addresses 0xA000 and 0xA001 seem to
be used. In this setup 0xA001 acts like a control register and 0xA000 like
a data register.
Accepted values by the TAMA5 control register:
0x00 - Writing to 0xA000 will set bits 3-0 for ROM bank selection.
0x01 - Writing to 0xA000 will set bits (7-?)4 for ROM bank selection.
0x04 - Bits 3-0 of the value to write
0x05 - Bits 4-7 of the value to write
0x06 - Address control hi
bit 0 - Bit 4 for the address
bit 3-1 - 000 - Write a byte to the 32 byte memory. The data to be
written must be set in registers 0x04 (lo nibble) and
0x05 (hi nibble).
- 001 - Read a byte from the 32 byte memory. The data read
will be available in registers 0x0C (lo nibble) and
0x0D (hi nibble).
- 010 - Unknown (occurs just after having started a game and
entered a date) (execution at address 1A19)
- 011 - Unknown (not encountered yet)
- 100 - Unknown (occurs during booting a game; appears to be
some kind of read command as it is followed by a read
of the 0x0C register) (execution at address 1B5B)
- 101 - Unknown (not encountered yet)
- 110 - Unknown (not encountered yet)
- 111 - Unknown (not encountered yet)
0x07 - Address control lo
bit 3-0 - bits 3-0 for the address
0x0A - After writing this the lowest 2 bits of A000 determine whether the
TAMA5 chip is ready to accept the next command. If the lowest 2 bits
hold the value 01 then the TAMA5 chip is ready for the next command.
0x0C - Reading from A000 will return bits 3-0 of the data
0x0D - Reading from A000 will return bits 7-4 of the data
0x04 - RTC controls? -> RTC/memory?
0x05 - Write time/memomry?
0x06 - RTC controls?
0x07 - RTC controls?
Unknown sequences:
During booting a game (1B5B:
04 <- 00, 06 <- 08, 07 <- 01, followed by read 0C
when value read from 0C equals 00 followed by the sequence:
04 <- 01, 06 <- 08, 07 <- 01, followed by read 0C
the value read from 0C is checked for non-zero, don't know the consequences for either
yet.
Initialization after starting a game:
At address 1A19:
06 <- 05, 07 <- 02, followed by read 0C, if != 0F => OK, otherwise do something.
***************************************************************************/
#include "emu.h"
#include "tama5.h"
#include "cartbase.h"
//#define VERBOSE 1
//#define LOG_OUTPUT_FUNC osd_printf_info
#include "logmacro.h"
namespace bus::gameboy {
namespace {
class tama5_device : public mbc_device_base
{
public:
static constexpr feature_type unemulated_features() { return feature::SOUND; }
tama5_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
virtual std::error_condition load(std::string &message) override ATTR_COLD;
protected:
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
private:
u8 data_r(address_space &space);
void data_w(u8 data);
void command_w(u8 data);
u8 m_bank_sel_rom;
u8 m_registers[0x20];
u8 m_response;
u8 m_command;
u8 m_data;
u8 m_address;
};
tama5_device::tama5_device(
machine_config const &mconfig,
char const *tag,
device_t *owner,
u32 clock) :
mbc_device_base(mconfig, GB_ROM_TAMA5, tag, owner, clock),
m_bank_sel_rom(0U),
m_response(0U),
m_command(0U),
m_data(0U),
m_address(0U)
{
}
std::error_condition tama5_device::load(std::string &message)
{
// set up ROM
set_bank_bits_rom(5);
if (!check_rom(message))
return image_error::BADSOFTWARE;
install_rom();
// install I/O
cart_space()->install_read_handler(0xa000, 0xa000, 0x0000, 0x1fff, 0x0000, emu::rw_delegate(*this, FUNC(tama5_device::data_r)));
cart_space()->install_write_handler(0xa000, 0xa000, 0x0000, 0x1ffe, 0x0000, emu::rw_delegate(*this, FUNC(tama5_device::data_w)));
cart_space()->install_write_handler(0xa001, 0xa001, 0x0000, 0x1ffe, 0x0000, emu::rw_delegate(*this, FUNC(tama5_device::command_w)));
// all good
return std::error_condition();
}
void tama5_device::device_start()
{
mbc_device_base::device_start();
save_item(NAME(m_bank_sel_rom));
save_item(NAME(m_registers));
save_item(NAME(m_response));
save_item(NAME(m_command));
save_item(NAME(m_data));
save_item(NAME(m_address));
}
void tama5_device::device_reset()
{
mbc_device_base::device_reset();
m_bank_sel_rom = 1;
std::fill(std::begin(m_registers), std::end(m_registers), 0xffU);
m_response = 0xffU;
m_command = 0x00U;
m_data = 0x00U;
m_address = 0x00U;
set_bank_rom(m_bank_sel_rom);
}
u8 tama5_device::data_r(address_space &space)
{
return (space.unmap() & 0xf0) | (m_response & 0x0f);
}
void tama5_device::data_w(u8 data)
{
switch (m_command)
{
case 0x00: // ROM bank low
m_bank_sel_rom = (m_bank_sel_rom & 0x10) | (data & 0x0f);
set_bank_rom(m_bank_sel_rom);
break;
case 0x01: // ROM bank high
m_bank_sel_rom = (m_bank_sel_rom & 0x0f) | ((data & 0x01) << 4);
set_bank_rom(m_bank_sel_rom);
break;
case 0x04: // value low
m_data = (m_data & 0xf0) | (data & 0x0f);
break;
case 0x05: // value high
m_data = (m_data & 0x0f) | (data << 4);
break;
case 0x06: // address high
m_address = (m_address & 0x0f) | (data << 4);
break;
case 0x07: // address low/trigger
m_address = (m_address & 0xf0) | (data & 0x0f);
switch (m_address & 0xe0)
{
case 0x00:
LOG("%s: write register 0x%02X = 0x%02X\n", machine().describe_context(), m_address & 0x1f, m_data);
m_registers[m_address & 0x1f] = m_data;
break;
case 0x20:
LOG("%s: read register 0x%02X\n", machine().describe_context(), m_address & 0x1f);
m_data = m_registers[m_address & 0x1f];
break;
case 0x40: // unknown - some kind of read
if ((m_address & 0x1f) == 0x12)
m_data = 0xff;
[[fallthrough]];
case 0x80: // unknown - some kind of read when 0x07=0x01, or write when 0x07=0x00 or 0x07=0x02
default:
logerror("%s: Unknown access 0x%02X = 0x%02X\n", machine().describe_context(), m_address, m_data);
}
}
}
void tama5_device::command_w(u8 data)
{
switch (data)
{
case 0x00: // ROM bank low
case 0x01: // ROM bank high
case 0x04: // value low
case 0x05: // value high
case 0x06: // address high
case 0x07: // address low/trigger
break;
case 0x0a: // ready status in least significant bit
m_response = 0x01U;
break;
case 0x0c: // read value low
m_response = m_data & 0x0f;
break;
case 0x0d: // read value high
m_response = m_data >> 4;
break;
default:
logerror("%s: Unknown command 0x%02X\n", machine().describe_context(), data);
}
m_command = data;
}
} // anonymous namespace
} // namespace bus::gameboy
DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_TAMA5, device_gb_cart_interface, bus::gameboy::tama5_device, "gb_rom_tama5", "Game Boy Bandai Tamagotchi Cartridge")
|