mirror of
https://github.com/holub/mame
synced 2025-10-04 16:34:53 +03:00
screenless: make it a device (nw)
This commit is contained in:
parent
f1d338e9e6
commit
ed0202220a
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
269
src/devices/video/pwm.cpp
Normal 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
96
src/devices/video/pwm.h
Normal 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
|
@ -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>
|
||||
|
@ -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 */
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
|
@ -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
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user