screenless: make it a device (nw)

This commit is contained in:
hap 2019-06-14 17:45:38 +02:00
parent f1d338e9e6
commit ed0202220a
18 changed files with 447 additions and 83 deletions

View File

@ -733,6 +733,17 @@ if (VIDEOS["SAA5050"]~=null) then
}
end
--------------------------------------------------
--
--@src/devices/video/pwm.h,VIDEOS["PWM_DISPLAY"] = true
--------------------------------------------------
if (VIDEOS["PWM_DISPLAY"]~=null) then
files {
MAME_DIR .. "src/devices/video/pwm.cpp",
MAME_DIR .. "src/devices/video/pwm.h",
}
end
--------------------------------------------------
--
--@src/devices/video/sed1200.h,VIDEOS["SED1200"] = true

View File

@ -336,6 +336,7 @@ VIDEOS["RAMDAC"] = true
VIDEOS["SAA5050"] = true
--VIDEOS["SDA5708"] = true
VIDEOS["SCN2674"] = true
--VIDEOS["PWM_DISPLAY"] = true
--VIDEOS["SED1200"] = true
--VIDEOS["SED1330"] = true
--VIDEOS["SED1520"] = true

View File

@ -354,6 +354,7 @@ VIDEOS["PSX"] = true
VIDEOS["RAMDAC"] = true
VIDEOS["S2636"] = true
VIDEOS["SAA5050"] = true
VIDEOS["PWM_DISPLAY"] = true
VIDEOS["SDA5708"] = true
VIDEOS["SED1200"] = true
VIDEOS["SED1330"] = true

View File

@ -6,8 +6,8 @@
*/
#ifndef MAME_MACHINE_CHESSM_H
#define MAME_MACHINE_CHESSM_H
#ifndef MAME_MACHINE_CHESSMACHINE_H
#define MAME_MACHINE_CHESSMACHINE_H
#pragma once
@ -63,4 +63,4 @@ private:
DECLARE_DEVICE_TYPE(CHESSMACHINE, chessmachine_device)
#endif // MAME_MACHINE_CHESSM_H
#endif // MAME_MACHINE_CHESSMACHINE_H

View File

@ -83,7 +83,7 @@ WRITE_LINE_MEMBER(hlcd0538_device::lcd_w)
// transfer to latches on rising edge
if (state && !m_lcd)
{
m_write_cols(0, m_shift, ~u64(0));
m_write_cols(0, m_shift);
m_shift = 0;
}

269
src/devices/video/pwm.cpp Normal file
View File

@ -0,0 +1,269 @@
// license:BSD-3-Clause
// copyright-holders:hap
/*
This thing is a generic helper for PWM(strobed) display elements, to prevent flickering
and optionally handle perceived brightness levels.
Common usecase is to call matrix(selmask, datamask), a collision between the 2 masks
implies a powered-on display element (eg, a LED, or VFD sprite). The maximum matrix
size is 64 by 64, simply due to uint64_t constraints. If a larger size is needed,
create an array of pwm_display_device.
If display elements are directly addressable, you can use write_element or write_row
to set them. In this case it is required to call update() to apply the changes.
Display element states are sent to output tags "y.x" where y is the matrix row number,
x is the row bit. It is also sent to "y.a" for all rows. The output state is 0 for off,
and >0 for on, depending on brightness level. If segmask is defined, it is also sent
to "digity", for use with multi-state elements, eg. 7seg leds.
If you use this device in a slot, or use multiple of them (or just don't want to use
the default output tags), set a callback.
TODO:
- multiple brightness levels doesn't work for SVGs
*/
#include "emu.h"
#include "video/pwm.h"
#include <algorithm>
DEFINE_DEVICE_TYPE(PWM_DISPLAY, pwm_display_device, "pwm_display", "PWM Display")
//-------------------------------------------------
// constructor
//-------------------------------------------------
pwm_display_device::pwm_display_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, PWM_DISPLAY, tag, owner, clock),
m_out_x(*this, "%u.%u", 0U, 0U),
m_out_a(*this, "%u.a", 0U),
m_out_digit(*this, "digit%u", 0U),
m_output_x_cb(*this),
m_output_a_cb(*this),
m_output_digit_cb(*this)
{
// set defaults (60hz frames, 0.5 interpolation, 1 brightness level)
set_refresh(attotime::from_hz(60));
set_interpolation(0.5);
set_bri_levels(0.02);
set_bri_minimum(0);
set_size(0, 0);
reset_segmask();
}
//-------------------------------------------------
// device_start/reset
//-------------------------------------------------
ALLOW_SAVE_TYPE(attotime); // m_acc
void pwm_display_device::device_start()
{
// resolve handlers
m_out_x.resolve();
m_out_a.resolve();
m_out_digit.resolve();
bool cb1 = m_output_x_cb.resolve_safe();
bool cb2 = m_output_a_cb.resolve_safe();
bool cb3 = m_output_digit_cb.resolve_safe();
m_external_output = cb1 || cb2 || cb3;
// initialize
std::fill_n(m_rowdata, ARRAY_LENGTH(m_rowdata), 0);
std::fill_n(m_rowdata_prev, ARRAY_LENGTH(m_rowdata_prev), 0);
std::fill_n(*m_bri, ARRAY_LENGTH(m_bri) * ARRAY_LENGTH(m_bri[0]), 0.0);
m_frame_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pwm_display_device::frame_tick),this));
m_update_time = machine().time();
m_rowsel = 0;
m_rowsel_prev = 0;
// register for savestates
save_item(NAME(m_width));
save_item(NAME(m_height));
save_item(NAME(m_framerate_set));
save_item(NAME(m_framerate));
save_item(NAME(m_interpolation));
save_item(NAME(m_levels));
save_item(NAME(m_level_min));
save_item(NAME(m_segmask));
save_item(NAME(m_rowsel));
save_item(NAME(m_rowsel_prev));
save_item(NAME(m_rowdata));
save_item(NAME(m_rowdata_prev));
save_item(NAME(m_bri));
save_item(NAME(m_acc));
save_item(NAME(m_update_time));
}
void pwm_display_device::device_reset()
{
if (m_height > 64 || m_width > 64)
fatalerror("%s: Invalid size %d*%d, maximum is 64*64!\n", tag(), m_height, m_width);
schedule_frame();
m_update_time = machine().time();
}
//-------------------------------------------------
// public handlers (most of the interface is in the .h file)
//-------------------------------------------------
pwm_display_device &pwm_display_device::set_bri_levels(double l0, double l1, double l2, double l3)
{
// init brightness level(s) (if you need to set more than 4, use set_bri_one)
reset_bri_levels();
m_levels[0] = l0;
m_levels[1] = l1;
m_levels[2] = l2;
m_levels[3] = l3;
return *this;
}
void pwm_display_device::segmask(u64 digits, u64 mask)
{
// set a segment mask per selected digit, but leave unselected ones alone
for (int y = 0; y < m_height; y++)
{
if (digits & 1)
m_segmask[y] = mask;
digits >>= 1;
}
}
void pwm_display_device::matrix_partial(u8 start, u8 height, u64 rowsel, u64 rowdata, bool upd)
{
u64 selmask = (u64(1) << height) - 1;
rowsel &= selmask;
selmask <<= start;
m_rowsel = (m_rowsel & ~selmask) | (rowsel << start);
// update selected rows
u64 rowmask = (u64(1) << m_width) - 1;
for (int y = start; y < (start + height) && y < m_height; y++)
{
m_rowdata[y] = (rowsel & 1) ? (rowdata & rowmask) : 0;
rowsel >>= 1;
}
if (upd)
update();
}
void pwm_display_device::update()
{
// call this every time after m_rowdata is changed (automatic with matrix)
const attotime now = machine().time();
const attotime diff = (m_update_time >= now) ? attotime::zero : now - m_update_time;
u64 sel = m_rowsel_prev;
m_rowsel_prev = m_rowsel;
// accumulate active time
for (int y = 0; y < m_height; y++)
{
u64 row = m_rowdata_prev[y];
m_rowdata_prev[y] = m_rowdata[y];
if (diff != attotime::zero)
{
if (sel & 1)
m_acc[y][m_width] += diff;
for (int x = 0; x < m_width; x++)
{
if (row & 1)
m_acc[y][x] += diff;
row >>= 1;
}
}
sel >>= 1;
}
m_update_time = now;
}
//-------------------------------------------------
// internal handlers
//-------------------------------------------------
void pwm_display_device::schedule_frame()
{
std::fill_n(*m_acc, m_height * ARRAY_LENGTH(m_acc[0]), attotime::zero);
m_framerate = m_framerate_set;
m_frame_timer->adjust(m_framerate);
}
TIMER_CALLBACK_MEMBER(pwm_display_device::frame_tick)
{
update(); // final timeslice
const double frame_time = m_framerate.as_double();
const double factor0 = m_interpolation;
const double factor1 = 1.0 - factor0;
for (int y = 0; y < m_height; y++)
{
u64 row = 0;
for (int x = 0; x <= m_width; x++)
{
// determine brightness level
double bri = m_bri[y][x] * factor1 + (m_acc[y][x].as_double() / frame_time) * factor0;
if (bri > 1.0) bri = 1.0; // shouldn't happen
m_bri[y][x] = bri;
u8 level;
for (level = 0; bri > m_levels[level]; level++) { ; }
// output to y.x, or y.a when always-on
if (x != m_width)
{
if (level > m_level_min)
row |= (u64(1) << x);
if (m_external_output)
m_output_x_cb(x << 6 | y, level);
else
m_out_x[y][x] = level;
}
else
{
if (m_external_output)
m_output_a_cb(y, level);
else
m_out_a[y] = level;
}
}
// output to digity (does not support brightness levels)
if (m_segmask[y] != 0)
{
row &= m_segmask[y];
if (m_external_output)
m_output_digit_cb(y, row);
else
m_out_digit[y] = row;
}
}
schedule_frame();
}

96
src/devices/video/pwm.h Normal file
View File

@ -0,0 +1,96 @@
// license:BSD-3-Clause
// copyright-holders:hap
/*
Generic PWM display device
*/
#ifndef MAME_VIDEO_PWM_H
#define MAME_VIDEO_PWM_H
#pragma once
class pwm_display_device : public device_t
{
public:
pwm_display_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
// configuration helpers
pwm_display_device &set_size(u8 numrows, u8 rowbits) { m_height = numrows; m_width = rowbits; return *this; } // max 64 * 64
pwm_display_device &set_refresh(attotime duration) { m_framerate_set = duration; return *this; } // time between each outputs refresh
pwm_display_device &set_interpolation(double factor) { m_interpolation = factor; return *this; } // frame interpolation (0.0 - 1.0)
pwm_display_device &set_segmask(u64 digits, u64 mask) { segmask(digits, mask); return *this; } // mask for multi-state outputs, eg. 7seg led
pwm_display_device &reset_segmask() { std::fill_n(m_segmask, ARRAY_LENGTH(m_segmask), 0); return *this; }
pwm_display_device &set_bri_levels(double l0, double l1 = 1.0, double l2 = 1.0, double l3 = 1.0); // brightness threshold per level (0.0 - 1.0)
pwm_display_device &set_bri_minimum(u8 i) { m_level_min = i; return *this; } // minimum level index for element to be considered "on"
// output callbacks when not using the default output tags
auto output_x() { return m_output_x_cb.bind(); } // x = offset >> 6, y = offset & 0x3f
auto output_a() { return m_output_a_cb.bind(); }
auto output_digit() { return m_output_digit_cb.bind(); }
void reset_bri_levels() { std::fill_n(m_levels, ARRAY_LENGTH(m_levels), 1.0); }
void set_bri_one(u8 i, double level) { m_levels[i] = level; }
void segmask(u64 digits, u64 mask);
void segmask_one(u8 y, u64 mask) { m_segmask[y] = mask; }
void matrix_partial(u8 start, u8 height, u64 rowsel, u64 rowdata, bool upd = true);
void matrix(u64 rowsel, u64 rowdata, bool upd = true) { matrix_partial(0, m_height, rowsel, rowdata, upd); }
void update(); // apply changes to m_rowdata
// directly handle individual element (does not affect m_rowsel), y = row num, x = row bit
int read_element(u8 y, u8 x) { return BIT(m_rowdata[y], x); }
void write_element(u8 y, u8 x, int state) { m_rowdata[y] = (m_rowdata[y] & ~(u64(1) << x)) | (u64(state ? 1 : 0) << x); }
// directly handle row data
u64 read_row(offs_t offset) { return m_rowdata[offset]; }
void write_row(offs_t offset, u64 data) { m_rowdata[offset] = data; m_rowsel |= u64(1) << offset; }
void clear_row(offs_t offset, u64 data = 0) { m_rowdata[offset] = 0; m_rowsel &= ~(u64(1) << offset); }
double element_bri(u8 y, u8 x) { return m_bri[y][x]; }
bool element_on(u8 y, u8 x) { return (m_bri[y][x] > m_levels[m_level_min]); }
bool row_on(u8 y) { return element_on(y, m_width); }
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
private:
output_finder<0x40, 0x40> m_out_x;
output_finder<0x40> m_out_a;
output_finder<0x40> m_out_digit;
devcb_write8 m_output_x_cb;
devcb_write8 m_output_a_cb;
devcb_write64 m_output_digit_cb;
bool m_external_output;
u8 m_width;
u8 m_height;
attotime m_framerate_set;
attotime m_framerate;
double m_interpolation;
double m_levels[0x100];
u8 m_level_min;
u64 m_segmask[0x40];
u64 m_rowsel;
u64 m_rowsel_prev;
u64 m_rowdata[0x40];
u64 m_rowdata_prev[0x40];
double m_bri[0x40][0x41];
attotime m_acc[0x40][0x41];
attotime m_update_time;
emu_timer *m_frame_timer;
TIMER_CALLBACK_MEMBER(frame_tick);
void schedule_frame();
};
DECLARE_DEVICE_TYPE(PWM_DISPLAY, pwm_display_device)
#endif // MAME_VIDEO_PWM_H

View File

@ -899,7 +899,7 @@ public:
virtual void validity_check(validity_checker &valid) const override;
void resolve();
void resolve_safe(Result dflt);
bool resolve_safe(Result dflt);
Result operator()(address_space &space, offs_t offset = 0, std::make_unsigned_t<Result> mem_mask = DefaultMask);
Result operator()(offs_t offset, std::make_unsigned_t<Result> mem_mask = DefaultMask);
@ -958,11 +958,13 @@ void devcb_read<Result, DefaultMask>::resolve()
}
template <typename Result, std::make_unsigned_t<Result> DefaultMask>
void devcb_read<Result, DefaultMask>::resolve_safe(Result dflt)
bool devcb_read<Result, DefaultMask>::resolve_safe(Result dflt)
{
resolve();
if (m_functions.empty())
bool resolved = !m_functions.empty();
if (!resolved)
m_functions.emplace_back([dflt] (address_space &space, offs_t offset, std::make_unsigned_t<Result> mem_mask) { return dflt; });
return resolved;
}
template <typename Result, std::make_unsigned_t<Result> DefaultMask>
@ -2369,7 +2371,7 @@ public:
virtual void validity_check(validity_checker &valid) const override;
void resolve();
void resolve_safe();
bool resolve_safe();
void operator()(address_space &space, offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask = DefaultMask);
void operator()(address_space &space, Input data);
@ -2420,11 +2422,13 @@ void devcb_write<Input, DefaultMask>::resolve()
}
template <typename Input, std::make_unsigned_t<Input> DefaultMask>
void devcb_write<Input, DefaultMask>::resolve_safe()
bool devcb_write<Input, DefaultMask>::resolve_safe()
{
resolve();
if (m_functions.empty())
bool resolved = !m_functions.empty();
if (!resolved)
m_functions.emplace_back([] (address_space &space, offs_t offset, Input data, std::make_unsigned_t<Input> mem_mask) { });
return resolved;
}
template <typename Input, std::make_unsigned_t<Input> DefaultMask>

View File

@ -3,27 +3,22 @@
// thanks-to:Berger
/******************************************************************************
* cking_master.cpp, subdriver of machine/screenless.cpp
TODO:
- 1 WAIT CLK per M1, workaround with z80_set_cycle_tables is possible
(wait state is similar to MSX) but I can't be bothered, better solution
is to add M1 pin to the z80 core. Until then, it'll run ~20% too fast.
*******************************************************************************
Chess King Master overview (yes, it's plainly named "Master"):
- Z80 CPU(NEC D780C-1) @ 4MHz(8MHz XTAL), IRQ from 555 timer
- 8KB ROM(NEC D2764C-3), 2KB RAM(NEC D4016C), ROM is scrambled for easy PCB placement
- simple I/O via 2*74373 and a 74145
- 8*8 chessboard buttons, 32+1 border leds, piezo
TODO:
- 1 WAIT CLK per M1, workaround with z80_set_cycle_tables is possible
(wait state is similar to MSX) but I can't be bothered, better solution
is to add M1 pin to the z80 core. Until then, it'll run ~20% too fast.
******************************************************************************/
#include "emu.h"
#include "includes/screenless.h"
#include "cpu/z80/z80.h"
#include "video/pwm.h"
#include "machine/bankdev.h"
#include "machine/timer.h"
#include "sound/dac.h"
@ -36,12 +31,13 @@ Chess King Master overview (yes, it's plainly named "Master"):
namespace {
class master_state : public screenless_state
class master_state : public driver_device
{
public:
master_state(const machine_config &mconfig, device_type type, const char *tag) :
screenless_state(mconfig, type, tag),
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_display(*this, "display"),
m_irq_on(*this, "irq_on"),
m_dac(*this, "dac"),
m_mainmap(*this, "mainmap"),
@ -59,6 +55,7 @@ protected:
private:
// devices/pointers
required_device<cpu_device> m_maincpu;
required_device<pwm_display_device> m_display;
required_device<timer_device> m_irq_on;
required_device<dac_2bit_binary_weighted_ones_complement_device> m_dac;
required_device<address_map_bank_device> m_mainmap;
@ -83,8 +80,6 @@ private:
void master_state::machine_start()
{
screenless_state::machine_start();
// zerofill, register for savestates
m_inp_mux = 0;
save_item(NAME(m_inp_mux));
@ -106,7 +101,7 @@ void master_state::control_w(u8 data)
u16 sel = 1 << m_inp_mux & 0x3ff;
// d4,d5: led data
display_matrix(2, 9, data >> 4 & 3, sel & 0x1ff);
m_display->matrix(sel & 0x1ff, data >> 4 & 3);
// d6,d7: speaker +/-
m_dac->write(data >> 6 & 3);
@ -301,6 +296,7 @@ void master_state::master(machine_config &config)
m_irq_on->set_start_delay(irq_period - attotime::from_nsec(22870)); // active for 22.87us
TIMER(config, "irq_off").configure_periodic(FUNC(master_state::irq_off<INPUT_LINE_IRQ0>), irq_period);
PWM_DISPLAY(config, m_display).set_size(9, 2);
config.set_default_layout(layout_ck_master);
/* sound hardware */

View File

@ -3,10 +3,6 @@
// thanks-to:Berger
/******************************************************************************
* cxg_ch2001.cpp, subdriver of machine/screenless.cpp
*******************************************************************************
CXG Chess 2001 overview:
- Zilog Z8400APS @ 4 MHz (8MHz XTAL)
- 2KB RAM HM6116, 16KB ROM D27128D
@ -15,9 +11,8 @@ CXG Chess 2001 overview:
******************************************************************************/
#include "emu.h"
#include "includes/screenless.h"
#include "cpu/z80/z80.h"
#include "video/pwm.h"
#include "machine/timer.h"
#include "sound/dac.h"
#include "sound/volt_reg.h"
@ -29,12 +24,13 @@ CXG Chess 2001 overview:
namespace {
class ch2001_state : public screenless_state
class ch2001_state : public driver_device
{
public:
ch2001_state(const machine_config &mconfig, device_type type, const char *tag) :
screenless_state(mconfig, type, tag),
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_display(*this, "display"),
m_irq_on(*this, "irq_on"),
m_dac(*this, "dac"),
m_speaker_off(*this, "speaker_off"),
@ -50,6 +46,7 @@ protected:
private:
// devices/pointers
required_device<cpu_device> m_maincpu;
required_device<pwm_display_device> m_display;
required_device<timer_device> m_irq_on;
required_device<dac_bit_interface> m_dac;
required_device<timer_device> m_speaker_off;
@ -74,8 +71,6 @@ private:
void ch2001_state::machine_start()
{
screenless_state::machine_start();
// zerofill, register for savestates
m_inp_mux = 0;
save_item(NAME(m_inp_mux));
@ -107,7 +102,7 @@ WRITE8_MEMBER(ch2001_state::leds_w)
// 74ls273 Q5-Q8: MC14028 A-D
// MC14028 Q0-Q7: led data, Q8,Q9: N/C
u8 led_data = 1 << (data >> 4 & 0xf) & 0xff;
display_matrix(8, 10, led_data, sel);
m_display->matrix(sel, led_data);
}
READ8_MEMBER(ch2001_state::input_r)
@ -256,14 +251,15 @@ void ch2001_state::ch2001(machine_config &config)
m_irq_on->set_start_delay(irq_period - attotime::from_nsec(18300)); // active for 18.3us
TIMER(config, "irq_off").configure_periodic(FUNC(ch2001_state::irq_off<INPUT_LINE_IRQ0>), irq_period);
TIMER(config, m_speaker_off).configure_generic(FUNC(ch2001_state::speaker_off));
PWM_DISPLAY(config, m_display).set_size(10, 8);
config.set_default_layout(layout_cxg_ch2001);
/* sound hardware */
SPEAKER(config, "speaker").front_center();
DAC_1BIT(config, m_dac).add_route(ALL_OUTPUTS, "speaker", 0.25);
VOLTAGE_REGULATOR(config, "vref").add_route(0, "dac", 1.0, DAC_VREF_POS_INPUT);
TIMER(config, m_speaker_off).configure_generic(FUNC(ch2001_state::speaker_off));
}

View File

@ -13,9 +13,8 @@
***************************************************************************/
#include "emu.h"
#include "includes/screenless.h"
#include "cpu/amis2000/amis2000.h"
#include "video/pwm.h"
#include "machine/timer.h"
#include "sound/spkrdev.h"
#include "speaker.h"
@ -26,20 +25,22 @@
//#include "hh_amis2k_test.lh" // common test-layout - use external artwork
class hh_amis2k_state : public screenless_state
class hh_amis2k_state : public driver_device
{
public:
hh_amis2k_state(const machine_config &mconfig, device_type type, const char *tag) :
screenless_state(mconfig, type, tag),
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_inp_matrix(*this, "IN.%u", 0),
m_speaker(*this, "speaker")
m_display(*this, "display"),
m_speaker(*this, "speaker"),
m_inp_matrix(*this, "IN.%u", 0)
{ }
// devices
required_device<amis2000_base_device> m_maincpu;
optional_ioport_array<4> m_inp_matrix; // max 4
optional_device<pwm_display_device> m_display;
optional_device<speaker_sound_device> m_speaker;
optional_ioport_array<4> m_inp_matrix; // max 4
// misc common
u16 m_a; // MCU address bus
@ -59,8 +60,6 @@ protected:
void hh_amis2k_state::machine_start()
{
screenless_state::machine_start();
// zerofill
m_a = 0;
m_d = 0;
@ -144,10 +143,7 @@ class wildfire_state : public hh_amis2k_state
public:
wildfire_state(const machine_config &mconfig, device_type type, const char *tag) :
hh_amis2k_state(mconfig, type, tag)
{
// bumpers are dimmed
set_display_levels(0.02, 0.1);
}
{ }
void prepare_display();
DECLARE_WRITE8_MEMBER(write_d);
@ -192,8 +188,8 @@ TIMER_DEVICE_CALLBACK_MEMBER(wildfire_state::speaker_decay_sim)
void wildfire_state::prepare_display()
{
// A0-A2 are 7segs
set_display_segmask(7, 0x7f);
display_matrix(8, 12, m_d, ~m_a);
m_display->segmask(7, 0x7f);
m_display->matrix(~m_a, m_d);
}
WRITE8_MEMBER(wildfire_state::write_d)
@ -249,6 +245,8 @@ void wildfire_state::wildfire(machine_config &config)
m_maincpu->write_a().set(FUNC(wildfire_state::write_a));
m_maincpu->write_f().set(FUNC(wildfire_state::write_f));
PWM_DISPLAY(config, m_display).set_size(12, 8);
m_display->set_bri_levels(0.02, 0.1); // bumpers are dimmed
config.set_default_layout(layout_wildfire);
/* sound hardware */

View File

@ -244,17 +244,18 @@ void hh_tms1k_state::machine_start()
{
screenless_state::machine_start();
// resolve handlers
m_out_power.resolve();
// zerofill
m_o = 0;
m_r = 0;
m_inp_mux = 0;
m_power_led = false;
m_power_on = false;
m_grid = 0;
m_plate = 0;
// register for savestates
/* save_item(NAME(m_power_led)); */ // don't save!
save_item(NAME(m_o));
save_item(NAME(m_r));
save_item(NAME(m_inp_mux));
@ -265,7 +266,7 @@ void hh_tms1k_state::machine_start()
void hh_tms1k_state::machine_reset()
{
m_power_on = true;
set_power(true);
}
@ -276,21 +277,6 @@ void hh_tms1k_state::machine_reset()
***************************************************************************/
// display update
void hh_tms1k_state::display_update()
{
screenless_state::display_update();
// output optional power led
if (m_power_led != m_power_on)
{
m_power_led = m_power_on;
output().set_value("power_led", m_power_led ? 1 : 0);
}
}
// generic input handlers
u8 hh_tms1k_state::read_inputs(int columns)
@ -337,7 +323,7 @@ INPUT_CHANGED_MEMBER(hh_tms1k_state::reset_button)
INPUT_CHANGED_MEMBER(hh_tms1k_state::power_button)
{
m_power_on = (bool)(uintptr_t)param;
set_power((bool)(uintptr_t)param);
m_maincpu->set_input_line(INPUT_LINE_RESET, m_power_on ? CLEAR_LINE : ASSERT_LINE);
}
@ -350,10 +336,16 @@ WRITE_LINE_MEMBER(hh_tms1k_state::auto_power_off)
void hh_tms1k_state::power_off()
{
m_power_on = false;
set_power(false);
m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
}
void hh_tms1k_state::set_power(bool state)
{
m_power_on = state;
m_out_power = state ? 1 : 0;
}
/***************************************************************************

View File

@ -784,7 +784,7 @@ INPUT_CHANGED_MEMBER(tispeak_state::power_button)
if (on && !m_power_on)
{
m_power_on = true;
set_power(true);
m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
}
else if (!on && m_power_on)

View File

@ -254,7 +254,7 @@ INPUT_CHANGED_MEMBER(tispellb_state::power_button)
if (on && !m_power_on)
{
m_power_on = true;
set_power(true);
m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
if (m_subcpu)

View File

@ -32,20 +32,21 @@ public:
screenless_state(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_inp_matrix(*this, "IN.%u", 0),
m_speaker(*this, "speaker")
m_speaker(*this, "speaker"),
m_out_power(*this, "power")
{ }
// devices
required_device<tms1k_base_device> m_maincpu;
optional_ioport_array<18> m_inp_matrix; // max 18
optional_device<speaker_sound_device> m_speaker;
output_finder<> m_out_power; // power state, eg. led
// misc common
u16 m_r; // MCU R-pins data
u16 m_o; // MCU O-pins data
u32 m_inp_mux; // multiplexed inputs mask
bool m_power_on;
bool m_power_led;
u32 m_grid; // VFD/LED current row data
u32 m_plate; // VFD/LED current column data
@ -56,6 +57,7 @@ public:
virtual DECLARE_INPUT_CHANGED_MEMBER(power_button);
virtual DECLARE_WRITE_LINE_MEMBER(auto_power_off);
virtual void power_off();
void set_power(bool state);
void switch_change(int sel, u32 mask, bool next);
template<int Sel> DECLARE_INPUT_CHANGED_MEMBER(switch_next) { if (newval) switch_change(Sel, (u32)(uintptr_t)param, true); }
@ -64,8 +66,6 @@ public:
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void display_update() override;
};

View File

@ -101,7 +101,7 @@
<bezel element="text_off"><bounds x="10.6" y="69.8" width="3" height="1.6" /></bezel>
<bezel element="text_on"><bounds x="67.9" y="69.8" width="2.3" height="1.6" /></bezel>
<bezel name="power_led" element="led"><bounds x="70.1" y="70.1" width="1" height="1" /></bezel> <!-- fake -->
<bezel name="power" element="led"><bounds x="70.1" y="70.1" width="1" height="1" /></bezel> <!-- fake -->
</view>
</mamelayout>

View File

@ -12,7 +12,7 @@ As workaround for the chess games, use an external chess GUI on the side,
such as Arena(in editmode).
TODO:
- use screenless class, this file will be removed eventually
- use pwm_display_device, this file will be removed eventually
******************************************************************************/

View File

@ -7,7 +7,7 @@ Generic screenless base class
This file contains helpers for strobed display elements.
TODO:
- multiple brightness levels doesn't work for SVGs
- use pwm_display_device, remove this file
******************************************************************************/