241 lines
8.2 KiB
TypeScript
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")
|
|
})
|
|
})
|
|
})
|
|
}) |