Added proper NMK004 internal rom [trap15]

Hooked up support for NMK004 internal rom in MAME, replacing Nicola's old simulation code [trap15, David Haywood]

Fixed TLCS90 16-bit timers & support NMI in the core [trap15]

Various tweaks and improvements in nmk16.c (timings, sound balance, etc.) [trap15, David Haywood]

US AAF Mustang now has sound / music for the first time

Much better sound / music in the following games Bio-ship Paladin, Vandyke, Black Heart, Acrobat Mission, Koutetsu Yousai Strahl, Thunder Dragon, Hacha Mecha Fighter, Super Spacefortress Macross, GunNail

new clones
Hacha Mecha Fighter (19th Sep. 1991, unprotected, bootleg Thunder Dragon conversion) [trap15]

note, Thunder Dragon parent was not protected, I've marked it as such and removed the protection sim from it
The protected Hacha Mecha Fighter set never worked properly, I've demoted it to non-working as a result, the new bootleg works with full sound and correct game logic.
The protected sets don't handshake with the NMK004 so now lack sound (the sim code didn't care)

note2, currently needs an ugly kludge to prevent bioship resetting periodically, the nmk004 is used as a watchdog, but it ends up hitting it slihtly too late so often resets after a few minutes, probably wants even more precise timing for timers / cores / framerate / whatever?

note3, still need to tweak a few things, convert to raw video params, add 2nd buffer.
This commit is contained in:
David Haywood 2014-09-13 10:41:04 +00:00
parent 5f7dbbad6b
commit 8fd4bed29d
8 changed files with 789 additions and 1625 deletions

View File

@ -1317,13 +1317,16 @@ void tlcs90_device::take_interrupt(tlcs90_e_irq irq)
void tlcs90_device::check_interrupts()
{
tlcs90_e_irq irq;
int mask;
if (!(F & IF))
return;
for (irq = INT0; irq < INTMAX; irq++)
for (irq = INTSWI; irq < INTMAX; irq++)
{
if ( m_irq_state & m_irq_mask & (1 << irq) )
mask = (1 << irq);
if(irq >= INT0) mask &= m_irq_mask;
if ( m_irq_state & mask )
{
take_interrupt( irq );
return;
@ -2342,11 +2345,6 @@ void tlcs90_device::t90_start_timer(int i)
break;
case 1:
// 16-bit mode
if (i & 1)
{
logerror("%04X: CPU Timer %d clocked by Timer %d overflow signal\n", m_pc.w.l, i,i-1);
return;
}
break;
case 2:
logerror("%04X: CPU Timer %d, unsupported PPG mode\n", m_pc.w.l, i);
@ -2411,71 +2409,60 @@ void tlcs90_device::t90_stop_timer4()
TIMER_CALLBACK_MEMBER( tlcs90_device::t90_timer_callback )
{
int is16bit;
int mode, timer_fired;
int i = param;
if ( (m_internal_registers[ T90_TRUN - T90_IOBASE ] & (1 << i)) == 0 )
return;
// logerror("CPU Timer %d fired! value = %d\n", i,(unsigned)m_timer_value[i]);
m_timer_value[i]++;
is16bit = ((m_internal_registers[ T90_TMOD - T90_IOBASE ] >> (i/2 * 2 + 2)) & 0x03) == 1;
timer_fired = 0;
mode = (m_internal_registers[ T90_TMOD - T90_IOBASE ] >> ((i & ~1) + 2)) & 0x03;
// Match
switch (mode)
{
case 0x02: // 8bit PPG
case 0x03: // 8bit PWM
logerror("CPU Timer %d expired with unhandled mode %d\n", i, mode);
// TODO: hmm...
case 0x00: // 8bit
m_timer_value[i]++;
if ( m_timer_value[i] == m_internal_registers[ T90_TREG0+i - T90_IOBASE ] )
timer_fired = 1;
break;
if ( m_timer_value[i] == m_internal_registers[ T90_TREG0+i - T90_IOBASE ] )
{
// logerror("CPU Timer %d match\n", i);
case 0x01: // 16bit
if(i & 1)
break;
m_timer_value[i]++;
if(m_timer_value[i] == 0) m_timer_value[i+1]++;
if(m_timer_value[i+1] == m_internal_registers[ T90_TREG0+i+1 - T90_IOBASE ])
if(m_timer_value[i] == m_internal_registers[ T90_TREG0+i - T90_IOBASE ])
timer_fired = 1;
break;
}
if (is16bit)
{
if (i & 1)
{
if ( m_timer_value[i-1] == m_internal_registers[ T90_TREG0+i-1 - T90_IOBASE ] )
{
m_timer_value[i] = 0;
m_timer_value[i-1] = 0;
set_irq_line(INTT0 + i, 1);
}
}
else
set_irq_line(INTT0 + i, 1);
}
else
{
m_timer_value[i] = 0;
set_irq_line(INTT0 + i, 1);
}
switch (i)
{
case 0:
case 2:
if ( !is16bit )
if ( (m_internal_registers[ T90_TCLK - T90_IOBASE ] & (0x03 << (i * 2 + 2))) == 0 ) // T0/T1 match signal clocks T1/T3
t90_timer_callback(ptr, i+1);
break;
}
}
// Overflow
if ( m_timer_value[i] == 0 )
{
// logerror("CPU Timer %d overflow\n", i);
switch (i)
{
case 0:
case 2:
if ( is16bit ) // T0/T1 overflow signal clocks T1/T3
t90_timer_callback(ptr, i+1);
break;
}
}
if(timer_fired) {
// special stuff handling
switch(mode) {
case 0x02: // 8bit PPG
case 0x03: // 8bit PWM
// TODO: hmm...
case 0x00: // 8bit
if(i & 1)
break;
if ( (m_internal_registers[ T90_TCLK - T90_IOBASE ] & (0x0C << (i * 2))) == 0 ) // T0/T1 match signal clocks T1/T3
t90_timer_callback(ptr, i+1);
break;
case 0x01: // 16bit, only can happen for i=0,2
m_timer_value[i+1] = 0;
set_irq_line(INTT0 + i+1, 1);
break;
}
// regular handling
m_timer_value[i] = 0;
set_irq_line(INTT0 + i, 1);
}
}
TIMER_CALLBACK_MEMBER( tlcs90_device::t90_timer4_callback )
@ -2523,10 +2510,12 @@ WRITE8_MEMBER( tlcs90_device::t90_internal_registers_w )
{
if ( (old ^ data) & (0x20 | (1 << i)) ) // if timer bit or prescaler bit changed
{
if ( data == (0x20 | (1 << i)) ) t90_start_timer(i);
else t90_stop_timer(i);
if ( (data & (1 << i)) && (data & 0x20) ) t90_start_timer(i);
else t90_stop_timer(i);
}
}
// Timer 4
if ( (old ^ data) & (0x20 | 0x10) )
{

View File

@ -19,7 +19,6 @@ enum e_ir
enum tlcs90_e_irq { INTSWI = 0, INTNMI, INTWD, INT0, INTT0, INTT1, INTT2, INTT3, INTT4, INT1, INTT5, INT2, INTRX, INTTX, INTMAX };
DECLARE_ENUM_OPERATORS(tlcs90_e_irq)
class tlcs90_device : public cpu_device
{
public:

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
#include "machine/nmk112.h"
#include "sound/okim6295.h"
#include "machine/nmk004.h"
class nmk16_state : public driver_device
{
@ -24,7 +25,10 @@ public:
m_afega_scroll_0(*this, "afega_scroll_0"),
m_afega_scroll_1(*this, "afega_scroll_1"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette") {}
m_palette(*this, "palette"),
m_nmk004(*this, "nmk004"),
m_sprdma_base(0x8000)
{}
required_device<cpu_device> m_maincpu;
optional_device<cpu_device> m_audiocpu;
@ -45,6 +49,8 @@ public:
optional_shared_ptr<UINT16> m_afega_scroll_1;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
optional_device<nmk004_device> m_nmk004;
int m_sprdma_base;
int mask[4*2];
int m_simple_scroll;
int m_redraw_bitmap;
@ -113,18 +119,16 @@ public:
DECLARE_WRITE16_MEMBER(bioship_bank_w);
DECLARE_WRITE8_MEMBER(spec2k_oki1_banking_w);
DECLARE_WRITE8_MEMBER(twinactn_oki_bank_w);
DECLARE_READ16_MEMBER( atombjt_unkr_r )
{
return 0x0000;
}
DECLARE_READ16_MEMBER(atombjt_unkr_r) {return 0x0000;}
DECLARE_WRITE16_MEMBER(nmk16_x0016_w);
DECLARE_WRITE16_MEMBER(nmk16_bioship_x0016_w);
DECLARE_DRIVER_INIT(nmk);
DECLARE_DRIVER_INIT(vandykeb);
DECLARE_DRIVER_INIT(tdragonb);
DECLARE_DRIVER_INIT(ssmissin);
DECLARE_DRIVER_INIT(hachamf);
DECLARE_DRIVER_INIT(hachamf_prot);
DECLARE_DRIVER_INIT(redhawk);
DECLARE_DRIVER_INIT(tdragon);
DECLARE_DRIVER_INIT(tdragon_prot);
DECLARE_DRIVER_INIT(bubl2000);
DECLARE_DRIVER_INIT(grdnstrm);
DECLARE_DRIVER_INIT(spec2k);
@ -163,8 +167,6 @@ public:
UINT32 screen_update_redhawki(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
UINT32 screen_update_redhawkb(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
UINT32 screen_update_bubl2000(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void screen_eof_nmk(screen_device &screen, bool state);
void screen_eof_strahl(screen_device &screen, bool state);
TIMER_DEVICE_CALLBACK_MEMBER(tdragon_mcu_sim);
TIMER_DEVICE_CALLBACK_MEMBER(hachamf_mcu_sim);
TIMER_DEVICE_CALLBACK_MEMBER(nmk16_scanline);

File diff suppressed because it is too large Load Diff

View File

@ -1,115 +1,54 @@
// license:MAME
// copyright-holders:David Haywood,trap15
/***************************************************************************
NMK004 emulation
***************************************************************************/
#ifndef NMK004_H
#define NMK004_H
#include "cpu/tlcs90/tlcs90.h"
#include "sound/2203intf.h"
#include "sound/okim6295.h"
#define FM_CHANNELS 6
#define PSG_CHANNELS 3
#define EFFECTS_CHANNELS 8
#define MCFG_NMK004_ADD(_tag, _clock) \
MCFG_DEVICE_ADD(_tag, NMK004, _clock)
struct psg_control
{
/* C220 */ UINT8 flags;
/* C221-C222 */ UINT16 note_timer;
/* C223-C224 */ UINT16 note_length;
/* C225 */ UINT8 volume_timer;
/* C227-C228 */ UINT16 current; // current position in control table
/* C229-C22A */ UINT16 return_address[16]; // return address when control table calls a subtable
int return_address_depth;
/* C22B-C22C */ UINT16 loop_start; // first instruction of loop
/* C22D */ UINT8 loop_times; // number of times to loop
/* C22E */ UINT8 volume_shape;
/* C22F */ UINT8 volume_position;
/* C230 */ UINT8 octave; // base octave
/* C231 */ UINT8 note; // note to play
/* C233 */ UINT8 note_period_hi_bits;
};
struct fm_control
{
UINT8 note;
/* C020 */ UINT8 flags;
/* C021 */ UINT8 slot; // for ym2203 keyon command
/* C022-C039 */ UINT8 voice_params[0x18]; // parameters for the YM2203 to configure sound shape
/* C03A-C03B */ UINT16 f_number;
/* C03C */ UINT8 self_feedback;
/* C03D */ UINT8 note_duration_table_select;
/* C03E-C03F */ UINT16 current; // current position in control table
/* C040-C041 */ UINT16 loop_start; // first instruction of loop
/* C042 */ UINT8 loop_times; // number of times to loop
/* C043-C044 */ UINT16 return_address[16]; // return address when control table calls a subtable
int return_address_depth;
/* C045 */ UINT8 octave;
/* C046-C047 */ UINT16 timer1;
/* C048-C049 */ UINT16 timer2;
/* C04A-C04B */ UINT16 timer1_duration;
/* C04C-C04D */ UINT16 timer2_duration;
/* C04E */ UINT8 modulation_table_number;
/* C04F-C050 */ UINT16 modulation_timer;
/* C051-C052 */ UINT16 modulation_table;
/* C053-C054 */ UINT16 modulation_table_position;
/* C055-C056 */ UINT16 note_period;
/* C057-C05A */ UINT8 voice_volume[4]; // parameters for the YM2203 to configure sound shape
/* C05C */ UINT8 must_update_voice_params;
};
struct effects_control
{
/* C1A0 */ UINT8 flags;
/* C1BE-C1BF */ UINT16 current; // current position in control table
/* C1C0-C1C1 */ UINT16 loop_start; // first instruction of loop
/* C1C2 */ UINT8 loop_times; // number of times to loop
/* C1C3-C1C4 */ UINT16 return_address[16]; // return address when control table calls a subtable
int return_address_depth;
/* C1C6-C1C7 */ UINT16 timer;
/* C1CA-C1CB */ UINT16 timer_duration;
};
/* device get info callback */
class nmk004_device : public device_t
{
public:
nmk004_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
~nmk004_device() {}
WRITE8_MEMBER( write );
READ8_MEMBER( read );
DECLARE_WRITE8_MEMBER(nmk004_port4_w);
DECLARE_WRITE8_MEMBER(nmk004_oki0_bankswitch_w);
DECLARE_WRITE8_MEMBER(nmk004_oki1_bankswitch_w);
DECLARE_READ8_MEMBER(nmk004_tonmk004_r);
DECLARE_WRITE8_MEMBER(nmk004_tomain_w);
void ym2203_irq_handler(int irq);
DECLARE_READ16_MEMBER( read );
DECLARE_WRITE16_MEMBER( write );
required_device<tlcs90_device> m_cpu;
protected:
// device-level overrides
virtual void device_config_complete();
virtual void device_start();
virtual void device_reset();
virtual const rom_entry *device_rom_region() const;
virtual machine_config_constructor device_mconfig_additions() const;
private:
// internal state
const UINT8 *m_rom; // NMK004 data ROM
UINT8 m_from_main; // command from main CPU
UINT8 m_to_main; // answer to main CPU
int m_protection_check;
required_device<cpu_device> m_systemcpu;
UINT8 to_nmk004;
UINT8 to_main;
ym2203_device *m_ymdevice;
okim6295_device *m_oki1device;
okim6295_device *m_oki2device;
/* C001 */ UINT8 m_last_command; // last command received
/* C016 */ UINT8 m_oki_playing; // bitmap of active Oki channels
/* C020-C19F */ struct fm_control m_fm_control[FM_CHANNELS];
/* C220-C2DF */ struct psg_control m_psg_control[PSG_CHANNELS];
/* C1A0-C21F */ struct effects_control m_effects_control[EFFECTS_CHANNELS];
TIMER_CALLBACK_MEMBER( real_init );
UINT8 read8(int address);
UINT16 read16(int address);
void oki_play_sample(int sample_no);
void oki_update_state(void);
void effects_update(int channel);
void fm_update(int channel);
void fm_voices_update(void);
void psg_update(int channel);
void get_command(void);
void update_music(void);
};
extern const device_type NMK004;
#define MCFG_NMK004_ADD(_tag) \
MCFG_DEVICE_ADD(_tag, NMK004, 0)
#endif /* NMK004_H */

View File

@ -7909,6 +7909,7 @@ bigbang // UPL-93091 (c) 1993 NMK
tdragon // (c) 1991 NMK / Tecmo
tdragon1 // (c) 1991 NMK / Tecmo
hachamf // (c) 1991 NMK
hachamfb // bootleg
macross // (c) 1992 Banpresto
riot // (c) 1992 NMK
gunnail // (c) 1993 NMK / Tecmo

View File

@ -139,6 +139,8 @@ VIDEO_START_MEMBER(nmk16_state,strahl)
m_fg_tilemap->set_transparent_pen(15);
m_tx_tilemap->set_transparent_pen(15);
m_sprdma_base = 0xf000;
nmk16_video_init();
}
@ -780,40 +782,6 @@ UINT32 nmk16_state::screen_update_bjtwin(screen_device &screen, bitmap_ind16 &bi
return nmk16_bg_spr_update(screen, bitmap, cliprect);
}
void nmk16_state::screen_eof_nmk(screen_device &screen, bool state)
{
// rising edge
if (state)
{
/* sprites are DMA'd from Main RAM to a private buffer automatically
(or at least this is how I interpret the datasheet) */
/* -- I actually see little evidence to support this, sprite lag
in some games should be checked on real boards */
// memcpy(m_spriteram_old2,m_spriteram_old,0x1000);
memcpy(m_spriteram_old2,m_mainram+0x8000/2,0x1000);
}
}
void nmk16_state::screen_eof_strahl(screen_device &screen, bool state)
{
// rising edge
if (state)
{
/* sprites are DMA'd from Main RAM to a private buffer automatically
(or at least this is how I interpret the datasheet) */
/* -- I actually see little evidence to support this, sprite lag
in some games should be checked on real boards */
/* strahl sprites are allocated in memory range FF000-FFFFF */
memcpy(m_spriteram_old2,m_mainram+0xF000/2,0x1000);
}
}
/***************************************************************************