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 ec91eb9..3ffb3d8 100644 Binary files a/doc/nb65_api_technical_reference.doc and b/doc/nb65_api_technical_reference.doc differ