1 // license:BSD-3-Clause
2 // copyright-holders:David Haywood
3
4 /*
5
6 todo: sometimes sprites get left onscreen (xain)
7
8 */
9 #include "emu.h"
10 #include "cedar_magnet_sprite.h"
11
12
13 DEFINE_DEVICE_TYPE(CEDAR_MAGNET_SPRITE, cedar_magnet_sprite_device, "cedmag_sprite", "Cedar Sprite")
14
15
cedar_magnet_sprite_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)16 cedar_magnet_sprite_device::cedar_magnet_sprite_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
17 : device_t(mconfig, CEDAR_MAGNET_SPRITE, tag, owner, clock)
18 , cedar_magnet_board_interface(mconfig, *this, "spritecpu", "ram")
19 , m_sprite_ram_bankdev(*this, "sp_sub_ram")
20 , m_pio(*this, "z80pio%u", 0U)
21 {
22 }
23
cedar_magnet_sprite_sub_ram_map(address_map & map)24 void cedar_magnet_sprite_device::cedar_magnet_sprite_sub_ram_map(address_map &map)
25 {
26 // these are 8x SIEMENS HYB 41256-15 AA - 262,144 bit DRAM (32kbytes)
27 // these are on the sprite board memory sub-board
28 map(0x00000, 0x3ffff).ram().share("ram");
29 }
30
exzisus_hack_r(offs_t offset)31 u8 cedar_magnet_sprite_device::exzisus_hack_r(offs_t offset)
32 {
33 //printf("exzisus_hack_r\n");
34 int pc = m_cpu->pc();
35
36 // exzisus has startup code outside of the first 0x400 bytes
37 // but the main cpu only transfers 0x400 bytes of the code to the other banks?!
38 if ((pc >= 0x3e0) && (pc <= 0x800))
39 {
40 return m_ram[0x400 + offset];
41 }
42 else
43 {
44 return m_ram[0x400 + offset + (m_pio2_pb_data & 0x3) * 0x10000];
45 }
46
47 }
48
49
cedar_magnet_sprite_map(address_map & map)50 void cedar_magnet_sprite_device::cedar_magnet_sprite_map(address_map &map)
51 {
52 map(0x00000, 0x0ffff).m("sp_sub_ram", FUNC(address_map_bank_device::amap8));
53
54 map(0x00400, 0x007ff).r(FUNC(cedar_magnet_sprite_device::exzisus_hack_r));
55 }
56
cedar_magnet_sprite_io(address_map & map)57 void cedar_magnet_sprite_device::cedar_magnet_sprite_io(address_map &map)
58 {
59 map.global_mask(0xff);
60
61 map(0xc0, 0xc3).rw("z80pio0", FUNC(z80pio_device::read_alt), FUNC(z80pio_device::write_alt));
62 map(0xc4, 0xc7).rw("z80pio1", FUNC(z80pio_device::read_alt), FUNC(z80pio_device::write_alt));
63 map(0xc8, 0xcb).rw("z80pio2", FUNC(z80pio_device::read_alt), FUNC(z80pio_device::write_alt));
64
65 map(0x80, 0x80).w(FUNC(cedar_magnet_sprite_device::sprite_port80_w));
66 map(0x84, 0x84).w(FUNC(cedar_magnet_sprite_device::sprite_port84_w));
67
68 map(0x88, 0x88).w(FUNC(cedar_magnet_sprite_device::sprite_port88_w)); // increasing values // upper address?
69
70 map(0x8c, 0x8c).w(FUNC(cedar_magnet_sprite_device::sprite_port8c_w)); // written after 88 (possible data upload?)
71
72 map(0x9c, 0x9c).w(FUNC(cedar_magnet_sprite_device::sprite_port9c_w)); // ?
73
74 }
75
do_blit()76 void cedar_magnet_sprite_device::do_blit()
77 {
78 // printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
79 // printf("~~~~~~~~~~~~~~~~~ drawing sprite with x:%02x y:%02x code:%04x size:%02x unk:%02x\n", m_loweraddr, m_upperaddr, (m_spritecodehigh << 8) | m_spritecodelow, m_spritesize, m_pio0_pb_data);
80 // printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
81
82 int ysize = 0;
83 int xsize = 0;
84 int erase = 0;
85
86 // bit 0x80 is always set
87 if ((m_spritesize & 0x7f) == 0x00)
88 ysize = xsize = 8;
89
90 if ((m_spritesize & 0x7f) == 0x01)
91 ysize = xsize = 16;
92
93 if ((m_spritesize & 0x7f) == 0x02)
94 ysize = xsize = 32;
95
96 if ((m_spritesize & 0x7f) == 0x03)
97 ysize = xsize = 64;
98
99 // m_spritesize
100 // m_pio0_pb_data
101
102 int source = (m_spritecodehigh << 8) | m_spritecodelow;
103
104 if (source == 0)
105 erase = 1;
106
107 source &= ~0x3f;
108
109 for (int y = 0; y < ysize; y++)
110 {
111 for (int x = 0; x < xsize; x++)
112 {
113 int xpos = (m_loweraddr + x);
114 int ypos = (m_upperaddr + y);
115
116 u8 data = m_ram[source + ((m_uppersprite & 0x3) * 0x10000)];
117
118 if (!(m_pio0_pb_data & 0x02))
119 data = machine().rand();
120
121 source++;
122
123 xpos &= 0xff;
124
125 // without this some sprites incorrectly wraparound on the volcano table.
126 if (!erase)
127 {
128 if (!(m_pio0_pb_data & 0x40))
129 {
130 if (xpos >= 0xff-64)
131 continue;
132 }
133 else
134 {
135 if (xpos < 64)
136 continue;
137 }
138 }
139
140 //if ((ypos >= 0) && (ypos < 0x100))
141 ypos &= 0xff;
142
143 {
144 int offset = (ypos * 256) + xpos;
145
146 if (erase == 1)
147 {
148 m_framebuffer[offset] = 0;
149 }
150 else
151 {
152 if (data) m_framebuffer[offset] = data;
153 }
154 }
155 }
156 }
157 }
158
sprite_port80_w(u8 data)159 void cedar_magnet_sprite_device::sprite_port80_w(u8 data)
160 {
161 m_spritecodelow = data;
162 // printf("%s:sprite numlow / trigger %02x\n", machine().describe_context().c_str(), data);
163
164 do_blit();
165 }
166
sprite_port84_w(u8 data)167 void cedar_magnet_sprite_device::sprite_port84_w(u8 data)
168 {
169 m_spritecodehigh = data;
170 m_high_write = 1;
171 // printf("%s:sprite numhigh %02x\n", machine().describe_context().c_str(), data);
172 }
173
sprite_port88_w(u8 data)174 void cedar_magnet_sprite_device::sprite_port88_w(u8 data)
175 {
176 // frequent
177 // printf("%s:sprite_y_coordinate %02x\n", machine().describe_context().c_str(), data);
178 m_upperaddr = data;
179 }
180
pio2_pa_w(u8 data)181 void cedar_magnet_sprite_device::pio2_pa_w(u8 data)
182 {
183 // frequent
184 // printf("%s:sprite_x_coordinate %02x\n", machine().describe_context().c_str(), data);
185 m_loweraddr = data;
186 }
187
sprite_port8c_w(u8 data)188 void cedar_magnet_sprite_device::sprite_port8c_w(u8 data)
189 {
190 int address = (m_upperaddr << 8) | m_loweraddr;
191 m_framebuffer[address] = data;
192 if (data!=0x00) printf("sprite_port8c_w write %04x %02x\n", address, data);
193 }
194
195 // possible watchdog?
sprite_port9c_w(u8 data)196 void cedar_magnet_sprite_device::sprite_port9c_w(u8 data)
197 {
198 // printf("%s:sprite_port9c_w %02x\n", machine().describe_context().c_str(), data);
199 }
200
device_add_mconfig(machine_config & config)201 void cedar_magnet_sprite_device::device_add_mconfig(machine_config &config)
202 {
203 z80_device &spritecpu(Z80(config, "spritecpu", 4000000));
204 spritecpu.set_addrmap(AS_PROGRAM, &cedar_magnet_sprite_device::cedar_magnet_sprite_map);
205 spritecpu.set_addrmap(AS_IO, &cedar_magnet_sprite_device::cedar_magnet_sprite_io);
206
207 Z80PIO(config, m_pio[0], 4000000/2);
208 // m_pio[0]->out_int_callback().set_inputline("maincpu", INPUT_LINE_IRQ0);
209 m_pio[0]->in_pa_callback().set(FUNC(cedar_magnet_sprite_device::pio0_pa_r));
210 m_pio[0]->out_pa_callback().set(FUNC(cedar_magnet_sprite_device::pio0_pa_w));
211 // m_pio[0]->in_pb_callback().set(FUNC(cedar_magnet_sprite_device::pio0_pb_r));
212 m_pio[0]->out_pb_callback().set(FUNC(cedar_magnet_sprite_device::pio0_pb_w));
213
214 Z80PIO(config, m_pio[1], 4000000/2);
215 // m_pio[1]->out_int_callback().set_inputline("maincpu", INPUT_LINE_IRQ0);
216 // m_pio[1]->in_pa_callback().set(FUNC(cedar_magnet_sprite_device::pio1_pa_r));
217 m_pio[1]->out_pa_callback().set(FUNC(cedar_magnet_sprite_device::pio1_pa_w));
218 // m_pio[1]->in_pb_callback().set(FUNC(cedar_magnet_sprite_device::pio1_pb_r));
219 m_pio[1]->out_pb_callback().set(FUNC(cedar_magnet_sprite_device::pio1_pb_w));
220
221 Z80PIO(config, m_pio[2], 4000000/2);
222 // m_pio[2]->out_int_callback().set_inputline("maincpu", INPUT_LINE_IRQ0);
223 // m_pio[2]->in_pa_callback().set(FUNC(cedar_magnet_sprite_device::pio2_pa_r));
224 m_pio[2]->out_pa_callback().set(FUNC(cedar_magnet_sprite_device::pio2_pa_w));
225 // m_pio[2]->in_pb_callback().set(FUNC(cedar_magnet_sprite_device::pio2_pb_r));
226 m_pio[2]->out_pb_callback().set(FUNC(cedar_magnet_sprite_device::pio2_pb_w));
227
228
229 ADDRESS_MAP_BANK(config, m_sprite_ram_bankdev).set_map(&cedar_magnet_sprite_device::cedar_magnet_sprite_sub_ram_map).set_options(ENDIANNESS_LITTLE, 8, 18, 0x10000);
230 }
231
232
pio0_pa_r()233 u8 cedar_magnet_sprite_device::pio0_pa_r()
234 {
235 // actually read
236 // printf("%s: pio0_pa_r\n", machine().describe_context().c_str());
237 return 0x00;
238 }
239
240
pio0_pa_w(u8 data)241 void cedar_magnet_sprite_device::pio0_pa_w(u8 data)
242 {
243 m_spritesize = data;
244 }
245
pio0_pb_w(u8 data)246 void cedar_magnet_sprite_device::pio0_pb_w(u8 data)
247 {
248 m_pio0_pb_data = data;
249 //printf("%s: pio0_pb_w %02x\n", machine().describe_context().c_str(), data);
250 }
251
pio1_pa_w(u8 data)252 void cedar_magnet_sprite_device::pio1_pa_w(u8 data)
253 {
254 //printf("%s: pio1_pa_w %02x\n", machine().describe_context().c_str(), data);
255 }
256
pio1_pb_w(u8 data)257 void cedar_magnet_sprite_device::pio1_pb_w(u8 data)
258 {
259 //printf("%s: pio1_pb_w %02x\n", machine().describe_context().c_str(), data);
260 }
261
262
pio2_pb_w(u8 data)263 void cedar_magnet_sprite_device::pio2_pb_w(u8 data)
264 {
265 // this feels like a hack
266 // the game writes here when creating the sprite list so that it can access the correct gfd data
267 // however the actual LIST data is always in bank 0 (it can't be in any other bank, those areas are occupied by actual gfx)
268 if (m_high_write)
269 {
270 m_uppersprite = data & 0x03;
271 m_high_write = 0;
272 return;
273
274 }
275
276 m_pio2_pb_data = data;
277 //printf("%s: ******************************************* BANK? **** pio2_pb_w %02x\n", machine().describe_context().c_str(), data);
278 // yes, it ends up banking the ram right out from under itself during startup execution...
279 // during this time the main cpu is waiting in a loop, after which it copies the startup code again, and reboots it.
280 m_sprite_ram_bankdev->set_bank(data & 0x03);
281 }
282
283
device_start()284 void cedar_magnet_sprite_device::device_start()
285 {
286 m_framebuffer = make_unique_clear<u8[]>(0x10000);
287 save_pointer(NAME(m_framebuffer), 0x10000);
288 }
289
290
device_reset()291 void cedar_magnet_sprite_device::device_reset()
292 {
293 halt_assert();
294 m_sprite_ram_bankdev->set_bank(0);
295 m_pio2_pb_data = 0x00;
296 m_spritesize = 0xff;
297 }
298
draw(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect,int palbase)299 u32 cedar_magnet_sprite_device::draw(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int palbase)
300 {
301 // printf("-----------------------------------------------------------------------------------------------------------\n");
302 // printf("--------------------------------------------- FRAME -------------------------------------------------------\n");
303 // printf("-----------------------------------------------------------------------------------------------------------\n");
304
305 int count = 0;
306
307 // if (!(m_m_spritesize & 0x40))
308 // return 0;
309
310 for (int y = 0; y < 256; y++)
311 {
312 uint16_t *const dst = &bitmap.pix((y) & 0xff);
313
314 for (int x = 0; x < 256; x++)
315 {
316 u8 pix = m_framebuffer[count];
317 count++;
318
319 if (pix) dst[(x) & 0xff] = pix + palbase * 0x100;
320 }
321 }
322
323 return 0;
324 }
325