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