; Simple ethernet programme loader for C65GS. ; Reads and checks packets, and then runs code contained in the packets. ; This keeps the programme VERY small. ; Now supports ARP replies to make life easier. .alias BUFFER $6800 .alias ETHER_FRAME_START BUFFER .alias ETHER_FRAME_DEST_MAC ETHER_FRAME_START + $00 .alias ETHER_FRAME_SRC_MAC ETHER_FRAME_START + $06 .alias ETHER_FRAME_TYPE ETHER_FRAME_START + $0C .alias ARP_PACKAGE_START ETHER_FRAME_START + $0E .alias ARP_PACKAGE_HTYPE ARP_PACKAGE_START + $00 .alias ARP_PACKAGE_PTYPE ARP_PACKAGE_START + $02 .alias ARP_PACKAGE_HLEN ARP_PACKAGE_START + $04 .alias ARP_PACKAGE_PLEN ARP_PACKAGE_START + $05 .alias ARP_PACKAGE_OPER ARP_PACKAGE_START + $06 .alias ARP_PACKAGE_SHA ARP_PACKAGE_START + $08 .alias ARP_PACKAGE_SPA ARP_PACKAGE_START + $0E .alias ARP_PACKAGE_THA ARP_PACKAGE_START + $12 .alias ARP_PACKAGE_TPA ARP_PACKAGE_START + $18 .alias ARP_PACKAGE_END ETHER_FRAME_START + $1C .alias ARP_OPER_REQUEST 1 .alias ARP_OPER_REPLY 2 ; make it start with SYS53000 .word 50000 ; $CF08 .org 50000 ; $CF08 .scope programentrypoint: ; C65GS io lda #$47 sta $d02f lda #$53 sta $D02f ; Map ethernet registers at $6000 - $7FFF ; Ethernet controller really lives $FFDE000 - $FFDEFFF, so select $FF megabyte section for MAP LO lda #$ff ldx #$0f ldy #$00 ldz #$00 map eom ; now enable mapping of $DE000-$DFFFF at $6000 ; MAPs are offset based, so we need to subtract $6000 from the target address ; $DE000 - $6000 = $D8000 lda #$80 ldx #$8d ldy #$00 ldz #$00 map eom ; Ethernet registers should now be visible from $6000 - $6FFF ; read buffer will be at $6800 - $6FFF ; length of frame is in $6FFE / $6FFF in little-endian byte order ; so LDA $6FFE ; LDX $6FFF ; jsr $BDCD should print packet length to screen ; make sure ethernet transceiver is on and not generating IRQs ; (we will poll it). ; also make sure that we acknowledge the last received packet so that the ; ethernet controller knows it can receive. lda $d6e1 lsr and #$02 ora #$01 sta $d6e1 loop: waitingforpacket: lda $d6e1 and #$20 beq waitingforpacket ; clear eth RX signal, and leave ethernet tranceiver on ; and make last used RX buffer visible lda $d6e1 and #$04 lsr ora #$01 sta $d6e1 ; Got a packet. ; check whether it is UDP port 4510 ; or whether it is an ARP request ; Here we want to check that $680E - $6817 = ; 08 06 00 01 08 00 06 04 00 01 ldx #$09 arploop0: lda $680e,x cmp arptemplate,x bne notarp dex bpl arploop0 ; check that IP address asked for ends in .65 lda $682b cmp #65 bne notarp ldx #$05 arploop1: lda 2+ETHER_FRAME_SRC_MAC,x sta ETHER_FRAME_DEST_MAC,x lda 2+ARP_PACKAGE_SHA,x sta ARP_PACKAGE_THA,x lda #$40 ; this should be loading a real mac address sta ETHER_FRAME_SRC_MAC,x sta ARP_PACKAGE_SHA,x dex bpl arploop1 ldx #$09 arploop2: lda arptemplate,x sta ETHER_FRAME_TYPE,x dex bpl arploop2 lda #$02 sta ARP_PACKAGE_OPER+1 ldx #$03 arploop3: lda 2+ARP_PACKAGE_SPA,x sta ARP_PACKAGE_TPA,x lda 2+ARP_PACKAGE_TPA,x sta ARP_PACKAGE_SPA,x dex bpl arploop3 ; packet should now all be ready - hit TX button lda #$01 sta $d6e4 notarp: ; is it IPv4? lda $6810 cmp #$45 bne waitingforpacket ; is it UDP? lda $6819 cmp #$11 bne waitingforpacket ; UDP port #4510 lda $6826 cmp #>4510 bne waitingforpacket lda $6827 cmp #<4510 bne waitingforpacket ; packet body begins at $0444 / $682C. ; if it begins with $A9 = LDA immediate, then jsr to the packet body. ; packet body can do whatever is required to load data, keeping this ; programme very simple. lda $682c cmp #$a9 bne loop jsr $682C jmp loop arptemplate: .byte $08,$06,$00,$01,$08,$00,$06,$04,$00,$01 .checkpc $CFFF .scend .outfile "etherload.prg"