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_rca180x_instr.c,v 1.1 2006/08/28 16:25:59 debug Exp $ |
29 |
* |
30 |
* RCA180X instructions. |
31 |
* |
32 |
* See http://www.elf-emulation.com/1802.html for a good list of 1802/1805 |
33 |
* opcodes. |
34 |
* |
35 |
* Individual functions should keep track of cpu->n_translated_instrs. |
36 |
* (n_translated_instrs is automatically increased by 1 for each function |
37 |
* call. If no instruction was executed, then it should be decreased. If, say, |
38 |
* 4 instructions were combined into one function and executed, then it should |
39 |
* be increased by 3.) |
40 |
* |
41 |
* NOTE/TODO: This file still contains CHIP8 instructions only... |
42 |
*/ |
43 |
|
44 |
|
45 |
/*****************************************************************************/ |
46 |
|
47 |
|
48 |
static void rca180x_putpixel(struct cpu *cpu, int x, int y, int color) |
49 |
{ |
50 |
/* TODO: Optimize. */ |
51 |
int sx, sy; |
52 |
uint8_t pixel = color? 255 : 0; |
53 |
int linelen = cpu->cd.rca180x.xres; |
54 |
uint64_t addr = (linelen * y * cpu->machine->x11_scaleup + x) |
55 |
* cpu->machine->x11_scaleup + CHIP8_FB_ADDR; |
56 |
|
57 |
cpu->cd.rca180x.framebuffer_cache[y * cpu->cd.rca180x.xres + x] = pixel; |
58 |
|
59 |
linelen = (linelen - 1) * cpu->machine->x11_scaleup; |
60 |
|
61 |
for (sy=0; sy<cpu->machine->x11_scaleup; sy++) { |
62 |
for (sx=0; sx<cpu->machine->x11_scaleup; sx++) { |
63 |
cpu->memory_rw(cpu, cpu->mem, addr, &pixel, |
64 |
sizeof(pixel), MEM_WRITE, PHYSICAL); |
65 |
addr ++; |
66 |
} |
67 |
addr += linelen; |
68 |
} |
69 |
} |
70 |
|
71 |
|
72 |
/* |
73 |
* cls: Clear screen. |
74 |
*/ |
75 |
X(cls) |
76 |
{ |
77 |
/* TODO: Optimize. */ |
78 |
int x, y; |
79 |
for (y=0; y<cpu->cd.rca180x.yres; y++) |
80 |
for (x=0; x<cpu->cd.rca180x.xres; x++) |
81 |
rca180x_putpixel(cpu, x, y, 0); |
82 |
} |
83 |
|
84 |
|
85 |
/* |
86 |
* sprite: Draw a 8 pixel wide sprite. |
87 |
* |
88 |
* arg[0] = ptr to register containing x coordinate |
89 |
* arg[1] = ptr to register containing y coordinate |
90 |
* arg[2] = height |
91 |
*/ |
92 |
X(sprite) |
93 |
{ |
94 |
int xb = *((uint8_t *)ic->arg[0]), yb = *((uint8_t *)ic->arg[1]); |
95 |
int x, y, height = ic->arg[2]; |
96 |
int index = cpu->cd.rca180x.index; |
97 |
|
98 |
/* Synchronize the PC first: */ |
99 |
int low_pc = ((size_t)ic - (size_t)cpu->cd.rca180x.cur_ic_page) |
100 |
/ sizeof(struct rca180x_instr_call); |
101 |
cpu->pc &= ~((RCA180X_IC_ENTRIES_PER_PAGE-1) |
102 |
<< RCA180X_INSTR_ALIGNMENT_SHIFT); |
103 |
cpu->pc += (low_pc << RCA180X_INSTR_ALIGNMENT_SHIFT); |
104 |
|
105 |
/* debug("[ rca180x sprite at x=%i y=%i, height=%i ]\n", |
106 |
xb, yb, height); */ |
107 |
cpu->cd.rca180x.v[15] = 0; |
108 |
|
109 |
for (y=yb; y<yb+height; y++) { |
110 |
uint8_t color; |
111 |
cpu->memory_rw(cpu, cpu->mem, index++, &color, |
112 |
sizeof(color), MEM_READ, PHYSICAL); |
113 |
for (x=xb; x<xb+8; x++) { |
114 |
int xc = x % cpu->cd.rca180x.xres; |
115 |
int yc = y % cpu->cd.rca180x.yres; |
116 |
if (cpu->cd.rca180x.framebuffer_cache[yc * |
117 |
cpu->cd.rca180x.xres + xc]) { |
118 |
color ^= 0x80; |
119 |
if ((color & 0x80) == 0) |
120 |
cpu->cd.rca180x.v[15] = 1; |
121 |
} |
122 |
rca180x_putpixel(cpu, xc, yc, color & 0x80); |
123 |
color <<= 1; |
124 |
} |
125 |
} |
126 |
|
127 |
cpu->n_translated_instrs += 200000; |
128 |
cpu->pc += 2; |
129 |
cpu->cd.rca180x.next_ic = ¬hing_call; |
130 |
} |
131 |
|
132 |
|
133 |
/* |
134 |
* mov: rx = ry |
135 |
* or: rx = rx | ry |
136 |
* and: rx = rx & ry |
137 |
* xor: rx = rx ^ ry |
138 |
* add: rx = rx + ry, vf set to 1 on carry overflow |
139 |
* sub: rx = rx - ry, vf set to 1 on borrow |
140 |
* |
141 |
* arg[0] = ptr to register x |
142 |
* arg[1] = ptr to register y |
143 |
*/ |
144 |
X(mov) { (*((uint8_t *)ic->arg[0])) = *((uint8_t *)ic->arg[1]); } |
145 |
X(or) { (*((uint8_t *)ic->arg[0])) |= *((uint8_t *)ic->arg[1]); } |
146 |
X(and) { (*((uint8_t *)ic->arg[0])) &= *((uint8_t *)ic->arg[1]); } |
147 |
X(xor) { (*((uint8_t *)ic->arg[0])) ^= *((uint8_t *)ic->arg[1]); } |
148 |
X(add) |
149 |
{ |
150 |
int x = *((uint8_t *)ic->arg[0]); |
151 |
int y = *((uint8_t *)ic->arg[1]); |
152 |
x += y; |
153 |
*((uint8_t *)ic->arg[0]) = x; |
154 |
cpu->cd.rca180x.v[15] = (x > 255); |
155 |
} |
156 |
X(sub) |
157 |
{ |
158 |
int x = *((uint8_t *)ic->arg[0]); |
159 |
int y = *((uint8_t *)ic->arg[1]); |
160 |
/* VF bit = negated borrow */ |
161 |
cpu->cd.rca180x.v[15] = (x >= y); |
162 |
*((uint8_t *)ic->arg[0]) = x - y; |
163 |
} |
164 |
|
165 |
|
166 |
/* |
167 |
* skeq_imm: Skip next instruction if a register is equal to a constant. |
168 |
* |
169 |
* arg[0] = ptr to register |
170 |
* arg[1] = 8-bit constant |
171 |
*/ |
172 |
X(skeq_imm) |
173 |
{ |
174 |
if (*((uint8_t *)ic->arg[0]) == ic->arg[1]) |
175 |
cpu->cd.rca180x.next_ic ++; |
176 |
} |
177 |
|
178 |
|
179 |
/* |
180 |
* skne_imm: Skip next instruction if a register is not equal to a constant. |
181 |
* |
182 |
* arg[0] = ptr to register |
183 |
* arg[1] = 8-bit constant |
184 |
*/ |
185 |
X(skne_imm) |
186 |
{ |
187 |
if (*((uint8_t *)ic->arg[0]) != ic->arg[1]) |
188 |
cpu->cd.rca180x.next_ic ++; |
189 |
} |
190 |
|
191 |
|
192 |
/* |
193 |
* skeq: Skip next instruction if a register is equal to another. |
194 |
* skne: Skip next instruction if a register is not equal to another. |
195 |
* |
196 |
* arg[0] = ptr to register x |
197 |
* arg[1] = ptr to register y |
198 |
*/ |
199 |
X(skeq) |
200 |
{ |
201 |
if (*((uint8_t *)ic->arg[0]) == *((uint8_t *)ic->arg[1])) |
202 |
cpu->cd.rca180x.next_ic ++; |
203 |
} |
204 |
X(skne) |
205 |
{ |
206 |
if (*((uint8_t *)ic->arg[0]) != *((uint8_t *)ic->arg[1])) |
207 |
cpu->cd.rca180x.next_ic ++; |
208 |
} |
209 |
|
210 |
|
211 |
/* |
212 |
* mov_imm: Move constant to register. |
213 |
* |
214 |
* arg[0] = ptr to register |
215 |
* arg[1] = 8-bit constant |
216 |
*/ |
217 |
X(mov_imm) |
218 |
{ |
219 |
(*((uint8_t *)ic->arg[0])) = ic->arg[1]; |
220 |
} |
221 |
|
222 |
|
223 |
/* |
224 |
* jmp: Jump to a fixed addres (always on the same page). |
225 |
* |
226 |
* arg[0] = ptr to new instruction |
227 |
*/ |
228 |
X(jmp) |
229 |
{ |
230 |
cpu->cd.rca180x.next_ic = (struct rca180x_instr_call *) ic->arg[0]; |
231 |
} |
232 |
|
233 |
|
234 |
/* |
235 |
* jsr: Jump to a subroutine at a fixed addres (always on the same page). |
236 |
* |
237 |
* arg[0] = ptr to new instruction |
238 |
*/ |
239 |
X(jsr) |
240 |
{ |
241 |
uint16_t pc12; |
242 |
|
243 |
/* Synchronize the PC first: */ |
244 |
int low_pc = ((size_t)ic - (size_t)cpu->cd.rca180x.cur_ic_page) |
245 |
/ sizeof(struct rca180x_instr_call); |
246 |
cpu->pc &= ~((RCA180X_IC_ENTRIES_PER_PAGE-1) |
247 |
<< RCA180X_INSTR_ALIGNMENT_SHIFT); |
248 |
cpu->pc += (low_pc << RCA180X_INSTR_ALIGNMENT_SHIFT); |
249 |
pc12 = (cpu->pc & 0xfff) + sizeof(uint16_t); |
250 |
|
251 |
/* Push return address to the stack: */ |
252 |
cpu->cd.rca180x.sp -= sizeof(uint16_t); |
253 |
cpu->memory_rw(cpu, cpu->mem, cpu->cd.rca180x.sp, (unsigned char *)&pc12, |
254 |
sizeof(pc12), MEM_WRITE, PHYSICAL); |
255 |
|
256 |
cpu->cd.rca180x.next_ic = (struct rca180x_instr_call *) ic->arg[0]; |
257 |
} |
258 |
|
259 |
|
260 |
/* |
261 |
* rts: Return from a subroutine. |
262 |
*/ |
263 |
X(rts) |
264 |
{ |
265 |
uint16_t pc12; |
266 |
|
267 |
/* Pop return address to the stack: */ |
268 |
cpu->memory_rw(cpu, cpu->mem, cpu->cd.rca180x.sp, (unsigned char *)&pc12, |
269 |
sizeof(pc12), MEM_READ, PHYSICAL); |
270 |
cpu->cd.rca180x.sp += sizeof(uint16_t); |
271 |
|
272 |
cpu->pc = pc12 & 0xfff; |
273 |
quick_pc_to_pointers(cpu); |
274 |
} |
275 |
|
276 |
|
277 |
/* |
278 |
* add_imm: Add constant to register, without updating the carry bit. |
279 |
* |
280 |
* arg[0] = ptr to register |
281 |
* arg[1] = 8-bit constant |
282 |
*/ |
283 |
X(add_imm) |
284 |
{ |
285 |
(*((uint8_t *)ic->arg[0])) += ic->arg[1]; |
286 |
} |
287 |
|
288 |
|
289 |
/* |
290 |
* rand: Set a register to a random value. |
291 |
* |
292 |
* arg[0] = ptr to register |
293 |
* arg[1] = 8-bit constant |
294 |
*/ |
295 |
X(rand) |
296 |
{ |
297 |
/* http://www.pdc.kth.se/~lfo/rca180x/RCA180X.htm says AND, |
298 |
http://members.aol.com/autismuk/rca180x/rca180xdef.htm says %. */ |
299 |
(*((uint8_t *)ic->arg[0])) = random() & ic->arg[1]; |
300 |
} |
301 |
|
302 |
|
303 |
/* |
304 |
* skpr: Skip next instruction if key is pressed. |
305 |
* skup: Skip next instruction if key is up. |
306 |
* |
307 |
* arg[0] = key number |
308 |
*/ |
309 |
X(skpr) |
310 |
{ |
311 |
/* TODO */ |
312 |
} |
313 |
X(skup) |
314 |
{ |
315 |
/* TODO */ |
316 |
cpu->cd.rca180x.next_ic ++; |
317 |
} |
318 |
|
319 |
|
320 |
/* |
321 |
* gdelay: Get the timer delay value. |
322 |
* sdelay: Set the timer delay value. |
323 |
* ssound: Set the sound delay value. |
324 |
* |
325 |
* arg[0] = ptr to register |
326 |
*/ |
327 |
X(gdelay) { *((uint8_t *)ic->arg[0]) = cpu->cd.rca180x.delay_timer_value; } |
328 |
X(sdelay) { cpu->cd.rca180x.delay_timer_value = *((uint8_t *)ic->arg[0]); } |
329 |
X(ssound) { cpu->cd.rca180x.sound_timer_value = *((uint8_t *)ic->arg[0]); } |
330 |
|
331 |
|
332 |
/* |
333 |
* adi: Add a register's value to the Index register. |
334 |
* |
335 |
* arg[0] = ptr to register |
336 |
*/ |
337 |
X(adi) |
338 |
{ |
339 |
cpu->cd.rca180x.index += *((uint8_t *)ic->arg[0]); |
340 |
} |
341 |
|
342 |
|
343 |
/* |
344 |
* font: Set the Index register to point to a font sprite. |
345 |
* |
346 |
* arg[0] = ptr to register containing the hex char |
347 |
*/ |
348 |
X(font) |
349 |
{ |
350 |
int c = *((uint8_t *)ic->arg[0]); |
351 |
if (c > 0xf) |
352 |
fatal("[ rca180x font: WARNING: c = 0x%02x ]\n", c); |
353 |
cpu->cd.rca180x.index = CHIP8_FONT_ADDR + 5 * (c & 0xf); |
354 |
} |
355 |
|
356 |
|
357 |
/* |
358 |
* bcd: Store BCD representation of a register in memory. |
359 |
* |
360 |
* arg[0] = ptr to register |
361 |
*/ |
362 |
X(bcd) |
363 |
{ |
364 |
int r = *((uint8_t *)ic->arg[0]); |
365 |
uint8_t a[3]; |
366 |
a[0] = r / 100, a[1] = (r / 10) % 10, a[2] = r % 10; |
367 |
|
368 |
cpu->memory_rw(cpu, cpu->mem, cpu->cd.rca180x.index, |
369 |
(unsigned char *) &a, sizeof(a), MEM_WRITE, PHYSICAL); |
370 |
} |
371 |
|
372 |
|
373 |
/* |
374 |
* str: Store multiple registers to memory. |
375 |
* |
376 |
* arg[0] = last register number (note: not pointer) |
377 |
*/ |
378 |
X(str) |
379 |
{ |
380 |
int r; |
381 |
for (r=0; r<=ic->arg[0]; r++) { |
382 |
cpu->memory_rw(cpu, cpu->mem, cpu->cd.rca180x.index++, |
383 |
&cpu->cd.rca180x.v[r], sizeof(uint8_t), MEM_WRITE, PHYSICAL); |
384 |
} |
385 |
} |
386 |
|
387 |
|
388 |
/* |
389 |
* ldr: Load multiple registers from memory. |
390 |
* |
391 |
* arg[0] = last register number (note: not pointer) |
392 |
*/ |
393 |
X(ldr) |
394 |
{ |
395 |
int r; |
396 |
for (r=0; r<=ic->arg[0]; r++) { |
397 |
cpu->memory_rw(cpu, cpu->mem, cpu->cd.rca180x.index++, |
398 |
&cpu->cd.rca180x.v[r], sizeof(uint8_t), MEM_READ, PHYSICAL); |
399 |
} |
400 |
} |
401 |
|
402 |
|
403 |
/* |
404 |
* mvi: Move constant to Index register. |
405 |
* |
406 |
* arg[0] = 12-bit constant |
407 |
*/ |
408 |
X(mvi) |
409 |
{ |
410 |
cpu->cd.rca180x.index = ic->arg[0]; |
411 |
} |
412 |
|
413 |
|
414 |
/*****************************************************************************/ |
415 |
|
416 |
|
417 |
X(end_of_page) |
418 |
{ |
419 |
/* Should never happen on RCA180X, because that would mean that we |
420 |
are running outside of available memory. */ |
421 |
|
422 |
fatal("[ rca180x end of page reached, halting ]\n"); |
423 |
|
424 |
cpu->running = 0; |
425 |
debugger_n_steps_left_before_interaction = 0; |
426 |
cpu->cd.rca180x.next_ic = ¬hing_call; |
427 |
|
428 |
/* end_of_page doesn't count as an executed instruction: */ |
429 |
cpu->n_translated_instrs --; |
430 |
} |
431 |
|
432 |
|
433 |
/*****************************************************************************/ |
434 |
|
435 |
|
436 |
/* |
437 |
* rca180x_instr_to_be_translated(): |
438 |
* |
439 |
* Translate an instruction word into an rca180x_instr_call. ic is filled in with |
440 |
* valid data for the translated instruction, or a "nothing" instruction if |
441 |
* there was a translation failure. The newly translated instruction is then |
442 |
* executed. |
443 |
*/ |
444 |
X(to_be_translated) |
445 |
{ |
446 |
int addr, low_pc, dst_addr; |
447 |
unsigned char ib[2]; |
448 |
unsigned char *page; |
449 |
|
450 |
/* Figure out the (virtual) address of the instruction: */ |
451 |
low_pc = ((size_t)ic - (size_t)cpu->cd.rca180x.cur_ic_page) |
452 |
/ sizeof(struct rca180x_instr_call); |
453 |
addr = cpu->pc & ~((RCA180X_IC_ENTRIES_PER_PAGE-1) << |
454 |
RCA180X_INSTR_ALIGNMENT_SHIFT); |
455 |
addr += (low_pc << RCA180X_INSTR_ALIGNMENT_SHIFT); |
456 |
cpu->pc = addr; |
457 |
addr &= ~((1 << RCA180X_INSTR_ALIGNMENT_SHIFT) - 1); |
458 |
|
459 |
/* Read the instruction word from memory: */ |
460 |
page = cpu->cd.avr.host_load[addr >> 12]; |
461 |
|
462 |
if (page != NULL) { |
463 |
/* fatal("TRANSLATION HIT!\n"); */ |
464 |
memcpy(ib, page + (addr & 0xfff), sizeof(uint16_t)); |
465 |
} else { |
466 |
/* fatal("TRANSLATION MISS!\n"); */ |
467 |
if (!cpu->memory_rw(cpu, cpu->mem, addr, ib, |
468 |
sizeof(uint16_t), MEM_READ, CACHE_INSTRUCTION)) { |
469 |
fatal("to_be_translated(): " |
470 |
"read failed: TODO\n"); |
471 |
exit(1); |
472 |
} |
473 |
} |
474 |
|
475 |
|
476 |
#define DYNTRANS_TO_BE_TRANSLATED_HEAD |
477 |
#include "cpu_dyntrans.c" |
478 |
#undef DYNTRANS_TO_BE_TRANSLATED_HEAD |
479 |
|
480 |
|
481 |
/* |
482 |
* Translate the instruction: |
483 |
*/ |
484 |
|
485 |
switch (ib[0] >> 4) { |
486 |
|
487 |
case 0x0: |
488 |
if (ib[0] == 0x00 && ib[1] == 0xe0) { |
489 |
ic->f = instr(cls); |
490 |
} else if (ib[0] == 0x00 && ib[1] == 0xee) { |
491 |
ic->f = instr(rts); |
492 |
} else { |
493 |
goto bad; |
494 |
} |
495 |
break; |
496 |
|
497 |
case 0x1: |
498 |
ic->f = instr(jmp); |
499 |
dst_addr = ((ib[0] & 0xf) << 8) + ib[1]; |
500 |
ic->arg[0] = (size_t) (cpu->cd.rca180x.cur_ic_page + |
501 |
(dst_addr >> RCA180X_INSTR_ALIGNMENT_SHIFT)); |
502 |
break; |
503 |
|
504 |
case 0x2: |
505 |
ic->f = instr(jsr); |
506 |
dst_addr = ((ib[0] & 0xf) << 8) + ib[1]; |
507 |
ic->arg[0] = (size_t) (cpu->cd.rca180x.cur_ic_page + |
508 |
(dst_addr >> RCA180X_INSTR_ALIGNMENT_SHIFT)); |
509 |
break; |
510 |
|
511 |
case 0x3: |
512 |
ic->f = instr(skeq_imm); |
513 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
514 |
ic->arg[1] = ib[1]; |
515 |
break; |
516 |
|
517 |
case 0x4: |
518 |
ic->f = instr(skne_imm); |
519 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
520 |
ic->arg[1] = ib[1]; |
521 |
break; |
522 |
|
523 |
case 0x5: |
524 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
525 |
ic->arg[1] = (size_t) &cpu->cd.rca180x.v[ib[1] >> 4]; |
526 |
switch (ib[1] & 0xf) { |
527 |
case 0x0: ic->f = instr(skeq); break; |
528 |
default:goto bad; |
529 |
} |
530 |
break; |
531 |
|
532 |
case 0x6: |
533 |
ic->f = instr(mov_imm); |
534 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
535 |
ic->arg[1] = ib[1]; |
536 |
break; |
537 |
|
538 |
case 0x7: |
539 |
ic->f = instr(add_imm); |
540 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
541 |
ic->arg[1] = ib[1]; |
542 |
break; |
543 |
|
544 |
case 0x8: |
545 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
546 |
ic->arg[1] = (size_t) &cpu->cd.rca180x.v[ib[1] >> 4]; |
547 |
switch (ib[1] & 0xf) { |
548 |
case 0x0: ic->f = instr(mov); break; |
549 |
case 0x1: ic->f = instr(or); break; |
550 |
case 0x2: ic->f = instr(and); break; |
551 |
case 0x3: ic->f = instr(xor); break; |
552 |
case 0x4: ic->f = instr(add); break; |
553 |
case 0x5: ic->f = instr(sub); break; |
554 |
default:goto bad; |
555 |
} |
556 |
break; |
557 |
|
558 |
case 0x9: |
559 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
560 |
ic->arg[1] = (size_t) &cpu->cd.rca180x.v[ib[1] >> 4]; |
561 |
switch (ib[1] & 0xf) { |
562 |
case 0x0: ic->f = instr(skne); break; |
563 |
default:goto bad; |
564 |
} |
565 |
break; |
566 |
|
567 |
case 0xa: |
568 |
ic->f = instr(mvi); |
569 |
ic->arg[0] = ((ib[0] & 0xf) << 8) + ib[1]; |
570 |
break; |
571 |
|
572 |
case 0xc: |
573 |
ic->f = instr(rand); |
574 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
575 |
ic->arg[1] = ib[1]; |
576 |
break; |
577 |
|
578 |
case 0xd: |
579 |
ic->f = instr(sprite); |
580 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
581 |
ic->arg[1] = (size_t) &cpu->cd.rca180x.v[ib[1] >> 4]; |
582 |
ic->arg[2] = ib[1] & 0xf; |
583 |
|
584 |
if (ic->arg[2] == 0) { |
585 |
fatal("xsprite: TODO\n"); |
586 |
goto bad; |
587 |
} |
588 |
break; |
589 |
|
590 |
case 0xe: |
591 |
/* Default arg 0: */ |
592 |
ic->arg[0] = ib[0] & 0xf; |
593 |
switch (ib[1]) { |
594 |
case 0x9e: ic->f = instr(skpr); break; |
595 |
case 0xa1: ic->f = instr(skup); break; |
596 |
default:goto bad; |
597 |
} |
598 |
break; |
599 |
|
600 |
case 0xf: |
601 |
/* Default arg 0: */ |
602 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
603 |
switch (ib[1]) { |
604 |
case 0x07: |
605 |
ic->f = instr(gdelay); |
606 |
break; |
607 |
case 0x15: |
608 |
ic->f = instr(sdelay); |
609 |
break; |
610 |
case 0x18: |
611 |
ic->f = instr(ssound); |
612 |
break; |
613 |
case 0x1e: |
614 |
ic->f = instr(adi); |
615 |
break; |
616 |
case 0x29: |
617 |
ic->f = instr(font); |
618 |
break; |
619 |
case 0x33: |
620 |
ic->f = instr(bcd); |
621 |
break; |
622 |
case 0x55: |
623 |
ic->f = instr(str); |
624 |
ic->arg[0] = ib[0] & 0xf; |
625 |
break; |
626 |
case 0x65: |
627 |
ic->f = instr(ldr); |
628 |
ic->arg[0] = ib[0] & 0xf; |
629 |
break; |
630 |
default:goto bad; |
631 |
} |
632 |
break; |
633 |
|
634 |
default:goto bad; |
635 |
} |
636 |
|
637 |
|
638 |
#define DYNTRANS_TO_BE_TRANSLATED_TAIL |
639 |
#include "cpu_dyntrans.c" |
640 |
#undef DYNTRANS_TO_BE_TRANSLATED_TAIL |
641 |
} |
642 |
|