summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/acorn_vidc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/acorn_vidc.cpp')
-rw-r--r--src/devices/machine/acorn_vidc.cpp166
1 files changed, 98 insertions, 68 deletions
diff --git a/src/devices/machine/acorn_vidc.cpp b/src/devices/machine/acorn_vidc.cpp
index 2179c64d787..ae4021e412f 100644
--- a/src/devices/machine/acorn_vidc.cpp
+++ b/src/devices/machine/acorn_vidc.cpp
@@ -12,8 +12,10 @@
* nebulus: 20 lines off with aa310;
* lotustc2: abuses color flipping;
* quazer: needs in-flight DMA;
- - improve sound DAC writes;
- - subclass this for VIDC20 emulation (RiscPC);
+ - move DAC handling into a separate sub-device(s),
+ particularly needed for proper VIDC20 mixing and likely for fixing aliasing
+ issues in VIDC10;
+ - complete VIDC20 emulation (RiscPC/ssfindo.cpp);
- Are CRTC values correct? VGA modes have a +1 in display line;
**********************************************************************************************/
@@ -117,7 +119,7 @@ void acorn_vidc10_device::device_add_mconfig(machine_config &config)
}
}
-u32 acorn_vidc10_device::palette_entries() const
+u32 acorn_vidc10_device::palette_entries() const noexcept
{
return 0x100+0x10+4; // 8bpp + 1/2/4bpp + 2bpp for cursor
}
@@ -146,9 +148,6 @@ void acorn_vidc10_device::device_config_complete()
void acorn_vidc10_device::device_start()
{
- m_vblank_cb.resolve_safe();
- m_sound_drq_cb.resolve_safe();
-
for (int i = 0; i < entries(); i++)
set_pen_color(i, rgb_t::black());
@@ -166,8 +165,8 @@ void acorn_vidc10_device::device_start()
save_pointer(NAME(m_cursor_vram), m_cursor_vram_size);
save_pointer(NAME(m_stereo_image), m_sound_max_channels);
- m_video_timer = timer_alloc(TIMER_VIDEO);
- m_sound_timer = timer_alloc(TIMER_SOUND);
+ m_video_timer = timer_alloc(FUNC(acorn_vidc10_device::vblank_timer), this);
+ m_sound_timer = timer_alloc(FUNC(acorn_vidc10_device::sound_drq_timer), this);
// generate u255 law lookup table
// cfr. page 48 of the VIDC20 manual, page 33 of the VIDC manual
@@ -208,28 +207,21 @@ void acorn_vidc10_device::device_reset()
{
m_cursor_enable = false;
memset(m_stereo_image, 4, m_sound_max_channels);
- for (int ch=0;ch<m_sound_max_channels;ch++)
+ for (int ch = 0; ch < m_sound_max_channels; ch++)
refresh_stereo_image(ch);
m_video_timer->adjust(attotime::never);
m_sound_timer->adjust(attotime::never);
}
-//-------------------------------------------------
-// device_timer - device-specific timer
-//-------------------------------------------------
+TIMER_CALLBACK_MEMBER(acorn_vidc10_device::vblank_timer)
+{
+ m_vblank_cb(ASSERT_LINE);
+ screen_vblank_line_update();
+}
-void acorn_vidc10_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(acorn_vidc10_device::sound_drq_timer)
{
- switch (id)
- {
- case TIMER_VIDEO:
- m_vblank_cb(ASSERT_LINE);
- screen_vblank_line_update();
- break;
- case TIMER_SOUND:
- m_sound_drq_cb(ASSERT_LINE);
- break;
- }
+ m_sound_drq_cb(ASSERT_LINE);
}
//**************************************************************************
@@ -303,13 +295,11 @@ void acorn_vidc10_device::write(offs_t offset, u32 data, u32 mem_mask)
inline void acorn_vidc10_device::update_4bpp_palette(u16 index, u32 paldata)
{
- int r,g,b;
-
// TODO: for TV Tuner we need to output this, also check if cursor mode actually sets this up for offset = 0
// i = (paldata & 0x1000) >> 12; //supremacy bit
- b = (paldata & 0x0f00) >> 8;
- g = (paldata & 0x00f0) >> 4;
- r = (paldata & 0x000f) >> 0;
+ int b = (paldata & 0x0f00) >> 8;
+ int g = (paldata & 0x00f0) >> 4;
+ int r = (paldata & 0x000f) >> 0;
set_pen_color(index, pal4bit(r), pal4bit(g), pal4bit(b) );
screen().update_partial(screen().vpos());
@@ -317,11 +307,11 @@ inline void acorn_vidc10_device::update_4bpp_palette(u16 index, u32 paldata)
void acorn_vidc10_device::pal_data_display_w(offs_t offset, u32 data)
{
- update_4bpp_palette(offset+0x100, data);
+ update_4bpp_palette(offset + 0x100, data);
//printf("%02x: %01x %01x %01x [%d]\n",offset,r,g,b,screen().vpos());
// 8bpp
- for(int idx=0;idx<0x100;idx+=0x10)
+ for (int idx = 0; idx < 0x100; idx += 0x10)
{
int b = ((data & 0x700) >> 8) | ((idx & 0x80) >> 4);
int g = ((data & 0x030) >> 4) | ((idx & 0x60) >> 3);
@@ -415,8 +405,8 @@ inline void acorn_vidc10_device::refresh_stereo_image(u8 channel)
const float left_gain[8] = { 1.0f, 2.0f, 1.66f, 1.34f, 1.0f, 0.66f, 0.34f, 0.0f };
const float right_gain[8] = { 1.0f, 0.0f, 0.34f, 0.66f, 1.0f, 1.34f, 1.66f, 2.0f };
- m_lspeaker->set_input_gain(channel,left_gain[m_stereo_image[channel]]*m_sound_input_gain);
- m_rspeaker->set_input_gain(channel,right_gain[m_stereo_image[channel]]*m_sound_input_gain);
+ m_lspeaker->set_input_gain(channel, left_gain[m_stereo_image[channel]] * m_sound_input_gain);
+ m_rspeaker->set_input_gain(channel, right_gain[m_stereo_image[channel]] * m_sound_input_gain);
//printf("%d %f %f\n",channel,m_lspeaker->input(channel).gain(),m_rspeaker->input(channel).gain());
}
@@ -442,8 +432,7 @@ void acorn_vidc10_device::sound_frequency_w(u32 data)
void acorn_vidc10_device::write_dac(u8 channel, u8 data)
{
- int16_t res;
- res = m_ulaw_lookup[data];
+ int16_t res = m_ulaw_lookup[data];
m_dac[channel & 7]->write(res);
}
@@ -454,7 +443,7 @@ void acorn_vidc10_device::refresh_sound_frequency()
{
// TODO: Range is between 3 and 256 usecs
double sndhz = 1e6 / ((m_sound_frequency_latch & 0xff) + 2);
- sndhz /= m_sound_internal_divider;
+ sndhz /= get_dac_mode() == true ? 2.0 : 8.0;
m_sound_timer->adjust(attotime::zero, 0, attotime::from_hz(sndhz));
//printf("VIDC: audio DMA start, sound freq %d, sndhz = %f\n", (m_crtc_regs[0xc0] & 0xff)-2, sndhz);
}
@@ -479,17 +468,17 @@ void acorn_vidc10_device::draw(bitmap_rgb32 &bitmap, const rectangle &cliprect,
//printf("%d %d %d %d\n",ystart, ysize, cliprect.min_y, cliprect.max_y);
- for (int srcy = raster_ystart; srcy<ysize; srcy++)
+ for (int srcy = raster_ystart; srcy < ysize; srcy++)
{
- int dsty = (srcy + ystart)*(m_crtc_interlace+1);
- for (int srcx = 0; srcx<xsize; srcx++)
+ int dsty = (srcy + ystart) * (m_crtc_interlace+1);
+ for (int srcx = 0; srcx < xsize; srcx++)
{
u8 pen = vram[srcx + srcy * xsize];
int dstx = (srcx*xchar_size) + xstart;
- for (int xi=0;xi<xchar_size;xi++)
+ for (int xi = 0; xi < xchar_size; xi++)
{
- u16 dot = ((pen>>(xi*pen_byte_size)) & pen_mask);
+ u16 dot = (pen >> (xi * pen_byte_size)) & pen_mask;
if (is_cursor == true && dot == 0)
continue;
dot += pen_base;
@@ -503,29 +492,25 @@ void acorn_vidc10_device::draw(bitmap_rgb32 &bitmap, const rectangle &cliprect,
u32 acorn_vidc10_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int xstart,ystart,xend,yend;
- int xsize,ysize;
- int calc_dxs = 0,calc_dxe = 0;
-
/* border color */
bitmap.fill(pen(m_pal_border_base), cliprect);
/* define X display area through BPP mode register */
- calc_dxs = m_crtc_regs[CRTC_HDSR];
- calc_dxe = m_crtc_regs[CRTC_HDER];
+ int calc_dxs = m_crtc_regs[CRTC_HDSR];
+ int calc_dxe = m_crtc_regs[CRTC_HDER];
/* now calculate display clip rectangle start/end areas */
- xstart = (calc_dxs)-m_crtc_regs[CRTC_HBSR];
- ystart = (m_crtc_regs[CRTC_VDSR]-m_crtc_regs[CRTC_VBSR]);
- xend = (calc_dxe)+xstart;
- yend = (m_crtc_regs[CRTC_VDER] * (m_crtc_interlace+1))+ystart;
+ int xstart = (calc_dxs)-m_crtc_regs[CRTC_HBSR];
+ int ystart = (m_crtc_regs[CRTC_VDSR]-m_crtc_regs[CRTC_VBSR]);
+ int xend = (calc_dxe)+xstart;
+ int yend = (m_crtc_regs[CRTC_VDER] * (m_crtc_interlace+1))+ystart;
/* disable the screen if display params are invalid */
if(xstart > xend || ystart > yend)
return 0;
- xsize = calc_dxe-calc_dxs;
- ysize = m_crtc_regs[CRTC_VDER]-m_crtc_regs[CRTC_VDSR];
+ int xsize = calc_dxe-calc_dxs;
+ int ysize = m_crtc_regs[CRTC_VDER]-m_crtc_regs[CRTC_VDSR];
if (xsize <= 0 || ysize <= 0)
return 0;
@@ -544,7 +529,7 @@ u32 acorn_vidc10_device::screen_update(screen_device &screen, bitmap_rgb32 &bitm
return 0;
}
-READ_LINE_MEMBER(acorn_vidc10_device::flyback_r)
+int acorn_vidc10_device::flyback_r()
{
int vert_pos = screen().vpos();
if (vert_pos <= m_crtc_regs[CRTC_VDSR] * (m_crtc_interlace+1))
@@ -556,7 +541,11 @@ READ_LINE_MEMBER(acorn_vidc10_device::flyback_r)
return false;
}
-// VIDC20
+/*
+ *
+ * VIDC20 overrides
+ *
+ */
void arm_vidc20_device::regs_map(address_map &map)
{
@@ -564,6 +553,7 @@ void arm_vidc20_device::regs_map(address_map &map)
map(0x10, 0x1f).w(FUNC(arm_vidc20_device::vidc20_pal_data_index_w));
map(0x40, 0x7f).w(FUNC(arm_vidc20_device::vidc20_pal_data_cursor_w));
map(0x80, 0x9f).w(FUNC(arm_vidc20_device::vidc20_crtc_w));
+// map(0xa0, 0xa7) stereo image
map(0xb0, 0xb0).w(FUNC(arm_vidc20_device::vidc20_sound_frequency_w));
map(0xb1, 0xb1).w(FUNC(arm_vidc20_device::vidc20_sound_control_w));
map(0xd0, 0xdf).w(FUNC(arm_vidc20_device::fsynreg_w));
@@ -572,6 +562,7 @@ void arm_vidc20_device::regs_map(address_map &map)
arm_vidc20_device::arm_vidc20_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: acorn_vidc10_device(mconfig, ARM_VIDC20, tag, owner, clock, 2)
+ , m_dac32(*this, "serial_dac_%u", 0)
{
m_space_config = address_space_config("regs_space", ENDIANNESS_LITTLE, 32, 8, -2, address_map_constructor(FUNC(arm_vidc20_device::regs_map), this));
m_pal_4bpp_base = 0x000;
@@ -583,8 +574,20 @@ arm_vidc20_device::arm_vidc20_device(const machine_config &mconfig, const char *
void arm_vidc20_device::device_add_mconfig(machine_config &config)
{
acorn_vidc10_device::device_add_mconfig(config);
- // ...
- // TODO: for simplicity we may as well add separate DACs for 32-bit mode
+
+ // FIXME: disable DACs for the time being
+ // so that it won't mixin with QS1000 source for ssfindo.cpp games
+ for (int i = 0; i < m_sound_max_channels; i++)
+ {
+ m_dac[i]->reset_routes();
+ m_dac[i]->add_route(0, m_lspeaker, 0.0);
+ m_dac[i]->add_route(0, m_rspeaker, 0.0);
+ }
+
+ // For simplicity we separate DACs for 32-bit mode
+ // TODO: how stereo image copes with this if at all?
+ DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_dac32[0], 0).add_route(ALL_OUTPUTS, m_lspeaker, 0.25);
+ DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_dac32[1], 0).add_route(ALL_OUTPUTS, m_rspeaker, 0.25);
}
void arm_vidc20_device::device_config_complete()
@@ -599,7 +602,7 @@ void arm_vidc20_device::device_config_complete()
screen().set_screen_update(*this, FUNC(arm_vidc20_device::screen_update));
}
-u32 arm_vidc20_device::palette_entries() const
+u32 arm_vidc20_device::palette_entries() const noexcept
{
return 0x100+4; // 8bpp + 2bpp for cursor
}
@@ -623,22 +626,31 @@ void arm_vidc20_device::device_reset()
// TODO: sensible defaults
m_vco_r_modulo = 1;
m_vco_v_modulo = 1;
+
+ // make sure DACs don't output any undefined behaviour for now
+ // (will cause wild DC offset in ssfindo.cpp games)
+ for (int ch = 0; ch < 8; ch ++)
+ write_dac(ch, 0);
+
+ write_dac32(0, 0);
+ write_dac32(1, 0);
}
-void arm_vidc20_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+inline void arm_vidc20_device::refresh_stereo_image(u8 channel)
{
- acorn_vidc10_device::device_timer(timer, id, param, ptr);
+ // TODO: set_input_gain hampers with both QS1000 and serial DAC mode
+ // Best option is to move the legacy DAC handling into a separate device,
+ // make it proper 8 channel output while clients are responsible of mix-ins
}
+
inline void arm_vidc20_device::update_8bpp_palette(u16 index, u32 paldata)
{
- int r,g,b;
-
// TODO: ext hookup, supremacy plus other stuff according to the manual
// ext = (paldata & 0x0f000000) >> 24;
- b = (paldata & 0x00ff0000) >> 16;
- g = (paldata & 0x0000ff00) >> 8;
- r = (paldata & 0x000000ff) >> 0;
+ int b = (paldata & 0x00ff0000) >> 16;
+ int g = (paldata & 0x0000ff00) >> 8;
+ int r = (paldata & 0x000000ff) >> 0;
set_pen_color(index, r, g, b );
screen().update_partial(screen().vpos());
@@ -732,7 +744,7 @@ void arm_vidc20_device::vidc20_control_w(u32 data)
// ---- --00: VCLK
// ---- --01: HCLK
// ---- --10: RCLK ("recommended" 24 MHz)
- // ---- --11: undefined, prolly same as RCLK
+ // ---- --11: undefined, probably same as RCLK
m_pixel_source = data & 3;
m_pixel_rate = (data & 0x1c) >> 2;
// (data & 0x700) >> 8 FIFO load
@@ -750,6 +762,26 @@ void arm_vidc20_device::vidc20_sound_control_w(u32 data)
{
// TODO: VIDC10 mode, ext clock bit 0
m_dac_serial_mode = BIT(data, 1);
+
+ if (m_dac_serial_mode)
+ {
+ m_dac32[0]->set_output_gain(0, 1.0);
+ m_dac32[1]->set_output_gain(0, 1.0);
+
+ for (int ch = 0; ch < m_sound_max_channels; ch++)
+ m_dac[ch]->set_output_gain(0, 0.0);
+ }
+ else
+ {
+ m_dac32[0]->set_output_gain(0, 0.0);
+ m_dac32[1]->set_output_gain(0, 0.0);
+
+ for (int ch = 0; ch < m_sound_max_channels; ch++)
+ {
+ //m_dac[ch]->set_output_gain(0, 0.0);
+ refresh_stereo_image(ch);
+ }
+ }
}
void arm_vidc20_device::vidc20_sound_frequency_w(u32 data)
@@ -761,7 +793,7 @@ void arm_vidc20_device::vidc20_sound_frequency_w(u32 data)
void arm_vidc20_device::write_dac32(u8 channel, u16 data)
{
- m_dac[channel & 1]->write(data);
+ m_dac32[channel & 1]->write(data);
}
bool arm_vidc20_device::get_dac_mode()
@@ -774,5 +806,3 @@ u32 arm_vidc20_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap
// TODO: support for true color modes
return acorn_vidc10_device::screen_update(screen, bitmap, cliprect);
}
-
-