Web-Ide mit aufgenommen
This commit is contained in:
@@ -0,0 +1,910 @@
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
import { assertExists } from "@davidsouther/jiffies/lib/esm/assert.js";
|
||||
import { bin } from "../util/twos.js";
|
||||
import { And, Inc16, Mux16, Not, Not16, Or, Xor } from "./builtins/index.js";
|
||||
import { Nand } from "./builtins/logic/nand.js";
|
||||
import { Bit, PC, Register } from "./builtins/sequential/bit.js";
|
||||
import { DFF } from "./builtins/sequential/dff.js";
|
||||
import {
|
||||
Bus,
|
||||
Chip,
|
||||
ConstantBus,
|
||||
HIGH,
|
||||
InSubBus,
|
||||
LOW,
|
||||
OutSubBus,
|
||||
parseToPin,
|
||||
printChip,
|
||||
TRUE_BUS,
|
||||
} from "./chip.js";
|
||||
import { Clock } from "./clock.js";
|
||||
|
||||
describe("Chip", () => {
|
||||
it("parses toPin", () => {
|
||||
expect(parseToPin("a")).toMatchObject({ pin: "a" });
|
||||
expect(parseToPin("a[2]")).toMatchObject({ pin: "a", start: 2 });
|
||||
expect(parseToPin("a[2..4]")).toMatchObject({
|
||||
pin: "a",
|
||||
start: 2,
|
||||
end: 4,
|
||||
});
|
||||
});
|
||||
|
||||
describe("combinatorial", () => {
|
||||
describe("nand", () => {
|
||||
it("can eval a nand gate", () => {
|
||||
const nand = new Nand();
|
||||
nand.eval();
|
||||
expect(nand.out().voltage()).toBe(HIGH);
|
||||
|
||||
nand.in("a")?.pull(HIGH);
|
||||
nand.eval();
|
||||
expect(nand.out().voltage()).toBe(HIGH);
|
||||
|
||||
nand.in("b")?.pull(HIGH);
|
||||
nand.eval();
|
||||
expect(nand.out().voltage()).toBe(LOW);
|
||||
|
||||
nand.in("a")?.pull(LOW);
|
||||
nand.eval();
|
||||
expect(nand.out().voltage()).toBe(HIGH);
|
||||
});
|
||||
});
|
||||
|
||||
describe("not", () => {
|
||||
it("evaluates a not gate", () => {
|
||||
const notChip = new Not();
|
||||
|
||||
notChip.eval();
|
||||
expect(notChip.out().voltage()).toBe(HIGH);
|
||||
|
||||
notChip.in().pull(HIGH);
|
||||
notChip.eval();
|
||||
expect(notChip.out().voltage()).toBe(LOW);
|
||||
});
|
||||
});
|
||||
|
||||
describe("and", () => {
|
||||
it("evaluates an and gate", () => {
|
||||
const andChip = new And();
|
||||
|
||||
const a = assertExists(andChip.in("a"));
|
||||
const b = assertExists(andChip.in("b"));
|
||||
|
||||
andChip.eval();
|
||||
expect(andChip.out().voltage()).toBe(LOW);
|
||||
|
||||
a.pull(HIGH);
|
||||
andChip.eval();
|
||||
expect(andChip.out().voltage()).toBe(LOW);
|
||||
|
||||
b.pull(HIGH);
|
||||
andChip.eval();
|
||||
expect(andChip.out().voltage()).toBe(HIGH);
|
||||
|
||||
a.pull(LOW);
|
||||
andChip.eval();
|
||||
expect(andChip.out().voltage()).toBe(LOW);
|
||||
});
|
||||
});
|
||||
|
||||
describe("or", () => {
|
||||
it("evaluates an or gate", () => {
|
||||
const orChip = new Or();
|
||||
|
||||
const a = assertExists(orChip.in("a"));
|
||||
const b = assertExists(orChip.in("b"));
|
||||
|
||||
orChip.eval();
|
||||
expect(orChip.out().voltage()).toBe(LOW);
|
||||
|
||||
a.pull(HIGH);
|
||||
orChip.eval();
|
||||
printChip(orChip);
|
||||
expect(orChip.out().voltage()).toBe(HIGH);
|
||||
|
||||
b.pull(HIGH);
|
||||
orChip.eval();
|
||||
expect(orChip.out().voltage()).toBe(HIGH);
|
||||
|
||||
a.pull(LOW);
|
||||
orChip.eval();
|
||||
expect(orChip.out().voltage()).toBe(HIGH);
|
||||
});
|
||||
});
|
||||
|
||||
describe("xor", () => {
|
||||
it("evaluates an xor gate", () => {
|
||||
const xorChip = new Xor();
|
||||
|
||||
const a = assertExists(xorChip.in("a"));
|
||||
const b = assertExists(xorChip.in("b"));
|
||||
|
||||
xorChip.eval();
|
||||
expect(xorChip.out().voltage()).toBe(LOW);
|
||||
|
||||
a.pull(HIGH);
|
||||
xorChip.eval();
|
||||
expect(xorChip.out().voltage()).toBe(HIGH);
|
||||
|
||||
b.pull(HIGH);
|
||||
xorChip.eval();
|
||||
expect(xorChip.out().voltage()).toBe(LOW);
|
||||
|
||||
a.pull(LOW);
|
||||
xorChip.eval();
|
||||
expect(xorChip.out().voltage()).toBe(HIGH);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("wide", () => {
|
||||
describe("Not16", () => {
|
||||
it("evaluates a not16 gate", () => {
|
||||
const not16 = new Not16();
|
||||
|
||||
const inn = not16.in();
|
||||
|
||||
inn.busVoltage = 0x0;
|
||||
not16.eval();
|
||||
expect(not16.out().busVoltage).toBe(0xffff);
|
||||
|
||||
inn.busVoltage = 0xf00f;
|
||||
not16.eval();
|
||||
expect(not16.out().busVoltage).toBe(0x0ff0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("bus voltage", () => {
|
||||
it("sets and returns wide busses", () => {
|
||||
const pin = new Bus("wide", 16);
|
||||
pin.busVoltage = 0xf00f;
|
||||
expect(pin.voltage(0)).toBe(1);
|
||||
expect(pin.voltage(8)).toBe(0);
|
||||
expect(pin.voltage(9)).toBe(0);
|
||||
expect(pin.voltage(15)).toBe(1);
|
||||
expect(pin.busVoltage).toBe(0xf00f);
|
||||
});
|
||||
|
||||
it("creates wide busses internally", () => {
|
||||
const chip = new Chip([], [], "WithWide");
|
||||
|
||||
chip.wire(new Not16(), [
|
||||
{
|
||||
to: { name: "out", start: 0, width: 16 },
|
||||
from: { name: "a", start: 0, width: 16 },
|
||||
},
|
||||
]);
|
||||
|
||||
const width = chip.pins.get("a")?.width;
|
||||
expect(width).toBe(16);
|
||||
});
|
||||
});
|
||||
|
||||
describe("and16", () => undefined);
|
||||
});
|
||||
|
||||
describe("SubBus", () => {
|
||||
class Not3 extends Chip {
|
||||
constructor() {
|
||||
super(["in[3]"], ["out[3]"]);
|
||||
}
|
||||
|
||||
override eval() {
|
||||
const inn = this.in().busVoltage;
|
||||
const out = ~inn & 0b111;
|
||||
this.out().busVoltage = out;
|
||||
}
|
||||
}
|
||||
|
||||
it("drives OutSubBus", () => {
|
||||
const notChip = new Not();
|
||||
const inPin = new Bus("in", 3);
|
||||
const outSubBus = new OutSubBus(notChip.in(), 1, 1);
|
||||
inPin.connect(outSubBus);
|
||||
|
||||
inPin.busVoltage = 0b0;
|
||||
expect(notChip.in().busVoltage).toBe(0b0);
|
||||
inPin.busVoltage = 0b111;
|
||||
expect(notChip.in().busVoltage).toBe(0b1);
|
||||
});
|
||||
|
||||
it("wires SubBus in=in[1]", () => {
|
||||
const not3Chip = new Not3();
|
||||
const notPart = new Not();
|
||||
const inPin = not3Chip.in();
|
||||
|
||||
not3Chip.wire(notPart, [
|
||||
{
|
||||
from: { name: "in", start: 1, width: 1 },
|
||||
to: { name: "in", start: 0, width: 1 },
|
||||
},
|
||||
]);
|
||||
|
||||
inPin.busVoltage = 0b0;
|
||||
not3Chip.eval();
|
||||
expect(notPart.in().busVoltage).toBe(0b0);
|
||||
inPin.busVoltage = 0b111;
|
||||
not3Chip.eval();
|
||||
expect(notPart.in().busVoltage).toBe(0b1);
|
||||
});
|
||||
|
||||
it("wires SubBus in[0]=a", () => {
|
||||
const chip = new Chip(["a", "b"], ["out[3]"]);
|
||||
const not3 = new Not3();
|
||||
|
||||
// Not3(in[0]=a, in[1]=b, in[2]=b, out=out)
|
||||
chip.wire(not3, [
|
||||
{
|
||||
from: { name: "a", start: 0, width: undefined },
|
||||
to: { name: "in", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "b", start: 0, width: undefined },
|
||||
to: { name: "in", start: 1, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "b", start: 0, width: undefined },
|
||||
to: { name: "in", start: 2, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "out", start: 0, width: undefined },
|
||||
to: { name: "out", start: 0, width: undefined },
|
||||
},
|
||||
]);
|
||||
|
||||
assertExists(chip.in("b")).busVoltage = 1;
|
||||
assertExists(chip.in("a")).busVoltage = 0;
|
||||
chip.eval();
|
||||
expect(chip.out().busVoltage).toBe(0b001);
|
||||
});
|
||||
|
||||
it("wires SubBus out=out[1]", () => {
|
||||
const threeChip = new (class ThreeChip extends Chip {
|
||||
constructor() {
|
||||
super([], ["out[3]"]);
|
||||
}
|
||||
})();
|
||||
|
||||
const notPart = new Not();
|
||||
threeChip.wire(notPart, [
|
||||
{
|
||||
from: { name: "out", start: 1, width: 1 },
|
||||
to: { name: "out", start: 0, width: 1 },
|
||||
},
|
||||
]);
|
||||
const outPin = notPart.out();
|
||||
|
||||
outPin.busVoltage = 0b0;
|
||||
expect(threeChip.out().busVoltage).toBe(0b0);
|
||||
outPin.busVoltage = 0b1;
|
||||
expect(threeChip.out().busVoltage).toBe(0b010);
|
||||
});
|
||||
|
||||
it("widens output busses if necessary", () => {
|
||||
const mux4way16 = new Chip(
|
||||
["in[16]", "b[16]", "c[16]", "d[16]", "sel[2]"],
|
||||
["out[16]"],
|
||||
);
|
||||
|
||||
mux4way16.wire(new Mux16(), [
|
||||
{
|
||||
from: { name: "a", start: 0 },
|
||||
to: { name: "a", start: 0 },
|
||||
},
|
||||
{
|
||||
from: { name: "b", start: 0 },
|
||||
to: { name: "b", start: 0 },
|
||||
},
|
||||
{
|
||||
from: { name: "sel", start: 0, width: 1 },
|
||||
to: { name: "sel", start: 0 },
|
||||
},
|
||||
{
|
||||
from: { name: "out1", start: 0 },
|
||||
to: { name: "out", start: 0 },
|
||||
},
|
||||
]);
|
||||
|
||||
mux4way16.wire(new Mux16(), [
|
||||
{
|
||||
from: { name: "c", start: 0 },
|
||||
to: { name: "a", start: 0 },
|
||||
},
|
||||
{
|
||||
from: { name: "d", start: 0 },
|
||||
to: { name: "b", start: 0 },
|
||||
},
|
||||
{
|
||||
from: { name: "sel", start: 0, width: 1 },
|
||||
to: { name: "sel", start: 0 },
|
||||
},
|
||||
{
|
||||
from: { name: "out2", start: 0 },
|
||||
to: { name: "out", start: 0 },
|
||||
},
|
||||
]);
|
||||
|
||||
mux4way16.wire(new Mux16(), [
|
||||
{
|
||||
from: { name: "out1", start: 0 },
|
||||
to: { name: "a", start: 0 },
|
||||
},
|
||||
{
|
||||
from: { name: "out2", start: 0 },
|
||||
to: { name: "b", start: 0 },
|
||||
},
|
||||
{
|
||||
from: { name: "sel", start: 1, width: 1 },
|
||||
to: { name: "sel", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "out", start: 0, width: 1 },
|
||||
to: { name: "out", start: 0, width: 1 },
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("widens internal busses if necessary", () => {
|
||||
const chip = new Chip(["in"], [], "test", ["t"]);
|
||||
|
||||
chip.wire(new Not(), [
|
||||
{
|
||||
from: { name: "in", start: 0, width: 1 },
|
||||
to: { name: "in", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "t", start: 1, width: 1 },
|
||||
to: { name: "out", start: 0, width: 1 },
|
||||
},
|
||||
]);
|
||||
|
||||
chip.in().busVoltage = 0b0;
|
||||
chip.eval();
|
||||
expect(chip.pin("t").busVoltage).toBe(0b10);
|
||||
});
|
||||
|
||||
class Not8 extends Chip {
|
||||
constructor() {
|
||||
super(["in[8]"], ["out[8]"]);
|
||||
}
|
||||
|
||||
override eval() {
|
||||
const inn = this.in().busVoltage;
|
||||
const out = ~inn & 0xff;
|
||||
this.out().busVoltage = out;
|
||||
}
|
||||
}
|
||||
|
||||
it("assigns input inside wide busses", () => {
|
||||
class Foo extends Chip {
|
||||
readonly not8 = new Not8();
|
||||
constructor() {
|
||||
super([], []);
|
||||
this.parts.push(this.not8);
|
||||
this.pins.insert(new ConstantBus("pal", 0b1010_1100_0011_0101));
|
||||
this.pins.get("pal")?.connect(new OutSubBus(this.not8.in(), 4, 8));
|
||||
this.pins.emplace("out1", 5);
|
||||
const out1Bus = new OutSubBus(
|
||||
assertExists(this.pins.get("out1")),
|
||||
3,
|
||||
5,
|
||||
);
|
||||
this.not8.out().connect(out1Bus);
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo();
|
||||
foo.eval();
|
||||
expect(foo.not8.in().busVoltage).toEqual(0b1100_0011);
|
||||
expect(foo.pin("out1")?.busVoltage).toEqual(0b00111);
|
||||
});
|
||||
|
||||
it("assigns output inside wide busses", () => {
|
||||
// From figure A2.2, page 287, 2nd edition
|
||||
class Foo extends Chip {
|
||||
readonly not8 = new Not8();
|
||||
constructor() {
|
||||
super([], []);
|
||||
this.parts.push(this.not8);
|
||||
this.pins.insert(new ConstantBus("six", 0b110));
|
||||
// in[0..1] = true
|
||||
TRUE_BUS.connect(new InSubBus(this.not8.in(), 0, 2));
|
||||
// in[3..5] = six, 110
|
||||
this.pins.get("six")?.connect(new InSubBus(this.not8.in(), 3, 3));
|
||||
// in[7] = true
|
||||
TRUE_BUS.connect(new InSubBus(this.not8.in(), 7, 1));
|
||||
// out[3..7] = out1
|
||||
this.pins.emplace("out1", 5);
|
||||
const out1Bus = new OutSubBus(
|
||||
assertExists(this.pins.get("out1")),
|
||||
3,
|
||||
5,
|
||||
);
|
||||
this.not8.out().connect(out1Bus);
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo();
|
||||
foo.eval();
|
||||
expect(foo.not8.in().busVoltage).toBe(0b10110011);
|
||||
expect(foo.pin("out1").busVoltage).toBe(0b01001);
|
||||
});
|
||||
|
||||
it("pulls portions of true", () => {
|
||||
class Foo extends Chip {
|
||||
readonly chip = new Not3();
|
||||
constructor() {
|
||||
super([], []);
|
||||
this.wire(this.chip, [
|
||||
{
|
||||
from: { name: "true", start: 0, width: 1 },
|
||||
to: { name: "in", start: 1, width: 2 },
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo();
|
||||
|
||||
const inVoltage = foo.chip.in().busVoltage;
|
||||
expect(bin(inVoltage)).toBe(bin(0b110));
|
||||
});
|
||||
|
||||
it("pulls start of true", () => {
|
||||
class Foo extends Chip {
|
||||
readonly chip = new Not3();
|
||||
constructor() {
|
||||
super([], []);
|
||||
this.wire(this.chip, [
|
||||
{
|
||||
from: { name: "true", start: 0, width: 1 },
|
||||
to: { name: "in", start: 0, width: 2 },
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo();
|
||||
|
||||
const inVoltage = foo.chip.in().busVoltage;
|
||||
expect(bin(inVoltage)).toBe(bin(0b11));
|
||||
});
|
||||
});
|
||||
|
||||
describe("sequential", () => {
|
||||
const clock = Clock.get();
|
||||
beforeEach(() => {
|
||||
clock.reset();
|
||||
});
|
||||
|
||||
describe("dff", () => {
|
||||
it("flips and flops", () => {
|
||||
clock.reset();
|
||||
const dff = new DFF();
|
||||
|
||||
clock.tick(); // Read input, low
|
||||
expect(dff.out().voltage()).toBe(LOW);
|
||||
clock.tock(); // Write t, low
|
||||
expect(dff.out().voltage()).toBe(LOW);
|
||||
|
||||
dff.in().pull(HIGH);
|
||||
clock.tick(); // Read input, HIGH
|
||||
expect(dff.out().voltage()).toBe(LOW);
|
||||
clock.tock(); // Write t, HIGH
|
||||
expect(dff.out().voltage()).toBe(HIGH);
|
||||
|
||||
clock.tick();
|
||||
expect(dff.out().voltage()).toBe(HIGH);
|
||||
clock.tock();
|
||||
expect(dff.out().voltage()).toBe(HIGH);
|
||||
});
|
||||
});
|
||||
|
||||
describe("bit", () => {
|
||||
it("does not update when load is low", () => {
|
||||
clock.reset();
|
||||
const bit = new Bit();
|
||||
|
||||
const inn = bit.in();
|
||||
const load = bit.in("load");
|
||||
const out = bit.out();
|
||||
|
||||
load.pull(LOW);
|
||||
inn.pull(HIGH);
|
||||
expect(out.voltage()).toBe(LOW);
|
||||
clock.tick();
|
||||
expect(out.voltage()).toBe(LOW);
|
||||
clock.tock();
|
||||
expect(out.voltage()).toBe(LOW);
|
||||
});
|
||||
|
||||
it("does updates when load is high", () => {
|
||||
clock.reset();
|
||||
const bit = new Bit();
|
||||
|
||||
const inn = bit.in();
|
||||
const load = bit.in("load");
|
||||
const out = bit.out();
|
||||
|
||||
load.pull(HIGH);
|
||||
inn.pull(HIGH);
|
||||
expect(out.voltage()).toBe(LOW);
|
||||
clock.tick();
|
||||
expect(out.voltage()).toBe(LOW);
|
||||
clock.tock();
|
||||
expect(out.voltage()).toBe(HIGH);
|
||||
});
|
||||
});
|
||||
|
||||
describe("PC", () => {
|
||||
it("remains constant when not ticking", () => {
|
||||
clock.reset();
|
||||
const pc = new PC();
|
||||
const out = pc.out();
|
||||
|
||||
expect(out.busVoltage).toBe(0);
|
||||
clock.tick();
|
||||
expect(out.busVoltage).toBe(0);
|
||||
clock.tock();
|
||||
expect(out.busVoltage).toBe(0);
|
||||
clock.tick();
|
||||
expect(out.busVoltage).toBe(0);
|
||||
clock.tock();
|
||||
expect(out.busVoltage).toBe(0);
|
||||
});
|
||||
|
||||
it("increments when ticking", () => {
|
||||
clock.reset();
|
||||
const pc = new PC();
|
||||
const out = pc.out();
|
||||
|
||||
pc.in("inc").pull(HIGH);
|
||||
|
||||
clock.tick();
|
||||
expect(out.busVoltage).toBe(0);
|
||||
clock.tock();
|
||||
expect(out.busVoltage).toBe(1);
|
||||
|
||||
clock.tick();
|
||||
expect(out.busVoltage).toBe(1);
|
||||
clock.tock();
|
||||
expect(out.busVoltage).toBe(2);
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
clock.eval();
|
||||
expect(out.busVoltage).toBe(i + 3);
|
||||
}
|
||||
});
|
||||
|
||||
it("loads a jump value", () => {
|
||||
clock.reset();
|
||||
const pc = new PC();
|
||||
const out = pc.out();
|
||||
|
||||
pc.in().busVoltage = 0x8286;
|
||||
|
||||
expect(out.busVoltage).toBe(0);
|
||||
clock.tick();
|
||||
expect(out.busVoltage).toBe(0);
|
||||
clock.tock();
|
||||
expect(out.busVoltage).toBe(0);
|
||||
|
||||
pc.in("load").pull(HIGH);
|
||||
|
||||
expect(out.busVoltage).toBe(0);
|
||||
clock.eval();
|
||||
expect(out.busVoltage).toBe(0x8286);
|
||||
});
|
||||
|
||||
it("resets", () => {
|
||||
clock.reset();
|
||||
const pc = new PC();
|
||||
const out = pc.out();
|
||||
pc.in("inc").pull(HIGH);
|
||||
|
||||
expect(out.busVoltage).toBe(0);
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
clock.eval();
|
||||
}
|
||||
|
||||
expect(out.busVoltage).toBe(10);
|
||||
|
||||
pc.in("reset").pull(HIGH);
|
||||
|
||||
clock.eval();
|
||||
|
||||
expect(out.busVoltage).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("sorts parts before eval", () => {
|
||||
class FooA extends Chip {
|
||||
readonly notA = new Not();
|
||||
readonly notB = new Not();
|
||||
constructor() {
|
||||
super([], ["out"], "Foo", ["x"]);
|
||||
this.wire(this.notA, [
|
||||
{
|
||||
from: { name: "x", start: 0, width: 1 },
|
||||
to: { name: "in", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "out", start: 0, width: 1 },
|
||||
to: { name: "out", start: 0, width: 1 },
|
||||
},
|
||||
]);
|
||||
this.wire(this.notB, [
|
||||
{
|
||||
from: { name: "true", start: 0, width: 1 },
|
||||
to: { name: "in", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "x", start: 0, width: 1 },
|
||||
to: { name: "out", start: 0, width: 1 },
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
const fooA = new FooA();
|
||||
fooA.sortParts();
|
||||
expect(fooA.parts).toEqual([fooA.notB, fooA.notA]);
|
||||
|
||||
class FooB extends Chip {
|
||||
readonly notA = new Not();
|
||||
readonly notB = new Not();
|
||||
constructor() {
|
||||
super([], ["out"], "Foo", ["x"]);
|
||||
this.wire(this.notA, [
|
||||
{
|
||||
from: { name: "true", start: 0, width: 1 },
|
||||
to: { name: "in", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "x", start: 0, width: 1 },
|
||||
to: { name: "out", start: 0, width: 1 },
|
||||
},
|
||||
]);
|
||||
this.wire(this.notB, [
|
||||
{
|
||||
from: { name: "x", start: 0, width: 1 },
|
||||
to: { name: "in", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "out", start: 0, width: 1 },
|
||||
to: { name: "out", start: 0, width: 1 },
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
const fooB = new FooB();
|
||||
fooB.sortParts();
|
||||
expect(fooB.parts).toEqual([fooB.notA, fooB.notB]);
|
||||
});
|
||||
|
||||
it("sorts clocked chips", () => {
|
||||
class FooC extends Chip {
|
||||
readonly register = new Register();
|
||||
readonly inc16A = new Inc16();
|
||||
readonly inc16B = new Inc16();
|
||||
constructor() {
|
||||
super([], [], "Foo", []);
|
||||
this.wire(this.inc16B, [
|
||||
{
|
||||
from: { name: "b", start: 0, width: 16 },
|
||||
to: { name: "in", start: 0, width: 16 },
|
||||
},
|
||||
{
|
||||
from: { name: "c", start: 0, width: 16 },
|
||||
to: { name: "out", start: 0, width: 16 },
|
||||
},
|
||||
]);
|
||||
this.wire(this.register, [
|
||||
{
|
||||
from: { name: "c", start: 0, width: 16 },
|
||||
to: { name: "in", start: 0, width: 16 },
|
||||
},
|
||||
{
|
||||
from: { name: "true", start: 0, width: 1 },
|
||||
to: { name: "load", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "a", start: 0, width: 16 },
|
||||
to: { name: "out", start: 0, width: 16 },
|
||||
},
|
||||
]);
|
||||
this.wire(this.inc16A, [
|
||||
{
|
||||
from: { name: "a", start: 0, width: 16 },
|
||||
to: { name: "in", start: 0, width: 16 },
|
||||
},
|
||||
{
|
||||
from: { name: "b", start: 0, width: 16 },
|
||||
to: { name: "out", start: 0, width: 16 },
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
const fooC = new FooC();
|
||||
fooC.sortParts();
|
||||
const parts = fooC.parts.map((chip) => chip.id);
|
||||
expect(parts).toEqual([fooC.register.id, fooC.inc16A.id, fooC.inc16B.id]);
|
||||
});
|
||||
|
||||
it("evals without order issues (after sorting)", () => {
|
||||
/*
|
||||
CHIP Or {
|
||||
IN a, b;
|
||||
OUT out;
|
||||
|
||||
PARTS:
|
||||
|
||||
Not(in =b , out = net2);
|
||||
Nand(a = net, b =net2 , out =out );
|
||||
Not(in =a , out = net);
|
||||
}
|
||||
*/
|
||||
class OrA extends Chip {
|
||||
readonly nota = new Not();
|
||||
readonly nand = new Nand();
|
||||
readonly notb = new Not();
|
||||
constructor() {
|
||||
super(["a", "b"], ["out"], "OrA", []);
|
||||
this.wire(this.nota, [
|
||||
{
|
||||
from: { name: "b", start: 0, width: 1 },
|
||||
to: { name: "in", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "net2", start: 0, width: 1 },
|
||||
to: { name: "out", start: 0, width: 1 },
|
||||
},
|
||||
]);
|
||||
this.wire(this.nand, [
|
||||
{
|
||||
from: { name: "net", start: 0, width: 1 },
|
||||
to: { name: "a", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "net2", start: 0, width: 1 },
|
||||
to: { name: "b", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "out", start: 0, width: 1 },
|
||||
to: { name: "out", start: 0, width: 1 },
|
||||
},
|
||||
]);
|
||||
this.wire(this.notb, [
|
||||
{
|
||||
from: { name: "a", start: 0, width: 1 },
|
||||
to: { name: "in", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "net", start: 0, width: 1 },
|
||||
to: { name: "out", start: 0, width: 1 },
|
||||
},
|
||||
]);
|
||||
this.sortParts();
|
||||
}
|
||||
}
|
||||
|
||||
class OrB extends Chip {
|
||||
readonly nota = new Not();
|
||||
readonly nand = new Nand();
|
||||
readonly notb = new Not();
|
||||
constructor() {
|
||||
super(["a", "b"], ["out"], "OrB", []);
|
||||
this.wire(this.nota, [
|
||||
{
|
||||
from: { name: "b", start: 0, width: 1 },
|
||||
to: { name: "in", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "net2", start: 0, width: 1 },
|
||||
to: { name: "out", start: 0, width: 1 },
|
||||
},
|
||||
]);
|
||||
this.wire(this.notb, [
|
||||
{
|
||||
from: { name: "a", start: 0, width: 1 },
|
||||
to: { name: "in", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "net", start: 0, width: 1 },
|
||||
to: { name: "out", start: 0, width: 1 },
|
||||
},
|
||||
]);
|
||||
this.wire(this.nand, [
|
||||
{
|
||||
from: { name: "net", start: 0, width: 1 },
|
||||
to: { name: "a", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "net2", start: 0, width: 1 },
|
||||
to: { name: "b", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "out", start: 0, width: 1 },
|
||||
to: { name: "out", start: 0, width: 1 },
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class OrC extends Chip {
|
||||
readonly nota = new Not();
|
||||
readonly nand = new Nand();
|
||||
readonly notb = new Not();
|
||||
constructor() {
|
||||
super(["a", "b"], ["out"], "OrC", []);
|
||||
this.wireAll([
|
||||
{
|
||||
part: this.nota,
|
||||
connections: [
|
||||
{
|
||||
from: { name: "b", start: 0, width: 1 },
|
||||
to: { name: "in", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "net2", start: 0, width: 1 },
|
||||
to: { name: "out", start: 0, width: 1 },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
part: this.nand,
|
||||
connections: [
|
||||
{
|
||||
from: { name: "net", start: 0, width: 1 },
|
||||
to: { name: "a", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "net2", start: 0, width: 1 },
|
||||
to: { name: "b", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "out", start: 0, width: 1 },
|
||||
to: { name: "out", start: 0, width: 1 },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
part: this.notb,
|
||||
connections: [
|
||||
{
|
||||
from: { name: "a", start: 0, width: 1 },
|
||||
to: { name: "in", start: 0, width: 1 },
|
||||
},
|
||||
{
|
||||
from: { name: "net", start: 0, width: 1 },
|
||||
to: { name: "out", start: 0, width: 1 },
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
const ora = new OrA();
|
||||
ora.in("a").pull(HIGH);
|
||||
ora.in("b").pull(LOW);
|
||||
ora.eval();
|
||||
expect(ora.out("out").busVoltage).toBe(HIGH);
|
||||
|
||||
const orb = new OrB();
|
||||
orb.in("a").pull(HIGH);
|
||||
orb.in("b").pull(LOW);
|
||||
orb.eval();
|
||||
expect(orb.out("out").busVoltage).toBe(HIGH);
|
||||
|
||||
const orc = new OrC();
|
||||
orc.in("a").pull(HIGH);
|
||||
orc.in("b").pull(LOW);
|
||||
orc.eval();
|
||||
expect(orc.out("out").busVoltage).toBe(HIGH);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user