1 /*
2 * Copyright (C) 2004-2009 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * COMMENT: SGI IP22 stuff
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "cpu.h"
36 #include "devices.h"
37 #include "machine.h"
38 #include "memory.h"
39 #include "misc.h"
40
41 #include "thirdparty/imcreg.h"
42
43
44 #define SGI_IP22_TICK_SHIFT 14
45
46
DEVICE_TICK(sgi_ip22)47 DEVICE_TICK(sgi_ip22)
48 {
49 struct sgi_ip22_data *d = (struct sgi_ip22_data *) extra;
50
51 // TODO: Document this!
52 if (d->reg[0x38 / 4] != 0)
53 d->reg[0x38 / 4] --;
54 }
55
56
57 /*
58 * dev_sgi_ip22_imc_access():
59 *
60 * The memory controller (?).
61 */
DEVICE_ACCESS(sgi_ip22_imc)62 DEVICE_ACCESS(sgi_ip22_imc)
63 {
64 struct sgi_ip22_data *d = (struct sgi_ip22_data *) extra;
65 uint64_t idata = 0, odata = 0;
66 int regnr;
67
68 if (writeflag == MEM_WRITE)
69 idata = memory_readmax64(cpu, data, len);
70
71 regnr = relative_addr / sizeof(uint32_t);
72
73 if (writeflag == MEM_WRITE)
74 d->imc_reg[regnr] = idata;
75 else
76 odata = d->imc_reg[regnr];
77
78 switch (relative_addr) {
79 case (IMC_CPUCTRL0 - IP22_IMC_BASE):
80 if (writeflag == MEM_WRITE) {
81 /* debug("[ sgi_ip22_imc: write to "
82 "IMC_CPUCTRL0, data=0x%08x ]\n", (int)idata); */
83 } else {
84 /* debug("[ sgi_ip22_imc: read from IMC_CPUCTRL0, "
85 "data=0x%08x ]\n", (int)odata); */
86 }
87 break;
88 case (IMC_SYSID - IP22_IMC_BASE):
89 if (writeflag == MEM_WRITE) {
90 debug("[ sgi_ip22_imc: unimplemented write "
91 "IMC_SYSID, data=0x%08x ]\n", (int)idata);
92 } else {
93 /* Lowest 4 bits are the revision bits. */
94 odata = 3; /* + IMC_SYSID_HAVEISA; */
95 /* debug("[ sgi_ip22_imc: read from IMC_SYSID, "
96 "data=0x%08x ]\n", (int)odata); */
97 }
98 break;
99 case (IMC_WDOG - IP22_IMC_BASE):
100 if (writeflag == MEM_WRITE) {
101 /* debug("[ sgi_ip22_imc: write to IMC_WDOG, "
102 "data=0x%08x ]\n", (int)idata); */
103 } else {
104 /* debug("[ sgi_ip22_imc: read from IMC_WDOG, "
105 "data=0x%08x ]\n", (int)odata); */
106 }
107 break;
108 case (IMC_MEMCFG0 - IP22_IMC_BASE):
109 if (writeflag == MEM_WRITE) {
110 debug("[ sgi_ip22_imc: unimplemented write "
111 "IMC_MEMCFG0, data=0x%08x ]\n", (int)idata);
112 } else {
113 odata = 0x3100 + (0x8000000 >> 22); /* ? TODO */
114 /* debug("[ sgi_ip22_imc: read from IMC_MEMCFG0,"
115 " data=0x%08x ]\n", (int)odata); */
116 }
117 break;
118 case (IMC_MEMCFG1 - IP22_IMC_BASE):
119 if (writeflag == MEM_WRITE) {
120 debug("[ sgi_ip22_imc: unimplemented write "
121 "IMC_MEMCFG1, data=0x%08x ]\n", (int)idata);
122 } else {
123 odata = 0;
124 /* debug("[ sgi_ip22_imc: read from IMC_MEMCFG1, "
125 "data=0x%08x ]\n", (int)odata); */
126 }
127 break;
128 case (IMC_EEPROM - IP22_IMC_BASE):
129 /*
130 * The IP22 prom tries to access this during bootup,
131 * but I have no idea how it works.
132 */
133 if (writeflag == MEM_WRITE) {
134 debug("[ sgi_ip22_imc: write to IMC_EEPROM, data="
135 "0x%08x ]\n", (int)idata);
136 } else {
137 odata = random() & 0x1e;
138 debug("[ sgi_ip22_imc: read from IMC_WDOG, "
139 "data=0x%08x ]\n", (int)odata);
140 }
141 break;
142 default:
143 if (writeflag == MEM_WRITE) {
144 debug("[ sgi_ip22_imc: unimplemented write to "
145 "address 0x%x, data=0x%08x ]\n",
146 (int)relative_addr, (int)idata);
147 } else {
148 debug("[ sgi_ip22_imc: unimplemented read from "
149 "address 0x%x, data=0x%08x ]\n",
150 (int)relative_addr, (int)odata);
151 }
152 }
153
154 if (writeflag == MEM_READ)
155 memory_writemax64(cpu, data, len, odata);
156
157 return 1;
158 }
159
160
161 /*
162 * dev_sgi_ip22_unknown_access():
163 *
164 * A so far unknown device, used by the IP22 prom during startup.
165 */
DEVICE_ACCESS(sgi_ip22_unknown)166 DEVICE_ACCESS(sgi_ip22_unknown)
167 {
168 struct sgi_ip22_data *d = (struct sgi_ip22_data *) extra;
169 uint64_t idata = 0, odata = 0;
170
171 idata = memory_readmax64(cpu, data, len);
172
173 switch (relative_addr) {
174 case 0x04:
175 if (writeflag == MEM_WRITE) {
176 debug("[ sgi_ip22_unknown: write to address 0x%x,"
177 " data=0x%08x ]\n", (int)relative_addr, (int)idata);
178 } else {
179 odata = d->unknown_timer;
180 d->unknown_timer += 100;
181 debug("[ sgi_ip22_unknown: read from address 0x%x, "
182 "data=0x%08x ]\n", (int)relative_addr, (int)odata);
183 }
184 break;
185 default:
186 if (writeflag == MEM_WRITE) {
187 debug("[ sgi_ip22_unknown: unimplemented write to "
188 "address 0x%x, data=0x%08x ]\n",
189 (int)relative_addr, (int)idata);
190 } else {
191 debug("[ sgi_ip22_unknown: unimplemented read from "
192 "address 0x%x, data=0x%08x ]\n",
193 (int)relative_addr, (int)odata);
194 }
195 }
196
197 if (writeflag == MEM_READ)
198 memory_writemax64(cpu, data, len, odata);
199
200 return 1;
201 }
202
203
204 /*
205 * dev_sgi_ip22_unknown2_access():
206 *
207 * A so far unknown device, used by the IP22 prom during startup.
208 */
DEVICE_ACCESS(sgi_ip22_unknown2)209 DEVICE_ACCESS(sgi_ip22_unknown2)
210 {
211 struct sgi_ip22_data *d = (struct sgi_ip22_data *) extra;
212 uint64_t idata = 0, odata = 0;
213 int regnr;
214
215 idata = memory_readmax64(cpu, data, len);
216 regnr = relative_addr / sizeof(uint32_t);
217
218 if (writeflag == MEM_WRITE)
219 d->unknown2_reg[regnr] = idata;
220 else
221 odata = d->unknown2_reg[regnr];
222
223 switch (relative_addr) {
224 default:
225 if (writeflag == MEM_WRITE) {
226 debug("[ sgi_ip22_unknown2: unimplemented write "
227 "to address 0x%x, data=0x%08x ]\n",
228 (int)relative_addr, (int)idata);
229 } else {
230 debug("[ sgi_ip22_unknown2: unimplemented read from "
231 "address 0x%x, data=0x%08x ]\n",
232 (int)relative_addr, (int)odata);
233 }
234 }
235
236 if (writeflag == MEM_READ)
237 memory_writemax64(cpu, data, len, odata);
238
239 return 1;
240 }
241
242
DEVICE_ACCESS(sgi_ip22_sysid)243 DEVICE_ACCESS(sgi_ip22_sysid)
244 {
245 struct sgi_ip22_data *d = (struct sgi_ip22_data *) extra;
246 uint64_t idata = 0, odata = 0;
247
248 idata = memory_readmax64(cpu, data, len);
249
250 if (writeflag == MEM_WRITE) {
251 debug("[ sgi_ip22_sysid: write to address 0x%x, "
252 "data=0x%08x ]\n", (int)relative_addr, (int)idata);
253 } else {
254 /*
255 * According to NetBSD's sgimips/ip22.c:
256 *
257 * printf("IOC rev %d, machine %s, board rev %d\n",
258 * (sysid >> 5) & 0x07,
259 * (sysid & 1) ? "Indigo2 (Fullhouse)" : "Indy (Guiness)",
260 * (sysid >> 1) & 0x0f);
261 */
262
263 /* IOC rev 1, Guiness, board rev 3: */
264 odata = (1 << 5) + (3 << 1) + (d->guiness_flag? 0 : 1);
265
266 debug("[ sgi_ip22_sysid: read from address 0x%x, data="
267 "0x%08x ]\n", (int)relative_addr, (int)odata);
268 }
269
270 if (writeflag == MEM_READ)
271 memory_writemax64(cpu, data, len, odata);
272
273 return 1;
274 }
275
276
DEVICE_ACCESS(sgi_ip22)277 DEVICE_ACCESS(sgi_ip22)
278 {
279 struct sgi_ip22_data *d = (struct sgi_ip22_data *) extra;
280 uint64_t idata = 0, odata = 0;
281 int regnr;
282
283 idata = memory_readmax64(cpu, data, len);
284 regnr = relative_addr / sizeof(uint32_t);
285
286 if (writeflag == MEM_WRITE)
287 d->reg[regnr] = idata;
288 else
289 odata = d->reg[regnr];
290
291 /* Read from/write to the sgi_ip22: */
292 switch (relative_addr) {
293 case 0x00: /* local0 irq stat */
294 if (writeflag == MEM_WRITE) {
295 debug("[ sgi_ip22: write to local0 IRQ STAT, "
296 "data=0x%llx ]\n", (long long)idata);
297 } else {
298 debug("[ sgi_ip22: read from local0 IRQ STAT, "
299 "data=0x%llx ]\n", (long long)odata);
300 }
301 break;
302 case 0x04: /* local0 irq mask */
303 if (writeflag == MEM_WRITE) {
304 /*
305 * Ugly hack: if an interrupt is asserted, and someone
306 * writes to this mask register, the interrupt should
307 * be masked. That is, sgi_ip22_interrupt() in
308 * src/machine.c has to be called to deal with this.
309 * The ugly solution I choose here is to deassert
310 * some interrupt which should never be used anyway.
311 * (TODO: Fix this.)
312 */
313
314 fatal("TODO: ip22 legacy interrupt rewrite!\n");
315 abort();
316
317 // cpu_interrupt_ack(cpu, 8 + 63);
318 // debug("[ sgi_ip22: write to local0 IRQ MASK, "
319 // "data=0x%llx ]\n", (long long)idata);
320 } else {
321 debug("[ sgi_ip22: read from local0 IRQ MASK, "
322 "data=0x%llx ]\n", (long long)odata);
323 }
324 break;
325 case 0x08: /* local1 irq stat */
326 if (writeflag == MEM_WRITE) {
327 debug("[ sgi_ip22: write to local1 IRQ STAT, "
328 "data=0x%llx ]\n", (long long)idata);
329 } else {
330 debug("[ sgi_ip22: read from local1 IRQ STAT, "
331 "data=0x%llx ]\n", (long long)odata);
332 }
333 break;
334 case 0x0c: /* local1 irq mask */
335 if (writeflag == MEM_WRITE) {
336 /* See commen above, about local0 irq mask. */
337
338 fatal("TODO: ip22 legacy interrupt rewrite!\n");
339 abort();
340 // cpu_interrupt_ack(cpu, 8 + 63);
341 // debug("[ sgi_ip22: write to local1 IRQ MASK, "
342 // "data=0x%llx ]\n", (long long)idata);
343 } else {
344 debug("[ sgi_ip22: read from local1 IRQ MASK, "
345 "data=0x%llx ]\n", (long long)odata);
346 }
347 break;
348 case 0x10:
349 if (writeflag == MEM_WRITE) {
350 debug("[ sgi_ip22: write to mappable IRQ STAT, "
351 "data=0x%llx ]\n", (long long)idata);
352 } else {
353 debug("[ sgi_ip22: read from mappable IRQ STAT, "
354 "data=0x%llx ]\n", (long long)odata);
355 }
356 break;
357 case 0x14:
358 if (writeflag == MEM_WRITE) {
359 debug("[ sgi_ip22: write to mappable local0 IRQ "
360 "MASK, data=0x%llx ]\n", (long long)idata);
361 } else {
362 debug("[ sgi_ip22: read from mappable local0 IRQ "
363 "MASK, data=0x%llx ]\n", (long long)odata);
364 }
365 break;
366 case 0x18:
367 if (writeflag == MEM_WRITE) {
368 debug("[ sgi_ip22: write to mappable local1 IRQ "
369 "MASK, data=0x%llx ]\n", (long long)idata);
370 } else {
371 debug("[ sgi_ip22: read from mappable local1 IRQ "
372 "MASK, data=0x%llx ]\n", (long long)odata);
373 }
374 break;
375 case 0x38: /* timer count */
376 if (writeflag == MEM_WRITE) {
377 /* Two byte values are written to this address,
378 sequentially... TODO */
379 } else {
380 /* The timer is decreased by the tick function. */
381 }
382 break;
383 case 0x3b: /* ? */
384 odata = random();
385 break;
386 case 0x3c: /* timer control */
387 break;
388 case 0x3f: /* ? */
389 odata = random();
390 break;
391 default:
392 if (writeflag == MEM_WRITE) {
393 debug("[ sgi_ip22: unimplemented write to address "
394 "0x%x, data=0x%02x ]\n", (int)relative_addr,
395 (int)idata);
396 } else {
397 debug("[ sgi_ip22: unimplemented read from address "
398 "0x%llx ]\n", (long long)relative_addr);
399 }
400 }
401
402 if (writeflag == MEM_READ)
403 memory_writemax64(cpu, data, len, odata);
404
405 return 1;
406 }
407
408
dev_sgi_ip22_init(struct machine * machine,struct memory * mem,uint64_t baseaddr,int guiness_flag)409 struct sgi_ip22_data *dev_sgi_ip22_init(struct machine *machine,
410 struct memory *mem, uint64_t baseaddr, int guiness_flag)
411 {
412 struct sgi_ip22_data *d;
413
414 CHECK_ALLOCATION(d = (struct sgi_ip22_data *) malloc(sizeof(struct sgi_ip22_data)));
415 memset(d, 0, sizeof(struct sgi_ip22_data));
416
417 d->guiness_flag = guiness_flag;
418
419 memory_device_register(mem, "sgi_ip22", baseaddr, DEV_SGI_IP22_LENGTH,
420 dev_sgi_ip22_access, (void *)d, DM_DEFAULT, NULL);
421 memory_device_register(mem, "sgi_ip22_sysid", 0x1fbd9858, 0x8,
422 dev_sgi_ip22_sysid_access, (void *)d, DM_DEFAULT, NULL);
423 memory_device_register(mem, "sgi_ip22_imc", IP22_IMC_BASE,
424 DEV_SGI_IP22_IMC_LENGTH, dev_sgi_ip22_imc_access, (void *)d,
425 DM_DEFAULT, NULL);
426 memory_device_register(mem, "sgi_ip22_unknown", 0x1fa01000, 0x10,
427 dev_sgi_ip22_unknown_access, (void *)d, DM_DEFAULT, NULL);
428 memory_device_register(mem, "sgi_ip22_unknown2", IP22_UNKNOWN2_BASE,
429 DEV_SGI_IP22_UNKNOWN2_LENGTH, dev_sgi_ip22_unknown2_access,
430 (void *)d, DM_DEFAULT, NULL);
431
432 machine_add_tickfunction(machine, dev_sgi_ip22_tick, d,
433 SGI_IP22_TICK_SHIFT);
434
435 return d;
436 }
437
438