Ruud's Commodore Site: Template Home Email

VIC-20 ISA bus

What is it

I want a 40 or 80 columns card for my VIC-20. I had one but gave it away to someone who really needed it. In return I received two cards to build your own expansion for the VIC-20. This triggered the idea to use a CGA, MDA or Hecules (compatible) video card for the PC.
I first made a design based on PC-card, a way to attach 16-bit PC ISA-cards to your C64 or C128. But later I decided to start with a very small design that can be expanded in the way the user wishes.

Theory and hardware

If you are unfamiliar with the so called ISA bus of the PC, please read The ISA bus first.

The ISA bus has 24 address lines that makes it capable of addressing up to 16 MB of memory and (theoretically) up to 64 KB of I/O. The VIC-20 has 16 address lines and therefore only is able to address up to 64 KB. But some of this 64 KB already is occupied by memory, ROM and I/O. Although there is a lot of free space available, for compatibility reasons the only free space left to use for our own purposes we can find from $9800 to $9FFF: a meager 2048 bytes. This leaves us no alternative then to use 'page swapping'.

What is 'page swapping'? You can compare 'page swapping' with having a VIC-20, a drive and a lot of floppies. Although you have loads of data and programs to your disposal, you only can access it by one floppy a time. If the data you need resides on another floppy then the one you currently are using, you have to swap it.
In our case we are able to connect up to 16 MB of RAM, ROM and I/O to our VIC-20 through the ISA bus but we will only access it 256 bytes a time. Remark regarding using RAM: the design discussed here after do not support dynamic RAM yet!

Only 256 bytes, what about the other xx free KiloBytes? Yes, the VIC-20 only has 5 KB of RAM on board so theoretically we use quite some KB's for mapping the ISA slot. But in this way we also would throw any the compatibility with other configurations. Thus seen from a practical point of view, we can only use the area covered by IO2 and/or IO3.
IO2 and IO3 of the VIC-20 each map 1024 bytes. So my first idea was using a window of 1024 bytes. Beside this window we also need some bytes for the hardware of the interface itself ie. we need both areas. The disadvantage of this method is that it disables us to use any other hardware in need of IO2 and/or IO3. With a 256 bytes for the window and some bytes for the hardware this means that either IO2 or IO3 is free for other purposes.

A window of 256 bytes (= 8 address lines) means we need to supply the other 16 address lines ourselves in the form of I/O registers. The ISA bus has a separated I/O and memory range, the VIC-20 hasn't. So we also need some I/O to support this feature.
The disadvantage of this 'window method' is that we may need two/three extra load/store instruction for every I/O / Memory operation. The worst thing that can happen is that we have to copy data from I/O (for example RS-232) to memory on an ISA card. In that case we need those two/three extra instructions for every operation! (in that case it would be wiser IMHO to copy the data first to the VIC-20 and then back to the ISA again in blocks of 256 bytes)

Version 1

This version is IMHO the smallest possible version. If you have alook at the schematic, you will see two ISA slots: the 8-bits and 16-bits version. This design is only meant for one slot: it is either this slot or that slot, not both!. The reason for this is that the 6522 can only drive one card. If you want to use more slots, see version 2. If you are only willing to connect the smaller 8-bits cards, like a CGA, MDA or Hercules card, you should go for the 8-bits slot of course.
Only using an 8-bits data bus, what is then the advantage of using a 16-bits slot? The 16-bits IDE interface! Officialy it is 16-bits but I already found out that it can be used with only 8 bits. But be aware, in this case you loose half of the capacity of an attached hard disk drive or CDROM!
Small bonus: the IDE interface most often is found in combination with a floppy disk interface, a printer port, one or two COM ports and maybe a game port; the so called Multi-I/O card.

Technical description:
First remark: to save parts, it uses both IO2 and IO3. IC1, a 6522, generates the needed address lines and is selected by IO3. As said above, the ISA bus has a separated I/O and memory range and IC2, a 74LS138 demultiplexer, takes care of it and is controlled by IO2. Remark: of course you are free to swap IO2 and IO3.
The signal that tells IC2 to generate either I/O or memory related signals, is provided by the 6522 by means of CB2.

To be able to address the complete range above the 1 MB barrier, we need to encode the address lines A20..23. But then we need extra parts. Given the parts we use now, we can use one extra megabyte by encoding address line A20.

Unfortunately the ISA bus needs an active (H) signal as Reset. Instead of adding an IC, I choose for a transistor and a resistor to be used as inverter.
- Address bus, A0..7     used unbuffered 
- Address bus, A8..20    generated by 6522
- Address bus, A21..23   not supported, tied to ground
- AEN                    only needed with DMA, tied to Ground                    
- BALE                   Phi2
- CLK                    Phi2
- Data bus, D0..7:       used unbuffered 
- Data bus, D8..15:      not used, buffered by resistors for safety reasons
- DRQ / DACK             not supported   
- IOCHRDY                cannot be used, left free
- IORD / IOWR            provided by IC1
- IRQ                    not supported
- MEMR / MEMW            provided by IC1 
- OSC                    fed by 14.3181 MHz crystal (optional)
- REFRESH                not supported
- RESET                  reset signal from host, inverted by transistor
- SMEMR / SMEMW          provided by IC1 
- T/C                    not supported
- all other 16-bits signals aren't supported as well   
Remark regarding MEMR and MEMW: officially they should be active during all memory accesses. In this case they are only active during accesses above the 1 MB barrier. If you aren't sure whether a 16-bits cards uses SMEMx or MEMx beneath the 1 MB barrier and you intend to use the card only in the first 1 MB range, connect the MEMx inputs of the ISA bus with SMEMx as well and connect address line A20 to GND.

Remark regarding IOCHRDY: this signal can halt the processor of a PC. The expansion port of the VIC-20 doesn't provide means to use this signal. Maybe a weird proposal but a direct line between this output and the RDY input of the 6502 should work IMHO.
I tested this in the past with an equivalent card for the C64 and that worked out fine.

Remark regarding OSC: this input should be fed with a 14.3181 MHz signal. But, AFAIK, it is only needed when you want to use a CGA video card.

Version 2

Version 2 has two additions, see the schematic:
- extra decoding
- buffers
Both additions are optional. But not implementing the extra decoding option means that the transistor Q1 stays.

Extra decoding
So far we needed both IO2 and IO3. IC3A, a 74LS139 demultiplexer, creates four 256 bytes ranges within the (in this case) IO2 area. One range is dedicated to the ISA bus, one to the 6522 and two are reserved for future use.
Not needing the second half of IC3 now, I use it to invert the Reset signal.

As said, version 1 only supports one slot. This can be changed by adding some buffers: IC4, a 74LS245, for the data bus and IC5/IC6, 74LS541s, for the address bus.

Version 3

This is the 16-bits version. IC7, a 74LS646, takes care of bits 8..15 of the ISA bus. To obtain the needed signals to control IC7, we need IC3B and an AND gate (IC8A). This means we need transistor Q1 back again for the Reset signal.
Having some 2 input AND gates left over, we can use two to generate the MEMx and SMEMx signals as mentioned in version 1.
IC10A, a 4 input AND gate, decodes the address lines A20..23 to make sure we can make use of the full 16 MB range.

Adress range
IC3A takes care of dividing IO2 (or IO3) in four parts:
- Y3 addresses the ISA slots.
- Y2 addresses the 6522.
- Reading Y1 gives you the data written by the ISA slot into the B register of the 646. Writing to Y1 has no effect.
- Writing to Y0 stores the data into the A register of the 646. The moment you write data to the ISA slot, the 646 will output this data to the data bits 8..15. Reading Y0 will erase the data.

Writing to or reading from the ISA slots
IC3B provides the needed signals for the 646 when we need to write to or read from the ISA slots. Y3 of IC3A and the R/W signal serve as main inputs. Phi2 is added to make sure that the timing is correct.
The moment data is read from the ISA slot, Y1 negates the CAB input of the 646. The rising edge clocks the data into the B register. The data is clocked during every read of the ISA bus, whether it is an 8-bits transfer or not. So it is upon the user/software to decide to read the B register or not.
The moment data is written to the ISA slot, the data in the A register is outputted to the data bits 8..15. This is done always, again whether it is an 8-bits transfer or not.

By now the function of the AND gate should be clear: it combines the signals coming from Y1/IC3B and Y2/IC3A.

Version 4

So far no use has been made of the interrupt lines of the ISA slots. Version 4 does.
The problem with these lines is that 1) they are active (H) and 2) they cannot by tied together as with the IRQ lines of the various 65xx ICs. One idea to solve this problem is using 8259 interrupt controllers. Having no experience with using and programming these ICs, I decided to skip this solution for the moment.
So I used a more understandable solution. As first step I inverted all IRQ signals by using 4069 CMOS inverters (IC 11 and IC12). IC13, a 74LS133 13 input NAND gate, combines the results of the inverters. A resistor and NPN transistor can now generate the needed IRQ signal.

When receiving an IRQ, the 6502 has to poll all possible IRQ source to find out which one generated it. By connecting the output to CA1 or CB1 of IC1, the 6522, we can simplify the proces because in this case the IRQ register tells us in one read whether the 6522 itself or the ISA slot was the source of the IRQ.

The next problem is to find out what ISA device caused the IRQ. And now we can run into trouble. The printer port can generate an interrupt but there is no mean to check this afterwards. The PC knows because the printe port activates either interupt 5 or 7. So I added another 6522 which only purpose is to find out what interrupt has been activated.

Version 5

Version 5 is the 8-bits version of Version 4. Not using all PB lines of the 6522 I decided to use them as inputs for reading the state of the individual IRQ lines. Together with the unused CAx and CB1 lines we can monitor up to seven IRQ lines.
As you can see I monitor the IRQ lines of the extended part of the bus as well. I have seen 8-bits cards that had a small PCB extension that enabled them to use these interrupts as well.

Which IRQ lines should be monitored?
Having eleven IRQ lines to monitor and only seven (six if you use A20 as well) inputs to monitor them, this means we have to make a choice. Please have a look at this tabel to see what device uses which interrupt. As you can see, some interrupts aren't dedicated at all and I wonder if we can or will use all those that are. Not knowing what cards you want to use, I leave the choice to you.
Just an idea: if you only need to monitor up to five lines, you can discard the transistor and connect the output of IC10 to CA1 (or CB1) and let the 6522 take care of generating the interrupt.

Version 6

I already mentioned using a 8259. Version 6 is version 5 but then using a 8259 to monitor the lines. IC3B is needed again; this time to generate the needed RD and WR signal for the 8259. IC3B is fed by Phi2, R/W and Y1 of IC3A. Y1 is used to select the 8259.
As you can see I connected Y0 of IC3A to the INTA input of the 8259. The 8259 can be polled to see what interrupt was activated. But this seems to be labourous process. By pulling INTA (L) the 8259 will place a vector in the form of two bytes on the bus. This vector can be used in combination with an indirect jump to execute the correct routine.

Version xE

'E' stands for Extended. The question: is there a possebility to free both IO2 and IO3? Yes, let's have a look at the memory map first:
  9000-93FF    36864-37887   IO0 :
  9000-900F    36864-36879   VIC chip
  9110-911F    37136-37151   6522 VIA#1
  9120-912F    37152-37167   6522 VIA#2
  9400-97FF    37888-38399   IO1 : COLOR RAM
  9800-9BFF    38912-39935   IO2
  9C00-9FFF    39936-40959   IO3
Adding a 74LS139 could do the trick. One half is used to divide Block 0 into four parts. The first part, 9000-90FF, is allocated to the VIC chip, the second part, 9100-91FF, to both the 6522's and the last two parts can be used for our own purposes.
No schematic.

Version PC

The idea is simple: use an old PC-XT or PC-AT (compatible) board instead of only using loose ISA slots. The problem: where should we connect the interface? This is something I have to work out yet. To be continued....

Version xU

'U' stands for Ultimate.
As you know the PC has a separate memory and I/O range. So far we changed the range by setting CB2. Copying data from ISA I/O to ISA memory will cost quite some time because 1) we have to set/reset CB2 before every load and store instruction and 2) we most probably have to set at least the address lines A8..10 every time as well. This idea makes use of both IO2 and IO3 and the idea mentioned in version xE:
- The 6522 and other I/O is controlled by the range we created in IO0. In this case I used an unconnected pin of the expansion port to transfer the generated signal from the VIC-20 to the board.
- BLK3 is used to address the memory range of the ISA board.
- IO2 is used to address the I/O range of the ISA board.

The disadavantage of using IO2 is clear IMHO. There isn't an immediate disadvantage of using BLK3. I positioned an 8-bits 64 KB static memory card in the range $F0000-$FFFFF. After a reset this RAM is automatically selected due to the uninitialized 6522. Having RAM connected to BLK1 and BLK2 as well, My VIC-20 sees the complete 32 KB memory range filled with RAM.

So what are the advantages?
The greatest advantage is the fact that IO2 covers the complete I/O range of a PC and therefore we only need one instruction to execute an I/O operation.
256 bytes is a nice window to exchange data using indexed and indirect instructions like LDA $1234,X and LDA ($12),Y, but is too small to run a decent program. 8 KB is a decent range.

Having questions or comment? You want more information?
You can email me here.