diff options
Diffstat (limited to 'riscv/riscv_platform.sail')
| -rw-r--r-- | riscv/riscv_platform.sail | 295 |
1 files changed, 0 insertions, 295 deletions
diff --git a/riscv/riscv_platform.sail b/riscv/riscv_platform.sail deleted file mode 100644 index aee72e47..00000000 --- a/riscv/riscv_platform.sail +++ /dev/null @@ -1,295 +0,0 @@ -/* Platform-specific definitions, and basic MMIO devices. */ - -/* Current constraints on this implementation are: - - it cannot access memory directly, but instead provides definitions for the physical memory model - - it can access system register state, needed to manipulate interrupt bits - - it relies on externs to get platform address information and doesn't hardcode them. -*/ - -/* Main memory */ -val plat_ram_base = {c: "plat_ram_base", ocaml: "Platform.dram_base", lem: "plat_ram_base"} : unit -> xlenbits -val plat_ram_size = {c: "plat_ram_size", ocaml: "Platform.dram_size", lem: "plat_ram_size"} : unit -> xlenbits - -/* whether the MMU should update dirty bits in PTEs */ -val plat_enable_dirty_update = {ocaml: "Platform.enable_dirty_update", - c: "plat_enable_dirty_update", - lem: "plat_enable_dirty_update"} : unit -> bool - -/* whether the platform supports misaligned accesses without trapping to M-mode. if false, - * misaligned loads/stores are trapped to Machine mode. - */ -val plat_enable_misaligned_access = {ocaml: "Platform.enable_misaligned_access", - c: "plat_enable_misaligned_access", - lem: "plat_enable_misaligned_access"} : unit -> bool - -/* whether mtval stores the bits of a faulting instruction on illegal instruction exceptions */ -val plat_mtval_has_illegal_inst_bits = {ocaml: "Platform.mtval_has_illegal_inst_bits", - c: "plat_mtval_has_illegal_inst_bits", - lem: "plat_mtval_has_illegal_inst_bits"} : unit -> bool - -/* ROM holding reset vector and device-tree DTB */ -val plat_rom_base = {ocaml: "Platform.rom_base", c: "plat_rom_base", lem: "plat_rom_base"} : unit -> xlenbits -val plat_rom_size = {ocaml: "Platform.rom_size", c: "plat_rom_size", lem: "plat_rom_size"} : unit -> xlenbits - -/* Location of clock-interface, which should match with the spec in the DTB */ -val plat_clint_base = {ocaml: "Platform.clint_base", c: "plat_clint_base", lem: "plat_clint_base"} : unit -> xlenbits -val plat_clint_size = {ocaml: "Platform.clint_size", c: "plat_clint_size", lem: "plat_clint_size"} : unit -> xlenbits - -/* Location of HTIF ports */ -val plat_htif_tohost = {ocaml: "Platform.htif_tohost", c: "plat_htif_tohost", lem: "plat_htif_tohost"} : unit -> xlenbits -// todo: fromhost - -val phys_mem_segments : unit -> list((xlenbits, xlenbits)) -function phys_mem_segments() = - (plat_rom_base (), plat_rom_size ()) :: - (plat_ram_base (), plat_ram_size ()) :: - [||] - -/* Physical memory map predicates */ - -function within_phys_mem forall 'n. (addr : xlenbits, width : atom('n)) -> bool = { - let ram_base = plat_ram_base (); - let rom_base = plat_rom_base (); - let ram_size = plat_ram_size (); - let rom_size = plat_rom_size (); - - /* todo: iterate over segment list */ - if ( ram_base <=_u addr - & (addr + sizeof('n)) <=_u (ram_base + ram_size)) - then true - else if ( rom_base <=_u addr - & (addr + sizeof('n)) <=_u (rom_base + rom_size)) - then true - else { - print_platform("within_phys_mem: " ^ BitStr(addr) ^ " not within phys-mem:"); - print_platform(" plat_rom_base: " ^ BitStr(rom_base)); - print_platform(" plat_rom_size: " ^ BitStr(rom_size)); - print_platform(" plat_ram_base: " ^ BitStr(ram_base)); - print_platform(" plat_ram_size: " ^ BitStr(ram_size)); - false - } -} - -function within_clint forall 'n. (addr : xlenbits, width : atom('n)) -> bool = - plat_clint_base() <=_u addr - & (addr + sizeof('n)) <=_u (plat_clint_base() + plat_clint_size()) - -function within_htif_writable forall 'n. (addr : xlenbits, width : atom('n)) -> bool = - plat_htif_tohost() == addr - -function within_htif_readable forall 'n. (addr : xlenbits, width : atom('n)) -> bool = - plat_htif_tohost() == addr - -/* CLINT (Core Local Interruptor), based on Spike. */ - -val plat_insns_per_tick = {ocaml: "Platform.insns_per_tick", c: "plat_insns_per_tick", lem: "plat_insns_per_tick"} : unit -> int - -// assumes a single hart, since this typically is a vector of per-hart registers. -register mtimecmp : xlenbits // memory-mapped internal clint register. - -/* CLINT memory-mapped IO */ - -/* relative address map: - * - * 0000 msip hart 0 -- memory-mapped software interrupt - * 0004 msip hart 1 - * 4000 mtimecmp hart 0 lo -- memory-mapped timer thresholds - * 4004 mtimecmp hart 0 hi - * 4008 mtimecmp hart 1 lo - * 400c mtimecmp hart 1 hi - * bff8 mtime lo -- memory-mapped clocktimer value - * bffc mtime hi - */ - -let MSIP_BASE : xlenbits = 0x0000000000000000 -let MTIMECMP_BASE : xlenbits = 0x0000000000004000 -let MTIME_BASE : xlenbits = 0x000000000000bff8 - -val clint_load : forall 'n, 'n > 0. (xlenbits, int('n)) -> MemoryOpResult(bits(8 * 'n)) effect {rreg} -function clint_load(addr, width) = { - let addr = addr - plat_clint_base (); - /* FIXME: For now, only allow exact aligned access. */ - if addr == MSIP_BASE & ('n == 8 | 'n == 4) - then { - print_platform("clint[" ^ BitStr(addr) ^ "] -> " ^ BitStr(mip.MSI())); - MemValue(zero_extend_type_hack(mip.MSI(), sizeof(8 * 'n))) - } - else if addr == MTIMECMP_BASE & ('n == 8) - then { - print_platform("clint[" ^ BitStr(addr) ^ "] -> " ^ BitStr(mtimecmp)); - MemValue(zero_extend_type_hack(mtimecmp, 64)) /* FIXME: Redundant zero_extend currently required by Lem backend */ - } - else if addr == MTIME_BASE & ('n == 8) - then { - print_platform("clint[" ^ BitStr(addr) ^ "] -> " ^ BitStr(mtime)); - MemValue(zero_extend_type_hack(mtime, 64)) - } - else { - print_platform("clint[" ^ BitStr(addr) ^ "] -> <not-mapped>"); - MemException(E_Load_Access_Fault) - } -} - -function clint_dispatch() -> unit = { - print_platform("clint::tick mtime <- " ^ BitStr(mtime)); - mip->MTI() = false; - if mtimecmp <=_u mtime then { - print_platform(" clint timer pending at mtime " ^ BitStr(mtime)); - mip->MTI() = true - } -} - -/* The rreg effect is due to checking mtime. */ -val clint_store: forall 'n, 'n > 0. (xlenbits, int('n), bits(8 * 'n)) -> MemoryOpResult(bool) effect {rreg,wreg} -function clint_store(addr, width, data) = { - let addr = addr - plat_clint_base (); - if addr == MSIP_BASE & ('n == 8 | 'n == 4) then { - print_platform("clint[" ^ BitStr(addr) ^ "] <- " ^ BitStr(data) ^ " (mip.MSI <- " ^ BitStr(data[0]) ^ ")"); - mip->MSI() = data[0] == 0b1; - clint_dispatch(); - MemValue(true) - } else if addr == MTIMECMP_BASE & 'n == 8 then { - print_platform("clint[" ^ BitStr(addr) ^ "] <- " ^ BitStr(data) ^ " (mtimecmp)"); - mtimecmp = zero_extend(data, 64); /* FIXME: Redundant zero_extend currently required by Lem backend */ - clint_dispatch(); - MemValue(true) - } else { - print_platform("clint[" ^ BitStr(addr) ^ "] <- " ^ BitStr(data) ^ " (<unmapped>)"); - MemException(E_SAMO_Access_Fault) - } -} - -val tick_clock : unit -> unit effect {rreg, wreg} -function tick_clock() = { - mcycle = mcycle + 1; - mtime = mtime + 1; - clint_dispatch() -} - -/* Basic terminal character I/O. */ - -val plat_term_write = {ocaml: "Platform.term_write", c: "plat_term_write", lem: "plat_term_write"} : bits(8) -> unit -val plat_term_read = {ocaml: "Platform.term_read", c: "plat_term_read", lem: "plat_term_read"} : unit -> bits(8) - -/* Spike's HTIF device interface, which multiplexes the above MMIO devices. */ - -bitfield htif_cmd : bits(64) = { - device : 63 .. 56, - cmd : 55 .. 48, - payload : 47 .. 0 -} - -register htif_tohost : xlenbits -register htif_done : bool -register htif_exit_code : xlenbits - - -/* Since the htif tohost port is only available at a single address, - * we'll assume here that physical memory model has correctly - * dispatched the address. - */ - -val htif_load : forall 'n, 'n > 0. (xlenbits, int('n)) -> MemoryOpResult(bits(8 * 'n)) effect {rreg} -function htif_load(addr, width) = { - print_platform("htif[" ^ BitStr(addr) ^ "] -> " ^ BitStr(htif_tohost)); - /* FIXME: For now, only allow the expected access widths. */ - if width == 8 - then MemValue(zero_extend_type_hack(htif_tohost, 64)) /* FIXME: Redundant zero_extend currently required by Lem backend */ - else MemException(E_Load_Access_Fault) -} - -/* The wreg effect is an artifact of using 'register' to implement device state. */ -val htif_store: forall 'n, 0 < 'n <= 8. (xlenbits, int('n), bits(8 * 'n)) -> MemoryOpResult(bool) effect {wreg} -function htif_store(addr, width, data) = { - print_platform("htif[" ^ BitStr(addr) ^ "] <- " ^ BitStr(data)); - /* Store the written value so that we can ack it later. */ - let cbits : xlenbits = EXTZ(data); - htif_tohost = cbits; - /* Process the cmd immediately; this is needed for terminal output. */ - let cmd = Mk_htif_cmd(cbits); - match cmd.device() { - 0x00 => { /* syscall-proxy */ - print_platform("htif-syscall-proxy cmd: " ^ BitStr(cmd.payload())); - if cmd.payload()[0] == 0b1 - then { - htif_done = true; - htif_exit_code = (zero_extend(cmd.payload(), xlen) >> 0b01) : xlenbits - } - else () - }, - 0x01 => { /* terminal */ - print_platform("htif-term cmd: " ^ BitStr(cmd.payload())); - match cmd.cmd() { - 0x00 => /* TODO: terminal input handling */ (), - 0x01 => plat_term_write(cmd.payload()[7..0]), - c => print("Unknown term cmd: " ^ BitStr(c)) - } - }, - d => print("htif-???? cmd: " ^ BitStr(data)) - }; - MemValue(true) -} - -val htif_tick : unit -> unit effect {rreg, wreg} -function htif_tick() = { - print_platform("htif::tick " ^ BitStr(htif_tohost)); - htif_tohost = EXTZ(0b0) /* htif ack */ -} - -/* Top-level MMIO dispatch */ - -function within_mmio_readable forall 'n. (addr : xlenbits, width : atom('n)) -> bool = - within_clint(addr, width) | (within_htif_readable(addr, width) & 1 <= 'n) - -function within_mmio_writable forall 'n. (addr : xlenbits, width : atom('n)) -> bool = - within_clint(addr, width) | (within_htif_writable(addr, width) & 'n <= 8) - -function mmio_read forall 'n, 'n > 0. (addr : xlenbits, width : atom('n)) -> MemoryOpResult(bits(8 * 'n)) = - if within_clint(addr, width) - then clint_load(addr, width) - else if within_htif_readable(addr, width) & (1 <= 'n) - then htif_load(addr, width) - else MemException(E_Load_Access_Fault) - -function mmio_write forall 'n, 'n > 0. (addr : xlenbits, width : atom('n), data: bits(8 * 'n)) -> MemoryOpResult(bool) = - if within_clint(addr, width) - then clint_store(addr, width, data) - else if within_htif_writable(addr, width) & 'n <= 8 - then htif_store(addr, width, data) - else MemException(E_SAMO_Access_Fault) - -/* Platform initialization and ticking. */ - -function init_platform() -> unit = { - htif_tohost = EXTZ(0b0); - htif_done = false; - htif_exit_code = EXTZ(0b0) -} - -function tick_platform() -> unit = { - cancel_reservation(); - htif_tick(); -} - -/* Platform-specific handling of instruction faults */ - -function handle_illegal() -> unit = { - let info = if plat_mtval_has_illegal_inst_bits () - then Some(instbits) - else None(); - let t : sync_exception = struct { trap = E_Illegal_Instr, - excinfo = info }; - nextPC = handle_exception(cur_privilege, CTL_TRAP(t), PC) -} - -/* Platform-specific wait-for-interrupt */ - -function platform_wfi() -> unit = { - /* speed execution by getting the timer to fire at the next instruction, - * since we currently don't have any other devices raising interrupts. - */ - if mtime <_u mtimecmp then { - mtime = mtimecmp; - mcycle = mtimecmp; - } -}
\ No newline at end of file |
