mirror of
https://github.com/holub/mame
synced 2025-07-03 17:08:39 +03:00
Cycle-accurate DSP16 core (disabled in QSound for performance reasons)
This commit is contained in:
parent
25652d6455
commit
0bf88bda8f
@ -261,7 +261,6 @@ if (CPUS["DSP16A"]~=null) then
|
|||||||
files {
|
files {
|
||||||
MAME_DIR .. "src/devices/cpu/dsp16/dsp16.cpp",
|
MAME_DIR .. "src/devices/cpu/dsp16/dsp16.cpp",
|
||||||
MAME_DIR .. "src/devices/cpu/dsp16/dsp16.h",
|
MAME_DIR .. "src/devices/cpu/dsp16/dsp16.h",
|
||||||
MAME_DIR .. "src/devices/cpu/dsp16/dsp16ops.hxx",
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,8 @@
|
|||||||
// license:BSD-3-Clause
|
// license:BSD-3-Clause
|
||||||
// copyright-holders:Andrew Gardner
|
// copyright-holders:Vas Crabb
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
|
|
||||||
dsp16.h
|
WE|AT&T DSP16 series emulator
|
||||||
|
|
||||||
WE|AT&T DSP16 series emulator.
|
|
||||||
|
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
@ -13,172 +11,443 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
//**************************************************************************
|
|
||||||
// TYPE DEFINITIONS
|
|
||||||
//**************************************************************************
|
|
||||||
|
|
||||||
// ======================> dsp16_device
|
#define MCFG_DSP16_EXM(exm) \
|
||||||
|
downcast<dsp16_device_base &>(*device).exm_w(exm);
|
||||||
|
|
||||||
class dsp16_device : public cpu_device
|
#define MCFG_DSP16_EXM_HIGH() \
|
||||||
|
downcast<dsp16_device_base &>(*device).exm_w(1);
|
||||||
|
|
||||||
|
#define MCFG_DSP16_EXM_LOW() \
|
||||||
|
downcast<dsp16_device_base &>(*device).exm_w(0);
|
||||||
|
|
||||||
|
#define MCFG_DSP16_IACK_CB(obj) \
|
||||||
|
downcast<dsp16_device_base &>(*device).set_iack_cb(DEVCB_##obj);
|
||||||
|
|
||||||
|
#define MCFG_DSP16_ICK_CB(obj) \
|
||||||
|
downcast<dsp16_device_base &>(*device).set_ick_cb(DEVCB_##obj);
|
||||||
|
|
||||||
|
#define MCFG_DSP16_ILD_CB(obj) \
|
||||||
|
downcast<dsp16_device_base &>(*device).set_ild_cb(DEVCB_##obj);
|
||||||
|
|
||||||
|
#define MCFG_DSP16_DO_CB(obj) \
|
||||||
|
downcast<dsp16_device_base &>(*device).set_do_cb(DEVCB_##obj);
|
||||||
|
|
||||||
|
#define MCFG_DSP16_OCK_CB(obj) \
|
||||||
|
downcast<dsp16_device_base &>(*device).set_ock_cb(DEVCB_##obj);
|
||||||
|
|
||||||
|
#define MCFG_DSP16_OLD_CB(obj) \
|
||||||
|
downcast<dsp16_device_base &>(*device).set_old_cb(DEVCB_##obj);
|
||||||
|
|
||||||
|
#define MCFG_DSP16_OSE_CB(obj) \
|
||||||
|
downcast<dsp16_device_base &>(*device).set_ose_cb(DEVCB_##obj);
|
||||||
|
|
||||||
|
#define MCFG_DSP16_PIO_R_CB(obj) \
|
||||||
|
downcast<dsp16_device_base &>(*device).set_pio_r_cb(DEVCB_##obj);
|
||||||
|
|
||||||
|
#define MCFG_DSP16_PIO_W_CB(obj) \
|
||||||
|
downcast<dsp16_device_base &>(*device).set_pio_w_cb(DEVCB_##obj);
|
||||||
|
|
||||||
|
#define MCFG_DSP16_PDB_W_CB(obj) \
|
||||||
|
downcast<dsp16_device_base &>(*device).set_pdb_w_cb(DEVCB_##obj);
|
||||||
|
|
||||||
|
#define MCFG_DSP16_PSEL_CB(obj) \
|
||||||
|
downcast<dsp16_device_base &>(*device).set_psel_cb(DEVCB_##obj);
|
||||||
|
|
||||||
|
#define MCFG_DSP16_PIDS_CB(obj) \
|
||||||
|
downcast<dsp16_device_base &>(*device).set_pids_cb(DEVCB_##obj);
|
||||||
|
|
||||||
|
#define MCFG_DSP16_PODS_CB(obj) \
|
||||||
|
downcast<dsp16_device_base &>(*device).set_pods_cb(DEVCB_##obj);
|
||||||
|
|
||||||
|
|
||||||
|
class dsp16_device_base : public cpu_device
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// construction/destruction
|
DECLARE_WRITE_LINE_MEMBER(exm_w);
|
||||||
dsp16_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
|
||||||
|
|
||||||
// public interfaces
|
// interrupt output callbacks
|
||||||
|
template <typename Obj> devcb_base *set_iack_cb(Obj &&cb) { return &m_iack_cb.set_callback(std::forward<Obj>(cb)); }
|
||||||
|
|
||||||
|
// serial output callbacks
|
||||||
|
template <typename Obj> devcb_base *set_ick_cb(Obj &&cb) { return &m_ick_cb.set_callback(std::forward<Obj>(cb)); }
|
||||||
|
template <typename Obj> devcb_base *set_ild_cb(Obj &&cb) { return &m_ild_cb.set_callback(std::forward<Obj>(cb)); }
|
||||||
|
template <typename Obj> devcb_base *set_do_cb(Obj &&cb) { return &m_do_cb.set_callback(std::forward<Obj>(cb)); }
|
||||||
|
template <typename Obj> devcb_base *set_ock_cb(Obj &&cb) { return &m_ock_cb.set_callback(std::forward<Obj>(cb)); }
|
||||||
|
template <typename Obj> devcb_base *set_old_cb(Obj &&cb) { return &m_old_cb.set_callback(std::forward<Obj>(cb)); }
|
||||||
|
template <typename Obj> devcb_base *set_ose_cb(Obj &&cb) { return &m_ose_cb.set_callback(std::forward<Obj>(cb)); }
|
||||||
|
|
||||||
|
// high-level active parallel I/O callbacks
|
||||||
|
template <typename Obj> devcb_base *set_pio_r_cb(Obj &&cb) { return &m_pio_r_cb.set_callback(std::forward<Obj>(cb)); }
|
||||||
|
template <typename Obj> devcb_base *set_pio_w_cb(Obj &&cb) { return &m_pio_w_cb.set_callback(std::forward<Obj>(cb)); }
|
||||||
|
|
||||||
|
// low-level parallel I/O callbacks
|
||||||
|
template <typename Obj> devcb_base *set_pdb_w_cb(Obj &&cb) { return &m_pdb_w_cb.set_callback(std::forward<Obj>(cb)); }
|
||||||
|
template <typename Obj> devcb_base *set_psel_cb(Obj &&cb) { return &m_psel_cb.set_callback(std::forward<Obj>(cb)); }
|
||||||
|
template <typename Obj> devcb_base *set_pids_cb(Obj &&cb) { return &m_pids_cb.set_callback(std::forward<Obj>(cb)); }
|
||||||
|
template <typename Obj> devcb_base *set_pods_cb(Obj &&cb) { return &m_pods_cb.set_callback(std::forward<Obj>(cb)); }
|
||||||
|
|
||||||
|
// interrupt outputs
|
||||||
|
DECLARE_READ_LINE_MEMBER(iack_r) { return m_iack_out; }
|
||||||
|
|
||||||
|
// serial outputs
|
||||||
|
DECLARE_READ_LINE_MEMBER(ick_r) { return sio_ick_active() ? m_sio_clk : 1; }
|
||||||
|
DECLARE_READ_LINE_MEMBER(ild_r) { return sio_ild_active() ? m_sio_ld : 1; }
|
||||||
|
DECLARE_READ_LINE_MEMBER(do_r) { return m_do_out; }
|
||||||
|
DECLARE_READ_LINE_MEMBER(ock_r) { return sio_ock_active() ? m_sio_clk : 1; }
|
||||||
|
DECLARE_READ_LINE_MEMBER(old_r) { return sio_old_active() ? m_sio_ld : 1; }
|
||||||
|
DECLARE_READ_LINE_MEMBER(ose_r) { return m_ose_out; }
|
||||||
|
|
||||||
|
// high-level passive parallel I/O handlers
|
||||||
|
DECLARE_READ16_MEMBER(pio_r);
|
||||||
|
DECLARE_WRITE16_MEMBER(pio_w);
|
||||||
|
|
||||||
|
// parallel I/O outputs
|
||||||
|
DECLARE_READ_LINE_MEMBER(psel_r) { return m_psel_out; }
|
||||||
|
DECLARE_READ_LINE_MEMBER(pids_r) { return m_pids_out; }
|
||||||
|
DECLARE_READ_LINE_MEMBER(pods_r) { return m_pods_out; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum
|
// construction/destruction
|
||||||
{
|
dsp16_device_base(
|
||||||
DSP16_I, // ROM Address Arithmetic Unit (XAAU)
|
machine_config const &mconfig,
|
||||||
DSP16_PC,
|
device_type type,
|
||||||
DSP16_PT,
|
char const *tag,
|
||||||
DSP16_PR,
|
device_t *owner,
|
||||||
DSP16_PI,
|
u32 clock,
|
||||||
DSP16_J, // RAM Address Arithmetic Unit (YAAU)
|
u8 yaau_bits,
|
||||||
DSP16_K,
|
address_map_constructor &&data_map);
|
||||||
DSP16_RB,
|
|
||||||
DSP16_RE,
|
|
||||||
DSP16_R0,
|
|
||||||
DSP16_R1,
|
|
||||||
DSP16_R2,
|
|
||||||
DSP16_R3,
|
|
||||||
DSP16_X, // Data Arithmetic Unit (DAU)
|
|
||||||
DSP16_Y,
|
|
||||||
DSP16_P,
|
|
||||||
DSP16_A0,
|
|
||||||
DSP16_A1,
|
|
||||||
DSP16_AUC,
|
|
||||||
DSP16_PSW,
|
|
||||||
DSP16_C0,
|
|
||||||
DSP16_C1,
|
|
||||||
DSP16_C2,
|
|
||||||
DSP16_SIOC,
|
|
||||||
DSP16_SRTA,
|
|
||||||
DSP16_SDX,
|
|
||||||
DSP16_PIOC,
|
|
||||||
DSP16_PDX0,
|
|
||||||
DSP16_PDX1
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// device_t implementation
|
||||||
// device-level overrides
|
virtual void device_resolve_objects() override;
|
||||||
virtual void device_start() override;
|
virtual void device_start() override;
|
||||||
virtual void device_reset() override;
|
virtual void device_reset() override;
|
||||||
|
|
||||||
// device_execute_interface overrides
|
// device_execute_interface implementation
|
||||||
virtual uint64_t execute_clocks_to_cycles(uint64_t clocks) const override { return (clocks + 2 - 1) / 2; } // internal /2 divider
|
virtual u64 execute_clocks_to_cycles(u64 clocks) const override { return (clocks + 2 - 1) >> 1; }
|
||||||
virtual uint64_t execute_cycles_to_clocks(uint64_t cycles) const override { return (cycles * 2); } // internal /2 divider
|
virtual u64 execute_cycles_to_clocks(u64 cycles) const override { return cycles << 1; }
|
||||||
virtual uint32_t execute_min_cycles() const override;
|
virtual u32 execute_input_lines() const override { return 5U; }
|
||||||
virtual uint32_t execute_max_cycles() const override;
|
|
||||||
virtual uint32_t execute_input_lines() const override;
|
|
||||||
virtual void execute_run() override;
|
virtual void execute_run() override;
|
||||||
virtual void execute_set_input(int inputnum, int state) override;
|
virtual void execute_set_input(int inputnum, int state) override;
|
||||||
|
|
||||||
// device_memory_interface overrides
|
// device_memory_interface implementation
|
||||||
virtual space_config_vector memory_space_config() const override;
|
virtual space_config_vector memory_space_config() const override;
|
||||||
|
|
||||||
// device_state_interface overrides
|
// device_state_interface implementation
|
||||||
virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
|
virtual void state_import(device_state_entry const &entry) override;
|
||||||
|
virtual void state_export(device_state_entry const &entry) override;
|
||||||
|
|
||||||
// device_disasm_interface overrides
|
// device_disasm_interface implementation
|
||||||
virtual util::disasm_interface *create_disassembler() override;
|
virtual util::disasm_interface *create_disassembler() override;
|
||||||
|
|
||||||
// address spaces
|
// for specialisations to override
|
||||||
const address_space_config m_program_config;
|
virtual void external_memory_enable(address_space &space, bool enable) = 0;
|
||||||
const address_space_config m_data_config;
|
|
||||||
|
|
||||||
// CPU registers
|
template <offs_t Base> DECLARE_READ16_MEMBER(external_memory_r);
|
||||||
// ROM Address Arithmetic Unit (XAAU) (page 2-4)
|
|
||||||
uint16_t m_i; // 12 bits
|
|
||||||
uint16_t m_pc;
|
|
||||||
uint16_t m_pt;
|
|
||||||
uint16_t m_pr;
|
|
||||||
uint16_t m_pi;
|
|
||||||
|
|
||||||
// RAM Address Arithmetic Unit (YAAU) (page 2-6)
|
private:
|
||||||
uint16_t m_j; // Signed
|
// state registration indices
|
||||||
uint16_t m_k; // Signed
|
enum
|
||||||
uint16_t m_rb;
|
{
|
||||||
uint16_t m_re;
|
DSP16_PT = 1, DSP16_PR, DSP16_PI, DSP16_I,
|
||||||
uint16_t m_r0;
|
DSP16_R0, DSP16_R1, DSP16_R2, DSP16_R3, DSP16_RB, DSP16_RE, DSP16_J, DSP16_K,
|
||||||
uint16_t m_r1;
|
DSP16_X, DSP16_Y, DSP16_P, DSP16_A0, DSP16_A1, DSP16_C0, DSP16_C1, DSP16_C2, DSP16_AUC, DSP16_PSW,
|
||||||
uint16_t m_r2;
|
DSP16_YH, DSP16_A0H, DSP16_A1H, DSP16_YL, DSP16_A0L, DSP16_A1L
|
||||||
uint16_t m_r3;
|
};
|
||||||
|
|
||||||
// Data Arithmetic Unit (DAU) (page 2-6)
|
// masks for registers that aren't power-of-two sizes
|
||||||
uint16_t m_x;
|
enum : s16
|
||||||
uint32_t m_y;
|
{
|
||||||
uint32_t m_p;
|
XAAU_I_SIGN = s16(1) << (12 - 1),
|
||||||
uint64_t m_a0; // 36 bits
|
XAAU_I_MASK = (s16(1) << 12) - 1,
|
||||||
uint64_t m_a1; // 36 bits
|
XAAU_I_EXT = ~XAAU_I_MASK
|
||||||
uint8_t m_auc; // 6 bits
|
};
|
||||||
uint16_t m_psw;
|
enum : s64
|
||||||
uint8_t m_c0;
|
{
|
||||||
uint8_t m_c1;
|
DAU_A_SIGN = s64(1) << (36 - 1),
|
||||||
uint8_t m_c2;
|
DAU_A_MASK = (s64(1) << 36) - 1,
|
||||||
|
DAU_A_EXT = ~DAU_A_MASK
|
||||||
|
};
|
||||||
|
|
||||||
// Serial and parallel interfaces (TODO: More here (page 2-13))
|
// execution state
|
||||||
uint16_t m_sioc;
|
enum class cache : u8 { NONE, LOAD, EXECUTE };
|
||||||
uint16_t m_srta;
|
enum class phase : u8 { PURGE, OP1, OP2, PREFETCH };
|
||||||
uint16_t m_sdx;
|
enum flags : u8
|
||||||
uint16_t m_pioc;
|
{
|
||||||
uint16_t m_pdx0; // pdx0 & pdx1 refer to the same physical register (page 6-1)
|
FLAGS_PRED_NONE = 0x00U,
|
||||||
uint16_t m_pdx1; // but we keep them separate for logic's sake.
|
FLAGS_PRED_TRUE = 0x01U,
|
||||||
|
FLAGS_PRED_FALSE = 0x02U,
|
||||||
|
FLAGS_PRED_MASK = 0x03U,
|
||||||
|
|
||||||
// internal stuff
|
FLAGS_IACK_NONE = 0x00U,
|
||||||
uint16_t m_ppc;
|
FLAGS_IACK_SET = 0x04U,
|
||||||
|
FLAGS_IACK_CLEAR = 0x08U,
|
||||||
|
FLAGS_IACK_MASK = 0x0cU,
|
||||||
|
|
||||||
// This CPU core handles the cache as more of a loop than 15 separate memory elements.
|
FLAGS_NONE = FLAGS_PRED_NONE | FLAGS_IACK_NONE
|
||||||
// It's a bit of a hack, but it's easier this way (for now).
|
};
|
||||||
uint16_t m_cacheStart;
|
friend constexpr flags operator~(flags);
|
||||||
uint16_t m_cacheEnd;
|
friend constexpr flags operator&(flags, flags);
|
||||||
uint16_t m_cacheRedoNextPC;
|
friend constexpr flags operator|(flags, flags);
|
||||||
uint16_t m_cacheIterations;
|
friend flags &operator&=(flags &, flags);
|
||||||
static const uint16_t CACHE_INVALID = 0xffff;
|
friend flags &operator|=(flags &, flags);
|
||||||
|
|
||||||
// memory access
|
// serial I/O state
|
||||||
inline uint32_t data_read(const uint16_t& addr);
|
enum sio_flags : u8
|
||||||
inline void data_write(const uint16_t& addr, const uint16_t& data);
|
{
|
||||||
inline uint32_t opcode_read(const uint8_t pcOffset=0);
|
SIO_FLAGS_NONE = 0x00U,
|
||||||
|
SIO_FLAGS_ILD = 0x01U,
|
||||||
|
SIO_FLAGS_OLD = 0x02U
|
||||||
|
};
|
||||||
|
friend constexpr sio_flags operator~(sio_flags);
|
||||||
|
friend constexpr sio_flags operator&(sio_flags, sio_flags);
|
||||||
|
friend constexpr sio_flags operator|(sio_flags, sio_flags);
|
||||||
|
friend sio_flags &operator&=(sio_flags &, sio_flags);
|
||||||
|
friend sio_flags &operator|=(sio_flags &, sio_flags);
|
||||||
|
|
||||||
// address spaces
|
// internal address maps
|
||||||
address_space* m_program;
|
void program_map(address_map &map);
|
||||||
address_space* m_data;
|
|
||||||
|
// instruction execution
|
||||||
|
void execute_one_rom();
|
||||||
|
void execute_one_cache();
|
||||||
|
void overlap_rom_data_read();
|
||||||
|
void yaau_short_immediate_load(u16 op);
|
||||||
|
s16 yaau_read(u16 op);
|
||||||
|
void yaau_write(u16 op, s16 value);
|
||||||
|
void yaau_write_z(u16 op);
|
||||||
|
u64 dau_f1(u16 op);
|
||||||
|
u64 dau_f2(u16 op);
|
||||||
|
|
||||||
|
// inline helpers
|
||||||
|
static bool op_interruptible(u16 op);
|
||||||
|
bool check_predicate();
|
||||||
|
flags &set_predicate(flags predicate) { return m_flags = (m_flags & ~FLAGS_PRED_MASK) | (predicate & FLAGS_PRED_MASK); }
|
||||||
|
flags &set_iack(flags iack) { return m_flags = (m_flags & ~FLAGS_IACK_MASK) | (iack & FLAGS_IACK_MASK); }
|
||||||
|
u16 &set_xaau_pc_offset(u16 offset);
|
||||||
|
void xaau_increment_pt(s16 increment) { m_xaau_pt = (m_xaau_pt & XAAU_I_EXT) | ((m_xaau_pt + increment) & XAAU_I_MASK); }
|
||||||
|
s16 get_r(u16 op);
|
||||||
|
void set_r(u16 op, s16 value);
|
||||||
|
void yaau_postmodify_r(u16 op);
|
||||||
|
void set_dau_y(u16 op, s16 value);
|
||||||
|
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
|
||||||
|
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)); }
|
||||||
|
bool dau_psw_llv() const { return bool(BIT(m_dau_psw, 13)); }
|
||||||
|
bool dau_psw_lmv() const { return bool(BIT(m_dau_psw, 12)); }
|
||||||
|
|
||||||
|
// opcode field handling
|
||||||
|
static constexpr u16 op_ja(u16 op) { return op & 0x0fffU; }
|
||||||
|
static constexpr u16 op_b(u16 op) { return (op >> 8) & 0x0007U; }
|
||||||
|
static constexpr u16 op_d(u16 op) { return BIT(op, 10); }
|
||||||
|
static constexpr u16 op_s(u16 op) { return BIT(op, 9); }
|
||||||
|
static constexpr u16 op_f1(u16 op) { return (op >> 5) & 0x000fU; }
|
||||||
|
static constexpr u16 op_f2(u16 op) { return (op >> 5) & 0x000fU; }
|
||||||
|
static constexpr u16 op_r(u16 op) { return (op >> 4) & 0x003fU; }
|
||||||
|
static constexpr u16 op_x(u16 op) { return BIT(op, 4); }
|
||||||
|
static constexpr u16 op_con(u16 op) { return op & 0x001fU; }
|
||||||
|
static constexpr u16 op_ni(u16 op) { return (op >> 7) & 0x000fU; }
|
||||||
|
static constexpr u16 op_k(u16 op) { return op & 0x007fU; }
|
||||||
|
s16 op_xaau_increment(u16 op) const { return op_x(op) ? m_xaau_i : 1; }
|
||||||
|
u16 &op_yaau_r(u16 op) { return m_yaau_r[(op >> 2) & 0x0003U]; }
|
||||||
|
s64 &op_dau_as(u16 op) { return m_dau_a[op_s(op)]; }
|
||||||
|
s64 &op_dau_ad(u16 op) { return m_dau_a[op_d(op)]; }
|
||||||
|
s64 &op_dau_at(u16 op) { return m_dau_a[op_d(~op)]; }
|
||||||
|
|
||||||
|
// serial I/O
|
||||||
|
bool sio_ld_ick() const { return !BIT(m_sio_sioc, 9); }
|
||||||
|
bool sio_ld_ock() const { return bool(BIT(m_sio_sioc, 9)); }
|
||||||
|
bool sio_lsb_first() const { return !BIT(m_sio_sioc, 6); }
|
||||||
|
bool sio_msb_first() const { return bool(BIT(m_sio_sioc, 6)); }
|
||||||
|
bool sio_old_active() const { return bool(BIT(m_sio_sioc, 5)); }
|
||||||
|
bool sio_ild_active() const { return bool(BIT(m_sio_sioc, 4)); }
|
||||||
|
bool sio_ock_active() const { return bool(BIT(m_sio_sioc, 3)); }
|
||||||
|
bool sio_ick_active() const { return bool(BIT(m_sio_sioc, 2)); }
|
||||||
|
unsigned sio_olen() const { return BIT(m_sio_sioc, 1) ? 8U : 16U; }
|
||||||
|
unsigned sio_ilen() const { return BIT(m_sio_sioc, 0) ? 8U : 16U; }
|
||||||
|
void sio_sioc_write(u16 value);
|
||||||
|
void sio_ick_active_edge();
|
||||||
|
void sio_ock_active_edge();
|
||||||
|
void sio_step_ld_div();
|
||||||
|
|
||||||
|
// parallel I/O
|
||||||
|
u16 pio_strobe() const { return ((m_pio_pioc >> 13) & 0x0003U) + 1; }
|
||||||
|
bool pio_pods_active() const { return bool(BIT(m_pio_pioc, 12)); }
|
||||||
|
bool pio_pids_active() const { return bool(BIT(m_pio_pioc, 11)); }
|
||||||
|
bool pio_sc_mode() const { return bool(BIT(m_pio_pioc, 10)); }
|
||||||
|
bool pio_ibf_enable() const { return bool(BIT(m_pio_pioc, 9)); }
|
||||||
|
bool pio_obe_enable() const { return bool(BIT(m_pio_pioc, 8)); }
|
||||||
|
bool pio_pids_enable() const { return bool(BIT(m_pio_pioc, 7)); }
|
||||||
|
bool pio_pods_enable() const { return bool(BIT(m_pio_pioc, 6)); }
|
||||||
|
bool pio_int_enable() const { return bool(BIT(m_pio_pioc, 5)); }
|
||||||
|
bool pio_ibf_status() const { return bool(BIT(m_pio_pioc, 4)); }
|
||||||
|
bool pio_obe_status() const { return bool(BIT(m_pio_pioc, 3)); }
|
||||||
|
bool pio_pids_status() const { return bool(BIT(m_pio_pioc, 2)); }
|
||||||
|
bool pio_pods_status() const { return bool(BIT(m_pio_pioc, 1)); }
|
||||||
|
bool pio_int_status() const { return bool(BIT(m_pio_pioc, 0)); }
|
||||||
|
void pio_pioc_write(u16 value);
|
||||||
|
u16 pio_pdx_read(u16 sel);
|
||||||
|
void pio_pdx_write(u16 sel, u16 value);
|
||||||
|
|
||||||
|
// interrupt callbacks
|
||||||
|
devcb_write_line m_iack_cb;
|
||||||
|
|
||||||
|
// serial output callbacks
|
||||||
|
devcb_write_line m_ick_cb, m_ild_cb;
|
||||||
|
devcb_write_line m_do_cb, m_ock_cb, m_old_cb, m_ose_cb;
|
||||||
|
|
||||||
|
// parallel I/O callbacks
|
||||||
|
devcb_read16 m_pio_r_cb;
|
||||||
|
devcb_write16 m_pio_w_cb;
|
||||||
|
devcb_write16 m_pdb_w_cb;
|
||||||
|
devcb_write_line m_psel_cb, m_pids_cb, m_pods_cb;
|
||||||
|
|
||||||
|
// configuration
|
||||||
|
address_space_config const m_space_config[3];
|
||||||
|
u16 const m_yaau_mask;
|
||||||
|
u16 const m_yaau_sign;
|
||||||
|
|
||||||
|
// memory system access
|
||||||
|
address_space *m_spaces[3];
|
||||||
direct_read_data<-1> *m_direct;
|
direct_read_data<-1> *m_direct;
|
||||||
|
|
||||||
// other internal states
|
// execution state
|
||||||
int m_icount;
|
int m_icount;
|
||||||
|
cache m_cache_mode;
|
||||||
|
phase m_phase;
|
||||||
|
u8 m_int_enable[2];
|
||||||
|
flags m_flags;
|
||||||
|
u8 m_cache_ptr, m_cache_limit, m_cache_iterations;
|
||||||
|
u16 m_cache[16];
|
||||||
|
u16 m_rom_data;
|
||||||
|
|
||||||
// operations
|
// line states
|
||||||
void execute_one(const uint16_t& op, uint8_t& cycles, uint8_t& pcAdvance);
|
u8 m_exm_in; // internal ROM disabled when low
|
||||||
|
u8 m_int_in; // external interrupt request
|
||||||
|
u8 m_iack_out; // asserted (low) while servicing interrupt
|
||||||
|
|
||||||
// table decoders
|
// serial I/O line states
|
||||||
void* registerFromRImmediateField(const uint8_t& R);
|
u8 m_ick_in; // data input clock - sampled on rising edge
|
||||||
void* registerFromRTable(const uint8_t& R);
|
u8 m_ild_in; // data input clock - sampled on rising edge
|
||||||
uint16_t* registerFromYFieldUpper(const uint8_t& Y);
|
u8 m_do_out; // serial data output - changes on rising edges of OCK
|
||||||
|
u8 m_ock_in; // data output clock - output changes on rising edge
|
||||||
|
u8 m_old_in; // falling edge indicates beginning of output word
|
||||||
|
u8 m_ose_out; // indicates the end of a serial transmission
|
||||||
|
|
||||||
// execution
|
// parallel I/O line states
|
||||||
void executeF1Field(const uint8_t& F1, const uint8_t& D, const uint8_t& S);
|
u8 m_psel_out; // last accessed parallel I/O data register
|
||||||
void executeYFieldPost(const uint8_t& Y);
|
u8 m_pids_out; // parallel input data strobe (sampled on rising edge)
|
||||||
void executeZFieldPartOne(const uint8_t& Z, uint16_t* rN);
|
u8 m_pods_out; // parallel output data strobe
|
||||||
void executeZFieldPartTwo(const uint8_t& Z, uint16_t* rN);
|
|
||||||
|
|
||||||
// helpers
|
// XAAU - ROM Address Arithmetic Unit
|
||||||
void* addressYL();
|
u16 m_xaau_pc; // 16 bits unsigned
|
||||||
void writeRegister(void* reg, const uint16_t& value);
|
u16 m_xaau_pt; // 16 bits unsigned
|
||||||
bool conditionTest(const uint8_t& CON);
|
u16 m_xaau_pr; // 16 bits unsigned
|
||||||
|
u16 m_xaau_pi; // 16 bits unsigned
|
||||||
|
s16 m_xaau_i; // 12 bits signed
|
||||||
|
|
||||||
// flags
|
// YAAU - RAM Address Arithmetic Unit
|
||||||
bool lmi();
|
u16 m_yaau_r[4]; // 9/16 bits unsigned
|
||||||
bool leq();
|
u16 m_yaau_rb; // 9/16 bits unsigned
|
||||||
bool llv();
|
u16 m_yaau_re; // 9/16 bits unsigned
|
||||||
bool lmv();
|
s16 m_yaau_j; // 9/16 bits signed
|
||||||
|
s16 m_yaau_k; // 9/16 bits signed
|
||||||
|
|
||||||
|
// DAU - Data Arithmetic Unit
|
||||||
|
s16 m_dau_x; // 16 bits signed
|
||||||
|
s32 m_dau_y; // 32 bits signed
|
||||||
|
s32 m_dau_p; // 32 bits signed
|
||||||
|
s64 m_dau_a[2]; // 36 bits signed
|
||||||
|
s8 m_dau_c[3]; // 8 bits signed
|
||||||
|
u8 m_dau_auc; // 7 bits unsigned
|
||||||
|
u16 m_dau_psw; // 16 bits
|
||||||
|
s16 m_dau_temp; // 16 bits
|
||||||
|
|
||||||
|
// SIO - Serial I/O
|
||||||
|
u16 m_sio_sioc; // 10 bits
|
||||||
|
u16 m_sio_obuf; // 16 bits
|
||||||
|
u16 m_sio_osr; // 16 bits
|
||||||
|
u16 m_sio_ofsr; // 16 bits
|
||||||
|
u8 m_sio_clk;
|
||||||
|
u8 m_sio_clk_div;
|
||||||
|
u8 m_sio_ld;
|
||||||
|
u8 m_sio_ld_div;
|
||||||
|
sio_flags m_sio_flags;
|
||||||
|
|
||||||
|
// PIO - Parallel I/O
|
||||||
|
u16 m_pio_pioc; // 16 bits
|
||||||
|
u16 m_pio_pdx_in; // 16 bits
|
||||||
|
u16 m_pio_pdx_out; // 16 bits
|
||||||
|
u8 m_pio_pids_cnt;
|
||||||
|
u8 m_pio_pods_cnt;
|
||||||
|
|
||||||
|
// fake registers for the debugger
|
||||||
|
u16 m_cache_pcbase;
|
||||||
|
u16 m_st_pcbase;
|
||||||
|
s16 m_st_yh, m_st_ah[2];
|
||||||
|
u16 m_st_yl, m_st_al[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// device type definition
|
class dsp16_device : public dsp16_device_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// construction/destruction
|
||||||
|
dsp16_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// dsp16_device_base implementation
|
||||||
|
virtual void external_memory_enable(address_space &space, bool enable) override;
|
||||||
|
|
||||||
|
// internal address maps
|
||||||
|
void data_map(address_map &map);
|
||||||
|
|
||||||
|
private:
|
||||||
|
required_region_ptr<u16> m_rom;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class dsp16a_device : public dsp16_device_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// construction/destruction
|
||||||
|
dsp16a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// dsp16_device_base implementation
|
||||||
|
virtual void external_memory_enable(address_space &space, bool enable) override;
|
||||||
|
|
||||||
|
// internal address maps
|
||||||
|
void data_map(address_map &map);
|
||||||
|
|
||||||
|
private:
|
||||||
|
required_region_ptr<u16> m_rom;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
DSP16_INT_LINE = INPUT_LINE_IRQ0,
|
||||||
|
DSP16_ICK_LINE,
|
||||||
|
DSP16_ILD_LINE,
|
||||||
|
DSP16_OCK_LINE,
|
||||||
|
DSP16_OLD_LINE
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
DECLARE_ENUM_BITWISE_OPERATORS(dsp16_device_base::flags)
|
||||||
|
DECLARE_ENUM_BITWISE_OPERATORS(dsp16_device_base::sio_flags)
|
||||||
|
|
||||||
|
|
||||||
DECLARE_DEVICE_TYPE(DSP16, dsp16_device)
|
DECLARE_DEVICE_TYPE(DSP16, dsp16_device)
|
||||||
|
DECLARE_DEVICE_TYPE(DSP16A, dsp16a_device)
|
||||||
|
|
||||||
#endif // MAME_CPU_DSP16_DSP16_H
|
#endif // MAME_CPU_DSP16_DSP16_H
|
||||||
|
@ -1,937 +0,0 @@
|
|||||||
// license:BSD-3-Clause
|
|
||||||
// copyright-holders:Andrew Gardner
|
|
||||||
#include "dsp16.h"
|
|
||||||
|
|
||||||
#define DSP_LINE(__DSP_DOCLINE__) printf("0x%04x - %d (%s)\n", m_pc, __LINE__, __DSP_DOCLINE__);
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// * AUC has a CLR field for writing to A0 & A1 + sign extension + psw + zero lower bits
|
|
||||||
// implement as a clean function (page 2-7)
|
|
||||||
// * Implement saturation overflow (SAT on AUC) (page 2-8)
|
|
||||||
// * Implement p alignment (ALIGN on AUC) (page 2-9)
|
|
||||||
// * When a register is used as a memory pointer. its value is compared with re. If its value is
|
|
||||||
// equal to the contents of re and the postincrement is +1, then the value in rb is copied into
|
|
||||||
// the register after the memory access is complete. See Section 4.2.3.
|
|
||||||
// * CPU flags go to the PSW & conditionTest() works on that (Page 3-4)
|
|
||||||
// * Some instructions are not interruptible.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
// NOTES:
|
|
||||||
// When y is used in an assembly-language instruction, the DSPI6/DSPI6A device will read
|
|
||||||
// or write the high half (bits 16-31) of the y register (page 2-7)
|
|
||||||
|
|
||||||
// The YL register is the lower half of the 32 bit Y register
|
|
||||||
void* dsp16_device::addressYL()
|
|
||||||
{
|
|
||||||
return (void*)(((uint8_t*)&m_y) + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Flag getters
|
|
||||||
bool dsp16_device::lmi()
|
|
||||||
{
|
|
||||||
return m_psw & 0x8000;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dsp16_device::leq()
|
|
||||||
{
|
|
||||||
return m_psw & 0x4000;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dsp16_device::llv()
|
|
||||||
{
|
|
||||||
return m_psw & 0x2000;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dsp16_device::lmv()
|
|
||||||
{
|
|
||||||
return m_psw & 0x1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void dsp16_device::writeRegister(void* reg, const uint16_t &value)
|
|
||||||
{
|
|
||||||
// Make sure you're not attempting to write somewhere this function doesn't support.
|
|
||||||
if (reg == &m_p || reg == &m_a0 || reg == &m_a1)
|
|
||||||
{
|
|
||||||
logerror("dsp16::writeRegister called on invalid register at PC 0x%04x.\n", m_pc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reg == &m_auc || reg == &m_c0 || reg == &m_c1 || reg == &m_c2)
|
|
||||||
{
|
|
||||||
// 8 bit registers
|
|
||||||
*(uint8_t*)reg = value & 0x00ff;
|
|
||||||
}
|
|
||||||
else if (reg == &m_psw)
|
|
||||||
{
|
|
||||||
// Writes to the a0 & a1 guard bits too
|
|
||||||
m_a0 &= 0x0ffffffffU;
|
|
||||||
m_a0 |= u64(m_psw & 0x000fU) << 32;
|
|
||||||
m_a1 &= 0x0ffffffffU;
|
|
||||||
m_a1 |= u64(m_psw & 0x01e0U) << 27;
|
|
||||||
m_psw = value;
|
|
||||||
}
|
|
||||||
else if (reg == &m_i)
|
|
||||||
{
|
|
||||||
// 12 bit register
|
|
||||||
m_i = value & 0x0fff;
|
|
||||||
}
|
|
||||||
else if (reg == &m_y)
|
|
||||||
{
|
|
||||||
// Y register
|
|
||||||
// TODO - Automatic clearing of yl may be selected (according to the CLR field of the auc register) (page 2-7)
|
|
||||||
m_y = (value << 16) | (m_y & 0x0000ffff);
|
|
||||||
}
|
|
||||||
else if (reg == addressYL())
|
|
||||||
{
|
|
||||||
// Yl register (Writes to yl do not change the data in the high half of y)
|
|
||||||
m_y = value | (m_y & 0xffff0000);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Everything else
|
|
||||||
*(uint16_t*)reg = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool dsp16_device::conditionTest(const uint8_t& CON)
|
|
||||||
{
|
|
||||||
switch (CON)
|
|
||||||
{
|
|
||||||
case 0x00: return lmi(); // mi (negative result)
|
|
||||||
case 0x01: return !lmi(); // pl (positive result)
|
|
||||||
case 0x02: return leq(); // eq (result == 0)
|
|
||||||
case 0x03: return !leq(); // ne (result != 0)
|
|
||||||
case 0x04: return llv(); // lvs (logical overflow set)
|
|
||||||
case 0x05: return !llv(); // lvc (logical overflow clear)
|
|
||||||
case 0x06: return lmv(); // mvs (math. overflow set)
|
|
||||||
case 0x07: return !lmv(); // mvc (math. overflow clear)
|
|
||||||
case 0x08: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // heads (random bit set)
|
|
||||||
case 0x09: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // tails (random bit clear)
|
|
||||||
case 0x0a: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // c0ge (counter0 >= 0)*
|
|
||||||
case 0x0b: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // c0lt (counter0 < 0)*
|
|
||||||
case 0x0c: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // c1ge (counter1 >= 0)*
|
|
||||||
case 0x0d: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // c1lt (counter1 < 0)*
|
|
||||||
case 0x0e: return true; // true (always)
|
|
||||||
case 0x0f: return false; // false (never)
|
|
||||||
case 0x10: return (!lmi() && !leq()); // gt (result > 0)
|
|
||||||
case 0x11: return (lmi() || leq()); // le (result <= 0)
|
|
||||||
default: logerror("Unrecognized condition at PC=0x%04x\n", m_pc); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Testing each of these conditions (*) increments the respective counter being tested (page 3-5)
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void* dsp16_device::registerFromRImmediateField(const uint8_t& R)
|
|
||||||
{
|
|
||||||
switch (R)
|
|
||||||
{
|
|
||||||
case 0x00: return (void*)&m_j;
|
|
||||||
case 0x01: return (void*)&m_k;
|
|
||||||
case 0x02: return (void*)&m_rb;
|
|
||||||
case 0x03: return (void*)&m_re;
|
|
||||||
case 0x04: return (void*)&m_r0;
|
|
||||||
case 0x05: return (void*)&m_r1;
|
|
||||||
case 0x06: return (void*)&m_r2;
|
|
||||||
case 0x07: return (void*)&m_r3;
|
|
||||||
|
|
||||||
default: return nullptr;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void* dsp16_device::registerFromRTable(const uint8_t &R)
|
|
||||||
{
|
|
||||||
switch (R)
|
|
||||||
{
|
|
||||||
case 0x00: return (void*)&m_r0;
|
|
||||||
case 0x01: return (void*)&m_r1;
|
|
||||||
case 0x02: return (void*)&m_r2;
|
|
||||||
case 0x03: return (void*)&m_r3;
|
|
||||||
case 0x04: return (void*)&m_j;
|
|
||||||
case 0x05: return (void*)&m_k;
|
|
||||||
case 0x06: return (void*)&m_rb;
|
|
||||||
case 0x07: return (void*)&m_re;
|
|
||||||
case 0x08: return (void*)&m_pt;
|
|
||||||
case 0x09: return (void*)&m_pr;
|
|
||||||
case 0x0a: return (void*)&m_pi;
|
|
||||||
case 0x0b: return (void*)&m_i;
|
|
||||||
|
|
||||||
case 0x10: return (void*)&m_x;
|
|
||||||
case 0x11: return (void*)&m_y;
|
|
||||||
case 0x12: return (void*)addressYL();
|
|
||||||
case 0x13: return (void*)&m_auc; // zero extended
|
|
||||||
case 0x14: return (void*)&m_psw;
|
|
||||||
case 0x15: return (void*)&m_c0; // sign extended
|
|
||||||
case 0x16: return (void*)&m_c1; // sign extended
|
|
||||||
case 0x17: return (void*)&m_c2; // sign extended
|
|
||||||
case 0x18: return (void*)&m_sioc;
|
|
||||||
case 0x19: return (void*)&m_srta;
|
|
||||||
case 0x1a: return (void*)&m_sdx;
|
|
||||||
case 0x1b: logerror("dsp16::registerFromRTable tdms requested 0x%04x.\n", m_pc); break;
|
|
||||||
case 0x1c: return (void*)&m_pioc;
|
|
||||||
case 0x1d: return (void*)&m_pdx0;
|
|
||||||
case 0x1e: return (void*)&m_pdx1;
|
|
||||||
|
|
||||||
default: return nullptr;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void dsp16_device::executeF1Field(const uint8_t& F1, const uint8_t& D, const uint8_t& S)
|
|
||||||
{
|
|
||||||
// TODO: I'm pretty sure we need to feed X into these as well - Double check
|
|
||||||
|
|
||||||
// Note these instructions read right-to-left, so act accordingly (page 3-6)
|
|
||||||
// y & p are sign extended (page 3-9)
|
|
||||||
// implementation details (page 3-9)
|
|
||||||
|
|
||||||
// Where is are the results going?
|
|
||||||
uint64_t* destinationReg = nullptr;
|
|
||||||
switch (D)
|
|
||||||
{
|
|
||||||
case 0x00: destinationReg = &m_a0; break;
|
|
||||||
case 0x01: destinationReg = &m_a1; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Which source is being used?
|
|
||||||
uint64_t* sourceReg = nullptr;
|
|
||||||
switch (S)
|
|
||||||
{
|
|
||||||
case 0x00: sourceReg = &m_a0; break;
|
|
||||||
case 0x01: sourceReg = &m_a1; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// We must compute into an intermediate variable to compute flags on
|
|
||||||
uint64_t result = 0;
|
|
||||||
bool justATest = false;
|
|
||||||
|
|
||||||
switch (F1)
|
|
||||||
{
|
|
||||||
case 0x00:
|
|
||||||
{
|
|
||||||
// Ad = p p = x*y
|
|
||||||
printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x01:
|
|
||||||
{
|
|
||||||
// Ad = aS+p p = x*y
|
|
||||||
printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x02:
|
|
||||||
{
|
|
||||||
// p = x*y
|
|
||||||
// TODO: What happens to the flags in this operation?
|
|
||||||
const int16_t y = (m_y & 0xffff0000) >> 16;
|
|
||||||
m_p = (int32_t)((int16_t)m_x * y);
|
|
||||||
justATest = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x03:
|
|
||||||
{
|
|
||||||
// Ad = aS-p p = x*y
|
|
||||||
printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x04:
|
|
||||||
{
|
|
||||||
// Ad = p
|
|
||||||
printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x05:
|
|
||||||
{
|
|
||||||
// Ad = aS+p
|
|
||||||
printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x06:
|
|
||||||
{
|
|
||||||
// nop
|
|
||||||
justATest = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x07:
|
|
||||||
{
|
|
||||||
// Ad = aS-p
|
|
||||||
printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x08:
|
|
||||||
{
|
|
||||||
// Ad = aS|y
|
|
||||||
printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x09:
|
|
||||||
{
|
|
||||||
// Ad = aS^y
|
|
||||||
printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x0a:
|
|
||||||
{
|
|
||||||
// aS&y
|
|
||||||
printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
|
|
||||||
justATest = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x0b:
|
|
||||||
{
|
|
||||||
// aS-y
|
|
||||||
int64_t aS = *sourceReg;
|
|
||||||
if (aS & 0x800000000U)
|
|
||||||
aS |= 0xfffffff000000000U;
|
|
||||||
|
|
||||||
int64_t y = (m_y & 0xffff0000) >> 16;
|
|
||||||
if (y & 0x8000)
|
|
||||||
y |= 0xffffffffffff0000U;
|
|
||||||
|
|
||||||
result = aS-y;
|
|
||||||
justATest = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x0c:
|
|
||||||
{
|
|
||||||
// Ad = y
|
|
||||||
printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x0d:
|
|
||||||
{
|
|
||||||
// Ad = aS+y
|
|
||||||
int64_t aS = *sourceReg;
|
|
||||||
if (aS & 0x800000000U)
|
|
||||||
aS |= 0xfffffff000000000U;
|
|
||||||
|
|
||||||
int64_t y = (m_y & 0xffff0000) >> 16;
|
|
||||||
if (y & 0x8000)
|
|
||||||
y |= 0xffffffffffff0000U;
|
|
||||||
|
|
||||||
result = aS+y;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x0e:
|
|
||||||
{
|
|
||||||
// Ad = aS&y
|
|
||||||
printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x0f:
|
|
||||||
{
|
|
||||||
// Ad = aS-y
|
|
||||||
int64_t aS = *sourceReg;
|
|
||||||
if (aS & 0x800000000U)
|
|
||||||
aS |= 0xfffffff000000000U;
|
|
||||||
|
|
||||||
int64_t y = (m_y & 0xffff0000) >> 16;
|
|
||||||
if (y & 0x8000)
|
|
||||||
y |= 0xffffffffffff0000U;
|
|
||||||
|
|
||||||
result = aS-y;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CPU Flags (page 3-4)
|
|
||||||
// LMI (logical minus)
|
|
||||||
if (result & 0x800000000U)
|
|
||||||
m_psw |= 0x8000;
|
|
||||||
else
|
|
||||||
m_psw &= (~0x8000);
|
|
||||||
|
|
||||||
// LEQ (logical equal)
|
|
||||||
if (result == 0x000000000U)
|
|
||||||
m_psw |= 0x4000;
|
|
||||||
else
|
|
||||||
m_psw &= (~0x4000);
|
|
||||||
|
|
||||||
// LLV (logical overflow)
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
// LMV (mathematical overflow)
|
|
||||||
if ((result & 0xf00000000U) != 0xf00000000U &&
|
|
||||||
(result & 0xf00000000U) != 0x000000000U)
|
|
||||||
m_psw |= 0x1000;
|
|
||||||
else
|
|
||||||
m_psw &= (~0x1000);
|
|
||||||
|
|
||||||
// If it was a real operation, make sure the data goes where it should
|
|
||||||
if (!justATest)
|
|
||||||
*destinationReg = (uint64_t)result & 0x0000000fffffffffU;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint16_t* dsp16_device::registerFromYFieldUpper(const uint8_t& Y)
|
|
||||||
{
|
|
||||||
uint16_t* destinationReg = nullptr;
|
|
||||||
const uint8_t N = (Y & 0x0c) >> 2;
|
|
||||||
switch (N)
|
|
||||||
{
|
|
||||||
case 0x00: destinationReg = &m_r0; break;
|
|
||||||
case 0x01: destinationReg = &m_r1; break;
|
|
||||||
case 0x02: destinationReg = &m_r2; break;
|
|
||||||
case 0x03: destinationReg = &m_r3; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
return destinationReg;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void dsp16_device::executeYFieldPost(const uint8_t& Y)
|
|
||||||
{
|
|
||||||
uint16_t* opReg = registerFromYFieldUpper(Y);
|
|
||||||
|
|
||||||
const uint8_t lower = Y & 0x03;
|
|
||||||
switch (lower)
|
|
||||||
{
|
|
||||||
case 0x00: /* nop */ break;
|
|
||||||
case 0x01: (*opReg)++; break;
|
|
||||||
case 0x02: (*opReg)--; break;
|
|
||||||
case 0x03: (*opReg) += m_j; break; // TODO: J is signed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void dsp16_device::executeZFieldPartOne(const uint8_t& Z, uint16_t* rN)
|
|
||||||
{
|
|
||||||
const uint8_t lower = Z & 0x03;
|
|
||||||
switch (lower)
|
|
||||||
{
|
|
||||||
case 0x00: /* nop */ break;
|
|
||||||
case 0x01: (*rN)++; break;
|
|
||||||
case 0x02: (*rN)--; break;
|
|
||||||
case 0x03: (*rN) += m_j; break; // TODO: J is signed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void dsp16_device::executeZFieldPartTwo(const uint8_t& Z, uint16_t* rN)
|
|
||||||
{
|
|
||||||
const uint8_t lower = Z & 0x03;
|
|
||||||
switch (lower)
|
|
||||||
{
|
|
||||||
case 0x00: (*rN)++; break;
|
|
||||||
case 0x01: /* nop */ break;
|
|
||||||
case 0x02: (*rN) += 2; break;
|
|
||||||
case 0x03: (*rN) += m_k; break; // TODO: K is signed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void dsp16_device::execute_one(const uint16_t& op, uint8_t& cycles, uint8_t& pcAdvance)
|
|
||||||
{
|
|
||||||
cycles = 1;
|
|
||||||
pcAdvance = 0;
|
|
||||||
|
|
||||||
// NOTE: pages 3-5 through 3-19 are good english descriptions of what's up
|
|
||||||
|
|
||||||
const uint8_t opcode = (op >> 11) & 0x1f;
|
|
||||||
switch(opcode)
|
|
||||||
{
|
|
||||||
// Format 1: Multiply/ALU Read/Write Group
|
|
||||||
case 0x06:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-38")
|
|
||||||
// F1, Y : (page 3-38)
|
|
||||||
const uint8_t Y = (op & 0x000f);
|
|
||||||
const uint8_t S = (op & 0x0200) >> 9;
|
|
||||||
const uint8_t D = (op & 0x0400) >> 10;
|
|
||||||
const uint8_t F1 = (op & 0x01e0) >> 5;
|
|
||||||
executeF1Field(F1, D, S);
|
|
||||||
executeYFieldPost(Y);
|
|
||||||
cycles = 1;
|
|
||||||
pcAdvance = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x04: case 0x1c:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-40")
|
|
||||||
// F1 Y=a0[1] | F1 Y=a1[1] : (page 3-40)
|
|
||||||
const uint8_t Y = (op & 0x000f);
|
|
||||||
//const uint8_t X = (op & 0x0010) >> 4;
|
|
||||||
const uint8_t S = (op & 0x0200) >> 9;
|
|
||||||
const uint8_t D = (op & 0x0400) >> 10;
|
|
||||||
const uint8_t F1 = (op & 0x01e0) >> 5;
|
|
||||||
uint16_t* destinationReg = registerFromYFieldUpper(Y);
|
|
||||||
// (page 3-18)
|
|
||||||
uint16_t aRegValue = 0x0000;
|
|
||||||
if (op & 0xc000)
|
|
||||||
{
|
|
||||||
aRegValue = (m_a0 & 0x0ffff0000U) >> 16;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aRegValue = (m_a1 & 0x0ffff0000U) >> 16;
|
|
||||||
}
|
|
||||||
data_write(*destinationReg, aRegValue);
|
|
||||||
executeYFieldPost(Y);
|
|
||||||
executeF1Field(F1, D, S);
|
|
||||||
cycles = 2;
|
|
||||||
pcAdvance = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x16:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-42")
|
|
||||||
// F1, x = Y : (page 3-42)
|
|
||||||
const uint8_t Y = (op & 0x000f);
|
|
||||||
const uint8_t S = (op & 0x0200) >> 9;
|
|
||||||
const uint8_t D = (op & 0x0400) >> 10;
|
|
||||||
const uint8_t F1 = (op & 0x01e0) >> 5;
|
|
||||||
executeF1Field(F1, D, S);
|
|
||||||
uint16_t* sourceReg = registerFromYFieldUpper(Y);
|
|
||||||
writeRegister(&m_x, data_read(*sourceReg));
|
|
||||||
executeYFieldPost(Y);
|
|
||||||
cycles = 1;
|
|
||||||
pcAdvance = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x17:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-44")
|
|
||||||
// F1, y[l] = Y : (page 3-44)
|
|
||||||
const uint8_t Y = (op & 0x000f);
|
|
||||||
const uint8_t X = (op & 0x0010) >> 4;
|
|
||||||
const uint8_t S = (op & 0x0200) >> 9;
|
|
||||||
const uint8_t D = (op & 0x0400) >> 10;
|
|
||||||
const uint8_t F1 = (op & 0x01e0) >> 5;
|
|
||||||
executeF1Field(F1, D, S);
|
|
||||||
uint16_t* sourceReg = registerFromYFieldUpper(Y);
|
|
||||||
uint16_t sourceValue = data_read(*sourceReg);
|
|
||||||
switch (X)
|
|
||||||
{
|
|
||||||
case 0x00: writeRegister(addressYL(), sourceValue); break;
|
|
||||||
case 0x01: writeRegister(&m_y, sourceValue); break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
executeYFieldPost(Y);
|
|
||||||
cycles = 1;
|
|
||||||
pcAdvance = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x1f:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-46")
|
|
||||||
// F1, y = Y, x = *pt++[i] : (page 3-46)
|
|
||||||
const uint8_t Y = (op & 0x000f);
|
|
||||||
const uint8_t X = (op & 0x0010) >> 4;
|
|
||||||
const uint8_t S = (op & 0x0200) >> 9;
|
|
||||||
const uint8_t D = (op & 0x0400) >> 10;
|
|
||||||
const uint8_t F1 = (op & 0x01e0) >> 5;
|
|
||||||
executeF1Field(F1, D, S);
|
|
||||||
uint16_t* sourceRegR = registerFromYFieldUpper(Y);
|
|
||||||
writeRegister(&m_y, data_read(*sourceRegR));
|
|
||||||
executeYFieldPost(Y);
|
|
||||||
writeRegister(&m_x, data_read(m_pt));
|
|
||||||
switch (X)
|
|
||||||
{
|
|
||||||
case 0x00: m_pt++; break;
|
|
||||||
case 0x01: m_pt += m_i; break;
|
|
||||||
}
|
|
||||||
cycles = 2; // TODO: 1 if cached
|
|
||||||
pcAdvance = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x19: case 0x1b:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-48")
|
|
||||||
// F1, y = a0|1, x = *pt++[i] : (page 3-48)
|
|
||||||
const uint8_t Y = (op & 0x000f);
|
|
||||||
const uint8_t X = (op & 0x0010) >> 4;
|
|
||||||
const uint8_t S = (op & 0x0200) >> 9;
|
|
||||||
const uint8_t D = (op & 0x0400) >> 10;
|
|
||||||
const uint8_t F1 = (op & 0x01e0) >> 5;
|
|
||||||
bool useA1 = (opcode == 0x1b);
|
|
||||||
if (Y != 0x00) printf("Unknown opcode @ PC=0x%04x", m_pc);
|
|
||||||
m_y = (useA1) ? (m_a1 & 0xffffffff) : (m_a0 & 0xffffffff); // TODO: What happens to Ax when it goes 32 bit (pc=3f & pc=47)?
|
|
||||||
executeF1Field(F1, D, S);
|
|
||||||
writeRegister(&m_x, data_read(m_pt)); // TODO: EXM Pin & internal/external ROM? Research.
|
|
||||||
switch (X)
|
|
||||||
{
|
|
||||||
case 0x00: m_pt++; break;
|
|
||||||
case 0x01: m_pt += m_i; break;
|
|
||||||
}
|
|
||||||
cycles = 2; // TODO: 1 if cached
|
|
||||||
pcAdvance = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x14:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-53")
|
|
||||||
// F1, Y = y[l] : (page 3-53)
|
|
||||||
const uint8_t Y = (op & 0x000f);
|
|
||||||
const uint8_t X = (op & 0x0010) >> 4;
|
|
||||||
const uint8_t S = (op & 0x0200) >> 9;
|
|
||||||
const uint8_t D = (op & 0x0400) >> 10;
|
|
||||||
const uint8_t F1 = (op & 0x01e0) >> 5;
|
|
||||||
executeF1Field(F1, D, S);
|
|
||||||
uint16_t* destinationReg = registerFromYFieldUpper(Y);
|
|
||||||
uint16_t yRegValue = 0x0000;
|
|
||||||
switch (X)
|
|
||||||
{
|
|
||||||
case 0x00: yRegValue = (m_y & 0x0000ffff); break;
|
|
||||||
case 0x01: yRegValue = (m_y & 0xffff0000) >> 16; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
data_write(*destinationReg, yRegValue);
|
|
||||||
executeYFieldPost(Y);
|
|
||||||
cycles = 2;
|
|
||||||
pcAdvance = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format 1a: Multiply/ALU Read/Write Group (TODO: Figure out major typo in docs on p3-51)
|
|
||||||
case 0x07:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-50")
|
|
||||||
// F1, At[1] = Y : (page 3-50)
|
|
||||||
// TODO: What does the X field do here, exactly?
|
|
||||||
const uint8_t Y = (op & 0x000f);
|
|
||||||
const uint8_t S = (op & 0x0200) >> 9;
|
|
||||||
const uint8_t aT = (op & 0x0400) >> 10;
|
|
||||||
const uint8_t F1 = (op & 0x01e0) >> 5;
|
|
||||||
executeF1Field(F1, !aT, S);
|
|
||||||
uint64_t* destinationReg = nullptr;
|
|
||||||
switch(aT)
|
|
||||||
{
|
|
||||||
case 0: destinationReg = &m_a1; break;
|
|
||||||
case 1: destinationReg = &m_a0; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
uint16_t sourceAddress = *(registerFromYFieldUpper(Y));
|
|
||||||
int64_t sourceValueSigned = (int16_t)data_read(sourceAddress);
|
|
||||||
*destinationReg = sourceValueSigned & 0xffffffffffU;
|
|
||||||
executeYFieldPost(Y);
|
|
||||||
cycles = 1;
|
|
||||||
pcAdvance = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format 2: Multiply/ALU Read/Write Group
|
|
||||||
case 0x15:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-54")
|
|
||||||
// F1, Z : y[l] : (page 3-54)
|
|
||||||
const uint8_t Z = (op & 0x000f);
|
|
||||||
const uint8_t X = (op & 0x0010) >> 4;
|
|
||||||
const uint8_t S = (op & 0x0200) >> 9;
|
|
||||||
const uint8_t D = (op & 0x0400) >> 10;
|
|
||||||
const uint8_t F1 = (op & 0x01e0) >> 5;
|
|
||||||
executeF1Field(F1, D, S);
|
|
||||||
uint16_t temp = 0x0000;
|
|
||||||
uint16_t* rN = registerFromYFieldUpper(Z);
|
|
||||||
switch (X)
|
|
||||||
{
|
|
||||||
case 0x00:
|
|
||||||
temp = m_y & 0x0000ffff;
|
|
||||||
m_y &= 0xffff0000;
|
|
||||||
m_y |= data_read(*rN);
|
|
||||||
executeZFieldPartOne(Z, rN);
|
|
||||||
data_write(*rN, temp);
|
|
||||||
executeZFieldPartTwo(Z, rN);
|
|
||||||
break;
|
|
||||||
case 0x01:
|
|
||||||
temp = (m_y & 0xffff0000) >> 16;
|
|
||||||
m_y &= 0x0000ffff;
|
|
||||||
m_y |= (data_read(*rN) << 16);
|
|
||||||
executeZFieldPartOne(Z, rN);
|
|
||||||
data_write(*rN, temp);
|
|
||||||
executeZFieldPartTwo(Z, rN);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cycles = 2;
|
|
||||||
pcAdvance = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x1d:
|
|
||||||
{
|
|
||||||
DSP_LINE("?")
|
|
||||||
// F1, Z : y, x=*pt++[i]
|
|
||||||
//const uint8_t Z = (op & 0x000f);
|
|
||||||
//const uint8_t X = (op & 0x0010) >> 4;
|
|
||||||
//const uint8_t S = (op & 0x0200) >> 9;
|
|
||||||
//const uint8_t D = (op & 0x0400) >> 10;
|
|
||||||
//const uint8_t F1 = (op & 0x01e0) >> 5;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format 2a: Multiply/ALU Read/Write Group
|
|
||||||
case 0x05:
|
|
||||||
{
|
|
||||||
DSP_LINE("?")
|
|
||||||
// F1, Z : aT[1]
|
|
||||||
//const uint8_t Z = (op & 0x000f);
|
|
||||||
//const uint8_t X = (op & 0x0010) >> 4;
|
|
||||||
//const uint8_t S = (op & 0x0200) >> 9;
|
|
||||||
//const uint8_t aT = (op & 0x0400) >> 10;
|
|
||||||
//const uint8_t F1 = (op & 0x01e0) >> 5;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format 3: Special Functions
|
|
||||||
case 0x12:
|
|
||||||
case 0x13:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-36")
|
|
||||||
// if|ifc CON F2 (page 3-36)
|
|
||||||
const uint8_t CON = (op & 0x001f);
|
|
||||||
//const uint8_t S = (op & 0x0200) >> 9;
|
|
||||||
//const uint8_t D = (op & 0x0400) >> 10;
|
|
||||||
//const uint8_t F2 = (op & 0x01e0) >> 5;
|
|
||||||
bool conditionFulfilled = conditionTest(CON);
|
|
||||||
if (conditionFulfilled)
|
|
||||||
{
|
|
||||||
printf("Fulfilled condition not yet implemented @ PC=0x%04x\n", m_pc);
|
|
||||||
}
|
|
||||||
cycles = 1;
|
|
||||||
pcAdvance = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format 4: Branch Direct Group
|
|
||||||
case 0x00: case 0x01:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-20")
|
|
||||||
// goto JA : (page 3-20) (DONE)
|
|
||||||
const uint16_t JA = (op & 0x0fff) | (m_pc & 0xf000);
|
|
||||||
m_pc = JA;
|
|
||||||
cycles = 2;
|
|
||||||
pcAdvance = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 0x10: case 0x11:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-23")
|
|
||||||
// call JA : (page 3-23)
|
|
||||||
const uint16_t JA = (op & 0x0fff) | (m_pc & 0xf000);
|
|
||||||
m_pr = m_pc + 1;
|
|
||||||
m_pc = JA;
|
|
||||||
cycles = 2;
|
|
||||||
pcAdvance = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format 5: Branch Indirect Group
|
|
||||||
case 0x18:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-21")
|
|
||||||
// goto B : (page 3-21)
|
|
||||||
const uint8_t B = (op & 0x0700) >> 8;
|
|
||||||
switch (B)
|
|
||||||
{
|
|
||||||
case 0x00: m_pc = m_pr; break;
|
|
||||||
case 0x01: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break;
|
|
||||||
case 0x02: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break;
|
|
||||||
case 0x03: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break;
|
|
||||||
default: logerror("DSP16: Invalid branch indirect instruction executed at PC=0x%04x\n.", m_pc); break;
|
|
||||||
}
|
|
||||||
cycles = 2;
|
|
||||||
pcAdvance = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format 6: Contitional Branch Qualifier/Software Interrupt (icall)
|
|
||||||
case 0x1a:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-22")
|
|
||||||
// if CON [goto/call/return] : (page 3-22)
|
|
||||||
const uint8_t CON = (op & 0x001f);
|
|
||||||
bool conditionFulfilled = conditionTest(CON);
|
|
||||||
cycles = 3; // TODO: This may need to interact with the next opcode to make sure it doesn't exceed 3?
|
|
||||||
pcAdvance = 1;
|
|
||||||
if (!conditionFulfilled)
|
|
||||||
{
|
|
||||||
pcAdvance = 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format 7: Data Move Group
|
|
||||||
case 0x09: case 0x0b:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-29")
|
|
||||||
// R = aS : (page 3-29)
|
|
||||||
// TODO: Fix register pdxX (pc=338)
|
|
||||||
const uint8_t R = (op & 0x03f0) >> 4;
|
|
||||||
const uint8_t S = (op & 0x1000) >> 12;
|
|
||||||
void* destinationReg = registerFromRTable(R);
|
|
||||||
uint64_t* sourceReg = (S) ? &m_a1 : &m_a0;
|
|
||||||
uint16_t sourceValue = (*sourceReg & 0x0ffff0000U) >> 16;
|
|
||||||
writeRegister(destinationReg, sourceValue);
|
|
||||||
cycles = 2;
|
|
||||||
pcAdvance = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x08:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-30")
|
|
||||||
// aT = R : (page 3-30)
|
|
||||||
const uint8_t R = (op & 0x03f0) >> 4;
|
|
||||||
const uint8_t aT = (op & 0x0400) >> 10;
|
|
||||||
uint64_t* destinationReg = nullptr;
|
|
||||||
switch(aT)
|
|
||||||
{
|
|
||||||
case 0: destinationReg = &m_a1; break;
|
|
||||||
case 1: destinationReg = &m_a0; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
void* sourceReg = registerFromRTable(R);
|
|
||||||
*destinationReg &= 0x00000ffffU;
|
|
||||||
*destinationReg |= (*(uint16_t*)sourceReg) << 16; // TODO: Fix for all registers
|
|
||||||
if (*(uint16_t*)sourceReg & 0x8000)
|
|
||||||
*destinationReg |= 0xf00000000U;
|
|
||||||
// TODO: Special function encoding
|
|
||||||
cycles = 2;
|
|
||||||
pcAdvance = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x0f:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-32")
|
|
||||||
// R = Y : (page 3-32)
|
|
||||||
const uint8_t Y = (op & 0x000f);
|
|
||||||
const uint8_t R = (op & 0x03f0) >> 4;
|
|
||||||
uint16_t* sourceReg = registerFromYFieldUpper(Y);
|
|
||||||
void* destinationReg = registerFromRTable(R);
|
|
||||||
writeRegister(destinationReg, data_read(*sourceReg));
|
|
||||||
executeYFieldPost(Y);
|
|
||||||
cycles = 2;
|
|
||||||
pcAdvance = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x0c:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-33")
|
|
||||||
// Y = R : (page 3-33)
|
|
||||||
// TODO: Zero & Sign extend i, c0, c1, c2, and auc
|
|
||||||
const uint8_t Y = (op & 0x000f);
|
|
||||||
const uint8_t R = (op & 0x03f0) >> 4;
|
|
||||||
uint16_t* destinationReg = registerFromYFieldUpper(Y);
|
|
||||||
uint16_t* sourceReg = (uint16_t*)registerFromRTable(R); // TODO: This won't work for certain registers!
|
|
||||||
data_write(*destinationReg, *sourceReg); // Fix in data_write() maybe?
|
|
||||||
executeYFieldPost(Y);
|
|
||||||
cycles = 2;
|
|
||||||
pcAdvance = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x0d:
|
|
||||||
{
|
|
||||||
DSP_LINE("?")
|
|
||||||
// Z : R
|
|
||||||
//const uint8_t Z = (op & 0x000f);
|
|
||||||
//const uint8_t R = (op & 0x03f0) >> 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format 8: Data Move (immediate operand - 2 words)
|
|
||||||
case 0x0a:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-28")
|
|
||||||
// R = N : (page 3-28) (DONE)
|
|
||||||
// NOTE: The docs speak of register sources & sign extension, but this is a register
|
|
||||||
// destination, so, typo? If so, what does one do with the overflow bits?
|
|
||||||
const uint8_t R = (op & 0x03f0) >> 4;
|
|
||||||
const uint16_t iVal = opcode_read(1);
|
|
||||||
void* destinationReg = registerFromRTable(R);
|
|
||||||
writeRegister(destinationReg, iVal);
|
|
||||||
cycles = 2;
|
|
||||||
pcAdvance = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format 9: Short Immediate Group
|
|
||||||
case 0x02: case 0x03:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-27")
|
|
||||||
// R = M : (page 3-27)
|
|
||||||
// TODO: Figure out notes about the DSP16A vs the DSP16. 9 bit is very DSP16...
|
|
||||||
const uint16_t M = (op & 0x01ff);
|
|
||||||
const uint8_t R = (op & 0x0e00) >> 9;
|
|
||||||
void* destinationReg = registerFromRImmediateField(R);
|
|
||||||
// Sign extend if the destination is j or k
|
|
||||||
uint16_t mValue = M;
|
|
||||||
if (destinationReg == &m_j || destinationReg == &m_k)
|
|
||||||
{
|
|
||||||
if (mValue & 0x0100) mValue |= 0xfe00;
|
|
||||||
}
|
|
||||||
writeRegister(destinationReg, mValue);
|
|
||||||
cycles = 1;
|
|
||||||
pcAdvance = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format 10: do - redo
|
|
||||||
case 0x0e:
|
|
||||||
{
|
|
||||||
DSP_LINE("3-25/3-26")
|
|
||||||
// do|redo K : (pages 3-25 & 3-26)
|
|
||||||
// TODO: The timings are intricate to say the least...
|
|
||||||
const uint8_t K = (op & 0x007f);
|
|
||||||
const uint8_t NI = (op & 0x0780) >> 7;
|
|
||||||
if (NI != 0)
|
|
||||||
{
|
|
||||||
// Do
|
|
||||||
m_cacheStart = m_pc + 1;
|
|
||||||
m_cacheEnd = m_pc + 1 + NI;
|
|
||||||
m_cacheIterations = K-1; // -1 because we check the counter @ the end
|
|
||||||
cycles = 1;
|
|
||||||
pcAdvance = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Redo
|
|
||||||
m_cacheIterations = K-1; // -1 because we check the counter @ the end
|
|
||||||
m_cacheRedoNextPC = m_pc + 1;
|
|
||||||
m_pc = m_cacheStart;
|
|
||||||
cycles = 2;
|
|
||||||
pcAdvance = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// RESERVED
|
|
||||||
case 0x1e:
|
|
||||||
{
|
|
||||||
DSP_LINE("XXX")
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// UNKNOWN
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
DSP_LINE("XXX")
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle end-of-cache conditions for do|redos
|
|
||||||
if (m_cacheIterations == 0 && m_cacheRedoNextPC != CACHE_INVALID)
|
|
||||||
{
|
|
||||||
// You've reached the end of a cache loop after a redo opcode.
|
|
||||||
m_pc = m_cacheRedoNextPC;
|
|
||||||
m_cacheRedoNextPC = CACHE_INVALID;
|
|
||||||
pcAdvance = 0;
|
|
||||||
}
|
|
||||||
if (m_cacheIterations > 0 && (m_pc+pcAdvance == m_cacheEnd))
|
|
||||||
{
|
|
||||||
// A regular iteration on a cached loop.
|
|
||||||
m_cacheIterations--;
|
|
||||||
m_pc = m_cacheStart;
|
|
||||||
pcAdvance = 0;
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,8 +2,8 @@
|
|||||||
// copyright-holders:Paul Leaman, Miguel Angel Horna
|
// copyright-holders:Paul Leaman, Miguel Angel Horna
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
|
|
||||||
Capcom System QSound(tm)
|
Capcom System QSound™
|
||||||
========================
|
=====================
|
||||||
|
|
||||||
Driver by Paul Leaman and Miguel Angel Horna
|
Driver by Paul Leaman and Miguel Angel Horna
|
||||||
|
|
||||||
@ -40,28 +40,13 @@ DEFINE_DEVICE_TYPE(QSOUND, qsound_device, "qsound", "Q-Sound")
|
|||||||
// chip decapped by siliconpr0n clearly shows 3x as much ROM as that, a total
|
// chip decapped by siliconpr0n clearly shows 3x as much ROM as that, a total
|
||||||
// of 12288 words of internal ROM.
|
// of 12288 words of internal ROM.
|
||||||
// The older DSP16 non-a part has 2048 words of ROM.
|
// The older DSP16 non-a part has 2048 words of ROM.
|
||||||
void qsound_device::dsp16_program_map(address_map &map)
|
|
||||||
{
|
|
||||||
map(0x0000, 0x2fff).rom();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// data map for the DSP16A; again, Western Electric/AT&T expanded the size of
|
// DSP internal ROM region
|
||||||
// the ram over time.
|
|
||||||
// As originally released, the DSP16A had 1024 words of internal RAM,
|
|
||||||
// but this was expanded to 2048 words in the DL-1425 decap.
|
|
||||||
// The older DSP16 non-a part has 512 words of RAM.
|
|
||||||
void qsound_device::dsp16_data_map(address_map &map)
|
|
||||||
{
|
|
||||||
map.unmap_value_high();
|
|
||||||
map(0x0000, 0x07ff).ram();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ROM definition for the Qsound program ROM
|
|
||||||
ROM_START( qsound )
|
ROM_START( qsound )
|
||||||
ROM_REGION( 0x6000, "qsound", 0 )
|
ROM_REGION( 0x2000, "dsp", 0 )
|
||||||
ROM_LOAD16_WORD( "dl-1425.bin", 0x0000, 0x6000, CRC(d6cf5ef5) SHA1(555f50fe5cdf127619da7d854c03f4a244a0c501) )
|
ROM_LOAD16_WORD_SWAP( "dl-1425.bin", 0x0000, 0x2000, CRC(d6cf5ef5) SHA1(555f50fe5cdf127619da7d854c03f4a244a0c501) )
|
||||||
|
ROM_IGNORE( 0x4000 )
|
||||||
ROM_END
|
ROM_END
|
||||||
|
|
||||||
|
|
||||||
@ -74,12 +59,12 @@ ROM_END
|
|||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
qsound_device::qsound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
qsound_device::qsound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||||
: device_t(mconfig, QSOUND, tag, owner, clock),
|
: device_t(mconfig, QSOUND, tag, owner, clock)
|
||||||
device_sound_interface(mconfig, *this),
|
, device_sound_interface(mconfig, *this)
|
||||||
device_rom_interface(mconfig, *this, 24),
|
, device_rom_interface(mconfig, *this, 24)
|
||||||
m_cpu(*this, "qsound"),
|
, m_dsp(*this, "dsp")
|
||||||
m_data(0),
|
, m_stream(nullptr)
|
||||||
m_stream(nullptr)
|
, m_data(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,9 +85,8 @@ const tiny_rom_entry *qsound_device::device_rom_region() const
|
|||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
MACHINE_CONFIG_START(qsound_device::device_add_mconfig)
|
MACHINE_CONFIG_START(qsound_device::device_add_mconfig)
|
||||||
MCFG_CPU_ADD("qsound", DSP16, DERIVED_CLOCK(1, 1))
|
MCFG_CPU_ADD("dsp", DSP16A, DERIVED_CLOCK(1, 1))
|
||||||
MCFG_CPU_PROGRAM_MAP(dsp16_program_map)
|
MCFG_DEVICE_DISABLE()
|
||||||
MCFG_CPU_DATA_MAP(dsp16_data_map)
|
|
||||||
MACHINE_CONFIG_END
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
|
||||||
@ -122,7 +106,7 @@ void qsound_device::rom_bank_updated()
|
|||||||
|
|
||||||
void qsound_device::device_start()
|
void qsound_device::device_start()
|
||||||
{
|
{
|
||||||
m_stream = stream_alloc(0, 2, clock() / 166); // /166 clock divider?
|
m_stream = stream_alloc(0, 2, clock() / 15 / 166); // /166 clock divider?
|
||||||
|
|
||||||
// create pan table
|
// create pan table
|
||||||
for (int i = 0; i < 33; i++)
|
for (int i = 0; i < 33; i++)
|
||||||
@ -152,6 +136,10 @@ void qsound_device::device_start()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qsound_device::device_reset()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
// sound_stream_update - handle a stream update
|
// sound_stream_update - handle a stream update
|
||||||
|
@ -2,10 +2,9 @@
|
|||||||
// copyright-holders:Paul Leaman, Miguel Angel Horna
|
// copyright-holders:Paul Leaman, Miguel Angel Horna
|
||||||
/*********************************************************
|
/*********************************************************
|
||||||
|
|
||||||
Capcom Q-Sound system
|
Capcom System QSound™
|
||||||
|
|
||||||
*********************************************************/
|
*********************************************************/
|
||||||
|
|
||||||
#ifndef MAME_SOUND_QSOUND_H
|
#ifndef MAME_SOUND_QSOUND_H
|
||||||
#define MAME_SOUND_QSOUND_H
|
#define MAME_SOUND_QSOUND_H
|
||||||
|
|
||||||
@ -13,46 +12,44 @@
|
|||||||
|
|
||||||
#include "cpu/dsp16/dsp16.h"
|
#include "cpu/dsp16/dsp16.h"
|
||||||
|
|
||||||
#define QSOUND_CLOCK 4000000 /* default 4MHz clock (60MHz/15?) */
|
// default 60MHz clock (divided by 2 for DSP core clock, and then by 1248 for sample rate)
|
||||||
|
#define QSOUND_CLOCK 60_MHz_XTAL
|
||||||
|
|
||||||
|
|
||||||
//**************************************************************************
|
//**************************************************************************
|
||||||
// INTERFACE CONFIGURATION MACROS
|
// INTERFACE CONFIGURATION MACROS
|
||||||
//**************************************************************************
|
//**************************************************************************
|
||||||
|
|
||||||
#define MCFG_QSOUND_ADD(_tag, _clock) \
|
|
||||||
MCFG_DEVICE_ADD(_tag, QSOUND, _clock)
|
|
||||||
#define MCFG_QSOUND_REPLACE(_tag, _clock) \
|
|
||||||
MCFG_DEVICE_REPLACE(_tag, QSOUND, _clock)
|
|
||||||
|
|
||||||
|
|
||||||
// ======================> qsound_device
|
// ======================> qsound_device
|
||||||
|
|
||||||
class qsound_device : public device_t,
|
class qsound_device : public device_t, public device_sound_interface, public device_rom_interface
|
||||||
public device_sound_interface,
|
|
||||||
public device_rom_interface
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
qsound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
qsound_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
|
||||||
|
|
||||||
DECLARE_WRITE8_MEMBER(qsound_w);
|
DECLARE_WRITE8_MEMBER(qsound_w);
|
||||||
DECLARE_READ8_MEMBER(qsound_r);
|
DECLARE_READ8_MEMBER(qsound_r);
|
||||||
|
|
||||||
void dsp16_data_map(address_map &map);
|
|
||||||
void dsp16_program_map(address_map &map);
|
|
||||||
protected:
|
protected:
|
||||||
// device-level overrides
|
// device_t implementation
|
||||||
const tiny_rom_entry *device_rom_region() const override;
|
tiny_rom_entry const *device_rom_region() const override;
|
||||||
virtual void device_add_mconfig(machine_config &config) override;
|
virtual void device_add_mconfig(machine_config &config) override;
|
||||||
virtual void device_start() override;
|
virtual void device_start() override;
|
||||||
|
virtual void device_reset() override;
|
||||||
|
|
||||||
// sound stream update overrides
|
// device_sound_interface implementation
|
||||||
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;
|
||||||
|
|
||||||
// device_rom_interface overrides
|
// device_rom_interface implementation
|
||||||
virtual void rom_bank_updated() override;
|
virtual void rom_bank_updated() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
// MAME resources
|
||||||
|
required_device<dsp16_device_base> m_dsp;
|
||||||
|
sound_stream *m_stream;
|
||||||
|
|
||||||
struct qsound_channel
|
struct qsound_channel
|
||||||
{
|
{
|
||||||
uint32_t bank; // bank
|
uint32_t bank; // bank
|
||||||
@ -69,11 +66,8 @@ private:
|
|||||||
uint32_t step_ptr; // current offset counter
|
uint32_t step_ptr; // current offset counter
|
||||||
} m_channel[16];
|
} m_channel[16];
|
||||||
|
|
||||||
required_device<dsp16_device> m_cpu;
|
|
||||||
|
|
||||||
int m_pan_table[33]; // pan volume table
|
int m_pan_table[33]; // pan volume table
|
||||||
uint16_t m_data; // register latch data
|
uint16_t m_data; // register latch data
|
||||||
sound_stream *m_stream; // audio stream
|
|
||||||
|
|
||||||
inline int8_t read_sample(uint32_t offset) { return (int8_t)read_byte(offset); }
|
inline int8_t read_sample(uint32_t offset) { return (int8_t)read_byte(offset); }
|
||||||
void write_data(uint8_t address, uint16_t data);
|
void write_data(uint8_t address, uint16_t data);
|
||||||
|
@ -1598,7 +1598,7 @@ void validity_checker::validate_roms(device_t &root)
|
|||||||
if (!ROMENTRY_ISREGIONEND(romp) && current_length > 0)
|
if (!ROMENTRY_ISREGIONEND(romp) && current_length > 0)
|
||||||
{
|
{
|
||||||
items_since_region++;
|
items_since_region++;
|
||||||
if (ROM_GETOFFSET(romp) + ROM_GETLENGTH(romp) > current_length)
|
if (!ROMENTRY_ISIGNORE(romp) && (ROM_GETOFFSET(romp) + ROM_GETLENGTH(romp) > current_length))
|
||||||
osd_printf_error("ROM '%s' extends past the defined memory region\n", last_name);
|
osd_printf_error("ROM '%s' extends past the defined memory region\n", last_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3456,7 +3456,7 @@ MACHINE_CONFIG_START(cps_state::qsound)
|
|||||||
MCFG_DEVICE_REMOVE("2151")
|
MCFG_DEVICE_REMOVE("2151")
|
||||||
MCFG_DEVICE_REMOVE("oki")
|
MCFG_DEVICE_REMOVE("oki")
|
||||||
|
|
||||||
MCFG_QSOUND_ADD("qsound", QSOUND_CLOCK)
|
MCFG_DEVICE_ADD("qsound", QSOUND, QSOUND_CLOCK)
|
||||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
|
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
|
||||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
|
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
|
||||||
MACHINE_CONFIG_END
|
MACHINE_CONFIG_END
|
||||||
|
@ -1336,7 +1336,7 @@ MACHINE_CONFIG_START(cps_state::cps2)
|
|||||||
/* sound hardware */
|
/* sound hardware */
|
||||||
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
||||||
|
|
||||||
MCFG_QSOUND_ADD("qsound", QSOUND_CLOCK)
|
MCFG_DEVICE_ADD("qsound", QSOUND, QSOUND_CLOCK)
|
||||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
|
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
|
||||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
|
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
|
||||||
MACHINE_CONFIG_END
|
MACHINE_CONFIG_END
|
||||||
|
@ -1757,7 +1757,7 @@ MACHINE_CONFIG_START(vgmplay_state::vgmplay)
|
|||||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1)
|
MCFG_SOUND_ROUTE(0, "lspeaker", 1)
|
||||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1)
|
MCFG_SOUND_ROUTE(1, "rspeaker", 1)
|
||||||
|
|
||||||
MCFG_QSOUND_ADD("qsound", 4000000)
|
MCFG_DEVICE_ADD("qsound", QSOUND, QSOUND_CLOCK)
|
||||||
MCFG_DEVICE_ADDRESS_MAP(0, qsound_map)
|
MCFG_DEVICE_ADDRESS_MAP(0, qsound_map)
|
||||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1)
|
MCFG_SOUND_ROUTE(0, "lspeaker", 1)
|
||||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1)
|
MCFG_SOUND_ROUTE(1, "rspeaker", 1)
|
||||||
|
@ -661,7 +661,7 @@ MACHINE_CONFIG_START(zn_state::coh1000c)
|
|||||||
MCFG_DEVICE_MODIFY("soundlatch")
|
MCFG_DEVICE_MODIFY("soundlatch")
|
||||||
MCFG_GENERIC_LATCH_DATA_PENDING_CB(INPUTLINE("audiocpu", INPUT_LINE_NMI))
|
MCFG_GENERIC_LATCH_DATA_PENDING_CB(INPUTLINE("audiocpu", INPUT_LINE_NMI))
|
||||||
|
|
||||||
MCFG_QSOUND_ADD("qsound", QSOUND_CLOCK)
|
MCFG_DEVICE_ADD("qsound", QSOUND, QSOUND_CLOCK)
|
||||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
|
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
|
||||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
|
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
|
||||||
MACHINE_CONFIG_END
|
MACHINE_CONFIG_END
|
||||||
@ -687,7 +687,7 @@ MACHINE_CONFIG_START(zn_state::coh1002c)
|
|||||||
MCFG_DEVICE_MODIFY("soundlatch")
|
MCFG_DEVICE_MODIFY("soundlatch")
|
||||||
MCFG_GENERIC_LATCH_DATA_PENDING_CB(INPUTLINE("audiocpu", INPUT_LINE_NMI))
|
MCFG_GENERIC_LATCH_DATA_PENDING_CB(INPUTLINE("audiocpu", INPUT_LINE_NMI))
|
||||||
|
|
||||||
MCFG_QSOUND_ADD("qsound", QSOUND_CLOCK)
|
MCFG_DEVICE_ADD("qsound", QSOUND, QSOUND_CLOCK)
|
||||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
|
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
|
||||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
|
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
|
||||||
MACHINE_CONFIG_END
|
MACHINE_CONFIG_END
|
||||||
@ -849,7 +849,7 @@ MACHINE_CONFIG_START(zn_state::coh3002c)
|
|||||||
MCFG_DEVICE_MODIFY("soundlatch")
|
MCFG_DEVICE_MODIFY("soundlatch")
|
||||||
MCFG_GENERIC_LATCH_DATA_PENDING_CB(INPUTLINE("audiocpu", INPUT_LINE_NMI))
|
MCFG_GENERIC_LATCH_DATA_PENDING_CB(INPUTLINE("audiocpu", INPUT_LINE_NMI))
|
||||||
|
|
||||||
MCFG_QSOUND_ADD("qsound", QSOUND_CLOCK)
|
MCFG_DEVICE_ADD("qsound", QSOUND, QSOUND_CLOCK)
|
||||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
|
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
|
||||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
|
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
|
||||||
MACHINE_CONFIG_END
|
MACHINE_CONFIG_END
|
||||||
|
Loading…
Reference in New Issue
Block a user