two-bit/machine.test.ts

241 lines
8.2 KiB
TypeScript

import { machine } from "./machine"
import { ram } from "./ram"
import { wordFromNumber, wordFromString } from "./word"
describe("Two bit machine", () => {
let subject: ReturnType<typeof machine>
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")
})
})
})
})