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