added copyright line to top of source files next to license information
[cyclone68000.git] / Pico / VideoPort.cpp
1 \r
2 // This file is part of the PicoDrive Megadrive Emulator\r
3 \r
4 // Copyright (c) 2011 FinalDave (emudave (at) gmail.com)\r
5 \r
6 // This code is licensed under the GNU General Public License version 2.0 and the MAME License.\r
7 // You can choose the license that has the most advantages for you.\r
8 \r
9 // SVN repository can be found at http://code.google.com/p/cyclone68000/\r
10 \r
11 #include "PicoInt.h"\r
12 \r
13 static inline void AutoIncrement()\r
14 {\r
15   Pico.video.addr=(unsigned short)(Pico.video.addr+Pico.video.reg[0xf]);\r
16 }\r
17 \r
18 static void VideoWrite(unsigned int d)\r
19 {\r
20   unsigned int a=0;\r
21   unsigned short sd=(unsigned short)d;\r
22 \r
23   a=Pico.video.addr;\r
24   if (a&1) d=((d<<8)&0xff00)|(d>>8); // If address is odd, bytes are swapped\r
25   a>>=1;\r
26 \r
27   switch (Pico.video.type)\r
28   {\r
29     case 1: Pico.vram [a&0x7fff]=sd; break;\r
30     case 3: Pico.cram [a&0x003f]=sd; Pico.m.dirtyPal=1; break;\r
31     case 5: Pico.vsram[a&0x003f]=sd; break;\r
32   }\r
33   \r
34   AutoIncrement();\r
35 }\r
36 \r
37 static unsigned int VideoRead()\r
38 {\r
39   unsigned int a=0,d=0;\r
40 \r
41   a=Pico.video.addr; a>>=1;\r
42 \r
43   switch (Pico.video.type)\r
44   {\r
45     case 0: d=Pico.vram [a&0x7fff]; break;\r
46     case 8: d=Pico.cram [a&0x003f]; break;\r
47     case 4: d=Pico.vsram[a&0x003f]; break;\r
48   }\r
49   \r
50   AutoIncrement();\r
51   return d;\r
52 }\r
53 \r
54 static int GetDmaSource()\r
55 {\r
56   struct PicoVideo *pvid=&Pico.video;\r
57   int source=0;\r
58   source =pvid->reg[0x15]<<1;\r
59   source|=pvid->reg[0x16]<<9;\r
60   source|=pvid->reg[0x17]<<17;\r
61   return source;\r
62 }\r
63 \r
64 static int GetDmaLength()\r
65 {\r
66   struct PicoVideo *pvid=&Pico.video;\r
67   int len=0;\r
68   // 16-bit words to transfer:\r
69   len =pvid->reg[0x13];\r
70   len|=pvid->reg[0x14]<<8;\r
71   return len;\r
72 }\r
73 \r
74 static void DmaSlow(int source,int len)\r
75 {\r
76   int i=0,max=0;\r
77 \r
78   if (source>=0x800000 && source<0xe00000) return; // Invalid source address\r
79 \r
80   /// Clip Cram DMA size (Todds Adventures in Slime World):\r
81   if (Pico.video.type==3) { max=0x80-Pico.video.addr; if (len>max) len=max; }\r
82 \r
83   for (i=0;i<len;i++)\r
84   {\r
85     VideoWrite(PicoRead16(source));\r
86     source+=2;\r
87   }\r
88 }\r
89 \r
90 static void DmaCopy(int source,int len)\r
91 {\r
92   int i=0;\r
93 \r
94   len>>=1; // Length specifies number of bytes\r
95 \r
96   for (i=0;i<len;i++)\r
97   {\r
98     VideoWrite(Pico.vram[source&0x7fff]);\r
99     source+=2;\r
100   }\r
101 }\r
102 \r
103 static void DmaFill(int data)\r
104 {\r
105   int len=0,i=0;\r
106   \r
107   len=GetDmaLength();\r
108 \r
109   for (i=0;i<len+1;i++) VideoWrite(data);\r
110 }\r
111 \r
112 static void CommandDma()\r
113 {\r
114   struct PicoVideo *pvid=&Pico.video;\r
115   int len=0,method=0,source=0;\r
116 \r
117   if ((pvid->reg[1]&0x10)==0) return; // DMA not enabled\r
118 \r
119   len=GetDmaLength();\r
120 \r
121   method=pvid->reg[0x17]>>6;\r
122   source=GetDmaSource();\r
123   if (method< 2) DmaSlow(source,len); // 68000 to VDP\r
124   if (method==3) DmaCopy(source,len); // VRAM Copy\r
125 }\r
126 \r
127 static void CommandChange()\r
128 {\r
129   struct PicoVideo *pvid=&Pico.video;\r
130   unsigned int cmd=0,addr=0;\r
131 \r
132   cmd=pvid->command;\r
133 \r
134   // Get type of transfer 0xc0000030 (v/c/vsram read/write)\r
135   pvid->type=(unsigned char)(((cmd>>2)&0xc)|(cmd>>30));\r
136 \r
137   // Get address 0x3fff0003\r
138   addr =(cmd>>16)&0x3fff;\r
139   addr|=(cmd<<14)&0xc000;\r
140   pvid->addr=(unsigned short)addr;\r
141 \r
142   // Check for dma:\r
143   if (cmd&0x80) CommandDma();\r
144 }\r
145 \r
146 void PicoVideoWrite(unsigned int a,unsigned int d)\r
147 {\r
148   struct PicoVideo *pvid=&Pico.video;\r
149 \r
150   a&=0x1c;\r
151   d=(unsigned short)d;\r
152 \r
153   if (a==0x00) // Data port 0 or 2\r
154   {    \r
155     if (pvid->pending) CommandChange();\r
156     pvid->pending=0;\r
157 \r
158     // If a DMA fill has been set up, do it\r
159     if ((pvid->command&0x80) && (pvid->reg[1]&0x10) && (pvid->reg[0x17]>>6)==2)\r
160     {\r
161       DmaFill(d);\r
162     }\r
163     else\r
164     {\r
165       VideoWrite(d);\r
166     }\r
167     return;\r
168   }\r
169 \r
170   if (a==0x04) // Command port 4 or 6\r
171   {\r
172     if (pvid->pending)\r
173     {\r
174       // Low word of command:\r
175       pvid->command&=0xffff0000;\r
176       pvid->command|=d;\r
177       pvid->pending=0;\r
178       CommandChange();\r
179       return;\r
180     }\r
181 \r
182     if ((d&0xc000)==0x8000)\r
183     {\r
184       // Register write:\r
185       int num=(d>>8)&0x1f;\r
186       pvid->reg[num]=(unsigned char)d;\r
187       return;\r
188     }\r
189 \r
190     // High word of command:\r
191     pvid->command&=0x0000ffff;\r
192     pvid->command|=d<<16;\r
193     pvid->pending=1;\r
194   }\r
195 }\r
196 \r
197 unsigned int PicoVideoRead(unsigned int a)\r
198 {\r
199   unsigned int d=0;\r
200   \r
201   a&=0x1c;\r
202 \r
203   if (a==0x00) { d=VideoRead(); goto end; }\r
204 \r
205   if (a==0x04)\r
206   {\r
207     d=Pico.video.status;\r
208 \r
209     // Toggle fifo full empty:\r
210     if (Pico.m.rotate&4) d|=0x3520; else d|=0x3620;\r
211     if (Pico.m.rotate&2) d|=0x0004; // Toggle in/out of H-Blank\r
212     Pico.m.rotate++;\r
213 \r
214     if (Pico.m.pal) d|=1; // PAL screen\r
215 \r
216     goto end;\r
217   }\r
218 \r
219   if ((a&0x1c)==0x08)\r
220   {\r
221     if (Pico.m.scanline>-64) d=Pico.m.scanline; // HV-Counter\r
222     else                     d=Pico.m.rotate++; // Fudge\r
223 \r
224     d&=0xff; d<<=8;\r
225     goto end;\r
226   }\r
227 \r
228 end:\r
229 \r
230   return d;\r
231 }\r