Hazard3/test/sim/rvcpp/include/rv_mem.h

161 lines
3.8 KiB
C++

#pragma once
#include "rv_types.h"
#include <optional>
#include <tuple>
#include <cassert>
#include <vector>
#include <cstdio>
struct MemBase32 {
virtual std::optional<uint8_t> r8(__attribute__((unused)) ux_t addr) {return std::nullopt;}
virtual bool w8(__attribute__((unused)) ux_t addr, __attribute__((unused)) uint8_t data) {return false;}
virtual std::optional<uint16_t> r16(__attribute__((unused)) ux_t addr) {return std::nullopt;}
virtual bool w16(__attribute__((unused)) ux_t addr, __attribute__((unused)) uint16_t data) {return false;}
virtual std::optional<uint32_t> r32(__attribute__((unused)) ux_t addr) {return std::nullopt;}
virtual bool w32(__attribute__((unused)) ux_t addr, __attribute__((unused)) uint32_t data) {return false;}
};
struct FlatMem32: MemBase32 {
uint32_t size;
uint32_t *mem;
FlatMem32(uint32_t size_) {
assert(size_ % sizeof(uint32_t) == 0);
size = size_;
mem = new uint32_t[size >> 2];
for (uint64_t i = 0; i < size >> 2; ++i)
mem[i] = 0;
}
~FlatMem32() {
delete mem;
}
virtual std::optional<uint8_t> r8(ux_t addr) {
assert(addr < size);
return mem[addr >> 2] >> 8 * (addr & 0x3) & 0xffu;
}
virtual bool w8(ux_t addr, uint8_t data) {
assert(addr < size);
mem[addr >> 2] &= ~(0xffu << 8 * (addr & 0x3));
mem[addr >> 2] |= (uint32_t)data << 8 * (addr & 0x3);
return true;
}
virtual std::optional<uint16_t> r16(ux_t addr) {
assert(addr < size && addr + 1 < size); // careful of ~0u
assert(addr % 2 == 0);
return mem[addr >> 2] >> 8 * (addr & 0x2) & 0xffffu;
}
virtual bool w16(ux_t addr, uint16_t data) {
assert(addr < size && addr + 1 < size);
assert(addr % 2 == 0);
mem[addr >> 2] &= ~(0xffffu << 8 * (addr & 0x2));
mem[addr >> 2] |= (uint32_t)data << 8 * (addr & 0x2);
return true;
}
virtual std::optional<uint32_t> r32(ux_t addr) {
assert(addr < size && addr + 3 < size);
assert(addr % 4 == 0);
return mem[addr >> 2];
}
virtual bool w32(ux_t addr, uint32_t data) {
assert(addr < size && addr + 3 < size);
assert(addr % 4 == 0);
mem[addr >> 2] = data;
return true;
}
};
struct TBExitException {
ux_t exitcode;
TBExitException(ux_t code): exitcode(code) {}
};
struct TBMemIO: MemBase32 {
virtual bool w32(ux_t addr, uint32_t data) {
switch (addr) {
case 0x0:
printf("%c", (char)data);
return true;
case 0x4:
printf("%08x\n", data);
return true;
case 0x8:
throw TBExitException(data);
return true;
default:
return false;
}
}
};
struct MemMap32: MemBase32 {
std::vector<std::tuple<uint32_t, uint32_t, MemBase32*> > memmap;
void add(uint32_t base, uint32_t size, MemBase32 *mem) {
memmap.push_back(std::make_tuple(base, size, mem));
}
std::tuple <uint32_t, MemBase32*> map_addr(uint32_t addr) {
for (auto&& [base, size, mem] : memmap) {
if (addr >= base && addr < base + size)
return std::make_tuple(addr - base, mem);
}
return std::make_tuple(addr, nullptr);
}
virtual std::optional<uint8_t> r8(ux_t addr) {
auto [offset, mem] = map_addr(addr);
if (mem)
return mem->r8(offset);
else
return std::nullopt;
}
virtual bool w8(ux_t addr, uint8_t data) {
auto [offset, mem] = map_addr(addr);
if (mem)
return mem->w8(offset, data);
else
return false;
}
virtual std::optional<uint16_t> r16(ux_t addr) {
auto [offset, mem] = map_addr(addr);
if (mem)
return mem->r16(offset);
else
return std::nullopt;
}
virtual bool w16(ux_t addr, uint16_t data) {
auto [offset, mem] = map_addr(addr);
if (mem)
return mem->w16(offset, data);
else
return false;
}
virtual std::optional<uint32_t> r32(ux_t addr) {
auto [offset, mem] = map_addr(addr);
if (mem)
return mem->r32(offset);
else
return std::nullopt;
}
virtual bool w32(ux_t addr, uint32_t data) {
auto [offset, mem] = map_addr(addr);
if (mem)
return mem->w32(offset, data);
else
return false;
}
};