1 // license:LGPL-2.1+
2 // copyright-holders:Michael Zapf
3 /****************************************************************************
4 
5     The MESS TI-99/8 emulation driver
6 
7     The TI-99/8 was the envisaged successor to the TI-99/4A but never passed
8     its prototype state. Only a few dozen consoles were built. The ROMs
9     were not even finalized, so the few available consoles have different
10     operating system versions and capabilities.
11 
12 
13     Characteristics
14     ---------------
15 
16     Name: "Texas Instruments Computer TI-99/8" (no "Home")
17 
18     Unofficial nickname: "Armadillo"
19 
20     CPU: Single-CPU system using a TMS9995, but as a variant named MP9537. This
21          variant does not offer on-chip RAM or decrementer.
22 
23     Video: TMS9118 Video Display Processor with 16 KiB RAM. The 9118 has the
24          same capabilities as the 9918/28 in the TI-99/4A, except for the
25          missing GROM clock (which must be provided separately) and the
26          different DRAM type (2 chips TMS 4416 16K*4). Delivers a 60 Hz
27          interrupt to the CPU via the PSI.
28 
29     Keyboard: 50-key keyboard, slightly different to the TI-99/4A, but also with
30          modifiers Control, Function, Shift, Caps Lock. Connects to the TMS 9901
31          PSI like in the TI-99/4A, but the pin assignment and key matrix
32          are different:
33          - P0-P3: column select
34          - INT6*-INT11*: row inputs (INT6* is only used for joystick fire)
35 
36     Cassette: Identical to TI-99/4A, except that the CS2 unit is not implemented
37 
38     Sound: SN94624 as used in the TI-99/4A
39 
40     Speech: TMS5200C, a rare variant of the TMS52xx family. Compatible to the
41          speech data for the separate speech synthesizer for the TI-99/4A.
42          Speech ROMs CD2325A, CD2326A (total 128K*1)
43 
44     ROM: TMS4764 (8K*8), called "ROM0" in the specifications [1]
45          TMS47256 (32K*8), called "ROM1" [1]
46          TMS47128 (16K*8), "P-Code ROM" (only available in late prototypes)
47          See below for contents
48 
49     GROMs: TI-specific ROM circuits with internal address counter and 6 KiB
50          capacity (see grom.c)
51          3 GROMs (system GROMs, access via port at logical address F830)
52          8 GROMs (Pascal / Text-to-speech GROMs, port at logical address F840)
53          8 GROMs (Pascal GROMs, port at logical address F850)
54          3 GROMs (Pascal GROMs, access via port at logical address F860)
55          (total of 132 KiB GROM)
56 
57     RAM: 1 TMS4016 (SRAM 2K*8)
58          8 TMS4164 (DRAM 64K*1)
59 
60     PSI: (programmable system interface) TMS9901 with connections to
61          keyboard, joystick port, cassette port, and external interrupt lines
62          (video, peripheral devices)
63 
64     External connectors:
65          - Joystick port (compatible to TI-99/4A joystick slot)
66          - Cassette port
67          - Cartridge port (compatible to TI-99/4A cartridge slot, but vertically
68            orientated, so cartridges are plugged in from the top)
69          - I/O port (not compatible to TI-99/4A I/O port, needs a special P-Box
70            card called "Armadillo interface")
71          - Hexbus port (new peripheral system, also seen with later TI designs)
72          - Video port (composite)
73 
74     Custom chips: Five custom chips contain mapping and selection logic
75          - "Vaquerro": Logical address space decoder
76          - "Mofetta" : Physical address space decoder
77          - "Amigo"   : Mapper
78          - "Pollo"   : DRAM controller
79          - "Oso"     : Hexbus interface
80 
81     Modes:
82          - Compatibility mode (TI-99/4A mode): Memory-mapped devices are
83            placed at the same location as found in the TI-99/4A, thereby
84            providing good downward compatibility.
85            The console starts up in compatibility mode.
86          - Native mode (Armadillo mode): Devices are located at positions above
87            0xF000 that allow for a contiguous usage of memory.
88 
89     Mapper
90     ------
91     The mapper uses 4K pages (unlike the Geneve mapper with 8K pages) which
92     are defined by a 32 bit word. The address bits A0-A3 serve as the page
93     index, whereas bits A4-A15 are the offset in the page.
94     From the 32 bits, 24 bits define the physical address, so this allows for
95     a maximum of 16 MiB of mapped-addressable memory.
96 
97     See more about the mapper in the file 998board.cpp
98 
99 
100     Availability of ROMs and documentation
101     --------------------------------------
102     By written consent, TI granted free use of all software and documentation
103     concerning the TI-99/8, including all specifications, ROMs, and source code
104     of ROMs.
105 
106 
107     Acknowledgements
108     ----------------
109     Special thanks go to Ciro Barile of the TI99 Italian User Club
110     (www.ti99iuc.it): By his courtesy we have a consistent dump of ROMs for
111     one of the most evolved versions of the TI-99/8 with
112 
113     - complete GROM set (with Pascal)
114     - complete ROM set (with Hexbus DSR and TTS)
115     - complete speech ROM set
116 
117     Also, by applying test programs on his real console, many unclear
118     specifications were resolved.
119 
120 
121     References
122     ----------
123     [1] Texas Instruments: Armadillo Product Specifications, July 1983
124     [2] Source code (Assembler and GPL) of the TI-99/8 ROMs and GROMs
125     [3] Schematics of the TI-99/8
126 
127 
128     Implementation
129     --------------
130     Initial version by Raphael Nabet, 2003.
131 
132     February 2012: Rewritten as class [Michael Zapf]
133     November 2013: Included new dumps [Michael Zapf]
134 
135 ===========================================================================
136 Known Issues (MZ, 2019-05-10)
137 
138   KEEP IN MIND THAT TEXAS INSTRUMENTS NEVER RELEASED THE TI-99/8 AND THAT
139   THERE ARE ONLY A FEW PROTOTYPES OF THE TI-99/8 AVAILABLE. ALL SOFTWARE
140   MUST BE ASSUMED TO HAVE REMAINED IN A PRELIMINARY STATE.
141 
142 - TI-99/4A disk controllers cannot be used with the TI-99/8 in Extended Basic II.
143   In the 99/8, the peripheral access block (PAB, set of data defining the
144   access to the device, like floppy) may be located in CPU RAM, while the
145   controllers of the 99/4A expect the PAB to be in video RAM only. Exbasic II
146   sets up the PAB in CPU RAM, which leads to a crash. Other cartridges from
147   the 99/4A certainly use video RAM, and so the disk controller works.
148   Therefore, the Hexbus floppy drive HX5102 is recommended for use with the
149   TI-99/8. You do not even need to attach the Peripheral Box.
150 
151   mame ti99_8 -hexbus hx5102 -flop1 somedisk.dsk
152 
153 - Multiple cartridges are not shown in the startup screen; only one
154   cartridge is presented. You have to manually select the cartridges with the
155   dip switch.
156 
157 - SAVE and OLD MINIMEM do not work properly in XB II. It seems as if the
158   mapper shadows the NVRAM of the cartridge. You will lose the contents when
159   you turn off the machine.
160 
161 *****************************************************************************/
162 
163 
164 #include "emu.h"
165 #include "cpu/tms9900/tms9995.h"
166 
167 #include "sound/sn76496.h"
168 #include "machine/tms9901.h"
169 #include "machine/tmc0430.h"
170 #include "imagedev/cassette.h"
171 
172 #include "bus/ti99/internal/998board.h"
173 #include "bus/ti99/gromport/gromport.h"
174 #include "bus/hexbus/hexbus.h"
175 
176 #include "bus/ti99/joyport/joyport.h"
177 #include "bus/ti99/internal/ioport.h"
178 
179 #include "softlist.h"
180 #include "speaker.h"
181 
182 // Debugging
183 #define LOG_WARN        (1U<<1)   // Warnings
184 #define LOG_CONFIG      (1U<<2)   // Configuration
185 #define LOG_READY       (1U<<3)
186 #define LOG_INTERRUPTS  (1U<<4)
187 #define LOG_CRU         (1U<<5)
188 #define LOG_CRUREAD     (1U<<6)
189 #define LOG_RESETLOAD   (1U<<7)
190 
191 #define VERBOSE ( LOG_CONFIG | LOG_WARN | LOG_RESETLOAD )
192 
193 #include "logmacro.h"
194 
195 /*
196     READY bits.
197 */
198 enum
199 {
200 	READY_GROM = 1,
201 	READY_MAPPER = 2,
202 	READY_PBOX = 4,
203 	READY_SOUND = 8,
204 	READY_CART = 16,
205 	READY_SPEECH = 32,
206 	READY_MAINBOARD = 64
207 };
208 
209 class ti99_8_state : public driver_device
210 {
211 public:
ti99_8_state(const machine_config & mconfig,device_type type,const char * tag)212 	ti99_8_state(const machine_config &mconfig, device_type type, const char *tag)
213 		: driver_device(mconfig, type, tag),
214 		m_cpu(*this, "maincpu"),
215 		m_tms9901(*this, TI998_TMS9901_TAG),
216 		m_gromport(*this, TI99_GROMPORT_TAG),
217 		m_ioport(*this, TI99_IOPORT_TAG),
218 		m_mainboard(*this, TI998_MAINBOARD_TAG),
219 		m_joyport(*this, TI_JOYPORT_TAG),
220 		m_cassette(*this, "cassette"),
221 		m_keyboard(*this, "COL%u", 0U)
222 	{
223 	}
224 
225 	void ti99_8(machine_config &config);
226 	void ti99_8_60hz(machine_config &config);
227 	void ti99_8_50hz(machine_config &config);
228 
229 	// Lifecycle
230 	void driver_start() override;
231 	void driver_reset() override;
232 
233 private:
234 	// Machine management
235 	DECLARE_MACHINE_START(ti99_8);
236 	DECLARE_MACHINE_RESET(ti99_8);
237 
238 	// Processor connections with the main board
239 	uint8_t cruread(offs_t offset);
240 	void cruwrite(offs_t offset, uint8_t data);
241 	void external_operation(offs_t offset, uint8_t data);
242 	DECLARE_WRITE_LINE_MEMBER( clock_out );
243 
244 	// Connections from outside towards the CPU (callbacks)
245 	DECLARE_WRITE_LINE_MEMBER( console_ready );
246 	DECLARE_WRITE_LINE_MEMBER( console_reset );
247 	DECLARE_WRITE_LINE_MEMBER( cpu_hold );
248 	DECLARE_WRITE_LINE_MEMBER( notconnected );
249 
250 	// GROM clock (coming from Vaquerro)
251 	DECLARE_WRITE_LINE_MEMBER( gromclk_in );
252 
253 	// Connections with the system interface chip 9901
254 	DECLARE_WRITE_LINE_MEMBER( extint );
255 	DECLARE_WRITE_LINE_MEMBER( video_interrupt );
256 
257 	// Connections with the system interface TMS9901
258 	uint8_t psi_input(offs_t offset);
259 	DECLARE_WRITE_LINE_MEMBER(keyC0);
260 	DECLARE_WRITE_LINE_MEMBER(keyC1);
261 	DECLARE_WRITE_LINE_MEMBER(keyC2);
262 	DECLARE_WRITE_LINE_MEMBER(keyC3);
263 	DECLARE_WRITE_LINE_MEMBER(audio_gate);
264 	DECLARE_WRITE_LINE_MEMBER(cassette_output);
265 	DECLARE_WRITE_LINE_MEMBER(cassette_motor);
266 	void tms9901_interrupt(offs_t offset, uint8_t data);
267 
268 	void crumap(address_map &map);
269 	void memmap(address_map &map);
270 	void memmap_setaddress(address_map &map);
271 
272 	// Keyboard support
273 	void    set_keyboard_column(int number, int data);
274 	int     m_keyboard_column;
275 
276 	// READY handling
277 	int m_ready_old;
278 
279 	// Latch for 9901 INT2, INT1 lines
280 	int  m_int1;
281 	int  m_int2;
282 
283 	// Connected devices
284 	required_device<tms9995_device>     m_cpu;
285 	required_device<tms9901_device>     m_tms9901;
286 	required_device<bus::ti99::gromport::gromport_device> m_gromport;
287 	required_device<bus::ti99::internal::ioport_device>     m_ioport;
288 	required_device<bus::ti99::internal::mainboard8_device>  m_mainboard;
289 	required_device<bus::ti99::joyport::joyport_device> m_joyport;
290 	required_device<cassette_image_device> m_cassette;
291 
292 	required_ioport_array<14> m_keyboard;
293 };
294 
295 /*
296     Memory map. We have a configurable mapper, so we need to delegate the
297     job to the mapper completely.
298 */
memmap(address_map & map)299 void ti99_8_state::memmap(address_map &map)
300 {
301 	map(0x0000, 0xffff).rw(TI998_MAINBOARD_TAG, FUNC(bus::ti99::internal::mainboard8_device::read), FUNC(bus::ti99::internal::mainboard8_device::write));
302 }
303 
memmap_setaddress(address_map & map)304 void ti99_8_state::memmap_setaddress(address_map &map)
305 {
306 	map(0x0000, 0xffff).w(TI998_MAINBOARD_TAG, FUNC(bus::ti99::internal::mainboard8_device::setaddress));
307 }
308 
309 /*
310     CRU map - see description above
311     The TMS9901 is fully decoded according to the specification, so we only
312     have 32 bits for it; the rest goes to the CRU bus
313     (decoded by the "Vaquerro" chip, signal NNOICS*)
314 */
315 
crumap(address_map & map)316 void ti99_8_state::crumap(address_map &map)
317 {
318 	map(0x0000, 0x2fff).rw(FUNC(ti99_8_state::cruread), FUNC(ti99_8_state::cruwrite));
319 	map(0x0000, 0x003f).rw(m_tms9901, FUNC(tms9901_device::read), FUNC(tms9901_device::write));
320 }
321 
322 /* ti99/8 : 54-key keyboard */
323 static INPUT_PORTS_START(ti99_8)
324 
325 	/* 16 ports for keyboard and joystick */
326 	PORT_START("COL0")    /* col 0 */
PORT_CODE(KEYCODE_CAPSLOCK)327 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("ALPHA LOCK") PORT_CODE(KEYCODE_CAPSLOCK)
328 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("FCTN") PORT_CODE(KEYCODE_LALT) PORT_CODE(KEYCODE_RALT)
329 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL)
330 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("LSHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
331 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
332 
333 	PORT_START("COL1")    /* col 1 */
334 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("1 ! DEL") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
335 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("q Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
336 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("a A") PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
337 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("z Z") PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
338 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
339 
340 	PORT_START("COL2")    /* col 2 */
341 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("2 @ INS") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
342 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("w W") PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
343 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("s S (LEFT)") PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
344 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("x X (DOWN)") PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
345 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
346 
347 	PORT_START("COL3")    /* col 3 */
348 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("3 #") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
349 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("e E (UP)") PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
350 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("d D (RIGHT)") PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
351 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("c C") PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
352 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
353 
354 	PORT_START("COL4")    /* col 4 */
355 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("4 $ CLEAR") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
356 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("r R") PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
357 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("f F") PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
358 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("v V") PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
359 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
360 
361 	PORT_START("COL5")    /* col 5 */
362 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("5 % BEGIN") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
363 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("t T") PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
364 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("g G") PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
365 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("b B") PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
366 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
367 
368 	PORT_START("COL6")    /* col 6 */
369 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("6 ^ PROC'D") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^')
370 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
371 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
372 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
373 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
374 
375 	PORT_START("COL7")    /* col 7 */
376 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("7 & AID") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')
377 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
378 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
379 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
380 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
381 
382 	PORT_START("COL8")    /* col 8 */
383 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("8 * REDO") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')
384 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
385 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
386 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
387 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
388 
389 	PORT_START("COL9")    /* col 9 */
390 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("9 ( BACK") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
391 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
392 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
393 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
394 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
395 
396 	PORT_START("COL10")    /* col 10 */
397 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
398 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
399 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
400 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
401 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
402 
403 	PORT_START("COL11")    /* col 11 */
404 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("= + QUIT") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+')
405 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
406 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"')
407 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("RSHIFT") PORT_CODE(KEYCODE_RSHIFT)
408 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
409 
410 	PORT_START("COL12")    /* col 12 */
411 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
412 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
413 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("ENTER") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
414 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("(SPACE)") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
415 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
416 
417 	PORT_START("COL13")    /* col 13 */
418 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|')
419 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('`') PORT_CHAR('~')
420 	PORT_BIT(0x07, IP_ACTIVE_LOW, IPT_UNUSED)
421 
422 INPUT_PORTS_END
423 
424 
425 uint8_t ti99_8_state::cruread(offs_t offset)
426 {
427 	LOGMASKED(LOG_CRUREAD, "read access to CRU address %04x\n", offset);
428 	uint8_t value = 0;
429 
430 	// Let the mapper, the gromport, and the p-box decide whether they want
431 	// to change the value at the CRU address
432 	m_mainboard->crureadz(offset<<1, &value);
433 	m_gromport->crureadz(offset<<1, &value);
434 	m_ioport->crureadz(offset<<1, &value);
435 
436 	LOGMASKED(LOG_CRU, "CRU %04x -> %x\n", offset<<1, value);
437 	return value;
438 }
439 
cruwrite(offs_t offset,uint8_t data)440 void ti99_8_state::cruwrite(offs_t offset, uint8_t data)
441 {
442 	LOGMASKED(LOG_CRU, "CRU %04x <- %x\n", offset<<1, data);
443 	m_mainboard->cruwrite(offset<<1, data);
444 	m_gromport->cruwrite(offset<<1, data);
445 	m_ioport->cruwrite(offset<<1, data);
446 }
447 
448 /***************************************************************************
449     TI99/8-specific tms9901 I/O handlers
450     These methods are callbacks from the TMS9901 system interface. That is,
451     they deliver the values queried via the TMS9901, and they represent
452     console functions which are under control of the TMS9901 (like the
453     keyboard column selection.)
454 ***************************************************************************/
455 
psi_input(offs_t offset)456 uint8_t ti99_8_state::psi_input(offs_t offset)
457 {
458 	switch (offset)
459 	{
460 	case tms9901_device::INT1:
461 		return (m_int1==CLEAR_LINE)? 1 : 0;
462 	case tms9901_device::INT2:
463 		return (m_int2==CLEAR_LINE)? 1 : 0;
464 
465 	case tms9901_device::INT6:
466 		if (m_keyboard_column >= 14)
467 			return BIT(m_joyport->read_port(),0);
468 
469 	case tms9901_device::INT7_P15:
470 		if (m_keyboard_column >= 14)
471 			return BIT(m_joyport->read_port(),4);
472 
473 	case tms9901_device::INT8_P14:
474 		if (m_keyboard_column >= 14)
475 			return BIT(m_joyport->read_port(),1);
476 
477 	case tms9901_device::INT9_P13:
478 		if (m_keyboard_column >= 14)
479 			return BIT(m_joyport->read_port(),2);
480 
481 	case tms9901_device::INT10_P12:
482 		if (m_keyboard_column >= 14)
483 			return BIT(m_joyport->read_port(),3);
484 
485 		// return for last 5 cases if column<14
486 		return BIT(m_keyboard[m_keyboard_column]->read(), offset-tms9901_device::INT6);
487 
488 	case tms9901_device::INT11_P11:
489 		return (m_cassette->input() > 0);
490 
491 	default:
492 		return 1;
493 	}
494 }
495 
496 /*
497     WRITE key column select (P2-P4), TI-99/8
498 */
set_keyboard_column(int number,int data)499 void ti99_8_state::set_keyboard_column(int number, int data)
500 {
501 	if (data != 0)
502 		m_keyboard_column |= 1 << number;
503 	else
504 		m_keyboard_column &= ~(1 << number);
505 
506 	if (m_keyboard_column >= 14)
507 	{
508 		m_joyport->write_port(m_keyboard_column - 13);
509 	}
510 }
511 
WRITE_LINE_MEMBER(ti99_8_state::keyC0)512 WRITE_LINE_MEMBER( ti99_8_state::keyC0 )
513 {
514 	set_keyboard_column(0, state);
515 }
516 
WRITE_LINE_MEMBER(ti99_8_state::keyC1)517 WRITE_LINE_MEMBER( ti99_8_state::keyC1 )
518 {
519 	set_keyboard_column(1, state);
520 }
521 
WRITE_LINE_MEMBER(ti99_8_state::keyC2)522 WRITE_LINE_MEMBER( ti99_8_state::keyC2 )
523 {
524 	set_keyboard_column(2, state);
525 }
526 
WRITE_LINE_MEMBER(ti99_8_state::keyC3)527 WRITE_LINE_MEMBER( ti99_8_state::keyC3 )
528 {
529 	set_keyboard_column(3, state);
530 }
531 
532 /*
533     Control cassette tape unit motor (P6)
534 */
WRITE_LINE_MEMBER(ti99_8_state::cassette_motor)535 WRITE_LINE_MEMBER( ti99_8_state::cassette_motor )
536 {
537 	m_cassette->change_state(state==ASSERT_LINE? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED,CASSETTE_MASK_MOTOR);
538 }
539 
540 /*
541     Audio gate (P8)
542     Set to 1 before using tape: this enables the mixing of tape input sound
543     with computer sound.
544     We do not really need to emulate this as the tape recorder generates sound
545     on its own.
546 */
WRITE_LINE_MEMBER(ti99_8_state::audio_gate)547 WRITE_LINE_MEMBER( ti99_8_state::audio_gate )
548 {
549 }
550 
551 /*
552     Tape output (P9)
553     I think polarity is correct, but don't take my word for it.
554 */
WRITE_LINE_MEMBER(ti99_8_state::cassette_output)555 WRITE_LINE_MEMBER( ti99_8_state::cassette_output )
556 {
557 	m_cassette->output(state==ASSERT_LINE? +1 : -1);
558 }
559 
tms9901_interrupt(offs_t offset,uint8_t data)560 void ti99_8_state::tms9901_interrupt(offs_t offset, uint8_t data)
561 {
562 	m_cpu->set_input_line(INT_9995_INT1, data);
563 }
564 
565 /*****************************************************************************/
566 
567 /*
568     set the state of TMS9901's INT2 (called by the VDP)
569 */
WRITE_LINE_MEMBER(ti99_8_state::video_interrupt)570 WRITE_LINE_MEMBER( ti99_8_state::video_interrupt )
571 {
572 	LOGMASKED(LOG_INTERRUPTS, "VDP int 2 on tms9901, level=%02x\n", state);
573 	m_int2 = (line_state)state;
574 	m_tms9901->set_int_line(2, state);
575 }
576 
577 /***********************************************************
578     Links to external devices
579 ***********************************************************/
580 
581 /*
582     Propagate READY signals to the CPU.
583 */
console_ready(int state)584 void ti99_8_state::console_ready(int state)
585 {
586 	if (m_ready_old != state)
587 		LOGMASKED(LOG_READY, "READY = %d\n", state);
588 	m_ready_old = (line_state)state;
589 	m_cpu->ready_line(state);
590 }
591 
592 /*
593     Enqueue a RESET signal.
594 */
WRITE_LINE_MEMBER(ti99_8_state::console_reset)595 WRITE_LINE_MEMBER( ti99_8_state::console_reset )
596 {
597 	LOGMASKED(LOG_RESETLOAD, "Incoming RESET line = %d\n", state);
598 	if (machine().phase() != machine_phase::INIT)
599 	{
600 		// RESET the 9901
601 		m_tms9901->rst1_line(state);
602 
603 		// Pull up the CRUS and PTGEN lines (9901 outputs have been deactivated, pull-up resistors on the board show effect)
604 		m_mainboard->crus_in(true); // assert
605 		m_mainboard->ptgen_in(true); // clear
606 
607 		// Setting ready to false so that automatic wait states are enabled
608 		m_cpu->ready_line(CLEAR_LINE);
609 		m_cpu->reset_line(ASSERT_LINE);
610 
611 		// Send RESET to the IOPort
612 		m_ioport->reset_in(state);
613 	}
614 }
615 
616 /*
617     The HOLD line leading to the CPU entering the HOLD state.
618 */
WRITE_LINE_MEMBER(ti99_8_state::cpu_hold)619 WRITE_LINE_MEMBER( ti99_8_state::cpu_hold )
620 {
621 	LOGMASKED(LOG_INTERRUPTS, "Incoming HOLD line = %d\n", state);
622 	m_cpu->hold_line(state);
623 }
624 
WRITE_LINE_MEMBER(ti99_8_state::extint)625 WRITE_LINE_MEMBER( ti99_8_state::extint )
626 {
627 	LOGMASKED(LOG_INTERRUPTS, "EXTINT level = %02x\n", state);
628 	m_int1 = (line_state)state;
629 	m_tms9901->set_int_line(1, state);
630 }
631 
WRITE_LINE_MEMBER(ti99_8_state::notconnected)632 WRITE_LINE_MEMBER( ti99_8_state::notconnected )
633 {
634 	LOGMASKED(LOG_INTERRUPTS, "Setting a not connected line ... ignored\n");
635 }
636 
external_operation(offs_t offset,uint8_t data)637 void ti99_8_state::external_operation(offs_t offset, uint8_t data)
638 {
639 	static char const *const extop[8] = { "inv1", "inv2", "IDLE", "RSET", "inv3", "CKON", "CKOF", "LREX" };
640 	if (offset == IDLE_OP) return;
641 	else
642 		LOGMASKED(LOG_WARN, "External operation %s not implemented on TI-99/8 board\n", extop[offset]);
643 }
644 
645 /*
646     Clock line from the CPU. Used to control wait state generation.
647 */
WRITE_LINE_MEMBER(ti99_8_state::clock_out)648 WRITE_LINE_MEMBER( ti99_8_state::clock_out )
649 {
650 	m_tms9901->phi_line(state);
651 	m_mainboard->clock_in(state);
652 }
653 
driver_start()654 void ti99_8_state::driver_start()
655 {
656 	// Need to configure the speech ROM for inverse bit order
657 //  speechrom_device* mem = subdevice<speechrom_device>(TI998_SPEECHROM_REG);
658 //  mem->set_reverse_bit_order(true);
659 
660 	save_item(NAME(m_keyboard_column));
661 	save_item(NAME(m_ready_old));
662 	save_item(NAME(m_int1));
663 	save_item(NAME(m_int2));
664 }
665 
driver_reset()666 void ti99_8_state::driver_reset()
667 {
668 	m_cpu->hold_line(CLEAR_LINE);
669 
670 	// Pulling down the line on RESET configures the CPU to insert one wait
671 	// state on external memory accesses
672 	//  m_cpu->ready_line(ASSERT_LINE);
673 
674 	// m_gromport->set_grom_base(0x9800, 0xfff1);
675 
676 	// Clear INT1 and INT2 latch
677 	m_int1 = CLEAR_LINE;
678 	m_int2 = CLEAR_LINE;
679 	console_reset(ASSERT_LINE);
680 	console_reset(CLEAR_LINE);
681 }
682 
ti99_8(machine_config & config)683 void ti99_8_state::ti99_8(machine_config& config)
684 {
685 	using namespace bus::ti99::internal;
686 	// basic machine hardware */
687 	// TMS9995-MP9537 CPU @ 10.7 MHz
688 	// MP9537 mask: This variant of the TMS9995 does not contain on-chip RAM
689 	TMS9995_MP9537(config, m_cpu, XTAL(10'738'635));
690 	m_cpu->set_addrmap(AS_PROGRAM, &ti99_8_state::memmap);
691 	m_cpu->set_addrmap(AS_IO, &ti99_8_state::crumap);
692 	m_cpu->set_addrmap(tms9995_device::AS_SETADDRESS, &ti99_8_state::memmap_setaddress);
693 	m_cpu->extop_cb().set(FUNC(ti99_8_state::external_operation));
694 	m_cpu->clkout_cb().set(FUNC(ti99_8_state::clock_out));
695 	m_cpu->holda_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::holda_line));
696 
697 	// 9901 configuration
698 	TMS9901(config, m_tms9901, 0);
699 	m_tms9901->read_cb().set(FUNC(ti99_8_state::psi_input));
700 	m_tms9901->p_out_cb(0).set(FUNC(ti99_8_state::keyC0));
701 	m_tms9901->p_out_cb(1).set(FUNC(ti99_8_state::keyC1));
702 	m_tms9901->p_out_cb(2).set(FUNC(ti99_8_state::keyC2));
703 	m_tms9901->p_out_cb(3).set(FUNC(ti99_8_state::keyC3));
704 	m_tms9901->p_out_cb(4).set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::crus_in));
705 	m_tms9901->p_out_cb(5).set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::ptgen_in));
706 	m_tms9901->p_out_cb(6).set(FUNC(ti99_8_state::cassette_motor));
707 	m_tms9901->p_out_cb(8).set(FUNC(ti99_8_state::audio_gate));
708 	m_tms9901->p_out_cb(9).set(FUNC(ti99_8_state::cassette_output));
709 	m_tms9901->intreq_cb().set(FUNC(ti99_8_state::tms9901_interrupt));
710 
711 	// Mainboard with custom chips
712 	TI99_MAINBOARD8(config, m_mainboard, 0);
713 	m_mainboard->ready_cb().set(FUNC(ti99_8_state::console_ready));
714 	m_mainboard->reset_cb().set(FUNC(ti99_8_state::console_reset));
715 	m_mainboard->hold_cb().set(FUNC(ti99_8_state::cpu_hold));
716 
717 	// Cartridge port
718 	TI99_GROMPORT(config, m_gromport, 0, ti99_gromport_options_998, "single").extend();
719 	m_gromport->ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::system_grom_ready));
720 	m_gromport->reset_cb().set(FUNC(ti99_8_state::console_reset));
721 
722 	// RAM
723 	RAM(config, TI998_SRAM_TAG).set_default_size("2K").set_default_value(0);
724 	RAM(config, TI998_DRAM_TAG).set_default_size("64K").set_default_value(0);
725 
726 	// Software list
727 	SOFTWARE_LIST(config, "cart_list_ti99").set_original("ti99_cart");
728 
729 	// I/O port
730 	TI99_IOPORT(config, m_ioport, 0, ti99_ioport_options_plain, nullptr);
731 	m_ioport->extint_cb().set(FUNC(ti99_8_state::extint));
732 	m_ioport->ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::pbox_ready));
733 
734 	// Hexbus
735 	HEXBUS(config, TI998_HEXBUS_TAG, 0, hexbus_options, nullptr);
736 
737 	// Sound hardware
738 	SPEAKER(config, "sound_out").front_center();
739 	sn76496_device& soundgen(SN76496(config, TI998_SOUNDCHIP_TAG, 3579545));
740 	soundgen.ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::sound_ready));
741 	soundgen.add_route(ALL_OUTPUTS, "sound_out", 0.75);
742 
743 	// Speech hardware
744 	// Note: SPEECHROM uses its tag for referencing the region
745 	SPEECHROM(config, TI998_SPEECHROM_REG, 0).set_reverse_bit_order(true);
746 	SPEAKER(config, "speech_out").front_center();
747 
748 	cd2501ecd_device& vsp(CD2501ECD(config, TI998_SPEECHSYN_TAG, 640000L));
749 	vsp.ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::speech_ready));
750 	vsp.set_speechrom_tag(TI998_SPEECHROM_REG);
751 	vsp.add_route(ALL_OUTPUTS, "speech_out", 0.50);
752 
753 	// Cassette drive
754 	SPEAKER(config, "cass_out").front_center();
755 	CASSETTE(config, "cassette", 0).add_route(ALL_OUTPUTS, "cass_out", 0.25);
756 
757 	// GROM library
758 	using namespace bus::ti99::internal;
759 	TMC0430(config, TI998_SYSGROM0_TAG, TI998_SYSGROM_REG, 0x0000, 0).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::system_grom_ready));
760 	TMC0430(config, TI998_SYSGROM1_TAG, TI998_SYSGROM_REG, 0x2000, 1).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::system_grom_ready));
761 	TMC0430(config, TI998_SYSGROM2_TAG, TI998_SYSGROM_REG, 0x4000, 2).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::system_grom_ready));
762 
763 	TMC0430(config, TI998_GLIB10_TAG, TI998_GROMLIB1_REG, 0x0000, 0).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::ptts_grom_ready));
764 	TMC0430(config, TI998_GLIB11_TAG, TI998_GROMLIB1_REG, 0x2000, 1).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::ptts_grom_ready));
765 	TMC0430(config, TI998_GLIB12_TAG, TI998_GROMLIB1_REG, 0x4000, 2).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::ptts_grom_ready));
766 	TMC0430(config, TI998_GLIB13_TAG, TI998_GROMLIB1_REG, 0x6000, 3).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::ptts_grom_ready));
767 	TMC0430(config, TI998_GLIB14_TAG, TI998_GROMLIB1_REG, 0x8000, 4).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::ptts_grom_ready));
768 	TMC0430(config, TI998_GLIB15_TAG, TI998_GROMLIB1_REG, 0xa000, 5).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::ptts_grom_ready));
769 	TMC0430(config, TI998_GLIB16_TAG, TI998_GROMLIB1_REG, 0xc000, 6).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::ptts_grom_ready));
770 	TMC0430(config, TI998_GLIB17_TAG, TI998_GROMLIB1_REG, 0xe000, 7).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::ptts_grom_ready));
771 
772 	TMC0430(config, TI998_GLIB20_TAG, TI998_GROMLIB2_REG, 0x0000, 0).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::p8_grom_ready));
773 	TMC0430(config, TI998_GLIB21_TAG, TI998_GROMLIB2_REG, 0x2000, 1).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::p8_grom_ready));
774 	TMC0430(config, TI998_GLIB22_TAG, TI998_GROMLIB2_REG, 0x4000, 2).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::p8_grom_ready));
775 	TMC0430(config, TI998_GLIB23_TAG, TI998_GROMLIB2_REG, 0x6000, 3).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::p8_grom_ready));
776 	TMC0430(config, TI998_GLIB24_TAG, TI998_GROMLIB2_REG, 0x8000, 4).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::p8_grom_ready));
777 	TMC0430(config, TI998_GLIB25_TAG, TI998_GROMLIB2_REG, 0xa000, 5).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::p8_grom_ready));
778 	TMC0430(config, TI998_GLIB26_TAG, TI998_GROMLIB2_REG, 0xc000, 6).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::p8_grom_ready));
779 	TMC0430(config, TI998_GLIB27_TAG, TI998_GROMLIB2_REG, 0xe000, 7).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::p8_grom_ready));
780 
781 	TMC0430(config, TI998_GLIB30_TAG, TI998_GROMLIB3_REG, 0x0000, 0).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::p3_grom_ready));
782 	TMC0430(config, TI998_GLIB31_TAG, TI998_GROMLIB3_REG, 0x2000, 1).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::p3_grom_ready));
783 	TMC0430(config, TI998_GLIB32_TAG, TI998_GROMLIB3_REG, 0x4000, 2).ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::p3_grom_ready));
784 
785 	// Joystick port
786 	TI99_JOYPORT(config, m_joyport, 0, ti99_joyport_options_mouse, "twinjoy");
787 }
788 
789 /*
790     TI-99/8 US version (NTSC, 60 Hz)
791 */
ti99_8_60hz(machine_config & config)792 void ti99_8_state::ti99_8_60hz(machine_config &config)
793 {
794 	ti99_8(config);
795 	// Video hardware
796 	tms9118_device &video(TMS9118(config, TI998_VDP_TAG, XTAL(10'738'635)));
797 	video.set_vram_size(0x4000);
798 	video.int_callback().set(FUNC(ti99_8_state::video_interrupt));
799 	video.set_screen("screen");
800 
801 	SCREEN(config, "screen", SCREEN_TYPE_RASTER);
802 }
803 
804 /*
805     TI-99/8 European version (PAL, 50 Hz)
806 */
ti99_8_50hz(machine_config & config)807 void ti99_8_state::ti99_8_50hz(machine_config &config)
808 {
809 	ti99_8(config);
810 	// Video hardware
811 	tms9129_device &video(TMS9129(config, TI998_VDP_TAG, XTAL(10'738'635)));
812 	video.set_vram_size(0x4000);
813 	video.int_callback().set(FUNC(ti99_8_state::video_interrupt));
814 	video.set_screen("screen");
815 
816 	SCREEN(config, "screen", SCREEN_TYPE_RASTER);
817 }
818 
819 /*
820     All ROM dumps except the speech ROM have a CRC16 checksum as the final two
821     bytes. ROM1 contains four 8K chunks of ROM contents with an own CRC at their
822     ends. All GROMs, ROM0, and the four ROM1 parts were successfully
823     validated.
824 */
825 ROM_START(ti99_8)
826 	// Logical (CPU) memory space: ROM0
827 	ROM_REGION(0x2000, TI998_ROM0_REG, 0)
828 	ROM_LOAD("rom0.u4", 0x0000, 0x2000, CRC(901eb8d6) SHA1(13190c5e834baa9c0a70066b566cfcef438ed88a))
829 
830 	// Physical memory space (mapped): ROM1
831 	ROM_REGION(0x8000, TI998_ROM1_REG, 0)
832 	ROM_LOAD("rom1.u25", 0x0000, 0x8000, CRC(b574461a) SHA1(42c6aed44802cfabdd26b565d6e5ddfcd689f11e))
833 
834 	// Physical memory space (mapped): P-Code ROM
835 	// This circuit is only available in later versions of the console and seems
836 	// to be piggy-backed on ROM1.
837 	// To make things worse, the decoding logic of the custom chips do not show
838 	// the required select line for this ROM on the available schematics, so
839 	// they seem to be from the earlier version. The location in the address
840 	// space was determined by ROM disassembly.
841 	ROM_REGION(0x8000, TI998_PASCAL_REG, 0)
842 	ROM_LOAD("pascal.u25a", 0x0000, 0x4000, CRC(d7ed6dd6) SHA1(32212ce6426ceccbff73d342d4a3ef699c0ae1e4))
843 
844 	// System GROMs. 3 chips @ f830
845 	// The schematics do not enumerate the circuits but only say
846 	// "circuits on board" (COB) so we name the GROMs as gM_N.bin where M is the
847 	// ID (0-7) and N is the access port in the logical address space.
848 	ROM_REGION(0x6000, TI998_SYSGROM_REG, 0)
849 	ROM_LOAD("g0_f830.bin", 0x0000, 0x1800, CRC(1026db60) SHA1(7327095bf4f390476e69d9fd8424e98ea1f2325a))
850 	ROM_LOAD("g1_f830.bin", 0x2000, 0x1800, CRC(93a43d65) SHA1(19be8a07d674bc7554c2bc9c7a5725d81e888e6e))
851 	ROM_LOAD("g2_f830.bin", 0x4000, 0x1800, CRC(06f2b901) SHA1(f65e0fcb2c63e230b4a9563c72f91259b94ce955))
852 
853 	// TTS & Pascal library. 8 chips @ f840
854 	ROM_REGION(0x10000, TI998_GROMLIB1_REG, 0)
855 	ROM_LOAD("g0_f840.bin", 0x0000, 0x1800, CRC(44501071) SHA1(4b5ef7f1aa43a87e7ae4f02090944be5c39b1f26))
856 	ROM_LOAD("g1_f840.bin", 0x2000, 0x1800, CRC(5a271d9e) SHA1(bb95befa2ffba2cc17ac437386e069e8ff621248))
857 	ROM_LOAD("g2_f840.bin", 0x4000, 0x1800, CRC(d52502df) SHA1(17063e33ee8709d0df8030f38bb92c4322d55e1e))
858 	ROM_LOAD("g3_f840.bin", 0x6000, 0x1800, CRC(86c12396) SHA1(119b6df9211b5399245e017721fc51b88b60879f))
859 	ROM_LOAD("g4_f840.bin", 0x8000, 0x1800, CRC(f17a2ef8) SHA1(dcb044f71d7f8a165b41f39e35a368d8f2d63b67))
860 	ROM_LOAD("g5_f840.bin", 0xA000, 0x1800, CRC(7dc41301) SHA1(dff714da68de352db93fba309db8e5a8ae7cab1a))
861 	ROM_LOAD("g6_f840.bin", 0xC000, 0x1800, CRC(7e310a90) SHA1(e927d8b3f8b32aa4fb9f7d080d5262c566a77fc7))
862 	ROM_LOAD("g7_f840.bin", 0xE000, 0x1800, CRC(3a9d20df) SHA1(1e6f9f8ec7df4b997a7579be742d0a7d54bc8763))
863 
864 	// Pascal library. 8 chips @ f850
865 	ROM_REGION(0x10000, TI998_GROMLIB2_REG, 0)
866 	ROM_LOAD("g0_f850.bin", 0x0000, 0x1800, CRC(2d948672) SHA1(cf15912d6dae5a450e0cfd796aa36ea5e521dc56))
867 	ROM_LOAD("g1_f850.bin", 0x2000, 0x1800, CRC(7d64a842) SHA1(d5884bb2af21c8027311478ee506beac6f46203d))
868 	ROM_LOAD("g2_f850.bin", 0x4000, 0x1800, CRC(e5ed8900) SHA1(03826882ce10fb5a6b3a9ccc85d3d1fe51979d0b))
869 	ROM_LOAD("g3_f850.bin", 0x6000, 0x1800, CRC(87aaf19e) SHA1(fdbe163773b8a30fa6b9508e679be6fa4f99bf7a))
870 	ROM_LOAD("g4_f850.bin", 0x8000, 0x1800, CRC(d3e789a5) SHA1(5ab06aa75ca694b1035ce5ac0bebacc928721388))
871 	ROM_LOAD("g5_f850.bin", 0xA000, 0x1800, CRC(49fd90bd) SHA1(44b2cef29c2d5304a0dcfedbdcdf9f21f2201bf9))
872 	ROM_LOAD("g6_f850.bin", 0xC000, 0x1800, CRC(31bac4ab) SHA1(e29049f0597d5de0bfd5c9c7bfea902abe858010))
873 	ROM_LOAD("g7_f850.bin", 0xE000, 0x1800, CRC(71534098) SHA1(75e87123efde885e27dd749e07cb189eb2cc45a8))
874 
875 	// Pascal library. 3 chips @ f860
876 	ROM_REGION(0x6000, TI998_GROMLIB3_REG, 0)
877 	ROM_LOAD("g0_f860.bin", 0x0000, 0x1800, CRC(0ceef210) SHA1(b89957fbff094b758746391a69dea6907c66b950))
878 	ROM_LOAD("g1_f860.bin", 0x2000, 0x1800, CRC(fc87de25) SHA1(4695b7f979f59a01ec16c55e4587c3379482b658))
879 	ROM_LOAD("g2_f860.bin", 0x4000, 0x1800, CRC(e833e350) SHA1(6ffe501981a1112be1af596a489d96e287fc6be5))
880 
881 	// Speech ROM
882 	ROM_REGION(0x8000, TI998_SPEECHROM_REG, 0)
883 	ROM_LOAD("cd2325a.vsm", 0x0000, 0x4000, CRC(1f58b571) SHA1(0ef4f178716b575a1c0c970c56af8a8d97561ffe))
884 	ROM_LOAD("cd2326a.vsm", 0x4000, 0x4000, CRC(65d00401) SHA1(a367242c2c96cebf0e2bf21862f3f6734b2b3020))
885 ROM_END
886 
887 #define rom_ti99_8e rom_ti99_8
888 
889 //    YEAR  NAME     PARENT  COMPAT  MACHINE      INPUT   CLASS         INIT        COMPANY              FULLNAME                     FLAGS
890 COMP( 1983, ti99_8,  0,      0,      ti99_8_60hz, ti99_8, ti99_8_state, empty_init, "Texas Instruments", "TI-99/8 Computer (US)",     MACHINE_SUPPORTS_SAVE )
891 COMP( 1983, ti99_8e, ti99_8, 0,      ti99_8_50hz, ti99_8, ti99_8_state, empty_init, "Texas Instruments", "TI-99/8 Computer (Europe)", MACHINE_SUPPORTS_SAVE )
892