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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11 - (show annotations)
Mon Oct 8 16:18:31 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 10748 byte(s)
0.3.4
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.8 2005/06/26 22:23:42 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 int urisc_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine,
97 int cpu_id, char *cpu_type_name)
98 {
99 if (strcmp(cpu_type_name, "URISC") != 0)
100 return 0;
101
102 cpu->memory_rw = urisc_memory_rw;
103 cpu->byte_order = EMUL_BIG_ENDIAN;
104
105 cpu->cd.urisc.wordlen = 32;
106 cpu->cd.urisc.acc_in_mem = 0;
107 cpu->cd.urisc.halt_on_zero = 1;
108
109 /* Only show name for CPU nr 0 (in SMP machines): */
110 if (cpu_id == 0) {
111 debug("%s", cpu->name);
112 debug(" (%i-bit, ", cpu->cd.urisc.wordlen);
113 debug("%s-endian", cpu->byte_order == EMUL_BIG_ENDIAN?
114 "big" : "little");
115 if (cpu->cd.urisc.acc_in_mem)
116 debug(", memory-mapped accumulator");
117 debug(")");
118 }
119
120 return 1;
121 }
122
123
124 /*
125 * urisc_cpu_dumpinfo():
126 */
127 void urisc_cpu_dumpinfo(struct cpu *cpu)
128 {
129 debug(" (%i-bit, ", cpu->cd.urisc.wordlen);
130 debug("%s-endian", cpu->byte_order == EMUL_BIG_ENDIAN?
131 "big" : "little");
132 if (cpu->cd.urisc.acc_in_mem)
133 debug(", memory-mapped accumulator");
134 debug(")\n");
135 }
136
137
138 /*
139 * urisc_cpu_list_available_types():
140 *
141 * Print a list of available URISC CPU types.
142 */
143 void urisc_cpu_list_available_types(void)
144 {
145 /* TODO */
146
147 debug("URISC\n");
148 }
149
150
151 /*
152 * urisc_cpu_register_dump():
153 *
154 * Dump cpu registers in a relatively readable format.
155 *
156 * gprs: set to non-zero to dump GPRs and some special-purpose registers.
157 * coprocs: set bit 0..3 to dump registers in coproc 0..3.
158 */
159 void urisc_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
160 {
161 char *symbol;
162 uint64_t offset;
163 int x = cpu->cpu_id;
164 char tmps[100];
165
166 symbol = get_symbol_name(&cpu->machine->symbol_context,
167 cpu->pc, &offset);
168 snprintf(tmps, sizeof(tmps), "cpu%%i: pc = 0x%%0%illx",
169 (cpu->cd.urisc.wordlen/4));
170 debug(tmps, x, (long long)cpu->pc);
171 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
172 snprintf(tmps, sizeof(tmps), "cpu%%i: acc = 0x%%0%illx\n",
173 (cpu->cd.urisc.wordlen/4));
174 debug(tmps, x, (long long)cpu->cd.urisc.acc);
175 }
176
177
178 /*
179 * urisc_cpu_disassemble_instr():
180 *
181 * Convert an instruction word into human readable format, for instruction
182 * tracing.
183 *
184 * If running is 1, cpu->pc should be the address of the instruction.
185 *
186 * If running is 0, things that depend on the runtime environment (eg.
187 * register contents) will not be shown, and addr will be used instead of
188 * cpu->pc for relative addresses.
189 */
190 int urisc_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr,
191 int running, uint64_t dumpaddr, int bintrans)
192 {
193 uint64_t offset;
194 char *symbol;
195 int i, nbytes = cpu->cd.urisc.wordlen / 8;
196 char tmps[50];
197
198 if (running)
199 dumpaddr = cpu->pc;
200
201 symbol = get_symbol_name(&cpu->machine->symbol_context,
202 dumpaddr, &offset);
203 if (symbol != NULL && offset==0)
204 debug("<%s>\n", symbol);
205
206 if (cpu->machine->ncpus > 1 && running)
207 debug("cpu%i: ", cpu->cpu_id);
208 snprintf(tmps, sizeof(tmps), "0x%%0%illx: 0x", nbytes * 2);
209 debug(tmps, (long long)dumpaddr);
210
211 /* TODO: Little-endian? */
212
213 for (i=0; i<nbytes; i++)
214 debug("%02x", instr[i]);
215
216 if (!running)
217 debug("\n");
218
219 return nbytes;
220 }
221
222
223 /*
224 * urisc_cpu_register_match():
225 */
226 void urisc_cpu_register_match(struct machine *m, char *name,
227 int writeflag, uint64_t *valuep, int *match_register)
228 {
229 int i, cpunr = 0;
230 int nbytes = m->cpus[cpunr]->cd.urisc.wordlen / 8;
231
232 /* CPU number: */
233 /* TODO */
234
235 /* Register name: */
236 if (strcasecmp(name, "pc") == 0) {
237 if (writeflag) {
238 unsigned char buf[8];
239 m->cpus[cpunr]->pc = *valuep;
240
241 for (i=0; i<nbytes; i++)
242 buf[nbytes-1-i] = *valuep >> (8*i);
243
244 m->cpus[cpunr]->memory_rw(m->cpus[cpunr],
245 m->cpus[cpunr]->mem, 0, buf,
246 m->cpus[cpunr]->cd.urisc.wordlen / 8, MEM_WRITE,
247 CACHE_NONE | NO_EXCEPTIONS);
248 } else
249 *valuep = m->cpus[cpunr]->pc;
250 *match_register = 1;
251 }
252
253 if (strcasecmp(name, "acc") == 0) {
254 if (writeflag) {
255 unsigned char buf[8];
256 m->cpus[cpunr]->cd.urisc.acc = *valuep;
257
258 if (m->cpus[cpunr]->cd.urisc.acc_in_mem) {
259 for (i=0; i<nbytes; i++)
260 buf[nbytes-1-i] = *valuep >> (8*i);
261
262 m->cpus[cpunr]->memory_rw(m->cpus[cpunr],
263 m->cpus[cpunr]->mem,
264 m->cpus[cpunr]->cd.urisc.wordlen / 8,
265 buf, m->cpus[cpunr]->cd.urisc.wordlen / 8,
266 MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS);
267 }
268 } else
269 *valuep = m->cpus[cpunr]->cd.urisc.acc;
270 *match_register = 1;
271 }
272 }
273
274
275 /*
276 * urisc_cpu_run_instr():
277 *
278 * Execute one instruction on a specific CPU.
279 *
280 * Return value is the number of instructions executed during this call,
281 * 0 if no instruction was executed.
282 */
283 int urisc_cpu_run_instr(struct emul *emul, struct cpu *cpu)
284 {
285 unsigned char buf[8];
286 unsigned char instr[8];
287 uint64_t addr, data, mask = (uint64_t) -1;
288 int skip = 0, i, nbytes = cpu->cd.urisc.wordlen / 8;
289 char tmps[100];
290
291 if (cpu->cd.urisc.wordlen < 64)
292 mask = ((int64_t)1 << cpu->cd.urisc.wordlen) - 1;
293
294 /* Read PC from memory, just to be sure: */
295 cpu->memory_rw(cpu, cpu->mem, 0, buf, nbytes, MEM_READ, CACHE_DATA);
296 cpu->pc = 0;
297 for (i=0; i<nbytes; i++) {
298 cpu->pc <<= 8;
299 cpu->pc += buf[i];
300 }
301
302 addr = cpu->pc;
303
304 if (cpu->cd.urisc.halt_on_zero && cpu->pc <= 4) {
305 cpu->running = 0;
306 return 0;
307 }
308
309 /* Advance the program counter: */
310 cpu->pc += nbytes;
311 cpu->pc &= mask;
312 for (i=0; i<nbytes; i++)
313 buf[nbytes-1-i] = cpu->pc >> (8*i);
314 cpu->memory_rw(cpu, cpu->mem, 0, buf, nbytes, MEM_WRITE, CACHE_DATA);
315
316 /* Read an instruction: */
317 cpu->memory_rw(cpu, cpu->mem, addr, instr, nbytes, MEM_READ,
318 CACHE_INSTRUCTION);
319
320 if (cpu->machine->instruction_trace) {
321 cpu->pc -= nbytes;
322 urisc_cpu_disassemble_instr(cpu, instr, 1, 0, 0);
323 cpu->pc += nbytes;
324 }
325
326 addr = 0;
327 for (i=0; i<nbytes; i++) {
328 addr <<= 8;
329 addr += instr[i];
330 }
331
332 /* Read data from memory: */
333 cpu->memory_rw(cpu, cpu->mem, addr, buf, cpu->cd.urisc.wordlen/8,
334 MEM_READ, CACHE_DATA);
335 data = 0;
336 for (i=0; i<nbytes; i++) {
337 data <<= 8;
338 data += buf[i];
339 }
340
341 if (cpu->machine->instruction_trace) {
342 snprintf(tmps, sizeof(tmps), "\t[mem=0x%%0%illx", nbytes * 2);
343 debug(tmps, (long long)data);
344 snprintf(tmps, sizeof(tmps), "; acc: 0x%%0%illx", nbytes * 2);
345 debug(tmps, (long long)cpu->cd.urisc.acc);
346 }
347
348 skip = (uint64_t)data < (uint64_t)cpu->cd.urisc.acc;
349
350 data -= cpu->cd.urisc.acc;
351 data &= mask;
352
353 cpu->cd.urisc.acc = data;
354
355 if (cpu->machine->instruction_trace) {
356 snprintf(tmps, sizeof(tmps), " ==> 0x%%0%illx", nbytes * 2);
357 debug(tmps, (long long)cpu->cd.urisc.acc);
358 if (skip)
359 debug(", SKIP");
360 debug("]\n");
361 }
362
363 /* Write back result to both memory and the accumulator: */
364 for (i=0; i<nbytes; i++)
365 buf[nbytes-1-i] = cpu->cd.urisc.acc >> (8*i);
366 cpu->memory_rw(cpu, cpu->mem, addr, buf, nbytes, MEM_WRITE, CACHE_DATA);
367 if (cpu->cd.urisc.acc_in_mem)
368 cpu->memory_rw(cpu, cpu->mem, nbytes, buf,
369 nbytes, MEM_WRITE, CACHE_DATA);
370
371 /* Skip on borrow: */
372 if (skip) {
373 /* Read PC from memory: */
374 cpu->memory_rw(cpu, cpu->mem, 0, buf, nbytes,
375 MEM_READ, CACHE_DATA);
376 cpu->pc = 0;
377 for (i=0; i<nbytes; i++) {
378 cpu->pc <<= 8;
379 cpu->pc += buf[i];
380 }
381
382 /* Advance the program counter: */
383 cpu->pc += nbytes;
384 cpu->pc &= mask;
385
386 for (i=0; i<nbytes; i++)
387 buf[nbytes-1-i] = cpu->pc >> (8*i);
388 cpu->memory_rw(cpu, cpu->mem, 0, buf, nbytes, MEM_WRITE,
389 CACHE_DATA);
390 }
391
392 return 1;
393 }
394
395
396 #define CPU_RUN urisc_cpu_run
397 #define CPU_RINSTR urisc_cpu_run_instr
398 #define CPU_RUN_URISC
399 #include "cpu_run.c"
400 #undef CPU_RINSTR
401 #undef CPU_RUN_URISC
402 #undef CPU_RUN
403
404
405 #define MEMORY_RW urisc_memory_rw
406 #define MEM_URISC
407 #include "memory_rw.c"
408 #undef MEM_URISC
409 #undef MEMORY_RW
410
411
412 /*
413 * urisc_cpu_family_init():
414 *
415 * Fill in the cpu_family struct for URISC.
416 */
417 int urisc_cpu_family_init(struct cpu_family *fp)
418 {
419 fp->name = "URISC";
420 fp->cpu_new = urisc_cpu_new;
421 fp->list_available_types = urisc_cpu_list_available_types;
422 fp->register_match = urisc_cpu_register_match;
423 fp->disassemble_instr = urisc_cpu_disassemble_instr;
424 fp->register_dump = urisc_cpu_register_dump;
425 fp->run = urisc_cpu_run;
426 fp->dumpinfo = urisc_cpu_dumpinfo;
427 return 1;
428 }
429
430 #endif /* ENABLE_URISC */

  ViewVC Help
Powered by ViewVC 1.1.26