Forum Index | FAQ | New User | Login | Search

Make a New PostPrevious ThreadView All ThreadsNext Thread*Show in Threaded Mode


SubjectBart, some thoughts on my PSP dev new Reply to this message
Posted bySnowball 2
Posted on12/11/07 08:04 PM



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. Seeing 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 begins 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 processor). I then interpret incoming opcodes and manipulate the registers almost as if it's the emulated CPU performing the activities itself (and taking advantage of 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 my initial thoughts. I'm far from effective in MIPS32 ISA. I'm going to spend my 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



SubjectRe: Bart, some thoughts on my PSP dev new Reply to this message
Posted byBart T.
Posted on12/12/07 01:15 PM



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. Seeing
> 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 begins
> 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 processor).
> I then interpret incoming opcodes and manipulate the registers almost as if
> it's the emulated CPU performing the activities itself (and taking advantage of
> 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 my
> initial thoughts. I'm far from effective in MIPS32 ISA. I'm going to spend my
> 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
>



SubjectRe: Bart, some thoughts on my PSP dev Reply to this message
Posted bySnowball 2
Posted on12/13/07 00:24 AM



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.
> Seeing
> > 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
> begins
> > 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
> processor).
> > I then interpret incoming opcodes and manipulate the registers almost as if
> > it's the emulated CPU performing the activities itself (and taking advantage
> of
> > 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
> my
> > initial thoughts. I'm far from effective in MIPS32 ISA. I'm going to spend
> my
> > 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
> >
>


pixel-eight.com



SubjectRe: Bart, some thoughts on my PSP dev new Reply to this message
Posted byBart T.
Posted on12/13/07 03:25 AM



> 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.

Avert your eyes from Turbo68K :) There should be better CPU cores based around this principle. IIRC, Neil Bradley's cores did it, and maybe A68K?

>I feel
> foolish for asking but what executes the emitted code? They are just a set of
> strings, right?

It spits out assembly source code and you assemble it with NASM. It's not done at run-time, but at compile time as part of the build process. The idea is that there is going to be a lot (a LOT) of redundancy in the assembly code, so why not write once, and emit it over and over again?

You could argue that macros would help, and that's true, but you have way more flexibility with the emitter approach. Also, many instruction handlers are almost identical (the only difference is that they inline some of the register accesses) so it makes sense to generate them in an automated fashion rather than to re-type them by hand, even with macros. For example: for the 68K instructions involving at least one register, the emitter emits 8 unique instances or so (and sets up the jump table appropriately by pointing to each one) by decoding the 3-bit register field and hard-coding that read/write for each different register. That way, less of the instruction operands have to be decoded inside each function, speeding things up (although perhaps at the cost of cache performance -- A68K does less of this and runs faster.)

> 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.

Yeah, I don't know the guy well, but he wrote a Saturn debugger which was pretty cool.

>SNES9x port for
> the PSP and I had planned on incrementally modifying it with code that's
> tailored for the PSP architecture.

That's not a bad idea. Isn't SNES9X fairly accurate? It sounds like you could modify quite a bit to get it up to speed.

> emulation may need some tweaks as there are glitches and there are certain
> effects that noticeably tax the PSP.

Graphics will be the hardest task, and will probably require several rewrites and some very clever ideas. It'll be more than just trying to beat the compiler's output by writing your own assembly code. Rather, it'll have to be about smart design as well as how you can leverage the PSP at the assembly language level when thinking up your design.


> 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?

Right.

> 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

You can still use OO design principles.



----
Bart


Previous ThreadView All ThreadsNext Thread*Show in Threaded Mode