增加对于 xilinx IP 的 entity 内部 port 的解析

This commit is contained in:
锦恢 2024-11-11 02:06:41 +08:00
parent b14f8bd17f
commit f055b2bbc3
4 changed files with 115 additions and 39 deletions

View File

@ -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) {

View File

@ -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,7 +429,60 @@ 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(

View File

@ -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);