/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (hide annotations)
Mon Oct 8 16:20:26 2007 UTC (13 years, 3 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 dpavlin 4 /*
2 dpavlin 22 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 dpavlin 4 *
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 dpavlin 28 * $Id: dev_mp.c,v 1.37 2006/07/01 21:15:46 debug Exp $
29 dpavlin 4 *
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 dpavlin 24 #include "testmachine/dev_mp.h"
47 dpavlin 4
48 dpavlin 24
49 dpavlin 4 struct mp_data {
50     struct cpu **cpus;
51     uint64_t startup_addr;
52     uint64_t stack_addr;
53     uint64_t pause_addr;
54 dpavlin 8
55     /* Each CPU has an array of pending ipis. */
56     int *n_pending_ipis;
57     int **ipi;
58 dpavlin 4 };
59    
60    
61 dpavlin 8 extern int single_step;
62    
63    
64 dpavlin 4 /*
65     * dev_mp_access():
66     */
67 dpavlin 22 DEVICE_ACCESS(mp)
68 dpavlin 4 {
69     struct mp_data *d = extra;
70     int i, which_cpu;
71     uint64_t idata = 0, odata = 0;
72    
73 dpavlin 18 if (writeflag == MEM_WRITE)
74     idata = memory_readmax64(cpu, data, len);
75 dpavlin 4
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 dpavlin 24 /* Pause all cpus except a specific CPU: */
125 dpavlin 4 which_cpu = idata;
126    
127     for (i=0; i<cpu->machine->ncpus; i++)
128 dpavlin 22 if (i != which_cpu)
129 dpavlin 4 d->cpus[i]->running = 0;
130     break;
131    
132     case DEV_MP_UNPAUSE_CPU:
133 dpavlin 22 /* Unpause a specific CPU: */
134 dpavlin 4 which_cpu = idata;
135 dpavlin 22
136     if (which_cpu >= 0 && which_cpu <cpu->machine->ncpus)
137     d->cpus[which_cpu]->running = 1;
138 dpavlin 4 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 dpavlin 22 /*
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 dpavlin 4 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 dpavlin 8 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 dpavlin 14 case DEV_MP_NCYCLES:
231     /*
232 dpavlin 28 * 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 dpavlin 14 */
240 dpavlin 28 odata = cpu->machine->ninstrs;
241 dpavlin 14 break;
242    
243 dpavlin 4 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 dpavlin 22 DEVINIT(mp)
256 dpavlin 4 {
257     struct mp_data *d;
258 dpavlin 8 int n;
259    
260 dpavlin 4 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 dpavlin 8 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 dpavlin 4
280 dpavlin 8 memory_device_register(devinit->machine->memory, devinit->name,
281 dpavlin 20 devinit->addr, DEV_MP_LENGTH, dev_mp_access, d, DM_DEFAULT, NULL);
282 dpavlin 8
283 dpavlin 4 return 1;
284     }
285    

  ViewVC Help
Powered by ViewVC 1.1.26