tags:

views:

60

answers:

2

I have an open-source Atari 2600 emulator (Z26), and I'd like to add support for cartridges containing an embedded ARM processor (NXP 21xx family). The idea would be to simulate the 6507 until it tries to read or write a byte of memory (which it will do every 841ns). If the 6507 performs a write, put the address and data on some of the ARM's I/O ports and let the ARM code run 20 cycles, confirm that the ARM is floating its data bus, and let the ARM run for another 38 cycles. If the 6507 performs a read, put the address on the ARM's I/O ports, let the ARM run 38 cycles, grab the data from the ARM's I/O port (hopefully the ARM software will have put it there), and let the ARM run another 20 cycles.

The ARM7 seems pretty straightforward to implement; I don't need to simulate a whole lot of hardware features. Any thoughts?

Edit What I have in mind would be a routine that would take as a parameter a struct holding the machine state and pointers to a memory access routine. When called, the routine would emulate the ARM's instruction engine, generating appropriate reads, writes, and code fetches. I could then write the memory access routine to regard appropriate areas as flash (with roughly-approximated wait states), RAM, I/O ports, and timer registers. Some other areas would be marked as don't-care, and accesses to any other areas would flag an error and stop the emulator.

Perhaps QEMU uses such a thing internally. Since the ARM emulation would be integrated into an already-existing emulation engine (which I didn't write and don't fully understand--the only parts of Z26 I've patched have been the memory read/write logic) I would need something with a fairly small footprint.

Any idea how QEMU works inside? Any idea what the GPL licence would require if I just use 2% of the code in QEMU--whether I'd have to bundle the code for the whole thing, or just the part that I use, or what?

A: 

Try QEMU.

Zack
@Zack: I'll take a look at that. It seems vastly overkill, but perhaps I can extract the part I'd need. I'll edit my question above to describe better what I have in mind.
supercat
+1  A: 

With some work, you can make my emulator do what you want. It was written for ARM920, and the Thumb instruction set isn't done yet. Neither is the MMU/cache interface. Also, it's slow because it is an interpreter. On the bright side, it's all written in C99.

http://code.google.com/p/gp2xemu/

I haven't worked on it for a while (The svn trunk is 2 years old), but if you're going to use the code, I'll be glad to help you out with the missing features. It is licensed under MIT, so it's just the same as the broad BSD license.

Mads Elvheim
@Mads Elvheim: Sounds like what I may be after, though I didn't see much code there. CPU.c didn't seem to have anything in it to actually execute instructions. Was I looking in the wrong place? BTW, my thought would be to build an interpreter which keeps for each word of memory an array holding pointers to routines to execute for that instruction and parameters therefor. The memory-write routine would reset the first routine pointer for the word to point to the "parse instruction" routine. That should allow good performance, portably.
supercat
Yeah, definitely the wrong place. Try http://code.google.com/p/gp2xemu/source/browse/trunk/gp2x-emu/src/emulator/instrset_armv4.cI tried your idea, by having a separate buffer with indices to functions, and flushed this buffer during self-modifying code. The problem is that memory barriers become extremely important then, or else self-modifying code can crash the emulator. That's why the svn version uses a stupid scheme for now. And no, performance is still not great even with opcode pre-parsing as you suggest.
Mads Elvheim
Continued: You could also keep track of "dirty" addresses in the function that writes memory, but that's more overhead per write, in addition to the MMU interface. This might be viable, as the instruction parsing is very slow at the moment. I started working on a dynamic recompiler earlier this year, but I don't have anything worthwhile to share yet.
Mads Elvheim
@Mads Elvheim: I'm not sure why self-modifying code would crash the emulator if the space for all the function pointers is allocated and remains so. The way I'd do things, would probably require ~36 bytes of RAM for every word of emulated memory, but unless one is emulating a really big system that shouldn't be a problem. Accurate emulation of prefetch behavior would probably be tricky, but my goal is to have a system I can use to develop and debug software, and know that if I follow certain conventions the real and emulated systems should behave similarly.
supercat
If the code modifies itself, your "pointer" or marker gets out of date. Funny things might happen, as you're running the wrong code, or worse, parsing the bits as the wrong instruction. As I mentioned, you can remedy this by keeping track of modified words, and re-parse them as necessary. But that's another check to do per-write and per-read.
Mads Elvheim
@Mads Elvheim: My expectation would be to have the memory-write routine unconditionally store a pointer to the "reparse" function in the first function pointer associated with a word. Since only a small portion of instructions are memory writes, the overhead from doing this should be small compared with the time saved by not having to reparse most instructions.
supercat
@Mads Elvheim: I suppose it's probably pointless, though, to speculate how I might design an emulator, unless I can't make yours work. I'd certainly be happy to share my thoughts regarding efficiency, but if you're not seeking such information it probably wouldn't be very helpful.
supercat
Did you actually try my code?
Mads Elvheim
@Mads Elvheim: I've looked at it a little, but haven't had a chance to try integrating it yet. I'd been rolling up my sleeves to code my own emulator, and then figured that before I began doing that I should make sure nothing suitable already exists. I'll probably look at it more this weekend. Should your code just link into a normal gcc project?
supercat
Yep. I did make a Makefile for it, if I remember correctly. Join the IRC network FreeNode, and the channels ##arm or #gp2xemu if you need help or have questions. I'm available from 4 pm to 12 am CET.
Mads Elvheim