CircuitOnline/public/js/subcircuit.js

411 lines
15 KiB
JavaScript

function loadSubCircuit(savedData, scope) {
var v = new SubCircuit(savedData["x"], savedData["y"], scope, savedData["id"], savedData);
// if(v.version == "1.0"){
// v.version = "2.0";
// v.x-=v.width/2;
// v.y-=v.height/2;
// }
}
//subCircuit class
function SubCircuit(x, y, scope = globalScope, id = undefined, savedData = undefined) {
this.id = id || prompt("Enter Id: ");
var subcircuitScope = scopeList[this.id]; // Scope of the subcircuit
// Error handing
if (subcircuitScope == undefined) {
showError("SubCircuit : " + ((savedData && savedData.title) || this.id) + " Not found");
} else if (!checkIfBackup(subcircuitScope)) {
showError("SubCircuit : " + ((savedData && savedData.title) || subcircuitScope.name) + " is an empty circuit");
} else if (subcircuitScope.checkDependency(scope.id)) {
showError("Cyclic Circuit Error");
}
// Error handling, cleanup
if (subcircuitScope == undefined || subcircuitScope.checkDependency(scope.id) || !checkIfBackup(subcircuitScope)) {
if (savedData) {
for (var i = 0; i < savedData["inputNodes"].length; i++) {
scope.allNodes[savedData["inputNodes"][i]].deleted = true;
}
for (var i = 0; i < savedData["outputNodes"].length; i++) {
scope.allNodes[savedData["outputNodes"][i]].deleted = true;
}
}
return;
}
CircuitElement.call(this, x, y, scope, "RIGHT", 1);
this.directionFixed = true;
this.fixedBitWidth = true;
this.savedData = savedData;
this.inputNodes = [];
this.outputNodes = [];
this.localScope = new Scope();
if (this.savedData != undefined) {
updateSubcircuit = true;
scheduleUpdate();
this.version = this.savedData["version"] || "1.0";
this.id = this.savedData["id"];
for (var i = 0; i < this.savedData["inputNodes"].length; i++) {
this.inputNodes.push(this.scope.allNodes[this.savedData["inputNodes"][i]]);
this.inputNodes[i].parent = this;
this.inputNodes[i].layout_id = subcircuitScope.Input[i].layoutProperties.id
}
for (var i = 0; i < this.savedData["outputNodes"].length; i++) {
this.outputNodes.push(this.scope.allNodes[this.savedData["outputNodes"][i]]);
this.outputNodes[i].parent = this;
this.outputNodes[i].layout_id = subcircuitScope.Output[i].layoutProperties.id;
}
if (this.version == "1.0") { // For backward compatibility
this.version = "2.0";
this.x -= subcircuitScope.layout.width / 2;
this.y -= subcircuitScope.layout.height / 2;
for (var i = 0; i < this.inputNodes.length; i++) {
this.inputNodes[i].x = subcircuitScope.Input[i].layoutProperties.x;
this.inputNodes[i].y = subcircuitScope.Input[i].layoutProperties.y;
this.inputNodes[i].leftx = this.inputNodes[i].x;
this.inputNodes[i].lefty = this.inputNodes[i].y;
}
for (var i = 0; i < this.outputNodes.length; i++) {
this.outputNodes[i].x = subcircuitScope.Output[i].layoutProperties.x;
this.outputNodes[i].y = subcircuitScope.Output[i].layoutProperties.y;
this.outputNodes[i].leftx = this.outputNodes[i].x;
this.outputNodes[i].lefty = this.outputNodes[i].y;
}
}
if (this.version == "2.0") {
this.leftDimensionX = 0;
this.upDimensionY = 0;
this.rightDimensionX = subcircuitScope.layout.width;
this.downDimensionY = subcircuitScope.layout.height;
}
this.nodeList.extend(this.inputNodes);
this.nodeList.extend(this.outputNodes);
} else {
this.version = "2.0";
}
this.data = JSON.parse(scheduleBackup(subcircuitScope));
this.buildCircuit();
this.makeConnections();
}
SubCircuit.prototype = Object.create(CircuitElement.prototype);
SubCircuit.prototype.constructor = SubCircuit;
SubCircuit.prototype.makeConnections = function() {
for (let i = 0; i < this.inputNodes.length; i++) {
this.localScope.Input[i].output1.connectWireLess(this.inputNodes[i]);
this.localScope.Input[i].output1.subcircuitOverride = true;
}
for (let i = 0; i < this.outputNodes.length; i++) {
this.localScope.Output[i].inp1.connectWireLess(this.outputNodes[i]);
this.outputNodes[i].subcircuitOverride = true;
}
}
SubCircuit.prototype.removeConnections = function() {
for (let i = 0; i < this.inputNodes.length; i++) {
this.localScope.Input[i].output1.disconnectWireLess(this.inputNodes[i]);
}
for (let i = 0; i < this.outputNodes.length; i++)
this.localScope.Output[i].inp1.disconnectWireLess(this.outputNodes[i]);
}
SubCircuit.prototype.buildCircuit = function() {
var subcircuitScope = scopeList[this.id];
loadScope(this.localScope, this.data);
this.lastUpdated = this.localScope.timeStamp;
updateSimulation = true;
updateCanvas = true;
if (this.savedData == undefined) {
this.leftDimensionX = 0;
this.upDimensionY = 0;
this.rightDimensionX = subcircuitScope.layout.width;
this.downDimensionY = subcircuitScope.layout.height;
for (var i = 0; i < subcircuitScope.Output.length; i++) {
var a = new Node(subcircuitScope.Output[i].layoutProperties.x, subcircuitScope.Output[i].layoutProperties.y, 1, this, subcircuitScope.Output[i].bitWidth);
a.layout_id = subcircuitScope.Output[i].layoutProperties.id;
this.outputNodes.push(a);
}
for (var i = 0; i < subcircuitScope.Input.length; i++) {
var a = new Node(subcircuitScope.Input[i].layoutProperties.x, subcircuitScope.Input[i].layoutProperties.y, 0, this, subcircuitScope.Input[i].bitWidth);
a.layout_id = subcircuitScope.Input[i].layoutProperties.id;
this.inputNodes.push(a);
}
}
}
// Needs to be deprecated, removed
SubCircuit.prototype.reBuild = function() {
return;
new SubCircuit(x = this.x, y = this.y, scope = this.scope, this.id)
this.scope.backups = []; // Because all previous states are invalid now
this.delete();
showMessage("Subcircuit: " + subcircuitScope.name + " has been reloaded.")
}
SubCircuit.prototype.reBuildCircuit = function() {
this.data = JSON.parse(scheduleBackup(scopeList[this.id]));
this.localScope = new Scope();
loadScope(this.localScope, this.data);
this.lastUpdated = this.localScope.timeStamp;
this.scope.timeStamp = this.localScope.timeStamp;
}
SubCircuit.prototype.reset = function() {
this.removeConnections();
var subcircuitScope = scopeList[this.id];
for (var i = 0; i < subcircuitScope.SubCircuit.length; i++) {
subcircuitScope.SubCircuit[i].reset();
}
if (subcircuitScope.Input.length == 0 && subcircuitScope.Output.length == 0) {
showError("SubCircuit : " + subcircuitScope.name + " is an empty circuit");
this.delete();
this.scope.backups = [];
return;
}
subcircuitScope.layout.height = subcircuitScope.layout.height;
subcircuitScope.layout.width = subcircuitScope.layout.width;
this.leftDimensionX = 0;
this.upDimensionY = 0;
this.rightDimensionX = subcircuitScope.layout.width;
this.downDimensionY = subcircuitScope.layout.height;
var temp_map_inp = {}
for (var i = 0; i < subcircuitScope.Input.length; i++) {
temp_map_inp[subcircuitScope.Input[i].layoutProperties.id] = [subcircuitScope.Input[i], undefined];
}
for (var i = 0; i < this.inputNodes.length; i++) {
if (temp_map_inp.hasOwnProperty(this.inputNodes[i].layout_id)) {
temp_map_inp[this.inputNodes[i].layout_id][1] = this.inputNodes[i];
} else {
this.scope.backups = [];
this.inputNodes[i].delete();
this.nodeList.clean(this.inputNodes[i])
}
}
for (id in temp_map_inp) {
if (temp_map_inp[id][1]) {
if (temp_map_inp[id][0].layoutProperties.x == temp_map_inp[id][1].x && temp_map_inp[id][0].layoutProperties.y == temp_map_inp[id][1].y)
temp_map_inp[id][1].bitWidth = temp_map_inp[id][0].bitWidth;
else {
this.scope.backups = [];
temp_map_inp[id][1].delete();
this.nodeList.clean(temp_map_inp[id][1]);
temp_map_inp[id][1] = new Node(temp_map_inp[id][0].layoutProperties.x, temp_map_inp[id][0].layoutProperties.y, 0, this, temp_map_inp[id][0].bitWidth)
temp_map_inp[id][1].layout_id = id;
}
}
}
this.inputNodes = []
for (var i = 0; i < subcircuitScope.Input.length; i++) {
var input = temp_map_inp[subcircuitScope.Input[i].layoutProperties.id][0]
if (temp_map_inp[input.layoutProperties.id][1])
this.inputNodes.push(temp_map_inp[input.layoutProperties.id][1])
else {
var a = new Node(input.layoutProperties.x, input.layoutProperties.y, 0, this, input.bitWidth);
a.layout_id = input.layoutProperties.id;
this.inputNodes.push(a);
}
}
var temp_map_out = {}
for (var i = 0; i < subcircuitScope.Output.length; i++) {
temp_map_out[subcircuitScope.Output[i].layoutProperties.id] = [subcircuitScope.Output[i], undefined];
}
for (var i = 0; i < this.outputNodes.length; i++) {
if (temp_map_out.hasOwnProperty(this.outputNodes[i].layout_id)) {
temp_map_out[this.outputNodes[i].layout_id][1] = this.outputNodes[i];
} else {
this.outputNodes[i].delete();
this.nodeList.clean(this.outputNodes[i])
}
}
for (id in temp_map_out) {
if (temp_map_out[id][1]) {
if (temp_map_out[id][0].layoutProperties.x == temp_map_out[id][1].x && temp_map_out[id][0].layoutProperties.y == temp_map_out[id][1].y)
temp_map_out[id][1].bitWidth = temp_map_out[id][0].bitWidth;
else {
temp_map_out[id][1].delete();
this.nodeList.clean(temp_map_out[id][1])
temp_map_out[id][1] = new Node(temp_map_out[id][0].layoutProperties.x, temp_map_out[id][0].layoutProperties.y, 1, this, temp_map_out[id][0].bitWidth)
temp_map_out[id][1].layout_id = id
}
}
}
this.outputNodes = []
for (var i = 0; i < subcircuitScope.Output.length; i++) {
var output = temp_map_out[subcircuitScope.Output[i].layoutProperties.id][0]
if (temp_map_out[output.layoutProperties.id][1])
this.outputNodes.push(temp_map_out[output.layoutProperties.id][1])
else {
var a = new Node(output.layoutProperties.x, output.layoutProperties.y, 1, this, output.bitWidth);
a.layout_id = output.layoutProperties.id;
this.outputNodes.push(a);
}
}
if (subcircuitScope.timeStamp > this.lastUpdated) {
this.reBuildCircuit();
}
this.localScope.reset();
this.makeConnections();
}
SubCircuit.prototype.click = function() {
// this.id=prompt();
}
SubCircuit.prototype.addInputs = function() {
for (let i = 0; i < subCircuitInputList.length; i++)
for (let j = 0; j < this.localScope[subCircuitInputList[i]].length; j++)
simulationArea.simulationQueue.add(this.localScope[subCircuitInputList[i]][j], 0)
for (let j = 0; j < this.localScope.SubCircuit.length; j++)
this.localScope.SubCircuit[j].addInputs();
}
SubCircuit.prototype.isResolvable = function() {
if (CircuitElement.prototype.isResolvable.call(this))
return true;
return false;
}
SubCircuit.prototype.dblclick = function() {
switchCircuit(this.id)
}
SubCircuit.prototype.saveObject = function() {
var data = {
x: this.x,
y: this.y,
id: this.id,
inputNodes: this.inputNodes.map(findNode),
outputNodes: this.outputNodes.map(findNode),
version: this.version,
}
return data;
}
SubCircuit.prototype.resolve = function() {
// deprecated
// var subcircuitScope = this.localScope;//scopeList[this.id];
// // this.scope.pending.clean(this); // To remove any pending instances
// // return;
//
// for (i = 0; i < subcircuitScope.Input.length; i++) {
// subcircuitScope.Input[i].state = this.inputNodes[i].value;
// }
//
// for (i = 0; i < subcircuitScope.Input.length; i++) {
// simulationArea.simulationQueue.add(subcircuitScope.Input[i]);
// }
// play(subcircuitScope);
//
// for (i = 0; i < subcircuitScope.Output.length; i++) {
// this.outputNodes[i].value = subcircuitScope.Output[i].inp1.value;
// }
// for (i = 0; i < subcircuitScope.Output.length; i++) {
// this.scope.stack.push(this.outputNodes[i]);
// }
}
SubCircuit.prototype.isResolvable = function() {
return false
}
SubCircuit.prototype.verilogName = function() {
return verilog.sanitizeLabel(scopeList[this.id].name);
}
SubCircuit.prototype.customDraw = function() {
var subcircuitScope = scopeList[this.id];
ctx = simulationArea.context;
ctx.lineWidth = globalScope.scale * 3;
ctx.strokeStyle = "black"; //("rgba(0,0,0,1)");
ctx.fillStyle = "white";
var xx = this.x;
var yy = this.y;
ctx.beginPath();
ctx.textAlign = "center";
ctx.fillStyle = "black";
if (this.version == "1.0")
fillText(ctx, subcircuitScope.name, xx, yy - subcircuitScope.layout.height / 2 + 13, 11);
else if (this.version == "2.0"){
if(subcircuitScope.layout.titleEnabled){
fillText(ctx, subcircuitScope.name, subcircuitScope.layout.title_x + xx, yy + subcircuitScope.layout.title_y, 11);
}
}
else
console.log(this.version)
for (var i = 0; i < subcircuitScope.Input.length; i++) {
if (!subcircuitScope.Input[i].label) continue;
var info = this.determine_label(this.inputNodes[i].x, this.inputNodes[i].y);
ctx.textAlign = info[0];
fillText(ctx, subcircuitScope.Input[i].label, this.inputNodes[i].x + info[1] + xx, yy + this.inputNodes[i].y + info[2], 12);
}
for (var i = 0; i < subcircuitScope.Output.length; i++) {
if (!subcircuitScope.Output[i].label) continue;
var info = this.determine_label(this.outputNodes[i].x, this.outputNodes[i].y);
ctx.textAlign = info[0];
fillText(ctx, subcircuitScope.Output[i].label, this.outputNodes[i].x + info[1] + xx, yy + this.outputNodes[i].y + info[2], 12);
}
ctx.fill();
for (var i = 0; i < this.inputNodes.length; i++)
this.inputNodes[i].draw();
for (var i = 0; i < this.outputNodes.length; i++)
this.outputNodes[i].draw();
}
SubCircuit.prototype.centerElement = true; // To center subcircuit when new
SubCircuit.prototype.determine_label = function(x, y) {
if (x == 0) return ["left", 5, 5]
if (x == scopeList[this.id].layout.width) return ["right", -5, 5]
if (y == 0) return ["center", 0, 13]
return ["center", 0, -6]
}