diff options
author | 2018-03-16 15:06:46 +1100 | |
---|---|---|
committer | 2018-03-16 15:06:46 +1100 | |
commit | 084d9a4ed3f47590fa02907ab45a11fe78adf2cb (patch) | |
tree | 83ed23cca79fe428d3b846f3bd270bd750d9f28c | |
parent | 48e62db544056cdbc02849cadaedbcb6454de122 (diff) |
dsp16: implement remaining instructions for completeness
qsound_hle: use same sample rate as DSP
-rw-r--r-- | src/devices/cpu/dsp16/dsp16.cpp | 164 | ||||
-rw-r--r-- | src/devices/cpu/dsp16/dsp16.h | 2 | ||||
-rw-r--r-- | src/devices/sound/qsoundhle.cpp | 2 |
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++) |