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