/[gxemul]/upstream/0.4.2/src/cpus/cpu_transputer_instr.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.4.2/src/cpus/cpu_transputer_instr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations)
Mon Oct 8 16:20:48 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 13341 byte(s)
0.4.2
1 /*
2 * Copyright (C) 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: cpu_transputer_instr.c,v 1.6 2006/07/23 19:36:14 debug Exp $
29 *
30 * INMOS transputer instructions.
31 *
32 * Individual functions should keep track of cpu->n_translated_instrs.
33 * (n_translated_instrs is automatically increased by 1 for each function
34 * call. If no instruction was executed, then it should be decreased. If, say,
35 * 4 instructions were combined into one function and executed, then it should
36 * be increased by 3.)
37 *
38 * NOTE: The PC does not need to be synched before e.g. memory_rw(), because
39 * there is no MMU in the Transputer, and hence there can not be any
40 * exceptions on memory accesses.
41 */
42
43
44 /*****************************************************************************/
45
46
47 /*
48 * j: Relative jump
49 */
50 X(j)
51 {
52 /* Synchronize the PC and then add the operand + 1: */
53 int low_pc = ((size_t)ic - (size_t)cpu->cd.transputer.cur_ic_page)
54 / sizeof(struct transputer_instr_call);
55 cpu->pc &= ~(TRANSPUTER_IC_ENTRIES_PER_PAGE-1);
56 cpu->pc += low_pc + ic->arg[0] + 1 + cpu->cd.transputer.oreg;
57 cpu->cd.transputer.oreg = 0;
58 quick_pc_to_pointers(cpu);
59 }
60
61
62 /*
63 * ldlp: Load local pointer
64 */
65 X(ldlp)
66 {
67 cpu->cd.transputer.c = cpu->cd.transputer.b;
68 cpu->cd.transputer.b = cpu->cd.transputer.a;
69 cpu->cd.transputer.oreg |= ic->arg[0];
70 cpu->cd.transputer.a = cpu->cd.transputer.oreg * sizeof(uint32_t) +
71 cpu->cd.transputer.wptr;
72 cpu->cd.transputer.oreg = 0;
73 }
74
75
76 /*
77 * pfix: Prefix
78 *
79 * arg[0] = nibble
80 */
81 X(pfix)
82 {
83 cpu->cd.transputer.oreg |= ic->arg[0];
84 cpu->cd.transputer.oreg <<= 4;
85 }
86
87
88 /*
89 * ldnl: Load non-local
90 */
91 X(ldnl)
92 {
93 uint32_t addr, w32;
94 uint8_t word[sizeof(uint32_t)];
95 unsigned char *page;
96
97 cpu->cd.transputer.oreg |= ic->arg[0];
98 addr = cpu->cd.transputer.oreg * sizeof(uint32_t) +
99 cpu->cd.transputer.a;
100
101 page = cpu->cd.transputer.host_load[TRANSPUTER_ADDR_TO_PAGENR(addr)];
102 if (page == NULL) {
103 cpu->memory_rw(cpu, cpu->mem, addr, word, sizeof(word),
104 MEM_READ, CACHE_DATA);
105 w32 = *(uint32_t *) &word[0];
106 } else {
107 w32 = *(uint32_t *) &page[TRANSPUTER_PC_TO_IC_ENTRY(addr)];
108 }
109
110 cpu->cd.transputer.a = LE32_TO_HOST(w32);
111 cpu->cd.transputer.oreg = 0;
112 }
113
114
115 /*
116 * ldc: Load constant
117 */
118 X(ldc)
119 {
120 cpu->cd.transputer.c = cpu->cd.transputer.b;
121 cpu->cd.transputer.b = cpu->cd.transputer.a;
122 cpu->cd.transputer.a = cpu->cd.transputer.oreg | ic->arg[0];
123 cpu->cd.transputer.oreg = 0;
124 }
125
126
127 /*
128 * ldnlp: Load non-local pointer
129 */
130 X(ldnlp)
131 {
132 cpu->cd.transputer.a += (cpu->cd.transputer.oreg | ic->arg[0])
133 * sizeof(uint32_t);
134 cpu->cd.transputer.oreg = 0;
135 }
136
137
138 /*
139 * nfix: Negative prefix
140 */
141 X(nfix)
142 {
143 cpu->cd.transputer.oreg |= ic->arg[0];
144 cpu->cd.transputer.oreg = (~cpu->cd.transputer.oreg) << 4;
145 }
146
147
148 /*
149 * ldl: Load local
150 */
151 X(ldl)
152 {
153 uint32_t addr;
154 uint8_t word[sizeof(uint32_t)];
155 uint32_t w32;
156 unsigned char *page;
157
158 cpu->cd.transputer.c = cpu->cd.transputer.b;
159 cpu->cd.transputer.b = cpu->cd.transputer.a;
160 cpu->cd.transputer.oreg |= ic->arg[0];
161 addr = cpu->cd.transputer.oreg * sizeof(uint32_t) +
162 cpu->cd.transputer.wptr;
163
164 page = cpu->cd.transputer.host_load[TRANSPUTER_ADDR_TO_PAGENR(addr)];
165 if (page == NULL) {
166 cpu->memory_rw(cpu, cpu->mem, addr, word, sizeof(word),
167 MEM_READ, CACHE_DATA);
168 w32 = *(uint32_t *) &word[0];
169 printf("A w32 = %08"PRIx32"\n", w32);
170 } else {
171 w32 = *(uint32_t *) &page[TRANSPUTER_PC_TO_IC_ENTRY(addr)];
172 printf("B w32 = %08"PRIx32"\n", w32);
173 }
174
175 cpu->cd.transputer.a = LE32_TO_HOST(w32);
176 cpu->cd.transputer.oreg = 0;
177 }
178
179
180 /*
181 * ajw: Adjust workspace
182 */
183 X(ajw)
184 {
185 cpu->cd.transputer.oreg |= ic->arg[0];
186 cpu->cd.transputer.wptr += (cpu->cd.transputer.oreg * sizeof(uint32_t));
187 cpu->cd.transputer.oreg = 0;
188 }
189
190
191 /*
192 * eqc: Equal to constant
193 */
194 X(eqc)
195 {
196 cpu->cd.transputer.a = (cpu->cd.transputer.a ==
197 (cpu->cd.transputer.oreg | ic->arg[0]));
198 cpu->cd.transputer.oreg = 0;
199 }
200
201
202 /*
203 * stl: Store local
204 */
205 X(stl)
206 {
207 uint32_t addr, w32;
208 unsigned char *page;
209
210 w32 = LE32_TO_HOST(cpu->cd.transputer.a);
211 cpu->cd.transputer.oreg |= ic->arg[0];
212 addr = cpu->cd.transputer.oreg * sizeof(uint32_t) +
213 cpu->cd.transputer.wptr;
214
215 page = cpu->cd.transputer.host_store[TRANSPUTER_ADDR_TO_PAGENR(addr)];
216 if (page == NULL) {
217 cpu->memory_rw(cpu, cpu->mem, addr, (void *)&w32, sizeof(w32),
218 MEM_WRITE, CACHE_DATA);
219 } else {
220 *((uint32_t *) &page[TRANSPUTER_PC_TO_IC_ENTRY(addr)]) = w32;
221 }
222
223 cpu->cd.transputer.a = cpu->cd.transputer.b;
224 cpu->cd.transputer.b = cpu->cd.transputer.c;
225 cpu->cd.transputer.oreg = 0;
226 }
227
228
229 /*
230 * stnl: Store non-local
231 */
232 X(stnl)
233 {
234 uint32_t addr, w32;
235 unsigned char *page;
236
237 w32 = LE32_TO_HOST(cpu->cd.transputer.b);
238 cpu->cd.transputer.oreg |= ic->arg[0];
239 addr = cpu->cd.transputer.oreg * sizeof(uint32_t) +
240 cpu->cd.transputer.a;
241
242 page = cpu->cd.transputer.host_store[TRANSPUTER_ADDR_TO_PAGENR(addr)];
243 if (page == NULL) {
244 cpu->memory_rw(cpu, cpu->mem, addr, (void *)&w32, sizeof(w32),
245 MEM_WRITE, CACHE_DATA);
246 } else {
247 *((uint32_t *) &page[TRANSPUTER_PC_TO_IC_ENTRY(addr)]) = w32;
248 }
249
250 cpu->cd.transputer.a = cpu->cd.transputer.c;
251 cpu->cd.transputer.oreg = 0;
252 }
253
254
255 /*
256 * opr: Operate
257 *
258 * TODO/NOTE: This doesn't work too well with the way dyntrans is designed
259 * to work. Maybe it should be rewritten some day. But how?
260 * Right now it works almost 100% like an old-style interpretation
261 * function.
262 */
263 X(opr)
264 {
265 cpu->cd.transputer.oreg |= ic->arg[0];
266
267 switch (cpu->cd.transputer.oreg) {
268
269 case T_OPC_F_REV:
270 {
271 uint32_t tmp = cpu->cd.transputer.b;
272 cpu->cd.transputer.b = cpu->cd.transputer.a;
273 cpu->cd.transputer.a = tmp;
274 }
275 break;
276
277 case T_OPC_F_ADD:
278 {
279 uint32_t old_a = cpu->cd.transputer.a;
280 cpu->cd.transputer.a = cpu->cd.transputer.b + old_a;
281 if ((cpu->cd.transputer.a & 0x80000000) !=
282 (cpu->cd.transputer.b & old_a & 0x80000000))
283 cpu->cd.transputer.error = 1;
284 cpu->cd.transputer.b = cpu->cd.transputer.c;
285 }
286 break;
287
288 case T_OPC_F_SUB:
289 {
290 uint32_t old_a = cpu->cd.transputer.a;
291 cpu->cd.transputer.a = cpu->cd.transputer.b - old_a;
292 if ((cpu->cd.transputer.a & 0x80000000) !=
293 (cpu->cd.transputer.b & old_a & 0x80000000))
294 cpu->cd.transputer.error = 1;
295 cpu->cd.transputer.b = cpu->cd.transputer.c;
296 }
297 break;
298
299 case T_OPC_F_LDPI:
300 /* Load pointer to (next) instruction */
301 {
302 int low_pc = ((size_t)ic -
303 (size_t)cpu->cd.transputer.cur_ic_page)
304 / sizeof(struct transputer_instr_call);
305 cpu->pc &= ~(TRANSPUTER_IC_ENTRIES_PER_PAGE-1);
306 cpu->pc += low_pc;
307 cpu->cd.transputer.a += cpu->pc + 1;
308 }
309 break;
310
311 case T_OPC_F_STHF:
312 cpu->cd.transputer.fptrreg0 = cpu->cd.transputer.a;
313 cpu->cd.transputer.a = cpu->cd.transputer.b;
314 cpu->cd.transputer.b = cpu->cd.transputer.c;
315 break;
316
317 case T_OPC_F_STLF:
318 cpu->cd.transputer.fptrreg1 = cpu->cd.transputer.a;
319 cpu->cd.transputer.a = cpu->cd.transputer.b;
320 cpu->cd.transputer.b = cpu->cd.transputer.c;
321 break;
322
323 case T_OPC_F_BCNT:
324 cpu->cd.transputer.a <<= 2;
325 break;
326
327 case T_OPC_F_GAJW:
328 {
329 uint32_t old_wptr = cpu->cd.transputer.wptr;
330 cpu->cd.transputer.wptr = cpu->cd.transputer.a & ~3;
331 cpu->cd.transputer.a = old_wptr;
332 }
333 break;
334
335 case T_OPC_F_WCNT:
336 cpu->cd.transputer.c = cpu->cd.transputer.b;
337 cpu->cd.transputer.b = cpu->cd.transputer.a & 3;
338 cpu->cd.transputer.a >>= 2;
339 break;
340
341 case T_OPC_F_MINT:
342 cpu->cd.transputer.c = cpu->cd.transputer.b;
343 cpu->cd.transputer.b = cpu->cd.transputer.a;
344 cpu->cd.transputer.a = 0x80000000;
345 break;
346
347 case T_OPC_F_MOVE:
348 /* TODO: This can be optimized a lot by using the host's
349 memmove(). The only important thing to consider is
350 if src or dst crosses a host memblock boundary. */
351 {
352 uint32_t i, src = cpu->cd.transputer.c,
353 dst = cpu->cd.transputer.b;
354 uint8_t byte;
355 for (i=1; i<=cpu->cd.transputer.a; i++) {
356 cpu->memory_rw(cpu, cpu->mem, src ++, &byte,
357 1, MEM_READ, CACHE_DATA);
358 cpu->memory_rw(cpu, cpu->mem, dst ++, &byte,
359 1, MEM_WRITE, CACHE_DATA);
360 }
361 }
362 break;
363
364 default:fatal("UNIMPLEMENTED opr oreg 0x%"PRIx32"\n",
365 cpu->cd.transputer.oreg);
366 exit(1);
367 }
368
369 cpu->cd.transputer.oreg = 0;
370 }
371
372
373 /*****************************************************************************/
374
375
376 X(end_of_page)
377 {
378 /* Update the PC: (offset 0, but on the next page) */
379 cpu->pc &= ~((TRANSPUTER_IC_ENTRIES_PER_PAGE-1) << 1);
380 cpu->pc += (TRANSPUTER_IC_ENTRIES_PER_PAGE << 1);
381
382 /* Find the new physical page and update the translation pointers: */
383 transputer_pc_to_pointers(cpu);
384
385 /* end_of_page doesn't count as an executed instruction: */
386 cpu->n_translated_instrs --;
387 }
388
389
390 /*****************************************************************************/
391
392
393 /*
394 * transputer_instr_to_be_translated():
395 *
396 * Translate an instruction word into an transputer_instr_call. ic is filled in with
397 * valid data for the translated instruction, or a "nothing" instruction if
398 * there was a translation failure. The newly translated instruction is then
399 * executed.
400 */
401 X(to_be_translated)
402 {
403 uint32_t addr, low_pc;
404 unsigned char *page;
405 unsigned char ib[1];
406 /* void (*samepage_function)(struct cpu *,
407 struct transputer_instr_call *);*/
408
409 /* Figure out the (virtual) address of the instruction: */
410 low_pc = ((size_t)ic - (size_t)cpu->cd.transputer.cur_ic_page)
411 / sizeof(struct transputer_instr_call);
412 addr = cpu->pc & ~((TRANSPUTER_IC_ENTRIES_PER_PAGE-1) <<
413 TRANSPUTER_INSTR_ALIGNMENT_SHIFT);
414 addr += (low_pc << TRANSPUTER_INSTR_ALIGNMENT_SHIFT);
415 cpu->pc = addr;
416 addr &= ~((1 << TRANSPUTER_INSTR_ALIGNMENT_SHIFT) - 1);
417
418 /* Read the instruction word from memory: */
419 page = cpu->cd.transputer.host_load[addr >> 12];
420
421 if (page != NULL) {
422 /* fatal("TRANSLATION HIT!\n"); */
423 memcpy(ib, page + (addr & 0xfff), sizeof(ib));
424 } else {
425 /* fatal("TRANSLATION MISS!\n"); */
426 if (!cpu->memory_rw(cpu, cpu->mem, addr, ib,
427 sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
428 fatal("to_be_translated(): "
429 "read failed: TODO\n");
430 goto bad;
431 }
432 }
433
434
435 #define DYNTRANS_TO_BE_TRANSLATED_HEAD
436 #include "cpu_dyntrans.c"
437 #undef DYNTRANS_TO_BE_TRANSLATED_HEAD
438
439
440 /*
441 * Translate the instruction:
442 * --------------------------
443 *
444 * Most instructions take the operand as arg[0], so we set it
445 * here by default:
446 */
447 ic->arg[0] = ib[0] & 0xf;
448
449 switch (ib[0] >> 4) {
450
451 case T_OPC_J:
452 /* relative jump */
453 ic->f = instr(j);
454 /* TODO: Samepage jump! */
455
456 if (cpu->cd.transputer.cpu_type.features & T_DEBUG
457 && (ib[0] & 0xf) == 0) {
458 /*
459 * From Wikipedia: ... "and, later, the T225. This
460 * added debugging breakpoint support (by extending
461 * the instruction J 0)"
462 */
463 fatal("TODO: Transputer Debugger support!\n");
464 goto bad;
465 }
466 break;
467
468 case T_OPC_LDLP:
469 /* load local pointer */
470 ic->f = instr(ldlp);
471 break;
472
473 case T_OPC_PFIX:
474 /* prefix */
475 ic->f = instr(pfix);
476 break;
477
478 case T_OPC_LDNL:
479 /* load non-local */
480 ic->f = instr(ldnl);
481 break;
482
483 case T_OPC_LDC:
484 /* load constant */
485 ic->f = instr(ldc);
486 break;
487
488 case T_OPC_LDNLP:
489 /* load non-local pointer */
490 ic->f = instr(ldnlp);
491 break;
492
493 case T_OPC_NFIX:
494 /* negative prefix */
495 ic->f = instr(nfix);
496 break;
497
498 case T_OPC_LDL:
499 /* load local */
500 ic->f = instr(ldl);
501 break;
502
503 case T_OPC_AJW:
504 /* adjust workspace */
505 ic->f = instr(ajw);
506 break;
507
508 case T_OPC_EQC:
509 /* equal to constant */
510 ic->f = instr(eqc);
511 break;
512
513 case T_OPC_STL:
514 /* store local */
515 ic->f = instr(stl);
516 break;
517
518 case T_OPC_STNL:
519 /* store non-local */
520 ic->f = instr(stnl);
521 break;
522
523 case T_OPC_OPR:
524 /* operate */
525 ic->f = instr(opr);
526 break;
527
528 default:fatal("UNIMPLEMENTED opcode 0x%02x\n", ib[0]);
529 goto bad;
530 }
531
532
533 #define DYNTRANS_TO_BE_TRANSLATED_TAIL
534 #include "cpu_dyntrans.c"
535 #undef DYNTRANS_TO_BE_TRANSLATED_TAIL
536 }
537

  ViewVC Help
Powered by ViewVC 1.1.26