1 // license:BSD-3-Clause
2 // copyright-holders:Angelo Salese, hap, AJR
3 /***************************************************************************
4 
5 prelim notes:
6 Flipper Jack, by Jackson, 1983
7 probably a prequel to superwng, it has a Falcon logo on the pcb
8 
9 xtal: 16mhz, 6mhz
10 cpu: 2*z80
11 sound: 2*ay8910
12 other: 8255 ppi, hd6845 crtc, 1 dipsw
13 ram: 2*8KB, 4*2KB
14 rom: see romdefs
15 
16 TODO:
17 - remaining gfx/color issues
18 - measure clocks
19 
20 
21 --------------------------------------------------------------------
22     DipSwitch Title   |  Function  | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
23 --------------------------------------------------------------------
24      Demo Sounds      |     Off    |off|                           |
25                       |     On     |on |                           |*
26 --------------------------------------------------------------------
27        Coinage        |   1C / 1C  |   |off|                       |*
28                       |   1C / 2C  |   |on |                       |
29 --------------------------------------------------------------------
30      Drop Target      |     On     |       |off|                   |*
31                       |     Off    |       |on |                   |
32 --------------------------------------------------------------------
33      Cabinet Type     |  Cocktail  |           |off|               |
34                       |  Upright   |           |on |               |*
35 --------------------------------------------------------------------
36 Additional Bonus Balls| Every 70K  |               |off|           |*
37  after 1st bonus ball | Every 100K |               |on |           |
38 --------------------------------------------------------------------
39    First Bonus Ball   |  100,000   |                   |off|       |*
40                       |  200,000   |                   |on |       |
41 --------------------------------------------------------------------
42   Bonus Ball Feature  |     On     |                       |off|   |*
43                       |     Off    |                       |on |   |
44 --------------------------------------------------------------------
45    Number of Balls    |     3      |                           |off|*
46                       |     5      |                           |on |
47 --------------------------------------------------------------------
48 
49 
50             Solder Side | Parts Side
51 ________________________|___________________________
52                  GND  | 1 |  GND
53                  GND  | 2 |  GND
54                  GND  | 3 |  GND
55                  +5V  | 4 |  +5V
56                  +5V  | 5 |  +5V
57                 +12V  | 6 |  +12V
58                       | 7 |  Sound (+)
59                       | 8 |  Sound (-)
60                       | 9 |  Coin
61                       | 10|
62             2P Shoot  | 11|  1P Shoot
63      2P Flipper Left  | 12|  1P Flipper Left
64              2P Tilt  | 13|  1P Tilt
65     2P Flipper Right  | 14|  1P Flipper Right
66             2P Start  | 15|  1P Start
67                       | 16|
68                       | 17|
69                       | 18|
70                       | 19|
71          Video Green  | 20|  Video Blue
72           Video Sync  | 21|  Video Red
73                  GND  | 22|  GRD
74 
75 
76 ***************************************************************************/
77 
78 #include "emu.h"
79 #include "cpu/z80/z80.h"
80 #include "machine/gen_latch.h"
81 #include "machine/i8255.h"
82 #include "sound/ay8910.h"
83 #include "video/mc6845.h"
84 #include "emupal.h"
85 #include "screen.h"
86 #include "speaker.h"
87 
88 
89 #define MASTER_CLOCK    16_MHz_XTAL
90 #define VIDEO_CLOCK     6_MHz_XTAL
91 
92 
93 class flipjack_state : public driver_device
94 {
95 public:
flipjack_state(const machine_config & mconfig,device_type type,const char * tag)96 	flipjack_state(const machine_config &mconfig, device_type type, const char *tag) :
97 		driver_device(mconfig, type, tag),
98 		m_maincpu(*this, "maincpu"),
99 		m_audiocpu(*this, "audiocpu"),
100 		m_prgbank(*this, "prgbank"),
101 		m_fbram(*this, "fb_ram"),
102 		m_vram(*this, "vram"),
103 		m_cram(*this, "cram"),
104 		m_tiles(*this, "tiles"),
105 		m_playfield(*this, "playfield"),
106 		m_palette(*this, "palette"),
107 		m_soundlatch(*this, "soundlatch")
108 	{
109 	}
110 
111 	void flipjack(machine_config &config);
112 
113 	DECLARE_WRITE_LINE_MEMBER(coin_nmi_w);
114 
115 protected:
116 	virtual void machine_start() override;
117 
118 private:
119 	required_device<cpu_device> m_maincpu;
120 	required_device<cpu_device> m_audiocpu;
121 
122 	required_memory_bank m_prgbank;
123 	required_shared_ptr<uint8_t> m_fbram;
124 	required_shared_ptr<uint8_t> m_vram;
125 	required_shared_ptr<uint8_t> m_cram;
126 	required_region_ptr<uint8_t> m_tiles;
127 	required_region_ptr<uint8_t> m_playfield;
128 
129 	required_device<palette_device> m_palette;
130 	required_device<generic_latch_8_device> m_soundlatch;
131 
132 	uint8_t m_bank = 0;
133 	uint8_t m_layer = 0;
134 
135 	void sound_nmi_ack_w(uint8_t data);
136 	void soundlatch_w(uint8_t data);
137 	void bank_w(uint8_t data);
138 	void layer_w(uint8_t data);
139 	void portc_w(uint8_t data);
140 	void flipjack_palette(palette_device &palette) const;
141 	MC6845_UPDATE_ROW(update_row);
142 
143 	void main_io_map(address_map &map);
144 	void main_map(address_map &map);
145 	void sound_io_map(address_map &map);
146 	void sound_map(address_map &map);
147 };
148 
149 
150 /***************************************************************************
151 
152   Video
153 
154 ***************************************************************************/
155 
flipjack_palette(palette_device & palette) const156 void flipjack_state::flipjack_palette(palette_device &palette) const
157 {
158 	// from PROM
159 	uint8_t const *const color_prom = memregion("proms")->base();
160 	for (int i = 0; i < 0x40; i++)
161 	{
162 		palette.set_pen_color(2*i+1, pal1bit(i >> 1), pal1bit(i >> 2), pal1bit(i >> 0));
163 		palette.set_pen_color(2*i+0, pal1bit(color_prom[i] >> 1), pal1bit(color_prom[i] >> 2), pal1bit(color_prom[i] >> 0));
164 	}
165 
166 	// standard 3bpp for blitter
167 	for (int i = 0; i < 8; i++)
168 		palette.set_pen_color(i+0x80, pal1bit(i >> 1), pal1bit(i >> 2), pal1bit(i >> 0));
169 }
170 
171 
MC6845_UPDATE_ROW(flipjack_state::update_row)172 MC6845_UPDATE_ROW(flipjack_state::update_row)
173 {
174 	const bool flip = !BIT(m_layer, 0);
175 	const uint16_t row_base = ((ma & 0x03e0) << 3 | (ra & 7) << 5) ^ (flip ? 0x1fff : 0);
176 	uint32_t *const pbegin = &bitmap.pix(y);
177 	uint32_t *const pend = &bitmap.pix(y, x_count * 8);
178 
179 	std::fill(pbegin, pend, rgb_t::black());
180 
181 	// draw playfield
182 	if (BIT(m_layer, 1))
183 	{
184 		uint16_t a1 = row_base;
185 		for (uint32_t *p = pbegin; p < pend; a1 = (flip ? a1 - 1 : a1 + 1) & 0x1fff)
186 		{
187 			uint8_t pen_r = (m_playfield[a1] & 0xff)>>0;
188 			uint8_t pen_g = (m_playfield[a1 + 0x2000] & 0xff)>>0;
189 			uint8_t pen_b = (m_playfield[a1 + 0x4000] & 0xff)>>0;
190 
191 			for (int xi = 0; xi < 8; xi++, p++)
192 			{
193 				int xxi = flip ? xi : 7 - xi;
194 				int color = BIT(pen_r, xxi) << 0;
195 				color |= BIT(pen_g, xxi) << 1;
196 				color |= BIT(pen_b, xxi) << 2;
197 				*p = m_palette->pen(color+0x80);
198 			}
199 		}
200 	}
201 
202 	// draw tiles
203 	uint16_t a2 = row_base & 0x1f1f;
204 	const uint8_t *const tile_data = &m_tiles[((m_bank & 3) << 11) | ((flip ? ~ra : ra) & 7)];
205 	for (uint32_t *p = pbegin; p < pend; a2 = (flip ? a2 - 1 : a2 + 1) & 0x1f1f)
206 	{
207 		uint8_t tile = tile_data[m_vram[a2] << 3];
208 		rgb_t color = m_palette->pen((m_cram[a2] & 0x3f) * 2 + 1);
209 
210 		for (int xi = 0; xi < 8; xi++, p++)
211 		{
212 			int xxi = flip ? xi : 7 - xi;
213 			if (BIT(tile, xxi))
214 				*p = color;
215 		}
216 	}
217 
218 	// draw framebuffer
219 	if (BIT(m_layer, 2))
220 	{
221 		uint16_t a3 = row_base;
222 		for (uint32_t *p = pbegin; p < pend; a3 = (flip ? a3 - 1 : a3 + 1) & 0x1fff)
223 		{
224 			uint8_t pen = m_fbram[a3];
225 			for (int xi = 0; xi < 8; xi++, p++)
226 			{
227 				int xxi = flip ? xi : 7 - xi;
228 				if (BIT(pen, xxi))
229 					*p = rgb_t::white();
230 			}
231 		}
232 	}
233 }
234 
235 
236 /***************************************************************************
237 
238   I/O
239 
240 ***************************************************************************/
241 
bank_w(uint8_t data)242 void flipjack_state::bank_w(uint8_t data)
243 {
244 	// d0-d1: tile bank
245 	// d2: prg bank
246 	// d4: ?
247 	// other bits: unused?
248 	m_bank = data;
249 	m_prgbank->set_entry(BIT(data, 2));
250 }
251 
layer_w(uint8_t data)252 void flipjack_state::layer_w(uint8_t data)
253 {
254 	// d0: flip screen
255 	// d1: enable playfield layer
256 	// d2: enable framebuffer layer
257 	// d3: ?
258 	// other bits: unused?
259 	m_layer = data;
260 }
261 
soundlatch_w(uint8_t data)262 void flipjack_state::soundlatch_w(uint8_t data)
263 {
264 	m_soundlatch->write(data);
265 	if (BIT(data, 7))
266 		m_audiocpu->set_input_line(0, ASSERT_LINE);
267 }
268 
sound_nmi_ack_w(uint8_t data)269 void flipjack_state::sound_nmi_ack_w(uint8_t data)
270 {
271 	m_audiocpu->set_input_line(0, CLEAR_LINE);
272 	m_audiocpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
273 }
274 
portc_w(uint8_t data)275 void flipjack_state::portc_w(uint8_t data)
276 {
277 	// vestigial hopper output?
278 }
279 
WRITE_LINE_MEMBER(flipjack_state::coin_nmi_w)280 WRITE_LINE_MEMBER(flipjack_state::coin_nmi_w)
281 {
282 	m_maincpu->set_input_line(INPUT_LINE_NMI, state ? CLEAR_LINE : ASSERT_LINE);
283 }
284 
285 
main_map(address_map & map)286 void flipjack_state::main_map(address_map &map)
287 {
288 	map(0x0000, 0x1fff).rom();
289 	map(0x2000, 0x3fff).bankr("prgbank");
290 	map(0x4000, 0x5fff).ram();
291 	map(0x6000, 0x67ff).ram();
292 	map(0x6800, 0x6803).rw("ppi8255", FUNC(i8255_device::read), FUNC(i8255_device::write));
293 	map(0x7000, 0x7000).w(FUNC(flipjack_state::soundlatch_w));
294 	map(0x7010, 0x7010).w("crtc", FUNC(hd6845s_device::address_w));
295 	map(0x7011, 0x7011).w("crtc", FUNC(hd6845s_device::register_w));
296 	map(0x7020, 0x7020).portr("DSW");
297 	map(0x7800, 0x7800).w(FUNC(flipjack_state::layer_w));
298 	map(0x8000, 0x9fff).rom();
299 	map(0xa000, 0xbfff).ram().share("cram");
300 	map(0xc000, 0xdfff).ram().share("vram");
301 	map(0xe000, 0xffff).ram().share("fb_ram");
302 }
303 
main_io_map(address_map & map)304 void flipjack_state::main_io_map(address_map &map)
305 {
306 	map.global_mask(0xff);
307 	map(0xff, 0xff).w(FUNC(flipjack_state::bank_w));
308 }
309 
sound_map(address_map & map)310 void flipjack_state::sound_map(address_map &map)
311 {
312 	map(0x0000, 0x1fff).rom();
313 	map(0x2000, 0x27ff).ram();
314 	map(0x4000, 0x4000).rw("ay2", FUNC(ay8910_device::data_r), FUNC(ay8910_device::data_w));
315 	map(0x6000, 0x6000).w("ay2", FUNC(ay8910_device::address_w));
316 	map(0x8000, 0x8000).rw("ay1", FUNC(ay8910_device::data_r), FUNC(ay8910_device::data_w));
317 	map(0xa000, 0xa000).w("ay1", FUNC(ay8910_device::address_w));
318 }
319 
sound_io_map(address_map & map)320 void flipjack_state::sound_io_map(address_map &map)
321 {
322 	map.global_mask(0xff);
323 	map(0x00, 0x00).w(FUNC(flipjack_state::sound_nmi_ack_w));
324 }
325 
326 
327 /***************************************************************************
328 
329   Inputs
330 
331 ***************************************************************************/
332 
333 static INPUT_PORTS_START( flipjack )
334 	PORT_START("COIN")
335 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, flipjack_state, coin_nmi_w) // not mapped in P1/P2/P3?
336 
337 	PORT_START("P1")
338 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P1 Shoot")
339 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 Left Flipper")
340 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P1 Tilt")
341 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P1 Right Flipper")
342 	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_START1 )
343 	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN )
344 	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN )
345 	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN )
346 
347 	PORT_START("P2")
348 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_COCKTAIL PORT_NAME("P2 Shoot")
349 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_COCKTAIL PORT_NAME("P2 Left Flipper")
350 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_COCKTAIL PORT_NAME("P2 Tilt")
351 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_COCKTAIL PORT_NAME("P2 Right Flipper")
352 	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_START2 )
353 	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN )
354 	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN )
355 	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN )
356 
357 	PORT_START("P3")
358 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNKNOWN ) // read only by unused routine?
359 	PORT_BIT( 0x0e, IP_ACTIVE_LOW, IPT_UNUSED )
360 	PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED ) // output
361 
362 	PORT_START("DSW")
363 	PORT_DIPNAME( 0x01, 0x00, DEF_STR( Demo_Sounds ) )  PORT_DIPLOCATION("A0:1")
364 	PORT_DIPSETTING(    0x01, DEF_STR( Off ) )
365 	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
366 	PORT_DIPNAME( 0x02, 0x02, DEF_STR( Coinage ) )      PORT_DIPLOCATION("A0:2")
367 	PORT_DIPSETTING(    0x02, DEF_STR( 1C_1C ) )
368 	PORT_DIPSETTING(    0x00, DEF_STR( 1C_2C ) )
369 	PORT_DIPNAME( 0x04, 0x04, "Drop Target" )       PORT_DIPLOCATION("A0:3")
370 	PORT_DIPSETTING(    0x00, DEF_STR( Off ) )
371 	PORT_DIPSETTING(    0x04, DEF_STR( On ) )
372 	PORT_DIPNAME( 0x08, 0x00, DEF_STR( Cabinet ) )      PORT_DIPLOCATION("A0:4")
373 	PORT_DIPSETTING(    0x00, DEF_STR( Upright ) )
374 	PORT_DIPSETTING(    0x08, DEF_STR( Cocktail ) )
375 	PORT_DIPNAME( 0x70, 0x70, DEF_STR( Bonus_Life ) )   PORT_DIPLOCATION("A0:5,6,7")
376 	PORT_DIPSETTING(    0x70, "150K & Every 70K" )
377 	PORT_DIPSETTING(    0x60, "150K & Every 100K" )
378 	PORT_DIPSETTING(    0x50, "200K & Every 70K" )
379 	PORT_DIPSETTING(    0x40, "200K & Every 100K" )
380 	PORT_DIPSETTING(    0x00, "None" )
381 	PORT_DIPNAME( 0x80, 0x80, DEF_STR( Lives ) )        PORT_DIPLOCATION("A0:8")
382 	PORT_DIPSETTING(    0x80, "3" )
383 	PORT_DIPSETTING(    0x00, "5" )
384 INPUT_PORTS_END
385 
386 
387 /***************************************************************************
388 
389   Machine Config
390 
391 ***************************************************************************/
392 
393 static const gfx_layout tilelayout =
394 {
395 	8, 8,
396 	RGN_FRAC(1,1),
397 	1,
398 	{ 0 },
399 	{ 7, 6, 5, 4, 3, 2, 1, 0 },
400 	{ 7*8, 6*8, 5*8, 4*8, 3*8, 2*8, 1*8, 0*8 },
401 	8*8
402 };
403 
404 static GFXDECODE_START( gfx_flipjack )
405 	GFXDECODE_ENTRY( "tiles", 0, tilelayout, 0, 64 )
406 GFXDECODE_END
407 
408 
409 
machine_start()410 void flipjack_state::machine_start()
411 {
412 	uint8_t *ROM = memregion("maincpu")->base();
413 	m_prgbank->configure_entries(0, 2, &ROM[0x10000], 0x2000);
414 	m_prgbank->set_entry(0);
415 
416 	save_item(NAME(m_bank));
417 	save_item(NAME(m_layer));
418 }
419 
420 
flipjack(machine_config & config)421 void flipjack_state::flipjack(machine_config &config)
422 {
423 	/* basic machine hardware */
424 	Z80(config, m_maincpu, MASTER_CLOCK/4);
425 	m_maincpu->set_addrmap(AS_PROGRAM, &flipjack_state::main_map);
426 	m_maincpu->set_addrmap(AS_IO, &flipjack_state::main_io_map);
427 
428 	Z80(config, m_audiocpu, MASTER_CLOCK/4);
429 	m_audiocpu->set_addrmap(AS_PROGRAM, &flipjack_state::sound_map);
430 	m_audiocpu->set_addrmap(AS_IO, &flipjack_state::sound_io_map);
431 
432 	i8255_device &ppi(I8255A(config, "ppi8255"));
433 	ppi.in_pa_callback().set_ioport("P1");
434 	ppi.in_pb_callback().set_ioport("P2");
435 	ppi.in_pc_callback().set_ioport("P3");
436 	ppi.out_pc_callback().set(FUNC(flipjack_state::portc_w));
437 
438 	/* video hardware */
439 	screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
440 	screen.set_raw(VIDEO_CLOCK, 0x188, 0, 0x100, 0x100, 0, 0xc0); // from crtc
441 	screen.set_screen_update("crtc", FUNC(hd6845s_device::screen_update));
442 
443 	hd6845s_device &crtc(HD6845S(config, "crtc", VIDEO_CLOCK/8));
444 	crtc.set_screen("screen");
445 	crtc.set_show_border_area(false);
446 	crtc.set_char_width(8);
447 	crtc.out_vsync_callback().set_inputline("maincpu", INPUT_LINE_IRQ0, HOLD_LINE);
448 	crtc.out_vsync_callback().append_inputline("audiocpu", INPUT_LINE_NMI, ASSERT_LINE);
449 	crtc.set_update_row_callback(FUNC(flipjack_state::update_row));
450 
451 	GFXDECODE(config, "gfxdecode", m_palette, gfx_flipjack);
452 	PALETTE(config, m_palette, FUNC(flipjack_state::flipjack_palette), 128+8);
453 
454 	/* sound hardware */
455 	SPEAKER(config, "mono").front_center();
456 
457 	GENERIC_LATCH_8(config, m_soundlatch);
458 
459 	ay8910_device &ay1(AY8910(config, "ay1", MASTER_CLOCK/8));
460 	ay1.port_a_read_callback().set(m_soundlatch, FUNC(generic_latch_8_device::read));
461 	ay1.add_route(ALL_OUTPUTS, "mono", 0.50);
462 
463 	AY8910(config, "ay2", MASTER_CLOCK/8).add_route(ALL_OUTPUTS, "mono", 0.50);
464 }
465 
466 
467 ROM_START( flipjack )
468 	ROM_REGION( 0x14000, "maincpu", 0 )
469 	ROM_LOAD( "3.d5", 0x00000, 0x2000, CRC(123bd992) SHA1(d845e2b9af5b81d950e5edf35201f1dd1c4af651) )
470 	ROM_LOAD( "4.f5", 0x08000, 0x2000, CRC(d27e0184) SHA1(f108993fc3fce9173a4961a76fc60655fdd1cd25) )
471 	ROM_LOAD( "1.l5", 0x10000, 0x2000, CRC(4632263b) SHA1(b1fbb851ffd8aff36aff6f36672122fef3dd0af1) )
472 	ROM_LOAD( "2.m5", 0x12000, 0x2000, CRC(e2bdce13) SHA1(50d990095a35837570b3117763e990440d8656ae) )
473 
474 	ROM_REGION( 0x2000, "audiocpu", 0 )
475 	ROM_LOAD( "s.s5",  0x0000, 0x2000, CRC(34515a7b) SHA1(affe34198b77bddd314fae2851fd6a29d80f734e) )
476 
477 	ROM_REGION( 0x2000, "tiles", 0 )
478 	ROM_LOAD( "cg.l6", 0x0000, 0x2000, CRC(8d87f6b9) SHA1(55ca726f190eac9ee7e26b8f4e519f1634bec0dd) )
479 
480 	ROM_REGION( 0x6000, "playfield", 0 )
481 	ROM_LOAD( "b.h6",  0x0000, 0x2000, CRC(bbc8fdcc) SHA1(93758ca13cc49b87508f01c86c652155945dd484) )
482 	ROM_LOAD( "r.f6",  0x2000, 0x2000, CRC(8c02fe71) SHA1(148e7382dc9b7678c447ada5ad19e03a3a051a7f) )
483 	ROM_LOAD( "g.d6",  0x4000, 0x2000, CRC(8624d07f) SHA1(fb51c9c785d56854a6530b71868e95ad6be7cbee) )
484 
485 	ROM_REGION( 0x0100, "proms", 0 )
486 	ROM_LOAD( "m3-7611-5.f8", 0x0000, 0x0100, CRC(f0248102) SHA1(22d87935c941e2e8bba5427599f6fd5fa1262ebc) )
487 ROM_END
488 
489 
490 GAME( 1983?, flipjack, 0, flipjack, flipjack, flipjack_state, empty_init, ROT270, "Jackson Co., Ltd.", "Flipper Jack", MACHINE_IMPERFECT_COLORS | MACHINE_SUPPORTS_SAVE ) // copyright not shown, datecodes on pcb suggests mid-1983
491