1 /**
2  * @file
3  * DGen v1.13+
4  * Megadrive's VDP C++ module
5  *
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  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <limits.h>
15 #include "md.h"
16 
17 /** Reset the VDP. */
reset()18 void md_vdp::reset()
19 {
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;
39 }
40 
41 /**
42  * VDP constructor.
43  *
44  * @param md The md instance this VDP belongs to.
45  */
md_vdp(md & md)46 md_vdp::md_vdp(md& md): belongs(md)
47 {
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();
55 }
56 
57 /**
58  * VDP destructor.
59  */
~md_vdp()60 md_vdp::~md_vdp()
61 {
62 	vram = cram = vsram = NULL;
63 }
64 
65 /** Calculate the DMA length. */
dma_len()66 int md_vdp::dma_len()
67 { return (reg[0x14]<<8)+reg[0x13]; }
68 
69 /** Calculate DMA start address. */
dma_addr()70 int md_vdp::dma_addr()
71 {
72   int addr=0;
73   addr=(reg[0x17]&0x7f)<<17;
74   addr+=reg[0x16]<<9;
75   addr+=reg[0x15]<<1;
76   return addr;
77 }
78 
79 
80 /**
81  * Do a DMA read.
82  * DMA can read from anywhere.
83  *
84  * @param addr Address where to read from.
85  * @return Byte read at "addr".
86  */
dma_mem_read(int addr)87 unsigned char md_vdp::dma_mem_read(int addr)
88 {
89   return belongs.misc_readbyte(addr);
90 }
91 
92 /**
93  * Set value in VRAM.
94  * Must go through these calls to update the dirty flags.
95  *
96  * @param addr Address to write to.
97  * @param d Byte to write.
98  * @return Always 0.
99  */
poke_vram(int addr,unsigned char d)100 int md_vdp::poke_vram(int addr,unsigned char d)
101 {
102   addr&=0xffff;
103   if (vram[addr]!=d)
104   {
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;
110   }
111   return 0;
112 }
113 
114 /**
115  * Set value in CRAM.
116  *
117  * @param addr Address to write to.
118  * @param d Byte to write.
119  * @return Always 0.
120  */
poke_cram(int addr,unsigned char d)121 int md_vdp::poke_cram(int addr,unsigned char d)
122 {
123   addr&=0x007f;
124   if (cram[addr]!=d)
125   {
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;
131   }
132 
133   return 0;
134 }
135 
136 /**
137  * Set value in VSRAM.
138  *
139  * @param addr Address to write to.
140  * @param d Byte to write.
141  * @return Always 0.
142  */
poke_vsram(int addr,unsigned char d)143 int md_vdp::poke_vsram(int addr,unsigned char d)
144 {
145 //  int diff=0;
146   addr&=0x007f;
147   if (vsram[addr]!=d)
148   { dirt[0x34]|=4; vsram[addr]=d; }
149   return 0;
150 }
151 
152 /**
153  * Write a word to memory and update dirty flags.
154  *
155  * @param d 16-bit data to write.
156  * @return Always 0.
157  */
putword(unsigned short d)158 int md_vdp::putword(unsigned short d)
159 {
160   // Called by dma or a straight write
161   switch(rw_mode)
162   {
163 	case 0x04:
164 		if (rw_addr & 0x0001) {
165 			poke_vram((rw_addr + 0), (d & 0xff));
166 			poke_vram((rw_addr + 1), (d >> 8));
167 		}
168 		else {
169 			poke_vram((rw_addr + 0), (d >> 8));
170 			poke_vram((rw_addr + 1), (d & 0xff));
171 		}
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;
181   }
182   rw_addr+=reg[15];
183   return 0;
184 }
185 
186 /**
187  * Write a byte to memory and update dirty flags.
188  *
189  * @param d 8-bit data to write.
190  * @return Always 0.
191  */
putbyte(unsigned char d)192 int md_vdp::putbyte(unsigned char d)
193 {
194   // Called by dma or a straight write
195   switch(rw_mode)
196   {
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;
200   }
201   rw_addr+=reg[15];
202   return 0;
203 }
204 
205 #undef MAYCHANGE
206 
207 /**
208  * Read a word from memory.
209  *
210  * @return Read word.
211  */
readword()212 unsigned short md_vdp::readword()
213 {
214   // Called by a straight read only
215   unsigned short result=0x0000;
216   switch(rw_mode)
217   {
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;
224   }
225   rw_addr+=reg[15];
226   return result;
227 }
228 
229 /**
230  * Read a byte from memory.
231  *
232  * @return Read byte.
233  */
readbyte()234 unsigned char md_vdp::readbyte()
235 {
236   // Called by a straight read only
237   unsigned char result=0x00;
238   switch(rw_mode)
239   {
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;
243   }
244   rw_addr+=reg[15];
245   return result;
246 }
247 
248 /**
249  * VDP commands
250  *
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.
254  *
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)
259  *
260  * Where CD* indicates which ram is read or written in subsequent
261  * data port read/writes. A* is an address.
262  *
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.
266  *
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.
270  *
271  * In these cases the pending flag is cleared, and the first half of
272  * the command remains comitted.
273  *
274  * @return Always 0.
275  */
command(uint16_t cmd)276 int md_vdp::command(uint16_t cmd)
277 {
278   if (cmd_pending) // If this is the second word of a command
279   {
280     uint16_t A14_15 = (cmd & 0x0003) << 14;
281     rw_addr = (rw_addr & 0xffff3fff) | A14_15;
282 
283     // Copy rw_addr to mirror register
284     rw_addr = (rw_addr & 0x0000ffff) | (rw_addr << 16);
285 
286     // CD{4,3,2}
287     uint16_t CD4_2 = (cmd & 0x0070);
288     rw_mode |= CD4_2;
289 
290     // if CD5 == 1
291     rw_dma = ((cmd & 0x80) == 0x80);
292 
293     cmd_pending = false;
294   }
295   else // This is the first word of a command
296   {
297     // masking away command bits CD1 CD0
298     uint16_t A00_13 = cmd & 0x3fff;
299     rw_addr = (rw_addr & 0xffffc000) | A00_13;
300 
301     // Copy rw_addr to mirror register
302     rw_addr = (rw_addr & 0x0000ffff) | (rw_addr << 16);
303 
304     // CD {1,0}
305     uint16_t CD0_1 = (cmd & 0xc000) >> 12;
306     rw_mode = CD0_1;
307     rw_dma = 0;
308 
309     // we will expect the second half of the command next
310     cmd_pending = true;
311 
312     return 0;
313   }
314 
315   // if it's a dma request do it straight away
316   if (rw_dma)
317   {
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)
323     {
324       case 0: case 1:
325         for (i=0;i<len;i++)
326         {
327           unsigned short val;
328           val= dma_mem_read(s++); val<<=8;
329           val|=dma_mem_read(s++); putword(val);
330         }
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++)
337         {
338           unsigned short val;
339           val= vram[(s++)&0xffff]; val<<=8;
340           val|=vram[(s++)&0xffff]; putword(val);
341         }
342       break;
343     }
344   }
345 
346   return 0;
347 }
348 
349 /**
350  * Write a word to the VDP.
351  *
352  * @param d 16-bit data to write.
353  * @return Always 0.
354  */
writeword(unsigned short d)355 int md_vdp::writeword(unsigned short d)
356 {
357   if (rw_dma)
358   {
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)
362     {
363       int i,len;
364       len=dma_len();
365       for (i=0;i<len;i++)
366         putword(d);
367       return 0;
368     }
369   }
370   else
371   {
372     putword(d);
373     return 0;
374   }
375   return 0;
376 }
377 
378 /**
379  * Write a byte to the VDP.
380  *
381  * @param d 8-bit data to write.
382  * @return Always 0.
383  */
writebyte(unsigned char d)384 int md_vdp::writebyte(unsigned char d)
385 {
386   if (rw_dma)
387   {
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)
391     {
392       int i,len;
393       len=dma_len();
394       for (i=0;i<len;i++)
395         putbyte(d);
396       return 0;
397     }
398   }
399   else
400   {
401     putbyte(d);
402     return 0;
403   }
404 
405   return 0;
406 }
407 
408 /**
409  * Write away a VDP register.
410  *
411  * @param addr Address of register.
412  * @param data 8-bit data to write.
413  */
write_reg(uint8_t addr,uint8_t data)414 void md_vdp::write_reg(uint8_t addr, uint8_t data)
415 {
416 	uint8_t byt, bit;
417 
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;
426 	}
427 	reg[addr] = data;
428 	// "Writing to a VDP register will clear the code register."
429 	rw_mode = 0;
430 }
431