diff options
Diffstat (limited to 'src/mame/drivers/scv.c')
-rw-r--r-- | src/mame/drivers/scv.c | 719 |
1 files changed, 719 insertions, 0 deletions
diff --git a/src/mame/drivers/scv.c b/src/mame/drivers/scv.c new file mode 100644 index 00000000000..20101807b25 --- /dev/null +++ b/src/mame/drivers/scv.c @@ -0,0 +1,719 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + Driver for Epoch Super Cassette Vision + +***************************************************************************/ + +#include "emu.h" +#include "cpu/upd7810/upd7810.h" +#include "audio/upd1771.h" +#include "bus/scv/slot.h" +#include "bus/scv/rom.h" + + +class scv_state : public driver_device +{ +public: + scv_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag), + m_videoram(*this,"videoram"), + m_maincpu(*this, "maincpu"), + m_upd1771c(*this, "upd1771c"), + m_cart(*this, "cartslot"), + m_pa(*this, "PA"), + m_pc0(*this, "PC0"), + m_charrom(*this, "charrom") { } + + DECLARE_WRITE8_MEMBER(porta_w); + DECLARE_READ8_MEMBER(portb_r); + DECLARE_READ8_MEMBER(portc_r); + DECLARE_WRITE8_MEMBER(portc_w); + DECLARE_WRITE_LINE_MEMBER(upd1771_ack_w); + required_shared_ptr<UINT8> m_videoram; + UINT8 m_porta; + UINT8 m_portc; + emu_timer *m_vb_timer; + virtual void machine_start(); + virtual void machine_reset(); + DECLARE_PALETTE_INIT(scv); + UINT32 screen_update_scv(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + enum + { + TIMER_VB + }; + + required_device<cpu_device> m_maincpu; + required_device<upd1771c_device> m_upd1771c; + required_device<scv_cart_slot_device> m_cart; + required_ioport_array<8> m_pa; + required_ioport m_pc0; + required_memory_region m_charrom; + + ioport_port *m_key[8]; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + void scv_set_banks(); + inline void plot_sprite_part( bitmap_ind16 &bitmap, UINT8 x, UINT8 y, UINT8 pat, UINT8 col, UINT8 screen_sprite_start_line ); + inline void draw_sprite( bitmap_ind16 &bitmap, UINT8 x, UINT8 y, UINT8 tile_idx, UINT8 col, UINT8 left, UINT8 right, UINT8 top, UINT8 bottom, UINT8 clip_y, UINT8 screen_sprite_start_line ); + inline void draw_text( bitmap_ind16 &bitmap, UINT8 x, UINT8 y, UINT8 *char_data, UINT8 fg, UINT8 bg ); + inline void draw_semi_graph( bitmap_ind16 &bitmap, UINT8 x, UINT8 y, UINT8 data, UINT8 fg ); + inline void draw_block_graph( bitmap_ind16 &bitmap, UINT8 x, UINT8 y, UINT8 col ); +}; + + +static ADDRESS_MAP_START( scv_mem, AS_PROGRAM, 8, scv_state ) + AM_RANGE( 0x0000, 0x0fff ) AM_ROM // BIOS + + AM_RANGE( 0x2000, 0x3403 ) AM_RAM AM_SHARE("videoram") // VRAM + 4 registers + AM_RANGE( 0x3600, 0x3600 ) AM_DEVWRITE("upd1771c", upd1771c_device, write) + + AM_RANGE( 0x8000, 0xff7f ) AM_DEVREADWRITE("cartslot", scv_cart_slot_device, read_cart, write_cart) // cartridge + AM_RANGE( 0xff80, 0xffff ) AM_RAM // upd7801 internal RAM +ADDRESS_MAP_END + + +static ADDRESS_MAP_START( scv_io, AS_IO, 8, scv_state ) + AM_RANGE( 0x00, 0x00 ) AM_WRITE(porta_w) + AM_RANGE( 0x01, 0x01 ) AM_READ(portb_r) + AM_RANGE( 0x02, 0x02 ) AM_READWRITE(portc_r, portc_w) +ADDRESS_MAP_END + + +static INPUT_PORTS_START( scv ) + PORT_START( "PA.0" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_8WAY + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_8WAY + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_8WAY + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_8WAY + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START( "PA.1" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_8WAY + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_8WAY + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_8WAY + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_8WAY + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START( "PA.2" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("0") PORT_CODE(KEYCODE_0_PAD) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("1") PORT_CODE(KEYCODE_1_PAD) + + PORT_START( "PA.3" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("2") PORT_CODE(KEYCODE_2_PAD) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("3") PORT_CODE(KEYCODE_3_PAD) + + PORT_START( "PA.4" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("4") PORT_CODE(KEYCODE_4_PAD) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("5") PORT_CODE(KEYCODE_5_PAD) + + PORT_START( "PA.5" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("6") PORT_CODE(KEYCODE_6_PAD) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("7") PORT_CODE(KEYCODE_7_PAD) + + PORT_START( "PA.6" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("8") PORT_CODE(KEYCODE_8_PAD) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("9") PORT_CODE(KEYCODE_9_PAD) + + PORT_START( "PA.7" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Cl") PORT_CODE(KEYCODE_MINUS_PAD) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("En") PORT_CODE(KEYCODE_PLUS_PAD) + + PORT_START( "PC0" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME(DEF_STR(Pause)) PORT_CODE(KEYCODE_O) +INPUT_PORTS_END + + +WRITE8_MEMBER( scv_state::porta_w ) +{ + m_porta = data; +} + + +READ8_MEMBER( scv_state::portb_r ) +{ + UINT8 data = 0xff; + + for (int i = 0; i < 8; i++) + { + if (!BIT(m_porta, i)) + data &= m_pa[i]->read(); + } + + return data; +} + + +READ8_MEMBER( scv_state::portc_r ) +{ + UINT8 data = m_portc; + + data = (data & 0xfe) | (m_pc0->read() & 0x01); + + return data; +} + + +WRITE8_MEMBER( scv_state::portc_w ) +{ + //logerror("%04x: scv_portc_w: data = 0x%02x\n", m_maincpu->pc(), data ); + m_portc = data; + m_cart->write_bank(space, 0, m_portc); + m_upd1771c->pcm_write(m_portc & 0x08); +} + + +PALETTE_INIT_MEMBER(scv_state, scv) +{ + /* + SCV Epoch-1A chip RGB voltage readouts from paused Bios color test: + + (values in millivolts) + + R G B + 0 29 29 325 + 1 29 27 22 + 2 25 24 510 + 3 337 28 508 + 4 29 515 22 + 5 336 512 329 + 6 26 515 511 + 7 29 337 25 + 8 520 24 22 + 9 517 338 21 + 10 520 25 512 + 11 521 336 333 + 12 518 515 21 + 13 342 336 22 + 14 337 336 330 + 15 516 511 508 + + Only tree 'bins' of values are obviously captured + 25 ish + 330 ish + 520 ish. + + Quamtizing/scaling/rounding between 0 and 255 we thus get: + + */ + palette.set_pen_color( 0, 0, 0, 155); + palette.set_pen_color( 1, 0, 0, 0); + palette.set_pen_color( 2, 0, 0, 255); + palette.set_pen_color( 3, 161, 0, 255); + palette.set_pen_color( 4, 0, 255, 0); + palette.set_pen_color( 5, 160, 255, 157); + palette.set_pen_color( 6, 0, 255, 255); + palette.set_pen_color( 7, 0, 161, 0); + palette.set_pen_color( 8, 255, 0, 0); + palette.set_pen_color( 9, 255, 161, 0); + palette.set_pen_color( 10, 255, 0, 255); + palette.set_pen_color( 11, 255, 160, 159); + palette.set_pen_color( 12, 255, 255, 0); + palette.set_pen_color( 13, 163, 160, 0); + palette.set_pen_color( 14, 161, 160, 157); + palette.set_pen_color( 15, 255, 255, 255); +} + + +void scv_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_VB: + { + int vpos = machine().first_screen()->vpos(); + + switch( vpos ) + { + case 240: + m_maincpu->set_input_line(UPD7810_INTF2, ASSERT_LINE); + break; + case 0: + m_maincpu->set_input_line(UPD7810_INTF2, CLEAR_LINE); + break; + } + + m_vb_timer->adjust(machine().first_screen()->time_until_pos((vpos + 1) % 262, 0)); + } + break; + + default: + assert_always(FALSE, "Unknown id in scv_state::device_timer"); + } +} + + +inline void scv_state::plot_sprite_part( bitmap_ind16 &bitmap, UINT8 x, UINT8 y, UINT8 pat, UINT8 col, UINT8 screen_sprite_start_line ) +{ + if ( x < 4 ) + { + return; + } + + x -= 4; + + if ( y + 2 >= screen_sprite_start_line ) + { + if ( pat & 0x08 ) + { + bitmap.pix16(y + 2, x ) = col; + } + if ( pat & 0x04 && x < 255 ) + { + bitmap.pix16(y + 2, x + 1 ) = col; + } + if ( pat & 0x02 && x < 254 ) + { + bitmap.pix16(y + 2, x + 2 ) = col; + } + if ( pat & 0x01 && x < 253 ) + { + bitmap.pix16(y + 2, x + 3 ) = col; + } + } +} + + +inline void scv_state::draw_sprite( bitmap_ind16 &bitmap, UINT8 x, UINT8 y, UINT8 tile_idx, UINT8 col, UINT8 left, UINT8 right, UINT8 top, UINT8 bottom, UINT8 clip_y, UINT8 screen_sprite_start_line ) +{ + int j; + + y += clip_y * 2; + for ( j = clip_y * 4; j < 32; j += 4 ) + { + UINT8 pat0 = m_videoram[ tile_idx * 32 + j + 0 ]; + UINT8 pat1 = m_videoram[ tile_idx * 32 + j + 1 ]; + UINT8 pat2 = m_videoram[ tile_idx * 32 + j + 2 ]; + UINT8 pat3 = m_videoram[ tile_idx * 32 + j + 3 ]; + + if ( ( top && j < 16 ) || ( bottom && j >= 16 ) ) + { + if ( left ) + { + plot_sprite_part( bitmap, x , y, pat0 >> 4, col, screen_sprite_start_line ); + plot_sprite_part( bitmap, x + 4, y, pat1 >> 4, col, screen_sprite_start_line ); + } + if ( right ) + { + plot_sprite_part( bitmap, x + 8, y, pat2 >> 4, col, screen_sprite_start_line ); + plot_sprite_part( bitmap, x + 12, y, pat3 >> 4, col, screen_sprite_start_line ); + } + + if ( left ) + { + plot_sprite_part( bitmap, x , y + 1, pat0 & 0x0f, col, screen_sprite_start_line ); + plot_sprite_part( bitmap, x + 4, y + 1, pat1 & 0x0f, col, screen_sprite_start_line ); + } + if ( right ) + { + plot_sprite_part( bitmap, x + 8, y + 1, pat2 & 0x0f, col, screen_sprite_start_line ); + plot_sprite_part( bitmap, x + 12, y + 1, pat3 & 0x0f, col, screen_sprite_start_line ); + } + } + + y += 2; + } +} + + +inline void scv_state::draw_text( bitmap_ind16 &bitmap, UINT8 x, UINT8 y, UINT8 *char_data, UINT8 fg, UINT8 bg ) +{ + int i; + + for ( i = 0; i < 8; i++ ) + { + UINT8 d = char_data[i]; + + bitmap.pix16(y + i, x + 0 ) = ( d & 0x80 ) ? fg : bg; + bitmap.pix16(y + i, x + 1 ) = ( d & 0x40 ) ? fg : bg; + bitmap.pix16(y + i, x + 2 ) = ( d & 0x20 ) ? fg : bg; + bitmap.pix16(y + i, x + 3 ) = ( d & 0x10 ) ? fg : bg; + bitmap.pix16(y + i, x + 4 ) = ( d & 0x08 ) ? fg : bg; + bitmap.pix16(y + i, x + 5 ) = ( d & 0x04 ) ? fg : bg; + bitmap.pix16(y + i, x + 6 ) = ( d & 0x02 ) ? fg : bg; + bitmap.pix16(y + i, x + 7 ) = ( d & 0x01 ) ? fg : bg; + } + + for ( i = 8; i < 16; i++ ) + { + bitmap.pix16(y + i, x + 0 ) = bg; + bitmap.pix16(y + i, x + 1 ) = bg; + bitmap.pix16(y + i, x + 2 ) = bg; + bitmap.pix16(y + i, x + 3 ) = bg; + bitmap.pix16(y + i, x + 4 ) = bg; + bitmap.pix16(y + i, x + 5 ) = bg; + bitmap.pix16(y + i, x + 6 ) = bg; + bitmap.pix16(y + i, x + 7 ) = bg; + } + +} + + +inline void scv_state::draw_semi_graph( bitmap_ind16 &bitmap, UINT8 x, UINT8 y, UINT8 data, UINT8 fg ) +{ + int i; + + if ( ! data ) + return; + + for ( i = 0; i < 4; i++ ) + { + bitmap.pix16(y + i, x + 0) = fg; + bitmap.pix16(y + i, x + 1) = fg; + bitmap.pix16(y + i, x + 2) = fg; + bitmap.pix16(y + i, x + 3) = fg; + } +} + + +inline void scv_state::draw_block_graph( bitmap_ind16 &bitmap, UINT8 x, UINT8 y, UINT8 col ) +{ + int i; + + for ( i = 0; i < 8; i++ ) + { + bitmap.pix16(y + i, x + 0) = col; + bitmap.pix16(y + i, x + 1) = col; + bitmap.pix16(y + i, x + 2) = col; + bitmap.pix16(y + i, x + 3) = col; + bitmap.pix16(y + i, x + 4) = col; + bitmap.pix16(y + i, x + 5) = col; + bitmap.pix16(y + i, x + 6) = col; + bitmap.pix16(y + i, x + 7) = col; + } +} + + +UINT32 scv_state::screen_update_scv(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + int x, y; + UINT8 fg = m_videoram[0x1403] >> 4; + UINT8 bg = m_videoram[0x1403] & 0x0f; + UINT8 gr_fg = m_videoram[0x1401] >> 4; + UINT8 gr_bg = m_videoram[0x1401] & 0x0f; + int clip_x = ( m_videoram[0x1402] & 0x0f ) * 2; + int clip_y = m_videoram[0x1402] >> 4; + + /* Clear the screen */ + bitmap.fill(gr_bg , cliprect); + + /* Draw background */ + for ( y = 0; y < 16; y++ ) + { + int text_y = 0; + + if ( y < clip_y ) + { + text_y = ( m_videoram[0x1400] & 0x80 ) ? 0 : 1; + } + else + { + text_y = ( m_videoram[0x1400] & 0x80 ) ? 1 : 0; + } + + for ( x = 0; x < 32; x++ ) + { + int text_x = 0; + UINT8 d = m_videoram[ 0x1000 + y * 32 + x ]; + + if ( x < clip_x ) + { + text_x = ( m_videoram[0x1400] & 0x40 ) ? 0 : 1; + } + else + { + text_x = ( m_videoram[0x1400] & 0x40 ) ? 1 : 0; + } + + if ( text_x && text_y ) + { + /* Text mode */ + UINT8 *char_data = m_charrom->base() + ( d & 0x7f ) * 8; + draw_text( bitmap, x * 8, y * 16, char_data, fg, bg ); + } + else + { + switch ( m_videoram[0x1400] & 0x03 ) + { + case 0x01: /* Semi graphics mode */ + draw_semi_graph( bitmap, x * 8 , y * 16 , d & 0x80, gr_fg ); + draw_semi_graph( bitmap, x * 8 + 4, y * 16 , d & 0x40, gr_fg ); + draw_semi_graph( bitmap, x * 8 , y * 16 + 4, d & 0x20, gr_fg ); + draw_semi_graph( bitmap, x * 8 + 4, y * 16 + 4, d & 0x10, gr_fg ); + draw_semi_graph( bitmap, x * 8 , y * 16 + 8, d & 0x08, gr_fg ); + draw_semi_graph( bitmap, x * 8 + 4, y * 16 + 8, d & 0x04, gr_fg ); + draw_semi_graph( bitmap, x * 8 , y * 16 + 12, d & 0x02, gr_fg ); + draw_semi_graph( bitmap, x * 8 + 4, y * 16 + 12, d & 0x01, gr_fg ); + break; + + case 0x03: /* Block graphics mode */ + draw_block_graph( bitmap, x * 8, y * 16 , d >> 4 ); + draw_block_graph( bitmap, x * 8, y * 16 + 8, d & 0x0f ); + break; + + default: /* Otherwise draw nothing? */ + break; + } + } + } + } + + /* Draw sprites if enabled */ + if ( m_videoram[0x1400] & 0x10 ) + { + UINT8 screen_start_sprite_line = ( ( ( m_videoram[0x1400] & 0xf7 ) == 0x17 ) && ( ( m_videoram[0x1402] & 0xef ) == 0x4f ) ) ? 21 + 32 : 0 ; + int i; + + for ( i = 0; i < 128; i++ ) + { + UINT8 spr_y = m_videoram[ 0x1200 + i * 4 ] & 0xfe; + UINT8 y_32 = m_videoram[ 0x1200 + i * 4 ] & 0x01; /* Xx32 sprite */ + UINT8 clip = m_videoram[ 0x1201 + i * 4 ] >> 4; + UINT8 col = m_videoram[ 0x1201 + i * 4 ] & 0x0f; + UINT8 spr_x = m_videoram[ 0x1202 + i * 4 ] & 0xfe; + UINT8 x_32 = m_videoram[ 0x1202 + i * 4 ] & 0x01; /* 32xX sprite */ + UINT8 tile_idx = m_videoram[ 0x1203 + i * 4 ] & 0x7f; + UINT8 half = m_videoram[ 0x1203 + i * 4] & 0x80; + UINT8 left = 1; + UINT8 right = 1; + UINT8 top = 1; + UINT8 bottom = 1; + + if ( !col ) + { + continue; + } + + if ( !spr_y ) + { + continue; + } + + if ( half ) + { + if ( tile_idx & 0x40 ) + { + if ( y_32 ) + { + spr_y -= 8; + top = 0; + bottom = 1; + y_32 = 0; + } + else + { + top = 1; + bottom = 0; + } + } + if ( x_32 ) + { + spr_x -= 8; + left = 0; + right = 1; + x_32 = 0; + } + else + { + left = 1; + right = 0; + } + } + + /* Check if 2 color sprites are enabled */ + if ( ( m_videoram[0x1400] & 0x20 ) && ( i & 0x20 ) ) + { + /* 2 color sprite handling */ + draw_sprite( bitmap, spr_x, spr_y, tile_idx, col, left, right, top, bottom, clip, screen_start_sprite_line ); + if ( x_32 || y_32 ) + { + static const UINT8 spr_2col_lut0[16] = { 0, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 1, 1 }; + static const UINT8 spr_2col_lut1[16] = { 0, 1, 8, 11, 2, 3, 10, 9, 4, 5, 12, 13, 6, 7, 14, 15 }; + + draw_sprite( bitmap, spr_x, spr_y, tile_idx ^ ( 8 * x_32 + y_32 ), ( i & 0x40 ) ? spr_2col_lut1[col] : spr_2col_lut0[col], left, right, top, bottom, clip, screen_start_sprite_line ); + } + } + else + { + /* regular sprite handling */ + draw_sprite( bitmap, spr_x, spr_y, tile_idx, col, left, right, top, bottom, clip, screen_start_sprite_line ); + if ( x_32 ) + { + draw_sprite( bitmap, spr_x + 16, spr_y, tile_idx | 8, col, 1, 1, top, bottom, clip, screen_start_sprite_line ); + } + + if ( y_32 ) + { + clip = ( clip & 0x08 ) ? ( clip & 0x07 ) : 0; + draw_sprite( bitmap, spr_x, spr_y + 16, tile_idx | 1, col, left, right, 1, 1, clip, screen_start_sprite_line ); + if ( x_32 ) + { + draw_sprite( bitmap, spr_x + 16, spr_y + 16, tile_idx | 9, col, 1, 1, 1, 1, clip, screen_start_sprite_line ); + } + } + } + } + } + + return 0; +} + + +WRITE_LINE_MEMBER( scv_state::upd1771_ack_w ) +{ + m_maincpu->set_input_line(UPD7810_INTF1, (state) ? ASSERT_LINE : CLEAR_LINE); +} + +void scv_state::machine_start() +{ + m_vb_timer = timer_alloc(TIMER_VB); + + save_item(NAME(m_porta)); + save_item(NAME(m_portc)); + if (m_cart->exists()) + m_cart->save_ram(); + +} + + +void scv_state::machine_reset() +{ + m_vb_timer->adjust(machine().first_screen()->time_until_pos(0, 0)); +} + + +/* F4 Character Displayer */ +static const gfx_layout scv_charlayout = +{ + 8, 8, /* 8 x 8 characters */ + 128, /* 128 characters */ + 1, /* 1 bits per pixel */ + { 0 }, /* no bitplanes */ + /* x offsets */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, + /* y offsets */ + { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, + 8*8 /* every char takes 8 bytes */ +}; + +static GFXDECODE_START( scv ) + GFXDECODE_ENTRY( "charrom", 0x0000, scv_charlayout, 0, 8 ) +GFXDECODE_END + + +static SLOT_INTERFACE_START(scv_cart) + SLOT_INTERFACE_INTERNAL("rom8k", SCV_ROM8K) + SLOT_INTERFACE_INTERNAL("rom16k", SCV_ROM16K) + SLOT_INTERFACE_INTERNAL("rom32k", SCV_ROM32K) + SLOT_INTERFACE_INTERNAL("rom32k_ram", SCV_ROM32K_RAM8K) + SLOT_INTERFACE_INTERNAL("rom64k", SCV_ROM64K) + SLOT_INTERFACE_INTERNAL("rom128k", SCV_ROM128K) + SLOT_INTERFACE_INTERNAL("rom128k_ram", SCV_ROM128K_RAM4K) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_START( scv, scv_state ) + + MCFG_CPU_ADD( "maincpu", UPD7801, XTAL_4MHz ) + MCFG_CPU_PROGRAM_MAP( scv_mem ) + MCFG_CPU_IO_MAP( scv_io ) + + /* Video chip is EPOCH TV-1 */ + MCFG_SCREEN_ADD( "screen", RASTER ) + MCFG_SCREEN_RAW_PARAMS( XTAL_14_31818MHz/2, 456, 24, 24+192, 262, 23, 23+222 ) /* TODO: Verify */ + MCFG_SCREEN_UPDATE_DRIVER(scv_state, screen_update_scv) + MCFG_SCREEN_PALETTE("palette") + + MCFG_GFXDECODE_ADD("gfxdecode", "palette", scv) + MCFG_PALETTE_ADD( "palette", 16 ) + MCFG_PALETTE_INIT_OWNER(scv_state, scv) + + /* Sound is generated by UPD1771C clocked at XTAL_6MHz */ + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD( "upd1771c", UPD1771C, XTAL_6MHz ) + MCFG_UPD1771_ACK_HANDLER(WRITELINE(scv_state, upd1771_ack_w)) + MCFG_SOUND_ROUTE( ALL_OUTPUTS, "mono", 1.00 ) + + MCFG_SCV_CARTRIDGE_ADD("cartslot", scv_cart, NULL) + + /* Software lists */ + MCFG_SOFTWARE_LIST_ADD("cart_list","scv") +MACHINE_CONFIG_END + + +static MACHINE_CONFIG_DERIVED( scv_pal, scv ) + MCFG_CPU_MODIFY( "maincpu" ) + MCFG_CPU_CLOCK( 3780000 ) + + /* Video chip is EPOCH TV-1A */ + MCFG_SCREEN_MODIFY( "screen" ) + MCFG_SCREEN_RAW_PARAMS( XTAL_13_4MHz/2, 456, 24, 24+192, 342, 23, 23+222 ) /* TODO: Verify */ +MACHINE_CONFIG_END + + +/* The same bios is used in both the NTSC and PAL versions of the console */ +ROM_START( scv ) + ROM_REGION( 0x1000, "maincpu", 0 ) + ROM_LOAD( "upd7801g.s01", 0, 0x1000, CRC(7ac06182) SHA1(6e89d1227581c76441a53d605f9e324185f1da33) ) + + ROM_REGION( 0x400, "charrom", 0 ) + ROM_LOAD( "epochtv.chr", 0, 0x400, BAD_DUMP CRC(db521533) SHA1(40b4e44838c35191f115437a14f200f052e71509) ) +ROM_END + + +ROM_START( scv_pal ) + ROM_REGION( 0x1000, "maincpu", 0 ) + ROM_LOAD( "upd7801g.s01", 0, 0x1000, CRC(7ac06182) SHA1(6e89d1227581c76441a53d605f9e324185f1da33) ) + + ROM_REGION( 0x400, "charrom", 0 ) + ROM_LOAD( "epochtv.chr", 0, 0x400, BAD_DUMP CRC(db521533) SHA1(40b4e44838c35191f115437a14f200f052e71509) ) +ROM_END + + +/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ +CONS( 1984, scv, 0, 0, scv, scv, driver_device, 0, "Epoch", "Super Cassette Vision", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) +CONS( 198?, scv_pal, scv, 0, scv_pal, scv, driver_device, 0, "Yeno", "Super Cassette Vision (PAL)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) |