Programming the User Port

Started by Mangelore, January 16, 2008, 09:08 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Mangelore

Hi guys,

I'm trying to figure out a way to interface a network adapter to the user port. My idea was to use the PB0-PB7 as a multiplexed Data/Address bus and PA2 as a R/W line. However, I need a few more lines to control the multiplexed bus. How easy is it to control SP1, SP2, PC2 and FLAG pins via software?

Cheers
Fotios

BigDumbDinosaur

Quote from: Mangelore on January 16, 2008, 09:08 AMHi guys,

I'm trying to figure out a way to interface a network adapter to the user port.  My idea was to use the PB0-PB7 as a multiplexed Data/Address bus and PA2 as a R/W line.  However, I need a few more lines to control the multiplexed bus. How easy is it to control SP1, SP2, PC2 and FLAG pins via software?

Cheers
Fotios

Actually, you haven't provided enough detail about your network adapter (aka network interface controller or NIC) to make a definitive answer possible.  So, I'll toss out a few bones and you chew on them and see if they taste good.

Use of PB0-7 for data and control/command/register select transfers is practical, since that is an eight bit, bi-directional interface.  On the other hand, the SP lines are probably useless for what you are trying to do, as they process serialized data via synchronous handshakes, one bit per handshake.  There probably isn't a suitable clock source on your NIC to handshake back, which is required for inbound transfer.  Also, the theoretical bit transfer rate via the CIA shift register is Ø2/4, where Ø2 is the I/O clock rate (approximately 1 MHz).  Therefore, you will never exceed 32 KB/sec transfer rate under any conditions.  Obviously, you can theoretically close in on 1 MB/sec using PB0-7 to pass bytes.

Regarding handshaking, your options are PC and *FLAG.  PC will go low for one Ø2 cycle when a read or write occurs on PB0-7.  Therefore, you can tell the NIC that you have written to it by having the NIC hardware watch for a toggle on PC.  That said, the toggle occurs simultaneously with the write, so the NIC's detection hardware has to have almost no latency.  Otherwise, you will drop bytes.

Since PC toggles when a read is performed on PB0-7, the NIC hardware could watch for that as well to determine when the computer has picked up an inbound byte.

To have the NIC tell the computer that inbound data is available, you'd use *FLAG.  *FLAG is wired to bit 4 in the ICR of CIA #2 and therefore can generate an NMI to get the computer's attention.  In your NIC hardware, you would have to hold *FLAG high with a 1K, 1/4 watt pullup resistor (driven from 5 volts) and arrange the circuit to pull *FLAG low for a couple of Ø2 clocks (at least two clocks recommended) when the NIC has something to say.  Toggling *FLAG will set bits 4 and 7 in the CIA's ICR, telling you the NIC wants attention:


       lda d2icr             ;read & clear interrupt control
       bpl nonmi             ;not a CIA NMI, must be the RESTORE key
;
       sta icrtmp            ;preserve D2ICR for later testing testing
       and #%00010000        ;mask all but *FLAG
       bne isflag            ;this was a *FLAG interrupt
;
       lda icrtmp            ;recover original ICR value &...
       jmp contin            ;process other NMI
;
isflag ...NIC has called -- do something about it...
...etc...


You can wedge the above into the start of the NMI handler and jump to the standard C-128 NMI code if a *FLAG NMI did not occur.  Note that testing D2ICR automatically clears the interrupt.  Therefore, you should not use BIT to test the ICR unless you don't care about any other interrupt source.

The only other really useful line is PA2, which can be used to tell the NIC if the byte on PB0-7 is data or command/control.  You could MUX a register bit pattern on PB0-7 if the number of registers requires no more than 4-5 bits and use bit patterns on 6 and 7 to tell the NIC the intention of the register bit pattern -- there are four possible combinations there.

Again, you really haven't given enough information about the NIC for me to suggest much more.  Also, I suspect that this project would be less complicated working through the expansion port, where R/W, IRQ, NMI, all the data and address bus lines, as well as clocks, are present.
x86?  We ain't got no x86.  We don't need no stinking x86!

Mangelore

Quote from: BigDumbDinosaur
Actually, you haven't provided enough detail about your network adapter (aka network interface controller or NIC) to make a definitive answer possible. So, I'll toss out a few bones and you chew on them and see if they taste good.

Sorry about that. The idea is to use a CS8900A similar to The Final Ethernet (TFE)
http://dunkels.com/adam/tfe/hardware.html
and RR-NET
http://www.schoenfeld.de/inside/Inside_RRnet.txt

When the CS8900A is used in 8-bit IO mode we need 8 data lines, 4 address lines and a R/W line.

Quote from: BigDumbDinosaur
Since PC toggles when a read is performed on PB0-7, the NIC hardware could watch for that as well to determine when the computer has picked up an inbound byte.

To have the NIC tell the computer that inbound data is available, you'd use *FLAG.
...
...
...
The only other really useful line is PA2, which can be used to tell the NIC if the byte on PB0-7 is data or command/control.  You could MUX a register bit pattern on PB0-7 if the number of registers requires no more than 4-5 bits and use bit patterns on 6 and 7 to tell the NIC the intention of the register bit pattern -- there are four possible combinations there.

Thanks for the above tips to chew on :-)

Quote from: BigDumbDinosaur
Also, I suspect that this project would be less complicated working through the expansion port, where R/W, IRQ, NMI, all the data and address bus lines, as well as clocks, are present.

Yes, it's been done before for the expansion port. I used an Olimex cs8900a-h header board for the FB-NET
www.c64net.com/fotios/fbnet.php
but it would be nice to have something similar for the user port.

BigDumbDinosaur

Quote from: Mangelore on January 16, 2008, 06:30 PM
Quote from: BigDumbDinosaur
Actually, you haven't provided enough detail about your network adapter (aka network interface controller or NIC) to make a definitive answer possible. So, I'll toss out a few bones and you chew on them and see if they taste good.

Sorry about that. The idea is to use a CS8900A similar to The Final Ethernet (TFE)
http://dunkels.com/adam/tfe/hardware.html
and RR-NET
http://www.schoenfeld.de/inside/Inside_RRnet.txt

When the CS8900A is used in 8-bit IO mode we need 8 data lines, 4 address lines and a R/W line.

Quote from: BigDumbDinosaur
Since PC toggles when a read is performed on PB0-7, the NIC hardware could watch for that as well to determine when the computer has picked up an inbound byte.

To have the NIC tell the computer that inbound data is available, you'd use *FLAG.
...
...
...
The only other really useful line is PA2, which can be used to tell the NIC if the byte on PB0-7 is data or command/control.  You could MUX a register bit pattern on PB0-7 if the number of registers requires no more than 4-5 bits and use bit patterns on 6 and 7 to tell the NIC the intention of the register bit pattern -- there are four possible combinations there.

Thanks for the above tips to chew on :-)

Quote from: BigDumbDinosaur
Also, I suspect that this project would be less complicated working through the expansion port, where R/W, IRQ, NMI, all the data and address bus lines, as well as clocks, are present.

Yes, it's been done before for the expansion port. I used an Olimex cs8900a-h header board for the FB-NET
www.c64net.com/fotios/fbnet.php
but it would be nice to have something similar for the user port.
PB0-7 will work for both data and control.  The trick is to be able to tell the NIC which way you are going.  Here's how I might do it.

Make PA2 act as the data/control flag.  If deasserted (low), the NIC should assume that data is being passed through PB0-7.  If PA2 is asserted, the NIC should assume that control/setup information is being passed through PB0-7.

Therefore, to set the NIC in data mode, read or write PB0-7 with PA2 low.  Your NIC would see that as a write to a register, e.g., to put a byte on the network, or a read from a register, e.g., get a byte off the network.  Naturally, to process data destined to or coming from the network, you will need a pair of FIFOs somewhere in RAM.  An Ethernet frame size is slightly less that 1.5 K, so you need to allocate six pages of RAM for each FIFO to collect a maximum-sized frame, a total of 3072 bytes for FIFOs.  You'll also need two sets of head/tail pointers per FIFO, a total of eight zero page locations (steal them from the RS-232/tape area in kernal zero page).

Now for the fun!  To put the NIC into control mode, read or write PB0-7 with PA2 asserted.  Now, the CIA, of course, knows the data direction, since you have to define that in the data direction register (PA2 can always be set as output).  However, the NIC will have to be told both the data direction and the register to which the next read or write is to be directed.  So, here's how I'd do it:

1) Assert PA2, indicating control mode to the NIC.  Wait at least one Ø2 cycle before proceeding to allow some deskew to occur in the NIC hardware (see the NIC hardware's timing info for the recommended setup times).  Succinctly stated, the NIC has to know if the next byte on PB0-7 is data or control before that byte is made available.  A single NOP should suffice, even in 2 MHz mode.

2) Place the target register address in bits 0-3, which would directly correspond to whatever chip select functions are used to select a register (I assume there's a decoder on the NIC board).  Also, set bit 7 to indicate that the next R/W operation will be a write operation, or clear bit 7 to indicate that it will be a read.

3) Write the value worked out in step 2 to PB0-7.  The write will toggle PC, telling the NIC that data has arrived.  Your NIC hardware will have to latch all bits, since the next step will change the bit pattern on PB0-7.  With the control bits latched, do a register select based on the bit 0-3 pattern.  After the NIC hardware has processed the control byte, toggle *FLAG.  The computer, meanwhile can do something else until the *FLAG NMI arrives

4) After the *FLAG interrupt is received, deassert PA2.  Follwing the deassertion of PA2, write your data to PB0-7 if steps 2 and 3 were a write-to-NIC setup, or read PB0-7 if steps 2 and 3 were a read-from-NIC setup.   Again, the NIC will see PC toggle as you read/write PB0-7 and do whatever has to be done in response.  Once the NIC has read or written PB0-7, toggle *FLAG.  Again, the computer can go off and do something else until the *FLAG NMI occurs.

5) When the *FLAG interrupt occurs, the NIC has completed the previous operation and is ready for another.  If more network processing is required (e.g., the send FIFO is not empty), go back to step 1 and start over.  Otherwise, set a flag somewhere to indicate that the NIC is idle and exit your NIC interrupt handler.

PA2 could be used for bi-directional control, as it can be read and the NIC can drive it low, even though it has been set hgh and as an outputi in the CIA.  Obviously, this is a fairly complicated control scheme, as you don't have all the facilities of the expansion port.  If it were me, I would not use the user port for this application.  It won't run very fast and there may be some unexpected hardware conditions that could cause your interrupt handler to go belly up on you.

Speaking of interrupts, don't forget that CIA #2, which controls the user port, is wired to NMI, so any interrupt processing must be done by redirecting the C-128's NMINV vector at $0318 to your NMI handler, followed by a jump to the regular NMI handler.  ALso, you *MUST* analyze the CIA's ICR value when an NMI occurs to determine that it was your NIC (look at bit 4) that caused it.  You shouldn't blindly assume that the NIC is the only possible NMI source, as doing to could result in a spurious interrupt processing situation that might break something else in the system.  Don't forget that RESTORE also generates an NMI.
x86?  We ain't got no x86.  We don't need no stinking x86!

Mangelore

Thanks for the suggestions.

Quote from: BigDumbDinosaurObviously, this is a fairly complicated control scheme, as you don't have all the facilities of the expansion port.  If it were me, I would not use the user port for this application.  It won't run very fast and there may be some unexpected hardware conditions that could cause your interrupt handler to go belly up on you.

Yeah, it seems more trouble than it's worth.
Cheers
Fotios