; ############# ; ; This will boot a C64 with an RR-NET compatible cs8900a from the network ; requires ; 1) a DHCP server, and ; 2) a TFTP server that responds to requests on the broadcast address (255.255.255.255) and that will serve a file called 'BOOTC64.PRG'. ; ; jonno@jamtronix.com - January 2009 ; .include "../inc/common.i" .include "../inc/commonprint.i" .include "../inc/c64keycodes.i" .include "../inc/menu.i" .import ip65_init .import dhcp_init .import tftp_ip .importzp tftp_filename .import tftp_load_address .import tftp_download .import cls .import beep .import exit_to_basic .import timer_vbl_handler .import get_key_ip65 .import cfg_ip .import cfg_netmask .import cfg_gateway .import cfg_dns .import cfg_tftp_server .import cfg_get_configuration_ptr .import copymem .importzp copy_src .importzp copy_dest .import get_filtered_input .import __DATA_LOAD__ .import __DATA_RUN__ .import __DATA_SIZE__ .import __SELF_MODIFIED_CODE_LOAD__ .import __SELF_MODIFIED_CODE_RUN__ .import __SELF_MODIFIED_CODE_SIZE__ directory_buffer = $6020 .bss tmp_load_address: .res 2 .data exit_cart: lda #$02 sta $de00 ;turns off RR cartridge by modifying GROUND and EXROM call_downloaded_prg: jsr $0000 ;overwritten when we load a file jmp init get_value_of_axy: ;some more self-modifying code lda $ffff,y rts .segment "CARTRIDGE_HEADER" .word init ;cold start vector .word $FE47 ;warm start vector .byte $C3,$C2,$CD,$38,$30 ; "CBM80" .code init: ;first let the kernal do a normal startup sei jsr $fda3 ;initialize CIA I/O jsr $fd50 ;RAM test, set pointers jsr $fd15 ;set vectors for KERNAL jsr $ff5B ;init. VIC cli ;KERNAL init. finished ;we need to set up BASIC as well jsr $e453 ;set BASIC vectors jsr $e3bf ;initialize zero page ;set some funky colours LDA #$05 ;green STA $D020 ;border LDA #$00 ;black STA $D021 ;background lda #$05 ;petscii for white text jsr print_a ;relocate our r/w data ldax #__DATA_LOAD__ stax copy_src ldax #__DATA_RUN__ stax copy_dest ldax #__DATA_SIZE__ jsr copymem ldax #netboot_msg jsr print ldax #init_msg+1 jsr print jsr ip65_init bcs @init_failed 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 cartridge default values) bcc init_ok @init_failed: print_failed jsr print_errorcode jsr wait_for_keypress jmp exit_to_basic init_ok: ldx #$03 : lda cfg_tftp_server,x sta tftp_ip,x dex bpl :- jsr print_cr jsr print_ip_config tftp_boot: ldax #tftp_dir_filemask jsr get_tftp_directory_listing bcs return_to_main @boot_filename_set: ;AX now points to filename jsr download bcc file_downloaded_ok tftp_boot_failed: jsr wait_for_keypress return_to_main: jmp tftp_boot file_downloaded_ok: ldax tftp_load_address boot_into_file: stax tmp_load_address ;use the param buffer as a temp holding place for the load address ;get ready to bank out jsr $ffe7 ; make sure all files have been closed. ;check whether the file we just downloaded was a BASIC prg lda tmp_load_address cmp #01 bne @not_a_basic_file lda tmp_load_address+1 cmp #$08 bne @not_a_basic_file jsr $e453 ;set BASIC vectors jsr $e3bf ;initialize BASIC jsr $a86e jsr $a533 ; re-bind BASIC lines ldx $22 ;load end-of-BASIC pointer (lo byte) ldy $23 ;load end-of-BASIC pointer (hi byte) stx $2d ;save end-of-BASIC pointer (lo byte) sty $2e ;save end-of-BASIC pointer (hi byte) jsr $a659 ; CLR (reset variables) ldax #$a7ae ; jump to BASIC interpreter loop jmp exit_cart_via_ax @not_a_basic_file: ldax tmp_load_address exit_cart_via_ax: sta call_downloaded_prg+1 stx call_downloaded_prg+2 jmp exit_cart get_tftp_directory_listing: stax tftp_filename ldax #directory_buffer stax tftp_load_address ldax #getting_dir_listing_msg jsr print jsr tftp_download bcs @dir_failed lda directory_buffer ;get the first byte that was downloaded bne :+ jmp @no_files_on_server : ;switch to lower case charset lda #23 sta $d018 @loop_till_filename_entered: ldax #directory_buffer jsr select_option_from_menu bcs @loop_till_filename_entered @tftp_filename_set: stax copy_dest stax get_value_of_axy+1 ldy #0 jsr get_value_of_axy ;A now == first char in string we just downloaded cmp #'$' bne @not_directory_name ;it's a directory name, so we need to append the file mask to end of it ;this will fail if the file path is more than 255 characters long @look_for_trailing_zero: iny inc copy_dest bne :+ inc copy_dest+1 : jsr get_value_of_axy ;A now == next char in string we just downloaded bne @look_for_trailing_zero ; got trailing zero ldax #tftp_dir_filemask+1 ;skip the leading '$' stax copy_src ldax #$07 jsr copymem ldax get_value_of_axy+1 jmp get_tftp_directory_listing @not_directory_name: ldax get_value_of_axy+1 clc rts @dir_failed: ldax #dir_listing_fail_msg jsr print jsr print_errorcode jsr print_cr ldax #tftp_file jmp @tftp_filename_set @no_files_on_server: ldax #no_files jsr print jmp tftp_boot_failed bad_boot: jsr wait_for_keypress jmp $fe66 ;do a wam start download: ;AX should point at filename to download stax tftp_filename ldax #$0000 ;load address will be first 2 bytes of file we download (LO/HI order) stax tftp_load_address ldax #downloading_msg jsr print ldax tftp_filename jsr print jsr print_cr jsr tftp_download bcc :+ ldax #tftp_download_fail_msg jsr print jsr print_errorcode sec rts : ldax #tftp_download_ok_msg jsr print clc rts wait_for_keypress: ldax #press_a_key_to_continue jsr print @loop: jsr $ffe4 beq @loop rts get_key: @loop: jsr $ffe4 beq @loop rts .rodata netboot_msg: .byte 13,"NETBOOT - V" .include "../inc/version.i" .byte 13,0 downloading_msg: .byte "DOWN" loading_msg: .asciiz "LOADING " getting_dir_listing_msg: .byte "FETCHING DIRECTORY",13,0 dir_listing_fail_msg: .byte "DIR FAILED",13,0 tftp_download_fail_msg: .byte "DOWNLOAD FAILED", 13, 0 tftp_download_ok_msg: .byte "DOWN" load_ok_msg: .byte "LOAD OK", 13, 0 current: .byte "CURRENT ",0 new: .byte"NEW ",0 tftp_dir_filemask: .asciiz "$/*.prg" tftp_file: .asciiz "BOOTC64.PRG" no_files: .byte "NO FILES",13,0