From 085c7c46ca1aabf3a6e4bd78d9073cbc90ddc3d7 Mon Sep 17 00:00:00 2001 From: Stephen Heumann Date: Tue, 30 Aug 2022 19:32:09 -0500 Subject: [PATCH] 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. --- linker.asm | 2 +- linker.notes | 25 +++++++++++- linker.rez | 10 ++--- seg.asm | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+), 8 deletions(-) diff --git a/linker.asm b/linker.asm index 11b3fff..8ce7b88 100644 --- a/linker.asm +++ b/linker.asm @@ -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 putcr wh1 anop ; diff --git a/linker.notes b/linker.notes index d5fb4cc..1cb0521 100644 --- a/linker.notes +++ b/linker.notes @@ -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 ---------------------------------- + +Auto-Segmentation +----------------- + +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. diff --git a/linker.rez b/linker.rez index 83918f2..337ea0a 100644 --- a/linker.rez +++ b/linker.rez @@ -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" }; diff --git a/seg.asm b/seg.asm index c4e49b6..ff94a14 100644 --- a/seg.asm +++ b/seg.asm @@ -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 + end + +**************************************************************** +* +* 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 + 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 + dey + dey + bpl lb4 +! set load seg name to auto-seg name +lb5 move4 autoSegNamePtr,loadNamePtr + rts +; +; Local constant +; +autoSegStr dc c'AUTOSEG~~~' end **************************************************************** @@ -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 rts +; +; Local constant +; +initialAutoSegName dc c'AUTOSEG~00' end **************************************************************** @@ -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