mirror of
https://github.com/holub/mame
synced 2025-04-16 05:24:54 +03:00
mu5: Add the lc7985nd and the lcd [O. Galibert]
This commit is contained in:
parent
b210948a61
commit
b644308114
@ -603,6 +603,18 @@ if (VIDEOS["LC7582"]~=null) then
|
||||
}
|
||||
end
|
||||
|
||||
--------------------------------------------------
|
||||
--
|
||||
--@src/devices/video/lc7985.h,VIDEOS["LC7985"] = true
|
||||
--------------------------------------------------
|
||||
|
||||
if (VIDEOS["LC7985"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/video/lc7985.cpp",
|
||||
MAME_DIR .. "src/devices/video/lc7985.h",
|
||||
}
|
||||
end
|
||||
|
||||
--------------------------------------------------
|
||||
--
|
||||
--@src/devices/video/m50458.h,VIDEOS["M50458"] = true
|
||||
|
@ -336,6 +336,7 @@ VIDEOS["I4100"] = true
|
||||
VIDEOS["I8275"] = true
|
||||
VIDEOS["JANGOU_BLITTER"] = true
|
||||
--VIDEOS["LC7582"] = true
|
||||
--VIDEOS["LC7985"] = true
|
||||
VIDEOS["M50458"] = true
|
||||
VIDEOS["MB90082"] = true
|
||||
VIDEOS["MB_VCU"] = true
|
||||
|
@ -366,6 +366,7 @@ VIDEOS["I82730"] = true
|
||||
VIDEOS["I8275"] = true
|
||||
VIDEOS["IMS_CVC"] = true
|
||||
VIDEOS["LC7582"] = true
|
||||
VIDEOS["LC7985"] = true
|
||||
--VIDEOS["M50458"] = true
|
||||
--VIDEOS["MB90082"] = true
|
||||
--VIDEOS["MB_VCU"] = true
|
||||
|
302
src/devices/video/lc7985.cpp
Normal file
302
src/devices/video/lc7985.cpp
Normal file
@ -0,0 +1,302 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Olivier Galibert
|
||||
/***************************************************************************
|
||||
|
||||
Sanyo LC7985NA/LC7985ND LCD controller
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "lc7985.h"
|
||||
|
||||
DEFINE_DEVICE_TYPE(LC7985, lc7985_device, "lc7985", "Sanyo LC7985NA/LC7985ND LCD controller")
|
||||
|
||||
|
||||
ROM_START( lc7985 )
|
||||
ROM_REGION( 0x1000, "cgrom", 0 )
|
||||
ROM_LOAD( "lc7985.bin", 0x0000, 0x1000, BAD_DUMP CRC(fdc64160) SHA1(8e6b54f8fb7c4c15aab2e65dd1a44729b97423b1)) // from page 12 of the LC7985D datasheet
|
||||
ROM_END
|
||||
|
||||
lc7985_device::lc7985_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, LC7985, tag, owner, clock),
|
||||
m_cgrom_region(*this, DEVICE_SELF)
|
||||
{
|
||||
}
|
||||
|
||||
const tiny_rom_entry *lc7985_device::device_rom_region() const
|
||||
{
|
||||
return ROM_NAME(lc7985);
|
||||
}
|
||||
|
||||
void lc7985_device::device_start()
|
||||
{
|
||||
m_cgrom = m_cgrom_region.found() ? m_cgrom_region : memregion("cgrom")->base();
|
||||
m_busy_timer = timer_alloc(0);
|
||||
|
||||
save_item(NAME(m_ddram));
|
||||
save_item(NAME(m_cgram));
|
||||
save_item(NAME(m_busy_flag));
|
||||
save_item(NAME(m_ddac));
|
||||
save_item(NAME(m_cgac));
|
||||
save_item(NAME(m_shift));
|
||||
save_item(NAME(m_access_ddram));
|
||||
save_item(NAME(m_function));
|
||||
save_item(NAME(m_cds));
|
||||
}
|
||||
|
||||
void lc7985_device::device_reset()
|
||||
{
|
||||
memset(m_ddram, 0x20, sizeof(m_ddram)); // filled with SPACE char
|
||||
memset(m_cgram, 0, sizeof(m_cgram));
|
||||
m_ddac = 0x00;
|
||||
m_cgac = 0x00;
|
||||
m_shift = 0x00;
|
||||
m_access_ddram = false;
|
||||
m_function = 0x00;
|
||||
m_cds = 0x00;
|
||||
m_display = 0x00;
|
||||
m_entry = 0x02;
|
||||
|
||||
busy(attotime::from_msec(10));
|
||||
}
|
||||
|
||||
void lc7985_device::busy(attotime time)
|
||||
{
|
||||
m_busy_flag = true;
|
||||
m_busy_timer->adjust(time);
|
||||
}
|
||||
|
||||
void lc7985_device::device_timer(emu_timer &, device_timer_id, int, void *)
|
||||
{
|
||||
m_busy_flag = false;
|
||||
}
|
||||
|
||||
void lc7985_device::inc_ddac()
|
||||
{
|
||||
if(m_function & 0x08) { // 2 lines
|
||||
if(m_ddac == 39)
|
||||
m_ddac = 64;
|
||||
else if(m_ddac == 64+39)
|
||||
m_ddac = 0;
|
||||
else
|
||||
m_ddac++;
|
||||
} else {
|
||||
if(m_ddac == 79)
|
||||
m_ddac = 0;
|
||||
else
|
||||
m_ddac++;
|
||||
}
|
||||
}
|
||||
|
||||
void lc7985_device::dec_ddac()
|
||||
{
|
||||
if(m_function & 0x08) { // 2 lines
|
||||
if(m_ddac == 64)
|
||||
m_ddac = 39;
|
||||
else if(m_ddac == 0)
|
||||
m_ddac = 64+39;
|
||||
else
|
||||
m_ddac--;
|
||||
} else {
|
||||
if(m_ddac == 0)
|
||||
m_ddac = 79;
|
||||
else
|
||||
m_ddac--;
|
||||
}
|
||||
}
|
||||
|
||||
void lc7985_device::shift_left()
|
||||
{
|
||||
if(m_shift == 79)
|
||||
m_shift = 0;
|
||||
else
|
||||
m_shift++;
|
||||
}
|
||||
|
||||
void lc7985_device::shift_right()
|
||||
{
|
||||
if(m_shift == 0)
|
||||
m_shift = 79;
|
||||
else
|
||||
m_shift--;
|
||||
}
|
||||
|
||||
void lc7985_device::ir_w(u8 data)
|
||||
{
|
||||
if(m_busy_flag)
|
||||
return;
|
||||
|
||||
if(data & 0x80) {
|
||||
// Set DDRAM address
|
||||
m_ddac = data & 0x7f;
|
||||
m_access_ddram = true;
|
||||
busy(attotime::from_usec(40));
|
||||
|
||||
} else if(data & 0x40) {
|
||||
// Set CGRAM address
|
||||
m_cgac = data & 0x3f;
|
||||
m_access_ddram = false;
|
||||
busy(attotime::from_usec(40));
|
||||
|
||||
} else if(data & 0x20) {
|
||||
// Set Function
|
||||
m_function = data;
|
||||
busy(attotime::from_usec(40));
|
||||
|
||||
} else if(data & 0x10) {
|
||||
// Cursor/Display Shift
|
||||
m_access_ddram = true;
|
||||
switch((data >> 2) & 3) {
|
||||
case 0: dec_ddac(); break;
|
||||
case 1: inc_ddac(); break;
|
||||
case 2: shift_left(); break;
|
||||
case 3: shift_right(); break;
|
||||
}
|
||||
|
||||
busy(attotime::from_usec(40));
|
||||
|
||||
} else if(data & 0x08) {
|
||||
// Display On/Off
|
||||
m_display = data;
|
||||
busy(attotime::from_usec(40));
|
||||
|
||||
} else if(data & 0x04) {
|
||||
// Set Entry Mode
|
||||
m_entry = data;
|
||||
busy(attotime::from_usec(40));
|
||||
|
||||
} else if(data & 0x02) {
|
||||
// Cursor home
|
||||
m_ddac = 0;
|
||||
m_shift = 0;
|
||||
m_access_ddram = true;
|
||||
busy(attotime::from_usec(16400));
|
||||
|
||||
} else if(data & 0x01) {
|
||||
// Display clear
|
||||
memset(m_ddram, 0x20, sizeof(m_ddram));
|
||||
m_ddac = 0x00;
|
||||
m_entry |= 0x02;
|
||||
busy(attotime::from_usec(16400));
|
||||
}
|
||||
}
|
||||
|
||||
u8 lc7985_device::status_r()
|
||||
{
|
||||
return (m_access_ddram ? m_ddac : m_cgac) | (m_busy_flag ? 0x80 : 0x00);
|
||||
}
|
||||
|
||||
void lc7985_device::dr_w(u8 data)
|
||||
{
|
||||
if(m_access_ddram) {
|
||||
m_ddram[(m_function & 0x08) && m_ddac >= 64 ? m_ddac - (64-40) : m_ddac] = data;
|
||||
switch(m_entry & 0x03) {
|
||||
case 0: dec_ddac(); break;
|
||||
case 1: dec_ddac(); shift_right(); break;
|
||||
case 2: inc_ddac(); break;
|
||||
case 3: inc_ddac(); shift_left(); break;
|
||||
}
|
||||
|
||||
} else {
|
||||
m_cgram[m_cgac] = data;
|
||||
if(m_entry & 0x02)
|
||||
m_cgac = (m_cgac + 1) & 0x3f;
|
||||
else
|
||||
m_cgac = (m_cgac - 1) & 0x3f;
|
||||
}
|
||||
}
|
||||
|
||||
u8 lc7985_device::dr_r()
|
||||
{
|
||||
u8 res;
|
||||
if(m_access_ddram) {
|
||||
res = m_ddram[(m_function & 0x08) && m_ddac >= 64 ? m_ddac - (64-40) : m_ddac];
|
||||
if(m_entry & 0x02)
|
||||
inc_ddac();
|
||||
else
|
||||
dec_ddac();
|
||||
|
||||
} else {
|
||||
res = m_cgram[m_cgac];
|
||||
if(m_entry & 0x02)
|
||||
m_cgac = (m_cgac + 1) & 0x3f;
|
||||
else
|
||||
m_cgac = (m_cgac - 1) & 0x3f;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
const u8 *lc7985_device::render()
|
||||
{
|
||||
memset(m_render_buffer, 0, sizeof(m_render_buffer));
|
||||
if(!(m_display & 0x04))
|
||||
return m_render_buffer;
|
||||
|
||||
if(m_function & 0x08) {
|
||||
for(int y = 0; y != 2; y++) {
|
||||
for(int x = 0; x != 40; x ++) {
|
||||
u8 c = m_ddram[((x + 80 - m_shift) % 40) + 40*y];
|
||||
const u8 *src = c < 32 ? m_cgram + 8*(c & 7) : m_cgrom + 16 * c;
|
||||
u8 *dest = m_render_buffer + 8 * y + 16 * x;
|
||||
for(int z = 0; z != 8; z ++)
|
||||
*dest++ = *src++ & 0x1f;
|
||||
}
|
||||
}
|
||||
if(m_display & 0x03) {
|
||||
int cx = ((m_ddac & 0x3f) + 80 - m_shift) % 80;
|
||||
u8 *dest = m_render_buffer + (m_ddac >= 0x40 ? 8 : 0) + 16*cx;
|
||||
if(m_display & 0x02)
|
||||
dest[7] = 0x1f;
|
||||
if(m_display & 0x01) {
|
||||
bool on = int(machine().time().as_double() / 0.409) & 1;
|
||||
if(on)
|
||||
for(int z = 0; z != 8; z ++)
|
||||
*dest++ = 0x1f;
|
||||
}
|
||||
}
|
||||
|
||||
} else if(m_function & 0x04) {
|
||||
for(int x = 0; x != 80; x ++) {
|
||||
u8 c = m_ddram[(x + 80 - m_shift) % 80];
|
||||
const u8 *src = c < 32 ? m_cgram + 8*(c & 6) : m_cgrom + 16 * c;
|
||||
u8 *dest = m_render_buffer + 16 * x;
|
||||
for(int z = 0; z != 11; z ++)
|
||||
*dest++ = *src++ & 0x1f;
|
||||
}
|
||||
if(m_display & 0x03) {
|
||||
int cx = (m_ddac + 80 - m_shift) % 80;
|
||||
u8 *dest = m_render_buffer + 16*cx;
|
||||
if(m_display & 0x02)
|
||||
dest[10] = 0x1f;
|
||||
if(m_display & 0x01) {
|
||||
bool on = int(machine().time().as_double() / 0.409) & 1;
|
||||
if(on)
|
||||
for(int z = 0; z != 11; z ++)
|
||||
*dest++ = 0x1f;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
for(int x = 0; x != 80; x ++) {
|
||||
u8 c = m_ddram[(x + 80 - m_shift) % 80];
|
||||
const u8 *src = c < 32 ? m_cgram + 8*(c & 7) : m_cgrom + 16 * c;
|
||||
u8 *dest = m_render_buffer + 16 * x;
|
||||
for(int z = 0; z != 8; z ++)
|
||||
*dest++ = *src++ & 0x1f;
|
||||
}
|
||||
if(m_display & 0x03) {
|
||||
int cx = (m_ddac + 80 - m_shift) % 80;
|
||||
u8 *dest = m_render_buffer + 16*cx;
|
||||
if(m_display & 0x02)
|
||||
dest[7] = 0x1f;
|
||||
if(m_display & 0x01) {
|
||||
bool on = int(machine().time().as_double() / 0.409) & 1;
|
||||
if(on)
|
||||
for(int z = 0; z != 8; z ++)
|
||||
*dest++ = 0x1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
return m_render_buffer;
|
||||
}
|
||||
|
61
src/devices/video/lc7985.h
Normal file
61
src/devices/video/lc7985.h
Normal file
@ -0,0 +1,61 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Olivier Galibert
|
||||
/***************************************************************************
|
||||
|
||||
Sanyo LC7985NA/LC7985ND LCD controller
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAME_VIDEO_LC7985_H
|
||||
#define MAME_VIDEO_LC7985_H
|
||||
|
||||
#pragma once
|
||||
|
||||
class lc7985_device : public device_t
|
||||
{
|
||||
public:
|
||||
lc7985_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
|
||||
void ir_w(u8 data);
|
||||
u8 status_r();
|
||||
void dr_w(u8 data);
|
||||
u8 dr_r();
|
||||
|
||||
// 5 bits used per byte, blocks of 16 lines, 80 blocks
|
||||
const u8 *render();
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
virtual const tiny_rom_entry *device_rom_region() const override;
|
||||
|
||||
private:
|
||||
optional_region_ptr<u8> m_cgrom_region; // internal chargen ROM
|
||||
u8 m_render_buffer[16*40];
|
||||
u8 m_ddram[80];
|
||||
u8 m_cgram[64];
|
||||
const u8 *m_cgrom;
|
||||
emu_timer *m_busy_timer;
|
||||
u8 m_ddac;
|
||||
u8 m_cgac;
|
||||
u8 m_shift;
|
||||
u8 m_function;
|
||||
u8 m_cds;
|
||||
u8 m_display;
|
||||
u8 m_entry;
|
||||
|
||||
bool m_busy_flag;
|
||||
bool m_access_ddram;
|
||||
|
||||
void inc_ddac();
|
||||
void dec_ddac();
|
||||
void shift_left();
|
||||
void shift_right();
|
||||
|
||||
void busy(attotime tm);
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(LC7985, lc7985_device)
|
||||
|
||||
#endif // MAME_VIDEO_LC7985_H
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "cpu/h8/h83002.h"
|
||||
#include "sound/multipcm.h"
|
||||
#include "video/lc7985.h"
|
||||
|
||||
#include "screen.h"
|
||||
#include "speaker.h"
|
||||
@ -23,21 +24,39 @@ public:
|
||||
driver_device(mconfig, type, tag),
|
||||
m_maincpu(*this, "maincpu"),
|
||||
m_ymw258(*this, "ymw258"),
|
||||
m_lcd(*this, "lcd"),
|
||||
m_key(*this, "S%c", 'A'),
|
||||
m_outputs(*this, "%x.%x.%x.%x", 0U, 0U, 0U, 0U),
|
||||
m_matrixsel(0)
|
||||
{ }
|
||||
|
||||
void mu5(machine_config &config);
|
||||
|
||||
protected:
|
||||
virtual void machine_start() override;
|
||||
virtual void machine_reset() override;
|
||||
|
||||
private:
|
||||
required_device<h83002_device> m_maincpu;
|
||||
required_device<multipcm_device> m_ymw258;
|
||||
required_device<lc7985_device> m_lcd;
|
||||
required_ioport_array<6> m_key;
|
||||
output_finder<2, 8, 8, 5> m_outputs;
|
||||
|
||||
void mu5_map(address_map &map);
|
||||
void mu5_io_map(address_map &map);
|
||||
void ymw258_map(address_map &map);
|
||||
|
||||
u8 m_lcd_ctrl;
|
||||
u8 m_lcd_data;
|
||||
|
||||
void lcd_ctrl_w(u16 data);
|
||||
u16 lcd_ctrl_r();
|
||||
void lcd_data_w(u16 data);
|
||||
u16 lcd_data_r();
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER(render_w);
|
||||
|
||||
u8 m_matrixsel;
|
||||
u8 matrix_r()
|
||||
{
|
||||
@ -68,7 +87,9 @@ void mu5_state::mu5_io_map(address_map &map)
|
||||
{
|
||||
map(h8_device::PORT_4, h8_device::PORT_4).lr8(NAME([this]() -> u8 { return m_matrixsel; }));
|
||||
map(h8_device::PORT_4, h8_device::PORT_4).lw8(NAME([this](u8 data) { m_matrixsel = data; }));
|
||||
map(h8_device::PORT_6, h8_device::PORT_6).rw(FUNC(mu5_state::lcd_ctrl_r), FUNC(mu5_state::lcd_ctrl_w));
|
||||
map(h8_device::PORT_7, h8_device::PORT_7).r(FUNC(mu5_state::matrix_r));
|
||||
map(h8_device::PORT_B, h8_device::PORT_B).rw(FUNC(mu5_state::lcd_data_r), FUNC(mu5_state::lcd_data_w));
|
||||
}
|
||||
|
||||
void mu5_state::ymw258_map(address_map &map)
|
||||
@ -76,6 +97,78 @@ void mu5_state::ymw258_map(address_map &map)
|
||||
map(0x000000, 0x1fffff).rom();
|
||||
}
|
||||
|
||||
void mu5_state::machine_start()
|
||||
{
|
||||
m_outputs.resolve();
|
||||
|
||||
save_item(NAME(m_lcd_ctrl));
|
||||
save_item(NAME(m_lcd_data));
|
||||
save_item(NAME(m_matrixsel));
|
||||
}
|
||||
|
||||
void mu5_state::machine_reset()
|
||||
{
|
||||
m_lcd_ctrl = 0;
|
||||
m_lcd_data = 0;
|
||||
m_matrixsel = 0;
|
||||
}
|
||||
|
||||
void mu5_state::lcd_ctrl_w(u16 data)
|
||||
{
|
||||
// bit 2 = rs
|
||||
// bit 1 = r/w
|
||||
// bit 0 = e
|
||||
|
||||
bool e_edge = (data ^ m_lcd_ctrl) & 1;
|
||||
m_lcd_ctrl = data;
|
||||
if(e_edge) {
|
||||
switch(m_lcd_ctrl & 7) {
|
||||
case 0:
|
||||
m_lcd->ir_w(m_lcd_data);
|
||||
break;
|
||||
case 3:
|
||||
m_lcd_data = m_lcd->status_r();
|
||||
break;
|
||||
case 4:
|
||||
m_lcd->dr_w(m_lcd_data);
|
||||
break;
|
||||
case 7:
|
||||
m_lcd_data = m_lcd->dr_r();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u16 mu5_state::lcd_ctrl_r()
|
||||
{
|
||||
return m_lcd_ctrl;
|
||||
}
|
||||
|
||||
void mu5_state::lcd_data_w(u16 data)
|
||||
{
|
||||
m_lcd_data = data;
|
||||
}
|
||||
|
||||
u16 mu5_state::lcd_data_r()
|
||||
{
|
||||
return m_lcd_data;
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(mu5_state::render_w)
|
||||
{
|
||||
if(!state)
|
||||
return;
|
||||
|
||||
const u8 *render = m_lcd->render();
|
||||
for(int y=0; y != 2; y++)
|
||||
for(int x=0; x != 8; x++)
|
||||
for(int yy=0; yy != 8; yy++) {
|
||||
u8 v = render[8 * y + 16 * x + yy];
|
||||
for(int xx=0; xx != 5; xx++)
|
||||
m_outputs[y][x][yy][xx] = (v >> xx) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
static INPUT_PORTS_START(mu5)
|
||||
PORT_START("SA")
|
||||
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Part Down") PORT_CODE(KEYCODE_Z)
|
||||
@ -137,6 +230,15 @@ void mu5_state::mu5(machine_config &config)
|
||||
m_ymw258->set_addrmap(0, &mu5_state::ymw258_map);
|
||||
m_ymw258->add_route(0, "lspeaker", 1.0);
|
||||
m_ymw258->add_route(1, "rspeaker", 1.0);
|
||||
|
||||
LC7985(config, m_lcd);
|
||||
|
||||
auto &screen = SCREEN(config, "screen", SCREEN_TYPE_SVG);
|
||||
screen.set_refresh_hz(60);
|
||||
screen.set_size(800, 435);
|
||||
screen.set_visarea_full();
|
||||
screen.screen_vblank().set(FUNC(mu5_state::render_w));
|
||||
|
||||
}
|
||||
|
||||
ROM_START( mu5 )
|
||||
@ -145,6 +247,9 @@ ROM_START( mu5 )
|
||||
|
||||
ROM_REGION(0x200000, "ymw258", 0)
|
||||
ROM_LOAD("yamaha_mu5_waverom_xp50280-801.bin", 0x000000, 0x200000, CRC(e0913030) SHA1(369f8df4942b6717c142ca8c4913e556dafae187))
|
||||
|
||||
ROM_REGION(257524, "screen", 0)
|
||||
ROM_LOAD("mu5lcd.svg", 0, 257524, CRC(a9a6f561) SHA1(c90d973bfb12755e99cf54d9323a54b773b48bba))
|
||||
ROM_END
|
||||
|
||||
CONS(1994, mu5, 0, 0, mu5, mu5, mu5_state, empty_init, "Yamaha", "MU-5", MACHINE_NOT_WORKING )
|
||||
|
Loading…
Reference in New Issue
Block a user