+2003-08-14 Erik Petrich <epetrich@ivorytower.norman.ok.us>
+
+ Fixed numerous bitfield problems.
+
+ * src/SDCC.y: More bitfield related error checking
+ * src/SDCCsymt.h,
+ * src/SDCCsymt.c (compStructSize): fixed bitfield offset calc
+ * support/Util/SDCCerr.h,
+ * support/Util/SDCCerr.c: Added & edited some bitfield err msgs
+ * src/mcs51/gen.c (genPackBits, genUnpackBits): fixed mask bugs
+ * src/ds390/gen.c (genPackBits, genUnpackBits): fixed mask bugs
+ * support/regression/tests/bitfields.c: tests added
+
+2003-08-13 Erik Petrich <epetrich@ivorytower.norman.ok.us>
+
+ Made the constant following the "interrupt" keyword optional. If
+ omitted, the function will not automatically be given an entry
+ in the interrupt vector table (similar to #pragma NOIV, but
+ less syntacticly kludgy). The interrupt number is also now
+ range checked. Also fixed a bug in the high order bit example
+ in the manual.
+
+ * src/SDCC.y
+ * src/SDCCmem.c
+ * src/SDCCglue.c
+ * src/SDCCsymt.h
+ * support/Util/SDCCerr.c
+ * support/Util/SDCCerr.h
+ * doc/sdccman.lyx
+
2003-08-13 Bernhard Held <bernhard@bernhardheld.de>
* src/SDCCcse.c (algebraicOpts): fix bug converting op from value to type
struct_declarator
: declarator
- | ':' constant_expr {
+ | ':' constant_expr {
+ int bitsize;
$$ = newSymbol (genSymName(NestLevel),NestLevel) ;
- $$->bitVar = (int) floatFromVal(constExprValue($2,TRUE));
+ bitsize= (int) floatFromVal(constExprValue($2,TRUE));
+ if (bitsize > (port->s.int_size * 8)) {
+ bitsize = port->s.int_size * 8;
+ werror(E_BITFLD_SIZE, bitsize);
+ }
+ if (!bitsize)
+ bitsize = BITVAR_PAD;
+ $$->bitVar = bitsize;
}
| declarator ':' constant_expr
- {
- $1->bitVar = (int) floatFromVal(constExprValue($3,TRUE));
+ {
+ int bitsize;
+ bitsize= (int) floatFromVal(constExprValue($3,TRUE));
+ if (bitsize > (port->s.int_size * 8)) {
+ bitsize = port->s.int_size * 8;
+ werror(E_BITFLD_SIZE, bitsize);
+ }
+ if (!bitsize) {
+ $$ = newSymbol (genSymName(NestLevel),NestLevel) ;
+ $$->bitVar = BITVAR_PAD;
+ werror(W_BITFLD_NAMED);
+ }
+ else
+ $1->bitVar = bitsize;
}
;
/* create the internal name for this variable */
SNPRINTF (loop->rname, sizeof(loop->rname), "_%s", loop->name);
- loop->offset = (su == UNION ? sum = 0 : sum);
+ if (su == UNION) {
+ sum = 0;
+ bitOffset = 0;
+ }
SPEC_VOLATILE (loop->etype) |= (su == UNION ? 1 : 0);
/* if this is a bit field */
/* change it to a unsigned bit */
SPEC_NOUN (loop->etype) = V_BIT;
SPEC_USIGN (loop->etype) = 1;
- /* check if this fit into the remaining */
- /* bits of this byte else align it to the */
- /* next byte boundary */
- if ((SPEC_BLEN (loop->etype) = loop->bitVar) <= (8 - bitOffset)) {
- SPEC_BSTR (loop->etype) = bitOffset;
- if ((bitOffset += (loop->bitVar % 8)) == 8)
- sum++;
- }
- else /* does not fit */ {
- bitOffset = 0;
- SPEC_BSTR (loop->etype) = bitOffset;
- sum += (loop->bitVar / 8);
- bitOffset += (loop->bitVar % 8);
+ SPEC_BLEN (loop->etype) = loop->bitVar;
+
+ if (loop->bitVar == BITVAR_PAD) {
+ /* A zero length bitfield forces padding */
+ SPEC_BSTR (loop->etype) = bitOffset;
+ SPEC_BLEN (loop->etype) = 0;
+ bitOffset = 8;
+ loop->offset = sum;
}
- /* if this is the last field then pad */
- if (!loop->next && bitOffset && bitOffset != 8) {
- bitOffset = 0;
- sum++;
+ else {
+ if (bitOffset == 8) {
+ bitOffset = 0;
+ sum++;
+ }
+ /* check if this fit into the remaining */
+ /* bits of this byte else align it to the */
+ /* next byte boundary */
+ if (loop->bitVar <= (8 - bitOffset)) {
+ /* fits into current byte */
+ loop->offset = sum;
+ SPEC_BSTR (loop->etype) = bitOffset;
+ bitOffset += loop->bitVar;
+ }
+ else if (!bitOffset) {
+ /* does not fit, but is already byte aligned */
+ loop->offset = sum;
+ SPEC_BSTR (loop->etype) = bitOffset;
+ bitOffset += loop->bitVar;
+ }
+ else {
+ /* does not fit; need to realign first */
+ sum++;
+ loop->offset = (su == UNION ? sum = 0 : sum);
+ bitOffset = 0;
+ SPEC_BSTR (loop->etype) = bitOffset;
+ bitOffset += loop->bitVar;
+ }
+ while (bitOffset>8) {
+ bitOffset -= 8;
+ sum++;
+ }
}
}
else {
+ /* This is a non-bit field. Make sure we are */
+ /* byte aligned first */
+ if (bitOffset) {
+ sum++;
+ loop->offset = (su == UNION ? sum = 0 : sum);
+ bitOffset = 0;
+ }
+ loop->offset = sum;
checkDecl (loop, 1);
sum += getSize (loop->type);
}
loop = loop->next;
- /* if this is not a bitfield but the */
- /* previous one was and did not take */
- /* the whole byte then pad the rest */
- if ((loop && !loop->bitVar) && bitOffset) {
- bitOffset = 0;
- sum++;
- }
-
/* if union then size = sizeof larget field */
- if (su == UNION)
+ if (su == UNION) {
+ /* For UNION, round up after each field */
+ sum += ((bitOffset+7)/8);
usum = max (usum, sum);
+ }
}
+
+ /* For STRUCT, round up after all fields processed */
+ if (su != UNION)
+ sum += ((bitOffset+7)/8);
return (su == UNION ? usum : sum);
}
#define INTNO_MAX 255 /* maximum allowed interrupt number */
#define INTNO_UNSPEC (INTNO_MAX+1) /* interrupt number unspecified */
+#define BITVAR_PAD -1
+
enum {
TYPEOF_INT=1,
TYPEOF_SHORT,
genUnpackBits (operand * result, char *rname, int ptype)
{
int shCnt;
- int rlen;
+ int rlen = 0;
sym_link *etype;
int offset = 0;
+ int rsize;
D (emitcode (";", "genUnpackBits "););
etype = getSpec (operandType (result));
+ rsize = getSize (operandType (result));
/* read the first byte */
switch (ptype)
emitcode ("anl", "a,#!constbyte",
((unsigned char) -1) >> (8 - SPEC_BLEN (etype)));
- aopPut (AOP (result), "a", offset);
- return;
+ aopPut (AOP (result), "a", offset++);
+ goto finish;
}
/* bit field did not fit in a byte */
- rlen = SPEC_BLEN (etype) - 8;
+ rlen = SPEC_BLEN (etype);
aopPut (AOP (result), "a", offset++);
while (1)
if (rlen)
{
- emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (rlen));
- aopPut (AOP (result), "a", offset);
+ emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
+ aopPut (AOP (result), "a", offset++);
}
- return;
+finish:
+ if (offset < rsize)
+ {
+ rsize -=offset;
+ while (rsize--)
+ aopPut (AOP (result), zero, offset++);
+ }
}
operand * right,
char *rname, int p_type)
{
+ int shCount = 0;
int offset = 0;
int rLen;
int blen, bstr;
/* it exactly fits a byte then */
if (SPEC_BLEN (etype) <= 8)
{
+ unsigned char mask = ((unsigned char) (0xFF << (blen + bstr)) |
+ (unsigned char) (0xFF >> (8 - bstr)));
+ shCount = SPEC_BSTR (etype);
+
/* shift left acc */
- AccLsh (SPEC_BSTR (etype));
+ AccLsh (shCount);
if (SPEC_BLEN (etype) < 8)
{ /* if smaller than a byte */
+ emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
switch (p_type)
{
break;
}
- emitcode ("anl", "a,#!constbyte", (unsigned char)
- ((unsigned char) (0xFF << (blen + bstr)) |
- (unsigned char) (0xFF >> (8 - bstr))));
+ emitcode ("anl", "a,#!constbyte", mask);
emitcode ("orl", "a,b");
if (p_type == GPOINTER)
emitcode ("pop", "b");
/* last last was not complete */
if (rLen)
{
+ emitcode ("anl", "a,#!constbyte",
+ (~(((unsigned char) -1 << rLen) & 0xff)) & 0xff);
+
/* save the byte & read byte */
switch (p_type)
{
break;
}
- emitcode ("anl", "a,#!constbyte", ((unsigned char) -1 << rLen));
+ emitcode ("anl", "a,#!constbyte", (((unsigned char) -1 << rLen) & 0xff));
emitcode ("orl", "a,b");
}
if (rlen)
{
- // emitcode("anl","a,#0x%02x",((unsigned char)-1)>>(rlen));
- AccLsh (8 - rlen);
+ emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
}
while (rsize--)
aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
}
- return;
}
/* it exactly fits a byte then */
if (SPEC_BLEN (etype) <= 8)
{
+ unsigned char mask = ((unsigned char) (0xFF << (blen + bstr)) |
+ (unsigned char) (0xFF >> (8 - bstr)));
shCount = SPEC_BSTR (etype);
/* shift left acc */
if (SPEC_BLEN (etype) < 8)
{ /* if smaller than a byte */
+ emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
switch (p_type)
{
break;
}
- emitcode ("anl", "a,#0x%02x", (unsigned char)
- ((unsigned char) (0xFF << (blen + bstr)) |
- (unsigned char) (0xFF >> (8 - bstr))));
+ emitcode ("anl", "a,#0x%02x", mask);
emitcode ("orl", "a,b");
if (p_type == GPOINTER)
emitcode ("pop", "b");
/* last last was not complete */
if (rLen)
{
+ emitcode ("anl", "a,#0x%02x",
+ (~(((unsigned char) -1 << rLen) & 0xff)) &0xff);
+
/* save the byte & read byte */
switch (p_type)
{
aopOp (right, ic, FALSE);
aopOp (result, ic, FALSE);
- /* if the result is a bit */
- if (IS_BITVAR(OP_SYMBOL(result)->type))
+ /* if the result is a bit (and not a bitfield) */
+ if (AOP_TYPE (result) == AOP_CRY)
{
/* if the right size is a literal then
we know what the value is */
goto release;
}
+
/* if they are the same size : or less */
if (AOP_SIZE (result) <= AOP_SIZE (right))
{
{ E_INT_REQD, ERROR_LEVEL_ERROR,
"type must be INT for bit field definition" },
{ E_BITFLD_SIZE, ERROR_LEVEL_ERROR,
- "bit field size greater than 16. assuming 16" },
+ "bit field size cannot be greater than int (%d bits)" },
{ W_TRUNCATION, ERROR_LEVEL_WARNING,
"high order truncation might occur" },
{ E_CODE_WRITE, ERROR_LEVEL_ERROR,
"useless declaration (possible use of keyword as variable name)" },
{ E_INT_BAD_INTNO, ERROR_LEVEL_ERROR,
"interrupt number '%u' is not valid" },
+{ W_BITFLD_NAMED, ERROR_LEVEL_WARNING,
+ "ignoring declarator of 0 length bitfield" },
};
/*
#define W_INT_OVL 165 /* integer overflow in expression */
#define W_USELESS_DECL 166 /* useless declaration */
#define E_INT_BAD_INTNO 167 /* invalid interrupt number */
+#define W_BITFLD_NAMED 168 /* declarator used with 0 length bitfield */
/** Describes the maximum error level that will be logged. Any level
* includes all of the levels listed after it.
struct {
char c0_3 : 3;
char c3_5 : 5;
-} c_bitfield;
+} c_bf;
struct {
int i0_7 : 7;
int i7_9 : 9;
-} i_bitfield;
+} i_bf;
struct {
long l0_7 : 7;
long l7_10 : 10;
long l17_15 : 15;
-} l_bitfield;
+} l_bf;
+
+
+struct {
+ unsigned int b0 : 1;
+ unsigned int b1 : 1;
+ unsigned int b2 : 1;
+ unsigned int b3 : 1;
+ unsigned int b4 : 1;
+ unsigned int b5 : 1;
+ unsigned int b6 : 1;
+ unsigned int b7 : 1;
+ unsigned int b8 : 1;
+ unsigned int b9 : 1;
+} sb_bf;
+
+struct {
+ unsigned int b0 : 1;
+ unsigned int b2 : 1;
+} size1a_bf;
+
+struct {
+ unsigned int b0 : 1;
+ unsigned int b1 : 1;
+ unsigned int : 0;
+} size1b_bf;
+
+struct {
+ unsigned int b0 : 1;
+ unsigned int b1 : 1;
+ unsigned int b2 : 6;
+} size1c_bf;
+
+struct {
+ unsigned int b0 : 1;
+ unsigned int : 0;
+ unsigned int b1 : 1;
+} size2a_bf;
+
+struct {
+ unsigned int b0 : 1;
+ unsigned int b1 : 1;
+ unsigned int b2 : 1;
+ unsigned int b3 : 1;
+ unsigned int b4 : 1;
+ unsigned int b5 : 1;
+ unsigned int b6 : 1;
+ unsigned int b7 : 1;
+ unsigned int b8 : 1;
+ unsigned int b9 : 1;
+} size2b_bf;
+
+struct {
+ unsigned int b0 : 4;
+ unsigned int b1 : 5;
+} size2c_bf;
+
+struct {
+ unsigned int b0 : 12;
+ unsigned int b1 : 3;
+} size2d_bf;
+
+struct {
+ unsigned int b0 : 3;
+ unsigned int b1 : 12;
+} size3a_bf;
+
+
+void
+testBitfieldSizeof(void)
+{
+ /* Although bitfields are extremely implementation dependant, these
+ assertions should hold for all implementations with storage units
+ of 8 bits or larger (nearly universal).
+ */
+ ASSERT( sizeof(size1a_bf) >= 1);
+ ASSERT( sizeof(size1b_bf) >= 1);
+ ASSERT( sizeof(size1c_bf) >= 1);
+ ASSERT( sizeof(size2a_bf) >= 2);
+ ASSERT( sizeof(size2b_bf) >= 2);
+ ASSERT( sizeof(size2c_bf) >= 2);
+ ASSERT( sizeof(size2d_bf) >= 2);
+ ASSERT( sizeof(size3a_bf) >= 2);
+ ASSERT( sizeof(size1a_bf) == sizeof(size1b_bf));
+ ASSERT( sizeof(size1a_bf) < sizeof(size2a_bf));
+
+ /* Some SDCC specific assertions. SDCC uses 8 bit storage units.
+ Bitfields that are less than 8 bits, but would (due to earlier
+ bitfield declarations) span a storage unit boundary are
+ realigned to the next storage unit boundary. Bitfields of
+ 8 or greater bits are always aligned to start on a storage
+ unit boundary.
+ */
+#ifdef SDCC
+ ASSERT( sizeof(size1a_bf) == 1);
+ ASSERT( sizeof(size1b_bf) == 1);
+ ASSERT( sizeof(size1c_bf) == 1);
+ ASSERT( sizeof(size2a_bf) == 2);
+ ASSERT( sizeof(size2b_bf) == 2);
+ ASSERT( sizeof(size2c_bf) == 2);
+ ASSERT( sizeof(size2d_bf) == 2);
+ ASSERT( sizeof(size3a_bf) == 3);
+#endif
+}
+
+
+void
+testBitfieldsSingleBitLiteral(void)
+{
+#if !defined(SDCC_z80) && !defined(SDCC_gbz80)
+ size2b_bf.b0 = 0;
+ size2b_bf.b1 = 0;
+ size2b_bf.b2 = 0;
+ size2b_bf.b3 = 0;
+ size2b_bf.b4 = 0;
+ size2b_bf.b5 = 0;
+ size2b_bf.b6 = 0;
+ size2b_bf.b7 = 0;
+ size2b_bf.b8 = 0;
+ size2b_bf.b9 = 0;
+
+ /* make sure modulo 2 truncation works */
+ size2b_bf.b0 = 0x3fe;
+ ASSERT(size2b_bf.b0==0);
+ ASSERT(size2b_bf.b1==0);
+ ASSERT(size2b_bf.b2==0);
+ ASSERT(size2b_bf.b3==0);
+ ASSERT(size2b_bf.b4==0);
+ ASSERT(size2b_bf.b5==0);
+ ASSERT(size2b_bf.b6==0);
+ ASSERT(size2b_bf.b7==0);
+ ASSERT(size2b_bf.b8==0);
+ ASSERT(size2b_bf.b9==0);
+ size2b_bf.b0 = 0x3ff;
+ ASSERT(size2b_bf.b0==1);
+ ASSERT(size2b_bf.b1==0);
+ ASSERT(size2b_bf.b2==0);
+ ASSERT(size2b_bf.b3==0);
+ ASSERT(size2b_bf.b4==0);
+ ASSERT(size2b_bf.b5==0);
+ ASSERT(size2b_bf.b6==0);
+ ASSERT(size2b_bf.b7==0);
+ ASSERT(size2b_bf.b8==0);
+ ASSERT(size2b_bf.b9==0);
+
+ /* make sure both bytes work */
+ size2b_bf.b9 = 0x3ff;
+ ASSERT(size2b_bf.b0==1);
+ ASSERT(size2b_bf.b1==0);
+ ASSERT(size2b_bf.b2==0);
+ ASSERT(size2b_bf.b3==0);
+ ASSERT(size2b_bf.b4==0);
+ ASSERT(size2b_bf.b5==0);
+ ASSERT(size2b_bf.b6==0);
+ ASSERT(size2b_bf.b7==0);
+ ASSERT(size2b_bf.b8==0);
+ ASSERT(size2b_bf.b9==1);
+#endif
+}
+
+void
+testBitfieldsSingleBit(void)
+{
+#if !defined(SDCC_z80) && !defined(SDCC_gbz80)
+ volatile unsigned char c;
+
+ c = 0;
+ size2b_bf.b0 = c;
+ size2b_bf.b1 = c;
+ size2b_bf.b2 = c;
+ size2b_bf.b3 = c;
+ size2b_bf.b4 = c;
+ size2b_bf.b5 = c;
+ size2b_bf.b6 = c;
+ size2b_bf.b7 = c;
+ size2b_bf.b8 = c;
+ size2b_bf.b9 = c;
+
+ /* make sure modulo 2 truncation works */
+ c = 0xfe;
+ size2b_bf.b0 = c;
+ ASSERT(size2b_bf.b0==0);
+ ASSERT(size2b_bf.b1==0);
+ ASSERT(size2b_bf.b2==0);
+ ASSERT(size2b_bf.b3==0);
+ ASSERT(size2b_bf.b4==0);
+ ASSERT(size2b_bf.b5==0);
+ ASSERT(size2b_bf.b6==0);
+ ASSERT(size2b_bf.b7==0);
+ ASSERT(size2b_bf.b8==0);
+ ASSERT(size2b_bf.b9==0);
+ c++;
+ size2b_bf.b0 = c;
+ ASSERT(size2b_bf.b0==1);
+ ASSERT(size2b_bf.b1==0);
+ ASSERT(size2b_bf.b2==0);
+ ASSERT(size2b_bf.b3==0);
+ ASSERT(size2b_bf.b4==0);
+ ASSERT(size2b_bf.b5==0);
+ ASSERT(size2b_bf.b6==0);
+ ASSERT(size2b_bf.b7==0);
+ ASSERT(size2b_bf.b8==0);
+ ASSERT(size2b_bf.b9==0);
+
+ /* make sure both bytes work */
+ size2b_bf.b9 = c;
+ ASSERT(size2b_bf.b0==1);
+ ASSERT(size2b_bf.b1==0);
+ ASSERT(size2b_bf.b2==0);
+ ASSERT(size2b_bf.b3==0);
+ ASSERT(size2b_bf.b4==0);
+ ASSERT(size2b_bf.b5==0);
+ ASSERT(size2b_bf.b6==0);
+ ASSERT(size2b_bf.b7==0);
+ ASSERT(size2b_bf.b8==0);
+ ASSERT(size2b_bf.b9==1);
+#endif
+}
+
+void
+testBitfieldsMultibit(void)
+{
+#if !defined(SDCC_z80) && !defined(SDCC_gbz80)
+ size2c_bf.b0 = 0xff; /* should truncate to 0x0f */
+ size2c_bf.b1 = 0;
+ ASSERT(size2c_bf.b0==0x0f);
+ ASSERT(size2c_bf.b1==0);
+
+ size2c_bf.b1 = 0xff; /* should truncate to 0x1f */
+ size2c_bf.b0 = 0;
+ ASSERT(size2c_bf.b0==0);
+ ASSERT(size2c_bf.b1==0x1f);
+
+ size2d_bf.b0 = 0xffff; /* should truncate to 0x0fff */
+ size2d_bf.b1 = 0;
+ ASSERT(size2d_bf.b0==0x0fff);
+ ASSERT(size2d_bf.b1==0);
+
+ size2d_bf.b1 = 0xffff; /* should truncate to 0x07 */
+ size2d_bf.b0 = 0;
+ ASSERT(size2d_bf.b0==0);
+ ASSERT(size2d_bf.b1==0x07);
+
+ size2d_bf.b0 = 0x0321;
+ size2d_bf.b1 = 1;
+ ASSERT(size2d_bf.b0==0x0321);
+ ASSERT(size2d_bf.b1==1);
+
+ size2d_bf.b0 = 0x0a46;
+ size2d_bf.b1 = 5;
+ ASSERT(size2d_bf.b0==0x0a46);
+ ASSERT(size2d_bf.b1==5);
+#endif
+}
void
testBitfields(void)