// license:BSD-3-Clause // copyright-holders:Wilbert Pol /*************************************************************************** i8244.c Intel 8244 (NTSC)/8245 (PAL) Graphics and sound chip ***************************************************************************/ #include "emu.h" #include "i8244.h" #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, 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) { } //------------------------------------------------- // device_config_complete - perform any // operations now that the configuration is // complete //------------------------------------------------- void i8244_device::device_config_complete() { if (!has_screen()) 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); } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void i8244_device::device_start() { // Let the screen create our temporary bitmap with the screen's dimensions screen().register_screen_bitmap(m_tmp_bitmap); m_line_timer = timer_alloc(TIMER_LINE); m_line_timer->adjust( screen().time_until_pos(1, START_ACTIVE_SCAN ), 0, screen().scan_period() ); m_hblank_timer = timer_alloc(TIMER_HBLANK); m_hblank_timer->adjust( screen().time_until_pos(1, END_ACTIVE_SCAN + 18 ), 0, screen().scan_period() ); m_irq_func.resolve_safe(); m_postprocess_func.resolve_safe(); // 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)); } //------------------------------------------------- // device_reset - device-specific reset //------------------------------------------------- void i8244_device::device_reset() { memset(m_vdc.reg, 0, 0x100); 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; } void i8244_device::i8244_palette(palette_device &palette) const { 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 { 0xff, 0xff, 0xff } // I R G B }; 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(); switch ( id ) { case TIMER_LINE: // handle i824x line timer render_scanline(vpos); break; case TIMER_HBLANK: // handle i824x HBlank timer if ( vpos < m_start_vpos - 1 ) { return; } if ( vpos < m_start_vblank - 1 ) { m_control_status |= 0x01; } break; } } int i8244_device::get_y_beam() { int y = screen().vpos() - m_start_vpos; // 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; } return y; } int i8244_device::get_x_beam() { int x = screen().hpos() - START_ACTIVE_SCAN; if ( x < 0 ) { x += LINE_CLOCKS; } return x >> 1; } 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 ) { offset &= ~0x0C; } // registers $A0-$AF are mirrored at $B0-$BF if ( ( offset & 0xF0 ) == 0xB0 ) { offset &= ~0x10; } return offset; } READ8_MEMBER(i8244_device::read) { uint8_t data; offset = fix_register_mirrors( offset ); switch (offset) { case 0xa1: data = m_control_status & 0xFE; m_iff = 0; m_irq_func(CLEAR_LINE); m_control_status &= ~0x08; if ( hblank() ) { data |= 1; } break; case 0xa2: data = m_collision_status; 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; 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; break; default: data = m_vdc.reg[offset]; break; } return data; } WRITE8_MEMBER(i8244_device::write) { offset = fix_register_mirrors( offset ); /* Update the sound */ if( offset >= 0xa7 && offset <= 0xaa ) { m_stream->update(); } if (offset == 0xa0) { 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(); } } m_vdc.reg[offset] = data; } READ_LINE_MEMBER(i8244_device::vblank) { if ( screen().vpos() > m_start_vpos && screen().vpos() < m_start_vblank ) { return 0; } return 1; } READ_LINE_MEMBER(i8244_device::hblank) { int hpos = screen().hpos(); int vpos = screen().vpos(); if ( hpos >= START_ACTIVE_SCAN && hpos < END_ACTIVE_SCAN ) { return 0; } // Before active area? if ( vpos < m_start_vpos - 1 ) { return 0; } // During active area? if ( vpos < m_start_vblank - 1 ) { return 1; } // After active area return 0; } void i8244_device::render_scanline(int vpos) { // 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; } if ( m_start_vpos < vpos && vpos < m_start_vblank ) { rectangle rect; int scanline = vpos - m_start_vpos; m_control_status &= ~ 0x01; /* 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 ); /* Clear collision map */ memset( collision_map, 0, sizeof( collision_map ) ); /* Display grid if enabled */ if ( m_vdc.s.control & 0x08 ) { 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 ) { if ( y_grid_offset + y * height <= scanline && scanline < y_grid_offset + y * height + 3 ) { for ( int i = 0; i < 9; i++ ) { if ( ( m_vdc.s.hgrid[0][i] & j ) || ( m_vdc.s.hgrid[1][i] & ( j >> 8 ) ) ) { for ( int k = 0; k < width + 2; k++ ) { 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; } } } } } } /* Draw vertical part of 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 ) { for ( int i = 0; i < 10; i++ ) { if ( m_vdc.s.vgrid[i] & j ) { for ( int k = 0; k < w; k++ ) { 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; } } } } } } } /* Display objects if enabled */ if ( m_vdc.s.control & 0x20 ) { /* Regular foreground objects */ for ( int i = 0; i < ARRAY_LENGTH( m_vdc.s.foreground ); 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 ) { 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++ ) { 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; } } } } } /* Quad objects */ for ( int i = 0; i < ARRAY_LENGTH( m_vdc.s.quad ); i++ ) { int y = m_vdc.s.quad[i].single[0].y; int height = 8; if ( y <= scanline && scanline < y + height * 2 ) { int x = m_vdc.s.quad[i].single[0].x; // 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 ); 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 ]; 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; } } } } /* Sprites */ for ( int i = 0; i < ARRAY_LENGTH( m_vdc.s.sprites ); i++ ) { int y = m_vdc.s.sprites[i].y; int height = 8; 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; 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; 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 { /* Regular sprite */ if ( y <= scanline && scanline < y + height * 2 ) { 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 ) { 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; } 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; } } } } } } } } // Allow driver to do additional processing m_postprocess_func( vpos ); /* Check for start of VBlank */ if ( vpos == m_start_vblank ) { m_control_status |= 0x08; if ( ! m_iff ) { m_iff = 1; m_irq_func(ASSERT_LINE); } } } 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); if( m_vdc.s.sound & 0x80 ) /* Sound is enabled */ { for( ii = 0; ii < samples; ii++, buffer++ ) { *buffer = signal & 0x1; period = (m_vdc.s.sound & 0x20) ? 1 : 4; if( ++m_sh_count >= period ) { m_sh_count = 0; signal >>= 1; /* Loop sound */ signal |= *buffer << 23; /* Check if noise should be applied */ if ( m_vdc.s.sound & 0x10 ) { /* 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 ); } 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! } /* Adjust volume */ *buffer *= m_vdc.s.sound & 0xf; /* Pump the volume up */ *buffer <<= 10; } } else { /* Sound disabled, so clear the buffer */ for( ii = 0; ii < samples; ii++, buffer++ ) { *buffer = 0; } } } uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { copybitmap( bitmap, m_tmp_bitmap, 0, 0, 0, 0, cliprect ); return 0; }