update loading
This commit is contained in:
parent
7a16c7add2
commit
284bb4bd1a
@ -1,8 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 4440655 */
|
font-family: "iconfont"; /* Project id 4440655 */
|
||||||
src: url('iconfont.woff2?t=1709106897565') format('woff2'),
|
src: url('iconfont.woff2?t=1709378049768') format('woff2'),
|
||||||
url('iconfont.woff?t=1709106897565') format('woff'),
|
url('iconfont.woff?t=1709378049768') format('woff'),
|
||||||
url('iconfont.ttf?t=1709106897565') format('truetype');
|
url('iconfont.ttf?t=1709378049768') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@ -13,6 +13,42 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-parameter:before {
|
||||||
|
content: "\e6be";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-task-:before {
|
||||||
|
content: "\e602";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-fork:before {
|
||||||
|
content: "\e735";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-prevent:before {
|
||||||
|
content: "\e69d";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-Function:before {
|
||||||
|
content: "\e90e";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-R:before {
|
||||||
|
content: "\e6ec";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-integer:before {
|
||||||
|
content: "\e603";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-String:before {
|
||||||
|
content: "\e614";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-brackets:before {
|
||||||
|
content: "\e613";
|
||||||
|
}
|
||||||
|
|
||||||
.icon-register:before {
|
.icon-register:before {
|
||||||
content: "\e611";
|
content: "\e611";
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
9529
public/test.vcd
Normal file
9529
public/test.vcd
Normal file
File diff suppressed because it is too large
Load Diff
@ -2,11 +2,15 @@
|
|||||||
--display-signal-info-height: 50px;
|
--display-signal-info-height: 50px;
|
||||||
--signal-default-color: #4CAF50;
|
--signal-default-color: #4CAF50;
|
||||||
--main-color: #CB81DA;
|
--main-color: #CB81DA;
|
||||||
|
--sidebar-width: 280px;
|
||||||
|
--right-nav-width: 60px;
|
||||||
|
--time-scale-height: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
body::-webkit-scrollbar {
|
body::-webkit-scrollbar {
|
||||||
@ -76,3 +80,11 @@ body::-webkit-scrollbar {
|
|||||||
.el-checkbox-button__inner {
|
.el-checkbox-button__inner {
|
||||||
font-size: 16px !important;
|
font-size: 16px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-select {
|
||||||
|
width: fit-content !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--main-color);
|
||||||
|
}
|
40
src/App.vue
40
src/App.vue
@ -1,13 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="vcd-render-wrapper" @mousemove="getMousemove">
|
<!-- 主渲染区 -->
|
||||||
</div>
|
<MainRender></MainRender>
|
||||||
|
|
||||||
<!-- 左上角的 sidebar,用于显示 -->
|
<!-- 左上角的 sidebar,用于显示 -->
|
||||||
<Sidebar></Sidebar>
|
<Sidebar></Sidebar>
|
||||||
|
|
||||||
<!-- 工具栏 -->
|
<!-- 工具栏 -->
|
||||||
<div class="vcd-toolbar">
|
<div class="vcd-toolbar">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 显示当前信号树形关系 -->
|
<!-- 显示当前信号树形关系 -->
|
||||||
@ -18,15 +17,17 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMounted, reactive } from 'vue';
|
import { onMounted, reactive } from 'vue';
|
||||||
import { getVcdStream, readVcdFile } from '@/hook/utils';
|
import { getVcdStream, readVcdFile } from '@/hook/utils';
|
||||||
import { emitter, globalLookup, globalSetting } from '@/hook/global';
|
import { emitter, globalLookup, globalSetting, signalValues } from '@/hook/global';
|
||||||
|
|
||||||
import Sidebar from '@/components/sidebar.vue';
|
import Sidebar from '@/components/sidebar.vue';
|
||||||
import RightNav from '@/components/right-nav.vue';
|
import RightNav from '@/components/right-nav.vue';
|
||||||
|
import MainRender from '@/components/render';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
RightNav,
|
RightNav,
|
||||||
Sidebar
|
Sidebar,
|
||||||
|
MainRender
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
|
|
||||||
@ -50,6 +51,10 @@ export default {
|
|||||||
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', 'transplant');
|
document.body.style.setProperty('--el-bg-color-overlay', 'transplant');
|
||||||
|
document.body.style.setProperty('--el-color-info-light-9', 'var(--vscode-focusBorder)');
|
||||||
|
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-bg-color-overlay', 'transplant');
|
||||||
|
|
||||||
|
|
||||||
// signal height
|
// signal height
|
||||||
@ -58,21 +63,34 @@ export default {
|
|||||||
|
|
||||||
const uint8array = await readVcdFile();
|
const uint8array = await readVcdFile();
|
||||||
const vcdstream = await getVcdStream();
|
const vcdstream = await getVcdStream();
|
||||||
|
|
||||||
|
vcdstream.change.any((id, time, cmd, value, mask) => {
|
||||||
|
if (signalValues[id] === undefined) {
|
||||||
|
signalValues[id] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
signalValues[id].push({time, cmd, value, mask});
|
||||||
|
});
|
||||||
|
|
||||||
const maxChunkLength = 1 << 17;
|
const maxChunkLength = 1 << 17;
|
||||||
for (let i = 0; i < uint8array.length; i += maxChunkLength) {
|
for (let i = 0; i < uint8array.length; i += maxChunkLength) {
|
||||||
const piece = uint8array.slice(i, i + maxChunkLength);
|
const piece = uint8array.slice(i, i + maxChunkLength);
|
||||||
vcdstream.write(piece);
|
vcdstream.write(piece);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const topModule of vcdstream.info.wires.body) {
|
for (const topModule of vcdstream.info.wires.body) {
|
||||||
VcdInfo.topModules.push(topModule);
|
VcdInfo.topModules.push(topModule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
globalLookup.status = vcdstream.info.status;
|
globalLookup.status = vcdstream.info.status;
|
||||||
globalLookup.version = vcdstream.info.version;
|
globalLookup.version = vcdstream.info.version;
|
||||||
globalLookup.timescale = vcdstream.info.timescale;
|
globalLookup.timescale = vcdstream.info.timescale;
|
||||||
globalLookup.date = vcdstream.info.date;
|
globalLookup.date = vcdstream.info.date;
|
||||||
globalLookup.t0 = vcdstream.info.t0;
|
globalLookup.t0 = vcdstream.info.t0;
|
||||||
|
|
||||||
|
emitter.emit('meta-ready', null);
|
||||||
|
|
||||||
// 这一步时,已经加载完成
|
// 这一步时,已经加载完成
|
||||||
// 默认第一个模块被选中
|
// 默认第一个模块被选中
|
||||||
if (VcdInfo.topModules.length > 0) {
|
if (VcdInfo.topModules.length > 0) {
|
||||||
@ -86,13 +104,8 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function getMousemove(event) {
|
|
||||||
console.log(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
VcdInfo,
|
VcdInfo
|
||||||
getMousemove
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,9 +120,4 @@ export default {
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vcd-render-wrapper {
|
|
||||||
height: 98vh;
|
|
||||||
width: 98vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
181
src/components/render/cursor.vue
Normal file
181
src/components/render/cursor.vue
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
<template>
|
||||||
|
<div class="vertical-cursor-wrapper"
|
||||||
|
@click="makeCursor"
|
||||||
|
:style="`left: ${currentX}px`">
|
||||||
|
<div class="current-display-cursor-up">
|
||||||
|
<div class="current-time-value">{{ currentX }} px</div>
|
||||||
|
<div class="cursor-down-arrow"></div>
|
||||||
|
</div>
|
||||||
|
<div class="vertical-line"></div>
|
||||||
|
<div class="current-display-cursor-down">
|
||||||
|
<div class="current-time-value">{{ currentX }} px</div>
|
||||||
|
<div class="cursor-up-arrow"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-show="showFixedOne"
|
||||||
|
class="vertical-cursor-wrapper"
|
||||||
|
@click="makeCursor"
|
||||||
|
:style="`left: ${fixedLeft}px`">
|
||||||
|
<div class="fix-current-display-cursor-up">
|
||||||
|
{{ globalLookup.view.currentX }} px
|
||||||
|
</div>
|
||||||
|
<div class="fix-vertical-line"></div>
|
||||||
|
<div class="fix-current-display-cursor-down">
|
||||||
|
{{ globalLookup.view.currentX }} px
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, ref } from 'vue';
|
||||||
|
import { globalLookup } from '../../hook/global';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'vertical-cursor',
|
||||||
|
setup() {
|
||||||
|
// see --sidebar-width
|
||||||
|
const left = 280 + 20;
|
||||||
|
|
||||||
|
// see --right-nav-width
|
||||||
|
const right = document.body.clientWidth - 60;
|
||||||
|
|
||||||
|
const showFixedOne = ref(false);
|
||||||
|
const fixedLeft = ref(0);
|
||||||
|
const currentX = ref(left);
|
||||||
|
const boxShift = 25;
|
||||||
|
|
||||||
|
document.onmousemove = event => {
|
||||||
|
const x = event.x;
|
||||||
|
if (x < left || x > right) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
currentX.value = x - boxShift;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param { PointerEvent } event
|
||||||
|
*/
|
||||||
|
function makeCursor(event) {
|
||||||
|
console.log(event.x);
|
||||||
|
showFixedOne.value = true;
|
||||||
|
fixedLeft.value = event.x - boxShift;
|
||||||
|
globalLookup.view.currentX = event.x - boxShift;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
makeCursor,
|
||||||
|
fixedLeft,
|
||||||
|
showFixedOne,
|
||||||
|
boxShift,
|
||||||
|
globalLookup,
|
||||||
|
currentX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.vertical-cursor-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
height: 100vh;
|
||||||
|
padding: 0;
|
||||||
|
top: 0;
|
||||||
|
cursor: crosshair;
|
||||||
|
z-index: 55;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center; /* 沿着横轴(水平方向)对齐 */
|
||||||
|
justify-content: center; /* 沿着纵轴(垂直方向)对齐 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-display-cursor-up {
|
||||||
|
height: var(--time-scale-height);
|
||||||
|
width: 50px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
color: var(--sidebar-item-text);
|
||||||
|
font-size: 14px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-display-cursor-down {
|
||||||
|
height: var(--time-scale-height);
|
||||||
|
width: 50px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
color: var(--sidebar-item-text);
|
||||||
|
font-size: 14px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-time-value {
|
||||||
|
border-radius: .4em;
|
||||||
|
background-color: var(--color-deepPurple);
|
||||||
|
color: var(--sidebar-item-text);
|
||||||
|
padding: 5px;
|
||||||
|
width: fit-content;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-down-arrow {
|
||||||
|
border-left: 5px solid var(--color-deepPurple);
|
||||||
|
border-top: 5px solid var(--color-deepPurple);
|
||||||
|
transform: rotate(225deg);
|
||||||
|
position: absolute;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
/* 25px - 10 * 2 / \sqrt{2} */
|
||||||
|
left: 17.93px;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-up-arrow {
|
||||||
|
border-left: 5px solid var(--color-deepPurple);
|
||||||
|
border-top: 5px solid var(--color-deepPurple);
|
||||||
|
transform: rotate(45deg);
|
||||||
|
position: absolute;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
left: 17.93px;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-line {
|
||||||
|
width: 1px;
|
||||||
|
height: calc(100vh - 2 * var(--time-scale-height));
|
||||||
|
}
|
||||||
|
|
||||||
|
.fix-vertical-line {
|
||||||
|
width: 1px;
|
||||||
|
height: calc(100vh - 2 * var(--time-scale-height));
|
||||||
|
background-color: var(--color-deepPurple);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fix-current-display-cursor-up {
|
||||||
|
height: var(--time-scale-height);
|
||||||
|
width: 50px;
|
||||||
|
background-color: var(--color-deepPurple);
|
||||||
|
border-radius: .5em .5em .5em .5em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
color: var(--sidebar-item-text);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fix-current-display-cursor-down {
|
||||||
|
height: var(--time-scale-height);
|
||||||
|
width: 50px;
|
||||||
|
background-color: var(--color-deepPurple);
|
||||||
|
border-radius: .5em .5em .5em .5em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
color: var(--sidebar-item-text);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
48
src/components/render/index.vue
Normal file
48
src/components/render/index.vue
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<VerticalCursor></VerticalCursor>
|
||||||
|
<TimeScale></TimeScale>
|
||||||
|
|
||||||
|
<div class="vcd-render-wrapper" >
|
||||||
|
<div style="height: var(--time-scale-height);"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, ref } from 'vue';
|
||||||
|
import { emitter, globalLookup, globalSetting } from '@/hook/global';
|
||||||
|
|
||||||
|
import VerticalCursor from '@/components/render/cursor.vue';
|
||||||
|
import TimeScale from '@/components/render/time-scale.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'main-render',
|
||||||
|
components: {
|
||||||
|
VerticalCursor,
|
||||||
|
TimeScale
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const cursorX = ref(0);
|
||||||
|
|
||||||
|
return {
|
||||||
|
cursorX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.vcd-render-wrapper {
|
||||||
|
height: 98vh;
|
||||||
|
width: 98vw;
|
||||||
|
cursor: crosshair;
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.render-canvas {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
144
src/components/render/time-scale.vue
Normal file
144
src/components/render/time-scale.vue
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
<template>
|
||||||
|
<div class="time-scale-up-wrapper">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="time-scale-wrapper" :style="`left: ${currentX}px; width: ${300}px;`">
|
||||||
|
<div class="current-display-cursor-up">
|
||||||
|
<div class="time-scale-value">{{ currentX }} {{ timeScaleManage.unit }}</div>
|
||||||
|
<div class="time-scale-down"></div>
|
||||||
|
</div>
|
||||||
|
<div class="time-scale-line"></div>
|
||||||
|
<div class="current-display-cursor-down">
|
||||||
|
<div class="time-scale-value">{{ currentX }} {{ timeScaleManage.unit }}</div>
|
||||||
|
<div class="time-scale-up"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="time-scale-down-wrapper">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { onMounted, reactive } from 'vue';
|
||||||
|
import { globalLookup, emitter } from '@/hook/global';
|
||||||
|
import { handleTimeScale } from '@/hook/utils';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'time-scale',
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
// see --sidebar-width
|
||||||
|
const left = 280 + 20;
|
||||||
|
|
||||||
|
// see --right-nav-width
|
||||||
|
const right = document.body.clientWidth - 60;
|
||||||
|
|
||||||
|
const timeScaleManage = reactive({
|
||||||
|
scale: 1,
|
||||||
|
unit: 'ns'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 此时有关波形的元信息已经加载完毕
|
||||||
|
emitter.on('meta-ready', () => {
|
||||||
|
const { scale, unit } = handleTimeScale(globalLookup.timescale);
|
||||||
|
timeScaleManage.scale = scale;
|
||||||
|
timeScaleManage.unit = unit;
|
||||||
|
|
||||||
|
console.log(timeScaleManage.unit);
|
||||||
|
|
||||||
|
const viewInfo = globalLookup.view;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('wheel', event => {
|
||||||
|
if ((event.wheelDelta && event.ctrlKey) || event.detail) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.ctrlKey) {
|
||||||
|
// console.log(event.wheelDelta);
|
||||||
|
console.log('deltaX', event.deltaX);
|
||||||
|
console.log('deltaY', event.deltaY);
|
||||||
|
} else if (event.shiftKey) {
|
||||||
|
// console.log(event.wheelDelta);
|
||||||
|
console.log('deltaX', event.deltaX);
|
||||||
|
console.log('deltaY', event.deltaY);
|
||||||
|
}
|
||||||
|
}, { capture: false, passive: false });
|
||||||
|
|
||||||
|
|
||||||
|
const currentX = 300;
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentX,
|
||||||
|
timeScaleManage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.time-scale-up-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: calc(var(--sidebar-width) + 20px);
|
||||||
|
width: calc(100vw - var(--sidebar-width) - var(--right-nav-width) - 20px);
|
||||||
|
height: var(--time-scale-height);
|
||||||
|
background-color: var(--sidebar);
|
||||||
|
z-index: 50;
|
||||||
|
cursor: crosshair;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-scale-down-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: calc(100vw - var(--right-nav-width));
|
||||||
|
height: var(--time-scale-height);
|
||||||
|
background-color: var(--sidebar);
|
||||||
|
z-index: 50;
|
||||||
|
cursor: crosshair;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-scale-down {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 1px;
|
||||||
|
height: 10px;
|
||||||
|
border: 1px solid var(--scrollbar-hover);
|
||||||
|
background-color: var(--scrollbar-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-scale-up {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 1px;
|
||||||
|
height: 10px;
|
||||||
|
border: 1px solid var(--scrollbar-hover);
|
||||||
|
background-color: var(--scrollbar-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-scale-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
height: 100vh;
|
||||||
|
padding: 0;
|
||||||
|
top: 0;
|
||||||
|
cursor: crosshair;
|
||||||
|
z-index: 55;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
/* 沿着横轴(水平方向)对齐 */
|
||||||
|
justify-content: center;
|
||||||
|
/* 沿着纵轴(垂直方向)对齐 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-scale-value {}
|
||||||
|
|
||||||
|
.time-scale-line {
|
||||||
|
width: 1px;
|
||||||
|
background-color: var(--scrollbar-hover);
|
||||||
|
height: calc(100vh - 2 * var(--time-scale-height));
|
||||||
|
}
|
||||||
|
</style>
|
@ -95,6 +95,7 @@ export default {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
z-index: 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vcd-function-panel {
|
.vcd-function-panel {
|
||||||
@ -107,12 +108,13 @@ export default {
|
|||||||
.vcd-function-option {
|
.vcd-function-option {
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
background-color: var(--sidebar);
|
||||||
box-shadow: 0 0 15px 1px rgb(16, 16, 16);
|
box-shadow: 0 0 15px 1px rgb(16, 16, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
.vcd-control-panel-wrapper {
|
.vcd-control-panel-wrapper {
|
||||||
width: 60px;
|
width: var(--right-nav-width);
|
||||||
height: 60px;
|
height: var(--right-nav-width);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
|
@ -18,11 +18,18 @@
|
|||||||
|
|
||||||
<div class="setting-option">
|
<div class="setting-option">
|
||||||
<span class="option-title">{{ t('search-scope') }}</span>
|
<span class="option-title">{{ t('search-scope') }}</span>
|
||||||
<el-checkbox-group v-model="globalSetting.searchScope" size="default">
|
<el-select
|
||||||
<el-checkbox-button label="wire" border>wire </el-checkbox-button>
|
v-model="globalSetting.searchScope"
|
||||||
<el-checkbox-button label="reg" border>reg </el-checkbox-button>
|
multiple
|
||||||
<el-checkbox-button label="module" border>module</el-checkbox-button>
|
collapse-tags
|
||||||
</el-checkbox-group>
|
collapse-tags-tooltip
|
||||||
|
placeholder="Select"
|
||||||
|
>
|
||||||
|
<el-option v-for="name in scopes" :key="name"
|
||||||
|
:label="name" :value="name" />
|
||||||
|
<el-option v-for="name in variables" :key="name"
|
||||||
|
:label="name" :value="name" />
|
||||||
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -69,7 +76,7 @@
|
|||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { globalSetting } from '@/hook/global';
|
import { globalSetting } from '@/hook/global';
|
||||||
import { debounceWrapper } from '@/hook/utils';
|
import { debounceWrapper, scopes, variables } from '@/hook/utils';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'dide-setting',
|
name: 'dide-setting',
|
||||||
@ -101,7 +108,9 @@ export default {
|
|||||||
languageSetting,
|
languageSetting,
|
||||||
globalSetting,
|
globalSetting,
|
||||||
safeModifySignalTrackHeight,
|
safeModifySignalTrackHeight,
|
||||||
locale
|
locale,
|
||||||
|
scopes,
|
||||||
|
variables
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="vcd-sidebar-wrapper">
|
<div class="vcd-sidebar-wrapper">
|
||||||
<div class="display-signal-wrapper">
|
<div class="display-signal-wrapper">
|
||||||
|
<div style="height: var(--time-scale-height);"></div>
|
||||||
<div class="display-signal-item"
|
<div class="display-signal-item"
|
||||||
v-for="(signal, index) in globalLookup.currentWires" :key="index">
|
v-for="(signal, index) in globalLookup.currentWires" :key="index">
|
||||||
<div class="signal-color-vendor">
|
<div class="signal-color-vendor">
|
||||||
@ -25,6 +26,7 @@
|
|||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { emitter, globalLookup, globalSetting } from '@/hook/global';
|
import { emitter, globalLookup, globalSetting } from '@/hook/global';
|
||||||
|
import { makeIconClass } from '@/hook/utils';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'sidebar',
|
name: 'sidebar',
|
||||||
@ -36,22 +38,9 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function makeSignalIconClass(signal) {
|
function makeSignalIconClass(signal) {
|
||||||
if (signal.type === 'wire') {
|
return 'iconfont ' + makeIconClass(signal);
|
||||||
return 'iconfont icon-wave-square';
|
|
||||||
} else if (signal.type === 'reg') {
|
|
||||||
return 'iconfont icon-register';
|
|
||||||
} else {
|
|
||||||
return 'iconfont icon-wave-square';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeSignalInfo(signal) {
|
|
||||||
let htmlString = '';
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
t,
|
t,
|
||||||
globalLookup,
|
globalLookup,
|
||||||
@ -67,10 +56,11 @@ export default {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
|
z-index: 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
.add-signal-button {
|
.add-signal-button {
|
||||||
margin: 10px;
|
margin-top: 10px;
|
||||||
padding: 10px 25px;
|
padding: 10px 25px;
|
||||||
background-color: var(--color-deepPurple);
|
background-color: var(--color-deepPurple);
|
||||||
border-radius: 0 0 .8em .8em;
|
border-radius: 0 0 .8em .8em;
|
||||||
@ -85,12 +75,11 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.display-signal-wrapper {
|
.display-signal-wrapper {
|
||||||
margin: 10px;
|
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
background-color: var(--sidebar);
|
background-color: var(--sidebar);
|
||||||
border: solid 1px var(--sidebar-border);
|
border: solid 1px var(--sidebar-border);
|
||||||
min-width: var(--sidebar-min-width);
|
min-width: var(--sidebar-width);
|
||||||
min-height: 50vh;
|
height: calc(100vh - 90px);
|
||||||
box-shadow: 0 0 15px 1px rgb(16, 16, 16);
|
box-shadow: 0 0 15px 1px rgb(16, 16, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ export default {
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.vcd-module-info {
|
.vcd-module-info {
|
||||||
width: 300px;
|
width: fit-content;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,8 +64,8 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.vcd-module-display-wrapper {
|
.vcd-module-display-wrapper {
|
||||||
height: 80vh;
|
height: 90vh;
|
||||||
overflow-x: scroll;
|
overflow: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vcd-treeview {
|
.vcd-treeview {
|
||||||
@ -82,7 +82,7 @@ export default {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
max-height: 98vh;
|
max-height: 99vh;
|
||||||
/* overflow: scroll; */
|
/* overflow: scroll; */
|
||||||
transition: flex .5s ease-in-out;
|
transition: flex .5s ease-in-out;
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<span class="module-tag-status" @click.stop="expandManage.click">
|
<span class="module-tag-status" @click.stop="expandManage.click">
|
||||||
<div :class="expandManage.expandTagClass"></div>
|
<div :class="expandManage.expandTagClass"></div>
|
||||||
</span>
|
</span>
|
||||||
<span class="iconfont icon-memory-chip"></span>
|
<span :class="`iconfont ${makeIconClass(module)}`"></span>
|
||||||
 {{ module.name }}
|
 {{ module.name }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -26,6 +26,7 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import { reactive, onMounted } from 'vue';
|
import { reactive, onMounted } from 'vue';
|
||||||
import { emitter, globalLookup } from '@/hook/global';
|
import { emitter, globalLookup } from '@/hook/global';
|
||||||
|
import { isScope, isVariable, makeIconClass } from '@/hook/utils';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "modules",
|
name: "modules",
|
||||||
@ -40,9 +41,9 @@ export default {
|
|||||||
const mods = [];
|
const mods = [];
|
||||||
|
|
||||||
for (const wire of module.body) {
|
for (const wire of module.body) {
|
||||||
if (wire.body) {
|
if (isScope(wire)) {
|
||||||
mods.push(wire);
|
mods.push(wire);
|
||||||
} else {
|
} else if (isVariable(wire)) {
|
||||||
signals.push(wire);
|
signals.push(wire);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,7 +52,7 @@ export default {
|
|||||||
emitter.emit('tree-view', signals);
|
emitter.emit('tree-view', signals);
|
||||||
// color change into selected
|
// color change into selected
|
||||||
globalLookup.currentModule = module;
|
globalLookup.currentModule = module;
|
||||||
|
console.log(module);
|
||||||
}
|
}
|
||||||
|
|
||||||
const expandManage = reactive({
|
const expandManage = reactive({
|
||||||
@ -68,10 +69,10 @@ export default {
|
|||||||
return {
|
return {
|
||||||
module,
|
module,
|
||||||
mods,
|
mods,
|
||||||
signals,
|
|
||||||
clickItem,
|
clickItem,
|
||||||
expandManage,
|
expandManage,
|
||||||
globalLookup
|
globalLookup,
|
||||||
|
makeIconClass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -97,6 +98,8 @@ export default {
|
|||||||
height: 27px;
|
height: 27px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vcd-treeview-item::selection {
|
.vcd-treeview-item::selection {
|
||||||
|
@ -12,13 +12,13 @@
|
|||||||
<div class="search-result-wrapper" v-if="searchManage.content.trim().length > 0">
|
<div class="search-result-wrapper" v-if="searchManage.content.trim().length > 0">
|
||||||
<div class="search-result">
|
<div class="search-result">
|
||||||
<div v-if="searchManage.searchResult.length > 0">
|
<div v-if="searchManage.searchResult.length > 0">
|
||||||
<div class="search-result-item"
|
<div v-for="(searchResult, index) in searchManage.searchResult"
|
||||||
v-for="(searchResult, index) in searchManage.searchResult"
|
:key="index"
|
||||||
:key="index"
|
:class="globalLookup.currentWires.has(searchResult.module) ? 'vcd-treeview-selected' : ''"
|
||||||
:class="globalLookup.currentWires.has(searchResult.module) ? 'vcd-treeview-selected' : ''"
|
@click="clickItem(searchResult.module)">
|
||||||
v-html="searchResult.htmlString"
|
<div v-html="searchResult.htmlString" class="search-result-item"></div>
|
||||||
@click="clickItem(searchResult.module)">
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
{{ t('search-nothing') }}
|
{{ t('search-nothing') }}
|
||||||
@ -76,6 +76,7 @@ export default {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function clickItem(signal) {
|
function clickItem(signal) {
|
||||||
|
console.log(signal);
|
||||||
if (!signal.link) {
|
if (!signal.link) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -108,6 +109,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.search-result-wrapper {
|
.search-result-wrapper {
|
||||||
|
position: absolute;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
background-color: var(--sidebar);
|
background-color: var(--sidebar);
|
||||||
@ -115,7 +117,6 @@ export default {
|
|||||||
color: var(--sidebar-item-text);
|
color: var(--sidebar-item-text);
|
||||||
border-radius: .5em;
|
border-radius: .5em;
|
||||||
min-width: 500px;
|
min-width: 500px;
|
||||||
position: absolute;
|
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +124,8 @@ export default {
|
|||||||
overflow-x: scroll;
|
overflow-x: scroll;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
max-height: 80vh;
|
max-height: 80vh;
|
||||||
|
max-width: 600px;
|
||||||
|
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +134,7 @@ export default {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
margin: 3px;
|
margin: 3px;
|
||||||
|
width: 800px;
|
||||||
padding-left: 3px;
|
padding-left: 3px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
@click="clickItem(signal)"
|
@click="clickItem(signal)"
|
||||||
class="vcd-signal-signal-item"
|
class="vcd-signal-signal-item"
|
||||||
:class="globalLookup.currentWires.has(signal) ? 'vcd-treeview-selected' : ''">
|
:class="globalLookup.currentWires.has(signal) ? 'vcd-treeview-selected' : ''">
|
||||||
<div><span class="iconfont icon-wave-square"></span> {{ signal.name }}</div>
|
<div><span :class="`iconfont ${makeIconClass(signal)}`"></span> {{ signal.name }}</div>
|
||||||
<div>
|
<div>
|
||||||
<div :class="signal.size > 1 ? 'vcd-signal-signal-caption' : ''">
|
<div :class="signal.size > 1 ? 'vcd-signal-signal-caption' : ''">
|
||||||
{{ makeSignalCaption(signal) }}
|
{{ makeSignalCaption(signal) }}
|
||||||
@ -23,6 +23,8 @@ import { reactive } from 'vue';
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { emitter, globalLookup } from '@/hook/global';
|
import { emitter, globalLookup } from '@/hook/global';
|
||||||
|
import { makeIconClass } from '@/hook/utils';
|
||||||
|
import { makeWaveCanvas, removeWaveCanvas } from '@/hook/render';
|
||||||
|
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
export default {
|
export default {
|
||||||
@ -37,7 +39,7 @@ export default {
|
|||||||
});
|
});
|
||||||
|
|
||||||
emitter.on('tree-view', sendWires => {
|
emitter.on('tree-view', sendWires => {
|
||||||
signals.content.length = 0;
|
signals.content = [];
|
||||||
signals.content = sendWires;
|
signals.content = sendWires;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -48,8 +50,10 @@ export default {
|
|||||||
function clickItem(signal) {
|
function clickItem(signal) {
|
||||||
if (globalLookup.currentWires.has(signal)) {
|
if (globalLookup.currentWires.has(signal)) {
|
||||||
globalLookup.currentWires.delete(signal);
|
globalLookup.currentWires.delete(signal);
|
||||||
|
removeWaveCanvas(signal);
|
||||||
} else {
|
} else {
|
||||||
globalLookup.currentWires.add(signal);
|
globalLookup.currentWires.add(signal);
|
||||||
|
makeWaveCanvas(signal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +62,8 @@ export default {
|
|||||||
clickItem,
|
clickItem,
|
||||||
globalLookup,
|
globalLookup,
|
||||||
makeSignalCaption,
|
makeSignalCaption,
|
||||||
t
|
t,
|
||||||
|
makeIconClass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,10 +78,34 @@ export default {
|
|||||||
color: var(--signal-default-color);
|
color: var(--signal-default-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-brackets {
|
||||||
|
color: #75BEDF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-register {
|
||||||
|
color:#885dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-integer {
|
||||||
|
color: #C76B3C;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-String {
|
||||||
|
color: #8CC265;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-R {
|
||||||
|
color: #5fb4d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-task- {
|
||||||
|
color: orange;
|
||||||
|
}
|
||||||
|
|
||||||
.vcd-signal-signals-display {
|
.vcd-signal-signals-display {
|
||||||
color: var(--sidebar-item-text);
|
color: var(--sidebar-item-text);
|
||||||
padding: 0px 8px;
|
padding: 0px 8px;
|
||||||
height: 80vh;
|
height: 90vh;
|
||||||
overflow-x: scroll;
|
overflow-x: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,16 @@ const globalLookup = reactive({
|
|||||||
// 初始时间,一般都是 0
|
// 初始时间,一般都是 0
|
||||||
t0: 0,
|
t0: 0,
|
||||||
|
|
||||||
|
// 当前视图的左上角的坐标
|
||||||
|
view : {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
gridGap: 300,
|
||||||
|
currentBaseUnit: 100,
|
||||||
|
currentX: 0,
|
||||||
|
currentScale: 1
|
||||||
|
},
|
||||||
|
|
||||||
initcurrentModule(module) {
|
initcurrentModule(module) {
|
||||||
if (this.currentModule === undefined && module) {
|
if (this.currentModule === undefined && module) {
|
||||||
this.currentModule = module;
|
this.currentModule = module;
|
||||||
@ -41,12 +51,17 @@ const globalSetting = reactive({
|
|||||||
displayParentOnly: false,
|
displayParentOnly: false,
|
||||||
displaySignalHeight: 50,
|
displaySignalHeight: 50,
|
||||||
searchMode: 'so', // so, mo, sm
|
searchMode: 'so', // so, mo, sm
|
||||||
searchScope: ['wire', 'reg'],
|
searchScope: ['wire', 'reg', 'integer'],
|
||||||
displaySignalInfoScope: ['width', 'parent'],
|
displaySignalInfoScope: ['width', 'parent'],
|
||||||
})
|
|
||||||
|
minGridWidth: 300
|
||||||
|
});
|
||||||
|
|
||||||
|
const signalValues = {};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
emitter,
|
emitter,
|
||||||
globalLookup,
|
globalLookup,
|
||||||
globalSetting
|
globalSetting,
|
||||||
|
signalValues
|
||||||
};
|
};
|
146
src/hook/render.js
Normal file
146
src/hook/render.js
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
import { globalLookup, globalSetting, signalValues } from "./global";
|
||||||
|
|
||||||
|
let mainRenderEl = null;
|
||||||
|
const canvasMap = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns {Element}
|
||||||
|
*/
|
||||||
|
function getMainRenderEl() {
|
||||||
|
if (!mainRenderEl) {
|
||||||
|
const el = document.querySelectorAll('.vcd-render-wrapper')[0];
|
||||||
|
if (el) {
|
||||||
|
mainRenderEl = el;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mainRenderEl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {{
|
||||||
|
* time: BigInt,
|
||||||
|
* cmd: number,
|
||||||
|
* value?: BigInt,
|
||||||
|
* mask?: BigInt
|
||||||
|
* }} dataItem
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function isBlocked(dataItem) {
|
||||||
|
const mask = dataItem.mask;
|
||||||
|
if (mask && mask === 1n) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (mask && mask === 0n) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mask === undefined && dataItem.cmd > 15) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{
|
||||||
|
* kind: 'var' | 'scope',
|
||||||
|
* type: 'wire' | 'reg' | 'module',
|
||||||
|
* name: string,
|
||||||
|
* size: number,
|
||||||
|
* link: string
|
||||||
|
* }} signal
|
||||||
|
*/
|
||||||
|
function makeWaveCanvas(signal) {
|
||||||
|
const mainRender = getMainRenderEl();
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.id = 'wave-' + signal.link;
|
||||||
|
canvas.className = 'render-canvas';
|
||||||
|
canvas.width = document.body.clientWidth;
|
||||||
|
canvas.height = globalSetting.displaySignalHeight;
|
||||||
|
|
||||||
|
mainRender.appendChild(canvas);
|
||||||
|
canvasMap[signal] = canvas;
|
||||||
|
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
const datas = signalValues[signal.link];
|
||||||
|
|
||||||
|
if (signal.size === 1) {
|
||||||
|
drawSimpleSignal(ctx, datas);
|
||||||
|
} else {
|
||||||
|
// adwa
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{
|
||||||
|
* kind: 'var' | 'scope',
|
||||||
|
* type: 'wire' | 'reg' | 'module',
|
||||||
|
* name: string,
|
||||||
|
* size: number,
|
||||||
|
* link: string
|
||||||
|
* }} signal
|
||||||
|
*/
|
||||||
|
function removeWaveCanvas(signal) {
|
||||||
|
const canvas = canvasMap[signal];
|
||||||
|
if (canvas instanceof HTMLCanvasElement) {
|
||||||
|
canvas.parentNode.removeChild(canvas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {CanvasRenderingContext2D} ctx
|
||||||
|
* @param {Array<{
|
||||||
|
* time: BigInt,
|
||||||
|
* cmd: number,
|
||||||
|
* value?: BigInt,
|
||||||
|
* mask?: BigInt
|
||||||
|
* }>} signals
|
||||||
|
*/
|
||||||
|
function drawSimpleSignal(ctx, signals) {
|
||||||
|
let last_data = null;
|
||||||
|
let last_x = 300;
|
||||||
|
ctx.lineWidth = 3;
|
||||||
|
ctx.lineJoin = 'round';
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
for (const data of signals) {
|
||||||
|
console.log(data);
|
||||||
|
if (last_data === null) {
|
||||||
|
last_data = data;
|
||||||
|
last_x = 300;
|
||||||
|
let last_y = Math.max((15 - last_data.cmd) * 30, 0) + 10;
|
||||||
|
ctx.moveTo(last_x, last_y);
|
||||||
|
} else {
|
||||||
|
// 高阻态
|
||||||
|
const start = last_data.time;
|
||||||
|
const end = data.time;
|
||||||
|
ctx.strokeStyle = isBlocked(last_data) ? 'rgb(224,108,117)' : 'rgb(10, 200, 10)';
|
||||||
|
|
||||||
|
let last_y = Math.max((15 - last_data.cmd) * 30, 0) + 10;
|
||||||
|
|
||||||
|
const duration = parseInt(end - start);
|
||||||
|
const current_x = last_x + 100;
|
||||||
|
|
||||||
|
console.log(current_x, last_y, duration);
|
||||||
|
ctx.lineTo(current_x, last_y);
|
||||||
|
|
||||||
|
if (last_data.cmd !== data.cmd) {
|
||||||
|
ctx.strokeStyle = isBlocked(data) ? 'rgb(224,108,117)' : 'rgb(10, 200, 10)';
|
||||||
|
let current_y = Math.max((15 - data.cmd) * 30, 0) + 10;
|
||||||
|
ctx.lineTo(current_x, current_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
last_data = data;
|
||||||
|
last_x = current_x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getMainRenderEl,
|
||||||
|
makeWaveCanvas,
|
||||||
|
removeWaveCanvas
|
||||||
|
}
|
@ -15,7 +15,7 @@ async function getVcdStream() {
|
|||||||
* @returns {Promise<Uint8Array>}
|
* @returns {Promise<Uint8Array>}
|
||||||
*/
|
*/
|
||||||
async function readVcdFile() {
|
async function readVcdFile() {
|
||||||
const response = await fetch('cpu.vcd');
|
const response = await fetch('test.vcd');
|
||||||
const blob = await response.blob();
|
const blob = await response.blob();
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@ -40,6 +40,40 @@ function debounceWrapper(fn, delay) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function makeIconClass(mod) {
|
||||||
|
switch (mod.type) {
|
||||||
|
case 'module': return 'icon-memory-chip';
|
||||||
|
case 'begin': return 'icon-brackets';
|
||||||
|
case 'fork': return 'icon-fork';
|
||||||
|
case 'function': return 'icon-Function';
|
||||||
|
case 'task': return 'icon-task-';
|
||||||
|
|
||||||
|
case 'event': return 'icon-prevent';
|
||||||
|
case 'integer': return 'icon-integer';
|
||||||
|
case 'parameter': return 'icon-parameter';
|
||||||
|
case 'real': return 'icon-R';
|
||||||
|
case 'realtime': return 'icon-wave-square';
|
||||||
|
case 'reg': return 'icon-register';
|
||||||
|
case 'supply0': return 'icon-wave-square';
|
||||||
|
case 'supply1': return 'icon-wave-square';
|
||||||
|
case 'time': return 'icon-wave-square';
|
||||||
|
case 'tri': return 'icon-wave-square';
|
||||||
|
case 'triand': return 'icon-wave-square';
|
||||||
|
case 'trior': return 'icon-wave-square';
|
||||||
|
case 'trireg': return 'icon-wave-square';
|
||||||
|
case 'tri0': return 'icon-wave-square';
|
||||||
|
case 'tri1': return 'icon-wave-square';
|
||||||
|
case 'wand': return 'icon-wave-square';
|
||||||
|
case 'wire': return 'icon-wave-square';
|
||||||
|
case 'wor': return 'icon-wave-square';
|
||||||
|
case 'string': return 'icon-String';
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param { string } searchString
|
* @param { string } searchString
|
||||||
* @param {{
|
* @param {{
|
||||||
@ -76,20 +110,27 @@ function makeSearchResultItem(searchString, module, searchScope, caseSensitivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
let htmlString = '';
|
let htmlString = '';
|
||||||
|
let depString = '';
|
||||||
|
let currentCounts = 0;
|
||||||
for (let i = deps.length - 1; i >= 0; -- i) {
|
for (let i = deps.length - 1; i >= 0; -- i) {
|
||||||
const mod = deps[i];
|
const mod = deps[i];
|
||||||
if (mod.type === 'module') {
|
// const displayName = mod.name.length > 6 ? mod.name.substring(0, 6) + '...' : mod.name;
|
||||||
htmlString += '<span class="iconfont icon-memory-chip"></span> ' + mod.name;
|
const iconClass = makeIconClass(mod);
|
||||||
} else {
|
const iconText = `<span class="iconfont ${iconClass}"></span> ${mod.name}`;
|
||||||
htmlString += '<span class="iconfont icon-wave-square"></span> ' + mod.name;
|
|
||||||
}
|
depString += iconText;
|
||||||
|
htmlString += iconText;
|
||||||
|
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
|
depString += '<br>';
|
||||||
htmlString += '<div class="dep-arrow"></div>';
|
htmlString += '<div class="dep-arrow"></div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
htmlString,
|
htmlString,
|
||||||
module
|
module,
|
||||||
|
depString
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,10 +138,49 @@ function makeSearchResultItem(searchString, module, searchScope, caseSensitivity
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} timescale
|
||||||
|
* @return {{
|
||||||
|
* scale: number,
|
||||||
|
* unit: string
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
function handleTimeScale(timescale) {
|
||||||
|
const match = timescale.match(/^(\d+)(.*)$/);
|
||||||
|
if (match.length === 3) {
|
||||||
|
const scale = parseInt(match[1]);
|
||||||
|
const unit = match[2];
|
||||||
|
return { scale, unit };
|
||||||
|
} else {
|
||||||
|
console.log('Error: fail to parse timescale ' + timescale);
|
||||||
|
return { scale: null, unit: null };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const scopes = new Set(['begin', 'fork', 'function', 'module', 'task']);
|
||||||
|
const variables = new Set(['event', 'integer', 'parameter', 'real', 'realtime', 'reg', 'supply0',
|
||||||
|
'supply1', 'time', 'tri', 'triand', 'trior', 'trireg', 'tri0', 'tri1',
|
||||||
|
'wand', 'wire', 'wor', 'string']);
|
||||||
|
|
||||||
|
function isScope(wire) {
|
||||||
|
return scopes.has(wire.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isVariable(wire) {
|
||||||
|
return variables.has(wire.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getVcdStream,
|
getVcdStream,
|
||||||
readVcdFile,
|
readVcdFile,
|
||||||
debounceWrapper,
|
debounceWrapper,
|
||||||
makeSearchResultItem
|
makeSearchResultItem,
|
||||||
|
handleTimeScale,
|
||||||
|
isScope,
|
||||||
|
isVariable,
|
||||||
|
makeIconClass,
|
||||||
|
scopes,
|
||||||
|
variables
|
||||||
};
|
};
|
Loading…
x
Reference in New Issue
Block a user