1 // license:BSD-3-Clause
2 // copyright-holders:AJR, Roberto Fresca
3 /*******************************************************************************
4 
5   The Boat
6   1987(c) Hit Gun Co, LTD.
7 
8   Gambling/Amusement game
9   Selectable through DIP switches.
10 
11   Driver by AJR.
12   Additional work by Roberto Fresca.
13 
14 *******************************************************************************
15 
16   Hardware specs...
17 
18   Seems based on MSX2.
19   PCB is marked "TVG01"
20 
21   CPU:
22   1x Sharp LH0080A (Z80-A).       (IC26)
23 
24   I/O:
25   2x NEC D8255AC-2 PPI.           (IC23, IC27)
26 
27   Sound:
28   1x GI AY-3-8910A.               (IC18)
29   1x Fujitsu MB3712 (audio amp)   (IC2)
30 
31   Video:
32   1x Yamaha V9938 VDP (scratched) (IC13)
33 
34   RAM:
35   4x Fujitsu MB81464-15 (256 Kbit DRAM) (VRAM)  (IC6, IC7, IC9, IC10)
36   1x NEC D449C-2 (2K x 8 Static RAM) (WRK RAM)  (IC1)
37 
38   ROM:
39   2x Mitsubishi M5L27128K for program.  (IC3, IC5)
40   3x Mitsubishi M5L27128K for graphics. (IC8, IC11, IC14)
41   1x Empty socket for extra data. (*)   (IC16)
42 
43   Other:
44   1x 21.47727 MHz Xtal.
45   1x 8 DIP switches bank.
46   1x 2x18 pins edge connector.
47   1x 2x10 pins edge connector.
48 
49 
50   (*) Note: The CE line of the extra ROM that should be located in the
51       empty socket, is tied to PPI port B, D3.
52 
53 *******************************************************************************/
54 
55 #include "emu.h"
56 #include "cpu/z80/z80.h"
57 #include "machine/i8255.h"
58 #include "machine/nvram.h"
59 #include "machine/ticket.h"
60 #include "sound/ay8910.h"
61 #include "video/v9938.h"
62 #include "screen.h"
63 #include "speaker.h"
64 
65 
66 class tvg01_state : public driver_device
67 {
68 public:
tvg01_state(const machine_config & mconfig,device_type type,const char * tag)69 	tvg01_state(const machine_config &mconfig, device_type type, const char *tag)
70 		: driver_device(mconfig, type, tag)
71 		, m_player_inputs{{*this, "INP1.%u", 0U}, {*this, "INP2.%u", 0U}}
72 		, m_banked_rom(*this, "banked_rom")
73 		, m_hopper(*this, "hopper")
74 	{
75 	}
76 
77 	void theboat(machine_config &config);
78 
79 protected:
80 	virtual void machine_start() override;
81 
82 private:
83 	template <int P> void input_select_w(u8 data);
84 	u8 player_inputs_r();
85 	void bank_select_w(u8 data);
86 	u8 bank_r(offs_t offset);
87 
88 	void mem_map(address_map &map);
89 	void io_map(address_map &map);
90 
91 	required_ioport_array<6> m_player_inputs[2];
92 	required_region_ptr<u8> m_banked_rom;
93 	required_device<ticket_dispenser_device> m_hopper;
94 
95 	u8 m_input_select[2];
96 	u8 m_bank_select;
97 };
98 
99 #define MAIN_CLOCK      XTAL(21'477'272)
100 #define VDP_CLOCK       MAIN_CLOCK
101 #define CPU_CLOCK       MAIN_CLOCK / 6
102 #define PSG_CLOCK       MAIN_CLOCK / 12
103 
104 #define VDP_MEM         0x20000     // 4x MB81464-15
105 #define HOPPER_PULSE    50          // time between hopper pulses in milliseconds
106 
107 
machine_start()108 void tvg01_state::machine_start()
109 {
110 	save_item(NAME(m_input_select));
111 	save_item(NAME(m_bank_select));
112 }
113 
114 template <int P>
input_select_w(u8 data)115 void tvg01_state::input_select_w(u8 data)
116 {
117 	m_input_select[P] = data;
118 }
119 
player_inputs_r()120 u8 tvg01_state::player_inputs_r()
121 {
122 	u8 result = 0xff;
123 
124 	for (int p = 0; p < 2; p++)
125 		for (int n = 0; n < 6; n++)
126 			if (!BIT(m_input_select[p], n))
127 				result &= m_player_inputs[p][n]->read();
128 
129 	return result;
130 }
131 
bank_select_w(u8 data)132 void tvg01_state::bank_select_w(u8 data)
133 {
134 	m_bank_select = data;
135 	m_hopper->motor_w(BIT(data, 4));
136 }
137 
bank_r(offs_t offset)138 u8 tvg01_state::bank_r(offs_t offset)
139 {
140 	u8 result = 0xff;
141 
142 	for (int i = 0; i < 4; i++)
143 		if (!BIT(m_bank_select, i))
144 			result &= m_banked_rom[i * 0x4000 + offset];
145 
146 	return result;
147 }
148 
149 
mem_map(address_map & map)150 void tvg01_state::mem_map(address_map &map)
151 {
152 	map(0x0000, 0x7fff).rom().region("program", 0);
153 	map(0x8000, 0x87ff).ram().share("nvram");
154 	map(0xc000, 0xffff).r(FUNC(tvg01_state::bank_r));
155 }
156 
io_map(address_map & map)157 void tvg01_state::io_map(address_map &map)
158 {
159 	map.global_mask(0xff);
160 	map(0x01, 0x01).r("psg", FUNC(ay8910_device::data_r));
161 	map(0x02, 0x03).w("psg", FUNC(ay8910_device::data_address_w));
162 	map(0x20, 0x23).rw("vdp", FUNC(v9938_device::read), FUNC(v9938_device::write));
163 	map(0x80, 0x83).rw("ppi1", FUNC(i8255_device::read), FUNC(i8255_device::write));
164 	map(0xa0, 0xa3).rw("ppi2", FUNC(i8255_device::read), FUNC(i8255_device::write));
165 }
166 
167 
168 static INPUT_PORTS_START(theboat)
169 	PORT_START("INP0")
170 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 )       PORT_IMPULSE(3)  PORT_NAME("P1 Coin (1 credit)")
171 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN4 )       PORT_IMPULSE(10)  PORT_NAME("P2 Key Up (10 credits)")
172 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_GAMBLE_BOOK)  PORT_NAME("Analyze / Bookkeeping")
PORT_CODE(KEYCODE_I)173 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Pay Out")  PORT_CODE(KEYCODE_I)
174 	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_COIN3 )       PORT_IMPULSE(10)  PORT_NAME("P1 Key Up (10 credits)")
175 	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_CUSTOM )      PORT_READ_LINE_DEVICE_MEMBER("hopper", ticket_dispenser_device, line_r)
176 	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_COIN2 )       PORT_IMPULSE(3)  PORT_NAME("P2 Coin (1 credit)")
177 	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Pay Out")  PORT_CODE(KEYCODE_U)
178 
179 	PORT_START("INP1.0")
180 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Bet 1-2") PORT_CODE(KEYCODE_Q)
181 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Bet 1-3") PORT_CODE(KEYCODE_W)
182 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Bet 1-4") PORT_CODE(KEYCODE_E)
183 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Bet 1-5") PORT_CODE(KEYCODE_R)
184 	PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
185 
186 	PORT_START("INP1.1")
187 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Bet 1-6") PORT_CODE(KEYCODE_T)
188 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Bet 2-3") PORT_CODE(KEYCODE_A)
189 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Bet 2-4") PORT_CODE(KEYCODE_S)
190 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Bet 2-5") PORT_CODE(KEYCODE_D)
191 	PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
192 
193 	PORT_START("INP1.2")
194 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Bet 2-6") PORT_CODE(KEYCODE_F)
195 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Bet 3-4") PORT_CODE(KEYCODE_G)
196 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Bet 3-5") PORT_CODE(KEYCODE_Z)
197 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Bet 3-6") PORT_CODE(KEYCODE_X)
198 	PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
199 
200 	PORT_START("INP1.3")
201 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Bet 4-5") PORT_CODE(KEYCODE_C)
202 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START1 )      PORT_NAME("P1 Start")
203 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Big") PORT_CODE(KEYCODE_J)
204 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Next Game") PORT_CODE(KEYCODE_N)
205 	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Bet 4-6") PORT_CODE(KEYCODE_V)
206 	PORT_BIT( 0xe0, IP_ACTIVE_LOW, IPT_UNUSED )
207 
208 	PORT_START("INP1.4")
209 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Take Score") PORT_CODE(KEYCODE_H)
210 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Small") PORT_CODE(KEYCODE_K)
211 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 SH") PORT_CODE(KEYCODE_M)
212 	PORT_BIT( 0xf8, IP_ACTIVE_LOW, IPT_UNUSED )
213 
214 	PORT_START("INP1.5")
215 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P1 Bet 5-6") PORT_CODE(KEYCODE_B)
216 	PORT_BIT( 0xfe, IP_ACTIVE_LOW, IPT_UNUSED )
217 
218 	PORT_START("INP2.0")
219 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Bet 1-2")
220 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Bet 1-3")
221 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Bet 1-4")
222 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Bet 1-5")
223 	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED )
224 	PORT_BIT( 0xe0, IP_ACTIVE_LOW, IPT_UNKNOWN )
225 
226 	PORT_START("INP2.1")
227 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Bet 1-6")
228 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Bet 2-3")
229 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Bet 2-4")
230 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Bet 2-5")
231 	PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
232 
233 	PORT_START("INP2.2")
234 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Bet 2-6")
235 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Bet 3-4")
236 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Bet 3-5")
237 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Bet 3-6")
238 	PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
239 
240 	PORT_START("INP2.3")
241 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Bet 4-5")
242 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START2 )      PORT_NAME("P2 Start")
243 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Big")
244 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Next Game")
245 	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Bet 4-6")
246 	PORT_BIT( 0xe0, IP_ACTIVE_LOW, IPT_UNUSED )
247 
248 	PORT_START("INP2.4")
249 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Take Score")
250 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Small")
251 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 SH")
252 	PORT_BIT( 0xf8, IP_ACTIVE_LOW, IPT_UNUSED )
253 
254 	PORT_START("INP2.5")
255 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER )       PORT_NAME("P2 Bet 5-6")
256 	PORT_BIT( 0xfe, IP_ACTIVE_LOW, IPT_UNUSED )
257 
258 	PORT_START("DSW")
259 	PORT_DIPNAME(0x01, 0x01, DEF_STR(Unknown))  PORT_DIPLOCATION("DSW:8")
260 	PORT_DIPSETTING(0x01, DEF_STR(Off))
261 	PORT_DIPSETTING(0x00, DEF_STR(On))
262 	PORT_DIPNAME(0x02, 0x02, DEF_STR(Unknown))  PORT_DIPLOCATION("DSW:7")
263 	PORT_DIPSETTING(0x02, DEF_STR(Off))
264 	PORT_DIPSETTING(0x00, DEF_STR(On))
265 	PORT_DIPNAME(0x0c, 0x0c, DEF_STR(Coinage))  PORT_DIPLOCATION("DSW:6,5")
266 	PORT_DIPSETTING(0x0c, "1 Coin 1 Credit / 1 Pulse 10 Credits")
267 	PORT_DIPSETTING(0x08, "1 Coin 2 Credit / 1 Pulse 20 Credits")
268 	PORT_DIPSETTING(0x04, "1 Coin 5 Credit / 1 Pulse 50 Credits")
269 	PORT_DIPSETTING(0x00, "1 Coin 10 Credit / 1 Pulse 100 Credits")
270 	PORT_DIPNAME(0x10, 0x10, "Payment")         PORT_DIPLOCATION("DSW:4")
271 	PORT_DIPSETTING(0x10, "Pay Out")
272 	PORT_DIPSETTING(0x00, "Hopper")
273 	PORT_DIPNAME(0x20, 0x20, DEF_STR(Unknown))  PORT_DIPLOCATION("DSW:3")
274 	PORT_DIPSETTING(0x20, DEF_STR(Off))
275 	PORT_DIPSETTING(0x00, DEF_STR(On))
276 	PORT_DIPNAME(0x40, 0x40, "Clear Memory")    PORT_DIPLOCATION("DSW:2")
277 	PORT_DIPSETTING(0x40, DEF_STR(Off))
278 	PORT_DIPSETTING(0x00, DEF_STR(On))
279 	PORT_DIPNAME(0x80, 0x80, "Test Mode")       PORT_DIPLOCATION("DSW:1")
280 	PORT_DIPSETTING(0x80, DEF_STR(Off))
281 	PORT_DIPSETTING(0x00, DEF_STR(On))
282 INPUT_PORTS_END
283 
284 
285 void tvg01_state::theboat(machine_config &config)
286 {
287 	z80_device &maincpu(Z80(config, "maincpu", CPU_CLOCK));  // LH0080A
288 	maincpu.set_addrmap(AS_PROGRAM, &tvg01_state::mem_map);
289 	maincpu.set_addrmap(AS_IO, &tvg01_state::io_map);
290 
291 	NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0);  // D449C-2 + battery
292 
293 	i8255_device &ppi1(I8255(config, "ppi1"));  // D8255AC-2
294 	ppi1.in_pa_callback().set_ioport("INP0");
295 	ppi1.out_pb_callback().set(FUNC(tvg01_state::bank_select_w));
296 
297 	i8255_device &ppi2(I8255(config, "ppi2"));  // D8255AC-2
298 	ppi2.out_pa_callback().set(FUNC(tvg01_state::input_select_w<0>));
299 	ppi2.out_pb_callback().set(FUNC(tvg01_state::input_select_w<1>));
300 	ppi2.in_pc_callback().set(FUNC(tvg01_state::player_inputs_r));
301 
302 	SCREEN(config, "screen", SCREEN_TYPE_RASTER);
303 
304 	v9938_device &vdp(V9938(config, "vdp", VDP_CLOCK));  // unknown type (surface-scratched 64-pin SDIP)
305 	vdp.set_screen_ntsc("screen");
306 	vdp.set_vram_size(VDP_MEM);  // 4x MB81464-15
307 	vdp.int_cb().set_inputline("maincpu", INPUT_LINE_IRQ0);
308 
309 	TICKET_DISPENSER(config, "hopper", attotime::from_msec(HOPPER_PULSE), TICKET_MOTOR_ACTIVE_HIGH, TICKET_STATUS_ACTIVE_HIGH);
310 
311 	SPEAKER(config, "mono").front_center();
312 
313 	ay8910_device &psg(AY8910(config, "psg", PSG_CLOCK));  // GI AY-3-8910A
314 	psg.port_a_read_callback().set_ioport("DSW");
315 	psg.add_route(ALL_OUTPUTS, "mono", 1.0);
316 }
317 
318 
319 ROM_START(theboat)
320 	ROM_REGION(0x8000, "program", 0)
321 	ROM_LOAD("1.ic3", 0x0000, 0x4000, CRC(04a0ef56) SHA1(40256f858032efa1375d336f141dbbd08a8802f7))
322 	ROM_LOAD("2.ic5", 0x4000, 0x4000, CRC(c18d4a61) SHA1(c40a8b7dcaa90ed871be20605fc853949361257e))
323 
324 	ROM_REGION(0x10000, "banked_rom", 0) // contains both code and data
325 	ROM_LOAD("3.ic8",  0x0000, 0x4000, CRC(74b44e32) SHA1(b36c90a13511c5bf4aef079ac506605096e39067))
326 	ROM_LOAD("4.ic11", 0x4000, 0x4000, CRC(4ea36fa3) SHA1(b020a478e8dd72154916c67d71255b5a6a822d6d))
327 	ROM_LOAD("5.ic14", 0x8000, 0x4000, CRC(7899a587) SHA1(13cbb7e837e14bc49d8b34dbf876b666cdf48979))
328 	// Empty socket for one more ROM (IC16),
329 ROM_END
330 
331 
332 //   YEAR  NAME      PARENT  MACHINE   INPUT     STATE        INIT        ROT    COMPANY            FULLNAME   FLAGS
333 GAME(1987, theboat,  0,      theboat,  theboat,  tvg01_state, empty_init, ROT0, "Hit Gun Co, LTD", "The Boat", MACHINE_SUPPORTS_SAVE)
334