74 lines
3.0 KiB
TypeScript
74 lines
3.0 KiB
TypeScript
import bit from "./bit";
|
|
import { memory } from "./memory";
|
|
import { Ram } from "./ram";
|
|
import { Word, emptyWord, wordFromNumber, wordFromString } from "./word";
|
|
|
|
export function machine<Width extends number>(ram: Ram<Width>) {
|
|
|
|
const programCounterRegister = memory(wordFromNumber(1, ram.addressLength))
|
|
|
|
const startAddress = ram.read(emptyWord(ram.addressLength)).subword(ram.wordSize - ram.addressLength, ram.addressLength)
|
|
|
|
const addressRegister = memory(startAddress)
|
|
|
|
const instructionCounterSize = Math.ceil(Math.log2(Math.floor(ram.wordSize / 2)))
|
|
const instructionCounterRegister = memory(emptyWord(instructionCounterSize))
|
|
|
|
function programCounter() {
|
|
return programCounterRegister
|
|
}
|
|
|
|
function instructionCounter() {
|
|
return instructionCounterRegister
|
|
}
|
|
|
|
function tick() {
|
|
|
|
const currentInstruction = ram.read(programCounterRegister.value()).subword(instructionCounterRegister.value().toNumber() * 2, 2)
|
|
if (currentInstruction.equals(wordFromString("00"))) {
|
|
const firstOperand = ram.read(addressRegister.value())
|
|
const secondOperand = ram.read(addressRegister.value().plus(wordFromNumber(1)).sum)
|
|
const result = firstOperand.plus(secondOperand).sum as Word<number>
|
|
|
|
ram.write(result as Word<Width>, addressRegister.value().plus(wordFromString("10")).sum)
|
|
incrementInstruction()
|
|
} else if (currentInstruction.equals(wordFromString("01"))) {
|
|
addressRegister.set(ram.read(addressRegister.value()))
|
|
incrementInstruction()
|
|
} else if (currentInstruction.equals(wordFromString("10"))) {
|
|
const current = ram.read(addressRegister.value())
|
|
const jumpAddress = ram.read(addressRegister.value().plus(wordFromNumber(1)).sum).subword(ram.wordSize - ram.addressLength, ram.addressLength)
|
|
|
|
if (current.toNumber() !== 0) {
|
|
programCounterRegister.set(jumpAddress)
|
|
instructionCounterRegister.set(emptyWord(instructionCounterSize))
|
|
} else {
|
|
incrementInstruction()
|
|
}
|
|
} else if (currentInstruction.equals(wordFromString("11"))) {
|
|
const nextValue = addressRegister.value().plus(wordFromNumber(1)).sum
|
|
addressRegister.set(nextValue)
|
|
|
|
incrementInstruction()
|
|
}
|
|
}
|
|
|
|
function incrementInstruction() {
|
|
const nextInstructionIndex = instructionCounterRegister.value().plus(wordFromNumber(1, instructionCounterSize))
|
|
instructionCounterRegister.set(nextInstructionIndex.sum)
|
|
|
|
if (nextInstructionIndex.carry.equals(bit(1))) {
|
|
const nextProgramCounterAddress = programCounterRegister.value().plus(wordFromNumber(1, ram.addressLength))
|
|
programCounterRegister.set(nextProgramCounterAddress.sum)
|
|
}
|
|
}
|
|
|
|
return {
|
|
programCounter,
|
|
addressRegister,
|
|
instructionCounter,
|
|
tick,
|
|
ram
|
|
}
|
|
}
|