/[gxemul]/trunk/src/cpus/cpu_rca180x.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 /trunk/src/cpus/cpu_rca180x.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (show annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 16885 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1421 2006/11/06 05:32:37 debug Exp $
20060816	Adding a framework for emulated/virtual timers (src/timer.c),
		using only setitimer().
		Rewriting the mc146818 to use the new timer framework.
20060817	Adding a call to gettimeofday() every now and then (once every
		second, at the moment) to resynch the timer if it drifts.
		Beginning to convert the ISA timer interrupt mechanism (8253
		and 8259) to use the new timer framework.
		Removing the -I command line option.
20060819	Adding the -I command line option again, with new semantics.
		Working on Footbridge timer interrupts; NetBSD/NetWinder and
		NetBSD/CATS now run at correct speed, but unfortunately with
		HUGE delays during bootup.
20060821	Some minor m68k updates. Adding the first instruction: nop. :)
		Minor Alpha emulation updates.
20060822	Adding a FreeBSD development specific YAMON environment
		variable ("khz") (as suggested by Bruce M. Simpson).
		Moving YAMON environment variable initialization from
		machine_evbmips.c into promemul/yamon.c, and adding some more
		variables.
		Continuing on the LCA PCI bus controller (for Alpha machines).
20060823	Continuing on the timer stuff: experimenting with MIPS count/
		compare interrupts connected to the timer framework.
20060825	Adding bogus SCSI commands 0x51 (SCSICDROM_READ_DISCINFO) and
		0x52 (SCSICDROM_READ_TRACKINFO) to the SCSI emulation layer,
		to allow NetBSD/pmax 4.0_BETA to be installed from CDROM.
		Minor updates to the LCA PCI controller.
20060827	Implementing a CHIP8 cpu mode, and a corresponding CHIP8
		machine, for fun. Disassembly support for all instructions,
		and most of the common instructions have been implemented: mvi,
		mov_imm, add_imm, jmp, rand, cls, sprite, skeq_imm, jsr,
		skne_imm, bcd, rts, ldr, str, mov, or, and, xor, add, sub,
		font, ssound, sdelay, gdelay, bogus skup/skpr, skeq, skne.
20060828	Beginning to convert the CHIP8 cpu in the CHIP8 machine to a
		(more correct) RCA 180x cpu. (Disassembly for all 1802
		instructions has been implemented, but no execution yet, and
		no 1805 extended instructions.)
20060829	Minor Alpha emulation updates.
20060830	Beginning to experiment a little with PCI IDE for SGI O2.
		Fixing the cursor key mappings for MobilePro 770 emulation.
		Fixing the LK201 warning caused by recent NetBSD/pmax.
		The MIPS R41xx standby, suspend, and hibernate instructions now
		behave like the RM52xx/MIPS32/MIPS64 wait instruction.
		Fixing dev_wdc so it calculates correct (64-bit) offsets before
		giving them to diskimage_access().
20060831	Continuing on Alpha emulation (OSF1 PALcode).
20060901	Minor Alpha updates; beginning on virtual memory pagetables.
		Removed the limit for max nr of devices (in preparation for
		allowing devices' base addresses to be changed during runtime).
		Adding a hack for MIPS [d]mfc0 select 0 (except the count
		register), so that the coproc register is simply copied.
		The MIPS suspend instruction now exits the emulator, instead
		of being treated as a wait instruction (this causes NetBSD/
		hpcmips to get correct 'halt' behavior).
		The VR41xx RTC now returns correct time.
		Connecting the VR41xx timer to the timer framework (fixed at
		128 Hz, for now).
		Continuing on SPARC emulation, adding more instructions:
		restore, ba_xcc, ble. The rectangle drawing demo works :)
		Removing the last traces of the old ENABLE_CACHE_EMULATION
		MIPS stuff (not usable with dyntrans anyway).
20060902	Splitting up src/net.c into several smaller files in its own
		subdirectory (src/net/).
20060903	Cleanup of the files in src/net/, to make them less ugly.
20060904	Continuing on the 'settings' subsystem.
		Minor progress on the SPARC emulation mode.
20060905	Cleanup of various things, and connecting the settings
		infrastructure to various subsystems (emul, machine, cpu, etc).
		Changing the lk201 mouse update routine to not rely on any
		emulated hardware framebuffer cursor coordinates, but instead
		always do (semi-usable) relative movements.
20060906	Continuing on the lk201 mouse stuff. Mouse behaviour with
		multiple framebuffers (which was working in Ultrix) is now
		semi-broken (but it still works, in a way).
		Moving the documentation about networking into its own file
		(networking.html), and refreshing it a bit. Adding an example
		of how to use ethernet frame direct-access (udp_snoop).
20060907	Continuing on the settings infrastructure.
20060908	Minor updates to SH emulation: for 32-bit emulation: delay
		slots and the 'jsr @Rn' instruction. I'm putting 64-bit SH5 on
		ice, for now.
20060909-10	Implementing some more 32-bit SH instructions. Removing the
		64-bit mode completely. Enough has now been implemented to run
		the rectangle drawing demo. :-)
20060912	Adding more SH instructions.
20060916	Continuing on SH emulation (some more instructions: div0u,
		div1, rotcl/rotcr, more mov instructions, dt, braf, sets, sett,
		tst_imm, dmuls.l, subc, ldc_rm_vbr, movt, clrt, clrs, clrmac).
		Continuing on the settings subsystem (beginning on reading/
		writing settings, removing bugs, and connecting more cpus to
		the framework).
20060919	More work on SH emulation; adding an ldc banked instruction,
		and attaching a 640x480 framebuffer to the Dreamcast machine
		mode (NetBSD/dreamcast prints the NetBSD copyright banner :-),
		and then panics).
20060920	Continuing on the settings subsystem.
20060921	Fixing the Footbridge timer stuff so that NetBSD/cats and
		NetBSD/netwinder boot up without the delays.
20060922	Temporarily hardcoding MIPS timer interrupt to 100 Hz. With
		'wait' support disabled, NetBSD/malta and Linux/malta run at
		correct speed.
20060923	Connecting dev_gt to the timer framework, so that NetBSD/cobalt
		runs at correct speed.
		Moving SH4-specific memory mapped registers into its own
		device (dev_sh4.c).
		Running with -N now prints "idling" instead of bogus nr of
		instrs/second (which isn't valid anyway) while idling.
20060924	Algor emulation should now run at correct speed.
		Adding disassembly support for some MIPS64 revision 2
		instructions: ext, dext, dextm, dextu.
20060926	The timer framework now works also when the MIPS wait
		instruction is used.
20060928	Re-implementing checks for coprocessor availability for MIPS
		cop0 instructions. (Thanks to Carl van Schaik for noticing the
		lack of cop0 availability checks.)
20060929	Implementing an instruction combination hack which treats
		NetBSD/pmax' idle loop as a wait-like instruction.
20060930	The ENTRYHI_R_MASK was missing in (at least) memory_mips_v2p.c,
		causing TLB lookups to sometimes succeed when they should have
		failed. (A big thank you to Juli Mallett for noticing the
		problem.)
		Adding disassembly support for more MIPS64 revision 2 opcodes
		(seb, seh, wsbh, jalr.hb, jr.hb, synci, ins, dins, dinsu,
		dinsm, dsbh, dshd, ror, dror, rorv, drorv, dror32). Also
		implementing seb, seh, dsbh, dshd, and wsbh.
		Implementing an instruction combination hack for Linux/pmax'
		idle loop, similar to the NetBSD/pmax case.
20061001	Changing the NetBSD/sgimips install instructions to extract
		files from an iso image, instead of downloading them via ftp.
20061002	More-than-31-bit userland addresses in memory_mips_v2p.c were
		not actually working; applying a fix from Carl van Schaik to
		enable them to work + making some other updates (adding kuseg
		support).
		Fixing hpcmips (vr41xx) timer initialization.
		Experimenting with O(n)->O(1) reduction in the MIPS TLB lookup
		loop. Seems to work both for R3000 and non-R3000.
20061003	Continuing a little on SH emulation (adding more control
		registers; mini-cleanup of memory_sh.c).
20061004	Beginning on a dev_rtc, a clock/timer device for the test
		machines; also adding a demo, and some documentation.
		Fixing a bug in SH "mov.w @(disp,pc),Rn" (the result wasn't
		sign-extended), and adding the addc and ldtlb instructions.
20061005	Contining on SH emulation: virtual to physical address
		translation, and a skeleton exception mechanism.
20061006	Adding more SH instructions (various loads and stores, rte,
		negc, muls.w, various privileged register-move instructions).
20061007	More SH instructions: various move instructions, trapa, div0s,
		float, fdiv, ftrc.
		Continuing on dev_rtc; removing the rtc demo.
20061008	Adding a dummy Dreamcast PROM module. (Homebrew Dreamcast
		programs using KOS libs need this.)
		Adding more SH instructions: "stc vbr,rn", rotl, rotr, fsca,
		fmul, fadd, various floating-point moves, etc. A 256-byte
		demo for Dreamcast runs :-)
20061012	Adding the SH "lds Rm,pr" and bsr instructions.
20061013	More SH instructions: "sts fpscr,rn", tas.b, and some more
		floating point instructions, cmp/str, and more moves.
		Adding a dummy dev_pvr (Dreamcast graphics controller).
20061014	Generalizing the expression evaluator (used in the built-in
		debugger) to support parentheses and +-*/%^&|.
20061015	Removing the experimental tlb index hint code in
		mips_memory_v2p.c, since it didn't really have any effect.
20061017	Minor SH updates; adding the "sts pr,Rn", fcmp/gt, fneg,
		frchg, and some other instructions. Fixing missing sign-
		extension in an 8-bit load instruction.
20061019	Adding a simple dev_dreamcast_rtc.
		Implementing memory-mapped access to the SH ITLB/UTLB arrays.
20061021	Continuing on various SH and Dreamcast things: sh4 timers,
		debug messages for dev_pvr, fixing some virtual address
		translation bugs, adding the bsrf instruction.
		The NetBSD/dreamcast GENERIC_MD kernel now reaches userland :)
		Adding a dummy dev_dreamcast_asic.c (not really useful yet).
		Implementing simple support for Store Queues.
		Beginning on the PVR Tile Accelerator.
20061022	Generalizing the PVR framebuffer to support off-screen drawing,
		multiple bit-depths, etc. (A small speed penalty, but most
		likely worth it.)
		Adding more SH instructions (mulu.w, fcmp/eq, fsub, fmac,
		fschg, and some more); correcting bugs in "fsca" and "float".
20061024	Adding the SH ftrv (matrix * vector) instruction. Marcus
		Comstedt's "tatest" example runs :) (wireframe only).
		Correcting disassembly for SH floating point instructions that
		use the xd* registers.
		Adding the SH fsts instruction.
		In memory_device_dyntrans_access(), only the currently used
		range is now invalidated, and not the entire device range.
20061025	Adding a dummy AVR32 cpu mode skeleton.
20061026	Various Dreamcast updates; beginning on a Maple bus controller.
20061027	Continuing on the Maple bus. A bogus Controller, Keyboard, and
		Mouse can now be detected by NetBSD and KOS homebrew programs.
		Cleaning up the SH4 Timer Management Unit, and beginning on
		SH4 interrupts.
		Implementing the Dreamcast SYSASIC.
20061028	Continuing on the SYSASIC.
		Adding the SH fsqrt instruction.
		memory_sh.c now actually scans the ITLB.
		Fixing a bug in dev_sh4.c, related to associative writes into
		the memory-mapped UTLB array. NetBSD/dreamcast now reaches
		userland stably, and prints the "Terminal type?" message :-]
		Implementing enough of the Dreamcast keyboard to make NetBSD
		accept it for input.
		Enabling SuperH for stable (non-development) builds.
		Adding NetBSD/dreamcast to the documentation, although it
		doesn't support root-on-nfs yet.
20061029	Changing usleep(1) calls in the debugger to to usleep(10000)
		(according to Brian Foley, this makes GXemul run better on
		MacOS X).
		Making the Maple "Controller" do something (enough to barely
		interact with dcircus.elf).
20061030-31	Some progress on the PVR. More test programs start running (but
		with strange output).
		Various other SH4-related updates.
20061102	Various Dreamcast and SH4 updates; more KOS demos run now.
20061104	Adding a skeleton dev_mb8696x.c (the Dreamcast's LAN adapter).
20061105	Continuing on the MB8696x; NetBSD/dreamcast detects it as mbe0.
		Testing for the release.

==============  RELEASE 0.4.3  ==============


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.c,v 1.2 2006/09/21 11:53:26 debug Exp $
29 *
30 * RCA180X CPU emulation.
31 *
32 * See http://www.elf-emulation.com/1802.html for a good list of 1802/1805
33 * opcodes.
34 */
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ctype.h>
40
41 #include "cpu.h"
42 #include "machine.h"
43 #include "memory.h"
44 #include "misc.h"
45 #include "settings.h"
46 #include "symbol.h"
47 #include "timer.h"
48
49
50 #define DYNTRANS_32
51 #include "tmp_rca180x_head.c"
52
53
54 static void rca180x_timer_tick(struct timer *timer, void *extra)
55 {
56 struct cpu *cpu = (struct cpu *) extra;
57 int dec = 3;
58
59 if (cpu->cd.rca180x.timer_mode_new)
60 dec = 1;
61
62 if (cpu->cd.rca180x.delay_timer_value > 0)
63 cpu->cd.rca180x.delay_timer_value -= dec;
64
65 if (cpu->cd.rca180x.sound_timer_value > 0)
66 cpu->cd.rca180x.sound_timer_value -= dec;
67
68 if (cpu->cd.rca180x.delay_timer_value < 0)
69 cpu->cd.rca180x.delay_timer_value = 0;
70 if (cpu->cd.rca180x.sound_timer_value < 0)
71 cpu->cd.rca180x.sound_timer_value = 0;
72 }
73
74
75 /*
76 * rca180x_cpu_new():
77 *
78 * Create a new RCA180X cpu object.
79 *
80 * Returns 1 on success, 0 if there was no matching RCA180X processor with
81 * this cpu_type_name.
82 */
83 int rca180x_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine,
84 int cpu_id, char *cpu_type_name)
85 {
86 int i;
87
88 if (strcasecmp(cpu_type_name, "RCA1802") != 0)
89 return 0;
90
91 /* TODO: RCA1805 etc */
92
93 cpu->run_instr = rca180x_run_instr;
94 cpu->memory_rw = rca180x_memory_rw;
95 cpu->update_translation_table = rca180x_update_translation_table;
96 cpu->invalidate_translation_caches =
97 rca180x_invalidate_translation_caches;
98 cpu->invalidate_code_translation = rca180x_invalidate_code_translation;
99 cpu->is_32bit = 1;
100
101 cpu->byte_order = EMUL_BIG_ENDIAN;
102
103 /*
104 * CHIP8 emulation:
105 */
106 cpu->cd.rca180x.sp = 0xff0;
107 cpu->cd.rca180x.xres = 64;
108 cpu->cd.rca180x.yres = 32;
109
110 cpu->cd.rca180x.framebuffer_cache = malloc(cpu->cd.rca180x.xres *
111 cpu->cd.rca180x.yres);
112 if (cpu->cd.rca180x.framebuffer_cache == NULL) {
113 fprintf(stderr, "Out of memory.\n");
114 exit(1);
115 }
116 memset(cpu->cd.rca180x.framebuffer_cache, 0, cpu->cd.rca180x.xres *
117 cpu->cd.rca180x.yres);
118
119 /* 18.2 Hz for original CHIP8, 60 Hz for new. */
120 cpu->cd.rca180x.timer_mode_new = 1;
121 cpu->cd.rca180x.timer = timer_add(
122 cpu->cd.rca180x.timer_mode_new? 60.0 : 18.2,
123 rca180x_timer_tick, cpu);
124
125
126 /* Only show name and caches etc for CPU nr 0 (in SMP machines): */
127 if (cpu_id == 0) {
128 debug("%s", cpu->name);
129 }
130
131 /* Add all register names to the settings: */
132 CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc);
133 CPU_SETTINGS_ADD_REGISTER16("index", cpu->cd.rca180x.index);
134 CPU_SETTINGS_ADD_REGISTER16("sp", cpu->cd.rca180x.sp);
135 CPU_SETTINGS_ADD_REGISTER8("d", cpu->cd.rca180x.d);
136 CPU_SETTINGS_ADD_REGISTER8("df", cpu->cd.rca180x.df);
137 CPU_SETTINGS_ADD_REGISTER8("ie", cpu->cd.rca180x.ie);
138 CPU_SETTINGS_ADD_REGISTER8("p", cpu->cd.rca180x.p);
139 CPU_SETTINGS_ADD_REGISTER8("q", cpu->cd.rca180x.q);
140 CPU_SETTINGS_ADD_REGISTER8("x", cpu->cd.rca180x.x);
141 CPU_SETTINGS_ADD_REGISTER8("t_p", cpu->cd.rca180x.t_p);
142 CPU_SETTINGS_ADD_REGISTER8("t_x", cpu->cd.rca180x.t_x);
143 CPU_SETTINGS_ADD_REGISTER8("chip8_mode", cpu->cd.rca180x.chip8_mode);
144 for (i=0; i<N_RCA180X_REGS; i++) {
145 char tmpstr[5];
146 snprintf(tmpstr, sizeof(tmpstr), "r%x", i);
147 CPU_SETTINGS_ADD_REGISTER16(tmpstr, cpu->cd.rca180x.r[i]);
148 }
149 for (i=0; i<N_CHIP8_REGS; i++) {
150 char tmpstr[5];
151 snprintf(tmpstr, sizeof(tmpstr), "v%x", i);
152 CPU_SETTINGS_ADD_REGISTER8(tmpstr, cpu->cd.rca180x.v[i]);
153 }
154
155 return 1;
156 }
157
158
159 /*
160 * rca180x_cpu_list_available_types():
161 *
162 * Print a list of available RCA180X CPU types.
163 */
164 void rca180x_cpu_list_available_types(void)
165 {
166 /* TODO: RCA1805... */
167 debug("RCA1802\n");
168 }
169
170
171 /*
172 * rca180x_cpu_dumpinfo():
173 */
174 void rca180x_cpu_dumpinfo(struct cpu *cpu)
175 {
176 debug("\n");
177 }
178
179
180 /*
181 * rca180x_cpu_register_dump():
182 *
183 * Dump cpu registers in a relatively readable format.
184 *
185 * gprs: set to non-zero to dump GPRs and some special-purpose registers.
186 * coprocs: set bit 0..3 to dump registers in coproc 0..3.
187 */
188 void rca180x_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
189 {
190 char *symbol;
191 uint64_t offset;
192 int i, x = cpu->cpu_id;
193
194 if (gprs) {
195 /* Special registers (pc, ...) first: */
196 symbol = get_symbol_name(&cpu->machine->symbol_context,
197 cpu->pc, &offset);
198
199 debug("cpu%i: pc=0x%x", x, (int)cpu->pc);
200 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
201
202 for (i=0; i<N_RCA180X_REGS; i++) {
203 if ((i % 4) == 0)
204 debug("cpu%i:", x);
205 debug(" r%x = 0x%04x", i, cpu->cd.rca180x.r[i]);
206 if ((i % 4) == 3)
207 debug("\n");
208 }
209
210 debug("cpu%i: d=0x%02x df=%i ie=%i q=%i p=0x%x x=0x%x t_p=0x%x "
211 "t_x=0x%x chip8_mode=%i\n", x,
212 cpu->cd.rca180x.d, cpu->cd.rca180x.df,
213 cpu->cd.rca180x.ie, cpu->cd.rca180x.q, cpu->cd.rca180x.p,
214 cpu->cd.rca180x.x, cpu->cd.rca180x.t_p, cpu->cd.rca180x.t_x,
215 cpu->cd.rca180x.chip8_mode);
216
217 if (cpu->cd.rca180x.chip8_mode) {
218 for (i=0; i<N_CHIP8_REGS; i++) {
219 if ((i % 8) == 0)
220 debug("cpu%i:", x);
221 debug(" v%x=0x%02x", i, cpu->cd.rca180x.v[i]);
222 if ((i % 8) == 7)
223 debug("\n");
224 }
225
226 debug("cpu%i: i=0x%04x sp=0x%03x delay=%i sound=%i\n",
227 x, cpu->cd.rca180x.index, cpu->cd.rca180x.sp,
228 cpu->cd.rca180x.delay_timer_value,
229 cpu->cd.rca180x.sound_timer_value);
230 }
231 }
232 }
233
234
235 /*
236 * rca180x_cpu_tlbdump():
237 *
238 * Called from the debugger to dump the TLB in a readable format.
239 * x is the cpu number to dump, or -1 to dump all CPUs.
240 *
241 * If rawflag is nonzero, then the TLB contents isn't formated nicely,
242 * just dumped.
243 */
244 void rca180x_cpu_tlbdump(struct machine *m, int x, int rawflag)
245 {
246 }
247
248
249 /*
250 * rca180x_cpu_gdb_stub():
251 *
252 * Execute a "remote GDB" command. Returns a newly allocated response string
253 * on success, NULL on failure.
254 */
255 char *rca180x_cpu_gdb_stub(struct cpu *cpu, char *cmd)
256 {
257 fatal("rca180x_cpu_gdb_stub(): TODO\n");
258 return NULL;
259 }
260
261
262 /*
263 * rca180x_cpu_interrupt():
264 */
265 int rca180x_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)
266 {
267 fatal("rca180x_cpu_interrupt(): TODO\n");
268 return 0;
269 }
270
271
272 /*
273 * rca180x_cpu_interrupt_ack():
274 */
275 int rca180x_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)
276 {
277 /* fatal("rca180x_cpu_interrupt_ack(): TODO\n"); */
278 return 0;
279 }
280
281
282 /*
283 * chip8_cpu_disassemble_instr():
284 *
285 * Convert an instruction word into human readable format, for instruction
286 * tracing and disassembly.
287 *
288 * If running is 1, cpu->pc should be the address of the instruction.
289 *
290 * If running is 0, things that depend on the runtime environment (eg.
291 * register contents) will not be shown, and addr will be used instead of
292 * cpu->pc for relative addresses.
293 */
294 int chip8_cpu_disassemble_instr(struct cpu *cpu, unsigned char *ib,
295 int running, uint64_t dumpaddr)
296 {
297 uint64_t offset;
298 char *symbol, *mnem;
299 int no_y;
300
301 if (running)
302 dumpaddr = cpu->pc;
303
304 symbol = get_symbol_name(&cpu->machine->symbol_context,
305 dumpaddr, &offset);
306 if (symbol != NULL && offset==0)
307 debug("<%s>\n", symbol);
308
309 if (cpu->machine->ncpus > 1 && running)
310 debug("cpu%i: ", cpu->cpu_id);
311
312 debug("0x%04x: %02x%02x\t", (int)dumpaddr, ib[0], ib[1]);
313
314 switch (ib[0] >> 4) {
315
316 case 0x0:
317 switch(ib[0] & 0xf) {
318 case 0x0:
319 switch(ib[1] >> 4) {
320 case 0xc:
321 debug("scdown\t%i\n", ib[1] & 0xf);
322 break;
323 case 0xe:
324 switch(ib[1] & 0xf) {
325 case 0x0:
326 debug("cls");
327 break;
328 case 0xe:
329 debug("rts");
330 break;
331 default:debug("UNIMPLEMENTED");
332 }
333 break;
334 case 0xf:
335 switch(ib[1] & 0xf) {
336 case 0xb:
337 debug("scright");
338 break;
339 case 0xc:
340 debug("scleft");
341 break;
342 case 0xe:
343 debug("low");
344 break;
345 case 0xf:
346 debug("high");
347 break;
348 default:debug("UNIMPLEMENTED");
349 }
350 break;
351
352 default:debug("UNIMPLEMENTED");
353 }
354 break;
355
356 default:debug("call\t0x%04x", (ib[0] << 8) + ib[1]);
357 }
358 break;
359
360 case 0x1:
361 case 0x2:
362 debug("%s\t0x%03x",
363 (ib[0] >> 4) == 0x1? "jmp" : "jsr",
364 ((ib[0] & 0xf) << 8) + ib[1]);
365 break;
366
367 case 0x3:
368 case 0x4:
369 debug("%s\tv%x, 0x%02x",
370 (ib[0] >> 4) == 0x3? "skeq" : "skne",
371 ib[0] & 0xf, ib[1]);
372 break;
373
374 case 0x5:
375 if ((ib[1] & 0xf) == 0)
376 debug("skeq\tv%x, v%x", ib[0] & 0xf, ib[1] >> 4);
377 else
378 debug("UNIMPLEMENTED (skeq, but low nibble non-zero)");
379 break;
380
381 case 0x6:
382 case 0x7:
383 debug("%s\tv%x, 0x%02x",
384 (ib[0] >> 4) == 0x6? "mov" : "add",
385 ib[0] & 0xf, ib[1]);
386 break;
387
388 case 0x8:
389 mnem = "UNIMPLEMENTED";
390 no_y = 0;
391
392 switch (ib[1] & 0xf) {
393 case 0: mnem = "mov"; break;
394 case 1: mnem = "or"; break;
395 case 2: mnem = "and"; break;
396 case 3: mnem = "xor"; break;
397 case 4: mnem = "add"; break;
398 case 5: mnem = "sub"; break;
399 case 6: mnem = "shr"; no_y = 1; break;
400 case 7: mnem = "rsb"; break;
401 case 14: mnem = "shl"; no_y = 1; break;
402 }
403
404 debug("%s\tv%x", mnem, ib[0] & 0xf);
405 if (!no_y)
406 debug(", v%x", ib[1] >> 4);
407 break;
408
409 case 0x9:
410 if ((ib[1] & 0xf) == 0)
411 debug("skne\tv%x, v%x", ib[0] & 0xf, ib[1] >> 4);
412 else
413 debug("UNIMPLEMENTED (skne, but low nibble non-zero)");
414 break;
415
416 case 0xa:
417 case 0xb:
418 debug("%s\t0x%03x",
419 (ib[0] >> 4) == 0xa? "mvi" : "jmi",
420 ((ib[0] & 0xf) << 8) + ib[1]);
421 break;
422
423 case 0xc:
424 debug("rand\tv%x, 0x%02x", ib[0] & 0xf, ib[1]);
425 break;
426
427 case 0xd:
428 if ((ib[1] & 0xf) == 0)
429 debug("xsprite\tv%x, v%x",
430 ib[0] & 0xf, ib[1] >> 4);
431 else
432 debug("sprite\tv%x, v%x, %i",
433 ib[0] & 0xf, ib[1] >> 4, ib[1] & 0xf);
434 break;
435
436 case 0xe:
437 switch (ib[1]) {
438 case 0x9e:
439 case 0xa1:
440 debug("%s\t%x",
441 ib[1] == 0x9e? "skpr" : "skup", ib[0] & 0xf);
442 break;
443 default:debug("UNIMPLEMENTED");
444 }
445 break;
446
447 case 0xf:
448 switch (ib[1]) {
449 case 0x07:
450 case 0x0a:
451 case 0x15:
452 case 0x18:
453 case 0x1e:
454 case 0x29:
455 case 0x30:
456 case 0x33:
457 mnem = NULL;
458 switch (ib[1]) {
459 case 0x07: mnem = "gdelay"; break;
460 case 0x0a: mnem = "key"; break;
461 case 0x15: mnem = "sdelay"; break;
462 case 0x18: mnem = "ssound"; break;
463 case 0x1e: mnem = "adi"; break;
464 case 0x29: mnem = "font"; break;
465 case 0x30: mnem = "xfont"; break;
466 case 0x33: mnem = "bcd"; break;
467 }
468 debug("%s\tv%x", mnem, ib[0] & 0xf);
469 break;
470 case 0x55:
471 case 0x65:
472 mnem = NULL;
473 switch (ib[1]) {
474 case 0x55: mnem = "str"; break;
475 case 0x65: mnem = "ldr"; break;
476 }
477 debug("%s\tv0-v%x", mnem, ib[0] & 0xf);
478 break;
479 default:debug("UNIMPLEMENTED");
480 }
481 break;
482
483 default:debug("UNIMPLEMENTED");
484 }
485
486 debug("\n");
487
488 return sizeof(uint16_t);
489 }
490
491
492 /*
493 * rca180x_cpu_disassemble_instr():
494 *
495 * Convert an instruction word into human readable format, for instruction
496 * tracing and disassembly.
497 *
498 * If running is 1, cpu->pc should be the address of the instruction.
499 *
500 * If running is 0, things that depend on the runtime environment (eg.
501 * register contents) will not be shown, and addr will be used instead of
502 * cpu->pc for relative addresses.
503 */
504 int rca180x_cpu_disassemble_instr(struct cpu *cpu, unsigned char *ib,
505 int running, uint64_t dumpaddr)
506 {
507 uint64_t offset;
508 char *symbol, *mnem = NULL;
509 int len, no_reg=0;
510
511 if (cpu->cd.rca180x.chip8_mode)
512 return chip8_cpu_disassemble_instr(cpu, ib, running, dumpaddr);
513
514 if (running)
515 dumpaddr = cpu->pc;
516
517 symbol = get_symbol_name(&cpu->machine->symbol_context,
518 dumpaddr, &offset);
519 if (symbol != NULL && offset==0)
520 debug("<%s>\n", symbol);
521
522 if (cpu->machine->ncpus > 1 && running)
523 debug("cpu%i: ", cpu->cpu_id);
524
525 debug("0x%04x:\t%02x", (int)dumpaddr, ib[0]);
526 len = 1;
527
528 switch (ib[0] >> 4) {
529
530 case 0x0:
531 case 0x1:
532 case 0x2:
533 case 0x4:
534 case 0x5:
535 case 0x8:
536 case 0x9:
537 case 0xa:
538 case 0xb:
539 case 0xd:
540 case 0xe:
541 switch (ib[0] >> 4) {
542 case 0x0: mnem = "ldn";
543 if (ib[0] == 0x00) {
544 no_reg = 1;
545 mnem = "idl";
546 }
547 break;
548 case 0x1: mnem = "inc"; break;
549 case 0x2: mnem = "dec"; break;
550 case 0x4: mnem = "lda"; break;
551 case 0x5: mnem = "str"; break;
552 case 0x8: mnem = "glo"; break;
553 case 0x9: mnem = "ghi"; break;
554 case 0xa: mnem = "plo"; break;
555 case 0xb: mnem = "phi"; break;
556 case 0xd: mnem = "sep"; break;
557 case 0xe: mnem = "sex"; break;
558 }
559 debug("\t%s", mnem);
560 if (!no_reg)
561 debug("\tr%x", ib[0] & 0xf);
562 break;
563
564 case 0x3:
565 len ++;
566 debug("%02x\t", ib[1]);
567
568 switch (ib[0] & 0xf) {
569 case 0x0: debug("br"); break;
570 case 0x1: debug("bq"); break;
571 case 0x2: debug("bz"); break;
572 case 0x3: debug("bdf"); break;
573 case 0x4: debug("b1"); break;
574 case 0x5: debug("b2"); break;
575 case 0x6: debug("b3"); break;
576 case 0x7: debug("b4"); break;
577 case 0x8: debug("nbr"); break;
578 case 0x9: debug("bnq"); break;
579 case 0xa: debug("bnz"); break;
580 case 0xb: debug("bnf"); break;
581 case 0xc: debug("bn1"); break;
582 case 0xd: debug("bn2"); break;
583 case 0xe: debug("bn3"); break;
584 case 0xf: debug("bn4"); break;
585 }
586
587 debug("\t0x%04x", ((dumpaddr + 1) & 0xff00) + ib[1]);
588 break;
589
590 case 0x6:
591 switch (ib[0] & 0xf) {
592 case 0x0:
593 debug("\tirx");
594 break;
595 case 0x8:
596 debug("\tTODO: 1805 instruction!");
597 break;
598 default:
599 debug("\t%s%i", ib[0] & 8? "inp" : "out", ib[0] & 7);
600 }
601 break;
602
603 case 0x7:
604 switch (ib[0] & 0xf) {
605
606 case 0x0: debug("\tret"); break;
607 case 0x1: debug("\tdis"); break;
608 case 0x2: debug("\tldxa"); break;
609 case 0x3: debug("\tstxd"); break;
610 case 0x4: debug("\tadc"); break;
611 case 0x5: debug("\tsdb"); break;
612 case 0x6: debug("\tshrc"); break;
613 case 0x7: debug("\tsmb"); break;
614 case 0x8: debug("\tsav"); break;
615 case 0x9: debug("\tmark"); break;
616 case 0xa: debug("\treq"); break;
617 case 0xb: debug("\tseq"); break;
618 case 0xe: debug("\tshlc"); break;
619
620 default:
621 switch (ib[0] & 0xf) {
622 case 0xc: mnem = "adci"; break;
623 case 0xd: mnem = "sdbi"; break;
624 case 0xf: mnem = "smbi"; break;
625 }
626 len ++;
627 debug("%02x\t%s\t0x%02x", ib[1], mnem, ib[1]);
628 break;
629 }
630 break;
631
632 case 0xc:
633 len += 2;
634 debug("%02x%02x\t", ib[1], ib[2]);
635
636 switch (ib[0] & 0xf) {
637 case 0x0: debug("lbr"); break;
638 case 0x1: debug("lbq"); break;
639 case 0x2: debug("lbz"); break;
640 case 0x3: debug("lbdf"); break;
641 case 0x4: debug("nop"); break;
642 case 0x5: debug("lsnq"); break;
643 case 0x6: debug("lsnz"); break;
644 case 0x7: debug("lsnf"); break;
645 case 0x8: debug("nlbr"); break;
646 case 0x9: debug("lbnq"); break;
647 case 0xa: debug("lbnz"); break;
648 case 0xb: debug("lbnf"); break;
649 case 0xc: debug("lsie"); break;
650 case 0xd: debug("lsq"); break;
651 case 0xe: debug("lsz"); break;
652 case 0xf: debug("lsdf"); break;
653 }
654
655 debug("\t0x%02x%02x", ib[1], ib[2]);
656 break;
657
658 case 0xf:
659 switch (ib[0] & 0xf) {
660
661 case 0x0: debug("\tldx"); break;
662 case 0x1: debug("\tor"); break;
663 case 0x2: debug("\tand"); break;
664 case 0x3: debug("\txor"); break;
665 case 0x4: debug("\tadd"); break;
666 case 0x5: debug("\tsb"); break;
667 case 0x6: debug("\tshr"); break;
668 case 0x7: debug("\tsm"); break;
669 case 0xe: debug("\tshl"); break;
670
671 default:
672 switch (ib[0] & 0xf) {
673 case 0x8: mnem = "ldi"; break;
674 case 0x9: mnem = "ori"; break;
675 case 0xa: mnem = "ani"; break;
676 case 0xb: mnem = "xri"; break;
677 case 0xc: mnem = "adi"; break;
678 case 0xd: mnem = "sdi"; break;
679 case 0xf: mnem = "smi"; break;
680 }
681 len ++;
682 debug("%02x\t%s\t0x%02x", ib[1], mnem, ib[1]);
683 break;
684 }
685 break;
686
687 default:debug("\tUNIMPLEMENTED");
688 }
689
690 debug("\n");
691
692 return len;
693 }
694
695
696 #include "tmp_rca180x_tail.c"
697

  ViewVC Help
Powered by ViewVC 1.1.26