1 |
/* |
2 |
* Copyright (C) 2006-2007 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.3 2006/12/30 13:30:55 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, |
254 |
(unsigned char *)&pc12, 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, |
269 |
(unsigned char *)&pc12, 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, |
384 |
PHYSICAL); |
385 |
} |
386 |
} |
387 |
|
388 |
|
389 |
/* |
390 |
* ldr: Load multiple registers from memory. |
391 |
* |
392 |
* arg[0] = last register number (note: not pointer) |
393 |
*/ |
394 |
X(ldr) |
395 |
{ |
396 |
int r; |
397 |
for (r=0; r<=ic->arg[0]; r++) { |
398 |
cpu->memory_rw(cpu, cpu->mem, cpu->cd.rca180x.index++, |
399 |
&cpu->cd.rca180x.v[r], sizeof(uint8_t), MEM_READ, PHYSICAL); |
400 |
} |
401 |
} |
402 |
|
403 |
|
404 |
/* |
405 |
* mvi: Move constant to Index register. |
406 |
* |
407 |
* arg[0] = 12-bit constant |
408 |
*/ |
409 |
X(mvi) |
410 |
{ |
411 |
cpu->cd.rca180x.index = ic->arg[0]; |
412 |
} |
413 |
|
414 |
|
415 |
/*****************************************************************************/ |
416 |
|
417 |
|
418 |
X(end_of_page) |
419 |
{ |
420 |
/* Should never happen on RCA180X, because that would mean that we |
421 |
are running outside of available memory. */ |
422 |
|
423 |
fatal("[ rca180x end of page reached, halting ]\n"); |
424 |
|
425 |
cpu->running = 0; |
426 |
debugger_n_steps_left_before_interaction = 0; |
427 |
cpu->cd.rca180x.next_ic = ¬hing_call; |
428 |
|
429 |
/* end_of_page doesn't count as an executed instruction: */ |
430 |
cpu->n_translated_instrs --; |
431 |
} |
432 |
|
433 |
|
434 |
/*****************************************************************************/ |
435 |
|
436 |
|
437 |
/* |
438 |
* rca180x_instr_to_be_translated(): |
439 |
* |
440 |
* Translate an instruction word into an rca180x_instr_call. ic is filled in |
441 |
* with valid data for the translated instruction, or a "nothing" instruction |
442 |
* if there was a translation failure. The newly translated instruction is |
443 |
* then executed. |
444 |
*/ |
445 |
X(to_be_translated) |
446 |
{ |
447 |
int addr, low_pc, dst_addr; |
448 |
unsigned char ib[2]; |
449 |
unsigned char *page; |
450 |
|
451 |
/* Figure out the (virtual) address of the instruction: */ |
452 |
low_pc = ((size_t)ic - (size_t)cpu->cd.rca180x.cur_ic_page) |
453 |
/ sizeof(struct rca180x_instr_call); |
454 |
addr = cpu->pc & ~((RCA180X_IC_ENTRIES_PER_PAGE-1) << |
455 |
RCA180X_INSTR_ALIGNMENT_SHIFT); |
456 |
addr += (low_pc << RCA180X_INSTR_ALIGNMENT_SHIFT); |
457 |
cpu->pc = addr; |
458 |
addr &= ~((1 << RCA180X_INSTR_ALIGNMENT_SHIFT) - 1); |
459 |
|
460 |
/* Read the instruction word from memory: */ |
461 |
page = cpu->cd.avr.host_load[addr >> 12]; |
462 |
|
463 |
if (page != NULL) { |
464 |
/* fatal("TRANSLATION HIT!\n"); */ |
465 |
memcpy(ib, page + (addr & 0xfff), sizeof(uint16_t)); |
466 |
} else { |
467 |
/* fatal("TRANSLATION MISS!\n"); */ |
468 |
if (!cpu->memory_rw(cpu, cpu->mem, addr, ib, |
469 |
sizeof(uint16_t), MEM_READ, CACHE_INSTRUCTION)) { |
470 |
fatal("to_be_translated(): " |
471 |
"read failed: TODO\n"); |
472 |
exit(1); |
473 |
} |
474 |
} |
475 |
|
476 |
|
477 |
#define DYNTRANS_TO_BE_TRANSLATED_HEAD |
478 |
#include "cpu_dyntrans.c" |
479 |
#undef DYNTRANS_TO_BE_TRANSLATED_HEAD |
480 |
|
481 |
|
482 |
/* |
483 |
* Translate the instruction: |
484 |
*/ |
485 |
|
486 |
switch (ib[0] >> 4) { |
487 |
|
488 |
case 0x0: |
489 |
if (ib[0] == 0x00 && ib[1] == 0xe0) { |
490 |
ic->f = instr(cls); |
491 |
} else if (ib[0] == 0x00 && ib[1] == 0xee) { |
492 |
ic->f = instr(rts); |
493 |
} else { |
494 |
goto bad; |
495 |
} |
496 |
break; |
497 |
|
498 |
case 0x1: |
499 |
ic->f = instr(jmp); |
500 |
dst_addr = ((ib[0] & 0xf) << 8) + ib[1]; |
501 |
ic->arg[0] = (size_t) (cpu->cd.rca180x.cur_ic_page + |
502 |
(dst_addr >> RCA180X_INSTR_ALIGNMENT_SHIFT)); |
503 |
break; |
504 |
|
505 |
case 0x2: |
506 |
ic->f = instr(jsr); |
507 |
dst_addr = ((ib[0] & 0xf) << 8) + ib[1]; |
508 |
ic->arg[0] = (size_t) (cpu->cd.rca180x.cur_ic_page + |
509 |
(dst_addr >> RCA180X_INSTR_ALIGNMENT_SHIFT)); |
510 |
break; |
511 |
|
512 |
case 0x3: |
513 |
ic->f = instr(skeq_imm); |
514 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
515 |
ic->arg[1] = ib[1]; |
516 |
break; |
517 |
|
518 |
case 0x4: |
519 |
ic->f = instr(skne_imm); |
520 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
521 |
ic->arg[1] = ib[1]; |
522 |
break; |
523 |
|
524 |
case 0x5: |
525 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
526 |
ic->arg[1] = (size_t) &cpu->cd.rca180x.v[ib[1] >> 4]; |
527 |
switch (ib[1] & 0xf) { |
528 |
case 0x0: ic->f = instr(skeq); break; |
529 |
default:goto bad; |
530 |
} |
531 |
break; |
532 |
|
533 |
case 0x6: |
534 |
ic->f = instr(mov_imm); |
535 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
536 |
ic->arg[1] = ib[1]; |
537 |
break; |
538 |
|
539 |
case 0x7: |
540 |
ic->f = instr(add_imm); |
541 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
542 |
ic->arg[1] = ib[1]; |
543 |
break; |
544 |
|
545 |
case 0x8: |
546 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
547 |
ic->arg[1] = (size_t) &cpu->cd.rca180x.v[ib[1] >> 4]; |
548 |
switch (ib[1] & 0xf) { |
549 |
case 0x0: ic->f = instr(mov); break; |
550 |
case 0x1: ic->f = instr(or); break; |
551 |
case 0x2: ic->f = instr(and); break; |
552 |
case 0x3: ic->f = instr(xor); break; |
553 |
case 0x4: ic->f = instr(add); break; |
554 |
case 0x5: ic->f = instr(sub); break; |
555 |
default:goto bad; |
556 |
} |
557 |
break; |
558 |
|
559 |
case 0x9: |
560 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
561 |
ic->arg[1] = (size_t) &cpu->cd.rca180x.v[ib[1] >> 4]; |
562 |
switch (ib[1] & 0xf) { |
563 |
case 0x0: ic->f = instr(skne); break; |
564 |
default:goto bad; |
565 |
} |
566 |
break; |
567 |
|
568 |
case 0xa: |
569 |
ic->f = instr(mvi); |
570 |
ic->arg[0] = ((ib[0] & 0xf) << 8) + ib[1]; |
571 |
break; |
572 |
|
573 |
case 0xc: |
574 |
ic->f = instr(rand); |
575 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
576 |
ic->arg[1] = ib[1]; |
577 |
break; |
578 |
|
579 |
case 0xd: |
580 |
ic->f = instr(sprite); |
581 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
582 |
ic->arg[1] = (size_t) &cpu->cd.rca180x.v[ib[1] >> 4]; |
583 |
ic->arg[2] = ib[1] & 0xf; |
584 |
|
585 |
if (ic->arg[2] == 0) { |
586 |
fatal("xsprite: TODO\n"); |
587 |
goto bad; |
588 |
} |
589 |
break; |
590 |
|
591 |
case 0xe: |
592 |
/* Default arg 0: */ |
593 |
ic->arg[0] = ib[0] & 0xf; |
594 |
switch (ib[1]) { |
595 |
case 0x9e: ic->f = instr(skpr); break; |
596 |
case 0xa1: ic->f = instr(skup); break; |
597 |
default:goto bad; |
598 |
} |
599 |
break; |
600 |
|
601 |
case 0xf: |
602 |
/* Default arg 0: */ |
603 |
ic->arg[0] = (size_t) &cpu->cd.rca180x.v[ib[0] & 0xf]; |
604 |
switch (ib[1]) { |
605 |
case 0x07: |
606 |
ic->f = instr(gdelay); |
607 |
break; |
608 |
case 0x15: |
609 |
ic->f = instr(sdelay); |
610 |
break; |
611 |
case 0x18: |
612 |
ic->f = instr(ssound); |
613 |
break; |
614 |
case 0x1e: |
615 |
ic->f = instr(adi); |
616 |
break; |
617 |
case 0x29: |
618 |
ic->f = instr(font); |
619 |
break; |
620 |
case 0x33: |
621 |
ic->f = instr(bcd); |
622 |
break; |
623 |
case 0x55: |
624 |
ic->f = instr(str); |
625 |
ic->arg[0] = ib[0] & 0xf; |
626 |
break; |
627 |
case 0x65: |
628 |
ic->f = instr(ldr); |
629 |
ic->arg[0] = ib[0] & 0xf; |
630 |
break; |
631 |
default:goto bad; |
632 |
} |
633 |
break; |
634 |
|
635 |
default:goto bad; |
636 |
} |
637 |
|
638 |
|
639 |
#define DYNTRANS_TO_BE_TRANSLATED_TAIL |
640 |
#include "cpu_dyntrans.c" |
641 |
#undef DYNTRANS_TO_BE_TRANSLATED_TAIL |
642 |
} |
643 |
|