============================================================================== >> WARNING: I PROVIDE THE INSTRUCTIONS BELOW FOR EDUCATIONAL PURPOSES << >> ONLY. IF YOU ATTEMPT TO BUILD AND OPERATE AN ECScable, YOU DO SO AT << >> YOUR OWN RISK. I CANNOT BE RESPONSIBLE FOR ANY DAMAGE TO YOUR << >> INTELLIVISION, YOUR ECS, YOUR INTELLICART, YOUR COMPUTER OR OTHER << >> EQUIPMENT. YOU HAVE BEEN WARNED. << ============================================================================== This directory includes the construction information for the ECScable, as well as the source code for the ECScable Monitor. The PC-side utilities are contained in the src/ tree. The ECScable is a simple data-cable that connects an Intellivision ECS to a PC via a parallel-port interface. The monitor allows a game to interact with the PC via a simple protocol. It also allows for reloading the game easily on-the-fly. The current ECScable monitor and software requires an Intellivision, an ECS, and an Intellicart. To use the ECScable, attach the cable between a printer port on your PC and the left/right controller connectors on an ECS. Load the ECScable Monitor into the Intellicart, and use the "ec_load", "ec_dump" and "ec_watch" utilities to communicate with the Intellivision via the ECScable. See ECScable Monitor Features below for details on using the ECScable Monitor itself, as well as on how to make your programs ECScable Aware. ============================================================================== RELIABILITY ADDENDUM: I have not been able to get my ECScable to work on a machine other than my primary Linux box. Upon reading the specs for the AY-3-8914, I suspect the problem is that the PSG isn't really designed to drive a typical PC's printer port. I will have to design and build a better electrical interface. So, at this time, I would recommend you do NOT attempt to build an ECScable unless you really know what you're doing. ============================================================================== ============================================================================== ECScable WIRING ============================================================================== The ECS cable has 8 lines going from PC->ECS, and 5 lines going from ECS->PC. One line in each direction is used as a clock line, leaving 7 data lines from PC->ECS and 4 data lines from ECS->PC. The wiring is as follows: Right hand controller: PC Cable pin # --------------- --------------------------- Bit 0 Pin 1 Pin 15 (FAULT) Bit 1 Pin 2 Pin 13 (SLCT) Bit 2 Pin 3 Pin 12 (PE) Bit 3 Pin 4 Pin 10 (ACK) Bit 4 Pin 5 Pin 11 (BUSY) Bit 5 Pin 6 n.c. Bit 6 Pin 7 n.c. Bit 7 Pin 8 n.c. GND Pin 9 Any of Pin 18 thru 25 Left hand controller: PC Cable pin # --------------- --------------------------- Bit 0 Pin 1 Pin 2 (Data bit 0) Bit 1 Pin 2 Pin 3 (Data bit 1) Bit 2 Pin 3 Pin 4 (Data bit 2) Bit 3 Pin 4 Pin 5 (Data bit 3) Bit 4 Pin 5 Pin 6 (Data bit 4) Bit 5 Pin 6 Pin 7 (Data bit 5) Bit 6 Pin 7 Pin 8 (Data bit 6) Bit 7 Pin 8 Pin 9 (Data bit 7) GND Pin 9 Any of Pin 18 thru 25 ============================================================================== PARTS LIST ============================================================================== The ECScable does not require many parts for construction. You can get all the needed parts at your local Radio Shack: 26-152B Shielded RS-232C Cable, Female DB9 to Female DB9 276-1536A Shielded Metallized Hood for 25-pin connectors 276-1429 25-Position Mail D-Sub Connector, with crimp-style pins. ============================================================================== SIGNALING PROTOCOL: PC MASTER MODE ============================================================================== For reliability reasons (primarily due to the fact that a 0->1 transition is faster than a 1->0 transition, owing to pullup resistors on the bus), all data transactions occur over a full "clock" period, with valid data being read at the end of a 1->0 clock transition. The PC always provides the clock, and the ECS echos the clock. The following diagram shows one read/write cycle from the PC's perspective: _____ PC Clock: ______| |_________ ________________ PC Data: XXXXX>>>>>>>__________< ______ ECS Clock: _________| |_____ ________________ ECS Data: XXXXX>>>>>>>>>>_______< ^^ ^^ Data changing Data valid Basically, the following code seems to reliably do a loopback: PC side: do { outb(i | c, base + 0); do { j = (0x80 ^ inb(base + 1)) >> 3; } while ((j & 1) != c); c = !c; } while (c == 0); INTV side: @@l MVI $FF, R0 MVO R0, $FE B @@l All data transmissions are simultaneously transmits and receives. If a given direction isn't sending or receiving something, it should set the lines to all 1s. (Alternately, the Inty can just echo back the value it read -- serves as Also, when the line is in the idle state, both directions should leave the line floating at all 1s. (eg. 0xFF) The Inty should set its xmit lines to the "input" direction to let the drivers on the PSG rest. ============================================================================== COMMAND SEQUENCE ============================================================================== The PC alerts the ECS that it wants to issue a command by sending 0x00 on its line, thereby coming out of idle and alerting the ECS that it wants to do something. It waits for the ECS to respond in kind by responding with 0x00. Once this short handshake completes, the PC can send a command. For robustness, each command is sent twice -- as the command word and as the inverse of the command word. The PC then sends up 0xAA and expects to read back a single nibble from the ECS. If it reads back a 0x0A, it assumes the Inty read the command ok. If it reads back anything else, it assumes the Inty did not read the command correctly. If the PC sees that the Inty did not read the command correctly, it returns to the idle state and then retries. Otherwise, the PC sends the body of the command packet (if any). Example: PC->ECS ECS->PC 11111111 11111 Idle 00000000 11111 PC initiates handshake 00000000 00000 ECS responds to handshake - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 01011101 00000 PC sends a command, clock HI 01011101 xxxx1 ECS responds by bringing clock HI 01011100 xxxx1 PC sends a command, clock LO 01011100 xxxx0 ECS responds by bringing clock LO - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 10100011 xxxx0 PC sends command inverse, clock HI 10100011 xxxx1 ECS responds by bringing clock HI 10100010 xxxx1 PC sends command inverse, clock LO 10100010 xxxx0 ECS responds by bringing clock LO - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 10101011 xxxx0 PC sends a zero to finish cmd, clock HI 10101011 01011 ECS responds with 0xA, clock HI 10101010 01011 PC sends a zero, clock LO 10101010 01010 ECS responds with 0xA, clock LO - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ============================================================================== COMMANDS ============================================================================== (Note: LSB is clock, and is shown as zero in commands below) 0x00: PING (just echo back "OK!") 0x02: Soft Reset to GAME 0x04: Soft Reset to MONITOR 0x06: Active video OFF 0x08: Active video ON 0x0A: Disable ECS ROMs 0x0C: Enable ECS ROMs 0x0E: NOP (reserved) 0x10: PC->ECS xfer bytes within Inty address space 0x12: PC->ECS xfer decles within Inty address space 0x14: PC->ECS xfer words within Inty address space 0x16: NOP (reserved) 0x18: ECS->PC xfer bytes within Inty address space 0x1A: ECS->PC xfer decles within Inty address space 0x1C: ECS->PC xfer words within Inty address space 0x1E: NOP (reserved) 0x20: PC->ECS xfer bytes within Intellicart address space 0x22: PC->ECS xfer decles within Intellicart address space 0x24: PC->ECS xfer words within Intellicart address space 0x26: NOP (reserved) 0x28: ECS->PC xfer bytes within Intellicart address space 0x2A: ECS->PC xfer decles within Intellicart address space 0x2C: ECS->PC xfer words within Intellicart address space 0x2E: NOP (reserved) The two RESET commands have no command body. The PC side should go to idle after issuing the command. ============================================================================== DATA FORMATS FOR BLOCK TRANSFERS ============================================================================== The remaining memory transfer commands are followed by short header which gives the address and length. The data is sent as follows: +--------+--------+--------+--------+--------+--------+--------+--------+ | A7 | A6 | A5 | A4 | A3 | A2 | A1 | (clk) | +--------+--------+--------+--------+--------+--------+--------+--------+ +--------+--------+--------+--------+--------+--------+--------+--------+ | A15 | A14 | A13 | A12 | A11 | A10 | A9 | (clk) | +--------+--------+--------+--------+--------+--------+--------+--------+ +--------+--------+--------+--------+--------+--------+--------+--------+ | "Length - 1" | A0 | A8 | (clk) | +--------+--------+--------+--------+--------+--------+--------+--------+ +--------+--------+--------+--------+--------+--------+--------+--------+ | Header Checksum | (clk) | +--------+--------+--------+--------+--------+--------+--------+--------+ The header checksum is a simple 2s complement arithmetic sum of the first three bytes. Not horribly robust, but hey. After the header, the PC expects to read back 0xA (as above). If it doesn't, then it goes back to the idle state, waits a moment, and tries sending the command again. After the header, the PC and the ECS send data back and forth. For the PC->ECS the following formats are used: For BYTE data, up to 7 bytes in a row in this format: +--------+--------+--------+--------+--------+--------+--------+--------+ | D7a | D6a | D5a | D4a | D3a | D2a | D1a | (clk) | +--------+--------+--------+--------+--------+--------+--------+--------+ +--------+--------+--------+--------+--------+--------+--------+--------+ | D7b | D6b | D5b | D4b | D3b | D2b | D1b | (clk) | +--------+--------+--------+--------+--------+--------+--------+--------+ .... Followed by one byte in this format to give the LSBs: +--------+--------+--------+--------+--------+--------+--------+--------+ | D0g | D0f | D0e | D0d | D0c | D0b | D0a | (clk) | +--------+--------+--------+--------+--------+--------+--------+--------+ If there are more than 7 bytes remaining in a packet, 7 are always sent, otherwise only the remaining bytes are sent. This eliminates the need for length bytes in the stream. - - - - - - - - - - - - - For DECLE data, up to 7 bytes in a row in this format: +--------+--------+--------+--------+--------+--------+--------+--------+ | D9a | D8a | D7a | D6a | D5a | D4a | D3a | (clk) | +--------+--------+--------+--------+--------+--------+--------+--------+ +--------+--------+--------+--------+--------+--------+--------+--------+ | D9b | D8b | D7b | D6b | D5b | D4b | D3b | (clk) | +--------+--------+--------+--------+--------+--------+--------+--------+ .... Followed by one byte in this format to give bit2 for the DECLEs: +--------+--------+--------+--------+--------+--------+--------+--------+ | D2g | D2f | D2e | D2d | D2c | D2b | D2a | (clk) | +--------+--------+--------+--------+--------+--------+--------+--------+ Followed by two bytes in this format to give bit1 and bit0 for the DECLEs: +--------+--------+--------+--------+--------+--------+--------+--------+ | D1d | D0c | D1c | D0b | D1b | D0a | D1a | (clk) | +--------+--------+--------+--------+--------+--------+--------+--------+ +--------+--------+--------+--------+--------+--------+--------+--------+ | D0g | D1g | D0f | D1f | D0e | D1e | D0d | (clk) | +--------+--------+--------+--------+--------+--------+--------+--------+ If there are more than 7 decles remaining in a packet, 7 are always sent, otherwise only the remaining decles are sent. This eliminates the need for length bytes in the stream. - - - - - - - - - - - - - For WORD data, up to 14 bytes in a row in pairs in this format: +--------+--------+--------+--------+--------+--------+--------+--------+ | D7a | D6a | D5a | D4a | D3a | D2a | D1a | (clk) | +--------+--------+--------+--------+--------+--------+--------+--------+ +--------+--------+--------+--------+--------+--------+--------+--------+ | D15a | D14a | D13a | D12a | D11a | D10a | D9a | (clk) | +--------+--------+--------+--------+--------+--------+--------+--------+ .... Followed by two decles in this format to give the missing bits: +--------+--------+--------+--------+--------+--------+--------+--------+ | D8d | D0c | D8c | D0b | D8b | D0a | D8a | (clk) | +--------+--------+--------+--------+--------+--------+--------+--------+ +--------+--------+--------+--------+--------+--------+--------+--------+ | D0g | D8g | D0f | D8f | D0e | D8e | D0d | (clk) | +--------+--------+--------+--------+--------+--------+--------+--------+ If there are more than 7 words remaining in a packet, 7 are always sent, otherwise only the remaining words are sent. This eliminates the need for length bytes in the stream. For ECS->PC the following formats are used: For BYTE data, data is just sent in "nickle" pairs: +--------+--------+--------+--------+--------+ | D3a | D2a | D1a | D0a | (clk) | +--------+--------+--------+--------+--------+ +--------+--------+--------+--------+--------+ | D7a | D6a | D5a | D4a | (clk) | +--------+--------+--------+--------+--------+ For DECLE data, data is just sent in "nickle" triads: +--------+--------+--------+--------+--------+ | D3a | D2a | D1a | D0a | (clk) | +--------+--------+--------+--------+--------+ +--------+--------+--------+--------+--------+ | D7a | D6a | D5a | D4a | (clk) | +--------+--------+--------+--------+--------+ +--------+--------+--------+--------+--------+ | n/a | n/a | D9a | D8a | (clk) | +--------+--------+--------+--------+--------+ For WORD data, data is just sent in "nickle" quads: +--------+--------+--------+--------+--------+ | D3a | D2a | D1a | D0a | (clk) | +--------+--------+--------+--------+--------+ +--------+--------+--------+--------+--------+ | D7a | D6a | D5a | D4a | (clk) | +--------+--------+--------+--------+--------+ +--------+--------+--------+--------+--------+ | D11a | D10a | D9a | D8a | (clk) | +--------+--------+--------+--------+--------+ +--------+--------+--------+--------+--------+ | D15a | D14a | D13a | D12a | (clk) | +--------+--------+--------+--------+--------+ After each transfer (in either direction) the transfer is ACKd by the PC sending 0xAA and the ECS sending 0xA, in what I call "the Standard 1010 Handshake." ============================================================================== STANDARD 1010 HANDSHAKE ============================================================================== No, this has nothing to do with those cheese long distance phone companies. The 1010 handshake is simple. The ECS transfer protocol actually transfers data both directions simultaneously. This is an artifact of how the clock protocol works. For most things in the ECScable Monitor protocol, we only use one direction at a time. However, the "handshake" that's used to terminate most of the commands below uses both directions simultaneously. Basically, this handshake is quite simple. The PC and the ECS send the following bit patterns to each other: +---+---+---+---+---+---+---+-----+ | 1 | 0 | 1 | 0 | 1 | 0 | 1 |(clk)| PC -> ECS +---+---+---+---+---+---+---+-----+ +---+---+---+---+-----+ | 0 | 1 | 0 | 1 |(clk)| ECS -> PC +---+---+---+---+-----+ For some of the transfers below (such as the command header), the PC -> ECS transfer may be a different value. The standard ECS->PC "All is OK!" response is the one shown above though. ============================================================================== ECScable MONITOR FEATURES ============================================================================== The ECScable Monitor is a small program which provides communication routines for the ECScable. The Monitor implements the PC MASTER protocol, and provides support for the commands described above. The Monitor resides at $C000 - $CFFF. It also places writeable memory at $0500 - $0FFF, for monitor variables and for program loading purposes. $0500 - $07FF is writeable but not bankswitched. $0800 - $0FFF is both writeable and bankswitched, and thus is used for program loading purposes. The Monitor works by hooking the ECS's initialization sequence very early on. The ECS initialization jumps to location $C043, and the Monitor takes over from there. On initial powerup, or when told to "Reset to Monitor", the Monitor will take over and display the main Monitor screen. The Monitor can be told to "Reset to Game," in which case it will return to the normal ECS initialization sequence without entering the main monitor loop. When set to "Reset to Game," this mode will remain the default until either: -- A command is received to change the default, or -- The [1] and [9] keys are depressed on either hand controller during reset to override Reset to Game. Once a game is active, the ECScable Monitor will by default lie dormant until activated again by the override sequence given above. While dormant, the ECScable functionality cannot be used, as the ECScable Monitor itself will not be running. To allow the ECScable to be used while a game is active, the Monitor provides support for Monitor-aware programs to allow ECScable commands to be processed in the background. This is accomplished by inserting a tiny sequence of code within some periodically-occurring task in the game program: EC_LOC EQU $CF00 EC_MAG EQU $69 EC_POLL EQU $CF01 MVI EC_LOC, R0 CMPI #EC_MAG,R0 BNEQ @@no_poll CALL EC_POLL @@no_poll By placing this code in, say, an idle loop or other non-time critical section of code, a game program can enable ECScable Monitor functionality with minimal effort. (Note: Do *NOT* call it from an interrupt service routine.) Because the code detects the ECScable Monitor before it jumps to it, it is safe to leave the code in even when the Monitor is not present. Very cool. Once a game is modified to poll the ECScable Monitor, it becomes possible again to send commands to the Monitor on-the-fly. Not all commands are supported in polling mode, however. Only the following commands are supported: 0x00: PING (just echo back "OK!") 0x02: Soft Reset to GAME 0x04: Soft Reset to MONITOR 0x10: PC->ECS xfer bytes within Inty address space 0x12: PC->ECS xfer decles within Inty address space 0x14: PC->ECS xfer words within Inty address space 0x16: NOP (reserved) 0x18: ECS->PC xfer bytes within Inty address space 0x1A: ECS->PC xfer decles within Inty address space 0x1C: ECS->PC xfer words within Inty address space 0x1E: NOP (reserved) 0x20: PC->ECS xfer bytes within Intellicart address space 0x22: PC->ECS xfer decles within Intellicart address space 0x24: PC->ECS xfer words within Intellicart address space 0x26: NOP (reserved) 0x28: ECS->PC xfer bytes within Intellicart address space 0x2A: ECS->PC xfer decles within Intellicart address space 0x2C: ECS->PC xfer words within Intellicart address space 0x2E: NOP (reserved) Because upload and download commands are supported, it becomes possible to implement run-time debugging features, such as "watch windows" and so on using the ECScable protocol. How cool is that? The "ec_watch" command provides just that functionality. It's also possible to reload the program without touching the Intellivision: Just issue an "ec_load", and it'll Reset to Monitor and reload the game automagically.