Add support for auto-segmentation.

This is a new feature where the linker will automatically divide the code into load segments, creating as many segments as necessary to fit it. This relieves the programmer from the need to manually figure out how a large program can be divided into segments.

Auto-segmentation is triggered by the use of the special load segment name AUTOSEG~~~. Using this approach (rather than a flag in the OMF header) allows auto-segmentation to be used with all existing languages that provide a mechanism for specifying load segment names.
This commit is contained in:
Stephen Heumann 2022-08-30 19:32:09 -05:00
parent 3bb2802f2f
commit 085c7c46ca
4 changed files with 137 additions and 8 deletions

View File

@ -298,7 +298,7 @@ sf8 anop
lda progress
beq wh1
puts #'Link Editor 2.0.6',cr=t
puts #'Link Editor 2.1.0 B1',cr=t
wh1 anop

View File

@ -1,9 +1,12 @@
ORCA/Linker 2.0.6
ORCA/Linker 2.1.0 B1
Copyright 1996, Byte Works Inc.
Updated 2021
Updated 2022
-- Change List --------------------------------------------------------------
2.1.0 B1 1. The linker can now automatically divide a large program into
segments. See "Auto-Segmentation," below.
2.0.6 1. The linker could give a spurious error about the relative
address calculation for a BRL instruction if it branched
forward or backward more than 32 KB. Since the address
@ -61,3 +64,21 @@ Updated 2021
-- Documentation Update -----------------------------------------------------
No changes.
-- Changes introduced in ORCA/Linker 2.1.0 ----------------------------------
On the Apple IIGS, programs with more than 64 KB of code have to be divided into multiple load segments. This can be done using the segment directives in the various ORCA languages, but the programmer has to manually manage them, working out how much code would fit in each segment. Changes to a program's code or its compilation options (e.g. debugging or optimization settings) could alter the size of the generated machine code, requiring its segmentation to be changed.
The ORCA linker can now automatically assign code to load segments, avoiding the need to manually change the segmentation based on the code size. If code uses the special load segment name AUTOSEG~~~, the linker will automatically place it into load segments named AUTOSEG~00, AUTOSEG~01, etc., creating as many load segments as necessary to fit the code.
To use this feature in ORCA/C, ORCA/Pascal, or ORCA/Modula-2, simply use those languages' segment directives to specify the load segment name as AUTOSEG~~~ :
segment "AUTOSEG~~~"; (in ORCA/C)
(*$Segment 'AUTOSEG~~~'*) (in ORCA/Pascal or ORCA/Modula-2)
You can place a directive like this at the top of each of your source files or (for ORCA/C) in a pre-include file.
It is also possible to use auto-segmentation for assembly code, but the code must be written to account for the fact that any two program segments using auto-segmentation may wind up in different load segments, and therefore might be placed in different banks at run time.

View File

@ -3,13 +3,13 @@
resource rVersion(1) {
2, /* Major revision */
0, /* Minor revision */
6, /* Bug version */
release, /* Release stage */
0, /* Non-final release # */
1, /* Minor revision */
0, /* Bug version */
beta, /* Release stage */
1, /* Non-final release # */
verUS, /* Region code */
"ORCA/Linker", /* Short version number */
"Copyright 1996, Byte Works, Inc.\n" /* Long version number */
"Updated 2021"
"Updated 2022"

View File

@ -24,6 +24,102 @@ isLibrary ds 2 is the file we are processing a library file?
largeLibFile ds 2 largest library file number
libDisp ds 4 disp in library symbol table
suffix ds 2 suffix letter
autoSegCounter ds 2 auto-segmentation counter (hex string)
autoSegLength ds 4 length of current auto segment
autoSegNamePtr ds 4 pointer to current auto-segment name
* AutoSegment - perform auto-segmentation
* inputs:
* loadNamePtr - load segment name
* segLength - # of bytes of code in the segment
* segAlign - segment alignment factor
* outputs:
* loadNamePtr - modified if using auto-segmentation
AutoSegment start
using SegCommon
using Common
using OutCommon
move4 loadNamePtr,r0 if load seg name is not 'AUTOSEG~~~'
ldy #nameSize-2
lb0 lda [r0],Y
cmp autoSegStr,Y
beq lb0a
rts return
lb0a dey
bpl lb0
lda segAlign perform alignment if necessary
bne lb1
lda segAlign+2
beq lb2
lda #0
lb1 dec a
bit autoSegLength
beq lb2
ora autoSegLength
inc a
sta autoSegLength
bne lb2
inc autoSegLength+2
lb2 add4 autoSegLength,segLength update auto seg length
lda autoSegLength+2 if it is over $10000 bytes
beq lb5
dec a
ora autoSegLength
beq lb5
move4 segLength,autoSegLength set length to seg length
short M update auto-seg counter
lda autoSegCounter+1
inc a
cmp #'9'+1
bne lb3
lda #'A'
lb3 cmp #'F'+1
bne lb3b
lda autoSegCounter
inc a
cmp #'9'+1
bne lb3a
lda #'A'
lb3a sta autoSegCounter
lda #'0'
lb3b sta autoSegCounter+1
long M
ph4 #nameSize make new auto-seg name string
jsr MLalloc
sta r4
sta autoSegNamePtr
stx r4+2
stx autoSegNamePtr+2
ldy #nameSize-2
lda autoSegCounter
bra lb4a
lb4 lda autoSegStr,Y
lb4a sta [r4],Y
bpl lb4
! set load seg name to auto-seg name
lb5 move4 autoSegNamePtr,loadNamePtr
; Local constant
autoSegStr dc c'AUTOSEG~~~'
@ -283,7 +379,17 @@ InitPass start
stz lastFileNumber
stz dataNumber no data areas processed
stz lastDataNumber
lda #'00' initial auto-seg is 'AUTOSEG~00'
sta autoSegCounter
lla autoSegNamePtr,initialAutoSegName
stz autoSegLength initial auto-seg length is 0
stz autoSegLength+2
; Local constant
initialAutoSegName dc c'AUTOSEG~00'
@ -876,6 +982,7 @@ vt0 ldy #version get the segment version number
sta segName+2
move4 segName,loadNamePtr
add4 segName,#10
jsr AutoSegment
jsr FindLoadSegment
ldy #s2numsex verify that numsex = 0
lda [seg],Y
@ -966,6 +1073,7 @@ vo1 cmp #1 branch if not version 1
sta segName+2
move4 segName,loadNamePtr
add4 segName,#10
jsr AutoSegment
jsr FindLoadSegment
ldy #s1numsex verify that numsex = 0
lda [seg],Y