.include "../inc/common.i" VARTAB = $2D ;BASIC variable table storage ARYTAB = $2F ;BASIC array table storage FREETOP = $33 ;bottom of string text storage area MEMSIZ = $37 ;highest address used by BASIC VARNAM = $45 ;current BASIC variable name VARPNT = $47 ; pointer to current BASIC variable value SETNAM = $FFBD SETLFS = $FFBA OPEN = $FFC0 CHKIN = $FFC6 READST = $FFB7 ; read status byte CHRIN = $FFCF ; get a byte from file CLOSE = $FFC3 MEMTOP = $FE25 TXTPTR = $7A ;BASIC text pointer IERROR = $0300 ICRUNCH = $0304 ;Crunch ASCII into token IQPLOP = $0306 ;List IGONE = $0308 ;Execute next BASIC token CHRGET = $73 CHRGOT = $79 CHROUT = $FFD2 GETBYT = $B79E ;BASIC routine GETPAR = $B7EB ;Get a 16,8 pair of numbers CHKCOM = $AEFD NEW = $A642 CLR = $A65E NEWSTT = $A7AE GETVAR = $B0E7 ;find or create a variable FRMEVL = $AD9E ;evaluate expression FRESTR = $B6A3 ;free temporary string FRMNUM = $AD8A ;get a number GETADR = $B7F7 ;convert number to 16 bit integer INLIN = $A560 ; read a line from keyboard VALTYP=$0D ;00=number, $FF=string LINNUM = $14 ;Number returned by GETPAR crunched_line = $0200 ;Input buffer .import copymem .importzp copy_src .importzp copy_dest .import dhcp_init .import ip65_init .import cfg_get_configuration_ptr .import tcp_listen .import tcp_callback .import tcp_connect_ip .import tcp_send .import tcp_connect .import tcp_close .import tcp_send_data_len .import tcp_inbound_data_ptr .import tcp_inbound_data_length .import dns_set_hostname .import dns_resolve .import dns_ip .import ip65_process .import ip65_error .import cfg_ip .import cfg_dns .import cfg_gateway .import cfg_netmask .import cfg_tftp_server .import icmp_ping .import icmp_echo_ip .import print_a .import print_cr .import dhcp_server .import cfg_mac .import cs_driver_name .importzp tftp_filename .import tftp_ip .import tftp_download .import tftp_set_callback_vector .import tftp_data_block_length .import tftp_upload .import get_key_if_available .import tcp_send_keep_alive .import timer_read .import native_to_ascii .import ascii_to_native .zeropage temp: .res 2 temp2: .res 2 pptr=temp .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 ;line number .byte $9e ;SYS .byte <(((relocate / 1000) .mod 10) + $30) .byte <(((relocate / 100 ) .mod 10) + $30) .byte <(((relocate / 10 ) .mod 10) + $30) .byte <(((relocate ) .mod 10) + $30) .byte 0 @nextline: .word 0 relocate: ldax #end_of_loader stax copy_src ldax #main_start stax copy_dest stax MEMSIZ FS=$8000-main_start ldax #FS ;copy memory 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: ldax #welcome_banner jsr print ldx #5 ;Copy CURRENT vectors @copy_old_vectors_loop: lda ICRUNCH,x sta oldcrunch,x dex bpl @copy_old_vectors_loop ldx #5 ;Copy CURRENT vectors install_new_vectors_loop: lda vectors,x sta ICRUNCH,x dex bpl install_new_vectors_loop ;BASIC keywords installed, now bring up the ip65 stack jsr ip65_init bcs @init_failed lda #0 sta ip65_error @init_failed: jsr set_error ;look for the CHAIN variabke lda #'C' sta VARNAM lda #'H'+$80 sta VARNAM+1 jsr safe_getvar .byte $92 sta (VARPNT),y jsr $A644 ;do a "NEW" jmp $A474 ;"READY" prompt welcome_banner: .incbin "welcome_banner.txt" .byte 0 end: .res 1 end_of_loader: .segment "MAINSTART" main_start: safe_getvar: ;if GETVAR doesn't find the desired variable name in the VARTABLE, a routine at $B11D will create it ;however that routine checks if the low byte of the return address of the caller is $2A. if it is, ;it assumes the caller is the routine at $AF28 which just wants to get the variable value, and ;returns a pointer to a dummy 'zero' pointer. ;so if user code that is calling GETVAR happens to be compiled to an address $xx28, it will ;trigger this check, and not create a new variable, which (from painful experience) will create ;a really nasty condition to debug! ;so vector to GETVAR via here, so the return address seen by $B11D is here, and never $xx28 jsr GETVAR rts .code ; CRUNCH -- If this is one of our keywords, then tokenize it ; crunch: jsr jmp_crunch ;First crunch line normally ldy #05 ;Offset for KERNAL ;Y will contain line length+5 @loop: sty temp jsr isword ;Are we at a keyword? bcs @gotcha @next: jsr nextchar bne @loop ;Null byte marks end sta crunched_line-3,Y ;00 line number lda #$FF ;'tis what A should be rts ;Buh-bye ; Insert token and crunch line @gotcha: ldx temp ;If so, A contains opcode sta crunched_line-5,X @move: inx lda crunched_line-5,Y sta crunched_line-5,X ;Move text backwards beq @next iny bpl @move ; ISWORD -- Checks to see if word is ; in table. If a word is found, then ; C is set, Y is one past the last char ; and A contains opcode. Otherwise, ; carry is clear. ; ; On entry, TEMP must contain current ; character position. ; isword: ldx #00 @loop: ldy temp @loop2: lda keywords,x beq @notmine cmp #$E0 bcs @done ;Tokens are >=$E0 cmp crunched_line-5,Y bne @next iny ;Success! Go to next char inx bne @loop2 @next: inx lda keywords,x ;Find next keyword cmp #$E0 bcc @next inx bne @loop ;And check again @notmine: clc @done: rts ; NEXTCHAR finds the next char ; in the buffer, skipping ; spaces and quotes. On ; entry, TEMP contains the ; position of the last spot ; read. On exit, Y contains ; the index to the next char, ; A contains that char, and Z is set if at end of line. nextchar: ldy temp @loop: iny lda crunched_line-5,Y beq @done cmp #$8F ;REM bne @cont lda #00 @skip: sta temp2 ;Find matching character @loop2: iny lda crunched_line-5,Y beq @done cmp temp2 bne @loop2 ;Skip to end of line beq @loop @cont: cmp #$20 ;space beq @loop cmp #$22 ;quote beq @skip @done: rts ; ; LIST -- patches the LIST routine ; to list our new tokens correctly. ; list: cmp #$E0 bcc @notmine ;Not my token cmp #HITOKEN bcs @notmine bit $0F ;Check for quote mode bmi @notmine sec sbc #$DF ;Find the corresponding text tax sty $49 ldy #00 @loop: dex beq @done @loop2: iny lda keywords,y cmp #$E0 bcc @loop2 iny bne @loop @done: lda keywords,y cmp #$91 ;is it "ON"? bne @not_on lda #'O' jsr CHROUT lda #'N' bne @skip @not_on: lda keywords,y bmi @out ;is it >=$80? @skip: jsr CHROUT iny bne @done @out: cmp #$E0 ;It might be BASIC token bcs @cont ldy $49 @notmine: and #$FF jmp (oldlist) @cont: ldy $49 jmp $A700 ;Normal exit ; ; EXECUTE -- if this is one of our new ; tokens, then execute it. execute: jsr CHRGET execute_a: php cmp #$8B ;is it 'IF'? bne @not_if lda #$E0 ;our dummy IF token @not_if: cmp #$E0 bcc @notmine cmp #HITOKEN bcs @notmine plp jsr @disp jmp NEWSTT @disp: eor #$E0 asl ;multiply by 2 tax lda token_routines+1,x pha lda token_routines,x pha jmp CHRGET ;exit to routine (via RTS) @notmine: plp cmp #0 ;reset flags jmp $A7E7 ;the standard BASIC IF routine calls the BASIC EXECUTE routine directly, ;without going through the vector. That means an extended keyword following THEN ;will lead to a syntax error. So we have to reimpliment IF here ;this is taken from TransBASIC - The Transactor, vol 5, Issue 04 (March 1985) page 34 if_keyword: jsr FRMEVL ;evaluate expression jsr CHRGOT cmp #$89 ;is next token GOTO? beq @ok lda #$A7 ;is next token THEN jsr $AEFF ;will generate SYNTAX ERROR if not @ok: jsr CHRGOT ldx $61 ;result of expression : 0 means false bne @expression_was_true jmp $A93B ;go to REM implementation - skips rest of line @expression_was_true: bcs @not_numeric;CHRGOT clears carry flag if current char is a number jmp $A8A0 ;do a GOTO @not_numeric: pla pla ;pop the return address off the stack jsr CHRGOT jmp execute_a ;execute current token set_result_code: pha txa pha lda #'R'+$80 sta VARNAM lda #'C'+$80 sta VARNAM+1 jsr safe_getvar ldy #0 pla sta (VARPNT),y iny pla sta (VARPNT),y clear_error: lda #0 sta ip65_error set_error: lda #'E'+$80 sta VARNAM lda #'R'+$80 sta VARNAM+1 jsr safe_getvar lda #0 tay sta (VARPNT),y iny lda ip65_error sta (VARPNT),y rts ;emit the 4 bytes pointed at by AX as dotted decimals emit_dotted_quad: sta pptr stx pptr + 1 ldy #0 lda (pptr),y jsr emit_decimal lda #'.' jsr emit_a ldy #1 lda (pptr),y jsr emit_decimal lda #'.' jsr emit_a ldy #2 lda (pptr),y jsr emit_decimal lda #'.' jsr emit_a ldy #3 lda (pptr),y jsr emit_decimal rts emit_decimal: ;emit 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 @emit_hundreds ; if N is set, the number is >=128 so emit all 3 digits cmp #10 bmi @emit_units cmp #100 bmi @emit_tens @emit_hundreds: lda temp_bcd+1 ;get the most significant digit and #$0f clc adc #'0' jsr emit_a @emit_tens: lda temp_bcd lsr lsr lsr lsr clc adc #'0' jsr emit_a @emit_units: lda temp_bcd and #$0f clc adc #'0' jsr emit_a 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 extract_string: jsr FRMEVL jsr $AD8F ;check result is a string, if not create type mismatch error ldy $19 ;temp string created by FRMEVL sty param_length lda #0 sta transfer_buffer,y dey @loop: lda ($1a),y sta transfer_buffer,y dey bpl @loop jmp FRESTR ;free up the temp string created by FRMEVL ;get a string value from BASIC command, turn into a 32 bit IP address,save it in the 4 bytes pointed at by AX get_ip_parameter: stax temp2 jsr extract_string ldax #transfer_buffer jsr dns_set_hostname bcs @error jsr dns_resolve bcc @ok @error: ldax #address_resolution jmp print_error @ok: ldax #dns_ip ldx #4 @copy_dns_ip: lda dns_ip,y sta (temp2),y iny dex bne @copy_dns_ip rts reset_string: ldy #string_buffer sty current_output_ptr+1 rts print_dotted_quad: jsr reset_string jsr emit_dotted_quad make_null_terminated_and_print: lda #0 jsr emit_a ldax #string_buffer jmp print print_mac: jsr reset_string jsr emit_mac jmp make_null_terminated_and_print ;print 6 bytes printed at by AX as a MAC address emit_mac: stax pptr ldy #0 @one_mac_digit: tya ;just to set the Z flag pha beq @dont_print_colon lda #':' jsr emit_a @dont_print_colon: pla tay lda (pptr),y jsr emit_hex iny cpy #06 bne @one_mac_digit rts emit_hex: pha pha lsr lsr lsr lsr tax lda hexdigits,x jsr emit_a pla and #$0F tax lda hexdigits,x jsr emit_a pla rts print_hex: jsr reset_string jsr emit_hex jmp make_null_terminated_and_print print_error: jsr print ldax #error jsr print lda ip65_error jsr print_hex jsr print_cr jsr set_error sec rts get_optional_byte: jsr CHRGOT beq @no_param ;leave X as it was jsr CHKCOM ;make sure next char is a comma (and skip it) jsr CHRGOT beq @eol jsr GETBYT @no_param: rts @eol: jmp $AF08 ;SYNTAX ERROR ipcfg_keyword: ldax #interface_type jsr print ldax #cs_driver_name jsr print jsr print_cr ldax #mac_address_msg jsr print ldax #cfg_mac jsr print_mac jsr print_cr 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 jmp clear_error dhcp_keyword: jsr dhcp_init bcc @init_ok jsr ip65_init ;if DHCP failed, then reinit the IP stack (which will reset IP address etc that DHCP messed with to default values) @init_failed: jsr set_error ldax #dhcp jmp print_error @init_ok: jmp clear_error rts ping_keyword: ldax #icmp_echo_ip jsr get_ip_parameter bcc @no_error rts @no_error: ;is there an optional parameter? ldx #3 jsr get_optional_byte stx ping_counter ldax #pinging jsr print ldax #dns_ip jsr print_dotted_quad jsr print_cr @ping_loop: jsr icmp_ping bcs @error jsr set_result_code lda #'.' @print_and_loop: jsr print_a lda $cb ;current key pressed cmp #$3F ;RUN/STOP? beq @done dec ping_counter bne @ping_loop @done: jsr print_cr jmp set_error @error: lda #'!' jmp @print_and_loop myip_keyword: ldax #cfg_ip jmp get_ip_parameter dns_keyword: ldax #cfg_dns jmp get_ip_parameter gateway_keyword: ldax #cfg_gateway jmp get_ip_parameter netmask_keyword: ldax #cfg_netmask jmp get_ip_parameter tftp_keyword: ldax #cfg_tftp_server jmp get_ip_parameter tf_param_setup: jsr print jsr extract_string ldax #transfer_buffer stax tftp_filename jsr print lda #' ' jsr print_a lda #'(' jsr print_a ldax #cfg_tftp_server jsr print_dotted_quad lda #')' jsr print_a jsr print_cr ldx #$03 : lda cfg_tftp_server,x sta tftp_ip,x dex bpl :- rts tfget_keyword: ldax #get_msg jsr tf_param_setup ldax #tftp_download_callback jsr tftp_set_callback_vector lda #0 sta file_opened ;make file output name lda #'@' sta string_buffer lda #':' sta string_buffer+1 ldy #$FF @loop: iny lda transfer_buffer,y sta string_buffer+2,y bne @loop iny iny lda #',' sta string_buffer,y iny lda #'P' sta string_buffer,y iny lda #',' sta string_buffer,y iny lda #'W' sta string_buffer,y iny sta string_length jsr tftp_download after_tftp_xfer: bcc @no_error ldax #tftp @error_set: jsr print_error @no_error: jsr close_file jmp set_error close_file: lda #$02 ; filenumber 2 jsr $FFC3 ; call CLOSE rts open_file: ;A,X,Y set up ready for a call to SETNAM for file #2 jsr $FFBD ; call SETNAM lda #$02 ; file number 2 ldx $BA ; last used drive ldy #$02 ; secondary address 2 jsr $FFBA ; call SETLFS jmp $FFC0 ; call OPEN tftp_download_callback: ;buffer pointed at by AX now contains "tftp_data_block_length" bytes stax temp lda #'.' jsr print_a lda file_opened bne @already_opened lda string_length ldx #string_buffer jsr open_file @already_opened: ldx #$02 ; filenumber 2 = output file jsr $FFC9 ; call CHKOUT @copy_one_byte: lda tftp_data_block_length bne @not_done lda tftp_data_block_length+1 beq @done @not_done: ldy #2 ;we want to skip the first 2 bytes in the buffer lda (temp),y jsr $ffd2 ;write byte inc temp bne :+ inc temp+1 : lda tftp_data_block_length dec tftp_data_block_length cmp #0 bne @copy_one_byte dec tftp_data_block_length+1 jmp @copy_one_byte @done: ldx #$00 ; filenumber 0 = console jmp $FFC9 ; call CHKOUT tfput_keyword: ldax #put_msg jsr tf_param_setup lda param_length ldx #transfer_buffer jsr open_file bcs @error lda $90 ;get ST beq @ok @error: ldx #4 ;"FILE NOT FOUND" error jmp $A437 ;error @ok: ldax #tftp_upload_callback jsr tftp_set_callback_vector jsr tftp_upload jmp after_tftp_xfer tftp_upload_callback: stax copy_dest lda #'.' jsr print_a lda #0 sta bytes_read sta bytes_read+1 ldx #$02 ; filenumber 2 = output file jsr $FFC6 ; call CHKIN (file 2 now used as input) @loop: jsr $FFCF ; call CHRIN (get a byte from file) ldy #0 sta (copy_dest),y inc copy_dest bne :+ inc copy_dest+1 : inc bytes_read bne :+ inc bytes_read+1 : lda bytes_read+1 cmp #2 beq @done jsr $FFB7 ; call READST (read status byte) beq @loop ; nonzero mean either EOF or read error @done: ldx #$00 ; filenumber 0 = console jsr $FFC6 ; call CHKIN (console now used as input) ldax bytes_read rts skip_comma_get_integer: jsr CHRGOT jsr CHKCOM ;make sure next char is a comma (and skip it) get_integer: jsr CHRGOT beq @eol jsr FRMNUM jsr GETADR ldax LINNUM @no_param: rts @eol: jmp $AF08 ;SYNTAX ERROR make_tcp_connection: ldax #tcp_connect_ip jsr get_ip_parameter bcc @no_error rts @no_error: jsr skip_comma_get_integer jsr tcp_connect bcc :+ @connect_error: ldax #connect jmp print_error : ldax #connected_msg jsr print lda #0 sta connection_closed clc rts netcat_keyword: ldax #netcat_callback stax tcp_callback jsr make_tcp_connection bcc :+ rts : ;is there an optional parameter? ldx #0 jsr get_optional_byte stx netcat_mode @main_polling_loop: jsr timer_read txa adc #$20 ;32 x 1/4 = ~ 8seconds sta netcat_timeout @wait_for_keypress: jsr timer_read cpx netcat_timeout bne @no_timeout jsr tcp_send_keep_alive jmp @main_polling_loop @no_timeout: jsr ip65_process lda connection_closed beq @not_disconnected ldax #disconnected jsr print rts @not_disconnected: lda netcat_mode beq @not_line_mode lda #$00 sta string_length ;process inbound ip packets while waiting for a keypress @read_line: lda $cb ;current key pressed cmp #$3F ;RUN/STOP? beq @runstop jsr ip65_process lda connection_closed beq :+ ldax #disconnected jsr print rts : jsr $f142 ;not officially documented - where F13E (GETIN) falls through to if device # is 0 (KEYBD) beq @read_line cmp #$14 ;Delete beq @delete cmp #$0d ;Return beq @input_done ;End reached? ldy string_length cpy #$FF beq @read_line jsr $ffd2 ;Print it jsr native_to_ascii sta transfer_buffer,y ;Add it to string inc string_length ;Not yet. jmp @read_line @delete: ;First, check if we're at the beginning. lda string_length bne @delete_ok jmp @read_line ;At least one character entered. @delete_ok: ;Move pointer back. dec string_length ;Print the delete char lda #$14 jsr $ffd2 ;Wait for next char jmp @read_line @input_done: lda #$0d jsr $ffd2 ;print a newline ldy string_length lda #$0d sta transfer_buffer,y iny lda #$0a sta transfer_buffer,y iny sty tcp_send_data_len jmp @send_buffer @not_line_mode: ;is there anything in the input buffer? lda $c6 ;NDX - chars in keyboard buffer bne :+ jmp @wait_for_keypress : lda #0 sta tcp_send_data_len sta tcp_send_data_len+1 @get_next_char: lda $cb ;current key pressed cmp #$3F ;RUN/STOP? bne @not_runstop @runstop: lda #0 sta $cb ;overwrite "current key pressed" else it's seen by the tcp stack and the close aborts jmp tcp_close @not_runstop: jsr $ffe4 ;getkey - 0 means no input tax beq @no_more_input txa ldy tcp_send_data_len sta transfer_buffer,y inc tcp_send_data_len jmp @get_next_char @no_more_input: @send_buffer: ldax #transfer_buffer jsr tcp_send bcs @error_on_send jmp @main_polling_loop @error_on_send: ldax #transmission jmp print_error netcat_callback: lda tcp_inbound_data_length+1 cmp #$ff bne @not_eof lda #1 sta connection_closed rts @not_eof: ldax tcp_inbound_data_ptr stax temp2 lda tcp_inbound_data_length sta buffer_length lda tcp_inbound_data_length+1 sta buffer_length+1 @next_byte: lda $cb ;current key pressed cmp #$3F ;RUN/STOP? beq @finished ldy #0 lda (temp2),y ldx netcat_mode beq @no_transform jsr ascii_to_native @no_transform: jsr print_a inc temp2 bne :+ inc temp2+1 : lda buffer_length+1 beq @last_page lda buffer_length bne @not_end_of_page dec buffer_length+1 @not_end_of_page: dec buffer_length jmp @next_byte @last_page: dec buffer_length beq @finished jmp @next_byte @finished: rts tcpconnect_keyword: lda #0 sta data_arrived_flag ldax #tcpconnect_callback stax tcp_callback jmp make_tcp_connection tcpconnect_callback: inc data_arrived_flag ldax #transfer_buffer stax copy_dest ldax tcp_inbound_data_ptr stax copy_src lda tcp_inbound_data_length ldx tcp_inbound_data_length+1 beq @short_packet cpx #$ff bne @not_end_packet inc data_arrived_flag rts @not_end_packet: lda #$ff @short_packet: set_input_string: pha lda #'I' sta VARNAM lda #'N'+$80 sta VARNAM+1 jsr safe_getvar ldy #0 pla pha sta (VARPNT),y iny lda #transfer_buffer sta (VARPNT),y pla beq :+ ldx #0 jsr copymem : rts poll_keyword: ldax #$FFFF jsr set_result_code lda #0 sta data_arrived_flag jsr set_input_string jsr ip65_process lda ip65_error beq @no_error jmp set_error @no_error: lda data_arrived_flag ldx #0 jmp set_result_code .rodata vectors: .word crunch .word list .word execute ; Keyword list ; Keywords are stored as normal text, ; followed by the token number. ; All tokens are >$80, ; so they easily mark the end of the keyword hexdigits: .byte "0123456789ABCDEF" pinging: .byte"PINGING ",0 interface_type: .byte "INTERFACE : ",0 mac_address_msg: .byte "MAC ADDRESS : ", 0 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 address_resolution: .byte "ADDRESS RESOLUTION",0 get_msg: .byte "GETTING ",0 put_msg: .byte "PUTTING ",0 tftp: .byte "TFTP",0 dhcp: .byte "DHCP",0 connect: .byte "CONNECT",0 transmission: .byte "TRANSMISSION",0 error: .byte " ERROR $",0 disconnected: .byte 13,"DIS" connected_msg: .byte "CONNECTED",13,0 keywords: .byte "IF",$E0 ;our dummy 'IF' entry takes $E0 .byte "IPCFG",$E1 .byte "DHCP",$E2 .byte "PING",$E3 .byte "MYIP",$E4 .byte "NETMASK",$E5 .byte "GATEWAY",$E6 .byte "DNS",$E7 .byte "TFTP",$E8 .byte "TF",$A1,$E9 ;TFGET - BASIC will replace GET with A1 .byte "TFPUT",$EA .byte "NETCAT",$EB .byte "TCPC",$91,"NECT",$EC ; TCPCONNECT BASIC will replace ON with 91 .byte "POLL",$ED .byte $00 ;end of list HITOKEN=$EE ; ; Table of token locations-1 ; token_routines: E0: .word if_keyword-1 E1: .word ipcfg_keyword-1 E2: .word dhcp_keyword-1 E3: .word ping_keyword-1 E4: .word myip_keyword-1 E5: .word netmask_keyword-1 E6: .word gateway_keyword-1 E7: .word dns_keyword-1 E8: .word tftp_keyword-1 E9: .word tfget_keyword-1 EA: .word tfput_keyword-1 EB: .word netcat_keyword-1 EC: .word tcpconnect_keyword-1 ED: .word poll_keyword-1 .segment "SELF_MODIFIED_CODE" jmp_crunch: .byte $4C ;JMP oldcrunch: .res 2 ;Old CRUNCH vector oldlist: .res 2 oldexec: .res 2 emit_a: current_output_ptr=emit_a+1 sta $ffff inc string_length inc current_output_ptr bne :+ inc current_output_ptr+1 : rts .bss netcat_mode: .res 1 bytes_read: .res 2 string_length: .res 1 param_length: .res 1 ip_string: .res 15 netmask_string: .res 15 dns_string: .res 15 gateway_string: .res 15 temp_bin: .res 1 temp_bcd: .res 2 ping_counter: .res 1 string_buffer: .res 128 transfer_buffer: .res 256 file_opened: .res 1 connection_closed: .res 1 netcat_timeout: .res 1 buffer_length: .res 2 data_arrived_flag: .res 1