Added 0.030 of PicoDrive and moved license files into root
[cyclone68000.git] / Pico / VideoPort.cpp
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