diff --git a/.gitattributes b/.gitattributes index 3967ca3d794..68f852c12a8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3271,6 +3271,7 @@ src/mame/audio/trackfld.c svneol=native#text/plain src/mame/audio/trackfld.h svneol=native#text/plain src/mame/audio/triplhnt.c svneol=native#text/plain src/mame/audio/turbo.c svneol=native#text/plain +src/mame/audio/turrett.c svneol=native#text/plain src/mame/audio/tx1.c svneol=native#text/plain src/mame/audio/vicdual.c svneol=native#text/plain src/mame/audio/videopin.c svneol=native#text/plain @@ -5212,6 +5213,7 @@ src/mame/includes/tumbleb.h svneol=native#text/plain src/mame/includes/tumblep.h svneol=native#text/plain src/mame/includes/tunhunt.h svneol=native#text/plain src/mame/includes/turbo.h svneol=native#text/plain +src/mame/includes/turrett.h svneol=native#text/plain src/mame/includes/tutankhm.h svneol=native#text/plain src/mame/includes/twin16.h svneol=native#text/plain src/mame/includes/twincobr.h svneol=native#text/plain @@ -6582,6 +6584,7 @@ src/mame/video/tumbleb.c svneol=native#text/plain src/mame/video/tumblep.c svneol=native#text/plain src/mame/video/tunhunt.c svneol=native#text/plain src/mame/video/turbo.c svneol=native#text/plain +src/mame/video/turrett.c svneol=native#text/plain src/mame/video/tutankhm.c svneol=native#text/plain src/mame/video/twin16.c svneol=native#text/plain src/mame/video/twincobr.c svneol=native#text/plain diff --git a/src/emu/machine/idehd.h b/src/emu/machine/idehd.h index fb1fa5db11d..32c17f6d947 100644 --- a/src/emu/machine/idehd.h +++ b/src/emu/machine/idehd.h @@ -60,8 +60,9 @@ protected: UINT8 m_num_sectors; UINT8 m_num_heads; + virtual UINT32 lba_address(); + private: - UINT32 lba_address(); void set_geometry(UINT8 sectors, UINT8 heads) { m_num_sectors = sectors; m_num_heads = heads; } void finished_read(); void finished_write(); diff --git a/src/mame/audio/turrett.c b/src/mame/audio/turrett.c new file mode 100644 index 00000000000..00771465004 --- /dev/null +++ b/src/mame/audio/turrett.c @@ -0,0 +1,162 @@ +/*************************************************************************** + + Turret Tower sound hardware + +****************************************************************************/ + +#include "emu.h" +#include "includes/turrett.h" + + + +//------------------------------------------------- +// turrett_device - constructor +//------------------------------------------------- + +turrett_device::turrett_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TURRETT, "Turret Tower Sound", tag, owner, clock, "ttsnd", __FILE__), + device_sound_interface(mconfig, *this), + device_memory_interface(mconfig, *this), + m_space_config("ttsound", ENDIANNESS_LITTLE, 16, 28, 0, NULL) +{ +} + + +//------------------------------------------------- +// memory_space_config - configure address space +//------------------------------------------------- + +const address_space_config *turrett_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == 0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// device_start - initialize the device +//------------------------------------------------- + +void turrett_device::device_start() +{ + // Find our direct access + m_direct = &space().direct(); + + // Create the sound stream + m_stream = machine().sound().stream_alloc(*this, 0, 2, 44100, this); + + // Create the volume table + for (int i = 0; i < 0x4f; ++i) + m_volume_table[i] = 65536 * powf(2.0, (-0.375/4) * i); + + // Last entry is effectively mute + m_volume_table[0x4f] = 0; + + // Register state for saving + for (int ch = 0; ch < SOUND_CHANNELS; ++ch) + { + save_item(NAME(m_channels[ch].m_address), ch); + save_item(NAME(m_channels[ch].m_volume), ch); + save_item(NAME(m_channels[ch].m_playing), ch); + } +} + + +//------------------------------------------------- +// device_reset - reset the device +//------------------------------------------------- + +void turrett_device::device_reset() +{ + for (int ch = 0; ch < SOUND_CHANNELS; ++ch) + m_channels[ch].m_playing = false; +} + + +//------------------------------------------------- +// sound_stream_update - update sound stream +//------------------------------------------------- + +void turrett_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + // Silence the buffers + memset(outputs[0], 0x00, sizeof(stream_sample_t) * samples); + memset(outputs[1], 0x00, sizeof(stream_sample_t) * samples); + + for (int ch = 0; ch < SOUND_CHANNELS; ++ch) + { + stream_sample_t *l = outputs[0]; + stream_sample_t *r = outputs[1]; + + if (m_channels[ch].m_playing) + { + UINT32 &addr = m_channels[ch].m_address; + INT32 lvol = (m_channels[ch].m_volume >> 16) & 0xff; + INT32 rvol = m_channels[ch].m_volume & 0xff; + + lvol = m_volume_table[lvol]; + rvol = m_volume_table[rvol]; + + // Channels 30 and 31 expect interleaved stereo samples + UINT32 incr = (ch >= 30) ? 2 : 1; + + for (int s = 0; s < samples; ++s) + { + INT16 sample = m_direct->read_raw_word(addr << 1); + + if ((UINT16)sample == 0x8000) + { + m_channels[ch].m_playing = false; + break; + } + + addr += incr; + + *l++ += (sample * lvol) >> 17; + *r++ += (sample * rvol) >> 17; + } + } + } +} + + +//------------------------------------------------- +// read - host CPU read access +//------------------------------------------------- + +READ32_MEMBER( turrett_device::read ) +{ + m_stream->update(); + + int ch = offset & 0x3f; + + return m_channels[ch].m_playing << 31; +} + + +//------------------------------------------------- +// write - host CPU write access +//------------------------------------------------- + +WRITE32_MEMBER( turrett_device::write ) +{ + m_stream->update(); + + int ch = offset & 0x3f; + + if (offset < 0x100/4) + { + if (data == 0) + { + m_channels[ch].m_playing = false; + } + else + { + m_channels[ch].m_address = data; + m_channels[ch].m_playing = true; + } + } + else + { + m_channels[ch].m_volume = data; + } +} diff --git a/src/mame/drivers/turrett.c b/src/mame/drivers/turrett.c index 8467bb4a3ce..a9b202cb8b3 100644 --- a/src/mame/drivers/turrett.c +++ b/src/mame/drivers/turrett.c @@ -1,139 +1,390 @@ -/* +/*************************************************************************** -Turret Tower by Dell Electronics + Turret Tower by Dell Electronics -PCB Info -======== - -Silkscreened Copyright (c) 2001 Dell Electroinics Labs, Ltd - -Samsung SV2001H Hard drive stickered (c)DELL V1.XX - TOCAB0181 - TURRET TOWER - -IDT 79R3041-25J - XG0110P - -Xilinx Spartan XCS30XL x2 - PQ208AKP0105 - D1164035A - 4c - - -Xilinx XC9572 - PC84AEM0109 - A1172748A - 10C - -IDT 71124 x8 - S12Y - N0048M - -COMPAQ MT16LSDT1664AG-10CY5 SDRAM stick x2 - -.u7 AM29F040B stickered U7 (c)DELL - -.u8 AM29F040B stickered U8 (c)DELL - -.u12 AM29F040B stickered U12 (c)DELL - -.u13 AM29F040B stickered U13 (c)DELL - -.u29 stickered TTML(1) (c) DELL Unmarked chip looks like 28 PIN DIP PLD - - -CHDMAN info -Version 0.128 -Input offset 511 -Cycliders 2438 -Heads 255 -Sectors 63 -Bytes/Sector 512 -Sectors/Hunk 8 -Logical size 20,053,232,640 - -Windows showed a 5.94 gig partion empty and a 12.74 unallocated partition - - -*/ + driver by Phil Bennett +****************************************************************************/ #include "emu.h" #include "cpu/mips/r3000.h" +#include "machine/ataintf.h" +#include "includes/turrett.h" -class turrett_state : public driver_device + +/************************************* + * + * Definitions + * + *************************************/ + +#define R3041_CLOCK XTAL_25MHz + + + +/************************************* + * + * Machine initialization + * + *************************************/ + +void turrett_state::machine_start() { -public: - turrett_state(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag), - m_maincpu(*this, "maincpu") - { } + // Allocate memory for the two 256kx16 banks of video RAM + m_video_ram[0] = (UINT16*)auto_alloc_array(machine(), UINT16, VRAM_BANK_WORDS); + m_video_ram[1] = (UINT16*)auto_alloc_array(machine(), UINT16, VRAM_BANK_WORDS); - UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + // Register our state for saving + save_pointer(NAME(m_video_ram[0]), VRAM_BANK_WORDS); + save_pointer(NAME(m_video_ram[1]), VRAM_BANK_WORDS); + save_item(NAME(m_inputs_active)); + save_item(NAME(m_last_pixel)); + save_item(NAME(m_video_ctrl)); + save_item(NAME(m_video_fade)); + save_item(NAME(m_x_pos)); + save_item(NAME(m_x_start)); + save_item(NAME(m_x_mod)); + save_item(NAME(m_dx)); + save_item(NAME(m_y_pos)); + save_item(NAME(m_scale_cnt_y)); + save_item(NAME(m_scale_cnt_x)); + save_item(NAME(m_skip_x)); + save_item(NAME(m_skip_y)); + save_item(NAME(m_scale)); + save_item(NAME(m_hotspot_x)); + save_item(NAME(m_hotspot_y)); + save_item(NAME(m_dma_idle)); + save_item(NAME(m_dma_addr)); + save_item(NAME(m_ipt_val)); + save_item(NAME(m_frame)); + save_item(NAME(m_adc)); -protected: - - // devices - required_device m_maincpu; - - // driver_device overrides - virtual void video_start(); -}; - - -#define R3041_CLOCK 25000000 - - -void turrett_state::video_start() -{ + m_dma_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(turrett_state::dma_complete), this)); } -UINT32 turrett_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) + +void turrett_state::machine_reset() { - return 0; + m_dma_idle = true; + m_frame = 0; + m_adc = 0; + m_inputs_active = 0; } + +/************************************* + * + * Memory maps + * + *************************************/ + static ADDRESS_MAP_START( cpu_map, AS_PROGRAM, 32, turrett_state ) AM_RANGE(0x00000000, 0x0007ffff) AM_RAM - AM_RANGE(0x1fc00000, 0x1fdfffff) AM_ROM AM_REGION("maincpu", 0) AM_RANGE(0x02000010, 0x02000013) AM_RAM AM_RANGE(0x02000040, 0x02000043) AM_RAM AM_RANGE(0x02000050, 0x02000053) AM_RAM AM_RANGE(0x02000060, 0x02000063) AM_RAM - AM_RANGE(0x02000070, 0x02000073) AM_RAM - AM_RANGE(0x04000100, 0x04000103) AM_RAM - AM_RANGE(0x08000000, 0x08000003) AM_RAM - AM_RANGE(0x08000004, 0x08000007) AM_RAM - AM_RANGE(0x08000008, 0x0800000b) AM_RAM - AM_RANGE(0x0800000c, 0x0800000f) AM_RAM + AM_RANGE(0x02000070, 0x02000073) AM_RAM // TODO: What are these? + AM_RANGE(0x04000000, 0x0400000f) AM_WRITE(dma_w) + AM_RANGE(0x04000100, 0x04000103) AM_READWRITE(int_r, int_w) + AM_RANGE(0x04000200, 0x040003ff) AM_DEVREADWRITE("ttsound", turrett_device, read, write) + AM_RANGE(0x08000000, 0x0800000f) AM_READWRITE(video_r, video_w) + AM_RANGE(0x08000200, 0x080003ff) AM_DEVREADWRITE16("ata", ata_interface_device, read_cs0, write_cs0, 0xffffffff) + AM_RANGE(0x1fc00000, 0x1fdfffff) AM_ROM AM_REGION("maincpu", 0) ADDRESS_MAP_END +static ADDRESS_MAP_START( turrett_sound_map, AS_0, 16, turrett_state ) + AM_RANGE(0x0000000, 0x7ffffff) AM_RAM AM_SHARE("bank_a") + AM_RANGE(0x8000000, 0xfffffff) AM_RAM AM_SHARE("bank_b") +ADDRESS_MAP_END + + + +/************************************* + * + * Port definitions + * + *************************************/ + static INPUT_PORTS_START( turrett ) + PORT_START("PORT 0X") + PORT_BIT( 0x3f, 0x00, IPT_AD_STICK_Y ) PORT_MINMAX(0x20,0x1f) PORT_SENSITIVITY(60) PORT_KEYDELTA(2) + + PORT_START("PORT 4X") + PORT_BIT( 0x3f, 0x00, IPT_AD_STICK_X ) PORT_MINMAX(0x20,0x1f) PORT_SENSITIVITY(60) PORT_KEYDELTA(2) + + PORT_START("PORT CX") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CHANGED_MEMBER(DEVICE_SELF, turrett_state, ipt_change, (void *)0x00000100) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_CHANGED_MEMBER(DEVICE_SELF, turrett_state, ipt_change, (void *)0x00000200) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BILL1 ) PORT_CHANGED_MEMBER(DEVICE_SELF, turrett_state, ipt_change, (void *)0x00000400) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_SERVICE ) PORT_CHANGED_MEMBER(DEVICE_SELF, turrett_state, ipt_change, (void *)0x00000800) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_CHANGED_MEMBER(DEVICE_SELF, turrett_state, ipt_change, (void *)0x00001000) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_COIN2 ) PORT_CHANGED_MEMBER(DEVICE_SELF, turrett_state, ipt_change, (void *)0x00002000) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_START ) PORT_CHANGED_MEMBER(DEVICE_SELF, turrett_state, ipt_change, (void *)0x00004000) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CHANGED_MEMBER(DEVICE_SELF, turrett_state, ipt_change, (void *)0x00008000) + + PORT_START("PORT DX") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CHANGED_MEMBER(DEVICE_SELF, turrett_state, ipt_change, (void *)0x00010000) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_CHANGED_MEMBER(DEVICE_SELF, turrett_state, ipt_change, (void *)0x00020000) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_CHANGED_MEMBER(DEVICE_SELF, turrett_state, ipt_change, (void *)0x00040000) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CHANGED_MEMBER(DEVICE_SELF, turrett_state, ipt_change, (void *)0x00080000) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CHANGED_MEMBER(DEVICE_SELF, turrett_state, ipt_change, (void *)0x00100000) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CHANGED_MEMBER(DEVICE_SELF, turrett_state, ipt_change, (void *)0x00200000) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CHANGED_MEMBER(DEVICE_SELF, turrett_state, ipt_change, (void *)0x00400000) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CHANGED_MEMBER(DEVICE_SELF, turrett_state, ipt_change, (void *)0x00800000) + + PORT_START("PORT EX") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Floor mat") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Door Lock") PORT_TOGGLE + + PORT_START("PORT FX") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("Seat Belt") PORT_TOGGLE + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("Home") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON7 ) PORT_NAME("Emergency Stop") PORT_TOGGLE INPUT_PORTS_END +/************************************* + * + * I/O handling + * + *************************************/ + +READ_LINE_MEMBER( turrett_state::sbrc2_r ) +{ + return machine().primary_screen->vblank(); +} + + +READ_LINE_MEMBER( turrett_state::sbrc3_r ) +{ + return m_dma_idle; +} + + +READ32_MEMBER( turrett_state::int_r ) +{ + return update_inputs() << 24; +} + + +WRITE32_MEMBER( turrett_state::int_w ) +{ + // TODO + logerror("Output write: %08x\n", data); +} + + +UINT32 turrett_state::update_inputs(void) +{ + UINT32 val = 0; + + // TODO: Prioritise? + if (m_inputs_active) + { + if (m_inputs_active & 0x00000001) + { + val = 0x00 | (ioport("PORT 0X")->read() & 0x3f); + m_inputs_active &= ~1; + } + else if (m_inputs_active & 0x00000002) + { + val = 0x40 | (ioport("PORT 4X")->read() & 0x3f); + m_inputs_active &= ~2; + } + else if (m_inputs_active & 0x0000ff00) + { + UINT32 data = ioport("PORT CX")->read(); + UINT32 bits = m_inputs_active >> 8; + + val = 0xc0; + + for (int i = 0; i < 8; ++i) + { + if (bits & (1 << i)) + { + val |= i << 1; + val |= (data >> i) & 1; + m_inputs_active &= ~(1 << (i + 8)); + break; + } + } + } + else if (m_inputs_active & 0x00ff0000) + { + UINT32 data = ioport("PORT DX")->read(); + UINT32 bits = m_inputs_active >> 16; + + val = 0xd0; + + for (int i = 0; i < 8; ++i) + { + if (bits & (1 << i)) + { + val |= i << 1; + val |= (data >> i) & 1; + m_inputs_active &= ~(1 << (i + 16)); + break; + } + } + } + else if (m_inputs_active & 0x01000000) + { + val = 0xe0 | ioport("PORT EX")->read(); + m_inputs_active &= ~0x01000000; + } + else if (m_inputs_active & 0x02000000) + { + val = 0xf0 | ioport("PORT FX")->read(); + m_inputs_active &= ~0x02000000; + } + } + + // Update IRQ state + m_maincpu->set_input_line(R3000_IRQ1, m_inputs_active ? ASSERT_LINE : CLEAR_LINE); + return val; +} + + +INPUT_CHANGED_MEMBER( turrett_state::ipt_change ) +{ + int p = (FPTR)param; + + if (newval != oldval) + { + // TODO: Tidy this up + if (p & (0x02000000 | 0x00000200 | 0x00000400 | 0x00001000 | 0x00002000)) + { + if (newval == 0) + { + m_inputs_active |= p; + m_maincpu->set_input_line(R3000_IRQ1, ASSERT_LINE); + } + } + else + { + m_inputs_active |= p; + m_maincpu->set_input_line(R3000_IRQ1, ASSERT_LINE); + } + } +} + + + +/************************************* + * + * Interrupts + * + *************************************/ + +INTERRUPT_GEN_MEMBER( turrett_state::vblank ) +{ + if (m_frame) + m_inputs_active |= 0x01000000; + else + m_inputs_active |= 0x02000000; + + m_frame ^= 1; + m_maincpu->set_input_line(R3000_IRQ1, ASSERT_LINE); +} + + +INTERRUPT_GEN_MEMBER( turrett_state::adc ) +{ + if (m_adc) + m_inputs_active |= 0x00000001; + else + m_inputs_active |= 0x00000002; + + m_adc ^= 1; + m_maincpu->set_input_line(R3000_IRQ1, ASSERT_LINE); +} + +/************************************* + * + * Hard drive + * + *************************************/ + +/// HACK: The game expects a different LBA mapping to the standard HDD. +/// The reason for this is unknown. + +#include "machine/idehd.h" + +extern const device_type TURRETT_HARDDISK; + +class turrett_hdd : public ide_hdd_device +{ +public: + turrett_hdd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ide_hdd_device(mconfig, TURRETT_HARDDISK, "Turrett Tower HDD", tag, owner, clock, "turrett_hdd", __FILE__) + { + } + + virtual UINT32 lba_address() + { + if (m_device_head & IDE_DEVICE_HEAD_L) + return (((m_device_head & IDE_DEVICE_HEAD_HS) << 24) | (m_cylinder_high << 16) | (m_cylinder_low << 8) | m_sector_number) - 63; + + return ata_mass_storage_device::lba_address(); + } +}; + +const device_type TURRETT_HARDDISK = &device_creator; + +SLOT_INTERFACE_START(turrett_devices) + SLOT_INTERFACE("hdd", TURRETT_HARDDISK) +SLOT_INTERFACE_END + +/************************************* + * + * Machine driver + * + *************************************/ + static MACHINE_CONFIG_START( turrett, turrett_state ) + /* basic machine hardware */ MCFG_CPU_ADD("maincpu", R3041, R3041_CLOCK) MCFG_R3000_ENDIANNESS(ENDIANNESS_BIG) + MCFG_R3000_BRCOND2_INPUT(READLINE(turrett_state, sbrc2_r)) + MCFG_R3000_BRCOND3_INPUT(READLINE(turrett_state, sbrc3_r)) MCFG_CPU_PROGRAM_MAP(cpu_map) + MCFG_CPU_VBLANK_INT_DRIVER("screen", turrett_state, vblank) + MCFG_CPU_PERIODIC_INT_DRIVER(turrett_state, adc, 60) + + MCFG_ATA_INTERFACE_ADD("ata", turrett_devices, "hdd", NULL, true) /* video hardware */ MCFG_SCREEN_ADD("screen", RASTER) - MCFG_SCREEN_REFRESH_RATE(60) - MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0)) + // TODO: Likely not correct. Refresh rate empirically determined + // to ensure in-sync streaming sound + MCFG_SCREEN_RAW_PARAMS(4000000, 512, 0, 336, 259, 0, 244) MCFG_SCREEN_UPDATE_DRIVER(turrett_state, screen_update) - MCFG_SCREEN_SIZE(64*8, 32*8) - MCFG_SCREEN_VISIBLE_AREA(0, 64*8-1, 0*8, 32*8-1) + MCFG_PALETTE_LENGTH(32768) + MCFG_PALETTE_INIT_OVERRIDE(driver_device, RRRRR_GGGGG_BBBBB) - MCFG_PALETTE_LENGTH(0x2000) + /* sound hardware */ + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + + MCFG_DEVICE_ADD("ttsound", TURRETT, R3041_CLOCK) // ? + MCFG_DEVICE_ADDRESS_MAP(AS_0, turrett_sound_map) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0) MACHINE_CONFIG_END + + /************************************* + * + * ROM definition + * + *************************************/ + ROM_START( turrett ) ROM_REGION( 0x200000, "maincpu", 0 ) ROM_LOAD32_BYTE( "turret.u13", 0x000000, 0x080000, CRC(85287007) SHA1(990b954905c66340d3e88918b2f8cc7f1b9c7cf4) ) @@ -141,9 +392,16 @@ ROM_START( turrett ) ROM_LOAD32_BYTE( "turret.u8", 0x000002, 0x080000, CRC(ddff4898) SHA1(a8f859a0dcab8ec83fbfe255d58b3e644933b923) ) ROM_LOAD32_BYTE( "turret.u7", 0x000003, 0x080000, CRC(fa8b5a5a) SHA1(658e9eeadc9c70185973470565d562c76f4fcdd7) ) - DISK_REGION( "disks" ) + DISK_REGION( "ata:0:hdd:image" ) DISK_IMAGE( "turrett", 0, SHA1(b0c98c5876870dd8b3e37a38fe35846c9e011df4) ) ROM_END -GAME( 2001, turrett, 0, turrett, turrett, driver_device, 0, ROT0, "Dell Electronics (Namco license)", "Turret Tower", GAME_IS_SKELETON ) + +/************************************* + * + * Game driver + * + *************************************/ + +GAME( 2001, turrett, 0, turrett, turrett, driver_device, 0, ROT0, "Dell Electronics (Namco license)", "Turret Tower", 0 ) diff --git a/src/mame/includes/turrett.h b/src/mame/includes/turrett.h new file mode 100644 index 00000000000..4fede71ae51 --- /dev/null +++ b/src/mame/includes/turrett.h @@ -0,0 +1,128 @@ +/*************************************************************************** + + Turret Tower hardware + +****************************************************************************/ + +#include "machine/ataintf.h" + + +class turrett_state : public driver_device +{ +public: + turrett_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_ata(*this, "ata"), + m_bank_a(*this, "bank_a"), + m_bank_b(*this, "bank_b") {} + + // constants + static const UINT32 X_VISIBLE = 336; + static const UINT32 Y_VISIBLE = 244; + static const UINT32 DIMM_BANK_WORDS = 128 * 1024 * 1024 / 2; + static const UINT32 DIMM_BANK_MASK = DIMM_BANK_WORDS - 1; + static const UINT32 VRAM_BANK_WORDS = 256 * 1024; + + // devices + required_device m_maincpu; + required_device m_ata; + required_shared_ptr m_bank_a; + required_shared_ptr m_bank_b; + + // handlers + DECLARE_WRITE32_MEMBER(dma_w); + DECLARE_READ32_MEMBER(video_r); + DECLARE_WRITE32_MEMBER(video_w); + DECLARE_READ32_MEMBER(int_r); + DECLARE_WRITE32_MEMBER(int_w); + DECLARE_READ32_MEMBER(sound_r); + DECLARE_WRITE32_MEMBER(sound_w); + INPUT_CHANGED_MEMBER(ipt_change); + DECLARE_READ_LINE_MEMBER(sbrc2_r); + DECLARE_READ_LINE_MEMBER(sbrc3_r); + + TIMER_CALLBACK_MEMBER(dma_complete); + INTERRUPT_GEN_MEMBER(vblank); + INTERRUPT_GEN_MEMBER(adc); + + // functions + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + UINT32 write_video_ram(UINT16 data); + void update_video_addr(void); + UINT32 update_inputs(void); + + // members + emu_timer *m_dma_timer; + UINT32 m_inputs_active; + UINT16 *m_video_ram[2]; + UINT16 m_last_pixel; + INT32 m_video_ctrl; + UINT16 m_video_fade; + INT16 m_x_pos; + INT16 m_x_start; + INT16 m_x_mod; + INT16 m_dx; + INT16 m_y_pos; + INT16 m_scale_cnt_y; + INT16 m_scale_cnt_x; + bool m_skip_x; + bool m_skip_y; + INT16 m_scale; + INT16 m_hotspot_x; + INT16 m_hotspot_y; + bool m_dma_idle; + UINT32 m_dma_addr[2]; + UINT32 m_ipt_val; + UINT8 m_frame; + UINT8 m_adc; + +protected: + // driver_device overrides + virtual void machine_reset(); + virtual void machine_start(); +}; + + +class turrett_device : public device_t, + public device_sound_interface, + public device_memory_interface +{ + static const UINT32 SOUND_CHANNELS = 32; + +public: + // construction/destruction + turrett_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ32_MEMBER(read); + DECLARE_WRITE32_MEMBER(write); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + const address_space_config m_space_config; + +private: + direct_read_data *m_direct; + sound_stream *m_stream; + + struct + { + UINT32 m_address; + UINT32 m_volume; + bool m_playing; + } m_channels[SOUND_CHANNELS]; + + INT32 m_volume_table[0x50]; +}; + +// device type definition +const device_type TURRETT = &device_creator; diff --git a/src/mame/mame.mak b/src/mame/mame.mak index e03a5d52ddb..cf2557d38cf 100644 --- a/src/mame/mame.mak +++ b/src/mame/mame.mak @@ -1351,7 +1351,7 @@ $(MAMEOBJ)/namco.a: \ $(DRIVERS)/tankbatt.o $(VIDEO)/tankbatt.o \ $(DRIVERS)/tceptor.o $(VIDEO)/tceptor.o \ $(DRIVERS)/toypop.o $(VIDEO)/toypop.o \ - $(DRIVERS)/turrett.o \ + $(DRIVERS)/turrett.o $(AUDIO)/turrett.o $(VIDEO)/turrett.o \ $(DRIVERS)/warpwarp.o $(AUDIO)/geebee.o $(AUDIO)/warpwarp.o $(VIDEO)/warpwarp.o \ $(MACHINE)/namcoio.o \ $(MACHINE)/namco06.o \ diff --git a/src/mame/video/turrett.c b/src/mame/video/turrett.c new file mode 100644 index 00000000000..51e438e3389 --- /dev/null +++ b/src/mame/video/turrett.c @@ -0,0 +1,409 @@ +/************************************************************************* + + Turrett Tower video hardware + +*************************************************************************/ + +#include "emu.h" +#include "machine/idectrl.h" +#include "includes/turrett.h" + + + +inline UINT8 clamp_5bit(INT8 val) +{ + if (val < 0) + return 0; + + if (val > 31) + return 31; + + return val; +} + + +UINT32 turrett_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + int page = (m_video_ctrl & 1) ^ 1; + + const UINT16 *vram = m_video_ram[page]; + + INT8 fade_b = m_video_fade & 0x1f; + INT8 fade_g = (m_video_fade >> 5) & 0x1f; + INT8 fade_r = (m_video_fade >> 10) & 0x1f; + + if (m_video_fade & 0x8000) + { + fade_b = -fade_b; + fade_g = -fade_g; + fade_r = -fade_r; + } + + for (int y = cliprect.min_y; y <= cliprect.max_y; ++y) + { + const UINT16 *src = &vram[y * X_VISIBLE + cliprect.min_x]; + UINT16 *dest = &bitmap.pix16(y, cliprect.min_x); + + if (m_video_fade != 0) + { + for (int x = cliprect.min_x; x <= cliprect.max_x; ++x) + { + UINT16 srcpix = *src++; + + UINT8 src_b = srcpix & 0x1f; + UINT8 src_g = (srcpix >> 5) & 0x1f; + UINT8 src_r = (srcpix >> 10) & 0x1f; + + UINT8 dst_b = clamp_5bit(src_b + fade_b); + UINT8 dst_g = clamp_5bit(src_g + fade_g); + UINT8 dst_r = clamp_5bit(src_r + fade_r); + + *dest++ = (dst_r << 10) | (dst_g << 5) | dst_b; + } + } + else + { + for (int x = cliprect.min_x; x <= cliprect.max_x; ++x) + { + *dest++ = *src++ & 0x7fff; + } + } + } + + return 0; +} + + +UINT32 turrett_state::write_video_ram(UINT16 data) +{ + UINT32 clocks = 1; + + if (!m_skip_x && !m_skip_y) + { + // Handle hot spot test + if (m_x_pos == m_hotspot_x + && m_y_pos == (m_hotspot_y & 0xfff)) + { + m_hotspot_y |= 0x8000; + } + + if (m_x_pos >= 0 && m_x_pos < X_VISIBLE + && m_y_pos >= 0 && m_y_pos < Y_VISIBLE) + { + int address = m_y_pos * X_VISIBLE + m_x_pos; + + UINT16 *vramptr = &m_video_ram[m_video_ctrl & 1][address]; + UINT16 srcpix = data; + UINT16 dstpix = data; + + // Blending enabled? + if (data & 0x8000) + { + dstpix = *vramptr; + + UINT8 src_b = srcpix & 0x1f; + UINT8 src_g = (srcpix >> 5) & 0x1f; + UINT8 src_r = (srcpix >> 10) & 0x1f; + + UINT8 dst_b = dstpix & 0x1f; + UINT8 dst_g = (dstpix >> 5) & 0x1f; + UINT8 dst_r = (dstpix >> 10) & 0x1f; + + // Additive + if (m_video_ctrl & 2) + { + dst_b = clamp_5bit(src_b + dst_b); + dst_g = clamp_5bit(src_g + dst_g); + dst_r = clamp_5bit(src_r + dst_r); + } + else + { + // R always seems to be 0 for blended pixels + if ((src_g & 1) && (src_b & 1)) + { + dst_b = clamp_5bit(dst_b - src_b); + dst_g = clamp_5bit(dst_g - src_g); + dst_r = clamp_5bit(dst_r - src_r); + } + else + { + // 75% source, 25% destination? + dst_b = (src_b - (src_b >> 2)) + (dst_b >> 2); + dst_g = (src_g - (src_g >> 2)) + (dst_g >> 2); + dst_r = (src_r - (src_r >> 2)) + (dst_r >> 2); + } + } + clocks += 2; + *vramptr = (dst_r << 10) | (dst_g << 5) | dst_b; + } + else + { + clocks += 2; + *vramptr = srcpix; + } + } + } + update_video_addr(); + + return clocks; +} + + +void turrett_state::update_video_addr(void) +{ + // Handle auto-increment + if (m_dx == m_x_mod) + { + m_dx = 0; + m_scale_cnt_y += m_scale; + + if (m_scale_cnt_y & 0x800) + { + m_skip_y = false; + m_scale_cnt_y &= 0x7ff; + --m_y_pos; + m_x_pos = m_x_start; + } + else + { + m_skip_y = true; + } + } + else + { + ++m_dx; + m_scale_cnt_x += m_scale; + + if (m_scale_cnt_x & 0x800) + { + m_scale_cnt_x &= 0x7ff; + m_skip_x = false; + ++m_x_pos; + } + else + { + m_skip_x = true; + } + } +} + + +READ32_MEMBER( turrett_state::video_r ) +{ + UINT32 ret = 0; + + if (offset == 3 && mem_mask == 0x0000ffff) + { + // Collision detection flag + ret = m_hotspot_y & 0x8000; + } + else + { + fatalerror("Unhandled video read (%x %x)!", offset, mem_mask); + } + + return ret; +} + + +WRITE32_MEMBER( turrett_state::video_w ) +{ + switch (offset) + { + case 0: + { + if (mem_mask == 0xffff0000) + { + data >>= 16; + + // TODO: Merge with DMA code? + if ((data & 0xc400) == 0xc400) + { + // RLE word + int count = (data & 0x3ff) + 1; + + // TODO: Cycle stalling + while (count--) + write_video_ram(m_last_pixel); + } + else + { + write_video_ram(data); + + // Store current pixel + m_last_pixel = data; + } + } + else + { + m_video_ctrl = data & 3; + } + break; + } + case 1: + { + m_x_mod = data & 0xffff; + m_scale = 0x800 - (data >> 16); + break; + } + case 2: + { + m_y_pos = data & 0xffff; + m_x_pos = data >> 16; + + // Seems the logical place to set these + m_x_start = m_x_pos; + m_skip_x = false; + m_skip_y = false; + m_dx = 0; + break; + } + case 3: + { + if (mem_mask == 0xffff0000) + { + m_video_fade = data >> 16; + } + else if (mem_mask == 0x0000ffff) + { + if (data & 0x4000) + m_hotspot_y = data; + else + m_hotspot_x = data; + } + else + { + fatalerror("Unhandled"); + } + break; + } + default: + fatalerror("Unhandled video write: %x %x\n", offset, data); + } +} + + +TIMER_CALLBACK_MEMBER( turrett_state::dma_complete ) +{ + m_dma_idle = true; +} + + +WRITE32_MEMBER( turrett_state::dma_w ) +{ + int bank = ((offset & 2) >> 1) ^ 1; + + if ((offset & 1) == 0) + { + m_dma_addr[bank] = data; + } + else + { + UINT32 clocks = 0; + UINT32 words = data & 0x0fffffff; + + // IDE to DRAM + if (data & 0x10000000) + { + UINT32 addr = m_dma_addr[bank]; + UINT16 *ram = bank ? m_bank_b : m_bank_a; + + while (words--) + { + ram[addr & DIMM_BANK_MASK] = m_ata->read_cs0(space, 0, 0xffff); + ++addr; + } + + clocks = 500; // TODO: May be too high + m_dma_addr[bank] = addr; + } + // IDE to video RAM + else if (data & 0x40000000) + { + while (words--) + { + UINT16 data = m_ata->read_cs0(space, 0, 0xffff); + + // TODO: Verify if this is correct + if ((data & 0xc400) == 0xc400) + { + fatalerror("IDE RLE detected"); + + // RLE word + int count = (data & 0x3ff) + 1; + + while (count--) + write_video_ram(m_last_pixel); + } + else + { + write_video_ram(data); + + // Store current pixel + m_last_pixel = data; + } + } + + clocks = 500; // TODO + } + // RAM to video RAM + else if (data & 0x80000000) + { + UINT32 addr = m_dma_addr[bank]; + UINT16 *ram = bank ? m_bank_b : m_bank_a; + + //bool first = true; // Does it matter? + + while (words--) + { + UINT16 val = ram[addr++]; + //++clocks; + + switch (val & 0xc400) + { + // Transparent run + case 0x8400: + { + int run = (((val & 0x3800) >> 1) | (val & 0x03ff)) + 1; + + while (run--) + { + update_video_addr(); + //++clocks; + } + + break; + } + + case 0xc400: + { + int run = (((val & 0x3800) >> 1) | (val & 0x03ff)) + 1; + + while (run--) + clocks += write_video_ram(m_last_pixel); + + break; + } + + default: + { + m_last_pixel = val; + clocks += write_video_ram(val); + break; + } + } + //first = false; + } + + // clocks =1;///= 2; + } + else + { + popmessage("Unhandled DMA case: %.8x, contact MAMEdev!\n", data); + } + + // Set the DMA completion timer + m_dma_idle = false; + m_dma_timer->adjust(attotime::from_nsec(10) * clocks, 0); + } +}