增加对于 xilinx IP 的 entity 内部 port 的解析
This commit is contained in:
parent
b14f8bd17f
commit
f055b2bbc3
@ -1,5 +1,6 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use log::info;
|
||||||
use vhdl_lang::ast::DesignFile;
|
use vhdl_lang::ast::DesignFile;
|
||||||
use vhdl_lang::{kind_str, Token, VHDLParser, VHDLStandard};
|
use vhdl_lang::{kind_str, Token, VHDLParser, VHDLStandard};
|
||||||
|
|
||||||
@ -67,7 +68,6 @@ pub fn make_fast_from_design_file(design_file: &DesignFile) -> Option<FastHdlpar
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
fn parse_tokens(tokens: Vec<Token>) -> Vec<Module> {
|
fn parse_tokens(tokens: Vec<Token>) -> Vec<Module> {
|
||||||
let mut modules = Vec::new();
|
let mut modules = Vec::new();
|
||||||
let mut last_module_name = String::new();
|
let mut last_module_name = String::new();
|
||||||
@ -81,24 +81,31 @@ fn parse_tokens(tokens: Vec<Token>) -> Vec<Module> {
|
|||||||
let start_pos = tokens[i].pos.range.start;
|
let start_pos = tokens[i].pos.range.start;
|
||||||
i += 1;
|
i += 1;
|
||||||
let entity_name = get_value(&tokens[i]);
|
let entity_name = get_value(&tokens[i]);
|
||||||
// println!("entity name {:?}", entity_name);
|
|
||||||
if (i >= 2 as usize) && (kind_str(tokens[i - 2].kind) != "use") || (i < 2) {
|
if (i >= 2 as usize) && (kind_str(tokens[i - 2].kind) != "use") || (i < 2) {
|
||||||
|
// 遍历整个 entity 内部的 token,找到结束的 token 和代表 port 的 token
|
||||||
let mut end = i;
|
let mut end = i;
|
||||||
|
let mut port_begin: usize = 0;
|
||||||
while (
|
while (
|
||||||
end + 1 < tokens.len()) &&
|
end + 1 < tokens.len()) &&
|
||||||
!(kind_str(tokens[end].kind) == "end" &&
|
!(kind_str(tokens[end].kind) == "end" &&
|
||||||
(kind_str(tokens[end+1].kind) == "entity" || get_value(&tokens[end+1]) == entity_name)) {
|
(kind_str(tokens[end + 1].kind) == "entity" || get_value(&tokens[end + 1]) == entity_name)
|
||||||
|
) {
|
||||||
|
if kind_str(tokens[end].kind) == "port" {
|
||||||
|
port_begin = end;
|
||||||
|
}
|
||||||
end += 1;
|
end += 1;
|
||||||
}
|
}
|
||||||
let end_pos = if end+1 < tokens.len() && get_value(&tokens[end+1]) == entity_name {
|
|
||||||
i = end + 1;
|
let (next_i, end_pos) = if end + 1 < tokens.len() && get_value(&tokens[end + 1]) == entity_name {
|
||||||
tokens[end+2].pos.range.end
|
(end + 1, tokens[end + 2].pos.range.end)
|
||||||
} else if end + 3 < tokens.len() {
|
} else if end + 3 < tokens.len() {
|
||||||
i = end + 2;
|
(end + 2, tokens[end + 3].pos.range.end)
|
||||||
tokens[end+3].pos.range.end
|
|
||||||
} else {
|
} else {
|
||||||
tokens[end].pos.range.end
|
(i, tokens[end].pos.range.end)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 创建一个空的 module 并标记上 last_module_name
|
||||||
let module = Module {
|
let module = Module {
|
||||||
name: entity_name.to_string(),
|
name: entity_name.to_string(),
|
||||||
params: Vec::new(),
|
params: Vec::new(),
|
||||||
@ -117,6 +124,14 @@ fn parse_tokens(tokens: Vec<Token>) -> Vec<Module> {
|
|||||||
};
|
};
|
||||||
last_module_name = entity_name.to_string();
|
last_module_name = entity_name.to_string();
|
||||||
modules.push(module);
|
modules.push(module);
|
||||||
|
|
||||||
|
// 如果内部含有 port,则不能直接跳过,否则直接跳过
|
||||||
|
if port_begin > 0 {
|
||||||
|
i = port_begin;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
i = next_i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"architecture" => {
|
"architecture" => {
|
||||||
@ -289,7 +304,7 @@ fn parse_tokens(tokens: Vec<Token>) -> Vec<Module> {
|
|||||||
let start = params.first().unwrap().range.start.clone();
|
let start = params.first().unwrap().range.start.clone();
|
||||||
let end = params.last().unwrap().range.start.clone();
|
let end = params.last().unwrap().range.start.clone();
|
||||||
if let Some(module) = modules.iter_mut().find(|module| module.name == last_module_name) {
|
if let Some(module) = modules.iter_mut().find(|module| module.name == last_module_name) {
|
||||||
module.instances.last_mut().unwrap().instparams = Some(Range { start, end });;
|
module.instances.last_mut().unwrap().instparams = Some(Range { start, end });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let Some(module) = modules.iter_mut().find(|module| module.name == last_module_name) {
|
if let Some(module) = modules.iter_mut().find(|module| module.name == last_module_name) {
|
||||||
|
@ -322,7 +322,7 @@ pub fn hover_module_declaration(
|
|||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
language_id: &str
|
language_id: &str
|
||||||
) -> Option<Hover> {
|
) -> Option<Hover> {
|
||||||
// info!("token: {:?}, module info: {:?}", token_name, module_info);
|
// info!("hover_module_declaration token: {:?}", token_name);
|
||||||
|
|
||||||
// let test = server.srcs.hdl_param.module_name_to_path.read().unwrap();
|
// let test = server.srcs.hdl_param.module_name_to_path.read().unwrap();
|
||||||
// info!("module name to path: {:#?}", test);
|
// info!("module name to path: {:#?}", test);
|
||||||
@ -429,8 +429,61 @@ fn hover_ip_module_declaration(
|
|||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
def_path: &str
|
def_path: &str
|
||||||
) -> Option<Hover> {
|
) -> Option<Hover> {
|
||||||
|
let def_path_buf = PathBuf::from_str(def_path).unwrap();
|
||||||
|
|
||||||
|
if def_path_buf.exists() {
|
||||||
|
// TODO: 当前工具链只支持 Xilinx 下的工具链,所以此处的代码是 vhdl 的代码
|
||||||
|
let path_uri = Url::from_file_path(def_path.to_string()).unwrap().to_string();
|
||||||
|
let def_row = module.range.start.line;
|
||||||
|
let def_col = module.range.start.character;
|
||||||
|
let define_info = format!("Go to [Definition]({path_uri}#L{def_row}:{def_col})");
|
||||||
|
|
||||||
|
let port_num = module.ports.len();
|
||||||
|
let param_num = module.params.len();
|
||||||
|
let instance_num = module.instances.len();
|
||||||
|
|
||||||
|
let port_desc = format!("`port` {port_num}, `generic` {param_num}, `instantiation` {instance_num}");
|
||||||
|
|
||||||
|
// 统计 dir
|
||||||
|
let mut input_count = 0 as u32;
|
||||||
|
let mut output_count = 0 as u32;
|
||||||
|
let mut inout_count = 0 as u32;
|
||||||
|
|
||||||
|
for port in &module.ports {
|
||||||
|
match port.dir_type.as_str() {
|
||||||
|
"input" => input_count += 1,
|
||||||
|
"output" => output_count += 1,
|
||||||
|
"inout" => inout_count += 1,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let io_desc = format!("`input` {input_count}, `output` {output_count}, `inout` {inout_count}");
|
||||||
|
|
||||||
|
let mut markdowns = Vec::<MarkedString>::new();
|
||||||
|
markdowns.push(MarkedString::String(port_desc));
|
||||||
|
markdowns.push(MarkedString::String(io_desc));
|
||||||
|
markdowns.push(MarkedString::String(define_info));
|
||||||
|
markdowns.push(MarkedString::String("---".to_string()));
|
||||||
|
|
||||||
|
let language_id = get_language_id_by_path_str(def_path);
|
||||||
|
let module_profile = make_module_profile_code(&module);
|
||||||
|
let profile_markdown = LanguageString {
|
||||||
|
language: language_id.to_string(),
|
||||||
|
value: module_profile
|
||||||
|
};
|
||||||
|
markdowns.push(MarkedString::LanguageString(profile_markdown));
|
||||||
|
|
||||||
|
let hover = Hover {
|
||||||
|
contents: HoverContents::Array(markdowns),
|
||||||
|
range: None
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(hover)
|
||||||
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn hover_primitives_module_declaration(
|
fn hover_primitives_module_declaration(
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
@ -227,10 +227,13 @@ fn do_vhdl_fast(
|
|||||||
// TODO: 支持对于 synth 下的 vhdl 文件的解析,从而提供更加丰富的 IP 支持
|
// TODO: 支持对于 synth 下的 vhdl 文件的解析,从而提供更加丰富的 IP 支持
|
||||||
if file_type == "ip" {
|
if file_type == "ip" {
|
||||||
match tool_chain {
|
match tool_chain {
|
||||||
|
// 此时的 pathbuf 类似 {ip_name}/synth/{ip_name}.vhd
|
||||||
"xilinx" => {
|
"xilinx" => {
|
||||||
|
// 如果 ip 描述文件存在,则解析它,否则,创建空的写入
|
||||||
|
// IP 描述文件一般都不会很大,所以不需要缓存
|
||||||
|
if !pathbuf.exists() {
|
||||||
let ip_name = pathbuf.file_name().unwrap().to_str().unwrap();
|
let ip_name = pathbuf.file_name().unwrap().to_str().unwrap();
|
||||||
let ip_name = ip_name.strip_suffix(".vhd").unwrap();
|
let ip_name = ip_name.strip_suffix(".vhd").unwrap();
|
||||||
info!("get ip_name: {}", ip_name);
|
|
||||||
let fake_content = vec![
|
let fake_content = vec![
|
||||||
core::hdlparam::Module {
|
core::hdlparam::Module {
|
||||||
name: ip_name.to_string(),
|
name: ip_name.to_string(),
|
||||||
@ -252,13 +255,18 @@ fn do_vhdl_fast(
|
|||||||
};
|
};
|
||||||
hdl_param.update_fast(path.to_string(), ip_fast.clone());
|
hdl_param.update_fast(path.to_string(), ip_fast.clone());
|
||||||
return Ok(ip_fast);
|
return Ok(ip_fast);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 没有特殊情况,则正常解析并写入
|
||||||
if let Some(design_file) = vhdl_parse(&pathbuf) {
|
if let Some(design_file) = vhdl_parse(&pathbuf) {
|
||||||
if let Some(mut fast) = make_fast_from_design_file(&design_file) {
|
if let Some(mut fast) = make_fast_from_design_file(&design_file) {
|
||||||
|
if path.contains("ip") {
|
||||||
|
info!("vhdl fast: {:?}", fast);
|
||||||
|
}
|
||||||
fast.file_type = file_type.to_string();
|
fast.file_type = file_type.to_string();
|
||||||
hdl_param.update_fast(path.to_string(), fast.clone());
|
hdl_param.update_fast(path.to_string(), fast.clone());
|
||||||
return Ok(fast);
|
return Ok(fast);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user