15eb0001 |
1 | \r |
4abeeb4b |
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 |
15eb0001 |
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 |