mirror of
https://github.com/holub/mame
synced 2025-04-16 05:24:54 +03:00
Clean up the Votrax SC-01[-A] class names and device names. [Lord Nightmare]
This commit is contained in:
parent
1420684c85
commit
c6f0e83ecf
@ -1122,11 +1122,11 @@ end
|
||||
|
||||
---------------------------------------------------
|
||||
-- Votrax SC-01[-A] speech synthesizer
|
||||
--@src/devices/sound/votrax.h,SOUNDS["VOTRAX_SC01"] = true
|
||||
--@src/devices/sound/votrax.h,SOUNDS["VOTRAX_SC01A"] = true
|
||||
--@src/devices/sound/votrax.h,SOUNDS["SC01"] = true
|
||||
--@src/devices/sound/votrax.h,SOUNDS["SC01A"] = true
|
||||
---------------------------------------------------
|
||||
|
||||
if (SOUNDS["VOTRAX_SC01"]~=null or SOUNDS["VOTRAX_SC01A"]~=null) then
|
||||
if (SOUNDS["SC01"]~=null or SOUNDS["SC01A"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/sound/votrax.cpp",
|
||||
MAME_DIR .. "src/devices/sound/votrax.h",
|
||||
|
@ -40,8 +40,8 @@ SOUNDS["DISCRETE"] = true
|
||||
SOUNDS["HC55516"] = true
|
||||
SOUNDS["OKIM6295"] = true
|
||||
SOUNDS["SAMPLES"] = true
|
||||
SOUNDS["SC01"] = true
|
||||
SOUNDS["TMS5220"] = true
|
||||
SOUNDS["VOTRAX_SC01"] = true
|
||||
SOUNDS["YM2151"] = true
|
||||
SOUNDS["YM3812"] = true
|
||||
|
||||
|
@ -33,6 +33,7 @@ namespace {
|
||||
#define AY3_TAG "mockbd_ay3"
|
||||
#define AY4_TAG "mockbd_ay4"
|
||||
#define E2P_TMS_TAG "tms5220"
|
||||
#define MB_SC01_TAG "sc01"
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
@ -87,7 +88,7 @@ protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
required_device<votrax_sc01_device> m_sc01;
|
||||
required_device<sc01a_device> m_sc01a;
|
||||
|
||||
private:
|
||||
void write_via1_cb2(int state);
|
||||
@ -181,10 +182,10 @@ void a2bus_mockingboard_device::device_add_mconfig(machine_config &config)
|
||||
AY8913(config, m_ay2, 1022727);
|
||||
m_ay2->add_route(ALL_OUTPUTS, "rspeaker", 0.5);
|
||||
|
||||
VOTRAX_SC01A(config, m_sc01, 1022727);
|
||||
m_sc01->ar_callback().set(m_via1, FUNC(via6522_device::write_cb1));
|
||||
m_sc01->add_route(ALL_OUTPUTS, "lspeaker", 1.0);
|
||||
m_sc01->add_route(ALL_OUTPUTS, "rspeaker", 1.0);
|
||||
SC01A(config, m_sc01a, 1022727);
|
||||
m_sc01a->ar_callback().set(m_via1, FUNC(via6522_device::write_cb1));
|
||||
m_sc01a->add_route(ALL_OUTPUTS, "lspeaker", 1.0);
|
||||
m_sc01a->add_route(ALL_OUTPUTS, "rspeaker", 1.0);
|
||||
}
|
||||
|
||||
void a2bus_phasor_device::device_add_mconfig(machine_config &config)
|
||||
@ -237,8 +238,8 @@ a2bus_ayboard_device::a2bus_ayboard_device(const machine_config &mconfig, device
|
||||
}
|
||||
|
||||
a2bus_mockingboard_device::a2bus_mockingboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
a2bus_ayboard_device(mconfig, A2BUS_MOCKINGBOARD, tag, owner, clock),
|
||||
m_sc01(*this, "sc01")
|
||||
a2bus_ayboard_device(mconfig, A2BUS_MOCKINGBOARD, tag, owner, clock)
|
||||
, m_sc01a(*this, MB_SC01_TAG)
|
||||
{
|
||||
}
|
||||
|
||||
@ -679,8 +680,8 @@ void a2bus_mockingboard_device::write_via1_cb2(int state)
|
||||
{
|
||||
if ((state == CLEAR_LINE) && (m_last_cb2_state == ASSERT_LINE))
|
||||
{
|
||||
m_sc01->write(m_portb1);
|
||||
m_sc01->inflection_w(m_portb1 >> 6);
|
||||
m_sc01a->write(m_portb1);
|
||||
m_sc01a->inflection_w(m_portb1 >> 6);
|
||||
}
|
||||
m_last_cb2_state = state;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ void c64_speakeasy_cartridge_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
SPEAKER(config, "mono").front_center();
|
||||
|
||||
VOTRAX_SC01A(config, m_votrax, 720000).add_route(ALL_OUTPUTS, "mono", 0.85);
|
||||
SC01A(config, m_votrax, 720000).add_route(ALL_OUTPUTS, "mono", 0.85);
|
||||
}
|
||||
|
||||
|
||||
|
@ -40,7 +40,7 @@ protected:
|
||||
virtual void c64_cd_w(offs_t offset, uint8_t data, int sphi2, int ba, int roml, int romh, int io1, int io2) override;
|
||||
|
||||
private:
|
||||
required_device<votrax_sc01_device> m_votrax;
|
||||
required_device<sc01a_device> m_votrax;
|
||||
};
|
||||
|
||||
|
||||
|
@ -37,7 +37,7 @@ void vic20_speakeasy_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
SPEAKER(config, "mono").front_center();
|
||||
|
||||
VOTRAX_SC01A(config, m_votrax, 720000).add_route(ALL_OUTPUTS, "mono", 0.85);
|
||||
SC01A(config, m_votrax, 720000).add_route(ALL_OUTPUTS, "mono", 0.85);
|
||||
}
|
||||
|
||||
|
||||
|
@ -42,7 +42,7 @@ protected:
|
||||
virtual void vic20_cd_w(offs_t offset, uint8_t data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) override;
|
||||
|
||||
private:
|
||||
required_device<votrax_sc01_device> m_votrax;
|
||||
required_device<sc01a_device> m_votrax;
|
||||
};
|
||||
|
||||
|
||||
|
@ -26,22 +26,22 @@ tp1 = phi clock (tied to f2q rom access)
|
||||
#include "votrax.h"
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(VOTRAX_SC01, votrax_sc01_device, "votrsc01", "Votrax SC-01")
|
||||
DEFINE_DEVICE_TYPE(VOTRAX_SC01A, votrax_sc01a_device, "votrsc01a", "Votrax SC-01-A")
|
||||
DEFINE_DEVICE_TYPE(SC01, sc01_device, "votrsc01", "Votrax SC-01")
|
||||
DEFINE_DEVICE_TYPE(SC01A, sc01a_device, "votrsc01a", "Votrax SC-01-A")
|
||||
|
||||
// ROM definition for the Votrax phone ROM
|
||||
ROM_START( votrax_sc01 )
|
||||
ROM_START( sc01 )
|
||||
ROM_REGION64_LE( 0x200, "internal", 0 )
|
||||
ROM_LOAD( "sc01.bin", 0x000, 0x200, CRC(528d1c57) SHA1(268b5884dce04e49e2376df3e2dc82e852b708c1) )
|
||||
ROM_END
|
||||
|
||||
ROM_START( votrax_sc01a )
|
||||
ROM_START( sc01a )
|
||||
ROM_REGION64_LE( 0x200, "internal", 0 )
|
||||
ROM_LOAD( "sc01a.bin", 0x000, 0x200, CRC(fc416227) SHA1(1d6da90b1807a01b5e186ef08476119a862b5e6d) )
|
||||
ROM_END
|
||||
|
||||
// textual phone names for debugging
|
||||
const char *const votrax_sc01_device::s_phone_table[64] =
|
||||
const char *const sc01_device::s_phone_table[64] =
|
||||
{
|
||||
"EH3", "EH2", "EH1", "PA0", "DT", "A1", "A2", "ZH",
|
||||
"AH2", "I3", "I2", "I1", "M", "N", "B", "V",
|
||||
@ -67,7 +67,7 @@ const char *const votrax_sc01_device::s_phone_table[64] =
|
||||
// the top at 1. The final wave is very similar to the patent
|
||||
// drawing.
|
||||
|
||||
const double votrax_sc01_device::s_glottal_wave[9] =
|
||||
const double sc01_device::s_glottal_wave[9] =
|
||||
{
|
||||
0,
|
||||
-4/7.0,
|
||||
@ -80,13 +80,13 @@ const double votrax_sc01_device::s_glottal_wave[9] =
|
||||
1/7.0
|
||||
};
|
||||
|
||||
votrax_sc01_device::votrax_sc01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: votrax_sc01_device(mconfig, VOTRAX_SC01, tag, owner, clock)
|
||||
sc01_device::sc01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: sc01_device(mconfig, SC01, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
// overridable type for subclass
|
||||
votrax_sc01_device::votrax_sc01_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
|
||||
sc01_device::sc01_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, type, tag, owner, clock),
|
||||
device_sound_interface(mconfig, *this),
|
||||
m_stream(nullptr),
|
||||
@ -95,12 +95,12 @@ votrax_sc01_device::votrax_sc01_device(const machine_config &mconfig, device_typ
|
||||
{
|
||||
}
|
||||
|
||||
votrax_sc01a_device::votrax_sc01a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: votrax_sc01_device(mconfig, VOTRAX_SC01A, tag, owner, clock)
|
||||
sc01a_device::sc01a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: sc01_device(mconfig, SC01A, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
void votrax_sc01_device::write(uint8_t data)
|
||||
void sc01_device::write(uint8_t data)
|
||||
{
|
||||
// flush out anything currently processing
|
||||
m_stream->update();
|
||||
@ -131,7 +131,7 @@ void votrax_sc01_device::write(uint8_t data)
|
||||
// inflection bits
|
||||
//-------------------------------------------------
|
||||
|
||||
void votrax_sc01_device::inflection_w(uint8_t data)
|
||||
void sc01_device::inflection_w(uint8_t data)
|
||||
{
|
||||
// only 2 bits matter
|
||||
data &= 3;
|
||||
@ -148,7 +148,7 @@ void votrax_sc01_device::inflection_w(uint8_t data)
|
||||
// for our sound stream
|
||||
//-------------------------------------------------
|
||||
|
||||
void votrax_sc01_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
|
||||
void sc01_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
|
||||
{
|
||||
for(int i=0; i<outputs[0].samples(); i++) {
|
||||
m_sample_count++;
|
||||
@ -169,14 +169,14 @@ void votrax_sc01_device::sound_stream_update(sound_stream &stream, std::vector<r
|
||||
// internal ROM region
|
||||
//-------------------------------------------------
|
||||
|
||||
const tiny_rom_entry *votrax_sc01_device::device_rom_region() const
|
||||
const tiny_rom_entry *sc01_device::device_rom_region() const
|
||||
{
|
||||
return ROM_NAME( votrax_sc01 );
|
||||
return ROM_NAME( sc01 );
|
||||
}
|
||||
|
||||
const tiny_rom_entry *votrax_sc01a_device::device_rom_region() const
|
||||
const tiny_rom_entry *sc01a_device::device_rom_region() const
|
||||
{
|
||||
return ROM_NAME( votrax_sc01a );
|
||||
return ROM_NAME( sc01a );
|
||||
}
|
||||
|
||||
|
||||
@ -184,14 +184,14 @@ const tiny_rom_entry *votrax_sc01a_device::device_rom_region() const
|
||||
// device_start - handle device startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void votrax_sc01_device::device_start()
|
||||
void sc01_device::device_start()
|
||||
{
|
||||
// initialize internal state
|
||||
m_mainclock = clock();
|
||||
m_sclock = m_mainclock / 18.0;
|
||||
m_cclock = m_mainclock / 36.0;
|
||||
m_stream = stream_alloc(0, 1, m_sclock);
|
||||
m_timer = timer_alloc(FUNC(votrax_sc01_device::phone_tick), this);
|
||||
m_timer = timer_alloc(FUNC(sc01_device::phone_tick), this);
|
||||
|
||||
// reset outputs
|
||||
m_ar_state = ASSERT_LINE;
|
||||
@ -272,7 +272,7 @@ void votrax_sc01_device::device_start()
|
||||
// device_reset - handle device reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void votrax_sc01_device::device_reset()
|
||||
void sc01_device::device_reset()
|
||||
{
|
||||
// Technically, there's no reset in this chip, and initial state
|
||||
// is random. Still, it's a good idea to start it with something
|
||||
@ -327,7 +327,7 @@ void votrax_sc01_device::device_reset()
|
||||
// changes by altering our output frequency
|
||||
//-------------------------------------------------
|
||||
|
||||
void votrax_sc01_device::device_clock_changed()
|
||||
void sc01_device::device_clock_changed()
|
||||
{
|
||||
// lookup the new frequency of the master clock, and update if changed
|
||||
u32 newfreq = clock();
|
||||
@ -354,7 +354,7 @@ void votrax_sc01_device::device_clock_changed()
|
||||
// phone_tick - process transitions
|
||||
//-------------------------------------------------
|
||||
|
||||
TIMER_CALLBACK_MEMBER(votrax_sc01_device::phone_tick)
|
||||
TIMER_CALLBACK_MEMBER(sc01_device::phone_tick)
|
||||
{
|
||||
m_stream->update();
|
||||
|
||||
@ -374,7 +374,7 @@ TIMER_CALLBACK_MEMBER(votrax_sc01_device::phone_tick)
|
||||
m_ar_cb(m_ar_state);
|
||||
}
|
||||
|
||||
void votrax_sc01_device::phone_commit()
|
||||
void sc01_device::phone_commit()
|
||||
{
|
||||
// Only these two counters are reset on phone change, the rest is
|
||||
// free-running.
|
||||
@ -421,14 +421,14 @@ void votrax_sc01_device::phone_commit()
|
||||
}
|
||||
}
|
||||
|
||||
void votrax_sc01_device::interpolate(u8 ®, u8 target)
|
||||
void sc01_device::interpolate(u8 ®, u8 target)
|
||||
{
|
||||
// One step of interpolation, adds one eight of the distance
|
||||
// between the current value and the target.
|
||||
reg = reg - (reg >> 3) + (target << 1);
|
||||
}
|
||||
|
||||
void votrax_sc01_device::chip_update()
|
||||
void sc01_device::chip_update()
|
||||
{
|
||||
// Phone tick counter update. Stopped when ticks reach 16.
|
||||
// Technically the counter keeps updating, but the comparator is
|
||||
@ -481,7 +481,7 @@ void votrax_sc01_device::chip_update()
|
||||
// Closure counter, reset every other tick in theory when not
|
||||
// active (on the extra rom cycle).
|
||||
//
|
||||
// The closure level is immediatly used in the analog path,
|
||||
// The closure level is immediately used in the analog path,
|
||||
// there's no pitch synchronization.
|
||||
|
||||
if(!m_cur_closure && (m_filt_fa || m_filt_va))
|
||||
@ -513,7 +513,7 @@ void votrax_sc01_device::chip_update()
|
||||
// logerror("%s tick %02x.%03x 625=%d 208=%d pitch=%02x.%x ns=%04x ni=%d noise=%d cl=%x.%x clf=%d/%d\n", machine().time().to_string(), m_ticks, m_phonetick, tick_625, tick_208, m_pitch >> 3, m_pitch & 7, m_noise, inp, m_cur_noise, m_closure >> 2, m_closure & 3, m_rom_closure, m_cur_closure);
|
||||
}
|
||||
|
||||
void votrax_sc01_device::filters_commit(bool force)
|
||||
void sc01_device::filters_commit(bool force)
|
||||
{
|
||||
m_filt_fa = m_cur_fa >> 4;
|
||||
m_filt_fc = m_cur_fc >> 4;
|
||||
@ -589,7 +589,7 @@ void votrax_sc01_device::filters_commit(bool force)
|
||||
m_filt_fa, m_filt_va, m_filt_fc, m_filt_f1, m_filt_f2, m_filt_f2q, m_filt_f3);
|
||||
}
|
||||
|
||||
stream_buffer::sample_t votrax_sc01_device::analog_calc()
|
||||
stream_buffer::sample_t sc01_device::analog_calc()
|
||||
{
|
||||
// Voice-only path.
|
||||
// 1. Pick up the pitch wave
|
||||
@ -683,16 +683,16 @@ stream_buffer::sample_t votrax_sc01_device::analog_calc()
|
||||
defined as the ratio Vo/Vi. To do that, you use some properties:
|
||||
|
||||
- The intensity through an element is equal to the voltage
|
||||
difference through the element divided by the impedence
|
||||
difference through the element divided by the impedance
|
||||
|
||||
- The impedence of a resistance is equal to its resistance
|
||||
- The impedance of a resistance is equal to its resistance
|
||||
|
||||
- The impedence of a capacitor is 1/(s*C) where C is its capacitance
|
||||
- The impedance of a capacitor is 1/(s*C) where C is its capacitance
|
||||
|
||||
- The impedence of elements in series is the sum of the impedences
|
||||
- The impedance of elements in series is the sum of their impedances
|
||||
|
||||
- The impedence of elements in parallel is the inverse of the sum of
|
||||
the inverses
|
||||
- The impedance of elements in parallel is the inverse of the sum of
|
||||
their inverses
|
||||
|
||||
- The sum of all intensities flowing into a node is 0 (there's no
|
||||
charge accumulation in a wire)
|
||||
@ -737,7 +737,7 @@ stream_buffer::sample_t votrax_sc01_device::analog_calc()
|
||||
| H(s) = -------------------------
|
||||
| 1 + k[1]*s + k[2]*s^2
|
||||
|
||||
We can always reintroduce the global multipler later, and it's 1 in
|
||||
We can always reintroduce the global multiplier later, and it's 1 in
|
||||
most of our cases anyway.
|
||||
|
||||
The we pose:
|
||||
@ -839,7 +839,7 @@ stream_buffer::sample_t votrax_sc01_device::analog_calc()
|
||||
|
||||
*/
|
||||
|
||||
void votrax_sc01_device::build_standard_filter(double *a, double *b,
|
||||
void sc01_device::build_standard_filter(double *a, double *b,
|
||||
double c1t, // Unswitched cap, input, top
|
||||
double c1b, // Switched cap, input, bottom
|
||||
double c2t, // Unswitched cap, over first amp-op, top
|
||||
@ -894,7 +894,7 @@ void votrax_sc01_device::build_standard_filter(double *a, double *b,
|
||||
H(s) = Vo/Vi = (R1/R0) * (1 / (1 + s.R1.C1))
|
||||
*/
|
||||
|
||||
void votrax_sc01_device::build_lowpass_filter(double *a, double *b,
|
||||
void sc01_device::build_lowpass_filter(double *a, double *b,
|
||||
double c1t, // Unswitched cap, over amp-op, top
|
||||
double c1b) // Switched cap, over amp-op, bottom
|
||||
{
|
||||
@ -947,7 +947,7 @@ void votrax_sc01_device::build_lowpass_filter(double *a, double *b,
|
||||
We assume r0 = r2
|
||||
*/
|
||||
|
||||
void votrax_sc01_device::build_noise_shaper_filter(double *a, double *b,
|
||||
void sc01_device::build_noise_shaper_filter(double *a, double *b,
|
||||
double c1, // Cap over first amp-op
|
||||
double c2t, // Unswitched cap between amp-ops, input, top
|
||||
double c2b, // Switched cap between amp-ops, input, bottom
|
||||
@ -1001,7 +1001,7 @@ void votrax_sc01_device::build_noise_shaper_filter(double *a, double *b,
|
||||
that H(infinity)=1.
|
||||
*/
|
||||
|
||||
void votrax_sc01_device::build_injection_filter(double *a, double *b,
|
||||
void sc01_device::build_injection_filter(double *a, double *b,
|
||||
double c1b, // Switched cap, input, bottom
|
||||
double c2t, // Unswitched cap, over first amp-op, top
|
||||
double c2b, // Switched cap, over first amp-op, bottom
|
||||
|
@ -13,12 +13,12 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
class votrax_sc01_device : public device_t,
|
||||
class sc01_device : public device_t,
|
||||
public device_sound_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
votrax_sc01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
sc01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
auto ar_callback() { return m_ar_cb.bind(); }
|
||||
|
||||
@ -28,7 +28,7 @@ public:
|
||||
|
||||
protected:
|
||||
// overridable type for subclass
|
||||
votrax_sc01_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
sc01_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
// device-level overrides
|
||||
virtual const tiny_rom_entry *device_rom_region() const override;
|
||||
virtual void device_start() override;
|
||||
@ -181,10 +181,10 @@ private:
|
||||
stream_buffer::sample_t analog_calc(); // Compute one more sample
|
||||
};
|
||||
|
||||
class votrax_sc01a_device : public votrax_sc01_device
|
||||
class sc01a_device : public sc01_device
|
||||
{
|
||||
public:
|
||||
votrax_sc01a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
sc01a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual const tiny_rom_entry *device_rom_region() const override;
|
||||
@ -195,7 +195,7 @@ protected:
|
||||
//**************************************************************************
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(VOTRAX_SC01, votrax_sc01_device)
|
||||
DECLARE_DEVICE_TYPE(VOTRAX_SC01A, votrax_sc01a_device)
|
||||
DECLARE_DEVICE_TYPE(SC01, sc01_device)
|
||||
DECLARE_DEVICE_TYPE(SC01A, sc01a_device)
|
||||
|
||||
#endif // MAME_SOUND_VOTRAX_H
|
||||
|
@ -72,8 +72,8 @@ void aussiebyte_state::io_map(address_map &map)
|
||||
map(0x1c, 0x1f).w(FUNC(aussiebyte_state::port1c_w)); // gpebh select
|
||||
map(0x20, 0x23).rw(m_pio2, FUNC(z80pio_device::read), FUNC(z80pio_device::write));
|
||||
map(0x24, 0x27).rw("sio2", FUNC(z80sio_device::ba_cd_r), FUNC(z80sio_device::ba_cd_w));
|
||||
map(0x28, 0x28).r(FUNC(aussiebyte_state::port28_r)).w(m_votrax, FUNC(votrax_sc01_device::write));
|
||||
map(0x2c, 0x2c).w(m_votrax, FUNC(votrax_sc01_device::inflection_w));
|
||||
map(0x28, 0x28).r(FUNC(aussiebyte_state::port28_r)).w(m_votrax, FUNC(sc01a_device::write));
|
||||
map(0x2c, 0x2c).w(m_votrax, FUNC(sc01a_device::inflection_w));
|
||||
map(0x30, 0x30).w(FUNC(aussiebyte_state::address_w));
|
||||
map(0x31, 0x31).r(m_crtc, FUNC(mc6845_device::status_r));
|
||||
map(0x32, 0x32).w(FUNC(aussiebyte_state::register_w));
|
||||
@ -517,7 +517,7 @@ void aussiebyte_state::aussiebyte(machine_config &config)
|
||||
/* sound hardware */
|
||||
SPEAKER(config, "mono").front_center();
|
||||
SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.50);
|
||||
VOTRAX_SC01A(config, m_votrax, 720000); // 720kHz? needs verify
|
||||
SC01A(config, m_votrax, 720000); // 720kHz? needs verify
|
||||
m_votrax->ar_callback().set([this] (bool state) { m_port28 = state ? 0 : 1; });
|
||||
m_votrax->add_route(ALL_OUTPUTS, "mono", 1.00);
|
||||
|
||||
|
@ -150,7 +150,7 @@ private:
|
||||
optional_device<floppy_connector> m_floppy1;
|
||||
required_device<mc6845_device> m_crtc;
|
||||
required_device<speaker_sound_device> m_speaker;
|
||||
required_device<votrax_sc01_device> m_votrax;
|
||||
required_device<sc01a_device> m_votrax;
|
||||
required_device<msm5832_device> m_rtc;
|
||||
};
|
||||
|
||||
|
@ -1367,7 +1367,7 @@ void astrocde_state::wow(machine_config &config)
|
||||
m_astrocade_sound[0]->so_cb<5>().set("outlatch", FUNC(cd4099_device::write_nibble_d0));
|
||||
m_astrocade_sound[0]->so_cb<7>().set(FUNC(astrocde_state::votrax_speech_w));
|
||||
|
||||
VOTRAX_SC01(config, m_votrax, 756000);
|
||||
SC01(config, m_votrax, 756000);
|
||||
|
||||
m_votrax->add_route(0, "f1", 0.65);
|
||||
FILTER_RC(config, "f1").set_lowpass(110e3, 560e-12).add_route(0, "f2", 1.00);
|
||||
@ -1423,7 +1423,7 @@ void astrocde_state::gorf(machine_config &config)
|
||||
|
||||
ASTROCADE_IO(config, m_astrocade_sound[1], ASTROCADE_CLOCK/4).add_route(ALL_OUTPUTS, "lower", 0.35);
|
||||
|
||||
VOTRAX_SC01(config, m_votrax, 756000);
|
||||
SC01(config, m_votrax, 756000);
|
||||
m_votrax->add_route(ALL_OUTPUTS, "upper", 0.45);
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ public:
|
||||
{ }
|
||||
|
||||
required_device<cpu_device> m_maincpu;
|
||||
optional_device<votrax_sc01_device> m_votrax;
|
||||
optional_device<sc01_device> m_votrax;
|
||||
optional_device_array<astrocade_io_device, 2> m_astrocade_sound;
|
||||
optional_shared_ptr<uint8_t> m_videoram;
|
||||
optional_shared_ptr<uint8_t> m_protected_ram;
|
||||
|
@ -117,7 +117,7 @@ private:
|
||||
u8 m_votrax_cmd = 0U;
|
||||
u8 m_io[32]{};
|
||||
required_device<i8080_cpu_device> m_maincpu;
|
||||
optional_device<votrax_sc01_device> m_votrax;
|
||||
optional_device<sc01a_device> m_votrax;
|
||||
};
|
||||
|
||||
class mrblkz80_state : public taito_state
|
||||
@ -564,7 +564,7 @@ void taito_8080::taito4(machine_config &config)
|
||||
taito(config);
|
||||
|
||||
SPEAKER(config, "voxsnd").front_center();
|
||||
VOTRAX_SC01A(config, m_votrax, 720000); // guess
|
||||
SC01A(config, m_votrax, 720000); // guess
|
||||
m_votrax->ar_callback().set(FUNC(taito_8080::votrax_request));
|
||||
m_votrax->add_route(ALL_OUTPUTS, "voxsnd", 2.0);
|
||||
|
||||
|
@ -41,7 +41,7 @@ DEFINE_DEVICE_TYPE(GOTTLIEB_SOUND_REV2, gottlieb_sound_r2_device,
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// PIN 2 SOUND BOARD: 6502 + 6530 + DAC
|
||||
// PIN 2 SOUND BOARD: 6503 + 6530 + DAC
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -262,7 +262,7 @@ void gottlieb_sound_p3_device::device_start()
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// REV 1 SOUND BOARD: 6502 + DAC part number MA-309
|
||||
// REV 1 SOUND BOARD: 6502 + DAC; part number MA-309
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -347,7 +347,7 @@ INPUT_PORTS_END
|
||||
INPUT_PORTS_START( gottlieb_sound_r1_with_votrax )
|
||||
PORT_INCLUDE(gottlieb_sound_r1)
|
||||
PORT_MODIFY("SB1")
|
||||
PORT_BIT( 0x80, 0x80, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER("votrax", votrax_sc01_device, request)
|
||||
PORT_BIT( 0x80, 0x80, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER("votrax", sc01_device, request)
|
||||
INPUT_PORTS_END
|
||||
|
||||
|
||||
@ -398,7 +398,7 @@ void gottlieb_sound_r1_device::device_start()
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// REV 1 SOUND BOARD WITH VOTRAX, part number MA-216 (same pcb as MA-309 but with a Votrax SC-01(-A) and support components populated)
|
||||
// REV 1 SOUND/SPEECH BOARD; part number MA-216 (same PCB as MA-309 above but with a Votrax SC-01(-A) and support components populated)
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -408,7 +408,7 @@ void gottlieb_sound_r1_device::device_start()
|
||||
|
||||
gottlieb_sound_r1_with_votrax_device::gottlieb_sound_r1_with_votrax_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: gottlieb_sound_r1_device(mconfig, GOTTLIEB_SOUND_REV1_VOTRAX, tag, owner, clock)
|
||||
, m_votrax(*this, "votrax")
|
||||
, m_sc01(*this, "votrax")
|
||||
, m_last_speech_clock(0)
|
||||
{
|
||||
}
|
||||
@ -425,10 +425,9 @@ void gottlieb_sound_r1_with_votrax_device::device_add_mconfig(machine_config &co
|
||||
m_dac->reset_routes();
|
||||
m_dac->add_route(ALL_OUTPUTS, *this, 0.20);
|
||||
|
||||
// add the VOTRAX
|
||||
VOTRAX_SC01A(config, m_votrax, 720000); // Note: early boards use an SC-01 (reactor, q-bert test version, maybe some early pinball machines?) while later boards (qbert main release, most pinball machines) use an SC-01-A
|
||||
m_votrax->ar_callback().set("nmi", FUNC(input_merger_device::in_w<1>));
|
||||
m_votrax->add_route(ALL_OUTPUTS, *this, 0.80);
|
||||
SC01A(config, m_sc01, 720000); // Note: early boards use an SC-01 (reactor, q-bert test version, maybe some early pinball machines?) while later boards (qbert main release, most pinball machines) use an SC-01-A
|
||||
m_sc01->ar_callback().set("nmi", FUNC(input_merger_device::in_w<1>));
|
||||
m_sc01->add_route(ALL_OUTPUTS, *this, 0.80);
|
||||
}
|
||||
|
||||
|
||||
@ -459,7 +458,7 @@ void gottlieb_sound_r1_with_votrax_device::device_post_load()
|
||||
gottlieb_sound_r1_device::device_post_load();
|
||||
|
||||
// totally random guesswork; would like to get real measurements on a board
|
||||
m_votrax->set_unscaled_clock(900000 + (m_last_speech_clock - 0xa0) * 9000);
|
||||
m_sc01->set_unscaled_clock(900000 + (m_last_speech_clock - 0xa0) * 9000);
|
||||
}
|
||||
|
||||
|
||||
@ -470,8 +469,8 @@ void gottlieb_sound_r1_with_votrax_device::device_post_load()
|
||||
|
||||
void gottlieb_sound_r1_with_votrax_device::votrax_data_w(uint8_t data)
|
||||
{
|
||||
m_votrax->inflection_w(data >> 6);
|
||||
m_votrax->write(~data & 0x3f);
|
||||
m_sc01->inflection_w(data >> 6);
|
||||
m_sc01->write(~data & 0x3f);
|
||||
}
|
||||
|
||||
|
||||
@ -491,7 +490,7 @@ void gottlieb_sound_r1_with_votrax_device::speech_clock_dac_w(uint8_t data)
|
||||
logerror("clock = %02X\n", data);
|
||||
|
||||
// totally random guesswork; would like to get real measurements on a board
|
||||
m_votrax->set_unscaled_clock(950000 + (data - 0xa0) * 5500);
|
||||
m_sc01->set_unscaled_clock(950000 + (data - 0xa0) * 5500);
|
||||
m_last_speech_clock = data;
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ protected:
|
||||
|
||||
private:
|
||||
// devices
|
||||
required_device<votrax_sc01_device> m_votrax;
|
||||
required_device<sc01_device> m_sc01;
|
||||
|
||||
// internal state
|
||||
uint8_t m_last_speech_clock = 0;
|
||||
|
@ -70,7 +70,7 @@ private:
|
||||
required_device<mm5445_device> m_vfd;
|
||||
required_device<pwm_display_device> m_display;
|
||||
required_device<tms6100_device> m_tms6100;
|
||||
required_device<votrax_sc01_device> m_speech;
|
||||
required_device<sc01a_device> m_speech;
|
||||
required_ioport_array<7> m_inputs;
|
||||
|
||||
bool m_power_on = false;
|
||||
@ -306,7 +306,7 @@ void k28_state::k28(machine_config &config)
|
||||
m_maincpu->p2_in_cb().set(FUNC(k28_state::mcu_p2_r));
|
||||
m_maincpu->p2_out_cb().set(FUNC(k28_state::mcu_p2_w));
|
||||
m_maincpu->prog_out_cb().set("vfd", FUNC(mm5445_device::clock_w));
|
||||
m_maincpu->t1_in_cb().set("speech", FUNC(votrax_sc01_device::request));
|
||||
m_maincpu->t1_in_cb().set("speech", FUNC(sc01a_device::request));
|
||||
|
||||
TMS6100(config, m_tms6100, 3.579545_MHz_XTAL / 15); // CLK tied to 8021 ALE pin
|
||||
|
||||
@ -318,7 +318,7 @@ void k28_state::k28(machine_config &config)
|
||||
|
||||
// sound hardware
|
||||
SPEAKER(config, "mono").front_center();
|
||||
VOTRAX_SC01A(config, "speech", 760000).add_route(ALL_OUTPUTS, "mono", 0.5); // measured 760kHz on its RC pin
|
||||
SC01A(config, "speech", 760000).add_route(ALL_OUTPUTS, "mono", 0.5); // measured 760kHz on its RC pin
|
||||
}
|
||||
|
||||
|
||||
|
@ -45,8 +45,6 @@
|
||||
+--------+
|
||||
see http://bitsavers.org/components/motorola/_dataBooks/1978_Motorola_CMOS_Data_Book.pdf
|
||||
page 488
|
||||
|
||||
TODO: make the two latcha/b flops combine together using input_merger
|
||||
*/
|
||||
|
||||
/* Core includes */
|
||||
@ -118,7 +116,7 @@ private:
|
||||
void mem_map(address_map &map);
|
||||
|
||||
required_device<m6800_cpu_device> m_maincpu;
|
||||
required_device<votrax_sc01_device> m_votrax;
|
||||
required_device<sc01a_device> m_votrax;
|
||||
|
||||
TIMER_CALLBACK_MEMBER(resume_tick);
|
||||
|
||||
@ -471,11 +469,11 @@ void votrhv_state::pho_done(int state)
|
||||
{
|
||||
bool rising_edge = (!m_latcha_in && (state == ASSERT_LINE));
|
||||
m_latcha_in = (state == ASSERT_LINE);
|
||||
if (rising_edge) // HACK: sc-01 is in /ready state now
|
||||
if (rising_edge) // HACK: SC-01-A is in /ready state now
|
||||
{
|
||||
// clock the pho_done flipflop which sets its state to 1
|
||||
m_latcha_flop = true;
|
||||
// HACK: we manually clock the same old phoneme into the sc-01 here, this is a hack since the 1818c the pho_done signal is a free running counter and doesn't stop like the A/R latch on the sc-01 does
|
||||
// HACK: we manually clock the same old phoneme into the SC-01-A here, this is a hack since on the 1818C the pho_done signal is a free running counter and doesn't stop like the A/R latch on the SC-01[-A] does
|
||||
//m_votrax->inflection_w((m_latchy&0xc0)>>6);
|
||||
m_votrax->write(m_latchy&0x3f);
|
||||
m_reset->in_w<0>(1);
|
||||
@ -508,7 +506,7 @@ void votrhv_state::latchx_w(uint8_t data)
|
||||
* |||\----- \ LED select 1/2/3/4
|
||||
* ||\------ /
|
||||
* |\------- Green status LED
|
||||
* \-------- Phoneme silence (ties pitch input of 1818c high thru a diode)
|
||||
* \-------- Phoneme silence (ties pitch input of 1818C high thru a diode)
|
||||
*/
|
||||
m_latchx = data;
|
||||
LOGLTX("latchx written with value of %02x\n", m_latchx);
|
||||
@ -678,7 +676,7 @@ void votrhv_state::votrhv(machine_config &config)
|
||||
/* sound hardware */
|
||||
SPEAKER(config, "mono").front_center();
|
||||
// TEMPORARY HACK until 1818c device is done
|
||||
VOTRAX_SC01A(config, m_votrax, 720000);
|
||||
SC01A(config, m_votrax, 720000);
|
||||
m_votrax->ar_callback().set(FUNC(votrhv_state::pho_done));
|
||||
m_votrax->add_route(ALL_OUTPUTS, "mono", 1.00);
|
||||
}
|
||||
@ -696,14 +694,14 @@ void votrhv_state::hc110(machine_config &config)
|
||||
******************************************************************************/
|
||||
|
||||
ROM_START(hc110)
|
||||
ROM_REGION(0x8000, "maskrom", 0) // 4x EA8316 (2316 equivalent) CMOS Mask ROMs and 2x 512x8 SN74S472 PROMs
|
||||
ROM_REGION(0x8000, "maskrom", 0) // 4x EA8316 (2316 equivalent) CMOS Mask ROMs
|
||||
//ROM_LOAD("ea8316e030.ic9", 0x0000, 0x0800, CRC(fd8cbf7d) SHA1(a2e1406c498a1821cacfcda254534f8e8d6b8260)) // used on older firmware?
|
||||
ROM_LOAD("ea8316e144.ic9", 0x0000, 0x0800, CRC(636415ee) SHA1(9699ea75eed566447d8682f52665b01c1e876981))
|
||||
ROM_LOAD("ea8316e031.ic8", 0x0800, 0x0800, CRC(f2de4e3b) SHA1(0cdc71a4d01d73e403cdf283c6eeb53f97ca5623))
|
||||
ROM_LOAD("ea8316e032.ic7", 0x1000, 0x0800, CRC(5df1270c) SHA1(5c81fcb2bb2c0bf509aa9fc11a92071cd469e407))
|
||||
ROM_LOAD("ea8316e033.ic6", 0x1800, 0x0800, CRC(0d7e246c) SHA1(1454c6c7ef3743320443c7bd1f37df6a25ff7795))
|
||||
|
||||
ROM_REGION(0x0600, "bootrom", 0)
|
||||
ROM_REGION(0x0600, "bootrom", 0) // 2x 512x8 SN74S472 PROMs
|
||||
// ic12 is unpopulated
|
||||
ROM_LOAD("7031r2.sn74s472.ic11", 0x0200, 0x0200, CRC(6ef744c9) SHA1(6a92e520adb3c47b849241648ec2ca4107edfd8f))
|
||||
ROM_LOAD("7031r3.sn74s472.ic10", 0x0400, 0x0200, CRC(0800b0e6) SHA1(9e0481bf6c5feaf6506ac241a2baf83fb9342033))
|
||||
@ -715,13 +713,13 @@ ROM_START(hc110)
|
||||
ROM_END
|
||||
|
||||
ROM_START(hc120) // ic10 and ic11 are Rev B? is there an older revision undumped?
|
||||
ROM_REGION(0x2000, "maskrom", 0) // 4x EA8316 (2316 equivalent) CMOS Mask ROMs and 2x 512x8 SN74S472 PROMs
|
||||
ROM_REGION(0x2000, "maskrom", 0) // 4x EA8316 (2316 equivalent) CMOS Mask ROMs
|
||||
ROM_LOAD("ea8316e030.ic9", 0x0000, 0x0800, CRC(fd8cbf7d) SHA1(a2e1406c498a1821cacfcda254534f8e8d6b8260))
|
||||
ROM_LOAD("ea8316e031.ic8", 0x0800, 0x0800, CRC(f2de4e3b) SHA1(0cdc71a4d01d73e403cdf283c6eeb53f97ca5623))
|
||||
ROM_LOAD("ea8316e032.ic7", 0x1000, 0x0800, CRC(5df1270c) SHA1(5c81fcb2bb2c0bf509aa9fc11a92071cd469e407))
|
||||
ROM_LOAD("ea8316e033.ic6", 0x1800, 0x0800, CRC(0d7e246c) SHA1(1454c6c7ef3743320443c7bd1f37df6a25ff7795))
|
||||
|
||||
ROM_REGION(0x0600, "bootrom", 0)
|
||||
ROM_REGION(0x0600, "bootrom", 0) // 2x 512x8 SN74S472 PROMs
|
||||
// ic12 is unpopulated
|
||||
ROM_LOAD("7037__r2b.sn74s472.ic11", 0x0200, 0x0200, CRC(44de1bb1) SHA1(53e6811baf37af5da0648e906fee6c6acf259b82))
|
||||
ROM_LOAD("7037__r3b.sn74s472.ic10", 0x0400, 0x0200, CRC(688be8c7) SHA1(c9bdc7472cabcdddc23e63f45afbfcc835bb8f69))
|
||||
|
@ -354,8 +354,12 @@ z80 pinout:
|
||||
39 A9-> to eproms and module bus
|
||||
40 A10-> to eproms and module bus
|
||||
|
||||
Note: it seems originally that /NMI and /HALT may have been tied together (and perhaps to VCC through a resistor) and NOT directly connected to VCc, so when the HALT opcode was executed it would immediately trigger an NMI and reset the cpu.
|
||||
BUT, at least on the revision C 1872 CPU pcb, they are both tied directly to VCC, disabling this behavior.
|
||||
Note: It seems originally that /NMI and /HALT may have been tied together
|
||||
(and perhaps to VCC through a resistor) and NOT directly connected to VCC,
|
||||
so when the HALT opcode was executed it would immediately trigger an NMI
|
||||
and the CPU could handle this specifically.
|
||||
However, at least on the revision C 1872 CPU pcb, they are both tied
|
||||
directly to VCC, disabling this behavior.
|
||||
*****************************************************************************/
|
||||
|
||||
/* Core includes */
|
||||
@ -568,9 +572,9 @@ void votrpss_state::votrpss(machine_config &config)
|
||||
SPEAKER(config, "mono").front_center();
|
||||
ay8910_device &ay(AY8910(config, "ay", XTAL(8'000'000)/4)); /* 2.000 MHz, verified */
|
||||
ay.port_b_read_callback().set_ioport("DSW1");
|
||||
ay.port_a_write_callback().set("votrax", FUNC(votrax_sc01_device::write));
|
||||
ay.port_a_write_callback().set("votrax", FUNC(sc01a_device::write));
|
||||
ay.add_route(ALL_OUTPUTS, "mono", 0.25);
|
||||
VOTRAX_SC01A(config, "votrax", 720000).add_route(ALL_OUTPUTS, "mono", 1.00); /* the actual SC-01-A clock is generated by an R/C circuit PWMed by the timer1 output of the 8253 PIT to adjust the resistance, to allow for fine pitch control. 8253 Timer2 is used to PWM an analog switch on the output of the SC-01 to adjust the volume.*/
|
||||
SC01A(config, "votrax", 720000).add_route(ALL_OUTPUTS, "mono", 1.00); /* the actual SC-01-A clock is generated by an R/C circuit PWMed by the timer1 output of the 8253 PIT to adjust the resistance, to allow for fine pitch control. 8253 Timer2 is used to PWM an analog switch on the output of the SC-01-A to adjust the volume.*/
|
||||
|
||||
/* Devices */
|
||||
GENERIC_TERMINAL(config, m_terminal, 0);
|
||||
|
@ -23,9 +23,6 @@
|
||||
* A0 switches the ACIA between status/command, and data in/out.
|
||||
*
|
||||
*
|
||||
* ToDo:
|
||||
* - Votrax device needs considerable improvement in sound quality.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/* Core includes */
|
||||
@ -48,7 +45,7 @@ public:
|
||||
votrtnt_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: driver_device(mconfig, type, tag)
|
||||
, m_maincpu(*this, "maincpu")
|
||||
, m_votrax(*this, "votrax")
|
||||
, m_sc01a(*this, "votrax")
|
||||
, m_clock(*this, "acia_clock")
|
||||
{ }
|
||||
|
||||
@ -60,7 +57,7 @@ private:
|
||||
void mem_map(address_map &map);
|
||||
|
||||
required_device<m6802_cpu_device> m_maincpu;
|
||||
required_device<votrax_sc01_device> m_votrax;
|
||||
required_device<sc01a_device> m_sc01a;
|
||||
required_device<clock_device> m_clock;
|
||||
};
|
||||
|
||||
@ -88,7 +85,7 @@ void votrtnt_state::mem_map(address_map &map)
|
||||
map.unmap_value_high();
|
||||
map(0x0000, 0x03ff).mirror(0x9c00).ram(); /* RAM, 2114*2 (0x400 bytes) mirrored 4x */
|
||||
map(0x2000, 0x2001).mirror(0x9ffe).rw("acia", FUNC(acia6850_device::read), FUNC(acia6850_device::write));
|
||||
map(0x4000, 0x4000).mirror(0x9fff).w(m_votrax, FUNC(votrax_sc01_device::write));
|
||||
map(0x4000, 0x4000).mirror(0x9fff).w(m_sc01a, FUNC(sc01a_device::write));
|
||||
map(0x6000, 0x6fff).mirror(0x9000).rom().region("maincpu",0); /* ROM in potted block */
|
||||
}
|
||||
|
||||
@ -163,9 +160,9 @@ void votrtnt_state::votrtnt(machine_config &config)
|
||||
|
||||
/* sound hardware */
|
||||
SPEAKER(config, "mono").front_center();
|
||||
VOTRAX_SC01A(config, m_votrax, 720000); // 720kHz? needs verify
|
||||
m_votrax->ar_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
|
||||
m_votrax->add_route(ALL_OUTPUTS, "mono", 1.00);
|
||||
SC01A(config, m_sc01a, 720000); // 720kHz? needs verify
|
||||
m_sc01a->ar_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
|
||||
m_sc01a->add_route(ALL_OUTPUTS, "mono", 1.00);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user