Previous 199869 Revisions Next

r34365 Monday 12th January, 2015 at 21:40:44 UTC by hap
(MESS)Game added or promoted to working
------------------
Electronic Detective [hap, Sean Riddle]
[src/mess]mess.lst mess.mak
[src/mess/drivers]elecdet.c* stopthie.c ticalc1x.c
[src/mess/layout]elecdet.lay*

trunk/src/mess/drivers/elecdet.c
r0r242877
1// license:BSD-3-Clause
2// copyright-holders:hap
3/***************************************************************************
4
5  Ideal Electronic Detective
6  * TMS0980NLL MP6100A (die labeled 0980B-00)
7  hardware (and concept) is very similar to Parker Bros Stop Thief
8
9  This is an electronic board game. It requires game cards with suspect info,
10  and good old pen and paper to record game progress. Refer to the manual
11  on how to play it.
12
13
14  TODO:
15  - MCU clock is unknown
16
17***************************************************************************/
18
19#include "emu.h"
20#include "cpu/tms0980/tms0980.h"
21#include "sound/speaker.h"
22
23#include "elecdet.lh"
24
25// master clock is unknown, the value below is an approximation
26#define MASTER_CLOCK (425000)
27
28
29class elecdet_state : public driver_device
30{
31public:
32   elecdet_state(const machine_config &mconfig, device_type type, const char *tag)
33      : driver_device(mconfig, type, tag),
34      m_maincpu(*this, "maincpu"),
35      m_button_matrix(*this, "IN"),
36      m_speaker(*this, "speaker")
37   { }
38
39   required_device<cpu_device> m_maincpu;
40   required_ioport_array<5> m_button_matrix;
41   required_device<speaker_sound_device> m_speaker;
42
43   UINT16 m_o;
44   bool m_power_on;
45
46   UINT16 m_leds_state[0x10];
47   UINT16 m_leds_cache[0x10];
48   UINT8 m_leds_decay[0x100];
49
50   DECLARE_READ8_MEMBER(read_k);
51   DECLARE_WRITE16_MEMBER(write_o);
52   DECLARE_WRITE16_MEMBER(write_r);
53
54   DECLARE_INPUT_CHANGED_MEMBER(power_button);
55   DECLARE_WRITE_LINE_MEMBER(auto_power_off);
56
57   TIMER_DEVICE_CALLBACK_MEMBER(leds_decay_tick);
58   void leds_update();
59
60   virtual void machine_reset();
61   virtual void machine_start();
62};
63
64
65
66/***************************************************************************
67
68  LEDs
69
70***************************************************************************/
71
72// The device strobes the outputs very fast, it is unnoticeable to the user.
73// To prevent flickering here, we need to simulate a decay.
74
75// decay time, in steps of 10ms
76#define LEDS_DECAY_TIME 4
77
78void elecdet_state::leds_update()
79{
80   UINT16 active_state[0x10];
81
82   for (int i = 0; i < 0x10; i++)
83   {
84      active_state[i] = 0;
85
86      for (int j = 0; j < 0x10; j++)
87      {
88         int di = j << 4 | i;
89
90         // turn on powered leds
91         if (m_power_on && m_leds_state[i] >> j & 1)
92            m_leds_decay[di] = LEDS_DECAY_TIME;
93
94         // determine active state
95         int ds = (m_leds_decay[di] != 0) ? 1 : 0;
96         active_state[i] |= (ds << j);
97      }
98   }
99
100   // on difference, send to output
101   for (int i = 0; i < 0x10; i++)
102      if (m_leds_cache[i] != active_state[i])
103         output_set_digit_value(i, active_state[i]);
104
105   memcpy(m_leds_cache, active_state, sizeof(m_leds_cache));
106}
107
108TIMER_DEVICE_CALLBACK_MEMBER(elecdet_state::leds_decay_tick)
109{
110   // slowly turn off unpowered leds
111   for (int i = 0; i < 0x100; i++)
112      if (!(m_leds_state[i & 0xf] >> (i>>4) & 1) && m_leds_decay[i])
113         m_leds_decay[i]--;
114
115   leds_update();
116}
117
118
119
120/***************************************************************************
121
122  I/O
123
124***************************************************************************/
125
126READ8_MEMBER(elecdet_state::read_k)
127{
128   // the Vss row is always on
129   UINT8 k = m_button_matrix[4]->read();
130
131   // read selected button rows
132   for (int i = 0; i < 4; i++)
133   {
134      const int ki[4] = { 0, 1, 4, 6 };
135      if (m_o >> ki[i] & 1)
136         k |= m_button_matrix[i]->read();
137   }
138
139   return k;
140}
141
142WRITE16_MEMBER(elecdet_state::write_r)
143{
144   // R0-R6: select digit
145   UINT8 o = BITSWAP8(m_o,7,5,2,1,4,0,6,3) & 0x7f;
146   for (int i = 0; i < 7; i++)
147      m_leds_state[i] = (data >> i & 1) ? o : 0;
148
149   leds_update();
150
151   // R7,R8: speaker on
152   m_speaker->level_w((data & 0x180 && m_o & 0x80) ? 1 : 0);
153}
154
155WRITE16_MEMBER(elecdet_state::write_o)
156{
157   // O0,O1,O4,O6: input mux
158   // O0-O6: led segments A-G
159   // O7: speaker out
160   m_o = data;
161}
162
163
164
165/***************************************************************************
166
167  Inputs
168
169***************************************************************************/
170
171INPUT_CHANGED_MEMBER(elecdet_state::power_button)
172{
173   m_power_on = (bool)(FPTR)param;
174   m_maincpu->set_input_line(INPUT_LINE_RESET, m_power_on ? CLEAR_LINE : ASSERT_LINE);
175}
176
177/* physical button layout and labels is like this:
178
179    [1]   [2]   [3]   [SUSPECT]
180    [4]   [5]   [6]   [PRIVATE QUESTION]
181    [7]   [8]   [9]   [I ACCUSE]
182                [0]   [ENTER]
183    [ON]  [OFF]       [END TURN]
184*/
185
186static INPUT_PORTS_START( elecdet )
187   PORT_START("IN.0") // O0 pin18
188   PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("4")
189   PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
190   PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("6")
191   PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_NAME("Private Question")
192   PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("5")
193
194   PORT_START("IN.1") // O1 pin17
195   PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED )
196   PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
197   PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CODE(KEYCODE_0_PAD) PORT_NAME("0")
198   PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER) PORT_CODE(KEYCODE_ENTER_PAD) PORT_NAME("Enter")
199   PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED )
200
201   PORT_START("IN.2") // O4 pin14
202   PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CODE(KEYCODE_7_PAD) PORT_NAME("7")
203   PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
204   PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CODE(KEYCODE_9_PAD) PORT_NAME("9")
205   PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_NAME("I Accuse")
206   PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CODE(KEYCODE_8_PAD) PORT_NAME("8")
207
208   PORT_START("IN.3") // O6 pin12
209   PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("1")
210   PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
211   PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("3")
212   PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_NAME("Suspect")
213   PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("2")
214
215   // note: even though power buttons are on the matrix, they are not CPU-controlled
216   PORT_START("IN.4") // Vss!
217   PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PGUP) PORT_NAME("On") PORT_CHANGED_MEMBER(DEVICE_SELF, elecdet_state, power_button, (void *)true)
218   PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
219   PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED )
220   PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_NAME("End Turn")
221   PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PGDN) PORT_NAME("Off") PORT_CHANGED_MEMBER(DEVICE_SELF, elecdet_state, power_button, (void *)false)
222INPUT_PORTS_END
223
224
225
226/***************************************************************************
227
228  Machine Config
229
230***************************************************************************/
231
232WRITE_LINE_MEMBER(elecdet_state::auto_power_off)
233{
234   // TMS0980 auto power-off opcode
235   if (state)
236   {
237      m_power_on = false;
238      m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
239   }
240}
241
242
243void elecdet_state::machine_reset()
244{
245   m_power_on = true;
246}
247
248void elecdet_state::machine_start()
249{
250   // zerofill
251   memset(m_leds_state, 0, sizeof(m_leds_state));
252   memset(m_leds_cache, 0, sizeof(m_leds_cache));
253   memset(m_leds_decay, 0, sizeof(m_leds_decay));
254
255   m_o = 0;
256   m_power_on = false;
257
258   // register for savestates
259   save_item(NAME(m_leds_state));
260   save_item(NAME(m_leds_cache));
261   save_item(NAME(m_leds_decay));
262
263   save_item(NAME(m_o));
264   save_item(NAME(m_power_on));
265}
266
267
268static MACHINE_CONFIG_START( elecdet, elecdet_state )
269
270   /* basic machine hardware */
271   MCFG_CPU_ADD("maincpu", TMS0980, MASTER_CLOCK)
272   MCFG_TMS1XXX_READ_K_CB(READ8(elecdet_state, read_k))
273   MCFG_TMS1XXX_WRITE_O_CB(WRITE16(elecdet_state, write_o))
274   MCFG_TMS1XXX_WRITE_R_CB(WRITE16(elecdet_state, write_r))
275   MCFG_TMS1XXX_POWER_OFF_CB(WRITELINE(elecdet_state, auto_power_off))
276
277   MCFG_TIMER_DRIVER_ADD_PERIODIC("leds_decay", elecdet_state, leds_decay_tick, attotime::from_msec(10))
278
279   MCFG_DEFAULT_LAYOUT(layout_elecdet)
280
281   /* no video! */
282
283   /* sound hardware */
284   MCFG_SPEAKER_STANDARD_MONO("mono")
285   MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0)
286   MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
287MACHINE_CONFIG_END
288
289
290
291/***************************************************************************
292
293  Game driver(s)
294
295***************************************************************************/
296
297ROM_START( elecdet )
298   ROM_REGION( 0x1000, "maincpu", 0 )
299   ROM_LOAD( "tms0980nll_mp6100a", 0x0000, 0x1000, CRC(f33f02ae) SHA1(a978d9cc1ba7897f6e8997715da265eb8c4a0c34) )
300
301   ROM_REGION( 1246, "maincpu:ipla", 0 )
302   ROM_LOAD( "tms0980_default_ipla.pla", 0, 1246, CRC(42db9a38) SHA1(2d127d98028ec8ec6ea10c179c25e447b14ba4d0) )
303   ROM_REGION( 1982, "maincpu:mpla", 0 )
304   ROM_LOAD( "tms0980_default_mpla.pla", 0, 1982, CRC(3709014f) SHA1(d28ee59ded7f3b9dc3f0594a32a98391b6e9c961) )
305   ROM_REGION( 352, "maincpu:opla", 0 )
306   ROM_LOAD( "tms0980_elecdet_opla.pla", 0, 352, CRC(652d19c3) SHA1(75550c2b293453b6b9efed88c8cc77195a53161f) )
307   ROM_REGION( 157, "maincpu:spla", 0 )
308   ROM_LOAD( "tms0980_elecdet_spla.pla", 0, 157, CRC(399aa481) SHA1(72c56c58fde3fbb657d69647a9543b5f8fc74279) )
309ROM_END
310
311
312CONS( 1979, elecdet, 0, 0, elecdet, elecdet, driver_device, 0, "Ideal", "Electronic Detective", GAME_SUPPORTS_SAVE )
trunk/src/mess/drivers/stopthie.c
r242876r242877
8888         int di = j << 4 | i;
8989
9090         // turn on powered leds
91         if (m_leds_state[i] >> j & 1)
91         if (m_power_on && m_leds_state[i] >> j & 1)
9292            m_leds_decay[di] = LEDS_DECAY_TIME;
9393
9494         // determine active state
95         int ds = (m_power_on && m_leds_decay[di] != 0) ? 1 : 0;
95         int ds = (m_leds_decay[di] != 0) ? 1 : 0;
9696         active_state[i] |= (ds << j);
9797      }
9898   }
trunk/src/mess/drivers/ticalc1x.c
r242876r242877
9595         int di = j << 4 | i;
9696
9797         // turn on powered leds
98         if (m_leds_state[i] >> j & 1)
98         if (m_power_on && m_leds_state[i] >> j & 1)
9999            m_leds_decay[di] = LEDS_DECAY_TIME;
100100
101101         // determine active state
102         int ds = (m_power_on && m_leds_decay[di] != 0) ? 1 : 0;
102         int ds = (m_leds_decay[di] != 0) ? 1 : 0;
103103         active_state[i] |= (ds << j);
104104      }
105105   }
trunk/src/mess/layout/elecdet.lay
r0r242877
1<?xml version="1.0"?>
2<mamelayout version="2">
3
4   <element name="digit" defstate="0">
5      <led7seg><color red="1.0" green="0.2" blue="0.2" /></led7seg>
6   </element>
7
8<!-- some of the display digits are unconnected (labeled digit99 here) -->
9
10   <view name="Internal Layout">
11      <bounds left="0" right="100" top="0" bottom="15" />
12
13      <bezel name="digit6" element="digit">
14         <bounds x="0" y="0" width="10" height="15" />
15      </bezel>
16      <bezel name="digit5" element="digit">
17         <bounds x="10" y="0" width="10" height="15" />
18      </bezel>
19      <bezel name="digit99" element="digit">
20         <bounds x="20" y="0" width="10" height="15" />
21      </bezel>
22      <bezel name="digit4" element="digit">
23         <bounds x="30" y="0" width="10" height="15" />
24      </bezel>
25      <bezel name="digit3" element="digit">
26         <bounds x="40" y="0" width="10" height="15" />
27      </bezel>
28      <bezel name="digit2" element="digit">
29         <bounds x="50" y="0" width="10" height="15" />
30      </bezel>
31      <bezel name="digit99" element="digit">
32         <bounds x="60" y="0" width="10" height="15" />
33      </bezel>
34      <bezel name="digit1" element="digit">
35         <bounds x="70" y="0" width="10" height="15" />
36      </bezel>
37      <bezel name="digit0" element="digit">
38         <bounds x="80" y="0" width="10" height="15" />
39      </bezel>
40      <bezel name="digit99" element="digit">
41         <bounds x="90" y="0" width="10" height="15" />
42      </bezel>
43
44   </view>
45</mamelayout>
trunk/src/mess/mess.lst
r242876r242877
25982598bitgrpha
25992599bitgrphb
26002600unk3403
2601elecdet
trunk/src/mess/mess.mak
r242876r242877
729729   $(MESSOBJ)/homebrew.a \
730730   $(MESSOBJ)/homelab.a \
731731   $(MESSOBJ)/hp.a \
732   $(MESSOBJ)/ideal.a \
732733   $(MESSOBJ)/imp.a \
733734   $(MESSOBJ)/intel.a \
734735   $(MESSOBJ)/interton.a \
r242876r242877
13051306   $(MESS_DRIVERS)/hp9k.o      \
13061307   $(MESS_DRIVERS)/hp9k_3xx.o  \
13071308
1308
13091309$(MESSOBJ)/hec2hrp.a:           \
13101310   $(MESS_DRIVERS)/hec2hrp.o   \
13111311   $(MESS_MACHINE)/hec2hrp.o   \
r242876r242877
13231323   $(MESS_DRIVERS)/sdk85.o     \
13241324   $(MESS_DRIVERS)/sdk86.o     \
13251325
1326$(MESSOBJ)/ideal.a:             \
1327   $(MESS_DRIVERS)/elecdet.o   \
1328
13261329$(MESSOBJ)/imp.a:               \
13271330   $(MESS_DRIVERS)/tim011.o    \
13281331   $(MESS_DRIVERS)/tim100.o    \
r242876r242877
21062109$(MESS_DRIVERS)/dmv.o:      $(MESS_LAYOUT)/dmv.lh
21072110$(MESS_DRIVERS)/dolphunk.o: $(MESS_LAYOUT)/dolphunk.lh
21082111$(MESS_DRIVERS)/eacc.o:     $(MESS_LAYOUT)/eacc.lh
2112$(MESS_DRIVERS)/elecdet.o:  $(MESS_LAYOUT)/elecdet.lh
2113$(MESS_DRIVERS)/elekscmp.o: $(MESS_LAYOUT)/elekscmp.lh
21092114$(MESS_DRIVERS)/elf.o:      $(MESS_LAYOUT)/elf2.lh
2110$(MESS_DRIVERS)/elekscmp.o: $(MESS_LAYOUT)/elekscmp.lh
21112115$(MESS_MACHINE)/esqvfd.o:   $(MESS_LAYOUT)/esq2by40.lh \
21122116                     $(MESS_LAYOUT)/esq1by22.lh
21132117$(MESS_DRIVERS)/et3400.o:   $(MESS_LAYOUT)/et3400.lh


Previous 199869 Revisions Next


© 1997-2024 The MAME Team