更新架构,进行依赖注入

This commit is contained in:
锦恢 2024-12-28 01:37:58 +08:00
parent eabdba2602
commit 0aa38f5133
24 changed files with 476 additions and 60 deletions

View File

@ -23,7 +23,8 @@
const skinBinary = await r2.arrayBuffer(); const skinBinary = await r2.arrayBuffer();
return [ netJson, skinBinary ]; return [ netJson, skinBinary ];
} }
window.avoidWasm = 'avoid.wasm'; window.moduleName = 'half_adder';
// window.avoidWasm = 'avoid.wasm';
</script> </script>
</head> </head>

View File

@ -37,8 +37,8 @@ body::-webkit-scrollbar {
* hr { * hr {
border: none; border: none;
background-color: var(--vscode-focusBorder); background-color: var(--main-color);
height: 2px; height: 1.5px;
width: 95%; width: 95%;
} }
/* /*

View File

@ -35,6 +35,8 @@ onMounted(async () => {
text: t('loading'), text: t('loading'),
background: 'rgba(0, 0, 0, 0.7)' background: 'rgba(0, 0, 0, 0.7)'
}); });
globalLookup.topModuleName = window.moduleName;
// netlist json // netlist json
const [ netJson, skinBinary ] = await window.readNetFile(); const [ netJson, skinBinary ] = await window.readNetFile();

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="vcd-right-nav"> <div class="netlist-right-nav">
<div class="vcd-function-panel"> <div class="netlist-function-panel">
<TreeView <TreeView
v-show="controlPanel.currentIndex === 0"></TreeView> v-show="controlPanel.currentIndex === 0"></TreeView>
<Setting <Setting
@ -10,17 +10,17 @@
v-show="controlPanel.currentIndex === 2"></About> v-show="controlPanel.currentIndex === 2"></About>
</div> </div>
<div class="vcd-function-option"> <div class="netlist-function-option">
<div class="vcd-control-panel-wrapper"> <div class="netlist-control-panel-wrapper">
<div class="vcd-control-panel-icon digital-ide-icon" /> <div class="netlist-control-panel-icon digital-ide-icon" />
</div> </div>
<hr> <hr>
<div class="vcd-control-panel-wrapper" <div class="netlist-control-panel-wrapper"
v-for="(section, index) of controlPanel.sections" :key="index" v-for="(section, index) of controlPanel.sections" :key="index"
@click="controlPanel.click(index)" @click="controlPanel.click(index)"
> >
<div :class="controlPanel.currentIndex === index ? 'vcd-control-panel-active': ''"><span <div :class="controlPanel.currentIndex === index ? 'netlist-control-panel-active': ''"><span
class="vcd-control-panel-icon" class="netlist-control-panel-icon"
:class="section.iconClass" :class="section.iconClass"
></span></div> ></span></div>
</div> </div>
@ -51,7 +51,7 @@ emitter.on('right-nav', index => {
</script> </script>
<style> <style>
.vcd-right-nav { .netlist-right-nav {
display: flex; display: flex;
position: fixed; position: fixed;
top: 0; top: 0;
@ -59,21 +59,21 @@ emitter.on('right-nav', index => {
z-index: 230; z-index: 230;
} }
.vcd-function-panel { .netlist-function-panel {
display: flex; display: flex;
background-color: var(--sidebar); background-color: var(--sidebar);
height: 100vh; height: 100vh;
box-shadow: var(--gray-box-shadow-1); box-shadow: var(--gray-box-shadow-1);
} }
.vcd-function-option { .netlist-function-option {
width: fit-content; width: fit-content;
height: 100vh; height: 100vh;
background-color: var(--sidebar); background-color: var(--sidebar);
box-shadow: var(--gray-box-shadow-1); box-shadow: var(--gray-box-shadow-1);
} }
.vcd-control-panel-wrapper { .netlist-control-panel-wrapper {
width: var(--right-nav-width); width: var(--right-nav-width);
height: var(--right-nav-width); height: var(--right-nav-width);
display: flex; display: flex;
@ -84,17 +84,17 @@ emitter.on('right-nav', index => {
color: var(--vscode-foreground); color: var(--vscode-foreground);
} }
.vcd-control-panel-wrapper:hover { .netlist-control-panel-wrapper:hover {
color: var(--vscode-icon-foreground); color: var(--vscode-icon-foreground);
} }
.vcd-control-panel-icon { .netlist-control-panel-icon {
width: 45px; width: 45px;
height: 45px; height: 45px;
font-size: 30px; font-size: 30px;
} }
.vcd-control-panel-active { .netlist-control-panel-active {
color: var(--main-color); color: var(--main-color);
} }
</style> </style>

View File

@ -1,20 +1,69 @@
<template> <template>
<div class="netlist-tree-view"> <div class="netlist-tree-view">
<div class="search-nothing"> <div class="netlist-module-info">
<span class="iconfont icon-empty"></span> <div class="netlist-signal-title">{{ t('module') }}</div>
<span>Mirror the unknown</span> <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>
</div> </div>
</template> </template>
<script setup> <script setup>
import { defineComponent } from 'vue'; 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' }); defineComponent({ name: 'tree-view' });
</script> </script>
<style> <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 { .search-nothing {
height: 40vh; height: 40vh;
width: 100%; width: 100%;

View 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>
&ensp;{{ 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>
&ensp;{{ 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>

View File

@ -0,0 +1,13 @@
import { ModuleView } from '@/hook/render/yosys';
import { reactive } from 'vue';
export const treeviewData = reactive({
/**
* @description 当前的顶层模块数量内部数据结构是递归的
* 大部分情况下它应该是只有一个元素
*
* @type {ModuleView[]}
*/
modules: []
});

View File

@ -8,7 +8,7 @@ export function setDefaultCss() {
document.body.style.setProperty('--el-color-primary-light-3', 'var(--main-color)'); 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-secondary', 'var(--foreground)');
document.body.style.setProperty('--el-text-color-regular', '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-blank', 'var(--sidebar)');
document.body.style.setProperty('--el-fill-color-light', 'var(--vscode-button-hoverBackground)'); document.body.style.setProperty('--el-fill-color-light', 'var(--vscode-button-hoverBackground)');
document.body.style.setProperty('--el-switch-on-color', 'var(--main-color)'); 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-light', 'var(--sidebar)');
document.body.style.setProperty('--el-border-color-lighter', '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-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', '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('--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('--sidebar-width', '330px');
document.body.style.setProperty('--toolbar-height', '60px'); document.body.style.setProperty('--toolbar-height', '60px');

View File

@ -25,7 +25,18 @@ export const globalLookup = {
/** /**
* @type {Avoid} * @type {Avoid}
*/ */
Avoid: undefined Avoid: undefined,
/**
* @description 当前仿真结果的顶层模块的名字
* @type {string}
*/
topModuleName: '',
/**
* @description 当前选择的实体可以是 wire也可以是 cell
*/
currentSelectEntity: undefined
}; };
function loadSetting() { function loadSetting() {

View File

@ -5,6 +5,8 @@
* @property {Record<string, YosysModel>} [models] 模型定义的映射仅在使用 `-aig` 选项时存在 * @property {Record<string, YosysModel>} [models] 模型定义的映射仅在使用 `-aig` 选项时存在
*/ */
import { Module } from "./render/layout";
/** /**
* @typedef {number | string} WireId 信号ID * @typedef {number | string} WireId 信号ID
*/ */
@ -252,4 +254,4 @@
/** /**
* @typedef DragConnection * @typedef DragConnection
* @property {d3.Selection} selection * @property {d3.Selection} selection
*/ */

View File

@ -9,7 +9,8 @@ import { InstantiationRender } from './instantiation';
import { CellRender } from './cell'; import { CellRender } from './cell';
import { ConnectionRender } from './connection'; import { ConnectionRender } from './connection';
import { WireRender } from './wire'; import { WireRender } from './wire';
import { pinkLog } from '../utils'; import { pinkLog, redLog } from '../utils';
import { treeviewData } from '@/components/treeview/tree';
export class NetlistRender { export class NetlistRender {
/** /**
@ -82,15 +83,20 @@ export class NetlistRender {
* @type {YosysRawNet} * @type {YosysRawNet}
*/ */
this.rawNet = rawNet; this.rawNet = rawNet;
this.topModuleName = globalLookup.topModuleName;
pinkLog(`当前模块 ${this.topModuleName}`);
/**
* @type {Module}
*/
let topModule = undefined;
// 构造模块树 // 构造模块树
for (const [moduleName, rawModule] of Object.entries(rawNet.modules)) { for (const [moduleName, rawModule] of Object.entries(rawNet.modules)) {
const top = parseInt(rawModule.attributes.top); const module = new Module(moduleName, rawModule);
// 一开始只渲染 top 模块,或者告诉我当前的 top 是什么 if (moduleName === this.topModuleName) {
if (top) {
const module = new Module(moduleName, rawModule);
// 构造符合 elk 格式的节点数据 // 构造符合 elk 格式的节点数据
topModule = module;
const portNodes = module.makeNetsElkNodes(); const portNodes = module.makeNetsElkNodes();
const cellNodes = module.makeCellsElkNodes(); const cellNodes = module.makeCellsElkNodes();
const [constantNodes, connectionEdges] = module.makeConnectionElkNodes(); const [constantNodes, connectionEdges] = module.makeConnectionElkNodes();
@ -104,6 +110,42 @@ export class NetlistRender {
this.nameToModule.set(moduleName, module); 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);
} }
/** /**

View File

@ -31,6 +31,7 @@ export class InstantiationRender {
this.data.push({ this.data.push({
x: node.x, x: node.x,
y: node.y, y: node.y,
name: node.name,
width: node.width, width: node.width,
height: node.height, height: node.height,
fill: 'var(--main-dark-color)', fill: 'var(--main-dark-color)',
@ -39,4 +40,98 @@ export class InstantiationRender {
ry: 3 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;
}
} }

View File

@ -3,7 +3,7 @@
*/ */
import { globalLookup } from "../global"; import { globalLookup } from "../global";
import { Cell, ModuleTree } from "./yosys"; import { Cell, ModuleView } from "./yosys";
export const LINE_WIDTH = 2; export const LINE_WIDTH = 2;
@ -48,9 +48,9 @@ export class Module {
/** /**
* @description * @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 = []; const nodes = [];
// 绘制 ports // 绘制 ports
for (const name of this.moduleTree.nameToPort.keys()) { for (const name of this.view.nameToPort.keys()) {
const port = this.moduleTree.nameToPort.get(name); const port = this.view.nameToPort.get(name);
if (port.direction === 'input') { if (port.direction === 'input') {
const node = { const node = {
id: port.id, id: port.id,
name: port.name,
renderName: name, renderName: name,
renderType: 'port', renderType: 'port',
type: port.direction, type: port.direction,
@ -81,6 +82,7 @@ export class Module {
} else { } else {
const node = { const node = {
id: port.id, id: port.id,
name: port.name,
renderName: name, renderName: name,
renderType: 'port', renderType: 'port',
type: port.direction, type: port.direction,
@ -111,8 +113,8 @@ export class Module {
const edges = []; const edges = [];
const skinManager = globalLookup.skinManager; const skinManager = globalLookup.skinManager;
for (const name of this.moduleTree.nameToCell.keys()) { for (const name of this.view.nameToCell.keys()) {
const cell = this.moduleTree.nameToCell.get(name); const cell = this.view.nameToCell.get(name);
const skin = skinManager.querySkin(cell.type); const skin = skinManager.querySkin(cell.type);
if (skin) { if (skin) {
@ -173,6 +175,7 @@ export class Module {
const node = { const node = {
id: cell.id, id: cell.id,
name: cell.name,
renderName: cell.type, renderName: cell.type,
renderType: 'cell', renderType: 'cell',
width, width,
@ -207,6 +210,7 @@ export class Module {
const node = { const node = {
id: cell.id, id: cell.id,
name: cell.name,
renderName: cell.type, renderName: cell.type,
renderType: 'cell', renderType: 'cell',
width, width,
@ -234,7 +238,7 @@ export class Module {
const nodes = []; const nodes = [];
const edges = []; const edges = [];
const tree = this.moduleTree const tree = this.view
for (const cellName of tree.nameToCell.keys()) { for (const cellName of tree.nameToCell.keys()) {
const cell = tree.nameToCell.get(cellName); const cell = tree.nameToCell.get(cellName);

View File

@ -1,8 +1,8 @@
/** /**
* @description 模块树对象直接作为 treeview 的渲染视图加入运算 * @description 模块树对象直接作为 treeview 的渲染视图加入运算
* 相比于 YosysNetModule, ModuleTree 只关心和渲染有关的那部分变量且不可被序列化 * 相比于 YosysNetModule, ModuleView 只关心和渲染有关的那部分变量且不可被序列化
*/ */
export class ModuleTree { export class ModuleView {
/** /**
* @param {string} name * @param {string} name
* @param {YosysNetModule} rawModule * @param {YosysNetModule} rawModule
@ -96,12 +96,12 @@ export class ModuleTree {
export class Port { export class Port {
/** /**
* @description port 的抽象 * @description port 的抽象
* @param {ModuleTree} moduleTree * @param {ModuleView} view
* @param {string} name * @param {string} name
* @param {YosysPort} rawPort * @param {YosysPort} rawPort
*/ */
constructor(moduleTree, name, rawPort) { constructor(view, name, rawPort) {
this.moduleTree = moduleTree; this.view = view;
this.name = name; this.name = name;
this.rawPort = rawPort; this.rawPort = rawPort;
} }
@ -115,22 +115,33 @@ export class Port {
} }
get id() { get id() {
return dotConnect(this.moduleTree.id, this.name); return dotConnect(this.view.id, this.name);
} }
} }
export class Cell { export class Cell {
/** /**
* @description 器件的抽象 * @description 器件的抽象
* @param {ModuleTree} moduleTree * @param {ModuleView} view
* @param {string} name * @param {string} name
* @param {YosysCell} rawCell * @param {YosysCell} rawCell
*/ */
constructor(moduleTree, name, rawCell) { constructor(view, name, rawCell) {
this.moduleTree = moduleTree; this.view = view;
this.name = name; this.name = name;
this.rawCell = rawCell; this.rawCell = rawCell;
/**
* @description 是否为例化模块
*/
this.isInstantiation = false;
/**
* @description 如果是例化模块它对应的 module tree
* @type {ModuleView}
*/
this.belongModuleView = undefined;
this._nameToConnection = new Map(); this._nameToConnection = new Map();
for (const [connectionName, wireIds] of Object.entries(rawCell.connections)) { for (const [connectionName, wireIds] of Object.entries(rawCell.connections)) {
@ -146,12 +157,17 @@ export class Cell {
return this._nameToConnection; return this._nameToConnection;
} }
/**
* @description 当前器件的类型
* - 如果器件是一个例化模块那么 type 就是这个例化的 module 的名字比如 `full_adder_1bit`
* - 如果器件是一个基本器件那么 type 就是 yosys 文档中记录的关于这个器件的名字比如 $_AND_(与门), $_OR_(或门)
*/
get type() { get type() {
return this.rawCell.type; return this.rawCell.type;
} }
get id() { get id() {
return dotConnect(this.moduleTree.id, this.name); return dotConnect(this.view.id, this.name);
} }
} }

View File

@ -1,5 +1,10 @@
const pinkLogStyle = 'background-color: #CB81DA; color: white; padding: 3px; border-radius: 3px;'; 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) { export function pinkLog(message) {
console.log('%c' + message, pinkLogStyle); console.log('%c' + message, pinkLogStyle);
}
export function redLog(message) {
console.log('%c' + message, redLogStyle);
} }

View File

@ -15,5 +15,6 @@
"usermanual.move-view": "عرض الجوال", "usermanual.move-view": "عرض الجوال",
"usermanual.scale-view": "تكبير/تصغير العرض", "usermanual.scale-view": "تكبير/تصغير العرض",
"usermanual.scale-view-more": "تكبير العرض (مقياس أكبر)", "usermanual.scale-view-more": "تكبير العرض (مقياس أكبر)",
"loading": "جاري التحميل" "loading": "جاري التحميل",
"module": "وحدة"
} }

View File

@ -15,5 +15,6 @@
"usermanual.move-view": "Mobile Ansicht", "usermanual.move-view": "Mobile Ansicht",
"usermanual.scale-view": "Ansicht zoomen", "usermanual.scale-view": "Ansicht zoomen",
"usermanual.scale-view-more": "Ansicht vergrößern (größerer Maßstab)", "usermanual.scale-view-more": "Ansicht vergrößern (größerer Maßstab)",
"loading": "Laden" "loading": "Laden",
"module": "Modul"
} }

View File

@ -15,5 +15,6 @@
"usermanual.move-view": "Mobile View", "usermanual.move-view": "Mobile View",
"usermanual.scale-view": "View zoom", "usermanual.scale-view": "View zoom",
"usermanual.scale-view-more": "View zoom (larger scale)", "usermanual.scale-view-more": "View zoom (larger scale)",
"loading": "loading" "loading": "loading",
"module": "Modules"
} }

View File

@ -15,5 +15,6 @@
"usermanual.move-view": "Vue mobile", "usermanual.move-view": "Vue mobile",
"usermanual.scale-view": "Zoom de la vue", "usermanual.scale-view": "Zoom de la vue",
"usermanual.scale-view-more": "Zoom de la vue (échelle plus grande)", "usermanual.scale-view-more": "Zoom de la vue (échelle plus grande)",
"loading": "Chargement" "loading": "Chargement",
"module": "Module"
} }

View File

@ -15,5 +15,6 @@
"usermanual.move-view": "モバイル表示", "usermanual.move-view": "モバイル表示",
"usermanual.scale-view": "ビューのズーム", "usermanual.scale-view": "ビューのズーム",
"usermanual.scale-view-more": "ビューのズーム(より大きなスケール)", "usermanual.scale-view-more": "ビューのズーム(より大きなスケール)",
"loading": "読み込み中" "loading": "読み込み中",
"module": "モジュール"
} }

View File

@ -15,5 +15,6 @@
"usermanual.move-view": "모바일 보기", "usermanual.move-view": "모바일 보기",
"usermanual.scale-view": "보기 확대/축소", "usermanual.scale-view": "보기 확대/축소",
"usermanual.scale-view-more": "보기 확대 (더 큰 스케일)", "usermanual.scale-view-more": "보기 확대 (더 큰 스케일)",
"loading": "로딩 중" "loading": "로딩 중",
"module": "모듈"
} }

View File

@ -15,5 +15,6 @@
"usermanual.move-view": "Мобильный вид", "usermanual.move-view": "Мобильный вид",
"usermanual.scale-view": "Масштабирование вида", "usermanual.scale-view": "Масштабирование вида",
"usermanual.scale-view-more": "Масштабирование вида (больший масштаб)", "usermanual.scale-view-more": "Масштабирование вида (больший масштаб)",
"loading": "Загрузка" "loading": "Загрузка",
"module": "Модуль"
} }

View File

@ -15,5 +15,6 @@
"usermanual.move-view": "移动视图", "usermanual.move-view": "移动视图",
"usermanual.scale-view": "视图缩放", "usermanual.scale-view": "视图缩放",
"usermanual.scale-view-more": "视图缩放(尺度更大)", "usermanual.scale-view-more": "视图缩放(尺度更大)",
"loading": "加载中" "loading": "加载中",
"module": "模块"
} }

View File

@ -15,5 +15,6 @@
"usermanual.move-view": "移動視圖", "usermanual.move-view": "移動視圖",
"usermanual.scale-view": "視圖縮放", "usermanual.scale-view": "視圖縮放",
"usermanual.scale-view-more": "視圖縮放(尺度更大)", "usermanual.scale-view-more": "視圖縮放(尺度更大)",
"loading": "加載中" "loading": "加載中",
"module": "模塊"
} }