aboutsummaryrefslogtreecommitdiff
path: root/triscv
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-01-21 23:10:36 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2024-01-21 23:10:36 +0200
commita152fbd956cc9cb9c05a233abe004ba3d12767a0 (patch)
tree458a7812ae3c4d5c4999d7f9650e2ee1c05c9ba6 /triscv
parent910ad02d86672cc3020cc5df0fa451ef4dd69bfd (diff)
downloadtri-a152fbd956cc9cb9c05a233abe004ba3d12767a0.tar.gz
tri-a152fbd956cc9cb9c05a233abe004ba3d12767a0.zip
start working on virtual memory
Diffstat (limited to 'triscv')
-rw-r--r--triscv/include/triscv/common.h4
-rw-r--r--triscv/include/triscv/cpu.h3
-rw-r--r--triscv/include/triscv/csr.h6
-rw-r--r--triscv/include/triscv/mmu.h4
-rw-r--r--triscv/src/cpu.c25
-rw-r--r--triscv/src/mmu.c147
6 files changed, 162 insertions, 27 deletions
diff --git a/triscv/include/triscv/common.h b/triscv/include/triscv/common.h
index 865f6e5..4f23edc 100644
--- a/triscv/include/triscv/common.h
+++ b/triscv/include/triscv/common.h
@@ -4,8 +4,8 @@
#include <tri.h>
#include <stdint.h>
-typedef uint64_t vm_t;
-typedef uint64_t pm_t;
+typedef int64_t vm_t;
+typedef int64_t pm_t;
/* forward declarations */
struct cpu;
diff --git a/triscv/include/triscv/cpu.h b/triscv/include/triscv/cpu.h
index 05f8b78..aedd1df 100644
--- a/triscv/include/triscv/cpu.h
+++ b/triscv/include/triscv/cpu.h
@@ -11,4 +11,7 @@ void cpu_destroy(struct cpu *cpu);
* update after each cycle? */
void cpu_run(struct cpu *cpu, vm_t start);
+void set_csr(struct cpu *cpu, long i, tri_t t);
+tri_t get_csr(struct cpu *cpu, long i);
+
#endif
diff --git a/triscv/include/triscv/csr.h b/triscv/include/triscv/csr.h
index a805702..0ca03a3 100644
--- a/triscv/include/triscv/csr.h
+++ b/triscv/include/triscv/csr.h
@@ -2,7 +2,11 @@
#define TRISCV_CSR_H
/* first trit is sleep mode, R/W, second trit shutdown, R/W */
-#define CSR_MPOWER 0
+#define CSR_MPOWER -9841
#define RW_MPOWER 0b1111
+#define CSR_SATPP -3280
+#define CSR_SATPO -3279
+#define CSR_SATPN -3278
+
#endif
diff --git a/triscv/include/triscv/mmu.h b/triscv/include/triscv/mmu.h
index c885814..100d9ac 100644
--- a/triscv/include/triscv/mmu.h
+++ b/triscv/include/triscv/mmu.h
@@ -4,6 +4,8 @@
#include <triscv/common.h>
#include <triscv/cpu.h>
+#define BASE_PAGE_SIZE 19683
+
typedef void (*dev_write1_t)(struct cpu *cpu, void *dev, pm_t addr, tri_t t);
typedef void (*dev_write3_t)(struct cpu *cpu, void *dev, pm_t addr, tri_t t);
typedef tri_t (*dev_read1_t)(struct cpu *cpu, void *dev, pm_t addr);
@@ -37,4 +39,6 @@ tri_t mmu_read3(struct cpu *cpu, struct mmu *mmu, vm_t addr);
void mmu_write1(struct cpu *cpu, struct mmu *mmu, vm_t addr, tri_t t);
void mmu_write3(struct cpu *cpu, struct mmu *mmu, vm_t addr, tri_t t);
+tri_t mmu_read_pc(struct cpu *cpu, struct mmu *mmu, vm_t addr);
+
#endif
diff --git a/triscv/src/cpu.c b/triscv/src/cpu.c
index a7213bb..a47ec78 100644
--- a/triscv/src/cpu.c
+++ b/triscv/src/cpu.c
@@ -27,23 +27,20 @@ struct cpu {
tri_t csrw[19683];
};
-static size_t get_csr_num(tri_t csr)
+tri_t get_csr(struct cpu *cpu, long i)
{
- return tri_to(csr) + 9841;
-}
-
-static tri_t get_csr(struct cpu *cpu, size_t i)
-{
- size_t max_csr = cpu->mode * 6561;
+ i += 9841;
+ long max_csr = cpu->mode * 6561;
if (i < max_csr)
return 0; /* illegal access, should maybe also raise an interrupt? */
return cpu->csr[i];
}
-static void set_csr(struct cpu *cpu, size_t i, tri_t t)
+void set_csr(struct cpu *cpu, long i, tri_t t)
{
- size_t max_csr = cpu->mode * 6561;
+ i += 9841;
+ long max_csr = cpu->mode * 6561;
if (i < max_csr)
return;
@@ -78,8 +75,8 @@ static void set_gpr(struct cpu *cpu, tri_t i, tri_t t)
static void csr_init(struct cpu *cpu)
{
- cpu->csr[CSR_MPOWER] = 0;
- cpu->csrw[CSR_MPOWER] = RW_MPOWER;
+ cpu->csrw[CSR_MPOWER + 9841] = RW_MPOWER;
+ set_csr(cpu, CSR_MPOWER, 0);
}
struct cpu *cpu_create(struct mmu *mmu, struct tmb *tmb)
@@ -127,7 +124,7 @@ static void do_system(struct cpu *cpu, tri_t i)
switch (fn0) {
case SYSTEM_CSRRW: {
/* read existing value and replace it with rs1 */
- size_t n = get_csr_num(imm9);
+ long n = tri_to(imm9);
tri_t c = get_csr(cpu, n);
set_csr(cpu, n, src);
set_gpr(cpu, rd, c);
@@ -215,8 +212,8 @@ void cpu_run(struct cpu *cpu, vm_t start)
cpu->pc = start;
/* run while the shutdown trit is zero */
- while (!(cpu->csr[CSR_MPOWER] & 0b1100)) {
- tri_t i = mmu_read3(cpu, cpu->mmu, cpu->pc);
+ while (!(get_csr(cpu, CSR_MPOWER) & 0b1100)) {
+ tri_t i = mmu_read_pc(cpu, cpu->mmu, cpu->pc);
/** @todo check for raised interrupts, illegal addr etc. */
/* check lowest five trits to determine opcode */
diff --git a/triscv/src/mmu.c b/triscv/src/mmu.c
index c73f91d..c90c51d 100644
--- a/triscv/src/mmu.c
+++ b/triscv/src/mmu.c
@@ -1,9 +1,11 @@
#include <triscv/mmu.h>
+#include <triscv/csr.h>
+/* from and to must be page aligned, each tlb in map represent a base page. */
struct tlb_map {
vm_t from;
pm_t to;
- bool valid;
+ tri_t tag;
};
struct dev_map {
@@ -45,7 +47,7 @@ static struct dev_map *mmu_find_dev_map(struct mmu *mmu, pm_t addr)
continue;
/* slightly tricky off by one here */
- if (d->dev.size <= (addr - d->start))
+ if (d->start + (pm_t)d->dev.size <= addr)
continue;
return d;
@@ -69,6 +71,25 @@ stat_t mmu_map_dev(struct mmu *mmu, pm_t start, struct dev dev)
return OK;
}
+struct tri_option {
+ tri_t value;
+ bool ok;
+};
+
+static struct tri_option __mmu_read3(struct cpu *cpu, struct mmu *mmu, vm_t addr)
+{
+ struct dev_map *d = mmu_find_dev_map(mmu, addr);
+ if (!d || !d->dev.read3) {
+ /** @todo raise bus error */
+ return (struct tri_option){.ok = false};
+ }
+
+ return (struct tri_option){
+ .value = d->dev.read3(cpu, d->dev.dev, addr - d->start),
+ .ok = true
+ };
+}
+
void mmu_enable(struct mmu *mmu)
{
mmu->translate = true;
@@ -79,12 +100,114 @@ void mmu_disable(struct mmu *mmu)
mmu->translate = false;
}
+static bool __valid_mapping(struct tlb_map mapping)
+{
+ return !(mapping.from == 1 && mapping.to == 1);
+}
+
+static struct tlb_map __build_invalid_mapping()
+{
+ return (struct tlb_map){.from = 1, .to = 1};
+}
+
+static struct tlb_map __build_mapping(vm_t from, pm_t to, tri_t tag)
+{
+ return (struct tlb_map){.from = from, .to = to, .tag = tag};
+}
+
+static bool __valid_pte(tri_t pte)
+{
+ return tri_get_trit(pte, 0) == 1;
+}
+
+static bool __leaf_pte(tri_t pte)
+{
+ int rw = tri_get_trit(pte, 1);
+ int x = tri_get_trit(pte, 3);
+
+ return !(x == 0 && rw == 0);
+}
+
+static pm_t __process_pte(struct cpu *cpu, struct mmu *mmu, pm_t table, tri_t orig, size_t shift,
+ struct tlb_map *mapping)
+{
+ tri_t ppn = tri_mask(tri_sr(orig, shift), 6);
+ pm_t i = tri_to(ppn);
+ struct tri_option pte = __mmu_read3(cpu, mmu, table + 3 * i);
+
+ if (!pte.ok || !__valid_pte(pte.value)) {
+ *mapping = __build_invalid_mapping();
+ return 0;
+ }
+
+ if (__leaf_pte(pte.value)) {
+ // pte was fine, so the tag must be as well
+ tri_t tag = __mmu_read3(cpu, mmu, table + 3 * i + 3).value;
+
+ tri_t base = tri_discard(pte.value, 9);
+ tri_t cur = tri_discard(orig, shift);
+ tri_t off = tri_sub(orig, cur);
+
+ *mapping = __build_mapping(tri_to(orig), tri_to(base) + tri_to(off), tag);
+ return 0;
+ }
+
+ return pte.value;
+}
+
+static struct tlb_map __fetch_mapping(struct cpu *cpu, struct mmu *mmu, vm_t addr)
+{
+ /* feels kind of silly to convert back to trinary, but I guess fine for
+ * now. */
+ tri_t orig = tri_from(addr);
+
+ int sign = tri_sign(orig);
+
+ tri_t start = 0;
+ switch (sign) {
+ case 1: start = get_csr(cpu, CSR_SATPP); break;
+ case 0: start = get_csr(cpu, CSR_SATPO); break;
+ case -1: start = get_csr(cpu, CSR_SATPN); break;
+ }
+
+ start = tri_to(start);
+
+ tri_t pte = 0;
+ struct tlb_map mapping = {0};
+ if (!(pte = __process_pte(cpu, mmu, start, orig, 21, &mapping)))
+ return mapping;
+
+ start = tri_to(tri_discard(pte, 9));
+ if (!(pte = __process_pte(cpu, mmu, start, orig, 15, &mapping)))
+ return mapping;
+
+ start = tri_to(tri_discard(pte, 9));
+ if (!(pte = __process_pte(cpu, mmu, start, orig, 9, &mapping)))
+ return mapping;
+
+ return __build_invalid_mapping();
+}
+
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 */
+
+ vm_t base_page = *addr / BASE_PAGE_SIZE;
+ vm_t base_addr = base_page * BASE_PAGE_SIZE;
+ size_t slot = (size_t)base_page % MMU_SIZE;
+ vm_t offset = *addr - base_addr;
+
+ struct tlb_map mapping = mmu->tlb[slot];
+ if (mapping.from != base_addr || !__valid_mapping(mapping))
+ mmu->tlb[slot] = mapping = __fetch_mapping(cpu, mmu, base_addr);
+
+ if (mapping.from != base_addr || !__valid_mapping(mapping)) {
+ /* @todo raise segfault */
+ return false;
+ }
+
+ /* @todo check rwx and tags */
+ *addr = mapping.to + offset;
return true;
}
@@ -141,11 +264,15 @@ tri_t mmu_read3(struct cpu *cpu, struct mmu *mmu, vm_t 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 __mmu_read3(cpu, mmu, addr).value;
+}
+
+tri_t mmu_read_pc(struct cpu *cpu, struct mmu *mmu, vm_t addr)
+{
+ if (mmu->translate) {
+ if (!mmu_translate(cpu, mmu, &addr))
+ return 0;
}
- return d->dev.read3(cpu, d->dev.dev, addr - d->start);
+ return __mmu_read3(cpu, mmu, addr).value;
}