Comparing version 0.0.13 to 0.0.14
{ | ||
"name": "hdl-js", | ||
"version": "0.0.13", | ||
"version": "0.0.14", | ||
"license": "MIT", | ||
@@ -5,0 +5,0 @@ "description": "Hardware definition language (HDL) and Hardware simulator", |
@@ -75,2 +75,5 @@ /** | ||
// By default is not clocked. | ||
expect(halfAdder.getClass().isClocked()).toBe(false); | ||
expect(halfAdder.getInputPins()).toEqual([a, b]); | ||
@@ -77,0 +80,0 @@ expect(halfAdder.getOutputPins()).toEqual([sum, carry]); |
@@ -34,7 +34,26 @@ /** | ||
expect(gate.getOutputPins()).toEqual([out]); | ||
expect(gate.getClass()).toBe(Gate); | ||
// Abstract class. | ||
// Abstract `eval`. | ||
expect(() => gate.eval()).toThrow( | ||
'Abstract method `Gate#eval` should be implemented in a concrete class.' | ||
); | ||
// Abstract `isClocked`. | ||
expect(() => gate.getClass().isClocked()).toThrow( | ||
'Abstract static method `Gate.isClocked` should be implemented ' + | ||
'in a concrete class.' | ||
); | ||
// Abstract `clockUp`. | ||
expect(() => gate.clockUp()).toThrow( | ||
'Abstract method `Gate#clockUp` should be implemented ' + | ||
'in a concrete class.' | ||
); | ||
// Abstract `clockDown`. | ||
expect(() => gate.clockDown()).toThrow( | ||
'Abstract method `Gate#clockDown` should be implemented ' + | ||
'in a concrete class.' | ||
); | ||
}); | ||
@@ -233,2 +252,39 @@ | ||
it('tick-tock', () => { | ||
let state = 0; | ||
let order = []; | ||
// Clocked gate. | ||
class MyGate extends Gate { | ||
eval() { | ||
order.push('eval'); | ||
} | ||
clockUp() { | ||
order.push('clockUp'); | ||
state++; | ||
} | ||
clockDown() { | ||
order.push('clockDown'); | ||
this.getOutputPins()[0].setValue(state); | ||
} | ||
} | ||
const gate = new MyGate({ | ||
inputPins: ['in'], | ||
outputPins: ['out'], | ||
}); | ||
gate.tick(); | ||
expect(state).toBe(1); | ||
gate.tock(); | ||
expect(state).toBe(1); | ||
expect(gate.getPin('out').getValue()).toBe(state); | ||
expect(order).toEqual(['eval', 'clockUp', 'clockDown', 'eval']); | ||
}); | ||
}); |
@@ -46,3 +46,3 @@ /** | ||
// In JS implemenation doesn't differ from the simple `And` gate. | ||
// In JS implementation doesn't differ from the simple `And` gate. | ||
this.getOutputPins()[0].setValue(a & b); | ||
@@ -49,0 +49,0 @@ } |
@@ -46,3 +46,3 @@ /** | ||
// In JS implemenation doesn't differ from the simple `Or` gate. | ||
// In JS implementation doesn't differ from the simple `Or` gate. | ||
// Use 16-bit values with 0xFFFF mask. | ||
@@ -49,0 +49,0 @@ this.getOutputPins()[0].setValue((a | b) & 0xFFFF); |
@@ -60,3 +60,3 @@ /** | ||
_validatePins(pins, kind) { | ||
const spec = BuiltInGate.validateSpec(this.constructor.Spec); | ||
const spec = BuiltInGate.validateSpec(this.getClass().Spec); | ||
@@ -117,4 +117,30 @@ if (pins.length !== spec[kind].length) { | ||
} | ||
/** | ||
* Handler for the rising edge of the clock: updates internal state, | ||
* outputs are not updated ("latched"). | ||
*/ | ||
clockUp() { | ||
// Noop. | ||
return; | ||
} | ||
/** | ||
* Handler for the falling edge of the clock: commits the internal state, | ||
* values to the output. | ||
*/ | ||
clockDown() { | ||
// Noop. | ||
return; | ||
} | ||
/** | ||
* Whether this gate is clocked. | ||
*/ | ||
static isClocked() { | ||
// Child classes can override. | ||
return false; | ||
} | ||
} | ||
module.exports = BuiltInGate; |
@@ -57,4 +57,45 @@ /** | ||
} | ||
/** | ||
* Whether this gate is clocked. | ||
*/ | ||
static isClocked() { | ||
// This default value is overriden in the child classes | ||
// created from HDL files. | ||
return false; | ||
} | ||
/** | ||
* Handler for the rising edge of the clock: updates internal state, | ||
* outputs are not updated ("latched"). | ||
*/ | ||
clockUp() { | ||
if (!this.getClass().isClocked()) { | ||
throw new TypeError( | ||
`Gate#clockUp: "${this._name}" is not clocked.` | ||
); | ||
} | ||
for (const part of this._parts) { | ||
part.tick(); | ||
} | ||
} | ||
/** | ||
* Handler for the falling edge of the clock: commits the internal state, | ||
* values to the output. | ||
*/ | ||
clockDown() { | ||
if (!this.getClass().isClocked()) { | ||
throw new TypeError( | ||
`Gate#clockDown: "${this._name}" is not clocked.` | ||
); | ||
} | ||
for (const part of this._parts) { | ||
part.tock(); | ||
} | ||
} | ||
} | ||
module.exports = CompositeGate; |
@@ -30,3 +30,3 @@ /** | ||
if (!name) { | ||
name = this.constructor.name; | ||
name = this.getClass().name; | ||
} | ||
@@ -43,2 +43,11 @@ | ||
/** | ||
* Any extra initialization a gate may provide. Called at construction | ||
* and reset signal. | ||
*/ | ||
init() { | ||
// Noop. | ||
return; | ||
} | ||
/** | ||
* Returns the name of this gate. | ||
@@ -168,4 +177,10 @@ */ | ||
this.setPinValues(row); | ||
this.eval(); | ||
if (this.getClass().isClocked()) { | ||
this.tick(); | ||
this.tock(); | ||
} else { | ||
this.eval(); | ||
} | ||
const outputRow = {}; | ||
@@ -323,4 +338,65 @@ const conflictsForRow = {}; | ||
} | ||
/** | ||
* Updates the internal state of a clocked gate according to the gate's functionality. | ||
* (outputs are not updated). | ||
*/ | ||
clockUp() { | ||
throw new Error( | ||
'Abstract method `Gate#clockUp` should be implemented '+ | ||
'in a concrete class.' | ||
); | ||
} | ||
/** | ||
* Updates the outputs of the gate according to its internal state. | ||
*/ | ||
clockDown() { | ||
throw new Error( | ||
'Abstract method `Gate#clockDown` should be implemented '+ | ||
'in a concrete class.' | ||
); | ||
} | ||
/** | ||
* Returns a class object of this gate instance. | ||
*/ | ||
getClass() { | ||
return this.constructor; | ||
} | ||
/** | ||
* Whether this gate is clocked. | ||
*/ | ||
static isClocked() { | ||
throw new Error( | ||
'Abstract static method `Gate.isClocked` should be implemented '+ | ||
'in a concrete class.' | ||
); | ||
} | ||
/** | ||
* Clock rising edge. | ||
* | ||
* First computes the gate's output (from non-clocked information), and | ||
* then updates the internal state of the gate (which doesn't | ||
* affect the outputs). | ||
*/ | ||
tick() { | ||
this.eval(); | ||
this.clockUp(); | ||
} | ||
/** | ||
* Clock falling edge. | ||
* | ||
* First updates the gate's outputs according to the internal state | ||
* of the gate, and then computes the outputs from non-clocked information. | ||
*/ | ||
tock() { | ||
this.clockDown(); | ||
this.eval(); | ||
} | ||
} | ||
module.exports = Gate; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
135901
78
3644