Files
Shawn Quick dfcaae62dd Add qlink, the disk tools, and a bootable ProDOS 8 image.
Move the assembler to src/qasm. qlink links OMF 1.0 and 2.0 from a script. makeBin flattens a load file, qomf dumps OMF, and qpro builds ProDOS volumes. APW and MPW assemble through the ORCA front end. Relocatable modules emit OMF objects. Listings stay off unless -l is set.

make boot assembles the GS/OS 6.0.1 ProDOS 8 kernel and BASIC.SYSTEM into an 800K volume. BASIC.SYSTEM accepts ls and pfx, and its splash reports PRODOS BASIC 2.0, copyright 1983-2026. IIGS.601.SRC is the source and the BASIC.SYSTEM oracle that image is built from.
2026-10-16 14:41:55 -07:00

1 line
189 KiB
Plaintext

print nomdir
pagesize 70
debug_on equ $00 ;$01 = debug code installed
entry draw_express
;==================================================================================================
;ExpressLoad: This program is designed to load and relocate GS applications very fast.
; It is intended to compliment the System Loader; not replace it.
;
;Create: Sept. 30, 1988
;Modified: Apr. 23, 1990
;Author: Rob Turner
;
;Copyright Apple Computer Inc. 1988,1989,1990 All Rights Reserved
;
;Before you get started grab the ERS which has pictures of the data structures.
;
;
;Version 1.0
; First version to go on a system disk.
;
;Version 1.0 a01 01/10/89 by Rob Turner
;
; Fixed a bug in the initial load routine. The routine was not storing
; the special_memory flag. I also added the ability to load the stack
; and direct page segments regardless of the attr_no_spec flag.
;
;Version 1.0 a02 01/11/89 by Rob Turner
;
; Speeded up reloading of restart segmments by leaving the file open
; while processing each segment. I also reversered the order of loading
; restart and init segments.
;
;Version 1.0 a03 01/12/89 by Rob Turner
;
; Changed all the main routines to return to the caller with an error
; if an error occurs after I have determined that the file is an ExpressLoad file.
;
;Version 1.0 a04 01/16/89 by Rob Turner
;
; Major changes have occurred. ExpressLoad now leaves a load file open if the
; file contains any Dynamic Segments. The file will be closed when the shutdown
; down call is made. The ProcessSegment routine was optimized, and in doing so I
; changed the data bank register to point to the relocation dicationary and NOT
; my program bank. This means that I must be very careful accessing data in my bank.
; I seperated the code that has the data bank register set to the relocation
; dictionary. The code is now in "ProcRelocDataBankChanged"
;
;Version 1.0 a05 01/17/89 by Rob Turner
;
; ExpressLoad now gets called directly instead of using the notification queue.
; Cheryl (GQuit) will call me with three different types of events.
; (0) = Startup. (4) = Switch P8 to GS/OS (2) = Switch GS/OS to P8
;
;Version 1.0 a06 01/17/89 by Rob Turner
;
; Fixed a bug in Restart. If the app could not be restarted I was using ExpressHandle
; when it was not valid. This caused the open routine to fail since I thing that
; there is a valid reference number.
;
;Version 1.0 a07 01/18/89 by Rob Turner
;
; Fixed a bug in restart. I was deleting a user_id then using it to allocate memory.
;
;Version 1.0 a08 01/22/89 by Rob Turner
;
; Changed the initial load routine. I now load the static segments in the order
; they appear in the file instead of loading the stack segment first. I also
; maintain my own file mark so I do not have to make extra GS/OS calls.
;
;Version 1.0 a09 01/25/89 by Rob Turner
;
; Changed the load static routine so it will not use the stack as the first
; code segment.
;
;Version 1.0 a0A 02/20/89 by Rob Turner
;
; I now unlock the ExpressHandle Segment on Exit.
;
;Version 1.0 a0B 02/21/89 by Rob Turner
;
; Fixed a bug in Unload2 routine. If the address passed in is in a jump table
; segment the Unload routine has to do a level of indirection to get the
; real address to unload. The old routine was just unloading the jump table segment
; without doing the indirection.
;
;Version 1.0 a0C 02/21/89 by Rob Turner
;
; Fixed a bug in Unload2 routine. The return parameters were not correct if the
; segment was not loaded.
;
;Version 1.0 a0D 02/23/89 by Rob Turner
;
; Fixed a bug in Load_seg_by_num. The routine was not converting the
; original segment number to the new segment number.
;
;Version 1.0 a0E 02/23/89 by Rob Turner
;
; Changed the inital load routines so they only leave the load file open
; if the file has a type of Application and contain dynamic segments.
;
;Version 1.0 a0F 02/27/89 by Rob Turner
;
; Added ExpressLoad to boot screen.
;
;Version 1.0 a10 03/01/89 by Rob Turner
;
; I now unlock the 2K User_ID_Table. I was leaving the handle locked.
;
;Version 1.0 b01 03/06/89 by Rob Turner
;
; Fixed a bug in Unload_Seg1. The routine was not converting the
; original segment number to the new segment number.
;
;Version 1.0 b02 03/06/89 by Rob Turner
;
; Changed the startup routine to allocate my direct page with my ID
; instead of a GS/OS ID.
;
;Version 1.0 b03 03/08/89 by Rob Turner
;
; Fixed the locked handle bug. I was saving a handles attributes even
; though the handle was not valid. I then allocated the handle and
; slammed the old attributes into it.
;
;Version 1.0 b04 03/21/89 by Rob Turner
;
; Init segments are now ran in the order that they appear in the file.
;
;Version 1.0 b05 03/27/89 by Rob Turner
;
; Added conditional to ExpressLoad boot screen. If the user holds down
; the Apple and Option key during boot then the ExpressLoad logo will be
; drawn. I will also draw the logo if the Aux type for ExpressLoad is set
; to $5254 i.e. 'RT'.
;
;Version 1.0 b06 03/31/89 by Rob Turner
;
; Fixed a bug in LoadSegByName and UnloadSeg. The routines were not returning
; the correct segment numbers when a user made the call.
;
;Version 1.0 b07 04/4/89 by Rob Turner
;
; Fixed a bug in UnloadSeg1. I was not purging all dynamic segments if the
; segment number was zero.
;
;Version 1.0 b08 04/6/89 by Rob Turner
;
; Fixed several bugs in allocating special memory segments. These include bank
; aligned and fixed address within a bank.
;
;Version 1.0 b09 04/24/89 by Rob Turner
;
; Fixed two bugs. The first bug occured when the user made a load_seg_by_name call.
; The call would return the address of the last loaded segment. Therefore, it was
; possible to get the wrong address returned. The second bug involved returned
; segment numbers. ExpressLoad was not converting output segment number when
; returning them to the caller. If the caller did a load_seg_by_name, then used the
; returned segment number to issue a load_seg_by_num call it would fail.
;
;Version 1.0 b0A 04/24/89 by Rob Turner
;
; Fixed a bug in all routines that have a user id as input. ExpressLoad
; could fail if the user_id was zero (indicating that ExpressLoad should
; use the current ID). If the file was not loaded by ExpressLoad the call
; would fail.
;
;Version 1.0 b0B 04/26/89 by Rob Turner
;
; Removed segment type check when loading the ExpressLoad segment.
; I now look for the name only. The name can be either, "ExpressLoad"
; or "~ExpressLoad".
;
;Version 1.0 b0C 05/09/89 by Rob Turner
;
; Changed "Check_express_seg" to check for a read failure.
;
;Version 1.0 b0D 05/12/89 by Rob Turner
;
; ExpressLoad now supports renaming of loaded files. The loader call
; number is $1311.
;
;Version 1.0 b0E 05/18/89 by Rob Turner
;
; ExpressLoad now supports renaming of ExpressLoad pathnames. ExpressLoad was
; only renaming pathnames that contained the Application.
;
;Version 1.0 b0F 05/19/89 by Rob Turner
;
; ExpressLoad now supports a relocation dictionary of zero length. LinkIIGS
; is creating a file mark for a zero length relocation dictionary, so I had
; to modify the loader to handle it.
;
;Version 1.0 b10 05/23/89 by Rob Turner
;
; ExpressLoad now returns "seg_not_found" if the caller passes in the
; wrong pathname.
;
;Version 1.0 b11 05/24/89 by Rob Turner
;
; ExpressLoad was using a buffer that was too small by two bytes.
;
;Version 1.0 b12 06/01/89 by Rob Turner
;
; Added calls to lock and unlock handles around OS calls. I also
; zero local handles when Dispose_handle is called.
;
;Version 1.02 06/11/89 by Rob Turner
;
; Fixed a bug in Restart. Restart could fail if the Application
; was launched off another volume (with a shorter name) and later,
; could not be restarted due to segments being purged. The problem
; was, merge_path was not setting up partial_offset, this caused
; the pathname to be screwed up in the ExpressSegment on the rebuild.
;
;Version 1.03 06/14/89 by Rob Turner
;
; Fixed a non-derefed pointer bug. One of the handles was left out
; of the Lock_Handles routine, causing bad things to happen under
; scrambler.
;
;Version 1.04 06/16/89 by Rob Turner
;
; Fixed a bug when calling INIT segments. I was calling lock_handles
; when the direct register was already set to $0000 for the init segment.
; This caused many problems. I also, now restore the bank register when
; returning from the init segment.
;
;Version 1.05 04/23/90 by Greg Branche
;
; Unloading a dynamic segment by address is not working reliably. When the address
; of a procedure within a dynamic segment is passed which hasn't been used yet,
; ExpressLoad looks at it's jump table segment and assumes that, since the referenced
; entry hasn't been patched yet, it can't have been loaded yet. This is being
; corrected by having ExpressLoad always attempt to mark the dynamic segment as
; purgeable, whether it's in memory or not. Since it ignores a "Segment Not Found"
; error returned by Make_Purgeable, this shouldn't cause any problems. Procedure
; affected = L_unload2. Change marked by {gab - 04/23/90}
;
;Version 1.06 05/07/91 by Greg Branche
; InitialLoad was trashing the first byte of the input pathname if it
; encountered a Bad Path Syntax error from GS/OS. Fixed.
; Restart would fail to restore the system preferences if it failed. Fixed.
; When loading Initalization segments, Expressload now tries to stay out of
; special memory. Only if we can't get non-special memory for the segment
; will special memory be used, unless the segment attributes prevent it.
; During Restart, special memory is not used unless there isn't enough
; non-special memory available.
; During InitialLoad, Expressload now checks the EOF of the load file and
; returns a NotLoadFile error if the EOF is 0.
; When loading a dynamic segment, Expressload no longer ORA's a #$1100 into
; any error code returned from other parts of the system prior to going
; to system death.
;
; 06/05/91 Extra PHA instruction was left in the error_routine subroutine, which was
; messing up the message displayed by the SysFailMgr.
; alloc_ExpLoad is returning the application userID as an error code when
; an error occurs. This has been fixed.
; close_load_file no longer restores the system preferences, since
; open_load_file already does that after the file is opened up.
; l_user_shutdown now locks the user_id_tbl memory block containing the
; user ID entry for the load file being shutdown prior to deleting the
; entry from the table. The block is then unlocked again prior to exit.
;
; 06/17/91 Added logic to set and restore the proper GS/OS system preferences while
; loading a dynamic segment.
;
; 06/21/91 Fixed load_segment so that non-special memory is ALWAYS requested first.
; Only if we can't get non-special memory for the segment, AND the segment
; attributes allow it will we try again, allowing special memory to be
; used.
; Fixed alloc_lconst_seg so that my handles are not locked and unlocked
; everytime a memory manager call is made in the loop that tries to
; allocate a bank-aligned block of memory.
; Fixed alloc_lconst_seg so that when the bank number to allocate reaches
; $80, the subroutine exits with a Memory Full error (used to loop
; until the bank value reached $FF.)
;
; 07/09/91 Added file type $C7 (CDev) to list of allowable load files.
; Fixed InitialLoad2 so that it disposes of any memory used by a partially
; loaded file when an error occurs.
; Fixed handling of no-special memory allocation so that fixed-bank segments
; are allowed to use special memory.
; Changed allocation of bank-aligned segments so that it should be quicker
; and memory won't get purged quite so often. Now, alloc_LConst_seg
; tries to allocate an entire bank of memory, then disposes of it again,
; then uses the allocated bank number to allocate memory for the
; loaded segment.
;
;==================================================================================================
;Revisions
Eject
ExpressLoad proc Export
import Switch_handler
import do_save_AXY
jmp Switch_handler
export Save_AXY
save_AXY jmp do_save_AXY
string pascal
dc.b 'ExpressLoad Ver 1.06 Designed and Written by Rob Turner'
string asis
endp
print push
print off
INCLUDE 'M16.Util'
INCLUDE 'M16.MEMORY'
INCLUDE 'ExpressLoad.Macros'
print pop
eject
include 'ExpressLoad.Data'
eject
;====================================================================================================
;seg_num_lookup: This routine will take a segment number and convert the number
; to the correct segment number via the segment conversion table
;
;Input: A = original segment number
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; HET_ptr ;must point to seg_num_count
;
;Output: A = new segment number
; X = preserved
; Y = preserved
; P = nvmxdizc
; ..000..1=error
; b = k
;
;
;
;====================================================================================================
longa on
longi on
seg_num_lookup proc
with data
tax
beq @bad_seg_num ;sorry bud
dec a ;make zero based
cmp [HET_ptr] ;is it in the range?
beq @num_OK
bcs @bad_seg_num ;sorry the segment number is no good
@num_OK
clc
lda [HET_ptr] ;get the number of segments please
inc a ;add one for 0 based stuff
asl a
asl a
asl a ;times 8 to pass Header Entry table
adc #$0002 ;pass the count please
; clc
adc HET_ptr ;add current position
sta temp_ptr
lda #$0000
adc HET_ptr+2
sta temp_ptr+2 ;Temp pointer now points to the segment conv tbl
dex ;subtract one for zero based please
txa ;Times two for word table
asl a
tay ;index to the real segment number
lda [temp_ptr],y
clc
rts ;return with the new segment number in "A"
@bad_seg_num
lda #seg_not_found
sec
rts ;return the "Error"
endp
eject
;====================================================================================================
;my_seg_to_user_seg: This routine will take my segment number and convert the number
; to the correct segment number via the segment conversion table.
; This means if you use the segment number returned to you as input
; to another loader call then everything will workout OK.
;
;Input: A = internal segment number
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; HET_ptr ;must point to seg_num_count
;
;Output: A = new segment number for user
; X = preserved
; Y = preserved
; P = nvmxdizc
; ..000..1=error
; b = k
;
;
;
;====================================================================================================
longa on
longi on
my_seg_to_user_seg proc
with data
pha ;segment we need to find
clc
lda [HET_ptr] ;get the number of segments please
inc a ;add one for 0 based stuff
asl a
asl a
asl a ;times 8 to pass Header Entry table
adc #$0002 ;pass the count please
; clc
adc HET_ptr ;add current position
sta temp_ptr
lda #$0000
adc HET_ptr+2
sta temp_ptr+2 ;Temp pointer now points to the segment conv tbl
ldy #$0000
@look_loop
lda [temp_ptr],y
cmp 1,s ;is this the correct segment number
beq @have_segment
iny
iny
bne @look_loop
pla
lda #seg_not_found
sec
rts ;return the "Error"
@have_segment pla ;stack fix
tya ;convert index to segment number
lsr a
inc a ;add one to convert from 0 to 1 based
clc
rts
endp
eject
;====================================================================================================
;reset_local_mark: This routine will reset our local mark to $FFFFFF.
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = preserved
; X = preserved
; Y = preserved
; P = preserved
; b = k
;
;
;
;====================================================================================================
longa on
longi on
reset_local_mark proc
with data
lda #$FFFF
sta local_mark
sta local_mark+2
rts
endp
eject
;====================================================================================================
;lock_handles This routine will save and lock handles used by ExpressLoad
;unlock_handles This routine will restore the previous state of the now locked handle
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = preserved
; X = preserved
; Y = preserved
; P = preserved
; b = k
;
;
;
;====================================================================================================
longa on
longi on
lock_handles proc
with data
php ;save all registers!
pha
phx
phy
ldy #$0004 ;lets lock this puppy
lda ExpressHandle
ora ExpressHandle+2
beq @skip_express
lda [ExpressHandle],y
sta ExpressHndl_flag
ora #$8000 ;lock the handle
sta [ExpressHandle],y
@skip_express
lda user_id_handle ;lock ID table down
ora user_id_handle+2
beq @skip_ids
lda [user_id_handle],y
sta User_ID_flag
ora #$8000 ;lock the handle
sta [user_id_handle],y
@skip_ids
lda temp_handle
ora temp_handle+2
beq @skip_temp
lda [temp_handle],y
sta tempHndl_flag
ora #$8000 ;lock the handle
sta [temp_handle],y
@skip_temp
lda reloc_handle
ora reloc_handle+2
beq @skip_reloc
lda [reloc_handle],y
sta relocHndl_flag
ora #$8000 ;lock the handle
sta [reloc_handle],y
@skip_reloc
lda seg_handle
ora seg_handle+2
beq @skip_seg
lda [seg_handle],y
sta segHndl_flag
ora #$8000 ;lock the handle
sta [seg_handle],y
@skip_seg
lda curr_id_handle
ora curr_id_handle+2
beq @skip_id
lda [curr_id_handle],y
sta idHndl_flag
ora #$8000 ;lock the handle
sta [curr_id_handle],y
@skip_id
bra end_handles
export unlock_handles
unlock_handles
php ;save all registers!
pha
phx
phy
ldy #$0004 ;lets lock this puppy
lda ExpressHandle
ora ExpressHandle+2
beq @skip_express
lda ExpressHndl_flag ;restore old state
sta [ExpressHandle],y
@skip_express
lda temp_handle
ora temp_handle+2
beq @skip_temp
lda tempHndl_flag ;restore original state
sta [temp_handle],y
@skip_temp
lda user_id_handle ;lock ID table down
ora user_id_handle+2
beq @skip_ids
lda User_ID_flag
sta [user_id_handle],y
@skip_ids
lda reloc_handle
ora reloc_handle+2
beq @skip_reloc
lda relocHndl_flag ;restore orig state
sta [reloc_handle],y
@skip_reloc
lda seg_handle
ora seg_handle+2
beq @skip_seg
lda segHndl_flag ;do the restore
sta [seg_handle],y
@skip_seg
lda curr_id_handle
ora curr_id_handle+2
beq @skip_id
lda idHndl_flag ;do the restore
sta [curr_id_handle],y
@skip_id
end_handles
ply
plx
pla
plp ;restore original registers
rts
ExpressHndl_flag dc.w 00
tempHndl_flag dc.w 00
relocHndl_flag dc.w 00
segHndl_flag dc.w 00
idHndl_flag dc.w 00
user_id_flag dc.w 00
endp
eject
;====================================================================================================
;clear_handles: This routine will zero any local handles that contain a copy of the
; handle that we are disposing
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; stack:
;
; Y register $1,s
; X register $3,s
; Accum $5,s
; processor_status $7,s
; return address $8,s
; low word of handle $A,s
; high word of handle $C,s
;
;Output: A = restored
; X = restored
; Y = restored
; P = nvmxdizc
; ..000...
; b = k
;
;
;
;====================================================================================================
clear_handles proc
php
pha
phx
phy
lda $0A,s ;get the low word of the handle
tax
lda $0C,s ;get the high word of the handle
cmp ExpressHandle+2
bne @skip_express ;Does Express = Dispose Handle?
cpx ExpressHandle
bne @skip_express
stz ExpressHandle ;zero matching handle
stz ExpressHandle+2
@skip_express
cmp temp_handle
bne @skip_temp
cpx temp_handle+2
bne @skip_temp
stz temp_handle
stz temp_handle+2
@skip_temp
cmp reloc_handle
bne @skip_reloc
cpx reloc_handle+2
bne @skip_reloc
stz reloc_handle
stz reloc_handle+2
@skip_reloc
cmp seg_handle
bne @skip_seg
cpx seg_handle+2
bne @skip_seg
stz seg_handle
stz seg_handle+2
@skip_seg
cmp curr_id_handle
bne @skip_id
cpx curr_id_handle+2
bne @skip_id
stz curr_id_handle
stz curr_id_handle+2
@skip_id
ply
plx
pla
plp
rts
endp
eject
;====================================================================================================
;Error_routine: This routine will call the death manager with an error code. The routine will not
; return to the caller. The routine is called with a JSR so I can display the
; address if I want to.
;
;Input: A = error_code
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;
;====================================================================================================
longa on
longi on
error_routine proc
with data
pha ;push the error code
pea err_string>>16
pea err_string
ldx #$1503 ;call the death manager
jsl $e10000
brk $ff
string pascal
err_string dc.b 'ExpressLoad error: '
string asis
endp
eject
;====================================================================================================
;make_HET_ptr: This routine builds a pointer to the Header Entry Table
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; ExpressHandle ;must be setup
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; HET_ptr will point to the segment count field in the Header Entry Table (HET)
; temp_ptr will point to the link field (HET_ptr-4)
;
;====================================================================================================
longa on
longi on
make_HET_ptr proc
with data
;
;Setup temp_ptr to point to the reserved field (of Disk Image) of the HET
;
ldy #$0002
clc
lda [ExpressHandle]
adc #extra_header ;load ExpressSegment past Extra Header
tax
sta temp_ptr ;temp now points the link field
lda [ExpressHandle],y
adc #$0000
tay
sta temp_ptr+2
;
;Now set HET_ptr to point past the reserved field of the disk image
;
clc
txa
adc #$0004 ;pass the reserved field
sta HET_ptr ;header entry table pointer
tya
adc #$0000
sta HET_ptr+2
rts
endp
eject
;====================================================================================================
;setup_seg_ptrs: This routine builds pointers to the segment header entry and the segment
;
;Input: A = segment number
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; HET_entry_ptr
; seg_header_ptr
;
;====================================================================================================
longa on
longi on
setup_seg_ptrs proc
with data
dec a ;convert the segment number please
sec
sbc ExpressSeg_pos ;0 or 1
asl a
asl a
asl a ;times 8 for HET entry size
inc a ;add two to pass the segment count field
inc a
clc
adc HET_ptr ;make a pointer to the Entry
sta HET_Entry_ptr ;pointer to the entry itself
lda #$0000
adc HET_ptr+2
sta HET_Entry_ptr+2
;
;Build a pointer to the segment header itself
;
clc
lda HET_entry_ptr ;add in relative address to segment
adc [HET_Entry_ptr]
sta seg_header_ptr
lda HET_Entry_ptr+2
adc #$0000
sta seg_header_ptr+2
rts
endp
eject
;====================================================================================================
;setup_base_ptr: This routine setups the pointer to the base address of the segment
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; Het_Entry_pointer ;must be setup
; seg_header_ptr
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
; base_ptr
; segment_entry
;====================================================================================================
longa on
longi on
setup_base_ptr proc
with data
import add_segment_offset
ldy #handle_offset ;setup the Base_ptr
lda [HET_entry_ptr],y
tax
iny
iny
lda [HET_entry_ptr],y
tay
bne @good_handle
txa
bne @good_Handle
sec
rts
@good_Handle
stx temp_handle
sty temp_handle+2 ;handle to the segment in memory
ldy #$0002 ;deref the handle to get the base address
lda [temp_handle]
tax
lda [temp_handle],y
tay
bne @good_address
tax
bne @good_address
sec
rts
@good_address
stx base_ptr
sty base_ptr+2 ;address of the segment in memory
jsr add_segment_offset
clc
rts
endp
eject
;====================================================================================================
;Alloc_ID: This routine will allocate a new user ID for a load file. This routine is called
; by the "initial_Load" routine
;
;Input: A = user_id ;ID from the caller
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = user_id ;ID for the application
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
Alloc_id proc
with data
tax
and #$00FF
bne @exit_alloc ;use the given ID
txa
and #$FF00 ;see if the Type_ID is 0
bne @get_new ;Use the Input Type and Aux type please
txa
ora #app_type_id ;set the Type to Application
tax
@get_new
pea $0000 ;space for result
phx ;ID stuff
ldx #$2003 ;GetNewID
jsl $e10000
plx
bcs @oops ;return the error
@exit_alloc
txa ;set A = User_ID
sta user_id ;this is now the Global_ID
clc
@oops
rts
endp
eject
;====================================================================================================
;compare_paths: This routine will compare Expanded_Name and Full_Blown to see if they are equal
; It can also compare partial paths if "Partial_Match" is negative.
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..0 = Complete path found
; 1 = Complete path not found
; 0 = partial path found.
; 1 = partial path not found.
; b = k
;
;
;====================================================================================================
longa on
longi on
compare_paths proc
with data
lda Expanded_name.size ;compare the string sizes first
tay
cmp Full_Blown.size
beq @do_full_check
bcc @chk_colon_full_blown ;expand_name_contains the smaller string.
lda full_blown.size
tay
iny ;full blown contains the smaller string
lda expanded_name.name-1,y
bra @do_chk
@chk_colon_full_blown
iny
lda full_blown.name-1,y
@do_chk
and #$00FF
cmp #seperator ;is it a seperator?
bne @not_same
dey
@do_partial_compare
lda partial_match ;are we looking for a partial match?
bpl @not_same ;don't bother.
sty SubStr_size ;size of the substring
longa off
sep #$20
@partial_loop
lda Expanded_name.name-1,y ;compare the ascii data
cmp full_blown.name-1,y
bne @not_same
dey
bne @partial_loop
rep #$60 ;we have a match (clear overflow bit as well)
sec ;no complete path found.
rts
@do_full_check
longa off
sep #$20
@loop
lda Expanded_name.name-1,y ;compare the ascii data
cmp full_blown.name-1,y
bne @not_same
dey
bne @loop
rep #$20
clc
rts ;the pathnames are the same
@not_same
longa on
rep #$20
sep #$41 ;no partial or complete match found
rts
endp
eject
;====================================================================================================
;Expand_Path: This routine will expand a partial path into a complete GS/OS pathname
; Note: The name buffer is an internal 256 byte buffer, in the future
; use the memory manager to get memory for the name.
;
;Input: A = undefined
; X = low word ptr to pathname
; Y = high word ptr to pathname
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
; Expanded_name is setup
;
;====================================================================================================
longa on
longi on
Expand_Path proc
with data
stx expand.src
sty expand.src+2
lda #expanded_name
sta expand.dest
lda #^expanded_name
sta expand.dest+2
jsr lock_handles
jsl $e100a8 ;call GS/OS
dc.w $200E ;expand path call
dc.l Expand ;pointer to the parameter
jsr unlock_handles
bcc @full_blown ;great news.
rts
@full_blown
with Expanded_name
lda #Expanded_name.size ;address of GString
sta Open_List.Path_ptr
lda #^Expanded_name.size ;address of GString
sta Open_List.Path_ptr+2 ;setup the Open Parameter block
;====================================================================================================
;
;This routine will take the pathname stored in Expanded_Name and generate the following variables:
;
; partial_size ;size of the partial string
; partial_offset ;offset to the partial string
; vol_size ;size of the volume
; path_size ;= Source size
;
;Input: Expanded_name ;must contain a GString.
;
;
;====================================================================================================
export setup_path_sizes
setup_path_sizes
stz partial_size ;there is no partial path
lda size
sta path_size ;the complete size of the string
beq @end_expand
ldx #$0001 ;convert from 1 based to two based
ldy #$0000 ;init the volume size counter
@vol_loop
lda name,x ;get the character please
iny
and #$00FF ;clear garbage
cmp #seperator
beq @save_vol ;we now have the volume size
inx ;move to the next character
cpx size ;have we looked at all the characters?
bne @vol_loop
iny ;adjust count correctly
@save_vol
dey ;make count correct
sty vol_size ;the size of the volume name
cpx size ;is there anything to look at?
beq @end_expand
ldy #$0000 ;reset counter for partial length
inx ;point pass the colon please
cpx size
beq @end_expand ;pathname ended with a colon
stx partial_offset ;beginning of the partial pathname
sec
lda size ;calculate the size of the partial
sbc partial_offset
sta partial_size
@end_expand
clc
rts
endp
eject
;====================================================================================================
;GString_to_PString: This routine will convert a GString into a PString. It will also
; Convert Colons to Slashes.
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; Expanded_Name ;Contains GString
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
; full_blown ;setup with the new string.
;
;====================================================================================================
longa on
longi on
GString_to_PString proc
with data
lda Expanded_name.size ;get the size of the name
sta Full_Blown.size
cmp #$0100
bcs @bad_name ;I cannot convert the name
tay ;number of characters to move
longa off
sep #$20
@loop
lda Expanded_Name.name-1,y ;get the character
cmp #'/'
beq @bad_name ;name contains Slashes
cmp #':'
bne @store_it
lda #'/' ;convert to a slash
@store_it
sta Full_Blown.size,y ;store the character
dey
bne @loop
rep #$20
clc
rts
@bad_name
sec
rts
endp
eject
;====================================================================================================
;Expand_app_path: This routine will expand the pathname that has been supplied by the
; caller.
;
;Input: A = undefined
; X = pointer to input string: low
; Y = pointer to input string: high
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
; full_blown ;setup with the new string.
;
;====================================================================================================
longa on
longi on
Expand_app_path proc
with data
txa ;back up one for GString conversion
bne @low_only
dey
@low_only
dex
stx temp_ptr
stx expand.src
sty temp_ptr+2
sty expand.src+2 ;parameter for Expand Path
lda [temp_ptr] ;get garbage + length byte
pha ;save it please
xba ;put length byte in the low word
and #$00FF ;clear the garbage
sta [temp_ptr] ;PString now equals GString
lda #full_blown ;setup destination buffer
sta expand.dest
lda #^full_blown
sta expand.dest+2
jsr lock_handles
jsl $e100a8 ;call GS/OS
dc.w $200E ;expand path call
dc.l Expand ;pointer to the parameter
jsr unlock_handles
bcc @big_name ;great news.
tax ;save the error code
pla
sta [temp_ptr]
txa
rts
@big_name
pla
sta [temp_ptr] ;restore the callers PString
rts
endp
eject
;====================================================================================================
;Merge_path: This routine will merge the volume name and partial path into one complete pathname
; The names are stored at the end of an ExpressLoad segment
;
;Input: A = undefined
; X = low word of ExpressHandle
; Y = High Word of ExpressHandle
; P = nvmxdizc
; ..000...
; b = k
;
; ExpressHandle ;must be setup
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
; Expanded_name ;setup with the new string.
;
;====================================================================================================
longa on
longi on
Merge_path proc
with data
stx ExpressHandle
sty ExpressHandle+2
ldy #$0002 ;build a pointer to ExpressSegment
lda [ExpressHandle]
sta temp_ptr
lda [ExpressHandle],y
sta temp_ptr+2
;
;Now we need to build a pointer to the volume name
;
ldy #seg_vol_offset ;offset to the volume name
clc
lda [Temp_ptr],y
adc temp_ptr
sta vol_ptr
lda #$0000
adc temp_ptr+2
sta vol_ptr+2 ;super_ptr now points to the volume name
;
;Now we need to build a pointer to the partial pathname
;
iny
iny ;point to the partial pathname
clc
lda [Temp_ptr],y
adc temp_ptr
sta path_ptr
lda #$0000
adc temp_ptr+2
sta path_ptr+2 ;super_ptr now points to the volume name
;
;OK now lets merge the volume and the partial pathname
;
with expanded_name
longa off
sep #$20 ;switch to eight bit mode
clc
lda #$02 ;there will be two seperators added
adc [vol_ptr] ;the length of the volume name
clc
adc [path_ptr] ;the length of the partial name
sta size
sta path_size
lda [vol_ptr] ;save the length
sta vol_size
lda [path_ptr]
sta partial_size ;save the length of the partial pathname
lda #seperator ;start the name with a ":"
sta name
ldx #$0001 ;where we start storing the ascii name
txy
@move_vol
lda [vol_ptr],y
sta name,x
inx
iny
cpy vol_size ;are we done
bcc @move_vol
beq @move_vol
lda #seperator ;add in the second seperator
sta name,x
inx
ldy #$0001
@move_partial
lda [path_ptr],y ;get the character
sta name,x
inx
iny
cpy partial_size
bcc @move_partial
beq @move_partial
longa on
rep #$20
sec
lda size ;build partial offset
sbc partial_size
sta partial_offset
clc
rts
endp
eject
;====================================================================================================
;alloc_my_dp: This routine will allocate my direct page from the system.
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
;
;====================================================================================================
longa on
longi on
alloc_my_dp proc
with data
lda #256
sta free_mem_size ;save the request count
stz free_mem_size+2
lda #gs_os_start
sta search_addr ;start looking at $9A00 (start of GS/OS)
stz search_addr+2
@search_loop
pha ;space for handle
pha
PushLong free_mem_size ;request bytes
PushWord ExpLoad_ID
PushWord #attr_locked+attr_fixed+attr_addr+attr_page
PushLong search_addr ;address to start at
_NewHandle
plx
ply ;get the handle
bcs @not_done
stx dp_handle ;save my handle please
sty dp_handle+2
rts ;return the handle
@not_done
lda search_addr+1
dec a
sta search_addr+1 ;move down one page
cmp #$0008 ;have we searched down to $000800?
bne @search_loop
sec
rts ;we cannot get our direct page/stack
endp
eject
;====================================================================================================
;Switch_handler This routine is called when we switch from GS/OS to ProDOS 8 and when we switch
; from ProDOS8 to GS/OS. It is also called for startup
;
;Input: A = Function: 0 = startup, 4 = Swicth P8 to GS/OS, 2 = Switch GS/OS to P8
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
; The Direct page is saved and released if we are switching from GS/OS to P8
; The Direct page is allocated and restored if we are switching from P8 to GS/OS
;
;====================================================================================================
longa on
longi on
Switch_handler proc
with data
import main
import loader_patch
tax ;Is this my startup call?
bne @not_startup
jmp main ;do our main thing.
@not_startup
phk ;set our data bank register
plb
lda data.my_dir_page ;setup our own direct page
tcd
cpx #$0004 ;Switch P8 to GS/OS
beq @restore_dp
ldx #dir_page_size ;save the direct page please
@save_loop lda 00,x
sta dir_page_buffer,x
dex
dex
bpl @save_loop
lda dp_handle+2 ;dispose the handle
pha
lda dp_handle
pha
jsr clear_handles ;clear local copy of handle
ldx #$1002 ;dispose handle
jsl $e10000 ;its gone
stz dp_handle
stz dp_handle+2
rtl ;exit back to the system
@restore_dp
jsr alloc_my_dp ;allocate me a direct page please
bcc @got_it
rts ;return the error
@got_it
pei temp_handle ;save the current handle please
pei temp_handle+2
stx temp_handle
sty temp_handle+2 ;to determine our direct page
lda [temp_handle] ;get the page please
sta my_dir_page ;save my direct page please
ply
sty temp_handle+2 ;restore data used on current direct page
ply
sty temp_handle ;it is now safe to setup the direct register
tcd ;go ahead and setup the direct register
ldx #dir_page_size ;save the direct page please
@restore_loop lda dir_page_buffer,x
sta 00,x
dex
dex
bpl @restore_loop
clc
rtl
endp
eject
;====================================================================================================
;alloc_ExpLoad: This routine will allocate memory from the system for the loader.
;
;Input: A = undefined
; X = request bytes low
; Y = requets bytes high
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = handle low
; Y = handle high
; P = nvmxdizc
; ..000..
; b = k
;
;
;====================================================================================================
longa on
longi on
alloc_ExpLoad proc
with data
lda ExpLoad_ID ;my ID
bra do_alloc ;go allocate
eject
;====================================================================================================
;alloc_mem: This routine will allocate memory from the system.
;
;Input: A = user ID to use
; X = request bytes low
; Y = requets bytes high
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = handle low
; Y = handle high
; P = nvmxdizc
; ..000..
; b = k
;
;
;====================================================================================================
entry alloc_mem
alloc_mem
lda AppID ;use application ID for normal allocation
do_alloc
pha ;space for handle
pha
phy ;high request bytes
phx ;low request bytes
pha ;userID
pea $8000 ;locked
lda #0
pha
pha
jsr lock_handles ;lock my handles so they stay put!!
_NewHandle ;allocate the memory
jsr unlock_handles ;put the handles back to original state
plx
ply
rts
endp
eject
;====================================================================================================
;alloc_LConst_seg This routine will allocate memory from the system.
;
;Input: A = undefined
; X = request bytes low
; Y = requets bytes high
; P = nvmxdizc
; ..000...
; b = k
;
; seg_header_ptr ;must be setup
;
;Output: A = undefined
; X = handle low
; Y = handle high
; P = nvmxdizc
; ..000..
; b = k
;
;
;====================================================================================================
longa on
longi on
alloc_LConst_seg proc
with data
jsr lock_handles
lda mem_attr ;see if this is bank aligned or align in bank
and #attr_bank_align+attr_align_in_bank
bne @align_to_bank
pha ;space for handle
pha
phy ;high request bytes
phx ;low request bytes
PushWord AppID
lda mem_attr
pha
PushLong org_address ;address to start at
_NewHandle
jsr unlock_handles ;put the handles back to original state
plx
ply
rts
@align_to_bank
stx free_mem_size ;save the request count
sty free_mem_size+2
lda mem_attr ;clear the align to bank bit
and #�(attr_bank_align+attr_align_in_bank)
sta mem_attr
lda #$0002 ;start looking in bank two
sta search_addr+2 ;address we are searching for
lda org_address ;add in org. align in bank if non zero
sta search_addr
pha ;space for handle
pha
ldx #$0000 ;convenient place for a zero
pea $0001 ;allocate 64K
phx
lda AppID ;use App's ID
pha
lda mem_attr ;attributes
and #�(attr_Bank+attr_Addr)
ora #attr_No_Spec+attr_No_Cross
pha
phx ;location pointer
phx
_NewHandle ;allocate the memory
plx ;retrieve handle
ply
bcs @no_memory ;oops! couldn't get a whole bank!
phb ;save current DBR
phy ;set to handle's DBR
plb
inx ;bump to bank word of handle
inx
lda |0,x ;get the bank # that was allocated
plb
plb ;restore DBR
sta search_addr+2 ;save the bank value
dex ;restore original value
dex
phy
phx ;now deallocate the bank again
_DisposeHandle
@no_memory
lda #attr_addr+attr_bank ;set the fixed address and bank bits
tsb mem_attr
@search_loop
pha ;space for handle
pha
PushLong free_mem_size
PushWord AppID
lda mem_attr
pha
PushLong search_addr ;address to start at
_NewHandle
plx
ply ;get the handle
bcc @done ;if no error, return!
@not_done
inc search_addr+2
lda search_addr+2 ;move up one bank
cmp #$0080 ;have we searched all of memory?
bcc @search_loop
lda #$0201 ;synthesize a Memory Manager error
;(carry already set)
@done jsr unlock_handles
rts ;return the handle
endp
eject
;====================================================================================================
;add_id_table: This routine will allocate memory for one user_id_table and link the table
; into the list of user_id_tables. It will also zero the entire table
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
add_id_table proc
with data
ldx #id_tbl_size ;allocate the table please
ldy #$0000
jsr alloc_ExpLoad ;go and allocate memory using ExpressLoad ID
bcc @got_it
rts ;return the error to the caller
@got_it
stx temp_handle ;save the handle please
stx temp_long
sty temp_handle+2
sty temp_long+2
ldy #$0004 ;offset to memory manager attributes
lda [temp_handle],y
and #$7FFF ;unlock the handle
sta [temp_handle],y
ldy #$0002 ;make a pointer to new memory
lda [temp_handle]
sta user_id_ptr
lda [temp_handle],y
sta user_id_ptr+2
lda #$0000
ldy #id_tbl_size-2 ;clear the buffer please
@clear_loop
sta [user_id_ptr],y
dey
dey
bpl @clear_loop
;
;Now that we have cleared the segment lets link it into the list
;
lda user_id_handle ;see if this is the first one!
ora user_id_handle+2
bne @walk_list
lda temp_handle ;setup the first handle and exit
sta user_id_handle
lda temp_handle+2
sta user_id_handle+2
clc
rts
@walk_list
lda user_id_handle ;start at front of the list
sta temp_handle
lda user_id_handle+2
sta temp_handle+2
@search_loop
ldy #$0002
lda [temp_handle]
sta user_id_ptr
lda [temp_handle],y
sta user_id_ptr+2
lda [user_id_ptr] ;get the forward link please (Link = Handle)
tax
lda [user_id_ptr],y
tay
bne @next_one
txa
bne @next_one
ldy #$0002 ;link in the new entry
lda temp_long ;handle to our new segment
sta [user_id_ptr]
lda temp_long+2
sta [user_id_ptr],y
lda [temp_long] ;deref handle
sta user_id_ptr
lda [temp_long],y
sta user_id_ptr+2
clc
rts
@next_one
stx temp_handle
sty temp_handle+2
bra @search_loop
endp
eject
;====================================================================================================
;add_user_id: This routine will find a empty spot in the user_id table and allocate it
;
;Input: A = user_id ;ID from the caller
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;Output: A = undefined
; X = low word address of entry
; Y = high word address of entry
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
Add_user_id proc
with data
sta temp_word ;ID to add
ldy #$0002 ;start at the beginning of the User_Id table
lda [user_id_handle]
sta user_id_ptr
lda [user_id_handle],y
sta user_id_ptr+2
@loop
jsr get_free_id ;find a free spot in the table
bcc @got_it
jsr add_id_table ;add another table please
bcc @loop ;try again
rts ;return the error
@got_it
ldx temp_ptr
ldy temp_ptr+2 ;address of the entry
clc
rts
get_free_id
ldy #id_entry_size ;start at the first available spot
ldx #id_entry_cnt ;number of entries in a table
@search_loop
lda [user_id_ptr],y ;is this avail.
beq @its_free
clc
tya
adc #id_entry_size
tay
dex
bpl @search_loop
sec
rts
@its_free
clc ;build a pointer to the entry
tya
adc user_id_ptr
sta temp_ptr
sta user_id_ptr
lda #$000
adc user_id_ptr+2
sta temp_ptr+2
sta user_id_ptr+2
ldy #14 ;clear the entry please (16 bytes total 0 thru 15)
lda #$0000
@clr_it
sta [temp_ptr],y
dey
dey
bpl @clr_it
lda temp_word ;save the user Id please
sta [temp_ptr]
clc
rts
endp
eject
;====================================================================================================
;delete_user_id: This routine will delete the user_id pointer to by user_id
;
;Input: A = User_ID_Flag: 0 = delete ID, 1 = keep the user_id
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
; user_id ;must be setup
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
delete_user_id proc
with data
sta id_flag ;used to determine if I should delete the user id
ldy #$0002
lda [user_id_ptr],y ;get the ExpressLoad handle
tax
iny
iny
lda [User_id_ptr],y
tay
bne @deallocate
tax
beq @no_handle
@deallocate
phy
phx
jsr clear_handles ;clear local copy of handle
ldx #$1002 ;dispose handle
jsl $e10000 ;its gone
@no_handle
lda [user_id_ptr] ;get the user_id
beq @zero_and_exit
pha ;ID to nuke
ldx #$1102 ;do a dispose all please
jsl $e10000
ldx id_flag ;should we nuke the ID?
bne @zero_and_exit ;no...
lda [user_id_ptr] ;get the user_id
pha ;ID to nuke
ldx #$2103 ;delete ID
jsl $e10000
@zero_and_exit
ldy #$0002
lda #$0000
sta [user_id_ptr]
sta [user_id_ptr],y
iny
iny
sta [user_id_ptr],y ;remove everything
stz ExpressHandle ;indicate that we no longer have the load file
stz ExpressHandle+2
clc
rts
endp
eject
;====================================================================================================
;purge_user_id: This routine will mark an application as purgable
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
; user_id ;must be setup
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
purge_user_id proc
with data
lda [user_id_ptr] ;get the user_id
beq @exit
pha
ldx #$1302 ;Purge all
jsl $e10000
@exit
rts
endp
eject
;====================================================================================================
;remove_segment: This routine will deallocate all memory associated with a user ID.
;
;Input: A = And Mask for flags field
; X = Compare Value
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
; ExpressHandle
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
remove_segment proc
with data
sta temp_word
stx search_kind
jsr make_HET_ptr
lda [HET_ptr] ;get the number of entries in table
inc a ;start from the last segment
inc a
tax
@search_loop
txa ;pass in the segment number
beq @end_remove ;sorry there is no segment
phx
jsr setup_seg_ptrs ;we are now in business
ldy #flags_offset
lda [HET_entry_ptr],y
and temp_word ;AND off user requested bits
cmp search_kind ;see if we have a match
bne @skip_it
jsr do_operation
@skip_it
plx
dex ;back off by one and try again
cpx #$0001
bne @search_loop
@end_remove
clc
rts
do_operation
lda #$0000 ;zero the status word
sta [HET_entry_ptr],y
ldy #handle_offset ;lets dispose of the handle please
lda [HET_entry_ptr],y
tax
lda #$0000
sta [HET_entry_ptr],y
iny
iny
lda [HET_entry_ptr],y ;get the high word
pha
lda #$000
sta [HET_entry_ptr],y
phx ;push the low word
jsr clear_handles ;clear local copy of handle
ldx #$1002 ;dispose handle
jsl $E10000
rts
endp
eject
;====================================================================================================
;find_user_id: This routine will find a user_id in the User_ID_Table
;
;Input: A = user_id ;ID from the caller
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = low word address of entry
; Y = high word address of entry
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
find_user_id proc
with data
tax
bne @use_input
lda User_ID ;use the global ID
@use_input
sta search_kind
sta User_ID ;update the global User ID
sta AppID
ldy #$0002
lda [user_id_handle]
sta user_id_ptr
lda [user_id_handle],y
sta user_id_ptr+2
@loop
jsr find_id
bcc @found_it
ldy #$0002 ;get the next link
lda [user_id_ptr]
tax
lda [user_id_ptr],y
tay
bne @keep_going
txa
bne @keep_going
sec
rts ;sorry ID not found
@keep_going
stx temp_handle
stx curr_id_handle ;the current handle table
sty temp_handle+2
sty curr_id_handle+2
ldy #$00002
lda [temp_handle]
sta user_id_ptr
lda [temp_handle],y
sta user_id_ptr+2
bra @loop
@found_it
ldx temp_ptr ;return pointer to the entry
ldy temp_ptr+2
clc
rts
find_id
ldy #id_entry_size ;start at the first available spot
ldx #id_entry_cnt ;number of entries in a table
@search_loop
lda [user_id_ptr],y ;is this the one
cmp search_kind
beq @its_the_one
clc
tya
adc #id_entry_size
tay
dex
bpl @search_loop
sec
rts
@its_the_one
clc ;build a pointer to the entry
tya
adc user_id_ptr
sta temp_ptr
sta user_id_ptr
lda #$000
adc user_id_ptr+2
sta temp_ptr+2
sta user_id_ptr+2
clc
rts
endp
eject
;====================================================================================================
;path_to_user_id: This routine will find a user_id in the User_ID_Table given a pathname
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; Full_Blown ;Path that we need to find
;
;Output: A = User ID
; X = undefined
; Y =undefined
; P = nvmxdizc
; ..000..1 = not found
; b = k
;
;
;====================================================================================================
longa on
longi on
path_to_user_id proc
with data
ldy #$0002
lda [user_id_handle]
sta user_id_ptr
lda [user_id_handle],y
sta user_id_ptr+2
@loop
jsr find_id
bcc @found_it ;we have found the complete path!
ldy #$0002 ;get the next link
lda [user_id_ptr]
tax
lda [user_id_ptr],y
tay
bne @keep_going
txa
bne @keep_going
sec
rts ;sorry ID not found
@keep_going
stx temp_handle
sty temp_handle+2
ldy #$00002
lda [temp_handle]
sta user_id_ptr
lda [temp_handle],y
sta user_id_ptr+2
bra @loop
@found_it
rts ;A = User_ID
find_id
ldy #id_entry_size ;start at the first available spot
ldx #id_entry_cnt ;number of entries in a table
@search_loop
lda [user_id_ptr],y ;is this the one
sta search_kind ;save the User ID
beq @empty_slot
phy
phx
jsr check_name ;is this the one
plx
ply
bcc @its_the_one
@empty_slot clc
tya
adc #id_entry_size
tay
dex
bpl @search_loop
sec
sep #$40 ;no partial match!!!
@its_the_one
rts
check_name
iny
iny ;get the handle
lda [user_id_ptr],y
sta ExpressHandle
tax
iny
iny
lda [user_id_ptr],y
sta ExpressHandle+2 ;Handle to the ExpressLoad segment
tay
jsr Merge_path ;build a complete pathname
jsr compare_paths ;is this the one?
lda search_kind
rts ;carry set or cleared from the compare routine
endp
eject
;====================================================================================================
;find_seg_handle: This routine will find a segment by handle
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; seg_handle ;must be setup
;
;Output: A = User ID
; X = undefined
; Y =undefined
; P = nvmxdizc
; ..000..1 = not found
; b = k
;
;
;====================================================================================================
longa on
longi on
find_seg_handle proc
with data
ldy #$0002
lda [user_id_handle]
sta user_id_ptr
lda [user_id_handle],y
sta user_id_ptr+2
@loop
jsr find_id
bcc @found_it
ldy #$0002 ;get the next link
lda [user_id_ptr]
tax
lda [user_id_ptr],y
tay
bne @keep_going
txa
bne @keep_going
sec
rts ;sorry ID not found
@keep_going
stx temp_handle
sty temp_handle+2
ldy #$00002
lda [temp_handle]
sta user_id_ptr
lda [temp_handle],y
sta user_id_ptr+2
bra @loop
@found_it
rts ;A = User_ID
find_id
ldy #id_entry_size ;start at the first available spot
ldx #id_entry_cnt ;number of entries in a table
@search_loop
lda [user_id_ptr],y ;is this the one
sta User_ID
beq @empty_slot
phy
phx
jsr check_handle ;is this the one
plx
ply
bcc @its_the_one
@empty_slot
clc
tya
adc #id_entry_size
tay
dex
bpl @search_loop
sec
@its_the_one
sta search_seg ;save the segment number
rts
check_handle
iny
iny ;get the handle
lda [user_id_ptr],y
sta ExpressHandle
tax
iny
iny
lda [user_id_ptr],y
sta ExpressHandle+2 ;Handle to the ExpressLoad segment
jsr walk_ExpressSeg ;look at all the handles in the ExpressLoad segment
rts ;found the handle
walk_expressSeg
jsr make_HET_ptr ;make a pointer to the Header Entry Table
lda [HET_ptr] ;get the number of entries in table
inc a ;start from the last segment
inc a
tax
@search_loop
txa ;pass in the segment number
beq @end_handle ;sorry there is no segment by this name
phx
jsr setup_seg_ptrs ;we are now in business
ldy #handle_offset ;see if this is a jump segment
lda [HET_Entry_ptr],y
cmp seg_handle
bne @not_handle
iny
iny
lda [HET_entry_ptr],y
cmp seg_handle+2
bne @not_handle
pla ;this is the segment number
clc
rts
@not_handle
plx
dex ;back off by one and try again
cpx #$0001
bne @search_loop
@end_handle
sec
rts
endp
eject
;====================================================================================================
;Get_ExpLoad_ID: This routine will request an ID from the ID manager.
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
; ExpLoad_ID ;contains our ID
;
;====================================================================================================
longa on
longi on
get_ExpLoad_ID proc
with data
lda #$7050 ;This is ExpressLoad ID
sta ExpLoad_ID
rts
endp
include 'ProcReloc.DataBankChanged'
eject
;====================================================================================================
;read_less_64K: This routine will read data from the input file. It is limited to $FFFF bytes
;
;
;Input: A = request count
; X = buffer_ptr low
; Y = buffer_ptr high
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
read_less_64k proc
stz read_list.cnt+2
sta read_list.cnt
export read_wBuf_ptr
read_wBuf_ptr
stx read_list.ptr
sty read_list.ptr+2
jsr lock_handles
jsl $e100a8
dc.w $2012 ;class 1 read call
dc.l read_list
jsr unlock_handles
bcs @exit
lda read_list.ret_cnt
adc local_mark ;bump the local mark please
sta local_mark
lda read_list.ret_cnt+2
adc local_mark+2
sta local_mark+2
lda #$0000
clc
@exit
rts
endp
eject
;====================================================================================================
;get_mark: This routine will return the current file position
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = Mark Low
; Y = Mark High
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
get_mark proc
jsr lock_handles
jsl $e100a8
dc.w $2017
dc.l get_mark_list
jsr unlock_handles
bcc @got_mark
rts
@got_mark
ldx get_mark_list.pos
ldy get_mark_list.pos+2
rts
endp
eject
;====================================================================================================
;set_mark: This routine will set the current file position
;
;
;Input: A = base
; X = displacement low
; Y = displacement high
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = error if carry set
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
set_mark proc
lda #absolute
sta set_mark_list.base
stx set_mark_list.disp
sty set_mark_list.disp+2
cpx local_mark ;lets see if we are already at the mark
bne @do_mark
cpy local_mark+2
bne @do_mark
clc
lda #$0000 ;we are already at the mark
rts ;return with no error
@do_mark
jsr lock_handles
jsl $e100a8
dc.w $2016 ;class 1 set mark call
dc.l set_mark_list
jsr unlock_handles
bcs @exit
lda set_mark_list.disp
sta local_mark ;reset our mark please
lda set_mark_list.disp+2
sta local_mark+2
@exit
rts
endp
eject
;====================================================================================================
;check_express_seg: This routine will determine if this is an expressload file
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; Expanded_name ;must be setup
; vol_size
; partial_size
; partial_offset ;all must be setup
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
check_express_seg proc
with data
; jsr get_mark ;save the current file position
ldx #header_buf
ldy #^header_buf
lda #$0047 ;read in $47 byte
jsr read_less_64k ;read in less then 64K
bcc @no_error
rts
@no_error
lda read_list.ret_cnt ;is the segment > $47 bytes
cmp #$0047
beq @good_size
sec
rts ;return with error flag
@good_size
;
;I am removing the type check so the linker can produce a skip segment if it wishes
;
; lda header_buf.kind ;see if it is my kind
; cmp #Data_Kind+Dynamic
; bne sorry_not_express ;this cannot be it
lda header_buf.name_disp ;offset to the name
clc
adc #10 ;pass my Name
clc
adc #header_buf
sta temp_ptr
lda #^header_buf
sta temp_ptr+2 ;point to the name field
longa off
longi off
sep #$30
lda [temp_ptr] ;get the length of the name
cmp express_name ;is the length the same?
bne next_name ;cannot be the same
tay
@loop
lda [temp_ptr],y
cmp #'a' ;is this lower case
bcc @not_lower
cmp #'z'+1
bcs @not_lower
and #$DF ;convert to Upper case
@Not_lower
cmp express_name,y
bne sorry_not_express
dey
bne @loop ;keep checking
bra load_it
;
;Now look for "~ExpressLoad"
;
next_name
cmp tilda_name ;now check for "~ExpressLoad"
bne sorry_not_express
tay
@loop
lda [temp_ptr],y
cmp #'a' ;is this lower case
bcc @not_lower
cmp #'z'+1
bcs @not_lower
and #$DF ;convert to Upper case
@Not_lower
cmp tilda_name,y
bne sorry_not_express
dey
bne @loop ;keep checking
bra load_it
sorry_not_express
longa on
longi on
rep #$30
sec
rts
load_it
rep #$30
clc
rts
endp
eject
;====================================================================================================
;find_segment: This routine will search for segments in the HET table
;
;
;Input: A = Kind to search for
; X = AND mask for kind field. If equal after AND the kind was a match
; Y = AND mask for flags field. If equal after AND then search succeeds
; P = nvmxdizc
; ..000...
; b = k
;
; HET_ptr ;must be setup!
;
;Output: A = Segment number in file
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = not found
; b = k
;
;
;====================================================================================================
longa on
longi on
find_Segment proc
with data
sta search_kind
stx kind_mask
sty flags_mask
ldx #$0000 ;start search from the beginning
@loop
txa
asl a
asl a
asl a ;times eight for HET
inc a
inc a ;pass the count word
tay
clc
adc HET_ptr
sta HET_Entry_ptr ;build a pointer to the HET entry
lda #$0000
adc HET_ptr+2
sta HET_entry_ptr+2
clc
lda [HET_entry_ptr] ;get the relative offset to segment
adc HET_entry_ptr
sta seg_header_ptr ;point to the segment
lda #$0000
adc HET_entry_ptr+2
sta seg_header_ptr+2
iny
iny
lda [HET_ptr],y ;check the flags mask
and flags_mask
bne @check_next ;sorry
ldy #seg_kind_offset ;lets check the kind please
lda [seg_header_ptr],y
and kind_mask
cmp search_kind ;is this it
bne @check_next ;sorry false alarm
txa
inc a ;convert 0 thru n to 1 thru n
clc
adc ExpressSeg_Pos ;account for Express Segments position
sta loaded_seg_num
clc
rts ;return the segment
@check_next
inx
txa
cmp [HET_ptr] ;are we done
beq @loop ;we have one more to do
bcc @loop
rts ;return with the carry set
endp
eject
;====================================================================================================
;chk_dynamic_seg: See if there are any dynamic segments in the file.
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; ExpressHandle ;handle to the express segment.
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = no seg.
; b = k
;
;
;====================================================================================================
longa on
longi on
chk_dynamic_seg proc
with data
jsr make_HET_ptr ;setup pointer to the HETable
lda #Dynamic ;Compare to Dynamic BIT
ldx #Dynamic ;And Mask (Only Dynamic Bit is important)
ldy #unloaded_state ;only unloaded segments please
jsr find_segment ;do the search
rts
endp
eject
;====================================================================================================
;Save_Ref_Num: This routine will save the files reference number if the file contains any dynamic
; segments. We do this so the file can remain open while the program is running.
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; open_list.ref_num ;reference number for the current file.
; ExpressHandle ;handle to the express segment.
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
Save_Ref_Num proc
with data
lda open_list.file_type
cmp #app_type ;only leave the file open if type = Application
bne @skip_dynamic_chk ;don't leave the file open
jsr chk_dynamic_seg
bcc @save_the_num ;There is a dynamic segment.
@skip_dynamic_chk
clc
rts
@save_the_num
ldy #$0002
clc
lda [ExpressHandle]
adc #extra_header ;load ExpressSegment past Extra Header
sta temp_ptr ;temp now points the link field
lda [ExpressHandle],y
adc #$0000
sta temp_ptr+2
lda open_list.ref_num ;save the file reference number since the file
sta [temp_ptr] ; contains Dynamic Segments.
rts
endp
eject
;====================================================================================================
;get_express_seg: This routine will locate and read in the ExpressLoad Header
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; Expanded_name ;must be setup
; vol_size
; partial_size
; partial_offset ;all must be setup
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
get_express_seg proc
with data
clc
lda header_buf.code_disp
adc #$0005 ;Add in LConst over header
clc
adc get_mark_list.pos
tax
lda #$000
adc get_mark_list.pos+2
tay
lda #absolute ;set the mark to the LConst please
jsr set_mark
bcc @its_there
rts ;return the error
@its_there
ldx header_buf.image ;get the size of the disk image please
stx read_list.cnt
ldy header_buf.image+2
sty read_list.cnt+2
;
;Now we need to add in the pathname overhead + link field overhead
;
lda vol_size ;see if the volume name is larger then 40 characters
cmp #max_vol+1
bcc @vol_ok
lda #$0001 ;error
rts
@vol_ok
clc
lda #max_vol ;add in volume buffer size
adc partial_size ;add in partial pathname size
clc
adc #extra_header+2 ;add in extra header size + two for vol and partial
clc ; length bytes.
adc header_buf.image ;add in ExpressLoad segment size
tax ;save request count low
lda #$0000
adc header_buf.image+2
tay ;save request count high
jsr alloc_ExpLoad ;get enough memory to hold segment
bcc @have_mem
rts
@have_mem
stx ExpressHandle ;handle to Express Segment
stx temp_handle
sty ExpressHandle+2
sty temp_handle+2
ldy #$0002
lda [temp_handle] ;clear the link field etc.
sta base_ptr
lda [temp_handle],y
sta base_ptr+2
ldy #extra_header
lda #$0000 ;clear the buffer
@clr_loop
sta [base_ptr],y
dey
bpl @clr_loop
;
;Lets go ahead and add the Express Segment into the User ID table
;
lda user_id ;this is the ID to use
jsr add_user_id ;temp_ptr setup by Add_User_ID
bcc @id_added
rts ;return the error
@id_added
ldy #$0002 ;save the Handle to the ExpressSegment
lda ExpressHandle
sta [temp_ptr],y
iny
iny
lda ExpressHandle+2
sta [temp_ptr],y
jsr make_het_ptr ;temp_ptr will point to the link field (HET_ptr-4)
jsr read_wBuf_ptr ;make the read call please
bcc @I_love_it
rts
@I_love_it
ldx temp_ptr ;pass in pointer to ExpressSegment link field
ldy temp_ptr+2
jsr store_pathname ;store the pathname in the ExpressLoad segment
jsr save_ref_num ;save the files reference number.
clc
rts
eject
;====================================================================================================
;
;This routine will add in the pathname stored in Expanded_name to the ExpressLoad segment.
;
;Input: A = undefined
; X = Points to the ExpressLoad segment link field
; Y = Points to the ExpressLoad segment link field
; P = nvmxdizc
; ..000...
; b = k
;
; Expanded_name ;must be setup
; base_ptr
; vol_size
; partial_size
; partial_offset ;all must be setup
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;Uses:
;
;====================================================================================================
store_pathname
clc
txa
adc read_list.cnt ;build a pointer to the Volume Name Buffer
sta super_ptr ;another temp pointer
tya
adc read_list.cnt+2
sta super_ptr+2 ;super_ptr now points past the ExpressLoad segment
;
;This entry point is used by rename call
;
export store_new_name
store_new_name
ldx #$0001
ldy #$0001
lda vol_size ;store the volume size (1 Byte)
sta [super_ptr]
@store_vol_loop
lda Expanded_name.name,x
sta [super_ptr],y
iny
inx
cpx vol_size ;see if we are done
bcc @store_vol_loop ;keep moving the name
ldy #seg_vol_offset ;index to offset field (relative offset is based
sec ;from the beginning of the segment)
lda super_ptr
sbc base_ptr
sta [base_ptr],y
iny
iny
clc
adc #max_vol ;offset to partial
sta [base_ptr],y ;save partial offset
clc
lda super_ptr
adc #max_vol
sta super_ptr ;build a pointer to the partial buffer
lda super_ptr+2
adc #$0000
sta super_ptr+2
ldx partial_offset ;start of the partial name
ldy #$0001
lda partial_size ;store the volume size (1 Byte)
sta [super_ptr]
longa off
sep #$20 ;8 bit mode
@store_part_loop
lda Expanded_name.name,x
sta [super_ptr],y
inx
iny
cpy partial_size ;see if we are done
bcc @store_part_loop ;keep moving the name
beq @store_part_loop
longa on
rep #$20 ;16 bit mode
rts
endp
eject
;====================================================================================================
;close_dynamic_file: This routine will close the load file if the file is still open
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; ExpressHandle
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error if any
; b = k
;
;
;====================================================================================================
longa on
longi on
close_dynamic_file proc
with data
import close_load_file
pei temp_ptr ;save temp pointer please
pei temp_ptr+2
ldy #$0002
clc
lda [ExpressHandle]
adc #extra_header ;load ExpressSegment past Extra Header
sta temp_ptr ;temp now points the link field
lda [ExpressHandle],y
adc #$0000
sta temp_ptr+2
lda [temp_ptr] ;see if there is reference number.
bne @do_close ;yes we must close the file
bra @exit ;accumulator already 0 here!
@do_close
sta open_list.ref_num ;setup the reference number for closing
lda #$0000 ;zero the reference number in ExpressSegment
sta [temp_ptr]
jsr lock_handles
jsl $e100a8 ;get the current system preferences
dc.w $200F
dc.l preference_list
;
;Save the current user's preference please
;
lda preference_list.sys_prefs
sta preference_list.users_prefs
;
;Now ask the operating system to put up a mount dialog when I ask for a disk
;
lda #$C000 ;ask the OS to put up the mount dialog
sta preference_list.sys_prefs
jsl $e100a8
dc.w $200C ;set the system preference
dc.l preference_list
jsr unlock_handles
jsr close_load_file ;close the file please
lda preference_list.users_prefs
sta preference_list.sys_prefs
jsr lock_handles
jsl $e100a8
dc.w $200C ;restore the caller's system preference
dc.l preference_list
jsr unlock_handles
@exit
plx
stx temp_ptr+2
plx
stx temp_ptr
cmp #$0001
rts ;exit with error if any
endp
eject
;====================================================================================================
;close_load_file: This routine will close the load file and restore the caller's sys_prefs
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error if any
; b = k
;
;
;====================================================================================================
longa on
longi on
close_load_file proc
with data
lda ExpressHandle ;see if there is an ExpressSegment for this file.
ora ExpressHandle+2
beq @do_close ;There is no Segment associated with the file.
ldy #$0002
clc
lda [ExpressHandle]
adc #extra_header ;load ExpressSegment past Extra Header
sta temp_ptr ;temp now points the reference number field
lda [ExpressHandle],y
adc #$0000
sta temp_ptr+2
lda [temp_ptr] ;see if there is reference number.
beq @do_close ;there is no reference number with the segment so
;go ahead and close the file they want.
lda #$0000
clc
bra @do_preference ;No error and I am not going to close the file
;since the file contains Dynamic Segments I will
;leave the file open.
@do_close
jsr lock_handles
jsl $e100a8
dc.w $14 ;GS/OS close command
dc.l open_list.ref_num
jsr unlock_handles
;
;Save the error code and statue from the close call while I restore the user's system preferences
;
@do_preference
pha
php
stz file_open ;file is now closed
jsr reset_local_mark ;our local mark is invalid
if 0 then
lda preference_list.users_prefs
sta preference_list.sys_prefs
jsr lock_handles
jsl $e100a8
dc.w $200C ;restore the caller's system preference
dc.l preference_list
jsr unlock_handles
endif
plp
pla ;restore the close error if any
rts
endp
eject
;====================================================================================================
;Open_load_file: This routine will open the load file and verify the storage type
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; pathname pointer must be setup
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
open_load_file proc
with data
;
;Now before I open the file let me see If I have a Reference number for it already.
;
lda ExpressHandle ;see if there is an ExpressSegment for this file.
ora ExpressHandle+2
beq @do_open ;There is no Segment associated with the file.
;
;There is an Active Segment so lets see if we have the reference number
;
ldy #$0002
clc
lda [ExpressHandle]
adc #extra_header ;load ExpressSegment past Extra Header
sta temp_ptr ;temp now points the reference number field
lda [ExpressHandle],y
adc #$0000
sta temp_ptr+2
lda [temp_ptr] ;see if there is reference number.
beq @do_open ;There is no reference number so lets open the file
sta open_list.ref_num ;save the reference number
lda #app_type ;setup the file type also
sta open_list.file_type
bra @opened ;say that we already opened the file.
@do_open
jsr lock_handles
jsl $e100a8 ;get the current system preferences
dc.w $200F
dc.l preference_list
;
;Save the current user's preference please
;
lda preference_list.sys_prefs
sta preference_list.users_prefs
;
;Now ask the operating system to put up a mount dialog when I ask for a disk
;
lda #$C000 ;ask the OS to put up the mount dialog
sta preference_list.sys_prefs
jsl $e100a8
dc.w $200C ;set the system preference
dc.l preference_list
jsl $e100a8 ;do a get level call to get the current level
dc.w $201B
dc.l level_list ;get the level
lda level_list.curr_level
sta level_list.hold_level ;save the current level
lda #my_level
sta level_list.curr_level
jsl $e100a8 ;do a get level call to get the current level
dc.w $201A ;set the current level
dc.l level_list ;get the level
jsl $e100a8 ;call GS/OS
dc.w $2010 ;class 1 open call
dc.l open_list
pha
php
lda level_list.hold_level ;restore the saved level
sta level_list.curr_level
jsl $e100a8 ;do a get level call to get the current level
dc.w $201A ;set the current level
dc.l level_list ;get the level
lda preference_list.users_prefs
sta preference_list.sys_prefs
jsl $e100a8
dc.w $200C ;restore the caller's system preference
dc.l preference_list
jsr unlock_handles
plp
pla
bcs @oops ;return the error to the caller
@opened
stz local_mark
stz local_mark+2 ;we are at the beginning of the file.
lda open_list.ref_num ;setup the reference number
sta read_list.ref_num
sta get_mark_list.ref_num
sta set_mark_list.ref_num
sta eof_list.ref_num
lda #$0001 ;indicate that the file is open
sta file_open
lda open_list.file_type
cmp #app_type
bcc @no_way
cmp #$00BD+1 ;max file type that we support
bcc @chk_length
cmp #$C7 ;is it a CDev file?
bne @no_way ;nope, can't be a load file
@chk_length
jsr lock_handles ;lock the handles around the OS call
jsl $E100A8 ;Call GS/OS
dc.w $2019 ; GetEOF
dc.l eof_list
jsr unlock_handles
bcs @oops
lda eof_list.eof ;is there anything in the file?
ora eof_list.eof+2
bne @oops ;actually no error
@no_way
lda #not_load_file ;Incompatible file format
sec
@oops
rts ;return error
endp
eject
;====================================================================================================
;conv_attributes: This routine will convert the attributes in the segment header to
; memory manager attributes
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; HET_Entry_ptr ;must be setup
; Seg_header_ptr ;must be setup
;
;Output: A = Memory Manager Attributes
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
mm_attr_tbl record
;Attr_Locked 1 = segment is locked when allocated
;Attr_fixed 1 = segment can't move while it is in memory
;attr_no_cross 1 = segment may not cross a bank boundary
;attr_no_spec 1 = segment may not use special memory
;attr_page 1 = segment will be page aligned
;attr_addr 1 = segment will remain at fixed address
;attr_bank 1 = segment must remain in fixed bank
dc.w attr_locked+attr_fixed+attr_no_cross
dc.w attr_locked+attr_fixed+attr_no_cross+attr_bank
dc.w attr_locked+attr_fixed+attr_no_cross+attr_no_spec
dc.w attr_locked+attr_fixed+attr_no_cross+attr_no_spec+attr_bank
dc.w attr_locked+attr_no_cross
dc.w attr_locked+attr_no_cross+attr_bank
dc.w attr_locked+attr_no_cross+attr_no_spec
dc.w attr_locked+attr_no_cross+attr_no_spec+attr_bank
dc.w attr_locked+attr_fixed
dc.w attr_locked+attr_fixed+attr_bank
dc.w attr_locked+attr_fixed+attr_no_spec
dc.w attr_locked+attr_fixed+attr_no_spec+attr_bank
dc.w attr_locked
dc.w attr_locked+attr_bank
dc.w attr_locked+attr_no_spec
dc.w attr_locked+attr_no_spec+attr_bank
endr
longa on
longi on
conv_attributes proc
with data
ldy #seg_kind_offset ;get the segment kind
lda [seg_header_ptr],y
sta seg_kind ;save the word for later
xba ;get the segment attributes
lsr a
lsr a
lsr a ;move abs. bank, special mem, and pos. independent
and #$0007 ;clear other garbage
sta mm_attr
;
;If the bank size = $10000 then we must set the no_cross bit in the attribute
;
ldx #$0008 ;default is can cross
ldy #bank_size_offset ;get the bank size please
lda [seg_header_ptr],y
bne @can_cross ;it must be able to cross
iny
iny
lda [seg_header_ptr],y ;get the high please
beq @can_cross ;we can cross bank boundaries
ldx #$0000
;
;now we get the memory manager attributes
;
; We have now handled the following bits:
;
; (1) absolute Bank
; (2) special Memory
; (3) position independent
; (4) bank crossing
;
@can_cross
txa
ora mm_attr
asl a
tax
lda mm_attr_tbl,x ;get the correct atributes for memory manager
;
;We still need to handle the following things:
;
; (1) Purge Level (3 for dynamics)
; (2) Alignment (page and Bank)
; (3) Org (fixed address)
ldx seg_kind
bpl @its_static ;this is a static segment
ora #purge_level_3 ;set the purge level to three for dynamics
@its_static
sta mm_attr
ldx #attr_Page ;default is page aligned
ldy #align_offset ;offset to the alignment field
lda [seg_header_ptr],y
beq @align_high
cmp #257
bcc @set_aligned ;align to a page boundary
ldx #attr_bank_align ;force bank alignment
bra @set_aligned
@align_high
iny
iny
ldx #attr_bank_align ;force bank alignment
lda [seg_header_ptr],y
beq @do_org ;there is no alignment
@set_aligned
txa
tsb mm_attr ;add in the alignment bit
@do_org
ldy #org_offset ;offset to segment org
lda [seg_header_ptr],y
sta org_address
iny
iny
lda [seg_header_ptr],y
sta org_address+2
ora org_address
beq @no_org
lda org_address ;if the low byte is non-zero then fixed attr = true
bne @do_fixed_addr
lda seg_kind ;see if this is a absolute bank segment
and #kind_abs_bank
bne @no_org ;This is absolute bank but not fixed address
@do_fixed_addr
lda #attr_addr ;block must remain at fixed addr
tsb mm_attr
@no_org
lda seg_kind ;see if this is an absolute Bank only
tay
and #kind_bank_bit ;see if this segment is aligned in any bank
beq @not_aligned_in_bank
lda mm_attr
ora #attr_align_in_bank ;segment is aligned within the bank
sta mm_attr
;
;Now we need to handle the direct page / stack segment
;
@not_aligned_in_bank
tya
bit #kind_abs_bank ;absolute bank segment?
bne @is_abs ;yes, allow special memory
and #kind_only ;clear attributes
cmp #dp_seg_type ;DP/Stack segment?
bne @no_stack ;no, conditionalize special memory bit
lda mm_attr
ora #attr_page+attr_bank ;fixed bank and page aligned
sta mm_attr
rts ;skip special memory flag
@is_abs
lda mm_attr ;must return attributes in accumulator
and #�attr_no_spec
sta mm_attr
rts
@no_stack
lda mm_attr
ldx spec_mem_flag ;check the special memory flag
beq @skip_spec
ora #attr_no_spec ;sorry bud no special memory for you
sta mm_attr
@skip_spec
rts
endp
eject
;====================================================================================================
;reset_jmp_tables: This routine will mark all jump table segments as unloaded for a given
; user id
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; ExpressHandle ;must be setup
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
reset_jmp_tables proc
with data
lda [HET_ptr] ;get the number of entries in table
inc a ;start from the last segment
inc a
tax
@search_loop
txa ;pass in the segment number
beq @end_reset ;sorry there is no segment by this name
phx
jsr setup_seg_ptrs ;we are now in business
ldy #flags_offset ;see if this is a jump segment
lda [HET_Entry_ptr],y
and #jmp_type
beq @not_jump
jsr clr_table ;clear this segment
@not_jump
plx
dex ;back off by one and try again
cpx #$0001
bne @search_loop
@end_reset
clc
rts
clr_table
ldy #handle_offset
lda [HET_Entry_ptr],y
sta temp_handle
iny
iny
lda [HET_Entry_ptr],y
sta temp_handle+2
ldy #$0002 ;point to the first entry in table
clc
lda [temp_handle]
adc #seg_jmp_start
sta temp_ptr
lda [temp_handle],y
adc #$0000
sta temp_ptr+2
@loop
ldy #$0002 ;see if we are done
lda [temp_ptr],y
beq @done
lda user_id ;see if this is the user ID
cmp [temp_ptr]
bne @next_entry
ldy #$000A ;index to the JSL instruction
lda jump_load_instr ;store the Jump Load Instruction
sta [temp_ptr],y
iny
iny
lda jump_load_instr+2
sta [temp_ptr],y
@next_entry
clc
lda temp_ptr
adc #jmp_entry_size ;size of one entry
sta temp_ptr
lda temp_ptr+2
adc #$0000
sta temp_ptr+2
bra @loop
@done
rts
endp
eject
;====================================================================================================
;Make_Purgable: This routine will make segment purgable and unlocked
;
;
;Input: A = segment_number
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; ExpressHandle ;must be setup
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
Make_Purgable proc
with data
sta search_seg ;segment we need to nuke
jsr make_HET_ptr
lda search_seg
jsr setup_seg_ptrs ;point to the entry please
ldy #flags_offset ;see of it is loaded
lda [HET_entry_ptr],y
bmi @do_it
@no_seg lda #seg_not_found ;seg_not_found
sec
rts
@do_it
ldy #handle_offset ;lets get the handle
lda [HET_entry_ptr],y
tax
iny
iny
lda [HET_entry_ptr],y
tay
bne @have_handle
txa
beq @no_Seg
@have_handle
pea $0003 ;make it purgable
phy
phx ;push the handle
stx temp_handle
sty temp_handle+2 ;handle to the segment
ldy #$0004 ;lets unlock this puppy
lda [temp_handle],y
and #$7FFF
sta [temp_handle],y
ldy #flags_offset ;mark this segment as Purgable
lda [HET_entry_ptr],y
ora #$0001
sta [HET_Entry_ptr],y ;segment is now marked purgable
jsr reset_jmp_tables ;go and reset the jump tables for this ID
ldx #$2402 ;SetPurgeLevel
jsl $e10000
rts ;return any error
endp
eject
;====================================================================================================
;purge_all_dyn: This routine will mark all dynamic segments as purgable
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; ExpressHandle ;must be setup
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
purge_all_dyn proc
with data
lda [HET_ptr] ;get the number of entries in table
inc a ;start from the last segment
inc a
tax
@search_loop
txa ;pass in the segment number
beq @end_purge ;sorry there is no segment
phx
jsr setup_seg_ptrs ;we are now in business
ldy #seg_kind_offset ;lets check the kind please
lda [seg_header_ptr],y
bpl @skip_it ;skip the segment if it is not dynamic
ldy #flags_offset ;mark this segment as Purgable
lda [HET_entry_ptr],y
bpl @skip_it ;the segment is already unloaded
lda 1,s ;get the seg number
jsr make_purgable
@skip_it
plx
dex ;back off by one and try again
cpx #$0001
bne @search_loop
@end_purge
clc
rts
endp
eject
;====================================================================================================
;mark_all_purgable: This routine will mark all segments as purgable
;
;
;Input: A =undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; ExpressHandle ;must be setup
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
mark_all_purgable proc
with data
lda [HET_ptr] ;get the number of entries in table
inc a ;start from the last segment
inc a
tax
@search_loop
txa ;pass in the segment number
beq @end_purge ;sorry there is no segment
phx
jsr setup_seg_ptrs ;we are now in business
lda 1,s ;get the seg number
jsr mark_purged
@skip_it
plx
dex ;back off by one and try again
cpx #$0001
bne @search_loop
@end_purge
;
; unlock all load segments
;
lda User_ID ;push the User ID
pha
ldx #$2302
jsl $e10000
; _HUnlockAll
;
; purge all other dynamic segments
;
lda User_ID ;push the User ID
pha
ldx #$1302
jsl $e10000
; _PurgeAll
;
; make all static segments purgeable
;
pea $0003 ;Purge Level
lda User_ID ;push the User ID
pha
ldx #$2502
jsl $e10000
; push #3 ;PurgeLevel
; push OUserID ;Owner
; _SetPurgeAll
clc
rts
mark_purged
sta search_seg ;segment we need to nuke
jsr make_HET_ptr
lda search_seg
jsr setup_seg_ptrs ;point to the entry please
ldy #flags_offset ;see of it is loaded
lda [HET_entry_ptr],y
bmi @do_it
@no_seg lda #seg_not_found ;seg_not_found
sec
rts
@do_it
ldy #handle_offset ;lets get the handle
lda [HET_entry_ptr],y
tax
iny
iny
lda [HET_entry_ptr],y
tay
bne @have_handle
txa
beq @no_Seg
@have_handle
stx temp_handle
sty temp_handle+2 ;handle to the segment
ldy #$0004 ;lets unlock this puppy
lda [temp_handle],y
and #$7FFF
sta [temp_handle],y
ldy #flags_offset ;mark this segment as Purgable
lda [HET_entry_ptr],y
ora #$0001
sta [HET_Entry_ptr],y ;segment is now marked purgable
jsr reset_jmp_tables ;go and reset the jump tables for this ID
clc
rts
endp
eject
;====================================================================================================
;lock_statics: This routine will check and see if all the static segments are loaded. It will
; also lock all the static segments that it finds. If any of the static segments
; have been purged the routine will error out with the carry set
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; ExpressHandle ;must be setup
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error all static segments are not loaded
; b = k
;
;
;====================================================================================================
longa on
longi on
lock_statics proc
with data
stz temp_word ;If zero on exit then there were no static segments
jsr make_HET_ptr ;convert ExpressHandle into pointers
lda [HET_ptr] ;get the number of entries in table
inc a ;start from the last segment
inc a
tax
@search_loop
txa ;pass in the segment number
beq @end_lock ;sorry there is no segment
phx
jsr setup_seg_ptrs ;setup pointer to the Header Entry
jsr lock_it
plx
bcs @error_out
dex ;back off by one and try again
cpx #$0001
bne @search_loop
@end_lock
lda temp_word ;see if we encountered any static segments
beq @error_out
clc
rts
@error_out
sec ;sorry there are no static segments or not all
;segments are still in memory
rts
lock_it
ldy #flags_offset ;first lets see if this is a static segment
lda [het_entry_ptr],y
and #stat_type
beq @not_static ;its not static so we do not care about the segment
sta temp_word ;this is used as a flag to indicate that there are
;static segments that can be locked
ldy #handle_offset ;now lets see if the segment has been purged
lda [het_entry_ptr],y
tax
iny
iny
lda [het_entry_ptr],y
tay
bne @handle_OK
txa
bne @handle_OK
sec
rts ;the handle is scewed up
@handle_OK
stx temp_handle
sty temp_handle+2
ldy #$0002
lda [temp_handle]
tax
lda [temp_handle],y ;get the address please
tay
bne @handle_valid
txa
bne @handle_valid ;the handle is still good
sec
rts
@handle_valid
ldy #$0004 ;now lets lock the handle please
lda [temp_handle],y
ora #$8000 ;set the lock bit
sta [temp_handle],y
pea #$0000 ;set the purge level to zero
pei temp_handle+2
pei temp_handle
ldx #$2402 ;SetPurge call to the memory manager
jsl $e10000 ;call the tool locator
rts ;carry is set based on the call.
@not_static
clc
rts
endp
eject
;====================================================================================================
;lock_segment: This routine will make segment purgable and locked
;
;
;Input: A = segment_number
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; ExpressHandle ;must be setup
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
lock_segment proc
with data
sta search_seg ;segment we need to lock
jsr make_HET_ptr
lda search_seg ;segment we need to lock
jsr setup_seg_ptrs ;point to the entry please
ldy #flags_offset ;see of it is loaded
lda [HET_entry_ptr],y
lsr a
bcs @do_it ;yep the segment is unlocked
clc
rts
@do_it
ldy #handle_offset ;lets get the handle
lda [HET_entry_ptr],y
tax
iny
iny
lda [HET_entry_ptr],y
tay
bne @have_handle
txa
beq @no_Seg
@have_handle
phy
phx ;push the handle
stx temp_handle
sty temp_handle+2 ;handle to the segment
ldy #$0002 ;deref the handle to see if it is nill
lda [temp_handle]
tax
lda [temp_handle],y
tay
bne @lock_it
txa
bne @lock_it
ldy #flags_offset ;mark segment as gone
lda #$0000
sta [HET_entry_ptr],y
ldy #handle_offset
sta [HET_entry_ptr],y
iny
iny
sta [HET_entry_ptr],y ;zero the handle also
jsr clear_handles ;clear local copy of handle
ldx #$1002 ;dispose handle
jsl $e10000
stz temp_handle
stz temp_handle+2 ;Temp Handle is not valid
@no_seg
lda #seg_not_found
sec
rts ;indicate segment is gone
@lock_it ldy #$0004 ;lets lock this puppy
lda [temp_handle],y
ora #$8000
sta [temp_handle],y
ldy #flags_offset ;mark this segment as locked
lda [HET_entry_ptr],y
and #$FFFE ;clear the Unlocked Bit
sta [HET_Entry_ptr],y ;segment is now marked purgable
plx
ply
clc ;indicate segment is safely locked down
rts
endp
eject
;====================================================================================================
;load_segment: This routine will load a segment into memory
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; HET_Entry_ptr ;must be setup
; Seg_header_ptr ;must be setup
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
load_segment proc
with data
stz reloc_handle
stz reloc_handle+2
ldy #reloc_dict_offset ;set handle to zero
lda #$000
sta [seg_header_ptr],y
iny
iny
sta [seg_header_ptr],y
jsr conv_attributes ;convert the attributes to something useful
;
;On exit conv_attributes sets A to memory manager Attributes
;
sta mem_attr
ldy #$0002
lda [seg_header_ptr]
tax
lda [seg_header_ptr],y
tay
lda #absolute
jsr set_mark
bcc @mark1_set
@oops rts ;return the error
@mark1_set
ldy #seg_size_offset ;now lets get the size of the segment
lda [seg_header_ptr],y
sta read_list.cnt
sta LConst_size
iny
iny
lda [seg_header_ptr],y ;get the high count
sta read_list.cnt+2
sta LConst_Size+2
;
;Now lets see if we already have memory. We will have memory if we are reloading a restart segment
;
ldy #handle_offset ;see if we already have the memory segment
lda [het_entry_ptr],y
tax
iny
iny
lda [het_entry_ptr],y
tay
bne @skip_alloc ;we already have the memory
txa
bne @skip_alloc ;this must be a restart call
lda seg_kind ;what kind of segment is it?
bit #kind_abs_bank ;absolute bank segment?
bne @just_allocate ;yes, use attributes as is
and #kind_only
cmp #dp_seg_type ;is it a DP segment?
beq @just_allocate ;yes, so we HAVE to allow special memory
lda mem_attr ;get the original attributes
pha ;save 'em
ora #attr_no_spec ;set the 'no-special-memory' bit
sta mem_attr
@try_again
ldx read_list.cnt
ldy read_list.cnt+2 ;load the number of bytes to allocate for the segment
jsr alloc_lconst_seg ;allocate the memory for the segment
bcs @had_error
pla ;restore original attributes
sta mem_attr
bra @skip_alloc ;all is fine, continue
@had_error
plx ;retrieve original attributes
tay ;save error code
lda mem_attr ;get the attributes we just used
and #$0008 ;did we allow special memory?
beq @oops2 ;yes, and still had a problem!
txa ;get the original attributes
and #$0008 ;did they allow special memory?
bne @oops2 ;no, don't override their wishes
stx mem_attr ;restore original attributes
phx ;back on stack
bra @try_again ;go back and try to allocate again
@oops2
tya ;restore error code
bra @oops ;and exit
@just_allocate
ldx read_list.cnt
ldy read_list.cnt+2 ;load the number of bytes to allocate for the segment
jsr alloc_lconst_seg ;allocate the memory for the segment
bcs @oops
@skip_alloc
stx temp_handle
stx seg_handle
sty temp_handle+2
sty seg_handle+2
ldy #handle_offset ;update the handle address in HET entry
txa
sta [HET_entry_ptr],y
lda temp_handle+2
iny
iny
sta [HET_entry_ptr],y
ldy #$0002 ;deref the handle please
lda [temp_handle]
sta base_ptr ;address of the image
tax
lda [temp_handle],y
sta base_ptr+2
tay
jsr read_wBuf_ptr ;read in the segment please
bcc @add_seg_offset
rts
@add_seg_offset
jsr add_segment_offset ;add seg offset to base_ptr return value in X&Y
entry load_reloc_dict
load_reloc_dict ;go ahead and load the relocation dictionary
;
;Now lets do the relocation dictionary
;
ldy #reloc_mark_offset
lda [seg_header_ptr],y
tax
iny
iny
lda [seg_header_ptr],y
tay
bne @data_avail
txa
beq @its_loaded
@data_avail
lda #absolute
jsr set_mark
bcc @mark2_set
rts ;return the error
@mark2_set
ldy #reloc_size_offset ;now lets get the size of the segment
clc
lda [seg_header_ptr],y
adc #$0001
sta read_list.cnt
tax
iny
iny
lda [seg_header_ptr],y ;get the high count
adc #$0000
sta read_list.cnt+2
tay
lda read_list.cnt ;check for a zero length relocation dictionary
dec a
ora read_list.cnt+2
beq @its_loaded
jsr alloc_mem ;allocate the memory for the segment
stx temp_handle
stx reloc_handle
sty temp_handle+2
sty reloc_handle+2
ldy #reloc_dict_offset ;save handle to relocation dictionary
lda temp_handle
sta [seg_header_ptr],y
iny
iny
lda temp_handle+2
sta [seg_header_ptr],y
ldy #$0002 ;deref the handle please
lda [temp_handle]
tax
lda [temp_handle],y
tay
jsr read_wBuf_ptr ;read in the segment please
bcc @its_loaded
rts
@its_loaded
ldy #flags_offset
lda [het_entry_ptr],y
ora #$8000 ;mark segment loaded
sta [het_entry_ptr],y
lda seg_kind
and #kind_only ;lets see if this is a jump table segment
cmp #jmp_tbl_seg
bne @not_jump
jsr patch_jmp_tbl ;we need to setup the jump table entries
ldy #flags_offset ;mark segment as a Jump Segment
lda [HET_Entry_ptr],y
ora #jmp_type
sta [HET_entry_ptr],y
@not_jump
lda seg_kind ;see if the segment is dynamic or static
bmi @its_dynamic
ldy #flags_offset ;set the static bit please
lda [HET_Entry_ptr],y
ora #stat_type
sta [HET_entry_ptr],y
@its_dynamic
clc
rts
patch_jmp_tbl
clc
lda base_ptr ;please point to the first segment entry
adc #seg_jmp_start
sta temp_ptr
lda base_ptr+2
adc #$0000
sta temp_ptr+2 ;point to the first entry
@loop
ldy #$0002 ;see if we are done
lda [temp_ptr],y
beq @done
lda user_id ;save the ID please
sta [temp_ptr]
ldy #$000A ;index to the JSL instruction
lda jump_load_instr ;store the Jump Load Instruction
sta [temp_ptr],y
iny
iny
lda jump_load_instr+2
sta [temp_ptr],y
@next_entry
clc
lda temp_ptr
adc #jmp_entry_size ;size of one entry
sta temp_ptr
lda temp_ptr+2
adc #$0000
sta temp_ptr+2
bra @loop
@done
rts
Export add_segment_offset
add_segment_offset
ldy #seg_entry_offset ;See if this segment is the main segment
lda [seg_header_ptr],y
tax
iny
iny
lda [seg_header_ptr],y ;get the high word
tay
bne @Seg_offset_true ;we must override the first segment
txa
bne @Seg_offset_true
ldx #$0000
txy
@seg_offset_true
clc
txa ;get the low word of the offset
adc base_ptr
sta segment_entry
tya ;get the high word of the segment offset
adc base_ptr+2
sta segment_entry+2
rts
endp
eject
;====================================================================================================
;find_seg_name: This routine will locate a segment by name
;
;
;Input: A = undefined
; X = low word pointer to name
; Y = high word pointer to the name
; P = nvmxdizc
; ..000...
; b = k
;
; ExpressHandle ;must be setup
;
;Output: A = segment number if found
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = segment not found
; b = k
;
;
;====================================================================================================
longa on
longi on
find_Seg_name proc
with data
stx path_ptr
sty path_ptr+2 ;segment name pointer
jsr Make_HET_ptr ;setup pointer to the Header Entry Table
lda [HET_ptr] ;get the number of entries in table
inc a ;start from the last segment
inc a
tax
@search_loop
txa ;pass in the segment number
beq @not_found ;sorry there is no segment by this name
phx
jsr setup_seg_ptrs ;we are now in business
jsr compare_names ;see if this is the one
bcc @found_it ;we have located the correct segment
plx
dex ;back off by one and try again
cpx #$0001
bne @search_loop
@not_found
sec
rts ;segment is not in ExpressLoad header
@found_it pla ;return the segment number
clc
rts ;return to the caller with the good news
compare_names
clc
ldy #seg_name_disp ;get the displacement
lda [seg_header_ptr],y
adc #name_overhead
clc
adc seg_header_ptr
sta temp_ptr
lda #$0000
adc seg_header_ptr+2
sta temp_ptr+2 ;temp_ptr now points to the segment name (PString)
if 0 then
;
;Special note: For some reason, segment names may or may not have a length byte.
; This means that I have to make a best guest as to the type of string.
; If the first byte is less the $20 (Space) then I assume it is a length byte.
;
lda [temp_ptr]
and #$00ff
cmp #$0020
bcc @is_length ;there is a length byte
lda temp_ptr
bne @only_low
dec temp_ptr+2
@only_low dec a
sta temp_ptr ;point to one less then the name
longa off
longi off
sep #$30
ldy #$0001 ;start counting characters
@count_loop
lda [temp_ptr],y
cmp #' '
beq @save_size
iny
bra @count_loop
@save_size
dey
tya
sta [temp_ptr] ;opdate the length please
;
;now adjust the displacement so the string will always have a length
;
ldy #seg_name_disp ;get the displacement
lda [seg_header_ptr],y ;adjust the displacement for the next time
dec a
sta [seg_header_ptr],y
else
ldy #lablen_offset ;offset to label length field in header
lda [seg_header_ptr],y ;get the value
and #$00ff ;it's only a byte wide
beq @is_length ;length is first byte of string (Pascal style)
ldy temp_ptr ;else decrement the string pointer
bne @only_low
dec temp_ptr+2
@only_low
dec temp_ptr
sep #$20 ;8-bit store here
sta [temp_ptr] ;store the string length (from lablen)
rep #$20
endif
@is_length
longa off
longi off
sep #$30
lda [path_ptr] ;get the length of the input name
tay
cmp [temp_ptr]
bne @not_it ;the length is not the same
@compare_loop
lda [temp_ptr],y ;get the character
cmp #'a'
bcc @no_convert
cmp #'z'+1
bcs @no_convert
and #$DF ;convert to upper case
@no_convert
cmp [path_ptr],y ;see if the characters are the same
beq @check_next
sta temp_word ;save for compare
lda [path_ptr],y ;get char from callers area
cmp #'a'
bcc @not_it ;it cannot be the one
cmp #'z'+1
bcs @not_it
and #$DF ;convert to upper case
cmp temp_word
bne @not_it ;sorry wrong name
@check_next
dey
bne @compare_loop ;keep looking
rep #$30
clc
rts ;We have found the segment!
@not_it
rep #$30
sec
rts
endp
eject
;====================================================================================================
;save_dp_info: This routine will save the direct page address
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
save_dp_info proc
with data
lda segment_entry ;address of the stack direct page
sta stack_addr
lda LConst_size ;save the size please
sta stack_size
rts
endp
eject
;====================================================================================================
;load_statics: This routine will load all static segments
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; HET_ptr ;must be setup
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
load_statics proc
with data
tsx ;save the stack pointer
stx stack
stz starting_addr
stz starting_addr+2
stz stack_addr ;there is no stack
stz stack_size
static_loop
lda #any_kind ;lets find all static segments that are left
ldx #static_only ;don't look at other bits
ldy #unloaded_state ;skip loaded segments
jsr find_segment ;do the search
bcc @another_seg
clc
@oops rts ;return with no error
@another_seg
jsr load_segment ;load the segment into memory
bcs @oops
ldy #seg_kind_offset ;lets see if this is a Stack/Direct Page segment
lda [seg_header_ptr],y ;If it is then save the correct Info.
and #kind_only
cmp #dp_seg_type ;lets find the stack seg please
bne @not_stack
jsr save_dp_info ;save stack and Direct page info
bra not_first ;even if it is skip it please
@not_stack cmp #init_seg_type ;is this an initilization segment?
beq run_init_seg ;go ahead and run the segment
lda starting_addr
ora starting_addr+2
bne not_first ;this is not the first segment
;
;If this is the first segment then save it's starting address so we can return it to the caller
;
lda segment_entry
sta starting_addr ;save the starting address that we will jump to
lda segment_entry+2
sta starting_addr+2
not_first
lda loaded_seg_num ;save the seg number
pha
jsr static_loop
bcs fix_stack_abort ;exit if an error occurred
pla
jsr process_reloc
bcs fix_stack_abort ;mjor problems
rts
run_init_seg
lda loaded_seg_num ;the init segment we just loaded!
jsr process_reloc
bcs fix_stack_abort ;exit with the error
lda segment_entry ;address of the segment just loaded
sta self_mod+1
lda segment_entry+1
sta self_mod+2 ;make a self modifing address to run init segment
jsr lock_handles
tdc ;save my direct page
pha
lda #$0000
tcd ;set direct register to real zero page
self_mod jsl >$000000
rep #$30 ;restore 16 bit mode
pla ;restore direct register
tcd
phk
plb ;set my bank please
jsr unlock_handles
bra static_loop ;load any other init segs please
fix_stack_abort
ldx stack
txs ;restore the stack pointer please
rts ;return the error to the caller
endp
eject
;====================================================================================================
;save_start: This routine will save the starting address and stack info in the user_id_table
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; user_id_ptr
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
save_start proc
with data
ldy #id_stack_addr ;save the address of the stack/direct page
lda stack_addr
sta [user_id_ptr],y
ldy #id_stack_size ;also save the size
lda stack_size
sta [user_id_ptr],y
ldy #id_start_addr
lda starting_addr ;save the starting address of the application
sta [user_id_ptr],y
iny
iny
lda starting_addr+2
sta [user_id_ptr],y
clc
rts
entry restore_start
restore_start
ldy #id_stack_addr ;get the address of the stack/direct page
lda [user_id_ptr],y
sta stack_addr
ldy #id_stack_size ;get save the size
lda [user_id_ptr],y
sta stack_size
ldy #id_start_addr
lda [user_id_ptr],y
sta starting_addr
iny
iny
lda [user_id_ptr],y
sta starting_addr+2
clc
rts
endp
eject
;====================================================================================================
;reload_restart: This routine will scan the ExpressLoad segment looking for a restart segment
; If any are found they will be loaded into the same address as they were before.
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; ExpressHandle
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
reload_restart proc
with data
jsr make_HET_ptr
lda [HET_ptr] ;get the number of entries in table
inc a ;start from the last segment
inc a
tax
@search_loop
txa ;pass in the segment number
beq @end_restarts ;sorry there is no segment
phx
sta loaded_seg_num
jsr setup_seg_ptrs ;we are now in business
jsr do_restarts
@skip_it
plx
bcs @restart_error
dex ;back off by one and try again
cpx #$0001
bne @search_loop
@end_restarts
clc
@restart_error
rts
do_restarts
ldy #seg_kind_offset
lda [seg_header_ptr],y ;get the segment kind field to determine if this
and #reload_segment ;segment needs to be reloaded.
beq @not_reload
jsr load_restart ;major pain in the butt!
@not_reload
clc
rts
load_restart
lda file_open ;is the file already open?
bne @skip_open ;someone has already opened the file
jsr open_load_file ;open the file please
bcs @load_exit
@skip_open
jsr load_segment ;load the segment into memory
bcs @load_exit ;bad news
lda loaded_seg_num ;now relocate the segment
jsr process_reloc ;process the segment
@load_exit
rts
endp
eject
;====================================================================================================
;reload_inits: This routine will scan the ExpressLoad segment looking for init segments. If it finds
; an init segment it will pass control to that segment
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; ExpressHandle
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
reload_inits proc
with data
jsr make_HET_ptr
lda [HET_ptr] ;get the number of entries in table
inc a ;start from the last segment
inc a
tax
@search_loop
txa ;pass in the segment number
beq @end_inits ;sorry there is no segment
phx
sta loaded_seg_num
jsr setup_seg_ptrs ;we are now in business
jsr do_inits
@skip_it
plx
bcs @init_error
dex ;back off by one and try again
cpx #$0001
bne @search_loop
@end_inits
clc
@init_error
rts
do_inits
ldy #seg_kind_offset
lda [seg_header_ptr],y ;get the segment kind field to determine if this
and #kind_only
cmp #init_seg_type
beq @do_init_type
clc
rts
@do_init_type
ldy #handle_offset ;get the handle to the segment
lda [het_entry_ptr],y
tax
iny
iny
lda [het_entry_ptr],y
tay
bne @have_handle
tax
bne @have_handle
sec
rts ;return the handle
@have_handle
stx temp_handle
sty temp_handle+2
ldy #$0001
lda [temp_handle]
sta self_mod+1
lda [temp_handle],y
sta self_mod+2
jsr lock_handles
tdc ;save my direct page
pha
lda #$0000
tcd ;set direct register to real zero page
self_mod jsl >$000000
rep #$30 ;restore 16 bit mode
pla ;restore direct register
tcd
phk
plb
jsr unlock_handles
clc
rts
endp
eject
;====================================================================================================
;jump_load: This routine is used to load segments via the Jump Table
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; On the stack is the return address of the routine that called me
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error ;If this happens I would be suprized
; b = k
;
;
; Jump Table Entry
;
; User_ID 2
; Load_File Number 2
; Load Segment Number 2
; Load Segment Offset 4
; JSL to Jump-table load 4
;
;====================================================================================================
longa on
longi on
jump_load proc
with data
;
; -------------
; Bank Register
; -------------
; Return addr
; -------------
;
phb ;save the callers bank
phk
plb ;set my bank please
;
; ----------------
; Processor Status
; ----------------
; Bank Register
; ----------------
; Return Address
; ----------------
; Return Address
; of main routine
; ----------------
;
php ;save the m and x bits
rep #$30 ;16 bit mode
sta save_a
stx save_x
sty save_y ;save apps registers
;
; ----------------
; Return Address
; of main routine
; ----------------
;
plx ;get the processor status + Bank registe
pla ;get the low word of the return address
sta starting_addr
sep #$20 ;8 bit mode
pla
sta starting_addr+2
stz starting_addr+3
rep #$20 ;16 bit
;
; ----------------
; Processor Status
; ----------------
; Bank Register
; ----------------
; Return Address
; of main routine
; ----------------
phx ;push back the processor status and bank register
;
; ----------------
; Direct Register
; ----------------
; Processor Status
; ----------------
; Bank Register
; ----------------
; Return Address
; of main routine
; ----------------
phd ;save the apps direct register please
;
;Now we need to setup our stuff
;
lda my_dir_page ;setup my direct register
tcd
jsr reset_local_mark
sec
lda starting_addr ;build a pointer to the start of the info
sbc #jmp_entry_size-1
sta jmp_tbl_ptr
lda starting_addr+2
sbc #$0000
sta jmp_tbl_ptr+2 ;temp_ptr points to Jump Table Entry
lda [jmp_tbl_ptr] ;get the user ID
sta user_id ;update the global User ID
jsr find_user_id
bcc @found_it
lda #User_id_err ;no way bud!! my system is messed up
jsr error_routine ;Time to go see Freddy (No Return)
@found_it
ldy #$0002 ;get handle to the ExpressLoad segment
lda [temp_ptr],y
sta ExpressHandle
iny
iny
lda [temp_ptr],y
sta ExpressHandle+2
ldy #$0002 ;check the load file number
lda [jmp_tbl_ptr],y
dec a
beq @good_file
lda #incompatible_err ;This file is not ExpressLoad compatible
jsr error_routine ;sorry no can do.
@good_file
iny
iny
lda [jmp_tbl_ptr],y ;get the segment we need to find
sta search_seg
iny
iny
lda [jmp_tbl_ptr],y ;get the relative offset
sta jmp_patch_value
iny
iny
lda [jmp_tbl_ptr],y
sta jmp_patch_value+2
ldx ExpressHandle
ldy ExpressHandle+2
jsr merge_path
clc
ldy #$0002
lda [ExpressHandle]
adc #extra_header ;load ExpressSegment past Extra Header
tax
clc
adc #$0004 ;pass the link field
sta HET_ptr ;header entry table pointer
lda [ExpressHandle],y
tay
adc #$0000
sta HET_ptr+2
lda search_seg
dec a
sec
sbc ExpressSeg_pos ;0 or 1
asl a
asl a
asl a ;times 8 for HET entry size
inc a ;add two to pass the segment count field
inc a
clc
adc HET_ptr ;make a pointer to the Entry
sta HET_Entry_ptr ;pointer to the entry itself
lda #$0000
adc HET_ptr+2
sta HET_Entry_ptr+2
;
;Build a pointer to the segment header itself
;
clc
lda HET_entry_ptr ;add in relative address to segment
adc [HET_Entry_ptr]
sta seg_header_ptr
lda HET_Entry_ptr+2
adc #$0000
sta seg_header_ptr+2
;
;Now lets see if the segment is already loaded into memory
;
ldy #flags_offset
lda [het_entry_ptr],y
bpl @new_segment ;we must load the segment from disk
lsr a ;see if the segment is marked as purgable
bcc @its_locked
lda search_seg ;pass in the segment number please
jsr lock_segment ;go and lock this segment
bcs @new_segment ;we have to reload the segment from disk
@its_locked
ldy #handle_offset ;get the base address
lda [het_entry_ptr],y
sta temp_handle
iny
iny
lda [het_entry_ptr],y
sta temp_handle+2
ldy #$0002 ;get the real address
lda [temp_handle]
sta base_ptr
lda [temp_handle],y
sta base_ptr+2
bra @do_patch
@new_segment
jsr open_load_file ;open the puppy
bcc @got_it
@oops
jsr error_routine ;sorry no can do. (No Return)
@got_it
jsr lock_handles
jsl $e100a8 ;get the current system preferences
dc.w $200F
dc.l preference_list
;
;Save the current user's preference please
;
lda preference_list.sys_prefs
sta preference_list.users_prefs
;
;Now ask the operating system to put up a mount dialog when I ask for a disk
;
lda #$C000 ;ask the OS to put up the mount dialog
sta preference_list.sys_prefs
jsl $e100a8
dc.w $200C ;set the system preference
dc.l preference_list
jsr unlock_handles
jsr load_segment ;load the segment into memory
bcs @oops
lda search_seg ;relocate the segment
jsr process_reloc
lda preference_list.users_prefs
sta preference_list.sys_prefs
jsr lock_handles
jsl $e100a8
dc.w $200C ;restore the caller's system preference
dc.l preference_list
jsr unlock_handles
jsr close_load_file ;close the file
@do_patch
clc ;add in the offset field
lda base_ptr
adc jmp_patch_value
sta base_ptr
lda base_ptr+2
adc jmp_patch_value+2
sta base_ptr+2
ldy #$000A ;offset to the JSL
longa off
sep #$20
lda #$5C ;convert to a JML
sta [jmp_tbl_ptr],y
longa on
rep #$20
iny
lda base_ptr
sta [jmp_tbl_ptr],y
sta call_routine+1
lda base_ptr+1
iny
sta [jmp_tbl_ptr],y
sta call_routine+2
;
; ----------------
; Processor Status
; ----------------
; Bank Register
; ----------------
; Return Address
; of main routine
; ----------------
pla ;restore Direct Register
tcd
lda save_a ;restore registers
ldx save_x
ldy save_y
;
; ----------------
; Return Address
; of main routine
; ----------------
plp ;restore processor mode
plb
call_routine jml $0000000 ;call the desired routine
endp
eject
;====================================================================================================
;startup: This routine will allocate memory used by the system loader and setup
; any data structures that are used by ExpressLoad.
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error ;If this happens I would be suprized
; b = k
;
;
;====================================================================================================
longa on
longi on
startup proc
with data
jsr Get_ExpLoad_ID ;get ID for me to use
jsr alloc_my_dp ;allocate me a direct page please
bcc @got_it
rts ;return the error
@got_it
lda temp_handle ;save the current handle please
pha
lda temp_handle+2
pha
stx temp_handle
sty temp_handle+2 ;to determine our direct page
lda [temp_handle] ;get the page please
sta my_dir_page ;save my direct page please
sta temp_handle ;setup pointer to direct page
stz temp_handle+2
lda #$0000
ldy #$00FE
@clear_it sta [temp_handle],y
dey
dey
bpl @clear_it
ply
sty temp_handle+2 ;restore data used on current direct page
ply
sty temp_handle ;it is now safe to setup the direct register
lda my_dir_page
tcd ;go ahead and setup the direct register
stz user_id_handle ;indicate that there is no ID table yet
stz user_id_handle+2
;
;Now lets setup one user_id_table
;
jsr add_id_table ;add the first User ID Table please
rts ;return the error code to caller
endp
eject
;====================================================================================================
;zero_handles: Zero handles to indicate that there is no segment
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = ?
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
zero_handles proc
with data
;
;We now zero the handles that do not live across calls. We do this so we can
;lock the handles when we make memory manager calls
;
stz ExpressHandle ;zero the handles please
stz ExpressHandle+2
stz temp_handle ;zero any temp handles hanging around
stz temp_handle+2
stz reloc_handle ;this handle does not live across calls
stz reloc_handle+2
stz seg_handle
stz seg_handle+2 ;this handles do not live across calls
stz curr_id_handle
stz curr_id_handle+2
rts
endp
eject
;====================================================================================================
;get_parameters: This routine is called at the beginning of each Tool call. It will
; get the input parameters off the stack and setup our operating environment.
;
;
;Input: A = undefined
; X = number of paramters on stack
; Y = undefined
; P = nvmxdizc
; ..000...
; b = ?
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
get_parameters proc
with data
pla ;save RTS
sta >local_return
;
;Save the data bank register
;
phb
phb ;save the bank register first
pla
sta >data_bank
;
;Set data bank register to our bank
;
phk
plb ;set data bank to our bank.
;
;save the apps direct page
;
tdc ;save the direct page register
sta apps_dir_page
;
;setup our direct page
;
lda my_dir_page
tcd ;we now have our own direct page
;
;save the return address
;
pla ;now save the return address
sta return_addr
pla ;get both return address off the stack
sta return_addr+2
pla
sta return_addr2+1
longa off
longi off
sep #$30
txy
beq @done ;we have done our job
;
;now we need to pull the needed parameters off of the stack.
;
ldy #$00
@loop
pla ;get a byte off the stack
sta param_blk,y ;save the byte in a common parameter block
iny
dex
bne @loop
@done
longa on
longi on
rep #$30
lda local_return
pha
jsr zero_handles
jsr reset_local_mark
stz partial_match ;indicate that we need a complete match!!!
rts
local_return dc.w 00
endp
eject
;====================================================================================================
;restore_params: This routine is called if we are going to call the standard system loader.
;
;
;Input: A = undefined
; X = number of paramters on stack
; Y = undefined
; P = nvmxdizc
; ..000...
; b = ?
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
restore_params proc
with data
pla
sta local_return
phx ;save x for one second: actually much less then that
lda file_open ;is the load file open?
beq @not_open ;the file is not open so don't worry about it.
jsr close_load_file ;go ahead and close the file since we are thru with it.
@not_open
plx ;restore the parameter count please.
longa off
longi off
sep #$30
txy
beq @done ;we have done our job
dex
;
;now we need to push the original parameters on the stack.
;
@loop
lda param_blk,x ;get the original byte
pha
dex
bpl @loop
@done
longa on
longi on
rep #$30
lda return_addr2+1
pha
lda return_addr+2
pha
lda return_addr
pha
lda apps_dir_page
tcd ;restore the direct page
lda >data_bank
pha
plb
plb
IF debug_on=0 GOTO .nobug
lda #$FEFE
sta >Rom_debug+2
.nobug
lda >orig_y
tay
lda >orig_x
tax
lda >local_return
pha
lda >orig_a ;restore the Accum
clc
rts
local_return dc.w 00
endp
eject
;====================================================================================================
;return_with_error: This routine is called if ExpresssLoad has handled the file and an error
; has occured.
;
;
;Input: A = Error Code
; X = number of bytes to push on the stack
; Y = undefined
; P = nvmxdizc
; ..000..1 = no error
; b = K
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
return_with_error proc
with data
tay
lda #$0000
sep #$20 ;eight bit mode for push
cpx #$0000
beq @nothing
@loop
pha
dex
bne @loop ;push the correct number of bytes.
@nothing
rep #$20
tya ;restore the error
sec
;
; jmp return_to_caller ;FALL THRU TO THE NORMAL EXIT
endp
eject
;====================================================================================================
;return_to_caller: This routine is called if ExpresssLoad has handled the file
;
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = no error
; b = K
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
return_to_caller proc
with data
sta local_error
IF debug_on=0 GOTO .nobug
sta >Rom_debug+2
.nobug
lda file_open ;is the load file open?
beq @not_open ;the file is not open so don't worry about it.
jsr close_load_file ;go ahead and close the file since we are thru with it.
@not_open
ldy #$0004 ;lets unlock this puppy
lda ExpressHandle
ora ExpressHandle+2
beq @skip_unlock ;there is no ExpressSegment
lda [ExpressHandle],y
and #$7FFF ;unlock the handle
sta [ExpressHandle],y
@skip_unlock
lda return_addr2+1
pha
lda return_addr+2
pha
lda return_addr
pha
lda apps_dir_page
tcd ;restore the direct page
lda >data_bank
pha
plb
plb
lda >orig_y
tay
lda >orig_x
tax
lda >local_error
cmp #$0001
rtl
local_error dc.w 00
endp
eject
;====================================================================================================
;Main Entry point for the loader
;====================================================================================================
longa on
longi on
Main proc
with data
import loader_patch
phk
plb
phd
lda #$0000
tcd ;setup the standard direct page
jsr startup ;init my self
jsr loader_patch
IMPORT draw_express
jsr draw_express
@skip_startup
pld ;restore the direct page
rtl
string asis
endp
eject
;====================================================================================================
;do_Save_AXY Save the A X and Y register from the tool dispatcher
;
;
;Input: A = ??
; X = Tool and Function Number
; Y = ??
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
;
;====================================================================================================
longa on
longi on
do_Save_AXY proc
with data
sta >orig_a
txa
sta >orig_x
tya
sta >orig_y
php
longa on
longi on
rep #$30 ;16 bit mode
pha
phx
phy
lda >show_splash ;have I already checked?
bmi @already_done
lda #$FFFF
sta >show_splash
jsl $e100a8 ;get info on ExpressLoad
dc.w $2006
dc.l ExpressInfoList
bcs @already_done ;An Error?
lda >ExpressAux ;get the AuxType
cmp #'RT' ;is it my initials?
bne @already_done
phb ;save bank from call
phk
plb
jsr draw_express ;draw the ExpressLoad logo and screw marketing!
plb
@already_done
ply
plx
pla
plp
rts
Export show_splash
show_splash dc.w 00 ;Used to indicate that I shown splash screen
ExpressInfoList dc.w $0004 ;PCount for the call
dc.l ExpressPath
dc.w 00 ;access
dc.w 00 ;filetype
ExpressAux dc.l 000000000 ;ExpressLoad Aux Type
ExpressPath dc.w 20
dc.b '*:System:ExpressLoad'
endp
eject
;====================================================================================================
;rename_segments: This routine will rename paths for ExpressLoad
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; Full_Blown ;Path that we need to find
;
;Output: A = User ID
; X = undefined
; Y =undefined
; P = nvmxdizc
; ..000..1 = not found
; b = k
;
;
;====================================================================================================
longa on
longi on
rename_segments proc
with data
lda #$8000
sta partial_match ;indicate that a partial match is OK
ldx user_id_handle
ldy user_id_handle+2
bra @keep_going
@loop
jsr do_rename ;rename all files in thie user_id chunck
ldy #$0004 ;unlock the handle
lda [temp_handle],y
and #$7FFF
sta [temp_handle],y
ldy #$0002 ;get the next link
lda [user_id_ptr]
tax
lda [user_id_ptr],y
tay
bne @keep_going
txa
bne @keep_going
rts ;we are done
@keep_going
stx temp_handle
sty temp_handle+2
ldy #$00002
lda [temp_handle]
sta user_id_ptr ;point to the next user_id table
lda [temp_handle],y
sta user_id_ptr+2
ldy #$0004 ;lock the handle
lda [temp_handle],y
ora #$8000
sta [temp_handle],y
bra @loop
@found_it
rts ;A = User_ID
do_rename
ldy #id_entry_size ;start at the first available spot
ldx #id_entry_cnt ;number of entries in a table
@rename_loop
lda [user_id_ptr],y ;get a user_id
beq @empty_slot
phy
phx
jsr copy_orig_name
plx
ply
phy
phx
jsr check_and_rename ;rename if needed
plx
ply
@empty_slot
clc
tya
adc #id_entry_size
tay
dex
bpl @rename_loop
clc
rts
;====================================================================================================
;Rename the segment if needed
;====================================================================================================
check_and_rename
iny
iny ;get the handle
lda [user_id_ptr],y
sta ExpressHandle
tax
iny
iny
lda [user_id_ptr],y
sta ExpressHandle+2 ;Handle to the ExpressLoad segment
tay
jsr Merge_path ;build a complete pathname
jsr compare_paths ;is this the one?
bcc @go_on ;a complete match was found!!!
bvc @partial_found ;we have a partial match
rts ;see if the pathname is found
@partial_found
php ;save partial/ complete flag
jsr Expand_to_full_blown ;copy name from ExpressLoad segment into fullBlown.
plp
@go_on
php ;save partial/compelete flag
lda param_blk+func_13_new_ptr+2
sta path_ptr+2 ;high word of the pathname
lda param_blk+func_13_new_ptr
sta path_ptr ;low word of the pathname
lda [path_ptr] ;get the length
cmp #$0100
bcc @go_around
plp ;fix the stack
@long_to_loader
rts
@go_around
tay
iny ;get all the characters
@new_loop
lda [path_ptr],y
sta Expanded_name.size,y ;Expanded now has a GString with the new name
dey
bpl @new_loop
plp
bcc @not_partial ;this is a complete pathname
jsr merge_names ;add partial to old ExpressLoad name
bcc @not_partial
rts
@not_partial
jsr setup_path_sizes ;setup vol_size, partial_size, partial_offset etc.
jsr make_HET_ptr
jsr setup_base_ptr
jsr adjust_handle_size
bcc @adjusted
rts
@adjusted jsr save_new_name
clc
rts
;====================================================================================================
;
;save_new_name will store the name in the ExpressLoad segment
;
;
;====================================================================================================
save_new_name
ldy #$0002 ;build a pointer to ExpressSegment
lda [ExpressHandle]
sta temp_ptr
sta base_ptr
lda [ExpressHandle],y
sta temp_ptr+2
sta base_ptr+2
;
;Now we need to build a pointer to the volume name
;
ldy #seg_vol_offset ;offset to the volume name
clc
lda [Temp_ptr],y
adc temp_ptr
sta super_ptr
lda #$0000
adc temp_ptr+2
sta super_ptr+2 ;super_ptr now points to the volume name
jsr store_new_name ;go and do it
rts
;====================================================================================================
;
;Get the original name from SCM
;
;====================================================================================================
copy_orig_name
lda param_blk+func_13_orig_ptr+2
sta path_ptr+2 ;high word of the pathname
lda param_blk+func_13_orig_ptr
sta path_ptr ;low word of the pathname
lda [path_ptr] ;get the length
cmp #$0100
bcc @onward
rts
@onward
tay
iny ;get all the characters
@loop
lda [path_ptr],y
sta full_blown.size,y ;Full blown now has a GString with the source
dey
bpl @loop
rts
;====================================================================================================
;
;This routine will resize the ExpressLoad handle as needed
;
;====================================================================================================
adjust_handle_size
lda #$0000
pha
pha
pei ExpressHandle+2 ;push the high word of the handle
pei ExpressHandle
ldx #$1802 ;GetHandle call
jsl $e10000
pla
sta express_size
pla
sta express_size+2
lda full_blown.size ;see if the original is larger then new pathname?
and #$00FF
sta full_blown.size
cmp Expanded_name.size
beq @no_problem ;the strings are the same size
bcc @grow_handle ;source < destination name so grow handle
;
;if here, the original name (Full) is greater then new name (expanded)
;
lda full_blown.size ;larger number
sbc Expanded_name.size
;
;A = size we need to reduce ExpressHandle by
;
pha
sec
lda express_size
sbc 1,s ;reduce the size
sta express_size
lda express_size+2
sbc #0000
sta express_size+2
pla
bra @set_size ;go and set the size
@grow_handle
sec
lda expanded_name.size ;larger name
sbc full_blown.size
pha
clc
lda express_size
adc 1,s ;increase the size
sta express_size
lda express_size+2
adc #0000
sta express_size+2
pla
@set_size
pei ExpressHandle+2
pei ExpressHandle
ldx #$2202 ;unlock the handle
jsl $e10000
lda express_size+2 ;get the size please
pha
lda express_size
pha
pei ExpressHandle+2
pei ExpressHandle
ldx #$1902 ;SetHandle size for ExpressLoad segment
jsl $e10000
rts
@no_problem
clc
rts
;====================================================================================================
;Copy Expanded name into Full_blown name
; == save name from ExpressLoad segment
;
;====================================================================================================
Expand_to_full_blown
lda expanded_name.size
sta full_blown.size
tay
longa off
sep #$20
lda #$00
sta full_blown.size+2,y ;make a C string
@loop
lda expanded_name.size+1,y
sta full_blown.size+1,y ;Full blown now has a GString with the source
dey
bne @loop
longa on
rep #$20
rts
;====================================================================================================
;This routine will merge the partial path onto the new name
; == Expanded_name will contain the new name for ExpressLoad segment
;====================================================================================================
merge_names
lda expanded_name.size ;get index to the end of the string
tay
ldx SubStr_size ;index into full blown
longa off
sep #$20
@merge_loop
lda full_blown.name,x ;get the seperator
sta expanded_name.size+2,y ;store the character
beq @done
inx
iny
inc expanded_name.size ;bump the count.
bne @merge_loop
longa on
rep #$20
sec
rts
@done
longa on
rep #$20
clc
rts
endp
eject
;====================================================================================================
;============= Beginning of the Patch code for the loader ===========================================
;====================================================================================================
longa on
longi on
string asis
loader_patch proc
with data
ptr1 equ $00
ptr2 equ $04
loader_ptr equ $08
longa on
longi on
patch_main
phk
plb
rep #$30
lda #$0000
pha
pha
pha
lda #$0011 ;get the loader table
pha
ldx #$0901
jsl $e10000
pla
sta loader_ptr
pla
sta loader_ptr+2
lda #Patch_table
sta ptr1
lda #^Patch_table
sta ptr1+2 ;pointer to the patch table
ldx #$0000
@loop
lda patch_table,x
beq @done ;we are thru
tay ;index to loader entry
inx
inx
inx
inx ;pass the offset field
lda patch_table,x
sta my_routine ;address that I need to patch with
inx
inx
lda patch_table,x
sta my_routine+2
inx
inx
clc
lda patch_table,x ;address of return address
adc #$0001
sta ptr1
inx
inx
lda patch_table,x
adc #$0000
sta ptr1+2
inx
inx ;point to the next entry
lda [loader_ptr],y
sta loader_address
iny
iny
lda [loader_ptr],y
sta loader_address+2
lda my_routine+2 ;Patch the Loader to point to me
sta [loader_ptr],y
dey
dey
lda my_routine
sta [loader_ptr],y
clc
lda loader_address
adc #$0001
sta loader_address
lda loader_address+2
adc #0000
sta loader_address+2 ;slowest way possible. But I'm hot and tired!
ldy #$0001 ;Patch my exit routine to point to the loader
lda loader_address
sta [ptr1]
lda loader_address+1
sta [ptr1],y
bra @loop
@done
rts
loader_address dc.l 00
my_routine dc.l 00
eject
;====================================================================================================
;Initial_Load: This routine will do an Initial Load of a load file.
;
;
;Input: A = undefined
; X = Tool and Function Number
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
;Stack before call:
;
; previous contents
; result space word
; result space word
; result space long
; result space word
; User ID word
; Addr of load file name long
; special memory flag word
; SP ---->
;
;Stack after call:
;
; previous contents
; direct page/stack size word
; direct page/stack addr word
; starting address long
; User ID word
; SP ---->
;
;
;====================================================================================================
longa on
longi on
L_init_load
jsr save_AXY
IF debug_on=0 GOTO .nobug
lda #$0001 ;initial load
sta >Rom_debug
.nobug
ldx #func_9_param_cnt ;get the number of parameters of the stack
jsr get_parameters
;now we make a string to the pathname
lda param_blk+func_9_path_addr
sta temp_ptr
lda param_blk+func_9_path_addr+2
sta temp_ptr+2 ;temp_ptr now points to a PString
;
;Now we need to do an Expand Path on the Input name. Expand Path expects a pointer to a
;GString, So I will cheat and convert the callers string into a GString.
;
lda temp_ptr
bne @low_only
dec temp_ptr+2 ;decrement the High Byte
@low_only dec a
sta temp_ptr
lda [temp_ptr] ;get garbage + length byte
pha ;save it please
xba ;put length byte in the low word
and #$00FF ;clear the garbage
sta [temp_ptr] ;PString now equals GString
ldx temp_ptr
ldy temp_ptr+2 ;convert the puppy please
jsr expand_path
pla ;restore the PString
sta [temp_ptr]
bcs @abort ;dump to Lou's loader on errors
jsr open_load_file ;open the file please
bcs @abort
jsr check_express_seg ;see if this is an expressload file
bcs @abort
;
;At this point all errors that we encounter must be returned to the caller since the file is mine.
;
;setup the special memory flag
lda param_blk+func_9_spec_mem
sta spec_mem_flag ;user's preference
;go and get the user ID
lda param_blk+func_9_user_id
;get the User_ID from the caller
jsr Alloc_ID
bcs @error_exit ;we have an error we must report to caller
sta User_ID ;make the New ID Global
sta AppID
jsr get_express_seg ;load in the express load segment
bcs @error_exit ;we have an error we must report to caller
ldx ExpressHandle
ldy ExpressHandle+2
jsr merge_path
jsr load_statics ;load all the static segments
bcs @error_exit ;return the error to the caller
jsr save_start ;save the starting address please
lda stack_size ;return the correct parameters
pha
lda stack_addr
pha
lda starting_addr+2 ;address of the Application
and #$00FF
pha
lda starting_addr
pha
lda User_ID
pha
lda #$0000
clc
jmp return_to_caller ;we were successful!!
@error_exit
ldx #func_9_err_cnt ;exit with the error
jmp return_with_error
@abort
ldx #func_9_param_cnt ;restore the stack for the loader
jsr restore_params
return9 jml $000000
eject
;====================================================================================================
;L_initial2: This routine will do an Initial Load of a load file. Version 2 of the call
;
;
;Input: A = undefined
; X = Tool and Function Number
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
;Stack before call:
;
; previous contents
; result space word
; result space word
; result space long
; result space word
; User ID word
; Addr of load file name long
; special memory flag word
; pathname flag word 1 = GString, 2 = mem load, 3=pathname table, 4= code resorce
; SP ---->
;
;
;Stack after call:
;
; previous contents
; direct page/stack size word
; direct page/stack addr word
; starting address long
; User ID word
; SP ---->
;
;
;====================================================================================================
longa on
longi on
L_initial2
jsr save_AXY
IF debug_on=0 GOTO .nobug
lda #$0002 ;initial load
sta >Rom_debug
.nobug
ldx #func_20_param_cnt ;get the number of parameters of the stack
jsr get_parameters
;now we make a string to the pathname
lda param_blk+func_20_path_addr
sta temp_ptr
lda param_blk+func_20_path_addr+2
sta temp_ptr+2 ;temp_ptr now points to a PString
lda param_blk+func_20_path_flag
;see if this is a class1 string
beq @old_style
cmp #$0002 ;see if I can handle this one
bcs @to_abort ;sorry not my type
bra @do_expand ;this is a class1 string
;
;Now we need to do an Expand Path on the Input name. Expand Path expects a pointer to a
;GString, So I will cheat and convert the callers string into a GString.
;
@old_style
lda temp_ptr
bne @low_only
dec temp_ptr+2 ;decrement the High Byte
@low_only dec a
sta temp_ptr
lda [temp_ptr] ;get garbage + length byte
pha ;save it please
xba ;put length byte in the low word
and #$00FF ;clear the garbage
sta [temp_ptr] ;PString now equals GString
@do_expand
ldx temp_ptr
ldy temp_ptr+2 ;convert the puppy please
jsr expand_path
lda param_blk+func_20_path_flag
;see if this is a class1 string
bne @class1
pla ;restore the PString
sta [temp_ptr]
@class1
bcs @to_abort
jsr open_load_file ;open the file please
bcs @to_abort
jsr check_express_seg ;see if this is an expressload file
bcc @its_expressed
@to_abort
brl @abort ;call the standard loader and let it try
;
;At this point all errors that we encounter must be returned to the caller since the file is mine.
;
@its_expressed
;setup the special memory flag
lda param_blk+func_20_spec_mem
sta spec_mem_flag ;user's preference
;go and get the user ID
lda param_blk+func_20_user_id
;get the User_ID from the caller
jsr Alloc_ID
bcs @skip_to_error ;pass the error back to the caller
sta User_ID ;make the New ID Global
sta AppID
jsr get_express_seg ;load in the express load segment
@skip_to_error
bcs @error_exit ;pass the error back to the caller
ldx ExpressHandle
ldy ExpressHandle+2
jsr merge_path
jsr load_statics ;load all the static segments
bcs @dispose_exit ;pass the error back to the caller
jsr save_start ;save starting address and stack info
lda stack_size ;return the correct parameters
pha
lda stack_addr
pha
lda starting_addr+2 ;address of the Application
and #$00FF
pha
lda starting_addr
pha
lda User_ID
pha
lda #$0000
clc
jmp return_to_caller ;we were successful!!
; this is used when an error occurs after loading at least one segment into memory.
; in this case, we must do a pseudo-userShutdown to clean up memory and dispose of
; the user ID.
@dispose_exit
pha ;save the error code
lda User_ID
jsr find_user_id ;get pointer to user_id_table
ldy #$0002
lda [temp_ptr],y ;get the ExpressLoad handle
sta ExpressHandle
iny
iny
lda [temp_ptr],y
sta ExpressHandle+2
jsr close_dynamic_file ;close file if any segments were dynamic
lda temp_ptr ;setup the User_ID pointer to point to the entry
sta user_id_ptr
lda temp_ptr+2
sta user_id_ptr+2
pha ;space for handle
pha
pei user_id_ptr+2 ;lock down the user ID table
pei user_id_ptr
ldx #$1A02 ;FindHandle
jsl $E10000
lda 3,s ;suplicate the handle on the stack
pha
lda 3,s
pha
ldx #$2002 ;HLock
jsl $E10000
lda #nuke_id ;delete the ID and the memory
jsr delete_user_id ;remove the user_id please
ldx #$2202 ;HUnlock (handle already on stack)
jsl $E10000 ;unlock the user ID table
pla ;restore error code
@error_exit
ldx #func_20_err_cnt ;exit with the error
jmp return_with_error
@abort
ldx #func_20_param_cnt ;restore the stack for the loader
jsr restore_params
return15 jml $000000
eject
;====================================================================================================
;L_restart: This routine is called to restart an application.
;
;
;Input: A = undefined
; X = Tool and Function Number
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
;Stack before call:
;
; previous contents
; result space word
; result space word
; result space long
; result space word
; User ID word
; SP ---->
;
;Stack after call:
;
; previous contents
; Dir. Page/Stack size word
; Dir. Page/Stack addr word
; starting address long
; User ID word
; SP ---->
;
;
;====================================================================================================
L_restart
jsr save_AXY
IF debug_on=0 GOTO .nobug
lda #$0003 ;initial load
sta >Rom_debug
.nobug
ldx #func_0A_param_cnt ;get the number of parameters of the stack
jsr get_parameters
lda param_blk+func_0A_user_id
;lets see if we know about this user ID
jsr find_user_id ;If found temp_ptr setup
bcc @continue
brl @abort ;not my job
@continue
;
;At this point all errors that we encounter must be returned to the caller since the file is mine.
;
ldy #$0002
lda [temp_ptr],y ;get the ExpressLoad handle
tax
iny
iny
lda [temp_ptr],y
tay
bne @have_handle
txa
bne @have_handle ;we have the handle
lda #ExpressSegLost
sec
bra @error_exit ;report error to the caller.
@have_handle
stx ExpressHandle
sty ExpressHandle+2
jsr Merge_path ;we now have the expanded ExpressLoad pathname
jsr lock_statics ;lock the static segments please
bcc @no_reload ;this is an easy case.
;
;If we get here we need to remove the old info and reload the application from disk
;
lda #keep_id ;indicate that we must keep the ID
jsr delete_user_id ;we need to nuke the old copy.
jsr zero_handles ;reset everything
jsr open_load_file ;open the file please
bcs @error_exit ;report error to the caller.
jsr check_express_seg ;see if this is an expressload file
bcs @error_exit ;report error to the caller.
jsr get_express_seg ;load in the express load segment
bcs @error_exit ;report error to the caller.
lda #any_state
sta load_state
lda #1
sta spec_mem_flag ;don't use special memory for restart
jsr load_statics ;try to load all static segments
bcc @loaded_ok ;loaded fine, thank you!
stz spec_mem_flag ;try again, using special memory
jsr load_statics ;load all the static segments
@loaded_ok
php ;save carry
pha ;save possible error code
jsr close_load_file ;close the file and restore sys_prefs
pla ;restore error code
plp ;restore carry
bcs @error_exit ;report error to the caller.
bra @clean_exit
@no_reload
jsr kick_start
bcs @error_exit ;report error to the caller.
@clean_exit
jsr save_start
lda stack_size ;return the correct parameters
pha
lda stack_addr
pha
lda starting_addr+2 ;address of the Application
and #$00FF
pha
lda starting_addr
pha
lda User_ID
pha
lda #$0000
clc
jmp return_to_caller ;we were successful!!
@error_exit
ldx param_blk+func_0A_user_id
beq @abort ;If the user_id was zero let Lou try.
ldx #func_0A_err_cnt ;exit with the error
jmp return_with_error
@abort
ldx #func_0A_param_cnt ;restore the stack for the loader
jsr restore_params
returnA
jml $000000
kick_start
stz file_open ;indicate that the file is closed
stz starting_addr ;reset all of our variables
stz starting_addr+2
stz stack_addr ;there is no stack
stz stack_size
jsr chk_dynamic_Seg ;does the file contain any dynamic segments
bcs @no_dynamics
jsr open_load_file ;open the file please
bcs @error_out ;report error to the caller.
jsr save_ref_num
@no_dynamics
jsr make_HET_ptr ;make pointer to Header Entry Table
jsr reset_jmp_tables ;delete any references to dynamic segments
jsr reload_inits ;please restart any init segments
bcs @error_out
jsr reload_restart ;please reload any restart segments.
bcs @error_out
jsr restore_start
clc
@error_out
php
pha
lda file_open ;is the file open?
beq @skip_close
jsr close_load_file
@skip_close
pla
plp
rts
eject
;====================================================================================================
;L_Seg_by_num: This routine will load a segment by number. Note: an application should never
; make this call. If they do they should be shot.
;
;
;Input: A = undefined
; X = Tool and Function Number
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
;Stack before call:
;
; previous contents
; result space long
; User ID word
; load-file number word
; load-segment number word
; SP ---->
;
;Stack after call:
;
; previous contents
; starting address long
; SP ---->
;
;
;====================================================================================================
L_seg_by_num
jsr save_AXY
IF debug_on=0 GOTO .nobug
lda #$0004 ;initial load
sta >Rom_debug
.nobug
ldx #func_0b_param_cnt ;get the number of parameters of the stack
jsr get_parameters
;see if this is file number one
lda param_blk+func_0B_file_num
dec a
bne @abort ;sorry we will let the system loader handle it
lda param_blk+func_0B_user_id
;lets see if we know about this user ID
jsr find_user_id ;If found temp_ptr setup
bcs @abort ;not my job
;
;At this point all errors that we encounter must be returned to the caller since the file is mine.
;
ldy #$0002
lda [temp_ptr],y ;get the ExpressLoad handle
tax
iny
iny
lda [temp_ptr],y
tay
bne @have_handle
txa
bne @have_handle ;we have the handle
lda #ExpressSegLost
sec
bra @error_exit ;report error to the caller.
@have_handle
stx ExpressHandle
sty ExpressHandle+2
jsr Merge_path ;we now have the expanded ExpressLoad pathname
;the segment we will have to load
jsr make_HET_ptr
lda param_blk+func_0B_seg_num
jsr seg_num_lookup ;convert the segment number to correct number
bcs @error_exit ;the number is not valid
sta search_seg ;save the real segment to load.
jsr setup_seg_ptrs ;setup pointers for the load
ldy #flags_offset ;see if the segment is already loaded
lda [HET_entry_ptr],y
bmi @already_in ;this segment is already loaded
@do_load
jsr open_load_file ;open the puppy
bcs @error_exit ;report error to the caller.
jsr load_segment ;load the segment into memory
bcs @error_exit ;report error to the caller.
lda search_seg ;relocate the segment
jsr process_reloc
bcs @error_exit ;report error to the caller.
bra @continue1
@already_in
lsr a ;see if the segment is purgable?
bcc @continue
lda search_seg ;go and lock the handle please
jsr lock_segment
bcs @do_load
@continue
jsr setup_base_ptr ;please setup the base pointer
@continue1
lda segment_entry+2 ;address of the segment
pha
lda segment_entry
pha
lda #$0000
clc
jmp return_to_caller ;we were successful!!
@error_exit
ldx param_blk+func_0B_user_id
beq @abort ;let Lou try if user_id was zero
ldx #func_0b_err_cnt ;exit with the error
jmp return_with_error
@abort
ldx #func_0b_param_cnt ;restore the stack for the loader
jsr restore_params
returnB
jml $000000
eject
;====================================================================================================
;L_unload1: This is the unload segment by number routine. It will mark a segment as purgable
; and unlocked.
;
;
;Input: A = undefined
; X = Tool and Function Number
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
;Stack before call:
;
; previous contents
; User ID word
; load-file number word
; load-segment number word
; SP ---->
;
;Stack after call:
;
; previous contents
; SP ---->
;
;
;====================================================================================================
L_unload1
jsr save_AXY
IF debug_on=0 GOTO .nobug
lda #$0005
sta >Rom_debug
.nobug
ldx #func_0c_param_cnt ;get the number of parameters of the stack
jsr get_parameters
;see if this is file number one
lda param_blk+func_0c_file_num
bne @check_for_1 ;we handle 0 and 1
sta param_blk+func_0C_seg_num
bra @skip_abort
@check_for_1
dec a
bne @abort ;sorry we will let the system loader handle it
@skip_abort
;see if this is for me
lda param_blk+func_0c_user_id
jsr find_user_id
bcs @abort ;must be the real system loaders
;
;At this point all errors that we encounter must be returned to the caller since the file is mine.
;
ldy #$0002
lda [temp_ptr],y ;get the ExpressLoad handle
tax
iny
iny
lda [temp_ptr],y
tay
bne @have_handle
txa
bne @have_handle ;we have the handle
lda #ExpressSegLost
sec
bra @error_exit ;report error to the caller.
@have_handle
stx ExpressHandle
sty ExpressHandle+2
jsr make_HET_ptr
lda param_blk+func_0C_seg_num
beq @do_all_dyn ;we need to purge all dynamics
jsr seg_num_lookup ;convert the segment number to correct number
bcs @error_exit ;the number is not valid
jsr make_purgable
jmp return_to_caller ;return to the caller
@do_all_dyn
jsr purge_all_dyn
jmp return_to_caller ;return the info please
@error_exit
ldx param_blk+func_0c_user_id
beq @abort ;let Lou try.
ldx #func_0c_err_cnt ;exit with the error
jmp return_with_error
@abort
ldx #func_0c_param_cnt ;restore the stack for the loader
jsr restore_params
returnC
jml $000000
;
;If we get here then we must purge all the dynamic segments
;
eject
;====================================================================================================
;L_seg_by_name: This routine will load a segment by Name.
;
;
;Input: A = undefined
; X = Tool and Function Number
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
;Stack before call:
;
; previous contents
; result space word
; result space word
; result space word
; result space long
; User ID word
; Addr of load file name long
; Addr of load seg name long
; SP ---->
;
;Stack after call:
;
; previous contents
; load-segment number word
; load-file number word
; User ID word
; Addr of the segment long
; SP ---->
;
; How it works:
; IF find_user_id(input_id) THEN {If found, ExpressHandle setup}
; BEGIN
; IF compare_path(input_path,ExpressLoad_path) THEN {See if looking for loaded segment}
; BEGIN
; IF find_seg(input_seg_name) THEN {See if segment is available}
; BEGIN
; IF seg_loaded(seg_num) THEN {See if the segment is loaded}
; BEGIN
; Return_parameters
; Exit () {return to the caller}
; END
; ELSE
; BEGIN
; Load_Seg(Seg_num) {load in the segment please}
; return_parameters
; Exit() {return to the caller}
; END
; END
; ELSE
; BEGIN {segment not found}
; Return_error(Seg_Not_Found)
; Exit ()
; END
; ELSE {not same file}
; BEGIN {Pain in the Butt}
; open_file(input_path) {open file, type check etc.}
; get_express_seg {get the ExpressLoad segment}
; IF find_seg(input_seg_name) THEN {See if segment is available}
; BEGIN
; IF seg_loaded(seg_num) THEN {See if the segment is loaded}
; BEGIN
; Return_parameters
; Exit () {return to the caller}
; END
; ELSE
; BEGIN
; Load_Seg(Seg_num) {load in the segment please}
; return_parameters
; Exit() {return to the caller}
; END
; END
; ELSE
; BEGIN {segment not found}
; Return_error(Seg_Not_Found)
; Exit ()
; END
; get_jmp_tbl_seg {load any jump tables please}
; Add_file_num {Link this file in please}
; Return_error(Seg_Not_Found)
; Exit ()
;
;====================================================================================================
L_seg_by_name
jsr save_AXY
IF debug_on=0 GOTO .nobug
lda #$0006
sta >Rom_debug
.nobug
ldx #func_0D_param_cnt ;get the number of parameters of the stack
jsr get_parameters
;get the input user id
lda param_blk+func_0D_user_id
jsr find_user_id ;see if we have the ID
bcc @its_mine
brl @abort ;later we need to handle this better
@its_mine
;
;At this point all errors that we encounter must be returned to the caller since the file is mine.
;
ldy #$0002
lda [temp_ptr],y ;get the ExpressLoad handle
tax
iny
iny
lda [temp_ptr],y
tay
bne @have_handle
txa
bne @have_handle ;we have the handle
lda #ExpressSegLost
sec
bra @error_exit ;report error to the caller.
@have_handle
stx ExpressHandle
sty ExpressHandle+2
jsr Merge_path ;we now have the expanded ExpressLoad pathname
;
;At this point Expanded_name contains the Pathname from the ExpressLoad segment
;Now we need to build an Expanded Name from the Applications input pathname
;
;lets build the name
lda param_blk+func_0D_file_name+2
tay ;high word of the pathname
lda param_blk+func_0D_file_name
tax ;low word of the pathname
jsr expand_app_path
bcs @error_exit ;GS/OS could not expand the pathname
jsr compare_paths ;see if the paths are equal
lda #seg_not_found ;pre-charge the error code if needed
bcs @error_exit ;report error to the caller.
;lets get a copy of the segment name
lda param_blk+func_0D_seg_name+2
tay
lda param_blk+func_0D_seg_name
tax ;low word address of the segment name
jsr find_seg_name ;go and find the segment name in ExpressLoad
bcs @error_exit ;report error to the caller.
sta search_seg ;segment number of the segment
ldy #flags_offset ;see if the segment is already loaded
lda [HET_entry_ptr],y
bmi @already_in ;this segment is already loaded
@do_load
jsr open_load_file ;open the puppy
bcs @error_exit ;report error to the caller.
jsr load_segment ;load the segment into memory
bcs @error_exit ;report error to the caller.
lda search_seg ;relocate the segment
jsr process_reloc
bcs @error_exit ;report error to the caller.
bra @continue1
@already_in
lsr a ;see if the segment is purgable?
bcc @continue
lda search_seg ;go and lock the handle please
jsr lock_segment
bcs @do_load ;segment was purged behind my back!
@continue
jsr setup_base_ptr ;please setup the base pointer
@continue1
lda search_seg ;push the load segment number
jsr my_seg_to_user_seg ;convert to user type number
pha
pea $0001 ;file number
lda User_ID
pha
lda segment_entry+2 ;address of the segment
pha
lda segment_entry
pha
lda #$0000
clc
jmp return_to_caller ;we were successful!!
@error_exit
ldx param_blk+func_0D_user_id
beq @abort ;Let Lou try
ldx #func_0D_err_cnt
jmp return_with_error ;Return to the caller with the error code
@abort
ldx #func_0D_param_cnt ;restore the stack for the loader
jsr restore_params
returnD
jml $000000
eject
;====================================================================================================
;L_unload2: This is the unload segment by address routine. It will mark a segment as purgable
; and unlocked.
;
;
;Input: A = undefined
; X = Tool and Function Number
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
;Stack before call:
;
; previous contents
; result word
; result word
; result word
; Address in segment long
; SP ---->
;
;Stack after call:
;
; previous contents
; load-segment number word
; load-file number word
; user_id word
; SP ---->
;
;
;====================================================================================================
L_unload2
jsr save_AXY
IF debug_on=0 GOTO .nobug
lda #$0007
sta >Rom_debug
.nobug
ldx #func_0e_param_cnt ;get the number of parameters of the stack
jsr get_parameters
stz search_seg
@retry
pea $0000
pea $0000 ;result space
lda param_blk+func_0e_seg_addr+2
sta hold_long+2 ;save the address in case this is a jump table seg
pha ;address in a segment
lda param_blk+func_0e_seg_addr
sta hold_long
pha
ldx #$1A02 ;find handle call
jsl $e10000
plx
ply
bcs @abort
stx seg_handle ;handle to the segment
sty seg_handle+2
jsr find_seg_handle
bcs @abort ;it must be in the original loader
tax
ldy #flags_offset ;see if this is a jump segment
lda [HET_Entry_ptr],y
and #jmp_type
beq @not_jump
lda hold_long
sta temp_ptr
lda hold_long+2
sta temp_ptr+2 ;setup pointer to the segment entry please
lda [temp_ptr] ;get the current opcode
and #$00FF ;clear the garbage
cmp #$0022 ;is it a JSL instruction to ME???
bne @chk_JML
sec
lda temp_ptr ;make pointer to the load_seg_number field
sbc #$0006
sta temp_ptr
lda temp_ptr+2
sbc #$0000
sta temp_ptr+2 ;temp_ptr now points to the correct field
; User_ID 2
; Load_File Number 2
; Load Segment Number 2
; Load Segment Offset 4
; JSL to Jump-table load 4
lda [temp_ptr] ;get the segment number please
sta search_seg
bra @return_info
@chk_JML
cmp #$005C ;is it a JML instruction!!
bne @abort ;let lou return the error
;
;Setup the new address to find
;
ldy #$0001 ;get the address that I need to unload please
lda [temp_ptr],y
sta param_blk+func_0e_seg_addr
iny
iny
lda [temp_ptr],y ;get the high word please
and #$00FF ;clear garbage
sta param_blk+func_0e_seg_addr+2
;save the new address please
bra @retry
@not_jump
txa ;setup the segment number
@return_info ;label moved so that we _always_ call Make_Purgeable
jsr make_purgable ;{gab - 04/23/90}
;@return_info
lda search_seg
jsr my_seg_to_user_seg
pha
pea $0001
lda user_id
pha
lda #$0000
jmp return_to_caller ;return to the caller
@abort
ldx #func_0e_param_cnt ;restore the stack for the loader
jsr restore_params
returnE
jml $000000
eject
;====================================================================================================
;L_Get_User_ID: This routine will return the user Id given a Pathname
;
;
;Input: A = undefined
; X = function number
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
;Stack before call:
;
; previous contents
; result space word
; Pathname Pointer Long PString
; SP ---->
;
;Stack after call:
;
; previous contents
; User_ID word
; SP ---->
;
;====================================================================================================
L_get_userID
jsr save_AXY
IF debug_on=0 GOTO .nobug
lda #$0008
sta >Rom_debug
.nobug
ldx #func_10_param_cnt ;get the number of parameters of the stack
jsr get_parameters
;lets build the name
lda param_blk+func_10_path_addr+2
tay ;high word of the pathname
lda param_blk+func_10_path_addr
tax ;low word of the pathname
jsr expand_app_path
bcs @abort ;GS/OS could not expand the pathname
jsr path_to_user_id ;given a path this routine finds a user ID
bcs @abort
pha ;push the user ID
lda #$0000
clc
jmp return_to_caller ;we were successful!!
@abort
ldx #func_10_param_cnt ;restore the stack for the loader
jsr restore_params
return10
jml $000000
eject
;====================================================================================================
;L_Get_User_ID2: This routine will return the user Id given a class1 Pathname
;
;
;Input: A = undefined
; X = function number
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
;Stack before call:
;
; previous contents
; result space word
; Pathname Pointer Long GString
; SP ---->
;
;Stack after call:
;
; previous contents
; User_ID word
; SP ---->
;
;====================================================================================================
L_get_userID2
jsr save_AXY
IF debug_on=0 GOTO .nobug
lda #$0009
sta >Rom_debug
.nobug
ldx #func_21_param_cnt ;get the number of parameters of the stack
jsr get_parameters
;lets build the name
lda param_blk+func_21_path_addr+2
tay ;high word of the pathname
lda param_blk+func_21_path_addr
tax ;low word of the pathname
stx expand.src
sty expand.src+2
lda #Full_blown
sta expand.dest
lda #^Full_blown ;put the destination name here
sta expand.dest+2
jsr lock_handles
jsl $e100a8 ;call GS/OS
dc.w $200E ;expand path call
dc.l Expand ;pointer to the parameter
jsr unlock_handles
bcs @abort ;GS/OS could not expand the pathname
jsr path_to_user_id ;given a path this routine finds a user ID
bcs @abort
pha ;push the user_id
lda #$0000
clc
jmp return_to_caller ;we were successful!!
@abort
ldx #func_21_param_cnt ;restore the stack for the loader
jsr restore_params
return17
jml $000000
eject
;====================================================================================================
;L_get_pathname: This call returns the pathname associated with a User ID.
;
;Input: A = undefined
; X = function number
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
;Stack before call:
;
; previous contents
; result space long
; User ID word
; file number word
; SP ---->
;
;Stack after call:
;
; previous contents
; pathname pointer long PString
; SP ---->
;
;
;
;====================================================================================================
L_get_pathname
jsr save_AXY
IF debug_on=0 GOTO .nobug
lda #$000A
sta >Rom_debug
.nobug
ldx #func_11_param_cnt ;get the number of parameters of the stack
jsr get_parameters
lda param_blk+func_11_file_num
dec a
bne @abort ;if file number not 1 then call system loader
lda param_blk+func_11_user_id
jsr find_user_id ;see if we have the ID
bcs @abort
ldy #$0002
lda [temp_ptr],y ;get the ExpressLoad handle
tax
iny
iny
lda [temp_ptr],y
tay
bne @have_handle
txa
bne @have_handle ;we have the handle
lda #ExpressSegLost
sec
bra @error_exit ;report error to the caller.
@have_handle
stx ExpressHandle
sty ExpressHandle+2
jsr Merge_path ;Build a GString
jsr GString_to_PString ;convert string to class 0 format
bcs @error_exit ;I could not convert the pathname
lda #^Full_Blown.size
pha
lda #Full_Blown.size
pha
lda #$0000
clc
jmp return_to_caller ;we were successful!!
@error_exit
ldx param_blk+func_11_user_id
beq @abort ;Give Lou a chance.
ldx #func_11_err_cnt
jmp return_with_error ;Return to the caller with the error code
@abort
ldx #func_11_param_cnt ;restore the stack for the loader
jsr restore_params
return11
jml $0000000
eject
;====================================================================================================
;L_getpath2: This routine will return a pathname for a user ID
;
;
;Input: A = undefined
; X = Tool and Function Number
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
;Stack before call:
;
; previous contents
; result space long
; User ID word
; file number word
; SP ---->
;
;Stack after call:
;
; previous contents
; pathname pointer long
; SP ---->
;
;
;====================================================================================================
longa on
longi on
L_getpath2
jsr save_AXY
IF debug_on=0 GOTO .nobug
lda #$000b
sta >Rom_debug
.nobug
ldx #func_22_param_cnt ;get the number of parameters of the stack
jsr get_parameters
lda param_blk+func_22_file_num
dec a
bne @abort ;if file number not 1 then call system loader
lda param_blk+func_22_user_id
jsr find_user_id ;see if we have the ID
bcs @abort
ldy #$0002
lda [temp_ptr],y ;get the ExpressLoad handle
tax
iny
iny
lda [temp_ptr],y
tay
bne @have_handle
txa
bne @have_handle ;we have the handle
lda #ExpressSegLost
sec
bra @error_exit ;report error to the caller.
@have_handle
stx ExpressHandle
sty ExpressHandle+2
jsr Merge_path
lda #^Expanded_name.size
pha
lda #expanded_name.size
pha
lda #$0000
clc
jmp return_to_caller ;we were successful!!
@error_exit
ldx param_blk+func_22_user_id
beq @abort
ldx #func_22_err_cnt
jmp return_with_error ;Return to the caller with the error code
@abort
ldx #func_22_param_cnt ;restore the stack for the loader
jsr restore_params
return16 jml $000000
eject
;====================================================================================================
;L_user_shutdown: This routine will shutdown a load segment
;
;
;Input: A = undefined
; X = Tool and Function Number
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
;Stack before call:
;
; previous contents
; result space long
; User ID word
; quit flag word
; SP ---->
;
;Stack after call:
;
; previous contents
; User ID word
; SP ---->
;
;
;====================================================================================================
L_user_shutdown
jsr save_AXY
IF debug_on=0 GOTO .nobug
lda #$000c
sta >Rom_debug
.nobug
ldx #func_12_param_cnt ;get the number of parameters of the stack
jsr get_parameters
;see if this is my User ID
lda param_blk+func_12_User_ID
jsr find_user_id ;Is this mine?
bcc @found_it ;yes...
brl @abort ;no. It must belong to the system loader
@found_it
ldy #$0002
lda [temp_ptr],y ;get the ExpressLoad handle
tax
iny
iny
lda [temp_ptr],y
tay
bne @have_handle
txa
bne @have_handle ;we have the handle
lda #ExpressSegLost
sec
bra @error_exit ;report error to the caller.
@have_handle
stx ExpressHandle
sty ExpressHandle+2
jsr close_dynamic_file ;close file if any segments were dynamic
lda temp_ptr ;setup the User_ID pointer to point to the entry
sta user_id_ptr
lda temp_ptr+2
sta user_id_ptr+2
;save the guit floag
lda param_blk+func_12_quit_flag
;what type of kill is this
beq @nuke_it ;remove the entire application
cmp #$8000 ;is this a "keep Only Table" quit
bne @make_dormant ;this a restart attemp
;
;If we get here we need to purge the app but keep our tables intack
;
lda #purge_all ;remove all segments
ldx #$0000 ;LOAD flags AND mask COMPARE value BEQ REMOVE_IT
jsr Remove_segment ;deallocate the segments
bra @norm_exit
@make_dormant
lda #purge_dynamics ;remove dynamic segments
ldx #$0000 ;LOAD flags AND mask COMPARE value BEQ REMOVE_IT
jsr Remove_segment ;deallocate the segments
jsr mark_all_purgable
bra @norm_exit
@nuke_it
pha ;space for handle
pha
pei user_id_ptr+2 ;lock down the user ID table
pei user_id_ptr
ldx #$1A02 ;FindHandle
jsl $E10000
lda 3,s ;duplicate the handle on the stack
pha
lda 3,s
pha
ldx #$2002 ;HLock
jsl $E10000
lda #nuke_id ;delete the ID and the memory
jsr delete_user_id ;remove the user_id please
ldx #$2202 ;HUnlock (handle already on stack)
jsl $E10000 ;unlock the user ID table
@norm_exit
lda user_id
pha
lda #$0000
clc
jmp return_to_caller ;we were successful!!
@error_exit
ldx param_blk+func_12_User_ID
beq @abort ;Must be Lou's
ldx #func_12_err_cnt
jmp return_with_error ;Return to the caller with the error code
@abort
ldx #func_12_param_cnt ;restore the stack for the loader
jsr restore_params
return12
jml $000000
eject
;====================================================================================================
;L_Rename_Path: This routine will rename a pathname if the pathname belongs to an ExpressLoad segment
;
;
;Input: A = undefined
; X = function number
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..
; b = k
;
;Stack before call:
;
; previous contents
; Pathname Pointer old Long GString
; Pathname Pointer new Long GString
; SP ---->
;
;Stack after call:
;
; previous contents
; SP ---->
;
;====================================================================================================
L_Rename_Path
jsr save_AXY
IF debug_on=0 GOTO .nobug
lda #$000F
sta >Rom_debug
.nobug
ldx #func_13_param_cnt ;get the number of parameters of the stack
jsr get_parameters
;lets build the name
jsr rename_segments ;go and rename what we can
ldx #func_13_param_cnt ;restore the stack for the loader
jsr restore_params
return13
jml $000000
patch_table
dc.l 9*4 ;skip to Initial Load
dc.l L_init_load-1
dc.l return9
dc.l $0A*4
dc.l L_restart-1
dc.l returnA
dc.l $0B*4
dc.l L_seg_by_num-1 ;load segment by number
dc.l returnB
dc.l $0C*4
dc.l L_unload1-1
dc.l returnC
dc.l $0D*4
dc.l L_seg_by_name-1 ;load the segment by name
dc.l returnD
dc.l $0E*4
dc.l L_unload2-1
dc.l returnE
dc.l $10*4
dc.l L_get_userID-1
dc.l return10
dc.l $11*4
dc.l L_get_pathname-1
dc.l return11
dc.l $12*4
dc.l L_user_shutdown-1
dc.l return12
dc.l $13*4
dc.l L_rename_path-1
dc.l return13
dc.l $20*4 ;initial load 2 routine
dc.l L_initial2-1
dc.l return15
dc.l $22*4 ;get pathname call
dc.l L_getpath2-1
dc.l return16
dc.l $21*4 ;get pathname call
dc.l L_get_userID2-1
dc.l return17
dc.l 0000
endp
eject
****************************************************************************************************
*
* draw_express - draws splash screen text
*
****************************************************************************************************
draw_express proc
line equ $A0
progress_start equ $e15109+02+(line*17)
php
pei temp_word
pei temp_ptr
pei temp_ptr+2
lda #$0008
sta temp_word
;
;setup pointer to graphics screen area I am going to write to.
;
lda #progress_start**$FFFF
sta temp_ptr
lda #^progress_start
sta temp_ptr+2
ldy #$0000
tyx
longa off
longi on
sep #$20
lda >show_splash
bmi loop ;I am being called because user wants screen
lda >$00C025 ;read the AppleKey while I boot
and #$C0 ;leave Option/Apple Key
cmp #$C0
bne jump_out
loop
lda Expanded_name.my_string,x ;grab graphics line from our buffer
sta [temp_ptr],y
inx
iny
cpy #Expanded_name.line_length ;move one line then update base pointer
bne loop
longa on
rep #$20
clc
lda temp_ptr
adc #line ;move to the next line
sta temp_ptr
lda temp_ptr+2
adc #$0000
sta temp_ptr+2
longa off
sep #$20
ldy #$0000
dec temp_word ;see if we have done enough lines
bne loop
longa on
longi on
rep #$20
lda #$FFFF ;we do not need to draw this twice.
sta >show_splash
jump_out
rep #$20
pla
sta temp_ptr+2
pla
sta temp_ptr
pla
sta temp_word
plp
rts ;we are done
endp
end