nmk16: get sprite dma trigger from prom, it's 2 scanlines earlier

This commit is contained in:
hap 2024-08-31 17:38:57 +02:00
parent a1f3f25093
commit f82e2958e6
3 changed files with 42 additions and 59 deletions

View File

@ -693,7 +693,7 @@ void nmk16_state::bioship_map(address_map &map)
void nmk16_state::hachamf_map(address_map &map)
{
map(0x000000, 0x03ffff).rom();
// I/O Region
map(0x080000, 0x080001).portr("IN0");
map(0x080002, 0x080003).portr("IN1");
map(0x080008, 0x080009).portr("DSW1");
@ -704,19 +704,13 @@ void nmk16_state::hachamf_map(address_map &map)
map(0x080019, 0x080019).w(FUNC(nmk16_state::tilebank_w));
map(0x08001f, 0x08001f).w(m_nmk004, FUNC(nmk004_device::write));
// Video Region
map(0x088000, 0x0887ff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette");
map(0x08c000, 0x08c007).w(FUNC(nmk16_state::scroll_w<0>)).umask16(0x00ff);
map(0x090000, 0x093fff).ram().w(FUNC(nmk16_state::bgvideoram_w<0>)).share("bgvideoram0");
map(0x09c000, 0x09c7ff).ram().w(FUNC(nmk16_state::txvideoram_w)).share("txvideoram");
// Main RAM, inc sprites, shared with MCU
map(0x0f0000, 0x0fffff).ram().share("mainram"); // ram is shared with MCU
map(0x0f0000, 0x0fffff).ram().share("mainram"); // Main RAM, inc sprites, shared with MCU
}
void nmk16_state::tdragon_map(address_map &map)
{
map(0x000000, 0x03ffff).rom();
@ -4022,12 +4016,12 @@ GFXDECODE_END
void nmk16_state::machine_start()
{
save_item(NAME(m_interrupt_trigger));
save_item(NAME(m_vtiming_val));
}
void nmk16_state::machine_reset()
{
m_interrupt_trigger = 0x01;
m_vtiming_val = 0xff;
}
/***************************************************************************
@ -4213,17 +4207,17 @@ void nmk16_state::set_screen_hires(machine_config &config)
*/
TIMER_DEVICE_CALLBACK_MEMBER(nmk16_state::nmk16_scanline)
{
// constexpr int SPRDMA_INDEX = 0; // not used in emulation TODO: check if it could be used to trigger the sprite DMA instead of setting it 4 lines after VBOUT
// constexpr int VSYNC_INDEX = 1; // not used in emulation
// constexpr int VBLANK_INDEX = 2; // not used in emulation
// constexpr int NOT_USED = 3; // not used in emulation
constexpr int SPRDMA_INDEX = 0;
// constexpr int VSYNC_INDEX = 1; // not used in emulation
// constexpr int VBLANK_INDEX = 2; // not used in emulation
// constexpr int NOT_USED = 3; // not used in emulation
constexpr int IPL0_INDEX = 4;
constexpr int IPL1_INDEX = 5;
constexpr int IPL2_INDEX = 6;
constexpr int TRIGG_INDEX = 7;
constexpr int PROM_START_OFFSET = 0x75; // previous entries are never addressed
constexpr int PROM_FRAME_OFFSET = 0x0b; // first 11 "used" entries (from 0x75 to 0x7f: 0xb entries) are prior to start of frame, which occurs on 0x80 address (128 entry)
constexpr int PROM_START_OFFSET = 0x75; // previous entries are never addressed
constexpr int PROM_FRAME_OFFSET = 0x0b; // first 11 "used" entries (from 0x75 to 0x7f: 0xb entries) are prior to start of frame, which occurs on 0x80 address (128 entry)
u8 *prom = m_vtiming_prom->base();
int len = m_vtiming_prom->bytes();
@ -4233,33 +4227,28 @@ TIMER_DEVICE_CALLBACK_MEMBER(nmk16_state::nmk16_scanline)
// every PROM entry is addressed each 2 scanlines, so only even lines are actually addressing it:
if ((scanline & 0x1) == 0x0)
{
int address = (((scanline / 2) + PROM_FRAME_OFFSET) % (len - PROM_START_OFFSET)) + PROM_START_OFFSET;
int promAddress = (((scanline / 2) + PROM_FRAME_OFFSET) % (len - PROM_START_OFFSET)) + PROM_START_OFFSET;
LOG("nmk16_scanline: Scanline: %03d - Current PROM entry: %03d\n", scanline, address);
LOG("nmk16_scanline: Scanline: %03d - Current PROM entry: %03d\n", scanline, promAddress);
u8 val = prom[address];
u8 val = prom[promAddress];
// Interrupt requests are triggered at raising edge of bit 7:
u8 trigger = BIT(val, TRIGG_INDEX);
if (m_interrupt_trigger == 0 && trigger == 1)
// Interrupt requests are triggered at rising edge of bit 7:
if (BIT(val & ~m_vtiming_val, TRIGG_INDEX))
{
u8 int_level = bitswap<3>(val, IPL2_INDEX, IPL1_INDEX, IPL0_INDEX);
if (int_level > 0)
{
LOG("nmk16_scanline: Triggered interrupt: IRQ%d at scanline: %03d\n", int_level, scanline);
m_maincpu->set_input_line(int_level, HOLD_LINE);
}
// Triggered at VBOUT. TODO: check if this could be triggered using SPRDMA_INDEX instead
if (int_level == 4)
{
m_dma_timer->adjust(m_screen->time_until_pos(scanline + 4)); // as per UPL docs, 256 usec after VBOUT = 4 lines, but index on the PROM says otherwise.
}
}
m_interrupt_trigger = trigger;
// Sprite DMA, as per UPL docs, 256 usec after VBOUT = 4 lines, but index on the PROM says otherwise:
if (BIT(val & ~m_vtiming_val, SPRDMA_INDEX))
sprite_dma();
m_vtiming_val = val;
}
}
@ -4286,7 +4275,7 @@ Timing:
LV4 LV2 LV1 LV1
| DISPLAY
|<->|<--->| |
|256| 694 | |
|128| 694 | |
| us| usec| |
| | DMA | |
@ -4305,17 +4294,18 @@ TIMER_DEVICE_CALLBACK_MEMBER(nmk16_state::nmk16_hacky_scanline)
{
const int VBIN_SCANLINE = 16;
const int VBOUT_SCANLINE = VBIN_SCANLINE + 224; // VBIN + 224 lines high of active video
const int SPRDMA_SCANLINE = VBOUT_SCANLINE + 4; // 256 usec after VBOUT = 4 lines (each line is 64 USEC)
const int SPRDMA_SCANLINE = VBOUT_SCANLINE + 2; // 2 lines after VBOUT
const int IRQ1_SCANLINE_1 = VBIN_SCANLINE + 52; // 52 lines after VBIN and 68 from the start of frame
const int IRQ1_SCANLINE_2 = IRQ1_SCANLINE_1 + 128; // 128 lines after IRQ1_SCANLINE_1
int scanline = param;
if (scanline == VBOUT_SCANLINE) // vblank-out irq
{
m_maincpu->set_input_line(4, HOLD_LINE);
m_dma_timer->adjust(m_screen->time_until_pos(SPRDMA_SCANLINE)/*attotime::from_usec(256)*/);
}
// sprite DMA after VBOUT
if (scanline == SPRDMA_SCANLINE)
sprite_dma();
/* Vblank-in irq, Vandyke definitely relies that irq fires at scanline ~0 instead of 112 (as per previous
cpu_getiloops function implementation), mostly noticeable with sword collisions and related attract mode behaviour. */
@ -4336,7 +4326,7 @@ void nmk16_state::set_hacky_interrupt_timing(machine_config &config)
TIMER(config, "scantimer").configure_scanline(FUNC(nmk16_state::nmk16_hacky_scanline), "screen", 0, 1);
}
TIMER_CALLBACK_MEMBER(nmk16_state::dma_callback)
void nmk16_state::sprite_dma()
{
// 2 buffers confirmed on PCB, 1 on sabotenb
memcpy(m_spriteram_old2.get(),m_spriteram_old.get(), 0x1000);
@ -4994,10 +4984,11 @@ void nmk16_state::strahljbl(machine_config &config)
seibu_sound.ym_write_callback().set("ymsnd", FUNC(ym3812_device::write));
}
// OSC : 10MHz, 12MHz, 16MHz
void nmk16_state::hachamf(machine_config &config)
{
// basic machine hardware
M68000(config, m_maincpu, 10000000); // 10 MHz ?
M68000(config, m_maincpu, 10000000); // MC68000P10, 10 MHz ?
m_maincpu->set_addrmap(AS_PROGRAM, &nmk16_state::hachamf_map);
set_interrupt_timing(config);
@ -5032,8 +5023,16 @@ void nmk16_state::hachamf(machine_config &config)
m_oki[1]->add_route(ALL_OUTPUTS, "mono", 0.10);
}
u8 tdragon_prot_state::mcu_port7_r()
void tdragon_prot_state::hachamf_prot(machine_config &config)
{
hachamf(config);
TMP91640(config, m_protcpu, 4000000); // Toshiba TMP91640 marked as NMK-113, with 16Kbyte internal ROM, 512bytes internal RAM
m_protcpu->set_addrmap(AS_PROGRAM, &tdragon_prot_state::tdragon_prot_map);
m_protcpu->port_write<6>().set(FUNC(tdragon_prot_state::mcu_port6_w));
m_protcpu->port_read<5>().set(FUNC(tdragon_prot_state::mcu_port5_r));
m_protcpu->port_read<6>().set(FUNC(tdragon_prot_state::mcu_port6_r));
// The NMK-113 code contains multiple different codepaths, which appear to be for different games
// a value is read from port 7, and masked with 0xf
// This happens in various places in the code, with 5 different possible startup programs, and
@ -5057,20 +5056,7 @@ u8 tdragon_prot_state::mcu_port7_r()
// 0x0d - unknown
// 0x0e - Double Dealer (but we use the single game 110 found on a Double Dealer PCB)
// 0x0f - Thunder Dragon (but we use the single game 110 found on a Thunder Dragon PCB)
return 0x0c;
}
void tdragon_prot_state::hachamf_prot(machine_config &config)
{
hachamf(config);
TMP91640(config, m_protcpu, 4000000); // Toshiba TMP91640 marked as NMK-113, with 16Kbyte internal ROM, 512bytes internal RAM
m_protcpu->set_addrmap(AS_PROGRAM, &tdragon_prot_state::tdragon_prot_map);
m_protcpu->port_write<6>().set(FUNC(tdragon_prot_state::mcu_port6_w));
m_protcpu->port_read<5>().set(FUNC(tdragon_prot_state::mcu_port5_r));
m_protcpu->port_read<6>().set(FUNC(tdragon_prot_state::mcu_port6_r));
m_protcpu->port_read<7>().set(FUNC(tdragon_prot_state::mcu_port7_r));
m_protcpu->port_read<7>().set_constant(0x0c);
config.set_maximum_quantum(attotime::from_hz(6000));
}
@ -10305,6 +10291,7 @@ ROM_START( twinactn )
ROM_LOAD( "afega.su13", 0x040000, 0x40000, CRC(30e1c306) SHA1(c859f11fd329793b11e96264e91c79a557b488a4) )
ROM_END
/***************************************************************************
@ -10313,7 +10300,6 @@ ROM_END
***************************************************************************/
GAME( 1989, tharrier, 0, tharrier, tharrier, nmk16_state, init_tharrier, ROT270, "UPL", "Task Force Harrier", MACHINE_NO_COCKTAIL )
GAME( 1989, tharrieru, tharrier, tharrier, tharrier, nmk16_state, init_tharrier, ROT270, "UPL (American Sammy license)", "Task Force Harrier (US)", MACHINE_NO_COCKTAIL ) // US version but no regional notice

View File

@ -144,7 +144,6 @@ protected:
optional_ioport_array<2> m_dsw_io;
optional_ioport_array<3> m_in_io;
emu_timer *m_dma_timer = nullptr;
int m_tilerambank = 0;
int m_sprdma_base = 0;
int mask[4*2]{};
@ -158,7 +157,7 @@ protected:
u8 m_scroll[2][4]{};
u16 m_vscroll[4]{};
int m_prot_count = 0;
u8 m_interrupt_trigger;
u8 m_vtiming_val = 0;
void mainram_strange_w(offs_t offset, u16 data/*, u16 mem_mask = ~0*/);
u16 mainram_swapped_r(offs_t offset);
@ -207,7 +206,7 @@ protected:
u32 screen_update_strahl(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
u32 screen_update_bjtwin(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void screen_vblank_powerins_bootleg(int state);
TIMER_CALLBACK_MEMBER(dma_callback);
void sprite_dma();
TIMER_DEVICE_CALLBACK_MEMBER(manybloc_scanline);
void video_init();
void draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, u16 *src);
@ -293,7 +292,6 @@ protected:
void mcu_port6_w(u8 data);
u8 mcu_port5_r();
u8 mcu_port6_r();
u8 mcu_port7_r(); // NMK-113 uses this
u8 m_bus_status;
};

View File

@ -90,7 +90,6 @@ void nmk16_state::video_init()
m_bgbank = 0;
m_mustang_bg_xscroll = 0;
m_dma_timer = timer_alloc(FUNC(nmk16_state::dma_callback), this);
save_pointer(NAME(m_spriteram_old), 0x1000/2);
save_pointer(NAME(m_spriteram_old2), 0x1000/2);
save_item(NAME(m_bgbank));