SDCC : mcs51/gbz80/z80/avr/ds390/pic16/pic14/TININative/xa51/ds400/hc08 2.8.0 #5117 (Mar 23 2008) (MINGW32)
Once the code size crosses 64K, the linker produces garbage.
These two python programs help reproduce it. The first one produces source code: a main program and two large source-code files, and compiles them.
The second one analyzes the resulting .ihx (or .hex) file, looking for gaps or overlaps.
Hope this helps.
#
# GenBig.py
# Written by: Jim Bell (http://jc-bell.com)
#
# This reproduces the SDCC Dallas DS80C400 64K boundary bug.
# It produces three files: Big.c, OtherBig.c and Bug64k1.c
# Big.c and OtherBig.c produce a large number of functions.
# Bug64k1 has the main function that verifies that the highest
# of each Big and OtherBig functions work.
#
# It requires the files from Dallas App Note 3346
# http://www.maxim-ic.com/appnotes.cfm/an_pk/3346
# Put them in the same directory as this script.
#
# This script does the build and link per app note 3346
#
# Fix the SDCC_PATH variable below for your environment.
#
import sys;
import os;
# 247 works, 248 doesn't. w/rominit commented out: 250 works
NUM_FUNCS=252
MAGIC_NUM=249 # 250 if you comment out init_romexport in startup400.a51
SDCC_PATH="C:\\Software\\Open\\app\\SDCC\\bin"
CFLAGS="-mds400 --model-flat24 --stack-10bit"
LFLAGS="-Wl-r --xram-loc 0x10000 --xram-size 0x3fff --code-loc 0x400000"
SDCC = os.path.join(SDCC_PATH, "sdcc");
PACKIHX = os.path.join(SDCC_PATH, "packihx");
ASX = os.path.join(SDCC_PATH, "asx8051");
bigPfx = [ "Big", "OtherBig" ]
mainPfx = "Bug64k1"
def WriteFunc(f, x, pfx):
f.write("""
unsigned long int %(var)s;
void %(func)s(void)
{
if (%(var)s > 1)
{ %(var)s += %(val)d; }
else
{ %(var)s -= 1; }
}
""" %
{
'func' : "F%s%d" % (pfx,x),
'var' : "v%s%d" % (pfx,x),
'val' : x
});
def WriteBigFile(pfxName, nFuncs):
f = file(pfxName + ".c", "w");
print ("%s.c: %s%d" % (pfxName,pfxName,nFuncs))
for x in range(nFuncs):
WriteFunc(f, x+1, pfxName);
f.close();
def WriteMain(baseFn, n):
f = file(baseFn + ".c", "w");
f.write("""
#include <stdio.h>
extern unsigned long vBig%(total)d;
extern void FBig%(total)d(void);
extern unsigned long vOtherBig%(total)d;
extern void FOtherBig%(total)d(void);
void main(void)
{
unsigned long int myVal, myOtherVal;
unsigned long int myRef, myOtherRef;
printf(\"Welcome. Functions:%(total)d.\\n\");
vBig%(total)d= 88;
myRef = 88 + %(total)d;
vOtherBig%(total)d = 9988;
myOtherRef = 9988 + %(total)d;
FBig%(total)d();
myVal = vBig%(total)d;
FOtherBig%(total)d();
myOtherVal = vOtherBig%(total)d;
printf(\"The functions returned. Did they work? %%lu==%%lu? %%lu==%%lu?.\\n\",
myVal, myRef, myOtherVal, myOtherRef);
while (1) { }
}
""" % { 'total' : n});
f.close();
def RunCmd(c):
r = os.system(c)
if (r != 0):
print "\t%s\nFailed: error code %d" % (c,r)
raise SystemExit
def DoCompile(baseFn):
print "Compiling " + baseFn + ".c"
RunCmd("%s %s --no-xinit-opt --codeseg %s -c %s.c" % (SDCC, CFLAGS, baseFn, baseFn));
def DoLink(mainPfx, pfxList):
print "Assembling startup400.a51"
RunCmd(ASX + " -losffgp startup400.a51");
print "Linking";
relList = mainPfx + ".rel startup400.rel";
for b in pfxList:
relList = relList + " " + b + ".rel";
RunCmd("%s %s %s %s -l rominit.lib" % (SDCC, CFLAGS, LFLAGS, relList));
RunCmd("%s %s.ihx > %s.hex" % (PACKIHX, mainPfx, mainPfx));
#
# Main code.
#
n = NUM_FUNCS; #int(sys.argv[1])
# print "Here we are, and sys.argv[1] is ", n
for b in bigPfx:
WriteBigFile(b, n);
WriteMain(mainPfx, n);
for b in bigPfx:
DoCompile(b);
DoCompile(mainPfx);
DoLink(mainPfx, bigPfx);
willWork = ""
if (n > MAGIC_NUM):
willWork = " NOT"
print "\nDone. This should%s work. Load %s.hex" % (willWork, mainPfx)
################### End of GenBig.py ####################
#
# ProcIhx.py -- Analyze the .ihx and .hex linker output files.
#
import sys;
import os;
def Assert(cond):
if (not cond):
raise Exception, "Assertion failed"
# global reptCount;
reptCount = 0;
class Ctxt:
def __init__(self, fn="", ln=0):
self.fileName = fn;
self.lineNum = ln;
pass
def str(self):
return "%s, line %d" % (self.fileName, self.lineNum)
def Report(self, x):
print self.str() + ":", x
global reptCount;
reptCount = reptCount + 1;
#if (reptCount > 10):
# raise SystemExit
class MemBlk:
def __init__(self, addr, hd, ct):
self.addr32 = addr;
self.hexData = hd;
self.fileName = ct.fileName;
self.lineNum = ct.lineNum;
pass;
def NumBytes(self):
return len(self.hexData) / 2;
def Empty(self):
return len(self.hexData) == 0;
def HiBound(self):
return self.addr32 + self.NumBytes();
def LoBound(self):
return self.addr32;
def str(self):
return "%2d b @ %X" % (len(self.hexData)/2, self.addr32);
def Report(self, x):
print self.str() + ": " + x;
def ReadFile(fn, myMem):
addrHi16 = 0;
myMem.clear();
lnCnt = 0;
atEof = False;
fCtxt = Ctxt(fn);
for ln in file(fn, "r"):
lnCnt += 1;
fCtxt.lineNum = lnCnt;
if len(ln) <= 0:
fCtxt.Report("Blank line");
continue
Assert(ln[0] == ':');
# :0E003600E0D0E0D0E0D0E0900103E07458F09C
nData = int(ln[1:3], 16) * 2; # *2 -> hex bytes
# print ln[1:3], " ", ln[3:7], " ", ln[7:9], " ", ln[9:9+nData], " ", ln[9+nData:9+nData+2], ">>>", ln[11+nData:]
addr16 = int(ln[3:7], 16);
recType = ln[7:9]
data = ln[9:9+nData]
if (len(ln) - nData != 12):
fCtxt.Report("Extraneous data: " + ln[11+nData:]);
if (recType == '00'): # data
# store it
if (atEof):
fCtxt.Report("Data found after EOF");
addr32 = addrHi16 | addr16;
if (addr32 in myMem):
fCtxt.Report("Memory already defined, line " + myMem[addr32].str());
else:
myMem[addr32] = MemBlk(addr32, data, fCtxt);
elif (recType == '01'): # EOF
atEof = True;
elif (recType == '02'): # Extended Segment Address
fCtxt.Report("We don't consider extended segment address records");
elif (recType == '04'):
if (len(data) != 4):
fCtxt.Report("Expecting 4 hex-digits of extended linear address, but found '%s'" % data);
addrHi16 = int(data, 16) << 16;
fCtxt.Report("Extended linear address %X" % addrHi16);
else:
fCtxt.Report("Unknown record type '%s'" % recType);
# presume the checksum is ok
# post-loop
def CheckMem(myMem):
prevMB = MemBlk(0x400000, "", Ctxt(""));
nOvlaps = nGaps = nRecs = 0;
for addr,mb in sorted(myMem.iteritems()):
nRecs += 1;
if (addr == prevMB.addr32) and not prevMB.Empty():
mb.Report("Memory start-overlap w/block " + prevMB.str());
elif (mb.LoBound() < prevMB.HiBound()):
mb.Report("Memory overlap (%d bytes) %s" % (prevMB.HiBound() - mb.LoBound(), prevMB.str()));
nOvlaps += 1;
elif (mb.LoBound() > prevMB.HiBound()):
prevMB.Report(" -- Memory gap (%6d bytes) -- %s" % (mb.LoBound() - prevMB.HiBound(), mb.str()));
nGaps += 1;
prevMB = mb;
print "%d recs: %d gaps; %d overlaps" % (nRecs, nGaps, nOvlaps)
mem1 = dict()
ReadFile("Bug64k1.ihx", mem1);
CheckMem(mem1);
##################### End of ProcIhx.py ####
Logged In: YES
user_id=1804579
Originator: YES
File Added: GenBig.py
Generates big source-code files and builds them.
Logged In: YES
user_id=1804579
Originator: YES
File Added: ProcIhx.py
Looks over the .ihx and .hex output for gaps and overlaps.
Logged In: YES
user_id=1804579
Originator: YES
Please forgive the long code paste. I didn't realize you could add individual files in the follow-up. (I added them there.) Nor did I realize it would zap the indentation, rendering it useless. (FWIW, if you "view source" on the HTML, the indentation's still there.)
Although app note 3346 can still be found on the Dallas website all links to the accompanying libraries are dead. So I think I will not be able to reproduce this bug as it states it requires those files.
Also it is very unclear what the bug actually is. What am I to expect from these scripts and why is that wrong?
I therefore set this bug pending and it will automatically close if nobody responds in the next few weeks. If anyone is interested in getting this fixed I would really prefer to get those generated source files instead of their generator attached. And of course the necessary libraries.
I don't know how this pending item never got closed, so I close it now.