diff --git a/public/test.vcd.pkl b/public/test.vcd.pkl new file mode 100644 index 0000000..3abecce --- /dev/null +++ b/public/test.vcd.pkl @@ -0,0 +1,16 @@ +{ + "waves": [ + { + "name": "friscv_rv32i_testbench.dut.mem_router.mst_en", + "option": {} + }, + { + "name": "friscv_rv32i_testbench.dut.mem_router.mst_addr", + "option": {} + }, + { + "name": "friscv_rv32i_testbench.dut.mem_router.data_mem_addr", + "option": {} + } + ] +} \ No newline at end of file diff --git a/src/App.vue b/src/App.vue index 2157371..882e823 100644 --- a/src/App.vue +++ b/src/App.vue @@ -28,7 +28,7 @@ import ToolBar from '@/components/toolbar'; import Sidebar from '@/components/sidebar'; import RightNav from '@/components/right-nav.vue'; import Pivot from '@/components/pivot'; -import { recoverFromInputFile } from './hook/recover'; +import { recoverFromInputFile, recoverSession } from './hook/recover'; const { t } = useI18n(); @@ -127,9 +127,6 @@ onMounted(async () => { // 这一步时,已经加载完成 - // 根据 recoverConfig 完成现场回复 - - // 初始化右侧的模型 treeview 面板 // 默认第一个模块被选中 if (VcdInfo.topModules.length > 0) { @@ -143,6 +140,10 @@ onMounted(async () => { } loading.close(); worker.terminate(); + + // 根据 recoverConfig 完成现场回复 + recoverSession(VcdInfo.topModules); + console.log(VcdInfo.topModules); }); }); diff --git a/src/hook/global.js b/src/hook/global.js index 91d4088..ecbc63c 100644 --- a/src/hook/global.js +++ b/src/hook/global.js @@ -111,10 +111,12 @@ export const globalLookup = reactive({ if (this.currentModule === undefined && module) { this.currentModule = module; } - // 创造 parent + // 创造 parent,当然,这一步也可能在 recoverSession 中被实现了 if (module.body && module.body instanceof Array) { for (const childModule of module.body) { - childModule.parent = module; + if (childModule.parent === undefined) { + childModule.parent = module; + } } } }, diff --git a/src/hook/recover.js b/src/hook/recover.js index f6502e1..266d38c 100644 --- a/src/hook/recover.js +++ b/src/hook/recover.js @@ -1,10 +1,11 @@ import { controller } from "@/components/treeview/signals"; import { globalLookup } from "./global"; import { WaveContainerView } from "./wave-container-view"; +import { isScope, isVariable } from "./utils"; export const recoverConfig = { /** - * @type {Map} + * @type {Map} 其中的 string 是形如 `cpu.alu.add1` 这样的字符串 */ waves: new Map(), }; @@ -44,14 +45,63 @@ export async function recoverFromInputFile(inputFile) { } } +class PrefixNode { + constructor() { + this.children = new Map(); + this.payload = undefined; + } +} + + + /** * @description 恢复现场的函数,主要恢复两个变量 currentWiresRenderView 和 currentSignalRenderOptions * @param {TopModWireItem[]} topModules */ export function recoverSession(topModules) { - // 匹配前缀树 - + const waves = recoverConfig.waves; + if (waves.size === 0) { + return; + } + + // 利用前缀树 记忆化搜索 + for (const [name, option] of waves.entries()) { + const deps = name.split('.'); + let layer = 0; + let nodes = topModules; + let result = undefined; + let lastNode = undefined; + + while (layer < deps.length) { + // 从当前 nodes 中匹配 className + const targetName = deps[layer]; + let targetNode = nodes.filter(n => n.name == targetName)[0]; + if (targetNode === undefined) { + break; + } + + if (isScope(targetNode)) { + nodes = targetNode.body; + } else if (isVariable(targetNode)) { + result = targetNode; + if (result.parent === undefined) { + result.parent = lastNode; + } + } else { + break; + } + lastNode = targetNode; + layer ++; + } + + if (result !== undefined) { + // 找到了 + + WaveContainerView.add(result); + globalLookup.currentSignalRenderOptions.set(result.link, option); + controller.lastSignal = result; + } + } - controller.lastSignal = undefined; globalLookup.render(); } \ No newline at end of file