1 // license:BSD-3-Clause
2 // copyright-holders:hap
3 // thanks-to:Sean Riddle
4 /******************************************************************************
5 
6 Mattel Computer Chess
7 
8 Hardware notes:
9 - INS8050 CPU @ 6MHz (4KB internal ROM, 256 bytes internal RAM)
10 - 2*HLCD0569(also seen with 2*HLCD0601, functionally same?)
11 - custom LCD screen with chess squares background
12 
13 ******************************************************************************/
14 
15 #include "emu.h"
16 #include "cpu/mcs48/mcs48.h"
17 #include "video/hlcd0515.h"
18 #include "screen.h"
19 
20 // internal artwork
21 #include "mchess.lh" // clickable
22 
23 
24 namespace {
25 
26 class mchess_state : public driver_device
27 {
28 public:
mchess_state(const machine_config & mconfig,device_type type,const char * tag)29 	mchess_state(const machine_config &mconfig, device_type type, const char *tag) :
30 		driver_device(mconfig, type, tag),
31 		m_maincpu(*this, "maincpu"),
32 		m_lcd(*this, "lcd%u", 0),
33 		m_inputs(*this, "IN.%u", 0),
34 		m_out_x(*this, "%u.%u.%u", 0U, 0U, 0U)
35 	{ }
36 
37 	void mchess(machine_config &config);
38 
DECLARE_INPUT_CHANGED_MEMBER(reset_switch)39 	DECLARE_INPUT_CHANGED_MEMBER(reset_switch) { update_reset(newval); }
40 
41 protected:
42 	virtual void machine_start() override;
43 	virtual void machine_reset() override;
44 
45 private:
46 	// devices/pointers
47 	required_device<mcs48_cpu_device> m_maincpu;
48 	required_device_array<hlcd0569_device, 2> m_lcd;
49 	required_ioport_array<4> m_inputs;
50 	output_finder<2, 8, 22> m_out_x;
51 
52 	u8 m_inp_mux;
53 	u8 m_lcd_control;
54 
55 	void update_reset(ioport_value state);
56 
57 	// I/O handlers
58 	template<int Sel> void lcd_output_w(offs_t offset, u32 data);
59 	void input_w(u8 data);
60 	u8 input_r();
61 	void lcd_w(u8 data);
62 	u8 lcd_r();
63 };
64 
machine_start()65 void mchess_state::machine_start()
66 {
67 	// resolve handlers
68 	m_out_x.resolve();
69 
70 	// zerofill
71 	m_inp_mux = 0;
72 	m_lcd_control = 0;
73 
74 	// register for savestates
75 	save_item(NAME(m_inp_mux));
76 	save_item(NAME(m_lcd_control));
77 }
78 
machine_reset()79 void mchess_state::machine_reset()
80 {
81 	update_reset(m_inputs[3]->read());
82 }
83 
update_reset(ioport_value state)84 void mchess_state::update_reset(ioport_value state)
85 {
86 	// battery is disconnected from CPU VCC pin when power switch is in SAVE mode
87 	// (at reboot, the game will read the chessboard positions from LCD RAM)
88 	m_maincpu->set_input_line(INPUT_LINE_RESET, state ? ASSERT_LINE : CLEAR_LINE);
89 }
90 
91 
92 
93 /******************************************************************************
94     I/O
95 ******************************************************************************/
96 
97 template<int Sel>
lcd_output_w(offs_t offset,u32 data)98 void mchess_state::lcd_output_w(offs_t offset, u32 data)
99 {
100 	int enabled = ~m_inputs[3]->read() & m_lcd_control & 1;
101 
102 	// output to x.y.z where x = chip, y = row, z = col
103 	// up to 22 columns used
104 	for (int i = 0; i < 22; i++)
105 		m_out_x[Sel][offset][i] = BIT(data, i) & enabled;
106 }
107 
input_w(u8 data)108 void mchess_state::input_w(u8 data)
109 {
110 	// d0,d5,d6: input mux
111 	m_inp_mux = (~data >> 4 & 6) | (~data & 1);
112 }
113 
input_r()114 u8 mchess_state::input_r()
115 {
116 	u8 data = 0;
117 
118 	// d1-d4,d7: multiplexed inputs
119 	for (int i = 0; i < 3; i++)
120 		if (BIT(m_inp_mux, i))
121 			data |= m_inputs[i]->read();
122 
123 	return ~data;
124 }
125 
lcd_w(u8 data)126 void mchess_state::lcd_w(u8 data)
127 {
128 	// d0: both LCDC VDRIVE
129 	// d1: N/C
130 
131 	// d3: 1st LCDC _CS
132 	// d6: 2nd LCDC _CS
133 	m_lcd[0]->cs_w(BIT(data, 3));
134 	m_lcd[1]->cs_w(BIT(data, 6));
135 
136 	// d4: both LCDC CLOCK
137 	// d5: both LCDC DATA IN
138 	for (int i = 0; i < 2; i++)
139 	{
140 		m_lcd[i]->data_w(BIT(data, 5));
141 		m_lcd[i]->clock_w(BIT(~data, 4));
142 	}
143 
144 	m_lcd_control = data;
145 }
146 
lcd_r()147 u8 mchess_state::lcd_r()
148 {
149 	// d2: 1st LCDC DATA OUT
150 	// d7: 2nd LCDC DATA OUT
151 	u8 r0 = m_lcd[0]->data_r();
152 	u8 r1 = m_lcd[1]->data_r();
153 	return (0x84^0xff) | r0 << 2 | r1 << 7;
154 }
155 
156 
157 
158 /******************************************************************************
159     Input Ports
160 ******************************************************************************/
161 
162 static INPUT_PORTS_START( mchess )
163 	PORT_START("IN.0")
PORT_CODE(KEYCODE_3)164 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_3) PORT_NAME("Player vs. Player")
165 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_2) PORT_NAME("Machine vs. Machine")
166 	PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_1) PORT_NAME("Player vs. Machine")
167 	PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_L) PORT_NAME("Level")
168 	PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED)
169 
170 	PORT_START("IN.1")
171 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_SPACE) PORT_NAME("Move")
172 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("Right")
173 	PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_LEFT) PORT_NAME("Left")
174 	PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_UP) PORT_NAME("Up")
175 	PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_DOWN) PORT_NAME("Down")
176 
177 	PORT_START("IN.2")
178 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_ENTER) PORT_CODE(KEYCODE_ENTER_PAD) PORT_NAME("Enter Move")
179 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_E) PORT_NAME("Enter Position")
180 	PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CODE(KEYCODE_DEL) PORT_NAME("Clear")
181 	PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_C) PORT_NAME("Color")
182 	PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_B) PORT_NAME("Take Back")
183 
184 	PORT_START("IN.3")
185 	PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_CODE(KEYCODE_F1) PORT_TOGGLE PORT_CHANGED_MEMBER(DEVICE_SELF, mchess_state, reset_switch, 0) PORT_NAME("Save Switch")
186 INPUT_PORTS_END
187 
188 
189 
190 /******************************************************************************
191     Machine Configs
192 ******************************************************************************/
193 
194 void mchess_state::mchess(machine_config &config)
195 {
196 	/* basic machine hardware */
197 	I8050(config, m_maincpu, 6_MHz_XTAL);
198 	m_maincpu->p1_out_cb().set(FUNC(mchess_state::input_w));
199 	m_maincpu->p1_in_cb().set(FUNC(mchess_state::input_r));
200 	m_maincpu->p2_out_cb().set(FUNC(mchess_state::lcd_w));
201 	m_maincpu->p2_in_cb().set(FUNC(mchess_state::lcd_r));
202 
203 	/* video hardware */
204 	HLCD0569(config, m_lcd[0], 500); // C=0.01uF
205 	m_lcd[0]->write_cols().set(FUNC(mchess_state::lcd_output_w<0>));
206 	HLCD0569(config, m_lcd[1], 500); // C=0.01uF
207 	m_lcd[1]->write_cols().set(FUNC(mchess_state::lcd_output_w<1>));
208 
209 	screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_SVG));
210 	screen.set_refresh_hz(60);
211 	screen.set_size(977, 1080);
212 	screen.set_visarea_full();
213 
214 	config.set_default_layout(layout_mchess);
215 }
216 
217 
218 
219 /******************************************************************************
220     ROM Definitions
221 ******************************************************************************/
222 
223 ROM_START( mchess )
224 	ROM_REGION( 0x1000, "maincpu", 0 )
225 	ROM_LOAD("ins8050-6hwu_n", 0x0000, 0x1000, CRC(de272323) SHA1(9ba323b614504e20b25c86d290c0667f0bbf6c6b) )
226 
227 	ROM_REGION( 796406, "screen", 0)
228 	ROM_LOAD("mchess.svg", 0, 796406, CRC(795d66e0) SHA1(5f786c00bf33793bfba7065d8e9ec476e02e5c46) )
229 ROM_END
230 
231 } // anonymous namespace
232 
233 
234 
235 /******************************************************************************
236     Drivers
237 ******************************************************************************/
238 
239 //    YEAR  NAME    PARENT CMP MACHINE  INPUT   CLASS         INIT        COMPANY, FULLNAME, FLAGS
240 CONS( 1980, mchess, 0,      0, mchess,  mchess, mchess_state, empty_init, "Mattel", "Computer Chess (Mattel)", MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND_HW | MACHINE_CLICKABLE_ARTWORK )
241