mirror of
https://github.com/bobbimanners/emailler.git
synced 2025-02-21 16:29:06 +00:00
restructure source tree to get better split between client (ca65) and server (ruby) files
git-svn-id: http://svn.code.sf.net/p/netboot65/code@13 93682198-c243-4bdb-bd91-e943c89aac3b
This commit is contained in:
parent
13c5f64524
commit
401effa912
@ -1,19 +0,0 @@
|
||||
|
||||
MEMORY {
|
||||
ZP: start = $00, size = $08, type = rw, define = yes;
|
||||
IP65ZP: start = $0f, size = $10, type = rw, define = yes;
|
||||
HEADER: start = $0000, size = $10, file = %O;
|
||||
RAM: start = $800, size = $8000, file = %O;
|
||||
}
|
||||
SEGMENTS {
|
||||
EXEHDR: load = HEADER, type = ro;
|
||||
STARTUP: load = RAM,run=RAM, type = ro, define = yes;
|
||||
CODE: load = RAM, run=RAM, type = ro, define = yes;
|
||||
RODATA: load = RAM, run=RAM, type = ro , define = yes;
|
||||
DATA: load = RAM, run=RAM, type = rw , define = yes;
|
||||
BSS: load=RAM, type = bss, define = yes;
|
||||
ZEROPAGE: load = ZP, type = zp;
|
||||
IP65ZP: load = IP65ZP, type = zp;
|
||||
}
|
||||
|
||||
|
@ -1,22 +0,0 @@
|
||||
|
||||
MEMORY {
|
||||
ZP: start = $00, size = $08, type = rw, define = yes;
|
||||
IP65ZP: start = $0f, size = $10, type = rw, define = yes;
|
||||
HEADER: start = $0000, size = $4, file = %O;
|
||||
RAM: start = $800, size = $8000, file = %O;
|
||||
LANGUAGE_CARD: start= $D000, size=$2800, type=rw, define=yes;
|
||||
PAGE3: start = $301, size = 20;
|
||||
}
|
||||
SEGMENTS {
|
||||
EXEHDR: load = HEADER, type = ro;
|
||||
STARTUP: load = RAM,run=RAM, type = ro, define = yes;
|
||||
CODE: load = RAM, run=LANGUAGE_CARD, type = ro, define = yes;
|
||||
RODATA: load = RAM, run=LANGUAGE_CARD, type = ro , define = yes;
|
||||
DATA: load = RAM, run=LANGUAGE_CARD, type = rw , define = yes;
|
||||
BSS: load=LANGUAGE_CARD, type = bss, define = yes;
|
||||
ZEROPAGE: load = ZP, type = zp;
|
||||
IP65ZP: load = IP65ZP, type = zp;
|
||||
PAGE3: load=PAGE3,type=bss;
|
||||
}
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
MEMORY {
|
||||
ZP: start = $02, size = $1A, type = rw, define = yes;
|
||||
IP65ZP: start = $5f, size = $10, type = rw, define = yes;
|
||||
RAM: start = $07FF, size = $c801, define = yes, file = %O;
|
||||
DISCARD: start = $77FF, size = $10, define = yes;
|
||||
}
|
||||
SEGMENTS {
|
||||
STARTUP: load = RAM, type = ro ,define = yes;
|
||||
CODE: load = RAM, type = ro,define = yes;
|
||||
DATA: load = RAM, type = rw,define = yes;
|
||||
RODATA: load = RAM, type = ro,define = yes;
|
||||
BSS: load = RAM, type = bss;
|
||||
ZEROPAGE: load = ZP, type = zp;
|
||||
IP65ZP: load = IP65ZP, type = zp;
|
||||
EXEHDR: load = DISCARD, type = ro;
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
MEMORY {
|
||||
ZP: start = $02, size = $1A, type = rw, define = yes;
|
||||
IP65ZP: start = $5f, size = $10, type = rw, define = yes;
|
||||
HEADER: start = $0000, size = $9, file = %O;
|
||||
ROM: start = $8009, size = $1FF7, define = yes, file = %O;
|
||||
RAM: start = $6000, size = $2000, define = yes;
|
||||
|
||||
|
||||
}
|
||||
SEGMENTS {
|
||||
CARTRIDGE_HEADER: load = HEADER, type = ro;
|
||||
CODE: load = ROM, type = ro;
|
||||
RODATA: load = ROM, type = ro;
|
||||
DATA: load = ROM, run = RAM, type = rw, define = yes;
|
||||
BSS: load = RAM, type = bss;
|
||||
IP65ZP: load = IP65ZP, type = zp;
|
||||
ZEROPAGE: load = ZP, type = zp;
|
||||
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
CC=cl65
|
||||
AS=ca65
|
||||
LD=ld65
|
||||
CFLAGS=-Oirs -t $(TARGET)
|
||||
AFLAGS=
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $<
|
||||
|
||||
%.o: %.s ../inc/print.i
|
||||
$(AS) $(AFLAGS) $<
|
||||
|
||||
IP65LIB=../ip65/ip65.lib
|
||||
|
||||
C64NETLIB=../drivers/c64net.lib
|
||||
APPLE2NETLIB=../drivers/apple2net.lib
|
||||
|
||||
INCFILES=\
|
||||
../inc/common.i\
|
||||
../inc/commonprint.i\
|
||||
../inc/net.i\
|
||||
|
||||
all: \
|
||||
rrnetboot.bin \
|
||||
utherboot.dsk \
|
||||
|
||||
rrnetboot.bin: rrnetboot.o $(IP65LIB) $(C64NETLIB) $(INCFILES) ../cfg/rrbin.cfg
|
||||
$(LD) -m rrnetboot.map -C ../cfg/rrbin.cfg -o rrnetboot.bin $(AFLAGS) $< $(IP65LIB) $(C64NETLIB)
|
||||
ruby fix_cart.rb rrnetboot.bin
|
||||
|
||||
utherboot.bin: utherboot.o $(IP65LIB) $(APPLE2NETLIB) $(INCFILES) ../cfg/a2language_card.cfg
|
||||
$(LD) -m utherboot.map -C ../cfg/a2language_card.cfg -o utherboot.bin $(AFLAGS) $< $(IP65LIB) $(APPLE2NETLIB)
|
||||
|
||||
utherboot.dsk: utherboot.bin
|
||||
dsktool.rb --init dos33 utherboot.dsk -a utherboot.bin -t B
|
||||
dsktool.rb utherboot.dsk -a hello -t A
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f rrnetboot.bin rrnetboot.map
|
||||
rm -f utherboot.bin utherboot.map utherboot.dsk
|
||||
|
||||
distclean: clean
|
||||
rm -f *~
|
@ -1,19 +0,0 @@
|
||||
#
|
||||
# Vice will treat a cartridge bin file that is of an even length as if the first 2 bytes in the file are a load address to be skipped over
|
||||
# so we want to make sure the bin file is an odd length - specifically 8193 bytes
|
||||
#
|
||||
|
||||
FILE_LENGTH=8193
|
||||
PAD_BYTE=0xff.chr
|
||||
filename=ARGV[0]
|
||||
if filename.nil? then
|
||||
puts "no filename specified"
|
||||
exit
|
||||
end
|
||||
|
||||
puts "fixing length of #{filename} to #{FILE_LENGTH} bytes"
|
||||
infile=File.open(filename,"rb").read
|
||||
outfile=File.open(filename,"wb")
|
||||
outfile<<infile
|
||||
outfile<<PAD_BYTE*(FILE_LENGTH-infile.length)
|
||||
outfile.close
|
BIN
clients/hello
BIN
clients/hello
Binary file not shown.
@ -1,163 +0,0 @@
|
||||
;#############
|
||||
;
|
||||
; This will boot a C64 with RR-NET from the network
|
||||
; requires
|
||||
; 1) a DHCP server, and
|
||||
; 2) a TFTP server that responds to requests on the broadcast address (255.255.255.255) and that will serve a file called 'BOOTC64.PRG'.
|
||||
; the prg file can be either BASIC or M/L, and up to 30K in length.
|
||||
;
|
||||
; jonno@jamtronix.com - January 2009
|
||||
;
|
||||
|
||||
.include "../inc/common.i"
|
||||
.include "../inc/commonprint.i"
|
||||
.include "../inc/net.i"
|
||||
|
||||
|
||||
.importzp tftp_filename
|
||||
.import tftp_load_address
|
||||
.import tftp_ip
|
||||
.import tftp_download
|
||||
.import cfg_tftp_server
|
||||
|
||||
.import copymem
|
||||
.importzp copy_src
|
||||
.importzp copy_dest
|
||||
|
||||
.import __DATA_LOAD__
|
||||
.import __DATA_RUN__
|
||||
.import __DATA_SIZE__
|
||||
|
||||
.bss
|
||||
|
||||
temp_bin: .res 1
|
||||
temp_bcd: .res 2
|
||||
|
||||
bin_file_jmp: .res 3
|
||||
|
||||
.segment "CARTRIDGE_HEADER"
|
||||
.word init ;cold start vector
|
||||
.word init ;warm start vector
|
||||
.byte $C3,$C2,$CD,$38,$30 ; "CBM80"
|
||||
|
||||
.code
|
||||
|
||||
|
||||
init:
|
||||
|
||||
;first let the kernal do a normal startup
|
||||
sei
|
||||
jsr $fda3 ;initialize CIA I/O
|
||||
jsr $fd50 ;RAM test, set pointers
|
||||
jsr $fd15 ;set vectors for KERNAL
|
||||
jsr $ff5B ;init. VIC
|
||||
cli ;KERNAL init. finished
|
||||
jsr $e453 ;set BASIC vectors
|
||||
jsr $e3bf ;initialize zero page
|
||||
|
||||
ldax #startup_msg
|
||||
jsr print
|
||||
|
||||
;relocate our r/w data
|
||||
ldax #__DATA_LOAD__
|
||||
stax copy_src
|
||||
ldax #__DATA_RUN__
|
||||
stax copy_dest
|
||||
ldax #__DATA_SIZE__
|
||||
jsr copymem
|
||||
|
||||
|
||||
|
||||
init_ip_via_dhcp
|
||||
|
||||
|
||||
jsr print_ip_config
|
||||
|
||||
ldx #3
|
||||
:
|
||||
lda cfg_tftp_server,x
|
||||
sta tftp_ip,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
ldax #$0000 ;load address will be first 2 bytes of file we dowload (LO/HI order)
|
||||
stax tftp_load_address
|
||||
|
||||
ldax #downloading_msg
|
||||
jsr print
|
||||
|
||||
ldax #tftp_file
|
||||
jsr download
|
||||
|
||||
bcc @file_downloaded_ok
|
||||
jmp bad_boot
|
||||
|
||||
@file_downloaded_ok:
|
||||
;check whether the file we just downloaded was a BASIC prg
|
||||
lda tftp_load_address
|
||||
cmp #01
|
||||
bne @not_a_basic_file
|
||||
lda tftp_load_address+1
|
||||
cmp #$08
|
||||
bne @not_a_basic_file
|
||||
|
||||
jsr $e453 ;set BASIC vectors
|
||||
jsr $e3bf ;initialize BASIC
|
||||
jsr $a86e
|
||||
jsr $a533 ; re-bind BASIC lines
|
||||
ldx $22 ;load end-of-BASIC pointer (lo byte)
|
||||
ldy $23 ;load end-of-BASIC pointer (hi byte)
|
||||
stx $2d ;save end-of-BASIC pointer (lo byte)
|
||||
sty $2e ;save end-of-BASIC pointer (hi byte)
|
||||
jsr $a659 ; CLR (reset variables)
|
||||
jmp $a7ae ; jump to BASIC interpreter loop
|
||||
|
||||
@not_a_basic_file:
|
||||
lda #$4C ;opcode for JMP
|
||||
sta bin_file_jmp
|
||||
ldax tftp_load_address
|
||||
stax bin_file_jmp+1
|
||||
jsr bin_file_jmp
|
||||
rts
|
||||
|
||||
|
||||
bad_boot:
|
||||
jmp bad_boot
|
||||
|
||||
|
||||
download:
|
||||
stax tftp_filename
|
||||
jsr print
|
||||
jsr print_cr
|
||||
|
||||
jsr tftp_download
|
||||
bcc :+
|
||||
|
||||
ldax #tftp_download_fail_msg
|
||||
jsr print
|
||||
sec
|
||||
rts
|
||||
|
||||
:
|
||||
ldax #tftp_download_ok_msg
|
||||
jsr print
|
||||
clc
|
||||
rts
|
||||
|
||||
.rodata
|
||||
|
||||
startup_msg: .byte "RR-NET NETWORK BOOK CLIENT V0.1",13,0
|
||||
|
||||
downloading_msg: .asciiz "DOWNLOADING "
|
||||
|
||||
tftp_file:
|
||||
.asciiz "BOOTC64.PRG"
|
||||
|
||||
tftp_download_fail_msg:
|
||||
.byte "DOWNLOAD FAILED", 13, 0
|
||||
|
||||
tftp_download_ok_msg:
|
||||
.byte "DOWNLOAD OK", 13, 0
|
||||
|
||||
|
||||
|
@ -1,236 +0,0 @@
|
||||
;#############
|
||||
;
|
||||
; This will boot an Apple 2 with uthernet in slot 3 from the network
|
||||
; requires
|
||||
; 1) a DHCP server, and
|
||||
; 2) a TFTP server that responds to requests on the broadcast address (255.255.255.255) and that will serve a file called 'BOOTA2.BIN'.
|
||||
;
|
||||
; jonno@jamtronix.com - January 2009
|
||||
;
|
||||
|
||||
.include "../inc/common.i"
|
||||
.include "../inc/commonprint.i"
|
||||
.include "../inc/net.i"
|
||||
.import cls
|
||||
|
||||
.importzp tftp_filename
|
||||
.import tftp_load_address
|
||||
.import tftp_ip
|
||||
.import tftp_download
|
||||
|
||||
.import copymem
|
||||
.importzp copy_src
|
||||
.importzp copy_dest
|
||||
|
||||
.import __STARTUP_LOAD__
|
||||
.import __STARTUP_SIZE__
|
||||
.import __BSS_LOAD__
|
||||
.import __DATA_LOAD__
|
||||
.import __DATA_RUN__
|
||||
.import __DATA_SIZE__
|
||||
.import __RODATA_LOAD__
|
||||
.import __RODATA_RUN__
|
||||
.import __RODATA_SIZE__
|
||||
.import __CODE_LOAD__
|
||||
.import __CODE_RUN__
|
||||
.import __CODE_SIZE__
|
||||
|
||||
.segment "PAGE3"
|
||||
|
||||
disable_language_card: .res 3
|
||||
bin_file_jmp: .res 3
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
|
||||
.segment "EXEHDR"
|
||||
|
||||
.addr __STARTUP_LOAD__ ; Start address
|
||||
.word __STARTUP_SIZE__+__CODE_SIZE__+__RODATA_SIZE__+__DATA_SIZE__+4 ; Size
|
||||
|
||||
; ------------------------------------------------------------------------
|
||||
|
||||
|
||||
.segment "STARTUP"
|
||||
|
||||
|
||||
lda $c089 ;enable language : card read ROM, write RAM, BANK 1
|
||||
|
||||
;copy the monitor rom on to the language card
|
||||
ldax #$f800
|
||||
stax copy_src
|
||||
stax copy_dest
|
||||
ldax #$0800
|
||||
jsr startup_copymem
|
||||
|
||||
|
||||
lda $c08b ;enable language : card read RAM, write RAM, BANK 1
|
||||
lda $c08b ;this soft switch needs to be read twice
|
||||
|
||||
|
||||
;relocate the CODE segment
|
||||
ldax #__CODE_LOAD__
|
||||
stax copy_src
|
||||
ldax #__CODE_RUN__
|
||||
stax copy_dest
|
||||
ldax #__CODE_SIZE__
|
||||
jsr startup_copymem
|
||||
|
||||
|
||||
;relocate the RODATA segment
|
||||
ldax #__RODATA_LOAD__
|
||||
stax copy_src
|
||||
ldax #__RODATA_RUN__
|
||||
stax copy_dest
|
||||
ldax #__RODATA_SIZE__
|
||||
jsr startup_copymem
|
||||
|
||||
;relocate the DATA segment
|
||||
ldax #__DATA_LOAD__
|
||||
stax copy_src
|
||||
ldax #__DATA_RUN__
|
||||
stax copy_dest
|
||||
ldax #__DATA_SIZE__
|
||||
jsr startup_copymem
|
||||
|
||||
jmp init
|
||||
|
||||
; copy memory
|
||||
; set copy_src and copy_dest, length in A/X
|
||||
|
||||
|
||||
end: .res 1
|
||||
|
||||
startup_copymem:
|
||||
sta end
|
||||
ldy #0
|
||||
|
||||
cpx #0
|
||||
beq @tail
|
||||
|
||||
: lda (copy_src),y
|
||||
sta (copy_dest),y
|
||||
iny
|
||||
bne :-
|
||||
inc copy_src+1 ;next page
|
||||
inc copy_dest+1 ;next page
|
||||
dex
|
||||
bne :-
|
||||
|
||||
@tail:
|
||||
lda end
|
||||
beq @done
|
||||
|
||||
: lda (copy_src),y
|
||||
sta (copy_dest),y
|
||||
iny
|
||||
cpy end
|
||||
bne :-
|
||||
|
||||
@done:
|
||||
rts
|
||||
|
||||
.code
|
||||
|
||||
|
||||
init:
|
||||
|
||||
jsr cls
|
||||
|
||||
ldax #startup_msg
|
||||
jsr print
|
||||
jsr print_cr
|
||||
|
||||
init_ip_via_dhcp
|
||||
bcs bad_boot
|
||||
jsr print_ip_config
|
||||
|
||||
ldx #3
|
||||
:
|
||||
lda cfg_tftp_server,x
|
||||
sta tftp_ip,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
ldax #$0000 ;load address will be first 2 bytes of file we download (LO/HI order)
|
||||
stax tftp_load_address
|
||||
|
||||
ldax #downloading_msg
|
||||
jsr print
|
||||
|
||||
ldax #tftp_file
|
||||
jsr download
|
||||
|
||||
bcc @file_downloaded_ok
|
||||
jmp bad_boot
|
||||
|
||||
@file_downloaded_ok:
|
||||
;set up to jump to where we just d/led the file to
|
||||
lda #$4C ;opcode for JMP
|
||||
sta bin_file_jmp
|
||||
ldax tftp_load_address
|
||||
stax bin_file_jmp+1
|
||||
|
||||
;but before we go, we need to shift the file down by 2 bytes (to skip over the file length)
|
||||
ldax tftp_load_address
|
||||
stax copy_dest
|
||||
clc
|
||||
adc #02
|
||||
bcc :+
|
||||
inx
|
||||
:
|
||||
stax copy_src
|
||||
ldy #1
|
||||
lda (copy_dest),y ;currently this is the high byte of the length
|
||||
tax
|
||||
dey
|
||||
lda (copy_dest),y ;currently this is the low byte of the length
|
||||
jsr copymem
|
||||
|
||||
|
||||
;now make the 'turn off language card' routine
|
||||
lda #$AD ;$AD=LDA
|
||||
sta disable_language_card
|
||||
lda #$82 ;low byte of soft switch
|
||||
sta disable_language_card+1
|
||||
lda #$c0 ;high byte of soft switch
|
||||
sta disable_language_card+2
|
||||
|
||||
jmp disable_language_card
|
||||
|
||||
bad_boot:
|
||||
jmp $3d0
|
||||
|
||||
|
||||
download:
|
||||
stax tftp_filename
|
||||
jsr print
|
||||
jsr print_cr
|
||||
|
||||
jsr tftp_download
|
||||
bcc :+
|
||||
|
||||
ldax #tftp_download_fail_msg
|
||||
jsr print
|
||||
sec
|
||||
rts
|
||||
|
||||
:
|
||||
ldax #tftp_download_ok_msg
|
||||
jsr print
|
||||
clc
|
||||
rts
|
||||
|
||||
.rodata
|
||||
downloading_msg: .asciiz "DOWNLOADING "
|
||||
|
||||
tftp_file:
|
||||
.asciiz "BOOTA2.BIN"
|
||||
|
||||
tftp_download_fail_msg:
|
||||
.asciiz "DOWNLOAD FAILED"
|
||||
|
||||
tftp_download_ok_msg:
|
||||
.asciiz "DOWNLOAD OK"
|
||||
|
||||
startup_msg: .byte "UTHERNET NETWORK BOOT CLIENT V0.1",0
|
||||
|
@ -1,15 +0,0 @@
|
||||
|
||||
WE NEED:
|
||||
|
||||
- about 4K of BSS space for ethernet buffers
|
||||
- about 6K of code
|
||||
|
||||
BOOT FROM DISK (UTHERBOOT.BIN)
|
||||
|
||||
- loads in at $0800
|
||||
- copies monitor rom to same spot in language card (F800-FFFF)
|
||||
- relocates to $D000-$C000 in the language card (bank 1 only)
|
||||
- makes language card active (bank 1)
|
||||
- downloads BOOTA2.BIN via tftp
|
||||
- turns off language card
|
||||
- jumps to start of of BOOTA2.BIN
|
@ -1,46 +0,0 @@
|
||||
DOS 3.3 MEMORY LAYOUT
|
||||
|
||||
$C000 --- TOP OF RAM
|
||||
|
||||
$B600 --- RWTS
|
||||
|
||||
$AAC9 --- FILE MANAGER
|
||||
|
||||
$9D00 --- MAIN DOS ROUTINES
|
||||
|
||||
$9600 -- DOS FILE BUFFERS (MAXFILES 3)
|
||||
|
||||
|
||||
BD00 - RWTS main entry
|
||||
- call with AY pointing at IOB
|
||||
|
||||
Input/Output Control Block
|
||||
|
||||
OFFSET DESCRIPTION
|
||||
$00 Table Type (must be 1)
|
||||
$01 Slot Number times 0x10
|
||||
$02 Drive Number ($01 or $02)
|
||||
$03 Volume Number ($00 matches any volume)
|
||||
$04 Track Number
|
||||
$05 Sector Number
|
||||
$06/$07 Address (lo/hi) of Device Characteristics Table
|
||||
$08/$09 Address (lo/hi) of 256 byte buffer for READ/WRITE
|
||||
$0A Not Used
|
||||
$0B byte count for partial sector
|
||||
$0c Command Code
|
||||
$00 = SEEK
|
||||
$01 = READ
|
||||
$02 = WRITE
|
||||
$04 = FORMAT
|
||||
$0d Return Code (if non zero, carry flag should be set)
|
||||
$00 = no error
|
||||
$08 = error during initialization
|
||||
$10 = write protect error
|
||||
$20 = volume mismatch error
|
||||
$40 = drive error
|
||||
$80 = read error (obsolete)
|
||||
$0e volume number of last access
|
||||
$0f slot number of last acces * 16
|
||||
$10 drive number of last access
|
||||
|
||||
|
@ -1,32 +0,0 @@
|
||||
AS=ca65
|
||||
LD=ld65
|
||||
AFLAGS=
|
||||
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $<
|
||||
|
||||
%.o: %.s
|
||||
$(AS) $(AFLAGS) $<
|
||||
|
||||
|
||||
DRIVERS=\
|
||||
apple2net.lib \
|
||||
c64net.lib \
|
||||
|
||||
all: $(DRIVERS)
|
||||
|
||||
|
||||
apple2net.lib: a2print.o uthernet.o a2timer.o a2kernal.o
|
||||
ar65 a apple2net.lib $^
|
||||
|
||||
c64net.lib: c64print.o rr-net.o c64timer.o c64kernal.o
|
||||
ar65 a c64net.lib $^
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f apple2net.lib
|
||||
rm -f c64net.lib
|
||||
|
||||
distclean: clean
|
||||
rm -f *~
|
@ -1,5 +0,0 @@
|
||||
.export exit_to_basic
|
||||
|
||||
.code
|
||||
exit_to_basic:
|
||||
jmp $3d0
|
@ -1,21 +0,0 @@
|
||||
|
||||
.export print_a
|
||||
.export print_cr
|
||||
.export cls
|
||||
|
||||
.code
|
||||
|
||||
print_a:
|
||||
ora #$80 ;turn ASCII into Apple 2 screen codes
|
||||
jmp $fdf0
|
||||
|
||||
|
||||
print_cr:
|
||||
|
||||
jmp $fd8e
|
||||
|
||||
|
||||
|
||||
cls:
|
||||
jmp $fc58
|
||||
rts
|
@ -1,40 +0,0 @@
|
||||
; timer routines
|
||||
;
|
||||
; unfortunately the standard Apple 2 has no CIA or VBI, so for the moment, we will
|
||||
; make each call to 'timer_read' delay for a little while
|
||||
; this kludge will make the polling loops work at least
|
||||
;
|
||||
; timer_read is meant to return a counter with millisecond resolution
|
||||
|
||||
.include "../inc/common.i"
|
||||
|
||||
|
||||
.export timer_init
|
||||
.export timer_read
|
||||
|
||||
.bss
|
||||
current_time_value: .res 2
|
||||
|
||||
.code
|
||||
|
||||
timer_init:
|
||||
ldax #0
|
||||
stax current_time_value
|
||||
rts
|
||||
|
||||
|
||||
; return the current value (actually, delay a while, then update current value, then return it in ax)
|
||||
|
||||
timer_read:
|
||||
lda #111
|
||||
jsr $fca8 ;wait for about 33ms
|
||||
clc
|
||||
lda #33
|
||||
adc current_time_value
|
||||
sta current_time_value
|
||||
bcc :+
|
||||
inc current_time_value+1
|
||||
:
|
||||
ldax current_time_value
|
||||
rts
|
||||
|
@ -1,5 +0,0 @@
|
||||
.export exit_to_basic
|
||||
|
||||
.code
|
||||
exit_to_basic:
|
||||
jmp $a7ae ; jump to BASIC interpreter loop
|
@ -1,13 +0,0 @@
|
||||
|
||||
.export print_a
|
||||
.export print_cr
|
||||
|
||||
.data
|
||||
print_a = $ffd2
|
||||
|
||||
.code
|
||||
|
||||
print_cr:
|
||||
lda #13
|
||||
jmp $ffd2
|
||||
|
@ -1,46 +0,0 @@
|
||||
; timer routines
|
||||
;
|
||||
; the timer should be a 16-bit counter that's incremented by about
|
||||
; 1000 units per second. it doesn't have to be particularly accurate,
|
||||
; if you're working with e.g. a 60 Hz VBLANK IRQ, adding 17 to the
|
||||
; counter every frame would be just fine.
|
||||
|
||||
|
||||
.include "../inc/common.i"
|
||||
|
||||
|
||||
.export timer_init
|
||||
.export timer_read
|
||||
|
||||
.code
|
||||
|
||||
; initialize timers
|
||||
timer_init:
|
||||
lda #$80 ; stop timers
|
||||
sta $dd0e
|
||||
sta $dd0f
|
||||
|
||||
ldax #999 ; timer A to 1000 cycles
|
||||
stax $dd04
|
||||
|
||||
ldax #$ffff ; timer B to max cycles
|
||||
stax $dd06
|
||||
|
||||
lda #$81 ; timer A in continuous mode
|
||||
sta $dd0e
|
||||
|
||||
lda #$c1 ; timer B to count timer A underflows
|
||||
sta $dd0f
|
||||
|
||||
rts
|
||||
|
||||
|
||||
; return the current value
|
||||
timer_read:
|
||||
lda $dd07 ; cia counts backwards, return inverted value
|
||||
eor #$ff
|
||||
tax
|
||||
lda $dd06
|
||||
eor #$ff
|
||||
rts
|
||||
|
@ -1,35 +0,0 @@
|
||||
; RR-Net driver
|
||||
|
||||
|
||||
.export cs_init
|
||||
|
||||
.export cs_packet_page
|
||||
.export cs_packet_data
|
||||
.export cs_rxtx_data
|
||||
.export cs_tx_cmd
|
||||
.export cs_tx_len
|
||||
.export cs_driver_name
|
||||
|
||||
rr_ctl = $de01
|
||||
|
||||
;cs_irq = $de00
|
||||
cs_packet_page = $de02
|
||||
cs_packet_data = $de04
|
||||
;cs_packet_data2 = $de06
|
||||
cs_rxtx_data = $de08
|
||||
;cs_rxtx_data2 = $de0a
|
||||
cs_tx_cmd = $de0c
|
||||
cs_tx_len = $de0e
|
||||
|
||||
|
||||
.code
|
||||
|
||||
cs_init:
|
||||
lda rr_ctl
|
||||
ora #1
|
||||
sta rr_ctl
|
||||
rts
|
||||
|
||||
.rodata
|
||||
cs_driver_name:
|
||||
.asciiz "RR-NET"
|
@ -1,29 +0,0 @@
|
||||
; uthernet driver
|
||||
; for the moment, always assume slot 3
|
||||
|
||||
|
||||
.export cs_init
|
||||
|
||||
.export cs_packet_page
|
||||
.export cs_packet_data
|
||||
.export cs_rxtx_data
|
||||
.export cs_tx_cmd
|
||||
.export cs_tx_len
|
||||
.export cs_driver_name
|
||||
|
||||
cs_rxtx_data = $c0b0
|
||||
cs_tx_cmd = $c0b4
|
||||
cs_tx_len = $c0b6
|
||||
cs_packet_page = $c0ba
|
||||
cs_packet_data = $c0bc
|
||||
|
||||
|
||||
.code
|
||||
|
||||
cs_init:
|
||||
|
||||
rts
|
||||
|
||||
.rodata
|
||||
cs_driver_name:
|
||||
.byte "UTHERNET",0
|
17
inc/common.i
17
inc/common.i
@ -1,17 +0,0 @@
|
||||
; load A/X macro
|
||||
.macro ldax arg
|
||||
.if (.match (.left (1, arg), #)) ; immediate mode
|
||||
lda #<(.right (.tcount (arg)-1, arg))
|
||||
ldx #>(.right (.tcount (arg)-1, arg))
|
||||
.else ; assume absolute or zero page
|
||||
lda arg
|
||||
ldx 1+(arg)
|
||||
.endif
|
||||
.endmacro
|
||||
|
||||
; store A/X macro
|
||||
.macro stax arg
|
||||
sta arg
|
||||
stx 1+(arg)
|
||||
.endmacro
|
||||
|
@ -1,232 +0,0 @@
|
||||
.zeropage
|
||||
pptr: .res 2
|
||||
.bss
|
||||
temp_bin: .res 1
|
||||
temp_bcd: .res 2
|
||||
|
||||
.code
|
||||
.macro print_driver_init
|
||||
ldax #cs_driver_name
|
||||
jsr print
|
||||
ldax #init_msg
|
||||
jsr print
|
||||
.endmacro
|
||||
|
||||
|
||||
.macro print_dhcp_init
|
||||
ldax #dhcp_msg
|
||||
jsr print
|
||||
ldax #init_msg
|
||||
jsr print
|
||||
.endmacro
|
||||
|
||||
.macro print_failed
|
||||
ldax #failed_msg
|
||||
jsr print
|
||||
jsr print_cr
|
||||
.endmacro
|
||||
|
||||
.macro print_ok
|
||||
ldax #ok_msg
|
||||
jsr print
|
||||
jsr print_cr
|
||||
.endmacro
|
||||
|
||||
|
||||
.code
|
||||
|
||||
.import print_a
|
||||
.import print_cr
|
||||
.import cs_driver_name
|
||||
|
||||
print_ip_config:
|
||||
ldax #ip_address_msg
|
||||
jsr print
|
||||
ldax #cfg_ip
|
||||
jsr print_dotted_quad
|
||||
jsr print_cr
|
||||
|
||||
ldax #netmask_msg
|
||||
jsr print
|
||||
ldax #cfg_netmask
|
||||
jsr print_dotted_quad
|
||||
jsr print_cr
|
||||
|
||||
ldax #gateway_msg
|
||||
jsr print
|
||||
ldax #cfg_gateway
|
||||
jsr print_dotted_quad
|
||||
jsr print_cr
|
||||
|
||||
ldax #dns_server_msg
|
||||
jsr print
|
||||
ldax #cfg_dns
|
||||
jsr print_dotted_quad
|
||||
jsr print_cr
|
||||
|
||||
ldax #dhcp_server_msg
|
||||
jsr print
|
||||
ldax #dhcp_server
|
||||
jsr print_dotted_quad
|
||||
jsr print_cr
|
||||
|
||||
ldax #tftp_server_msg
|
||||
jsr print
|
||||
ldax #cfg_tftp_server
|
||||
jsr print_dotted_quad
|
||||
jsr print_cr
|
||||
|
||||
rts
|
||||
|
||||
print:
|
||||
sta pptr
|
||||
stx pptr + 1
|
||||
|
||||
@print_loop:
|
||||
ldy #0
|
||||
lda (pptr),y
|
||||
beq @done_print
|
||||
jsr print_a
|
||||
inc pptr
|
||||
bne @print_loop
|
||||
inc pptr+1
|
||||
bne @print_loop ;if we ever get to $ffff, we've probably gone far enough ;-)
|
||||
@done_print:
|
||||
rts
|
||||
|
||||
|
||||
;print the 4 bytes pointed at by AX as dotted decimals
|
||||
print_dotted_quad:
|
||||
sta pptr
|
||||
stx pptr + 1
|
||||
ldy #0
|
||||
lda (pptr),y
|
||||
jsr print_decimal
|
||||
lda #'.'
|
||||
jsr print_a
|
||||
|
||||
ldy #1
|
||||
lda (pptr),y
|
||||
jsr print_decimal
|
||||
lda #'.'
|
||||
jsr print_a
|
||||
|
||||
ldy #2
|
||||
lda (pptr),y
|
||||
jsr print_decimal
|
||||
lda #'.'
|
||||
jsr print_a
|
||||
|
||||
ldy #3
|
||||
lda (pptr),y
|
||||
jsr print_decimal
|
||||
|
||||
rts
|
||||
|
||||
print_decimal: ;print byte in A as a decimal number
|
||||
pha
|
||||
sta temp_bin ;save
|
||||
sed ; Switch to decimal mode
|
||||
lda #0 ; Ensure the result is clear
|
||||
sta temp_bcd
|
||||
sta temp_bcd+1
|
||||
ldx #8 ; The number of source bits
|
||||
:
|
||||
asl temp_bin+0 ; Shift out one bit
|
||||
lda temp_bcd+0 ; And add into result
|
||||
adc temp_bcd+0
|
||||
sta temp_bcd+0
|
||||
lda temp_bcd+1 ; propagating any carry
|
||||
adc temp_bcd+1
|
||||
sta temp_bcd+1
|
||||
dex ; And repeat for next bit
|
||||
bne :-
|
||||
|
||||
cld ;back to binary
|
||||
|
||||
pla ;get back the original passed in number
|
||||
bmi @print_hundreds ; if N is set, the number is >=128 so print all 3 digits
|
||||
cmp #10
|
||||
bmi @print_units
|
||||
cmp #100
|
||||
bmi @print_tens
|
||||
@print_hundreds:
|
||||
lda temp_bcd+1 ;get the most significant digit
|
||||
and #$0f
|
||||
clc
|
||||
adc #'0'
|
||||
jsr print_a
|
||||
|
||||
@print_tens:
|
||||
lda temp_bcd
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
clc
|
||||
adc #'0'
|
||||
jsr print_a
|
||||
@print_units:
|
||||
lda temp_bcd
|
||||
and #$0f
|
||||
clc
|
||||
adc #'0'
|
||||
jsr print_a
|
||||
|
||||
rts
|
||||
|
||||
|
||||
print_hex:
|
||||
pha
|
||||
pha
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
tax
|
||||
lda hexdigits,x
|
||||
jsr print_a
|
||||
pla
|
||||
and #$0F
|
||||
tax
|
||||
lda hexdigits,x
|
||||
jsr print_a
|
||||
pla
|
||||
rts
|
||||
|
||||
.rodata
|
||||
hexdigits:
|
||||
.byte "0123456789ABCDEF"
|
||||
|
||||
ip_address_msg:
|
||||
.byte "IP ADDRESS: ", 0
|
||||
|
||||
netmask_msg:
|
||||
.byte "NETMASK: ", 0
|
||||
|
||||
gateway_msg:
|
||||
.byte "GATEWAY: ", 0
|
||||
|
||||
dns_server_msg:
|
||||
.byte "DNS SERVER: ", 0
|
||||
|
||||
dhcp_server_msg:
|
||||
.byte "DHCP SERVER:", 0
|
||||
|
||||
tftp_server_msg:
|
||||
.byte "TFTP SERVER: ", 0
|
||||
|
||||
dhcp_msg:
|
||||
.byte "DHCP",0
|
||||
|
||||
init_msg:
|
||||
.byte " INIT ",0
|
||||
|
||||
failed_msg:
|
||||
.byte "FAILED", 0
|
||||
|
||||
ok_msg:
|
||||
.byte "OK", 0
|
||||
|
||||
dns_lookup_failed_msg:
|
||||
.byte "DNS LOOKUP FAILED", 0
|
41
inc/net.i
41
inc/net.i
@ -1,41 +0,0 @@
|
||||
.import ip65_init
|
||||
.import ip65_process
|
||||
|
||||
.import cfg_mac
|
||||
.import cfg_ip
|
||||
.import cfg_netmask
|
||||
.import cfg_gateway
|
||||
.import cfg_dns
|
||||
.import cfg_tftp_server
|
||||
|
||||
.import dhcp_init
|
||||
.import dhcp_server
|
||||
|
||||
|
||||
.macro init_ip_via_dhcp
|
||||
|
||||
print_driver_init
|
||||
jsr ip65_init
|
||||
bcc :+
|
||||
print_failed
|
||||
sec
|
||||
jmp @end_macro
|
||||
|
||||
:
|
||||
|
||||
print_ok
|
||||
|
||||
print_dhcp_init
|
||||
|
||||
jsr dhcp_init
|
||||
bcc :+
|
||||
|
||||
|
||||
print_failed
|
||||
sec
|
||||
rts
|
||||
:
|
||||
print_ok
|
||||
clc
|
||||
@end_macro:
|
||||
.endmacro
|
@ -1,22 +0,0 @@
|
||||
petscii_black = 144
|
||||
petscii_white = 5
|
||||
petscii_red = 28
|
||||
petscii_cyan = 159
|
||||
petscii_purple = 156
|
||||
petscii_green = 30
|
||||
petscii_blue = 31
|
||||
petscii_yellow = 158
|
||||
petscii_orange = 129
|
||||
petscii_brown = 149
|
||||
petscii_ltred = 150
|
||||
petscii_dkgray = 151
|
||||
petscii_gray = 152
|
||||
petscii_ltgreen = 153
|
||||
petscii_ltblue = 154
|
||||
petscii_ltgray = 155
|
||||
|
||||
petscii_lower = 14
|
||||
petscii_home = 19
|
||||
petscii_clear = 147
|
||||
|
||||
petscii_down = 17
|
55
inc/printf.i
55
inc/printf.i
@ -1,55 +0,0 @@
|
||||
.import console_printf
|
||||
|
||||
|
||||
.macro printfargs arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
|
||||
.ifnblank arg1
|
||||
.addr arg1
|
||||
printfargs arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
|
||||
.endif
|
||||
.endmacro
|
||||
|
||||
.macro printf str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
|
||||
|
||||
.local arglist
|
||||
.local string
|
||||
|
||||
pha
|
||||
.ifpc02
|
||||
phx
|
||||
phy
|
||||
.else
|
||||
txa
|
||||
pha
|
||||
tya
|
||||
pha
|
||||
.endif
|
||||
ldax #arglist
|
||||
jsr console_printf
|
||||
.ifpc02
|
||||
ply
|
||||
plx
|
||||
.else
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
.endif
|
||||
pla
|
||||
|
||||
.pushseg
|
||||
.rodata
|
||||
.if (.match(str, ""))
|
||||
string:
|
||||
.asciiz str
|
||||
arglist:
|
||||
.addr string
|
||||
.else
|
||||
arglist:
|
||||
.addr str
|
||||
.endif
|
||||
|
||||
printfargs arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
|
||||
|
||||
.popseg
|
||||
|
||||
.endmacro
|
@ -1,43 +0,0 @@
|
||||
AS=ca65
|
||||
LD=ld65
|
||||
AFLAGS=
|
||||
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $<
|
||||
|
||||
%.o: %.s
|
||||
$(AS) $(AFLAGS) $<
|
||||
|
||||
|
||||
ETHOBJS= \
|
||||
copymem.o \
|
||||
config.o \
|
||||
timer.o \
|
||||
cs8900a.o \
|
||||
eth.o \
|
||||
arp.o \
|
||||
ip.o \
|
||||
icmp.o \
|
||||
udp.o \
|
||||
ip65.o \
|
||||
printf.o \
|
||||
debug.o \
|
||||
dhcp.o \
|
||||
dns.o \
|
||||
tftp.o \
|
||||
|
||||
all: ip65.lib
|
||||
|
||||
|
||||
ip65.lib: $(ETHOBJS)
|
||||
ar65 a ip65.lib $^
|
||||
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f ip65.lib
|
||||
|
||||
|
||||
distclean: clean
|
||||
rm -f *~
|
448
ip65/arp.s
448
ip65/arp.s
@ -1,448 +0,0 @@
|
||||
; ARP address resolution
|
||||
|
||||
;originally from Per Olofsson's IP65 library - http://www.paradroid.net/ip65
|
||||
|
||||
.include "../inc/common.i"
|
||||
|
||||
.export arp_init
|
||||
.export arp_lookup
|
||||
.export arp_process
|
||||
.export arp_add
|
||||
|
||||
.export arp_ip
|
||||
.export arp_mac
|
||||
.export arp_cache
|
||||
|
||||
.import eth_inp
|
||||
.import eth_inp_len
|
||||
.import eth_outp
|
||||
.import eth_outp_len
|
||||
.import eth_tx
|
||||
.import eth_set_broadcast_dest
|
||||
.import eth_set_my_mac_src
|
||||
.import eth_set_proto
|
||||
.importzp eth_proto_arp
|
||||
|
||||
.import cfg_mac
|
||||
.import cfg_ip
|
||||
.import cfg_netmask
|
||||
.import cfg_gateway
|
||||
|
||||
.import timer_read
|
||||
.import timer_timeout
|
||||
|
||||
|
||||
.segment "IP65ZP" : zeropage
|
||||
|
||||
ap: .res 2
|
||||
|
||||
|
||||
.bss
|
||||
|
||||
; arp state machine
|
||||
arp_idle = 1 ; idling
|
||||
arp_wait = 2 ; waiting for reply
|
||||
arp_state: .res 1 ; current activity
|
||||
|
||||
; arguments for lookup and add
|
||||
arp: ; ptr to mac/ip pair
|
||||
arp_mac: .res 6 ; result is delivered here
|
||||
arp_ip: .res 4 ; set ip before calling lookup
|
||||
|
||||
; arp cache
|
||||
ac_size = 8 ; lookup cache
|
||||
ac_ip = 6 ; offset for ip
|
||||
ac_mac = 0 ; offset for mac
|
||||
arp_cache: .res (6+4)*ac_size
|
||||
|
||||
; offsets for arp packet generation
|
||||
ap_hw = 14 ; hw type (eth = 0001)
|
||||
ap_proto = 16 ; protocol (ip = 0800)
|
||||
ap_hwlen = 18 ; hw addr len (eth = 06)
|
||||
ap_protolen = 19 ; proto addr len (ip = 04)
|
||||
ap_op = 20 ; request = 0001, reply = 0002
|
||||
ap_shw = 22 ; sender hw addr
|
||||
ap_sp = 28 ; sender proto addr
|
||||
ap_thw = 32 ; target hw addr
|
||||
ap_tp = 38 ; target protoaddr
|
||||
ap_packlen = 42 ; total length of packet
|
||||
|
||||
; gateway handling
|
||||
gw_mask: .res 4 ; inverted netmask
|
||||
gw_test: .res 4 ; gateway ip or:d with inverted netmask
|
||||
gw_last: .res 1 ; netmask length - 1
|
||||
|
||||
; timeout
|
||||
arptimeout: .res 2 ; time when we will have timed out
|
||||
|
||||
|
||||
.code
|
||||
|
||||
; initialize arp
|
||||
arp_init:
|
||||
lda #0
|
||||
|
||||
ldx #(6+4)*ac_size - 1 ; clear cache
|
||||
: sta arp_cache,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
lda #$ff ; counter for netmask length - 1
|
||||
sta gw_last
|
||||
|
||||
ldx #3
|
||||
@gw:
|
||||
lda cfg_netmask,x
|
||||
eor #$ff
|
||||
cmp #$ff
|
||||
bne :+
|
||||
inc gw_last
|
||||
: sta gw_mask,x
|
||||
ora cfg_gateway,x
|
||||
sta gw_test,x
|
||||
dex
|
||||
bpl @gw
|
||||
|
||||
lda #arp_idle ; start out idle
|
||||
sta arp_state
|
||||
|
||||
rts
|
||||
|
||||
|
||||
; lookup an ip
|
||||
; clc = mac returned in arp_mac
|
||||
; sec = request sent, call again for result
|
||||
arp_lookup:
|
||||
|
||||
lda arp_ip ; check for broadcast IP (255.255.255.255)
|
||||
and arp_ip + 1
|
||||
and arp_ip + 2
|
||||
and arp_ip + 3
|
||||
cmp #$ff
|
||||
bne @notbroadcast
|
||||
ldx #6 ;copy ff:ff:ff:ff:ff:ff to ap_mac
|
||||
: sta arp_mac,x
|
||||
dex
|
||||
bpl :-
|
||||
clc
|
||||
rts
|
||||
|
||||
@notbroadcast:
|
||||
|
||||
ldx gw_last ; check if address is on our subnet
|
||||
: lda arp_ip,x
|
||||
ora gw_mask,x
|
||||
cmp gw_test,x
|
||||
bne @notlocal
|
||||
dex
|
||||
bpl :-
|
||||
bmi @local
|
||||
|
||||
@notlocal:
|
||||
|
||||
ldx #3 ; copy gateway's ip address
|
||||
: lda cfg_gateway,x
|
||||
sta arp_ip,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
@local:
|
||||
jsr findip
|
||||
bcs @cachemiss
|
||||
|
||||
ldy #ac_ip - 1 ; copy mac
|
||||
: lda (ap),y
|
||||
sta arp,y
|
||||
dey
|
||||
bpl :-
|
||||
rts
|
||||
|
||||
@cachemiss:
|
||||
lda arp_state ; are we already waiting for a reply?
|
||||
cmp #arp_idle
|
||||
beq @sendrequest ; yes, send request
|
||||
|
||||
ldax arptimeout ; check if we've timed out
|
||||
jsr timer_timeout
|
||||
bcs @notimeout ; no, don't send
|
||||
|
||||
@sendrequest: ; send out arp request
|
||||
jsr eth_set_broadcast_dest
|
||||
jsr eth_set_my_mac_src
|
||||
|
||||
jsr makearppacket ; add arp, eth, ip, hwlen, protolen
|
||||
|
||||
lda #0 ; set opcode (request = 0001)
|
||||
sta eth_outp + ap_op
|
||||
lda #1
|
||||
sta eth_outp + ap_op + 1
|
||||
|
||||
ldx #5
|
||||
: lda cfg_mac,x ; set source mac addr
|
||||
sta eth_outp + ap_shw,x
|
||||
lda #0 ; set target mac addr
|
||||
sta eth_outp + ap_thw,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
ldx #3
|
||||
: lda cfg_ip,x ; set source ip addr
|
||||
sta eth_outp + ap_sp,x
|
||||
lda arp_ip,x ; set target ip addr
|
||||
sta eth_outp + ap_tp,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
lda #<ap_packlen ; set packet length
|
||||
sta eth_outp_len
|
||||
lda #>ap_packlen
|
||||
sta eth_outp_len + 1
|
||||
|
||||
jsr eth_tx ; send packet
|
||||
|
||||
lda #arp_wait ; waiting for reply
|
||||
sta arp_state
|
||||
|
||||
jsr timer_read ; read current timer value
|
||||
clc
|
||||
adc #<1000 ; set timeout to now + 1000 ms
|
||||
sta arptimeout
|
||||
txa
|
||||
adc #>1000
|
||||
sta arptimeout + 1
|
||||
|
||||
@notimeout:
|
||||
sec ; set carry to indicate that
|
||||
rts ; no result is availble
|
||||
|
||||
|
||||
; find arp_ip in the cache
|
||||
; clc returns pointer to entry in (ap)
|
||||
findip:
|
||||
ldax #arp_cache
|
||||
stax ap
|
||||
|
||||
ldx #ac_size
|
||||
@compare: ; compare cache entry
|
||||
ldy #ac_ip
|
||||
lda (ap),y
|
||||
beq @notfound
|
||||
: lda (ap),y
|
||||
cmp arp,y
|
||||
bne @next
|
||||
iny
|
||||
cpy #ac_ip + 4
|
||||
bne :-
|
||||
|
||||
clc ; return
|
||||
rts
|
||||
|
||||
@next: ; next entry
|
||||
lda ap
|
||||
clc
|
||||
adc #10
|
||||
sta ap
|
||||
bcc :+
|
||||
inc ap + 1
|
||||
: dex
|
||||
bne @compare
|
||||
|
||||
@notfound:
|
||||
sec
|
||||
rts
|
||||
|
||||
|
||||
; handle incoming arp packets
|
||||
arp_process:
|
||||
; lda eth_inp_len ; check packet size
|
||||
; cmp #<ap_packlen
|
||||
; bne @badpacket
|
||||
; lda eth_inp_len + 1
|
||||
; cmp #>ap_packlen
|
||||
; bne @badpacket
|
||||
|
||||
lda eth_inp + ap_op ; should be 0
|
||||
bne @badpacket
|
||||
lda eth_inp + ap_op + 1 ; check opcode
|
||||
cmp #1 ; request?
|
||||
beq @request
|
||||
cmp #2 ; reply?
|
||||
beq @reply
|
||||
|
||||
@badpacket:
|
||||
sec
|
||||
rts
|
||||
|
||||
@request:
|
||||
ldx #3
|
||||
: lda eth_inp + ap_tp,x ; check if they're asking for
|
||||
cmp cfg_ip,x ; my address
|
||||
bne @done
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
ldax #eth_inp + ap_shw
|
||||
jsr ac_add_source ; add them to arp cache
|
||||
|
||||
ldx #5 ; send reply
|
||||
: lda eth_inp + ap_shw,x
|
||||
sta eth_outp,x ; set sender packet dest
|
||||
sta eth_outp + ap_thw,x ; and as target
|
||||
lda cfg_mac,x ; me as source
|
||||
sta eth_outp + ap_shw,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
jsr eth_set_my_mac_src ; me as packet source
|
||||
|
||||
jsr makearppacket ; add arp, eth, ip, hwlen, protolen
|
||||
|
||||
lda #0 ; set opcode (reply = 0002)
|
||||
sta eth_outp + ap_op
|
||||
lda #2
|
||||
sta eth_outp + ap_op + 1
|
||||
|
||||
ldx #3
|
||||
: lda eth_inp + ap_sp,x ; sender as target addr
|
||||
sta eth_outp + ap_tp,x
|
||||
lda cfg_ip,x ; my ip as source addr
|
||||
sta eth_outp + ap_sp,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
lda #<ap_packlen ; set packet length
|
||||
sta eth_outp_len
|
||||
lda #>ap_packlen
|
||||
sta eth_outp_len + 1
|
||||
|
||||
jsr eth_tx ; send packet
|
||||
|
||||
@done:
|
||||
clc
|
||||
rts
|
||||
|
||||
@reply:
|
||||
lda arp_state
|
||||
cmp #arp_wait ; are we waiting for a reply?
|
||||
bne @badpacket
|
||||
|
||||
; ldx #0
|
||||
;: lda gotmsg,x
|
||||
; beq :+
|
||||
; jsr $ffd2
|
||||
; inx
|
||||
; bne :-
|
||||
;:
|
||||
|
||||
ldax #eth_inp + ap_shw
|
||||
jsr ac_add_source ; add to cache
|
||||
|
||||
lda #arp_idle
|
||||
sta arp_state
|
||||
|
||||
rts
|
||||
|
||||
;gotmsg:
|
||||
; .byte "gOT arp REPLY",13,0
|
||||
;
|
||||
;addmsg:
|
||||
; .byte "aDDING ARP ENTRY",13,0
|
||||
|
||||
|
||||
; add arp_mac and arp_ip to the cache
|
||||
arp_add:
|
||||
jsr findip ; check if ip is already in cache
|
||||
bcs @add
|
||||
|
||||
ldy #9 ; update old entry
|
||||
: lda arp,y ; move to top as well?
|
||||
sta (ap),y
|
||||
dey
|
||||
bpl :-
|
||||
rts
|
||||
|
||||
@add:
|
||||
ldax #arp ; add
|
||||
|
||||
|
||||
; add source to cache
|
||||
ac_add_source:
|
||||
stax ap
|
||||
|
||||
; ldx #0
|
||||
;: lda addmsg,x
|
||||
; beq :+
|
||||
; jsr $ffd2
|
||||
; inx
|
||||
; bne :-
|
||||
;:
|
||||
|
||||
ldx #9 ; make space in the arp cache
|
||||
:
|
||||
; lda arp_cache + 140,x
|
||||
; sta arp_cache + 150,x
|
||||
; lda arp_cache + 130,x
|
||||
; sta arp_cache + 140,x
|
||||
; lda arp_cache + 120,x
|
||||
; sta arp_cache + 130,x
|
||||
|
||||
; lda arp_cache + 110,x
|
||||
; sta arp_cache + 120,x
|
||||
; lda arp_cache + 100,x
|
||||
; sta arp_cache + 110,x
|
||||
; lda arp_cache + 90,x
|
||||
; sta arp_cache + 100,x
|
||||
; lda arp_cache + 80,x
|
||||
; sta arp_cache + 90,x
|
||||
|
||||
; lda arp_cache + 70,x
|
||||
; sta arp_cache + 80,x
|
||||
lda arp_cache + 60,x
|
||||
sta arp_cache + 70,x
|
||||
lda arp_cache + 50,x
|
||||
sta arp_cache + 60,x
|
||||
lda arp_cache + 40,x
|
||||
sta arp_cache + 50,x
|
||||
|
||||
lda arp_cache + 30,x
|
||||
sta arp_cache + 40,x
|
||||
lda arp_cache + 20,x
|
||||
sta arp_cache + 30,x
|
||||
lda arp_cache + 10,x
|
||||
sta arp_cache + 20,x
|
||||
lda arp_cache,x
|
||||
sta arp_cache + 10,x
|
||||
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
ldy #9
|
||||
: lda (ap),y ; copy source
|
||||
sta arp_cache,y
|
||||
dey
|
||||
bpl :-
|
||||
|
||||
rts
|
||||
|
||||
|
||||
; adds proto = arp, hw = eth, and proto = ip to outgoing packet
|
||||
makearppacket:
|
||||
lda #eth_proto_arp
|
||||
jsr eth_set_proto
|
||||
|
||||
lda #0 ; set hw type (eth = 0001)
|
||||
sta eth_outp + ap_hw
|
||||
lda #1
|
||||
sta eth_outp + ap_hw + 1
|
||||
|
||||
lda #8 ; set protcol (ip = 0800)
|
||||
sta eth_outp + ap_proto
|
||||
lda #0
|
||||
sta eth_outp + ap_proto + 1
|
||||
|
||||
lda #6 ; set hw addr len (eth = 06)
|
||||
sta eth_outp + ap_hwlen
|
||||
lda #4 ; set proto addr len (eth = 04)
|
||||
sta eth_outp + ap_protolen
|
||||
|
||||
rts
|
@ -1,21 +0,0 @@
|
||||
;originally from Per Olofsson's IP65 library - http://www.paradroid.net/ip65
|
||||
|
||||
; Configuration
|
||||
|
||||
|
||||
.export cfg_mac
|
||||
.export cfg_ip
|
||||
.export cfg_netmask
|
||||
.export cfg_gateway
|
||||
.export cfg_dns
|
||||
.export cfg_tftp_server
|
||||
|
||||
.data ; these are defaults
|
||||
|
||||
cfg_mac: .byte $00, $80, $10, $6d, $76, $30
|
||||
;cfg_ip: .byte 192, 168, 0, 64
|
||||
cfg_ip: .byte 0,0,0,0
|
||||
cfg_netmask: .byte 255, 255, 255, 0
|
||||
cfg_gateway: .byte 0, 0, 0, 0
|
||||
cfg_dns: .byte 0, 0, 0, 0
|
||||
cfg_tftp_server: .byte $ff,$ff,$ff,$ff
|
@ -1,54 +0,0 @@
|
||||
;originally from Per Olofsson's IP65 library - http://www.paradroid.net/ip65
|
||||
|
||||
; copy memory
|
||||
|
||||
|
||||
.export copymem
|
||||
.exportzp copy_src
|
||||
.exportzp copy_dest
|
||||
|
||||
|
||||
.segment "IP65ZP" : zeropage
|
||||
|
||||
; pointers for copying
|
||||
copy_src: .res 2 ; source pointer
|
||||
copy_dest: .res 2 ; destination pointer
|
||||
|
||||
|
||||
.bss
|
||||
|
||||
end: .res 1
|
||||
|
||||
|
||||
.code
|
||||
|
||||
; copy memory
|
||||
; set copy_src and copy_dest, length in A/X
|
||||
copymem:
|
||||
sta end
|
||||
ldy #0
|
||||
|
||||
cpx #0
|
||||
beq @tail
|
||||
|
||||
: lda (copy_src),y
|
||||
sta (copy_dest),y
|
||||
iny
|
||||
bne :-
|
||||
inc copy_src+1 ;next page
|
||||
inc copy_dest+1 ;next page
|
||||
dex
|
||||
bne :-
|
||||
|
||||
@tail:
|
||||
lda end
|
||||
beq @done
|
||||
|
||||
: lda (copy_src),y
|
||||
sta (copy_dest),y
|
||||
iny
|
||||
cpy end
|
||||
bne :-
|
||||
|
||||
@done:
|
||||
rts
|
@ -1,7 +0,0 @@
|
||||
;originally from Per Olofsson's IP65 library - http://www.paradroid.net/ip65
|
||||
|
||||
pp_rx_ctl = $0104
|
||||
pp_line_ctl = $0112
|
||||
pp_self_ctl = $0114
|
||||
pp_bus_status = $0138
|
||||
pp_ia = $0158
|
275
ip65/cs8900a.s
275
ip65/cs8900a.s
@ -1,275 +0,0 @@
|
||||
;originally from Per Olofsson's IP65 library - http://www.paradroid.net/ip65
|
||||
|
||||
; Ethernet driver for CS8900A
|
||||
;
|
||||
; Based on Doc Bacardi's tftp source
|
||||
|
||||
|
||||
.include "../inc/common.i"
|
||||
.include "cs8900a.i"
|
||||
|
||||
|
||||
;.import dbg_dump_eth_header
|
||||
|
||||
|
||||
.export eth_init
|
||||
.export eth_rx
|
||||
.export eth_tx
|
||||
|
||||
.export eth_inp
|
||||
.export eth_inp_len
|
||||
.export eth_outp
|
||||
.export eth_outp_len
|
||||
|
||||
.exportzp eth_dest
|
||||
.exportzp eth_src
|
||||
.exportzp eth_type
|
||||
.exportzp eth_data
|
||||
|
||||
.import cs_init
|
||||
.import cs_packet_page
|
||||
.import cs_packet_data
|
||||
.import cs_rxtx_data
|
||||
.import cs_tx_cmd
|
||||
.import cs_tx_len
|
||||
|
||||
.import cfg_mac
|
||||
|
||||
|
||||
.macro write_page page, value
|
||||
lda #page/2
|
||||
ldx #<value
|
||||
ldy #>value
|
||||
jsr cs_write_page
|
||||
.endmacro
|
||||
|
||||
|
||||
.segment "IP65ZP" : zeropage
|
||||
|
||||
eth_packet: .res 2
|
||||
|
||||
|
||||
.bss
|
||||
|
||||
; input and output buffers
|
||||
eth_inp_len: .res 2 ; input packet length
|
||||
eth_inp: .res 1518 ; space for input packet
|
||||
eth_outp_len: .res 2 ; output packet length
|
||||
eth_outp: .res 1518 ; space for output packet
|
||||
|
||||
; ethernet packet offsets
|
||||
eth_dest = 0 ; destination address
|
||||
eth_src = 6 ; source address
|
||||
eth_type = 12 ; packet type
|
||||
eth_data = 14 ; packet data
|
||||
|
||||
|
||||
.code
|
||||
|
||||
; initialize, return clc on success
|
||||
eth_init:
|
||||
jsr cs_init
|
||||
|
||||
lda #0 ; check magic signature
|
||||
jsr cs_read_page
|
||||
cpx #$0e
|
||||
bne @notfound
|
||||
cpy #$63
|
||||
bne @notfound
|
||||
|
||||
lda #1
|
||||
jsr cs_read_page
|
||||
cpx #0
|
||||
bne @notfound
|
||||
; y contains chip rev
|
||||
|
||||
write_page pp_self_ctl, $0055 ; $0114, reset chip
|
||||
|
||||
write_page pp_rx_ctl, $0d05 ; $0104, accept individual and broadcast packets
|
||||
;write_page pp_rx_ctl, $0d85 ; $0104, promiscuous mode
|
||||
|
||||
lda #pp_ia/2 ; $0158, write mac address
|
||||
ldx cfg_mac
|
||||
ldy cfg_mac + 1
|
||||
jsr cs_write_page
|
||||
|
||||
lda #pp_ia/2 + 1
|
||||
ldx cfg_mac + 2
|
||||
ldy cfg_mac + 3
|
||||
jsr cs_write_page
|
||||
|
||||
lda #pp_ia/2 + 2
|
||||
ldx cfg_mac + 4
|
||||
ldy cfg_mac + 5
|
||||
jsr cs_write_page
|
||||
|
||||
write_page pp_line_ctl, $00d3 ; $0112, enable rx and tx
|
||||
|
||||
clc
|
||||
rts
|
||||
|
||||
@notfound:
|
||||
sec
|
||||
rts
|
||||
|
||||
|
||||
; receive a packet
|
||||
eth_rx:
|
||||
lda #$24 ; check rx status
|
||||
sta cs_packet_page
|
||||
lda #$01
|
||||
sta cs_packet_page + 1
|
||||
|
||||
lda cs_packet_data + 1
|
||||
and #$0d
|
||||
bne :+
|
||||
|
||||
sec ; no packet ready
|
||||
rts
|
||||
|
||||
: lda cs_rxtx_data + 1 ; ignore status
|
||||
lda cs_rxtx_data
|
||||
|
||||
lda cs_rxtx_data + 1 ; read packet length
|
||||
sta eth_inp_len + 1
|
||||
tax ; save
|
||||
lda cs_rxtx_data
|
||||
sta eth_inp_len
|
||||
|
||||
lda #<eth_inp ; set packet pointer
|
||||
sta eth_packet
|
||||
lda #>eth_inp
|
||||
sta eth_packet + 1
|
||||
|
||||
ldy #0
|
||||
cpx #0 ; < 256 bytes left?
|
||||
beq @tail
|
||||
|
||||
@get256:
|
||||
lda cs_rxtx_data
|
||||
sta (eth_packet),y
|
||||
iny
|
||||
lda cs_rxtx_data + 1
|
||||
sta (eth_packet),y
|
||||
iny
|
||||
bne @get256
|
||||
inc eth_packet + 1
|
||||
dex
|
||||
bne @get256
|
||||
|
||||
@tail:
|
||||
lda eth_inp_len ; bytes left / 2, round up
|
||||
lsr
|
||||
adc #0
|
||||
beq @done
|
||||
tax
|
||||
|
||||
@get:
|
||||
lda cs_rxtx_data
|
||||
sta (eth_packet),y
|
||||
iny
|
||||
lda cs_rxtx_data + 1
|
||||
sta (eth_packet),y
|
||||
iny
|
||||
dex
|
||||
bne @get
|
||||
|
||||
@done:
|
||||
clc
|
||||
rts
|
||||
|
||||
|
||||
; send a packet
|
||||
eth_tx:
|
||||
;jsr dbg_dump_eth_header
|
||||
|
||||
lda #$c9 ; ask for buffer space
|
||||
sta cs_tx_cmd
|
||||
lda #0
|
||||
sta cs_tx_cmd + 1
|
||||
|
||||
lda eth_outp_len ; set length
|
||||
sta cs_tx_len
|
||||
lda eth_outp_len + 1
|
||||
sta cs_tx_len + 1
|
||||
and #$f8
|
||||
beq :+
|
||||
|
||||
inc $d020
|
||||
sec ; oversized packet
|
||||
rts
|
||||
|
||||
: lda #<pp_bus_status ; select bus status register
|
||||
sta cs_packet_page
|
||||
lda #>pp_bus_status
|
||||
sta cs_packet_page + 1
|
||||
|
||||
@waitspace:
|
||||
lda cs_packet_data + 1 ; wait for space
|
||||
ldx cs_packet_data
|
||||
lsr
|
||||
bcs @gotspace
|
||||
jsr @done ; polling too fast doesn't work, delay added by David Schmidt
|
||||
jmp @waitspace
|
||||
@gotspace:
|
||||
ldax #eth_outp ; send packet
|
||||
stax eth_packet
|
||||
|
||||
ldy #0
|
||||
ldx eth_outp_len + 1
|
||||
beq @tail
|
||||
|
||||
@send256:
|
||||
lda (eth_packet),y
|
||||
sta cs_rxtx_data
|
||||
iny
|
||||
lda (eth_packet),y
|
||||
sta cs_rxtx_data + 1
|
||||
iny
|
||||
bne @send256
|
||||
inc eth_packet + 1
|
||||
dex
|
||||
bne @send256
|
||||
|
||||
@tail:
|
||||
ldx eth_outp_len
|
||||
beq @done
|
||||
|
||||
@send:
|
||||
lda (eth_packet),y
|
||||
sta cs_rxtx_data
|
||||
dex
|
||||
beq @done
|
||||
iny
|
||||
lda (eth_packet),y
|
||||
sta cs_rxtx_data + 1
|
||||
iny
|
||||
dex
|
||||
bne @send
|
||||
|
||||
@done: ; also used by timeout code above
|
||||
clc
|
||||
rts
|
||||
|
||||
|
||||
; read X/Y from page A * 2
|
||||
cs_read_page:
|
||||
asl
|
||||
sta cs_packet_page
|
||||
lda #0
|
||||
rol
|
||||
sta cs_packet_page + 1
|
||||
ldx cs_packet_data
|
||||
ldy cs_packet_data + 1
|
||||
rts
|
||||
|
||||
; write X/Y to page A * 2
|
||||
cs_write_page:
|
||||
asl
|
||||
sta cs_packet_page
|
||||
lda #0
|
||||
rol
|
||||
sta cs_packet_page + 1
|
||||
stx cs_packet_data
|
||||
sty cs_packet_data + 1
|
||||
rts
|
130
ip65/debug.s
130
ip65/debug.s
@ -1,130 +0,0 @@
|
||||
;originally from Per Olofsson's IP65 library - http://www.paradroid.net/ip65
|
||||
|
||||
.include "../inc/common.i"
|
||||
.include "../inc/printf.i"
|
||||
|
||||
|
||||
.export dbgout16
|
||||
.export dbg_dump_eth_header
|
||||
.export dbg_dump_ip_header
|
||||
.export dbg_dump_udp_header
|
||||
|
||||
.export console_out
|
||||
.export console_strout
|
||||
|
||||
|
||||
.import eth_outp, eth_outp_len
|
||||
.import ip_outp
|
||||
.import udp_outp
|
||||
|
||||
|
||||
.segment "IP65ZP" : zeropage
|
||||
|
||||
cptr: .res 2
|
||||
|
||||
|
||||
.code
|
||||
|
||||
|
||||
dbg_dump_eth_header:
|
||||
pha
|
||||
txa
|
||||
pha
|
||||
tya
|
||||
pha
|
||||
|
||||
printf "\rethernet header:\r"
|
||||
printf "len: %04x\r", eth_outp_len
|
||||
printf "dest: %04x:%04x:%04x\r", eth_outp, eth_outp + 2, eth_outp + 4
|
||||
printf "src: %04x:%04x:%04x\r", eth_outp + 6, eth_outp + 8, eth_outp + 10
|
||||
printf "type: %04x\r", eth_outp + 12
|
||||
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
rts
|
||||
|
||||
|
||||
dbg_dump_ip_header:
|
||||
pha
|
||||
txa
|
||||
pha
|
||||
tya
|
||||
pha
|
||||
|
||||
printf "\rip header:\r"
|
||||
printf "ver,ihl,tos: %04x\r", ip_outp
|
||||
printf "len: %04x\r", ip_outp + 2
|
||||
printf "id: %04x\r", ip_outp + 4
|
||||
printf "frag: %04x\r", ip_outp + 6
|
||||
printf "ttl: %02x\r", ip_outp + 8
|
||||
printf "proto: %02x\r", ip_outp + 9
|
||||
printf "cksum: %04x\r", ip_outp + 10
|
||||
printf "src: %04x%04x\r", ip_outp + 12, ip_outp + 14
|
||||
printf "dest: %04x%04x\r", ip_outp + 16, ip_outp + 18
|
||||
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
rts
|
||||
|
||||
|
||||
dbg_dump_udp_header:
|
||||
pha
|
||||
txa
|
||||
pha
|
||||
tya
|
||||
pha
|
||||
|
||||
printf "\rudp header:\r"
|
||||
printf "srcport: %04x\r", ip_outp
|
||||
printf "destport: %04x\r", ip_outp + 2
|
||||
printf "len: %04x\r", ip_outp + 4
|
||||
printf "cksum: %04x\r", ip_outp + 6
|
||||
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
rts
|
||||
|
||||
|
||||
console_out = $ffd2
|
||||
|
||||
console_strout:
|
||||
stax cptr
|
||||
|
||||
pha
|
||||
txa
|
||||
pha
|
||||
tya
|
||||
pha
|
||||
ldy #0
|
||||
: lda (cptr),y
|
||||
beq @done
|
||||
jsr console_out
|
||||
iny
|
||||
bne :-
|
||||
@done:
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
rts
|
||||
|
||||
|
||||
dbgout16:
|
||||
stax val16
|
||||
printf "%04x", val16
|
||||
rts
|
||||
|
||||
|
||||
.bss
|
||||
|
||||
val16: .res 2
|
448
ip65/dhcp.s
448
ip65/dhcp.s
@ -1,448 +0,0 @@
|
||||
;########################
|
||||
; minimal dhcp implementation
|
||||
; written by jonno@jamtronix.com 2009
|
||||
;
|
||||
;########################
|
||||
; to use - first call ip65_init, then call dhcp_init
|
||||
; no inputs required.
|
||||
; on return, carry flag clear means IP config has been
|
||||
; sucesfully obtained (cfg_ip, cfg_netmask, cfg_gateway and cfg_dns set as appropriate).
|
||||
; if carry flag is set, IP config could not be set. that could be because of a network
|
||||
; error or because there was no response from a DHCP server within about 5 seconds.
|
||||
;########################
|
||||
|
||||
|
||||
MAX_DHCP_MESSAGES_SENT=12 ;timeout after sending 12 messages will be about 15 seconds (1+2+3...)/4
|
||||
|
||||
.include "../inc/common.i"
|
||||
.export dhcp_init
|
||||
.export dhcp_server
|
||||
.export dhcp_state
|
||||
|
||||
.import cfg_mac
|
||||
.import cfg_ip
|
||||
.import cfg_netmask
|
||||
.import cfg_gateway
|
||||
.import cfg_dns
|
||||
|
||||
.import arp_init
|
||||
|
||||
.import ip65_process
|
||||
|
||||
.import udp_add_listener
|
||||
.import udp_remove_listener
|
||||
|
||||
.import udp_callback
|
||||
.import udp_send
|
||||
|
||||
.import udp_inp
|
||||
|
||||
.importzp udp_data
|
||||
|
||||
.import udp_send_dest
|
||||
.import udp_send_src_port
|
||||
.import udp_send_dest_port
|
||||
.import udp_send_len
|
||||
|
||||
.import timer_read
|
||||
|
||||
.bss
|
||||
|
||||
; dhcp packet offsets
|
||||
dhcp_inp = udp_inp + udp_data
|
||||
dhcp_outp: .res 576
|
||||
dhcp_op = 0
|
||||
dhcp_htype = 1
|
||||
dhcp_hlen = 2
|
||||
dhcp_hops = 3
|
||||
dhcp_xid = 4
|
||||
dhcp_secs = 8
|
||||
dhcp_flags = 10
|
||||
dhcp_ciaddr = 12
|
||||
dhcp_yiaddr = 16
|
||||
dhcp_siaddr = 20
|
||||
dhcp_giaddr = 24
|
||||
dhcp_chaddr =28
|
||||
dhcp_sname = 44
|
||||
dhcp_file=108
|
||||
dhcp_cookie=236
|
||||
dhcp_options=240
|
||||
|
||||
dhcp_server_port=67
|
||||
dhcp_client_port=68
|
||||
|
||||
|
||||
; dhcp state machine
|
||||
dhcp_initializing = 1 ; initial state
|
||||
dhcp_selecting = 2 ; sent a DHCPDISCOVER, waiting for a DHCPOFFER
|
||||
dhcp_ready_to_request = 3 ; got a DHCPOFFER, ready to send a DHCPREQUEST
|
||||
dhcp_requesting = 4 ; sent a DHCPREQUEST, waiting for a DHCPACK
|
||||
dhcp_bound = 5 ; we have been allocated an IP address
|
||||
|
||||
dhcp_state: .res 1 ; current activity
|
||||
|
||||
dhcp_message_sent_count: .res 1
|
||||
dhcp_timer: .res 1
|
||||
dhcp_loop_count: .res 1
|
||||
dhcp_break_polling_loop: .res 1
|
||||
|
||||
dhcp_server: .res 4
|
||||
|
||||
;DHCP constants
|
||||
BOOTREQUEST =1
|
||||
BOOTREPLY =2
|
||||
|
||||
DHCPDISCOVER =1
|
||||
DHCPOFFER =2
|
||||
DHCPREQUEST =3
|
||||
DHCPDECLINE =4
|
||||
DHCPACK =5
|
||||
DHCPNAK =6
|
||||
DHCPRELEASE =7
|
||||
DHCPINFORM =8
|
||||
|
||||
|
||||
.code
|
||||
|
||||
dhcp_init:
|
||||
|
||||
|
||||
ldx #3 ; rewrite ip address
|
||||
lda #0
|
||||
: sta cfg_ip,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
lda #dhcp_initializing
|
||||
sta dhcp_state
|
||||
|
||||
ldax #dhcp_in
|
||||
stax udp_callback
|
||||
ldax #dhcp_client_port
|
||||
jsr udp_add_listener
|
||||
bcc :+
|
||||
rts
|
||||
:
|
||||
lda #0 ;reset the "message sent" counter
|
||||
sta dhcp_message_sent_count
|
||||
jsr send_dhcpdiscover
|
||||
|
||||
@dhcp_polling_loop:
|
||||
|
||||
lda dhcp_message_sent_count
|
||||
adc #1
|
||||
sta dhcp_loop_count ;we wait a bit longer between each resend
|
||||
|
||||
@outer_delay_loop:
|
||||
lda #0
|
||||
sta dhcp_break_polling_loop
|
||||
jsr timer_read
|
||||
stx dhcp_timer ;we only care about the high byte
|
||||
|
||||
@inner_delay_loop:
|
||||
jsr ip65_process
|
||||
lda #0
|
||||
cmp dhcp_break_polling_loop
|
||||
bne @break_polling_loop
|
||||
jsr timer_read
|
||||
cpx dhcp_timer ;this will tick over after about 1/4 of a second
|
||||
beq @inner_delay_loop
|
||||
|
||||
dec dhcp_loop_count
|
||||
bne @outer_delay_loop
|
||||
|
||||
@break_polling_loop:
|
||||
|
||||
inc dhcp_message_sent_count
|
||||
lda dhcp_message_sent_count
|
||||
cmp #MAX_DHCP_MESSAGES_SENT-1
|
||||
bpl @too_many_messages_sent
|
||||
lda dhcp_state
|
||||
cmp #dhcp_initializing
|
||||
beq @initializing
|
||||
cmp #dhcp_selecting
|
||||
beq @selecting
|
||||
cmp #dhcp_ready_to_request
|
||||
beq @ready_to_request
|
||||
cmp #dhcp_bound
|
||||
beq @bound
|
||||
jmp @dhcp_polling_loop
|
||||
@initializing:
|
||||
@selecting:
|
||||
jsr send_dhcpdiscover
|
||||
jmp @dhcp_polling_loop
|
||||
|
||||
@ready_to_request:
|
||||
jsr send_dhcprequest
|
||||
jmp @dhcp_polling_loop
|
||||
|
||||
@bound:
|
||||
ldax #dhcp_client_port
|
||||
jsr udp_remove_listener
|
||||
rts
|
||||
|
||||
@too_many_messages_sent:
|
||||
sec ;signal an error
|
||||
rts
|
||||
|
||||
dhcp_create_request_msg:
|
||||
lda #BOOTREQUEST
|
||||
sta dhcp_outp+dhcp_op
|
||||
lda #1 ;htype 1 = "10 MB ethernet"
|
||||
sta dhcp_outp+dhcp_htype
|
||||
lda #6 ;ethernet MACs are 6 bytes
|
||||
sta dhcp_outp+dhcp_hlen
|
||||
lda #0 ;hops = 0
|
||||
sta dhcp_outp+dhcp_hops
|
||||
ldx #3 ;set xid to be "1234"
|
||||
clc
|
||||
: txa
|
||||
adc #01
|
||||
sta dhcp_outp+dhcp_xid,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
lda #0 ;secs =00
|
||||
sta dhcp_outp+dhcp_secs
|
||||
sta dhcp_outp+dhcp_secs+1
|
||||
;initially turn off all flags
|
||||
sta dhcp_outp+dhcp_flags
|
||||
sta dhcp_outp+dhcp_flags+1
|
||||
|
||||
ldx #$0F ;set ciaddr to 0.0.0.0
|
||||
;set yiaddr to 0.0.0.0
|
||||
;set siaddr to 0.0.0.0
|
||||
;set giaddr to 0.0.0.0
|
||||
: sta dhcp_outp+dhcp_ciaddr,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
ldx #5 ;set chaddr to mac
|
||||
: lda cfg_mac,x
|
||||
sta dhcp_outp+dhcp_chaddr,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
ldx #192 ;set sname & file both to null
|
||||
lda #0
|
||||
: sta dhcp_outp+dhcp_sname-1,x
|
||||
dex
|
||||
bne :-
|
||||
|
||||
|
||||
lda #$63 ;copy the magic cookie
|
||||
sta dhcp_outp+dhcp_cookie+0
|
||||
lda #$82
|
||||
sta dhcp_outp+dhcp_cookie+1
|
||||
lda #$53
|
||||
sta dhcp_outp+dhcp_cookie+2
|
||||
lda #$63
|
||||
sta dhcp_outp+dhcp_cookie+3
|
||||
|
||||
ldax #dhcp_client_port ; set source port
|
||||
stax udp_send_src_port
|
||||
|
||||
ldax #dhcp_server_port ; set destination port
|
||||
stax udp_send_dest_port
|
||||
|
||||
rts
|
||||
|
||||
send_dhcpdiscover:
|
||||
lda #dhcp_initializing
|
||||
sta dhcp_state
|
||||
|
||||
jsr dhcp_create_request_msg
|
||||
|
||||
lda #$80 ;broadcast flag =1, all other bits 0
|
||||
sta dhcp_outp+dhcp_flags
|
||||
|
||||
lda #53 ;option 53 - DHCP message type
|
||||
sta dhcp_outp+dhcp_options+0
|
||||
lda #1 ;option length is 1
|
||||
sta dhcp_outp+dhcp_options+1
|
||||
lda #DHCPDISCOVER
|
||||
sta dhcp_outp+dhcp_options+2
|
||||
lda #$FF ;option FF = end of options
|
||||
sta dhcp_outp+dhcp_options+3
|
||||
|
||||
ldx #3 ; set destination address
|
||||
lda #$FF ; des = 255.255.255.255 (broadcast)
|
||||
: sta udp_send_dest,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
ldax #dhcp_options+4
|
||||
stax udp_send_len
|
||||
ldax #dhcp_outp
|
||||
jsr udp_send
|
||||
bcc :+
|
||||
rts
|
||||
|
||||
: lda #dhcp_selecting
|
||||
sta dhcp_state
|
||||
rts
|
||||
|
||||
;got a message on port 68
|
||||
dhcp_in:
|
||||
|
||||
lda dhcp_inp+dhcp_op
|
||||
cmp #BOOTREPLY
|
||||
beq :+
|
||||
rts ;it's not what we were expecting
|
||||
:
|
||||
|
||||
lda #0
|
||||
cmp dhcp_inp+dhcp_yiaddr ;is the first byte in the assigned address 0?
|
||||
bne :+
|
||||
rts ;if so, it's a bogus response - ignore
|
||||
:
|
||||
ldx #4 ;copy the our new IP address
|
||||
:
|
||||
lda dhcp_inp+dhcp_yiaddr,x
|
||||
sta cfg_ip,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
ldx #0
|
||||
@unpack_dhcp_options:
|
||||
lda dhcp_inp+dhcp_options,x
|
||||
cmp #$ff
|
||||
bne :+
|
||||
jmp @finished_unpacking_dhcp_options
|
||||
:
|
||||
cmp #53 ;is this field DHCP message type?
|
||||
bne @not_dhcp_message_type
|
||||
jmp @get_next_option
|
||||
lda dhcp_inp+dhcp_options+2,x
|
||||
cmp #DHCPOFFER ;if it's not a DHCP OFFER message, then stop processing
|
||||
beq :+
|
||||
rts
|
||||
: jmp @get_next_option
|
||||
|
||||
@not_dhcp_message_type:
|
||||
|
||||
cmp #1 ;option 1 is netmask
|
||||
bne @not_netmask
|
||||
lda dhcp_inp+dhcp_options+2,x
|
||||
sta cfg_netmask
|
||||
lda dhcp_inp+dhcp_options+3,x
|
||||
sta cfg_netmask+1
|
||||
lda dhcp_inp+dhcp_options+4,x
|
||||
sta cfg_netmask+2
|
||||
lda dhcp_inp+dhcp_options+5,x
|
||||
sta cfg_netmask+3
|
||||
jmp @get_next_option
|
||||
|
||||
@not_netmask:
|
||||
|
||||
cmp #3 ;option 3 is gateway
|
||||
bne @not_gateway
|
||||
lda dhcp_inp+dhcp_options+2,x
|
||||
sta cfg_gateway
|
||||
lda dhcp_inp+dhcp_options+3,x
|
||||
sta cfg_gateway+1
|
||||
lda dhcp_inp+dhcp_options+4,x
|
||||
sta cfg_gateway+2
|
||||
lda dhcp_inp+dhcp_options+5,x
|
||||
sta cfg_gateway+3
|
||||
jmp @get_next_option
|
||||
|
||||
@not_gateway:
|
||||
|
||||
cmp #6 ;option 3 6 is dns server
|
||||
bne @not_dns_server
|
||||
lda dhcp_inp+dhcp_options+2,x
|
||||
sta cfg_dns
|
||||
lda dhcp_inp+dhcp_options+3,x
|
||||
sta cfg_dns+1
|
||||
lda dhcp_inp+dhcp_options+4,x
|
||||
sta cfg_dns+2
|
||||
lda dhcp_inp+dhcp_options+5,x
|
||||
sta cfg_dns+3
|
||||
jmp @get_next_option
|
||||
|
||||
@not_dns_server:
|
||||
|
||||
cmp #54 ;option 54 is DHCP server
|
||||
bne @not_server
|
||||
lda dhcp_inp+dhcp_options+2,x
|
||||
sta dhcp_server
|
||||
lda dhcp_inp+dhcp_options+3,x
|
||||
sta dhcp_server+1
|
||||
lda dhcp_inp+dhcp_options+4,x
|
||||
sta dhcp_server+2
|
||||
lda dhcp_inp+dhcp_options+5,x
|
||||
sta dhcp_server+3
|
||||
jmp @get_next_option
|
||||
|
||||
@not_server:
|
||||
|
||||
|
||||
@get_next_option:
|
||||
txa
|
||||
clc
|
||||
adc #02
|
||||
adc dhcp_inp+dhcp_options+1,x
|
||||
bcs @finished_unpacking_dhcp_options ; if we overflow, then we're done
|
||||
tax
|
||||
jmp @unpack_dhcp_options
|
||||
|
||||
|
||||
@finished_unpacking_dhcp_options:
|
||||
jsr arp_init ;we have modified our netmask, so we need to recalculate gw_test
|
||||
lda dhcp_state
|
||||
cmp #dhcp_bound
|
||||
beq :+
|
||||
lda #dhcp_ready_to_request
|
||||
sta dhcp_state
|
||||
:
|
||||
lda #1
|
||||
sta dhcp_break_polling_loop
|
||||
|
||||
rts
|
||||
|
||||
send_dhcprequest:
|
||||
jsr dhcp_create_request_msg
|
||||
lda #53 ;option 53 - DHCP message type
|
||||
sta dhcp_outp+dhcp_options+0
|
||||
lda #1 ;option length is 1
|
||||
sta dhcp_outp+dhcp_options+1
|
||||
lda #DHCPREQUEST
|
||||
sta dhcp_outp+dhcp_options+2
|
||||
|
||||
lda #50 ;option 50 - requested IP address
|
||||
sta dhcp_outp+dhcp_options+3
|
||||
ldx #4 ;option length is 4
|
||||
stx dhcp_outp+dhcp_options+4
|
||||
dex
|
||||
: lda cfg_ip,x
|
||||
sta dhcp_outp+dhcp_options+5,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
lda #54 ;option 54 - DHCP server
|
||||
sta dhcp_outp+dhcp_options+9
|
||||
ldx #4 ;option length is 4
|
||||
stx dhcp_outp+dhcp_options+10
|
||||
dex
|
||||
|
||||
: lda dhcp_server,x
|
||||
sta dhcp_outp+dhcp_options+11,x
|
||||
sta udp_send_dest,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
|
||||
lda #$FF ;option FF = end of options
|
||||
sta dhcp_outp+dhcp_options+17
|
||||
|
||||
ldax #dhcp_options+18
|
||||
stax udp_send_len
|
||||
|
||||
ldax #dhcp_outp
|
||||
jsr udp_send
|
||||
bcs :+ ;if we didn't send the message we probably need to wait for an ARP reply to come back.
|
||||
lda #dhcp_bound ;technically, we should wait till we get a DHCPACK message. but we'll assume success
|
||||
sta dhcp_state
|
||||
:
|
||||
rts
|
414
ip65/dns.s
414
ip65/dns.s
@ -1,414 +0,0 @@
|
||||
;########################
|
||||
; minimal dns implementation
|
||||
; requires a DNS server that supports recursion
|
||||
; written by jonno@jamtronix.com 2009
|
||||
;
|
||||
;########################
|
||||
; to use -
|
||||
; ensure cfg_dns points to a DNS server that supports recursion
|
||||
; call dns_set_hostname with AX pointing to null terminated hostname
|
||||
; then call dns_resolve
|
||||
; on exit: carry flag is set if there was an error. if carry flag is clear, then dns_ip will point to the
|
||||
; IP address of the hostname
|
||||
;########################
|
||||
|
||||
|
||||
MAX_DNS_MESSAGES_SENT=8 ;timeout after sending 8 messages will be about 7 seconds (1+2+3+4+5+6+7+8)/4
|
||||
|
||||
.include "../inc/common.i"
|
||||
|
||||
.export dns_set_hostname
|
||||
.export dns_resolve
|
||||
.export dns_ip
|
||||
.export dns_status
|
||||
|
||||
.import cfg_dns
|
||||
|
||||
.import ip65_process
|
||||
|
||||
.import udp_add_listener
|
||||
.import udp_remove_listener
|
||||
|
||||
.import udp_callback
|
||||
.import udp_send
|
||||
|
||||
.import udp_inp
|
||||
|
||||
.importzp udp_data
|
||||
|
||||
.import udp_send_dest
|
||||
.import udp_send_src_port
|
||||
.import udp_send_dest_port
|
||||
.import udp_send_len
|
||||
|
||||
.import timer_read
|
||||
|
||||
.segment "IP65ZP" : zeropage
|
||||
|
||||
dns_hostname: .res 2
|
||||
|
||||
.bss
|
||||
|
||||
; dns packet offsets
|
||||
dns_inp = udp_inp + udp_data
|
||||
dns_outp: .res 256
|
||||
dns_id = 0
|
||||
dns_flags=2
|
||||
dns_qdcount=4
|
||||
dns_ancount=6
|
||||
dns_nscount=8
|
||||
dns_arcount=10
|
||||
dns_qname=12
|
||||
|
||||
dns_server_port=53
|
||||
dns_client_port_low_byte: .res 1
|
||||
|
||||
dns_ip: .res 4
|
||||
|
||||
dns_msg_id: .res 2
|
||||
|
||||
dns_current_label_length: .res 1
|
||||
dns_current_label_offset: .res 1
|
||||
|
||||
dns_message_sent_count: .res 1
|
||||
|
||||
dns_packed_hostname: .res 128
|
||||
|
||||
; dns state machine
|
||||
dns_initializing = 1 ; initial state
|
||||
dns_query_sent = 2 ; sent a query, waiting for a response
|
||||
dns_complete = 3 ; got a good response
|
||||
dns_failed = 4 ; got either a 'no such name' or 'recursion declined' response
|
||||
|
||||
dns_state: .res 1 ; current activity
|
||||
dns_timer: .res 1
|
||||
dns_loop_count: .res 1
|
||||
dns_break_polling_loop: .res 1
|
||||
|
||||
dns_status: .res 2
|
||||
|
||||
hostname_copied: .res 1
|
||||
|
||||
questions_in_response: .res 1
|
||||
|
||||
|
||||
.code
|
||||
|
||||
dns_set_hostname:
|
||||
stax dns_hostname
|
||||
;copy the hostname into a buffer suitable to copy directly into the qname field
|
||||
;we need to split on dots
|
||||
ldy #0 ;input pointer
|
||||
ldx #1 ;output pointer (start at 1, to skip first length offset, which will be filled in later)
|
||||
|
||||
sty dns_current_label_length
|
||||
sty dns_current_label_offset
|
||||
sty hostname_copied
|
||||
|
||||
@next_hostname_byte:
|
||||
lda (dns_hostname),y ;get next char in hostname
|
||||
cmp #0 ;are we at the end of the string?
|
||||
bne :+
|
||||
inc hostname_copied
|
||||
bne @set_length_of_last_label
|
||||
:
|
||||
|
||||
cmp #'.' ;do we need to split the labels?
|
||||
bne @not_a_dot
|
||||
@set_length_of_last_label:
|
||||
txa
|
||||
pha
|
||||
lda dns_current_label_length
|
||||
ldx dns_current_label_offset
|
||||
sta dns_packed_hostname,x
|
||||
lda #0
|
||||
sta dns_current_label_length
|
||||
pla
|
||||
tax
|
||||
stx dns_current_label_offset
|
||||
lda hostname_copied
|
||||
beq @update_counters
|
||||
jmp @hostname_done
|
||||
@not_a_dot:
|
||||
sta dns_packed_hostname,x
|
||||
inc dns_current_label_length
|
||||
|
||||
@update_counters:
|
||||
iny
|
||||
inx
|
||||
bmi @hostname_too_long ;don't allow a hostname of more than 128 bytes
|
||||
jmp @next_hostname_byte
|
||||
|
||||
@hostname_done:
|
||||
|
||||
lda dns_packed_hostname-1,x ;get the last byte we wrote out
|
||||
beq :+ ;was it a zero?
|
||||
lda #0
|
||||
sta dns_packed_hostname,x ;write a trailing zero (i.e. a zero length label)
|
||||
inx
|
||||
:
|
||||
clc ;no error
|
||||
|
||||
rts
|
||||
|
||||
@hostname_too_long:
|
||||
sec
|
||||
rts
|
||||
|
||||
dns_resolve:
|
||||
ldax #dns_in
|
||||
stax udp_callback
|
||||
lda #53
|
||||
inc dns_client_port_low_byte ;each call to resolve uses a different client address
|
||||
ldx dns_client_port_low_byte ;so we don't get confused by late replies to a previous call
|
||||
jsr udp_add_listener
|
||||
|
||||
bcc :+
|
||||
rts
|
||||
:
|
||||
|
||||
lda #dns_initializing
|
||||
sta dns_state
|
||||
lda #0 ;reset the "message sent" counter
|
||||
sta dns_message_sent_count
|
||||
|
||||
jsr send_dns_query
|
||||
|
||||
@dns_polling_loop:
|
||||
lda dns_message_sent_count
|
||||
adc #1
|
||||
sta dns_loop_count ;we wait a bit longer between each resend
|
||||
@outer_delay_loop:
|
||||
lda #0
|
||||
sta dns_break_polling_loop
|
||||
jsr timer_read
|
||||
stx dns_timer ;we only care about the high byte
|
||||
|
||||
@inner_delay_loop:
|
||||
jsr ip65_process
|
||||
lda dns_state
|
||||
cmp #dns_complete
|
||||
beq @complete
|
||||
cmp #dns_failed
|
||||
beq @failed
|
||||
|
||||
lda #0
|
||||
cmp dns_break_polling_loop
|
||||
bne @break_polling_loop
|
||||
jsr timer_read
|
||||
cpx dns_timer ;this will tick over after about 1/4 of a second
|
||||
beq @inner_delay_loop
|
||||
|
||||
dec dns_loop_count
|
||||
bne @outer_delay_loop
|
||||
|
||||
@break_polling_loop:
|
||||
jsr send_dns_query
|
||||
inc dns_message_sent_count
|
||||
lda dns_message_sent_count
|
||||
cmp #MAX_DNS_MESSAGES_SENT-1
|
||||
bpl @too_many_messages_sent
|
||||
jmp @dns_polling_loop
|
||||
|
||||
@complete:
|
||||
lda #53
|
||||
ldx dns_client_port_low_byte
|
||||
jsr udp_remove_listener
|
||||
rts
|
||||
|
||||
@too_many_messages_sent:
|
||||
@failed:
|
||||
lda #53
|
||||
ldx dns_client_port_low_byte
|
||||
jsr udp_remove_listener
|
||||
sec ;signal an error
|
||||
rts
|
||||
|
||||
send_dns_query:
|
||||
|
||||
ldax dns_msg_id
|
||||
inx
|
||||
adc #0
|
||||
stax dns_msg_id
|
||||
stax dns_outp+dns_id
|
||||
|
||||
ldax #$0001 ;QR =0 (query), opcode=0 (query), AA=0, TC=0,RD=1,RA=0,Z=0,RCODE=0
|
||||
stax dns_outp+dns_flags
|
||||
ldax #$0100 ;we ask 1 question
|
||||
stax dns_outp+dns_qdcount
|
||||
ldax #$0000
|
||||
stax dns_outp+dns_ancount ;we send no answers
|
||||
stax dns_outp+dns_nscount ;we send no name servers
|
||||
stax dns_outp+dns_arcount ;we send no authorative records
|
||||
|
||||
ldx #0
|
||||
:
|
||||
lda dns_packed_hostname,x
|
||||
sta dns_outp+dns_qname,x
|
||||
inx
|
||||
bmi @error_on_send ;if we got past 128 bytes, there's a problem
|
||||
cmp #0
|
||||
bne :- ;keep looping until we have a zero byte.
|
||||
|
||||
lda #0
|
||||
sta dns_outp+dns_qname,x ;high byte of QTYPE=1 (A)
|
||||
sta dns_outp+dns_qname+2,x ;high byte of QLASS=1 (IN)
|
||||
lda #1
|
||||
sta dns_outp+dns_qname+1,x ;low byte of QTYPE=1 (A)
|
||||
sta dns_outp+dns_qname+3,x ;low byte of QLASS=1 (IN)
|
||||
|
||||
txa
|
||||
clc
|
||||
adc #(dns_qname+4)
|
||||
ldx #0
|
||||
stax udp_send_len
|
||||
|
||||
lda #53
|
||||
ldx dns_client_port_low_byte
|
||||
stax udp_send_src_port
|
||||
|
||||
ldx #3 ; set destination address
|
||||
: lda cfg_dns,x
|
||||
sta udp_send_dest,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
ldax #dns_server_port ; set destination port
|
||||
stax udp_send_dest_port
|
||||
ldax #dns_outp
|
||||
jsr udp_send
|
||||
bcs @error_on_send
|
||||
lda #dns_query_sent
|
||||
sta dns_state
|
||||
rts
|
||||
@error_on_send:
|
||||
|
||||
sec
|
||||
rts
|
||||
|
||||
dns_in:
|
||||
lda dns_inp+dns_flags+1 ;
|
||||
and #$0f ;get the RCODE
|
||||
cmp #0
|
||||
beq @not_an_error_response
|
||||
|
||||
sta dns_status ;anything non-zero is a permanent error (invalid domain, server doesn't support recursion etc)
|
||||
sta dns_status+1
|
||||
lda #dns_failed
|
||||
sta dns_state
|
||||
rts
|
||||
@not_an_error_response:
|
||||
lda dns_inp+dns_qdcount+1
|
||||
sta questions_in_response
|
||||
cmp #1 ;should be exactly 1 Q in the response (i.e. the one we sent)
|
||||
beq :+
|
||||
jmp @error_in_response
|
||||
:
|
||||
lda dns_inp+dns_ancount+1
|
||||
bne :+
|
||||
jmp @error_in_response ;should be at least 1 answer in response
|
||||
: ;we need to skip over the question (we will assume it's the question we just asked)
|
||||
ldx #dns_qname
|
||||
:
|
||||
lda dns_inp,x ;get next length byte in question
|
||||
beq :+ ; we're done if length==0
|
||||
clc
|
||||
txa
|
||||
|
||||
adc dns_inp,x ;add length of next label to ptr
|
||||
adc #1 ;+1 for the length byte itself
|
||||
tax
|
||||
bcs @error_in_response ;if we overflowed x, then message is too big
|
||||
bcc :-
|
||||
:
|
||||
inx ;skip past the nul byte
|
||||
lda dns_inp+1,x
|
||||
cmp #1 ;QTYPE should 1
|
||||
lda dns_inp+3,x
|
||||
cmp #1 ;QCLASS should 1
|
||||
bne @error_in_response
|
||||
|
||||
inx ;skip past the QTYPE/QCLASS
|
||||
inx
|
||||
inx
|
||||
inx
|
||||
|
||||
;x now points to the start of the answers
|
||||
|
||||
lda dns_inp,x
|
||||
bpl @error_in_response ;we are expecting the high bit to be set (we assume the server will send us back the answer to the question we just asked)
|
||||
inx ;skip past the compression
|
||||
inx
|
||||
;we are now pointing at the TYPE field
|
||||
lda dns_inp+1,x ;
|
||||
|
||||
cmp #5 ; is this a CNAME?
|
||||
bne @not_a_cname
|
||||
|
||||
|
||||
txa
|
||||
clc
|
||||
adc #10 ;skip 2 bytes TYPE, 2 bytes CLASS, 4 bytes TTL, 2 bytes RDLENGTH
|
||||
tax
|
||||
;we're now pointing at the CNAME record
|
||||
ldy #0 ;start of CNAME hostname
|
||||
:
|
||||
lda dns_inp,x
|
||||
beq @last_byte_of_cname
|
||||
bmi @found_compression_marker
|
||||
sta dns_packed_hostname,y
|
||||
inx
|
||||
iny
|
||||
bmi @error_in_response ;if we go past 128 bytes, something is wrong
|
||||
bpl :- ;go get next byte
|
||||
@last_byte_of_cname:
|
||||
sta dns_packed_hostname,y
|
||||
|
||||
lda #$ff ;set a status marker so we know whats going on
|
||||
sta dns_status
|
||||
stx dns_status+1
|
||||
|
||||
lda #1
|
||||
sta dns_break_polling_loop
|
||||
|
||||
rts ; finished processing - the main dns polling loop should now resend a query, this time for the hostname from the CNAME record
|
||||
|
||||
@found_compression_marker:
|
||||
lda dns_inp+1,x
|
||||
tax
|
||||
jmp :-
|
||||
|
||||
@not_a_cname:
|
||||
cmp #1 ; should be 1 (A record)
|
||||
bne @error_in_response
|
||||
txa
|
||||
clc
|
||||
adc #10 ;skip 2 bytes TYPE, 2 bytes CLASS, 4 bytes TTL, 2 bytes RDLENGTH
|
||||
tax
|
||||
;we're now pointing at the answer!
|
||||
lda dns_inp,x
|
||||
sta dns_ip
|
||||
|
||||
lda dns_inp+1,x
|
||||
sta dns_ip+1
|
||||
|
||||
lda dns_inp+2,x
|
||||
sta dns_ip+2
|
||||
|
||||
lda dns_inp+3,x
|
||||
sta dns_ip+3
|
||||
|
||||
|
||||
lda #dns_complete
|
||||
sta dns_state
|
||||
|
||||
lda #1
|
||||
sta dns_break_polling_loop
|
||||
|
||||
@error_in_response:
|
||||
|
||||
sta dns_status
|
||||
stx dns_status+1
|
||||
rts
|
||||
|
||||
|
55
ip65/eth.s
55
ip65/eth.s
@ -1,55 +0,0 @@
|
||||
;originally from Per Olofsson's IP65 library - http://www.paradroid.net/ip65
|
||||
|
||||
; Common ethernet driver code
|
||||
|
||||
|
||||
.include "../inc/common.i"
|
||||
|
||||
.export eth_set_broadcast_dest
|
||||
.export eth_set_my_mac_src
|
||||
.export eth_set_proto
|
||||
|
||||
.exportzp eth_proto_ip
|
||||
.exportzp eth_proto_arp
|
||||
|
||||
.import eth_outp
|
||||
|
||||
.import cfg_mac
|
||||
|
||||
|
||||
; ethernet packet offsets
|
||||
eth_dest = 0 ; destination address
|
||||
eth_src = 6 ; source address
|
||||
eth_type = 12 ; packet type
|
||||
eth_data = 14 ; packet data
|
||||
|
||||
; protocols
|
||||
eth_proto_ip = 0
|
||||
eth_proto_arp = 6
|
||||
|
||||
|
||||
.code
|
||||
|
||||
eth_set_broadcast_dest:
|
||||
ldx #5
|
||||
lda #$ff
|
||||
: sta eth_outp,x
|
||||
dex
|
||||
bpl :-
|
||||
rts
|
||||
|
||||
|
||||
eth_set_my_mac_src:
|
||||
ldx #5
|
||||
: lda cfg_mac,x
|
||||
sta eth_outp + 6,x
|
||||
dex
|
||||
bpl :-
|
||||
rts
|
||||
|
||||
|
||||
eth_set_proto:
|
||||
sta eth_outp + eth_type + 1
|
||||
lda #8
|
||||
sta eth_outp + eth_type
|
||||
rts
|
226
ip65/icmp.s
226
ip65/icmp.s
@ -1,226 +0,0 @@
|
||||
;originally from Per Olofsson's IP65 library - http://www.paradroid.net/ip65
|
||||
|
||||
.include "../inc/common.i"
|
||||
|
||||
.export icmp_init
|
||||
.export icmp_process
|
||||
.export icmp_add_listener
|
||||
.export icmp_remove_listener
|
||||
|
||||
.export icmp_callback
|
||||
|
||||
.export icmp_inp
|
||||
.export icmp_outp
|
||||
.exportzp icmp_type
|
||||
.exportzp icmp_code
|
||||
.exportzp icmp_cksum
|
||||
.exportzp icmp_data
|
||||
|
||||
|
||||
.import ip_calc_cksum
|
||||
.import ip_inp
|
||||
.import ip_outp
|
||||
.import ip_broadcast
|
||||
.importzp ip_cksum_ptr
|
||||
.importzp ip_header_cksum
|
||||
.importzp ip_src
|
||||
.importzp ip_dest
|
||||
.importzp ip_data
|
||||
|
||||
.import eth_tx
|
||||
.import eth_inp
|
||||
.import eth_inp_len
|
||||
.import eth_outp
|
||||
.import eth_outp_len
|
||||
|
||||
|
||||
.bss
|
||||
|
||||
; argument for icmp_add_listener
|
||||
icmp_callback: .res 2
|
||||
|
||||
; icmp callbacks
|
||||
icmp_cbmax = 4
|
||||
icmp_cbtmp: .res 3 ; temporary vector
|
||||
icmp_cbveclo: .res icmp_cbmax ; table of listener vectors (lsb)
|
||||
icmp_cbvechi: .res icmp_cbmax ; table of listener vectors (msb)
|
||||
icmp_cbtype: .res icmp_cbmax ; table of listener types
|
||||
icmp_cbcount: .res 1 ; number of active listeners
|
||||
|
||||
; icmp packet offsets
|
||||
icmp_inp = ip_inp + ip_data
|
||||
icmp_outp = ip_outp + ip_data
|
||||
icmp_type = 0
|
||||
icmp_code = 1
|
||||
icmp_cksum = 2
|
||||
icmp_data = 4
|
||||
|
||||
; icmp echo packet offsets
|
||||
icmp_echo_id = 4
|
||||
icmp_echo_seq = 6
|
||||
icmp_echo_data = 8
|
||||
|
||||
|
||||
.code
|
||||
|
||||
; initialize icmp
|
||||
icmp_init:
|
||||
lda #0
|
||||
sta icmp_cbcount
|
||||
lda #$4c ; jmp addr
|
||||
sta icmp_cbtmp
|
||||
rts
|
||||
|
||||
|
||||
; process incoming icmp packet
|
||||
icmp_process:
|
||||
lda icmp_inp + icmp_type
|
||||
cmp #8 ; ping
|
||||
beq @echo
|
||||
|
||||
lda icmp_cbcount ; any installed icmp listeners?
|
||||
beq @drop
|
||||
|
||||
ldx icmp_cbcount ; check listened types
|
||||
dex
|
||||
: lda icmp_cbtype,x
|
||||
cmp icmp_inp + icmp_type
|
||||
beq @handle ; found a match
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
@drop:
|
||||
sec
|
||||
rts
|
||||
|
||||
@handle:
|
||||
lda icmp_cbveclo,x ; copy vector
|
||||
sta icmp_cbtmp + 1
|
||||
lda icmp_cbvechi,x
|
||||
sta icmp_cbtmp + 2
|
||||
jsr icmp_cbtmp ; call listener
|
||||
clc
|
||||
rts
|
||||
|
||||
@echo:
|
||||
lda ip_broadcast ; check if packet is broadcast
|
||||
beq @notbc
|
||||
sec ; don't reply to broadcast pings
|
||||
rts
|
||||
@notbc:
|
||||
ldx #5
|
||||
: lda eth_inp,x ; swap dest and src mac
|
||||
sta eth_outp + 6,x
|
||||
lda eth_inp + 6,x
|
||||
sta eth_outp,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
ldx #12 ; copy the packet
|
||||
: lda eth_inp,x
|
||||
sta eth_outp,x
|
||||
inx
|
||||
cpx eth_inp_len
|
||||
bne :-
|
||||
|
||||
ldx #3
|
||||
: lda ip_inp + ip_src,x ; swap dest and src ip
|
||||
sta ip_outp + ip_dest,x
|
||||
lda ip_inp + ip_dest,x
|
||||
sta ip_outp + ip_src,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
lda #0 ; change type to reply
|
||||
sta icmp_outp + icmp_type
|
||||
|
||||
lda icmp_inp + icmp_cksum ; recalc checksum
|
||||
clc
|
||||
adc #8
|
||||
sta icmp_outp + icmp_cksum
|
||||
bcc :+
|
||||
inc icmp_outp + icmp_cksum + 1
|
||||
:
|
||||
lda eth_inp_len ; copy length
|
||||
sta eth_outp_len
|
||||
lda eth_inp_len + 1
|
||||
sta eth_outp_len + 1
|
||||
|
||||
lda #0 ; clear checksum
|
||||
sta ip_outp + ip_header_cksum
|
||||
sta ip_outp + ip_header_cksum + 1
|
||||
ldax #ip_outp ; calculate ip header checksum
|
||||
stax ip_cksum_ptr
|
||||
ldax #20
|
||||
jsr ip_calc_cksum
|
||||
stax ip_outp + ip_header_cksum
|
||||
|
||||
jsr eth_tx ; send packet
|
||||
|
||||
clc
|
||||
rts
|
||||
|
||||
|
||||
; add an icmp listener
|
||||
; icmp type in A, vector in icmp_callback
|
||||
icmp_add_listener:
|
||||
ldx icmp_cbcount ; any listeners at all?
|
||||
beq @add
|
||||
cpx #icmp_cbmax ; max?
|
||||
beq @full
|
||||
ldx #0
|
||||
: cmp icmp_cbtype,x ; check if type is already listened
|
||||
beq @busy
|
||||
inx
|
||||
cpx icmp_cbcount
|
||||
bne :-
|
||||
@add:
|
||||
inc icmp_cbcount ; increase counter
|
||||
sta icmp_cbtype,x ; add type
|
||||
lda icmp_callback ; and vector
|
||||
sta icmp_cbveclo,x
|
||||
lda icmp_callback + 1
|
||||
sta icmp_cbvechi,x
|
||||
|
||||
clc
|
||||
rts
|
||||
@full:
|
||||
@busy:
|
||||
sec
|
||||
rts
|
||||
|
||||
|
||||
; remove an icmp listener
|
||||
; icmp type in A
|
||||
icmp_remove_listener:
|
||||
ldx icmp_cbcount ; any listeners installed?
|
||||
beq @notfound
|
||||
: cmp icmp_cbtype,x ; check if type is listened
|
||||
beq @remove
|
||||
inx
|
||||
cpx icmp_cbcount
|
||||
bne :-
|
||||
@notfound:
|
||||
sec
|
||||
rts
|
||||
@remove:
|
||||
txa ; number of listeners below
|
||||
eor #$ff
|
||||
clc
|
||||
adc icmp_cbcount
|
||||
beq @done
|
||||
@move:
|
||||
tay ; number of items to move
|
||||
: lda icmp_cbtype + 1,x ; move type
|
||||
sta icmp_cbtype,x
|
||||
lda icmp_cbveclo + 1,x ; move vector lsb
|
||||
sta icmp_cbveclo,x
|
||||
lda icmp_cbvechi + 1,x ; move vector msb
|
||||
sta icmp_cbvechi,x
|
||||
inx
|
||||
dey
|
||||
bne :-
|
||||
@done:
|
||||
dec icmp_cbcount ; decrement counter
|
||||
clc
|
||||
rts
|
410
ip65/ip.s
410
ip65/ip.s
@ -1,410 +0,0 @@
|
||||
;originally from Per Olofsson's IP65 library - http://www.paradroid.net/ip65
|
||||
|
||||
.include "../inc/common.i"
|
||||
|
||||
;.import dbg_dump_ip_header
|
||||
|
||||
|
||||
.export ip_init
|
||||
.export ip_process
|
||||
.export ip_calc_cksum
|
||||
.export ip_create_packet
|
||||
.export ip_send
|
||||
|
||||
.export ip_inp
|
||||
.export ip_outp
|
||||
.export ip_broadcast
|
||||
.exportzp ip_cksum_ptr
|
||||
.exportzp ip_ver_ihl
|
||||
.exportzp ip_tos
|
||||
.exportzp ip_len
|
||||
.exportzp ip_id
|
||||
.exportzp ip_frag
|
||||
.exportzp ip_ttl
|
||||
.exportzp ip_proto
|
||||
.exportzp ip_header_cksum
|
||||
.exportzp ip_src
|
||||
.exportzp ip_dest
|
||||
.exportzp ip_data
|
||||
|
||||
.exportzp ip_proto_icmp
|
||||
.exportzp ip_proto_tcp
|
||||
.exportzp ip_proto_udp
|
||||
|
||||
|
||||
.import cfg_mac
|
||||
.import cfg_ip
|
||||
|
||||
.import eth_tx
|
||||
.import eth_set_proto
|
||||
.import eth_inp
|
||||
.import eth_inp_len
|
||||
.import eth_outp
|
||||
.import eth_outp_len
|
||||
|
||||
.importzp eth_dest
|
||||
.importzp eth_src
|
||||
.importzp eth_type
|
||||
.importzp eth_data
|
||||
.importzp eth_proto_ip
|
||||
.importzp eth_proto_arp
|
||||
|
||||
.import arp_lookup
|
||||
.import arp_mac
|
||||
.import arp_ip
|
||||
|
||||
.import icmp_init
|
||||
.import icmp_process
|
||||
|
||||
.import udp_init
|
||||
.import udp_process
|
||||
|
||||
.importzp copy_src
|
||||
|
||||
|
||||
.segment "IP65ZP" : zeropage
|
||||
|
||||
; checksum
|
||||
ip_cksum_ptr: .res 2 ; data pointer
|
||||
|
||||
|
||||
.bss
|
||||
|
||||
ip_cksum_len: .res 2 ; length of data
|
||||
|
||||
; ip packets start at ethernet packet + 14
|
||||
ip_inp = eth_inp + eth_data
|
||||
ip_outp = eth_outp + eth_data
|
||||
|
||||
; temp storage for size calculation
|
||||
len: .res 2
|
||||
|
||||
; flag for incoming broadcast packets
|
||||
ip_broadcast: .res 1
|
||||
|
||||
; ip packet offsets
|
||||
ip_ver_ihl = 0
|
||||
ip_tos = 1
|
||||
ip_len = 2
|
||||
ip_id = 4
|
||||
ip_frag = 6
|
||||
ip_ttl = 8
|
||||
ip_proto = 9
|
||||
ip_header_cksum = 10
|
||||
ip_src = 12
|
||||
ip_dest = 16
|
||||
ip_data = 20
|
||||
|
||||
; ip protocols
|
||||
ip_proto_icmp = 1
|
||||
ip_proto_tcp = 6
|
||||
ip_proto_udp = 17
|
||||
|
||||
|
||||
; temp for calculating checksum
|
||||
cksum: .res 3
|
||||
|
||||
; bad packet counters
|
||||
bad_header: .res 2
|
||||
bad_addr: .res 2
|
||||
|
||||
|
||||
.code
|
||||
|
||||
; initialize ip routines
|
||||
ip_init:
|
||||
lda #0
|
||||
sta bad_header
|
||||
sta bad_header + 1
|
||||
sta bad_addr
|
||||
sta bad_addr + 1
|
||||
|
||||
jsr icmp_init
|
||||
jsr udp_init
|
||||
; jsr tcp_init
|
||||
|
||||
rts
|
||||
|
||||
|
||||
; process an incoming packet
|
||||
ip_process:
|
||||
jsr verifyheader ; ver, ihl, len, frag, checksum
|
||||
bcc @ok
|
||||
@badpacket:
|
||||
sec
|
||||
rts
|
||||
@ok:
|
||||
jsr checkaddr ; make sure it's meant for us
|
||||
bcs @badpacket
|
||||
|
||||
lda ip_inp + ip_proto
|
||||
cmp #ip_proto_icmp
|
||||
bne :+
|
||||
jmp icmp_process ; jump to icmp handler
|
||||
: cmp #ip_proto_tcp
|
||||
bne :+
|
||||
jmp tcp_process ; jump to tcp handler
|
||||
: cmp #ip_proto_udp
|
||||
bne :+
|
||||
jmp udp_process ; jump to udp handler
|
||||
:
|
||||
tcp_process:
|
||||
sec ; unknown protocol
|
||||
rts
|
||||
|
||||
|
||||
; verify that header contains what we expect
|
||||
verifyheader:
|
||||
lda ip_inp + ip_ver_ihl ; IPv4 and no IP options
|
||||
cmp #$45
|
||||
bne @badpacket
|
||||
|
||||
; lda ip_inp + ip_tos ; ignore ToS
|
||||
|
||||
lda ip_inp + ip_len + 1 ; ip + 14 bytes ethernet header
|
||||
clc
|
||||
adc #14
|
||||
sta len
|
||||
lda ip_inp + ip_len
|
||||
adc #0
|
||||
sta len + 1
|
||||
|
||||
lda eth_inp_len ; check if advertised length is shorter
|
||||
sec ; than actual length
|
||||
sbc len
|
||||
lda eth_inp_len + 1
|
||||
sbc len + 1
|
||||
bmi @badpacket
|
||||
|
||||
lda ip_inp + ip_frag ; check for fragmentation
|
||||
beq :+
|
||||
cmp #$40
|
||||
bne @badpacket
|
||||
: lda ip_inp + ip_frag + 1
|
||||
bne @badpacket
|
||||
|
||||
ldax #ip_inp ; verify checksum
|
||||
stax ip_cksum_ptr
|
||||
ldax #20
|
||||
jsr ip_calc_cksum
|
||||
cmp #0
|
||||
bne @badpacket
|
||||
cpx #0
|
||||
bne @badpacket
|
||||
|
||||
clc
|
||||
rts
|
||||
@badpacket:
|
||||
inc bad_header
|
||||
bne :+
|
||||
inc bad_header + 1
|
||||
: sec
|
||||
rts
|
||||
|
||||
|
||||
; check that this packet was addressed to us
|
||||
checkaddr:
|
||||
lda #0
|
||||
sta ip_broadcast
|
||||
lda ip_inp + ip_dest ; compare ip address
|
||||
cmp cfg_ip
|
||||
bne @broadcast
|
||||
lda ip_inp + ip_dest + 1
|
||||
cmp cfg_ip + 1
|
||||
bne @broadcast
|
||||
lda ip_inp + ip_dest + 2
|
||||
cmp cfg_ip + 2
|
||||
bne @broadcast
|
||||
lda ip_inp + ip_dest + 3
|
||||
cmp cfg_ip + 3
|
||||
bne @broadcast
|
||||
@ok: clc
|
||||
rts
|
||||
@broadcast:
|
||||
inc ip_broadcast
|
||||
lda ip_inp + ip_dest ; check for broadcast
|
||||
and ip_inp + ip_dest + 1
|
||||
and ip_inp + ip_dest + 2
|
||||
and ip_inp + ip_dest + 3
|
||||
cmp #$ff
|
||||
beq @ok
|
||||
inc bad_addr
|
||||
bne :+
|
||||
inc bad_addr + 1
|
||||
: sec
|
||||
rts
|
||||
|
||||
|
||||
; create a packet template
|
||||
ip_create_packet:
|
||||
lda #$45 ; set IP version and header length
|
||||
sta ip_outp + ip_ver_ihl
|
||||
|
||||
lda #0 ; set type of service
|
||||
sta ip_outp + ip_tos
|
||||
|
||||
; skip length
|
||||
|
||||
; skip ID
|
||||
|
||||
lda #$40 ; don't fragment - or should we not care?
|
||||
sta ip_outp + ip_frag
|
||||
lda #0
|
||||
sta ip_outp + ip_frag + 1
|
||||
|
||||
lda #$40 ; set time to live
|
||||
sta ip_outp + ip_ttl
|
||||
|
||||
; skip protocol
|
||||
|
||||
lda #0 ; clear checksum
|
||||
sta ip_outp + ip_header_cksum
|
||||
sta ip_outp + ip_header_cksum + 1
|
||||
|
||||
ldx #3 ; copy source address
|
||||
: lda cfg_ip,x
|
||||
sta ip_outp + ip_src,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
; skip destination address
|
||||
|
||||
rts
|
||||
|
||||
|
||||
; send an IP packet
|
||||
;
|
||||
; but first:
|
||||
;
|
||||
; call ip_create_packet
|
||||
; set length
|
||||
; set ID
|
||||
; set protocol
|
||||
; set destination address
|
||||
ip_send:
|
||||
ldx #3 ; get mac addr from ip
|
||||
: lda ip_outp + ip_dest,x
|
||||
sta arp_ip,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
jsr arp_lookup
|
||||
bcc :+
|
||||
rts ; packet buffer nuked, fail
|
||||
:
|
||||
ldax #ip_outp ; calculate ip header checksum
|
||||
stax ip_cksum_ptr
|
||||
ldax #20
|
||||
jsr ip_calc_cksum
|
||||
stax ip_outp + ip_header_cksum
|
||||
|
||||
ldx #5
|
||||
: lda arp_mac,x ; copy destination mac address
|
||||
sta eth_outp + eth_dest,x
|
||||
lda cfg_mac,x ; copy my mac address
|
||||
sta eth_outp + eth_src,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
lda #eth_proto_ip ; set type to IP
|
||||
jsr eth_set_proto
|
||||
|
||||
lda ip_outp + ip_len + 1 ; set packet length
|
||||
lsr
|
||||
bcc @dontpad
|
||||
|
||||
rol ; pad with 0
|
||||
;clc
|
||||
adc #<ip_outp
|
||||
sta copy_src ; borrow copymem zp...
|
||||
lda ip_outp + ip_len
|
||||
adc #>ip_outp
|
||||
sta copy_src + 1
|
||||
ldy #0
|
||||
tya
|
||||
sta (copy_src),y
|
||||
|
||||
sec ; round up to even number
|
||||
@dontpad:
|
||||
lda ip_outp + ip_len + 1
|
||||
adc #eth_data
|
||||
sta eth_outp_len
|
||||
lda ip_outp + ip_len
|
||||
adc #0
|
||||
sta eth_outp_len + 1
|
||||
|
||||
;jsr dbg_dump_ip_header
|
||||
|
||||
jmp eth_tx ; send packet and return status
|
||||
|
||||
|
||||
; calculate checksum for ip header
|
||||
ip_calc_cksum:
|
||||
sta ip_cksum_len ; save length
|
||||
stx ip_cksum_len + 1
|
||||
|
||||
lda #0
|
||||
sta cksum
|
||||
sta cksum + 1
|
||||
sta cksum + 2
|
||||
|
||||
cpx #0
|
||||
beq @tail
|
||||
|
||||
: ldx #$80 ; number of bytes / 2
|
||||
jsr @calc
|
||||
inc ip_cksum_ptr + 1
|
||||
dec ip_cksum_len + 1
|
||||
bne :-
|
||||
|
||||
@tail:
|
||||
lda ip_cksum_len ; divide length by 2
|
||||
lsr
|
||||
php ; save carry for odd size
|
||||
tax
|
||||
|
||||
jsr @calc
|
||||
|
||||
plp
|
||||
bcc @done
|
||||
|
||||
clc
|
||||
lda (ip_cksum_ptr),y
|
||||
adc cksum
|
||||
sta cksum
|
||||
bcc @done
|
||||
inc cksum + 1
|
||||
bne @done
|
||||
inc cksum + 2
|
||||
|
||||
@done:
|
||||
lda cksum + 2 ; add carries back in
|
||||
clc
|
||||
adc cksum
|
||||
pha
|
||||
lda cksum + 1
|
||||
adc #0
|
||||
eor #$ff ; return inverted result
|
||||
tax
|
||||
pla
|
||||
eor #$ff
|
||||
|
||||
rts
|
||||
|
||||
@calc:
|
||||
ldy #0 ; 1's complement 16-bit sum
|
||||
@next:
|
||||
clc
|
||||
lda (ip_cksum_ptr),y
|
||||
adc cksum
|
||||
sta cksum
|
||||
iny
|
||||
lda (ip_cksum_ptr),y
|
||||
adc cksum + 1
|
||||
sta cksum + 1
|
||||
bcc :+
|
||||
inc cksum + 2
|
||||
: iny
|
||||
dex
|
||||
bne @next
|
||||
rts
|
76
ip65/ip65.s
76
ip65/ip65.s
@ -1,76 +0,0 @@
|
||||
;originally from Per Olofsson's IP65 library - http://www.paradroid.net/ip65
|
||||
|
||||
; ip65 main routines
|
||||
|
||||
.include "../inc/common.i"
|
||||
|
||||
.export ip65_init
|
||||
.export ip65_process
|
||||
|
||||
.export ip65_ctr
|
||||
.export ip65_ctr_arp
|
||||
.export ip65_ctr_ip
|
||||
|
||||
.import eth_init
|
||||
.import timer_init
|
||||
.import arp_init
|
||||
.import ip_init
|
||||
|
||||
.import eth_inp
|
||||
.import eth_rx
|
||||
|
||||
.import ip_process
|
||||
.import arp_process
|
||||
|
||||
.importzp eth_proto_arp
|
||||
|
||||
|
||||
.bss
|
||||
|
||||
ip65_ctr: .res 1 ; incremented for every incoming packet
|
||||
ip65_ctr_arp: .res 1 ; incremented for every incoming arp packet
|
||||
ip65_ctr_ip: .res 1 ; incremented for every incoming ip packet
|
||||
|
||||
|
||||
.code
|
||||
|
||||
; initialize stack
|
||||
ip65_init:
|
||||
|
||||
|
||||
jsr eth_init ; initialize ethernet driver
|
||||
|
||||
bcs @fail
|
||||
jsr timer_init ; initialize timer
|
||||
jsr arp_init ; initialize arp
|
||||
jsr ip_init ; initialize ip, icmp, udp, and tcp
|
||||
clc
|
||||
@fail:
|
||||
rts
|
||||
|
||||
|
||||
; maintenance routine
|
||||
; polls for packets, and dispatches to listeners
|
||||
ip65_process:
|
||||
jsr eth_rx ; check for incoming packets
|
||||
bcs @done
|
||||
|
||||
lda eth_inp + 12 ; type should be 08xx
|
||||
cmp #8
|
||||
bne @done
|
||||
|
||||
lda eth_inp + 13
|
||||
; cmp #eth_proto_ip ; ip = 00
|
||||
beq @ip
|
||||
cmp #eth_proto_arp ; arp = 06
|
||||
beq @arp
|
||||
@done:
|
||||
rts
|
||||
|
||||
@arp:
|
||||
inc ip65_ctr_arp
|
||||
jmp arp_process
|
||||
|
||||
@ip:
|
||||
inc ip65_ctr_ip
|
||||
jmp ip_process
|
396
ip65/printf.s
396
ip65/printf.s
@ -1,396 +0,0 @@
|
||||
;originally from Per Olofsson's IP65 library - http://www.paradroid.net/ip65
|
||||
|
||||
.include "../inc/common.i"
|
||||
|
||||
.export console_printf
|
||||
|
||||
|
||||
.import console_out
|
||||
.import console_strout
|
||||
|
||||
|
||||
.segment "IP65ZP" : zeropage
|
||||
|
||||
strptr: .res 2
|
||||
argptr: .res 2
|
||||
valptr: .res 2
|
||||
|
||||
|
||||
.bss
|
||||
|
||||
ysave: .res 1
|
||||
arg: .res 1
|
||||
fieldwidth: .res 1
|
||||
fieldwcnt: .res 1
|
||||
leadzero: .res 1
|
||||
argtemp: .res 1
|
||||
int: .res 2
|
||||
num: .res 5
|
||||
ext: .res 2
|
||||
|
||||
|
||||
.code
|
||||
|
||||
console_printf:
|
||||
stax argptr
|
||||
ldy #0
|
||||
lda (argptr),y
|
||||
sta strptr
|
||||
iny
|
||||
lda (argptr),y
|
||||
sta strptr + 1
|
||||
iny
|
||||
sty arg
|
||||
|
||||
ldy #0
|
||||
@nextchar:
|
||||
lda (strptr),y
|
||||
bne :+
|
||||
rts
|
||||
:
|
||||
cmp #'%'
|
||||
beq @printarg
|
||||
|
||||
cmp #'\'
|
||||
beq @printescape
|
||||
|
||||
jsr console_out
|
||||
|
||||
@next:
|
||||
iny
|
||||
bne @nextchar
|
||||
|
||||
inc strptr + 1
|
||||
jmp @nextchar
|
||||
|
||||
@printescape:
|
||||
iny
|
||||
bne :+
|
||||
inc strptr + 1
|
||||
: lda (strptr),y
|
||||
ldx #esc_count - 1
|
||||
: cmp esc_code,x
|
||||
beq @escmatch
|
||||
dex
|
||||
bpl :-
|
||||
bmi @next
|
||||
@escmatch:
|
||||
lda esc_char,x
|
||||
jsr console_out
|
||||
jmp @next
|
||||
|
||||
@printarg:
|
||||
lda #0
|
||||
sta fieldwidth
|
||||
sta leadzero
|
||||
lda #$ff
|
||||
sta fieldwcnt
|
||||
@argnext:
|
||||
iny
|
||||
bne :+
|
||||
inc strptr + 1
|
||||
:
|
||||
tya
|
||||
pha
|
||||
|
||||
lda (strptr),y
|
||||
|
||||
cmp #'0' ; check for field width
|
||||
bcc @notdigit
|
||||
cmp #'9'+1
|
||||
bcs @notdigit
|
||||
and #$0f
|
||||
bne :+ ; check for leading 0
|
||||
inc fieldwcnt
|
||||
bne :+
|
||||
lda #$80
|
||||
sta leadzero
|
||||
pla
|
||||
tay
|
||||
jmp @argnext
|
||||
:
|
||||
pha ; multiply old value by 10
|
||||
asl fieldwidth
|
||||
lda fieldwidth
|
||||
asl
|
||||
asl
|
||||
clc
|
||||
adc fieldwidth
|
||||
sta fieldwidth
|
||||
pla
|
||||
clc ; add new value
|
||||
adc fieldwidth
|
||||
sta fieldwidth
|
||||
pla
|
||||
tay
|
||||
jmp @argnext
|
||||
|
||||
@notdigit:
|
||||
cmp #'s'
|
||||
beq @argstr
|
||||
|
||||
cmp #'d'
|
||||
beq @argint
|
||||
|
||||
cmp #'x'
|
||||
beq @arghex
|
||||
|
||||
cmp #'c'
|
||||
beq @argchar
|
||||
|
||||
@argdone:
|
||||
pla
|
||||
tay
|
||||
jmp @next
|
||||
|
||||
@argstr:
|
||||
jsr @argax
|
||||
jsr console_strout
|
||||
|
||||
jmp @argdone
|
||||
|
||||
@argint:
|
||||
jsr @argax
|
||||
stax valptr
|
||||
jsr @valax
|
||||
jsr printint
|
||||
|
||||
jmp @argdone
|
||||
|
||||
@arghex:
|
||||
jsr @argax
|
||||
stax valptr
|
||||
jsr @valax
|
||||
jsr printhex
|
||||
|
||||
jmp @argdone
|
||||
|
||||
@argchar:
|
||||
jsr @argax
|
||||
stax valptr
|
||||
ldy #0
|
||||
lda (valptr),y
|
||||
jsr console_out
|
||||
|
||||
jmp @argdone
|
||||
|
||||
@argax:
|
||||
ldy arg
|
||||
lda (argptr),y
|
||||
pha
|
||||
iny
|
||||
lda (argptr),y
|
||||
tax
|
||||
iny
|
||||
sty arg
|
||||
pla
|
||||
rts
|
||||
|
||||
@valax:
|
||||
ldy #0
|
||||
lda (valptr),y
|
||||
pha
|
||||
iny
|
||||
lda (valptr),y
|
||||
tax
|
||||
pla
|
||||
rts
|
||||
|
||||
@printx:
|
||||
txa
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
tay
|
||||
lda hex2asc,y
|
||||
jsr console_out
|
||||
txa
|
||||
and #$0f
|
||||
tay
|
||||
lda hex2asc,y
|
||||
jmp console_out
|
||||
|
||||
|
||||
; print 16-bit hexadecimal number
|
||||
printhex:
|
||||
tay
|
||||
and #$0f
|
||||
sta num + 3
|
||||
tya
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
sta num + 2
|
||||
|
||||
txa
|
||||
and #$0f
|
||||
sta num + 1
|
||||
txa
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
sta num
|
||||
|
||||
lda #4
|
||||
sec
|
||||
sbc fieldwidth
|
||||
tax
|
||||
bpl :+
|
||||
jsr printlong
|
||||
:
|
||||
cpx #4
|
||||
beq @nowidth
|
||||
|
||||
@printlead:
|
||||
lda num,x
|
||||
bne @printrest
|
||||
lda #' '
|
||||
bit leadzero
|
||||
bpl :+
|
||||
lda #'0'
|
||||
: jsr console_out
|
||||
inx
|
||||
cpx #3
|
||||
bne @printlead
|
||||
|
||||
@nowidth:
|
||||
ldx #0
|
||||
: lda num,x
|
||||
bne @printrest
|
||||
inx
|
||||
cpx #4
|
||||
bne :-
|
||||
lda #'0'
|
||||
jsr console_out
|
||||
rts
|
||||
|
||||
@printrest:
|
||||
lda num,x
|
||||
tay
|
||||
lda hex2asc,y
|
||||
jsr console_out
|
||||
inx
|
||||
cpx #4
|
||||
bne @printrest
|
||||
rts
|
||||
|
||||
|
||||
printlong:
|
||||
lda #' '
|
||||
bit leadzero
|
||||
bpl :+
|
||||
lda #'0'
|
||||
: jsr console_out
|
||||
inx
|
||||
bne :-
|
||||
rts
|
||||
|
||||
|
||||
; print a 16-bit integer
|
||||
printint:
|
||||
stax int
|
||||
|
||||
ldx #4
|
||||
@next:
|
||||
lda #0
|
||||
sta num,x
|
||||
jsr div10
|
||||
lda ext
|
||||
sta num,x
|
||||
dex
|
||||
bpl @next
|
||||
|
||||
lda fieldwidth
|
||||
beq @nowidth
|
||||
lda #5
|
||||
sec
|
||||
sbc fieldwidth
|
||||
tax
|
||||
bpl :+
|
||||
jsr printlong
|
||||
:
|
||||
@printlead:
|
||||
lda num,x
|
||||
bne @print
|
||||
|
||||
lda #' '
|
||||
bit leadzero
|
||||
bpl :+
|
||||
lda #'0'
|
||||
: jsr console_out
|
||||
inx
|
||||
cpx #5
|
||||
bne @printlead
|
||||
beq @printzero
|
||||
|
||||
@nowidth:
|
||||
inx
|
||||
cpx #5
|
||||
beq @printzero
|
||||
lda num,x
|
||||
beq @nowidth
|
||||
|
||||
@print:
|
||||
clc
|
||||
adc #'0'
|
||||
jsr console_out
|
||||
inx
|
||||
cpx #5
|
||||
beq @done
|
||||
@printall:
|
||||
lda num,x
|
||||
jmp @print
|
||||
|
||||
@done:
|
||||
rts
|
||||
|
||||
@printzero:
|
||||
lda #'0'
|
||||
jmp console_out
|
||||
|
||||
|
||||
; 16/16-bit division, from the fridge
|
||||
; int/aux -> int, remainder in ext
|
||||
div10:
|
||||
lda #0
|
||||
sta ext+1
|
||||
ldy #$10
|
||||
@dloop:
|
||||
asl int
|
||||
rol int+1
|
||||
rol
|
||||
rol ext+1
|
||||
pha
|
||||
cmp #10
|
||||
lda ext+1
|
||||
sbc #0 ; is this a nop?
|
||||
bcc @div2
|
||||
sta ext+1
|
||||
pla
|
||||
sbc #10
|
||||
pha
|
||||
inc int
|
||||
@div2:
|
||||
pla
|
||||
dey
|
||||
bne @dloop
|
||||
sta ext
|
||||
rts
|
||||
|
||||
|
||||
.rodata
|
||||
|
||||
msg_unimplemented:
|
||||
.byte "<unimplemented>",0
|
||||
|
||||
hex2asc:
|
||||
.byte "0123456789abcdef"
|
||||
|
||||
esc_code:
|
||||
.byte "eabfnrt", '\'
|
||||
esc_count = * - esc_code
|
||||
esc_char:
|
||||
.byte 27, 7, 8, 12, 10, 13, 9, '\'
|
357
ip65/tftp.s
357
ip65/tftp.s
@ -1,357 +0,0 @@
|
||||
;########################
|
||||
; minimal tftp implementation (client only)
|
||||
; written by jonno@jamtronix.com 2009
|
||||
;
|
||||
;########################
|
||||
; to use -
|
||||
; set tftp_ip to host to download from (which can be broadcast address 255.255.255.255)
|
||||
; set tftp_load_address to point to memory location that file will be downloaded to
|
||||
; OR set tftp_load_address to $0000, and first 2 bytes of downloaded file will be treated as the load address
|
||||
; set tftp_filename to null terminated filename to download
|
||||
; then call tftp_download
|
||||
; on exit: carry flag is set if there was an error. tftp_load_address will be set to address file loaded to (i.e. gets overwritten if originally set to $0000)f
|
||||
;########################
|
||||
|
||||
TFTP_MAX_RESENDS=10
|
||||
TFTP_TIMER_MASK=$F8 ;mask lower two bits, means we wait for 8 x1/4 seconds
|
||||
|
||||
.include "../inc/common.i"
|
||||
|
||||
.exportzp tftp_filename
|
||||
.export tftp_load_address
|
||||
.export tftp_ip
|
||||
.export tftp_download
|
||||
|
||||
|
||||
.import ip65_process
|
||||
|
||||
.import udp_add_listener
|
||||
.import udp_remove_listener
|
||||
|
||||
.import udp_callback
|
||||
.import udp_send
|
||||
|
||||
.import udp_inp
|
||||
.import ip_inp
|
||||
.importzp ip_src
|
||||
.importzp udp_src_port
|
||||
|
||||
|
||||
.importzp udp_data
|
||||
|
||||
.import udp_send_dest
|
||||
.import udp_send_src_port
|
||||
.import udp_send_dest_port
|
||||
.import udp_send_len
|
||||
|
||||
.import copymem
|
||||
.importzp copy_src
|
||||
.importzp copy_dest
|
||||
|
||||
.import timer_read
|
||||
|
||||
.segment "IP65ZP" : zeropage
|
||||
|
||||
tftp_filename: .res 2
|
||||
|
||||
.bss
|
||||
|
||||
;packet offsets
|
||||
tftp_inp = udp_inp + udp_data
|
||||
tftp_outp: .res 128
|
||||
;everything after filename in a request at a relative address, not fixed, so don't bother defining offset constants
|
||||
|
||||
tftp_server_port=69
|
||||
tftp_client_port_low_byte: .res 1
|
||||
|
||||
tftp_load_address: .res 2
|
||||
tftp_ip: .res 4
|
||||
|
||||
tftp_bytes_to_copy: .res 2
|
||||
tftp_current_memloc: .res 2
|
||||
|
||||
; tftp state machine
|
||||
tftp_initializing = 1 ; initial state
|
||||
tftp_rrq_sent=2 ; sent the read request, waiting for some data
|
||||
tftp_receiving_file=3 ; we have received the first packet of file data
|
||||
tftp_complete=4 ; we have received the final packet of file data
|
||||
tftp_error=5 ; we got an error
|
||||
|
||||
tftp_state: .res 1 ; current activity
|
||||
tftp_timer: .res 1
|
||||
tftp_resend_counter: .res 1
|
||||
tftp_break_inner_loop: .res 1
|
||||
tftp_expected_block_number: .res 1
|
||||
tftp_block_number_to_ack: .res 1
|
||||
tftp_actual_server_port: .res 2 ;this is read from the reply - it is not (usually) the port # we send the RRQ to
|
||||
tftp_actual_server_ip: .res 4 ;this is read from the reply - it may not be the IP we sent to (e.g. if we send to broadcast)
|
||||
|
||||
tftp_just_set_new_load_address: .res 1
|
||||
|
||||
.code
|
||||
|
||||
tftp_download:
|
||||
|
||||
lda #tftp_initializing
|
||||
sta tftp_state
|
||||
sta tftp_expected_block_number ;(tftp_initializing=1)
|
||||
ldax tftp_load_address
|
||||
stax tftp_current_memloc
|
||||
ldax #tftp_in
|
||||
stax udp_callback
|
||||
lda #$69
|
||||
inc tftp_client_port_low_byte ;each call to resolve uses a different client address
|
||||
ldx tftp_client_port_low_byte ;so we don't get confused by late replies to a previous call
|
||||
jsr udp_add_listener
|
||||
|
||||
bcc :+ ;bail if we couldn't listen on the port we want
|
||||
rts
|
||||
:
|
||||
|
||||
lda #TFTP_MAX_RESENDS
|
||||
sta tftp_resend_counter
|
||||
@outer_delay_loop:
|
||||
jsr timer_read
|
||||
txa
|
||||
and #TFTP_TIMER_MASK
|
||||
sta tftp_timer ;we only care about the high byte
|
||||
lda #0
|
||||
sta tftp_break_inner_loop
|
||||
lda tftp_state
|
||||
cmp #tftp_initializing
|
||||
bne @not_initializing
|
||||
jsr send_read_request
|
||||
jmp @inner_delay_loop
|
||||
|
||||
@not_initializing:
|
||||
cmp #tftp_error
|
||||
bne @not_error
|
||||
|
||||
@exit_with_error:
|
||||
lda #$69
|
||||
ldx tftp_client_port_low_byte
|
||||
jsr udp_remove_listener
|
||||
sec
|
||||
rts
|
||||
|
||||
@not_error:
|
||||
|
||||
cmp #tftp_complete
|
||||
bne @not_complete
|
||||
jsr send_ack ;send the ack for the last block
|
||||
lda #$69
|
||||
ldx tftp_client_port_low_byte
|
||||
jsr udp_remove_listener
|
||||
rts
|
||||
|
||||
@not_complete:
|
||||
cmp #tftp_receiving_file
|
||||
bne @not_receiving
|
||||
jsr send_ack
|
||||
jmp @inner_delay_loop
|
||||
@not_receiving:
|
||||
jsr send_read_request
|
||||
|
||||
@inner_delay_loop:
|
||||
|
||||
jsr ip65_process
|
||||
lda tftp_break_inner_loop
|
||||
bne @outer_delay_loop
|
||||
jsr timer_read
|
||||
txa
|
||||
and #TFTP_TIMER_MASK
|
||||
cmp tftp_timer
|
||||
beq @inner_delay_loop
|
||||
|
||||
dec tftp_resend_counter
|
||||
bne @outer_delay_loop
|
||||
jmp @exit_with_error
|
||||
|
||||
send_read_request:
|
||||
lda #tftp_initializing
|
||||
sta tftp_state
|
||||
ldax #$0100 ;opcode 01 = RRQ
|
||||
stax tftp_outp
|
||||
|
||||
ldx #$01 ;we inc x/y at start of loop, so
|
||||
ldy #$ff ;set them to be 1 below where we want the copy to begin
|
||||
@copy_filename_loop:
|
||||
inx
|
||||
iny
|
||||
bmi @error_in_send ;if we get to 0x80 bytes, we've gone too far
|
||||
lda (tftp_filename),y
|
||||
sta tftp_outp,x
|
||||
bne @copy_filename_loop
|
||||
|
||||
ldy #$ff
|
||||
@copy_mode_loop:
|
||||
inx
|
||||
iny
|
||||
lda tftp_octet_mode,y
|
||||
sta tftp_outp,x
|
||||
bne @copy_mode_loop
|
||||
|
||||
inx
|
||||
txa
|
||||
ldx #0
|
||||
stax udp_send_len
|
||||
|
||||
lda #$69
|
||||
ldx tftp_client_port_low_byte
|
||||
stax udp_send_src_port
|
||||
|
||||
ldx #3 ; set destination address
|
||||
: lda tftp_ip,x
|
||||
sta udp_send_dest,x
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
ldax #tftp_server_port ; set destination port
|
||||
stax udp_send_dest_port
|
||||
ldax #tftp_outp
|
||||
jsr udp_send
|
||||
bcs @error_in_send
|
||||
lda #tftp_rrq_sent
|
||||
sta tftp_state
|
||||
rts
|
||||
@error_in_send:
|
||||
|
||||
sec
|
||||
rts
|
||||
|
||||
send_ack:
|
||||
ldax #$0400 ;opcode 04 = ACK
|
||||
stax tftp_outp
|
||||
ldx tftp_block_number_to_ack
|
||||
stax tftp_outp+2
|
||||
lda #$69
|
||||
ldx tftp_client_port_low_byte
|
||||
stax udp_send_src_port
|
||||
|
||||
lda tftp_actual_server_ip
|
||||
sta udp_send_dest
|
||||
lda tftp_actual_server_ip+1
|
||||
sta udp_send_dest+1
|
||||
lda tftp_actual_server_ip+2
|
||||
sta udp_send_dest+2
|
||||
lda tftp_actual_server_ip+3
|
||||
sta udp_send_dest+3
|
||||
ldx tftp_actual_server_port
|
||||
lda tftp_actual_server_port+1
|
||||
stax udp_send_dest_port
|
||||
ldax #04
|
||||
stax udp_send_len
|
||||
|
||||
ldax #tftp_outp
|
||||
jsr udp_send
|
||||
rts
|
||||
|
||||
|
||||
tftp_in:
|
||||
|
||||
lda tftp_inp+1 ;get the opcode
|
||||
cmp #5
|
||||
bne @not_an_error
|
||||
@recv_error:
|
||||
lda #tftp_error
|
||||
sta tftp_state
|
||||
|
||||
rts
|
||||
@not_an_error:
|
||||
|
||||
cmp #3
|
||||
beq :+
|
||||
jmp @not_data_block
|
||||
:
|
||||
|
||||
lda #0
|
||||
sta tftp_just_set_new_load_address ;clear the flag
|
||||
clc
|
||||
lda tftp_load_address
|
||||
adc tftp_load_address+1 ;is load address currently $0000?
|
||||
bne @dont_set_load_address
|
||||
ldax udp_inp+$0c ;get first two bytes of data
|
||||
stax tftp_load_address ;make them the new load adress
|
||||
stax tftp_current_memloc ;also the current memory destination
|
||||
lda #1 ;set the flag
|
||||
sta tftp_just_set_new_load_address
|
||||
|
||||
@dont_set_load_address:
|
||||
lda tftp_inp+3 ;get the (low byte) of the data block
|
||||
bmi @recv_error ;if we get to block $80, we've d/led more than 64k!
|
||||
cmp tftp_expected_block_number
|
||||
beq :+
|
||||
jmp @not_expected_block_number
|
||||
:
|
||||
;this is the block we wanted
|
||||
sta tftp_block_number_to_ack
|
||||
inc tftp_expected_block_number
|
||||
lda #tftp_receiving_file
|
||||
sta tftp_state
|
||||
lda #TFTP_MAX_RESENDS
|
||||
sta tftp_resend_counter
|
||||
lda #1
|
||||
sta tftp_break_inner_loop
|
||||
|
||||
ldax udp_inp+udp_src_port
|
||||
stax tftp_actual_server_port
|
||||
ldax ip_inp+ip_src
|
||||
stax tftp_actual_server_ip
|
||||
ldax ip_inp+ip_src+2
|
||||
stax tftp_actual_server_ip+2
|
||||
|
||||
|
||||
lda tftp_just_set_new_load_address
|
||||
bne @skip_first_2_bytes_in_calculating_header_length
|
||||
lda udp_inp+5 ;get the low byte of udp packet length
|
||||
sec
|
||||
sbc #$0c ;take off the length of the UDP header+OPCODE + BLOCK
|
||||
|
||||
jmp @adjusted_header_length
|
||||
@skip_first_2_bytes_in_calculating_header_length:
|
||||
lda udp_inp+5 ;get the low byte of udp packet length
|
||||
sec
|
||||
sbc #$0e ;take off the length of the UDP header+OPCODE + BLOCK + first 2 bytes (memory location)
|
||||
@adjusted_header_length:
|
||||
|
||||
sta tftp_bytes_to_copy
|
||||
lda udp_inp+4 ;get high byte of the length of the UDP packet
|
||||
sbc #0
|
||||
sta tftp_bytes_to_copy+1
|
||||
|
||||
lda tftp_just_set_new_load_address
|
||||
bne @skip_first_2_bytes_in_calculating_copy_src
|
||||
ldax #udp_inp+$0c
|
||||
jmp @got_copy_src
|
||||
@skip_first_2_bytes_in_calculating_copy_src:
|
||||
ldax #udp_inp+$0e
|
||||
@got_copy_src:
|
||||
stax copy_src
|
||||
ldax tftp_current_memloc
|
||||
stax copy_dest
|
||||
ldax tftp_bytes_to_copy
|
||||
jsr copymem
|
||||
clc
|
||||
lda tftp_bytes_to_copy ;update the location where the next data will go
|
||||
adc tftp_current_memloc
|
||||
sta tftp_current_memloc
|
||||
lda tftp_bytes_to_copy+1
|
||||
adc tftp_current_memloc+1
|
||||
sta tftp_current_memloc+1
|
||||
lda udp_inp+4 ;check the length of the UDP packet
|
||||
cmp #02
|
||||
bne @last_block
|
||||
|
||||
lda udp_inp+5
|
||||
cmp #$0c
|
||||
bne @last_block
|
||||
@not_data_block:
|
||||
@not_expected_block_number:
|
||||
rts
|
||||
|
||||
@last_block:
|
||||
lda #tftp_complete
|
||||
sta tftp_state
|
||||
rts
|
||||
.rodata
|
||||
tftp_octet_mode: .asciiz "OCTET"
|
38
ip65/timer.s
38
ip65/timer.s
@ -1,38 +0,0 @@
|
||||
;originally from Per Olofsson's IP65 library - http://www.paradroid.net/ip65
|
||||
|
||||
; timer routines
|
||||
;
|
||||
; the timer should be a 16-bit counter that's incremented by about
|
||||
; 1000 units per second. it doesn't have to be particularly accurate,
|
||||
; if you're working with e.g. a 60 Hz VBLANK IRQ, adding 17 to the
|
||||
; counter every frame would be just fine.
|
||||
|
||||
|
||||
.include "../inc/common.i"
|
||||
|
||||
|
||||
.export timer_timeout
|
||||
.import timer_read
|
||||
|
||||
.bss
|
||||
|
||||
time: .res 2
|
||||
|
||||
|
||||
.code
|
||||
|
||||
; check if value in A/X is smaller than current timer value
|
||||
timer_timeout:
|
||||
pha
|
||||
txa
|
||||
pha
|
||||
jsr timer_read
|
||||
stax time
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
sec ; subtract current value
|
||||
sbc time
|
||||
txa
|
||||
sbc time + 1
|
||||
rts ; clc = timeout, sec = no timeout
|
313
ip65/udp.s
313
ip65/udp.s
@ -1,313 +0,0 @@
|
||||
;originally from Per Olofsson's IP65 library - http://www.paradroid.net/ip65
|
||||
|
||||
.include "../inc/common.i"
|
||||
|
||||
;.import dbg_dump_udp_header
|
||||
|
||||
|
||||
.export udp_init
|
||||
.export udp_process
|
||||
.export udp_add_listener
|
||||
.export udp_remove_listener
|
||||
.export udp_send
|
||||
|
||||
.export udp_callback
|
||||
|
||||
.export udp_inp
|
||||
.export udp_outp
|
||||
|
||||
.exportzp udp_src_port
|
||||
.exportzp udp_dest_port
|
||||
.exportzp udp_len
|
||||
.exportzp udp_cksum
|
||||
.exportzp udp_data
|
||||
|
||||
.export udp_send_dest
|
||||
.export udp_send_src_port
|
||||
.export udp_send_dest_port
|
||||
.export udp_send_len
|
||||
|
||||
|
||||
.import ip_calc_cksum
|
||||
.import ip_send
|
||||
.import ip_create_packet
|
||||
.import ip_inp
|
||||
.import ip_outp
|
||||
.importzp ip_cksum_ptr
|
||||
.importzp ip_header_cksum
|
||||
.importzp ip_src
|
||||
.importzp ip_dest
|
||||
.importzp ip_data
|
||||
.importzp ip_proto
|
||||
.importzp ip_proto_udp
|
||||
.importzp ip_id
|
||||
.importzp ip_len
|
||||
|
||||
.import copymem
|
||||
.importzp copy_src
|
||||
.importzp copy_dest
|
||||
|
||||
.import cfg_ip
|
||||
|
||||
|
||||
.bss
|
||||
|
||||
; argument for udp_add_listener
|
||||
udp_callback: .res 2
|
||||
|
||||
; arguments for udp_send
|
||||
udp_send_dest: .res 4
|
||||
udp_send_src_port: .res 2
|
||||
udp_send_dest_port: .res 2
|
||||
udp_send_len: .res 2
|
||||
|
||||
; udp listener callbacks
|
||||
udp_cbmax = 4
|
||||
udp_cbtmp: .res 3 ; temporary vector
|
||||
udp_cbveclo: .res udp_cbmax ; table of listener vectors (lsb)
|
||||
udp_cbvechi: .res udp_cbmax ; table of listener vectors (msb)
|
||||
udp_cbportlo: .res udp_cbmax ; table of ports (lsb)
|
||||
udp_cbporthi: .res udp_cbmax ; table of ports (msb)
|
||||
udp_cbcount: .res 1 ; number of active listeners
|
||||
|
||||
; udp packet offsets
|
||||
udp_inp = ip_inp + ip_data
|
||||
udp_outp = ip_outp + ip_data
|
||||
udp_src_port = 0
|
||||
udp_dest_port = 2
|
||||
udp_len = 4
|
||||
udp_cksum = 6
|
||||
udp_data = 8
|
||||
|
||||
; virtual header
|
||||
udp_vh = udp_outp - 12
|
||||
udp_vh_src = 0
|
||||
udp_vh_dest = 4
|
||||
udp_vh_zero = 8
|
||||
udp_vh_proto = 9
|
||||
udp_vh_len = 10
|
||||
|
||||
|
||||
; temp for port comparison
|
||||
port: .res 2
|
||||
|
||||
|
||||
.code
|
||||
|
||||
; initialize udp
|
||||
udp_init:
|
||||
lda #0
|
||||
sta udp_cbcount
|
||||
lda #$4c ; jmp addr
|
||||
sta udp_cbtmp
|
||||
rts
|
||||
|
||||
|
||||
; process incoming udp packet
|
||||
udp_process:
|
||||
lda udp_cbcount ; any installed udp listeners?
|
||||
beq @drop
|
||||
|
||||
tax ; check ports
|
||||
dex
|
||||
@checkport:
|
||||
lda udp_cbportlo,x
|
||||
cmp udp_inp + udp_dest_port + 1
|
||||
bne :+
|
||||
lda udp_cbporthi,x
|
||||
cmp udp_inp + udp_dest_port
|
||||
beq @handle
|
||||
: dex
|
||||
bpl @checkport
|
||||
|
||||
@drop:
|
||||
sec
|
||||
rts
|
||||
|
||||
@handle:
|
||||
lda udp_cbveclo,x ; copy vector
|
||||
sta udp_cbtmp + 1
|
||||
lda udp_cbvechi,x
|
||||
sta udp_cbtmp + 2
|
||||
jsr udp_cbtmp ; call listener
|
||||
clc
|
||||
rts
|
||||
|
||||
|
||||
; add an udp listener
|
||||
; udp port in A/X, vector in udp_callback
|
||||
udp_add_listener:
|
||||
sta port
|
||||
stx port + 1
|
||||
|
||||
ldy udp_cbcount ; any listeners at all?
|
||||
beq @add
|
||||
cpy #udp_cbmax ; max?
|
||||
beq @full
|
||||
ldy #0
|
||||
@check:
|
||||
lda udp_cbportlo,y ; check if port is already handled
|
||||
cmp port
|
||||
bne :+
|
||||
lda udp_cbporthi,y
|
||||
cmp port + 1
|
||||
beq @busy
|
||||
: iny
|
||||
cpy udp_cbcount
|
||||
bne @check
|
||||
@add:
|
||||
inc udp_cbcount ; increase counter
|
||||
sta udp_cbportlo,y ; add port
|
||||
txa
|
||||
sta udp_cbporthi,y ; add port
|
||||
lda udp_callback ; and vector
|
||||
sta udp_cbveclo,y
|
||||
lda udp_callback + 1
|
||||
sta udp_cbvechi,y
|
||||
|
||||
clc
|
||||
rts
|
||||
@full:
|
||||
@busy:
|
||||
sec
|
||||
rts
|
||||
|
||||
|
||||
; remove an udp listener
|
||||
; udp port in A/X
|
||||
udp_remove_listener:
|
||||
sta port
|
||||
stx port + 1
|
||||
|
||||
ldy udp_cbcount ; any listeners installed?
|
||||
beq @notfound
|
||||
@check:
|
||||
lda udp_cbportlo,y ; check if port is handled
|
||||
cmp port
|
||||
bne :+
|
||||
lda udp_cbporthi,y
|
||||
cmp port + 1
|
||||
beq @remove
|
||||
: iny
|
||||
cpy udp_cbcount
|
||||
bne @check
|
||||
@notfound:
|
||||
sec
|
||||
rts
|
||||
@remove:
|
||||
tya ; number of listeners below
|
||||
eor #$ff
|
||||
clc
|
||||
adc udp_cbcount
|
||||
beq @done
|
||||
@move:
|
||||
tax ; number of items to move
|
||||
: lda udp_cbportlo + 1,y ; move ports
|
||||
sta udp_cbportlo,y
|
||||
lda udp_cbporthi + 1,y
|
||||
sta udp_cbporthi,y
|
||||
lda udp_cbveclo + 1,y ; move vectors
|
||||
sta udp_cbveclo,y
|
||||
lda udp_cbvechi + 1,y
|
||||
sta udp_cbvechi,y
|
||||
iny
|
||||
dex
|
||||
bne :-
|
||||
@done:
|
||||
dec udp_cbcount ; decrement counter
|
||||
clc
|
||||
rts
|
||||
|
||||
|
||||
; send udp packet
|
||||
;
|
||||
; but first:
|
||||
;
|
||||
; set destination address
|
||||
; set source port
|
||||
; set destination port
|
||||
; set length
|
||||
udp_send:
|
||||
stax copy_src ; copy data to output buffer
|
||||
ldax #udp_outp + udp_data
|
||||
stax copy_dest
|
||||
ldax udp_send_len
|
||||
jsr copymem
|
||||
|
||||
ldx #3 ; copy virtual header addresses
|
||||
: lda udp_send_dest,x
|
||||
sta udp_vh + udp_vh_dest,x ; set virtual header destination
|
||||
lda cfg_ip,x
|
||||
sta udp_vh + udp_vh_src,x ; set virtual header source
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
lda udp_send_src_port ; copy source port
|
||||
sta udp_outp + udp_src_port + 1
|
||||
lda udp_send_src_port + 1
|
||||
sta udp_outp + udp_src_port
|
||||
|
||||
lda udp_send_dest_port ; copy destination port
|
||||
sta udp_outp + udp_dest_port + 1
|
||||
lda udp_send_dest_port + 1
|
||||
sta udp_outp + udp_dest_port
|
||||
|
||||
lda #ip_proto_udp
|
||||
sta udp_vh + udp_vh_proto
|
||||
|
||||
lda #0 ; clear checksum
|
||||
sta udp_outp + udp_cksum
|
||||
sta udp_outp + udp_cksum + 1
|
||||
sta udp_vh + udp_vh_zero ; clear virtual header zero byte
|
||||
|
||||
ldax #udp_vh ; checksum pointer to virtual header
|
||||
stax ip_cksum_ptr
|
||||
|
||||
lda udp_send_len ; copy length + 8
|
||||
clc
|
||||
adc #8
|
||||
sta udp_outp + udp_len + 1 ; lsb for udp header
|
||||
sta udp_vh + udp_vh_len + 1 ; lsb for virtual header
|
||||
tay
|
||||
lda udp_send_len + 1
|
||||
adc #0
|
||||
sta udp_outp + udp_len ; msb for udp header
|
||||
sta udp_vh + udp_vh_len ; msb for virtual header
|
||||
|
||||
tax ; length to A/X
|
||||
tya
|
||||
|
||||
clc ; add 12 bytes for virtual header
|
||||
adc #12
|
||||
bcc :+
|
||||
inx
|
||||
:
|
||||
jsr ip_calc_cksum ; calculate checksum
|
||||
stax udp_outp + udp_cksum
|
||||
|
||||
ldx #3 ; copy addresses
|
||||
: lda udp_send_dest,x
|
||||
sta ip_outp + ip_dest,x ; set ip destination address
|
||||
dex
|
||||
bpl :-
|
||||
|
||||
jsr ip_create_packet ; create ip packet template
|
||||
|
||||
lda udp_outp + udp_len + 1 ; ip len = udp len + 20
|
||||
ldx udp_outp + udp_len
|
||||
clc
|
||||
adc #20
|
||||
bcc :+
|
||||
inx
|
||||
: sta ip_outp + ip_len + 1 ; set length
|
||||
stx ip_outp + ip_len
|
||||
|
||||
ldax #$1234 ; set ID
|
||||
stax ip_outp + ip_id
|
||||
|
||||
lda #ip_proto_udp ; set protocol
|
||||
sta ip_outp + ip_proto
|
||||
|
||||
;jsr dbg_dump_udp_header
|
||||
|
||||
jmp ip_send ; send packet, sec on error
|
@ -1,45 +0,0 @@
|
||||
CC=cl65
|
||||
AS=ca65
|
||||
LD=ld65
|
||||
CFLAGS=-Oirs -t $(TARGET)
|
||||
AFLAGS=
|
||||
|
||||
|
||||
IP65LIB=../ip65/ip65.lib
|
||||
C64NETLIB=../drivers/c64net.lib
|
||||
APPLE2NETLIB=../drivers/apple2net.lib
|
||||
|
||||
INCFILES=\
|
||||
../inc/common.i\
|
||||
../inc/commonprint.i\
|
||||
../inc/net.i\
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $<
|
||||
|
||||
%.o: %.s
|
||||
$(AS) $(AFLAGS) $<
|
||||
|
||||
%.bin: %.o $(IP65LIB) $(APPLE2NETLIB) $(INCFILES) ../cfg/a2bin.cfg
|
||||
$(LD) -m $*.map -C ../cfg/a2bin.cfg -o $*.bin $(AFLAGS) $< $(IP65LIB) $(APPLE2NETLIB)
|
||||
|
||||
%.prg: %.o $(IP65LIB) $(C64NETLIB) $(INCFILES) ../cfg/c64prg.cfg
|
||||
$(LD) -m $*.map -C ../cfg/c64prg.cfg -o $*.prg $(AFLAGS) $< $(IP65LIB) $(C64NETLIB)
|
||||
|
||||
ip65test.dsk: testdns.bin
|
||||
dsktool.rb --init dos33 ip65test.dsk -a testdns.bin -t B
|
||||
|
||||
|
||||
all: \
|
||||
ip65test.dsk \
|
||||
testdns.bin \
|
||||
testdns.prg \
|
||||
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f testdns.prg testdns.map testdns.bin
|
||||
rm -f ip65test.dsk
|
||||
|
||||
distclean: clean
|
||||
rm -f *~
|
136
test/testdns.s
136
test/testdns.s
@ -1,136 +0,0 @@
|
||||
.include "../inc/common.i"
|
||||
.include "../inc/commonprint.i"
|
||||
.include "../inc/net.i"
|
||||
|
||||
.import exit_to_basic
|
||||
|
||||
.import dns_set_hostname
|
||||
.import dns_resolve
|
||||
.import dns_ip
|
||||
.import dns_status
|
||||
.import __CODE_LOAD__
|
||||
.import __CODE_SIZE__
|
||||
.import __RODATA_SIZE__
|
||||
.import __DATA_SIZE__
|
||||
|
||||
|
||||
.segment "STARTUP" ;this is what gets put at the start of the file on the C64
|
||||
|
||||
.word basicstub ; load address
|
||||
|
||||
basicstub:
|
||||
.word @nextline
|
||||
.word 2003
|
||||
.byte $9e
|
||||
.byte <(((init / 1000) .mod 10) + $30)
|
||||
.byte <(((init / 100 ) .mod 10) + $30)
|
||||
.byte <(((init / 10 ) .mod 10) + $30)
|
||||
.byte <(((init ) .mod 10) + $30)
|
||||
.byte 0
|
||||
@nextline:
|
||||
.word 0
|
||||
|
||||
.segment "EXEHDR" ;this is what gets put an the start of the file on the Apple 2
|
||||
.addr __CODE_LOAD__-$11 ; Start address
|
||||
.word __CODE_SIZE__+__RODATA_SIZE__+__DATA_SIZE__+4 ; Size
|
||||
jmp init
|
||||
|
||||
.code
|
||||
|
||||
init:
|
||||
|
||||
jsr print_cr
|
||||
jsr print_ip_config
|
||||
|
||||
init_ip_via_dhcp
|
||||
|
||||
; jsr overwrite_with_hardcoded_dns_server
|
||||
jsr print_ip_config
|
||||
|
||||
ldax #hostname_1
|
||||
jsr do_dns_query
|
||||
|
||||
ldax #hostname_2
|
||||
jsr do_dns_query
|
||||
|
||||
ldax #hostname_3
|
||||
jsr do_dns_query
|
||||
|
||||
ldax #hostname_4
|
||||
jsr do_dns_query
|
||||
|
||||
ldax #hostname_5
|
||||
jsr do_dns_query
|
||||
|
||||
ldax #hostname_6
|
||||
jsr do_dns_query
|
||||
|
||||
jmp exit_to_basic
|
||||
|
||||
|
||||
do_dns_query:
|
||||
pha
|
||||
jsr print
|
||||
lda #' '
|
||||
jsr print_a
|
||||
lda #':'
|
||||
jsr print_a
|
||||
lda #' '
|
||||
jsr print_a
|
||||
pla
|
||||
jsr dns_set_hostname
|
||||
jsr dns_resolve
|
||||
bcc :+
|
||||
ldax #dns_lookup_failed_msg
|
||||
jsr print
|
||||
jmp @print_dns_status
|
||||
:
|
||||
ldax #dns_ip
|
||||
jsr print_dotted_quad
|
||||
@print_dns_status:
|
||||
jsr print_cr
|
||||
lda dns_status
|
||||
jsr print_hex
|
||||
lda dns_status+1
|
||||
jsr print_hex
|
||||
jsr print_cr
|
||||
rts
|
||||
|
||||
overwrite_with_hardcoded_dns_server:
|
||||
ldx #3
|
||||
:
|
||||
lda hardcoded_dns_server,x
|
||||
sta cfg_dns,x
|
||||
dex
|
||||
bpl :-
|
||||
rts
|
||||
|
||||
|
||||
|
||||
.rodata
|
||||
|
||||
|
||||
buffer1: .res 256
|
||||
hostname_1:
|
||||
.byte "SLASHDOT.ORG",0 ;this should be an A record
|
||||
|
||||
hostname_2:
|
||||
.byte "VICTA.JAMTRONIX.COM",0 ;this should be a CNAME
|
||||
|
||||
hostname_3:
|
||||
.byte "WWW.JAMTRONIX.COM",0 ;this should be another CNAME
|
||||
|
||||
hostname_4:
|
||||
.byte "FOO.BAR.BOGUS",0 ;this should fail
|
||||
|
||||
hostname_5: ;this currently fails, would be nice if we noticed it was an IP address
|
||||
.byte "111.22.3.4",0
|
||||
|
||||
hostname_6: ;make sure doesn't get treated as a number
|
||||
.byte "3COM.COM",0
|
||||
|
||||
hardcoded_dns_server:
|
||||
;.byte 61,9,195,193
|
||||
;.byte 64,127,100,12
|
||||
.byte 205,171,3,65
|
||||
.byte 69,111,95,106
|
Loading…
x
Reference in New Issue
Block a user