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

Contents of /upstream/0.3.2/src/cpu_urisc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5 - (show annotations)
Mon Oct 8 16:18:06 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 10994 byte(s)
0.3.2
1 /*
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