// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
#include "emu.h"
#include "wpc_dmd.h"
#include "rendlay.h"
#include "screen.h"
DEFINE_DEVICE_TYPE(WPC_DMD, wpc_dmd_device, "wpc_dmd", "Williams Pinball Controller Dot Matrix Display")
void wpc_dmd_device::registers(address_map &map)
{
map(0, 0).w(FUNC(wpc_dmd_device::bank2_w));
map(1, 1).w(FUNC(wpc_dmd_device::bank0_w));
map(2, 2).w(FUNC(wpc_dmd_device::bank6_w));
map(3, 3).w(FUNC(wpc_dmd_device::bank4_w));
map(4, 4).w(FUNC(wpc_dmd_device::banka_w));
map(5, 5).w(FUNC(wpc_dmd_device::firq_scanline_w));
map(6, 6).w(FUNC(wpc_dmd_device::bank8_w));
map(7, 7).w(FUNC(wpc_dmd_device::visible_page_w));
}
wpc_dmd_device::wpc_dmd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, WPC_DMD, tag, owner, clock),
scanline_cb(*this),
dmd0(*this, ":dmd0"),
dmd2(*this, ":dmd2"),
dmd4(*this, ":dmd4"),
dmd6(*this, ":dmd6"),
dmd8(*this, ":dmd8"),
dmda(*this, ":dmda")
{
}
wpc_dmd_device::~wpc_dmd_device()
{
}
MACHINE_CONFIG_START(wpc_dmd_device::device_add_mconfig)
MCFG_SCREEN_ADD("screen", LCD)
MCFG_SCREEN_REFRESH_RATE(60)
MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500))
MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, wpc_dmd_device, screen_update)
MCFG_SCREEN_SIZE(128*4, 32*4)
MCFG_SCREEN_VISIBLE_AREA(0, 128*4-1, 0, 32*4-1)
MCFG_DEFAULT_LAYOUT(layout_lcd)
MCFG_TIMER_DRIVER_ADD_PERIODIC("scanline", wpc_dmd_device, scanline_timer, attotime::from_hz(60*4*32))
MACHINE_CONFIG_END
void wpc_dmd_device::device_start()
{
scanline_cb.resolve_safe();
ram.resize(0x2000);
screen_buffer.resize(128*32);
bitcounts.resize(256);
dmd0->configure_entries(0, 0x10, &ram[0], 0x200);
dmd2->configure_entries(0, 0x10, &ram[0], 0x200);
dmd4->configure_entries(0, 0x10, &ram[0], 0x200);
dmd6->configure_entries(0, 0x10, &ram[0], 0x200);
dmd8->configure_entries(0, 0x10, &ram[0], 0x200);
dmda->configure_entries(0, 0x10, &ram[0], 0x200);
memset(&ram[0], 0x00, 0x2000);
for(int i=0; i<256; i++) {
int bc = i;
bc = ((bc & 0xaa) >> 1) + (bc & 0x55);
bc = ((bc & 0xcc) >> 2) + (bc & 0x33);
bc = ((bc & 0xf0) >> 4) + (bc & 0x0f);
bitcounts[i] = bc;
}
save_item(NAME(visible_page));
save_item(NAME(cur_scanline));
save_item(NAME(firq_scanline));
save_item(NAME(ram));
save_item(NAME(screen_buffer));
save_item(NAME(bitcounts));
}
void wpc_dmd_device::device_reset()
{
dmd0->set_entry(0);
dmd2->set_entry(1);
dmd4->set_entry(2);
dmd6->set_entry(3);
dmd8->set_entry(4);
dmda->set_entry(5);
memset(&screen_buffer[0], 0x00, 128*32);
visible_page = 0;
firq_scanline = 0;
cur_scanline = 0;
}
uint32_t wpc_dmd_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
const uint8_t *src = &screen_buffer[0];
for(int y=0; y<32; y++) {
uint32_t *pix0 = reinterpret_cast<uint32_t *>(bitmap.raw_pixptr(y*4));
uint32_t *pix1 = reinterpret_cast<uint32_t *>(bitmap.raw_pixptr(y*4+1));
uint32_t *pix2 = reinterpret_cast<uint32_t *>(bitmap.raw_pixptr(y*4+2));
uint32_t *pix3 = reinterpret_cast<uint32_t *>(bitmap.raw_pixptr(y*4+3));
for(int x=0; x<128; x++) {
uint8_t v = bitcounts[*src++ & 0x3f];
uint8_t v0 = v < 2 ? 0 : v-2;
uint8_t v1 = v < 1 ? 0 : v-1;
uint8_t v2 = v > 5 ? 5 : v;
v0 = 255*v0/5;
v1 = 255*v1/5;
v2 = 255*v2/5;
uint32_t xv0 = (v0 << 16) | (v0 << 8);
uint32_t xv1 = (v1 << 16) | (v1 << 8);
uint32_t xv2 = (v2 << 16) | (v2 << 8);
*pix0++ = xv0;
*pix0++ = xv1;
*pix0++ = xv1;
*pix0++ = xv0;
*pix1++ = xv1;
*pix1++ = xv2;
*pix1++ = xv2;
*pix1++ = xv1;
*pix2++ = xv1;
*pix2++ = xv2;
*pix2++ = xv2;
*pix2++ = xv1;
*pix3++ = xv0;
*pix3++ = xv1;
*pix3++ = xv1;
*pix3++ = xv0;
}
}
return 0;
}
TIMER_DEVICE_CALLBACK_MEMBER(wpc_dmd_device::scanline_timer)
{
const uint8_t *src = &ram[0x200*(visible_page & 0xf) + 16*cur_scanline];
uint8_t *base = &screen_buffer[128*cur_scanline];
for(int x1=0; x1<16; x1++) {
uint8_t v = *src++;
for(int x2=0; x2<8; x2++) {
*base = (*base << 1) | ((v & (0x01 << x2)) ? 1 : 0);
base++;
}
}
cur_scanline = (cur_scanline+1) & 0x1f;
scanline_cb(cur_scanline == (firq_scanline & 0x1f));
}
WRITE8_MEMBER(wpc_dmd_device::firq_scanline_w)
{
firq_scanline = data;
}
WRITE8_MEMBER(wpc_dmd_device::bank0_w)
{
dmd0->set_entry(data & 0xf);
}
WRITE8_MEMBER(wpc_dmd_device::bank2_w)
{
dmd2->set_entry(data & 0xf);
}
WRITE8_MEMBER(wpc_dmd_device::bank4_w)
{
dmd4->set_entry(data & 0xf);
}
WRITE8_MEMBER(wpc_dmd_device::bank6_w)
{
dmd6->set_entry(data & 0xf);
}
WRITE8_MEMBER(wpc_dmd_device::bank8_w)
{
dmd8->set_entry(data & 0xf);
}
WRITE8_MEMBER(wpc_dmd_device::banka_w)
{
dmda->set_entry(data & 0xf);
}
WRITE8_MEMBER(wpc_dmd_device::visible_page_w)
{
visible_page = data;
}