# ip65 technical reference

# File : drivers/cs8900a.s

     Ethernet driver for CS8900A chip (as used in RR-NET and Uthernet adapters)

     Based on Doc Bacardi's tftp source

## functions

function | description
--- | ---
eth_init |
    initialize the ethernet adaptor
    inputs: none
    outputs: carry flag is set if there was an error, clear otherwise
eth_rx |
    receive a packet
    inputs: none
    outputs:
     if there was an error receiving the packet (or no packet was ready) then carry flag is set
     if packet was received correctly then carry flag is clear,
     eth_inp contains the received packet,
     and eth_inp_len contains the length of the packet
eth_tx |
     send a packet
    inputs:
     eth_outp: packet to send
     eth_outp_len: length of packet to send
    outputs:
     if there was an error sending the packet then carry flag is set
     otherwise carry flag is cleared

## implementation

    ; Ethernet driver for CS8900A chip (as used in RR-NET and Uthernet adapters)
    ;
    ; Based on Doc Bacardi's tftp source

    .ifndef KPR_API_VERSION_NUMBER
      .define EQU     =
      .include "../inc/kipper_constants.i"
    .endif

    .include "../inc/common.i"
    .include "cs8900a.i"

      .export eth_init
      .export eth_rx
      .export eth_tx

      .import eth_inp
      .import eth_inp_len
      .import eth_outp
      .import eth_outp_len

      .importzp eth_dest
      .importzp eth_src
      .importzp eth_type
      .importzp eth_data

      .import cs_init
      .import cs_packet_page
      .import cs_packet_data
      .import cs_rxtx_data
      .import cs_tx_cmd
      .import cs_tx_len

      .import cfg_mac

      .import ip65_error

      .macro write_page page, value
      lda #page/2
      ldx #value
      jsr cs_write_page
      .endmacro

      .segment "IP65ZP" : zeropage

    eth_packet:  .res 2

      .code

    ;initialize the ethernet adaptor
    ;inputs: none
    ;outputs: carry flag is set if there was an error, clear otherwise
    eth_init:
      jsr cs_init

      lda #0      ; check magic signature
      jsr cs_read_page
      cpx #$0e
      bne @notfound
      cpy #$63
      bne @notfound

      lda #1
      jsr cs_read_page
      cpx #0
      bne @notfound
      ; y contains chip rev

      write_page pp_self_ctl, $0055  ; $0114, reset chip

      write_page pp_rx_ctl, $0d05  ; $0104, accept individual and broadcast packets

      lda #pp_ia/2      ; $0158, write mac address
      ldx cfg_mac
      ldy cfg_mac + 1
      jsr cs_write_page

      lda #pp_ia/2 + 1
      ldx cfg_mac + 2
      ldy cfg_mac + 3
      jsr cs_write_page

      lda #pp_ia/2 + 2
      ldx cfg_mac + 4
      ldy cfg_mac + 5
      jsr cs_write_page

      write_page pp_line_ctl, $00d3  ; $0112, enable rx and tx

      clc
      rts

    @notfound:
      sec
      rts

    ;receive a packet
    ;inputs: none
    ;outputs:
    ; if there was an error receiving the packet (or no packet was ready) then carry flag is set
    ; if packet was received correctly then carry flag is clear,
    ; eth_inp contains the received packet,
    ; and eth_inp_len contains the length of the packet
    eth_rx:
      lda #$24      ; check rx status
      sta cs_packet_page
      lda #$01
      sta cs_packet_page + 1

      lda cs_packet_data + 1
      and #$0d
      bne :+

      sec        ; no packet ready
      rts

    :  lda cs_rxtx_data + 1    ; ignore status
      lda cs_rxtx_data

      lda cs_rxtx_data + 1    ; read packet length
      sta eth_inp_len + 1
      tax        ; save
      lda cs_rxtx_data
      sta eth_inp_len

      lda #eth_inp
      sta eth_packet + 1

      ldy #0
      cpx #0        ; < 256 bytes left?
      beq @tail

    @get256:
      lda cs_rxtx_data
      sta (eth_packet),y
      iny
      lda cs_rxtx_data + 1
      sta (eth_packet),y
      iny
      bne @get256
      inc eth_packet + 1
      dex
      bne @get256

    @tail:
      lda eth_inp_len      ; bytes left / 2, round up
      lsr
      adc #0
      beq @done
      tax

    @get:
      lda cs_rxtx_data
      sta (eth_packet),y
      iny
      lda cs_rxtx_data + 1
      sta (eth_packet),y
      iny
      dex
      bne @get

    @done:
      clc
      rts

    ; send a packet
    ;inputs:
    ; eth_outp: packet to send
    ; eth_outp_len: length of packet to send
    ;outputs:
    ; if there was an error sending the packet then carry flag is set
    ; otherwise carry flag is cleared
    eth_tx:

      lda #$c9      ; ask for buffer space
      sta cs_tx_cmd
      lda #0
      sta cs_tx_cmd + 1

      lda eth_outp_len    ; set length
      sta cs_tx_len
      lda eth_outp_len + 1
      sta cs_tx_len + 1
      cmp #6
      bmi :+
      lda #KPR_ERROR_INPUT_TOO_LARGE
      sta ip65_error
      sec        ; oversized packet
      rts

    :  lda #pp_bus_status
      sta cs_packet_page + 1

    @waitspace:
      lda cs_packet_data + 1    ; wait for space
      ldx cs_packet_data
      lsr
      bcs @gotspace
      jsr @done      ; polling too fast doesn't work, delay added by David Schmidt
      jmp @waitspace
    @gotspace:
      ldax #eth_outp      ; send packet
      stax eth_packet

      ldy #0
      ldx eth_outp_len + 1
      beq @tail

    @send256:
      lda (eth_packet),y
      sta cs_rxtx_data
      iny
      lda (eth_packet),y
      sta cs_rxtx_data + 1
      iny
      bne @send256
      inc eth_packet + 1
      dex
      bne @send256

    @tail:
      ldx eth_outp_len
      beq @done

    @send:
      lda (eth_packet),y
      sta cs_rxtx_data
      dex
      beq @done
      iny
      lda (eth_packet),y
      sta cs_rxtx_data + 1
      iny
      dex
      bne @send

    @done:          ; also used by timeout code above
      clc
      rts

    ; read X/Y from page A * 2
    cs_read_page:
      asl
      sta cs_packet_page
      lda #0
      rol
      sta cs_packet_page + 1
      ldx cs_packet_data
      ldy cs_packet_data + 1
      rts

    ; write X/Y to page A * 2
    cs_write_page:
      asl
      sta cs_packet_page
      lda #0
      rol
      sta cs_packet_page + 1
      stx cs_packet_data
      sty cs_packet_data + 1
      rts

    ;-- LICENSE FOR cs8900a.s --
    ; The contents of this file are subject to the Mozilla Public License
    ; Version 1.1 (the "License"); you may not use this file except in
    ; compliance with the License. You may obtain a copy of the License at
    ; http://www.mozilla.org/MPL/
    ;
    ; Software distributed under the License is distributed on an "AS IS"
    ; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
    ; License for the specific language governing rights and limitations
    ; under the License.
    ;
    ; The Original Code is ip65.
    ;
    ; The Initial Developer of the Original Code is Per Olofsson,
    ; MagerValp@gmail.com.
    ; Portions created by the Initial Developer are Copyright (C) 2009
    ; Per Olofsson. All Rights Reserved.
    ; -- LICENSE END --