feat(arnitech): network entries NET_INIT, NET_MAC, NET_SEND, NET_RECV at $FF0C-$FF15

Version 2 of the Arnitech jump table, with 6 entries: whole Ethernet frames
through the CS8900A at the RR-Net socket (arnitech's ADR 0027), found by its
Product ID and polled, from the CS8900A datasheet's PacketPage registers and
its 8-bit mode. NET_INIT resets the chip and turns on receiving its own and
broadcast frames and sending; NET_MAC copies the Individual Address; NET_SEND
bids and writes a frame; NET_RECV copies the oldest frame received, or drops
one longer than the buffer with Skip_1. Carry is the result, with an error
code in A, and the pointer and count go in SAL and EAL.
This commit is contained in:
chris committed 2026-10-18 07:36:43 +02:00
1 parent aa39286d9d
commit 1aaed55bc7
3 files changed
+347 -4

No files matched your search

+9
View File
@@ -23,4 +23,13 @@
!addr ARNITECH_CLOCK_HRS = $DE94 ; hours, BCD 1-12, bit 7 PM
!addr ARNITECH_CARD_WINDOW = $DEA0 ; slot n's Card window at $DEA0 + 16 * n
; The RR-Net socket: the CS8900A of the Network Card in the lowest slot, in RR-Net order
; (arnitech's ADR 0027; Cirrus Logic DS271F5 Table 18, each port's even byte the low one)
!addr RRNET_PP_POINTER = $DE02 ; PacketPage pointer
!addr RRNET_PP_DATA = $DE04 ; PacketPage data port 0
!addr RRNET_RX_TX_DATA = $DE08 ; receive and transmit data port 0
!addr RRNET_TX_CMD = $DE0C ; write-only
!addr RRNET_TX_LENGTH = $DE0E ; write-only
}
+298
View File
@@ -0,0 +1,298 @@
;; #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
sta RRNET_RX_TX_DATA, x
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
}
+40 -4
View File
@@ -9,11 +9,12 @@
; stay clear, for the stock IRQ entry, CINT, and the KERNAL revision byte.
;
; $FF00-$FF03 "ARNI"
; $FF04 version of the table, $01
; $FF04 version of the table, $02
; $FF05 number of entries
;
; $FF06 ARNI_FINDCARD - finds the first Card slot holding a Card of a given type
; In: A = the Card's type ($01 Redstone Card, $02 Internet Card; $00 finds an empty slot)
; In: A = the Card's type ($01 Redstone Card, $02 Internet Card, $03 Network Card;
; $00 finds an empty slot)
; Out: carry clear if found: A = the slot (0-5), X = the low byte of its Card window
; ($DEA0 + 16 * slot, so LDA $DE00,X reads the window's first byte);
; carry set if no slot holds one, or no controller answers (a Cartridge switched it off)
@@ -26,15 +27,50 @@
; untouched but on 50 Hz all the same
; A and X are not kept, Y is
;
; Version 2 adds the network: whole Ethernet frames, from the Destination Address to the end of
; the data without the CRC, through the CS8900A at the RR-Net socket (arnitech's ADR 0027),
; found by its Product ID. Software polls; ARP and IP are its own.
;
; $FF0C NET_INIT - resets the chip and sets it to receive frames for its own address and
; broadcasts, and to send
; In: nothing
; Out: carry clear if done; carry set if there is no Network Card
; A and X are not kept, Y is
;
; $FF0F NET_MAC - copies the MAC address: the chip's Individual Address, which a reset sets to
; the Network Card's
; In: X/Y = the address of 6 bytes for it, low byte in X
; Out: carry clear if copied; carry set if there is no Network Card
; A, X, and Y are not kept
;
; $FF12 NET_SEND - sends a frame
; In: A = a zero page address holding a pointer to the frame,
; X/Y = its length, 14-1514, low byte in X; the chip pads one under 60 bytes
; Out: carry clear if sent; carry set if not, with A = 1 no Network Card, 2 no room in
; the chip while it holds frames received, 3 the chip refuses the length
; A, X, and Y are not kept
;
; $FF15 NET_RECV - takes the oldest frame received
; In: A = a zero page address holding a pointer to a buffer,
; X/Y = its length, low byte in X
; Out: carry clear if a frame was copied into the buffer, with X/Y = its length, low byte
; in X; carry set if not, with A = 0 none waiting, 1 no Network Card, 4 the frame is
; longer than the buffer, and is dropped
; A is not kept when a frame is copied
;
!ifdef CONFIG_ARNITECH_CONTROLLER {
arnitech_jumptable:
!byte $41, $52, $4E, $49 ; "ARNI"
!byte $01 ; version
!byte $02 ; entries
!byte $02 ; version
!byte $06 ; entries
jmp arnitech_find_card ; $FF06
jmp arnitech_set_tod ; $FF09
jmp arnitech_net_init ; $FF0C
jmp arnitech_net_mac ; $FF0F
jmp arnitech_net_send ; $FF12
jmp arnitech_net_recv ; $FF15
}