1 // license: BSD-3-Clause
2 // copyright-holders: Dirk Best
3 /***************************************************************************
4 
5     Digitek Micrologic 20
6 
7     Access control device with dot-matrix display
8 
9   ML20/232
10   ____________________________________________________
11   |   ________  ________  ________  ______    __      |
12   |   |74HC04N|M74HC139B1 |__DP1__| |_XT1_| : CN7     |
13   |__ _______________    ____________      JP2        |
14   ||C||IC4 M27C512  ||   |D70320L-8  |       (CN4)__  |
15   ||N||_____________||   |NEC V25    |   ______   |C| |
16   ||2|_______________    |           |   |BATT |  |N| |
17   ||_||KM681000CLP-7L|   |           |   |_____|  |6| |
18   |__ |______________|   |___________|   o <- LED     |
19   ||C| ________          ________       .. <- JP1     |
20   ||N||_M6242B_|         MAX693CPE              __    |
21   ||8|                   ________               |C|__ |
22   |         XT2          ULN2003A               |N|| ||
23   | :<-JP4       ________               ____    |3||_|<- LM2575T
24   |    ________  SN74HC05N             TLP504A  |_|   |
25   |__  MAX232CPE                :<-JP8                |
26   || |            MEISEI         ________             |
27   || | ________  P12  P12        MAX232CPE            |
28   ||_| 26LS32ACN                                   __ |
29   |   :: <-JP5                                     |F||
30   |  ____________   ________  ________             |U||
31   |  |___CN10____|  |_CN11__| |_______|   ________ |S||
32   |  |___________|  |_____  | |_CN9___|   |_CN1___| E |
33   |___________________________________________________|
34 
35  XT1 = 16.000 MHz
36  XT2 = S873
37  DP1 = 8 dipswitches
38  CN4 = Speaker
39  CN9 = RS232
40  CN8 = Power Out
41  CN6 = Magnetic stripe reader
42  CN2 = Display (dot-matrix, 2 lines x 16 characters, 5x7 each character)
43  CN7 = Keypad
44 
45  Display = Hyundai HC16203-A (Hitachi HD44780A00 based).
46 
47    Status:
48    - Needs currently unimplemented V25 features (serial etc.)
49 
50 ***************************************************************************/
51 
52 #include "emu.h"
53 #include "cpu/nec/v25.h"
54 #include "machine/msm6242.h"
55 #include "video/hd44780.h"
56 #include "sound/spkrdev.h"
57 #include "emupal.h"
58 #include "screen.h"
59 #include "speaker.h"
60 
61 #include "ml20.lh"
62 
63 class ml20_state : public driver_device
64 {
65 public:
ml20_state(const machine_config & mconfig,device_type type,const char * tag)66 	ml20_state(const machine_config &mconfig, device_type type, const char *tag)
67 		: driver_device(mconfig, type, tag),
68 		m_maincpu(*this, "maincpu"),
69 		m_lcdc(*this, "lcdc"),
70 		m_speaker(*this, "speaker"),
71 		m_keys(*this, "COL.%d", 0U),
72 		m_dsw(*this, "DSW")
73 		{}
74 
75 	void ml20(machine_config &config);
76 
77 	void lcd_palette(palette_device &palette) const;
78 	HD44780_PIXEL_UPDATE(lcd_pixel_update);
79 
80 protected:
81 	void machine_start() override;
82 
83 private:
84 	required_device<v25_device> m_maincpu;
85 	required_device<hd44780_device> m_lcdc;
86 	required_device<speaker_sound_device> m_speaker;
87 	required_ioport_array<4> m_keys;
88 	required_ioport m_dsw;
89 
90 	void mem_map(address_map &map);
91 	void io_map(address_map &map);
92 
93 	uint8_t p0_r();
94 	uint8_t p1_r();
95 	uint8_t p2_r();
96 	void p0_w(uint8_t data);
97 	void p1_w(uint8_t data);
98 	void p2_w(uint8_t data);
99 	uint8_t pt_r();
100 
101 	uint8_t m_p0;
102 	uint8_t m_p1;
103 	uint8_t m_p2;
104 };
105 
mem_map(address_map & map)106 void ml20_state::mem_map(address_map &map)
107 {
108 	map(0x00000, 0x1ffff).ram();
109 	map(0xf0000, 0xfffff).rom().region("bios", 0);
110 }
111 
io_map(address_map & map)112 void ml20_state::io_map(address_map &map)
113 {
114 	map(0x00, 0x0f).rw("rtc", FUNC(msm6242_device::read), FUNC(msm6242_device::write));
115 	map(0x10, 0x10).rw(m_lcdc, FUNC(hd44780_device::data_r), FUNC(hd44780_device::data_w));
116 	map(0x14, 0x14).rw(m_lcdc, FUNC(hd44780_device::control_r), FUNC(hd44780_device::control_w));
117 }
118 
119 static INPUT_PORTS_START( ml20 )
120 	PORT_START("COL.0")
PORT_CODE(KEYCODE_ENTER)121 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_NAME("ENTER")
122 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0)     PORT_NAME("0")
123 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL)   PORT_NAME("CLEAR")
124 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D)     PORT_NAME("ler. MARC")
125 	PORT_BIT(0xf0, IP_ACTIVE_LOW, IPT_UNKNOWN)
126 
127 	PORT_START("COL.1")
128 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_NAME("9")
129 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_NAME("8")
130 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_NAME("7")
131 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_NAME("MENSAJ.")
132 	PORT_BIT(0xf0, IP_ACTIVE_LOW, IPT_UNKNOWN)
133 
134 	PORT_START("COL.2")
135 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_NAME("6")
136 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_NAME("5")
137 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_NAME("4")
138 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_NAME("SALDOS")
139 	PORT_BIT(0xf0, IP_ACTIVE_LOW, IPT_UNKNOWN)
140 
141 	PORT_START("COL.3")
142 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_NAME("3")
143 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_NAME("2")
144 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_NAME("1")
145 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_NAME("ANULAR")
146 	PORT_BIT(0xf0, IP_ACTIVE_LOW, IPT_UNKNOWN)
147 
148 	PORT_START("DSW")
149 	PORT_DIPUNKNOWN(0x01, 0x01)
150 	PORT_DIPUNKNOWN(0x02, 0x02)
151 	PORT_DIPUNKNOWN(0x04, 0x04)
152 	PORT_DIPUNKNOWN(0x08, 0x08)
153 	PORT_DIPUNKNOWN(0x10, 0x10)
154 	PORT_DIPUNKNOWN(0x20, 0x20)
155 	PORT_DIPUNKNOWN(0x40, 0x40)
156 	PORT_DIPUNKNOWN(0x80, 0x80)
157 INPUT_PORTS_END
158 
159 void ml20_state::lcd_palette(palette_device &palette) const
160 {
161 	palette.set_pen_color(0, rgb_t(138, 146, 148)); // background
162 	palette.set_pen_color(1, rgb_t( 92,  83,  88)); // lcd pixel on
163 	palette.set_pen_color(2, rgb_t(131, 136, 139)); // lcd pixel off
164 }
165 
HD44780_PIXEL_UPDATE(ml20_state::lcd_pixel_update)166 HD44780_PIXEL_UPDATE( ml20_state::lcd_pixel_update )
167 {
168 	// char size is 5x7
169 	if (x > 4 || y > 6)
170 		return;
171 
172 	if (line < 2 && pos < 16)
173 		bitmap.pix(1 + y + line*8 + line, 1 + pos*6 + x) = state ? 1 : 2;
174 }
175 
176 // 7654----  unknown (set to input)
177 // ----3210  keypad column
178 
p0_r()179 uint8_t ml20_state::p0_r()
180 {
181 	return m_p0;
182 }
183 
p0_w(uint8_t data)184 void ml20_state::p0_w(uint8_t data)
185 {
186 	if (0)
187 		logerror("p0_w: %d %d %d %d  %d %d %d %d\n", BIT(data, 7), BIT(data, 6), BIT(data, 5), BIT(data, 4), BIT(data, 3), BIT(data, 2), BIT(data, 1), BIT(data, 0));
188 
189 	m_p0 = data;
190 }
191 
192 // 765-----  unknown (set to output)
193 // ---43210  unknown (set to input)
194 
p1_r()195 uint8_t ml20_state::p1_r()
196 {
197 	return m_p1;
198 }
199 
p1_w(uint8_t data)200 void ml20_state::p1_w(uint8_t data)
201 {
202 	if (0)
203 		logerror("p1_w: %d %d %d %d  %d %d %d %d\n", BIT(data, 7), BIT(data, 6), BIT(data, 5), BIT(data, 4), BIT(data, 3), BIT(data, 2), BIT(data, 1), BIT(data, 0));
204 
205 	m_p1 = data;
206 }
207 
208 // 7-------  some kind of heartbeat? led?
209 // -6------  unknown (set to output)
210 // --543---  unknown (set to input)
211 // -----2--  set when waiting for keypad or other data?
212 // ------1-  toggles continously
213 // -------0  unknown (set to output)
214 
p2_r()215 uint8_t ml20_state::p2_r()
216 {
217 	return m_p2;
218 }
219 
p2_w(uint8_t data)220 void ml20_state::p2_w(uint8_t data)
221 {
222 	if (0)
223 		logerror("p2_w: %d %d %d %d  %d %d %d %d\n", BIT(data, 7), BIT(data, 6), BIT(data, 5), BIT(data, 4), BIT(data, 3), BIT(data, 2), BIT(data, 1), BIT(data, 0));
224 
225 	m_p2 = data;
226 }
227 
pt_r()228 uint8_t ml20_state::pt_r()
229 {
230 	uint8_t data = 0xff;
231 
232 	if (BIT(m_p0, 0) == 0) data &= m_keys[0]->read();
233 	if (BIT(m_p0, 1) == 0) data &= m_keys[1]->read();
234 	if (BIT(m_p0, 2) == 0) data &= m_keys[2]->read();
235 	if (BIT(m_p0, 3) == 0) data &= m_keys[3]->read();
236 
237 	return data;
238 }
239 
machine_start()240 void ml20_state::machine_start()
241 {
242 	// register for save states
243 	save_item(NAME(m_p0));
244 	save_item(NAME(m_p1));
245 	save_item(NAME(m_p2));
246 }
247 
ml20(machine_config & config)248 void ml20_state::ml20(machine_config &config)
249 {
250 	V25(config, m_maincpu, 16_MHz_XTAL / 2); // unknown clock
251 	m_maincpu->set_addrmap(AS_PROGRAM, &ml20_state::mem_map);
252 	m_maincpu->set_addrmap(AS_IO, &ml20_state::io_map);
253 	m_maincpu->p0_in_cb().set(FUNC(ml20_state::p0_r));
254 	m_maincpu->p0_out_cb().set(FUNC(ml20_state::p0_w));
255 	m_maincpu->p1_in_cb().set(FUNC(ml20_state::p1_r));
256 	m_maincpu->p1_out_cb().set(FUNC(ml20_state::p1_w));
257 	m_maincpu->p2_in_cb().set(FUNC(ml20_state::p2_r));
258 	m_maincpu->p2_out_cb().set(FUNC(ml20_state::p2_w));
259 	m_maincpu->pt_in_cb().set(FUNC(ml20_state::pt_r));
260 
261 	MSM6242(config, "rtc", 32.768_kHz_XTAL);
262 
263 	// video hardware
264 	screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD));
265 	screen.set_refresh_hz(50);
266 	screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); // not accurate
267 	screen.set_size(6*16+1, 18);
268 	screen.set_visarea_full();
269 	screen.set_screen_update("lcdc", FUNC(hd44780_device::screen_update));
270 	screen.set_palette("palette");
271 
272 	PALETTE(config, "palette", FUNC(ml20_state::lcd_palette), 3);
273 
274 	HD44780(config, m_lcdc, 0);
275 	m_lcdc->set_lcd_size(2, 16);
276 	m_lcdc->set_pixel_update_cb(FUNC(ml20_state::lcd_pixel_update));
277 
278 	config.set_default_layout(layout_ml20);
279 
280 	// sound
281 	SPEAKER(config, "mono").front_center();
282 	SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.25);
283 }
284 
285 ROM_START( ml20 )
286 	ROM_REGION(0x10000, "bios", 0)
287 	ROM_LOAD("ml-20_v1.27.ic4", 0x0000, 0x10000, CRC(844d6d23) SHA1(08cd290bc342da328abc91b0699662c9ba335c0d) )
288 ROM_END
289 
290 //    YEAR  NAME  PARENT  COMPAT  MACHINE INPUT  CLASS       INIT        COMPANY    FULLNAME         FLAGS
291 COMP( 1999, ml20, 0,      0,      ml20,   ml20,  ml20_state, empty_init, "Digitek", "Micrologic 20", MACHINE_NOT_WORKING | MACHINE_NO_SOUND | MACHINE_SUPPORTS_SAVE)
292