/*************************************************************************** Unior 12/05/2009 Skeleton driver. Some info obtained from EMU-80. There are no manuals, diagrams, or anything else available afaik. The entire driver is guesswork. The monitor will only allow certain characters to be typed, thus the modifier keys appear to do nothing. There is no need to use the enter key; using spacebar and the correct parameters is enough. Monitor commands: C D E - save F G H - set register I - load J - modify memory K L - list registers M ToDo: - All devices - Beeper (requires a timer chip) - Cassette (requires a UART) - Colour? ****************************************************************************/ #include "emu.h" #include "cpu/i8085/i8085.h" class unior_state : public driver_device { public: unior_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_p_videoram(*this, "p_videoram"){ } DECLARE_WRITE8_MEMBER(vram_w); DECLARE_WRITE8_MEMBER(unior_4c_w); DECLARE_READ8_MEMBER(unior_4c_r); DECLARE_READ8_MEMBER(unior_4d_r); DECLARE_WRITE8_MEMBER(unior_50_w); DECLARE_WRITE8_MEMBER(unior_60_w); UINT8 *m_p_vram; required_shared_ptr m_p_videoram; UINT8 *m_p_chargen; UINT8 m_4c; UINT8 m_cursor_col; UINT8 m_cursor_row; virtual void machine_reset(); virtual void video_start(); UINT32 screen_update_unior(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); }; READ8_MEMBER( unior_state::unior_4c_r ) { return m_4c; } READ8_MEMBER( unior_state::unior_4d_r ) { char kbdrow[6]; sprintf(kbdrow,"X%X", m_4c&15); return ioport(kbdrow)->read(); } WRITE8_MEMBER( unior_state::unior_4c_w ) { m_4c = data; } WRITE8_MEMBER( unior_state::vram_w ) { m_p_vram[offset] = data; } WRITE8_MEMBER( unior_state::unior_50_w ) { if (data) memcpy(m_p_vram, m_p_vram+80, 24*80); } WRITE8_MEMBER( unior_state::unior_60_w ) { static UINT8 ctrl=0; if (offset) ctrl = 0; // port 61 - reset ctrl else if (ctrl) m_cursor_row = data; // port 60 - row else { m_cursor_col = data; // port 60 - column ctrl++; } } static ADDRESS_MAP_START( unior_mem, AS_PROGRAM, 8, unior_state ) ADDRESS_MAP_UNMAP_HIGH AM_RANGE(0x0000, 0xf7af) AM_RAM AM_RANGE(0xf7b0, 0xf7ff) AM_RAM AM_SHARE("p_videoram") // status line AM_RANGE(0xf800, 0xffff) AM_ROM AM_WRITE(vram_w) // main video ADDRESS_MAP_END static ADDRESS_MAP_START( unior_io, AS_IO, 8, unior_state ) ADDRESS_MAP_UNMAP_HIGH ADDRESS_MAP_GLOBAL_MASK(0xff) AM_RANGE(0x30, 0x38) AM_NOP // dma data AM_RANGE(0x3c, 0x3f) AM_NOP // cassette player control AM_RANGE(0x4c, 0x4c) AM_READWRITE(unior_4c_r,unior_4c_w) AM_RANGE(0x4d, 0x4d) AM_READ(unior_4d_r) AM_RANGE(0x4e, 0x4f) AM_NOP // possibly the control ports of a PIO AM_RANGE(0x50, 0x50) AM_WRITE(unior_50_w) AM_RANGE(0x60, 0x61) AM_READNOP AM_WRITE(unior_60_w) AM_RANGE(0xdc, 0xdf) AM_NOP // timer chip + beeper AM_RANGE(0xec, 0xed) AM_NOP // cassette data to&from UART ADDRESS_MAP_END /* Input ports */ static INPUT_PORTS_START( unior ) PORT_START("X0") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9_PAD) PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8_PAD) PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) // nothing PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNUSED) // nothing PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4_PAD) PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) PORT_START("X1") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(27) // cancel input PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR(9) // Russian little M PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL) PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Rus/Lat") PORT_CODE(KEYCODE_LALT) PORT_CODE(KEYCODE_RALT) PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("NUMLK") PORT_CODE(KEYCODE_NUMLOCK) // switches 1st indicator between N and B - numlock? rctrl PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PLUS_PAD) PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD) PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ASTERISK) PORT_START("X2") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') // ; PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('J') PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('F') PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("CAPS") PORT_CODE(KEYCODE_CAPSLOCK) // switches 2nd indicator between U and B - capslock? rshift PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0_PAD) PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL_PAD) PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER_PAD) PORT_START("X3") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) // A PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('C') PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('^') // ^ (') PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1_PAD) PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2_PAD) PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) PORT_START("X4") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) // B PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('U') PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('W') PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('S') PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7_PAD) PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F7) // H PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F8) // I PORT_START("X5") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) // C PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('K') PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('A') PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('M') PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("BSPACE") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F6) // G PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("LF") PORT_CODE(KEYCODE_HOME) PORT_CHAR(10) // line feed? PORT_START("X6") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('\xA4') PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('E') PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('P') PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('I') // I then hangs PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) // Russian A PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) // ? (/) PORT_START("X7") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) // D PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('N') PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('R') PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('T') PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) // Russian bl PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) // Russian signpost PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) // } (<>) PORT_START("X8") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) // E PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&') PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('G') PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('O') PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('X') PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) PORT_CHAR('>') // > PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("= :") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR(':') // : PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("- =") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('=') // = PORT_START("X9") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'') PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('L') PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('B') PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) // Russian U PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('H') PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_START("XA") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(') PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('D') PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('@') // (`) PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR('<') // < PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('V') PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')') INPUT_PORTS_END void unior_state::machine_reset() { machine().device("maincpu")->state().set_state_int(I8085_PC, 0xF800); } void unior_state::video_start() { m_p_chargen = machine().root_device().memregion("chargen")->base(); m_p_vram = memregion("vram")->base(); } UINT32 unior_state::screen_update_unior(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { UINT8 y,ra,gfx; UINT16 sy=0,ma=0,x,chr; UINT8 *videoram; videoram = m_p_videoram; static UINT8 framecnt=0; framecnt++; for (y = 0; y < 25; y++) { for (ra = 0; ra < 8; ra++) { UINT16 *p = &bitmap.pix16(sy++); for (x = 0; x < 80; x++) { chr = videoram[x+ma]; gfx = m_p_chargen[(chr<<3) | ra ]; /* cursor */ if ((y == m_cursor_row) && (x == m_cursor_col) && (ra > 6) & BIT(framecnt, 3)) gfx ^= 0xff; /* Display a scanline of a character */ *p++ = BIT(gfx, 7); *p++ = BIT(gfx, 6); *p++ = BIT(gfx, 5); *p++ = BIT(gfx, 4); *p++ = BIT(gfx, 3); *p++ = BIT(gfx, 2); *p++ = BIT(gfx, 1); *p++ = BIT(gfx, 0); } } if (y) ma+=80; else videoram = m_p_vram; } return 0; } /* F4 Character Displayer */ static const gfx_layout unior_charlayout = { 8, 8, /* 8 x 8 characters */ 256, /* 256 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( unior ) GFXDECODE_ENTRY( "chargen", 0x0000, unior_charlayout, 0, 1 ) GFXDECODE_END static MACHINE_CONFIG_START( unior, unior_state ) /* basic machine hardware */ MCFG_CPU_ADD("maincpu",I8080, 2222222) MCFG_CPU_PROGRAM_MAP(unior_mem) MCFG_CPU_IO_MAP(unior_io) /* video hardware */ MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_REFRESH_RATE(50) MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ MCFG_SCREEN_SIZE(640, 200) MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 200-1) MCFG_SCREEN_UPDATE_DRIVER(unior_state, screen_update_unior) MCFG_GFXDECODE(unior) MCFG_PALETTE_LENGTH(2) MCFG_PALETTE_INIT(black_and_white) MACHINE_CONFIG_END /* ROM definition */ ROM_START( unior ) ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF ) ROM_LOAD( "unior.rom", 0xf800, 0x0800, CRC(23a347e8) SHA1(2ef3134e2f4a696c3b52a145fa5a2d4c3487194b)) ROM_REGION( 0x0840, "chargen", ROMREGION_ERASEFF ) ROM_LOAD( "unior.fnt", 0x0000, 0x0800, CRC(4f654828) SHA1(8c0ac11ea9679a439587952e4908940b67c4105e)) ROM_LOAD( "palette.rom", 0x0800, 0x0040, CRC(b4574ceb) SHA1(f7a82c61ab137de8f6a99b0c5acf3ac79291f26a)) ROM_REGION( 0x0800, "vram", ROMREGION_ERASEFF ) ROM_END /* Driver */ /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ COMP( 19??, unior, radio86, 0, unior, unior, driver_device, 0, "", "Unior", GAME_NOT_WORKING | GAME_NO_SOUND)