mirror of
https://github.com/holub/mame
synced 2025-07-05 18:08:04 +03:00
taito_zm: DSP emulation (work in progress!) (#3854)
* taito_zm.cpp : Updates Add DSP, Reduce MCFGs, Add device_mixer_interface for sound gain, Add imperfect_features related to DSP, Add notes * taito_zm.cpp : Fix TMS57002 clock * Improve Taito Zoom ZSG-2 sound emulation zsg2.cpp: implement emphasis filter, this is a noise reduction scheme that amplifies higher frequncies to reduce quantization noise. zsg2.cpp: Add sample interpolation and another adjustable lowpass filter. This seems to be roughly what real hardware does... zsg2.cpp: Improve panning registers and identify DSP output gain registers. * zsg2: minor changes [nw] zsg2: Register 0b appears to be status flags [nw] zsg2: Linear ramping probably makes more sense [nw] * zsg2: slight adjustment of emphasis filter [nw] * zsg2: slight adjustment of emphasis filter #2 [nw] * zsg2: more sober ramping algorithm [nw] * tms57002: add instructions 3c/3d, make them behave as NOP as they're undocumented and not understood * tms57002: Add dready callback for superctr (nw) * tms57002: Fixes to make Taito Zoom DSP working tms57002: Add undocumented instruction saom / raom, they set saturation mode for the ALU. tms57002: Implement MACC pipeline. tms57002: Add callbacks for EMPTY and PC0 pins. tms57002: Add a few unimplemented instructions. tms57002: Proper behavior of CMEM UPLOAD mode. tms57002: Fix an issue where program is not properly loaded if PLOAD is set after a program has already been written. * Documentation fix, properly identified registers as ramping control, will implement that soon [nw] * taito_zm: Working DSP emulation Pretty much OST quality now. A pretty decent upgrade from how it was previously, I'd say. * typo [nw] * just adding some quick notes about the WIP [nw] * Fix build [nw] * zsg2: Proper ramping implemenation, add register map, minor cleanups * oops [nw]
This commit is contained in:
parent
59c2a0536c
commit
3b57b7e90c
@ -25,8 +25,10 @@ void tms57002_device::internal_pgm(address_map &map)
|
|||||||
tms57002_device::tms57002_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
tms57002_device::tms57002_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||||
: cpu_device(mconfig, TMS57002, tag, owner, clock)
|
: cpu_device(mconfig, TMS57002, tag, owner, clock)
|
||||||
, device_sound_interface(mconfig, *this)
|
, device_sound_interface(mconfig, *this)
|
||||||
, macc(0), st0(0), st1(0), sti(0), txrd(0)
|
, macc(0), macc_read(0), macc_write(0), st0(0), st1(0), sti(0), txrd(0)
|
||||||
, m_dready_callback(*this)
|
, m_dready_callback(*this)
|
||||||
|
, m_pc0_callback(*this)
|
||||||
|
, m_empty_callback(*this)
|
||||||
, program_config("program", ENDIANNESS_LITTLE, 32, 8, -2, address_map_constructor(FUNC(tms57002_device::internal_pgm), this))
|
, program_config("program", ENDIANNESS_LITTLE, 32, 8, -2, address_map_constructor(FUNC(tms57002_device::internal_pgm), this))
|
||||||
, data_config("data", ENDIANNESS_LITTLE, 8, 20)
|
, data_config("data", ENDIANNESS_LITTLE, 8, 20)
|
||||||
{
|
{
|
||||||
@ -47,7 +49,9 @@ WRITE_LINE_MEMBER(tms57002_device::pload_w)
|
|||||||
if(olds ^ sti) {
|
if(olds ^ sti) {
|
||||||
if (sti & IN_PLOAD) {
|
if (sti & IN_PLOAD) {
|
||||||
hidx = 0;
|
hidx = 0;
|
||||||
hpc = 0;
|
pc = 0;
|
||||||
|
ca = 0;
|
||||||
|
sti &= ~(SU_MASK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,26 +66,30 @@ WRITE_LINE_MEMBER(tms57002_device::cload_w)
|
|||||||
if(olds ^ sti) {
|
if(olds ^ sti) {
|
||||||
if (sti & IN_CLOAD) {
|
if (sti & IN_CLOAD) {
|
||||||
hidx = 0;
|
hidx = 0;
|
||||||
ca = 0;
|
//ca = 0; // Seems extremely dubious
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tms57002_device::device_reset()
|
void tms57002_device::device_reset()
|
||||||
{
|
{
|
||||||
sti = (sti & ~(SU_MASK|S_READ|S_WRITE|S_BRANCH|S_HOST)) | (SU_ST0|S_IDLE);
|
sti = (sti & ~(SU_MASK|S_READ|S_WRITE|S_BRANCH|S_HOST|S_UPDATE)) | (SU_ST0|S_IDLE);
|
||||||
pc = 0;
|
pc = 0;
|
||||||
ca = 0;
|
ca = 0;
|
||||||
hidx = 0;
|
hidx = 0;
|
||||||
id = 0;
|
id = 0;
|
||||||
ba0 = 0;
|
ba0 = 0;
|
||||||
ba1 = 0;
|
ba1 = 0;
|
||||||
|
update_counter_tail = 0;
|
||||||
|
update_counter_head = 0;
|
||||||
st0 &= ~(ST0_INCS | ST0_DIRI | ST0_FI | ST0_SIM | ST0_PLRI |
|
st0 &= ~(ST0_INCS | ST0_DIRI | ST0_FI | ST0_SIM | ST0_PLRI |
|
||||||
ST0_PBCI | ST0_DIRO | ST0_FO | ST0_SOM | ST0_PLRO |
|
ST0_PBCI | ST0_DIRO | ST0_FO | ST0_SOM | ST0_PLRO |
|
||||||
ST0_PBCO | ST0_CNS);
|
ST0_PBCO | ST0_CNS);
|
||||||
st1 &= ~(ST1_AOV | ST1_SFAI | ST1_SFAO | ST1_MOVM | ST1_MOV |
|
st1 &= ~(ST1_AOV | ST1_SFAI | ST1_SFAO | ST1_AOVM | ST1_MOVM | ST1_MOV |
|
||||||
ST1_SFMA | ST1_SFMO | ST1_RND | ST1_CRM | ST1_DBP);
|
ST1_SFMA | ST1_SFMO | ST1_RND | ST1_CRM | ST1_DBP);
|
||||||
update_dready();
|
update_dready();
|
||||||
|
update_pc0();
|
||||||
|
update_empty();
|
||||||
|
|
||||||
xba = 0;
|
xba = 0;
|
||||||
xoa = 0;
|
xoa = 0;
|
||||||
@ -112,6 +120,7 @@ WRITE8_MEMBER(tms57002_device::data_w)
|
|||||||
break;
|
break;
|
||||||
case SU_PRG:
|
case SU_PRG:
|
||||||
program->write_dword(pc++, val);
|
program->write_dword(pc++, val);
|
||||||
|
update_pc0();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,9 +130,11 @@ WRITE8_MEMBER(tms57002_device::data_w)
|
|||||||
host[hidx++] = data;
|
host[hidx++] = data;
|
||||||
if(hidx >= 4) {
|
if(hidx >= 4) {
|
||||||
uint32_t val = (host[0]<<24) | (host[1]<<16) | (host[2]<<8) | host[3];
|
uint32_t val = (host[0]<<24) | (host[1]<<16) | (host[2]<<8) | host[3];
|
||||||
cmem[sa] = val;
|
|
||||||
sti &= ~SU_CVAL;
|
sti &= ~SU_CVAL;
|
||||||
allow_update = 0;
|
update[update_counter_head] = val;
|
||||||
|
update_counter_head = (update_counter_head + 1) & 0x0f;
|
||||||
|
hidx = 1; // the write shouldn't really happen until CLOAD is high though
|
||||||
|
update_empty();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sa = data;
|
sa = data;
|
||||||
@ -160,11 +171,6 @@ READ8_MEMBER(tms57002_device::data_r)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
READ_LINE_MEMBER(tms57002_device::empty_r)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
READ_LINE_MEMBER(tms57002_device::dready_r)
|
READ_LINE_MEMBER(tms57002_device::dready_r)
|
||||||
{
|
{
|
||||||
return sti & S_HOST ? 0 : 1;
|
return sti & S_HOST ? 0 : 1;
|
||||||
@ -180,9 +186,24 @@ READ_LINE_MEMBER(tms57002_device::pc0_r)
|
|||||||
return pc == 0 ? 0 : 1;
|
return pc == 0 ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tms57002_device::update_pc0()
|
||||||
|
{
|
||||||
|
m_pc0_callback(pc == 0 ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
READ_LINE_MEMBER(tms57002_device::empty_r)
|
||||||
|
{
|
||||||
|
return (update_counter_head == update_counter_tail);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tms57002_device::update_empty()
|
||||||
|
{
|
||||||
|
m_empty_callback(update_counter_head == update_counter_tail);
|
||||||
|
}
|
||||||
|
|
||||||
WRITE_LINE_MEMBER(tms57002_device::sync_w)
|
WRITE_LINE_MEMBER(tms57002_device::sync_w)
|
||||||
{
|
{
|
||||||
if(sti & (IN_PLOAD | IN_CLOAD))
|
if(sti & (IN_PLOAD /*| IN_CLOAD*/))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
allow_update = 1;
|
allow_update = 1;
|
||||||
@ -293,7 +314,7 @@ inline void tms57002_device::xm_step_write()
|
|||||||
|
|
||||||
int64_t tms57002_device::macc_to_output_0(int64_t rounding, uint64_t rmask)
|
int64_t tms57002_device::macc_to_output_0(int64_t rounding, uint64_t rmask)
|
||||||
{
|
{
|
||||||
int64_t m = macc;
|
int64_t m = macc_read;
|
||||||
uint64_t m1;
|
uint64_t m1;
|
||||||
int over = 0;
|
int over = 0;
|
||||||
|
|
||||||
@ -318,7 +339,7 @@ int64_t tms57002_device::macc_to_output_0(int64_t rounding, uint64_t rmask)
|
|||||||
|
|
||||||
int64_t tms57002_device::macc_to_output_1(int64_t rounding, uint64_t rmask)
|
int64_t tms57002_device::macc_to_output_1(int64_t rounding, uint64_t rmask)
|
||||||
{
|
{
|
||||||
int64_t m = macc;
|
int64_t m = macc_read;
|
||||||
uint64_t m1;
|
uint64_t m1;
|
||||||
int over = 0;
|
int over = 0;
|
||||||
|
|
||||||
@ -344,7 +365,7 @@ int64_t tms57002_device::macc_to_output_1(int64_t rounding, uint64_t rmask)
|
|||||||
|
|
||||||
int64_t tms57002_device::macc_to_output_2(int64_t rounding, uint64_t rmask)
|
int64_t tms57002_device::macc_to_output_2(int64_t rounding, uint64_t rmask)
|
||||||
{
|
{
|
||||||
int64_t m = macc;
|
int64_t m = macc_read;
|
||||||
uint64_t m1;
|
uint64_t m1;
|
||||||
int over = 0;
|
int over = 0;
|
||||||
|
|
||||||
@ -370,7 +391,7 @@ int64_t tms57002_device::macc_to_output_2(int64_t rounding, uint64_t rmask)
|
|||||||
|
|
||||||
int64_t tms57002_device::macc_to_output_3(int64_t rounding, uint64_t rmask)
|
int64_t tms57002_device::macc_to_output_3(int64_t rounding, uint64_t rmask)
|
||||||
{
|
{
|
||||||
int64_t m = macc;
|
int64_t m = macc_read;
|
||||||
uint64_t m1;
|
uint64_t m1;
|
||||||
int over = 0;
|
int over = 0;
|
||||||
|
|
||||||
@ -393,7 +414,7 @@ int64_t tms57002_device::macc_to_output_3(int64_t rounding, uint64_t rmask)
|
|||||||
|
|
||||||
int64_t tms57002_device::macc_to_output_0s(int64_t rounding, uint64_t rmask)
|
int64_t tms57002_device::macc_to_output_0s(int64_t rounding, uint64_t rmask)
|
||||||
{
|
{
|
||||||
int64_t m = macc;
|
int64_t m = macc_read;
|
||||||
uint64_t m1;
|
uint64_t m1;
|
||||||
int over = 0;
|
int over = 0;
|
||||||
|
|
||||||
@ -422,7 +443,7 @@ int64_t tms57002_device::macc_to_output_0s(int64_t rounding, uint64_t rmask)
|
|||||||
|
|
||||||
int64_t tms57002_device::macc_to_output_1s(int64_t rounding, uint64_t rmask)
|
int64_t tms57002_device::macc_to_output_1s(int64_t rounding, uint64_t rmask)
|
||||||
{
|
{
|
||||||
int64_t m = macc;
|
int64_t m = macc_read;
|
||||||
uint64_t m1;
|
uint64_t m1;
|
||||||
int over = 0;
|
int over = 0;
|
||||||
|
|
||||||
@ -452,7 +473,7 @@ int64_t tms57002_device::macc_to_output_1s(int64_t rounding, uint64_t rmask)
|
|||||||
|
|
||||||
int64_t tms57002_device::macc_to_output_2s(int64_t rounding, uint64_t rmask)
|
int64_t tms57002_device::macc_to_output_2s(int64_t rounding, uint64_t rmask)
|
||||||
{
|
{
|
||||||
int64_t m = macc;
|
int64_t m = macc_read;
|
||||||
uint64_t m1;
|
uint64_t m1;
|
||||||
int over = 0;
|
int over = 0;
|
||||||
|
|
||||||
@ -482,7 +503,7 @@ int64_t tms57002_device::macc_to_output_2s(int64_t rounding, uint64_t rmask)
|
|||||||
|
|
||||||
int64_t tms57002_device::macc_to_output_3s(int64_t rounding, uint64_t rmask)
|
int64_t tms57002_device::macc_to_output_3s(int64_t rounding, uint64_t rmask)
|
||||||
{
|
{
|
||||||
int64_t m = macc;
|
int64_t m = macc_read;
|
||||||
uint64_t m1;
|
uint64_t m1;
|
||||||
int over = 0;
|
int over = 0;
|
||||||
|
|
||||||
@ -607,6 +628,34 @@ int64_t tms57002_device::check_macc_overflow_3s()
|
|||||||
return macc;
|
return macc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t tms57002_device::get_cmem(uint8_t addr)
|
||||||
|
{
|
||||||
|
if(sa == addr && update_counter_head != update_counter_tail)
|
||||||
|
sti |= S_UPDATE;
|
||||||
|
|
||||||
|
if(sti & S_UPDATE)
|
||||||
|
{
|
||||||
|
cmem[addr] = update[update_counter_tail];
|
||||||
|
update_counter_tail = (update_counter_tail + 1) & 0x0f;
|
||||||
|
update_empty();
|
||||||
|
|
||||||
|
if(update_counter_head == update_counter_tail)
|
||||||
|
sti &= ~S_UPDATE;
|
||||||
|
|
||||||
|
return cmem[addr]; // The value of crm is ignored during an update.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int crm = (st1 & ST1_CRM) >> ST1_CRM_SHIFT;
|
||||||
|
uint32_t cvar = cmem[addr];
|
||||||
|
if(crm == 1)
|
||||||
|
return (cvar & 0xffff0000);
|
||||||
|
else if(crm == 2)
|
||||||
|
return (cvar << 16);
|
||||||
|
return cvar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void tms57002_device::cache_flush()
|
void tms57002_device::cache_flush()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -730,7 +779,7 @@ void tms57002_device::execute_run()
|
|||||||
{
|
{
|
||||||
int ipc = -1;
|
int ipc = -1;
|
||||||
|
|
||||||
while(icount > 0 && !(sti & (S_IDLE | IN_PLOAD | IN_CLOAD))) {
|
while(icount > 0 && !(sti & (S_IDLE | IN_PLOAD /*| IN_CLOAD*/))) {
|
||||||
int iipc;
|
int iipc;
|
||||||
|
|
||||||
debugger_instruction_hook(pc);
|
debugger_instruction_hook(pc);
|
||||||
@ -746,6 +795,9 @@ void tms57002_device::execute_run()
|
|||||||
else
|
else
|
||||||
xm_step_write();
|
xm_step_write();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macc_read = macc_write;
|
||||||
|
macc_write = macc;
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
uint32_t c, d;
|
uint32_t c, d;
|
||||||
@ -786,8 +838,10 @@ void tms57002_device::execute_run()
|
|||||||
} else if(sti & S_BRANCH) {
|
} else if(sti & S_BRANCH) {
|
||||||
sti &= ~S_BRANCH;
|
sti &= ~S_BRANCH;
|
||||||
ipc = -1;
|
ipc = -1;
|
||||||
} else
|
} else {
|
||||||
pc++; // Wraps if it reaches 256, next wraps too
|
pc++; // Wraps if it reaches 256, next wraps too
|
||||||
|
update_pc0();
|
||||||
|
}
|
||||||
|
|
||||||
if(rptc_next) {
|
if(rptc_next) {
|
||||||
rptc = rptc_next;
|
rptc = rptc_next;
|
||||||
@ -825,6 +879,8 @@ void tms57002_device::sound_stream_update(sound_stream &stream, stream_sample_t
|
|||||||
void tms57002_device::device_resolve_objects()
|
void tms57002_device::device_resolve_objects()
|
||||||
{
|
{
|
||||||
m_dready_callback.resolve_safe();
|
m_dready_callback.resolve_safe();
|
||||||
|
m_pc0_callback.resolve_safe();
|
||||||
|
m_empty_callback.resolve_safe();
|
||||||
}
|
}
|
||||||
|
|
||||||
void tms57002_device::device_start()
|
void tms57002_device::device_start()
|
||||||
@ -861,10 +917,13 @@ void tms57002_device::device_start()
|
|||||||
stream_alloc(4, 4, STREAM_SYNC);
|
stream_alloc(4, 4, STREAM_SYNC);
|
||||||
|
|
||||||
save_item(NAME(macc));
|
save_item(NAME(macc));
|
||||||
|
save_item(NAME(macc_read));
|
||||||
|
save_item(NAME(macc_write));
|
||||||
|
|
||||||
save_item(NAME(cmem));
|
save_item(NAME(cmem));
|
||||||
save_item(NAME(dmem0));
|
save_item(NAME(dmem0));
|
||||||
save_item(NAME(dmem1));
|
save_item(NAME(dmem1));
|
||||||
|
save_item(NAME(update));
|
||||||
|
|
||||||
save_item(NAME(si));
|
save_item(NAME(si));
|
||||||
save_item(NAME(so));
|
save_item(NAME(so));
|
||||||
@ -893,6 +952,9 @@ void tms57002_device::device_start()
|
|||||||
|
|
||||||
save_item(NAME(host));
|
save_item(NAME(host));
|
||||||
save_item(NAME(hidx));
|
save_item(NAME(hidx));
|
||||||
|
|
||||||
|
save_item(NAME(update_counter_head));
|
||||||
|
save_item(NAME(update_counter_tail));
|
||||||
save_item(NAME(allow_update));
|
save_item(NAME(allow_update));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@ public:
|
|||||||
tms57002_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
tms57002_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||||
|
|
||||||
auto dready_callback() { return m_dready_callback.bind(); }
|
auto dready_callback() { return m_dready_callback.bind(); }
|
||||||
|
auto pc0_callback() { return m_pc0_callback.bind(); }
|
||||||
|
auto empty_callback() { return m_empty_callback.bind(); }
|
||||||
|
|
||||||
DECLARE_READ8_MEMBER(data_r);
|
DECLARE_READ8_MEMBER(data_r);
|
||||||
DECLARE_WRITE8_MEMBER(data_w);
|
DECLARE_WRITE8_MEMBER(data_w);
|
||||||
@ -51,7 +53,8 @@ private:
|
|||||||
S_READ = 0x00000040,
|
S_READ = 0x00000040,
|
||||||
S_WRITE = 0x00000080,
|
S_WRITE = 0x00000080,
|
||||||
S_BRANCH = 0x00000100,
|
S_BRANCH = 0x00000100,
|
||||||
S_HOST = 0x00000200
|
S_HOST = 0x00000200,
|
||||||
|
S_UPDATE = 0x00000400,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -75,6 +78,7 @@ private:
|
|||||||
ST1_AOV = 0x000001,
|
ST1_AOV = 0x000001,
|
||||||
ST1_SFAI = 0x000002,
|
ST1_SFAI = 0x000002,
|
||||||
ST1_SFAO = 0x000004,
|
ST1_SFAO = 0x000004,
|
||||||
|
ST1_AOVM = 0x000008, // undocumented!
|
||||||
ST1_MOVM = 0x000020,
|
ST1_MOVM = 0x000020,
|
||||||
ST1_MOV = 0x000040,
|
ST1_MOV = 0x000040,
|
||||||
ST1_SFMA = 0x000180, ST1_SFMA_SHIFT = 7,
|
ST1_SFMA = 0x000180, ST1_SFMA_SHIFT = 7,
|
||||||
@ -120,7 +124,8 @@ private:
|
|||||||
short ipc;
|
short ipc;
|
||||||
};
|
};
|
||||||
|
|
||||||
int64_t macc;
|
// macc_read and macc_write are used by non-pipelined instructions
|
||||||
|
int64_t macc, macc_read, macc_write;
|
||||||
|
|
||||||
uint32_t cmem[256];
|
uint32_t cmem[256];
|
||||||
uint32_t dmem0[256];
|
uint32_t dmem0[256];
|
||||||
@ -136,10 +141,15 @@ private:
|
|||||||
uint32_t xm_adr;
|
uint32_t xm_adr;
|
||||||
|
|
||||||
uint8_t host[4], hidx, allow_update;
|
uint8_t host[4], hidx, allow_update;
|
||||||
|
|
||||||
|
uint32_t update[16];
|
||||||
|
uint8_t update_counter_head, update_counter_tail;
|
||||||
|
|
||||||
cd cache;
|
cd cache;
|
||||||
|
|
||||||
devcb_write_line m_dready_callback;
|
devcb_write_line m_dready_callback;
|
||||||
|
devcb_write_line m_pc0_callback;
|
||||||
|
devcb_write_line m_empty_callback;
|
||||||
|
|
||||||
const address_space_config program_config, data_config;
|
const address_space_config program_config, data_config;
|
||||||
|
|
||||||
@ -164,6 +174,8 @@ private:
|
|||||||
inline int sfma(uint32_t st1);
|
inline int sfma(uint32_t st1);
|
||||||
|
|
||||||
void update_dready();
|
void update_dready();
|
||||||
|
void update_pc0();
|
||||||
|
void update_empty();
|
||||||
|
|
||||||
void xm_init();
|
void xm_init();
|
||||||
void xm_step_read();
|
void xm_step_read();
|
||||||
@ -190,6 +202,7 @@ private:
|
|||||||
short get_hash(unsigned char adr, uint32_t st1, short *pnode);
|
short get_hash(unsigned char adr, uint32_t st1, short *pnode);
|
||||||
short get_hashnode(unsigned char adr, uint32_t st1, short pnode);
|
short get_hashnode(unsigned char adr, uint32_t st1, short pnode);
|
||||||
int decode_get_pc();
|
int decode_get_pc();
|
||||||
|
uint32_t get_cmem(uint8_t addr);
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "emu.h"
|
#include "emu.h"
|
||||||
#include "debugger.h"
|
#include "debugger.h"
|
||||||
#include "tms57002.h"
|
#include "tms57002.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
inline int tms57002_device::xmode(uint32_t opcode, char type, cstate *cs)
|
inline int tms57002_device::xmode(uint32_t opcode, char type, cstate *cs)
|
||||||
{
|
{
|
||||||
@ -40,6 +41,10 @@ inline int tms57002_device::dbp(uint32_t st1)
|
|||||||
|
|
||||||
inline int tms57002_device::crm(uint32_t st1)
|
inline int tms57002_device::crm(uint32_t st1)
|
||||||
{
|
{
|
||||||
|
// value overridden during cvar update
|
||||||
|
if(update_counter_head != update_counter_tail)
|
||||||
|
return 0;
|
||||||
|
|
||||||
int crm = (st1 & ST1_CRM) >> ST1_CRM_SHIFT;
|
int crm = (st1 & ST1_CRM) >> ST1_CRM_SHIFT;
|
||||||
return crm <= 2 ? crm : 0;
|
return crm <= 2 ? crm : 0;
|
||||||
}
|
}
|
||||||
@ -90,6 +95,7 @@ void tms57002_device::decode_cat1(uint32_t opcode, unsigned short *op, cstate *c
|
|||||||
#undef CDEC1
|
#undef CDEC1
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
logerror("Unhandled cat1 opcode %02x\n",opcode >> 18);
|
||||||
decode_error(opcode);
|
decode_error(opcode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -106,6 +112,7 @@ void tms57002_device::decode_cat2_pre(uint32_t opcode, unsigned short *op, cstat
|
|||||||
#undef CDEC2A
|
#undef CDEC2A
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
logerror("Unhandled cat2_pre opcode %02x \n",(opcode >> 11) & 0x7f);
|
||||||
decode_error(opcode);
|
decode_error(opcode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -122,6 +129,7 @@ void tms57002_device::decode_cat2_post(uint32_t opcode, unsigned short *op, csta
|
|||||||
#undef CDEC2B
|
#undef CDEC2B
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
logerror("Unhandled cat2_post opcode %02x\n",(opcode >> 11) & 0x7f);
|
||||||
decode_error(opcode);
|
decode_error(opcode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -138,6 +146,7 @@ void tms57002_device::decode_cat3(uint32_t opcode, unsigned short *op, cstate *c
|
|||||||
#undef CDEC3
|
#undef CDEC3
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
logerror("Unhandled cat3 opcode %02x\n",(opcode >> 11) & 0x7f);
|
||||||
decode_error(opcode);
|
decode_error(opcode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -219,17 +219,17 @@ lirk 3 20 1 n
|
|||||||
|
|
||||||
lmhc 1 33 1 n
|
lmhc 1 33 1 n
|
||||||
lmhc %c
|
lmhc %c
|
||||||
macc = ((int64_t)(int32_t)%c) << 16;
|
macc_write = macc = ((int64_t)(int32_t)%c) << 16;
|
||||||
|
|
||||||
lmhd 1 31 1 n
|
lmhd 1 31 1 n
|
||||||
lmhd %d
|
lmhd %d
|
||||||
macc = ((int64_t)(int32_t)%d) << 16;
|
macc_write = macc = ((int64_t)(int32_t)%d) << 16;
|
||||||
|
|
||||||
lmld 1 32 1 n
|
lmld 1 32 1 n
|
||||||
lmld %d
|
lmld %d
|
||||||
macc = (macc & ~0xffffffULL) | %d24;
|
macc_write = macc = (macc & ~0xffffffULL) | %d24;
|
||||||
|
|
||||||
lpc 2b 31 1 n
|
lpc 2a 31 1 n
|
||||||
lpc %c
|
lpc %c
|
||||||
if(sti & S_HOST)
|
if(sti & S_HOST)
|
||||||
break;
|
break;
|
||||||
@ -242,7 +242,7 @@ lpc 2b 31 1 n
|
|||||||
sti |= S_HOST;
|
sti |= S_HOST;
|
||||||
update_dready();
|
update_dready();
|
||||||
|
|
||||||
lpd 2b 30 1 n
|
lpd 2a 30 1 n
|
||||||
lpd %d
|
lpd %d
|
||||||
|
|
||||||
mac 1 24 1 y
|
mac 1 24 1 y
|
||||||
@ -256,6 +256,12 @@ mac 1 24 1 y
|
|||||||
|
|
||||||
mac 1 25 1 y
|
mac 1 25 1 y
|
||||||
mac a,%d
|
mac a,%d
|
||||||
|
d = %d24;
|
||||||
|
if(d & 0x00800000)
|
||||||
|
d |= 0xff000000;
|
||||||
|
creg = c = %a;
|
||||||
|
r = (int64_t)(int32_t)c * (int64_t)(int32_t)d;
|
||||||
|
macc = %ml + (r >> 7);
|
||||||
|
|
||||||
mac 1 26 1 y
|
mac 1 26 1 y
|
||||||
mac %c,a
|
mac %c,a
|
||||||
@ -310,6 +316,7 @@ mpyu 1 28 1 y
|
|||||||
|
|
||||||
neg 1 02 1 n
|
neg 1 02 1 n
|
||||||
neg
|
neg
|
||||||
|
%wa(-(int64_t)%a);
|
||||||
|
|
||||||
or 1 17 1 n
|
or 1 17 1 n
|
||||||
or %d,a
|
or %d,a
|
||||||
@ -408,11 +415,11 @@ scrm 2a 4b 1 n f
|
|||||||
scrm <3>
|
scrm <3>
|
||||||
st1 = (st1 & ~ST1_CRM) | (3 << ST1_CRM_SHIFT);
|
st1 = (st1 & ~ST1_CRM) | (3 << ST1_CRM_SHIFT);
|
||||||
|
|
||||||
sfai 2b 54 1 n f
|
sfai 2a 54 1 n f
|
||||||
sfai 0
|
sfai 0
|
||||||
st1 &= ~ST1_SFAI;
|
st1 &= ~ST1_SFAI;
|
||||||
|
|
||||||
sfai 2b 55 1 n f
|
sfai 2a 55 1 n f
|
||||||
sfai -1
|
sfai -1
|
||||||
st1 |= ST1_SFAI;
|
st1 |= ST1_SFAI;
|
||||||
|
|
||||||
@ -422,21 +429,21 @@ sfao 2a 50 1 n f
|
|||||||
|
|
||||||
sfao 2a 51 1 n f
|
sfao 2a 51 1 n f
|
||||||
sfao 7
|
sfao 7
|
||||||
st1 |= ST1_SFAI;
|
st1 |= ST1_SFAO;
|
||||||
|
|
||||||
sfma 2b 58 1 n f
|
sfma 2a 58 1 n f
|
||||||
sfma 0
|
sfma 0
|
||||||
st1 = (st1 & ~ST1_SFMA) | (0 << ST1_SFMA_SHIFT);
|
st1 = (st1 & ~ST1_SFMA) | (0 << ST1_SFMA_SHIFT);
|
||||||
|
|
||||||
sfma 2b 59 1 n f
|
sfma 2a 59 1 n f
|
||||||
sfma 2
|
sfma 2
|
||||||
st1 = (st1 & ~ST1_SFMA) | (1 << ST1_SFMA_SHIFT);
|
st1 = (st1 & ~ST1_SFMA) | (1 << ST1_SFMA_SHIFT);
|
||||||
|
|
||||||
sfma 2b 5a 1 n f
|
sfma 2a 5a 1 n f
|
||||||
sfma 4
|
sfma 4
|
||||||
st1 = (st1 & ~ST1_SFMA) | (2 << ST1_SFMA_SHIFT);
|
st1 = (st1 & ~ST1_SFMA) | (2 << ST1_SFMA_SHIFT);
|
||||||
|
|
||||||
sfma 2b 5b 1 n f
|
sfma 2a 5b 1 n f
|
||||||
sfma -16
|
sfma -16
|
||||||
st1 = (st1 & ~ST1_SFMA) | (3 << ST1_SFMA_SHIFT);
|
st1 = (st1 & ~ST1_SFMA) | (3 << ST1_SFMA_SHIFT);
|
||||||
|
|
||||||
@ -504,9 +511,12 @@ sub 1 0a 1 y
|
|||||||
|
|
||||||
sub 1 0b 1 y
|
sub 1 0b 1 y
|
||||||
sub %d,m
|
sub %d,m
|
||||||
|
%sfai(d, %d);
|
||||||
|
%wa((int64_t)(int32_t)d - (%mo >> 16));
|
||||||
|
|
||||||
sub 1 0c 1 y
|
sub 1 0c 1 y
|
||||||
sub %c,m
|
sub %c,m
|
||||||
|
%wa((int64_t)(int32_t)%c - (%mo >> 16));
|
||||||
|
|
||||||
sub 1 0d 1 y
|
sub 1 0d 1 y
|
||||||
sub %d,%c
|
sub %d,%c
|
||||||
@ -535,3 +545,13 @@ zacc 1 10 1 n
|
|||||||
|
|
||||||
zmac 1 30 1 n
|
zmac 1 30 1 n
|
||||||
zmac
|
zmac
|
||||||
|
|
||||||
|
raom 2a 3c 1 n
|
||||||
|
raom
|
||||||
|
/* Undocumented instruction, reset ALU saturation flag */
|
||||||
|
st1 &= ~ST1_AOVM;
|
||||||
|
|
||||||
|
saom 2a 3d 1 n
|
||||||
|
saom
|
||||||
|
/* Undocumented instruction, sets ALU saturation flag */
|
||||||
|
st1 |= ST1_AOVM;
|
||||||
|
@ -23,11 +23,6 @@ TYPES = {
|
|||||||
"f": None,
|
"f": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
def expand_c(v):
|
|
||||||
fmt = ["%s", "(%s & 0xffff0000)", "(%s << 16)"][v["crm"]]
|
|
||||||
param = ["cmem[i->param]", "cmem[ca]"][v["cmode"]]
|
|
||||||
return fmt % param
|
|
||||||
|
|
||||||
def expand_d(v):
|
def expand_d(v):
|
||||||
index = ["(i->param + ", "(id + "][v["dmode"]]
|
index = ["(i->param + ", "(id + "][v["dmode"]]
|
||||||
mask = ["ba0) & 0xff] << 8)", "ba1) & 0x1f] << 8)"][v["dbp"]]
|
mask = ["ba0) & 0xff] << 8)", "ba1) & 0x1f] << 8)"][v["dbp"]]
|
||||||
@ -44,6 +39,8 @@ def expand_mv(v):
|
|||||||
c = ["", "s"][v["movm"]]
|
c = ["", "s"][v["movm"]]
|
||||||
return "check_macc_overflow_%d%s()" % (v["sfmo"], c)
|
return "check_macc_overflow_%d%s()" % (v["sfmo"], c)
|
||||||
|
|
||||||
|
|
||||||
|
EXPAND_C = ["get_cmem(i->param)", "get_cmem(ca)"]
|
||||||
EXPAND_WC = ["cmem[i->param] =", "cmem[ca] ="]
|
EXPAND_WC = ["cmem[i->param] =", "cmem[ca] ="]
|
||||||
|
|
||||||
|
|
||||||
@ -70,14 +67,15 @@ def expand_wd1(v):
|
|||||||
return "dmem%d[" % v["dbp"] + index + mask
|
return "dmem%d[" % v["dbp"] + index + mask
|
||||||
|
|
||||||
WA2 = (
|
WA2 = (
|
||||||
" if(r < -0x80000000 || r > 0x7fffffff)\n"
|
" if(r < -2147483648 || r > 2147483647) {\n"
|
||||||
" st1 |= ST1_AOV;\n"
|
" st1 |= ST1_AOV;\n"
|
||||||
|
" if(st1 & ST1_AOVM) r = std::max(int64_t(-2147483648), std::min(int64_t(2147483647), r));\n"
|
||||||
|
" }"
|
||||||
" aacc = r;")
|
" aacc = r;")
|
||||||
|
|
||||||
|
|
||||||
PDESC_EXPAND = {
|
PDESC_EXPAND = {
|
||||||
"a": lambda v: ["aacc", "(aacc << 7)"][v["sfao"]],
|
"a": lambda v: ["aacc", "(aacc << 7)"][v["sfao"]],
|
||||||
"c": expand_c,
|
"c": lambda v: EXPAND_C[v["cmode"]],
|
||||||
"d": expand_d,
|
"d": expand_d,
|
||||||
"d24": expand_d24,
|
"d24": expand_d24,
|
||||||
"i": lambda v: "i->param",
|
"i": lambda v: "i->param",
|
||||||
@ -97,7 +95,7 @@ PDESC_EXPAND = {
|
|||||||
|
|
||||||
PDESC = {
|
PDESC = {
|
||||||
"a": (0, ["sfao"]),
|
"a": (0, ["sfao"]),
|
||||||
"c": (0, ["cmode", "crm"]),
|
"c": (0, ["cmode"]),
|
||||||
"d": (0, ["dmode", "dbp"]),
|
"d": (0, ["dmode", "dbp"]),
|
||||||
"d24": (0, ["dmode", "dbp"]),
|
"d24": (0, ["dmode", "dbp"]),
|
||||||
"i": (0, []),
|
"i": (0, []),
|
||||||
@ -115,7 +113,6 @@ VARIANTS = {
|
|||||||
"cmode": (2, "xmode(opcode, 'c', cs)" ),
|
"cmode": (2, "xmode(opcode, 'c', cs)" ),
|
||||||
"dmode": (2, "xmode(opcode, 'd', cs)" ),
|
"dmode": (2, "xmode(opcode, 'd', cs)" ),
|
||||||
"sfai": (2, "sfai(st1)"),
|
"sfai": (2, "sfai(st1)"),
|
||||||
"crm": (3, "crm(st1)"),
|
|
||||||
"dbp": (2, "dbp(st1)"),
|
"dbp": (2, "dbp(st1)"),
|
||||||
"sfao": (2, "sfao(st1)"),
|
"sfao": (2, "sfao(st1)"),
|
||||||
"sfmo": (4, "sfmo(st1)"),
|
"sfmo": (4, "sfmo(st1)"),
|
||||||
@ -131,7 +128,6 @@ VARIANT_CANONICAL_ORDER = [
|
|||||||
"cmode",
|
"cmode",
|
||||||
"dmode",
|
"dmode",
|
||||||
"sfai",
|
"sfai",
|
||||||
"crm",
|
|
||||||
"dbp",
|
"dbp",
|
||||||
"sfao",
|
"sfao",
|
||||||
"sfmo",
|
"sfmo",
|
||||||
|
@ -6,9 +6,48 @@
|
|||||||
Written by Olivier Galibert
|
Written by Olivier Galibert
|
||||||
MAME conversion by R. Belmont
|
MAME conversion by R. Belmont
|
||||||
Working emulation by The Talentuous Hands Of The Popularious hap
|
Working emulation by The Talentuous Hands Of The Popularious hap
|
||||||
Improvements by superctr
|
Properly working emulation by superctr
|
||||||
---------------------------------------------------------
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
Register map:
|
||||||
|
000-5fe : Channel specific registers
|
||||||
|
(high) (low)
|
||||||
|
+000 : xxxxxxxx -------- : Start address (low)
|
||||||
|
+000 : -------- xxxxxxxx : Unknown register (usually cleared)
|
||||||
|
+002 : xxxxxxxx -------- : Address page
|
||||||
|
: -------- xxxxxxxx : Start address (high)
|
||||||
|
+004 : -------- -------- : Unknown register (usually cleared)
|
||||||
|
+006 : -----x-- -------- : Unknown bit, always set
|
||||||
|
+008 : xxxxxxxx xxxxxxxx : Frequency
|
||||||
|
+00a : xxxxxxxx -------- : DSP ch 3 (right) output gain
|
||||||
|
: -------- xxxxxxxx : Loop address (low)
|
||||||
|
+00c : xxxxxxxx xxxxxxxx : End address
|
||||||
|
+00e : xxxxxxxx -------- : DSP ch 2 (Left) output gain
|
||||||
|
: -------- xxxxxxxx : Loop address (high)
|
||||||
|
+010 : xxxxxxxx xxxxxxxx : Filter time constant (latch)
|
||||||
|
+012 : -------- -------- : Unknown register (usually cleared)
|
||||||
|
+014 : xxxxxxxx xxxxxxxx : Volume (latch)
|
||||||
|
+016 : --x----- -------- : Key on status flag (only read)
|
||||||
|
+018 : xxxxxxxx xxxxxxxx : Filter time constant (Ramping target)
|
||||||
|
+01a : xxxxxxxx -------- : DSP ch 1 (chorus) output gain
|
||||||
|
: -------- xxxxxxxx : Filter ramping speed
|
||||||
|
+01c : xxxxxxxx xxxxxxxx : Volume (target)
|
||||||
|
+01e : xxxxxxxx -------- : DSP ch 0 (reverb) output gain
|
||||||
|
: -------- xxxxxxxx : Filter ramping speed
|
||||||
|
600-604 : Key on flags (each bit corresponds to a channel)
|
||||||
|
608-60c : Key off flags (each bit corresponds to a channel)
|
||||||
|
618 : Unknown register (usually 0x5cbc is written)
|
||||||
|
61a : Unknown register (usually 0x5cbc is written)
|
||||||
|
620 : Unknown register (usually 0x0128 is written)
|
||||||
|
628 : Unknown register (usually 0x0066 is written)
|
||||||
|
630 : Unknown register (usually 0x0001 is written)
|
||||||
|
638 : ROM readback address low
|
||||||
|
63a : ROM readback address high
|
||||||
|
63c : ROM readback word low
|
||||||
|
63e : ROM readback word high
|
||||||
|
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
Additional notes on the sample format, reverse-engineered
|
Additional notes on the sample format, reverse-engineered
|
||||||
by Olivier Galibert and David Haywood:
|
by Olivier Galibert and David Haywood:
|
||||||
|
|
||||||
@ -45,12 +84,8 @@
|
|||||||
---------------------------------------------------------
|
---------------------------------------------------------
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
- Filter behavior might not be perfect.
|
- Filter and ramping behavior might not be perfect.
|
||||||
- Volume ramping probably behaves differently on hardware.
|
- sometimes clicking
|
||||||
- hook up DSP, it's used for reverb and chorus effects.
|
|
||||||
- identify sample flags
|
|
||||||
* bassdrum in shikigam level 1 music is a good hint: it should be one octave
|
|
||||||
lower, indicating possible stereo sample, or base octave(like in ymf278)
|
|
||||||
- memory reads out of range sometimes
|
- memory reads out of range sometimes
|
||||||
|
|
||||||
*/
|
*/
|
||||||
@ -63,7 +98,6 @@ TODO:
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#define EMPHASIS_CUTOFF_BASE 0x800
|
#define EMPHASIS_CUTOFF_BASE 0x800
|
||||||
#define EMPHASIS_CUTOFF_SHIFT 1
|
|
||||||
#define EMPHASIS_OUTPUT_SHIFT 15
|
#define EMPHASIS_OUTPUT_SHIFT 15
|
||||||
|
|
||||||
// device type definition
|
// device type definition
|
||||||
@ -104,16 +138,18 @@ void zsg2_device::device_start()
|
|||||||
save_item(NAME(m_read_address));
|
save_item(NAME(m_read_address));
|
||||||
|
|
||||||
// Generate the output gain table. Assuming -1dB per step for now.
|
// Generate the output gain table. Assuming -1dB per step for now.
|
||||||
for (int i = 0; i < 32; i++)
|
for (int i = 0, history=0; i < 32; i++)
|
||||||
{
|
{
|
||||||
double val = pow(10, -(31 - i) / 20.) * 65535.;
|
double val = pow(10, -(31 - i) / 20.) * 65535.;
|
||||||
gain_tab[i] = val;
|
gain_tab[i] = val;
|
||||||
|
gain_tab_frac[i] = val-history;
|
||||||
|
history = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int ch = 0; ch < 48; ch++)
|
for (int ch = 0; ch < 48; ch++)
|
||||||
{
|
{
|
||||||
save_item(NAME(m_chan[ch].v), ch);
|
save_item(NAME(m_chan[ch].v), ch);
|
||||||
save_item(NAME(m_chan[ch].is_playing), ch);
|
save_item(NAME(m_chan[ch].status), ch);
|
||||||
save_item(NAME(m_chan[ch].cur_pos), ch);
|
save_item(NAME(m_chan[ch].cur_pos), ch);
|
||||||
save_item(NAME(m_chan[ch].step_ptr), ch);
|
save_item(NAME(m_chan[ch].step_ptr), ch);
|
||||||
save_item(NAME(m_chan[ch].step), ch);
|
save_item(NAME(m_chan[ch].step), ch);
|
||||||
@ -125,14 +161,12 @@ void zsg2_device::device_start()
|
|||||||
save_item(NAME(m_chan[ch].vol), ch);
|
save_item(NAME(m_chan[ch].vol), ch);
|
||||||
save_item(NAME(m_chan[ch].vol_initial), ch);
|
save_item(NAME(m_chan[ch].vol_initial), ch);
|
||||||
save_item(NAME(m_chan[ch].vol_target), ch);
|
save_item(NAME(m_chan[ch].vol_target), ch);
|
||||||
|
save_item(NAME(m_chan[ch].vol_delta), ch);
|
||||||
save_item(NAME(m_chan[ch].emphasis_cutoff), ch);
|
|
||||||
save_item(NAME(m_chan[ch].emphasis_cutoff_initial), ch);
|
|
||||||
save_item(NAME(m_chan[ch].emphasis_cutoff_target), ch);
|
|
||||||
|
|
||||||
save_item(NAME(m_chan[ch].output_cutoff), ch);
|
save_item(NAME(m_chan[ch].output_cutoff), ch);
|
||||||
save_item(NAME(m_chan[ch].output_cutoff_initial), ch);
|
save_item(NAME(m_chan[ch].output_cutoff_initial), ch);
|
||||||
save_item(NAME(m_chan[ch].output_cutoff_target), ch);
|
save_item(NAME(m_chan[ch].output_cutoff_target), ch);
|
||||||
|
save_item(NAME(m_chan[ch].output_cutoff_delta), ch);
|
||||||
|
|
||||||
save_item(NAME(m_chan[ch].emphasis_filter_state), ch);
|
save_item(NAME(m_chan[ch].emphasis_filter_state), ch);
|
||||||
save_item(NAME(m_chan[ch].output_filter_state), ch);
|
save_item(NAME(m_chan[ch].output_filter_state), ch);
|
||||||
@ -141,6 +175,8 @@ void zsg2_device::device_start()
|
|||||||
|
|
||||||
save_item(NAME(m_chan[ch].samples), ch);
|
save_item(NAME(m_chan[ch].samples), ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
save_item(NAME(m_sample_count));
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
@ -159,6 +195,7 @@ void zsg2_device::device_reset()
|
|||||||
for (int ch = 0; ch < 48; ch++)
|
for (int ch = 0; ch < 48; ch++)
|
||||||
for (int reg = 0; reg < 0x10; reg++)
|
for (int reg = 0; reg < 0x10; reg++)
|
||||||
chan_w(ch, reg, 0);
|
chan_w(ch, reg, 0);
|
||||||
|
m_sample_count = 0;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
for (int i = 0; i < m_mem_blocks; i++)
|
for (int i = 0; i < m_mem_blocks; i++)
|
||||||
@ -232,7 +269,7 @@ void zsg2_device::filter_samples(zchan *ch)
|
|||||||
|
|
||||||
// not sure if the filter works exactly this way, however I am pleased
|
// not sure if the filter works exactly this way, however I am pleased
|
||||||
// with the output for now.
|
// with the output for now.
|
||||||
ch->emphasis_filter_state += (raw_samples[i]-(ch->emphasis_filter_state>>16)) * (EMPHASIS_CUTOFF_BASE - ch->emphasis_cutoff);
|
ch->emphasis_filter_state += (raw_samples[i]-(ch->emphasis_filter_state>>16)) * EMPHASIS_CUTOFF_BASE;
|
||||||
ch->samples[i+1] = (ch->emphasis_filter_state) >> EMPHASIS_OUTPUT_SHIFT;
|
ch->samples[i+1] = (ch->emphasis_filter_state) >> EMPHASIS_OUTPUT_SHIFT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -243,6 +280,7 @@ void zsg2_device::filter_samples(zchan *ch)
|
|||||||
|
|
||||||
void zsg2_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
|
void zsg2_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
|
||||||
{
|
{
|
||||||
|
// DSP is programmed to expect 24-bit samples! So we're not limiting to 16-bit here
|
||||||
for (int i = 0; i < samples; i++)
|
for (int i = 0; i < samples; i++)
|
||||||
{
|
{
|
||||||
int32_t mix[4] = {};
|
int32_t mix[4] = {};
|
||||||
@ -254,7 +292,7 @@ void zsg2_device::sound_stream_update(sound_stream &stream, stream_sample_t **in
|
|||||||
//auto & elem = m_chan[0];
|
//auto & elem = m_chan[0];
|
||||||
{
|
{
|
||||||
ch++;
|
ch++;
|
||||||
if (!elem.is_playing)
|
if (!(elem.status & STATUS_ACTIVE))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
elem.step_ptr += elem.step;
|
elem.step_ptr += elem.step;
|
||||||
@ -268,12 +306,11 @@ void zsg2_device::sound_stream_update(sound_stream &stream, stream_sample_t **in
|
|||||||
if ((elem.cur_pos + 1) >= elem.end_pos)
|
if ((elem.cur_pos + 1) >= elem.end_pos)
|
||||||
{
|
{
|
||||||
// end of sample
|
// end of sample
|
||||||
elem.is_playing = false;
|
elem.status &= ~STATUS_ACTIVE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
filter_samples(&elem);
|
filter_samples(&elem);
|
||||||
//elem.samples = prepare_samples(elem.page | elem.cur_pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sample_pos = elem.step_ptr >> 14 & 3;
|
uint8_t sample_pos = elem.step_ptr >> 14 & 3;
|
||||||
@ -282,6 +319,7 @@ void zsg2_device::sound_stream_update(sound_stream &stream, stream_sample_t **in
|
|||||||
// linear interpolation (hardware certainly does something similar)
|
// linear interpolation (hardware certainly does something similar)
|
||||||
sample = elem.samples[sample_pos];
|
sample = elem.samples[sample_pos];
|
||||||
sample += ((uint16_t)(elem.step_ptr<<2&0xffff) * (int16_t)(elem.samples[sample_pos+1] - sample))>>16;
|
sample += ((uint16_t)(elem.step_ptr<<2&0xffff) * (int16_t)(elem.samples[sample_pos+1] - sample))>>16;
|
||||||
|
|
||||||
sample = (sample * elem.vol) >> 16;
|
sample = (sample * elem.vol) >> 16;
|
||||||
|
|
||||||
// another filter...
|
// another filter...
|
||||||
@ -299,10 +337,13 @@ void zsg2_device::sound_stream_update(sound_stream &stream, stream_sample_t **in
|
|||||||
mix[output] += (output_sample * gain_tab[output_gain&0x1f]) >> 13;
|
mix[output] += (output_sample * gain_tab[output_gain&0x1f]) >> 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply transitions (This is not accurate yet)
|
// Apply ramping every other update
|
||||||
elem.vol = ramp(elem.vol, elem.vol_target);
|
// It's possible key on is handled on the other sample
|
||||||
elem.output_cutoff = ramp(elem.output_cutoff, elem.output_cutoff_target);
|
if(m_sample_count & 1)
|
||||||
elem.emphasis_cutoff = ramp(elem.emphasis_cutoff, elem.emphasis_cutoff_target);
|
{
|
||||||
|
elem.vol = ramp(elem.vol, elem.vol_target, elem.vol_delta);
|
||||||
|
elem.output_cutoff = ramp(elem.output_cutoff, elem.output_cutoff_target, elem.output_cutoff_delta);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ch = 0;
|
ch = 0;
|
||||||
@ -311,6 +352,7 @@ void zsg2_device::sound_stream_update(sound_stream &stream, stream_sample_t **in
|
|||||||
outputs[output][i] = mix[output];
|
outputs[output][i] = mix[output];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
m_sample_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@ -347,9 +389,9 @@ void zsg2_device::chan_w(int ch, int reg, uint16_t data)
|
|||||||
|
|
||||||
case 0x5:
|
case 0x5:
|
||||||
// lo byte: loop address low
|
// lo byte: loop address low
|
||||||
// hi byte: right output gain (bypass DSP)
|
// hi byte: right output gain (direct)
|
||||||
m_chan[ch].loop_pos = (m_chan[ch].loop_pos & 0xff00) | (data & 0xff);
|
m_chan[ch].loop_pos = (m_chan[ch].loop_pos & 0xff00) | (data & 0xff);
|
||||||
m_chan[ch].output_gain[1] = data >> 8;
|
m_chan[ch].output_gain[3] = data >> 8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x6:
|
case 0x6:
|
||||||
@ -359,13 +401,13 @@ void zsg2_device::chan_w(int ch, int reg, uint16_t data)
|
|||||||
|
|
||||||
case 0x7:
|
case 0x7:
|
||||||
// lo byte: loop address high
|
// lo byte: loop address high
|
||||||
// hi byte: left output gain (bypass DSP)
|
// hi byte: left output gain (direct)
|
||||||
m_chan[ch].loop_pos = (m_chan[ch].loop_pos & 0x00ff) | (data << 8 & 0xff00);
|
m_chan[ch].loop_pos = (m_chan[ch].loop_pos & 0x00ff) | (data << 8 & 0xff00);
|
||||||
m_chan[ch].output_gain[0] = data >> 8;
|
m_chan[ch].output_gain[2] = data >> 8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x8:
|
case 0x8:
|
||||||
// Filter cutoff (Direct)
|
// IIR lowpass time constant (initial, latched on key on)
|
||||||
m_chan[ch].output_cutoff_initial = data;
|
m_chan[ch].output_cutoff_initial = data;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -374,7 +416,7 @@ void zsg2_device::chan_w(int ch, int reg, uint16_t data)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xa:
|
case 0xa:
|
||||||
// volume (Direct)
|
// volume (initial, latched on key on)
|
||||||
m_chan[ch].vol_initial = data;
|
m_chan[ch].vol_initial = data;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -384,27 +426,27 @@ void zsg2_device::chan_w(int ch, int reg, uint16_t data)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xc:
|
case 0xc:
|
||||||
// filter gain ?
|
// IIR lowpass time constant (target)
|
||||||
m_chan[ch].output_cutoff_target = data;
|
m_chan[ch].output_cutoff_target = data;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xd:
|
case 0xd:
|
||||||
// hi byte: DSP Chorus volume
|
// hi byte: DSP channel 1 (chorus) gain
|
||||||
// lo byte: Emphasis filter time constant (direct value)
|
// lo byte: Filter ramping speed
|
||||||
m_chan[ch].output_gain[3] = data >> 8;
|
m_chan[ch].output_gain[1] = data >> 8;
|
||||||
m_chan[ch].emphasis_cutoff_initial = expand_reg(data & 0xff);
|
m_chan[ch].output_cutoff_delta = get_ramp(data & 0xff);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xe:
|
case 0xe:
|
||||||
// volume (Target)
|
// volume target
|
||||||
m_chan[ch].vol_target = data;
|
m_chan[ch].vol_target = data;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xf:
|
case 0xf:
|
||||||
// hi byte: DSP Reverb volume
|
// hi byte: DSP channel 0 (reverb) gain
|
||||||
// lo byte: Emphasis filter time constant
|
// lo byte: Volume ramping speed
|
||||||
m_chan[ch].output_gain[2] = data >> 8;
|
m_chan[ch].output_gain[0] = data >> 8;
|
||||||
m_chan[ch].emphasis_cutoff_target = expand_reg(data & 0xff);
|
m_chan[ch].vol_delta = get_ramp(data & 0xff);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -419,7 +461,7 @@ uint16_t zsg2_device::chan_r(int ch, int reg)
|
|||||||
switch (reg)
|
switch (reg)
|
||||||
{
|
{
|
||||||
case 0xb: // Only later games (taitogn) read this register...
|
case 0xb: // Only later games (taitogn) read this register...
|
||||||
return m_chan[ch].is_playing << 13;
|
return m_chan[ch].status;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -427,37 +469,30 @@ uint16_t zsg2_device::chan_r(int ch, int reg)
|
|||||||
return m_chan[ch].v[reg];
|
return m_chan[ch].v[reg];
|
||||||
}
|
}
|
||||||
|
|
||||||
// expand 8-bit reg to 16-bit value. This is used for the emphasis filter
|
// Convert ramping register value to something more usable.
|
||||||
// register. Not sure about how this works, the sound
|
// Upper 4 bits is a shift amount, lower 4 bits is a 2's complement value.
|
||||||
|
// Get ramp amount by sign extending the low 4 bits, XOR by 8, then
|
||||||
|
// shifting it by the upper 4 bits.
|
||||||
// CPU uses a lookup table (stored in gdarius sound cpu ROM at 0x6332) to
|
// CPU uses a lookup table (stored in gdarius sound cpu ROM at 0x6332) to
|
||||||
// calculate this value, for now I'm generating an opproximate inverse.
|
// calculate this value, for now I'm generating an opproximate inverse.
|
||||||
int16_t zsg2_device::expand_reg(uint8_t val)
|
int16_t zsg2_device::get_ramp(uint8_t val)
|
||||||
{
|
{
|
||||||
static const signed char frac_tab[16] = {8,9,10,11,12,13,14,15,-15,-14,-13,-12,-11,-10,-9,-8};
|
int16_t frac = val<<12; // sign extend
|
||||||
static const unsigned char shift_tab[8] = {1, 2, 3, 4, 5, 6, 7, 8};
|
frac = ((frac>>12) ^ 8) << (val >> 4);
|
||||||
|
|
||||||
return (frac_tab[val&0x0f] << shift_tab[val>>4])>>EMPHASIS_CUTOFF_SHIFT;
|
return (frac >> 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ramp registers
|
inline uint16_t zsg2_device::ramp(uint16_t current, uint16_t target, int16_t delta)
|
||||||
// The CPU does not write often enough to make the transitions always sound
|
|
||||||
// smooth, so the sound chip probably helps by smoothing the changes.
|
|
||||||
// There are two sets of the volume and filter cutoff registers.
|
|
||||||
// At key on, the CPU writes to the "direct" registers, after that it will
|
|
||||||
// write to the "target" register instead.
|
|
||||||
inline int32_t zsg2_device::ramp(int32_t current, int32_t target)
|
|
||||||
{
|
{
|
||||||
int32_t difference = abs(target-current);
|
int32_t rampval = current + delta;
|
||||||
difference -= 0x40;
|
|
||||||
|
|
||||||
if(difference < 0)
|
if(delta < 0 && rampval < target)
|
||||||
return target;
|
rampval = target;
|
||||||
else if(target < current)
|
else if(delta >= 0 && rampval > target)
|
||||||
return target + difference;
|
rampval = target;
|
||||||
else if(target > current)
|
|
||||||
return target - difference;
|
return rampval;
|
||||||
|
|
||||||
return target;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@ -475,13 +510,12 @@ void zsg2_device::control_w(int reg, uint16_t data)
|
|||||||
if (data & (1 << i))
|
if (data & (1 << i))
|
||||||
{
|
{
|
||||||
int ch = base | i;
|
int ch = base | i;
|
||||||
m_chan[ch].is_playing = true;
|
m_chan[ch].status |= STATUS_ACTIVE;
|
||||||
m_chan[ch].cur_pos = m_chan[ch].start_pos;
|
m_chan[ch].cur_pos = m_chan[ch].start_pos;
|
||||||
m_chan[ch].step_ptr = 0;
|
m_chan[ch].step_ptr = 0;
|
||||||
m_chan[ch].emphasis_filter_state = 0;
|
m_chan[ch].emphasis_filter_state = 0;
|
||||||
m_chan[ch].vol = m_chan[ch].vol_initial;
|
m_chan[ch].vol = m_chan[ch].vol_initial;
|
||||||
m_chan[ch].output_cutoff = m_chan[ch].output_cutoff_initial;
|
m_chan[ch].output_cutoff = m_chan[ch].output_cutoff_initial;
|
||||||
m_chan[ch].emphasis_cutoff = m_chan[ch].emphasis_cutoff_initial;
|
|
||||||
filter_samples(&m_chan[ch]);
|
filter_samples(&m_chan[ch]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -497,7 +531,7 @@ void zsg2_device::control_w(int reg, uint16_t data)
|
|||||||
if (data & (1 << i))
|
if (data & (1 << i))
|
||||||
{
|
{
|
||||||
int ch = base | i;
|
int ch = base | i;
|
||||||
m_chan[ch].is_playing = false;
|
m_chan[ch].status &= ~STATUS_ACTIVE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// license:BSD-3-Clause
|
// license:BSD-3-Clause
|
||||||
// copyright-holders:Olivier Galibert, R. Belmont, hap
|
// copyright-holders:Olivier Galibert, R. Belmont, hap, superctr
|
||||||
/*
|
/*
|
||||||
ZOOM ZSG-2 custom wavetable synthesizer
|
ZOOM ZSG-2 custom wavetable synthesizer
|
||||||
*/
|
*/
|
||||||
@ -14,11 +14,6 @@
|
|||||||
// INTERFACE CONFIGURATION MACROS
|
// INTERFACE CONFIGURATION MACROS
|
||||||
//**************************************************************************
|
//**************************************************************************
|
||||||
|
|
||||||
#define MCFG_ZSG2_ADD(_tag, _clock) \
|
|
||||||
MCFG_DEVICE_ADD(_tag, ZSG2, _clock)
|
|
||||||
#define MCFG_ZSG2_REPLACE(_tag, _clock) \
|
|
||||||
MCFG_DEVICE_REPLACE(_tag, ZSG2, _clock)
|
|
||||||
|
|
||||||
#define MCFG_ZSG2_EXT_READ_HANDLER(_devcb) \
|
#define MCFG_ZSG2_EXT_READ_HANDLER(_devcb) \
|
||||||
downcast<zsg2_device &>(*device).set_ext_read_handler(DEVCB_##_devcb);
|
downcast<zsg2_device &>(*device).set_ext_read_handler(DEVCB_##_devcb);
|
||||||
|
|
||||||
@ -46,11 +41,14 @@ protected:
|
|||||||
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
|
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const uint16_t STATUS_ACTIVE = 0x2000;
|
||||||
|
|
||||||
// 16 registers per channel, 48 channels
|
// 16 registers per channel, 48 channels
|
||||||
struct zchan
|
struct zchan
|
||||||
{
|
{
|
||||||
uint16_t v[16];
|
uint16_t v[16];
|
||||||
bool is_playing;
|
|
||||||
|
uint16_t status;
|
||||||
uint32_t cur_pos;
|
uint32_t cur_pos;
|
||||||
uint32_t step_ptr;
|
uint32_t step_ptr;
|
||||||
uint32_t step;
|
uint32_t step;
|
||||||
@ -62,14 +60,12 @@ private:
|
|||||||
uint16_t vol;
|
uint16_t vol;
|
||||||
uint16_t vol_initial;
|
uint16_t vol_initial;
|
||||||
uint16_t vol_target;
|
uint16_t vol_target;
|
||||||
|
int16_t vol_delta;
|
||||||
int16_t emphasis_cutoff;
|
|
||||||
int16_t emphasis_cutoff_initial;
|
|
||||||
int16_t emphasis_cutoff_target;
|
|
||||||
|
|
||||||
uint16_t output_cutoff;
|
uint16_t output_cutoff;
|
||||||
uint16_t output_cutoff_initial;
|
uint16_t output_cutoff_initial;
|
||||||
uint16_t output_cutoff_target;
|
uint16_t output_cutoff_target;
|
||||||
|
int16_t output_cutoff_delta;
|
||||||
|
|
||||||
int32_t emphasis_filter_state;
|
int32_t emphasis_filter_state;
|
||||||
int32_t output_filter_state;
|
int32_t output_filter_state;
|
||||||
@ -81,7 +77,10 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
uint16_t gain_tab[256];
|
uint16_t gain_tab[256];
|
||||||
|
uint16_t gain_tab_frac[256];
|
||||||
|
|
||||||
zchan m_chan[48];
|
zchan m_chan[48];
|
||||||
|
uint32_t m_sample_count;
|
||||||
|
|
||||||
required_region_ptr<uint32_t> m_mem_base;
|
required_region_ptr<uint32_t> m_mem_base;
|
||||||
uint32_t m_read_address;
|
uint32_t m_read_address;
|
||||||
@ -100,8 +99,8 @@ private:
|
|||||||
uint16_t control_r(int reg);
|
uint16_t control_r(int reg);
|
||||||
int16_t *prepare_samples(uint32_t offset);
|
int16_t *prepare_samples(uint32_t offset);
|
||||||
void filter_samples(zchan *ch);
|
void filter_samples(zchan *ch);
|
||||||
int16_t expand_reg(uint8_t val);
|
int16_t get_ramp(uint8_t val);
|
||||||
inline int32_t ramp(int32_t current, int32_t target);
|
inline uint16_t ramp(uint16_t current, uint16_t target, int16_t delta);
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_DEVICE_TYPE(ZSG2, zsg2_device)
|
DECLARE_DEVICE_TYPE(ZSG2, zsg2_device)
|
||||||
|
@ -22,7 +22,12 @@ and a Zoom Corp. ZFX-2 DSP instead of the TMS57002.
|
|||||||
|
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
- add DSP, sound is tinny without it
|
- Raycrisis song 9 gets cut off due to clipping. Possible DSP emulation bug,
|
||||||
|
or just have to change the volumes. in the sound test, it will start to cut
|
||||||
|
at about 55%. and the timbre doesn't sound right anyway.
|
||||||
|
|
||||||
|
- check DSP behavior
|
||||||
|
- Implement the ramping control registers in zsg2.cpp
|
||||||
|
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
@ -38,9 +43,11 @@ DEFINE_DEVICE_TYPE(TAITO_ZOOM, taito_zoom_device, "taito_zoom", "Taito Zoom Soun
|
|||||||
// taito_zoom_device - constructor
|
// taito_zoom_device - constructor
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
taito_zoom_device::taito_zoom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
taito_zoom_device::taito_zoom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||||
: device_t(mconfig, TAITO_ZOOM, tag, owner, clock),
|
device_t(mconfig, TAITO_ZOOM, tag, owner, clock),
|
||||||
|
device_mixer_interface(mconfig, *this, 2),
|
||||||
m_soundcpu(*this, "mn10200"),
|
m_soundcpu(*this, "mn10200"),
|
||||||
|
m_tms57002(*this, "tms57002"),
|
||||||
m_zsg2(*this, "zsg2"),
|
m_zsg2(*this, "zsg2"),
|
||||||
m_reg_address(0),
|
m_reg_address(0),
|
||||||
m_tms_ctrl(0),
|
m_tms_ctrl(0),
|
||||||
@ -71,6 +78,7 @@ void taito_zoom_device::device_reset()
|
|||||||
m_reg_address = 0;
|
m_reg_address = 0;
|
||||||
|
|
||||||
m_zsg2->reset();
|
m_zsg2->reset();
|
||||||
|
m_tms57002->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -98,15 +106,20 @@ READ8_MEMBER(taito_zoom_device::tms_ctrl_r)
|
|||||||
|
|
||||||
WRITE8_MEMBER(taito_zoom_device::tms_ctrl_w)
|
WRITE8_MEMBER(taito_zoom_device::tms_ctrl_w)
|
||||||
{
|
{
|
||||||
#if 0
|
// According to the TMS57002 manual, reset should NOT be set low during the data transfer.
|
||||||
tms57002_reset_w(data & 4);
|
//m_tms57002->set_input_line(INPUT_LINE_RESET, data & 0x10 ? CLEAR_LINE : ASSERT_LINE);
|
||||||
tms57002_cload_w(data & 2);
|
m_tms57002->cload_w(data & 2);
|
||||||
tms57002_pload_w(data & 1);
|
m_tms57002->pload_w(data & 1);
|
||||||
#endif
|
// Other bits unknown (0x9F at most games)
|
||||||
|
|
||||||
m_tms_ctrl = data;
|
m_tms_ctrl = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void taito_zoom_device::update_status_pin(int state)
|
||||||
|
{
|
||||||
|
printf("inside callback set status to %d\n",state);
|
||||||
|
m_soundcpu->set_input_line(1, state);
|
||||||
|
machine().scheduler().synchronize(); // the fix to all problems
|
||||||
|
}
|
||||||
|
|
||||||
void taito_zoom_device::taitozoom_mn_map(address_map &map)
|
void taito_zoom_device::taitozoom_mn_map(address_map &map)
|
||||||
{
|
{
|
||||||
@ -116,11 +129,17 @@ void taito_zoom_device::taitozoom_mn_map(address_map &map)
|
|||||||
map(0x080000, 0x0fffff).rom().region("mn10200", 0);
|
map(0x080000, 0x0fffff).rom().region("mn10200", 0);
|
||||||
}
|
}
|
||||||
map(0x400000, 0x41ffff).ram();
|
map(0x400000, 0x41ffff).ram();
|
||||||
map(0x800000, 0x8007ff).rw("zsg2", FUNC(zsg2_device::read), FUNC(zsg2_device::write));
|
map(0x800000, 0x8007ff).rw(m_zsg2, FUNC(zsg2_device::read), FUNC(zsg2_device::write));
|
||||||
map(0xc00000, 0xc00001).ram(); // TMS57002 comms
|
map(0xc00000, 0xc00000).rw(m_tms57002, FUNC(tms57002_device::data_r), FUNC(tms57002_device::data_w)); // TMS57002 comms
|
||||||
map(0xe00000, 0xe000ff).rw(FUNC(taito_zoom_device::shared_ram_r), FUNC(taito_zoom_device::shared_ram_w)); // M66220FP for comms with maincpu
|
map(0xe00000, 0xe000ff).rw(FUNC(taito_zoom_device::shared_ram_r), FUNC(taito_zoom_device::shared_ram_w)); // M66220FP for comms with maincpu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_DSP
|
||||||
|
void taito_zoom_device::tms57002_map(address_map &map)
|
||||||
|
{
|
||||||
|
map(0x00000, 0x3ffff).ram();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
|
|
||||||
@ -148,14 +167,14 @@ WRITE16_MEMBER(taito_zoom_device::reg_data_w)
|
|||||||
// zsg2+dsp global volume left
|
// zsg2+dsp global volume left
|
||||||
if (data & 0xc0c0)
|
if (data & 0xc0c0)
|
||||||
popmessage("ZOOM gain L %04X, contact MAMEdev", data);
|
popmessage("ZOOM gain L %04X, contact MAMEdev", data);
|
||||||
m_zsg2->set_output_gain(0, (data & 0x3f) / 63.0);
|
m_tms57002->set_output_gain(2, (data & 0x3f) / 63.0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x05:
|
case 0x05:
|
||||||
// zsg2+dsp global volume right
|
// zsg2+dsp global volume right
|
||||||
if (data & 0xc0c0)
|
if (data & 0xc0c0)
|
||||||
popmessage("ZOOM gain R %04X, contact MAMEdev", data);
|
popmessage("ZOOM gain R %04X, contact MAMEdev", data);
|
||||||
m_zsg2->set_output_gain(1, (data & 0x3f) / 63.0);
|
m_tms57002->set_output_gain(3, (data & 0x3f) / 63.0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -184,13 +203,27 @@ MACHINE_CONFIG_START(taito_zoom_device::device_add_mconfig)
|
|||||||
|
|
||||||
MCFG_QUANTUM_TIME(attotime::from_hz(60000))
|
MCFG_QUANTUM_TIME(attotime::from_hz(60000))
|
||||||
|
|
||||||
MCFG_ZSG2_ADD("zsg2", XTAL(25'000'000))
|
TMS57002(config, m_tms57002, XTAL(25'000'000)/2);
|
||||||
|
#ifdef USE_DSP
|
||||||
|
//m_tms57002->empty_callback().set_inputline(m_soundcpu, MN10200_IRQ1, m_tms57002->empty_r()); /*.invert();*/
|
||||||
|
m_tms57002->empty_callback().set_inputline(m_soundcpu, MN10200_IRQ1).invert();
|
||||||
|
|
||||||
// we assume the parent machine has created lspeaker/rspeaker
|
m_tms57002->set_addrmap(AS_DATA, &taito_zoom_device::tms57002_map);
|
||||||
MCFG_SOUND_ROUTE(0, "^lspeaker", 1.0) // bypass DSP
|
m_tms57002->add_route(2, *this, 1.0, AUTO_ALLOC_INPUT, 0);
|
||||||
MCFG_SOUND_ROUTE(1, "^rspeaker", 1.0)
|
m_tms57002->add_route(3, *this, 1.0, AUTO_ALLOC_INPUT, 1);
|
||||||
|
#else // Unsupported opcode issue
|
||||||
|
m_tms57002->set_disable();
|
||||||
|
#endif
|
||||||
|
|
||||||
//MCFG_SOUND_ROUTE(2, "^lspeaker", 1.0) // DSP reverb
|
ZSG2(config, m_zsg2, XTAL(25'000'000));
|
||||||
//MCFG_SOUND_ROUTE(3, "^rspeaker", 1.0) // DSP chorus
|
#ifdef USE_DSP
|
||||||
|
m_zsg2->add_route(0, *m_tms57002, 0.5, 0); // reverb effect
|
||||||
|
m_zsg2->add_route(1, *m_tms57002, 0.5, 1); // chorus effect
|
||||||
|
m_zsg2->add_route(2, *m_tms57002, 0.5, 2); // left direct
|
||||||
|
m_zsg2->add_route(3, *m_tms57002, 0.5, 3); // right direct
|
||||||
|
#else
|
||||||
|
m_zsg2->add_route(2, *this, 1.0, AUTO_ALLOC_INPUT, 0);
|
||||||
|
m_zsg2->add_route(3, *this, 1.0, AUTO_ALLOC_INPUT, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
MACHINE_CONFIG_END
|
MACHINE_CONFIG_END
|
||||||
|
@ -14,12 +14,15 @@
|
|||||||
#include "cpu/tms57002/tms57002.h"
|
#include "cpu/tms57002/tms57002.h"
|
||||||
#include "sound/zsg2.h"
|
#include "sound/zsg2.h"
|
||||||
|
|
||||||
|
#define USE_DSP // Uncomment when DSP emulation is working
|
||||||
|
|
||||||
class taito_zoom_device : public device_t
|
class taito_zoom_device : public device_t, public device_mixer_interface
|
||||||
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
taito_zoom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
static constexpr feature_type imperfect_features() { return feature::SOUND; }
|
||||||
|
|
||||||
|
taito_zoom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||||
|
|
||||||
DECLARE_WRITE16_MEMBER(sound_irq_w);
|
DECLARE_WRITE16_MEMBER(sound_irq_w);
|
||||||
DECLARE_READ16_MEMBER(sound_irq_r);
|
DECLARE_READ16_MEMBER(sound_irq_r);
|
||||||
@ -34,6 +37,9 @@ public:
|
|||||||
void set_use_flash() { m_use_flash = true; }
|
void set_use_flash() { m_use_flash = true; }
|
||||||
|
|
||||||
void taitozoom_mn_map(address_map &map);
|
void taitozoom_mn_map(address_map &map);
|
||||||
|
#ifdef USE_DSP
|
||||||
|
void tms57002_map(address_map &map);
|
||||||
|
#endif
|
||||||
protected:
|
protected:
|
||||||
// device-level overrides
|
// device-level overrides
|
||||||
virtual void device_start() override;
|
virtual void device_start() override;
|
||||||
@ -43,6 +49,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
// inherited devices/pointers
|
// inherited devices/pointers
|
||||||
required_device<mn10200_device> m_soundcpu;
|
required_device<mn10200_device> m_soundcpu;
|
||||||
|
required_device<tms57002_device> m_tms57002;
|
||||||
required_device<zsg2_device> m_zsg2;
|
required_device<zsg2_device> m_zsg2;
|
||||||
|
|
||||||
// internal state
|
// internal state
|
||||||
@ -50,6 +57,8 @@ private:
|
|||||||
uint8_t m_tms_ctrl;
|
uint8_t m_tms_ctrl;
|
||||||
bool m_use_flash;
|
bool m_use_flash;
|
||||||
std::unique_ptr<uint8_t[]> m_snd_shared_ram;
|
std::unique_ptr<uint8_t[]> m_snd_shared_ram;
|
||||||
|
|
||||||
|
void update_status_pin(int state);
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_DEVICE_TYPE(TAITO_ZOOM, taito_zoom_device)
|
DECLARE_DEVICE_TYPE(TAITO_ZOOM, taito_zoom_device)
|
||||||
|
@ -744,8 +744,10 @@ MACHINE_CONFIG_START(taitogn_state::coh3002t)
|
|||||||
MCFG_SOUND_ROUTE(0, "lspeaker", 0.45)
|
MCFG_SOUND_ROUTE(0, "lspeaker", 0.45)
|
||||||
MCFG_SOUND_ROUTE(1, "rspeaker", 0.45)
|
MCFG_SOUND_ROUTE(1, "rspeaker", 0.45)
|
||||||
|
|
||||||
MCFG_TAITO_ZOOM_ADD("taito_zoom")
|
TAITO_ZOOM(config, m_zoom);
|
||||||
MCFG_TAITO_ZOOM_USE_FLASH
|
m_zoom->set_use_flash();
|
||||||
|
m_zoom->add_route(0, "lspeaker", 1.0);
|
||||||
|
m_zoom->add_route(1, "rspeaker", 1.0);
|
||||||
|
|
||||||
MCFG_DEVICE_MODIFY("taito_zoom:zsg2")
|
MCFG_DEVICE_MODIFY("taito_zoom:zsg2")
|
||||||
MCFG_ZSG2_EXT_READ_HANDLER(READ32(*this, taitogn_state, zsg2_ext_r))
|
MCFG_ZSG2_EXT_READ_HANDLER(READ32(*this, taitogn_state, zsg2_ext_r))
|
||||||
|
@ -1206,7 +1206,9 @@ MACHINE_CONFIG_START(zn_state::coh1000tb)
|
|||||||
MCFG_SOUND_ROUTE(0, "lspeaker", 0.45)
|
MCFG_SOUND_ROUTE(0, "lspeaker", 0.45)
|
||||||
MCFG_SOUND_ROUTE(1, "rspeaker", 0.45)
|
MCFG_SOUND_ROUTE(1, "rspeaker", 0.45)
|
||||||
|
|
||||||
MCFG_TAITO_ZOOM_ADD("taito_zoom")
|
TAITO_ZOOM(config, m_zoom);
|
||||||
|
m_zoom->add_route(0, "lspeaker", 1.0);
|
||||||
|
m_zoom->add_route(1, "rspeaker", 1.0);
|
||||||
MACHINE_CONFIG_END
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
MACHINE_CONFIG_START(zn_state::coh1002tb)
|
MACHINE_CONFIG_START(zn_state::coh1002tb)
|
||||||
@ -1228,7 +1230,9 @@ MACHINE_CONFIG_START(zn_state::coh1002tb)
|
|||||||
MCFG_SOUND_ROUTE(0, "lspeaker", 0.45)
|
MCFG_SOUND_ROUTE(0, "lspeaker", 0.45)
|
||||||
MCFG_SOUND_ROUTE(1, "rspeaker", 0.45)
|
MCFG_SOUND_ROUTE(1, "rspeaker", 0.45)
|
||||||
|
|
||||||
MCFG_TAITO_ZOOM_ADD("taito_zoom")
|
TAITO_ZOOM(config, m_zoom);
|
||||||
|
m_zoom->add_route(0, "lspeaker", 1.0);
|
||||||
|
m_zoom->add_route(1, "rspeaker", 1.0);
|
||||||
MACHINE_CONFIG_END
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user