INCLUDE "serial.inc" ETH_STATUS EQU $FF68 ETH_DATA EQU $FF69 ARP_ENTRIES EQU 6 ARP_ENTRY_SIZE EQU 13 SECTION "config", HOME[$0] myMAC: db $12, $34, $56, $78, $9A, $00 myIP: db $0A, $00, $00, $02 myMask: db $FF, $00, $00, $00 myGW: db $0A, $00, $00, $01 SECTION "boot", HOME[$100] jr start nop nop db $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83 ;<<< no $00,$c3,$50,$01 db $00,$0C,$00,$0D,$00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6 db $DD,$DD,$D9,$99,$BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F db $BB,$B9,$33,$3E ; Standard Nintendo DO NOT CHANGE... db "GB Ethernet " ; Cart name 16bytes db $00,$00,$00 ; Not used db $00 ; Cart type ROM Only db $00 ; ROM Size 32k db $00 ; RAM Size 0k db $cf,$08 ; Maker ID Matthew Johnson db $01 ; Version =1 db $87 ; Complement check (Important) db $ff,$ff ; Cheksum, fix this if you are going to start: ld sp, $D800 call zerobss PUTSIL "Ethernet test ROM" .lp: xor a ; Reset state machines ld [ETH_STATUS], a 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, packet .cplp: ld a, b or c jr z, .done dec bc ld a, [ETH_DATA] ld [hli], a jr .cplp .done: pop bc PUTSI "getpacket: Got " PUTHEX b PUTHEX c PUTSIL " byte packet from hardware." ld hl, packet call ether_input ret ether_input: push hl PUTSI "ether_input: Packet to " PUTHEX [hli] PUTC $3A PUTHEX [hli] PUTC $3A PUTHEX [hli] PUTC $3A PUTHEX [hli] PUTC $3A PUTHEX [hli] PUTC $3A PUTHEX [hli] PUTSI " from " PUTHEX [hli] PUTC $3A PUTHEX [hli] PUTC $3A PUTHEX [hli] PUTC $3A PUTHEX [hli] PUTC $3A PUTHEX [hli] PUTC $3A PUTHEX [hli] PUTSI " protocol " PUTHEX [hli] PUTHEX [hli] PUTSIL "." pop hl ; Verify the destination MAC. push hl ld de, myMAC ld c, $06 .maclp: ld a, [de] cp [hl] jr nz, .notus inc de inc hl dec c jr nz, .maclp ; Done? Then it was to us! jr .us .notus: ; Was it to broadcast? pop hl 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 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 .notbc: pop hl PUTSIL "ether_input: Not addressed to us and not broadcast." ret .unknownproto: PUTSIL "ether_input: Unknown protocol; dropping" ret .arp: PUTSIL "ether_input: ARP packet" call arp_input ret .ip: PUTSIL "ether_input: IP packet" call ip_input ret 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 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 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 ip_input: ; check for ipv4 ld a, [hl] 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 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 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