summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Michael Zapf <github@mizapf.de>2019-12-27 20:03:07 +0100
committer Michael Zapf <github@mizapf.de>2019-12-27 20:03:07 +0100
commit5aaa481d0f97c6da69472255a81d5e69187ae190 (patch)
tree94449aee6ec8dfe6d23cd2a703111a76a2386880
parent84d8241556b5b205394d75ca55f57244a38f9166 (diff)
geneve: Lower-level emulation of the Geneve architecture (Gate Array, PAL, Genmod daughterboard); correct Genmod adaptation of the peribox cards; RESET line in ioport and peribox
-rw-r--r--src/devices/bus/ti99/internal/genboard.cpp1904
-rw-r--r--src/devices/bus/ti99/internal/genboard.h276
-rw-r--r--src/devices/bus/ti99/internal/ioport.cpp6
-rw-r--r--src/devices/bus/ti99/internal/ioport.h2
-rw-r--r--src/devices/bus/ti99/peb/bwg.cpp17
-rw-r--r--src/devices/bus/ti99/peb/evpc.cpp14
-rw-r--r--src/devices/bus/ti99/peb/hfdc.cpp21
-rw-r--r--src/devices/bus/ti99/peb/horizon.cpp46
-rw-r--r--src/devices/bus/ti99/peb/horizon.h4
-rw-r--r--src/devices/bus/ti99/peb/memex.cpp29
-rw-r--r--src/devices/bus/ti99/peb/pcode.cpp14
-rw-r--r--src/devices/bus/ti99/peb/peribox.cpp51
-rw-r--r--src/devices/bus/ti99/peb/peribox.h18
-rw-r--r--src/devices/bus/ti99/peb/samsmem.cpp6
-rw-r--r--src/devices/bus/ti99/peb/spchsyn.cpp33
-rw-r--r--src/devices/bus/ti99/peb/spchsyn.h6
-rw-r--r--src/devices/bus/ti99/peb/ti_fdc.cpp14
-rw-r--r--src/devices/bus/ti99/peb/ti_rs232.cpp15
-rw-r--r--src/devices/bus/ti99/peb/tn_ide.cpp14
-rw-r--r--src/devices/bus/ti99/peb/tn_usbsm.cpp14
-rw-r--r--src/mame/drivers/geneve.cpp1097
-rw-r--r--src/mame/drivers/ti99_4p.cpp2
-rw-r--r--src/mame/drivers/ti99_4x.cpp62
-rw-r--r--src/mame/drivers/ti99_8.cpp3
24 files changed, 2129 insertions, 1539 deletions
diff --git a/src/devices/bus/ti99/internal/genboard.cpp b/src/devices/bus/ti99/internal/genboard.cpp
index 773aa0ef217..1f77e482080 100644
--- a/src/devices/bus/ti99/internal/genboard.cpp
+++ b/src/devices/bus/ti99/internal/genboard.cpp
@@ -1,14 +1,13 @@
// license:LGPL-2.1+
// copyright-holders:Michael Zapf
/***************************************************************************
- Geneve 9640 Gate Array and more components
+ Geneve 9640 Gate Array, PAL, and Genmod daughterboard
This file contains the emulation of the gate array and of the PAL chip
that is used to control wait state generation.
Pins of the Gate Array:
-
- in: AMC, AMB, AMA, A0..A15: Address bus
+ in: A0..A15: Address bus
in: CLKOUT
in: IAQ/HOLDA
in?: NMI*
@@ -36,7 +35,8 @@
out: RAMENX*: SRAM expansion
out: RAMEN*: SRAM
out: ROMEN*: EPROM
- out: AB0, AB1, AB2: Mapped address bits
+ out: AB0, AB1, AB2: Mapped address bits (2^15, 2^14, 2^13)
+ out: AMC, AMB, AMA: Higher address bits (2^18, 2^17, 2^16)
in: DBIN*
? : ABUS* / HOLDA
out: DBIN
@@ -48,88 +48,219 @@
out: WE* / CRUCLK
out: PhiCLK: System clock for 9901
- Onboard SRAM configuration:
- There is an adjustable SRAM configuration on board, representing the
- various enhancements by users.
-
- The standard memory configuration as reported by chkdsk (32 KiB):
- 557056 bytes of total memory
+ Onboard SRAM configuration
+ ==========================
- With 64 KiB SRAM:
- 589824 bytes of total memory
+ Earlier versions of this emulation allowed for up to 384 KiB of SRAM.
+ However, this did not reflect the technical options of the real device.
+ In fact, there are only two select lines (RAMEN*, RAMEN-X*) that each
+ select one SRAM chip of 32 KiB capacity. Accordingly, we now only offer
+ the optional 32K expansion.
+
+ Measurements on the real system proved that the zero waitstate access
+ is only available for the banks of stock and expansion SRAM, not for
+ the other areas (including the EPROM).
+
+ The later operating systems of the Geneve (starting with 2.50s)
+ assume the 32K expansion to be available. For this reason, this option is
+ selected by default.
+
+ Higher amounts of SRAM require extensive changes to the hardware (also
+ with respect to the wait state generation).
+
+ Geneve mapper
+ ============
+
+ In the Gate Array, a set of 8 map registers is used to expand the logical
+ address to a physical address of 21 bits length. This is done by defining
+ frames of 8 KiB size (13 bits); the most significant 3 bits select the
+ map register, and its 8 bits are then prepended to the offset.
+
+ Logical address:
+ fffx xxxx xxxx xxxx
+ \|/
+ | Map registers
+ +--> 000: pppp pppp ---> Physical address (21 bits):
+ 001: pppp pppp p pppp pppx xxxx xxxx xxxx
+ 010: pppp pppp
+ ...
+ 111: pppp pppp = 000000 ... 1FFFFF (2 MiB space)
+
+ The map registers are memory-mapped into the logical address space
+ (Geneve mode: F110..F117, TI mode: 8000..8007) and set by writing the
+ bytes into them.
+
+ AMA/B/C decoding
+ ================
+
+ Since TI decided, for some obscure reason, to order the address bits in the
+ direction from MSB to LSB, the highest address bit is called A0. This
+ raises the problem that higher address bits lack a proper number (you
+ don't want to use negative numbers for sure). The Peripheral Expansion Box
+ already has three additional address lines: AMA (for the 2^16 position),
+ AMB (2^17), AMC (2^18).
+
+ The Flex Cable Interface (the card that allows the TI-99/4A console to
+ be connected to the Peribox) sets these bits to 1. The Geneve, however,
+ may use these lines to expand the usual 64K address space.
+
+ The classic Peribox cards check ABA/B/C for being set to 1. Since all
+ addresses starting with 00 or 01 are routed to the Geneve main board
+ itself, and the 11 prefix is reserved for SRAM and the Boot EPROM, the
+ 64K address range of the Peribox cards is on map values 10 111 xxx, which
+ means pages b8..bf. As the DSR (Device Service Routine, the card firmware)
+ is expected on logical addresses 4000-5FFF, this corresponds to the page 0xba.
+
+ A problem occurs with some 3rd party expansion cards which do not check
+ AMA/B/C=1. In a normal TI system, this would have no effect anyway, but
+ with the Geneve this leads to mirroring. The usual DSR space at 4000-5fff
+ which would be reachable via page 0xba is then mirrored on a number of
+ other pages:
- With 384 KiB SRAM:
- 917504 bytes of total memory
+ 10 xxx 010x = 82, 8a, 92, 9a, a2, aa, b2, ba
- The original 32 KiB SRAM memory needs to be expanded to 64 KiB for
- MDOS 2.50s and higher, or the system will lock up. Therefore the emulation
- default is 64 KiB.
+ Another block to take care of is 0xbc which covers 8000-9fff since this
+ area contains the speech synthesizer port at 9000/9400.
- The ultimate expansion is a 512 KiB SRAM circuit wired to the gate array
- to provide 48 pages of fast static RAM. This also requires to build an
- adapter for a larger socket. From the 512 KiB, only 384 KiB will be
- accessed, since the higher pages are hidden behind the EPROM pages.
+ Address map
+ ===========
- === Address map ===
p,q = page value bit (q = AMC, AMB, AMA)
c = address offset within 8 KiB page
p pqqq pppc cccc cccc cccc
- 0 0... .... .... .... .... on-board dram 512 KiB
-
+ 0 .... .... .... .... .... on-board bus (external drivers inactive)
+ 0 0... .... .... .... .... on-board DRAM 512 KiB
0 1... .... .... .... .... on-board future expansion 512 KiB or Memex with Genmod
- 1 00.. .... .... .... .... p-box AMA=0 (256 KiB)
- 1 010. .... .... .... .... p-box AMA=1 AMB=0 (128 KiB)
- 1 0110 .... .... .... .... p-box AMA=1 AMB=1 AMC=0 (64 KiB)
+ 1 0... .... .... .... .... external bus (p-box)
+ 1 0111 .... .... .... .... p-box (AMA/B/C=1)
+ 1 0111 000. .... .... .... address block 0xxx
+ 1 0111 001. .... .... .... address block 2xxx
+ 1 0111 010. .... .... .... address block 4xxx (DSR)
+ 1 0111 011. .... .... .... address block 6xxx
+ 1 0111 100. .... .... .... address block 8xxx (Speech at 0x9000)
+ 1 0111 101. .... .... .... address block axxx
+ 1 0111 110. .... .... .... address block cxxx
+ 1 0111 111. .... .... .... address block exxx
- 1 0111 00.. .... .... .... p-box address block 0xxx, 2xxx
- 1 0111 010. .... .... .... p-box address block 4xxx (DSR)
- 1 0111 011. .... .... .... p-box address block 6xxx
- 1 0111 100. .... .... .... p-box address block 8xxx (Speech at 0x9000)
- 1 0111 101. .... .... .... p-box address block axxx
- 1 0111 11.. .... .... .... p-box address block cxxx, exxx
+ 1 1... .... .... .... .... on-board bus or external bus (unclear)
+ 1 10.. .... .... .... .... Future expansion
+ 1 1100 .... .... .... .... Future expansion
- 1 100. .... .... .... .... on-board sram (128K) -\
- 1 101. .... .... .... .... on-board sram (128K) --+- maximum SRAM expansion
- 1 1100 .... .... .... .... on-board sram (64K) --/
- 1 1101 0... .... .... .... on-board sram (32K) - additional 32 KiB required for MDOS 2.50s and higher
- 1 1101 1... .... .... .... on-board sram (32K) - standard setup
+ 1 1101 0... .... .... .... on-board sram (32K) - Optional 32 KiB expansion, 0 WS
+ 1 1101 1... .... .... .... on-board sram (32K) - stock 32 KiB SRAM, 0 WS
1 111. ..0. .... .... .... on-board boot1
1 111. ..1. .... .... .... on-board boot2
- The TI console (or more precise, the Flex Cable Interface) sets the AMA/B/C
- lines to 1. Most cards actually check for AMA/B/C=1. However, this decoding
- was forgotten in third party cards which cause the card address space
- to be mirrored. The usual DSR space at 4000-5fff which would be reachable
- via page 0xba is then mirrored on a number of other pages:
- 10 xxx 010x = 82, 8a, 92, 9a, a2, aa, b2, ba
+ Address operation
+ =================
- Another block to take care of is 0xbc which covers 8000-9fff since this
- area contains the speech synthesizer port at 9000/9400.
+ For DRAM access, a separate address bus between the Gate Array and the
+ DRAM circuits is used. The address bus has a width of 9 bits, which makes
+ it 18 bit for the whole address (row/column). Also, two CAS* lines are
+ used, selecting one set of DRAMs.
+
+ For SRAM access, the least significant two map value bits (AB1, AB2)
+ are prepended to the 13 bits of the offset from the logical address.
+ The next bit (AB0) controls the RAMEN* / RAMENX* lines.
+
+ For the EPROM access, the least significant bit of the map value is
+ prepended to the 13 bits of the offset from the logical address. This
+ yields a boot ROM size of 16K, mirrored on pages f0, f2, ..., fe, and
+ f1, f3, ..., ff. Bigger EPROMs (or flash memory, see PFM) require to use
+ the remaining bits AB1, AB0, and AMA.
+
+ The external bus is selected by the two most significant map bits 10.
+
+
+ GROM emulation and cartridge ROM space
+ ======================================
+
+ The Gate Array emulates a 64K GROM space in order to allow TI-99/4A
+ cartridge images to be run on the Geneve in TI mode. Also, two 8K ROM
+ pages are reserved to allow for emulating Extended Basic type cartridges.
+
+ In TI mode, pages 38 to 3f constitute the 64K GROM space. Pages 36 and 37
+ are the two 8K ROM banks. All are located in DRAM with 1 WS. Page 36
+ (or page 37) is mapped to logical space 6000-7FFF, regardless of the
+ mapper value at 8003 (can be set to any value without effect).
- For the standard Geneve, only prefix 10 is routed to the P-Box. The Genmod
- modification wires these address lines to pins 8 and 9 in the P-Box as AMD and
- AME. This requires all cards to be equipped with an additional selection logic
- to detect AMD=0, AME=1. Otherwise these cards, although completely decoding the
- 19-bit address, would reappear at 512 KiB distances.
+ CRU address >1EF8 determines the ROM size (1 or 2 banks):
+ 0 = 1 bank (page 36, fixed)
+ 1 = 2 banks (page 36 when writing a byte to 6000, 6004, ...,
+ page 37 when writing a byte to 6002, 6006, ...)
+
+ CRU address >1EFA write-protects 6000-6FFF when set to 0.
+ CRU address >1EFC write-protects 7000-7FFF when set to 0.
+ Both do not apply for 2-bank settings.
+
+ As with every page, the GROM pages may be mapped to any other memory
+ area as well so that they may be randomly accessed.
+
+ Unlike the real GROM, the GROM emulation allows free access to the whole
+ 8K of its page. Also, the emulation allows writing, so we essentially
+ have a GRAM emulation.
+
+ The Gate Array contains a 16-bit counter that represents the current
+ GROM address. It wraps at 8K boundaries (>3FFE->3FFF->2000->2001). Reading
+ from the GROM read port delivers the byte at the current address and
+ increases the counter. Writing to the GROM port stores the byte at that
+ address, respectively, and then increases the counter.
+
+ Reading the address counter delivers first the MSB, then on every
+ following access, the LSB. The counter itself contains the LSB in both
+ bytes after the first read operation. Thus, its value must be restored
+ after reading.
+
+ Setting the address counter copies its LSB to the MSB and then writes
+ the new byte into the LSB. After the second write (without intermediate
+ data transfer), the counter is increased by one.
+
+
+ Genmod expansion
+ ================
+
+ The objective of the Genmod is to allow the Geneve to access the full
+ 2 MiB physical address space, in conjunction with the MEMEX card that
+ must be plugged into the p-box. There are actually two lines in the box
+ that are unused; those are now defined as AMD and AME. They are located
+ on the p-box bus on pins 8 and 9.
+
+ Since the Gate Array does not output the first two address bits, they have
+ to be reconstructed by two GAL chips on a daughterboard that must be
+ soldered to the backside of the Gate Array.
+
+ When ROMEN is active, the on-board EPROM is accessed, and the external
+ bus is inactive.
+
+ The MEMEX card allows for using 0 waitstate accesses. This means that
+ the wait state generation for box accesses must be inhibited; this is
+ done by cutting the trace from the Gate Array pin READY to the PAL.
+
+ Some peripheral cards must now be modified to check for AMD and AME
+ as well, or they will be mirrored into other memory areas.
+ This GenMod feature is automatically applied to all peripheral cards in
+ this emulation.
+
+ The only remaining issue is that GROM access in the TI mode is under
+ full control of the Gate Array; it will always activate one of the DRAM
+ banks. To change this, the GA would need to be fully replaced. Instead,
+ the real GenMod contains a small box with two switches, which is also
+ emulation here:
- Genmod's double switch box is also emulated. There are two switches:
- Turbo mode: Activates or deactivates the wait state logic on the Geneve
board. This switch may be changed at any time.
- TI mode: Selects between the on-board memory, which is required
- for the GPL interpreter, and the external Memex memory. This switch
+ for the GROM access, and the external Memex memory. This switch
triggers a reset when changed.
- ===================
- Mapping
- ===================
-
- Logical address space: 64 KiB
+ Logical address space layout
+ ============================
Geneve mode
-----------
@@ -154,13 +285,13 @@
Mapper: 8000 - 8007 1000 0000 0000 0xxx
Keyboard: 8008 - 800F 1000 0000 0000 1...
Clock: 8010 - 801F 1000 0000 0001 xxxx
+ Sound: 8400 - 87FE 1000 01.. .... ...0
Speech: 9000 / 9400 1001 0w.. .... ...0
Grom: 9800 / 9802 1001 1w.. .... ..x0
9c00 / 9c02
- Physical address space
- ----------------------
- Address space size = 2 MiB
+ Physical address space layout
+ -----------------------------
Start End Phys.pages
000000 - 07FFFF 00-3F 512 KiB DRAM on-board
@@ -169,7 +300,9 @@
080000 - 0FFFFF 40-7F 512 KiB on-board expansion (never used)
100000 - 16FFFF 80-B7 448 KiB P-Box space (special cards, like MEMEX)
170000 - 17FFFF B8-BF 64 KiB P-Box space (current cards)
- 180000 - 1DFFFF C0-EF 384 KiB SRAM space on-board; stock Geneve comes with 32 KiB
+ 180000 - 1CFFFF C0-E7 Future expansion
+ 1D0000 - 1D7FFF E8-EB 32 KiB SRAM expansion
+ 1D8000 - 1DFFFF EC-EF 32 KiB stock SRAM
1E0000 - 1FFFFF F0-FF 128 KiB EPROM space; 16 KiB actually used, 8 mirrors
@@ -187,7 +320,7 @@
1E0000 - 1FFFFF F0-FF 128 KiB EPROM space; 16 KiB actually used, 8 mirrors
Waitstate handling
- ------------------
+ ==================
Waitstates are caused by a cleared READY line of the TMS9995 processor
during an external memory cycle. That means that waitstates have no effect
for operations within the on-chip memory, and only when an access to the
@@ -197,54 +330,83 @@
and the PAL 16R4, both lacking proper documentation. All of the following
numbers have been determined by experiments with the real machine.
- Waitstates are generated for:
- - memory-mapped devices (mapper, clock, keyboard): 1 WS
- - accesses to the peripheral expansion box: 1 WS
- - accesses to on-board DRAM: 1 WS
- - accesses to video: 15 WS
- - accesses to SRAM: 0 WS
+ Waitstates are generated for all accesses except for the SRAM in pages
+ E8..EF. Video accesses produce 15 waitstates, created by the counter
+ in the PAL. However, these video wait states are effective after the video
+ access has been completed. Wait states are not effective when the
+ execution is running in on-chip RAM.
+ Without additional wait states, the video access takes the usual 1 or 2 WS.
Additional waitstates are created when one of the CRU bits is set. In that
case, all delays are extended to 2 WS (including SRAM).
- Sound waitstates are somewhat unpredictable. It seems as if they depend
- on the clock of the sound chip; the READY line is pulled down until the
- next clock pulse, which may take some value between 18 CPU cycles and
- 30 CPU cycles.
-
- The gate array is able to create wait states for video accesses. However,
- these wait states are effective after the video access has been completed.
- Wait states are not effective when the execution is running in on-chip
- RAM. Additional wait states are requested by m_video_waitstates = true.
- Without additional wait states, the video access takes the usual 1 or 2 WS.
-
- Waitstate behavior (Nov 2013)
- Almost perfect. Only video read access from code in DRAM is too fast
- by one WS
-
- ==========================
- PFM expansion
- ==========================
-
- The "Programmable Flash Memory expansion" is a replacement for the boot
- EPROM.
-
- PFM: Original version, 128 KiB
- PFM+: Expansion of the original version, piggybacked, adds another 128KiB
- PFM512: Using an AT29C040 (not A), 512 KiB
-
- The PFM is visible as four banks in memory pages 0xF0 - 0xFF.
-
- Bank switching is done by four 9901 pins:
-
- 0028: LSB of bank number
- 003A: MSB of bank number
-
- Bank 0 is the boot code, while banks 1-3 can be used as flash drives
+ Sound waitstates depend on the clock of the sound chip; the READY line is
+ pulled down until the next clock pulse.
+
+
+ CRU map
+ =======
+ ---- TMS 9901 ----
+ 0000: flag Clock mode
+ 0002: int INTA* (pbox pin 17)
+ 0004: int Video interrupt
+ 0006: in Joystick button
+ 0008: in left
+ 000A: in right
+ 000C: in down
+ 000E: in up
+ 0010: int Keyboard scancode available
+ 0012: in (mirror of 003A)
+ 0014: in Left mouse button
+ 0016: in Real-time clock interrupt
+ 0018: in INTB* (pbox pin 18)
+ 001A: in (reflects 0032)
+ 001C: -
+ 001E: in (reflects 002E)
+ 0020: out Pbox reset
+ 0022: out Video reset
+ 0024: out Joystick select (0=Joystick 1, 1=Joystick 2)
+ 0026: -
+ 0028: out PFM bank switch LSB
+ 002A: out PFM output enable
+ 002C: out Keyboard reset
+ 002E: out System clock speed (external memory cycles)
+ 0030: -
+ 0032: out Video wait state enable
+ 0034: in (mirror of 0018)
+ 0036: in (mirror of 0016)
+ 0038: in (mirror of 0014)
+ 003A: out PFM bank switch MSB
+ 003C: in (mirror of 0010)
+ 003E: in (mirror of 000E)
+
+ ----Gate Array----
+ 13C0 - 13FE: Single step execution (not implemented, not available for most systems)
+
+ ----TMS9995-internal flag registers----
+ The values are all latched inside the CPU, but output values are visible
+ on the bus outside the CPU
+ 1EE0-1EE8, 1FDA: see tms9995.cpp
+ 1EEA: PAL/NTSC flag
+ 1EEC: (unused)
+ 1EEE: CapsLock flag
+ 1EF0: Keyboard clock
+ 1EF2: Keyboard shift register enable
+ 1EF4: Operation mode (native, GPL)
+ 1EF6: Memory mode (unmapped, mapped)
+ 1EF8: Cartridge size (0: 16 KiB, 1: 8 KiB)
+ 1EFA: Protect 6xxx
+ 1EFC: Protect 7xxx
+ 1EFE: Additional wait state per memory access
+
+ -------------------------------------------------------------------------
Michael Zapf, October 2011
February 2012: rewritten as class, restructured
Aug 2015: PFM added
+ Nov 2019: Extensive rewrite to provide a true emulation of the Gate Array
+ and the PAL, and also to allow for different kinds of external
+ keyboards.
***************************************************************************/
#include "emu.h"
@@ -255,252 +417,122 @@
#define LOG_WRITE (1U<<4)
#define LOG_KEYBOARD (1U<<5)
#define LOG_CLOCK (1U<<6)
-#define LOG_LINES (1U<<7)
+#define LOG_READY (1U<<7)
#define LOG_SETTING (1U<<8)
-#define LOG_VIDEOWS (1U<<9)
-#define LOG_PFM (1U<<10)
+#define LOG_CRU (1U<<9)
+#define LOG_CRUKEY (1U<<10)
#define LOG_DECODE (1U<<11)
-#define LOG_INVADDR (1U<<12)
+#define LOG_ADDRESS (1U<<12)
+#define LOG_LINES (1U<<13)
+#define LOG_WAIT (1U<<14)
+#define LOG_GROM (1U<<15)
+#define LOG_MAPPER (1U<<16)
-// Minimum log should be settings and warnings
-#define VERBOSE ( LOG_SETTING | LOG_WARN )
+// Minimum log should be warnings
+#define VERBOSE ( LOG_GENERAL | LOG_SETTING | LOG_WARN )
#include "genboard.h"
#include "logmacro.h"
DEFINE_DEVICE_TYPE_NS(GENEVE_GATE_ARRAY, bus::ti99::internal, geneve_gate_array_device, "geneve_gate_array", "Geneve Gate Array")
-DEFINE_DEVICE_TYPE_NS(GENMOD_GATE_ARRAY, bus::ti99::internal, genmod_gate_array_device, "genmod_gate_array", "Geneve Mod Gate Array")
+DEFINE_DEVICE_TYPE_NS(GENMOD_DECODER, bus::ti99::internal, genmod_decoder_device, "genmod_decoder", "GenMod decoder circuit")
+DEFINE_DEVICE_TYPE_NS(GENEVE_PAL, bus::ti99::internal, geneve_pal_device, "geneve_pal", "Geneve PAL circuit")
namespace bus { namespace ti99 { namespace internal {
geneve_gate_array_device::geneve_gate_array_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock),
- m_boot_rom(0),
- m_gromwaddr_LSB(false),
- m_gromraddr_LSB(false),
+ m_have_waitstate(false),
+ m_have_extra_waitstate(false),
+ m_enable_extra_waitstates(false),
+ m_extready(true),
+ m_sndready(true),
+
m_grom_address(0),
- m_video_waitstates(false),
- m_extra_waitstates(false),
- m_ready_asserted(false),
- m_read_mode(false),
- m_debug_no_ws(false),
- m_geneve_mode(false),
- m_direct_mode(false),
- m_cartridge_size(0),
+ m_cartridge_banked(false),
m_cartridge_secondpage(false),
m_cartridge6_writable(false),
m_cartridge7_writable(false),
- m_pfm_bank(0),
- m_pfm_output_enable(false),
- m_sram_mask(0),
- m_sram_val(0),
- m_ready(*this),
+ m_load_lsb(false),
+
+ m_geneve_mode(false),
+ m_direct_mode(false),
+
m_keyint(*this),
- m_waitcount(0),
- m_video_waitcount(0),
m_keyboard_shift_reg(0),
m_keyboard_last_clock(CLEAR_LINE),
m_keyboard_data_in(CLEAR_LINE),
m_shift_reg_enabled(false),
- m_cpu(*owner, "maincpu"),
- m_sound(*owner, TI_SOUNDCHIP_TAG),
- m_video(*owner, TI_VDP_TAG),
- m_rtc(*owner, GENEVE_CLOCK_TAG),
- m_sram(*this, GENEVE_SRAM_PAR_TAG),
- m_dram(*this, GENEVE_DRAM_PAR_TAG),
+
+ m_pal(*owner, GENEVE_PAL_TAG),
m_peribox(*owner, TI_PERIBOX_TAG),
- m_pfm512(*owner, GENEVE_PFM512_TAG),
- m_pfm512a(*owner, GENEVE_PFM512A_TAG),
- m_keyb_conn(*owner, GENEVE_KEYBOARD_CONN_TAG)
+ m_keyb_conn(*owner, GENEVE_KEYBOARD_CONN_TAG),
+
+ m_debug(false)
{
}
geneve_gate_array_device::geneve_gate_array_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: geneve_gate_array_device(mconfig, GENEVE_GATE_ARRAY, tag, owner, clock)
{
- m_eprom = nullptr;
- m_pbox_prefix = 0x070000;
-}
-
-genmod_gate_array_device::genmod_gate_array_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : geneve_gate_array_device(mconfig, GENMOD_GATE_ARRAY, tag, owner, clock),
- m_gm_timode(false),
- m_turbo(false)
-{
- m_eprom = nullptr;
- m_pbox_prefix = 0x170000;
}
-INPUT_CHANGED_MEMBER( geneve_gate_array_device::settings_changed )
+WRITE8_MEMBER( geneve_gate_array_device::cru_sstep_write )
{
- // Used when switching the boot ROMs during runtime, especially the PFM
- m_boot_rom = newval;
+ // Single step
+ // 13c0 - 13fe: 0001 0011 11xx xxx0 (offset << 1)
+ LOGMASKED(LOG_WARN, "Single step not implemented; bit %d set to %d\n", offset & 0x001f, data);
}
-INPUT_CHANGED_MEMBER( genmod_gate_array_device::setgm_changed )
+WRITE8_MEMBER( geneve_gate_array_device::cru_ctrl_write )
{
- int number = int(param&0x03);
- int value = newval;
-
- switch (number)
+ // This is just mirroring the internal flags of the 9995
+ int bit = (offset & 0x000f);
+ switch (bit)
{
- case 1:
- // Turbo switch. May be changed at any time.
- LOGMASKED(LOG_SETTING, "Setting turbo flag to %d\n", value);
- m_turbo = (value!=0);
+ case 5:
+ // Unknown effect
+ LOGMASKED(LOG_CRU, "Set PAL flag = %02x\n", data);
+ // m_palvideo = (data!=0);
+ break;
+ case 7:
+ // Capslock flag; just to keep track of the current state
break;
- case 2:
- // TIMode switch. Causes reset when changed.
- LOGMASKED(LOG_SETTING, "Setting timode flag to %d\n", value);
- m_gm_timode = (value!=0);
- machine().schedule_hard_reset();
+ case 8:
+ LOGMASKED(LOG_CRUKEY, "Set keyboard clock = %02x\n", data);
+ set_keyboard_clock(data);
break;
- case 3:
- // Used when switching the boot ROMs during runtime, especially the PFM
- m_boot_rom = value;
+ case 9:
+ LOGMASKED(LOG_CRUKEY, "Enable keyboard shift reg = %02x\n", data);
+ enable_shift_register(data);
+ break;
+ case 10:
+ LOGMASKED(LOG_CRU, "Operation mode = %s\n", (data!=0)? "native" : "GPL");
+ m_geneve_mode = (data!=0);
+ break;
+ case 11:
+ LOGMASKED(LOG_CRU, "Addressing mode = %s\n", (data!=0)? "unmapped" : "mapped");
+ m_direct_mode = (data!=0);
+ break;
+ case 12:
+ LOGMASKED(LOG_CRU, "Cartridge ROM: %s\n", (data==0)? "banked" : "unbanked");
+ m_cartridge_banked = (data==0);
+ break;
+ case 13:
+ LOGMASKED(LOG_CRU, "Cartridge ROM 6000-6fff %s\n", (data!=0)? "writable" : "protected");
+ m_cartridge6_writable = (data!=0);
+ break;
+ case 14:
+ LOGMASKED(LOG_CRU, "Cartridge ROM 7000-7fff %s\n", (data!=0)? "writable" : "protected");
+ m_cartridge7_writable = (data!=0);
+ break;
+ case 15:
+ LOGMASKED(LOG_SETTING, "Extra wait states %s\n", (data==0)? "enabled" : "disabled");
+ m_enable_extra_waitstates = (data==0);
break;
default:
- LOGMASKED(LOG_WARN, "Unknown setting %d ignored\n", number);
- }
-}
-
-/****************************************************************************
- GROM simulation. The Geneve board simulated GROM circuits within its gate
- array.
-*****************************************************************************/
-
-/*
- Simulates GROM. The real Geneve does not use GROMs but simulates them
- within the gate array. Unlike with real GROMs, no address wrapping occurs,
- and the complete 64K space is available.
-*/
-uint8_t geneve_gate_array_device::read_grom(offs_t offset)
-{
- uint8_t reply;
- if (offset & 0x0002)
- {
- // GROM address handling
- m_gromwaddr_LSB = false;
-
- if (m_gromraddr_LSB)
- {
- reply = m_grom_address & 0xff;
- m_gromraddr_LSB = false;
- }
- else
- {
- reply = (m_grom_address >> 8) & 0xff;
- m_gromraddr_LSB = true;
- }
- }
- else
- {
- // GROM data handling
- // GROMs are stored in pages 38..3f
- int physpage = 0x38;
- reply = m_dram->pointer()[(physpage<<13) + m_grom_address];
- m_grom_address = (m_grom_address + 1) & 0xffff;
- m_gromraddr_LSB = m_gromwaddr_LSB = false;
- }
- return reply;
-}
-
-/*
- Simulates GROM. The real Geneve does not use GROMs but simulates them
- within the gate array.
-*/
-void geneve_gate_array_device::write_grom(offs_t offset, uint8_t data)
-{
- if (offset & 0x0002)
- {
- // set address
- m_gromraddr_LSB = false;
- if (m_gromwaddr_LSB)
- {
- m_grom_address = (m_grom_address & 0xff00) | data;
- m_grom_address = (m_grom_address + 1) & 0xffff;
- m_gromwaddr_LSB = false;
- }
- else
- {
- m_grom_address = (m_grom_address & 0x00ff) | ((uint16_t)data<<8);
- m_gromwaddr_LSB = true;
- }
- }
- else
- { // write GPL data
- // The Geneve GROM simulator allows for GROM writing (verified with a real system)
- int physpage = 0x38;
- m_dram->pointer()[(physpage<<13) + m_grom_address] = data;
-
- m_grom_address = (m_grom_address + 1) & 0xffff;
- m_gromraddr_LSB = m_gromwaddr_LSB = false;
- }
-}
-
-void geneve_gate_array_device::set_wait(int min)
-{
- if (m_extra_waitstates && min < 2) min = 2;
-
- // if we still have video wait states, do not set this counter
- // (or it will assert READY when expiring)
- if (m_video_waitcount > min) return;
-
- // need one more pass so that READY will be asserted again
- m_waitcount = min + 1;
- if (m_waitcount > 1)
- {
- LOGMASKED(LOG_LINES, "Pulling down READY line for %d cycles\n", min);
- m_ready(CLEAR_LINE);
- m_ready_asserted = false;
- }
-}
-
-void geneve_gate_array_device::set_video_waitcount(int min)
-{
- if (m_debug_no_ws) return;
- m_video_waitcount = min;
-}
-
-void geneve_gate_array_device::set_geneve_mode(bool geneve)
-{
- LOGMASKED(LOG_SETTING, "Setting Geneve mode = %d\n", geneve);
- m_geneve_mode = geneve;
-}
-
-void geneve_gate_array_device::set_direct_mode(bool direct)
-{
- LOGMASKED(LOG_SETTING, "Setting direct mode = %d\n", direct);
- m_direct_mode = direct;
-}
-
-void geneve_gate_array_device::set_cartridge_size(int size)
-{
- LOGMASKED(LOG_SETTING, "Setting cartridge size to %d\n", size);
- m_cartridge_size = size;
-}
-
-void geneve_gate_array_device::set_cartridge_writable(int base, bool write)
-{
- LOGMASKED(LOG_SETTING, "Cartridge %04x space writable = %d\n", base, write);
- if (base==0x6000) m_cartridge6_writable = write;
- else m_cartridge7_writable = write;
-}
-
-void geneve_gate_array_device::set_video_waitstates(bool wait)
-{
- // Tends to be called repeatedly
- if (m_video_waitstates != wait)
- {
- LOGMASKED(LOG_SETTING, "Setting video waitstates = %d\n", wait);
+ break;
}
- m_video_waitstates = wait;
-}
-
-void geneve_gate_array_device::set_extra_waitstates(bool wait)
-{
- LOGMASKED(LOG_SETTING, "Setting extra waitstates = %d\n", wait);
- m_extra_waitstates = wait;
}
/******************************************************************
@@ -597,468 +629,229 @@ WRITE_LINE_MEMBER( geneve_gate_array_device::kbddata )
m_keyboard_data_in = (line_state)state;
}
-/************************************************************************
- Called by the address map
-************************************************************************/
-
-/*
- Read a byte via the data bus. The decoding has already been done in the
- SETADDRESS method, and we re-use the values stored there to quickly
- access the appropriate component.
-*/
-uint8_t geneve_gate_array_device::readm(offs_t offset)
-{
- uint8_t value = 0;
-
- decdata *dec;
- decdata debug;
-
- // For the debugger, do the decoding here with no wait states
- if (machine().side_effects_disabled())
- {
- if (m_cpu->is_onchip(offset)) return m_cpu->debug_read_onchip_memory(offset&0xff);
- dec = &debug;
- m_debug_no_ws = true;
- dec->offset = offset;
- decode_logical(true, dec);
- if (dec->function == MUNDEF)
- {
- map_address(m_read_mode, dec);
- decode_physical(dec);
- decode_mod(dec);
- }
- if (dec->function == MBOX)
- {
- m_peribox->memen_in(ASSERT_LINE);
- m_peribox->setaddress_dbin(dec->physaddr, true);
- }
- }
- else
- {
- // Use the values found in the setaddress phase
- dec = &m_decoded;
- m_debug_no_ws = false;
- }
-
- // Logical space
-
- switch (dec->function)
- {
- case MLVIDEO:
- if (!machine().side_effects_disabled())
- {
- value = m_video->read(dec->offset>>1);
- LOGMASKED(LOG_READ, "Read video %04x -> %02x\n", dec->offset, value);
- // Video wait states are created *after* the access
- // Accordingly, they have no effect when execution is in onchip RAM
- if (m_video_waitstates) set_video_waitcount(15);
- }
- break;
-
- case MLMAPPER:
- // mapper
- value = m_map[dec->offset & 0x0007];
- LOGMASKED(LOG_READ, "Read mapper %04x -> %02x\n", dec->offset, value);
- break;
-
- case MLKEY:
- // key
- value = m_keyboard_shift_reg>>1;
- LOGMASKED(LOG_KEYBOARD, "Read keyboard -> %02x\n", value);
- break;
-
- case MLCLOCK:
- // clock
- // Tests on the real machine showed that the upper nibble is 0xf
- // (probably because of the location at f130-f13f?)
- // In TI mode, however, the upper nibble is 1, unless we read 801f,
- // in which case the nibble is 2. Here the location is 8010-801f.
- // Needs more investigation. We might as well ignore this,
- // as the high nibble is obviously undefined and takes some past
- // value floating around.
- value = m_rtc->read(dec->offset & 0x000f);
- if (m_geneve_mode) value |= 0xf0;
- else value |= ((dec->offset & 0x000f)==0x000f)? 0x20 : 0x10;
- LOGMASKED(LOG_READ, "Read clock %04x -> %02x\n", dec->offset, value);
- break;
-
- case MLGROM:
- // grom simulation
- // ++++ ++-- ---- ---+
- // 1001 1000 0000 00x0
- if (!machine().side_effects_disabled()) value = read_grom(dec->offset);
- LOGMASKED(LOG_READ, "Read GROM %04x -> %02x\n", dec->offset, value);
- break;
-
- case MLSOUND:
- value = 0;
- break;
-
- case MPDRAM:
- // DRAM. One wait state.
- value = m_dram->pointer()[dec->physaddr];
- LOGMASKED(LOG_READ, "Read DRAM %04x (%06x) -> %02x\n", dec->offset, dec->physaddr, value);
- break;
-
- case MPEXP:
- // On-board memory expansion for standard Geneve (never used)
- LOGMASKED(LOG_READ, "Read on-board expansion (not available) %06x -> 00\n", dec->physaddr);
- value = 0;
- break;
-
- case MPEPROM:
- // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K)
- // mirrored for f0, f2, f4, ...; f1, f3, f5, ...
- value = boot_rom(dec->physaddr);
- break;
-
- case MPSRAM:
- if ((dec->physaddr & m_sram_mask)==m_sram_val)
- {
- value = m_sram->pointer()[dec->physaddr & ~m_sram_mask];
- LOGMASKED(LOG_READ, "Read SRAM %04x (%06x) -> %02x\n", dec->offset, dec->physaddr, value);
- }
- else
- {
- LOGMASKED(LOG_INVADDR, "Decoded as SRAM read, but no SRAM at %06x\n", dec->physaddr);
- value = 0;
- }
- // Return in any case
- break;
-
- case MBOX:
- // Route everything else to the P-Box
- // 0x000000-0x07ffff for the stock Geneve (AMC,AMB,AMA,A0 ...,A15)
- // 0x000000-0x1fffff for the GenMod.(AME,AMD,AMC,AMB,AMA,A0 ...,A15)
-
- m_peribox->readz(dec->physaddr, &value);
- m_peribox->memen_in(CLEAR_LINE);
- LOGMASKED(LOG_READ, "Read P-Box %04x (%06x) -> %02x\n", dec->offset, dec->physaddr, value);
- break;
-
- default:
- LOGMASKED(LOG_WARN, "Unknown decoding result type: %d\n", dec->function);
- break;
- }
- return value;
-}
-
-void geneve_gate_array_device::writem(offs_t offset, uint8_t data)
-{
- decdata *dec;
- decdata debug;
-
- // For the debugger, do the decoding here with no wait states
- if (machine().side_effects_disabled())
- {
- // TODO: add debug_write_onchip_memory
- dec = &debug;
- m_debug_no_ws = true;
- dec->offset = offset;
- decode_logical(false, dec);
- if (dec->function == MUNDEF)
- {
- map_address(m_read_mode, dec);
- decode_physical(dec);
- decode_mod(dec);
- }
- if (dec->function == MBOX)
- {
- m_peribox->memen_in(ASSERT_LINE);
- m_peribox->setaddress_dbin(dec->physaddr, false);
- }
- }
- else
- {
- // Use the values found in the setaddress phase
- dec = &m_decoded;
- m_debug_no_ws = false;
- }
-
+// sysspeed has no effect for vwait/speed
- // Logical space
+// TODO: Video write timing
- switch (dec->function)
- {
- case MLVIDEO:
- // video
- // ++++ ++++ ++++ ---+
- // 1111 0001 0000 .cc0
- // Initialize waitstate timer
-
- if (!machine().side_effects_disabled())
- {
- m_video->write(dec->offset>>1, data);
- LOGMASKED(LOG_WRITE, "Write video %04x <- %02x\n", offset, data);
- // See above
- if (m_video_waitstates) set_video_waitcount(15);
- }
- break;
-
- case MLMAPPER:
- // mapper
- m_map[dec->offset & 0x0007] = data;
- LOGMASKED(LOG_WRITE, "Write mapper %04x <- %02x\n", offset, data);
- break;
-
- case MLCLOCK:
- // clock
- // ++++ ++++ ++++ ----
- m_rtc->write(dec->offset & 0x000f, data);
- LOGMASKED(LOG_WRITE, "Write clock %04x <- %02x\n", offset, data);
- break;
-
- case MLSOUND:
- // sound
- // ++++ ++++ ++++ ---+
- m_sound->write(data);
- LOGMASKED(LOG_WRITE, "Write sound <- %02x\n", data);
- break;
-
- case MLGROM:
- // The GROM simulator is only available in TI Mode
- write_grom(dec->offset, data);
- LOGMASKED(LOG_WRITE, "Write GROM %04x <- %02x\n", offset, data);
- break;
-
- // Physical space
- case MPDRAM:
- // DRAM write
- m_dram->pointer()[dec->physaddr] = data;
- LOGMASKED(LOG_WRITE, "Write DRAM %04x (%06x) <- %02x\n", offset, dec->physaddr, data);
- break;
-
- case MPEXP:
- // On-board memory expansion for standard Geneve
- // Actually never built, so we show it as unmapped
- LOGMASKED(LOG_WRITE, "Write on-board expansion (not available) %06x <- %02x\n", dec->physaddr, data);
- break;
-
- case MPEPROM:
- // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K)
- // mirrored for f0, f2, f4, ...; f1, f3, f5, ...
- // Ignore EPROM write (unless PFM)
- if (m_boot_rom != GENEVE_EPROM) write_to_pfm(dec->physaddr, data);
- else
- LOGMASKED(LOG_INVADDR, "Write EPROM %04x (%06x) <- %02x, ignored\n", offset, dec->physaddr, data);
- break;
-
- case MPSRAM:
- if ((dec->physaddr & m_sram_mask)==m_sram_val)
- {
- m_sram->pointer()[dec->physaddr & ~m_sram_mask] = data;
- LOGMASKED(LOG_WRITE, "Write SRAM %04x (%06x) <- %02x\n", offset, dec->physaddr, data);
- }
- else
- {
- LOGMASKED(LOG_INVADDR, "Decoded as SRAM write, but no SRAM at %06x\n", dec->physaddr);
- }
- break;
-
- case MBOX:
- // Route everything else to the P-Box
- LOGMASKED(LOG_WRITE, "Write P-Box %04x (%06x) <- %02x\n", offset, dec->physaddr, data);
- m_peribox->write(dec->physaddr, data);
- m_peribox->memen_in(CLEAR_LINE);
- break;
-
- default:
- LOGMASKED(LOG_WARN, "Unknown decoding result type: %d\n", dec->function);
- break;
- }
-}
+/*****************************************************************
+ Decoding functions
+******************************************************************/
-const geneve_gate_array_device::logentry_t geneve_gate_array_device::s_logmap[7] =
+const geneve_gate_array_device::logentry_t geneve_gate_array_device::s_logmap[10] =
{
{ 0xf100, 0x000e, 0x8800, 0x03fe, 0x0400, MLVIDEO, "video" },
{ 0xf110, 0x0007, 0x8000, 0x0007, 0x0000, MLMAPPER, "mapper" },
{ 0xf118, 0x0007, 0x8008, 0x0007, 0x0000, MLKEY, "keyboard" },
- { 0xf120, 0x000e, 0x8400, 0x03fe, 0x0000, MLSOUND, "sound" },
+ { 0xf120, 0x000e, 0x8400, 0x01ff, 0x0000, MLSOUND, "sound" },
+ { 0x0000, 0x0000, 0x8600, 0x01ff, 0x0000, MLEXT, "external bus" },
{ 0xf130, 0x000f, 0x8010, 0x000f, 0x0000, MLCLOCK, "clock" },
- { 0x0000, 0x0000, 0x9000, 0x03fe, 0x0400, MBOX, "speech (in P-Box)" },
- { 0x0000, 0x0000, 0x9800, 0x03fe, 0x0400, MLGROM, "GROM" },
+ { 0x0000, 0x0000, 0x9000, 0x03fe, 0x0400, MLEXT, "speech (ext. bus)" },
+ { 0x0000, 0x0000, 0x9800, 0x03fc, 0x0400, MLGROM, "GROM data" },
+ { 0x0000, 0x0000, 0x9802, 0x03fc, 0x0400, MLGROMAD, "GROM address" },
+ { 0x0000, 0x0000, 0x6000, 0x1fff, 0x0000, MLCARTROM, "Cartridge ROM" }
};
-void geneve_gate_array_device::decode_logical(bool reading, geneve_gate_array_device::decdata* dec)
+void geneve_gate_array_device::decode_logical(geneve_gate_array_device::decdata* dec)
{
dec->function = MUNDEF;
- dec->physaddr = m_pbox_prefix | dec->offset;
- dec->wait = 1;
+ int index = -1;
- int i = 0;
- while (i < 7)
+ for (int i = 0; (i < 10) && (index == -1); i++)
{
if (m_geneve_mode)
{
// Skip when genbase is 0
if ((s_logmap[i].genbase != 0) && ((dec->offset & ~s_logmap[i].genmask) == s_logmap[i].genbase))
- break;
+ index = i;
}
else
{
- if (reading)
+ if (dec->read)
{
if ((dec->offset & ~s_logmap[i].timask) == s_logmap[i].tibase)
- break;
+ index = i;
}
else
{
if ((dec->offset & ~s_logmap[i].timask) == (s_logmap[i].tibase | s_logmap[i].writeoff))
- break;
+ index = i;
}
}
- i++;
}
- if (i != 7)
+
+ if (index != -1)
{
- LOGMASKED(LOG_DECODE, "Decoded as %s: %04x\n", s_logmap[i].description, dec->offset);
- dec->function = s_logmap[i].function;
+ LOGMASKED(LOG_DECODE, "Decoded as %s: %04x\n", s_logmap[index].description, dec->offset);
+ dec->function = s_logmap[index].function;
+ }
+
+ // Handle write operations to the cartridge ROM
+ if (dec->function == MLCARTROM && !dec->read)
+ {
+ if (m_cartridge_banked) dec->function = MLCARTBANK;
+ else
+ {
+ if ((((dec->offset & 0x1000)==0) && !m_cartridge6_writable)
+ || (((dec->offset & 0x1000)!=0) && !m_cartridge7_writable))
+ {
+ dec->function = CARTPROT;
+ LOGMASKED(LOG_WARN, "Writing to protected cartridge space %04x ignored\n", dec->offset);
+ }
+ }
}
}
-void geneve_gate_array_device::map_address(bool reading, geneve_gate_array_device::decdata* dec)
+/*
+ Look up the mapper value (page) for the given logical address.
+ Cartridges need special handling.
+*/
+void geneve_gate_array_device::get_page(geneve_gate_array_device::decdata* dec)
{
int logpage = (dec->offset & 0xe000) >> 13;
- int physpage = 0;
+ dec->physpage = 0;
// Determine physical address
- if (m_direct_mode) physpage = 0xf8; // points to boot eprom
+ if (m_direct_mode) dec->physpage = 0xf8; // points to boot eprom
else
{
- // TI mode, accessing logical addresses 6000-7fff
- if (!m_geneve_mode && logpage==3)
+ if (dec->function == MLCARTROM)
+ dec->physpage = (m_cartridge_banked && m_cartridge_secondpage)? 0x37 : 0x36;
+ else
{
- if (reading)
- {
- physpage = (m_cartridge_size==0x4000 && m_cartridge_secondpage)? 0x37 : 0x36;
- }
+ if (dec->function == MLGROM)
+ dec->physpage = ((m_grom_address >> 13) & 0x07) | 0x38;
else
{
- // Emulate the cartridge bank switch feature of Extended Basic
- // TODO: Is this the right place? Or writem()?
- if (m_cartridge_size==0x4000)
+ if (dec->function == MLEXT)
{
- m_cartridge_secondpage = ((dec->offset & 0x0002)!=0);
- LOGMASKED(LOG_WRITE, "Set cartridge page %02x\n", m_cartridge_secondpage);
+ dec->physpage = 0xb8 | logpage;
}
else
- {
- // writing into cartridge rom space (no bank switching)
- if ((((dec->offset & 0x1000)==0x0000) && !m_cartridge6_writable)
- || (((dec->offset & 0x1000)==0x1000) && !m_cartridge7_writable))
- {
- LOGMASKED(LOG_WARN, "Writing to protected cartridge space %04x ignored\n", dec->offset);
- }
- else
- // TODO: Check whether secondpage is really ignored
- physpage = 0x36;
- }
+ dec->physpage = m_map[logpage];
}
}
- else
- physpage = m_map[logpage];
}
- dec->physaddr = ((physpage << 13) | (dec->offset & 0x1fff)) & 0x1fffff;
}
-const geneve_gate_array_device::physentry_t geneve_gate_array_device::s_physmap[4] =
+const geneve_gate_array_device::physentry_t geneve_gate_array_device::s_physmap[7] =
{
- { 0x000000, 0x07ffff, MPDRAM, 1, "DRAM" },
- { 0x080000, 0x07ffff, MPEXP, 1, "on-board expansion" },
- { 0x1e0000, 0x01ffff, MPEPROM, 0, "EPROM" },
- { 0x180000, 0x07ffff, MPSRAM, 0, "SRAM" }
+ { 0x00, 0x3f, MPDRAM, "DRAM" },
+ { 0x40, 0x3f, MPEXP, "Future exp (on-board)" },
+ { 0xe8, 0x03, MPSRAMX, "SRAM exp" },
+ { 0xec, 0x03, MPSRAM, "SRAM" },
+ { 0xf0, 0x0f, MPEPROM, "Boot ROM/PFM" },
+ { 0x80, 0x7f, MBOX, "external" } // catch-all
};
+/*
+ Try to decode the physical address.
+*/
void geneve_gate_array_device::decode_physical(geneve_gate_array_device::decdata* dec)
{
- dec->function = MUNDEF;
-
- int i = 0;
- while (i < 4)
+ // Search the map
+ if (dec->function == MUNDEF || dec->function == MLCARTROM || dec->function == MLGROM)
{
- if ((dec->physaddr & ~s_physmap[i].mask) == s_physmap[i].base)
- break;
- i++;
- }
- if (i != 4)
- {
- LOGMASKED(LOG_DECODE, "Decoded as %s: %06x\n", s_physmap[i].description, dec->physaddr);
- dec->function = s_physmap[i].function;
- dec->wait = s_physmap[i].wait;
- }
- else
- {
- // Route everything else to the P-Box
- dec->function = MBOX;
- dec->wait = 1;
+ if (dec->function == MLGROM)
+ {
+ // GROM is actually DRAM; substitute the address and update the address counter
+ // The page has already been set in get_page
+ LOGMASKED(LOG_GROM, "GROM address = %04x\n", m_grom_address);
+ dec->offset = m_grom_address; // Do not wipe the GROM number
+ // Auto-increment here (not in clock_in, as we have two clock cycles by wait states)
+ increase_grom_address();
+ return;
+ }
+
+ // Search for the matching page interval. Cartridge space will be decoded as DRAM.
+ bool found = false;
+ for (int i = 0; (i < 6) && !found; i++)
+ {
+ if ((dec->physpage & ~s_physmap[i].mask) == s_physmap[i].base)
+ {
+ dec->function = s_physmap[i].function;
+ LOGMASKED(LOG_DECODE, "Decoded as %s, page %02x\n", s_physmap[i].description, dec->physpage);
+ found = true;
+ }
+ }
+
+ if (!found)
+ LOGMASKED(LOG_DECODE, "Unmapped address %06x\n", (get_prefix(0xff) | (dec->offset & 0x1fff)) & 0x1fffff);
}
}
-void genmod_gate_array_device::decode_mod(geneve_gate_array_device::decdata* dec)
+void geneve_gate_array_device::increase_grom_address()
{
- // GenMod mode
- // The TI Mode switch activates the DRAM on the board (1 WS)
- // for the first 512K (000000-07ffff)
- if (((dec->function == MPDRAM) && !m_gm_timode) || dec->function==MPSRAM || dec->function==MPEXP)
+ if (!m_debug)
{
- dec->function = MBOX;
+ m_grom_address = ((m_grom_address + 1) & 0x1fff) | (m_grom_address & 0xe000);
+ m_load_lsb = false;
}
-
- if ((dec->function != MPDRAM) && m_turbo)
- dec->wait = 0;
}
/*
- Boot ROM handling, from EPROM or PFM.
+ Are we addressing DRAM?
*/
-uint8_t geneve_gate_array_device::boot_rom(offs_t offset)
+bool geneve_gate_array_device::accessing_dram()
{
- uint8_t value;
- int pfmaddress = (offset & 0x01ffff) | (m_pfm_bank<<17);
+ decdata* dec = (m_debug)? &m_decdebug : &m_decoded;
+ return accessing_dram_s(dec->function);
+}
- switch (m_boot_rom)
- {
- case GENEVE_EPROM:
- value = m_eprom[offset & 0x003fff];
- LOGMASKED(LOG_READ, "Read EPROM %04x -> %02x\n", offset & 0x003fff, value);
- return value;
- case GENEVE_PFM512:
- value = m_pfm512->read(pfmaddress);
- break;
- case GENEVE_PFM512A:
- value = m_pfm512a->read(pfmaddress);
- break;
- default:
- LOGMASKED(LOG_WARN, "Illegal mode for reading boot ROM: %d\n", m_boot_rom);
- value = 0;
- }
+bool geneve_gate_array_device::accessing_dram_s(int function)
+{
+ return (function == MPDRAM) || (function == MLGROM) || (function == MLCARTROM);
+}
+
+bool geneve_gate_array_device::accessing_sram_s(int function)
+{
+ return (function == MPSRAM) || (function == MPSRAMX);
+}
- if (!m_pfm_output_enable) value = 0;
- LOGMASKED(LOG_PFM, "Reading from PFM at address %05x -> %02x\n", pfmaddress, value);
- return value;
+bool geneve_gate_array_device::accessing_devs_s(int function)
+{
+ return (function == MLMAPPER) || (function == MLKEY) || (function == MLCLOCK) || (function == MLGROMAD);
}
-void geneve_gate_array_device::write_to_pfm(offs_t offset, uint8_t data)
+bool geneve_gate_array_device::accessing_grom()
+{
+ decdata* dec = (m_debug)? &m_decdebug : &m_decoded;
+ return (dec->function == MLGROM);
+}
+
+bool geneve_gate_array_device::accessing_box_s(int function, bool genmod)
+{
+ return (function == MLEXT) || (function == MBOX) || (genmod && function == MPEXP);
+}
+
+/*
+ The Gate Array has a private address bus to the DRAM.
+*/
+offs_t geneve_gate_array_device::get_dram_address()
{
- // Nota bene: The PFM must be write protected on startup, or the RESET
- // of the 9995 will attempt to write the return vector into the flash EEPROM
- int address = (offset & 0x01ffff) | (m_pfm_bank<<17);
- LOGMASKED(LOG_PFM, "Writing to PFM at address %05x <- %02x\n", address, data);
+ offs_t physaddr = 0;
+ decdata* dec = (m_debug)? &m_decdebug : &m_decoded;
+ int addr13 = dec->offset & 0x1fff;
- switch (m_boot_rom)
+ // Cartridge access is also done in DRAM; the pages are fixed to
+ // 36, 37 (ROM), 38...3f (GROM), regardless of the mapper.
+
+ if (dec->function == MLGROM)
{
- case GENEVE_PFM512:
- m_pfm512->write(address, data);
- break;
- case GENEVE_PFM512A:
- m_pfm512a->write(address, data);
- break;
- default:
- LOGMASKED(LOG_WARN, "Illegal mode for writing to PFM: %d\n", m_boot_rom);
+ physaddr = (0x38 << 13) | dec->offset;
+ // The GROM address counter is updated in decode_physical
}
+ else
+ {
+ if (dec->function == MPDRAM || dec->function == MLCARTROM)
+ {
+ physaddr = (get_prefix(0x3f) | addr13) & 0x7ffff;
+ }
+ else
+ LOGMASKED(LOG_WARN, "Unknown decoding %d for DRAM\n", dec->function);
+ }
+ return physaddr;
}
-
/*
Accept the address passed over the address bus and decode it appropriately.
This decoding will later be used in the READ/WRITE member functions. Also,
@@ -1066,116 +859,210 @@ void geneve_gate_array_device::write_to_pfm(offs_t offset, uint8_t data)
*/
void geneve_gate_array_device::setaddress(offs_t address, uint8_t busctrl)
{
- LOGMASKED(LOG_DETAIL, "setaddress = %04x\n", address);
- m_debug_no_ws = false;
- m_decoded.offset = address;
+ LOGMASKED(LOG_ADDRESS, "setaddress = %04x%s\n", address, m_debug? " (debug)" : "");
+ decdata& dec = (m_debug)? m_decdebug : m_decoded;
- m_read_mode = ((busctrl & TMS99xx_BUS_DBIN)!=0);
+ dec.offset = address;
+ dec.read = ((busctrl & TMS99xx_BUS_DBIN)!=0);
- decode_logical(m_read_mode, &m_decoded);
- if (m_decoded.function == MUNDEF)
- {
- map_address(m_read_mode, &m_decoded);
- decode_physical(&m_decoded);
- decode_mod(&m_decoded);
- }
+ decode_logical(&dec);
+ get_page(&dec);
+ decode_physical(&dec);
- set_wait(m_decoded.wait);
-
- if (m_decoded.function == MBOX)
+ if (!m_debug)
{
- m_peribox->memen_in(ASSERT_LINE);
- m_peribox->setaddress_dbin(m_decoded.physaddr, m_read_mode);
+ m_have_extra_waitstate = m_enable_extra_waitstates;
+ m_have_waitstate = (dec.function != MPSRAM && dec.function != MPSRAMX) || m_have_extra_waitstate;
}
}
/*
- The mapper is connected to the clock line in order to operate
- the wait state counter.
- The wait counter is decremented on each rising clock edge; when 0, the
- READY line is asserted. However, there is a second counter which is used for
- video wait states.
- The READY line must be asserted when the wait counter reaches 0, but must be
- cleared immediately again if the video counter has not reached 0.
- (See comments at the file header: The additional video wait states do not
- affect the video access itself but become effective after the access; if
- the code runs on the chip, these wait states are ignored.)
+ The Gate Array uses the clock to operate the wait state flags. The actual
+ wait state generation is up to the PAL chip.
*/
WRITE_LINE_MEMBER( geneve_gate_array_device::clock_in )
{
- if (state==ASSERT_LINE)
+ // Falling CLK
+ if (state == CLEAR_LINE)
{
- // Rising edge
- if (!m_ready_asserted)
- {
- if (m_waitcount > 0)
- {
- m_waitcount--;
- if (m_waitcount == 0)
- {
- LOGMASKED(LOG_CLOCK, "clock, READY asserted\n");
- m_ready(ASSERT_LINE);
- m_ready_asserted = true;
- }
- else
- {
- LOGMASKED(LOG_CLOCK, "clock\n");
- }
- }
- else
- {
- if (m_video_waitcount > 0)
- {
- m_video_waitcount--;
- if (m_video_waitcount == 0)
- {
- LOGMASKED(LOG_CLOCK, "clock, READY asserted after video\n");
- m_ready(ASSERT_LINE);
- m_ready_asserted = true;
- }
- else
- {
- LOGMASKED(LOG_CLOCK, "vclock, ew=%d\n", m_video_waitcount);
- }
- }
- }
- }
+ if (!m_have_extra_waitstate)
+ m_have_waitstate = false;
+ else
+ m_have_extra_waitstate = false;
}
- else
+}
+
+/*
+ READY line from the peribox. Together with the sndready and the READY output
+ of the Gate Array itself, this forms a wired AND.
+*/
+WRITE_LINE_MEMBER( geneve_gate_array_device::extready_in )
+{
+ LOGMASKED(LOG_READY, "External READY = %d\n", state);
+ m_extready = (state==ASSERT_LINE);
+}
+
+WRITE_LINE_MEMBER( geneve_gate_array_device::sndready_in )
+{
+ LOGMASKED(LOG_READY, "Sound READY = %d\n", state);
+ m_sndready = (state==ASSERT_LINE);
+}
+
+READ_LINE_MEMBER(geneve_gate_array_device::csw_out)
+{
+ // Do not access a port-based device in debugger mode
+ if (m_debug) return CLEAR_LINE;
+ return ((m_decoded.function == MLVIDEO) && !m_decoded.read)? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER(geneve_gate_array_device::csr_out)
+{
+ // Do not access a port-based device in debugger mode
+ if (m_debug) return CLEAR_LINE;
+ return ((m_decoded.function == MLVIDEO) && m_decoded.read)? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER(geneve_gate_array_device::romen_out)
+{
+ decdata* dec = (m_debug)? &m_decdebug : &m_decoded;
+ return ((dec->function == MPEPROM) && dec->read)? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER(geneve_gate_array_device::ramen_out)
+{
+ decdata* dec = (m_debug)? &m_decdebug : &m_decoded;
+ return (dec->function == MPSRAM)? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER(geneve_gate_array_device::ramenx_out)
+{
+ decdata* dec = (m_debug)? &m_decdebug : &m_decoded;
+ return (dec->function == MPSRAMX)? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER(geneve_gate_array_device::rtcen_out)
+{
+ decdata* dec = (m_debug)? &m_decdebug : &m_decoded;
+ return (dec->function == MLCLOCK)? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER(geneve_gate_array_device::snden_out)
+{
+ decdata* dec = (m_debug)? &m_decdebug : &m_decoded;
+ return ((dec->function == MLSOUND) && !dec->read)? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER(geneve_gate_array_device::dben_out)
+{
+ decdata* dec = (m_debug)? &m_decdebug : &m_decoded;
+ return accessing_box_s(dec->function, false)? ASSERT_LINE : CLEAR_LINE;
+}
+
+// After setaddress, pull down READY if
+// - we have an extra waitstate OR
+// - we do not access SRAM(X) OR
+// - extready = 0
+
+// In Genmod, pull down READY if
+// - we have an extra waitstate OR
+// - we access the box and have turbo==0 OR
+// - we access DRAM and have timode==1 OR
+// - extready = 0
+
+READ_LINE_MEMBER(geneve_gate_array_device::gaready_out)
+{
+ if (m_debug) return ASSERT_LINE; // Always READY when debugging
+ // Return true (READY=1) when we are accessing SRAM/SRAMX and when we do not have extra waitstates
+ // return ((m_decoded.function == MPSRAM || m_decoded.function == MPSRAMX) && !m_have_extra_waitstate)? ASSERT_LINE : CLEAR_LINE;
+ return (m_have_waitstate || m_have_extra_waitstate || !m_extready || !m_sndready)? CLEAR_LINE : ASSERT_LINE;
+}
+
+
+/**********************************************************
+ Gate Array-internal functions
+***********************************************************/
+
+/*
+ Changes the value of the parameter if one of the functions applies.
+*/
+void geneve_gate_array_device::readz(uint8_t& value)
+{
+ decdata* dec = (m_debug)? &m_decdebug : &m_decoded;
+ uint8_t lsb = 0;
+
+ switch (dec->function)
{
- // Falling edge
- // Do we have video wait states? In that case, clear the line again
- if ((m_waitcount == 0) && (m_video_waitcount > 0) && m_ready_asserted)
+ case MLMAPPER:
+ value = m_map[dec->offset & 0x0007];
+ LOGMASKED(LOG_READ, "Read mapper %04x -> %02x\n", dec->offset, value);
+ break;
+ case MLKEY:
+ value = m_keyboard_shift_reg>>1;
+ LOGMASKED(LOG_READ, "Read keyboard %04x -> %02x\n", dec->offset, value);
+ break;
+ case MLGROMAD:
+ if (!m_debug) // don't let the debugger mess with the address counter
{
- LOGMASKED(LOG_CLOCK, "clock, READY cleared for video\n");
- m_ready(CLEAR_LINE);
- m_ready_asserted = false;
+ value = (m_grom_address & 0xff00)>>8;
+ lsb = (m_grom_address & 0xff);
+ m_grom_address = lsb << 8 | lsb;
+ m_load_lsb = false;
+ LOGMASKED(LOG_READ, "Read GROM address %04x -> %02x\n", dec->offset, value);
}
+ break;
+ case MLCARTBANK:
+ break;
+ default:
+ break;
}
}
/*
- PFM expansion: Setting the bank.
+ Internal functions of the Gate Array. Returns without changes if none
+ of the function applies.
*/
-WRITE_LINE_MEMBER( geneve_gate_array_device::pfm_select_lsb )
+void geneve_gate_array_device::write(uint8_t data)
{
- if (state==ASSERT_LINE) m_pfm_bank |= 1;
- else m_pfm_bank &= 0xfe;
- LOGMASKED(LOG_PFM, "Setting bank (l) = %d\n", m_pfm_bank);
-}
+ decdata* dec = (m_debug)? &m_decdebug : &m_decoded;
-WRITE_LINE_MEMBER( geneve_gate_array_device::pfm_select_msb )
-{
- if (state==ASSERT_LINE) m_pfm_bank |= 2;
- else m_pfm_bank &= 0xfd;
- LOGMASKED(LOG_PFM, "Setting bank (u) = %d\n", m_pfm_bank);
+ switch (dec->function)
+ {
+ case MLMAPPER:
+ m_map[dec->offset & 0x0007] = data;
+ // LOGMASKED(LOG_MAPPER, "Write mapper %04x <- %02x\n", dec->offset, data);
+ LOGMASKED(LOG_MAPPER, "Set %04x mapper[%02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ dec->offset, m_map[0], m_map[1], m_map[2], m_map[3], m_map[4], m_map[5], m_map[6], m_map[7]);
+ break;
+ case MLGROMAD:
+ if (!m_debug) // don't let the debugger mess with the address counter
+ {
+ m_grom_address = (m_grom_address << 8 | data) & 0xffff;
+ if (m_load_lsb) increase_grom_address();
+ else m_load_lsb = true;
+ LOGMASKED(LOG_GROM, "Write GROM address %04x <- %02x\n", dec->offset, data);
+ }
+ break;
+ case MLCARTBANK:
+ m_cartridge_secondpage = ((dec->offset & 0x0002)!=0);
+ LOGMASKED(LOG_WRITE, "Set cartridge bank %04x <- %02x\n", dec->offset, data);
+ break;
+ case MLKEY:
+ LOGMASKED(LOG_WRITE, "Write to keyboard ignored\n");
+ break;
+ default:
+ break;
+ }
}
-WRITE_LINE_MEMBER( geneve_gate_array_device::pfm_output_enable )
+/*
+ Address lines that the Gate Array offers. They reflect the 8 bits of
+ the mapper byte. AME and AMD are only used by GenMod.
+ (AME, AMD,) AMC, AMB, AMA, AB0, AB1, AB2
+*/
+int geneve_gate_array_device::get_prefix(int lines)
{
- // Negative logic
- m_pfm_output_enable = (state==CLEAR_LINE);
- LOGMASKED(LOG_PFM, "PFM output %s\n", m_pfm_output_enable? "enable" : "disable");
+ decdata* dec = (m_debug)? &m_decdebug : &m_decoded;
+ return (dec->physpage & lines) << 13;
}
//====================================================================
@@ -1184,109 +1071,444 @@ WRITE_LINE_MEMBER( geneve_gate_array_device::pfm_output_enable )
void geneve_gate_array_device::device_start()
{
- m_ready.resolve_safe();
m_keyint.resolve_safe();
m_geneve_mode = false;
m_direct_mode = true;
// State registration
- save_item(NAME(m_gromwaddr_LSB));
- save_item(NAME(m_gromraddr_LSB));
+ save_item(NAME(m_have_extra_waitstate));
+ save_item(NAME(m_enable_extra_waitstates));
+ save_item(NAME(m_extready));
+ save_item(NAME(m_sndready));
+
save_item(NAME(m_grom_address));
- save_item(NAME(m_video_waitstates));
- save_item(NAME(m_extra_waitstates));
- save_item(NAME(m_ready_asserted));
- save_item(NAME(m_read_mode));
- save_item(NAME(m_debug_no_ws));
- save_item(NAME(m_geneve_mode));
- save_item(NAME(m_direct_mode));
- save_item(NAME(m_cartridge_size));
+ save_item(NAME(m_cartridge_banked));
save_item(NAME(m_cartridge_secondpage));
save_item(NAME(m_cartridge6_writable));
save_item(NAME(m_cartridge7_writable));
+ save_item(NAME(m_load_lsb));
+
+ save_item(NAME(m_geneve_mode));
+ save_item(NAME(m_direct_mode));
+
save_pointer(NAME(m_map), 8);
+
+ save_item(NAME(m_decoded.read));
save_item(NAME(m_decoded.function));
save_item(NAME(m_decoded.offset));
- save_item(NAME(m_decoded.physaddr));
- save_item(NAME(m_boot_rom));
- save_item(NAME(m_pfm_bank));
- save_item(NAME(m_pfm_output_enable));
- save_item(NAME(m_sram_mask));
- save_item(NAME(m_sram_val));
- save_item(NAME(m_waitcount));
- save_item(NAME(m_video_waitcount));
+ save_item(NAME(m_decoded.physpage));
+
+ save_item(NAME(m_keyboard_shift_reg));
+ save_item(NAME(m_shift_reg_enabled));
}
void geneve_gate_array_device::common_reset()
{
- m_extra_waitstates = false;
- m_video_waitstates = true;
- m_read_mode = false;
- m_waitcount = 0;
- m_video_waitcount = 0;
- m_ready_asserted = true;
+ m_have_extra_waitstate = false;
+ m_enable_extra_waitstates = false;
- m_geneve_mode =false;
- m_direct_mode = true;
- m_cartridge_size = 0x4000;
+ m_grom_address = 0;
+ m_cartridge_banked = false;
m_cartridge_secondpage = false;
m_cartridge6_writable = false;
m_cartridge7_writable = false;
- m_grom_address = 0;
- m_pfm_bank = 0;
- m_pfm_output_enable = true;
+
+ m_geneve_mode =false;
+ m_direct_mode = true;
// Clear map
for (auto & elem : m_map) elem = 0;
-
- // Check which boot EPROM we are using (or PFM)
- m_boot_rom = machine().root_device().ioport("BOOTROM")->read();
- m_eprom = machine().root_device().memregion("maincpu")->base();
-
- // Allow for configuring the VRAM size
- uint32_t videoram = (machine().root_device().ioport("VRAM")->read()!=0)? 0x30000 : 0x20000;
- downcast<v99x8_device &>(*m_video.target()).set_vram_size(videoram);
- LOGMASKED(LOG_SETTING, "Video RAM set to %d KiB\n", videoram / 1024);
}
void geneve_gate_array_device::device_reset()
{
common_reset();
+}
+
+/* ========================================================================
+
+ The PAL circuit on the Geneve main board. It is the actual waitstate
+ generator, and its task is to control the READY line depending on the
+ accessed device, and to control the outgoing MEMEN* and WE* lines into
+ the peribox.
+
+ The chip is a PAL16R4ACN
+
+ Pin Dir Meaning
+ ---------------------
+ 1 in CLK (assert=H)
+ 2 in WE* (write)
+ 3 in READYIN (from Gate Array and sound chip)
+ 4 in CSR* (Video read)
+ 5 in CRU bit 23 (>002E) ("System clock speed")
+ 6 in MEMEN* (memory access)
+ 7 in DBEN* (external data bus enable)
+ 8 in (Gate Array bit 36)
+ 9 in CSW* (video write)
+ 10 GND
+ 11 in OE*, hardwired to H
+ 12 out WE*
+ 13 out MEMEN*
+ 14 (output of FF1, disabled by pin 11)
+ 15 (output of FF2, disabled by pin 11)
+ 16 (output of FF3, disabled by pin 11)
+ 17 (output of FF4, disabled by pin 11)
+ 18 out READYOUT
+ 19 in VDPWAITEN
+ 20 Vcc
+
+ ======================================================================== */
+
+geneve_pal_device::geneve_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, GENEVE_PAL, tag, owner, clock),
+ m_pin3(true),
+ m_pin4(true),
+ m_pin5(true),
+ m_pin9(true),
+ m_pin19(false),
+ m_pin14d(false),m_pin14q(false),
+ m_pin15d(false),m_pin15q(false),
+ m_pin16d(false),m_pin16q(false),
+ m_pin17d(false),m_pin17q(false),
+ m_prev_ready(CLEAR_LINE),
+ m_peribox(*owner, TI_PERIBOX_TAG),
+ m_ready(*this)
+{
+}
- // SRAM is only separately handled for the standard Geneve; Genmod uses
- // the Memex instead
- switch (machine().root_device().ioport("SRAM")->read())
+/*
+ READY input from the Gate Array.
+*/
+WRITE_LINE_MEMBER(geneve_pal_device::gaready_in)
+{
+ bool prev = m_pin3;
+ m_pin3 = (state==ASSERT_LINE);
+ if (prev != m_pin3)
{
-/* 1 100. .... .... .... .... on-board sram (128K) -+
- 1 101. .... .... .... .... on-board sram (128K) -+-- maximum SRAM expansion
- 1 1100 .... .... .... .... on-board sram (64K) --+
- 1 1101 0... .... .... .... on-board sram (32K) - additional 32 KiB required for MDOS 2.50s and higher
- 1 1101 1... .... .... .... on-board sram (32K) - standard setup
+ LOGMASKED(LOG_LINES, "READY(ga) <- %d\n", state);
+ // When GAREADY=L, the video lines have immediate effect on the ready line
+ set_ready();
+ }
+}
+
+/*
+ Video read (ASSERT=low).
*/
- case 0: // 32 KiB
- m_sram_mask = 0x1f8000;
- m_sram_val = 0x1d8000;
- break;
- case 1: // 64 KiB
- m_sram_mask = 0x1f0000;
- m_sram_val = 0x1d0000;
- break;
- case 2: // 384 KiB (actually 512 KiB, but the EPROM masks the upper 128 KiB)
- m_sram_mask = 0x180000;
- m_sram_val = 0x180000;
- break;
+WRITE_LINE_MEMBER(geneve_pal_device::csr_in)
+{
+ bool prev = m_pin4;
+ m_pin4 = (state==CLEAR_LINE);
+ if (prev != m_pin4)
+ {
+ LOGMASKED(LOG_LINES, "CSR <- %d\n", state);
+ set_ready();
}
}
-void genmod_gate_array_device::device_reset()
+/*
+ Video write (ASSERT=low).
+*/
+WRITE_LINE_MEMBER(geneve_pal_device::csw_in)
{
- common_reset();
- LOGMASKED(LOG_SETTING, "Using GenMod modification\n");
- m_turbo = ((machine().root_device().ioport("GENMODDIPS")->read() & GENEVE_GM_TURBO)!=0);
- m_gm_timode = ((machine().root_device().ioport("GENMODDIPS")->read() & GENEVE_GM_TIM)!=0);
+ bool prev = m_pin9;
+ m_pin9 = (state==CLEAR_LINE);
+ if (prev != m_pin9)
+ {
+ LOGMASKED(LOG_LINES, "CSW <- %d\n", state);
+ set_ready();
+ }
+}
+
+/*
+ Memory enable (ASSERT=low); pass through
+*/
+WRITE_LINE_MEMBER(geneve_pal_device::memen)
+{
+ LOGMASKED(LOG_LINES, "MEMEN -> %d\n", state);
+ m_peribox->memen_in(state);
+}
+
+/*
+ Write external mem cycles (0=long, 1=short)
+ System clock speed (PAL pin 5). (ASSERT=high)
+ The function from the equations could not be verified on a real machine.
+ This function seems to have no effect. So either the equations are
+ wrong, or something else is going on.
+*/
+WRITE_LINE_MEMBER(geneve_pal_device::sysspeed)
+{
+ bool prev = m_pin5;
+ m_pin5 = (state == ASSERT_LINE);
+ if (prev != m_pin5)
+ {
+ LOGMASKED(LOG_SETTING, "System clock speed set to %d\n", state);
+ set_ready();
+ }
}
+/*
+ Write vdp wait cycles (1=add 14 cycles, 0=add none)
+ see above for waitstate handling
+*/
+WRITE_LINE_MEMBER(geneve_pal_device::vwaiten)
+{
+ bool prev = m_pin19;
+ m_pin19 = (state==ASSERT_LINE);
+ if (prev != m_pin19)
+ {
+ LOGMASKED(LOG_SETTING, "Video wait states %s\n", (state!=0)? "enabled" : "disabled");
+ set_ready();
+ }
+}
+
+/*
+ Clock input. This controls the state of the waitstate counter.
+*/
+WRITE_LINE_MEMBER(geneve_pal_device::clock_in)
+{
+ LOGMASKED(LOG_CLOCK, "CLK%s\n", state? "?" : "?");
+ // Set the FF
+ if (state==ASSERT_LINE)
+ {
+ m_pin14q = m_pin14d;
+ m_pin15q = m_pin15d;
+ m_pin16q = m_pin16d;
+ m_pin17q = m_pin17d;
+ set_ready();
+ }
+}
+
+/*
+ Called from clock_in and input pin functions. Set the state of the
+ READY line. Since this is the only source for the state, we always have
+ 0 or 1, but no Z state.
+
+ FIXME: The video write wait state handling is still not correct. Unfortunately,
+ the equations of the PAL did not help, in contrast, the problem got worse.
+ Problem: After initiating a video write (CSW*=0), the READY line must
+ remain high for the next falling clock edge so that the CPU can complete
+ the command cycle. By these equations, the READY line immediately goes
+ low when the clock line rises, and thus on the falling edge, a wait state
+ is produced.
+ The effect is that in the real machine, if all code runs in on-chip memory,
+ a video write does not cause any wait state, while in this emulation, it
+ always causes the full 14 cycles of wait states. In rare situations, this
+ may heavily slow down the processing.
+*/
+void geneve_pal_device::set_ready()
+{
+ line_state ready_line;
+
+ // Original equations from the PAL
+/*
+ ready_line = ((!m_pin4 && !m_pin3) ||
+ (!m_pin9 && !m_pin3) ||
+ (m_pin9 && m_pin4 && !m_pin14q) ||
+ (m_pin5 && m_pin4 && !m_pin15q) ||
+ (m_pin5 && m_pin4 && !m_pin16q) ||
+ (m_pin9 && m_pin4 && !m_pin17q))? CLEAR_LINE : ASSERT_LINE;
+
+ m_pin17d = (m_pin9 && m_pin4 && !m_pin17q && !m_pin14q) ||
+ (m_pin9 && m_pin4 && !m_pin17q && !m_pin15q) ||
+ (m_pin9 && m_pin4 && !m_pin17q && !m_pin16q) ||
+ (m_pin9 && m_pin4 && m_pin3 && m_pin16q && m_pin15q && m_pin14q) ||
+ (!m_pin19 && !m_pin17q && !m_pin14q) ||
+ (!m_pin19 && !m_pin17q && !m_pin15q) ||
+ (!m_pin19 && !m_pin17q && !m_pin16q) ||
+ (m_pin3 && !m_pin19 && m_pin16q && m_pin15q && m_pin14q);
+
+ m_pin16d = (m_pin9 && m_pin4 && m_pin17q && !m_pin16q) ||
+ (m_pin9 && m_pin4 && !m_pin17q && m_pin16q) ||
+ (m_pin9 && m_pin4 && m_pin16q && m_pin15q && m_pin14q) ||
+ !m_pin19;
+
+ m_pin15d = (m_pin9 && m_pin4 && m_pin15q && m_pin14q) ||
+ (m_pin9 && m_pin4 && !m_pin16q && m_pin15q) ||
+ (m_pin9 && m_pin4 && !m_pin17q && m_pin15q) ||
+ (m_pin9 && m_pin4 && m_pin17q && m_pin16q && !m_pin15q) ||
+ !m_pin19;
+
+ m_pin14d = (m_pin9 && m_pin4 && m_pin14q) ||
+ (m_pin9 && m_pin4 && m_pin17q && m_pin16q && m_pin15q) ||
+ !m_pin19;
+*/
+
+ // Simplified equations for better performance
+
+ bool pin4_9 = m_pin9 && m_pin4;
+
+ ready_line = ((!m_pin3 && !pin4_9) ||
+ (pin4_9 && (!m_pin14q || !m_pin17q)) ||
+ (m_pin5 && m_pin4 && (!m_pin15q || !m_pin16q)))? CLEAR_LINE : ASSERT_LINE;
+
+ m_pin17d = (pin4_9 && !m_pin17q && (!m_pin14q || !m_pin15q || !m_pin16q)) ||
+ (((pin4_9 && m_pin3) || (m_pin3 && !m_pin19)) && m_pin16q && m_pin15q && m_pin14q) ||
+ (!m_pin19 && !m_pin17q && (!m_pin14q || !m_pin15q || !m_pin16q));
+
+ m_pin16d = (pin4_9 && m_pin17q && !m_pin16q) ||
+ (pin4_9 && !m_pin17q && m_pin16q) ||
+ (pin4_9 && m_pin16q && m_pin15q && m_pin14q) ||
+ !m_pin19;
+
+ m_pin15d = (pin4_9 && m_pin15q && (m_pin14q || !m_pin16q || !m_pin17q)) ||
+ (pin4_9 && m_pin17q && m_pin16q && !m_pin15q) ||
+ !m_pin19;
+
+ m_pin14d = (pin4_9 && m_pin14q) ||
+ (pin4_9 && m_pin17q && m_pin16q && m_pin15q) ||
+ !m_pin19;
+
+ if (m_prev_ready != ready_line) LOGMASKED(LOG_WAIT, "READY = %d (%d %d %d %d, %d %d %d, %d %d)\n", ready_line, m_pin14d, m_pin15d, m_pin16d, m_pin17d, m_pin3, m_pin4, m_pin9, m_pin5, m_pin19 ); m_prev_ready = ready_line;
+ m_ready(ready_line);
+}
+
+void geneve_pal_device::device_start()
+{
+ m_ready.resolve_safe();
+
+ save_item(NAME(m_pin3));
+ save_item(NAME(m_pin4));
+ save_item(NAME(m_pin5));
+ save_item(NAME(m_pin9));
+ save_item(NAME(m_pin19));
+ save_item(NAME(m_pin17q));
+ save_item(NAME(m_pin16q));
+ save_item(NAME(m_pin15q));
+ save_item(NAME(m_pin14q));
+}
+
+/********************************************************************
+ Genmod daughterboard, soldered to the back of the Gate Array
+ The main task of the Genmod is to route all memory accesses to the
+ Memex card in the peripheral box.
+
+ Also, the Genmod may inhibit wait states by flipping on the TURBO switch.
+
+ The TIMODE switch blocks the box access for the DRAM space (pages
+ 00-3F) so that the GROM emulator remains functional. Without this GROM
+ emulation (which is hardwired to the board DRAM), the TI-99/4A
+ software cannot run.
+
+********************************************************************/
+
+genmod_decoder_device::genmod_decoder_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, GENMOD_DECODER, tag, owner, clock),
+ m_debug(false),
+ m_turbo(false),
+ m_timode(false),
+ m_function(0),
+ m_function_debug(0),
+ m_page(0),
+ m_page_debug(0),
+ m_gaready(0),
+ m_extready(ASSERT_LINE),
+ m_sndready(ASSERT_LINE)
+{
+}
+
+void genmod_decoder_device::set_function(int func, int page)
+{
+ if (m_debug)
+ {
+ m_function_debug = func;
+ m_page_debug = page;
+ }
+ else
+ {
+ m_function = func; // values from logical map or physical map
+ m_page = page;
+ }
+}
+
+WRITE_LINE_MEMBER(genmod_decoder_device::gaready_in)
+{
+ m_gaready = state;
+}
+
+/*
+ READY line from the box. Do not ignore this line, as it is important
+ for device operation.
+*/
+WRITE_LINE_MEMBER(genmod_decoder_device::extready_in)
+{
+ m_extready = state;
+}
+
+/*
+ READY line from the sound chip.
+*/
+WRITE_LINE_MEMBER(genmod_decoder_device::sndready_in)
+{
+ m_sndready = state;
+}
+
+/*
+ Wait state generation
+ The Genmod board does not look inside the Gate Array. The call we are using
+ is just a shorthand for evaluating the states of the select lines.
+*/
+READ_LINE_MEMBER(genmod_decoder_device::gaready_out)
+{
+ int func = m_debug? m_function_debug : m_function;
+ int page = m_debug? m_page_debug : m_page;
+
+ // External or sound READY must always be respected
+ if (m_extready==CLEAR_LINE || m_sndready==CLEAR_LINE) return CLEAR_LINE;
+
+ // When TURBO is off, pass through
+ if (!m_turbo) return m_gaready;
+
+ // When accessing internal devices, pass through
+ if (geneve_gate_array_device::accessing_devs_s(func)) return m_gaready;
+
+ // In TURBO mode:
+ // When TIMODE is active, and we access the DRAM area, pass through
+ if (m_timode && ((page & 0xc0)==0)) return m_gaready;
+
+ // When accessing SRAM, SRAMX, EPROM, or page BA, pass through
+ if ((((page & 0xf0)==0xf0) || ((page&0xf8)==0xe8) || page == 0xba)) return m_gaready;
+
+ // else no wait states
+ return ASSERT_LINE;
+}
+
+/*
+ Genmod accesses the box also for the DRAM range, but only if timode==0.
+ (This includes GROM and cartridge ROM access.)
+ Note: It is not sufficient to check for the page area; we need to check
+ the select lines (via the static functions).
+*/
+READ_LINE_MEMBER(genmod_decoder_device::dben_out)
+{
+ int func = m_debug? m_function_debug : m_function;
+
+ if (geneve_gate_array_device::accessing_box_s(func, true))
+ return ASSERT_LINE;
+
+ if (!m_timode && geneve_gate_array_device::accessing_dram_s(func))
+ return ASSERT_LINE;
+
+ // This needs to be verified with a real device.
+ if (geneve_gate_array_device::accessing_sram_s(func))
+ return ASSERT_LINE;
+
+ return CLEAR_LINE;
+}
+
+void genmod_decoder_device::device_start()
+{
+ save_item(NAME(m_debug));
+ save_item(NAME(m_turbo));
+ save_item(NAME(m_timode));
+ save_item(NAME(m_function));
+ save_item(NAME(m_function_debug));
+ save_item(NAME(m_page));
+ save_item(NAME(m_page_debug));
+ save_item(NAME(m_gaready));
+ save_item(NAME(m_extready));
+ save_item(NAME(m_sndready));
+}
} } } // end namespace bus::ti99::internal
diff --git a/src/devices/bus/ti99/internal/genboard.h b/src/devices/bus/ti99/internal/genboard.h
index 3e927ab70df..ef1e4402c44 100644
--- a/src/devices/bus/ti99/internal/genboard.h
+++ b/src/devices/bus/ti99/internal/genboard.h
@@ -39,60 +39,98 @@ enum
};
#define GENEVE_GATE_ARRAY_TAG "gatearray"
+#define GENMOD_DECODER_TAG "genmod"
+#define GENEVE_PAL_TAG "pal"
#define GENEVE_MOUSE_TAG "gmouse"
-#define GENEVE_CLOCK_TAG "mm58274c"
#define GENEVE_PFM512_TAG "pfm512"
#define GENEVE_PFM512A_TAG "pfm512a"
#define GENEVE_KEYBOARD_CONN_TAG "keybconn"
-#define GENEVE_SRAM_TAG "sram"
-#define GENEVE_DRAM_TAG "dram"
-#define GENEVE_SRAM_PAR_TAG ":sram"
-#define GENEVE_DRAM_PAR_TAG ":dram"
-
namespace bus { namespace ti99 { namespace internal {
/*****************************************************************************/
+class geneve_pal_device;
+class genmod_decoder_device;
+
class geneve_gate_array_device : public device_t
{
+ // friend class genmod_decoder_device;
+
public:
geneve_gate_array_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- void set_geneve_mode(bool geneve);
- void set_direct_mode(bool direct);
- void set_cartridge_size(int size);
- void set_cartridge_writable(int base, bool write);
- void set_video_waitstates(bool wait);
- void set_extra_waitstates(bool wait);
-
- uint8_t readm(offs_t offset);
- void writem(offs_t offset, uint8_t data);
+ // Set the internal state and output lines according to the address
void setaddress(offs_t offset, uint8_t busctrl);
- DECLARE_INPUT_CHANGED_MEMBER( settings_changed );
+ // Access to Gate Array-internal registers. Depends on the previous
+ // call of setaddress
+ // - Mapper
+ // - Keyboard
+ // - Grom address counter
+ // - Cartridge bank switch
+ void readz(uint8_t& value);
+ void write(uint8_t data);
+ // Inputs
DECLARE_WRITE_LINE_MEMBER( clock_in );
DECLARE_WRITE_LINE_MEMBER( dbin_in );
+ DECLARE_WRITE_LINE_MEMBER( extready_in );
+ DECLARE_WRITE_LINE_MEMBER( sndready_in );
+ DECLARE_WRITE8_MEMBER( cru_sstep_write );
+ DECLARE_WRITE8_MEMBER( cru_ctrl_write );
+
+ // Outputs
+ DECLARE_READ_LINE_MEMBER( csr_out );
+ DECLARE_READ_LINE_MEMBER( csw_out );
+ DECLARE_READ_LINE_MEMBER( rtcen_out );
+ DECLARE_READ_LINE_MEMBER( romen_out );
+ DECLARE_READ_LINE_MEMBER( ramen_out );
+ DECLARE_READ_LINE_MEMBER( ramenx_out );
+ DECLARE_READ_LINE_MEMBER( snden_out );
+ DECLARE_READ_LINE_MEMBER( dben_out );
+ DECLARE_READ_LINE_MEMBER( gaready_out );
+
+ int get_prefix(int lines);
+ bool accessing_dram();
+ static bool accessing_dram_s(int function);
+ static bool accessing_sram_s(int function);
+ static bool accessing_box_s(int function, bool genmod);
+ static bool accessing_devs_s(int function);
+
+ bool accessing_grom();
+ offs_t get_dram_address();
// Keyboard support
DECLARE_WRITE_LINE_MEMBER( set_keyboard_clock );
DECLARE_WRITE_LINE_MEMBER( enable_shift_register );
DECLARE_WRITE_LINE_MEMBER( kbdclk );
DECLARE_WRITE_LINE_MEMBER( kbddata );
-
- // PFM support
- DECLARE_WRITE_LINE_MEMBER( pfm_select_lsb );
- DECLARE_WRITE_LINE_MEMBER( pfm_select_msb );
- DECLARE_WRITE_LINE_MEMBER( pfm_output_enable );
-
- auto ready_cb() { return m_ready.bind(); }
auto kbdint_cb() { return m_keyint.bind(); }
-protected:
+ // Miscellaneous
+ void set_debug(bool deb) { m_debug = deb; }
+ bool geneve_mode() { return m_geneve_mode; }
+ int get_function() { return m_debug? m_decdebug.function : m_decoded.function; }
+
+private:
geneve_gate_array_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
void common_reset();
+ // Mapper function
+ typedef struct
+ {
+ bool read; // Reading
+ int function; // must be a fundamental type to be saveable
+ offs_t offset; // Logical address
+ int physpage; // Physical page
+ } decdata;
+
+ // Functions
+ void decode_logical(decdata* dec);
+ void get_page(decdata* dec);
+ void decode_physical(decdata* dec);
+
/*
Constants for mapper decoding. Naming scheme:
M=Mapper, L=Logical space; P=Physical space
@@ -106,60 +144,54 @@ protected:
MLKEY,
MLSOUND,
MLCLOCK,
+ MLEXT,
MLGROM,
+ MLGROMAD,
+ MLCARTROM,
+ MLCARTBANK,
MPDRAM,
MPEXP,
MPEPROM,
MPSRAM,
+ MPSRAMX,
+ MBOX,
- MBOX
- } decfunct_t;
+ CARTPROT
- // Mapper function
- typedef struct
- {
- int function; // must be a fundamental type to be saveable
- offs_t offset; // Logical address
- offs_t physaddr; // Physical address
- int wait; // Wait states
- } decdata;
-
- uint8_t* m_eprom;
- int m_pbox_prefix;
- int m_boot_rom;
+ } decfunct_t;
-private:
void device_start() override;
virtual void device_reset() override;
- // GROM simulation
- bool m_gromwaddr_LSB;
- bool m_gromraddr_LSB;
- int m_grom_address;
- uint8_t read_grom(offs_t offset);
- void write_grom(offs_t offset, uint8_t data);
-
- // wait states
- void set_wait(int min);
- void set_video_waitcount(int min);
- bool m_video_waitstates;
- bool m_extra_waitstates;
- bool m_ready_asserted;
+ // Wait state creation
+ bool m_have_waitstate;
+ bool m_have_extra_waitstate;
+ bool m_enable_extra_waitstates;
+ bool m_extready;
+ bool m_sndready;
- bool m_read_mode;
-
- bool m_debug_no_ws;
- bool m_geneve_mode;
- bool m_direct_mode;
- int m_cartridge_size;
+ // Cartridge and GROM support
+ int m_grom_address;
+ bool m_cartridge_banked;
bool m_cartridge_secondpage;
bool m_cartridge6_writable;
bool m_cartridge7_writable;
+ bool m_load_lsb;
+ void increase_grom_address();
+
+ // Global modes
+ bool m_geneve_mode;
+ bool m_direct_mode;
+
+ // Mapper file
int m_map[8];
// The result of decoding
decdata m_decoded;
+ decdata m_decdebug;
+
+ // ====== Decoding ============
// Static decoder entry for the logical space
// Not all entries apply for native mode, e.g. there is no GROM in native
@@ -181,82 +213,116 @@ private:
// There are no differences between native mode and TI mode.
typedef struct
{
- offs_t base; // Base address
+ offs_t base; // Base page
int mask; // Bits that also match this entry
decfunct_t function; // Decoded function
- int wait; // Wait states
const char* description; // Good for logging
} physentry_t;
+ // Tables
static const geneve_gate_array_device::logentry_t s_logmap[];
static const geneve_gate_array_device::physentry_t s_physmap[];
- void decode_logical(bool reading, decdata* dec);
- void map_address(bool reading, decdata* dec);
- void decode_physical(decdata* dec);
- // This is the hook for Genmod. The normal Geneve just does nothing here.
- virtual void decode_mod(decdata* dec) { };
+ // Keyboard support
+ devcb_write_line m_keyint;
+ uint16_t m_keyboard_shift_reg;
+ line_state m_keyboard_last_clock;
+ line_state m_keyboard_data_in;
+ bool m_shift_reg_enabled;
+ void shift_reg_changed();
- // PFM mod (0 = none, 1 = AT29C040, 2 = AT29C040A)
- uint8_t boot_rom(offs_t offset);
- void write_to_pfm(offs_t offset, uint8_t data);
- int m_pfm_bank;
- bool m_pfm_output_enable;
+ // Devices
+ required_device<geneve_pal_device> m_pal;
+ required_device<bus::ti99::peb::peribox_device> m_peribox;
+ required_device<pc_kbdc_device> m_keyb_conn;
- // SRAM access
- int m_sram_mask;
- int m_sram_val;
+ // Emulation-specific: Is the debugger active?
+ bool m_debug;
+};
- // Ready line to the CPU
- devcb_write_line m_ready;
+/*****************************************************************************/
- // Keyboard interrupt
- devcb_write_line m_keyint;
+/*
+ PAL circuit, controlling the READY line to the CPU and MEMEN/WE
+ to the peribox
+*/
- // Counter for the wait states.
- int m_waitcount;
- int m_video_waitcount;
+class geneve_pal_device : public device_t
+{
+public:
+ geneve_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ DECLARE_WRITE_LINE_MEMBER( gaready_in );
+ DECLARE_WRITE_LINE_MEMBER( csw_in );
+ DECLARE_WRITE_LINE_MEMBER( csr_in );
+ DECLARE_WRITE_LINE_MEMBER( memen );
+ DECLARE_WRITE_LINE_MEMBER( vwaiten ); // pin 19
+ DECLARE_WRITE_LINE_MEMBER( sysspeed ); // pin 5
+ DECLARE_WRITE_LINE_MEMBER( clock_in );
- // Keyboard support
- uint16_t m_keyboard_shift_reg;
- line_state m_keyboard_last_clock;
- line_state m_keyboard_data_in;
- bool m_shift_reg_enabled;
- void shift_reg_changed();
+ auto ready_cb() { return m_ready.bind(); }
- // Devices
- required_device<tms9995_device> m_cpu;
- required_device<sn76496_base_device> m_sound;
- required_device<v9938_device> m_video;
- required_device<mm58274c_device> m_rtc;
- required_device<ram_device> m_sram;
- required_device<ram_device> m_dram;
+private:
+ void device_start() override;
+ void set_ready();
+
+ // Pins
+ bool m_pin3;
+ bool m_pin4;
+ bool m_pin5;
+ bool m_pin9;
+ bool m_pin19;
+ bool m_pin14d,m_pin14q;
+ bool m_pin15d,m_pin15q;
+ bool m_pin16d,m_pin16q;
+ bool m_pin17d,m_pin17q;
+
+ // Debugging
+ int m_prev_ready;
required_device<bus::ti99::peb::peribox_device> m_peribox;
- required_device<at29c040_device> m_pfm512;
- required_device<at29c040a_device> m_pfm512a;
-
- required_device<pc_kbdc_device> m_keyb_conn;
+ // Ready line to the CPU
+ devcb_write_line m_ready;
};
-class genmod_gate_array_device : public geneve_gate_array_device
+class genmod_decoder_device : public device_t
{
public:
- genmod_gate_array_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
- void decode_mod(decdata* dec) override;
- void device_reset() override;
- DECLARE_INPUT_CHANGED_MEMBER( setgm_changed );
+ genmod_decoder_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // Set the internal state and output lines according to the address
+ void set_function(int func, int page);
+ void set_debug(bool deb) { m_debug = deb; }
+ void set_turbo(bool turbo) { m_turbo = turbo; }
+ void set_timode(bool timode) { m_timode = timode; }
+
+ DECLARE_READ_LINE_MEMBER( gaready_out );
+ DECLARE_READ_LINE_MEMBER( dben_out );
+ DECLARE_WRITE_LINE_MEMBER( gaready_in );
+ DECLARE_WRITE_LINE_MEMBER( extready_in );
+ DECLARE_WRITE_LINE_MEMBER( sndready_in );
private:
- // Genmod modifications
- bool m_gm_timode;
+ void device_start() override;
+
+ // Emulation-specific: Is the debugger active?
+ bool m_debug;
bool m_turbo;
+ bool m_timode;
+ int m_function;
+ int m_function_debug;
+ int m_page;
+ int m_page_debug;
+ int m_gaready;
+ int m_extready;
+ int m_sndready;
};
} } } // end namespace bus::ti99::internal
DECLARE_DEVICE_TYPE_NS(GENEVE_GATE_ARRAY, bus::ti99::internal, geneve_gate_array_device)
-DECLARE_DEVICE_TYPE_NS(GENMOD_GATE_ARRAY, bus::ti99::internal, genmod_gate_array_device)
+DECLARE_DEVICE_TYPE_NS(GENEVE_PAL, bus::ti99::internal, geneve_pal_device)
+DECLARE_DEVICE_TYPE_NS(GENMOD_DECODER, bus::ti99::internal, genmod_decoder_device)
#endif // MAME_BUS_TI99_INTERNAL_GENBOARD_H
diff --git a/src/devices/bus/ti99/internal/ioport.cpp b/src/devices/bus/ti99/internal/ioport.cpp
index a855fd3bf41..5faaee0a9a6 100644
--- a/src/devices/bus/ti99/internal/ioport.cpp
+++ b/src/devices/bus/ti99/internal/ioport.cpp
@@ -141,6 +141,12 @@ WRITE_LINE_MEMBER(ioport_device::clock_in)
m_connected->clock_in(state);
}
+WRITE_LINE_MEMBER(ioport_device::reset_in)
+{
+ if (m_connected != nullptr)
+ m_connected->reset_in(state);
+}
+
void ioport_device::device_start()
{
m_console_extint.resolve();
diff --git a/src/devices/bus/ti99/internal/ioport.h b/src/devices/bus/ti99/internal/ioport.h
index 6b468007eda..75033c467bb 100644
--- a/src/devices/bus/ti99/internal/ioport.h
+++ b/src/devices/bus/ti99/internal/ioport.h
@@ -37,6 +37,7 @@ public:
virtual DECLARE_WRITE_LINE_MEMBER( memen_in ) { }
virtual DECLARE_WRITE_LINE_MEMBER( msast_in ) { }
virtual DECLARE_WRITE_LINE_MEMBER( clock_in ) { }
+ virtual DECLARE_WRITE_LINE_MEMBER( reset_in ) { }
void set_ioport(ioport_device* ioport) { m_ioport = ioport; }
@@ -78,6 +79,7 @@ public:
DECLARE_WRITE_LINE_MEMBER( memen_in );
DECLARE_WRITE_LINE_MEMBER( msast_in );
DECLARE_WRITE_LINE_MEMBER( clock_in );
+ DECLARE_WRITE_LINE_MEMBER( reset_in );
// Callbacks
auto extint_cb() { return m_console_extint.bind(); }
diff --git a/src/devices/bus/ti99/peb/bwg.cpp b/src/devices/bus/ti99/peb/bwg.cpp
index d6e738f90eb..1a18ac66918 100644
--- a/src/devices/bus/ti99/peb/bwg.cpp
+++ b/src/devices/bus/ti99/peb/bwg.cpp
@@ -150,7 +150,7 @@ SETADDRESS_DBIN_MEMBER( snug_bwg_device::setaddress_dbin )
// Is the card being selected?
m_address = offset;
- m_inDsrArea = ((m_address & m_select_mask)==m_select_value);
+ m_inDsrArea = in_dsr_space(m_address, true);
if (!m_inDsrArea) return;
@@ -196,7 +196,7 @@ SETADDRESS_DBIN_MEMBER( snug_bwg_device::setaddress_dbin )
*/
void snug_bwg_device::debug_read(offs_t offset, uint8_t* value)
{
- if (((offset & m_select_mask)==m_select_value) && m_selected)
+ if (in_dsr_space(offset, true) && m_selected)
{
if ((offset & 0x1c00)==0x1c00)
{
@@ -210,7 +210,7 @@ void snug_bwg_device::debug_read(offs_t offset, uint8_t* value)
void snug_bwg_device::debug_write(offs_t offset, uint8_t data)
{
- if (((offset & m_select_mask)==m_select_value) && m_selected)
+ if (in_dsr_space(offset, true) && m_selected)
{
if (((offset & 0x1c00)==0x1c00) && ((offset & 0x1fe0)!=0x1fe0))
m_buffer_ram->pointer()[(m_crulatch8_15->q5_r()<<10) | (m_address & 0x03ff)] = data;
@@ -527,17 +527,6 @@ void snug_bwg_device::device_start()
void snug_bwg_device::device_reset()
{
- if (m_genmod)
- {
- m_select_mask = 0x1fe000;
- m_select_value = 0x174000;
- }
- else
- {
- m_select_mask = 0x7e000;
- m_select_value = 0x74000;
- }
-
m_DRQ = CLEAR_LINE;
m_IRQ = CLEAR_LINE;
m_MOTOR_ON = CLEAR_LINE;
diff --git a/src/devices/bus/ti99/peb/evpc.cpp b/src/devices/bus/ti99/peb/evpc.cpp
index 6e532ae11ea..3c97a282fd5 100644
--- a/src/devices/bus/ti99/peb/evpc.cpp
+++ b/src/devices/bus/ti99/peb/evpc.cpp
@@ -86,10 +86,10 @@ SETADDRESS_DBIN_MEMBER( snug_enhanced_video_device::setaddress_dbin )
m_address = offset;
bool reading = (state==ASSERT_LINE);
- int offbase = (m_address & 0xfc01);
+ int offbase = (m_address & 0x7fc01); // The 7 represents the AMA/B/C lines
// Sound
- m_sound_accessed = ((m_address & 0xff01)==0x8400) && !reading;
+ m_sound_accessed = ((m_address & 0x7ff01)==0x78400) && !reading;
// Video space
// 8800 / 8802 / 8804 / 8806
@@ -97,15 +97,15 @@ SETADDRESS_DBIN_MEMBER( snug_enhanced_video_device::setaddress_dbin )
//
// Bits 1000 1w00 0000 0xx0
// Mask 1111 1000 0000 0001
- m_video_accessed = ((offbase==0x8800) && reading) || ((offbase==0x8c00) && !reading);
+ m_video_accessed = ((offbase==0x78800) && reading) || ((offbase==0x78c00) && !reading);
// Read a byte in evpc DSR space
// 0x4000 - 0x5eff DSR (paged)
// 0x5f00 - 0x5fef NOVRAM
// 0x5ff0 - 0x5fff Palette
- m_inDsrArea = ((m_address & 0xe000)==0x4000);
- m_novram_accessed = ((m_address & 0xff00)==0x5f00);
- m_palette_accessed = ((m_address & 0xfff0)==0x5ff0);
+ m_inDsrArea = in_dsr_space(m_address, true);
+ m_novram_accessed = ((m_address & 0x7ff00)==0x75f00);
+ m_palette_accessed = ((m_address & 0x7fff0)==0x75ff0);
// Note that we check the selection in reverse order so that the overlap is avoided
}
@@ -413,8 +413,6 @@ void snug_enhanced_video_device::device_start()
void snug_enhanced_video_device::device_reset()
{
- m_select_mask = 0x7e000;
- m_select_value = 0x74000;
m_dsr_page = 0;
m_RAMEN = false;
m_selected = false;
diff --git a/src/devices/bus/ti99/peb/hfdc.cpp b/src/devices/bus/ti99/peb/hfdc.cpp
index 6a9a89726b2..ac418f30256 100644
--- a/src/devices/bus/ti99/peb/hfdc.cpp
+++ b/src/devices/bus/ti99/peb/hfdc.cpp
@@ -124,7 +124,7 @@ SETADDRESS_DBIN_MEMBER( myarc_hfdc_device::setaddress_dbin )
// 010x xxxx xxxx xxxx
m_address = offset;
- m_inDsrArea = ((m_address & m_select_mask)==m_select_value);
+ m_inDsrArea = in_dsr_space(m_address, true);
if (!m_inDsrArea) return;
@@ -161,7 +161,7 @@ SETADDRESS_DBIN_MEMBER( myarc_hfdc_device::setaddress_dbin )
*/
void myarc_hfdc_device::debug_read(offs_t offset, uint8_t* value)
{
- if (((offset & m_select_mask)==m_select_value) && m_selected)
+ if (in_dsr_space(offset, true) && m_selected)
{
if ((offset & 0x1000)==RAM_ADDR)
{
@@ -180,7 +180,7 @@ void myarc_hfdc_device::debug_read(offs_t offset, uint8_t* value)
void myarc_hfdc_device::debug_write(offs_t offset, uint8_t data)
{
- if (((offset & m_select_mask)==m_select_value) && m_selected)
+ if (in_dsr_space(offset, true) && m_selected)
{
if ((offset & 0x1000)==RAM_ADDR)
{
@@ -880,10 +880,7 @@ void myarc_hfdc_device::device_start()
save_item(NAME(m_senila));
save_item(NAME(m_senilb));
save_item(NAME(m_selected));
- save_item(NAME(m_genmod));
save_item(NAME(m_cru_base));
- save_item(NAME(m_select_mask));
- save_item(NAME(m_select_value));
// Own members
save_item(NAME(m_see_switches));
@@ -911,18 +908,6 @@ void myarc_hfdc_device::device_start()
void myarc_hfdc_device::device_reset()
{
- // The GenMOD mod; our implementation automagically adapts all cards
- if (m_genmod)
- {
- m_select_mask = 0x1fe000;
- m_select_value = 0x174000;
- }
- else
- {
- m_select_mask = 0x7e000;
- m_select_value = 0x74000;
- }
-
m_cru_base = ioport("CRUHFDC")->read();
m_wait_for_hd1 = ioport("WAITHD1")->read();
diff --git a/src/devices/bus/ti99/peb/horizon.cpp b/src/devices/bus/ti99/peb/horizon.cpp
index 89383125cbb..0ed6d0fff03 100644
--- a/src/devices/bus/ti99/peb/horizon.cpp
+++ b/src/devices/bus/ti99/peb/horizon.cpp
@@ -48,6 +48,11 @@
less than 2 MiB onboard. As the community is still alive we can hope for
a fix for this problem; so we make the size configurable.
+ According to the Genmod setup instructions, the Horizon Ramdisks do not
+ decode the AMA/AMB/AMC lines, so it is important to modify them when
+ running with the Genmod system. This can be done with the configuration
+ setting "Genmod fix".
+
*****************************************************************************/
#include "emu.h"
@@ -81,8 +86,6 @@ horizon_ramdisk_device::horizon_ramdisk_device(const machine_config &mconfig, co
m_ram(*this, RAMREGION),
m_nvram(*this, NVRAMREGION),
m_ros(*this, ROSREGION),
- m_select6_value(0),
- m_select_all(0),
m_page(0),
m_cru_horizon(0),
m_cru_phoenix(0),
@@ -91,7 +94,8 @@ horizon_ramdisk_device::horizon_ramdisk_device(const machine_config &mconfig, co
m_split_mode(false),
m_rambo_mode(false),
m_hideswitch(false),
- m_use_rambo(false)
+ m_use_rambo(false),
+ m_genmod_fix(false)
{
}
@@ -185,7 +189,7 @@ READ8Z_MEMBER(horizon_ramdisk_device::readz)
if (!m_rambo_mode)
{
- if ((offset & m_select_mask) == m_select_value)
+ if (in_dsr_space(offset, m_genmod_fix))
{
if ((offset & 0x1800) == 0x1800)
{
@@ -203,12 +207,12 @@ READ8Z_MEMBER(horizon_ramdisk_device::readz)
}
else
{
- if ((offset & m_select_mask)==m_select_value)
+ if (in_dsr_space(offset, m_genmod_fix))
{
*value = m_ros->pointer()[offset & 0x1fff];
LOGMASKED(LOG_READ, "offset=%04x (Rambo) -> %02x\n", offset&0xffff, *value);
}
- if ((offset & m_select_mask)==m_select6_value)
+ if (in_cart_space(offset, m_genmod_fix))
{
// In RAMBO mode the page numbers are multiples of 4
// (encompassing 4 Horizon pages)
@@ -251,7 +255,7 @@ void horizon_ramdisk_device::write(offs_t offset, uint8_t data)
if (!m_rambo_mode)
{
- if ((offset & m_select_mask) == m_select_value)
+ if (in_dsr_space(offset, m_genmod_fix))
{
if ((offset & 0x1800) == 0x1800)
{
@@ -269,12 +273,12 @@ void horizon_ramdisk_device::write(offs_t offset, uint8_t data)
}
else
{
- if ((offset & m_select_mask)==m_select_value)
+ if (in_dsr_space(offset, m_genmod_fix))
{
m_ros->pointer()[offset & 0x1fff] = data;
LOGMASKED(LOG_WRITE, "offset=%04x (Rambo) <- %02x\n", offset&0xffff, data);
}
- if ((offset & m_select_mask)==m_select6_value)
+ if (in_cart_space(offset, m_genmod_fix))
{
// In RAMBO mode the page numbers are multiples of 4
// (encompassing 4 Horizon pages)
@@ -376,8 +380,6 @@ void horizon_ramdisk_device::device_start(void)
m_cru_horizon = 0;
m_cru_phoenix = 0;
- save_item(NAME(m_select6_value));
- save_item(NAME(m_select_all));
save_item(NAME(m_page));
save_item(NAME(m_cru_horizon));
save_item(NAME(m_cru_phoenix));
@@ -391,21 +393,6 @@ void horizon_ramdisk_device::device_start(void)
void horizon_ramdisk_device::device_reset(void)
{
- if (m_genmod)
- {
- m_select_mask = 0x1fe000;
- m_select_value = 0x174000;
- m_select6_value = 0x176000;
- m_select_all = 0x170000;
- }
- else
- {
- m_select_mask = 0x7e000;
- m_select_value = 0x74000;
- m_select6_value = 0x76000;
- m_select_all = 0x70000;
- }
-
m_cru_horizon = ioport("CRUHOR")->read();
m_cru_phoenix = ioport("CRUPHOE")->read();
@@ -419,6 +406,8 @@ void horizon_ramdisk_device::device_reset(void)
m_use_rambo = (ioport("RAMBO")->read()!=0);
+ m_genmod_fix = (ioport("GENMODFIX")->read()!=0);
+
m_page = 0;
m_selected = false;
}
@@ -477,6 +466,11 @@ INPUT_PORTS_START( horizon )
PORT_CONFSETTING( 0x02, "8 MiB")
PORT_CONFSETTING( 0x03, "16 MiB")
+ PORT_START( "GENMODFIX" )
+ PORT_CONFNAME( 0x01, 0x00, "Horizon Genmod fix" )
+ PORT_CONFSETTING( 0x00, DEF_STR( Off ))
+ PORT_CONFSETTING( 0x01, DEF_STR( On ))
+
INPUT_PORTS_END
void horizon_ramdisk_device::device_add_mconfig(machine_config &config)
diff --git a/src/devices/bus/ti99/peb/horizon.h b/src/devices/bus/ti99/peb/horizon.h
index f72e9f109fc..234dd68028a 100644
--- a/src/devices/bus/ti99/peb/horizon.h
+++ b/src/devices/bus/ti99/peb/horizon.h
@@ -51,9 +51,6 @@ private:
required_device<ram_device> m_nvram;
required_device<ram_device> m_ros;
- int m_select6_value;
- int m_select_all;
-
int m_page;
int m_cru_horizon;
@@ -64,6 +61,7 @@ private:
bool m_rambo_mode;
bool m_hideswitch;
bool m_use_rambo;
+ bool m_genmod_fix;
};
} } } // end namespace bus::ti99::peb
diff --git a/src/devices/bus/ti99/peb/memex.cpp b/src/devices/bus/ti99/peb/memex.cpp
index 3a3116d262d..49d41bba4ec 100644
--- a/src/devices/bus/ti99/peb/memex.cpp
+++ b/src/devices/bus/ti99/peb/memex.cpp
@@ -15,8 +15,12 @@
#include "emu.h"
#include "memex.h"
-#define LOG_WARN (1U<<1) // Warnings
-#define LOG_CONFIG (1U<<2) // Configuration
+#define LOG_WARN (1U<<1)
+#define LOG_CONFIG (1U<<2)
+#define LOG_READ (1U<<3)
+#define LOG_WRITE (1U<<4)
+#define LOG_BLOCK (1U<<5)
+
#define VERBOSE ( LOG_CONFIG | LOG_WARN )
#include "logmacro.h"
@@ -56,12 +60,19 @@ bool geneve_memex_device::access_enabled(offs_t offset)
// we may have to lock out those areas
int page = (offset >> 13)&0xff;
+ // All mirrors of page ba via AMD/AME are blocked.
+ // These are 3a, 7a, ba, and fa.
+ if ((page & 0x3f)==0x3a)
+ {
+ LOGMASKED(LOG_BLOCK, "memex blocks page %02x\n", page);
+ return false;
+ }
+
// SW2: 10xxx010 locked when SW2=off
// 10111010 locked when SW2=on
- if (page == 0xba) return false;
if ((page & 0xc7)==0x82 && ((m_switches & MDIP2)==0))
{
- LOGMASKED(LOG_CONFIG, "memex blocks page %02x; dip2=%d\n", page, (m_switches & MDIP2)!=0);
+ LOGMASKED(LOG_BLOCK, "memex blocks page %02x; dip2=%d\n", page, (m_switches & MDIP2)!=0);
return false;
}
@@ -91,11 +102,14 @@ bool geneve_memex_device::access_enabled(offs_t offset)
READ8Z_MEMBER( geneve_memex_device::readz )
{
/* If not Genmod, add the upper two address bits 10 */
- if (!m_genmod) offset |= 0x100000;
+// if (!m_genmod) offset |= 0x100000;
// The card is accessed for all addresses in the address space
if (access_enabled(offset))
+ {
*value = m_ram->pointer()[offset];
+ LOGMASKED(LOG_READ, "%06x -> %02x\n", offset, *value);
+ }
}
/*
@@ -104,11 +118,14 @@ READ8Z_MEMBER( geneve_memex_device::readz )
void geneve_memex_device::write(offs_t offset, uint8_t data)
{
/* If not Genmod, add the upper two address bits 10 */
- if (!m_genmod) offset |= 0x100000;
+// if (!m_genmod) offset |= 0x100000;
// The card is accessed for all addresses in the address space
if (access_enabled(offset))
+ {
+ LOGMASKED(LOG_WRITE, "%06x <- %02x\n", offset, data);
m_ram->pointer()[offset] = data;
+ }
}
/**************************************************************************/
diff --git a/src/devices/bus/ti99/peb/pcode.cpp b/src/devices/bus/ti99/peb/pcode.cpp
index 9b711c6bfc6..3cd03205be7 100644
--- a/src/devices/bus/ti99/peb/pcode.cpp
+++ b/src/devices/bus/ti99/peb/pcode.cpp
@@ -118,7 +118,7 @@ ti_pcode_card_device::ti_pcode_card_device(const machine_config &mconfig, const
SETADDRESS_DBIN_MEMBER( ti_pcode_card_device::setaddress_dbin )
{
m_address = offset;
- m_inDsrArea = ((m_address & m_select_mask)==m_select_value);
+ m_inDsrArea = in_dsr_space(offset, true);
line_state a14 = ((m_address & 2)!=0)? ASSERT_LINE : CLEAR_LINE;
@@ -145,7 +145,7 @@ SETADDRESS_DBIN_MEMBER( ti_pcode_card_device::setaddress_dbin )
void ti_pcode_card_device::debugger_read(uint16_t offset, uint8_t& value)
{
// The debuger does not call setaddress
- if (m_active && ((offset & m_select_mask)==m_select_value))
+ if (m_active && in_dsr_space(offset, true))
{
bool isrom0 = ((offset & 0xf000)==0x4000);
bool isrom12 = ((offset & 0xf000)==0x5000);
@@ -287,16 +287,6 @@ void ti_pcode_card_device::device_start()
void ti_pcode_card_device::device_reset()
{
- if (m_genmod)
- {
- m_select_mask = 0x1fe000;
- m_select_value = 0x174000;
- }
- else
- {
- m_select_mask = 0x7e000;
- m_select_value = 0x74000;
- }
m_bank_select = 1;
m_selected = false;
m_clock_count = 0;
diff --git a/src/devices/bus/ti99/peb/peribox.cpp b/src/devices/bus/ti99/peb/peribox.cpp
index 3c93f44e536..ae7ec8ab0dd 100644
--- a/src/devices/bus/ti99/peb/peribox.cpp
+++ b/src/devices/bus/ti99/peb/peribox.cpp
@@ -264,8 +264,10 @@ peribox_device::peribox_device(const machine_config &mconfig, device_type type,
peribox_device::peribox_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: peribox_device(mconfig, TI99_PERIBOX, tag, owner, clock)
{
+ // The address prefix represents a set of pull-up resistors for the
+ // additional address lines AMA, AMB, AMC. They are contained in the
+ // Flex Cable Interface.
m_address_prefix = 0x70000;
- m_genmod = false;
}
READ8Z_MEMBER(peribox_device::readz)
@@ -312,6 +314,17 @@ void peribox_device::cruwrite(offs_t offset, uint8_t data)
}
/*
+ RESET line from the console.
+*/
+WRITE_LINE_MEMBER(peribox_device::reset_in)
+{
+ for (int i=2; i <= 8; i++)
+ {
+ if (m_slot[i]!=nullptr) m_slot[i]->reset_in(state);
+ }
+}
+
+/*
And here are finally the two mythical lines SENILA* and SENILB*; mythical
since there is no report of any software that ever used them.
*/
@@ -428,8 +441,6 @@ void peribox_device::ready_join(int slot, int state)
void peribox_device::set_slot_loaded(int slot, peribox_slot_device* slotdev)
{
m_slot[slot] = slotdev;
- if (slotdev != nullptr)
- slotdev->set_genmod(m_genmod);
}
void peribox_device::device_start()
@@ -500,7 +511,6 @@ peribox_ev_device::peribox_ev_device(const machine_config &mconfig, const char *
: peribox_device(mconfig, TI99_PERIBOX_EV, tag, owner, clock)
{
m_address_prefix = 0x70000;
- m_genmod = false;
}
void ti99_peribox_slot_evpc(device_slot_interface &device)
@@ -548,13 +558,11 @@ peribox_gen_device::peribox_gen_device(const machine_config &mconfig, device_typ
peribox_gen_device::peribox_gen_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: peribox_gen_device(mconfig, TI99_PERIBOX_GEN, tag, owner, clock)
{
- m_genmod = false;
}
peribox_genmod_device::peribox_genmod_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: peribox_gen_device(mconfig, TI99_PERIBOX_GENMOD, tag, owner, clock)
{
- m_genmod = true;
}
// The BwG controller will not run with the Geneve due to its wait state
@@ -601,8 +609,9 @@ void peribox_genmod_device::device_add_mconfig(machine_config &config)
peribox_sg_device::peribox_sg_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: peribox_device(mconfig, TI99_PERIBOX_SG, tag, owner, clock)
{
+ // The SGCPU card contains pull-up registers for the AMA/AMB/AMC lines
+ // like the Flex Cable Interface
m_address_prefix = 0x70000;
- m_genmod = false;
}
void ti99_peribox_slot_sgcpu(device_slot_interface &device)
@@ -685,12 +694,9 @@ WRITE_LINE_MEMBER( peribox_slot_device::clock_in )
m_card->clock_in(state);
}
-/*
- Genmod support
-*/
-void peribox_slot_device::set_genmod(bool set)
+WRITE_LINE_MEMBER( peribox_slot_device::reset_in )
{
- m_card->m_genmod = set;
+ m_card->reset_in(state);
}
void peribox_slot_device::device_start()
@@ -738,13 +744,10 @@ WRITE_LINE_MEMBER( peribox_slot_device::set_ready )
device_ti99_peribox_card_interface::device_ti99_peribox_card_interface(const machine_config &mconfig, device_t &device):
device_interface(device, "ti99peb"),
m_selected(false),
- m_cru_base(0),
- m_select_mask(0),
- m_select_value(0)
+ m_cru_base(0)
{
m_senila = CLEAR_LINE;
m_senilb = CLEAR_LINE;
- m_genmod = false;
}
void device_ti99_peribox_card_interface::interface_config_complete()
@@ -752,4 +755,20 @@ void device_ti99_peribox_card_interface::interface_config_complete()
m_slot = dynamic_cast<peribox_slot_device*>(device().owner());
}
+bool device_ti99_peribox_card_interface::in_dsr_space(offs_t offset, bool amadec)
+{
+ if (amadec)
+ return (offset & 0x7e000)==0x74000;
+ else
+ return (offset & 0x0e000)==0x04000;
+}
+
+bool device_ti99_peribox_card_interface::in_cart_space(offs_t offset, bool amadec)
+{
+ if (amadec)
+ return (offset & 0x7e000)==0x76000;
+ else
+ return (offset & 0x0e000)==0x06000;
+}
+
} } } // end namespace bus::ti99::peb
diff --git a/src/devices/bus/ti99/peb/peribox.h b/src/devices/bus/ti99/peb/peribox.h
index 7444745f3d9..dc294a8778c 100644
--- a/src/devices/bus/ti99/peb/peribox.h
+++ b/src/devices/bus/ti99/peb/peribox.h
@@ -49,6 +49,7 @@ public:
DECLARE_WRITE_LINE_MEMBER( msast_in ) override;
DECLARE_WRITE_LINE_MEMBER( clock_in ) override;
+ DECLARE_WRITE_LINE_MEMBER( reset_in ) override;
// Part of configuration
void set_prefix(int prefix) { m_address_prefix = prefix; }
@@ -107,9 +108,6 @@ protected:
// Configured as a slot device (of the ioport)
bool m_ioport_connected;
-
- // Used for Genmod
- bool m_genmod;
};
/************************************************************************
@@ -182,6 +180,8 @@ public:
virtual DECLARE_SETADDRESS_DBIN_MEMBER(setaddress_dbin) { };
virtual DECLARE_WRITE_LINE_MEMBER(clock_in) { }
+ virtual DECLARE_WRITE_LINE_MEMBER(reset_in) { }
+
void set_senila(int state) { m_senila = state; }
void set_senilb(int state) { m_senilb = state; }
@@ -196,15 +196,13 @@ protected:
// When true, card is accessible. Indicated by a LED.
bool m_selected;
- // When true, GenMod is selected. Modified by peribox_slot_device.
- bool m_genmod;
-
// CRU base. Used to configure the address by which a card is selected.
int m_cru_base;
- // Used to decide whether this card has been selected.
- int m_select_mask;
- int m_select_value;
+ // Methods to decide whether we are acccessing the 4000-5fff region (DSR)
+ // or the cartridge region
+ static bool in_dsr_space(offs_t offset, bool amadec);
+ static bool in_cart_space(offs_t offset, bool amadec);
};
/*****************************************************************************
@@ -236,6 +234,7 @@ public:
DECLARE_WRITE_LINE_MEMBER(senila);
DECLARE_WRITE_LINE_MEMBER(senilb);
DECLARE_WRITE_LINE_MEMBER(clock_in);
+ DECLARE_WRITE_LINE_MEMBER(reset_in);
// Called from the card (direction to box)
DECLARE_WRITE_LINE_MEMBER( set_inta );
@@ -247,7 +246,6 @@ public:
void cruwrite(offs_t offset, uint8_t data);
// called from the box itself
- void set_genmod(bool set);
void set_number(int number) { m_slotnumber = number; }
protected:
diff --git a/src/devices/bus/ti99/peb/samsmem.cpp b/src/devices/bus/ti99/peb/samsmem.cpp
index dff96b57198..61b668bb46e 100644
--- a/src/devices/bus/ti99/peb/samsmem.cpp
+++ b/src/devices/bus/ti99/peb/samsmem.cpp
@@ -19,6 +19,8 @@
called the Super AMS. Any documentation and software containing a reference
to the AEMS are applicable to either AMS or SAMS.
+ The SAMS does not decode AMA/AMB/AMC.
+
Michael Zapf
*****************************************************************************/
@@ -50,7 +52,7 @@ READ8Z_MEMBER(sams_memory_expansion_device::readz)
{
int base;
- if (m_access_mapper && ((offset & 0xe000)==0x4000))
+ if (m_access_mapper && in_dsr_space(offset, false))
{
*value = m_mapper[(offset>>1)&0x000f];
}
@@ -74,7 +76,7 @@ void sams_memory_expansion_device::write(offs_t offset, uint8_t data)
{
int base;
- if (m_access_mapper && ((offset & 0xe000)==0x4000))
+ if (m_access_mapper && in_dsr_space(offset, false))
{
m_mapper[(offset>>1)&0x000f] = data;
}
diff --git a/src/devices/bus/ti99/peb/spchsyn.cpp b/src/devices/bus/ti99/peb/spchsyn.cpp
index 73e6d37e682..4d9f5cbd259 100644
--- a/src/devices/bus/ti99/peb/spchsyn.cpp
+++ b/src/devices/bus/ti99/peb/spchsyn.cpp
@@ -47,7 +47,8 @@ ti_speech_synthesizer_device::ti_speech_synthesizer_device(const machine_config
device_ti99_peribox_card_interface(mconfig, *this),
m_vsp(*this, "vsp"),
m_reading(false),
- m_sbe(false)
+ m_sbe(false),
+ m_dec_high(false)
{
}
@@ -95,7 +96,11 @@ SETADDRESS_DBIN_MEMBER( ti_speech_synthesizer_device::setaddress_dbin )
m_reading = (state==ASSERT_LINE);
bool valid = (((offset & 0x0400)==0) == m_reading);
- m_sbe = ((offset & m_select_mask)==m_select_value) && valid;
+
+ if (m_dec_high)
+ m_sbe = ((offset & 0x7f801)==0x79000) && valid;
+ else
+ m_sbe = ((offset & 0x0f801)==0x09000) && valid;
if (m_sbe)
{
@@ -136,19 +141,9 @@ void ti_speech_synthesizer_device::device_start()
void ti_speech_synthesizer_device::device_reset()
{
- if (m_genmod)
- {
- m_select_mask = 0x1ff801;
- m_select_value = 0x179000;
- }
- else
- {
- m_select_mask = 0x7f801;
- m_select_value = 0x79000;
- }
-
m_reading = false;
m_sbe = false;
+ m_dec_high = (ioport("AMADECODE")->read()!=0);
}
ROM_START( ti99_speech )
@@ -177,6 +172,18 @@ void ti_speech_synthesizer_device::device_add_mconfig(machine_config& config)
*/
}
+INPUT_PORTS_START( ti99_speech )
+ PORT_START( "AMADECODE" )
+ PORT_CONFNAME( 0x01, 0x01, "Decode AMA/AMB/AMC lines" )
+ PORT_CONFSETTING( 0x00, DEF_STR( Off ))
+ PORT_CONFSETTING( 0x01, DEF_STR( On ))
+INPUT_PORTS_END
+
+ioport_constructor ti_speech_synthesizer_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(ti99_speech);
+}
+
const tiny_rom_entry *ti_speech_synthesizer_device::device_rom_region() const
{
return ROM_NAME( ti99_speech );
diff --git a/src/devices/bus/ti99/peb/spchsyn.h b/src/devices/bus/ti99/peb/spchsyn.h
index 8efee71aed7..9b6a464e519 100644
--- a/src/devices/bus/ti99/peb/spchsyn.h
+++ b/src/devices/bus/ti99/peb/spchsyn.h
@@ -37,13 +37,15 @@ protected:
virtual void device_reset() override;
virtual const tiny_rom_entry *device_rom_region() const override;
virtual void device_add_mconfig(machine_config &config) override;
+ virtual ioport_constructor device_input_ports() const override;
private:
DECLARE_WRITE_LINE_MEMBER( speech_ready );
required_device<cd2501e_device> m_vsp;
- bool m_reading;
- bool m_sbe; // Signal "Speech block enable"
+ bool m_reading;
+ bool m_sbe; // Signal "Speech block enable"
+ bool m_dec_high; // Decode the AMA/AMB/ABC address lines
};
} } } // end namespace bus::ti99::peb
diff --git a/src/devices/bus/ti99/peb/ti_fdc.cpp b/src/devices/bus/ti99/peb/ti_fdc.cpp
index 0e293c41401..1ad839ac537 100644
--- a/src/devices/bus/ti99/peb/ti_fdc.cpp
+++ b/src/devices/bus/ti99/peb/ti_fdc.cpp
@@ -105,7 +105,7 @@ SETADDRESS_DBIN_MEMBER( ti_fdc_device::setaddress_dbin )
// Is the card being selected?
m_address = offset;
- m_inDsrArea = ((m_address & m_select_mask)==m_select_value);
+ m_inDsrArea = in_dsr_space(offset, true);
if (!m_inDsrArea || !m_selected) return;
@@ -124,7 +124,7 @@ SETADDRESS_DBIN_MEMBER( ti_fdc_device::setaddress_dbin )
*/
void ti_fdc_device::debug_read(offs_t offset, uint8_t* value)
{
- if (((offset & m_select_mask)==m_select_value) && m_selected)
+ if (in_dsr_space(offset, true) && m_selected)
{
if ((offset & 0x1ff1)!=0x1ff0)
*value = m_dsrrom[offset & 0x1fff];
@@ -349,16 +349,6 @@ void ti_fdc_device::device_start()
void ti_fdc_device::device_reset()
{
- if (m_genmod)
- {
- m_select_mask = 0x1fe000;
- m_select_value = 0x174000;
- }
- else
- {
- m_select_mask = 0x7e000;
- m_select_value = 0x74000;
- }
m_DRQ = CLEAR_LINE;
m_IRQ = CLEAR_LINE;
m_DVENA = CLEAR_LINE;
diff --git a/src/devices/bus/ti99/peb/ti_rs232.cpp b/src/devices/bus/ti99/peb/ti_rs232.cpp
index 1ebae489d3a..ffb1d38c980 100644
--- a/src/devices/bus/ti99/peb/ti_rs232.cpp
+++ b/src/devices/bus/ti99/peb/ti_rs232.cpp
@@ -387,7 +387,7 @@ READ8Z_MEMBER( ti_rs232_pio_device::readz )
// use of it
m_ila = 0;
}
- if (((offset & m_select_mask)==m_select_value) && m_selected)
+ if (in_dsr_space(offset, true) && m_selected)
{
if ((offset & 0x1000)==0x0000)
{
@@ -405,7 +405,7 @@ READ8Z_MEMBER( ti_rs232_pio_device::readz )
*/
void ti_rs232_pio_device::write(offs_t offset, uint8_t data)
{
- if (((offset & m_select_mask)==m_select_value) && m_selected)
+ if (in_dsr_space(offset, true) && m_selected)
{
if ((offset & 0x1001)==0x1000)
{
@@ -1061,17 +1061,6 @@ void ti_rs232_pio_device::device_reset()
m_bufpos[0] = m_bufpos[1] = m_buflen[0] = m_buflen[1] = 0;
- if (m_genmod)
- {
- m_select_mask = 0x1fe000;
- m_select_value = 0x174000;
- }
- else
- {
- m_select_mask = 0x7e000;
- m_select_value = 0x74000;
- }
-
m_selected = false;
m_cru_base = (ioport("CRURS232")->read()==0)? 0x1300 : 0x1500;
diff --git a/src/devices/bus/ti99/peb/tn_ide.cpp b/src/devices/bus/ti99/peb/tn_ide.cpp
index 4654a926791..5feb284f5bc 100644
--- a/src/devices/bus/ti99/peb/tn_ide.cpp
+++ b/src/devices/bus/ti99/peb/tn_ide.cpp
@@ -133,7 +133,7 @@ READ8Z_MEMBER(nouspikel_ide_interface_device::readz)
uint8_t reply = 0;
if (machine().side_effects_disabled()) return;
- if (((offset & m_select_mask)==m_select_value) && m_selected)
+ if (in_dsr_space(offset, true) && m_selected)
{
int addr = offset & 0x1fff;
@@ -199,7 +199,7 @@ void nouspikel_ide_interface_device::write(offs_t offset, uint8_t data)
{
if (machine().side_effects_disabled()) return;
- if (((offset & m_select_mask)==m_select_value) && m_selected)
+ if (in_dsr_space(offset, true) && m_selected)
{
if (m_cru_register & cru_reg_page_switching)
{
@@ -326,16 +326,6 @@ void nouspikel_ide_interface_device::device_reset()
m_sram_enable = false;
m_cru_register = 0;
- if (m_genmod)
- {
- m_select_mask = 0x1fe000;
- m_select_value = 0x174000;
- }
- else
- {
- m_select_mask = 0x7e000;
- m_select_value = 0x74000;
- }
m_selected = false;
m_cru_base = ioport("CRUIDE")->read();
diff --git a/src/devices/bus/ti99/peb/tn_usbsm.cpp b/src/devices/bus/ti99/peb/tn_usbsm.cpp
index 77f933667e9..8f6a9064c7e 100644
--- a/src/devices/bus/ti99/peb/tn_usbsm.cpp
+++ b/src/devices/bus/ti99/peb/tn_usbsm.cpp
@@ -192,7 +192,7 @@ READ8Z_MEMBER(nouspikel_usb_smartmedia_device::readz)
{
if (machine().side_effects_disabled()) return;
- if (((offset & m_select_mask)==m_select_value) && m_selected)
+ if (in_dsr_space(offset, true) && m_selected)
{
if (m_tms9995_mode ? (!(offset & 1)) : (offset & 1))
{
@@ -243,7 +243,7 @@ void nouspikel_usb_smartmedia_device::write(offs_t offset, uint8_t data)
{
if (machine().side_effects_disabled()) return;
- if (((offset & m_select_mask)==m_select_value) && m_selected)
+ if (in_dsr_space(offset, true) && m_selected)
{
/* latch write */
if (offset & 1)
@@ -325,16 +325,6 @@ void nouspikel_usb_smartmedia_device::device_reset()
m_enable_sm = false;
m_write_flash = false;
- if (m_genmod)
- {
- m_select_mask = 0x1fe000;
- m_select_value = 0x174000;
- }
- else
- {
- m_select_mask = 0x7e000;
- m_select_value = 0x74000;
- }
m_selected = false;
m_cru_base = ioport("CRUUSBSM")->read();
diff --git a/src/mame/drivers/geneve.cpp b/src/mame/drivers/geneve.cpp
index c0f40b8769a..c7b871d56a6 100644
--- a/src/mame/drivers/geneve.cpp
+++ b/src/mame/drivers/geneve.cpp
@@ -1,186 +1,174 @@
// license:LGPL-2.1+
// copyright-holders:Michael Zapf
/******************************************************************************
- Myarc Geneve 9640.
-
- The Geneve has two operation modes. One is compatible with the TI-99/4a,
- the other is not.
-
-
- General architecture:
-
- TMS9995@12MHz (including 256 bytes of on-chip 16-bit RAM and a timer),
- V9938, SN76496 (compatible with TMS9919), TMS9901, MM58274 RTC, 512 kbytes
- of 1-wait-state CPU RAM (expandable to almost 2 Mbytes), 32 kbytes of
- 0-wait-state CPU RAM (expandable to 64 kbytes), 128 kbytes of VRAM
- (expandable to 192 kbytes).
-
-
- Memory map:
-
- 64-kbyte CPU address space is mapped to a 2-Mbyte virtual address space.
- 8 8-kbyte pages are available simultaneously, out of a total of 256.
-
- Page map (regular console):
- >00->3f: 512kbytes of CPU RAM (pages >36 and >37 are used to emulate
- cartridge CPU ROMs in ti99 mode, and pages >38 through >3f are used to
- emulate console and cartridge GROMs in ti99 mode)
- >40->7f: optional Memex RAM (except >7a and >7c that are mirrors of >ba and
- >bc?)
- >80->b7: PE-bus space using spare address lines (AMA-AMC)? Used by RAM
- extension (Memex or PE-Bus 512k card).
- >b8->bf: PE-bus space (most useful pages are >ba: DSR space and >bc: speech
- synthesizer page; other pages are used by RAM extension)
- >c0->e7: optional Memex RAM
- >e8->ef: 64kbytes of 0-wait-state RAM (with 32kbytes of SRAM installed,
- only even pages (>e8, >ea, >ec and >ee) are available)
- >f0->f1: boot ROM
- >f2->fe: optional Memex RAM? (except >fa and >fc that are mirrors of >ba
- and >bc?)
- >ff: always empty?
-
- Page map (genmod console):
- >00->39, >40->b9, >bb, >bd->ef, f2->fe: Memex RAM (except >3a, >3c, >7a,
- >7c, >fa and >fc that are mirrors of >ba and >bc?) (I don't know if
- >e8->ef is on the Memex board or the Geneve motherboard)
- >ba: DSR space
- >bc: speech synthesizer space
- >f0->f1: boot ROM
- >ff: always empty?
-
- >00->3f: switch-selectable(?): 512kbytes of onboard RAM (1-wait-state DRAM)
- or first 512kbytes of the Memex Memory board (0-wait-state SRAM). The
- latter setting is incompatible with TI mode.
-
- Note that >bc is actually equivalent to >8000->9fff on the /4a bus,
- therefore the speech synthesizer is only available at offsets >1800->1bff
- (read port) and >1c00->1fff (write port). OTOH, if you installed a FORTI
- sound card, it will be available in the same page at offsets >0400->7ff.
-
-
- Unpaged locations (ti99 mode):
- >8000->8007: memory page registers (>8000 for page 0, >8001 for page 1,
- etc. register >8003 is ignored (this page is hard-wired to >36->37).
- >8008: key buffer
- >8009->800f: ???
- >8010->801f: clock chip
- >8400->9fff: sound, VDP, speech, and GROM registers (according to one
- source, the GROM and sound registers are only available if page >3
- is mapped in at location >c000 (register 6). I am not sure the Speech
- registers are implemented, though I guess they are.)
- Note that >8020->83ff is mapped to regular CPU RAM according to map
- register 4.
-
- Unpaged locations (native mode):
- >f100: VDP data port (read/write)
- >f102: VDP address/status port (read/write)
- >f104: VDP port 2
- >f106: VDP port 3
- >f108->f10f: VDP mirror (used by Barry Boone's converted Tomy cartridges)
- >f110->f117: memory page registers (>f110 for page 0, >f111 for page 1,
- etc.)
- >f118: key buffer
- >f119->f11f: ???
- >f120: sound chip
- >f121->f12f: ???
- >f130->f13f: clock chip
-
- Unpaged locations (tms9995 locations):
- >f000->f0fb and >fffc->ffff: tms9995 RAM
- >fffa->fffb: tms9995 timer register
- Note: accessing tms9995 locations will also read/write corresponding paged
- locations.
-
-
- GROM emulator:
-
- The GPL interface is accessible only in TI99 mode. GPL data is fetched
- from pages >38->3f. It uses a straight 16-bit address pointer. The
- address pointer is incremented when the read data and write data ports
- are accessed, and when the second byte of the GPL address is written. A
- weird consequence of this is the fact that GPL data is always off by one
- byte, i.e. GPL bytes 0, 1, 2... are stored in bytes 1, 2, 3... of pages
- >38->3f (byte 0 of page >38 corresponds to GPL address >ffff).
-
- I think that I have once read that the geneve GROM emulator does not
- emulate wrap-around within a GROM, i.e. address >1fff is followed by >2000
- (instead of >0000 with a real GROM).
-
- There are two ways to implement GPL address load and store.
- One is maintaining 2 flags (one for address read and one for address write)
- that tell if you are accessing address LSB: these flags must be cleared
- whenever data is read, and the read flag must be cleared when the write
- address port is written to.
- The other is to shift the register and always read/write the MSByte of the
- address pointer. The LSByte is copied to the MSbyte when the address is
- read, whereas the former MSByte is copied to the LSByte when the address is
- written. The address pointer must be incremented after the address is
- written to. It will not harm if it is incremented after the address is
- read, provided the LSByte has been cleared.
-
-
- Cartridge emulator:
-
- The cartridge interface is in the >6000->7fff area.
-
- If CRU bit @>F7C is set, the cartridge area is always mapped to virtual
- page >36. Writes in the >6000->6fff area are ignored if the CRU bit @>F7D
- is 0, whereas writes in the >7000->7fff area are ignored if the CRU bit
- @>F7E is 0.
-
- If CRU bit @>F7C is clear, the cartridge area is mapped either to virtual
- page >36 or to page >37 according to which page is currently selected.
- Writing data to address >6000->7fff will select page >36 if A14 is 0,
- >37 if A14 is 1.
-
-
- CRU map:
-
- Base >0000: tms9901
- tms9901 pin assignment:
- int1: external interrupt (INTA on PE-bus) (connected to tms9995 (int4/EC)*
- pin as well)
- int2: VDP interrupt
- int3-int7: joystick port inputs (fire, left, right, down, up)
- int8: keyboard interrupt (asserted when key buffer full)
- int9/p13: unused
- int10/p12: third mouse button
- int11/p11: clock interrupt?
- int12/p10: INTB from PE-bus
- int13/p9: (used as output)
- int14/p8: unused
- int15/p7: (used as output)
- p0: PE-bus reset line
- p1: VDP reset line
- p2: joystick select (0 for joystick 1, 1 for joystick 2)
- p3-p5: unused
- p6: keyboard reset line
- p7/int15: external mem cycles 0=long, 1=short
- p9/int13: vdp wait cycles 1=add 15 cycles, 0=add none
-
- Base >1EE0 (>0F70): tms9995 flags and geneve mode register
- bits 0-1: tms9995 flags
- Bits 2-4: tms9995 interrupt state register
- Bits 5-15: tms9995 user flags - overlaps geneve mode, but hopefully the
- geneve registers are write-only, so no real conflict happens
- TMS9995 user flags:
- Bit 5: 0 if NTSC, 1 if PAL video
- Bit 6: unused???
- Bit 7: some keyboard flag, set to 1 if caps is on
- Geneve gate array + TMS9995 user flags:
- Bit 8: 1 = allow keyboard clock
- Bit 9: 0 = clear keyboard input buffer, 1 = allow keyboard buffer to be
- loaded
- Bit 10: 1 = geneve mode, 0 = ti99 mode
- Bit 11: 1 = ROM mode, 0 = map mode
- Bit 12: 0 = Enable cartridge paging
- Bit 13: 0 = protect cartridge range >6000->6fff
- Bit 14: 0 = protect cartridge range >7000->7fff
- bit 15: 1 = add 1 extra wait state when accessing 0-wait-state SRAM???
-
- Original version 2003 by Raphael Nabet
-
- Rewritten 2012 by Michael Zapf
+
+ ====== Original system =========
+
+ Myarc Geneve 9640
+ =================
+
+ +--------------------------------------------------------------------+
+ | /---\ +---+
+ | +-----+-----+ |Bat| |Vid()
+ | | | | +-HM62256---+ ____\---/ +---+
+ | +-----+-----+ | 32K SRAM ||RTC_|+-------------+ +---+
+ | | 512K | +-----------+ ____ | V9938 | |Mou[]
+ | +- DRAM ---+ +-----------+|Snd_|| VDP | +---+
+ | | ... | ... | | 16K EPROM | +-------------+ +---+
+ | | 16* | +-----------+ +----+ +--+ +----+ |Joy[]
+ | +--HM50256--+ +--------------+ | | +-----+ | | |Keyb| +---+
+ | | 256Kx1 | | TMS9995 | | | |128K | | +---+( )+----+
+ | +-----+-----+ | CPU | |TMS | +Video+ |
+ | | | | +--------------+ |9901| |RAM | | outside of box
+ | +-----+-----+ +--------+ +-+ | | +- - -+ |
+ | | | |P| | | |4*HM | |
+ | | Gate | |A| | | +50464+ |
+ | | Array | |L| +----+ |64Kx4| |
+ O= LED | | +-+ +-----+ |
+ | +-+ +--------+ +-+ |
+ +--------------+ | | +---------+
+ Front ||||||||||||||||||||||| Back
+ +---------------------+
+
+ The Geneve 9640 is a card for the Peripheral Expansion Box of the TI-99/4A
+ system, equipped with a complete computing architecture and thus replaces
+ the TI console. It was created by the company Myarc Inc. in 1987, who also
+ manufactured several expansion cards for the TI system (like floppy disk
+ controllers, hard disk controllers, serial interfaces, memory expansions).
+
+ The Geneve 9640 got its name purportedly from a picture at the wall of
+ one of its creators, showing the Swiss city Geneva (Geneve). The number
+ 9640 should be read as 9-640, with the 9 being a reference to the TI-99
+ family (TI did not agree to use the 99 as a reference), and the 640 as
+ the amount of built-in RAM (CPU + video).
+
+ It is equipped with a TMS9995 microprocessor, which is downward compatible
+ with the TMS9900 used in the TI console. It is clocked at 12 MHz,
+ internally divided by 4, which makes it compatible with the expected clock
+ rate of external devices, but internally it is much more efficient and
+ can execute TMS programs about 2-3 times faster. For more details, see
+ tms9995.cpp.
+
+ General architecture
+ --------------------
+ - CPU: TMS9995, 12 Mhz, with 256 bytes on-chip RAM and decrementer
+ - RAM: SRAM (32 KiB, 0 wait states, HM62256 32Kx8),
+ DRAM (512 KiB, 1 wait state, 16*HM50256 256Kx1)
+ - Video: Yamaha V9938 (compatible to TMS9928, also used in MSX2)
+ - Video memory: 128 KiB (4*HM50464 64Kx4)
+ - Sound: SN76496 (compat. to TMS9919)
+ - System interface: TMS9901
+ - Real time clock: MM58274, battery-backed
+ - Keyboard: Connector for external XT-compatible keyboard
+ - Mouse: Bus mouse connector, going to the color bus of the V9938
+ - Joysticks: TI-99/4A joystick connector
+ - Video output: RGB or composite via DIN plug
+
+ A Gate Array circuit (labeled Myarc M60014-1004J 715500) contains most of
+ logic circuitry for device and memory selection, a memory mapper, and the
+ keyboard interface. Unfortunately, the details of its implementation must
+ be considered as lost. We can only guess its implementation by its
+ behavior.
+
+ Also, a PAL circuit (PAL16R4ACN) is mounted on the board whose task is
+ to drive the READY line to the processor and selection lines to the
+ peribox. The equations of the PAL are available. The PAL controls
+ the creation of wait states according to the device or memory selected
+ by the Gate Array.
+
+
+ Operating modes
+ ---------------
+ To achieve a maximum degree of compatibility, the Geneve offers two
+ operation modes: native and GPL.
+
+ In the GPL mode, memory space layout is largely equal to the TI-99/4A
+ layout, thus allowing programs to run without any adaptation.
+
+ The native mode rearranges the memory layout in order to exploit all
+ capabilities of the enhanced architecture. However, this mode cannot run
+ older TI-99 programs.
+
+ Memory Map
+ ----------
+ The memory map is described in genboard.cpp where the emulation of the
+ Gate Array and the PAL are implemented.
+
+ CRU map
+ -------
+ The CRU space contains the selectable devices and flags of the system.
+ For more details, see genboard.cpp.
+
+
+ ====== Modifications ===========
+
+ 32K SRAM expansion
+ ------------------
+ The schematics prove that Myarc already planned for a 32K expansion of
+ the stock 32K SRAM memory. One additional chip is soldered on top
+ of the base 32K chip, with its CE* line (pin 20) wired to pin 48 of the
+ Gate Array (RAMEN-X*).
+
+ The 32K expansion is required for releases of the operating system (MDOS)
+ later than version 2.5.
+
+
+ PFM: Boot EPROM replacement
+ ---------------------------
+ The Programmable Flash Memory mod replaces the stock EPROM (16K) by a
+ flash memory chip (AT29C040(A) for 512K). It is enabled by selecting
+ the machine configuration switch BOOTROM. When set to EPROM, the mod is
+ inactive.
+
+ There were several versions. Only the third one is emulated, since it
+ functionally subsumes the other two:
+
+ PFM: Original version, 128 KiB
+ PFM+: Expansion of the original version, piggybacked, adds another 128KiB
+ PFM512: Using an AT29C040 (not A), 512 KiB
+
+ The PFM512 is visible as four banks in memory pages 0xF0-0xFF.
+ Bank 0 is the boot code, while banks 1-3 can be used as flash drives.
+
+ The lower 13 bits (A3-A15 by TI counting) of its memory space are set by
+ the main address bus, provided that the Gate Array enables the access.
+ This is true when the EPROM bank area is accessed (pages F0-FF) or in
+ direct mode (unmapped mode, used during boot).
+
+ The next four bits (AMA, AB0, AB1, AB2) are set by the Gate Array as the
+ lower four bits of the page number (F0-FF, i.e. 0-F). Note that the AMB
+ and further lines cannot be used, because the boot ROM area is restricted
+ to that range by the Gate Array.
+
+ To set the most significant two bits of the flash memory chip (A17 and A18
+ in the usual counting), two dedicated CRU bits are used, set and latched
+ by the 9901 chip. Also, the output can be disabled by another CRU bit.
+
+ CRU 0028: LSB of bank number
+ CRU 003A: MSB of bank number
+ CRU 002A: PFM output enable
+
+ Genmod
+ ------
+ A special modification was published for the Geneve around 1990. The goal
+ was to fill all memory space with physical memory from a memory
+ expansion card, and also to make use of 0-wait state SRAM from this card.
+ The mod required some few changes on the Geneve card. The Geneve itself
+ never had a large user base, compared to the 99/4A, and this modification
+ was even much rarer. Nevertheless, its interesting point is that it
+ in fact expands the Geneve architecture to its maximum.
+
+ For more details, see genboard.cpp.
+
+ Genmod is treated as a separate system in MAME. Beside the modified
+ hardware, it also requires a modified boot ROM.
+
+ ============================================
+
+ 2003: Original version by Raphael Nabet
+ 2012: Rewritten by Michael Zapf (functionally, high level)
+ 2019: Rewritten by Michael Zapf (closer to the actual hardware)
+
******************************************************************************/
#include "emu.h"
@@ -204,16 +192,33 @@
#include "speaker.h"
#define LOG_WARN (1U<<1)
-#define LOG_READY (1U<<2)
-#define LOG_LINES (1U<<3)
#define LOG_CRU (1U<<4)
#define LOG_CRUKEY (1U<<5)
+#define LOG_READ (1U<<6)
+#define LOG_READG (1U<<7)
+#define LOG_WRITE (1U<<8)
+#define LOG_SETTING (1U<<9)
+#define LOG_PFM (1U<<10)
// Minimum log should be settings and warnings
-#define VERBOSE ( LOG_GENERAL | LOG_WARN )
+#define VERBOSE ( LOG_GENERAL | LOG_SETTING | LOG_WARN )
#include "logmacro.h"
+#define GENEVE_SRAM_TAG "sram"
+#define GENEVE_SRAMX_TAG "sramexp"
+#define GENEVE_DRAM_TAG "dram"
+#define GENEVE_CLOCK_TAG "mm58274c"
+
+enum
+{
+ AB2 = 1,
+ AB1 = 2,
+ AB0 = 4,
+ AMA = 8,
+ FULLGEN = 63, // AMC,AMB,AMA,AB0,AB1,AB2
+ FULLGNM = 255 // AME,AMD,FULLGEN
+};
void geneve_xt_keyboards(device_slot_interface &device)
{
@@ -229,20 +234,37 @@ public:
: driver_device(mconfig, type, tag),
m_cpu(*this, "maincpu"),
m_tms9901(*this, TI_TMS9901_TAG),
+ m_sound(*this, TI_SOUNDCHIP_TAG),
+ m_video(*this, TI_VDP_TAG),
+ m_rtc(*this, GENEVE_CLOCK_TAG),
+ m_dram(*this, GENEVE_DRAM_TAG),
+ m_sram(*this, GENEVE_SRAM_TAG),
+ m_sramx(*this, GENEVE_SRAMX_TAG),
m_gatearray(*this, GENEVE_GATE_ARRAY_TAG),
- m_peribox(*this, TI_PERIBOX_TAG),
+ m_genmod_decoder(*this, GENMOD_DECODER_TAG),
+ m_pal(*this, GENEVE_PAL_TAG),
m_joyport(*this, TI_JOYPORT_TAG),
m_colorbus(*this, COLORBUS_TAG),
m_kbdconn(*this, GENEVE_KEYBOARD_CONN_TAG),
- m_left_button(0)
+ m_peribox(*this, TI_PERIBOX_TAG),
+ m_pfm512(*this, GENEVE_PFM512_TAG),
+ m_pfm512a(*this, GENEVE_PFM512A_TAG),
+ m_left_button(0),
+ m_pfm_prefix(0),
+ m_pfm_oe(true),
+ m_sram_exp(true),
+ m_genmod(false)
{
}
void geneve_common(machine_config &config);
void geneve(machine_config &config);
void genmod(machine_config &config);
-
void init_geneve();
+ void init_genmod();
+
+ DECLARE_INPUT_CHANGED_MEMBER( settings_changed );
+ DECLARE_INPUT_CHANGED_MEMBER( setgm_changed );
private:
// CRU (Communication Register Unit) handling
@@ -254,7 +276,6 @@ private:
DECLARE_WRITE_LINE_MEMBER(peripheral_bus_reset);
DECLARE_WRITE_LINE_MEMBER(VDP_reset);
DECLARE_WRITE_LINE_MEMBER(joystick_select);
- DECLARE_WRITE_LINE_MEMBER(extbus_wait_states);
DECLARE_WRITE_LINE_MEMBER(keyboard_reset);
DECLARE_WRITE_LINE_MEMBER(video_wait_states);
DECLARE_WRITE_LINE_MEMBER(left_mouse_button);
@@ -270,39 +291,74 @@ private:
DECLARE_WRITE_LINE_MEMBER( keyboard_interrupt );
- required_device<tms9995_device> m_cpu;
- required_device<tms9901_device> m_tms9901;
- required_device<bus::ti99::internal::geneve_gate_array_device> m_gatearray;
- required_device<bus::ti99::peb::peribox_device> m_peribox;
- required_device<bus::ti99::joyport::joyport_device> m_joyport;
- required_device<bus::ti99::colorbus::v9938_colorbus_device> m_colorbus;
- required_device<pc_kbdc_device> m_kbdconn;
+ required_device<tms9995_device> m_cpu;
+ required_device<tms9901_device> m_tms9901;
+ required_device<sn76496_device> m_sound;
+ required_device<v9938_device> m_video;
+ required_device<mm58274c_device> m_rtc;
+ required_device<ram_device> m_dram;
+ required_device<ram_device> m_sram;
+ required_device<ram_device> m_sramx;
+
+ required_device<bus::ti99::internal::geneve_gate_array_device> m_gatearray;
+ optional_device<bus::ti99::internal::genmod_decoder_device> m_genmod_decoder;
+ required_device<bus::ti99::internal::geneve_pal_device> m_pal;
+ required_device<bus::ti99::joyport::joyport_device> m_joyport;
+ required_device<bus::ti99::colorbus::v9938_colorbus_device> m_colorbus;
+ required_device<pc_kbdc_device> m_kbdconn;
+ required_device<bus::ti99::peb::peribox_device> m_peribox;
+
+ uint8_t* m_eprom; // Pointer to the EPROM
+ // PFM expansion
+ required_device<at29c040_device> m_pfm512;
+ required_device<at29c040a_device> m_pfm512a;
+ void read_eprom_or_pfm(offs_t offset, uint8_t& value);
+ DECLARE_WRITE8_MEMBER( write_pfm );
+ DECLARE_WRITE_LINE_MEMBER( pfm_a17 );
+ DECLARE_WRITE_LINE_MEMBER( pfm_a18 );
+ DECLARE_WRITE_LINE_MEMBER( pfm_oe );
+
+ // Interrupts
DECLARE_WRITE_LINE_MEMBER( inta );
DECLARE_WRITE_LINE_MEMBER( intb );
- DECLARE_WRITE_LINE_MEMBER( ext_ready );
- DECLARE_WRITE_LINE_MEMBER( mapper_ready );
DECLARE_WRITE_LINE_MEMBER( keyboard_int );
+ DECLARE_WRITE_LINE_MEMBER( int2_from_v9938 );
+
+ // READY line contributors
+ DECLARE_WRITE_LINE_MEMBER( extready );
+ DECLARE_WRITE_LINE_MEMBER( sndready );
+
+ // Memory bus
+ void setaddress_debug(bool debug, offs_t address, uint8_t busctrl);
+ void setaddress(offs_t address, uint8_t busctrl);
+ DECLARE_READ8_MEMBER( memread );
+ DECLARE_WRITE8_MEMBER( memwrite );
+
+ void crumap(address_map &map);
+ void memmap(address_map &map);
+ void memmap_setaddress(address_map &map);
+ // General device lifecycle
virtual void machine_start() override;
virtual void machine_reset() override;
- DECLARE_WRITE_LINE_MEMBER(set_tms9901_INT2_from_v9938);
-
+ // Members
int m_inta;
int m_intb;
int m_int2;
int m_keyint;
- int m_video_wait; // reflects the line to the mapper for CRU query
- int m_ready_line;
- int m_ready_line1;
+ int m_left_button; // Left mouse button, not wired to the 9938
+ int m_pfm_prefix;
+ bool m_pfm_oe;
- int m_left_button;
+ // Settings
+ int m_boot_rom; // Kind of boot ROM (EPROM or PFM512 or PFM512A)
+ bool m_sram_exp;
- void crumap(address_map &map);
- void memmap(address_map &map);
- void memmap_setaddress(address_map &map);
+ // Genmod modifications
+ bool m_genmod;
};
/*
@@ -311,12 +367,12 @@ private:
void geneve_state::memmap(address_map &map)
{
- map(0x0000, 0xffff).rw(GENEVE_GATE_ARRAY_TAG, FUNC(bus::ti99::internal::geneve_gate_array_device::readm), FUNC(bus::ti99::internal::geneve_gate_array_device::writem));
+ map(0x0000, 0xffff).rw(FUNC(geneve_state::memread), FUNC(geneve_state::memwrite));
}
void geneve_state::memmap_setaddress(address_map &map)
{
- map(0x0000, 0xffff).w(GENEVE_GATE_ARRAY_TAG, FUNC(bus::ti99::internal::geneve_gate_array_device::setaddress));
+ map(0x0000, 0xffff).w(FUNC(geneve_state::setaddress));
}
/*
@@ -324,19 +380,19 @@ void geneve_state::memmap_setaddress(address_map &map)
The TMS9901 is fully decoded, no mirroring, so we have 32 bits for it,
and the rest goes to the board (and from there to the PEB)
TMS9995 has a full 15-bit CRU bit address space (attached to A0-A14)
- TODO: Check whether A0-A2 are available for CRU addressing since those
- bits are usually routed through the mapper first.
*/
void geneve_state::crumap(address_map &map)
{
map(0x0000, 0xffff).rw(FUNC(geneve_state::cruread), FUNC(geneve_state::cruwrite));
+ map(0x1ee0, 0x1eff).w(m_gatearray, FUNC(bus::ti99::internal::geneve_gate_array_device::cru_ctrl_write));
+ map(0x13c0, 0x13cf).w(m_gatearray, FUNC(bus::ti99::internal::geneve_gate_array_device::cru_sstep_write));
map(0x0000, 0x003f).rw(m_tms9901, FUNC(tms9901_device::read), FUNC(tms9901_device::write));
}
static INPUT_PORTS_START(geneve_common)
PORT_START( "BOOTROM" )
- PORT_CONFNAME( 0x03, GENEVE_EPROM, "Boot from" ) PORT_CHANGED_MEMBER(GENEVE_GATE_ARRAY_TAG, bus::ti99::internal::geneve_gate_array_device, settings_changed, 3)
+ PORT_CONFNAME( 0x03, GENEVE_EPROM, "Boot from" ) PORT_CHANGED_MEMBER(DEVICE_SELF, geneve_state, settings_changed, 3)
PORT_CONFSETTING( GENEVE_EPROM, "EPROM" )
PORT_CONFSETTING( GENEVE_PFM512, "PFM 512" )
PORT_CONFSETTING( GENEVE_PFM512A, "PFM 512A" )
@@ -352,10 +408,9 @@ static INPUT_PORTS_START(geneve)
PORT_INCLUDE(geneve_common)
PORT_START( "SRAM" )
- PORT_CONFNAME( 0x03, 0x01, "Onboard SRAM" )
- PORT_CONFSETTING( 0x00, "32 KiB" )
- PORT_CONFSETTING( 0x01, "64 KiB" )
- PORT_CONFSETTING( 0x02, "384 KiB" )
+ PORT_CONFNAME( 0x03, 0x01, "SRAM expansion 32K" )
+ PORT_CONFSETTING( 0x00, "off" )
+ PORT_CONFSETTING( 0x01, "on" )
INPUT_PORTS_END
@@ -363,113 +418,400 @@ static INPUT_PORTS_START(genmod)
PORT_INCLUDE(geneve_common)
PORT_START( "GENMODDIPS" )
- PORT_DIPNAME( GENEVE_GM_TURBO, 0x00, "Genmod Turbo mode") PORT_CHANGED_MEMBER(GENEVE_GATE_ARRAY_TAG, bus::ti99::internal::genmod_gate_array_device, setgm_changed, 1)
+ PORT_DIPNAME( GENEVE_GM_TURBO, 0x00, "Genmod Turbo mode") PORT_CHANGED_MEMBER(DEVICE_SELF, geneve_state, setgm_changed, 1)
PORT_CONFSETTING( 0x00, DEF_STR( Off ))
PORT_CONFSETTING( GENEVE_GM_TURBO, DEF_STR( On ))
- PORT_DIPNAME( GENEVE_GM_TIM, GENEVE_GM_TIM, "Genmod TI mode") PORT_CHANGED_MEMBER(GENEVE_GATE_ARRAY_TAG, bus::ti99::internal::genmod_gate_array_device, setgm_changed, 2)
+ PORT_DIPNAME( GENEVE_GM_TIM, GENEVE_GM_TIM, "Genmod TI mode") PORT_CHANGED_MEMBER(DEVICE_SELF, geneve_state, setgm_changed, 2)
PORT_CONFSETTING( 0x00, DEF_STR( Off ))
PORT_CONFSETTING( GENEVE_GM_TIM, DEF_STR( On ))
INPUT_PORTS_END
+INPUT_CHANGED_MEMBER( geneve_state::settings_changed )
+{
+ // Used when switching the boot ROMs during runtime, especially the PFM
+ m_boot_rom = newval;
+}
-/****************************************************************************
- CRU handling
-*****************************************************************************/
+INPUT_CHANGED_MEMBER( geneve_state::setgm_changed )
+{
+ int number = int(param&0x03);
+ int value = newval;
+
+ switch (number)
+ {
+ case 1:
+ // Turbo switch. May be changed at any time.
+ LOGMASKED(LOG_SETTING, "Setting turbo flag to %d\n", value);
+ m_genmod_decoder->set_turbo(value!=0);
+ break;
+ case 2:
+ // TIMode switch. Causes reset when changed.
+ LOGMASKED(LOG_SETTING, "Setting timode flag to %d\n", value);
+ m_genmod_decoder->set_timode(value!=0);
+ machine().schedule_hard_reset();
+ break;
+ case 3:
+ // Used when switching the boot ROMs during runtime, especially the PFM
+ m_boot_rom = value;
+ break;
+ default:
+ LOGMASKED(LOG_WARN, "Unknown setting %d ignored\n", number);
+ }
+}
-#define CRU_CONTROL_BASE 0x1ee0
-#define CRU_SSTEP_BASE 0x13c0
+/*
+ Propagate the address bus levels to the Gate Array. This will make it
+ create waitstates before the read operation and assert the selector lines.
+*/
+void geneve_state::setaddress(offs_t address, uint8_t busctrl)
+{
+ setaddress_debug(false, address, busctrl);
+}
-void geneve_state::cruwrite(offs_t offset, uint8_t data)
+void geneve_state::setaddress_debug(bool debug, offs_t address, uint8_t busctrl)
{
- int addroff = offset << 1;
+ m_gatearray->set_debug(debug);
+ m_gatearray->setaddress(address, busctrl);
- // Single step
- // 13c0 - 13fe: 0001 0011 11xx xxx0
- if ((addroff & 0xffc0) == CRU_SSTEP_BASE)
+ // Genmod
+ if (m_genmod)
{
- int bit = (addroff & 0x003e)>>1;
- LOGMASKED(LOG_WARN, "Single step not implemented; bit %d set to %d\n", bit, data);
- return;
+ m_genmod_decoder->set_debug(debug);
+ m_genmod_decoder->set_function(m_gatearray->get_function(), m_gatearray->get_prefix(FULLGNM)>>13);
}
- // This is just mirroring the internal flags of the 9995
- if ((addroff & 0xffe0) == CRU_CONTROL_BASE)
+ // Insert a wait state except for SRAM (not by debugger)
+ if (!debug)
{
- int bit = (addroff & 0x001e)>>1;
- switch (bit)
+ // Note that the CSR/CSW inputs must not be asserted for more than
+ // 2 us; i.e. they cannot remain asserted for the whole 14 wait cycles
+ // (which are 4.6 us). Accordingly, we have to assume that the CSW/CSR
+ // signals are only asserted for a single clock cycle (333ns, which
+ // is more than the minimum pulse width of 186 ns).
+ // See V9938 specs
+ m_pal->csw_in(m_gatearray->csw_out());
+ m_pal->csr_in(m_gatearray->csr_out());
+ }
+
+ // Going to the box
+ int extbus = m_genmod? m_genmod_decoder->dben_out() : m_gatearray->dben_out();
+
+ if (extbus==ASSERT_LINE)
+ {
+ offs_t addr13 = address & 0x1fff;
+ m_peribox->memen_in(ASSERT_LINE);
+ m_peribox->setaddress_dbin(m_gatearray->get_prefix(m_genmod? FULLGNM : FULLGEN) | addr13, ((busctrl & TMS99xx_BUS_DBIN)!=0));
+ }
+}
+
+READ8_MEMBER( geneve_state::memread )
+{
+ uint8_t value = 0;
+ offs_t sramadd;
+ offs_t dramadd;
+ offs_t pboxadd;
+ offs_t addr13 = offset & 0x1fff;
+
+ if (machine().side_effects_disabled())
+ {
+ if (m_cpu->is_onchip(offset))
+ return m_cpu->debug_read_onchip_memory(offset);
+
+ // The debugger does not call setaddress, so we do it here
+ // Also, the decode result is replaced by the debugger version
+ setaddress_debug(true, offset, TMS99xx_BUS_DBIN);
+ }
+
+ // Video read (never by debugger)
+ if (m_gatearray->csr_out()==ASSERT_LINE)
+ {
+ value = m_video->read((offset>>1)&3); // M1=A13, M0=A14
+ LOGMASKED(LOG_READ, "Read video %04x -> %02x\n", offset, value);
+ }
+
+ // All of the following parts are accessed in parallel and can set the
+ // value on the data bus. In reality, if several of them did, this would
+ // be a bug and likely damage the machine.
+
+ // Gate array itself (Keyboard, mapper, GROM address register)
+ // If not addressed, value remains unchanged
+ m_gatearray->readz(value);
+
+ // Clock
+ // The clock is connected with only 4 data bits. Tests on the real machine
+ // showed that the upper nibble is 0xf (probably because of the location
+ // at f130-f13f?)
+ // In TI mode, however, the upper nibble is 1, unless we read 801f,
+ // in which case the nibble is 2. Here the location is 8010-801f.
+ // Needs more investigation. Simply clearing the upper nibble will not work
+ // for some software that assumes these bits to be set.
+ if (m_gatearray->rtcen_out()==ASSERT_LINE)
+ {
+ value = m_rtc->read(offset & 0x000f);
+ if (m_gatearray->geneve_mode())
+ value |= 0xf0;
+ else
+ value |= ((offset & 0x001f)+1) & 0xf0;
+
+ LOGMASKED(LOG_READ, "Read clock %04x -> %02x\n", offset, value);
+ }
+
+ // DRAM (also for GROM simulator)
+ // Genmod uses the box, but also the DRAM in parallel. Only for
+ // TIMODE, the box access is suppressed.
+ if (m_gatearray->accessing_dram())
+ {
+ dramadd = m_gatearray->get_dram_address();
+ value = m_dram->pointer()[dramadd];
+
+ const char* ramtype = (m_gatearray->accessing_grom())? "GROM" : "DRAM";
+ LOGMASKED(LOG_READ, "Read %s %04x (%06x) -> %02x\n", ramtype, offset, dramadd, value);
+ }
+
+ // Boot ROM or PFM (normal and Genmod)
+ if (m_gatearray->romen_out()==ASSERT_LINE)
+ read_eprom_or_pfm(offset, value);
+
+ // Stock SRAM 32K (normal and Genmod)
+ if (m_gatearray->ramen_out()==ASSERT_LINE)
+ {
+ sramadd = m_gatearray->get_prefix(AB1 | AB2) | addr13;
+ value = m_sram->pointer()[sramadd];
+ LOGMASKED(LOG_READ, "Read SRAM %04x (%04x) -> %02x\n", offset, sramadd, value);
+ }
+
+ // Expanded SRAM 32K (not in Genmod)
+ if (!m_genmod)
+ {
+ if (m_gatearray->ramenx_out()==ASSERT_LINE)
{
- case 5:
- // No one really cares...
- LOGMASKED(LOG_CRU, "Set PAL flag = %02x\n", data);
- // m_palvideo = (data!=0);
- break;
- case 7:
- // m_capslock = (data!=0);
- LOGMASKED(LOG_CRU, "Set capslock flag = %02x\n", data);
- break;
- case 8:
- LOGMASKED(LOG_CRUKEY, "Set keyboard clock = %02x\n", data);
- m_gatearray->set_keyboard_clock(data);
- break;
- case 9:
- LOGMASKED(LOG_CRUKEY, "Enable keyboard shift reg = %02x\n", data);
- m_gatearray->enable_shift_register(data);
- break;
- case 10:
- LOGMASKED(LOG_CRU, "Geneve mode = %02x\n", data);
- m_gatearray->set_geneve_mode(data!=0);
- break;
- case 11:
- LOGMASKED(LOG_CRU, "Direct mode = %02x\n", data);
- m_gatearray->set_direct_mode(data!=0);
- break;
- case 12:
- LOGMASKED(LOG_CRU, "Cartridge size 8K = %02x\n", data);
- m_gatearray->set_cartridge_size((data!=0)? 0x2000 : 0x4000);
- break;
- case 13:
- LOGMASKED(LOG_CRU, "Cartridge writable 6000 = %02x\n", data);
- m_gatearray->set_cartridge_writable(0x6000, (data!=0));
- break;
- case 14:
- LOGMASKED(LOG_CRU, "Cartridge writable 7000 = %02x\n", data);
- m_gatearray->set_cartridge_writable(0x7000, (data!=0));
- break;
- case 15:
- LOGMASKED(LOG_CRU, "Extra wait states = %02x\n", data==0);
- m_gatearray->set_extra_waitstates(data==0); // let's use the inverse semantics
- break;
- default:
- LOGMASKED(LOG_WARN, "set CRU address %04x=%02x ignored\n", addroff, data);
- break;
+ if (m_sram_exp)
+ {
+ sramadd = m_gatearray->get_prefix(AB1 | AB2) | addr13;
+ value = m_sramx->pointer()[sramadd];
+ LOGMASKED(LOG_READ, "Read SRAMX %04x (%04x) -> %02x\n", offset, sramadd, value);
+ }
+ else
+ LOGMASKED(LOG_WARN, "Access to SRAMX %04x, but no SRAM expansion available\n", offset);
}
}
- else
+
+ // Peripheral box
+ if ((m_genmod && m_genmod_decoder->dben_out())
+ || (!m_genmod && m_gatearray->dben_out()==ASSERT_LINE))
{
- m_peribox->cruwrite(addroff, data);
+ pboxadd = m_gatearray->get_prefix(m_genmod? FULLGNM : FULLGEN) | addr13;
+ m_peribox->readz(pboxadd, &value);
+ m_peribox->memen_in(CLEAR_LINE);
+ LOGMASKED(LOG_READ, "Read P-Box [%s] %04x (%06x) -> %02x\n", m_genmod? "GeM" : "Gen", offset, pboxadd, value);
}
+
+ // In case we had a debugger read, reset the flag.
+ m_gatearray->set_debug(false);
+
+ return value;
}
-uint8_t geneve_state::cruread(offs_t offset)
+WRITE8_MEMBER( geneve_state::memwrite )
{
- uint8_t value = 0;
- uint16_t addroff = offset << 1;
+ offs_t sramadd = 0;
+ offs_t dramadd = 0;
+ offs_t pboxadd = 0;
+
+ offs_t addr13 = offset & 0x1fff;
+
+ if (machine().side_effects_disabled())
+ {
+ // TODO: add method to tms9995
+// if (m_cpu->is_onchip(offset))
+// {
+// m_cpu->debug_write_onchip_memory(offset, data);
+// return;
+// }
+
+ // The debugger does not call setaddress, so we do it here
+ // Also, the decode result is replaced by the debugger version
+ setaddress_debug(true, offset, 0);
+ }
+
+ // Video write (never by debugger)
+ if (m_gatearray->csw_out()==ASSERT_LINE)
+ {
+ LOGMASKED(LOG_WRITE, "Write video %04x <- %02x\n", offset, data);
+ m_video->write((offset>>1)&3, data); // M1=A13, M0=A14
+ }
+
+ // Gate array itself (Keyboard, mapper, GROM address (not by debugger))
+ // Has no effect when not addressed
+ m_gatearray->write(data);
+
+ // Clock
+ if (m_gatearray->rtcen_out()==ASSERT_LINE)
+ {
+ LOGMASKED(LOG_WRITE, "Write clock %04x <- %02x\n", offset, data);
+ m_rtc->write(offset & 0x000f, data);
+ }
- // Single step
- // 13c0 - 13fe: 0001 0011 11xx xxx0
- if ((addroff & 0xffc0) == CRU_SSTEP_BASE)
+ // DRAM (also for GROM simulator)
+ if (m_gatearray->accessing_dram())
{
- int bit = (addroff & 0x003e)>>1;
- LOGMASKED(LOG_WARN, "Single step not implemented; attempting to read bit %d\n", bit);
- return value;
+ // We block the write access to the DRAM for the Genmod when not in TI mode
+ // This is not verified to happen on the real machine, but if we do not
+ // block, page 3A will be declared as available, which is wrong.
+ if (!m_genmod || !m_genmod_decoder->dben_out())
+ {
+ dramadd = m_gatearray->get_dram_address();
+ m_dram->pointer()[dramadd] = data;
+ const char* ramtype = (m_gatearray->accessing_grom())? "GROM" : "DRAM";
+ LOGMASKED(LOG_WRITE, "Write %s %04x (%06x) <- %02x\n", ramtype, offset, dramadd, data);
+ }
}
- // TMS9995-internal CRU locations (1ee0-1efe) are handled within the processor
- // so we just don't arrive here
+ // Sound
+ if (m_gatearray->snden_out()==ASSERT_LINE)
+ {
+ LOGMASKED(LOG_WRITE, "Write sound <- %02x\n", data);
+ m_sound->write(data);
+ }
+ // Stock SRAM 32K
+ if (m_gatearray->ramen_out()==ASSERT_LINE)
+ {
+ sramadd = m_gatearray->get_prefix(AB1 | AB2) | addr13;
+ LOGMASKED(LOG_WRITE, "Write SRAM %04x (%04x) <- %02x\n", offset, sramadd, data);
+ m_sram->pointer()[sramadd] = data;
+ }
+
+ // Expanded SRAM
+ if (!m_genmod)
+ {
+ if (m_gatearray->ramenx_out()==ASSERT_LINE)
+ {
+ if (m_sram_exp)
+ {
+ sramadd = m_gatearray->get_prefix(AB1 | AB2) | addr13;
+ LOGMASKED(LOG_WRITE, "Write SRAMX %04x (%04x) <- %02x\n", offset, sramadd, data);
+ m_sramx->pointer()[sramadd] = data;
+ }
+ else
+ LOGMASKED(LOG_WARN, "Access to SRAMX %04x, but no SRAM expansion available\n", offset);
+ }
+ }
+
+ // Peripheral box
+ if ((m_genmod && m_genmod_decoder->dben_out())
+ || (!m_genmod && m_gatearray->dben_out()==ASSERT_LINE))
+ {
+ pboxadd = m_gatearray->get_prefix(m_genmod? FULLGNM : FULLGEN) | addr13;
+ LOGMASKED(LOG_WRITE, "Write P-Box [%s] %04x (%06x) <- %02x\n", m_genmod? "GeM" : "Gen", offset, pboxadd, data);
+ m_peribox->write(pboxadd, data);
+ m_peribox->memen_in(CLEAR_LINE);
+ }
+
+ // In case we had a debugger write, reset the flag.
+ m_gatearray->set_debug(false);
+}
+
+/****************************************************************************
+ PFM handling
+*****************************************************************************/
+
+WRITE_LINE_MEMBER( geneve_state::pfm_a17 )
+{
+ if (state==ASSERT_LINE) m_pfm_prefix |= 0x20000;
+ else m_pfm_prefix &= ~0x20000;
+}
+
+WRITE_LINE_MEMBER( geneve_state::pfm_a18 )
+{
+ if (state==ASSERT_LINE) m_pfm_prefix |= 0x40000;
+ else m_pfm_prefix &= ~0x40000;
+}
+
+WRITE_LINE_MEMBER( geneve_state::pfm_oe )
+{
+ // Negative logic
+ LOGMASKED(LOG_PFM, "PFM output %s\n", (state==0)? "enable" : "disable");
+ m_pfm_oe = (state==0);
+}
+
+/*
+ Boot ROM handling, from EPROM or PFM.
+*/
+void geneve_state::read_eprom_or_pfm(offs_t offset, uint8_t& value)
+{
+ int pfmaddress;
+ offs_t addr13 = offset & 0x1fff;
+
+ switch (m_boot_rom)
+ {
+ case GENEVE_EPROM:
+ // Mirrors at pages F0, F2, F4,... FE, and F1, F3, ... FF.
+ value = m_eprom[addr13 | m_gatearray->get_prefix(AB2)];
+ LOGMASKED(LOG_READ, "Read EPROM %04x -> %02x\n", offset, value);
+ break;
+ case GENEVE_PFM512:
+ pfmaddress = addr13 | m_gatearray->get_prefix(AMA | AB0 | AB1 | AB2) | m_pfm_prefix;
+ if (m_pfm_oe)
+ {
+ value = m_pfm512->read(pfmaddress);
+ LOGMASKED(LOG_PFM, "PFM %05x -> %02x\n", pfmaddress, value);
+ }
+ else LOGMASKED(LOG_PFM, "PFM %05x disabled\n", pfmaddress);
+ break;
+ case GENEVE_PFM512A:
+ pfmaddress = addr13 | m_gatearray->get_prefix(AMA | AB0 | AB1 | AB2) | m_pfm_prefix;
+ if (m_pfm_oe)
+ {
+ value = m_pfm512a->read(pfmaddress);
+ LOGMASKED(LOG_PFM, "PFM %05x -> %02x\n", pfmaddress, value);
+ }
+ else LOGMASKED(LOG_PFM, "PFM %05x disabled\n", pfmaddress);
+ break;
+ default:
+ LOGMASKED(LOG_WARN, "Illegal mode for reading boot ROM: %d\n", m_boot_rom);
+ }
+}
+
+WRITE8_MEMBER( geneve_state::write_pfm )
+{
+ // Nota bene: The PFM must be write protected on startup, or the RESET
+ // of the 9995 will attempt to write the return vector into the flash EEPROM
+ offs_t addr13 = offset & 0x1fff;
+ int pfmaddress = addr13 | m_gatearray->get_prefix(AMA | AB0 | AB1 | AB2) | m_pfm_prefix;
+
+ LOGMASKED(LOG_PFM, "Writing to PFM at address %05x <- %02x\n", pfmaddress, data);
+
+ switch (m_boot_rom)
+ {
+ case GENEVE_PFM512:
+ m_pfm512->write(pfmaddress, data);
+ break;
+ case GENEVE_PFM512A:
+ m_pfm512a->write(pfmaddress, data);
+ break;
+ default:
+ LOGMASKED(LOG_WARN, "Illegal mode for writing to PFM: %d\n", m_boot_rom);
+ }
+}
+
+/****************************************************************************
+ CRU handling
+*****************************************************************************/
+
+// TODO: change peribox::cruwrite to make this obsolete
+
+void geneve_state::cruwrite(offs_t offset, uint8_t data)
+{
+ m_peribox->cruwrite(offset << 1, data);
+}
+
+uint8_t geneve_state::cruread(offs_t offset)
+{
+ uint8_t value = 0;
// Propagate the CRU access to external devices
- m_peribox->crureadz(addroff, &value);
+ m_peribox->crureadz(offset << 1, &value);
return value;
}
@@ -532,7 +874,7 @@ WRITE_LINE_MEMBER( geneve_state::left_mouse_button )
*/
WRITE_LINE_MEMBER( geneve_state::peripheral_bus_reset )
{
- LOGMASKED(LOG_WARN, "Peripheral bus reset request; not implemented yet.\n");
+ m_peribox->reset_in(state);
}
/*
@@ -540,7 +882,7 @@ WRITE_LINE_MEMBER( geneve_state::peripheral_bus_reset )
*/
WRITE_LINE_MEMBER( geneve_state::VDP_reset )
{
- LOGMASKED(LOG_WARN, "Video reset request; not implemented yet.\n");
+ m_video->reset_line(state);
}
/*
@@ -551,32 +893,14 @@ WRITE_LINE_MEMBER( geneve_state::joystick_select )
m_joyport->write_port((state==ASSERT_LINE)? 1:2);
}
-
-/*
- Write external mem cycles (0=long, 1=short)
-*/
-WRITE_LINE_MEMBER( geneve_state::extbus_wait_states )
-{
- LOGMASKED(LOG_WARN, "External bus wait states set to %d, not implemented yet.\n", state);
-}
-
/*
- Write vdp wait cycles (1=add 14 cycles, 0=add none)
- see above for waitstate handling
-*/
-WRITE_LINE_MEMBER( geneve_state::video_wait_states )
-{
- LOGMASKED(LOG_LINES, "Video wait states set to %d\n", state);
- m_gatearray->set_video_waitstates(state==ASSERT_LINE);
- m_video_wait = (state!=0)? ASSERT_LINE : CLEAR_LINE;
-}
-
-/*
- Keyboard reset (active low).
+ Keyboard reset (active low). Most keyboards do not use a dedicated reset
+ line but trigger a reset when the clock line is held low for some time.
*/
WRITE_LINE_MEMBER( geneve_state::keyboard_reset )
{
- LOGMASKED(LOG_CRUKEY, "Keyboard reset %d\n", state);
+ if (state==CLEAR_LINE)
+ LOGMASKED(LOG_GENERAL, "Keyboard reset (line not connected)\n");
}
/*
@@ -614,24 +938,10 @@ WRITE_LINE_MEMBER( geneve_state::intb )
m_tms9901->set_int_line(12, state);
}
-WRITE_LINE_MEMBER( geneve_state::ext_ready )
-{
- LOGMASKED(LOG_READY, "READY level (ext) = %02x\n", state);
- m_ready_line = state;
- m_cpu->ready_line((m_ready_line == ASSERT_LINE && m_ready_line1 == ASSERT_LINE)? ASSERT_LINE : CLEAR_LINE);
-}
-
-WRITE_LINE_MEMBER( geneve_state::mapper_ready )
-{
- LOGMASKED(LOG_READY, "READY level (mapper) = %02x\n", state);
- m_ready_line1 = state;
- m_cpu->ready_line((m_ready_line == ASSERT_LINE && m_ready_line1 == ASSERT_LINE)? ASSERT_LINE : CLEAR_LINE);
-}
-
/*
set the state of int2 (called by the v9938 core)
*/
-WRITE_LINE_MEMBER(geneve_state::set_tms9901_INT2_from_v9938)
+WRITE_LINE_MEMBER(geneve_state::int2_from_v9938)
{
// This method is frequently called without level change, so we only
// react on changes
@@ -651,6 +961,26 @@ WRITE_LINE_MEMBER( geneve_state::keyboard_interrupt )
m_tms9901->set_int_line(8, state);
}
+/*
+ READY from the box is connected to the Gate Array and the Genmod board.
+*/
+WRITE_LINE_MEMBER( geneve_state::extready )
+{
+ m_gatearray->extready_in(state);
+ if (m_genmod)
+ m_genmod_decoder->extready_in(state);
+}
+
+/*
+ READY from the sound chip is connected to the Gate Array and the Genmod board.
+*/
+WRITE_LINE_MEMBER( geneve_state::sndready )
+{
+ m_gatearray->sndready_in(state);
+ if (m_genmod)
+ m_genmod_decoder->sndready_in(state);
+}
+
void geneve_state::external_operation(offs_t offset, uint8_t data)
{
static char const *const extop[8] = { "inv1", "inv2", "IDLE", "RSET", "inv3", "CKON", "CKOF", "LREX" };
@@ -665,10 +995,45 @@ WRITE_LINE_MEMBER( geneve_state::clock_out )
{
m_tms9901->phi_line(state);
m_gatearray->clock_in(state);
+
+
+ if (state==ASSERT_LINE)
+ {
+ // Video also has a GA waitstate, in addition to the video wait states
+ // obviously, when comparing to the real machine
+
+ int readyin = m_gatearray->gaready_out();
+ if (m_genmod)
+ {
+ m_genmod_decoder->gaready_in(readyin);
+ readyin = m_genmod_decoder->gaready_out();
+ }
+ m_pal->gaready_in(readyin);
+ }
+ else
+ {
+ // Stop the pulse after one cycle for video write. Video read
+ // will be reset by the next access.
+ if (m_gatearray->csw_out()==ASSERT_LINE)
+ {
+ m_pal->csw_in(CLEAR_LINE);
+ } // see pal_device::set_ready
+
+ // The pulse must be active so that the READY line is asserted after
+ // the ext waitstate
+ }
+
+ m_pal->clock_in(state);
}
void geneve_state::init_geneve()
{
+ m_genmod = false;
+}
+
+void geneve_state::init_genmod()
+{
+ m_genmod = true;
}
void geneve_state::machine_start()
@@ -677,10 +1042,9 @@ void geneve_state::machine_start()
save_item(NAME(m_intb));
save_item(NAME(m_int2));
save_item(NAME(m_keyint));
- save_item(NAME(m_video_wait)); // reflects the line to the mapper for CRU query
- save_item(NAME(m_ready_line));
- save_item(NAME(m_ready_line1));
save_item(NAME(m_left_button));
+ save_item(NAME(m_pfm_prefix));
+ save_item(NAME(m_pfm_oe));
}
/*
@@ -699,9 +1063,30 @@ void geneve_state::machine_reset()
m_cpu->hold_line(CLEAR_LINE);
m_cpu->reset_line(ASSERT_LINE);
- m_ready_line = m_ready_line1 = ASSERT_LINE;
-
m_joyport->write_port(0x01); // select Joystick 1
+
+ // Configuring the VRAM size
+ uint32_t videoram = (ioport("VRAM")->read()!=0)? 0x30000 : 0x20000;
+ m_video->set_vram_size(videoram);
+ LOGMASKED(LOG_SETTING, "Video RAM set to %d KiB\n", videoram / 1024);
+
+ // Check which boot EPROM we are using (or PFM)
+ m_eprom = memregion("maincpu")->base();
+ m_boot_rom = ioport("BOOTROM")->read();
+
+ if (m_genmod)
+ {
+ m_sram_exp = false;
+ m_genmod_decoder->set_turbo((ioport("GENMODDIPS")->read() & GENEVE_GM_TURBO)!=0);
+ m_genmod_decoder->set_timode((ioport("GENMODDIPS")->read() & GENEVE_GM_TIM)!=0);
+ }
+ else
+ {
+ // SRAM expansion
+ // Only separately handled for the standard Geneve; Genmod uses
+ // the Memex instead
+ m_sram_exp = (ioport("SRAM")->read()!=0);
+ }
}
void geneve_state::geneve(machine_config &config)
@@ -710,30 +1095,29 @@ void geneve_state::geneve(machine_config &config)
// Gate array
GENEVE_GATE_ARRAY(config, m_gatearray, 0);
- m_gatearray->ready_cb().set(FUNC(geneve_state::mapper_ready));
m_gatearray->kbdint_cb().set(FUNC(geneve_state::keyboard_interrupt));
// Peripheral expansion box (Geneve composition)
TI99_PERIBOX_GEN(config, m_peribox, 0);
m_peribox->inta_cb().set(FUNC(geneve_state::inta));
m_peribox->intb_cb().set(FUNC(geneve_state::intb));
- m_peribox->ready_cb().set(FUNC(geneve_state::ext_ready));
+ m_peribox->ready_cb().set(FUNC(geneve_state::extready));
}
void geneve_state::genmod(machine_config &config)
{
geneve_common(config);
+ GENMOD_DECODER(config, m_genmod_decoder, 0);
- // Mapper
- GENMOD_GATE_ARRAY(config, m_gatearray, 0);
- m_gatearray->ready_cb().set(FUNC(geneve_state::mapper_ready));
+ // Gate Array
+ GENEVE_GATE_ARRAY(config, m_gatearray, 0);
m_gatearray->kbdint_cb().set(FUNC(geneve_state::keyboard_interrupt));
// Peripheral expansion box (Geneve composition with Genmod and plugged-in Memex)
TI99_PERIBOX_GENMOD(config, m_peribox, 0);
m_peribox->inta_cb().set(FUNC(geneve_state::inta));
m_peribox->intb_cb().set(FUNC(geneve_state::intb));
- m_peribox->ready_cb().set(FUNC(geneve_state::ext_ready));
+ m_peribox->ready_cb().set(FUNC(geneve_state::extready));
}
void geneve_state::geneve_common(machine_config &config)
@@ -750,7 +1134,7 @@ void geneve_state::geneve_common(machine_config &config)
// Video hardware
v99x8_device& video(V9938(config, TI_VDP_TAG, XTAL(21'477'272))); // typical 9938 clock, not verified
video.set_vram_size(0x20000);
- video.int_cb().set(FUNC(geneve_state::set_tms9901_INT2_from_v9938));
+ video.int_cb().set(FUNC(geneve_state::int2_from_v9938));
video.set_screen(TI_SCREEN_TAG);
screen_device& screen(SCREEN(config, TI_SCREEN_TAG, SCREEN_TYPE_RASTER));
screen.set_raw(XTAL(21'477'272), \
@@ -768,22 +1152,28 @@ void geneve_state::geneve_common(machine_config &config)
m_tms9901->p_out_cb(0).set(FUNC(geneve_state::peripheral_bus_reset));
m_tms9901->p_out_cb(1).set(FUNC(geneve_state::VDP_reset));
m_tms9901->p_out_cb(2).set(FUNC(geneve_state::joystick_select));
- m_tms9901->p_out_cb(4).set(GENEVE_GATE_ARRAY_TAG, FUNC(bus::ti99::internal::geneve_gate_array_device::pfm_select_lsb));
- m_tms9901->p_out_cb(5).set(GENEVE_GATE_ARRAY_TAG, FUNC(bus::ti99::internal::geneve_gate_array_device::pfm_output_enable));
m_tms9901->p_out_cb(6).set(FUNC(geneve_state::keyboard_reset));
- m_tms9901->p_out_cb(7).set(FUNC(geneve_state::extbus_wait_states));
- m_tms9901->p_out_cb(9).set(FUNC(geneve_state::video_wait_states));
- m_tms9901->p_out_cb(13).set(GENEVE_GATE_ARRAY_TAG, FUNC(bus::ti99::internal::geneve_gate_array_device::pfm_select_msb));
+ m_tms9901->p_out_cb(7).set(GENEVE_PAL_TAG, FUNC(bus::ti99::internal::geneve_pal_device::sysspeed));
+ m_tms9901->p_out_cb(9).set(GENEVE_PAL_TAG, FUNC(bus::ti99::internal::geneve_pal_device::vwaiten));
m_tms9901->intreq_cb().set(FUNC(geneve_state::tms9901_interrupt));
+ // PFM expansion: Select the 2^17 and 2^18 bit and the output enable
+ m_tms9901->p_out_cb(4).set(FUNC(geneve_state::pfm_a17));
+ m_tms9901->p_out_cb(5).set(FUNC(geneve_state::pfm_oe));
+ m_tms9901->p_out_cb(13).set(FUNC(geneve_state::pfm_a18));
+
// Clock
MM58274C(config, GENEVE_CLOCK_TAG, 0).set_mode_and_day(1, 0); // 24h, sunday
+ // PAL
+ GENEVE_PAL(config, m_pal, 0);
+ m_pal->ready_cb().set("maincpu", FUNC(tms9995_device::ready_line));
+
// Sound hardware
SPEAKER(config, "sound_out").front_center();
- sn76496_device& soundgen(SN76496(config, TI_SOUNDCHIP_TAG, 3579545));
- soundgen.ready_cb().set(FUNC(geneve_state::ext_ready));
- soundgen.add_route(ALL_OUTPUTS, "sound_out", 0.75);
+ SN76496(config, m_sound, XTAL(21'477'272)/6); // Delivered by the CLKOUT of the V9938
+ m_sound->add_route(ALL_OUTPUTS, "sound_out", 0.75);
+ m_sound->ready_cb().set(FUNC(geneve_state::sndready));
// User interface devices: PC-style keyboard, joystick port, mouse connector
PC_KBDC(config, m_kbdconn, 0);
@@ -802,8 +1192,9 @@ void geneve_state::geneve_common(machine_config &config)
// DRAM 512K
RAM(config, GENEVE_DRAM_TAG).set_default_size("512K").set_default_value(0);
- // SRAM 384K (max; stock Geneve: 32K, but later MDOS releases require 64K)
- RAM(config, GENEVE_SRAM_TAG).set_default_size("384K").set_default_value(0);
+ // SRAM
+ RAM(config, GENEVE_SRAM_TAG).set_default_size("32K").set_default_value(0);
+ RAM(config, GENEVE_SRAMX_TAG).set_default_size("32K").set_default_value(0);
}
/*
@@ -828,4 +1219,4 @@ ROM_END
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
COMP( 1987, geneve, 0, 0, geneve, geneve, geneve_state, init_geneve, "Myarc", "Geneve 9640", MACHINE_SUPPORTS_SAVE)
-COMP( 1990, genmod, 0, 0, genmod, genmod, geneve_state, init_geneve, "Myarc / Ron G. Walters", "Geneve 9640 Mod", MACHINE_SUPPORTS_SAVE)
+COMP( 1990, genmod, 0, 0, genmod, genmod, geneve_state, init_genmod, "Myarc / Ron G. Walters", "Geneve 9640 Mod", MACHINE_SUPPORTS_SAVE)
diff --git a/src/mame/drivers/ti99_4p.cpp b/src/mame/drivers/ti99_4p.cpp
index 215916f68e6..93fd96eac7e 100644
--- a/src/mame/drivers/ti99_4p.cpp
+++ b/src/mame/drivers/ti99_4p.cpp
@@ -1014,6 +1014,8 @@ void ti99_4p_state::driver_reset()
m_cpu->set_ready(ASSERT_LINE);
m_cpu->set_hold(CLEAR_LINE);
m_int1 = m_int2 = CLEAR_LINE;
+ m_peribox->reset_in(ASSERT_LINE);
+ m_peribox->reset_in(CLEAR_LINE);
}
/*
diff --git a/src/mame/drivers/ti99_4x.cpp b/src/mame/drivers/ti99_4x.cpp
index 4b1c17dc4ea..a662ceae7ec 100644
--- a/src/mame/drivers/ti99_4x.cpp
+++ b/src/mame/drivers/ti99_4x.cpp
@@ -578,67 +578,6 @@ READ8_MEMBER( ti99_4x_state::psi_input_4a )
return 1;
}
}
-/* switch (offset & 0x03)
- {
- case tms9901_device::CB_INT7:
- //
- // Read pins INT3*-INT7* of TI99's 9901.
- // bit 1: INT1 status
- // bit 2: INT2 status
- // bit 3-7: keyboard status bits 0 to 4
- //
- // |K|K|K|K|K|I2|I1|C|
- //
- if (m_keyboard_column >= (m_model==MODEL_4? 5:6)) // joy 1, 2, handset
- {
- answer = m_joyport->read_port();
-
- if ((m_model!=MODEL_4) && (m_alphabug->read()!=0) ) answer |= (m_alpha->read() | m_alpha1->read());
- }
- else
- {
- answer = m_keyboard[m_keyboard_column]->read();
- }
- if (m_check_alphalock) // never true for TI-99/4
- {
- answer &= ~(m_alpha->read() | m_alpha1->read());
- }
- answer = (answer << 3);
- if (m_int1 == CLEAR_LINE) answer |= 0x02;
- if (m_int2 == CLEAR_LINE) answer |= 0x04;
-
- break;
-
- case tms9901_device::INT8_INT15:
- // |1|1|1|INT12|0|K|K|K|
- if (m_keyboard_column >= (m_model==MODEL_4? 5:6)) answer = 0x07;
- else answer = ((m_keyboard[m_keyboard_column]->read())>>5) & 0x07;
- answer |= 0xe0;
- if (m_model != MODEL_4 || m_int12==CLEAR_LINE) answer |= 0x10;
- break;
-
- case tms9901_device::P0_P7:
- // Required for the handset (only on TI-99/4)
- if ((m_joyport->read_port() & 0x20)!=0) answer |= 2;
- break;
-
- case tms9901_device::P8_P15:
- // Preset to 1
- answer = 4;
-
- // Interrupt pin of the handset (only on TI-99/4)
- // Negative logic (interrupt pulls line down)
- if ((m_joyport->read_port() & 0x40)==0) answer = 0;
-
- // we don't take CS2 into account, as CS2 is a write-only unit
- if (m_cassette1->input() > 0)
- {
- answer |= 8;
- }
- break;
- }
- */
-
/*
Handler for TMS9901 P0 pin (handset data acknowledge); only for 99/4
@@ -885,6 +824,7 @@ WRITE_LINE_MEMBER( ti99_4x_state::console_reset )
LOGMASKED(LOG_RESETLOAD, "Console reset line = %d\n", state);
m_cpu->set_input_line(INT_9900_RESET, state);
m_video->reset_line(state);
+ m_ioport->reset_in(state);
}
}
diff --git a/src/mame/drivers/ti99_8.cpp b/src/mame/drivers/ti99_8.cpp
index 99aa0804886..44876108c35 100644
--- a/src/mame/drivers/ti99_8.cpp
+++ b/src/mame/drivers/ti99_8.cpp
@@ -609,6 +609,9 @@ WRITE_LINE_MEMBER( ti99_8_state::console_reset )
// Setting ready to false so that automatic wait states are enabled
m_cpu->ready_line(CLEAR_LINE);
m_cpu->reset_line(ASSERT_LINE);
+
+ // Send RESET to the IOPort
+ m_ioport->reset_in(state);
}
}