(mess) D-110: Preliminary driver [Lord_Nightmare, O. Galibert]

This commit is contained in:
Olivier Galibert 2013-01-04 13:18:27 +00:00
parent e8738c6a89
commit 2187a8afa7
10 changed files with 778 additions and 10 deletions

View File

@ -81,7 +81,7 @@ void i8x9x_device::commit_hso_cam()
{
for(int i=0; i<8; i++)
if(!hso_info[i].active) {
if(hso_command != 0x18)
if(hso_command != 0x18 && hso_command != 0x19)
logerror("%s: hso cam %02x %04x in slot %d (%04x)\n", tag(), hso_command, hso_time, i, PPC);
hso_info[i].active = true;
hso_info[i].command = hso_command;
@ -347,7 +347,7 @@ void i8x9x_device::internal_update(UINT64 current_time)
UINT16 t = hso_info[i].time;
if(((cmd & 0x40) && t == current_timer2) ||
(!(cmd & 0x40) && t == current_timer1)) {
if(cmd != 0x18)
if(cmd != 0x18 && cmd != 0x19)
logerror("%s: hso cam %02x %04x in slot %d triggered\n",
tag(), cmd, t, i);
trigger_cam(i, current_time);

View File

@ -61,13 +61,14 @@ public:
#define O(o) void o ## _196_full(); void o ## _196_partial()
O(bmov_direct_2);
O(cmpl_direct_2);
O(bmovi_direct_2);
O(pop_indirect_1);
O(pop_indexed_1);
O(cmpl_direct_2);
O(djnzw_rrel8);
O(pusha_none);
O(idlpd_none);
O(pop_indexed_1);
O(pop_indirect_1);
O(popa_none);
O(pusha_none);
#undef O
};

View File

@ -692,6 +692,66 @@ UINT16 mcs96_device::do_sub(UINT16 v1, UINT16 v2)
return diff;
}
UINT8 mcs96_device::do_addcb(UINT8 v1, UINT8 v2)
{
UINT16 sum = v1+v2+(PSW & F_C ? 1 : 0);
PSW &= ~(F_Z|F_N|F_C|F_V);
if(!UINT8(sum))
PSW |= F_Z;
else if(INT8(sum) < 0)
PSW |= F_N;
if(~(v1^v2) & (v1^sum) & 0x80)
PSW |= F_V|F_VT;
if(sum & 0xff00)
PSW |= F_C;
return sum;
}
UINT16 mcs96_device::do_addc(UINT16 v1, UINT16 v2)
{
UINT32 sum = v1+v2+(PSW & F_C ? 1 : 0);
PSW &= ~(F_Z|F_N|F_C|F_V);
if(!UINT16(sum))
PSW |= F_Z;
else if(INT16(sum) < 0)
PSW |= F_N;
if(~(v1^v2) & (v1^sum) & 0x8000)
PSW |= F_V|F_VT;
if(sum & 0xffff0000)
PSW |= F_C;
return sum;
}
UINT8 mcs96_device::do_subcb(UINT8 v1, UINT8 v2)
{
UINT16 diff = v1 - v2 - (PSW & F_C ? 0 : 1);
PSW &= ~(F_N|F_V|F_Z|F_C);
if(!UINT8(diff))
PSW |= F_Z;
else if(INT8(diff) < 0)
PSW |= F_N;
if((v1^v2) & (v1^diff) & 0x80)
PSW |= F_V;
if(!(diff & 0xff00))
PSW |= F_C;
return diff;
}
UINT16 mcs96_device::do_subc(UINT16 v1, UINT16 v2)
{
UINT32 diff = v1 - v2 - (PSW & F_C ? 0 : 1);
PSW &= ~(F_N|F_V|F_Z|F_C);
if(!UINT16(diff))
PSW |= F_Z;
else if(INT16(diff) < 0)
PSW |= F_N;
if((v1^v2) & (v1^diff) & 0x8000)
PSW |= F_V;
if(!(diff & 0xffff0000))
PSW |= F_C;
return diff;
}
void mcs96_device::set_nz8(UINT8 v)
{
PSW &= ~(F_N|F_V|F_Z|F_C);

View File

@ -163,6 +163,11 @@ protected:
UINT8 do_subb(UINT8 v1, UINT8 v2);
UINT16 do_sub(UINT16 v1, UINT16 v2);
UINT8 do_addcb(UINT8 v1, UINT8 v2);
UINT16 do_addc(UINT16 v1, UINT16 v2);
UINT8 do_subcb(UINT8 v1, UINT8 v2);
UINT16 do_subc(UINT16 v1, UINT16 v2);
void set_nz8(UINT8 v);
void set_nz16(UINT16 v);
@ -233,10 +238,8 @@ protected:
O(or_direct_2); O(or_immed_2w); O(or_indexed_2); O(or_indirect_2);
O(orb_direct_2); O(orb_immed_2b); O(orb_indexed_2); O(orb_indirect_2);
O(pop_direct_1); O(pop_indexed_1); O(pop_indirect_1);
O(popa_none);
O(popf_none);
O(push_direct_1); O(push_immed_1w); O(push_indexed_1); O(push_indirect_1);
O(pusha_none);
O(pushf_none);
O(ret_none);
O(rst_none);

View File

@ -1218,7 +1218,7 @@ fe8f div indexed_2
9a cmpb indirect_2
TMP = any_r8(OP1);
do_subb(reg_r8(OP2), TMP);
post_indirect 2 6 7 // +5 when external
post_indirect 1 6 7 // +5 when external
9b cmpb indexed_2
TMP = any_r8(OP1);
@ -1352,20 +1352,50 @@ a3 ld indexed_2
post_indexed 6 7 // +5 when external
a4 addc direct_2
TMP = reg_r16(OP1);
TMP = do_addc(reg_r16(OP2), TMP);
reg_w16(OP2, TMP);
next(4);
a5 addc immed_2w
TMP = do_addc(reg_r16(OP2), OP1);
reg_w16(OP2, TMP);
next(5);
a6 addc indirect_2
TMP = any_r16(OP1);
TMP = do_addc(reg_r16(OP2), TMP);
reg_w16(OP2, TMP);
post_indirect 2 6 7 // +5 when external
a7 addc indexed_2
TMP = any_r16(OP1);
TMP = do_addc(reg_r16(OP2), TMP);
reg_w16(OP2, TMP);
post_indexed 6 7 // +5 when external
a8 subc direct_2
TMP = reg_r16(OP1);
TMP = do_subc(reg_r16(OP2), TMP);
reg_w16(OP2, TMP);
next(4);
a9 subc immed_2w
TMP = do_subc(reg_r16(OP2), OP1);
reg_w16(OP2, TMP);
next(5);
aa subc indirect_2
TMP = any_r16(OP1);
TMP = do_subc(reg_r16(OP2), TMP);
reg_w16(OP2, TMP);
post_indirect 2 6 7 // +5 when external
ab subc indexed_2
TMP = any_r16(OP1);
TMP = do_subc(reg_r16(OP2), TMP);
reg_w16(OP2, TMP);
post_indexed 6 7 // +5 when external
ac ldbze direct_2
reg_w16(OP2, UINT8(reg_r8(OP1)));
@ -1400,20 +1430,50 @@ b3 ldb indexed_2
post_indexed 6 7 // +5 when external
b4 addcb direct_2
TMP = reg_r8(OP1);
TMP = do_addcb(reg_r8(OP2), TMP);
reg_w8(OP2, TMP);
next(4);
b5 addcb immed_2w
TMP = do_addcb(reg_r8(OP2), OP1);
reg_w8(OP2, TMP);
next(4);
b6 addcb indirect_2
TMP = any_r8(OP1);
TMP = do_addcb(reg_r8(OP2), TMP);
reg_w8(OP2, TMP);
post_indirect 1 6 7 // +5 when external
b7 addcb indexed_2
TMP = any_r8(OP1);
TMP = do_addcb(reg_r8(OP2), TMP);
reg_w8(OP2, TMP);
post_indexed 6 7 // +5 when external
b8 subcb direct_2
TMP = reg_r8(OP1);
TMP = do_subcb(reg_r8(OP2), TMP);
reg_w8(OP2, TMP);
next(4);
b9 subcb immed_2w
TMP = do_subcb(reg_r8(OP2), OP1);
reg_w8(OP2, TMP);
next(4);
ba subcb indirect_2
TMP = any_r8(OP1);
TMP = do_subcb(reg_r8(OP2), TMP);
reg_w8(OP2, TMP);
post_indirect 1 6 7 // +5 when external
bb subcb indexed_2
TMP = any_r8(OP1);
TMP = do_subcb(reg_r8(OP2), TMP);
reg_w8(OP2, TMP);
post_indexed 6 7 // +5 when external
bc ldbse direct_2
reg_w16(OP2, INT8(reg_r8(OP1)));
@ -1727,7 +1787,7 @@ f3 popf none
f4 pusha none 196
f5 popa none
f5 popa none 196
f6 idlpd none 196

View File

@ -0,0 +1,272 @@
/*************************************************************************************************
Roland D-110 driver
Driver by Olivier Galibert and Jonathan Gevaryahu
The Roland D-110 is an expander (synthesizer without the keyboard)
from 1988. Internally it's very similar to a mt32, with a better
LCD screen (16x2) and more control buttons. More importantly, it
has more sound rom, a battery-backed ram and a port for memory
cards allowing to load and save new sounds.
After the first boot, the ram needs to be reinitialized to factory
default values. Press Write/Copy (I) while resetting then
validate with Enter (K).
*/
#include "emu.h"
#include "machine/ram.h"
#include "machine/nvram.h"
#include "machine/msm6222b.h"
#include "cpu/mcs96/i8x9x.h"
static INPUT_PORTS_START( d110 )
PORT_START("SC0")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Write/Copy") PORT_CODE(KEYCODE_I)
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Number +") PORT_CODE(KEYCODE_U)
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Bank +") PORT_CODE(KEYCODE_Y)
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Group +") PORT_CODE(KEYCODE_T)
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Part +") PORT_CODE(KEYCODE_R)
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Timbre") PORT_CODE(KEYCODE_E)
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Patch") PORT_CODE(KEYCODE_W)
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Exit") PORT_CODE(KEYCODE_Q)
PORT_START("SC1")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Enter") PORT_CODE(KEYCODE_K)
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Number -") PORT_CODE(KEYCODE_J)
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Bank -") PORT_CODE(KEYCODE_H)
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Group -") PORT_CODE(KEYCODE_G)
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Part -") PORT_CODE(KEYCODE_F)
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("System") PORT_CODE(KEYCODE_D)
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Part") PORT_CODE(KEYCODE_S)
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Edit") PORT_CODE(KEYCODE_A)
INPUT_PORTS_END
class d110_state : public driver_device
{
public:
required_device<i8x9x_device> cpu;
required_device<ram_device> ram;
required_device<nvram_device> rams;
required_device<ram_device> memc;
required_device<nvram_device> memcs;
required_device<msm6222b_device> lcd;
required_device<timer_device> midi_timer;
d110_state(const machine_config &mconfig, device_type type, const char *tag);
virtual void machine_start();
virtual void machine_reset();
virtual void palette_init();
UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
DECLARE_WRITE8_MEMBER(bank_w);
DECLARE_WRITE8_MEMBER(so_w);
DECLARE_WRITE16_MEMBER(midi_w);
DECLARE_READ8_MEMBER(lcd_ctrl_r);
DECLARE_WRITE8_MEMBER(lcd_ctrl_w);
DECLARE_WRITE8_MEMBER(lcd_data_w);
DECLARE_READ16_MEMBER(port0_r);
TIMER_DEVICE_CALLBACK_MEMBER(midi_timer_cb);
TIMER_DEVICE_CALLBACK_MEMBER(samples_timer_cb);
private:
UINT8 lcd_data_buffer[256];
int lcd_data_buffer_pos;
UINT8 midi;
int midi_pos;
UINT8 port0;
};
d110_state::d110_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
cpu(*this, "maincpu"),
ram(*this, "ram"),
rams(*this, "rams"),
memc(*this, "memc"),
memcs(*this, "memcs"),
lcd(*this, "lcd"),
midi_timer(*this, "midi_timer")
{
}
UINT32 d110_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
bitmap.fill(0);
const UINT8 *data = lcd->render();
for(int l=0; l<2; l++)
for(int c=0; c<20; c++)
for(int y=0; y<8; y++) {
UINT8 v = data[c*16 + l*40*16 + y];
for(int x=0; x<5; x++)
bitmap.pix16(y+9*l, c*6+x) = v & (0x10 >> x) ? 1 : 0;
}
return 0;
}
void d110_state::machine_start()
{
rams->set_base(ram->pointer(), 32768);
memcs->set_base(memc->pointer(), 32768);
membank("bank")->configure_entries(0x00, 4, memregion("maincpu")->base(), 0x4000);
membank("bank")->configure_entries(0x10, 2, ram->pointer(), 0x4000);
membank("bank")->configure_entries(0x20, 8, memregion("presets")->base(), 0x4000);
membank("bank")->configure_entries(0x30, 2, memc->pointer(), 0x4000);
membank("fixed")->set_base(ram->pointer());
lcd_data_buffer_pos = 0;
}
void d110_state::machine_reset()
{
// midi_timer->adjust(attotime::from_hz(1));
midi_pos = 0;
port0 = 0x80; // battery ok
}
WRITE8_MEMBER(d110_state::lcd_ctrl_w)
{
lcd->control_w(data);
for(int i=0; i != lcd_data_buffer_pos; i++)
lcd->data_w(lcd_data_buffer[i]);
lcd_data_buffer_pos = 0;
}
READ8_MEMBER(d110_state::lcd_ctrl_r)
{
// Busy flag in the msm622b is bit 7, while the software expects it in bit 0...
return lcd->control_r() >> 7;
}
WRITE8_MEMBER(d110_state::lcd_data_w)
{
if(lcd_data_buffer_pos == sizeof(lcd_data_buffer)) {
logerror("Warning: lcd data buffer overflow (%04x)\n", cpu->pc());
return;
}
lcd_data_buffer[lcd_data_buffer_pos++] = data;
}
WRITE8_MEMBER(d110_state::bank_w)
{
membank("bank")->set_entry(data);
}
WRITE16_MEMBER(d110_state::midi_w)
{
logerror("midi_out %02x\n", data);
midi = data;
}
TIMER_DEVICE_CALLBACK_MEMBER(d110_state::midi_timer_cb)
{
const static UINT8 midi_data[3] = { 0x91, 0x40, 0x7f };
midi = midi_data[midi_pos++];
logerror("midi_in %02x\n", midi);
cpu->serial_w(midi);
if(midi_pos < sizeof(midi_data))
midi_timer->adjust(attotime::from_hz(1250));
}
READ16_MEMBER(d110_state::port0_r)
{
return port0;
}
TIMER_DEVICE_CALLBACK_MEMBER(d110_state::samples_timer_cb)
{
port0 ^= 0x10;
}
WRITE8_MEMBER(d110_state::so_w)
{
// bit 0 = led
// bit 1-2 = reverb program a13/a14
// bit 3 = R. SW. to ananlog board
// bit 5 = boss 8Mhz clock, handled internally
// logerror("so: rw=%d bank=%d led=%d\n", (data >> 3) & 1, (data >> 1) & 3, data & 1);
}
void d110_state::palette_init()
{
palette_set_color(machine(), 0, MAKE_RGB(0, 255, 0));
palette_set_color(machine(), 1, MAKE_RGB(0, 0, 0));
}
static ADDRESS_MAP_START( d110_map, AS_PROGRAM, 8, d110_state )
AM_RANGE(0x0100, 0x0100) AM_WRITE(bank_w)
AM_RANGE(0x0200, 0x0200) AM_WRITE(so_w)
AM_RANGE(0x021a, 0x021a) AM_READ_PORT("SC0") AM_WRITENOP
AM_RANGE(0x021c, 0x021c) AM_READ_PORT("SC1")
AM_RANGE(0x0300, 0x0300) AM_WRITE(lcd_data_w)
AM_RANGE(0x0380, 0x0380) AM_READWRITE(lcd_ctrl_r, lcd_ctrl_w)
AM_RANGE(0x1000, 0x7fff) AM_ROM AM_REGION("maincpu", 0x1000)
AM_RANGE(0x8000, 0xbfff) AM_RAMBANK("bank")
AM_RANGE(0xc000, 0xffff) AM_RAMBANK("fixed")
ADDRESS_MAP_END
static ADDRESS_MAP_START( d110_io, AS_IO, 16, d110_state )
AM_RANGE(i8x9x_device::SERIAL, i8x9x_device::SERIAL) AM_WRITE(midi_w)
AM_RANGE(i8x9x_device::P0, i8x9x_device::P0) AM_READ(port0_r)
ADDRESS_MAP_END
static MACHINE_CONFIG_START( d110, d110_state )
MCFG_CPU_ADD( "maincpu", P8098, XTAL_12MHz )
MCFG_CPU_PROGRAM_MAP( d110_map )
MCFG_CPU_IO_MAP( d110_io )
// Battery-backed main ram
MCFG_RAM_ADD( "ram" )
MCFG_RAM_DEFAULT_SIZE( "32K" )
MCFG_NVRAM_ADD_0FILL( "rams" )
// Shall become a proper memcard device someday
MCFG_RAM_ADD( "memc" )
MCFG_RAM_DEFAULT_SIZE( "32K" )
MCFG_NVRAM_ADD_0FILL( "memcs" )
MCFG_SCREEN_ADD( "screen", LCD )
MCFG_SCREEN_REFRESH_RATE(50)
MCFG_SCREEN_UPDATE_DRIVER(d110_state, screen_update)
// MCFG_SCREEN_SIZE(20*6-1, 2*9-1)
MCFG_SCREEN_SIZE(16*6-1, (16*6-1)*3/4)
MCFG_SCREEN_VISIBLE_AREA(0, 16*6-2, 0, (16*6-1)*3/4-1)
MCFG_PALETTE_LENGTH(2)
MCFG_MSM6222B_01_ADD( "lcd" )
MCFG_TIMER_DRIVER_ADD( "midi_timer", d110_state, midi_timer_cb )
MCFG_TIMER_DRIVER_ADD_PERIODIC( "samples_timer", d110_state, samples_timer_cb, attotime::from_hz(32000*2) )
MACHINE_CONFIG_END
ROM_START( d110 )
ROM_REGION( 0x10000, "maincpu", 0 )
ROM_DEFAULT_BIOS( "110" )
ROM_SYSTEM_BIOS( 0, "106", "Firmware 1.06" )
ROMX_LOAD( "d-110.v1.06.ic19.bin", 0, 0x8000, CRC(3dd5b6e9) SHA1(73b155fb0a8adc2362e73cb0803dafba9ccfb508), ROM_BIOS(1) )
ROM_SYSTEM_BIOS( 1, "110", "Firmware 1.10" )
ROMX_LOAD( "d-110.v1.10.ic19.bin", 0, 0x8000, CRC(3ae68187) SHA1(28635510f30d6c1fb88e00da03e5b4e045c380cb), ROM_BIOS(2) )
ROM_REGION( 0x20000, "presets", 0 )
ROM_LOAD( "r15179873-lh5310-97.ic12.bin", 0, 0x20000, CRC(580a8f9e) SHA1(05587a0542b01625dcde37de5bb339880e47eb93) )
ROM_REGION( 0x100000, "la32", 0 )
ROM_LOAD( "r15179878.ic7.bin", 0, 0x80000, CRC(e117e6ab) SHA1(6760d14900161b8715c2bfd4ebe997877087c90c) )
ROM_LOAD( "r15179880.ic8.bin", 0x80000, 0x80000, CRC(b329f945) SHA1(9c59f50518a070461b2ec6cb4e43ee7cc1e905b6) )
ROM_REGION( 0x8000, "boss", 0 )
ROM_LOAD( "r15179879.ic6.bin", 0, 0x8000, CRC(5d34174e) SHA1(17bd2887711c5c5458aba6d3be5972b2096eb450) )
ROM_END
CONS( 1988, d110, 0, 0, d110, d110, driver_device, 0, "Roland", "D110", GAME_NOT_WORKING|GAME_NO_SOUND )

View File

@ -0,0 +1,277 @@
/***************************************************************************
MSM6222B
A somewhat hd44780-compatible LCD controller.
The -01 variant has a fixed cgrom, the other variants are mask-programmed.
****************************************************************************
Copyright Olivier Galibert
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name 'MAME' nor the names of its contributors may be
used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY OLIVIER GALIBERT ''AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL OLIVIER GALIBERT BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/
#include "emu.h"
#include "msm6222b.h"
const device_type MSM6222B = &device_creator<msm6222b_device>;
const device_type MSM6222B_01 = &device_creator<msm6222b_01_device>;
ROM_START( msm6222b_01 )
ROM_REGION( 0x1000, "cgrom", 0 )
ROM_LOAD( "msm6222b-01.bin", 0x0000, 0x1000, CRC(8ffa8521) SHA1(e108b520e6d20459a7bbd5958bbfa1d551a690bd) )
ROM_END
msm6222b_device::msm6222b_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
device_t(mconfig, type, name, tag, owner, clock)
{
m_shortname = "msm6222b";
}
msm6222b_device::msm6222b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
device_t(mconfig, MSM6222B, "msm6222b-xx", tag, owner, clock)
{
m_shortname = "msm6222b";
}
msm6222b_01_device::msm6222b_01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
msm6222b_device(mconfig, MSM6222B_01, "msm6222b-01", tag, owner, clock)
{
}
const rom_entry *msm6222b_01_device::device_rom_region() const
{
return ROM_NAME(msm6222b_01);
}
void msm6222b_device::device_start()
{
if(memregion("cgrom"))
cgrom = memregion("cgrom")->base();
else if(m_region)
cgrom = m_region->base();
else
cgrom = NULL;
memset(cgram, 0, sizeof(cgram));
memset(ddram, 0x20, sizeof(ddram));
cursor_direction = true;
cursor_blinking = false;
display_on = false;
two_line = false;
cursor_on = false;
shift_on_write = false;
double_height = false;
adc = 0x00;
shift = 0;
}
void msm6222b_device::control_w(UINT8 data)
{
int cmd;
for(cmd = 7; cmd >= 0 && !(data & (1<<cmd)); cmd--);
switch(cmd) {
case 0:
memset(ddram, 0x20, sizeof(ddram));
adc = 0x00;
break;
case 1:
adc = 0x00;
shift = 0x00;
break;
case 2:
shift_on_write = data & 1;
cursor_direction = data & 2;
break;
case 3:
display_on = data & 4;
cursor_on = data & 2;
cursor_blinking = data & 1;
break;
case 4:
if(data & 8)
shift_step(data & 4);
else
cursor_step(data & 4);
break;
case 5:
two_line = data & 8;
double_height = (data & 0xc) == 4;
// Bit 4 is 4bits/8bits data access
break;
case 6:
adc = data & 0x3f;
break;
case 7:
adc = data; // Bit 7 is set
break;
}
}
UINT8 msm6222b_device::control_r()
{
return adc & 0x7f;
}
void msm6222b_device::data_w(UINT8 data)
{
if(adc & 0x80) {
int adr = adc & 0x7f;
if(two_line) {
if((adr >= 40 && adr < 64) || adr >= 64+40)
adr = -1;
if(adr >= 64)
adr += 40-64;
} else {
if(adr >= 80)
adr = -1;
}
if(adr != -1) {
ddram[adr] = data;
if(shift_on_write)
shift_step(cursor_direction);
else
cursor_step(cursor_direction);
}
} else {
if(adc < 8*8) {
cgram[adc] = data;
cursor_step(cursor_direction);
}
}
}
void msm6222b_device::cursor_step(bool direction)
{
if(direction) {
if(adc & 0x80) {
if(two_line && adc == (0x80|39))
adc = 0x80|64;
else if(two_line && adc == (0x80|(64+39)))
adc = 0x80;
else if((!two_line) && adc == (0x80|79))
adc = 0x80;
else
adc++;
} else {
if(adc == 8*8-1)
adc = 0x00;
else
adc++;
}
} else {
if(adc & 0x80) {
if(adc == 0x80)
adc = two_line ? 0x80|(64+39) : 0x80|79;
else if(two_line && adc == (0x80|64))
adc = 0x80|39;
else
adc--;
} else {
if(adc == 0x00)
adc = 8*8-1;
else
adc--;
}
}
}
void msm6222b_device::shift_step(bool direction)
{
if(direction) {
if(shift == 79)
shift = 0;
else
shift++;
} else {
if(shift == 0)
shift = 79;
else
shift--;
}
}
bool msm6222b_device::blink_on() const
{
if(!cursor_blinking)
return false;
UINT64 clocks = machine().time().as_ticks(250000);
if(double_height)
return clocks % 281600 >= 140800;
else
return clocks % 204800 >= 102400;
}
const UINT8 *msm6222b_device::render()
{
memset(render_buf, 0, 80*16);
if(!display_on)
return render_buf;
int char_height = double_height ? 11 : 8;
for(int i=0; i<80; i++) {
UINT8 c = ddram[(i+shift) % 80];
if(c < 16)
memcpy(render_buf + 16*i, double_height ? cgram + 8*(c & 6) : cgram + 8*(c & 7), char_height);
else if(cgrom)
memcpy(render_buf + 16*i, cgrom + 16*c, char_height);
}
if(cursor_on) {
int cpos = adc & 0x7f;
if(two_line) {
if((cpos >= 40 && cpos < 64) || cpos >= 64+40)
cpos = -1;
else if(cpos >= 64)
cpos += 40-64;
} else {
if(cpos >= 80)
cpos = -1;
}
if(cpos != -1) {
cpos = (cpos + shift) % 80;
render_buf[cpos*16 + (double_height ? 10 : 7)] |= 0x1f;
if(blink_on())
for(int i=0; i<char_height; i++)
render_buf[cpos*16 + i] ^= 0x1f;
}
}
return render_buf;
}

View File

@ -0,0 +1,92 @@
/***************************************************************************
MSM6222B
A somewhat hd44780-compatible LCD controller.
The -01 variant has a fixed cgrom, the other variants are mask-programmed.
****************************************************************************
Copyright Olivier Galibert
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name 'MAME' nor the names of its contributors may be
used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY OLIVIER GALIBERT ''AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL OLIVIER GALIBERT BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/
#ifndef __MSM6222B_H__
#define __MSM6222B_H__
#define MCFG_MSM6222B_ADD( _tag ) \
MCFG_DEVICE_ADD( _tag, MSM6222B, 0 )
#define MCFG_MSM6222B_01_ADD( _tag ) \
MCFG_DEVICE_ADD( _tag, MSM6222B_01, 0 )
class msm6222b_device : public device_t {
public:
msm6222b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
msm6222b_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
void control_w(UINT8 data);
UINT8 control_r();
void data_w(UINT8 data);
UINT8 data_r();
// Character n bits are at bytes n*16..n*16+7 when 8-high, +10 when 11-high. Only the low 5 bits are used.
// In one line mode n = 0..79. In two line mode first line is 0..39 and second is 40..79.
const UINT8 *render();
protected:
virtual void device_start();
private:
UINT8 cgram[8*8];
UINT8 ddram[80];
UINT8 render_buf[80*16];
bool cursor_direction, cursor_blinking, two_line, shift_on_write, double_height, cursor_on, display_on;
UINT8 adc, shift;
const UINT8 *cgrom;
void cursor_step(bool direction);
void shift_step(bool direction);
bool blink_on() const;
};
class msm6222b_01_device : public msm6222b_device {
public:
msm6222b_01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
protected:
virtual const rom_entry *device_rom_region() const;
};
extern const device_type MSM6222B;
extern const device_type MSM6222B_01;
#endif

View File

@ -346,6 +346,7 @@ mu100 // 1997 MU-100
// Roland
mt32
cm32l
d110
//***************COMPUTERS**************************************************

View File

@ -532,6 +532,7 @@ $(MESSOBJ)/shared.a: \
$(MESS_MACHINE)/mos6530.o \
$(MESS_MACHINE)/s100.o \
$(MESS_MACHINE)/sed1200.o \
$(MESS_MACHINE)/msm6222b.o \
$(MESS_MACHINE)/serial.o \
$(MESS_MACHINE)/ncr5380.o \
$(MESS_MACHINE)/ncr5390.o \
@ -1594,6 +1595,7 @@ $(MESSOBJ)/robotron.a: \
$(MESSOBJ)/roland.a: \
$(MESS_DRIVERS)/rmt32.o \
$(MESS_DRIVERS)/rd110.o \
$(MESSOBJ)/rockwell.a: \
$(MESS_MACHINE)/aim65.o \