diff options
Diffstat (limited to 'trunk/src/mame/drivers/saturn.c')
-rw-r--r-- | trunk/src/mame/drivers/saturn.c | 2455 |
1 files changed, 2455 insertions, 0 deletions
diff --git a/trunk/src/mame/drivers/saturn.c b/trunk/src/mame/drivers/saturn.c new file mode 100644 index 00000000000..10f53ba340e --- /dev/null +++ b/trunk/src/mame/drivers/saturn.c @@ -0,0 +1,2455 @@ +/************************************************************************************************** + + Sega Saturn & Sega ST-V (Sega Titan Video) HW (c) 1994 Sega + + Driver by David Haywood, Angelo Salese, Olivier Galibert & Mariusz Wojcieszek + SCSP driver provided by R.Belmont, based on ElSemi's SCSP sound chip emulator + CD Block driver provided by ANY, based on sthief original emulator + Many thanks to Guru, Fabien, Runik and Charles MacDonald for the help given. + +=================================================================================================== + +Notes: +-To enter into an Advanced Test Mode,keep pressed the Test Button (F2) on the start-up. +-Memo: Some tests done on the original & working PCB,to be implemented: + -The AD-Stick returns 0x00 or a similar value. + -The Ports E,F & G must return 0xff + +TODO: +(Main issues) +- decap the SH-1, used for CD block (needed especially for Sega Saturn) +- IRQs: some games have some issues with timing accurate IRQs, check/fix all of them. +- The Cart-Dev mode hangs even with the -dev bios,I would like to see what it does on the real HW. +- IC13 games on the dev bios doesn't even load the cartridge / crashes the emulation at start-up, + rom rearrange needed? +- SCU DSP still has its fair share of issues, it also needs to be converted to CPU structure; +- Add the RS232c interface (serial port),needed by fhboxers. +- Video emulation bugs: check stvvdp2.c file. +- Reimplement the idle skip if possible. +- clean up the I/Os, by using per-game specific mapped ports and rewrite it by using 16-bit trampolines +- Properly emulate the protection chips, used by several games (check stvprot.c for more info) +- Move SCU device into its respective file; +- Split ST-V and Saturn files properly; + +(per-game issues) +- stress: accesses the Sound Memory Expansion Area (0x05a80000-0x05afffff), unknown purpose; +- smleague / finlarch: it randomly hangs / crashes,it works if you use a ridiculous MCFG_INTERLEAVE number,might need strict + SH-2 synching. +- groovef / myfairld: why do we get 2 credits on startup? Cause might be by a communication with the M68k +- myfairld: Apparently this game gives a black screen (either test mode and in-game mode),but let it wait for about + 10 seconds and the game will load everything. This is because of a hellishly slow m68k sub-routine located at 54c2. + Likely to not be a bug but an in-game design issue. +- danchih: hanafuda panel doesn't work. +- findlove: controls doesn't work? Playing with the debugger at location $6063720 it makes it get furter,but controls + still doesn't work, missing irq? +- batmanfr: Missing sound,caused by an extra ADSP chip which is on the cart.The CPU is a + ADSP-2181,and it's the same used by NBA Jam Extreme (ZN game). +- vfremix: when you play as Akira, there is a problem with third match: game doesn't upload all textures + and tiles and doesn't enable display, although gameplay is normal - wait a while to get back + to title screen after losing a match + +=================================================================================================== + +Hardware overview: +------------------ +-two SH-2 CPUs,in a master/slave configuration.The master cpu is used to +boot-up and to do the most of the work,the slave one does extra work that could be +too much for a single cpu.They both shares all the existant devices; +-a M68000 CPU,used to drive sound(the SCSP chip).The program is uploaded via the +SH-2 cpus; +-a SMPC (System Manager & Peripheral Control),used to drive all the +devices on the board; +-a SCU (System Control Unit),mainly used to do DMA operations and to drive interrupts,it +also has a DSP; +-an (optional for the ST-V) SH-1 CPU,used to be the CD driver; +-An A-Bus,where the cart ROM area is located; +-A B-Bus,where the Video Hardware & the SCU sections are located; +-Two VDPs chips(named as 1 & 2),used for the video section: + -VDP1 is used to render sprites & polygons. + -VDP2 is for the tilemap system,there are: + 4 effective normal layers; + 2 roz layers; + 1 back layer; + 1 line layer; + The VDP2 is capable of the following things (in order): + -dynamic resolution (up to 704x512) & various interlacing modes; + -mosaic process; + -scrolling,scaling,horizontal & vertical cell scrolling & linescroll for the + normal planes, the roz ones can also rotate; + -versatile window system,used for various effects; + -alpha-blending,refered as Color Calculation in the docs; + -shadow effects; + -global rgb brightness control,separate for every plane; + +****************************************************************************************************/ + +#include "emu.h" +#include "cpu/m68000/m68000.h" +#include "machine/eeprom.h" +#include "cpu/sh2/sh2.h" +#include "machine/stvcd.h" +#include "machine/scudsp.h" +#include "sound/scsp.h" +#include "sound/cdda.h" +#include "machine/stvprot.h" +#include "machine/smpc.h" +#include "includes/stv.h" +#include "imagedev/chd_cd.h" +#include "imagedev/cartslot.h" +#include "coreutil.h" + + +/* TODO: do this in a verboselog style */ +#define LOG_CDB 0 +#define LOG_SCU 1 +#define LOG_IRQ 0 +#define LOG_IOGA 0 + +static int DectoBCD(int num) +{ + int i, cnt = 0, tmp, res = 0; + + while (num > 0) { + tmp = num; + while (tmp >= 10) tmp %= 10; + for (i=0; i<cnt; i++) + tmp *= 16; + res += tmp; + cnt++; + num /= 10; + } + + return res; +} + +static void scu_do_transfer(running_machine &machine,UINT8 event); +static void scu_dma_direct(address_space *space, UINT8 dma_ch); /*DMA level 0 direct transfer function*/ +static void scu_dma_indirect(address_space *space, UINT8 dma_ch); /*DMA level 0 indirect transfer function*/ + +/**************************************************************************************/ + +/* + +SCU Handling + +*/ + +/********************************************************************************** +SCU Register Table +offset,relative address +Registers are in long words. +=================================================================================== +0 0000 Level 0 DMA Set Register +1 0004 +2 0008 +3 000c +4 0010 +5 0014 +6 0018 +7 001c +8 0020 Level 1 DMA Set Register +9 0024 +10 0028 +11 002c +12 0030 +13 0034 +14 0038 +15 003c +16 0040 Level 2 DMA Set Register +17 0044 +18 0048 +19 004c +20 0050 +21 0054 +22 0058 +23 005c +24 0060 DMA Forced Stop +25 0064 +26 0068 +27 006c +28 0070 <Free> +29 0074 +30 0078 +31 007c DMA Status Register +32 0080 DSP Program Control Port +33 0084 DSP Program RAM Data Port +34 0088 DSP Data RAM Address Port +35 008c DSP Data RAM Data Port +36 0090 Timer 0 Compare Register +37 0094 Timer 1 Set Data Register +38 0098 Timer 1 Mode Register +39 009c <Free> +40 00a0 Interrupt Mask Register +41 00a4 Interrupt Status Register +42 00a8 A-Bus Interrupt Acknowledge +43 00ac <Free> +44 00b0 A-Bus Set Register +45 00b4 +46 00b8 A-Bus Refresh Register +47 00bc <Free> +48 00c0 +49 00c4 SCU SDRAM Select Register +50 00c8 SCU Version Register +51 00cc <Free> +52 00cf +=================================================================================== +DMA Status Register(32-bit): +xxxx xxxx x--- xx-- xx-- xx-- xx-- xx-- UNUSED +---- ---- -x-- ---- ---- ---- ---- ---- DMA DSP-Bus access +---- ---- --x- ---- ---- ---- ---- ---- DMA B-Bus access +---- ---- ---x ---- ---- ---- ---- ---- DMA A-Bus access +---- ---- ---- --x- ---- ---- ---- ---- DMA lv 1 interrupt +---- ---- ---- ---x ---- ---- ---- ---- DMA lv 0 interrupt +---- ---- ---- ---- --x- ---- ---- ---- DMA lv 2 in stand-by +---- ---- ---- ---- ---x ---- ---- ---- DMA lv 2 in operation +---- ---- ---- ---- ---- --x- ---- ---- DMA lv 1 in stand-by +---- ---- ---- ---- ---- ---x ---- ---- DMA lv 1 in operation +---- ---- ---- ---- ---- ---- --x- ---- DMA lv 0 in stand-by +---- ---- ---- ---- ---- ---- ---x ---- DMA lv 0 in operation +---- ---- ---- ---- ---- ---- ---- --x- DSP side DMA in stand-by +---- ---- ---- ---- ---- ---- ---- ---x DSP side DMA in operation + +**********************************************************************************/ +/* +DMA TODO: +-Remove CD transfer DMA hack (tied with CD block bug(s)?) +-Add timings(but how fast are each DMA?). +-Add level priority & DMA status register. +*/ + +#define DIRECT_MODE(_lv_) (!(state->m_scu_regs[5+(_lv_*8)] & 0x01000000)) +#define INDIRECT_MODE(_lv_) (state->m_scu_regs[5+(_lv_*8)] & 0x01000000) +#define DRUP(_lv_) (state->m_scu_regs[5+(_lv_*8)] & 0x00010000) +#define DWUP(_lv_) (state->m_scu_regs[5+(_lv_*8)] & 0x00000100) + +#define DMA_STATUS (state->m_scu_regs[31]) +/*These macros sets the various DMA status flags.*/ +#define DnMV_1(_ch_) DMA_STATUS|=(0x10 << 4 * _ch_) +#define DnMV_0(_ch_) DMA_STATUS&=~(0x10 << 4 * _ch_) + +/*For area checking*/ +#define BIOS_BUS(var) (var & 0x07000000) == 0 +#define ABUS(_lv_) ((state->m_scu.src[_lv_] & 0x07000000) >= 0x02000000) && ((state->m_scu.src[_lv_] & 0x07000000) <= 0x04000000) +#define BBUS(_lv_) ((scu_##_lv_ & 0x07ffffff) >= 0x05a00000) && ((scu_##_lv_ & 0x07ffffff) <= 0x05ffffff) +#define VDP1_REGS(_lv_) ((scu_##_lv_ & 0x07ffffff) >= 0x05d00000) && ((scu_##_lv_ & 0x07ffffff) <= 0x05dfffff) +#define VDP2(_lv_) ((scu_##_lv_ & 0x07ffffff) >= 0x05e00000) && ((scu_##_lv_ & 0x07ffffff) <= 0x05fdffff) +#define WORK_RAM_L(_lv_) ((scu_##_lv_ & 0x07ffffff) >= 0x00200000) && ((scu_##_lv_ & 0x07ffffff) <= 0x002fffff) +#define WORK_RAM_H(var) (var & 0x07000000) == 0x06000000 +#define SOUND_RAM(_lv_) ((scu_##_lv_ & 0x07ffffff) >= 0x05a00000) && ((scu_##_lv_ & 0x07ffffff) <= 0x05afffff) + +static void scu_do_transfer(running_machine &machine,UINT8 event) +{ + saturn_state *state = machine.driver_data<saturn_state>(); + address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM); + int i; + + for(i=0;i<3;i++) + { + if(state->m_scu.enable_mask[i] && state->m_scu.start_factor[i] == event) + { + if(DIRECT_MODE(i)) { scu_dma_direct(space,i); } + else { scu_dma_indirect(space,i); } + } + } +} + +/* test pending irqs */ +static void scu_test_pending_irq(running_machine &machine) +{ + saturn_state *state = machine.driver_data<saturn_state>(); + int i; + const int irq_level[32] = { 0xf, 0xe, 0xd, 0xc, + 0xb, 0xa, 0x9, 0x8, + 0x8, 0x6, 0x6, 0x5, + 0x3, 0x2, -1, -1, + 0x7, 0x7, 0x7, 0x7, + 0x4, 0x4, 0x4, 0x4, + 0x1, 0x1, 0x1, 0x1, + 0x1, 0x1, 0x1, 0x1 }; + + for(i=0;i<32;i++) + { + if((!(state->m_scu.ism & 1 << i)) && (state->m_scu.ist & 1 << i)) + { + if(irq_level[i] != -1) /* TODO: cheap check for undefined irqs */ + { + device_set_input_line_and_vector(state->m_maincpu, irq_level[i], HOLD_LINE, 0x40 + i); + state->m_scu.ist &= ~(1 << i); + return; /* avoid spurious irqs, correct? */ + } + } + } +} + +static READ32_HANDLER( saturn_scu_r ) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + UINT32 res; + + /*TODO: write only registers must return 0 or open bus */ + switch(offset) + { + case 0x5c/4: + // Super Major League and Shin Megami Tensei - Akuma Zensho reads from there (undocumented), DMA status mirror? + if(LOG_SCU) logerror("(PC=%08x) DMA status reg read\n",cpu_get_pc(&space->device())); + res = state->m_scu_regs[0x7c/4]; + break; + case 0x7c/4: + if(LOG_SCU) logerror("(PC=%08x) DMA status reg read\n",cpu_get_pc(&space->device())); + res = state->m_scu_regs[offset]; + break; + case 0x80/4: + res = dsp_prg_ctrl_r(space); + break; + case 0x8c/4: + if(LOG_SCU) logerror( "DSP mem read at %08X\n", state->m_scu_regs[34]); + res = dsp_ram_addr_r(); + break; + case 0xa0/4: + if(LOG_SCU) logerror("(PC=%08x) IRQ mask reg read %08x MASK=%08x\n",cpu_get_pc(&space->device()),mem_mask,state->m_scu_regs[0xa0/4]); + res = state->m_scu.ism; + break; + case 0xa4/4: + if(LOG_SCU) logerror("(PC=%08x) IRQ status reg read %08x MASK=%08x\n",cpu_get_pc(&space->device()),mem_mask,state->m_scu_regs[0xa0/4]); + res = state->m_scu.ist; + break; + case 0xc8/4: + logerror("(PC=%08x) SCU version reg read\n",cpu_get_pc(&space->device())); + res = 0x00000004;/*SCU Version 4, OK? */ + break; + default: + if(LOG_SCU) logerror("(PC=%08x) SCU reg read at %d = %08x\n",cpu_get_pc(&space->device()),offset,state->m_scu_regs[offset]); + res = state->m_scu_regs[offset]; + break; + } + + return res; +} + +#define DMA_CH ((offset & 0x18) / 8) + +static WRITE32_HANDLER( saturn_scu_w ) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + + COMBINE_DATA(&state->m_scu_regs[offset]); + + switch(offset) + { + /*LV 0 DMA*/ + case 0x00/4: case 0x20/4: case 0x40/4: state->m_scu.src[DMA_CH] = ((state->m_scu_regs[offset] & 0x07ffffff) >> 0); break; + case 0x04/4: case 0x24/4: case 0x44/4: state->m_scu.dst[DMA_CH] = ((state->m_scu_regs[offset] & 0x07ffffff) >> 0); break; + case 0x08/4: case 0x28/4: case 0x48/4: state->m_scu.size[DMA_CH] = ((state->m_scu_regs[offset] & ((offset == 2) ? 0x000fffff : 0xfff)) >> 0); break; + case 0x0c/4: case 0x2c/4: case 0x4c/4: + state->m_scu.src_add[DMA_CH] = (state->m_scu_regs[offset] & 0x100) ? 4 : 0; + state->m_scu.dst_add[DMA_CH] = 1 << (state->m_scu_regs[offset] & 7); + if(state->m_scu.dst_add[DMA_CH] == 1) { state->m_scu.dst_add[DMA_CH] = 0; } + break; + case 0x10/4: case 0x30/4: case 0x50/4: + state->m_scu.enable_mask[DMA_CH] = (data & 0x100) >> 8; + if(state->m_scu.enable_mask[DMA_CH] && state->m_scu.start_factor[DMA_CH] == 7 && state->m_scu_regs[offset] & 1) + { + if(DIRECT_MODE(DMA_CH)) { scu_dma_direct(space,DMA_CH); } + else { scu_dma_indirect(space,DMA_CH); } + state->m_scu_regs[offset]&=~1;//disable starting bit. + } + break; + case 0x14/4: case 0x34/4: case 0x54/4: + if(INDIRECT_MODE(DMA_CH)) + { + //if(LOG_SCU) logerror("Indirect Mode DMA lv %d set\n",DMA_CH); + if(!DWUP(DMA_CH)) state->m_scu.index[DMA_CH] = state->m_scu.dst[DMA_CH]; + } + + state->m_scu.start_factor[DMA_CH] = state->m_scu_regs[offset] & 7; + break; + + case 0x60/4: + if(LOG_SCU) logerror("DMA Forced Stop Register set = %02x\n",state->m_scu_regs[24]); + break; + case 0x7c/4: if(LOG_SCU) logerror("Warning: DMA status WRITE! Offset %02x(%d)\n",offset*4,offset); break; + /*DSP section*/ + case 0x80/4: + /* TODO: you can't overwrite some flags with this */ + dsp_prg_ctrl_w(space, state->m_scu_regs[offset]); + if(LOG_SCU) logerror("SCU DSP: Program Control Port Access %08x\n",data); + break; + case 0x84/4: + dsp_prg_data(state->m_scu_regs[offset]); + if(LOG_SCU) logerror("SCU DSP: Program RAM Data Port Access %08x\n",data); + break; + case 0x88/4: + dsp_ram_addr_ctrl(state->m_scu_regs[offset]); + if(LOG_SCU) logerror("SCU DSP: Data RAM Address Port Access %08x\n",data); + break; + case 0x8c/4: + dsp_ram_addr_w(state->m_scu_regs[offset]); + if(LOG_SCU) logerror("SCU DSP: Data RAM Data Port Access %08x\n",data); + break; + case 0x90/4: /*if(LOG_SCU) logerror("timer 0 compare data = %03x\n",state->m_scu_regs[36]);*/ break; + case 0x94/4: /*if(LOG_SCU) logerror("timer 1 set data = %08x\n",state->m_scu_regs[37]);*/ break; + case 0x98/4: /*if(LOG_SCU) logerror("timer 1 mode data = %08x\n",state->m_scu_regs[38]);*/ break; + case 0xa0/4: /* IRQ mask */ + state->m_scu.ism = state->m_scu_regs[0xa0/4]; + scu_test_pending_irq(space->machine()); + break; + case 0xa4/4: /* IRQ control */ + if(LOG_SCU) logerror("PC=%08x IRQ status reg set:%08x %08x\n",cpu_get_pc(&space->device()),state->m_scu_regs[41],mem_mask); + state->m_scu.ist &= state->m_scu_regs[offset]; + break; + case 0xa8/4: if(LOG_SCU) logerror("A-Bus IRQ ACK %08x\n",state->m_scu_regs[42]); break; + case 0xc4/4: if(LOG_SCU) logerror("SCU SDRAM set: %02x\n",state->m_scu_regs[49]); break; + default: if(LOG_SCU) logerror("Warning: unused SCU reg set %d = %08x\n",offset,data); + } +} + +/*Lv 0 DMA end irq*/ +static TIMER_CALLBACK( dma_lv0_ended ) +{ + saturn_state *state = machine.driver_data<saturn_state>(); + + if(!(state->m_scu.ism & IRQ_DMALV0)) + device_set_input_line_and_vector(state->m_maincpu, 5, HOLD_LINE, 0x4b); + else + state->m_scu.ist |= (IRQ_DMALV0); + + DnMV_0(0); +} + +/*Lv 1 DMA end irq*/ +static TIMER_CALLBACK( dma_lv1_ended ) +{ + saturn_state *state = machine.driver_data<saturn_state>(); + + if(!(state->m_scu.ism & IRQ_DMALV1)) + device_set_input_line_and_vector(state->m_maincpu, 6, HOLD_LINE, 0x4a); + else + state->m_scu.ist |= (IRQ_DMALV1); + + DnMV_0(1); +} + +/*Lv 2 DMA end irq*/ +static TIMER_CALLBACK( dma_lv2_ended ) +{ + saturn_state *state = machine.driver_data<saturn_state>(); + + if(!(state->m_scu.ism & IRQ_DMALV2)) + device_set_input_line_and_vector(state->m_maincpu, 6, HOLD_LINE, 0x49); + else + state->m_scu.ist |= (IRQ_DMALV2); + + DnMV_0(2); +} + +static void scu_single_transfer(address_space *space, UINT32 src, UINT32 dst,UINT8 *src_shift) +{ + UINT32 src_data; + + if(src & 1) + { + /* Road Blaster does a work ram h to color ram with offsetted source address, do some data rotation */ + src_data = ((space->read_dword(src & 0x07fffffc) & 0x00ffffff)<<8); + src_data |= ((space->read_dword((src & 0x07fffffc)+4) & 0xff000000) >> 24); + src_data >>= (*src_shift)*16; + } + else + src_data = space->read_dword(src & 0x07fffffc) >> (*src_shift)*16; + + space->write_word(dst,src_data); + + *src_shift ^= 1; +} + +static void scu_dma_direct(address_space *space, UINT8 dma_ch) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + UINT32 tmp_src,tmp_dst,tmp_size; + UINT8 cd_transfer_flag; + + if(state->m_scu.src_add[dma_ch] == 0 || (state->m_scu.dst_add[dma_ch] != 2 && state->m_scu.dst_add[dma_ch] != 4)) + { + if(LOG_SCU) printf("DMA lv %d transfer START\n" + "Start %08x End %08x Size %04x\n",dma_ch,state->m_scu.src[dma_ch],state->m_scu.dst[dma_ch],state->m_scu.size[dma_ch]); + if(LOG_SCU) printf("Start Add %04x Destination Add %04x\n",state->m_scu.src_add[dma_ch],state->m_scu.dst_add[dma_ch]); + } + + /* TODO: Game Basic trips this, bogus transfer from BIOS area to VDP1? */ + if(BIOS_BUS(state->m_scu.src[dma_ch])) + popmessage("Warning: SCU transfer from BIOS area, contact MAMEdev"); + + DnMV_1(dma_ch); + + /* max size */ + if(state->m_scu.size[dma_ch] == 0) { state->m_scu.size[dma_ch] = (dma_ch == 0) ? 0x00100000 : 0x1000; } + + tmp_src = tmp_dst = 0; + + tmp_size = state->m_scu.size[dma_ch]; + if(!(DRUP(dma_ch))) tmp_src = state->m_scu.src[dma_ch]; + if(!(DWUP(dma_ch))) tmp_dst = state->m_scu.dst[dma_ch]; + + cd_transfer_flag = state->m_scu.src_add[dma_ch] == 0 && state->m_scu.src[dma_ch] == 0x05818000; + + /* TODO: Many games directly accesses CD-ROM register 0x05818000, it must be a dword access with current implementation otherwise it won't work */ + if(cd_transfer_flag) + { + int i; + if(WORK_RAM_H(state->m_scu.dst[dma_ch])) + state->m_scu.dst_add[dma_ch] = 4; + else + state->m_scu.dst_add[dma_ch] <<= 1; + + for (i = 0; i < state->m_scu.size[dma_ch];i+=state->m_scu.dst_add[dma_ch]) + { + space->write_dword(state->m_scu.dst[dma_ch],space->read_dword(state->m_scu.src[dma_ch])); + if(state->m_scu.dst_add[dma_ch] == 8) + space->write_dword(state->m_scu.dst[dma_ch]+4,space->read_dword(state->m_scu.src[dma_ch])); + + state->m_scu.src[dma_ch]+=state->m_scu.src_add[dma_ch]; + state->m_scu.dst[dma_ch]+=state->m_scu.dst_add[dma_ch]; + } + } + else + { + int i; + UINT8 src_shift; + + src_shift = ((state->m_scu.src[dma_ch] & 2) >> 1) ^ 1; + + for (i = 0; i < state->m_scu.size[dma_ch];i+=2) + { + scu_single_transfer(space,state->m_scu.src[dma_ch],state->m_scu.dst[dma_ch],&src_shift); + + if(src_shift) + state->m_scu.src[dma_ch]+=state->m_scu.src_add[dma_ch]; + + /* if target is Work RAM H, the add value is fixed, behaviour confirmed by Final Romance 2, Virtual Mahjong and Burning Rangers */ + state->m_scu.dst[dma_ch]+=(WORK_RAM_H(state->m_scu.dst[dma_ch])) ? 2 : state->m_scu.dst_add[dma_ch]; + } + } + + state->m_scu.size[dma_ch] = tmp_size; + if(!(DRUP(dma_ch))) state->m_scu.src[dma_ch] = tmp_src; + if(!(DWUP(dma_ch))) state->m_scu.dst[dma_ch] = tmp_dst; + + { + /*TODO: this is completely wrong HW-wise ... */ + switch(dma_ch) + { + case 0: space->machine().scheduler().timer_set(attotime::from_usec(300), FUNC(dma_lv0_ended)); break; + case 1: space->machine().scheduler().timer_set(attotime::from_usec(300), FUNC(dma_lv1_ended)); break; + case 2: space->machine().scheduler().timer_set(attotime::from_usec(300), FUNC(dma_lv2_ended)); break; + } + } +} + +static void scu_dma_indirect(address_space *space,UINT8 dma_ch) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + + /*Helper to get out of the cycle*/ + UINT8 job_done = 0; + /*temporary storage for the transfer data*/ + UINT32 tmp_src; + UINT32 indirect_src,indirect_dst; + INT32 indirect_size; + + DnMV_1(dma_ch); + + state->m_scu.index[dma_ch] = state->m_scu.dst[dma_ch]; + + do{ + tmp_src = state->m_scu.index[dma_ch]; + + indirect_size = space->read_dword(state->m_scu.index[dma_ch]); + indirect_src = space->read_dword(state->m_scu.index[dma_ch]+8); + indirect_dst = space->read_dword(state->m_scu.index[dma_ch]+4); + + /*Indirect Mode end factor*/ + if(indirect_src & 0x80000000) + job_done = 1; + + if(state->m_scu.src_add[dma_ch] == 0 || (state->m_scu.dst_add[dma_ch] != 2)) + { + if(LOG_SCU) printf("DMA lv %d indirect mode transfer START\n" + "Index %08x Start %08x End %08x Size %04x\n",dma_ch,tmp_src,indirect_src,indirect_dst,indirect_size); + if(LOG_SCU) printf("Start Add %04x Destination Add %04x\n",state->m_scu.src_add[dma_ch],state->m_scu.dst_add[dma_ch]); + } + + indirect_src &=0x07ffffff; + indirect_dst &=0x07ffffff; + indirect_size &= ((dma_ch == 0) ? 0xfffff : 0x3ffff); //TODO: Guardian Heroes sets up a 0x23000 transfer for the FMV? + + if(indirect_size == 0) { indirect_size = (dma_ch == 0) ? 0x00100000 : 0x2000; } + + { + int i; + UINT8 src_shift; + + src_shift = ((indirect_src & 2) >> 1) ^ 1; + + for (i = 0; i < indirect_size;i+=2) + { + scu_single_transfer(space,indirect_src,indirect_dst,&src_shift); + + if(src_shift) + indirect_src+=state->m_scu.src_add[dma_ch]; + + indirect_dst+= (WORK_RAM_H(indirect_dst)) ? 2 : state->m_scu.dst_add[dma_ch]; + } + } + + //if(DRUP(0)) space->write_dword(tmp_src+8,state->m_scu.src[0]|job_done ? 0x80000000 : 0); + //if(DWUP(0)) space->write_dword(tmp_src+4,state->m_scu.dst[0]); + + state->m_scu.index[dma_ch] = tmp_src+0xc; + + }while(job_done == 0); + + { + /*TODO: this is completely wrong HW-wise ... */ + switch(dma_ch) + { + case 0: space->machine().scheduler().timer_set(attotime::from_usec(300), FUNC(dma_lv0_ended)); break; + case 1: space->machine().scheduler().timer_set(attotime::from_usec(300), FUNC(dma_lv1_ended)); break; + case 2: space->machine().scheduler().timer_set(attotime::from_usec(300), FUNC(dma_lv2_ended)); break; + } + } +} + + +/**************************************************************************************/ + +static WRITE16_HANDLER( saturn_soundram_w ) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + + //space->machine().scheduler().synchronize(); // force resync + + COMBINE_DATA(&state->m_sound_ram[offset]); +} + +static READ16_HANDLER( saturn_soundram_r ) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + + //space->machine().scheduler().synchronize(); // force resync + + return state->m_sound_ram[offset]; +} + +/* communication,SLAVE CPU acquires data from the MASTER CPU and triggers an irq. */ +static WRITE32_HANDLER( minit_w ) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + + //logerror("cpu %s (PC=%08X) MINIT write = %08x\n", space->device().tag(), cpu_get_pc(&space->device()),data); + space->machine().scheduler().boost_interleave(state->m_minit_boost_timeslice, attotime::from_usec(state->m_minit_boost)); + space->machine().scheduler().trigger(1000); + sh2_set_frt_input(state->m_slave, PULSE_LINE); +} + +static WRITE32_HANDLER( sinit_w ) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + + //logerror("cpu %s (PC=%08X) SINIT write = %08x\n", space->device().tag(), cpu_get_pc(&space->device()),data); + space->machine().scheduler().boost_interleave(state->m_sinit_boost_timeslice, attotime::from_usec(state->m_sinit_boost)); + sh2_set_frt_input(state->m_maincpu, PULSE_LINE); +} + +static READ8_HANDLER(saturn_backupram_r) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + + if(!(offset & 1)) + return 0; // yes, it makes sure the "holes" are there. + + return state->m_backupram[offset >> 1] & 0xff; +} + +static WRITE8_HANDLER(saturn_backupram_w) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + + if(!(offset & 1)) + return; + + state->m_backupram[offset >> 1] = data; +} + +/* TODO: if you change the driver configuration then NVRAM contents gets screwed, needs mods in MAME framework */ +static NVRAM_HANDLER(saturn) +{ + saturn_state *state = machine.driver_data<saturn_state>(); + static const UINT32 BUP_SIZE = 32*1024; + static const UINT32 EBUP_SIZE = 0;//0x100000; // TODO: can't support more than 8 Mbit + UINT8 backup_file[(BUP_SIZE)+EBUP_SIZE+4]; + static const UINT8 init[16] = + { + 'B', 'a', 'c', 'k', 'U', 'p', 'R', 'a', 'm', ' ', 'F', 'o', 'r', 'm', 'a', 't' + }; + UINT32 i; + + if (read_or_write) + { + for(i=0;i<BUP_SIZE;i++) + backup_file[i] = state->m_backupram[i]; + #if 0 + for(i=0;i<EBUP_SIZE;i++) + backup_file[i+BUP_SIZE] = state->m_cart_backupram[i]; + #endif + for(i=0;i<4;i++) + backup_file[i+(BUP_SIZE)+EBUP_SIZE] = state->m_smpc.SMEM[i]; + + file->write(backup_file, (BUP_SIZE)+EBUP_SIZE+4); + } + else + { + if (file) + { + file->read(backup_file, (BUP_SIZE)+EBUP_SIZE+4); + + for(i=0;i<BUP_SIZE;i++) + state->m_backupram[i] = backup_file[i]; + #if 0 + for(i=0;i<EBUP_SIZE;i++) + state->m_cart_backupram[i] = backup_file[i+BUP_SIZE]; + #endif + for(i=0;i<4;i++) + state->m_smpc.SMEM[i] = backup_file[i+BUP_SIZE+EBUP_SIZE]; + } + else + { + UINT8 j; + memset(state->m_backupram, 0, BUP_SIZE); + for (i = 0; i < 4; i++) + { + for(j=0;j<16;j++) + state->m_backupram[i*16+j] = init[j]; + } + #if 0 + memset(state->m_cart_backupram, 0, EBUP_SIZE); + for (i = 0; i < 32; i++) + { + for(j=0;j<16;j++) + state->m_cart_backupram[i*16+j] = init[j]; + } + #endif + memset(state->m_smpc.SMEM, 0, 4); // TODO: default for each region + } + } +} + +static READ8_HANDLER( saturn_cart_type_r ) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + const int cart_ram_header[7] = { 0xff, 0x21, 0x22, 0x23, 0x24, 0x5a, 0x5c }; + + return cart_ram_header[state->m_cart_type]; +} + +static ADDRESS_MAP_START( saturn_mem, AS_PROGRAM, 32 ) + AM_RANGE(0x00000000, 0x0007ffff) AM_ROM AM_SHARE("share6") // bios + AM_RANGE(0x00100000, 0x0010007f) AM_READWRITE8(saturn_SMPC_r, saturn_SMPC_w,0xffffffff) + AM_RANGE(0x00180000, 0x0018ffff) AM_READWRITE8(saturn_backupram_r, saturn_backupram_w,0xffffffff) AM_SHARE("share1") + AM_RANGE(0x00200000, 0x002fffff) AM_RAM AM_MIRROR(0x20100000) AM_SHARE("share2") AM_BASE_MEMBER(saturn_state,m_workram_l) + AM_RANGE(0x01000000, 0x017fffff) AM_WRITE(minit_w) + AM_RANGE(0x01800000, 0x01ffffff) AM_WRITE(sinit_w) + AM_RANGE(0x02000000, 0x023fffff) AM_ROM AM_SHARE("share7") AM_REGION("maincpu", 0x80000) // cartridge space +// AM_RANGE(0x02400000, 0x027fffff) AM_RAM //cart RAM area, dynamically allocated +// AM_RANGE(0x04000000, 0x047fffff) AM_RAM //backup RAM area, dynamically allocated + AM_RANGE(0x04fffffc, 0x04ffffff) AM_READ8(saturn_cart_type_r,0x000000ff) + AM_RANGE(0x05800000, 0x0589ffff) AM_READWRITE(stvcd_r, stvcd_w) + /* Sound */ + AM_RANGE(0x05a00000, 0x05a7ffff) AM_READWRITE16(saturn_soundram_r, saturn_soundram_w,0xffffffff) + AM_RANGE(0x05b00000, 0x05b00fff) AM_DEVREADWRITE16("scsp", scsp_r, scsp_w, 0xffffffff) + /* VDP1 */ + AM_RANGE(0x05c00000, 0x05c7ffff) AM_READWRITE(saturn_vdp1_vram_r, saturn_vdp1_vram_w) + AM_RANGE(0x05c80000, 0x05cbffff) AM_READWRITE(saturn_vdp1_framebuffer0_r, saturn_vdp1_framebuffer0_w) + AM_RANGE(0x05d00000, 0x05d0001f) AM_READWRITE16(saturn_vdp1_regs_r, saturn_vdp1_regs_w,0xffffffff) + AM_RANGE(0x05e00000, 0x05efffff) AM_READWRITE(saturn_vdp2_vram_r, saturn_vdp2_vram_w) + AM_RANGE(0x05f00000, 0x05f7ffff) AM_READWRITE(saturn_vdp2_cram_r, saturn_vdp2_cram_w) + AM_RANGE(0x05f80000, 0x05fbffff) AM_READWRITE16(saturn_vdp2_regs_r, saturn_vdp2_regs_w,0xffffffff) + AM_RANGE(0x05fe0000, 0x05fe00cf) AM_READWRITE(saturn_scu_r, saturn_scu_w) + AM_RANGE(0x06000000, 0x060fffff) AM_RAM AM_MIRROR(0x21f00000) AM_SHARE("share3") AM_BASE_MEMBER(saturn_state,m_workram_h) + AM_RANGE(0x20000000, 0x2007ffff) AM_ROM AM_SHARE("share6") // bios mirror + AM_RANGE(0x22000000, 0x24ffffff) AM_ROM AM_SHARE("share7") // cart mirror + AM_RANGE(0x45000000, 0x46ffffff) AM_WRITENOP + AM_RANGE(0xc0000000, 0xc00007ff) AM_RAM // cache RAM, Dragon Ball Z sprites needs this +ADDRESS_MAP_END + +static ADDRESS_MAP_START( stv_mem, AS_PROGRAM, 32 ) + AM_RANGE(0x00000000, 0x0007ffff) AM_ROM AM_SHARE("share6") // bios + AM_RANGE(0x00100000, 0x0010007f) AM_READWRITE8(stv_SMPC_r, stv_SMPC_w,0xffffffff) + AM_RANGE(0x00180000, 0x0018ffff) AM_READWRITE8(saturn_backupram_r,saturn_backupram_w,0xffffffff) AM_SHARE("share1") + AM_RANGE(0x00200000, 0x002fffff) AM_RAM AM_MIRROR(0x20100000) AM_SHARE("share2") AM_BASE_MEMBER(saturn_state,m_workram_l) +// AM_RANGE(0x00400000, 0x0040001f) AM_READWRITE(stv_ioga_r32, stv_io_w32) AM_BASE_MEMBER(saturn_state,m_ioga) AM_SHARE("share4") AM_MIRROR(0x20) /* installed with per-game specific */ + AM_RANGE(0x01000000, 0x017fffff) AM_WRITE(minit_w) + AM_RANGE(0x01800000, 0x01ffffff) AM_WRITE(sinit_w) + AM_RANGE(0x02000000, 0x04ffffff) AM_ROM AM_SHARE("share7") AM_REGION("abus", 0) // cartridge + AM_RANGE(0x05800000, 0x0589ffff) AM_READWRITE(stvcd_r, stvcd_w) + /* Sound */ + AM_RANGE(0x05a00000, 0x05afffff) AM_READWRITE16(saturn_soundram_r, saturn_soundram_w,0xffffffff) + AM_RANGE(0x05b00000, 0x05b00fff) AM_DEVREADWRITE16("scsp", scsp_r, scsp_w, 0xffffffff) + /* VDP1 */ + AM_RANGE(0x05c00000, 0x05c7ffff) AM_READWRITE(saturn_vdp1_vram_r, saturn_vdp1_vram_w) + AM_RANGE(0x05c80000, 0x05cbffff) AM_READWRITE(saturn_vdp1_framebuffer0_r, saturn_vdp1_framebuffer0_w) + AM_RANGE(0x05d00000, 0x05d0001f) AM_READWRITE16(saturn_vdp1_regs_r, saturn_vdp1_regs_w,0xffffffff) + AM_RANGE(0x05e00000, 0x05efffff) AM_READWRITE(saturn_vdp2_vram_r, saturn_vdp2_vram_w) + AM_RANGE(0x05f00000, 0x05f7ffff) AM_READWRITE(saturn_vdp2_cram_r, saturn_vdp2_cram_w) + AM_RANGE(0x05f80000, 0x05fbffff) AM_READWRITE16(saturn_vdp2_regs_r, saturn_vdp2_regs_w,0xffffffff) + AM_RANGE(0x05fe0000, 0x05fe00cf) AM_READWRITE(saturn_scu_r, saturn_scu_w) + AM_RANGE(0x06000000, 0x060fffff) AM_RAM AM_MIRROR(0x21f00000) AM_SHARE("share3") AM_BASE_MEMBER(saturn_state,m_workram_h) + AM_RANGE(0x20000000, 0x2007ffff) AM_ROM AM_SHARE("share6") // bios mirror + AM_RANGE(0x22000000, 0x24ffffff) AM_ROM AM_SHARE("share7") // cart mirror + AM_RANGE(0xc0000000, 0xc00007ff) AM_RAM // cache RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( sound_mem, AS_PROGRAM, 16 ) + AM_RANGE(0x000000, 0x0fffff) AM_RAM AM_BASE_MEMBER(saturn_state,m_sound_ram) + AM_RANGE(0x100000, 0x100fff) AM_DEVREADWRITE("scsp", scsp_r, scsp_w) +ADDRESS_MAP_END + + +/* keyboard code */ +/* TODO: needs a proper keycode table */ +static INPUT_CHANGED( key_stroke ) +{ + saturn_state *state = field.machine().driver_data<saturn_state>(); + + if(newval && !oldval) + { + state->m_keyb.data = ((UINT8)(FPTR)(param) & 0xff); + state->m_keyb.status |= 8; + } + + if(oldval && !newval) + { + //state->m_keyb.status &= ~8; + state->m_keyb.data = 0; + } +} + +#define SATURN_PAD_P1(_mask_, _val_) \ + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 A") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P1 C") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P1 B") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("P1 R") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P1 X") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P1 Y") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P1 Z") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("P1 L") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0007, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) //read '1' when direct mode is polled + +#define SATURN_PAD_P2(_mask_, _val_) \ + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P2 A") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P2 C") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P2 B") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("P2 R") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P2 X") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P2 Y") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P2 Z") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("P2 L") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0007, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) //read '1' when direct mode is polled + +#define MD_PAD_P1(_mask_, _val_) \ + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 A") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P1 C") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P1 B") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("P1 Mode") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P1 X") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P1 Y") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P1 Z") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x000f, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) //read '1' when direct mode is polled + +#define MD_PAD_P2(_mask_, _val_) \ + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P2 A") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P2 C") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P2 B") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("P2 Mode") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P2 X") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P2 Y") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P2 Z") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) \ + PORT_BIT( 0x000f, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("INPUT_TYPE", _mask_, PORTCOND_EQUALS, _val_) //read '1' when direct mode is polled + +#define SATURN_KEYBOARD PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x05) + +static INPUT_CHANGED( nmi_reset ) +{ + saturn_state *state = field.machine().driver_data<saturn_state>(); + + /* TODO: correct? */ + if(!state->m_NMI_reset) + return; + + /* TODO: NMI doesn't stay held on SH-2 core so we can't use ASSERT_LINE/CLEAR_LINE with that yet */ + if(newval) + device_set_input_line(state->m_maincpu, INPUT_LINE_NMI, PULSE_LINE); +} + +static INPUT_CHANGED( tray_open ) +{ + if(newval) + stvcd_set_tray_open(field.machine()); +} + +static INPUT_CHANGED( tray_close ) +{ + if(newval) + stvcd_set_tray_close(field.machine()); +} + +static INPUT_PORTS_START( saturn ) + PORT_START("RESET") /* hardwired buttons */ + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_CHANGED(nmi_reset,0) PORT_NAME("Reset Button") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_CHANGED(tray_open,0) PORT_NAME("Tray Open Button") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_CHANGED(tray_close,0) PORT_NAME("Tray Close") + + PORT_START("JOY1") + SATURN_PAD_P1(0x0f, 0) + + PORT_START("JOY2") + SATURN_PAD_P2(0xf0, 0) + + /* TODO: there's no info about the keycode used on Saturn keyboard, following is trial & error with Game Basic software */ + PORT_START("KEY0") // 0x00 - 0x07 + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_UNUSED) SATURN_KEYBOARD + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F1") /*PORT_CODE(KEYCODE_F1)*/ PORT_CHANGED(key_stroke, 0x01) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("0-3") /*PORT_CODE(KEYCODE_2) PORT_CHAR('2')*/ PORT_CHANGED(key_stroke, 0x02) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F2") /*PORT_CODE(KEYCODE_F2)*/ PORT_CHANGED(key_stroke, 0x03) PORT_PLAYER(1) SATURN_KEYBOARD // RUN + PORT_BIT(0x10,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F3") /*PORT_CODE(KEYCODE_F3)*/ PORT_CHANGED(key_stroke, 0x04) PORT_PLAYER(1) SATURN_KEYBOARD // LIST + PORT_BIT(0x20,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F4") /*PORT_CODE(KEYCODE_F4)*/ PORT_CHANGED(key_stroke, 0x05) PORT_PLAYER(1) SATURN_KEYBOARD // EDIT + PORT_BIT(0x40,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F5") /*PORT_CODE(KEYCODE_F5)*/ PORT_CHANGED(key_stroke, 0x06) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x80,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("CLR SCR") PORT_CHANGED(key_stroke, 0x07) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_START("KEY1") // 0x08 - 0x0f + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("1-1") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x08) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F6") /*PORT_CODE(KEYCODE_F6)*/ PORT_CHANGED(key_stroke, 0x09) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F7") /*PORT_CODE(KEYCODE_F7)*/ PORT_CHANGED(key_stroke, 0x0a) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F8") /*PORT_CODE(KEYCODE_F8)*/ PORT_CHANGED(key_stroke, 0x0b) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x10,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F9") /*PORT_CODE(KEYCODE_F9)*/ PORT_CHANGED(key_stroke, 0x0c) PORT_PLAYER(1) SATURN_KEYBOARD // LIST again + PORT_BIT(0x20,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("1-6") /*PORT_CODE(KEYCODE_5) PORT_CHAR('5')*/ PORT_CHANGED(key_stroke, 0x0d) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x40,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("1-7") /*PORT_CODE(KEYCODE_6) PORT_CHAR('6')*/ PORT_CHANGED(key_stroke, 0x0e) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x80,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("1-8") /*PORT_CODE(KEYCODE_7) PORT_CHAR('7')*/ PORT_CHANGED(key_stroke, 0x0f) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_START("KEY2") // 0x10 - 0x17 + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("2-1") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x10) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("2-2") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x11) PORT_PLAYER(1) SATURN_KEYBOARD + /* TODO: break codes! */ + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("SHIFT") /*PORT_CODE(KEYCODE_2) PORT_CHAR('2')*/ PORT_CHANGED(key_stroke, 0x12) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("KANA SHIFT") /*PORT_CODE(KEYCODE_3) PORT_CHAR('3')*/ PORT_CHANGED(key_stroke, 0x13) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x10,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("(special keys)") /*PORT_CODE(KEYCODE_4) PORT_CHAR('4')*/ PORT_CHANGED(key_stroke, 0x14) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_BIT(0x20,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') PORT_CHANGED(key_stroke, 0x15) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x40,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("1") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHANGED(key_stroke, 0x16) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x80,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("2-8") /*PORT_CODE(KEYCODE_7) PORT_CHAR('7')*/ PORT_CHANGED(key_stroke, 0x17) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_START("KEY3") // 0x18 - 0x1f + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("3-1") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x18) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("3-2") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x19) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') PORT_CHANGED(key_stroke, 0x1a) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) PORT_CHAR('S') PORT_CHANGED(key_stroke, 0x1b) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x10,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) PORT_CHAR('A') PORT_CHANGED(key_stroke, 0x1c) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x20,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) PORT_CHAR('W') PORT_CHANGED(key_stroke, 0x1d) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x40,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("2") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHANGED(key_stroke, 0x1e) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x80,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("3-8") /*PORT_CODE(KEYCODE_7) PORT_CHAR('7')*/ PORT_CHANGED(key_stroke, 0x1f) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_START("KEY4") // 0x20 - 0x27 + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("4-1") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x20) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) PORT_CHAR('C') PORT_CHANGED(key_stroke, 0x21) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) PORT_CHAR('X') PORT_CHANGED(key_stroke, 0x22) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) PORT_CHAR('D') PORT_CHANGED(key_stroke, 0x23) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x10,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) PORT_CHAR('E') PORT_CHANGED(key_stroke, 0x24) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x20,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("4") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHANGED(key_stroke, 0x25) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x40,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("3") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHANGED(key_stroke, 0x26) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x80,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("4-8") /*PORT_CODE(KEYCODE_7) PORT_CHAR('7')*/ PORT_CHANGED(key_stroke, 0x27) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_START("KEY5") // 0x28 - 0x2f + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("5-1") /*PORT_CODE(KEYCODE_F) PORT_CHAR('F')*/ PORT_CHANGED(key_stroke, 0x28) PORT_PLAYER(1) SATURN_KEYBOARD // another F? + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') PORT_CHANGED(key_stroke, 0x29) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) PORT_CHAR('V') PORT_CHANGED(key_stroke, 0x2a) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) PORT_CHAR('F') PORT_CHANGED(key_stroke, 0x2b) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x10,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) PORT_CHAR('T') PORT_CHANGED(key_stroke, 0x2c) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x20,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) PORT_CHAR('R') PORT_CHANGED(key_stroke, 0x2d) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x40,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("5") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHANGED(key_stroke, 0x2e) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x80,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("5-8") /*PORT_CODE(KEYCODE_7) PORT_CHAR('7')*/ PORT_CHANGED(key_stroke, 0x2f) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_START("KEY6") // 0x30 - 0x37 + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("6-1") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x30) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) PORT_CHAR('N') PORT_CHANGED(key_stroke, 0x31) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) PORT_CHAR('B') PORT_CHANGED(key_stroke, 0x32) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) PORT_CHAR('H') PORT_CHANGED(key_stroke, 0x33) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x10,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) PORT_CHAR('G') PORT_CHANGED(key_stroke, 0x34) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x20,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') PORT_CHANGED(key_stroke, 0x35) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x40,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("6") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHANGED(key_stroke, 0x36) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x80,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("6-8") /*PORT_CODE(KEYCODE_7) PORT_CHAR('7')*/ PORT_CHANGED(key_stroke, 0x37) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_START("KEY7") // 0x38 - 0x3f + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("7-1") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x38) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("7-2") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x39) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) PORT_CHAR('M') PORT_CHANGED(key_stroke, 0x3a) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) PORT_CHAR('J') PORT_CHANGED(key_stroke, 0x3b) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x10,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) PORT_CHAR('U') PORT_CHANGED(key_stroke, 0x3c) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x20,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("7") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHANGED(key_stroke, 0x3d) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x40,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("8") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHANGED(key_stroke, 0x3e) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x80,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("7-8") /*PORT_CODE(KEYCODE_7) PORT_CHAR('7')*/ PORT_CHANGED(key_stroke, 0x3f) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_START("KEY8") // 0x40 - 0x47 + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("8-1") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x40) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(",") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x41) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) PORT_CHAR('K') PORT_CHANGED(key_stroke, 0x42) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) PORT_CHAR('I') PORT_CHANGED(key_stroke, 0x43) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x10,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) PORT_CHAR('O') PORT_CHANGED(key_stroke, 0x44) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x20,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("0") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHANGED(key_stroke, 0x45) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x40,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("9") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHANGED(key_stroke, 0x46) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x80,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("8-8") /*PORT_CODE(KEYCODE_7) PORT_CHAR('7')*/ PORT_CHANGED(key_stroke, 0x47) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_START("KEY9") // 0x48 - 0x4f + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("9-1") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x48) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(".") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x49) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("/") /*PORT_CODE(KEYCODE_2) PORT_CHAR('2')*/ PORT_CHANGED(key_stroke, 0x4a) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) PORT_CHAR('L') PORT_CHANGED(key_stroke, 0x4b) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x10,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(";") /*PORT_CODE(KEYCODE_4) PORT_CHAR('4')*/ PORT_CHANGED(key_stroke, 0x4c) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x20,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) PORT_CHAR('P') PORT_CHANGED(key_stroke, 0x4d) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x40,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("- / =") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHANGED(key_stroke, 0x4e) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x80,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("9-8") /*PORT_CODE(KEYCODE_7) PORT_CHAR('7')*/ PORT_CHANGED(key_stroke, 0x4f) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_START("KEYA") // 0x50 - 0x57 + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("A-1") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x50) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("\xC2\xA5") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x51) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(":") /*PORT_CODE(KEYCODE_2) PORT_CHAR('2')*/ PORT_CHANGED(key_stroke, 0x52) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("A-4") /*PORT_CODE(KEYCODE_3) PORT_CHAR('3')*/ PORT_CHANGED(key_stroke, 0x53) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x10,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("@") /*PORT_CODE(KEYCODE_4) PORT_CHAR('4')*/ PORT_CHANGED(key_stroke, 0x54) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x20,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("^") /*PORT_CODE(KEYCODE_5) PORT_CHAR(0xd)*/ PORT_CHANGED(key_stroke, 0x55) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x40,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("A-7") /*PORT_CODE(KEYCODE_6) PORT_CHAR('6')*/ PORT_CHANGED(key_stroke, 0x56) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x80,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("A-8") /*PORT_CODE(KEYCODE_7) PORT_CHAR('7')*/ PORT_CHANGED(key_stroke, 0x57) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_START("KEYB") // 0x58 - 0x5f + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("B-1") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x58) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("B-2") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x59) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("ENTER") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(0x0d) PORT_CHANGED(key_stroke, 0x5a) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("[") /*PORT_CODE(KEYCODE_3) PORT_CHAR('3')*/ PORT_CHANGED(key_stroke, 0x5b) PORT_PLAYER(1) SATURN_KEYBOARD // { + PORT_BIT(0x10,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("B-5") /*PORT_CODE(KEYCODE_4) PORT_CHAR('4')*/ PORT_CHANGED(key_stroke, 0x5c) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x20,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("]") /*PORT_CODE(KEYCODE_5) PORT_CHAR(0xd)*/ PORT_CHANGED(key_stroke, 0x5d) PORT_PLAYER(1) SATURN_KEYBOARD // } + PORT_BIT(0x40,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("B-7") /*PORT_CODE(KEYCODE_6) PORT_CHAR('6')*/ PORT_CHANGED(key_stroke, 0x5e) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x80,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("B-8") /*PORT_CODE(KEYCODE_7) PORT_CHAR('7')*/ PORT_CHANGED(key_stroke, 0x5f) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_START("KEYC") // 0x60 - 0x67 + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("C-1") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x60) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("C-2") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x61) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("C-3") /*PORT_CODE(KEYCODE_2) PORT_CHAR('2')*/ PORT_CHANGED(key_stroke, 0x62) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("C-4") /*PORT_CODE(KEYCODE_3) PORT_CHAR('3')*/ PORT_CHANGED(key_stroke, 0x63) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x10,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("C-5") /*PORT_CODE(KEYCODE_4) PORT_CHAR('4')*/ PORT_CHANGED(key_stroke, 0x64) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x20,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("C-6") /*PORT_CODE(KEYCODE_5) PORT_CHAR(0xd)*/ PORT_CHANGED(key_stroke, 0x65) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x40,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("BACKSPACE") PORT_CODE(KEYCODE_BACKSPACE) /* PORT_CHAR('6')*/ PORT_CHANGED(key_stroke, 0x66) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x80,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("C-8") /*PORT_CODE(KEYCODE_7) PORT_CHAR('7')*/ PORT_CHANGED(key_stroke, 0x67) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_START("KEYD") // 0x68 - 0x6f + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("D-1") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x68) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("D-2") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x69) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("D-3") /*PORT_CODE(KEYCODE_2) PORT_CHAR('2')*/ PORT_CHANGED(key_stroke, 0x6a) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("D-4") /*PORT_CODE(KEYCODE_3) PORT_CHAR('3')*/ PORT_CHANGED(key_stroke, 0x6b) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x10,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("D-5") /*PORT_CODE(KEYCODE_4) PORT_CHAR('4')*/ PORT_CHANGED(key_stroke, 0x6c) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x20,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("D-6") /*PORT_CODE(KEYCODE_5) PORT_CHAR(0xd)*/ PORT_CHANGED(key_stroke, 0x6d) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x40,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("D-7") /*PORT_CODE(KEYCODE_6) PORT_CHAR('6')*/ PORT_CHANGED(key_stroke, 0x6e) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x80,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("D-8") /*PORT_CODE(KEYCODE_7) PORT_CHAR('7')*/ PORT_CHANGED(key_stroke, 0x6f) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_START("KEYE") // 0x70 - 0x77 + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("E-1") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x70) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("E-2") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x71) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("E-3") /*PORT_CODE(KEYCODE_2) PORT_CHAR('2')*/ PORT_CHANGED(key_stroke, 0x72) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("E-4") /*PORT_CODE(KEYCODE_3) PORT_CHAR('3')*/ PORT_CHANGED(key_stroke, 0x73) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x10,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("E-5") /*PORT_CODE(KEYCODE_4) PORT_CHAR('4')*/ PORT_CHANGED(key_stroke, 0x74) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x20,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("E-6") /*PORT_CODE(KEYCODE_5) PORT_CHAR(0xd)*/ PORT_CHANGED(key_stroke, 0x75) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x40,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("E-7") /*PORT_CODE(KEYCODE_6) PORT_CHAR('6')*/ PORT_CHANGED(key_stroke, 0x76) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x80,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("E-8") /*PORT_CODE(KEYCODE_7) PORT_CHAR('7')*/ PORT_CHANGED(key_stroke, 0x77) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_START("KEYF") // 0x78 - 0x7f + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F-1") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x78) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F-2") /*PORT_CODE(KEYCODE_1) PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x79) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F-3") /*PORT_CODE(KEYCODE_2) PORT_CHAR('2')*/ PORT_CHANGED(key_stroke, 0x7a) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F-4") /*PORT_CODE(KEYCODE_3) PORT_CHAR('3')*/ PORT_CHANGED(key_stroke, 0x7b) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x10,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F-5") /*PORT_CODE(KEYCODE_4) PORT_CHAR('4')*/ PORT_CHANGED(key_stroke, 0x7c) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x20,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F-6") /*PORT_CODE(KEYCODE_5) PORT_CHAR(0xd)*/ PORT_CHANGED(key_stroke, 0x7d) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x40,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F-7") /*PORT_CODE(KEYCODE_6) PORT_CHAR('6')*/ PORT_CHANGED(key_stroke, 0x7e) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x80,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("ESC") /*PORT_CODE(KEYCODE_7) PORT_CHAR('7')*/ PORT_CHANGED(key_stroke, 0x7f) PORT_PLAYER(1) SATURN_KEYBOARD //SYSTEM CONFIGURATION + + PORT_START("KEYS_1") // special keys + PORT_BIT(0x01,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("UP") PORT_CODE(KEYCODE_UP) /*PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x78) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x02,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("DOWN") PORT_CODE(KEYCODE_DOWN) /*PORT_CHAR('1')*/ PORT_CHANGED(key_stroke, 0x79) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x04,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("LEFT") PORT_CODE(KEYCODE_LEFT) /*PORT_CHAR('2')*/ PORT_CHANGED(key_stroke, 0x7a) PORT_PLAYER(1) SATURN_KEYBOARD + PORT_BIT(0x08,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("RIGHT") PORT_CODE(KEYCODE_RIGHT) /*PORT_CHAR('3')*/ PORT_CHANGED(key_stroke, 0x7b) PORT_PLAYER(1) SATURN_KEYBOARD + + PORT_START("MOUSEB1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P1 Pointer Left Button") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x04) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P1 Pointer Right Button") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x04) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P1 Pointer Middle Button") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x04) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_NAME("P1 Pointer Start Button") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x04) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P1 Mouse Left Button") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x08) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P1 Mouse Right Button") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x08) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P1 Mouse Middle Button") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x08) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_NAME("P1 Mouse Start Button") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x08) + + PORT_START("MOUSEX1") + PORT_BIT(0xffff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_MINMAX(0x000, 0xffff) PORT_KEYDELTA(2) PORT_RESET PORT_NAME("P1 Pointer X") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x04) + PORT_BIT(0xffff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_MINMAX(0x000, 0xffff) PORT_KEYDELTA(2) PORT_RESET PORT_NAME("P1 Mouse X") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x08) + + PORT_START("MOUSEY1") + PORT_BIT(0xffff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_MINMAX(0x000, 0xffff) PORT_KEYDELTA(2) PORT_RESET PORT_REVERSE PORT_NAME("P1 Pointer Y") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x04) + PORT_BIT(0xffff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_MINMAX(0x000, 0xffff) PORT_KEYDELTA(2) PORT_RESET PORT_REVERSE PORT_NAME("P1 Mouse Y") PORT_PLAYER(1) PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x08) + + PORT_START("MOUSEB2") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 Pointer Left Button") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x40) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 Pointer Right Button") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x40) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P2 Pointer Middle Button") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x40) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_NAME("P2 Pointer Start Button") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x40) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 Mouse Left Button") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x80) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 Mouse Right Button") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x80) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P2 Mouse Middle Button") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x80) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_NAME("P2 Mouse Start Button") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x80) + + PORT_START("MOUSEX2") + PORT_BIT(0xffff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_MINMAX(0x000, 0xffff) PORT_KEYDELTA(2) PORT_RESET PORT_NAME("P2 Pointer X") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x40) + PORT_BIT(0xffff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_MINMAX(0x000, 0xffff) PORT_KEYDELTA(2) PORT_RESET PORT_NAME("P2 Mouse X") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x80) + + PORT_START("MOUSEY2") + PORT_BIT(0xffff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_MINMAX(0x000, 0xffff) PORT_KEYDELTA(2) PORT_RESET PORT_REVERSE PORT_NAME("P2 Pointer Y") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x40) + PORT_BIT(0xffff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_MINMAX(0x000, 0xffff) PORT_KEYDELTA(2) PORT_RESET PORT_REVERSE PORT_NAME("P2 Mouse Y") PORT_PLAYER(2) PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x80) + + PORT_START("AN_JOY1") + SATURN_PAD_P1(0x0f, 0x01) // racing device + SATURN_PAD_P1(0x0f, 0x02) // analog controller + + PORT_START("AN_JOY2") + SATURN_PAD_P2(0xf0, 0x10) // racing device + SATURN_PAD_P2(0xf0, 0x20) // analog controller + + PORT_START("AN_X1") + PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_MINMAX(0x00, 0xff) PORT_SENSITIVITY(25) PORT_KEYDELTA(200) PORT_PLAYER(1) PORT_NAME("P1 Racing Stick X") PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x01) + PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_MINMAX(0x00, 0xff) PORT_SENSITIVITY(25) PORT_KEYDELTA(200) PORT_PLAYER(1) PORT_NAME("P1 AD Stick X") PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x02) + + PORT_START("AN_Y1") + PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_MINMAX(0x00, 0xff) PORT_SENSITIVITY(25) PORT_KEYDELTA(200) PORT_PLAYER(1) PORT_NAME("P1 Racing Stick Y") PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x01) + PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_MINMAX(0x00, 0xff) PORT_SENSITIVITY(25) PORT_KEYDELTA(200) PORT_PLAYER(1) PORT_NAME("P1 AD Stick Y") PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x02) + + PORT_START("AN_Z1") + PORT_BIT( 0xff, 0x00, IPT_AD_STICK_Z ) PORT_MINMAX(0x00, 0xff) PORT_SENSITIVITY(25) PORT_KEYDELTA(200) PORT_PLAYER(1) PORT_NAME("P1 Racing Stick Z") PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x01) + PORT_BIT( 0xff, 0x00, IPT_AD_STICK_Z ) PORT_MINMAX(0x00, 0xff) PORT_SENSITIVITY(25) PORT_KEYDELTA(200) PORT_PLAYER(1) PORT_NAME("P1 AD Stick Z") PORT_CONDITION("INPUT_TYPE", 0x0f, PORTCOND_EQUALS, 0x02) + + PORT_START("AN_X2") + PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_MINMAX(0x00, 0xff) PORT_SENSITIVITY(25) PORT_KEYDELTA(200) PORT_PLAYER(2) PORT_NAME("P2 Racing Stick X") PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x10) + PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_MINMAX(0x00, 0xff) PORT_SENSITIVITY(25) PORT_KEYDELTA(200) PORT_PLAYER(2) PORT_NAME("P2 AD Stick X") PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x20) + + PORT_START("AN_Y2") + PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_MINMAX(0x00, 0xff) PORT_SENSITIVITY(25) PORT_KEYDELTA(200) PORT_PLAYER(2) PORT_NAME("P2 Racing Stick Y") PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x10) + PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_MINMAX(0x00, 0xff) PORT_SENSITIVITY(25) PORT_KEYDELTA(200) PORT_PLAYER(2) PORT_NAME("P2 AD Stick Y") PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x20) + + PORT_START("AN_Z2") + PORT_BIT( 0xff, 0x00, IPT_AD_STICK_Z ) PORT_MINMAX(0x00, 0xff) PORT_SENSITIVITY(25) PORT_KEYDELTA(200) PORT_PLAYER(2) PORT_NAME("P2 Racing Stick Z") PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x10) + PORT_BIT( 0xff, 0x00, IPT_AD_STICK_Z ) PORT_MINMAX(0x00, 0xff) PORT_SENSITIVITY(25) PORT_KEYDELTA(200) PORT_PLAYER(2) PORT_NAME("P2 AD Stick Z") PORT_CONDITION("INPUT_TYPE", 0xf0, PORTCOND_EQUALS, 0x20) + + PORT_START("MD_JOY1") + MD_PAD_P1(0x0f, 0x06) // MD 3 buttons pad + MD_PAD_P1(0x0f, 0x07) // MD 6 buttons pad + + PORT_START("MD_JOY2") + MD_PAD_P2(0xf0, 0x60) // MD 3 buttons pad + MD_PAD_P2(0xf0, 0x70) // MD 6 buttons pad + + PORT_START("CART_AREA") + PORT_CONFNAME( 0x07, 0x06, "Cart Type" ) + PORT_CONFSETTING( 0x00, "None" ) +// PORT_CONFSETTING( 0x01, "4 Mbit backup RAM" ) +// PORT_CONFSETTING( 0x02, "8 Mbit backup RAM" ) +// PORT_CONFSETTING( 0x03, "16 Mbit backup RAM" ) +// PORT_CONFSETTING( 0x04, "32 Mbit backup RAM" ) + PORT_CONFSETTING( 0x05, "8 Mbit Cart RAM" ) + PORT_CONFSETTING( 0x06, "32 Mbit Cart RAM" ) + + PORT_START("INPUT_TYPE") + PORT_CONFNAME(0x0f,0x00,"Controller Port 1") + PORT_CONFSETTING(0x00,"Digital Device (standard Saturn pad)") + PORT_CONFSETTING(0x01,"Racing Device") /* steering wheel only */ + PORT_CONFSETTING(0x02,"Analog Device") //Nights pad? +// PORT_CONFSETTING(0x03,"Lightgun Device") + PORT_CONFSETTING(0x04,"Trackball") // TODO: according to the docs this ID is labeled "Pointing Device" + PORT_CONFSETTING(0x05,"Keyboard Device") + PORT_CONFSETTING(0x06,"Megadrive 3B Pad") + PORT_CONFSETTING(0x07,"Megadrive 6B Pad") + PORT_CONFSETTING(0x08,"Saturn Mouse") +// PORT_CONFSETTING(0x09,"<unconnected>") + PORT_CONFNAME(0xf0,0x00,"Controller Port 2") + PORT_CONFSETTING(0x00,"Digital Device (standard Saturn pad)") + PORT_CONFSETTING(0x10,"Racing Device") + PORT_CONFSETTING(0x20,"Analog Device") //Nights pad? +// PORT_CONFSETTING(0x30,"Lightgun Device") + PORT_CONFSETTING(0x40,"Pointing Device") +// PORT_CONFSETTING(0x50,"Keyboard Device") + PORT_CONFSETTING(0x60,"Megadrive 3B Pad") + PORT_CONFSETTING(0x70,"Megadrive 6B Pad") + PORT_CONFSETTING(0x80,"Saturn Mouse") + PORT_CONFSETTING(0x90,"<unconnected>") +INPUT_PORTS_END + +#define STV_PLAYER_INPUTS(_n_, _b1_, _b2_, _b3_,_b4_) \ + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_##_b1_ ) PORT_PLAYER(_n_) \ + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_##_b2_ ) PORT_PLAYER(_n_) \ + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_##_b3_ ) PORT_PLAYER(_n_) \ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_##_b4_ ) PORT_PLAYER(_n_) \ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(_n_) \ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(_n_) \ + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(_n_) \ + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(_n_) + +static INPUT_PORTS_START( stv ) + PORT_START("DSW1") + PORT_DIPNAME( 0x01, 0x01, "PDR1" ) + PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x02, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x04, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x10, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + + PORT_START("DSW2") + PORT_DIPNAME( 0x01, 0x01, "PDR2" ) + PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x02, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x04, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x10, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + + PORT_START("PORTA") + STV_PLAYER_INPUTS(1, BUTTON1, BUTTON2, BUTTON3, BUTTON4) + + PORT_START("PORTB") + STV_PLAYER_INPUTS(2, BUTTON1, BUTTON2, BUTTON3, BUTTON4) + + PORT_START("PORTC") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN2 ) + PORT_SERVICE_NO_TOGGLE( 0x04, IP_ACTIVE_LOW ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_SERVICE1 ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(1) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(2) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SERVICE ) PORT_NAME("1P Push Switch") PORT_CODE(KEYCODE_7) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SERVICE ) PORT_NAME("2P Push Switch") PORT_CODE(KEYCODE_8) + + PORT_START("PORTE") + STV_PLAYER_INPUTS(3, BUTTON1, BUTTON2, BUTTON3, START) + + PORT_START("PORTF") + STV_PLAYER_INPUTS(4, BUTTON1, BUTTON2, BUTTON3, START) +INPUT_PORTS_END + +static INPUT_PORTS_START( stv6b ) + PORT_INCLUDE( stv ) + + PORT_MODIFY("PORTA") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_MODIFY("PORTB") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_MODIFY("PORTE") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) + + /* Extra button layout, used by Power Instinct 3, Suikoenbu, Elan Doree, Golden Axe Duel & Astra SuperStars */ + PORT_MODIFY("PORTF") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(1) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(1) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(2) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(2) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) +INPUT_PORTS_END + +static INPUT_PORTS_START( critcrsh ) + PORT_INCLUDE( stv ) + + PORT_MODIFY("PORTA") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_MODIFY("PORTB") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_MODIFY("PORTC") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Hammer Hit") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_MODIFY("PORTE") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_MODIFY("PORTF") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("LIGHTX") /* mask default type sens delta min max */ + PORT_BIT( 0x3f, 0x00, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_MINMAX(0,0x3f) PORT_SENSITIVITY(50) PORT_KEYDELTA(1) PORT_PLAYER(1) + + PORT_START("LIGHTY") + PORT_BIT( 0x3f, 0x00, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_MINMAX(0x0,0x3f) PORT_SENSITIVITY(50) PORT_KEYDELTA(1) PORT_PLAYER(1) +INPUT_PORTS_END + +/* Same as the regular one, but with an additional & optional mahjong panel */ +static INPUT_PORTS_START( stvmp ) + PORT_INCLUDE( stv ) + + PORT_MODIFY("PORTE") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_MODIFY("PORTF") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) + + /* Mahjong panel/player 1 side */ + PORT_START("P1_KEY0") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_MAHJONG_KAN ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START1 ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_MAHJONG_E ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_MAHJONG_A ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_MAHJONG_M ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_MAHJONG_I ) + + PORT_START("P1_KEY1") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_MAHJONG_RON ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_MAHJONG_F ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_MAHJONG_B ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_MAHJONG_N ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_MAHJONG_J ) + + PORT_START("P1_KEY2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_MAHJONG_REACH ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_MAHJONG_G ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_MAHJONG_C ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_MAHJONG_CHI ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_MAHJONG_K ) + + PORT_START("P1_KEY3") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_MAHJONG_H ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_MAHJONG_D ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_MAHJONG_PON ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_MAHJONG_L ) + + PORT_START("P1_KEY4") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_MAHJONG_FLIP_FLOP ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + /* Mahjong panel/player 2 side */ + PORT_START("P2_KEY0") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_MAHJONG_KAN ) PORT_PLAYER(2) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START2 ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_MAHJONG_E ) PORT_PLAYER(2) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_MAHJONG_A ) PORT_PLAYER(2) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_MAHJONG_M ) PORT_PLAYER(2) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_MAHJONG_I ) PORT_PLAYER(2) + + PORT_START("P2_KEY1") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_MAHJONG_RON ) PORT_PLAYER(2) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_MAHJONG_F ) PORT_PLAYER(2) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_MAHJONG_B ) PORT_PLAYER(2) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_MAHJONG_N ) PORT_PLAYER(2) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_MAHJONG_J ) PORT_PLAYER(2) + + PORT_START("P2_KEY2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_MAHJONG_REACH ) PORT_PLAYER(2) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_MAHJONG_G ) PORT_PLAYER(2) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_MAHJONG_C ) PORT_PLAYER(2) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_MAHJONG_CHI ) PORT_PLAYER(2) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_MAHJONG_K ) PORT_PLAYER(2) + + PORT_START("P2_KEY3") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_MAHJONG_H ) PORT_PLAYER(2) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_MAHJONG_D ) PORT_PLAYER(2) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_MAHJONG_PON ) PORT_PLAYER(2) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_MAHJONG_L ) PORT_PLAYER(2) + + PORT_START("P2_KEY4") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_MAHJONG_FLIP_FLOP ) PORT_PLAYER(2) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) +INPUT_PORTS_END + +/* Micronet layout, routes joystick port to the mux! */ +static INPUT_PORTS_START( myfairld ) + PORT_INCLUDE( stv ) + + PORT_MODIFY("PORTA") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_MODIFY("PORTB") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_MODIFY("PORTC") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(1) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x01) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_MODIFY("PORTE") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_MODIFY("PORTF") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("P1_KEY0") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_MAHJONG_KAN ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_START1 ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_MAHJONG_E ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_MAHJONG_A ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_MAHJONG_M ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_MAHJONG_I ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x01) + + PORT_START("P1_KEY1") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_MAHJONG_REACH ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_MAHJONG_BET ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_MAHJONG_F ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_MAHJONG_B ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_MAHJONG_N ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_MAHJONG_J ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x01) + + PORT_START("P1_KEY2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_MAHJONG_RON ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_MAHJONG_G ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_MAHJONG_C ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_MAHJONG_CHI ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_MAHJONG_K ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x01) + + PORT_START("P1_KEY3") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_MAHJONG_H ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_MAHJONG_D ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_MAHJONG_PON ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_MAHJONG_L ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x00) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x01) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x01) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x01) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x01) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x01) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x01) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x01) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CONDITION("IO_TYPE", 0x01, PORTCOND_EQUALS, 0x01) + + PORT_START("P1_KEY4") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) /* F/F is there, but these two games are single player so it isn't connected */ + + PORT_START("P2_KEY0") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("P2_KEY1") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("P2_KEY2") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("P2_KEY3") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("P2_KEY4") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("IO_TYPE") + PORT_CONFNAME( 0x01, 0x00, "I/O Device type" ) + PORT_CONFSETTING( 0x00, "Mahjong Panel" ) + PORT_CONFSETTING( 0x01, "Joystick" ) +INPUT_PORTS_END + +static const gfx_layout tiles8x8x4_layout = +{ + 8,8, + 0x100000/(32*8/8), + 4, + { 0, 1, 2, 3 }, + { 0, 4, 8, 12, 16, 20, 24, 28 }, + { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32 }, + 32*8 +}; + +static const gfx_layout tiles16x16x4_layout = +{ + 16,16, + 0x100000/(32*32/8), + 4, + { 0, 1, 2, 3 }, + { 0, 4, 8, 12, 16, 20, 24, 28, + 32*8+0, 32*8+4, 32*8+8, 32*8+12, 32*8+16, 32*8+20, 32*8+24, 32*8+28, + + }, + { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32, + 32*16, 32*17,32*18, 32*19,32*20,32*21,32*22,32*23 + + }, + 32*32 +}; + +static const gfx_layout tiles8x8x8_layout = +{ + 8,8, + 0x100000/(32*8/8), + 8, + { 0, 1, 2, 3, 4, 5, 6, 7 }, + { 0, 8, 16, 24, 32, 40, 48, 56 }, + { 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64 }, + 32*8 /* really 64*8, but granularity is 32 bytes */ +}; + +static const gfx_layout tiles16x16x8_layout = +{ + 16,16, + 0x100000/(64*16/8), + 8, + { 0, 1, 2, 3, 4, 5, 6, 7 }, + { 0, 8, 16, 24, 32, 40, 48, 56, + 64*8+0, 65*8, 66*8, 67*8, 68*8, 69*8, 70*8, 71*8 + + }, + { 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64, + 64*16, 64*17, 64*18, 64*19, 64*20, 64*21, 64*22, 64*23 + }, + 64*16 /* really 128*16, but granularity is 32 bytes */ +}; + + + + +static GFXDECODE_START( stv ) + GFXDECODE_ENTRY( NULL, 0, tiles8x8x4_layout, 0x00, (0x80*(2+1)) ) + GFXDECODE_ENTRY( NULL, 0, tiles16x16x4_layout, 0x00, (0x80*(2+1)) ) + GFXDECODE_ENTRY( NULL, 0, tiles8x8x8_layout, 0x00, (0x08*(2+1)) ) + GFXDECODE_ENTRY( NULL, 0, tiles16x16x8_layout, 0x00, (0x08*(2+1)) ) + + /* vdp1 .. pointless for drawing but can help us debug */ + GFXDECODE_ENTRY( NULL, 0, tiles8x8x4_layout, 0x00, 0x100 ) + GFXDECODE_ENTRY( NULL, 0, tiles16x16x4_layout, 0x00, 0x100 ) + GFXDECODE_ENTRY( NULL, 0, tiles8x8x8_layout, 0x00, 0x20 ) + GFXDECODE_ENTRY( NULL, 0, tiles16x16x8_layout, 0x00, 0x20 ) + +GFXDECODE_END + +static const sh2_cpu_core sh2_conf_master = { 0, NULL }; +static const sh2_cpu_core sh2_conf_slave = { 1, NULL }; + +static int scsp_last_line = 0; + +static void scsp_irq(device_t *device, int irq) +{ + saturn_state *state = device->machine().driver_data<saturn_state>(); + + // don't bother the 68k if it's off + if (!state->m_en_68k) + { + return; + } + + if (irq > 0) + { + scsp_last_line = irq; + cputag_set_input_line(device->machine(), "audiocpu", irq, ASSERT_LINE); + } + else if (irq < 0) + { + cputag_set_input_line(device->machine(), "audiocpu", -irq, CLEAR_LINE); + } + else + { + cputag_set_input_line(device->machine(), "audiocpu", scsp_last_line, CLEAR_LINE); + } +} + +static WRITE_LINE_DEVICE_HANDLER( scsp_to_main_irq ) +{ + saturn_state *drvstate = device->machine().driver_data<saturn_state>(); + + if(!(drvstate->m_scu.ism & IRQ_SOUND_REQ)) + { + device_set_input_line_and_vector(drvstate->m_maincpu, 9, HOLD_LINE, 0x46); + scu_do_transfer(device->machine(),5); + } + else + drvstate->m_scu.ist |= (IRQ_SOUND_REQ); +} + +static const scsp_interface scsp_config = +{ + 0, + scsp_irq, + DEVCB_LINE(scsp_to_main_irq) +}; + +static TIMER_CALLBACK(stv_rtc_increment) +{ + saturn_state *state = machine.driver_data<saturn_state>(); + static const UINT8 dpm[12] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 }; + static int year_num, year_count; + + /* + state->m_smpc.rtc_data[0] = DectoBCD(systime.local_time.year /100); + state->m_smpc.rtc_data[1] = DectoBCD(systime.local_time.year %100); + state->m_smpc.rtc_data[2] = (systime.local_time.weekday << 4) | (systime.local_time.month+1); + state->m_smpc.rtc_data[3] = DectoBCD(systime.local_time.mday); + state->m_smpc.rtc_data[4] = DectoBCD(systime.local_time.hour); + state->m_smpc.rtc_data[5] = DectoBCD(systime.local_time.minute); + state->m_smpc.rtc_data[6] = DectoBCD(systime.local_time.second); + */ + + state->m_smpc.rtc_data[6]++; + + /* seconds from 9 -> 10*/ + if((state->m_smpc.rtc_data[6] & 0x0f) >= 0x0a) { state->m_smpc.rtc_data[6]+=0x10; state->m_smpc.rtc_data[6]&=0xf0; } + /* seconds from 59 -> 0 */ + if((state->m_smpc.rtc_data[6] & 0xf0) >= 0x60) { state->m_smpc.rtc_data[5]++; state->m_smpc.rtc_data[6] = 0; } + /* minutes from 9 -> 10 */ + if((state->m_smpc.rtc_data[5] & 0x0f) >= 0x0a) { state->m_smpc.rtc_data[5]+=0x10; state->m_smpc.rtc_data[5]&=0xf0; } + /* minutes from 59 -> 0 */ + if((state->m_smpc.rtc_data[5] & 0xf0) >= 0x60) { state->m_smpc.rtc_data[4]++; state->m_smpc.rtc_data[5] = 0; } + /* hours from 9 -> 10 */ + if((state->m_smpc.rtc_data[4] & 0x0f) >= 0x0a) { state->m_smpc.rtc_data[4]+=0x10; state->m_smpc.rtc_data[4]&=0xf0; } + /* hours from 23 -> 0 */ + if((state->m_smpc.rtc_data[4] & 0xff) >= 0x24) { state->m_smpc.rtc_data[3]++; state->m_smpc.rtc_data[2]+=0x10; state->m_smpc.rtc_data[4] = 0; } + /* week day name sunday -> monday */ + if((state->m_smpc.rtc_data[2] & 0xf0) >= 0x70) { state->m_smpc.rtc_data[2]&=0x0f; } + /* day number 9 -> 10 */ + if((state->m_smpc.rtc_data[3] & 0x0f) >= 0x0a) { state->m_smpc.rtc_data[3]+=0x10; state->m_smpc.rtc_data[3]&=0xf0; } + + // year BCD to dec conversion (for the leap year stuff) + { + year_num = (state->m_smpc.rtc_data[1] & 0xf); + + for(year_count = 0; year_count < (state->m_smpc.rtc_data[1] & 0xf0); year_count += 0x10) + year_num += 0xa; + + year_num += (state->m_smpc.rtc_data[0] & 0xf)*0x64; + + for(year_count = 0; year_count < (state->m_smpc.rtc_data[0] & 0xf0); year_count += 0x10) + year_num += 0x3e8; + } + + /* month +1 check */ + /* the RTC have a range of 1980 - 2100, so we don't actually need to support the leap year special conditions */ + if(((year_num % 4) == 0) && (state->m_smpc.rtc_data[2] & 0xf) == 2) + { + if((state->m_smpc.rtc_data[3] & 0xff) >= dpm[(state->m_smpc.rtc_data[2] & 0xf)-1]+1+1) + { state->m_smpc.rtc_data[2]++; state->m_smpc.rtc_data[3] = 0x01; } + } + else if((state->m_smpc.rtc_data[3] & 0xff) >= dpm[(state->m_smpc.rtc_data[2] & 0xf)-1]+1){ state->m_smpc.rtc_data[2]++; state->m_smpc.rtc_data[3] = 0x01; } + /* year +1 check */ + if((state->m_smpc.rtc_data[2] & 0x0f) > 12) { state->m_smpc.rtc_data[1]++; state->m_smpc.rtc_data[2] = (state->m_smpc.rtc_data[2] & 0xf0) | 0x01; } + /* year from 9 -> 10 */ + if((state->m_smpc.rtc_data[1] & 0x0f) >= 0x0a) { state->m_smpc.rtc_data[1]+=0x10; state->m_smpc.rtc_data[1]&=0xf0; } + /* year from 99 -> 100 */ + if((state->m_smpc.rtc_data[1] & 0xf0) >= 0xa0) { state->m_smpc.rtc_data[0]++; state->m_smpc.rtc_data[1] = 0; } + + // probably not SO precise, here just for reference ... + /* year from 999 -> 1000 */ + //if((state->m_smpc.rtc_data[0] & 0x0f) >= 0x0a) { state->m_smpc.rtc_data[0]+=0x10; state->m_smpc.rtc_data[0]&=0xf0; } + /* year from 9999 -> 0 */ + //if((state->m_smpc.rtc_data[0] & 0xf0) >= 0xa0) { state->m_smpc.rtc_data[0] = 0; } //roll over +} + +static MACHINE_START( stv ) +{ + saturn_state *state = machine.driver_data<saturn_state>(); + system_time systime; + machine.base_datetime(systime); + + state->m_maincpu = downcast<legacy_cpu_device*>( machine.device("maincpu") ); + state->m_slave = downcast<legacy_cpu_device*>( machine.device("slave") ); + state->m_audiocpu = downcast<legacy_cpu_device*>( machine.device("audiocpu") ); + + scsp_set_ram_base(machine.device("scsp"), state->m_sound_ram); + + // save states + state_save_register_global_pointer(machine, state->m_scu_regs, 0x100/4); + state_save_register_global_pointer(machine, state->m_scsp_regs, 0x1000/2); + state_save_register_global(machine, state->m_NMI_reset); + state_save_register_global(machine, state->m_en_68k); +// state_save_register_global(machine, scanline); + state_save_register_global(machine, state->m_smpc.IOSEL1); + state_save_register_global(machine, state->m_smpc.IOSEL2); + state_save_register_global(machine, state->m_smpc.EXLE1); + state_save_register_global(machine, state->m_smpc.EXLE2); + state_save_register_global(machine, state->m_smpc.PDR1); + state_save_register_global(machine, state->m_smpc.PDR2); + state_save_register_global(machine, state->m_port_sel); + state_save_register_global(machine, state->m_mux_data); + state_save_register_global(machine, scsp_last_line); + + stv_register_protection_savestates(machine); // machine/stvprot.c + + machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(stvcd_exit), &machine)); + + state->m_smpc.rtc_data[0] = DectoBCD(systime.local_time.year /100); + state->m_smpc.rtc_data[1] = DectoBCD(systime.local_time.year %100); + state->m_smpc.rtc_data[2] = (systime.local_time.weekday << 4) | (systime.local_time.month+1); + state->m_smpc.rtc_data[3] = DectoBCD(systime.local_time.mday); + state->m_smpc.rtc_data[4] = DectoBCD(systime.local_time.hour); + state->m_smpc.rtc_data[5] = DectoBCD(systime.local_time.minute); + state->m_smpc.rtc_data[6] = DectoBCD(systime.local_time.second); + + state->m_stv_rtc_timer = machine.scheduler().timer_alloc(FUNC(stv_rtc_increment)); +} + + +static MACHINE_START( saturn ) +{ + saturn_state *state = machine.driver_data<saturn_state>(); + system_time systime; + machine.base_datetime(systime); + + state->m_maincpu = downcast<legacy_cpu_device*>( machine.device("maincpu") ); + state->m_slave = downcast<legacy_cpu_device*>( machine.device("slave") ); + state->m_audiocpu = downcast<legacy_cpu_device*>( machine.device("audiocpu") ); + + scsp_set_ram_base(machine.device("scsp"), state->m_sound_ram); + + // save states + state_save_register_global_pointer(machine, state->m_scu_regs, 0x100/4); + state_save_register_global_pointer(machine, state->m_scsp_regs, 0x1000/2); + state_save_register_global(machine, state->m_NMI_reset); + state_save_register_global(machine, state->m_en_68k); + state_save_register_global(machine, state->m_smpc.IOSEL1); + state_save_register_global(machine, state->m_smpc.IOSEL2); + state_save_register_global(machine, state->m_smpc.EXLE1); + state_save_register_global(machine, state->m_smpc.EXLE2); + state_save_register_global(machine, state->m_smpc.PDR1); + state_save_register_global(machine, state->m_smpc.PDR2); +// state_save_register_global(machine, state->m_port_sel); +// state_save_register_global(machine, mux_data); + state_save_register_global(machine, scsp_last_line); + state_save_register_global(machine, state->m_smpc.intback_stage); + state_save_register_global(machine, state->m_smpc.pmode); + state_save_register_global(machine, state->m_smpc.SR); + state_save_register_global_array(machine, state->m_smpc.SMEM); + state_save_register_global_pointer(machine, state->m_cart_dram, 0x400000/4); + + machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(stvcd_exit), &machine)); + + state->m_smpc.rtc_data[0] = DectoBCD(systime.local_time.year /100); + state->m_smpc.rtc_data[1] = DectoBCD(systime.local_time.year %100); + state->m_smpc.rtc_data[2] = (systime.local_time.weekday << 4) | (systime.local_time.month+1); + state->m_smpc.rtc_data[3] = DectoBCD(systime.local_time.mday); + state->m_smpc.rtc_data[4] = DectoBCD(systime.local_time.hour); + state->m_smpc.rtc_data[5] = DectoBCD(systime.local_time.minute); + state->m_smpc.rtc_data[6] = DectoBCD(systime.local_time.second); + + state->m_stv_rtc_timer = machine.scheduler().timer_alloc(FUNC(stv_rtc_increment)); +} + + +/* +(Preliminary) explanation about this: +VBLANK-OUT is used at the start of the vblank period.It also sets the timer zero +variable to 0. +If the Timer Compare register is zero too,the Timer 0 irq is triggered. + +HBLANK-IN is used at the end of each scanline except when in VBLANK-IN/OUT periods. + +The timer 0 is also incremented by one at each HBLANK and checked with the value +of the Timer Compare register;if equal,the timer 0 irq is triggered here too. +Notice that the timer 0 compare register can be more than the VBLANK maximum range,in +this case the timer 0 irq is simply never triggered.This is a known Sega Saturn/ST-V "bug". + +VBLANK-IN is used at the end of the vblank period. + +SCU register[36] is the timer zero compare register. +SCU register[40] is for IRQ masking. + +TODO: +- VDP1 timing and CEF emulation isn't accurate at all. +*/ + + +static TIMER_DEVICE_CALLBACK( saturn_scanline ) +{ + saturn_state *state = timer.machine().driver_data<saturn_state>(); + int scanline = param; + int max_y = timer.machine().primary_screen->height(); + int y_step,vblank_line; + + y_step = 2; + + if((max_y == 263 && state->m_vdp2.pal == 0) || (max_y == 313 && state->m_vdp2.pal == 1)) + y_step = 1; + + vblank_line = (state->m_vdp2.pal) ? 288 : 240; + + //popmessage("%08x %d T0 %d T1 %d %08x",state->m_scu.ism ^ 0xffffffff,max_y,state->m_scu_regs[36],state->m_scu_regs[37],state->m_scu_regs[38]); + + if(scanline == (0)*y_step) + { + video_update_vdp1(timer.machine()); + + if(STV_VDP1_VBE) + state->m_vdp1.framebuffer_clear_on_next_frame = 1; + + if(!(state->m_scu.ism & IRQ_VDP1_END)) + { + device_set_input_line_and_vector(state->m_maincpu, 0x2, HOLD_LINE, 0x4d); + scu_do_transfer(timer.machine(),6); + } + else + state->m_scu.ist |= (IRQ_VDP1_END); + } + + if(scanline == 0*y_step) + { + if(!(state->m_scu.ism & IRQ_VBLANK_OUT)) + { + device_set_input_line_and_vector(state->m_maincpu, 0xe, HOLD_LINE, 0x41); + scu_do_transfer(timer.machine(),1); + } + else + state->m_scu.ist |= (IRQ_VBLANK_OUT); + + } + else if(scanline == vblank_line*y_step) + { + if(!(state->m_scu.ism & IRQ_VBLANK_IN)) + { + device_set_input_line_and_vector(state->m_maincpu, 0xf, HOLD_LINE ,0x40); + scu_do_transfer(timer.machine(),0); + } + else + state->m_scu.ist |= (IRQ_VBLANK_IN); + } + else if((scanline % y_step) == 0 && scanline < vblank_line*y_step) + { + if(!(state->m_scu.ism & IRQ_HBLANK_IN)) + { + device_set_input_line_and_vector(state->m_maincpu, 0xd, HOLD_LINE, 0x42); + scu_do_transfer(timer.machine(),2); + } + else + state->m_scu.ist |= (IRQ_HBLANK_IN); + } + + if(scanline == (state->m_scu_regs[36] & 0x3ff)*y_step) + { + if(!(state->m_scu.ism & IRQ_TIMER_0)) + { + device_set_input_line_and_vector(state->m_maincpu, 0xc, HOLD_LINE, 0x43 ); + scu_do_transfer(timer.machine(),3); + } + else + state->m_scu.ist |= (IRQ_TIMER_0); + } + + /* TODO: this isn't completely correct */ + if(state->m_scu_regs[38] & 0x1) + { + if((!(state->m_scu_regs[38] & 0x100) && (scanline % y_step) == 0) || + ((state->m_scu_regs[38] & 0x100) && (scanline == (state->m_scu_regs[36] & 0x3ff)*y_step))) + { + if(!(state->m_scu.ism & IRQ_TIMER_1)) + { + device_set_input_line_and_vector(state->m_maincpu, 0xb, HOLD_LINE, 0x44 ); + scu_do_transfer(timer.machine(),4); + } + else + state->m_scu.ist |= (IRQ_TIMER_1); + } + } +} + +static TIMER_DEVICE_CALLBACK( saturn_slave_scanline ) +{ + saturn_state *state = timer.machine().driver_data<saturn_state>(); + int scanline = param; + int max_y = timer.machine().primary_screen->height(); + int y_step,vblank_line; + + y_step = 2; + + if((max_y == 263 && state->m_vdp2.pal == 0) || (max_y == 313 && state->m_vdp2.pal == 1)) + y_step = 1; + + vblank_line = (state->m_vdp2.pal) ? 288 : 240; + + if(scanline == vblank_line*y_step) + device_set_input_line_and_vector(state->m_slave, 0x6, HOLD_LINE, 0x43); + else if((scanline % y_step) == 0 && scanline < vblank_line*y_step) + device_set_input_line_and_vector(state->m_slave, 0x2, HOLD_LINE, 0x41); +} + +/* Die Hard Trilogy tests RAM address 0x25e7ffe bit 2 with Slave during FRT minit irq, in-development tool for breaking execution of it? */ +static READ32_HANDLER( saturn_null_ram_r ) +{ + return 0xffffffff; +} + +static WRITE32_HANDLER( saturn_null_ram_w ) +{ + +} + +static READ32_HANDLER( saturn_cart_dram0_r ) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + + return state->m_cart_dram[offset]; +} + +static WRITE32_HANDLER( saturn_cart_dram0_w ) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + + COMBINE_DATA(&state->m_cart_dram[offset]); +} + +static READ32_HANDLER( saturn_cart_dram1_r ) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + + return state->m_cart_dram[offset+0x200000/4]; +} + +static WRITE32_HANDLER( saturn_cart_dram1_w ) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + + COMBINE_DATA(&state->m_cart_dram[offset+0x200000/4]); +} + +static READ32_HANDLER( saturn_cs1_r ) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + UINT32 res; + + res = 0; + //res = state->m_cart_backupram[offset*4+0] << 24; + res |= state->m_cart_backupram[offset*2+0] << 16; + //res |= state->m_cart_backupram[offset*4+2] << 8; + res |= state->m_cart_backupram[offset*2+1] << 0; + + return res; +} + +static WRITE32_HANDLER( saturn_cs1_w ) +{ + saturn_state *state = space->machine().driver_data<saturn_state>(); + + if(ACCESSING_BITS_16_23) + state->m_cart_backupram[offset*2+0] = (data & 0x00ff0000) >> 16; + if(ACCESSING_BITS_0_7) + state->m_cart_backupram[offset*2+1] = (data & 0x000000ff) >> 0; +} + +static MACHINE_RESET( saturn ) +{ + saturn_state *state = machine.driver_data<saturn_state>(); + // don't let the slave cpu and the 68k go anywhere + cputag_set_input_line(machine, "slave", INPUT_LINE_RESET, ASSERT_LINE); + cputag_set_input_line(machine, "audiocpu", INPUT_LINE_RESET, ASSERT_LINE); + + state->m_smpc.SR = 0x40; // this bit is always on according to docs + + state->m_en_68k = 0; + state->m_NMI_reset = 0; + + DMA_STATUS = 0; + + //memset(stv_m_workram_l, 0, 0x100000); + //memset(stv_m_workram_h, 0, 0x100000); + + machine.device("maincpu")->set_unscaled_clock(MASTER_CLOCK_320/2); + machine.device("slave")->set_unscaled_clock(MASTER_CLOCK_320/2); + + stvcd_reset( machine ); + + state->m_cart_type = input_port_read(machine,"CART_AREA") & 7; + + machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x02400000, 0x027fffff, FUNC(saturn_null_ram_r), FUNC(saturn_null_ram_w)); + machine.device("slave")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x02400000, 0x027fffff, FUNC(saturn_null_ram_r), FUNC(saturn_null_ram_w)); + + if(state->m_cart_type == 5) + { + // AM_RANGE(0x02400000, 0x027fffff) AM_RAM //cart RAM area, dynamically allocated + machine.device("maincpu")->memory().space(AS_PROGRAM)->nop_readwrite(0x02400000, 0x027fffff); + machine.device("slave")->memory().space(AS_PROGRAM)->nop_readwrite(0x02400000, 0x027fffff); + + machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x02400000, 0x0247ffff, FUNC(saturn_cart_dram0_r), FUNC(saturn_cart_dram0_w)); + machine.device("slave")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x02400000, 0x0247ffff, FUNC(saturn_cart_dram0_r), FUNC(saturn_cart_dram0_w)); + machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x02600000, 0x0267ffff, FUNC(saturn_cart_dram1_r), FUNC(saturn_cart_dram1_w)); + machine.device("slave")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x02600000, 0x0267ffff, FUNC(saturn_cart_dram1_r), FUNC(saturn_cart_dram1_w)); + } + + if(state->m_cart_type == 6) + { + // AM_RANGE(0x02400000, 0x027fffff) AM_RAM //cart RAM area, dynamically allocated + machine.device("maincpu")->memory().space(AS_PROGRAM)->nop_readwrite(0x02400000, 0x027fffff); + machine.device("slave")->memory().space(AS_PROGRAM)->nop_readwrite(0x02400000, 0x027fffff); + + machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x02400000, 0x025fffff, FUNC(saturn_cart_dram0_r), FUNC(saturn_cart_dram0_w)); + machine.device("slave")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x02400000, 0x025fffff, FUNC(saturn_cart_dram0_r), FUNC(saturn_cart_dram0_w)); + machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x02600000, 0x027fffff, FUNC(saturn_cart_dram1_r), FUNC(saturn_cart_dram1_w)); + machine.device("slave")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x02600000, 0x027fffff, FUNC(saturn_cart_dram1_r), FUNC(saturn_cart_dram1_w)); + } + + machine.device("maincpu")->memory().space(AS_PROGRAM)->nop_readwrite(0x04000000, 0x047fffff); + machine.device("slave")->memory().space(AS_PROGRAM)->nop_readwrite(0x04000000, 0x047fffff); + + if(state->m_cart_type > 0 && state->m_cart_type < 5) + { + // AM_RANGE(0x04000000, 0x047fffff) AM_RAM //backup RAM area, dynamically allocated + UINT32 mask; + mask = 0x7fffff >> (4-state->m_cart_type); + //mask = 0x7fffff >> 4-4 = 0x7fffff 32mbit + //mask = 0x7fffff >> 4-3 = 0x3fffff 16mbit + //mask = 0x7fffff >> 4-2 = 0x1fffff 8mbit + //mask = 0x7fffff >> 4-1 = 0x0fffff 4mbit + machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x04000000, 0x04000000 | mask, FUNC(saturn_cs1_r), FUNC(saturn_cs1_w)); + machine.device("slave")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x04000000, 0x04000000 | mask, FUNC(saturn_cs1_r), FUNC(saturn_cs1_w)); + } + + + /* TODO: default value is probably 7 */ + state->m_scu.start_factor[0] = -1; + state->m_scu.start_factor[1] = -1; + state->m_scu.start_factor[2] = -1; + + state->m_vdp2.old_crmd = -1; + state->m_vdp2.old_tvmd = -1; + + state->m_stv_rtc_timer->adjust(attotime::zero, 0, attotime::from_seconds(1)); +} + + +static MACHINE_RESET( stv ) +{ + saturn_state *state = machine.driver_data<saturn_state>(); + + // don't let the slave cpu and the 68k go anywhere + cputag_set_input_line(machine, "slave", INPUT_LINE_RESET, ASSERT_LINE); + cputag_set_input_line(machine, "audiocpu", INPUT_LINE_RESET, ASSERT_LINE); + + state->m_en_68k = 0; + state->m_NMI_reset = 0; + + state->m_port_sel = state->m_mux_data = 0; + + machine.device("maincpu")->set_unscaled_clock(MASTER_CLOCK_320/2); + machine.device("slave")->set_unscaled_clock(MASTER_CLOCK_320/2); + + stvcd_reset(machine); + + state->m_stv_rtc_timer->adjust(attotime::zero, 0, attotime::from_seconds(1)); + state->m_prev_bankswitch = 0xff; + + /* TODO: default value is probably 7 */ + state->m_scu.start_factor[0] = -1; + state->m_scu.start_factor[1] = -1; + state->m_scu.start_factor[2] = -1; + + state->m_vdp2.old_crmd = -1; + state->m_vdp2.old_tvmd = -1; +} + +struct cdrom_interface saturn_cdrom = +{ + NULL, + NULL +}; + +static MACHINE_CONFIG_START( saturn, saturn_state ) + + /* basic machine hardware */ + MCFG_CPU_ADD("maincpu", SH2, MASTER_CLOCK_352/2) // 28.6364 MHz + MCFG_CPU_PROGRAM_MAP(saturn_mem) + MCFG_CPU_CONFIG(sh2_conf_master) + MCFG_TIMER_ADD_SCANLINE("scantimer", saturn_scanline, "screen", 0, 1) + + MCFG_CPU_ADD("slave", SH2, MASTER_CLOCK_352/2) // 28.6364 MHz + MCFG_CPU_PROGRAM_MAP(saturn_mem) + MCFG_CPU_CONFIG(sh2_conf_slave) + MCFG_TIMER_ADD_SCANLINE("slave_scantimer", saturn_slave_scanline, "screen", 0, 1) + + MCFG_CPU_ADD("audiocpu", M68000, 11289600) //256 x 44100 Hz = 11.2896 MHz + MCFG_CPU_PROGRAM_MAP(sound_mem) + + MCFG_MACHINE_START(saturn) + MCFG_MACHINE_RESET(saturn) + + MCFG_NVRAM_HANDLER(saturn) + + MCFG_TIMER_ADD("sector_timer", stv_sector_cb) + MCFG_TIMER_ADD("sh1_cmd", stv_sh1_sim) + + /* video hardware */ + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(MASTER_CLOCK_320/8, 427, 0, 320, 263, 0, 224) + #if NEW_VIDEO_CODE + MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) + MCFG_SCREEN_UPDATE(saturn) + MCFG_PALETTE_LENGTH(2048+(2048*2))//standard palette + extra memory for rgb brightness. (TODO: remove AT LEAST the latter) + #else + MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB15) + MCFG_SCREEN_UPDATE(stv_vdp2) + MCFG_PALETTE_LENGTH(2048+(2048*2))//standard palette + extra memory for rgb brightness. + #endif + + MCFG_GFXDECODE(stv) + + MCFG_VIDEO_START(stv_vdp2) + + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + + MCFG_SOUND_ADD("scsp", SCSP, 0) + MCFG_SOUND_CONFIG(scsp_config) + MCFG_SOUND_ROUTE(0, "lspeaker", 1.0) + MCFG_SOUND_ROUTE(1, "rspeaker", 1.0) + + MCFG_SOUND_ADD("cdda", CDDA, 0) + MCFG_SOUND_ROUTE(0, "lspeaker", 1.0) + MCFG_SOUND_ROUTE(1, "rspeaker", 1.0) + + MCFG_CDROM_ADD( "cdrom", saturn_cdrom) + MCFG_CARTSLOT_ADD("cart") +MACHINE_CONFIG_END + + +static MACHINE_CONFIG_START( stv, saturn_state ) + + /* basic machine hardware */ + MCFG_CPU_ADD("maincpu", SH2, MASTER_CLOCK_352/2) // 28.6364 MHz + MCFG_CPU_PROGRAM_MAP(stv_mem) + MCFG_CPU_CONFIG(sh2_conf_master) + MCFG_TIMER_ADD_SCANLINE("scantimer", saturn_scanline, "screen", 0, 1) + + MCFG_CPU_ADD("slave", SH2, MASTER_CLOCK_352/2) // 28.6364 MHz + MCFG_CPU_PROGRAM_MAP(stv_mem) + MCFG_CPU_CONFIG(sh2_conf_slave) + MCFG_TIMER_ADD_SCANLINE("slave_scantimer", saturn_slave_scanline, "screen", 0, 1) + + MCFG_CPU_ADD("audiocpu", M68000, 11289600) //11.2896 MHz + MCFG_CPU_PROGRAM_MAP(sound_mem) + + MCFG_MACHINE_START(stv) + MCFG_MACHINE_RESET(stv) + + MCFG_EEPROM_93C46_ADD("eeprom") /* Actually 93c45 */ + + MCFG_TIMER_ADD("sector_timer", stv_sector_cb) + MCFG_TIMER_ADD("sh1_cmd", stv_sh1_sim) + + /* video hardware */ + MCFG_VIDEO_ATTRIBUTES(VIDEO_UPDATE_AFTER_VBLANK) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(MASTER_CLOCK_320/8, 427, 0, 320, 263, 0, 224) + #if NEW_VIDEO_CODE + MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32) + MCFG_SCREEN_UPDATE(saturn) + MCFG_PALETTE_LENGTH(2048+(2048*2))//standard palette + extra memory for rgb brightness. (TODO: remove AT LEAST the latter) + #else + MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB15) + MCFG_SCREEN_UPDATE(stv_vdp2) + MCFG_PALETTE_LENGTH(2048+(2048*2))//standard palette + extra memory for rgb brightness. + #endif + + MCFG_GFXDECODE(stv) + + MCFG_VIDEO_START(stv_vdp2) + + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + + MCFG_SOUND_ADD("scsp", SCSP, 0) + MCFG_SOUND_CONFIG(scsp_config) + MCFG_SOUND_ROUTE(0, "lspeaker", 1.0) + MCFG_SOUND_ROUTE(1, "rspeaker", 1.0) + + MCFG_SOUND_ADD("cdda", CDDA, 0) + MCFG_SOUND_ROUTE(0, "lspeaker", 1.0) + MCFG_SOUND_ROUTE(1, "rspeaker", 1.0) +MACHINE_CONFIG_END + +struct stv_cart_region +{ + const char *tag; + int slot; + const char *region; +}; + +static const struct stv_cart_region stv_cart_table[] = +{ + { "cart1", 0, "game0" }, + { "cart2", 1, "game1" }, + { "cart3", 2, "game2" }, + { "cart4", 3, "game3" }, + { 0 } +}; + +static DEVICE_IMAGE_LOAD( stv_cart ) +{ +// saturn_state *state = image.device().machine().driver_data<saturn_state>(); + const struct stv_cart_region *stv_cart = &stv_cart_table[0], *this_cart; + //const char *pcb_name; + + /* First, determine where this cart has to be loaded */ + while (stv_cart->tag) + { + if (strcmp(stv_cart->tag, image.device().tag()) == 0) + break; + + stv_cart++; + } + + this_cart = stv_cart; + + if (image.software_entry() == NULL) + return IMAGE_INIT_FAIL; + + UINT8 *ROM = image.device().machine().region(this_cart->region)->base(); + UINT32 length = image.get_software_region_length("rom"); + + memcpy(ROM, image.get_software_region("rom"), length); + + /* fix endianess */ + { + UINT8 j[4]; + int i; + + for(i=0;i<length;i+=4) + { + j[0] = ROM[i]; + j[1] = ROM[i+1]; + j[2] = ROM[i+2]; + j[3] = ROM[i+3]; + ROM[i] = j[3]; + ROM[i+1] = j[2]; + ROM[i+2] = j[1]; + ROM[i+3] = j[0]; + } + } + + //if ((pcb_name = image.get_feature("pcb_type")) == NULL) + // return IMAGE_INIT_FAIL; + + return IMAGE_INIT_PASS; +} + + +#define MCFG_STV_CARTSLOT_ADD(_tag) \ + MCFG_CARTSLOT_ADD(_tag) \ + MCFG_CARTSLOT_INTERFACE("stv_cart") \ + MCFG_CARTSLOT_LOAD(stv_cart) + +MACHINE_CONFIG_FRAGMENT( stv_cartslot ) + MCFG_STV_CARTSLOT_ADD("cart1") + MCFG_STV_CARTSLOT_ADD("cart2") + MCFG_STV_CARTSLOT_ADD("cart3") + MCFG_STV_CARTSLOT_ADD("cart4") + + MCFG_SOFTWARE_LIST_ADD("cart_list","stv") +MACHINE_CONFIG_END + +static MACHINE_CONFIG_DERIVED( stv_slot, stv ) + MCFG_FRAGMENT_ADD( stv_cartslot ) +MACHINE_CONFIG_END + + +static void saturn_init_driver(running_machine &machine, int rgn) +{ + saturn_state *state = machine.driver_data<saturn_state>(); + + state->m_saturn_region = rgn; + state->m_vdp2.pal = (rgn == 12) ? 1 : 0; + + // set compatible options + sh2drc_set_options(machine.device("maincpu"), SH2DRC_STRICT_VERIFY|SH2DRC_STRICT_PCREL); + sh2drc_set_options(machine.device("slave"), SH2DRC_STRICT_VERIFY|SH2DRC_STRICT_PCREL); + + /* amount of time to boost interleave for on MINIT / SINIT, needed for communication to work */ + state->m_minit_boost = 400; + state->m_sinit_boost = 400; + state->m_minit_boost_timeslice = attotime::zero; + state->m_sinit_boost_timeslice = attotime::zero; + + state->m_scu_regs = auto_alloc_array(machine, UINT32, 0x100/4); + state->m_scsp_regs = auto_alloc_array(machine, UINT16, 0x1000/2); + state->m_cart_dram = auto_alloc_array(machine, UINT32, 0x400000/4); + state->m_backupram = auto_alloc_array(machine, UINT8, 0x8000); + state->m_cart_backupram = auto_alloc_array(machine, UINT8, 0x400000); +} + +static DRIVER_INIT( saturnus ) +{ + saturn_init_driver(machine, 4); +} + +static DRIVER_INIT( saturneu ) +{ + saturn_init_driver(machine, 12); +} + +static DRIVER_INIT( saturnjp ) +{ + saturn_init_driver(machine, 1); +} + + +/* Japanese Saturn */ +ROM_START(saturnjp) + ROM_REGION( 0x480000, "maincpu", ROMREGION_ERASEFF ) /* SH2 code */ + ROM_SYSTEM_BIOS(0, "101", "Japan v1.01 (941228)") + ROMX_LOAD("sega_101.bin", 0x00000000, 0x00080000, CRC(224b752c) SHA1(df94c5b4d47eb3cc404d88b33a8fda237eaf4720), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(1, "1003", "Japan v1.003 (941012)") + ROMX_LOAD("sega1003.bin", 0x00000000, 0x00080000, CRC(b3c63c25) SHA1(7b23b53d62de0f29a23e423d0fe751dfb469c2fa), ROM_BIOS(2)) + ROM_SYSTEM_BIOS(2, "100", "Japan v1.00 (940921)") + ROMX_LOAD("sega_100.bin", 0x00000000, 0x00080000, CRC(2aba43c2) SHA1(2b8cb4f87580683eb4d760e4ed210813d667f0a2), ROM_BIOS(3)) + ROM_CART_LOAD("cart", 0x080000, 0x400000, ROM_NOMIRROR | ROM_OPTIONAL) + ROM_REGION( 0x080000, "slave", 0 ) /* SH2 code */ + ROM_COPY( "maincpu",0,0,0x080000) +ROM_END + +/* Overseas Saturn */ +ROM_START(saturn) + ROM_REGION( 0x480000, "maincpu", ROMREGION_ERASEFF ) /* SH2 code */ + ROM_SYSTEM_BIOS(0, "101a", "Overseas v1.01a (941115)") + /* Confirmed by ElBarto */ + ROMX_LOAD("mpr-17933.bin", 0x00000000, 0x00080000, CRC(4afcf0fa) SHA1(faa8ea183a6d7bbe5d4e03bb1332519800d3fbc3), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(1, "100a", "Overseas v1.00a (941115)") + ROMX_LOAD("sega_100a.bin", 0x00000000, 0x00080000, CRC(f90f0089) SHA1(3bb41feb82838ab9a35601ac666de5aacfd17a58), ROM_BIOS(2)) + ROM_CART_LOAD("cart", 0x080000, 0x400000, ROM_NOMIRROR | ROM_OPTIONAL) + ROM_REGION( 0x080000, "slave", 0 ) /* SH2 code */ + ROM_COPY( "maincpu",0,0,0x080000) +ROM_END + +ROM_START(saturneu) + ROM_REGION( 0x480000, "maincpu", ROMREGION_ERASEFF ) /* SH2 code */ + ROM_SYSTEM_BIOS(0, "101a", "Overseas v1.01a (941115)") + /* Confirmed by ElBarto */ + ROMX_LOAD("mpr-17933.bin", 0x00000000, 0x00080000, CRC(4afcf0fa) SHA1(faa8ea183a6d7bbe5d4e03bb1332519800d3fbc3), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(1, "100a", "Overseas v1.00a (941115)") + ROMX_LOAD("sega_100a.bin", 0x00000000, 0x00080000, CRC(f90f0089) SHA1(3bb41feb82838ab9a35601ac666de5aacfd17a58), ROM_BIOS(2)) + ROM_CART_LOAD("cart", 0x080000, 0x400000, ROM_NOMIRROR | ROM_OPTIONAL) + ROM_REGION( 0x080000, "slave", 0 ) /* SH2 code */ + ROM_COPY( "maincpu",0,0,0x080000) +ROM_END + +ROM_START(vsaturn) + ROM_REGION( 0x480000, "maincpu", ROMREGION_ERASEFF ) /* SH2 code */ + ROM_LOAD("vsaturn.bin", 0x00000000, 0x00080000, CRC(e4d61811) SHA1(4154e11959f3d5639b11d7902b3a393a99fb5776)) + ROM_CART_LOAD("cart", 0x080000, 0x400000, ROM_NOMIRROR | ROM_OPTIONAL) + ROM_REGION( 0x080000, "slave", 0 ) /* SH2 code */ + ROM_COPY( "maincpu",0,0,0x080000) +ROM_END + +ROM_START(hisaturn) + ROM_REGION( 0x480000, "maincpu", ROMREGION_ERASEFF ) /* SH2 code */ + ROM_LOAD("hisaturn.bin", 0x00000000, 0x00080000, CRC(721e1b60) SHA1(49d8493008fa715ca0c94d99817a5439d6f2c796)) + ROM_CART_LOAD("cart", 0x080000, 0x400000, ROM_NOMIRROR | ROM_OPTIONAL) + ROM_REGION( 0x080000, "slave", 0 ) /* SH2 code */ + ROM_COPY( "maincpu",0,0,0x080000) +ROM_END + +/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ +CONS( 1994, saturn, 0, 0, saturn, saturn, saturnus, "Sega", "Saturn (USA)", GAME_NOT_WORKING ) +CONS( 1994, saturnjp, saturn, 0, saturn, saturn, saturnjp, "Sega", "Saturn (Japan)", GAME_NOT_WORKING ) +CONS( 1994, saturneu, saturn, 0, saturn, saturn, saturneu, "Sega", "Saturn (PAL)", GAME_NOT_WORKING ) +CONS( 1995, vsaturn, saturn, 0, saturn, saturn, saturnjp, "JVC", "V-Saturn", GAME_NOT_WORKING ) +CONS( 1995, hisaturn, saturn, 0, saturn, saturn, saturnjp, "Hitachi", "HiSaturn", GAME_NOT_WORKING ) + +#include "stv.c" |