diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2023-10-28 00:00:21 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2023-10-28 00:00:21 +0300 |
| commit | d96b8c7d12fc61ec609d6138627b9d6d18139a9a (patch) | |
| tree | 82bc9a4c2b22de6c021097fb79a57b6d7756a127 /triscv/src/mmu.c | |
| download | tri-d96b8c7d12fc61ec609d6138627b9d6d18139a9a.tar.gz tri-d96b8c7d12fc61ec609d6138627b9d6d18139a9a.zip | |
move to monorepo
+ Will probably have to make some changes to dir layout to make things
make more sense
Diffstat (limited to 'triscv/src/mmu.c')
| -rw-r--r-- | triscv/src/mmu.c | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/triscv/src/mmu.c b/triscv/src/mmu.c new file mode 100644 index 0000000..c73f91d --- /dev/null +++ b/triscv/src/mmu.c @@ -0,0 +1,151 @@ +#include <triscv/mmu.h> + +struct tlb_map { + vm_t from; + pm_t to; + bool valid; +}; + +struct dev_map { + pm_t start; + struct dev dev; +}; + +/* completely arbitrary value */ +#define MMU_SIZE 1024 +#define MAX_DEVS 16 +struct mmu { + /* virtual -> physical */ + struct tlb_map tlb[MMU_SIZE]; + + /* physical to dev */ + struct dev_map dev[MAX_DEVS]; + size_t devs; + + /* whether we should treat incoming addresses as virtual or physical */ + bool translate; +}; + +struct mmu *mmu_create() +{ + /** @todo map some backing memory as well */ + return calloc(1, sizeof(struct mmu)); +} + +void mmu_destroy(struct mmu *mmu) +{ + free(mmu); +} + +static struct dev_map *mmu_find_dev_map(struct mmu *mmu, pm_t addr) +{ + for (size_t i = 0; i < mmu->devs; ++i) { + struct dev_map *d = &mmu->dev[i]; + if (d->start > addr) + continue; + + /* slightly tricky off by one here */ + if (d->dev.size <= (addr - d->start)) + continue; + + return d; + } + + return NULL; +} + +stat_t mmu_map_dev(struct mmu *mmu, pm_t start, struct dev dev) +{ + /** @todo return status or something */ + if (mmu->devs == MAX_DEVS) + return ERR_FULL; + + if (mmu_find_dev_map(mmu, start)) + return ERR_EXISTS; + + struct dev_map *d = &mmu->dev[mmu->devs++]; + d->dev = dev; + d->start = start; + return OK; +} + +void mmu_enable(struct mmu *mmu) +{ + mmu->translate = true; +} + +void mmu_disable(struct mmu *mmu) +{ + mmu->translate = false; +} + +static bool mmu_translate(struct cpu *cpu, struct mmu *mmu, vm_t *addr) +{ + (void)cpu; + (void)mmu; + (void)addr; + /** @todo raise segfault if addr is not allowed */ + return true; +} + +void mmu_write1(struct cpu *cpu, struct mmu *mmu, vm_t addr, tri_t t) +{ + if (mmu->translate) { + if (!mmu_translate(cpu, mmu, &addr)) + return; + } + + struct dev_map *d = mmu_find_dev_map(mmu, addr); + if (!d || !d->dev.write1) { + /** @todo raise bus (?) error */ + } + + d->dev.write1(cpu, d->dev.dev, addr - d->start, t); +} + +void mmu_write3(struct cpu *cpu, struct mmu *mmu, vm_t addr, tri_t t) +{ + if (mmu->translate) { + if (!mmu_translate(cpu, mmu, &addr)) + return; + } + + struct dev_map *d = mmu_find_dev_map(mmu, addr); + if (!d || !d->dev.write3) { + /** @todo raise bus error */ + } + + d->dev.write3(cpu, d->dev.dev, addr - d->start, t); +} + +tri_t mmu_read1(struct cpu *cpu, struct mmu *mmu, vm_t addr) +{ + if (mmu->translate) { + if (!mmu_translate(cpu, mmu, &addr)) + return 0; + } + + struct dev_map *d = mmu_find_dev_map(mmu, addr); + if (!d || !d->dev.read1) { + /** @todo raise bus error */ + return 0; + } + + return d->dev.read1(cpu, d->dev.dev, addr - d->start); +} + +tri_t mmu_read3(struct cpu *cpu, struct mmu *mmu, vm_t addr) +{ + if (mmu->translate) { + if (!mmu_translate(cpu, mmu, &addr)) + return 0; + } + + struct dev_map *d = mmu_find_dev_map(mmu, addr); + if (!d || !d->dev.read3) { + /** @todo raise bus error */ + return 0; + } + + return d->dev.read3(cpu, d->dev.dev, addr - d->start); +} |
