Coder Social home page Coder Social logo

zachjs / sv2v Goto Github PK

View Code? Open in Web Editor NEW
475.0 14.0 49.0 1.76 MB

SystemVerilog to Verilog conversion

License: BSD 3-Clause "New" or "Revised" License

Haskell 54.30% Makefile 0.03% SystemVerilog 26.61% Verilog 16.64% Shell 2.10% Python 0.30% Max 0.03%
systemverilog verilog conversion yosys

sv2v's Introduction

sv2v: SystemVerilog to Verilog

sv2v converts SystemVerilog (IEEE 1800-2017) to Verilog (IEEE 1364-2005), with an emphasis on supporting synthesizable language constructs.

The primary goal of this project is to create a completely free and open-source tool for converting SystemVerilog to Verilog. While methods for performing this conversion already exist, they generally either rely on commercial tools, or are limited in scope.

This project was originally developed to target Yosys, and so allows for disabling the conversion of (passing through) those SystemVerilog features that Yosys supports.

The idea for this project was shared with me while I was an undergraduate at Carnegie Mellon University as part of a joint Computer Science and Electrical and Computer Engineering research project on open hardware under Professors Ken Mai and Dave Eckhardt. I have greatly enjoyed collaborating with the team at CMU since January 2019, even after my graduation the following May.

Dependencies

All of sv2v's dependencies are free and open-source.

  • Build Dependencies
    • Haskell Stack - Haskell build system
    • Haskell dependencies are managed in sv2v.cabal
  • Test Dependencies
    • Icarus Verilog - for Verilog simulation
    • shUnit2 - test framework
    • Python 3.x - for evaluating certain test cases

Installation

Pre-built binaries

Binaries for Ubuntu, macOS, and Windows are available on the releases page. If your system is not covered, or you would like to build the latest commit, simple instructions for building from source are below.

Building from source

You must have Stack installed to build sv2v. Then you can:

git clone https://github.com/zachjs/sv2v.git
cd sv2v
make

This creates the executable at ./bin/sv2v. Stack takes care of installing exact (compatible) versions of the compiler and sv2v's build dependencies.

You can install the binary to your local bin path (typically ~/.local/bin) by running stack install, or copy over the executable manually.

Usage

sv2v takes in a list of files and prints the converted Verilog to stdout by default. Users should typically pass all of their SystemVerilog source files to sv2v at once so it can properly resolve packages, interfaces, type parameters, etc., across files. Using --write=adjacent will create a converted .v for every .sv input file rather than printing to stdout. --write/-w can also be used to specify a path to a .v output file. Undefined modules and interfaces can be automatically loaded from library directories using --libdir/-y.

Users may specify include search paths, define macros during preprocessing, and exclude some of the conversions. Specifying - as an input file will read from stdin.

Below is the current usage printout.

sv2v [OPTIONS] [FILES]

Preprocessing:
  -I --incdir=DIR           Add a directory to the include search path
  -y --libdir=DIR           Add a directory to the library search path used
                            when looking for undefined modules and interfaces
  -D --define=NAME[=VALUE]  Define a macro for preprocessing
     --siloed               Lex input files separately, so macros from
                            earlier files are not defined in later files
     --skip-preprocessor    Disable preprocessing of macros, comments, etc.
Conversion:
     --pass-through         Dump input without converting
  -E --exclude=CONV         Exclude a particular conversion (Always, Assert,
                            Interface, Logic, or UnbasedUnsized)
  -v --verbose              Retain certain conversion artifacts
  -w --write=MODE/FILE/DIR  How to write output; default is 'stdout'; use
                            'adjacent' to create a .v file next to each input;
                            use a path ending in .v to write to a file; use a
                            path to an existing directory to create a .v within
                            for each converted module
     --top=NAME             Remove uninstantiated modules except the given
                            top module; can be used multiple times
Other:
     --oversized-numbers    Disable standard-imposed 32-bit limit on unsized
                            number literals (e.g., 'h1_ffff_ffff, 4294967296)
     --dump-prefix=PATH     Create intermediate output files with the given
                            path prefix; used for internal debugging
     --help                 Display this help message
     --version              Print version information
     --numeric-version      Print just the version number

Supported Features

sv2v supports most synthesizable SystemVerilog features. Current notable exceptions include defparam on interface instances, certain synthesizable usages of parameterized classes, and the bind keyword. Assertions are also supported, but are simply dropped during conversion.

If you find a bug or have a feature request, please create an issue. Preference will be given to issues that include examples or test cases.

SystemVerilog Front End

This project contains a preprocessor, lexer, and parser, and an abstract syntax tree representation for a subset of the SystemVerilog specification. The parser is not very strict. The AST allows for the representation of syntactically (and semantically) invalid Verilog. The goal is to be more general in the representation to enable more standardized and straightforward conversion procedures. This could be extended into an independent and more fully-featured front end if there is significant interest.

Testing

Once the test dependencies are installed, tests can be run with make test. GitHub Actions is used to automatically test commits. Please review the test documentation for guidance on adding, debugging, and interpreting tests.

There is also a SystemVerilog compliance suite that tests open-source tools' SystemVerilog support. Although not every test in the suite is applicable, it has been a valuable asset in finding edge cases.

Acknowledgements

This project was originally forked from Tom Hawkin's Verilog parser. While the front end has changed substantially to support the larger SystemVerilog standard, his project was a great starting point.

Reid Long was invaluable in developing this tool, providing significant tests and advice, and isolating many bugs.

Edric Kusuma helped me with the ins and outs of SystemVerilog, with which I had no prior experience, and has also helped with test cases.

Since sv2v's public release, many people have taken the time to file detailed bug reports and feature requests. I greatly appreciate their help in furthering the project.

sv2v's People

Contributors

b1f6c1c4 avatar de0u avatar dwrchyngqxs avatar hofstee avatar hzeller avatar rswarbrick avatar saw235 avatar sifferman avatar tgorochowik avatar zachjs avatar zyedidia avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sv2v's Issues

Support multi-dimensional localparams

Input:

localparam logic [7:0] init_val [4] = '{8'd0, 8'd8, 8'd10, 8'd200};

Output:

sv2v: Parse error: unexpected token '[' (Sym_brack_l) at ./foo_pkg.sv:10:35.
CallStack (from HasCallStack):
  error, called at .stack-work/dist/x86_64-linux-tinfo6/Cabal-2.4.0.1/build/sv2v/sv2v-tmp/Language/SystemVerilog/Parser/Parse.hs:6149:22 in main:Language.SystemVerilog.Parser.Parse

Exclude array flattening feature

This is a request for the --exclude=CONV switch. Currently CONV includes always, interface, logic. It would be nice to also retain multi-dimensional arrays inside a module (not for interfaces, which is not supported by Verilog).

This would be helpful for register-files or memories. Flattening those to 1-dimensional regs makes it harder for synthesis tools to recognize them as memories.

Support "logic signed" conversion to wire for assigns

foo.sv:

module foo;
  logic signed [7:0] goo_signed;
  logic        [7:0] goo;

  assign goo_signed = 8'd0;
  assign goo = 8'd0;
endmodule

Generated Verilog:

module foo;
	reg signed [7:0] goo_signed;  // <-- this should be "wire signed" 
	wire [7:0] goo;
	assign goo_signed = 8'd0;
	assign goo = 8'd0;
endmodule

Support struct default assignment

File foo.sv:

module foo;

  typedef struct packed {
    logic goo;
    logic hoo;
  } foo_t;

  foo_t my_foo;
  assign my_foo = '{goo: 1'b1, default: '0};  // <-- notice the "default" in this line
endmodule

Output:

sv2v: Maybe.fromJust: Nothing

Note: this is a distilled testcase derived from Ibex core file ibex_cs_registers.sv.

Support for `parameter type`

module foo #(
    parameter type T = logic
)();
endmodule

Gives:

sv2v: Parse error: unexpected token 'type' (KW_type) at ./foo.sv:2:15.
CallStack (from HasCallStack):
  error, called at .stack-work/dist/x86_64-linux/Cabal-2.4.0.1/build/sv2v/sv2v-tmp/Language/SystemVerilog/Parser/Parse.hs:6549:22 in main:Language.SystemVerilog.Parser.Parse

Version used: 9cc211d

Nested structs seem to be not supported

What doesn't seem to work (i.e. it doesn't get replaced by a flat wire):

typedef struct packed {
  logic [7:0] rsvd;
  logic [7:0] parity; 
} boo_t;

typedef struct packed {
  logic valid;
  boo_t user;
} foo_t;

But it works well when it's not nested:

typedef struct packed {
  logic        valid;
  logic [15:0] user;
} foo_t;

Any ideas how to support nested typedef structs? Thanks!

Support for localparams in parameter list

foo.v

module foo
 #(parameter baz = 2
   , localparam in_width_p = baz + 2
   , localparam out_width_p = baz + 3
   )
  (input [in_width_p-1:0] a
   , output [out_width_p-1:0] b
   );

assign b = a+1;

endmodule

Command:

$ sv2v --oneunit foo.v

Result:

sv2v: Parse error: unexpected token 'localparam' (KW_localparam) at ./foo.v:5:6.
CallStack (from HasCallStack):
  error, called at .stack-work/dist/x86_64-linux/Cabal-2.4.0.1/build/sv2v/sv2v-tmp/Language/SystemVerilog/Parser/Parse.hs:6165:22 in main:Language.SystemVerilog.Parser.Parse

I think this feature came in SV-2012
http://www.ece.uah.edu/~gaede/cpe526/2012%20System%20Verilog%20Language%20Reference%20Manual.pdf
Section 06.20.04

Local parameters may be declared in a moduleโ€™s parameter_port_list.

Possibly a solution is to convert localparams in parameter lists to vanilla parameters?

Thanks again!

Wrapping if statements with begin/end

I noticed some odd behavior when converting code with a snippet like this:

always_comb begin
  x = 1'b0;
  y = 1'b0;

  if (a) begin
    if (b) begin
      x = 1'b1;
    end
  end else begin
    if (c) begin
      y = 1'b1;
    end
  end
end

sv2v doesn't wrap the body of the if(a) statement in begin/end tags, rather it gives output like this:

always @(*) begin
  x = 1'b0;
  y = 1'b0;
  if (a)
    if (b)
      x = 1'b1;
  else if (c)
    y = 1'b1;
end

Although I initially assumed this was legal Verilog (since the body of the if(a) statement is just one statement itself), this doesn't seem to act as expected when running in simulation under both Icarus Verilog and Vivado. y doesn't get set to 1 even when a = 0, b = 0, and c = 1. However, adding the additional begin and end causes the code to work as intended.

I'm not 100% sure what the Verilog spec actually says here, but it may be a good idea to wrap all blocks in begin and end regardless of length to make sure all tools handle them correctly.

Here's a more complete test case that should let you reproduce this behavior:

`timescale 1ns / 1ps

module test();

logic a;
logic b;
logic c;

logic x;
logic y;

always_comb begin
  x = 1'b0;
  y = 1'b0;

  if (a) begin
    if (b) begin
      x = 1'b1;
    end
  end else begin
    if (c) begin
      y = 1'b1;
    end
  end
end

initial begin
  a = 1'b0;
  b = 1'b0;
  c = 1'b0;
  // y = 0 here
  #10;
  c = 1'b1;
  // expect y = 1 here, but it's still 0!
  #10;
  $finish;
end
endmodule

Issue handling always_latch

Hi, thanks for the great work on this tool! I got an unexpected output when converting SystemVerilog code containing an always_latch block. I'm not sure if this keyword just isn't supported yet or if it's a proper bug, but here's a code snippet to reproduce -

Code:

module test();
  logic a;
  logic b;
  logic en;
  always_latch begin
    if (en) begin
      a <= b;
    end
  end
endmodule

Gives:

module test;
	reg a;
	wire b;
	wire en;
	always_latch if (en)
		a <= b;
endmodule

Whereas I'd expect something more like this:

module test;
  reg a;
  wire b;
  wire en;
  always @(*) begin
    if (en) begin
      a = b;
    end
  end
endmodule

sv2v command not found

Hello zachjs
I've installed sv2v completely on windows 10 but when i run sv2v.exe nothing happens and when I use this command format sv2v [option] [file] it's says command 'sv2v' not found.

this is my installation details copied from command prompt:
__log.txt


sorry it was my fault. that problem is solved. thank you very much

Support for `function void`

function void foo()
endfunction

Fails by:

sv2v: Parse error: unexpected token 'void' (KW_void) at ....
CallStack (from HasCallStack):
  error, called at .stack-work/dist/x86_64-linux/Cabal-2.4.0.1/build/sv2v/sv2v-tmp/Language/SystemVerilog/Parser/Parse.hs:6549:22 in main:Language.SystemVerilog.Parser.Parse

Support for nested packages

I love the tool, but it doesn't seem to support nested packages. Here is an example:

File top_pkg.sv:

package top_pkg;
  localparam AW = 16;
endpackage

File foo_pkg.sv:

package foo_pkg;
  typedef struct packed {
    logic                   valid;
    logic [top_pkg::AW-1:0] user;
  } boo_t;
endpackage

The generated Verilog contains logic [top_pkg::AW-1:0] instead of replacing it by [16-1:0]. Any ideas?

Support enum elements

This testcase has two files:
File foo_pkg.sv:

package foo_pkg;
  typedef enum logic [2:0] {
    AccessAck     = 3'd0,
    AccessAckData = 3'd1
  } inp_t;
endpackage

File goo.sv:

module goo;
  foo_pkg::inp_t test;
  assign test = foo_pkg::AccessAck;
endmodule

Typing sv2v foo_pkg.sv goo.sv produces:

// removed typedef: foo_pkg_inp_t
// removed typedef: foo_pkg_inp_t
module goo;
        wire [2:0] test;
        assign test = foo_pkg_AccessAck;
endmodule

But it should say assign test = 3'd0;

By the way, is it possible to suppress the comments // removed typedef? It's a minor cosmetic thing, some of my generated files have 100s of these lines (as they include many packages).

Another corner case for attributes

Hey Zack,

This one still fails

(* use_dsp = "yes" *) module example(
    input  [8 - 1:0] in0,
    input  [8 - 1:0] in1,
    input  [16 - 1:0] in2,
    output [17 - 1:0]  dout);

wire signed [25 - 1:0]     a;
wire signed [18 - 1:0]     b;
wire signed [48 - 1:0]     c;
wire signed [43 - 1:0]     m;
wire signed [48 - 1:0]     p;

assign a  = $signed(in0);
assign b  = $signed(in1);
assign c  = $signed(in2);

assign m  = a * b;
assign p  = m + c;

assign dout = p;

endmodule

The error is the following

sv2v: .stack-work/dist/x86_64-linux/Cabal-2.4.0.1/build/sv2v/sv2v-tmp/Language/SystemVerilog/Parser/Parse.hs:1800:19-66: Non-exhaustive patterns in lambda

Thanks for your quick fixes, this is an awesome project!

Support for empty packages

Another edge case!

foo.v

package foo;

endpackage

boo.v

package boo;
`define X 3
endpackage

Command

sv2v foo.v
sv2v boo.v

Results

sv2v: Parse error: unexpected token 'endpackage' (KW_endpackage) at ./foo.v:4:1.
CallStack (from HasCallStack):
  error, called at .stack-work/dist/x86_64-linux/Cabal-2.4.0.1/build/sv2v/sv2v-tmp/Language/SystemVerilog/Parser/Parse.hs:6136:22 in main:Language.SystemVerilog.Parser.Parse

sv2v: Parse error: unexpected token 'endpackage' (KW_endpackage) at ./boo.v:5:1.
CallStack (from HasCallStack):
  error, called at .stack-work/dist/x86_64-linux/Cabal-2.4.0.1/build/sv2v/sv2v-tmp/Language/SystemVerilog/Parser/Parse.hs:6136:22 in main:Language.SystemVerilog.Parser.Parse

sv2v doesn't like empty packages, or packages with only `defines in them

bar.v

package bar;

localparam x = 1;

endpackage

Command:

sv2v bar.v

Result:


Packages with a single param are fine.

gaz.v

module gaz;

endmodule

Command:

sv2v gaz.v

Result:

module gaz;

endmodule

Empty modules are fine, too.

Support "automatic" inside functions

Input:

function automatic logic [7:0] foo(input logic goo);
  automatic logic temp;
  foo = 8'd42;
endfunction

Output (it complains about the second line automatic logic temp):

sv2v: Parse error: unexpected token 'automatic' (KW_automatic) at ./foo_pkg.sv:39:5.
CallStack (from HasCallStack):
  error, called at .stack-work/dist/x86_64-linux-tinfo6/Cabal-2.4.0.1/build/sv2v/sv2v-tmp/Language/SystemVerilog/Parser/Parse.hs:6149:22 in main:Language.SystemVerilog.Parser.Parse

Bug: multiple array declaration

Code:

module foo;
    struct packed {
        logic f1;
        logic f2;
    } a[1:0], b[1:0];
endmodule

Error message:

sv2v: incomplete declaration
CallStack (from HasCallStack):
  error, called at src/Language/SystemVerilog/Parser/ParseDecl.hs:293:21 in main:Language.SystemVerilog.Parser.ParseDecl

Workaround:

module foo;
    typedef struct packed {
        logic f1;
        logic f2;
    } T;

    T a[1:0];
    T b[1:0];
endmodule

Note: T a[1:0], b[1:0]; won't work.

Support genvar inside generate blocks

One more corner case: Original SystemVerilog snippet:

for (genvar i = 0; i < 32; i++) begin : gen_filter
  ...
end

Output of sv2v:

generate
  for (genvar i = 0; (i < 32); i = (i + 1)) begin : gen_filter
    ...                      
  end
endgenerate

However, Yosys has problems with the genvar inside the generate block, saying ERROR: syntax error, unexpected TOK_GENVAR, expecting TOK_ID or '{'. Yosys works fine if I manually change the generated Verilog as follows:

genvar i;
generate
  for (i = 0; (i < 32); i = (i + 1)) begin : gen_filter
    ...                      
  end
endgenerate

An even safer way is shown below, which uses a unique genvar name to avoid possible name collisions with other generate blocks that use the same genvar name:

genvar gen_filter_i;
generate
  for (gen_filter_i = 0; (gen_filter_i < 32); gen_filter_i = (gen_filter_i + 1)) begin : gen_filter
    ...                      
  end
endgenerate

Support for structs in port declarations with nested packages

Consider this testcase, three files: top_pkg.sv, foo_pkg.sv, goo.sv.

File top_pkg.sv:

package top_pkg;
  localparam DW = 32;
endpackage

File foo_pkg.sv:

package foo_pkg;
  typedef struct packed {
    logic                   valid;
    logic [top_pkg::DW-1:0] user;
  } inp_t;

  typedef struct packed {
    logic valid;
    logic opcode;
  } out_t;
endpackage

File goo.sv:

module goo (
  input  foo_pkg::inp_t dat_i,
  output foo_pkg::out_t dat_o
);
endmodule

Typing sv2v top_pkg.sv foo_pkg.sv goo.sv produces the following (note the lin input wire ...):

// removed typedef: foo_pkg_inp_t
// removed typedef: foo_pkg_out_t
// removed typedef: foo_pkg_inp_t
// removed typedef: foo_pkg_out_t
// removed typedef: foo_pkg_inp_t
// removed typedef: foo_pkg_out_t
module goo (
        dat_i,
        dat_o
);
        input wire [((1 + (((top_pkg_DW - 1) >= 0) ? top_pkg_DW : ((0 - (top_pkg_DW - 1)) + 1))) - 1):0] dat_i;
        output wire [1:0] dat_o;
endmodule

Memory initialized by $readmemh inferred as wire

When I use $readmemh to initialize a memory array in a module, sv2v infers that the memory signals should be wires instead of registers, but wires don't work in this context.

Code:

module test
(
    input [7:0] addr,
    output [31:0] data,
);
    // this is a problem if you declare rom as either logic or even a reg explicitly
    reg [31:0] rom [7:0];   
    initial begin
        $readmemh("rom.mem", rom);
    end

    assign data = rom[addr];

endmodule

Output:

module test (
	addr,
	data
);
	input [7:0] addr;
	output [31:0] data;
	wire [31:0] rom [7:0];  // EXPECTED: this line should be `reg [31:0] rom ... ` 
	initial $readmemh("rom.mem", rom);
	assign data = rom[addr];
endmodule

Support streaming operator

The SV streaming operators don't seem to be supported right now. Examples (see here for more examples):

value = {<<{foo}};
value = {<<8{foo}};

Output:

sv2v: Parse error: unexpected token '<<' (Sym_lt_lt) at ./foo.sv:24:29.
CallStack (from HasCallStack):
  error, called at .stack-work/dist/x86_64-linux-tinfo6/Cabal-2.4.0.1/build/sv2v/sv2v-tmp/Language/SystemVerilog/Parser/Parse.hs:6149:22 in main:Language.SystemVerilog.Parser.Parse

Support bitwidth casting in parameter assignments

module foo;
  localparam bit Hoo = '0;
  localparam logic [31:0] Goo = 32'(Hoo);
endmodule

Generated Verilog:

module foo;
	localparam Hoo = 'b0;
	localparam [31:0] Goo = 32'(Hoo);  // <-- this line should not contain 32'( )
endmodule

Spawned from issue #15: uniquify genvars

This spawned from issue #15: While the implementation for issue #15 works fine, there is a problem when there are multiple generate blocks in a file using the same genvar i. In this case, Conformal LEC tool errors out saying that i is redefined.

Could the sv2v tool uniquify all genvars, e.g. by using the name of the generate block, as shown in example of issue #15 where genvar i becomes genvar gen_filter_i?

Support for `foreach`

A foreach loop is more concise than generate. It will be very helpful in creating readable code.

Add switch to disable/enable defparam support

This spawned from issue #13.

The SystemVerilog IEEE standard lists defparam as a candidate for deprecation in future versions (see Annex C.4.1), see also here.

Would it make sense to have a switch that enables/disables defparam support? Disabling defparam support would improve the readability of the generated Verilog, because parameters could be hardcoded (see #13 for examples of current Verilog output that supports defparam).

Support macros defined in stand-alone files (rather than include files)

I have a few macros defined in a file utils.sv, which is not an include file. We just compile this file with all the other RTL, and all commercial EDA tools support this. However, sv2v doesn't seem to support it. Below testcase has two files utils.sv and goo.sv.

File utils.sv:

`define DW 32

File goo.sv:

module goo (
  input  logic inp,
  output logic out
);

  logic [`DW -1:0] foo;

endmodule

Output:

sv2v utils.sv goo.sv
sv2v: Lexical Error: Undefined macro: DW, at ./goo.sv:6:11
CallStack (from HasCallStack):
  error, called at src/Language/SystemVerilog/Parser/Lex.x:353:21 in main:Language.SystemVerilog.Parser.Lex

Add default git tag so git-describe works

Could you make and push a tag for your first commit 363ca80?

git tag -a v0.0 363ca80af20229a887931f57e2809a876cbf5599 -m "First commit"
git push origin v0.0

That way the git-describe command will return a useful value for your repository.

Support for array of struct parameters

foo.v

typedef struct packed
{
  logic [2:0] width;
} baz_s;

parameter baz_s [1:0] bar = '{2, 1};

module foo
 #(parameter width_p = bar[0])
  (input [width_p-1:0] x
   , output [width_p-1:0] y
   );

   assign y = x + 1'b1;

endmodule

Command:

sv2v --oneunit foo.v

Result:

sv2v: Parse error: unexpected token '[' (Sym_brack_l) at ./foo.v:8:17.
CallStack (from HasCallStack):
  error, called at .stack-work/dist/x86_64-linux/Cabal-2.4.0.1/build/sv2v/sv2v-tmp/Language/SystemVerilog/Parser/Parse.hs:6124:22 in main:Language.SystemVerilog.Parser.Parse

This works:

typedef struct packed
{
  logic [2:0] width;
} baz_s;

localparam baz_s my_baz = '{width: 2};

module foo
 #(parameter baz_s width_p = my_baz)
  (input [width_p-1:0] x
   , output [width_p-1:0] y
   );

   assign y = x + 1'b1;

endmodule

Result:

module foo (
	x,
	y
);
	// removed typedef: baz_s
	localparam [2:0] my_baz = '{
		width: 2
	};
	parameter [2:0] width_p = my_baz;
	input [(width_p - 1):0] x;
	output [(width_p - 1):0] y;
	assign y = (x + 1'b1);
endmodule

So it seems that sv2v doesn't like array of structs as parameters.

Page 85/86 are relevant here:
http://www.ece.uah.edu/~gaede/cpe526/2012%20System%20Verilog%20Language%20Reference%20Manual.pdf

The LRM doesn't explicitly forbid or permit structs as a type for parameters, but Synopsys tools do accept them (and they're very useful in certain niche cases!). Haven't checked with other vendors.

Support "for (int i =0; ...)" inside always_comb blocks

module foo;
  logic [3:0] goo;
  always_comb
    for (int i = 0; i < 4; i++)
      goo[i] = 1'b0;
endmodule

Generated Verilog:

module foo;
	reg [3:0] goo;
	always @(*) begin : sv2v_autoblock_0
		reg signed [31:0] i;  // <-- issue: can't declare variable inside always block 
		for (i = 0; (i < 4); i = (i + 1))
			goo[i] = 1'b0;
	end
endmodule

Instead, it could generate something like this:

module foo;
  reg [3:0] goo;
  integer i_autoblock_0;
  always @(*)  
    for (i_autoblock_0 = 0; (i_autoblock_0 < 4); i_autoblock_0 = (i_autoblock_0 + 1))
      goo[i] = 1'b0;
endmodule

Support for multi-line macro definitions

sv2v seems to have a problem with backslash-delimited multi-line macros.

// Doesn't work
// foo.vh:6:35: Parse error: unexpected token '\' (Unknown)
`define declare_foo_s(a_width_mp) \
    typedef struct packed         \
    {                             \
      logic [a_width_mp-1:0] a;   \
    } foo_s


// Works
`define declare_foo_s(a_width_mp) typedef struct packed { logic [a_width_mp-1:0] a; } foo_s

Support functions with empty argument lists

SystemVerilog input:

function automatic logic [31:0] nop ();
  return 32'h00000013;
endfunction

Output:

Parse error: unexpected token ')' (Sym_paren_r) at ./dm_pkg.sv:373:42.
CallStack (from HasCallStack):
  error, called at .stack-work/dist/x86_64-linux-tinfo6/Cabal-2.4.0.1/build/sv2v/sv2v-tmp/Language/SystemVerilog/Parser/Parse.hs:6149:22 in main:Language.SystemVerilog.Parser.Parse

It does however work without the () at the end of the first line.

Avoid explicit unsigned parameters

Similar to issue #45, Yosys errors out on the following unsigned parameters:

parameter unsigned ...
localparam unsigned ...

Could sv2v simply remove the unsigned for parameter and localparam?

Let me know if you need a testcase for this. Thanks!

[question] Is the grammar complete?

Hello,

I like simplicity of your SV grammar

Seeing from history, you probably building it on your own.
Do you have any system in it, I mean can you measure how much does remain?

If I compare for example property expression rule in this two grammars.

https://github.com/zachjs/sv2v/blob/master/src/Language/SystemVerilog/Parser/Parse.y#L498

https://github.com/Nic30/hdlConvertor/blob/sv2017/grammars/sv2017Parser.g4#L979

There is wast difference. I would like to simplify the second grammar and I am asking if you do have some tool which can be used to simplify the grammar or you simplified some rules and you know that they are complete and correct.

Thanks for response,
Nic30

Macro defined in package not found

foo_pkg.vh

package foo_pkg;
  `define width_calc(a) (a+3)
endpackage

foo.v

module foo
import foo_pkg::*;
 #(parameter width = `width_calc(2))
  (input [width-1:0] i
   , output [width-1:0] o
   );

 assign o = i + 1'b1;

endmodule

Command:

$ sv2v foo_pkg.vh foo.v

Result:

sv2v: Lexical Error: Undefined macro: width_calc, at ./foo.v:4:33
CallStack (from HasCallStack):
  error, called at src/Language/SystemVerilog/Parser/Lex.x:346:21 in main:Language.SystemVerilog.Parser.Lex

However, this works:
bar.v:

`define width_calc(a) (a+3)

module bar
 #(parameter width = `width_calc(2))
  (input [width-1:0] i
   , output [width-1:0] o
   );

 assign o = i + 1'b1;

endmodule

Command:

sv2v bar.v

Result:

module bar (
	i,
	o
);
	parameter width = (2 + 3);
	input [(width - 1):0] i;
	output [(width - 1):0] o;
	assign o = (i + 1'b1);
endmodule

Support bitwidth casting

File foo.sv:

module foo;
  localparam BW = 3;
  wire [2:0] test;
  assign test = BW'(0);  // <- see this bitwidth casting
endmodule

Generated Verilog:

module foo;
  localparam BW = 3;
  wire [2:0] test;
  assign test = BW'(0);  // <-- this should not be here
endmodule

Instead of keeping the bitwidth casting in the generated Verilog, sv2v could simply replace it by 0.

Array flattening in nested structs

Similar to #11, except that if there is an array of nested structs:

package foo_pkg;

  typedef struct packed {
    logic [31:0] q;
  } key_t;

  typedef struct packed {
    key_t [7:0] keys;
  } inp_t;

endpackage

module bar (
  input  foo_pkg::inp_t dat_i,
  output logic [31:0] key_o
);
  assign key_o = dat_i.keys[0].q;
endmodule

Running ec0eecb produces both the wrong size for dat_i (only 8 bits instead of 256) and an invalid multi-dimensional dereference:

module bar (
	dat_i,
	key_o
);
	input wire [7:0] dat_i;
	output wire [31:0] key_o;
	assign key_o = dat_i[0][31:0];
endmodule

(example distilled from https://github.com/lowRISC/opentitan/blob/master/hw/ip/aes/rtl/aes_core.sv since that is the first file that sv2v hits in their syn_yosys script)

New open source SystemVerilog compliance suite being created

It might be of interest to you that the SymbiFlow project has started working on an open source System Verilog compliance suite which can be found at https://github.com/SymbiFlow/sv-tests

It's still very early stages, but its goal is to cover the whole of the System Verilog LRM.

The project is currently trying to produce a "status report" for popular open source tools and your sv2v parser is being added in https://github.com/SymbiFlow/sv-tests/pull/47 . The resulting output report can be found at https://symbiflow.github.io/sv-tests/.

Support 2-dimensional ports

SystemVerilog input:

input [DW-1:0] req_data [N],

Generated Verilog:

input [(DW - 1):0] req_data [(N - 1):0];

However, Verilog doesn't support multi-dimensional ports. So could sv2v convert it into a 1-dimensional bus, such as input [DW*N-1 : 0] req_data? Thanks

Possible error with port parsing

I'm not totally sure where this error is coming from but I'm assuming it's port parsing (possibly when data types are in use?). I'm trying to translate the rename unit of AnyCore.

From the directory above, I created an sv2v.flist file containing:

../ISA/RISCV_ISA.h
../configs/CommonConfig.h
../configs/RAM_Params.h
../include/structs.sv
Rename.sv
RenameDispatch.sv
RenameLane.sv
RenameMapTable.sv
SpecFreeList.sv
ppa_rename.sv

And then ran cat sv2v.flist | xargs sv2v -i ../ISA -i ../include -i ../configs -o. Besides the deprecations the output is:

sv2v: takeIdent didn't find identifier: [DTComma,DTDir input,DTIdent "phys_reg",DTIdent "freedPhyReg_i",DTRange (:,(0,(1 - 1))),DTComma,DTDir output,DTType reg,DTRange (:,(((8 + 1) - 1),0)),DTIdent "freePhyReg_o",DTRange (:,(0,(1 - 1))),DTComma,DTDir output,DTType reg,DTIdent "freeListEmpty_o",DTComma,DTDir output,DTIdent "flRamReady_o"]
CallStack (from HasCallStack):
  error, called at src/Language/SystemVerilog/Parser/ParseDecl.hs:398:20 in main:Language.SystemVerilog.Parser.ParseDecl

I also get a similar error for other components of the core. It's possible I changed some other stuff in AnyCore (it's an old clone that I was in the middle of changing) but I think it's mostly just what came with it and should be reproducible.

Support for unique case inside

module foo(
    input  logic x,
    output logic y
);

    always_comb
        unique case (x) inside
            [1:2]:   y = 0;
            default: y = 1;
        endcase

endmodule

Should translate to

module foo (
        x,
        y
);
        input wire x;
        output reg y;
        always @(*)
                case (x)
                        1, 2: y = 0;
                        default: y = 1;
                endcase
endmodule

Support for packed unions

baz_pkg.v

package baz_pkg;

typedef union packed
{
  logic [5:0] a;
  logic [5:0] b;
} baz_u;

endpackage

Command:

sv2v baz_pkg.v

Result:

sv2v: Parse error: unexpected token 'packed' (KW_packed) at ./baz_pkg.v:4:15.
CallStack (from HasCallStack):
  error, called at .stack-work/dist/x86_64-linux/Cabal-2.4.0.1/build/sv2v/sv2v-tmp/Language/SystemVerilog/Parser/Parse.hs:6134:22 in main:Language.SystemVerilog.Parser.Parse

Packed unions are defined around page 142: IEEE_Std1800-2017

Thanks!

Misinterpretation of '1

'1 should set all bits to 1 (not just bit 0), this is a common mistake. Testcase foo.sv:

module foo;
  logic [7:0] goo;
  assign goo = '1;
endmodule

Generated Verilog:

module foo;
	wire [7:0] goo;
	assign goo = 'b1;  // <-- should be {8{1'b1}} instead
endmodule

Support for set membership operator "inside"

File foo.sv:

module foo;
  logic [1:0] a;

  initial
    if (a inside {2'b01, 2'b11})
      $display("foo");

endmodule

Error message:

sv2v: Parse error: unexpected token 'inside' (Id_simple) at ./foo.sv:5:11.
CallStack (from HasCallStack):
  error, called at .stack-work/dist/x86_64-linux-tinfo6/Cabal-2.4.0.1/build/sv2v/sv2v-tmp/Language/SystemVerilog/Parser/Parse.hs:6348:22 in main:Language.SystemVerilog.Parser.Parse

a inside {2'b01, 2'b11} should be expanded to ( (a == 2'b01) || (a == 2'b11) ).

Bug: localparam dependency violation in corner case

package evil_pkg;
    localparam Z = 1;
    localparam A = Z;
    localparam B = Z;

    function logic evil_fun;
        return A;
    endfunction
endpackage

module evil_mdl (
    output logic [evil_pkg::B-1:0] foo
);
    always @(*)
        foo = evil_pkg::evil_fun();
endmodule

Output:

module evil_mdl (foo);
        localparam evil_pkg_A = evil_pkg_Z; // <- VIOLATION !!!!
        localparam evil_pkg_Z = 1;
        localparam evil_pkg_B = evil_pkg_Z;
        function evil_pkg_evil_fun;
                input _sv2v_unused;
                evil_pkg_evil_fun = evil_pkg_A;
        endfunction
        output reg [(evil_pkg_B - 1):0] foo;
        always @(*) foo = evil_pkg_evil_fun();
endmodule

Package imports don't always work

File foo_pkg.sv:

package foo_pkg;
  typedef enum logic [2:0] {
    AccessAck     = 3'd0,
    AccessAckData = 3'd1
  } inp_t;
endpackage

File goo.sv:

module goo;
  import foo_pkg::*;
  inp_t test;
  assign test = foo_pkg::AccessAck;
endmodule

sv2v -o foo_pkg.sv goo.sv produces below, but it should also define parameter foo_pkg_AccessAck:

module goo;
  wire [2:0] test;
  assign test = foo_pkg_AccessAck;
endmodule

Interestingly, if goo.sv is changed as follows, then correct output is generated:
Modified goo.sv (only line 4 is modified):

module goo;
  import foo_pkg::*;
  inp_t test;
  assign test = AccessAck;
endmodule

Correctly generated Verilog (see line 2, which correctly defines the localparm AccessAck):

module goo;
  localparam [2:0] AccessAck = 3'd0;
  wire [2:0] test;
  assign test = AccessAck;
endmodule

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.