mirror of https://github.com/bsnes-emu/bsnes.git
3 Commits
Author | SHA1 | Message | Date |
---|---|---|---|
![]() |
a266a2b5e2 |
Update to bsnes v066 release.
Major features in this release are: serial controller emulation, a brand new scheduler that supports multiple simultaneous coprocessors, and accuracy improvements. The serial controller is something devised by blargg. With the proper voltage adjustments (5v-9v), it is possible to wire an SNES controller to a serial port, which can then be used for bidirectional communication between the SNES, and (usually, but not only) a PC. The support in bsnes was added so that such programs could be debugged and ran from within an emulator, and not just on real hardware. The scheduler rewrite was meant to allow the combination of coprocessors. It was specifically meant to allow the serial controller thread to run alongside the SuperFX and SA-1 coprocessor threads, but it also allows fun things like MSU1 support in SuperFX and SA-1 games, and even creating dev cartridges that utilize both the SuperFX and SA-1 at the same time. The one thing not yet allowed is running multiple instances of the exact same coprocessor at the same time, as this is due to design constraints favoring code inlining. There are two important accuracy updates. The first is that when PAL video mode is used without being in overscan mode, black bars are shown. Emulators have always shown this black bar at the bottom of the screen, but this is actually incorrect. resxto took pictures from his PAL TV that shows the image is in fact vertically centered in the screen. bsnes has been updated to reflect this. Also interesting is that I have backported some code from the dot-based PPU renderer. In the game Uniracers, it writes to OAM during Hblank, and expects the write to go to a specific address. In previous releases, that address was hard-coded to go to the required memory location. But the way the hardware really works is that the write goes to the extended attribute address for the last sprite that the PPU fetched, as the PPU is still asserting the OAM address bus. Now, due to the precision limitations, I was not able to also port timing access during the active display period. However, this is sufficient to at least remove the last global hack from the older, speed-focused scanline renderer. |
|
![]() |
79f20030a0 |
Update to bsnes v065r01 release.
In order to fully decode the 16MB address maps, I am going to need to use blargg's stop-and-swap, which will require a serial-communications program. To develop this program, and others in the future, as well as for testing automation, it would be very beneficial to have a way to debug these programs through bsnes. So what I'm working on now is emulating a serial port inside bsnes. The basic premise is to start with a custom XML map that specifies its presence: <?xml version="1.0" encoding="UTF-8"?> <cartridge region="NTSC"> <rom> <map mode="linear" address="00-7f:8000-ffff"/> <map mode="linear" address="80-ff:8000-ffff"/> </rom> <ram size="2000"> <map mode="linear" address="70-7f:0000-7fff"/> </ram> <serial baud="57600"> </serial> </cartridge> I am essentially treating the serial communication as a special chip. One could argue this belongs as an option under controllers, and one would be right. But as I can't have two coprocessor threads at the same time, this is how it is for right now. Eventually it'll probably be under controller port 2, and only enabled in the debugger builds. So, this pseudo-coprocessor ... it's basically emulating the PC-side communications program. Meaning I still need to externalize this somehow so that any program can be run. The below program writes 0x96 six times, and then reads in data six times. Well, technically forever, but the SNES ROM only writes six times at the end. void Serial::enter() { scheduler.clock.cop_freq = cartridge.serial_baud_rate() * 2; latch = 0; add_clocks(512); for(unsigned i = 0; i < 6; i++) { latch = 1; add_clocks(2); latch = 1; add_clocks(2); latch = 0; add_clocks(2); latch = 0; add_clocks(2); latch = 1; add_clocks(2); latch = 0; add_clocks(2); latch = 1; add_clocks(2); latch = 1; add_clocks(2); latch = 0; add_clocks(2); latch = 0; add_clocks(2); } while(true) { while(cpu.joylatch() == 0) add_clocks(1); while(cpu.joylatch() == 1) add_clocks(1); add_clocks(1); uint8 data = 0; for(unsigned i = 0; i < 8; i++) { add_clocks(2); data = (data << 1) | cpu.joylatch(); } print("Read ", strhex<2>(data), "\n"); } } The SNES code looks like this: //21,477,272hz cpu / 57,600hz serial = ~372.87 clocks/tick org $8000 xce; rep #$10 ldx #$01ff; txs jsr serial_read; sta $700000 jsr serial_read; sta $700001 jsr serial_read; sta $700002 jsr serial_read; sta $700003 jsr serial_read; sta $700004 jsr serial_read; sta $700005 nop #46 jsr serial_write jsr serial_write jsr serial_write jsr serial_write jsr serial_write jsr serial_write //hang -; bra - serial_read: -; lda $4017; and #$01; bne - -; lda $4017; and #$01; beq - nop #23; lda $00; nop #10 lda $4017; and #$01; asl $00; ora $00; sta $00; lda $00; nop #13 lda $4017; and #$01; asl $00; ora $00; sta $00; lda $00; nop #13 lda $4017; and #$01; asl $00; ora $00; sta $00; lda $00; nop #13 lda $4017; and #$01; asl $00; ora $00; sta $00; lda $00; nop #13 lda $4017; and #$01; asl $00; ora $00; sta $00; lda $00; nop #13 lda $4017; and #$01; asl $00; ora $00; sta $00; lda $00; nop #13 lda $4017; and #$01; asl $00; ora $00; sta $00; lda $00; nop #13 lda $4017; and #$01; asl $00; ora $00; sta $00; lda $00; nop #13 rts serial_write: lda #$01; sta $4016; nop #23 lda #$00; sta $4016; nop #23 lda #$01; sta $4016; nop #23 lda #$00; sta $4016; nop #23 lda #$00; sta $4016; nop #23 lda #$01; sta $4016; nop #23 lda #$00; sta $4016; nop #23 lda #$01; sta $4016; nop #23 lda #$01; sta $4016; nop #23 lda #$00; sta $4016; nop #23 lda #$01; sta $4016; nop #23 rts That reads six times, and then writes six times. I haven't made the test do an infinite PC->SNES transfer, but I have for SNES->PC. No errors after millions of bytes, even if I stride the CPU timing. As this is just an example, it's pretty lousy with actual timing, but I guess that's a good thing as it still works quite well. More tolerance = less potential for errors. **Now, this part is important.** While debugging this, I noticed that my serial coprocessor was only running when Vcounter=n,Hcounter=0. In other words, nothing was making the CPU synchronize back to the coprocessor, except the once-per- scanline synchronization that was there in case of CPU stalls. That's ... really bad. MSU1 worked only because it buffers a few hundred samples for audio mixing. I don't really know why this didn't cause an issue for SuperFX, SA-1 or Super Game Boy games; but in theory they were at most 682x less precise than they should have been in terms of CPU->coprocessor synchronization. Making it sync after every add_clocks() call results in a 10% speed hit to SuperFX, SA-1 and Super Game Boy emulation, unfortunately. I don't notice any quality improvements in emulation, but in theory the lack of this syncing before effectively eliminated the benefits of the SuperFX and SA-1 being cycle based. I'm going to have to look into this more to understand if I was intentionally not doing this sync before, or if I really did forget it. I'm thinking it was an oversight right now. The SuperFX and SA-1 don't really talk back and forth a whole hell of a lot, so once a scanline probably wouldn't be that noticeable. But holy hell ... now that I'm thinking about it, I wonder if this was the cause of all that craziness in trying to sync up the Super Game Boy's VRAM transfers. Yeah, definitely need to look into this more ... |
|
![]() |
79b939e1c7 |
Update to bsnes v065 release.
It's been a while, so here is a new release of bsnes. Unfortunately I don't have a full changelog this time. Most of the work went into stabilizing libsnes (which is used by the experimental .NET, Cocoa and Python UIs; as well as by Richard Bannister's OS X port). The Windows binary package now comes with all three variants included: bsnes.exe, the standard version that casual users should run; bsnes-debugger.exe, for SNES programmers and ROM hackers only; and bsnes-accurate.exe, which should not be used by anybody, ever. In all seriousness, bsnes-accurate.exe is bsnes with the dot-based S-PPU renderer. It's twice as slow as the normal build, and you won't really notice any differences except in Air Strike Patrol. It's there for the curious and for any SNES programmers who want to try making some really awesome video demos. Changelog: * OS X port builds once again; now requires gcc44 from Macports * libsnes API finalized * fixed a bug with S-CPU debugger breakpoints * various source cleanup |