diff --git a/.gitattributes b/.gitattributes index faf38e10403..3dea7c97ec6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6054,6 +6054,7 @@ src/mess/drivers/supercon.c svneol=native#text/plain src/mess/drivers/supracan.c svneol=native#text/plain src/mess/drivers/svi318.c svneol=native#text/plain src/mess/drivers/svision.c svneol=native#text/plain +src/mess/drivers/svmu.c svneol=native#text/plain src/mess/drivers/swtpc.c svneol=native#text/plain src/mess/drivers/sym1.c svneol=native#text/plain src/mess/drivers/sys2900.c svneol=native#text/plain diff --git a/src/mess/drivers/svmu.c b/src/mess/drivers/svmu.c new file mode 100644 index 00000000000..d33094fb7ba --- /dev/null +++ b/src/mess/drivers/svmu.c @@ -0,0 +1,361 @@ +/*************************************************************************** + + Sega Visual Memory Unit + + driver by Sandro Ronco + + TODO: + - add more bios versions + - layout for LCD symbols + - serial + +****************************************************************************/ + +#include "emu.h" +#include "cpu/lc8670/lc8670.h" +#include "imagedev/snapquik.h" +#include "machine/intelfsh.h" +#include "sound/speaker.h" +#include "rendlay.h" + +#define PIXEL_SIZE 7 +#define PIXEL_DISTANCE 1 + +class svmu_state : public driver_device +{ +public: + svmu_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_flash(*this, "flash"), + m_speaker(*this, SPEAKER_TAG) + { } + + required_device m_maincpu; + required_device m_flash; + required_device m_speaker; + + virtual void palette_init(); + virtual void machine_reset(); + + DECLARE_WRITE8_MEMBER(page_w); + DECLARE_READ8_MEMBER(flash_r); + DECLARE_WRITE8_MEMBER(flash_w); + DECLARE_READ8_MEMBER(prog_r); + DECLARE_WRITE8_MEMBER(prog_w); + DECLARE_READ8_MEMBER(p1_r); + DECLARE_WRITE8_MEMBER(p1_w); + DECLARE_READ8_MEMBER(p7_r); + +private: + UINT8 * m_bios; + UINT8 m_page; +}; + + +WRITE8_MEMBER(svmu_state::page_w) +{ + m_page = data & 0x03; +} + +READ8_MEMBER(svmu_state::flash_r) +{ + return m_flash->read(offset); +} + +WRITE8_MEMBER(svmu_state::flash_w) +{ + m_flash->write(offset, data); +} + +READ8_MEMBER(svmu_state::prog_r) +{ + if (m_page == 1) + return m_flash->read(offset); + else if (m_page == 2) + return m_flash->read(0x10000 + offset); + else + return m_bios[offset]; +} + +WRITE8_MEMBER(svmu_state::prog_w) +{ + if (m_page == 1) + m_flash->write(offset, data); + else if (m_page == 2) + m_flash->write(0x10000 + offset, data); +} + +/* + Port 1 + + x--- ---- PWM output + -x-- ---- BUZ + --x- ---- SCK1 + ---x ---- SB1 + ---- x--- SO1 + ---- -x-- SCK0 + ---- --x- SB0 + ---- ---x SO0 + +*/ + +READ8_MEMBER(svmu_state::p1_r) +{ + return 0; +} + +WRITE8_MEMBER(svmu_state::p1_w) +{ + speaker_level_w(m_speaker, BIT(data, 7)); +} + + +/* + Port 7 + + ---- x--- ID1 + ---- -x-- ID0 + ---- --x- battery low voltage + ---- ---x 5V detection +*/ + +READ8_MEMBER(svmu_state::p7_r) +{ + return (ioport("BATTERY")->read()<<1); +} + + +static ADDRESS_MAP_START(svmu_mem, AS_PROGRAM, 8, svmu_state) + AM_RANGE( 0x0000, 0xffff ) AM_READWRITE(prog_r, prog_w) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(svmu_io_mem, AS_IO, 8, svmu_state) + AM_RANGE( LC8670_PORT1, LC8670_PORT1 ) AM_READWRITE(p1_r, p1_w) + AM_RANGE( LC8670_PORT3, LC8670_PORT3 ) AM_READ_PORT("P3") + AM_RANGE( LC8670_PORT7, LC8670_PORT7 ) AM_READ(p7_r) +ADDRESS_MAP_END + +/* Input ports */ +static INPUT_PORTS_START( svmu ) + PORT_START( "P3" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("UP") PORT_CODE( KEYCODE_UP ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("DOWN") PORT_CODE( KEYCODE_DOWN ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("LEFT") PORT_CODE( KEYCODE_LEFT ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("RIGHT") PORT_CODE( KEYCODE_RIGHT ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("A") PORT_CODE( KEYCODE_A ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("B") PORT_CODE( KEYCODE_B ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("MODE") PORT_CODE( KEYCODE_M ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("SLEEP") PORT_CODE( KEYCODE_S ) + PORT_START("BATTERY") + PORT_CONFNAME( 0x01, 0x01, "Battery" ) + PORT_CONFSETTING( 0x01, "Good" ) + PORT_CONFSETTING( 0x00, "Poor" ) +INPUT_PORTS_END + +void svmu_state::machine_reset() +{ + m_bios = (UINT8*)(*memregion("bios")); + m_page = 0; +} + +void svmu_state::palette_init() +{ + palette_set_color(machine(), 0, MAKE_RGB(138, 146, 148)); + palette_set_color(machine(), 1, MAKE_RGB(92, 83, 88)); +} + +static LC8670_LCD_UPDATE( svmu_lcd_update ) +{ + if (lcd_enabled) + { + for (int y=0; y<32; y++) + for (int x=0; x<6; x++) + { + int gfx = vram[y*6 + x]; + + for (int b=0; b<8; b++) + bitmap.plot_box((x*8 + b) * (PIXEL_SIZE + PIXEL_DISTANCE), y * (PIXEL_SIZE + PIXEL_DISTANCE), PIXEL_SIZE, PIXEL_SIZE, BIT(gfx,7-b)); + } + + popmessage("%c %c %c %c\n", BIT(vram[0xc1],6) ? 'F' : ' ', // File icon + BIT(vram[0xc2],4) ? 'G' : ' ', // Game icon + BIT(vram[0xc3],2) ? 'C' : ' ', // Clock icon + BIT(vram[0xc4],0) ? 'A' : ' '); // Flash icon + } + else + { + bitmap.fill(0, cliprect); + } + + output_set_value("file_icon" , lcd_enabled ? BIT(vram[0xc1],6) : 0); + output_set_value("game_icon" , lcd_enabled ? BIT(vram[0xc2],4) : 0); + output_set_value("clock_icon", lcd_enabled ? BIT(vram[0xc3],2) : 0); + output_set_value("flash_icon", lcd_enabled ? BIT(vram[0xc4],0) : 0); + + return 0; +} + + +inline void vmufat_write_byte(UINT8* flash, UINT8 block, offs_t offset, UINT8 data) +{ + flash[(block * 512) + offset] = data; +} + +inline void vmufat_write_word(UINT8* flash, UINT8 block, offs_t offset, UINT16 data) +{ + // 16-bit data are stored in little endian + flash[(block * 512) + offset + 0] = data & 0xff; + flash[(block * 512) + offset + 1] = (data>>8) & 0xff; +} + +static QUICKLOAD_LOAD( svmu ) +{ + running_machine &machine = image.device().machine(); + svmu_state *state = machine.driver_data(); + UINT32 size = image.length(); + UINT8 *flash = (UINT8*)state->m_flash->space().get_read_ptr(0); + + image.fread(flash, size); + + // verify if image is already a valid VMUFAT file system + bool valid_vmufat = true; + if (size == 0x20000) + { + for (int i=0; i<0x10; i++) + if (flash[255 * 512 + i] != 0x55) + { + valid_vmufat = false; + break; + } + } + else + { + valid_vmufat = false; + } + + if (!valid_vmufat) + { + // more info about the VMUFAT here: http://mc.pp.se/dc/vms/flashmem.html + + //-------------------------------- Formatting -------------------------------- + memset(flash + 241*512, 0, 15*512); // clears the last 15 blocks that contain file system information + + for (int i=0; i<0x10; i++) + vmufat_write_byte(flash, 255, i, 0x55); // first 16 bytes should be 0x55 to indicate a properly formatted card + + vmufat_write_byte(flash, 255, 0x10, 0x00); // custom VMS colour (1 = use custom colours, 0 = standard colour) + vmufat_write_byte(flash, 255, 0x11, 0x00); // VMS colour blue component + vmufat_write_byte(flash, 255, 0x12, 0x00); // VMS colour green component + vmufat_write_byte(flash, 255, 0x13, 0x00); // VMS colour red component + vmufat_write_byte(flash, 255, 0x14, 0x00); // VMS colour alpha component + vmufat_write_byte(flash, 255, 0x30, 0x19); // Century (BCD) + vmufat_write_byte(flash, 255, 0x31, 0x99); // Year (BCD) + vmufat_write_byte(flash, 255, 0x32, 0x01); // Month (BCD) + vmufat_write_byte(flash, 255, 0x33, 0x01); // Day (BCD) + vmufat_write_byte(flash, 255, 0x34, 0x00); // Hour (BCD) + vmufat_write_byte(flash, 255, 0x35, 0x00); // Minute (BCD) + vmufat_write_byte(flash, 255, 0x36, 0x00); // Second (BCD) + vmufat_write_byte(flash, 255, 0x37, 0x00); // Day of week (0 = Monday, 6 = Sunday) + vmufat_write_word(flash, 255, 0x44, 0x00ff); // location of Root + vmufat_write_word(flash, 255, 0x46, 0x00fe); // location of FAT (254) + vmufat_write_word(flash, 255, 0x48, 0x0001); // size of FAT in blocks (1) + vmufat_write_word(flash, 255, 0x4a, 0x00fd); // location of Directory (253) + vmufat_write_word(flash, 255, 0x4c, 0x000d); // size of Directory in blocks (13) + vmufat_write_word(flash, 255, 0x4e, 0x0000); // icon shape for this VMS (0-123) + vmufat_write_word(flash, 255, 0x50, 0x00c8); // number of user blocks (200) + + for (int i=0; i<256; i++) + vmufat_write_word(flash, 254, i<<1, 0xfffc); // marks all blocks as unallocated + + for (int i=253; i>241; --i) + vmufat_write_word(flash, 254, i<<1, i - 1); // marsk all Directory blocks as allocate + + vmufat_write_word(flash, 254, 0x1e2, 0xfffa); // marks last Directory block + vmufat_write_word(flash, 254, 0x1fc, 0xfffa); // marks FAT block as allocated + vmufat_write_word(flash, 254, 0x1fe, 0xfffa); // marks Root block as allocated + + //-------------------------------- Create the vms file -------------------------------- + int vms_blocks = (size / 512) + (size & 0x1ff ? 1 : 0); // number of blocks required for store the vms file + + for (int i=0; i