更新架构,进行依赖注入
This commit is contained in:
parent
eabdba2602
commit
0aa38f5133
@ -23,7 +23,8 @@
|
||||
const skinBinary = await r2.arrayBuffer();
|
||||
return [ netJson, skinBinary ];
|
||||
}
|
||||
window.avoidWasm = 'avoid.wasm';
|
||||
window.moduleName = 'half_adder';
|
||||
// window.avoidWasm = 'avoid.wasm';
|
||||
</script>
|
||||
</head>
|
||||
|
||||
|
@ -37,8 +37,8 @@ body::-webkit-scrollbar {
|
||||
|
||||
* hr {
|
||||
border: none;
|
||||
background-color: var(--vscode-focusBorder);
|
||||
height: 2px;
|
||||
background-color: var(--main-color);
|
||||
height: 1.5px;
|
||||
width: 95%;
|
||||
}
|
||||
/*
|
||||
|
@ -36,6 +36,8 @@ onMounted(async () => {
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
});
|
||||
|
||||
globalLookup.topModuleName = window.moduleName;
|
||||
|
||||
// 初始化载入 netlist 的 json 文件
|
||||
const [ netJson, skinBinary ] = await window.readNetFile();
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="vcd-right-nav">
|
||||
<div class="netlist-right-nav">
|
||||
|
||||
<div class="vcd-function-panel">
|
||||
<div class="netlist-function-panel">
|
||||
<TreeView
|
||||
v-show="controlPanel.currentIndex === 0"></TreeView>
|
||||
<Setting
|
||||
@ -10,17 +10,17 @@
|
||||
v-show="controlPanel.currentIndex === 2"></About>
|
||||
</div>
|
||||
|
||||
<div class="vcd-function-option">
|
||||
<div class="vcd-control-panel-wrapper">
|
||||
<div class="vcd-control-panel-icon digital-ide-icon" />
|
||||
<div class="netlist-function-option">
|
||||
<div class="netlist-control-panel-wrapper">
|
||||
<div class="netlist-control-panel-icon digital-ide-icon" />
|
||||
</div>
|
||||
<hr>
|
||||
<div class="vcd-control-panel-wrapper"
|
||||
<div class="netlist-control-panel-wrapper"
|
||||
v-for="(section, index) of controlPanel.sections" :key="index"
|
||||
@click="controlPanel.click(index)"
|
||||
>
|
||||
<div :class="controlPanel.currentIndex === index ? 'vcd-control-panel-active': ''"><span
|
||||
class="vcd-control-panel-icon"
|
||||
<div :class="controlPanel.currentIndex === index ? 'netlist-control-panel-active': ''"><span
|
||||
class="netlist-control-panel-icon"
|
||||
:class="section.iconClass"
|
||||
></span></div>
|
||||
</div>
|
||||
@ -51,7 +51,7 @@ emitter.on('right-nav', index => {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.vcd-right-nav {
|
||||
.netlist-right-nav {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
@ -59,21 +59,21 @@ emitter.on('right-nav', index => {
|
||||
z-index: 230;
|
||||
}
|
||||
|
||||
.vcd-function-panel {
|
||||
.netlist-function-panel {
|
||||
display: flex;
|
||||
background-color: var(--sidebar);
|
||||
height: 100vh;
|
||||
box-shadow: var(--gray-box-shadow-1);
|
||||
}
|
||||
|
||||
.vcd-function-option {
|
||||
.netlist-function-option {
|
||||
width: fit-content;
|
||||
height: 100vh;
|
||||
background-color: var(--sidebar);
|
||||
box-shadow: var(--gray-box-shadow-1);
|
||||
}
|
||||
|
||||
.vcd-control-panel-wrapper {
|
||||
.netlist-control-panel-wrapper {
|
||||
width: var(--right-nav-width);
|
||||
height: var(--right-nav-width);
|
||||
display: flex;
|
||||
@ -84,17 +84,17 @@ emitter.on('right-nav', index => {
|
||||
color: var(--vscode-foreground);
|
||||
}
|
||||
|
||||
.vcd-control-panel-wrapper:hover {
|
||||
.netlist-control-panel-wrapper:hover {
|
||||
color: var(--vscode-icon-foreground);
|
||||
}
|
||||
|
||||
.vcd-control-panel-icon {
|
||||
.netlist-control-panel-icon {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.vcd-control-panel-active {
|
||||
.netlist-control-panel-active {
|
||||
color: var(--main-color);
|
||||
}
|
||||
</style>
|
@ -1,20 +1,69 @@
|
||||
<template>
|
||||
<div class="netlist-tree-view">
|
||||
<div class="search-nothing">
|
||||
<span class="iconfont icon-empty"></span>
|
||||
<span>Mirror the unknown</span>
|
||||
<div class="netlist-module-info">
|
||||
<div class="netlist-signal-title">{{ t('module') }}</div>
|
||||
<hr>
|
||||
<el-scrollbar height="86vh" style="padding-right: 7px;">
|
||||
<modules
|
||||
v-for="mod of treeviewData.modules"
|
||||
:key="mod.name"
|
||||
:module="mod"
|
||||
></modules>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineComponent } from 'vue';
|
||||
import modules from './modules.vue';
|
||||
import { treeviewData } from './tree';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
defineComponent({ name: 'tree-view' });
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.netlist-module-info {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.netlist-signal-title {
|
||||
margin-left: 5px;
|
||||
height: 2.5vh;
|
||||
}
|
||||
|
||||
.icon-wave-square {
|
||||
color: var(--signal-default-color);
|
||||
}
|
||||
|
||||
.icon-brackets {
|
||||
color: #75BEDF;
|
||||
}
|
||||
|
||||
.icon-register {
|
||||
color: #885dff;
|
||||
}
|
||||
|
||||
.icon-integer {
|
||||
color: #C76B3C;
|
||||
}
|
||||
|
||||
.icon-string {
|
||||
color: #8CC265;
|
||||
}
|
||||
|
||||
.icon-real {
|
||||
color: #5fb4d8;
|
||||
}
|
||||
|
||||
.icon-task {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.search-nothing {
|
||||
height: 40vh;
|
||||
width: 100%;
|
||||
|
166
src/components/treeview/modules.vue
Normal file
166
src/components/treeview/modules.vue
Normal file
@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<div class="module">
|
||||
<div @click="clickItem()" class="netlist-treeview-item">
|
||||
<span class="module-tag-status" @click.stop="expandManage.click">
|
||||
<div :class="expandManage.expandTagClass"></div>
|
||||
</span>
|
||||
<span :class="`iconfont ${makeIconClass(module)}`"></span>
|
||||
 {{ module.name }}
|
||||
</div>
|
||||
|
||||
<!-- 渲染这个 module scope 有的组件 -->
|
||||
<div v-if="ports.length > 0 || cells.length > 0" class="netlist-subtree-wrapper">
|
||||
<div style="width: 20px;"></div>
|
||||
<div style="width: 100%;">
|
||||
<!-- ports -->
|
||||
<div v-for="port in ports" :key="port.name" class="netlist-treeview-item">
|
||||
<span class="module-tag-status">
|
||||
</span>
|
||||
<span class="iconfont icon-wave-square"></span>
|
||||
 {{ port.name }}
|
||||
</div>
|
||||
|
||||
<!-- 例化模块 -->
|
||||
<modules
|
||||
v-for="(cell, index) in cells"
|
||||
:module="cell.view"
|
||||
:key="index"
|
||||
></modules>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/* eslint-disable */
|
||||
import { ModuleView } from '@/hook/render/yosys';
|
||||
import { defineComponent, reactive } from 'vue';
|
||||
|
||||
defineComponent({ name: 'modules' });
|
||||
|
||||
const props = defineProps({
|
||||
module: {
|
||||
type: ModuleView,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const module = props.module;
|
||||
|
||||
// 当前 scope 的例化模块下的
|
||||
const ports = [];
|
||||
const cells = [];
|
||||
|
||||
// 初始化渲染的子视图 ports & modules
|
||||
for (const portName of module.nameToPort.keys()) {
|
||||
ports.push({
|
||||
name: portName
|
||||
});
|
||||
}
|
||||
|
||||
for (const cellName of module.nameToCell.keys()) {
|
||||
const cell = module.nameToCell.get(cellName);
|
||||
if (cell.view === module) {
|
||||
// 防止递归
|
||||
continue;
|
||||
}
|
||||
if (cell.isInstantiation) {
|
||||
cells.push({
|
||||
name: cellName,
|
||||
view: cell.belongModuleView
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function clickItem() {
|
||||
|
||||
}
|
||||
|
||||
function getExpandStatus() {
|
||||
if (ports.length === 0 && cells.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const expandManage = reactive({
|
||||
expanded: getExpandStatus(),
|
||||
expandTagClass: ports.length === 0 && cells.length === 0 ? '' : 'collapse-tag',
|
||||
click() {
|
||||
this.expanded = !this.expanded;
|
||||
if (this.expandTagClass) {
|
||||
this.expandTagClass = this.expanded ? 'expand-tag' : 'collapse-tag';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function makeIconClass() {
|
||||
return 'icon-memory-chip';
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.icon-memory-chip {
|
||||
color: #FF7043;
|
||||
}
|
||||
|
||||
.module {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.netlist-subtree-wrapper {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.netlist-treeview-item {
|
||||
color: var(--vscode-foreground);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.netlist-treeview-item::selection {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.netlist-treeview-item:hover {
|
||||
background-color: var(--sidebar-item-selected);
|
||||
border-radius: .3em;
|
||||
}
|
||||
|
||||
.netlist-treeview-selected {
|
||||
color: #ddd;
|
||||
background-color: var(--button-active) !important;
|
||||
border-radius: .3em;
|
||||
}
|
||||
|
||||
.module-tag-status {
|
||||
width: 23px;
|
||||
height: 23px;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.expand-tag {
|
||||
height: 5px;
|
||||
width: 5px;
|
||||
border-top: solid 1.7px var(--vscode-foreground);
|
||||
border-left: solid 1.7px var(--vscode-foreground);
|
||||
transform: rotate(225deg);
|
||||
}
|
||||
|
||||
.collapse-tag {
|
||||
height: 5px;
|
||||
width: 5px;
|
||||
border-top: solid 1.7px var(--vscode-foreground);
|
||||
border-left: solid 1.7px var(--vscode-foreground);
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
</style>
|
13
src/components/treeview/tree.js
Normal file
13
src/components/treeview/tree.js
Normal file
@ -0,0 +1,13 @@
|
||||
import { ModuleView } from '@/hook/render/yosys';
|
||||
import { reactive } from 'vue';
|
||||
|
||||
export const treeviewData = reactive({
|
||||
/**
|
||||
* @description 当前的顶层模块数量,内部数据结构是递归的
|
||||
* 大部分情况下,它应该是只有一个元素
|
||||
*
|
||||
* @type {ModuleView[]}
|
||||
*/
|
||||
modules: []
|
||||
});
|
||||
|
@ -8,7 +8,7 @@ export function setDefaultCss() {
|
||||
document.body.style.setProperty('--el-color-primary-light-3', 'var(--main-color)');
|
||||
document.body.style.setProperty('--el-text-color-secondary', 'var(--foreground)');
|
||||
document.body.style.setProperty('--el-text-color-regular', 'var(--foreground)');
|
||||
document.body.style.setProperty('--el-border-color', 'var(--vscode-focusBorder)');
|
||||
document.body.style.setProperty('--el-border-color', 'var(--main-color)');
|
||||
document.body.style.setProperty('--el-fill-color-blank', 'var(--sidebar)');
|
||||
document.body.style.setProperty('--el-fill-color-light', 'var(--vscode-button-hoverBackground)');
|
||||
document.body.style.setProperty('--el-switch-on-color', 'var(--main-color)');
|
||||
@ -16,14 +16,15 @@ export function setDefaultCss() {
|
||||
document.body.style.setProperty('--el-border-color-light', 'var(--sidebar)');
|
||||
document.body.style.setProperty('--el-border-color-lighter', 'var(--sidebar)');
|
||||
document.body.style.setProperty('--el-bg-color-overlay', 'var(--sidebar)');
|
||||
document.body.style.setProperty('--el-color-info-light-9', 'var(--vscode-focusBorder)');
|
||||
document.body.style.setProperty('--el-color-info-light-9', 'var(--main-color)');
|
||||
document.body.style.setProperty('--el-color-info', 'var(--foreground)');
|
||||
document.body.style.setProperty('--el-color-info-light-8', 'var(--vscode-focusBorder)');
|
||||
document.body.style.setProperty('--el-color-info-light-8', 'var(--main-color)');
|
||||
document.body.style.setProperty('--el-fill-color-light', 'var(--sidebar-item-selected)');
|
||||
|
||||
// document.body.style.setProperty('--el-color-white', 'var(--background)');
|
||||
|
||||
// 设置全局宏
|
||||
document.body.style.setProperty('--vcd-render-padding', '30px');
|
||||
document.body.style.setProperty('--netlist-render-padding', '30px');
|
||||
document.body.style.setProperty('--sidebar-width', '330px');
|
||||
document.body.style.setProperty('--toolbar-height', '60px');
|
||||
|
||||
|
@ -25,7 +25,18 @@ export const globalLookup = {
|
||||
/**
|
||||
* @type {Avoid}
|
||||
*/
|
||||
Avoid: undefined
|
||||
Avoid: undefined,
|
||||
|
||||
/**
|
||||
* @description 当前仿真结果的顶层模块的名字
|
||||
* @type {string}
|
||||
*/
|
||||
topModuleName: '',
|
||||
|
||||
/**
|
||||
* @description 当前选择的实体,可以是 wire,也可以是 cell
|
||||
*/
|
||||
currentSelectEntity: undefined
|
||||
};
|
||||
|
||||
function loadSetting() {
|
||||
|
@ -5,6 +5,8 @@
|
||||
* @property {Record<string, YosysModel>} [models] 模型定义的映射(仅在使用 `-aig` 选项时存在)。
|
||||
*/
|
||||
|
||||
import { Module } from "./render/layout";
|
||||
|
||||
/**
|
||||
* @typedef {number | string} WireId 信号ID
|
||||
*/
|
||||
|
@ -9,7 +9,8 @@ import { InstantiationRender } from './instantiation';
|
||||
import { CellRender } from './cell';
|
||||
import { ConnectionRender } from './connection';
|
||||
import { WireRender } from './wire';
|
||||
import { pinkLog } from '../utils';
|
||||
import { pinkLog, redLog } from '../utils';
|
||||
import { treeviewData } from '@/components/treeview/tree';
|
||||
|
||||
export class NetlistRender {
|
||||
/**
|
||||
@ -82,15 +83,20 @@ export class NetlistRender {
|
||||
* @type {YosysRawNet}
|
||||
*/
|
||||
this.rawNet = rawNet;
|
||||
this.topModuleName = globalLookup.topModuleName;
|
||||
pinkLog(`当前模块 ${this.topModuleName}`);
|
||||
|
||||
/**
|
||||
* @type {Module}
|
||||
*/
|
||||
let topModule = undefined;
|
||||
|
||||
// 构造模块树
|
||||
for (const [moduleName, rawModule] of Object.entries(rawNet.modules)) {
|
||||
const top = parseInt(rawModule.attributes.top);
|
||||
// 一开始只渲染 top 模块,或者告诉我当前的 top 是什么
|
||||
if (top) {
|
||||
const module = new Module(moduleName, rawModule);
|
||||
|
||||
if (moduleName === this.topModuleName) {
|
||||
// 构造符合 elk 格式的节点数据
|
||||
topModule = module;
|
||||
const portNodes = module.makeNetsElkNodes();
|
||||
const cellNodes = module.makeCellsElkNodes();
|
||||
const [constantNodes, connectionEdges] = module.makeConnectionElkNodes();
|
||||
@ -104,6 +110,42 @@ export class NetlistRender {
|
||||
this.nameToModule.set(moduleName, module);
|
||||
}
|
||||
}
|
||||
|
||||
if (topModule === undefined) {
|
||||
redLog(`当前 netlist 中没有找到名为 ${this.topModuleName} 的顶层模块! Digital IDE 无法构建它的 treeview 视图!`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据 topModule + this.nameToModule 构建出用于渲染右侧列表的数据结构
|
||||
const nameToModule = this.nameToModule;
|
||||
|
||||
// 记录当前需要不断递归解析成渲染视图的 module 的 name
|
||||
// 从将每一个 module 的 tree 中关于 Cell 的部分完成指向(判断这个 Cell 是不是 例化模块,并找到它们对应的 Module 对象)
|
||||
const moduleStack = [topModule.name];
|
||||
|
||||
while (moduleStack.length > 0) {
|
||||
const moduleName = moduleStack.pop();
|
||||
const currentModule = nameToModule.get(moduleName);
|
||||
// 需要展示的数据:port, cell, (other netnames)
|
||||
const view = currentModule.view;
|
||||
for (const cellName of view.nameToCell.keys()) {
|
||||
const cell = view.nameToCell.get(cellName);
|
||||
const solveInstanceTypes = new Set();
|
||||
if (nameToModule.has(cell.type)) {
|
||||
cell.isInstantiation = true;
|
||||
const instModule = nameToModule.get(cell.type);
|
||||
cell.belongModuleView = instModule.view;
|
||||
solveInstanceTypes.add(cell.type);
|
||||
}
|
||||
for (const instanceBelongModuleName of solveInstanceTypes) {
|
||||
moduleStack.push(instanceBelongModuleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 将默认的顶层模块的 view 加入响应数组中,响应地去渲染右侧的 view
|
||||
const rootView = topModule.view;
|
||||
treeviewData.modules.push(rootView);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -31,6 +31,7 @@ export class InstantiationRender {
|
||||
this.data.push({
|
||||
x: node.x,
|
||||
y: node.y,
|
||||
name: node.name,
|
||||
width: node.width,
|
||||
height: node.height,
|
||||
fill: 'var(--main-dark-color)',
|
||||
@ -39,4 +40,98 @@ export class InstantiationRender {
|
||||
ry: 3
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const data = this.data;
|
||||
const rootRender = this.rootRender;
|
||||
const id2manager = this.id2manager;
|
||||
const _this = this;
|
||||
|
||||
let instantiationSelections = this.parentSelection.selectAll('g.instance')
|
||||
.data(data)
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('class', 'instance')
|
||||
.attr("transform", d => `translate(${d.x}, ${d.y})`);
|
||||
|
||||
let instances = instantiationSelections.append('rect')
|
||||
.attr('width', data => data.width)
|
||||
.attr('height', data => data.height)
|
||||
.attr('fill', d => d.fill);
|
||||
|
||||
let texts = instantiationSelections.append('text')
|
||||
.attr('x', data => data.width / 2) // 文本的 x 坐标(居中)
|
||||
.attr('y', data => data.height / 2) // 文本的 y 坐标(居中)
|
||||
.attr('dominant-baseline', 'middle') // 文本垂直居中
|
||||
.attr('text-anchor', 'middle') // 文本水平居中
|
||||
.attr('fill', 'var(--foreground)') // 文本颜色
|
||||
.attr('font-size', '0')
|
||||
.transition()
|
||||
.duration(1000)
|
||||
.attr('font-size', '15px')
|
||||
.attr('class', 'port-caption')
|
||||
.text(data => data.name); // 设置文本内容
|
||||
|
||||
|
||||
if (globalSetting.renderAnimation) {
|
||||
instances.transition()
|
||||
.duration(1000)
|
||||
.attr('stroke', 'var(--main-color)')
|
||||
.attr('stroke-width', 2)
|
||||
.attr('rx', d => d.rx)
|
||||
.attr('ry', d => d.ry);
|
||||
} else {
|
||||
instances.attr('stroke', 'var(--main-color)')
|
||||
.attr('stroke-width', 2)
|
||||
.attr('rx', d => d.rx)
|
||||
.attr('ry', d => d.ry);
|
||||
}
|
||||
|
||||
instantiationSelections
|
||||
.attr('class', 'grab')
|
||||
.each(function (data) {
|
||||
const portSelection = d3.select(this);
|
||||
const manager = _this.createDataManager(portSelection, data);
|
||||
|
||||
// TODO: 实现拖拽
|
||||
// registerDragEvent(manager, rootRender);
|
||||
});
|
||||
|
||||
this.selections = instantiationSelections;
|
||||
return instantiationSelections;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {d3.Selection} selection
|
||||
* @param {BasicD3DataItem} data
|
||||
* @returns {BasicD3ManagmentItem}
|
||||
*/
|
||||
createDataManager(selection, data) {
|
||||
const id2manager = this.id2manager;
|
||||
// 创建拖拽上下文
|
||||
const dragContext = {
|
||||
neighbors: [],
|
||||
elkGraph: {
|
||||
// elk 是无状态的,id 取什么名字都行
|
||||
id: 'root',
|
||||
children: [],
|
||||
edges: [],
|
||||
layoutOptions: {}
|
||||
}
|
||||
}
|
||||
const managerItem = {
|
||||
data,
|
||||
selection,
|
||||
type: 'cell',
|
||||
dragContext
|
||||
};
|
||||
|
||||
if (!id2manager.has(data.id)) {
|
||||
id2manager.set(data.id, []);
|
||||
}
|
||||
|
||||
id2manager.get(data.id).push(managerItem);
|
||||
return managerItem;
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import { globalLookup } from "../global";
|
||||
import { Cell, ModuleTree } from "./yosys";
|
||||
import { Cell, ModuleView } from "./yosys";
|
||||
|
||||
export const LINE_WIDTH = 2;
|
||||
|
||||
@ -48,9 +48,9 @@ export class Module {
|
||||
|
||||
/**
|
||||
* @description
|
||||
* @type {ModuleTree}
|
||||
* @type {ModuleView}
|
||||
*/
|
||||
this.moduleTree = new ModuleTree(name, module);
|
||||
this.view = new ModuleView(name, module);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -61,12 +61,13 @@ export class Module {
|
||||
const nodes = [];
|
||||
|
||||
// 绘制 ports
|
||||
for (const name of this.moduleTree.nameToPort.keys()) {
|
||||
const port = this.moduleTree.nameToPort.get(name);
|
||||
for (const name of this.view.nameToPort.keys()) {
|
||||
const port = this.view.nameToPort.get(name);
|
||||
|
||||
if (port.direction === 'input') {
|
||||
const node = {
|
||||
id: port.id,
|
||||
name: port.name,
|
||||
renderName: name,
|
||||
renderType: 'port',
|
||||
type: port.direction,
|
||||
@ -81,6 +82,7 @@ export class Module {
|
||||
} else {
|
||||
const node = {
|
||||
id: port.id,
|
||||
name: port.name,
|
||||
renderName: name,
|
||||
renderType: 'port',
|
||||
type: port.direction,
|
||||
@ -111,8 +113,8 @@ export class Module {
|
||||
const edges = [];
|
||||
|
||||
const skinManager = globalLookup.skinManager;
|
||||
for (const name of this.moduleTree.nameToCell.keys()) {
|
||||
const cell = this.moduleTree.nameToCell.get(name);
|
||||
for (const name of this.view.nameToCell.keys()) {
|
||||
const cell = this.view.nameToCell.get(name);
|
||||
const skin = skinManager.querySkin(cell.type);
|
||||
|
||||
if (skin) {
|
||||
@ -173,6 +175,7 @@ export class Module {
|
||||
|
||||
const node = {
|
||||
id: cell.id,
|
||||
name: cell.name,
|
||||
renderName: cell.type,
|
||||
renderType: 'cell',
|
||||
width,
|
||||
@ -207,6 +210,7 @@ export class Module {
|
||||
|
||||
const node = {
|
||||
id: cell.id,
|
||||
name: cell.name,
|
||||
renderName: cell.type,
|
||||
renderType: 'cell',
|
||||
width,
|
||||
@ -234,7 +238,7 @@ export class Module {
|
||||
const nodes = [];
|
||||
const edges = [];
|
||||
|
||||
const tree = this.moduleTree
|
||||
const tree = this.view
|
||||
|
||||
for (const cellName of tree.nameToCell.keys()) {
|
||||
const cell = tree.nameToCell.get(cellName);
|
||||
|
@ -1,8 +1,8 @@
|
||||
/**
|
||||
* @description 模块树对象,直接作为 treeview 的渲染视图加入运算
|
||||
* 相比于 YosysNetModule, ModuleTree 只关心和渲染有关的那部分变量,且不可被序列化
|
||||
* 相比于 YosysNetModule, ModuleView 只关心和渲染有关的那部分变量,且不可被序列化
|
||||
*/
|
||||
export class ModuleTree {
|
||||
export class ModuleView {
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {YosysNetModule} rawModule
|
||||
@ -96,12 +96,12 @@ export class ModuleTree {
|
||||
export class Port {
|
||||
/**
|
||||
* @description port 的抽象
|
||||
* @param {ModuleTree} moduleTree
|
||||
* @param {ModuleView} view
|
||||
* @param {string} name
|
||||
* @param {YosysPort} rawPort
|
||||
*/
|
||||
constructor(moduleTree, name, rawPort) {
|
||||
this.moduleTree = moduleTree;
|
||||
constructor(view, name, rawPort) {
|
||||
this.view = view;
|
||||
this.name = name;
|
||||
this.rawPort = rawPort;
|
||||
}
|
||||
@ -115,22 +115,33 @@ export class Port {
|
||||
}
|
||||
|
||||
get id() {
|
||||
return dotConnect(this.moduleTree.id, this.name);
|
||||
return dotConnect(this.view.id, this.name);
|
||||
}
|
||||
}
|
||||
|
||||
export class Cell {
|
||||
/**
|
||||
* @description 器件的抽象
|
||||
* @param {ModuleTree} moduleTree
|
||||
* @param {ModuleView} view
|
||||
* @param {string} name
|
||||
* @param {YosysCell} rawCell
|
||||
*/
|
||||
constructor(moduleTree, name, rawCell) {
|
||||
this.moduleTree = moduleTree;
|
||||
constructor(view, name, rawCell) {
|
||||
this.view = view;
|
||||
this.name = name;
|
||||
this.rawCell = rawCell;
|
||||
|
||||
/**
|
||||
* @description 是否为例化模块
|
||||
*/
|
||||
this.isInstantiation = false;
|
||||
|
||||
/**
|
||||
* @description 如果是例化模块,它对应的 module 的 tree
|
||||
* @type {ModuleView}
|
||||
*/
|
||||
this.belongModuleView = undefined;
|
||||
|
||||
this._nameToConnection = new Map();
|
||||
|
||||
for (const [connectionName, wireIds] of Object.entries(rawCell.connections)) {
|
||||
@ -146,12 +157,17 @@ export class Cell {
|
||||
return this._nameToConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 当前器件的类型
|
||||
* - 如果器件是一个例化模块,那么 type 就是这个例化的 module 的名字,比如 `full_adder_1bit`
|
||||
* - 如果器件是一个基本器件,那么 type 就是 yosys 文档中记录的关于这个器件的名字,比如 $_AND_(与门), $_OR_(或门)
|
||||
*/
|
||||
get type() {
|
||||
return this.rawCell.type;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return dotConnect(this.moduleTree.id, this.name);
|
||||
return dotConnect(this.view.id, this.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,10 @@
|
||||
const pinkLogStyle = 'background-color: #CB81DA; color: white; padding: 3px; border-radius: 3px;';
|
||||
const redLogStyle = 'background-color:rgb(227, 91, 49); color: white; padding: 3px; border-radius: 3px;';
|
||||
|
||||
export function pinkLog(message) {
|
||||
console.log('%c' + message, pinkLogStyle);
|
||||
}
|
||||
|
||||
export function redLog(message) {
|
||||
console.log('%c' + message, redLogStyle);
|
||||
}
|
@ -15,5 +15,6 @@
|
||||
"usermanual.move-view": "عرض الجوال",
|
||||
"usermanual.scale-view": "تكبير/تصغير العرض",
|
||||
"usermanual.scale-view-more": "تكبير العرض (مقياس أكبر)",
|
||||
"loading": "جاري التحميل"
|
||||
"loading": "جاري التحميل",
|
||||
"module": "وحدة"
|
||||
}
|
@ -15,5 +15,6 @@
|
||||
"usermanual.move-view": "Mobile Ansicht",
|
||||
"usermanual.scale-view": "Ansicht zoomen",
|
||||
"usermanual.scale-view-more": "Ansicht vergrößern (größerer Maßstab)",
|
||||
"loading": "Laden"
|
||||
"loading": "Laden",
|
||||
"module": "Modul"
|
||||
}
|
@ -15,5 +15,6 @@
|
||||
"usermanual.move-view": "Mobile View",
|
||||
"usermanual.scale-view": "View zoom",
|
||||
"usermanual.scale-view-more": "View zoom (larger scale)",
|
||||
"loading": "loading"
|
||||
"loading": "loading",
|
||||
"module": "Modules"
|
||||
}
|
@ -15,5 +15,6 @@
|
||||
"usermanual.move-view": "Vue mobile",
|
||||
"usermanual.scale-view": "Zoom de la vue",
|
||||
"usermanual.scale-view-more": "Zoom de la vue (échelle plus grande)",
|
||||
"loading": "Chargement"
|
||||
"loading": "Chargement",
|
||||
"module": "Module"
|
||||
}
|
@ -15,5 +15,6 @@
|
||||
"usermanual.move-view": "モバイル表示",
|
||||
"usermanual.scale-view": "ビューのズーム",
|
||||
"usermanual.scale-view-more": "ビューのズーム(より大きなスケール)",
|
||||
"loading": "読み込み中"
|
||||
"loading": "読み込み中",
|
||||
"module": "モジュール"
|
||||
}
|
@ -15,5 +15,6 @@
|
||||
"usermanual.move-view": "모바일 보기",
|
||||
"usermanual.scale-view": "보기 확대/축소",
|
||||
"usermanual.scale-view-more": "보기 확대 (더 큰 스케일)",
|
||||
"loading": "로딩 중"
|
||||
"loading": "로딩 중",
|
||||
"module": "모듈"
|
||||
}
|
@ -15,5 +15,6 @@
|
||||
"usermanual.move-view": "Мобильный вид",
|
||||
"usermanual.scale-view": "Масштабирование вида",
|
||||
"usermanual.scale-view-more": "Масштабирование вида (больший масштаб)",
|
||||
"loading": "Загрузка"
|
||||
"loading": "Загрузка",
|
||||
"module": "Модуль"
|
||||
}
|
@ -15,5 +15,6 @@
|
||||
"usermanual.move-view": "移动视图",
|
||||
"usermanual.scale-view": "视图缩放",
|
||||
"usermanual.scale-view-more": "视图缩放(尺度更大)",
|
||||
"loading": "加载中"
|
||||
"loading": "加载中",
|
||||
"module": "模块"
|
||||
}
|
@ -15,5 +15,6 @@
|
||||
"usermanual.move-view": "移動視圖",
|
||||
"usermanual.scale-view": "視圖縮放",
|
||||
"usermanual.scale-view-more": "視圖縮放(尺度更大)",
|
||||
"loading": "加載中"
|
||||
"loading": "加載中",
|
||||
"module": "模塊"
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user