diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/devices/bus/nscsi/hd.cpp | 22 | ||||
| -rw-r--r-- | src/devices/machine/mb87030.cpp | 9 | ||||
| -rw-r--r-- | src/devices/sound/fz_pcm.cpp | 427 | ||||
| -rw-r--r-- | src/devices/sound/fz_pcm.h | 113 | ||||
| -rw-r--r-- | src/mame/casio/fz1.cpp | 65 |
5 files changed, 624 insertions, 12 deletions
diff --git a/src/devices/bus/nscsi/hd.cpp b/src/devices/bus/nscsi/hd.cpp index fe5fc45127b..75767e7b701 100644 --- a/src/devices/bus/nscsi/hd.cpp +++ b/src/devices/bus/nscsi/hd.cpp @@ -136,8 +136,15 @@ void nscsi_harddisk_device::scsi_command() LOG("command WRITE start=%08x blocks=%04x\n", lba, blocks); - scsi_data_out(2, blocks*bytes_per_sector); - scsi_status_complete(SS_GOOD); + if(image->write(lba, block)) { + scsi_data_out(2, blocks*bytes_per_sector); + scsi_status_complete(SS_GOOD); + } + else + { + scsi_status_complete(SS_CHECK_CONDITION); + sense(false, SK_ILLEGAL_REQUEST, SK_ASC_INVALID_FIELD_IN_CDB); + } break; case SC_INQUIRY: { @@ -486,8 +493,15 @@ void nscsi_harddisk_device::scsi_command() LOG("command WRITE EXTENDED start=%08x blocks=%04x\n", lba, blocks); - scsi_data_out(2, blocks*bytes_per_sector); - scsi_status_complete(SS_GOOD); + if(image->write(lba, block)) { + scsi_data_out(2, blocks*bytes_per_sector); + scsi_status_complete(SS_GOOD); + } + else + { + scsi_status_complete(SS_CHECK_CONDITION); + sense(false, SK_ILLEGAL_REQUEST, SK_ASC_INVALID_FIELD_IN_CDB); + } break; case SC_FORMAT_UNIT: diff --git a/src/devices/machine/mb87030.cpp b/src/devices/machine/mb87030.cpp index ad60af82e42..9266a81821a 100644 --- a/src/devices/machine/mb87030.cpp +++ b/src/devices/machine/mb87030.cpp @@ -276,6 +276,7 @@ void mb87030_device::step(bool timeout) if ((m_sctl & SCTL_RESET_AND_DISABLE) && m_state != State::Idle) { scsi_set_ctrl(0, S_ALL); m_ssts &= ~SSTS_SPC_BUSY; + m_fifo.clear(); update_state(State::Idle); return; } @@ -383,8 +384,9 @@ void mb87030_device::step(bool timeout) if (m_scsi_phase != (ctrl & S_PHASE_MASK)) { LOG("SCSI phase change during transfer\n"); - m_ints |= INTS_SERVICE_REQUIRED; + m_ints |= (INTS_SERVICE_REQUIRED | INTS_COMMAND_COMPLETE); m_ssts &= ~SSTS_SPC_BUSY; + scsi_bus->data_w(scsi_refid, 0); update_ints(); update_state(State::Idle); break; @@ -583,6 +585,11 @@ void mb87030_device::scmd_w(uint8_t data) LOG("%s: %02X\n", __FUNCTION__, data); m_scmd = data; + if (!(m_sctl & SCTL_RESET_AND_DISABLE)) + { + scsi_set_ctrl((m_scmd & SCMD_RST_OUT) ? S_RST : 0, S_RST); + } + switch (m_scmd & SCMD_CMD_MASK) { case SCMD_CMD_BUS_RELEASE: LOG("%s: Bus release\n", __FUNCTION__); diff --git a/src/devices/sound/fz_pcm.cpp b/src/devices/sound/fz_pcm.cpp new file mode 100644 index 00000000000..fce3df53634 --- /dev/null +++ b/src/devices/sound/fz_pcm.cpp @@ -0,0 +1,427 @@ +// license:BSD-3-Clause +// copyright-holders:Devin Acker + +/* + Casio FZ series PCM + + This hardware actually comprises two main gate arrays (GAA and GAB) + which each handle about half of the address generation & timing logic + for 8 PCM voices. An additional gate array (GAX) demultiplexes the + sample RAM output for each voice. + + TODO: + - crossfade loop support + - sampling (writes 16-bit mic/line input to sample RAM) +*/ + +#include "emu.h" + +#include "fz_pcm.h" + +#include <climits> + +DEFINE_DEVICE_TYPE(FZ_PCM, fz_pcm_device, "fz_pcm", "Casio FZ PCM") + +fz_pcm_device::fz_pcm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, FZ_PCM, tag, owner, clock) + , device_sound_interface(mconfig, *this) + , device_memory_interface(mconfig, *this) + , m_irq_cb(*this) + , m_ram_config("ram", ENDIANNESS_LITTLE, 16, 21, -1) +{ +} + +/**************************************************************************/ +void fz_pcm_device::device_start() +{ + m_stream = stream_alloc(1, 8, clock() / CLOCKS_PER_SAMPLE); + + m_irq_timer = timer_alloc(FUNC(fz_pcm_device::timer_tick), this); + + space().specific(m_ram); + + save_item(NAME(m_gaa_param)); + save_item(NAME(m_gab_param)); + save_item(NAME(m_gaa_cmd)); + save_item(NAME(m_gab_cmd)); + + save_item(NAME(m_irq_stat)); + + save_item(STRUCT_MEMBER(m_voices, m_flags)); + + save_item(STRUCT_MEMBER(m_voices, m_addr_start)); + save_item(STRUCT_MEMBER(m_voices, m_addr_end)); + save_item(STRUCT_MEMBER(m_voices, m_loop_start)); + save_item(STRUCT_MEMBER(m_voices, m_loop_end)); + save_item(STRUCT_MEMBER(m_voices, m_loop_start_fine)); + save_item(STRUCT_MEMBER(m_voices, m_loop_len)); + save_item(STRUCT_MEMBER(m_voices, m_loop_trace)); + save_item(STRUCT_MEMBER(m_voices, m_loop_xfade)); + + save_item(STRUCT_MEMBER(m_voices, m_pitch)); + save_item(STRUCT_MEMBER(m_voices, m_addr)); + save_item(STRUCT_MEMBER(m_voices, m_addr_frac)); + + save_item(STRUCT_MEMBER(m_voices, m_sample)); + save_item(STRUCT_MEMBER(m_voices, m_sample_last)); +} + +/**************************************************************************/ +void fz_pcm_device::device_reset() +{ + m_gaa_param[0] = m_gaa_param[1] = m_gaa_param[2] = 0; + m_gab_param[0] = m_gab_param[1] = 0; + m_gaa_cmd = m_gab_cmd = 0; + m_voice_mask = 0; + + m_irq_stat = 0; + m_irq_timer->adjust(attotime::never); + m_irq_cb(0); + + for (voice_t &v : m_voices) + v = voice_t(); +} + +/**************************************************************************/ +void fz_pcm_device::device_clock_changed() +{ + m_stream->set_sample_rate(clock() / CLOCKS_PER_SAMPLE); + update_pending_irq(); +} + +/**************************************************************************/ +device_memory_interface::space_config_vector fz_pcm_device::memory_space_config() const +{ + return space_config_vector { + std::make_pair(0, &m_ram_config) + }; +} + +/**************************************************************************/ +TIMER_CALLBACK_MEMBER(fz_pcm_device::timer_tick) +{ + m_irq_cb(1); +} + +/**************************************************************************/ +void fz_pcm_device::sound_stream_update(sound_stream &stream) +{ + for (int s = 0; s < stream.samples(); s++) + { + for (int i = 0; i < 8; i++) + { + voice_t &v = m_voices[i]; + + if (BIT(v.m_flags, FLAG_PLAY)) + { + v.m_addr_frac += v.m_pitch; + if (v.m_addr_frac >= (1 << ADDR_FRAC_SHIFT)) + { + v.m_sample_last = v.m_sample; + v.m_sample = (s16)m_ram.read_word(v.m_addr); + + if (v.update()) + m_irq_stat |= (1 << i); + } + } + + s16 sample = 0; + if (BIT(v.m_flags, FLAG_OUTPUT)) + { + const u8 frac = BIT(v.m_addr_frac, ADDR_FRAC_SHIFT - 3, 3); + sample = v.m_sample_last + (s32(v.m_sample - v.m_sample_last) * frac / 8); + } + + stream.put_int_clamp(i, s, sample, 1 << 15); + } + } +} + +/**************************************************************************/ +bool fz_pcm_device::voice_t::update() +{ + bool looped = false; + + while (m_addr_frac >= (1 << ADDR_FRAC_SHIFT)) + { + m_addr_frac -= (1 << ADDR_FRAC_SHIFT); + + if (!BIT(m_flags, FLAG_REVERSE)) + { + if (m_addr < m_addr_end) + { + m_addr++; + + if (BIT(m_flags, FLAG_LOOP) && m_addr >= m_loop_end) + { + looped = BIT(m_flags, FLAG_INT); + + if (m_loop_trace) + { + // next=trace: continue as normal + m_addr = m_loop_start + (m_addr - m_loop_end); + m_addr_frac += m_loop_start_fine << (ADDR_FRAC_SHIFT - 8); + } + else + { + // next=skip: jump to exact loop start, stop further interrupts + m_addr = m_loop_start; + m_addr_frac = m_loop_start_fine << (ADDR_FRAC_SHIFT - 8); + m_flags &= ~(1 << FLAG_INT); + } + } + } + else + { + m_flags &= ~(1 << FLAG_PLAY); + } + } + else + { + if (m_addr > m_addr_end) + m_addr--; + else + m_flags &= ~(1 << FLAG_PLAY); + } + } + + return looped; +} + +/**************************************************************************/ +bool fz_pcm_device::voice_t::calc_timeout(u32 &samples) const +{ + // don't update interrupt timer if this voice isn't set to interrupt + if (!BIT(m_flags, FLAG_PLAY) + || !BIT(m_flags, FLAG_LOOP) + || !BIT(m_flags, FLAG_INT) + || BIT(m_flags, FLAG_REVERSE) + || !m_pitch) + { + return false; + } + + if (m_addr >= m_loop_end) + { + // loop end is somehow in the past + samples = 0; + } + else + { + // calculate number of output samples until loop end is reached + const u64 to_loop = ((u64(m_loop_end - m_addr) << ADDR_FRAC_SHIFT) - m_addr_frac + m_pitch - 1) / m_pitch; + if (to_loop < samples) + samples = to_loop; + } + + return true; +} + +/**************************************************************************/ +void fz_pcm_device::update_pending_irq() +{ + bool pending = false; + u32 new_time = UINT_MAX; + + for (voice_t &v : m_voices) + pending |= v.calc_timeout(new_time); + + if (pending) + m_irq_timer->adjust(clocks_to_attotime((u64)new_time * CLOCKS_PER_SAMPLE)); + else + m_irq_timer->adjust(attotime::never); +} + +/**************************************************************************/ +u16 fz_pcm_device::gaa_r(offs_t offset) +{ + offset &= 3; + + switch (offset & 3) + { + default: + return m_gaa_param[offset & 3]; + + case 3: + return m_gaa_cmd; + } +} + +/**************************************************************************/ +u16 fz_pcm_device::gab_r(offs_t offset) +{ + switch (offset & 3) + { + default: + return m_gab_param[offset & 3]; + + case 2: + if (!machine().side_effects_disabled()) + m_stream->update(); + return m_irq_stat; + + case 3: + return m_gab_cmd; + } +} + +/**************************************************************************/ +void fz_pcm_device::gaa_w(offs_t offset, u16 data, u16 mem_mask) +{ + m_stream->update(); + + switch (offset & 3) + { + default: + COMBINE_DATA(&m_gaa_param[offset & 3]); + break; + + case 3: + COMBINE_DATA(&m_gaa_cmd); + if (ACCESSING_BITS_8_15) + { + m_voice_mask = m_gaa_cmd & 0xff; + + switch (m_gaa_cmd >> 8) + { + case 0x40: voice_cmd(CMD_ADDR_START); break; + case 0x41: voice_cmd(CMD_LOOP_START); break; + case 0x42: voice_cmd(CMD_PITCH); break; + case 0x43: voice_cmd(CMD_LOOP_LEN); break; + case 0x45: voice_cmd(CMD_LOOP_XFADE); break; + case 0x80: voice_cmd(CMD_GET_ADDR); break; + + default: + logerror("%s: unknown GAA cmd %04x (param %04x %04x %04x)\n", machine().describe_context(), + m_gaa_cmd, m_gaa_param[0], m_gaa_param[1], m_gaa_param[2]); + break; + } + + update_pending_irq(); + } + break; + } +} + +/**************************************************************************/ +void fz_pcm_device::gab_w(offs_t offset, u16 data, u16 mem_mask) +{ + m_stream->update(); + + switch (offset & 3) + { + case 0: + case 1: + COMBINE_DATA(&m_gab_param[offset & 3]); + break; + + case 3: + COMBINE_DATA(&m_gab_cmd); + if (ACCESSING_BITS_8_15) + { + m_voice_mask = m_gab_cmd & 0xff; + + switch (m_gab_cmd >> 8) + { + case 0x20: /* TODO: recording rate */ break; + case 0x28: /* TODO: recording cue */ break; + case 0x30: /* TODO: recording start */ break; + case 0x38: /* TODO: recording stop */ break; + case 0x40: voice_cmd(CMD_ADDR_END); break; + case 0x41: voice_cmd(CMD_LOOP_END); break; + case 0x42: voice_cmd(CMD_FLAG_SET); break; + case 0x43: voice_cmd(CMD_FLAG_CLR); break; + case 0x44: voice_cmd(CMD_LOOP_TRACE); break; + + case 0x46: + m_irq_stat &= m_gab_param[0]; + if (!m_irq_stat) + m_irq_cb(0); + break; + + case 0x82: + m_gab_param[0] = 0; + voice_cmd(CMD_GET_STATUS); + break; + + default: + logerror("%s: unknown GAB cmd %04x (param %04x %04x)\n", machine().describe_context(), + m_gab_cmd, m_gab_param[0], m_gab_param[1]); + break; + } + + update_pending_irq(); + } + break; + } +} + +/**************************************************************************/ +void fz_pcm_device::voice_cmd(unsigned cmd) +{ + for (int i = 0; i < 8; i++) + { + if (!BIT(m_voice_mask, i)) + continue; + + voice_t &v = m_voices[i]; + + switch (cmd) + { + case CMD_ADDR_START: + v.m_addr_start = m_gaa_param[1] | (m_gaa_param[2] << 16); + v.m_addr = v.m_addr_start; + v.m_addr_frac = 0; + v.m_sample = v.m_sample_last = 0; + break; + + case CMD_ADDR_END: + v.m_addr_end = m_gab_param[0] | (m_gab_param[1] << 16); + break; + + case CMD_LOOP_START: + v.m_loop_start = m_gaa_param[0] | (m_gaa_param[1] << 16); + v.m_loop_start_fine = m_gaa_param[2] & 0xff; + break; + + case CMD_LOOP_END: + v.m_loop_end = m_gab_param[0] | (m_gab_param[1] << 16); + break; + + case CMD_LOOP_LEN: + // TODO: what is this used for? it only has half the resolution of the actual loop start/end points + v.m_loop_len = (m_gaa_param[0] << 1) | (m_gaa_param[1] << 17); + break; + + case CMD_LOOP_TRACE: + v.m_loop_trace = m_gab_param[0] & 1; + break; + + case CMD_LOOP_XFADE: + v.m_loop_xfade = m_gaa_param[0]; + break; + + case CMD_PITCH: + v.m_pitch = m_gaa_param[0]; + break; + + case CMD_FLAG_SET: + v.m_flags |= m_gab_param[0]; + break; + + case CMD_FLAG_CLR: + v.m_flags &= ~m_gab_param[0]; + break; + + case CMD_GET_ADDR: + m_gaa_param[1] = v.m_addr; + m_gaa_param[2] = v.m_addr >> 16; + break; + + case CMD_GET_STATUS: + // TODO: verify + m_gab_param[0] |= v.m_flags; + break; + } + } +} diff --git a/src/devices/sound/fz_pcm.h b/src/devices/sound/fz_pcm.h new file mode 100644 index 00000000000..0736429da06 --- /dev/null +++ b/src/devices/sound/fz_pcm.h @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:Devin Acker +#ifndef MAME_SOUND_FZ_PCM_H +#define MAME_SOUND_FZ_PCM_H + +#pragma once + +#include "dimemory.h" + +class fz_pcm_device : public device_t, + public device_sound_interface, + public device_memory_interface +{ +public: + static constexpr feature_type imperfect_features() { return feature::SOUND; } + + fz_pcm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + + auto irq_cb() { return m_irq_cb.bind(); } + + u16 gaa_r(offs_t offset); + u16 gab_r(offs_t offset); + + void gaa_w(offs_t offset, u16 data, u16 mem_mask = 0xffff); + void gab_w(offs_t offset, u16 data, u16 mem_mask = 0xffff); + +protected: + // device_t overrides + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + virtual void device_clock_changed() override; + + // device_memory_interface overrides + virtual space_config_vector memory_space_config() const override; + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream) override; + +private: + static constexpr unsigned CLOCKS_PER_SAMPLE = 384; + static constexpr unsigned ADDR_FRAC_SHIFT = 13; + + struct voice_t + { + bool update(); + bool calc_timeout(u32 &samples) const; + + u16 m_flags = 0; + + u32 m_addr_start = 0, m_addr_end = 0; + u32 m_loop_start = 0, m_loop_end = 0; + u8 m_loop_start_fine = 0; + u32 m_loop_len = 0; + u8 m_loop_trace = 1; + u16 m_loop_xfade = 0; + + u16 m_pitch = 0; + u32 m_addr = 0, m_addr_frac = 0; + s16 m_sample = 0, m_sample_last = 0; + }; + + enum + { + CMD_ADDR_START, + CMD_ADDR_END, + CMD_LOOP_START, + CMD_LOOP_END, + CMD_LOOP_LEN, + CMD_LOOP_TRACE, + CMD_LOOP_XFADE, + CMD_PITCH, + CMD_FLAG_SET, + CMD_FLAG_CLR, + CMD_GET_ADDR, + CMD_GET_STATUS, + }; + + enum + { + FLAG_PLAY = 0, + FLAG_LOOP = 1, + FLAG_REVERSE = 3, + FLAG_OUTPUT = 4, + FLAG_INT = 5, + FLAG_XFADE = 6, + }; + + TIMER_CALLBACK_MEMBER(timer_tick); + + void update_pending_irq(); + void voice_cmd(unsigned cmd); + + sound_stream* m_stream; + + devcb_write_line m_irq_cb; + emu_timer *m_irq_timer; + + address_space_config m_ram_config; + memory_access<21, 1, -1, ENDIANNESS_LITTLE>::specific m_ram; + + u16 m_gaa_param[3]; + u16 m_gab_param[2]; + u16 m_gaa_cmd, m_gab_cmd; + u8 m_voice_mask; + + u8 m_irq_stat; + + voice_t m_voices[8]; +}; + +DECLARE_DEVICE_TYPE(FZ_PCM, fz_pcm_device) + +#endif // MAME_SOUND_FZ_PCM_H diff --git a/src/mame/casio/fz1.cpp b/src/mame/casio/fz1.cpp index aea73b07f12..ce23f4a8eb5 100644 --- a/src/mame/casio/fz1.cpp +++ b/src/mame/casio/fz1.cpp @@ -19,6 +19,11 @@ A good deal of hardware and programming info is available courtesy of Rainer Buchty: http://www.buchty.net/casio/ + + TODO: + - add mic & line in/cassette, connect to PCM hardware & filter + - audio input peak detection (connected to AN0) + - filters */ #include "emu.h" @@ -35,6 +40,8 @@ #include "machine/msm6200.h" #include "machine/ram.h" #include "machine/upd765.h" +#include "sound/flt_biquad.h" +#include "sound/fz_pcm.h" #include "video/hd44352.h" #include "emupal.h" @@ -54,6 +61,9 @@ public: : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") , m_subcpu(*this, "subcpu") + , m_pcm(*this, "pcm") + , m_filter(*this, "filter_%u", 1) + , m_line_out(*this, "line_out_%u", 1) , m_ram(*this, "ram") , m_ram_bank(*this, "ram_bank") , m_io(*this, "io%u", 0u) @@ -70,6 +80,9 @@ public: void fz10m(machine_config &config); void fz20m(machine_config &config); + void mem_w(offs_t offset, u8 data) { m_maincpu->space(AS_PROGRAM).write_byte(offset, data); } + u8 mem_r(offs_t offset) { return m_maincpu->space(AS_PROGRAM).read_byte(offset); } + u8 fdc_irq_r() { return m_fdc->get_irq() ? 1 : 0; } void fdc_control_w(u8 data); @@ -98,6 +111,7 @@ private: void gal_w(u8 data); void led_w(u8 data); + void dca_w(offs_t offset, u8 data); // main CPU / key MCU comm methods u8 subcpu_r(); @@ -106,6 +120,10 @@ private: required_device<v50_device> m_maincpu; optional_device<i8049_device> m_subcpu; + required_device<fz_pcm_device> m_pcm; + required_device_array<filter_biquad_device, 8> m_filter; + required_device_array<speaker_device, 8> m_line_out; + required_device<ram_device> m_ram; required_device<address_map_bank_device> m_ram_bank; @@ -131,6 +149,8 @@ private: u8 m_lcd_data; u8 m_lcd_data_phase; u8 m_lcd_nibble; + + u16 m_dca_level[8]; }; /**************************************************************************/ @@ -194,10 +214,10 @@ static INPUT_PORTS_START(fz10m) PORT_BIT(0xff, 0x00, IPT_CUSTOM) // audio input peak level PORT_START("AN5") - PORT_BIT(0xff, 0xff, IPT_POSITIONAL_V) PORT_NAME("Master Volume") PORT_SENSITIVITY(100) PORT_KEYDELTA(10) PORT_CENTERDELTA(0) PORT_PLAYER(2) PORT_CODE_DEC(JOYCODE_Y_DOWN_SWITCH) PORT_CODE_INC(JOYCODE_Y_UP_SWITCH) + PORT_BIT(0xff, 0xff, IPT_POSITIONAL_V) PORT_NAME("Master Volume") PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_CENTERDELTA(0) PORT_PLAYER(2) PORT_CODE_DEC(JOYCODE_Y_DOWN_SWITCH) PORT_CODE_INC(JOYCODE_Y_UP_SWITCH) PORT_START("AN6") - PORT_BIT(0xff, 0x80, IPT_POSITIONAL_V) PORT_NAME("Value") PORT_SENSITIVITY(100) PORT_KEYDELTA(10) PORT_CENTERDELTA(0) PORT_CODE_DEC(JOYCODE_Y_DOWN_SWITCH) PORT_CODE_INC(JOYCODE_Y_UP_SWITCH) + PORT_BIT(0xff, 0x80, IPT_POSITIONAL_V) PORT_NAME("Value") PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_CENTERDELTA(0) PORT_CODE_DEC(JOYCODE_Y_DOWN_SWITCH) PORT_CODE_INC(JOYCODE_Y_UP_SWITCH) INPUT_PORTS_END @@ -356,8 +376,8 @@ void fz1_state::maincpu_map(address_map &map) /**************************************************************************/ void fz1_state::fz10m_io_map(address_map &map) { - // 0x00-07: GAA - // 0x08-0f: GAB + map(0x00, 0x07).rw(m_pcm, FUNC(fz_pcm_device::gaa_r), FUNC(fz_pcm_device::gaa_w)); + map(0x08, 0x0f).rw(m_pcm, FUNC(fz_pcm_device::gab_r), FUNC(fz_pcm_device::gab_w)); map(0x10, 0x13).mirror(0x04).m(m_fdc, FUNC(upd72065_device::map)).umask16(0x00ff); map(0x18, 0x1f).rw(m_io[0], FUNC(i8255_device::read), FUNC(i8255_device::write)).umask16(0x00ff); map(0x20, 0x27).rw(m_io[1], FUNC(i8255_device::read), FUNC(i8255_device::write)).umask16(0x00ff); @@ -366,6 +386,8 @@ void fz1_state::fz10m_io_map(address_map &map) map(0x70, 0x77).w(FUNC(fz1_state::gal_w)).umask16(0x00ff); map(0x78, 0x7f).w(FUNC(fz1_state::led_w)).umask16(0x00ff); // 0x80-bf: DCF/DCA + map(0x80, 0x9f).w(FUNC(fz1_state::dca_w)).umask16(0x00ff); + map(0xa0, 0xbf).ram(); } /**************************************************************************/ @@ -451,6 +473,18 @@ void fz1_state::fz10m(machine_config &config) screen.set_palette("palette"); PALETTE(config, "palette", palette_device::MONOCHROME_INVERTED); + + FZ_PCM(config, m_pcm, 13.824_MHz_XTAL); + m_pcm->irq_cb().set_inputline(m_maincpu, INPUT_LINE_IRQ2); + for (int i = 0; i < 8; i++) + { + SPEAKER(config, m_line_out[i]).front_center(); + m_pcm->add_route(i, m_filter[i], 1.0); + + FILTER_BIQUAD(config, m_filter[i]); + // TODO: these are switched-capacitor lowpass filters + m_filter[i]->add_route(0, m_line_out[i], 1.0 / 8); + } } /**************************************************************************/ @@ -484,6 +518,9 @@ void fz1_state::fz20m(machine_config &config) { fz10m(config); m_maincpu->set_addrmap(AS_IO, &fz1_state::fz20m_io_map); + m_maincpu->out_hreq_cb().set(m_maincpu, FUNC(v50_device::hack_w)); + m_maincpu->in_memr_cb().set(FUNC(fz1_state::mem_r)); + m_maincpu->out_memw_cb().set(FUNC(fz1_state::mem_w)); m_maincpu->in_ior_cb<1>().set("scsi:7:spc", FUNC(mb89352_device::dma_r)); m_maincpu->out_iow_cb<1>().set("scsi:7:spc", FUNC(mb89352_device::dma_w)); @@ -518,6 +555,7 @@ void fz1_state::machine_start() m_sub_p2 = 0; m_ram_bank->space().install_ram(0, m_ram->mask(), m_ram->pointer()); + m_pcm->space().install_ram(0, m_ram->mask() >> 1, m_ram->pointer()); m_fdc->set_rate(500000); m_fdc->set_floppy(m_floppy->get_device()); @@ -531,6 +569,8 @@ void fz1_state::machine_start() save_item(NAME(m_lcd_nibble)); save_item(NAME(m_lcd_data)); save_item(NAME(m_lcd_data_phase)); + + save_item(NAME(m_dca_level)); } /**************************************************************************/ @@ -649,6 +689,17 @@ void fz1_state::led_w(u8 data) } /**************************************************************************/ +void fz1_state::dca_w(offs_t offset, u8 data) +{ + const offs_t num = offset & 7; + if (BIT(offset, 3)) + m_dca_level[num] = (m_dca_level[num] & 0xff) | ((data & 3) << 8); + else + m_dca_level[num] = (m_dca_level[num] & 0x300) | data; + m_filter[num]->set_output_gain(ALL_OUTPUTS, m_dca_level[num] / 1023.0); +} + +/**************************************************************************/ ROM_START( fz1 ) ROM_REGION(0x10000, "maincpu", 0) // "ROM ver.[B]" ROM_LOAD16_BYTE( "fz1s.bin", 0x00000, 0x08000, CRC(b0ba313d) SHA1(45a3660d708f0a584f9f61d04e205a96688f0950) ) @@ -681,6 +732,6 @@ ROM_END } // anonymous namespace -SYST( 1987, fz1, 0, 0, fz1, fz1, fz1_state, empty_init, "Casio", "FZ-1 Digital Sampling Synthesizer", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -SYST( 1987, fz10m, fz1, 0, fz10m, fz10m, fz1_state, empty_init, "Casio", "FZ-10M Digital Sampling Synthesizer Module", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -SYST( 1989, fz20m, fz1, 0, fz20m, fz10m, fz1_state, empty_init, "Casio", "FZ-20M Digital Sampling Synthesizer Module", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +SYST( 1987, fz1, 0, 0, fz1, fz1, fz1_state, empty_init, "Casio", "FZ-1 Digital Sampling Synthesizer", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) +SYST( 1987, fz10m, fz1, 0, fz10m, fz10m, fz1_state, empty_init, "Casio", "FZ-10M Digital Sampling Synthesizer Module", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) +SYST( 1989, fz20m, fz1, 0, fz20m, fz10m, fz1_state, empty_init, "Casio", "FZ-20M Digital Sampling Synthesizer Module", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) |
