import { machine } from "./machine" import { ram } from "./ram" import { wordFromNumber, wordFromString } from "./word" describe("Two bit machine", () => { let subject: ReturnType beforeEach(() => { const machineRam = ram([ wordFromString("1011"), wordFromString("0001"), wordFromString("0000"), wordFromString("1110") ]) subject = machine(machineRam) }) test("starts with the program counter pointing at the second adddress in ram", () => { expect(subject.programCounter().value().toString()).toEqual("01") }) test("starts with the instruction counter pointing at the first two bits in the current instruction", () => { expect(subject.instructionCounter().value().toString()).toEqual("0") }) test("starts with the address register pointing to the first word stored in ram", () => { expect(subject.addressRegister.value().toString()).toEqual("11") }) describe("for each clock cycle", () => { describe("the instruction counter", () => { beforeEach(() => { subject.tick() }) test("increments by one", () => { expect(subject.instructionCounter().value().toString()).toEqual("1") }) test("resets to zero when already pointing at the end of the current word", () => { subject.tick() expect(subject.instructionCounter().value().toString()).toEqual("0") }) }) test("increments the program counter when the instruction counter rolls over", () => { subject.tick() subject.tick() expect(subject.programCounter().value().toString()).toEqual("10") }) describe("if the current instruction is 00 (add)", () => { test("ram[addressRegister] + ram[addressRegister + 1] is stored in ram[addressRegister + 2]", () => { const subject = machine(ram([ wordFromString("0010"), wordFromString("0000"), wordFromString("0110"), wordFromString("0101"), wordFromString("1111") ])) subject.tick() expect(subject.ram.read(wordFromNumber(4, 3)).toString()).toEqual("1011") }) test("the instruction counter is incremented as usual", () => { const subject = machine(ram([ wordFromString("0010"), wordFromString("0000"), wordFromString("0110"), wordFromString("0101"), wordFromString("1111") ])) subject.tick() expect(subject.instructionCounter().value().toString()).toEqual("1") }) test("the program counter is incremented as usual", () => { const subject = machine(ram([ wordFromString("0010"), wordFromString("0000"), wordFromString("0110"), wordFromString("0101"), wordFromString("1111") ])) subject.tick() expect(subject.programCounter().value().toString()).toEqual("001") }) }) describe("if the current instruction is 01 (load)", () => { test("ram[addressRegister] is loaded into addressRegister",() => { const subject = machine(ram([ wordFromString("0011"), wordFromString("0100"), wordFromString("0110"), wordFromString("0101"), wordFromString("1111") ])) subject.tick() expect(subject.addressRegister.value().toString()).toEqual("0101") }) test("ram is unchanged", () => { const subject = machine(ram([ wordFromString("0010"), wordFromString("0100"), wordFromString("0110"), ])) subject.tick() expect(subject.ram.values().map(word => word.toString())).toEqual([ "0010", "0100", "0110" ]) }) test("the instruction counter is incremented as usual", () => { const subject = machine(ram([ wordFromString("0010"), wordFromString("0100"), wordFromString("0110"), ])) subject.tick() expect(subject.instructionCounter().value().toString()).toEqual("1") }) test("the program counter is incremented as usual", () => { const subject = machine(ram([ wordFromString("0010"), wordFromString("0100"), wordFromString("0110"), ])) subject.tick() expect(subject.programCounter().value().toString()).toEqual("01") }) }) describe("if the current instruction is 10 (jump)", () => { describe("and ram[addressRegister] is nonzero", () => { let subject beforeEach(() => { subject = machine(ram([ wordFromString("0010"), wordFromString("1000"), wordFromString("1111"), wordFromString("1111"), wordFromString("0010"), wordFromString("0010"), wordFromString("0010"), wordFromString("0010"), ])) subject.tick() }) test("the instruction counter is set to zero", () => { expect(subject.instructionCounter().value().toString()).toEqual("0") }) test("the program counter is set to ram[addressRegister + 1]", () => { expect(subject.programCounter().value().toString()).toEqual("111") }) }) describe("and ram[addressRegister] is zero", () => { let subject beforeEach(() => { subject = machine(ram([ wordFromString("0010"), wordFromString("1000"), wordFromString("0000"), wordFromString("1000"), wordFromString("0010"), wordFromString("0010"), wordFromString("0010"), wordFromString("0010"), ])) subject.tick() }) test("the instruction counter is incremented as usual", () => { expect(subject.instructionCounter().value().toString()).toEqual("1") }) test("the program counter is incremented as usual", () => { expect(subject.programCounter().value().toString()).toEqual("001") }) }) }) describe("if the current instruction is 11 (increment addressRegister)", () => { let subject beforeEach(() => { subject = machine(ram([ wordFromString("0010"), wordFromString("1100"), wordFromString("1111"), wordFromString("1111") ])) subject.tick() }) test("the address register is incremented", () => { expect(subject.addressRegister.value().toString()).toEqual("11") }) test("the instruction counter is incremented as usual", () => { expect(subject.instructionCounter().value().toString()).toEqual("1") }) test("the program counter is incremented as usual", () => { expect(subject.programCounter().value().toString()).toEqual("01") }) }) }) })