mirror of
https://github.com/holub/mame
synced 2025-06-05 20:33:45 +03:00
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.
This commit is contained in:
parent
aaf935a9a1
commit
e47f02485c
@ -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)
|
||||
|
@ -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 <int ROWS, int COLS>
|
||||
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_graphic_chars[0x80][(RM380Z_CHDIMX+1)*(RM380Z_CHDIMY+1)];
|
||||
uint8_t m_character_row = 0;
|
||||
uint8_t m_character = 0;
|
||||
|
||||
uint8_t m_vramchars[RM380Z_SCREENROWS][RM380Z_SCREENCOLS];
|
||||
uint8_t m_vramattribs[RM380Z_SCREENROWS][RM380Z_SCREENCOLS];
|
||||
uint8_t m_graphic_chars[0x80][(RM380Z_CHDIMX+1)*(RM380Z_CHDIMY+1)];
|
||||
uint8_t m_user_defined_chars[2048];
|
||||
|
||||
rm380z_vram<RM380Z_SCREENROWS, RM380Z_SCREENCOLS> 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<u8> m_chargen;
|
||||
required_device<cpu_device> m_maincpu;
|
||||
optional_device<screen_device> m_screen;
|
||||
optional_device<cassette_image_device> m_cassette;
|
||||
optional_device<ram_device> m_messram;
|
||||
optional_device<fd1771_device> m_fdc;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
for (int r=0; r < 10; r++, data_pos++)
|
||||
{
|
||||
uint8_t data;
|
||||
|
||||
if (attrUnder && (r == 8))
|
||||
{
|
||||
// rows 11 and 12 of char data replace rows 9 and 10 to underline
|
||||
data_pos += 2;
|
||||
}
|
||||
|
||||
if (charnum < 128)
|
||||
{
|
||||
data = m_chargen[data_pos];
|
||||
}
|
||||
else
|
||||
{
|
||||
data = m_user_defined_chars[data_pos];
|
||||
}
|
||||
|
||||
for (int c=0; c < 8; c++, data <<= 1)
|
||||
{
|
||||
uint8_t pixel_value = (data & 0x80) ? 1 : 0;
|
||||
if (attrRev)
|
||||
{
|
||||
pixel_value = !pixel_value;
|
||||
}
|
||||
bitmap.pix(y * 10 + r, x * 8 + c) = pixel_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rm380z_state::putChar_vdu40(int charnum, int x, int y, bitmap_ind16 &bitmap)
|
||||
{
|
||||
if ((charnum > 0) && (charnum <= 0x7f))
|
||||
{
|
||||
// normal chars (base set)
|
||||
int basex=RM380Z_CHDIMX*(charnum/RM380Z_NCY);
|
||||
int basey=RM380Z_CHDIMY*(charnum%RM380Z_NCY);
|
||||
|
||||
if (vmode==RM380Z_VIDEOMODE_80COL)
|
||||
for (int r=0;r<RM380Z_CHDIMY;r++)
|
||||
{
|
||||
int basex=RM380Z_CHDIMX*(charnum/RM380Z_NCY);
|
||||
int basey=RM380Z_CHDIMY*(charnum%RM380Z_NCY);
|
||||
|
||||
for (int r=0;r<RM380Z_CHDIMY;r++)
|
||||
for (int c=0;c<RM380Z_CHDIMX;c++)
|
||||
{
|
||||
for (int c=0;c<RM380Z_CHDIMX;c++)
|
||||
{
|
||||
uint8_t chval = (m_chargen[((basey + r) * RM380Z_CHDIMX * RM380Z_NCX) + (basex + c)] == 0xff) ? 0 : 1;
|
||||
|
||||
if (attrRev)
|
||||
{
|
||||
if (chval==0) chval=1;
|
||||
else chval=0;
|
||||
}
|
||||
|
||||
if (attrUnder)
|
||||
{
|
||||
if (r==(RM380Z_CHDIMY-1))
|
||||
{
|
||||
if (attrRev) chval=0;
|
||||
else chval=1;
|
||||
}
|
||||
}
|
||||
|
||||
bitmap.pix((y*(RM380Z_CHDIMY+1))+r,(x*(RM380Z_CHDIMX+1))+c) = chval;
|
||||
}
|
||||
}
|
||||
|
||||
// last pixel of underline
|
||||
if (attrUnder&&(!attrRev))
|
||||
{
|
||||
bitmap.pix((y*(RM380Z_CHDIMY+1))+(RM380Z_CHDIMY-1),(x*(RM380Z_CHDIMX+1))+RM380Z_CHDIMX) = attrRev?0:1;
|
||||
}
|
||||
|
||||
// if reversed, print another column of pixels on the right
|
||||
if (attrRev)
|
||||
{
|
||||
for (int r=0;r<RM380Z_CHDIMY;r++)
|
||||
{
|
||||
bitmap.pix((y*(RM380Z_CHDIMY+1))+r,(x*(RM380Z_CHDIMX+1))+RM380Z_CHDIMX) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (vmode==RM380Z_VIDEOMODE_40COL)
|
||||
{
|
||||
int basex=RM380Z_CHDIMX*(charnum/RM380Z_NCY);
|
||||
int basey=RM380Z_CHDIMY*(charnum%RM380Z_NCY);
|
||||
|
||||
for (int r=0;r<RM380Z_CHDIMY;r++)
|
||||
{
|
||||
for (int c=0;c<(RM380Z_CHDIMX*2);c+=2)
|
||||
{
|
||||
uint8_t chval = (m_chargen[((basey + r) * RM380Z_CHDIMX * RM380Z_NCX) + (basex + (c / 2))] == 0xff) ? 0 : 1;
|
||||
|
||||
if (attrRev)
|
||||
{
|
||||
if (chval==0) chval=1;
|
||||
else chval=0;
|
||||
}
|
||||
|
||||
if (attrUnder)
|
||||
{
|
||||
if (r==(RM380Z_CHDIMY-1))
|
||||
{
|
||||
if (attrRev) chval=0;
|
||||
else chval=1;
|
||||
}
|
||||
}
|
||||
|
||||
bitmap.pix( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+c) = chval;
|
||||
bitmap.pix( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+c+1) = chval;
|
||||
}
|
||||
}
|
||||
|
||||
// last 2 pixels of underline
|
||||
if (attrUnder)
|
||||
{
|
||||
bitmap.pix( (y*(RM380Z_CHDIMY+1))+RM380Z_CHDIMY-1 , ((x*(RM380Z_CHDIMX+1))*2)+(RM380Z_CHDIMX*2)) = attrRev?0:1;
|
||||
bitmap.pix( (y*(RM380Z_CHDIMY+1))+RM380Z_CHDIMY-1 , ((x*(RM380Z_CHDIMX+1))*2)+(RM380Z_CHDIMX*2)+1) = attrRev?0:1;
|
||||
}
|
||||
|
||||
// if reversed, print another 2 columns of pixels on the right
|
||||
if (attrRev)
|
||||
{
|
||||
for (int r=0;r<RM380Z_CHDIMY;r++)
|
||||
{
|
||||
bitmap.pix( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+((RM380Z_CHDIMX)*2)) = 1;
|
||||
bitmap.pix( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+((RM380Z_CHDIMX)*2)+1) = 1;
|
||||
}
|
||||
uint8_t chval = (m_chargen[((basey + r) * RM380Z_CHDIMX * RM380Z_NCX) + basex + c] == 0xff) ? 0 : 1;
|
||||
bitmap.pix(y * (RM380Z_CHDIMY+1) + r, x * (RM380Z_CHDIMX+1) + c) = chval;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// graphic chars: 0x80-0xbf is "dimmed", 0xc0-0xff is full bright
|
||||
if (vmode==RM380Z_VIDEOMODE_80COL)
|
||||
// graphic chars
|
||||
for (int r=0;r<RM380Z_CHDIMY;r++)
|
||||
{
|
||||
for (int r=0;r<(RM380Z_CHDIMY+1);r++)
|
||||
for (int c=0;c<RM380Z_CHDIMX;c++)
|
||||
{
|
||||
for (int c=0;c<RM380Z_CHDIMX;c++)
|
||||
{
|
||||
bitmap.pix((y*(RM380Z_CHDIMY+1))+r,(x*(RM380Z_CHDIMX+1))+c) = m_graphic_chars[charnum&0x3f][c+(r*(RM380Z_CHDIMX+1))];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int r=0;r<RM380Z_CHDIMY;r++)
|
||||
{
|
||||
for (int c=0;c<(RM380Z_CHDIMX*2);c+=2)
|
||||
{
|
||||
bitmap.pix( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+c) = m_graphic_chars[charnum&0x3f][(c/2)+(r*(RM380Z_CHDIMX+1))];
|
||||
bitmap.pix( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+c+1) = m_graphic_chars[charnum&0x3f][(c/2)+(r*(RM380Z_CHDIMX+1))];
|
||||
}
|
||||
bitmap.pix(y * (RM380Z_CHDIMY+1) + r, x * (RM380Z_CHDIMX+1) +c) = m_graphic_chars[charnum&0x3f][c + r * (RM380Z_CHDIMX+1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rm380z_state::update_screen(bitmap_ind16 &bitmap)
|
||||
void rm380z_state::update_screen_vdu80(bitmap_ind16 &bitmap)
|
||||
{
|
||||
const int ncols = (m_videomode == RM380Z_VIDEOMODE_40COL) ? 40 : 80;
|
||||
|
||||
@ -361,8 +270,32 @@ void rm380z_state::update_screen(bitmap_ind16 &bitmap)
|
||||
{
|
||||
uint8_t curch,attribs;
|
||||
decode_videoram_char(row, col, curch, attribs);
|
||||
putChar(curch, attribs, col, row, bitmap, m_videomode);
|
||||
//putChar(0x44, 0x00, 10, 10, bitmap, m_videomode);
|
||||
putChar_vdu80(curch, attribs, col, row, bitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rm380z_state::update_screen_vdu40(bitmap_ind16 &bitmap)
|
||||
{
|
||||
const int ncols = 40;
|
||||
|
||||
// blank screen
|
||||
bitmap.fill(0);
|
||||
|
||||
for (int row = 0; row < RM380Z_SCREENROWS; row++)
|
||||
{
|
||||
for (int col = 0; col < ncols; col++)
|
||||
{
|
||||
uint8_t curch = m_vram.get_char(row, col);
|
||||
if (curch == 0)
|
||||
{
|
||||
// NUL character looked like 'O' when displayed and could be used instead of 'O'
|
||||
// In fact the front panel writes 0x49, 0x00 to display "IO", and in COS 3.4
|
||||
// displaying or typing 'O' actually writes 0x00 to vram.
|
||||
// This hack is only necessary because we don't have the real 74LS262 charset ROM
|
||||
curch = 'O';
|
||||
}
|
||||
putChar_vdu40(curch, col, row, bitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -383,7 +316,7 @@ uint32_t rm380z_state::screen_update_rm480z(screen_device &screen, bitmap_ind16
|
||||
uint8_t gfx = 0;
|
||||
if (ra < 10)
|
||||
{
|
||||
const uint8_t chr = m_vramchars[y][x];
|
||||
const uint8_t chr = m_vram.get_char(y, x);
|
||||
gfx = m_chargen[(chr << 4) | ra ];
|
||||
}
|
||||
/* Display a scanline of a character */
|
||||
|
Loading…
Reference in New Issue
Block a user