From 4027ab28efb49a9a6fd618deeed8525261b8dfb5 Mon Sep 17 00:00:00 2001 From: jonnosan Date: Sun, 19 Jul 2009 10:57:28 +0000 Subject: [PATCH] git-svn-id: http://svn.code.sf.net/p/netboot65/code@163 93682198-c243-4bdb-bd91-e943c89aac3b --- client/drivers/Makefile | 4 +- client/drivers/c64_disk_access.s | 239 +++++++++++++++++++++++++++ client/examples/httpd.asm | 136 ++++++++++++--- client/inc/nb65_constants.i | 11 +- client/ip65/function_dispatcher.s | 39 +++++ client/ip65/tcp.s | 4 +- client/nb65/nb65_c64.s | 8 + client/test/Makefile | 6 +- client/test/test_disk_io.s | 140 ++++++++++++++++ doc/nb65_api_technical_reference.doc | Bin 131584 -> 137728 bytes 10 files changed, 559 insertions(+), 28 deletions(-) create mode 100644 client/drivers/c64_disk_access.s create mode 100644 client/test/test_disk_io.s diff --git a/client/drivers/Makefile b/client/drivers/Makefile index d4eded6..8ba13d6 100644 --- a/client/drivers/Makefile +++ b/client/drivers/Makefile @@ -21,10 +21,10 @@ all: $(DRIVERS) apple2prog.lib: a2print.o uthernet.o a2timer.o a2kernal.o a2input.o ar65 a $@ $^ -c64prog.lib: c64print.o rr-net.o c64timer.o c64kernal.o c64inputs.o +c64prog.lib: c64print.o rr-net.o c64timer.o c64kernal.o c64inputs.o c64_disk_access.o ar65 a $@ $^ -c64nb65.lib: c64print.o rr-net.o c64timer_nb65.o c64kernal.o c64inputs.o +c64nb65.lib: c64print.o rr-net.o c64timer_nb65.o c64kernal.o c64inputs.o c64_disk_access.o ar65 a $@ $^ clean: diff --git a/client/drivers/c64_disk_access.s b/client/drivers/c64_disk_access.s new file mode 100644 index 0000000..bb9af0f --- /dev/null +++ b/client/drivers/c64_disk_access.s @@ -0,0 +1,239 @@ +;C64 disk access routines +; + + +.ifndef NB65_API_VERSION_NUMBER + .define EQU = + .include "../inc/nb65_constants.i" +.endif + +.include "../inc/common.i" +.export io_device_no +.export io_sector_no +.export io_track_no +.export io_read_sector + +.importzp copy_src +.import ip65_error +.import output_buffer +;.importzp copy_dest + +;reuse the copy_src zero page location +buffer_ptr = copy_src + +;######### KERNEL functions +CHKIN = $ffc6 +CHKOUT = $ffc9 +CHRIN = $ffcf +CHROUT = $ffd2 +CLALL = $FFE7 +CLOSE = $ffc3 +OPEN = $ffc0 +READST = $ffb7 +SETNAM = $ffbd +SETLFS = $ffba + +.bss + + io_track_no: .res 2 + io_sector_no: .res 1 + io_device_no: .res 1 + + error_buffer = output_buffer + 256 + command_buffer = error_buffer+128 + sector_buffer_address: .res 2 + +.data + drive_id: .byte 08 ;default to drive 8 + + +.code + ; init + ; jsr CLALL + + ;close +; lda #15 ; filenumber 15 - command channel +; jsr CLOSE + + ;jsr read_sector +; lda #$30 + + +;routine to read a sector +;cribbed from http://codebase64.org/doku.php?id=base:reading_a_sector +;inputs: +; io_device_number set to specify drive to use ($00 = same as last time, $01 = first disk (i.e. #8), $02 = 2nd disk (drive #9)) +; io_sector_no - set to sector number to be read +; io_track_no - set to track number to be read (only lo byte is used) +; AX - address of buffer to read sector into +; outputs: +; on errror, carry flag is set. otherwise buffer will be filled with 256 bytes + +io_read_sector: + + stax sector_buffer_address + lda io_device_no + beq @drive_id_set + clc + adc #07 ;so 01->08, 02->09 etc + sta drive_id + jsr make_read_sector_command +@drive_id_set: + lda #1 + ldx #cname + jsr SETNAM + lda #02 + ldx drive_id + ldy #02 + jsr SETLFS + jsr OPEN + bcs @error + ldx #command_buffer + lda #12 + jsr SETNAM + lda #15 + ldx $BA ;use whatever was last device # + ldy #15 + jsr SETLFS + jsr OPEN + bcs @error + + jsr check_error_channel + lda #$30 + cmp error_buffer + beq @was_not_an_error + lda #NB65_ERROR_DEVICE_FAILURE + sta ip65_error + sec + rts + @was_not_an_error: + ldx #$02 ; filenumber 2 + jsr CHKIN ;(file 2 now used as input) + + lda sector_buffer_address + sta buffer_ptr + lda sector_buffer_address+1 + sta buffer_ptr+1 + ldy #$00 +@loop: + jsr CHRIN ;(get a byte from file) + sta (buffer_ptr),Y ; write byte to memory + iny + bne @loop ; next byte, end when 256 bytes are read +@close: + lda #15 ; filenumber 15 + jsr CLOSE + lda #$02 ; filenumber 2 + jsr CLOSE + ldx #$00 ; filenumber 0 = keyboard + jsr CHKIN ;(keyboard now input device again) + clc + rts +@error: + lda #NB65_ERROR_DEVICE_FAILURE + sta ip65_error + jmp @close + +check_error_channel: + LDX #$0F ; filenumber 15 + JSR CHKIN ;(file 15 now used as input) + LDY #$00 +@loop: + JSR READST ;(read status byte) + BNE @eof ; either EOF or read error + JSR CHRIN ;(get a byte from file) + sta error_buffer,y + iny + JMP @loop ; next byte + +@eof: + lda #0 + sta error_buffer,y + LDX #$00 ; filenumber 0 = keyboard + JSR CHKIN ;(keyboard now input device again) + rts + +make_read_sector_command: +;fill command buffer with command to read in track & sector +;returns length of command in Y + + ldy #0 + lda #85 ;"U" + sta command_buffer,y + iny + lda #$31 ;"1" + sta command_buffer,y + iny + lda #$20 ;" " + sta command_buffer,y + iny + lda #$32 ;"2" - file number + sta command_buffer,y + iny + lda #$20 ;" " + sta command_buffer,y + iny + lda #$30 ;"0" - drive number + sta command_buffer,y + iny + lda #$20 ;" " + sta command_buffer,y + iny + lda io_track_no + jsr byte_to_ascii + pha + txa + sta command_buffer,y + pla + iny + sta command_buffer,y + iny + lda #$20 ;" " + sta command_buffer,y + iny + lda io_sector_no + jsr byte_to_ascii + pha + txa + sta command_buffer,y + pla + iny + sta command_buffer,y + iny + + lda #0 + sta command_buffer,y ;make it ASCIIZ so we can print it + + rts + +byte_to_ascii: + cmp #30 + bmi @not_30 + ldx #$33 + clc + adc #18 + rts +@not_30: + cmp #20 + bmi @not_20 + ldx #$32 + clc + adc #28 + rts +@not_20: + cmp #10 + bmi @not_10 + ldx #$31 + clc + adc #38 + rts +@not_10: + ldx #$30 + clc + adc #48 + rts + +.rodata +cname: .byte '#' \ No newline at end of file diff --git a/client/examples/httpd.asm b/client/examples/httpd.asm index 8ede624..b398d1e 100644 --- a/client/examples/httpd.asm +++ b/client/examples/httpd.asm @@ -43,8 +43,8 @@ ;some routines & zero page variables -print_a equ $ffd2 -temp_ptr equ $FB ; scratch space in page zero +print_a equ $ffd2 +temp_ptr equ $FB ; scratch space in page zero ;start of code @@ -88,7 +88,11 @@ found_nb65_signature ;print out the current configuration nb65call #NB65_PRINT_IP_CONFIG + listen_on_port_80 + + ldaxi #scratch_buffer + stax tcp_buffer_ptr print #waiting ldaxi #80 ;port number stax nb65_param_buffer+NB65_TCP_PORT @@ -98,8 +102,7 @@ listen_on_port_80 stx nb65_param_buffer+NB65_TCP_REMOTE_IP+3 ldaxi #http_callback stax nb65_param_buffer+NB65_TCP_CALLBACK - ldaxi #nb65_param_buffer - + ldaxi #nb65_param_buffer nb65call #NB65_TCP_CONNECT ;wait for inbound connect bcc .connected_ok print #error_while_waiting @@ -109,30 +112,38 @@ listen_on_port_80 print #ok lda #0 sta connection_closed + sta found_eol .main_polling_loop jsr NB65_PERIODIC_PROCESSING_VECTOR + lda found_eol + beq .no_eol_yet + nb65call #NB65_PRINT_HEX + lda #"!" + jsr print_a + ldaxi #4 + stax nb65_param_buffer+NB65_TCP_PAYLOAD_LENGTH + ldaxi #press_a_key_to_continue + stax nb65_param_buffer+NB65_TCP_PAYLOAD_POINTER + ldaxi #nb65_param_buffer + nb65call #NB65_SEND_TCP_PACKET + + ldaxi #4 + stax nb65_param_buffer+NB65_TCP_PAYLOAD_LENGTH + ldaxi #nb65_signature + stax nb65_param_buffer+NB65_TCP_PAYLOAD_POINTER + ldaxi #nb65_param_buffer + nb65call #NB65_SEND_TCP_PACKET + + nb65call #NB65_TCP_CLOSE_CONNECTION + jmp listen_on_port_80 +.no_eol_yet lda connection_closed beq .main_polling_loop jmp listen_on_port_80 -;http callback - will be executed whenever data arrives on the TCP connection -http_callback - ldaxi #nb65_param_buffer - nb65call #NB65_GET_INPUT_PACKET_INFO - lda nb65_param_buffer+NB65_PAYLOAD_LENGTH+1 - cmp #$ff - bne .not_eof - lda #1 - sta connection_closed - rts -.not_eof - ldax nb65_param_buffer+NB65_PAYLOAD_POINTER - stax temp_ptr - ldax nb65_param_buffer+NB65_PAYLOAD_LENGTH - stax buffer_length - rts + ;look for NB65 signature at location pointed at by AX look_for_signature subroutine @@ -181,7 +192,73 @@ print_errorcode print_cr rts +;http callback - will be executed whenever data arrives on the TCP connection +http_callback + ldaxi #nb65_param_buffer + nb65call #NB65_GET_INPUT_PACKET_INFO + lda nb65_param_buffer+NB65_PAYLOAD_LENGTH+1 + cmp #$ff + bne .not_eof + lda #1 + sta connection_closed + rts +.not_eof + + lda #"*" + jsr print_a + + ldax nb65_param_buffer+NB65_PAYLOAD_POINTER + stax tcp_inbound_data_ptr + ldax nb65_param_buffer+NB65_PAYLOAD_LENGTH + stax tcp_inbound_data_length + +;copy this chunk to our input buffer + ldax tcp_buffer_ptr + stax nb65_param_buffer+NB65_BLOCK_DEST + ldax tcp_inbound_data_ptr + stax nb65_param_buffer+NB65_BLOCK_SRC + ldax tcp_inbound_data_length + stax nb65_param_buffer+NB65_BLOCK_SIZE + ldaxi #nb65_param_buffer + nb65call #NB65_BLOCK_COPY + + +;increment the pointer into the input buffer + clc + lda tcp_buffer_ptr + adc tcp_inbound_data_length + sta tcp_buffer_ptr + sta temp_ptr + lda tcp_buffer_ptr+1 + adc tcp_inbound_data_length+1 + sta tcp_buffer_ptr+1 + sta temp_ptr + +;put a null byte at the end (assumes we have set temp_ptr already) + lda #0 + tay + sta (temp_ptr),y + +;look for EOL ($0D) in input + sta found_eol + ldaxi #scratch_buffer + stax get_next_byte+1 + +.look_for_eol + jsr get_next_byte + cmp #$0a + bne .found_eol + cmp #$0d + bne .not_eol +.found_eol + inc found_eol + rts +.not_eol + cmp #0 + bne .look_for_eol + rts + ;constants nb65_api_not_found_message dc.b "ERROR - NB65 API NOT FOUND.",13,0 @@ -198,9 +275,24 @@ disconnected dc.b 13,"CONNECTION CLOSED",13,0 failed dc.b "FAILED ", 0 ok dc.b "OK ", 0 transmission_error dc.b "ERROR WHILE SENDING ",0 + +;self modifying code +get_next_byte + lda $ffff + inc get_next_byte+1 + bne .skip + inc get_next_byte+2 +.skip + rts + + ;variables connection_closed ds.b 1 +found_eol ds.b 1 nb65_param_buffer DS.B $20 -buffer_length: ds.b 2 -buffer_pointer: ds.b 2 +tcp_buffer_ptr ds.b 2 +scan_ptr ds.b 2 +tcp_inbound_data_ptr ds.b 2 +tcp_inbound_data_length ds.b 2 scratch_buffer: DS.B $1000 + diff --git a/client/inc/nb65_constants.i b/client/inc/nb65_constants.i index 234fd76..3b3b7ee 100644 --- a/client/inc/nb65_constants.i +++ b/client/inc/nb65_constants.i @@ -56,6 +56,8 @@ NB65_PRINT_IP_CONFIG EQU $83 ;no inputs, no outputs, prints to screen NB65_INPUT_HOSTNAME EQU $90 ;no inputs, outputs: AX = pointer to hostname (which may be IP address). NB65_INPUT_PORT_NUMBER EQU $91 ;no inputs, outputs: AX = port number entered ($0000..$FFFF) +NB65_BLOCK_COPY EQU $A0 ;inputs: AX points to a block copy structure, outputs: none + NB65_GET_LAST_ERROR EQU $FF ;no inputs, outputs A EQU error code (from last function that set the global error value, not necessarily the ;last function that was called) @@ -68,8 +70,8 @@ NB65_CFG_DNS_SERVER EQU $12 ;4 byte IP address of DNS server (will be overw NB65_CFG_DHCP_SERVER EQU $16 ;4 byte IP address of DHCP server (will only be set by DHCP initialisation) NB65_DRIVER_NAME EQU $1A ;2 byte pointer to name of driver -;offsets in TFTP transfer parameter structure (used by NB65_TFTP_DIRECTORY_LISTING & NB65_TFTP_DOWNLOAD) -NB65_TFTP_FILENAME EQU $00 ;2 byte pointer to asciiz filename (or filemask in case of NB65_TFTP_DIRECTORY_LISTING) +;offsets in TFTP transfer parameter structure (used by NB65_TFTP_DOWNLOAD, NB65_TFTP_CALLBACK_DOWNLOAD, NB65_TFTP_UPLOAD, NB65_TFTP_CALLBACK_UPLOAD) +NB65_TFTP_FILENAME EQU $00 ;2 byte pointer to asciiz filename (or filemask) NB65_TFTP_POINTER EQU $02 ;2 byte pointer to memory location data to be stored in OR address of callback function NB65_TFTP_FILESIZE EQU $04 ;2 byte file length (filled in by NB65_TFTP_DOWNLOAD, must be passed in to NB65_TFTP_UPLOAD) @@ -84,6 +86,11 @@ NB65_DNS_HOSTNAME_IP EQU $00 ;4 byte IP address (filled NB65_UDP_LISTENER_PORT EQU $00 ;2 byte port number NB65_UDP_LISTENER_CALLBACK EQU $02 ;2 byte address of routine to call when UDP packet arrives for specified port +;offsets in block copy parameter structure +NB65_BLOCK_SRC EQU $00 ;2 byte address of start of source block +NB65_BLOCK_DEST EQU $02 ;2 byte address of start of destination block +NB65_BLOCK_SIZE EQU $04 ;2 byte length of block to be copied (in bytes + ;offsets in TCP connect parameter structure NB65_TCP_REMOTE_IP EQU $00 ;4 byte IP address of remote host (0.0.0.0 means wait for inbound i.e. server mode) diff --git a/client/ip65/function_dispatcher.s b/client/ip65/function_dispatcher.s index 72b73b1..3409071 100644 --- a/client/ip65/function_dispatcher.s +++ b/client/ip65/function_dispatcher.s @@ -557,6 +557,45 @@ cpy #NB65_INPUT_PORT_NUMBER @no_port_entered: rts : + +cpy #NB65_BLOCK_COPY + bne :+ + ;this is where we pay the price for trying to save a few 'zero page' pointers + ;by reusing the 'copy_src' and 'copy_dest' addresses! +.segment "TCP_VARS" + tmp_copy_src: .res 2 + tmp_copy_dest: .res 2 + tmp_copy_length: .res 2 +.code + + ldy #NB65_BLOCK_SRC + lda (nb65_params),y + sta tmp_copy_src + iny + lda (nb65_params),y + sta tmp_copy_src+1 + + ldy #NB65_BLOCK_DEST + lda (nb65_params),y + sta tmp_copy_dest + iny + lda (nb65_params),y + sta tmp_copy_dest+1 + + ldy #NB65_BLOCK_SIZE + lda (nb65_params),y + sta tmp_copy_length + iny + lda (nb65_params),y + sta tmp_copy_length+1 + + ldax tmp_copy_src + stax copy_src + ldax tmp_copy_dest + stax copy_dest + ldax tmp_copy_length + jmp copymem +: .endif .endif diff --git a/client/ip65/tcp.s b/client/ip65/tcp.s index db51519..7d5b896 100644 --- a/client/ip65/tcp.s +++ b/client/ip65/tcp.s @@ -187,7 +187,8 @@ tcp_listen: lda #tcp_cxn_state_listening cmp tcp_state beq @listen_loop - clc + + jmp tcp_connection_established rts ;make outbound tcp connection @@ -277,6 +278,7 @@ tcp_connect: sec ;signal an error rts @got_a_response: +tcp_connection_established: ;inc the sequence number to cover the SYN we have sent ldax #tcp_connect_sequence_number stax acc32 diff --git a/client/nb65/nb65_c64.s b/client/nb65/nb65_c64.s index 6a1b95d..9f55235 100644 --- a/client/nb65/nb65_c64.s +++ b/client/nb65/nb65_c64.s @@ -258,6 +258,10 @@ main_menu: @get_key_config_menu: jsr ip65_process jsr get_key + cmp #KEYCODE_ABORT + bne @not_abort + jmp main_menu +@not_abort: cmp #KEYCODE_F1 bne @not_ip ldax #new @@ -547,6 +551,10 @@ net_apps_menu: @get_key: jsr ip65_process jsr get_key +cmp #KEYCODE_ABORT + bne @not_abort + jmp main_menu +@not_abort: cmp #KEYCODE_F1 bne @not_telnet jsr cls diff --git a/client/test/Makefile b/client/test/Makefile index 92ce1bc..4fb4c50 100644 --- a/client/test/Makefile +++ b/client/test/Makefile @@ -21,7 +21,8 @@ INCFILES=\ all: \ ip65test.dsk \ testdns.prg \ - gopher_browser.prg \ + test_disk_io.prg \ + test_disk_io.d64 \ testdns.pg2 \ testtftp.prg \ testtftp.pg2\ @@ -54,6 +55,9 @@ ip65test.dsk: testdns.pg2 testdottedquad.pg2 testtftp.pg2 ripxplore.rb ip65test.dsk -a testtftp.pg2 -t AppleBinary ripxplore.rb ip65test.dsk -a testdottedquad.pg2 -t AppleBinary ripxplore.rb ip65test.dsk -a testdns.pg2 -t AppleBinary + +test_disk_io.d64: test_disk_io.prg + ripxplore.rb --init CbmDos test_disk_io.d64 -a test_disk_io.prg clean: rm -f *.o *.pg2 *.prg diff --git a/client/test/test_disk_io.s b/client/test/test_disk_io.s new file mode 100644 index 0000000..437f1e2 --- /dev/null +++ b/client/test/test_disk_io.s @@ -0,0 +1,140 @@ + +.ifndef NB65_API_VERSION_NUMBER + .define EQU = + .include "../inc/nb65_constants.i" +.endif + +.include "../inc/common.i" +.include "../inc/commonprint.i" +.import print_a +.import cfg_get_configuration_ptr +.import io_device_no +.import io_sector_no +.import io_track_no +.import io_read_sector +.import ip65_error + +.macro cout arg + lda arg + jsr print_a +.endmacro + + + +.bss + sector_buffer: .res 256 + output_buffer: .res 520 + .export output_buffer +current_byte: .res 1 + +.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 + +init: + + lda #01 + sta io_track_no + lda #01 + sta io_sector_no + lda #01 + sta io_device_no + ldax #sector_buffer + jsr io_read_sector + bcs @error + + ; jsr dump_sector ;DEBUG + + lda #$12 + sta io_track_no + lda #01 + sta io_sector_no + lda #01 + sta io_device_no + ldax #sector_buffer + jsr io_read_sector + + bcs @error + jsr dump_sector ;DEBUG + +@error: + jsr print_cr + lda ip65_error + jsr print_hex + rts + +dump_sector: +;hex dump sector + lda #0 + sta current_byte +@dump_byte: + ldy current_byte + lda sector_buffer,y + jsr print_hex + lda sector_buffer,y + jsr print_a + inc current_byte + bne @dump_byte +rts + + +.rodata + +error_code: + .byte "ERROR CODE: $",0 +press_a_key_to_continue: + .byte "PRESS A KEY TO CONTINUE",13,0 + +failed: + .byte "FAILED ", 0 + +ok: + .byte "OK ", 0 + +initializing: + .byte "INITIALIZING ",0 +track_no: + .byte "TRACK ",0 + + +sector_no: + .byte " SECTOR ",0 + +signon_message: + .byte "D64 UPLOADER V0.1",13,0 + +enter_filename: +.byte "SEND AS: ",0 + +drive_error: + .byte "DRIVE ACCESS ERROR - ",0 + nb65_signature_not_found_message: + .byte "NO NB65 API FOUND",13,"PRESS ANY KEY TO RESET", 0 + error_opening_channel: + .byte "ERROR OPENING CHANNEL $",0 + +disk_access: +.byte 13,13,13,13,13,"SENDING TO CHANNEL $",0 + +nb65_signature: + .byte $4E,$42,$36,$35 ; "NB65" - API signature + .byte ' ',0 ; so we can use this as a string +position_cursor_for_track_display: +; .byte $13,13,13,13,13,13,13,13,13,13,13," SENDING ",0 +.byte $13,13,13,"SENDING ",0 +position_cursor_for_error_display: + .byte $13,13,13,13,"LAST ",0 + +cname: .byte '#' \ No newline at end of file diff --git a/doc/nb65_api_technical_reference.doc b/doc/nb65_api_technical_reference.doc index ec91eb9ffa110dd0ed5de84689f0160b54fc6173..3ffb3d86b2b3805b3f1319218daa739e7a40fb3a 100644 GIT binary patch delta 15644 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 F`yX5jWjX)=