944e4c864f2800bed425ea10941cf6f289fb761f
[picodrive.git] / Misc.c
1 // This is part of Pico Library\r
2 \r
3 // (c) Copyright 2006 notaz, All rights reserved.\r
4 // Free for non-commercial use.\r
5 \r
6 // For commercial use, separate licencing terms must be obtained.\r
7 \r
8 \r
9 #include "PicoInt.h"\r
10 \r
11 // H-counter table for hvcounter reads in 40col mode\r
12 // based on Gens code\r
13 const unsigned char hcounts_40[] = {\r
14 0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,\r
15 0x0e,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x13,0x14,\r
16 0x14,0x15,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b,\r
17 0x1b,0x1b,0x1c,0x1c,0x1d,0x1d,0x1d,0x1e,0x1e,0x1f,0x1f,0x20,0x20,0x20,0x21,0x21,\r
18 0x22,0x22,0x23,0x23,0x23,0x24,0x24,0x25,0x25,0x25,0x26,0x26,0x27,0x27,0x28,0x28,\r
19 0x28,0x29,0x29,0x2a,0x2a,0x2a,0x2b,0x2b,0x2c,0x2c,0x2d,0x2d,0x2d,0x2e,0x2e,0x2f,\r
20 0x2f,0x30,0x30,0x30,0x31,0x31,0x32,0x32,0x32,0x33,0x33,0x34,0x34,0x35,0x35,0x35,\r
21 0x36,0x36,0x37,0x37,0x38,0x38,0x38,0x39,0x39,0x3a,0x3a,0x3a,0x3b,0x3b,0x3c,0x3c,\r
22 0x3d,0x3d,0x3d,0x3e,0x3e,0x3f,0x3f,0x3f,0x40,0x40,0x41,0x41,0x42,0x42,0x42,0x43,\r
23 0x43,0x44,0x44,0x45,0x45,0x45,0x46,0x46,0x47,0x47,0x47,0x48,0x48,0x49,0x49,0x4a,\r
24 0x4a,0x4a,0x4b,0x4b,0x4c,0x4c,0x4d,0x4d,0x4d,0x4e,0x4e,0x4f,0x4f,0x4f,0x50,0x50,\r
25 0x51,0x51,0x52,0x52,0x52,0x53,0x53,0x54,0x54,0x55,0x55,0x55,0x56,0x56,0x57,0x57,\r
26 0x57,0x58,0x58,0x59,0x59,0x5a,0x5a,0x5a,0x5b,0x5b,0x5c,0x5c,0x5c,0x5d,0x5d,0x5e,\r
27 0x5e,0x5f,0x5f,0x5f,0x60,0x60,0x61,0x61,0x62,0x62,0x62,0x63,0x63,0x64,0x64,0x64,\r
28 0x65,0x65,0x66,0x66,0x67,0x67,0x67,0x68,0x68,0x69,0x69,0x6a,0x6a,0x6a,0x6b,0x6b,\r
29 0x6c,0x6c,0x6c,0x6d,0x6d,0x6e,0x6e,0x6f,0x6f,0x6f,0x70,0x70,0x71,0x71,0x71,0x72,\r
30 0x72,0x73,0x73,0x74,0x74,0x74,0x75,0x75,0x76,0x76,0x77,0x77,0x77,0x78,0x78,0x79,\r
31 0x79,0x79,0x7a,0x7a,0x7b,0x7b,0x7c,0x7c,0x7c,0x7d,0x7d,0x7e,0x7e,0x7f,0x7f,0x7f,\r
32 0x80,0x80,0x81,0x81,0x81,0x82,0x82,0x83,0x83,0x84,0x84,0x84,0x85,0x85,0x86,0x86,\r
33 0x86,0x87,0x87,0x88,0x88,0x89,0x89,0x89,0x8a,0x8a,0x8b,0x8b,0x8c,0x8c,0x8c,0x8d,\r
34 0x8d,0x8e,0x8e,0x8e,0x8f,0x8f,0x90,0x90,0x91,0x91,0x91,0x92,0x92,0x93,0x93,0x94,\r
35 0x94,0x94,0x95,0x95,0x96,0x96,0x96,0x97,0x97,0x98,0x98,0x99,0x99,0x99,0x9a,0x9a,\r
36 0x9b,0x9b,0x9b,0x9c,0x9c,0x9d,0x9d,0x9e,0x9e,0x9e,0x9f,0x9f,0xa0,0xa0,0xa1,0xa1,\r
37 0xa1,0xa2,0xa2,0xa3,0xa3,0xa3,0xa4,0xa4,0xa5,0xa5,0xa6,0xa6,0xa6,0xa7,0xa7,0xa8,\r
38 0xa8,0xa9,0xa9,0xa9,0xaa,0xaa,0xab,0xab,0xab,0xac,0xac,0xad,0xad,0xae,0xae,0xae,\r
39 0xaf,0xaf,0xb0,0xb0,\r
40 0xe4,0xe4,0xe4,0xe5,0xe5,0xe6,0xe6,0xe6,0xe7,0xe7,0xe8,0xe8,0xe9,0xe9,0xe9,0xea,\r
41 0xea,0xeb,0xeb,0xeb,0xec,0xec,0xed,0xed,0xee,0xee,0xee,0xef,0xef,0xf0,0xf0,0xf1,\r
42 0xf1,0xf1,0xf2,0xf2,0xf3,0xf3,0xf3,0xf4,0xf4,0xf5,0xf5,0xf6,0xf6,0xf6,0xf7,0xf7,\r
43 0xf8,0xf8,0xf9,0xf9,0xf9,0xfa,0xfa,0xfb,0xfb,0xfb,0xfc,0xfc,0xfd,0xfd,0xfe,0xfe,\r
44 0xfe,0xff,0xff,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x03,0x04,0x04,0x05,\r
45 0x05,0x06,0x06,0x06,\r
46 0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,\r
47 0x0e,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x10,\r
48 };\r
49 \r
50 // H-counter table for hvcounter reads in 32col mode\r
51 const unsigned char hcounts_32[] = {\r
52 0x05,0x05,0x05,0x06,0x06,0x07,0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x09,0x0a,0x0a,\r
53 0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x0f,0x10,\r
54 0x10,0x10,0x11,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x13,0x14,0x14,0x14,0x15,0x15,\r
55 0x15,0x16,0x16,0x17,0x17,0x17,0x18,0x18,0x18,0x19,0x19,0x19,0x1a,0x1a,0x1a,0x1b,\r
56 0x1b,0x1b,0x1c,0x1c,0x1c,0x1d,0x1d,0x1d,0x1e,0x1e,0x1f,0x1f,0x1f,0x20,0x20,0x20,\r
57 0x21,0x21,0x21,0x22,0x22,0x22,0x23,0x23,0x23,0x24,0x24,0x24,0x25,0x25,0x26,0x26,\r
58 0x26,0x27,0x27,0x27,0x28,0x28,0x28,0x29,0x29,0x29,0x2a,0x2a,0x2a,0x2b,0x2b,0x2b,\r
59 0x2c,0x2c,0x2c,0x2d,0x2d,0x2e,0x2e,0x2e,0x2f,0x2f,0x2f,0x30,0x30,0x30,0x31,0x31,\r
60 0x31,0x32,0x32,0x32,0x33,0x33,0x33,0x34,0x34,0x34,0x35,0x35,0x36,0x36,0x36,0x37,\r
61 0x37,0x37,0x38,0x38,0x38,0x39,0x39,0x39,0x3a,0x3a,0x3a,0x3b,0x3b,0x3b,0x3c,0x3c,\r
62 0x3d,0x3d,0x3d,0x3e,0x3e,0x3e,0x3f,0x3f,0x3f,0x40,0x40,0x40,0x41,0x41,0x41,0x42,\r
63 0x42,0x42,0x43,0x43,0x43,0x44,0x44,0x45,0x45,0x45,0x46,0x46,0x46,0x47,0x47,0x47,\r
64 0x48,0x48,0x48,0x49,0x49,0x49,0x4a,0x4a,0x4a,0x4b,0x4b,0x4b,0x4c,0x4c,0x4d,0x4d,\r
65 0x4d,0x4e,0x4e,0x4e,0x4f,0x4f,0x4f,0x50,0x50,0x50,0x51,0x51,0x51,0x52,0x52,0x52,\r
66 0x53,0x53,0x53,0x54,0x54,0x55,0x55,0x55,0x56,0x56,0x56,0x57,0x57,0x57,0x58,0x58,\r
67 0x58,0x59,0x59,0x59,0x5a,0x5a,0x5a,0x5b,0x5b,0x5c,0x5c,0x5c,0x5d,0x5d,0x5d,0x5e,\r
68 0x5e,0x5e,0x5f,0x5f,0x5f,0x60,0x60,0x60,0x61,0x61,0x61,0x62,0x62,0x62,0x63,0x63,\r
69 0x64,0x64,0x64,0x65,0x65,0x65,0x66,0x66,0x66,0x67,0x67,0x67,0x68,0x68,0x68,0x69,\r
70 0x69,0x69,0x6a,0x6a,0x6a,0x6b,0x6b,0x6c,0x6c,0x6c,0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,\r
71 0x6f,0x6f,0x6f,0x70,0x70,0x70,0x71,0x71,0x71,0x72,0x72,0x72,0x73,0x73,0x74,0x74,\r
72 0x74,0x75,0x75,0x75,0x76,0x76,0x76,0x77,0x77,0x77,0x78,0x78,0x78,0x79,0x79,0x79,\r
73 0x7a,0x7a,0x7b,0x7b,0x7b,0x7c,0x7c,0x7c,0x7d,0x7d,0x7d,0x7e,0x7e,0x7e,0x7f,0x7f,\r
74 0x7f,0x80,0x80,0x80,0x81,0x81,0x81,0x82,0x82,0x83,0x83,0x83,0x84,0x84,0x84,0x85,\r
75 0x85,0x85,0x86,0x86,0x86,0x87,0x87,0x87,0x88,0x88,0x88,0x89,0x89,0x89,0x8a,0x8a,\r
76 0x8b,0x8b,0x8b,0x8c,0x8c,0x8c,0x8d,0x8d,0x8d,0x8e,0x8e,0x8e,0x8f,0x8f,0x8f,0x90,\r
77 0x90,0x90,0x91,0x91,\r
78 0xe8,0xe8,0xe8,0xe9,0xe9,0xe9,0xea,0xea,0xea,0xeb,0xeb,0xeb,0xec,0xec,0xec,0xed,\r
79 0xed,0xed,0xee,0xee,0xee,0xef,0xef,0xf0,0xf0,0xf0,0xf1,0xf1,0xf1,0xf2,0xf2,0xf2,\r
80 0xf3,0xf3,0xf3,0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf6,0xf6,0xf6,0xf7,0xf7,0xf8,0xf8,\r
81 0xf8,0xf9,0xf9,0xf9,0xfa,0xfa,0xfa,0xfb,0xfb,0xfb,0xfc,0xfc,0xfc,0xfd,0xfd,0xfd,\r
82 0xfe,0xfe,0xfe,0xff,0xff,0x00,0x00,0x00,0x01,0x01,0x01,0x02,0x02,0x02,0x03,0x03,\r
83 0x03,0x04,0x04,0x04,\r
84 0x05,0x05,0x05,0x06,0x06,0x07,0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x09,0x0a,0x0a,\r
85 0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0c,0x0d,\r
86 };\r
87 \r
88 \r
89 // rarely used EEPROM SRAM code\r
90 // known games which use this:\r
91 // Wonder Boy in Monster World, Megaman - The Wily Wars (X24C01, 128 bytes)\r
92 \r
93 // (see Genesis Plus for Wii/GC code and docs for info,\r
94 //  full game list and better code).\r
95 \r
96 unsigned int lastSSRamWrite = 0xffff0000;\r
97 \r
98 // sram_reg: LAtd sela (L=pending SCL, A=pending SDA, t=(unused),\r
99 //                      d=SRAM was detected (header or by access), s=started, e=save is EEPROM, l=old SCL, a=old SDA)\r
100 PICO_INTERNAL void SRAMWriteEEPROM(unsigned int d) // ???? ??la (l=SCL, a=SDA)\r
101 {\r
102   unsigned int sreg = Pico.m.sram_reg, saddr = Pico.m.eeprom_addr, scyc = Pico.m.eeprom_cycle, ssa = Pico.m.eeprom_slave;\r
103 \r
104   elprintf(EL_EEPROM, "eeprom: scl/sda: %i/%i -> %i/%i, newtime=%i", (sreg&2)>>1, sreg&1,\r
105     (d&2)>>1, d&1, SekCyclesDoneT()-lastSSRamWrite);\r
106   saddr&=0x1fff;\r
107 \r
108   if(sreg & d & 2) {\r
109     // SCL was and is still high..\r
110     if((sreg & 1) && !(d&1)) {\r
111       // ..and SDA went low, means it's a start command, so clear internal addr reg and clock counter\r
112       elprintf(EL_EEPROM, "eeprom: -start-");\r
113       //saddr = 0;\r
114       scyc = 0;\r
115       sreg |= 8;\r
116     } else if(!(sreg & 1) && (d&1)) {\r
117       // SDA went high == stop command\r
118       elprintf(EL_EEPROM, "eeprom: -stop-");\r
119       sreg &= ~8;\r
120     }\r
121   }\r
122   else if((sreg & 8) && !(sreg & 2) && (d&2))\r
123   {\r
124     // we are started and SCL went high - next cycle\r
125     scyc++; // pre-increment\r
126     if(SRam.eeprom_type) {\r
127       // X24C02+\r
128       if((ssa&1) && scyc == 18) {\r
129         scyc = 9;\r
130         saddr++; // next address in read mode\r
131         /*if(SRam.eeprom_type==2) saddr&=0xff; else*/ saddr&=0x1fff; // mask\r
132       }\r
133       else if(SRam.eeprom_type == 2 && scyc == 27) scyc = 18;\r
134       else if(scyc == 36) scyc = 27;\r
135     } else {\r
136       // X24C01\r
137       if(scyc == 18) {\r
138         scyc = 9;  // wrap\r
139         if(saddr&1) { saddr+=2; saddr&=0xff; } // next addr in read mode\r
140       }\r
141     }\r
142     elprintf(EL_EEPROM, "eeprom: scyc: %i", scyc);\r
143   }\r
144   else if((sreg & 8) && (sreg & 2) && !(d&2))\r
145   {\r
146     // we are started and SCL went low (falling edge)\r
147     if(SRam.eeprom_type) {\r
148       // X24C02+\r
149       if(scyc == 9 || scyc == 18 || scyc == 27); // ACK cycles\r
150       else if( (SRam.eeprom_type == 3 && scyc > 27) || (SRam.eeprom_type == 2 && scyc > 18) ) {\r
151         if(!(ssa&1)) {\r
152           // data write\r
153           unsigned char *pm=SRam.data+saddr;\r
154           *pm <<= 1; *pm |= d&1;\r
155           if(scyc == 26 || scyc == 35) {\r
156             saddr=(saddr&~0xf)|((saddr+1)&0xf); // only 4 (?) lowest bits are incremented\r
157             elprintf(EL_EEPROM, "eeprom: write done, addr inc to: %x, last byte=%02x", saddr, *pm);\r
158           }\r
159           SRam.changed = 1;\r
160         }\r
161       } else if(scyc > 9) {\r
162         if(!(ssa&1)) {\r
163           // we latch another addr bit\r
164           saddr<<=1;\r
165           if(SRam.eeprom_type == 2) saddr&=0xff; else saddr&=0x1fff; // mask\r
166           saddr|=d&1;\r
167           if(scyc==17||scyc==26) {\r
168             elprintf(EL_EEPROM, "eeprom: addr reg done: %x", saddr);\r
169             if(scyc==17&&SRam.eeprom_type==2) { saddr&=0xff; saddr|=(ssa<<7)&0x700; } // add device bits too\r
170           }\r
171         }\r
172       } else {\r
173         // slave address\r
174         ssa<<=1; ssa|=d&1;\r
175         if(scyc==8) elprintf(EL_EEPROM, "eeprom: slave done: %x", ssa);\r
176       }\r
177     } else {\r
178       // X24C01\r
179       if(scyc == 9); // ACK cycle, do nothing\r
180       else if(scyc > 9) {\r
181         if(!(saddr&1)) {\r
182           // data write\r
183           unsigned char *pm=SRam.data+(saddr>>1);\r
184           *pm <<= 1; *pm |= d&1;\r
185           if(scyc == 17) {\r
186             saddr=(saddr&0xf9)|((saddr+2)&6); // only 2 lowest bits are incremented\r
187             elprintf(EL_EEPROM, "eeprom: write done, addr inc to: %x, last byte=%02x", saddr>>1, *pm);\r
188           }\r
189           SRam.changed = 1;\r
190         }\r
191       } else {\r
192         // we latch another addr bit\r
193         saddr<<=1; saddr|=d&1; saddr&=0xff;\r
194         if(scyc==8) elprintf(EL_EEPROM, "eeprom: addr done: %x", saddr>>1);\r
195       }\r
196     }\r
197   }\r
198 \r
199   sreg &= ~3; sreg |= d&3; // remember SCL and SDA\r
200   Pico.m.sram_reg    = (unsigned char) sreg;\r
201   Pico.m.eeprom_cycle= (unsigned char) scyc;\r
202   Pico.m.eeprom_slave= (unsigned char) ssa;\r
203   Pico.m.eeprom_addr = (unsigned short)saddr;\r
204 }\r
205 \r
206 PICO_INTERNAL_ASM unsigned int SRAMReadEEPROM(void)\r
207 {\r
208   unsigned int shift, d;\r
209   unsigned int sreg, saddr, scyc, ssa, interval;\r
210 \r
211   // flush last pending write\r
212   SRAMWriteEEPROM(Pico.m.sram_reg>>6);\r
213 \r
214   sreg = Pico.m.sram_reg; saddr = Pico.m.eeprom_addr&0x1fff; scyc = Pico.m.eeprom_cycle; ssa = Pico.m.eeprom_slave;\r
215   interval = SekCyclesDoneT()-lastSSRamWrite;\r
216   d = (sreg>>6)&1; // use SDA as "open bus"\r
217 \r
218   // NBA Jam is nasty enough to read <before> raising the SCL and starting the new cycle.\r
219   // this is probably valid because data changes occur while SCL is low and data can be read\r
220   // before it's actual cycle begins.\r
221   if (!(sreg&0x80) && interval >= 24) {\r
222     elprintf(EL_EEPROM, "eeprom: early read, cycles=%i", interval);\r
223     scyc++;\r
224   }\r
225 \r
226   if (!(sreg & 8)); // not started, use open bus\r
227   else if (scyc == 9 || scyc == 18 || scyc == 27) {\r
228     elprintf(EL_EEPROM, "eeprom: r ack");\r
229     d = 0;\r
230   } else if (scyc > 9 && scyc < 18) {\r
231     // started and first command word received\r
232     shift = 17-scyc;\r
233     if (SRam.eeprom_type) {\r
234       // X24C02+\r
235       if (ssa&1) {\r
236         elprintf(EL_EEPROM, "eeprom: read: addr %02x, cycle %i, reg %02x", saddr, scyc, sreg);\r
237         if (shift==0) elprintf(EL_EEPROM, "eeprom: read done, byte %02x", SRam.data[saddr]);\r
238         d = (SRam.data[saddr]>>shift)&1;\r
239       }\r
240     } else {\r
241       // X24C01\r
242       if (saddr&1) {\r
243         elprintf(EL_EEPROM, "eeprom: read: addr %02x, cycle %i, reg %02x", saddr>>1, scyc, sreg);\r
244         if (shift==0) elprintf(EL_EEPROM, "eeprom: read done, byte %02x", SRam.data[saddr>>1]);\r
245         d = (SRam.data[saddr>>1]>>shift)&1;\r
246       }\r
247     }\r
248   }\r
249 \r
250   return (d << SRam.eeprom_bit_out);\r
251 }\r
252 \r
253 PICO_INTERNAL void SRAMUpdPending(unsigned int a, unsigned int d)\r
254 {\r
255   unsigned int d1, sreg = Pico.m.sram_reg;\r
256 \r
257   if (!((SRam.eeprom_abits^a)&1))\r
258   {\r
259     // SCL\r
260     sreg &= ~0x80;\r
261     d1 = (d >> SRam.eeprom_bit_cl) & 1;\r
262     sreg |= d1<<7;\r
263   }\r
264   if (!(((SRam.eeprom_abits>>1)^a)&1))\r
265   {\r
266     // SDA in\r
267     sreg &= ~0x40;\r
268     d1 = (d >> SRam.eeprom_bit_in) & 1;\r
269     sreg |= d1<<6;\r
270   }\r
271 \r
272   Pico.m.sram_reg = (unsigned char) sreg;\r
273 }\r
274 \r
275 \r
276 #ifndef _ASM_MISC_C\r
277 typedef struct\r
278 {\r
279         int b0;\r
280         int b1;\r
281         int b2;\r
282         int b3;\r
283         int b4;\r
284         int b5;\r
285         int b6;\r
286         int b7;\r
287 } intblock;\r
288 \r
289 PICO_INTERNAL_ASM void memcpy16(unsigned short *dest, unsigned short *src, int count)\r
290 {\r
291         if ((((int)dest | (int)src) & 3) == 0)\r
292         {\r
293                 if (count >= 32) {\r
294                         memcpy32((int *)dest, (int *)src, count/2);\r
295                         count&=1;\r
296                 } else {\r
297                         for (; count >= 2; count -= 2, dest+=2, src+=2)\r
298                                 *(int *)dest = *(int *)src;\r
299                 }\r
300         }\r
301         while (count--)\r
302                 *dest++ = *src++;\r
303 }\r
304 \r
305 \r
306 PICO_INTERNAL_ASM void memcpy16bswap(unsigned short *dest, void *src, int count)\r
307 {\r
308         unsigned char *src_ = src;\r
309 \r
310         for (; count; count--, src_ += 2)\r
311                 *dest++ = (src_[0] << 8) | src_[1];\r
312 }\r
313 \r
314 #ifndef _ASM_MISC_C_AMIPS\r
315 PICO_INTERNAL_ASM void memcpy32(int *dest, int *src, int count)\r
316 {\r
317         intblock *bd = (intblock *) dest, *bs = (intblock *) src;\r
318 \r
319         for (; count >= sizeof(*bd)/4; count -= sizeof(*bd)/4)\r
320                 *bd++ = *bs++;\r
321 \r
322         dest = (int *)bd; src = (int *)bs;\r
323         while (count--)\r
324                 *dest++ = *src++;\r
325 }\r
326 \r
327 \r
328 PICO_INTERNAL_ASM void memset32(int *dest, int c, int count)\r
329 {\r
330         for (; count >= 8; count -= 8, dest += 8)\r
331                 dest[0] = dest[1] = dest[2] = dest[3] =\r
332                 dest[4] = dest[5] = dest[6] = dest[7] = c;\r
333 \r
334         while (count--)\r
335                 *dest++ = c;\r
336 }\r
337 void memset32_uncached(int *dest, int c, int count) { memset32(dest, c, count); }\r
338 #endif\r
339 #endif\r
340 \r