Skip to content

Commit e3b9eaf

Browse files
Merge pull request #53 from AlexandreSinger/feature-parse-arch
[Parse] Added Support for Models
2 parents c3ce0a1 + 933a20c commit e3b9eaf

File tree

5 files changed

+296
-6
lines changed

5 files changed

+296
-6
lines changed

fpga_arch_parser/src/arch.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11

2-
pub struct Model {
2+
pub struct ModelPort {
3+
pub name: String,
4+
pub is_clock: bool,
5+
pub clock: Option<String>,
6+
pub combinational_sink_ports: Vec<String>,
7+
}
38

9+
pub struct Model {
10+
pub name: String,
11+
pub never_prune: bool,
12+
pub input_ports: Vec<ModelPort>,
13+
pub output_ports: Vec<ModelPort>,
414
}
515

616
pub struct Metadata {

fpga_arch_parser/src/lib.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod arch;
1111
mod parse_error;
1212
mod parse_metadata;
1313
mod parse_port;
14+
mod parse_models;
1415
mod parse_tiles;
1516
mod parse_layouts;
1617
mod parse_device;
@@ -22,6 +23,7 @@ mod parse_complex_block_list;
2223
pub use crate::parse_error::FPGAArchParseError;
2324
pub use crate::arch::*;
2425

26+
use crate::parse_models::parse_models;
2527
use crate::parse_tiles::parse_tiles;
2628
use crate::parse_layouts::parse_layouts;
2729
use crate::parse_device::parse_device;
@@ -37,6 +39,7 @@ fn parse_architecture(name: &OwnedName,
3739
return Err(FPGAArchParseError::UnknownAttribute(String::from("Expected to be empty"), parser.position()));
3840
}
3941

42+
let mut models: Option<Vec<Model>> = None;
4043
let mut tiles: Option<Vec<Tile>> = None;
4144
let mut layouts: Option<Vec<Layout>> = None;
4245
let mut device: Option<DeviceInfo> = None;
@@ -49,8 +52,10 @@ fn parse_architecture(name: &OwnedName,
4952
Ok(XmlEvent::StartElement { name, attributes, .. }) => {
5053
match name.to_string().as_str() {
5154
"models" => {
52-
// TODO: Implement.
53-
let _ = parser.skip();
55+
models = match models {
56+
None => Some(parse_models(&name, &attributes, parser)?),
57+
Some(_) => return Err(FPGAArchParseError::DuplicateTag(format!("<{name}>"), parser.position())),
58+
}
5459
},
5560
"tiles" => {
5661
tiles = match tiles {
@@ -128,6 +133,10 @@ fn parse_architecture(name: &OwnedName,
128133
};
129134
}
130135

136+
let models = match models {
137+
Some(t) => t,
138+
None => return Err(FPGAArchParseError::MissingRequiredTag("<models>".to_string())),
139+
};
131140
let tiles = match tiles {
132141
Some(t) => t,
133142
None => return Err(FPGAArchParseError::MissingRequiredTag("<tiles>".to_string())),
@@ -154,7 +163,7 @@ fn parse_architecture(name: &OwnedName,
154163
};
155164

156165
Ok(FPGAArch {
157-
models: Vec::new(),
166+
models,
158167
tiles,
159168
layouts,
160169
device,

fpga_arch_parser/src/parse_complex_block_list.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,8 +477,8 @@ fn parse_pb_type(name: &OwnedName,
477477
}
478478

479479
pub fn parse_complex_block_list(name: &OwnedName,
480-
attributes: &[OwnedAttribute],
481-
parser: &mut EventReader<BufReader<File>>) -> Result<Vec<PBType>, FPGAArchParseError> {
480+
attributes: &[OwnedAttribute],
481+
parser: &mut EventReader<BufReader<File>>) -> Result<Vec<PBType>, FPGAArchParseError> {
482482
assert!(name.to_string() == "complexblocklist");
483483
if !attributes.is_empty() {
484484
return Err(FPGAArchParseError::UnknownAttribute(String::from("Expected to be empty"), parser.position()));
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
use std::fs::File;
2+
use std::io::BufReader;
3+
4+
use xml::common::Position;
5+
use xml::reader::{EventReader, XmlEvent};
6+
use xml::name::OwnedName;
7+
use xml::attribute::OwnedAttribute;
8+
9+
use crate::parse_error::*;
10+
use crate::arch::*;
11+
12+
fn parse_model_port(tag_name: &OwnedName,
13+
attributes: &[OwnedAttribute],
14+
parser: &mut EventReader<BufReader<File>>) -> Result<ModelPort, FPGAArchParseError> {
15+
assert!(tag_name.to_string() == "port");
16+
17+
let mut name: Option<String> = None;
18+
let mut is_clock: Option<bool> = None;
19+
let mut clock: Option<String> = None;
20+
let mut combinational_sink_ports: Option<Vec<String>> = None;
21+
for a in attributes {
22+
match a.name.to_string().as_ref() {
23+
"name" => {
24+
name = match name {
25+
None => Some(a.value.clone()),
26+
Some(_) => return Err(FPGAArchParseError::DuplicateAttribute(a.to_string(), parser.position())),
27+
}
28+
},
29+
"is_clock" => {
30+
is_clock = match is_clock {
31+
None => match a.value.as_ref() {
32+
"0" => Some(false),
33+
"1" => Some(true),
34+
_ => return Err(FPGAArchParseError::AttributeParseError(format!("is_clock can only be 0 or 1, found: {}", a.value), parser.position())),
35+
},
36+
Some(_) => return Err(FPGAArchParseError::DuplicateAttribute(a.to_string(), parser.position())),
37+
}
38+
},
39+
"clock" => {
40+
clock = match clock {
41+
None => Some(a.value.clone()),
42+
Some(_) => return Err(FPGAArchParseError::DuplicateAttribute(a.to_string(), parser.position())),
43+
}
44+
},
45+
"combinational_sink_ports" => {
46+
combinational_sink_ports = match combinational_sink_ports {
47+
None => Some(a.value.split_whitespace().map(str::to_string).collect()),
48+
Some(_) => return Err(FPGAArchParseError::DuplicateAttribute(a.to_string(), parser.position())),
49+
}
50+
},
51+
_ => return Err(FPGAArchParseError::UnknownAttribute(a.to_string(), parser.position())),
52+
};
53+
}
54+
let name = match name {
55+
Some(p) => p,
56+
None => return Err(FPGAArchParseError::MissingRequiredAttribute("name".to_string(), parser.position())),
57+
};
58+
let is_clock = is_clock.unwrap_or(false);
59+
let combinational_sink_ports = combinational_sink_ports.unwrap_or_default();
60+
61+
loop {
62+
match parser.next() {
63+
Ok(XmlEvent::StartElement { name, .. }) => {
64+
return Err(FPGAArchParseError::InvalidTag(name.to_string(), parser.position()));
65+
},
66+
Ok(XmlEvent::EndElement { name }) => {
67+
match name.to_string().as_ref() {
68+
"port" => break,
69+
_ => return Err(FPGAArchParseError::UnexpectedEndTag(name.to_string(), parser.position())),
70+
}
71+
},
72+
Ok(XmlEvent::EndDocument) => {
73+
return Err(FPGAArchParseError::UnexpectedEndOfDocument(name.to_string()));
74+
},
75+
Err(e) => {
76+
return Err(FPGAArchParseError::XMLParseError(format!("{e:?}"), parser.position()));
77+
},
78+
_ => {},
79+
};
80+
}
81+
82+
Ok(ModelPort {
83+
name,
84+
is_clock,
85+
clock,
86+
combinational_sink_ports,
87+
})
88+
}
89+
90+
fn parse_model_port_list(tag_name: &OwnedName,
91+
attributes: &[OwnedAttribute],
92+
parser: &mut EventReader<BufReader<File>>) -> Result<Vec<ModelPort>, FPGAArchParseError> {
93+
assert!(tag_name.to_string() == "input_ports" || tag_name.to_string() == "output_ports");
94+
if !attributes.is_empty() {
95+
return Err(FPGAArchParseError::UnknownAttribute(String::from("Expected to be empty"), parser.position()));
96+
}
97+
98+
let mut ports: Vec<ModelPort> = Vec::new();
99+
loop {
100+
match parser.next() {
101+
Ok(XmlEvent::StartElement { name, attributes, .. }) => {
102+
match name.to_string().as_str() {
103+
"port" => {
104+
ports.push(parse_model_port(&name, &attributes, parser)?);
105+
},
106+
_ => return Err(FPGAArchParseError::InvalidTag(name.to_string(), parser.position())),
107+
};
108+
},
109+
Ok(XmlEvent::EndElement { name }) => {
110+
if name.to_string() == tag_name.to_string() {
111+
break;
112+
} else {
113+
return Err(FPGAArchParseError::UnexpectedEndTag(name.to_string(), parser.position()));
114+
}
115+
},
116+
Ok(XmlEvent::EndDocument) => {
117+
return Err(FPGAArchParseError::UnexpectedEndOfDocument(tag_name.to_string()));
118+
},
119+
Err(e) => {
120+
return Err(FPGAArchParseError::XMLParseError(format!("{e:?}"), parser.position()));
121+
},
122+
_ => {},
123+
}
124+
};
125+
126+
Ok(ports)
127+
}
128+
129+
fn parse_model(tag_name: &OwnedName,
130+
attributes: &[OwnedAttribute],
131+
parser: &mut EventReader<BufReader<File>>) -> Result<Model, FPGAArchParseError> {
132+
assert!(tag_name.to_string() == "model");
133+
134+
let mut name: Option<String> = None;
135+
let mut never_prune: Option<bool> = None;
136+
for a in attributes {
137+
match a.name.to_string().as_ref() {
138+
"name" => {
139+
name = match name {
140+
None => Some(a.value.clone()),
141+
Some(_) => return Err(FPGAArchParseError::DuplicateAttribute(a.to_string(), parser.position())),
142+
}
143+
},
144+
"never_prune" => {
145+
never_prune = match never_prune {
146+
None => match a.value.parse() {
147+
Ok(v) => Some(v),
148+
Err(e) => return Err(FPGAArchParseError::AttributeParseError(format!("{a}: {e}"), parser.position())),
149+
},
150+
Some(_) => return Err(FPGAArchParseError::DuplicateAttribute(a.to_string(), parser.position())),
151+
}
152+
},
153+
_ => return Err(FPGAArchParseError::UnknownAttribute(a.to_string(), parser.position())),
154+
};
155+
}
156+
let name = match name {
157+
Some(p) => p,
158+
None => return Err(FPGAArchParseError::MissingRequiredAttribute("name".to_string(), parser.position())),
159+
};
160+
let never_prune = never_prune.unwrap_or(false);
161+
162+
let mut input_ports: Option<Vec<ModelPort>> = None;
163+
let mut output_ports: Option<Vec<ModelPort>> = None;
164+
loop {
165+
match parser.next() {
166+
Ok(XmlEvent::StartElement { name, attributes, .. }) => {
167+
match name.to_string().as_str() {
168+
"input_ports" => {
169+
input_ports = match input_ports {
170+
None => Some(parse_model_port_list(&name, &attributes, parser)?),
171+
Some(_) => return Err(FPGAArchParseError::DuplicateTag(name.to_string(), parser.position())),
172+
}
173+
},
174+
"output_ports" => {
175+
output_ports = match output_ports {
176+
None => Some(parse_model_port_list(&name, &attributes, parser)?),
177+
Some(_) => return Err(FPGAArchParseError::DuplicateTag(name.to_string(), parser.position())),
178+
}
179+
},
180+
_ => return Err(FPGAArchParseError::InvalidTag(name.to_string(), parser.position())),
181+
};
182+
},
183+
Ok(XmlEvent::EndElement { name }) => {
184+
match name.to_string().as_str() {
185+
"model" => break,
186+
_ => return Err(FPGAArchParseError::UnexpectedEndTag(name.to_string(), parser.position())),
187+
}
188+
},
189+
Ok(XmlEvent::EndDocument) => {
190+
return Err(FPGAArchParseError::UnexpectedEndOfDocument(name.to_string()));
191+
},
192+
Err(e) => {
193+
return Err(FPGAArchParseError::XMLParseError(format!("{e:?}"), parser.position()));
194+
},
195+
_ => {},
196+
}
197+
};
198+
let input_ports = match input_ports {
199+
Some(t) => t,
200+
None => return Err(FPGAArchParseError::MissingRequiredTag("<input_ports>".to_string())),
201+
};
202+
let output_ports = match output_ports {
203+
Some(t) => t,
204+
None => return Err(FPGAArchParseError::MissingRequiredTag("<output_ports>".to_string())),
205+
};
206+
207+
Ok(Model {
208+
name,
209+
never_prune,
210+
input_ports,
211+
output_ports,
212+
})
213+
}
214+
215+
pub fn parse_models(name: &OwnedName,
216+
attributes: &[OwnedAttribute],
217+
parser: &mut EventReader<BufReader<File>>) -> Result<Vec<Model>, FPGAArchParseError> {
218+
assert!(name.to_string() == "models");
219+
if !attributes.is_empty() {
220+
return Err(FPGAArchParseError::UnknownAttribute(String::from("Expected to be empty"), parser.position()));
221+
}
222+
223+
let mut models: Vec<Model> = Vec::new();
224+
loop {
225+
match parser.next() {
226+
Ok(XmlEvent::StartElement { name, attributes, .. }) => {
227+
match name.to_string().as_str() {
228+
"model" => {
229+
models.push(parse_model(&name, &attributes, parser)?);
230+
},
231+
_ => return Err(FPGAArchParseError::InvalidTag(name.to_string(), parser.position())),
232+
};
233+
},
234+
Ok(XmlEvent::EndElement { name }) => {
235+
match name.to_string().as_str() {
236+
"models" => break,
237+
_ => return Err(FPGAArchParseError::UnexpectedEndTag(name.to_string(), parser.position())),
238+
}
239+
},
240+
Ok(XmlEvent::EndDocument) => {
241+
return Err(FPGAArchParseError::UnexpectedEndOfDocument(name.to_string()));
242+
},
243+
Err(e) => {
244+
return Err(FPGAArchParseError::XMLParseError(format!("{e:?}"), parser.position()));
245+
},
246+
_ => {},
247+
}
248+
};
249+
250+
Ok(models)
251+
}

fpga_arch_parser/tests/integration_test.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ fn test_k4_n4_90nm_parse() -> Result<(), FPGAArchParseError> {
2323

2424
let res = fpga_arch_parser::parse(&input_xml)?;
2525

26+
// Check models.
27+
assert_eq!(res.models.len(), 0);
28+
2629
// Check tiles.
2730
assert_eq!(res.tiles.len(), 2);
2831
assert_eq!(res.tiles[0].name,"io");
@@ -182,6 +185,23 @@ fn test_vtr_flagship_parse() -> Result<(), FPGAArchParseError> {
182185

183186
let res = fpga_arch_parser::parse(&input_xml)?;
184187

188+
// Check models.
189+
assert_eq!(res.models.len(), 4);
190+
let multiply_model = &res.models[0];
191+
assert_eq!(multiply_model.name, "multiply");
192+
assert_eq!(multiply_model.input_ports.len(), 2);
193+
let multiply_model_port_a = &multiply_model.input_ports[0];
194+
assert_eq!(multiply_model_port_a.name, "a");
195+
assert_eq!(multiply_model_port_a.combinational_sink_ports.len(), 1);
196+
assert_eq!(multiply_model_port_a.combinational_sink_ports[0], "out");
197+
let multiply_model_port_b = &multiply_model.input_ports[1];
198+
assert_eq!(multiply_model_port_b.name, "b");
199+
assert_eq!(multiply_model_port_b.combinational_sink_ports.len(), 1);
200+
assert_eq!(multiply_model_port_b.combinational_sink_ports[0], "out");
201+
assert_eq!(multiply_model.output_ports.len(), 1);
202+
let multiply_model_port_out = &multiply_model.output_ports[0];
203+
assert_eq!(multiply_model_port_out.name, "out");
204+
185205
// Check tiles
186206
let tiles = &res.tiles;
187207
assert_eq!(tiles.len(), 4);

0 commit comments

Comments
 (0)