Skip to content
This repository
tree: e0f82981e7
Fetching contributors…

Cannot retrieve contributors at this time

file 631 lines (495 sloc) 20.456 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
#ifndef __expression_H
#define __expression_H
/*
* Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

# include "StringHeap.h"
# include "LineInfo.h"
# include "entity.h"
# include <inttypes.h>
# include <list>
# include <memory>
# include <vector>

class prange_t;
class Entity;
class Architecture;
class ScopeBase;
class VType;
class VTypeArray;
class VTypePrimitive;

class ExpName;

/*
* The Expression class represents parsed expressions from the parsed
* VHDL input. The Expression class is a virtual class that holds more
* specific derived expression types.
*/
class Expression : public LineInfo {

    public:
      Expression();
      virtual ~Expression() =0;

// This virtual method handles the special case of elaborating
// an expression that is the l-value of a sequential variable
// assignment. This generates an error for most cases, but
// expressions that are valid l-values return 0 and set any
// flags needed to indicate their status as writable variables.
      virtual int elaborate_lval(Entity*ent, Architecture*arc,
bool is_sequ);

// This virtual method probes the expression to get the most
// constrained type for the expression. For a given instance,
// this may be called before the elaborate_expr method.
      virtual const VType*probe_type(Entity*ent, Architecture*arc) const;

// The fit_type virtual method is used by the ExpConcat class
// to probe the type of operands. The atype argument is the
// type of the ExpConcat expression itself. This expression
// returns its type as interpreted in this context. Really,
// this is mostly about helping aggregate expressions within
// concatenations to figure out their type.
      virtual const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const;

// This virtual method elaborates an expression. The ltype is
// the type of the lvalue expression, if known, and can be
// used to calculate the type for the expression being
// elaborated.
      virtual int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);

// Return the type that this expression would be if it were an
// l-value. This should only be called after elaborate_lval is
// called and only if elaborate_lval succeeded.
      inline const VType*peek_type(void) const { return type_; }

// This virtual method writes a VHDL-accurate representation
// of this expression to the designated stream. This is used
// for writing parsed types to library files.
      virtual void write_to_stream(std::ostream&fd) =0;

// The emit virtual method is called by architecture emit to
// output the generated code for the expression. The derived
// class fills in the details of what exactly happened.
      virtual int emit(ostream&out, Entity*ent, Architecture*arc) =0;

// The evaluate virtual method tries to evaluate expressions
// to constant literal values. Return true and set the val
// argument if the evaluation works, or return false if it
// cannot be done.
      virtual bool evaluate(ScopeBase*scope, int64_t&val) const;
      virtual bool evaluate(Entity*ent, Architecture*arc, int64_t&val) const;


// The symbolic compare returns true if the two expressions
// are equal without actually calculating the value.
      virtual bool symbolic_compare(const Expression*that) const;

// This method returns true if the drawn Verilog for this
// expression is a primary. A containing expression can use
// this method to know if it needs to wrap parentheses. This
// is somewhat optional, so it is better to return false if
// not certain. The default implementation does return false.
      virtual bool is_primary(void) const;

// Debug dump of the expression.
      virtual void dump(ostream&out, int indent = 0) const =0;
      virtual ostream& dump_inline(ostream&out) const;

    protected:
// This function is called by the derived class during
// elaboration to set the type of the current expression that
// elaboration assigns to this expression.
      void set_type(const VType*);

    private:
      const VType*type_;

    private: // Not implemented
      Expression(const Expression&);
      Expression& operator = (const Expression&);
};

static inline void FILE_NAME(Expression*tgt, const LineInfo*src)
{
      tgt->set_line(*src);
}

static inline ostream& operator <<(ostream&out, const Expression&exp)
{
      return exp.dump_inline(out);
}

class ExpUnary : public Expression {

    public:
      ExpUnary(Expression*op1);
      virtual ~ExpUnary() =0;

      const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const;

    protected:
      inline void write_to_stream_operand1(std::ostream&fd)
      { operand1_->write_to_stream(fd); }

      int emit_operand1(ostream&out, Entity*ent, Architecture*arc);
      void dump_operand1(ostream&out, int indent = 0) const;

    private:
      Expression*operand1_;
};

/*
* This is an abstract class that collects some of the common features
* of binary operators.
*/
class ExpBinary : public Expression {

    public:
      ExpBinary(Expression*op1, Expression*op2);
      virtual ~ExpBinary() =0;

      const Expression* peek_operand1(void) const { return operand1_; }
      const Expression* peek_operand2(void) const { return operand2_; }

      const VType*probe_type(Entity*ent, Architecture*arc) const;

    protected:

      int elaborate_exprs(Entity*, Architecture*, const VType*);
      int emit_operand1(ostream&out, Entity*ent, Architecture*arc);
      int emit_operand2(ostream&out, Entity*ent, Architecture*arc);

      bool eval_operand1(ScopeBase*scope, int64_t&val) const;
      bool eval_operand2(ScopeBase*scope, int64_t&val) const;

      inline void write_to_stream_operand1(std::ostream&out)
          { operand1_->write_to_stream(out); }
      inline void write_to_stream_operand2(std::ostream&out)
          { operand2_->write_to_stream(out); }

      void dump_operands(ostream&out, int indent = 0) const;

    private:
      Expression*operand1_;
      Expression*operand2_;
};

class ExpAggregate : public Expression {

    public:
// A "choice" is only part of an element. It is the thing that
// is used to identify an element of the aggregate. It can
// represent the index (or range) of an array, or the name of
// a record member.
      class choice_t {
public:
// Create an "others" choice
choice_t();
// Create a simple_expression choice
explicit choice_t(Expression*exp);
// Create a named choice
explicit choice_t(perm_string name);
// discreate_range choice
explicit choice_t(prange_t*ran);
~choice_t();

// true if this represents an "others" choice
bool others() const;
// Return expression if this represents a simple_expression.
Expression*simple_expression(bool detach_flag =true);
// Return prange_t if this represents a range_expression
prange_t*range_expressions(void);

void dump(ostream&out, int indent) const;

private:
std::auto_ptr<Expression>expr_;
std::auto_ptr<prange_t> range_;
private: // not implemented
choice_t(const choice_t&);
choice_t& operator= (const choice_t&);
      };

      struct choice_element {
choice_t*choice;
Expression*expr;
bool alias_flag;
      };

// Elements are the syntactic items in an aggregate
// expression. Each element expressions a bunch of fields
// (choices) and binds them to a single expression
      class element_t {
public:
explicit element_t(std::list<choice_t*>*fields, Expression*val);
~element_t();

size_t count_choices() const { return fields_.size(); }
void map_choices(choice_element*dst);

inline Expression* extract_expression() { return val_; }

void dump(ostream&out, int indent) const;

private:
std::vector<choice_t*>fields_;
Expression*val_;
private: // not implemented
element_t(const element_t&);
element_t& operator = (const element_t&);
      };

    public:
      ExpAggregate(std::list<element_t*>*el);
      ~ExpAggregate();


      const VType*probe_type(Entity*ent, Architecture*arc) const;
      const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const;
      int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
      void write_to_stream(std::ostream&fd);
      int emit(ostream&out, Entity*ent, Architecture*arc);
      void dump(ostream&out, int indent = 0) const;

    private:
      int elaborate_expr_array_(Entity*ent, Architecture*arc, const VTypeArray*ltype);
      int emit_array_(ostream&out, Entity*ent, Architecture*arc, const VTypeArray*ltype);

    private:
// This is the elements as directly parsed.
      std::vector<element_t*> elements_;

// These are the elements after elaboration. This form is
// easier to check and emit.
      std::vector<choice_element> aggregate_;
};

class ExpArithmetic : public ExpBinary {

    public:
      enum fun_t { PLUS, MINUS, MULT, DIV, MOD, REM, POW, xCONCAT };

    public:
      ExpArithmetic(ExpArithmetic::fun_t op, Expression*op1, Expression*op2);
      ~ExpArithmetic();

      int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
      void write_to_stream(std::ostream&fd);
      int emit(ostream&out, Entity*ent, Architecture*arc);
      virtual bool evaluate(ScopeBase*scope, int64_t&val) const;
      void dump(ostream&out, int indent = 0) const;

    private:
      fun_t fun_;
};

class ExpAttribute : public Expression {

    public:
      ExpAttribute(ExpName*base, perm_string name);
      ~ExpAttribute();

      inline perm_string peek_attribute() const { return name_; }
      inline const ExpName* peek_base() const { return base_; }

      const VType*probe_type(Entity*ent, Architecture*arc) const;
      int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
      void write_to_stream(std::ostream&fd);
      int emit(ostream&out, Entity*ent, Architecture*arc);
// Some attributes can be evaluated at compile time
      bool evaluate(ScopeBase*scope, int64_t&val) const;
      bool evaluate(Entity*ent, Architecture*arc, int64_t&val) const;
      void dump(ostream&out, int indent = 0) const;

    private:
      ExpName*base_;
      perm_string name_;
};

class ExpBitstring : public Expression {

    public:
      explicit ExpBitstring(const char*);
      ~ExpBitstring();

      const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const;
      int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
      void write_to_stream(std::ostream&fd);
      int emit(ostream&out, Entity*ent, Architecture*arc);
      void dump(ostream&out, int indent = 0) const;

    private:
      std::vector<char>value_;
};


class ExpCharacter : public Expression {

    public:
      ExpCharacter(char val);
      ~ExpCharacter();

      const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const;
      int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
      void write_to_stream(std::ostream&fd);
      int emit(ostream&out, Entity*ent, Architecture*arc);
      bool is_primary(void) const;
      void dump(ostream&out, int indent = 0) const;

      char value() const { return value_; }

    private:
      int emit_primitive_bit_(ostream&out, Entity*ent, Architecture*arc,
const VTypePrimitive*etype);

    private:
      char value_;
};

class ExpConcat : public Expression {

    public:
      ExpConcat(Expression*op1, Expression*op2);
      ~ExpConcat();

      const VType*probe_type(Entity*ent, Architecture*arc) const;
      int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
      void write_to_stream(std::ostream&fd);
      int emit(ostream&out, Entity*ent, Architecture*arc);
      virtual bool evaluate(ScopeBase*scope, int64_t&val) const;
      bool is_primary(void) const;
      void dump(ostream&out, int indent = 0) const;

    private:
      int elaborate_expr_array_(Entity*ent, Architecture*arc, const VTypeArray*ltype);

    private:
      Expression*operand1_;
      Expression*operand2_;
};

/*
* The conditional expression represents the VHDL when-else
* expressions. Note that by the VHDL syntax rules, these cannot show
* up other than at the root of an expression.
*/
class ExpConditional : public Expression {

    public:
      class else_t : public LineInfo {
public:
else_t(Expression*cond, std::list<Expression*>*tru);
~else_t();

int elaborate_expr(Entity*ent, Architecture*arc, const VType*lt);
int emit_when_else(ostream&out, Entity*ent, Architecture*arc);
int emit_else(ostream&out, Entity*ent, Architecture*arc);
void dump(ostream&out, int indent = 0) const;

private:
Expression*cond_;
std::list<Expression*> true_clause_;
      };

    public:
      ExpConditional(Expression*cond, std::list<Expression*>*tru,
std::list<else_t*>*fal);
      ~ExpConditional();

      const VType*probe_type(Entity*ent, Architecture*arc) const;
      int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
      void write_to_stream(std::ostream&fd);
      int emit(ostream&out, Entity*ent, Architecture*arc);
      void dump(ostream&out, int indent = 0) const;

    private:
      Expression*cond_;
      std::list<Expression*> true_clause_;
      std::list<else_t*> else_clause_;
};

/*
* This is a special expression type that represents posedge/negedge
* expressions in sensitivity lists.
*/
class ExpEdge : public ExpUnary {

    public:
      enum fun_t { NEGEDGE, ANYEDGE, POSEDGE };

    public:
      explicit ExpEdge(ExpEdge::fun_t ty, Expression*op);
      ~ExpEdge();

      inline fun_t edge_fun() const { return fun_; }

      void write_to_stream(std::ostream&fd);
      int emit(ostream&out, Entity*ent, Architecture*arc);
      void dump(ostream&out, int indent = 0) const;

    private:
      fun_t fun_;
};
class ExpFunc : public Expression {

    public:
      explicit ExpFunc(perm_string nn);
      ExpFunc(perm_string nn, std::list<Expression*>*args);
      ~ExpFunc();

    public: // Base methods
      int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
      void write_to_stream(std::ostream&fd);
      int emit(ostream&out, Entity*ent, Architecture*arc);
      void dump(ostream&out, int indent = 0) const;

    private:
      perm_string name_;
      std::vector<Expression*> argv_;
};

class ExpInteger : public Expression {

    public:
      ExpInteger(int64_t val);
      ~ExpInteger();

      const VType*probe_type(Entity*ent, Architecture*arc) const;
      int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
      void write_to_stream(std::ostream&fd);
      int emit(ostream&out, Entity*ent, Architecture*arc);
      bool is_primary(void) const;
      bool evaluate(ScopeBase*scope, int64_t&val) const;
      void dump(ostream&out, int indent = 0) const;
      virtual ostream& dump_inline(ostream&out) const;

    private:
      int64_t value_;
};

class ExpLogical : public ExpBinary {

    public:
      enum fun_t { AND, OR, NAND, NOR, XOR, XNOR };

    public:
      ExpLogical(ExpLogical::fun_t ty, Expression*op1, Expression*op2);
      ~ExpLogical();

      inline fun_t logic_fun() const { return fun_; }

      int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
      void write_to_stream(std::ostream&fd);
      int emit(ostream&out, Entity*ent, Architecture*arc);
      void dump(ostream&out, int indent = 0) const;

    private:
      fun_t fun_;
};

/*
* The ExpName class represents an expression that is an identifier or
* other sort of name. The ExpNameALL is a special case of ExpName
* that represents the "all" keyword is contexts that can handle it.
*/
class ExpName : public Expression {

    public:
      explicit ExpName(perm_string nn);
      ExpName(perm_string nn, std::list<Expression*>*indices);
      ExpName(perm_string nn, Expression*msb, Expression*lsb);
      ExpName(ExpName*prefix, perm_string nn);
      ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb);
      ~ExpName();

    public: // Base methods
      int elaborate_lval(Entity*ent, Architecture*arc, bool);
      int elaborate_rval(Entity*ent, Architecture*arc, const InterfacePort*);
      const VType* probe_type(Entity*ent, Architecture*arc) const;
      const VType* fit_type(Entity*ent, Architecture*arc, const VTypeArray*host) const;
      int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
      void write_to_stream(std::ostream&fd);
      int emit(ostream&out, Entity*ent, Architecture*arc);
      bool is_primary(void) const;
      bool evaluate(ScopeBase*scope, int64_t&val) const;
      bool evaluate(Entity*ent, Architecture*arc, int64_t&val) const;
      bool symbolic_compare(const Expression*that) const;
      void dump(ostream&out, int indent = 0) const;
      const char* name() const;

      void set_range(Expression*msb, Expression*lsb);

    private:
      const VType* elaborate_adjust_type_with_range_(Entity*ent, Architecture*arc, const VType*type);

      int elaborate_lval_(Entity*ent, Architecture*arc, bool, ExpName*suffix);
      const VType* probe_prefix_type_(Entity*ent, Architecture*arc) const;
      const VType* probe_prefixed_type_(Entity*ent, Architecture*arc) const;

      int emit_as_prefix_(ostream&out, Entity*ent, Architecture*arc);

    private:
      std::auto_ptr<ExpName> prefix_;
      perm_string name_;
      Expression*index_;
      Expression*lsb_;
};

class ExpNameALL : public ExpName {

    public:
      ExpNameALL() : ExpName(perm_string()) { }

    public:
      int elaborate_lval(Entity*ent, Architecture*arc, bool);
      const VType* probe_type(Entity*ent, Architecture*arc) const;
      void dump(ostream&out, int indent =0) const;
};

class ExpRelation : public ExpBinary {

    public:
      enum fun_t { EQ, LT, GT, NEQ, LE, GE };

      inline fun_t relation_fun(void) const { return fun_; }

    public:
      ExpRelation(ExpRelation::fun_t ty, Expression*op1, Expression*op2);
      ~ExpRelation();

      const VType* probe_type(Entity*ent, Architecture*arc) const;
      int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
      void write_to_stream(std::ostream&fd);
      int emit(ostream&out, Entity*ent, Architecture*arc);
      void dump(ostream&out, int indent = 0) const;

    private:
      fun_t fun_;
};

class ExpString : public Expression {

    public:
      explicit ExpString(const char*);
      ~ExpString();

      const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const;
      int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
      void write_to_stream(std::ostream&fd);
      int emit(ostream&out, Entity*ent, Architecture*arc);
      bool is_primary(void) const;
      void dump(ostream&out, int indent = 0) const;

    private:
      int emit_as_array_(ostream&out, Entity*ent, Architecture*arc, const VTypeArray*arr);

    private:
      std::vector<char> value_;
};

class ExpUAbs : public ExpUnary {

    public:
      ExpUAbs(Expression*op1);
      ~ExpUAbs();

      void write_to_stream(std::ostream&fd);
      int emit(ostream&out, Entity*ent, Architecture*arc);
      void dump(ostream&out, int indent = 0) const;
};

class ExpUNot : public ExpUnary {

    public:
      ExpUNot(Expression*op1);
      ~ExpUNot();

      int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
      void write_to_stream(std::ostream&fd);
      int emit(ostream&out, Entity*ent, Architecture*arc);
      void dump(ostream&out, int indent = 0) const;
};

#endif
Something went wrong with that request. Please try again.