Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -259,4 +259,5 @@ type SimulatorStateType = {
}
</style>

<!-- TODO: add type to scopeList and fix clock timer and clock enable and lite mode (crashing with continuous resetup() calls) -->
<!-- TODO: add type to scopeList -->
<!-- Note: Clock timer and clock enable crash issue fixed with debouncing in ux.js -->
2 changes: 0 additions & 2 deletions src/components/Panels/Shared/InputGroups.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ function increaseValue() {
step = isNaN(step) ? 1 : step
if (value + step <= props.valueMax) value = value + step
else return
props.propertyValue = value
ele.value = value
// manually triggering on change event
const e = new Event('change')
Expand All @@ -72,7 +71,6 @@ function decreaseValue() {
step = isNaN(step) ? 1 : step
if (value - step >= props.valueMin) value = value - step
else return
props.propertyValue = value
ele.value = value
// manually triggering on change event
const e = new Event('change')
Expand Down
33 changes: 14 additions & 19 deletions src/simulator/src/data/load.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,25 +84,11 @@ function loadModule(data, scope) {
}

/**
* This function shouldn't ideally exist. But temporary fix
* for some issues while loading nodes.
* @deprecated This function has been removed as the root cause has been fixed.
* Nodes are now loaded correctly and orphaned nodes are cleaned up properly.
* The removeBugNodes() workaround is no longer needed.
* @category data
*/
function removeBugNodes(scope = globalScope) {
let x = scope.allNodes.length
for (let i = 0; i < x; i++) {
if (
scope.allNodes[i].type !== 2 &&
scope.allNodes[i].parent.objectType === 'CircuitElement'
) {
scope.allNodes[i].delete()
}
if (scope.allNodes.length !== x) {
i = 0
x = scope.allNodes.length
}
}
}

/**
* Function to load a full circuit
Expand All @@ -114,7 +100,7 @@ export function loadScope(scope, data) {
const ML = moduleList.slice() // Module List copy
scope.restrictedCircuitElementsUsed = data.restrictedCircuitElementsUsed

// Load all nodes
// Load all nodes first (required for replace() to work with correct indices)
data.allNodes.map((x) => loadNode(x, scope))

// Make all connections
Expand All @@ -137,11 +123,20 @@ export function loadScope(scope, data) {
}
}
}

// Clean up orphaned input/output nodes that weren't properly replaced
// Delete inline during reverse iteration to avoid index staling (delete() reassigns scope.allNodes)
for (let i = scope.allNodes.length - 1; i >= 0; i--) {
const node = scope.allNodes[i]
if (node.type !== 2 && node.parent === scope.root) {
node.delete()
}
}

// Update wires according
scope.wires.map((x) => {
x.updateData(scope)
})
removeBugNodes(scope) // To be deprecated

// If Verilog Circuit Metadata exists, then restore
if (data.verilogMetadata) {
Expand Down
58 changes: 57 additions & 1 deletion src/simulator/src/ux.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ var ctxPos = {
}
let isFullViewActive = false
let prevMobileState = null

// Debounce timers for clock properties to prevent excessive updates
let clockTimeDebounceTimer = null
let clockEnableDebounceTimer = null
const DEBOUNCE_DELAY = 300 // milliseconds
// FUNCTION TO SHOW AND HIDE CONTEXT MENU
function hideContextMenu() {
var el = document.getElementById('contextMenu')
Expand Down Expand Up @@ -184,6 +189,33 @@ function checkValidBitWidth() {
}

export function objectPropertyAttributeUpdate() {
const propertyName = this.name

// Special handling for clock time - debounce and skip heavy updates
// Clock time changes don't require canvas resets, only interval updates
if (propertyName === 'changeClockTime') {
if (clockTimeDebounceTimer) {
clearTimeout(clockTimeDebounceTimer)
}

clockTimeDebounceTimer = setTimeout(() => {
checkValidBitWidth()
let { value } = this
if (this.type === 'number') {
value = parseFloat(value)
}
// Only update clock time, skip canvas updates to prevent crashes
if (simulationArea.lastSelected && simulationArea.lastSelected[propertyName]) {
simulationArea.lastSelected[propertyName](value)
} else {
circuitProperty[propertyName](value)
}
clockTimeDebounceTimer = null
}, DEBOUNCE_DELAY)
return
}

// Default behavior for other properties
checkValidBitWidth()
scheduleUpdate()
updateCanvasSet(true)
Expand All @@ -200,7 +232,31 @@ export function objectPropertyAttributeUpdate() {
}

export function objectPropertyAttributeCheckedUpdate() {
if (this.name === 'toggleLabelInLayoutMode') return // Hack to prevent toggleLabelInLayoutMode from toggling twice
const propertyName = this.name

// Hack to prevent toggleLabelInLayoutMode from toggling twice
if (propertyName === 'toggleLabelInLayoutMode') return

// Special handling for clock enable - debounce and skip heavy updates
// Clock enable changes don't require canvas resets, only state updates
if (propertyName === 'changeClockEnable') {
if (clockEnableDebounceTimer) {
clearTimeout(clockEnableDebounceTimer)
}

clockEnableDebounceTimer = setTimeout(() => {
// Only update clock enable, skip canvas updates to prevent crashes
if (simulationArea.lastSelected && simulationArea.lastSelected[propertyName]) {
simulationArea.lastSelected[propertyName](this.checked)
} else {
circuitProperty[propertyName](this.checked)
}
clockEnableDebounceTimer = null
}, DEBOUNCE_DELAY)
return
}

// Default behavior for other properties
scheduleUpdate()
updateCanvasSet(true)
wireToBeCheckedSet(1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,4 +259,5 @@ type SimulatorStateType = {
}
</style>

<!-- TODO: add type to scopeList and fix clock timer and clock enable and lite mode (crashing with continuous resetup() calls) -->
<!-- TODO: add type to scopeList -->
<!-- Note: Clock timer and clock enable crash issue fixed with debouncing in ux.js -->
2 changes: 0 additions & 2 deletions v1/src/components/Panels/Shared/InputGroups.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ function increaseValue() {
step = isNaN(step) ? 1 : step
if (value + step <= props.valueMax) value = value + step
else return
props.propertyValue = value
ele.value = value
// manually triggering on change event
const e = new Event('change')
Expand All @@ -72,7 +71,6 @@ function decreaseValue() {
step = isNaN(step) ? 1 : step
if (value - step >= props.valueMin) value = value - step
else return
props.propertyValue = value
ele.value = value
// manually triggering on change event
const e = new Event('change')
Expand Down
29 changes: 11 additions & 18 deletions v1/src/simulator/src/data/load.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,25 +84,10 @@ function loadModule(data, scope) {
}

/**
* This function shouldn't ideally exist. But temporary fix
* for some issues while loading nodes.
* @deprecated This function has been removed as the root cause has been fixed.
* Nodes are now loaded correctly and orphaned nodes are cleaned up properly.
* @category data
*/
function removeBugNodes(scope = globalScope) {
let x = scope.allNodes.length
for (let i = 0; i < x; i++) {
if (
scope.allNodes[i].type !== 2 &&
scope.allNodes[i].parent.objectType === 'CircuitElement'
) {
scope.allNodes[i].delete()
}
if (scope.allNodes.length !== x) {
i = 0
x = scope.allNodes.length
}
}
}

/**
* Function to load a full circuit
Expand Down Expand Up @@ -137,11 +122,19 @@ export function loadScope(scope, data) {
}
}
}
// Clean up orphaned input/output nodes that weren't properly replaced
// Delete inline during reverse iteration to avoid index staling (delete() reassigns scope.allNodes)
for (let i = scope.allNodes.length - 1; i >= 0; i--) {
const node = scope.allNodes[i]
if (node.type !== 2 && node.parent === scope.root) {
node.delete()
}
}

// Update wires according
scope.wires.map((x) => {
x.updateData(scope)
})
removeBugNodes(scope) // To be deprecated

// If Verilog Circuit Metadata exists, then restore
if (data.verilogMetadata) {
Expand Down
60 changes: 58 additions & 2 deletions v1/src/simulator/src/ux.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ var ctxPos = {
visible: false,
}
let isFullViewActive = false
let prevMobileState = null
let prevMobileState = null

// Debounce timers for clock properties to prevent excessive updates
let clockTimeDebounceTimer = null
let clockEnableDebounceTimer = null
const DEBOUNCE_DELAY = 300 // milliseconds
// FUNCTION TO SHOW AND HIDE CONTEXT MENU
function hideContextMenu() {
var el = document.getElementById('contextMenu')
Expand Down Expand Up @@ -184,6 +189,33 @@ function checkValidBitWidth() {
}

export function objectPropertyAttributeUpdate() {
const propertyName = this.name

// Special handling for clock time - debounce and skip heavy updates
// Clock time changes don't require canvas resets, only interval updates
if (propertyName === 'changeClockTime') {
if (clockTimeDebounceTimer) {
clearTimeout(clockTimeDebounceTimer)
}

clockTimeDebounceTimer = setTimeout(() => {
checkValidBitWidth()
let { value } = this
if (this.type === 'number') {
value = parseFloat(value)
}
// Only update clock time, skip canvas updates to prevent crashes
if (simulationArea.lastSelected && simulationArea.lastSelected[propertyName]) {
simulationArea.lastSelected[propertyName](value)
} else {
circuitProperty[propertyName](value)
}
clockTimeDebounceTimer = null
}, DEBOUNCE_DELAY)
return
}

// Default behavior for other properties
checkValidBitWidth()
scheduleUpdate()
updateCanvasSet(true)
Expand All @@ -200,7 +232,31 @@ export function objectPropertyAttributeUpdate() {
}

export function objectPropertyAttributeCheckedUpdate() {
if (this.name === 'toggleLabelInLayoutMode') return // Hack to prevent toggleLabelInLayoutMode from toggling twice
const propertyName = this.name

// Hack to prevent toggleLabelInLayoutMode from toggling twice
if (propertyName === 'toggleLabelInLayoutMode') return

// Special handling for clock enable - debounce and skip heavy updates
// Clock enable changes don't require canvas resets, only state updates
if (propertyName === 'changeClockEnable') {
if (clockEnableDebounceTimer) {
clearTimeout(clockEnableDebounceTimer)
}

clockEnableDebounceTimer = setTimeout(() => {
// Only update clock enable, skip canvas updates to prevent crashes
if (simulationArea.lastSelected && simulationArea.lastSelected[propertyName]) {
simulationArea.lastSelected[propertyName](this.checked)
} else {
circuitProperty[propertyName](this.checked)
}
clockEnableDebounceTimer = null
}, DEBOUNCE_DELAY)
return
}

// Default behavior for other properties
scheduleUpdate()
updateCanvasSet(true)
wireToBeCheckedSet(1)
Expand Down