411 lines
10 KiB
C
411 lines
10 KiB
C
/***************************************************************************
|
|
|
|
cgenie.c
|
|
|
|
Functions to emulate the video controller 6845.
|
|
|
|
***************************************************************************/
|
|
|
|
#include "emu.h"
|
|
#include "includes/cgenie.h"
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Start the video hardware emulation.
|
|
|
|
***************************************************************************/
|
|
void cgenie_state::video_start()
|
|
{
|
|
m_screen->register_screen_bitmap(m_dlybitmap);
|
|
m_screen->register_screen_bitmap(m_bitmap);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
Calculate the horizontal and vertical offset for the
|
|
current register settings of the 6845 CRTC
|
|
|
|
***************************************************************************/
|
|
void cgenie_state::cgenie_offset_xy()
|
|
{
|
|
if( m_crt.horizontal_sync_pos )
|
|
m_off_x = m_crt.horizontal_total - m_crt.horizontal_sync_pos - 14;
|
|
else
|
|
m_off_x = -15;
|
|
|
|
m_off_y = (m_crt.vertical_total - m_crt.vertical_sync_pos) *
|
|
(m_crt.scan_lines + 1) + m_crt.vertical_adjust
|
|
- 32;
|
|
|
|
if( m_off_y < 0 )
|
|
m_off_y = 0;
|
|
|
|
if( m_off_y > 128 )
|
|
m_off_y = 128;
|
|
|
|
// logerror("cgenie offset x:%d y:%d\n", m_off_x, m_off_y);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Write to an indexed register of the 6845 CRTC
|
|
***************************************************************************/
|
|
WRITE8_MEMBER( cgenie_state::cgenie_register_w )
|
|
{
|
|
//int addr;
|
|
|
|
switch (m_crt.idx)
|
|
{
|
|
case 0:
|
|
if( m_crt.horizontal_total == data )
|
|
break;
|
|
m_crt.horizontal_total = data;
|
|
cgenie_offset_xy();
|
|
break;
|
|
case 1:
|
|
if( m_crt.horizontal_displayed == data )
|
|
break;
|
|
m_crt.horizontal_displayed = data;
|
|
break;
|
|
case 2:
|
|
if( m_crt.horizontal_sync_pos == data )
|
|
break;
|
|
m_crt.horizontal_sync_pos = data;
|
|
cgenie_offset_xy();
|
|
break;
|
|
case 3:
|
|
m_crt.horizontal_length = data;
|
|
break;
|
|
case 4:
|
|
if( m_crt.vertical_total == data )
|
|
break;
|
|
m_crt.vertical_total = data;
|
|
cgenie_offset_xy();
|
|
break;
|
|
case 5:
|
|
if( m_crt.vertical_adjust == data )
|
|
break;
|
|
m_crt.vertical_adjust = data;
|
|
cgenie_offset_xy();
|
|
break;
|
|
case 6:
|
|
if( m_crt.vertical_displayed == data )
|
|
break;
|
|
m_crt.vertical_displayed = data;
|
|
break;
|
|
case 7:
|
|
if( m_crt.vertical_sync_pos == data )
|
|
break;
|
|
m_crt.vertical_sync_pos = data;
|
|
cgenie_offset_xy();
|
|
break;
|
|
case 8:
|
|
m_crt.crt_mode = data;
|
|
break;
|
|
case 9:
|
|
data &= 15;
|
|
if( m_crt.scan_lines == data )
|
|
break;
|
|
m_crt.scan_lines = data;
|
|
cgenie_offset_xy();
|
|
break;
|
|
case 10:
|
|
if( m_crt.cursor_top == data )
|
|
break;
|
|
m_crt.cursor_top = data;
|
|
//addr = 256 * m_crt.cursor_address_hi + m_crt.cursor_address_lo;
|
|
break;
|
|
case 11:
|
|
if( m_crt.cursor_bottom == data )
|
|
break;
|
|
m_crt.cursor_bottom = data;
|
|
//addr = 256 * m_crt.cursor_address_hi + m_crt.cursor_address_lo;
|
|
break;
|
|
case 12:
|
|
data &= 63;
|
|
if( m_crt.screen_address_hi == data )
|
|
break;
|
|
m_crt.screen_address_hi = data;
|
|
break;
|
|
case 13:
|
|
if( m_crt.screen_address_lo == data )
|
|
break;
|
|
m_crt.screen_address_lo = data;
|
|
break;
|
|
case 14:
|
|
data &= 63;
|
|
if( m_crt.cursor_address_hi == data )
|
|
break;
|
|
m_crt.cursor_address_hi = data;
|
|
//addr = 256 * m_crt.cursor_address_hi + m_crt.cursor_address_lo;
|
|
break;
|
|
case 15:
|
|
if( m_crt.cursor_address_lo == data )
|
|
break;
|
|
m_crt.cursor_address_lo = data;
|
|
//addr = 256 * m_crt.cursor_address_hi + m_crt.cursor_address_lo;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Write to the index register of the 6845 CRTC
|
|
***************************************************************************/
|
|
WRITE8_MEMBER( cgenie_state::cgenie_index_w )
|
|
{
|
|
m_crt.idx = data & 15;
|
|
}
|
|
|
|
/***************************************************************************
|
|
Read from an indexed register of the 6845 CRTC
|
|
***************************************************************************/
|
|
READ8_MEMBER( cgenie_state::cgenie_register_r )
|
|
{
|
|
return cgenie_get_register(m_crt.idx);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Read from a register of the 6845 CRTC
|
|
***************************************************************************/
|
|
int cgenie_state::cgenie_get_register(int indx)
|
|
{
|
|
switch (indx)
|
|
{
|
|
case 0:
|
|
return m_crt.horizontal_total;
|
|
case 1:
|
|
return m_crt.horizontal_displayed;
|
|
case 2:
|
|
return m_crt.horizontal_sync_pos;
|
|
case 3:
|
|
return m_crt.horizontal_length;
|
|
case 4:
|
|
return m_crt.vertical_total;
|
|
case 5:
|
|
return m_crt.vertical_adjust;
|
|
case 6:
|
|
return m_crt.vertical_displayed;
|
|
case 7:
|
|
return m_crt.vertical_sync_pos;
|
|
case 8:
|
|
return m_crt.crt_mode;
|
|
case 9:
|
|
return m_crt.scan_lines;
|
|
case 10:
|
|
return m_crt.cursor_top;
|
|
case 11:
|
|
return m_crt.cursor_bottom;
|
|
case 12:
|
|
return m_crt.screen_address_hi;
|
|
case 13:
|
|
return m_crt.screen_address_lo;
|
|
case 14:
|
|
return m_crt.cursor_address_hi;
|
|
case 15:
|
|
return m_crt.cursor_address_lo;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************
|
|
Read the index register of the 6845 CRTC
|
|
***************************************************************************/
|
|
READ8_MEMBER( cgenie_state::cgenie_index_r )
|
|
{
|
|
return m_crt.idx;
|
|
}
|
|
|
|
/***************************************************************************
|
|
Switch mode between character generator and graphics
|
|
***************************************************************************/
|
|
void cgenie_state::cgenie_mode_select(int mode)
|
|
{
|
|
m_graphics = (mode) ? 1 : 0;
|
|
}
|
|
|
|
|
|
void cgenie_state::cgenie_refresh_monitor(bitmap_ind16 &bitmap, const rectangle &cliprect)
|
|
{
|
|
UINT8 *videoram = m_videoram;
|
|
int i, address, offset, cursor, size, code, x, y;
|
|
rectangle r;
|
|
|
|
bitmap.fill(m_palette->black_pen(), cliprect);
|
|
|
|
if(m_crt.vertical_displayed || m_crt.horizontal_displayed)
|
|
{
|
|
offset = 256 * m_crt.screen_address_hi + m_crt.screen_address_lo;
|
|
size = m_crt.horizontal_displayed * m_crt.vertical_displayed;
|
|
cursor = 256 * m_crt.cursor_address_hi + m_crt.cursor_address_lo;
|
|
|
|
/*
|
|
* for every character in the Video RAM, check if it has been modified since
|
|
* last time and update it accordingly.
|
|
*/
|
|
for( address = 0; address < size; address++ )
|
|
{
|
|
i = (offset + address) & 0x3fff;
|
|
x = address % m_crt.horizontal_displayed + m_off_x;
|
|
y = address / m_crt.horizontal_displayed;
|
|
|
|
r.min_x = x * 8;
|
|
r.max_x = r.min_x + 7;
|
|
r.min_y = y * (m_crt.scan_lines + 1) + m_off_y;
|
|
r.max_y = r.min_y + m_crt.scan_lines;
|
|
|
|
if( m_graphics )
|
|
{
|
|
/* get graphics code */
|
|
code = videoram[i];
|
|
m_gfxdecode->gfx(1)->opaque(bitmap,r, code, 0,
|
|
0, 0, r.min_x, r.min_y);
|
|
}
|
|
else
|
|
{
|
|
/* get character code */
|
|
code = videoram[i];
|
|
|
|
/* translate defined character sets */
|
|
code += m_font_offset[(code >> 6) & 3];
|
|
m_gfxdecode->gfx(0)->opaque(bitmap,r, code, m_colorram[i&0x3ff],
|
|
0, 0, r.min_x, r.min_y);
|
|
}
|
|
|
|
if( i == cursor )
|
|
{
|
|
rectangle rc;
|
|
|
|
/* check if cursor turned off */
|
|
if( (m_crt.cursor_top & 0x60) == 0x20 )
|
|
continue;
|
|
|
|
if( (m_crt.cursor_top & 0x60) == 0x60 )
|
|
{
|
|
m_crt.cursor_visible = 1;
|
|
}
|
|
else
|
|
{
|
|
m_crt.cursor_phase++;
|
|
m_crt.cursor_visible = (m_crt.cursor_phase >> 3) & 1;
|
|
}
|
|
|
|
if( !m_crt.cursor_visible )
|
|
continue;
|
|
|
|
rc.min_x = r.min_x;
|
|
rc.max_x = r.max_x;
|
|
rc.min_y = r.min_y + (m_crt.cursor_top & 15);
|
|
rc.max_y = r.min_y + (m_crt.cursor_bottom & 15);
|
|
m_gfxdecode->gfx(0)->opaque(bitmap,rc, 0x7f, m_colorram[i&0x3ff],
|
|
0, 0, rc.min_x, rc.min_y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void cgenie_state::cgenie_refresh_tv_set(bitmap_ind16 &bitmap, const rectangle &cliprect)
|
|
{
|
|
UINT8 *videoram = m_videoram;
|
|
int i, address, offset, cursor, size, code, x, y;
|
|
rectangle r;
|
|
|
|
m_bitmap.fill(m_palette->black_pen(), cliprect);
|
|
m_dlybitmap.fill(m_palette->black_pen(), cliprect);
|
|
|
|
if(m_crt.vertical_displayed || m_crt.horizontal_displayed)
|
|
{
|
|
offset = 256 * m_crt.screen_address_hi + m_crt.screen_address_lo;
|
|
size = m_crt.horizontal_displayed * m_crt.vertical_displayed;
|
|
cursor = 256 * m_crt.cursor_address_hi + m_crt.cursor_address_lo;
|
|
|
|
/*
|
|
* for every character in the Video RAM, check if it has been modified since
|
|
* last time and update it accordingly.
|
|
*/
|
|
for( address = 0; address < size; address++ )
|
|
{
|
|
i = (offset + address) & 0x3fff;
|
|
x = address % m_crt.horizontal_displayed + m_off_x;
|
|
y = address / m_crt.horizontal_displayed;
|
|
|
|
r.min_x = x * 8;
|
|
r.max_x = r.min_x + 7;
|
|
r.min_y = y * (m_crt.scan_lines + 1) + m_off_y;
|
|
r.max_y = r.min_y + m_crt.scan_lines;
|
|
|
|
if( m_graphics )
|
|
{
|
|
/* get graphics code */
|
|
code = videoram[i];
|
|
m_gfxdecode->gfx(1)->opaque(m_bitmap,r, code, 1,
|
|
0, 0, r.min_x, r.min_y);
|
|
m_gfxdecode->gfx(1)->opaque(m_dlybitmap,r, code, 2,
|
|
0, 0, r.min_x, r.min_y);
|
|
}
|
|
else
|
|
{
|
|
/* get character code */
|
|
code = videoram[i];
|
|
|
|
/* translate defined character sets */
|
|
code += m_font_offset[(code >> 6) & 3];
|
|
m_gfxdecode->gfx(0)->opaque(m_bitmap,r, code, m_colorram[i&0x3ff] + 16,
|
|
0, 0, r.min_x, r.min_y);
|
|
m_gfxdecode->gfx(0)->opaque(m_dlybitmap,r, code, m_colorram[i&0x3ff] + 32,
|
|
0, 0, r.min_x, r.min_y);
|
|
}
|
|
|
|
if( i == cursor )
|
|
{
|
|
rectangle rc;
|
|
|
|
/* check if cursor turned off */
|
|
if( (m_crt.cursor_top & 0x60) == 0x20 )
|
|
continue;
|
|
|
|
if( (m_crt.cursor_top & 0x60) == 0x60 )
|
|
{
|
|
m_crt.cursor_visible = 1;
|
|
}
|
|
else
|
|
{
|
|
m_crt.cursor_phase++;
|
|
m_crt.cursor_visible = (m_crt.cursor_phase >> 3) & 1;
|
|
}
|
|
|
|
if( !m_crt.cursor_visible )
|
|
continue;
|
|
|
|
rc.min_x = r.min_x;
|
|
rc.max_x = r.max_x;
|
|
rc.min_y = r.min_y + (m_crt.cursor_top & 15);
|
|
rc.max_y = r.min_y + (m_crt.cursor_bottom & 15);
|
|
|
|
m_gfxdecode->gfx(0)->opaque(m_bitmap,rc, 0x7f, m_colorram[i&0x3ff] + 16,
|
|
0, 0, rc.min_x, rc.min_y);
|
|
m_gfxdecode->gfx(0)->opaque(m_dlybitmap,rc, 0x7f, m_colorram[i&0x3ff] + 32,
|
|
0, 0, rc.min_x, rc.min_y);
|
|
}
|
|
}
|
|
}
|
|
|
|
copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
|
|
copybitmap_trans(bitmap, m_dlybitmap, 0, 0, 1, 0, cliprect, 0);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Draw the game screen in the given bitmap_ind16.
|
|
***************************************************************************/
|
|
UINT32 cgenie_state::screen_update_cgenie(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
|
|
{
|
|
if( m_tv_mode )
|
|
cgenie_refresh_tv_set(bitmap, cliprect);
|
|
else
|
|
cgenie_refresh_monitor(bitmap, cliprect);
|
|
return 0;
|
|
}
|