1 // license:BSD-3-Clause
2 // copyright-holders:rfka01, Robbbert
3 /***************************************************************************
4 
5 Mikrocomputer fuer Ausbildung
6 Berufsfoerdungszentrum Essen
7 Information found on Wikipedia:
8 - System is a backbone upon which all functions are available on plug-in cards
9 - 32k RAM, 32k ROM
10 - Serial is via CPU SID/SOD pins, but can be replaced by 8251 on RS232 card
11 - Protocol is COM1, 4800, 8N1
12 - Timer card uses 8253
13 - PIO card uses 8255 and has a printer interface
14 - Cassette interface uses RS232 card
15 - Optional floppy (both sizes); and a EPROM burner
16 - OS: MAT85
17 
18 Manuals have no schematics and no mention of the 8253 or 8255. The bios
19 doesn't try communicating with them either.
20 
21 Commands:
22 A     Assembler
23 B     Set Breakpoint
24 D     Disassembler
25 G     Go
26 H     Help
27 I     Inport
28 L     Load memory from tape
29 M     Print/Modify memory (A=ascii, B=bit, H=hex)
30 N     Turn on tracer & step to next instruction
31 O     Outport
32 P     Display memory contents in various formats
33 R     Set initial register contents
34 S     Save memory to tape
35 T     Trace interval
36 
37 Pressing enter will change the prompt from KMD > to KMD+> and pressing
38 space will change it back.
39 
40 mfabfz85 -bios 0, 3 and 4 work; others produce rubbish.
41 
42 Cassette:
43 - Like many early designs, the interface is grossly over-complicated, using 12 chips.
44 - Similar to Kansas City, except that 1 = 3600Hz, 0 = 2400Hz
45 - The higher frequencies, only 50% apart, cause the interface to be less reliable
46 - Baud rates of 150, 300, 600, 1200 selected by a jumper. We emulate 1200 only,
47   as the current code would be too unreliable with the lower rates.
48 
49 ****************************************************************************/
50 
51 #include "emu.h"
52 #include "cpu/i8085/i8085.h"
53 #include "imagedev/cassette.h"
54 #include "machine/clock.h"
55 #include "machine/i8251.h"
56 #include "bus/rs232/rs232.h"
57 #include "speaker.h"
58 
59 
60 class mfabfz_state : public driver_device
61 {
62 public:
mfabfz_state(const machine_config & mconfig,device_type type,const char * tag)63 	mfabfz_state(const machine_config &mconfig, device_type type, const char *tag)
64 		: driver_device(mconfig, type, tag)
65 		, m_maincpu(*this, "maincpu")
66 		, m_cass(*this, "cassette")
67 		, m_uart(*this, "uart2")
68 	{ }
69 
70 	void mfabfz85(machine_config &config);
71 	void mfabfz(machine_config &config);
72 
73 private:
74 	void mfabfz85_io(address_map &map);
75 	void mfabfz_io(address_map &map);
76 	void mfabfz_mem(address_map &map);
77 	void machine_reset() override;
78 	void machine_start() override;
79 	DECLARE_WRITE_LINE_MEMBER(kansas_r);
80 	DECLARE_WRITE_LINE_MEMBER(kansas_w);
81 	u8 m_cass_data[5];
82 	bool m_cassoutbit, m_cassbit, m_cassold;
83 	required_device<cpu_device> m_maincpu;
84 	required_device<cassette_image_device> m_cass;
85 	required_device<i8251_device> m_uart;
86 };
87 
88 
mfabfz_mem(address_map & map)89 void mfabfz_state::mfabfz_mem(address_map &map)
90 {
91 	map.unmap_value_high();
92 	map(0x0000, 0x7fff).rom().region("roms", 0);
93 	map(0x8000, 0xffff).ram();
94 }
95 
mfabfz_io(address_map & map)96 void mfabfz_state::mfabfz_io(address_map &map)
97 {
98 	map.unmap_value_high();
99 	map.global_mask(0xff);
100 	map(0xbe, 0xbf).rw("uart1", FUNC(i8251_device::read), FUNC(i8251_device::write));
101 	map(0xfe, 0xff).rw("uart2", FUNC(i8251_device::read), FUNC(i8251_device::write));
102 }
103 
mfabfz85_io(address_map & map)104 void mfabfz_state::mfabfz85_io(address_map &map)
105 {
106 	map.unmap_value_high();
107 	map.global_mask(0xff);
108 	map(0xfe, 0xff).rw("uart2", FUNC(i8251_device::read), FUNC(i8251_device::write));
109 }
110 
111 /* Input ports */
INPUT_PORTS_START(mfabfz)112 static INPUT_PORTS_START( mfabfz )
113 INPUT_PORTS_END
114 
115 // Note: if the other baud rates are to be supported, then this function
116 //       will need to be redesigned.
117 WRITE_LINE_MEMBER( mfabfz_state::kansas_w )
118 {
119 	if ((m_cass->get_state() & CASSETTE_MASK_UISTATE) == CASSETTE_RECORD)
120 	{
121 		if (state)
122 		{
123 			// incoming @76923Hz (1200), 38461.5 (600), 19231.77 (300), 9615.38 (150)
124 			u8 twobit = m_cass_data[3] & 63;
125 			static u8 cycles[3] = { 11, 10, 11 }; // 1200 baud
126 
127 			if (twobit == 0)
128 			{
129 				m_cassold = m_cassoutbit;
130 				m_cass_data[2] = 0;
131 				m_cass_data[4] = 0;
132 			}
133 
134 			if (m_cass_data[2] == 0)
135 			{
136 				m_cassbit ^= 1;
137 				m_cass->output(m_cassbit ? -1.0 : +1.0);
138 
139 				if (m_cassold)
140 				{
141 					m_cass_data[4]++;
142 					if (m_cass_data[4] > 2)
143 						m_cass_data[4] = 0;
144 					m_cass_data[2] = cycles[m_cass_data[4]]; // 3600 Hz
145 				}
146 				else
147 					m_cass_data[2] = 16; // 2400 Hz
148 			}
149 
150 			m_cass_data[2]--;
151 			m_cass_data[3]++;
152 		}
153 	}
154 
155 	m_uart->write_txc(state);
156 }
157 
WRITE_LINE_MEMBER(mfabfz_state::kansas_r)158 WRITE_LINE_MEMBER(mfabfz_state::kansas_r)
159 {
160 	// incoming @76923Hz
161 	if (state)
162 	{
163 		// no tape - set to idle
164 		m_cass_data[1]++;
165 		if (m_cass_data[1] > 32)
166 		{
167 			m_cass_data[1] = 32;
168 			m_uart->write_rxd(1);
169 		}
170 
171 		if ((m_cass->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_PLAY)
172 			return;
173 
174 		/* cassette - turn 2400/3600Hz to a bit */
175 		uint8_t cass_ws = (m_cass->input() > +0.04) ? 1 : 0;
176 
177 		if (cass_ws != m_cass_data[0])
178 		{
179 			m_cass_data[0] = cass_ws;
180 			m_uart->write_rxd((m_cass_data[1] < 14) ? 1 : 0);
181 			m_cass_data[1] = 0;
182 		}
183 	}
184 
185 	m_uart->write_rxc(state);
186 }
187 
machine_reset()188 void mfabfz_state::machine_reset()
189 {
190 	m_cass_data[0] = m_cass_data[1] = m_cass_data[2] = m_cass_data[3] = m_cass_data[4] = 0;
191 	m_cassoutbit = m_cassold = m_cassbit = 1;
192 	m_uart->write_rxd(1);
193 	m_uart->write_cts(0);
194 }
195 
machine_start()196 void mfabfz_state::machine_start()
197 {
198 	save_item(NAME(m_cass_data));
199 	save_item(NAME(m_cassoutbit));
200 	save_item(NAME(m_cassbit));
201 	save_item(NAME(m_cassold));
202 }
203 
mfabfz(machine_config & config)204 void mfabfz_state::mfabfz(machine_config &config)
205 {
206 	/* basic machine hardware */
207 	I8085A(config, m_maincpu, 4_MHz_XTAL / 2);
208 	m_maincpu->set_addrmap(AS_PROGRAM, &mfabfz_state::mfabfz_mem);
209 	m_maincpu->set_addrmap(AS_IO, &mfabfz_state::mfabfz_io);
210 
211 	// uart1 - terminal
212 	clock_device &uart1_clock(CLOCK(config, "uart1_clock", 4_MHz_XTAL / 26));
213 	uart1_clock.signal_handler().set("uart1", FUNC(i8251_device::write_txc));
214 	uart1_clock.signal_handler().append("uart1", FUNC(i8251_device::write_rxc));
215 
216 	i8251_device &uart1(I8251(config, "uart1", 0));
217 	uart1.txd_handler().set("rs232", FUNC(rs232_port_device::write_txd));
218 	uart1.dtr_handler().set("rs232", FUNC(rs232_port_device::write_dtr));
219 	uart1.rts_handler().set("rs232", FUNC(rs232_port_device::write_rts));
220 
221 	rs232_port_device &rs232(RS232_PORT(config, "rs232", default_rs232_devices, "terminal"));
222 	rs232.rxd_handler().set("uart1", FUNC(i8251_device::write_rxd));
223 	rs232.dsr_handler().set("uart1", FUNC(i8251_device::write_dsr));
224 	rs232.cts_handler().set("uart1", FUNC(i8251_device::write_cts));
225 
226 	// uart2 - cassette - clock comes from 2MHz through a divider consisting of 4 chips and some jumpers.
227 	I8251(config, m_uart, 4_MHz_XTAL / 2);
228 	m_uart->txd_handler().set([this] (bool state) { m_cassoutbit = state; });
229 
230 	clock_device &uart_clock(CLOCK(config, "uart_clock", 4_MHz_XTAL / 52));
231 	uart_clock.signal_handler().set(FUNC(mfabfz_state::kansas_w));
232 	uart_clock.signal_handler().append(FUNC(mfabfz_state::kansas_r));
233 
234 	// cassette is connected to the uart
235 	CASSETTE(config, m_cass);
236 	m_cass->set_default_state(CASSETTE_STOPPED | CASSETTE_SPEAKER_ENABLED | CASSETTE_MOTOR_ENABLED);
237 	SPEAKER(config, "mono").front_center();
238 	m_cass->add_route(ALL_OUTPUTS, "mono", 0.05);
239 }
240 
241 static DEVICE_INPUT_DEFAULTS_START( terminal )
242 	DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_4800 )
243 	DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_4800 )
244 	DEVICE_INPUT_DEFAULTS( "RS232_STARTBITS", 0xff, RS232_STARTBITS_1 )
245 	DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_8 )
246 	DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_NONE )
247 	DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_2 )
248 DEVICE_INPUT_DEFAULTS_END
249 
mfabfz85(machine_config & config)250 void mfabfz_state::mfabfz85(machine_config &config)
251 {
252 	/* basic machine hardware */
253 	i8085a_cpu_device &maincpu(I8085A(config, m_maincpu, 4_MHz_XTAL / 2));
254 	maincpu.set_addrmap(AS_PROGRAM, &mfabfz_state::mfabfz_mem);
255 	maincpu.set_addrmap(AS_IO, &mfabfz_state::mfabfz85_io);
256 	maincpu.in_sid_func().set("rs232", FUNC(rs232_port_device::rxd_r));
257 	maincpu.out_sod_func().set("rs232", FUNC(rs232_port_device::write_txd)).invert();
258 
259 	rs232_port_device &rs232(RS232_PORT(config, "rs232", default_rs232_devices, "terminal"));
260 	rs232.set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(terminal));
261 
262 	I8251(config, m_uart, 4_MHz_XTAL / 2);
263 	m_uart->txd_handler().set([this] (bool state) { m_cassoutbit = state; });
264 
265 	clock_device &uart_clock(CLOCK(config, "uart_clock", 4_MHz_XTAL / 52));
266 	uart_clock.signal_handler().set(FUNC(mfabfz_state::kansas_w));
267 	uart_clock.signal_handler().append(FUNC(mfabfz_state::kansas_r));
268 
269 	// cassette is connected to the uart
270 	CASSETTE(config, m_cass);
271 	m_cass->set_default_state(CASSETTE_STOPPED | CASSETTE_SPEAKER_ENABLED | CASSETTE_MOTOR_ENABLED);
272 	SPEAKER(config, "mono").front_center();
273 	m_cass->add_route(ALL_OUTPUTS, "mono", 0.05);
274 }
275 
276 
277 /* ROM definition */
278 ROM_START( mfabfz )
279 	ROM_REGION( 0x8000, "roms", 0 ) // MAT32K, 1986, works
280 	ROM_LOAD( "mfa_mat32k_vers.1.8-t_ic0.bin", 0x0000, 0x8000, CRC(6cba989e) SHA1(81611b6250a5319e5d28af5ce3a1e261af8315ae) )
281 ROM_END
282 
283 ROM_START( mfabfz85 )
284 	ROM_REGION( 0x8000, "roms", 0 )
285 	ROM_SYSTEM_BIOS( 0, "32k", "MAT32K v1.8s" ) // 1982, 4800, 8N2, txd-invert
286 	ROMX_LOAD( "mfa_mat32k_vers.1.8-s_ic0.bin", 0x0000, 0x8000, CRC(021d7dff) SHA1(aa34b3a8bac52fc7746d35f5ffc6328734788cc2), ROM_BIOS(0) )
287 	ROM_SYSTEM_BIOS( 1, "8k", "MAT85 8k" ) // 1982, not working
288 	ROMX_LOAD( "mfa_mat_1_0000.bin", 0x0000, 0x0800, CRC(73b588ea) SHA1(2b9570fe44c3c19d6aa7c7c11ecf390fa5d48998), ROM_BIOS(1) )
289 	ROMX_LOAD( "mfa_mat_2_0800.bin", 0x0800, 0x0800, CRC(13f5be91) SHA1(2b9d64600679bab319a37381fc84e874c3b2a877), ROM_BIOS(1) )
290 	ROMX_LOAD( "mfa_mat_3_1000.bin", 0x1000, 0x0800, CRC(c9b91bb4) SHA1(ef829964f507b1f6bbcf3c557c274fe728636efe), ROM_BIOS(1) )
291 	ROMX_LOAD( "mfa_mat_4_1800.bin", 0x1800, 0x0800, CRC(649cd7f0) SHA1(e92f29c053234b36f22d525fe92e61bf24476f14), ROM_BIOS(1) )
292 	ROM_SYSTEM_BIOS( 2, "16k_set1", "MAT85+ 16k set1" ) // not working
293 	ROMX_LOAD( "mfa_mat85_0x0000-0x07ff.bin", 0x0000, 0x0800, CRC(73b588ea) SHA1(2b9570fe44c3c19d6aa7c7c11ecf390fa5d48998), ROM_BIOS(2) )
294 	ROMX_LOAD( "mfa_mat85_0x0800-0x0fff.bin", 0x0800, 0x0800, CRC(13f5be91) SHA1(2b9d64600679bab319a37381fc84e874c3b2a877), ROM_BIOS(2) )
295 	ROMX_LOAD( "mfa_mat85_0x1000-0x17ff.bin", 0x1000, 0x0800, CRC(c9b91bb4) SHA1(ef829964f507b1f6bbcf3c557c274fe728636efe), ROM_BIOS(2) )
296 	ROMX_LOAD( "mfa_mat85_0x1800-0x1fff.bin", 0x1800, 0x0800, CRC(649cd7f0) SHA1(e92f29c053234b36f22d525fe92e61bf24476f14), ROM_BIOS(2) )
297 	ROMX_LOAD( "mfa_mat85_0x2000-0x27ff.bin", 0x2000, 0x0800, CRC(d3592915) SHA1(68daec6c5c63692bc147b1710b9c45ca780f2c7b), ROM_BIOS(2) )
298 	ROMX_LOAD( "mfa_mat85_0x2800-0x2fff.bin", 0x2800, 0x0800, CRC(9a6aafa9) SHA1(af897e91cc2ce5d6e49fa88c920ad85e1f0209bf), ROM_BIOS(2) )
299 	ROMX_LOAD( "mfa_mat85_0x3000-0x37ff.bin", 0x3000, 0x0800, CRC(eae4e3d5) SHA1(f7112965874417bbfc4a32f31f84e1db83249ab7), ROM_BIOS(2) )
300 	ROMX_LOAD( "mfa_mat85_0x3800-0x3fff.bin", 0x3800, 0x0800, CRC(536db0e3) SHA1(328ccc18455f710390c29c0fd0f4b0713a4a69ae), ROM_BIOS(2) )
301 	ROM_SYSTEM_BIOS( 3, "16k_set2", "MAT85+ 16k set2" ) // 2400, 7N2, txd-invert
302 	ROMX_LOAD( "mat85_1_1of8.bin", 0x0000, 0x0800, CRC(73b588ea) SHA1(2b9570fe44c3c19d6aa7c7c11ecf390fa5d48998), ROM_BIOS(3) )
303 	ROMX_LOAD( "mat85_2_2of8.bin", 0x0800, 0x0800, CRC(c97acc82) SHA1(eedb27c19a2d21b5ec5bca6cafeb25584e21e500), ROM_BIOS(3) )
304 	ROMX_LOAD( "mat85_3_3of8.bin", 0x1000, 0x0800, CRC(c9b91bb4) SHA1(ef829964f507b1f6bbcf3c557c274fe728636efe), ROM_BIOS(3) )
305 	ROMX_LOAD( "mat85_4_4of8.bin", 0x1800, 0x0800, CRC(649cd7f0) SHA1(e92f29c053234b36f22d525fe92e61bf24476f14), ROM_BIOS(3) )
306 	ROMX_LOAD( "soft_1_5of8.bin",  0x2000, 0x0800, CRC(98d9e86e) SHA1(af78b370fe97a6017b192dadec4059256ee4f4c7), ROM_BIOS(3) )
307 	ROMX_LOAD( "soft_2_6of8.bin",  0x2800, 0x0800, CRC(81fc3b24) SHA1(186dbd389fd700c5af1ef7c37948e11701ec596e), ROM_BIOS(3) )
308 	ROMX_LOAD( "soft_3_7of8.bin",  0x3000, 0x0800, CRC(eae4e3d5) SHA1(f7112965874417bbfc4a32f31f84e1db83249ab7), ROM_BIOS(3) )
309 	ROMX_LOAD( "soft_4_8of8.bin",  0x3800, 0x0800, CRC(536db0e3) SHA1(328ccc18455f710390c29c0fd0f4b0713a4a69ae), ROM_BIOS(3) )
310 	ROM_SYSTEM_BIOS (4, "32k_dtp", "MAT32K dtp" ) // 2400, 7N2, txd-invert
311 	ROMX_LOAD( "mfa_mat85_sp1_ed_kpl_dtp_terminal.bin", 0x0000, 0x8000, CRC(ed432c19) SHA1(31cbc06d276dbb201d50967f4ddba26a42560753), ROM_BIOS(4) )
312 ROM_END
313 
314 /*    YEAR  NAME      PARENT  COMPAT  MACHINE   INPUT   CLASS,        INIT        COMPANY                         FULLNAME                               FLAGS */
315 COMP( 1979, mfabfz,   0,      0,      mfabfz,   mfabfz, mfabfz_state, empty_init, "Berufsfoerdungszentrum Essen", "Mikrocomputer fuer Ausbildung",       MACHINE_NOT_WORKING | MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE )
316 COMP( 1979, mfabfz85, mfabfz, 0,      mfabfz85, mfabfz, mfabfz_state, empty_init, "Berufsfoerdungszentrum Essen", "Mikrocomputer fuer Ausbildung MAT85", MACHINE_NOT_WORKING | MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE )
317