Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rm/rm380z.cpp: Add support for high resolution graphics, colour and text character dimming #12044

Merged
merged 17 commits into from Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/mame/rm/rm380z.cpp
Expand Up @@ -168,7 +168,6 @@ Module timer tag static_vblank_timer name m_expire.seconds
#include "rm380z.h"
#include "speaker.h"

#include "emupal.h"
#include "screen.h"


Expand Down Expand Up @@ -215,8 +214,15 @@ void rm380z_state::rm480z_io(address_map &map)
}

INPUT_PORTS_START( rm380z )

PORT_START("display_type")
PORT_CONFNAME( 0x01, 0x00, "Monitor" ) PORT_CHANGED_MEMBER(DEVICE_SELF, rm380z_state, monitor_changed, 0)
PORT_CONFSETTING( 0x00, "Colour Monitor" )
PORT_CONFSETTING( 0x01, "Monochrome b/w Monitor" )

// PORT_START("additional_chars")
// PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Escape") PORT_CODE(KEYCODE_ESC) PORT_CODE(KEYCODE_ESC)

INPUT_PORTS_END

//
Expand Down Expand Up @@ -257,7 +263,7 @@ void rm380z_state::rm380z(machine_config &config)
m_screen->set_screen_update(FUNC(rm380z_state::screen_update_rm380z));
m_screen->set_palette("palette");

PALETTE(config, "palette", palette_device::MONOCHROME);
PALETTE(config, m_palette, FUNC(rm380z_state::palette_init), 19);

SPEAKER(config, "mono").front_center();

Expand Down Expand Up @@ -360,7 +366,7 @@ ROM_END
/* Driver */
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
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(1978, rm380z34d, rm380z, 0, rm380z, rm380z, rm380z_state, init_rm380z34, "Research Machines", "RM-380Z, COS 3.4D", MACHINE_NO_SOUND_HW)
COMP(1978, rm380z34e, rm380z, 0, rm380z, rm380z, rm380z_state, init_rm380z34, "Research Machines", "RM-380Z, COS 3.4E", MACHINE_NO_SOUND_HW)
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)
43 changes: 35 additions & 8 deletions src/mame/rm/rm380z.h
Expand Up @@ -13,6 +13,7 @@ Research Machines RM 380Z
#pragma once

#include "cpu/z80/z80.h"
#include "emupal.h"
#include "imagedev/cassette.h"
cuavas marked this conversation as resolved.
Show resolved Hide resolved
#include "imagedev/floppy.h"
#include "machine/keyboard.h"
Expand All @@ -38,22 +39,25 @@ class rm380z_state : public driver_device
m_chargen(*this, "chargen"),
m_maincpu(*this, RM380Z_MAINCPU_TAG),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_cassette(*this, "cassette"),
m_messram(*this, RAM_TAG),
m_fdc(*this, "wd1771"),
m_floppy0(*this, "wd1771:0"),
m_floppy1(*this, "wd1771:1")
m_floppy1(*this, "wd1771:1"),
m_io_display_type(*this, "display_type")
{
}

void rm480z(machine_config &config);
void rm380z(machine_config &config);

void init_rm380z();
void init_rm380z34d();
void init_rm380z34e();
void init_rm380z34();
void init_rm480z();

DECLARE_INPUT_CHANGED_MEMBER(monitor_changed);

protected:
virtual void machine_reset() override;
virtual void machine_start() override;
Expand All @@ -79,6 +83,8 @@ class rm380z_state : public driver_device
uint8_t m_scroll_reg = 0;
};

enum hrg_display_mode { RM380Z_HRG_MODE_NONE, RM380Z_HRG_MODE_HIGH, RM380Z_HRG_MODE_MEDIUM_0, RM380Z_HRG_MODE_MEDIUM_1 };
cuavas marked this conversation as resolved.
Show resolved Hide resolved

static inline constexpr int RM380Z_VIDEOMODE_40COL = 0x01;
static inline constexpr int RM380Z_VIDEOMODE_80COL = 0x02;

Expand All @@ -89,16 +95,23 @@ class rm380z_state : public driver_device
static inline constexpr int RM380Z_SCREENCOLS = 80;
static inline constexpr int RM380Z_SCREENROWS = 24;

// the HRG reference manual only mentions 12 memory pages for the display, but RML Extended BASIC v 5.0L
// writes beyond this to store character data for the HRG Level 2 "STPLOT" function. Hence 16 pages are
// reserved here to support HRG text characters.
static inline constexpr int RM380Z_HRG_RAM_PAGES = 16;
static inline constexpr int RM380Z_HRG_RAM_SIZE = RM380Z_HRG_RAM_PAGES * 1280;
static inline constexpr int RM380Z_HRG_SCRATCHPAD_SIZE = 16;

bool ports_enabled_high() const { return ( m_port0 & 0x80 ); }
bool ports_enabled_low() const { return !( m_port0 & 0x80 ); }

bool get_rowcol_from_offset(int &row, int &col, offs_t offset) const;
void put_point(int charnum, int x, int y, int col);
void init_graphic_chars();

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 putChar_vdu80(int charnum, int attribs, int x, int y, bitmap_ind16 &bitmap) const;
void putChar_vdu40(int charnum, int x, int y, bitmap_ind16 &bitmap) const;
void decode_videoram_char(int row, int col, uint8_t &chr, uint8_t &attrib) const;
cuavas marked this conversation as resolved.
Show resolved Hide resolved
void config_videomode();

void port_write(offs_t offset, uint8_t data);
Expand All @@ -121,8 +134,13 @@ class rm380z_state : public driver_device
DECLARE_MACHINE_RESET(rm480z);

void config_memory_map();
void update_screen_vdu80(bitmap_ind16 &bitmap);
void update_screen_vdu40(bitmap_ind16 &bitmap);
void palette_init(palette_device &palette) const;
void change_hrg_scratchpad(int index, uint8_t value, uint8_t mask);
void change_palette(int index, uint8_t value) const;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are also conceptually not the sort of things that should be const.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree about these so have changed the palette altering methods to be non const.

void draw_high_res_graphics(bitmap_ind16 &bitmap) const;
void draw_medium_res_graphics(bitmap_ind16 &bitmap) const;
void update_screen_vdu80(bitmap_ind16 &bitmap) const;
void update_screen_vdu40(bitmap_ind16 &bitmap) const;
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);
Expand All @@ -139,6 +157,10 @@ class rm380z_state : public driver_device
uint8_t m_fbfd_mask = 0;
uint8_t m_fbfe = 0;

uint8_t m_hrg_port0 = 0;
uint8_t m_hrg_port1 = 0;
hrg_display_mode m_hrg_display_mode = RM380Z_HRG_MODE_NONE;

uint8_t m_character_row = 0;
uint8_t m_character = 0;

Expand All @@ -147,6 +169,9 @@ class rm380z_state : public driver_device

rm380z_vram<RM380Z_SCREENROWS, RM380Z_SCREENCOLS> m_vram;

uint8_t m_hrg_ram[RM380Z_HRG_RAM_SIZE];
uint8_t m_hrg_scratchpad[RM380Z_HRG_SCRATCHPAD_SIZE];

int m_rasterlineCtr = 0;
emu_timer* m_vblankTimer = nullptr;

Expand All @@ -157,11 +182,13 @@ class rm380z_state : public driver_device
required_region_ptr<u8> m_chargen;
required_device<cpu_device> m_maincpu;
optional_device<screen_device> m_screen;
optional_device<palette_device> m_palette;
optional_device<cassette_image_device> m_cassette;
optional_device<ram_device> m_messram;
optional_device<fd1771_device> m_fdc;
optional_device<floppy_connector> m_floppy0;
optional_device<floppy_connector> m_floppy1;
required_ioport m_io_display_type;
};

#endif // MAME_RM_RM380Z_H
74 changes: 57 additions & 17 deletions src/mame/rm/rm380z_m.cpp
Expand Up @@ -30,18 +30,52 @@ void rm380z_state::port_write(offs_t offset, uint8_t data)
{
switch (offset)
{
case 0x00:
if ((m_hrg_port0 & 0x01) && !(data & 0x01))
{
// set low nibble of scratchpad (palette data) when bit 0 toggled
change_hrg_scratchpad(m_hrg_port1 >> 4, m_hrg_port1 & 0x0f, 0xf0);
}
else if ((m_hrg_port0 & 0x02) && !(data & 0x02))
{
// set high nibble of scratchpad (palette data) when bit 1 toggled
change_hrg_scratchpad(m_hrg_port1 >> 4, m_hrg_port1 << 4, 0x0f);
}

switch (data)
{
case 0x03:
m_hrg_display_mode = RM380Z_HRG_MODE_HIGH;
break;
case 0xa3:
m_hrg_display_mode = RM380Z_HRG_MODE_MEDIUM_0;
break;
case 0xc3:
m_hrg_display_mode = RM380Z_HRG_MODE_MEDIUM_1;
break;
}

m_hrg_port0 = data;
break;

case 0x01:
// video ram page number (for subsequent read/write) or scratchpad data
m_hrg_port1 = data;
break;

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);
m_port0 = data;

m_cassette->output((m_port0 & 0xef) ? +1.0 : -1.0); // set 2400hz, bit 4
m_cassette->output((data & 0xef) ? +1.0 : -1.0); // set 2400hz, bit 4

if (data & 0x01)
if ((data & 0x01) && !(m_port0 & 0x01))
{
//printf("WARNING: bit0 of port0 reset\n");
// only clear keyboard latch if bit has changed value
m_port0_kbd = 0;
m_port1 &= ~0x01;
}
m_port1 &= ~0x01; //?

m_port0 = data;

config_videomode();
config_memory_map();
Expand Down Expand Up @@ -100,6 +134,13 @@ uint8_t rm380z_state::port_read(offs_t offset)

switch (offset)
{
case 0x00:
// bit 0 is low during HRG frame blanking
// bit 1 is low duing HRG line blanking
// (this is the inverse of VDU port 1 shifted 6 bits to the right)
data = ((m_port1 & 0xf0) >> 6) ^ 0x03;
break;
cuavas marked this conversation as resolved.
Show resolved Hide resolved

case 0xfc: // PORT0
//m_port0_kbd=getKeyboard();
data = m_port0_kbd;
Expand Down Expand Up @@ -209,7 +250,8 @@ TIMER_CALLBACK_MEMBER(rm380z_state::static_vblank_timer)
}

// line blanking
if ((m_rasterlineCtr % LINE_SUBDIVISION) > 80)
// according to wikipedia this occupies 18.8% of a scanline for PAL
if ((m_rasterlineCtr % LINE_SUBDIVISION) > 67)
{
m_port1 |= 0x80;
}
Expand Down Expand Up @@ -268,20 +310,13 @@ void rm380z_state::init_rm380z()
m_fbfd_mask = 0x1f; // enable hw scrolling (uses lower 5 bits of counter)
}

void rm380z_state::init_rm380z34d()
{
m_videomode = RM380Z_VIDEOMODE_40COL;
m_port0_mask = 0xdf; // disable 80 column mode
m_screen->set_size(240, 240);
m_screen->set_visarea_full();
}

void rm380z_state::init_rm380z34e()
void rm380z_state::init_rm380z34()
{
m_videomode = RM380Z_VIDEOMODE_40COL;
m_port0_mask = 0xdf; // disable 80 column mode
m_screen->set_size(240, 240);
m_screen->set_visarea_full();
init_graphic_chars();
}

void rm380z_state::init_rm480z()
Expand All @@ -296,15 +331,20 @@ void rm380z_state::machine_reset()
m_port1 = 0x00;
m_fbfe = 0x00;

m_hrg_port0 = 0x00;
m_hrg_port1 = 0x00;
m_hrg_display_mode = RM380Z_HRG_MODE_NONE;

m_rasterlineCtr = 0;

// note: from COS 4.0 videos, screen seems to show garbage at the beginning
m_vram.reset();

memset(m_hrg_ram, 0, sizeof(m_hrg_ram));
memset(m_hrg_scratchpad, 0, sizeof(m_hrg_scratchpad));

config_memory_map();
m_fdc->reset();

init_graphic_chars();
}

void rm380z_state::config_memory_map()
Expand Down