1 // license:LGPL-2.1+
2 // copyright-holders:Michael Zapf
3 /***************************************************************************
4
5 TI-99/8 main board logic
6
7 This component implements the address decoder and mapper logic from the
8 TI-99/8 console.
9
10 The TI-99/8 defines a "logical address map" with 64 KiB (according to the
11 16 address bits) and a "physical address map" with 16 MiB (according to the
12 24 address bits of the mapper). Note that the mapper only uses 16 outgoing
13 address lines and multiplexes the address bytes.
14
15 Note: The TI-99/8's internal codename was "Armadillo"
16
17
18 +-------+ +--------+
19 | CPU |========LogAddrBus======| Mapper |====PhysAddrBus==========
20 | TMS | || | AMIGO | ||
21 | 9995 | +----------+ | | +----------+
22 | | | Logical | +--------+ | Physical |
23 +-------+ | space | | | space |
24 | decoder | | | decoder |
25 | VAQUERRO | | | MOFETTA |
26 +----------+ | +----------+
27 | | |
28 +--------------------+ | +---------------------+
29 | Devices | | | Devices |
30 | +-------+ | | |
31 | ROM0 | SRAM | | | DRAM (POLLO) |
32 | Video | ---- | | | ROM1 |
33 | Speech | Maps--+--+ | Cartridge port |
34 | GROM +-------+ | PEB |
35 | Sound | | Hexbus (OSO) |
36 +--------------------+ +---------------------+
37
38 Custom chips
39 ------------
40 The chipset of the TI-99/8 consists of five specifically programmed chips.
41 All are nicknamed after some Spanish words (albeit sometimes misspelled)
42
43 VAQUERRO: Logical Address Space decoder ("Vaquero" = "Cowboy")
44 MOFETTA : Physical Address Space decoder ("Mofeta" = "Skunk")
45 AMIGO : Mapper ("Amigo" = "Friend")
46 OSO : Hexbus adapter ("Oso" = "Bear")
47 POLLO : DRAM controller (Not emulated) ("Pollo" = "Chicken")
48
49 See the comments for the respective chip implementation for details.
50
51
52 ROM contents
53 ------------
54 The ROM0 chip is accessible at addresses 0000-1FFF in the logical address
55 space of the compatibility mode. It contains the GPL interpreter. In
56 native mode the ROM0 chip is invisible.
57
58 ROM0
59 offset Logical address Name
60 -----------------------------------
61 0000 0000-1FFF ROM0
62
63
64 The ROM1 chip contains 32 KiB of various system software. It is located in
65 the physical address space, so it must be mapped into the logical address
66 space by defining an appropriate map.
67
68 ROM1
69 offset Physical address Name
70 ----------------------------------------------------------
71 0000 FFA000-FFDFFF ROM1
72 4000 FF4000-FF5FFF @CRU>2700 Text-to-speech ROM/DSR
73 6000 FF4000-FF5FFF @CRU>1700 Hexbus DSR
74
75 The DSR portions have to be selected via the CRU bits >1700 or >2700.
76
77
78 CRU map (I/O address space)
79 ===========================
80 0000-003e: TMS9901 system interface (see ti99_8.c)
81 1700-17fe: Hexbus
82 2000-26fe: Future external devices
83 2700-27fe: Additional ROM ("internal DSR")
84 2702 : System reset (when set to 1)
85 2800-3ffe: Future external devices
86 4000-fffe: Future external devices
87
88 The TMS9995 offers the full 15-bit CRU address space. Devices designed for
89 the TI-99/4A should only be accessed in the area 1000-1ffe. They will (by
90 design) incompletely decode the CRU address and be mirrored in the higher
91 areas.
92
93 Note that the cartridge port of the TI-99/8 offers support for 16K ROM
94 cartridges, but lacks CRU support.
95
96 Michael Zapf, October 2010
97 February 2012: Rewritten as class
98 March 2016: Redesigned for custom chip emulation
99
100 Informations taken from
101 [1] ARMADILLO PRODUCT SPECIFICATIONS
102 [2] TI-99/8 Graphics Programming Language interpreter
103
104 ***************************************************************************/
105
106 #include "emu.h"
107 #include "998board.h"
108 #include "cpu/tms9900/tms99com.h"
109
110 #define LOG_DETAIL (1U<<1) // More detail
111 #define LOG_CRU (1U<<2) // CRU logging
112 #define LOG_ADDRESS (1U<<3) // Address bus
113 #define LOG_MEM (1U<<4) // Memory access
114 #define LOG_MAP (1U<<5) // Mapper
115 #define LOG_READY (1U<<6) // READY line
116 #define LOG_CLOCK (1U<<7) // CLKOUT
117 #define LOG_MOFETTA (1U<<8) // Mofetta operation
118 #define LOG_AMIGO (1U<<9) // Amigo operation
119 #define LOG_OSO (1U<<10) // Oso operation
120 #define LOG_HEXBUS (1U<<11) // Hexbus operation
121 #define LOG_WS (1U<<12) // Wait states
122 #define LOG_CPURY (1U<<13) // Combined ready line
123 #define LOG_GROM (1U<<14) // GROM operation
124 #define LOG_PUNMAP (1U<<15) // Unmapped physical addresss
125 #define LOG_WARN (1U<<31) // Warnings
126
127 #define VERBOSE ( LOG_WARN )
128
129 #include "logmacro.h"
130
131 DEFINE_DEVICE_TYPE_NS(TI99_MAINBOARD8, bus::ti99::internal, mainboard8_device, "ti998_mainboard", "TI-99/8 Mainboard")
132 DEFINE_DEVICE_TYPE_NS(TI99_VAQUERRO, bus::ti99::internal, vaquerro_device, "ti998_vaquerro", "TI-99/8 Logical Address Space Decoder")
133 DEFINE_DEVICE_TYPE_NS(TI99_MOFETTA, bus::ti99::internal, mofetta_device, "ti998_mofetta", "TI-99/8 Physical Address Space Decoder")
134 DEFINE_DEVICE_TYPE_NS(TI99_OSO, bus::ti99::internal, oso_device, "ti998_oso", "TI-99/8 Hexbus interface")
135 DEFINE_DEVICE_TYPE_NS(TI99_AMIGO, bus::ti99::internal, amigo_device, "ti998_amigo", "TI-99/8 Address space mapper")
136
137 namespace bus { namespace ti99 { namespace internal {
138
139 enum
140 {
141 SGMSEL = 1,
142 TSGSEL = 2,
143 P8GSEL = 4,
144 P3GSEL = 8,
145 VIDSEL = 16
146 };
147
mainboard8_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)148 mainboard8_device::mainboard8_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
149 : device_t(mconfig, TI99_MAINBOARD8, tag, owner, clock),
150 m_A14_set(false),
151 m_pending_write(false),
152 m_speech_ready(true),
153 m_sound_ready(true),
154 m_pbox_ready(true),
155 m_ready(*this),
156 m_console_reset(*this),
157 m_hold_line(*this),
158 m_vaquerro(*this, TI998_VAQUERRO_TAG),
159 m_mofetta(*this, TI998_MOFETTA_TAG),
160 m_amigo(*this, TI998_AMIGO_TAG),
161 m_oso(*this, TI998_OSO_TAG),
162 m_maincpu(*owner, "maincpu"),
163 m_video(*owner, TI998_VDP_TAG),
164 m_sound(*owner, TI998_SOUNDCHIP_TAG),
165 m_speech(*owner, TI998_SPEECHSYN_TAG),
166 m_gromport(*owner, TI99_GROMPORT_TAG),
167 m_ioport(*owner, TI99_IOPORT_TAG),
168 m_sram(*owner, TI998_SRAM_TAG),
169 m_dram(*owner, TI998_DRAM_TAG),
170 m_sgrom0(*owner, TI998_SYSGROM0_TAG),
171 m_sgrom1(*owner, TI998_SYSGROM1_TAG),
172 m_sgrom2(*owner, TI998_SYSGROM2_TAG),
173 m_tsgrom0(*owner, TI998_GLIB10_TAG),
174 m_tsgrom1(*owner, TI998_GLIB11_TAG),
175 m_tsgrom2(*owner, TI998_GLIB12_TAG),
176 m_tsgrom3(*owner, TI998_GLIB13_TAG),
177 m_tsgrom4(*owner, TI998_GLIB14_TAG),
178 m_tsgrom5(*owner, TI998_GLIB15_TAG),
179 m_tsgrom6(*owner, TI998_GLIB16_TAG),
180 m_tsgrom7(*owner, TI998_GLIB17_TAG),
181 m_p8grom0(*owner, TI998_GLIB20_TAG),
182 m_p8grom1(*owner, TI998_GLIB21_TAG),
183 m_p8grom2(*owner, TI998_GLIB22_TAG),
184 m_p8grom3(*owner, TI998_GLIB23_TAG),
185 m_p8grom4(*owner, TI998_GLIB24_TAG),
186 m_p8grom5(*owner, TI998_GLIB25_TAG),
187 m_p8grom6(*owner, TI998_GLIB26_TAG),
188 m_p8grom7(*owner, TI998_GLIB27_TAG),
189 m_p3grom0(*owner, TI998_GLIB30_TAG),
190 m_p3grom1(*owner, TI998_GLIB31_TAG),
191 m_p3grom2(*owner, TI998_GLIB32_TAG),
192 m_sgrom_idle(true),
193 m_tsgrom_idle(true),
194 m_p8grom_idle(true),
195 m_p3grom_idle(true)
196 {
197 }
198
199 // Debugger support
200 // The memory accesses by the debugger are routed around the custom chip logic
201
debugger_read(offs_t offset)202 uint8_t mainboard8_device::debugger_read(offs_t offset)
203 {
204 int logical_address = offset;
205 bool compat_mode = (m_crus_debug==ASSERT_LINE);
206
207 // Check whether the mapper itself is accessed
208 int mapaddr = compat_mode? 0x8810 : 0xf870;
209 bool mapper_accessed = ((offset & 0xfff1)==mapaddr);
210
211 if (mapper_accessed) return 0; // do not allow the debugger to mess with the mapper
212
213 // or SRAM
214 int sramaddr = compat_mode? 0x8000 : 0xf000;
215
216 if ((offset & 0xf800)==sramaddr)
217 {
218 // SRAM access
219 return m_sram->pointer()[logical_address & 0x07ff];
220 }
221 if ((offset & 0xe000)==0x0000 && compat_mode)
222 {
223 // ROM0 access
224 return m_rom0[logical_address & 0x1fff];
225 }
226
227 // Physical space
228 u8 value = 0;
229 int physical_address = m_amigo->get_physical_address_debug(offset);
230
231 if ((physical_address & 0x00ff0000)==0x00000000)
232 {
233 // DRAM
234 return m_dram->pointer()[physical_address & 0xffff];
235 }
236 if ((physical_address & 0x00ffc000)==0x00f00000)
237 {
238 // Pascal ROM 16K
239 return m_pascalrom[physical_address & 0x3fff];
240 }
241 if ((physical_address & 0x00ffe000)==0x00ff4000)
242 {
243 // Internal DSR, Hexbus DSR, or PEB
244 if (m_mofetta->hexbus_access_debug()) return m_rom1[(physical_address & 0x1fff) | 0x6000];
245 if (m_mofetta->intdsr_access_debug()) return m_rom1[(physical_address & 0x1fff) | 0x4000];
246 m_ioport->memen_in(ASSERT_LINE);
247 m_ioport->readz(physical_address & 0xffff, &value);
248 m_ioport->memen_in(CLEAR_LINE);
249 return value;
250 }
251 if ((physical_address & 0x00ffe000)==0x00ff6000)
252 {
253 // Cartridge space lower 8
254 m_gromport->romgq_line(ASSERT_LINE);
255 m_gromport->readz(physical_address & 0x1fff, &value);
256 m_gromport->romgq_line(CLEAR_LINE);
257 return value;
258 }
259 if ((physical_address & 0x00ffe000)==0x00ff8000)
260 {
261 // Cartridge space upper 8
262 m_gromport->romgq_line(ASSERT_LINE);
263 m_gromport->readz((physical_address & 0x1fff) | 0x2000, &value);
264 m_gromport->romgq_line(CLEAR_LINE);
265 return value;
266 }
267 if ((physical_address & 0x00ffe000)==0x00ffa000)
268 {
269 // ROM1 lower 8
270 return m_rom1[(physical_address & 0x1fff) | 0x0000];
271 }
272 if ((physical_address & 0x00ffe000)==0x00ffc000)
273 {
274 // ROM1 upper 8
275 return m_rom1[(physical_address & 0x1fff) | 0x2000];
276 }
277 return 0;
278 }
279
debugger_write(offs_t offset,uint8_t data)280 void mainboard8_device::debugger_write(offs_t offset, uint8_t data)
281 {
282 int logical_address = offset;
283 bool compat_mode = (m_crus_debug==ASSERT_LINE);
284
285 // Check whether the mapper itself is accessed
286 int mapaddr = compat_mode? 0x8810 : 0xf870;
287 bool mapper_accessed = ((offset & 0xfff1)==mapaddr);
288
289 if (mapper_accessed)
290 {
291 // Allow for loading/saving mapper registers
292 m_amigo->mapper_access_debug(data);
293 return;
294 }
295
296 // SRAM
297 int sramaddr = compat_mode? 0x8000 : 0xf000;
298
299 if ((offset & 0xf800)==sramaddr)
300 {
301 // SRAM access
302 m_sram->pointer()[logical_address & 0x07ff] = data & 0xff;
303 return;
304 }
305
306 // ROM0 (no write access)
307 if ((offset & 0xe000)==0x0000 && compat_mode) return;
308
309 // Physical space
310 int physical_address = m_amigo->get_physical_address_debug(offset);
311
312 if ((physical_address & 0x00ff0000)==0x00000000)
313 {
314 // DRAM
315 m_dram->pointer()[physical_address & 0xffff] = data & 0xff;
316 return;
317 }
318
319 // Pascal ROM (no write)
320 if ((physical_address & 0x00ffc000)==0x00f00000) return;
321
322 // Internal DSR, Hexbus DSR, or PEB
323 if ((physical_address & 0x00ffe000)==0x00ff4000)
324 {
325 if (m_mofetta->hexbus_access_debug()) return;
326 if (m_mofetta->intdsr_access_debug()) return;
327 m_ioport->memen_in(ASSERT_LINE);
328 m_ioport->write(physical_address & 0xffff, data & 0xff);
329 m_ioport->memen_in(CLEAR_LINE); return;
330 }
331 if ((physical_address & 0x00ffe000)==0x00ff6000)
332 {
333 // Cartridge space lower 8
334 m_gromport->romgq_line(ASSERT_LINE);
335 m_gromport->write(physical_address & 0x1fff, data & 0xff);
336 m_gromport->romgq_line(CLEAR_LINE);
337 return;
338 }
339 if ((physical_address & 0x00ffe000)==0x00ff8000)
340 {
341 // Cartridge space upper 8
342 m_gromport->romgq_line(ASSERT_LINE);
343 m_gromport->write((physical_address & 0x1fff) | 0x2000, data & 0xff);
344 m_gromport->romgq_line(CLEAR_LINE);
345 return;
346 }
347
348 // ROM1 not writable
349 if ((physical_address & 0x00ffe000)==0x00ffa000 || (physical_address & 0x00ffe000)==0x00ffc000) return;
350 }
351
352 // =============== CRU bus access ==================
353
crureadz(offs_t offset,uint8_t * value)354 void mainboard8_device::crureadz(offs_t offset, uint8_t *value)
355 {
356 m_ioport->crureadz(offset, value);
357 }
358
359 /*
360 CRU handling. Mofetta is the only chip that bothers to handle it, beside the PEB
361 */
cruwrite(offs_t offset,uint8_t data)362 void mainboard8_device::cruwrite(offs_t offset, uint8_t data)
363 {
364 m_mofetta->cruwrite(offset, data);
365 m_ioport->cruwrite(offset, data);
366 }
367
368 // =============== Memory bus access ==================
369
setaddress(offs_t offset,uint8_t busctrl)370 void mainboard8_device::setaddress(offs_t offset, uint8_t busctrl)
371 {
372 m_dbin_level = ((busctrl & TMS99xx_BUS_DBIN)!=0);
373 LOGMASKED(LOG_ADDRESS, "set %s %04x\n", (m_dbin_level==ASSERT_LINE)? "R" : "W", offset);
374
375 // No data is waiting on the data bus
376 m_pending_write = false;
377
378 // Memory cycle begins
379 m_vaquerro->memen_in(ASSERT_LINE);
380 m_amigo->memen_in(ASSERT_LINE);
381
382 // Save the logical address
383 m_logical_address = offset;
384 m_physical_address = 0;
385
386 // In TI's bit order, A14 is the second line from the right side (2^1)
387 m_A14_set = ((m_logical_address & 2)!=0); // Needed for clock_in
388
389 // Check for match in logical space
390 m_vaquerro->set_address(m_logical_address, m_dbin_level);
391
392 // Select GROMs if addressed
393 select_groms();
394
395 // Speech select lines will always be asserted/cleared as soon as the address is available
396 m_speech->wsq_w((m_vaquerro->spwt_out() == ASSERT_LINE)? false : true);
397 m_speech->rsq_w((m_vaquerro->sprd_out() == ASSERT_LINE)? false : true);
398
399 // If it is a logical space address, tell the mapper to stay inactive
400 line_state lasreq = (line_state)m_vaquerro->lascsq_out();
401 m_amigo->lascs_in(lasreq);
402 m_mofetta->lascs_in(lasreq);
403
404 // Need to set the address in any case so that the lines can be cleared
405 m_amigo->set_address(m_logical_address);
406
407 // AMIGO is the one to control the READY line to the CPU
408 // MOFETTA does not contribute to READY
409 m_ready(m_amigo->cpury_out());
410 }
411
WRITE_LINE_MEMBER(mainboard8_device::reset_console)412 WRITE_LINE_MEMBER( mainboard8_device::reset_console )
413 {
414 m_console_reset(state);
415 }
416
WRITE_LINE_MEMBER(mainboard8_device::hold_cpu)417 WRITE_LINE_MEMBER( mainboard8_device::hold_cpu )
418 {
419 m_hold_line(state);
420 }
421
422 /*
423 HOLD Acknowledge from the CPU
424 */
WRITE_LINE_MEMBER(mainboard8_device::holda_line)425 WRITE_LINE_MEMBER( mainboard8_device::holda_line )
426 {
427 m_amigo->holda_in(state);
428 }
429
430 /*
431 Clock line from the CPU. Forward to the custom chips.
432 */
WRITE_LINE_MEMBER(mainboard8_device::clock_in)433 WRITE_LINE_MEMBER( mainboard8_device::clock_in )
434 {
435 LOGMASKED(LOG_CLOCK, "CLKOUT = %d\n", state);
436
437 // Propagate to Vaquerro; may change GGRDY (trailing edge) and the GROM select lines
438 m_vaquerro->clock_in((line_state)state);
439
440 // Set the incoming ready line of Amigo (Mapper) before the clock
441 bool readycomb = ((m_vaquerro->ggrdy_out()==ASSERT_LINE) && m_speech_ready && m_sound_ready && m_pbox_ready);
442 m_amigo->srdy_in(readycomb? ASSERT_LINE : CLEAR_LINE);
443
444 // This may change the incoming READY lines of Vaquerro
445 if (state==CLEAR_LINE) select_groms();
446
447 m_amigo->clock_in((line_state)state);
448
449 // Mofetta only needs the clock to produce the GROM clock
450 m_mofetta->clock_in(state);
451
452 m_mofetta->skdrcs_in(m_amigo->skdrcs_out());
453
454 // Clock to Oso
455 m_oso->clock_in(state);
456
457 int gromclk = m_mofetta->gromclk_out();
458
459 if (gromclk != m_gromclk) // when it changed, propagate to the GROMs
460 {
461 m_gromclk = gromclk;
462
463 // Get some more performance. We only propagate the clock line to
464 // those GROMs that are not idle.
465 // Yields about 25% in bench (hoped for more, but well)
466 if (!m_sgrom_idle)
467 {
468 m_sgrom0->gclock_in(gromclk);
469 m_sgrom1->gclock_in(gromclk);
470 m_sgrom2->gclock_in(gromclk);
471 m_gromport->gclock_in(gromclk);
472 m_sgrom_idle = m_sgrom0->idle();
473 }
474
475 if (!m_tsgrom_idle)
476 {
477 m_tsgrom0->gclock_in(gromclk);
478 m_tsgrom1->gclock_in(gromclk);
479 m_tsgrom2->gclock_in(gromclk);
480 m_tsgrom3->gclock_in(gromclk);
481 m_tsgrom4->gclock_in(gromclk);
482 m_tsgrom5->gclock_in(gromclk);
483 m_tsgrom6->gclock_in(gromclk);
484 m_tsgrom7->gclock_in(gromclk);
485 m_tsgrom_idle = m_tsgrom0->idle();
486 }
487 if (!m_p8grom_idle)
488 {
489 m_p8grom0->gclock_in(gromclk);
490 m_p8grom1->gclock_in(gromclk);
491 m_p8grom2->gclock_in(gromclk);
492 m_p8grom3->gclock_in(gromclk);
493 m_p8grom4->gclock_in(gromclk);
494 m_p8grom5->gclock_in(gromclk);
495 m_p8grom6->gclock_in(gromclk);
496 m_p8grom7->gclock_in(gromclk);
497 m_p8grom_idle = m_p8grom0->idle();
498 }
499
500 if (!m_p3grom_idle)
501 {
502 m_p3grom0->gclock_in(gromclk);
503 m_p3grom1->gclock_in(gromclk);
504 m_p3grom2->gclock_in(gromclk);
505 m_p3grom_idle = m_p3grom0->idle();
506 }
507 }
508
509 // Check video for writing
510 if (m_pending_write && m_vaquerro->vdpwt_out()==ASSERT_LINE)
511 {
512 if (m_A14_set) m_video->register_write(m_latched_data);
513 else m_video->vram_write(m_latched_data);
514 m_pending_write = false;
515 LOGMASKED(LOG_MEM, "Write %04x (video) <- %02x\n", m_logical_address, m_latched_data);
516 cycle_end();
517 return;
518 }
519
520 // Propagate the READY signal
521 m_ready(m_amigo->cpury_out());
522
523 // In case we're reading, the CPU will now do the READ operation.
524 // Otherwise we must do the write operation now which we postponed before.
525
526 if (m_pending_write && (state==CLEAR_LINE))
527 {
528 if (m_amigo->skdrcs_out()==ASSERT_LINE)
529 {
530 m_dram->pointer()[m_physical_address & 0xffff] = m_latched_data;
531 m_pending_write = false;
532 LOGMASKED(LOG_MEM, "Write %04x (phys %06x, DRAM) <- %02x\n", m_logical_address, m_physical_address, m_latched_data);
533 }
534
535 if (m_mofetta->alccs_out()==ASSERT_LINE)
536 {
537 m_oso->write(m_physical_address>>1, m_latched_data);
538 m_pending_write = false;
539 LOGMASKED(LOG_MEM, "Write %04x (phys %06x, OSO) <- %02x\n", m_logical_address, m_physical_address, m_latched_data);
540 }
541
542 if (m_mofetta->cmas_out()==ASSERT_LINE)
543 {
544 m_gromport->romgq_line(ASSERT_LINE);
545 m_gromport->write(m_physical_address & 0x3fff, m_latched_data);
546 m_pending_write = false;
547 LOGMASKED(LOG_MEM, "Write %04x (phys %06x, cartridge) <- %02x\n", m_logical_address, m_physical_address, m_latched_data);
548 }
549 else
550 {
551 m_gromport->romgq_line(CLEAR_LINE);
552 }
553
554 if (m_mofetta->dbc_out()==ASSERT_LINE)
555 {
556 m_ioport->write(m_physical_address, m_latched_data);
557 m_pending_write = false;
558 LOGMASKED(LOG_MEM, "Write %04x (phys %06x, PEB) <- %02x\n", m_logical_address, m_physical_address, m_latched_data);
559 }
560 }
561
562 if (m_dbin_level==CLEAR_LINE && !m_pending_write) // Memory cycle ends
563 cycle_end();
564 }
565
select_groms()566 void mainboard8_device::select_groms()
567 {
568 // Select the GROM libs
569 // Note that we must also deselect them again, so we have to visit each
570 // one of them
571
572 int select = m_vaquerro->gromcs_out();
573
574 // Avoid to be called too often; this would have a bad penalty on emulation performance
575 // This simple check actually increases bench performance from 120% to 240%
576 if (select != m_prev_grom)
577 {
578 m_prev_grom = select;
579 line_state a14 = m_A14_set? ASSERT_LINE : CLEAR_LINE;
580
581 if (select & SGMSEL) m_sgrom_idle = false;
582 if (select & TSGSEL) m_tsgrom_idle = false;
583 if (select & P8GSEL) m_p8grom_idle = false;
584 if (select & P3GSEL) m_p3grom_idle = false;
585
586 line_state ssel = (select & SGMSEL)? ASSERT_LINE : CLEAR_LINE;
587 line_state tsel = (select & TSGSEL)? ASSERT_LINE : CLEAR_LINE;
588 line_state p8sel = (select & P8GSEL)? ASSERT_LINE : CLEAR_LINE;
589 line_state p3sel = (select & P3GSEL)? ASSERT_LINE : CLEAR_LINE;
590
591 m_sgrom0->set_lines((line_state)m_dbin_level, a14, ssel);
592 m_sgrom1->set_lines((line_state)m_dbin_level, a14, ssel);
593 m_sgrom2->set_lines((line_state)m_dbin_level, a14, ssel);
594
595 m_tsgrom0->set_lines((line_state)m_dbin_level, a14, tsel);
596 m_tsgrom1->set_lines((line_state)m_dbin_level, a14, tsel);
597 m_tsgrom2->set_lines((line_state)m_dbin_level, a14, tsel);
598 m_tsgrom3->set_lines((line_state)m_dbin_level, a14, tsel);
599 m_tsgrom4->set_lines((line_state)m_dbin_level, a14, tsel);
600 m_tsgrom5->set_lines((line_state)m_dbin_level, a14, tsel);
601 m_tsgrom6->set_lines((line_state)m_dbin_level, a14, tsel);
602 m_tsgrom7->set_lines((line_state)m_dbin_level, a14, tsel);
603
604 m_p8grom0->set_lines((line_state)m_dbin_level, a14, p8sel);
605 m_p8grom1->set_lines((line_state)m_dbin_level, a14, p8sel);
606 m_p8grom2->set_lines((line_state)m_dbin_level, a14, p8sel);
607 m_p8grom3->set_lines((line_state)m_dbin_level, a14, p8sel);
608 m_p8grom4->set_lines((line_state)m_dbin_level, a14, p8sel);
609 m_p8grom5->set_lines((line_state)m_dbin_level, a14, p8sel);
610 m_p8grom6->set_lines((line_state)m_dbin_level, a14, p8sel);
611 m_p8grom7->set_lines((line_state)m_dbin_level, a14, p8sel);
612
613 m_p3grom0->set_lines((line_state)m_dbin_level, a14, p3sel);
614 m_p3grom1->set_lines((line_state)m_dbin_level, a14, p3sel);
615 m_p3grom2->set_lines((line_state)m_dbin_level, a14, p3sel);
616
617 // Write to the cartridge port. The GROMs on cartridges are accessed as system GROMs
618 if (select & SGMSEL) m_gromport->romgq_line(CLEAR_LINE);
619 m_gromport->set_gromlines((line_state)m_dbin_level, a14, ssel);
620 }
621
622 // If we're planning to write to the GROMs, let's do it right now
623 if (select !=0 && m_pending_write)
624 {
625 m_pending_write = false;
626 switch (select)
627 {
628 case SGMSEL:
629 m_sgrom0->write(m_latched_data);
630 m_sgrom1->write(m_latched_data);
631 m_sgrom2->write(m_latched_data);
632 LOGMASKED(LOG_MEM, "Write GS <- %02x\n", m_latched_data);
633 m_gromport->write(0, m_latched_data);
634 break;
635
636 case TSGSEL:
637 m_tsgrom0->write(m_latched_data);
638 m_tsgrom1->write(m_latched_data);
639 m_tsgrom2->write(m_latched_data);
640 m_tsgrom3->write(m_latched_data);
641 m_tsgrom4->write(m_latched_data);
642 m_tsgrom5->write(m_latched_data);
643 m_tsgrom6->write(m_latched_data);
644 m_tsgrom7->write(m_latched_data);
645 LOGMASKED(LOG_MEM, "Write GT <- %02x\n", m_latched_data);
646 break;
647
648 case P8GSEL:
649 m_p8grom0->write(m_latched_data);
650 m_p8grom1->write(m_latched_data);
651 m_p8grom2->write(m_latched_data);
652 m_p8grom3->write(m_latched_data);
653 m_p8grom4->write(m_latched_data);
654 m_p8grom5->write(m_latched_data);
655 m_p8grom6->write(m_latched_data);
656 m_p8grom7->write(m_latched_data);
657 LOGMASKED(LOG_MEM, "Write G8 <- %02x\n", m_latched_data);
658 break;
659
660 case P3GSEL:
661 m_p3grom0->write(m_latched_data);
662 m_p3grom1->write(m_latched_data);
663 m_p3grom2->write(m_latched_data);
664 LOGMASKED(LOG_MEM, "Write G3 <- %02x\n", m_latched_data);
665 break;
666
667 default:
668 LOGMASKED(LOG_WARN, "Error: Multiple GROM libs selected: SGM=%d TSG=%d P8G=%d P3G=%d\n", (select & SGMSEL)!=0, (select & TSGSEL)!=0, (select & P8GSEL)!=0, (select & P3GSEL)!=0);
669 break;
670 }
671 }
672 }
673
set_paddress(int address)674 void mainboard8_device::set_paddress(int address)
675 {
676 // Keep this value as the current address
677 m_physical_address = (m_physical_address << 16) | address;
678 LOGMASKED(LOG_DETAIL, "Setting physical address %06x\n", m_physical_address);
679
680 m_mofetta->set_address(address, m_dbin_level);
681 m_ioport->setaddress_dbin(address, m_dbin_level);
682 }
683
WRITE_LINE_MEMBER(mainboard8_device::msast_in)684 WRITE_LINE_MEMBER( mainboard8_device::msast_in )
685 {
686 LOGMASKED(LOG_DETAIL, "msast = %d\n", state);
687
688 // Start physical space cycle on the trailing edge
689 if (state==CLEAR_LINE)
690 {
691 m_mofetta->pmemen_in(ASSERT_LINE);
692 m_ioport->memen_in(ASSERT_LINE);
693 }
694 m_mofetta->msast_in(state);
695 m_ioport->msast_in(state);
696 }
697
698
read(offs_t offset)699 uint8_t mainboard8_device::read(offs_t offset)
700 {
701 uint8_t value = 0;
702 const char* what;
703
704 if (machine().side_effects_disabled())
705 {
706 return debugger_read(offset);
707 }
708
709 // =================================================
710 // Logical space
711 // =================================================
712 if (m_amigo->mapper_accessed())
713 {
714 value = m_amigo->read();
715 what = "mapper";
716 goto readdone;
717 }
718
719 if (m_amigo->sramcs_out()==ASSERT_LINE)
720 {
721 value = m_sram->pointer()[m_logical_address & 0x07ff];
722 what = "SRAM";
723 goto readdone;
724 }
725
726 if (m_vaquerro->lascsq_out()==ASSERT_LINE)
727 {
728 // VDP access
729 if (m_vaquerro->vdprd_out()==ASSERT_LINE)
730 {
731 value = m_A14_set? m_video->register_read() : m_video->vram_read();
732 what = "video";
733 goto readdone;
734 }
735
736 // System ROM0
737 if (m_vaquerro->sromcs_out()==ASSERT_LINE)
738 {
739 value = m_rom0[m_logical_address & 0x1fff];
740 what = "ROM0";
741 goto readdone;
742 }
743
744 // Speech
745 if (m_vaquerro->sprd_out()==ASSERT_LINE)
746 {
747 value = m_speech->status_r() & 0xff;
748 what = "speech";
749 goto readdone;
750 }
751
752 // GROMs
753 switch (m_vaquerro->gromcs_out())
754 {
755 case SGMSEL:
756 m_sgrom_idle = false;
757 m_sgrom0->readz(&value);
758 m_sgrom1->readz(&value);
759 m_sgrom2->readz(&value);
760 m_gromport->readz(0, &value);
761 if (!m_A14_set) LOGMASKED(LOG_GROM, "GS>%04x\n", m_sgrom0->debug_get_address()-1);
762 what = "system GROM";
763 goto readdone;
764
765 case TSGSEL:
766 m_tsgrom_idle = false;
767 m_tsgrom0->readz(&value);
768 m_tsgrom1->readz(&value);
769 m_tsgrom2->readz(&value);
770 m_tsgrom3->readz(&value);
771 m_tsgrom4->readz(&value);
772 m_tsgrom5->readz(&value);
773 m_tsgrom6->readz(&value);
774 m_tsgrom7->readz(&value);
775 if (!m_A14_set) LOGMASKED(LOG_GROM, "GT>%04x\n", m_tsgrom0->debug_get_address()-1);
776 what = "TTS GROM";
777 goto readdone;
778
779 case P8GSEL:
780 m_p8grom_idle = false;
781 m_p8grom0->readz(&value);
782 m_p8grom1->readz(&value);
783 m_p8grom2->readz(&value);
784 m_p8grom3->readz(&value);
785 m_p8grom4->readz(&value);
786 m_p8grom5->readz(&value);
787 m_p8grom6->readz(&value);
788 m_p8grom7->readz(&value);
789 if (!m_A14_set) LOGMASKED(LOG_GROM, "G8>%04x\n", m_p8grom0->debug_get_address()-1);
790 what = "P8 GROM";
791 goto readdone;
792
793 case P3GSEL:
794 m_p3grom_idle = false;
795 m_p3grom0->readz(&value);
796 m_p3grom1->readz(&value);
797 m_p3grom2->readz(&value);
798 if (!m_A14_set) LOGMASKED(LOG_GROM, "G3>%04x\n", m_p3grom0->debug_get_address()-1);
799 what = "P3 GROM";
800 goto readdone;
801 default:
802 break;
803 }
804
805 // These messages appear in fact every time that a GPL command writes
806 // an immediate value to a write-only address (like 9400) because the
807 // GPL interpreter always tries to load the value from the provided memory address first
808
809 LOGMASKED(LOG_WARN, "Read %04x (unmapped) ignored\n", m_logical_address);
810
811 // Memory cycle ends
812 cycle_end();
813 return 0;
814 }
815 else
816 {
817 // =================================================
818 // Physical space
819 // =================================================
820 if (m_amigo->skdrcs_out()==ASSERT_LINE)
821 {
822 value = m_dram->pointer()[m_physical_address & 0xffff];
823 what = "DRAM";
824 goto readdonephys;
825 }
826
827 if (m_mofetta->rom1cs_out()==ASSERT_LINE)
828 {
829 int address = (m_physical_address & 0x1fff);
830 if (m_mofetta->rom1am_out()==ASSERT_LINE) address |= 0x4000;
831 if (m_mofetta->rom1al_out()==ASSERT_LINE) address |= 0x2000;
832 value = m_rom1[address];
833
834 LOGMASKED(LOG_MEM, "Read %04x (ROM1@%04x) -> %02x\n", m_logical_address, address, value);
835 cycle_end();
836 return value;
837 }
838
839 if (m_mofetta->alccs_out()==ASSERT_LINE)
840 {
841 value = m_oso->read(m_physical_address>>1);
842 what = "OSO";
843 goto readdonephys;
844 }
845
846 if (m_mofetta->prcs_out()==ASSERT_LINE)
847 {
848 value = m_pascalrom[m_physical_address & 0x3fff];
849 what = "PASCAL";
850 goto readdonephys;
851 }
852
853 if (m_mofetta->cmas_out()==ASSERT_LINE)
854 {
855 m_gromport->romgq_line(ASSERT_LINE);
856 m_gromport->readz(m_physical_address & 0x3fff, &value);
857 what = "Cartridge";
858 goto readdonephys;
859 }
860
861 if (m_mofetta->dbc_out()==ASSERT_LINE)
862 {
863 m_ioport->readz(m_physical_address & 0xffff, &value);
864 what = "PEB";
865 goto readdonephys;
866 }
867
868 LOGMASKED(LOG_PUNMAP, "Read %04x (phys %06x, unmapped) ignored\n", m_logical_address, m_physical_address);
869
870 // Memory cycle ends
871 cycle_end();
872 return 0;
873 }
874
875
876 readdone:
877 LOGMASKED(LOG_MEM, "Read %04x (%s) -> %02x\n", m_logical_address, what, value);
878 cycle_end();
879 return value;
880
881 readdonephys:
882 LOGMASKED(LOG_MEM, "Read %04x (phys %06x, %s) -> %02x\n", m_logical_address, m_physical_address, what, value);
883 cycle_end();
884 return value;
885 }
886
cycle_end()887 void mainboard8_device::cycle_end()
888 {
889 // Memory cycle ends
890 m_vaquerro->memen_in(CLEAR_LINE);
891 m_amigo->memen_in(CLEAR_LINE);
892 m_mofetta->pmemen_in(CLEAR_LINE);
893 m_ioport->memen_in(CLEAR_LINE);
894 }
895
896 /*
897 When writing, the emulation relies on a push mechanism; the write
898 operation follows the setaddress operation immediately.
899
900 If the READY line is pulled down due to the mapping process, we must
901 store the data bus value until the physical address is available.
902 */
write(offs_t offset,uint8_t data)903 void mainboard8_device::write(offs_t offset, uint8_t data)
904 {
905 m_latched_data = data;
906 m_pending_write = true;
907
908 if (machine().side_effects_disabled())
909 {
910 return debugger_write(offset, data);
911 }
912
913 // Some logical space devices can be written immediately
914 // GROMs and video must wait to be selected
915 if (m_amigo->mapper_accessed())
916 {
917 LOGMASKED(LOG_MEM, "Write %04x (mapper) <- %02x\n", m_logical_address, data);
918 m_amigo->write(data);
919 m_pending_write = false;
920 }
921
922 // Sound ... we have to put it before SRAM because in compatibility mode the
923 // sound address lies within the SRAM area
924 if (m_vaquerro->sccs_out()==ASSERT_LINE)
925 {
926 LOGMASKED(LOG_MEM, "Write %04x (sound) <- %02x\n", m_logical_address, data);
927 m_sound->write(data); // Sound chip will lower READY after this access
928 m_pending_write = false;
929 }
930 else
931 {
932 // SRAM
933 if (m_amigo->sramcs_out()==ASSERT_LINE)
934 {
935 LOGMASKED(LOG_MEM, "Write %04x (SRAM) <- %02x\n", m_logical_address, data);
936 m_sram->pointer()[m_logical_address & 0x07ff] = data;
937 m_pending_write = false;
938 }
939 }
940
941 // Speech
942 if (m_vaquerro->spwt_out()==ASSERT_LINE)
943 {
944 LOGMASKED(LOG_MEM, "Write %04x (speech) <- %02x\n", m_logical_address, data);
945 m_speech->data_w(data);
946 m_pending_write = false;
947 }
948
949 if (!m_pending_write)
950 cycle_end();
951
952 // The remaining physical devices will respond as soon as the physical address is completely set
953 }
954
955 /*
956 Set 99/4A compatibility mode (CRUS=1)
957 */
WRITE_LINE_MEMBER(mainboard8_device::crus_in)958 WRITE_LINE_MEMBER( mainboard8_device::crus_in )
959 {
960 LOGMASKED(LOG_CRU, "%s CRUS\n", (state==1)? "Assert" : "Clear");
961 m_vaquerro->crus_in(state);
962 m_amigo->crus_in(state);
963 m_crus_debug = (line_state)state;
964 }
965
966 /*
967 Set mapper /PTGEN line ("Pascal and Text-to-speech GROMs enable").
968 Note that PTGEN is negative logic.
969 */
WRITE_LINE_MEMBER(mainboard8_device::ptgen_in)970 WRITE_LINE_MEMBER( mainboard8_device::ptgen_in )
971 {
972 LOGMASKED(LOG_CRU, "%s PTGEN*\n", (state==0)? "Assert" : "Clear");
973 m_vaquerro->crusgl_in((state==0)? ASSERT_LINE : CLEAR_LINE);
974 }
975
976
977 /*
978 READY lines, to be combined
979 */
WRITE_LINE_MEMBER(mainboard8_device::system_grom_ready)980 WRITE_LINE_MEMBER( mainboard8_device::system_grom_ready )
981 {
982 m_vaquerro->sgmry(state);
983 }
984
WRITE_LINE_MEMBER(mainboard8_device::ptts_grom_ready)985 WRITE_LINE_MEMBER( mainboard8_device::ptts_grom_ready )
986 {
987 m_vaquerro->tsgry(state);
988 }
989
WRITE_LINE_MEMBER(mainboard8_device::p8_grom_ready)990 WRITE_LINE_MEMBER( mainboard8_device::p8_grom_ready )
991 {
992 m_vaquerro->p8gry(state);
993 }
994
WRITE_LINE_MEMBER(mainboard8_device::p3_grom_ready)995 WRITE_LINE_MEMBER( mainboard8_device::p3_grom_ready )
996 {
997 m_vaquerro->p3gry(state);
998 }
999
WRITE_LINE_MEMBER(mainboard8_device::sound_ready)1000 WRITE_LINE_MEMBER( mainboard8_device::sound_ready )
1001 {
1002 m_sound_ready = state;
1003 }
1004
WRITE_LINE_MEMBER(mainboard8_device::speech_ready)1005 WRITE_LINE_MEMBER( mainboard8_device::speech_ready )
1006 {
1007 // The TMS5200 implementation uses true/false, not ASSERT/CLEAR semantics
1008 m_speech_ready = (state==false)? ASSERT_LINE : CLEAR_LINE;
1009 }
1010
WRITE_LINE_MEMBER(mainboard8_device::pbox_ready)1011 WRITE_LINE_MEMBER( mainboard8_device::pbox_ready )
1012 {
1013 m_pbox_ready = state;
1014 }
1015
WRITE_LINE_MEMBER(mainboard8_device::ggrdy_in)1016 WRITE_LINE_MEMBER( mainboard8_device::ggrdy_in )
1017 {
1018 m_amigo->srdy_in((state==ASSERT_LINE && m_speech_ready && m_sound_ready && m_pbox_ready)? ASSERT_LINE : CLEAR_LINE);
1019 }
1020
device_start()1021 void mainboard8_device::device_start()
1022 {
1023 // Lines going to the main driver class, then to the CPU
1024 m_ready.resolve_safe(); // READY
1025 m_console_reset.resolve_safe(); // RESET
1026 m_hold_line.resolve_safe(); // HOLD
1027
1028 m_rom0 = machine().root_device().memregion(TI998_ROM0_REG)->base();
1029 m_rom1 = machine().root_device().memregion(TI998_ROM1_REG)->base();
1030 m_pascalrom = machine().root_device().memregion(TI998_PASCAL_REG)->base();
1031
1032 // Register state variables
1033 save_item(NAME(m_A14_set));
1034 save_item(NAME(m_logical_address));
1035 save_item(NAME(m_physical_address));
1036 save_item(NAME(m_pending_write));
1037 save_item(NAME(m_latched_data));
1038 save_item(NAME(m_gromclk));
1039 save_item(NAME(m_prev_grom));
1040 save_item(NAME(m_speech_ready));
1041 save_item(NAME(m_sound_ready));
1042 save_item(NAME(m_pbox_ready));
1043 save_item(NAME(m_dbin_level));
1044 save_item(NAME(m_last_ready));
1045 save_item(NAME(m_sgrom_idle));
1046 save_item(NAME(m_tsgrom_idle));
1047 save_item(NAME(m_p8grom_idle));
1048 save_item(NAME(m_p3grom_idle));
1049 }
1050
device_reset()1051 void mainboard8_device::device_reset()
1052 {
1053 m_last_ready = CLEAR_LINE;
1054 m_speech_ready = true;
1055 m_sound_ready = true;
1056 m_pbox_ready = true;
1057 m_pending_write = false;
1058 m_prev_grom = 0;
1059 m_A14_set = false;
1060 // Configure RAM and AMIGO
1061 m_amigo->connect_sram(m_sram->pointer());
1062 }
1063
device_add_mconfig(machine_config & config)1064 void mainboard8_device::device_add_mconfig(machine_config &config)
1065 {
1066 TI99_VAQUERRO(config, TI998_VAQUERRO_TAG, 0);
1067 TI99_MOFETTA(config, TI998_MOFETTA_TAG, 0);
1068 TI99_AMIGO(config, TI998_AMIGO_TAG, 0);
1069 TI99_OSO(config, TI998_OSO_TAG, 0);
1070 }
1071
1072 /***************************************************************************
1073 ===== VAQUERRO: Logical Address Space decoder =====
1074
1075 Logical address space (LAS)
1076 ===========================
1077 The LAS is the address space as seen by the TMS 9995 CPU. It is 64 KiB large.
1078 The LAS can be configured in two ways:
1079 - the native (99/8) mode
1080 - and the compatibility mode (99/4A)
1081
1082 Both modes are selected by CRU bit 20 on base 0000 (named "CRUS").
1083
1084 The console starts up in compatibility mode.
1085
1086 The compatibility mode organizes the LAS in a similar way as the TI-99/4A.
1087 This means that machine language programs should run with no or only minor
1088 changes. In particular, game cartridges work without problems.
1089
1090 The native mode rearranges the address space and puts memory-mapped devices
1091 to other positions.
1092
1093 TI-99/4A compatibility mode (CRUS=1)
1094 ------------------------------------
1095 0000-1fff: 2 KiB ROM0
1096 2000-7fff: Free area
1097 8000-87ff: 2 KiB SRAM
1098 8000-81ff: mapper files (8 files with 16*4 bytes each)
1099 8200-82ff: Free RAM
1100 8300-83ff: Scratch-pad RAM as in the 99/4A
1101 8400-840f: Sound chip
1102 8800-880f: VDP read port (data, status)
1103 8810-881f: Mapper access port
1104 8820-8bff: Free area
1105 8c00-8c0f: VDP write port (data, address)
1106 8c10-8fff: Free area
1107 9000-900f: Speech synthesizer read (on-board)
1108 9010-93ff: Free area
1109 9400-940f: Speech synthesizer write (on-board)
1110 9410-97ff: Free area
1111 9800-980f: System GROM read (data, address)
1112 9810-9bff: Free area
1113 9c00-9c0f: System GROM write (data, address)
1114 9c10-fffb: Free area
1115 fffc-ffff: NMI vector
1116
1117 TI-99/8 native mode (CRUS=0)
1118 ----------------------------
1119 0000-efff: Free area
1120 f000-f7ff: 2 KiB SRAM
1121 f000-f1ff: mapper files (8 files with 16*4 bytes each)
1122 f200-f7ff: Free RAM
1123 f800-f80f: Sound chip
1124 f810-f81f: VDP read (data, status) and write (data, address)
1125 f820-f82f: Speech synthesizer read/write
1126 f830-f83f: System GROM read/write
1127 f840-f86f: Free area
1128 f870-f87f: Mapper access port
1129 f880-fffb: Free area
1130 fffc-ffff: NMI vector
1131
1132 Note that ROM0 is not visible in the native mode.
1133
1134 If CRU bit 21 (PTGEN*) is set to 0, Pascal GROMs appear in the LAS in either
1135 mode. It is highly recommended to use native mode when turning on these
1136 GROMs, because the area where they appear may be occupied by a program in
1137 99/4A mode.
1138
1139 Pascal and Text-to-speech GROM enabled (PTGEN*=0)
1140 -------------------------------------------------
1141 f840-f84f: Text-to-speech GROM read/write
1142 f850-f85f: P-Code library #1 GROM read/write
1143 f860-f86f: P-Code library #2 GROM read/write
1144
1145
1146 ***************************************************************************/
1147
vaquerro_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1148 vaquerro_device::vaquerro_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1149 : device_t(mconfig, TI99_VAQUERRO, tag, owner, clock),
1150 m_crus(ASSERT_LINE),
1151 m_crugl(ASSERT_LINE),
1152 m_ggrdy(ASSERT_LINE)
1153 {
1154 }
1155
set_address(offs_t offset,int state)1156 void vaquerro_device::set_address(offs_t offset, int state)
1157 {
1158 // Do the decoding
1159 // state = dbin, offset = address
1160
1161 bool reading = (state==ASSERT_LINE);
1162 bool sgfap = false;
1163 bool tsgfap = false;
1164 bool p8gfap = false;
1165 bool p3gfap = false;
1166 bool vfap = false;
1167
1168 m_a14 = ((offset & 2)!=0)? ASSERT_LINE : CLEAR_LINE; // Needed for clock_in
1169
1170 m_dbin_level = (line_state)state;
1171
1172 int offbase = (offset & 0xfff1);
1173
1174 // =================== TI (compatibility) mode ======================
1175 if (m_crus == ASSERT_LINE)
1176 {
1177 LOGMASKED(LOG_DETAIL, "Compatibility mode\n");
1178
1179 // SPRD (Speech read)
1180 m_sprd = ((offbase==0x9000) && reading);
1181
1182 // SPWT (Speech write)
1183 m_spwt = ((offbase==0x9400) && !reading);
1184
1185 // Sound
1186 m_sccs = ((offbase==0x8400)&& !reading);
1187
1188 // ROM0
1189 m_sromcs = (((offset & 0xe000)==0x0000) && reading);
1190
1191 // Video select
1192 vfap = ((offbase==0x8800) && reading) || ((offbase==0x8c00) && !reading);
1193
1194 // System GROM
1195 sgfap = ((offbase==0x9800) && reading) || ((offbase==0x9c00) && !reading);
1196 }
1197 // ====================== Native mode ======================
1198 else
1199 {
1200 LOGMASKED(LOG_DETAIL, "Native mode\n");
1201
1202 // SPRD (Speech read)
1203 m_sprd = ((offbase==0xf820) && reading);
1204
1205 // SPWT (Speech write)
1206 m_spwt = ((offbase==0xf820) && !reading);
1207
1208 // Sound
1209 m_sccs = ((offbase==0xf800) && !reading);
1210
1211 // Video
1212 vfap = (offbase==0xf810);
1213
1214 // System GROM (read and write)
1215 sgfap = (offbase==0xf830);
1216 }
1217
1218 // These lines are not decoded for compatibility or native mode, only
1219 // the line CRUGL determines whether they become visible.
1220 tsgfap = (offbase==0xf840) && m_crugl;
1221 p8gfap = (offbase==0xf850) && m_crugl;
1222 p3gfap = (offbase==0xf860) && m_crugl;
1223
1224 // The LASREQ line says whether Vaquerro does the job, or whether it is Mofetta's turn.
1225 m_grom_or_video = sgfap || tsgfap || p8gfap || p3gfap || vfap ;
1226
1227 m_lasreq = (m_sprd || m_spwt || m_sccs || m_sromcs || m_grom_or_video);
1228
1229 LOGMASKED(LOG_DETAIL, "sgfap=%d tsgfap=%d p8gfap=%d p3gfap=%d vfap=%d\n", sgfap, tsgfap, p8gfap, p3gfap, vfap);
1230
1231 // Pass the selection to the wait state generators
1232 // and pick up the current select line states
1233 m_sgmws.select_in(sgfap);
1234 m_tsgws.select_in(tsgfap);
1235 m_p8gws.select_in(p8gfap);
1236 m_p3gws.select_in(p3gfap);
1237 m_vidws.select_in(vfap);
1238
1239 m_gromsel = m_sgmws.select_out() | m_tsgws.select_out() | m_p8gws.select_out() | m_p3gws.select_out();
1240
1241 m_vdprd = (reading && (m_vidws.select_out()!=0));
1242 m_vdpwt = (!reading && (m_vidws.select_out()!=0));
1243
1244 if (m_grom_or_video)
1245 {
1246 // We don't see the current selection now; only with next clock pulse.
1247 m_mainboard->ggrdy_in(m_sry);
1248 LOGMASKED(LOG_READY, "GGRDY = %d\n", m_sry);
1249 }
1250 }
1251
WRITE_LINE_MEMBER(vaquerro_device::crusgl_in)1252 WRITE_LINE_MEMBER( vaquerro_device::crusgl_in )
1253 {
1254 m_crugl = (state==ASSERT_LINE);
1255 }
1256
WRITE_LINE_MEMBER(vaquerro_device::crus_in)1257 WRITE_LINE_MEMBER( vaquerro_device::crus_in )
1258 {
1259 m_crus = (line_state)state;
1260 }
1261
WRITE_LINE_MEMBER(vaquerro_device::memen_in)1262 WRITE_LINE_MEMBER( vaquerro_device::memen_in )
1263 {
1264 m_memen = (state==ASSERT_LINE);
1265 }
1266
1267 /*
1268 Called by Mofetta
1269 */
READ_LINE_MEMBER(vaquerro_device::lascsq_out)1270 READ_LINE_MEMBER( vaquerro_device::lascsq_out )
1271 {
1272 return (m_lasreq && m_memen)? ASSERT_LINE : CLEAR_LINE;
1273 }
1274
1275 /*
1276 Incoming ready lines from the GROM library
1277 */
WRITE_LINE_MEMBER(vaquerro_device::sgmry)1278 WRITE_LINE_MEMBER( vaquerro_device::sgmry )
1279 {
1280 LOGMASKED(LOG_READY, "Incoming SGMRY = %d\n", state);
1281 m_sgmws.ready_in((line_state)state);
1282 }
1283
WRITE_LINE_MEMBER(vaquerro_device::tsgry)1284 WRITE_LINE_MEMBER( vaquerro_device::tsgry )
1285 {
1286 LOGMASKED(LOG_READY, "Incoming TSGRY = %d\n", state);
1287 m_tsgws.ready_in((line_state)state);
1288 }
1289
WRITE_LINE_MEMBER(vaquerro_device::p8gry)1290 WRITE_LINE_MEMBER( vaquerro_device::p8gry )
1291 {
1292 LOGMASKED(LOG_READY, "Incoming 8GRY = %d\n", state);
1293 m_p8gws.ready_in((line_state)state);
1294 }
1295
WRITE_LINE_MEMBER(vaquerro_device::p3gry)1296 WRITE_LINE_MEMBER( vaquerro_device::p3gry )
1297 {
1298 LOGMASKED(LOG_READY, "Incoming P3GRY = %d\n", state);
1299 m_p3gws.ready_in((line_state)state);
1300 }
1301
1302 /*
1303 Outgoing READY
1304 */
READ_LINE_MEMBER(vaquerro_device::ggrdy_out)1305 READ_LINE_MEMBER( vaquerro_device::ggrdy_out )
1306 {
1307 LOGMASKED(LOG_READY, "GGRDY out = %d\n", m_ggrdy);
1308 return m_ggrdy;
1309 }
1310
1311 /*
1312 Select lines
1313 */
1314
1315 // =========================
1316
gromcs_out()1317 int vaquerro_device::gromcs_out()
1318 {
1319 return m_gromsel;
1320 }
1321
1322 // =========================
1323
READ_LINE_MEMBER(vaquerro_device::vdprd_out)1324 READ_LINE_MEMBER( vaquerro_device::vdprd_out )
1325 {
1326 return (m_vdprd && m_memen)? ASSERT_LINE : CLEAR_LINE;
1327 }
1328
READ_LINE_MEMBER(vaquerro_device::vdpwt_out)1329 READ_LINE_MEMBER( vaquerro_device::vdpwt_out )
1330 {
1331 return (m_vdpwt && m_memen)? ASSERT_LINE : CLEAR_LINE;
1332 }
1333
READ_LINE_MEMBER(vaquerro_device::sprd_out)1334 READ_LINE_MEMBER( vaquerro_device::sprd_out )
1335 {
1336 return (m_sprd && m_memen)? ASSERT_LINE : CLEAR_LINE;
1337 }
1338
READ_LINE_MEMBER(vaquerro_device::spwt_out)1339 READ_LINE_MEMBER( vaquerro_device::spwt_out )
1340 {
1341 return (m_spwt && m_memen)? ASSERT_LINE : CLEAR_LINE;
1342 }
1343
READ_LINE_MEMBER(vaquerro_device::sromcs_out)1344 READ_LINE_MEMBER( vaquerro_device::sromcs_out )
1345 {
1346 return (m_sromcs && m_memen)? ASSERT_LINE : CLEAR_LINE;
1347 }
1348
READ_LINE_MEMBER(vaquerro_device::sccs_out)1349 READ_LINE_MEMBER( vaquerro_device::sccs_out )
1350 {
1351 return (m_sccs && m_memen)? ASSERT_LINE : CLEAR_LINE;
1352 }
1353
1354 /*
1355 Incoming clock signal.
1356
1357 The Vaquerro has a Wait State generation logic circuit for the video
1358 processor and all 4 GROM libraries. Each one has its separate generator.
1359 The GROMs get a 16 cycle wait period after their access, while the video
1360 processors gets an 8 cycle wait period. If during that period another
1361 access occurs, the system READY line will be cleared, triggering wait
1362 states in the CPU.
1363 */
WRITE_LINE_MEMBER(vaquerro_device::clock_in)1364 WRITE_LINE_MEMBER( vaquerro_device::clock_in )
1365 {
1366 line_state level = (line_state)state;
1367
1368 // Propagate to the wait state generators (note that we need both clock levels)
1369 m_sgmws.clock_in(level);
1370 m_tsgws.clock_in(level);
1371 m_p8gws.clock_in(level);
1372 m_p3gws.clock_in(level);
1373 m_vidws.clock_in(level);
1374
1375 // Collect the selections
1376 // Each one has its own indication, defined at init time
1377 m_gromsel = m_sgmws.select_out() | m_tsgws.select_out() | m_p8gws.select_out() | m_p3gws.select_out();
1378
1379 bool reading = (m_dbin_level==ASSERT_LINE);
1380
1381 m_vdprd = (reading && (m_vidws.select_out()!=0));
1382 m_vdpwt = (!reading && (m_vidws.select_out()!=0));
1383
1384 // Get the READY levels from the GROMs
1385 if (level==CLEAR_LINE)
1386 {
1387 m_sry = m_sgmws.ready_out() || m_tsgws.ready_out() || m_p8gws.ready_out() || m_p3gws.ready_out() || m_vidws.ready_out();
1388 LOGMASKED(LOG_WS, "ready_out = (%d, %d, %d, %d, %d)\n", m_sgmws.ready_out(), m_tsgws.ready_out(), m_p8gws.ready_out(), m_p3gws.ready_out(),m_vidws.ready_out());
1389 }
1390
1391 // If the output gate is closed, propagate ASSERT_LINE (pulled up)
1392 m_ggrdy = (!m_grom_or_video || m_sry)? ASSERT_LINE : CLEAR_LINE;
1393 }
1394
1395
device_start()1396 void vaquerro_device::device_start()
1397 {
1398 m_mainboard = downcast<mainboard8_device*>(owner());
1399 m_sgmws.init(SGMSEL);
1400 m_tsgws.init(TSGSEL);
1401 m_p8gws.init(P8GSEL);
1402 m_p3gws.init(P3GSEL);
1403 m_vidws.init(VIDSEL);
1404
1405 save_item(NAME(m_memen));
1406 save_item(NAME(m_video_wait));
1407 save_item(NAME(m_crus));
1408 save_item(NAME(m_crugl));
1409 save_item(NAME(m_lasreq));
1410 save_item(NAME(m_grom_or_video));
1411 save_item(NAME(m_spwt));
1412 save_item(NAME(m_sccs));
1413 save_item(NAME(m_sromcs));
1414 save_item(NAME(m_sprd));
1415 save_item(NAME(m_vdprd));
1416 save_item(NAME(m_vdpwt));
1417 save_item(NAME(m_gromsel));
1418 save_item(NAME(m_ggrdy));
1419 save_item(NAME(m_sry));
1420 save_item(NAME(m_a14));
1421 save_item(NAME(m_dbin_level));
1422
1423 // FIXME: In rare occasions, the saved state is invalid and restoring
1424 // may crash the emulated 99/8 (e.g. with invalid opcodes)
1425 // Saving the wait state logic does not affect the operation, as it seems,
1426 // so we leave it out.
1427 }
1428
device_reset()1429 void vaquerro_device::device_reset()
1430 {
1431 m_ggrdy = ASSERT_LINE;
1432 m_vdpwt = m_vdprd = CLEAR_LINE;
1433 m_gromsel = 0;
1434 m_sgmws.treset_in(ASSERT_LINE);
1435 m_tsgws.treset_in(ASSERT_LINE);
1436 m_p8gws.treset_in(ASSERT_LINE);
1437 m_p3gws.treset_in(ASSERT_LINE);
1438 m_vidws.treset_in(ASSERT_LINE);
1439 }
1440
1441 /*
1442 Wait state generation logic inside Vaquerro
1443
1444 Analysis of the logic diagram of the Vaquerro delivers the following
1445 behavior (for the first GROM library; similar behavior applies for the
1446 other libraries). Note that the CLKOUT line is inverted.
1447
1448 1. When the GROMs are unselected by address (SGFAP), the SRY line is Z
1449 (System READY). The GROM ready line (SGMRY) has no effect.
1450 2. When SGFAP is asserted while the internal counter is off, the
1451 READY line changes from Z to Low and the GROM select line (SGCS) is
1452 asserted (both immediately, before the next tick edge). SGMRY has no effect.
1453 The circuit state is constant during further clock ticks.
1454 3. After being selected, when SGMRY is asserted (GROM is ready), SRY
1455 changes to High on the next trailing edge. This will allow the
1456 CPU to complete the GROM access on the next cycle,
1457 and the address bus will change, typically deselecting the GROMs.
1458 Until this deselection, the circuit state remains constant
1459 (SGCS asserted, READY=H).
1460 4. When the GROMs are deselected, SRY changes to Z, and SGCS is cleared
1461 (immediately). A counter is started at 0 that is incremented on each clock
1462 tick (leading edge).
1463 5. When SGFAP is asserted while the counter is less that 15, SRY changes
1464 to Low immediately. SGCS remains cleared, so the GROMs are not selected.
1465 While SGFAP stays cleared, the counter completes its way to 15,
1466 then 0, and turns off.
1467 6. When the counter reaches 15, it returns to 0 on the next tick
1468 (leading). On the following trailing edge, the GROM select line is
1469 asserted, while the READY line remains Low.
1470 7. Continue at 3.
1471 */
select_in(bool addressed)1472 void vaquerro_device::waitstate_generator::select_in(bool addressed)
1473 {
1474 m_addressed = addressed;
1475 }
1476
select_out()1477 int vaquerro_device::waitstate_generator::select_out()
1478 {
1479 return (!m_counting && m_addressed)? m_selvalue : 0;
1480 }
1481
1482 /*
1483 Should be low by default.
1484 */
ready_out()1485 line_state vaquerro_device::waitstate_generator::ready_out()
1486 {
1487 return (m_ready && !m_counting && m_generate)? ASSERT_LINE : CLEAR_LINE;
1488 }
1489
is_counting()1490 bool vaquerro_device::waitstate_generator::is_counting()
1491 {
1492 return m_counting;
1493 }
1494
is_generating()1495 bool vaquerro_device::waitstate_generator::is_generating()
1496 {
1497 return m_generate;
1498 }
1499
is_ready()1500 bool vaquerro_device::waitstate_generator::is_ready()
1501 {
1502 return m_ready;
1503 }
1504
1505 /*
1506 READY in. This may only show an effect with the next trailing edge of CLKOUT.
1507 */
ready_in(line_state ready)1508 void vaquerro_device::grom_waitstate_generator::ready_in(line_state ready)
1509 {
1510 m_ready = (ready==ASSERT_LINE);
1511 }
1512
clock_in(line_state clkout)1513 void vaquerro_device::grom_waitstate_generator::clock_in(line_state clkout)
1514 {
1515 if (clkout == ASSERT_LINE)
1516 {
1517 if (m_counting) m_counter++;
1518 }
1519 else
1520 {
1521 if (m_counting && m_counter==16)
1522 {
1523 m_counter = 0;
1524 m_counting = false;
1525 }
1526 else
1527 {
1528 if (!m_addressed && m_generate) m_counting = true;
1529 m_generate = ((m_addressed || m_counting) && (m_counter != 15));
1530 }
1531 }
1532 }
1533
treset_in(line_state reset)1534 void vaquerro_device::waitstate_generator::treset_in(line_state reset)
1535 {
1536 if (reset==ASSERT_LINE)
1537 {
1538 m_counter = 0;
1539 m_generate = m_counting = m_addressed = false;
1540 }
1541 }
1542
clock_in(line_state clkout)1543 void vaquerro_device::video_waitstate_generator::clock_in(line_state clkout)
1544 {
1545 if (clkout == ASSERT_LINE)
1546 {
1547 if (m_counting) m_counter++;
1548 }
1549 else
1550 {
1551 if (m_counting && m_counter==7)
1552 {
1553 m_counter = 0;
1554 m_counting = false;
1555 }
1556 else
1557 {
1558 if (!m_addressed && m_generate) m_counting = true;
1559 m_generate = ((m_addressed || m_counting) && (m_counter != 6));
1560 }
1561 }
1562 }
1563
1564 /***************************************************************************
1565 ===== MOFETTA: Physical Address Space decoder =====
1566
1567 Physical address space (PAS)
1568 ============================
1569 The PAS is 24 bits wide and accessed via the custom mapper chip nicknamed
1570 "Amigo". The mapper exchanges map definitions with SRAM (see LAS). That
1571 means, a map can be prepared in SRAM, and for activating it, the mapper
1572 is accessed on its port, telling it to load or save a map.
1573
1574 000000-00ffff: 64 KiB console DRAM
1575 010000-efffff: undefined
1576
1577 f00000-f03fff: PASCAL support ROM (not mentioned in [1])
1578
1579 f04000-feffff: undefined
1580 ff0000 : unmapped (code for mapper)
1581 ff0001-ff3fff: undefined
1582 ff4000-ff5fff: DSR ROM in Peripheral Box, Hexbus DSR (CRU 1700) or additional ROM (CRU 2700)
1583 ff6000-ff9fff: Cartridge ROM space
1584 ffa000-ffdfff: 16 KiB ROM1
1585 ffe000-ffe00f: Interrupt level sense
1586 ffe010-ffffff: undefined
1587
1588
1589 ***************************************************************************/
1590
1591 enum
1592 {
1593 UNDEF=0,
1594 DRAM,
1595 PASCAL,
1596 INTERNAL
1597 };
1598
mofetta_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1599 mofetta_device::mofetta_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1600 : device_t(mconfig, TI99_MOFETTA, tag, owner, clock),
1601 m_gotfirstword(false)
1602 {
1603 }
1604
set_address(offs_t offset,int state)1605 void mofetta_device::set_address(offs_t offset, int state)
1606 {
1607 if (!m_gotfirstword)
1608 {
1609 // Store the first word and wait for clearing of MSAST
1610 LOGMASKED(LOG_MOFETTA, "Got the upper word of the address: %04x\n", offset);
1611 m_address_latch = offset;
1612 }
1613 else
1614 {
1615 // Second part - now decode the address
1616 LOGMASKED(LOG_MOFETTA, "Got the lower word of the address: %04x\n", offset);
1617
1618 bool acs, tcs, rcs, acsx;
1619 bool reading = (state==ASSERT_LINE);
1620 int offbase = (offset & 0xe000);
1621
1622 // PASCAL ROM select (16K)
1623 m_prcs = (m_prefix == 0xf0) && ((offset & 0xc000) == 0x0000);
1624
1625 // Hexbus select
1626 acs = (m_prefix == 0xff) && (offbase == 0x4000) && m_alcpg;
1627
1628 // Internal DSR select (ff4000-ff5fff @ CRU>2700)
1629 tcs = (m_prefix == 0xff) && (offbase == 0x4000) && m_txspg;
1630
1631 // Hexbus select (ff4000-ff5fef @ CRU>1700), excluding OSO
1632 acsx = acs && ((offset & 0x1ff0)!=0x1ff0);
1633
1634 // Upper 16K of ROM1
1635 m_rom1am = !((offbase == 0xa000) || (offbase == 0xc000));
1636
1637 // ROM select
1638 rcs = (m_prefix == 0xff) && reading && !m_rom1am;
1639
1640 // ROM1 select (containing 16K ROM, 8K TTS, 8K ACS)
1641 m_rom1cs = tcs || rcs || acsx;
1642
1643 // Accessing OSO (ff5ff0 @ CRU>1700)
1644 m_alccs = acs && ((offset & 0x1ff0)==0x1ff0);
1645
1646 // Second half of ROM or ACS
1647 m_rom1al = reading && (m_prefix == 0xff) && ((offbase == 0xc000) || acs);
1648
1649 // Cartridge port (ff6000-ff9fff)
1650 m_cmas = (m_prefix == 0xff) && ((offbase == 0x6000) || (offbase == 0x8000));
1651
1652 m_gotfirstword = false;
1653 }
1654 }
1655
1656 /*
1657 Mofetta delivers the GROMCLK. In the 99/4A, this clock is produced by the VDP.
1658 Apart from that, Mofetta does not need the CLKOUT.
1659 */
WRITE_LINE_MEMBER(mofetta_device::clock_in)1660 WRITE_LINE_MEMBER( mofetta_device::clock_in )
1661 {
1662 if (state == CLEAR_LINE) // TODO: Correct edge?
1663 {
1664 m_gromclock_count++;
1665 if (m_gromclock_count >=3)
1666 {
1667 m_gromclk_up = !m_gromclk_up;
1668 m_gromclock_count = 0;
1669 }
1670 }
1671 }
1672
READ_LINE_MEMBER(mofetta_device::alccs_out)1673 READ_LINE_MEMBER( mofetta_device::alccs_out )
1674 {
1675 return (m_alccs && m_pmemen)? ASSERT_LINE : CLEAR_LINE;
1676 }
1677
READ_LINE_MEMBER(mofetta_device::gromclk_out)1678 READ_LINE_MEMBER( mofetta_device::gromclk_out )
1679 {
1680 return m_gromclk_up? ASSERT_LINE : CLEAR_LINE;
1681 }
1682
READ_LINE_MEMBER(mofetta_device::rom1cs_out)1683 READ_LINE_MEMBER( mofetta_device::rom1cs_out )
1684 {
1685 return (m_rom1cs && m_pmemen)? ASSERT_LINE : CLEAR_LINE;
1686 }
1687
READ_LINE_MEMBER(mofetta_device::rom1am_out)1688 READ_LINE_MEMBER( mofetta_device::rom1am_out )
1689 {
1690 return (m_rom1am && m_pmemen)? ASSERT_LINE : CLEAR_LINE;
1691 }
1692
READ_LINE_MEMBER(mofetta_device::rom1al_out)1693 READ_LINE_MEMBER( mofetta_device::rom1al_out )
1694 {
1695 return (m_rom1al && m_pmemen)? ASSERT_LINE : CLEAR_LINE;
1696 }
1697
READ_LINE_MEMBER(mofetta_device::prcs_out)1698 READ_LINE_MEMBER( mofetta_device::prcs_out )
1699 {
1700 return (m_prcs && m_pmemen)? ASSERT_LINE : CLEAR_LINE;
1701 }
1702
READ_LINE_MEMBER(mofetta_device::cmas_out)1703 READ_LINE_MEMBER( mofetta_device::cmas_out )
1704 {
1705 return (m_cmas && m_pmemen)? ASSERT_LINE : CLEAR_LINE;
1706 }
1707
1708 /*
1709 Asserted when a PEB access occurs
1710 */
READ_LINE_MEMBER(mofetta_device::dbc_out)1711 READ_LINE_MEMBER( mofetta_device::dbc_out )
1712 {
1713 return (m_lasreq || m_cmas || m_rom1cs || m_skdrcs || !m_pmemen)? CLEAR_LINE : ASSERT_LINE;
1714 }
1715
1716 /*
1717 Debugger support
1718 */
hexbus_access_debug()1719 bool mofetta_device::hexbus_access_debug()
1720 {
1721 return m_alcpg;
1722 }
1723
intdsr_access_debug()1724 bool mofetta_device::intdsr_access_debug()
1725 {
1726 return m_txspg;
1727 }
1728
cruwrite(offs_t offset,uint8_t data)1729 void mofetta_device::cruwrite(offs_t offset, uint8_t data)
1730 {
1731 if ((offset & 0xff00)==0x2700)
1732 {
1733 if ((offset & 0x0002)!=0)
1734 {
1735 // SWRST (Software reset)
1736 // Value seems to be irrelevant
1737 LOGMASKED(LOG_CRU, "Doing a software reset by SBO 2702\n");
1738 m_mainboard->reset_console(ASSERT_LINE);
1739 m_mainboard->reset_console(CLEAR_LINE);
1740 }
1741 else
1742 {
1743 m_txspg = (data!=0); // CRU>2700
1744 LOGMASKED(LOG_CRU, "Turning %s CRU>2700\n", m_txspg? "on" : "off");
1745 }
1746 }
1747 else
1748 {
1749 if ((offset & 0xff00)==0x1700)
1750 {
1751 m_alcpg = (data!=0); // CRU>1700
1752 LOGMASKED(LOG_CRU, "Turning %s CRU>1700\n", m_alcpg? "on" : "off");
1753 }
1754 }
1755 }
1756
1757 /*
1758 Setting or clearing the MSAST line.
1759 */
WRITE_LINE_MEMBER(mofetta_device::msast_in)1760 WRITE_LINE_MEMBER( mofetta_device::msast_in )
1761 {
1762 if (state == ASSERT_LINE)
1763 {
1764 if (m_msast == CLEAR_LINE) // Leading edge
1765 {
1766 m_gotfirstword = true; // Process first word
1767 // We now have the first part, containing the flags and the upper byte.
1768 m_prefix = m_address_latch & 0xff;
1769 }
1770 }
1771 // TODO: Evaluate the first three bits
1772 m_msast = (line_state)state;
1773 }
1774
WRITE_LINE_MEMBER(mofetta_device::pmemen_in)1775 WRITE_LINE_MEMBER( mofetta_device::pmemen_in )
1776 {
1777 m_pmemen = (state==ASSERT_LINE);
1778 }
1779
WRITE_LINE_MEMBER(mofetta_device::lascs_in)1780 WRITE_LINE_MEMBER( mofetta_device::lascs_in )
1781 {
1782 m_lasreq = (state==ASSERT_LINE);
1783 }
1784
WRITE_LINE_MEMBER(mofetta_device::skdrcs_in)1785 WRITE_LINE_MEMBER( mofetta_device::skdrcs_in )
1786 {
1787 m_skdrcs = (state==ASSERT_LINE);
1788 }
1789
device_start()1790 void mofetta_device::device_start()
1791 {
1792 m_mainboard = downcast<mainboard8_device*>(owner());
1793
1794 save_item(NAME(m_pmemen));
1795 save_item(NAME(m_lasreq));
1796 save_item(NAME(m_skdrcs));
1797 save_item(NAME(m_gromclk_up));
1798 save_item(NAME(m_gotfirstword));
1799 save_item(NAME(m_address_latch));
1800 save_item(NAME(m_prefix));
1801 save_item(NAME(m_alcpg));
1802 save_item(NAME(m_txspg));
1803 save_item(NAME(m_rom1cs));
1804 save_item(NAME(m_rom1am));
1805 save_item(NAME(m_rom1al));
1806 save_item(NAME(m_alccs));
1807 save_item(NAME(m_prcs));
1808 save_item(NAME(m_cmas));
1809 save_item(NAME(m_gromclock_count));
1810 save_item(NAME(m_msast));
1811 }
1812
device_reset()1813 void mofetta_device::device_reset()
1814 {
1815 m_gotfirstword = false;
1816 m_alcpg = false;
1817 m_txspg = false;
1818 m_prefix = 0;
1819 }
1820
1821 /***************************************************************************
1822
1823 ==============================
1824 Mapper (codename "Amigo")
1825 ==============================
1826
1827 Unfortunately, we do not have logic diagrams for Amigo, so we have to
1828 guess how it is actually working.
1829
1830 Initial setting of mapper (as defined in the power-up routine, TI-99/4A mode)
1831
1832 0 00ff0000 -> Unmapped; logical address 0000...0fff = ROM0
1833 1 00ff0000 -> Unmapped; logical address 1000...1fff = ROM0
1834 2 00000800 -> DRAM; 2000 = 000800, 2fff = 0017ff
1835 3 00001800 -> DRAM; 3000 = 001800, 3fff = 0027ff
1836 4 00ff4000 -> DSR space (internal / ioport)
1837 5 00ff5000 -> DSR space (internal / ioport)
1838 6 00ff6000 -> Cartridge space (6000..6fff)
1839 7 00ff7000 -> Cartridge space (7000..7fff)
1840 8 00ff0000 -> Unmapped; device ports (VDP) and SRAM
1841 9 00ff0000 -> Unmapped; device ports (Speech, GROM)
1842 A 00002800 -> DRAM; a000 = 002800, afff = 0037ff
1843 B 00003800 -> DRAM; b000 = 003800, bfff = 0047ff
1844 C 00004800 -> DRAM; c000 = 004800, cfff = 0057ff
1845 D 00005800 -> DRAM; d000 = 005800, dfff = 0067ff
1846 E 00006800 -> DRAM; e000 = 006800, efff = 0077ff
1847 F 00007800 -> DRAM; f000 = 007800, ffff = 0087ff
1848
1849 Format of map table entry
1850
1851 +--+---+---+---+---+---+---+---+ +-----------+ +----------+ +---------+
1852 | W| X | R | 0 | 0 | 0 | 0 | 0 | | Upper (8) | | High (8) | | Low (8) |
1853 +--+---+---+---+---+---+---+---+ +-----------+ +----------+ +---------+
1854
1855 W: Write protection if set to 1
1856 X: Execute protection if set to 1
1857 R: Read protection if set to 1
1858
1859 When a protection violation occurs, the tms9901 INT1* pin is pulled low
1860 (active). The pin remains low until the mapper status register is read.
1861
1862 Address handling
1863 ----------------
1864 Physical address is (Upper * 2^16) + (High * 2^8) + Low
1865
1866 The mapper calculates the actual physical address by looking up the
1867 table entry from the first four bits of the logical address and then
1868 *adding* the remaining 12 bits of the logical address on the map value.
1869
1870 The value 0xff0000 is used to indicate a non-mapped area.
1871
1872 Mapper control register
1873 -----------------------
1874 The mapper control register is used to initiate a map load/save operation.
1875
1876 +---+---+---+---+---+---+---+---+
1877 | 0 | 0 | 0 | 0 | Map File | RW|
1878 +---+---+---+---+---+---+---+---+
1879
1880 The map file is a number from 0-7 indicating the set of map values for the
1881 operation, which means the location in SRAM where the next 64 values are
1882 loaded from or stored into.
1883
1884 RW = 1: load from SRAM into mapper
1885 RW = 0: store from mapper into SRAM
1886
1887 When read, the mapper register returns the violation flags:
1888 +---+---+---+---+---+---+---+---+
1889 | W | X | R | 0 | 0 | 0 | 0 | 0 |
1890 +---+---+---+---+---+---+---+---+
1891
1892 ***************************************************************************/
1893
amigo_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1894 amigo_device::amigo_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1895 : device_t(mconfig, TI99_AMIGO, tag, owner, clock),
1896 m_logical_space(true),
1897 m_crus(ASSERT_LINE)
1898 {
1899 }
1900
1901 enum
1902 {
1903 IDLE = 0,
1904 CREATE_PADDR,
1905 ADDR_MSW,
1906 ADDR_LSW,
1907 SRAMLOAD,
1908 SRAMSAVE
1909 };
1910
1911 /*
1912 Debugger support
1913 */
get_physical_address_debug(offs_t offset)1914 int amigo_device::get_physical_address_debug(offs_t offset)
1915 {
1916 return ((offset & 0x0fff) + m_base_register[(offset >> 12) & 0x000f]) & 0x00ffffff;
1917 }
1918
1919 /*
1920 Incoming READY line (SRDY)
1921 */
WRITE_LINE_MEMBER(amigo_device::srdy_in)1922 WRITE_LINE_MEMBER( amigo_device::srdy_in )
1923 {
1924 LOGMASKED(LOG_READY, "Incoming SRDY = %d\n", state);
1925 m_srdy = (line_state)state;
1926
1927 // If the access is going to logical space, pass through the READY line
1928 if (m_logical_space)
1929 {
1930 LOGMASKED(LOG_CPURY, "Setting CPURY = %d (SRDY)\n", m_ready_out);
1931 m_ready_out = m_srdy;
1932 }
1933 }
1934
WRITE_LINE_MEMBER(amigo_device::memen_in)1935 WRITE_LINE_MEMBER( amigo_device::memen_in )
1936 {
1937 m_memen = (state==ASSERT_LINE);
1938 }
1939
1940 /*
1941 Polled from the mainboard
1942 */
READ_LINE_MEMBER(amigo_device::cpury_out)1943 READ_LINE_MEMBER( amigo_device::cpury_out )
1944 {
1945 return m_ready_out;
1946 }
1947
1948 /*
1949 Polled from the mainboard
1950 */
READ_LINE_MEMBER(amigo_device::sramcs_out)1951 READ_LINE_MEMBER( amigo_device::sramcs_out )
1952 {
1953 return m_sram_accessed && m_memen? ASSERT_LINE : CLEAR_LINE;
1954 }
1955
1956 /*
1957 SKDRCS line (maybe "Sixty-four Kilobyte DRam Chip Select"). We assume that
1958 Amigo asserts the select line not before the whole address was written.
1959 This is actually more than needed because we only have 64K DRAM (which
1960 would only need a 16 bit address), and Amigo itself selects it.
1961 */
READ_LINE_MEMBER(amigo_device::skdrcs_out)1962 READ_LINE_MEMBER( amigo_device::skdrcs_out )
1963 {
1964 return m_dram_accessed && (m_amstate == IDLE) && m_memen? ASSERT_LINE : CLEAR_LINE;
1965 }
1966
1967 /*
1968 Incoming CRUS line. Needed to set the mapper config addresses.
1969 */
WRITE_LINE_MEMBER(amigo_device::crus_in)1970 WRITE_LINE_MEMBER( amigo_device::crus_in )
1971 {
1972 m_crus = (line_state)state;
1973 }
1974
1975 /*
1976 Incoming LASCS line.
1977 */
WRITE_LINE_MEMBER(amigo_device::lascs_in)1978 WRITE_LINE_MEMBER( amigo_device::lascs_in )
1979 {
1980 m_logical_space = (state==ASSERT_LINE);
1981 }
1982
1983 /*
1984 The logical address bus has been set. The Amigo chip now has to map this
1985 address to a physical address. There are three phases (3 clock ticks):
1986 1. Sample the logical address lines, determine the map register
1987 (first four bits), create the physical address by adding the remaining
1988 12 bits and the map register contents
1989 2. Set the physical address bus with the first 16 bits of the physical
1990 address. Assert the MSAST line.
1991 3. Set the physical address bus with the second 16 bits of the physical
1992 address. Clear the MSAST line. Forward any incoming READY=0 to the CPU.
1993 */
set_address(offs_t offset)1994 uint8_t amigo_device::set_address(offs_t offset)
1995 {
1996 // Check whether the mapper itself is accessed
1997 int mapaddr = (m_crus==ASSERT_LINE)? 0x8810 : 0xf870;
1998 m_mapper_accessed = ((offset & 0xfff1)==mapaddr);
1999
2000 // or SRAM
2001 int sramaddr = (m_crus==ASSERT_LINE)? 0x8000 : 0xf000;
2002 m_sram_accessed = ((offset & 0xf800)==sramaddr);
2003
2004 m_logical_space |= (m_mapper_accessed || m_sram_accessed);
2005
2006 // Is the address not in the logical address space?
2007 if (!m_logical_space)
2008 {
2009 LOGMASKED(LOG_AMIGO, "Amigo decoding; %04x is a physical address.\n", offset);
2010 // Build the physical address
2011 // The first three bits are the protection bits (Write, Execute, Read)
2012 // Theoretically, the addition of the logical address could mess up those
2013 // first three bits, but the physical address is only 24 bits wide, so we
2014 // have a space of 5 zeros between the protection bits and the address.
2015 // We should just clear those five bits after the addition.
2016
2017 m_physical_address = ((offset & 0x0fff) + m_base_register[(offset >> 12) & 0x000f]) & 0x00ffffff;
2018
2019 // TODO: Process flags
2020
2021 // Is it DRAM?
2022 m_dram_accessed = (m_physical_address & 0x00ff0000)==0;
2023
2024 // This takes one clock pulse.
2025 m_amstate = CREATE_PADDR;
2026
2027 // Pull down READY
2028 m_ready_out = CLEAR_LINE;
2029
2030 LOGMASKED(LOG_CPURY, "Setting CPURY = %d (PAS)\n", m_ready_out);
2031 }
2032 else
2033 {
2034 // This was a logical space access. Pass through READY.
2035 m_dram_accessed = false;
2036 m_amstate = IDLE;
2037 m_ready_out = m_srdy;
2038 LOGMASKED(LOG_CPURY, "Setting CPURY = %d (LAS)\n", m_ready_out);
2039 }
2040
2041 return 0;
2042 }
2043
2044 /*
2045 Read the mapper status bits
2046 */
read()2047 uint8_t amigo_device::read()
2048 {
2049 // Read the protection status bits and reset them
2050 uint8_t value = m_protflag;
2051 m_protflag = 0;
2052 return value;
2053 }
2054
2055 /*
2056 Configure the mapper. This is the only reason to write to the AMIGO.
2057 */
write(uint8_t data)2058 void amigo_device::write(uint8_t data)
2059 {
2060 // Load or save map file
2061 if ((data & 0xf0)==0x00)
2062 {
2063 // Need to HOLD the CPU
2064 m_amstate = ((data & 1)==1)? SRAMLOAD : SRAMSAVE;
2065 m_sram_address = (data & 0x0e) << 5;
2066 m_hold_acknowledged = false;
2067 m_basereg = 0;
2068 m_mapvalue = 0;
2069 m_mainboard->hold_cpu(ASSERT_LINE);
2070 }
2071 else LOGMASKED(LOG_WARN, "Invalid value written to Amigo: %02x\n", data);
2072 }
2073
WRITE_LINE_MEMBER(amigo_device::clock_in)2074 WRITE_LINE_MEMBER( amigo_device::clock_in )
2075 {
2076 if (state==CLEAR_LINE)
2077 {
2078 switch (m_amstate)
2079 {
2080 case IDLE:
2081 break;
2082 case CREATE_PADDR:
2083 // Address has been created
2084 m_amstate = ADDR_MSW;
2085 break;
2086 case ADDR_MSW:
2087 // Transmit the first word (without the protection bits)
2088 m_mainboard->set_paddress((m_physical_address >> 16) & 0x00ff);
2089 m_amstate = ADDR_LSW;
2090 break;
2091 case ADDR_LSW:
2092 m_mainboard->msast_in(ASSERT_LINE); // Pulse MSAST
2093 m_mainboard->msast_in(CLEAR_LINE);
2094 m_mainboard->set_paddress(m_physical_address & 0xffff);
2095 m_amstate = IDLE;
2096 m_ready_out = m_srdy; // Propagate incoming READY
2097 break;
2098
2099 case SRAMLOAD:
2100 if (m_hold_acknowledged) mapper_load();
2101 break;
2102
2103 case SRAMSAVE:
2104 if (m_hold_acknowledged) mapper_save();
2105 break;
2106
2107 default:
2108 LOGMASKED(LOG_WARN, "Invalid state in mapper: %d\n", m_amstate);
2109 }
2110 }
2111 }
2112
mapper_load()2113 void amigo_device::mapper_load()
2114 {
2115 m_mapvalue = (m_mapvalue << 8) | m_sram[m_sram_address++];
2116
2117 if ((m_sram_address & 0x03)==0)
2118 {
2119 LOGMASKED(LOG_MAP, "Loaded basereg %02d = %08x\n", m_basereg, m_mapvalue);
2120 m_base_register[m_basereg++] = m_mapvalue;
2121 }
2122 if (m_basereg == 16)
2123 {
2124 m_amstate = IDLE;
2125 m_mainboard->hold_cpu(CLEAR_LINE);
2126 }
2127 }
2128
mapper_save()2129 void amigo_device::mapper_save()
2130 {
2131 if ((m_sram_address & 0x03)==0)
2132 {
2133 if (m_basereg == 16)
2134 {
2135 m_amstate = IDLE;
2136 m_mainboard->hold_cpu(CLEAR_LINE);
2137 return;
2138 }
2139 else
2140 {
2141 m_mapvalue = m_base_register[m_basereg];
2142 LOGMASKED(LOG_MAP, "Saving basereg %02d = %08x\n", m_basereg, m_mapvalue);
2143 m_basereg++;
2144 }
2145 }
2146
2147 m_sram[m_sram_address++] = (m_mapvalue >> 24) & 0xff;
2148 m_mapvalue = m_mapvalue << 8;
2149 }
2150
2151 /*
2152 Debugger support
2153 */
mapper_access_debug(int data)2154 void amigo_device::mapper_access_debug(int data)
2155 {
2156 if ((data & 0xf0)==0x00)
2157 {
2158 int address = (data & 0x0e) << 5;
2159
2160 if ((data & 1)==1)
2161 {
2162 for (int i=0; i < 64; i++)
2163 {
2164 // Load from SRAM
2165 m_base_register[i/4] = (m_base_register[i/4] << 8) | (m_sram[address++] & 0xff);
2166 }
2167 }
2168 else
2169 {
2170 for (int i=0; i < 16; i++)
2171 {
2172 // Save to SRAM
2173 m_sram[address++] = (m_base_register[i] >> 24) & 0xff;
2174 m_sram[address++] = (m_base_register[i] >> 16) & 0xff;
2175 m_sram[address++] = (m_base_register[i] >> 8) & 0xff;
2176 m_sram[address++] = m_base_register[i] & 0xff;
2177 }
2178 }
2179 }
2180 }
2181
WRITE_LINE_MEMBER(amigo_device::holda_in)2182 WRITE_LINE_MEMBER( amigo_device::holda_in )
2183 {
2184 LOGMASKED(LOG_MAP, "HOLD acknowledged = %d\n", state);
2185 m_hold_acknowledged = (state==ASSERT_LINE);
2186 }
2187
device_start()2188 void amigo_device::device_start()
2189 {
2190 m_mainboard = downcast<mainboard8_device*>(owner());
2191
2192 std::fill(std::begin(m_base_register), std::end(m_base_register), 0);
2193
2194 save_item(NAME(m_memen));
2195 save_pointer(NAME(m_base_register),16);
2196 save_item(NAME(m_logical_space));
2197 save_item(NAME(m_physical_address));
2198 save_item(NAME(m_srdy));
2199 save_item(NAME(m_ready_out));
2200 save_item(NAME(m_crus));
2201 save_item(NAME(m_amstate));
2202 save_item(NAME(m_protflag));
2203 save_item(NAME(m_sram_accessed));
2204 save_item(NAME(m_dram_accessed));
2205 save_item(NAME(m_mapper_accessed));
2206 save_item(NAME(m_hold_acknowledged));
2207 save_item(NAME(m_sram_address));
2208 save_item(NAME(m_basereg));
2209 save_item(NAME(m_mapvalue));
2210 }
2211
device_reset()2212 void amigo_device::device_reset()
2213 {
2214 m_logical_space = true;
2215 }
2216
2217 /***************************************************************************
2218
2219 ===== OSO: Hexbus interface =====
2220
2221 The Hexbus is a 4-bit peripheral bus with master/slave coordination. Bytes
2222 are written over the bus in two passes. Hexbus was the designated standard
2223 peripheral bus for TI computers before TI left the home computer market.
2224
2225 Existing devices are floppy drive, RS232 serial adapter, and
2226 a "Wafertape" drive (kind of tape streamer)
2227
2228 Registers: Read Write Bits of register
2229 ----------------------------------------------------------------------------
2230 Data : 5FF8 - ADB3 ADB2 ADB1 ADB0 ADB3 ADB2 ADB1 ADB0
2231 Status : 5FFA - HSKWT HSKRD BAVIAS BAVAIS SBAV WBUSY RBUSY SHSK
2232 Control : 5FFC 5FFA WIEN RIEN BAVIAEN BAVAIEN BAVC WEN REN CR7
2233 Xmit : 5FFE 5FF8 XDR0 XDR1 XDR2 XDR3 XDR4 XDR5 XDR6 XDR7
2234
2235 ADBx = Hexbus data bit X
2236 HSKWT = Set when a byte has been sent over the bus and HSK has been asserted
2237 HSKRD = Set when a byte has been received
2238 BAVIAS = set when the BAV* signal (bus available) transits to active state
2239 BAVAIS = set when the BAV* signal transits to inactive state (=1)
2240 SBAV = set when BAV* = 0 (active)
2241 WBUSY = set when a write action is in progress (two transfers @ 4 bits)
2242 Reset when HSKWT is set
2243 RBUSY = set when a read action is in progress (two transfers @ 4 bits)
2244 Reset when HSKRD is set
2245 SHSK = set when HSK* is active (0)
2246
2247 WIEN = Enable interrupt for write completion
2248 RIEN = Enable interrupt for read completion
2249 BAVIAEN = BAVIA enable (slave mode)
2250 BAVAIEN = BAVAI enable (slave mode)
2251 BAVC = set BAV* line (0=active)
2252 WEN = set write enable (byte is written from xmit reg)
2253 REN = set read enable (latch HSK and read byte into data reg)
2254 CR7 = future extension
2255 XDRx = transmit register bit
2256
2257 Hexbus connector (console)
2258 +---+---+---+---+
2259 | 4 | 3 | 2 | 1 | 4 = L; 3 = BAV*; 2 = ADB1; 1 = ADB0
2260 +---+---+---+---+
2261 | 8 | 7 | 6 | 5 | 8 = ADB3; 7 = ADB2; 6 = nc; 5 = HSK*
2262 +---+---+---+---+
2263
2264 ****************************************************************************/
2265
oso_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)2266 oso_device::oso_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
2267 bus::hexbus::hexbus_chained_device(mconfig, TI99_OSO, tag, owner, clock),
2268 m_int(*this),
2269 m_hexbusout(*this, ":" TI998_HEXBUS_TAG),
2270 m_data(0),
2271 m_status(0xff),
2272 m_control(0),
2273 m_xmit(0),
2274 m_bav(false), m_sbav(false), m_sbavold(false), m_bavold(false),
2275 m_hsk(false), m_hsklocal(false), m_shsk(false), m_hskold(false),
2276 m_wq1(false), m_wq1old(false), m_wq2(false), m_wq2old(false),
2277 m_wnp(false), m_wbusy(false), m_wbusyold(false), m_sendbyte(false),
2278 m_wrset(false), m_counting(false), m_clkcount(0),
2279 m_rq1(false), m_rq2(false), m_rq2old(false),
2280 m_rnib(false), m_rnibcold(false),
2281 m_rdset(false), m_rdsetold(false),
2282 m_msns(false), m_lsns(false),
2283 m_rhsus(false), m_rbusy(false),
2284 m_phi3(false),
2285 m_oldvalue(0xff)
2286 {
2287 m_hexbus_inbound = nullptr;
2288 m_hexbus_outbound = nullptr;
2289 }
2290
read(offs_t offset)2291 uint8_t oso_device::read(offs_t offset)
2292 {
2293 int value = 0;
2294 offset &= 0x03;
2295 switch (offset)
2296 {
2297 case 0:
2298 // read 5FF8: read data register
2299 value = m_data;
2300 LOGMASKED(LOG_OSO, "Read data register = %02x\n", value);
2301 // Release the handshake
2302 m_rhsus = false;
2303 break;
2304 case 1:
2305 // read 5FFA: read status register
2306 value = m_status;
2307 clear_int_status();
2308 LOGMASKED(LOG_OSO, "Read status %02x (HSKWT=%d,HSKRD=%d,BAVIAS=%d,BAVAIS=%d,SBAV=%d,WBUSY=%d,RBUSY=%d,SHSK=%d)\n", value,
2309 (value&HSKWT)? 1:0, (value&HSKRD)? 1:0, (value&BAVIAS)? 1:0,
2310 (value&BAVAIS)? 1:0, (value&SBAV)? 1:0, (value&WBUSY)? 1:0,
2311 (value&RBUSY)? 1:0,(value&SHSK)? 1:0);
2312 break;
2313 case 2:
2314 // read 5FFC: read control register
2315 value = m_control;
2316 LOGMASKED(LOG_OSO, "Read control register = %02x\n", value);
2317 break;
2318 case 3:
2319 // read 5FFE: read transmit register
2320 value = m_xmit;
2321 LOGMASKED(LOG_OSO, "Read transmit register = %02x\n", value);
2322 break;
2323 }
2324 return value;
2325 }
2326
write(offs_t offset,uint8_t data)2327 void oso_device::write(offs_t offset, uint8_t data)
2328 {
2329 offset &= 0x03;
2330 switch (offset)
2331 {
2332 case 0:
2333 // write 5FF8: write transmit register
2334 LOGMASKED(LOG_OSO, "Write transmit register %02x\n", data);
2335
2336 // trigger some actions in the write subsystem
2337 m_sendbyte = true;
2338 if (!m_wq1)
2339 {
2340 m_wbusyold = true;
2341 set_status(WBUSY, true);
2342 }
2343
2344 m_xmit = data;
2345 break;
2346 case 1:
2347 // write 5FFA: write control register
2348 LOGMASKED(LOG_OSO, "Write control register %02x (WIEN=%d, RIEN=%d, BAVIAEN=%d, BAVAIEN=%d, BAVC=%d, WEN=%d, REN=%d)\n",
2349 data, (data & WIEN)? 1:0, (data & RIEN)? 1:0, (data&BAVIAEN)? 1:0, (data&BAVAIEN)? 1:0,
2350 (data & BAVC)? 1:0, (data & WEN)? 1:0, (data & REN)? 1:0);
2351 m_control = data;
2352 m_bav = control_bit(BAVC);
2353
2354 // Reset some flipflops in the write/read timing section
2355 if (!control_bit(WEN))
2356 {
2357 m_wq1 = m_wq2 = m_wrset = false;
2358 }
2359 if (!control_bit(REN))
2360 {
2361 m_rq1 = m_rq2 = m_rdset = false;
2362 }
2363 update_hexbus();
2364 break;
2365 default:
2366 // write 5FFC, 5FFE: undefined
2367 LOGMASKED(LOG_OSO, "Invalid write on %04x: %02x\n", (offset<<1) | 0x5ff0, data);
2368 break;
2369 }
2370 }
2371
clear_int_status()2372 void oso_device::clear_int_status()
2373 {
2374 m_status &= ~(HSKWT | HSKRD | BAVIAS | BAVAIS);
2375 m_int(CLEAR_LINE);
2376 }
2377
2378 /*
2379 Phi3 incoming clock pulse
2380 */
WRITE_LINE_MEMBER(oso_device::clock_in)2381 WRITE_LINE_MEMBER( oso_device::clock_in )
2382 {
2383 m_phi3 = state;
2384 if (state==ASSERT_LINE)
2385 {
2386 // Control lines SHSK, SBAV
2387 // When BAV/HSK is 0/1 for two rising edges of Phi3*, SBAV/SHSK goes to
2388 // 0/1 at the following falling edge of Phi3*.
2389 // Page 5
2390
2391 // In reality, the HSK and BAV signals are checked for their minimum
2392 // width (by waiting for two cycles of constant level), but due to
2393 // problems with synchronous execution between different parts in the
2394 // emulation, we accept the level change immediately.
2395
2396 m_sbav = m_bav; // could mean "stable BAV"
2397 // if (control_bit(WEN)) logerror("hskhold=%d, hsk=%d\n", m_hskhold? 1:0, m_hsk? 1:0);
2398
2399 m_shsk = m_hsk;
2400 set_status(SHSK, m_shsk);
2401 set_status(SBAV, m_sbav);
2402
2403 // Raising edge of SBAV*
2404 if (m_sbav == true && m_sbavold == false)
2405 set_status(BAVIAS, true);
2406 // Falling edge of SBAV*
2407 if (m_sbav == false && m_sbavold == true)
2408 set_status(BAVAIS, true);
2409 m_sbavold = m_sbav;
2410
2411 // Implement the write timing logic
2412 // This subcircuit in the OSO chip autonomously runs the Hexbus
2413 // protocol. After loading a byte into the transmit register, it sends
2414 // both nibbles (little-endian) one after another over the Hexbus,
2415 // pausing for 30 cycles, and checking the HSK line.
2416
2417 // The schematics show some fascinating signal line spaghetti with
2418 // embedded JK* flipflops which may give you some major headaches.
2419 // Compared to that, the lines below are a true relief.
2420
2421 if (control_bit(WEN)) // Nothing happens without WEN
2422 {
2423 if (!m_wrset && m_sendbyte)
2424 LOGMASKED(LOG_OSO, "Starting write process\n");
2425
2426 // Page 3: Write timing
2427 // Note: First pass counts to 30, second to 31
2428 bool cnt30 = ((m_clkcount & 0x1e) == 30);
2429 bool cont = (m_wrset && !m_wq2 && !m_wq1) || (cnt30 && m_wq2 && !m_wq1)
2430 || (cnt30 && !m_wq2 && m_wq1) || (m_shsk && m_wq2 && m_wq1);
2431
2432 bool jwq1 = cont && m_wq2;
2433 bool kwq1 = !(cont && !m_wq2) && !(!cont && m_wq2 && m_wnp);
2434
2435 bool jwq2 = cont;
2436 bool kwq2 = !(m_wq1 && !cont);
2437
2438 if (m_wq1 == m_wq2) m_clkcount = 0;
2439
2440 // Reset "byte loaded" flipflop during the second phase
2441 if (m_wq1 == true)
2442 m_sendbyte = false;
2443
2444 // logerror("sendbyte=%d, wq1=%d, wq2=%d, jwq1=%d, kwq1=%d, jwq2=%d, kwq2=%d\n", m_sendbyte, m_wq1, m_wq2, jwq1, kwq1, jwq2, kwq2);
2445 // logerror("sendbyte=%d, wq1=%d, wq2=%d, m_shsk=%d\n", m_sendbyte, m_wq1, m_wq2, m_shsk);
2446 // WBUSY is asserted on byte load, during phase 1, and phase 2.
2447 m_wbusy = m_sendbyte || m_wq1 || m_wq2;
2448
2449 // Set status bits and raise interrupt (p. 4)
2450 set_status(WBUSY, m_wbusy);
2451
2452 // Raising edge of wbusy*
2453 // This is true when the two nibbles of the byte have been written and acknowledged
2454 // by the receiver which has released HSK*
2455 if (m_wbusyold == true && m_wbusy == false)
2456 {
2457 LOGMASKED(LOG_HEXBUS, "Setting HSKWT to true\n");
2458 set_status(HSKWT, true);
2459 // Problem: By turning off the WBUSY signal, the transmit register goes inactive
2460 // so the peripheral setting dominates again. However, the peripheral sender will not
2461 // send its value again.
2462 }
2463 m_wbusyold = m_wbusy;
2464
2465 // Operate flipflops
2466 // Write phases
2467 // 74LS109: J-K* flipflop (inverted K)
2468 if (jwq1)
2469 {
2470 if (!kwq1) m_wq1 = !m_wq1;
2471 else m_wq1 = true;
2472 }
2473 else
2474 if (!kwq1) m_wq1 = false;
2475
2476 if (jwq2)
2477 {
2478 if (!kwq2) m_wq2 = !m_wq2;
2479 else m_wq2 = true;
2480 }
2481 else
2482 if (!kwq2) m_wq2 = false;
2483
2484 // Set WNP on rising edge of WQ2*
2485 if (m_wq2 != m_wq2old)
2486 {
2487 if (!m_wq2)
2488 m_wnp = true;
2489
2490 m_wq2old = m_wq2;
2491 }
2492 m_wq1old = m_wq1;
2493
2494 // Reset WNP if phases are done
2495 if (!m_wq2 && !m_wq1)
2496 {
2497 m_wnp = false;
2498 }
2499 }
2500
2501 // This is the reading behavior. In this case, the master (this
2502 // component) pulls down BAV*, then the slave sets the data lines
2503 // with the back nibble, pulls down HSK*, then releases HSK*,
2504 // puts the front nibble on the data lines, pulls down HSK* again,
2505 // releases it, and this continues until the master releases BAV*
2506
2507 if (control_bit(REN))
2508 {
2509 bool rdsetin = !status_bit(WBUSY) && m_sbav && m_shsk;
2510 bool next = (m_rdset && !m_rq2) || (m_shsk && m_rq2);
2511 bool drq1 = (next && m_rq2) || (m_rq2 && m_rq1 && !m_rnib);
2512 bool jrq2 = next && !m_rq1;
2513 bool krq2 = !m_rq1 || m_rnib;
2514 bool rnibc = m_rq1;
2515
2516 //logerror("n=%d,d1=%d,j2=%d,k2=%d,rn=%d\n", next, drq1, jrq2, krq2, m_rnib);
2517 // Next state
2518 if (!m_rdsetold && rdsetin)
2519 {
2520 m_rdset = true; // raising edge
2521 }
2522 m_rdsetold = rdsetin;
2523 // logerror("rdset=%d, rdsetin=%d\n", m_rdset, rdsetin);
2524
2525 // Set the RQ1 flipflop
2526 m_rq1 = drq1;
2527
2528 // Set the RQ2 flipflop
2529 if (jrq2)
2530 {
2531 if (!krq2) m_rq2 = !m_rq2;
2532 else m_rq2 = true;
2533 }
2534 else
2535 if (!krq2) m_rq2 = false;
2536
2537 if (m_rq2) m_rdset = false;
2538
2539 // Set the rnib flipflop. This is in sequence to the RQ1 flipflop.
2540 rnibc = m_rq1;
2541 if (m_rnibcold == false && rnibc == true) // raising edge
2542 m_rnib = !m_rnib;
2543
2544 m_rnibcold = rnibc;
2545
2546 // Debugging only
2547 // next = (m_rdset && !m_rq2) || (m_shsk && m_rq2);
2548 // drq1 = (next && m_rq2) || (m_rq2 && m_rq1 && !m_rnib);
2549 // jrq2 = next && !m_rq1;
2550 // krq2 = !m_rq1 || m_rnib;
2551 // logerror("r=%d,n=%d,rn=%d,d1=%d,j2=%d,k2=%d,q1=%d,q2=%d\n", m_rdset, next, m_rnib, drq1, jrq2, krq2, m_rq1, m_rq2);
2552
2553 // Set RBUSY
2554 bool rbusy = m_rq1 || m_rq2;
2555
2556 if (rbusy != m_rbusy)
2557 LOGMASKED(LOG_HEXBUS, "RBUSY=%d\n",rbusy);
2558
2559 m_rbusy = rbusy;
2560 set_status(RBUSY, rbusy);
2561
2562 // Flipflop resets
2563 if (!rbusy) m_rnib = false;
2564
2565 bool msns = m_rnib && !m_rq1 && m_rq2;
2566 bool lsns = !m_rnib && !m_rq1 && m_rq2;
2567
2568 // if (msns != m_msns) LOGMASKED(LOG_HEXBUS, "MSNS=%d\n", msns);
2569 // if (lsns != m_lsns) LOGMASKED(LOG_HEXBUS, "LSNS=%d\n", lsns);
2570
2571 m_lsns = lsns;
2572 m_msns = msns;
2573
2574 // Raising edge of RQ2*
2575 if (m_rq2old == true && m_rq2 == false)
2576 {
2577 LOGMASKED(LOG_HEXBUS, "Byte available for reading\n");
2578 set_status(HSKRD, true);
2579 m_rhsus = true; // byte is available for reading
2580 }
2581 m_rq2old = m_rq2;
2582 }
2583 else
2584 {
2585 m_rhsus = false;
2586 }
2587
2588 // Handshake control
2589 // Set HSK (Page 6, RHSUS*)
2590 // This is very likely an error in the schematics. It does not make
2591 // sense, and simulations show that the behaviour would be wrong.
2592 // bool hskwrite = !m_wq1 && m_wq2;
2593 bool hskwrite = (m_wq1 != m_wq2);
2594
2595 // We can simplify this to a single flag because the CPU read operation
2596 // is atomic here (starts and immediately terminates)
2597 m_hsklocal = hskwrite || m_rhsus;
2598 update_hexbus();
2599 }
2600 // Actions that occur for Phi3=0
2601 else
2602 {
2603 m_wrset = m_sendbyte;
2604 // Only count when one phase is active
2605 m_counting = !(m_wq1==m_wq2);
2606
2607 if (m_counting)
2608 m_clkcount++;
2609 else
2610 m_clkcount = 0; // Reset when not counting
2611 }
2612
2613 // Flipflop resets (not related to clock)
2614 if (!control_bit(WEN))
2615 {
2616 m_wq1 = m_wq2 = m_wrset = m_counting = false;
2617 m_clkcount = 0;
2618 }
2619 if (!control_bit(REN))
2620 {
2621 m_rq1 = m_rq2 = m_rdset = false;
2622 }
2623
2624 // Raise interrupt
2625 if ((control_bit(WIEN) && status_bit(HSKWT))
2626 || (control_bit(RIEN) && status_bit(HSKRD))
2627 || (control_bit(BAVAIEN) && status_bit(BAVAIS))
2628 || (control_bit(BAVIAEN) && status_bit(BAVIAS)))
2629 {
2630 m_int(ASSERT_LINE);
2631 }
2632 }
2633
2634 /*
2635 Change the Hexbus line levels and propagate them towards the peripherals.
2636 */
update_hexbus()2637 void oso_device::update_hexbus()
2638 {
2639 bool changed = false;
2640 if (m_hsklocal != m_hskold)
2641 {
2642 LOGMASKED(LOG_HEXBUS, "%s HSK*\n", m_hsklocal? "Pulling down" : "Releasing");
2643 m_hskold = m_hsklocal;
2644 changed = true;
2645 }
2646
2647 if (m_bav != m_bavold)
2648 {
2649 LOGMASKED(LOG_HEXBUS, "%s BAV*\n", m_bav? "Pulling down" : "Releasing");
2650 m_bavold = m_bav;
2651 changed = true;
2652 }
2653
2654 if (!changed) return;
2655
2656 // If wbusy==false, set the data output to 1111; since the Hexbus is
2657 // a pull-down line bus, this means to inactivate the output
2658 uint8_t nibble = m_wbusy? m_xmit : 0xff;
2659 if (m_wnp) nibble >>= 4;
2660
2661 uint8_t value = to_line_state(nibble, control_bit(BAVC), m_hsklocal);
2662
2663 // if (m_oldvalue != value)
2664 // LOGMASKED(LOG_OSO, "Set hexbus = %02x (BAV*=%d, HSK*=%d, data=%01x)\n", value, (value & 0x04)? 1:0, (value & 0x10)? 1:0, ((value>>4)&0x0c) | (value&0x03));
2665
2666 // As for Oso, we can be sure that hexbus_write does not trigger further
2667 // activities from the peripherals that cause a call to hexbus_value_changed.
2668 hexbus_write(value);
2669
2670 // Check how the bus has changed. This depends on the states of all
2671 // connected peripherals
2672
2673 // Update the state of BAV and HSK
2674 m_bav = (bus_bav_level()==ASSERT_LINE);
2675 m_hsk = (bus_hsk_level()==ASSERT_LINE);
2676
2677 // Sometimes, Oso does not have a chance to advance its state after the
2678 // last byte was read. In that case, a change of rdsetin would not be
2679 // sensed. We reset the flag right here and so pretend that the tick
2680 // has happened.
2681 if (m_hsk==false) m_rdsetold = false;
2682
2683 m_oldvalue = m_current_bus_value;
2684 }
2685
2686 /*
2687 Called when the value on the Hexbus has changed.
2688 */
hexbus_value_changed(uint8_t data)2689 void oso_device::hexbus_value_changed(uint8_t data)
2690 {
2691 // LOGMASKED(LOG_OSO, "Hexbus value changed to %02x\n", data);
2692 bool bav = (bus_bav_level()==ASSERT_LINE);
2693 bool hsk = (bus_hsk_level()==ASSERT_LINE);
2694
2695 if ((bav != m_bav) || (hsk != m_hsk))
2696 {
2697 m_bav = bav | control_bit(BAVC);
2698 m_hsk = hsk;
2699
2700 LOGMASKED(LOG_HEXBUS, "BAV*=%d, HSK*=%d\n", m_bav? 0:1, m_hsk? 0:1);
2701 int nibble = data_lines(data);
2702
2703 // The real devices are driven at a similar clock rate like the 99/8.
2704 // The designers assumed that there is a clock tick of Oso between
2705 // every clock tick of the peripheral device. This is not true for
2706 // the emulation in MAME, however. For that reason, we trigger "fake"
2707 // clock ticks on every change of the hexbus.
2708 for (int fake=0; fake < 4; fake++)
2709 {
2710 if (m_msns)
2711 {
2712 m_data = (m_data & 0x0f) | (nibble<<4);
2713 LOGMASKED(LOG_HEXBUS, "Data register = %02x\n", m_data);
2714 }
2715 if (m_lsns)
2716 {
2717 m_data = (m_data & 0xf0) | nibble;
2718 LOGMASKED(LOG_HEXBUS, "Data register = %02x\n", m_data);
2719 }
2720
2721 LOGMASKED(LOG_HEXBUS, "Fake tick %d\n", fake);
2722 bool phi3 = m_phi3; // mind that clock_in swaps the state of m_phi3
2723 clock_in(!phi3);
2724 clock_in(phi3);
2725 LOGMASKED(LOG_HEXBUS, "Fake tick %d end\n", fake);
2726 }
2727 }
2728 else
2729 {
2730 LOGMASKED(LOG_HEXBUS, "No change for BAV* and HSK*\n");
2731 }
2732 }
2733
device_start()2734 void oso_device::device_start()
2735 {
2736 m_status = m_xmit = m_control = m_data = 0;
2737 m_int.resolve_safe();
2738
2739 // Establish the downstream link in the parent class hexbus_chained_device
2740 set_outbound_hexbus(m_hexbusout);
2741
2742 // Establish callback for inbound propagations
2743 m_hexbus_outbound->set_chain_element(this);
2744
2745 save_item(NAME(m_data));
2746 save_item(NAME(m_status));
2747 save_item(NAME(m_control));
2748 save_item(NAME(m_xmit));
2749 }
2750
2751 } } } // end namespace bus::ti99::internal
2752
2753