1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus - dd_controller.c *
3 * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4 * Copyright (C) 2015 LuigiBlood *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
20 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21
22 #include "dd_controller.h"
23 #include "dd_rom.h"
24 #include "dd_disk.h"
25
26 #include <string.h>
27 #include <time.h>
28
29 #define M64P_CORE_PROTOTYPES 1
30 #include "api/m64p_config.h"
31 #include "api/m64p_types.h"
32 #include "main/main.h"
33 #include "main/device.h"
34 #include "memory/memory.h"
35 #include "r4300/cp0.h"
36 #include "r4300/cp0_private.h"
37 #include "r4300/interrupt.h"
38 #include "r4300/r4300_core.h"
39 #include "si/pif.h"
40 #include "si/si_controller.h"
41
42 extern int dd_bm_mode_read;
43 extern int CUR_BLOCK;
44 int dd_bm_reset_hold;
45 struct tm* timeinfo;
46
byte2bcd(int n)47 static unsigned char byte2bcd(int n)
48 {
49 n %= 100;
50 return ((n / 10) << 4) | (n % 10);
51 }
52
init_dd(struct dd_controller * dd,struct r4300_core * r4300,uint8_t * dd_disk,size_t dd_disk_size)53 void init_dd(struct dd_controller* dd,
54 struct r4300_core* r4300,
55 uint8_t* dd_disk,
56 size_t dd_disk_size)
57 {
58 dd->r4300 = r4300;
59
60 init_dd_disk(&dd->disk, dd_disk, dd_disk_size);
61 }
62
poweron_dd(struct dd_controller * dd)63 void poweron_dd(struct dd_controller* dd)
64 {
65 memset(dd->regs, 0, ASIC_REGS_COUNT*sizeof(uint32_t));
66 memset(dd->c2_buf, 0, 0x400);
67 memset(dd->sec_buf, 0, 0x100);
68 memset(dd->mseq_buf, 0, 0x40);
69
70 dd_bm_reset_hold = 0;
71
72 dd->regs[ASIC_CMD_STATUS] =
73 (ConfigGetParamBool(g_CoreConfig, "64DD") == 1) ? 0x01400000 : 0xffffffff;
74 dd->regs[ASIC_ID_REG] = 0x00030000;
75 }
76
read_dd_regs(void * opaque,uint32_t address,uint32_t * value)77 int read_dd_regs(void* opaque, uint32_t address, uint32_t* value)
78 {
79 int Cur_Sector;
80 struct dd_controller* dd = (struct dd_controller*)opaque;
81 uint32_t reg = dd_reg(address);
82
83 uint32_t offset = address & 0x00000fff;
84
85 *value = 0x00000000;
86
87 if (reg < ASIC_REGS_COUNT)
88 *value = dd->regs[reg];
89
90 Cur_Sector = dd->regs[ASIC_CUR_SECTOR] >> 16;
91 if (Cur_Sector >= 0x5A)
92 Cur_Sector -= 0x5A;
93
94 if ((reg == ASIC_CMD_STATUS) && (dd->regs[ASIC_CMD_STATUS] & 0x04000000) && (85 < Cur_Sector))
95 {
96 dd->regs[ASIC_CMD_STATUS] &= ~0x04000000;
97 cp0_update_count();
98 g_cp0_regs[CP0_CAUSE_REG] &= ~0x00000800;
99 check_interrupt();
100 dd_update_bm(dd);
101 }
102
103 #if 0
104 /* BUFFERS */
105 switch (address & 0x00000c00)
106 {
107 case 0x000:
108 /* C2 BUFFER */
109 *value = dd->c2_buf[offset/4];
110 break;
111 case 0x400:
112 /* SECTOR BUFFER */
113 offset -= 0x400;
114 *value = dd->sec_buf[offset/4];
115 break;
116 }
117
118 if ((address & 0x00000f00) == 0x500)
119 {
120 /* REGS */
121 if (reg < ASIC_REGS_COUNT)
122 *value = dd->regs[reg];
123
124 if (((address & 0x00000FFF) >= 0x580) || ((address & 0x00000FFF) < 0x5C0))
125 {
126 /* MSEQ */
127 offset -= 0x580;
128 *value = dd->mseq_buf[offset/4];
129 }
130 }
131 #endif
132 return 0;
133 }
134
write_dd_regs(void * opaque,uint32_t address,uint32_t value,uint32_t mask)135 int write_dd_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
136 {
137 uint8_t year, month, hour, day, min, sec;
138 struct dd_controller* dd = (struct dd_controller*)opaque;
139 uint32_t reg = dd_reg(address);
140
141 value &= 0xffff0000;
142
143 if (!ConfigGetParamBool(g_CoreConfig, "64DD"))
144 return 0;
145
146 switch (reg)
147 {
148 case ASIC_DATA:
149 dd->regs[ASIC_DATA] = value;
150 break;
151
152 case ASIC_BM_STATUS_CTL:
153 /* SET SECTOR */
154 dd->regs[ASIC_CUR_SECTOR] = value & 0x00FF0000;
155 CUR_BLOCK = ((dd->regs[ASIC_CUR_SECTOR] >> 16) < 0x5A) ? 0 : 1;
156
157 if (value & 0x01000000)
158 {
159 /* MECHA INT RESET */
160 dd->regs[ASIC_CMD_STATUS] &= ~0x02000000;
161 }
162
163 if (value & 0x02000000)
164 {
165 /* BLOCK TRANSFER */
166 dd->regs[ASIC_BM_STATUS_CTL] |= 0x01000000;
167 }
168
169 if (value & 0x10000000)
170 {
171 /* BM RESET */
172 dd_bm_reset_hold = 1;
173 }
174
175 if (!(value & 0x10000000) && dd_bm_reset_hold)
176 {
177 /* BM RESET */
178 dd_bm_reset_hold = 0;
179 dd->regs[ASIC_CMD_STATUS] &= ~0x5C000000;
180 dd->regs[ASIC_BM_STATUS_CTL] = 0x00000000;
181 CUR_BLOCK = 0;
182 dd->regs[ASIC_CUR_SECTOR] = 0;
183 }
184
185 if ((dd->regs[ASIC_CMD_STATUS] & 0x06000000) == 0)
186 {
187 g_cp0_regs[CP0_CAUSE_REG] &= ~0x00000800;
188 cp0_update_count();
189 check_interrupt();
190 }
191
192 if (value & 0x80000000)
193 {
194 /* BM START */
195 dd->regs[ASIC_BM_STATUS_CTL] |= 0x80000000;
196 dd_update_bm(dd);
197 }
198
199 break;
200
201 case ASIC_CMD_STATUS:
202 /* ASIC Commands */
203 timeinfo = (struct tm*)af_rtc_get_time(&g_dev.si.pif.af_rtc);
204
205 switch (value >> 16)
206 {
207 case 0x01:
208 /* SEEK READ TRACK */
209 dd->regs[ASIC_CUR_TK] = dd->regs[ASIC_DATA] | 0x60000000;
210 dd->regs[ASIC_CMD_STATUS] &= ~0x00180000;
211 dd_bm_mode_read = 1;
212 dd_set_zone_and_track_offset(dd);
213 break;
214
215 case 0x02:
216 /* SEEK WRITE TRACK */
217 dd->regs[ASIC_CUR_TK] = dd->regs[ASIC_DATA] | 0x60000000;
218 dd->regs[ASIC_CMD_STATUS] &= ~0x00180000;
219 dd_bm_mode_read = 0;
220 dd_set_zone_and_track_offset(dd);
221 break;
222
223 case 0x08:
224 /* CLEAR DISK CHANGE FLAG */
225 dd->regs[ASIC_CMD_STATUS] &= ~0x00010000;
226 break;
227
228 case 0x09:
229 /* CLEAR RESET FLAG */
230 dd->regs[ASIC_CMD_STATUS] &= ~0x00400000;
231 break;
232
233 case 0x12:
234 /* Get Year/Month */
235
236 /* Put time in DATA as BCD */
237 year = (uint8_t)byte2bcd(timeinfo->tm_year);
238 month = (uint8_t)byte2bcd((timeinfo->tm_mon + 1));
239
240 dd->regs[ASIC_DATA] = (year << 24) | (month << 16);
241 break;
242
243 case 0x13:
244 /* Get Day/Hour */
245
246 /* Put time in DATA as BCD */
247 hour = (uint8_t)byte2bcd(timeinfo->tm_hour);
248 day = (uint8_t)byte2bcd(timeinfo->tm_mday);
249
250 dd->regs[ASIC_DATA] = (day << 24) | (hour << 16);
251 break;
252 case 0x14:
253 /* Get Min/Sec */
254
255 /* Put time in DATA as BCD */
256 min = (uint8_t)byte2bcd(timeinfo->tm_min);
257 sec = (uint8_t)byte2bcd(timeinfo->tm_sec);
258
259 dd->regs[ASIC_DATA] = (min << 24) | (sec << 16);
260 break;
261
262 case 0x1b:
263 /* Feature Inquiry */
264 dd->regs[ASIC_DATA] = 0x00000000;
265 break;
266 }
267
268 dd->regs[ASIC_CMD_STATUS] |= 0x02000000;
269 cp0_update_count();
270 g_cp0_regs[CP0_CAUSE_REG] |= 0x00000800;
271 check_interrupt();
272 #if 0
273 add_interrupt_event(CART_INT, 1000);
274 #endif
275 break;
276
277 case ASIC_HARD_RESET:
278 dd->regs[ASIC_CMD_STATUS] |= 0x00400000;
279 break;
280
281 case ASIC_HOST_SECBYTE:
282 dd->regs[ASIC_HOST_SECBYTE] = value;
283 break;
284 }
285
286 return 0;
287 }
288
dd_end_of_dma_event(struct dd_controller * dd)289 int dd_end_of_dma_event(struct dd_controller* dd)
290 {
291 #if 0
292 Insert clear CART INT here or something
293 dd_update_bm(dd);
294
295 if ((dd->regs[ASIC_CMD_STATUS] & 0x04000000) == 0)
296 return 1;
297 #endif
298
299 return 0;
300 }
301
dd_pi_test()302 void dd_pi_test()
303 {
304 g_cp0_regs[CP0_CAUSE_REG] &= ~0x00000800;
305 cp0_update_count();
306 check_interrupt();
307 }
308