1 // license:BSD-3-Clause
2 // copyright-holders:Miodrag Milanovic, Jonathan Gevaryahu
3 /***************************************************************************
4 
5     Canon Cat, Model V777
6     Copyright (C) 2009-2013 Miodrag Milanovic and Jonathan Gevaryahu AKA Lord Nightmare
7     With information and help from John "Sandy" Bumgarner, Dwight Elvey,
8     Charles Springer, Terry Holmes, Jonathan Sand, Aza Raskin and others.
9 
10 
11     This driver is dedicated in memory of Jef Raskin and Dave Boulton
12 
13     12/06/2009 Skeleton driver.
14     15/06/2009 Working driver
15 
16 Pictures: http://www.regnirps.com/Apple6502stuff/apple_iie_cat.htm
17 
18 Canon cat blue "Use Front Labels":
19 ` (really degree, +-, paragraph-mark and section-mark): LEFT MARGIN
20 -_: INDENT
21 +=: RIGHT MARGIN
22 UNDO: SPELL CHECK LEAP (this is actually a red LEAP label)
23 PERM SPACE/TAB: SET/CLEAR TAB
24 Q: UNDER LINE
25 W: BOLD
26 E: CAPS
27 T: Paragraph STYLE
28 U: LINE SPACE
29 O: ADD SPELLING
30 [ (really 1/4, 1/2, double-underline and |): SETUP
31 Backspace (really ERASE): ANSWER
32 LOCK: DOCUMENT LOCK
33 A: COPY
34 D: SEND CONTROL
35 G: CALC
36 J: PRINT
37 L: DISK
38 Colon: FORMAT/WIPE DISK (only when wheel! mode is enabled, see below)
39 "': PHONE
40 Enter (really RETURN): SEND
41 X: LOCAL LEAP
42 V: LEARN
43 N: EXPLAIN
44 ,: SORT
45 ?/: KBI/II
46 Pgup (really DOCUMENT/PAGE): TITLES
47 Leap Left: LEAP AGAIN (left)
48 Leap Right: LEAP AGAIN (right)
49 
50 
51 How to enable the FORTH interpreter (http://canoncat.org/canoncat/enableforth.html)
52 
53 The definitive instructions of going Forth on a Cat, tested on a living Cat.
54 The Canon Cat is programmed with FORTH, a remarkably different programming language in itself.
55 On the Canon Cat, you can access the FORTH interpreter with a special sequence of key presses.
56 Here are exact working instructions thanks to Sandy Bumgarner:
57 - Type Enable Forth Language exactly like that, capitals and all.
58 - Highlight from the En to the ge, exactly [i.e. Leap back to Enable by keeping the left Leap
59   key down while typing E n a, release the leap key, then click both leap keys simultaneously],
60   and press USE FRONT with ERASE (the ANSWER command).
61 - The Cat should beep and flash the ruler.
62 - Then press USE FRONT and the SHIFT keys together and tap the space bar. Note that the cursor
63   stops blinking. Now a Pressing the RETURN key gets the Forth OK and you are 'in' as they say.
64 
65 In MESS, to activate it as above:
66 * when the Cat boots, type (without quotes) "Enable Forth Language"
67 * hold left-alt(leap left) and type E n a, release left-alt (the left cursor is now at the first character)
68 * simultaneously press both alt keys for a moment and release both (the whole "Enable Forth Language" line will be selected)
69 * press control(use front) and press backspace(ERASE) (The cat will beep here)
70 * press control(use front), shift, and space (the cursor should stop blinking)
71 * press enter and the forth "ok" prompt should appear. you can type 'page' and enter to clear the screen
72 Optional further steps:
73 * type without quotes "-1 wheel! savesetup re" at the forth prompt to permanently
74   enable shift + use front + space to dump to forth mode easily
75 * change the keyboard setting in the setup menu (use front + [ ) to ASCII so you can type < and >
76 * after doing the -1 wheel! thing, you can compile a selected forth program in the editor
77   by selecting it and hitting ANSWER (use front + ERASE)
78 
79 If ever in forth mode you can return to the editor with the forth word (without quotes) "re"
80 
81 Canon cat gate array ASIC markings:
82 GA1 (prototype): D65013CW276 [same as final]
83 GA1 (final): NH4-5001 276 [schematic: upD65013CW-276]
84 GA2 (prototype): D65013CW208 [DIFFERENT FROM FINAL! larger asic used here, shrank for final?]
85 GA2 (final): NH4-5002 191 [schematic: upD65012CW-191]
86 GA3 (prototype): D65013CW141 [same as final? typo 65013 vs 65012?]
87 GA3 (final): NH4-5003 141 [schematic: upD65012CW-141]
88 
89 Canon cat credits easter egg:
90 * hold either leap key, then simultaneously hold shift, then type Q W E R A S D F Z X C V and release all the keys
91 * hit EXPLAIN (use front + N) and the credits screen will be displayed
92 
93 Canon Cat credits details: (WIP)
94 Jef Raskin
95 John "Sandy" Bumgarner
96 Charles Springer
97 Jonathan Sand
98 Terry Holmes - wrote tForth, the language in which the cat is programmed
99 Scott Kim - responsible for fonts on swyft and cat
100 Ralph Voorhees - Model construction and mockups (swyft 'flat cat')
101 
102 Cat HLSL stuff:
103 *scanlines:
104 the cat has somewhat visible and fairly close scanlines with very little fuzziness
105 try hlsl options:
106 hlsl_prescale_x           4
107 hlsl_prescale_y           4
108 scanline_alpha            0.3
109 scanline_size             1.0
110 scanline_height           0.7
111 scanline_bright_scale     1.0
112 scanline_bright_offset    0.6
113 *phosphor persistence of the original cat CRT is VERY LONG and fades to a greenish-yellow color, though the main color itself is white
114 try hlsl option:
115 phosphor_life             0.93,0.95,0.87
116 which is fairly close but may actually be too SHORT compared to the real thing.
117 
118 
119 Canon Cat versions:
120 There is really only one version of the cat which saw wide release, the US version.
121 * It is possible a very small number of UK/European units were released as a test.
122   If so, these will have slightly different keyboard key caps and different
123   system and spellcheck ROMs.
124 
125 As for prototypes/dev cat machines, a few minor variants exist:
126 * Prototype cat motherboards used 16k*4bit drams instead of 64k*4bit as the
127   final system did and hence max out at 128k of dram instead of 512k.
128   One of the gate arrays is also different, and the motherboard is arranged
129   differently. The IC9 "buserr" PAL is not used, even on the prototype.
130   The final system included 256k of dram and can be upgraded to 512k.
131 * At least some developer units were modified to have an external BNC
132   connector, ostensibly to display the internal screen's video externally.
133   http://www.digibarn.com/collections/systems/canon-cat/Image55.jpg
134 
135 
136 Canon Cat:
137 <insert guru-diagram here once drawn>
138 Crystals:
139 X1: 19.968Mhz, used by GA2 (plus a PLL to multiply by 2?), and divide by 4 for
140     cpuclk, divide by 8 for 2.5mhz and divide by 5.5 for 3.63mhz (is this
141     supposed to be divide by 6? there may not be a pll if it is...)
142 X2: 3.579545Mhz, used by the DTMF generator chip AMI S2579 at IC40
143 X3: 2.4576Mhz, used by the modem chip AMI S35213 at IC37
144 
145 
146 ToDo:
147 * Canon Cat
148 - Find the mirrors for the write-only video control register and figure out
149   what the writes actually do; hook these up properly to screen timing etc
150 - Floppy drive (3.5", Single Sided Double Density MFM, ~400kb)
151   * Cat has very low level control of data being read or written, much like
152     the Amiga or AppleII does
153   * first sector is id ZERO which is unusual since most MFM formats are base-1
154     for sector numbering
155   * sectors are 512 bytes, standard MFM with usual address and data marks and
156     ccitt crc16
157   * track 0 contains sector zero repeated identically 10 times; the cat SEEMS
158     to use this as a disk/document ID
159   * tracks 1-79 each contain ten sectors, id 0x0 thru 0x9
160     ('normal' mfm parlance: sectors -1, 0, 1, ... 7, 8)
161   * this means the whole disk effectively contains 512*10*80 = 409600 bytes of
162     data, though track 0 is just a disk "unique" identifier for the cat
163     meaning 404480 usable bytes
164   * (Once the floppy is working I'd declare the system working)
165 - Centronics port finishing touches: verify where the paper out, slct/err, and
166   IPP pins map in memory. The firmware doesn't actually use them, but they must
167   map somewhere as they connect to the ASIC.
168 - RS232C port and Modem "port" connected to the DUART's two ports
169   These are currently optionally debug-logged but don't connect anywhere
170 - DTMF generator chip (connected to DUART 'user output' pins OP4,5,6,7)
171 - WIP: Watchdog timer/powerfail at 0x85xxxx (watchdog NMI needs to actually
172   fire if wdt goes above a certain number, possibly 3, 7 or F?)
173 - Canon Cat released versions known: 1.74 US (dumped), 2.40 US (dumped both
174   original compile, and Dwight's recompile from the released source code),
175   2.42 (NEED DUMP)
176   It is possible a few prototype UK 1.74 or 2.40 units were produced; the code
177   ROMs of these will differ (they contain different spellcheck "core" code) as
178   well as the spellcheck ROMs, the keyboard id and the keycaps.
179 - Known Spellcheck ROMs: NH7-0684 (US, dumped); NH7-0724 (UK, NEED DUMP);
180   NH7-0813/0814 (Quebec/France, NEED DUMP); NH7-1019/1020/1021 (Germany, NEED DUMP)
181   It is possible the non-US ROMs were never officially released.
182   Wordlist sources: American Heritage (US and UK), Librarie Larousse (FR),
183   Langenscheidt (DE)
184 - (would-be-really-nice-but-totally-unnecessary feature): due to open bus, the
185   svrom1 and svrom2 checksums in diagnostics read as 01A80000 and 01020000
186   respectively on a real machine (and hence appear inverted/'fail'-state).
187   This requires sub-cycle accurate 68k open bus emulation to pull off, as well
188   as emulating the fact that UDS/LDS are ?not connected? (unclear because this
189   happens inside an asic) for the SVROMS (or the svram or the code ROMs, for
190   that matter!)
191 - Hook Battery Low input to a dipswitch.
192 - Hook pfail to a dipswitch.
193 - Hook the floppy control register readback up properly, things seem to get
194   confused.
195 
196 ****************************************************************************/
197 
198 #include "emu.h"
199 #include "cpu/m68000/m68000.h"
200 #include "machine/clock.h"
201 #include "machine/mc68681.h"
202 #include "machine/nvram.h"
203 #include "sound/spkrdev.h"
204 #include "bus/centronics/ctronics.h"
205 #include "screen.h"
206 #include "speaker.h"
207 
208 
209 // Defines
210 
211 #undef DEBUG_GA2OPR_W
212 #undef DEBUG_VIDEO_CONTROL_W
213 
214 #undef DEBUG_FLOPPY_CONTROL_W
215 #undef DEBUG_FLOPPY_CONTROL_R
216 #undef DEBUG_FLOPPY_DATA_W
217 #undef DEBUG_FLOPPY_DATA_R
218 #undef DEBUG_FLOPPY_STATUS_R
219 
220 #undef DEBUG_PRINTER_DATA_W
221 #undef DEBUG_PRINTER_CONTROL_W
222 
223 #undef DEBUG_MODEM_R
224 #undef DEBUG_MODEM_W
225 
226 #undef DEBUG_DUART_OUTPUT_LINES
227 // data sent to rs232 port
228 #undef DEBUG_DUART_TXA
229 // data sent to modem chip
230 #undef DEBUG_DUART_TXB
231 #undef DEBUG_DUART_IRQ_HANDLER
232 #undef DEBUG_PRN_FF
233 
234 #undef DEBUG_TEST_W
235 
236 #define DEBUG_SWYFT_VIA0 1
237 #define DEBUG_SWYFT_VIA1 1
238 
239 
240 class cat_state : public driver_device
241 {
242 public:
243 	enum
244 	{
245 		TIMER_KEYBOARD,
246 		TIMER_COUNTER_6MS
247 	};
248 
cat_state(const machine_config & mconfig,device_type type,const char * tag)249 	cat_state(const machine_config &mconfig, device_type type, const char *tag) :
250 		driver_device(mconfig, type, tag),
251 		m_maincpu(*this, "maincpu"),
252 		//m_nvram(*this, "nvram"), // merge with svram?
253 		m_duart(*this, "duartn68681"),
254 		m_ctx(*this, "ctx"),
255 		m_ctx_data_out(*this, "ctx_data_out"),
256 		m_speaker(*this, "speaker"),
257 		m_svram(*this, "svram"), // nvram
258 		m_p_cat_videoram(*this, "p_cat_vram"),
259 		m_y0(*this, "Y0"),
260 		m_y1(*this, "Y1"),
261 		m_y2(*this, "Y2"),
262 		m_y3(*this, "Y3"),
263 		m_y4(*this, "Y4"),
264 		m_y5(*this, "Y5"),
265 		m_y6(*this, "Y6"),
266 		m_y7(*this, "Y7"),
267 		m_dipsw(*this, "DIPSW1")
268 	{ }
269 
270 	required_device<cpu_device> m_maincpu;
271 	//optional_device<nvram_device> m_nvram;
272 	required_device<mc68681_device> m_duart;
273 	required_device<centronics_device> m_ctx;
274 	required_device<output_latch_device> m_ctx_data_out;
275 	required_device<speaker_sound_device> m_speaker;
276 	required_shared_ptr<uint16_t> m_svram;
277 	required_shared_ptr<uint16_t> m_p_cat_videoram;
278 	required_ioport m_y0;
279 	required_ioport m_y1;
280 	required_ioport m_y2;
281 	required_ioport m_y3;
282 	required_ioport m_y4;
283 	required_ioport m_y5;
284 	required_ioport m_y6;
285 	required_ioport m_y7;
286 	required_ioport m_dipsw;
287 	emu_timer *m_keyboard_timer;
288 	emu_timer *m_6ms_timer;
289 
290 	DECLARE_MACHINE_START(cat);
291 	DECLARE_MACHINE_RESET(cat);
292 	DECLARE_VIDEO_START(cat);
293 	void init_cat();
294 
295 	uint32_t screen_update_cat(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
296 
297 	DECLARE_WRITE_LINE_MEMBER(cat_duart_irq_handler);
298 	DECLARE_WRITE_LINE_MEMBER(cat_duart_txa);
299 	DECLARE_WRITE_LINE_MEMBER(cat_duart_txb);
300 	void cat_duart_output(uint8_t data);
301 	DECLARE_WRITE_LINE_MEMBER(prn_ack_ff);
302 
303 	uint16_t cat_floppy_control_r(offs_t offset);
304 	void cat_floppy_control_w(offs_t offset, uint16_t data);
305 	void cat_printer_data_w(offs_t offset, uint16_t data);
306 	uint16_t cat_floppy_data_r(offs_t offset);
307 	void cat_floppy_data_w(offs_t offset, uint16_t data);
308 	uint16_t cat_keyboard_r(offs_t offset);
309 	void cat_keyboard_w(uint16_t data);
310 	void cat_video_control_w(offs_t offset, uint16_t data);
311 	uint16_t cat_floppy_status_r(offs_t offset);
312 	uint16_t cat_battery_r();
313 	void cat_printer_control_w(offs_t offset, uint16_t data);
314 	uint16_t cat_modem_r(offs_t offset);
315 	void cat_modem_w(offs_t offset, uint16_t data);
316 	uint16_t cat_6ms_counter_r();
317 	void cat_opr_w(offs_t offset, uint16_t data);
318 	uint16_t cat_wdt_r();
319 	void cat_tcb_w(offs_t offset, uint16_t data);
320 	uint16_t cat_2e80_r();
321 	uint16_t cat_0080_r();
322 	uint16_t cat_0000_r();
323 
324 
325 	/* gate array 2 has a 16-bit counter inside which counts at 10mhz and
326 	   rolls over at FFFF->0000; on roll-over (or likely at FFFF terminal count)
327 	   it triggers the KTOBF output. It does this every 6.5535ms, which causes
328 	   a 74LS74 d-latch at IC100 to invert the state of the DUART IP2 line;
329 	   this causes the DUART to fire an interrupt, which makes the 68000 read
330 	   the keyboard.
331 	   The watchdog counter and the 6ms counter are both incremented
332 	   every time the KTOBF pulses.
333 	 */
334 	uint16_t m_6ms_counter;
335 	uint8_t m_wdt_counter;
336 	uint8_t m_duart_ktobf_ff;
337 	/* the /ACK line from the centronics printer port goes through a similar
338 	   flipflop to the ktobf line as well, so duart IP4 inverts on /ACK rising edge
339 	 */
340 	uint8_t m_duart_prn_ack_prev_state;
341 	uint8_t m_duart_prn_ack_ff;
342 	/* Gate array 2 is in charge of serializing the video for display to the screen;
343 	   Gate array 1 is in charge of vblank/hblank timing, and in charge of refreshing
344 	   dram and indicating to GA2, using the /LDPS signal, what times the address it is
345 	   writing to ram it is intending to be used by GA2 to read 16 bits of data to be
346 	   shifted out to the screen. (it is obviously not active during hblank and vblank)
347 	   GA2 then takes: ((output_bit XNOR video_invert) AND video enable), and serially
348 	   bangs the result to the analog display circuitry.
349 	 */
350 	uint8_t m_video_enable;
351 	uint8_t m_video_invert;
352 	uint16_t m_pr_cont;
353 	uint8_t m_keyboard_line;
354 	uint8_t m_floppy_control;
355 
356 	//TIMER_CALLBACK_MEMBER(keyboard_callback);
357 	TIMER_CALLBACK_MEMBER(counter_6ms_callback);
358 
359 	void cat(machine_config &config);
360 	void cat_mem(address_map &map);
361 	void cpu_space_map(address_map &map);
362 
363 protected:
364 	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
365 };
366 
367 // TODO: this init doesn't actually work yet! please fix me!
368 /*
369 void cat_state::init_cat()
370 {
371     uint8_t *svrom = memregion("svrom")->base();
372     // fill svrom with the correct 2e80 pattern except where svrom1 sits
373     // first half
374     for (int i = 0; i < 0x20000; i+=2)
375         svrom[i] = 0x2E;
376     // second half
377     for (int i = 0x20000; i < 0x40000; i+=2)
378     {
379         svrom[i] = 0x2E;
380         svrom[i+1] = 0x80;
381     }
382 }*/
383 
384 /* 0x600000-0x65ffff Write: Video Generator (AKA NH4-5001 AKA Gate Array #1 @ IC30)
385  writing to the video generator is done by putting the register number in the high 3 bits
386  and the data to write in the lower 12 (14?) bits.
387  The actual data-bus data written here is completely ignored,
388  in fact it isn't even connected to the gate array; The firmware writes 0x0000.
389  hence:
390  0 = must be 0
391  s = register select
392  d = data to write
393  ? = unknown
394  x = ignored
395  ? 1 1 ?  ? s s s  s ? ? ?  ? ? ? d  d d d d  d d d .
396  600xxx - VSE (End of Frame)
397  608xxx - VST (End of VSync)
398  610xxx - VSS (VSync Start)
399  618xxx - VDE (Active Lines) = value written * 4
400  620xxx - unknown
401  628xxx - unknown
402  630xxx - unknown
403  638xxx - unknown
404  640xxx - HSE (End H Line)
405  648xxx - HST (End HSync)
406  650xxx - HSS (HSync Start)
407  658xxx - VOC (Video Control)
408  */
cat_video_control_w(offs_t offset,uint16_t data)409 void cat_state::cat_video_control_w(offs_t offset, uint16_t data)
410 {
411 	/*
412 	 * 006500AE ,          ( HSS HSync Start    89 )
413 	 * 006480C2 ,          ( HST End HSync   96 )
414 	 * 006400CE ,          ( HSE End H Line    104 )
415 	 * 006180B0 ,          ( VDE Active Lines    344 )
416 	 * 006100D4 ,          ( VSS VSync Start   362 )
417 	 * 006080F4 ,          ( VST End of VSync    378 )
418 	 * 00600120 ,          ( VSE End of Frame    400 )
419 	 * 006581C0 ,          ( VOC Video Control Normal Syncs )
420 	 * based on diagrams from https://archive.org/details/DTCJefRaskinDoc062
421 	 * we can determine what at least some of these values do:
422 	 * HORIZONTAL:
423 	 *   0 is the first pixel output to the screen at the end of the frontporch
424 	 *   stuff is shifted to the screen here, and then zeroed for the backporch; manual claims backporch is 2 cycles, it is actually 7
425 	 *   HSS (89) is the horizontal count at which the HSYNC pin goes high
426 	 *   sync is active here for 7 cycles; manual claims 10 but is wrong
427 	 *   HST (96) is the horizontal count at which the HSYNC pin goes low
428 	 *   sync is inactive here for 7 cycles, manual claims 8 but is wrong?, this is the frontporch
429 	 *   HSE (104) is the horizontal count at which the horizontal counter is reset to 0 (so counts 0-103 then back to 0)
430 	 *
431 	 * VERTICAL:
432 	 *   0 is the first vertical line displayed to screen
433 	 *   VDE (344) affects the number of lines that /LDPS is active for display of
434 	 *   VSS (362) is the vertical line at which the VSYNC pin goes high
435 	 *   VST (378) is the vertical line at which the VSYNC pin goes low
436 	 *   VSE (400) is the vertical line at which the vertical line count is reset to 0
437 	 *   VOC (0x1c0) controls the polarity and enabling of the sync signals in some unknown way
438 	 *     Suffice to say, whatever bit combination 0b00011100000x does, it enables both horiz and vert sync and both are positive
439 	 */
440 #ifdef DEBUG_VIDEO_CONTROL_W
441 	static const char *const regDest[16] = { "VSE (End of frame)", "VST (End of VSync)", "VSS (Start of VSync)", "VDE (Active Lines)",
442 	"unknown 620xxx", "unknown 628xxx", "unknown 630xxx", "unknown 638xxx",
443 	"HSE (end of horizontal line)", "HST (end of HSync)", "HSS (HSync Start)", "VOC (Video Control)",
444 	"unknown 660xxx", "unknown 668xxx", "unknown 670xxx", "unknown 678xxx" };
445 	fprintf(stderr,"Write to video chip address %06X; %02X -> register %s with data %04X\n", 0x600000+(offset<<1), offset&0xFF, regDest[(offset&0x3C000)>>14], data);
446 #endif
447 }
448 
449 // Floppy control register (called fd.cont in the cat source code)
450 	/* FEDCBA98 (76543210 is open bus)
451 	 * |||||||\-- unknown[1] (may be some sort of 'reset' or debug bit? the cat code explicitly clears this bit but never sets it)
452 	 * ||||||\--- WRITE GATE: 0 = write head disabled, 1 = write head enabled (verified from cat source code)
453 	 * |||||\---- unknown[2] (leftover debug bit? unused by cat code)
454 	 * ||||\----- /DIRECTION: 1 = in, 0 = out (verified from forth cmd)
455 	 * |||\------ /SIDESEL: 1 = side1, 0 = side0 (verified from forth cmd)
456 	 * ||\------- STEP: 1 = STEP active, 0 = STEP inactive (verified from cat source code)
457 	 * |\-------- MOTOR ON: 1 = on, 0 = off (verified)
458 	 * \--------- /DRIVESELECT: 1 = drive 0, 0 = drive 1 (verified from forth cmd)
459 	 * all 8 bits 'stick' on write and are readable at this register as well
460 	 * [1] writing this bit as high seems to 'freeze' floppy acquisition so
461 	 *   the value at the floppy_data_r register is held rather than updated
462 	 *   with new data from the shifter/mfm clock/data separator
463 	 * [2] this bit's function is unknown. it could possibly be an FM vs MFM selector bit, where high = MFM, low = FM ? or MFM vs GCR?
464 	 */
465 // 0x800000-0x800001 read
cat_floppy_control_r(offs_t offset)466 uint16_t cat_state::cat_floppy_control_r(offs_t offset)
467 {
468 #ifdef DEBUG_FLOPPY_CONTROL_R
469 	fprintf(stderr,"Read from Floppy Status address %06X\n", 0x800000+(offset<<1));
470 #endif
471 	return (m_floppy_control << 8)|0x80; // LOW 8 BITS ARE OPEN BUS
472 }
473 // 0x800000-0x800001 write
cat_floppy_control_w(offs_t offset,uint16_t data)474 void cat_state::cat_floppy_control_w(offs_t offset, uint16_t data)
475 {
476 #ifdef DEBUG_FLOPPY_CONTROL_W
477 	fprintf(stderr,"Write to Floppy Control address %06X, data %04X\n", 0x800000+(offset<<1), data);
478 #endif
479 	m_floppy_control = (data >> 8)&0xFF;
480 }
481 
482 // 0x800002-0x800003 read = 0x0080, see open bus
483 // 0x800002-0x800003 write
cat_keyboard_w(uint16_t data)484 void cat_state::cat_keyboard_w(uint16_t data)
485 {
486 	m_keyboard_line = data >> 8;
487 }
488 
489 // 0x800004-0x800005 'pr.data' write
490 // /DSTB (centronics pin 1) is implied by the cat source code to be pulsed
491 // low (for some unknown period of time) upon any write to this port.
cat_printer_data_w(offs_t offset,uint16_t data)492 void cat_state::cat_printer_data_w(offs_t offset, uint16_t data)
493 {
494 #ifdef DEBUG_PRINTER_DATA_W
495 	fprintf(stderr,"Write to Printer Data address %06X, data %04X\n", 0x800004+(offset<<1), data);
496 #endif
497 	m_ctx_data_out->write(data>>8);
498 	m_ctx->write_strobe(1);
499 	m_ctx->write_strobe(0);
500 	m_ctx->write_strobe(1);
501 }
502 // 0x800006-0x800007: Floppy data register (called fd.dwr in the cat source code)
cat_floppy_data_r(offs_t offset)503 uint16_t cat_state::cat_floppy_data_r(offs_t offset)
504 {
505 #ifdef DEBUG_FLOPPY_DATA_R
506 	fprintf(stderr,"Read from Floppy Data address %06X\n", 0x800006+(offset<<1));
507 #endif
508 	return 0x0080;
509 }
cat_floppy_data_w(offs_t offset,uint16_t data)510 void cat_state::cat_floppy_data_w(offs_t offset, uint16_t data)
511 {
512 #ifdef DEBUG_FLOPPY_DATA_W
513 	fprintf(stderr,"Write to Floppy Data address %06X, data %04X\n", 0x800006+(offset<<1), data);
514 #endif
515 }
516 
517 // 0x800008-0x800009: Floppy status register (called fd.status in the cat source code)
518 	/* FEDCBA98 (76543210 is open bus)
519 	 * |||||||\-- ? always low
520 	 * ||||||\--- ? always low
521 	 * |||||\---- READY: 1 = ready, 0 = not ready (verified from cat source code)
522 	 * ||||\----- /WRITE PROTECT: 1 = writable, 0 = protected (verified)
523 	 * |||\------ /TRACK0: 0 = on track 0, 1 = not on track 0 (verified)
524 	 * ||\------- /INDEX: 0 = index sensor active, 1 = index sensor inactive (verified)
525 	 * |\-------- ? this bit may indicate which drive is selected, i.e. same as floppy control bit 7; low on drive 1, high on drive 0?
526 	 * \--------- ? this bit may indicate 'data separator overflow'; it is usually low but becomes high if you manually select the floppy drive
527 	 ALL of these bits except bit F seem to be reset when the selected drive in floppy control is switched
528 	 */
cat_floppy_status_r(offs_t offset)529 uint16_t cat_state::cat_floppy_status_r(offs_t offset)
530 {
531 #ifdef DEBUG_FLOPPY_STATUS_R
532 	fprintf(stderr,"Read from Floppy Status address %06X\n", 0x800008+(offset<<1));
533 #endif
534 	return 0x2480;
535 }
536 
537 // 0x80000a-0x80000b
cat_keyboard_r(offs_t offset)538 uint16_t cat_state::cat_keyboard_r(offs_t offset)
539 {
540 	uint16_t retVal = 0;
541 	// Read country code
542 	if ((m_pr_cont&0xFF00) == 0x0900)
543 		retVal = m_dipsw->read();
544 
545 	// Regular keyboard read
546 	if ((m_pr_cont&0xFF00) == 0x0800 || (m_pr_cont&0xFF00) == 0x0a00)
547 	{
548 		retVal=0xff00;
549 		switch(m_keyboard_line)
550 		{
551 			case 0x01: retVal = m_y0->read() << 8; break;
552 			case 0x02: retVal = m_y1->read() << 8; break;
553 			case 0x04: retVal = m_y2->read() << 8; break;
554 			case 0x08: retVal = m_y3->read() << 8; break;
555 			case 0x10: retVal = m_y4->read() << 8; break;
556 			case 0x20: retVal = m_y5->read() << 8; break;
557 			case 0x40: retVal = m_y6->read() << 8; break;
558 			case 0x80: retVal = m_y7->read() << 8; break;
559 		}
560 	}
561 #if 0
562 	if (((m_pr_cont&0xFF00) != 0x0800) && ((m_pr_cont&0xFF00) != 0x0900) && ((m_pr_cont&0xFF00) != 0x0a00))
563 	{
564 		fprintf(stderr,"Read from keyboard in %06X with unexpected pr_cont %04X\n", 0x80000a+(offset<<1), m_pr_cont);
565 	}
566 #endif
567 	return retVal;
568 }
569 
570 // 0x80000c-0x80000d (unused in cat source code; may have originally been a separate read only port where 800006 would have been write-only)
571 
572 // 0x80000e-0x80000f 'pr.cont' read
cat_battery_r()573 uint16_t cat_state::cat_battery_r()
574 {
575 	/*
576 	 * FEDCBA98 (76543210 is open bus)
577 	 * |||||||\-- ? possibly PE (pin 1) read ("PAPER OUT" pin 12 of centronics port)
578 	 * ||||||\--- ? possibly SLCT/ERR (pin 3) read ("not selected or error" NAND of pins 32 and 13 of centronics port)
579 	 * |||||\---- (always 0?)
580 	 * ||||\----- (always 0?)
581 	 * |||\------ (always 0?)
582 	 * ||\------- (always 0?)
583 	 * |\-------- (always 0?)
584 	 * \--------- Battery status (0 = good, 1 = bad)
585 	 */
586 	/* just return that battery is full, i.e. bit 15 is 0 */
587 	/* to make the cat think the battery is bad, return 0x8080 instead of 0x0080 */
588 	// TODO: hook this to a dipswitch
589 	return 0x0080;
590 }
591 // 0x80000e-0x80000f 'pr.cont' write
cat_printer_control_w(offs_t offset,uint16_t data)592 void cat_state::cat_printer_control_w(offs_t offset, uint16_t data)
593 {
594 	/*
595 	 * FEDCBA98 (76543210 is ignored)
596 	 * |||||||\-- CC line enable (pin 34) (verified from cat source code)
597 	 * ||||||\--- LEDE line enable (pin 33) (verified from cat source code)
598 	 * |||||\---- ?
599 	 * ||||\----- ? may be IPP (pin 2) write (non-standard pin 34 of centronics port) or another watchdog reset bit; may also be /DSTB-enable-on-pr.data-write
600 	 * |||\------ ?
601 	 * ||\------- ?
602 	 * |\-------- ?
603 	 * \--------- ?
604 	 */
605 	// writes of 0x0A00 turn on the keyboard LED on the LOCK key
606 	// writes of 0x0800 turn off the keyboard LED on the LOCK key
607 #ifdef DEBUG_PRINTER_CONTROL_W
608 	fprintf(stderr,"Write to Printer Control address %06X, data %04X\n", (offset<<1)+0x80000e, data);
609 #endif
610 	m_pr_cont = data;
611 }
612 
613 // 0x820000: AMI S35213 300/1200 Single Chip Modem (datasheet found at http://bitsavers.trailing-edge.com/pdf/ami/_dataBooks/1985_AMI_MOS_Products_Catalog.pdf on pdf page 243)
cat_modem_r(offs_t offset)614 uint16_t cat_state::cat_modem_r(offs_t offset)
615 {
616 #ifdef DEBUG_MODEM_R
617 	fprintf(stderr,"Read from s35213 modem address %06X\n", 0x820000+(offset<<1));
618 #endif
619 // HACK: return default 'sane' modem state
620 	return 0x00;
621 }
622 
cat_modem_w(offs_t offset,uint16_t data)623 void cat_state::cat_modem_w(offs_t offset, uint16_t data)
624 {
625 #ifdef DEBUG_MODEM_W
626 	fprintf(stderr,"Write to s35213 modem address %06X, data %04X\n", 0x820000+(offset<<1), data);
627 #endif
628 }
629 
630 // 0x830000: 6ms counter (counts KTOBF pulses and does not reset; 16 bits wide)
cat_6ms_counter_r()631 uint16_t cat_state::cat_6ms_counter_r()
632 {
633 	return m_6ms_counter;
634 }
635 
636 /* 0x840001: 'opr' or 'ga2opr' Output Port Register (within GA2)
637  * writing anything with bit 3 set here resets the watchdog
638  * if the watchdog expires /NMI (and maybe /RESET) are asserted to the cpu
639  * watchdog counter (counts KTOBF pulses and is reset on any ga2opr write with bit 3 set; <9 bits wide)
640  */
cat_opr_w(offs_t offset,uint16_t data)641 void cat_state::cat_opr_w(offs_t offset, uint16_t data)
642 {
643 	/*
644 	 * 76543210 (FEDCBA98 are ignored)
645 	 * |||||||\-- OFFHOOK pin (pin 3) output control (1 = puts phone off hook by energizing relay K2)
646 	 * ||||||\--- PHONE pin (pin 4) output control (1 = connects phone and line together by energizing relay K1)
647 	 * |||||\---- Video enable (1 = video on, 0 = video off/screen black)
648 	 * ||||\----- Watchdog reset (the watchdog is reset whenever this bit is written with a 1)
649 	 * |||\------ Video invert (1 = black-on-white video; 0 = white-on-black)
650 	 * ||\------- (unused?)
651 	 * |\-------- (unused?)
652 	 * \--------- (unused?)
653 	 */
654 #ifdef DEBUG_GA2OPR_W
655 	if (data != 0x001C)
656 		fprintf(stderr, "GA2 OPR (video ena/inv, watchdog, and phone relay) reg write: offset %06X, data %04X\n", 0x840000+(offset<<1), data);
657 #endif
658 	if (data&0x08) m_wdt_counter = 0;
659 	m_video_enable = BIT( data, 2 );
660 	m_video_invert = 1-BIT( data, 4 );
661 }
662 
663 // 0x850000: 'wdt' "watchdog timer and power fail", read only?
664 	/* NOTE: BELOW IS A GUESS based on seeing what the register reads as,
665 	 * the cat code barely touches this stuff at all, despite the fact
666 	 * that the service manual states that PFAIL is supposed to be checked
667 	 * before each write to SVRAM, the forth code does NOT actually do that!
668 	 *
669 	 * 76543210
670 	 * ??????\\-- Watchdog count? (counts upward? if this reaches <some unknown number greater than 3> the watchdog fires? writing bit 3 set to opr above resets this)
671 	 *
672 	 * FEDCBA98
673 	 * |||||||\-- PFAIL state (MB3771 comparator: 1: vcc = 5v; 0: vcc != 5v, hence do not write to svram!)
674 	 * ||||||\--- (always 0?)
675 	 * |||||\---- (always 0?)
676 	 * ||||\----- (always 0?)
677 	 * |||\------ (always 0?)
678 	 * ||\------- (always 0?)
679 	 * |\-------- (always 0?)
680 	 * \--------- (always 0?)
681 	 */
cat_wdt_r()682 uint16_t cat_state::cat_wdt_r()
683 {
684 	uint16 Retval = 0x0100; // set pfail to 1; should this be a dipswitch?
685 	return Retval | m_wdt_counter;
686 }
687 
688 // 0x860000: 'tcb' "test control bits" test mode register; what the bits do is
689 // unknown. 0x0000 is written here to disable test mode, and that is the extent
690 // of the cat touching this register.
cat_tcb_w(offs_t offset,uint16_t data)691 void cat_state::cat_tcb_w(offs_t offset, uint16_t data)
692 {
693 #ifdef DEBUG_TEST_W
694 	fprintf(stderr, "Test reg write: offset %06X, data %04X\n", 0x860000+(offset<<1), data);
695 #endif
696 }
697 
698 // open bus etc handlers
cat_2e80_r()699 uint16_t cat_state::cat_2e80_r()
700 {
701 	return 0x2e80;
702 }
703 
cat_0000_r()704 uint16_t cat_state::cat_0000_r()
705 {
706 	return 0x0000;
707 }
708 
cat_0080_r()709 uint16_t cat_state::cat_0080_r()
710 {
711 	return 0x0080;
712 }
713 
714 
715 /* Canon cat memory map, based on testing and a 16MB dump of the entire address space of a running unit using forth "1000000 0 do i c@ semit loop"
716 68k address map:
717 a23 a22 a21 a20 a19 a18 a17 a16 a15 a14 a13 a12 a11 a10 a9  a8  a7  a6  a5  a4  a3  a2  a1  (a0 via UDS/LDS)
718 *i  *i  *   x   x   *   *   *   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x       *GATE ARRAY 2 DECODES THESE LINES TO ENABLE THIS AREA* (a23 and a22 are indirectly decoded via the /RAMROMCS and /IOCS lines from gate array 1)
719 0   0   0   x   x   0   a   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   b       R   ROM (ab: 00=ic4 01=ic2 10=ic5 11=ic3) (EPROM 27C512 x 4) [controlled via GA2 /ROMCS]
720 0   0   0   x   x   1   0   0   x   x   *   *   *   *   *   *   *   *   *   *   *   *   *   0       RW  SVRAM ic11 d4364 (battery backed) [controlled via GA2 /RAMCS]
721 0   0   0   x   x   1   x   1   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   0       O   OPEN BUS (reads as 0x2e) [may be controlled via GA2 /RAMCS?]
722 0   0   0   x   x   1   1   0   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   0       O   OPEN BUS (reads as 0x2e) [may be controlled via GA2 /RAMCS?]
723 0   0   0   x   x   1   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   1       O   OPEN BUS (reads as 0x80) [may be controlled via GA2 /RAMCS?]
724 0   0   1   x   x   0   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   0       R   SVROM 2 ic7 (not present on cat as sold, open bus reads as 0x2e) [controlled via GA2 /SVCS0]
725 0   0   1   x   x   0   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   1       R   SVROM 0 ic6 (mask ROM tc531000) [controlled via GA2 /SVCS0]
726 0   0   1   x   x   1   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   0       O   OPEN BUS (reads as 0x2e) [controlled via GA2 /SVCS1] *SEE BELOW*
727 0   0   1   x   x   1   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   1       R   SVROM 1 ic8 (not present on cat as sold, open bus reads as 0x80) [controlled via GA2 /SVCS1] *SEE BELOW*
728                                                                                                     *NOTE: on Dwight E's user-made developer unit, two 128K SRAMS are mapped in place of the
729                                                                                                     two entries immediately above!* (this involves some creative wiring+sockets); the official
730                                                                                                     IAI 'shadow ram board' maps the ram to the A00000-A3FFFF area instead)
731 0   1   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *       *BOTH GATE ARRAYS 1 and 2 DECODE THIS AREA; 2 DEALS WITH ADDR AND 1 WITH DATA/CAS/RAS*
732 0   1   0   x   x   a   b   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *       RW  VIDEO/SYSTEM DRAM (ab: 00=row 0, ic26-29; 01=row 1, ic22-25; 10=row 2; ic18-21; 11=row 3; ic14-17)
733                                                                                                     *NOTE: DRAM rows 2 and 3 above are only usually populated in cat developer units!*
734 0   1   1   ?   ?   *   *   *   ?   ?   ?   ?   ?   ?   ?   *   *   *   *   *   *   *   *   x       W   VIDEO CONTRL REGISTERS (reads as 0x2e80)
735 1   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   *   *   *   *   *       *GATE ARRAY 3 DECODES THIS AREA, GA3 IS ENABLED BY /IOCS1 FROM GA2*
736 1   0   0   Y   Y   0   0   0   x   x   x   x   x   x   x   x   x   x   x   *   *   *   *   0       {'ga3'} *IO AREA* Note byte reads in this area behave erratically if both Y bits are set while word reads work fine always
737                                                                             x   x   x   x   1       O   OPEN BUS (reads as 0x80)
738                                                                             0   0   0   0   0       RW  {'fd.cont'} Floppy control lines (drive select, motor on, direction, step, side select, ?write gate?)
739                                                                             0   0   0   1   0       W   {'kb.wr'} Keyboard Row Select (reads as 0x00)
740                                                                             0   0   1   0   0       W   {'pr.data'} Centronics Printer Data W (reads as 0x00)
741                                                                             0   0   1   1   0       RW  {'fd.dwr' and 'fd.drd'} Floppy data read/write register; maybe the write gate value in fd.cont chooses which?
742                                                                             0   1   0   0   0       R   {'fd.status'} Floppy status lines (write protect, ready, index, track0)
743                                                                             0   1   0   1   0       R   Keyboard Column Read
744                                                                             0   1   1   0   0       W?  Unknown (reads as 0x00)
745                                                                             0   1   1   1   0       RW  {'pr.cont'} Read: Battery status (MSB bit, 0 = ok, 1 = dead, other bits read as 0)/Write: Centronics Printer and Keyboard LED/Country Code Related
746                                                                             1   x   x   x   0       W?  Unknown (reads as 0x00)
747 1   0   0   x   x   0   0   1   x   x   x   x   x   x   x   x   x   x   x   *   *   *   *   1       RW  {'duart'} 68681 DUART at ic34 [controlled via GA2 /DUARTCS]
748 1   0   0   x   x   0   1   0   x   x   x   x   x   x   x   x   x   x   *   *   *   *   *   0       RW  {'modem'} Modem Chip AMI S35213 @ IC37 DATA BIT 7 ONLY [controlled via GA2 /SMCS]
749 1   0   0   x   x   0   1   1   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   *       R   {'timer'} Read: Fixed 16-bit counter from ga2. increments every 6.5535ms when another 16-bit counter clocked at 10mhz overflows
750 1   0   0   x   x   1   0   0   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   *       W   {'opr'} Output Port (Video/Sync enable and watchdog reset?) register (screen enable on bit 3?) (reads as 0x2e80)
751 1   0   0   x   x   1   0   1   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   *       R   {'wdt'} Watchdog timer reads as 0x0100 0x0101 or 0x0102, some sort of test register or video status register?
752 1   0   0   x   x   1   1   0   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   *       R?W {'tcb'} test control bits (reads as 0x0000)
753 1   0   0   x   x   1   1   1   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   *       ?   Unknown (reads as 0x2e80)
754 
755 1   0   1   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x       O   OPEN BUS (reads as 0x2e80) [68k DTACK is asserted by gate array 1 when accessing this area, for testing?] On real IAI shadow ROM board, at least 0x40000 of ram lives here.
756 1   1   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x   x       O   OPEN BUS (reads as 0x2e80) [68k VPA is asserted by gate array 1 when accessing this area, for testing?]
757 */
758 
759 
cat_mem(address_map & map)760 void cat_state::cat_mem(address_map &map)
761 {
762 	map.unmap_value_high();
763 	map(0x000000, 0x03ffff).rom().mirror(0x180000); // 256 KB ROM
764 	map(0x040000, 0x043fff).ram().share("svram").mirror(0x18C000);// SRAM powered by battery
765 	map(0x200000, 0x27ffff).rom().region("svrom", 0x0000).mirror(0x180000); // SV ROM
766 	map(0x400000, 0x47ffff).ram().share("p_cat_vram").mirror(0x180000); // 512 KB RAM
767 	map(0x600000, 0x67ffff).rw(FUNC(cat_state::cat_2e80_r), FUNC(cat_state::cat_video_control_w)).mirror(0x180000); // Gate Array #1: Video Addressing and Timing, dram refresh timing, dram /cs and /wr (ga2 does the actual video invert/display and access to the dram data bus)
768 	map(0x800000, 0x800001).rw(FUNC(cat_state::cat_floppy_control_r), FUNC(cat_state::cat_floppy_control_w)).mirror(0x18FFE0); // floppy control lines and readback
769 	map(0x800002, 0x800003).rw(FUNC(cat_state::cat_0080_r), FUNC(cat_state::cat_keyboard_w)).mirror(0x18FFE0); // keyboard col write
770 	map(0x800004, 0x800005).rw(FUNC(cat_state::cat_0080_r), FUNC(cat_state::cat_printer_data_w)).mirror(0x18FFE0); // Centronics Printer Data
771 	map(0x800006, 0x800007).rw(FUNC(cat_state::cat_floppy_data_r), FUNC(cat_state::cat_floppy_data_w)).mirror(0x18FFE0); // floppy data read/write
772 	map(0x800008, 0x800009).r(FUNC(cat_state::cat_floppy_status_r)).mirror(0x18FFE0); // floppy status lines
773 	map(0x80000a, 0x80000b).r(FUNC(cat_state::cat_keyboard_r)).mirror(0x18FFE0); // keyboard row read
774 	map(0x80000c, 0x80000d).r(FUNC(cat_state::cat_0080_r)).mirror(0x18FFE0); // Open bus?
775 	map(0x80000e, 0x80000f).rw(FUNC(cat_state::cat_battery_r), FUNC(cat_state::cat_printer_control_w)).mirror(0x18FFE0); // Centronics Printer Control, keyboard led and country code enable
776 	map(0x800010, 0x80001f).r(FUNC(cat_state::cat_0080_r)).mirror(0x18FFE0); // Open bus?
777 	map(0x810000, 0x81001f).rw(m_duart, FUNC(mc68681_device::read), FUNC(mc68681_device::write)).umask16(0x00ff).mirror(0x18FFE0);
778 	map(0x820000, 0x82003f).rw(FUNC(cat_state::cat_modem_r), FUNC(cat_state::cat_modem_w)).mirror(0x18FFC0); // AMI S35213 Modem Chip, all access is on bit 7
779 	map(0x830000, 0x830001).r(FUNC(cat_state::cat_6ms_counter_r)).mirror(0x18FFFE); // 16bit 6ms counter clocked by output of another 16bit counter clocked at 10mhz
780 	map(0x840000, 0x840001).rw(FUNC(cat_state::cat_2e80_r), FUNC(cat_state::cat_opr_w)).mirror(0x18FFFE); // GA2 Output port register (video enable, invert, watchdog reset, phone relays)
781 	map(0x850000, 0x850001).r(FUNC(cat_state::cat_wdt_r)).mirror(0x18FFFE); // watchdog and power fail state read
782 	map(0x860000, 0x860001).rw(FUNC(cat_state::cat_0000_r), FUNC(cat_state::cat_tcb_w)).mirror(0x18FFFE); // Test mode
783 	map(0x870000, 0x870001).r(FUNC(cat_state::cat_2e80_r)).mirror(0x18FFFE); // Open bus?
784 	map(0xA00000, 0xA00001).r(FUNC(cat_state::cat_2e80_r)).mirror(0x1FFFFE); // Open bus/dtack? The 0xA00000-0xA3ffff area is ram used for shadow ROM storage on cat developer machines, which is either banked over top of, or jumped to instead of the normal ROM
785 	map(0xC00000, 0xC00001).r(FUNC(cat_state::cat_2e80_r)).mirror(0x3FFFFE); // Open bus/vme?
786 }
787 
788 /* Input ports */
789 
790 /* 2009-07 FP
791    FIXME: Natural keyboard does not catch all the Shifted chars. No idea of the reason!  */
792 static INPUT_PORTS_START( cat )
793 	PORT_START("DIPSW1")
794 	PORT_DIPNAME( 0x8000, 0x8000, "Mode" )
DEF_STR(Normal)795 	PORT_DIPSETTING(    0x8000, DEF_STR( Normal ) )
796 	PORT_DIPSETTING(    0x0000, "Diagnostic" )
797 	PORT_DIPNAME( 0x7f00,0x7f00, "Country code" )
798 	PORT_DIPSETTING(    0x7f00, "United States" )
799 	PORT_DIPSETTING(    0x7e00, "Canada" )
800 	PORT_DIPSETTING(    0x7d00, "United Kingdom" )
801 	PORT_DIPSETTING(    0x7c00, "Norway" )
802 	PORT_DIPSETTING(    0x7b00, "France" )
803 	PORT_DIPSETTING(    0x7a00, "Denmark" )
804 	PORT_DIPSETTING(    0x7900, "Sweden" )
805 	PORT_DIPSETTING(    0x7800, DEF_STR(Japan) )
806 	PORT_DIPSETTING(    0x7700, "West Germany" )
807 	PORT_DIPSETTING(    0x7600, "Netherlands" )
808 	PORT_DIPSETTING(    0x7500, "Spain" )
809 	PORT_DIPSETTING(    0x7400, "Italy" )
810 	PORT_DIPSETTING(    0x7300, "Latin America" )
811 	PORT_DIPSETTING(    0x7200, "South Africa" )
812 	PORT_DIPSETTING(    0x7100, "Switzerland" )
813 	PORT_DIPSETTING(    0x7000, "ASCII" )
814 
815 	PORT_START("Y0")
816 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
817 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
818 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
819 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
820 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
821 	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
822 	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR(0xA2)
823 	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
824 
825 	PORT_START("Y1")
826 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('n') PORT_CHAR('B')
827 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
828 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
829 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
830 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
831 	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
832 	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')
833 	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
834 
835 	PORT_START("Y2")
836 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
837 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
838 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
839 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
840 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
841 	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) // totally unused
842 	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')
843 	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
844 
845 	PORT_START("Y3")
846 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
847 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Left USE FRONT") PORT_CODE(KEYCODE_LCONTROL)
848 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"')
849 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
850 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
851 	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
852 	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
853 	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) // totally unused
854 
855 	PORT_START("Y4")
856 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
857 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Right USE FRONT") PORT_CODE(KEYCODE_RCONTROL)
858 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Right Shift") PORT_CODE(KEYCODE_F2) // intl only: latin diaresis and latin !; norway, danish and finnish * and '; others
859 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
860 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
861 	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
862 	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
863 	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
864 
865 	PORT_START("Y5")
866 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
867 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
868 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
869 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
870 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR(0xBD) PORT_CHAR(0xBC) //PORT_CHAR('}') PORT_CHAR('{')
871 	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
872 	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
873 	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
874 
875 	PORT_START("Y6")
876 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Left Shift") PORT_CODE(KEYCODE_F1) // intl only: latin inv ? and inv !; norway and danish ! and |; finnish <>; others
877 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Left LEAP") PORT_CODE(KEYCODE_LALT)
878 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
879 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
880 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('[')
881 	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t')
882 	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+')
883 	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) // totally unused
884 
885 	PORT_START("Y7")
886 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_RSHIFT) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
887 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Right Leap") PORT_CODE(KEYCODE_RALT)
888 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Page") PORT_CODE(KEYCODE_PGUP) PORT_CODE(KEYCODE_PGDN)
889 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Shift Lock") PORT_CODE(KEYCODE_CAPSLOCK)
890 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Erase") PORT_CODE(KEYCODE_BACKSPACE)
891 	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) // totally unused
892 	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("UNDO") PORT_CODE(KEYCODE_BACKSLASH)
893 	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0xB1) PORT_CHAR(0xB0) // PORT_CHAR('\\') PORT_CHAR('~')
894 INPUT_PORTS_END
895 
896 
897 void cat_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
898 {
899 	switch (id)
900 	{
901 	case TIMER_COUNTER_6MS:
902 		counter_6ms_callback(ptr, param);
903 		break;
904 	default:
905 		throw emu_fatalerror("Unknown id in cat_state::device_timer");
906 	}
907 }
908 
TIMER_CALLBACK_MEMBER(cat_state::counter_6ms_callback)909 TIMER_CALLBACK_MEMBER(cat_state::counter_6ms_callback)
910 {
911 	// This is effectively also the KTOBF (guessed: acronym for "Keyboard Timer Out Bit Flip")
912 	// line connected in such a way to invert the d-flipflop connected to the duart IP2
913 	m_duart_ktobf_ff ^= 1;
914 	m_duart->ip2_w(m_duart_ktobf_ff);
915 	m_wdt_counter++;
916 	m_6ms_counter++;
917 }
918 
cpu_space_map(address_map & map)919 void cat_state::cpu_space_map(address_map &map)
920 {
921 	map(0xfffff0, 0xffffff).m(m_maincpu, FUNC(m68000_base_device::autovectors_map));
922 	map(0xfffff3, 0xfffff3).lr8(NAME([this]() { m_maincpu->set_input_line(1, CLEAR_LINE); return m68000_device::autovector(1); }));
923 }
924 
MACHINE_START_MEMBER(cat_state,cat)925 MACHINE_START_MEMBER(cat_state,cat)
926 {
927 	m_duart_ktobf_ff = 0; // reset doesn't touch this
928 	m_duart_prn_ack_prev_state = 1; // technically uninitialized
929 	m_duart_prn_ack_ff = 0; // reset doesn't touch this
930 	m_6ms_counter = 0;
931 	m_wdt_counter = 0;
932 	m_video_enable = 1;
933 	m_video_invert = 0;
934 	m_6ms_timer = timer_alloc(TIMER_COUNTER_6MS);
935 	subdevice<nvram_device>("nvram")->set_base(m_svram, 0x4000);
936 }
937 
MACHINE_RESET_MEMBER(cat_state,cat)938 MACHINE_RESET_MEMBER(cat_state,cat)
939 {
940 	m_6ms_counter = 0;
941 	m_wdt_counter = 0;
942 	m_floppy_control = 0;
943 	m_6ms_timer->adjust(attotime::zero, 0, attotime::from_hz((XTAL(19'968'000)/2)/65536));
944 }
945 
VIDEO_START_MEMBER(cat_state,cat)946 VIDEO_START_MEMBER(cat_state,cat)
947 {
948 }
949 
screen_update_cat(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)950 uint32_t cat_state::screen_update_cat(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
951 {
952 	const rgb_t on_color = m_video_invert ? rgb_t::black() : rgb_t::white();
953 	const rgb_t off_color = m_video_invert ? rgb_t::white() : rgb_t::black();
954 
955 	int addr = 0;
956 	if (m_video_enable == 1)
957 	{
958 		for (int y = 0; y < 344; y++)
959 		{
960 			int horpos = 0;
961 			for (int x = 0; x < 42; x++)
962 			{
963 				const uint16_t code = m_p_cat_videoram[addr++];
964 				for (int b = 15; b >= 0; b--)
965 				{
966 					bitmap.pix(y, horpos++) = BIT(code, b) ? on_color : off_color;
967 				}
968 			}
969 		}
970 	} else {
971 		const rectangle black_area(0, 672 - 1, 0, 344 - 1);
972 		bitmap.fill(rgb_t::black(), black_area);
973 	}
974 	return 0;
975 }
976 
977 /* The duart is the only thing actually connected to the cpu IRQ pin
978  * The KTOBF output of the gate array 2 (itself the terminal count output
979  * of a 16-bit counter clocked at ~10mhz, hence 6.5536ms period) goes to a
980  * d-latch and inputs on ip2 of the duart, causing the duart to fire an irq;
981  * this is used by the cat to read the keyboard.
982  * The duart also will, if configured to do so, fire an int when the state
983  * changes of the centronics /ACK pin; this is used while printing.
984  */
WRITE_LINE_MEMBER(cat_state::cat_duart_irq_handler)985 WRITE_LINE_MEMBER(cat_state::cat_duart_irq_handler)
986 {
987 #ifdef DEBUG_DUART_IRQ_HANDLER
988 	fprintf(stderr, "Duart IRQ handler called: state: %02X, vector: %06X\n", state, irqvector);
989 #endif
990 	m_maincpu->set_input_line(M68K_IRQ_1, state);
991 }
992 
WRITE_LINE_MEMBER(cat_state::cat_duart_txa)993 WRITE_LINE_MEMBER(cat_state::cat_duart_txa) // semit sends stuff here; connects to the serial port on the back
994 {
995 #ifdef DEBUG_DUART_TXA
996 	fprintf(stderr, "Duart TXA: data %02X\n", state);
997 #endif
998 }
999 
WRITE_LINE_MEMBER(cat_state::cat_duart_txb)1000 WRITE_LINE_MEMBER(cat_state::cat_duart_txb) // memit sends stuff here; connects to the modem chip
1001 {
1002 #ifdef DEBUG_DUART_TXB
1003 	fprintf(stderr, "Duart TXB: data %02X\n", state);
1004 #endif
1005 }
1006 
1007 /* mc68681 DUART Input pins:
1008  * IP0: CTS [using the DUART builtin hardware-CTS feature?]
1009  * IP1: Centronics /ACK (pin 10) positive edge detect (IP1 changes state 0->1
1010         or 1->0 on the rising edge of /ACK using a 74ls74a d-flipflop)
1011  * IP2: KTOBF (IP2 changes state 0->1 or 1->0 on the rising edge of KTOBF
1012         using a 74ls74a d-flipflop; KTOBF is a 6.5536ms-period squarewave
1013         generated by one of the gate arrays, I need to check with a scope to
1014         see whether it is a single spike/pulse every 6.5536ms or if from the
1015         gate array it inverts every 6.5536ms, documentation isn't 100% clear
1016         but I suspect the former) [uses the Delta IP2 state change detection
1017         feature to generate an interrupt; I'm not sure if IP2 is used as a
1018         counter clock source but given the beep frequency of the real unit I
1019         very much doubt it, 6.5536ms is too slow]
1020  * IP3: RG ("ring" input)
1021  * IP4: Centronics BUSY (pin 11), inverted
1022  * IP5: DSR
1023  */
1024 
1025 /* mc68681 DUART Output pins:
1026  * OP0: RTS [using the DUART builtin hardware-RTS feature?]
1027  * OP1: DTR
1028  * OP2: /TDCS (select/enable the S2579 DTMF tone generator chip)
1029  * OP3: speaker out [using the 'channel b 1X tx or rx clock output' or more likely the 'timer output' feature to generate a squarewave]
1030  * OP4: TD03 (data bus for the S2579 DTMF tone generator chip)
1031  * OP5: TD02 "
1032  * OP6: TD01 "
1033  * OP7: TD00 "
1034  */
cat_duart_output(uint8_t data)1035 void cat_state::cat_duart_output(uint8_t data)
1036 {
1037 #ifdef DEBUG_DUART_OUTPUT_LINES
1038 	fprintf(stderr,"Duart output io lines changed to: %02X\n", data);
1039 #endif
1040 	m_speaker->level_w((data >> 3) & 1);
1041 }
1042 
WRITE_LINE_MEMBER(cat_state::prn_ack_ff)1043 WRITE_LINE_MEMBER(cat_state::prn_ack_ff) // switch the flipflop state on the rising edge of /ACK
1044 {
1045 	if ((m_duart_prn_ack_prev_state == 0) && (state == 1))
1046 	{
1047 		m_duart_prn_ack_ff ^= 1;
1048 	}
1049 	m_duart->ip1_w(m_duart_prn_ack_ff);
1050 	m_duart_prn_ack_prev_state = state;
1051 #ifdef DEBUG_PRN_FF
1052 	fprintf(stderr, "Printer ACK: state %02X, flipflop is now %02x\n", state, m_duart_prn_ack_ff);
1053 #endif
1054 }
1055 
cat(machine_config & config)1056 void cat_state::cat(machine_config &config)
1057 {
1058 	/* basic machine hardware */
1059 	M68000(config, m_maincpu, XTAL(19'968'000)/4);
1060 	m_maincpu->set_addrmap(AS_PROGRAM, &cat_state::cat_mem);
1061 	m_maincpu->set_addrmap(m68000_base_device::AS_CPU_SPACE, &cat_state::cpu_space_map);
1062 
1063 	MCFG_MACHINE_START_OVERRIDE(cat_state,cat)
1064 	MCFG_MACHINE_RESET_OVERRIDE(cat_state,cat)
1065 
1066 	/* video hardware */
1067 	screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
1068 	screen.set_refresh_hz(50);
1069 	screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */
1070 	screen.set_size(672, 344);
1071 	screen.set_visarea_full();
1072 	screen.set_screen_update(FUNC(cat_state::screen_update_cat));
1073 
1074 	MCFG_VIDEO_START_OVERRIDE(cat_state,cat)
1075 
1076 	MC68681(config, m_duart, (XTAL(19'968'000)*2)/11); // duart is normally clocked by 3.6864mhz xtal, but cat seemingly uses a divider from the main xtal instead which probably yields 3.63054545Mhz. There is a trace to cut and a mounting area to allow using an actual 3.6864mhz xtal if you so desire
1077 	m_duart->irq_cb().set(FUNC(cat_state::cat_duart_irq_handler));
1078 	m_duart->a_tx_cb().set(FUNC(cat_state::cat_duart_txa));
1079 	m_duart->b_tx_cb().set(FUNC(cat_state::cat_duart_txb));
1080 	m_duart->outport_cb().set(FUNC(cat_state::cat_duart_output));
1081 
1082 	CENTRONICS(config, m_ctx, centronics_devices, "printer");
1083 	m_ctx->ack_handler().set(FUNC(cat_state::prn_ack_ff));
1084 	m_ctx->busy_handler().set(m_duart, FUNC(mc68681_device::ip4_w)).invert();
1085 
1086 	OUTPUT_LATCH(config, m_ctx_data_out);
1087 	m_ctx->set_output_latch(*m_ctx_data_out);
1088 
1089 	SPEAKER(config, "mono").front_center();
1090 	SPEAKER_SOUND(config, "speaker").add_route(ALL_OUTPUTS, "mono", 1.00);
1091 
1092 	NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0);
1093 }
1094 
1095 ROM_START( cat )
1096 	ROM_REGION( 0x40000, "maincpu", ROMREGION_ERASEFF )
1097 	// SYS ROM
1098 	/* This 2.40 code came from two development cat machines owned or formerly
1099 	 * owned by former IAI employees Sandy Bumgarner and Dave Boulton.
1100 	 * Dave Boulton's machine is interesting in that it has a prototype cat
1101 	 * motherboard in it, which it has less space for dram than a 'released'
1102 	 * cat does: it uses 16k*4 dram chips instead of 64k*4 as in the final
1103 	 * cat, and hence can only support 128k of ram with all 4 rows of drams
1104 	 * populated, as opposed to 256k-standard (2 rows) and 512k-max with all
1105 	 * 4 rows populated on a "released" cat.
1106 	 */
1107 	ROM_SYSTEM_BIOS( 0, "r240", "Canon Cat V2.40 US Firmware")
1108 	ROMX_LOAD( "boultl0.ic2", 0x00001, 0x10000, CRC(77b66208) SHA1(9d718c0a521fefe4f86ef328805b7921bade9d89), ROM_SKIP(1) | ROM_BIOS(0))
1109 	ROMX_LOAD( "boulth0.ic4", 0x00000, 0x10000, CRC(f1e1361a) SHA1(0a85385527e2cc55790de9f9919eb44ac32d7f62), ROM_SKIP(1) | ROM_BIOS(0))
1110 	ROMX_LOAD( "boultl1.ic3", 0x20001, 0x10000, CRC(c61dafb0) SHA1(93216c26c2d5fc71412acc548c96046a996ea668), ROM_SKIP(1) | ROM_BIOS(0))
1111 	ROMX_LOAD( "boulth1.ic5", 0x20000, 0x10000, CRC(bed1f761) SHA1(d177e1d3a39b005dd94a6bda186221d597129af4), ROM_SKIP(1) | ROM_BIOS(0))
1112 	/* This 2.40 code was compiled by Dwight Elvey based on the v2.40 source
1113 	 * code disks recovered around 2004. It does NOT exactly match the above
1114 	 * set exactly but has a few small differences. One of the printer drivers
1115 	 * may have been replaced by Dwight with an HP PCL4 driver.
1116 	 * It is as of yet unknown whether it is earlier or later code than the
1117 	 * set above.
1118 	 */
1119 	ROM_SYSTEM_BIOS( 1, "r240r", "Canon Cat V2.40 US Firmware compiled from recovered source code")
1120 	ROMX_LOAD( "r240l0.ic2", 0x00001, 0x10000, CRC(1b89bdc4) SHA1(39c639587dc30f9d6636b46d0465f06272838432), ROM_SKIP(1) | ROM_BIOS(1))
1121 	ROMX_LOAD( "r240h0.ic4", 0x00000, 0x10000, CRC(94f89b8c) SHA1(6c336bc30636a02c625d31f3057ec86bf4d155fc), ROM_SKIP(1) | ROM_BIOS(1))
1122 	ROMX_LOAD( "r240l1.ic3", 0x20001, 0x10000, CRC(1a73be4f) SHA1(e2de2cb485f78963368fb8ceba8fb66ca56dba34), ROM_SKIP(1) | ROM_BIOS(1))
1123 	ROMX_LOAD( "r240h1.ic5", 0x20000, 0x10000, CRC(898dd9f6) SHA1(93e791dd4ed7e4afa47a04df6fdde359e41c2075), ROM_SKIP(1) | ROM_BIOS(1))
1124 	/* This v1.74 code comes from (probably) the 'main us release' of first-run
1125 	 * Canon cats, and was dumped from machine serial number R12014979
1126 	 * Canon cat v1.74 ROMs are labeled as r74; they only added the major number
1127 	 * to the ROM label after v2.0?
1128 	 */
1129 	ROM_SYSTEM_BIOS( 2, "r174", "Canon Cat V1.74 US Firmware")
1130 	ROMX_LOAD( "r74__0l__c18c.blue.ic2", 0x00001, 0x10000, CRC(b19aa0c8) SHA1(85b3e549cfb91bd3dd32335e02eaaf9350e80900), ROM_SKIP(1) | ROM_BIOS(2))
1131 	ROMX_LOAD( "r74__0h__75a6.yellow.ic4", 0x00000, 0x10000, CRC(75281f77) SHA1(ed8b5e37713892ee83413d23c839d09e2fd2c1a9), ROM_SKIP(1) | ROM_BIOS(2))
1132 	ROMX_LOAD( "r74__1l__c8a3.green.ic3", 0x20001, 0x10000, CRC(93275558) SHA1(f690077a87076fd51ae385ac5a455804cbc43c8f), ROM_SKIP(1) | ROM_BIOS(2))
1133 	ROMX_LOAD( "r74__1h__3c37.white.ic5", 0x20000, 0x10000, CRC(5d7c3962) SHA1(8335993583fdd30b894c01c1a7a6aca61cd81bb4), ROM_SKIP(1) | ROM_BIOS(2))
1134 	// According to Sandy Bumgarner, there should be a 2.42 version which fixes some bugs in the calc command vs 2.40
1135 	// According to the Cat Repair Manual page 4-20, there should be a version called B91U0x (maybe 1.91 or 0.91?) with sum16s of 9F1F, FF0A, 79BF and 03FF
1136 
1137 	ROM_REGION16_BE( 0x80000, "svrom", ROMREGION_ERASE00 )
1138 	// SPELLING VERIFICATION ROM (SVROM)
1139 	/* Romspace here is a little strange: there are 3 ROM sockets on the board:
1140 	 * svrom-0 maps to 200000-21ffff every ODD byte (d8-d0)
1141 	 * svrom-1 maps to 200000-21ffff every EVEN byte (d15-d7)
1142 	 *  (since no ROM is in the socket; it reads as open bus, sometimes 0x2E)
1143 	 * svrom-2 maps to 240000-25ffff every ODD byte (d8-d0)
1144 	 *  (since no ROM is in the socket; it reads as open bus, sometimes 0x80)
1145 	 * there is no svrom-3 socket; 240000-25ffff EVEN always reads as 0x2E
1146 	 * since ROM_FILL16BE(0x0, 0x80000, 0x2e80) doesn't exist, the
1147 	 * even bytes and latter chunk of the svrom space need to be filled in
1148 	 * DRIVER_INIT or some other means needs to be found to declare them as
1149 	 * 'open bus' once the mame/mess core supports that.
1150 	 * NOTE: there are at least 6 more SVROMS which existed (possibly in
1151 	 * limited form), and are not dumped:
1152 	 * UK (1 ROM, NH7-0724)
1153 	 * French/Quebec (2 ROMs, NH7-0813/0814)
1154 	 * German (3 ROMs, NH7-1019/1020/1021)
1155 	 * Each of these will also have its own code ROMset as well.
1156 	 */
1157 	// NH7-0684 (US, dumped):
1158 	ROMX_LOAD( "uv1__nh7-0684__hn62301apc11__7h1.ic6", 0x00001, 0x20000, CRC(229ca210) SHA1(564b57647a34acdd82159993a3990a412233da14), ROM_SKIP(1)) // this is a 28pin tc531000 mask ROM, 128KB long; "US" SVROM
1159 
1160 	/* There is an unpopulated PAL16L8 at IC9 whose original purpose (based
1161 	 * on the schematics) was probably to cause a 68k bus error when
1162 	 * memory in certain ranges when accessed (likely so 'forth gone insane'
1163 	 * won't destroy the contents of ram and svram).
1164 	 * Its connections are (where Ix = inp on pin x, Ox = out on pin x):
1165 	 * I1 = A23, I2 = A22, I3 = A2, I4 = R/W, I5 = A5, I6 = FC2, I7 = gnd,
1166 	 * I8 = A1, I9 = gnd, I11 = gnd, O16 = /BERR,
1167 	 * I14 = REMAP (connects to emulator 'shadow ROM' board or to gnd when unused)
1168 	 * Based on the inputs and outputs of this pal, almost if not the entire
1169 	 * open bus and mirrored areas of the cat address space could be made
1170 	 * to cause bus errors. REMAP was probably used to 'open up' the A00000-A7ffff
1171 	 * shadow ROM/RAM area and make it writeable without erroring.
1172 	 */
1173 ROM_END
1174 
1175 /* Driver */
1176 
1177 /*    YEAR  NAME  PARENT  COMPAT  MACHINE  INPUT  CLASS      INIT        COMPANY  FULLNAME  FLAGS */
1178 COMP( 1987, cat,  0,      0,      cat,     cat,   cat_state, empty_init, "Canon", "Cat",    MACHINE_NOT_WORKING)
1179