15eb0001 |
1 | \r |
4abeeb4b |
2 | // This file is part of the PicoDrive Megadrive Emulator\r |
3 | \r |
c41b9b97 |
4 | // Copyright (c) 2011 FinalDave (emudave (at) gmail.com)\r |
5 | \r |
4abeeb4b |
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 |
15eb0001 |
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 |