added Philips PCF2100 LCD Driver (nw)

This commit is contained in:
hap 2020-04-10 15:32:58 +02:00
parent 4af78838ad
commit d708a86325
12 changed files with 267 additions and 40 deletions

View File

@ -745,6 +745,18 @@ if (VIDEOS["PCD8544"]~=null) then
}
end
--------------------------------------------------
--
--@src/devices/video/pcf2100.h,VIDEOS["PCF2100"] = true
--------------------------------------------------
if (VIDEOS["PCF2100"]~=null) then
files {
MAME_DIR .. "src/devices/video/pcf2100.cpp",
MAME_DIR .. "src/devices/video/pcf2100.h",
}
end
--------------------------------------------------
--
--@src/devices/video/polylgcy.h,VIDEOS["POLY"] = true

View File

@ -342,6 +342,7 @@ VIDEOS["MC6845"] = true
--VIDEOS["MSM6255"] = true
--VIDEOS["MOS6566"] = true
VIDEOS["PC_VGA"] = true
--VIDEOS["PCF2100"] = true
VIDEOS["POLY"] = true
VIDEOS["PSX"] = true
VIDEOS["RAMDAC"] = true

View File

@ -371,6 +371,7 @@ VIDEOS["MSM6255"] = true
VIDEOS["MOS6566"] = true
VIDEOS["PC_VGA"] = true
VIDEOS["PCD8544"] = true
VIDEOS["PCF2100"] = true
--VIDEOS["POLY"] = true
VIDEOS["PSX"] = true
VIDEOS["RAMDAC"] = true

View File

@ -64,7 +64,8 @@ void hlcd0515_device::device_start()
// timer
m_lcd_timer = timer_alloc();
m_lcd_timer->adjust(attotime::from_hz(clock() / 2), 0, attotime::from_hz(clock() / 2));
attotime period = attotime::from_hz(clock() / 2);
m_lcd_timer->adjust(period, 0, period);
// zerofill
m_cs = 0;
@ -98,7 +99,7 @@ void hlcd0515_device::device_start()
//-------------------------------------------------
// device_timer - handler timer events
// device_timer - handle timer events
//-------------------------------------------------
void hlcd0515_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)

View File

@ -24,7 +24,6 @@ DEFINE_DEVICE_TYPE(LC7582, lc7582_device, "lc7582", "Sanyo LC7582 LCD Driver")
lc7582_device::lc7582_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
device_t(mconfig, LC7582, tag, owner, clock),
m_latch{0, 0},
m_write_segs(*this)
{ }

View File

@ -59,7 +59,7 @@ private:
int m_duty = 0;
int m_addsp = 0;
u64 m_shift = 0;
u64 m_latch[2];
u64 m_latch[2] = { 0, 0 };
// callbacks
devcb_write64 m_write_segs;

View File

@ -0,0 +1,119 @@
// license:BSD-3-Clause
// copyright-holders:hap
/*
Philips PCF2100 family LCD Driver
PCF2100: 2*20 LCD segments
PCF2110: 2*30 LCD segments, S31,S32 are LED outputs
PCF2111: 2*32 LCD segments
PCF2112: 1*32 LCD segments
OSC is R/C, 2100/10/11: 60-100Hz, 2112: 30-50Hz
Actual segment output frequency is divided by number of LCD commons.
*/
#include "emu.h"
#include "video/pcf2100.h"
DEFINE_DEVICE_TYPE(PCF2100, pcf2100_device, "pcf2100", "Philips PCF2100 LCD Driver")
DEFINE_DEVICE_TYPE(PCF2110, pcf2110_device, "pcf2110", "Philips PCF2110 LCD Driver")
DEFINE_DEVICE_TYPE(PCF2111, pcf2111_device, "pcf2111", "Philips PCF2111 LCD Driver")
DEFINE_DEVICE_TYPE(PCF2112, pcf2112_device, "pcf2112", "Philips PCF2112 LCD Driver")
//-------------------------------------------------
// constructor
//-------------------------------------------------
pcf2100_device::pcf2100_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 bpmax, u8 smax) :
device_t(mconfig, type, tag, owner, clock),
m_bpmax(bpmax), m_smax(smax), m_write_segs(*this)
{ }
pcf2100_device::pcf2100_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
pcf2100_device(mconfig, PCF2100, tag, owner, clock, 2, 20)
{ }
pcf2110_device::pcf2110_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
pcf2100_device(mconfig, PCF2110, tag, owner, clock, 2, 32)
{ }
pcf2111_device::pcf2111_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
pcf2100_device(mconfig, PCF2111, tag, owner, clock, 2, 32)
{ }
pcf2112_device::pcf2112_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
pcf2100_device(mconfig, PCF2112, tag, owner, clock, 1, 32)
{ }
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void pcf2100_device::device_start()
{
// resolve callbacks
m_write_segs.resolve_safe();
// timer
m_lcd_timer = timer_alloc();
attotime period = attotime::from_hz(clock());
m_lcd_timer->adjust(period, 0, period);
// register for savestates
save_item(NAME(m_shift));
save_item(NAME(m_count));
save_item(NAME(m_bpout));
save_item(NAME(m_latch));
save_item(NAME(m_clb));
save_item(NAME(m_data));
save_item(NAME(m_dlen));
}
//-------------------------------------------------
// handlers
//-------------------------------------------------
void pcf2100_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
// transfer latches to output
m_write_segs(m_bpout, m_latch[m_bpout]);
m_bpout = (m_bpout + 1) % m_bpmax;
}
WRITE_LINE_MEMBER(pcf2100_device::clb_w)
{
state = (state) ? 1 : 0;
bool rise = state && !m_clb;
m_clb = state;
if (!rise)
return;
if (m_dlen)
{
// before shifting data, test leading 0 at start
if ((m_data && m_count == 0) || m_count > (m_smax + 2))
return;
m_shift |= u64(m_data) << m_count;
m_count++;
}
else
{
if (m_count == (m_smax + 2))
{
// transfer to latches
int dest = BIT(m_shift, m_smax + 1) ? 0 : 1;
u64 mask = (u64(1) << m_smax) - 1;
m_latch[dest] = m_shift >> 1 & mask;
}
m_shift = 0;
m_count = 0;
}
}

View File

@ -0,0 +1,94 @@
// license:BSD-3-Clause
// copyright-holders:hap
/*
Philips PCF2100 family LCD Driver
*/
#ifndef MAME_VIDEO_PCF2100_H
#define MAME_VIDEO_PCF2100_H
#pragma once
/*
pinout reference (brief)
see datasheet for details, pin numbers differ per chip
inputs:
OSC = oscillator input
CLB = clock burst
DATA = data line
DLEN = data line enable
outputs:
S: LCD driver outputs
BP1/BP2: backplane drivers (LCD commons)
*/
class pcf2100_device : public device_t
{
public:
pcf2100_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
// configuration helpers
auto write_segs() { return m_write_segs.bind(); }
DECLARE_WRITE_LINE_MEMBER(clb_w);
DECLARE_WRITE_LINE_MEMBER(data_w) { m_data = (state) ? 1 : 0; }
DECLARE_WRITE_LINE_MEMBER(dlen_w) { m_dlen = (state) ? 1 : 0; }
protected:
pcf2100_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 bpmax, u8 smax);
// device-level overrides
virtual void device_start() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
emu_timer *m_lcd_timer;
const u8 m_bpmax; // number of BP pins
const u8 m_smax; // number of S pins
u64 m_shift = 0;
u8 m_count = 0;
u8 m_bpout = 0;
u32 m_latch[2] = { 0, 0 };
// pin state
int m_clb = 0;
int m_data = 0;
int m_dlen = 0;
// callbacks
devcb_write32 m_write_segs;
};
class pcf2110_device : public pcf2100_device
{
public:
pcf2110_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
class pcf2111_device : public pcf2100_device
{
public:
pcf2111_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
class pcf2112_device : public pcf2100_device
{
public:
pcf2112_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
DECLARE_DEVICE_TYPE(PCF2100, pcf2100_device)
DECLARE_DEVICE_TYPE(PCF2110, pcf2110_device)
DECLARE_DEVICE_TYPE(PCF2111, pcf2111_device)
DECLARE_DEVICE_TYPE(PCF2112, pcf2112_device)
#endif // MAME_VIDEO_PCF2100_H

View File

@ -20,7 +20,7 @@ Hardware:
#include "machine/timer.h"
#include "sound/dac.h"
#include "sound/volt_reg.h"
#include "video/pwm.h"
#include "video/pcf2100.h"
#include "speaker.h"
// internal artwork
@ -35,7 +35,7 @@ public:
, m_maincpu(*this, "maincpu")
, m_dac(*this, "dac")
, m_board(*this, "board")
, m_display(*this, "display")
, m_lcd(*this, "lcd")
, m_inputs(*this, "IN.%u", 0)
, m_digits(*this, "digit%u", 0U)
, m_leds(*this, "led%u", 0U)
@ -49,6 +49,7 @@ protected:
void mondial68k_mem(address_map &map);
DECLARE_WRITE32_MEMBER(lcd_s_w);
DECLARE_WRITE8_MEMBER(lcd_dlen_w);
DECLARE_WRITE8_MEMBER(lcd_clb_w);
DECLARE_WRITE8_MEMBER(lcd_data_w);
@ -61,14 +62,13 @@ protected:
required_device<cpu_device> m_maincpu;
required_device<dac_bit_interface> m_dac;
required_device<sensorboard_device> m_board;
required_device<pwm_display_device> m_display;
required_device<pcf2112_device> m_lcd;
required_ioport_array<4> m_inputs;
output_finder<8> m_digits;
output_finder<4> m_digits;
output_finder<16> m_leds;
uint8_t m_input_mux;
uint8_t m_board_mux;
uint8_t m_lcd_shift;
uint8_t m_dac_data;
};
@ -80,7 +80,6 @@ void mondial68k_state::machine_start()
save_item(NAME(m_input_mux));
save_item(NAME(m_board_mux));
save_item(NAME(m_lcd_shift));
save_item(NAME(m_dac_data));
}
@ -88,7 +87,6 @@ void mondial68k_state::machine_reset()
{
m_input_mux = 0;
m_board_mux = 0;
m_lcd_shift = 0;
m_dac_data = 0;
}
@ -104,27 +102,29 @@ TIMER_DEVICE_CALLBACK_MEMBER(mondial68k_state::refresh_leds)
m_leds[0 + i] = 0;
}
WRITE8_MEMBER( mondial68k_state::lcd_clb_w )
WRITE32_MEMBER(mondial68k_state::lcd_s_w)
{
if (BIT(data, 0))
m_lcd_shift++;
// output LCD digits (note: last digit DP segment is unused)
for (int i=0; i<4; i++)
m_digits[i] = bitswap<8>((data & 0x7fffffff) >> (8 * i), 7,4,5,0,1,2,3,6);
}
WRITE8_MEMBER( mondial68k_state::lcd_dlen_w )
WRITE8_MEMBER(mondial68k_state::lcd_clb_w)
{
m_lcd_shift = 0;
m_lcd->clb_w(data & 1);
}
WRITE8_MEMBER( mondial68k_state::lcd_data_w )
WRITE8_MEMBER(mondial68k_state::lcd_dlen_w)
{
if (m_lcd_shift > 0 && m_lcd_shift < 0x21)
{
m_display->write_element((m_lcd_shift - 1) / 8, (m_lcd_shift - 1) % 8, BIT(data, 0));
m_display->update();
}
m_lcd->dlen_w(data & 1);
}
WRITE8_MEMBER( mondial68k_state::speaker_w )
WRITE8_MEMBER(mondial68k_state::lcd_data_w)
{
m_lcd->data_w(data & 1);
}
WRITE8_MEMBER(mondial68k_state::speaker_w)
{
m_dac_data ^= 1;
m_dac->write(m_dac_data);
@ -172,14 +172,15 @@ READ8_MEMBER(mondial68k_state::inputs_r)
void mondial68k_state::mondial68k_mem(address_map &map)
{
map(0x000000, 0x00ffff).rom();
map(0x800000, 0x800001).r(FUNC(mondial68k_state::inputs_r));
map(0x820000, 0x820001).w(FUNC(mondial68k_state::lcd_clb_w));
map(0x820002, 0x820003).w(FUNC(mondial68k_state::lcd_data_w));
map(0x820004, 0x820005).w(FUNC(mondial68k_state::lcd_dlen_w));
map(0x800000, 0x800000).r(FUNC(mondial68k_state::inputs_r));
map(0x820000, 0x82000f).nopr();
map(0x820000, 0x820000).w(FUNC(mondial68k_state::lcd_clb_w));
map(0x820002, 0x820002).w(FUNC(mondial68k_state::lcd_data_w));
map(0x820004, 0x820004).w(FUNC(mondial68k_state::lcd_dlen_w));
map(0x82000c, 0x82000d).nopw();
map(0x82000e, 0x82000f).w(FUNC(mondial68k_state::speaker_w));
map(0x840000, 0x840001).w(FUNC(mondial68k_state::input_mux_w));
map(0x860000, 0x860001).w(FUNC(mondial68k_state::board_mux_w));
map(0x82000e, 0x82000e).w(FUNC(mondial68k_state::speaker_w));
map(0x840000, 0x840000).w(FUNC(mondial68k_state::input_mux_w));
map(0x860000, 0x860000).w(FUNC(mondial68k_state::board_mux_w));
map(0xc00000, 0xc03fff).ram();
}
@ -233,10 +234,8 @@ void mondial68k_state::mondial68k(machine_config &config)
m_board->set_delay(attotime::from_msec(100));
/* video hardware */
PWM_DISPLAY(config, m_display).set_size(4, 8);
m_display->set_segmask(0xf, 0xff);
m_display->set_segmask(0x8, 0x7f); // last digit: DP segment unused
m_display->output_digit().set([this](offs_t offset, u8 data) { m_digits[offset] = bitswap<8>(data, 7,4,5,0,1,2,3,6); });
PCF2112(config, m_lcd, 50); // frequency guessed
m_lcd->write_segs().set(FUNC(mondial68k_state::lcd_s_w));
config.set_default_layout(layout_mephisto_mondial68k);
/* sound hardware */

View File

@ -14,7 +14,8 @@
- holding CL+INFO+BOOK on boot load the test mode
TODO:
- split driver into several files? need to make PCF2112T device
- split driver into several files?
- use PCF2112T device (it has 2 of them)
- why are megaiv/smondial2 beeps noisy?
- add Monte Carlo IV (non-LE)
- add MM 1000 module

View File

@ -12,7 +12,7 @@
* (http://worstconsole.blogspot.ca/2012/12/the-worstconsoleever.html)
* Note a spare dead GIC has been given to Lord Nightmare and should be sent for decap!
*
* The Unisonc Champion is the only known GI "Gimini Mid-Range 8950 Programmable Game Set"
* The Unisonic Champion is the only known GI "Gimini Mid-Range 8950 Programmable Game Set"
* to ever reach the market, and only in limited quantities (aprox 500 units ever built)
*
* Architecture:

View File

@ -45,9 +45,9 @@
for a total of (12*20*16) = 3840 RAM reads (3 clocks per read at 1.79MHz)
Then it relingishes control to the CPU by raising BUSREQ.
Then it relinquishes control to the CPU by raising BUSREQ.
Cloking in more detail: (in 1.79MHz clocks)
Clocking in more detail: (in 1.79MHz clocks)
boot:
busy:1 5360 clocks
busy:0 22116 clocks
@ -257,9 +257,9 @@ void gic_device::sound_stream_update(sound_stream &stream, stream_sample_t **inp
stream_sample_t *buffer = outputs[0];
//Audio is basic and badly implemented (doubt that was the intent)
//The datasheet list the 3 different frequencies the GIC can generate: 500,1000 and 2000Hz
//The datasheet lists the 3 different frequencies the GIC can generate: 500,1000 and 2000Hz
//but it is clear (for an audio guy at least) that the resulting spectrum
//is not a pure square wav. In fact, the counter is reset on vertical sync!
//is not a pure square wave. In fact, the counter is reset on vertical sync!
//http://twitter.com/plgDavid/status/527269086016077825
//...thus creating a buzzing sound.