diff options
Diffstat (limited to 'src/mess/drivers/geneve.c')
-rw-r--r-- | src/mess/drivers/geneve.c | 807 |
1 files changed, 807 insertions, 0 deletions
diff --git a/src/mess/drivers/geneve.c b/src/mess/drivers/geneve.c new file mode 100644 index 00000000000..48caeff9c3d --- /dev/null +++ b/src/mess/drivers/geneve.c @@ -0,0 +1,807 @@ +/* + MESS Driver for the 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??? + + + 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*). 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 +*/ + + +#include "emu.h" +#include "cpu/tms9900/tms9995.h" +#include "machine/tms9901.h" +#include "machine/mm58274c.h" +#include "sound/sn76496.h" + +#include "machine/ti99/genboard.h" +#include "machine/ti99/peribox.h" +#include "machine/ti99/videowrp.h" + +#include "machine/ti99/joyport.h" + +#define VERBOSE 1 +#define LOG logerror + +#define SRAM_SIZE 384*1024 // maximum SRAM expansion on-board +#define DRAM_SIZE 512*1024 + +class geneve : public driver_device +{ +public: + geneve(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) { } + + // CRU (Communication Register Unit) handling + DECLARE_READ8_MEMBER(cruread); + DECLARE_WRITE8_MEMBER(cruwrite); + + // Connections with the system interface TMS9901 + DECLARE_READ8_MEMBER(read_by_9901); + 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(video_wait_states); + + DECLARE_WRITE_LINE_MEMBER(clock_out); + DECLARE_WRITE8_MEMBER(external_operation); + + DECLARE_WRITE8_MEMBER(tms9901_interrupt); + + WRITE_LINE_MEMBER( keyboard_interrupt ); + + geneve_keyboard_device* m_keyboard; + geneve_mouse_device* m_mouse; + tms9901_device* m_tms9901; + geneve_mapper_device* m_mapper; + peribox_device* m_peribox; + tms9995_device* m_cpu; + joyport_device* m_joyport; + + WRITE_LINE_MEMBER( inta ); + WRITE_LINE_MEMBER( intb ); + WRITE_LINE_MEMBER( ext_ready ); + WRITE_LINE_MEMBER( mapper_ready ); + + DECLARE_DRIVER_INIT(geneve); + + void set_tms9901_INT2_from_v9938(v99x8_device &vdp, int state); + + line_state m_inta; + line_state m_intb; + line_state m_int2; + line_state m_keyint; + line_state m_video_wait; // reflects the line to the mapper for CRU query + + int m_ready_line, m_ready_line1; + +private: + int m_joystick_select; + // Some values to keep. Rest is on the geneve_mapper. +}; + +/* + Memory map +*/ + +static ADDRESS_MAP_START(memmap, AS_PROGRAM, 8, geneve) + AM_RANGE(0x0000, 0xffff) AM_DEVREADWRITE(GMAPPER_TAG, geneve_mapper_device, readm, writem) +ADDRESS_MAP_END + +/* + CRU 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. +*/ +static ADDRESS_MAP_START(crumap, AS_IO, 8, geneve) + AM_RANGE(0x0000, 0x0003) AM_DEVREAD(TMS9901_TAG, tms9901_device, read) + AM_RANGE(0x0000, 0x0fff) AM_READ( cruread ) + + AM_RANGE(0x0000, 0x001f) AM_DEVWRITE(TMS9901_TAG, tms9901_device, write) + AM_RANGE(0x0000, 0x7fff) AM_WRITE( cruwrite ) +ADDRESS_MAP_END + +/* 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(PERIBOX_TAG, peribox_device, genmod_changed, 0) + PORT_CONFSETTING( 0x00, "Standard" ) + PORT_CONFSETTING( GENMOD, "GenMod" ) + + PORT_START( "BOOTROM" ) + PORT_CONFNAME( 0x01, GENEVE_098, "Boot ROM" ) PORT_CONDITION( "MODE", 0x01, EQUALS, 0x00 ) + PORT_CONFSETTING( GENEVE_098, "Version 0.98" ) + PORT_CONFSETTING( GENEVE_100, "Version 1.00" ) + + PORT_START( "SRAM" ) + PORT_CONFNAME( 0x03, 0x01, "Onboard SRAM" ) PORT_CONDITION( "MODE", 0x01, EQUALS, 0x00 ) + PORT_CONFSETTING( 0x00, "32 KiB" ) + PORT_CONFSETTING( 0x01, "64 KiB" ) + PORT_CONFSETTING( 0x02, "384 KiB" ) + + PORT_START( "GENMODDIPS" ) + PORT_DIPNAME( GM_TURBO, 0x00, "Genmod Turbo mode") PORT_CONDITION( "MODE", 0x01, EQUALS, GENMOD ) PORT_CHANGED_MEMBER(GMAPPER_TAG, geneve_mapper_device, gm_changed, 1) + PORT_CONFSETTING( 0x00, DEF_STR( Off )) + PORT_CONFSETTING( GM_TURBO, DEF_STR( On )) + PORT_DIPNAME( GM_TIM, GM_TIM, "Genmod TI mode") PORT_CONDITION( "MODE", 0x01, EQUALS, GENMOD ) PORT_CHANGED_MEMBER(GMAPPER_TAG, geneve_mapper_device, gm_changed, 2) + PORT_CONFSETTING( 0x00, DEF_STR( Off )) + PORT_CONFSETTING( GM_TIM, DEF_STR( On )) + +INPUT_PORTS_END + +/**************************************************************************** + CRU handling +*****************************************************************************/ + +#define CRU_CONTROL_BASE 0x1ee0 +#define CRU_SSTEP_BASE 0x13c0 + +WRITE8_MEMBER ( geneve::cruwrite ) +{ + int addroff = offset << 1; + + // Single step + // 13c0 - 13fe: 0001 0011 11xx xxx0 + if ((addroff & 0xffc0) == CRU_SSTEP_BASE) + { + int bit = (addroff & 0x003e)>>1; + if (VERBOSE>0) LOG("geneve: Single step not implemented; bit %d set to %d\n", bit, data); + return; + } + + if ((addroff & 0xffe0) == CRU_CONTROL_BASE) + { + int bit = (addroff & 0x001e)>>1; + switch (bit) + { + case 5: + // No one really cares... + if (VERBOSE>8) LOG("geneve: Set PAL flag = %02x\n", data); + // m_palvideo = (data!=0); + break; + case 7: + // m_capslock = (data!=0); + if (VERBOSE>8) LOG("geneve: Set capslock flag = %02x\n", data); + break; + case 8: + if (VERBOSE>8) LOG("geneve: Set keyboard clock flag = %02x\n", data); + m_keyboard->clock_control((data!=0)? ASSERT_LINE : CLEAR_LINE); + break; + case 9: + if (VERBOSE>8) LOG("geneve: Set keyboard scan flag = %02x\n", data); + m_keyboard->send_scancodes((data!=0)? ASSERT_LINE : CLEAR_LINE); + break; + case 10: + if (VERBOSE>8) LOG("geneve: Geneve mode = %02x\n", data); + m_mapper->set_geneve_mode(data!=0); + break; + case 11: + if (VERBOSE>8) LOG("geneve: Direct mode = %02x\n", data); + m_mapper->set_direct_mode(data!=0); + break; + case 12: + if (VERBOSE>8) LOG("geneve: Cartridge size 8K = %02x\n", data); + m_mapper->set_cartridge_size((data!=0)? 0x2000 : 0x4000); + break; + case 13: + if (VERBOSE>8) LOG("geneve: Cartridge writable 6000 = %02x\n", data); + m_mapper->set_cartridge_writable(0x6000, (data!=0)); + break; + case 14: + if (VERBOSE>8) LOG("geneve: Cartridge writable 7000 = %02x\n", data); + m_mapper->set_cartridge_writable(0x7000, (data!=0)); + break; + case 15: + if (VERBOSE>8) LOG("geneve: Extra wait states = %02x\n", data==0); + m_mapper->set_extra_waitstates(data==0); // let's use the inverse semantics + break; + default: + if (VERBOSE>0) LOG("geneve: set CRU address %04x=%02x ignored\n", addroff, data); + break; + } + } + else + { + m_peribox->cruwrite(addroff, data); + } +} + +READ8_MEMBER( geneve::cruread ) +{ + UINT8 value = 0; + int addroff = offset << 4; + + // Single step + // 13c0 - 13fe: 0001 0011 11xx xxx0 + if ((addroff & 0xffc0) == CRU_SSTEP_BASE) + { + int bit = (addroff & 0x003e)>>1; + if (VERBOSE>0) LOG("geneve: Single step not implemented; attempting to read bit %d\n", bit); + return value; + } + + // TMS9995-internal CRU locations (1ee0-1efe) are handled within the processor + // so we just don't arrive here + + // Propagate the CRU access to external devices + m_peribox->crureadz(addroff, &value); + return value; +} + +/*********************************************************************** + CRU callbacks +***********************************************************************/ + +READ8_MEMBER( geneve::read_by_9901 ) +{ + int answer = 0; + + switch (offset & 0x03) + { + case TMS9901_CB_INT7: + // + // Read pins INT3*-INT7* of Geneve's 9901. + // bit 1: INTA status + // bit 2: INT2 status + // bit 3-7: joystick status + // + // |K|K|K|K|K|I2|I1|C| + // negative logic + if (m_inta==CLEAR_LINE) answer |= 0x02; + if (m_int2==CLEAR_LINE) answer |= 0x04; + answer |= m_joyport->read_port()<<3; + break; + + case TMS9901_INT8_INT15: + // Read pins INT8*-INT15* of Geneve 9901. + // + // bit 0: keyboard interrupt + // bit 1: unused + // bit 2: mouse left button + // (bit 3: clock interrupt) + // bit 4: INTB from PE-bus + // bit 5 & 7: used as output + // bit 6: unused + if (m_keyint==CLEAR_LINE) answer |= 0x01; + if (m_mouse->left_button()==CLEAR_LINE) answer |= 0x04; + // TODO: add clock interrupt + if (m_intb==CLEAR_LINE) answer |= 0x10; + if (m_video_wait==ASSERT_LINE) answer |= 0x20; + // TODO: PAL pin 5 + if (VERBOSE>8) LOG("geneve: INT15-8 = %02x\n", answer); + break; + + case TMS9901_P0_P7: + // Read pins P0-P7 of TMS9901. All pins are configured as outputs, so nothing here. + break; + + case TMS9901_P8_P15: + // Read pins P8-P15 of TMS 9901. + // bit 4: mouse left button + // video wait is an output; no input possible here + if (m_intb==CLEAR_LINE) answer |= 0x04; // mirror from above + // TODO: 0x08 = real-time clock int + if (m_mouse->left_button()==CLEAR_LINE) answer |= 0x10; // mirror from above + if (m_keyint==CLEAR_LINE) answer |= 0x40; + + // Joystick up (mirror of bit 7) + if ((m_joyport->read_port() & 0x10)==0) answer |= 0x80; + break; + } + return answer; +} + +/* + Write PE bus reset line +*/ +WRITE_LINE_MEMBER( geneve::peripheral_bus_reset ) +{ + if (VERBOSE>0) LOG("geneve: peripheral bus reset request; not implemented yet.\n"); +} + +/* + Write VDP reset line +*/ +WRITE_LINE_MEMBER( geneve::VDP_reset ) +{ + if (VERBOSE>0) LOG("geneve: Video reset request; not implemented yet.\n"); +} + +/* + Write joystick select line. 1 selects joystick 1 (pin 7), 0 selects joystick 2 (pin 2) +*/ +WRITE_LINE_MEMBER( geneve::joystick_select ) +{ + m_joyport->write_port((state==ASSERT_LINE)? 1:2); +} + +/* + Write external mem cycles (0=long, 1=short) +*/ +WRITE_LINE_MEMBER( geneve::extbus_wait_states ) +{ + if (VERBOSE>0) LOG("geneve: 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::video_wait_states ) +{ + if (VERBOSE>1) LOG("geneve: 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; +} + +/* + Called by the 9901 core whenever the state of INTREQ and IC0-3 changes. + As with the TI-99/4A, the interrupt level is delivered as the offset, + but again it is ignored. Anyway, the TMS9995 has only two external inputs + (INT1 and INT4). +*/ +WRITE8_MEMBER( geneve::tms9901_interrupt ) +{ + /* INTREQ is connected to INT1. */ + device_execute(m_cpu)->set_input_line(INPUT_LINE_99XX_INT1, data); +} + +/* tms9901 setup */ +const tms9901_interface tms9901_wiring_geneve = +{ + TMS9901_INT1 | TMS9901_INT2 | TMS9901_INT8 | TMS9901_INTB | TMS9901_INTC, /* only input pins whose state is always known */ + + // read handler + DEVCB_DRIVER_MEMBER(geneve, read_by_9901), + + { /* write handlers */ + DEVCB_DRIVER_LINE_MEMBER(geneve, peripheral_bus_reset), + DEVCB_DRIVER_LINE_MEMBER(geneve, VDP_reset), + DEVCB_DRIVER_LINE_MEMBER(geneve, joystick_select), + DEVCB_NULL, + DEVCB_NULL, + DEVCB_NULL, + DEVCB_DEVICE_LINE_MEMBER(GKEYBOARD_TAG, geneve_keyboard_device, reset_line), + DEVCB_DRIVER_LINE_MEMBER(geneve, extbus_wait_states), + DEVCB_NULL, + DEVCB_DRIVER_LINE_MEMBER(geneve, video_wait_states), + DEVCB_NULL, + DEVCB_NULL, + DEVCB_NULL, + DEVCB_NULL, + DEVCB_NULL, + DEVCB_NULL + }, + + /* interrupt handler */ + DEVCB_DRIVER_MEMBER(geneve, tms9901_interrupt) +}; + +/******************************************************************* + Signal lines +*******************************************************************/ +/* + inta is connected to both tms9901 IRQ1 line and to tms9995 INT4/EC line. +*/ +WRITE_LINE_MEMBER( geneve::inta ) +{ + m_inta = (state!=0)? ASSERT_LINE : CLEAR_LINE; + m_tms9901->set_single_int(1, state); + device_execute(m_cpu)->set_input_line(INPUT_LINE_99XX_INT4, state); +} + +/* + intb is connected to tms9901 IRQ12 line. +*/ +WRITE_LINE_MEMBER( geneve::intb ) +{ + m_intb = (state!=0)? ASSERT_LINE : CLEAR_LINE; + m_tms9901->set_single_int(12, state); +} + +WRITE_LINE_MEMBER( geneve::ext_ready ) +{ + if (VERBOSE>6) LOG("ti99_8: READY level (ext) =%02x\n", state); + m_ready_line = state; + m_cpu->set_ready((m_ready_line == ASSERT_LINE && m_ready_line1 == ASSERT_LINE)? ASSERT_LINE : CLEAR_LINE); +} + +WRITE_LINE_MEMBER( geneve::mapper_ready ) +{ + if (VERBOSE>6) LOG("geneve: READY level (mapper) = %02x\n", state); + m_ready_line1 = state; + m_cpu->set_ready((m_ready_line == ASSERT_LINE && m_ready_line1 == ASSERT_LINE)? ASSERT_LINE : CLEAR_LINE); +} + +/* + set the state of int2 (called by the v9938 core) +*/ +void geneve::set_tms9901_INT2_from_v9938(v99x8_device &vdp, int state) +{ + m_int2 = (state!=0)? ASSERT_LINE : CLEAR_LINE; + m_tms9901->set_single_int(2, state); +} + +/* + Interrupt from the keyboard. +*/ +WRITE_LINE_MEMBER( geneve::keyboard_interrupt ) +{ + m_keyint = (state!=0)? ASSERT_LINE : CLEAR_LINE; + m_tms9901->set_single_int(8, state); +} + +/* + scanline interrupt +*/ +TIMER_DEVICE_CALLBACK( geneve_hblank_interrupt ) +{ + int scanline = param; + geneve *driver = timer.machine().driver_data<geneve>(); + + timer.machine().device<v9938_device>(VDP_TAG)->interrupt(); + + if (scanline == 0) // was 262 + { + // TODO + // The technical docs do not say anything about the way the mouse + // is queried. It sounds plausible that the mouse is sampled once + // per vertical interrupt; however, the mouse sometimes shows jerky + // behaviour. Maybe we should use an autonomous timer with a higher + // rate? -> to be checked + driver->m_mouse->poll(); + } +} + +WRITE8_MEMBER( geneve::external_operation ) +{ + static const char* extop[8] = { "inv1", "inv2", "IDLE", "RSET", "inv3", "CKON", "CKOF", "LREX" }; + if (VERBOSE>1) + if (offset != IDLE_OP) LOG("geneve: External operation %s not implemented on Geneve board\n", extop[offset]); +} + +/* + Clock line from the CPU. Used to control wait state generation. +*/ +WRITE_LINE_MEMBER( geneve::clock_out ) +{ + m_mapper->clock_in(state); +} + +static TMS9995_CONFIG( geneve_processor_config ) +{ + DEVCB_DRIVER_MEMBER(geneve, external_operation), + DEVCB_NULL, // Instruction acquisition + DEVCB_DRIVER_LINE_MEMBER(geneve, clock_out), + DEVCB_NULL, // wait + DEVCB_NULL, // HOLDA + INTERNAL_RAM, // use internal RAM + NO_OVERFLOW_INT // The generally available versions of TMS9995 have a deactivated overflow interrupt +}; + +static TI_SOUND_CONFIG( sound_conf ) +{ + DEVCB_DRIVER_LINE_MEMBER(geneve, ext_ready) // READY +}; + +static const mm58274c_interface geneve_mm58274c_interface = +{ + 1, /* mode 24*/ + 0 /* first day of week */ +}; + +static GENEVE_KEYBOARD_CONFIG( geneve_keyb_conf ) +{ + DEVCB_DRIVER_LINE_MEMBER(geneve, keyboard_interrupt) +}; + +static PERIBOX_CONFIG( peribox_conf ) +{ + DEVCB_DRIVER_LINE_MEMBER(geneve, inta), // INTA + DEVCB_DRIVER_LINE_MEMBER(geneve, intb), // INTB + DEVCB_DRIVER_LINE_MEMBER(geneve, ext_ready), // READY + 0x00000 // Address bus prefix (Mapper will produce prefixes) +}; + +static GENEVE_MAPPER_CONFIG( mapper_conf ) +{ + DEVCB_DRIVER_LINE_MEMBER(geneve, mapper_ready) // READY +}; + +static JOYPORT_CONFIG( joyport_60 ) +{ + DEVCB_NULL, + 60 +}; + +DRIVER_INIT_MEMBER(geneve,geneve) +{ +} + +static MACHINE_START( geneve ) +{ + geneve *driver = machine.driver_data<geneve>(); + driver->m_tms9901 = static_cast<tms9901_device*>(machine.device(TMS9901_TAG)); + driver->m_mapper = static_cast<geneve_mapper_device*>(machine.device(GMAPPER_TAG)); + driver->m_keyboard = static_cast<geneve_keyboard_device*>(machine.device(GKEYBOARD_TAG)); + driver->m_peribox = static_cast<peribox_device*>(machine.device(PERIBOX_TAG)); + driver->m_mouse = static_cast<geneve_mouse_device*>(machine.device(GMOUSE_TAG)); + driver->m_cpu = static_cast<tms9995_device*>(machine.device("maincpu")); + driver->m_joyport = static_cast<joyport_device*>(machine.device(JOYPORT_TAG)); +} + +/* + Reset the machine. +*/ +static MACHINE_RESET( geneve ) +{ + geneve *driver = machine.driver_data<geneve>(); + driver->m_inta = CLEAR_LINE; // flag reflecting the INTA line + driver->m_intb = CLEAR_LINE; // flag reflecting the INTB line + driver->m_int2 = CLEAR_LINE; // flag reflecting the INT2 line + driver->m_keyint = CLEAR_LINE; + + // No automatic wait state (auto wait state is enabled with READY=CLEAR at RESET) + driver->m_cpu->set_ready(ASSERT_LINE); + driver->m_cpu->set_hold(CLEAR_LINE); + + driver->m_ready_line = driver->m_ready_line1 = ASSERT_LINE; + + driver->m_peribox->set_genmod(machine.root_device().ioport("MODE")->read()==GENMOD); + + driver->m_joyport->write_port(0x01); // select Joystick 1 +} + +static MACHINE_CONFIG_START( geneve_60hz, geneve ) + // basic machine hardware + // TMS9995 CPU @ 12.0 MHz + MCFG_TMS9995_ADD("maincpu", TMS9995, 12000000, memmap, crumap, geneve_processor_config) + + MCFG_MACHINE_START( geneve ) + MCFG_MACHINE_RESET( geneve ) + + // video hardware + // Although we should have a 60 Hz screen rate, we have to set it to 30 here. + // The reason is that that the number of screen lines is counted twice for the + // interlace mode, but in non-interlace modes only half of the lines are + // painted. Accordingly, the full set of lines is refreshed at 30 Hz, + // not 60 Hz. This should be fixed in the v9938 emulation. + MCFG_TI_V9938_ADD(VIDEO_SYSTEM_TAG, 30, SCREEN_TAG, 2500, 512+32, (212+28)*2, DEVICE_SELF, geneve, set_tms9901_INT2_from_v9938) + MCFG_TIMER_ADD_SCANLINE("scantimer", geneve_hblank_interrupt, SCREEN_TAG, 0, 1) /* 262.5 in 60Hz, 312.5 in 50Hz */ + + // Main board components + MCFG_TMS9901_ADD(TMS9901_TAG, tms9901_wiring_geneve, 3000000) + MCFG_GENEVE_MAPPER_ADD(GMAPPER_TAG, mapper_conf) + MCFG_MM58274C_ADD(GCLOCK_TAG, geneve_mm58274c_interface) + + // Peripheral expansion box (Geneve composition) + MCFG_PERIBOX_GEN_ADD( PERIBOX_TAG, peribox_conf ) + + // sound hardware + MCFG_TI_SOUND_76496_ADD( TISOUND_TAG, sound_conf ) + + // User interface devices + MCFG_GENEVE_KEYBOARD_ADD( GKEYBOARD_TAG, geneve_keyb_conf ) + MCFG_GENEVE_MOUSE_ADD( GMOUSE_TAG ) + MCFG_GENEVE_JOYPORT_ADD( JOYPORT_TAG, joyport_60 ) + +MACHINE_CONFIG_END + +/* + ROM loading +*/ + +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(SRAM_SIZE, SRAM_TAG, 0) + ROM_FILL(0x0000, SRAM_SIZE, 0) + + ROM_REGION(DRAM_SIZE, DRAM_TAG, 0) + ROM_FILL(0x0000, DRAM_SIZE, 0) +ROM_END + +/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */ +COMP( 1987,geneve, 0, 0, geneve_60hz, geneve, geneve, geneve, "Myarc", "Geneve 9640" , 0) |