summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/video/i8244.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/video/i8244.cpp')
-rw-r--r--src/devices/video/i8244.cpp1180
1 files changed, 604 insertions, 576 deletions
diff --git a/src/devices/video/i8244.cpp b/src/devices/video/i8244.cpp
index a2d142b0410..b92b7ce9c56 100644
--- a/src/devices/video/i8244.cpp
+++ b/src/devices/video/i8244.cpp
@@ -1,11 +1,19 @@
// license:BSD-3-Clause
-// copyright-holders:Wilbert Pol
+// copyright-holders:Peter Trauner, Wilbert Pol, hap
+// thanks-to:Kevin Horton
/***************************************************************************
- i8244.c
+Intel 8244 (NTSC)/8245 (PAL) Graphics and sound chip
+Exclusively used in Odyssey 2 series.
- Intel 8244 (NTSC)/8245 (PAL) Graphics and sound chip
+Features summary:
+- 9*8 grid
+- major system (predefined 8*7 objects, 12 single + 4 quads)
+- minor system (4 user-defined 8*8 sprites)
+- collision detection between all layers
+- 1-bit sound from rotating shift register
+See Odyssey 2 driver file for known problems.
***************************************************************************/
@@ -15,124 +23,34 @@
#include "screen.h"
-
// device type definition
DEFINE_DEVICE_TYPE(I8244, i8244_device, "i8244", "Intel 8244")
DEFINE_DEVICE_TYPE(I8245, i8245_device, "i8245", "Intel 8245")
-// Kevtris verified that the data below matches a dump
-// taken from a real chip.
-static const uint8_t c_shape[0x40 * 8] =
-{
- 0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00, // 0
- 0x18,0x38,0x18,0x18,0x18,0x18,0x3C,0x00,
- 0x3C,0x66,0x0C,0x18,0x30,0x60,0x7E,0x00,
- 0x7C,0xC6,0x06,0x3C,0x06,0xC6,0x7C,0x00,
- 0xCC,0xCC,0xCC,0xFE,0x0C,0x0C,0x0C,0x00,
- 0xFE,0xC0,0xC0,0x7C,0x06,0xC6,0x7C,0x00,
- 0x7C,0xC6,0xC0,0xFC,0xC6,0xC6,0x7C,0x00,
- 0xFE,0x06,0x0C,0x18,0x30,0x60,0xC0,0x00,
- 0x7C,0xC6,0xC6,0x7C,0xC6,0xC6,0x7C,0x00,
- 0x7C,0xC6,0xC6,0x7E,0x06,0xC6,0x7C,0x00,
- 0x00,0x18,0x18,0x00,0x18,0x18,0x00,0x00,
- 0x18,0x7E,0x58,0x7E,0x1A,0x7E,0x18,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x3C,0x66,0x0C,0x18,0x18,0x00,0x18,0x00,
- 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xFE,0x00,
- 0xFC,0xC6,0xC6,0xFC,0xC0,0xC0,0xC0,0x00,
- 0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,
- 0xC6,0xC6,0xC6,0xD6,0xFE,0xEE,0xC6,0x00,
- 0xFE,0xC0,0xC0,0xF8,0xC0,0xC0,0xFE,0x00,
- 0xFC,0xC6,0xC6,0xFC,0xD8,0xCC,0xC6,0x00,
- 0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00,
- 0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,
- 0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,
- 0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,
- 0x7C,0xC6,0xC6,0xC6,0xDE,0xCC,0x76,0x00,
- 0x7C,0xC6,0xC0,0x7C,0x06,0xC6,0x7C,0x00,
- 0xFC,0xC6,0xC6,0xC6,0xC6,0xC6,0xFC,0x00,
- 0xFE,0xC0,0xC0,0xF8,0xC0,0xC0,0xC0,0x00,
- 0x7C,0xC6,0xC0,0xC0,0xCE,0xC6,0x7E,0x00,
- 0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,
- 0x06,0x06,0x06,0x06,0x06,0xC6,0x7C,0x00,
- 0xC6,0xCC,0xD8,0xF0,0xD8,0xCC,0xC6,0x00,
- 0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x00,
- 0x7E,0x06,0x0C,0x18,0x30,0x60,0x7E,0x00,
- 0xC6,0xC6,0x6C,0x38,0x6C,0xC6,0xC6,0x00,
- 0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,
- 0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x00,
- 0xFC,0xC6,0xC6,0xFC,0xC6,0xC6,0xFC,0x00,
- 0xC6,0xEE,0xFE,0xD6,0xC6,0xC6,0xC6,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,
- 0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,
- 0x00,0x66,0x3C,0x18,0x3C,0x66,0x00,0x00,
- 0x00,0x18,0x00,0x7E,0x00,0x18,0x00,0x00,
- 0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00,
- 0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00,
- 0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0x00,
- 0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x00,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,
- 0xCE,0xDB,0xDB,0xDB,0xDB,0xDB,0xCE,0x00,
- 0x00,0x00,0x3C,0x7E,0x7E,0x7E,0x3C,0x00,
- 0x1C,0x1C,0x18,0x1E,0x18,0x18,0x1C,0x00,
- 0x1C,0x1C,0x18,0x1E,0x18,0x34,0x26,0x00,
- 0x38,0x38,0x18,0x78,0x18,0x2C,0x64,0x00,
- 0x38,0x38,0x18,0x78,0x18,0x18,0x38,0x00,
- 0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00,
- 0x18,0x3C,0x7E,0xFF,0xFF,0x18,0x18,0x00,
- 0x03,0x07,0x0F,0x1F,0x3F,0x7F,0xFF,0x00,
- 0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,0xFF,0x00,
- 0x38,0x38,0x12,0xFE,0xB8,0x28,0x6C,0x00,
- 0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x00,
- 0x00,0x00,0x0C,0x08,0x08,0x7F,0x3E,0x00,
- 0x00,0x03,0x63,0xFF,0xFF,0x18,0x08,0x00,
- 0x00,0x00,0x00,0x10,0x38,0xFF,0x7E,0x00
-};
-
-
-// Background and grid information is stored in RGB format
-// while the character and sprite colors are stored in BGR
-// format.
-static const uint8_t bgr2rgb[8] =
-{
- 0x00, 0x04, 0x02, 0x06, 0x01, 0x05, 0x03, 0x07
-};
-
-
//-------------------------------------------------
// i8244_device - constructor
//-------------------------------------------------
-i8244_device::i8244_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : i8244_device(mconfig, I8244, tag, owner, clock, i8244_device::LINES)
-{
-}
+i8244_device::i8244_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ i8244_device(mconfig, I8244, tag, owner, clock)
+{ }
+i8244_device::i8244_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, type, tag, owner, clock),
+ device_sound_interface(mconfig, *this),
+ device_video_interface(mconfig, *this),
+ m_irq_func(*this),
+ m_charset(*this, "cgrom")
+{ }
-i8244_device::i8244_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int lines)
- : device_t(mconfig, type, tag, owner, clock)
- , device_sound_interface(mconfig, *this)
- , device_video_interface(mconfig, *this)
- , m_irq_func(*this)
- , m_postprocess_func(*this)
- , m_start_vpos(START_Y)
- , m_start_vblank(START_Y + SCREEN_HEIGHT)
- , m_screen_lines(lines)
-{
-}
-
-
-i8245_device::i8245_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : i8244_device(mconfig, I8245, tag, owner, clock, i8245_device::LINES)
-{
-}
+i8245_device::i8245_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ i8244_device(mconfig, I8245, tag, owner, clock)
+{ }
//-------------------------------------------------
-// device_config_complete - perform any
-// operations now that the configuration is
-// complete
+// device configuration
//-------------------------------------------------
void i8244_device::device_config_complete()
@@ -141,200 +59,245 @@ void i8244_device::device_config_complete()
return;
if (!screen().refresh_attoseconds())
- screen().set_raw(clock(), LINE_CLOCKS, START_ACTIVE_SCAN, END_ACTIVE_SCAN, m_screen_lines, START_Y, START_Y + SCREEN_HEIGHT);
+ screen().set_raw(clock()*2, m_htotal, m_cropx, m_cropx + m_width, m_vtotal, m_cropy, m_cropy + m_height);
}
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void i8244_device::device_start()
+void i8244_device::set_default_params()
{
- // Let the screen create our temporary bitmap with the screen's dimensions
- screen().register_screen_bitmap(m_tmp_bitmap);
+ m_htotal = 455;
+ m_vtotal = 263;
+ m_vblank_start = 242;
+ m_vblank_end = 0;
+ m_hblank_start = 366;
+ m_hblank_end = 453;
+ m_bgate_start = 413;
+}
- m_line_timer = timer_alloc(TIMER_LINE);
- m_line_timer->adjust( screen().time_until_pos(1, START_ACTIVE_SCAN ), 0, screen().scan_period() );
+void i8245_device::set_default_params()
+{
+ // this timing is partially derived externally, 8245 on the PAL console is set to slave mode in vblank (M/S pin)
+ m_htotal = 456;
+ m_vtotal = 313;
+ m_vblank_start = 242;
+ m_vblank_end = 312;
+ m_hblank_start = 366;
+ m_hblank_end = 454;
+ m_bgate_start = 414;
+}
- m_hblank_timer = timer_alloc(TIMER_HBLANK);
- m_hblank_timer->adjust( screen().time_until_pos(1, END_ACTIVE_SCAN + 18 ), 0, screen().scan_period() );
+i8244_device &i8244_device::set_screen_size(int width, int height, int cropx, int cropy)
+{
+ m_width = width;
+ m_height = height;
+ m_cropx = cropx;
+ m_cropy = cropy;
- m_irq_func.resolve_safe();
- m_postprocess_func.resolve_safe();
+ set_default_params();
- // allocate a stream
- m_stream = stream_alloc( 0, 1, clock()/(LINE_CLOCKS*4) );
-
- // register our state
- save_pointer(NAME(m_vdc.reg), 0x100);
- save_item(NAME(m_sh_count));
- save_item(NAME(m_x_beam_pos));
- save_item(NAME(m_y_beam_pos));
- save_item(NAME(m_control_status));
- save_item(NAME(m_collision_status));
- save_item(NAME(m_iff));
+ return *this;
}
//-------------------------------------------------
-// device_reset - device-specific reset
+// internal character set rom
//-------------------------------------------------
-void i8244_device::device_reset()
-{
- memset(m_vdc.reg, 0, 0x100);
+ROM_START( i8244 )
+ ROM_REGION( 0x200, "cgrom", 0 )
+ ROM_LOAD( "charset_i8244.bin", 0x0000, 0x0200, CRC(b46a3f31) SHA1(415382715455b47b69401b3d60bd8f0036dd7fef) )
+ROM_END
- m_sh_count = 0;
- m_x_beam_pos = 0;
- m_y_beam_pos = 0;
- m_control_status = 0;
- m_collision_status = 0;
- m_iff = 0;
+const tiny_rom_entry *i8244_device::device_rom_region() const
+{
+ return ROM_NAME( i8244 );
}
+//-------------------------------------------------
+// i8244_palette - default palette
+//-------------------------------------------------
+
void i8244_device::i8244_palette(palette_device &palette) const
{
+ // RGB output, before any NTSC/PAL RF encoder
static constexpr rgb_t i8244_colors[16] =
{
{ 0x00, 0x00, 0x00 }, // i r g b
- { 0x00, 0x00, 0xaa }, // i r g B
- { 0x00, 0xaa, 0x00 }, // i r G b
- { 0x00, 0xaa, 0xaa }, // i r G B
- { 0xaa, 0x00, 0x00 }, // i R g b
- { 0xaa, 0x00, 0xaa }, // i R g B
- { 0xaa, 0xaa, 0x00 }, // i R G b
- { 0xaa, 0xaa, 0xaa }, // i R G B
- { 0x55, 0x55, 0x55 }, // I r g b
- { 0x55, 0x55, 0xff }, // I r g B
- { 0x55, 0xff, 0x55 }, // I r G b
- { 0x55, 0xff, 0xff }, // I r G B
- { 0xff, 0x55, 0x55 }, // I R g b
- { 0xff, 0x55, 0xff }, // I R g B
- { 0xff, 0xff, 0x55 }, // I R G b
+ { 0xb6, 0x00, 0x00 }, // i R g b
+ { 0x00, 0xb6, 0x00 }, // i r G b
+ { 0xb6, 0xb6, 0x00 }, // i R G b
+ { 0x00, 0x00, 0xb6 }, // i r g B
+ { 0xb6, 0x00, 0xb6 }, // i R g B
+ { 0x00, 0xb6, 0xb6 }, // i r G B
+ { 0xb6, 0xb6, 0xb6 }, // i R G B
+ { 0x49, 0x49, 0x49 }, // I r g b
+ { 0xff, 0x49, 0x49 }, // I R g b
+ { 0x49, 0xff, 0x49 }, // I r G b
+ { 0xff, 0xff, 0x49 }, // I R G b
+ { 0x49, 0x49, 0xff }, // I r g B
+ { 0xff, 0x49, 0xff }, // I R g B
+ { 0x49, 0xff, 0xff }, // I r G B
{ 0xff, 0xff, 0xff } // I R G B
};
- palette.set_pen_colors( 0, i8244_colors );
+ palette.set_pen_colors(0, i8244_colors);
}
-void i8244_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- int vpos = screen().vpos();
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
- switch ( id )
- {
- case TIMER_LINE:
- // handle i824x line timer
- render_scanline(vpos);
- break;
+void i8244_device::device_start()
+{
+ // allocate timers
+ m_vblank_timer = timer_alloc(FUNC(i8244_device::vblank_start), this);
+ m_vblank_timer->adjust(screen().time_until_pos(m_vblank_start, m_hblank_start - 1), 0, screen().frame_period());
- case TIMER_HBLANK:
- // handle i824x HBlank timer
- if ( vpos < m_start_vpos - 1 )
- {
- return;
- }
+ m_hblank_timer = timer_alloc(FUNC(i8244_device::hblank_start), this);
+ m_hblank_timer->adjust(screen().time_until_pos(0, m_hblank_start), 0, screen().scan_period());
- if ( vpos < m_start_vblank - 1 )
- {
- m_control_status |= 0x01;
- }
- break;
- }
-}
+ // allocate a stream
+ m_stream = stream_alloc(0, 1, clock());
+ // zerofill
+ memset(m_vdc.reg, 0, 0x100);
+ memset(m_collision_map, 0, sizeof(m_collision_map));
+ memset(m_priority_map, 0, sizeof(m_priority_map));
-int i8244_device::get_y_beam()
-{
- int y = screen().vpos() - m_start_vpos;
+ m_x_beam_pos = 0;
+ m_y_beam_pos = 0;
+ m_control_status = 0;
+ m_collision_status = 0;
+ m_sh_written = false;
+ m_sh_pending = false;
+ m_sh_prescaler = 0;
+ m_sh_count = 0;
+ m_sh_output = 0;
+ m_sh_duty = 0;
- // The Y register becomes 0 only when the VBlank signal is turned off!
- if ( y < 0 || ( y == 0 && screen().hpos() < 366+42 ) )
- {
- y += m_screen_lines;
- }
+ // register our state
+ save_pointer(NAME(m_vdc.reg), 0x100);
+ save_item(NAME(m_collision_map));
+ save_item(NAME(m_priority_map));
- return y;
+ save_item(NAME(m_x_beam_pos));
+ save_item(NAME(m_y_beam_pos));
+ save_item(NAME(m_control_status));
+ save_item(NAME(m_collision_status));
+ save_item(NAME(m_sh_written));
+ save_item(NAME(m_sh_pending));
+ save_item(NAME(m_sh_prescaler));
+ save_item(NAME(m_sh_count));
+ save_item(NAME(m_sh_output));
+ save_item(NAME(m_sh_duty));
}
-int i8244_device::get_x_beam()
-{
- int x = screen().hpos() - START_ACTIVE_SCAN;
+//-------------------------------------------------
+// timer events
+//-------------------------------------------------
- if ( x < 0 )
- {
- x += LINE_CLOCKS;
- }
+TIMER_CALLBACK_MEMBER(i8244_device::hblank_start)
+{
+ // hblank starts (updates sound shift register)
+ sound_update();
+}
- return x >> 1;
+TIMER_CALLBACK_MEMBER(i8244_device::vblank_start)
+{
+ // vblank starts
+ m_control_status |= 0x08;
+ m_irq_func(ASSERT_LINE);
}
-offs_t i8244_device::fix_register_mirrors( offs_t offset )
+/***************************************************************************
+ I/O
+***************************************************************************/
+
+offs_t i8244_device::fix_register_mirrors(offs_t offset)
{
- // registers $40,$41 are mirrored at $44,$45, $48,$49, and $4C,$4D
- if ( ( offset & 0xF2 ) == 0x40 )
+ // quad x/y registers are mirrored for each quad
+ if ((offset & 0xc2) == 0x40)
{
- offset &= ~0x0C;
+ offset &= ~0x0c;
}
// registers $A0-$AF are mirrored at $B0-$BF
- if ( ( offset & 0xF0 ) == 0xB0 )
+ if ((offset & 0xe0) == 0xa0)
{
offset &= ~0x10;
}
- return offset;
+ return offset & 0xff;
}
-READ8_MEMBER(i8244_device::read)
+u8 i8244_device::read(offs_t offset)
{
- uint8_t data;
+ u8 data;
+
+ offset = fix_register_mirrors(offset);
- offset = fix_register_mirrors( offset );
+ // update screen before accessing video status registers
+ if (offset == 0xa1 || offset == 0xa2)
+ screen().update_now();
switch (offset)
{
case 0xa1:
- data = m_control_status & 0xFE;
- m_iff = 0;
- m_irq_func(CLEAR_LINE);
- m_control_status &= ~0x08;
- if ( hblank() )
+ {
+ data = m_control_status;
+
+ // hstatus (not same as hblank), goes high at falling edge of X=0x70
+ int h = screen().hpos();
+ data |= (h >= 225 && h < m_bgate_start && get_y_beam() <= m_vblank_start) ? 1 : 0;
+
+ // position strobe status
+ data |= m_vdc.s.control & 0x02;
+
+ if (!machine().side_effects_disabled())
{
- data |= 1;
+ m_irq_func(CLEAR_LINE);
+ m_control_status &= ~0xcc;
}
+
break;
+ }
case 0xa2:
data = m_collision_status;
- m_collision_status = 0;
+ if (!machine().side_effects_disabled())
+ m_collision_status = 0;
break;
case 0xa4:
- if (m_vdc.s.control & VDC_CONTROL_REG_STROBE_XY)
- {
- m_y_beam_pos = get_y_beam();
- }
- data = m_y_beam_pos;
+ data = (m_vdc.s.control & 0x02) ? get_y_beam() : m_y_beam_pos;
break;
-
case 0xa5:
- if ((m_vdc.s.control & VDC_CONTROL_REG_STROBE_XY))
- {
- m_x_beam_pos = get_x_beam();
- }
- data = m_x_beam_pos;
+ data = (m_vdc.s.control & 0x02) ? get_x_beam() : m_x_beam_pos;
+ break;
+
+ case 0x02: case 0x06: case 0x0a: case 0x0e:
+ case 0xa3: case 0xa7: case 0xa8: case 0xa9:
+ // write-only registers
+ data = 0;
break;
default:
data = m_vdc.reg[offset];
+
+ // object x/y/attr registers are not accessible when display is enabled
+ // (sprite shape registers still are)
+ if (offset < 0x80 && m_vdc.s.control & 0x20)
+ data = 0;
+
+ // grid registers are not accessible when grid is enabled
+ else if (offset >= 0xc0 && m_vdc.s.control & 0x08)
+ data = 0;
+
break;
}
@@ -342,466 +305,531 @@ READ8_MEMBER(i8244_device::read)
}
-WRITE8_MEMBER(i8244_device::write)
+void i8244_device::write(offs_t offset, u8 data)
{
- offset = fix_register_mirrors( offset );
+ offset = fix_register_mirrors(offset);
- /* Update the sound */
- if( offset >= 0xa7 && offset <= 0xaa )
- {
- m_stream->update();
- }
+ // object x/y/attr registers are not accessible when display is enabled
+ // (sprite shape registers still are)
+ if (offset < 0x80 && m_vdc.s.control & 0x20)
+ return;
- if (offset == 0xa0)
+ // grid registers are not accessible when grid is enabled
+ // grid registers >= 0xf0 are unmapped
+ if ((offset >= 0xc0 && m_vdc.s.control & 0x08) || offset >= 0xf0)
+ return;
+
+ // update screen before accessing video registers
+ if ((offset <= 0xa0 || offset == 0xa2 || offset == 0xa3) && data != m_vdc.reg[offset])
+ screen().update_now();
+
+ // color registers d4-d7 are not connected
+ if ((offset & 0x83) == 0x03)
+ data &= 0x0f;
+
+ // major systems Y CAM d0 is not connected!
+ if (offset >= 0x10 && (offset & 0x83) == 0x00)
+ data &= ~0x01;
+
+ // horizontal grid high byte only d0 is connected
+ if ((offset & 0xf0) == 0xd0)
+ data &= 0x01;
+
+ switch (offset)
{
- if ( ( m_vdc.s.control & VDC_CONTROL_REG_STROBE_XY )
- && !(data & VDC_CONTROL_REG_STROBE_XY))
- {
- /* Toggling strobe bit, tuck away values */
- m_x_beam_pos = get_x_beam();
- m_y_beam_pos = get_y_beam();
- }
+ case 0xa0:
+ if ((m_vdc.s.control & 0x02) && !(data & 0x02))
+ {
+ // toggling strobe bit, tuck away values
+ m_x_beam_pos = get_x_beam();
+ m_y_beam_pos = get_y_beam();
+ }
+ break;
+
+ case 0xa7: case 0xa8: case 0xa9:
+ m_sh_written = true;
+ break;
+
+ case 0xaa:
+ // update the sound
+ m_stream->update();
+ data &= ~0x40;
+ break;
+
+ case 0xa1: case 0xa4: case 0xa5:
+ // read-only registers
+ return;
+
+ case 0x03: case 0x07: case 0x0b: case 0x0f:
+ case 0xa6: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
+ case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
+ case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
+ case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
+ // unused registers
+ return;
+
+ default:
+ break;
}
m_vdc.reg[offset] = data;
}
-READ_LINE_MEMBER(i8244_device::vblank)
+int i8244_device::get_y_beam()
{
- if ( screen().vpos() > m_start_vpos && screen().vpos() < m_start_vblank )
- {
- return 0;
- }
- return 1;
+ int h = screen().hpos();
+ int v = screen().vpos();
+
+ // Y resets before hblank on the first scanline
+ if (v == 0 && h < m_hblank_start)
+ v = m_vtotal;
+
+ // Y increments on BG sync
+ if (h >= m_bgate_start)
+ v++;
+
+ return (v > 263) ? 263 : v;
}
-READ_LINE_MEMBER(i8244_device::hblank)
+int i8244_device::get_x_beam()
{
- int hpos = screen().hpos();
- int vpos = screen().vpos();
+ return screen().hpos() >> 1;
+}
- if ( hpos >= START_ACTIVE_SCAN && hpos < END_ACTIVE_SCAN )
- {
- return 0;
- }
- // Before active area?
- if ( vpos < m_start_vpos - 1 )
- {
- return 0;
- }
+int i8244_device::vblank()
+{
+ int h = screen().hpos();
+ int v = screen().vpos();
+ int start = m_vblank_start;
+ int end = m_vblank_end;
- // During active area?
- if ( vpos < m_start_vblank - 1 )
- {
+ if ((v == start && h >= (m_hblank_start - 1)) || (v == end && h <= (m_hblank_start - 1)))
return 1;
- }
- // After active area
- return 0;
+ if (end < start)
+ return (v > start || v < end) ? 1 : 0;
+ else
+ return (v > start && v < end) ? 1 : 0;
}
-void i8244_device::render_scanline(int vpos)
+int i8244_device::hblank()
{
- // Some local constants for this method
- //static const uint8_t COLLISION_SPRITE_0 = 0x01;
- //static const uint8_t COLLISION_SPRITE_1 = 0x02;
- //static const uint8_t COLLISION_SPRITE_2 = 0x04;
- //static const uint8_t COLLISION_SPRITE_3 = 0x08;
- static const uint8_t COLLISION_VERTICAL_GRID = 0x10;
- static const uint8_t COLLISION_HORIZ_GRID_DOTS = 0x20;
- //static const uint8_t COLLISION_EXTERNAL_UNUSED = 0x40;
- static const uint8_t COLLISION_CHARACTERS = 0x80;
-
- uint8_t collision_map[160];
-
- if ( vpos == m_start_vpos )
- {
- m_control_status &= ~0x08;
- }
+ int h = screen().hpos();
+ int start = m_hblank_start;
+ int end = m_hblank_end;
- if ( m_start_vpos < vpos && vpos < m_start_vblank )
+ if (end < start)
+ return (h >= start || h < end) ? 1 : 0;
+ else
+ return (h >= start && h < end) ? 1 : 0;
+}
+
+
+void i8244_device::write_cx(int x, bool cx)
+{
+ if (cx)
{
- rectangle rect;
- int scanline = vpos - m_start_vpos;
+ u8 colx = m_collision_map[x];
- m_control_status &= ~ 0x01;
+ // check if we collide with an already drawn source object
+ if (colx)
+ {
+ // external overlap interrupt
+ if (m_vdc.s.control & 0x10)
+ {
+ m_irq_func(ASSERT_LINE);
+ m_control_status |= 0x40;
+ }
- /* Draw a line */
- rect.set(START_ACTIVE_SCAN, END_ACTIVE_SCAN - 1, vpos, vpos);
- m_tmp_bitmap.fill( (m_vdc.s.color >> 3) & 0x7, rect );
+ if (colx & m_vdc.s.collision)
+ m_collision_status |= 0x40;
+ }
+
+ // check if an already drawn object would collide with us
+ if (m_vdc.s.collision & 0x40)
+ m_collision_status |= colx;
+ }
+}
- /* Clear collision map */
- memset( collision_map, 0, sizeof( collision_map ) );
- /* Display grid if enabled */
- if ( m_vdc.s.control & 0x08 )
+/***************************************************************************
+ RENDER
+***************************************************************************/
+
+void i8244_device::draw_grid(int scanline, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ u16 color = bitswap<4>(m_vdc.s.color,6,0,1,2);
+ int x_grid_offset = 13;
+ int y_grid_offset = 24;
+ int width = 16;
+ int height = 24;
+ int w = (m_vdc.s.control & 0x80) ? width : 2;
+
+ // draw horizontal part of the grid
+ for (int y = 0; y < 9; y++)
+ {
+ if (y_grid_offset + y * height <= scanline && scanline < y_grid_offset + y * height + 3)
{
- uint16_t color = ( m_vdc.s.color & 7 ) | ( ( m_vdc.s.color >> 3 ) & 0x08 );
- int x_grid_offset = 8;
- int y_grid_offset = 24;
- int width = 16;
- int height = 24;
- int w = ( m_vdc.s.control & 0x80 ) ? width : 2;
-
- /* Draw horizontal part of grid */
- for ( int j = 1, y = 0; y < 9; y++, j <<= 1 )
+ for (int i = 0; i < 9; i++)
{
- if ( y_grid_offset + y * height <= scanline && scanline < y_grid_offset + y * height + 3 )
+ if (BIT(m_vdc.s.hgrid[1][i] << 8 | m_vdc.s.hgrid[0][i], y))
{
- for ( int i = 0; i < 9; i++ )
+ for (int k = 0; k < width + 2; k++)
{
- if ( ( m_vdc.s.hgrid[0][i] & j ) || ( m_vdc.s.hgrid[1][i] & ( j >> 8 ) ) )
+ int x = (x_grid_offset + i * width + k) * 2;
+
+ for (int px = x; px < x + 2; px++)
{
- for ( int k = 0; k < width + 2; k++ )
+ if (cliprect.contains(px, scanline))
{
- int px = x_grid_offset + i * width + k;
-
- if ( px < 160 )
- {
- collision_map[ px ] |= COLLISION_HORIZ_GRID_DOTS;
- m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * px ) = color;
- m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * px + 1 ) = color;
- }
+ m_collision_map[px] |= 0x20;
+ bitmap.pix(scanline, px) = color;
}
}
}
}
}
+ }
+ }
- /* Draw vertical part of grid */
- for( int j = 1, y = 0; y < 8; y++, j <<= 1 )
+ // draw dots part of the grid
+ if (m_vdc.s.control & 0x40)
+ {
+ for (int y = 0; y < 9; y++)
+ {
+ if (y_grid_offset + y * height <= scanline && scanline < y_grid_offset + y * height + 3)
{
- if ( y_grid_offset + y * height <= scanline && scanline < y_grid_offset + ( y + 1 ) * height )
+ for (int i = 0; i < 10; i++)
{
- for ( int i = 0; i < 10; i++ )
+ for (int k = 0; k < 2; k++)
{
- if ( m_vdc.s.vgrid[i] & j )
+ int x = (x_grid_offset + i * width + k) * 2;
+
+ for (int px = x; px < x + 2; px++)
{
- for ( int k = 0; k < w; k++ )
+ if (cliprect.contains(px, scanline))
{
- int px = x_grid_offset + i * width + k;
-
- if ( px < 160 )
- {
- /* Check if we collide with an already drawn source object */
- if ( collision_map[ px ] & m_vdc.s.collision )
- {
- m_collision_status |= COLLISION_VERTICAL_GRID;
- }
- /* Check if an already drawn object would collide with us */
- if ( COLLISION_VERTICAL_GRID & m_vdc.s.collision && collision_map[ px ] )
- {
- m_collision_status |= collision_map[ px ];
- }
- collision_map[ px ] |= COLLISION_VERTICAL_GRID;
- m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * px ) = color;
- m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * px + 1 ) = color;
- }
+ m_collision_map[px] |= 0x20;
+ bitmap.pix(scanline, px) = color;
}
}
}
}
}
}
+ }
- /* Display objects if enabled */
- if ( m_vdc.s.control & 0x20 )
+ // draw vertical part of the grid
+ for (int j = 1, y = 0; y < 8; y++, j <<= 1)
+ {
+ if (y_grid_offset + y * height <= scanline && scanline < y_grid_offset + (y + 1) * height)
{
- /* Regular foreground objects */
- for ( int i = 0; i < ARRAY_LENGTH( m_vdc.s.foreground ); i++ )
+ for (int i = 0; i < 10; i++)
{
- int y = m_vdc.s.foreground[i].y & 0xFE;
- int height = 8 - ( ( ( y >> 1 ) + m_vdc.s.foreground[i].ptr ) & 7 );
-
- if ( y >= 0x0E && y <= scanline && scanline < y + height * 2 )
+ if (m_vdc.s.vgrid[i] & j)
{
- uint16_t color = 8 + bgr2rgb[ ( ( m_vdc.s.foreground[i].color >> 1 ) & 0x07 ) ];
- int offset = ( m_vdc.s.foreground[i].ptr | ( ( m_vdc.s.foreground[i].color & 0x01 ) << 8 ) ) + ( y >> 1 ) + ( ( scanline - y ) >> 1 );
- uint8_t chr = c_shape[ offset & 0x1FF ];
- int x = m_vdc.s.foreground[i].x;
-
- for ( uint8_t m = 0x80; m > 0; m >>= 1, x++ )
+ for (int k = 0; k < w; k++)
{
- if ( chr & m )
+ int x = (x_grid_offset + i * width + k) * 2;
+
+ for (int px = x; px < x + 2; px++)
{
- if ( x >= 0 && x < 160 )
+ if (cliprect.contains(px, scanline))
{
- /* Check if we collide with an already drawn source object */
- if ( collision_map[ x ] & m_vdc.s.collision )
- {
- m_collision_status |= COLLISION_CHARACTERS;
- }
- /* Check if an already drawn object would collide with us */
- if ( COLLISION_CHARACTERS & m_vdc.s.collision && collision_map[ x ] )
- {
- m_collision_status |= collision_map[ x ];
- }
- collision_map[ x ] |= COLLISION_CHARACTERS;
- m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * x ) = color;
- m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * x + 1 ) = color;
+ m_collision_map[px] |= 0x10;
+ bitmap.pix(scanline, px) = color;
}
}
}
}
}
+ }
+ }
+}
+
- /* Quad objects */
- for ( int i = 0; i < ARRAY_LENGTH( m_vdc.s.quad ); i++ )
+void i8244_device::major_pixel(u8 index, int x, int y, u8 pixel, u16 color, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ for (int px = x; px < x + 2; px++)
+ {
+ if (cliprect.contains(px, y))
+ {
+ u8 colx = m_collision_map[px];
+
+ // check collision with self
+ if (index < m_priority_map[px])
{
- int y = m_vdc.s.quad[i].single[0].y;
- int height = 8;
+ m_control_status |= 0x80;
- if ( y <= scanline && scanline < y + height * 2 )
- {
- int x = m_vdc.s.quad[i].single[0].x;
+ // TODO: much more complex on actual console (weird glitches happen)
+ if (colx & 0x80)
+ continue;
+ }
+ else
+ m_priority_map[px] = index;
- // Charaecter height is always determined by the height of the 4th character
- int char_height = 8 - ( ( ( y >> 1 ) + m_vdc.s.quad[i].single[3].ptr ) & 7 );
+ if (pixel)
+ {
+ // check if we collide with an already drawn source object
+ if (m_vdc.s.collision & colx)
+ m_collision_status |= 0x80;
- for ( int j = 0; j < ARRAY_LENGTH( m_vdc.s.quad[0].single ); j++, x += 8 )
- {
- if ( y <= scanline && scanline < y + char_height * 2 )
- {
- uint16_t color = 8 + bgr2rgb[ ( ( m_vdc.s.quad[i].single[j].color >> 1 ) & 0x07 ) ];
- int offset = ( m_vdc.s.quad[i].single[j].ptr | ( ( m_vdc.s.quad[i].single[j].color & 0x01 ) << 8 ) ) + ( y >> 1 ) + ( ( scanline - y ) >> 1 );
- uint8_t chr = c_shape[ offset & 0x1FF ];
+ // check if an already drawn object would collide with us
+ if (m_vdc.s.collision & 0x80)
+ m_collision_status |= colx;
- for ( uint8_t m = 0x80; m > 0; m >>= 1, x++ )
- {
- if ( chr & m )
- {
- if ( x >= 0 && x < 160 )
- {
- /* Check if we collide with an already drawn source object */
- if ( collision_map[ x ] & m_vdc.s.collision )
- {
- m_collision_status |= COLLISION_CHARACTERS;
- }
- /* Check if an already drawn object would collide with us */
- if ( COLLISION_CHARACTERS & m_vdc.s.collision && collision_map[ x ] )
- {
- m_collision_status |= collision_map[ x ];
- }
- collision_map[ x ] |= COLLISION_CHARACTERS;
- m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * x ) = color;
- m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * x + 1 ) = color;
- }
- }
- }
- }
- else
- {
- x += 8;
- }
- }
- }
+ m_collision_map[px] |= 0x80;
+ bitmap.pix(y, px) = color;
}
+ }
+ }
+}
- /* Sprites */
- for ( int i = 0; i < ARRAY_LENGTH( m_vdc.s.sprites ); i++ )
+
+void i8244_device::draw_major(int scanline, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ // quad objects
+ for (int i = std::size(m_vdc.s.quad) - 1; i >= 0; i--)
+ {
+ int y = m_vdc.s.quad[i].single[0].y;
+ if (is_ntsc() && y < 0xe)
+ continue;
+
+ // character height is always determined by the height of the 4th character
+ int height = 7 - (((y >> 1) + m_vdc.s.quad[i].single[3].ptr) & 7);
+ if (height == 0) height = 8;
+
+ if (y <= scanline && scanline < y + height * 2)
+ {
+ int x = (m_vdc.s.quad[i].single[0].x + 5) * 2;
+
+ for (int j = 0; j < std::size(m_vdc.s.quad[0].single); j++, x += 16)
{
- int y = m_vdc.s.sprites[i].y;
- int height = 8;
+ int offset = (m_vdc.s.quad[i].single[j].ptr | ((m_vdc.s.quad[i].single[j].color & 0x01) << 8)) + (y >> 1) + ((scanline - y) >> 1);
- if ( m_vdc.s.sprites[i].color & 4 )
- {
- /* Zoomed sprite */
- if ( y <= scanline && scanline < y + height * 4 )
- {
- uint16_t color = 8 + bgr2rgb[ ( ( m_vdc.s.sprites[i].color >> 3 ) & 0x07 ) ];
- uint8_t chr = m_vdc.s.shape[i][ ( ( scanline - y ) >> 2 ) ];
- int x = m_vdc.s.sprites[i].x;
- int x_shift = 0;
+ u16 color = 8 + ((m_vdc.s.quad[i].single[j].color >> 1) & 0x07);
+ for (int cx = 0; cx < 8; cx++, x += 2)
+ major_pixel(4 * j + 16 * i + 0x40, x, scanline, BIT(m_charset[offset & 0x1ff], cx ^ 7), color, bitmap, cliprect);
+ }
+ }
+ }
- switch ( m_vdc.s.sprites[i].color & 0x03 )
- {
- case 1: // Xg attribute set
- x_shift = 2;
- break;
- case 2: // S attribute set
- x_shift = ( ( ( scanline - y ) >> 1 ) & 0x01 ) ^ 0x01;
- break;
- case 3: // Xg and S attributes set
- x_shift = ( ( scanline - y ) >> 1 ) & 0x01;
- break;
- }
- x_shift <<= 1;
+ // regular foreground objects
+ for (int i = std::size(m_vdc.s.foreground) - 1; i >= 0; i--)
+ {
+ int y = m_vdc.s.foreground[i].y;
+ if (is_ntsc() && y < 0xe)
+ continue;
- for ( uint8_t m = 0x01; m > 0; m <<= 1, x += 2 )
- {
- if ( chr & m )
- {
- if ( x >= 0 && x < 160 )
- {
- /* Check if we collide with an already drawn source object */
- if ( collision_map[ x ] & m_vdc.s.collision )
- {
- m_collision_status |= ( 1 << i );
- }
- /* Check if an already drawn object would collide with us */
- if ( ( 1 << i ) & m_vdc.s.collision && collision_map[ x ] )
- {
- m_collision_status |= collision_map[ x ];
- }
- collision_map[ x ] |= ( 1 << i );
- m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x ) = color;
- m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x + 1 ) = color;
- }
- if ( x >= -1 && x < 159 )
- {
- if ( x >= 0 )
- {
- /* Check if we collide with an already drawn source object */
- if ( collision_map[ x ] & m_vdc.s.collision )
- {
- m_collision_status |= ( 1 << i );
- }
- /* Check if an already drawn object would collide with us */
- if ( ( 1 << i ) & m_vdc.s.collision && collision_map[ x ] )
- {
- m_collision_status |= collision_map[ x ];
- }
- collision_map[ x ] |= ( 1 << i );
- }
- m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x + 2 ) = color;
- m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x + 3 ) = color;
- }
- }
- }
- }
- }
- else
+ int height = 7 - (((y >> 1) + m_vdc.s.foreground[i].ptr) & 7);
+ if (height == 0) height = 8;
+
+ if (y <= scanline && scanline < y + height * 2)
+ {
+ int offset = (m_vdc.s.foreground[i].ptr | ((m_vdc.s.foreground[i].color & 0x01) << 8)) + (y >> 1) + ((scanline - y) >> 1);
+
+ int x = (m_vdc.s.foreground[i].x + 5) * 2;
+ u16 color = 8 + ((m_vdc.s.foreground[i].color >> 1) & 0x07);
+ for (int cx = 0; cx < 8; cx++, x += 2)
+ major_pixel(4 * i + 0x10, x, scanline, BIT(m_charset[offset & 0x1ff], cx ^ 7), color, bitmap, cliprect);
+ }
+ }
+}
+
+
+void i8244_device::draw_minor(int scanline, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ // minor system (sprites)
+ for (int i = std::size(m_vdc.s.sprites) - 1; i >= 0; i--)
+ {
+ int y = m_vdc.s.sprites[i].y;
+ int height = 8;
+ bool zoom_enable = bool(m_vdc.s.sprites[i].color & 4);
+ int zoom_px = zoom_enable ? 4 : 2;
+
+ if (y <= scanline && scanline < y + height * zoom_px)
+ {
+ u16 color = 8 + ((m_vdc.s.sprites[i].color >> 3) & 0x07);
+ u8 chr = m_vdc.s.shape[i][((scanline - y) / zoom_px)];
+ int x = (m_vdc.s.sprites[i].x + 5) * 2;
+ int x_shift = 0;
+
+ switch (m_vdc.s.sprites[i].color & 0x03)
+ {
+ case 1: // X9 attribute set
+ x_shift = 1;
+ break;
+ case 2: // S attribute set
+ x_shift = (((scanline - y) / zoom_px) & 0x01) ^ 0x01;
+ break;
+ case 3: // X9 and S attributes set
+ x_shift = ((scanline - y) / zoom_px) & 0x01;
+ break;
+ default:
+ break;
+ }
+
+ x += x_shift * (zoom_px / 2);
+
+ for (u8 m = 0x01; m > 0; m <<= 1, x += zoom_px)
+ {
+ if (chr & m)
{
- /* Regular sprite */
- if ( y <= scanline && scanline < y + height * 2 )
+ for (int px = x; px < x + zoom_px; px++)
{
- uint16_t color = 8 + bgr2rgb[ ( ( m_vdc.s.sprites[i].color >> 3 ) & 0x07 ) ];
- uint8_t chr = m_vdc.s.shape[i][ ( ( scanline - y ) >> 1 ) ];
- int x = m_vdc.s.sprites[i].x;
- int x_shift = 0;
-
- switch ( m_vdc.s.sprites[i].color & 0x03 )
+ if (cliprect.contains(px, scanline))
{
- case 1: // Xg attribute set
- x_shift = 1;
- break;
- case 2: // S attribute set
- x_shift = ( ( ( scanline - y ) >> 1 ) & 0x01 ) ^ 0x01;
- break;
- case 3: // Xg and S attributes set
- x_shift = ( ( scanline - y ) >> 1 ) & 0x01;
- break;
- }
+ // put zoom flag on high byte for later collision detection
+ u16 mask = (zoom_enable ? 0x101 : 1) << i;
+ u8 colx = m_collision_map[px];
- for ( uint8_t m = 0x01; m > 0; m <<= 1, x++ )
- {
- if ( chr & m )
- {
- if ( x >= 0 && x < 160 )
- {
- /* Check if we collide with an already drawn source object */
- if ( collision_map[ x ] & m_vdc.s.collision )
- {
- m_collision_status |= ( 1 << i );
- }
- /* Check if an already drawn object would collide with us */
- if ( ( 1 << i ) & m_vdc.s.collision && collision_map[ x ] )
- {
- m_collision_status |= collision_map[ x ];
- }
- collision_map[ x ] |= ( 1 << i );
- m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x ) = color;
- m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x + 1 ) = color;
- }
- }
+ // check if we collide with an already drawn source object
+ if (m_vdc.s.collision & colx)
+ m_collision_status |= mask;
+
+ // check if an already drawn object would collide with us
+ if (m_vdc.s.collision & mask)
+ m_collision_status |= colx;
+
+ m_collision_map[px] |= mask;
+ bitmap.pix(scanline, px) = color;
}
}
}
}
}
}
+}
+
- // Allow driver to do additional processing
- m_postprocess_func( vpos );
+u32 i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ // draw background color
+ bitmap.fill(bitswap<3>(m_vdc.s.color,3,4,5), cliprect);
- /* Check for start of VBlank */
- if ( vpos == m_start_vblank )
+ for (int scanline = cliprect.min_y; scanline <= cliprect.max_y; scanline++)
{
- m_control_status |= 0x08;
- if ( ! m_iff )
+ // clear collision maps
+ if (cliprect.min_x == screen.visible_area().min_x)
{
- m_iff = 1;
- m_irq_func(ASSERT_LINE);
+ memset(m_collision_map, 0, sizeof(m_collision_map));
+ memset(m_priority_map, 0, sizeof(m_priority_map));
}
- }
-}
+ // display grid if enabled
+ if (m_vdc.s.control & 0x08 && scanline >= 24 && scanline <= 218)
+ draw_grid(scanline, bitmap, cliprect);
-void i8244_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
-{
- uint32_t old_signal, signal;
- int ii;
- int period;
- stream_sample_t *buffer = outputs[0];
-
- /* Generate the signal */
- old_signal = signal = m_vdc.s.shift3 | (m_vdc.s.shift2 << 8) | (m_vdc.s.shift1 << 16);
+ // display objects if enabled
+ if (m_vdc.s.control & 0x20 && scanline <= 242)
+ {
+ draw_major(scanline, bitmap, cliprect);
+ draw_minor(scanline, bitmap, cliprect);
+ }
- if( m_vdc.s.sound & 0x80 ) /* Sound is enabled */
- {
- for( ii = 0; ii < samples; ii++, buffer++ )
+ // go over the collision map again for edge cases on this scanline
+ for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
{
- *buffer = signal & 0x1;
- period = (m_vdc.s.sound & 0x20) ? 1 : 4;
- if( ++m_sh_count >= period )
+ if (x > screen.visible_area().min_x)
{
- m_sh_count = 0;
- signal >>= 1;
- /* Loop sound */
- signal |= *buffer << 23;
- /* Check if noise should be applied */
- if ( m_vdc.s.sound & 0x10 )
+ u16 colx0 = m_collision_map[x - 1];
+ u16 colx1 = m_collision_map[x];
+
+ // grid or minor to the left of major
+ if (colx1 & 0x80)
{
- /* Noise tap is on bits 0 and 5 and fed back to bits 15 (and 23!) */
- uint32_t new_bit = ( ( old_signal ) ^ ( old_signal >> 5 ) ) & 0x01;
- signal = ( old_signal & 0xFF0000 ) | ( ( old_signal & 0xFFFF ) >> 1 ) | ( new_bit << 15 ) | ( new_bit << 23 );
+ if (m_vdc.s.collision & colx0 & 0x3f)
+ m_collision_status |= 0x80;
+
+ if (m_vdc.s.collision & 0x80)
+ m_collision_status |= colx0 & 0x3f;
}
- m_vdc.s.shift3 = signal & 0xFF;
- m_vdc.s.shift2 = ( signal >> 8 ) & 0xFF;
- m_vdc.s.shift1 = ( signal >> 16 ) & 0xFF;
- old_signal = signal;
- }
- /* Throw an interrupt if enabled */
- if( m_vdc.s.control & 0x4 )
- {
- // This feature does not seem to be finished/enabled in hardware!
- }
+ // grid to the left of non-zoomed minor
+ u8 mask = (colx1 & 0xf) & (~colx1 >> 8);
+
+ if (m_vdc.s.collision & colx0 & 0x30)
+ m_collision_status |= mask;
- /* Adjust volume */
- *buffer *= m_vdc.s.sound & 0xf;
- /* Pump the volume up */
- *buffer <<= 10;
+ if (m_vdc.s.collision & mask)
+ m_collision_status |= colx0 & 0x30;
+ }
}
}
- else
+
+ return 0;
+}
+
+
+/***************************************************************************
+ SOUND
+***************************************************************************/
+
+void i8244_device::sound_stream_update(sound_stream &stream)
+{
+ u8 volume = m_vdc.s.sound & 0xf;
+ sound_stream::sample_t sample_on = (m_sh_output & m_vdc.s.sound >> 7) * 0.5;
+
+ for (int i = 0; i < stream.samples(); i++)
{
- /* Sound disabled, so clear the buffer */
- for( ii = 0; ii < samples; ii++, buffer++ )
- {
- *buffer = 0;
- }
+ // clock duty cycle
+ m_sh_duty = (m_sh_duty + 1) & 0xf;
+ stream.put(0, i, (m_sh_duty < volume) ? sample_on : 0.0);
}
}
-uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+void i8244_device::sound_update()
{
- copybitmap( bitmap, m_tmp_bitmap, 0, 0, 0, 0, cliprect );
+ // clock prescaler
+ m_sh_prescaler++;
+ u8 prescaler_mask = (m_vdc.s.sound & 0x20) ? 3 : 0xf;
+ if ((m_sh_prescaler & prescaler_mask) == 0)
+ m_sh_pending = true;
+
+ // clock shift registers
+ if (m_sh_pending && !m_sh_written)
+ {
+ m_stream->update();
+ m_sh_pending = false;
- return 0;
+ u32 signal = m_vdc.s.shift3 | (m_vdc.s.shift2 << 8) | (m_vdc.s.shift1 << 16);
+ m_sh_output = signal & 1;
+ int feedback = m_sh_output;
+ signal >>= 1;
+
+ // noise tap is on bits 0 and 5 and fed back to bit 15
+ if (m_vdc.s.sound & 0x10)
+ {
+ feedback ^= signal >> 4 & 1; // pre-shift bit 5
+ signal = (signal & ~0x8000) | (feedback << 15);
+ }
+
+ // loop sound
+ signal |= feedback << 23;
+
+ m_vdc.s.shift3 = signal & 0xff;
+ m_vdc.s.shift2 = (signal >> 8) & 0xff;
+ m_vdc.s.shift1 = (signal >> 16) & 0xff;
+
+ // sound interrupt
+ if (++m_sh_count == 24)
+ {
+ m_sh_count = 0;
+ if (m_vdc.s.control & 0x04)
+ {
+ m_control_status |= 0x04;
+ m_irq_func(ASSERT_LINE);
+ }
+ }
+ }
+ else if (m_sh_written)
+ {
+ m_sh_count = 0;
+ m_sh_written = false;
+ }
}