Author Topic: usb support  (Read 15927 times)

0 Members and 1 Guest are viewing this topic.

Offline redguy

  • Jr. Member
  • **
  • Posts: 54
  • Karma: +148/-0
    • View Profile
usb support
« on: June 17, 2017, 11:10 PM »
I took saturnu's usb firmware mods and made the following changes:
- Ported it to 0.1.7e.
- Rewrote most of the packet handling code to provide an interface to the file system and some common FW commands.

It's all a bit of hack right now while I figure out what I ultimately want to do with it.  The USB version supported by the sd2snes HW is 2.0 @ full speed (12 Mb/s theoretical data rate).  Reasonably fast for transferring single digit number of files, but not anywhere close to accessing the SD card directly from your computer.

Please back up your SD card if you decide to try it out.  The error/reset logic isn't the greatest so it's possible to get the usb state machine in the firmware and/or the app accessing it out of sync.  Getting the USB to work again usually involves reopening the app and/or rebooting the snes.

One odd thing I've seen is something related to sd2snes SRAM reads seem to indirectly mask or disable the interrupt that gets called when EP2/BulkIn is available.  I saw some comments from saturnu regarding this, too.  The current code has to poll (hack) in order to push the data out when SRAM is accessed.  When it's a transfer of a file from the SD card the interrupt seems to work fine.  Maybe it's caused by the FPGA accesses?

https://github.com/RedGuyyyy/sd2snes/releases/latest

This includes:
- The firmware with instructions on how to update the firmware and install a suitable windows driver.
- A c# app to access the file system of the SD card over USB with a variety of commands to modify, boot, etc.
- A hacked version of an alttp item randomizer display that reads SRAM over USB to update.

Source here:
https://github.com/RedGuyyyy/sd2snes
https://github.com/RedGuyyyy/usb2snesw
https://github.com/RedGuyyyy/ZeldaHud
« Last Edit: December 24, 2017, 12:13 AM by redguy »

Offline redguy

  • Jr. Member
  • **
  • Posts: 54
  • Karma: +148/-0
    • View Profile
Re: usb support
« Reply #1 on: June 24, 2017, 03:10 AM »
I have real-time IPS patching working over USB which can use the NMI hook to call any new code.  It cheats (pun intended) by using the cheat/snescmd address range that is typically used for WRAM writes to call into arbitrary code.  There's still a race with modifying running code (I may add a spin loop + status to work around this), but it works for applying the patch over other parts of the sd2snes SRAM.

So I thought it would be interesting to use this to write a generic save/load state IPS patch with the help of $21XX and $42XX snooping for write only registers.  I tried mirroring a set of them from $2B00-$2B60.  Then using the new save state trigger in the game they are written to a the SRM file which I can use as a poor man's logic analyzer.  The initial values are read out correctly, but I can't figure out the timing for the ~SNES_PAWR, SNES_PA, and SNES_DATA signals.   I tried collecting a sample write for -5 and +59 cycles of data from the assertion of SNES_PAWR and the data doesn't make sense for the address I think it's writing (e.g. background vertical scroll in a particular part of the game vs bsnes).  I may have to try a different game as the one I have patched isn't making sense. 

Is PA write timing similar to the 24b address timing for writes?  It looks like it's 12 master cycles as opposed to 8 based on SNES_PAWR assertion.

EDIT: I should mention that after looking through the verilog and it looks like the bus is properly tristated from the sd2snes during writes.  The pin on the board also looks to go somewhere... where I can't say for certain, but the samples look sensible for the write assertion and associated address.

EDIT2: I figured it out.  I wasn't driving the OE signal properly.  There are still some bugs to work through, but now I'm seeing mostly correct mirrored values.
« Last Edit: June 25, 2017, 04:21 AM by redguy »

Offline saturnu

  • ヽ(^o^)丿
  • Hero Member
  • *****
  • Posts: 1168
  • Karma: +150/-0
    • View Profile
    • :D
Re: usb support
« Reply #2 on: June 27, 2017, 06:36 AM »
oh nice!
i have to check this out. ^^

Offline redguy

  • Jr. Member
  • **
  • Posts: 54
  • Karma: +148/-0
    • View Profile
Re: usb support
« Reply #3 on: June 27, 2017, 08:22 PM »
The usb port has the potential to enable some interesting debug features and runtime game changes.  Both pushed to the snes as well as a usb address space that is accessible by the game.

Im struggling a little with getting a generalized save state patch working. I can patch the game specific ips at runtime and it works great, but when i try to make it more general it fails. One problem is the snooping of 21xx registers sometimes get corrupted.  I think ill need to locate a logic analyzer to help understand the bus transactions.   The other is a problem with relocating the code to unused rom space results in some weird behavior i only see on console. Random controller input is detected by the game for a frame or two.

Offline redguy

  • Jr. Member
  • **
  • Posts: 54
  • Karma: +148/-0
    • View Profile
Re: usb support
« Reply #4 on: July 22, 2017, 09:38 PM »
https://drive.google.com/file/d/0Bx9gzQZCkH8qampxbTk0UWdUU2M/view?usp=sharing

EDIT: If you downloaded the zip and Chrono Trigger or other 4MB games stopped working then try downloading again.  I fixed a bug.  Make sure to copy the new files in the sd2snes directory to your SD card to fix the bug.

usb2snes v0.3

- Fixed more timeouts due to collisions with other interrupts in FW.  MSU is still buggy.
- Added Write-Only register snooping to enable save-stating.
- Added basic IPS patch and state managing support.  Included save_state IPS patch.

See the readme file for more details on how to setup and use it.  The save state patch works reasonably well.  I haven't tested it with every game so changes are it will lock up or not work.  Despite this, I thought people might like to try it out.

<Technical stuff below>

The way the patch works is hijacking the cheat area, $2A90+, to jump to a region called the PATCH region $F0-$FF.  This region is mapper independent, supports read/write, and only accessible in the NMI hook.  The save state code does a one time init to setup some basic state and then uses SMC (self modifying code) to skip the init after the call.  It monitors the controller button state which is conveniently saved off to $2BF0.  When a save state is triggered it DMAs a lot of stuff to $F0-$F3 (inclusive) including the write-only PPU and CPU registers that are now being snooped by the SD2SNES firmware.  The load state transfers the data in reverse.  Several games (mostly Capcom) have fixes to make the audio port state coherent with the cached copy in WRAM.  I was running into a lot of problems with nested NMIs that were worked around by enabling and waiting for the next NMI at the end of save/load, consuming the associated stack frame, and finally exiting to the game's NMI handler.  This more closely lines up the NMI timing with what the game expects.  I'm sure some race conditions remain, but it works reasonably well.  A logic analyzer hooked up to the cart bus and UART->USB have been extremely helpful for debugging it.

I still consider this a collection of hacks as I'm not sure where to go with it, yet.  One could really go off the deep end and add OS-like functionality for dynamically loaded patches, RAM memory management, and other things.  But even now the patch support is a pretty powerful tool coupled with tool that can read the RAM contents over USB.  I'm considering hijacking the MSU-1 data buffer to provide a writeable address space that can be mapped to USB for communication among different SNESs.
« Last Edit: July 23, 2017, 03:24 AM by redguy »

Offline iwasaperson

  • Full Member
  • ***
  • Posts: 141
  • Karma: +13/-0
    • View Profile
Re: usb support
« Reply #5 on: July 22, 2017, 10:22 PM »
Can you update the tool for Linux by any chance?

I tried this one, but I can't get it to work: https://github.com/RedGuyyyy/usb2snes

Works fine in a Windows VM, but it's such a pain for me to go in and out of Windows all the time.
@Syboxez on Discord and some other places as well.

Offline redguy

  • Jr. Member
  • **
  • Posts: 54
  • Karma: +148/-0
    • View Profile
Re: usb support
« Reply #6 on: July 23, 2017, 03:52 AM »
That version of usb2snes on github was made by saturnu a few years ago and the protocol is no longer supported.  My changes aren't stable enough to maintain multiple apps to access the sd2snes so it will be windows only for the time being.  I don't have a linux or macos desktop, but if someone wants to take a look at the c# code and suggest changes to get it to work on those platforms (assuming they have c# compilers available) I'd be happy to make them assuming they are simple.

I also fixed a bug that broke Chrono Trigger so please redownload the zip again and update the sd2snes directory on your flash card.

Offline ikari_01

  • Sr. Member
  • ****
  • Posts: 309
  • Karma: +80/-0
    • View Profile
Re: usb support
« Reply #7 on: July 23, 2017, 06:36 AM »
I recall there were stalling and/or data corruption issues when transferring data from sd2snes to PC using the Windows build of usb2snes. Did you encounter anything like it?

Offline redguy

  • Jr. Member
  • **
  • Posts: 54
  • Karma: +148/-0
    • View Profile
Re: usb support
« Reply #8 on: July 23, 2017, 07:34 AM »
Yes.  I had problems with transfers to and from sd2snes with the original code and the windows utility.  It was random and infrequent when I could successfully upload a file to RAM and boot it.  I was getting both data corruption and stalls plus the downloads were slow when they worked.  If I remember correctly, the code was using an interrupt to deliver packets to a buffer which were then serviced by a handler in the menu loop for both command and data.  In the download code path there was some comments about problems with interrupts and it polled the CDC directly to send data every time it entered the loop handler.

The new code retains the loop handler in the menu and snes loop for operating on various command types (get, put, boot, ls, etc) which sets up state for receiving data or performing the operation.  For put operations the data is then directly written into RAM or a file when a full block is received by the interrupt handler rather than waiting for the loop handler to poll.  Uploads are a lot faster now, although, they are still slower than downloads.  The stalls and data corruption with downloads seemed related to other code in the loop.  SD writes for saveram and potentially other things were causing the interrupt to stop asserting even if data was still available.  I never figured out the exact cause but the solution was to put the code in a spin loop on get and ls operations while the interrupt pulled all the data and finally updated the state to exit the spin loop in the loop handler.  Maybe there are DMA operations in the other code that share that change interrupt state?  Downloads are much faster and I haven't encountered data corruption since making the changes.  Timeouts are pretty rare.  The only one I've seen recently is when I hooked up 2 SNES/SD2SNES with USB and switched between them with the app.

The original USB code was a great reference as it setup the PLL and various other things that would have otherwise taken a long time to figure out.

Offline OsteHovel

  • Newbie
  • *
  • Posts: 1
  • Karma: +0/-0
    • View Profile
Re: usb support
« Reply #9 on: July 27, 2017, 08:04 AM »
I was pludering around with your code yesterday and i was able to communicate with no problem with my SNES, but i have a question, can i read/write ram directly from the console or can i only read/write to rom+sram using it?

OsteHovel
« Last Edit: July 27, 2017, 08:08 AM by OsteHovel »

Offline redguy

  • Jr. Member
  • **
  • Posts: 54
  • Karma: +148/-0
    • View Profile
Re: usb support
« Reply #10 on: July 27, 2017, 04:56 PM »
Without the usb changes, the SD2SNES has an address map that includes an IS_WRITABLE flag based on a 3-bit mapper field and some other state.  It basically provides the same address space mapping and attributes (read-only, etc) as the typical mapping modes usually referred to as lorom, hirom, exthirom, etc.  One exception is a region referred to as SNESCMD ($00:2A00-$00:2BFF) which is used to store the NMI hook that enables WRAM cheats and in-game buttons.  This region is protected from access until a NMI (or IRQ, dependent on configuration state) is taken in which case the address map dynamically changes to allow read (execute)/write to it.

With the latest USB changes, the address map is also dynamically modified inside the hook to make $F0:0000-$FF:FFFF available as whats called the PATCH region with flat addressing.  This the 15-16MB memory range on the 16MB SD2SNES RAM that the menu also uses.  So while you are in the NMI hook you can read and write this.  Right now it's used by the save_state patch to hold the code, variables, and save state data.  The address map is changed back to the original mapper when you exit the hook as it would break some games to leave it.

It's possible to extend the address map changes to make any address writable by the SNES so that you can write the full SD2SNES RAM which contains the ROM image (0-? MB), SRAM (14-15? MB), MENU/PATCH (15-16 MB), plus some other regions for MENU and BS-X.  But whether you only want this to be true in the NMI hook or all the time, which will break some games, is not clear.  It would be cool to have a programmable address map where the SNES code chooses the read/write flags and mapping functions in the hook and decide whether they persist outside of it.  But I'm not really sure what this interface should look like, yet, so I kept the address map hacks to a minimum for now.  Allowing all addresses to be writable inside the hook by default is pretty easy to do so I might just add it in while I think of a better solution.

The short answer is not currently, but I'll try adding it in so all addresses are modifiable inside the hook.
« Last Edit: July 27, 2017, 05:01 PM by redguy »

Offline Enmet

  • Newbie
  • *
  • Posts: 16
  • Karma: +0/-0
    • View Profile
Re: usb support
« Reply #11 on: August 10, 2017, 11:33 PM »
I have been trying to use this. I have installed the driver and all that correctly according to the readme, but the usb2snes program gives me this on startup:

Quote
************** Exception Text **************
System.Exception: Can not read Bus provided device description device 4d36e978-e325-11ce-bfc1-08002be10318
   at usb2snes.utils.Win32DeviceMgmt.GetDeviceBusDescription(IntPtr hDeviceInfoSet, SP_DEVINFO_DATA deviceInfoData)
   at usb2snes.utils.Win32DeviceMgmt.GetAllCOMPorts()
   at WindowsFormsApplication1.usb2snes.buttonRefresh_Click(Object sender, EventArgs e)
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.PerformClick()
   at WindowsFormsApplication1.usb2snes.usb2snes_Load(Object sender, EventArgs e)
   at System.Windows.Forms.Form.OnLoad(EventArgs e)
   at System.Windows.Forms.Form.OnCreateControl()
   at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
   at System.Windows.Forms.Control.CreateControl()
   at System.Windows.Forms.Control.WmShowWindow(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
   at System.Windows.Forms.Form.WmShowWindow(Message& m)
   at System.Windows.Forms.Form.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

Probably something with .NET but I tried to reinstall it up to 4.5.2 with no results. Note that the usb2snes program still runs if I press continue but there will be no ports listed. I do know it's not the USB port or the cable as I've been using that with an Arduino before. Firmware version shows up correctly in the SD2SNES menu.

Offline redguy

  • Jr. Member
  • **
  • Posts: 54
  • Karma: +148/-0
    • View Profile
Re: usb support
« Reply #12 on: August 10, 2017, 11:42 PM »
Someone else had the same problem and I have a workaround.  It's interesting that they also had an Arduino.  Let me clean up a few of the things I'm working on and I'll post up another version in a few hours.

Offline redguy

  • Jr. Member
  • **
  • Posts: 54
  • Karma: +148/-0
    • View Profile
Re: usb support
« Reply #13 on: August 11, 2017, 02:32 AM »
https://github.com/RedGuyyyy/sd2snes/blob/master/rel/usb2snes_v0.4.zip
(click download button in upper right)

usb2snes v0.4

- Fixed more timeouts due to disconnect problems.  There are still more left to fix.  E.g. pulling the cable out typically requires a reboot of the snes and app.
- Added preliminary USB/NET memory region support.  Work in progress.
- Fixed (workaround) problem where querying certain COM devices results in an exception.  The exception is now discarded.

See the readme file for more details on how to setup and use it.  This is mostly bug fixes as the majority of the changes aren't accessible from the app.  Don't click the 'Test' button as it is for testing purposes only.  :)

<Technical stuff below>

This should fix the COM device exception on startup.  I'm not sure why it's happening, but if I catch, discard, and ignore that port it looks to work.  I can't reproduce it, but someone else said this fixed their problem.

The major thing I've been working on is USB/network play support.  It's a bit of a hack right now (much like everything else I've done).  What it provides is a (currently unused) register region at $2010-$2017 and a scratch region which a USB enabled app can access at $1E-$1F:5000-5FFF.  In a test IPS patch I've set up $1000 of that region for scratch and some state variables.  In the other $1000 region it holds an input and output queue.  The patch which currently runs on a NMI inits the scratch and queue state and can generate queue operations (write, add, compare and swap, etc) to regions in scratch memory.  Those queue operations are read by an application polling that memory space over USB which then broadcasts the operation to all networked clients.  The client app pushes these writes down to the other queue which the NMI reads and operates on scratch memory.  This way one game running on hardware can affect the state of another game.

Here's an example where one link gives another link (still in bed) the moon pearl in the lttp randomizer:

https://www.youtube.com/watch?v=q70PdvOG70A

The other thing I tried was allowing save states to be initiated on game start.  It works with one major flaw: I'm cheating and not providing saved APU state.  This results in no sound and eventually it locks up.  I'd like to add a generic HW context engine which saves all APU, WRAM, VRAM, etc writes to a fixed location in sd2snes RAM, but that project needs to wait.  This would provide much simpler (and efficient) save state code while also allowing for snooping of various snes RAM regions for debugging.

I would also like to have a unified driver that multiplexes multiple apps onto the USB connection so you can interleave use of usb2snes, HUDs, input monitors, networked games, etc.

Needless to say this is all going to take a lot of work and long time.  There are some really cool things that can be done with the USB connection.

EDIT: I also made it so the ROM addresses in RAM are writeable while you're in the PATCH region.  It's not very well tested so it may break some games.  This lets you rewrite the game ROM on the fly (code or data... doesn't matter).
« Last Edit: August 11, 2017, 04:10 AM by redguy »

Offline Enmet

  • Newbie
  • *
  • Posts: 16
  • Karma: +0/-0
    • View Profile
Re: usb support
« Reply #14 on: August 11, 2017, 03:01 AM »
The new version works for me, great job and thank you!