From 185bbbe681d02874796e70a1ee147f4b8dca6cbb Mon Sep 17 00:00:00 2001 From: Kazuki Sakamoto Date: Sun, 14 Jun 2020 15:15:59 -0700 Subject: static cast: support changing size and signedness Support SystemVerilog Static Cast - size - signedness - (type is not supposted yet) Fix #535 --- frontends/ast/ast.cc | 1 + frontends/ast/ast.h | 1 + frontends/ast/genrtlil.cc | 24 ++++++++++++++++++++++++ frontends/ast/simplify.cc | 1 + frontends/verilog/verilog_lexer.l | 2 ++ frontends/verilog/verilog_parser.y | 19 +++++++++++++++++++ 6 files changed, 48 insertions(+) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 03fd272da..9520ae32c 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -95,6 +95,7 @@ std::string AST::type2str(AstNodeType type) X(AST_TO_SIGNED) X(AST_TO_UNSIGNED) X(AST_SELFSZ) + X(AST_CAST_SIZE) X(AST_CONCAT) X(AST_REPLICATE) X(AST_BIT_NOT) diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 46864a4e1..9a5aa15f9 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -76,6 +76,7 @@ namespace AST AST_TO_SIGNED, AST_TO_UNSIGNED, AST_SELFSZ, + AST_CAST_SIZE, AST_CONCAT, AST_REPLICATE, AST_BIT_NOT, diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 9546558aa..e878d0dd2 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -814,6 +814,16 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun children.at(0)->detectSignWidthWorker(sub_width_hint, sign_hint); break; + case AST_CAST_SIZE: + while (children.at(0)->simplify(true, false, false, 1, -1, false, false)) { } + if (children.at(0)->type != AST_CONSTANT) + log_file_error(filename, location.first_line, "Static cast with non constant expression!\n"); + children.at(1)->detectSignWidthWorker(width_hint, sign_hint); + width_hint = children.at(0)->bitsAsConst().as_int(); + if (width_hint <= 0) + log_file_error(filename, location.first_line, "Static cast with zero or negative size!\n"); + break; + case AST_CONCAT: for (auto child : children) { sub_width_hint = 0; @@ -1289,6 +1299,20 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) return sig; } + // changing the size of signal can be done directly using RTLIL::SigSpec + case AST_CAST_SIZE: { + RTLIL::SigSpec size = children[0]->genRTLIL(); + RTLIL::SigSpec sig = children[1]->genRTLIL(); + if (!size.is_fully_const()) + log_file_error(filename, location.first_line, "Static cast with non constant expression!\n"); + int width = size.as_int(); + if (width <= 0) + log_file_error(filename, location.first_line, "Static cast with zero or negative size!\n"); + sig.extend_u0(width, sign_hint); + is_signed = sign_hint; + return sig; + } + // concatenation of signals can be done directly using RTLIL::SigSpec case AST_CONCAT: { RTLIL::SigSpec sig; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 5f026dfed..1d5dd91a7 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -950,6 +950,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, case AST_TO_SIGNED: case AST_TO_UNSIGNED: case AST_SELFSZ: + case AST_CAST_SIZE: case AST_CONCAT: case AST_REPLICATE: case AST_REDUCE_AND: diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index e6fa6361e..6195bb149 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -517,6 +517,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { "<<<" { return OP_SSHL; } ">>>" { return OP_SSHR; } +"'" { return OP_CAST; } + "::" { return TOK_PACKAGESEP; } "++" { return TOK_INCREMENT; } "--" { return TOK_DECREMENT; } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 15c231f3b..bbf1a436b 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -298,6 +298,7 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode) %left '+' '-' %left '*' '/' '%' %left OP_POW +%left OP_CAST %right UNARY_OPS %define parse.error verbose @@ -3001,6 +3002,24 @@ basic_expr: $$ = new AstNode(AST_LOGIC_NOT, $3); SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); + } | + TOK_SIGNED OP_CAST '(' expr ')' { + if (!sv_mode) + frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); + $$ = new AstNode(AST_TO_SIGNED, $4); + SET_AST_NODE_LOC($$, @1, @4); + } | + TOK_UNSIGNED OP_CAST '(' expr ')' { + if (!sv_mode) + frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); + $$ = new AstNode(AST_TO_UNSIGNED, $4); + SET_AST_NODE_LOC($$, @1, @4); + } | + basic_expr OP_CAST '(' expr ')' { + if (!sv_mode) + frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); + $$ = new AstNode(AST_CAST_SIZE, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); }; concat_list: -- cgit v1.2.3 From 6bf75be73bc0767b5df9e3fa33a58cfe6aae9f89 Mon Sep 17 00:00:00 2001 From: Kazuki Sakamoto Date: Sun, 14 Jun 2020 15:26:47 -0700 Subject: static cast: add tests --- tests/svtypes/static_cast_negative.ys | 4 +++ tests/svtypes/static_cast_nonconst.ys | 4 +++ tests/svtypes/static_cast_simple.sv | 64 +++++++++++++++++++++++++++++++++++ tests/svtypes/static_cast_verilog.ys | 4 +++ tests/svtypes/static_cast_zero.ys | 4 +++ 5 files changed, 80 insertions(+) create mode 100644 tests/svtypes/static_cast_negative.ys create mode 100644 tests/svtypes/static_cast_nonconst.ys create mode 100644 tests/svtypes/static_cast_simple.sv create mode 100644 tests/svtypes/static_cast_verilog.ys create mode 100644 tests/svtypes/static_cast_zero.ys diff --git a/tests/svtypes/static_cast_negative.ys b/tests/svtypes/static_cast_negative.ys new file mode 100644 index 000000000..4f9e8cf6e --- /dev/null +++ b/tests/svtypes/static_cast_negative.ys @@ -0,0 +1,4 @@ +logger -expect error "Static cast with zero or negative size" 1 +read_verilog -sv <> 8; + assign d = (16'(a) * b) >> 8; + + parameter P = 16; + + wire signed [7:0] s0, s1, s2; + wire [7:0] u0, u1, u2, u3, u4, u5, u6; + assign s0 = -8'd1; + assign s1 = 4'(s0); + assign s2 = 4'(unsigned'(s0)); + assign u0 = -8'd1; + assign u1 = 4'(u0); + assign u2 = 4'(signed'(u0)); + assign u3 = 8'(4'(s0)); + assign u4 = 8'(4'(u0)); + assign u5 = 8'(4'(signed'(-8'd1))); + assign u6 = 8'(4'(unsigned'(-8'd1))); + + wire [8:0] n0, n1, n2, n3, n4, n5, n6, n7, n8, n9; + assign n0 = s1; + assign n1 = s2; + assign n2 = 9'(s1); + assign n3 = 9'(s2); + assign n4 = 9'(unsigned'(s1)); + assign n5 = 9'(unsigned'(s2)); + assign n6 = 9'(u0); + assign n7 = 9'(u1); + assign n8 = 9'(signed'(u0)); + assign n9 = 9'(signed'(u1)); + + always_comb begin + assert(c == 8'b0000_0000); + assert(d == 8'b0000_0001); + + assert((P + 1)'(a) == 17'b0_0000_0000_0001_0000); + assert((P + 1)'(d - 2) == 17'b1_1111_1111_1111_1111); + + assert(s0 == 8'b1111_1111); + assert(s1 == 8'b1111_1111); + assert(s2 == 8'b0000_1111); + assert(u0 == 8'b1111_1111); + assert(u1 == 8'b0000_1111); + assert(u2 == 8'b1111_1111); + assert(u3 == 8'b1111_1111); + assert(u4 == 8'b0000_1111); + assert(u5 == 8'b1111_1111); + assert(u6 == 8'b0000_1111); + + assert(n0 == 9'b1_1111_1111); + assert(n1 == 9'b0_0000_1111); + assert(n2 == 9'b1_1111_1111); + assert(n3 == 9'b0_0000_1111); + assert(n4 == 9'b0_1111_1111); + assert(n5 == 9'b0_0000_1111); + assert(n6 == 9'b0_1111_1111); + assert(n7 == 9'b0_0000_1111); + assert(n8 == 9'b1_1111_1111); + assert(n9 == 9'b0_0000_1111); + end +endmodule diff --git a/tests/svtypes/static_cast_verilog.ys b/tests/svtypes/static_cast_verilog.ys new file mode 100644 index 000000000..fa3680b68 --- /dev/null +++ b/tests/svtypes/static_cast_verilog.ys @@ -0,0 +1,4 @@ +logger -expect error "Static cast is only supported in SystemVerilog mode" 1 +read_verilog < Date: Fri, 19 Jun 2020 19:09:43 -0700 Subject: static cast: simplify --- frontends/ast/simplify.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 1d5dd91a7..e2da17c09 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -3484,6 +3484,13 @@ replace_fcall_later:; } } break; + case AST_CAST_SIZE: + if (children.at(0)->type == AST_CONSTANT && children.at(1)->type == AST_CONSTANT) { + int width = children[0]->bitsAsConst().as_int(); + RTLIL::Const val = children[1]->bitsAsConst(width); + newNode = mkconst_bits(val.bits, children[1]->is_signed); + } + break; case AST_CONCAT: string_op = !children.empty(); for (auto it = children.begin(); it != children.end(); it++) { -- cgit v1.2.3