NES to PC link cable standard

Discuss hardware-related topics, such as development cartridges, CopyNES, PowerPak, EPROMs, or whatever.

Moderators: B00daW, Moderators

User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

NES to PC link cable standard

Post by blargg »

I start at first principles of a programmable cartridge, show how a boot loader fits in, then get to design of a standard PC link cable, and the issues it faces, so that we can focus on these and not be distracted by tangential things like the boot loader. I'll comment in a follow-up posting, so it's separate from this coverage.

Programmable Cartridge

We've got a programmable cartridge and we want to run programs on it. We don't want to remove it from the NES every time we need to change the program, so we connect it to a PC via a link cable. The NES must boot to a loader on the cartridge that receives data from the PC and programs it into the cartridge. This loader knows how to do everything, so the PC just needs to send the data.

We run into problems. We must first write and debug the loader itself. This will involve lots of cartridge swapping, since we don't yet have a loader that uses the link cable. If we ever find any bugs or improve the loader, we must reprogram the cartridge. This requires that the boot area be reprogrammable. If updating the loader ever fails, the cartridge might become unbootable and must be reprogrammed with an external programmer. If we change the protocol, the updater program must be able to send the new loader using the OLD protocol.

Boot loader

A boot loader solves the problems posed by a full loader on the cartridge. The boot loader is a tiny loader whose only purpose is to receive code from the PC and put it in NES RAM, and then execute it. It need not support loading of arbitrary-sized programs to arbitrary regions of memory. The boot loader is simple to get debugged and working. It gives the PC control of the NES, where it can then send the main loader and run it. This allows the main loader to be written and debugged easily. Updates aren't an issue, because the latest version is always running.

The boot loader for a particular cartridge-link cable pair only needs to handle that link cable. If you have programmable cartridge and cable X, and programmable cartridge and cable Y, there's no need for them to use the same boot loader, since the main loader must know about each cartridge anyway. This avoids complicating the boot loader with code to handle many different link cable types. The only reason to have a universal boot loader would be if there were a need for a single cartridge that would work with multiple PC link cable designs.

Low-cost link cable

The lowest-cost PC link cable can be made by anyone with just a few discrete parts (transistor, resistors), and a NES controller and RS-232 cable. Someone constructing this wouldn't necessarily have a programmable cartridge, so he would need to get it from someone else. To make this easier, a boot loader supporting this cable could be put on various homebrew game cartridges as an extra feature. This boot loader would only need to support this low-cost cable; other cable types would be distributed with an associated development cartridge, so that the user didn't need anything extra to use them.

A similar low-cost cable can be made for the Famicom, but it would use different I/O lines. At first it might seem like the same boot loader would need to support this as well as NES, but that's not the case. The boot loader will be on a cartridge, either NES or Famicom, which can only be used on the respective system. Thus, the boot loader put on to NES homebrew would only need to support the NES cable, and on Famicom homebrew would only need to support the Famicom cable.

Even though homebrew cartridges wouldn't be programmable, the boot loader would still allow loading small programs into NES RAM, or if the homebrew cartridge has WRAM, there as well. This covers the boot loader; if user programs want to use the link cable as well, then you might want a standard for that so that programs can work with various link cable types.

PC link cable differences

Different cartridges might use different PC link cables. One might use a USB cable that does parallel transfer over the expansion port, another a synchronous parallel connection using three data inputs on the controller, and third asynchronous serial connected to RS-232. These are each handled by the software on their respective programmable cartridges.

But, user programs might also want to communicate with the PC. To work with different cables, they must either know about every cable type, have hooks for plugging in the proper driver code, or the cables must all behave in a way that a single driver can work with (though not necessarily optimally).

Trying to include driver code for every possible link cable isn't practical. Having hooks is reasonable, and could either be some reserved area of the user code where the appropriate driver can be patched in just before loading the program onto the cartridge, an area in ROM that user code can call, or even the driver routines put into NES RAM by the loader.

The third approach spreads the complexity across hardware and software. The hardware is constrained to something that can be read common driver code, and the common driver is made to allow some flexibility in hardware, but not so much that the driver becomes unwieldy. Note that the hardware need not support only this common way of receiving data; it can support other more capable methods as well, as long as this common one is available by default.

Standard PC link cable

We want a set of standard PC link cable designs for which at least one is easy to build, and all are easy to interface with in software. This will allow it to be used by more than just the loader programs. So, the boot loader isn't relevant to decisions about the cable; it must also work easily with user programs as well.

Coming up with driver code that works with different cables, and cable designs that can all work with driver is challenging, and involves tradeoffs. We don't want to make the driver unnecessarily general, because that makes it more complex, harder to test, and larger. We don't want to over-constrain the link cable design either. So it's important to avoid designing in flexibility just in case it's needed. To avoid this, we should examine the various configurations we might encounter.

Note that a user program is much more likely to merely receive data from the PC, rather than send it. There are lots of useful programs which have the PC stream various kinds of data, without the NES needing to send anything back. So having a standard for the PC-to-NES direction should be the main focus.

Hardware-wise, there's the front-loader NES, redesigned NES, NTSC/PAL versions, Famicom, and NES/Famicom clones. Each has variations on how the link cable can be connected, and the CPU timing.

The standard five-wire NES controller cable only allows for one approach: D0 for data to the NES, and Strobe for data from the NES. The NES connector also has D3 and D4, but the standard cable doesn't connect these, and third-party cables might not either. So this must be one of the supported cable connections. But on the Famicom, D0 is hardwired to the controllers, so another bit must be used for input. The Famicom allows access to Strobe, so that can be used as an output there as well.

Software-wise, there are several considerations.

Ideally, input is in bit 0 of a register. This allows easy shifting into the carry bit without disturbing A. The NES supports this, but the Famicom hardwires the controllers to bit 0, so another bit must be support as well if this is to support Famicom.

Supporting inputs on more than one register is not very practical. The loop that waits for the start bit must introduce as little jitter as possible. This requires that it not take very many cycles per iteration, since that determines jitter. Checking a single register requires 7 cycles per iteration, giving a jitter of +/- 3.5 cycles.

Code: Select all

        lda #mask
wait:   bit register    ; 4
        beq wait        ; 3
Checking two registers cannot take less than 11 cycles, and realistically would take 17 cycles, giving a jitter of +/- 8.5 cycles.

Code: Select all

wait:   lda register1   ; 4
        and #mask1      ; 2
        bne start       ; 2
        lda register2   ; 4
        and #mask2      ; 2
        beq wait        ; 3
start:
At 57600 bits per second on a PAL NES, this represents a +/- 30% deviation from the center of a bit, as compared to the +/- 12% a single register gives.

Output-wise, bit 0 of a register is also easier to support. Again, the NES supports this via the strobe, and the Famicom does as well. Outputting on multiple bits would need some justifying hardware reason. Note that even if data were output on another bit, it would still need to be output on bit 0 to support the low-cost link cable.

The PAL NES can be supported by two different drivers (or one with a variable delay) that are selected between at run-time after detecting whether the code is being run on an NTSC or PAL NES. This wouldn't support other CPU clock rates that another clone might have, though.
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

First off, I don't want to spend a lot of time coming up with a standard link cable unless people will actually be building them for all the platforms. If it's just going to be built on the NES, then let's only support the NES for now. The more general the design is made, the more it costs in time and effort to come up with and write code for.

Memblers, you proposed an alternate NES link cable that uses $4017.D1 for input and $4016.D1 for output, as opposed to D0 as used by the low-cost cable. This is to keep it separated from the controller lines, so that the two can operate without any interference. These would be connected on the expansion port of course, since neither is exposed on the NES controller connector.

If you added a 1K resistor in your design between $4017.D1 and $4017.D0, then user code which read from $4017.D0 would work, without having to even examine D1. The resistor would cause this copying to D0 only if nothing was plugged into the second controller port. The 1K is sufficient to overcome the internal 10K pullup, but a controller would override the 1K. The current draw wouldn't be an issue, because it would only be drawing significant current when the controller was outputting a low; once all 8 buttons are read on a controller, it outputs high on D0, which would be the idle state for your D1 as well.

Output-wise, user code must output on $4016.D0 if it's going to work with the low-cost cable, so using $4016.D1 wouldn't eliminate this constant strobing of the controllers in such user code. Such user code would also have to deal with the junk data the PC would receive when polling the controller using the low-cost cable, so the only benefit of using D1 is that code written specially for your cable wouldn't send junk to the PC (but it would then only work on your cable).

I want to be sure that this standard cable design is kept as narrow as possible. I mention the above things just to be sure that we're on the same page, and that any widening of the allowed cable connections really gives a benefit for the intended use, that of user programs using the serial cable. If it's just a matter of the boot loader, there's little reason to try to make a common standard, as covered in the opening post.

I mainly would like us (and any others interested) to explore the issue and determine what, if any, standard would be beneficial, and how likely it is for it to actually be made and for people to use it. I realize it's partly a chicken-and-egg thing, but it would still be nice to get some idea of how likely anyone is to utilize this.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: NES to PC link cable standard

Post by tepples »

blargg wrote:The lowest-cost PC link cable can be made by anyone with just a few discrete parts (transistor, resistors), and a NES controller and RS-232 cable.
By "RS-232 cable" you mean a commercially available USB to RS-232 adapter cable, I'm guessing.

Image

Image

Nope, no DE9 here.
User avatar
kyuusaku
Posts: 1665
Joined: Mon Sep 27, 2004 2:13 pm

Post by kyuusaku »

Unless I'm missing something, why can't the initial loader use 4017.4-0 to cover everyone and temporarily assume all other bits (other than the one connected) are inactive?

Code: Select all

loop:
lda $4017
and #%00011111
bne loop (or beq loop for inverted bit)
This leaves you >4 cycles into the bit best case, <17 cycles worst case, I guess 10.5 on average. Delay 5 cycles after and on average you're centered at 15.5. So best case you sample >4 + 5 = >9 cycles into the bit, worst case you sample <22, >9 cycles in either direction. 9 cycles allows for a frequency deviation of 29% assuming the frequency is constant, not too bad... Doesn't RS232 specify the tolerance to be 3%?

By post-compensating a little it seems this might be usable with clean 115200 baud even.
User avatar
Memblers
Site Admin
Posts: 3902
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers »

If you added a 1K resistor in your design between $4017.D1 and $4017.D0, then user code which read from $4017.D0 would work, without having to even examine D1. The resistor would cause this copying to D0 only if nothing was plugged into the second controller port.
That's a good solution for NES, but not for Famicom (which is a design goal with my project as well, both expansion ports have audio :)). It's true that Famicom is another hardware and might as well have a different ROM (like one would for a PAL/NTSC version, or language versions), but with Famiclones there are also corner-cases, such as PAL ones that have hardwired controllers. A suppose PAL/NTSC speed detection would handle odd cases. I don't really know how common that is, but I have a Famiclone like that (it's not a glob-top).

I don't think the code size and the speed is too big a deal. That's what is great about this particular bootloader idea, I like how it loads 256 bytes and that's it. At that size, even 2400 baud is under a second. After that, it can go as fast as possible. Having the PC's host program able to 'shift gears', so to speak, is a really good idea, I think. I don't know if that's what was said, but that's what I was assuming was part of the idea - the host uploader having a way to select the baud-rate (this is done only after the initial, compatible loader).

Usually bootloaders I've seen for the PIC will do one of 2 things - the PC host program will send a signal continuously, the PIC-side of the bootloader will have a pause at the beginning while it checks for the signal. The second method, the PC host waits for input from the PIC, whenever the PIC boots up it sends a request and waits very briefly for a response. I kind of like the 2nd method myself, that way a program on the NES will never receive any garbage data (if you hit the upload button on PC, before hitting reset on NES, for example). One advantage with having the host program poll by sending $AA, is that the receiver can detect the baud-rate before it responds (but we don't need none of that crap :P)

I was also sorta thinking that if code had to be really tight, only the initial polling session would be used to determine if it's D0 or D1, then go to specific branches for each one.

I guess there's not a whole lot I can do until I finish my board, I'm still doing the schematic. So what I propose is that if you want to make a v1.0 (or whatever version) as you're doing, if the source is open I'd be more than happy to make a v1.1 later on that adds this compatibility.
User avatar
koitsu
Posts: 4203
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: NES to PC link cable standard

Post by koitsu »

tepples wrote:
blargg wrote:The lowest-cost PC link cable can be made by anyone with just a few discrete parts (transistor, resistors), and a NES controller and RS-232 cable.
By "RS-232 cable" you mean a commercially available USB to RS-232 adapter cable, I'm guessing.
...which there are many, and the easy majority are horrible (specifically crummy drivers on Windows platforms combined with FIFO problems -- in English: you will absolutely lose characters). The only ones which are known to be highly reliable are those which use FTDI chips -- which aren't easily discernible from looking at external packaging (and most vendors don't even mention this). These do require OS driver support (am I the only one who finds it highly offensive that the USB-IF, still to date, has yet to provide a standard serial class?)

What I'm trying to say is that if you force serial-to-USB adapters onto people as a result of this project, folks will go out and buy whatever they can find then start complaining about how the PC-to-NES transfer software fails randomly. Mark my words.

A colleague of mine who's into EE and works predominantly on projects using PICs and FPGAs has stated to me that there's absolutely no reason the proposed project here cannot use USB natively. There are multiple USB base classes (read: classes which every OS implements natively, meaning you don't have to write a device driver, and you might not even have to provide an INF that describes the device) available for this purpose.

Please take the time to Do It Right(tm).
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

tepples, one would use a USB-to-RS-232 adaptor on machines lacking an RS-232 port.

kyuusaku, yeah, it could support any set of bits from $4017, and using the original loop with the bit instruction:

Code: Select all

        lda #%00011111
loop:   bit $4017
        bne loop
And yeah, this works with 115200. I think 57600 is the way to go for the default rate, since it gives plenty of time between bytes to process them, is plenty fast for most uses, and works very reliably.

It actually would be good not to use both D3 and D4, because one might want to wire serial to a NES controller with the PC's RTS line also connected to the NES (so the NES won't send when the PC's serial port is closed). So maybe only check D0,D1, and D3. This allows one to make a second controller pass-through cable for the NES that allows serial and the controller connected at the same time.
Memblers wrote:[1K resistor between D0 and D1] is a good solution for NES, but not for Famicom (which is a design goal with my project as well, both expansion ports have audio ). It's true that Famicom is another hardware and might as well have a different ROM
If we're aiming for user code, then my solution wouldn't work, since you want it to work on Famicom unchanged. This is the kind of feedback I was seeking, because it shows me that supporting other bits really is important, rather than just a nifty idea. It makes it easier to justify spending the time on supporting it.
I don't think the code size and the speed is too big a deal.
Yeah, you're right. The only case where it's slightly relevant is when running small programs directly from NES RAM while hotswapping to cartridges lacking any RAM. There you might want to go back to a boot loader, so it needs to be included with the mini program. But then you can always use a specialized one suited only to your particular hardware setup.
That's what is great about this particular bootloader idea, I like how it loads 256 bytes and that's it. At that size, even 2400 baud is under a second. After that, it can go as fast as possible. Having the PC's host program able to 'shift gears', so to speak, is a really good idea, I think.
I've actually worked on one that you send a bunch of "training" bytes to, during which it measures the bit period down to a small fraction of a CPU cycle, allowing baud rates from 9600 through 28800, with any arbitrary rate inbetween. It works on NTSC and PAL without even needing to detect which it's on. But unless 57600 proves to be a problem, I think it's best to just use it. For most cases, you then don't even need to switch the PC rate afterwards, since it's plenty fast.

As mentioned above, 115200 is tricky to deal with. Once you do the buffering and flow control it's not a lot faster than 57600, where you can usually handle the data as it comes. The main reason to use 115200 is for flow control, so you can process bytes at whatever rate the NES can handle at the moment, and still get an average rate of at least 5KB/sec.
The second method, the PC host waits for input from the PIC, whenever the PIC boots up it sends a request and waits very briefly for a response. I kind of like the 2nd method myself, that way a program on the NES will never receive any garbage data (if you hit the upload button on PC, before hitting reset on NES, for example).
Even having to hit reset before sending a program to the NES is inconvenient. Most of the time I just have my programs run a boot loader once they're done, so I can send the next without having to touch the NES. I suppose in this case the boot loader could periodically send this awake byte.
I guess there's not a whole lot I can do until I finish my board, I'm still doing the schematic. So what I propose is that if you want to make a v1.0 (or whatever version) as you're doing, if the source is open I'd be more than happy to make a v1.1 later on that adds this compatibility.
Well, since I'm also going to need to support Famicom for what I'm working on, I'll have to implement the D1 thing anyway for input. Since the (current) boot loader never outputs anything, I guess that's all that matters.

What about output? I'm interested in your reasons for using $4016.D1 instead of D0. I take it it's because software written specially for your interface won't have to deal with junk bytes when strobing the controllers, whereas code using Strobe for output has to carefully strobe the controllers for a few hundred cycles so that it sends a known byte to the host.

koitsu, I'll keep that in mind and recommend the FTDI cable over other USB adaptors. I just don't have the resources to develop and manufacture direct USB interfaces and ship them to people.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

blargg wrote:tepples, one would use a USB-to-RS-232 adaptor on machines lacking an RS-232 port.
Though koitsu made a good point: only FTDI chips are worth a $#!+. It's also important to work with established classes because 64-bit Windows Vista and 64-bit Windows 7 require kernel-mode drivers to have been digitally signed by a proper organization with a certificate that costs $200 a year, and most end users don't want to have to close their instant messaging and music player programs and reboot to a Linux live CD just to send code to an NES.
I don't think the code size and the speed is too big a deal.
Yeah, you're right. The only case where it's slightly relevant is when running small programs directly from NES RAM while hotswapping to cartridges lacking any RAM.
But if the boot loader is 4096 bytes, for instance, you'll have a lot more trouble getting homebrew developers to fit it into every new homebrew game as an Easter egg.
I just don't have the resources to develop and manufacture direct USB interfaces and ship them to people.
Might retrousb.com be able to help?
User avatar
Dwedit
Posts: 4470
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

Retrousb doesn't manufacture the adapters, they just sell them.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

tepples wrote:
I just don't have the resources to develop and manufacture direct USB interfaces and ship them to people.
Might retrousb.com be able to help?
I want something that can be built with readily-available parts. The other solutions are more capable, but I'm not interested in those. There are others who can persue those approaches. Yes, the bootloader is still needed, but a lot of people have EPROM programmers already, and the bootloader might be put onto homebrews as an extra feature as well.

BTW, I've gotten the full-checking loader supporting arbitrary bits on $4017 without bloating it above 128 bytes. It can even handle crossing a page without messing up timing. I may even be able to make it autoselect between NTSC and PAL, while still fitting within 128 bytes. If the budget were a 256-byte aligned page, it'd be no problem.
User avatar
p1xl
Posts: 32
Joined: Sat May 15, 2010 4:13 pm
Location: U.S./Canada
Contact:

Post by p1xl »

As an option, Sparkfun has a breakout board for the FT232RL chip (USB-Serial). More of a direct shot and it's only $15.

http://www.sparkfun.com/commerce/produc ... cts_id=718
User avatar
koitsu
Posts: 4203
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu »

blargg wrote:koitsu, I'll keep that in mind and recommend the FTDI cable over other USB adaptors. I just don't have the resources to develop and manufacture direct USB interfaces and ship them to people.
There are PIC chips which include native USB capability -- look at the PIC 18 series and beyond (PIC offers a full USB library/stack for you to use). Some offer Ethernet capability too (with an included IP and TCP stack). For example, the PIC18F13K50, which costs something like $3.

Try it: http://www.microchip.com/productselecto ... ector.html

Just sayin'. :-)
ibeenew2
Posts: 60
Joined: Sat May 01, 2010 9:58 am

Post by ibeenew2 »

Dwedit wrote:Retrousb doesn't manufacture the adapters, they just sell them.
maybe you mean something else but that is like saying apple doesn't manufacture ipods. retrousb would at least have the experience/knowledge/resources to get them made and shipped to people.
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

Sparkfun has a breakout board for the FT232RL chip
That would be useful for mounting the USB connection in the case of something. For a basic NES cable, you'd want to use the $18 FTDI USB-to-TTL 5V cable. Just splice with a NES controller cable (don't even have to solder if you don't have an iron) and you've got a PC link cable.
User avatar
Memblers
Site Admin
Posts: 3902
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers »

I have to LOL a little bit about the RetroUSB mentions in this thread. Of course they started out converting NES controllers to USB, many years ago I emailed Brian and got a box of NES and SNES cables from him (which was great and helpful, that's what I built my batch of NES-RS232 adapters with). Otherwise they were just being put in the trash, what a waste.. I really wanted to try making some NES peripherals, but I was highly frustrated with not being able to get a response, and wondering if they were probably just being thrown away. It may have a been a total waste of time if I had continued trying to develop that stuff.. Was easier to quit then deal with the uncertainty. One can't manufacture shit if you don't have a supplier.

So I can see why it's a good idea to just have people build their own. I'm not gonna mess up a bunch of controllers just to steal the cables.

koitsu: Don't worry, I'm working on a device that uses the PIC32 and will have USB, among lots of other nifty stuff (sound synth :). It will use the expansion port, but if one really had to, it should be easy enough to just install it inside the console and wire it to the NES board (on the expansion port pins). It's not exactly dirt-cheap though.
blargg wrote: What about output? I'm interested in your reasons for using $4016.D1 instead of D0. I take it it's because software written specially for your interface won't have to deal with junk bytes when strobing the controllers, whereas code using Strobe for output has to carefully strobe the controllers for a few hundred cycles so that it sends a known byte to the host.
Yeah, with the PIC if I use the port in SPI mode, then I will be receiving junk, and if I leave it UART mode, framing errors. At least with D1, in SPI mode I would be guaranteed to receive zeros during controller reading, which would be a little easier to handle (but needs some care to send an actual zero as data, then..). What I might look into also, is to see if I can use $4016.D2 as a positive enable for the SPI port. Otherwise I might hook it to an I/O that can wake the PIC from sleep mode, not sure what else I can do with it (heheh 2-bit SPI maybe, but I'm about out of ports).
Post Reply