summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2018-03-16 15:06:46 +1100
committer Vas Crabb <vas@vastheman.com>2018-03-16 15:06:46 +1100
commit084d9a4ed3f47590fa02907ab45a11fe78adf2cb (patch)
tree83ed23cca79fe428d3b846f3bd270bd750d9f28c
parent48e62db544056cdbc02849cadaedbcb6454de122 (diff)
dsp16: implement remaining instructions for completeness
qsound_hle: use same sample rate as DSP
-rw-r--r--src/devices/cpu/dsp16/dsp16.cpp164
-rw-r--r--src/devices/cpu/dsp16/dsp16.h2
-rw-r--r--src/devices/sound/qsoundhle.cpp2
3 files changed, 124 insertions, 44 deletions
diff --git a/src/devices/cpu/dsp16/dsp16.cpp b/src/devices/cpu/dsp16/dsp16.cpp
index 7beda7ab0e8..8501bafd9a0 100644
--- a/src/devices/cpu/dsp16/dsp16.cpp
+++ b/src/devices/cpu/dsp16/dsp16.cpp
@@ -64,7 +64,6 @@
the current value in the input register and initiates a read.
TODO:
- * Remaining instructions
* PSW overflow bits
* Clarify rounding behaviour (F2 1011)
* Random condition
@@ -753,6 +752,17 @@ inline void dsp16_device_base::execute_one_rom()
m_phase = phase::OP2;
break;
+ case 0x05: // F1 ; Z : aT[l]
+ {
+ fetch_target = nullptr;
+ s64 const d(dau_f1(op));
+ m_dau_temp = u16(u64(dau_saturate(op_d(~op))) >> (op_x(op) ? 16 : 0));
+ op_dau_ad(op) = d;
+ set_dau_at(op, yaau_read(op));
+ m_phase = phase::OP2;
+ }
+ break;
+
case 0x06: // F1 ; Y
op_dau_ad(op) = dau_f1(op);
yaau_read(op);
@@ -772,15 +782,10 @@ inline void dsp16_device_base::execute_one_rom()
case 0x09: // R = a0
case 0x0b: // R = a1
- {
- assert(!(op & 0x040fU)); // reserved fields?
- fetch_target = nullptr;
- s64 a(m_dau_a[BIT(op, 12)]);
- if (!BIT(m_dau_auc, 2 + BIT(op, 12)))
- a = std::min<s64>(std::max<s64>(a, std::numeric_limits<s32>::min()), std::numeric_limits<s32>::max());
- set_r(op, u16(u64(a) >> 16));
- m_phase = phase::OP2;
- }
+ assert(!(op & 0x040fU)); // reserved fields?
+ fetch_target = nullptr;
+ set_r(op, u16(u64(dau_saturate(BIT(op, 12))) >> 16));
+ m_phase = phase::OP2;
break;
case 0x0a: // R = N
@@ -795,6 +800,13 @@ inline void dsp16_device_base::execute_one_rom()
m_phase = phase::OP2;
break;
+ case 0x0d: // Z : R
+ fetch_target = nullptr;
+ m_dau_temp = get_r(op);
+ set_r(op, yaau_read(op));
+ m_phase = phase::OP2;
+ break;
+
case 0x0e: // do K { instr1...instrIN } # redo K
{
u16 const ni(op_ni(op));
@@ -915,9 +927,23 @@ inline void dsp16_device_base::execute_one_rom()
break;
case 0x1a: // if CON # icall
- // FIXME: icall is a special case of this op
- assert(!(op & 0x07e0U)); // reserved field?
+ assert(!(op & 0x03e0U)); // reserved field?
predicate = op_dau_con(op) ? FLAGS_PRED_TRUE : FLAGS_PRED_FALSE;
+ if (BIT(op, 10))
+ {
+ fetch_target = nullptr;
+ assert(0x000eU == op_con(op)); // CON must be true for icall?
+ m_phase = phase::OP2;
+ }
+ break;
+
+ case 0x1d: // F1 ; Z : y ; x = *pt++[i]
+ op_dau_ad(op) = dau_f1(op);
+ m_dau_temp = s16(m_dau_y >> 16);
+ m_dau_y = (u32(u16(yaau_read(op))) << 16) | u32(BIT(m_dau_psw, 6) ? u16(u32(m_dau_y)) : u16(0));
+ fetch_target = nullptr;
+ m_rom_data = m_spaces[AS_PROGRAM]->read_word(m_xaau_pt);
+ m_phase = phase::OP2;
break;
case 0x1e: // Reserved
@@ -960,14 +986,14 @@ inline void dsp16_device_base::execute_one_rom()
{
case 0x04: // F1 ; Y = a1[l]
case 0x1c: // F1 ; Y = a0[l]
- {
- s64 a(m_dau_a[BIT(~op, 14)]);
- bool const sat(!BIT(m_dau_auc, 2 + BIT(~op, 14)));
- if (sat)
- a = std::min<s64>(std::max<s64>(a, std::numeric_limits<s32>::min()), std::numeric_limits<s32>::max());
- yaau_write(op, u16(u64(a) >> (op_x(op) ? 16 : 0)));
- op_dau_ad(op) = dau_f1(op);
- }
+ yaau_write(op, u16(u64(dau_saturate(BIT(~op, 14))) >> (op_x(op) ? 16 : 0)));
+ op_dau_ad(op) = dau_f1(op);
+ break;
+
+ case 0x05: // F1 ; Z : aT[l]
+ case 0x0d: // Z : R
+ case 0x15: // F1 ; Z : y[l]
+ yaau_write_z(op);
break;
case 0x08: // aT = R
@@ -991,10 +1017,6 @@ inline void dsp16_device_base::execute_one_rom()
yaau_write(op, u16(u32(m_dau_y) >> (op_x(op) ? 16 : 0)));
break;
- case 0x15: // F1 ; Z : y[l]
- yaau_write_z(op);
- break;
-
case 0x19: // F1 ; y = a0 ; x = *pt++[i]
case 0x1b: // F1 ; y = a1 ; x = *pt++[i]
case 0x1f: // F1 ; y = Y ; x = *pt++[i]
@@ -1002,6 +1024,32 @@ inline void dsp16_device_base::execute_one_rom()
m_dau_x = m_rom_data;
break;
+ case 0x1a: // icall
+ // TODO: does INT get sampled or could an external interrupt be lost here?
+ assert(BIT(op, 10));
+ assert(FLAGS_PRED_TRUE == (m_flags & FLAGS_PRED_MASK));
+ if (check_predicate())
+ {
+ LOGINT(
+ "DSP16: servicing software interrupt%s%s%s%s%s (PC = %04X)\n",
+ (pio_ibf_enable() && pio_ibf_status()) ? " IBF" : "",
+ (pio_obe_enable() && pio_obe_status()) ? " OBE" : "",
+ (pio_pids_enable() && pio_pids_status()) ? " PIDS" : "",
+ (pio_pods_enable() && pio_pods_status()) ? " PODS" : "",
+ (pio_int_enable() && pio_int_status()) ? " INT" : "",
+ m_st_pcbase);
+ set_iack(FLAGS_IACK_SET);
+ m_xaau_pc = 0x0002U;
+ m_phase = phase::PURGE;
+ }
+ break;
+
+ case 0x1d: // F1 ; Z : y ; x = *pt++[i]
+ xaau_increment_pt(op_xaau_increment(op));
+ m_dau_x = m_rom_data;
+ yaau_write_z(op);
+ break;
+
default:
throw emu_fatalerror("DSP16: op %u doesn't take two cycles to run from ROM\n", op >> 11);
}
@@ -1065,6 +1113,16 @@ inline void dsp16_device_base::execute_one_cache()
m_phase = phase::OP2;
break;
+ case 0x05: // F1 ; Z : aT[l]
+ {
+ s64 const d(dau_f1(op));
+ m_dau_temp = u16(u64(dau_saturate(op_d(~op))) >> (op_x(op) ? 16 : 0));
+ op_dau_ad(op) = d;
+ set_dau_at(op, yaau_read(op));
+ m_phase = phase::OP2;
+ }
+ break;
+
case 0x06: // F1 ; Y
op_dau_ad(op) = dau_f1(op);
yaau_read(op);
@@ -1083,14 +1141,9 @@ inline void dsp16_device_base::execute_one_cache()
case 0x09: // R = a0
case 0x0b: // R = a1
- {
- assert(!(op & 0x040fU)); // reserved fields?
- s64 a(m_dau_a[BIT(op, 12)]);
- if (!BIT(m_dau_auc, 2 + BIT(op, 12)))
- a = std::min<s64>(std::max<s64>(a, std::numeric_limits<s32>::min()), std::numeric_limits<s32>::max());
- set_r(op, u16(u64(a) >> 16));
- m_phase = phase::OP2;
- }
+ assert(!(op & 0x040fU)); // reserved fields?
+ set_r(op, u16(u64(dau_saturate(BIT(op, 12))) >> 16));
+ m_phase = phase::OP2;
break;
case 0x0c: // Y = R
@@ -1098,6 +1151,12 @@ inline void dsp16_device_base::execute_one_cache()
m_phase = phase::OP2;
break;
+ case 0x0d: // Z : R
+ m_dau_temp = get_r(op);
+ set_r(op, yaau_read(op));
+ m_phase = phase::OP2;
+ break;
+
case 0x0f: // R = Y
assert(!(op & 0x0400U)); // reserved field?
set_r(op, yaau_read(op));
@@ -1162,6 +1221,14 @@ inline void dsp16_device_base::execute_one_cache()
}
break;
+ case 0x1d: // F1 ; Z : y ; x = *pt++[i]
+ op_dau_ad(op) = dau_f1(op);
+ m_dau_temp = s16(m_dau_y >> 16);
+ m_dau_y = (u32(u16(yaau_read(op))) << 16) | u32(BIT(m_dau_psw, 6) ? u16(u32(m_dau_y)) : u16(0));
+ m_rom_data = m_direct->read_word(m_xaau_pt);
+ m_phase = phase::OP2;
+ break;
+
case 0x1f: // F1 ; y = Y ; x = *pt++[i]
op_dau_ad(op) = dau_f1(op);
m_dau_y = (u32(u16(yaau_read(op))) << 16) | u32(BIT(m_dau_psw, 6) ? u16(u32(m_dau_y)) : u16(0));
@@ -1188,13 +1255,14 @@ inline void dsp16_device_base::execute_one_cache()
{
case 0x04: // F1 ; Y = a1[l]
case 0x1c: // F1 ; Y = a0[l]
- {
- s64 a(m_dau_a[BIT(~op, 14)]);
- if (!BIT(m_dau_auc, 2 + BIT(~op, 14)))
- a = std::min<s64>(std::max<s64>(a, std::numeric_limits<s32>::min()), std::numeric_limits<s32>::max());
- yaau_write(op, u16(u64(a) >> (op_x(op) ? 16 : 0)));
- op_dau_ad(op) = dau_f1(op);
- }
+ yaau_write(op, u16(u64(dau_saturate(BIT(~op, 14))) >> (op_x(op) ? 16 : 0)));
+ op_dau_ad(op) = dau_f1(op);
+ break;
+
+ case 0x05: // F1 ; Z : aT[l]
+ case 0x0d: // Z : R
+ case 0x15: // F1 ; Z : y[l]
+ yaau_write_z(op);
break;
case 0x08: // aT = R
@@ -1213,10 +1281,6 @@ inline void dsp16_device_base::execute_one_cache()
yaau_write(op, u16(u32(m_dau_y) >> (op_x(op) ? 16 : 0)));
break;
- case 0x15: // F1 ; Z : y[l]
- yaau_write_z(op);
- break;
-
case 0x19: // F1 ; y = a0 ; x = *pt++[i]
case 0x1b: // F1 ; y = a1 ; x = *pt++[i]
case 0x1f: // F1 ; y = Y ; x = *pt++[i]
@@ -1225,6 +1289,12 @@ inline void dsp16_device_base::execute_one_cache()
m_dau_x = m_rom_data;
break;
+ case 0x1d: // F1 ; Z : y ; x = *pt++[i]
+ xaau_increment_pt(op_xaau_increment(op));
+ m_dau_x = m_rom_data;
+ yaau_write_z(op);
+ break;
+
default:
throw emu_fatalerror("DSP16: op %u doesn't take two cycles to run from cache\n", op >> 11);
}
@@ -1719,6 +1789,14 @@ inline void dsp16_device_base::set_dau_y(u16 op, s16 value)
}
}
+s64 dsp16_device_base::dau_saturate(u16 a) const
+{
+ if (dau_auc_sat(a))
+ return m_dau_a[a];
+ else
+ return std::min<s64>(std::max<s64>(m_dau_a[a], std::numeric_limits<s32>::min()), std::numeric_limits<s32>::max());
+}
+
inline void dsp16_device_base::set_dau_at(u16 op, s16 value)
{
s64 &at(op_dau_at(op));
diff --git a/src/devices/cpu/dsp16/dsp16.h b/src/devices/cpu/dsp16/dsp16.h
index 22295ceea6b..4c52eb6fd5d 100644
--- a/src/devices/cpu/dsp16/dsp16.h
+++ b/src/devices/cpu/dsp16/dsp16.h
@@ -232,12 +232,14 @@ private:
void set_r(u16 op, s16 value);
void yaau_postmodify_r(u16 op);
void set_dau_y(u16 op, s16 value);
+ s64 dau_saturate(u16 a) const;
void set_dau_at(u16 op, s16 value);
u64 set_dau_psw_flags(s64 d);
u64 get_dau_p_aligned() const;
bool op_dau_con(u16 op);
// flag accessors
+ bool dau_auc_sat(u16 a) const { return bool(BIT(m_dau_auc, 2 + a)); }
u16 dau_auc_align() const { return m_dau_auc & 0x0003U; }
bool dau_psw_lmi() const { return bool(BIT(m_dau_psw, 15)); }
bool dau_psw_leq() const { return bool(BIT(m_dau_psw, 14)); }
diff --git a/src/devices/sound/qsoundhle.cpp b/src/devices/sound/qsoundhle.cpp
index e310fb98090..c464785b581 100644
--- a/src/devices/sound/qsoundhle.cpp
+++ b/src/devices/sound/qsoundhle.cpp
@@ -106,7 +106,7 @@ void qsound_hle_device::rom_bank_updated()
void qsound_hle_device::device_start()
{
- m_stream = stream_alloc(0, 2, clock() / 15 / 166); // /166 clock divider?
+ m_stream = stream_alloc(0, 2, clock() / clock() / 2 / 1248); // DSP program uses 1248 machine cycles per iteration
// create pan table
for (int i = 0; i < 33; i++)