import { Memory, memory } from "./memory" import { Word, wordFromString } from "./word" export interface Ram { get(address: Word): Memory addressLength: number values: () => Word[] write: (value: Word, address: Word) => void read: (address: Word) => Word wordSize: Width } type RamDimensions = { size: number, width: Width } export function ram(initialValues: string[]): Ram export function ram(initialValues: Word[]): Ram export function ram({ size, width }: RamDimensions): Ram export function ram(arg: RamDimensions | (Word[]) | string[]): Ram { const memorySpace = unpackArgToMemoryArray(arg) const wordSize = memorySpace[0].value().bits.length const addressLength = Math.ceil(Math.log2(memorySpace.length)) function write(value: Word, address: Word) { memorySpace[address.toNumber()].set(value) } function read(address: Word) { return get(address).value() } function values() { return memorySpace.map(memory => memory.value()) } function get(address: Word) { return memorySpace[address.toNumber()] } return { values, write, read, get, wordSize, addressLength, } } function unpackArgToMemoryArray(arg: RamDimensions | (Word[]) | string[]) { return isDimensionsArg(arg) ? memoryFromSizeAndWidth(arg.size, arg.width) : memoryFromArrayArg(arg) } function memoryFromArrayArg(array: Word[] | string[]) { const isStringArray = typeof array[0] === "string" const words = isStringArray ? (array as string[]).map(stringValue => wordFromString(stringValue) as Word) : array as Word[] return words.map(word => memory(word)) as Memory[] } function memoryFromSizeAndWidth(size: number, width: Width) { return Array(size).fill(() => 0).map(() => memory(width)) } function isDimensionsArg(arg: any): arg is RamDimensions { return typeof arg === "object" && typeof arg.size === "number" && typeof arg.width === "number" }