343 lines
12 KiB
Rust
343 lines
12 KiB
Rust
use std::collections::HashSet;
|
|
use std::path::PathBuf;
|
|
use vhdl_lang::{kind_str, Token, VHDLParser, VHDLStandard};
|
|
use super::fast_hdlparam::*;
|
|
|
|
pub fn vhdl_parser(path: &str) -> FastHdlparam {
|
|
// The path of SystemVerilog source file
|
|
let path = PathBuf::from(path);
|
|
|
|
let mut hdlparam = FastHdlparam {
|
|
fast: Vec::new()
|
|
};
|
|
|
|
let parser = VHDLParser::new(VHDLStandard::VHDL2008);
|
|
let mut diagnostics = Vec::new();
|
|
let (_, design_file) = parser.parse_design_file(&path, &mut diagnostics).unwrap();
|
|
|
|
let mut all_tockens = Vec::new();
|
|
for (tokens, _) in design_file.design_units {
|
|
all_tockens.extend(tokens);
|
|
}
|
|
|
|
hdlparam.fast.extend(parse_tokens(all_tockens));
|
|
hdlparam
|
|
}
|
|
|
|
fn parse_tokens(tokens: Vec<Token>) -> Vec<Module> {
|
|
let mut modules = Vec::new();
|
|
let mut instance_type = HashSet::new();
|
|
|
|
let mut i = 0;
|
|
while i < tokens.len() {
|
|
let token = &tokens[i];
|
|
match kind_str(token.kind) {
|
|
"entity" => {
|
|
i += 1;
|
|
let module = Module {
|
|
name: get_value(&tokens[i]),
|
|
params: Vec::new(),
|
|
ports: Vec::new(),
|
|
instances: Vec::new(),
|
|
range: Range {
|
|
start: Position {
|
|
line: tokens[i].pos.range.start.line + 1,
|
|
character: tokens[i].pos.range.start.character + 1
|
|
},
|
|
end: Position {
|
|
line: tokens[i].pos.range.end.line + 1,
|
|
character: tokens[i].pos.range.end.character + 1
|
|
}
|
|
}
|
|
};
|
|
modules.push(module);
|
|
}
|
|
"component" => {
|
|
i += 1;
|
|
instance_type.insert(get_value(&tokens[i]));
|
|
while !(kind_str(tokens[i].kind) == "end" && kind_str(tokens[i+1].kind) == "component") {
|
|
i += 1;
|
|
}
|
|
i += 1;
|
|
}
|
|
":" => {
|
|
if instance_type.contains(&get_value(&tokens[i+1])) {
|
|
let instance = Instance {
|
|
name: get_value(&tokens[i-1]),
|
|
inst_type: get_value(&tokens[i+1]),
|
|
instports: None,
|
|
instparams: None,
|
|
range: Range {
|
|
start: Position {
|
|
line: tokens[i-1].pos.range.start.line,
|
|
character: tokens[i-1].pos.range.start.character
|
|
},
|
|
end: Position {
|
|
line: tokens[i+1].pos.range.start.line,
|
|
character: tokens[i+1].pos.range.start.character
|
|
}
|
|
}
|
|
};
|
|
modules.last_mut().unwrap().instances.push(instance);
|
|
}
|
|
}
|
|
"generic" => {
|
|
let is_map = kind_str(tokens[i+1].kind) == "map";
|
|
let (params, next_index) = parse_parameters(&tokens, i + 1, is_map);
|
|
if is_map {
|
|
let start = params.first().unwrap().range.start.clone();
|
|
let end = params.last().unwrap().range.start.clone();
|
|
modules.last_mut().unwrap().instances.last_mut().unwrap().instparams = Some(Range { start, end });
|
|
} else {
|
|
modules.last_mut().unwrap().params.extend(params);
|
|
}
|
|
i = next_index;
|
|
}
|
|
"port" => {
|
|
let is_map = kind_str(tokens[i+1].kind) == "map";
|
|
let (ports, next_index) = parse_port(&tokens, i + 1, is_map);
|
|
if is_map {
|
|
let start = ports.first().unwrap().range.start.clone();
|
|
let end = ports.last().unwrap().range.start.clone();
|
|
modules.last_mut().unwrap().instances.last_mut().unwrap().instports = Some(Range { start, end });
|
|
} else {
|
|
modules.last_mut().unwrap().ports.extend(ports);
|
|
}
|
|
i = next_index;
|
|
}
|
|
_ => {}
|
|
}
|
|
i += 1;
|
|
}
|
|
|
|
// println!("{:?}", modules);
|
|
modules
|
|
|
|
}
|
|
|
|
fn parse_port(tokens: &[Token], start: usize, is_map: bool) -> (Vec<Port>, usize) {
|
|
let mut ports = Vec::new();
|
|
let mut i = start;
|
|
let mut stack = Vec::new();
|
|
|
|
while i < tokens.len() {
|
|
let token = &tokens[i];
|
|
match kind_str(token.kind) {
|
|
"(" => {
|
|
stack.push(token);
|
|
}
|
|
")" => {
|
|
if stack.is_empty() {
|
|
break;
|
|
}
|
|
stack.pop();
|
|
}
|
|
";" => {
|
|
if stack.is_empty() {
|
|
break;
|
|
}
|
|
}
|
|
"{identifier}" => {
|
|
if is_map {
|
|
let start_pos = tokens[i].pos.range.start;
|
|
let end_pos = tokens[i+3].pos.range.end;
|
|
let port = Port {
|
|
name: get_value(&tokens[i]),
|
|
dir_type: "none".to_string(),
|
|
net_type: get_value(&tokens[i+2]),
|
|
width: "none".to_string(),
|
|
signed: "unsigned".to_string(),
|
|
range: Range {
|
|
start: Position {
|
|
line: start_pos.line + 1,
|
|
character: start_pos.character + 1
|
|
},
|
|
end: Position {
|
|
line: end_pos.line + 1,
|
|
character: end_pos.character + 1
|
|
}
|
|
},
|
|
};
|
|
i += 2;
|
|
ports.push(port);
|
|
} else {
|
|
let start_pos = tokens[i].pos.range.start;
|
|
let width ;
|
|
let end_idx;
|
|
if get_value(&tokens[i+3]).contains("VECTOR") || get_value(&tokens[i+3]).contains("vector") {
|
|
let (width_str, index) = parse_width(&tokens, i+4);
|
|
width = "[".to_string() + &width_str + "]";
|
|
end_idx = index;
|
|
} else {
|
|
width = "1".to_string();
|
|
end_idx = i+3;
|
|
}
|
|
let end_pos = tokens[end_idx].pos.range.end;
|
|
let direction = if kind_str(tokens[i+2].kind) == "buffer" { "out" } else { kind_str(tokens[i+2].kind) };
|
|
let port = Port {
|
|
name: get_value(&tokens[i]),
|
|
dir_type: direction.to_string(),
|
|
net_type: get_value(&tokens[i+3]),
|
|
width,
|
|
signed: "unsigned".to_string(),
|
|
range: Range {
|
|
start: Position {
|
|
line: start_pos.line + 1,
|
|
character: start_pos.character + 1
|
|
},
|
|
end: Position {
|
|
line: end_pos.line + 1,
|
|
character: end_pos.character + 1
|
|
}
|
|
},
|
|
};
|
|
i = end_idx;
|
|
ports.push(port);
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
i += 1;
|
|
}
|
|
|
|
(ports, i)
|
|
}
|
|
|
|
fn parse_width(tokens: &[Token], start: usize) -> (String, usize) {
|
|
let mut width = String::new();
|
|
let mut i = start;
|
|
let mut stack = Vec::new();
|
|
|
|
while i < tokens.len() {
|
|
match kind_str(tokens[i].kind) {
|
|
"(" => {
|
|
stack.push(&tokens[i]);
|
|
}
|
|
")" => {
|
|
if stack.is_empty() {
|
|
break;
|
|
}
|
|
stack.pop();
|
|
}
|
|
";" => {
|
|
if stack.is_empty() {
|
|
break;
|
|
}
|
|
}
|
|
_ => {
|
|
if stack.len() >= 1 {
|
|
if get_value(&tokens[i]) == "None" {
|
|
if kind_str(tokens[i].kind) == "downto" || kind_str(tokens[i].kind) == "to" {
|
|
width = width + ":";
|
|
} else {
|
|
width = width + kind_str(tokens[i].kind);
|
|
}
|
|
} else {
|
|
width = width + &get_value(&tokens[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
i += 1;
|
|
}
|
|
(width, i)
|
|
}
|
|
|
|
fn parse_parameters(tokens: &[Token], start: usize, is_map: bool) -> (Vec<Parameter>, usize) {
|
|
let mut params = Vec::new();
|
|
let mut i = start;
|
|
let mut stack = Vec::new();
|
|
|
|
while i < tokens.len() {
|
|
let token = &tokens[i];
|
|
match kind_str(token.kind) {
|
|
"(" => {
|
|
stack.push(token);
|
|
}
|
|
")" => {
|
|
if stack.is_empty() {
|
|
break;
|
|
}
|
|
stack.pop();
|
|
}
|
|
";" => {
|
|
if stack.is_empty() {
|
|
break;
|
|
}
|
|
}
|
|
"{identifier}" => {
|
|
if is_map {
|
|
let start_pos = tokens[i].pos.range.start;
|
|
let end_pos = tokens[i+2].pos.range.end;
|
|
let param = Parameter {
|
|
name: get_value(&tokens[i]),
|
|
net_type: get_value(&tokens[i+2]),
|
|
init: get_value(&tokens[i+2]),
|
|
range: Range {
|
|
start: Position {
|
|
line: start_pos.line + 1,
|
|
character: start_pos.character + 1
|
|
},
|
|
end: Position {
|
|
line: end_pos.line + 1,
|
|
character: end_pos.character + 1
|
|
}
|
|
},
|
|
};
|
|
i += 2;
|
|
params.push(param);
|
|
} else {
|
|
let start_pos = tokens[i].pos.range.start;
|
|
let end_pos = tokens[i+4].pos.range.end;
|
|
let param = Parameter {
|
|
name: get_value(&tokens[i]),
|
|
net_type: get_value(&tokens[i+2]),
|
|
init: get_value(&tokens[i+4]),
|
|
range: Range {
|
|
start: Position {
|
|
line: start_pos.line + 1,
|
|
character: start_pos.character + 1
|
|
},
|
|
end: Position {
|
|
line: end_pos.line + 1,
|
|
character: end_pos.character + 1
|
|
}
|
|
},
|
|
};
|
|
i += 4;
|
|
params.push(param);
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
i += 1;
|
|
}
|
|
|
|
(params, i)
|
|
}
|
|
|
|
fn get_value(token: &Token) -> String {
|
|
match &token.value {
|
|
vhdl_lang::Value::Identifier(symbol) => {
|
|
return symbol.name_utf8();
|
|
}
|
|
vhdl_lang::Value::String(latin1_string) => {
|
|
return latin1_string.to_string();
|
|
}
|
|
vhdl_lang::Value::BitString(latin1_string, _) => {
|
|
return latin1_string.to_string().replace("\\", "");
|
|
}
|
|
vhdl_lang::Value::AbstractLiteral(latin1_string, _) => {
|
|
return latin1_string.to_string();
|
|
}
|
|
vhdl_lang::Value::Character(character) => {
|
|
return character.to_string();
|
|
}
|
|
vhdl_lang::Value::Text(latin1_string) => {
|
|
return latin1_string.to_string();
|
|
}
|
|
vhdl_lang::Value::None => {
|
|
return "None".to_string();
|
|
}
|
|
}
|
|
} |