1 // license:BSD-3-Clause
2 // copyright-holders:Olivier Galibert
3 #include "emu.h"
4 #include "wpc_dmd.h"
5 #include "screen.h"
6
7 DEFINE_DEVICE_TYPE(WPC_DMD, wpc_dmd_device, "wpc_dmd", "Williams Pinball Controller Dot Matrix Display")
8
registers(address_map & map)9 void wpc_dmd_device::registers(address_map &map)
10 {
11 map(0, 0).w(FUNC(wpc_dmd_device::bank2_w));
12 map(1, 1).w(FUNC(wpc_dmd_device::bank0_w));
13 map(2, 2).w(FUNC(wpc_dmd_device::bank6_w));
14 map(3, 3).w(FUNC(wpc_dmd_device::bank4_w));
15 map(4, 4).w(FUNC(wpc_dmd_device::banka_w));
16 map(5, 5).w(FUNC(wpc_dmd_device::firq_scanline_w));
17 map(6, 6).w(FUNC(wpc_dmd_device::bank8_w));
18 map(7, 7).w(FUNC(wpc_dmd_device::visible_page_w));
19 }
20
21
wpc_dmd_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)22 wpc_dmd_device::wpc_dmd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
23 device_t(mconfig, WPC_DMD, tag, owner, clock),
24 scanline_cb(*this),
25 dmd0(*this, ":dmd0"),
26 dmd2(*this, ":dmd2"),
27 dmd4(*this, ":dmd4"),
28 dmd6(*this, ":dmd6"),
29 dmd8(*this, ":dmd8"),
30 dmda(*this, ":dmda")
31 {
32 }
33
~wpc_dmd_device()34 wpc_dmd_device::~wpc_dmd_device()
35 {
36 }
37
device_add_mconfig(machine_config & config)38 void wpc_dmd_device::device_add_mconfig(machine_config &config)
39 {
40 screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD));
41 screen.set_refresh_hz(60);
42 screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500));
43 screen.set_screen_update(FUNC(wpc_dmd_device::screen_update));
44 screen.set_size(128*4, 32*4);
45 screen.set_visarea(0, 128*4-1, 0, 32*4-1);
46
47 TIMER(config, "scanline").configure_periodic(FUNC(wpc_dmd_device::scanline_timer), attotime::from_hz(60*4*32));
48 }
49
device_start()50 void wpc_dmd_device::device_start()
51 {
52 scanline_cb.resolve_safe();
53
54 ram.resize(0x2000);
55 screen_buffer.resize(128*32);
56 bitcounts.resize(256);
57
58 dmd0->configure_entries(0, 0x10, &ram[0], 0x200);
59 dmd2->configure_entries(0, 0x10, &ram[0], 0x200);
60 dmd4->configure_entries(0, 0x10, &ram[0], 0x200);
61 dmd6->configure_entries(0, 0x10, &ram[0], 0x200);
62 dmd8->configure_entries(0, 0x10, &ram[0], 0x200);
63 dmda->configure_entries(0, 0x10, &ram[0], 0x200);
64
65 memset(&ram[0], 0x00, 0x2000);
66
67 for(int i=0; i<256; i++) {
68 int bc = i;
69 bc = ((bc & 0xaa) >> 1) + (bc & 0x55);
70 bc = ((bc & 0xcc) >> 2) + (bc & 0x33);
71 bc = ((bc & 0xf0) >> 4) + (bc & 0x0f);
72 bitcounts[i] = bc;
73 }
74
75 save_item(NAME(visible_page));
76 save_item(NAME(cur_scanline));
77 save_item(NAME(firq_scanline));
78 save_item(NAME(ram));
79 save_item(NAME(screen_buffer));
80 save_item(NAME(bitcounts));
81 }
82
device_reset()83 void wpc_dmd_device::device_reset()
84 {
85 dmd0->set_entry(0);
86 dmd2->set_entry(1);
87 dmd4->set_entry(2);
88 dmd6->set_entry(3);
89 dmd8->set_entry(4);
90 dmda->set_entry(5);
91
92 memset(&screen_buffer[0], 0x00, 128*32);
93 visible_page = 0;
94 firq_scanline = 0;
95 cur_scanline = 0;
96 }
97
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)98 uint32_t wpc_dmd_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
99 {
100 const uint8_t *src = &screen_buffer[0];
101 for(int y=0; y<32; y++) {
102 uint32_t *pix0 = reinterpret_cast<uint32_t *>(bitmap.raw_pixptr(y*4));
103 uint32_t *pix1 = reinterpret_cast<uint32_t *>(bitmap.raw_pixptr(y*4+1));
104 uint32_t *pix2 = reinterpret_cast<uint32_t *>(bitmap.raw_pixptr(y*4+2));
105 uint32_t *pix3 = reinterpret_cast<uint32_t *>(bitmap.raw_pixptr(y*4+3));
106 for(int x=0; x<128; x++) {
107 uint8_t v = bitcounts[*src++ & 0x3f];
108 uint8_t v0 = v < 2 ? 0 : v-2;
109 uint8_t v1 = v < 1 ? 0 : v-1;
110 uint8_t v2 = v > 5 ? 5 : v;
111 v0 = 255*v0/5;
112 v1 = 255*v1/5;
113 v2 = 255*v2/5;
114
115 uint32_t xv0 = (v0 << 16) | (v0 << 8);
116 uint32_t xv1 = (v1 << 16) | (v1 << 8);
117 uint32_t xv2 = (v2 << 16) | (v2 << 8);
118 *pix0++ = xv0;
119 *pix0++ = xv1;
120 *pix0++ = xv1;
121 *pix0++ = xv0;
122
123 *pix1++ = xv1;
124 *pix1++ = xv2;
125 *pix1++ = xv2;
126 *pix1++ = xv1;
127
128 *pix2++ = xv1;
129 *pix2++ = xv2;
130 *pix2++ = xv2;
131 *pix2++ = xv1;
132
133 *pix3++ = xv0;
134 *pix3++ = xv1;
135 *pix3++ = xv1;
136 *pix3++ = xv0;
137 }
138 }
139 return 0;
140 }
141
142
TIMER_DEVICE_CALLBACK_MEMBER(wpc_dmd_device::scanline_timer)143 TIMER_DEVICE_CALLBACK_MEMBER(wpc_dmd_device::scanline_timer)
144 {
145 const uint8_t *src = &ram[0x200*(visible_page & 0xf) + 16*cur_scanline];
146 uint8_t *base = &screen_buffer[128*cur_scanline];
147
148 for(int x1=0; x1<16; x1++) {
149 uint8_t v = *src++;
150 for(int x2=0; x2<8; x2++) {
151 *base = (*base << 1) | ((v & (0x01 << x2)) ? 1 : 0);
152 base++;
153 }
154 }
155
156 cur_scanline = (cur_scanline+1) & 0x1f;
157 scanline_cb(cur_scanline == (firq_scanline & 0x1f));
158 }
159
firq_scanline_w(uint8_t data)160 void wpc_dmd_device::firq_scanline_w(uint8_t data)
161 {
162 firq_scanline = data;
163 }
164
bank0_w(uint8_t data)165 void wpc_dmd_device::bank0_w(uint8_t data)
166 {
167 dmd0->set_entry(data & 0xf);
168 }
169
bank2_w(uint8_t data)170 void wpc_dmd_device::bank2_w(uint8_t data)
171 {
172 dmd2->set_entry(data & 0xf);
173 }
174
bank4_w(uint8_t data)175 void wpc_dmd_device::bank4_w(uint8_t data)
176 {
177 dmd4->set_entry(data & 0xf);
178 }
179
bank6_w(uint8_t data)180 void wpc_dmd_device::bank6_w(uint8_t data)
181 {
182 dmd6->set_entry(data & 0xf);
183 }
184
bank8_w(uint8_t data)185 void wpc_dmd_device::bank8_w(uint8_t data)
186 {
187 dmd8->set_entry(data & 0xf);
188 }
189
banka_w(uint8_t data)190 void wpc_dmd_device::banka_w(uint8_t data)
191 {
192 dmda->set_entry(data & 0xf);
193 }
194
visible_page_w(uint8_t data)195 void wpc_dmd_device::visible_page_w(uint8_t data)
196 {
197 visible_page = data;
198 }
199