/[gxemul]/trunk/src/devices/dev_mp.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/devices/dev_mp.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8 - (show annotations)
Mon Oct 8 16:18:19 2007 UTC (14 years, 3 months ago) by dpavlin
File MIME type: text/plain
File size: 7484 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.777 2005/06/12 12:31:52 debug Exp $
==============  RELEASE 0.3.3.1  ==============

20050609	Adding simple MIPS IPIs (to dev_mp).
20050611	Adding an ugly hack to track down low-reference bugs
		(define TRACE_NULL_CRASHES, or configure --tracenull).
		Other minor updates.
20050612	Adding a dummy evbmips mode.

==============  RELEASE 0.3.3.2  ==============


1 /*
2 * Copyright (C) 2003-2005 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 * $Id: dev_mp.c,v 1.27 2005/06/11 20:51:41 debug Exp $
29 *
30 * This is a fake multiprocessor (MP) device. It can be useful for
31 * theoretical experiments, but probably bares no resemblance to any
32 * multiprocessor controller used in any real machine.
33 */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "cpu.h"
40 #include "cpu_mips.h"
41 #include "device.h"
42 #include "machine.h"
43 #include "memory.h"
44 #include "misc.h"
45 #include "mp.h"
46
47
48 struct mp_data {
49 struct cpu **cpus;
50 uint64_t startup_addr;
51 uint64_t stack_addr;
52 uint64_t pause_addr;
53
54 /* Each CPU has an array of pending ipis. */
55 int *n_pending_ipis;
56 int **ipi;
57 };
58
59
60 extern int single_step;
61
62
63 /*
64 * dev_mp_access():
65 */
66 int dev_mp_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr,
67 unsigned char *data, size_t len, int writeflag, void *extra)
68 {
69 struct mp_data *d = extra;
70 int i, which_cpu;
71 uint64_t idata = 0, odata = 0;
72
73 idata = memory_readmax64(cpu, data, len);
74
75 /*
76 * NOTE: It is up to the user of this device to read or write
77 * correct addresses. (A write to NCPUS is pretty useless,
78 * for example.)
79 */
80
81 switch (relative_addr) {
82
83 case DEV_MP_WHOAMI:
84 odata = cpu->cpu_id;
85 break;
86
87 case DEV_MP_NCPUS:
88 odata = cpu->machine->ncpus;
89 break;
90
91 case DEV_MP_STARTUPCPU:
92 which_cpu = idata;
93 d->cpus[which_cpu]->pc = d->startup_addr;
94 switch (cpu->machine->arch) {
95 case ARCH_MIPS:
96 d->cpus[which_cpu]->cd.mips.gpr[MIPS_GPR_SP] =
97 d->stack_addr;
98 break;
99 case ARCH_PPC:
100 d->cpus[which_cpu]->cd.ppc.gpr[1] = d->stack_addr;
101 break;
102 default:
103 fatal("dev_mp(): DEV_MP_STARTUPCPU: not for this"
104 " arch yet!\n");
105 exit(1);
106 }
107 d->cpus[which_cpu]->running = 1;
108 /* debug("[ dev_mp: starting up cpu%i at 0x%llx ]\n",
109 which_cpu, (long long)d->startup_addr); */
110 break;
111
112 case DEV_MP_STARTUPADDR:
113 if (len==4 && (idata >> 32) == 0 && (idata & 0x80000000ULL))
114 idata |= 0xffffffff00000000ULL;
115 d->startup_addr = idata;
116 break;
117
118 case DEV_MP_PAUSE_ADDR:
119 d->pause_addr = idata;
120 break;
121
122 case DEV_MP_PAUSE_CPU:
123 /* Pause all cpus except our selves: */
124 which_cpu = idata;
125
126 for (i=0; i<cpu->machine->ncpus; i++)
127 if (i!=which_cpu)
128 d->cpus[i]->running = 0;
129 break;
130
131 case DEV_MP_UNPAUSE_CPU:
132 /* Unpause all cpus except our selves: */
133 which_cpu = idata;
134 for (i=0; i<cpu->machine->ncpus; i++)
135 if (i!=which_cpu)
136 d->cpus[i]->running = 1;
137 break;
138
139 case DEV_MP_STARTUPSTACK:
140 if (len == 4 && (idata >> 32) == 0 && (idata & 0x80000000ULL))
141 idata |= 0xffffffff00000000ULL;
142 d->stack_addr = idata;
143 break;
144
145 case DEV_MP_HARDWARE_RANDOM:
146 /* Return (up to) 64 bits of "hardware random": */
147 odata = random();
148 odata = (odata << 31) ^ random();
149 odata = (odata << 31) ^ random();
150 break;
151
152 case DEV_MP_MEMORY:
153 /*
154 * Return the number of bytes of memory in the system.
155 *
156 * (It is assumed to be located at physical address 0.
157 * It is actually located at machine->memory_offset_in_mb
158 * but that is only used for SGI emulation so far.)
159 */
160 odata = cpu->machine->physical_ram_in_mb * 1048576;
161 break;
162
163 case DEV_MP_IPI_ONE:
164 case DEV_MP_IPI_MANY:
165 /*
166 * idata should be of the form:
167 *
168 * (IPI_nr << 16) | cpu_id
169 *
170 * This will send an Inter-processor interrupt to a specific
171 * CPU. (DEV_MP_IPI_MANY sends to all _except_ the specific
172 * CPU.)
173 *
174 * Sending an IPI means adding the IPI last in the list of
175 * pending IPIs, and asserting the IPI "pin".
176 */
177 which_cpu = (idata & 0xffff);
178 for (i=0; i<cpu->machine->ncpus; i++) {
179 int send_it = 0;
180 if (relative_addr == DEV_MP_IPI_ONE && i == which_cpu)
181 send_it = 1;
182 if (relative_addr == DEV_MP_IPI_MANY && i != which_cpu)
183 send_it = 1;
184 if (send_it) {
185 d->n_pending_ipis[i] ++;
186 d->ipi[i] = realloc(d->ipi[i],
187 d->n_pending_ipis[i] * sizeof(int));
188 if (d->ipi[i] == NULL) {
189 fprintf(stderr, "out of memory\n");
190 exit(1);
191 }
192 /* Add the IPI last in the array: */
193 d->ipi[i][d->n_pending_ipis[i] - 1] =
194 idata >> 16;
195 cpu_interrupt(d->cpus[i], MIPS_IPI_INT);
196 }
197 }
198 break;
199
200 case DEV_MP_IPI_READ:
201 /*
202 * If the current CPU has any IPIs pending, accessing this
203 * address reads the IPI value. (Writing to this address
204 * discards _all_ pending IPIs.) If there is no pending
205 * IPI, then 0 is returned. Usage of the value 0 for real
206 * IPIs should thus be avoided.
207 */
208 if (writeflag == MEM_WRITE) {
209 d->n_pending_ipis[cpu->cpu_id] = 0;
210 }
211 odata = 0;
212 if (d->n_pending_ipis[cpu->cpu_id] > 0) {
213 odata = d->ipi[cpu->cpu_id][0];
214 if (d->n_pending_ipis[cpu->cpu_id]-- > 1)
215 memmove(&d->ipi[cpu->cpu_id][0],
216 &d->ipi[cpu->cpu_id][1],
217 d->n_pending_ipis[cpu->cpu_id]);
218 }
219 /* Deassert the interrupt, if there are no pending IPIs: */
220 if (d->n_pending_ipis[cpu->cpu_id] == 0)
221 cpu_interrupt_ack(d->cpus[cpu->cpu_id], MIPS_IPI_INT);
222 break;
223
224 default:
225 fatal("[ dev_mp: unimplemented relative addr 0x%x ]\n",
226 relative_addr);
227 }
228
229 if (writeflag == MEM_READ)
230 memory_writemax64(cpu, data, len, odata);
231
232 return 1;
233 }
234
235
236 /*
237 * devinit_mp():
238 */
239 int devinit_mp(struct devinit *devinit)
240 {
241 struct mp_data *d;
242 int n;
243
244 d = malloc(sizeof(struct mp_data));
245 if (d == NULL) {
246 fprintf(stderr, "out of memory\n");
247 exit(1);
248 }
249 memset(d, 0, sizeof(struct mp_data));
250 d->cpus = devinit->machine->cpus;
251 d->startup_addr = INITIAL_PC;
252 d->stack_addr = INITIAL_STACK_POINTER;
253
254 n = devinit->machine->ncpus;
255 d->n_pending_ipis = malloc(n * sizeof(int));
256 d->ipi = malloc(n * sizeof(int *));
257 if (d->ipi == NULL || d->n_pending_ipis == NULL) {
258 fprintf(stderr, "out of memory\n");
259 exit(1);
260 }
261 memset(d->n_pending_ipis, 0, sizeof(int) * n);
262 memset(d->ipi, 0, sizeof(int *) * n);
263
264 memory_device_register(devinit->machine->memory, devinit->name,
265 devinit->addr, DEV_MP_LENGTH, dev_mp_access, d, MEM_DEFAULT, NULL);
266
267 return 1;
268 }
269

  ViewVC Help
Powered by ViewVC 1.1.26