Files
risc-d/source/riscd/memory.d
2025-05-27 14:39:37 +02:00

255 lines
5.1 KiB
D

module riscd.memory;
import std.format;
import std.file : readFile = read;
import std.traits;
interface MemoryDevice
{
@safe:
bool get(size_t addr, ref ubyte value);
bool set(size_t addr, ubyte value);
}
class RAM : MemoryDevice
{
@safe:
public:
this(size_t size)
{
data.length = size;
}
this(void[] data, bool copy = true) @system
{
if (copy)
this.data = cast(ubyte[]) data.dup;
else
this.data = cast(ubyte[]) data;
}
static RAM loadFile(string filename) @system
{
return new RAM(readFile(filename), false);
}
bool get(size_t addr, ref ubyte value) @nogc nothrow pure
{
if (data.length <= addr)
return false;
value = data[addr];
return true;
}
bool set(size_t addr, ubyte value) @nogc nothrow pure
{
if (data.length <= addr)
return false;
data[addr] = value;
return true;
}
protected:
ubyte[] data;
}
class ROM : MemoryDevice
{
@safe:
public:
this(const(void)[] data, bool copy = true)
{
if (copy)
this.data = cast(const(ubyte)[]) data.idup;
else
this.data = cast(const(ubyte)[]) data;
}
static ROM loadFile(string filename)
{
return new ROM(readFile(filename), false);
}
bool get(size_t addr, ref ubyte value) @nogc nothrow pure
{
if (data.length <= addr)
return false;
value = data[addr];
return true;
}
bool set(size_t addr, ubyte value) @nogc nothrow pure
{
return false;
}
protected:
const(ubyte)[] data;
}
class MMIO : MemoryDevice
{
@safe:
public:
this()
{
}
void map(MemoryDevice device, size_t origin, size_t length)
{
// Check for colliding mappings
foreach (mapping; mappings)
if (
// Is mapping.origin inside new mapping?
(mapping.origin > origin && mapping.origin < origin + length)
||
// Is origin inside existing mapping?
(origin > mapping.origin && origin < mapping.origin + mapping.length)
)
// We collide, throw
throw new Exception(
format("Trying to map %p over existing %p", origin, mapping.origin)
);
// No collisons? Cool, craete a new mapping
mappings ~= MemoryMapping(device, origin, length);
}
void unmap(size_t origin)
{
size_t index = findMapping(origin);
// Could not find the mapping
if (index == -1)
throw new Exception(format("Nothing mapped at %p", origin));
if (mappings.length != 1)
mappings[index] = mappings[$];
mappings.length -= 1;
}
bool get(size_t addr, ref ubyte value)
{
size_t index = findMapping(addr);
if (index == -1)
return false;
return mappings[index].device.get( addr - mappings[index].origin, value);
}
bool set(size_t addr, ubyte value)
{
size_t index = findMapping(addr);
if (index == -1)
return false;
return mappings[index].device.set( addr - mappings[index].origin, value);
}
protected:
struct MemoryMapping
{
MemoryDevice device;
size_t origin, length;
}
size_t findMapping(size_t origin) @nogc pure nothrow
{
// Is there only one mapping, and it's the correct one?
if (mappings.length == 1 && mappings[0].origin == origin)
return 0;
// Look for the mapping
for (size_t i = 0; i < mappings.length; i++)
if (mappings[i].origin == origin)
return i;
// Could not find the mapping
return -1;
}
MemoryMapping[] mappings;
}
// TODO: Add endianess support
class Memory
{
@safe:
public:
this(MemoryDevice device)
{
this.device = device;
}
bool get(T)(size_t addr, ref T value) @trusted
if (isBasicType!T)
{
return get(addr, (&value)[0..1]);
}
bool set(T)(size_t addr, T value) @trusted
if (isBasicType!T)
{
return set(addr, (&value)[0..1]);
}
bool get(T)(size_t addr, ref T value) @system
if (!isBasicType!T)
{
return get(addr, (&value)[0..1]);
}
bool set(T)(size_t addr, T value) @system
if (!isBasicType!T)
{
return set(addr, (&value)[0..1]);
}
bool get(size_t addr, void[] buffer) @system
{
ubyte[] buff = cast(ubyte[])buffer;
for (size_t i = 0; i < buff.length; i++)
if (!get(addr+i, buff[i]))
return false;
return true;
}
bool set(size_t addr, const(void)[] buffer) @system
{
const(ubyte)[] buff = cast(const(ubyte)[])buffer;
for (size_t i = 0; i < buff.length; i++)
if (!set(addr+i, buff[i]))
return false;
return true;
}
bool get(size_t addr, ref ubyte value)
{
return device.get(addr, value);
}
bool set(size_t addr, ubyte value)
{
return device.set(addr, value);
}
protected:
MemoryDevice device;
}