summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2014-02-16 22:25:20 +1100
committerDavid Gibson <david@gibson.dropbear.id.au>2014-03-03 10:51:50 +1100
commit3d3fc9208207dfa40ce21426d556071fb7017085 (patch)
treefdb18ca4697b564f31e2660bbe7ccba028e0992c
parente7f37606f984b3c7663624e5573da18a1d4529e0 (diff)
downloaddevice-tree-compiler-3d3fc9208207dfa40ce21426d556071fb7017085.tar.gz
Implement arrays as expressions
This implements dtc's < ... > array syntax in terms of the new expression infrastructure. Internally this uses two operator types, one to convert an integer expression to a bytestring expression and another to append multiple bytestring expressions together. phandle references require some fiddling. These are implemented by using a constant bytestring expression containing a placeholder plus the marker to substitute in the correct phandle later. Logically it would be neater for an integer expression itself to expand to the right phandle value, but we can't do that just yet since the tree's phandle values aren't all resolved at the time we evaluate expressions. Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
-rw-r--r--dtc-parser.y60
-rw-r--r--dtc.h6
-rw-r--r--expression.c54
3 files changed, 89 insertions, 31 deletions
diff --git a/dtc-parser.y b/dtc-parser.y
index 07cb067..fcc3b4d 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -48,8 +48,8 @@ static struct data expr_bytestring(struct expression *expr);
struct data data;
struct {
- struct data data;
- int bits;
+ int bits;
+ struct expression *expr;
} array;
struct property *prop;
@@ -80,6 +80,7 @@ static struct data expr_bytestring(struct expression *expr);
%type <data> propdataprefix
%type <re> memreserve
%type <re> memreserves
+%type <array> array
%type <array> arrayprefix
%type <data> bytestring_literal
%type <prop> propdef
@@ -216,10 +217,6 @@ propdata:
struct data d = expr_bytestring($2);
$$ = data_merge($1, d);
}
- | propdataprefix arrayprefix '>'
- {
- $$ = data_merge($1, $2.data);
- }
| propdataprefix DT_REF
{
$$ = data_add_marker($1, REF_PATH, $2);
@@ -245,6 +242,10 @@ propdataprefix:
}
;
+array:
+ arrayprefix '>' { $$ = $1; }
+ ;
+
arrayprefix:
DT_BITS DT_LITERAL '<'
{
@@ -259,52 +260,48 @@ arrayprefix:
bits = 32;
}
- $$.data = empty_data;
$$.bits = bits;
+ $$.expr = expression_bytestring_constant(&@$, empty_data);
}
| '<'
{
- $$.data = empty_data;
$$.bits = 32;
+ $$.expr = expression_bytestring_constant(&@$, empty_data);
}
| arrayprefix expr_prim
{
- uint64_t val = expr_int($2);
-
- if ($1.bits < 64) {
- uint64_t mask = (1ULL << $1.bits) - 1;
- /*
- * Bits above mask must either be all zero
- * (positive within range of mask) or all one
- * (negative and sign-extended). The second
- * condition is true if when we set all bits
- * within the mask to one (i.e. | in the
- * mask), all bits are one.
- */
- if ((val > mask) && ((val | mask) != -1ULL))
- ERROR(&@2, "Value out of range for"
- " %d-bit array element", $1.bits);
- }
-
- $$.data = data_append_integer($1.data, val, $1.bits);
+ struct expression *cell = expression_arraycell(&@2,
+ $1.bits,
+ $2);
+ $$.bits = $1.bits;
+ $$.expr = expression_join(&@$, $1.expr, cell);
}
| arrayprefix DT_REF
{
uint64_t val = ~0ULL >> (64 - $1.bits);
+ struct data d = empty_data;
+ struct expression *cell;
if ($1.bits == 32)
- $1.data = data_add_marker($1.data,
- REF_PHANDLE,
- $2);
+ d = data_add_marker(d, REF_PHANDLE, $2);
else
ERROR(&@2, "References are only allowed in "
"arrays with 32-bit elements.");
- $$.data = data_append_integer($1.data, val, $1.bits);
+ d = data_append_integer(d, val, $1.bits);
+ cell = expression_bytestring_constant(&@2, d);
+
+ $$.bits = $1.bits;
+ $$.expr = expression_join(&@$, $1.expr, cell);
}
| arrayprefix DT_LABEL
{
- $$.data = data_add_marker($1.data, LABEL, $2);
+ struct data d = data_add_marker(empty_data, LABEL, $2);
+ struct expression *label;
+
+ label = expression_bytestring_constant(&@2, d);
+ $$.bits = $1.bits;
+ $$.expr = expression_join(&@$, $1.expr, label);
}
;
@@ -333,6 +330,7 @@ expr_prim:
$$ = expression_bytestring_constant(&@2, $2);
}
| expr_incbin
+ | array { $$ = $1.expr; }
| '(' expr ')'
{
$$ = $2;
diff --git a/dtc.h b/dtc.h
index 2ab4ba4..d270626 100644
--- a/dtc.h
+++ b/dtc.h
@@ -246,6 +246,7 @@ struct expression {
int nargs;
union {
struct expression_value constant;
+ int bits;
} u;
struct expression *arg[0];
};
@@ -309,6 +310,11 @@ struct expression *expression_incbin(struct srcpos *loc,
struct expression *file,
struct expression *off,
struct expression *len);
+struct expression *expression_arraycell(struct srcpos *loc, int bits,
+ struct expression *cell);
+struct expression *expression_join(struct srcpos *loc,
+ struct expression *arg0,
+ struct expression *arg1);
/* Boot info (tree plus memreserve information */
diff --git a/expression.c b/expression.c
index 49bc8b0..8d6474b 100644
--- a/expression.c
+++ b/expression.c
@@ -380,3 +380,57 @@ struct expression *expression_incbin(struct srcpos *loc,
{
return expression_build(loc, &op_incbin, file, off, len);
}
+
+static struct expression_value op_eval_arraycell(struct expression *expr,
+ enum expr_type context)
+{
+ uint64_t cellval;
+ struct expression_value v = {
+ .type = EXPR_BYTESTRING,
+ };
+ int bits = expr->u.bits;
+
+ assert(expr->nargs == 1);
+ EVALUATE_INT(cellval, expr->arg[0]);
+
+ v.value.d = data_append_integer(empty_data, cellval, bits);
+ return v;
+}
+static struct operator op_arraycell = {
+ .name = "< >",
+ .evaluate = op_eval_arraycell,
+};
+struct expression *expression_arraycell(struct srcpos *loc, int bits,
+ struct expression *cell)
+{
+ struct expression *expr = expression_build(loc, &op_arraycell, cell);
+
+ expr->u.bits = bits;
+ return expr;
+}
+
+static struct expression_value op_eval_join(struct expression *expr,
+ enum expr_type context)
+{
+ struct data arg0, arg1;
+ struct expression_value v = {
+ .type = EXPR_BYTESTRING,
+ };
+
+ assert(expr->nargs == 2);
+ EVALUATE_BS(arg0, expr->arg[0]);
+ EVALUATE_BS(arg1, expr->arg[1]);
+
+ v.value.d = data_merge(arg0, arg1);
+ return v;
+}
+static struct operator op_join = {
+ .name = ",",
+ .evaluate = op_eval_join,
+};
+struct expression *expression_join(struct srcpos *loc,
+ struct expression *arg0,
+ struct expression *arg1)
+{
+ return expression_build(loc, &op_join, arg0, arg1);
+}