mirror of
https://github.com/bobbimanners/emailler.git
synced 2025-01-07 14:30:35 +00:00
746 lines
13 KiB
ArmAsm
746 lines
13 KiB
ArmAsm
|
|
.include "../inc/common.i"
|
|
.ifndef KPR_API_VERSION_NUMBER
|
|
.define EQU =
|
|
.include "../inc/kipper_constants.i"
|
|
.endif
|
|
|
|
|
|
SERVER_PORT=1541
|
|
.define SERVERNAME "COMMODORESERVER.COM"
|
|
|
|
.import ip65_init
|
|
.import dhcp_init
|
|
.import tcp_connect
|
|
.import dns_resolve
|
|
.import dns_set_hostname
|
|
.import dns_ip
|
|
.import print_a
|
|
.import tcp_connect_ip
|
|
.import tcp_send
|
|
.import tcp_send_data_len
|
|
.import tcp_send_string
|
|
.import tcp_connect
|
|
.import tcp_close
|
|
.import tcp_callback
|
|
.import ip65_process
|
|
.import ip65_error
|
|
.import tcp_state
|
|
.import copymem
|
|
.import check_for_abort_key
|
|
.import tcp_inbound_data_ptr
|
|
.import tcp_inbound_data_length
|
|
.import tcp_send_keep_alive
|
|
.import get_key
|
|
.importzp copy_src
|
|
.importzp copy_dest
|
|
.export keep_alive_counter
|
|
pptr=copy_src
|
|
IERROR=$300
|
|
CINV=$314
|
|
ILOAD=$330
|
|
ISAVE=$332
|
|
|
|
FNLEN = $B7
|
|
FNADDR = $BB
|
|
CHRGOT=$79
|
|
TXTPTR=$7A
|
|
MEMSIZ = $37 ;highest address used by BASIC
|
|
.import __CODE_LOAD__
|
|
.import __CODE_RUN__
|
|
.import __CODE_SIZE__
|
|
|
|
.import __RODATA_LOAD__
|
|
.import __RODATA_RUN__
|
|
.import __RODATA_SIZE__
|
|
|
|
.import __DATA_LOAD__
|
|
.import __DATA_RUN__
|
|
.import __DATA_SIZE__
|
|
|
|
.import __IP65_DEFAULTS_LOAD__
|
|
.import __IP65_DEFAULTS_RUN__
|
|
.import __IP65_DEFAULTS_SIZE__
|
|
|
|
.import __CODESTUB_LOAD__
|
|
.import __CODESTUB_RUN__
|
|
.import __CODESTUB_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 10 ;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 #$9000
|
|
stax $37; MEMSIZ
|
|
jsr $A65E ;do a CLR
|
|
|
|
;relocate everything
|
|
ldax #__CODE_LOAD__
|
|
stax copy_src
|
|
ldax #__CODE_RUN__
|
|
stax copy_dest
|
|
ldax #__CODE_SIZE__
|
|
jsr __copymem
|
|
|
|
|
|
ldx ILOAD+1
|
|
cpx #>load_handler
|
|
bne @not_installed
|
|
ldax #@already_installed_msg
|
|
jsr __print
|
|
rts
|
|
|
|
@installed_msg: .byte "V1541 INSTALLED",0
|
|
@already_installed_msg: .byte "V1541 ALREADY INSTALLED",0
|
|
@not_installed:
|
|
|
|
|
|
ldax #__DATA_LOAD__
|
|
stax copy_src
|
|
ldax #__DATA_RUN__
|
|
stax copy_dest
|
|
ldax #__DATA_SIZE__
|
|
jsr __copymem
|
|
|
|
ldax #__CODESTUB_LOAD__
|
|
stax copy_src
|
|
ldax #__CODESTUB_RUN__
|
|
stax copy_dest
|
|
ldax #__CODESTUB_SIZE__
|
|
jsr __copymem
|
|
|
|
ldax #__RODATA_LOAD__
|
|
stax copy_src
|
|
ldax #__RODATA_RUN__
|
|
stax copy_dest
|
|
ldax #__RODATA_SIZE__
|
|
jsr __copymem
|
|
|
|
ldax #__IP65_DEFAULTS_LOAD__
|
|
stax copy_src
|
|
ldax #__IP65_DEFAULTS_RUN__
|
|
stax copy_dest
|
|
ldax #__IP65_DEFAULTS_SIZE__
|
|
jsr __copymem
|
|
|
|
|
|
|
|
|
|
jsr swap_basic_out
|
|
|
|
jsr ip65_init
|
|
bcc @init_ok
|
|
ldax #@no_nic
|
|
jsr print
|
|
@fail_and_exit:
|
|
ldax #@not_installed_msg
|
|
jsr print
|
|
jmp @done
|
|
@no_nic: .byte "NO RR-NET FOUND - ",0
|
|
@not_installed_msg: .byte "V1541 NOT INSTALLED.",0
|
|
@init_ok:
|
|
ldax #@dhcp_init_msg
|
|
jsr print
|
|
jsr dhcp_init
|
|
bcc @dhcp_worked
|
|
@failed:
|
|
ldax #@fail_msg
|
|
jsr print
|
|
jmp @fail_and_exit
|
|
@dhcp_init_msg: .byte "DHCP INITIALISATION"
|
|
@elipses: .byte "...",0
|
|
@ok_msg: .byte "OK",13,0
|
|
@fail_msg: .byte "FAILED",13,0
|
|
@dhcp_worked:
|
|
ldax #@ok_msg
|
|
jsr print
|
|
|
|
ldax #@resolve_servername_msg
|
|
jsr print
|
|
ldax #@elipses
|
|
jsr print
|
|
ldax #@servername
|
|
jsr dns_set_hostname
|
|
jsr dns_resolve
|
|
bcc @dns_worked
|
|
jmp @failed
|
|
@resolve_servername_msg: .byte "RESOLVING "
|
|
@servername: .byte SERVERNAME,0
|
|
@dns_worked:
|
|
ldax #@ok_msg
|
|
jsr print
|
|
ldx #3
|
|
@copy_server_ip_loop:
|
|
lda dns_ip,x
|
|
sta tcp_connect_ip,x
|
|
dex
|
|
bpl @copy_server_ip_loop
|
|
|
|
ldax #@connecting_msg
|
|
jsr print
|
|
ldax #@servername
|
|
jsr print
|
|
ldax #@elipses
|
|
jsr print
|
|
ldax #csip_callback
|
|
stax tcp_callback
|
|
ldax #SERVER_PORT
|
|
jsr tcp_connect
|
|
bcc @connect_worked
|
|
jmp @failed
|
|
@connecting_msg: .byte "CONNECTING TO ",0
|
|
|
|
@connect_worked:
|
|
ldax #@ok_msg
|
|
jsr print
|
|
;IP stack OK, now set vectors
|
|
|
|
ldax CINV
|
|
stax old_irq_vector
|
|
|
|
ldax ILOAD
|
|
stax old_load_vector
|
|
ldax #load_handler
|
|
stax ILOAD
|
|
ldax #@installed_msg
|
|
jsr print
|
|
|
|
ldax #irq_handler
|
|
sei
|
|
stax CINV
|
|
|
|
@done:
|
|
jsr swap_basic_in
|
|
lda #0
|
|
sta $dc08 ;make sure TOD clock is started
|
|
cli
|
|
|
|
rts
|
|
|
|
__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
|
|
|
|
end: .byte 0
|
|
|
|
__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
|
|
|
|
|
|
.code
|
|
|
|
load_dev_2:
|
|
ldy #$00
|
|
sty receive_type ;0 = display to screen, 1 = load to memory
|
|
sty buffer_length
|
|
sty buffer_length+1
|
|
lda (FNADDR),y
|
|
cmp #'!'
|
|
beq @do_disks
|
|
cmp #'>'
|
|
beq @do_command
|
|
cmp #'#'
|
|
beq @do_insert
|
|
cmp #'='
|
|
beq @do_find
|
|
cmp #'/'
|
|
bne @not_cf
|
|
lda FNLEN
|
|
cmp #1
|
|
bne @do_cf
|
|
ldax #cmd_cf_root
|
|
jmp @send_string_receive_response
|
|
@not_cf:
|
|
cmp #'%'
|
|
beq @do_name
|
|
cmp #'$'
|
|
beq @do_cat
|
|
inc receive_type
|
|
ldax #cmd_load
|
|
jmp @copy_prefix
|
|
|
|
@done:
|
|
|
|
clc
|
|
jmp swap_basic_in
|
|
|
|
@do_command:
|
|
ldy FNLEN
|
|
@copy_cmd:
|
|
lda (FNADDR),y
|
|
sta cmd_buffer-1,y
|
|
dey
|
|
bne @copy_cmd
|
|
|
|
ldy FNLEN
|
|
lda #$0D
|
|
sta cmd_buffer-1,y
|
|
lda #0
|
|
sta cmd_buffer,y
|
|
@send_command_buffer:
|
|
ldax #cmd_buffer
|
|
jmp @send_string_receive_response
|
|
|
|
@do_name:
|
|
ldax #cmd_name
|
|
jmp @send_string_receive_response
|
|
|
|
@do_find:
|
|
ldax #cmd_find
|
|
jmp @copy_prefix
|
|
|
|
@do_cat:
|
|
ldax #cmd_cat
|
|
jmp @send_string_receive_response
|
|
|
|
|
|
@do_disks:
|
|
ldax #cmd_dsks
|
|
@send_string_receive_response:
|
|
jsr tcp_send_string
|
|
bcs @error
|
|
lda receive_type
|
|
bne @load_file
|
|
jsr show_list
|
|
jmp @done
|
|
@load_file:
|
|
jsr receive_file
|
|
jmp @done
|
|
|
|
@do_cf:
|
|
ldax #cmd_cf
|
|
jmp @copy_prefix
|
|
|
|
|
|
@do_insert:
|
|
ldax #cmd_insert
|
|
@copy_prefix:
|
|
stax copy_src
|
|
ldy #0
|
|
@copy_prefix_loop:
|
|
lda (copy_src),y
|
|
beq @end_copy_prefix
|
|
sta cmd_buffer,y
|
|
iny
|
|
bne @copy_prefix_loop
|
|
@end_copy_prefix:
|
|
tya
|
|
tax
|
|
ldy #1
|
|
lda receive_type
|
|
beq :+
|
|
dey ;if this is a LOAD command, don't skip the first byte
|
|
:
|
|
lda (FNADDR),y
|
|
sta cmd_buffer,x
|
|
iny
|
|
inx
|
|
cpy FNLEN
|
|
|
|
bne :-
|
|
|
|
lda #$0D
|
|
sta cmd_buffer,x
|
|
lda #0
|
|
sta cmd_buffer+1,x
|
|
jmp @send_command_buffer
|
|
|
|
@error:
|
|
ldax #SERVER_PORT
|
|
jsr tcp_connect
|
|
|
|
ldax #transmission_error
|
|
jsr print
|
|
|
|
jmp @done
|
|
|
|
|
|
show_list:
|
|
|
|
@loop:
|
|
lda $91 ; look for STOP key
|
|
cmp #$7F
|
|
beq @done
|
|
lda #2 ;wait for max 2 seconds
|
|
jsr getc
|
|
bcc @got_data
|
|
rts
|
|
@got_data:
|
|
|
|
cmp #$03 ;ETX byte (indicating end of page)?
|
|
beq @get_user_input
|
|
cmp #$04 ;EOT byte (indicating end of list)?
|
|
beq @done
|
|
jsr print_a ;got a byte - output it
|
|
jmp @loop ;continue getting characters
|
|
|
|
;End of page, so ask for user input
|
|
@get_user_input:
|
|
|
|
jsr get_key
|
|
|
|
cmp #'S'
|
|
beq @user_exit
|
|
|
|
cmp #$0D
|
|
bne @get_user_input
|
|
ldax #continue_cmd
|
|
|
|
jsr tcp_send_string
|
|
jmp @loop
|
|
|
|
;User wishes to stop - send S to server and quit
|
|
@user_exit:
|
|
ldax #stop_cmd
|
|
jsr tcp_send_string
|
|
|
|
@done:
|
|
|
|
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
|
|
|
|
|
|
csip_callback:
|
|
lda tcp_inbound_data_length+1
|
|
cmp #$ff
|
|
bne @not_eof
|
|
rts
|
|
@not_eof:
|
|
|
|
ldax tcp_inbound_data_ptr
|
|
stax copy_src
|
|
ldax #csip_stream_buffer
|
|
stax copy_dest
|
|
stax next_char_ptr
|
|
|
|
ldax tcp_inbound_data_length
|
|
stax buffer_length
|
|
jsr copymem
|
|
rts
|
|
|
|
getc:
|
|
sta getc_timeout_seconds
|
|
|
|
clc
|
|
lda $dc09 ;time of day clock: seconds (in BCD)
|
|
sed
|
|
adc getc_timeout_seconds
|
|
cmp #$60
|
|
bcc @timeout_set
|
|
sec
|
|
sbc #$60
|
|
@timeout_set:
|
|
cld
|
|
sta getc_timeout_end
|
|
|
|
@poll_loop:
|
|
jsr next_char
|
|
bcs @no_char
|
|
rts ;done!
|
|
@no_char:
|
|
jsr check_for_abort_key
|
|
bcc @no_abort
|
|
lda #KPR_ERROR_ABORTED_BY_USER
|
|
sta ip65_error
|
|
inc user_abort
|
|
rts
|
|
@no_abort:
|
|
jsr ip65_process
|
|
lda $dc09 ;time of day clock: seconds
|
|
cmp getc_timeout_end
|
|
bne @poll_loop
|
|
lda #00
|
|
sec
|
|
rts
|
|
|
|
next_char:
|
|
lda buffer_length
|
|
bne @not_eof
|
|
lda buffer_length+1
|
|
bne @not_eof
|
|
sec
|
|
rts
|
|
@not_eof:
|
|
next_char_ptr=*+1
|
|
lda $ffff
|
|
pha
|
|
inc next_char_ptr
|
|
bne :+
|
|
inc next_char_ptr+1
|
|
:
|
|
sec
|
|
lda buffer_length
|
|
sbc #1
|
|
sta buffer_length
|
|
lda buffer_length+1
|
|
sbc #0
|
|
sta buffer_length+1
|
|
pla
|
|
clc
|
|
|
|
rts
|
|
|
|
tcp_irq_handler:
|
|
|
|
inc keep_alive_counter
|
|
lda keep_alive_counter
|
|
bne @skip
|
|
jsr tcp_send_keep_alive
|
|
@skip:
|
|
jsr ip65_process
|
|
@done:
|
|
|
|
rts
|
|
|
|
receive_file:
|
|
lda #0
|
|
sta byte_count
|
|
@loop:
|
|
lda $91 ; look for STOP key
|
|
cmp #$7F
|
|
beq @done
|
|
lda #2 ;wait for max 2 seconds
|
|
jsr getc
|
|
bcc @got_data
|
|
@done:
|
|
rts
|
|
@got_data:
|
|
ldy byte_count
|
|
sta file_length,y
|
|
inc byte_count
|
|
lda byte_count
|
|
cmp #4
|
|
bne @loop
|
|
;is the first 4 bytes "500 "
|
|
;
|
|
lda file_length+1
|
|
cmp #'0' ;if 2nd char was '0' this might be an ASCII error message
|
|
bne @real_file_transmission
|
|
lda file_location
|
|
cmp #$01
|
|
beq @real_file_transmission
|
|
;this was probably an ASCII error message
|
|
|
|
lda #0
|
|
sta byte_count
|
|
:
|
|
ldy byte_count
|
|
lda file_length,y
|
|
jsr print_a
|
|
inc byte_count
|
|
lda byte_count
|
|
cmp #4
|
|
bne :-
|
|
jmp show_list
|
|
@real_file_transmission:
|
|
ldax file_location
|
|
stax copy_dest
|
|
|
|
lda file_length
|
|
sec
|
|
sbc #2
|
|
sta file_length
|
|
|
|
lda file_length+1
|
|
sbc #0
|
|
sta file_length+1
|
|
|
|
@rx_loop:
|
|
lda file_length+1
|
|
bne @not_done
|
|
lda file_length
|
|
bne @not_done
|
|
;file now fully in RAM, time for housekeeping
|
|
sta $297 ;RS-232 status = 0 (no error)
|
|
sta $90 ;status = 0 (no error)
|
|
ldy copy_dest+1 ;high byte of end of loaded program
|
|
ldx copy_dest ;lo byte of end of loaded program
|
|
inx
|
|
bne :+
|
|
iny ;if X rolled over, bump y
|
|
:
|
|
rts ;done!
|
|
|
|
@not_done:
|
|
lda #2 ;wait for max 2 seconds
|
|
jsr getc
|
|
bcs @rx_error
|
|
ldy #0
|
|
sta (copy_dest),y
|
|
inc copy_dest
|
|
bne :+
|
|
inc copy_dest+1
|
|
:
|
|
lda file_length
|
|
bne :+
|
|
dec file_length+1
|
|
lda #'.'
|
|
jsr print_a
|
|
:
|
|
dec file_length
|
|
jmp @rx_loop
|
|
|
|
@rx_error:
|
|
ldax #receive_error
|
|
jmp print
|
|
|
|
.segment "CODESTUB"
|
|
|
|
swap_basic_out:
|
|
lda $01
|
|
sta underneath_basic
|
|
and #$FE
|
|
sta $01
|
|
rts
|
|
|
|
swap_basic_in:
|
|
lda $01
|
|
ora #$01
|
|
sta $01
|
|
lda #$0
|
|
sta underneath_basic
|
|
rts
|
|
|
|
underneath_basic: .res 1
|
|
|
|
load_handler:
|
|
ldx $BA ; Current Device Number
|
|
cpx #$02
|
|
beq :+
|
|
.byte $4c ;jmp
|
|
old_load_vector:
|
|
.word $ffff
|
|
:
|
|
jsr swap_basic_out
|
|
jmp load_dev_2
|
|
|
|
irq_handler:
|
|
|
|
lda underneath_basic
|
|
bne @done
|
|
jsr swap_basic_out
|
|
jsr tcp_irq_handler
|
|
jsr swap_basic_in
|
|
@done:
|
|
.byte $4c ;jmp
|
|
old_irq_vector:
|
|
.word $ffff
|
|
|
|
|
|
.data
|
|
cmd_dsks: .byte "DISKS 22",$0d,$0
|
|
cmd_insert: .byte "INSERT ",0
|
|
cmd_cat: .byte "$",$0d,$00
|
|
cmd_find: .byte "FIND ",$00
|
|
cmd_name: .byte "NAME",$0d,$00
|
|
cmd_cf: .byte "CF ",0
|
|
cmd_load: .byte "LOAD ",0
|
|
cmd_cf_root: .byte "CF /",$0d,0
|
|
|
|
transmission_error: .byte "TRANSMIT ERROR",13,0
|
|
receive_error: .byte "RECEIVE ERROR",13,0
|
|
|
|
.segment "TCP_VARS"
|
|
csip_stream_buffer: .res 1500
|
|
cmd_buffer: .res 100
|
|
.bss
|
|
|
|
user_abort: .res 1
|
|
getc_timeout_end: .res 1
|
|
getc_timeout_seconds: .res 1
|
|
buffer_length: .res 2
|
|
keep_alive_counter: .res 1
|
|
file_length: .res 2
|
|
file_location: .res 2
|
|
rx_length: .res 2
|
|
receive_type: .res 1
|
|
byte_count: .res 1
|
|
.data
|
|
continue_cmd: .byte $0D,0
|
|
stop_cmd: .byte "S",0
|
|
|
|
|
|
;-- LICENSE FOR v1541.s --
|
|
; The contents of this file are subject to the Mozilla Public License
|
|
; Version 1.1 (the "License"); you may not use this file except in
|
|
; compliance with the License. You may obtain a copy of the License at
|
|
; http://www.mozilla.org/MPL/
|
|
;
|
|
; Software distributed under the License is distributed on an "AS IS"
|
|
; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
|
; License for the specific language governing rights and limitations
|
|
; under the License.
|
|
;
|
|
; The Original Code is ip65.
|
|
;
|
|
; The Initial Developer of the Original Code is Jonno Downes,
|
|
; jonno@jamtronix.com.
|
|
; Portions created by the Initial Developer are Copyright (C) 2010
|
|
; Jonno Downes. All Rights Reserved.
|
|
; -- LICENSE END --
|