verilog/
lib.rs

1extern crate lalrpop_util;
2extern crate regex;
3
4pub mod ast;
5pub mod verilog_parser;
6
7pub use lalrpop_util::ParseError as ParseError;
8use regex::Regex;
9use std::fmt::Debug;
10
11
12pub fn codelist(code: &str) {
13    for (i, line) in code.lines().enumerate() {
14        println!("{:>3} | {}", i+1, line);
15    }
16}
17
18pub fn code_error(code: &str, tok_pos: usize) {
19    let code = format!("\n\n{}", code);
20    let code = code.lines().collect::<Vec<_>>();
21    let mut pos: isize = 0;
22    for (i, lines) in (&code[..]).windows(3).enumerate() {
23        if pos + lines[2].len() as isize >= tok_pos as isize {
24            if i > 1 {
25                println!("{:>3} | {}", i - 1, lines[0]);
26            }
27            if i > 0 {
28                println!("{:>3} | {}", i, lines[1]);
29            }
30            println!("{:>3} | {}", i + 1, lines[2]);
31
32            println!("{}^", (0..(tok_pos as isize) - (pos - 6)).map(|_| "~").collect::<String>());
33            return;
34        }
35        pos += (lines[2].len() as isize) + 1;
36    }
37}
38
39pub fn parse_results<C,T,E>(code: &str, res: Result<C, ParseError<usize,T,E>>) -> C
40where C: Debug, T: Debug, E: Debug {
41    match res {
42        Ok(value) => {
43            return value;
44        }
45        Err(ParseError::InvalidToken {
46            location: loc
47        }) => {
48            println!("Error: Invalid token:");
49            code_error(code, loc);
50            panic!("{:?}", res);
51        }
52        Err(ParseError::UnrecognizedToken {
53            token: Some((loc, _, _)),
54            ..
55        }) => {
56            println!("Error: Unrecognized token:");
57            code_error(code, loc);
58            panic!("{:?}", res);
59        }
60        err => {
61            panic!("{:?}", err);
62        }
63    }
64}
65
66// Easy invocation of Verilog parsing.
67pub fn parse(code: &str) -> ast::Code {
68    // Removes comments.
69    let re = Regex::new(r"(?m)//.*").unwrap();
70    let code = re.replace_all(&code, "");
71
72    parse_results(&code, verilog_parser::parse_Code(&code))
73}
74
75trait ToVerilog {
76    fn to_verilog(&self) -> String;
77}
78
79impl ToVerilog for ast::Code {
80    fn to_verilog(&self) -> String {
81        self.0.iter()
82            .map(|x| x.to_verilog())
83            .collect::<Vec<_>>()
84            .join("\n")
85    }
86}
87
88impl ToVerilog for ast::Toplevel {
89    fn to_verilog(&self) -> String {
90        match self {
91            &ast::Toplevel::Module(ast::Ident(ref name), ref args, ref decls) => {
92                format!("module {name} ({args}\n);{decls}\nendmodule\n",
93                    name=name,
94                    args=args.iter()
95                        .map(|a| format!("\n{}", (a.0).0))
96                        .collect::<Vec<_>>()
97                        .join(","),
98                    decls=decls.iter()
99                        .map(|a| a.to_verilog())
100                        .collect::<Vec<_>>()
101                        .join(""))
102            }
103        }
104    }
105}
106
107impl ToVerilog for ast::Decl {
108    fn to_verilog(&self) -> String {
109        match self {
110            &ast::Decl::InnerArg(ref args) => {
111                format!("\n{args};",
112                    args=args.iter()
113                        .map(|a| format!("{}", (a.0).0))
114                        .collect::<Vec<_>>()
115                        .join(", "))
116            }
117            &ast::Decl::Reg(ast::Ident(ref name), ref dims) => {
118                format!("\nreg [{dims}] {name};",
119                    name=name,
120                    dims=dims.iter()
121                        .map(|a| format!("{}", a.to_verilog()))
122                        .collect::<Vec<_>>()
123                        .join(":"))
124            }
125            &ast::Decl::Always(ref edge, ref body) => {
126                format!("\nalways @({edge}) {body}",
127                    edge=edge.to_verilog(),
128                    body=body.to_verilog())
129            }
130            _ => { "\nTODO;".to_string() },
131        }
132    }
133}
134
135impl ToVerilog for ast::Seq {
136    fn to_verilog(&self) -> String {
137        match self {
138            &ast::Seq::If(ref cond, ref then, ref alt) => {
139                format!("\nif ({cond}) {then}{alt}",
140                    cond=cond.to_verilog(),
141                    then=then.to_verilog(),
142                    alt=if let &Some(ref alt) = alt {
143                        format!("\nelse {then}",
144                            then=alt.to_verilog())
145                    } else {
146                        "".to_string()
147                    })
148            }
149            &ast::Seq::Set(ref kind, ast::Ident(ref name), ref value) => {
150                format!("\n{name} {kind} {value};",
151                    name=name,
152                    kind="<=",
153                    value=value.to_verilog())
154            }
155            _ => { "\nTODO;".to_string() },
156        }
157    }
158}
159
160impl ToVerilog for ast::SeqBlock {
161    fn to_verilog(&self) -> String {
162        if (self.0).len() == 0 {
163            panic!("should be > 0")
164        } else if (self.0).len() == 1 {
165            (self.0)[0].to_verilog()
166        } else {
167            format!("\nbegin{}\nend", self.0.iter().map(|x| x.to_verilog()).collect::<Vec<_>>().join(""))
168        }
169    }
170}
171
172impl ToVerilog for ast::Expr {
173    fn to_verilog(&self) -> String {
174        match self {
175            &ast::Expr::Ref(ast::Ident(ref name)) => {
176                name.to_string()
177            }
178            &ast::Expr::Num(value) => {
179                format!("{}", value)
180            }
181            &ast::Expr::Arith(ref op, ref left, ref right) => {
182                format!("{left} {op} {right}",
183                    left=left.to_verilog(),
184                    op=match *op {
185                        ast::Op::Add => "+",
186                        _ => "??",
187                    },
188                    right=right.to_verilog())
189            }
190            _ => { "TODO EXPR".to_string() },
191        }
192    }
193}
194
195impl ToVerilog for ast::EdgeRef {
196    fn to_verilog(&self) -> String {
197        format!("{} {}", self.1.to_verilog(), (self.0).0)
198    }
199}
200
201impl ToVerilog for ast::Edge {
202    fn to_verilog(&self) -> String {
203        match self {
204            &ast::Edge::Pos => "posedge".to_string(),
205            &ast::Edge::Neg => "negedge".to_string(),
206        }
207    }
208}
209
210#[test]
211fn test_parser() {
212    let input = r#"
213//-----------------------------------------------------
214// Design Name : up_counter
215// File Name   : up_counter.v
216// Function    : Up counter
217// Coder       : Deepak
218//-----------------------------------------------------
219module up_counter    (
220out     ,  // Output of the counter
221enable  ,  // enable for counter
222clk     ,  // clock Input
223reset      // reset Input
224);
225//----------Output Ports--------------
226     output [7:0] out;
227//------------Input Ports--------------
228  input enable, clk, reset;
229//------------Internal Variables--------
230 reg [7:0] out;
231//-------------Code Starts Here-------
232 always @(posedge clk)
233 if (reset) begin
234   out <= 8'b0 ;
235 end else if (enable) begin
236   out <= out + 1;
237 end
238endmodule
239"#;
240
241    let res = parse(input);
242    println!("Out: {:?}", res);
243    println!("Out: \n{}\n", res.to_verilog());
244}