I always prefer reusable, flexible and easily maintained code so I'm on board with modeling this in C. I actually took some time the other day to parse Turbo68k to see what you had done there and saw what you described. I feel foolish for asking but what executes the emitted code? They are just a set of strings, right? I also saw a reference to some dude named Tyranid on your page. He seems to be big in the hacking/homebrew scene. He's a big player in the public SDK that was built for the PSP.
I didn't really intend to build an emulator from the ground up. There are a lot of details that I'm not altogether interested in. There's an SNES9x port for the PSP and I had planned on incrementally modifying it with code that's tailored for the PSP architecture. Namely injecting efficient code where necessary (modifying the CPU cores where necessary). This way I already have the blueprint for execution. On first blush it seems that the graphics emulation may need some tweaks as there are glitches and there are certain effects that noticeably tax the PSP.
And I also agree with premature optimizations; I was letting myself get carried away with this project. I've tried to contact some of the authors of the PSP port but my email is understandably being ignored. I'd like to know what they have to say about where the optimizations would best be served. There's a PSP profiling tool and I'll run some tests with that, time permitting.
Just to clarify, when you talk about passing the context of the CPU we're talking about something like a struct in the C world, right? I'm devolving from the OO world I've been living in for the past 3 years to go back to the procedural ways of C/assembler. I'm glad that modular design is still available to some degree :-P
> It's been a while for me, but here are some thoughts:
> Most CPU cores are written to be flexible and reusable and are therefore not
> aware of the system's memory map. They call handlers to read/write the address
> space and these handlers are defined elsewhere in the emulator and passed to the
> CPU emulator during initialization. If you're going for absolute speed and don't
> mind trading off design elegance, I suppose there may be an opportunity to
> optimize this process by identifying when a write to memory is occurring and
> somehow inlining it. It ultimately might not gain you very much in an
> interpreter, it's hard to say.
> As for registers, I think you've got the basic idea, but have you looked at
> other CPU cores? Typically, registers are stored in a CPU context which
> describes the complete state of the CPU. If you wanted to go for maximum
> flexibility and re-usability, you would have this context passed as a parameter
> to every CPU function, thereby eliminating global variables and allowing an
> unlimited number of CPUs to be emulated within a program. Of course, this might
> be overkill. I don't know of any systems that use more than one of these
> processors, so there's no point in over-designing. Some CPU cores have a fixed,
> statically allocated area for the context and provide functions (GetContext(),
> SetContext()) to read the context out and write it back in. In your case, this
> is probably what you'd want to do. To take advantage of the large MIPS register
> set, you should be able to keep the 65C816 registers inside a subset of the MIPS
> registers during CPU emulation: load them up at the beginning of a call to
> CPU_Run(), and then save them to your context at the end. IIRC, the 65C816 has
> few registers, so this should involve only a handful of loads and stores.
> Finally, it's a good idea to write assembly language CPU cores in the form of a
> program (C or whatever language you're most comfortable with) that emits them.
> There is a ton of redundancy in a CPU emulator that this helps manage and, if
> done properly, is more maintainable. I did it once with Turbo68K and it was a
> disaster because I didn't have the necessary practice and had only seen it done
> with Starscream and Neil Bradley's emulators. It might take a couple of
> revisions and a lot of work, but it would be well worth it. Should you decide
> that you want to change how something is handled (registers for example, or
> memory handling -- inlined or using callbacks), you'll need to modify less
> actual code.
> Anyway, I would recommend using a known C core first. It's not a good idea to
> start writing an emulator with a CPU core if you don't absolutely have to.
> You'll have a hard time finding core bugs which will stop games from running,
> and even worse, you'll be optimizing prematurely. I would say, get the basic
> structure of the rest of the emulator worked out and running entirely in C, and
> then start optimizing from there. It's a much more sound design process and
> you'll be able to see more progress quickly.
> > So I've gotten myself all set up with PSP dev. I have the libraries, SDK and
> > Eclipse for the IDE. Everything was written for Linux so I'm running on my
> > Ubuntu partition. I've managed to compile programs and I've gotten past the
> > Hello, world! stuffs.
> > Now I'm looking at implementing my first CPU core using MIPS assembler.
> > as you've written one or two cores of your own I just wanted to bounce some
> > ideas off of you.
> > So here's my first idea. Upon initialization of the program I allocate memory
> > to mirror the memory available to the CPU I'm emulating (5A22 aka custom
> > 65c816). I also allocate memory to store the registers. Once execution
> > I load up the initial state of the registers from memory and put them resident
> > to the many available registers of the Allegrex (PSP's custom MIPS32
> > I then interpret incoming opcodes and manipulate the registers almost as if
> > it's the emulated CPU performing the activities itself (and taking advantage
> > the speed). When it comes time to perform other duties (give up the CPU, run
> > another emulated processor, etc.) I just save the contents of the registers to
> > memory to perform a pseudo context switch.
> > I'm sure things will change once I get into the nitty gritty. These are just
> > initial thoughts. I'm far from effective in MIPS32 ISA. I'm going to spend
> > time writing functions to emulate the opcodes of the SNES's main processor. I
> > think the PPU needs the help more but I'm more comfortable with the 5A22
> > documentation.
> > pixel-eight.com