;; An example ROM and how to override a firmware function with our own function ;; ;; Firmware jumpblock entries are 3 bytes long. ;; ;; Patch the function with a FAR CALL which is: ;; RST 3 ;; defw address ;; ;; The address should be in main RAM, preferably in an area that your ROM has reserved. ;; The address has 3 bytes: ;; defw address_in_rom (e.g. &c000) ;; defb rom_number (e.g. &7) ;; ;; You can find the number of your ROM by calling KL CURR SELECTION when your start-up function ;; of your ROM has been called. ;; ;; calling the function then becomes: ;; call <firmware_function> -> far call -> your rom ;; ;; For a filesystem, we want to call our functions only if our filesystem is active, otherwise call ;; the previous functions ;; ;; AMSDOS uses a clever method when it patches the functions.. it looks at the return address ;; and uses that to go to the appropiate overridden function. ;; location for upper roms org &c000 ;; rom header defb 1 ;; type defb 1 ;; mark defb 0 ;; version defb 0 ;; modification defw name_table jp boot ;;----------------------------------------------------------------------------- ;; name table name_table: ;; this is the start-up function ;; use a space in the name to stop basic from calling it defb "NEW DO","S"+&80 defb 0 ;;------------------------------------------------------------------------------ boot_message: defb "OUR NEW DOS",0 ;;------------------------------------------------------------------------------ display_message: ld a,(hl) inc hl or a ret z call txt_output jr display_message ;;----------------------------------------------------------------------------- ;; functions we want to override cas_in_open equ &bc77 cas_in_close equ &bc7a cas_in_abandon equ &bc7d cas_in_char equ &bc80 cas_in_direct equ &bc83 cas_return equ &bc86 cas_test_eof equ &bc89 cas_out_open equ &bc8c cas_out_close equ &bc8f cas_out_abandon equ &bc92 cas_out_char equ &bc95 cas_out_direct equ &bc98 cas_catalog equ &bc9b kl_curr_selection equ &b912 txt_output equ &bb5a rst_3_instruction equ &df cas_range_size equ cas_catalog+3-cas_in_open our_far_calls equ 0 old_calls_offset equ cas_range_size boot: ;; allocate some space for: ;; 1. old calls ;; 2. our new far calls or a ld bc,cas_range_size+cas_range_size ;; reserve some bytes sbc hl,bc push hl push de push hl ld bc,old_calls_offset ;; offset into our buffer for old calls add hl,bc ;; base of our area ex de,hl ;; DE = address in our reserved area to store old calls ld hl,cas_in_open ;; length of all the calls we will patch ld bc,cas_catalog+3-cas_in_open ldir ;; setup some far calls ;; we patch the firmware function with ;; rst and an address (within our reserved area) ;; which will call our rom functions ;; which rom are we? call kl_curr_selection ld c,a ;; offset into our data ld e,(ix+store_offset+0) ld d,(ix+store_offset+1) add hl,de ex de,hl ;; DE = address to write ;; function to copy ld l,(ix+orig_function+0) ld h,(ix+orig_function+1) push hl ;; copy 3 bytes ldi ldi ldi pop hl ld a,rst_3_instruction ld (hl),a inc hl ld e,(ix+new_function+0) ld d,(ix+new_function+1) ld (hl),e inc hl ld (hl),d inc de pop hl ;; hl = address of our calls ld bc,our_far_calls add hl,bc ;; hl = address in ram of our far calls ld ix,our_calls ld b,num_our_calls ld e,(ix+0) ld d,(ix+1) ld e,(ix+0) ld d,(ix+1) inc ix inc ix ld (hl),e ;; address inc hl ld (hl),d inc hl ld (hl),c ;; rom inc hl ;; write into our ram ld de,our_cas_in_open call write_far_call ld hl,cas_in_open ld de,our_cas_in_open_farcall call patch_firmware ;; we could try a crc and report an error and return bad initialisation...? ;; show startup message ld hl,boot_message call display_message pop de pop hl ;; initialisation successful scf ret num_our_calls equ (end_our_calls-our_calls)/2 our_calls: ;; function to override defw cas_in_open ;; our call defw our_cas_in_open ;; offset to stored function defw 0 ;; offset to far call in our area defw 0 defw cas_in_close defw our_cas_in_close defw cas_in_abandon defw our_cas_in_abandon defw cas_in_char defw our_cas_in_char defw our_cas_in_direct defw our_cas_return defw our_cas_test_eof defw our_cas_out_open defw our_cas_out_close defw our_cas_out_abandon defw our_cas_out_char defw our_cas_out_direct defw our_cas_catalog end_our_calls: ;;----------------------------------------------------------------------- ;; B = length of filename ;; HL = points to filename ;; DE = 2k buffer ;; example AMSDOS filenames: ;; <user><drive>:<filename> ;; <drive>:<filename> ;; <user>:<filename> ;; <filename> ;; ;; ;; iy points to our area. our_cas_in_open: ret ;;----------------------------------------------------------------------- ;; HL = address in main ram to write far call ;; DE = function in our rom ;; C = rom select ;; ;; far call structure: ;; 2-byte address, 1-byte rom select write_far_call: ld (hl),e inc hl ld (hl),d inc hl ld (hl),c inc hl ret ;;----------------------------------------------------------------------- ;; HL = firmware function to patch ;; DE = far call address ;; ;; far call: ;; rst 3 ;; 2-byte address of far call structure patch_firmware: ld (hl),rst_3_instruction ;; rst 3 inc hl ld (hl),e inc hl ld (hl),d inc hl ret