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
144 KiB
Plaintext

TITLE ', ExpressLoad.a - Switch_handler'
SEG 'Loader'
;====================================================================================================
;Switch_handler This routine is called when we switch from GS/OS to ProDOS 8 and when we switch
; from ProDOS8 to GS/OS.
;
;Input: 1 = Switch P8 to GS/OS, 0 = Switch GS/OS to P8
;
;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
LoadSegCheck
with DirectPage, Globals
Import clear_handles, alloc_my_dp
function equ 7
lda function,s ;get the input parameter
tax ;save in X for a minute
lda 5,s ;remove input parameter from stack
sta 7,s ;by moving two return addresses up
lda 3,s
sta 5,s
pla
sta 1,s
phb
phk ;set our data bank register
plb
phd ;save caller's direct page
txa ;check the input parameter
bne @restore_dp ;goin' back to GS/OS
lda Globals.my_dir_page ;setup our own direct page
tcd
ldx #dir_page_size-2 ;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
_DisposeHandle
stz dp_handle
stz dp_handle+2
bra no_errors
@restore_dp
jsr alloc_my_dp ;allocate me a direct page please
bcs error_exit ;return the error
ldx #dir_page_size-2 ;save the direct page please
@restore_loop lda dir_page_buffer,x
sta 00,x
dex
dex
bpl @restore_loop
no_errors
lda #0 ;no errors
clc
error_exit
pld ;restore direct page
plb ;and DBR
rtl
endp
if 0 then ;nobody likes my special graphics <pout>
TITLE ', ExpressLoad.a - draw_express'
****************************************************************************************************
*
* draw_express - draws splash screen text
*
****************************************************************************************************
draw_express proc
LoadSegCheck
with DirectPage, Globals
line equ $A0
progress_start PointAddress 95,310
my_string_width equ $001a
my_string_height equ $0007
sep #$20 ;8-bit accumulator
longa off
lda >$E0C025
bit #%00000100 ;Caps Lock key down?
rep #$20
longa on
beq jump_out ;no, just skip it
lda #my_string_height
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
ldx #$0000
longa off
longi on
sep #$20
loop1
ldy #$0000
loop
lda splash_image,x ;grab graphics line from our buffer
sta [temp_ptr],y
inx
iny
cpy #my_string_width ;move one line then update base pointer
bne loop
clc
lda temp_ptr
adc #line ;move to the next line
sta temp_ptr
bcc @1
inc temp_ptr+1
@1
dec temp_word ;see if we have done enough lines
bne loop1
longa on
longi on
rep #$20
jump_out
rts ;we are done
splash_image
HEX FFFFFFFFFFFF03FFFFFFFFFFFF
HEX FC0FFFFFFFFFFFF03FFFFFF003
HEX FFFF4444444F03FFFFFFFFFFFF
HEX FC0FFFFFFFFFFFF0303FFFC303
HEX FFFFFFFFFFFF03FFF003FC003F
HEX 000FC00FC003FFF0303FFF0303
HEX F44444444FFF03FFC0C0F0303C
HEX 0C0F0303C03FFFC0303FFF0303
HEX FFFFFFFFFFFC0FFF0303C0C0F0
HEX 303C000F03FFFFC000FFFC0C0F
HEX FFFFF4444FFC0FFF0303C0C0F0
HEX 303C0FFF03FFFFFFC0FFFC0C3F
HEX FFFFFFFFFFFC000FC00FF000FC
HEX 003F003F03FFFFFFC0F03C00FF
endp
endif
TITLE ', ExpressLoad.a - startup'
;====================================================================================================
;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
LoadSegCheck
with DirectPage
Import alloc_my_dp,add_id_table
sep #$20 ;go into 8-bit mode
longa off
lda >statereg ;get current language card setting
pha ;save on stack temporarily
lda >$E0C08B ;turn language card on
lda >$E0C08B
rep #$20
longa on
jsr alloc_my_dp ;allocate me a direct page please
bcs @error_exit
ldx #256
@clear_it
dex
dex
stz DirectPage,x ;zero out my direct page
bne @clear_it
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
@error_exit
tax ;save any possible error code
sep #$20 ;8-bit accumulator
longa off
pla ;retrieve saved language card state
sta >statereg ;restore it
rep #$20
longa on
txa ;retrieve possible error code
rts ;return the error code to caller
endp
TITLE ', ExpressLoad.a - get_parameters'
;====================================================================================================
;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
LoadSegCheck
with DirectPage, Globals
Import zero_handles,reset_local_mark
;
;Save the data bank register
;
phb
phb ;save the bank register first
pla
;
;Set data bank register to our bank
;
phk
plb ;set data bank to our bank.
sta data_bank ;save caller's DBR
;
;Save the return address
;
pla ;save RTS
sta local_return
;
;save the app's 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_addr+4
phx ;save the # of input parameters
jsl incbusyflg ;don't let nobody bother us!
;
; enable the language card memory
;
sep #$20 ;8-bit soft-switch access
longa off
lda >statereg ;get the current setting
sta save_statereg
lda >$E0C08B ;turn language card on
lda >$E0C08B
rep #$20
longa on
ply ;retrieve the # of input parameters
beq @done ;we have done our job
;
;now we need to pull the needed parameters off of the stack.
;
ldx #$0000
@loop
pla ;get a byte off the stack
sta input_parms,x ;save the byte in a common parameter block
inx
inx
dey
dey
bne @loop
@done
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
TITLE ', ExpressLoad.a - return_to_caller'
;====================================================================================================
;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
LoadSegCheck
with DirectPage, Globals
Import close_load_file
sta local_error
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
sep #$20 ;8-bit soft-switch access
longa off
lda save_statereg ;get the original setting
sta >statereg ;reset
rep #$20
longa on
jsl decbusyflg ;we be done now
lda return_addr+4
pha
lda return_addr+2
pha
lda return_addr
pha
lda apps_dir_page
tcd ;restore the direct page
lda data_bank
pha
lda local_error
plb
plb
cmp #$0001
rtl
local_error dc.w 00
endp
TITLE ', ExpressLoad.a - lock_handles'
;====================================================================================================
;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 DirectPage,Globals
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
entry 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
TITLE ', ExpressLoad.a - clear_handles'
;
; Language card portion of loader starts here
;
SEG 'Loader_LC'
;====================================================================================================
;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
with DirectPage
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
TITLE ', ExpressLoad.a - alloc_ExpLoad'
;====================================================================================================
;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 DirectPage, Globals
lda #uExpressSegment ;my ID
bra do_alloc ;go allocate
;====================================================================================================
;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, do_alloc
alloc_mem
lda |USERID ;use application ID for normal allocation
do_alloc
pha ;space for handle
pha
phy ;high request bytes
phx ;low request bytes
pha ;userID
pea attrLocked ;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
TITLE ', ExpressLoad.a - alloc_my_dp'
;====================================================================================================
;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 Globals
Import DeRef
lda #0
pha ;space for handle
pha
pha ;request bytes
pea 256
pea uDirectPage ;userID
pea #attr_locked+attr_bank+attr_page
pha ;MUST be in bank 0
pha
_NewHandle
plx
ply ;get the handle
stx dp_handle ;save my handle please
sty dp_handle+2
bcs @oops
txa ;put low word into accumulator
jsr DeRef ;get the pointer to the direct page
sta my_dir_page
tcd ;go ahead and setup the direct register
@oops
rts ;and return it
endp
TITLE ', ExpressLoad.a - alloc_LConst_seg'
;====================================================================================================
;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 DirectPage, Globals
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
lda |USERID
pha
lda mem_attr
pha
lda org_address+2
pha
lda org_address ;address to start at
pha
_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 |USERID ;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
lda free_mem_size+2
pha
lda free_mem_size
pha
lda |USERID
pha
lda mem_attr
pha
lda search_addr+2 ;address to start at
pha
lda search_addr
pha
_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
TITLE ', ExpressLoad.a - add_id_table'
;====================================================================================================
;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 DirectPage, Globals
ldx #id_tbl_size ;allocate the table please
ldy #$0000
lda #uUserIDTable ;ID to use for the user id table
jsr do_alloc ;go and allocate memory
bcs @oops
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
@oops
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)
sta temp_handle
lda [user_id_ptr],y
sta temp_handle+2
ora temp_handle
bne @search_loop
ldy #User_ID_Table.Next+2 ;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
endp
TITLE ', ExpressLoad.a - reset_local_mark'
;====================================================================================================
;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 DirectPage, Globals
lda #$FFFF
sta local_mark
sta local_mark+2
rts
endp
TITLE ', ExpressLoad.a - seg_num_lookup'
;====================================================================================================
;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 DirectPage, Globals
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
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
TITLE ', ExpressLoad.a - my_seg_to_user_seg'
;====================================================================================================
;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 DirectPage, Globals
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
pla ;retrieve comparison value
@look_loop
cmp [temp_ptr],y ;is this the correct segment number?
beq @have_segment
iny
iny
bne @look_loop
lda #seg_not_found
sec
rts ;return the "Error"
@have_segment tya ;convert index to segment number
lsr a
inc a ;add one to convert from 0 to 1 based
clc
rts
endp
TITLE ', ExpressLoad.a - error_routine'
;====================================================================================================
;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 DirectPage, Globals
pha ;push the error code
pea err_string>>16
pea err_string
_SysFailMgr
brk $ff
string pascal
err_string dc.b 'ExpressLoad error: '
string asis
endp
TITLE ', ExpressLoad.a - make_HET_ptr'
;====================================================================================================
;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 = low word of pointer to Expressload Segment memory
; Y = high word of pointer to Expressload Segment memory
; 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 DirectPage, Globals
;
;Setup temp_ptr to point to the reserved field (of Disk Image) of the HET,
; and HET_ptr to point to the segment count field of the segment.
;
ldy #$0002
clc
lda [ExpressHandle]
sta temp_ptr ;temp now points the link field
tax
clc
adc #ExpressloadSeg.SegCount
sta HET_ptr ;and HET_ptr points to count field
lda [ExpressHandle],y
tay
sta temp_ptr+2
adc #0
sta HET_ptr+2
rts
endp
TITLE ', ExpressLoad.a - setup_seg_ptrs'
;====================================================================================================
;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 DirectPage, Globals
dec a ;convert the segment number please
dec a ;allow for ExpressLoad segment
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
TITLE ', ExpressLoad.a - setup_base_ptr'
;====================================================================================================
;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 DirectPage, Globals
import add_segment_offset
ldy #HET_Entry.SegHandle ;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
ora [temp_handle]
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
TITLE ', ExpressLoad.a - alloc_id'
;====================================================================================================
;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 DirectPage, Globals
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 #Application ;set the Type to Application
tax
@get_new
pea $0000 ;space for result
phx ;ID stuff
_GetNewID
plx
bcs @oops ;return the error
@exit_alloc
txa ;set A = user_id
sta |USERID ;this is now the Global_ID
clc
@oops
rts
endp
TITLE ', ExpressLoad.a - compare_paths'
;====================================================================================================
;compare_paths: This routine will compare the full pathnames pointed to by PathnamePtr and
; TempBuff 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
; PathnamePtr & TempBuff point to the two pathnames to compare
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; .x000..0 = Match found (complete or partial, depending on V flag)
; 1 = Match not found
; 0 = partial match found.
; 1 = complete match found.
; b = k
;
;
;====================================================================================================
longa on
longi on
compare_paths proc
with DirectPage, Globals
lda [PathnamePtr] ;compare the string sizes first
tay
cmp [TempBuff]
beq @do_full_check
bcc @chk_colon_full_blown ;PathnamePtr contains the smaller string.
lda [TempBuff]
tay
iny ;TempBuff contains the smaller string
iny
lda [PathnamePtr],y
bra @do_chk
@chk_colon_full_blown
iny
iny
lda [TempBuff],y
@do_chk
and #$00FF
cmp #seperator ;is it a seperator?
bne @not_same
@do_partial_compare
lda partial_match ;are we looking for a partial match?
bpl @not_same ;don't bother.
dey
longa off
sep #$20
@partial_loop
lda [PathnamePtr],y ;compare the ascii data
eor [TempBuff],y ;case insensitive comparison
beq @equal_1
cmp #$20 ;difference only in case?
bne @not_same ;nope!
lda [PathnamePtr],y ;get character again
cmp #'A' ;make sure it's alphabetic
bcc @not_same
cmp #'Z'+1
bcc @equal_1
cmp #'a' ;lower case?
bcc @not_same
cmp #'z'+1
bcs @not_same
@equal_1
dey
bne @partial_loop
rep #$61 ;clear overflow & carry bits
rts
@do_full_check
iny ;bump for leading length word
longa off
sep #$20
@loop
lda [PathnamePtr],y ;compare the ascii data
eor [TempBuff],y ;case insensitive comparison
beq @equal_2
cmp #$20 ;difference only in case?
bne @not_same ;nope!
lda [PathnamePtr],y ;get character again
cmp #'A' ;make sure it's alphabetic
bcc @not_same
cmp #'Z'+1
bcc @equal_2
cmp #'a' ;lower case?
bcc @not_same
cmp #'z'+1
bcs @not_same
@equal_2
dey
bne @loop
rep #$21 ;clears carry too
sep #$40 ;set overflow bit (full match)
rts ;the pathnames are the same
@not_same
longa on
rep #$20
sep #$41 ;no partial or complete match found
rts
endp
TITLE ', ExpressLoad.a - merge_path'
;====================================================================================================
;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.
;
;merge_path_2: Alternate entry point that can be used when ExpressHandle already contains the handle.
;
;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
;
; PathnamePtr pointer to pathname within ExpressLoad segment
;
;====================================================================================================
longa on
longi on
merge_path proc
entry merge_path_2
with DirectPage, Globals
stx ExpressHandle
sty ExpressHandle+2
merge_path_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 #ExpressloadSeg.PathnameOffset ;offset to the volume name
clc
lda [temp_ptr],y
adc temp_ptr
sta PathnamePtr
lda #$0000
adc temp_ptr+2
sta PathnamePtr+2 ;PathnamePtr now points to the volume name
clc
rts
endp
TITLE ', ExpressLoad.a - add_user_id'
;====================================================================================================
;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 DirectPage, Globals
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
TITLE ', ExpressLoad.a - delete_user_id'
;====================================================================================================
;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 DirectPage, Globals
sta id_flag ;used to determine if I should delete the user id
ldy #ID_Table_Entry.ExpressHandle
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
_DisposeHandle
@no_handle
lda [user_id_ptr] ;get the user_id
beq @zero_and_exit
pha ;ID to nuke
_DisposeAll
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
_DeleteID
@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
TITLE ', ExpressLoad.a - purge_user_id'
;====================================================================================================
;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 DirectPage, Globals
lda [user_id_ptr] ;get the user_id
beq @exit
pha
_PurgeAll
@exit
rts
endp
TITLE ', ExpressLoad.a - remove_segment'
;====================================================================================================
;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 DirectPage, Globals
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 #HET_Entry.SegFlags
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 #HET_Entry.SegHandle ;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
_DisposeHandle
rts
endp
TITLE ', ExpressLoad.a - find_user_id'
;====================================================================================================
;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 DirectPage, Globals
tax
bne @use_input
lda |USERID ;use the global ID
@use_input
sta search_kind
sta |USERID ;update the global User ID
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 #User_ID_Table.Next+2 ;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 #$0002
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
TITLE ', ExpressLoad.a - path_to_user_id'
;====================================================================================================
;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
;
; TempBuff ;pointer to 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 DirectPage, Globals
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
ora [user_id_ptr]
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
tax
iny
iny
lda [user_id_ptr],y
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
TITLE ', ExpressLoad.a - find_seg_handle'
;====================================================================================================
;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 DirectPage, Globals
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 #User_ID_Table.Next+2 ;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 |USERID
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 #HET_Entry.SegHandle ;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
TITLE ', ExpressLoad.a - get_seg_base'
;====================================================================================================
;get_seg_base: Given a segment number this routine will setup segment_base
;
;Input: A = segment_number
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = undefined
;
; HET_ptr ;must be setup!
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
get_seg_base proc
with DirectPage
dec a ;HET table numbers are 0 thru (-n- minus 1)
dec a ;allow for ExpressLoad segment
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
;
;Now we need to setup our Base address for this segment
;
ldy #HET_Entry.SegHandle ;index to the handle
lda [HET_entry_ptr],y
sta temp_handle
iny
iny
lda [HET_entry_ptr],y
sta temp_handle+2
;
;Deref the handle to find out the base address
;
ldy #$0002
lda [temp_handle]
sta segment_base ;starting address of the segment
lda [temp_handle],y
sta segment_base+2
ora segment_base ;see if the segment has been purged!
bne @segment_alive ;great.
lda #seg_not_found
sec
rts
@segment_alive
clc
rts
TITLE ', ExpressLoad.a - Process_Reloc'
;====================================================================================================
;Process_Reloc: This routine is called to process the relocation dictionary of a segment
; ** NOTE ** This code changes the data bank register to the bank that
; contains the Relocation Dictionary. This means all data access to data in
; our bank must use long addressing.
;
;Input: A = segment number to relocate
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
; HET_ptr ;pointer to HET (Header Entry Table) must be setup!
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;
;-Note-
; All Segments that this segment links to must be loaded into memory
;
;HET Entry definition:
;
; -------------------
; Number of segments (word)
; -------------------
; �
; �
; �
; ------------------- [This is one Header Entry, it is repeated -n- times]
; Relative offset to
; segment header (word)
; -------------------
; Flags (word) Bit 15 = loaded
; -------------------
; Handle to segment (Long) Points to the segment in memory
; -------------------
; �
; �
; �
;
;====================================================================================================
longa on
longi on
Process_Reloc proc
with DirectPage, Globals
; sta reloc_seg ;segment numbers are 1 thru -n-
jsr setup_seg_ptrs ;build pointers to the segment entries
;
;Now we need to setup our Base address for this segment
;
ldy #HET_Entry.SegHandle ;index to the handle
lda [HET_entry_ptr],y
sta temp_handle
iny
iny
lda [HET_entry_ptr],y
sta temp_handle+2
;
;Deref the handle to find out the base address
;
ldy #$0002
lda [temp_handle]
sta base_ptr ;starting address of the segment
lda [temp_handle],y
sta base_ptr+2
ora base_ptr ;see if the segment has been purged!
bne @segment_alive ;great.
@no_seg
sec
lda #seg_not_found ;sorry we cannot process the segment
rts
;
;Now we need to deref the handle to the relocation dictionary
;The handle for the relocation dictionary is located in the segment header
;
@segment_alive
ldy #SegHeaderEntry.RelocDict_Length ;now lets get the size of the segment
lda [seg_header_ptr],y
bne @its_there
iny
iny
lda [seg_header_ptr],y
bne @its_there
clc
rts ;easy case
@its_there
ldy #SegHeaderEntry.RelocDict_Hndl ;offset to the relocation dictionary handle
lda [seg_header_ptr],y ;get the handle
sta temp_handle
iny
iny
lda [seg_header_ptr],y
sta temp_handle+2
;
;now lets deref the handle and build a pointer to the relocation dictionary
;
ldy #$0002
lda [temp_handle]
sta reloc_dict_ptr ;points the relocation dictionary in memory
lda [temp_handle],y
sta reloc_dict_ptr+2
ora reloc_dict_ptr ;is the dictionary available
beq @no_seg
stz patch_cnt
stz shift_cnt
lda reloc_dict_ptr+1 ;set the data bank register to relocation dictionary
pha
plb ;get the Bank Address of Relocation Dictionary
plb
opcode_loop
lda (reloc_dict_ptr) ;get the current opcode
and #$00FF ;clear any garbage
beq do_end_handler ;this is the end handler
cmp #$00E2 ;valid record?
bcc @invalid_record ;no...
cmp #$F8
bcc @good_record
@invalid_record
lda #$00E4 ;translate into another invalid number
@good_record
asl a ;times two for word table
tax
jsr (opcode_handlers-$1C4,x) ;Subtract of base of opcodes ($1C4 = $E2*2)
bcc opcode_loop ;do the next opcode please
phk
plb ;restore our bank
rts ;return the error code
;
;This routine dispatches to the correct opcode handler
;
do_end_handler
pea we_are_done-1 ;this is the last one!
pea end_handler-1
rts
we_are_done
phk
plb ;restore our bank please
ldy #SegHeaderEntry.RelocDict_Hndl+2 ;offset to the relocation dictionary handle
lda [seg_header_ptr],y ;get the handle
pha
lda #$0000
sta [seg_header_ptr],y
dey
dey
lda [seg_header_ptr],y
pha
lda #$0000
sta [seg_header_ptr],y
_DisposeHandle
stz temp_handle ;make sure we note that the handle is invalid
stz temp_handle+2
clc
rts ;we did it!!!!
bad_opcode
sec
lda #illegal_record
rts ;exit with error
opcode_handlers
dc.w Reloc_handler ;$E2
dc.w Interseg_handler ;$E3
dc.w bad_opcode ;$E4
dc.w bad_opcode ;$E5
dc.w bad_opcode ;$E6
dc.w bad_opcode ;$E7
dc.w bad_opcode ;$E8
dc.w bad_opcode ;$E9
dc.w bad_opcode ;$EA
dc.w bad_opcode ;$EB
dc.w bad_opcode ;$EC
dc.w bad_opcode ;$ED
dc.w bad_opcode ;$EE
dc.w bad_opcode ;$EF
dc.w bad_opcode ;$F0
dc.w bad_opcode ;$F1
dc.w bad_opcode ;$F2
dc.w bad_opcode ;$F3
dc.w bad_opcode ;$F4
dc.w cReloc_handler ;$F5
dc.w cInterseg_handler ;$F6
dc.w super_handler ;$F7
TITLE ', ExpressLoad.a - Reloc_handler'
;====================================================================================================
;
;This routine will process a standard relocation entry
;
;Structure pointed to by Reloc_dict_ptr
;
; opcode $E2 (1 Byte)
; patch_cnt (1 byte: number of bytes to patch)
; bit_shift (1 byte: (+) = ASL (-) = LSR
; patch_offset (4 bytes: offset from the start of the segment)
; patch_value (4 bytes: offset from the start of the segment)
;
;====================================================================================================
Reloc_handler
ldy #$0001
lda (reloc_dict_ptr),y ;get the patch cnt and bit shift
sep #$20
sta patch_cnt ;the number of bytes to patch 1,2 or 3
xba
sta shift_cnt
rep #$20 ;back to 16 bit mode
ldy #$0003 ;point to the patch offset
clc
lda (reloc_dict_ptr),y
adc base_ptr ;base address
sta patch_ptr ;address to patch
ldy #$0005
lda (reloc_dict_ptr),y
adc base_ptr+2
sta patch_ptr+2 ;high word of patch address
ldy #$0007 ;point to the patch value field
clc
lda (reloc_dict_ptr),y
adc base_ptr
sta patch_value
ldy #$0009
lda (reloc_dict_ptr),y
adc base_ptr+2
sta patch_value+2 ;what we will patch with
clc
lda reloc_dict_ptr ;bump the relocation dictionary pointer please
adc #$000b
sta reloc_dict_ptr
bcc @low_only
inc reloc_dict_ptr+2 ;don't forget the high byte please
lda reloc_dict_ptr+1
pha
plb
plb ;setup for the new bank please
@low_only
jmp shift_patch ;the the patch please
TITLE ', ExpressLoad.a - cReloc_handler'
;====================================================================================================
;
;This routine will process a compressed relocation entry
;
;Structure pointed to by Reloc_dict_ptr
;
; opcode $F5 (1 Byte)
; patch_cnt (1 byte: number of bytes to patch)
; bit_shift (1 byte: (+) = ASL (-) = LSR
; patch_offset (2 bytes: offset from the start of the segment)
; patch_value (2 bytes: offset from the start of the segment)
;
;====================================================================================================
cReloc_handler
ldy #$0001
lda (reloc_dict_ptr),y ;get the patch cnt and bit shift
sep #$20
sta patch_cnt ;the number of bytes to patch 1,2 or 3
xba
sta shift_cnt
rep #$20 ;back to 16 bit mode
ldy #$0003 ;point the patch offset
clc
lda (reloc_dict_ptr),y
adc base_ptr ;base address
sta patch_ptr ;address to patch
lda #$0000
adc base_ptr+2
sta patch_ptr+2 ;high word of patch address
ldy #$0005 ;point to the patch value field
clc
lda (reloc_dict_ptr),y
adc base_ptr
sta patch_value
lda #$0000
adc base_ptr+2
sta patch_value+2 ;what we will patch with
clc
lda reloc_dict_ptr ;bump the relocation dictionary pointer please
adc #$0007
sta reloc_dict_ptr
bcc @low_only
inc reloc_dict_ptr+2 ;don't forget the high byte please
pei reloc_dict_ptr+1
plb
plb ;setup for the new bank please
@low_only
jmp shift_patch ;the the patch please
TITLE ', ExpressLoad.a - Interseg_handler'
;====================================================================================================
;
;This routine will process a Interseg relocation entry
;
;Structure pointed to by Reloc_dict_ptr
;
; opcode $E3 (1 Byte)
; patch_cnt (1 byte: number of bytes to patch)
; bit_shift (1 byte: (+) = ASL (-) = LSR
; patch_offset (4 bytes: offset from the start of the segment)
; file number (2 bytes: file number of load file: not supported yet)
; segment number (2 bytes: segment that we are linking to)
; patch_value (4 bytes: offset from the start of the destination segment)
;
;====================================================================================================
Interseg_handler
ldy #$0001
lda (reloc_dict_ptr),y ;get the patch cnt and bit shift
sep #$20
sta patch_cnt ;the number of bytes to patch 1,2 or 3
xba
sta shift_cnt
rep #$20 ;back to 16 bit mode
ldy #$0003 ;point the patch offset
clc
lda (reloc_dict_ptr),y
adc base_ptr ;base address
sta patch_ptr ;address to patch
ldy #$0005
lda (reloc_dict_ptr),y
adc base_ptr+2
sta patch_ptr+2 ;high word of patch address
ldy #$0007 ;now lets point to the file number
lda (reloc_dict_ptr),y
dec a ;better be one
beq @great
sec
lda #illegal_record
rts ;return the error
@great
ldy #$0009 ;get the segment number
lda (reloc_dict_ptr),y
and #$00FF
jsr get_seg_base
bcc @got_it
rts
@got_it
ldy #$000B ;offset to relative address in destination seg
clc
lda (reloc_dict_ptr),y
adc segment_base
sta patch_value
ldy #$000D
lda (reloc_dict_ptr),y
adc segment_base+2
sta patch_value+2
clc
lda reloc_dict_ptr ;bump the relocation dictionary pointer please
adc #$000F
sta reloc_dict_ptr
bcc @low_only
inc reloc_dict_ptr+2 ;don't forget the high byte please
lda reloc_dict_ptr+1
pha
plb
plb ;setup for the new bank please
@low_only
jmp shift_patch ;patch the segment please
TITLE ', ExpressLoad.a - cInterseg_handler'
;====================================================================================================
;
;This routine will process a compressed Interseg relocation entry
;
;Structure pointed to by Reloc_dict_ptr
;
; opcode $F6 (1 Byte)
; patch_cnt (1 byte: number of bytes to patch)
; bit_shift (1 byte: (+) = ASL (-) = LSR
; patch_offset (2 bytes: offset from the start of the segment)
; segment number (1 bytes: segment that we are linking to)
; patch_value (2 bytes: offset from the start of the destination segment)
;
;====================================================================================================
cInterseg_handler
ldy #$0001
lda (reloc_dict_ptr),y ;get the patch cnt and bit shift
sep #$20
sta patch_cnt ;the number of bytes to patch 1,2 or 3
xba
sta shift_cnt
rep #$20 ;back to 16 bit mode
ldy #$0003 ;point the patch offset
clc
lda (reloc_dict_ptr),y
adc base_ptr ;base address
sta patch_ptr ;address to patch
lda #$0000
adc base_ptr+2
sta patch_ptr+2 ;high word of patch address
ldy #$0005 ;get the segment number
lda (reloc_dict_ptr),y
and #$00FF ;one byte segment number
jsr get_seg_base
bcc @got_it
rts
@got_it
ldy #$0006 ;offset to relative address in destination seg
clc
lda (reloc_dict_ptr),y
adc segment_base
sta patch_value
lda #$0000
adc segment_base+2
sta patch_value+2
clc
lda reloc_dict_ptr ;bump the relocation dictionary pointer please
adc #$0008
sta reloc_dict_ptr
bcc @low_only
inc reloc_dict_ptr+2 ;don't forget the high byte please
lda reloc_dict_ptr+1
pha
plb
plb ;setup for the new bank please
@low_only
jmp shift_patch ;patch the segment please
TITLE ', ExpressLoad.a - super_handler'
;====================================================================================================
;super_handler This one is a bitch.
;
;There are several types of super records. Below is the list that I support.
;
; 1) Reloc2
; 2) Reloc3
; 3) Interseg1-Interseg36
;
;
;Super record structure:
;
; opcode $F7 ;byte
; ------------------------
; size of record ;long
; ------------------------
; record type ;byte
; ------------------------
; patch info: example
;
; $01 ;patch two bytes in page one of load segment
; $34 ;offset to 1st byte in page one of load segment
; $7A ;offset to 2nd byte in page one of load segment
; $81 ;skip 1 page. (High bit means lower 7 bits contain skip cnt)
; $00 ;patch one byte in page three of load segment
; $82 ;offset in page three to patch
;
;====================================================================================================
super_handler
lda base_ptr ;address of the segment
sta temp_ptr
lda base_ptr+2
sta temp_ptr+2
clc
lda reloc_dict_ptr
adc #$0006 ;pass the record type
sta super_ptr
lda reloc_dict_ptr+2
adc #$0000
sta super_ptr+2
ldy #$0001 ;get the total count of entries please
lda (reloc_dict_ptr),y ;get the size of the Super Record
sta super_size
dec a ;remove one for the opcode byte
sta cnt_word
ldy #$0003
lda (reloc_dict_ptr),y ;fail if non-zero
beq @size_ok
sec
lda #illegal_record
rts ;return the error
@size_ok
ldy #$0005 ;pass the size field
lda (reloc_dict_ptr),y
and #$00FF ;clear the garbage
tax
beq @reloc2_type ;do a reloc 2 type
dec a
beq @reloc3_type
;
;If we get here we know that this is an Interseg Record of some kind
;
txa ;get back the kind again
cmp #26
bcc @chk_14
jsr Interseg_26
bra @end_super ;we are done
@chk_14
cmp #14
bcc @one_thru_12
jsr Interseg_14 ;do the conversion
bra @end_super
@one_thru_12
jsr Interseg_1
bra @end_super
@reloc2_type
jsr reloc2
bra @end_super
@reloc3_type
jsr reloc3
@end_super
bcs @abort
lda super_size ;size of the data area
adc #$0005 ;overhead in record
clc
adc reloc_dict_ptr ;bump the relocation dictionary pointer please
sta reloc_dict_ptr
bcc @low_only
inc reloc_dict_ptr+2 ;don't forget the high byte please
lda reloc_dict_ptr+1
pha
plb
plb ;setup for the new bank please
@low_only
clc
@abort
rts
TITLE ', ExpressLoad.a - Interseg_1'
;====================================================================================================
;Interseg1 This routine is used to patch Super interseg records 1 thru 12:
;
;structure:
;
; If the opcode field is 3 thru 13 then this value indicates
; the file number (plus 1) to load from. I do not support this.
;
; relocation information is in the operand field of load segment.
; Format:
; Offset ;word
; segment number ;byte number of segment to link to.
;
;
;====================================================================================================
Interseg_1
ldy #$0005 ;lets get the segment number
lda (reloc_dict_ptr),y
and #$00FF ;get the record type
cmp #$0003 ;is the number 2 thru 12?
bcc @good_seg
lda #illegal_record ;sorry illegal record type
@good_seg
ldy #$0000
lda cnt_word ;see if we are done yet
beq @done
@outter_loop
lda [super_ptr],y ;get the command (8 Bits)
bit #$0080 ;clear all but the pages bit
beq @do_inner_loop ;process the relocation info
and #$007F ;get the number of pages to skip
xba ;multiply the number times 256
clc
adc temp_ptr
sta temp_ptr
bcc @low_only
inc temp_ptr+2
@low_only
iny ;bump index to the next byte
dec cnt_word ;reduce the count by one
bne @outter_loop
@done
clc
rts ;we are done
@do_inner_loop
and #$007F ;number of entries we have to patch
tax
@inner_loop
dec cnt_word ;reduce the count by one
iny ;bump index to the next byte
lda [super_ptr],y ;A = offset
and #$00FF ;clear garbage
phy ;save the index please
tay
phy ;index to patch area
lda [temp_ptr],y ;get the relative offset in other segment
sta patch_value
iny
iny
lda [temp_ptr],y ;get the segment number to patch to
and #$00FF
jsr get_seg_base ;go and get the segment base address
ply ;get our index back please
bcc @have_segment
ply ;remove super index please
rts ;return the error
@have_segment
clc
lda segment_base
adc patch_value
sta [temp_ptr],y
iny
iny
lda segment_base+2
adc #$0000
sep #$20 ;8 bit store only
sta [temp_ptr],y ;save the new address please
rep #$20 ;16 bit mode
ply ;restore super index
dex
bpl @inner_loop ;process this page
iny ;bump to next byte
inc temp_ptr+1 ;add 256 to the page pointer
dec cnt_word ;reduce the count by one
bne @outter_loop
clc
rts
TITLE ', ExpressLoad.a - Interseg_14'
;====================================================================================================
;Interseg_14 This routine processes interseg 14 thru interseg 24 types.
; This type allows a 16 bit patch with no shifting.
;
;Structure:
;
; The segment number to process is in the opcode byte. To determine
; the real segment number just subtract 13 from the stored value.
;
;====================================================================================================
Interseg_14
ldy #$0005 ;lets get the segment number
sec
lda (reloc_dict_ptr),y
and #$00FF ;get the record type
sbc #13
jsr get_seg_base ;setup the base address for this segment
ldy #$0000 ;init super index
bcc @continue
rts ;return the error
@continue
lda cnt_word ;see if we are done yet
beq @done
@outter_loop
lda [super_ptr],y ;get the command (8 Bits)
bit #$0080 ;clear all but the pages bit
beq @do_inner_loop ;process the relocation info
and #$007F ;get the number of pages to skip
xba ;multiply the number times 256
clc
adc temp_ptr
sta temp_ptr
bcc @low_only
inc temp_ptr+2
@low_only
iny ;bump index to the next byte
dec cnt_word ;reduce the count by one
bne @outter_loop
@done
clc
rts
@do_inner_loop
and #$007F ;number of entries we have to patch
tax
@inner_loop
dec cnt_word ;reduce the count by one
iny ;point to the next byte
lda [super_ptr],y ;A = offset
and #$00FF ;clear garbage
phy ;save super index
tay ;build patch record index
clc ;do the 16 bit patch
lda [temp_ptr],y ;get the relative offset in other segment
adc segment_base
sta [temp_ptr],y
ply ;get back super index
dex
bpl @inner_loop ;process this page
iny ;point to the next byte
inc temp_ptr+1 ;point to the next page please
dec cnt_word ;reduce the count by one
bne @outter_loop
clc
rts
TITLE ', ExpressLoad.a - Interseg_26'
;====================================================================================================
;Interseg_26 This routine processes interseg 25 thru interseg 36 types.
; This type allows a 16 bit patch with 16 bit shifting.
;
;Structure:
;
; The segment number to process is in the opcode byte. To determine
; the real segment number just subtract 25 from the stored value.
;====================================================================================================
Interseg_26
ldy #$0005 ;lets get the segment number
sec
lda (reloc_dict_ptr),y
and #$00FF ;get the record type
sbc #25
jsr get_seg_base ;setup the base address for this segment
ldy #$0000 ;init the super index pointer
bcc @continue
rts ;return the error
@continue
lda cnt_word ;see if we are done yet
beq @done
@outter_loop
lda [super_ptr],y ;get the command (8 Bits)
bit #$0080 ;clear all but the pages bit
beq @do_inner_loop ;process the relocation info
and #$007F ;get the number of pages to skip
xba ;multiply the number times 256
clc
adc temp_ptr
sta temp_ptr
bcc @low_only
inc temp_ptr+2
@low_only
iny ;bump index to point to the next byte
dec cnt_word ;reduce the count by one
bne @outter_loop
@done
clc
rts
@do_inner_loop
and #$007F ;number of entries we have to patch
tax
@inner_loop
dec cnt_word ;reduce the count by one
iny ;point to the next byte
lda [super_ptr],y ;A = offset
and #$00FF ;clear garbage
phy ;save super index
tay ;build index to patch address
lda [temp_ptr],y ;get the relative offset in other segment
sta patch_value
clc ;do the 16 bit patch
lda segment_base
adc patch_value
lda segment_base+2 ;store the upper 16 bits only
adc #$0000
sta [temp_ptr],y
ply ;restore super index
dex
bpl @inner_loop ;process this page
iny ;point to the next byte
inc temp_ptr+1 ;bump to the next page
dec cnt_word ;reduce the count by one
bne @outter_loop
clc
rts
TITLE ', ExpressLoad.a - reloc2'
;====================================================================================================
reloc2
ldy #$0000 ;init the index
@outter_loop
lda cnt_word ;see if we are done yet
bne @not_yet
clc
rts ;we are done
@not_yet
lda [super_ptr],y ;get the command (8 Bits)
bit #$0080 ;clear all but the pages bit
beq @do_inner_loop ;process the relocation info
and #$007F ;get the number of pages to skip
xba ;multiply the number times 256
clc
adc temp_ptr
sta temp_ptr
bcc @low_only
inc temp_ptr+2
@low_only
dec cnt_word ;reduce the count by one
iny ;bump index to the next byte
bra @outter_loop
@do_inner_loop
and #$007F ;number of entries we have to patch
tax
@inner_loop
dec cnt_word ;reduce the count by one
iny ;point to the next index please
lda [super_ptr],y ;A = offset
and #$00FF ;clear garbage
phy ;save super index
tay ;build index to the patch area
clc
lda [temp_ptr],y ;get the relative offset to patch with
adc base_ptr ;base address of segment
sta [temp_ptr],y
ply ;restore super index
dex
bpl @inner_loop ;process this page
dec cnt_word ;reduce the count by one
iny ;point to the next byte
inc temp_ptr+1 ;point to the next page please
bra @outter_loop
TITLE ', ExpressLoad.a - reloc3'
;====================================================================================================
reloc3
ldy #$0000 ;init super index to zero
@outter_loop
lda cnt_word ;see if we are done yet
bne @not_yet
clc
rts ;we are done
@not_yet
lda [super_ptr],y ;get the command (8 Bits)
bit #$0080 ;clear all but the pages bit
beq @do_inner_loop ;process the relocation info
and #$007F ;get the number of pages to skip
xba ;multiply the number times 256
clc
adc temp_ptr
sta temp_ptr
bcc @low_only
inc temp_ptr+2
@low_only
dec cnt_word ;reduce the count by one
iny ;point to next byte
bra @outter_loop
@do_inner_loop
and #$007F ;number of entries we have to patch
tax
@inner_loop
dec cnt_word ;reduce the count by one
iny ;point to next byte in super record
lda [super_ptr],y ;A = offset
and #$00FF ;clear garbage
phy ;save the super index please
tay
clc
lda [temp_ptr],y ;get the relative offset to patch with
adc base_ptr ;base address of segment
sta [temp_ptr],y
iny
iny
sep #$20 ;8 bit accumulator
lda [temp_ptr],y
adc base_ptr+2
sta [temp_ptr],y ;save the third byte please
rep #$20 ;16 bit accumulator
ply ;restore super index
dex
bpl @inner_loop ;process this page
dec cnt_word ;reduce the count by one
iny ;bump super record index
inc temp_ptr+1 ;bump to the next page please
bra @outter_loop
;====================================================================================================
;End_handler: Just sets the flag indicating that we are done.
;====================================================================================================
end_handler
; lda #$FFFF
; sta >end_found ;indicate that we are done!!!
rts
TITLE ', ExpressLoad.a - shift_patch'
;====================================================================================================
;
;Below is the common patch code. This code will do the relocation of the operand field
;
;====================================================================================================
shift_patch
longa off
sep #$20
lda shift_cnt ;number of times to shift
beq @no_shift ;very common case
cmp #$F0 ;load the 3rd byte of address
beq @skip_16_bits
cmp #$F8 ;load the 2nd byte of address
beq @skip_8_bits
;
;we have now handled the common cases. So lets do the odd cases now
;
lda shift_cnt
bpl @shift_left ;not a commom case
sec
lda #$00
sbc shift_cnt ;convert twos compliment please
;
;do the slow shift right
;
longa on
rep #$20 ;back to 16 bit mode
and #$00FF ;clear garbage
tax ;count
@right_loop
lsr patch_value+2
ror patch_value ;shift by amount in x
dex
bne @right_loop
bra patch_it ;continue the patch
@shift_left
longa on
rep #$20
and #$00FF
tax
@left_loop
asl patch_value
rol patch_value+2
dex
bne @left_loop ;shift the correct amount
bra patch_it ;continue the patch
@skip_16_bits ;equals a shift 16
longa on
rep #$20
lda patch_value+2 ;get the high word please
sta patch_value
bra patch_it
@skip_8_bits ;equals a shift 8
longa on
rep #$20
lda patch_value+1
sta patch_value
bra patch_it
@no_shift ;equals no shift
longa on
rep #$20
patch_it
ldy #$0000
lda patch_cnt ;number of bytes to patch
asl a
tax
lda >quick_jump-2,x
pha
rts
quick_jump
dc.w one_byte-1
dc.w two_byte-1
dc.w three_byte-1
dc.w four_byte-1
one_byte
sep #$20
lda patch_value
sta [patch_ptr] ;store the value
rep #$20
clc
rts
two_byte
lda patch_value
sta [patch_ptr]
clc
rts
three_byte
lda patch_value
sta [patch_ptr]
ldy #$0001
lda patch_value+1
sta [patch_ptr],y
clc
rts
four_byte
ldy #$0002
lda patch_value
sta [patch_ptr]
lda patch_value+2
sta [patch_ptr],y
clc
rts
endp
TITLE ', ExpressLoad.a - read_less_64k'
;====================================================================================================
;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
with DirectPage, Globals
stz |PRead.requestCount+2
sta |PRead.requestCount
export read_wBuf_ptr
read_wBuf_ptr
stx |PRead.dataBuffer
sty |PRead.dataBuffer+2
jsr lock_handles
jsl $e100a8
dc.w PD_READ ;class 0 read call
dc.l PRead
jsr unlock_handles
bcs @exit
lda |PRead.transferCount
adc local_mark ;bump the local mark please
sta local_mark
lda |PRead.transferCount+2
adc local_mark+2
sta local_mark+2
lda #$0000
clc
@exit
rts
endp
TITLE ', ExpressLoad.a - set_mark'
;====================================================================================================
;set_mark: This routine will set the current file position
;
;
;Input: A = undefined
; 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
with DirectPage, Globals
stx |PSetMark.position
sty |PSetMark.position+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 SET_MARK ;class 0 set mark call
dc.l PSetMark
jsr unlock_handles
bcs @exit
lda |PSetMark.position
sta local_mark ;reset our mark please
lda |PSetMark.position+2
sta local_mark+2
@exit
rts
endp
TITLE ', ExpressLoad.a - check_express_seg'
;====================================================================================================
;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
;
; PathnamePtr pointer to file's pathname
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
check_express_seg proc
with DirectPage, Globals
ldx #Header
ldy #^Header
lda #SegmentHeader.SegHeaderSize ;read in segment header
jsr read_less_64k ;read in less then 64K
bcs @oops
@no_error
lda |PRead.transferCount ;is the segment > $47 bytes
cmp #SegmentHeader.SegHeaderSize
beq @good_size
sec
@oops
rts ;return with error flag
@good_size
lda Header.DispName ;offset to the name
clc
adc #10 ;pass my Name
clc
adc #Header
sta temp_ptr
lda #^Header
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
load_it
rep #$30
clc
rts
sorry_not_express
longa on
longi on
rep #$30
sec
rts
endp
TITLE ', ExpressLoad.a - find_Segment'
;====================================================================================================
;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 DirectPage, Globals
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 #SegHeaderEntry.Kind ;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
inc a ;account for ExpressLoad segment
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
TITLE ', ExpressLoad.a - chk_dynamic_seg'
;====================================================================================================
;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 DirectPage, Globals
jsr make_HET_ptr ;setup pointer to the HETable
lda #dynamic ;Compare to Dynamic BIT
tax ;And Mask (Only Dynamic Bit is important)
ldy #unloaded_state ;only unloaded segments please
jsr find_Segment ;do the search
rts
endp
TITLE ', ExpressLoad.a - save_ref_num'
;====================================================================================================
;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
;
; POpen.refNum ;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 DirectPage, Globals
lda |POpen.fileType ;retrieve returned 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]
sta temp_ptr ;temp now points the link field
lda [ExpressHandle],y
sta temp_ptr+2
lda |POpen.refNum ;save the file reference number since the file
sta [temp_ptr] ; contains Dynamic Segments.
rts
endp
TITLE ', ExpressLoad.a - get_express_seg'
;====================================================================================================
;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
;
; PathnamePtr points to pathname
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
get_express_seg proc
with DirectPage, Globals
clc
lda Header.DispData
adc #$0005 ;Add in LConst overhead
tax
ldy #$0000
jsr set_mark
bcs @error_return
ldx Header.Length ;get the size of the disk image please
stx |PRead.requestCount
ldy Header.Length+2
sty |PRead.requestCount+2
;
;Now we need to add in the pathname overhead + mod date field overhead
;
lda [PathnamePtr] ;get the length of the pathname
clc
adc #10 ;add 2 (for length word) and 8 (for mod date)
clc
adc Header.Length ;add in ExpressLoad segment size
tax ;save request count low
lda #$0000
adc Header.Length+2
tay ;save request count high
jsr alloc_ExpLoad ;get enough memory to hold segment
bcs @error_return
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
;
;Lets go ahead and add the Express Segment into the User ID table
;
lda |USERID ;this is the ID to use
jsr add_user_id ;temp_ptr setup by Add_user_id
bcs @error_return
ldy #ID_Table_Entry.ExpressHandle ;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
bcs @error_return
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
@error_return
rts
TITLE ', ExpressLoad.a - store_pathname'
;====================================================================================================
;
;This routine will add in the pathname stored at [PathnamePtr] 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
;
; PathnamePtr pointer to pathname
; base_ptr pointer to ExpressLoad segment
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;Uses:
;
;====================================================================================================
store_pathname
clc
txa
adc |PRead.requestCount ;build a pointer to the Volume Name Buffer
sta super_ptr ;another temp pointer
tya
adc |PRead.requestCount+2
sta super_ptr+2 ;super_ptr now points past the ExpressLoad segment
ldy #6 ;copy 8 bytes
@store_date_loop
lda POpen.modDateTime,y
sta [super_ptr],y
dey
dey
bpl @store_date_loop
lda super_ptr ;update super_ptr to location for pathname
clc
adc #8
sta super_ptr
bcc @no_bump
inc super_ptr+2
@no_bump
lda [PathnamePtr] ;get the length
sta [super_ptr] ;and store in destination
inc a ;bump by 1 for leading length word
tay ;into indexor
sep #$20 ;8-bit mode
longa off
@store_name_loop
lda [PathnamePtr],y ;copy characters from source
sta [super_ptr],y ;to destination
dey ;continue until back at length word
bne @store_name_loop
rep #$20 ;back to 16-bit accumulator
longa on
ldy #ExpressloadSeg.PathnameOffset ;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
rts
endp
TITLE ', ExpressLoad.a - close_dynamic_file'
;====================================================================================================
;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 DirectPage, Globals
import close_load_file
pei temp_ptr ;save temp pointer please
pei temp_ptr+2
ldy #$0002
clc
lda [ExpressHandle]
sta temp_ptr ;temp now points the link field
lda [ExpressHandle],y
sta temp_ptr+2
lda [temp_ptr] ;see if there is reference number.
beq @exit ;no, just exit with Acc = 0
sta |POpen.refNum ;setup the reference number for closing
lda #$0000 ;zero the reference number in ExpressSegment
sta [temp_ptr]
inc a ;set the pCount
sta PSysPrefs.pCount
jsr lock_handles
jsl $e100a8 ;get the current system preferences
dc.w GetSysPrefs
dc.l PSysPrefs
;
;Save the current user's preference please
;
lda PSysPrefs.preferences
sta 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 PSysPrefs.preferences
jsl $e100a8
dc.w SetSysPrefs ;set the system preference
dc.l PSysPrefs
jsr unlock_handles
jsr close_load_file ;close the file please
lda users_prefs
sta PSysPrefs.preferences
jsr lock_handles
jsl $e100a8
dc.w SetSysPrefs ;restore the caller's system preference
dc.l PSysPrefs
jsr unlock_handles
@exit
plx
stx temp_ptr+2
plx
stx temp_ptr
cmp #$0001
rts ;exit with error if any
endp
TITLE ', ExpressLoad.a - close_load_file'
;====================================================================================================
;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 DirectPage, Globals
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]
sta temp_ptr ;temp now points the reference number field
lda [ExpressHandle],y
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
lda POpen.refNum ;is there a valid refNum?
beq @do_preference ;no, so don't do a global close
jsr lock_handles
jsl $e100a8
dc.w PD_CLOSE ;GS/OS close command
dc.l POpen.refNum
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
plp
pla ;restore the close error if any
rts
endp
TITLE ', ExpressLoad.a - open_load_file'
;====================================================================================================
;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 DirectPage, Globals
;
;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]
sta temp_ptr ;temp now points the reference number field
lda [ExpressHandle],y
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 |POpen.refNum ;save the reference number
lda #app_type ;setup the file type also
sta |POpen.fileType
brl @opened ;say that we already opened the file.
@get_pathname
@do_open
lda #10 ;pCount (return info up to OptionList)
sta |POpen.pCount
lda #$01 ;requestAccess
sta |POpen.requestAccess
sta PSysPrefs.pCount
inc a
sta PGetLevel.pCount
sta PSetLevel.pCount
stz PGetLevel.levelMode
stz PSetLevel.levelMode
stz POpen.resourceNumber ;resourceNumber (data fork always)
lda PathnamePtr ;address of GString
sta |POpen.pathname
lda PathnamePtr+2 ;address of GString
sta |POpen.pathname+2 ;setup the Open Parameter block
jsr lock_handles
jsl $e100a8 ;get the current system preferences
dc.w GetSysPrefs
dc.l PSysPrefs
;
;Save the current user's preference please
;
lda PSysPrefs.preferences
sta 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 PSysPrefs.preferences
jsl $e100a8
dc.w SetSysPrefs ;set the system preference
dc.l PSysPrefs
jsl $e100a8 ;do a get level call to get the current level
dc.w GetLevel
dc.l PGetLevel ;get the level
lda #my_level
sta PSetLevel.level
jsl $e100a8
dc.w SetLevel ;set the current level
dc.l PSetLevel
jsl $e100a8 ;call GS/OS
dc.w Open ;class 1 open call
dc.l POpen
pha
php
jsl $e100a8 ;set back to user's setting
dc.w SetLevel ;set the current level
dc.l PGetLevel ;(just reuse this parm block)
lda users_prefs
sta PSysPrefs.preferences
jsl $e100a8
dc.w SetSysPrefs ;restore the caller's system preference
dc.l PSysPrefs
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 |POpen.refNum ;setup the reference number
sta |PRead.fileRefNum
sta |PGetMark.markRefNum
sta |PSetMark.markRefNum
lda #$0001 ;indicate that the file is open
sta file_open
*** added 18-Aug-92 DAL -- allow file types $003x
lda |POpen.fileType
and #$FFF0
cmp #$0030
beq @chk_length
*** end 18-Aug-92
lda |POpen.fileType ;get returned filetype
cmp #Load_File
bcc @no_way
cmp #Last_Load_File+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 GET_EOF ; GetEOF
dc.l PGetMark
jsr unlock_handles
bcs @oops
lda |PGetMark.position ;is there anything in the file?
ora |PGetMark.position+2
bne @oops ;actually no error
@no_way
lda #not_load_file ;Incompatible file format
sec
@oops
rts ;return error
endp
TITLE ', ExpressLoad.a - conv_attributes'
;====================================================================================================
;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
;
; 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 DirectPage, Globals
ldy #SegHeaderEntry.Kind ;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 ;save temporarily
;
;If the bank size = $10000 then we must set the no_cross bit in the attribute
;
ldx #$0008 ;default is can cross
ldy #SegHeaderEntry.BankSize ;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 #SegHeaderEntry.Align ;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 #SegHeaderEntry.Org ;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 #attr_align_in_bank
tsb mm_attr ;segment is aligned within the bank
;
;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
TITLE ', ExpressLoad.a - reset_jmp_tables'
;====================================================================================================
;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 DirectPage, Globals
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 #HET_Entry.SegFlags ;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 #HET_Entry.SegHandle
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 #JE_FileNum ;see if we are done
lda [temp_ptr],y
beq @done
lda |USERID ;see if this is the user ID
cmp [temp_ptr]
bne @next_entry
ldy #JE_jsl ;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
TITLE ', ExpressLoad.a - make_purgable'
;====================================================================================================
;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 DirectPage, Globals
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 #HET_Entry.SegFlags ;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 #HET_Entry.SegHandle ;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 #HET_Entry.SegFlags ;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
_SetPurge
rts ;return any error
endp
TITLE ', ExpressLoad.a - purge_all_dyn'
;====================================================================================================
;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 DirectPage, Globals
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 #SegHeaderEntry.Kind ;lets check the kind please
lda [seg_header_ptr],y
bpl @skip_it ;skip the segment if it is not dynamic
ldy #HET_Entry.SegFlags ;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
TITLE ', ExpressLoad.a - mark_all_purgable'
;====================================================================================================
;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 DirectPage, Globals
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 |USERID ;push the User ID
pha
_HUnlockAll
;
; purge all other dynamic segments
;
lda |USERID ;push the User ID
pha
_PurgeAll
;
; make all static segments purgeable
;
pea $0003 ;Purge Level
lda |USERID ;push the User ID
pha
_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 #HET_Entry.SegFlags ;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 #HET_Entry.SegHandle ;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 #HET_Entry.SegFlags ;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
TITLE ', ExpressLoad.a - lock_statics'
;====================================================================================================
;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 DirectPage, Globals
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 #HET_Entry.SegFlags ;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 #HET_Entry.SegHandle ;now lets see if the segment has been purged
lda [HET_entry_ptr],y
tax
iny
iny
lda [HET_entry_ptr],y
tay
ora [HET_entry_ptr] ;check for a null handle
bne @handle_OK
@bad_handle
sec
rts ;the handle is scewed up
@handle_OK
stx temp_handle
sty temp_handle+2
ldy #$0002
lda [temp_handle]
ora [temp_handle],y ;valid handle?
beq @bad_handle ;nope
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
_SetPurge
rts ;carry is set based on the call.
@not_static
clc
rts
endp
TITLE ', ExpressLoad.a - lock_segment'
;====================================================================================================
;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 DirectPage, Globals
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 #HET_Entry.SegFlags ;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 #HET_Entry.SegHandle ;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]
ora [temp_handle],y
bne @lock_it
ldy #HET_Entry.SegFlags ;mark segment as gone
lda #$0000
sta [HET_entry_ptr],y
ldy #HET_Entry.SegHandle
sta [HET_entry_ptr],y
iny
iny
sta [HET_entry_ptr],y ;zero the handle also
jsr clear_handles ;clear local copy of handle
_DisposeHandle
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 #HET_Entry.SegFlags ;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
TITLE ', ExpressLoad.a - load_segment'
;====================================================================================================
;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 - Pointer to SegHeaderEntry
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
load_segment proc
with DirectPage, Globals
stz reloc_handle
stz reloc_handle+2
ldy #SegHeaderEntry.RelocDict_Hndl ;set handle to zero
lda #$0000
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 #SegHeaderEntry.LConst_Mark+2
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 #SegHeaderEntry.LConst_Length ;now lets get the size of the segment
lda [seg_header_ptr],y
sta |PRead.requestCount
sta LConst_Size
iny
iny
lda [seg_header_ptr],y ;get the high count
sta |PRead.requestCount+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 #HET_Entry.SegHandle ;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 |PRead.requestCount
ldy |PRead.requestCount+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 |PRead.requestCount
ldy |PRead.requestCount+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 #HET_Entry.SegHandle ;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 #SegHeaderEntry.RelocDict_Mark
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 #SegHeaderEntry.RelocDict_Length ;now lets get the size of the segment
clc
lda [seg_header_ptr],y
adc #$0001
sta |PRead.requestCount
tax
iny
iny
lda [seg_header_ptr],y ;get the high count
adc #$0000
sta |PRead.requestCount+2
tay
lda |PRead.requestCount ;check for a zero length relocation dictionary
dec a
ora |PRead.requestCount+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 #SegHeaderEntry.RelocDict_Hndl ;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 #HET_Entry.SegFlags
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 #HET_Entry.SegFlags ;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 #HET_Entry.SegFlags ;set the static bit please
lda [HET_entry_ptr],y
ora #stat_type
sta [HET_entry_ptr],y
@its_dynamic
clc
rts
entry patch_jmp_tbl
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 #JE_FileNum ;see if we are done
lda [temp_ptr],y
beq @done
lda |USERID ;save the ID please
sta [temp_ptr]
ldy #JE_jsl ;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
bcc @loop
inc temp_ptr+2
bra @loop
@done
rts
Entry add_segment_offset
add_segment_offset
ldy #SegHeaderEntry.Entry ;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
TITLE ', ExpressLoad.a - find_Seg_name'
;====================================================================================================
;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 DirectPage, Globals
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 #SegHeaderEntry.DispName ;get the displacement
lda [seg_header_ptr],y
adc #SegHeaderEntry.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)
ldy #SegHeaderEntry.LabLen ;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
@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
if 0 then ;segment name comparison should be case SENSITIVE
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
else
lda [temp_ptr],y ;get the character
cmp [path_ptr],y ;same as supplied?
bne @not_it ;nope!
endif
@check_next
dey
bne @compare_loop ;keep looking
rep #$30
clc
rts ;We have found the segment!
@not_it
rep #$30
sec
rts
endp
TITLE ', ExpressLoad.a - save_dp_info'
;====================================================================================================
;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 DirectPage, Globals
lda segment_entry ;address of the stack direct page
sta stack_addr
lda LConst_Size ;save the size please
sta stack_size
rts
endp
TITLE ', ExpressLoad.a - load_statics'
;====================================================================================================
;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 DirectPage, Globals
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 #SegHeaderEntry.Kind ;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
jsr lock_handles
lda segment_entry ;address of the segment just loaded
ldy segment_entry+2
jsr Do_Init_Segment
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
TITLE ', ExpressLoad.a - save_start'
;====================================================================================================
;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 DirectPage, Globals
ldy #ID_Table_Entry.Stack_Addr ;save the address of the stack/direct page
lda stack_addr
sta [user_id_ptr],y
ldy #ID_Table_Entry.Stack_Size ;also save the size
lda stack_size
sta [user_id_ptr],y
ldy #ID_Table_Entry.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_Table_Entry.Stack_Addr ;get the address of the stack/direct page
lda [user_id_ptr],y
sta stack_addr
ldy #ID_Table_Entry.Stack_Size ;get save the size
lda [user_id_ptr],y
sta stack_size
ldy #ID_Table_Entry.Start_Addr
lda [user_id_ptr],y
sta starting_addr
iny
iny
lda [user_id_ptr],y
sta starting_addr+2
clc
rts
endp
TITLE ', ExpressLoad.a - reload_restart'
;====================================================================================================
;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 DirectPage, Globals
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 #SegHeaderEntry.Kind
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
TITLE ', ExpressLoad.a - reload_inits'
;====================================================================================================
;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 DirectPage, Globals
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 #SegHeaderEntry.Kind
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 #HET_Entry.SegHandle ;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
TITLE ', ExpressLoad.a - zero_handles'
;====================================================================================================
;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 DirectPage
;
;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
TITLE ', ExpressLoad.a - rename_segments'
;====================================================================================================
;rename_segments: This routine will rename paths for ExpressLoad
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;Output: A = User ID
; X = undefined
; Y =undefined
; P = nvmxdizc
; ..000..1 = not found
; b = k
;
;
;====================================================================================================
longa on
longi on
rename_segments proc
with DirectPage, Globals
newAddr EQU input_parms
oldAddr EQU newAddr+4
ldx user_id_handle
ldy user_id_handle+2
@keep_going
stx temp_handle
sty temp_handle+2
ldy #$0002
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
jsr do_rename ;rename all files in this user_id chunk
ldy #$0004 ;unlock the handle
lda [temp_handle],y
and #$7FFF
sta [temp_handle],y
ldy #User_ID_Table.Next+2 ;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
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 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
Import MemMove
iny
iny ;get the ExpressHandle
lda [user_id_ptr],y
tax
iny
iny
lda [user_id_ptr],y
tay
jsr merge_path ;build a complete pathname
jsr compare_paths ;is this the one?
bcs @no_match ;yup
php ;save partial/full match status
lda ExpressHandle ;copy ExpressHandle into generic variable
sta Handle
lda ExpressHandle+2
sta Handle+2
lda [newAddr] ;get the length of the new name
sec
sbc [oldAddr] ;calculate difference (may be negative)
beq @no_size_change ;if same length, no adjustment necessary
jsr adjust_handle_size ;change the size of the Express Segment buffer
bcs @no_match ;just punt if we get an error
ldy #2 ;deref Handle
lda [Handle]
sta TempZero
lda [Handle],y
sta TempZero+2
ldy #ExpressloadSeg.PathnameOffset
clc
lda [TempZero],y
adc TempZero ;offset to position of pathname within segment
sta PathnamePtr
lda TempZero+2
adc #0
sta PathnamePtr+2
@no_size_change
plp ;retrieve complete/partial match status
jsr change_pathname ;go make the change
@no_match
rts ;else we're done with this one
entry change_pathname
change_pathname
php ;save overflow flag
bvs @full_match ;complete match, go move the new name in
@partial_match
lda [oldAddr] ;get length of matching portion of name
inc a ;adjust for leading length word
inc a
clc
adc PathnamePtr ;calculate address of remainder of name
tax
lda PathnamePtr+2
adc #0
pha ;put source pointer on stack
phx
lda [newAddr] ;get length of new name
inc a ;adjust for leading length word
inc a
clc
adc PathnamePtr ;calculate address of destination
tax
lda PathnamePtr+2
adc #0
pha ;put destination pointer on stack
phx
lda [PathnamePtr] ;get length of Express segment name
sec
sbc [oldAddr] ;calculate length of remainder of name
pha
jsr MemMove ;move the unchanging portion of name in
@full_match
lda [PathnamePtr] ;get length of original name
pha ;save on stack for a bit
pei newAddr+2 ;source pointer
pei newAddr
pei PathnamePtr+2 ;destination address
pei PathnamePtr
lda [newAddr]
inc a ;adjust for leading length word
inc a
pha
jsr MemMove ;move the new name in
pla ;retrieve original length
plp ;complete or partial match?
bvs @done ;complete, so we're done
sta [PathnamePtr] ;save here for a bit
lda [newAddr] ;calculate difference in size
sec
sbc [oldAddr]
clc ;calculate new length
adc [PathnamePtr]
sta [PathnamePtr] ;set new length
@done
rts ;we're done with this name
;====================================================================================================
;
;This routine will resize the ExpressLoad handle as needed
;
;====================================================================================================
entry adjust_handle_size
adjust_handle_size
pha ;save the amount of change
lda #$0000
pha
pha
pei Handle+2 ;push the high word of the handle
pei Handle
_GetHandleSize
ldx #0 ;init high word of difference
lda 5,s ;get difference value
bpl @enlarge ;if positive, must grow the segment
dex ;else sign extend the high word
@enlarge
clc
adc 1,s ;calculate the new size
tay ;save here for a second
txa ;do high word
adc 3,s
sta 5,s ;save the value back on the stack
pla ;remove old size
pla
phy ;and put low word of new size on stack
pei Handle+2
pei Handle
_HUnlock ;unlock the handle
; new size is already on stack
pei Handle+2
pei Handle
_SetHandleSize ;SetHandle size for ExpressLoad segment
rts
endp