1 // license:BSD-3-Clause
2 // copyright-holders:Robbbert
3 /******************************************************************************
4 
5     Proteus III computer.
6 
7     2015-10-02 Skeleton [Robbbert]
8 
9     Chips:
10     6800 @ 894kHz
11     6850 (TTY keyboard interface)
12     6850 (Cassette interface)
13     6820 (PIA for Keyboard and video
14     6844 DMA
15     MC14411 baud rate generator
16     CRT96364 CRTC @1008kHz
17 
18     There's an undumped 74S287 prom (M24) in the video section.
19     It converts ascii control codes into the crtc control codes
20 
21     Schematic has lots of errors and omissions.
22 
23     Like many systems of the time, the cassette is grossly over-complicated,
24     using 12 chips for a standard Kansas-city interface. Speed = 600 baud.
25 
26     To use the serial keyboard, type in the command: PORT#1
27     and to go back to the parallel keyboard type in: PORT#0
28 
29     The Basic seems rather buggy and does odd things from time to time.
30     bios 0 doesn't seem to have any way to backspace and type over
31     bios 0 is the only one to have the EDIT command, although no idea how
32     to use it.
33     bios 2 is from a compatible system called "Micro Systemes 1", from the
34     same company.
35 
36     To Do:
37     - Add support for k7 cassette files.
38     - Need software
39     - Need missing PROM, so that all the CRTC controls can be emulated
40     - Keyboard may have its own CPU etc, but no info available.
41     - Missing buttons: BYE, PANIC, SPEED, HERE-IS. Could be more.
42     - Should be able to type in some low-res graphics from the keyboard, not implemented.
43 
44 ******************************************************************************/
45 
46 #include "emu.h"
47 
48 #include "cpu/m6800/m6800.h"
49 #include "imagedev/cassette.h"
50 #include "machine/6821pia.h"
51 #include "machine/6850acia.h"
52 #include "machine/mc14411.h"
53 #include "machine/clock.h"
54 #include "machine/keyboard.h"
55 #include "machine/timer.h"
56 
57 #include "bus/rs232/rs232.h"
58 
59 #include "emupal.h"
60 #include "screen.h"
61 #include "speaker.h"
62 
63 
64 class proteus3_state : public driver_device
65 {
66 public:
proteus3_state(const machine_config & mconfig,device_type type,const char * tag)67 	proteus3_state(const machine_config &mconfig, device_type type, const char *tag)
68 		: driver_device(mconfig, type, tag)
69 		, m_maincpu(*this, "maincpu")
70 		, m_p_chargen(*this, "chargen")
71 		, m_pia(*this, "pia")
72 		, m_brg(*this, "brg")
73 		, m_acia1(*this, "acia1")
74 		, m_acia2(*this, "acia2")
75 		, m_cass(*this, "cassette")
76 		, m_serial(*this, "SERIAL")
77 	{ }
78 
79 	void proteus3(machine_config &config);
80 
81 private:
82 	DECLARE_WRITE_LINE_MEMBER(ca2_w);
83 	void video_w(u8 data);
84 	void kbd_put(u8 data);
85 	DECLARE_WRITE_LINE_MEMBER(acia1_clock_w);
86 	TIMER_DEVICE_CALLBACK_MEMBER(kansas_r);
87 	u32 screen_update_proteus3(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
88 
89 	// Clocks
90 	void write_acia_clocks(int id, int state);
DECLARE_WRITE_LINE_MEMBER(write_f1_clock)91 	DECLARE_WRITE_LINE_MEMBER (write_f1_clock){ write_acia_clocks(mc14411_device::TIMER_F1, state); }
DECLARE_WRITE_LINE_MEMBER(write_f2_clock)92 	DECLARE_WRITE_LINE_MEMBER (write_f2_clock){ write_acia_clocks(mc14411_device::TIMER_F2, state); }
DECLARE_WRITE_LINE_MEMBER(write_f3_clock)93 	DECLARE_WRITE_LINE_MEMBER (write_f3_clock){ write_acia_clocks(mc14411_device::TIMER_F3, state); }
DECLARE_WRITE_LINE_MEMBER(write_f4_clock)94 	DECLARE_WRITE_LINE_MEMBER (write_f4_clock){ write_acia_clocks(mc14411_device::TIMER_F4, state); }
DECLARE_WRITE_LINE_MEMBER(write_f5_clock)95 	DECLARE_WRITE_LINE_MEMBER (write_f5_clock){ write_acia_clocks(mc14411_device::TIMER_F5, state); }
DECLARE_WRITE_LINE_MEMBER(write_f6_clock)96 	DECLARE_WRITE_LINE_MEMBER (write_f6_clock){ write_acia_clocks(mc14411_device::TIMER_F6, state); }
DECLARE_WRITE_LINE_MEMBER(write_f7_clock)97 	DECLARE_WRITE_LINE_MEMBER (write_f7_clock){ write_acia_clocks(mc14411_device::TIMER_F7, state); }
DECLARE_WRITE_LINE_MEMBER(write_f8_clock)98 	DECLARE_WRITE_LINE_MEMBER (write_f8_clock){ write_acia_clocks(mc14411_device::TIMER_F8, state); }
DECLARE_WRITE_LINE_MEMBER(write_f9_clock)99 	DECLARE_WRITE_LINE_MEMBER (write_f9_clock){ write_acia_clocks(mc14411_device::TIMER_F9, state); }
DECLARE_WRITE_LINE_MEMBER(write_f10_clock)100 	DECLARE_WRITE_LINE_MEMBER (write_f10_clock){ write_acia_clocks(mc14411_device::TIMER_F10, state); }
DECLARE_WRITE_LINE_MEMBER(write_f11_clock)101 	DECLARE_WRITE_LINE_MEMBER (write_f11_clock){ write_acia_clocks(mc14411_device::TIMER_F11, state); }
DECLARE_WRITE_LINE_MEMBER(write_f12_clock)102 	DECLARE_WRITE_LINE_MEMBER (write_f12_clock){ write_acia_clocks(mc14411_device::TIMER_F12, state); }
DECLARE_WRITE_LINE_MEMBER(write_f13_clock)103 	DECLARE_WRITE_LINE_MEMBER (write_f13_clock){ write_acia_clocks(mc14411_device::TIMER_F13, state); }
DECLARE_WRITE_LINE_MEMBER(write_f14_clock)104 	DECLARE_WRITE_LINE_MEMBER (write_f14_clock){ write_acia_clocks(mc14411_device::TIMER_F14, state); }
DECLARE_WRITE_LINE_MEMBER(write_f15_clock)105 	DECLARE_WRITE_LINE_MEMBER (write_f15_clock){ write_acia_clocks(mc14411_device::TIMER_F15, state); }
106 
107 	void mem_map(address_map &map);
108 
109 	virtual void machine_reset() override;
110 	virtual void machine_start() override;
111 	u8 m_video_data;
112 	u8 m_flashcnt;
113 	u16 m_curs_pos;
114 	u8 m_cass_data[4];
115 	bool m_cassbit, m_cassold, m_cassinbit;
116 	std::unique_ptr<u8[]> m_vram;
117 	required_device<cpu_device> m_maincpu;
118 	required_region_ptr<u8> m_p_chargen;
119 	required_device<pia6821_device> m_pia;
120 	required_device<mc14411_device> m_brg;
121 	required_device<acia6850_device> m_acia1; // cassette uart
122 	required_device<acia6850_device> m_acia2; // tty keyboard uart
123 	required_device<cassette_image_device> m_cass;
124 
125 	// hardware configuration and things that need rewiring
126 	required_ioport             m_serial;
127 };
128 
129 
130 
131 
132 /******************************************************************************
133  Address Maps
134 ******************************************************************************/
135 
mem_map(address_map & map)136 void proteus3_state::mem_map(address_map &map)
137 {
138 	map.unmap_value_high();
139 	map(0x0000, 0x7fff).ram();
140 	map(0x8004, 0x8007).rw(m_pia, FUNC(pia6821_device::read), FUNC(pia6821_device::write));
141 	map(0x8008, 0x8009).rw(m_acia1, FUNC(acia6850_device::read), FUNC(acia6850_device::write)); // cassette
142 	map(0x8010, 0x8011).rw(m_acia2, FUNC(acia6850_device::read), FUNC(acia6850_device::write)); // serial keyboard 7E2 (never writes data)
143 	map(0xc000, 0xffff).rom().region("maincpu", 0);
144 }
145 
146 
147 /******************************************************************************
148  Input Ports
149 ******************************************************************************/
150 
151 static INPUT_PORTS_START(proteus3)
152 	PORT_START("SERIAL")
153 	PORT_CONFNAME(0x0F , 0x00 , "Serial Baud Rate") // F1-F16 pins on MC14411 in X16
154 	PORT_CONFSETTING(mc14411_device::TIMER_F1,  "9600")
155 	PORT_CONFSETTING(mc14411_device::TIMER_F2,  "7200")
156 	PORT_CONFSETTING(mc14411_device::TIMER_F3,  "4800")
157 	PORT_CONFSETTING(mc14411_device::TIMER_F4,  "3600")
158 	PORT_CONFSETTING(mc14411_device::TIMER_F5,  "2400")
159 	PORT_CONFSETTING(mc14411_device::TIMER_F6,  "1800")
160 	PORT_CONFSETTING(mc14411_device::TIMER_F7,  "1200")
161 	PORT_CONFSETTING(mc14411_device::TIMER_F8,  "600")
162 	PORT_CONFSETTING(mc14411_device::TIMER_F9,  "300")
163 	PORT_CONFSETTING(mc14411_device::TIMER_F10, "200")
164 	PORT_CONFSETTING(mc14411_device::TIMER_F11, "150")
165 	PORT_CONFSETTING(mc14411_device::TIMER_F12, "134.5")
166 	PORT_CONFSETTING(mc14411_device::TIMER_F13, "110")
167 	PORT_CONFSETTING(mc14411_device::TIMER_F14, "75")
168 	PORT_CONFSETTING(mc14411_device::TIMER_F15, "57600")
169 	PORT_CONFSETTING(mc14411_device::TIMER_F16, "115200")
170 INPUT_PORTS_END
171 
kbd_put(u8 data)172 void proteus3_state::kbd_put(u8 data)
173 {
174 	if (data == 0x08)
175 		data = 0x0f; // take care of backspace (bios 1 and 2)
176 	m_pia->portb_w(data);
177 	m_pia->cb1_w(1);
178 	m_pia->cb1_w(0);
179 }
180 
write_acia_clocks(int id,int state)181 void proteus3_state::write_acia_clocks(int id, int state)
182 {
183 	if (id == m_serial->read()) // Configurable serial port
184 	{
185 		m_acia2->write_txc(state);
186 		m_acia2->write_rxc(state);
187 	}
188 	if (id == mc14411_device::TIMER_F8) // Fixed bitrate for the cassette interface
189 	{
190 		acia1_clock_w(state);
191 	}
192 }
193 
194 /******************************************************************************
195  Cassette
196 ******************************************************************************/
197 
TIMER_DEVICE_CALLBACK_MEMBER(proteus3_state::kansas_r)198 TIMER_DEVICE_CALLBACK_MEMBER( proteus3_state::kansas_r )
199 {
200 	// no tape - set uart to idle
201 	m_cass_data[1]++;
202 	if (m_cass_data[1] > 32)
203 	{
204 		m_cass_data[1] = 32;
205 		m_cassinbit = 1;
206 	}
207 
208 	/* cassette - turn 1200/2400Hz to a bit */
209 	u8 cass_ws = (m_cass->input() > +0.04) ? 1 : 0;
210 
211 	if (cass_ws != m_cass_data[0])
212 	{
213 		m_cass_data[0] = cass_ws;
214 		m_cassinbit = (m_cass_data[1] < 12) ? 1 : 0;
215 		m_cass_data[1] = 0;
216 	}
217 }
218 
WRITE_LINE_MEMBER(proteus3_state::acia1_clock_w)219 WRITE_LINE_MEMBER( proteus3_state::acia1_clock_w )
220 {
221 	// Save - 8N2 - /16 - 600baud
222 	// Load - 8N2 - /1
223 	u8 twobit = m_cass_data[3] & 15;
224 	// incoming @9600Hz
225 	if (state)
226 	{
227 		if (twobit == 0)
228 		{
229 			m_cassold = m_cassbit;
230 			// synchronous rx
231 			m_acia1->write_rxc(0);
232 			m_acia1->write_rxd(m_cassinbit);
233 			m_acia1->write_rxc(1);
234 		}
235 
236 		if (m_cassold)
237 			m_cass->output(BIT(m_cass_data[3], 1) ? +1.0 : -1.0); // 2400Hz
238 		else
239 			m_cass->output(BIT(m_cass_data[3], 2) ? +1.0 : -1.0); // 1200Hz
240 
241 		m_cass_data[3]++;
242 	}
243 
244 	m_acia1->write_txc(state);
245 }
246 
247 
248 /******************************************************************************
249  Video
250 ******************************************************************************/
video_w(u8 data)251 void proteus3_state::video_w(u8 data)
252 {
253 	m_video_data = data;
254 }
255 
WRITE_LINE_MEMBER(proteus3_state::ca2_w)256 WRITE_LINE_MEMBER( proteus3_state::ca2_w )
257 {
258 	if (state)
259 	{
260 		switch(m_video_data)
261 		{
262 			case 0x0a: // Line Feed
263 				if (m_curs_pos > 959) // on bottom line?
264 				{
265 					memmove(m_vram.get(), m_vram.get()+64, 960); // scroll
266 					memset(m_vram.get()+960, 0x20, 64); // blank bottom line
267 				}
268 				else
269 					m_curs_pos += 64;
270 				break;
271 			case 0x0d: // Carriage Return
272 				m_curs_pos &= 0x3c0;
273 				break;
274 			case 0x0c: // CLS
275 				m_curs_pos = 0; // home cursor
276 				memset(m_vram.get(), 0x20, 1024); // clear screen
277 				break;
278 			case 0x0f: // Cursor Left
279 				if (m_curs_pos)
280 					m_curs_pos--;
281 				break;
282 			case 0x7f: // Erase character under cursor
283 				m_vram[m_curs_pos] = 0x20;
284 				break;
285 			default: // If a displayable character, show it
286 				if ((m_video_data > 0x1f) && (m_video_data < 0x7f))
287 				{
288 					m_vram[m_curs_pos] = m_video_data;
289 					m_curs_pos++;
290 					if (m_curs_pos > 1023) // have we run off the bottom?
291 					{
292 						m_curs_pos -= 64;
293 						memmove(m_vram.get(), m_vram.get()+64, 960); // scroll
294 						memset(m_vram.get()+960, 0x20, 64); // blank bottom line
295 					}
296 				}
297 		}
298 	}
299 }
300 
screen_update_proteus3(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)301 u32 proteus3_state::screen_update_proteus3(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
302 {
303 	u16 sy=0,ma=0;
304 	m_flashcnt++;
305 
306 	for (u8 y = 0; y < 16; y++ )
307 	{
308 		for (u8 ra = 0; ra < 12; ra++)
309 		{
310 			u16 *p = &bitmap.pix(sy++);
311 
312 			for (u16 x = ma; x < ma + 64; x++)
313 			{
314 				u8 gfx = 0;
315 				if (ra < 8)
316 				{
317 					u8 chr = m_vram[x]; // get char in videoram
318 					gfx = m_p_chargen[(chr<<3) | ra]; // get dot pattern in chargen
319 				}
320 				else if ((ra == 9) && (m_curs_pos == x) && BIT(m_flashcnt, 4))
321 					gfx = 0xff;
322 
323 				/* Display a scanline of a character */
324 				*p++ = BIT(gfx, 0);
325 				*p++ = BIT(gfx, 1);
326 				*p++ = BIT(gfx, 2);
327 				*p++ = BIT(gfx, 3);
328 				*p++ = BIT(gfx, 4);
329 				*p++ = BIT(gfx, 5);
330 				*p++ = BIT(gfx, 6);
331 				*p++ = BIT(gfx, 7);
332 			}
333 		}
334 		ma+=64;
335 	}
336 	return 0;
337 }
338 
339 
340 /* F4 Character Displayer */
341 static const gfx_layout charlayout =
342 {
343 	8, 8,                  /* 8 x 8 characters */
344 	128,                    /* 128 characters */
345 	1,                  /* 1 bits per pixel */
346 	{ 0 },                  /* no bitplanes */
347 	/* x offsets */
348 	{ 7, 6, 5, 4, 3, 2, 1, 0 },
349 	/* y offsets */
350 	{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
351 	8*8                    /* every char takes 8 bytes */
352 };
353 
354 static GFXDECODE_START( gfx_proteus3 )
355 	GFXDECODE_ENTRY( "chargen", 0, charlayout, 0, 1 )
356 GFXDECODE_END
357 
358 
machine_reset()359 void proteus3_state::machine_reset()
360 {
361 	m_curs_pos = 0;
362 	m_cass_data[0] = m_cass_data[1] = m_cass_data[2] = m_cass_data[3] = 0;
363 	m_cassbit = 1;
364 	m_cassold = 1;
365 	m_acia1->write_rxd(1);
366 
367 	// Set up the BRG divider. RSA is a jumper setting and RSB is always set High
368 	m_brg->rsa_w( CLEAR_LINE );
369 	m_brg->rsb_w( ASSERT_LINE );
370 
371 	// Disable all configured timers, only enabling the used ones
372 	m_brg->timer_disable_all();
373 	m_brg->timer_enable((mc14411_device::timer_id) m_serial->read(), true); // Serial port
374 	m_brg->timer_enable( mc14411_device::TIMER_F8, true); // Cassette interface
375 }
376 
machine_start()377 void proteus3_state::machine_start()
378 {
379 	m_vram = make_unique_clear<u8[]>(0x0400);
380 	save_pointer(NAME(m_vram), 0x0400);
381 	save_item(NAME(m_video_data));
382 	save_item(NAME(m_flashcnt));
383 	save_item(NAME(m_curs_pos));
384 	save_item(NAME(m_cass_data));
385 	save_item(NAME(m_cassbit));
386 	save_item(NAME(m_cassold));
387 	save_item(NAME(m_cassinbit));
388 }
389 
390 /******************************************************************************
391  Machine Drivers
392 ******************************************************************************/
393 
proteus3(machine_config & config)394 void proteus3_state::proteus3(machine_config &config)
395 {
396 	/* basic machine hardware */
397 	M6800(config, m_maincpu, XTAL(3'579'545));  /* Divided by 4 internally */
398 	m_maincpu->set_addrmap(AS_PROGRAM, &proteus3_state::mem_map);
399 
400 	/* video hardware */
401 	screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
402 	screen.set_refresh_hz(50);
403 	screen.set_vblank_time(ATTOSECONDS_IN_USEC(200));
404 	screen.set_size(64*8, 16*12);
405 	screen.set_visarea(0, 64*8-1, 0, 16*12-1);
406 	screen.set_screen_update(FUNC(proteus3_state::screen_update_proteus3));
407 	screen.set_palette("palette");
408 	GFXDECODE(config, "gfxdecode", "palette", gfx_proteus3);
409 	PALETTE(config, "palette", palette_device::MONOCHROME);
410 
411 	/* Devices */
412 	PIA6821(config, m_pia, 0);
413 	m_pia->writepa_handler().set(FUNC(proteus3_state::video_w));
414 	m_pia->ca2_handler().set(FUNC(proteus3_state::ca2_w));
415 	m_pia->irqb_handler().set_inputline("maincpu", M6800_IRQ_LINE);
416 
417 	generic_keyboard_device &keyboard(GENERIC_KEYBOARD(config, "keyboard", 0));
418 	keyboard.set_keyboard_callback(FUNC(proteus3_state::kbd_put));
419 
420 	/* cassette */
421 	ACIA6850(config, m_acia1, 0);
422 	m_acia1->txd_handler().set([this] (bool state) { m_cassbit = state; });
423 
424 	SPEAKER(config, "mono").front_center();
425 
426 	CASSETTE(config, m_cass);
427 	m_cass->set_default_state(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED);
428 	m_cass->add_route(ALL_OUTPUTS, "mono", 0.05);
429 	TIMER(config, "kansas_r").configure_periodic(FUNC(proteus3_state::kansas_r), attotime::from_hz(40000));
430 
431 	// optional tty keyboard
432 	ACIA6850(config, m_acia2, 0);
433 	m_acia2->txd_handler().set("rs232", FUNC(rs232_port_device::write_txd));
434 	m_acia2->rts_handler().set("rs232", FUNC(rs232_port_device::write_rts));
435 
436 	rs232_port_device &rs232(RS232_PORT(config, "rs232", default_rs232_devices, "keyboard"));
437 	rs232.rxd_handler().set(m_acia2, FUNC(acia6850_device::write_rxd));
438 	rs232.cts_handler().set(m_acia2, FUNC(acia6850_device::write_cts));
439 
440 	/* Bit Rate Generator */
441 	MC14411(config, m_brg, XTAL(1'843'200)); // crystal needs verification but is the likely one
442 	m_brg->out_f<1>().set(FUNC(proteus3_state::write_f1_clock));
443 	m_brg->out_f<2>().set(FUNC(proteus3_state::write_f2_clock));
444 	m_brg->out_f<3>().set(FUNC(proteus3_state::write_f3_clock));
445 	m_brg->out_f<4>().set(FUNC(proteus3_state::write_f4_clock));
446 	m_brg->out_f<5>().set(FUNC(proteus3_state::write_f5_clock));
447 	m_brg->out_f<6>().set(FUNC(proteus3_state::write_f6_clock));
448 	m_brg->out_f<7>().set(FUNC(proteus3_state::write_f7_clock));
449 	m_brg->out_f<8>().set(FUNC(proteus3_state::write_f8_clock));
450 	m_brg->out_f<9>().set(FUNC(proteus3_state::write_f9_clock));
451 	m_brg->out_f<10>().set(FUNC(proteus3_state::write_f10_clock));
452 	m_brg->out_f<11>().set(FUNC(proteus3_state::write_f11_clock));
453 	m_brg->out_f<12>().set(FUNC(proteus3_state::write_f12_clock));
454 	m_brg->out_f<13>().set(FUNC(proteus3_state::write_f13_clock));
455 	m_brg->out_f<14>().set(FUNC(proteus3_state::write_f14_clock));
456 	m_brg->out_f<15>().set(FUNC(proteus3_state::write_f15_clock));
457 }
458 
459 
460 
461 /******************************************************************************
462  ROM Definitions
463 ******************************************************************************/
464 
465 ROM_START(proteus3)
466 	ROM_REGION(0x4000, "maincpu", ROMREGION_ERASE00)  // if c000 isn't 0 it assumes a rom is there and jumps to it
467 	ROM_SYSTEM_BIOS( 0, "14k", "14k BASIC")
468 	ROMX_LOAD( "bas1.bin",     0x0800, 0x0800, CRC(016bf2d6) SHA1(89605dbede3b6fd101ee0548e5c545a0824fcfd3), ROM_BIOS(0) )
469 	ROMX_LOAD( "bas2.bin",     0x1000, 0x0800, CRC(39d3e543) SHA1(dd0fe220e3c2a48ce84936301311cbe9f1597ca7), ROM_BIOS(0) )
470 	ROMX_LOAD( "bas3.bin",     0x1800, 0x0800, CRC(3a41617d) SHA1(175406f4732389e226bc50d27ada39e6ea48de34), ROM_BIOS(0) )
471 	ROMX_LOAD( "bas4.bin",     0x2000, 0x0800, CRC(ee9d77ee) SHA1(f7e60a1ab88a3accc8ffdc545657c071934d09d2), ROM_BIOS(0) )
472 	ROMX_LOAD( "bas5.bin",     0x2800, 0x0800, CRC(bd81bb34) SHA1(6325735e5750a9536e63b67048f74711fae1fa42), ROM_BIOS(0) )
473 	ROMX_LOAD( "bas6.bin",     0x3000, 0x0800, CRC(60cd006b) SHA1(28354f78490da1eb5116cbbc43eaca0670f7f398), ROM_BIOS(0) )
474 	ROMX_LOAD( "bas7.bin",     0x3800, 0x0800, CRC(84c3dc22) SHA1(8fddba61b5f0270ca2daef32ab5edfd60300c776), ROM_BIOS(0) )
475 
476 	ROM_SYSTEM_BIOS( 1, "8k", "8k BASIC")
477 	ROMX_LOAD( "proteus3_basic8k.m0", 0x2000, 0x2000, CRC(7d9111c2) SHA1(3c032c9c7f87d22a1a9819b3b812be84404d2ad2), ROM_BIOS(1) )
478 	ROM_RELOAD( 0x0000, 0x2000 )
479 
480 	ROM_SYSTEM_BIOS( 2, "8kms", "8k Micro-Systemes BASIC")
481 	ROMX_LOAD( "ms1_basic8k.bin", 0x2000, 0x2000, CRC(b5476e28) SHA1(c8c2366d549b2645c740be4ab4237e05c3cab4a9), ROM_BIOS(2) )
482 	ROM_RELOAD( 0x0000, 0x2000 )
483 
484 	ROM_REGION(0x0400, "chargen", 0)
485 	ROM_LOAD( "proteus3_font.m25",   0x0200, 0x0100, CRC(6a3a30a5) SHA1(ab39bf09722928483e497b87ac2dbd870828893b) )
486 	ROM_CONTINUE( 0x100, 0x100 )
487 	ROM_CONTINUE( 0x300, 0x100 )
488 	ROM_CONTINUE( 0x000, 0x100 )
489 
490 	ROM_REGION(0x0800, "user1", 0) // roms not used yet
491 	// Proteus III - pbug F800-FFFF, expects RAM at F000-F7FF
492 	ROM_LOAD( "proteus3_pbug.bin", 0x0000, 0x0800, CRC(1118694d) SHA1(2dfc08d405e8f2936f5b0bd1c4007995151abbba) )
493 ROM_END
494 
495 
496 /******************************************************************************
497  Drivers
498 ******************************************************************************/
499 
500 //    YEAR  NAME      PARENT  COMPAT  MACHINE   INPUT     CLASS           INIT        COMPANY                  FULLNAME       FLAGS
501 COMP( 1978, proteus3, 0,      0,      proteus3, proteus3, proteus3_state, empty_init, "Proteus International", "Proteus III", MACHINE_NOT_WORKING | MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE )
502