// license:BSD-3-Clause // copyright-holders:Sandro Ronco /*************************************************************************** Belogic Uzebox driver by Sandro Ronco TODO: - Sound - SDCard - Mouse ****************************************************************************/ #include "emu.h" #include "cpu/avr8/avr8.h" #include "sound/dac.h" #include "imagedev/cartslot.h" // overclocked to 8 * NTSC burst frequency #define MASTER_CLOCK 28618180 #define INTERLACED 0 class uzebox_state : public driver_device { public: uzebox_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu") { } required_device m_maincpu; DECLARE_READ8_MEMBER(port_a_r); DECLARE_WRITE8_MEMBER(port_a_w); DECLARE_READ8_MEMBER(port_b_r); DECLARE_WRITE8_MEMBER(port_b_w); DECLARE_READ8_MEMBER(port_c_r); DECLARE_WRITE8_MEMBER(port_c_w); DECLARE_READ8_MEMBER(port_d_r); DECLARE_WRITE8_MEMBER(port_d_w); virtual void machine_start(); virtual void machine_reset(); void line_update(); UINT32 screen_update_uzebox(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); DECLARE_DEVICE_IMAGE_LOAD_MEMBER(uzebox_cart); private: int m_vpos; UINT64 m_line_start_cycles; UINT32 m_line_pos_cycles; UINT8 m_port_a; UINT8 m_port_b; UINT8 m_port_c; UINT8 m_port_d; UINT16 m_joy_data[2]; bitmap_rgb32 m_bitmap; }; void uzebox_state::machine_start() { machine().first_screen()->register_screen_bitmap(m_bitmap); } void uzebox_state::machine_reset() { m_vpos = 0; m_line_start_cycles = 0; m_line_pos_cycles = 0; m_port_a = 0; m_port_b = 0; m_port_c = 0; m_port_d = 0; m_joy_data[0] = m_joy_data[1] = 0; } WRITE8_MEMBER(uzebox_state::port_a_w) { // xxxx ---- NC // ---- x--- SNES controller clk // ---- -x-- SNES controller latch // ---- --x- SNES controller P2 data // ---- ---x SNES controller P1 data UINT8 changed = m_port_a ^ data; if (changed & data & 0x04) { m_joy_data[0] = ioport("P1")->read(); m_joy_data[1] = ioport("P2")->read(); } else if (changed & 0x08) { if (changed & data & 0x08) { m_joy_data[0] >>= 1; m_joy_data[1] >>= 1; } m_port_a = (m_joy_data[0] & 0x01) | ((m_joy_data[1] & 0x01) << 1); } m_port_a = (data & 0x0c) | (m_port_a & 0x03); } READ8_MEMBER(uzebox_state::port_a_r) { return m_port_a | 0xf0; } WRITE8_MEMBER(uzebox_state::port_b_w) { // xxx- ---- SDCard // ---x ---- AD725 CE // ---- x--- AD725 4FSC // ---- -xx- NC // ---- ---x AD725 HSYNC // AD725 CE is hard-wired to VCC in early revisions (C1, D1 and E1) if ((m_port_b & 0x10) || ioport("AD725_CE")->read() == 0) if ((m_port_b ^ data) & m_port_b & 0x01) { line_update(); UINT32 cycles = (UINT32)(m_maincpu->get_elapsed_cycles() - m_line_start_cycles); if (cycles < 1000 && m_vpos >= 448) m_vpos = INTERLACED ? ((m_vpos ^ 0x01) & 0x01) : 0; else if (cycles > 1000) m_vpos += 2; m_line_start_cycles = m_maincpu->get_elapsed_cycles(); m_line_pos_cycles = 0; } m_port_b = data; } READ8_MEMBER(uzebox_state::port_b_r) { return m_port_b; } WRITE8_MEMBER(uzebox_state::port_c_w) { // xx-- ---- blue // --xx x--- green // ---- -xxx red line_update(); m_port_c = data; } READ8_MEMBER(uzebox_state::port_c_r) { return m_port_c; } WRITE8_MEMBER(uzebox_state::port_d_w) { // x--- ---- sound // -x-- ---- SDCard CS // ---x ---- LED // --x- x--- NC // ---- -x-- power // ---- --xx UART MIDI m_port_d = data; } READ8_MEMBER(uzebox_state::port_d_r) { return m_port_d; } /****************************************************\ * Address maps * \****************************************************/ static ADDRESS_MAP_START( uzebox_prg_map, AS_PROGRAM, 8, uzebox_state ) AM_RANGE(0x0000, 0xffff) AM_ROM // 64 KB internal eprom ATmega644 ADDRESS_MAP_END static ADDRESS_MAP_START( uzebox_data_map, AS_DATA, 8, uzebox_state ) AM_RANGE(0x0100, 0x10ff) AM_RAM // 4KB RAM ADDRESS_MAP_END static ADDRESS_MAP_START( uzebox_io_map, AS_IO, 8, uzebox_state ) AM_RANGE(AVR8_REG_A, AVR8_REG_A) AM_READWRITE( port_a_r, port_a_w ) AM_RANGE(AVR8_REG_B, AVR8_REG_B) AM_READWRITE( port_b_r, port_b_w ) AM_RANGE(AVR8_REG_C, AVR8_REG_C) AM_READWRITE( port_c_r, port_c_w ) AM_RANGE(AVR8_REG_D, AVR8_REG_D) AM_READWRITE( port_d_r, port_d_w ) ADDRESS_MAP_END /****************************************************\ * Input ports * \****************************************************/ static INPUT_PORTS_START( uzebox ) PORT_START( "P1" ) PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 Button B") PORT_PLAYER(1) PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P1 Button Y") PORT_PLAYER(1) PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P1 Select") PORT_PLAYER(1) PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START1 ) PORT_NAME("P1 Start") PORT_PLAYER(1) PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P1 Button A") PORT_PLAYER(1) PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P1 Button X") PORT_PLAYER(1) PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P1 Button L") PORT_PLAYER(1) PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P1 Button R") PORT_PLAYER(1) PORT_BIT( 0xf000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_START( "P2" ) PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P2 Button B") PORT_PLAYER(2) PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P2 Button Y") PORT_PLAYER(2) PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P2 Select") PORT_PLAYER(2) PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START2 ) PORT_NAME("P2 Start") PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P2 Button A") PORT_PLAYER(2) PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P2 Button X") PORT_PLAYER(2) PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P2 Button L") PORT_PLAYER(2) PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P2 Button R") PORT_PLAYER(2) PORT_BIT( 0xf000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_START("AD725_CE") PORT_CONFNAME( 0x01, 0x00, "AD725 CE" ) PORT_CONFSETTING( 0x00, "VCC" ) PORT_CONFSETTING( 0x01, "PB4" ) INPUT_PORTS_END /****************************************************\ * Video hardware * \****************************************************/ void uzebox_state::line_update() { UINT32 cycles = (UINT32)(m_maincpu->get_elapsed_cycles() - m_line_start_cycles) / 2; rgb_t color = rgb_t(pal3bit(m_port_c >> 0), pal3bit(m_port_c >> 3), pal2bit(m_port_c >> 6)); for (UINT32 x = m_line_pos_cycles; x < cycles; x++) { if (m_bitmap.cliprect().contains(x, m_vpos)) m_bitmap.pix32(m_vpos, x) = color; if (!INTERLACED) if (m_bitmap.cliprect().contains(x, m_vpos + 1)) m_bitmap.pix32(m_vpos + 1, x) = color; } m_line_pos_cycles = cycles; } UINT32 uzebox_state::screen_update_uzebox(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); return 0; } DEVICE_IMAGE_LOAD_MEMBER(uzebox_state,uzebox_cart) { UINT8* rom = (UINT8*)(*memregion("maincpu")); memset(rom, 0xff, memregion("maincpu")->bytes()); if (image.software_entry() == NULL) { UINT32 size = image.length(); dynamic_buffer data(size); image.fread(data, size); if (!strncmp((const char*)&data[0], "UZEBOX", 6)) memcpy(rom, data + 0x200, size - 0x200); else memcpy(rom, data, size); } else { memcpy(rom, image.get_software_region("rom"), image.get_software_region_length("rom")); } return IMAGE_INIT_PASS; } /****************************************************\ * Machine definition * \****************************************************/ const avr8_config atmega644_config = { "eeprom" }; static MACHINE_CONFIG_START( uzebox, uzebox_state ) /* basic machine hardware */ MCFG_CPU_ADD("maincpu", ATMEGA644, MASTER_CLOCK) MCFG_CPU_AVR8_CONFIG(atmega644_config) MCFG_CPU_PROGRAM_MAP(uzebox_prg_map) MCFG_CPU_DATA_MAP(uzebox_data_map) MCFG_CPU_IO_MAP(uzebox_io_map) /* video hardware */ MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_REFRESH_RATE(59.99) MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(1395)) MCFG_SCREEN_SIZE(870, 525) MCFG_SCREEN_VISIBLE_AREA(150, 870-1, 40, 488-1) MCFG_SCREEN_UPDATE_DRIVER(uzebox_state, screen_update_uzebox) /* sound hardware */ MCFG_SPEAKER_STANDARD_MONO("avr8") MCFG_SOUND_ADD("dac", DAC, 0) MCFG_SOUND_ROUTE(0, "avr8", 1.00) MCFG_CARTSLOT_ADD("cart1") MCFG_CARTSLOT_EXTENSION_LIST("bin,uze") MCFG_CARTSLOT_MANDATORY MCFG_CARTSLOT_LOAD(uzebox_state,uzebox_cart) MCFG_CARTSLOT_INTERFACE("uzebox") MCFG_SOFTWARE_LIST_ADD("eprom_list","uzebox") MACHINE_CONFIG_END ROM_START( uzebox ) ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF ) /* Main program store */ ROM_REGION( 0x800, "eeprom", ROMREGION_ERASE00 ) /* on-die eeprom */ ROM_END /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */ CONS(2010, uzebox, 0, 0, uzebox, uzebox, driver_device, 0, "Belogic", "Uzebox", GAME_NO_SOUND | GAME_NOT_WORKING)