Add VCS links
[debian-dgen.git] / vdp.cpp
blobf29ba154ebccc1b903b3d78fb6a1af24ba14a95f
1 /**
2 * @file
3 * DGen v1.13+
4 * Megadrive's VDP C++ module
6 * A useful resource for the Genesis VDP:
7 * http://cgfm2.emuviews.com/txt/genvdp.txt
8 * Thanks to Charles MacDonald for writing these docs.
9 */
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <limits.h>
15 #include "md.h"
17 /** Reset the VDP. */
18 void md_vdp::reset()
20 hint_pending = false;
21 vint_pending = false;
22 cmd_pending = false;
23 rw_mode = 0x00;
24 rw_addr = 0;
25 rw_dma = 0;
26 memset(mem, 0, sizeof(mem));
27 memset(reg, 0, 0x20);
28 memset(dirt, 0xff, 0x35); // mark everything as changed
29 memset(highpal, 0, sizeof(highpal));
30 memset(sprite_order, 0, sizeof(sprite_order));
31 memset(sprite_mask, 0xff, sizeof(sprite_mask));
32 sprite_base = NULL;
33 sprite_count = 0;
34 masking_sprite_index_cache = -1;
35 dots_cache = 0;
36 sprite_overflow_line = INT_MIN;
37 dest = NULL;
38 bmap = NULL;
41 /**
42 * VDP constructor.
44 * @param md The md instance this VDP belongs to.
46 md_vdp::md_vdp(md& md): belongs(md)
48 vram = (mem + 0x00000);
49 cram = (mem + 0x10000);
50 vsram = (mem + 0x10080);
51 dirt = (mem + 0x10100); // VRAM/CRAM/Reg dirty buffer bitfield
52 // Also in 0x34 are global dirt flags (inclduing VSRAM this time)
53 Bpp = Bpp_times8 = 0;
54 reset();
57 /**
58 * VDP destructor.
60 md_vdp::~md_vdp()
62 vram = cram = vsram = NULL;
65 /** Calculate the DMA length. */
66 int md_vdp::dma_len()
67 { return (reg[0x14]<<8)+reg[0x13]; }
69 /** Calculate DMA start address. */
70 int md_vdp::dma_addr()
72 int addr=0;
73 addr=(reg[0x17]&0x7f)<<17;
74 addr+=reg[0x16]<<9;
75 addr+=reg[0x15]<<1;
76 return addr;
80 /**
81 * Do a DMA read.
82 * DMA can read from anywhere.
84 * @param addr Address where to read from.
85 * @return Byte read at "addr".
87 unsigned char md_vdp::dma_mem_read(int addr)
89 return belongs.misc_readbyte(addr);
92 /**
93 * Set value in VRAM.
94 * Must go through these calls to update the dirty flags.
96 * @param addr Address to write to.
97 * @param d Byte to write.
98 * @return Always 0.
100 int md_vdp::poke_vram(int addr,unsigned char d)
102 addr&=0xffff;
103 if (vram[addr]!=d)
105 // Store dirty information down to 256 byte level in bits
106 int byt,bit;
107 byt=addr>>8; bit=byt&7; byt>>=3; byt&=0x1f;
108 dirt[0x00+byt]|=(1<<bit); dirt[0x34]|=1;
109 vram[addr]=d;
111 return 0;
115 * Set value in CRAM.
117 * @param addr Address to write to.
118 * @param d Byte to write.
119 * @return Always 0.
121 int md_vdp::poke_cram(int addr,unsigned char d)
123 addr&=0x007f;
124 if (cram[addr]!=d)
126 // Store dirty information down to 1byte level in bits
127 int byt,bit;
128 byt=addr; bit=byt&7; byt>>=3; byt&=0x0f;
129 dirt[0x20+byt]|=(1<<bit); dirt[0x34]|=2;
130 cram[addr]=d;
133 return 0;
137 * Set value in VSRAM.
139 * @param addr Address to write to.
140 * @param d Byte to write.
141 * @return Always 0.
143 int md_vdp::poke_vsram(int addr,unsigned char d)
145 // int diff=0;
146 addr&=0x007f;
147 if (vsram[addr]!=d)
148 { dirt[0x34]|=4; vsram[addr]=d; }
149 return 0;
153 * Write a word to memory and update dirty flags.
155 * @param d 16-bit data to write.
156 * @return Always 0.
158 int md_vdp::putword(unsigned short d)
160 // Called by dma or a straight write
161 switch(rw_mode)
163 case 0x04:
164 if (rw_addr & 0x0001) {
165 poke_vram((rw_addr + 0), (d & 0xff));
166 poke_vram((rw_addr + 1), (d >> 8));
168 else {
169 poke_vram((rw_addr + 0), (d >> 8));
170 poke_vram((rw_addr + 1), (d & 0xff));
172 break;
173 case 0x0c:
174 poke_cram((rw_addr + 0), (d >> 8));
175 poke_cram((rw_addr + 1), (d & 0xff));
176 break;
177 case 0x14:
178 poke_vsram((rw_addr + 0), (d >> 8));
179 poke_vsram((rw_addr + 1), (d & 0xff));
180 break;
182 rw_addr+=reg[15];
183 return 0;
187 * Write a byte to memory and update dirty flags.
189 * @param d 8-bit data to write.
190 * @return Always 0.
192 int md_vdp::putbyte(unsigned char d)
194 // Called by dma or a straight write
195 switch(rw_mode)
197 case 0x04: poke_vram (rw_addr,d); break;
198 case 0x0c: poke_cram (rw_addr,d); break;
199 case 0x14: poke_vsram(rw_addr,d); break;
201 rw_addr+=reg[15];
202 return 0;
205 #undef MAYCHANGE
208 * Read a word from memory.
210 * @return Read word.
212 unsigned short md_vdp::readword()
214 // Called by a straight read only
215 unsigned short result=0x0000;
216 switch(rw_mode)
218 case 0x00: result=( vram[(rw_addr+0)&0xffff]<<8)+
219 vram[(rw_addr+1)&0xffff]; break;
220 case 0x20: result=( cram[(rw_addr+0)&0x007f]<<8)+
221 cram[(rw_addr+1)&0x007f]; break;
222 case 0x10: result=(vsram[(rw_addr+0)&0x007f]<<8)+
223 vsram[(rw_addr+1)&0x007f]; break;
225 rw_addr+=reg[15];
226 return result;
230 * Read a byte from memory.
232 * @return Read byte.
234 unsigned char md_vdp::readbyte()
236 // Called by a straight read only
237 unsigned char result=0x00;
238 switch(rw_mode)
240 case 0x00: result= vram[(rw_addr+0)&0xffff]; break;
241 case 0x20: result= cram[(rw_addr+0)&0x007f]; break;
242 case 0x10: result=vsram[(rw_addr+0)&0x007f]; break;
244 rw_addr+=reg[15];
245 return result;
249 * VDP commands
251 * A VDP command is 32-bits in length written into the control port
252 * as two 16-bit words. The VDP maintains a pending flag so that it knows
253 * what to expect next.
255 * CD1 CD0 A13 A12 A11 A10 A09 A08 (D31-D24)
256 * A07 A06 A05 A04 A03 A02 A01 A00 (D23-D16)
257 * ? ? ? ? ? ? ? ? (D15-D8)
258 * CD5 CD4 CD3 CD2 ? ? A15 A14 (D7-D0)
260 * Where CD* indicates which ram is read or written in subsequent
261 * data port read/writes. A* is an address.
263 * Note that the command is not cached, but rather, the lower 14 address bits
264 * are commited as soon as the first half of the command arrives. Then when
265 * the second word arrives, the remaining two address bits are commited.
267 * It is possible to cancel (but not roll back) a pending command by:
268 * - reading or writing to the data port.
269 * - reading the control port.
271 * In these cases the pending flag is cleared, and the first half of
272 * the command remains comitted.
274 * @return Always 0.
276 int md_vdp::command(uint16_t cmd)
278 if (cmd_pending) // If this is the second word of a command
280 uint16_t A14_15 = (cmd & 0x0003) << 14;
281 rw_addr = (rw_addr & 0xffff3fff) | A14_15;
283 // Copy rw_addr to mirror register
284 rw_addr = (rw_addr & 0x0000ffff) | (rw_addr << 16);
286 // CD{4,3,2}
287 uint16_t CD4_2 = (cmd & 0x0070);
288 rw_mode |= CD4_2;
290 // if CD5 == 1
291 rw_dma = ((cmd & 0x80) == 0x80);
293 cmd_pending = false;
295 else // This is the first word of a command
297 // masking away command bits CD1 CD0
298 uint16_t A00_13 = cmd & 0x3fff;
299 rw_addr = (rw_addr & 0xffffc000) | A00_13;
301 // Copy rw_addr to mirror register
302 rw_addr = (rw_addr & 0x0000ffff) | (rw_addr << 16);
304 // CD {1,0}
305 uint16_t CD0_1 = (cmd & 0xc000) >> 12;
306 rw_mode = CD0_1;
307 rw_dma = 0;
309 // we will expect the second half of the command next
310 cmd_pending = true;
312 return 0;
315 // if it's a dma request do it straight away
316 if (rw_dma)
318 int mode=(reg[0x17]>>6)&3;
319 int s=0,d=0,i=0,len=0;
320 s=dma_addr(); d=rw_addr; len=dma_len();
321 (void)d;
322 switch (mode)
324 case 0: case 1:
325 for (i=0;i<len;i++)
327 unsigned short val;
328 val= dma_mem_read(s++); val<<=8;
329 val|=dma_mem_read(s++); putword(val);
331 break;
332 case 2:
333 // Done later on (VRAM fill I believe)
334 break;
335 case 3:
336 for (i=0;i<len;i++)
338 unsigned short val;
339 val= vram[(s++)&0xffff]; val<<=8;
340 val|=vram[(s++)&0xffff]; putword(val);
342 break;
346 return 0;
350 * Write a word to the VDP.
352 * @param d 16-bit data to write.
353 * @return Always 0.
355 int md_vdp::writeword(unsigned short d)
357 if (rw_dma)
359 // This is the 'done later on' bit for words
360 // Do a dma fill if it's set up:
361 if (((reg[0x17]>>6)&3)==2)
363 int i,len;
364 len=dma_len();
365 for (i=0;i<len;i++)
366 putword(d);
367 return 0;
370 else
372 putword(d);
373 return 0;
375 return 0;
379 * Write a byte to the VDP.
381 * @param d 8-bit data to write.
382 * @return Always 0.
384 int md_vdp::writebyte(unsigned char d)
386 if (rw_dma)
388 // This is the 'done later on' bit for bytes
389 // Do a dma fill if it's set up:
390 if (((reg[0x17]>>6)&3)==2)
392 int i,len;
393 len=dma_len();
394 for (i=0;i<len;i++)
395 putbyte(d);
396 return 0;
399 else
401 putbyte(d);
402 return 0;
405 return 0;
409 * Write away a VDP register.
411 * @param addr Address of register.
412 * @param data 8-bit data to write.
414 void md_vdp::write_reg(uint8_t addr, uint8_t data)
416 uint8_t byt, bit;
418 // store dirty information down to 1 byte level in bits
419 if (reg[addr] != data) {
420 byt = addr;
421 bit = (byt & 7);
422 byt >>= 3;
423 byt &= 0x03;
424 dirt[(0x30 + byt)] |= (1 << bit);
425 dirt[0x34] |= 8;
427 reg[addr] = data;
428 // "Writing to a VDP register will clear the code register."
429 rw_mode = 0;