Expand the size of the object buffer from 64K to 128K, and use 32-bit values to track related sizes.

This allows functions that require an OMF segment byte count of up to 128K to be compiled, although the length in memory at run time is still limited to 64K. (The OMF segment byte count is usually larger, due to the size of relocation records, etc.)

This is useful for compiling large functions, e.g. the main interpreter loop in git. It also fixes the bug shown in the compca23 test case, where functions that require a segment of over 64K may appear to compile correctly but generate corrupted OMF segment headers. This related to tracking sizes with 16-bit values that could roll over.

This patch increases the memory needed at run time by 64K. This shouldn’t generally be a problem on systems with sufficient memory, although it does increase the minimum memory requirement a bit. If behavior in low-memory configurations is a concern, buffSize could be made into a run-time option.
This commit is contained in:
Stephen Heumann 2016-11-27 19:11:12 -06:00
parent 41fb05404e
commit 8c81b23b6f
5 changed files with 329 additions and 278 deletions

View File

@ -40,12 +40,12 @@ type
var var
{msc} {msc}
{---} {---}
blkcnt: integer; {number of bytes in current segment} blkcnt: longint; {number of bytes in current segment}
{buffers} {buffers}
{-------} {-------}
cbufflen: 0..maxcbuff; {number of bytes now in cbuff} cbufflen: 0..maxcbuff; {number of bytes now in cbuff}
segDisp: integer; {disp in the current segment} segDisp: longint; {disp in the current segment}
{-- Global subroutines -----------------------------------------} {-- Global subroutines -----------------------------------------}

View File

@ -35,7 +35,7 @@ uses CCommon, CGI, CGC, ObjOut;
type type
labelptr = ^labelentry; {pointer to a forward ref node} labelptr = ^labelentry; {pointer to a forward ref node}
labelentry = record {forward ref node} labelentry = record {forward ref node}
addr: integer; addr: longint;
next: labelptr; next: labelptr;
end; end;
@ -359,7 +359,7 @@ var
end; end;
count: integer; {number of constants to repeat} count: integer; {number of constants to repeat}
i,j,k: integer; {loop variables} i,j,k: integer; {loop variables}
lsegDisp: integer; {for backtracking while writting the } lsegDisp: longint; {for backtracking while writting the }
{ debugger's symbol table } { debugger's symbol table }
lval: longint; {temp storage for long constant} lval: longint; {temp storage for long constant}
nptr: stringPtr; {pointer to a name} nptr: stringPtr; {pointer to a name}
@ -1292,6 +1292,9 @@ Out(0); {end the segment}
segDisp := 8; {update header} segDisp := 8; {update header}
Out2(long(pc).lsw); Out2(long(pc).lsw);
Out2(long(pc).msw); Out2(long(pc).msw);
if pc > $0000FFFF then
if currentSegment <> '~ARRAYS ' then
Error(112);
blkcnt := blkcnt-4; {purge the segment to disk} blkcnt := blkcnt-4; {purge the segment to disk}
segDisp := blkcnt; segDisp := blkcnt;
CloseSeg; CloseSeg;
@ -2218,7 +2221,6 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool
if stackSize <> 0 then begin if stackSize <> 0 then begin
currentSegment := '~_STACK '; {write the header} currentSegment := '~_STACK '; {write the header}
Header(@'~_STACK', $4012, 0); Header(@'~_STACK', $4012, 0);
currentSegment := defaultSegment;
Out($F1); {write the DS record to reserve space} Out($F1); {write the DS record to reserve space}
Out2(stackSize); Out2(stackSize);
Out2(0); Out2(0);

View File

@ -81,7 +81,7 @@ COut start
pha pha
plb plb
jsr OutByte jsr OutByte
inc blkcnt blkcnt := blkcnt+1; inc4 blkcnt blkcnt := blkcnt+1;
inc4 pc pc := pc+1; inc4 pc pc := pc+1;
rtl rtl
end end
@ -105,8 +105,7 @@ Out2 start
pha pha
plb plb
jsr OutWord jsr OutWord
inc blkcnt blkcnt := blkcnt+2; add4 blkcnt,#2 blkcnt := blkcnt+2;
inc blkcnt
rtl rtl
end end
@ -129,7 +128,7 @@ Out start
pha pha
plb plb
jsr OutByte jsr OutByte
inc blkcnt blkcnt := blkcnt+1; inc4 blkcnt blkcnt := blkcnt+1;
rtl rtl
end end
@ -147,15 +146,26 @@ OutByte private
lda objLen if objLen+segDisp = buffSize then lda objLen if objLen+segDisp = buffSize then
clc clc
adc segDisp adc segDisp
bcc lb2 lda objLen+2
adc segDisp+2
and #$FFFE
beq lb2
phx PurgeObjBuffer; phx PurgeObjBuffer;
jsl PurgeObjBuffer jsl PurgeObjBuffer
plx plx
lda objLen check for segment overflow lda objLen check for segment overflow
clc clc
adc segDisp adc segDisp
bcs lb2a lda objLen+2
lb2 ph4 objPtr p := pointer(ord4(objPtr)+segDisp); adc segDisp+2
and #$FFFE
bne lb2a
lb2 anop carry must be clear
lda objPtr+2 p := pointer(ord4(objPtr)+segDisp);
adc segDisp+2
pha
lda objPtr
pha
tsc p^ := b; tsc p^ := b;
phd phd
tcd tcd
@ -164,7 +174,7 @@ lb2 ph4 objPtr p := pointer(ord4(objPtr)+segDisp);
txa txa
sta [1],Y sta [1],Y
long M long M
inc segDisp segDisp := segDisp+1; inc4 segDisp segDisp := segDisp+1;
pld pld
tsc tsc
@ -175,6 +185,7 @@ lb2 ph4 objPtr p := pointer(ord4(objPtr)+segDisp);
lb2a lda #$8000 handle a segment overflow lb2a lda #$8000 handle a segment overflow
sta segDisp sta segDisp
stz segDisp+2
ph2 #112 ph2 #112
jsl Error jsl Error
rts rts
@ -194,24 +205,33 @@ OutWord private
lda objLen if objLen+segDisp+1 = buffSize then lda objLen if objLen+segDisp+1 = buffSize then
sec sec
adc segDisp adc segDisp
bcc lb2 lda objLen+2
adc segDisp+2
and #$FFFE
beq lb2
phx PurgeObjBuffer; phx PurgeObjBuffer;
jsl PurgeObjBuffer jsl PurgeObjBuffer
plx plx
lda objLen check for segment overflow lda objLen check for segment overflow
sec sec
adc segDisp adc segDisp
bcs lb3 lda objLen+2
lb2 ph4 objPtr p := pointer(ord4(objPtr)+segDisp); adc segDisp+2
and #$FFFE
bne lb3
lb2 anop carry must be clear
lda objPtr+2 p := pointer(ord4(objPtr)+segDisp);
adc segDisp+2
pha
lda objPtr
pha
tsc p^ := b; tsc p^ := b;
phd phd
tcd tcd
ldy segDisp ldy segDisp
txa txa
sta [1],Y sta [1],Y
iny segDisp := segDisp+2; add4 segDisp,#2 segDisp := segDisp+2;
iny
sty segDisp save new segDisp
pld pld
tsc tsc
@ -224,5 +244,6 @@ lb3 ph2 #112 flag segment overflow error
jsl Error jsl Error
lda #$8000 lda #$8000
sta segDisp sta segDisp
stz segDisp+2
rts rts
end end

View File

@ -1,253 +1,281 @@
MACRO macro
&LAB LONG &A,&B &l add4 &m1,&m2,&m3
LCLB &I lclb &yistwo
LCLB &M lclc &c
&A AMID &A,1,1 &l ~setm
&M SETB ("&A"="M").OR.("&A"="m") aif c:&m3,.a
&I SETB ("&A"="I").OR.("&A"="i") &c amid "&m2",1,1
AIF C:&B=0,.A aif "&c"<>"#",.a
&B AMID &B,1,1 &c amid "&m1",1,1
&M SETB ("&B"="M").OR.("&B"="m").OR.&M aif "&c"="{",.a
&I SETB ("&B"="I").OR.("&B"="i").OR.&I aif "&c"="[",.a
.A &c amid "&m2",2,l:&m2-1
&LAB REP #&M*32+&I*16 aif &c>=65536,.a
AIF .NOT.&M,.B clc
LONGA ON ~lda &m1
.B ~op adc,&m2
AIF .NOT.&I,.C ~sta &m1
LONGI ON bcc ~&SYSCNT
.C ~op.h inc,&m1
MEND ~&SYSCNT anop
MACRO ago .c
&LAB PH4 &N1 .a
LCLC &C aif c:&m3,.b
&LAB ANOP lclc &m3
&C AMID &N1,1,1 &m3 setc &m1
AIF "&C"="#",.D .b
AIF S:LONGA=1,.A clc
REP #%00100000 ~lda &m1
.A ~op adc,&m2
AIF "&C"<>"{",.B ~sta &m3
&C AMID &N1,L:&N1,1 ~lda.h &m1
AIF "&C"<>"}",.G ~op.h adc,&m2
&N1 AMID &N1,2,L:&N1-2 ~sta.h &m3
LDY #2 .c
LDA (&N1),Y ~restm
PHA mend
LDA (&N1) macro
PHA &l inc4 &a
AGO .E &l ~setm
.B inc &a
AIF "&C"<>"[",.C bne ~&SYSCNT
LDY #2 inc 2+&a
LDA &N1,Y ~&SYSCNT ~restm
PHA mend
LDA &N1 macro
PHA &l long &a,&b
AGO .E lclb &i
.C lclb &m
LDA &N1+2 &a amid &a,1,1
PHA &m setb ("&a"="M").or.("&a"="m")
LDA &N1 &i setb ("&a"="I").or.("&a"="i")
PHA aif c:&b=0,.a
AGO .E &b amid &b,1,1
.D &m setb ("&b"="M").or.("&b"="m").or.&m
&N1 AMID &N1,2,L:&N1-1 &i setb ("&b"="I").or.("&b"="i").or.&i
PEA +(&N1)|-16 .a
PEA &N1 &l rep #&m*32+&i*16
AGO .F aif .not.&m,.b
.E longa on
AIF S:LONGA=1,.F .b
SEP #%00100000 aif .not.&i,.c
.F longi on
MEXIT .c
.G mend
MNOTE "Missing closing '}'",16 macro
MEND &l ph2 &n1
MACRO &l anop
&LAB SHORT &A,&B aif "&n1"="*",.f
LCLB &I lclc &c
LCLB &M &c amid &n1,1,1
&A AMID &A,1,1 aif "&c"="#",.d
&M SETB ("&A"="M").OR.("&A"="m") aif s:longa=1,.a
&I SETB ("&A"="I").OR.("&A"="i") rep #%00100000
AIF C:&B=0,.A .a
&B AMID &B,1,1 aif "&c"<>"{",.b
&M SETB ("&B"="M").OR.("&B"="m").OR.&M &c amid &n1,l:&n1,1
&I SETB ("&B"="I").OR.("&B"="i").OR.&I aif "&c"<>"}",.g
.A &n1 amid &n1,2,l:&n1-2
&LAB SEP #&M*32+&I*16 lda (&n1)
AIF .NOT.&M,.B pha
LONGA OFF ago .e
.B .b
AIF .NOT.&I,.C aif "&c"="<",.c
LONGI OFF lda &n1
.C pha
MEND ago .e
MACRO .c
&LAB INC4 &A &n1 amid &n1,2,l:&n1-1
&LAB ~SETM pei &n1
INC &A ago .e
BNE ~&SYSCNT .d
INC 2+&A &n1 amid &n1,2,l:&n1-1
~&SYSCNT ~RESTM pea &n1
MEND ago .f
MACRO .e
&LAB ~SETM aif s:longa=1,.f
&LAB ANOP sep #%00100000
AIF C:&~LA,.B .f
GBLB &~LA mexit
GBLB &~LI .g
.B mnote "Missing closing '}'",16
&~LA SETB S:LONGA mend
&~LI SETB S:LONGI macro
AIF S:LONGA.AND.S:LONGI,.A &l short &a,&b
REP #32*(.NOT.&~LA)+16*(.NOT.&~LI) lclb &i
LONGA ON lclb &m
LONGI ON &a amid &a,1,1
.A &m setb ("&a"="M").or.("&a"="m")
MEND &i setb ("&a"="I").or.("&a"="i")
MACRO aif c:&b=0,.a
&LAB ~RESTM &b amid &b,1,1
&LAB ANOP &m setb ("&b"="M").or.("&b"="m").or.&m
AIF (&~LA+&~LI)=2,.I &i setb ("&b"="I").or.("&b"="i").or.&i
SEP #32*(.NOT.&~LA)+16*(.NOT.&~LI) .a
AIF &~LA,.H &l sep #&m*32+&i*16
LONGA OFF aif .not.&m,.b
.H longa off
AIF &~LI,.I .b
LONGI OFF aif .not.&i,.c
.I longi off
MEND .c
MACRO mend
&LAB PUT2 &N1,&F1,&CR,&ERROUT macro
AIF C:&F1,.A &l ~lda &op
LCLC &F1 lclc &c
&F1 SETC #0 &c amid "&op",1,1
.A aif "&c"<>"{",.b
&LAB ~SETM &c amid "&op",l:&op,1
PH2 &N1 aif "&c"="}",.a
PH2 &F1 mnote "Missing closing '}'",2
PH2 #C:&CR &op setc &op}
PH2 #C:&ERROUT .a
JSL ~PUT2 &op amid "&op",2,l:&op-2
~RESTM &op setc (&op)
MEND .b
MACRO &l lda &op
&LAB PUT4 &N1,&F1,&CR,&ERROUT mend
AIF C:&F1,.A macro
LCLC &F1 &l ~lda.h &op
&F1 SETC #0 &l anop
.A lclc &c
&LAB ~SETM &c amid "&op",1,1
PH4 &N1 aif "&c"="[",.b
PH2 &F1 aif "&c"<>"{",.d
PH2 #C:&CR &c amid "&op",l:&op,1
PH2 #C:&ERROUT aif "&c"="}",.a
JSL ~PUT4 mnote "Missing closing '}'",2
~RESTM &op setc &op}
MEND .a
MACRO &op amid "&op",2,l:&op-2
&LAB PUTS &N1,&F1,&CR,&ERROUT &op setc (&op)
&LAB ~SETM .b
LCLC &C aif &yistwo,.c
&C AMID "&N1",1,1 &yistwo setb 1
AIF "&C"<>"#",.C ldy #2
AIF L:&N1>127,.A .c
BRA ~&SYSCNT &op setc "&op,y"
AGO .B lda &op
.A mexit
BRL ~&SYSCNT .d
.B aif "&c"<>"#",.e
&N1 AMID "&N1",2,L:&N1-1 &op amid "&op",2,l:&op-1
~L&SYSCNT DC I1"L:~S&SYSCNT" &op setc "#^&op"
~S&SYSCNT DC C&N1 lda &op
~&SYSCNT ANOP mexit
&N1 SETC ~L&SYSCNT-1 .e
AIF C:&F1=0,.D lda 2+&op
.C mend
~PUSHA &N1 macro
AIF C:&F1,.C1 &l ~op &opc,&op
PEA 0 lclc &c
AGO .C2 &c amid "&op",1,1
.C1 aif "&c"<>"{",.b
PH2 &F1 &c amid "&op",l:&op,1
.C2 aif "&c"="}",.a
PH2 #C:&CR mnote "Missing closing '}'",2
PH2 #C:&ERROUT &op setc &op}
JSL ~PUTS .a
~RESTM &op amid "&op",2,l:&op-2
MEXIT &op setc (&op)
.D .b
PEA ~L&SYSCNT|-16 &l &opc &op
PEA ~L&SYSCNT mend
LDX #$1C0C+(C:&ERROUT*256)-(512*C:&CR) macro
JSL $E10000 &l ~op.h &opc,&op
~RESTM &l anop
MEND lclc &c
MACRO &c amid "&op",1,1
&LAB ~PUSHA &N1 aif "&c"="[",.b
LCLC &C aif "&c"<>"{",.d
&LAB ANOP &c amid "&op",l:&op,1
&C AMID &N1,1,1 aif "&c"="}",.a
AIF "&C"<>"{",.B mnote "Missing closing '}'",2
&C AMID &N1,L:&N1,1 &op setc &op}
AIF "&C"<>"}",.G .a
&N1 AMID &N1,2,L:&N1-2 &op amid "&op",2,l:&op-2
SEP #$20 &op setc (&op)
LONGA OFF .b
LDA #0 aif &yistwo,.c
PHA &yistwo setb 1
REP #$20 ldy #2
LONGA ON .c
PHK &op setc "&op,y"
LDA &N1 &opc &op
PHA mexit
MEXIT .d
.B aif "&c"<>"#",.e
AIF "&C"<>"[",.C &op amid "&op",2,l:&op-1
&N1 AMID &N1,2,L:&N1-2 &op setc "#^&op"
LDA &N1+2 &opc &op
PHA mexit
LDA &N1 .e
PHA &opc 2+&op
MEXIT mend
.C macro
PEA +(&N1)|-16 &l ~restm
PEA &N1 &l anop
MEXIT aif (&~la+&~li)=2,.i
.G sep #32*(.not.&~la)+16*(.not.&~li)
MNOTE "Missing closing '}'",16 aif &~la,.h
MEND longa off
MACRO .h
&LAB PH2 &N1 aif &~li,.i
LCLC &C longi off
&LAB ANOP .i
&C AMID &N1,1,1 mend
AIF "&C"="#",.D macro
AIF S:LONGA=1,.A &l ~setm
REP #%00100000 &l anop
.A aif c:&~la,.b
AIF "&C"<>"{",.B gblb &~la
&C AMID &N1,L:&N1,1 gblb &~li
AIF "&C"<>"}",.G .b
&N1 AMID &N1,2,L:&N1-2 &~la setb s:longa
LDA (&N1) &~li setb s:longi
PHA aif s:longa.and.s:longi,.a
AGO .E rep #32*(.not.&~la)+16*(.not.&~li)
.B longa on
LDA &N1 longi on
PHA .a
AGO .E mend
.D macro
&N1 AMID &N1,2,L:&N1-1 &l ~sta &op
PEA &N1 lclc &c
AGO .F &c amid "&op",1,1
.E aif "&c"<>"{",.b
AIF S:LONGA=1,.F &c amid "&op",l:&op,1
SEP #%00100000 aif "&c"="}",.a
.F mnote "Missing closing '}'",2
MEXIT &op setc &op}
.G .a
MNOTE "Missing closing '}'",16 &op amid "&op",2,l:&op-2
MEND &op setc (&op)
.b
&l sta &op
mend
macro
&l ~sta.h &op
&l anop
lclc &c
&c amid "&op",1,1
aif "&c"="[",.b
aif "&c"<>"{",.d
&c amid "&op",l:&op,1
aif "&c"="}",.a
mnote "Missing closing '}'",2
&op setc &op}
.a
&op amid "&op",2,l:&op-2
&op setc (&op)
.b
aif &yistwo,.c
&yistwo setb 1
ldy #2
.c
&op setc "&op,y"
sta &op
mexit
.d
sta 2+&op
mend

View File

@ -139,8 +139,8 @@ implementation
const const
{NOTE: OutByte and Outword assume } {NOTE: OutByte and Outword assume }
{ buffSize is 64K } { buffSize is 128K }
buffSize = 65536; {size of the obj buffer} buffSize = 131072; {size of the obj buffer}
maxCBuffLen = 191; {length of the constant buffer} maxCBuffLen = 191; {length of the constant buffer}
OBJ = $B1; {object file type} OBJ = $B1; {object file type}
@ -313,7 +313,7 @@ if len <> 0 then begin
if ToolError <> 0 then {check for write errors} if ToolError <> 0 then {check for write errors}
TermError(9); TermError(9);
objLen := 0; {adjust file pointers} objLen := 0; {adjust file pointers}
BlockMove(segStart, sPtr, ord4(segDisp) & $00FFFF); BlockMove(segStart, sPtr, segDisp);
objPtr := sPtr; objPtr := sPtr;
segStart := sPtr; segStart := sPtr;
end; {if} end; {if}
@ -436,12 +436,13 @@ var
begin {CloseSeg} begin {CloseSeg}
longPtr := pointer(objPtr); {set the block count} longPtr := pointer(objPtr); {set the block count}
longPtr^ := ord4(segDisp) & $00FFFF; longPtr^ := segDisp;
objLen := objLen + (ord4(segDisp) & $00FFFF); {update the length of the obj file} objLen := objLen + segDisp; {update the length of the obj file}
objPtr := pointer(ord4(objHandle^)+objLen); {set objPtr} objPtr := pointer(ord4(objHandle^)+objLen); {set objPtr}
segStart := objPtr; segStart := objPtr;
if objLen = buffSize then if objLen = buffSize then
PurgeObjBuffer; PurgeObjBuffer;
currentSegment := defaultSegment; {revert to default segment name}
end; {CloseSeg} end; {CloseSeg}
@ -513,7 +514,6 @@ Out2($30); Out2($3B+len);
Out2(0); Out2(0); {temporg} Out2(0); Out2(0); {temporg}
for i := 1 to 10 do {write the segment name} for i := 1 to 10 do {write the segment name}
Out(ord(currentSegment[i])); Out(ord(currentSegment[i]));
currentSegment := defaultSegment; {revert to default segment name}
Out(len); {segname} Out(len); {segname}
for i := 1 to len do for i := 1 to len do
Out(ord(name^[i])); Out(ord(name^[i]));