Bottom     Previous     Contents

Chapter Nine
Interrupt Techniques and the User Port

The anatomy of the user port

Superficially, the user port is a 20-pin socket situated at the rear of the machine. It is rather neglected, only a minority of owners putting it to use. there are several reasons for this lack of interest In the first place, its use demands at least a smattering of electronic knowledge and perhaps some dexterity with a soldering iron. For some reason (snobbery, perhaps?), many reviewers and critics mention the soldering iron with a slight air of patronage. This is a pity because once the craze for games begins to wear thin (hopefully not too far distant in time), practical work, combining computer interests with home-made electronic gadgetry can open up exciting new possibilities. Another reason for the neglect may be a failure to appreciate the sophistication built into the 6522 VIA. This powerful chip provides the versatility and power of the port. The 20-pin socket is only the visible interface. To put the port into perspective, it should be considered as a component of the VIA, the full complement being as follows:

  1. Sixteen memory-mapped registers.
  2. Two 16-bit timers (also under software control).
  3. A serial port
  4. Two 8-bit parallel ports, referred to as the A and B sides, each with two handshake control lines.

Apart from one of the 8-bit parallel ports (Side A, which is dedicated to forming the Centronics printer interface), all the above facilities are freely available to the user.
Both the user port and the RS423 are undedicated links to the outside world but the user port is the more complex and, unlike the RS423, obeys no established protocol. Although there are twenty pins in the socket, only ten carry information. The rest are either unused or earth return and +5V lines. The pin connections are shown in Fig. 9.1. In this chapter there will follow examples of routines rather than programs. They should help you to experiment with the user port so as to control external machinery, robotic projects etc.

Fig. 9.1. Pin connections on the user port

Never use gash wiring when you are experimenting. Resist the temptation to make both connections to the pins with croc clips or twisted wire. Croc clips are a boon in 'heavy' engineering hook-ups but getting them to stick on to the delicate pins of computer plugs (without shorting other pins) requires patience, dexterity and luck. Luck is not an acceptable commodity where the user port is concerned. Damage to the port can feed back through the entire VIA and consequently damage the health of the printer interface. The correct thing to do, before even contemplating experimentation, is to purchase the correct ribbon cable and socket which mates with the user port plug. The cable and plug can be bought a little more cheaply as separate items. The plug is of the type known as an 'Insulation Displacement Connector' (IDC for short). All you need is a vice to squeeze the plug directly onto the ribbon cable, the insulation is automatically pierced and good contact made during the vice pressure. No solder and no wire strippers are needed! However, if you are at all squeamish, or don't have a vice (mechanical that is), you can buy the ribbon cable with the plug already attached.
Before the connection is made to the plug on the user port you should do something to the other end, the free end of the cable. Don't just leave it flopping about with bare wires sticking out. Connect them, even if only temporarily, to some form of positive terminal. This can be a multi pin connector strip soldered directly to the cable wires. Alternatively, if you intend to embark on long experimental orgies, it is wise to invest in one of those boards containing rows of tiny sockets into which you can push components and wires directly. The best solution of all (although requiring more outlay) is to invest in one of the more ambitious contraptions on the market, providing on-board power supplies. For what it's worth, we have used a Proto-board (trademark) for some years. It provides just about everything needed for safe experimentation. ICs, even the 40-pin species, resistors, capacitors, LEDs and wire connecting links can all be pushed directly into any of the hundreds of tiny holes. The net result is a gadget which allows quite complex circuitry to be assembled quickly without suffering second degree burns on the finger tips. Power supply bus bars run round the edges, supplied from a 1.0 amp/5V power supply and a pair of +/-15 volt lines, ideal for supplying op-amp chips needed in hybrid systems.
Although a +5V supply is provided to the port, it should be used with great care. Remember, the power comes from the long-suffering switched mode power supply which already is reasonably well-occupied, particularly if it has to supply a single drive disk. Another useful purchase which quickly becomes invaluable is one of the 'logic probes'. The power supply for the probes is taken (via croc clips this time) from the 5 volt computer supply or, preferably, from the Proto-board. The probe can be placed on any point of the circuit and will indicate whether it is in the HIGH (logic 1) or LOW (logic 0). The nature of the indication will vary according to the make but will normally be the colour of a LED lamp.
Notice from Fig. 9.1 that each signal line has its own independent earth line. All these earths are already electrically connected together inside the computer and will, in most cases, be similarly connected at the user device end of the ribbon cable. A signal line, and its own separate earth line running next to it behave together as a 'transmission line' with an impedance of the order of 600 ohms. This technique helps to guard against 'cross talk' between wires and stray interference induced electromagnetically. The transmission line concept, however, borders on the tongue-in-cheek because no attempt is made to terminate the lines with a matched load a necessary practice according to established theory. However, the ribbon cable connection is quite satisfactory, providing it is not too long. A couple of metres is probably the safe limit.

The 6522 VIA registers

Before discussing these, the overall disposition of the user port fines should be understood. Figure 9.2 is the effective diagram.
The eight data lines are labelled PB0 to FB7. Each one can be separately programmed as either an input or an output by setting appropriate bits in a direction register (see later). When programmed as outputs, they deliver the usual TTL logic levels but are also capable of delivering 1mA at 1.5V. It is therefore possible to drive silicon transistor pairs in the Darlington configuration (ie. two transistors connected in series to achieve gain multiplication). Since a Darlington can have exceptionally high current gains, it is possible to switch loads approaching, say, 0.5 amp directly. PB7 has a unique feature. It can be programmed to receive the output of T1, one of the interval timers on the chip. PB6 is also unique when programmed as an input. It is possible for the other timer (T2) to count the number of pulses arriving at the input of PB6.
The handshake (control) lines are CB1 and CR2. These can act as interrupt inputs or as handshake outputs.

Figure 9.2. The electrical appearance of the user port.

The VIA internal registers

The VIA responsible for the user port occupies 16 consecutive addresses in the SHEILA band, starting at &FE60. The following table shows the addresses in the form of an offset to &FE60. Thus, if the offset number for a particular register is given as 3, then its absolute address is &FE63. It is better to think of the address of any individual register as consisting of the base address (&FE60) plus the offset number of the register. For example, the address base+5 is tidier than writing this as &FE65. Table 9.1 shows the location of the registers in the VIA.

Table 9.1 The VIA addresses.

Register offset no. Designation Function
0 ORB or IRB Output or input register B
1 ORA or IRA Output or input register A
2 DDRB Data direction register B
3 DDRA Data direction register A
4 TIC-L T1 low-byte latch or T1 low-byte counter
5 T1C-H T1 high-byte counter
6 T1L-L T1 low-byte latch
7 T1L-H T1 high-byte latch
8 T2C-L T2 low-byte latch or T2 low-byte counter
9 T2C-H T2 high byte counter
10 SR Shift register
11 ACR Auxiliary Control Register
12 PCR Peripheral Control Register
13 IFR Interrupt Flag Register
14 IER Interrupt Enable Register
15 ORA/IRA Identical to offset 1 but no handshake

Registers 1 and 3 will normally be left unused because, as stated previously, they are dedicated to the parallel printer interface. This still leaves fourteen registers left to grapple with. To understand them all is a formidable task. It would be demoralising to plod methodically through them in register order. Far better to attack the most commonly used ones first, the DDRB and the ORB.

DDRB (Data Direction Register B)

This is addressed at&FE62 (Base+2). The binary pattern initialised in DDR defines which of the lines PB0-PB7 will behave as outputs and which as inputs. The rule for direction in this register is as follows;

A '1' defines the corresponding pin as an output and a '0' defines an input.

Here are some examples:

LDA #&FF \all data lines outputs

STA DDRB

LDA #&0F \PB0-PB3 outputs

STA DDRB \PB4-PB7 inputs

ORB or IRB (Output Register B or Input Register B)

DDRB defines the directivity of the data lines only; it does not define their actual logic states. For example, just because we have a 1 in bit 7 of the DDRB, it does not mean FB7 will be in the '1' state. Only the contents of ORB or IRB control the logic states on the data lines. Thus, when a data line is programmed as an output, the corresponding bit set into DDRB decides the logic on the data line. On the other hand, if a line is programmed as an input, the logic state received from a device on that line is entered into the Input Register (IRB). If a line is programmed as an input, then any attempt to write into that line via ORB is ignored.

Example 1:

LDR #&FF \All data lines outputs

STA DDRB

LDA #&03 \Set PB0 and PB1 to 1

STA ORB \rest at 0

Example 2:

LDR #0 \All data lines inputs

STA DDRB

LDA IRB \Read input reg. into A

Example 3:

LDA #&F0 \PB4-PB7 outputs,

STR DDRB \rest inputs

LDA #&FF \Attempt to write 1

8TA ORB \in all lines

Example 3 illustrates the point made earlier that any attempt to write into lines programmed as inputs will fail. Although we have written &FF in the instruction, only the higher order nibble will directly affect ORB. The bits in the output register corresponding to PB0-PB3 will depend on the peripheral input logic. It is assumed in these examples that DDRB and ORB have been assigned to &FE62 and &FE60 respectively.
There are two variations of input behaviour depending on whether 'latching' is enabled or disabled. If latching is disabled, the level present at an input (the relevant PB pin) is read into IRB. If the latch is enabled, the level read into IRB is that which existed after the 'last active transition' arriving on CBI (when a pulse of the correct phasing and shape hit CBI input). In other words, if the conditions existing now are required, then latch must be in the disabled condition. We only enable latching if we require CBI to act as a data-valid signal and we wish to ignore levels arriving after the latching. The latch enabling is carried out on bit 1 of the Auxiliary Control Register (ACR). If this bit is 1, the input latch on IRB is enabled. If 0, it is disabled. The ACR (addressed at base+&B) controls many other functions, so it is essential that programming bit 1 is carried out in such a way that the remaining bits are left undisturbed. This is where the logic instructions ORA and AND become useful (refer back to Chapter 3).
To enable the input latch, study the following:

LDA ACR \Obtain the ACR

ORA #&02 \OR it with 0000 0010

STA ACR \Bit-l in ACR is now I

To disable the latch:

LDA ACR \Obtain ACR

AND #&FD \AND with 111 1101

STA ACR \Bit-1 in ACR now 0.

The two control lines

The control lines CBI and CB2 can be used for a wide range of control functions apart from initiating interrupt action.
We are concerned at this point only with the VIA registers which are involved either entirely or partly with these control fines. They will also be used for defining the kind of signal we wish to initiate the interrupt, These and other registers in the VIA must be understood first. Any gadget we construct (or buy) which is going to initiate interrupts will emit an electrical pulse of fixed characteristics. The pulse (or electrical level) will, of course, have to conform to TTL protocol but, even so, there are many possible variants. For example, the initiating signal may be simply the drop in voltage from HIGH to LOW (a so-called negative-going edge) or it may be from LOW to HIGH (a positive-going edge). It may even be a narrow downward-going or an upward-going spike. The VIA is brilliantly designed to cater for many possible input conditions. Registers can be initialised to accept, as an active interrupt, one of the above signal patterns but ignore the others. You may also remember that if an interrupt request is made, it will be refused if the I bit in the Processor Status Register is 1.

PCR (Peripheral Control Reigster)

The two control, or 'handshake', lines CB1 and CB2 have other functions besides interrupt. CB1 is always an input but CB2 can be an input or an output. Although the PCR is an 8-bit register, we shall only treat the lef-thand four (bits 4 to 7) because the other half is identical and dedicated to the parallel printer interface. It is also a fraction easier to understand if the bit pattern is first restricted to the case when CB2 is an input.
When mention is made of the 'active edge', it refers to the setting of the appropriate flag in another register (IFR). That is to say, the only indication that an acceptable pulse has appeared on CB1 or CR2 input is the setting of the appropriate flag.
The terms 'normal' and 'independent', apply only to CB2 and, even then, only when it is an input. These terms concern the conditions under which the CB2 flag is reset after it has been set. In the normal mode, the flag remains set until a READ or WRITE instruction on the data registers, ORB or IRB is activated (for example, an LDA or STA). In the independent mode, once a flag is set, READ or WRITE does not reset it. The normal mode is designed for handshaking operations between computer and peripheral. The independent mode is useful for actions not directly involving computer interraction.


Behaviour of CB2 when it is an output

CR2 becomes an output if bit 7 of the PCR is set to 1. Clearly, the significance of bits 6 and 5 is then completely different as can be seen from the following:

  1. Let bit 5=0 and bit 6=0. This configures the so-called handshake mode. CB2 goes LOW by a write operation on ORB and goes HIGH again on an active transition of the CB1 input signal.
  2. Let bit 5=1 and bit 6=0. This is the pulse output mode. A negative-going pulse (goes from HIGH down to LOW then back again) is emitted following a write operation on ORB. Ideal for gadgetry which is activated by a negative-going pulse. Just do a dummy write to ORB with an ST A ORB. If the pulse is in the wrong direction for the gadget, it is a simple matter to interpose an inverter.
  3. Let bit 6=1 This is the so-called manual mode because both levels output on CB2 must be directly programmed. The level on CB2 depends on bit 5. If bit 5 is 0, CB2 remains LOW. If bit 5 is 1, then CB2 is HIGH. In other words, providing bit 6 remains at l,CB2 mirrors the state of bit 5.

Before continuing with the next register, some consolidation examples may help to decipher all this terrible complexity. If you find the above just a bit too much, don't despair, yet! Just study the following and console yourself with the fact that the control of sophisticated and versatile equipment (and the VIA is certainly within this category) can never be easy.

(1) To configure a simple 8-bit input port, with CB1 and CB2 not used:

LDA #0

STA DDRB \make all 8 lines inputs

This would be useful for reading a set of push-buttons. Once configured as above, IRB could be read into the accumulator for processing

(2) A simple 8-bit output port, with CB1 and CB2 not used:

LDA #&FF

STA DDRB \make all 8 lines outputs

This is used for switching LEDs, etc.

(3) An output port with CB1 to be active high input and CB2 to be active high input in independent mode:

LDA #&FF \Make all lines outputs

STA DDRB

LDA #&70 \set 0111 in left half

STA PCR

Note that the right-hand four bits in the PCR (the A side of the VIA dedicated to the printer) have been tentatively reset to 0. This is not always a safe procedure because the printer is controlled by the operating system and should not be altered. The safe way, in the general case, would be to use masking techniques. For example:

LDA #&FF

STA DDRB

LDA PCR \Bring out PCR

AND #&0F \Clear left, keep right

ORA #&70 \0111 in left;leave right

STA PCR \replace modified PCR

(4) PB0-PB4 to be inputs, PB5-PB7 to be outputs. CB1 to be active low input; CB2 to be a negative-going pulse on a WRITE to the ORB:

LDA #&E0 \1110 0000 in DDRB

STA DDRB

LDA #&A0 \1010 in left half

STA PCR \of PCR

The previous remarks regarding the printer interface still apply but the extra coding, if considered important, would be the same as before.

(5) All data lines to be inputs. CB I active high input CB 2 an output in the manual mode commencing with CB2 LOW.

LDA #0

STA DDRB

LDA #&D0 \1101 0000 in PCR

STA PCR

The general concepts of interrupt techniques have been discussed in Chapter 1. You will remember that it is possible for a signal, which could arrive from an external device, to set in motion a chain of events. Such events (if allowed to progress) interrupt the present program then bring into play an interrupt service routine. On completion of this routine, the original program is rejoined at the point from which it was interrupted. If all goes well, the interruption and the rejoining goes smoothly. However, there are many pitfalls to overcome and much to be learned before 'things do go well'.
As might be expected, the computer itself contributes little towards the task. Apart from recognising the existence of an interrupt, most of the preparation is the programmer's responsibility. The concept of an interrupt is based on unpredictability. The computer never knows when it is going to be interrupted so precautions must be taken to ensure that the interrupt service routine contains provisions for preserving the contents of all registers (on the stack is a good a place as any) before corrupting them with the new routine data. Before the return from interrupt (RTI) the original register data must be returned. Apart from the loss in time, the original program should not even be aware of the interruption. With regard to the question of time, there is a well-established rule in the BBC machine. It is unwise for interrupt routines to last longer than 2 milliseconds.
The routine is deemed to start at the instant the request is granted and lasts until the recognition of RTI. The operating system periodically requests interrupt to service the screen, keyboard and other routine background tasks, hence the above warning. However, 2 milliseconds is a long time. The clock is 2 M Hz so it is still possible to squeeze in about 500 machine code instructions, even if they each take an average of 4 clock cycles.

The IFR (Interrupt Flag Register)

When a signal arrives on CBI or CB2 (if it is an input) it sets an appropriate flag to I in the ]ER. The significance of each bit in the IFR is as follows:

It is possible, and sometimes desirable, to clear directly one or more of the flags in the IFR. This is done (rather strangely) by writing 'l's into the flag positions to be cleared. Direct clearing in this manner will normally be required when the CBI or CB2 inputs are being used for purposes other than 6502 involvement in particular, when using the manual mode (refer back to PCR). Here are some examples in direct clearing:

(1) Clear CB2 flag

LDA #&0B \0000 1000

STR IFR

(2) Clear CBI and T2 flags

LDA #&30 \0011 0000

STA IFR

(3) Clear all flags

LDA #&FF \ 1111 1111

STR IFR

Bit 7 is the general interrupt status and is the only flag which cannot be reset (or set) directly. Therefore, the 1 in bit 7 position above is really of no consequence.

The IER (Interrupt Enable Register)

The bits in this register correspond exactly as described for the previous register (IFR). It represents a last ditch stand between the various interrupt request sources and the 6502 IRQ input pin. For example, there may have been an active signal arriving on, say, CB I. This will have set the CB I flag in the IFR. However, there may already be another flag or flags set. The 6502 can only accept one interrupt at a time so there is clearly a need for higher status register which can be programmed to select which flag is to be recognised (enabled). This is the role of the IER. It operates as follows:

Bits 0-6:
1 = enable
0 = enable

Bit 7:
Like bit 7 in the IFR, this bit is special.
When bit 7 = 0: Each 1 in a bit position is cleared (disabled).
When bit 7 = 1: Each 1 in a bit position enables that bit.
(Zeros in bit positions are left unchanged)

We found this quite terrible to understand. Here are some examples which we hope will help you:

(1) Enable CB1 interrupt and disable all others:

LDA #&6F \0110 1111

STA IER \Bit-7=0 so '1's disabled

LDA #&90 \1001 0000

STA IER \Bit-7=1 so bit-4 enabled

Note that the second pattern is the logical complement of the first. This is not a coincidence.

(2) Enable Tirner 1, disable the rest and then clear the T1 flag bit in the IFR.

LDA #&3F \Disable all others

STA IER

LDA #&CO \1100 0000 to enable T1

STA IER

STA IFR \Reset T1 flag in IFR

Note the logical complement again.

Organising a system in which only one device is expected to request interrupts is not too difficult. We can see from the above that the trouble starts when there are many devices, all requesting interrupt at the same time. Whatever machinations we employ down at the VIA end, they will always be subservient to the I bit in the 6502. If this is at I, nothing can barge into the existing program except, of course, via the NMI input which should be treated as sacrosanct anyway. It is worth repeating the 6502 instructions directly concerned with interrupt control:

SEI will set the I bit, preventing interrupts.
CLI will clear the I bit.
BRK will set the B bit, save the Program Counter and the Status Register on the stack, set the I bit and load the contents of addresses &FFEE and &FFFF into the Program Counter.
RTI restores the Status Register and the Program Counter from the stack. Unlike RTS, R does not add 1 to the return address.

The timers and counters

It is always possible to generate delays (time intervals) by loading one or more of the 6502 instruction registers with the desired delay number and counting down to zero. This is not always satisfactory because it ties up the computer. To provide for independent delays and various other pulse-counting operations, the VIA is equipped with a variety of timers. counters and latches. They are useful for generating interrupts at regular intervals, triggering external devices or simulating a real-time environment. The two timers, T] and T2, are essentially 16-bit counters. Each counter occupies two consecutive addresses (low and high byte) but T1, the more complex of the two, has an associated 16-bit latch, consequently occupying a further two addresses. Before treating the timers in detail, it is useful to begin with an overview of the possibilities on offer.

  1. They may be read or written into as six memory locations, four for T1 and two for T2. (See the VIA addresses given earlier in this chapter.)
  2. Their respective operation modes are governed by bits 5,6 and 7 of the Auxdrary Control Register (this is treated later).
  3. Their status, at any time during the counting phase, is obtainable by examining bits 5 and 6 in the {ER. By 'status' we mean whether or not the programmed interval has ended (time out).
  4. To generate a single time interval, a timer is loaded with the number of clock pulses required (to generate that interval).
  5. Pulses arriving on FB6 can be counted until they compare with a previously loaded number (T2 only). The normal use of PB6 as one of the eight data lines is, of course, suspended.
  6. T1 can be used to provide continuous time intervals- The time interval between pulses will depend on a previously loaded number.
  7. A single, or continuous series of pulses can be produced on FB7; the pulse width will be dependent on a previously loaded number. In this mode, FB7 will not be available as a normal data line.

Timer T2 details

It is clear from the above overview that T2 is more simple than T1. It can only generate simple time intervals or count pulses arriving on PB6.
The low-byte address of T2 is used to write or read the low-order byte of the delay number. The T2 interrupt flag is automatically cleared on a read Interrupt Techniques and the User Port 207 action. The high-byte address is used to write or read the high-byte of the number. Writing to this address completes the timer loading, clears the T2 interrupt flag and starts the timing operation. On completion of the timing interval, the T2 interrupt flag is set (bit 5 of IFR). Here are some examples:

(1) To program a delay time, equivalent to 2048 clock pulses

LDA #0 \Ensure bit-5=0 for system

STA ACR \clock mode

STA T2Lowbyte \Clear low-byte

LDA #&08

STA T2Highbyte \This starts count

LDA #&20 \0010 0000 mask for bit-5

.BACK BIT IFR \Performs AND mask

BEQ BACK \Bit-5 not yet set

LDA T2Lowbyte \Dummy read clears f

(2) To cause delay until 100 pulses have been counted from an external source on PB6:

LDA #0

STA DDRB \Make data lines inputs

LDA #&20 \0010 0000

STA ACR \Make bit-5=0,pulse count

LDA #&64 \Prepare for 100 pulses

STA T2Lowbyte

LDA #0

STA T2Highbyte \ This starts count

LDA #&20 \0010 0000 mask for bit-5

.BACK BIT IFR \Performs AND mask

BEQ BACK \ Bit-5 not yet set

LDA T2Lowbyte \Dummy read clears f

Since these two examples have used the BIT test you may find it necessary to refer back to chapter 3.

Timer T1 details

This timer has a 16-bit latch as well as the normal 16-bit counter. It is also possible to generate an output on PB7. There are four different operating modes, depending on bits 6 and 7 in the ACR. The choice is single-shot or free-running mode (bit 6) and enable or disable PB7 output (bit 7). Bit 7=0 will disable PB7 output. Bit 7=1 will enable FB7 output. Bit 6=0 is one-shot mode. Bit 6=1 is free-running mode.
The addressing details and the start and finish of timing are virtually the same as described under T2 apart from the different addresses and bit 6, instead of bit 5, for the interrupt flag in the IFR. The free-running mode is made possible by the provision of a separate 16-bit latch in the usual low-byte (T1L), high-byte (T1H) form. These occupy two separate addresses. It is possible, therefore, to read or write into the latches without affecting the associated timer count. In the free-running mode, the number in the latches is automatically re-entered into the timer again and the count restarted. This makes it possible to generate a wave form of any mark to space ratio on FB7. This is because the logic level (HIGH or LOW) on FB7 remains fixed within a timing interval but inverts to the opposite state during the next interval and so on. Some examples of T1 operations are now given.

(1) To produce a wave form of unity mark to space ratio from PB7 which carries on indefinitely. The pulse width is to be equivalent to 1024 clock cycles.

LDA #&FF \Make data lines outputs

STA DDRB

LDA #&C0 \1100 0000(bit6,7 set to 1)

STA ACR \Free-running mode in T1

LDA #0

STA T1L \Clear T1 low byte latch

LDA #&04 \&04=1024 dec in high byte

STA T1H \Starts waveform action

Note carefully that no loop is necessary in the above coding to produce repetitive action because of the automatic re-entering of the latch into the timers. The above coding merely triggers off the action and the computer is then free to carry on with other work. This can be a boon when designing complex control devices fed from the user port. It is useful to remember that the flag in the {ER is still a valid signal if the completion of each timing interval is significant to the rest of the program. It could, of course, be made to initiate an interrupt service routine.

(2) To produce an output on PB7 after 64535 clock pulses.

LDA #0 \Set T1 in one-shot mode

STA ACR

LDA #&FF

STA T1L \&FF in T1 low byte latch

STA T1H \This starts timing

LDA #&40 \0100 0000 mask for bit-6

.BACK BIT IFR

BEQ BACK \Flag not yet set

LDA T1L \Dummy read to clear f

The SR (Shift Register)

This will not be one of the commonly used registers. It is more suitable for serial data transmission, whereas the user port is oriented towards parallel. However, in the interests of continuity, the following information is given on the facilities available. As previously stated, bits 2,3 and 4 in the ACR determine the behaviour of the SR so it is sufficient to limit the discussion to the eight permutations of the three bits.

ACR bits Effect on Shift Register
000 Disable SR
001 Shift in at Counter 2 rate
010 Shift in at system clock rate
011 Shift in at external clock rate
100 Free running output at Counter 2 rate
101 Shift out at Counter 2 rate
110 Shift out at system clock rate
111 Shift out at external clock rate

Summary of the user port and its functions

Any chapter attempting to explain a device as complex as the user port is an ordeal for the writer and an even worse ordeal for anyone trying to make sense of it afterwards! A brief summary is therefore justified.

  1. The 16 registers within the 6522 VIA chip are addressed within the band &FE60 to &FEFF.
  2. The chip handles the parallel printer interface on the 'A side' and the user port on the 'B side'.
  3. Any of the eight data fines, PB0 to PB7, can be inputs or outputs depending on the bit pattern set into the DDRB. FB6 and FB7 have qualifies unique to the rest
  4. Output states on the lines depend on writing to ORB. Input states (which can be either direct or latched, depending on bit I of the AC R) can be read from IRB. ORB and IRB share the same address. Trying to write to an input n, a sterile exercise.
  5. Lines CB1 (always an input) and CB2 are for control purposes. They can be used for handshaking data transfers to or from the eight data fines or for any other purpose thought desirable. Either of them can be used to set 'interrupt flags' in the {ER. The setting of a flag, however, need not actually initiate an interrupt.
  6. The CB2 direction depends on bit 7 of the PCR.
  7. CB1 and CB2 can be programmed (by the PCR) to accept either a falling or rising edge of a pulse. CR2 can also have its flag in {ER reset 'normally' (by a read of IRE or a write to ORB) or 'independently'.
  8. Two flags in the IFR act as event signals for CBI and CB2. They are reset automatically on a read of IRB or a write to ORB, They can also be directly cleared by writing '1's into the flag bits (yes '1'!). Bit 7 of the IFR is immune to attempts directly to set or reset It is a general signal to indicate if any flags at all are at 1.
  9. The timers T1 and T2 are associated with low- and high-byte counters. Numbers placed in the counters determine the time intervals. The count starts and the previous flag (in the IFR) cleared when the highbyte is loaded. The flag is set after the count number loaded has decreased to zero.
  10. There are many possible modes of timer operation, determined by bits 5,6 and 7 in the ACR.
  11. T2 is the simplest of the two. It can generate a delay of N clock pulses, terminated by a flag, or count input pulses arriving on PB6 input.
  12. Tl can be used to provide various continuous waveforms on PB7 output, independent of continuing computer support. It can also provide simple delays.
  13. A programmable Shift Register is available. mainly for organising serial data activities.

This completes the treatment of the user port. Although it is under some control from the central processor (6502), it is clearly capable of carrying out some operations almost under its own volition. This is why the treatment has, so far, made little reference to the operating system. The coding examples given have been in isolation but it is hoped they will at least point the way. It is worth emphasising again that the flags are often referred to (rather misleadingly) as 'interrupt flags'. They can cause interrupt (if you let them) only by enabling the appropriate bit in the I ER. Many interesting projects designed for attachment to the user port can be handled quite successfully without involving interrupt action. Nevertheless, this is no excuse for not attempting simple interrupt routines. The essential thing is to keep them simple. in fact very simple, during the learning period. It is better to get used to handling internally generated interrupts before progressing to their initiation from the user port.

Internally generated interrupts

The BBC operating system is unique in the way it exposes (almost indecently) its hidden workings to the ordinary user. Not only does it expose them, it almost demands they are made use of. One example of this is the fist of FX14 calls at the top of page 426 of the User Guide, which is given more detailed treatment on page 465. FX calls become OSBYTE calls when in machine code. Thus, if we wish to take advantage of these calls, we ensure that the accumulator contains 14 before calling OSBYTE at &FFF4. There are seven dynamic conditions, any of which can be chosen to initiate an interrupt, as set out in Table 9.2

Table 9.2 OSBYTE Event Interrupt Table.
Note: Place 14 in A and Event Number in X before calling &FFEE

Event number (number in X) Enable event causing interrupt
0 Output buffer empty
1 Input buffer full
2 A/D conversion complete
3 Character entering input buffer
4 Start of vertical sync pulse
5 Interval timer crossing zero
6 Escape key pressed

A table, similar to the above, applies to disabling interrupts, except that A must contain 13 instead of 14 before calling OSBYTE.
The interrupts service routine, initiated by any of the above events, depends on the user and guidelines will be given later. However, the first problem is how to prepare the operating system to accept the routine and, what is more important, how to instruct the operating system to jump to it and return. The steps to ensure smooth linkage can be carried out in the following order:

  1. Load A and X then JSR OSBYTE (&FFEE), as selected from the Event Table above.
  2. Load the low- and high-byte starting address of your service routine in the indirection vector locations at &0220 and &0221 respectively. These addresses can be confirmed from page 465 of the User Guide.

Program 9.1 is a skeleton program to illustrate the above steps. To keep everything simple, the service routine is a simple jump to OSWRCH which prints the letter 'Z' whenever the ESCAPE key is pressed.
Lines 100 to 180 prepare everything for a smooth transition to the service routine. Lines 190 to 230 give the example service routine. The event enabled is code 6 in the Event Fable, so fines 110 and 120 load 6 in X and 14 in A, prior to calling OSBYTE. This sets in motion an interrupt to 'SERVICE' whenever the ESCAPE key is pressed. Lines 140 to 170 are responsible for placing the starting address of 'SERVICE' in the page two vectors &0220/1 which the operating system reserves for user-supplied interrupt routines. Since the program uses dynamic storage space allocated by the DIM statement at the top, it is not possible to know in advance the absolute addresses of 'SERVICE'. This is why lines 140 and 160 take advantage of the MOD and DIV instructions. These sort out the addresses in the form of low- and high-byte.

Program 9.1. Simple interrupt on event code 6.

10 REM SIMPLE EVENT INTERRUPT

20 DIM ITEST 100

30 OSBYTE=&FFF4:OSWRCH=&FFEE

40 REM ---------------------

50 FOR PASS=0 TO 3 STEP 3

60 P%=ITEST

70 REM ----------------------

80 [

90 OPT PASS

100 .PREPARE

110 LDX #6 \Enable ESCAPE event

120 LDA #14

130 JSR OSBYTE

140 LDA #Service MOD 256

150 STA &220 \Low byte interrupt vector

160 LDA #Service DIV 256

170 STA &221 \High byte interrupt vector

180 RTS

190 .Service

200 PHA:TXA:PHA:TYA:PHA:PHP

210 LDA #90

220 JSR OSWRCH

230 PLP:PLA:TAY:PLA:TAX:PLA

240 RTS

250 ]

260 REM ---------------------

270 NEXT

'Service' starts, as all interrupt routines should start, with saving all the registers on the stack. This is done by line 200 and it is well to note carefully the order of stacking. The example routine is a simple call to OSWRCH to write the character 'Z'. Line 230 restores, in reverse order, the registers to their previous values.
RUN the program first and examine the assembly out, particularly the addresses for the start of 'SERVICE' which was generated by the DIM statement.
Then enter CALL PREPARE. The interrupt routine is now activated. This can be verified by pressing ESCAPE several times and noting the 'Z'. This routine is permanent (until BREAK) and will appear to remain as part of the operating system. For example, type NEW to get rid of the BASIC program and type in a few lines of another program, say, a simple FOR/NEXT loop. Whenever ESCAPE key is pressed, the letter 'Z' will still appear.
To counter possible 'so what?' criticism. we must admit that Program 9.1 is not expected to be of the slightest use, apart from pointing the way to event interrupt handling. To have included a complex program as a service routine would haw clouded the essential issues. Any coding you choose can be substituted in the space occupied by fines 210 and 220 (you can always RENUMBER 10, 100) to get more fine space.) Also, you can change the event code 6 in line 110 to experiment with other events. Try it with Event 4 in A so that 'SERVICE' interrupts whenever a vertical sync pulse appears (which is very often!). The screen fills up with Zs until you BREAK.

Peripheral initiated interrupts

Once the general form of Program 9. I is understood, it is comparatively simple to transfer the idea from Event interrupts to peripheral interrupts. The peripheral is, of course, the user port. You will remember that an active transition at the input of either CB! or CB2 (when it is an input) can set a flag in the IFR. If the corresponding bit in the IER is set to I, the VIA sends the signal up the IRQ line and, providing the I bit in the process status register is 0, a full-blooded interrupt situation is established. The only difference in general principle in handling this kind of interrupt is the interrupt vector. It is no longer &0220/1. Page 466 of the User Guide names the vector as IRQ2V which is situated at &0206.

Summary

  1. The user port is the 'B' half of the VIA. This is an interface to the outside world, providing a set of 8 data lines (PBO to PB7) and 2 control fines (CB1 and CB2).
  2. The port also supplies a five volt positive supply rail and an earth rail for each of the data and control lines.
  3. There are 16 programmable registers in the VIA, occupying addresses &FE60 to &FE6F in the SHEILA band.
  4. The bits within DDRB determine the direction of the 8 data lines. Data lines to be outputs must have 'Us, lines to be inputs must have '0%, in the respect the bit positions.
  5. ORB and IRB are the output and input registers for the 8 data lines.
  6. Data lines. programmed as inputs by DDRB, are unaffected by attempts to WRITE directly into them.
  7. Input data can be latched or unlatched, depending on whether bit I in the ACR is 1 or 0 respectively.
  8. CB1 is always an input but CB2 can be programmed as an input or as an output.
  9. Bits 4 to 7 in the PCR are concerned with the behaviour of CBI and CB2. Bits 0 to 3 are concerned with the A side of the VIA dedicated to the Centronics printer.
  10. The IFR indicates to the programmer, by means of flags- that an active signal has been detected at CB1 and „' or CB2 input. It also has flags for detecting time out conditions on the timers T1, T2 and the completion of 8 shifts from the shift register S R.
  11. IER is closely associated with IFR on a bit by bit level. A set flag in IFR can only cause an interrupt request on the IRQ fine if the corresponding bit in IER is at 1.
  12. The timers T1 and T2 are 16-bit counters, T1 having an associated latch.
  13. Delays can be achieved, or interrupts generated, at regular intervals by loading starting numbers into the high- and low-bytes of the counters.
  14. PB7 can receive the output of the timers. PB6 can accept input pulses which can be compared with a number present in T2.
  15. It is possible to produce a waveform of arbitrary mark to space ratio at the output of PB7.

Self test

  1. What is the absolute hexadecimal address of the IFR?
  2. What is the absolute hexadecimal address of T2 high-byte counter?
  3. State the required hexadecimal contents of DDRB if all fines except PB5 are to be outputs.
  4. Which of the two control lines can never be an output?
  5. Assume the CBI flag in the [ER is set. What additional status bits in the system must be set, or reset. before an actual interrupt occurs?
  6. How do you enable the input latch on port B?

Next     Top