The ethernet adapter (I'll call it etha from now on) is plugged into the clock port of the retro replay (rr). The registers are mapped in from $de02 to $de10, but only if bit #0 in $de01 is set.
Table 1-1. a short description of $de01
Bit | read | write |
---|---|---|
0 | Flashmode jumper | enable clockport |
1 | allowBank | |
2 | freeze button pressed | disable freeze |
3 | banking bit 13 | |
4 | banking bit 14 | |
5 | banking bit 16 | |
6 | REU compatibility | |
7 | banking bit 15 |
The banking address in bits 3, 4, 5 and 7 is important and should not
be modified without purpose.
Bit 1,2 and 6 can only be set once after a reset. For write access it's
a nice idea to set them to 0.
This little routine maps the etha in:
lda $de01 and #%10111000 ora #%00000001 sta $de01 |
Now the etha is mapped into the c64's memory. Or something else which is connected to the clock port, like a silver surfer. The only way to find out for sure is a detection routine which looks for the etha, or better the used chip, a CS8900.
The CS8900 has 8 registers, each 16 bits wide. They are mapped into the c64 memory from $de00 - $de10. Unfortunately the rr uses the same location for the 2 controll registers at $de00 and $de01. This means both locations are lost for the clock port. Here's the chip's register map:
Table 3-1. CS8900 registers (chip order)
Register | Description | |
---|---|---|
$de00/1 | Receive/Transmit Data (Port0) | *LOST* |
$de02/3 | Receive/Transmit Data (Port1) | |
$de04/5 | Transmit Command | |
$de06/7 | Transmit Length | |
$de08/9 | Interrupt Status | |
$de0a/b | PacketPage Pointer | |
$de0c/d | PacketPage Data (Port0) | |
$de0e/f | PacketPage Data (Port1) |
The lost register is the "Receive/Transmit Data (Port0)". It is quite useful for efficient operation. A very pointless register is the "Interrupt Status" at $de08. The CS8900 simply supports no interrupts in it's 8 bit mode. So the idea is to swap the registers from $de00-$de07 with $de08-$de0f:
Table 3-2. CS8900 registers (swapped)
Register | Description | |
---|---|---|
$de00/1 | Interrupt Status | *LOST* |
$de02/3 | PacketPage Pointer | |
$de04/5 | PacketPage Data (Port0) | |
$de06/7 | PacketPage Data (Port1) | |
$de08/9 | Receive/Transmit Data (Port0) | |
$de0a/b | Receive/Transmit Data (Port1) | |
$de0c/d | Transmit Command | |
$de0e/f | Transmit Length |
Now the useless "Interrupt Status" is lost. For the other registers I will use some shorter labels from now on:
CS_PacketPage = $de02 CS_PacketData0 = $de04 CS_PacketData1 = $de06 CS_RxTxPort0 = $de08 CS_RxTxPort1 = $de0a CS_TxCmd = $de0c CS_TxLength = $de0e |
The first 3 registers deal with a so called "Packet Page". They are used to access the internal ram and configuration registers. The "packet page" technique is very similar to the C128's $d800 registers which access the VDC.
Write the address to write to or read from to the CS_PacketPage register. Now the CS_PacketData0 and CS_PacketData1 register are like a window to this selected address. It can be read or modified with the CS_PacketData registers.
Example: I want to read register #4 of the internal ram.
lda #4 sta CS_PacketPage lda #0 sta CS_PacketPage+1 ldx CS_PacketData0 ldy CS_PacketData0+1 |
lda #4 sta CS_PacketPage lda #0 sta CS_PacketPage+1 lda #$12 sta CS_PacketData0 lda #$34 sta CS_PacketData0+1 |
This looks quite slow and unefficient (and it really is), but fortunately there is a much faster way to read and write data for ethernet packets (later more).
The Packet Page contains information and configuration registers. All registers are 16 bits wide and start at an even address. This can be useful for a routine to read or write to the packet page.
Here are two little demo routines:
cs_readPage: asl sta CS_PacketPage lda #0 rol sta CS_PacketPage+1 ldx CS_PacketData0 ldy CS_PacketData0+1 rts |
Description: | read a packet page register |
Parameter: | Akku: number of the register divided by 2 |
Return: | value of the register in X (lo) and Y (hi) |
cs_writePage: asl sta CS_PacketPage lda #0 rol sta CS_PacketPage+1 stx CS_PacketData0 sty CS_PacketData0+1 rts |
Description: | write to a packet page register |
Parameter: | Akku: number of the register divided by 2 value of the register in X (lo) and Y (hi) |
Return: | nothing |
Read only, Packet Page $000
The ID Code can be used to identify a CS8900A chip and it's revision.
The value is: 0000 1110 0110 0011 0000 0000 000X XXXX
with X XXX as:
Read / Write, Packet Page $102
RxCFG determines how frames will be transfered and which frames will cause interrupts.
000011 | internal address of the register |
Skip_1 | When set, this bit causes the last received frame to be deleted from the receive buffer. After the frame is deleted, the bit is cleared again. |
StreamE | Enable StreamTransfer. As StreamTransfer needs DMA it is of no use for etha |
RxOKiE | Enable Interrupt to indicate a received frame. As IRQs are not possible with etha this is of no use |
RxDMAOnly | Use DMA to transfer all received frames to the host. As DMA is not possible with etha this is of no use |
AutoRxDMAE | Enable DMA to transfer data to Host when some conditions are met. As DMA is not possible with etha this is of no use |
BufferCRC | Set this bit to include the received CRC with the data stored in the receive buffer. The four CRC bytes are included in the receive-frame length. |
CRCError_iE | Enable Interrupt to indicate a received frame with a bad CRC. As IRQs are not possible with etha this is useless. |
Runt_iE | Enable Interrupt to indicate a received frame of less than 64 bytes. As IRQs are not possible with etha this is useless. |
Extradata_iE | Enable Interrupt to indicate a received frame with more than 1518 bytes. As IRQs are not possible with etha this is useless. |
Read only, Packet Page $124
If Bits 8 and 9 are both set, this register has an alternate meaning for the bits A-F:
000100 | internal address of the register |
IAHash | If the received address is accepted by the hash filter this bit is set. |
DribbleBits | This bit is set if the received frame is followed by 1 to 7 bits. An "alignment error" occurs if Dribblebits and CRCError are both set. |
RxOK | Set if the received frame has a good CRC and a valid length (i.e. no CRCError, no RuntError, no ExtraDataError). If this bit is set, the framelength is contained at PacketPage $0402. |
Read/Write, Packet Page $104
RxCTL defines which frames are accepted.
000101 | internal address of the register |
IAHashA | Accept frames with an individual address which passes the hash filter. |
PromiscousA | if set, frames with any address are accepted. |
RxOKA | Accept frames with a correct CRC and valid length (>=64 and <=1518) |
MulticastA | Accept multicast frames if their destination address passes the hash filter. |
IndividualA | Accept frames if their destination address match the configured individual address (see register $158). |
BroadcastA | Accept broadcast frames |
CRCErrorA | Accept frames with a bad crc. |
RuntA | Accept frames which are too small (<64 bytes) |
ExtradataA | Accept frames which are too long (>1518 bytes). Even though the frames are accepted only the first 1518 bytes are copied to the internal buffer. The rest is ignored. |
Bits 8,C,D and E specify the accepted frame type. Bits 6,7,9,A and B specify the accepted addresses. Note that a frame must pass both the type and the address filter to be accepted.
Most specs were copied from the crystal docs. The few sources are written by me, Doc Bacardi/The Dreams.
If you found some of the bugs or typos, have better information or whatever, then just give me a mail: <DocBacardi@freenet.de>