/[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 28 - (show annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 7802 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

==============  RELEASE 0.4.1  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26