1pub mod ast;
2pub mod lexer;
3
4use crate::ast::{Circuit, Module};
5use crate::firrtl::*;
6use crate::lexer::{FIRRTLLexer, Token, LexicalError};
7use ast::CircuitModule;
8use lalrpop_util::{lalrpop_mod, ParseError};
9
10lalrpop_mod!(pub firrtl);
11
12pub type FIRRTLParserError = ParseError<usize, Token, LexicalError>;
13
14pub fn parse_circuit(source: &str) -> Result<Circuit, FIRRTLParserError> {
16 let lexer = FIRRTLLexer::new(source);
17 let parser = CircuitParser::new();
18 parser.parse(lexer)
19}
20
21#[cfg(test)]
22mod lexer_test {
23 use crate::lexer::*;
24
25 fn run(source: &str) {
26 let mut lex = FIRRTLLexer::new(source);
27 while let Some(ts) = lex.next_token() {
28 println!("{:?}", ts);
29 match ts.token {
30 Token::Error => {
31 println!("{:?}", ts);
32 panic!("Got a error token");
33 }
34 _ => { }
35 }
36 }
37 }
38
39 #[test]
40 fn gcd() {
41 let source =
42r#"FIRRTL version 3.3.0
43circuit GCD :
44 module GCD : @[src/main/scala/gcd/GCD.scala 15:7]
45 input clock : Clock @[src/main/scala/gcd/GCD.scala 15:7]
46 input reset : UInt<1> @[src/main/scala/gcd/GCD.scala 15:7]
47 output io : { flip value1 : UInt<16>, flip value2 : UInt<16>, flip loadingValues : UInt<1>, outputGCD : UInt<16>, outputValid : UInt<1>} @[src/main/scala/gcd/GCD.scala 16:14]
48
49 reg x : UInt, clock @[src/main/scala/gcd/GCD.scala 24:15]
50 reg y : UInt, clock @[src/main/scala/gcd/GCD.scala 25:15]
51 node _T = gt(x, y) @[src/main/scala/gcd/GCD.scala 27:10]
52 when _T : @[src/main/scala/gcd/GCD.scala 27:15]
53 node _x_T = sub(x, y) @[src/main/scala/gcd/GCD.scala 27:24]
54 node _x_T_1 = tail(_x_T, 1) @[src/main/scala/gcd/GCD.scala 27:24]
55 connect x, _x_T_1 @[src/main/scala/gcd/GCD.scala 27:19]
56 else :
57 node _y_T = sub(y, x) @[src/main/scala/gcd/GCD.scala 28:25]
58 node _y_T_1 = tail(_y_T, 1) @[src/main/scala/gcd/GCD.scala 28:25]
59 connect y, _y_T_1 @[src/main/scala/gcd/GCD.scala 28:20]
60 when io.loadingValues : @[src/main/scala/gcd/GCD.scala 30:26]
61 connect x, io.value1 @[src/main/scala/gcd/GCD.scala 31:7]
62 connect y, io.value2 @[src/main/scala/gcd/GCD.scala 32:7]
63 connect io.outputGCD, x @[src/main/scala/gcd/GCD.scala 35:16]
64 node _io_outputValid_T = eq(y, UInt<1>(0h0)) @[src/main/scala/gcd/GCD.scala 36:23]
65 connect io.outputValid, _io_outputValid_T @[src/main/scala/gcd/GCD.scala 36:18]
66"#;
67
68 run(source);
69 }
70
71 #[test]
72 fn one_read_one_write_sram() {
73 let source =
74r#"FIRRTL version 3.3.0
75circuit OneReadOneWritePortSRAM :
76 module OneReadOneWritePortSRAM : @[src/main/scala/gcd/SRAM.scala 10:7]
77 input clock : Clock @[src/main/scala/gcd/SRAM.scala 10:7]
78 input reset : UInt<1> @[src/main/scala/gcd/SRAM.scala 10:7]
79 output io : { flip ren : UInt<1>, flip raddr : UInt<3>, rdata : UInt<2>[4], flip wen : UInt<1>, flip waddr : UInt<3>, flip wdata : UInt<2>[4], flip wmask : UInt<1>[4]} @[src/main/scala/gcd/SRAM.scala 11:14]
80
81 smem mem : UInt<2>[4] [8] @[src/main/scala/gcd/SRAM.scala 22:24]
82 when io.wen : @[src/main/scala/gcd/SRAM.scala 23:17]
83 write mport MPORT = mem[io.waddr], clock @[src/main/scala/gcd/SRAM.scala 24:14]
84 when io.wmask[0] : @[src/main/scala/gcd/SRAM.scala 24:14]
85 connect MPORT[0], io.wdata[0] @[src/main/scala/gcd/SRAM.scala 24:14]
86 when io.wmask[1] : @[src/main/scala/gcd/SRAM.scala 24:14]
87 connect MPORT[1], io.wdata[1] @[src/main/scala/gcd/SRAM.scala 24:14]
88 when io.wmask[2] : @[src/main/scala/gcd/SRAM.scala 24:14]
89 connect MPORT[2], io.wdata[2] @[src/main/scala/gcd/SRAM.scala 24:14]
90 when io.wmask[3] : @[src/main/scala/gcd/SRAM.scala 24:14]
91 connect MPORT[3], io.wdata[3] @[src/main/scala/gcd/SRAM.scala 24:14]
92 wire _WIRE : UInt<3> @[src/main/scala/gcd/SRAM.scala 26:23]
93 invalidate _WIRE @[src/main/scala/gcd/SRAM.scala 26:23]
94 when io.ren : @[src/main/scala/gcd/SRAM.scala 26:23]
95 connect _WIRE, io.raddr @[src/main/scala/gcd/SRAM.scala 26:23]
96 read mport MPORT_1 = mem[_WIRE], clock @[src/main/scala/gcd/SRAM.scala 26:23]
97 connect io.rdata, MPORT_1 @[src/main/scala/gcd/SRAM.scala 26:12]
98 "#;
99
100 run(source);
101 }
102
103 #[test]
104 fn ports_2() {
105 let source = r#"output io : { flip a : UInt<2>, flip b : UInt<2>, flip c : UInt<2>, flip sel : UInt<2>, output : UInt<2>}"#;
106 run(source);
107 }
108
109 #[test]
110 fn extmodule() {
111 let source =
112r#"extmodule plusarg_reader : @[generators/rocket-chip/src/main/scala/util/PlusArg.scala 45:7]
113 output out : UInt<32>
114 defname = plusarg_reader
115 parameter DEFAULT = 0
116 parameter FORMAT = "tilelink_timeout=%d"
117 parameter WIDTH = 32"#;
118 run(source);
119 }
120
121 #[test]
122 fn stmts() {
123 let source =
124r#"reg x : UInt, clock @[src/main/scala/gcd/GCD.scala 24:15]
125reg y : UInt, clock @[src/main/scala/gcd/GCD.scala 25:15]
126node _T = gt(x, y) @[src/main/scala/gcd/GCD.scala 27:10]
127when _T : @[src/main/scala/gcd/GCD.scala 27:15]
128 node _x_T = sub(x, y) @[src/main/scala/gcd/GCD.scala 27:24]
129 node _x_T_1 = tail(_x_T, 1) @[src/main/scala/gcd/GCD.scala 27:24]
130 connect x, _x_T_1 @[src/main/scala/gcd/GCD.scala 27:19]
131else :
132 node _y_T = sub(y, x) @[src/main/scala/gcd/GCD.scala 28:25]
133 node _y_T_1 = tail(_y_T, 1) @[src/main/scala/gcd/GCD.scala 28:25]
134 connect y, _y_T_1 @[src/main/scala/gcd/GCD.scala 28:20]
135when io.loadingValues : @[src/main/scala/gcd/GCD.scala 30:26]
136 connect x, io.value1 @[src/main/scala/gcd/GCD.scala 31:7]
137 connect y, io.value2 @[src/main/scala/gcd/GCD.scala 32:7]
138"#;
139 run(source);
140 }
141
142 #[test]
143 fn circuit_annos() {
144 let source =
145r#"FIRRTL version 3.3.0
146circuit GCD :%[[
147 {
148 "class":"firrtl.transforms.DedupGroupAnnotation",
149 "target":"~TestHarness|IntXbar_i1_o1",
150 "group":"IntXbar_i1_o1"
151 }
152]]
153 module GCD : @[src/main/scala/gcd/GCD.scala 15:7]
154 input clock : Clock @[src/main/scala/gcd/GCD.scala 15:7]
155 input reset : UInt<1> @[src/main/scala/gcd/GCD.scala 15:7]
156 output io : { flip value1 : UInt<16>, flip value2 : UInt<16>, flip loadingValues : UInt<1>, outputGCD : UInt<16>, outputValid : UInt<1>} @[src/main/scala/gcd/GCD.scala 16:14]
157
158 reg x : UInt, clock @[src/main/scala/gcd/GCD.scala 24:15]
159 reg y : UInt, clock @[src/main/scala/gcd/GCD.scala 25:15]
160 node _T = gt(x, y) @[src/main/scala/gcd/GCD.scala 27:10]
161 when _T : @[src/main/scala/gcd/GCD.scala 27:15]
162 node _x_T = sub(x, y) @[src/main/scala/gcd/GCD.scala 27:24]
163 node _x_T_1 = tail(_x_T, 1) @[src/main/scala/gcd/GCD.scala 27:24]
164 connect x, _x_T_1 @[src/main/scala/gcd/GCD.scala 27:19]
165 else :
166 node _y_T = sub(y, x) @[src/main/scala/gcd/GCD.scala 28:25]
167 node _y_T_1 = tail(_y_T, 1) @[src/main/scala/gcd/GCD.scala 28:25]
168 connect y, _y_T_1 @[src/main/scala/gcd/GCD.scala 28:20]
169 when io.loadingValues : @[src/main/scala/gcd/GCD.scala 30:26]
170 connect x, io.value1 @[src/main/scala/gcd/GCD.scala 31:7]
171 connect y, io.value2 @[src/main/scala/gcd/GCD.scala 32:7]
172 connect io.outputGCD, x @[src/main/scala/gcd/GCD.scala 35:16]
173 node _io_outputValid_T = eq(y, UInt<1>(0h0)) @[src/main/scala/gcd/GCD.scala 36:23]
174 connect io.outputValid, _io_outputValid_T @[src/main/scala/gcd/GCD.scala 36:18]
175"#;
176 run(&source);
177 }
178
179 #[test]
180 fn rocketconfig() -> Result<(), std::io::Error> {
181 let source = std::fs::read_to_string("./test-inputs/chipyard.harness.TestHarness.RocketConfig.fir")?;
182 run(&source);
183 Ok(())
184 }
185
186 #[test]
187 fn largeboomconfig() -> Result<(), std::io::Error> {
188 let source = std::fs::read_to_string("./test-inputs/chipyard.harness.TestHarness.LargeBoomV3Config.fir")?;
189 run(&source);
190 Ok(())
191 }
192
193}
194
195#[cfg(test)]
196mod parser_test {
197 use crate::lexer::*;
198 use crate::firrtl::*;
199
200 #[test]
201 fn stmts() {
202 let source =
203r#"reg x : UInt, clock @[src/main/scala/gcd/GCD.scala 24:15]
204reg y : UInt, clock @[src/main/scala/gcd/GCD.scala 25:15]
205node _T = gt(x, y) @[src/main/scala/gcd/GCD.scala 27:10]
206when _T : @[src/main/scala/gcd/GCD.scala 27:15]
207 node _x_T = sub(x, y) @[src/main/scala/gcd/GCD.scala 27:24]
208 node _x_T_1 = tail(_x_T, 1) @[src/main/scala/gcd/GCD.scala 27:24]
209 connect x, _x_T_1 @[src/main/scala/gcd/GCD.scala 27:19]
210else :
211 node _y_T = sub(y, x) @[src/main/scala/gcd/GCD.scala 28:25]
212 node _y_T_1 = tail(_y_T, 1) @[src/main/scala/gcd/GCD.scala 28:25]
213 connect y, _y_T_1 @[src/main/scala/gcd/GCD.scala 28:20]
214when io.loadingValues : @[src/main/scala/gcd/GCD.scala 30:26]
215 connect x, io.value1 @[src/main/scala/gcd/GCD.scala 31:7]
216 connect y, io.value2 @[src/main/scala/gcd/GCD.scala 32:7]
217"#;
218 let lexer = FIRRTLLexer::new(source);
219 let parser = StmtsParser::new();
220 let ast = parser.parse(lexer).unwrap();
221
222 for stmt in ast.iter() {
223 stmt.traverse();
224 }
225 }
226
227 #[test]
228 fn ports() {
229 let source =
230r#"
231input clock : Clock @[src/main/scala/gcd/GCD.scala 15:7]
232input reset : UInt<1> @[src/main/scala/gcd/GCD.scala 15:7]
233output io : { flip value1 : UInt<16>, flip value2 : UInt<16>, flip loadingValues : UInt<1>, outputGCD : UInt<16>, outputValid : UInt<1>} @[src/main/scala/gcd/GCD.scala 16:14]
234"#;
235 let lexer = FIRRTLLexer::new(source);
236 let parser = PortsParser::new();
237 let ast = parser.parse(lexer).unwrap();
238 println!("{:?}", ast);
239 }
240
241 #[test]
242 fn ports_2() {
243 let source = r#"output io : { flip a : UInt<2>, flip b : UInt<2>, flip c : UInt<2>, flip sel : UInt<2>, output : UInt<2>}"#;
244 let lexer = FIRRTLLexer::new(source);
245 let parser = PortsParser::new();
246 let ast = parser.parse(lexer).unwrap();
247 println!("{:?}", ast);
248 }
249
250 #[test]
251 fn ports_3() {
252 let source = r#"output io : { flip in : { a : { ready : UInt<1>, valid : UInt<1>, bits : { opcode : UInt<3>, param : UInt<3>, size : UInt<4>, source : UInt<5>, address : UInt<32>, user : { }, echo : { }, mask : UInt<8>, data : UInt<64>, corrupt : UInt<1>}}, d : { ready : UInt<1>, valid : UInt<1>, bits : { opcode : UInt<3>, param : UInt<2>, size : UInt<4>, source : UInt<5>, sink : UInt<3>, denied : UInt<1>, user : { }, echo : { }, data : UInt<64>, corrupt : UInt<1>}}}} @[generators/rocket-chip/src/main/scala/tilelink/Monitor.scala 20:14]"#;
253 let lexer = FIRRTLLexer::new(source);
254 let parser = PortsParser::new();
255 let ast = parser.parse(lexer).unwrap();
256 println!("{:?}", ast);
257 }
258
259 #[test]
260 fn when() {
261 let source =
262r#"
263when io.in.a.valid : @[generators/rocket-chip/src/main/scala/tilelink/Monitor.scala 372:27]
264 node _T = leq(io.in.a.bits.opcode, UInt<3>(0h7)) @[generators/rocket-chip/src/main/scala/tilelink/Bundles.scala 42:24]
265 node _T_1 = asUInt(reset) @[generators/rocket-chip/src/main/scala/tilelink/Monitor.scala 45:11]
266 node _T_2 = eq(_T_1, UInt<1>(0h0)) @[generators/rocket-chip/src/main/scala/tilelink/Monitor.scala 45:11]
267 when _T_2 : @[generators/rocket-chip/src/main/scala/tilelink/Monitor.scala 45:11]
268 node _T_3 = eq(_T, UInt<1>(0h0)) @[generators/rocket-chip/src/main/scala/tilelink/Monitor.scala 45:11]
269 when _T_3 : @[generators/rocket-chip/src/main/scala/tilelink/Monitor.scala 45:11]
270 printf(clock, UInt<1>(0h1), "Assertion failed: 'A' channel has invalid opcode (connected at generators/rocket-chip/src/main/scala/subsystem/SystemBus.scala:48:55)\n at Monitor.scala:45 assert(cond, message)\n") : printf @[generators/rocket-chip/src/main/scala/tilelink/Monitor.scala 45:11]
271 assert(clock, _T, UInt<1>(0h1), "") : assert @[generators/rocket-chip/src/main/scala/tilelink/Monitor.scala 45:11]
272"#;
273
274 let lexer = FIRRTLLexer::new(source);
275 let parser = StmtsParser::new();
276 let ast = parser.parse(lexer).unwrap();
277 println!("{:?}", ast);
278
279 }
280
281 #[test]
282 fn module() {
283 let source =
284r#"
285module GCD : @[src/main/scala/gcd/GCD.scala 15:7]
286 input clock : Clock @[src/main/scala/gcd/GCD.scala 15:7]
287 input reset : UInt<1> @[src/main/scala/gcd/GCD.scala 15:7]
288 output io : { flip value1 : UInt<16>, flip value2 : UInt<16>, flip loadingValues : UInt<1>, outputGCD : UInt<16>, outputValid : UInt<1>} @[src/main/scala/gcd/GCD.scala 16:14]
289
290 reg x : UInt, clock @[src/main/scala/gcd/GCD.scala 24:15]
291 reg y : UInt, clock @[src/main/scala/gcd/GCD.scala 25:15]
292 node _T = gt(x, y) @[src/main/scala/gcd/GCD.scala 27:10]
293 when _T : @[src/main/scala/gcd/GCD.scala 27:15]
294 node _x_T = sub(x, y) @[src/main/scala/gcd/GCD.scala 27:24]
295 node _x_T_1 = tail(_x_T, 1) @[src/main/scala/gcd/GCD.scala 27:24]
296 connect x, _x_T_1 @[src/main/scala/gcd/GCD.scala 27:19]
297 else :
298 node _y_T = sub(y, x) @[src/main/scala/gcd/GCD.scala 28:25]
299 node _y_T_1 = tail(_y_T, 1) @[src/main/scala/gcd/GCD.scala 28:25]
300 connect y, _y_T_1 @[src/main/scala/gcd/GCD.scala 28:20]
301 when io.loadingValues : @[src/main/scala/gcd/GCD.scala 30:26]
302 connect x, io.value1 @[src/main/scala/gcd/GCD.scala 31:7]
303 connect y, io.value2 @[src/main/scala/gcd/GCD.scala 32:7]
304 connect io.outputGCD, x @[src/main/scala/gcd/GCD.scala 35:16]
305 node _io_outputValid_T = eq(y, UInt<1>(0h0)) @[src/main/scala/gcd/GCD.scala 36:23]
306 connect io.outputValid, _io_outputValid_T @[src/main/scala/gcd/GCD.scala 36:18]
307"#;
308 let lexer = FIRRTLLexer::new(source);
309 let parser = ModuleParser::new();
310 let ast = parser.parse(lexer).unwrap();
311 println!("{:?}", ast);
312 }
313 #[test]
314 fn version() {
315 let source = r#"FIRRTL version 3.3.0"#;
316 let lexer = FIRRTLLexer::new(source);
317 let parser = VersionParser::new();
318 let ast = parser.parse(lexer).unwrap();
319 println!("{:?}", ast);
320 }
321
322 #[test]
323 fn circuit() {
324 let source =
325r#"FIRRTL version 3.3.0
326circuit GCD :
327 module GCD : @[src/main/scala/gcd/GCD.scala 15:7]
328 input clock : Clock @[src/main/scala/gcd/GCD.scala 15:7]
329 input reset : UInt<1> @[src/main/scala/gcd/GCD.scala 15:7]
330 output io : { flip value1 : UInt<16>, flip value2 : UInt<16>, flip loadingValues : UInt<1>, outputGCD : UInt<16>, outputValid : UInt<1>} @[src/main/scala/gcd/GCD.scala 16:14]
331
332 reg x : UInt, clock @[src/main/scala/gcd/GCD.scala 24:15]
333 reg y : UInt, clock @[src/main/scala/gcd/GCD.scala 25:15]
334 node _T = gt(x, y) @[src/main/scala/gcd/GCD.scala 27:10]
335 when _T : @[src/main/scala/gcd/GCD.scala 27:15]
336 node _x_T = sub(x, y) @[src/main/scala/gcd/GCD.scala 27:24]
337 node _x_T_1 = tail(_x_T, 1) @[src/main/scala/gcd/GCD.scala 27:24]
338 connect x, _x_T_1 @[src/main/scala/gcd/GCD.scala 27:19]
339 else :
340 node _y_T = sub(y, x) @[src/main/scala/gcd/GCD.scala 28:25]
341 node _y_T_1 = tail(_y_T, 1) @[src/main/scala/gcd/GCD.scala 28:25]
342 connect y, _y_T_1 @[src/main/scala/gcd/GCD.scala 28:20]
343 when io.loadingValues : @[src/main/scala/gcd/GCD.scala 30:26]
344 connect x, io.value1 @[src/main/scala/gcd/GCD.scala 31:7]
345 connect y, io.value2 @[src/main/scala/gcd/GCD.scala 32:7]
346 connect io.outputGCD, x @[src/main/scala/gcd/GCD.scala 35:16]
347 node _io_outputValid_T = eq(y, UInt<1>(0h0)) @[src/main/scala/gcd/GCD.scala 36:23]
348 connect io.outputValid, _io_outputValid_T @[src/main/scala/gcd/GCD.scala 36:18]
349"#;
350 let lexer = FIRRTLLexer::new(source);
351 let parser = CircuitParser::new();
352 let ast = parser.parse(lexer).unwrap();
353 println!("{:?}", ast);
354 }
355
356 #[test]
357 fn circuit_annos() {
358 let source =
359r#"FIRRTL version 3.3.0
360circuit GCD :%[[
361 {
362 "class":"firrtl.transforms.DedupGroupAnnotation",
363 "target":"~TestHarness|IntXbar_i1_o1",
364 "group":"IntXbar_i1_o1"
365 }
366]]
367 module GCD : @[src/main/scala/gcd/GCD.scala 15:7]
368 input clock : Clock @[src/main/scala/gcd/GCD.scala 15:7]
369 input reset : UInt<1> @[src/main/scala/gcd/GCD.scala 15:7]
370 output io : { flip value1 : UInt<16>, flip value2 : UInt<16>, flip loadingValues : UInt<1>, outputGCD : UInt<16>, outputValid : UInt<1>} @[src/main/scala/gcd/GCD.scala 16:14]
371
372 reg x : UInt, clock @[src/main/scala/gcd/GCD.scala 24:15]
373 reg y : UInt, clock @[src/main/scala/gcd/GCD.scala 25:15]
374 node _T = gt(x, y) @[src/main/scala/gcd/GCD.scala 27:10]
375 when _T : @[src/main/scala/gcd/GCD.scala 27:15]
376 node _x_T = sub(x, y) @[src/main/scala/gcd/GCD.scala 27:24]
377 node _x_T_1 = tail(_x_T, 1) @[src/main/scala/gcd/GCD.scala 27:24]
378 connect x, _x_T_1 @[src/main/scala/gcd/GCD.scala 27:19]
379 else :
380 node _y_T = sub(y, x) @[src/main/scala/gcd/GCD.scala 28:25]
381 node _y_T_1 = tail(_y_T, 1) @[src/main/scala/gcd/GCD.scala 28:25]
382 connect y, _y_T_1 @[src/main/scala/gcd/GCD.scala 28:20]
383 when io.loadingValues : @[src/main/scala/gcd/GCD.scala 30:26]
384 connect x, io.value1 @[src/main/scala/gcd/GCD.scala 31:7]
385 connect y, io.value2 @[src/main/scala/gcd/GCD.scala 32:7]
386 connect io.outputGCD, x @[src/main/scala/gcd/GCD.scala 35:16]
387 node _io_outputValid_T = eq(y, UInt<1>(0h0)) @[src/main/scala/gcd/GCD.scala 36:23]
388 connect io.outputValid, _io_outputValid_T @[src/main/scala/gcd/GCD.scala 36:18]
389"#;
390 let lexer = FIRRTLLexer::new(source);
391 let parser = CircuitParser::new();
392 let ast = parser.parse(lexer).unwrap();
393 println!("{:?}", ast);
394 }
395
396 #[test]
397 fn nested_whens() {
398 let source =
399r#"FIRRTL version 3.3.0
400circuit NestedWhen :
401 module NestedWhen : @[src/main/scala/gcd/NestedWhen.scala 8:7]
402 input clock : Clock @[src/main/scala/gcd/NestedWhen.scala 8:7]
403 input reset : UInt<1> @[src/main/scala/gcd/NestedWhen.scala 8:7]
404 output io : { flip a : UInt<2>, flip b : UInt<2>, flip c : UInt<2>, flip sel : UInt<2>, output : UInt<2>} @[src/main/scala/gcd/NestedWhen.scala 9:14]
405
406 node _T = eq(io.output, UInt<1>(0h0)) @[src/main/scala/gcd/NestedWhen.scala 17:19]
407 when _T : @[src/main/scala/gcd/NestedWhen.scala 17:28]
408 connect io.output, io.a @[src/main/scala/gcd/NestedWhen.scala 18:15]
409 else :
410 node _T_1 = eq(io.output, UInt<1>(0h1)) @[src/main/scala/gcd/NestedWhen.scala 19:26]
411 when _T_1 : @[src/main/scala/gcd/NestedWhen.scala 19:35]
412 connect io.output, io.b @[src/main/scala/gcd/NestedWhen.scala 20:15]
413 else :
414 connect io.output, io.c @[src/main/scala/gcd/NestedWhen.scala 22:15]
415
416"#;
417 let lexer = FIRRTLLexer::new(source);
418 let parser = CircuitParser::new();
419 let ast = parser.parse(lexer).unwrap();
420 println!("{:?}", ast);
421 }
422
423 #[test]
424 fn one_read_one_write_sram() {
425 let source =
426r#"FIRRTL version 3.3.0
427circuit OneReadOneWritePortSRAM :
428 module OneReadOneWritePortSRAM : @[src/main/scala/gcd/SRAM.scala 10:7]
429 input clock : Clock @[src/main/scala/gcd/SRAM.scala 10:7]
430 input reset : UInt<1> @[src/main/scala/gcd/SRAM.scala 10:7]
431 output io : { flip ren : UInt<1>, flip raddr : UInt<3>, rdata : UInt<2>[4], flip wen : UInt<1>, flip waddr : UInt<3>, flip wdata : UInt<2>[4], flip wmask : UInt<1>[4]} @[src/main/scala/gcd/SRAM.scala 11:14]
432
433 smem mem : UInt<2>[4] [8] @[src/main/scala/gcd/SRAM.scala 22:24]
434 when io.wen : @[src/main/scala/gcd/SRAM.scala 23:17]
435 write mport MPORT = mem[io.waddr], clock @[src/main/scala/gcd/SRAM.scala 24:14]
436 when io.wmask[0] : @[src/main/scala/gcd/SRAM.scala 24:14]
437 connect MPORT[0], io.wdata[0] @[src/main/scala/gcd/SRAM.scala 24:14]
438 when io.wmask[1] : @[src/main/scala/gcd/SRAM.scala 24:14]
439 connect MPORT[1], io.wdata[1] @[src/main/scala/gcd/SRAM.scala 24:14]
440 when io.wmask[2] : @[src/main/scala/gcd/SRAM.scala 24:14]
441 connect MPORT[2], io.wdata[2] @[src/main/scala/gcd/SRAM.scala 24:14]
442 when io.wmask[3] : @[src/main/scala/gcd/SRAM.scala 24:14]
443 connect MPORT[3], io.wdata[3] @[src/main/scala/gcd/SRAM.scala 24:14]
444 wire _WIRE : UInt<3> @[src/main/scala/gcd/SRAM.scala 26:23]
445 invalidate _WIRE @[src/main/scala/gcd/SRAM.scala 26:23]
446 when io.ren : @[src/main/scala/gcd/SRAM.scala 26:23]
447 connect _WIRE, io.raddr @[src/main/scala/gcd/SRAM.scala 26:23]
448 read mport MPORT_1 = mem[_WIRE], clock @[src/main/scala/gcd/SRAM.scala 26:23]
449 connect io.rdata, MPORT_1 @[src/main/scala/gcd/SRAM.scala 26:12]
450 "#;
451
452 let lexer = FIRRTLLexer::new(source);
453 let parser = CircuitParser::new();
454 let ast = parser.parse(lexer).unwrap();
455 println!("{:?}", ast);
456 }
457
458 #[test]
459 fn as_clock_stmt() {
460 let source = "node _childClock_T = asClock(UInt<1>(0h0)) @[generators/diplomacy/diplomacy/src/diplomacy/lazymodule/LazyModuleImp.scala 160:25]";
461 let lexer = FIRRTLLexer::new(source);
462 let parser = StmtParser::new();
463 let ast = parser.parse(lexer).unwrap();
464 println!("{:?}", ast);
465 }
466
467 #[test]
468 fn printf_stmt() {
469 let source = r#"printf(clock, UInt<1>(0h1), "Assertion failed: 'A' channel has invalid opcode (connected at generators/rocket-chip/src/main/scala/subsystem/SystemBus.scala:48:55)\n at Monitor.scala:45 assert(cond, message)\n") : printf @[generators/rocket-chip/src/main/scala/tilelink/Monitor.scala 45:11]"#;
470 let lexer = FIRRTLLexer::new(source);
471 let parser = StmtParser::new();
472 let ast = parser.parse(lexer).unwrap();
473 println!("{:?}", ast);
474 }
475
476 #[test]
477 fn empty_type() {
478 let source = "output auto : { } @[generators/diplomacy/diplomacy/src/diplomacy/lazymodule/LazyModuleImp.scala 107:25]";
479 let lexer = FIRRTLLexer::new(source);
480 let parser = PortParser::new();
481 let ast = parser.parse(lexer).unwrap();
482 println!("{:?}", ast);
483 }
484
485 #[test]
486 fn extmodule() {
487 let source =
488r#"extmodule plusarg_reader : @[generators/rocket-chip/src/main/scala/util/PlusArg.scala 45:7]
489 output out : UInt<32>
490 defname = plusarg_reader
491 parameter DEFAULT = 0
492 parameter FORMAT = "tilelink_timeout=%d"
493 parameter WIDTH = 32"#;
494
495 let lexer = FIRRTLLexer::new(source);
496 let parser = CircuitModuleParser::new();
497 let ast = parser.parse(lexer).unwrap();
498 println!("{:?}", ast);
499 }
500
501 #[test] fn primop_name_overlaps_with_variable() {
502 let source =
503r#"
504node pad = or(bootAddrReg, UInt<64>(0h0)) @[generators/rocket-chip/src/main/scala/regmapper/RegField.scala 150:19]
505node _oldBytes_T = bits(pad, 7, 0) @[generators/rocket-chip/src/main/scala/regmapper/RegField.scala 151:57]
506node _oldBytes_T_1 = bits(pad, 15, 8) @[generators/rocket-chip/src/main/scala/regmapper/RegField.scala 151:57]
507node _oldBytes_T_2 = bits(pad, 23, 16) @[generators/rocket-chip/src/main/scala/regmapper/RegField.scala 151:57]
508node _oldBytes_T_3 = bits(pad, 31, 24) @[generators/rocket-chip/src/main/scala/regmapper/RegField.scala 151:57]
509node _oldBytes_T_4 = bits(pad, 39, 32) @[generators/rocket-chip/src/main/scala/regmapper/RegField.scala 151:57]
510node _oldBytes_T_5 = bits(pad, 47, 40) @[generators/rocket-chip/src/main/scala/regmapper/RegField.scala 151:57]
511node _oldBytes_T_6 = bits(pad, 55, 48) @[generators/rocket-chip/src/main/scala/regmapper/RegField.scala 151:57]
512node _oldBytes_T_7 = bits(pad, 63, 56) @[generators/rocket-chip/src/main/scala/regmapper/RegField.scala 151:57]
513"#;
514 let lexer = FIRRTLLexer::new(&source);
515 let parser = StmtsParser::new();
516 let ast = parser.parse(lexer).expect("FAILED");
517 println!("{:?}", ast);
518 }
519
520 #[test] fn empty_skip() {
521 let source =
522r#"
523when do_deq : @[src/main/scala/chisel3/util/Decoupled.scala 273:16]
524 skip
525"#;
526 let lexer = FIRRTLLexer::new(&source);
527 let parser = StmtsParser::new();
528 let ast = parser.parse(lexer).expect("FAILED");
529 println!("{:?}", ast);
530 }
531
532 #[test]
533 fn primop_name_overlaps_with_variable_2() {
534 let source =
535r#"node pad = or(bootAddrReg, UInt<64>(0h0)) @[generators/rocket-chip/src/main/scala/regmapper/RegField.scala 150:19]"#;
536
537 let lexer = FIRRTLLexer::new(&source);
538 let parser = StmtsParser::new();
539 let ast = parser.parse(lexer).expect("FAILED");
540 println!("{:?}", ast);
541 }
542
543 #[test]
544 fn primop_name_overlaps_with_variable_3() {
545 let source =
546r#"
547cmem head : UInt<6> [40] @[generators/rocket-chip-inclusive-cache/design/craft/inclusivecache/src/ListBuffer.scala 48:18]
548cmem tail : UInt<6> [40] @[generators/rocket-chip-inclusive-cache/design/craft/inclusivecache/src/ListBuffer.scala 49:18]
549read mport push_tail = tail[io.push.bits.index], clock @[generators/rocket-chip-inclusive-cache/design/craft/inclusivecache/src/ListBuffer.scala 62:28]
550when _T : @[generators/rocket-chip-inclusive-cache/design/craft/inclusivecache/src/ListBuffer.scala 66:23]
551 node valid_set_shiftAmount = bits(io.push.bits.index, 5, 0) @[src/main/scala/chisel3/util/OneHot.scala 64:49]
552 node _valid_set_T = dshl(UInt<1>(0h1), valid_set_shiftAmount) @[src/main/scala/chisel3/util/OneHot.scala 65:12]
553 node _valid_set_T_1 = bits(_valid_set_T, 39, 0) @[src/main/scala/chisel3/util/OneHot.scala 65:27]
554 connect valid_set, _valid_set_T_1 @[generators/rocket-chip-inclusive-cache/design/craft/inclusivecache/src/ListBuffer.scala 67:15]
555 connect used_set, freeOH @[generators/rocket-chip-inclusive-cache/design/craft/inclusivecache/src/ListBuffer.scala 68:14]
556 write mport MPORT = data[freeIdx], clock @[generators/rocket-chip-inclusive-cache/design/craft/inclusivecache/src/ListBuffer.scala 69:15]
557 connect MPORT, io.push.bits.data @[generators/rocket-chip-inclusive-cache/design/craft/inclusivecache/src/ListBuffer.scala 69:15]
558 when push_valid : @[generators/rocket-chip-inclusive-cache/design/craft/inclusivecache/src/ListBuffer.scala 70:23]
559 write mport MPORT_1 = next[push_tail], clock @[generators/rocket-chip-inclusive-cache/design/craft/inclusivecache/src/ListBuffer.scala 71:17]
560 connect MPORT_1, freeIdx @[generators/rocket-chip-inclusive-cache/design/craft/inclusivecache/src/ListBuffer.scala 71:17]
561 else :
562 write mport MPORT_2 = head[io.push.bits.index], clock @[generators/rocket-chip-inclusive-cache/design/craft/inclusivecache/src/ListBuffer.scala 73:17]
563 connect MPORT_2, freeIdx @[generators/rocket-chip-inclusive-cache/design/craft/inclusivecache/src/ListBuffer.scala 73:17]
564 write mport MPORT_3 = tail[io.push.bits.index], clock @[generators/rocket-chip-inclusive-cache/design/craft/inclusivecache/src/ListBuffer.scala 75:15]
565 connect MPORT_3, freeIdx @[generators/rocket-chip-inclusive-cache/design/craft/inclusivecache/src/ListBuffer.scala 75:15]
566"#;
567 let lexer = FIRRTLLexer::new(&source);
568 let parser = StmtsParser::new();
569 let ast = parser.parse(lexer).expect("FAILED");
570 println!("{:?}", ast);
571 }
572
573 #[test]
574 fn extmodule_without_param() {
575 let source =
576r#"
577extmodule GenericDigitalOutIOCell : @[generators/chipyard/src/main/scala/iocell/IOCell.scala 151:7]
578 output pad : UInt<1>
579 input o : UInt<1>
580 input oe : UInt<1>
581 defname = GenericDigitalOutIOCell
582"#;
583 let lexer = FIRRTLLexer::new(&source);
584 let parser = CircuitModuleParser::new();
585 let ast = parser.parse(lexer).expect("FAILED");
586 println!("{:?}", ast);
587 }
588
589 #[test]
590 fn bug() -> Result<(), std::io::Error> {
591 let source = r#"node _T_567 = asSInt(_T_566) @[generators/rocket-chip/src/main/scala/diplomacy/Parameters.scala 137:46]"#;
592 let lexer = FIRRTLLexer::new(&source);
593 let parser = StmtParser::new();
594 let ast = parser.parse(lexer).expect("FAILED");
595 Ok(())
596 }
597
598 #[test]
599 fn rocketconfig() -> Result<(), std::io::Error> {
600 let source = std::fs::read_to_string("./test-inputs/chipyard.harness.TestHarness.RocketConfig.fir")?;
601 let lexer = FIRRTLLexer::new(&source);
602 let parser = CircuitParser::new();
603 let ast = parser.parse(lexer).expect("FAILED");
604 Ok(())
605 }
606
607 #[test]
608 fn boomconfig() -> Result<(), std::io::Error> {
609 let source = std::fs::read_to_string("./test-inputs/chipyard.harness.TestHarness.LargeBoomV3Config.fir")?;
610 let lexer = FIRRTLLexer::new(&source);
611 let parser = CircuitParser::new();
612 let ast = parser.parse(lexer).expect("FAILED");
613 Ok(())
614 }
615
616 #[test]
617 fn double_indexing() -> Result<(), std::io::Error> {
618 let source = r#"connect io_debug_fetch_pc_0_REG, pcs[io.debug_ftq_idx[0]] @[generators/boom/src/main/scala/v3/ifu/fetch-target-queue.scala 363:36]"#;
619 let lexer = FIRRTLLexer::new(&source);
620 let parser = StmtParser::new();
621 let ast = parser.parse(lexer).expect("FAILED");
622 println!("{:?}", ast);
623 Ok(())
624 }
625
626 #[test]
627 fn rocket_modules() -> Result<(), std::io::Error> {
628 for entry in std::fs::read_dir("./test-inputs/rocket-modules/")? {
629 let entry = entry?;
630 let path = entry.path();
631
632 if path.is_file() {
634 match std::fs::read_to_string(&path) {
635 Ok(source) => {
636 let lexer = FIRRTLLexer::new(&source);
637 let parser = CircuitModuleParser::new();
638
639 println!("Parsing file: {:?}", path);
640 let ast = parser.parse(lexer).expect("TOWORK");
641 }
642 Err(e) => {
643 eprintln!("Could not read file {}: {}", path.display(), e);
644 }
645 }
646 }
647 }
648 Ok(())
649 }
650}