diff options
Diffstat (limited to 'triscv')
| -rw-r--r-- | triscv/include/triscv/common.h | 4 | ||||
| -rw-r--r-- | triscv/include/triscv/cpu.h | 3 | ||||
| -rw-r--r-- | triscv/include/triscv/csr.h | 6 | ||||
| -rw-r--r-- | triscv/include/triscv/mmu.h | 4 | ||||
| -rw-r--r-- | triscv/src/cpu.c | 25 | ||||
| -rw-r--r-- | triscv/src/mmu.c | 147 |
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; } |
