From 02e37f561f38f4c1b30f52e9f8c6b4a249328356 Mon Sep 17 00:00:00 2001 From: Michael Zapf Date: Sun, 10 Jun 2018 18:14:05 +0200 Subject: geneve: Using bios selection; split genmod as a separate driver --- src/devices/bus/ti99/internal/genboard.cpp | 1038 +++++++++------------------- src/devices/bus/ti99/internal/genboard.h | 145 +++- src/devices/bus/ti99/peb/peribox.cpp | 51 +- src/devices/bus/ti99/peb/peribox.h | 21 +- src/mame/drivers/geneve.cpp | 178 ++--- src/mame/mame.lst | 3 +- 6 files changed, 598 insertions(+), 838 deletions(-) diff --git a/src/devices/bus/ti99/internal/genboard.cpp b/src/devices/bus/ti99/internal/genboard.cpp index 4d8b5935b26..a9ed0e9e1bb 100644 --- a/src/devices/bus/ti99/internal/genboard.cpp +++ b/src/devices/bus/ti99/internal/genboard.cpp @@ -81,7 +81,7 @@ 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 obviously required + - TI mode: Selects between the on-board memory, which is required for the GPL interpreter, and the external Memex memory. This switch triggers a reset when changed. @@ -92,27 +92,41 @@ Logical address space: 64 KiB - Geneve mode: + Geneve mode + ----------- + Video: F100 (port 0, rw), + F102 (port 1, rw), + F104 (port 2, w), + F106 (port 3, w) + 1111 0001 0000 .xx0 + Mapper: F110 - F117 1111 0001 0001 0xxx + Keyboard: F118 1111 0001 0001 1... + Clock: F130 - F13F 1111 0001 0011 xxxx + Sound: F120 1111 0001 0010 ...0 - Video: F100, F102, F104, F106 (mirror: +8) - Mapper: F110 - F117 - Keyboard: F118 - Clock: F130 - F13F - Sound: F120 - - TI mode: - - Video: 8800, 8802, 8804, 8806 - Mapper: 8000 - 8007 - Keyboard: 8008 - 800F - Clock: 8010 - 801F - Speech: 9000 / 9400 - Grom: 9800 / 9802 - - Physical address space: 2 MiB - - Start End Banks + TI mode + ------- + Video: 8800 (port 0, r), 8c00 (port 0, w), + 8802 (port 1, r), 8c02 (port 0, w), + 8c04 (port 2, w), + 8c06 (port 3, w) + + 1000 1w.. .... .xx0 + Mapper: 8000 - 8007 1000 0000 0000 0xxx + Keyboard: 8008 - 800F 1000 0000 0000 1... + Clock: 8010 - 801F 1000 0000 0001 xxxx + Speech: 9000 / 9400 1001 0w.. .... ...0 + Grom: 9800 / 9802 1001 1w.. .... ..x0 + 9c00 / 9c02 + + Physical address space + ---------------------- + Address space size = 2 MiB + + Start End Phys.pages 000000 - 07FFFF 00-3F 512 KiB DRAM on-board + 06C000 - 06DFFF 36 Cartridge space first 8K + 06E000 - 06FFFF 37 Cartridge space second 8K 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) @@ -120,10 +134,12 @@ 1E0000 - 1FFFFF F0-FF 128 KiB EPROM space; 16 KiB actually used, 8 mirrors - GenMod modification: - + GenMod modification + ------------------- TI mode 000000 - 07FFFF 00-3F 512 KiB DRAM on-board + 06C000 - 06DFFF 36 Cartridge space first 8K + 06E000 - 06FFFF 37 Cartridge space second 8K 080000 - 1DFFFF 40-EF 1408 KiB P-Box space 1E0000 - 1FFFFF F0-FF 128 KiB EPROM space; 16 KiB actually used, 8 mirrors @@ -147,16 +163,15 @@ - accesses to the peripheral expansion box: 1 WS - accesses to on-board DRAM: 1 WS - accesses to video: 15 WS - - accesses to sound: ~25 WS - accesses to SRAM: 0 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 theory is that the READY line is - pulled down until the next clock pulse, which may take some value between - 18 CPU cycles and 30 CPU cycles. + 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. @@ -165,7 +180,8 @@ 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 + Almost perfect. Only video read access from code in DRAM is too fast + by one WS ========================== PFM expansion @@ -204,20 +220,22 @@ #define LOG_SETTING (1U<<8) #define LOG_VIDEOWS (1U<<9) #define LOG_PFM (1U<<10) +#define LOG_DECODE (1U<<11) // Minimum log should be settings and warnings -#define VERBOSE (LOG_GENERAL | LOG_SETTING | LOG_WARN) +#define VERBOSE ( LOG_SETTING | LOG_WARN ) #include "genboard.h" #include "logmacro.h" DEFINE_DEVICE_TYPE_NS(GENEVE_KEYBOARD, bus::ti99::internal, geneve_keyboard_device, "geneve_keyboard", "Geneve XT-style keyboard") DEFINE_DEVICE_TYPE_NS(GENEVE_MAPPER, bus::ti99::internal, geneve_mapper_device, "geneve_mapper", "Geneve Gate Array") +DEFINE_DEVICE_TYPE_NS(GENMOD_MAPPER, bus::ti99::internal, genmod_mapper_device, "genmod_mapper", "Geneve Mod Gate Array") namespace bus { namespace ti99 { namespace internal { -geneve_mapper_device::geneve_mapper_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, GENEVE_MAPPER, tag, owner, clock), m_gromwaddr_LSB(false), +geneve_mapper_device::geneve_mapper_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_gromwaddr_LSB(false), m_gromraddr_LSB(false), m_grom_address(0), m_video_waitstates(false), @@ -231,17 +249,14 @@ geneve_mapper_device::geneve_mapper_device(const machine_config &mconfig, const m_cartridge_secondpage(false), m_cartridge6_writable(false), m_cartridge7_writable(false), - m_turbo(false), - m_genmod(false), - m_timode(false), - m_pfm_mode(0), + m_boot_rom(0), m_pfm_bank(0), m_pfm_output_enable(false), m_sram_mask(0), m_sram_val(0), m_ready(*this), m_waitcount(0), - m_ext_waitcount(0), + m_video_waitcount(0), m_clock(*owner, GENEVE_CLOCK_TAG), m_cpu(*owner, "maincpu"), m_pfm512(*owner, GENEVE_PFM512_TAG), @@ -252,11 +267,32 @@ geneve_mapper_device::geneve_mapper_device(const machine_config &mconfig, const m_peribox(*owner, TI_PERIBOX_TAG), m_sram(*this, GENEVE_SRAM_PAR_TAG), m_dram(*this, GENEVE_DRAM_PAR_TAG) +{ +} + +geneve_mapper_device::geneve_mapper_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : geneve_mapper_device(mconfig, GENEVE_MAPPER, tag, owner, clock) { m_eprom = nullptr; + m_pbox_prefix = 0x070000; +} + +genmod_mapper_device::genmod_mapper_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : geneve_mapper_device(mconfig, GENMOD_MAPPER, tag, owner, clock), + m_gm_timode(false), + m_turbo(false) +{ + m_eprom = nullptr; + m_pbox_prefix = 0x170000; } INPUT_CHANGED_MEMBER( geneve_mapper_device::settings_changed ) +{ + // Used when switching the boot ROMs during runtime, especially the PFM + m_boot_rom = newval; +} + +INPUT_CHANGED_MEMBER( genmod_mapper_device::setgm_changed ) { int number = (int)((uint64_t)param&0x03); int value = newval; @@ -271,12 +307,12 @@ INPUT_CHANGED_MEMBER( geneve_mapper_device::settings_changed ) case 2: // TIMode switch. Causes reset when changed. LOGMASKED(LOG_SETTING, "Setting timode flag to %d\n", value); - m_timode = (value!=0); + m_gm_timode = (value!=0); machine().schedule_hard_reset(); break; case 3: // Used when switching the boot ROMs during runtime, especially the PFM - set_boot_rom(value); + m_boot_rom = value; break; default: LOGMASKED(LOG_WARN, "Unknown setting %d ignored\n", number); @@ -316,8 +352,8 @@ READ8_MEMBER( geneve_mapper_device::read_grom ) { // GROM data handling // GROMs are stored in pages 38..3f - int page = 0x38; - reply = m_dram->pointer()[(page<<13) + m_grom_address]; + 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; } @@ -349,8 +385,8 @@ WRITE8_MEMBER( geneve_mapper_device::write_grom ) else { // write GPL data // The Geneve GROM simulator allows for GROM writing (verified with a real system) - int page = 0x38; - m_dram->pointer()[(page<<13) + m_grom_address] = data; + 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; @@ -359,12 +395,11 @@ WRITE8_MEMBER( geneve_mapper_device::write_grom ) void geneve_mapper_device::set_wait(int min) { - if (m_debug_no_ws) return; 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_ext_waitcount > min) return; + if (m_video_waitcount > min) return; // need one more pass so that READY will be asserted again m_waitcount = min + 1; @@ -376,37 +411,10 @@ void geneve_mapper_device::set_wait(int min) } } -void geneve_mapper_device::set_ext_wait(int min) +void geneve_mapper_device::set_video_waitcount(int min) { if (m_debug_no_ws) return; - m_ext_waitcount = min; -} - -void geneve_mapper_device::set_boot_rom(int selection) -{ - switch (selection) - { - case GENEVE_098: - LOGMASKED(LOG_SETTING, "Using 0.98 boot eprom\n"); - m_eprom = machine().root_device().memregion("maincpu")->base() + 0x4000; - m_pfm_mode = 0; - break; - case GENEVE_100: - LOGMASKED(LOG_SETTING, "Using 1.00 boot eprom\n"); - m_eprom = machine().root_device().memregion("maincpu")->base(); - m_pfm_mode = 0; - break; - case GENEVE_PFM512: - LOGMASKED(LOG_SETTING, "Using PFM512 (AT29C040)\n"); - m_pfm_mode = 1; - break; - case GENEVE_PFM512A: - LOGMASKED(LOG_SETTING, "Using PFM512A (AT29C040A)\n"); - m_pfm_mode = 2; - break; - default: - LOGMASKED(LOG_WARN, "Unknown boot ROM selection\n"); - } + m_video_waitcount = min; } void geneve_mapper_device::set_geneve_mode(bool geneve) @@ -454,35 +462,6 @@ void geneve_mapper_device::set_extra_waitstates(bool wait) /************************************************************************ Called by the address map ************************************************************************/ -/* - Constants for mapper decoding. Naming scheme: - M=mapper - L=Logical space; P=Physical space - G=Geneve mode; T=TI mode; GM=GenMod -*/ -enum -{ - MLGVIDEO=1, - MLGMAPPER, - MLGKEY, - MLGCLOCK, - MLGSOUND, - MLTMAPPER, - MLTKEY, - MLTCLOCK, - MLTVIDEO, - MLTSPEECH, - MLTGROM, - MLTSOUND, - MPGDRAM, - MPGEXP, - MPGEPROM, - MPGSRAM, - MPGBOX, - MPGMDRAM, - MPGMEPROM, - MPGMBOX -}; /* Read a byte via the data bus. The decoding has already been done in the @@ -502,7 +481,19 @@ READ8_MEMBER( geneve_mapper_device::readm ) if (m_cpu->is_onchip(offset)) return m_cpu->debug_read_onchip_memory(offset&0xff); dec = &debug; m_debug_no_ws = true; - decode(space, offset, true, dec); + 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(space, dec->physaddr, true); + } } else { @@ -511,89 +502,49 @@ READ8_MEMBER( geneve_mapper_device::readm ) m_debug_no_ws = false; } + // Logical space + switch (dec->function) { - case MLGVIDEO: + case MLVIDEO: if (!machine().side_effects_disabled()) { value = m_video->read(space, 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_ext_wait(15); + if (m_video_waitstates) set_video_waitcount(15); } break; - case MLGMAPPER: + case MLMAPPER: // mapper - value = m_map[dec->offset]; - LOGMASKED(LOG_READ, "read mapper %04x -> %02x\n", dec->offset, value); - break; - - case MLGKEY: - // key - if (!machine().side_effects_disabled()) value = m_keyboard->get_recent_key(); - LOGMASKED(LOG_READ, "Read keyboard -> %02x\n", value); - break; - - case MLGCLOCK: - // clock - // tests on the real machine showed that - // upper nibble is 0xf (probably because of the location at 0xf130?) - value = m_clock->read(space, dec->offset) | 0xf0; - LOGMASKED(LOG_READ, "Read clock %04x -> %02x\n", dec->offset, value); - break; - - case MLTMAPPER: - // mapper - value = m_map[dec->offset]; + value = m_map[dec->offset & 0x0007]; LOGMASKED(LOG_READ, "Read mapper %04x -> %02x\n", dec->offset, value); break; - case MLTKEY: + case MLKEY: // key if (!machine().side_effects_disabled()) value = m_keyboard->get_recent_key(); LOGMASKED(LOG_READ, "Read keyboard -> %02x\n", value); break; - case MLTCLOCK: + case MLCLOCK: // clock - // upper nibble is 1, only last byte gets a 2 - // probably because of the location at 8010...8020? - // (TI mode used swapped byte order) - // unless we use a workspace at >F000, in which case we get 8x values - // Obscure, needs more investigation. We might as well ignore this, + // 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_clock->read(space, dec->offset); - value |= (dec->offset==0x000f)? 0x20 : 0x10; + value = m_clock->read(space, 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 MLTVIDEO: - // video - // ++++ ++-- ---- ---+ - // 1000 1000 0000 00x0 - if (!machine().side_effects_disabled()) - { - value = m_video->read(space, dec->offset>>1); - LOGMASKED(LOG_READ, "Read video %04x -> %02x\n", dec->offset, value); - // See above - if (m_video_waitstates) set_ext_wait(15); - } - break; - - case MLTSPEECH: - // speech - // ++++ ++-- ---- ---+ - // 1001 0000 0000 0000 - // We need to add the address prefix bits - m_peribox->readz(space, dec->offset, &value, 0xff); - m_peribox->memen_in(CLEAR_LINE); - LOGMASKED(LOG_READ, "Read speech -> %02x\n", value); - break; - - case MLTGROM: + case MLGROM: // grom simulation // ++++ ++-- ---- ---+ // 1001 1000 0000 00x0 @@ -601,49 +552,43 @@ READ8_MEMBER( geneve_mapper_device::readm ) LOGMASKED(LOG_READ, "Read GROM %04x -> %02x\n", dec->offset, value); break; - case MLGSOUND: - case MLTSOUND: + case MLSOUND: value = 0; break; - - case MPGDRAM: - // DRAM. + case MPDRAM: + // DRAM. One wait state. value = m_dram->pointer()[dec->physaddr]; -// LOG("dram read physaddr = %06x logaddr = %04x value = %02x\n", dec->physaddr, dec->offset, value); LOGMASKED(LOG_READ, "Read DRAM %04x (%06x) -> %02x\n", dec->offset, dec->physaddr, value); break; - case MPGEXP: + case MPEXP: // On-board memory expansion for standard Geneve (never used) - LOGMASKED(LOG_READ, "Read unmapped area %06x\n", dec->physaddr); + LOGMASKED(LOG_READ, "Read on-board expansion (not available) %06x -> 00\n", dec->physaddr); value = 0; break; - case MPGEPROM: + case MPEPROM: // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) // mirrored for f0, f2, f4, ...; f1, f3, f5, ... - if (m_pfm_mode == 0) - { - value = m_eprom[dec->physaddr & 0x003fff]; - LOGMASKED(LOG_READ, "Read EPROM %04x (%06x) -> %02x\n", dec->offset, dec->physaddr, value); - } - else value = read_from_pfm(space, dec->physaddr, 0xff); - + value = boot_rom(space, dec->physaddr, 0xff); break; - case MPGSRAM: + 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_WARN, "Decoded as SRAM read, but no SRAM at %06x\n", dec->physaddr); + value = 0; } - else value = 0; // Return in any case -// LOG("sram read physaddr = %06x logaddr = %04x value = %02x\n", dec->physaddr, dec->offset, value); - LOGMASKED(LOG_READ, "Read SRAM %04x (%06x) -> %02x\n", dec->offset, dec->physaddr, value); break; - case MPGBOX: + 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) @@ -653,26 +598,8 @@ READ8_MEMBER( geneve_mapper_device::readm ) LOGMASKED(LOG_READ, "Read P-Box %04x (%06x) -> %02x\n", dec->offset, dec->physaddr, value); break; - case MPGMDRAM: - // DRAM. One wait state. - value = m_dram->pointer()[dec->physaddr]; - break; - - case MPGMEPROM: - // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) - // mirrored for f0, f2, f4, ...; f1, f3, f5, ... - if (m_pfm_mode == 0) - { - value = m_eprom[dec->physaddr & 0x003fff]; - LOGMASKED(LOG_READ, "Read EPROM %04x (%06x) -> %02x\n", dec->offset, dec->physaddr, value); - } - else value = read_from_pfm(space, dec->physaddr, 0xff); - break; - - case MPGMBOX: - // Route everything else to the P-Box - m_peribox->readz(space, dec->physaddr, &value, 0xff); - m_peribox->memen_in(CLEAR_LINE); + default: + LOGMASKED(LOG_WARN, "Unknown decoding result type: %d\n", dec->function); break; } return value; @@ -686,598 +613,271 @@ WRITE8_MEMBER( geneve_mapper_device::writem ) // 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; - decode(space, offset, false, dec); + 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(space, dec->physaddr, false); + } } else { // Use the values found in the setaddress phase - m_debug_no_ws = false; dec = &m_decoded; + m_debug_no_ws = false; } + + // Logical space + switch (dec->function) { - case MLGVIDEO: + case MLVIDEO: // video // ++++ ++++ ++++ ---+ // 1111 0001 0000 .cc0 + // Initialize waitstate timer if (!machine().side_effects_disabled()) { m_video->write(space, dec->offset>>1, data); LOGMASKED(LOG_WRITE, "Write video %04x <- %02x\n", offset, data); // See above - if (m_video_waitstates) set_ext_wait(15); + if (m_video_waitstates) set_video_waitcount(15); } break; - case MLGMAPPER: + case MLMAPPER: // mapper - m_map[dec->offset] = data; + m_map[dec->offset & 0x0007] = data; LOGMASKED(LOG_WRITE, "Write mapper %04x <- %02x\n", offset, data); break; - case MLGCLOCK: + case MLCLOCK: // clock // ++++ ++++ ++++ ---- - m_clock->write(space, dec->offset, data); + m_clock->write(space, dec->offset & 0x000f, data); LOGMASKED(LOG_WRITE, "Write clock %04x <- %02x\n", offset, data); break; - case MLGSOUND: + case MLSOUND: // sound // ++++ ++++ ++++ ---+ m_sound->write(data); LOGMASKED(LOG_WRITE, "Write sound <- %02x\n", data); break; - case MLTMAPPER: - // mapper - m_map[dec->offset] = data; - LOGMASKED(LOG_WRITE, "Write mapper %04x <- %02x\n", offset, data); - break; - - case MLTCLOCK: - // clock - m_clock->write(space, dec->offset, data); - LOGMASKED(LOG_WRITE, "Write clock %04x <- %02x\n", offset, data); - break; - - case MLTVIDEO: - // video - // ++++ ++-- ---- ---+ - // 1000 1100 0000 00c0 - // Initialize waitstate timer - if (!machine().side_effects_disabled()) - { - m_video->write(space, dec->offset>>1, data); - LOGMASKED(LOG_WRITE, "Write video %04x <- %02x\n", offset, data); - // See above - if (m_video_waitstates) set_ext_wait(15); - } - break; - - case MLTSPEECH: - // speech - // ++++ ++-- ---- ---+ - // 1001 0100 0000 0000 - // We need to add the address prefix bits - m_peribox->write(space, dec->offset, data, 0xff); - m_peribox->memen_in(CLEAR_LINE); - LOGMASKED(LOG_WRITE, "Write speech <- %02x\n", data); - break; - - case MLTGROM: - // grom simulation - // ++++ ++-- ---- ---+ - // 1001 1100 0000 00c0 + case MLGROM: + // The GROM simulator is only available in TI Mode write_grom(space, dec->offset, data, 0xff); LOGMASKED(LOG_WRITE, "Write GROM %04x <- %02x\n", offset, data); break; - case MLTSOUND: - // sound - // ++++ ++-- ---- ---+ - // 1000 0100 0000 0000 - m_sound->write(data); - LOGMASKED(LOG_WRITE, "Write sound <- %02x\n", data); - break; - - case MLTKEY: - case MLGKEY: - break; - - case MPGDRAM: - // DRAM write. One wait state. (only for normal Geneve) + // 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 MPGEXP: - // On-board memory expansion for standard Geneve (never used) - LOGMASKED(LOG_WRITE, "Write unmapped area %06x\n", dec->physaddr); + 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 MPGEPROM: + 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_pfm_mode != 0) write_to_pfm(space, dec->physaddr, data, 0xff); + if (m_boot_rom != GENEVE_EPROM) write_to_pfm(space, dec->physaddr, data, 0xff); else LOGMASKED(LOG_WARN, "Write EPROM %04x (%06x) <- %02x, ignored\n", offset, dec->physaddr, data); break; - case MPGSRAM: + 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_WARN, "Decoded as SRAM write, but no SRAM at %06x\n", dec->physaddr); } - LOGMASKED(LOG_WRITE, "Write SRAM %04x (%06x) <- %02x\n", offset, dec->physaddr, data); break; - case MPGBOX: - dec->physaddr = (dec->physaddr & 0x0007ffff); // 19 bit address + 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(space, dec->physaddr, data, 0xff); m_peribox->memen_in(CLEAR_LINE); break; - case MPGMDRAM: - // DRAM. One wait state. - m_dram->pointer()[dec->physaddr] = data; - break; - - case MPGMEPROM: - // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) - // mirrored for f0, f2, f4, ...; f1, f3, f5, ... - // Ignore EPROM write - if (m_pfm_mode != 0) write_to_pfm(space, dec->physaddr, data, 0xff); - else - LOGMASKED(LOG_WARN, "Write EPROM %04x (%06x) <- %02x, ignored\n", offset, dec->physaddr, data); - break; - - case MPGMBOX: - // Route everything else to the P-Box - m_peribox->write(space, dec->physaddr, data, 0xff); - m_peribox->memen_in(CLEAR_LINE); + default: + LOGMASKED(LOG_WARN, "Unknown decoding result type: %d\n", dec->function); break; } } -void geneve_mapper_device::decode(address_space& space, offs_t offset, bool read_mode, geneve_mapper_device::decdata* dec) +void geneve_mapper_device::decode_logical(bool reading, geneve_mapper_device::decdata* dec) { - dec->function = 0; - dec->offset = offset; - dec->physaddr = 0; + dec->function = MUNDEF; + dec->physaddr = m_pbox_prefix | dec->offset; + dec->wait = 1; - int page; - - if (read_mode) // got this from DBIN + int i = 0; + while (i < 7) { - // Logical addresses if (m_geneve_mode) { - // TODO: shortcut offset & 0xffc0 = 0xf100 - if ((offset & 0xfff5)==0xf100) - { - // video - // ++++ ++++ ++++ -+-+ - // 1111 0001 0000 0000 - // 1111 0001 0000 0010 - // 1111 0001 0000 1000 - // 1111 0001 0000 1010 - - dec->function = MLGVIDEO; - set_wait(1); - return; - } - if ((offset & 0xfff8)==0xf110) - { - // mapper - dec->function = MLGMAPPER; - dec->offset = dec->offset & 0x0007; - set_wait(1); - return; - } - if ((offset & 0xfff8) == 0xf118) - { - // key - dec->function = MLGKEY; - set_wait(1); - return; - } - if ((offset & 0xfff0)==0xf130) - { - // clock - // tests on the real machine showed that - // upper nibble is 0xf (probably because of the location at 0xf130?) - dec->function = MLGCLOCK; - dec->offset = dec->offset & 0x000f; - set_wait(1); - return; - } - } - else - { - if ((offset & 0xfff8)==0x8000) - { - // mapper - dec->function = MLTMAPPER; - dec->offset = dec->offset & 0x0007; - set_wait(1); - return; - } - if ((offset & 0xfff8)== 0x8008) - { - // key - dec->function = MLTKEY; - set_wait(1); - return; - } - if ((offset & 0xfff0)==0x8010) - { - // clock - dec->function = MLTCLOCK; - dec->offset = dec->offset & 0x000f; - set_wait(1); - return; - } - if ((offset & 0xfc01)==0x8800) - { - // video - // ++++ ++-- ---- ---+ - // 1000 1000 0000 00x0 - // 1 WS is always added; any pending video waitstates are canceled - dec->function = MLTVIDEO; - set_wait(1); - return; - } - if ((offset & 0xfc01)==0x9000) - { - // speech - // ++++ ++-- ---- ---+ - // 1001 0000 0000 0000 - // We need to add the address prefix bits - dec->function = MLTSPEECH; - dec->offset = offset | ((m_genmod)? 0x170000 : 0x070000); - m_peribox->memen_in(ASSERT_LINE); - m_peribox->setaddress_dbin(space, dec->offset, read_mode); - set_wait(1); - return; - } - if ((offset & 0xfc01)==0x9800) - { - // grom simulation - // ++++ ++-- ---- ---+ - // 1001 1000 0000 00x0 - dec->function = MLTGROM; - set_wait(1); - return; - } - } - // still here? Then go via mapping. - page = (offset & 0xe000) >> 13; - - // Determine physical address - if (m_direct_mode) - { - dec->physaddr = 0x1f0000; // points to boot eprom (page F8) + // Skip when genbase is 0 + if ((m_logmap[i].genbase != 0) && ((dec->offset & ~m_logmap[i].genmask) == m_logmap[i].genbase)) + break; } else { - if (!m_geneve_mode && page==3) + if (reading) { - if (m_cartridge_size==0x4000 && m_cartridge_secondpage) dec->physaddr = 0x06e000; - else dec->physaddr = 0x06c000; + if ((dec->offset & ~m_logmap[i].timask) == m_logmap[i].tibase) + break; } else { - dec->physaddr = (m_map[page] << 13); + if ((dec->offset & ~m_logmap[i].timask) == (m_logmap[i].tibase | m_logmap[i].writeoff)) + break; } } - dec->physaddr |= (offset & 0x1fff); - - if (!m_genmod) // Standard Geneve - { - if ((dec->physaddr & 0x180000)==0x000000) - { - // DRAM. - dec->physaddr = dec->physaddr & 0x07ffff; - dec->function = MPGDRAM; - set_wait(1); - return; - } - - if ((dec->physaddr & 0x180000)==0x080000) - { - // On-board memory expansion for standard Geneve (never used) - dec->function = MPGEXP; - set_wait(1); - return; - } - - if ((dec->physaddr & 0x1e0000)==0x1e0000) - { - // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) - // mirrored for f0, f2, f4, ...; f1, f3, f5, ... unless using PFM - dec->function = MPGEPROM; - set_wait(0); - return; - } - - if ((dec->physaddr & 0x180000)==0x180000) - { - dec->function = MPGSRAM; - set_wait(0); - return; - } - - // 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) - // Add a wait state - set_wait(1); - dec->function = MPGBOX; - - dec->physaddr = (dec->physaddr & 0x0007ffff); // 19 bit address (with AMA..AMC) - m_peribox->memen_in(ASSERT_LINE); - m_peribox->setaddress_dbin(space, dec->physaddr, read_mode); - return; - } - else - { - // GenMod mode - if ((m_timode) && ((dec->physaddr & 0x180000)==0x000000)) - { - // DRAM. One wait state. - dec->function = MPGMDRAM; - dec->physaddr = dec->physaddr & 0x07ffff; - if (!m_turbo) set_wait(1); - return; - } - - if ((dec->physaddr & 0x1e0000)==0x1e0000) - { - // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) - // mirrored for f0, f2, f4, ...; f1, f3, f5, ... unless using PFM - dec->function = MPGMEPROM; - set_wait(0); - return; - } - - // Route everything else to the P-Box - dec->physaddr = (dec->physaddr & 0x001fffff); // 21 bit address for Genmod - dec->function = MPGMBOX; + i++; + } + if (i != 7) + { + LOGMASKED(LOG_DECODE, "Decoded as %s: %04x\n", m_logmap[i].description, dec->offset); + dec->function = m_logmap[i].function; + } +} - if (!m_turbo) set_wait(1); - // Check: Are waitstates completely turned off for turbo mode, or - // merely the waitstates for DRAM memory access and box access? +void geneve_mapper_device::map_address(bool reading, geneve_mapper_device::decdata* dec) +{ + int logpage = (dec->offset & 0xe000) >> 13; + int physpage = 0; - m_peribox->memen_in(ASSERT_LINE); - m_peribox->setaddress_dbin(space, dec->physaddr, read_mode); - return; - } - } + // Determine physical address + if (m_direct_mode) physpage = 0xf8; // points to boot eprom else - { // Write access - // Logical addresses - if (m_geneve_mode) - { - if ((offset & 0xfff1)==0xf100) - { - // 1 WS is always added; any pending video waitstates are canceled - dec->function = MLGVIDEO; - set_wait(1); - return; - } - if ((offset & 0xfff8)==0xf110) - { - dec->function = MLGMAPPER; - dec->offset = dec->offset & 0x0007; - set_wait(1); - return; - } - if ((offset & 0xfff1)==0xf120) - { - // Add 24 waitstates. This is an average value, as the - // waitstate generation seems to depend on an external timer of - // the sound chip - // TODO: do it properly with the use of READY - dec->function = MLGSOUND; - set_wait(24); - return; - } - if ((offset & 0xfff0)==0xf130) - { - dec->function = MLGCLOCK; - dec->offset = dec->offset & 0x00f; - set_wait(1); - return; - } - } - else + { + // TI mode, accessing logical addresses 6000-7fff + if (!m_geneve_mode && logpage==3) { - // TI mode - if ((offset & 0xfff8)==0x8000) - { - dec->function = MLTMAPPER; - dec->offset = dec->offset & 0x0007; - set_wait(1); - return; - } - if ((offset & 0xfff0)==0x8010) - { - dec->function = MLTCLOCK; - dec->offset = dec->offset & 0x00f; - set_wait(1); - return; - } - if ((offset & 0xfc01)==0x9c00) - { - dec->function = MLTGROM; - set_wait(1); - return; - } - if ((offset & 0xfc01)==0x8400) - { - // Add 24 waitstates. This is an approximation, as the - // waitstate generation seems to depend on an external timer of - // the sound chip - // TODO: do it properly with the use of READY- - dec->function = MLTSOUND; - set_wait(24); - return; - } - if ((offset & 0xfc01)==0x8c00) + if (reading) { - // 1 WS is always added; any pending video waitstates are canceled - dec->function = MLTVIDEO; - set_wait(1); - return; + physpage = (m_cartridge_size==0x4000 && m_cartridge_secondpage)? 0x37 : 0x36; } - - if ((offset & 0xfc01)==0x9400) - { - dec->function = MLTSPEECH; - dec->offset = dec->offset | ((m_genmod)? 0x170000 : 0x070000); - m_peribox->memen_in(ASSERT_LINE); - m_peribox->setaddress_dbin(space, dec->offset, read_mode); - set_wait(1); - return; - } - } - - // Determine physical address - page = (dec->offset & 0xe000) >> 13; - - if (m_direct_mode) - { - dec->physaddr = 0x1e0000; // points to boot eprom - } - else - { - if (!m_geneve_mode && page==3) + else { + // Emulate the cartridge bank switch feature of Extended Basic + // TODO: Is this the right place? Or writem()? if (m_cartridge_size==0x4000) { m_cartridge_secondpage = ((dec->offset & 0x0002)!=0); LOGMASKED(LOG_WRITE, "Set cartridge page %02x\n", m_cartridge_secondpage); - set_wait(1); - return; } else { - // writing into cartridge rom space (no bankswitching) + // 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); - return; } else // TODO: Check whether secondpage is really ignored - dec->physaddr = 0x06c000; + physpage = 0x36; } } - else - dec->physaddr = (m_map[page] << 13); - } - - dec->physaddr |= dec->offset & 0x1fff; - - if (!m_genmod) - { - if ((dec->physaddr & 0x180000)==0x000000) - { - dec->function = MPGDRAM; - dec->physaddr = dec->physaddr & 0x07ffff; - set_wait(1); - return; - } - if ((dec->physaddr & 0x180000)==0x080000) - { - dec->function = MPGEXP; - set_wait(1); - return; - } - - if ((dec->physaddr & 0x1e0000)==0x1e0000) - { - dec->function = MPGEPROM; - set_wait(0); // EPROM - return; - } - if ((dec->physaddr & 0x180000)==0x180000) - { - dec->function = MPGSRAM; - set_wait(0); // SRAM - return; - } - - // Route everything else to the P-Box - // Add a wait state - - // only AMA, AMB, AMC are used; AMD and AME are not used - dec->function = MPGBOX; - dec->physaddr = (dec->physaddr & 0x0007ffff); // 19 bit address - m_peribox->memen_in(ASSERT_LINE); - m_peribox->setaddress_dbin(space, dec->physaddr, read_mode); - set_wait(1); } else - { - // GenMod mode - if ((dec->physaddr & 0x1e0000)==0x1e0000) - { // EPROM, ignore (unless PFM) - dec->function = MPGMEPROM; - set_wait(0); - return; - } + physpage = m_map[logpage]; + } + dec->physaddr = ((physpage << 13) | (dec->offset & 0x1fff)) & 0x1fffff; +} - if (m_timode && ((dec->physaddr & 0x180000)==0x000000)) - { - dec->function = MPGMDRAM; - dec->physaddr = dec->physaddr & 0x07ffff; - if (!m_turbo) set_wait(1); - return; - } +void geneve_mapper_device::decode_physical(geneve_mapper_device::decdata* dec) +{ + dec->function = MUNDEF; - // Route everything else to the P-Box - dec->function = MPGMBOX; - dec->physaddr = (dec->physaddr & 0x001fffff); // 21 bit address for Genmod - m_peribox->memen_in(ASSERT_LINE); - m_peribox->setaddress_dbin(space, dec->physaddr, read_mode); - if (!m_turbo) set_wait(1); - } + int i = 0; + while (i < 4) + { + if ((dec->physaddr & ~m_physmap[i].mask) == m_physmap[i].base) + break; + i++; + } + if (i != 4) + { + LOGMASKED(LOG_DECODE, "Decoded as %s: %06x\n", m_physmap[i].description, dec->physaddr); + dec->function = m_physmap[i].function; + dec->wait = m_physmap[i].wait; } + else + { + // Route everything else to the P-Box + dec->function = MBOX; + dec->wait = 1; + } +} + +void genmod_mapper_device::decode_mod(geneve_mapper_device::decdata* dec) +{ + // 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) + { + dec->function = MBOX; + } + + if ((dec->function != MPDRAM) && m_turbo) + dec->wait = 0; } /* - Read from PFM. + Boot ROM handling, from EPROM or PFM. */ -READ8_MEMBER( geneve_mapper_device::read_from_pfm ) +READ8_MEMBER( geneve_mapper_device::boot_rom ) { uint8_t value; - if (!m_pfm_output_enable) return 0; + int pfmaddress = (offset & 0x01ffff) | (m_pfm_bank<<17); - int address = (offset & 0x01ffff) | (m_pfm_bank<<17); - - switch (m_pfm_mode) + switch (m_boot_rom) { - case 1: - value = m_pfm512->read(space, address, mem_mask); + 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(space, pfmaddress, mem_mask); break; - case 2: - value = m_pfm512a->read(space, address, mem_mask); + case GENEVE_PFM512A: + value = m_pfm512a->read(space, pfmaddress, mem_mask); break; default: - LOGMASKED(LOG_WARN, "Illegal mode for reading PFM: %d\n", m_pfm_mode); - return 0; + LOGMASKED(LOG_WARN, "Illegal mode for reading boot ROM: %d\n", m_boot_rom); + value = 0; } - LOGMASKED(LOG_PFM, "Reading from PFM at address %05x -> %02x\n", address, value); + if (!m_pfm_output_enable) value = 0; + LOGMASKED(LOG_PFM, "Reading from PFM at address %05x -> %02x\n", pfmaddress, value); return value; } @@ -1288,16 +888,16 @@ WRITE8_MEMBER( geneve_mapper_device::write_to_pfm ) int address = (offset & 0x01ffff) | (m_pfm_bank<<17); LOGMASKED(LOG_PFM, "Writing to PFM at address %05x <- %02x\n", address, data); - switch (m_pfm_mode) + switch (m_boot_rom) { - case 1: + case GENEVE_PFM512: m_pfm512->write(space, address, data, mem_mask); break; - case 2: + case GENEVE_PFM512A: m_pfm512a->write(space, address, data, mem_mask); break; default: - LOGMASKED(LOG_WARN, "Illegal mode for writing to PFM: %d\n", m_pfm_mode); + LOGMASKED(LOG_WARN, "Illegal mode for writing to PFM: %d\n", m_boot_rom); } } @@ -1311,7 +911,23 @@ SETOFFSET_MEMBER( geneve_mapper_device::setoffset ) { LOGMASKED(LOG_DETAIL, "setoffset = %04x\n", offset); m_debug_no_ws = false; - decode(space, offset, m_read_mode, &m_decoded); + m_decoded.offset = offset; + + 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); + } + + set_wait(m_decoded.wait); + + if (m_decoded.function == MBOX) + { + m_peribox->memen_in(ASSERT_LINE); + m_peribox->setaddress_dbin(space, m_decoded.physaddr, m_read_mode); + } } /* @@ -1349,10 +965,10 @@ WRITE_LINE_MEMBER( geneve_mapper_device::clock_in ) } else { - if (m_ext_waitcount > 0) + if (m_video_waitcount > 0) { - m_ext_waitcount--; - if (m_ext_waitcount == 0) + m_video_waitcount--; + if (m_video_waitcount == 0) { LOGMASKED(LOG_CLOCK, "clock, READY asserted after video\n"); m_ready(ASSERT_LINE); @@ -1360,7 +976,7 @@ WRITE_LINE_MEMBER( geneve_mapper_device::clock_in ) } else { - LOGMASKED(LOG_CLOCK, "vclock, ew=%d\n", m_ext_waitcount); + LOGMASKED(LOG_CLOCK, "vclock, ew=%d\n", m_video_waitcount); } } } @@ -1370,7 +986,7 @@ WRITE_LINE_MEMBER( geneve_mapper_device::clock_in ) { // Falling edge // Do we have video wait states? In that case, clear the line again - if ((m_waitcount == 0) && (m_ext_waitcount > 0) && m_ready_asserted) + if ((m_waitcount == 0) && (m_video_waitcount > 0) && m_ready_asserted) { LOGMASKED(LOG_CLOCK, "clock, READY cleared for video\n"); m_ready(CLEAR_LINE); @@ -1442,25 +1058,22 @@ void geneve_mapper_device::device_start() save_item(NAME(m_decoded.function)); save_item(NAME(m_decoded.offset)); save_item(NAME(m_decoded.physaddr)); - save_item(NAME(m_turbo)); - save_item(NAME(m_genmod)); - save_item(NAME(m_timode)); - save_item(NAME(m_pfm_mode)); + 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_ext_waitcount)); + save_item(NAME(m_video_waitcount)); } -void geneve_mapper_device::device_reset() +void geneve_mapper_device::common_reset() { m_extra_waitstates = false; m_video_waitstates = true; m_read_mode = false; m_waitcount = 0; - m_ext_waitcount = 0; + m_video_waitcount = 0; m_ready_asserted = true; m_geneve_mode =false; @@ -1476,25 +1089,22 @@ void geneve_mapper_device::device_reset() // Clear map for (auto & elem : m_map) elem = 0; - m_genmod = false; - // Check which boot EPROM we are using (or PFM) - set_boot_rom(machine().root_device().ioport("BOOTROM")->read()); + m_boot_rom = machine().root_device().ioport("BOOTROM")->read(); + m_eprom = machine().root_device().memregion("maincpu")->base(); - // Check for GenMod. We assume that GenMod can be combined with PFM. - if (machine().root_device().ioport("MODE")->read()!=0) - { - LOGMASKED(LOG_SETTING, "Using GenMod modification\n"); - m_eprom = machine().root_device().memregion("maincpu")->base() + 0x8000; - if (m_eprom[0] != 0xf0) - { - fatalerror("genboard: GenMod boot ROM missing\n"); - } - m_genmod = true; - m_turbo = ((machine().root_device().ioport("GENMODDIPS")->read() & GENEVE_GM_TURBO)!=0); - m_timode = ((machine().root_device().ioport("GENMODDIPS")->read() & GENEVE_GM_TIM)!=0); - } + // Allow for configuring the VRAM size + uint32_t videoram = (machine().root_device().ioport("VRAM")->read()!=0)? 0x30000 : 0x20000; + downcast(*m_video.target()).set_vram_size(videoram); + LOGMASKED(LOG_SETTING, "Video RAM set to %d KiB\n", videoram / 1024); +} + +void geneve_mapper_device::device_reset() +{ + common_reset(); + // SRAM is only separately handled for the standard Geneve; Genmod uses + // the Memex instead switch (machine().root_device().ioport("SRAM")->read()) { /* 1 100. .... .... .... .... on-board sram (128K) -+ @@ -1516,15 +1126,35 @@ void geneve_mapper_device::device_reset() m_sram_val = 0x180000; break; } +} - // Allow for configuring the VRAM size - uint32_t videoram = (machine().root_device().ioport("VRAM")->read()!=0)? 0x30000 : 0x20000; - downcast(*m_video.target()).set_vram_size(videoram); - LOGMASKED(LOG_SETTING, "Video RAM set to %d KiB\n", videoram / 1024); +void genmod_mapper_device::device_reset() +{ + 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); } /**************************************************************************** Keyboard support + + The XT keyboard interface is described in various places on the internet, + like (http://www-2.cs.cmu.edu/afs/cs/usr/jmcm/www/info/key2.txt). It is a + synchronous unidirectional serial interface: the data line is driven by the + keyboard to send data to the CPU; the CTS/clock line has a pull up resistor + and can be driven low by both keyboard and CPU. To send data to the CPU, + the keyboard pulses the clock line low 9 times, and the Geneve samples all + 8 bits of data (plus one start bit) on each falling edge of the clock. + When the key code buffer is full, the Geneve gate array asserts the kbdint* + line (connected to 9901 int8_t*). The Geneve gate array will hold the + CTS/clock line low as long as the keyboard buffer is full or CRU bit @>F78 + is 0. Writing a 0 to >F79 will clear the Geneve keyboard buffer, and + writing a 1 will resume normal operation: you need to write a 0 to >F78 + before clearing >F79, or the keyboard will be enabled to send data the gate + array when >F79 is is set to 0, and any such incoming data from the + keyboard will be cleared as soon as it is buffered by the gate array. + ****************************************************************************/ static const uint8_t MF1_CODE[0xe] = diff --git a/src/devices/bus/ti99/internal/genboard.h b/src/devices/bus/ti99/internal/genboard.h index 26e6766adef..baac4db69de 100644 --- a/src/devices/bus/ti99/internal/genboard.h +++ b/src/devices/bus/ti99/internal/genboard.h @@ -32,8 +32,7 @@ enum enum { - GENEVE_098 = 0, - GENEVE_100, + GENEVE_EPROM = 0, GENEVE_PFM512, GENEVE_PFM512A }; @@ -117,6 +116,7 @@ class geneve_mapper_device : public device_t { public: geneve_mapper_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); @@ -141,10 +141,11 @@ public: template devcb_base &set_ready_callback(Object &&cb) { return m_ready.set_callback(std::forward(cb)); } protected: + geneve_mapper_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); void device_start() override; - void device_reset() override; + virtual void device_reset() override; + void common_reset(); -private: // GROM simulation bool m_gromwaddr_LSB; bool m_gromraddr_LSB; @@ -153,24 +154,15 @@ private: DECLARE_WRITE8_MEMBER( write_grom ); // wait states - void set_wait(int min); - void set_ext_wait(int min); - bool m_video_waitstates; - bool m_extra_waitstates; - bool m_ready_asserted; - - bool m_read_mode; + void set_wait(int min); + void set_video_waitcount(int min); + bool m_video_waitstates; + bool m_extra_waitstates; + bool m_ready_asserted; - bool m_debug_no_ws; - - // Mapper function - typedef struct - { - int function; - offs_t offset; - offs_t physaddr; - } decdata; + bool m_read_mode; + bool m_debug_no_ws; bool m_geneve_mode; bool m_direct_mode; int m_cartridge_size; @@ -179,22 +171,102 @@ private: bool m_cartridge7_writable; int m_map[8]; - void decode(address_space& space, offs_t offset, bool read_mode, decdata* dec); + /* + Constants for mapper decoding. Naming scheme: + M=Mapper, L=Logical space; P=Physical space + */ + typedef enum + { + MUNDEF=0, + + MLVIDEO, + MLMAPPER, + MLKEY, + MLSOUND, + MLCLOCK, + MLGROM, + + MPDRAM, + MPEXP, + MPEPROM, + MPSRAM, + + MBOX + } decfunct_t; + + // 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; + + // The result of decoding decdata m_decoded; - // Genmod modifications - bool m_turbo; - bool m_genmod; - bool m_timode; + // Static decoder entry for the logical space + // Not all entries apply for native mode, e.g. there is no GROM in native + // mode. In that case the base and mask are 0000, and the entry must be + // skipped. Speech is accessible in the physical space in native mode. + // All entries have a wait state count of 1. + typedef struct + { + offs_t genbase; // Base address in native mode + int genmask; // Bits that also match this entry + offs_t tibase; // Base address in TI mode + int timask; // Bits that also match this entry + int writeoff; // Additional offset in TI mode for writing + decfunct_t function; // Decoded function + const char* description; // Good for logging + } logentry_t; + + logentry_t m_logmap[7] = + { + { 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" }, + { 0xf130, 0x000f, 0x8010, 0x000f, 0x0000, MLCLOCK, "clock" }, + { 0x0000, 0x0000, 0x9000, 0x03fe, 0x0400, MBOX, "speech (in P-Box)" }, + { 0x0000, 0x0000, 0x9800, 0x03fe, 0x0400, MLGROM, "GROM" }, + }; + + // Static decoder entry for the physical space + // There are no differences between native mode and TI mode. + typedef struct + { + offs_t base; // Base address + 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; + + physentry_t m_physmap[4] = + { + { 0x000000, 0x07ffff, MPDRAM, 1, "DRAM" }, + { 0x080000, 0x07ffff, MPEXP, 1, "on-board expansion" }, + { 0x1e0000, 0x01ffff, MPEPROM, 0, "EPROM" }, + { 0x180000, 0x07ffff, MPSRAM, 0, "SRAM" } + }; + + 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) { }; // PFM mod (0 = none, 1 = AT29C040, 2 = AT29C040A) - DECLARE_READ8_MEMBER( read_from_pfm ); + DECLARE_READ8_MEMBER( boot_rom ); DECLARE_WRITE8_MEMBER( write_to_pfm ); - void set_boot_rom(int selection); - int m_pfm_mode; + int m_boot_rom; int m_pfm_bank; bool m_pfm_output_enable; + int m_pbox_prefix; + // SRAM access int m_sram_mask; int m_sram_val; @@ -204,7 +276,7 @@ private: // Counter for the wait states. int m_waitcount; - int m_ext_waitcount; + int m_video_waitcount; // Devices required_device m_clock; @@ -221,6 +293,20 @@ private: required_device m_dram; }; +class genmod_mapper_device : public geneve_mapper_device +{ +public: + genmod_mapper_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 ); + +private: + // Genmod modifications + bool m_gm_timode; + bool m_turbo; +}; + #define MCFG_GENEVE_READY_HANDLER( _intcallb ) \ devcb = &downcast(*device).set_ready_callback(DEVCB_##_intcallb); @@ -228,5 +314,6 @@ private: DECLARE_DEVICE_TYPE_NS(GENEVE_KEYBOARD, bus::ti99::internal, geneve_keyboard_device) DECLARE_DEVICE_TYPE_NS(GENEVE_MAPPER, bus::ti99::internal, geneve_mapper_device) +DECLARE_DEVICE_TYPE_NS(GENMOD_MAPPER, bus::ti99::internal, genmod_mapper_device) #endif // MAME_BUS_TI99_INTERNAL_GENBOARD_H diff --git a/src/devices/bus/ti99/peb/peribox.cpp b/src/devices/bus/ti99/peb/peribox.cpp index 1ada6e9a75f..6e81dc6886b 100644 --- a/src/devices/bus/ti99/peb/peribox.cpp +++ b/src/devices/bus/ti99/peb/peribox.cpp @@ -208,6 +208,9 @@ DEFINE_DEVICE_TYPE_NS(TI99_PERIBOX_SG, bus::ti99::peb, peribox_sg_device, "p // Peripheral box which hosts the Geneve 9640 in slot 1 DEFINE_DEVICE_TYPE_NS(TI99_PERIBOX_GEN, bus::ti99::peb, peribox_gen_device, "peribox_gen", "Peripheral expansion box Geneve") +// Peripheral box which hosts the Geneve 9640 in slot 1 with Genmod +DEFINE_DEVICE_TYPE_NS(TI99_PERIBOX_GENMOD, bus::ti99::peb, peribox_genmod_device, "peribox_genmod", "Peripheral expansion box Genmod") + // Single slot of the PEB DEFINE_DEVICE_TYPE_NS(TI99_PERIBOX_SLOT, bus::ti99::peb, peribox_slot_device, "peribox_slot", "TI P-Box slot") @@ -251,6 +254,7 @@ peribox_device::peribox_device(const machine_config &mconfig, const char *tag, d // The address prefix is actually created by the "Flex cable interface" // which sits in slot 1. m_address_prefix = 0x70000; + m_genmod = false; } /* @@ -363,23 +367,6 @@ WRITE_LINE_MEMBER(peribox_device::clock_in) } } -/* - The Genmod modification is only of interest for the Geneve. It requires - to modify the decoding of each single card. -*/ -INPUT_CHANGED_MEMBER( peribox_device::genmod_changed ) -{ - set_genmod(newval==1); -} - -void peribox_device::set_genmod(bool set) -{ - for (int i=2; i <= 8; i++) - { - if (m_slot[i]!=nullptr) m_slot[i]->set_genmod(set); - } -} - /* The INTA*, INTB*, and READY* lines are connected to each PEB card and are pulled up when inactive. If any card asserts the line (pulling down), the @@ -449,6 +436,8 @@ 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() @@ -521,6 +510,7 @@ 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 peribox_slotv(device_slot_interface &device) @@ -555,8 +545,8 @@ MACHINE_CONFIG_END A variant of the box used for the Geneve. *****************************************************************************/ -peribox_gen_device::peribox_gen_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : peribox_device(mconfig, TI99_PERIBOX_GEN, tag, owner, clock) +peribox_gen_device::peribox_gen_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock): + peribox_device(mconfig, type, tag, owner, clock) { // The Geneve sits in slot 1; there is no prefix here - it can control // a maximum address space of 512 KiB in the box. With the Genmod @@ -564,6 +554,18 @@ peribox_gen_device::peribox_gen_device(const machine_config &mconfig, const char m_address_prefix = 0x00000; } +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 // logic (see bwg.c) @@ -589,6 +591,16 @@ MACHINE_CONFIG_START(peribox_gen_device::device_add_mconfig) MCFG_PERIBOX_SLOT_ADD( PEBSLOT8, peribox_slotg ) MACHINE_CONFIG_END +MACHINE_CONFIG_START(peribox_genmod_device::device_add_mconfig) + MCFG_PERIBOX_SLOT_ADD_DEF( PEBSLOT2, peribox_slotg, "memex" ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT3, peribox_slotv ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT4, peribox_slotv ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT5, peribox_slotv ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT6, peribox_slotv ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT7, peribox_slotv ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT8, peribox_slotv ) +MACHINE_CONFIG_END + /**************************************************************************** A variant of the box used for the SGCPU (aka TI-99/4P). *****************************************************************************/ @@ -597,6 +609,7 @@ peribox_sg_device::peribox_sg_device(const machine_config &mconfig, const char * : peribox_device(mconfig, TI99_PERIBOX_SG, tag, owner, clock) { m_address_prefix = 0x70000; + m_genmod = false; } void peribox_slotp(device_slot_interface &device) diff --git a/src/devices/bus/ti99/peb/peribox.h b/src/devices/bus/ti99/peb/peribox.h index 00be0795d10..71ad9eb589b 100644 --- a/src/devices/bus/ti99/peb/peribox.h +++ b/src/devices/bus/ti99/peb/peribox.h @@ -58,10 +58,6 @@ public: // Part of configuration void set_prefix(int prefix) { m_address_prefix = prefix; } - // Genmod support - DECLARE_INPUT_CHANGED_MEMBER( genmod_changed ); - void set_genmod(bool set); - protected: peribox_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); @@ -102,6 +98,9 @@ protected: // Configured as a slot device (of the ioport) bool m_ioport_connected; + + // Used for Genmod + bool m_genmod; }; /************************************************************************ @@ -139,12 +138,25 @@ protected: class peribox_gen_device : public peribox_device { public: + peribox_gen_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); peribox_gen_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); protected: virtual void device_add_mconfig(machine_config &config) override; }; +/* + Variation for Geneve with Genmod +*/ +class peribox_genmod_device : public peribox_gen_device +{ +public: + peribox_genmod_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + void device_add_mconfig(machine_config &config) override; +}; + /***************************************************************************** The parent class for all expansion cards. ******************************************************************************/ @@ -256,5 +268,6 @@ DECLARE_DEVICE_TYPE_NS(TI99_PERIBOX_EV, bus::ti99::peb, peribox_ev_device) DECLARE_DEVICE_TYPE_NS(TI99_PERIBOX_SLOT, bus::ti99::peb, peribox_slot_device) DECLARE_DEVICE_TYPE_NS(TI99_PERIBOX_SG, bus::ti99::peb, peribox_sg_device) DECLARE_DEVICE_TYPE_NS(TI99_PERIBOX_GEN, bus::ti99::peb, peribox_gen_device) +DECLARE_DEVICE_TYPE_NS(TI99_PERIBOX_GENMOD, bus::ti99::peb, peribox_genmod_device) #endif // MAME_BUS_TI99_PEB_PERIBOX_H diff --git a/src/mame/drivers/geneve.cpp b/src/mame/drivers/geneve.cpp index 8d8ded314bd..ce0285bdd7c 100644 --- a/src/mame/drivers/geneve.cpp +++ b/src/mame/drivers/geneve.cpp @@ -178,25 +178,6 @@ Bit 14: 0 = protect cartridge range >7000->7fff bit 15: 1 = add 1 extra wait state when accessing 0-wait-state SRAM??? - - Keyboard interface: - - The XT keyboard interface is described in various places on the internet, - like (http://www-2.cs.cmu.edu/afs/cs/usr/jmcm/www/info/key2.txt). It is a - synchronous unidirectional serial interface: the data line is driven by the - keyboard to send data to the CPU; the CTS/clock line has a pull up resistor - and can be driven low by both keyboard and CPU. To send data to the CPU, - the keyboard pulses the clock line low 9 times, and the Geneve samples all - 8 bits of data (plus one start bit) on each falling edge of the clock. - When the key code buffer is full, the Geneve gate array asserts the kbdint* - line (connected to 9901 int8_t*). The Geneve gate array will hold the - CTS/clock line low as long as the keyboard buffer is full or CRU bit @>F78 - is 0. Writing a 0 to >F79 will clear the Geneve keyboard buffer, and - writing a 1 will resume normal operation: you need to write a 0 to >F78 - before clearing >F79, or the keyboard will be enabled to send data the gate - array when >F79 is is set to 0, and any such incoming data from the - keyboard will be cleared as soon as it is buffered by the gate array. - Original version 2003 by Raphael Nabet Rewritten 2012 by Michael Zapf @@ -216,11 +197,15 @@ #include "speaker.h" -#define TRACE_READY 0 -#define TRACE_LINES 0 -#define TRACE_CRU 0 +#define LOG_WARN (1U<<1) +#define LOG_READY (1U<<2) +#define LOG_LINES (1U<<3) +#define LOG_CRU (1U<<4) -#define GENMOD 0x01 +// Minimum log should be settings and warnings +#define VERBOSE (LOG_GENERAL | LOG_WARN) + +#include "logmacro.h" class geneve_state : public driver_device { @@ -285,7 +270,10 @@ public: int m_ready_line; int m_ready_line1; - void geneve_60hz(machine_config &config); + void geneve_common(machine_config &config); + void geneve(machine_config &config); + void genmod(machine_config &config); + void crumap(address_map &map); void memmap(address_map &map); }; @@ -316,42 +304,46 @@ void geneve_state::crumap(address_map &map) map(0x0000, 0x001f).w(m_tms9901, FUNC(tms9901_device::write)); } -/* TI joysticks. The keyboard is implemented in genboard.c. */ -static INPUT_PORTS_START(geneve) - - PORT_START( "MODE" ) - PORT_CONFNAME( 0x01, 0x00, "Operating mode" ) PORT_CHANGED_MEMBER(TI_PERIBOX_TAG, bus::ti99::peb::peribox_device, genmod_changed, 0) - PORT_CONFSETTING( 0x00, "Standard" ) - PORT_CONFSETTING( GENMOD, "GenMod" ) +static INPUT_PORTS_START(geneve_common) PORT_START( "BOOTROM" ) - PORT_CONFNAME( 0x03, GENEVE_098, "Boot ROM" ) PORT_CHANGED_MEMBER(GENEVE_MAPPER_TAG, bus::ti99::internal::geneve_mapper_device, settings_changed, 3) - PORT_CONFSETTING( GENEVE_098, "Version 0.98" ) - PORT_CONFSETTING( GENEVE_100, "Version 1.00" ) + PORT_CONFNAME( 0x03, GENEVE_EPROM, "Boot from" ) PORT_CHANGED_MEMBER(GENEVE_MAPPER_TAG, bus::ti99::internal::geneve_mapper_device, settings_changed, 3) + PORT_CONFSETTING( GENEVE_EPROM, "EPROM" ) PORT_CONFSETTING( GENEVE_PFM512, "PFM 512" ) PORT_CONFSETTING( GENEVE_PFM512A, "PFM 512A" ) + PORT_START( "VRAM" ) + PORT_CONFNAME( 0x01, 0x00, "Video RAM" ) + PORT_CONFSETTING( 0x00, "128 KiB" ) + PORT_CONFSETTING( 0x01, "192 KiB" ) + +INPUT_PORTS_END + +static INPUT_PORTS_START(geneve) + PORT_INCLUDE(geneve_common) + PORT_START( "SRAM" ) - PORT_CONFNAME( 0x03, 0x01, "Onboard SRAM" ) PORT_CONDITION( "MODE", 0x01, EQUALS, 0x00 ) + PORT_CONFNAME( 0x03, 0x01, "Onboard SRAM" ) PORT_CONFSETTING( 0x00, "32 KiB" ) PORT_CONFSETTING( 0x01, "64 KiB" ) PORT_CONFSETTING( 0x02, "384 KiB" ) - PORT_START( "VRAM" ) - PORT_CONFNAME( 0x01, 0x00, "Video RAM" ) - PORT_CONFSETTING( 0x00, "128 KiB" ) - PORT_CONFSETTING( 0x01, "192 KiB" ) +INPUT_PORTS_END + +static INPUT_PORTS_START(genmod) + PORT_INCLUDE(geneve_common) PORT_START( "GENMODDIPS" ) - PORT_DIPNAME( GENEVE_GM_TURBO, 0x00, "Genmod Turbo mode") PORT_CONDITION( "MODE", 0x01, EQUALS, GENMOD ) PORT_CHANGED_MEMBER(GENEVE_MAPPER_TAG, bus::ti99::internal::geneve_mapper_device, settings_changed, 1) + PORT_DIPNAME( GENEVE_GM_TURBO, 0x00, "Genmod Turbo mode") PORT_CHANGED_MEMBER(GENEVE_MAPPER_TAG, bus::ti99::internal::genmod_mapper_device, 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_CONDITION( "MODE", 0x01, EQUALS, GENMOD ) PORT_CHANGED_MEMBER(GENEVE_MAPPER_TAG, bus::ti99::internal::geneve_mapper_device, settings_changed, 2) + PORT_DIPNAME( GENEVE_GM_TIM, GENEVE_GM_TIM, "Genmod TI mode") PORT_CHANGED_MEMBER(GENEVE_MAPPER_TAG, bus::ti99::internal::genmod_mapper_device, setgm_changed, 2) PORT_CONFSETTING( 0x00, DEF_STR( Off )) PORT_CONFSETTING( GENEVE_GM_TIM, DEF_STR( On )) INPUT_PORTS_END + /**************************************************************************** CRU handling *****************************************************************************/ @@ -368,10 +360,11 @@ WRITE8_MEMBER ( geneve_state::cruwrite ) if ((addroff & 0xffc0) == CRU_SSTEP_BASE) { int bit = (addroff & 0x003e)>>1; - logerror("Single step not implemented; bit %d set to %d\n", bit, data); + LOGMASKED(LOG_WARN, "Single step not implemented; bit %d set to %d\n", bit, data); return; } + // This is just mirroring the internal flags of the 9995 if ((addroff & 0xffe0) == CRU_CONTROL_BASE) { int bit = (addroff & 0x001e)>>1; @@ -379,47 +372,47 @@ WRITE8_MEMBER ( geneve_state::cruwrite ) { case 5: // No one really cares... - if (TRACE_CRU) logerror("Set PAL flag = %02x\n", data); + LOGMASKED(LOG_CRU, "Set PAL flag = %02x\n", data); // m_palvideo = (data!=0); break; case 7: // m_capslock = (data!=0); - if (TRACE_CRU) logerror("Set capslock flag = %02x\n", data); + LOGMASKED(LOG_CRU, "Set capslock flag = %02x\n", data); break; case 8: - if (TRACE_CRU) logerror("Set keyboard clock flag = %02x\n", data); + LOGMASKED(LOG_CRU, "Set keyboard clock flag = %02x\n", data); m_keyboard->clock_control((data!=0)? ASSERT_LINE : CLEAR_LINE); break; case 9: - if (TRACE_CRU) logerror("Set keyboard scan flag = %02x\n", data); + LOGMASKED(LOG_CRU, "Set keyboard scan flag = %02x\n", data); m_keyboard->send_scancodes((data!=0)? ASSERT_LINE : CLEAR_LINE); break; case 10: - if (TRACE_CRU) logerror("Geneve mode = %02x\n", data); + LOGMASKED(LOG_CRU, "Geneve mode = %02x\n", data); m_mapper->set_geneve_mode(data!=0); break; case 11: - if (TRACE_CRU) logerror("Direct mode = %02x\n", data); + LOGMASKED(LOG_CRU, "Direct mode = %02x\n", data); m_mapper->set_direct_mode(data!=0); break; case 12: - if (TRACE_CRU) logerror("Cartridge size 8K = %02x\n", data); + LOGMASKED(LOG_CRU, "Cartridge size 8K = %02x\n", data); m_mapper->set_cartridge_size((data!=0)? 0x2000 : 0x4000); break; case 13: - if (TRACE_CRU) logerror("Cartridge writable 6000 = %02x\n", data); + LOGMASKED(LOG_CRU, "Cartridge writable 6000 = %02x\n", data); m_mapper->set_cartridge_writable(0x6000, (data!=0)); break; case 14: - if (TRACE_CRU) logerror("Cartridge writable 7000 = %02x\n", data); + LOGMASKED(LOG_CRU, "Cartridge writable 7000 = %02x\n", data); m_mapper->set_cartridge_writable(0x7000, (data!=0)); break; case 15: - if (TRACE_CRU) logerror("Extra wait states = %02x\n", data==0); + LOGMASKED(LOG_CRU, "Extra wait states = %02x\n", data==0); m_mapper->set_extra_waitstates(data==0); // let's use the inverse semantics break; default: - logerror("set CRU address %04x=%02x ignored\n", addroff, data); + LOGMASKED(LOG_WARN, "set CRU address %04x=%02x ignored\n", addroff, data); break; } } @@ -439,7 +432,7 @@ READ8_MEMBER( geneve_state::cruread ) if ((addroff & 0xffc0) == CRU_SSTEP_BASE) { int bit = (addroff & 0x003e)>>1; - logerror("Single step not implemented; attempting to read bit %d\n", bit); + LOGMASKED(LOG_WARN, "Single step not implemented; attempting to read bit %d\n", bit); return value; } @@ -491,7 +484,7 @@ READ8_MEMBER( geneve_state::read_by_9901 ) if (m_intb==CLEAR_LINE) answer |= 0x10; if (m_video_wait==ASSERT_LINE) answer |= 0x20; // TODO: PAL pin 5 - if (TRACE_LINES) logerror("INT15-8 = %02x\n", answer); + LOGMASKED(LOG_LINES, "INT15-8 = %02x\n", answer); break; case tms9901_device::P0_P7: @@ -519,7 +512,7 @@ READ8_MEMBER( geneve_state::read_by_9901 ) */ WRITE_LINE_MEMBER( geneve_state::peripheral_bus_reset ) { - logerror("Peripheral bus reset request; not implemented yet.\n"); + LOGMASKED(LOG_WARN, "Peripheral bus reset request; not implemented yet.\n"); } /* @@ -527,7 +520,7 @@ WRITE_LINE_MEMBER( geneve_state::peripheral_bus_reset ) */ WRITE_LINE_MEMBER( geneve_state::VDP_reset ) { - logerror("Video reset request; not implemented yet.\n"); + LOGMASKED(LOG_WARN, "Video reset request; not implemented yet.\n"); } /* @@ -543,7 +536,7 @@ WRITE_LINE_MEMBER( geneve_state::joystick_select ) */ WRITE_LINE_MEMBER( geneve_state::extbus_wait_states ) { - logerror("External bus wait states set to %d, not implemented yet.\n", state); + LOGMASKED(LOG_WARN, "External bus wait states set to %d, not implemented yet.\n", state); } /* @@ -552,7 +545,7 @@ WRITE_LINE_MEMBER( geneve_state::extbus_wait_states ) */ WRITE_LINE_MEMBER( geneve_state::video_wait_states ) { - if (TRACE_LINES) logerror("Video wait states set to %d\n", state); + LOGMASKED(LOG_LINES, "Video wait states set to %d\n", state); m_mapper->set_video_waitstates(state==ASSERT_LINE); m_video_wait = (state!=0)? ASSERT_LINE : CLEAR_LINE; } @@ -594,14 +587,14 @@ WRITE_LINE_MEMBER( geneve_state::intb ) WRITE_LINE_MEMBER( geneve_state::ext_ready ) { - if (TRACE_READY) logerror("READY level (ext) = %02x\n", state); + 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 ) { - if (TRACE_READY) logerror("READY level (mapper) = %02x\n", state); + 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); } @@ -636,7 +629,8 @@ WRITE_LINE_MEMBER( geneve_state::keyboard_interrupt ) WRITE8_MEMBER( geneve_state::external_operation ) { static const char* extop[8] = { "inv1", "inv2", "IDLE", "RSET", "inv3", "CKON", "CKOF", "LREX" }; - if (offset != IDLE_OP) logerror("External operation %s not implemented on Geneve board\n", extop[offset]); + if (offset != IDLE_OP) + LOGMASKED(LOG_WARN, "External operation %s not implemented on Geneve board\n", extop[offset]); } /* @@ -688,12 +682,35 @@ void geneve_state::machine_reset() m_ready_line = m_ready_line1 = ASSERT_LINE; - m_peribox->set_genmod(ioport("MODE")->read()==GENMOD); - m_joyport->write_port(0x01); // select Joystick 1 } -MACHINE_CONFIG_START(geneve_state::geneve_60hz) +MACHINE_CONFIG_START(geneve_state::geneve) + geneve_common(config); + // Mapper + MCFG_DEVICE_ADD(GENEVE_MAPPER_TAG, GENEVE_MAPPER, 0) + MCFG_GENEVE_READY_HANDLER( WRITELINE(*this, geneve_state, mapper_ready) ) + // Peripheral expansion box (Geneve composition) + MCFG_DEVICE_ADD( TI_PERIBOX_TAG, TI99_PERIBOX_GEN, 0) + MCFG_PERIBOX_INTA_HANDLER( WRITELINE(*this, geneve_state, inta) ) + MCFG_PERIBOX_INTB_HANDLER( WRITELINE(*this, geneve_state, intb) ) + MCFG_PERIBOX_READY_HANDLER( WRITELINE(*this, geneve_state, ext_ready) ) + +MACHINE_CONFIG_END + +MACHINE_CONFIG_START(geneve_state::genmod) + geneve_common(config); + // Mapper + MCFG_DEVICE_ADD(GENEVE_MAPPER_TAG, GENMOD_MAPPER, 0) + MCFG_GENEVE_READY_HANDLER( WRITELINE(*this, geneve_state, mapper_ready) ) + // Peripheral expansion box (Geneve composition with Genmod and plugged-in Memex) + MCFG_DEVICE_ADD( TI_PERIBOX_TAG, TI99_PERIBOX_GENMOD, 0) + MCFG_PERIBOX_INTA_HANDLER( WRITELINE(*this, geneve_state, inta) ) + MCFG_PERIBOX_INTB_HANDLER( WRITELINE(*this, geneve_state, intb) ) + MCFG_PERIBOX_READY_HANDLER( WRITELINE(*this, geneve_state, ext_ready) ) +MACHINE_CONFIG_END + +MACHINE_CONFIG_START(geneve_state::geneve_common) // basic machine hardware // TMS9995 CPU @ 12.0 MHz MCFG_TMS99xx_ADD("maincpu", TMS9995, 12000000, memmap, crumap) @@ -720,21 +737,11 @@ MACHINE_CONFIG_START(geneve_state::geneve_60hz) MCFG_TMS9901_P13_HANDLER( WRITELINE( GENEVE_MAPPER_TAG, bus::ti99::internal::geneve_mapper_device, pfm_select_msb) ) // new for PFM MCFG_TMS9901_INTLEVEL_HANDLER( WRITE8( *this, geneve_state, tms9901_interrupt) ) - // Mapper - MCFG_DEVICE_ADD(GENEVE_MAPPER_TAG, GENEVE_MAPPER, 0) - MCFG_GENEVE_READY_HANDLER( WRITELINE(*this, geneve_state, mapper_ready) ) - // Clock MCFG_DEVICE_ADD(GENEVE_CLOCK_TAG, MM58274C, 0) MCFG_MM58274C_MODE24(1) // 24 hour MCFG_MM58274C_DAY1(0) // sunday - // Peripheral expansion box (Geneve composition) - MCFG_DEVICE_ADD( TI_PERIBOX_TAG, TI99_PERIBOX_GEN, 0) - MCFG_PERIBOX_INTA_HANDLER( WRITELINE(*this, geneve_state, inta) ) - MCFG_PERIBOX_INTB_HANDLER( WRITELINE(*this, geneve_state, intb) ) - MCFG_PERIBOX_READY_HANDLER( WRITELINE(*this, geneve_state, ext_ready) ) - // Sound hardware SPEAKER(config, "sound_out").front_center(); MCFG_DEVICE_ADD(TI_SOUNDCHIP_TAG, SN76496, 3579545) /* 3.579545 MHz */ @@ -756,7 +763,7 @@ MACHINE_CONFIG_START(geneve_state::geneve_60hz) MCFG_RAM_DEFAULT_SIZE("512K") MCFG_RAM_DEFAULT_VALUE(0) - // SRAM 384K (max; stock Geneve: 32K) + // SRAM 384K (max; stock Geneve: 32K, but later MDOS releases require 64K) MCFG_RAM_ADD(GENEVE_SRAM_TAG) MCFG_RAM_DEFAULT_SIZE("384K") MCFG_RAM_DEFAULT_VALUE(0) @@ -769,11 +776,20 @@ MACHINE_CONFIG_END ROM_START(geneve) /*CPU memory space*/ - ROM_REGION(0xc000, "maincpu", 0) - ROM_LOAD("genbt100.bin", 0x0000, 0x4000, CRC(8001e386) SHA1(b44618b54dabac3882543e18555d482b299e0109)) /* CPU ROMs v1.0 */ - ROM_LOAD_OPTIONAL("genbt098.bin", 0x4000, 0x4000, CRC(b2e20df9) SHA1(2d5d09177afe97d63ceb3ad59b498b1c9e2153f7)) /* CPU ROMs v0.98 */ - ROM_LOAD_OPTIONAL("gnmbt100.bin", 0x8000, 0x4000, CRC(19b89479) SHA1(6ef297eda78dc705946f6494e9d7e95e5216ec47)) /* CPU ROMs GenMod */ + ROM_REGION(0x4000, "maincpu", 0) + ROM_DEFAULT_BIOS("0.98") + ROM_SYSTEM_BIOS(0, "0.98", "Geneve Boot ROM 0.98") + ROMX_LOAD("genbt098.bin", 0x0000, 0x4000, CRC(b2e20df9) SHA1(2d5d09177afe97d63ceb3ad59b498b1c9e2153f7), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "1.00", "Geneve Boot ROM 1.00") + ROMX_LOAD("genbt100.bin", 0x0000, 0x4000, CRC(8001e386) SHA1(b44618b54dabac3882543e18555d482b299e0109), ROM_BIOS(1)) +ROM_END + +ROM_START(genmod) + /*CPU memory space*/ + ROM_REGION(0x4000, "maincpu", 0) + ROM_LOAD("gnmbt100.bin", 0x0000, 0x4000, CRC(19b89479) SHA1(6ef297eda78dc705946f6494e9d7e95e5216ec47)) ROM_END // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS -COMP( 1987, geneve, 0, 0, geneve_60hz, geneve, geneve_state, init_geneve, "Myarc", "Geneve 9640", MACHINE_SUPPORTS_SAVE) +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) diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 7ab004726e9..ddb5ae412fd 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -13836,7 +13836,8 @@ suprpokra // (c) 1986 Grayhound Electronics suprpokrb // (c) 1986 Grayhound Electronics @source:geneve.cpp -geneve // 1987? Myarc Geneve 9640 +geneve // 1987 Myarc Geneve 9640 +genmod // 1990 Myarc / Ron G. Walters Geneve 9640 Mod @source:geniusiq.cpp iq128 // 1997 Genius IQ 128 (Germany) -- cgit v1.2.3