1 // license:BSD-3-Clause
2 // copyright-holders:Carl
3 /****************************************************************************
4 
5     Olivetti M24 emulation
6 
7     http://olivettim24.hadesnet.org/index.html
8     https://sites.google.com/site/att6300shrine/Home
9     http://www.ti99.com/exelvision/website/index.php?page=logabax-persona-1600
10 
11     The AT&T PC6300, the Xerox 6060 and the Logabax Persona 1600 were
12     badge-engineered Olivetti M24s.
13 
14     The Olivetti M21 was a portable version of the M24 that sported a 9"
15     monochrome monitor.
16 
17     http://www.computinghistory.org.uk/det/43175/Olivetti-M21/
18     https://www.nightfallcrew.com/23/02/2014/repairing-a-defective-olivetti-m21/
19 
20 ****************************************************************************/
21 
22 #include "emu.h"
23 
24 #include "bus/isa/isa.h"
25 #include "bus/isa/isa_cards.h"
26 #include "cpu/i86/i86.h"
27 #include "cpu/tms7000/tms7000.h"
28 #include "imagedev/floppy.h"
29 #include "machine/am9517a.h"
30 #include "machine/i8087.h"
31 #include "machine/m24_kbd.h"
32 #include "machine/m24_z8000.h"
33 #include "machine/mm58174.h"
34 #include "machine/pit8253.h"
35 #include "machine/pic8259.h"
36 #include "machine/ram.h"
37 #include "sound/spkrdev.h"
38 #include "speaker.h"
39 
40 #include "formats/pc_dsk.h"
41 #include "formats/naslite_dsk.h"
42 #include "formats/m20_dsk.h"
43 
44 #include "softlist.h"
45 
46 class m24_state : public driver_device
47 {
48 public:
m24_state(const machine_config & mconfig,device_type type,const char * tag)49 	m24_state(const machine_config &mconfig, device_type type, const char *tag) :
50 		driver_device(mconfig, type, tag),
51 		m_maincpu(*this, "maincpu"),
52 		m_ram(*this, RAM_TAG),
53 		m_isabus(*this, "isabus"),
54 		m_dmac(*this, "dmac"),
55 		m_pic(*this, "pic"),
56 		m_pit(*this, "pit"),
57 		m_speaker(*this, "speaker"),
58 		m_kbc(*this, "kbc"),
59 		m_keyboard(*this, "keyboard"),
60 		m_z8000_apb(*this, "z8000_apb"),
61 		m_dsw0(*this, "DSW0")
62 	{ }
63 
64 	void olivetti(machine_config &config);
65 
66 protected:
67 	virtual void machine_start() override;
68 	virtual void machine_reset() override;
69 
70 private:
71 	void dma_segment_w(offs_t offset, u8 data);
72 	DECLARE_WRITE_LINE_MEMBER(dma_hrq_w);
73 	u8 dma_memory_read(offs_t offset);
74 	void dma_memory_write(offs_t offset, u8 data);
75 	template <int Channel> u8 dma_io_read(offs_t offset);
76 	template <int Channel> void dma_io_write(offs_t offset, u8 data);
77 	template <int Channel> DECLARE_WRITE_LINE_MEMBER(dma_dack_w);
78 	DECLARE_WRITE_LINE_MEMBER(dma_tc_w);
79 	DECLARE_WRITE_LINE_MEMBER(dreq0_ck_w);
80 	DECLARE_WRITE_LINE_MEMBER(speaker_ck_w);
81 	void update_speaker();
82 
83 	u8 keyboard_data_r();
84 	u8 keyboard_status_r();
85 	void keyboard_data_w(u8 data);
86 
87 	void ctrlport_a_w(u8 data);
88 	u8 ctrlport_a_r();
89 	u8 ctrlport_b_r();
90 
91 	void alt_w(u8 data);
92 	DECLARE_WRITE_LINE_MEMBER(chck_w);
93 	DECLARE_WRITE_LINE_MEMBER(int87_w);
94 	void nmi_enable_w(u8 data);
95 	void update_nmi();
96 
97 	required_device<i8086_cpu_device> m_maincpu;
98 	required_device<ram_device> m_ram;
99 	required_device<isa8_device> m_isabus;
100 	required_device<am9517a_device> m_dmac;
101 	required_device<pic8259_device> m_pic;
102 	required_device<pit8253_device> m_pit;
103 	required_device<speaker_sound_device> m_speaker;
104 	required_device<tms7000_device> m_kbc;
105 	required_device<m24_keyboard_device> m_keyboard;
106 	optional_device<m24_z8000_device> m_z8000_apb;
107 	required_ioport m_dsw0;
108 
109 	u8 m_dma_segment[4];
110 	u8 m_dma_active;
111 	bool m_tc;
112 	bool m_dreq0_ck;
113 
114 	u8 m_ctrlport_a;
115 	u8 m_ctrlport_b;
116 
117 	bool m_87int;
118 	bool m_chck_active;
119 	bool m_nmi_enable;
120 
121 	u8 m_pa, m_kbcin, m_kbcout;
122 	bool m_kbcibf, m_kbdata, m_i86_halt, m_i86_halt_perm;
123 
124 	u8 pa_r();
125 	void pb_w(u8 data);
126 	u8 kbcdata_r();
127 	void kbcdata_w(u8 data);
128 	DECLARE_WRITE_LINE_MEMBER(kbcin_w);
129 	DECLARE_WRITE_LINE_MEMBER(int_w);
130 	DECLARE_WRITE_LINE_MEMBER(halt_i86_w);
131 	DECLARE_FLOPPY_FORMATS( floppy_formats );
132 
133 	static void cfg_m20_format(device_t *device);
134 	void kbc_map(address_map &map);
135 	void m24_io(address_map &map);
136 	void m24_map(address_map &map);
137 };
138 
machine_start()139 void m24_state::machine_start()
140 {
141 	m_maincpu->space(AS_PROGRAM).install_ram(0, m_ram->size() - 1, m_ram->pointer());
142 
143 	std::fill_n(&m_dma_segment[0], 4, 0);
144 	m_dma_active = 0;
145 	m_tc = false;
146 	m_dreq0_ck = true;
147 
148 	m_ctrlport_a = 0;
149 	m_ctrlport_b = 0;
150 
151 	m_87int = false;
152 	m_chck_active = false;
153 	m_nmi_enable = false;
154 
155 	save_item(NAME(m_dma_segment));
156 	save_item(NAME(m_dma_active));
157 	save_item(NAME(m_tc));
158 	save_item(NAME(m_dreq0_ck));
159 	save_item(NAME(m_ctrlport_a));
160 	save_item(NAME(m_ctrlport_b));
161 	save_item(NAME(m_87int));
162 	save_item(NAME(m_chck_active));
163 	save_item(NAME(m_nmi_enable));
164 	save_item(NAME(m_pa));
165 	save_item(NAME(m_kbcin));
166 	save_item(NAME(m_kbcout));
167 	save_item(NAME(m_kbcibf));
168 	save_item(NAME(m_kbdata));
169 	save_item(NAME(m_i86_halt));
170 	save_item(NAME(m_i86_halt_perm));
171 }
172 
machine_reset()173 void m24_state::machine_reset()
174 {
175 	ctrlport_a_w(0);
176 	nmi_enable_w(0);
177 	m_pa = 0x40;
178 	m_kbcibf = false;
179 	m_kbdata = true;
180 	m_i86_halt = false;
181 	m_i86_halt_perm = false;
182 	if(m_z8000_apb)
183 		m_z8000_apb->halt_w(ASSERT_LINE);
184 }
185 
dma_segment_w(offs_t offset,u8 data)186 void m24_state::dma_segment_w(offs_t offset, u8 data)
187 {
188 	m_dma_segment[offset] = data & 0x0f;
189 }
190 
WRITE_LINE_MEMBER(m24_state::dma_hrq_w)191 WRITE_LINE_MEMBER(m24_state::dma_hrq_w)
192 {
193 	if(!m_i86_halt)
194 		m_maincpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
195 	if(m_z8000_apb && !m_z8000_apb->halted())
196 		m_z8000_apb->halt_w(state ? ASSERT_LINE : CLEAR_LINE);
197 
198 	/* Assert HLDA */
199 	m_dmac->hack_w(state);
200 }
201 
dma_memory_read(offs_t offset)202 u8 m24_state::dma_memory_read(offs_t offset)
203 {
204 	const int seg = (BIT(m_dma_active, 2) ? 0 : 2) | (BIT(m_dma_active, 3) ? 0 : 1);
205 	return m_maincpu->space(AS_PROGRAM).read_byte(offset | u32(m_dma_segment[seg]) << 16);
206 }
207 
dma_memory_write(offs_t offset,u8 data)208 void m24_state::dma_memory_write(offs_t offset, u8 data)
209 {
210 	const int seg = (BIT(m_dma_active, 2) ? 0 : 2) | (BIT(m_dma_active, 3) ? 0 : 1);
211 	m_maincpu->space(AS_PROGRAM).write_byte(offset | u32(m_dma_segment[seg]) << 16, data);
212 }
213 
214 template <int Channel>
dma_io_read(offs_t offset)215 u8 m24_state::dma_io_read(offs_t offset)
216 {
217 	return m_isabus->dack_r(Channel);
218 }
219 
220 template <int Channel>
dma_io_write(offs_t offset,u8 data)221 void m24_state::dma_io_write(offs_t offset, u8 data)
222 {
223 	m_isabus->dack_w(Channel, data);
224 }
225 
226 template <int Channel>
WRITE_LINE_MEMBER(m24_state::dma_dack_w)227 WRITE_LINE_MEMBER(m24_state::dma_dack_w)
228 {
229 	m_isabus->dack_line_w(Channel, state);
230 
231 	if (!state)
232 	{
233 		m_dma_active |= 1 << Channel;
234 		if (Channel == 0)
235 			m_dmac->dreq0_w(0);
236 		if (m_tc)
237 			m_isabus->eop_w(Channel, ASSERT_LINE);
238 	}
239 	else
240 	{
241 		m_dma_active &= ~(1 << Channel);
242 		if (m_tc)
243 			m_isabus->eop_w(Channel, CLEAR_LINE);
244 	}
245 }
246 
WRITE_LINE_MEMBER(m24_state::dma_tc_w)247 WRITE_LINE_MEMBER(m24_state::dma_tc_w)
248 {
249 	m_tc = (state == ASSERT_LINE);
250 	for (int channel = 0; channel < 4; channel++)
251 		if (BIT(m_dma_active, channel))
252 			m_isabus->eop_w(channel, state);
253 }
254 
WRITE_LINE_MEMBER(m24_state::dreq0_ck_w)255 WRITE_LINE_MEMBER(m24_state::dreq0_ck_w)
256 {
257 	if (state && !m_dreq0_ck && !BIT(m_dma_active, 0))
258 		m_dmac->dreq0_w(1);
259 
260 	m_dreq0_ck = state;
261 }
262 
WRITE_LINE_MEMBER(m24_state::speaker_ck_w)263 WRITE_LINE_MEMBER(m24_state::speaker_ck_w)
264 {
265 	if (state)
266 		m_ctrlport_b |= 0x20;
267 	else
268 		m_ctrlport_b &= 0xdf;
269 
270 	update_speaker();
271 }
272 
update_speaker()273 void m24_state::update_speaker()
274 {
275 	if (BIT(m_ctrlport_a, 1) && BIT(m_ctrlport_b, 5))
276 	{
277 		m_speaker->level_w(1);
278 		m_ctrlport_b &= 0xef;
279 	}
280 	else
281 	{
282 		m_speaker->level_w(0);
283 		m_ctrlport_b |= 0x10;
284 	}
285 }
286 
keyboard_data_r()287 u8 m24_state::keyboard_data_r()
288 {
289 	if (!machine().side_effects_disabled())
290 	{
291 		m_pa |= 0x40;
292 		m_pic->ir1_w(0);
293 	}
294 	return m_kbcout;
295 }
296 
keyboard_status_r()297 u8 m24_state::keyboard_status_r()
298 {
299 	return (m_kbcibf ? 2 : 0) | ((m_pa & 0x40) ? 0 : 1);
300 }
301 
keyboard_data_w(u8 data)302 void m24_state::keyboard_data_w(u8 data)
303 {
304 	m_kbc->set_input_line(TMS7000_INT1_LINE, ASSERT_LINE);
305 	m_kbcibf = true;
306 	m_kbcin = data;
307 }
308 
ctrlport_a_w(u8 data)309 void m24_state::ctrlport_a_w(u8 data)
310 {
311 	const bool spkrdata_en_dis = BIT(data ^ m_ctrlport_a, 1);
312 	const bool iochk_en_dis = BIT(data ^ m_ctrlport_a, 4);
313 
314 	m_pit->write_gate2(BIT(data, 0));
315 
316 	if (BIT(m_ctrlport_a, 4) && !m_chck_active)
317 		m_ctrlport_b &= 0xbf;
318 
319 	if (BIT(data, 6))
320 		m_pa |= 4;
321 	else
322 		m_pa &= ~4;
323 
324 	m_ctrlport_a = data;
325 
326 	if (spkrdata_en_dis)
327 		update_speaker();
328 	if (iochk_en_dis)
329 		update_nmi();
330 }
331 
ctrlport_a_r()332 u8 m24_state::ctrlport_a_r()
333 {
334 	return m_ctrlport_a;
335 }
336 
ctrlport_b_r()337 u8 m24_state::ctrlport_b_r()
338 {
339 	// Bit 0 = NC
340 	// Bit 1 = SW4 (8087 present)
341 	// Bit 2 = ~RI1
342 	// Bit 3 = ~DSR1
343 	// Bit 4 = SPKR
344 	// Bit 5 = OUT2 (8253)
345 	// Bit 6 = IOCHK
346 	// Bit 7 = MBMERR (MRD parity check)
347 
348 	if (BIT(m_dsw0->read(), 4))
349 		m_ctrlport_b |= 0x02;
350 	else
351 		m_ctrlport_b &= 0xfd;
352 
353 	return m_ctrlport_b;
354 }
355 
alt_w(u8 data)356 void m24_state::alt_w(u8 data)
357 {
358 	m_maincpu->set_input_line(INPUT_LINE_HALT, (data & 0x40) ? ASSERT_LINE : CLEAR_LINE);
359 	m_i86_halt = true;
360 	m_i86_halt_perm = true;
361 }
362 
WRITE_LINE_MEMBER(m24_state::chck_w)363 WRITE_LINE_MEMBER(m24_state::chck_w)
364 {
365 	m_chck_active = (state == 0);
366 	if (m_chck_active)
367 	{
368 		if (!BIT(m_ctrlport_b, 6))
369 		{
370 			m_ctrlport_b |= 0x40;
371 			update_nmi();
372 		}
373 	}
374 	else if (BIT(m_ctrlport_a, 4))
375 		m_ctrlport_b &= 0xbf;
376 }
377 
WRITE_LINE_MEMBER(m24_state::int87_w)378 WRITE_LINE_MEMBER(m24_state::int87_w)
379 {
380 	m_87int = state;
381 	update_nmi();
382 }
383 
nmi_enable_w(u8 data)384 void m24_state::nmi_enable_w(u8 data)
385 {
386 	m_nmi_enable = BIT(data, 7);
387 	update_nmi();
388 }
389 
update_nmi()390 void m24_state::update_nmi()
391 {
392 	if (m_nmi_enable && ((m_87int && BIT(m_dsw0->read(), 4)) || (BIT(m_ctrlport_b, 6) && !BIT(m_ctrlport_a, 4))))
393 		m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
394 	else
395 		m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
396 }
397 
pa_r()398 u8 m24_state::pa_r()
399 {
400 	return m_pa & (m_kbdata ? 0xff : 0xfd);
401 }
402 
pb_w(u8 data)403 void m24_state::pb_w(u8 data)
404 {
405 	m_keyboard->clock_w(!BIT(data, 0));
406 	m_keyboard->data_w(!BIT(data, 1));
407 	m_pa = (m_pa & ~3) | (~data & 3);
408 }
409 
kbcdata_r()410 u8 m24_state::kbcdata_r()
411 {
412 	m_kbc->set_input_line(TMS7000_INT1_LINE, CLEAR_LINE);
413 	m_kbcibf = false;
414 	return m_kbcin;
415 }
416 
kbcdata_w(u8 data)417 void m24_state::kbcdata_w(u8 data)
418 {
419 	m_pa &= ~0x40;
420 	m_pic->ir1_w(1);
421 	m_kbcout = data;
422 }
423 
WRITE_LINE_MEMBER(m24_state::kbcin_w)424 WRITE_LINE_MEMBER(m24_state::kbcin_w)
425 {
426 	m_kbdata = state;
427 }
428 
WRITE_LINE_MEMBER(m24_state::int_w)429 WRITE_LINE_MEMBER(m24_state::int_w)
430 {
431 	if(!m_i86_halt)
432 		m_maincpu->set_input_line(INPUT_LINE_IRQ0, state ? ASSERT_LINE : CLEAR_LINE);
433 	if(m_z8000_apb && !m_z8000_apb->halted())
434 		m_z8000_apb->int_w(state ? ASSERT_LINE : CLEAR_LINE);
435 }
436 
WRITE_LINE_MEMBER(m24_state::halt_i86_w)437 WRITE_LINE_MEMBER(m24_state::halt_i86_w)
438 {
439 	if(m_i86_halt_perm)
440 		return;
441 	m_maincpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
442 	m_i86_halt = state ? true : false;
443 }
444 
m24_map(address_map & map)445 void m24_state::m24_map(address_map &map)
446 {
447 	map.unmap_value_high();
448 	map(0xf8000, 0xfffff).rom().region("bios", 0);
449 }
450 
m24_io(address_map & map)451 void m24_state::m24_io(address_map &map)
452 {
453 	map.unmap_value_high();
454 	map(0x0000, 0x000f).rw(m_dmac, FUNC(am9517a_device::read), FUNC(am9517a_device::write));
455 	map(0x0020, 0x0021).mirror(0xe).rw(m_pic, FUNC(pic8259_device::read), FUNC(pic8259_device::write));
456 	map(0x0040, 0x0043).mirror(0xc).rw(m_pit, FUNC(pit8253_device::read), FUNC(pit8253_device::write));
457 	map(0x0060, 0x0060).rw(FUNC(m24_state::keyboard_data_r), FUNC(m24_state::keyboard_data_w));
458 	map(0x0061, 0x0061).rw(FUNC(m24_state::ctrlport_a_r), FUNC(m24_state::ctrlport_a_w));
459 	map(0x0062, 0x0062).r(FUNC(m24_state::ctrlport_b_r));
460 	map(0x0064, 0x0064).r(FUNC(m24_state::keyboard_status_r));
461 	map(0x0065, 0x0065).w(FUNC(m24_state::alt_w));
462 	map(0x0066, 0x0067).portr("DSW0");
463 	map(0x0070, 0x007f).rw("mm58174an", FUNC(mm58174_device::read), FUNC(mm58174_device::write));
464 	map(0x0080, 0x0083).mirror(0xc).w(FUNC(m24_state::dma_segment_w));
465 	map(0x00a0, 0x00a1).mirror(0xe).w(FUNC(m24_state::nmi_enable_w));
466 	map(0x80c1, 0x80c1).rw(m_z8000_apb, FUNC(m24_z8000_device::handshake_r), FUNC(m24_z8000_device::handshake_w));
467 }
468 
kbc_map(address_map & map)469 void m24_state::kbc_map(address_map &map)
470 {
471 	map(0x8000, 0x8fff).r(FUNC(m24_state::kbcdata_r));
472 	map(0xa000, 0xafff).w(FUNC(m24_state::kbcdata_w));
473 	map(0xf800, 0xffff).rom().region("kbc", 0);
474 }
475 
476 static INPUT_PORTS_START( m24 )
477 	PORT_START("DSW0")
478 	PORT_DIPNAME( 0x8f, 0x89, "RAM banks")
479 	PORT_DIPSETTING(    0x01, "128K" )
480 	PORT_DIPSETTING(    0x82, "256K" )
481 	PORT_DIPSETTING(    0x84, "512K - 256/256" )
482 	PORT_DIPSETTING(    0x08, "512K - 512/0" )
483 	PORT_DIPSETTING(    0x85, "640K - 256/384" )
484 	PORT_DIPSETTING(    0x8d, "640K - 128/512" )
485 	PORT_DIPSETTING(    0x89, "640K - 512/128" )
486 	PORT_DIPNAME( 0x10, 0x00, "8087 installed")
DEF_STR(No)487 	PORT_DIPSETTING(    0x00, DEF_STR(No) )
488 	PORT_DIPSETTING(    0x10, DEF_STR(Yes) )
489 	PORT_DIPNAME( 0x20, 0x00, "Serial Port")
490 	PORT_DIPSETTING(    0x20, "Z8530 SCC")
491 	PORT_DIPSETTING(    0x00, "INS8250" )
492 
493 	//PORT_START("DSW1")
494 	PORT_DIPNAME( 0x0100, 0x0000, "FDD Type")
495 	PORT_DIPSETTING(    0x0000, "360K" )
496 	PORT_DIPSETTING(    0x0100, "720K" )
497 	PORT_DIPNAME( 0x0200, 0x0200, "FDD spinup")
498 	PORT_DIPSETTING(    0x0000, "Slow" )
499 	PORT_DIPSETTING(    0x0200, "Fast" )
500 	PORT_DIPNAME( 0x0400, 0x0400, "HDD ROM")
501 	PORT_DIPSETTING(    0x0000, "Internal" )
502 	PORT_DIPSETTING(    0x0400, "External" )
503 	PORT_DIPNAME( 0x0800, 0x0000, "Scroll rate")
504 	PORT_DIPSETTING(    0x0800, "Slow" )
505 	PORT_DIPSETTING(    0x0000, "Fast")
506 	PORT_DIPNAME( 0x3000, 0x2000, "Graphics adapter")
507 	PORT_DIPSETTING(    0x0000, "EGA/VGA" )
508 	PORT_DIPSETTING(    0x1000, "Color 40x25" )
509 	PORT_DIPSETTING(    0x2000, "Color 80x25" )
510 	PORT_DIPSETTING(    0x3000, "Monochrome" )
511 	PORT_DIPNAME( 0xc000, 0x4000, "Number of floppy drives")
512 	PORT_DIPSETTING(    0x0000, "1" )
513 	PORT_DIPSETTING(    0x4000, "2" )
514 	PORT_DIPSETTING(    0x8000, "3" )
515 	PORT_DIPSETTING(    0xc000, "4" )
516 INPUT_PORTS_END
517 
518 FLOPPY_FORMATS_MEMBER( m24_state::floppy_formats )
519 	FLOPPY_PC_FORMAT,
520 	FLOPPY_NASLITE_FORMAT,
521 	FLOPPY_M20_FORMAT
522 FLOPPY_FORMATS_END
523 
524 void m24_state::cfg_m20_format(device_t *device)
525 {
526 	device->subdevice<floppy_connector>("fdc:0")->set_formats(m24_state::floppy_formats);
527 	device->subdevice<floppy_connector>("fdc:1")->set_formats(m24_state::floppy_formats);
528 }
529 
olivetti(machine_config & config)530 void m24_state::olivetti(machine_config &config)
531 {
532 	/* basic machine hardware */
533 	I8086(config, m_maincpu, 24_MHz_XTAL / 3);
534 	m_maincpu->set_addrmap(AS_PROGRAM, &m24_state::m24_map);
535 	m_maincpu->set_addrmap(AS_IO, &m24_state::m24_io);
536 	m_maincpu->set_irq_acknowledge_callback("pic", FUNC(pic8259_device::inta_cb));
537 	m_maincpu->esc_opcode_handler().set("ndp", FUNC(i8087_device::insn_w));
538 	m_maincpu->esc_data_handler().set("ndp", FUNC(i8087_device::addr_w));
539 
540 	i8087_device &i8087(I8087(config, "ndp", 24_MHz_XTAL / 3));
541 	i8087.set_space_86(m_maincpu, AS_PROGRAM);
542 	i8087.irq().set(FUNC(m24_state::int87_w));
543 	i8087.busy().set_inputline(m_maincpu, INPUT_LINE_TEST);
544 
545 	AM9517A(config, m_dmac, 24_MHz_XTAL / 6); // 8237A-4
546 	m_dmac->out_hreq_callback().set(FUNC(m24_state::dma_hrq_w));
547 	m_dmac->in_memr_callback().set(FUNC(m24_state::dma_memory_read));
548 	m_dmac->out_memw_callback().set(FUNC(m24_state::dma_memory_write));
549 	m_dmac->in_ior_callback<1>().set(FUNC(m24_state::dma_io_read<1>));
550 	m_dmac->in_ior_callback<2>().set(FUNC(m24_state::dma_io_read<2>));
551 	m_dmac->in_ior_callback<3>().set(FUNC(m24_state::dma_io_read<3>));
552 	m_dmac->out_iow_callback<1>().set(FUNC(m24_state::dma_io_write<1>));
553 	m_dmac->out_iow_callback<2>().set(FUNC(m24_state::dma_io_write<2>));
554 	m_dmac->out_iow_callback<3>().set(FUNC(m24_state::dma_io_write<3>));
555 	m_dmac->out_dack_callback<0>().set(FUNC(m24_state::dma_dack_w<0>));
556 	m_dmac->out_dack_callback<1>().set(FUNC(m24_state::dma_dack_w<1>));
557 	m_dmac->out_dack_callback<2>().set(FUNC(m24_state::dma_dack_w<2>));
558 	m_dmac->out_dack_callback<3>().set(FUNC(m24_state::dma_dack_w<3>));
559 	m_dmac->out_eop_callback().set(FUNC(m24_state::dma_tc_w));
560 
561 	PIC8259(config, m_pic);
562 	m_pic->in_sp_callback().set_constant(1);
563 	m_pic->out_int_callback().set(FUNC(m24_state::int_w));
564 
565 	PIT8253(config, m_pit); // 8253-5
566 	m_pit->set_clk<0>(3.6864_MHz_XTAL / 3); // divided by LS175 at 8T
567 	m_pit->set_clk<1>(3.6864_MHz_XTAL / 3);
568 	m_pit->set_clk<2>(3.6864_MHz_XTAL / 3);
569 	m_pit->out_handler<0>().set(m_pic, FUNC(pic8259_device::ir0_w));
570 	m_pit->out_handler<1>().set(FUNC(m24_state::dreq0_ck_w));
571 	m_pit->out_handler<2>().set(FUNC(m24_state::speaker_ck_w));
572 
573 	SPEAKER(config, "mono").front_center();
574 	SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 1.00);
575 
576 	ISA8(config, m_isabus, 24_MHz_XTAL / 6);
577 	m_isabus->set_memspace(m_maincpu, AS_PROGRAM);
578 	m_isabus->set_iospace(m_maincpu, AS_IO);
579 	m_isabus->irq2_callback().set(m_pic, FUNC(pic8259_device::ir2_w));
580 	m_isabus->irq3_callback().set(m_pic, FUNC(pic8259_device::ir3_w));
581 	m_isabus->irq4_callback().set(m_pic, FUNC(pic8259_device::ir4_w));
582 	m_isabus->irq5_callback().set(m_pic, FUNC(pic8259_device::ir5_w));
583 	m_isabus->irq6_callback().set(m_pic, FUNC(pic8259_device::ir6_w));
584 	m_isabus->irq7_callback().set(m_pic, FUNC(pic8259_device::ir7_w));
585 	m_isabus->drq1_callback().set(m_dmac, FUNC(am9517a_device::dreq1_w));
586 	m_isabus->drq2_callback().set(m_dmac, FUNC(am9517a_device::dreq2_w));
587 	m_isabus->drq3_callback().set(m_dmac, FUNC(am9517a_device::dreq3_w));
588 	m_isabus->iochck_callback().set(FUNC(m24_state::chck_w));
589 
590 	ISA8_SLOT(config, "mb1", 0, m_isabus, pc_isa8_cards, "cga_m24", true);
591 	ISA8_SLOT(config, "mb2", 0, m_isabus, pc_isa8_cards, "fdc_xt", true).set_option_machine_config("fdc_xt", cfg_m20_format);
592 	ISA8_SLOT(config, "mb3", 0, m_isabus, pc_isa8_cards, "lpt", true);
593 	ISA8_SLOT(config, "mb4", 0, m_isabus, pc_isa8_cards, "com", true);
594 
595 	ISA8_SLOT(config, "isa1", 0, m_isabus, pc_isa8_cards, nullptr, false);
596 	ISA8_SLOT(config, "isa2", 0, m_isabus, pc_isa8_cards, nullptr, false);
597 	ISA8_SLOT(config, "isa3", 0, m_isabus, pc_isa8_cards, nullptr, false);
598 
599 	// 2 banks of 16 64Kx1 or 256Kx1 DRAMs on motherboard
600 	RAM(config, m_ram).set_default_size("640K").set_extra_options("128K, 256K, 512K");
601 
602 	TMS7000(config, m_kbc, 24_MHz_XTAL / 6);
603 	m_kbc->set_addrmap(AS_PROGRAM, &m24_state::kbc_map);
604 	m_kbc->in_porta().set(FUNC(m24_state::pa_r));
605 	m_kbc->out_portb().set(FUNC(m24_state::pb_w));
606 
607 	M24_KEYBOARD(config, m_keyboard, 0);
608 	m_keyboard->out_data_handler().set(FUNC(m24_state::kbcin_w));
609 
610 	MM58174(config, "mm58174an", 32.768_kHz_XTAL);
611 
612 	M24_Z8000(config, m_z8000_apb, 0); // TODO: make this a slot device (uses custom bus connector)
613 	m_z8000_apb->halt_callback().set(FUNC(m24_state::halt_i86_w));
614 
615 	/* software lists */
616 	SOFTWARE_LIST(config, "disk_list").set_original("ibm5150");
617 	SOFTWARE_LIST(config, "m24_disk_list").set_original("m24");
618 }
619 
620 ROM_START( m21 )
621 	ROM_REGION16_LE(0x8000,"bios", 0)
622 	ROMX_LOAD( "bios_m24_144_even.bin", 0x4000, 0x2000, CRC(5f3d7084) SHA1(d55c0d8472b45e4c4ca9cb0066cd5c122056ba8e), ROM_SKIP(1))
623 	ROMX_LOAD( "bios_m24_144_odd.bin", 0x4001, 0x2000, CRC(18fd8db8) SHA1(f2c9d189f7ded88946a99432abd7106d509a7411), ROM_SKIP(1))
624 
625 	ROM_REGION(0x800, "kbc", 0)
626 	ROM_LOAD("pdbd.tms2516.kbdmcu_replacement_board.10u", 0x000, 0x800, CRC(b8c4c18a) SHA1(25b4c24e19ff91924c53557c66513ab242d926c6))
627 ROM_END
628 
629 ROM_START( m24 )
630 	ROM_REGION16_LE(0x8000,"bios", 0)
631 	ROM_SYSTEM_BIOS(0,"v1.1","v1.1")
632 	ROMX_LOAD("m24_bios11h.rom",0x4001, 0x2000, CRC(f08e859a) SHA1(c2ede7ce4472c77462d1d841e2b47e8b306c563d), ROM_SKIP(1) | ROM_BIOS(0))
633 	ROMX_LOAD("m24_bios11l.rom", 0x4000, 0x2000, CRC(ec494e66) SHA1(51259cf9fd9f6a6855d52730206ff66ad3367ea4), ROM_SKIP(1) | ROM_BIOS(0))
634 
635 	ROM_SYSTEM_BIOS(1,"v1.21","v1.21")
636 	ROMX_LOAD("m24_bios121h.rom",0x4001, 0x2000, CRC(93292715) SHA1(863eccfb3beca6e64c5b0cc070c64394bad7da82), ROM_SKIP(1) | ROM_BIOS(1))
637 	ROMX_LOAD("m24_bios121l.rom", 0x4000, 0x2000, CRC(1acbc9d7) SHA1(d3696e38853cea31e70ffa4e13e127ec7551bf57), ROM_SKIP(1) | ROM_BIOS(1))
638 
639 	ROM_SYSTEM_BIOS(2,"v1.36","v1.36")
640 	ROMX_LOAD("m24_bios136h.rom",0x4001, 0x2000, CRC(25cbf8ba) SHA1(1ab90985852544d2c12b47bb7f20f9faccabdf88), ROM_SKIP(1) | ROM_BIOS(2))
641 	ROMX_LOAD("m24_bios136l.rom", 0x4000, 0x2000, CRC(e2f738c0) SHA1(da9771325a5021cf9908997e0e0d14e47258125f), ROM_SKIP(1) | ROM_BIOS(2))
642 
643 	ROM_SYSTEM_BIOS(3,"v1.43","v1.43")
644 	ROMX_LOAD("olivetti_m24_version_1.43_high.bin",0x4001, 0x2000, CRC(04e697ba) SHA1(1066dcc849e6289b5ac6372c84a590e456d497a6), ROM_SKIP(1) | ROM_BIOS(3))
645 	ROMX_LOAD("olivetti_m24_version_1.43_low.bin", 0x4000, 0x2000, CRC(ff7e0f10) SHA1(13423011a9bae3f3193e8c199f98a496cab48c0f), ROM_SKIP(1) | ROM_BIOS(3))
646 
647 	ROM_REGION(0x800, "kbc", 0)
648 	ROM_LOAD("pdbd.tms2516.kbdmcu_replacement_board.10u", 0x000, 0x800, CRC(b8c4c18a) SHA1(25b4c24e19ff91924c53557c66513ab242d926c6))
649 ROM_END
650 
651 ROM_START( m240 )
652 	ROM_REGION16_LE(0x8000,"bios", 0)
653 	ROMX_LOAD("olivetti_m240_pch5_2.04_high.bin", 0x0001, 0x4000, CRC(ceb97b59) SHA1(84fabbeab355e0a4c9445910f2b7d1ec98886642), ROM_SKIP(1))
654 	ROMX_LOAD("olivetti_m240_pch6_2.04_low.bin",  0x0000, 0x4000, CRC(c463aa94) SHA1(a30c763c1ace9f3ff79e7136b252d624108a50ae), ROM_SKIP(1))
655 
656 	// is this one the same?
657 	ROM_REGION(0x800, "kbc", 0)
658 	ROM_LOAD("pdbd.tms2516.kbdmcu_replacement_board.10u", 0x000, 0x800, BAD_DUMP CRC(b8c4c18a) SHA1(25b4c24e19ff91924c53557c66513ab242d926c6))
659 ROM_END
660 
661 COMP( 1984, m21,  ibm5150, 0, olivetti, m24, m24_state, empty_init, "Olivetti", "M21",  MACHINE_NOT_WORKING )
662 COMP( 1983, m24,  ibm5150, 0, olivetti, m24, m24_state, empty_init, "Olivetti", "M24",  MACHINE_NOT_WORKING )
663 COMP( 1987, m240, ibm5150, 0, olivetti, m24, m24_state, empty_init, "Olivetti", "M240", MACHINE_NOT_WORKING )
664