mirror of
https://github.com/holub/mame
synced 2025-04-25 09:50:04 +03:00

* Electronic circuits and base components like resistors or capacitors do not have a reset line. You can use them to create reset circuits. There is thus no point to support soft reset, the equivalent to pressing the reset button. * Fixed some bugs around reset and start up logic. * This also fixes the "scramble F3" crash.
591 lines
18 KiB
C++
591 lines
18 KiB
C++
// license:BSD-3-Clause
|
|
// copyright-holders:Couriersud
|
|
/***************************************************************************
|
|
|
|
fixfreq.h
|
|
|
|
2013-2020 Couriersud
|
|
|
|
Fixed frequency monochrome monitor emulation
|
|
|
|
The driver is intended for drivers which provide an analog video signal.
|
|
VSYNC and HSYNC levels are used to create the bitmap.
|
|
|
|
***************************************************************************/
|
|
|
|
#include "emu.h"
|
|
#include "ui/uimain.h"
|
|
#include "rendutil.h"
|
|
#include "fixfreq.h"
|
|
|
|
// for quick and dirty debugging
|
|
#define VERBOSE 0
|
|
#define LOG_OUTPUT_STREAM std::cerr
|
|
#include "logmacro.h"
|
|
|
|
#include <algorithm>
|
|
|
|
// --------------------------------------------------------------------------
|
|
// Fixed frequency monitor
|
|
// --------------------------------------------------------------------------
|
|
|
|
// device type definition
|
|
DEFINE_DEVICE_TYPE(FIXFREQ, fixedfreq_device, "fixfreq", "Fixed-Frequency Monochrome Monitor")
|
|
|
|
// --------------------------------------------------------------------------
|
|
// Port adjuster support
|
|
// --------------------------------------------------------------------------
|
|
|
|
#define PORT_ADJUSTERX(_id, _name, _min, _max) \
|
|
PORT_START(# _id) \
|
|
configurer.field_alloc(IPT_ADJUSTER, (static_cast<fixedfreq_device &>(owner).monitor_val(_id)), 0xffff, ("Monitor - " _name)); \
|
|
PORT_MINMAX(_min, _max) PORT_CHANGED_MEMBER(DEVICE_SELF, fixedfreq_device, port_changed, _id) \
|
|
PORT_CONDITION("ENABLE", 0x01, EQUALS, 0x01)
|
|
|
|
#define IOPORT_ID(_id) ioport(# _id)
|
|
|
|
enum fixedfreq_tag_id_e
|
|
{
|
|
HVISIBLE,
|
|
HFRONTPORCH,
|
|
HSYNC,
|
|
HBACKPORCH,
|
|
VVISIBLE,
|
|
VFRONTPORCH,
|
|
VSYNC,
|
|
VBACKPORCH,
|
|
SYNCTHRESHOLD,
|
|
VSYNCTHRESHOLD,
|
|
GAIN,
|
|
SCANLINE_HEIGHT
|
|
};
|
|
|
|
void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const double newval)
|
|
{
|
|
const time_type delta_time = time - m_last_sync_time;
|
|
|
|
const int last_vsync = m_sig_vsync;
|
|
const int last_comp = m_sig_composite;
|
|
|
|
m_vsync_filter += ((double) last_comp - m_vsync_filter) * (1.0 - exp(-delta_time * m_desc.vsync_filter_timeconst()));
|
|
m_sig_composite = (newval < m_desc.m_sync_threshold) ? 1 : 0 ;
|
|
|
|
m_sig_vsync = (m_vsync_filter > m_desc.m_vsync_threshold) ? 1 : 0;
|
|
|
|
if (!last_vsync && m_sig_vsync)
|
|
{
|
|
LOG("VSYNC UP %f %d\n", m_last_x, m_last_y);
|
|
m_intf.vsync_end_cb(time - m_last_vsync_time);
|
|
//auto d=time - m_last_vsync_time;
|
|
//printf("%f\n", 1.0 / d);
|
|
m_last_vsync_time = time;
|
|
// FIXME: this is wrong: we need to count lines with half-scanline width
|
|
// to determine the field.
|
|
m_sig_field = last_comp; /* force false-progressive */
|
|
m_sig_field = (m_sig_field ^ 1) ^ last_comp; /* if there is no field switch, auto switch */
|
|
m_last_y = 0; //m_desc.vbackporch_width();
|
|
|
|
// discharge
|
|
//m_vsync_filter = 0.0;
|
|
}
|
|
else if (last_vsync && !m_sig_vsync)
|
|
{
|
|
LOG("VSYNC DOWN %f %d\n", m_last_x, m_last_y);
|
|
//LOG("Field: %d\n", m_sig_field);
|
|
}
|
|
|
|
if (!last_comp && m_sig_composite)
|
|
{
|
|
if (m_sig_vsync)
|
|
LOG("Hsync in vsync\n");
|
|
/* TODO - time since last hsync and field detection */
|
|
//LOG("HSYNC up %d\n", m_last_x);
|
|
// FIXME: pixels > 50 filters some spurious hysnc on line 23/24 in breakout
|
|
// The hsync signal transition from high to low is 7 pixels too
|
|
// early, goes up again after 6.8 pix and down after 7.2 pix.
|
|
// Therefore we need to filter early low to high transitions
|
|
// and base hsync on the start of the hsync signal.
|
|
if (!m_sig_vsync && (m_last_x > m_desc.m_hscale * 100))
|
|
{
|
|
m_last_y += m_desc.m_fieldcount;
|
|
m_last_x = 0;
|
|
m_line_time = time + 1.0 / m_desc.hsync_filter_timeconst();
|
|
}
|
|
//if (!m_sig_vsync && (m_last_x < m_desc.m_hscale * 100))
|
|
// printf("HSYNC up %d %f\n", m_last_y, m_last_x);
|
|
}
|
|
else if (last_comp && !m_sig_composite)
|
|
{
|
|
/* falling composite */
|
|
//LOG("HSYNC down %f %d %f\n", time * 1e6, m_last_x, m_sync_signal);
|
|
}
|
|
m_last_sync_val = newval;
|
|
m_last_sync_time = time;
|
|
}
|
|
|
|
void fixedfreq_monitor_state::update_bm(const time_type &time)
|
|
{
|
|
const float pixels = (time - m_line_time) * (double) m_desc.monitor_clock();
|
|
const int has_fields = (m_desc.m_fieldcount > 1) ? 1: 0;
|
|
const float fhscale(static_cast<float>(m_desc.m_hscale));
|
|
|
|
//uint32_t col(0xffff0000); // Mark sync areas
|
|
//if (m_last_sync >= m_desc.m_sync_threshold)
|
|
// col = m_col;
|
|
|
|
if (!m_sig_vsync && !m_sig_composite)
|
|
{
|
|
m_fragments.push_back({static_cast<float>(m_last_y + m_sig_field * has_fields),
|
|
m_last_x * fhscale, pixels * fhscale, m_col});
|
|
}
|
|
//m_intf.plot_hline(m_last_x, m_last_y + m_sig_field * has_fields, pixels, col);
|
|
m_last_x = pixels;
|
|
}
|
|
|
|
void fixedfreq_monitor_state::update_composite_monochrome(const time_type &time, const double data)
|
|
{
|
|
update_bm(time);
|
|
update_sync_channel(time, data);
|
|
|
|
//int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
|
|
int colv = (int) ((data - 1.5) * m_desc.m_gain * 255.0);
|
|
if (colv > 255)
|
|
colv = 255;
|
|
if (colv < 0)
|
|
//m_col = 0xffff0000;
|
|
m_col = 0x0000000;
|
|
else
|
|
m_col = 0xff000000 | (colv<<16) | (colv<<8) | colv;
|
|
}
|
|
|
|
void fixedfreq_monitor_state::update_red(const time_type &time, const double data)
|
|
{
|
|
update_bm(time);
|
|
|
|
int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
|
|
if (colv > 255)
|
|
colv = 255;
|
|
if (colv < 0)
|
|
colv = 0;
|
|
m_col = (m_col & 0xff00ffff) | (colv<<16);
|
|
}
|
|
|
|
void fixedfreq_monitor_state::update_green(const time_type &time, const double data)
|
|
{
|
|
update_bm(time);
|
|
//update_sync_channel(ctime, data);
|
|
|
|
int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
|
|
if (colv > 255)
|
|
colv = 255;
|
|
if (colv < 0)
|
|
colv = 0;
|
|
m_col = (m_col & 0xffff00ff) | (colv<<8);
|
|
}
|
|
|
|
void fixedfreq_monitor_state::update_blue(const time_type &time, const double data)
|
|
{
|
|
update_bm(time);
|
|
//update_sync_channel(ctime, data);
|
|
|
|
int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
|
|
if (colv > 255)
|
|
colv = 255;
|
|
if (colv < 0)
|
|
colv = 0;
|
|
m_col = (m_col & 0xffffff00) | colv;
|
|
|
|
}
|
|
|
|
void fixedfreq_monitor_state::update_sync(const time_type &time, const double data)
|
|
{
|
|
update_bm(time);
|
|
update_sync_channel(time, data);
|
|
}
|
|
|
|
fixedfreq_device::fixedfreq_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
|
|
: device_t(mconfig, type, tag, owner, clock),
|
|
device_video_interface(mconfig, *this, false),
|
|
m_enable(*this, "ENABLE"),
|
|
m_vector(*this, "VECTOR"),
|
|
m_scanline_height(1.0),
|
|
m_monitor(),
|
|
m_state(m_monitor, *this)
|
|
{
|
|
}
|
|
|
|
fixedfreq_device::fixedfreq_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: fixedfreq_device(mconfig, FIXFREQ, tag, owner, clock)
|
|
{
|
|
}
|
|
|
|
void fixedfreq_device::device_config_complete()
|
|
{
|
|
if (!has_screen())
|
|
return;
|
|
if (!screen().refresh_attoseconds())
|
|
screen().set_raw(m_monitor.m_monitor_clock, m_monitor.htotal(), 0,
|
|
m_monitor.htotal(), m_monitor.vtotal(), 0,
|
|
m_monitor.vtotal());
|
|
if (!screen().has_screen_update())
|
|
screen().set_screen_update(*this, FUNC(fixedfreq_device::screen_update));
|
|
LOG("config complete\n");
|
|
}
|
|
|
|
void fixedfreq_device::device_start()
|
|
{
|
|
m_state.start();
|
|
|
|
// FIXME: will be done by netlist going forward
|
|
save_item(NAME(m_state.m_last_sync_val));
|
|
save_item(NAME(m_state.m_last_x));
|
|
save_item(NAME(m_state.m_last_y));
|
|
save_item(NAME(m_state.m_last_sync_time));
|
|
save_item(NAME(m_state.m_line_time));
|
|
save_item(NAME(m_state.m_last_hsync_time));
|
|
save_item(NAME(m_state.m_last_vsync_time));
|
|
|
|
/* sync separator */
|
|
save_item(NAME(m_state.m_vsync_filter));
|
|
|
|
save_item(NAME(m_state.m_sig_vsync));
|
|
save_item(NAME(m_state.m_sig_composite));
|
|
save_item(NAME(m_state.m_sig_field));
|
|
LOG("start\n");
|
|
}
|
|
|
|
void fixedfreq_device::device_reset()
|
|
{
|
|
m_state.reset();
|
|
LOG("Reset\n");
|
|
//ioport("YYY")->field(0xffff)->live().value = 20;
|
|
#if 0
|
|
//IOPORT_ID(HVISIBLE)->field(~0)->set_value(m_monitor.m_hvisible);
|
|
//IOPORT_ID(HVISIBLE)->update_defvalue(false);
|
|
IOPORT_ID(HVISIBLE)->live().defvalue = m_monitor.m_hvisible;
|
|
IOPORT_ID(HFRONTPORCH)->write(m_monitor.m_hsync);
|
|
IOPORT_ID(HSYNC)->write(m_monitor.m_hfrontporch);
|
|
IOPORT_ID(HBACKPORCH)->write(m_monitor.m_hbackporch);
|
|
IOPORT_ID(VVISIBLE)->write(m_monitor.m_vvisible);
|
|
IOPORT_ID(VFRONTPORCH)->write(m_monitor.m_vfrontporch);
|
|
IOPORT_ID(VSYNC)->write(m_monitor.m_vsync);
|
|
IOPORT_ID(VBACKPORCH)->write(m_monitor.m_vbackporch);
|
|
IOPORT_ID(SYNCTHRESHOLD)->write(m_monitor.m_sync_threshold * 1000.0);
|
|
IOPORT_ID(GAIN)->write(m_monitor.m_gain * 1000.0);
|
|
#endif
|
|
}
|
|
|
|
void fixedfreq_device::device_post_load()
|
|
{
|
|
//recompute_parameters();
|
|
LOG("post load\n");
|
|
}
|
|
|
|
static uint32_t nom_col(uint32_t col)
|
|
{
|
|
float r = ((col >> 16) & 0xff);
|
|
float g = ((col >> 8) & 0xff);
|
|
float b = ((col >> 0) & 0xff);
|
|
|
|
float m = std::max(r, std::max(g,b));
|
|
if (m == 0.0f)
|
|
return 0;
|
|
return (((uint32_t) m ) << 24) | (((uint32_t) (r/m*255.0f) ) << 16)
|
|
| (((uint32_t) (g/m*255.0f) ) << 8) | (((uint32_t) (b/m*255.0f) ) << 0);
|
|
}
|
|
|
|
static void draw_testpat(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
|
{
|
|
// Test pattern Grey scale
|
|
const int stripes = 255;
|
|
//auto va(screen.visible_area());
|
|
auto &va(cliprect);
|
|
|
|
for (int i = 0; i < stripes; i++)
|
|
{
|
|
int l = va.left() + (i * va.width() / stripes);
|
|
int w = (va.left() + (i+1) * va.width() / stripes) - l;
|
|
int v = (255 * i) / stripes;
|
|
bitmap.plot_box(l, va.top()+20, w, va.height()/2-20, rgb_t(0xff, v, v, v));
|
|
}
|
|
|
|
int l(va.left() + va.width() / 4);
|
|
int w(va.width() / 4);
|
|
int t(va.top() + va.height() / 2);
|
|
int h(va.height() / 2);
|
|
// 50% Test pattern
|
|
for (int i = t; i < t + h; i += 2)
|
|
{
|
|
bitmap.plot_box(l, i, w, i, rgb_t(0xff, 0xff, 0xff, 0xff));
|
|
bitmap.plot_box(l, i + 1, w, i + 1, rgb_t(0xff, 0, 0, 0));
|
|
}
|
|
l += va.width() / 4;
|
|
bitmap.plot_box(l, t, w, h, rgb_t(0xff, 0xc3, 0xc3, 0xc3)); // 195
|
|
}
|
|
|
|
uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
|
{
|
|
//printf("%f %f\n", m_state.m_fragments[0].y, m_state.m_fragments[m_state.m_fragments.size()-1].y);
|
|
bool force_vector = screen.screen_type() == SCREEN_TYPE_VECTOR || (m_vector->read() & 1);
|
|
bool debug_timing = (m_enable->read() & 2) == 2;
|
|
bool test_pat = (m_enable->read() & 4) == 4;
|
|
rgb_t backcol = debug_timing ? rgb_t(0xff, 0xff, 0x00, 0x00) : rgb_t(0xff, 0x00, 0x00, 0x00);
|
|
|
|
if (!force_vector)
|
|
{
|
|
screen.set_video_attributes(0);
|
|
bitmap.fill(backcol);
|
|
for (auto &f : m_state.m_fragments)
|
|
if (f.y < bitmap.height())
|
|
bitmap.plot_box(f.x, f.y, f.xr - f.x, 1, f.col);
|
|
|
|
if (test_pat)
|
|
draw_testpat(screen, bitmap, cliprect);
|
|
}
|
|
else
|
|
{
|
|
screen.set_video_attributes(VIDEO_SELF_RENDER);
|
|
|
|
const uint32_t flags(PRIMFLAG_ANTIALIAS(1)
|
|
| PRIMFLAG_BLENDMODE(BLENDMODE_ADD)
|
|
| (screen.screen_type() == SCREEN_TYPE_VECTOR ? PRIMFLAG_VECTOR(1) : 0));
|
|
const rectangle &visarea = screen.visible_area();
|
|
float xscale = 1.0f / (float)visarea.width();
|
|
float yscale = 1.0f / (float)visarea.height();
|
|
float xoffs = (float)visarea.min_x;
|
|
float yoffs = (float)visarea.min_y;
|
|
screen.container().empty();
|
|
screen.container().add_rect(0.0f, 0.0f, 1.0f, 1.0f, rgb_t(0xff,0x00,0x00,0x00),
|
|
PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)
|
|
| (screen.screen_type() == SCREEN_TYPE_VECTOR ? PRIMFLAG_VECTORBUF(1) : 0));
|
|
|
|
float last_y = -1e6;
|
|
for (auto &f : m_state.m_fragments)
|
|
{
|
|
const float x0((f.x - xoffs) * xscale);
|
|
const float y0((f.y - yoffs) * yscale);
|
|
const float x1((f.xr - xoffs) * xscale);
|
|
|
|
rgb_t col = (debug_timing && f.y < last_y) ? backcol : (rgb_t) f.col;
|
|
// FIXME: Debug check for proper vsync timing
|
|
#if 0
|
|
auto w = m_scanline_height * xscale * 0.5;
|
|
screen.container().add_line(
|
|
x0+w, y0, x1-w, y0, m_scanline_height*yscale,
|
|
nom_col(f.col),
|
|
// (0xff << 24) | (f.col & 0xffffff),
|
|
flags);
|
|
#elif 1
|
|
const float y1((f.y + m_scanline_height - yoffs) * yscale);
|
|
screen.container().add_rect(
|
|
x0, y0, x1, y1,
|
|
nom_col(col),
|
|
// (0xaf << 24) | (f.col & 0xffffff),
|
|
flags);
|
|
#else
|
|
const float y1((f.y + m_scanline_height - yoffs) * yscale);
|
|
// Crashes with bgfx
|
|
screen.container().add_quad(
|
|
x0, y0, x1, y1,
|
|
rgb_t(nom_col(f.col)),
|
|
// (0xaf << 24) | (f.col & 0xffffff),
|
|
m_texture,
|
|
flags);
|
|
#endif
|
|
last_y = f.y;
|
|
}
|
|
}
|
|
m_state.m_fragments.clear();
|
|
return 0;
|
|
}
|
|
|
|
void fixedfreq_device::vsync_end_cb(double refresh_time)
|
|
{
|
|
const auto expected_frame_period(m_monitor.clock_period() * m_monitor.vtotal() * m_monitor.htotal());
|
|
|
|
const auto refresh_limited(std::min(4.0 * expected_frame_period,
|
|
std::max(refresh_time, 0.25 * expected_frame_period)));
|
|
|
|
rectangle visarea(m_monitor.minh(), m_monitor.maxh(), m_monitor.minv(), m_monitor.maxv());
|
|
|
|
screen().configure(m_monitor.htotal_scaled(), m_monitor.vtotal(), visarea, DOUBLE_TO_ATTOSECONDS(refresh_limited));
|
|
screen().reset_origin(m_state.m_last_y-(m_monitor.vsync_width() + m_monitor.vbackporch_width()), 0);
|
|
}
|
|
|
|
NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_composite_monochrome)
|
|
{
|
|
// double is good enough for this exercise;
|
|
|
|
const time_type ctime = time.as_double();
|
|
m_state.update_composite_monochrome(ctime, data);
|
|
}
|
|
|
|
NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_red)
|
|
{
|
|
// double is good enough for this exercise;
|
|
|
|
const time_type ctime = time.as_double();
|
|
m_state.update_red(ctime, data);
|
|
}
|
|
|
|
NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_green)
|
|
{
|
|
// double is good enough for this exercise;
|
|
|
|
const time_type ctime = time.as_double();
|
|
m_state.update_green(ctime, data);
|
|
}
|
|
|
|
NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_blue)
|
|
{
|
|
// double is good enough for this exercise;
|
|
|
|
const time_type ctime = time.as_double();
|
|
m_state.update_blue(ctime, data);
|
|
}
|
|
|
|
NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_sync)
|
|
{
|
|
// double is good enough for this exercise;
|
|
|
|
const time_type ctime = time.as_double();
|
|
m_state.update_sync(ctime, data);
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
static INPUT_PORTS_START(fixedfreq_base_ports)
|
|
PORT_START("ENABLE")
|
|
PORT_CONFNAME( 0x01, 0x00, "Display Monitor sliders" )
|
|
PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
|
|
PORT_CONFSETTING( 0x01, DEF_STR( On ) )
|
|
PORT_CONFNAME( 0x02, 0x00, "Visual Timing Debug" )
|
|
PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
|
|
PORT_CONFSETTING( 0x02, DEF_STR( On ) )
|
|
PORT_CONFNAME( 0x04, 0x00, "Display gray test pattern" ) PORT_CONDITION("VECTOR", 0x01, EQUALS, 0x00)
|
|
PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
|
|
PORT_CONFSETTING( 0x04, DEF_STR( On ) )
|
|
|
|
PORT_ADJUSTERX(HVISIBLE, "H Visible", 10, 1000)
|
|
PORT_ADJUSTERX(HFRONTPORCH, "H Front porch width", 1, 100)
|
|
PORT_ADJUSTERX(HSYNC, "H Sync width", 1, 100)
|
|
PORT_ADJUSTERX(HBACKPORCH, "H Back porch width", 1, 1000)
|
|
PORT_ADJUSTERX(VVISIBLE, "V Visible", 1, 1000)
|
|
PORT_ADJUSTERX(VFRONTPORCH, "V Front porch width", 0, 100)
|
|
PORT_ADJUSTERX(VSYNC, "V Sync width", 1, 100)
|
|
PORT_ADJUSTERX(VBACKPORCH, "V Back porch width", 1, 100)
|
|
PORT_ADJUSTERX(SYNCTHRESHOLD, "Sync threshold mV", 10, 2000)
|
|
PORT_ADJUSTERX(VSYNCTHRESHOLD, "V Sync threshold mV", 10, 1000)
|
|
PORT_ADJUSTERX(GAIN, "Signal Gain", 10, 1000)
|
|
PORT_ADJUSTERX(SCANLINE_HEIGHT, "Scanline Height", 10, 300)
|
|
INPUT_PORTS_END
|
|
|
|
|
|
static INPUT_PORTS_START(fixedfreq_raster_ports)
|
|
PORT_START("VECTOR")
|
|
PORT_CONFNAME( 0x01, 0x00, "Use vector rendering" )
|
|
PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
|
|
PORT_CONFSETTING( 0x01, DEF_STR( On ) )
|
|
|
|
PORT_INCLUDE(fixedfreq_base_ports)
|
|
|
|
INPUT_PORTS_END
|
|
|
|
static INPUT_PORTS_START(fixedfreq_vector_ports)
|
|
PORT_INCLUDE(fixedfreq_base_ports)
|
|
INPUT_PORTS_END
|
|
|
|
ioport_constructor fixedfreq_device::device_input_ports() const
|
|
{
|
|
LOG("input ports\n");
|
|
if (has_screen())
|
|
{
|
|
if (screen().screen_type() == SCREEN_TYPE_RASTER)
|
|
return INPUT_PORTS_NAME(fixedfreq_raster_ports);
|
|
else
|
|
return INPUT_PORTS_NAME(fixedfreq_vector_ports);
|
|
}
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
unsigned fixedfreq_device::monitor_val(unsigned param) const
|
|
{
|
|
switch (param)
|
|
{
|
|
case HVISIBLE:
|
|
return m_monitor.hvisible_width();
|
|
case HFRONTPORCH:
|
|
return m_monitor.hfrontporch_width();
|
|
case HSYNC:
|
|
return m_monitor.hsync_width();
|
|
case HBACKPORCH:
|
|
return m_monitor.hbackporch_width();
|
|
case VVISIBLE:
|
|
return m_monitor.vvisible_width();
|
|
case VFRONTPORCH:
|
|
return m_monitor.vfrontporch_width();
|
|
case VSYNC:
|
|
return m_monitor.vsync_width();
|
|
case VBACKPORCH:
|
|
return m_monitor.vbackporch_width();
|
|
case SYNCTHRESHOLD:
|
|
return m_monitor.m_sync_threshold * 1000.0;
|
|
case VSYNCTHRESHOLD:
|
|
return m_monitor.m_vsync_threshold * 1000.0;
|
|
case GAIN:
|
|
return m_monitor.m_gain * 100.0;
|
|
case SCANLINE_HEIGHT:
|
|
return m_scanline_height * 100.0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
INPUT_CHANGED_MEMBER(fixedfreq_device::port_changed)
|
|
{
|
|
auto &m(m_monitor);
|
|
|
|
LOG("%d %d\n", param, newval);
|
|
switch (param)
|
|
{
|
|
case HVISIBLE:
|
|
m.set_h_rel(newval, m.hfrontporch_width(), m.hsync_width(), m.hbackporch_width());
|
|
break;
|
|
case HFRONTPORCH:
|
|
m.set_h_rel(m.hvisible_width(), newval, m.hsync_width(), m.hbackporch_width());
|
|
break;
|
|
case HSYNC:
|
|
m.set_h_rel(m.hvisible_width(), m.hfrontporch_width(), newval, m.hbackporch_width());
|
|
break;
|
|
case HBACKPORCH:
|
|
m.set_h_rel(m.hvisible_width(), m.hfrontporch_width(), m.hsync_width(), newval);
|
|
break;
|
|
case VVISIBLE:
|
|
m.set_v_rel(newval, m.vfrontporch_width(), m.vsync_width(), m.vbackporch_width());
|
|
break;
|
|
case VFRONTPORCH:
|
|
m.set_v_rel(m.vvisible_width(), newval, m.vsync_width(), m.vbackporch_width());
|
|
break;
|
|
case VSYNC:
|
|
m.set_v_rel(m.vvisible_width(), m.vfrontporch_width(), newval, m.vbackporch_width());
|
|
break;
|
|
case VBACKPORCH:
|
|
m.set_v_rel(m.vvisible_width(), m.vfrontporch_width(), m.vsync_width(), newval);
|
|
break;
|
|
case SYNCTHRESHOLD:
|
|
m.m_sync_threshold = static_cast<double>(newval) / 1000.0;
|
|
break;
|
|
case VSYNCTHRESHOLD:
|
|
m.m_vsync_threshold = static_cast<double>(newval) / 1000.0;
|
|
break;
|
|
case GAIN:
|
|
m.m_gain = static_cast<double>(newval) / 100.0;
|
|
break;
|
|
case SCANLINE_HEIGHT:
|
|
m_scanline_height = static_cast<double>(newval) / 100.0;
|
|
break;
|
|
}
|
|
machine().ui().popup_time(5, "Screen Dim %d x %d\n", m.htotal(), m.vtotal());
|
|
//ioport("YYY")->update_defvalue(true);
|
|
}
|