mirror of
https://github.com/holub/mame
synced 2025-04-24 09:20:02 +03:00
k28: simplify display handling (nw)
This commit is contained in:
parent
da3c5ca875
commit
725fa0f772
@ -72,7 +72,7 @@ public:
|
||||
m_led(*this, "led%u", 0U)
|
||||
{ }
|
||||
|
||||
// machine drivers
|
||||
// machine configs
|
||||
void intel02(machine_config &config);
|
||||
|
||||
// assume that reset button is tied to RESET pin
|
||||
@ -196,7 +196,7 @@ WRITE8_MEMBER(intel02_state::control_w)
|
||||
if (BIT(data, i))
|
||||
m_led_active |= 1 << i;
|
||||
|
||||
// on falling edge, delay it going off to prevent flicker
|
||||
// they're strobed, so on falling edge, delay them going off to prevent flicker
|
||||
else if (BIT(m_led_select, i))
|
||||
m_led_delay[i]->adjust(attotime::from_msec(10), i);
|
||||
}
|
||||
@ -261,7 +261,7 @@ INPUT_PORTS_END
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
Machine Drivers
|
||||
Machine Configs
|
||||
******************************************************************************/
|
||||
|
||||
void intel02_state::intel02(machine_config &config)
|
||||
@ -278,7 +278,7 @@ void intel02_state::intel02(machine_config &config)
|
||||
m_ppi8255->tri_pb_callback().set_constant(0);
|
||||
m_ppi8255->out_pc_callback().set(FUNC(intel02_state::control_w));
|
||||
|
||||
/* display hardware */
|
||||
/* video hardware */
|
||||
for (int i = 0; i < 6; i++)
|
||||
TIMER(config, m_led_delay[i]).configure_generic(FUNC(intel02_state::led_delay_off));
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include "k28.lh"
|
||||
|
||||
namespace {
|
||||
|
||||
class k28_state : public driver_device
|
||||
{
|
||||
@ -39,57 +40,40 @@ public:
|
||||
m_tms6100(*this, "tms6100"),
|
||||
m_speech(*this, "speech"),
|
||||
m_vfd(*this, "vfd"),
|
||||
m_digit_delay(*this, "led_delay_%u", 0),
|
||||
m_onbutton_timer(*this, "on_button"),
|
||||
m_inp_matrix(*this, "IN.%u", 0),
|
||||
m_out_x(*this, "%u.%u", 0U, 0U),
|
||||
m_out_a(*this, "%u.a", 0U),
|
||||
m_out_digit(*this, "digit%u", 0U),
|
||||
m_display_wait(33),
|
||||
m_display_maxy(1),
|
||||
m_display_maxx(0)
|
||||
m_out_digit(*this, "digit%u", 0U)
|
||||
{ }
|
||||
|
||||
void k28(machine_config &config);
|
||||
|
||||
DECLARE_INPUT_CHANGED_MEMBER(power_on);
|
||||
|
||||
protected:
|
||||
virtual void machine_start() override;
|
||||
virtual void machine_reset() override;
|
||||
|
||||
private:
|
||||
// devices
|
||||
required_device<i8021_device> m_maincpu;
|
||||
required_device<tms6100_device> m_tms6100;
|
||||
required_device<votrax_sc01_device> m_speech;
|
||||
required_device<mm5445_device> m_vfd;
|
||||
required_device_array<timer_device, 9> m_digit_delay;
|
||||
required_device<timer_device> m_onbutton_timer;
|
||||
required_ioport_array<7> m_inp_matrix;
|
||||
output_finder<0x20, 0x20> m_out_x;
|
||||
output_finder<0x20> m_out_a;
|
||||
output_finder<0x20> m_out_digit;
|
||||
output_finder<9, 16> m_out_x;
|
||||
output_finder<9> m_out_digit;
|
||||
|
||||
// display common
|
||||
int m_display_wait; // led/lamp off-delay in milliseconds (default 33ms)
|
||||
int m_display_maxy; // display matrix number of rows
|
||||
int m_display_maxx; // display matrix number of columns (max 31 for now)
|
||||
|
||||
u32 m_display_state[0x20]; // display matrix rows data (last bit is used for always-on)
|
||||
u16 m_display_segmask[0x20]; // if not 0, display matrix row is a digit, mask indicates connected segments
|
||||
u8 m_display_decay[0x20][0x20]; // (internal use)
|
||||
|
||||
TIMER_DEVICE_CALLBACK_MEMBER(display_decay_tick);
|
||||
void display_update();
|
||||
void set_display_size(int maxx, int maxy);
|
||||
void set_display_segmask(u32 digits, u32 mask);
|
||||
void display_matrix(int maxx, int maxy, u32 setx, u32 sety, bool update = true);
|
||||
TIMER_DEVICE_CALLBACK_MEMBER(digit_delay_off);
|
||||
|
||||
bool m_power_on;
|
||||
u8 m_inp_mux;
|
||||
u8 m_phoneme;
|
||||
int m_speech_strobe;
|
||||
int m_vfd_data_enable;
|
||||
int m_vfd_data_in;
|
||||
int m_vfd_clock;
|
||||
u64 m_vfd_shiftreg;
|
||||
u64 m_vfd_shiftreg_out;
|
||||
int m_vfd_shiftcount;
|
||||
u64 m_vfd_data;
|
||||
|
||||
DECLARE_WRITE64_MEMBER(vfd_output_w);
|
||||
DECLARE_WRITE8_MEMBER(mcu_p0_w);
|
||||
@ -98,9 +82,6 @@ private:
|
||||
DECLARE_WRITE8_MEMBER(mcu_p2_w);
|
||||
|
||||
void power_off();
|
||||
|
||||
virtual void machine_start() override;
|
||||
virtual void machine_reset() override;
|
||||
};
|
||||
|
||||
|
||||
@ -110,44 +91,21 @@ void k28_state::machine_start()
|
||||
{
|
||||
// resolve handlers
|
||||
m_out_x.resolve();
|
||||
m_out_a.resolve();
|
||||
m_out_digit.resolve();
|
||||
|
||||
// zerofill
|
||||
memset(m_display_state, 0, sizeof(m_display_state));
|
||||
memset(m_display_decay, 0, sizeof(m_display_decay));
|
||||
memset(m_display_segmask, 0, sizeof(m_display_segmask));
|
||||
|
||||
m_power_on = false;
|
||||
m_inp_mux = 0;
|
||||
m_phoneme = 0x3f;
|
||||
m_speech_strobe = 0;
|
||||
m_vfd_data_enable = 0;
|
||||
m_vfd_data_in = 0;
|
||||
m_vfd_clock = 0;
|
||||
m_vfd_shiftreg = 0;
|
||||
m_vfd_shiftreg_out = 0;
|
||||
m_vfd_shiftcount = 0;
|
||||
m_vfd_data = 0;
|
||||
|
||||
// register for savestates
|
||||
save_item(NAME(m_display_maxy));
|
||||
save_item(NAME(m_display_maxx));
|
||||
save_item(NAME(m_display_wait));
|
||||
|
||||
save_item(NAME(m_display_state));
|
||||
save_item(NAME(m_display_decay));
|
||||
save_item(NAME(m_display_segmask));
|
||||
|
||||
save_item(NAME(m_power_on));
|
||||
save_item(NAME(m_inp_mux));
|
||||
save_item(NAME(m_phoneme));
|
||||
save_item(NAME(m_speech_strobe));
|
||||
save_item(NAME(m_vfd_data_enable));
|
||||
save_item(NAME(m_vfd_data_in));
|
||||
save_item(NAME(m_vfd_clock));
|
||||
save_item(NAME(m_vfd_shiftreg));
|
||||
save_item(NAME(m_vfd_shiftreg_out));
|
||||
save_item(NAME(m_vfd_shiftcount));
|
||||
save_item(NAME(m_vfd_data));
|
||||
}
|
||||
|
||||
void k28_state::machine_reset()
|
||||
@ -172,108 +130,56 @@ void k28_state::power_off()
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Helper Functions
|
||||
/******************************************************************************
|
||||
Devices, I/O
|
||||
******************************************************************************/
|
||||
|
||||
***************************************************************************/
|
||||
// VFD handling
|
||||
|
||||
// The device may strobe the outputs very fast, it is unnoticeable to the user.
|
||||
// To prevent flickering here, we need to simulate a decay.
|
||||
|
||||
void k28_state::display_update()
|
||||
TIMER_DEVICE_CALLBACK_MEMBER(k28_state::digit_delay_off)
|
||||
{
|
||||
for (int y = 0; y < m_display_maxy; y++)
|
||||
// clear vfd outputs
|
||||
if (!BIT(m_vfd_data, param+16))
|
||||
{
|
||||
u32 active_state = 0;
|
||||
m_out_digit[param] = 0;
|
||||
|
||||
for (int x = 0; x <= m_display_maxx; x++)
|
||||
{
|
||||
// turn on powered segments
|
||||
if (m_power_on && m_display_state[y] >> x & 1)
|
||||
m_display_decay[y][x] = m_display_wait;
|
||||
|
||||
// determine active state
|
||||
u32 ds = (m_display_decay[y][x] != 0) ? 1 : 0;
|
||||
active_state |= (ds << x);
|
||||
|
||||
// output to y.x, or y.a when always-on
|
||||
if (x != m_display_maxx)
|
||||
m_out_x[y][x] = ds;
|
||||
else
|
||||
m_out_a[y] = ds;
|
||||
}
|
||||
|
||||
// output to digity
|
||||
if (m_display_segmask[y] != 0)
|
||||
m_out_digit[y] = active_state & m_display_segmask[y];
|
||||
for (int i = 0; i < 16; i++)
|
||||
m_out_x[param][i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
TIMER_DEVICE_CALLBACK_MEMBER(k28_state::display_decay_tick)
|
||||
{
|
||||
// slowly turn off unpowered segments
|
||||
for (int y = 0; y < m_display_maxy; y++)
|
||||
for (int x = 0; x <= m_display_maxx; x++)
|
||||
if (m_display_decay[y][x] != 0)
|
||||
m_display_decay[y][x]--;
|
||||
|
||||
display_update();
|
||||
}
|
||||
|
||||
void k28_state::set_display_size(int maxx, int maxy)
|
||||
{
|
||||
m_display_maxx = maxx;
|
||||
m_display_maxy = maxy;
|
||||
}
|
||||
|
||||
void k28_state::set_display_segmask(u32 digits, u32 mask)
|
||||
{
|
||||
// set a segment mask per selected digit, but leave unselected ones alone
|
||||
for (int i = 0; i < 0x20; i++)
|
||||
{
|
||||
if (digits & 1)
|
||||
m_display_segmask[i] = mask;
|
||||
digits >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
void k28_state::display_matrix(int maxx, int maxy, u32 setx, u32 sety, bool update)
|
||||
{
|
||||
set_display_size(maxx, maxy);
|
||||
|
||||
// update current state
|
||||
u32 mask = (1 << maxx) - 1;
|
||||
for (int y = 0; y < maxy; y++)
|
||||
m_display_state[y] = (sety >> y & 1) ? ((setx & mask) | (1 << maxx)) : 0;
|
||||
|
||||
display_update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
I/O
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
WRITE64_MEMBER(k28_state::vfd_output_w)
|
||||
{
|
||||
// O1-O16: digit segment data
|
||||
// O17-O25: digit select
|
||||
u16 seg_data = bitswap<16>(data,15,14,2,6,5,3,1,7,12,11,10,13,0,4,9,8);
|
||||
u16 digit_sel = data >> 16 & 0x1ff;
|
||||
|
||||
set_display_segmask(0x1ff, 0x3fff);
|
||||
display_matrix(16, 9, seg_data, digit_sel);
|
||||
// O17-O25: digit select
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
if (BIT(data, i+16))
|
||||
{
|
||||
m_out_digit[i] = seg_data & 0x3fff;
|
||||
|
||||
// output individual segments (2 of them are not in MAME's 16seg)
|
||||
for (int j = 0; j < 16; j++)
|
||||
m_out_x[i][j] = seg_data >> j & 1;
|
||||
}
|
||||
|
||||
// they're strobed, so on falling edge, delay them going off to prevent flicker
|
||||
else if (BIT(m_vfd_data, i+16))
|
||||
m_digit_delay[i]->adjust(attotime::from_msec(50), i);
|
||||
}
|
||||
|
||||
// O26: power-off request on falling edge
|
||||
if (~data & m_vfd_shiftreg_out & 0x2000000)
|
||||
if (~data & m_vfd_data & 0x2000000)
|
||||
power_off();
|
||||
m_vfd_shiftreg_out = data;
|
||||
m_vfd_data = data;
|
||||
}
|
||||
|
||||
|
||||
// I8021 ports
|
||||
|
||||
WRITE8_MEMBER(k28_state::mcu_p0_w)
|
||||
{
|
||||
// d0,d1: phoneme high bits
|
||||
@ -337,11 +243,9 @@ WRITE8_MEMBER(k28_state::mcu_p2_w)
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Inputs
|
||||
|
||||
***************************************************************************/
|
||||
/******************************************************************************
|
||||
Input Ports
|
||||
******************************************************************************/
|
||||
|
||||
static INPUT_PORTS_START( k28 )
|
||||
PORT_START("IN.0")
|
||||
@ -417,11 +321,9 @@ INPUT_PORTS_END
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Machine Config
|
||||
|
||||
***************************************************************************/
|
||||
/******************************************************************************
|
||||
Machine Configs
|
||||
******************************************************************************/
|
||||
|
||||
void k28_state::k28(machine_config &config)
|
||||
{
|
||||
@ -442,7 +344,8 @@ void k28_state::k28(machine_config &config)
|
||||
MM5445(config, m_vfd).output_cb().set(FUNC(k28_state::vfd_output_w));
|
||||
config.set_default_layout(layout_k28);
|
||||
|
||||
TIMER(config, "display_decay").configure_periodic(FUNC(k28_state::display_decay_tick), attotime::from_msec(1));
|
||||
for (int i = 0; i < 9; i++)
|
||||
TIMER(config, m_digit_delay[i]).configure_generic(FUNC(k28_state::digit_delay_off));
|
||||
|
||||
/* sound hardware */
|
||||
SPEAKER(config, "mono").front_center();
|
||||
@ -451,11 +354,9 @@ void k28_state::k28(machine_config &config)
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
ROM Defs, Game driver(s)
|
||||
|
||||
***************************************************************************/
|
||||
/******************************************************************************
|
||||
ROM Definitions
|
||||
******************************************************************************/
|
||||
|
||||
ROM_START( k28 )
|
||||
ROM_REGION( 0x1000, "maincpu", 0 )
|
||||
@ -466,7 +367,13 @@ ROM_START( k28 )
|
||||
ROM_LOAD( "cm62051.vsm", 0x4000, 0x4000, CRC(0fa61baa) SHA1(831be669423ba60c7f85a896b4b09a1295478bd9) )
|
||||
ROM_END
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
Drivers
|
||||
******************************************************************************/
|
||||
|
||||
// YEAR NAME PARENT CMP MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
|
||||
COMP( 1981, k28, 0, 0, k28, k28, k28_state, empty_init, "Tiger Electronics", "K28: Talking Learning Computer (model 7-230)", MACHINE_SUPPORTS_SAVE )
|
||||
|
Loading…
Reference in New Issue
Block a user