From 40f4b4f73e73ce595fa19e563d69dbe46cdc0153 Mon Sep 17 00:00:00 2001 From: AJR Date: Fri, 7 Sep 2018 13:50:32 -0400 Subject: m79152pc: Add cursor, scrolling support and some video attributes --- src/mame/drivers/m79152pc.cpp | 197 +++++++++++++++++++++++++++++++----------- 1 file changed, 147 insertions(+), 50 deletions(-) diff --git a/src/mame/drivers/m79152pc.cpp b/src/mame/drivers/m79152pc.cpp index 2c37227a46e..1ae87cbb669 100644 --- a/src/mame/drivers/m79152pc.cpp +++ b/src/mame/drivers/m79152pc.cpp @@ -2,11 +2,21 @@ // copyright-holders:Miodrag Milanovic,AJR /*************************************************************************** - Mera-Elzab 79152pc + Mera-Elzab 79152pc - This is terminal + This system provides a half-featured emulation of the ADM-3A or similar + terminals by TeleVideo and Wyse. The “half-featured” part is that some + commands are not recognized at all and others are merely filtered out. - 29/12/2011 Skeleton driver. + The 8035 here serves as a soft CRTC, counting horizontal scans and + outputting row addresses (dependent on scrolling) and vertical sync + pulses. The present emulation produces incorrect video output at the + vertical margins and is extremely prone to desyncing. + + “PC Shadow” is the name of the software this terminal either runs or + interfaces with. The actual keyboard is unknown, but is almost + certainly PC-XT compatible. The character set is a nonstandard variant + of CP 437 that incorporates a few Polish letters. ****************************************************************************/ @@ -31,36 +41,59 @@ class m79152pc_state : public driver_device public: m79152pc_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) - , m_p_videoram(*this, "videoram") - , m_p_attributes(*this, "attributes") + , m_videoram(*this, "videoram") + , m_attributes(*this, "attributes") + , m_chargen(*this, "chargen") , m_maincpu(*this, "maincpu") - , m_p_chargen(*this, "chargen") + , m_mcu(*this, "mcu") , m_uart(*this, "uart") + , m_screen(*this, "screen") , m_beep(*this, "beep") { } void m79152pc(machine_config &config); +protected: + virtual void machine_start() override; + private: DECLARE_WRITE8_MEMBER(beep_w); DECLARE_WRITE_LINE_MEMBER(latch_full_w); DECLARE_READ_LINE_MEMBER(mcu_t0_r); + DECLARE_READ_LINE_MEMBER(mcu_t1_r); + void mcu_p1_w(u8 data); + void mcu_p2_w(u8 data); + void lc_reset_w(u8 data); + + TIMER_CALLBACK_MEMBER(hsync_on); + TIMER_CALLBACK_MEMBER(hsync_off); - uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + void screen_draw_line(bitmap_ind16 &bitmap, unsigned y); void mem_map(address_map &map); void io_map(address_map &map); void mcu_map(address_map &map); void mcu_io_map(address_map &map); - required_shared_ptr m_p_videoram; - required_shared_ptr m_p_attributes; + required_shared_ptr m_videoram; + required_shared_ptr m_attributes; + required_region_ptr m_chargen; + required_device m_maincpu; - required_region_ptr m_p_chargen; + required_device m_mcu; required_device m_uart; + required_device m_screen; required_device m_beep; + u8 m_line_base; + u8 m_line_count; bool m_latch_full; + u8 m_mcu_p2; + bool m_hsync; + + emu_timer *m_hsync_on_timer; + emu_timer *m_hsync_off_timer; }; WRITE8_MEMBER(m79152pc_state::beep_w) @@ -78,6 +111,26 @@ READ_LINE_MEMBER(m79152pc_state::mcu_t0_r) return m_latch_full ? 0 : 1; } +READ_LINE_MEMBER(m79152pc_state::mcu_t1_r) +{ + return m_hsync ? 0 : 1; +} + +void m79152pc_state::mcu_p1_w(u8 data) +{ + m_line_base = data; +} + +void m79152pc_state::mcu_p2_w(u8 data) +{ + m_mcu_p2 = data; +} + +void m79152pc_state::lc_reset_w(u8 data) +{ + m_line_count = (data >> 4) & 0xf; +} + void m79152pc_state::mem_map(address_map &map) { map.unmap_value_high(); @@ -106,7 +159,7 @@ void m79152pc_state::mcu_map(address_map &map) void m79152pc_state::mcu_io_map(address_map &map) { - map(0x00, 0x00).mirror(0xff).r("mculatch", FUNC(i8212_device::read)); + map(0x00, 0x00).mirror(0xff).r("mculatch", FUNC(i8212_device::read)).w(FUNC(m79152pc_state::lc_reset_w)); } /* Input ports */ @@ -114,37 +167,55 @@ static INPUT_PORTS_START( m79152pc ) INPUT_PORTS_END -uint32_t m79152pc_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +TIMER_CALLBACK_MEMBER(m79152pc_state::hsync_on) { -// Attributes are unknown so are not implemented - uint8_t y,ra,chr,gfx; //,attr; - uint16_t sy=0,ma=0,x; + m_screen->update_now(); + m_mcu->set_input_line(MCS48_INPUT_IRQ, ASSERT_LINE); + m_hsync = true; + m_line_count = (m_line_count + 1) & 0xf; +} + +TIMER_CALLBACK_MEMBER(m79152pc_state::hsync_off) +{ + unsigned vpos = m_screen->vpos(); + m_mcu->set_input_line(MCS48_INPUT_IRQ, CLEAR_LINE); + m_hsync_on_timer->adjust(m_screen->time_until_pos(vpos, 640)); + m_hsync = false; +} - for (y = 0; y < 25; y++) +void m79152pc_state::screen_draw_line(bitmap_ind16 &bitmap, unsigned y) +{ + u16 ma = u16(m_line_base) << 4; + u8 ra = m_line_count & 0xf; + + u16 *p = &bitmap.pix16(y++); + + for (u16 x = ma; x < ma + 80; x++) { - for (ra = 0; ra < 12; ra++) - { - uint16_t *p = &bitmap.pix16(sy++); - - for (x = ma; x < ma + 80; x++) - { - chr = m_p_videoram[x]; - //attr = m_p_attributes[x]; - gfx = m_p_chargen[((chr<<4) | ra) + 4 ]; - - /* 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); - } - } - ma+=80; + // BIT(attr, 3) should probably be blinking + // BIT(attr, 1) may be used for high-intensity text ( + u8 chr = m_videoram[x]; + u8 attr = m_attributes[x]; + u8 gfx = m_chargen[(chr << 4) | (BIT(attr, 2) && ra == 15 ? 3 : ra)]; + if (BIT(attr, 0)) + gfx ^= 0xff; + + *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); } +} + +u32 m79152pc_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + for (unsigned y = cliprect.top(); y <= cliprect.bottom(); y++) + screen_draw_line(bitmap, y); + return 0; } @@ -166,6 +237,26 @@ static GFXDECODE_START( gfx_m79152pc ) GFXDECODE_ENTRY( "chargen", 0x0000, m79152pc_charlayout, 0, 1 ) GFXDECODE_END + +void m79152pc_state::machine_start() +{ + m_latch_full = false; + m_mcu_p2 = 0xff; + m_line_base = 0; + m_line_count = 0; + m_hsync = false; + + m_hsync_on_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(m79152pc_state::hsync_on), this)); + m_hsync_off_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(m79152pc_state::hsync_off), this)); + m_hsync_off_timer->adjust(m_screen->time_until_pos(9, 0), 0, m_screen->scan_period()); + + save_item(NAME(m_latch_full)); + save_item(NAME(m_mcu_p2)); + save_item(NAME(m_line_base)); + save_item(NAME(m_line_count)); + save_item(NAME(m_hsync)); +} + static const z80_daisy_config daisy_chain[] = { { "ctc" }, @@ -180,20 +271,21 @@ MACHINE_CONFIG_START(m79152pc_state::m79152pc) m_maincpu->set_addrmap(AS_IO, &m79152pc_state::io_map); m_maincpu->set_daisy_config(daisy_chain); - mcs48_cpu_device &mcu(I8035(config, "mcu", 6'000'000)); // NEC D8035HLC - mcu.set_addrmap(AS_PROGRAM, &m79152pc_state::mcu_map); - mcu.set_addrmap(AS_IO, &m79152pc_state::mcu_io_map); - mcu.t0_in_cb().set(FUNC(m79152pc_state::mcu_t0_r)); + I8035(config, m_mcu, 6'000'000); // NEC D8035HLC + m_mcu->set_addrmap(AS_PROGRAM, &m79152pc_state::mcu_map); + m_mcu->set_addrmap(AS_IO, &m79152pc_state::mcu_io_map); + m_mcu->t0_in_cb().set(FUNC(m79152pc_state::mcu_t0_r)); + m_mcu->t1_in_cb().set(FUNC(m79152pc_state::mcu_t1_r)); + m_mcu->p1_out_cb().set(FUNC(m79152pc_state::mcu_p1_w)); + m_mcu->p2_out_cb().set(FUNC(m79152pc_state::mcu_p2_w)); + m_mcu->p2_out_cb().append("ctc", FUNC(z80ctc_device::trg0)).bit(6); // determines beep duration + m_mcu->p2_out_cb().append("ctc", FUNC(z80ctc_device::trg3)).bit(6); /* 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, 300) - MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 300-1) - MCFG_SCREEN_UPDATE_DRIVER(m79152pc_state, screen_update) - MCFG_SCREEN_PALETTE("palette") - MCFG_SCREEN_VBLANK_CALLBACK(WRITELINE("ctc", z80ctc_device, trg0)) // determines beep duration (probably too slow) + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_raw(50 * 720 * 324, 720, 0, 640, 324, 0, 250); + m_screen->set_screen_update(FUNC(m79152pc_state::screen_update)); + m_screen->set_palette("palette"); MCFG_DEVICE_ADD("gfxdecode", GFXDECODE, "palette", gfx_m79152pc) MCFG_PALETTE_ADD_MONOCHROME("palette") @@ -219,6 +311,8 @@ MACHINE_CONFIG_START(m79152pc_state::m79152pc) ctc.zc_callback<2>().set(m_uart, FUNC(z80sio_device::txca_w)); ctc.zc_callback<2>().append(m_uart, FUNC(z80sio_device::rxca_w)); + // FIXME: Channel A should be the modem channel. Channel B should be a PC keyboard + // that outputs XT scancodes, which are then rebroadcast through channel A! Z80SIO(config, m_uart, 4'000'000); // UB8560D m_uart->out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0); m_uart->out_txda_callback().set("keyboard", FUNC(rs232_port_device::write_txd)); @@ -250,6 +344,9 @@ ROM_START( m79152pc ) ROM_REGION( 0x0800, "mcu", 0 ) ROM_LOAD( "char.bin", 0x0000, 0x0800, CRC(da3792a5) SHA1(b4a4f0d61d8082b7909a346a5b01494c53cf8d05)) + + ROM_REGION( 0x0200, "proms", 0 ) + ROM_LOAD( "7641apc.bin", 0x0000, 0x0200, NO_DUMP) ROM_END /* Driver */ -- cgit v1.2.3