Skip to content

feat(gsoc'24): Implemented state machine for simulator (#3781) #368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
13 changes: 13 additions & 0 deletions src/simulator/src/circuit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ export function changeCircuitName(name: string, id = globalScope.id) {
circuit_list.value[index].name = name
}

type State = 'normal' | 'error'

/**
* Class representing a Scope
* @class
Expand Down Expand Up @@ -305,6 +307,8 @@ export default class Scope {
Splitter?: any[];
SubCircuit?: any[];
Clock?: any[];
states: { NORMAL: State; ERROR: State; };
currentState: State;
constructor(name = 'localScope', id = undefined) {
this.restrictedCircuitElementsUsed = []
this.id = id || Math.floor(Math.random() * 100000000000 + 1)
Expand Down Expand Up @@ -340,6 +344,15 @@ export default class Scope {
title_y: 13,
titleEnabled: true,
}

// Defining all the possible states of simulator
this.states = {
NORMAL: 'normal',
ERROR: 'error',
};

// Setting current state of simulator
this.currentState = this.states.NORMAL;
}

isVisible() {
Expand Down
5 changes: 4 additions & 1 deletion src/simulator/src/data/undo.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { layoutModeGet } from '../layoutMode'
import Scope, { scopeList } from '../circuit'
import { loadScope } from './load'
import { updateRestrictedElementsInScope } from '../restrictedElementDiv'
import { forceResetNodesSet } from '../engine'
import { errorDetectedSet, forceResetNodesSet } from '../engine';
/**
* Function called to generate a prompt to save an image
* @param {Scope=} - the circuit in which we want to call undo
Expand Down Expand Up @@ -38,6 +38,9 @@ export default function undo(scope = globalScope) {
tempScope.name = scope.name
tempScope.testbenchData = scope.testbenchData
scopeList[scope.id] = tempScope
if (globalScope.currentState === globalScope.states.ERROR) {
errorDetectedSet(false);
}
globalScope = tempScope
globalScope.ox = backupOx
globalScope.oy = backupOy
Expand Down
93 changes: 53 additions & 40 deletions src/simulator/src/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { resetup } from './setup'
import { verilogModeGet } from './Verilog2CV'
import { renderOrder, updateOrder } from './metadata'
import ContentionPendingData from './contention';
import { hidetabs, visibletabs } from './listeners';

/**
* Core of the simulation and rendering algorithm.
Expand Down Expand Up @@ -401,53 +402,65 @@ export function updateSelectionsAndPane(scope = globalScope) {
* @category engine
*/
export function play(scope = globalScope, resetNodes = false) {
if (errorDetected) return // Don't simulate until error is fixed
if (loading === true) return // Don't simulate until loaded

simulationArea.simulationQueue.reset()
plotArea.setExecutionTime() // Waveform thing
resetNodeHighlights(scope);
// Reset Nodes if required
if (resetNodes || forceResetNodes) {
scope.reset()
simulationArea.simulationQueue.reset()
forceResetNodesSet(false)
}
try {
if (errorDetected) return; // Don't simulate until error is fixed
if (loading === true) return; // Don't simulate until loaded

simulationArea.simulationQueue.reset();
plotArea.setExecutionTime(); // Waveform thing
resetNodeHighlights(scope);
// Reset Nodes if required
if (resetNodes || forceResetNodes) {
scope.reset();
simulationArea.simulationQueue.reset();
forceResetNodesSet(false);
}

// To store set of Nodes that have shown contention but kept temporarily
// To store set of Nodes that have shown contention but kept temporarily
simulationArea.contentionPending = new ContentionPendingData();
// add inputs to the simulation queue
scope.addInputs()
// to check if we have infinite loop in circuit
let stepCount = 0
let elem
while (!simulationArea.simulationQueue.isEmpty()) {
if (errorDetected) {
simulationArea.simulationQueue.reset()
return
}
elem = simulationArea.simulationQueue.pop()
// add inputs to the simulation queue
scope.addInputs();
// to check if we have infinite loop in circuit
let stepCount = 0;
let elem;
while (!simulationArea.simulationQueue.isEmpty()) {
if (errorDetected) {
simulationArea.simulationQueue.reset();
return;
}
elem = simulationArea.simulationQueue.pop();

elem.resolve()
elem.resolve();

stepCount++
if (stepCount > 1000000) {
// Cyclic or infinite Circuit Detection
showError(
'Simulation Stack limit exceeded: maybe due to cyclic paths or contention'
)
forceResetNodesSet(true)
}
}
// Check for Contentions
if (simulationArea.contentionPending.size() > 0) {
for (const [ourNode, theirNode] of simulationArea.contentionPending.nodes()) {
ourNode.highlighted = true;
theirNode.highlighted = true;
stepCount++;
if (stepCount > 1000000) { // Cyclic or infinite Circuit Detection
showError('Simulation Stack limit exceeded: maybe due to cyclic paths or contention');
forceResetNodesSet(true);
}
}
// Check for Contentions
if (simulationArea.contentionPending.size() > 0) {
for (const [ourNode, theirNode] of simulationArea.contentionPending.nodes()) {
ourNode.highlighted = true;
theirNode.highlighted = true;
}

forceResetNodesSet(true);
forceResetNodesSet(true);
showError('Contention Error: One or more bus contentions in the circuit (check highlighted nodes)');
}

// change the state of simulator to normal
if (globalScope.currentState === globalScope.states.ERROR) {
globalScope.currentState = globalScope.states.NORMAL;
}
visibletabs();
} catch (error) {
// change the state of simulator to error
if (globalScope.currentState === globalScope.states.NORMAL) {
globalScope.currentState = globalScope.states.ERROR;
hidetabs();
}
showError('The simulator is in an error state. Now, you can only delete or undo components until the simulator returns to the normal state');
}
}

Expand Down
32 changes: 32 additions & 0 deletions src/simulator/src/listeners.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,38 @@ import { setupTimingListeners } from './plotArea'
var unit = 10
var listenToSimulator = true

function setPanelVisibility(visibility, display) {
if (window.screen.width < 1000) {
$('#touchMenu').toggle(visibility === 'visible');
$('#smallNavbarMenu-btn').toggle(visibility === 'visible');
}
else {
const classes = ['draggable-panel', 'nav-dropdown', 'logixButton'];
classes.forEach((className) => {
$(`.${className}`).each((index, element) => {
if (className === 'logixButton') {
$(element).toggle(visibility === 'visible');
$(element).parent().toggle(visibility === 'visible');
} else {
$(element).css('visibility', visibility);
}
});
});
}
var contextMenuItems = $("#contextMenu li:nth-child(1), #contextMenu li:nth-child(2), #contextMenu li:nth-child(3), #contextMenu li:nth-child(6), #contextMenu li:nth-child(7), #contextMenu li:nth-child(8)");
contextMenuItems.css("display", display);
}

// Function to hide tabs when simulator goes into error state
export function hidetabs() {
setPanelVisibility('hidden', 'none');
}

// Function to visible tabs when simulator returns back to normal state
export function visibletabs() {
setPanelVisibility('visible', 'block');
}

export default function startListeners() {
$(document).on('keyup', (e) => {
if (e.key === 'Escape') exitFullView()
Expand Down
7 changes: 6 additions & 1 deletion src/simulator/src/ux.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { layoutModeGet } from './layoutMode'
import {
scheduleUpdate,
wireToBeCheckedSet,
updateCanvasSet
updateCanvasSet,
errorDetectedSet
} from './engine'
import { simulationArea } from './simulationArea'
import logixFunction from './data'
Expand Down Expand Up @@ -289,6 +290,10 @@ export function deleteSelected() {
updateCanvasSet(true)
scheduleUpdate()
updateRestrictedElementsInScope()

if (globalScope.currentState === globalScope.states.ERROR) {
errorDetectedSet(false);
}
}

/**
Expand Down
Loading