From e47f02485c218cd3dcc74819161ea6165eb22bb8 Mon Sep 17 00:00:00 2001 From: Robin Sergeant Date: Sat, 17 Feb 2024 14:42:07 +0000 Subject: rm/rm380z.cpp: Improved character mode video emulation: (#12031) * Use real character generator ROM for COS 4.0. * Corrected screen resolution. * Implemented user-defined character support. --- src/mame/rm/rm380z.cpp | 48 +++++----- src/mame/rm/rm380z.h | 48 ++++++---- src/mame/rm/rm380z_m.cpp | 96 ++++++++++++------- src/mame/rm/rm380z_v.cpp | 239 +++++++++++++++++------------------------------ 4 files changed, 206 insertions(+), 225 deletions(-) diff --git a/src/mame/rm/rm380z.cpp b/src/mame/rm/rm380z.cpp index e7a8dcf8e8e..1792db26270 100644 --- a/src/mame/rm/rm380z.cpp +++ b/src/mame/rm/rm380z.cpp @@ -136,7 +136,6 @@ Notes on COS 4.0 disassembly: TODO: -- Properly implement "backwards" or "last 4 lines" scrolling - Properly implement dimming and graphic chars (>0x80) - Understand why any write to disk command fails with "bad sector" - Understand why ctrl-U (blinking cursor) in COS 4.0 stops keyboard input from working @@ -231,7 +230,14 @@ static void rm380z_floppies(device_slot_interface &device) uint32_t rm380z_state::screen_update_rm380z(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { - update_screen(bitmap); + if (screen.width() > 240) + { + update_screen_vdu80(bitmap); + } + else + { + update_screen_vdu40(bitmap); + } return 0; } @@ -243,15 +249,13 @@ void rm380z_state::rm380z(machine_config &config) m_maincpu->set_addrmap(AS_IO, &rm380z_state::rm380z_io); /* video hardware */ - screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); - screen.set_refresh_hz(50); - screen.set_vblank_time(ATTOSECONDS_IN_USEC(0)); - // according to videos and pictures of the real hardware, chars are spaced of at least 1 pixel - // and there is at least 1 pixel between each row of characters - screen.set_size((RM380Z_SCREENCOLS*(RM380Z_CHDIMX+1)), (RM380Z_SCREENROWS*(RM380Z_CHDIMY+1))); - screen.set_visarea(0, (RM380Z_SCREENCOLS*(RM380Z_CHDIMX+1))-1, 0, (RM380Z_SCREENROWS*(RM380Z_CHDIMY+1))-1); - screen.set_screen_update(FUNC(rm380z_state::screen_update_rm380z)); - screen.set_palette("palette"); + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_refresh_hz(50); + m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0)); + m_screen->set_size(640, 240); + m_screen->set_visarea_full(); + m_screen->set_screen_update(FUNC(rm380z_state::screen_update_rm380z)); + m_screen->set_palette("palette"); PALETTE(config, "palette", palette_device::MONOCHROME); @@ -322,13 +326,12 @@ ROM_END ROM_START( rm380z ) // COS 4.0B/M ROM_REGION( 0x10000, RM380Z_MAINCPU_TAG, 0 ) - // I'm not sure of how those roms have been dumped. I don't know if those are good dumps or not. - ROM_LOAD( "cos40b-m.bin", 0x0000, 0x1000, BAD_DUMP CRC(1f0b3a5c) SHA1(0b29cb2a3b7eaa3770b34f08c4fd42844f42700f)) - ROM_LOAD( "cos40b-m_f600-f9ff.bin", 0x1000, 0x400, BAD_DUMP CRC(e3397d9d) SHA1(490a0c834b0da392daf782edc7d51ca8f0668b1a)) - ROM_LOAD( "cos40b-m_1c00-1dff.bin", 0x1400, 0x200, BAD_DUMP CRC(0f759f44) SHA1(9689c1c1faa62c56def999cbedbbb0c8d928dcff)) - // chargen ROM is undumped, afaik - ROM_REGION( 0x1680, "chargen", 0 ) - ROM_LOAD( "ch3.raw", 0x0000, 0x1680, BAD_DUMP CRC(c223622b) SHA1(185ef24896419d7ff46f71a760ac217de3811684)) + // I'm not sure of how those ROMs have been dumped. I don't know if those are good dumps or not. + ROM_LOAD( "cos40b-m.bin", 0x0000, 0x1000, BAD_DUMP CRC(1f0b3a5c) SHA1(0b29cb2a3b7eaa3770b34f08c4fd42844f42700f) ) + ROM_LOAD( "cos40b-m_f600-f9ff.bin", 0x1000, 0x0400, BAD_DUMP CRC(e3397d9d) SHA1(490a0c834b0da392daf782edc7d51ca8f0668b1a) ) + ROM_LOAD( "cos40b-m_1c00-1dff.bin", 0x1400, 0x0200, BAD_DUMP CRC(0f759f44) SHA1(9689c1c1faa62c56def999cbedbbb0c8d928dcff) ) + ROM_REGION( 0x0800, "chargen", 0 ) + ROM_LOAD( "c-gen-22.bin", 0x0000, 0x0800, CRC(1b67127f) SHA1(289a919871d30c5e832d22244bcac1dcfd544baa) ) ROM_END // RM480Z is quite different, might be better off in its own driver @@ -337,7 +340,7 @@ ROM_START( rm480z ) ROM_LOAD( "fv2.0_0_12099_19.2.86.ic83", 0x0000, 0x4000, CRC(a0f02d8a) SHA1(1c063b842699dc0ad85a5a5f337f2864497f9c0f) ) ROM_LOAD( "fv2.0_1_12100_27.2.86.ic93", 0x4000, 0x4000, CRC(2a93ca6e) SHA1(7fdd772d4251dbf951a687d184ed787cfe21212b) ) ROM_REGION( 0x2000, "chargen", 0 ) - ROM_LOAD( "cg06_12098_28.2.86.ic98", 0x0000, 0x2000, CRC(15d40f7e) SHA1(a7266357eb9be849f77a97ff3013b236c0af8289) ) + ROM_LOAD( "cg06_12098_28.2.86.ic98", 0x0000, 0x2000, CRC(15d40f7e) SHA1(a7266357eb9be849f77a97ff3013b236c0af8289) ) ROM_END ROM_START( rm480za ) @@ -350,7 +353,7 @@ ROM_START( rm480za ) ROM_LOAD( "idc3-1i.rom", 0x0000, 0x2000, CRC(39e2cdf0) SHA1(ba523af357b61bbe6192727139850f36597d79f1) ) ROM_LOAD( "idc5-1j.rom", 0x2000, 0x2000, CRC(d2ac27e2) SHA1(12d3966e0096c9bfb98135e15c3ddb37920cce15) ) ROM_REGION( 0x2000, "chargen", 0 ) - ROM_LOAD( "cg06.lq", 0x0000, 0x2000, BAD_DUMP CRC(15d40f7e) SHA1(a7266357eb9be849f77a97ff3013b236c0af8289) ) // chip is marked CG05, might not be the same, so marked as bad + ROM_LOAD( "cg06.lq", 0x0000, 0x2000, BAD_DUMP CRC(15d40f7e) SHA1(a7266357eb9be849f77a97ff3013b236c0af8289) ) // chip is marked CG05, might not be the same, so marked as bad ROM_END @@ -359,6 +362,5 @@ ROM_END COMP(1978, rm380z, 0, 0, rm380z, rm380z, rm380z_state, init_rm380z, "Research Machines", "RM-380Z, COS 4.0B", MACHINE_NO_SOUND_HW) COMP(1978, rm380z34d, rm380z, 0, rm380z, rm380z, rm380z_state, init_rm380z34d, "Research Machines", "RM-380Z, COS 3.4D", MACHINE_NO_SOUND_HW) COMP(1978, rm380z34e, rm380z, 0, rm380z, rm380z, rm380z_state, init_rm380z34e, "Research Machines", "RM-380Z, COS 3.4E", MACHINE_NO_SOUND_HW) -COMP(1981, rm480z, rm380z, 0, rm480z, rm380z, rm380z_state, init_rm380z34e, "Research Machines", "LINK RM-480Z (set 1)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) -COMP(1981, rm480za, rm380z, 0, rm480z, rm380z, rm380z_state, init_rm380z34e, "Research Machines", "LINK RM-480Z (set 2)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) - +COMP(1981, rm480z, rm380z, 0, rm480z, rm380z, rm380z_state, init_rm480z, "Research Machines", "LINK RM-480Z (set 1)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) +COMP(1981, rm480za, rm380z, 0, rm480z, rm380z, rm380z_state, init_rm480z, "Research Machines", "LINK RM-480Z (set 2)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) diff --git a/src/mame/rm/rm380z.h b/src/mame/rm/rm380z.h index ae5c4bd5991..e35ff6cb1e4 100644 --- a/src/mame/rm/rm380z.h +++ b/src/mame/rm/rm380z.h @@ -37,6 +37,7 @@ public: driver_device(mconfig, type, tag), m_chargen(*this, "chargen"), m_maincpu(*this, RM380Z_MAINCPU_TAG), + m_screen(*this, "screen"), m_cassette(*this, "cassette"), m_messram(*this, RAM_TAG), m_fdc(*this, "wd1771"), @@ -58,6 +59,26 @@ protected: virtual void machine_start() override; private: + template + class rm380z_vram + { + public: + void set_char(int row, int col, uint8_t data) { m_chars[get_row(row)][col] = data; } + void set_attrib(int row, int col, uint8_t data) { m_attribs[get_row(row)][col] = data; } + void set_scroll_register(uint8_t value) { m_scroll_reg = value; } + void reset() { memset(m_attribs, 0, sizeof(m_attribs)); memset(m_chars, 0x80, sizeof(m_chars)); } + + uint8_t get_char(int row, int col) const { return m_chars[get_row(row)][col]; } + uint8_t get_attrib(int row, int col) const { return m_attribs[get_row(row)][col]; } + + private: + int get_row(int row) const { return (row + m_scroll_reg) % ROWS; } + + uint8_t m_chars[ROWS][COLS]; + uint8_t m_attribs[ROWS][COLS]; + uint8_t m_scroll_reg = 0; + }; + static inline constexpr int RM380Z_VIDEOMODE_40COL = 0x01; static inline constexpr int RM380Z_VIDEOMODE_80COL = 0x02; @@ -68,9 +89,6 @@ private: static inline constexpr int RM380Z_SCREENCOLS = 80; static inline constexpr int RM380Z_SCREENROWS = 24; - static inline constexpr int RM380Z_VIDEORAM_SIZE = 0x600; - static inline constexpr int RM380Z_SCREENSIZE = 0x1200; - bool ports_enabled_high() const { return ( m_port0 & 0x80 ); } bool ports_enabled_low() const { return !( m_port0 & 0x80 ); } @@ -78,11 +96,10 @@ private: void put_point(int charnum, int x, int y, int col); void init_graphic_chars(); - void putChar(int charnum, int attribs, int x, int y, bitmap_ind16 &bitmap, int vmode); + void putChar_vdu80(int charnum, int attribs, int x, int y, bitmap_ind16 &bitmap); + void putChar_vdu40(int charnum, int x, int y, bitmap_ind16 &bitmap); void decode_videoram_char(int row, int col, uint8_t &chr, uint8_t &attrib); - void scroll_videoram(); void config_videomode(); - void check_scroll_register(); void port_write(offs_t offset, uint8_t data); uint8_t port_read(offs_t offset); @@ -104,7 +121,8 @@ private: DECLARE_MACHINE_RESET(rm480z); void config_memory_map(); - void update_screen(bitmap_ind16 &bitmap); + void update_screen_vdu80(bitmap_ind16 &bitmap); + void update_screen_vdu40(bitmap_ind16 &bitmap); uint32_t screen_update_rm380z(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); uint32_t screen_update_rm480z(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); TIMER_CALLBACK_MEMBER(static_vblank_timer); @@ -114,33 +132,31 @@ private: void rm480z_io(address_map &map); void rm480z_mem(address_map &map); - int writenum = 0; - uint8_t m_port0 = 0; uint8_t m_port0_mask = 0; uint8_t m_port0_kbd = 0; uint8_t m_port1 = 0; - uint8_t m_fbfd = 0; + uint8_t m_fbfd_mask = 0; uint8_t m_fbfe = 0; + uint8_t m_character_row = 0; + uint8_t m_character = 0; + uint8_t m_graphic_chars[0x80][(RM380Z_CHDIMX+1)*(RM380Z_CHDIMY+1)]; + uint8_t m_user_defined_chars[2048]; - uint8_t m_vramchars[RM380Z_SCREENROWS][RM380Z_SCREENCOLS]; - uint8_t m_vramattribs[RM380Z_SCREENROWS][RM380Z_SCREENCOLS]; + rm380z_vram m_vram; int m_rasterlineCtr = 0; emu_timer* m_vblankTimer = nullptr; - uint8_t m_old_fbfd = 0; - uint8_t m_old_old_fbfd = 0; - int m_videomode = 0; - int m_old_videomode = 0; emu_timer *m_static_vblank_timer = nullptr; required_region_ptr m_chargen; required_device m_maincpu; + optional_device m_screen; optional_device m_cassette; optional_device m_messram; optional_device m_fdc; diff --git a/src/mame/rm/rm380z_m.cpp b/src/mame/rm/rm380z_m.cpp index a079a417fda..947c47dd8d8 100644 --- a/src/mame/rm/rm380z_m.cpp +++ b/src/mame/rm/rm380z_m.cpp @@ -7,7 +7,6 @@ RM 380Z machine */ - #include "emu.h" #include "rm380z.h" @@ -29,13 +28,13 @@ bit7: 1=map ROM at 0000-0fff/0=RAM void rm380z_state::port_write(offs_t offset, uint8_t data) { - switch ( offset ) + switch (offset) { case 0xfc: // PORT0 - //printf("%s FBFCw[%2.2x] FBFD [%2.2x] FBFE [%2.2x] writenum [%4.4x]\n",machine().describe_context().c_str(),data,m_fbfd,m_fbfe,writenum); + //printf("%s FBFCw[%2.2x] FBFD [%2.2x] FBFE [%2.2x] writenum [%4.4x]\n", machine().describe_context().c_str(), data, m_fbfd, m_fbfe,writenum); m_port0 = data; - m_cassette->output((m_port0 & 0xEF) ? +1.0 : -1.0); // set 2400hz, bit 4 + m_cassette->output((m_port0 & 0xef) ? +1.0 : -1.0); // set 2400hz, bit 4 if (data & 0x01) { @@ -51,26 +50,43 @@ void rm380z_state::port_write(offs_t offset, uint8_t data) case 0xfd: // screen line counter (?) //printf("%s FBFC [%2.2x] FBFDw[%2.2x] FBFE [%2.2x] writenum [%4.4x]\n",machine().describe_context().c_str(),m_port0,data,m_fbfe,writenum); - m_old_old_fbfd = m_old_fbfd; - m_old_fbfd = m_fbfd; - m_fbfd = data; - - writenum++; - - check_scroll_register(); + if (m_port0 & 0x08) + { + // update user defined character data + if (m_character >= 128) + { + m_user_defined_chars[(m_character % 128) * 16 + m_character_row] = data; + } + } + // ignore updates while bit 4 of port 0 is set + // (counter is not used to set the scroll register in this case, maybe used for smooth scrolling?) + else if (!(m_port0 & 0x10)) + { + // set scroll register (used to verticaly scroll the screen and effect vram addressing) + m_vram.set_scroll_register(data & m_fbfd_mask); + } break; // port 1 case 0xfe: // line on screen to write to divided by 2 //printf("%s FBFC [%2.2x] FBFD [%2.2x] FBFEw[%2.2x] writenum [%4.4x]\n",machine().describe_context().c_str(),m_port0,m_fbfd,data,writenum); - m_fbfe = data; + if (!(m_port0 & 0x04)) + { + m_character_row = data; + } + else if (m_port0 & 0x08) + { + m_character = data; + } + + m_fbfe = data; break; case 0xff: // user I/O port //printf("write of [%x] to FBFF\n",data); - //logerror("%s: Write %02X to user I/O port\n", machine().describe_context(), data ); + //logerror("%s: Write %02X to user I/O port\n", machine().describe_context(), data); break; default: @@ -82,7 +98,7 @@ uint8_t rm380z_state::port_read(offs_t offset) { uint8_t data = 0xff; - switch ( offset ) + switch (offset) { case 0xfc: // PORT0 //m_port0_kbd=getKeyboard(); @@ -94,12 +110,27 @@ uint8_t rm380z_state::port_read(offs_t offset) case 0xfd: // "counter" (?) //printf("%s: Read from counter FBFD\n", machine().describe_context().c_str()); - data = 0x00; + if (m_port0 & 0x08) + { + // return character data for requested character and row + if (m_character >= 128) + { + data = m_user_defined_chars[(m_character % 128) * 16 + m_character_row]; + } + else + { + data = m_chargen[m_character * 16 + m_character_row]; + } + } + else + { + data = 0x00; + } break; case 0xfe: // PORT1 if (m_cassette->input() < +0.0) - m_port1 &= 0xDF; // bit 5 off + m_port1 &= 0xdf; // bit 5 off else m_port1 |= 0x20; // bit 5 on @@ -233,43 +264,42 @@ void rm380z_state::machine_start() void rm380z_state::init_rm380z() { m_videomode = RM380Z_VIDEOMODE_80COL; - m_old_videomode = m_videomode; m_port0_mask = 0xff; + m_fbfd_mask = 0x1f; // enable hw scrolling (uses lower 5 bits of counter) } void rm380z_state::init_rm380z34d() { m_videomode = RM380Z_VIDEOMODE_40COL; - m_old_videomode = m_videomode; m_port0_mask = 0xdf; // disable 80 column mode + m_screen->set_size(240, 240); + m_screen->set_visarea_full(); } void rm380z_state::init_rm380z34e() { m_videomode = RM380Z_VIDEOMODE_40COL; - m_old_videomode = m_videomode; m_port0_mask = 0xdf; // disable 80 column mode + m_screen->set_size(240, 240); + m_screen->set_visarea_full(); } +void rm380z_state::init_rm480z() +{ + // machine not working so do nothing +} void rm380z_state::machine_reset() { m_port0 = 0x00; m_port0_kbd = 0x00; m_port1 = 0x00; - m_fbfd = 0x00; m_fbfe = 0x00; - m_old_fbfd = 0x00; - m_old_old_fbfd = 0x00; - writenum = 0; -// m_videomode=RM380Z_VIDEOMODE_80COL; -// m_old_videomode = m_videomode; m_rasterlineCtr = 0; // note: from COS 4.0 videos, screen seems to show garbage at the beginning - memset(m_vramattribs, 0, sizeof(m_vramattribs)); - memset(m_vramchars, 0, sizeof(m_vramchars)); + m_vram.reset(); config_memory_map(); m_fdc->reset(); @@ -283,16 +313,16 @@ void rm380z_state::config_memory_map() uint8_t *rom = memregion(RM380Z_MAINCPU_TAG)->base(); uint8_t* m_ram_p = m_messram->pointer(); - if ( ports_enabled_high() ) + if (ports_enabled_high()) { - program.install_ram( 0x0000, 0xDFFF, m_ram_p ); + program.install_ram(0x0000, 0xdfff, m_ram_p); } else { - program.install_rom( 0x0000, 0x0FFF, rom ); - program.install_readwrite_handler(0x1BFC, 0x1BFF, read8sm_delegate(*this, FUNC(rm380z_state::port_read_1b00)), write8sm_delegate(*this, FUNC(rm380z_state::port_write_1b00))); - program.install_rom( 0x1C00, 0x1DFF, rom + 0x1400 ); - program.install_ram( 0x4000, 0xDFFF, m_ram_p ); + program.install_rom(0x0000, 0x0fff, rom); + program.install_readwrite_handler(0x1bfc, 0x1bff, read8sm_delegate(*this, FUNC(rm380z_state::port_read_1b00)), write8sm_delegate(*this, FUNC(rm380z_state::port_write_1b00))); + program.install_rom(0x1c00, 0x1dff, rom + 0x1400); + program.install_ram(0x4000, 0xdfff, m_ram_p); } } diff --git a/src/mame/rm/rm380z_v.cpp b/src/mame/rm/rm380z_v.cpp index 2eae61448dd..87e88200484 100644 --- a/src/mame/rm/rm380z_v.cpp +++ b/src/mame/rm/rm380z_v.cpp @@ -66,6 +66,8 @@ void rm380z_state::init_graphic_chars() void rm380z_state::config_videomode() { + int old_mode = m_videomode; + if (m_port0 & 0x20 & m_port0_mask) { // 80 cols @@ -77,9 +79,17 @@ void rm380z_state::config_videomode() m_videomode = RM380Z_VIDEOMODE_40COL; } - if (m_old_videomode != m_videomode) + if (m_videomode != old_mode) { - m_old_videomode = m_videomode; + if (m_videomode == RM380Z_VIDEOMODE_80COL) + { + m_screen->set_size(640, 240); + } + else + { + m_screen->set_size(320, 240); + } + m_screen->set_visarea_full(); } } @@ -93,8 +103,8 @@ void rm380z_state::config_videomode() void rm380z_state::decode_videoram_char(int row, int col, uint8_t& chr, uint8_t &attrib) { - uint8_t ch1 = m_vramchars[row][col]; - uint8_t ch2 = m_vramattribs[row][col]; + uint8_t ch1 = m_vram.get_char(row, col); + uint8_t ch2 = m_vram.get_attrib(row, col); // "special" (unknown) cases first if ((ch1 == 0x80) && (ch2 == 0x04)) @@ -111,13 +121,6 @@ void rm380z_state::decode_videoram_char(int row, int col, uint8_t& chr, uint8_t attrib = 8; return; } - else if ((ch1 == 0) && (ch2 == 0)) - { - // delete char (?) - chr = 0x20; - attrib = 0; - return; - } else if ((ch1 == 4) && (ch2 == 4)) { // reversed cursor? @@ -141,37 +144,6 @@ void rm380z_state::decode_videoram_char(int row, int col, uint8_t& chr, uint8_t } } -void rm380z_state::scroll_videoram() -{ - // scroll up one row of videoram - std::memmove(m_vramchars, m_vramchars[1], (RM380Z_SCREENROWS - 1) * RM380Z_SCREENCOLS); - std::memmove(m_vramattribs, m_vramattribs[1], (RM380Z_SCREENROWS - 1) * RM380Z_SCREENCOLS); - - // the last line is filled with spaces - std::memset(m_vramchars[RM380Z_SCREENROWS - 1], 0x20, RM380Z_SCREENCOLS); - std::memset(m_vramattribs[RM380Z_SCREENROWS - 1], 0x00, RM380Z_SCREENCOLS); -} - -void rm380z_state::check_scroll_register() -{ - const uint8_t r[3] = { m_old_old_fbfd, m_old_fbfd, m_fbfd }; - - if (!(r[1] & 0x20) && !(r[2] & 0x20)) - { - // it's a scroll command - - if (r[2] > r[1]) - { - scroll_videoram(); - } - else if (!r[2] && (r[1] == 0x17)) - { - // wrap-scroll - scroll_videoram(); - } - } -} - // after ctrl-L (clear screen?): routine at EBBD is executed // EB30??? next line? // memory at FF02 seems to hold the line counter (same as FBFD) @@ -189,11 +161,11 @@ void rm380z_state::videoram_write(offs_t offset, uint8_t data) // fbfc 6th bit set=attribute, unset=char if (m_port0 & 0x40) { - m_vramattribs[row][col] = data; + m_vram.set_attrib(row, col, data); } else { - m_vramchars[row][col] = data; + m_vram.set_char(row, col, data); } } // else out of bounds write had no effect (see VTOUT description in firmware guide) @@ -206,149 +178,86 @@ uint8_t rm380z_state::videoram_read(offs_t offset) { if (m_port0 & 0x40) { - return m_vramattribs[row][col]; + return m_vram.get_attrib(row, col); } else { - return m_vramchars[row][col]; + return m_vram.get_char(row, col); } } return 0; // return 0 if out of bounds (see VTIN description in firmware guide) } -void rm380z_state::putChar(int charnum, int attribs, int x, int y, bitmap_ind16 &bitmap, int vmode) +void rm380z_state::putChar_vdu80(int charnum, int attribs, int x, int y, bitmap_ind16 &bitmap) { const bool attrUnder = attribs & 0x02; - //const bool attrDim = attribs & 0x04; const bool attrRev = attribs & 0x08; + + int data_pos = (charnum % 128) * 16; - if ((charnum > 0) && (charnum <= 0x7f)) + for (int r=0; r < 10; r++, data_pos++) { - // normal chars (base set) + uint8_t data; - if (vmode==RM380Z_VIDEOMODE_80COL) + if (attrUnder && (r == 8)) { - int basex=RM380Z_CHDIMX*(charnum/RM380Z_NCY); - int basey=RM380Z_CHDIMY*(charnum%RM380Z_NCY); - - for (int r=0;r 0) && (charnum <= 0x7f)) { - // graphic chars: 0x80-0xbf is "dimmed", 0xc0-0xff is full bright - if (vmode==RM380Z_VIDEOMODE_80COL) + // normal chars (base set) + int basex=RM380Z_CHDIMX*(charnum/RM380Z_NCY); + int basey=RM380Z_CHDIMY*(charnum%RM380Z_NCY); + + for (int r=0;r