From bc23bcc3fd75f5f7ea5825710aa2ddd50bb9f934 Mon Sep 17 00:00:00 2001 From: jonnosan Date: Wed, 15 Apr 2009 21:39:33 +0000 Subject: [PATCH] git-svn-id: http://svn.code.sf.net/p/netboot65/code@106 93682198-c243-4bdb-bd91-e943c89aac3b --- client/inc/nb65_constants.i | 4 +- client/ip65/function_dispatcher.s | 16 ++++++- client/nb65/Makefile | 1 + client/test/test_cart_api.s | 62 +++++++++++++++++++++++++-- doc/nb65_api_technical_reference.doc | Bin 100864 -> 103424 bytes 5 files changed, 75 insertions(+), 8 deletions(-) diff --git a/client/inc/nb65_constants.i b/client/inc/nb65_constants.i index b87b924..afeae16 100644 --- a/client/inc/nb65_constants.i +++ b/client/inc/nb65_constants.i @@ -34,7 +34,7 @@ NB65_UDP_ADD_LISTENER EQU $06 ;inputs: AX points to a UDP listener para NB65_GET_INPUT_PACKET_INFO EQU $07 ;inputs: AX points to a UDP packet parameter structure, outputs: UDP packet structure filled in NB65_SEND_UDP_PACKET EQU $08 ;inputs: AX points to a UDP packet parameter structure, outputs: none packet is sent NB65_DEACTIVATE EQU $09 ;inputs: none, outputs: none (removes call to NB65_VBL_VECTOR on IRQ chain) - +NB65_TFTP_CALLBACK_DOWNLOAD EQU $0A ;inputs: AX points to a TFTP parameter structure, outputs: none NB65_PRINT_ASCIIZ EQU $80 ;inputs: AX=pointer to null terminated string to be printed to screen, outputs: none NB65_PRINT_HEX EQU $81 ;inputs: A=byte digit to be displayed on screen as (zero padded) hex digit, outputs: none NB65_PRINT_DOTTED_QUAD EQU $82 ;inputs: AX=pointer to 4 bytes that will be displayed as a decimal dotted quad (e.g. 192.168.1.1) @@ -56,7 +56,7 @@ NB65_DRIVER_NAME EQU $1A ;2 byte pointer to name of driver ;offsets in TFTP parameter structure (used by NB65_TFTP_DIRECTORY_LISTING & NB65_TFTP_DOWNLOAD) NB65_TFTP_IP EQU $00 ;4 byte IP address of TFTP server NB65_TFTP_FILENAME EQU $04 ;2 byte pointer to asciiz filename (or filemask in case of NB65_TFTP_DIRECTORY_LISTING) -NB65_TFTP_POINTER EQU $06 ;2 byte pointer to memory location data to be stored in +NB65_TFTP_POINTER EQU $06 ;2 byte pointer to memory location data to be stored in OR address of callback function ;offsets in DNS parameter structure (used by NB65_DNS_RESOLVE) NB65_DNS_HOSTNAME EQU $00 ;2 byte pointer to asciiz hostname to resolve (can also be a dotted quad string) diff --git a/client/ip65/function_dispatcher.s b/client/ip65/function_dispatcher.s index 81c8821..1abf2c6 100644 --- a/client/ip65/function_dispatcher.s +++ b/client/ip65/function_dispatcher.s @@ -21,6 +21,7 @@ .import ip65_error .import tftp_clear_callbacks .import tftp_download +.import tftp_set_download_callback .import dns_ip .import dns_resolve .import dns_set_hostname @@ -88,7 +89,6 @@ set_tftp_params: jsr tftp_clear_callbacks - clc rts nb65_dispatcher: @@ -151,7 +151,6 @@ irq_handler_installed: cpy #NB65_TFTP_DOWNLOAD bne :+ jsr set_tftp_params - bcs @tftp_error jsr tftp_download jmp @after_tftp_call : @@ -292,6 +291,19 @@ irq_handler_installed: rts : + cpy #NB65_TFTP_CALLBACK_DOWNLOAD + bne :+ + jsr set_tftp_params + ldy #NB65_TFTP_POINTER+1 + lda (nb65_params),y + tax + dey + lda (nb65_params),y + jsr tftp_set_download_callback + jmp tftp_download +: + + cpy #NB65_PRINT_ASCIIZ bne :+ jsr print diff --git a/client/nb65/Makefile b/client/nb65/Makefile index fdd0233..30845f5 100644 --- a/client/nb65/Makefile +++ b/client/nb65/Makefile @@ -56,6 +56,7 @@ utherboot.dsk: utherboot.pg2 c64boot.d64: nb65_c64_ram.prg ripxplore.rb --init CbmDos $@ -a nb65_c64_ram.prg + ripxplore.rb $@ -a ..\test\test_cart_api.prg $(BOOTA2.PG2): bootmenu.o $(IP65LIB) $(APPLE2PROGLIB) $(INCFILES) ../cfg/a2language_card.cfg $(LD) -m bootmenu.map -C ../cfg/a2language_card.cfg -o $(BOOTA2.PG2) $< $(IP65LIB) $(APPLE2PROGLIB) diff --git a/client/test/test_cart_api.s b/client/test/test_cart_api.s index 4b9001f..8c93777 100644 --- a/client/test/test_cart_api.s +++ b/client/test/test_cart_api.s @@ -33,7 +33,8 @@ print_a = $ffd2 .bss nb65_param_buffer: .res $20 - + block_number: .res $0 + .segment "STARTUP" ;this is what gets put at the start of the file on the C64 .word basicstub ; load address @@ -136,7 +137,24 @@ init: call #NB65_PRINT_DOTTED_QUAD print_cr -;callback test +;tftp callback test + lda #0 + sta block_number + lda #$FF + ldx #$03 +: + sta nb65_param_buffer,x ;set TFTP server as broadcast address + dex + bpl :- + ldax #test_file + stax nb65_param_buffer+NB65_TFTP_FILENAME + ldax #tftp_callback + stax nb65_param_buffer+NB65_TFTP_POINTER + ldax #nb65_param_buffer + call #NB65_TFTP_CALLBACK_DOWNLOAD + + +;udp callback test ldax #64 ;listen on port 64 stax nb65_param_buffer+NB65_UDP_LISTENER_PORT @@ -157,6 +175,15 @@ init: jsr NB65_PERIODIC_PROCESSING_VECTOR jmp @loop_forever + +tftp_callback: + inc block_number + print #block_no + lda block_number + jsr print_hex + print_cr + rts + udp_callback: ldax #nb65_param_buffer @@ -260,7 +287,28 @@ get_key: beq get_key rts - .rodata + 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" + test_hostname: .byte "RETROHACKERS.COM",0 ;this should be an A record @@ -286,7 +334,10 @@ length: data: .byte "DATA: ",0 - + +block_no: + .byte "BLOCK: $",0 + error_code: .asciiz "ERROR CODE: $" press_a_key_to_continue: @@ -309,5 +360,8 @@ reply_message: reply_message_end: reply_message_length=reply_message_end-reply_message +test_file: +.byte "BOOTA2.PG2",0 + nb65_signature: .byte $4E,$42,$36,$35 ; "NB65" - API signature \ No newline at end of file diff --git a/doc/nb65_api_technical_reference.doc b/doc/nb65_api_technical_reference.doc index 695f8bfa096bdd76e955433717fddd77135a5d5d..d937267869b1267375c82edec039d6faa3ea7235 100644 GIT binary patch delta 12507 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 E7l$fewEzGB