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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (show annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 15462 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_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 = &nothing_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 = &nothing_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

  ViewVC Help
Powered by ViewVC 1.1.26