Skip to content

Commit d965288

Browse files
[Parse] Added Globl Direct Support
A top-level tag called directlist is used to specify all of the direct connections on the global-level (between tiles).
1 parent e3b9eaf commit d965288

File tree

5 files changed

+240
-3
lines changed

5 files changed

+240
-3
lines changed

fpga_arch_parser/src/arch.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,18 @@ pub struct Segment {
381381
pub switch_points: SegmentSwitchPoints,
382382
}
383383

384+
pub struct GlobalDirect {
385+
pub name: String,
386+
pub from_pin: String,
387+
pub to_pin: String,
388+
pub x_offset: i32,
389+
pub y_offset: i32,
390+
pub z_offset: i32,
391+
pub switch_name: Option<String>,
392+
pub from_side: Option<PinSide>,
393+
pub to_side: Option<PinSide>,
394+
}
395+
384396
pub enum DelayType {
385397
Max,
386398
Min,
@@ -496,5 +508,6 @@ pub struct FPGAArch {
496508
pub device: DeviceInfo,
497509
pub switch_list: Vec<Switch>,
498510
pub segment_list: Vec<Segment>,
511+
pub direct_list: Vec<GlobalDirect>,
499512
pub complex_block_list: Vec<PBType>,
500513
}

fpga_arch_parser/src/lib.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ mod parse_device;
1818
mod parse_switch_list;
1919
mod parse_segment_list;
2020
mod parse_timing;
21+
mod parse_direct_list;
2122
mod parse_complex_block_list;
2223

2324
pub use crate::parse_error::FPGAArchParseError;
@@ -29,6 +30,7 @@ use crate::parse_layouts::parse_layouts;
2930
use crate::parse_device::parse_device;
3031
use crate::parse_switch_list::parse_switch_list;
3132
use crate::parse_segment_list::parse_segment_list;
33+
use crate::parse_direct_list::parse_direct_list;
3234
use crate::parse_complex_block_list::parse_complex_block_list;
3335

3436
fn parse_architecture(name: &OwnedName,
@@ -45,6 +47,7 @@ fn parse_architecture(name: &OwnedName,
4547
let mut device: Option<DeviceInfo> = None;
4648
let mut switch_list: Option<Vec<Switch>> = None;
4749
let mut segment_list: Option<Vec<Segment>> = None;
50+
let mut direct_list: Option<Vec<GlobalDirect>> = None;
4851
let mut complex_block_list: Option<Vec<PBType>> = None;
4952

5053
loop {
@@ -93,9 +96,10 @@ fn parse_architecture(name: &OwnedName,
9396
let _ = parser.skip();
9497
},
9598
"directlist" => {
96-
// TODO: Implement.
97-
// FIXME: Check that this is documented in VTR.
98-
let _ = parser.skip();
99+
direct_list = match direct_list {
100+
None => Some(parse_direct_list(&name, &attributes, parser)?),
101+
Some(_) => return Err(FPGAArchParseError::DuplicateTag(format!("<{name}>"), parser.position())),
102+
}
99103
},
100104
"complexblocklist" => {
101105
complex_block_list = match complex_block_list {
@@ -161,6 +165,7 @@ fn parse_architecture(name: &OwnedName,
161165
Some(c) => c,
162166
None => return Err(FPGAArchParseError::MissingRequiredTag("<complexblocklist>".to_string())),
163167
};
168+
let direct_list = direct_list.unwrap_or_default();
164169

165170
Ok(FPGAArch {
166171
models,
@@ -169,6 +174,7 @@ fn parse_architecture(name: &OwnedName,
169174
device,
170175
switch_list,
171176
segment_list,
177+
direct_list,
172178
complex_block_list,
173179
})
174180
}

fpga_arch_parser/src/parse_complex_block_list.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ fn parse_pb_type(name: &OwnedName,
436436
// files.
437437
// Will skip for now without error so we can support
438438
// their arch files.
439+
// TODO: Print a warning.
439440
let _ = parser.skip();
440441
},
441442
_ => return Err(FPGAArchParseError::InvalidTag(name.to_string(), parser.position())),
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
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_direct(tag_name: &OwnedName,
13+
attributes: &[OwnedAttribute],
14+
parser: &mut EventReader<BufReader<File>>) -> Result<GlobalDirect, FPGAArchParseError> {
15+
assert!(tag_name.to_string() == "direct");
16+
17+
let mut name: Option<String> = None;
18+
let mut from_pin: Option<String> = None;
19+
let mut to_pin: Option<String> = None;
20+
let mut x_offset: Option<i32> = None;
21+
let mut y_offset: Option<i32> = None;
22+
let mut z_offset: Option<i32> = None;
23+
let mut switch_name: Option<String> = None;
24+
let mut from_side: Option<PinSide> = None;
25+
let mut to_side: Option<PinSide> = None;
26+
for a in attributes {
27+
match a.name.to_string().as_ref() {
28+
"name" => {
29+
name = match name {
30+
None => Some(a.value.clone()),
31+
Some(_) => return Err(FPGAArchParseError::DuplicateAttribute(a.to_string(), parser.position())),
32+
}
33+
},
34+
"from_pin" => {
35+
from_pin = match from_pin {
36+
None => Some(a.value.clone()),
37+
Some(_) => return Err(FPGAArchParseError::DuplicateAttribute(a.to_string(), parser.position())),
38+
}
39+
},
40+
"to_pin" => {
41+
to_pin = match to_pin {
42+
None => Some(a.value.clone()),
43+
Some(_) => return Err(FPGAArchParseError::DuplicateAttribute(a.to_string(), parser.position())),
44+
}
45+
},
46+
"x_offset" => {
47+
x_offset = match x_offset {
48+
None => match a.value.parse() {
49+
Ok(v) => Some(v),
50+
Err(e) => return Err(FPGAArchParseError::AttributeParseError(format!("{a}: {e}"), parser.position())),
51+
},
52+
Some(_) => return Err(FPGAArchParseError::DuplicateAttribute(a.to_string(), parser.position())),
53+
}
54+
},
55+
"y_offset" => {
56+
y_offset = match y_offset {
57+
None => match a.value.parse() {
58+
Ok(v) => Some(v),
59+
Err(e) => return Err(FPGAArchParseError::AttributeParseError(format!("{a}: {e}"), parser.position())),
60+
},
61+
Some(_) => return Err(FPGAArchParseError::DuplicateAttribute(a.to_string(), parser.position())),
62+
}
63+
},
64+
"z_offset" => {
65+
z_offset = match z_offset {
66+
None => match a.value.parse() {
67+
Ok(v) => Some(v),
68+
Err(e) => return Err(FPGAArchParseError::AttributeParseError(format!("{a}: {e}"), parser.position())),
69+
},
70+
Some(_) => return Err(FPGAArchParseError::DuplicateAttribute(a.to_string(), parser.position())),
71+
}
72+
},
73+
"switch_name" => {
74+
switch_name = match switch_name {
75+
None => Some(a.value.clone()),
76+
Some(_) => return Err(FPGAArchParseError::DuplicateAttribute(a.to_string(), parser.position())),
77+
}
78+
},
79+
"from_side" => {
80+
from_side = match from_side {
81+
None => match a.value.as_ref() {
82+
"left" => Some(PinSide::Left),
83+
"right" => Some(PinSide::Right),
84+
"top" => Some(PinSide::Top),
85+
"bottom" => Some(PinSide::Bottom),
86+
_ => return Err(FPGAArchParseError::AttributeParseError(format!("Unknown side: {}", a.value), parser.position())),
87+
},
88+
Some(_) => return Err(FPGAArchParseError::DuplicateAttribute(a.to_string(), parser.position())),
89+
}
90+
},
91+
"to_side" => {
92+
to_side = match to_side {
93+
None => match a.value.as_ref() {
94+
"left" => Some(PinSide::Left),
95+
"right" => Some(PinSide::Right),
96+
"top" => Some(PinSide::Top),
97+
"bottom" => Some(PinSide::Bottom),
98+
_ => return Err(FPGAArchParseError::AttributeParseError(format!("Unknown side: {}", a.value), parser.position())),
99+
},
100+
Some(_) => return Err(FPGAArchParseError::DuplicateAttribute(a.to_string(), parser.position())),
101+
}
102+
},
103+
_ => return Err(FPGAArchParseError::UnknownAttribute(a.to_string(), parser.position())),
104+
};
105+
}
106+
let name = match name {
107+
Some(p) => p,
108+
None => return Err(FPGAArchParseError::MissingRequiredAttribute("name".to_string(), parser.position())),
109+
};
110+
let from_pin = match from_pin {
111+
Some(p) => p,
112+
None => return Err(FPGAArchParseError::MissingRequiredAttribute("from_pin".to_string(), parser.position())),
113+
};
114+
let to_pin = match to_pin {
115+
Some(p) => p,
116+
None => return Err(FPGAArchParseError::MissingRequiredAttribute("to_pin".to_string(), parser.position())),
117+
};
118+
let x_offset = match x_offset {
119+
Some(p) => p,
120+
None => return Err(FPGAArchParseError::MissingRequiredAttribute("x_offset".to_string(), parser.position())),
121+
};
122+
let y_offset = match y_offset {
123+
Some(p) => p,
124+
None => return Err(FPGAArchParseError::MissingRequiredAttribute("y_offset".to_string(), parser.position())),
125+
};
126+
let z_offset = match z_offset {
127+
Some(p) => p,
128+
None => return Err(FPGAArchParseError::MissingRequiredAttribute("z_offset".to_string(), parser.position())),
129+
};
130+
131+
loop {
132+
match parser.next() {
133+
Ok(XmlEvent::StartElement { name, .. }) => {
134+
return Err(FPGAArchParseError::InvalidTag(name.to_string(), parser.position()));
135+
},
136+
Ok(XmlEvent::EndElement { name }) => {
137+
match name.to_string().as_ref() {
138+
"direct" => break,
139+
_ => return Err(FPGAArchParseError::UnexpectedEndTag(name.to_string(), parser.position())),
140+
}
141+
},
142+
Ok(XmlEvent::EndDocument) => {
143+
return Err(FPGAArchParseError::UnexpectedEndOfDocument(name.to_string()));
144+
},
145+
Err(e) => {
146+
return Err(FPGAArchParseError::XMLParseError(format!("{e:?}"), parser.position()));
147+
},
148+
_ => {},
149+
};
150+
}
151+
152+
Ok(GlobalDirect {
153+
name,
154+
from_pin,
155+
to_pin,
156+
x_offset,
157+
y_offset,
158+
z_offset,
159+
switch_name,
160+
from_side,
161+
to_side,
162+
})
163+
}
164+
165+
pub fn parse_direct_list(name: &OwnedName,
166+
attributes: &[OwnedAttribute],
167+
parser: &mut EventReader<BufReader<File>>) -> Result<Vec<GlobalDirect>, FPGAArchParseError> {
168+
assert!(name.to_string() == "directlist");
169+
if !attributes.is_empty() {
170+
return Err(FPGAArchParseError::UnknownAttribute(String::from("Expected to be empty"), parser.position()));
171+
}
172+
173+
let mut direct_list: Vec<GlobalDirect> = Vec::new();
174+
loop {
175+
match parser.next() {
176+
Ok(XmlEvent::StartElement { name, attributes, .. }) => {
177+
match name.to_string().as_str() {
178+
"direct" => {
179+
direct_list.push(parse_direct(&name, &attributes, parser)?);
180+
},
181+
_ => return Err(FPGAArchParseError::InvalidTag(name.to_string(), parser.position())),
182+
};
183+
},
184+
Ok(XmlEvent::EndElement { name }) => {
185+
match name.to_string().as_str() {
186+
"directlist" => break,
187+
_ => return Err(FPGAArchParseError::UnexpectedEndTag(name.to_string(), parser.position())),
188+
}
189+
},
190+
Ok(XmlEvent::EndDocument) => {
191+
return Err(FPGAArchParseError::UnexpectedEndOfDocument(name.to_string()));
192+
},
193+
Err(e) => {
194+
return Err(FPGAArchParseError::XMLParseError(format!("{e:?}"), parser.position()));
195+
},
196+
_ => {},
197+
}
198+
};
199+
200+
Ok(direct_list)
201+
}

fpga_arch_parser/tests/integration_test.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ fn test_k4_n4_90nm_parse() -> Result<(), FPGAArchParseError> {
108108
assert_eq!(res.segment_list[0].r_metal, 0.0);
109109
assert_eq!(res.segment_list[0].c_metal, 0.0);
110110

111+
// Check direct list
112+
assert_eq!(res.direct_list.len(), 0);
113+
111114
// Check complex block list.
112115
assert_eq!(res.complex_block_list.len(), 2);
113116
let clb0 = &res.complex_block_list[0];
@@ -233,6 +236,19 @@ fn test_vtr_flagship_parse() -> Result<(), FPGAArchParseError> {
233236
assert_eq!(io_subtile.name, "io");
234237
assert_eq!(io_subtile.capacity, 8);
235238

239+
// Check direct list.
240+
assert_eq!(res.direct_list.len(), 1);
241+
let gdirect = &res.direct_list[0];
242+
assert_eq!(gdirect.name, "adder_carry");
243+
assert_eq!(gdirect.from_pin, "clb.cout");
244+
assert_eq!(gdirect.to_pin, "clb.cin");
245+
assert_eq!(gdirect.x_offset, 0);
246+
assert_eq!(gdirect.y_offset, -1);
247+
assert_eq!(gdirect.z_offset, 0);
248+
assert!(gdirect.switch_name.is_none());
249+
assert!(gdirect.from_side.is_none());
250+
assert!(gdirect.to_side.is_none());
251+
236252
// TODO: Add stronger tests for the tiles.
237253
Ok(())
238254
}

0 commit comments

Comments
 (0)