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