; ; kernal_os.asm ; sample C64 OS skeleton that keeps the KERNAL ROM visible ; ; build: ; ca65 kernal_os.asm -o kernal_os.o ; ld65 -C kernal_os.cfg kernal_os.o -o kernal_os.prg ; ; run: ; LOAD "KERNAL_OS.PRG",8 ; RUN ; .setcpu "6502" ; ------------------------------------------------------------ ; KERNAL routines ; ------------------------------------------------------------ CINT = $FF81 IOINIT = $FF84 RESTOR = $FF8A CHROUT = $FFD2 GETIN = $FFE4 STOPKEY = $FFE1 SCREEN = $FFED READST = $FFB7 SETLFS = $FFBA SETNAM = $FFBD OPEN = $FFC0 CLOSE = $FFC3 CHKIN = $FFC6 CHKOUT = $FFC9 CLRCH = $FFCC BASIN = $FFCF CLALL = $FFE7 ; ------------------------------------------------------------ ; system locations ; ------------------------------------------------------------ CPU_PORT = $0001 PTR1_LO = $FB PTR1_HI = $FC ; ------------------------------------------------------------ ; memory layout for this sample OS ; ------------------------------------------------------------ OS_LOAD = $0801 WORKSPACE = $A000 FILE_BUFFER = $A100 FILE_BUFFER_MAX = 224 INPUT_MAX = 64 DISK_DEV = 8 LFN_DIR = 2 LFN_CMD = 15 SYS_ENTRY = 2061 ; ------------------------------------------------------------ ; PETSCII constants ; ------------------------------------------------------------ CR = $0D CLR_HOME = $93 .segment "LOADADDR" .word OS_LOAD .segment "BASIC" .word basic_end .word 10 .byte $9E .byte "2061" .byte 0 basic_end: .word 0 .segment "CODE" start: jsr IOINIT jsr RESTOR jsr CINT jsr reset_file_state jsr set_os_memory jsr init_workspace jsr print_banner jmp main_loop main_loop: jsr print_prompt jsr read_line lda exit_requested beq parse_shell_command jmp exit_to_basic parse_shell_command: jsr parse_command lda exit_requested beq continue_shell jmp exit_to_basic continue_shell: jmp main_loop do_mem: lda #msg_mode jsr print_string lda CPU_PORT jsr print_hex_byte lda #msg_workspace jsr print_string lda WORKSPACE jsr print_hex_byte lda #msg_layout jsr print_string rts do_inc: inc workspace_counter lda workspace_counter sta WORKSPACE lda #msg_written jsr print_string lda WORKSPACE jsr print_hex_byte lda #CR jsr CHROUT rts do_dump: lda #msg_dump jsr print_string ldx #0 dump_loop: lda WORKSPACE,x jsr print_hex_byte lda #' ' jsr CHROUT inx cpx #16 bne dump_loop lda #CR jsr CHROUT rts do_zero: ldx #0 zero_loop: lda #0 sta WORKSPACE,x inx cpx #16 bne zero_loop lda #0 sta workspace_counter lda #msg_zeroed jsr print_string rts do_sign: jsr write_signature lda #msg_signed jsr print_string rts do_cls: lda #CLR_HOME jsr CHROUT rts do_help: lda #msg_help jsr print_string rts do_about: lda #msg_about jsr print_string rts do_screen: lda #msg_screen jsr print_string jsr SCREEN txa jsr print_decimal_byte lda #'X' jsr CHROUT tya jsr print_decimal_byte lda #CR jsr CHROUT rts do_dir: lda #0 sta dir_line_count jsr build_dir_spec jsr reset_file_state lda #LFN_DIR sta active_lfn ldx current_device ldy #0 jsr SETLFS lda filename_len ldx #filename_spec jsr SETNAM jsr OPEN bcc dir_channel_input jmp disk_open_error dir_channel_input: ldx #LFN_DIR jsr CHKIN bcc dir_next_line jmp disk_input_error dir_next_line: lda #0 sta line_had_name sta quote_state jsr BASIN sta dir_link_lo jsr BASIN sta dir_link_hi lda dir_link_lo ora dir_link_hi beq dir_done jsr BASIN jsr BASIN lda dir_line_count beq dir_skip_line dir_line_loop: jsr BASIN beq dir_line_end sta temp_char cmp #'"' beq dir_toggle_quote lda quote_state beq dir_line_loop lda line_had_name bne dir_print_char lda #1 sta line_had_name dir_print_char: lda temp_char jsr CHROUT jmp dir_line_loop dir_toggle_quote: lda quote_state eor #1 sta quote_state jmp dir_line_loop dir_skip_line: jsr BASIN beq dir_line_end jmp dir_skip_line dir_line_end: inc dir_line_count lda line_had_name beq dir_next_line lda #CR jsr CHROUT jmp dir_next_line dir_done: jsr close_active_file rts do_status: lda #msg_status jsr print_string jsr print_current_target lda #CR jsr CHROUT jsr reset_file_state lda #LFN_CMD sta active_lfn ldx current_device ldy #15 jsr SETLFS lda #0 ldx #0 ldy #0 jsr SETNAM jsr OPEN bcc status_channel_input jmp disk_open_error status_channel_input: ldx #LFN_CMD jsr CHKIN bcc status_loop jmp disk_input_error status_loop: jsr BASIN jsr CHROUT jsr READST and #$40 beq status_loop lda #CR jsr CHROUT jsr close_active_file rts do_init: lda #msg_init jsr print_string jsr print_current_target lda #CR jsr CHROUT jsr reset_file_state lda #LFN_CMD sta active_lfn ldx current_device ldy #15 jsr SETLFS lda #1 ldx #fname_init jsr SETNAM jsr OPEN bcc init_done jmp disk_open_error init_done: jsr close_active_file jmp do_status do_delete: jsr find_argument_start bcs delete_missing_name jsr build_scratch_command bcs delete_missing_name lda #msg_delete jsr print_string jsr print_current_target lda #CR jsr CHROUT jsr reset_file_state lda #LFN_CMD sta active_lfn ldx current_device ldy #15 jsr SETLFS lda scratch_len ldx #scratch_command jsr SETNAM jsr OPEN bcc delete_done jmp disk_open_error delete_done: jsr close_active_file jmp do_status delete_missing_name: lda #msg_delete_usage jsr print_string rts do_touch: jsr find_argument_start bcs touch_missing_name jsr build_write_filename bcs touch_missing_name lda #msg_touch jsr print_string jsr print_current_target lda #CR jsr CHROUT jsr reset_file_state lda #LFN_DIR sta active_lfn ldx current_device ldy #2 jsr SETLFS lda filename_len ldx #filename_spec jsr SETNAM jsr OPEN bcc touch_done jmp disk_open_error touch_done: jsr close_active_file jmp do_status touch_missing_name: lda #msg_touch_usage jsr print_string rts do_echo: jsr find_argument_start bcs echo_missing_text jsr copy_echo_to_buffer bcs echo_missing_text lda file_buffer_len beq echo_missing_text ldy #0 echo_print_loop: cpy file_buffer_len beq echo_print_done lda FILE_BUFFER,y jsr CHROUT iny bne echo_print_loop echo_print_done: lda #CR jsr CHROUT lda pipe_found beq echo_done jsr rewrite_input_after_pipe lda input_buffer beq echo_done jmp parse_command echo_done: rts echo_missing_text: lda #msg_echo_usage jsr print_string rts do_type: jsr find_argument_start bcs type_missing_name jsr build_read_filename bcs type_missing_name jsr reset_file_state lda #LFN_DIR sta active_lfn ldx current_device ldy #2 jsr SETLFS lda filename_len ldx #filename_spec jsr SETNAM jsr OPEN bcc type_channel_input jmp disk_open_error type_channel_input: ldx #LFN_DIR jsr CHKIN bcc type_loop jmp disk_input_error type_loop: jsr BASIN jsr CHROUT jsr READST and #$40 beq type_loop lda #CR jsr CHROUT jsr close_active_file rts type_missing_name: lda #msg_type_usage jsr print_string rts do_load_file: jsr find_argument_start bcc load_have_arg jmp load_missing_name load_have_arg: jsr build_read_filename bcc load_name_ready jmp load_missing_name load_name_ready: jsr reset_file_state lda #LFN_DIR sta active_lfn ldx current_device ldy #2 jsr SETLFS lda filename_len ldx #filename_spec jsr SETNAM jsr OPEN bcc load_channel_input jmp disk_open_error load_channel_input: ldx #LFN_DIR jsr CHKIN bcc load_prepare jmp disk_input_error load_prepare: lda #0 sta file_buffer_len sta file_truncated ldx #0 load_loop: jsr BASIN sta temp_char ldy file_buffer_len cpy #FILE_BUFFER_MAX bcs load_set_truncated lda temp_char sta FILE_BUFFER,y inc file_buffer_len jmp load_check_eof load_set_truncated: lda #1 sta file_truncated load_check_eof: jsr READST and #$40 beq load_loop lda file_buffer_len tay cpy #FILE_BUFFER_MAX bcs load_report lda #0 sta FILE_BUFFER,y load_report: jsr close_active_file lda #msg_loaded jsr print_string lda file_buffer_len jsr print_decimal_byte lda #msg_bytes jsr print_string lda file_truncated beq load_done lda #msg_truncated jsr print_string load_done: rts load_missing_name: lda #msg_load_usage jsr print_string rts do_save_file: jsr find_argument_start bcs save_missing_name lda file_buffer_len bne save_have_data lda #msg_buffer_empty jsr print_string rts save_have_data: jsr build_write_filename bcs save_missing_name jsr reset_file_state lda #LFN_DIR sta active_lfn ldx current_device ldy #2 jsr SETLFS lda filename_len ldx #filename_spec jsr SETNAM jsr OPEN bcc save_channel_output jmp disk_open_error save_channel_output: ldx #LFN_DIR jsr CHKOUT bcc save_loop_prepare jmp disk_input_error save_loop_prepare: ldy #0 save_loop: cpy file_buffer_len beq save_done lda FILE_BUFFER,y jsr CHROUT iny bne save_loop save_done: jsr close_active_file lda #msg_saved jsr print_string lda file_buffer_len jsr print_decimal_byte lda #msg_bytes jsr print_string rts save_missing_name: lda #msg_save_usage jsr print_string rts do_device: jsr find_argument_start bcc device_parse_arg jmp show_current_target device_parse_arg: jsr parse_decimal_argument bcs device_usage lda parsed_number cmp #8 bcc device_usage cmp #16 bcs device_usage sta current_device lda #msg_device_set jsr print_string jsr print_current_target lda #CR jsr CHROUT rts device_usage: lda #msg_device_usage jsr print_string rts do_drive: jsr find_argument_start bcc drive_parse_arg jmp show_current_target drive_parse_arg: jsr parse_decimal_argument bcs drive_usage lda parsed_number cmp #2 bcs drive_usage sta current_drive lda #msg_drive_set jsr print_string jsr print_current_target lda #CR jsr CHROUT rts drive_usage: lda #msg_drive_usage jsr print_string rts do_hex: lda file_buffer_len bne hex_have_data lda #msg_buffer_empty jsr print_string rts hex_have_data: lda #msg_hex jsr print_string ldy #0 ldx #0 hex_loop: cpy file_buffer_len beq hex_done lda FILE_BUFFER,y jsr print_hex_byte lda #' ' jsr CHROUT iny inx cpx #8 bne hex_loop lda #CR jsr CHROUT ldx #0 jmp hex_loop hex_done: lda #CR jsr CHROUT rts do_run: lda file_buffer_len bne run_have_code lda #msg_buffer_empty jsr print_string rts run_have_code: lda #msg_run jsr print_string jsr FILE_BUFFER rts do_rename: jsr find_argument_start bcs rename_missing_args jsr find_second_argument bcs rename_missing_args jsr build_rename_command bcs rename_missing_args lda #msg_rename jsr print_string jsr print_current_target lda #CR jsr CHROUT jsr reset_file_state lda #LFN_CMD sta active_lfn ldx current_device ldy #15 jsr SETLFS lda scratch_len ldx #scratch_command jsr SETNAM jsr OPEN bcc rename_file_done jmp disk_open_error rename_file_done: jsr close_active_file jmp do_status rename_missing_args: lda #msg_rename_usage jsr print_string rts do_copy: jsr find_argument_start bcs copy_missing_args jsr find_second_argument bcs copy_missing_args jsr build_copy_command bcs copy_missing_args lda #msg_copy jsr print_string jsr print_current_target lda #CR jsr CHROUT jsr reset_file_state lda #LFN_CMD sta active_lfn ldx current_device ldy #15 jsr SETLFS lda scratch_len ldx #scratch_command jsr SETNAM jsr OPEN bcc copy_file_done jmp disk_open_error copy_file_done: jsr close_active_file jmp do_status copy_missing_args: lda #msg_copy_usage jsr print_string rts exit_to_basic: jsr restore_normal_memory rts request_exit: lda #1 sta exit_requested rts close_active_file: jsr CLRCH lda active_lfn jsr CLOSE lda #0 sta active_lfn rts reset_file_state: jsr CLRCH jsr CLALL lda #0 sta active_lfn rts disk_open_error: sta last_error jsr reset_file_state lda #msg_disk_open_error jsr print_string lda last_error jsr print_hex_byte lda #CR jsr CHROUT rts disk_input_error: sta last_error jsr reset_file_state lda #msg_disk_input_error jsr print_string lda last_error jsr print_hex_byte lda #CR jsr CHROUT rts parse_command: lda input_buffer bne check_help jmp command_empty check_help: lda #cmd_help jsr str_equals_input bcc check_mem jmp do_help check_mem: lda #cmd_mem jsr str_equals_input bcc check_inc jmp do_mem check_inc: lda #cmd_inc jsr str_equals_input bcc check_dump jmp do_inc check_dump: lda #cmd_dump jsr str_equals_input bcc check_zero jmp do_dump check_zero: lda #cmd_zero jsr str_equals_input bcc check_sign jmp do_zero check_sign: lda #cmd_sign jsr str_equals_input bcc check_cls jmp do_sign check_cls: lda #cmd_cls jsr str_equals_input bcc check_screen jmp do_cls check_screen: lda #cmd_screen jsr str_equals_input bcc check_about jmp do_screen check_about: lda #cmd_about jsr str_equals_input bcc check_dir jmp do_about check_dir: lda #cmd_dir jsr str_matches_command bcc check_status jmp do_dir check_status: lda #cmd_status jsr str_equals_input bcc check_init jmp do_status check_init: lda #cmd_init jsr str_equals_input bcc check_echo jmp do_init check_echo: lda #cmd_echo jsr str_matches_command bcc check_touch jmp do_echo check_touch: lda #cmd_touch jsr str_matches_command bcc check_type jmp do_touch check_type: lda #cmd_type jsr str_matches_command bcc check_load jmp do_type check_load: lda #cmd_load jsr str_matches_command bcc check_save jmp do_load_file check_save: lda #cmd_save jsr str_matches_command bcc check_device jmp do_save_file check_device: lda #cmd_device jsr str_matches_command bcc check_dev jmp do_device check_dev: lda #cmd_dev jsr str_matches_command bcc check_drive jmp do_device check_drive: lda #cmd_drive jsr str_matches_command bcc check_del jmp do_drive check_del: lda #cmd_del jsr str_matches_command bcc check_erase jmp do_delete check_erase: lda #cmd_erase jsr str_matches_command bcc check_hex jmp do_delete check_hex: lda #cmd_hex jsr str_equals_input bcc check_run jmp do_hex check_run: lda #cmd_run jsr str_equals_input bcc check_rename jmp do_run check_rename: lda #cmd_rename jsr str_matches_command bcc check_copy jmp do_rename check_copy: lda #cmd_copy jsr str_matches_command bcc check_exit jmp do_copy check_exit: lda #cmd_exit jsr str_matches_command bcc command_unknown jmp request_exit command_unknown: lda #msg_unknown jsr print_string rts command_empty: rts ; ------------------------------------------------------------ ; memory mode helpers ; ------------------------------------------------------------ set_os_memory: lda CPU_PORT and #$F8 ora #$06 sta CPU_PORT rts restore_normal_memory: lda CPU_PORT and #$F8 ora #$07 sta CPU_PORT rts ; ------------------------------------------------------------ ; write an initial signature into RAM hidden under BASIC ROM ; ------------------------------------------------------------ init_workspace: lda #0 sta WORKSPACE sta workspace_counter sta exit_requested sta dir_line_count sta quote_state sta line_had_name sta argument_index sta scratch_len sta filename_len sta parsed_number sta temp_digit sta temp_value sta current_drive sta file_buffer_len sta file_truncated sta pipe_found sta pipe_index sta argument2_index lda #DISK_DEV sta current_device jsr write_signature rts write_signature: ldx #0 copy_signature: lda msg_signature,x sta WORKSPACE + 1,x beq workspace_done inx bne copy_signature workspace_done: rts find_argument_start: ldx #0 arg_seek_end: lda input_buffer,x beq arg_missing cmp #' ' beq arg_skip_spaces inx bne arg_seek_end arg_skip_spaces: lda input_buffer,x beq arg_missing cmp #' ' bne arg_found inx bne arg_skip_spaces arg_found: stx argument_index clc rts arg_missing: sec rts find_second_argument: ldy argument_index sec_skip_first: lda input_buffer,y beq sec_arg_missing cmp #' ' beq sec_find_start iny bne sec_skip_first sec_find_start: lda input_buffer,y beq sec_arg_missing cmp #' ' bne sec_arg_found iny bne sec_find_start sec_arg_found: sty argument2_index clc rts sec_arg_missing: sec rts build_scratch_command: ldx #0 lda #'S' sta scratch_command,x inx lda current_drive clc adc #'0' sta scratch_command,x inx lda #':' sta scratch_command,x inx ldy argument_index copy_delete_name: lda input_buffer,y beq scratch_done sta scratch_command,x inx iny cpx #31 bcc copy_delete_name sec rts scratch_done: stx scratch_len lda #0 sta scratch_command,x clc rts build_dir_spec: lda #'$' sta filename_spec lda current_drive clc adc #'0' sta filename_spec + 1 lda #2 sta filename_len lda #0 sta filename_spec + 2 rts build_read_filename: jsr build_drive_filename_prefix bcs filename_build_error lda #',' jsr append_filename_char lda #'S' jsr append_filename_char lda #',' jsr append_filename_char lda #'R' jsr append_filename_char bcs filename_build_error jmp finish_filename_spec build_write_filename: jsr build_drive_filename_prefix bcs filename_build_error lda #',' jsr append_filename_char lda #'S' jsr append_filename_char lda #',' jsr append_filename_char lda #'W' jsr append_filename_char bcs filename_build_error jmp finish_filename_spec build_drive_filename_prefix: ldx #0 lda current_drive clc adc #'0' sta filename_spec,x inx lda #':' sta filename_spec,x inx ldy argument_index copy_filename_arg: lda input_buffer,y beq prefix_done sta filename_spec,x inx iny cpx #35 bcc copy_filename_arg sec rts prefix_done: stx filename_len clc rts append_filename_char: ldx filename_len cpx #39 bcs filename_build_error sta filename_spec,x inx stx filename_len clc rts finish_filename_spec: ldx filename_len lda #0 sta filename_spec,x clc rts filename_build_error: sec rts ; builds R{d}:{newname}={oldname} in scratch_command ; arg1=old (argument_index), arg2=new (argument2_index) build_rename_command: ldx #0 lda #'R' sta scratch_command,x inx lda current_drive clc adc #'0' sta scratch_command,x inx lda #':' sta scratch_command,x inx ldy argument2_index rename_copy_new_name: lda input_buffer,y beq rename_new_name_done cmp #' ' beq rename_new_name_done sta scratch_command,x inx iny cpx #20 bcc rename_copy_new_name sec rts rename_new_name_done: lda #'=' sta scratch_command,x inx ldy argument_index rename_copy_old_name: lda input_buffer,y beq rename_cmd_done cmp #' ' beq rename_cmd_done sta scratch_command,x inx iny cpx #31 bcc rename_copy_old_name sec rts rename_cmd_done: stx scratch_len lda #0 sta scratch_command,x clc rts ; builds C{d}:{dstname}={d}:{srcname} in scratch_command ; arg1=src (argument_index), arg2=dst (argument2_index) build_copy_command: ldx #0 lda #'C' sta scratch_command,x inx lda current_drive clc adc #'0' sta scratch_command,x inx lda #':' sta scratch_command,x inx ldy argument2_index copy_dst_name: lda input_buffer,y beq copy_dst_done cmp #' ' beq copy_dst_done sta scratch_command,x inx iny cpx #16 bcc copy_dst_name sec rts copy_dst_done: lda #'=' sta scratch_command,x inx lda current_drive clc adc #'0' sta scratch_command,x inx lda #':' sta scratch_command,x inx ldy argument_index copy_src_name: lda input_buffer,y beq copy_cmd_done cmp #' ' beq copy_cmd_done sta scratch_command,x inx iny cpx #31 bcc copy_src_name sec rts copy_cmd_done: stx scratch_len lda #0 sta scratch_command,x clc rts parse_decimal_argument: ldy argument_index lda #0 sta parsed_number parse_digit_loop: lda input_buffer,y beq parse_number_done cmp #'0' bcc parse_number_error cmp #'9' + 1 bcs parse_number_error sec sbc #'0' sta temp_digit lda parsed_number asl sta temp_value asl asl clc adc temp_value clc adc temp_digit sta parsed_number iny bne parse_digit_loop parse_number_done: clc rts parse_number_error: sec rts copy_echo_to_buffer: lda #0 sta pipe_found sta file_buffer_len ldy argument_index ldx #0 echo_copy_loop: lda input_buffer,y beq echo_copy_done cmp #'>' beq echo_pipe_here cpx #FILE_BUFFER_MAX bcs echo_copy_done sta FILE_BUFFER,x inx iny bne echo_copy_loop echo_pipe_here: lda #1 sta pipe_found sty pipe_index echo_copy_done: stx file_buffer_len trim_echo_spaces: cpx #0 beq echo_copy_finish dex lda FILE_BUFFER,x cmp #' ' bne restore_echo_len stx file_buffer_len jmp trim_echo_spaces restore_echo_len: inx stx file_buffer_len echo_copy_finish: ldy file_buffer_len lda #0 sta FILE_BUFFER,y clc rts rewrite_input_after_pipe: ldy pipe_index lda input_buffer,y cmp #'>' beq pipe_skip_marker rts pipe_skip_marker: iny pipe_skip_spaces: lda input_buffer,y beq clear_input_after_pipe cmp #' ' bne pipe_copy_command iny bne pipe_skip_spaces pipe_copy_command: ldx #0 pipe_copy_loop: lda input_buffer,y beq pipe_rewrite_done sta input_buffer,x inx iny cpx #INPUT_MAX bcc pipe_copy_loop pipe_rewrite_done: lda #0 sta input_buffer,x rts clear_input_after_pipe: lda #0 sta input_buffer rts ; ------------------------------------------------------------ ; utility routines ; ------------------------------------------------------------ print_prompt: lda #msg_prompt jmp print_string show_current_target: lda #msg_current_target jsr print_string jsr print_current_target lda #CR jsr CHROUT rts print_current_target: lda current_device jsr print_decimal_byte lda #'/' jsr CHROUT lda current_drive clc adc #'0' jsr CHROUT rts print_banner: lda #CLR_HOME jsr CHROUT lda #msg_banner jmp print_string print_string: sta PTR1_LO sty PTR1_HI print_loop: ldy #0 lda (PTR1_LO),y beq print_done jsr CHROUT inc PTR1_LO bne print_loop inc PTR1_HI jmp print_loop print_done: rts read_line: lda #0 sta input_len read_loop: jsr STOPKEY bne read_getin jmp request_exit read_getin: jsr GETIN beq read_loop cmp #CR beq read_done cmp #$14 beq read_delete ldx input_len cpx #INPUT_MAX bcs read_loop jsr normalize_petscii_letter sta input_buffer,x inc input_len jsr CHROUT jmp read_loop read_delete: lda input_len beq read_loop dec input_len lda #$14 jsr CHROUT jmp read_loop read_done: ldx input_len lda #0 sta input_buffer,x lda #CR jsr CHROUT rts str_equals_input: sta PTR1_LO sty PTR1_HI lda #0 sta compare_index compare_loop: ldx compare_index lda input_buffer,x sta temp_char ldy #0 lda (PTR1_LO),y beq compare_end cmp temp_char bne compare_no inc PTR1_LO bne compare_next inc PTR1_HI compare_next: inc compare_index jmp compare_loop compare_end: ldx compare_index lda input_buffer,x beq compare_yes compare_no: clc rts compare_yes: sec rts str_matches_command: sta PTR1_LO sty PTR1_HI lda #0 sta compare_index match_loop: ldx compare_index lda input_buffer,x sta temp_char ldy #0 lda (PTR1_LO),y beq match_end cmp temp_char bne match_no inc PTR1_LO bne match_next inc PTR1_HI match_next: inc compare_index jmp match_loop match_end: ldx compare_index lda input_buffer,x beq match_yes cmp #' ' beq match_yes match_no: clc rts match_yes: sec rts print_hex_byte: pha lsr lsr lsr lsr jsr print_hex_nibble pla and #$0F jsr print_hex_nibble rts print_hex_nibble: cmp #10 bcc print_hex_digit clc adc #'A' - 10 jsr CHROUT rts print_hex_digit: clc adc #'0' jsr CHROUT rts print_decimal_byte: ldx #'0' hundreds_loop: cmp #100 bcc tens_setup sec sbc #100 inx bne hundreds_loop tens_setup: stx dec_hundreds ldx #'0' tens_loop: cmp #10 bcc decimal_ready sec sbc #10 inx bne tens_loop decimal_ready: stx dec_tens clc adc #'0' sta dec_ones lda dec_hundreds cmp #'0' beq maybe_skip_hundreds jsr CHROUT lda dec_tens jsr CHROUT lda dec_ones jsr CHROUT rts maybe_skip_hundreds: lda dec_tens cmp #'0' beq print_last_digit jsr CHROUT lda dec_ones jsr CHROUT rts print_last_digit: lda dec_ones jsr CHROUT rts normalize_petscii_letter: cmp #'a' bcc maybe_shifted_letter cmp #'z' + 1 bcs maybe_shifted_letter sec sbc #$20 rts maybe_shifted_letter: cmp #$C1 bcc normalize_done cmp #$DB bcs normalize_done and #$7F normalize_done: rts .segment "RODATA" msg_banner: .byte "KERNAL OS SHELL", CR .byte "BASIC OFF KERNAL ON I/O ON", CR .byte "BOOT $0801 WORK $A000", CR .byte "HELP FOR CMDS", CR, CR .byte 0 msg_prompt: .byte "OS> ", 0 msg_unknown: .byte "UNKNOWN. HELP", CR, 0 msg_help: .byte CR .byte "HELP MEM INC DUMP ZERO SIGN", CR .byte "SCREEN DIR STATUS INIT CLS", CR .byte "ECHO TOUCH TYPE LOAD SAVE", CR .byte "HEX RUN RENAME COPY", CR .byte "DEVICE DEV DRIVE DEL ERASE", CR .byte "ABOUT EXIT", CR .byte CR .byte 0 msg_mode: .byte "CPU PORT $0001 = $", 0 msg_workspace: .byte CR, "WORK BYTE $A000 = $", 0 msg_layout: .byte CR .byte "$0001 LOW BITS %110", CR .byte "$080D START $A000-$BFFF RAM", CR .byte CR .byte 0 msg_written: .byte "WROTE $", 0 msg_dump: .byte "A000:", ' ', 0 msg_zeroed: .byte "ZEROED $A000-$A00F", CR, 0 msg_signed: .byte "REWROTE SIGNATURE AT $A001", CR, 0 msg_about: .byte CR .byte "BASIC LINE 10 SYS 2061 BOOTS THIS.", CR .byte "KERNAL STAYS MAPPED IN.", CR .byte "SHELL CODE STARTS AT $080D.", CR .byte "USE $A000-$BFFF AS WORK RAM.", CR .byte CR .byte 0 msg_screen: .byte "SCREEN SIZE: ", 0 msg_status: .byte CR, "STATUS OF TARGET ", 0 msg_init: .byte CR, "INITIALIZING TARGET ", 0 msg_delete: .byte CR, "SCRATCHING FILE ON TARGET ", 0 msg_delete_usage: .byte "USAGE: DEL filename OR ERASE filename", CR, 0 msg_touch: .byte CR, "CREATING EMPTY FILE ON TARGET ", 0 msg_touch_usage: .byte "USAGE: TOUCH filename", CR, 0 msg_echo_usage: .byte "USAGE: ECHO text OR ECHO text > SAVE file", CR, 0 msg_type_usage: .byte "USAGE: TYPE filename", CR, 0 msg_load_usage: .byte "USAGE: LOAD filename", CR, 0 msg_save_usage: .byte "USAGE: SAVE filename", CR, 0 msg_loaded: .byte "LOADED ", 0 msg_saved: .byte "SAVED ", 0 msg_bytes: .byte " BYTES", CR, 0 msg_truncated: .byte " (TRUNCATED TO BUFFER SIZE)", CR, 0 msg_buffer_empty: .byte "BUFFER EMPTY. USE LOAD FIRST.", CR, 0 msg_current_target: msg_device_set: .byte "TARGET ", 0 msg_device_usage: .byte "USAGE: DEVICE 8-15 OR DEV 8-15", CR, 0 msg_drive_set: .byte "TARGET ", 0 msg_drive_usage: .byte "USAGE: DRIVE 0 OR DRIVE 1", CR, 0 msg_disk_open_error: .byte "DISK OPEN ERROR $", 0 msg_disk_input_error: .byte "DISK INPUT ERROR $", 0 msg_signature: .byte "OSWORK", 0 fname_init: .byte "I0:" cmd_help: .byte "HELP", 0 cmd_mem: .byte "MEM", 0 cmd_inc: .byte "INC", 0 cmd_dump: .byte "DUMP", 0 cmd_zero: .byte "ZERO", 0 cmd_sign: .byte "SIGN", 0 cmd_cls: .byte "CLS", 0 cmd_screen: .byte "SCREEN", 0 cmd_about: .byte "ABOUT", 0 cmd_dir: .byte "DIR", 0 cmd_status: .byte "STATUS", 0 cmd_init: .byte "INIT", 0 cmd_echo: .byte "ECHO", 0 cmd_touch: .byte "TOUCH", 0 cmd_type: .byte "TYPE", 0 cmd_load: .byte "LOAD", 0 cmd_save: .byte "SAVE", 0 cmd_device: .byte "DEVICE", 0 cmd_dev: .byte "DEV", 0 cmd_drive: .byte "DRIVE", 0 cmd_del: .byte "DEL", 0 cmd_erase: .byte "ERASE", 0 cmd_exit: .byte "EXIT", 0 cmd_hex: .byte "HEX", 0 cmd_run: .byte "RUN", 0 cmd_rename: .byte "RENAME", 0 cmd_copy: .byte "COPY", 0 msg_hex: .byte "BUF HEX:", CR, 0 msg_run: .byte "RUNNING $A100", CR, 0 msg_rename: .byte CR, "RENAMING FILE ON TARGET ", 0 msg_rename_usage: .byte "USAGE: RENAME oldname newname", CR, 0 msg_copy: .byte CR, "COPYING FILE ON TARGET ", 0 msg_copy_usage: .byte "USAGE: COPY srcname dstname", CR, 0 .segment "BSS" workspace_counter: .res 1 exit_requested: .res 1 active_lfn: .res 1 last_error: .res 1 dir_link_lo: .res 1 dir_link_hi: .res 1 dir_line_count: .res 1 quote_state: .res 1 line_had_name: .res 1 argument_index: .res 1 argument2_index: .res 1 scratch_len: .res 1 scratch_command: .res 32 filename_len: .res 1 filename_spec: .res 40 parsed_number: .res 1 temp_digit: .res 1 temp_value: .res 1 current_device: .res 1 current_drive: .res 1 file_buffer_len: .res 1 file_truncated: .res 1 pipe_found: .res 1 pipe_index: .res 1 input_buffer: .res INPUT_MAX + 1 input_len: .res 1 compare_index: .res 1 temp_char: .res 1 dec_hundreds: .res 1 dec_tens: .res 1 dec_ones: .res 1