1 |
/* |
/* |
2 |
* Copyright (C) 2005 Anders Gavare. All rights reserved. |
* Copyright (C) 2005-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_bebox.c,v 1.3 2005/02/23 22:08:19 debug Exp $ |
* $Id: dev_bebox.c,v 1.13 2007/02/16 19:57:56 debug Exp $ |
29 |
* |
* |
30 |
* Emulation of BeBox motherboard registers. See the following URL for more |
* Emulation of BeBox motherboard registers (and interrupt controller). |
31 |
* information: |
* See the following URL for more information: |
32 |
* |
* |
33 |
* http://www.bebox.nu/history.php?s=history/benews/benews27 |
* http://www.bebox.nu/history.php?s=history/benews/benews27 |
34 |
|
* |
35 |
|
* These interrupt numbers are from NetBSD's bebox/extint.c: |
36 |
|
* |
37 |
|
* serial3 6 |
38 |
|
* serial4 7 |
39 |
|
* midi1 8 |
40 |
|
* midi2 9 |
41 |
|
* scsi 10 |
42 |
|
* pci1 11 |
43 |
|
* pci2 12 |
44 |
|
* pci3 13 |
45 |
|
* sound 14 |
46 |
|
* 8259 26 |
47 |
|
* irda 27 |
48 |
|
* a2d 28 |
49 |
|
* geekport 29 |
50 |
|
* |
51 |
|
* Note that these are in IBM order, i.e. reversed. So 8259 interrupts |
52 |
|
* go to interrupt 31 - 26 = 5, when using normal numbers. |
53 |
|
* |
54 |
|
* Interrupt routing should work to both CPUs, but I've only ever seen the |
55 |
|
* first CPU being used by NetBSD/bebox, so the second CPU is untested :-) |
56 |
*/ |
*/ |
57 |
|
|
58 |
#include <stdio.h> |
#include <stdio.h> |
61 |
|
|
62 |
#include "cpu.h" |
#include "cpu.h" |
63 |
#include "device.h" |
#include "device.h" |
64 |
|
#include "interrupt.h" |
65 |
#include "machine.h" |
#include "machine.h" |
66 |
#include "memory.h" |
#include "memory.h" |
67 |
#include "misc.h" |
#include "misc.h" |
68 |
|
|
69 |
|
|
70 |
struct bebox_data { |
struct bebox_data { |
71 |
|
struct interrupt cpu_irq[2]; |
72 |
|
|
73 |
/* The 5 motherboard registers: */ |
/* The 5 motherboard registers: */ |
74 |
uint32_t cpu0_intmask; |
uint32_t cpu0_int_mask; |
75 |
uint32_t cpu1_intmask; |
uint32_t cpu1_int_mask; |
76 |
uint32_t int_source; |
uint32_t int_status; |
77 |
uint32_t xpi; |
uint32_t xpi; |
78 |
uint32_t resets; |
uint32_t resets; |
79 |
}; |
}; |
80 |
|
|
81 |
|
|
82 |
|
static void bebox_interrupt_assert(struct interrupt *interrupt) |
83 |
|
{ |
84 |
|
struct bebox_data *d = interrupt->extra; |
85 |
|
d->int_status |= interrupt->line; |
86 |
|
|
87 |
|
/* printf("STATUS %08x CPU0 %08x CPU1 %08x\n", |
88 |
|
d->int_status, d->cpu0_int_mask, d->cpu1_int_mask); */ |
89 |
|
|
90 |
|
if (d->int_status & d->cpu0_int_mask) |
91 |
|
INTERRUPT_ASSERT(d->cpu_irq[0]); |
92 |
|
if (d->int_status & d->cpu1_int_mask) |
93 |
|
INTERRUPT_ASSERT(d->cpu_irq[1]); |
94 |
|
} |
95 |
|
static void bebox_interrupt_deassert(struct interrupt *interrupt) |
96 |
|
{ |
97 |
|
struct bebox_data *d = interrupt->extra; |
98 |
|
d->int_status &= ~interrupt->line; |
99 |
|
|
100 |
|
if (!(d->int_status & d->cpu0_int_mask)) |
101 |
|
INTERRUPT_DEASSERT(d->cpu_irq[0]); |
102 |
|
if (!(d->int_status & d->cpu1_int_mask)) |
103 |
|
INTERRUPT_DEASSERT(d->cpu_irq[1]); |
104 |
|
} |
105 |
|
|
106 |
|
|
107 |
/* |
/* |
108 |
* dev_bebox_access(): |
* check_cpu_masks(): |
109 |
|
* |
110 |
|
* BeBox interrupt enable bits are not allowed to be present in |
111 |
|
* both CPUs at the same time. |
112 |
*/ |
*/ |
113 |
int dev_bebox_access(struct cpu *cpu, struct memory *mem, |
static void check_cpu_masks(struct cpu *cpu, struct bebox_data *d) |
114 |
uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, |
{ |
115 |
void *extra) |
d->cpu0_int_mask &= 0x7fffffff; |
116 |
|
d->cpu1_int_mask &= 0x7fffffff; |
117 |
|
if ((d->cpu0_int_mask | d->cpu1_int_mask) != |
118 |
|
(d->cpu0_int_mask ^ d->cpu1_int_mask)) |
119 |
|
fatal("check_cpu_masks(): BeBox cpu int masks collide!\n"); |
120 |
|
} |
121 |
|
|
122 |
|
|
123 |
|
DEVICE_ACCESS(bebox) |
124 |
{ |
{ |
125 |
struct bebox_data *d = extra; |
struct bebox_data *d = extra; |
126 |
uint64_t idata = 0, odata = 0; |
uint64_t idata = 0, odata = 0; |
127 |
|
|
128 |
idata = memory_readmax64(cpu, data, len); |
if (writeflag == MEM_WRITE) |
129 |
|
idata = memory_readmax64(cpu, data, len); |
130 |
|
|
131 |
switch (relative_addr) { |
switch (relative_addr) { |
132 |
|
|
133 |
|
case 0x0f0: |
134 |
|
if (writeflag == MEM_READ) |
135 |
|
odata = d->cpu0_int_mask; |
136 |
|
else { |
137 |
|
if (idata & 0x80000000) |
138 |
|
d->cpu0_int_mask |= idata; |
139 |
|
else |
140 |
|
d->cpu0_int_mask &= ~idata; |
141 |
|
check_cpu_masks(cpu, d); |
142 |
|
} |
143 |
|
break; |
144 |
|
|
145 |
|
case 0x1f0: |
146 |
|
if (writeflag == MEM_READ) |
147 |
|
odata = d->cpu1_int_mask; |
148 |
|
else { |
149 |
|
if (idata & 0x80000000) |
150 |
|
d->cpu1_int_mask |= idata; |
151 |
|
else |
152 |
|
d->cpu1_int_mask &= ~idata; |
153 |
|
check_cpu_masks(cpu, d); |
154 |
|
} |
155 |
|
break; |
156 |
|
|
157 |
|
case 0x2f0: |
158 |
|
if (writeflag == MEM_READ) |
159 |
|
odata = d->int_status; |
160 |
|
else { |
161 |
|
if (idata & 0x80000000) |
162 |
|
d->int_status |= idata; |
163 |
|
else |
164 |
|
d->int_status &= ~idata; |
165 |
|
d->int_status &= 0x7fffffff; |
166 |
|
} |
167 |
|
break; |
168 |
|
|
169 |
case 0x3f0: |
case 0x3f0: |
170 |
if (writeflag == MEM_READ) { |
if (writeflag == MEM_READ) { |
171 |
odata = d->xpi; |
odata = d->xpi; |
196 |
} |
} |
197 |
|
|
198 |
|
|
199 |
/* |
DEVINIT(bebox) |
|
* devinit_bebox(): |
|
|
*/ |
|
|
int devinit_bebox(struct devinit *devinit) |
|
200 |
{ |
{ |
201 |
struct bebox_data *d; |
struct bebox_data *d; |
202 |
|
int i; |
203 |
|
char n[300]; |
204 |
|
struct machine *machine = devinit->machine; |
205 |
|
|
206 |
d = malloc(sizeof(struct bebox_data)); |
d = malloc(sizeof(struct bebox_data)); |
207 |
if (d == NULL) { |
if (d == NULL) { |
210 |
} |
} |
211 |
memset(d, 0, sizeof(struct bebox_data)); |
memset(d, 0, sizeof(struct bebox_data)); |
212 |
|
|
213 |
memory_device_register(devinit->machine->memory, devinit->name, |
/* Connect to the two BeBox CPUs: */ |
214 |
0x7ffff000, 0x500, dev_bebox_access, d, MEM_DEFAULT, NULL); |
for (i=0; i<2; i++) { |
215 |
|
if (i >= machine->ncpus) { |
216 |
|
fatal("FATAL ERROR: The machine seem to be " |
217 |
|
"lacking cpu nr %i (0-based)\n", i); |
218 |
|
exit(1); |
219 |
|
} |
220 |
|
|
221 |
|
snprintf(n, sizeof(n), "%s.cpu[%i]", machine->path, i); |
222 |
|
INTERRUPT_CONNECT(n, d->cpu_irq[i]); |
223 |
|
} |
224 |
|
|
225 |
|
/* |
226 |
|
* Register the 32 BeBox interrupts: |
227 |
|
* |
228 |
|
* NOTE: They are registered on cpu[0], but the interrupt assert/ |
229 |
|
* deassert routines in this file make sure that the interrupts |
230 |
|
* are routed to the correct cpu! |
231 |
|
*/ |
232 |
|
for (i=0; i<32; i++) { |
233 |
|
struct interrupt template; |
234 |
|
snprintf(n, sizeof(n), "%s.bebox.%i", |
235 |
|
devinit->interrupt_path, i); |
236 |
|
memset(&template, 0, sizeof(template)); |
237 |
|
template.line = 1 << i; |
238 |
|
template.name = n; |
239 |
|
template.extra = d; |
240 |
|
template.interrupt_assert = bebox_interrupt_assert; |
241 |
|
template.interrupt_deassert = bebox_interrupt_deassert; |
242 |
|
interrupt_handler_register(&template); |
243 |
|
} |
244 |
|
|
245 |
|
memory_device_register(machine->memory, devinit->name, |
246 |
|
0x7ffff000, 0x500, dev_bebox_access, d, DM_DEFAULT, NULL); |
247 |
|
|
248 |
|
devinit->return_ptr = d; |
249 |
|
|
250 |
return 1; |
return 1; |
251 |
} |
} |