From 01b2f120343b6126fee95f9dd2ffe2b37d1e6cd6 Mon Sep 17 00:00:00 2001 From: Ivan Vangelista Date: Sun, 12 Jan 2025 09:38:15 +0100 Subject: [PATCH 01/15] New working clones ------------------ Toride II (Japan, revision I) [twistedsymphony] New systems marked not working ------------------------------ Omatsuri Yasan: Ganso Takoyaki [SnakeGrunger] New clones marked not working ----------------------------- Omatsuri Yasan: Kingyo Sukui [SnakeGrunger] --- src/mame/cave/fstgfish.cpp | 42 +++++++++++++++++++++++++++++++------- src/mame/mame.lst | 5 ++++- src/mame/metro/metro.cpp | 21 ++++++++++++++++++- 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/src/mame/cave/fstgfish.cpp b/src/mame/cave/fstgfish.cpp index 5efda3e5eca16..2e4cf9424cfcb 100644 --- a/src/mame/cave/fstgfish.cpp +++ b/src/mame/cave/fstgfish.cpp @@ -59,7 +59,7 @@ to the missing CV1000XP card. Connecting directly into the CV1000XP CN2 with a standard USB cable results in the message: USB device not recognized. Attempts to -increase the current on the 5V have not been succesful. +increase the current on the 5V have not been successful. Make a dd of the image, and write to an SSD disk, the game will boot happily. Rename cvgame.exe to @@ -121,7 +121,7 @@ INPUT_PORTS_END void fstgfish_state::fstgfish(machine_config &config) { - PENTIUM3(config, m_maincpu, 200'000'000); /* Intel Core 2 Duo, 333/266/200 FSB clocks */ + PENTIUM3(config, m_maincpu, 200'000'000); // Intel Core 2 Duo, 333/266/200 FSB clocks m_maincpu->set_addrmap(AS_PROGRAM, &fstgfish_state::main_map); m_maincpu->set_addrmap(AS_IO, &fstgfish_state::main_io); @@ -130,16 +130,42 @@ void fstgfish_state::fstgfish(machine_config &config) } ROM_START(fstgfish) - ROM_REGION32_LE(0x80000, "bios", 0) - ROM_LOAD( "g31ms2l.f7", 0x000000, 0x80000, CRC(4f92f678) SHA1(c29ce14f093b5d6ef308f674fe4d514eb10e4742) ) + ROM_REGION32_LE( 0x80000, "bios", 0 ) + ROM_LOAD( "g31ms2l.f7", 0x000000, 0x80000, CRC(4f92f678) SHA1(c29ce14f093b5d6ef308f674fe4d514eb10e4742) ) DISK_REGION( "cfcard" ) // CF with Windows XP embedded DISK_IMAGE( "x11_15305", 0, SHA1(67bce99fb55760d0c06d698e68656eebbda8a28f) ) // H8S/2218 on CV2000XP board, assume with internal ROM - ROM_REGION(0x20000, "cv2000xp", ROMREGION_ERASEFF) - ROM_LOAD( "h8s2218.bin", 0x000000, 0x20000, NO_DUMP ) + ROM_REGION( 0x20000, "cv2000xp", ROMREGION_ERASEFF ) + ROM_LOAD( "h8s2218.bin", 0x000000, 0x20000, NO_DUMP ) +ROM_END + +// for the following 2 games, only CF card dumps are available. + +ROM_START( oyks ) + ROM_REGION32_LE( 0x80000, "bios", 0 ) + ROM_LOAD( "g31ms2l.f7", 0x00000, 0x080000, BAD_DUMP CRC(4f92f678) SHA1(c29ce14f093b5d6ef308f674fe4d514eb10e4742) ) + + DISK_REGION( "cfcard" ) + DISK_IMAGE( "oyks", 0, SHA1(5aea6e0e64e1a2bb01b6225c215634961376e308) ) // お祭りやさん きんぎょR label, 2009/4/20 label, Window XP embedded label + + // H8S/2218 on CV2000XP board, assume with internal ROM + ROM_REGION( 0x20000, "cv2000xp", ROMREGION_ERASEFF ) + ROM_LOAD( "h8s2218.bin", 0x000000, 0x20000, NO_DUMP ) +ROM_END + +ROM_START( oygt ) + ROM_REGION32_LE( 0x80000, "bios", 0 ) + ROM_LOAD( "g31ms2l.f7", 0x00000, 0x080000, BAD_DUMP CRC(4f92f678) SHA1(c29ce14f093b5d6ef308f674fe4d514eb10e4742) ) + + DISK_REGION( "cfcard" ) + DISK_IMAGE( "oygt", 0, SHA1(86581acca549544ec5d1945e46ca95bb76f05b40) ) // 新たこやきD label, Window XP embedded label + + // H8S/2218 on CV2000XP board, assume with internal ROM + ROM_REGION( 0x20000, "cv2000xp", ROMREGION_ERASEFF ) + ROM_LOAD( "h8s2218.bin", 0x000000, 0x20000, NO_DUMP ) ROM_END } // anonymous namespace @@ -147,4 +173,6 @@ ROM_END /*****************************************************************************/ -GAME(2008, fstgfish, 0, fstgfish, fstgfish, fstgfish_state, empty_init, ROT0, "Cave", "Festival: Goldfish Scoop", MACHINE_NO_SOUND | MACHINE_NOT_WORKING ) +GAME( 2009, fstgfish, 0, fstgfish, fstgfish, fstgfish_state, empty_init, ROT0, "Cave", "Festival: Goldfish Scoop", MACHINE_NO_SOUND | MACHINE_NOT_WORKING ) // probably Japanese, too +GAME( 2009, oyks, fstgfish, fstgfish, fstgfish, fstgfish_state, empty_init, ROT0, "Cave", "Omatsuri Yasan: Kingyo Sukui", MACHINE_NO_SOUND | MACHINE_NOT_WORKING ) +GAME( 2009, oygt, 0, fstgfish, fstgfish, fstgfish_state, empty_init, ROT0, "Cave", "Omatsuri Yasan: Ganso Takoyaki", MACHINE_NO_SOUND | MACHINE_NOT_WORKING ) diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 3944076c5c075..d194db198122c 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -16250,7 +16250,9 @@ pinkswtsx // (c) 2006 Cave (AMI license) - 2006/xx/xx MAST pinkswtssc // bootleg @source:cave/fstgfish.cpp -fstgfish // (c) 2008 Cave +fstgfish // (c) 2009 Cave +oygt // (c) 2009 Cave +oyks // (c) 2009 Cave @source:cce/mc1000.cpp mc1000 // @@ -27598,6 +27600,7 @@ toride2g // (c) 1994 toride2gg // (c) 1994 toride2gk // (c) 1994 toride2j // (c) 1994 +toride2ji // (c) 1994 vmetal // (c) 1995 Excellent System? vmetaln // (c) 1995 Excellent System? diff --git a/src/mame/metro/metro.cpp b/src/mame/metro/metro.cpp index a9fe023f7692f..60f94cfdf7007 100644 --- a/src/mame/metro/metro.cpp +++ b/src/mame/metro/metro.cpp @@ -5320,6 +5320,24 @@ ROM_START( toride2j ) ROM_LOAD( "tr2_ja_7.3g", 0x000000, 0x020000, CRC(6ee32315) SHA1(ef4d59576929deab0aa459a67be21d97c2803dea) ) ROM_END +ROM_START( toride2ji ) + ROM_REGION( 0x080000, "maincpu", 0 ) // 68000 Code + ROM_LOAD16_BYTE( "tr2_ji-5.20e", 0x000000, 0x040000, CRC(15906855) SHA1(ac905ed62a0a3cd951146224acc4dab75d730237) ) + ROM_LOAD16_BYTE( "tr2_ji-6.20c", 0x000001, 0x040000, CRC(e71e291e) SHA1(5ac5043208237d2b1ee45d34e5ad74ba2f821cd3) ) + + ROM_REGION( 0x20000, "audiocpu", 0 ) // NEC78C10 Code + ROM_LOAD( "tr2_jb-8.3i", 0x000000, 0x020000, CRC(0168f46f) SHA1(01bf4cc425d72936897c3c572f6c0b1366fe4041) ) + + ROM_REGION( 0x200000, "vdp2", 0 ) // Gfx + Data (Addressable by CPU & Blitter) + ROM_LOAD64_WORD( "tr2_jb-2.14i", 0x000000, 0x080000, CRC(b31754dc) SHA1(be2423bafbf07c93c3d222e907190b44616014f0) ) + ROM_LOAD64_WORD( "tr2_jb-4.18i", 0x000002, 0x080000, CRC(a855c3fa) SHA1(eca3e235256df7e6ae66ecbe43bc0edb974af503) ) + ROM_LOAD64_WORD( "tr2_jb-1.12i", 0x000004, 0x080000, CRC(856f40b7) SHA1(99aca5472b991cd08e9c2128ffdd40675a3b968d) ) + ROM_LOAD64_WORD( "tr2_jb-3.16i", 0x000006, 0x080000, CRC(78ba205f) SHA1(1069a362e60747aaa284c0d9bb7718013df347f3) ) + + ROM_REGION( 0x40000, "oki", 0 ) // Samples + ROM_LOAD( "tr2_ja_7.3g", 0x000000, 0x020000, CRC(6ee32315) SHA1(ef4d59576929deab0aa459a67be21d97c2803dea) ) +ROM_END + /*************************************************************************** Varia Metal @@ -5488,7 +5506,8 @@ GAME( 1994, dharmak, dharma, dharma, dharma, metro_upd7810_state, ini GAME( 1994, toride2g, 0, toride2g, toride2g, metro_upd7810_state, empty_init, ROT0, "Metro", "Toride II Adauchi Gaiden", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) GAME( 1994, toride2gg, toride2g, toride2g, toride2g, metro_upd7810_state, empty_init, ROT0, "Metro", "Toride II Adauchi Gaiden (German)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) GAME( 1994, toride2gk, toride2g, toride2g, toride2g, metro_upd7810_state, empty_init, ROT0, "Metro", "Toride II Bok Su Oi Jeon Adauchi Gaiden (Korea)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) -GAME( 1994, toride2j, toride2g, toride2g, toride2g, metro_upd7810_state, empty_init, ROT0, "Metro", "Toride II (Japan)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) +GAME( 1994, toride2j, toride2g, toride2g, toride2g, metro_upd7810_state, empty_init, ROT0, "Metro", "Toride II (Japan, revision K)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) +GAME( 1994, toride2ji, toride2g, toride2g, toride2g, metro_upd7810_state, empty_init, ROT0, "Metro", "Toride II (Japan, revision I)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) GAME( 1994, gunmast, 0, pururun, gunmast, metro_upd7810_state, empty_init, ROT0, "Metro", "Gun Master", MACHINE_SUPPORTS_SAVE ) GAME( 1995, daitorid, 0, daitorid, daitorid, metro_upd7810_state, empty_init, ROT0, "Metro", "Daitoride", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) GAME( 1995, pururun, 0, pururun, pururun, metro_upd7810_state, empty_init, ROT0, "Metro / Banpresto", "Pururun (set 1)", MACHINE_SUPPORTS_SAVE ) From 15f8ec61e379f660bcebde6f89ae0b14952ea72d Mon Sep 17 00:00:00 2001 From: hap Date: Sun, 12 Jan 2025 12:46:40 +0100 Subject: [PATCH 02/15] New working systems ------------------- Beluga [hap, Berger] --- src/mame/layout/novag_beluga.lay | 502 +++++++++++++++++++++++++++++++ src/mame/mame.lst | 1 + src/mame/novag/primo.cpp | 53 +++- 3 files changed, 546 insertions(+), 10 deletions(-) create mode 100644 src/mame/layout/novag_beluga.lay diff --git a/src/mame/layout/novag_beluga.lay b/src/mame/layout/novag_beluga.lay new file mode 100644 index 0000000000000..5655c439233ed --- /dev/null +++ b/src/mame/layout/novag_beluga.lay @@ -0,0 +1,502 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/mame.lst b/src/mame/mame.lst index d194db198122c..2f4b3ddd3bf06 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -35504,6 +35504,7 @@ nmicro nmicro2 @source:novag/primo.cpp +beluga nprimo nsnova nsnovaa diff --git a/src/mame/novag/primo.cpp b/src/mame/novag/primo.cpp index e0b6a19f8f6b5..352e9bd78a397 100644 --- a/src/mame/novag/primo.cpp +++ b/src/mame/novag/primo.cpp @@ -12,28 +12,34 @@ properly. - if/when MAME supports an exit callback, hook up power-off switch to that - Novag Super System peripherals don't work on nsnova due to serial clock drift, baud rate differs a bit between host and client, m6801 serial emulation issue -- unmapped reads from 0x3c/0x3d (primo/supremo) or 0x33/0x34 (nsnova) +- unmapped reads from 0x33/0x34 (nsnova) or 0x3c/0x3d (others) - supremo unmapped writes to 0x2000/0x6000, always 0? - is the 1st version of supremo(black plastic) the same ROM? - is "Aquamarine / Super Nova" the same ROM as nsnova and just a redesign? BTANB: -- primo has the same bug as nvip, where if the user presses Go right after - entering a move during the opening, the CPU opponent will answer by playing - a move with white +- nprimo/beluga has the same bug as nvip, where if the user presses Go right + after entering a move during the opening, the CPU opponent will answer by + playing a move with white ================================================================================ -Novag Primo (model 871) ------------------------ +Novag Primo family +------------------ Hardware notes: + +Primo (model 871): - PCB label: 100059/100060 - Hitachi HD6301Y0P (mode 2) @ 8MHz - 2KB RAM(M5M5118P) - LCD with 4 7segs and custom segments, no LCD chip - buzzer, 16 LEDs, 8*8 chessboard buttons +Beluga (model 903): +- PCB label: 100116 +- CPU runs at 16MHz, rest is same as Primo + The LCD is the same as the one in VIP / Super VIP. ================================================================================ @@ -83,6 +89,7 @@ the Super VIP combined with the Novag Super System Touch Sensory board. #include "speaker.h" // internal artwork +#include "novag_beluga.lh" #include "novag_primo.lh" #include "novag_snova.lh" #include "novag_supremo.lh" @@ -106,6 +113,7 @@ class primo_state : public driver_device { } void primo(machine_config &config); + void beluga(machine_config &config); void supremo(machine_config &config); void snova(machine_config &config); @@ -216,14 +224,14 @@ u8 primo_state::p2_r() if (BIT(m_select, i + 6)) data |= BIT(m_inputs[i]->read(), m_inp_mux); - // P23 (nprimo, supremo): power switch - if (!m_power) - data |= 8; - // P23 (nsnova): serial rx if (m_rs232) data |= m_rs232->rxd_r() << 3; + // P23 (others): power switch + if (!m_power) + data |= 8; + return data ^ 1; } @@ -398,6 +406,20 @@ void primo_state::primo(machine_config &config) DAC_1BIT(config, m_dac).add_route(ALL_OUTPUTS, "speaker", 0.25); } +void primo_state::beluga(machine_config &config) +{ + primo(config); + + // basic machine hardware + m_maincpu->set_clock(16_MHz_XTAL); + m_maincpu->in_p2_cb().set(FUNC(primo_state::p2_r)).mask(0xef); + + // P24 is tied to P52 (freq sel via P50-P53) + m_maincpu->in_p2_cb().append([this]() { return m_select << 2; }).mask(0x10); + + config.set_default_layout(layout_novag_beluga); +} + void primo_state::supremo(machine_config &config) { primo(config); @@ -445,6 +467,15 @@ ROM_START( nprimo ) ROM_END +ROM_START( beluga ) + ROM_REGION( 0x4000, "maincpu", 0 ) + ROM_LOAD("novag_903_31y0rm59p.u1", 0x0000, 0x4000, CRC(16fc6bfc) SHA1(5ab4c7e92eb7b6b449c388f50293dfd01aa87c24) ) + + ROM_REGION( 36256, "screen", 0 ) + ROM_LOAD("nvip.svg", 0, 36256, CRC(3373e0d5) SHA1(25bfbf0405017388c30f4529106baccb4723bc6b) ) +ROM_END + + ROM_START( supremo ) ROM_REGION( 0x10000, "maincpu", 0 ) ROM_LOAD("sp_a10.u5", 0x8000, 0x8000, CRC(1db63786) SHA1(4f24452ed8955b31ba88f68cc95c357660930aa4) ) @@ -481,6 +512,8 @@ ROM_END // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS SYST( 1987, nprimo, 0, 0, primo, primo, primo_state, empty_init, "Novag Industries / Intelligent Heuristic Programming", "Primo (Novag)", MACHINE_SUPPORTS_SAVE ) +SYST( 1990, beluga, 0, 0, beluga, primo, primo_state, empty_init, "Novag Industries / Intelligent Heuristic Programming", "Beluga", MACHINE_SUPPORTS_SAVE ) + SYST( 1988, supremo, 0, 0, supremo, supremo, primo_state, empty_init, "Novag Industries / Intelligent Heuristic Programming", "Supremo", MACHINE_SUPPORTS_SAVE ) SYST( 1990, nsnova, 0, 0, snova, snova, primo_state, empty_init, "Novag Industries / Intelligent Heuristic Programming", "Super Nova (Novag, set 1)", MACHINE_SUPPORTS_SAVE ) From 02f5cf6671c97d928da913c475a753cedf6517a9 Mon Sep 17 00:00:00 2001 From: hap Date: Sun, 12 Jan 2025 12:54:38 +0100 Subject: [PATCH 03/15] elf: correction to in button, remove some more trampolines --- src/mame/netronics/elf.cpp | 45 +++++++++++++------------------------- src/mame/netronics/elf.h | 4 +--- 2 files changed, 16 insertions(+), 33 deletions(-) diff --git a/src/mame/netronics/elf.cpp b/src/mame/netronics/elf.cpp index 9416061f60e8c..9be0c506a21aa 100644 --- a/src/mame/netronics/elf.cpp +++ b/src/mame/netronics/elf.cpp @@ -13,6 +13,7 @@ and it will write twice. It is because set_input_line is delayed until the CPU finished execute_run after sc_w. - proper layout + - add cassette I/O */ @@ -22,18 +23,12 @@ #include "speaker.h" #include "elf2.lh" -#define RUN \ - BIT(m_special->read(), 0) - #define LOAD \ BIT(m_special->read(), 1) #define MEMORY_PROTECT \ BIT(m_special->read(), 2) -#define INPUT \ - BIT(m_special->read(), 3) - /* Read/Write Handlers */ uint8_t elf2_state::dispon_r() @@ -94,13 +89,18 @@ void elf2_state::elf2_io(address_map &map) /* Input Ports */ +INPUT_CHANGED_MEMBER(elf2_state::load_w) +{ + /* DMAIN is reset while LOAD is off */ + if (!newval) + m_maincpu->set_input_line(COSMAC_INPUT_LINE_DMAIN, CLEAR_LINE); +} + INPUT_CHANGED_MEMBER(elf2_state::input_w) { - if (newval && ~m_sc & 2) - { - /* assert DMAIN */ + /* assert DMAIN */ + if (LOAD && !newval && ~m_sc & 2) m_maincpu->set_input_line(COSMAC_INPUT_LINE_DMAIN, ASSERT_LINE); - } } static INPUT_PORTS_START( elf2 ) @@ -134,28 +134,13 @@ static INPUT_PORTS_START( elf2 ) PORT_START("SPECIAL") PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("RUN") PORT_CODE(KEYCODE_R) PORT_TOGGLE - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("LOAD") PORT_CODE(KEYCODE_L) PORT_TOGGLE + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("LOAD") PORT_CODE(KEYCODE_L) PORT_TOGGLE PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(elf2_state::load_w), 0) PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("M/P") PORT_CODE(KEYCODE_M) PORT_TOGGLE - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("INPUT") PORT_CODE(KEYCODE_ENTER) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(elf2_state::input_w), 0) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("IN") PORT_CODE(KEYCODE_ENTER) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(elf2_state::input_w), 0) INPUT_PORTS_END /* CDP1802 Configuration */ -int elf2_state::wait_r() -{ - return !LOAD; -} - -int elf2_state::clear_r() -{ - return RUN; -} - -int elf2_state::ef4_r() -{ - return INPUT; -} - uint8_t elf2_state::dma_r() { return m_data; @@ -226,9 +211,9 @@ void elf2_state::elf2(machine_config &config) CDP1802(config, m_maincpu, XTAL(3'579'545)/2); m_maincpu->set_addrmap(AS_PROGRAM, &elf2_state::elf2_mem); m_maincpu->set_addrmap(AS_IO, &elf2_state::elf2_io); - m_maincpu->wait_cb().set(FUNC(elf2_state::wait_r)); - m_maincpu->clear_cb().set(FUNC(elf2_state::clear_r)); - m_maincpu->ef4_cb().set(FUNC(elf2_state::ef4_r)); + m_maincpu->wait_cb().set_ioport("SPECIAL").bit(1).invert(); + m_maincpu->clear_cb().set_ioport("SPECIAL").bit(0); + m_maincpu->ef4_cb().set_ioport("SPECIAL").bit(3); m_maincpu->q_cb().set_output("led0"); m_maincpu->dma_rd_cb().set(FUNC(elf2_state::dma_r)); m_maincpu->dma_wr_cb().set(m_vdc, FUNC(cdp1861_device::dma_w)); diff --git a/src/mame/netronics/elf.h b/src/mame/netronics/elf.h index 11e00cb24a391..5ace7a8138e21 100644 --- a/src/mame/netronics/elf.h +++ b/src/mame/netronics/elf.h @@ -39,6 +39,7 @@ class elf2_state : public driver_device void elf2(machine_config &config); + DECLARE_INPUT_CHANGED_MEMBER(load_w); DECLARE_INPUT_CHANGED_MEMBER(input_w); protected: @@ -49,9 +50,6 @@ class elf2_state : public driver_device uint8_t data_r(); void data_w(uint8_t data); void memory_w(offs_t offset, uint8_t data); - int wait_r(); - int clear_r(); - int ef4_r(); uint8_t dma_r(); void sc_w(uint8_t data); void da_w(int state); From b67f6c88f6b572206189f649a437123faeb8c71d Mon Sep 17 00:00:00 2001 From: hap Date: Sun, 12 Jan 2025 13:05:50 +0100 Subject: [PATCH 04/15] trclchick: remove duplicated ports --- src/mame/handheld/hh_sm510.cpp | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/mame/handheld/hh_sm510.cpp b/src/mame/handheld/hh_sm510.cpp index e9d2db07953a2..8e133d6de492f 100644 --- a/src/mame/handheld/hh_sm510.cpp +++ b/src/mame/handheld/hh_sm510.cpp @@ -11633,25 +11633,13 @@ static INPUT_PORTS_START( trdivadv ) INPUT_PORTS_END static INPUT_PORTS_START( trclchick ) - PORT_START("IN.0") // S1 + PORT_INCLUDE( trdivadv ) + + PORT_MODIFY("IN.0") // S1 PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_CHANGED_CB(input_changed) PORT_16WAY PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_CHANGED_CB(input_changed) PORT_16WAY PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_CHANGED_CB(input_changed) PORT_16WAY - - PORT_START("IN.1") // S2 - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_CHANGED_CB(input_changed) PORT_NAME("Time") - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_START2 ) PORT_CHANGED_CB(input_changed) PORT_NAME("Game B") - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_START1 ) PORT_CHANGED_CB(input_changed) PORT_NAME("Game A") - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_SERVICE2 ) PORT_CHANGED_CB(input_changed) PORT_NAME("Alarm") - - PORT_START("B") - PORT_CONFNAME( 0x01, 0x01, "Invincibility (Cheat)") // factory test, unpopulated on PCB - PORT_CONFSETTING( 0x01, DEF_STR( Off ) ) - PORT_CONFSETTING( 0x00, DEF_STR( On ) ) - - PORT_START("ACL") - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_SERVICE1 ) PORT_CHANGED_CB(acl_button) PORT_NAME("ACL") INPUT_PORTS_END // config From 035b34aa99e84bb5092a393bf3c188b905507408 Mon Sep 17 00:00:00 2001 From: hap Date: Sun, 12 Jan 2025 13:10:15 +0100 Subject: [PATCH 05/15] m6800: add dummy read to CLR opcode [blueonesarefaster] --- src/devices/cpu/m6800/6800ops.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices/cpu/m6800/6800ops.hxx b/src/devices/cpu/m6800/6800ops.hxx index eab1825c0e33f..98e45de37d113 100644 --- a/src/devices/cpu/m6800/6800ops.hxx +++ b/src/devices/cpu/m6800/6800ops.hxx @@ -829,7 +829,7 @@ OP_HANDLER( jmp_ix ) /* $6f CLR indexed -0100 */ OP_HANDLER( clr_ix ) { - INDEXED; WM(EAD,0); + INDEXED; RM(EAD); WM(EAD,0); CLR_NZVC; SEZ; } @@ -981,7 +981,7 @@ OP_HANDLER( jmp_ex ) /* $7f CLR extended -0100 */ OP_HANDLER( clr_ex ) { - EXTENDED; WM(EAD,0); + EXTENDED; RM(EAD); WM(EAD,0); CLR_NZVC; SEZ; } From cd2d3f417717fba6cf92a0aa96074451afc24d2b Mon Sep 17 00:00:00 2001 From: hap Date: Sun, 12 Jan 2025 14:23:06 +0100 Subject: [PATCH 06/15] misc atari: add nopr to addressmaps for 6800 clr spam --- src/mame/atari/cball.cpp | 7 +++++-- src/mame/atari/destroyr.cpp | 4 ++-- src/mame/atari/dragrace.cpp | 4 ++-- src/mame/atari/poolshrk.cpp | 6 +++--- src/mame/atari/sprint8.cpp | 6 +++--- src/mame/atari/tank8.cpp | 18 +++++++++--------- 6 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/mame/atari/cball.cpp b/src/mame/atari/cball.cpp index 51b50281bb6eb..2c7241aa7fa7a 100644 --- a/src/mame/atari/cball.cpp +++ b/src/mame/atari/cball.cpp @@ -2,7 +2,11 @@ // copyright-holders:Stefan Jokisch /*************************************************************************** - Atari Cannonball (prototype) driver +Atari Cannonball (prototype) driver + +TODO: +- half of the graphics are missing due to undumped ROM +- often hits illegal opcode 0x02, harmless leftover from devkit? ***************************************************************************/ @@ -252,7 +256,6 @@ void cball_state::cball(machine_config &config) M6800(config, m_maincpu, XTAL(12'096'000) / 16); /* ? */ m_maincpu->set_addrmap(AS_PROGRAM, &cball_state::cpu_map); - /* video hardware */ SCREEN(config, m_screen, SCREEN_TYPE_RASTER); m_screen->set_refresh_hz(60); diff --git a/src/mame/atari/destroyr.cpp b/src/mame/atari/destroyr.cpp index c87708adb065e..81e17ed3b35ea 100644 --- a/src/mame/atari/destroyr.cpp +++ b/src/mame/atari/destroyr.cpp @@ -290,8 +290,8 @@ void destroyr_state::main_map(address_map &map) map(0x1000, 0x1007).mirror(0xff0).w("outlatch", FUNC(f9334_device::write_d0)); map(0x1008, 0x1008).mirror(0xff7).w(FUNC(destroyr_state::misc_w)); map(0x2000, 0x2000).mirror(0xfff).portr("IN2"); - map(0x3000, 0x30ff).mirror(0xf00).writeonly().share("alpha_nuram"); - map(0x4000, 0x401f).mirror(0xfe0).writeonly().share("major_obj_ram"); + map(0x3000, 0x30ff).mirror(0xf00).nopr().writeonly().share("alpha_nuram"); + map(0x4000, 0x401f).mirror(0xfe0).nopr().writeonly().share("major_obj_ram"); map(0x5000, 0x5000).mirror(0xff8).w(FUNC(destroyr_state::cursor_load_w)); map(0x5001, 0x5001).mirror(0xff8).w(FUNC(destroyr_state::interrupt_ack_w)); map(0x5002, 0x5007).mirror(0xff8).writeonly().share("minor_obj_ram"); diff --git a/src/mame/atari/dragrace.cpp b/src/mame/atari/dragrace.cpp index 33db8bb9577b4..8103a8b08bf80 100644 --- a/src/mame/atari/dragrace.cpp +++ b/src/mame/atari/dragrace.cpp @@ -271,8 +271,8 @@ void dragrace_state::main_map(address_map &map) map(0x0928, 0x092f).w("latch_a5", FUNC(addressable_latch_device::clear)); map(0x0930, 0x0937).w("latch_h5", FUNC(addressable_latch_device::clear)); map(0x0938, 0x093f).w("latch_e5", FUNC(addressable_latch_device::clear)); - map(0x0a00, 0x0aff).writeonly().share(m_playfield_ram); - map(0x0b00, 0x0bff).writeonly().share(m_position_ram); + map(0x0a00, 0x0aff).nopr().writeonly().share(m_playfield_ram); + map(0x0b00, 0x0bff).nopr().writeonly().share(m_position_ram); map(0x0c00, 0x0c00).r(FUNC(dragrace_state::steering_r)); map(0x0d00, 0x0d00).r(FUNC(dragrace_state::scanline_r)); map(0x0e00, 0x0eff).w(m_watchdog, FUNC(watchdog_timer_device::reset_w)); diff --git a/src/mame/atari/poolshrk.cpp b/src/mame/atari/poolshrk.cpp index fc0089280b258..4050ef13188c3 100644 --- a/src/mame/atari/poolshrk.cpp +++ b/src/mame/atari/poolshrk.cpp @@ -237,9 +237,9 @@ void poolshrk_state::cpu_map(address_map &map) { map.global_mask(0x7fff); map(0x0000, 0x00ff).mirror(0x2300).ram(); - map(0x0400, 0x07ff).mirror(0x2000).writeonly().share(m_playfield_ram); - map(0x0800, 0x080f).mirror(0x23f0).writeonly().share(m_hpos_ram); - map(0x0c00, 0x0c0f).mirror(0x23f0).writeonly().share(m_vpos_ram); + map(0x0400, 0x07ff).mirror(0x2000).nopr().writeonly().share(m_playfield_ram); + map(0x0800, 0x080f).mirror(0x23f0).nopr().writeonly().share(m_hpos_ram); + map(0x0c00, 0x0c0f).mirror(0x23f0).nopr().writeonly().share(m_vpos_ram); map(0x1000, 0x13ff).mirror(0x2000).rw(FUNC(poolshrk_state::input_r), FUNC(poolshrk_state::watchdog_w)); map(0x1400, 0x17ff).mirror(0x2000).w(FUNC(poolshrk_state::scratch_sound_w)); map(0x1800, 0x1bff).mirror(0x2000).w(FUNC(poolshrk_state::score_sound_w)); diff --git a/src/mame/atari/sprint8.cpp b/src/mame/atari/sprint8.cpp index ab9a02da5ae58..c88667bb6954c 100644 --- a/src/mame/atari/sprint8.cpp +++ b/src/mame/atari/sprint8.cpp @@ -358,9 +358,9 @@ void sprint8_state::program_map(address_map &map) map(0x1c10, 0x1c1f).writeonly().share(m_pos_v_ram); map(0x1c20, 0x1c2f).writeonly().share(m_pos_d_ram); map(0x1c30, 0x1c37).w(FUNC(sprint8_state::lockout_w)); - map(0x1d00, 0x1d07).w("latch", FUNC(f9334_device::write_d0)); - map(0x1e00, 0x1e07).w("motor", FUNC(f9334_device::write_d0)); - map(0x1f00, 0x1f00).nopw(); // probably a watchdog, disabled in service mode + map(0x1d00, 0x1d07).nopr().w("latch", FUNC(f9334_device::write_d0)); + map(0x1e00, 0x1e07).nopr().w("motor", FUNC(f9334_device::write_d0)); + map(0x1f00, 0x1f00).noprw(); // probably a watchdog, disabled in service mode map(0x2000, 0x3fff).rom(); map(0xf800, 0xffff).rom(); } diff --git a/src/mame/atari/tank8.cpp b/src/mame/atari/tank8.cpp index 27ba3e04cd203..e74bc27fecdb2 100644 --- a/src/mame/atari/tank8.cpp +++ b/src/mame/atari/tank8.cpp @@ -453,15 +453,15 @@ void tank8_state::cpu_map(address_map &map) map(0x1c10, 0x1c1f).writeonly().share(m_pos_v_ram); map(0x1c20, 0x1c2f).writeonly().share(m_pos_d_ram); - map(0x1c30, 0x1c37).w(FUNC(tank8_state::lockout_w)); - map(0x1d00, 0x1d00).w(FUNC(tank8_state::int_reset_w)); - map(0x1d01, 0x1d01).w(FUNC(tank8_state::crash_w)); - map(0x1d02, 0x1d02).w(FUNC(tank8_state::explosion_w)); - map(0x1d03, 0x1d03).w(FUNC(tank8_state::bugle_w)); - map(0x1d04, 0x1d04).w(FUNC(tank8_state::bug_w)); - map(0x1d05, 0x1d05).writeonly().share(m_team); - map(0x1d06, 0x1d06).w(FUNC(tank8_state::attract_w)); - map(0x1e00, 0x1e07).w(FUNC(tank8_state::motor_w)); + map(0x1c30, 0x1c37).nopr().w(FUNC(tank8_state::lockout_w)); + map(0x1d00, 0x1d00).nopr().w(FUNC(tank8_state::int_reset_w)); + map(0x1d01, 0x1d01).nopr().w(FUNC(tank8_state::crash_w)); + map(0x1d02, 0x1d02).nopr().w(FUNC(tank8_state::explosion_w)); + map(0x1d03, 0x1d03).nopr().w(FUNC(tank8_state::bugle_w)); + map(0x1d04, 0x1d04).nopr().w(FUNC(tank8_state::bug_w)); + map(0x1d05, 0x1d05).nopr().writeonly().share(m_team); + map(0x1d06, 0x1d06).nopr().w(FUNC(tank8_state::attract_w)); + map(0x1e00, 0x1e07).nopr().w(FUNC(tank8_state::motor_w)); } From 35bb55fb24b0b9a4f396940f2920404cfd6854d3 Mon Sep 17 00:00:00 2001 From: hap Date: Sun, 12 Jan 2025 15:21:47 +0100 Subject: [PATCH 07/15] beluga: change keypad shortcuts --- src/mame/atari/tank8.cpp | 1 - src/mame/novag/primo.cpp | 40 ++++++++++++++++++++++++++++++---------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/mame/atari/tank8.cpp b/src/mame/atari/tank8.cpp index e74bc27fecdb2..56da95dd6b734 100644 --- a/src/mame/atari/tank8.cpp +++ b/src/mame/atari/tank8.cpp @@ -462,7 +462,6 @@ void tank8_state::cpu_map(address_map &map) map(0x1d05, 0x1d05).nopr().writeonly().share(m_team); map(0x1d06, 0x1d06).nopr().w(FUNC(tank8_state::attract_w)); map(0x1e00, 0x1e07).nopr().w(FUNC(tank8_state::motor_w)); - } diff --git a/src/mame/novag/primo.cpp b/src/mame/novag/primo.cpp index 352e9bd78a397..3b1c3a5358347 100644 --- a/src/mame/novag/primo.cpp +++ b/src/mame/novag/primo.cpp @@ -40,7 +40,8 @@ Beluga (model 903): - PCB label: 100116 - CPU runs at 16MHz, rest is same as Primo -The LCD is the same as the one in VIP / Super VIP. +The LCD is the same as the one in VIP / Super VIP. Beluga is an updated version +of the program in Primo, just in a different housing (more similar to nsnova). ================================================================================ @@ -338,28 +339,47 @@ static INPUT_PORTS_START( supremo ) INPUT_PORTS_END -static INPUT_PORTS_START( snova ) +static INPUT_PORTS_START( beluga ) PORT_START("IN.0") PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_8) PORT_NAME("Trace Back / Next Best") PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_7) PORT_NAME("Trace Forward / Auto Play") PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_6) PORT_NAME("Set Level / Pawn") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_5) PORT_NAME("Info / Knight") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_4) PORT_NAME("Easy / Bishop") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_3) PORT_NAME("Solve Mate / Rook") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_2) PORT_NAME("Sound / Queen") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_1) PORT_NAME("Referee / King") + + PORT_START("IN.1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_I) PORT_NAME("Go") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_U) PORT_NAME("Restore") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_Y) PORT_NAME("Hint") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_T) PORT_NAME("Clear Board / Clear") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_R) PORT_NAME("Color") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_E) PORT_NAME("Set Up / Verify") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_W) PORT_NAME("Random") + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_Q) PORT_CODE(KEYCODE_N) PORT_NAME("New Game") + + PORT_START("POWER") // needs to be triggered for nvram to work + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_POWER_OFF) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(primo_state::primo_power_off), 0) +INPUT_PORTS_END + +static INPUT_PORTS_START( snova ) + PORT_INCLUDE( beluga ) + + PORT_MODIFY("IN.0") PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_5) PORT_NAME("Info / Echo / Knight") PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_4) PORT_NAME("Easy / Moves / Bishop") PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_3) PORT_NAME("Solve Mate / Language / Rook") PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_2) PORT_NAME("Sound / Game / Queen") PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_1) PORT_NAME("Referee / Board / King") - PORT_START("IN.1") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_I) PORT_NAME("Go") - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_U) PORT_NAME("Restore") + PORT_MODIFY("IN.1") PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_Y) PORT_NAME("Hint / Human") - PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_T) PORT_NAME("Clear Board / Clear") PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_R) PORT_NAME("Color / Video") - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_E) PORT_NAME("Set Up / Verify") PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_W) PORT_NAME("Random / Auto Clock") - PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_CODE(KEYCODE_Q) PORT_CODE(KEYCODE_N) PORT_NAME("New Game") - PORT_START("POWER") // needs to be triggered for nvram to work + PORT_MODIFY("POWER") // needs to be triggered for nvram to work PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_POWER_OFF) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(primo_state::snova_power_off), 0) INPUT_PORTS_END @@ -512,7 +532,7 @@ ROM_END // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS SYST( 1987, nprimo, 0, 0, primo, primo, primo_state, empty_init, "Novag Industries / Intelligent Heuristic Programming", "Primo (Novag)", MACHINE_SUPPORTS_SAVE ) -SYST( 1990, beluga, 0, 0, beluga, primo, primo_state, empty_init, "Novag Industries / Intelligent Heuristic Programming", "Beluga", MACHINE_SUPPORTS_SAVE ) +SYST( 1990, beluga, 0, 0, beluga, beluga, primo_state, empty_init, "Novag Industries / Intelligent Heuristic Programming", "Beluga", MACHINE_SUPPORTS_SAVE ) SYST( 1988, supremo, 0, 0, supremo, supremo, primo_state, empty_init, "Novag Industries / Intelligent Heuristic Programming", "Supremo", MACHINE_SUPPORTS_SAVE ) From 65f39de21491a34e7f7e15a458bb542c7ba1f478 Mon Sep 17 00:00:00 2001 From: hap Date: Sun, 12 Jan 2025 16:27:13 +0100 Subject: [PATCH 08/15] triplhunt: add default nvram, add debugger side effect checks --- src/mame/atari/triplhnt.cpp | 75 +++++++++++++------------------------ 1 file changed, 27 insertions(+), 48 deletions(-) diff --git a/src/mame/atari/triplhnt.cpp b/src/mame/atari/triplhnt.cpp index 4d49cbe81dc07..e4cafa548e7d8 100644 --- a/src/mame/atari/triplhnt.cpp +++ b/src/mame/atari/triplhnt.cpp @@ -5,8 +5,6 @@ Atari Triple Hunt Driver - Calibrate controls in service mode the first time you run this game. - ***************************************************************************/ #include "emu.h" @@ -46,6 +44,7 @@ class triplhnt_state : public driver_device m_hpos_ram(*this, "hpos_ram"), m_orga_ram(*this, "orga_ram"), m_code_ram(*this, "code_ram"), + m_cmos(*this, "nvram", 0x10, ENDIANNESS_BIG), m_0c09(*this, "0C09"), m_0c0b(*this, "0C0B"), m_vblank(*this, "VBLANK"), @@ -54,10 +53,7 @@ class triplhnt_state : public driver_device void triplhnt(machine_config &config); - void init_triplhnt(); - protected: - virtual void machine_start() override ATTR_COLD; virtual void video_start() override ATTR_COLD; private: @@ -75,12 +71,12 @@ class triplhnt_state : public driver_device required_shared_ptr m_hpos_ram; required_shared_ptr m_orga_ram; required_shared_ptr m_code_ram; + memory_share_creator m_cmos; required_ioport m_0c09; required_ioport m_0c0b; required_ioport m_vblank; required_ioport_array<2> m_stick; - uint8_t m_cmos[16]{}; uint8_t m_da_latch = 0; uint8_t m_cmos_latch = 0; uint8_t m_hit_code = 0; @@ -112,7 +108,6 @@ class triplhnt_state : public driver_device TILE_GET_INFO_MEMBER(triplhnt_state::get_tile_info) { int const code = m_playfield_ram[tile_index] & 0x3f; - tileinfo.set(2, code, code == 0x3f ? 1 : 0, 0); } @@ -125,7 +120,6 @@ void triplhnt_state::video_start() m_hit_timer = timer_alloc(FUNC(triplhnt_state::set_collision), this); - save_item(NAME(m_cmos)); save_item(NAME(m_da_latch)); save_item(NAME(m_cmos_latch)); save_item(NAME(m_hit_code)); @@ -146,7 +140,6 @@ void triplhnt_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprec int const j = (m_orga_ram[i] & 15) ^ 15; // software sorts sprites by x and stores order in orga RAM - int hpos = m_hpos_ram[j] ^ 255; int vpos = m_vpos_ram[j] ^ 255; int code = m_code_ram[j] ^ 255; @@ -155,7 +148,6 @@ void triplhnt_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprec continue; // sprite placement might be wrong - if (m_sprite_zoom) { rect.set(hpos - 16, hpos - 16 + 63, 196 - vpos, 196 - vpos + 63); @@ -166,10 +158,9 @@ void triplhnt_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprec } // render sprite to auxiliary bitmap - m_gfxdecode->gfx(m_sprite_zoom)->opaque(m_helper, cliprect, - 2 * code + m_sprite_bank, 0, code & 8, 0, - rect.left(), rect.top()); + 2 * code + m_sprite_bank, 0, code & 8, 0, + rect.left(), rect.top()); rect &= cliprect; @@ -201,7 +192,6 @@ void triplhnt_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprec uint32_t triplhnt_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { m_bg_tilemap->mark_all_dirty(); - m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0); draw_sprites(bitmap, cliprect); @@ -212,12 +202,6 @@ uint32_t triplhnt_state::screen_update(screen_device &screen, bitmap_ind16 &bitm } -void triplhnt_state::init_triplhnt() -{ - subdevice("nvram")->set_base(m_cmos, sizeof(m_cmos)); -} - - TIMER_CALLBACK_MEMBER(triplhnt_state::set_collision) { m_hit_code = param; @@ -252,7 +236,8 @@ void triplhnt_state::tape_control_w(int state) uint8_t triplhnt_state::cmos_r(offs_t offset) { - m_cmos_latch = offset; + if (!machine().side_effects_disabled()) + m_cmos_latch = offset; return m_cmos[m_cmos_latch] ^ 15; } @@ -260,34 +245,29 @@ uint8_t triplhnt_state::cmos_r(offs_t offset) uint8_t triplhnt_state::input_port_4_r() { - m_watchdog->watchdog_reset(); + if (!machine().side_effects_disabled()) + m_watchdog->watchdog_reset(); + return m_0c0b->read(); } uint8_t triplhnt_state::misc_r(offs_t offset) { - m_latch->write_a0(offset); + if (!machine().side_effects_disabled()) + m_latch->write_a0(offset); + return m_vblank->read() | m_hit_code; } uint8_t triplhnt_state::da_latch_r(offs_t offset) { - int const cross_x = m_stick[0]->read(); - int const cross_y = m_stick[1]->read(); - - m_da_latch = offset; + if (!machine().side_effects_disabled()) + m_da_latch = offset; // the following is a slight simplification - - return (offset & 1) ? cross_x : cross_y; -} - - -void triplhnt_state::machine_start() -{ - m_hit_code = 0; + return m_stick[offset & 1]->read(); } @@ -348,21 +328,17 @@ static INPUT_PORTS_START( triplhnt ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_COIN2 ) PORT_START("0C48") -// default to service enabled to make users calibrate gun -// PORT_SERVICE( 0x40, IP_ACTIVE_LOW ) - PORT_DIPNAME( 0x40, 0x00, DEF_STR( Service_Mode )) PORT_TOGGLE PORT_CODE(KEYCODE_F2) - PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_SERVICE( 0x40, IP_ACTIVE_LOW ) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_START("VBLANK") PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER("screen", FUNC(screen_device::vblank)) PORT_START("STICKX") - PORT_BIT( 0xfc, 0x80, IPT_AD_STICK_X ) PORT_MINMAX(0x00,0xfc) PORT_CROSSHAIR(X, 62.0/64, 1.0/64, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) + PORT_BIT( 0xfc, 0x80, IPT_AD_STICK_X ) PORT_MINMAX(0x00,0xfc) PORT_CROSSHAIR(X, 62.0/64, 1.0/64, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(4) PORT_START("STICKY") - PORT_BIT( 0xfc, 0x78, IPT_AD_STICK_Y ) PORT_MINMAX(0x00,0xec) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) + PORT_BIT( 0xfc, 0x78, IPT_AD_STICK_Y ) PORT_MINMAX(0x00,0xec) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(4) PORT_START("BEAR") // 10 PORT_ADJUSTER( 35, "Bear Roar Frequency" ) @@ -374,8 +350,7 @@ static const gfx_layout triplhnt_small_sprite_layout = 32, 32, // width, height 16, // total 2, // planes - // plane offsets - { 0x0000, 0x4000 }, + { 0x0000, 0x4000 }, // plane offsets { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, @@ -474,7 +449,7 @@ void triplhnt_state::triplhnt(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &triplhnt_state::program_map); m_maincpu->set_vblank_int("screen", FUNC(triplhnt_state::irq0_line_hold)); - NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); // battery-backed 74C89 at J5 + NVRAM(config, "nvram"); // battery-backed 74C89 at J5 F9334(config, m_latch); // J7 m_latch->q_out_cb<0>().set_nop(); // unused @@ -492,6 +467,7 @@ void triplhnt_state::triplhnt(machine_config &config) // video hardware screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); + screen.set_video_attributes(VIDEO_ALWAYS_UPDATE); screen.set_refresh_hz(60); screen.set_size(256, 262); screen.set_visarea(0, 255, 0, 239); @@ -525,16 +501,19 @@ ROM_START( triplhnt ) ROM_LOAD_NIB_HIGH( "8401.c1", 0x7C00, 0x400, CRC(7461b05e) SHA1(16573ae655c306a38ff0f29a3c3285d636907f38) ) ROM_LOAD_NIB_LOW ( "8405.c2", 0x7C00, 0x400, CRC(ba370b97) SHA1(5d799ce6ae56c315ff0abedea7ad9204bacc266b) ) + ROM_REGION( 0x10, "nvram", 0 ) // calibrated gun + ROM_LOAD( "74c89.j5", 0x00, 0x10, CRC(1a1a3802) SHA1(e82a1aec083c9cba2f5870ba0c266dc5e8dda3d3) ) + ROM_REGION( 0x1000, "sprites", 0 ) ROM_LOAD( "8423.n1", 0x0000, 0x800, CRC(9937d0da) SHA1(abb906c2d9869b09be5172cc7639bb9cda38831b) ) ROM_LOAD( "8422.r1", 0x0800, 0x800, CRC(803621dd) SHA1(ffbd7f87a86477e5eb94f12fc20a837128a02442) ) ROM_REGION( 0x200, "tiles", 0 ) - ROM_LOAD_NIB_HIGH( "8409.l3", 0x0000, 0x200, CRC(ec304172) SHA1(ccbf7e117fef7fa4288e3bf68f1a150b3a492ce6) ) - ROM_LOAD_NIB_LOW ( "8410.m3", 0x0000, 0x200, CRC(f75a1b08) SHA1(81b4733194462cd4cef7f4221ecb7abd1556b871) ) + ROM_LOAD_NIB_HIGH( "8409.l3", 0x000, 0x200, CRC(ec304172) SHA1(ccbf7e117fef7fa4288e3bf68f1a150b3a492ce6) ) + ROM_LOAD_NIB_LOW ( "8410.m3", 0x000, 0x200, CRC(f75a1b08) SHA1(81b4733194462cd4cef7f4221ecb7abd1556b871) ) ROM_END } // anonymous namespace -GAME( 1977, triplhnt, 0, triplhnt, triplhnt, triplhnt_state, init_triplhnt, 0, "Atari", "Triple Hunt", MACHINE_REQUIRES_ARTWORK | MACHINE_SUPPORTS_SAVE ) +GAME( 1977, triplhnt, 0, triplhnt, triplhnt, triplhnt_state, empty_init, 0, "Atari", "Triple Hunt", MACHINE_REQUIRES_ARTWORK | MACHINE_SUPPORTS_SAVE ) From 43b23c15ecf5f29fb0622dbd31c64d950f0eba3f Mon Sep 17 00:00:00 2001 From: m1macrophage <168948267+m1macrophage@users.noreply.github.com> Date: Sun, 12 Jan 2025 08:24:30 -0800 Subject: [PATCH 09/15] oberheim/dmx.cpp: Emulating pitch tunning. Optimizing pitch computations. (#13223) Also simplified and documented pitch computations. --- src/mame/oberheim/dmx.cpp | 240 +++++++++++++++++++++++++++++--------- 1 file changed, 182 insertions(+), 58 deletions(-) diff --git a/src/mame/oberheim/dmx.cpp b/src/mame/oberheim/dmx.cpp index 4d0223d68236c..2e87b31d570bd 100644 --- a/src/mame/oberheim/dmx.cpp +++ b/src/mame/oberheim/dmx.cpp @@ -45,7 +45,6 @@ educational tool. Known audio inaccuracies (reasons for MACHINE_IMPERFECT_SOUND): - No anti-aliasing filters (coming soon). -- No voice tuning (coming soon). - Closed and Accent hi-hat volume variations might be wrong. See comments in HIHAT_CONFIG (to be researched soon). - No metronome yet. @@ -62,7 +61,9 @@ Known audio inaccuracies (reasons for MACHINE_IMPERFECT_SOUND): Usage notes: - Interactive layout included. -- The mixer faders can be controlled with the mouse, or from the "Sliders" menu. +- The mixer faders can be controlled with the mouse, or from the "Slider + Controls" menu. +- Voices can be tuned using the "Sider Controls" menu. - The drum keys are mapped to the keyboard, starting at "Q". Specifically: Q - Bass 1, W - Snare 1, ... A - Bass 2, S - Snare 2, ... @@ -148,10 +149,14 @@ struct dmx_voice_card_config class dmx_voice_card : public device_t, public device_sound_interface { public: + // Default value of pitch adjustment trimpot. + static constexpr const s32 T1_DEFAULT_PERCENT = 50; + dmx_voice_card(const machine_config &mconfig, const char *tag, device_t *owner, const dmx_voice_card_config &config, required_memory_region *sample_rom) ATTR_COLD; dmx_voice_card(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0) ATTR_COLD; void trigger(bool tr0, bool tr1); + void set_pitch_adj(s32 t1_percent); // Valid values: 0-100. protected: void device_add_mconfig(machine_config &config) override ATTR_COLD; @@ -161,7 +166,9 @@ class dmx_voice_card : public device_t, public device_sound_interface private: void reset_counter(); - void configure_pitch(); + void init_pitch() ATTR_COLD; + void compute_pitch_variations(); + void select_pitch(); void configure_volume(); bool is_decay_enabled() const; @@ -173,8 +180,14 @@ class dmx_voice_card : public device_t, public device_sound_interface required_device m_timer; // 555, U5. required_device m_dac; // AM6070, U8. Compatible with DAC76. + // Configuration. Do not include in save state. const dmx_voice_card_config m_config; required_memory_region *m_sample_rom = nullptr; + std::vector m_cv; // 555 CV (pin 5) voltage variations. + std::vector m_sample_t; // Sample period variations. + s32 m_t1_percent = T1_DEFAULT_PERCENT; + + // Device state. bool m_counting = false; u16 m_counter = 0; // 4040 counter. @@ -203,6 +216,7 @@ dmx_voice_card::dmx_voice_card( , m_config(config) , m_sample_rom(sample_rom) { + init_pitch(); } dmx_voice_card::dmx_voice_card( @@ -235,7 +249,7 @@ void dmx_voice_card::trigger(bool tr0, bool tr1) m_decaying = false; if (m_config.pitch_control) - configure_pitch(); + select_pitch(); else configure_volume(); @@ -243,6 +257,13 @@ void dmx_voice_card::trigger(bool tr0, bool tr1) tr0, tr1, m_trigger_mode, m_volume); } +void dmx_voice_card::set_pitch_adj(s32 t1_percent) +{ + m_stream->update(); + m_t1_percent = t1_percent; + compute_pitch_variations(); +} + void dmx_voice_card::device_add_mconfig(machine_config &config) { TIMER(config, m_timer).configure_generic(FUNC(dmx_voice_card::clock_callback)); @@ -265,7 +286,7 @@ void dmx_voice_card::device_reset() { m_trigger_mode = 0; reset_counter(); - configure_pitch(); + compute_pitch_variations(); configure_volume(); } @@ -304,20 +325,14 @@ void dmx_voice_card::sound_stream_update( void dmx_voice_card::reset_counter() { + m_stream->update(); m_counter = 0; m_counting = false; } -void dmx_voice_card::configure_pitch() +void dmx_voice_card::init_pitch() { - // TODO: A lot of the computations below can be cached at object - // construction time for all 3 trigger modes. - - // Pitch variations are accomplished by changing the playback sample rate. - // This is done by changing the control voltage (CV) on the 555 timer that - // generates the sampling clock. - - // *** Compute CV input (pin 5) of the 555. + // Precompute all variations of CV (pin 5 of 555 timer). // The CV equations were derived from Kirchhoff analysis and verified with // simulations: https://tinyurl.com/26x8oq75 @@ -327,47 +342,113 @@ void dmx_voice_card::configure_pitch() // should help with accuracy. static constexpr const float VD = 0.48F; static constexpr const float R_555 = RES_K(5); - static constexpr const float R3 = RES_K(1); - static constexpr const float R4 = RES_K(10); static constexpr const float R5 = RES_K(3.3); - static constexpr const float T1 = RES_K(6); // TODO: 10K potentiometer. - float cv = VCC * 2 / 3; // The 555 default, if the CV pin is not connected. - const float r12 = m_config.r12; - if (m_trigger_mode == 1) + m_cv.clear(); + m_cv.push_back(VCC * 2 / 3); // The 555 default, if pin 5 is floating. + + if (m_config.pitch_control) { - const float alpha = 1.0 + r12 / m_config.r17; - cv = (alpha * R5 + r12) * (2 * VCC - 3 * VD) / - (3 * alpha * R5 + 3 * r12 + 2 * alpha * R_555) + VD; + const float r12 = m_config.r12; + + // For trigger mode 1. + const float alpha = 1.0F + r12 / m_config.r17; + m_cv.push_back((alpha * R5 + r12) * (2 * VCC - 3 * VD) / + (3 * alpha * R5 + 3 * r12 + 2 * alpha * R_555) + VD); + + // For trigger mode 2. + m_cv.push_back((R5 + r12) * (2 * VCC - 3 * VD) / + (3 * R5 + 3 * r12 + 2 * R_555) + VD); + + // For trigger mode 3. + m_cv.push_back(m_cv[0]); } - else if (m_trigger_mode == 2) + + for (int i = 0; i < m_cv.size(); ++i) + LOGMASKED(LOG_PITCH, "%s 555 CV %d: %f\n", tag(), i, m_cv[i]); + + // m_sample_t will be populated by subsequent calls to configure_pitch(). + m_sample_t.clear(); + m_sample_t.resize(m_cv.size()); +} + +void dmx_voice_card::compute_pitch_variations() +{ + static constexpr const float R3 = RES_K(1); + static constexpr const float R4 = RES_K(10); + static constexpr const float T1_MAX = RES_K(10); + + // The baseline pitch (and sampling rate) for all voice cards is controlled + // by a 555 timer (U5). Users can adjust the pitch with a trimpot (T1). + + // For voice cards configured for pitch control (m_config.pitch_control is + // true), pitch variations are accomplished by changing the Control Voltage + // (pin 5) of the 555 (see init_pitch()). + + // Computing the timer period is a bit involved, because of the use of CV, + // and because the 555 is not configured in the typical astable mode. + // For an RC circuit, V(t) = Vstart + (Vend - Vstart) * (1 - exp(-t / RC)). + // Solving for t: t = -RC * log( (Vend - V) / (Vend - Vstart) ). + // Let t_high be the time interval for which the 555 output is high. This is + // the time it takes for the capacitor to charge from CV/2 to CV. + // Let t_low be the time interval for which the 555 output is low. This is + // the time it takes for the capacitor to discharge from CV to CV/2. + // The timer period is then: t_high + t_low. t_* can be computed by + // substituting appropriate values in the function for `t`, keeping in mind + // that RC, Vstart, Vend and V are different for charging and discharging. + + // Compute RC time constant for charging. + assert(m_t1_percent >= 0 && m_t1_percent <= 100); + const float r_charge = m_t1_percent * T1_MAX / 100 + R4; + const float rc_charge = r_charge * m_config.c2; + + // Compute Vend and RC time constant for discharging, taking into account + // the atypical 555 configuration. + const float rc_discharge = RES_2_PARALLEL(r_charge, R3) * m_config.c2; + const float ve_discharge = VCC * RES_VOLTAGE_DIVIDER(r_charge, R3); + + // Optimization: when m_config.pitch_control is true, + // m_sample_t[0] = m_sample_t[3]. So skip index 0 and copy after the loop. + const int start_i = m_config.pitch_control ? 1 : 0; + + for (int i = start_i; i < m_sample_t.size(); ++i) { - cv = (R5 + r12) * (2 * VCC - 3 * VD) / - (3 * R5 + 3 * r12 + 2 * R_555) + VD; + const float cv = m_cv[i]; + const float half_cv = 0.5F * cv; + + // Time for C2 to charge from CV/2 (Vstart) to CV (V). Vend = VCC + const float t_high = -rc_charge * logf((VCC - cv) / (VCC - half_cv)); + assert(t_high > 0); + + // Time for C2 to discharge from CV (Vstart) to CV/2 (V). + const float t_low = -rc_discharge * logf((ve_discharge - half_cv) / (ve_discharge - cv)); + assert(t_low > 0); + + m_sample_t[i] = attotime::from_double(t_high + t_low); + LOGMASKED(LOG_PITCH, "%s Pitch variation %d: %f (%f, %f)\n", + tag(), i, 1.0 / m_sample_t[i].as_double(), t_high, t_low); } - const float cv_norm = cv / VCC; - LOGMASKED(LOG_PITCH, "S555 CV: %f\n", cv); - - // *** Compute sampling rate. - - // Compute time for which the output is high. - // TODO: T1 will not be a constant once tuning is supported. - const float r_charge = T1 + R4; - const float t_high = - -r_charge * m_config.c2 * logf((2 * cv_norm - 2) / (cv_norm - 2)); - assert(t_high > 0); - - // Compute time for which the output is low. - const float target_v_fraction = RES_VOLTAGE_DIVIDER(r_charge, R3); - const float effective_r = RES_2_PARALLEL(r_charge, R3); - const float t_low = - -effective_r * m_config.c2 * logf((cv_norm - 2 * target_v_fraction) / - (2 * (cv_norm - target_v_fraction))); - assert(t_low > 0); - - const attotime period = attotime::from_double(t_high + t_low); - m_timer->adjust(period, 0, period); - LOGMASKED(LOG_PITCH, "Sampling frequency: %f\n", 1.0 / period.as_double()); + + if (m_config.pitch_control) + m_sample_t[0] = m_sample_t[3]; + + select_pitch(); +} + +void dmx_voice_card::select_pitch() +{ + attotime sampling_t; + if (m_config.pitch_control) + sampling_t = m_sample_t[m_trigger_mode]; + else + sampling_t = m_sample_t[0]; + + if (sampling_t == m_timer->period()) + return; // Avoid resetting the timer in this case. + + m_timer->adjust(sampling_t, 0, sampling_t); + LOGMASKED(LOG_PITCH, "Setting sampling frequency: %f\n", + 1.0 / sampling_t.as_double()); } void dmx_voice_card::configure_volume() @@ -605,6 +686,7 @@ class dmx_state : public driver_device DECLARE_INPUT_CHANGED_MEMBER(voice_volume_changed); DECLARE_INPUT_CHANGED_MEMBER(metronome_volume_changed); DECLARE_INPUT_CHANGED_MEMBER(master_volume_changed); + DECLARE_INPUT_CHANGED_MEMBER(pitch_adj_changed); protected: void machine_start() override ATTR_COLD; @@ -1008,6 +1090,13 @@ DECLARE_INPUT_CHANGED_MEMBER(dmx_state::master_volume_changed) LOGMASKED(LOG_FADERS, "Master volume changed: %d\n", newval); } +DECLARE_INPUT_CHANGED_MEMBER(dmx_state::pitch_adj_changed) +{ + // Using "100 -" so that larger values increase pitch. + m_voices[param]->set_pitch_adj(100 - newval); + LOGMASKED(LOG_PITCH, "Voice %d pitch adjustment changed: %d\n", param, newval); +} + INPUT_PORTS_START(dmx) PORT_START("buttons_0") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("2") PORT_CODE(KEYCODE_2_PAD) @@ -1094,44 +1183,79 @@ INPUT_PORTS_START(dmx) // Fader potentiometers. P1-P10 on the Switch Board. PORT_START("fader_p1") - PORT_ADJUSTER(100, "BASS") + PORT_ADJUSTER(100, "BASS volume") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::voice_volume_changed), dmx_state::VC_BASS) PORT_START("fader_p2") - PORT_ADJUSTER(100, "SNARE") + PORT_ADJUSTER(100, "SNARE volume") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::voice_volume_changed), dmx_state::VC_SNARE) PORT_START("fader_p3") - PORT_ADJUSTER(100, "HI-HAT") + PORT_ADJUSTER(100, "HI-HAT volume") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::voice_volume_changed), dmx_state::VC_HIHAT) PORT_START("fader_p4") - PORT_ADJUSTER(100, "TOM1") + PORT_ADJUSTER(100, "TOM1 volume") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::voice_volume_changed), dmx_state::VC_SMALL_TOMS) PORT_START("fader_p5") - PORT_ADJUSTER(100, "TOM2") + PORT_ADJUSTER(100, "TOM2 volume") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::voice_volume_changed), dmx_state::VC_LARGE_TOMS) PORT_START("fader_p6") - PORT_ADJUSTER(100, "CYMBAL") + PORT_ADJUSTER(100, "CYMBAL volume") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::voice_volume_changed), dmx_state::VC_CYMBAL) PORT_START("fader_p7") - PORT_ADJUSTER(100, "PERC1") + PORT_ADJUSTER(100, "PERC1 volume") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::voice_volume_changed), dmx_state::VC_PERC1) PORT_START("fader_p8") - PORT_ADJUSTER(100, "PERC2") + PORT_ADJUSTER(100, "PERC2 volume") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::voice_volume_changed), dmx_state::VC_PERC2) PORT_START("fader_p9") - PORT_ADJUSTER(100, "MET") + PORT_ADJUSTER(100, "MET volume") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::metronome_volume_changed), 0) PORT_START("fader_p10") PORT_ADJUSTER(100, "VOLUME") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::master_volume_changed), 0) + + // Tunning potentiomenters. One per voice card, designated as T1 and labeled + // as "PITCH ADJ." + + PORT_START("pitch_adj_0") + PORT_ADJUSTER(dmx_voice_card::T1_DEFAULT_PERCENT, "BASS pitch") + PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::pitch_adj_changed), dmx_state::VC_BASS) + + PORT_START("pitch_adj_1") + PORT_ADJUSTER(dmx_voice_card::T1_DEFAULT_PERCENT, "SNARE pitch") + PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::pitch_adj_changed), dmx_state::VC_SNARE) + + PORT_START("pitch_adj_2") + PORT_ADJUSTER(dmx_voice_card::T1_DEFAULT_PERCENT, "HI-HAT pitch") + PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::pitch_adj_changed), dmx_state::VC_HIHAT) + + PORT_START("pitch_adj_3") + PORT_ADJUSTER(dmx_voice_card::T1_DEFAULT_PERCENT, "TOM1 pitch") + PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::pitch_adj_changed), dmx_state::VC_SMALL_TOMS) + + PORT_START("pitch_adj_4") + PORT_ADJUSTER(dmx_voice_card::T1_DEFAULT_PERCENT, "TOM2 pitch") + PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::pitch_adj_changed), dmx_state::VC_LARGE_TOMS) + + PORT_START("pitch_adj_5") + PORT_ADJUSTER(dmx_voice_card::T1_DEFAULT_PERCENT, "PERC1 pitch") + PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::pitch_adj_changed), dmx_state::VC_PERC1) + + PORT_START("pitch_adj_6") + PORT_ADJUSTER(dmx_voice_card::T1_DEFAULT_PERCENT, "PERC2 pitch") + PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::pitch_adj_changed), dmx_state::VC_PERC2) + + PORT_START("pitch_adj_7") + PORT_ADJUSTER(dmx_voice_card::T1_DEFAULT_PERCENT, "CYMBAL pitch") + PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(dmx_state::pitch_adj_changed), dmx_state::VC_CYMBAL) INPUT_PORTS_END ROM_START(obdmx) From 9a06c424e0a900a1327ef1c52768bb6602f300fc Mon Sep 17 00:00:00 2001 From: Mark Garlanger Date: Sun, 12 Jan 2025 10:27:13 -0600 Subject: [PATCH 10/15] formats/h17disk.cpp: Add format for Heath hard-sectored formats (#13222) * formats/h17disk.cpp: Add format for Heath hard-sectored formats * fix compile error * minor formatting changes --- scripts/src/formats.lua | 12 + src/devices/bus/heathzenith/h89/h17_fdc.cpp | 9 +- src/lib/formats/all.cpp | 9 + src/lib/formats/h17disk.cpp | 246 ++++++++++++++++++++ src/lib/formats/h17disk.h | 38 +++ 5 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 src/lib/formats/h17disk.cpp create mode 100644 src/lib/formats/h17disk.h diff --git a/scripts/src/formats.lua b/scripts/src/formats.lua index fa0d3d5f8dcf3..bf1086cb13aa9 100644 --- a/scripts/src/formats.lua +++ b/scripts/src/formats.lua @@ -1050,6 +1050,18 @@ if opt_tool(FORMATS, "GUAB_DSK") then } end +-------------------------------------------------- +-- +--@src/lib/formats/h17disk.h,FORMATS["H17D_DSK"] = true +-------------------------------------------------- + +if opt_tool(FORMATS, "H17D_DSK") then + files { + MAME_DIR.. "src/lib/formats/h17disk.cpp", + MAME_DIR.. "src/lib/formats/h17disk.h", + } +end + -------------------------------------------------- -- --@src/lib/formats/h8_cas.h,FORMATS["H8_CAS"] = true diff --git a/src/devices/bus/heathzenith/h89/h17_fdc.cpp b/src/devices/bus/heathzenith/h89/h17_fdc.cpp index 26edaaa892909..8f57a8ed72d98 100644 --- a/src/devices/bus/heathzenith/h89/h17_fdc.cpp +++ b/src/devices/bus/heathzenith/h89/h17_fdc.cpp @@ -15,6 +15,7 @@ #include "emu.h" #include "h17_fdc.h" +#include "formats/h17disk.h" #include "imagedev/floppy.h" #include "machine/s2350.h" @@ -63,6 +64,7 @@ class heath_h17_fdc_device : public device_t, public device_h89bus_right_card_in void ctrl_w(u8 val); u8 floppy_status_r(); + static void floppy_formats(format_registration &fr); void set_floppy(floppy_image_device *floppy); void step_w(int state); void dir_w(int state); @@ -340,6 +342,11 @@ TIMER_DEVICE_CALLBACK_MEMBER(heath_h17_fdc_device::tx_timer_cb) m_s2350->tcp_w(); } +void heath_h17_fdc_device::floppy_formats(format_registration &fr) +{ + fr.add(FLOPPY_H17D_FORMAT); +} + void heath_h17_fdc_device::device_add_mconfig(machine_config &config) { S2350(config, m_s2350, 0); @@ -348,7 +355,7 @@ void heath_h17_fdc_device::device_add_mconfig(machine_config &config) for (int i = 0; i < MAX_FLOPPY_DRIVES; i++) { // TODO -> add (and define) heath hard-sectored floppy formats. - FLOPPY_CONNECTOR(config, m_floppies[i], h17_floppies, "ssdd", floppy_image_device::default_fm_floppy_formats); + FLOPPY_CONNECTOR(config, m_floppies[i], h17_floppies, "ssdd", heath_h17_fdc_device::floppy_formats); m_floppies[i]->enable_sound(true); } diff --git a/src/lib/formats/all.cpp b/src/lib/formats/all.cpp index 80d5930e37bd0..bab86919cb727 100644 --- a/src/lib/formats/all.cpp +++ b/src/lib/formats/all.cpp @@ -320,6 +320,10 @@ #include "guab_dsk.h" #endif +#ifdef HAS_FORMATS_H17D_DSK +#include "h17disk.h" +#endif + #ifdef HAS_FORMATS_H8_CAS #include "h8_cas.h" #endif @@ -1530,4 +1534,9 @@ void mame_formats_full_list(mame_formats_enumerator &en) #ifdef HAS_FORMATS_X07_CAS en.add(x07_cassette_formats); // x07_cas.h #endif + + en.category("Heath"); +#ifdef HAS_FORMATS_H17D_DSK + en.add(FLOPPY_H17D_FORMAT); // h17disk.h +#endif } diff --git a/src/lib/formats/h17disk.cpp b/src/lib/formats/h17disk.cpp new file mode 100644 index 0000000000000..47d164fda1d77 --- /dev/null +++ b/src/lib/formats/h17disk.cpp @@ -0,0 +1,246 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +/********************************************************************* + +Heath H17D disk image format (version 2.0.0) + + Format for Heath hard-sectored 5.25" disk images. + + See https://heathkit.garlanger.com/diskformats/ for more information + + TODO - implement writing to H17D image + +*********************************************************************/ + +#include "h17disk.h" +#include "ioprocs.h" +#include "imageutl.h" + +#include + +static constexpr int TRACK_SIZE = 50'000; +static constexpr int BITCELL_SIZE = 4000; + +static constexpr int SECTOR_METADATA_SIZE = 16; + +static constexpr int SECTOR_DATA_SIZE = 256; +static constexpr int SECTORS_PER_TRACK = 10; + + +heath_h17d_format::heath_h17d_format() : floppy_image_format_t() +{ +} + +struct format { + int head_count; + int track_count; + uint32_t variant; +}; + +static const format formats[] = { + { 1, 40, floppy_image::SSSD10 }, // H-17-1 + { 2, 40, floppy_image::DSSD10 }, + { 1, 80, floppy_image::SSQD10 }, + { 2, 80, floppy_image::DSQD10 }, // H-17-4 + {} +}; + +struct block_header { + uint32_t block_name; + uint32_t length; +}; + +enum { + DskF = 0x466b7344, //!< "DskF", Disk Format + Parm = 0x6b726150, //!< "Parm", Parameters + Date = 0x65746144, //!< "Date", Date + Imgr = 0x72676d49, //!< "Imgr", Imager + + Prog = 0x676f7250, //!< "Prog", Program (creation) + Padd = 0x64646150, //!< "Padd", Padding + H8DB = 0x42443848, //!< "H8DB", H8D data block + SecM = 0x4d636553, //!< "SecM", Sector Metadata + Labl = 0x6c62614c, //!< "Labl", Label + Comm = 0x6d6d6f43, //!< "Comm", Comment +}; + +static std::pair find_block(util::random_read &io, uint32_t block_id) +{ + LOG_FORMATS("find_block: 0x%x\n", block_id); + + // start of file + int pos = 0; + block_header header = { 0, 0 }; + + do + { + pos += header.length + 8; + auto const [err, actual] = read_at(io, pos, (void *) &header, 8); + if (err || actual !=8) + { + return std::make_pair(0, 0); + } + header.length = swapendian_int32(header.length); + } + while (header.block_name != block_id); + + // update position to point to data portion of the block + return std::make_pair(pos + 8, header.length); +} + +static format find_format(util::random_read &io) +{ + auto const [pos, length] = find_block(io, DskF); + if ((pos == 0) || (length < 2) || (length > 3)) + { + LOG_FORMATS("Can't find valid DskF block %d/%d\n", pos, length); + + return {}; + } + + uint8_t buf[3]; + + auto const [err, actual] = read_at(io, pos, buf, length); + if (err || (actual != length)) + { + LOG_FORMATS("read error\n"); + + return {}; + } + + int head_count = buf[0]; + int track_count = buf[1]; + + for (int i = 0; formats[i].head_count; i++) + { + if ((formats[i].head_count == head_count) && (formats[i].track_count == track_count)) + { + LOG_FORMATS("find_format format found: %d - variant: 0x%x\n", i, formats[i].variant); + + return formats[i]; + } + } + + LOG_FORMATS("Invalid disk format - heads: %d, tracks: %d\n", head_count, track_count); + return {}; +} + +int heath_h17d_format::identify(util::random_read &io, uint32_t form_factor, const std::vector &variants) const +{ + uint8_t h[4]; + auto const [err, actual] = read_at(io, 0, h, 4); + + if (err || (actual != 4)) + { + return 0; + } + + // Verify "H17D" Signature. + if ((h[0] == 0x48) && (h[1] == 0x31) && (h[2] == 0x37) && (h[3] == 0x44)) + { + return FIFID_SIGN; + } + + return 0; +} + +bool heath_h17d_format::load(util::random_read &io, uint32_t form_factor, const std::vector &variants, floppy_image &image) const +{ + const format fmt = find_format(io); + + if (!fmt.head_count) + { + LOG_FORMATS("invalid format\n"); + + return false; + } + + image.set_variant(fmt.variant); + + std::vector buf; + + auto const [secm_pos, secm_length] = find_block(io, SecM); + + uint8_t sector_meta_data[SECTOR_METADATA_SIZE]; + uint8_t sector_data[SECTOR_DATA_SIZE]; + + for (int head = 0; head < fmt.head_count; head++) + { + for (int track = 0; track < fmt.track_count; track++) + { + for (int sector = 0; sector < SECTORS_PER_TRACK; sector++) + { + int sect_meta_pos = (sector + (track * fmt.head_count + head) * SECTORS_PER_TRACK) * SECTOR_METADATA_SIZE + secm_pos; + + auto const [err, actual] = read_at(io, sect_meta_pos, sector_meta_data, SECTOR_METADATA_SIZE); + + if (err || (actual != SECTOR_METADATA_SIZE)) + { + LOG_FORMATS("unable to read sect meta data %d/%d/%d\n", head, track, sector); + + return false; + } + int data_offset = sector_meta_data[0] << 24 | sector_meta_data[1] << 16 | sector_meta_data[2] << 8 | sector_meta_data[3]; + + auto const [err2, actual2] = read_at(io, data_offset, sector_data, SECTOR_DATA_SIZE); + + if (err2 || (actual2 != SECTOR_DATA_SIZE)) + { + LOG_FORMATS("unable to read sect data %d/%d/%d\n", head, track, sector); + + return false; + } + + // Inital 15 zero bytes + for (int i = 0; i < 15; i++) + { + fm_reverse_byte_w(buf, 0); + } + + // header (sync byte, volume, track, sector, checksum) + for (int i = 0; i < 5; i++) + { + fm_reverse_byte_w(buf, sector_meta_data[5 + i]); + } + + // 12 zero bytes + for (int i = 0; i < 12; i++) + { + fm_reverse_byte_w(buf, 0); + } + + // data sync byte + fm_reverse_byte_w(buf, sector_meta_data[10]); + + // sector data + for (int i = 0; i < 256; i++) + { + fm_reverse_byte_w(buf, sector_data[i]); + } + + // sector data checksum + fm_reverse_byte_w(buf, sector_meta_data[11]); + + // trailing zero's until the next sector hole usually ~ 30 characters. + while (buf.size() < TRACK_SIZE / SECTORS_PER_TRACK * (sector + 1)) + { + fm_reverse_byte_w(buf, 0); + } + } + + generate_track_from_levels(track, head, buf, 0, image); + buf.clear(); + } + } + + return true; +} + +void heath_h17d_format::fm_reverse_byte_w(std::vector &buffer, uint8_t val) const +{ + static unsigned char lookup[16] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf }; + + fm_w(buffer, 8, lookup[val & 0x0f] << 4 | lookup[val >> 4], BITCELL_SIZE); +} + +const heath_h17d_format FLOPPY_H17D_FORMAT; diff --git a/src/lib/formats/h17disk.h b/src/lib/formats/h17disk.h new file mode 100644 index 0000000000000..19ac0bac0526b --- /dev/null +++ b/src/lib/formats/h17disk.h @@ -0,0 +1,38 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +/********************************************************************* + +Heath h17disk disk image format + +The Heath hard-sectored disk format for the H8 and H89 systems with the +H17 controller on the H8 and the H-88-1 controller on the H89. + +*********************************************************************/ +#ifndef MAME_FORMATS_H17DISK_H +#define MAME_FORMATS_H17DISK_H + +#pragma once + +#include "flopimg.h" + +class heath_h17d_format : public floppy_image_format_t +{ +public: + heath_h17d_format(); + + int identify(util::random_read &io, uint32_t form_factor, const std::vector &variants) const override; + bool load(util::random_read &io, uint32_t form_factor, const std::vector &variants, floppy_image &image) const override; + + const char *name() const noexcept override { return "h17disk"; } + const char *description() const noexcept override { return "Heath H17D disk image"; } + const char *extensions() const noexcept override { return "h17,h17d,h17disk"; } + bool supports_save() const noexcept override { return false; } + +protected: + + void fm_reverse_byte_w(std::vector &buffer, uint8_t val) const; +}; + +extern const heath_h17d_format FLOPPY_H17D_FORMAT; + +#endif // MAME_FORMATS_H17DISK_H From 38111d1ba1b0f4b2646f8607cf5143a0c7738919 Mon Sep 17 00:00:00 2001 From: angelosa Date: Sun, 12 Jan 2025 17:04:49 +0100 Subject: [PATCH 11/15] New software list items marked not working ------------------------------------------ amiga_cd: The Big Red Adventure, Red Hat Linux 5.1 [archive.org], Emulators Unlimited Plus, Final Odyssey: Theseus Verses the Minotaur [redump.org] --- hash/amiga_cd.xml | 69 ++++++++++++++++++++++++++++++++++++++++-- hash/amigaocs_flop.xml | 3 ++ 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/hash/amiga_cd.xml b/hash/amiga_cd.xml index 231745ce83cac..aebfd94a1c6b4 100644 --- a/hash/amiga_cd.xml +++ b/hash/amiga_cd.xml @@ -7,10 +7,60 @@ http://redump.org/discs/system/acd --> + + + + + Red Hat Linux 5.1 + 1998 + Red Hat + + + + + + + + - - + + The Big Red Adventure (Europe) + 1997 + Power Computing + + + + + + + + + + + + Final Odyssey: Theseus verses the Minotaur (Europe) + 1997 + Vulcan Software + + + + + + + + + + Kang Fu 1996 GREat Effects Development (GREED) @@ -42,6 +92,21 @@ Not extensively tested, some games known to use ECS or AGA features. (cfr. Bruta + + + Emulators Unlimited Plus (Germany) + + + 1995? + + <unknown> + + + + + + + Ten on Ten Compilation (Europe) 1995 diff --git a/hash/amigaocs_flop.xml b/hash/amigaocs_flop.xml index fdd1cf067beb4..7c47c4b32a25b 100644 --- a/hash/amigaocs_flop.xml +++ b/hash/amigaocs_flop.xml @@ -6395,6 +6395,7 @@ ATK test: C:1 Bad 1992 Psygnosis @@ -16431,6 +16432,8 @@ ATK test: C:0 H:U 1 Sector Bad 1990 Rainbow Arts From 3eca0c379328c37860ff7b88477feed933141cc7 Mon Sep 17 00:00:00 2001 From: angelosa Date: Sun, 12 Jan 2025 17:45:17 +0100 Subject: [PATCH 12/15] amiga/amiga_v.cpp: fix sprite display in hires mode --- hash/amiga_cd.xml | 2 +- src/mame/amiga/amiga_v.cpp | 3 ++- src/mame/amiga/amigaaga.cpp | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/hash/amiga_cd.xml b/hash/amiga_cd.xml index aebfd94a1c6b4..68a6f072f6243 100644 --- a/hash/amiga_cd.xml +++ b/hash/amiga_cd.xml @@ -46,7 +46,7 @@ Not extensively tested - Final Odyssey: Theseus verses the Minotaur (Europe) + Final Odyssey: Theseus Verses the Minotaur (Europe) 1997 Vulcan Software > 6) & 0x2a; } - if ((raw_scanline & 1) == 0) + //if ((raw_scanline & 1) == 0) { - const int min_x = 0x18 << 1; + const int min_x = 0x18 << 1; const int max_x = 0x34 << 1; // TODO: refine, merge with OCS version From 43c5edd139178545db68a794bdd9ad57678098ad Mon Sep 17 00:00:00 2001 From: AJR Date: Sun, 12 Jan 2025 11:49:57 -0500 Subject: [PATCH 13/15] atari/tank8.cpp: Add addressable latch devices and XTAL definition; use raw parameters for screen --- src/emu/xtal.cpp | 1 + src/mame/atari/poolshrk.cpp | 4 ++-- src/mame/atari/tank8.cpp | 45 ++++++++++++++++++++++++------------- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/emu/xtal.cpp b/src/emu/xtal.cpp index 9d5f4f55a5a8b..e5536621d0849 100644 --- a/src/emu/xtal.cpp +++ b/src/emu/xtal.cpp @@ -198,6 +198,7 @@ const double XTAL::known_xtals[] = { 10'920'000, // 10.92_MHz_XTAL ADDS Viewpoint 60, Viewpoint A2 11'000'000, // 11_MHz_XTAL Mario I8039 sound 11'004'000, // 11.004_MHz_XTAL TI 911 VDT + 11'055'000, // 11.055_MHz_XTAL Atari Tank 8 11'059'200, // 11.0592_MHz_XTAL Used with MCS-51 to generate common baud rates 11'200'000, // 11.2_MHz_XTAL New York, New York 11'289'000, // 11.289_MHz_XTAL Vanguard diff --git a/src/mame/atari/poolshrk.cpp b/src/mame/atari/poolshrk.cpp index 4050ef13188c3..46241fe008c64 100644 --- a/src/mame/atari/poolshrk.cpp +++ b/src/mame/atari/poolshrk.cpp @@ -351,9 +351,8 @@ void poolshrk_state::palette(palette_device &palette) const void poolshrk_state::poolshrk(machine_config &config) { // basic machine hardware - M6800(config, m_maincpu, 11'055'000 / 8); // ? + M6800(config, m_maincpu, 11.055_MHz_XTAL / 8); // divider not verified m_maincpu->set_addrmap(AS_PROGRAM, &poolshrk_state::cpu_map); - m_maincpu->set_vblank_int("screen", FUNC(poolshrk_state::irq0_line_assert)); WATCHDOG_TIMER(config, m_watchdog); @@ -364,6 +363,7 @@ void poolshrk_state::poolshrk(machine_config &config) screen.set_visarea(1, 255, 24, 255); screen.set_screen_update(FUNC(poolshrk_state::screen_update)); screen.set_palette(m_palette); + screen.screen_vblank().set_inputline(m_maincpu, M6800_IRQ_LINE, ASSERT_LINE); GFXDECODE(config, m_gfxdecode, m_palette, gfx_poolshrk); PALETTE(config, m_palette, FUNC(poolshrk_state::palette), 4); diff --git a/src/mame/atari/tank8.cpp b/src/mame/atari/tank8.cpp index 56da95dd6b734..05363ce53b876 100644 --- a/src/mame/atari/tank8.cpp +++ b/src/mame/atari/tank8.cpp @@ -12,6 +12,7 @@ Atari Tank 8 driver #include "tank8_a.h" #include "cpu/m6800/m6800.h" +#include "machine/74259.h" #include "sound/discrete.h" #include "emupal.h" @@ -66,7 +67,7 @@ class tank8_state : public driver_device emu_timer *m_collision_timer = nullptr; uint8_t collision_r(); - void lockout_w(offs_t offset, uint8_t data); + template void lockout_w(int state); void int_reset_w(uint8_t data); void video_ram_w(offs_t offset, uint8_t data); void crash_w(uint8_t data); @@ -74,7 +75,6 @@ class tank8_state : public driver_device void bugle_w(uint8_t data); void bug_w(uint8_t data); void attract_w(uint8_t data); - void motor_w(offs_t offset, uint8_t data); TILE_GET_INFO_MEMBER(get_tile_info); @@ -365,9 +365,10 @@ uint8_t tank8_state::collision_r() return m_collision_index; } -void tank8_state::lockout_w(offs_t offset, uint8_t data) +template +void tank8_state::lockout_w(int state) { - machine().bookkeeping().coin_lockout_w(offset, ~data & 1); + machine().bookkeeping().coin_lockout_w(N, !state); } @@ -422,11 +423,6 @@ void tank8_state::attract_w(uint8_t data) m_discrete->write(TANK8_ATTRACT_EN, data); } -void tank8_state::motor_w(offs_t offset, uint8_t data) -{ - m_discrete->write(NODE_RELATIVE(TANK8_MOTOR1_EN, offset), data); -} - void tank8_state::cpu_map(address_map &map) { map(0x0000, 0x00ff).ram(); @@ -453,7 +449,7 @@ void tank8_state::cpu_map(address_map &map) map(0x1c10, 0x1c1f).writeonly().share(m_pos_v_ram); map(0x1c20, 0x1c2f).writeonly().share(m_pos_d_ram); - map(0x1c30, 0x1c37).nopr().w(FUNC(tank8_state::lockout_w)); + map(0x1c30, 0x1c37).nopr().w("locklatch", FUNC(f9334_device::write_d0)); map(0x1d00, 0x1d00).nopr().w(FUNC(tank8_state::int_reset_w)); map(0x1d01, 0x1d01).nopr().w(FUNC(tank8_state::crash_w)); map(0x1d02, 0x1d02).nopr().w(FUNC(tank8_state::explosion_w)); @@ -461,7 +457,7 @@ void tank8_state::cpu_map(address_map &map) map(0x1d04, 0x1d04).nopr().w(FUNC(tank8_state::bug_w)); map(0x1d05, 0x1d05).nopr().writeonly().share(m_team); map(0x1d06, 0x1d06).nopr().w(FUNC(tank8_state::attract_w)); - map(0x1e00, 0x1e07).nopr().w(FUNC(tank8_state::motor_w)); + map(0x1e00, 0x1e07).nopr().w("motorlatch", FUNC(f9334_device::write_d0)); } @@ -661,16 +657,33 @@ GFXDECODE_END void tank8_state::tank8(machine_config &config) { // basic machine hardware - M6800(config, m_maincpu, 11'055'000 / 10); // ? + M6800(config, m_maincpu, 11.055_MHz_XTAL / 10); // divider not verified m_maincpu->set_addrmap(AS_PROGRAM, &tank8_state::cpu_map); + f9334_device &locklatch(F9334(config, "locklatch")); // C5 on audio board + locklatch.q_out_cb<0>().set(FUNC(tank8_state::lockout_w<0>)); + locklatch.q_out_cb<1>().set(FUNC(tank8_state::lockout_w<1>)); + locklatch.q_out_cb<2>().set(FUNC(tank8_state::lockout_w<2>)); + locklatch.q_out_cb<3>().set(FUNC(tank8_state::lockout_w<3>)); + locklatch.q_out_cb<4>().set(FUNC(tank8_state::lockout_w<4>)); + locklatch.q_out_cb<5>().set(FUNC(tank8_state::lockout_w<5>)); + locklatch.q_out_cb<6>().set(FUNC(tank8_state::lockout_w<6>)); + locklatch.q_out_cb<7>().set(FUNC(tank8_state::lockout_w<7>)); + + f9334_device &motorlatch(F9334(config, "motorlatch")); // D5 on audio board + motorlatch.q_out_cb<0>().set(m_discrete, FUNC(discrete_device::write_line)); + motorlatch.q_out_cb<1>().set(m_discrete, FUNC(discrete_device::write_line)); + motorlatch.q_out_cb<2>().set(m_discrete, FUNC(discrete_device::write_line)); + motorlatch.q_out_cb<3>().set(m_discrete, FUNC(discrete_device::write_line)); + motorlatch.q_out_cb<4>().set(m_discrete, FUNC(discrete_device::write_line)); + motorlatch.q_out_cb<5>().set(m_discrete, FUNC(discrete_device::write_line)); + motorlatch.q_out_cb<6>().set(m_discrete, FUNC(discrete_device::write_line)); + motorlatch.q_out_cb<7>().set(m_discrete, FUNC(discrete_device::write_line)); + // video hardware SCREEN(config, m_screen, SCREEN_TYPE_RASTER); m_screen->set_video_attributes(VIDEO_UPDATE_AFTER_VBLANK); - m_screen->set_refresh_hz(60); - m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(30 * 1000000 / 15681)); - m_screen->set_size(512, 524); - m_screen->set_visarea(16, 495, 0, 463); + m_screen->set_raw(11.055_MHz_XTAL * 2, 703, 16, 496, 524, 0, 464); // FIXME: should be 30 Hz interlaced, with two VBLANK interrupts per frame m_screen->set_screen_update(FUNC(tank8_state::screen_update)); m_screen->screen_vblank().set(FUNC(tank8_state::screen_vblank)); m_screen->set_palette(m_palette); From ff92d10a0485717149b6cebc7122a3d545d48fd3 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Mon, 13 Jan 2025 05:43:09 +1100 Subject: [PATCH 14/15] osd: Added helper for getting CPU cache line size. --- src/devices/cpu/drcbex64.cpp | 17 +++++++++++-- src/devices/cpu/drcbex86.cpp | 16 ++++++++++-- src/osd/modules/lib/osdlib_macosx.cpp | 17 +++++++++++++ src/osd/modules/lib/osdlib_unix.cpp | 26 +++++++++++++++++++ src/osd/modules/lib/osdlib_win32.cpp | 36 +++++++++++++++++++++++++++ src/osd/osdcore.h | 11 ++++++++ 6 files changed, 119 insertions(+), 4 deletions(-) diff --git a/src/devices/cpu/drcbex64.cpp b/src/devices/cpu/drcbex64.cpp index 17b25bba95862..891b8c69dd574 100644 --- a/src/devices/cpu/drcbex64.cpp +++ b/src/devices/cpu/drcbex64.cpp @@ -945,8 +945,21 @@ void drcbe_x64::generate(drcuml_block &block, const instruction *instlist, uint3 m_hash.block_begin(block, instlist, numinst); m_map.block_begin(block); - // compute the base by aligning the cache top to a cache line (assumed to be 64 bytes) - x86code *dst = (x86code *)(uint64_t(m_cache.top() + 63) & ~63); + // compute the base by aligning the cache top to a cache line + auto [err, linesize] = osd_get_cache_line_size(); + uintptr_t linemask = 63; + if (err) + { + osd_printf_verbose("Error getting cache line size (%s:%d %s), assuming 64 bytes\n", err.category().name(), err.value(), err.message()); + } + else + { + assert(linesize); + linemask = linesize - 1; + for (unsigned shift = 1; linemask & (linemask + 1); ++shift) + linemask |= linemask >> shift; + } + x86code *dst = (x86code *)(uintptr_t(m_cache.top() + linemask) & ~linemask); CodeHolder ch; ch.init(Environment::host(), uint64_t(dst)); diff --git a/src/devices/cpu/drcbex86.cpp b/src/devices/cpu/drcbex86.cpp index 6e187e6846a36..d9a6b79e13742 100644 --- a/src/devices/cpu/drcbex86.cpp +++ b/src/devices/cpu/drcbex86.cpp @@ -840,8 +840,20 @@ void drcbe_x86::generate(drcuml_block &block, const instruction *instlist, uint3 m_hash.block_begin(block, instlist, numinst); m_map.block_begin(block); - // compute the base by aligning the cache top to a cache line (assumed to be 64 bytes) - x86code *dst = (x86code *)(uint64_t(m_cache.top() + 63) & ~63); + // compute the base by aligning the cache top to a cache line + auto [err, linesize] = osd_get_cache_line_size(); + uintptr_t linemask = 63; + if (err) + { + osd_printf_verbose("Error getting cache line size (%s:%d %s), assuming 64 bytes\n", err.category().name(), err.value(), err.message()); + } + else + { + assert(linesize); + linemask = linesize - 1; + for (unsigned shift = 1; linemask & (linemask + 1); ++shift) + linemask |= linemask >> shift; + } CodeHolder ch; ch.init(Environment::host(), uint64_t(dst)); diff --git a/src/osd/modules/lib/osdlib_macosx.cpp b/src/osd/modules/lib/osdlib_macosx.cpp index 9d13f118ff2aa..54836f9ec69a8 100644 --- a/src/osd/modules/lib/osdlib_macosx.cpp +++ b/src/osd/modules/lib/osdlib_macosx.cpp @@ -56,6 +56,7 @@ void osd_process_kill() kill(getpid(), SIGKILL); } + //============================================================ // osd_break_into_debugger //============================================================ @@ -81,6 +82,22 @@ void osd_break_into_debugger(const char *message) } +//============================================================ +// osd_get_cache_line_size +//============================================================ + +std::pair osd_get_cache_line_size() noexcept +{ + size_t result = 0; + size_t resultsize = sizeof(result); + int const err = sysctlbyname("hw.cachelinesize", &result, &resultsize, 0, 0); + if (!err) + return std::make_pair(std::error_condition(), unsigned(result)); + else + return std::make_pair(std::error_condition(err, std::generic_category()), 0U); +} + + //============================================================ // osd_get_clipboard_text //============================================================ diff --git a/src/osd/modules/lib/osdlib_unix.cpp b/src/osd/modules/lib/osdlib_unix.cpp index 20f6a9ab40c3c..3600458022283 100644 --- a/src/osd/modules/lib/osdlib_unix.cpp +++ b/src/osd/modules/lib/osdlib_unix.cpp @@ -53,6 +53,7 @@ void osd_process_kill() kill(getpid(), SIGKILL); } + //============================================================ // osd_break_into_debugger //============================================================ @@ -68,6 +69,31 @@ void osd_break_into_debugger(const char *message) #endif } + +//============================================================ +// osd_get_cache_line_size +//============================================================ + +std::pair osd_get_cache_line_size() noexcept +{ +#if defined(__linux__) + FILE *const f = std::fopen("/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size", "r"); + if (!f) + return std::make_pair(std::error_condition(errno, std::generic_category()), 0U); + + unsigned result = 0; + auto const cnt = std::fscanf(f, "%u", &result); + std::fclose(f); + if (1 == cnt) + return std::make_pair(std::error_condition(), result); + else + return std::make_pair(std::errc::io_error, 0U); +#else // defined(__linux__) + return std::make_pair(std::errc::not_supported, 0U); +#endif +} + + #ifdef SDLMAME_ANDROID std::string osd_get_clipboard_text() noexcept { diff --git a/src/osd/modules/lib/osdlib_win32.cpp b/src/osd/modules/lib/osdlib_win32.cpp index d42ad14d3df64..cf3fd7c9320ab 100644 --- a/src/osd/modules/lib/osdlib_win32.cpp +++ b/src/osd/modules/lib/osdlib_win32.cpp @@ -106,6 +106,42 @@ void osd_break_into_debugger(const char *message) #endif } + +//============================================================ +// osd_get_cache_line_size +//============================================================ + +std::pair osd_get_cache_line_size() noexcept +{ + DWORD resultsize = 0; + if (GetLogicalProcessorInformation(nullptr, &resultsize) || (ERROR_INSUFFICIENT_BUFFER != GetLastError()) || !resultsize) + return std::make_pair(std::errc::operation_not_permitted, 0U); + + auto const result = reinterpret_cast(std::malloc(resultsize)); + if (!result) + return std::make_pair(std::errc::not_enough_memory, 0U); + + if (!GetLogicalProcessorInformation(result, &resultsize)) + { + std::free(result); + return std::make_pair(std::errc::operation_not_permitted, 0U); + } + + for (unsigned i = 0; i < (resultsize / sizeof(result[0])); ++i) + { + if ((RelationCache == result[i].Relationship) && (1 == result[i].Cache.Level)) + { + unsigned const linesize = result[i].Cache.LineSize; + std::free(result); + return std::make_pair(std::error_condition(), linesize); + } + } + + std::free(result); + return std::make_pair(std::errc::operation_not_permitted, 0U); +} + + //============================================================ // get_clipboard_text_by_format //============================================================ diff --git a/src/osd/osdcore.h b/src/osd/osdcore.h index f3f5fc2e9b33c..b3dc209991304 100644 --- a/src/osd/osdcore.h +++ b/src/osd/osdcore.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -128,6 +129,8 @@ osd_ticks_t osd_ticks_per_second() noexcept; -----------------------------------------------------------------------------*/ void osd_sleep(osd_ticks_t duration) noexcept; + + /*************************************************************************** WORK ITEM INTERFACES ***************************************************************************/ @@ -350,6 +353,14 @@ void osd_work_item_release(osd_work_item *item); void osd_break_into_debugger(const char *message); +/// \brief Get cache line size in bytes +/// +/// This function gets the host CPU's level 1 cache line size in bytes. +/// \return A pair consisting of an error condition and the cache line +/// size in bytes if successful. +std::pair osd_get_cache_line_size() noexcept; + + /*************************************************************************** UNCATEGORIZED INTERFACES From aa0c4f914f230f8236ed4e315a21f6064fbb9aac Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Mon, 13 Jan 2025 05:54:28 +1100 Subject: [PATCH 15/15] =?UTF-8?q?cpu/drcbex86.cpp:=20Sorry,=20I=E2=80=99m?= =?UTF-8?q?=20an=20idiot,=20didn't=20stage=20this=20line.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/devices/cpu/drcbex86.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices/cpu/drcbex86.cpp b/src/devices/cpu/drcbex86.cpp index d9a6b79e13742..aadd119a3616d 100644 --- a/src/devices/cpu/drcbex86.cpp +++ b/src/devices/cpu/drcbex86.cpp @@ -854,6 +854,7 @@ void drcbe_x86::generate(drcuml_block &block, const instruction *instlist, uint3 for (unsigned shift = 1; linemask & (linemask + 1); ++shift) linemask |= linemask >> shift; } + x86code *dst = (x86code *)(uintptr_t(m_cache.top() + linemask) & ~linemask); CodeHolder ch; ch.init(Environment::host(), uint64_t(dst));