把前端从CircuitVerse中拆了出来
This commit is contained in:
commit
5bf1284599
2182 changed files with 189323 additions and 0 deletions
202
public/js/ram.js
Normal file
202
public/js/ram.js
Normal file
|
@ -0,0 +1,202 @@
|
|||
/**
|
||||
* RAM Component.
|
||||
*
|
||||
* Two settings are available:
|
||||
* - addressWidth: 1 to 20, default=10. Controls the width of the address input.
|
||||
* - bitWidth: 1 to 32, default=8. Controls the width of data pins.
|
||||
*
|
||||
* Amount of memory in the element is 2^addressWidth x bitWidth bits.
|
||||
* Minimum RAM size is: 2^1 x 1 = 2 bits.
|
||||
* Maximum RAM size is: 2^20 x 32 = 1M x 32 bits => 32 Mbits => 4MB.
|
||||
* Maximum 8-bits size: 2^20 x 8 = 1M x 8 bits => 1MB.
|
||||
* Default RAM size is: 2^10 x 8 = 1024 bytes => 1KB.
|
||||
*
|
||||
* RAMs are volatile therefore this component does not persist the memory contents.
|
||||
*
|
||||
* Changes to addressWidth and bitWidth also cause data to be lost.
|
||||
* Think of these operations as being equivalent to taking a piece of RAM out of a
|
||||
* circuit board and replacing it with another RAM of different size.
|
||||
*
|
||||
* The contents of the RAM can be reset to zero by setting the RESET pin 1 or
|
||||
* or by selecting the component and pressing the "Reset" button in the properties window.
|
||||
*
|
||||
* The contents of the RAM can be dumped to the console by transitioning CORE DUMP pin to 1
|
||||
* or by selecting the component and pressing the "Core Dump" button in the properties window.
|
||||
* Address spaces that have not been written will show up as `undefined` in the core dump.
|
||||
*
|
||||
* NOTE: The maximum address width of 20 is arbitrary.
|
||||
* Larger values are possible, but in practice circuits won't need this much
|
||||
* memory and keeping the value small helps avoid allocating too much memory on the browser.
|
||||
* Internally we use a sparse array, so only the addresses that are written are actually
|
||||
* allocated. Nevertheless, it is better to prevent large allocations from happening
|
||||
* by keeping the max addressWidth small. If needed, we can increase the max.
|
||||
*/
|
||||
function RAM(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 8, addressWidth = 10) {
|
||||
CircuitElement.call(this, x, y, scope, dir, Math.min(Math.max(1, bitWidth), 32));
|
||||
this.setDimensions(60, 40);
|
||||
|
||||
this.directionFixed = true;
|
||||
this.labelDirection = "UP";
|
||||
|
||||
this.addressWidth = Math.min(Math.max(1, addressWidth), this.maxAddressWidth);
|
||||
this.address = new Node(-this.leftDimensionX, -20, 0, this, this.addressWidth, "ADDRESS");
|
||||
this.dataIn = new Node(-this.leftDimensionX, 0, 0, this, this.bitWidth, "DATA IN");
|
||||
this.write = new Node(-this.leftDimensionX, 20, 0, this, 1, "WRITE");
|
||||
this.reset = new Node(0, this.downDimensionY, 0, this, 1, "RESET");
|
||||
this.coreDump = new Node(-20, this.downDimensionY, 0, this, 1, "CORE DUMP");
|
||||
this.dataOut = new Node(this.rightDimensionX, 0, 1, this, this.bitWidth, "DATA OUT");
|
||||
this.prevCoreDumpValue = undefined;
|
||||
|
||||
this.clearData()
|
||||
}
|
||||
RAM.prototype = Object.create(CircuitElement.prototype);
|
||||
RAM.prototype.tooltipText = "Random Access Memory";
|
||||
RAM.prototype.shortName = "RAM";
|
||||
RAM.prototype.maxAddressWidth = 20;
|
||||
RAM.prototype.constructor = RAM;
|
||||
RAM.prototype.helplink = "https://docs.circuitverse.org/#/memoryElements?id=ram";
|
||||
RAM.prototype.mutableProperties = {
|
||||
"addressWidth": {
|
||||
name: "Address Width",
|
||||
type: "number",
|
||||
max: "20",
|
||||
min: "1",
|
||||
func: "changeAddressWidth",
|
||||
},
|
||||
"dump": {
|
||||
name: "Core Dump",
|
||||
type: "button",
|
||||
func: "dump",
|
||||
},
|
||||
"reset": {
|
||||
name: "Reset",
|
||||
type: "button",
|
||||
func: "clearData",
|
||||
},
|
||||
}
|
||||
RAM.prototype.customSave = function () {
|
||||
return {
|
||||
// NOTE: data is not persisted since RAMs are volatile.
|
||||
constructorParamaters: [this.direction, this.bitWidth, this.addressWidth],
|
||||
nodes: {
|
||||
address: findNode(this.address),
|
||||
dataIn: findNode(this.dataIn),
|
||||
write: findNode(this.write),
|
||||
reset: findNode(this.reset),
|
||||
coreDump: findNode(this.coreDump),
|
||||
dataOut: findNode(this.dataOut),
|
||||
},
|
||||
}
|
||||
}
|
||||
RAM.prototype.newBitWidth = function (value) {
|
||||
value = parseInt(value);
|
||||
if (!isNaN(value) && this.bitWidth != value && value >= 1 && value <= 32) {
|
||||
this.bitWidth = value;
|
||||
this.dataIn.bitWidth = value;
|
||||
this.dataOut.bitWidth = value;
|
||||
this.clearData();
|
||||
}
|
||||
}
|
||||
RAM.prototype.changeAddressWidth = function (value) {
|
||||
value = parseInt(value);
|
||||
if (!isNaN(value) && this.addressWidth != value && value >= 1 && value <= this.maxAddressWidth) {
|
||||
this.addressWidth = value;
|
||||
this.address.bitWidth = value;
|
||||
this.clearData();
|
||||
}
|
||||
}
|
||||
RAM.prototype.clearData = function () {
|
||||
this.data = new Array(Math.pow(2, this.addressWidth));
|
||||
this.tooltipText = this.memSizeString() + " " + this.shortName;
|
||||
}
|
||||
RAM.prototype.isResolvable = function () {
|
||||
return this.address.value !== undefined || this.reset.value !== undefined || this.coreDump.value !== undefined;
|
||||
}
|
||||
RAM.prototype.resolve = function () {
|
||||
if (this.write.value == 1) {
|
||||
this.data[this.address.value] = this.dataIn.value;
|
||||
}
|
||||
|
||||
if (this.reset.value == 1) {
|
||||
this.clearData();
|
||||
}
|
||||
|
||||
if (this.coreDump.value && this.prevCoreDumpValue != this.coreDump.value) {
|
||||
this.dump();
|
||||
}
|
||||
this.prevCoreDumpValue = this.coreDump.value;
|
||||
|
||||
this.dataOut.value = this.data[this.address.value] || 0;
|
||||
simulationArea.simulationQueue.add(this.dataOut);
|
||||
}
|
||||
RAM.prototype.customDraw = function () {
|
||||
var ctx = simulationArea.context;
|
||||
var xx = this.x;
|
||||
var yy = this.y;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = "gray";
|
||||
ctx.fillStyle = this.write.value ? "red" : "lightgreen";
|
||||
ctx.lineWidth = correctWidth(1);
|
||||
drawCircle2(ctx, 50, -30, 3, xx, yy, this.direction);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillStyle = "black";
|
||||
fillText4(ctx, this.memSizeString(), 0, -10, xx, yy, this.direction, 12);
|
||||
fillText4(ctx, this.shortName, 0, 10, xx, yy, this.direction, 12);
|
||||
fillText2(ctx, "A", this.address.x + 12, this.address.y, xx, yy, this.direction);
|
||||
fillText2(ctx, "DI", this.dataIn.x + 12, this.dataIn.y, xx, yy, this.direction);
|
||||
fillText2(ctx, "W", this.write.x + 12, this.write.y, xx, yy, this.direction);
|
||||
fillText2(ctx, "DO", this.dataOut.x - 15, this.dataOut.y, xx, yy, this.direction);
|
||||
ctx.fill();
|
||||
}
|
||||
RAM.prototype.memSizeString = function () {
|
||||
var mag = ['', 'K', 'M'];
|
||||
var unit = this.bitWidth == 8 ? "B" : this.bitWidth == 1 ? "b" : " x " + this.bitWidth + 'b';
|
||||
var v = Math.pow(2, this.addressWidth);
|
||||
var m = 0;
|
||||
while (v >= 1024 && m < mag.length - 1) {
|
||||
v /= 1024;
|
||||
m++;
|
||||
}
|
||||
return v + mag[m] + unit;
|
||||
}
|
||||
RAM.prototype.dump = function () {
|
||||
var logLabel = console.group && this.label;
|
||||
if (logLabel) {
|
||||
console.group(this.label);
|
||||
}
|
||||
|
||||
console.log(this.data)
|
||||
|
||||
if (logLabel) {
|
||||
console.groupEnd();
|
||||
}
|
||||
}
|
||||
//This is a RAM without a clock - not normal
|
||||
//reset is not supported
|
||||
RAM.moduleVerilog = function () {
|
||||
return `
|
||||
module RAM(dout, addr, din, we, dmp, rst);
|
||||
parameter WIDTH = 8;
|
||||
parameter ADDR = 10;
|
||||
output [WIDTH-1:0] dout;
|
||||
input [ADDR-1:0] addr;
|
||||
input [WIDTH-1:0] din;
|
||||
input we;
|
||||
input dmp;
|
||||
input rst;
|
||||
reg [WIDTH-1:0] mem [2**ADDR-1:0];
|
||||
|
||||
assign dout = mem[addr];
|
||||
|
||||
always @ (*) begin
|
||||
if (!we)
|
||||
mem[addr] = din;
|
||||
end
|
||||
endmodule
|
||||
`;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue