mirror of
https://github.com/marketideas/qasm.git
synced 2026-10-25 13:02:45 +00:00
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.
1 line
27 KiB
Plaintext
1 line
27 KiB
Plaintext
eject
|
|
;====================================================================================================
|
|
;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 = k
|
|
;
|
|
; 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 data
|
|
dec a ;HET table numbers are 0 thru (-n- minus 1)
|
|
sec
|
|
sbc >data.ExpressSeg_pos
|
|
|
|
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 #$0004 ;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
|
|
|
|
eject
|
|
;====================================================================================================
|
|
;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 data
|
|
|
|
sta reloc_seg ;segment numbers are 1 thru -n-
|
|
jsr setup_seg_ptrs ;build pointers to the segment entries
|
|
|
|
IF debug_on=0 GOTO .nobug
|
|
lda #$EEEE
|
|
sta >Rom_debug+4
|
|
.nobug
|
|
;
|
|
;Now we need to setup our Base address for this segment
|
|
;
|
|
ldy #$0004 ;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 #reloc_size_offset ;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 #Reloc_dict_offset ;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 end_found ;indicate there are records to process
|
|
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
|
|
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
|
|
|
|
IF debug_on=0 GOTO .nobug
|
|
lda #$BBBB
|
|
sta >Rom_debug+6
|
|
.nobug
|
|
ldy #Reloc_dict_offset+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
|
|
|
|
ldx #$1002 ;dispose handle
|
|
jsl $e10000
|
|
|
|
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
|
|
|
|
eject
|
|
;====================================================================================================
|
|
;
|
|
;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
|
|
|
|
eject
|
|
;====================================================================================================
|
|
;
|
|
;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
|
|
|
|
eject
|
|
;====================================================================================================
|
|
;
|
|
;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
|
|
|
|
eject
|
|
;====================================================================================================
|
|
;
|
|
;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
|
|
|
|
eject
|
|
;====================================================================================================
|
|
;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
|
|
|
|
eject
|
|
;====================================================================================================
|
|
;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
|
|
|
|
eject
|
|
;====================================================================================================
|
|
;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
|
|
|
|
eject
|
|
;====================================================================================================
|
|
;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
|
|
|
|
eject
|
|
;====================================================================================================
|
|
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
|
|
|
|
eject
|
|
;====================================================================================================
|
|
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
|
|
|
|
eject
|
|
;====================================================================================================
|
|
;
|
|
;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
|
|
|