1 |
/* |
/* |
2 |
* Copyright (C) 2004-2006 Anders Gavare. All rights reserved. |
* Copyright (C) 2004-2007 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: dev_sgi_ip30.c,v 1.21 2006/03/04 12:38:48 debug Exp $ |
* $Id: dev_sgi_ip30.c,v 1.24 2007/02/03 20:14:23 debug Exp $ |
29 |
* |
* |
30 |
* SGI IP30 stuff. |
* SGI IP30 stuff. |
31 |
* |
* |
37 |
#include <string.h> |
#include <string.h> |
38 |
|
|
39 |
#include "cpu.h" |
#include "cpu.h" |
40 |
#include "devices.h" |
#include "device.h" |
41 |
#include "machine.h" |
#include "machine.h" |
42 |
#include "memory.h" |
#include "memory.h" |
43 |
#include "misc.h" |
#include "misc.h" |
44 |
|
|
45 |
|
|
46 |
|
#define DEV_SGI_IP30_LENGTH 0x80000 |
47 |
|
|
48 |
|
struct sgi_ip30_data { |
49 |
|
/* ip30: */ |
50 |
|
uint64_t imask0; /* 0x10000 */ |
51 |
|
uint64_t reg_0x10018; |
52 |
|
uint64_t isr; /* 0x10030 */ |
53 |
|
uint64_t reg_0x20000; |
54 |
|
uint64_t reg_0x30000; |
55 |
|
|
56 |
|
/* ip30_2: */ |
57 |
|
uint64_t reg_0x0029c; |
58 |
|
|
59 |
|
/* ip30_3: */ |
60 |
|
uint64_t reg_0x00284; |
61 |
|
|
62 |
|
/* ip30_4: */ |
63 |
|
uint64_t reg_0x000b0; |
64 |
|
|
65 |
|
/* ip30_5: */ |
66 |
|
uint64_t reg_0x00000; |
67 |
|
}; |
68 |
|
|
69 |
|
|
70 |
void dev_sgi_ip30_tick(struct cpu *cpu, void *extra) |
void dev_sgi_ip30_tick(struct cpu *cpu, void *extra) |
71 |
{ |
{ |
72 |
struct sgi_ip30_data *d = extra; |
struct sgi_ip30_data *d = extra; |
76 |
if (d->imask0 & ((int64_t)1<<50)) { |
if (d->imask0 & ((int64_t)1<<50)) { |
77 |
/* TODO: Only interrupt if reg 0x20000 (the counter) |
/* TODO: Only interrupt if reg 0x20000 (the counter) |
78 |
has passed the compare (0x30000). */ |
has passed the compare (0x30000). */ |
79 |
cpu_interrupt(cpu, 8+1 + 50); |
fatal("IP30 legacy interrupt rewrite: TODO\n"); |
80 |
|
abort(); |
81 |
|
// cpu_interrupt(cpu, 8+1 + 50); |
82 |
} |
} |
83 |
} |
} |
84 |
|
|
124 |
case 0x10020: /* Set ISR, according to Linux/IP30 */ |
case 0x10020: /* Set ISR, according to Linux/IP30 */ |
125 |
d->isr = idata; |
d->isr = idata; |
126 |
/* Recalculate CPU interrupt assertions: */ |
/* Recalculate CPU interrupt assertions: */ |
127 |
cpu_interrupt(cpu, 8); |
fatal("IP30 legacy interrupt rewrite: TODO\n"); |
128 |
|
abort(); |
129 |
|
// cpu_interrupt(cpu, 8); |
130 |
break; |
break; |
131 |
case 0x10028: /* Clear ISR, according to Linux/IP30 */ |
case 0x10028: /* Clear ISR, according to Linux/IP30 */ |
132 |
d->isr &= ~idata; |
d->isr &= ~idata; |
133 |
/* Recalculate CPU interrupt assertions: */ |
/* Recalculate CPU interrupt assertions: */ |
134 |
cpu_interrupt(cpu, 8); |
fatal("IP30 legacy interrupt rewrite: TODO\n"); |
135 |
|
abort(); |
136 |
|
// cpu_interrupt(cpu, 8); |
137 |
break; |
break; |
138 |
case 0x10030: /* Interrupt Status Register */ |
case 0x10030: /* Interrupt Status Register */ |
139 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
140 |
/* Clear-on-write (TODO: is this correct?) */ |
/* Clear-on-write (TODO: is this correct?) */ |
141 |
d->isr &= ~idata; |
d->isr &= ~idata; |
142 |
/* Recalculate CPU interrupt assertions: */ |
/* Recalculate CPU interrupt assertions: */ |
143 |
cpu_interrupt(cpu, 8); |
fatal("IP30 legacy interrupt rewrite: TODO\n"); |
144 |
|
abort(); |
145 |
|
// cpu_interrupt(cpu, 8); |
146 |
} else { |
} else { |
147 |
odata = d->isr; |
odata = d->isr; |
148 |
} |
} |
376 |
} |
} |
377 |
|
|
378 |
|
|
379 |
/* |
DEVINIT(sgi_ip30) |
|
* dev_sgi_ip30_init(): |
|
|
*/ |
|
|
struct sgi_ip30_data *dev_sgi_ip30_init(struct machine *machine, |
|
|
struct memory *mem, uint64_t baseaddr) |
|
380 |
{ |
{ |
381 |
struct sgi_ip30_data *d = malloc(sizeof(struct sgi_ip30_data)); |
struct sgi_ip30_data *d = malloc(sizeof(struct sgi_ip30_data)); |
382 |
if (d == NULL) { |
if (d == NULL) { |
385 |
} |
} |
386 |
memset(d, 0, sizeof(struct sgi_ip30_data)); |
memset(d, 0, sizeof(struct sgi_ip30_data)); |
387 |
|
|
388 |
memory_device_register(mem, "sgi_ip30_1", baseaddr, |
memory_device_register(devinit->machine->memory, "sgi_ip30_1", |
389 |
DEV_SGI_IP30_LENGTH, dev_sgi_ip30_access, (void *)d, |
devinit->addr, DEV_SGI_IP30_LENGTH, dev_sgi_ip30_access, (void *)d, |
390 |
DM_DEFAULT, NULL); |
DM_DEFAULT, NULL); |
391 |
memory_device_register(mem, "sgi_ip30_2", 0x10000000, |
memory_device_register(devinit->machine->memory, "sgi_ip30_2", |
392 |
0x10000, dev_sgi_ip30_2_access, (void *)d, DM_DEFAULT, NULL); |
0x10000000, 0x10000, dev_sgi_ip30_2_access, (void *)d, DM_DEFAULT, |
393 |
memory_device_register(mem, "sgi_ip30_3", 0x1f000000, |
NULL); |
394 |
0x10000, dev_sgi_ip30_3_access, (void *)d, DM_DEFAULT, NULL); |
memory_device_register(devinit->machine->memory, "sgi_ip30_3", |
395 |
memory_device_register(mem, "sgi_ip30_4", 0x1f600000, |
0x1f000000, 0x10000, dev_sgi_ip30_3_access, (void *)d, DM_DEFAULT, |
396 |
0x10000, dev_sgi_ip30_4_access, (void *)d, DM_DEFAULT, NULL); |
NULL); |
397 |
memory_device_register(mem, "sgi_ip30_5", 0x1f6c0000, |
memory_device_register(devinit->machine->memory, "sgi_ip30_4", |
398 |
0x10000, dev_sgi_ip30_5_access, (void *)d, DM_DEFAULT, NULL); |
0x1f600000, 0x10000, dev_sgi_ip30_4_access, (void *)d, DM_DEFAULT, |
399 |
|
NULL); |
400 |
|
memory_device_register(devinit->machine->memory, "sgi_ip30_5", |
401 |
|
0x1f6c0000, 0x10000, dev_sgi_ip30_5_access, (void *)d, DM_DEFAULT, |
402 |
|
NULL); |
403 |
|
|
404 |
machine_add_tickfunction(machine, dev_sgi_ip30_tick, d, 16, 0.0); |
machine_add_tickfunction(devinit->machine, |
405 |
|
dev_sgi_ip30_tick, d, 16, 0.0); |
406 |
|
|
407 |
return d; |
return 1; |
408 |
} |
} |
409 |
|
|