two-bit/ram.ts

67 lines
2.4 KiB
TypeScript

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