1 // license:BSD-3-Clause
2 // copyright-holders:Wilbert Pol, Robbbert
3 /***************************************************************************
4 
5 Driver file to handle emulation of the Tiger Game.com by Wilbert Pol.
6 Various improvements by Robbbert.
7 
8 Todo:
9 - Fix cpu and system problems that prevent the games from working fully.
10 - RS232 port
11 - Sound ports 1,2 do not sound anything like the real thing
12 - Sound port 3 (noise channel)
13 - Sound dac port (mostly works but is the wrong speed in some places).
14   dac pitch is controlled by how often TIM1_INT occurs. This same
15   interrupt also controls the seconds countdown in some games, such as
16   Quiz Wiz and Scrabble. Currently this countdown goes twice as fast
17   as it should. If the INT is slowed down to compensate, the dac sound
18   is so slow as to be unintelligible. Need to find a way to keep both happy.
19 - System seems slower than it should. Probably wrong cycle count in the CPU.
20   What we have there is a guess as the real info has not been found.
21   -speed 1.2 makes the sound more natural
22   -speed 1.7 if TIM1_INT is slowed to fix the countdown.
23 
24 Game Status:
25 - Inbuilt ROM and PDA functions all work
26 - Due to an irritating message, the NVRAM is commented out in the machine config
27 - All carts appear to work, from my limited testing.
28 -- indy500 skips some speech just before the trial race starts.
29 
30 ***************************************************************************/
31 
32 #include "emu.h"
33 #include "includes/gamecom.h"
34 
35 #include "screen.h"
36 #include "softlist.h"
37 #include "speaker.h"
38 
39 #include "gamecom.lh"
40 
41 
gamecom_mem_map(address_map & map)42 void gamecom_state::gamecom_mem_map(address_map &map)
43 {
44 	map(0x0000, 0x0013).ram().region("maincpu", 0x00);
45 	map(0x0014, 0x0017).rw(FUNC(gamecom_state::gamecom_pio_r), FUNC(gamecom_state::gamecom_pio_w));        // buttons
46 	map(0x0018, 0x001F).ram().region("maincpu", 0x18);
47 	map(0x0020, 0x007F).rw(FUNC(gamecom_state::gamecom_internal_r), FUNC(gamecom_state::gamecom_internal_w));/* CPU internal register file */
48 	map(0x0080, 0x03FF).ram().region("maincpu", 0x80);                     /* RAM */
49 	map(0x0400, 0x0FFF).noprw();                                                /* Nothing */
50 	map(0x1000, 0x1FFF).rom();                                                /* Internal ROM (initially), or External ROM/Flash. Controlled by MMU0 (never swapped out in game.com) */
51 	map(0x2000, 0x3FFF).bankr("bank1");                                   /* External ROM/Flash. Controlled by MMU1 */
52 	map(0x4000, 0x5FFF).bankr("bank2");                                   /* External ROM/Flash. Controlled by MMU2 */
53 	map(0x6000, 0x7FFF).bankr("bank3");                                   /* External ROM/Flash. Controlled by MMU3 */
54 	map(0x8000, 0x9FFF).bankr("bank4");                                   /* External ROM/Flash. Controlled by MMU4 */
55 	map(0xA000, 0xDFFF).writeonly().share("videoram").nopr();             /* VRAM - writeonly, returns 0 on read, as expected by lostwrld */
56 	map(0xE000, 0xFFFF).ram().share("nvram");           /* Extended I/O, Extended RAM */
57 }
58 
59 static INPUT_PORTS_START( gamecom )
60 	PORT_START("IN0")
61 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_NAME( "Up" )
62 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_NAME( "Down" )
63 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_NAME( "Left" )
64 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_NAME( "Right" )
PORT_CODE(KEYCODE_M)65 	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME( "Menu" ) PORT_CODE( KEYCODE_M )
66 	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME( DEF_STR(Pause) ) PORT_CODE( KEYCODE_V )
67 	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME( "Sound" ) PORT_CODE( KEYCODE_S )
68 	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME( "Button A" ) PORT_CODE( KEYCODE_A ) PORT_CODE( KEYCODE_LCONTROL )
69 
70 	PORT_START("IN1")
71 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME( "Button B" ) PORT_CODE( KEYCODE_B ) PORT_CODE( KEYCODE_LALT )
72 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME( "Button C" ) PORT_CODE( KEYCODE_C ) PORT_CODE( KEYCODE_SPACE )
73 
74 	PORT_START("IN2")
75 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME( "Reset" ) PORT_CODE( KEYCODE_N )
76 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME( "Button D" ) PORT_CODE( KEYCODE_D ) PORT_CODE( KEYCODE_LSHIFT )
77 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME( "Stylus press" ) PORT_CODE( KEYCODE_Z ) PORT_CODE( MOUSECODE_BUTTON1 )
78 
79 	// These are used by the "Default Grid" artwork to detect mouse clicks
80 	PORT_START("GRID.0")
81 	PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER)
82 	PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER)
83 	PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER)
84 	PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER)
85 	PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER)
86 	PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER)
87 	PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_OTHER)
88 	PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_OTHER)
89 	PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_OTHER)
90 	PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_OTHER)
91 
92 	PORT_START("GRID.1")
93 	PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER)
94 	PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER)
95 	PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER)
96 	PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER)
97 	PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER)
98 	PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER)
99 	PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_OTHER)
100 	PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_OTHER)
101 	PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_OTHER)
102 	PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_OTHER)
103 
104 	PORT_START("GRID.2")
105 	PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER)
106 	PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER)
107 	PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER)
108 	PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER)
109 	PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER)
110 	PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER)
111 	PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_OTHER)
112 	PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_OTHER)
113 	PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_OTHER)
114 	PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_OTHER)
115 
116 	PORT_START("GRID.3")
117 	PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER)
118 	PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER)
119 	PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER)
120 	PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER)
121 	PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER)
122 	PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER)
123 	PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_OTHER)
124 	PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_OTHER)
125 	PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_OTHER)
126 	PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_OTHER)
127 
128 	PORT_START("GRID.4")
129 	PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER)
130 	PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER)
131 	PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER)
132 	PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER)
133 	PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER)
134 	PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER)
135 	PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_OTHER)
136 	PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_OTHER)
137 	PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_OTHER)
138 	PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_OTHER)
139 
140 	PORT_START("GRID.5")
141 	PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER)
142 	PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER)
143 	PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER)
144 	PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER)
145 	PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER)
146 	PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER)
147 	PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_OTHER)
148 	PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_OTHER)
149 	PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_OTHER)
150 	PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_OTHER)
151 
152 	PORT_START("GRID.6")
153 	PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER)
154 	PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER)
155 	PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER)
156 	PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER)
157 	PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER)
158 	PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER)
159 	PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_OTHER)
160 	PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_OTHER)
161 	PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_OTHER)
162 	PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_OTHER)
163 
164 	PORT_START("GRID.7")
165 	PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER)
166 	PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER)
167 	PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER)
168 	PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER)
169 	PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER)
170 	PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER)
171 	PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_OTHER)
172 	PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_OTHER)
173 	PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_OTHER)
174 	PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_OTHER)
175 
176 	PORT_START("GRID.8")
177 	PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER)
178 	PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER)
179 	PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER)
180 	PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER)
181 	PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER)
182 	PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER)
183 	PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_OTHER)
184 	PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_OTHER)
185 	PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_OTHER)
186 	PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_OTHER)
187 
188 	PORT_START("GRID.9")
189 	PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER)
190 	PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER)
191 	PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER)
192 	PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER)
193 	PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER)
194 	PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER)
195 	PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_OTHER)
196 	PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_OTHER)
197 	PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_OTHER)
198 	PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_OTHER)
199 
200 	PORT_START("GRID.10")
201 	PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER)
202 	PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER)
203 	PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER)
204 	PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER)
205 	PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER)
206 	PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER)
207 	PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_OTHER)
208 	PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_OTHER)
209 	PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_OTHER)
210 	PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_OTHER)
211 
212 	PORT_START("GRID.11")
213 	PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER)
214 	PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER)
215 	PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER)
216 	PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER)
217 	PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER)
218 	PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER)
219 	PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_OTHER)
220 	PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_OTHER)
221 	PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_OTHER)
222 	PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_OTHER)
223 
224 	PORT_START("GRID.12")
225 	PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER)
226 	PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER)
227 	PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER)
228 	PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER)
229 	PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER)
230 	PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER)
231 	PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_OTHER)
232 	PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_OTHER)
233 	PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_OTHER)
234 	PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_OTHER)
235 	INPUT_PORTS_END
236 
237 void gamecom_state::gamecom_palette(palette_device &palette) const
238 {
239 	palette.set_pen_color(0, 0x00, 0x00, 0x00); // Black
240 	palette.set_pen_color(1, 0x0f, 0x4f, 0x2f); // Gray 1
241 	palette.set_pen_color(2, 0x6f, 0x8f, 0x4f); // Gray 2
242 	palette.set_pen_color(3, 0x8f, 0xcf, 0x8f); // Grey 3
243 	palette.set_pen_color(4, 0xdf, 0xff, 0x8f); // White
244 }
245 
screen_update(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)246 uint32_t gamecom_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
247 {
248 	copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
249 	return 0;
250 }
251 
INTERRUPT_GEN_MEMBER(gamecom_state::gamecom_interrupt)252 INTERRUPT_GEN_MEMBER(gamecom_state::gamecom_interrupt)
253 {
254 	m_maincpu->set_input_line(sm8500_cpu_device::LCDC_INT, ASSERT_LINE );
255 }
256 
gamecom(machine_config & config)257 void gamecom_state::gamecom(machine_config &config)
258 {
259 	/* basic machine hardware */
260 	SM8500(config, m_maincpu, XTAL(11'059'200)/2);   /* actually it's an sm8521 microcontroller containing an sm8500 cpu */
261 	m_maincpu->set_addrmap(AS_PROGRAM, &gamecom_state::gamecom_mem_map);
262 	m_maincpu->dma_cb().set(FUNC(gamecom_state::gamecom_handle_dma));
263 	m_maincpu->timer_cb().set(FUNC(gamecom_state::gamecom_update_timers));
264 	m_maincpu->set_vblank_int("screen", FUNC(gamecom_state::gamecom_interrupt));
265 
266 	config.set_maximum_quantum(attotime::from_hz(60));
267 
268 	//NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0);
269 
270 	/* video hardware */
271 	SCREEN(config, m_screen, SCREEN_TYPE_LCD);
272 	m_screen->set_refresh_hz(59.732155);
273 	m_screen->set_vblank_time(500);
274 	m_screen->set_screen_update(FUNC(gamecom_state::screen_update));
275 	m_screen->set_size(200, 160);
276 	m_screen->set_visarea_full();
277 	m_screen->set_palette("palette");
278 
279 	config.set_default_layout(layout_gamecom);
280 	PALETTE(config, "palette", FUNC(gamecom_state::gamecom_palette), 5);
281 
282 	/* sound hardware */
283 	SPEAKER(config, "speaker").front_center();
284 	/* TODO: much more complex than this */
285 	DAC_8BIT_R2R(config, m_dac, 0).add_route(ALL_OUTPUTS, "speaker", 0.5); // unknown DAC (Digital audio)
286 	DAC_4BIT_R2R(config, m_dac0, 0).add_route(ALL_OUTPUTS, "speaker", 0.05); // unknown DAC (Frequency modulation)
287 	DAC_4BIT_R2R(config, m_dac1, 0).add_route(ALL_OUTPUTS, "speaker", 0.05); // unknown DAC (Frequency modulation)
288 
289 	/* cartridge */
290 	GENERIC_CARTSLOT(config, "cartslot1", generic_linear_slot, "gamecom_cart", "bin,tgc").set_device_load(FUNC(gamecom_state::cart1_load));
291 	GENERIC_CARTSLOT(config, "cartslot2", generic_linear_slot, "gamecom_cart", "bin,tgc").set_device_load(FUNC(gamecom_state::cart2_load));
292 	SOFTWARE_LIST(config, "cart_list").set_original("gamecom");
293 }
294 
295 ROM_START( gamecom )
296 	ROM_REGION( 0x2000, "maincpu", 0 )
297 	ROM_LOAD( "internal.bin", 0x1000,  0x1000, CRC(a0cec361) SHA1(03368237e8fed4a8724f3b4a1596cf4b17c96d33) )
298 
299 	ROM_REGION( 0x40000, "kernel", 0 )
300 	ROM_LOAD( "external.bin", 0x00000, 0x40000, CRC(e235a589) SHA1(97f782e72d738f4d7b861363266bf46b438d9b50) )
301 ROM_END
302 
303 //    YEAR  NAME     PARENT  COMPAT  MACHINE  INPUT    CLASS          INIT          COMPANY  FULLNAME    FLAGS
304 CONS( 1997, gamecom, 0,      0,      gamecom, gamecom, gamecom_state, init_gamecom, "Tiger", "Game.com", MACHINE_IMPERFECT_SOUND | MACHINE_CLICKABLE_ARTWORK)
305