It's unfussy and quick to code, and has good string & array manipulation. I suppose I use it like someone who knows Perl would use Perl.creaothceann wrote:Why PHP, though?
Try my Java SNES emulator? :)
Moderator: General Mods
That was the gist of it, but I'll go into more detail.Explain this. I don't follow but I really want to! By the way something I tried very early on was to split the complex banks into smaller objects so instead of using if/elses to dissect the address ranges it would use some of the upper bits of the 16-bit bank offset as an index into an array of more function pointer things. It turned out slower, though.
Okay, so the smallest block of memory is the GSU1, it spans 00-3f|80-bf:3000-32ff. 768 bytes, and since that's not divisible cleanly, we end up with 256.
So the net result is we need a page table, 64k entries. I know, that's a lot of memory, 256KB on a 32-bit system.
So now you would do:
Page &p = page[addr >> 8];
uint8 read = p.read(addr + p.offset);
p.write(addr + p.offset, write);
MMIO tends to map individual registers, but they always appear in 00-3f|80-bf:2000-5fff, so I special case those. I set their page[] entries to a special MMIO class. This class has 16K entries and performs one last indirection.
uint8 read = mmio[addr & 0x3fff].read(addr);
mmio[addr & 0x3fff].write(addr, write);
We want the full 24-bit address passed through to the final read/write, as the BS-X mapper treats an access to 00:5000 differently than to 01:5000, etc.
Now whenever you load a ROM, you initialize this table. You would have a class to represent ROM, and it would inherit from whatever type the page[] table is.
So say you map 01:8000-80ff in LoROM, you would have a call to:
uint8 ROM::read(unsigned addr) {
//addr = 0x018000 + offset
return rom_data[addr];
}
offset in this case would have been set in the page table during ROM load. Since we really want 0x8000, offset would be -0x010000; thus 0x018000 + -0x010000 == 0x8000.
And we sit back and laugh at the idiots who say Java is purer because it doesn't have pointer arithmetic =)
99% of games do not have any memory mapping capabilities, the only ones that do:
BS-X town cartridge + Satellaview downloaded games
S-DD1 games (2 total)
SPC7110 games (effectively 3 total)
And even then, it's not like they do nothing but remap constantly. Still, make your remapper fast. Or if it really bothers you, you can always make a special class that does the MMC functions for you, eg:
uint8 SDD1::read(unsigned addr) {
addr = transform_addr_per_MMC_settings(addr);
return ROM[addr];
}
Also, you're getting close to multiple inheritance here, but if you can make your CPU+PPU inheritable by the MMIO[] base type, you can map the objects directly into your tables. This bypasses your need for a dispatcher that shunts one range to the PPU, one to the APU, and one to the CPU.
Anyway, it may be a bit slower, I don't know. You know me, I've always valued code readability and maintainability over speed. And it allowed me to implement XML-based memory mapping in a day, which would seem to be impossible with your model :(
We definitely have our differences in approach, especially with regards to language, but it is always fun seeing the similarities.Those op files are compiled with a rather big and uglyish PHP parser, but there are two big advantages:
(1) reduced code duplication
(2) I can directly compare, for each CPU, running the opcodes with a switch block versus arrays of function pointers, and also ways of handling the states of the M/X/E CPU flag bits, because it takes seconds to switch between different ways of generating the code.
I did the exact same thing with a custom parser:
Code: Select all
bcc(0x90, !regs.p.c),
bcs(0xb0, regs.p.c),
bne(0xd0, !regs.p.z),
beq(0xf0, regs.p.z),
bpl(0x10, !regs.p.n),
bmi(0x30, regs.p.n),
bvc(0x50, !regs.p.v),
bvs(0x70, regs.p.v) {
if(!$1) last_cycle();
rd.l = op_readpc();
if($1) {
aa.w = regs.pc.d + (int8)rd.l;
regs.pc.w = aa.w;
} else {
end;
}
op_io_cond6(aa.w);
last_cycle();
op_io();
}
What I've discovered in regards to that is that speed is the same. The jump table is more eloquent from an optimization standpoint (it won't overwhelm the compiler with a 50,000-line function), but the switch table compiles faster (doesn't have to make 256*~1-5 functions) and produces a slightly smaller binary.
I've never noticed a difference in speed. The switch table just becomes a jump table after compilation anyway.
I go with a jump table now because I generate the code using C++ templates now. I guess I just really hated having to invoke a pre-processor prior to compilation, though you could automate that with fancy Makefile rules, too. Eh, whatever.
Really, I would say if Java has it, run a profiler on your code. I made the mistake earlier on of considering optimizations just like this, switch vs function pointer, 16-bit read optimizations, NZ flag optimizations, etc. It's focusing on stuff that really doesn't matter.
If you really want to gain massive speed benefits, the most important parts are PPU rendering and S-CPU interrupt testing.
8-bit page division is something I've tried, but it was within the 16-bit bank division system. So that's two levels of objects, and it wasn't worth it. I suppose I could try redoing the CPU to use 8-bit pages everywhere, but 16-bit banks align naturally with most of the the address wrapping logic of the 65816, and its PB & DB registers.byuu wrote:So now you would do:
Page &p = page[addr >> 8];
uint8 read = p.read(addr + p.offset);
p.write(addr + p.offset, write);
I've not done any of the BS-X, S-DD1, or SPC7110 things, so I might have to rethink the memory mapping logic as I do those, I dunno.
I've discovered this with the NES. Some games flip segments in and out rapidly, so I break the PRG ROM and CHR ROM arrays into small chunks that can be mapped in and out of byte[][] arrays with simple pointer assignment instead of copying memory. During normal execution then, there aren't even any offsets to add. (It's a sorry substitute for real pointer arithmetic though.)Still, make your remapper fast.
Elegant!, though I don't think there's any real advantage to it.if you can make your CPU+PPU inheritable by the MMIO[] base type, you can map the objects directly into your tables. This bypasses your need for a dispatcher that shunts one range to the PPU, one to the APU, and one to the CPU.
Oh the PPU, definitely, but since I only aim for opcode-level accuracy on most of the rest of the system, interrupts are happily trivial.If you really want to gain massive speed benefits, the most important parts are PPU rendering and S-CPU interrupt testing.
Java has a bytecode instruction for switch jump tables, but the VM doesn't use it to actually implement a jump table once compiling to native code. So manually coding a function pointer table makes a *massive* difference.The switch table just becomes a jump table after compilation anyway.
-
- ZSNES Shake Shake Prinny
- Posts: 5632
- Joined: Wed Jul 28, 2004 4:15 pm
- Location: PAL50, dood !
For reference, if you drop the "i know what's on the other side already" approach and go for a hardware approach, the smallest block is still 256, with 00-3F(7):2100-21FF being bound to address bus B.byuu wrote:Okay, so the smallest block of memory is the GSU1, it spans 00-3f|80-bf:3000-32ff. 768 bytes, and since that's not divisible cleanly, we end up with 256.
皆黙って俺について来い!!
Pantheon: Gideon Zhi | CaitSith2 | Nach | kode54
Code: Select all
<jmr> bsnes has the most accurate wiki page but it takes forever to load (or something)
Well, technically B breaks down further.
2100-213f = PPU
2140-217f = APU
2180-2183 = CPU
2184+ = BS-X base unit, Exertainment Bike, and if my memory of a forum post years ago is correct, the Ultra-16; and maybe the SFC Box too.
Of course, a purer method would be to multicast the access to all chips on the B bus and let them decide whether or not they want to respond, heh.
2100-213f = PPU
2140-217f = APU
2180-2183 = CPU
2184+ = BS-X base unit, Exertainment Bike, and if my memory of a forum post years ago is correct, the Ultra-16; and maybe the SFC Box too.
Of course, a purer method would be to multicast the access to all chips on the B bus and let them decide whether or not they want to respond, heh.
-
- New Member
- Posts: 2
- Joined: Wed Aug 15, 2012 6:05 pm
Re: Try my Java SNES emulator? :)
Hi there,
Do you intend on releasing the source code?
Or would you like to work something out together?
I would love to hack an Android version... !!
I think we could hack games like Pac-Man 2 to run amazingly on the touch screen. =)
Cheers*
Do you intend on releasing the source code?
Or would you like to work something out together?
I would love to hack an Android version... !!
I think we could hack games like Pac-Man 2 to run amazingly on the touch screen. =)
Cheers*
-
- New Member
- Posts: 2
- Joined: Wed Aug 15, 2012 6:05 pm
Re: Try my Java SNES emulator? :)
This is a noob post... please don't kill me. :p
I got an email saying there was a reply to this thread... I don't see any. Please send me a PM, if it was something meant for me. Thx.
I got an email saying there was a reply to this thread... I don't see any. Please send me a PM, if it was something meant for me. Thx.
Re: Try my Java SNES emulator? :)
Probably a spam post that got deleted.
Robot edit: you guessed correctly.
Robot edit: you guessed correctly.
Re: Try my Java SNES emulator? :)
the emulator doesn't seemed to work on my phone (SE k610i).
here are the things that I did.
first, I downloaded the two versions (the two *.zip files) and I used my phone's file manager to see what is inside. Apparently, It was just a bunch *.class files so I just renamed it to *.jar. then, I installed it. but it says "Operation Failed" so I checked the MANIFEST.MF and I changed it (actually, I changed it with the manifest from other apps that I have.). And it installed. but I cant open it...
It kept on saying "Invalid Application".
can someone tell me what's wrong?
it is actually the first time i had encounter such error on an emulator...
other emulator worked just fine on my phone (gb,gbc,nes,commodore64 emulators).
haha.. sorry for the wrong grammar...
here are the things that I did.
first, I downloaded the two versions (the two *.zip files) and I used my phone's file manager to see what is inside. Apparently, It was just a bunch *.class files so I just renamed it to *.jar. then, I installed it. but it says "Operation Failed" so I checked the MANIFEST.MF and I changed it (actually, I changed it with the manifest from other apps that I have.). And it installed. but I cant open it...
It kept on saying "Invalid Application".
can someone tell me what's wrong?
it is actually the first time i had encounter such error on an emulator...
other emulator worked just fine on my phone (gb,gbc,nes,commodore64 emulators).
haha.. sorry for the wrong grammar...
Re: Try my Java SNES emulator? :)
It probably needs a full, fairly up to date JRE. I imagine phones use something reasonably old and stripped down. If you do get it to run on a phone, though, I could imagine like single digit FPS.
Maybe these people were born without that part of their brain that lets you try different things to see if they work better. --Retsupurae
Re: Try my Java SNES emulator? :)
incompatibility eh?...
you've got some point there. I just wanted to try it to my old SE phone to see if the emulator works. I dont want to break my android by playing games like super mario world. haha...
thanks man...
you've got some point there. I just wanted to try it to my old SE phone to see if the emulator works. I dont want to break my android by playing games like super mario world. haha...
thanks man...