/[gxemul]/upstream/0.3.2/src/cpu_urisc.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 /upstream/0.3.2/src/cpu_urisc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5 - (hide annotations)
Mon Oct 8 16:18:06 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 10994 byte(s)
0.3.2
1 dpavlin 2 /*
2     * Copyright (C) 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: cpu_urisc.c,v 1.6 2005/04/04 20:08:58 debug Exp $
29     *
30     * URISC CPU emulation. See http://en.wikipedia.org/wiki/URISC for more
31     * information about the "instruction set".
32     *
33     *
34     * NOTE:
35     *
36     * The PC should always be in sync with the memory word at address 0.
37     *
38     * Optional: The accumulator register should always be in sync with the
39     * memory word following the word at address 0.
40     *
41     * This implementation of URISC emulation supports any wordlen 8*n,
42     * where 1 <= n <= 8. (I think.)
43     *
44     *
45     * TODO:
46     *
47     * o) Little-endian support?
48     */
49    
50     #include <stdio.h>
51     #include <stdlib.h>
52     #include <string.h>
53    
54     #include "misc.h"
55    
56    
57     #ifndef ENABLE_URISC
58    
59    
60     #include "cpu_urisc.h"
61    
62    
63     /*
64     * urisc_cpu_family_init():
65     *
66     * Bogus, when ENABLE_URISC isn't defined.
67     */
68     int urisc_cpu_family_init(struct cpu_family *fp)
69     {
70     return 0;
71     }
72    
73    
74     #else /* ENABLE_URISC */
75    
76    
77     #include "cpu.h"
78     #include "cpu_urisc.h"
79     #include "machine.h"
80     #include "memory.h"
81     #include "symbol.h"
82    
83    
84     extern volatile int single_step;
85     extern int old_show_trace_tree;
86     extern int old_instruction_trace;
87     extern int old_quiet_mode;
88     extern int quiet_mode;
89    
90    
91     /*
92     * urisc_cpu_new():
93     *
94     * Create a new URISC cpu object.
95     */
96     struct cpu *urisc_cpu_new(struct memory *mem, struct machine *machine,
97     int cpu_id, char *cpu_type_name)
98     {
99     struct cpu *cpu;
100    
101     if (cpu_type_name == NULL || strcmp(cpu_type_name, "URISC") != 0)
102     return NULL;
103    
104     cpu = malloc(sizeof(struct cpu));
105     if (cpu == NULL) {
106     fprintf(stderr, "out of memory\n");
107     exit(1);
108     }
109    
110     memset(cpu, 0, sizeof(struct cpu));
111     cpu->memory_rw = urisc_memory_rw;
112     cpu->name = cpu_type_name;
113     cpu->mem = mem;
114     cpu->machine = machine;
115     cpu->cpu_id = cpu_id;
116     cpu->byte_order = EMUL_BIG_ENDIAN;
117    
118     cpu->cd.urisc.wordlen = 32;
119     cpu->cd.urisc.acc_in_mem = 0;
120     cpu->cd.urisc.halt_on_zero = 1;
121    
122     /* Only show name for CPU nr 0 (in SMP machines): */
123     if (cpu_id == 0) {
124     debug("%s", cpu->name);
125     debug(" (%i-bit, ", cpu->cd.urisc.wordlen);
126     debug("%s-endian", cpu->byte_order == EMUL_BIG_ENDIAN?
127     "big" : "little");
128     if (cpu->cd.urisc.acc_in_mem)
129     debug(", memory-mapped accumulator");
130     debug(")");
131     }
132    
133     return cpu;
134     }
135    
136    
137     /*
138     * urisc_cpu_dumpinfo():
139     */
140     void urisc_cpu_dumpinfo(struct cpu *cpu)
141     {
142     debug(" (%i-bit, ", cpu->cd.urisc.wordlen);
143     debug("%s-endian", cpu->byte_order == EMUL_BIG_ENDIAN?
144     "big" : "little");
145     if (cpu->cd.urisc.acc_in_mem)
146     debug(", memory-mapped accumulator");
147     debug(")\n");
148     }
149    
150    
151     /*
152     * urisc_cpu_list_available_types():
153     *
154     * Print a list of available URISC CPU types.
155     */
156     void urisc_cpu_list_available_types(void)
157     {
158     /* TODO */
159    
160     debug("URISC\n");
161     }
162    
163    
164     /*
165     * urisc_cpu_register_dump():
166     *
167     * Dump cpu registers in a relatively readable format.
168     *
169     * gprs: set to non-zero to dump GPRs and some special-purpose registers.
170     * coprocs: set bit 0..3 to dump registers in coproc 0..3.
171     */
172     void urisc_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
173     {
174     char *symbol;
175     uint64_t offset;
176     int x = cpu->cpu_id;
177     char tmps[100];
178    
179     symbol = get_symbol_name(&cpu->machine->symbol_context,
180     cpu->pc, &offset);
181     sprintf(tmps, "cpu%%i: pc = 0x%%0%illx", (cpu->cd.urisc.wordlen/4));
182     debug(tmps, x, (long long)cpu->pc);
183     debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
184     sprintf(tmps, "cpu%%i: acc = 0x%%0%illx\n", (cpu->cd.urisc.wordlen/4));
185     debug(tmps, x, (long long)cpu->cd.urisc.acc);
186     }
187    
188    
189     /*
190     * urisc_cpu_disassemble_instr():
191     *
192     * Convert an instruction word into human readable format, for instruction
193     * tracing.
194     *
195     * If running is 1, cpu->pc should be the address of the instruction.
196     *
197     * If running is 0, things that depend on the runtime environment (eg.
198     * register contents) will not be shown, and addr will be used instead of
199     * cpu->pc for relative addresses.
200     */
201     int urisc_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr,
202     int running, uint64_t dumpaddr, int bintrans)
203     {
204     uint64_t offset;
205     char *symbol;
206     int i, nbytes = cpu->cd.urisc.wordlen / 8;
207     char tmps[50];
208    
209     if (running)
210     dumpaddr = cpu->pc;
211    
212     symbol = get_symbol_name(&cpu->machine->symbol_context,
213     dumpaddr, &offset);
214     if (symbol != NULL && offset==0)
215     debug("<%s>\n", symbol);
216    
217     if (cpu->machine->ncpus > 1 && running)
218     debug("cpu%i: ", cpu->cpu_id);
219     sprintf(tmps, "0x%%0%illx: 0x", nbytes * 2);
220     debug(tmps, (long long)dumpaddr);
221    
222     /* TODO: Little-endian? */
223    
224     for (i=0; i<nbytes; i++)
225     debug("%02x", instr[i]);
226    
227     if (!running)
228     debug("\n");
229    
230     return nbytes;
231     }
232    
233    
234     /*
235     * urisc_cpu_register_match():
236     */
237     void urisc_cpu_register_match(struct machine *m, char *name,
238     int writeflag, uint64_t *valuep, int *match_register)
239     {
240     int i, cpunr = 0;
241     int nbytes = m->cpus[cpunr]->cd.urisc.wordlen / 8;
242    
243     /* CPU number: */
244     /* TODO */
245    
246     /* Register name: */
247     if (strcasecmp(name, "pc") == 0) {
248     if (writeflag) {
249     unsigned char buf[8];
250     m->cpus[cpunr]->pc = *valuep;
251    
252     for (i=0; i<nbytes; i++)
253     buf[nbytes-1-i] = *valuep >> (8*i);
254    
255     m->cpus[cpunr]->memory_rw(m->cpus[cpunr],
256     m->cpus[cpunr]->mem, 0, buf,
257     m->cpus[cpunr]->cd.urisc.wordlen / 8, MEM_WRITE,
258     CACHE_NONE | NO_EXCEPTIONS);
259     } else
260     *valuep = m->cpus[cpunr]->pc;
261     *match_register = 1;
262     }
263    
264     if (strcasecmp(name, "acc") == 0) {
265     if (writeflag) {
266     unsigned char buf[8];
267     m->cpus[cpunr]->cd.urisc.acc = *valuep;
268    
269     if (m->cpus[cpunr]->cd.urisc.acc_in_mem) {
270     for (i=0; i<nbytes; i++)
271     buf[nbytes-1-i] = *valuep >> (8*i);
272    
273     m->cpus[cpunr]->memory_rw(m->cpus[cpunr],
274     m->cpus[cpunr]->mem,
275     m->cpus[cpunr]->cd.urisc.wordlen / 8,
276     buf, m->cpus[cpunr]->cd.urisc.wordlen / 8,
277     MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS);
278     }
279     } else
280     *valuep = m->cpus[cpunr]->cd.urisc.acc;
281     *match_register = 1;
282     }
283     }
284    
285    
286     /*
287     * urisc_cpu_run_instr():
288     *
289     * Execute one instruction on a specific CPU.
290     *
291     * Return value is the number of instructions executed during this call,
292     * 0 if no instruction was executed.
293     */
294     int urisc_cpu_run_instr(struct emul *emul, struct cpu *cpu)
295     {
296     unsigned char buf[8];
297     unsigned char instr[8];
298     uint64_t addr, data, mask = (uint64_t) -1;
299     int skip = 0, i, nbytes = cpu->cd.urisc.wordlen / 8;
300     char tmps[100];
301    
302     if (cpu->cd.urisc.wordlen < 64)
303     mask = ((int64_t)1 << cpu->cd.urisc.wordlen) - 1;
304    
305     /* Read PC from memory, just to be sure: */
306     cpu->memory_rw(cpu, cpu->mem, 0, buf, nbytes, MEM_READ, CACHE_DATA);
307     cpu->pc = 0;
308     for (i=0; i<nbytes; i++) {
309     cpu->pc <<= 8;
310     cpu->pc += buf[i];
311     }
312    
313     addr = cpu->pc;
314    
315     if (cpu->cd.urisc.halt_on_zero && cpu->pc <= 4) {
316     cpu->running = 0;
317     return 0;
318     }
319    
320     /* Advance the program counter: */
321     cpu->pc += nbytes;
322     cpu->pc &= mask;
323     for (i=0; i<nbytes; i++)
324     buf[nbytes-1-i] = cpu->pc >> (8*i);
325     cpu->memory_rw(cpu, cpu->mem, 0, buf, nbytes, MEM_WRITE, CACHE_DATA);
326    
327     /* Read an instruction: */
328     cpu->memory_rw(cpu, cpu->mem, addr, instr, nbytes, MEM_READ,
329     CACHE_INSTRUCTION);
330    
331     if (cpu->machine->instruction_trace) {
332     cpu->pc -= nbytes;
333     urisc_cpu_disassemble_instr(cpu, instr, 1, 0, 0);
334     cpu->pc += nbytes;
335     }
336    
337     addr = 0;
338     for (i=0; i<nbytes; i++) {
339     addr <<= 8;
340     addr += instr[i];
341     }
342    
343     /* Read data from memory: */
344     cpu->memory_rw(cpu, cpu->mem, addr, buf, cpu->cd.urisc.wordlen/8,
345     MEM_READ, CACHE_DATA);
346     data = 0;
347     for (i=0; i<nbytes; i++) {
348     data <<= 8;
349     data += buf[i];
350     }
351    
352     if (cpu->machine->instruction_trace) {
353     sprintf(tmps, "\t[mem=0x%%0%illx", nbytes * 2);
354     debug(tmps, (long long)data);
355     sprintf(tmps, "; acc: 0x%%0%illx", nbytes * 2);
356     debug(tmps, (long long)cpu->cd.urisc.acc);
357     }
358    
359     skip = (uint64_t)data < (uint64_t)cpu->cd.urisc.acc;
360    
361     data -= cpu->cd.urisc.acc;
362     data &= mask;
363    
364     cpu->cd.urisc.acc = data;
365    
366     if (cpu->machine->instruction_trace) {
367     sprintf(tmps, " ==> 0x%%0%illx", nbytes * 2);
368     debug(tmps, (long long)cpu->cd.urisc.acc);
369     if (skip)
370     debug(", SKIP");
371     debug("]\n");
372     }
373    
374     /* Write back result to both memory and the accumulator: */
375     for (i=0; i<nbytes; i++)
376     buf[nbytes-1-i] = cpu->cd.urisc.acc >> (8*i);
377     cpu->memory_rw(cpu, cpu->mem, addr, buf, nbytes, MEM_WRITE, CACHE_DATA);
378     if (cpu->cd.urisc.acc_in_mem)
379     cpu->memory_rw(cpu, cpu->mem, nbytes, buf,
380     nbytes, MEM_WRITE, CACHE_DATA);
381    
382     /* Skip on borrow: */
383     if (skip) {
384     /* Read PC from memory: */
385     cpu->memory_rw(cpu, cpu->mem, 0, buf, nbytes,
386     MEM_READ, CACHE_DATA);
387     cpu->pc = 0;
388     for (i=0; i<nbytes; i++) {
389     cpu->pc <<= 8;
390     cpu->pc += buf[i];
391     }
392    
393     /* Advance the program counter: */
394     cpu->pc += nbytes;
395     cpu->pc &= mask;
396    
397     for (i=0; i<nbytes; i++)
398     buf[nbytes-1-i] = cpu->pc >> (8*i);
399     cpu->memory_rw(cpu, cpu->mem, 0, buf, nbytes, MEM_WRITE,
400     CACHE_DATA);
401     }
402    
403     return 1;
404     }
405    
406    
407     #define CPU_RUN urisc_cpu_run
408     #define CPU_RINSTR urisc_cpu_run_instr
409     #define CPU_RUN_URISC
410     #include "cpu_run.c"
411     #undef CPU_RINSTR
412     #undef CPU_RUN_URISC
413     #undef CPU_RUN
414    
415    
416     #define MEMORY_RW urisc_memory_rw
417     #define MEM_URISC
418     #include "memory_rw.c"
419     #undef MEM_URISC
420     #undef MEMORY_RW
421    
422    
423     /*
424     * urisc_cpu_family_init():
425     *
426     * Fill in the cpu_family struct for URISC.
427     */
428     int urisc_cpu_family_init(struct cpu_family *fp)
429     {
430     fp->name = "URISC";
431     fp->cpu_new = urisc_cpu_new;
432     fp->list_available_types = urisc_cpu_list_available_types;
433     fp->register_match = urisc_cpu_register_match;
434     fp->disassemble_instr = urisc_cpu_disassemble_instr;
435     fp->register_dump = urisc_cpu_register_dump;
436     fp->run = urisc_cpu_run;
437     fp->dumpinfo = urisc_cpu_dumpinfo;
438     return 1;
439     }
440    
441     #endif /* ENABLE_URISC */

  ViewVC Help
Powered by ViewVC 1.1.26