Commodore 1551 cartridge interface

From C64-Wiki
Jump to navigationJump to search

The Commodore 1551 uses a special included cartridge to interface to the Plus/4 or Commodore 16. This is called Commodore 1551 cartridge interface. The Kernal on these computers recognizes the cartridge; the cartridge contains no ROM. The interface, and the Kernal's use of it, are described here.

The description of the interface is based on examining source code for the Plus/4 Kernal. It is liable to be wrong in some places; the author does not have a working implementation at hand. Users are cautioned to use this information at their own risk.

Devices[edit | edit source]

The Commodore 1551, if it is present and powered on, replaces device 8 or 9. Accesses to these device numbers will go to the cartridge; otherwise, they go to the serial port, which may access a 1541 or other compatible device. It is possible to connect two cartridges, provided one is configured for device 8 and one for device 9.

Memory addresses[edit | edit source]

The cartridge presents six registers in the memory space, beginning at address $FEF0 for device 8 or $FEC0 for device 9.

The six registers address a 6523 Tri-Port Interface. This chip is nothing fancy; it simply presents three eight-bit I/O ports, with each bit configurable as input or as output. They work like the ports in a VIA or CIA, or the built-in port in a 6510. Though 24 bits are available, the interface uses only twelve.

The six registers are as follows:

Address (device 8) Address (device 9) Name Usage
$FEF0 $FEC0 Port A Bits 7-0: Command and data
$FEF1 $FEC1 Port B Bits 0-1:
0=OK
1=write timeout
2=read timeout
3=EOI
$FEF2 $FEC2 Port C Bit 7: peripheral acknowledges byte transfer
Bit 6: controller requests byte transfer
$FEF3 $FEC3 Port A direction Normally $FF (all bits are outputs)
Set to $00 (all inputs) while reading a data byte
$FEF4 $FEC4 Port B direction $00: bits 1-0 are inputs
$FEF5 $FEC5 Port C direction $40: bit 7 is an input and bit 6 is an output

Protocol[edit | edit source]

Each possible command on the serial port seems to have an equivalent on the cartridge interface, except that there appears to be no way for the controller to signal EOI. Because each cartridge can connect to only one drive, there is no need to send the device address when requesting TALK or LISTEN.

Detecting a drive[edit | edit source]

The Kernal proceeds as follows:

  • If the device number is not 8 or 9, report not found.
  • Write $55 to Port A.
  • Read Port A back. Port A is normally configured for output and anything written to it should read back.
  • If the $55 byte does not read back, report not found.
  • Read Port B and check bit 1. The pin has a pull-up resistor and will read as 1 if the drive is not connected.
  • If Port B bit 1 is 1, report not found.
  • If all the above checks pass, report found. The access will go through the cartridge.
  • If the cartridge is not found, the access will go to the serial port.

Writing a byte[edit | edit source]

The protocol actually writes two bytes. The first gives the type of the second byte and the second byte contains the contents. The Kernal proceeds as follows:

  • Initially Port A is set for output, and it contains $00. This byte, or any byte other than those listed below, is ignored. The device sets Port C bit 7 to 1, and the controller sets Port C bit 6 to 1.
  • Write the first byte to Port A. This byte is a command, and can be any of the following:
    • $81, "change state": this corresponds to the ATN signal on the serial port. The second byte can be any of the following:
      • $40, ITALK: place device in talk mode
      • $20, ILSTN: place device in listen mode
      • $5F, IUTALK: end talk mode
      • $3F, IULSTN: end listen mode
    • $82, "secondary address": this sets the secondary address. The second byte is the secondary address. Valid secondary addresses are 0 to 31; it is not clear whether the upper 3 bits will have the same values as on the serial port.
    • $83, DOUT: this sends a data byte. The second byte is the data.
    • $84 is also permitted here, but it indicates a read. Reading is described in the next section.
  • Wait for the device to acknowledge the command. The device acknowledges by setting Port C bit 7 to 0.
  • Write the second byte (new state, secondary address or data) to Port A.
  • Write $00 to Port C. This sets bit 6 to 0 (and has no effect on bit 7, because it is an input).
  • Wait for the device to acknowledge the byte. The device acknowledges by setting Port C bit 7 to 1.
  • Read status from Port B. Bit 1 should always be 0; bit 0 set indicates a timeout.
  • Return outputs to the initial state: $00 to port A and $40 to port C.

Reading a byte[edit | edit source]

The controller writes a read command and then reads a byte:

  • Initially Port A is set for output, and it contains $00. This byte is ignored. The device sets Port C bit 7 to 1, and the controller sets Port C bit 6 to 1.
  • Write $84, DIN, to Port A.
  • Wait for the device to acknowledge the command. The device acknowledges by setting Port C bit 7 to 0.
  • Write $00 to the Port A direction register. This sets all bits of Port A for input.
  • Write $00 to Port C. This sets bit 6 to 0 (and has no effect on bit 7, because it is an input).
    • The device should not drive Port A until it sees a 0 on Port C bit 6, or it may cause contention with the outputs from the cartridge.
  • Wait for the device to signal that data and status are ready. The device signals by setting Port C bit 7 to 1.
  • Read the data from Port A and the status from Port B.
    • Port B bits 0 and 1 both set indicate EOI. Bit 1 alone indicates read timeout.
  • Write $40 to Port C. This sets bit 6 to 1.
  • The device should cease driving Port A before it acknowledges.
  • Wait for the device to signal that it has released Port A. The device signals by setting Port C bit 7 to 0.
  • Reset Port A to its initial state: all outputs ($FF in the direction register) and outputs set to $00.
  • Write $00 to Port C. This sets bit 6 to 0.
  • Wait for the device to set Port C bit 7 to 1.
  • Write $40 to Port C. This sets bit 6 to 1. The interface is returned to its initial state.

Higher level protocol[edit | edit source]

A full description of how the input and output bytes go together awaits a working implementation. They likely work similarly to the serial port.