Files
open-roms/src/kernal/arnitech/arnitech_net.s
T
chris 05e4b67858 fix(arnitech): NET_SEND writes the chip's data port with plain stores
The copy loop wrote each byte with STA RRNET_RX_TX_DATA,X, and an indexed
store reads its address first. Reads of RxTxData take the bytes of a received
frame (AN181), so on a real CS8900A each byte sent took one of a frame the
program had started reading. The loop now stores to the port's low or high
byte by address, as ip65's and Contiki's drivers do; reads stay indexed, which
read once.
2026-10-18 10:04:40 +02:00

304 lines
5.9 KiB
ArmAsm

;; #LAYOUT# STD * #TAKE
;; #LAYOUT# * * #IGNORE
;
; The network entries of the Arnitech jump table (mc64 only, arnitech's ADR 0027): whole
; Ethernet frames through the CS8900A at the RR-Net socket, polled, from the Destination
; Address to the end of the data, without the CRC. The chip is found by its Product ID, so
; the routines find an RR-Net on any C64 that has one. Register semantics are the CS8900A
; datasheet's (Cirrus Logic DS271F5) and its 8-bit mode's (AN181).
;
; SAL holds the pointer to the frame or buffer, EAL the bytes left, as LOAD and SAVE use them.
;
!ifdef CONFIG_ARNITECH_CONTROLLER {
; PacketPage addresses, all but the Product ID's in page $01
CS_PRODUCT_ID = $630E ; at $0000, low byte first
CS_RX_CFG = $02 ; bit 6 Skip_1
CS_RX_CTL = $04
CS_LINE_CTL = $12
CS_SELF_CTL = $14 ; bit 6 RESET
CS_RX_EVENT = $24 ; bit 8 RxOK
CS_SELF_ST = $36 ; bit 7 INITD
CS_BUS_ST = $38 ; bit 7 TxBidErr, bit 8 Rdy4TxNOW
CS_IA = $58 ; Individual Address, $0158-$015D
CS_RX_CTL_VALUE = $0D05 ; RxOKA, IndividualA, BroadcastA
CS_LINE_VALUE = $00D3 ; SerRxON, SerTxON
CS_TX_AFTER_ALL = $C0 ; TxCMD: start once the whole frame is in the chip
NET_NONE_WAITING = $00
NET_NO_CARD = $01
NET_NO_ROOM = $02
NET_LENGTH_REFUSED = $03
NET_TOO_LONG = $04
;
; NET_INIT, $FF0C: see ff00.arnitech_jumptable.s
;
arnitech_net_init:
jsr arnitech_net_probe
bcs @2
lda #CS_SELF_CTL
jsr arnitech_net_point
lda #$40 ; RESET, which points the PacketPage pointer at $0000
sta RRNET_PP_DATA
lda #CS_SELF_ST
jsr arnitech_net_point
@1:
lda RRNET_PP_DATA
bpl @1 ; until INITD
+phy_trash_a
lda #CS_RX_CTL
ldx #<CS_RX_CTL_VALUE
ldy #>CS_RX_CTL_VALUE
jsr arnitech_net_write
lda #CS_LINE_CTL
ldx #<CS_LINE_VALUE
ldy #>CS_LINE_VALUE
jsr arnitech_net_write
+ply_trash_a
clc
@2:
rts
;
; NET_MAC, $FF0F: see ff00.arnitech_jumptable.s
;
arnitech_net_mac:
stx SAL+0
sty SAL+1
jsr arnitech_net_probe
bcs @2
ldy #$00
@1:
tya
ora #CS_IA ; $58, $5A, $5C
jsr arnitech_net_point
lda RRNET_PP_DATA+0
sta (SAL), y
iny
lda RRNET_PP_DATA+1
sta (SAL), y
iny
cpy #$06
bne @1
clc
@2:
rts
;
; NET_SEND, $FF12: see ff00.arnitech_jumptable.s
;
arnitech_net_send:
jsr arnitech_net_args
lda #NET_NO_CARD
bcs arnitech_net_done
lda #CS_TX_AFTER_ALL ; TxCMD, which the high byte's write gives the chip
sta RRNET_TX_CMD+0
lda #$00
sta RRNET_TX_CMD+1
lda EAL+0 ; TxLength: the bid, at the high byte's write
sta RRNET_TX_LENGTH+0
lda EAL+1
sta RRNET_TX_LENGTH+1
lda #CS_BUS_ST
jsr arnitech_net_point
lda RRNET_PP_DATA+0
bmi @1 ; TxBidErr
lda RRNET_PP_DATA+1
lsr ; Rdy4TxNOW into carry
lda #NET_NO_ROOM
bcc arnitech_net_fail
clv ; memory to chip
jmp arnitech_net_copy ; carry clear
@1:
lda #NET_LENGTH_REFUSED
; FALLTROUGH
arnitech_net_fail:
sec
; FALLTROUGH
arnitech_net_done:
rts
;
; NET_RECV, $FF15: see ff00.arnitech_jumptable.s
;
arnitech_net_recv:
jsr arnitech_net_args
lda #NET_NO_CARD
bcs arnitech_net_done
lda #CS_RX_EVENT
jsr arnitech_net_point
lda RRNET_PP_DATA+1 ; reading the event clears it
lsr ; RxOK into carry
lda #NET_NONE_WAITING
bcc arnitech_net_fail
lda RRNET_RX_TX_DATA+1 ; RxStatus, high byte first, not needed
lda RRNET_RX_TX_DATA+0
ldx RRNET_RX_TX_DATA+1 ; RxLength, high byte first
lda RRNET_RX_TX_DATA+0
cpx EAL+1
bne @1
cmp EAL+0
beq @2
@1:
bcs @3 ; longer than the buffer
@2:
sta EAL+0
stx EAL+1
pha
txa
pha
bit arnitech_net_copy_end ; an RTS, $60: sets V, chip to memory
jsr arnitech_net_copy
pla
tay
pla
tax
clc
rts
@3:
lda #CS_RX_CFG
jsr arnitech_net_point
lda RRNET_PP_DATA+0
ora #$40 ; Skip_1: the frame is dropped
sta RRNET_PP_DATA+0
lda #NET_TOO_LONG
bne arnitech_net_fail ; branch always
;
; The pointer from the zero page address in A into SAL, the length in X/Y into EAL, and the
; chip probed. Out: carry clear if it answers.
;
arnitech_net_args:
stx EAL+0
sty EAL+1
tax
lda $00, x
sta SAL+0
lda $01, x
sta SAL+1
; FALLTROUGH
;
; Whether the chip answers: its Product ID at PacketPage $0000. Out: carry clear if it does.
; X and Y are kept.
;
arnitech_net_probe:
lda #$00
sta RRNET_PP_POINTER+0
sta RRNET_PP_POINTER+1
lda RRNET_PP_DATA+0
cmp #<CS_PRODUCT_ID
bne @1
lda RRNET_PP_DATA+1
cmp #>CS_PRODUCT_ID
bne @1
clc
rts
@1:
sec
rts
;
; PacketPage register $01xx, xx in A, written with X (low byte) and Y (high byte)
;
arnitech_net_write:
jsr arnitech_net_point
stx RRNET_PP_DATA+0
sty RRNET_PP_DATA+1
rts
;
; The PacketPage pointer at $01xx, xx in A. X and Y are kept.
;
arnitech_net_point:
sta RRNET_PP_POINTER+0
lda #$01
sta RRNET_PP_POINTER+1
rts
;
; EAL bytes between the chip's receive and transmit data port and SAL: from the chip with V
; set, to it with V clear. Even bytes go through the port's low byte, odd ones through its
; high byte. Out: carry clear.
;
arnitech_net_copy:
ldy #$00
@1:
lda EAL+0
ora EAL+1
beq @4
tya
and #$01
tax
bvs @2
lda (SAL), y
cpx #$01 ; plain stores: an indexed one reads the port
beq @7 ; first, which takes a byte of a received frame
sta RRNET_RX_TX_DATA+0
bvc @3 ; branch always
@7:
sta RRNET_RX_TX_DATA+1
bvc @3 ; branch always
@2:
lda RRNET_RX_TX_DATA, x
sta (SAL), y
@3:
iny
bne @5
inc SAL+1
@5:
lda EAL+0
bne @6
dec EAL+1
@6:
dec EAL+0
jmp @1
@4:
clc
arnitech_net_copy_end:
rts
}