| //===- unittest/Format/FormatTestVerilog.cpp ------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "FormatTestUtils.h" |
| #include "clang/Format/Format.h" |
| #include "llvm/Support/Debug.h" |
| #include "gtest/gtest.h" |
| |
| #define DEBUG_TYPE "format-test" |
| |
| namespace clang { |
| namespace format { |
| |
| class FormatTestVerilog : public ::testing::Test { |
| protected: |
| static std::string format(llvm::StringRef Code, unsigned Offset, |
| unsigned Length, const FormatStyle &Style) { |
| LLVM_DEBUG(llvm::errs() << "---\n"); |
| LLVM_DEBUG(llvm::errs() << Code << "\n\n"); |
| std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length)); |
| tooling::Replacements Replaces = reformat(Style, Code, Ranges); |
| auto Result = applyAllReplacements(Code, Replaces); |
| EXPECT_TRUE(static_cast<bool>(Result)); |
| LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n"); |
| return *Result; |
| } |
| |
| static std::string |
| format(llvm::StringRef Code, |
| const FormatStyle &Style = getLLVMStyle(FormatStyle::LK_Verilog)) { |
| return format(Code, 0, Code.size(), Style); |
| } |
| |
| static void verifyFormat( |
| llvm::StringRef Code, |
| const FormatStyle &Style = getLLVMStyle(FormatStyle::LK_Verilog)) { |
| EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable"; |
| EXPECT_EQ(Code.str(), |
| format(test::messUp(Code, /*HandleHash=*/false), Style)); |
| } |
| }; |
| |
| TEST_F(FormatTestVerilog, BasedLiteral) { |
| verifyFormat("x = '0;"); |
| verifyFormat("x = '1;"); |
| verifyFormat("x = 'X;"); |
| verifyFormat("x = 'x;"); |
| verifyFormat("x = 'Z;"); |
| verifyFormat("x = 'z;"); |
| verifyFormat("x = 659;"); |
| verifyFormat("x = 'h837ff;"); |
| verifyFormat("x = 'o7460;"); |
| verifyFormat("x = 4'b1001;"); |
| verifyFormat("x = 5'D3;"); |
| verifyFormat("x = 3'b01x;"); |
| verifyFormat("x = 12'hx;"); |
| verifyFormat("x = 16'hz;"); |
| verifyFormat("x = -8'd6;"); |
| verifyFormat("x = 4'shf;"); |
| verifyFormat("x = -4'sd15;"); |
| verifyFormat("x = 16'sd?;"); |
| } |
| |
| TEST_F(FormatTestVerilog, Block) { |
| verifyFormat("begin\n" |
| " x = x;\n" |
| "end"); |
| verifyFormat("begin : x\n" |
| " x = x;\n" |
| "end : x"); |
| verifyFormat("begin\n" |
| " x = x;\n" |
| " x = x;\n" |
| "end"); |
| verifyFormat("fork\n" |
| " x = x;\n" |
| "join"); |
| verifyFormat("fork\n" |
| " x = x;\n" |
| "join_any"); |
| verifyFormat("fork\n" |
| " x = x;\n" |
| "join_none"); |
| verifyFormat("generate\n" |
| " x = x;\n" |
| "endgenerate"); |
| verifyFormat("generate : x\n" |
| " x = x;\n" |
| "endgenerate : x"); |
| // Nested blocks. |
| verifyFormat("begin\n" |
| " begin\n" |
| " end\n" |
| "end"); |
| verifyFormat("begin : x\n" |
| " begin\n" |
| " end\n" |
| "end : x"); |
| verifyFormat("begin : x\n" |
| " begin : x\n" |
| " end : x\n" |
| "end : x"); |
| verifyFormat("begin\n" |
| " begin : x\n" |
| " end : x\n" |
| "end"); |
| // Test that 'disable fork' and 'rand join' don't get mistaken as blocks. |
| verifyFormat("disable fork;\n" |
| "x = x;"); |
| verifyFormat("rand join x x;\n" |
| "x = x;"); |
| } |
| |
| TEST_F(FormatTestVerilog, Case) { |
| verifyFormat("case (data)\n" |
| "endcase"); |
| verifyFormat("casex (data)\n" |
| "endcase"); |
| verifyFormat("casez (data)\n" |
| "endcase"); |
| verifyFormat("case (data) inside\n" |
| "endcase"); |
| verifyFormat("case (data)\n" |
| " 16'd0:\n" |
| " result = 10'b0111111111;\n" |
| "endcase"); |
| verifyFormat("case (data)\n" |
| " xxxxxxxx:\n" |
| " result = 10'b0111111111;\n" |
| "endcase"); |
| // Test labels with multiple options. |
| verifyFormat("case (data)\n" |
| " 16'd0, 16'd1:\n" |
| " result = 10'b0111111111;\n" |
| "endcase"); |
| verifyFormat("case (data)\n" |
| " 16'd0, //\n" |
| " 16'd1:\n" |
| " result = 10'b0111111111;\n" |
| "endcase"); |
| // Test that blocks following labels are indented. |
| verifyFormat("case (data)\n" |
| " 16'd1: fork\n" |
| " result = 10'b1011111111;\n" |
| " join\n" |
| "endcase\n"); |
| verifyFormat("case (data)\n" |
| " 16'd1: fork : x\n" |
| " result = 10'b1011111111;\n" |
| " join : x\n" |
| "endcase\n"); |
| // Test default. |
| verifyFormat("case (data)\n" |
| " default\n" |
| " result = 10'b1011111111;\n" |
| "endcase"); |
| verifyFormat("case (data)\n" |
| " default:\n" |
| " result = 10'b1011111111;\n" |
| "endcase"); |
| // Test that question marks and colons don't get mistaken as labels. |
| verifyFormat("case (data)\n" |
| " 8'b1???????:\n" |
| " instruction1(ir);\n" |
| "endcase"); |
| verifyFormat("case (data)\n" |
| " x ? 8'b1??????? : 1:\n" |
| " instruction3(ir);\n" |
| "endcase"); |
| // Test indention options. |
| auto Style = getLLVMStyle(FormatStyle::LK_Verilog); |
| Style.IndentCaseLabels = false; |
| verifyFormat("case (data)\n" |
| "16'd0:\n" |
| " result = 10'b0111111111;\n" |
| "endcase", |
| Style); |
| verifyFormat("case (data)\n" |
| "16'd0: begin\n" |
| " result = 10'b0111111111;\n" |
| "end\n" |
| "endcase", |
| Style); |
| Style.IndentCaseLabels = true; |
| verifyFormat("case (data)\n" |
| " 16'd0:\n" |
| " result = 10'b0111111111;\n" |
| "endcase", |
| Style); |
| verifyFormat("case (data)\n" |
| " 16'd0: begin\n" |
| " result = 10'b0111111111;\n" |
| " end\n" |
| "endcase", |
| Style); |
| } |
| |
| TEST_F(FormatTestVerilog, Delay) { |
| // Delay by the default unit. |
| verifyFormat("#0;"); |
| verifyFormat("#1;"); |
| verifyFormat("#10;"); |
| verifyFormat("#1.5;"); |
| // Explicit unit. |
| verifyFormat("#1fs;"); |
| verifyFormat("#1.5fs;"); |
| verifyFormat("#1ns;"); |
| verifyFormat("#1.5ns;"); |
| verifyFormat("#1us;"); |
| verifyFormat("#1.5us;"); |
| verifyFormat("#1ms;"); |
| verifyFormat("#1.5ms;"); |
| verifyFormat("#1s;"); |
| verifyFormat("#1.5s;"); |
| // The following expression should be on the same line. |
| verifyFormat("#1 x = x;"); |
| EXPECT_EQ("#1 x = x;", format("#1\n" |
| "x = x;")); |
| } |
| |
| TEST_F(FormatTestVerilog, Hierarchy) { |
| verifyFormat("module x;\n" |
| "endmodule"); |
| // Test that the end label is on the same line as the end keyword. |
| verifyFormat("module x;\n" |
| "endmodule : x"); |
| // Test that things inside are indented. |
| verifyFormat("module x;\n" |
| " generate\n" |
| " endgenerate\n" |
| "endmodule"); |
| verifyFormat("program x;\n" |
| " generate\n" |
| " endgenerate\n" |
| "endprogram"); |
| verifyFormat("interface x;\n" |
| " generate\n" |
| " endgenerate\n" |
| "endinterface"); |
| verifyFormat("task x;\n" |
| " generate\n" |
| " endgenerate\n" |
| "endtask"); |
| verifyFormat("function x;\n" |
| " generate\n" |
| " endgenerate\n" |
| "endfunction"); |
| verifyFormat("class x;\n" |
| " generate\n" |
| " endgenerate\n" |
| "endclass"); |
| // Test that they nest. |
| verifyFormat("module x;\n" |
| " program x;\n" |
| " program x;\n" |
| " endprogram\n" |
| " endprogram\n" |
| "endmodule"); |
| // Test that an extern declaration doesn't change the indentation. |
| verifyFormat("extern module x;\n" |
| "x = x;"); |
| // Test complex headers |
| verifyFormat("extern module x\n" |
| " import x.x::x::*;\n" |
| " import x;\n" |
| " #(parameter x)\n" |
| " (output x);"); |
| verifyFormat("module x\n" |
| " import x.x::x::*;\n" |
| " import x;\n" |
| " #(parameter x)\n" |
| " (output x);\n" |
| " generate\n" |
| " endgenerate\n" |
| "endmodule : x"); |
| verifyFormat("virtual class x\n" |
| " (x)\n" |
| " extends x(x)\n" |
| " implements x, x, x;\n" |
| " generate\n" |
| " endgenerate\n" |
| "endclass : x\n"); |
| verifyFormat("function automatic logic [1 : 0] x\n" |
| " (input x);\n" |
| " generate\n" |
| " endgenerate\n" |
| "endfunction : x"); |
| } |
| |
| TEST_F(FormatTestVerilog, If) { |
| verifyFormat("if (x)\n" |
| " x = x;"); |
| verifyFormat("unique if (x)\n" |
| " x = x;"); |
| verifyFormat("unique0 if (x)\n" |
| " x = x;"); |
| verifyFormat("priority if (x)\n" |
| " x = x;"); |
| verifyFormat("if (x)\n" |
| " x = x;\n" |
| "x = x;"); |
| |
| // Test else |
| verifyFormat("if (x)\n" |
| " x = x;\n" |
| "else if (x)\n" |
| " x = x;\n" |
| "else\n" |
| " x = x;"); |
| verifyFormat("if (x) begin\n" |
| " x = x;\n" |
| "end else if (x) begin\n" |
| " x = x;\n" |
| "end else begin\n" |
| " x = x;\n" |
| "end"); |
| verifyFormat("if (x) begin : x\n" |
| " x = x;\n" |
| "end : x else if (x) begin : x\n" |
| " x = x;\n" |
| "end : x else begin : x\n" |
| " x = x;\n" |
| "end : x"); |
| |
| // Test block keywords. |
| verifyFormat("if (x) begin\n" |
| " x = x;\n" |
| "end"); |
| verifyFormat("if (x) begin : x\n" |
| " x = x;\n" |
| "end : x"); |
| verifyFormat("if (x) begin\n" |
| " x = x;\n" |
| " x = x;\n" |
| "end"); |
| verifyFormat("if (x) fork\n" |
| " x = x;\n" |
| "join"); |
| verifyFormat("if (x) fork\n" |
| " x = x;\n" |
| "join_any"); |
| verifyFormat("if (x) fork\n" |
| " x = x;\n" |
| "join_none"); |
| verifyFormat("if (x) generate\n" |
| " x = x;\n" |
| "endgenerate"); |
| verifyFormat("if (x) generate : x\n" |
| " x = x;\n" |
| "endgenerate : x"); |
| |
| // Test that concatenation braces don't get regarded as blocks. |
| verifyFormat("if (x)\n" |
| " {x} = x;"); |
| verifyFormat("if (x)\n" |
| " x = {x};"); |
| verifyFormat("if (x)\n" |
| " x = {x};\n" |
| "else\n" |
| " {x} = {x};"); |
| |
| // With attributes. |
| verifyFormat("(* x *) if (x)\n" |
| " x = x;"); |
| verifyFormat("(* x = \"x\" *) if (x)\n" |
| " x = x;"); |
| verifyFormat("(* x, x = \"x\" *) if (x)\n" |
| " x = x;"); |
| } |
| |
| TEST_F(FormatTestVerilog, Operators) { |
| // Test that unary operators are not followed by space. |
| verifyFormat("x = +x;"); |
| verifyFormat("x = -x;"); |
| verifyFormat("x = !x;"); |
| verifyFormat("x = ~x;"); |
| verifyFormat("x = &x;"); |
| verifyFormat("x = ~&x;"); |
| verifyFormat("x = |x;"); |
| verifyFormat("x = ~|x;"); |
| verifyFormat("x = ^x;"); |
| verifyFormat("x = ~^x;"); |
| verifyFormat("x = ^~x;"); |
| verifyFormat("x = ++x;"); |
| verifyFormat("x = --x;"); |
| |
| // Test that operators don't get split. |
| verifyFormat("x = x++;"); |
| verifyFormat("x = x--;"); |
| verifyFormat("x = x ** x;"); |
| verifyFormat("x = x << x;"); |
| verifyFormat("x = x >> x;"); |
| verifyFormat("x = x <<< x;"); |
| verifyFormat("x = x >>> x;"); |
| verifyFormat("x = x <= x;"); |
| verifyFormat("x = x >= x;"); |
| verifyFormat("x = x == x;"); |
| verifyFormat("x = x != x;"); |
| verifyFormat("x = x === x;"); |
| verifyFormat("x = x !== x;"); |
| verifyFormat("x = x ==? x;"); |
| verifyFormat("x = x !=? x;"); |
| verifyFormat("x = x ~^ x;"); |
| verifyFormat("x = x ^~ x;"); |
| verifyFormat("x = x && x;"); |
| verifyFormat("x = x || x;"); |
| verifyFormat("x = x->x;"); |
| verifyFormat("x = x <-> x;"); |
| verifyFormat("x += x;"); |
| verifyFormat("x -= x;"); |
| verifyFormat("x *= x;"); |
| verifyFormat("x /= x;"); |
| verifyFormat("x %= x;"); |
| verifyFormat("x &= x;"); |
| verifyFormat("x ^= x;"); |
| verifyFormat("x |= x;"); |
| verifyFormat("x <<= x;"); |
| verifyFormat("x >>= x;"); |
| verifyFormat("x <<<= x;"); |
| verifyFormat("x >>>= x;"); |
| verifyFormat("x <= x;"); |
| |
| // Test that space is added between operators. |
| EXPECT_EQ("x = x < -x;", format("x=x<-x;")); |
| EXPECT_EQ("x = x << -x;", format("x=x<<-x;")); |
| EXPECT_EQ("x = x <<< -x;", format("x=x<<<-x;")); |
| } |
| |
| TEST_F(FormatTestVerilog, Preprocessor) { |
| auto Style = getLLVMStyle(FormatStyle::LK_Verilog); |
| Style.ColumnLimit = 20; |
| |
| // Macro definitions. |
| EXPECT_EQ("`define X \\\n" |
| " if (x) \\\n" |
| " x = x;", |
| format("`define X if(x)x=x;", Style)); |
| EXPECT_EQ("`define X(x) \\\n" |
| " if (x) \\\n" |
| " x = x;", |
| format("`define X(x) if(x)x=x;", Style)); |
| EXPECT_EQ("`define X \\\n" |
| " x = x; \\\n" |
| " x = x;", |
| format("`define X x=x;x=x;", Style)); |
| // Macro definitions with invocations inside. |
| EXPECT_EQ("`define LIST \\\n" |
| " `ENTRY \\\n" |
| " `ENTRY", |
| format("`define LIST \\\n" |
| "`ENTRY \\\n" |
| "`ENTRY", |
| Style)); |
| EXPECT_EQ("`define LIST \\\n" |
| " `x = `x; \\\n" |
| " `x = `x;", |
| format("`define LIST \\\n" |
| "`x = `x; \\\n" |
| "`x = `x;", |
| Style)); |
| EXPECT_EQ("`define LIST \\\n" |
| " `x = `x; \\\n" |
| " `x = `x;", |
| format("`define LIST `x=`x;`x=`x;", Style)); |
| // Macro invocations. |
| verifyFormat("`x = (`x1 + `x2 + x);"); |
| // Lines starting with a preprocessor directive should not be indented. |
| std::string Directives[] = { |
| "begin_keywords", |
| "celldefine", |
| "default_nettype", |
| "define", |
| "else", |
| "elsif", |
| "end_keywords", |
| "endcelldefine", |
| "endif", |
| "ifdef", |
| "ifndef", |
| "include", |
| "line", |
| "nounconnected_drive", |
| "pragma", |
| "resetall", |
| "timescale", |
| "unconnected_drive", |
| "undef", |
| "undefineall", |
| }; |
| for (auto &Name : Directives) { |
| EXPECT_EQ("if (x)\n" |
| "`" + |
| Name + |
| "\n" |
| " ;", |
| format("if (x)\n" |
| "`" + |
| Name + |
| "\n" |
| ";", |
| Style)); |
| } |
| // Lines starting with a regular macro invocation should be indented as a |
| // normal line. |
| EXPECT_EQ("if (x)\n" |
| " `x = `x;\n" |
| "`timescale 1ns / 1ps", |
| format("if (x)\n" |
| "`x = `x;\n" |
| "`timescale 1ns / 1ps", |
| Style)); |
| EXPECT_EQ("if (x)\n" |
| "`timescale 1ns / 1ps\n" |
| " `x = `x;", |
| format("if (x)\n" |
| "`timescale 1ns / 1ps\n" |
| "`x = `x;", |
| Style)); |
| std::string NonDirectives[] = { |
| // For `__FILE__` and `__LINE__`, although the standard classifies them as |
| // preprocessor directives, they are used like regular macros. |
| "__FILE__", "__LINE__", "elif", "foo", "x", |
| }; |
| for (auto &Name : NonDirectives) { |
| EXPECT_EQ("if (x)\n" |
| " `" + |
| Name + ";", |
| format("if (x)\n" |
| "`" + |
| Name + |
| "\n" |
| ";", |
| Style)); |
| } |
| } |
| |
| TEST_F(FormatTestVerilog, Primitive) { |
| verifyFormat("primitive multiplexer\n" |
| " (mux, control, dataA, dataB);\n" |
| " output mux;\n" |
| " input control, dataA, dataB;\n" |
| " table\n" |
| " 0 1 ? : 1;\n" |
| " 0 0 ? : 0;\n" |
| " 1 ? 1 : 1;\n" |
| " 1 ? 0 : 0;\n" |
| " x 0 0 : 0;\n" |
| " x 1 1 : 1;\n" |
| " endtable\n" |
| "endprimitive"); |
| verifyFormat("primitive latch\n" |
| " (q, ena_, data);\n" |
| " output q;\n" |
| " reg q;\n" |
| " input ena_, data;\n" |
| " table\n" |
| " 0 1 : ? : 1;\n" |
| " 0 0 : ? : 0;\n" |
| " 1 ? : ? : -;\n" |
| " ? * : ? : -;\n" |
| " endtable\n" |
| "endprimitive"); |
| verifyFormat("primitive d\n" |
| " (q, clock, data);\n" |
| " output q;\n" |
| " reg q;\n" |
| " input clock, data;\n" |
| " table\n" |
| " (01) 0 : ? : 0;\n" |
| " (01) 1 : ? : 1;\n" |
| " (0?) 1 : 1 : 1;\n" |
| " (0?) 0 : 0 : 0;\n" |
| " (?0) ? : ? : -;\n" |
| " (?\?) ? : ? : -;\n" |
| " endtable\n" |
| "endprimitive"); |
| } |
| } // namespace format |
| } // end namespace clang |