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