In this page...


Index

$DC00-$DC0F

56320-56321 $DC00-$DC01 D1PRA D1PRB

I/O port data registers

The CIA chip has two eight-line data ports, designated A and B. Each bit in the data registers is connected to one of the port lines (PA0-PA7 for port A and PB0-PB7 for port B). The lines can be either inputs or outputs, depending on the setting of the data direction registers ($DC02-$DC03). For port B, bits 6-7 (lines PB6-PB7) can also have special timer output functions. See the discussion of the control registers at $DC0E-$DC0F for more information.

When a port line is set for input, its corresponding data register bit will reflect the state of the line. The bit will hold %0 when the line is pulled low (0 volts), or %1 when the line is high (+ 5 volts). An unconnected input line, or one connected to a device that isn’t actively pulling the line low, will “float” in a high state, and the corresponding data register bit will hold a %1. Writing to a data register bit for an input line has no effect on the state of the line, or on the value returned when the bit is read. However, the value written to the bit will be retained internally, and will determine the state of the line if the line is changed to an output.

When a port line is set for output, its corresponding data register bit will control the state of the line. Setting the bit to %0 will pull the line to a low (0 volts) state, and setting the bit to %1 will allow the line to go to a high state (+5 volts). Note that string the bit to %1 doesn’t guarantee that the output line will be set to a high state. The data CIA can force an output line low when an external device connected to the line is trying to hold the line high, but it cannot bring an output line high when an external device is holding the line low. Reading the data register bit for an output line returns the current state of the line (%0 if the line is low, or %1 if the line is high). Thus, a line set for output can still be used for a limited form of input. If the data register bit for the output line is set to %1, then reading that bit will return %1 while the output line is high and %0 when an external device pulls the line low. This explains how a joystick can be read from port A despite the fact that the lines of that port are normally configured as outputs.

Port B has a feature not available with port A. A special handshaking output line (from the CIA) designated PC, normally high, will go low for one system clock cycle each time data is read from or written to port B. This can be used to signal an external device that data has been written or accepted at the port. The PC line from CIA #1 is not connected to anything in the 128, but the PC line from CIA #2 is available at pin 8 of the user port.

For CIA #1, all port A lines are normally configured as outputs and all port B lines are normally configured as inputs. This is to set up the lines for their primary function-reading the keyboard.

The second major function of these ports is to read the status of digital controllers connected to the two control ports °n the side of the 128. Each control port is connected to five lines of one of the CIA #1 ports. Port B is connected to control port 1 (the front one) and port A to control port 2 (the back one), which is the opposite of what you might expect. The connections are as follows:

CIA port bit Controller port pin Joystick function
0 1 up
1 2 down
2 3 left
3 4 right
4 6 button

The control port pins are usually described in terms of their joystick functions, since the joystick is the device most commonly connected to the ports. A joystick is a very simple device consisting of five switches, one for each of the four primary directions and one for the fire button. The switches are normally open, meaning that no connection is made when the joystick is not being pressed. Remember that unconnected CIA port lines float to a high state (+ 5 volts), so the corresponding CIA port bits will be %1. Pressing the stick in one of the eight possible directions (four primary directions and four diagonals) closes one or two of the switches, grounding the CIA port lines and forcing the corresponding bit or bits to %0. Pressing the fire button grounds that line, so it is possible to have as many as three lines simultaneously grounded.

For reading the joysticks, BASIC provides the JOY function $8203, which returns a value from 1-7, depending on the direction the stick is pressed (the value is 0 if it is not being pressed), with 128 added if the fire button is pressed. To read the joystick from machine language, you simply read the corresponding CIA port data register and check for %0 bits. Even though the port A lines are normally set up as outputs, you can still read the joystick without switching the lines to inputs. The keyboard scan routine leaves all port A bits except bit 7 set to %1 , so it is still possible for external devices like the joystick to pull the lines low (bit 7 of that port will normally always be %0). The possible port readings are as follows:

Control port 1 CIA port B ($DC01) Control port 2 CIA port A ($DC00) Joystick direction
%11111111 255/$FF %01111111 127/$7F not pressed
%11111110 254/$FE %01111110 126/$7E up
%11111101 253/$FD %01111101 125/$7D down
%11111011 251/$FB %01111011 123/$7B left
%11111010 250/$FA %01111010 122/$7A up + left
%11111001 249/$F9 %01111001 121/$79 down + left
%11110111 247/$F7 %01110111 119/$77 right
%11110110 246/$F6 %01110110 118/$76 up + right
%11110101 245/$F5 %01110101 117/$75 up + left

If the fire button is pressed, bit 4 of the data register will also be set to %0, and the values listed above will be reduced by 16/$10. If you’d prefer to read %1 bits instead, try the following code:

Control port 1 Control port 2
LDA $DC01 LDA $DC00
AND #$1F AND #$1F
EOR #$1F EOR #$1F

Using this method, the accumulator will hold one of the following values after the port is read:

Value Joystick direction
0/$00 not pressed
1/$01 up
2/$02 down
4/$04 left
5/$05 up + left
6/$06 down + left
8/$08 right
9/$09 up + right
10/$0A down + right

Pressing the fire button will add 16/$10 to any of the values listed above.

You should be aware, however, that using control port 1 (CIA port B) for joystick input can have an undesirable side effect. Since the input lines of that port are also used for reading the keyboard, the keyscan routine $C55D has no way to tell whether the port lines are being grounded by keypresses or joystick presses. As a result, moving a joystick effectively generates a keypress, and certain keypresses produce the same effect as moving the joystick:

Joystick conflicts and Keyboard conflicts

Direction Effective keypress Keypress Effective direction
up ALT 1 up
down SHIFT-INST/DEL - down
left RETURN CONTROL left
right cursor left 2 right
fire SHIFT-F7 space fire

Many programs avoid this problem by using only port A (control port 2), which is the simplest solution. Because the port A lines are outputs, the joystick is never mistaken for the keyboard in control port 2. You can prevent the keyboard conflicts by disabling interrupts and forcing all keyboard column lines high before reading the port (add SEI:LDA #$FF:STA $DC00:STA $D02F before the LDA $DC01 instruction, and CLI after it). The joystick conflicts are more difficult to prevent-there is no way to disable the joystick. If your program doesn’t require keyboard input, a rather inelegant solution is to simply zero the count of keys in the buffer and pending function key characters (locations 208/$D0 and 209/$D1) before exiting from the program.

Any device which behaves like a joystick can be read in the same manner. This includes trackballs and the new mouse controllers (which are more or less upside-down trackballs). Devices such as paddles or graphics tablets are analog, not digital, devices, and are read by the SID chip. See the entry for the SID registers at 54297-54298/$D419-$D41A. However, any buttons on these devices are read as if they were joystick lines. For example, the two buttons on a standard pair of Commodore paddles are read exactly like the joystick left and right-direction lines for the corresponding control ports. Since the CIA ports are bidirectional, you could also use the control port lines in interfacing projects. Together they provide ten lines which can be either inputs or outputs.

The final function of these CIA ports is that bits 6-7 (lines PA6-PA7) of port A control which control port will be connected to the SID lines for reading paddles. Since paddles come in pairs and the 128 has two control ports, you can connect up to four paddles. However, the SID has only two paddle inputs. As a result, you can read paddles from only one port at a time.

The port A lines are always outputs, so there is no problem with using them for this purpose. The default value in port A (except during the IRQ, when it is being used to scan the keyboard) is 127/$7F. This has the bits set to %01, selecting control port 1. Unless you really need four paddles, it’s best to use this port. To write any value other than 127/$7F into port A, you must disable interrupts, since the keyboard-scanning routine always leaves the port set to that value.

Another bit of 128 hardware trivia: our experience indicates that a CIA #1 failure is one of the most common hardware problems the 128 owner is likely to experience. Integrated circuit chips like the CIA are very sensitive to electric discharges such as the static electric spark you see when you touch a doorknob after shuffling across a carpet. Since the control port lines lead directly to the pins of CIA #1, touching a control port pin when your body carries a static charge is like a lightning strike to the chip. Unfortunately, since the control ports lie so close to the reset and power switches, it’s very easy to touch them unintentionally, especially control port 2. Of the five 128s we have had at COMPUTE! Publications to date, three have experienced “blown” CIAs. Bit 1 of port A seems to be particularly susceptible. This is in keeping with our experience with Commodore 64s over the past several years, where we have lost approximately a dozen CIA chips out of about 30 computers. If one joystick direction or a group of keys suddenly becomes impossible to read, a blown CIA is the likely source. To prevent this, some users resort to covering the control ports with masking or electrical tape when the port is not in use. Another solution is to leave the joystick plugged in at all times.

56322-56323 $DC02-$DC03 D1DDRA D1DDRB

Data direction registers

Each of the eight lines in the CIA’s two data ports can be individually configured as either an input or an output. These data direction registers (DDRs) specify the direction of data flow on the port lines. Each register bit corresponds to one port line (PA0-PA7 for port A and PB0-PB7 for port B). Setting a register bit to %0 makes the corresponding port line an input while setting the bit to %1 makes the line an output. The lines are read and controlled by the data registers at $DC00-$DC01. For lines PB6-PB7 of port B, the settings of bits 6-7 of 56323/$DC03 can be superseded when those lines are used for their special timer output functions. See the discussion of the control registers at $DC0E-$DC0F for more information.

For CIA #1, the IOINIT routine $E109-part of both the reset and RUN/STOP-RESTORE sequences-initializes the port A DDR (56322/$DC02) to 255/$FF, making all port A lines outputs, and the port B DDR (56323/$DC03) to 0/$00, making all port B lines inputs. These settings are not changed by any other ROM routines. You can change these settings briefly for special I/O functions involving the control ports, but leaving any port A lines set as inputs or port B lines set as outputs will disable normal keyboard functioning. See the discussion of the data registers above for more information on the uses of the port lines.

56324-56325 $DC04-$DC05 D1T1L D1T1H

Timer A latch/counter registers

Timer A is a programmable counter that can provide a variety of timing functions. It is a countdown timer, meaning that it repeatedly decrements the counter contents until the value is decremented below zero, a condition known as underflow. When Timer A underflow causes an internal CIA interrupt, bit 0 of the CIA interrupt register at $DC0D will be set to %1. The timer can be set to count down repeatedly or just once. The timer countdown can be driven by either of two sources: the system clock frequency or a signal provided on the CNT line by an external device. The operating conditions of the timer are specified in the CIA control register A ($DC0E).

When read, the registers here return the current value in the 16-bit counter (low byte in $DC04 and high byte in 56325/$DC05), Data written to these registers does not go directly into the counter unless the timer is currently stopped.

Instead, the values are held in an internal latch register. The latch contents are transferred into the counter whenever the timer underflows. Alternatively, a bit in the control register can force an immediate transfer of the latched value into the counter.

One special function of timer A is to control the rate of data output over the CIA’s serial port (SP) line. In this case, timer A generates a clock signal that is provided as an output on the CNT line. Since timer A must underflow twice to produce the full clock cycle on the CNT line required for each bit, you should load timer A with a value which will produce an underflow in half the time desired for each bit. In other words, the duration of each bit transmitted on the serial line will be twice the time required to count down the value specified in the timer A latch. See the entry for the CIA serial data register ($DC0C) for more information on the CIA’s serial data I/O capabilities.

For CIA #1, timer A can be a source of IRQ interrupts to the processor. This feature is used during tape I/O to generate the IRQ interrupts which drive the reading and writing of data. CIA #1 timer A also controls the transmission rate for data sent over the fast serial bus. Thus, if you use the timer for your own timing applications, you should be aware that both tape and fast serial operations will change the settings of the timer. The timer will be stopped upon completion of any tape or fast serial operation. The IOINIT routine $E109 calls the Kernal fast serial output setup routine, which starts the timer counting down from $0004, but then immediately calls the fast serial input setup routine, which halts timer A. Thus, upon completion of the reset or RUN/STOP-RESTORE sequence, the timer will contain some very low value: usually either $0001 or $0002. Unlike the Commodore 64, CIA #1 timer A is not the source of the 128’s normal jiffy IRQ interrupts. That task is instead performed by raster interrupts from the VIC chip.

56326-56327 $DC06-$DC07 D1T2L D1T2H

Timer B latch/counter registers

The operation of timer B is quite similar to that described above for timer A, but is a bit more flexible. In addition to counting system clock and CNT pulses, timer B can also count timer A underflows. This effectively ties the two timers together to form a 32-bit countdown value, allowing countdown intervals of up to 70 minutes. The operation of timer B is controlled by the register at $DC0F

For CIA #1, the IOINIT routine $E109, part of both the reset and RUN/STOP-RESTORE sequences, loads the latch for this timer with 65535/$FFFF and starts the timer running in continuous mode. There is no obvious reason for this step. The only use of timer B by 128 ROM routines is during tape I/O, where it is used to generate IRQ interrupts to drive the reading and writing of data. Upon completion of a tape operation, the timer will be left halted and set for one-shot mode.

56328-56329-56330-56331 $DC08-$DC09-$DC0A-$DC0B D1TOD1 D1TODS D1TODM D1TODH

Time-of-day clock registers

The time-of-day (TOD) clock is a special feature of the CIA. It keeps time in hours, minutes, seconds, and tenths of seconds-units more useful to humans than the jiffies of the system software clock or the fractional microseconds of timer A or B. There are actually two sets of registers at these locations, the time and the alarm. By storing an alarm value here, you can trigger an internal interrupt (and, optionally, an external IRQ request) when a specified time is reached. When you read the registers, you always see the time value (the alarm setting is never visible). When you’re writing to the register, bit 7 of control register B ($DC0F) determines whether the value being written will set the time or the alarm.

The time is kept in 12-hour format, with bit 7 of the hours register used as a flag to indicate AM or PM. The time data in the registers is in binary coded decimal (BCD) format. In this format, each half-byte (nybble) contains a value which represents one decimal digit. For example, if the minutes register contains the value %00100110, equivalent to 38/$26, the minutes digits should be interpreted as 2 and 6-26 minutes past the hour, rather than 38 minutes. The register bits should be interpreted as follows:

The order in which you read and write these registers is important. When reading the clock, the registers latch (remain constant) after you read the hours register until you read from the 1/10-seconds register. The clock continues to count internally; only the register values remain constant. Thus, each read of the hours register must be followed by a read of the 1/10-seconds register, even if you don’t care about the 1/10- second value. Likewise, the clock stops whenever a value is written to the hours register, and does not start again until a value is written to the 1/10-seconds register. Thus, for both reading and writing you should start with the hours register and end with the 1/10-seconds register.

The following routine illustrates the use of the time-of-day clock by displaying the current time in the upper left corner of the screen:

D00 LDA #$89    // Load clock registers with desired
D02 STA $DC0B   // initial time. (This example uses
D05 LDA #$05    // 9:05:00.0 PM)
D07 STA $DC0A
D0A LDA #$00
D0C STA $DC09
D0F LDA #$00
D11 STA $DC08   // Clock starts when this register is written
D14 LDA $DC0B   // Read hours byte (this latches the time value)
D17 BMI $0D1D   // Add either an A or a P to the time string,
D19 LDX #$41    // depending on the state of the AM/PM bit
D1B BNE $0D1F
D1D LDX #$50
D1F STX $0D70
D22 AND #$7F    // Mask off the AM/PM bit
D24 JSR $0D54   // Convert the hours byte to two characters
D27 CMP #$30    // RepIace leading zero with a space
D29 BNE $0D2D
D2B LDA #$20
D2D STA $0D67   // Add hours-digit characters to string
D30 STX $0D68
D33 LDA $DC0A   // Read minutes byte
D36 JSR $0D54   // Convert to two character
D39 STA $0D6A   // Add minutes-digit characters to string
D3C STX $0D6B
D3F LDA $DC09   // Read seconds byte
D42 JSR $0D54   // Convert to two characters
D45 STA $0D6D   // Add seconds-digit characters to string
D48 STX $0D6E
D4B LDA $DC08   // Read 1/10-seconds byte (to unlatch time)
D4E JSR $0D62   // Print time string
D51 JMP $0D14   // Repeat indefinitely
                // Convert BCD byte to two ASCII characters
D54 PHA         // Stash the byte
D55 AND #$0F    // Mask off all but the lower four bits
D57 ORA #$30    // Add base ASCII numeral value
D59 TAX         // Leave low digit in X register
D5A PLA         // Retrieve original value
D5B LSR         // Move high four bits into low nybble
D5C LSR
D5D LSR
D5E LSR
D5F ORA #$30    // Add base ASCII numeral value
D61 RTS
D62 JSR $FF7D   // Print time string using Kernal PRIMM
.byte $13, $13, $30, $30, $3A, $30, $30, $3A
.byte $30, $30, $20, $41, $4D, $20, $00
D74 RTS

Neither CIA’s time-of-day clock is used by 128 mode, although CP/M does make use of the CIA #1 dock for timekeeping. None of these registers is initialized by any 128 ROM routine. Thus, both are free for your own programming. All clock registers are reset to %0 when the system is reset.

56332 $DC0C D1SDR

Serial data register

The CIA supports serial (bit-by-bit) data transfers in hardware. This register holds the byte of data to be sent over the CIA’s SP (serial port) line, or the byte read from the line. At any given time, the CIA serial line must be configured for either input or output. This is controlled by the setting of bit 6 of control register A ($DC0E).

When the line is set for input, the state of the SP line is read as a data bit each time there is a low-to-high (0 to +5 volts) transition on the CNT input line. (CNT must be driven by the external device which is sending data.) As each bit is read, it is transferred into an internal serial shift register. When an entire byte has been read (after eight pulses of the CNT line), the value in the internal shift register is transferred to this register and an interrupt will be indicated in bit 3 of the CIA interrupt register ($DC0D). At this point, the received byte can be read from the register.

When the line is set to be an output, data written to this register will be transferred into the internal shift register and then sent out a bit at a time over the SP line. Timer A determines the rate at which bits will be sent. The transmission will begin immediately if timer A is running; otherwise, it begins when the timer is started. Bits will be written on the serial line at one-half the countdown rate of timer A. That is, timer A must underflow twice for each bit sent. This clock signal appears as output on the CNT line. After all eight bits are sent, an interrupt will be indicated in bit 3 of the CIA interrupt register ($DC0D) to indicate that another byte can be sent.

This hardware serial data communications feature went unused in the Commodore 64, but in the 128 it is used to support the fast serial bus. The only fast serial peripheral device currently in widespread distribution is the 1571 disk drive, but others may appear in the future. For CIA #1, the SP line is connected to the serial bus DATA line (with additional circuitry to prevent conflicts with slow serial communications) and the CNT line is connected to the SRQIN line. The CIA #1 SP and CNT lines are also available from the user port, at pins 5 and 4, respectively.

56333 $DC0D D1ICR

Interrupt control register

The CIA chip has five internal interrupt sources: timer A underflow, timer B underflow, time-of-day clock alarm, serial data buffer full or empty, and FLAG signal. The CIA can also generate an interrupt request output signal as a result of any of these conditions. The location actually has two different functions, depending on whether it is being read from or written to. When you read from this register, you see the contents of an internal interrupt data register that indicates which interrupts, if any, have occurred. When you write to this register, the value goes to an internal interrupt mask register that specifies which interrupts-if any-are to result in an external interrupt request being generated. The data register is read-only (it can’t be written to), and the mask register is write-only (it can’t be read from).

When you’re reading from the register, bits 0-4 indicate which interrupts have occurred since the last time those bits were read. The bit is set to %1 when the corresponding interrupt occurs, regardless of whether or not the source is set to trigger an external interrupt request output. All these bits are automatically cleared to %0 after the register has been read. The interrupt type indicated by the individual bits is as follows:

Bit Interrupt source
0 Timer A undeflow
1 Timer B undeflow
2 Time-of-day clock alarm
3 Serial data buffer full or empty
4 High-to-low transition on FLAG input line

A timer underflow occurs when the timer counts down below zero. A time-of-day clock alarm occurs when the time in the clock registers matches the value in the alarm registers. The serial-buffer-empty condition occurs during output after all eight bits for a byte have been written on the serial port (SP) line, and a buffer-full condition occurs during input after eight bits have been read from the SP line. The FLAG line is a special input provided on the CIA specifically for the purpose of generating interrupts. A FLAG interrupt occurs whenever the device connected to the FLAG line causes a high-to-low voltage transition (+5 to 0 volts) on the line.

Bits 5-6 are unused. Writing to them has no effect, and they always return %0 when read.

Bit 7 controls the interrupt mask register function. When vou’re writing to this register, bit 7 determines which mask bits will be set or cleared. If bit 7 is set to %1 in a value written to this register and any of bits 0-4 in the value are also set to %1/ then the corresponding interrupt mask bits will be set and the specified interrupt or interrupts will generate an external interrupt request output. The mask bits correspond to the sources listed above the data register. For example, to enable timer B as an interrupt source you would write a value to the register which has bits 1 and 7 set to %1 - LDA #$82:STA $DC0D. Bits in the value which are %0 are not significant. If bit 7 in the value written to the register is set to %0 and any of bits 0-4 in the value are %1, then the corresponding mask bits will be cleared and the specified interrupt or interrupts will be disabled. For example, you could use LDA #$0F:STA $DC0D to clear all except FLAG interrupts. Again, bits in the value which are %0 have no effect.

When external interrupt requests are enabled, you can read bit 7 to determine whether any interrupts have occurred. When read, bit 7 will be %0 if no CIA source has generated an interrupt request, or %1 if an interrupt request output has been generated as the result of one or more enabled internal CIA interrupt conditions. Remember, however, that all the data bits in this register are cleared to %0 after the register is read. Thus, you must preserve the read register value if you wish to determine which source produced the interrupt request. For example, you shouldn’t test bit 7 with the machine language BIT instruction, since that will result in the loss of the data register bit settings. For CIA #1, the interrupt request output is connected to the processor’s IRQ input line, so interrupt requests from CIA #1 result in IRQ interrupts to the processor. The IOINIT routine $E109 clears all interrupt mask bits, so initially no interrupts are enabled. Some operations enable interrupts for the duration of their activity. Tape I/O, which is interrupt-driven, uses timer A, timer B, and FLAG interrupts as IRQ sources. Fast serial bus I/O uses internal serial data buffer interrupts, but does not trigger external IRQ requests. See the tape and fast serial routines in Chapter 9 for details. You are, of course, free to set up your own CIA #1 interrupts, but you must write your own interrupt service routine. The standard IRQ handler $FA65 merely reads this register to clear it, and ignores the value read. In Commodore 64 mode (and in the original Commodore 64), timer A interrupts from CIA #1 were the source for the system’s 1/60-second jiffy IRQ. However, 128 mode instead uses raster interrupts from the VIC chip for that function.

56334 $DC0E D1CRA

Control register A

This register controls the operation of timer A, except for bits 6-7, which control serial data port and time-of-day clock functions, respectively. See the entry at $DC04-$DC05 for more information on timer A.

Bit 0: this bit acts as the ignition switch for timer A. Writing a %0 here stops the timer. If the timer is currently stopped, writing a %1 here causes the counter to begin decrementing its current contents (unless the force load strobe, bit 4 of this register, is also set to %1-in that case, the latch value is loaded into the counter before counting resumes). Writing a %1 here when the bit is already set to %1 has no effect. Setting the bit to %0 when it has previously been %1 halts the timer, leaving the counter holding the value it has reached when stopped. When the timer is set for one-shot mode, this bit will automatically be reset to %0 when the count underflows. In this case, the counter will be reloaded with the latch value.

For CIA #1, the IOINIT routine sets this bit to %0, so timer A is initially stopped. The ROM routines for tape I/O use this timer to generate IRQ interrupts for reading and writing tape bits, but the bit is reset to %0 upon completion of any tape operation. The Kernal SPOUT routine $E5D6, which prepares the fast serial bus for output, starts the timer and leaves it counting. (Timer A determines the rate at which data is sent over the fast serial lines.) The Kernal fast serial output routines end with calls to the SPIN routine $E5C3, which resets this bit to %0, halting the timer.

Bit 1: this bit controls whether or not timer A generates output on the PB6 line of port B. Writing a %1 here enables PB6 output. When PB6 is selected for timer A output, the line automatically becomes an output, regardless of the setting of the data direction register bit for that line. The output on PB6 will be either short pulses or a regular toggling of the line between high and low states. The output mode is controlled by bit 2 of this register. Writing a %0 here disables timer A output and restores PB6 to the state and function defined in the port B data and data direction registers. For CIA #1, this bit is set to %0 during the IOINIT routine $E109, and is not changed by any 128 ROM routine. The PB6 output feature is not useful on CIA #1 , since the PB6 line for that CIA is connected only to a keyboard row scanning line, and is not available externally. However, the PB6 line from CIA #2 is available at pin K of the user port, so this feature could be used with timer A of that CIA.

Bit 2: when bit 1 of this register is set to allow timer A to generate output on the PB6 line of port A, this bit controls the type of output. (This bit has no effect when bit 1 is %0.) The two selections for output type are pulse and toggle. For pulse output, selected when this bit is set to %0, the output line is held low except for a very brief high pulse each time timer A overflows. The line will be held high for one cycle of the O2 clock rate. For the 128, that is equal to 0.978 microseconds in NTSC (North American) systems, or 1.01 microseconds on PAL (European) systems. For toggle output, selected when this bit is set to %1 , the PB6 line switches state-low-to-high or high-to-low-each time the timer underflows, starting from a high state.

For CIA #1, this bit is set to %0 during the IOINIT routine $E109, and is not changed by any 128 ROM routine.

Bit 3: this bit controls whether timer A runs in continuous or one-shot mode. In continuous mode, selected when this bit is set to %0, the timer will perform repeated countdowns. After each underflow, the counter is reloaded with the latch value and restarted. In one-shot mode, selected when this bit is set to %1, the timer counts down to underflow only once, at which time bit 0 of this register is reset to %0 to halt further counting. However, the latch value is still transferred to the counter when the underflow occurs.

For CIA #1, the IOINIT routine $E109 initializes this bit to %1, Tape I/O routines use this timer, but also in one-shot wode, so the bit should still be set to %1 after any tape operation is performed. The Kernal fast serial output routines will change this bit to %0 to run the timer in continuous mode. However, upon completion of any fast serial output operation, the port is reset for fast serial input, which includes resetting this bit to %1 for one-shot mode.

Bit 4: writing a %1 to this bit, called the force load strobe, causes the contents of the timer A latch to be transferred to the counter, regardless of whether the timer is currently running or stopped. Using the strobe bit while the timer is running allows you to modify the counter contents in the middle of a countdown. Writing a %0 to this bit has no effect. This bit is write-only; it always returns a %0 when read.

Bit 5: this bit controls which of two possible events will drive timer A. Two different input signals can be used to make the timer decrement. The timer will be decremented once for each cycle of the specified event, but only if bit 0 of this register is set to %1 to allow counting. When this bit is set to %0, the timer will be driven by the system O2 clock, which provides a “tick” every 0.978 microseconds in NTSC (North American) systems, or 1.01 microseconds on PAL (European) systems. The maximum delay between underflows with this clock rate is in the neighborhood of 1/15 second. Setting the bit to %1 makes the CIA’s CNT line the clock source, so that an external source can drive the count rate. In this case, the counter will be decremented once each time the external device connected to CNT provides a low-to-high transition on the line. For CIA #1, the CNT line is available at pin 4 of the user port. The CNT line is also used as the clock source for the fast serial bus, and is connected to the SRQIN line of the serial port. However, the line from SRQIN will be an input only when the FSDIR bit (bit 3) of the MMU mode configuration register at $D505 is set to %0.

For CIA #1, this bit is initialized to %0 during the IOINIT routine $E109, and that setting is not changed by any other 128 ROM routine. Timer A must be set to count system clock pulses in order for tape operations to perform properly

Bit 6: This bit does not control a timer A function, but instead specifies the direction of data flow on the CIA’s serial port (SP) line. When this bit is set to %0, the SP line is an input. Data read on the line will be collected in the serial shift register until a full byte has been received; then an interrupt will be generated. When this bit is set to %1, the SP line is an output, and data written to the serial data register at $DC0C will be sent out on the SP line at a rate depending on timer A.

For CIA #1, this bit is initialized during the IOINIT routine to %0. The 128 uses the CIA #1 serial data register for fast serial bus communications, so the bit must be set to %1 whenever fast serial output is being performed. However, after the output has been completed the Kernal fast serial output routines reset the bus for input, which includes resetting this bit to %0.

Bit 7: This bit controls a time-of-day clock function rather than a timer A function. It determines the rate at which the time-of-day clock will be incremented. The clock is driven by the CIA’s TOD input pin, which, in the 128, is connected to circuitry which produces a clock signal from the AC power supply. This signal will have the same frequency as the local power supply, generally 60 hertz (60 cycles per second) in North America and 50 hertz in Europe. Setting this bit to %0 specifies that the 1/10-seconds digit of the clock time should be incremented once for every 6 cycles of the TOD signal (for a 60-hertz source), while setting it to %1 specifies that the digit should be incremented on every fifth cycle (for a 50-hertz source). Specifying an incorrect rate will make the time-of-day clocks in your system count either too fast or too slow.

For CIA #1, this bit is initialized to %0 during the IOINIT routine $E109, and that setting is not changed by any other 128 ROM routine. This is the proper setting for North America, but unless there is a different version of the ROM in European 128s, overseas users will need to change this bit to get proper timekeeping.

56335 $DC0F D1CRB

Control register B

This register controls the operation of timer B, except for bit 7, which controls a time-of-day clock function. See the entry at $DC04-$DC05 for more information on timer B.

Bit 0: this bit acts as the ignition switch for timer B. While the bit is %0, the timer is stopped. If the timer is currently stopped, writing a %1 here starts the counter. The countdown will resume with the current counter contents unless bit 4 of this register is also set to %1 to force the latch value to be reloaded. Writing a %1 here when the bit is already set to %1 has no effect. Setting the bit to %0 when it has previously been %1 halts the timer, leaving the counter holding whatever count value it has reached when stopped. When the timer is set for one-shot mode, this bit is automatically reset to %0 when the count underflows. In this case, the counter is reloaded with the latch value.

For CIA #1, the IOINIT routine sets this bit to %1, so timer B is normally running (although there is no obvious reason for this). The timer is used in one-shot mode for tape I/O, so this bit will be set to %0 (and the timer will be stopped) upon completion of any tape operation.

Bit 1: this bit controls whether or not timer B generates output on the PB7 line of port B. Writing a %1 here enables PB7 output. When PB7 is selected for timer B output, the line automatically becomes an output, regardless of the setting of the data direction register bit for that line. The output on PB7 will be either short pulses or a regular toggling of the line between high and low states. The output mode is controlled by bit 2 of this register. Writing a %0 here disables timer B output and restores PB7 to the state and function defined in the port B data and data direction registers. For CIA #1, this bit is set to %0 during the IOINIT routine $E109, and is not changed by any 128 ROM routine. The PB7 output feature is not useful on CIA #1, since the PB7 line for that CIA is connected only to a keyboard row scanning line, and is not available externally. However, the PB7 line from CIA #2 is available at pin L of the user port, so this feature could be used with timer B of that CIA.

Bit 2: when bit 1 of this register is set to allow timer B to generate output on the PB7 line of port B, this bit controls the type of output. This bit has no effect when bit 1 is %0. The two selections for output type are pulse and toggle. For pulse output, selected when this bit is set to %0, the output line is held low except for a very brief high pulse each time timer B overflows. The line will be held high for one cycle of the O2 clock rate. For the 128, that is equal to 0.978 microseconds in NTSC (North American) systems, or 1.01 microseconds on PAL (European) systems. For toggle output, selected when this bit is set to %1, the PB7 line switches state-low-to-high or high-to-low-each time the timer underflows, starting from a high state.

For CIA #1, this bit is set to %0 during the IOINIT routine $E109, and is not changed by any 128 ROM routine.

Bit 3: this bit controls whether timer B runs in continuous or one-shot mode. In continuous mode, selected when this bit is set to %0, the timer will perform repeated countdowns. After each underflow, the counter is reloaded with the latch value and restarted. In one-shot mode, selected when this bit is set to %1/ the timer counts down to underflow only once, at which time bit 0 of this register is reset to %0 to halt further counting. However, the latch value is still transferred to the counter when the underflow occurs.

For CIA #1, the IOINIT routine $E109 initializes this bit to %0, so timer B starts running continuously. However, the tape I/O routines use this timer in one-shot mode, and this bit will be left set to %1 after any tape operation has been performed.

Bit 4: writing a %1 to this bit, called the force load strobe, causes the contents of the timer B latch to be transferred to the counter, regardless of whether the timer is currently running or stopped. Using the strobe bit while the timer is running allows you to modify the counter contents in the middle of a countdown. Writing a %0 to this bit has no effect. This bit is write-only; it always returns a %0 when read.

Bits 5-6: these bits control which of four possible events will drive timer B. That is, four different input signals can be used to make the timer decrement. The timer will be decremented once for each specified event, but only if bit 0 of this register is set to %1 to allow counting. The four possible selections are as follows:

Bit 6-5 Timer B driving source
0 0 System clock
0 1 CNT line transition
1 0 Timer A underflows
1 1 Timer A underflows while the CNT line is high

The default source, the system O2 clock, provides a “tick” every 0.978 microseconds in NTSC (North American) systems, or 1.01 microseconds on PAL (European) systems. The maximum delay between underflows with this clock rate is in the neighborhood of 1/15 second. The CNT option (%01) allows an external source to drive the count rate. In this case, the counter will be decremented once each time some external device causes a low-to-high transition on the CIA’s CNT line. For CIA #1, the CNT line is available at pin 4 of the user port. The CNT line is also used as the clock source for the fast serial bus, and is connected to the SRQIN line of the serial port. However, the line to SRQIN will be an input only when the FSDIR bit (bit 3) of the MMU mode configuration register at 54533/$D505 is set to %0. The option to count timer A underflows is convenient for creating longer delays. By setting timer A to count system O2 clock pulses and timer B to count timer A underflows, you can achieve a countdown interval of up to 70 minutes when both timers start with maximum counts.

For CIA #1, these bits are initialized by the IOINIT routine to %00 to have the timer count system clock pulses. This setting is not changed by any other Kernal routine. Tape operations will function properly only when CIA #1 timer B is counting system clock pulses.

Bit 7: unlike the other bits of this register, this one does not control a function of timer B. Instead, it specifies whether values written to the time-of-day clock registers at $DC08-$DC0B will be directed to the clock time latch or to the alarm latch (see the discussion of the time-of-day clock registers for more information on the alarm function). While the bit is %0, values written to the registers affect the clock time latch. Setting this bit to %1 allows you to set the alarm time. This bit affects only writing to the time-of-day clock registers. When read, the registers always return the clock time, never the alarm time.

56336-56575 $DC10-$DCFF D1CRB

CIA #1 register images

Due to incomplete address decoding, images of the CIA chip registers appear repeatedly every 16 bytes throughout the remainder of this page of memory. That is, storing a value in any location in this range with an address that is an exact multiple of 16 greater than one of the base register addresses has the same effect as storing the same value in one of the base register locations. For example, storing a value in 56336/$DC10 or 56560/$DCF0 has the same effect as storing a value in 56320/$DC00. However, it’s better programming practice to use the officially designated register addresses.

See also