IP
[fpgaboy.git] / ethernet.asm
index 4bcee82..8fb4fed 100644 (file)
@@ -1,35 +1,10 @@
+       INCLUDE "serial.inc"
+
 ETH_STATUS EQU $FF68
 ETH_DATA EQU $FF69
+ARP_ENTRIES EQU 6
+ARP_ENTRY_SIZE EQU 13
 
-PUTC: MACRO
-       ld a, \1
-       call putc
-       ENDM
-
-PUTS: MACRO
-       ld hl, \1
-       call puts
-       ENDM
-
-PUTSI: MACRO
-       push hl
-       call putsi
-       db \1, 0
-       pop hl
-       ENDM
-
-PUTSIL: MACRO
-       push hl
-       call putsi
-       db \1, 13, 10, 0
-       pop hl
-       ENDM
-
-PUTHEX: MACRO
-       ld a, \1
-       call puthex
-       ENDM
-       
        SECTION "config", HOME[$0]
 myMAC: db $12, $34, $56, $78, $9A, $00
 myIP:  db $0A, $00, $00, $02
@@ -58,22 +33,35 @@ myGW:       db $0A, $00, $00, $01
 
 start:
        ld sp, $D800
+       call zerobss
        PUTSIL "Ethernet test ROM"
-.lp:   xor a                   ; Rest state machines
+.lp:   xor a                   ; Reset state machines
        ld [ETH_STATUS], a
-       ld a, [ETH_STATUS]      ; New shit?
+       ld a, [ETH_STATUS]      ; Load current status
        ld [$FF51], a
        and $02         ; New packet?
        call nz, getpacket
        jr .lp
 
+zerobss:
+       ld hl, bssstart
+       ld bc, bssend - bssstart
+.lp:   ld a, b
+       or c
+       ret z
+       dec bc
+       xor a
+       ld [hli], a
+       ld a, h
+       jr .lp
+
 getpacket:
        ld a, [ETH_DATA]
        ld b, a
        ld a, [ETH_DATA]
        ld c, a
        push bc
-       ld hl, $D000
+       ld hl, packet
 .cplp: ld a, b
        or c
        jr z, .done
@@ -86,7 +74,7 @@ getpacket:
        PUTHEX b
        PUTHEX c
        PUTSIL " byte packet from hardware."
-       ld hl, $D000
+       ld hl, packet
        call ether_input
        ret
 
@@ -133,82 +121,307 @@ ether_input:
        inc hl
        dec c
        jr nz, .maclp
-       PUTSIL "ether_input: It's to us!"
+       ; Done? Then it was to us!
+       jr .us
+.notus:        ; Was it to broadcast?
        pop hl
-       
-       ret
-.notus:        PUTSIL "ether_input: Not to us..."
+       push hl
+       ld c, $06
+.bclp: ld a, [hli]
+       cp $FF
+       jr nz, .notbc
+       dec c
+       jr nz, .bclp
+
+.us:   PUTSIL "ether_input: It's to us!"
+       ; Which protocol does it belong to?
        pop hl
-       ret
+       ld b, $00
+       ld c, 12
+       add hl, bc      ; Skip source and dest MAC.
+       ld a, [hli]
+       cp $08
+       jr nz, .unknownproto
+       ld a, [hli]
+       cp $06
+       jr z, .arp
+       cp $00
+       jp z, .ip
+       jr .unknownproto
 
-; SERIAL ROUTINES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+.notbc:        pop hl
+       PUTSIL "ether_input: Not addressed to us and not broadcast."
+       ret
+       
+.unknownproto:
+       PUTSIL "ether_input: Unknown protocol; dropping"
+       ret
 
-putc:
-       push af
-.waitport:
-       ld a,[$FF53]
-       and $01
-       jr nz,.waitport
-       pop af
-       ld [$FF52],a
+.arp:
+       PUTSIL "ether_input: ARP packet"
+       call arp_input
+       ret
+.ip:
+       PUTSIL "ether_input: IP packet"
+       call ip_input
        ret
 
-puts:
+arp_input:
+       ; First, verify that this is an ARP packet that we can handle.
+       ld c, 7
+       ld de, .expectedarp
+.cklp: xor a
+       cp c
+       jr z, .ckdone
+       ld a, [de]
+       cp [hl]
+       jr nz, .badarp
+       inc de
+       inc hl
+       dec c
+       jr .cklp
+.ckdone:
        ld a, [hli]
-       cp $00
-       ret z
-       call putc
-       jr puts
-
-EX_SP_HL: MACRO
-       push de
-       di
-       add sp, 2
-       pop de
+       cp 1
+       jr z, .req
+       cp 2
+       jp z, .resp
+.badarp:
+       PUTSIL "arp_input: Unknown protocol hardware or request"
+       ret
+.expectedarp:
+       db $00, $01, $08, $00, $06, $04, $00
+
+.req:
+       PUTSIL "arp_input.req: Request"
+       ; Is it asking about us?
        push hl
-       ld l, e
-       ld h, d
-       add sp, -2
-       ei
-       pop de
-       ENDM
-
-putsi:
-       pop hl
-       push af
-       push bc
-       push de
-.lp:   ld a, [hli]
-       or a
-       jr z, .done
-       call putc
-       jr .lp
-.done: pop de
-       pop bc
-       pop af
+       ld b, 0
+       ld c, $10       ; SHA + SPA + THA
+       add hl, bc
+       ld de, myIP
+       ld c, 4
+.iplp: ld a, [de]
+       cp [hl]
+       jp nz, .notourip
+       inc de
+       inc hl
+       dec c
+       jr nz, .iplp
+       PUTSIL "arp_input.req: Aimed at us."
+       pop hl  ; Now synthesize a response packet.
        push hl
+       dec hl
+       ld a, $02       ; Reply!
+       ld [hli], a
+       ld d, h
+       ld e, l
+       ld hl, 10       ; SHA + SPA
+       add hl, de      ; Now DE points at SHA, and HL points at THA
+       ld c, 10
+.dcl:  ld a, [de]
+       ld [hli], a
+       inc de
+       dec c
+       jr nz, .dcl
+       pop hl          ; HL now points at SHA
+       ld de, myMAC
+       ld c, $06
+.mcl:  ld a, [de]
+       ld [hli], a
+       inc de
+       dec c
+       jr nz, .mcl
+       ld de, myIP     ; HL now points at SPA
+       ld c, $04
+.icl:  ld a, [de]
+       ld [hli], a
+       inc de
+       dec c
+       jr nz, .icl
+       ld d, h
+       ld e, l         ; HL now points at THA
+       ld hl, -32
+       add hl, de      ; HL has now been backed up to the start of the ethernet header.
+       ld d, h
+       ld e, l         ; DE now points at the dest
+       ld hl, 6
+       add hl, de      ; HL now points at the source
+       ld c, $06
+.sdcl: ld a, [hli]
+       ld [de], a
+       inc de
+       dec c
+       jr nz, .sdcl
+       ld hl, myMAC    ; DE now points at the source
+       ld c, $06
+.smcl: ld a, [hli]
+       ld [de], a
+       inc de
+       dec c
+       jr nz, .smcl
+       ld hl, -12
+       add hl, de      ; HL now points at the start of the packet -- should be C000!
+       ld b, 0
+       ld c, 64        ; Minimum size packet; avoid transmitting a runt
+       call packet_send
+       PUTSIL "arp_input.req: sent response!"
+       ret
+.notourip:
+       PUTSIL "arp_input.req: Not aimed at us; ignoring."
+       pop hl
+       ret
+       
+.resp:
+       PUTSIL "arp_input.resp: Response"
        ret
 
-puthex:                                ; Put two hex nibbles to the serial console.
-       push bc
-       push hl
-       push af
-       swap a
-       and $0F
-       ld hl,hex
-       ld b,0
-       ld c,a
-       add hl,bc
+ip_input:
+       ; check for ipv4
        ld a, [hl]
-       call putc
-       pop af
+       ld c, a
+       and $F0
+       swap a
+       sub $04
+       jr z, .ip_isv4
+       PUTSIL "ip_input: not ipv4 -- fuck off"
+       ret
+.ip_isv4
+       ; get length
+       ld a, c
        and $0F
-       ld hl,hex
-       ld c,a
-       add hl,bc
-       ld a, [hl]
-       call putc
+       sla a
+       ld c, a
+       sla a
+       sub $14
+       ld b, a
+       push bc
+
+       ; check checksum
+       xor a
+       ld d, a
+       ld e, a
+       push hl
+.ip_cksumloop:
+       ld a, [hli]
+       ld b, a
+       ld a, [hli]
+       add e
+       ld e, a
+       ld a, b
+       add d
+       ld d, a
+       jr nc, .ip_noinc
+       inc de
+.ip_noinc:
+       dec c
+       jr nz, .ip_cksumloop
+
+       ; checksum ok
        pop hl
+       ld a, d
+       or e
+       jr z, .ip_cksumgood
+       ld a, d
+       and e
+       cpl
+       or a
+       jr z, .ip_cksumgood
+       PUTSIL "ip_input: checksum fail -- bailing"
+       pop hl
+       ret
+.ip_cksumgood:
+       PUTSIL "ip_input: checksum good"
+       ld b, $00
+       ld c, $0C
+       add hl, bc
+       ld c, $04
+
+       ; print source IP
+       PUTSI "ip_input: this packet is from 0x"
+.ip_get_srcip:
+       ld a, [hli]
+       PUTHEX a
+       dec c
+       jr nz, .ip_get_srcip
+       PUTSIL "."
+
+       ; check dest IP
+       ld d, myIP >> 8
+       ld e, myIP & $FF
+       ld c, $04
+.ip_chkip:
+       ld b, [hl]
+       inc hl
+       ld a, [de]
+       inc de
+       cp b
+       jr nz, .ip_ipfail
+       dec c
+       jr nz, .ip_chkip
+
+       PUTSIL "ip_input: wheeeeeeeeeeeeeeee"
+       ; get protocol in A
+       ld d, $FF
+       ld e, -$0B
+       add hl, de
+       ld a, [hl]
+       ld d, $00
+       ld e, $0B
+       add hl, de
+
+       ; make hl point at beginning of data
        pop bc
+       ld c, b
+       ld b, $00
+       add hl, bc
+
+       ; ok, pass it off to something else
+       cp $01
+       jr z, .ip_icmp
+       cp $11
+       jr z, .ip_udp
+       ret
+
+.ip_icmp:
+       call icmp_input
+       ret
+
+.ip_udp:
+       call udp_input
+       ret
+
+.ip_ipfail:
+       PUTSIL "ip_input: this packet is not to our IP address. Bailing."
+       pop hl
+       ret
+
+icmp_input:
+       PUTSIL "icmp_input: too lazy to parse -- fuck off"
+       ret
+
+udp_input:
+       PUTSIL "udp_input: too lazy to parse -- fuck off"
        ret
-hex:   db "0123456789ABCDEF"
+
+packet_send:
+       ld a, [ETH_STATUS]      ; Wait for the port to become available.
+       and $01
+       jr nz, packet_send
+       ld a, b
+       ld [ETH_DATA], a
+       ld a, c
+       ld [ETH_DATA], a
+.pkts: ld a, b
+       or c
+       ret z
+       dec bc
+       ld a, [hli]
+       ld [ETH_DATA], a
+       jr .pkts
+
+       SECTION "ethdata", BSS
+bssstart       DS 0
+packet         DS 1552
+arptable       DS ARP_ENTRIES * ARP_ENTRY_SIZE
+bssend         DS 0
This page took 0.02949 seconds and 4 git commands to generate.