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