diff --git a/examples/simple_system/README.md b/examples/simple_system/README.md new file mode 100644 index 00000000..f553d3a6 --- /dev/null +++ b/examples/simple_system/README.md @@ -0,0 +1,107 @@ +# Ibex Simple System + +Simple System gives you an Ibex based system simulated by Verilator that can +run stand-alone binaries. It contains: + +* An Ibex Core +* A single memory for instructions and data +* A basic peripheral to write ASCII output to a file and halt simulation from + software +* A software framework to build programs for it + +## Prerequisites + +* [Verilator](https://www.veripool.org/wiki/verilator) + Note Linux package managers may have Verilator but often a very old version + that is not suitable. It is recommended Verilator is built from source. +* [FuseSoC](https://github.com/olofk/fusesoc) +* RISC-V Compiler Toolchain - lowRISC provides a pre-built GCC based toolchain + + +## Building Simulation + +The Simple System simulator binary can be built via FuseSoC. From the Ibex +repository root run: + +``` +fusesoc --cores-root=. run --target=sim --setup --build lowrisc:ibex:ibex_simple_system --RV32M=1 --RV32E=0 +``` + +## Building Software + +Simple System related software can be found in examples/sw/simple_system + +To build the hello world example, from the Ibex reposistory root run: + +``` +make -C examples/sw/simple_system/hello_test +``` + +This should create the file +examples/sw/simple_system/hello_test/hello_test.vmem which is the memory +initialisation file used to run the hello_test program + +To build new software make a copy of the hello_test directory named as desired. +Look inside the Makefile for further instructions. + +If using a toolchain other than the lowRISC pre-built one +examples/sw/simple_system/common/common.mk may need altering to point to the +correct compiler binaries. + +## Running the Simulator + +Having built the simulator and software, from the Ibex repository root run: + +``` +./build/lowrisc_ibex_ibex_simple_system_0/sim-verilator/Vibex_simple_system [-t] --raminit= +``` + +`` should be a path to a vmem file built as described above, use +./examples/sw/simple_system/hello_test/hello_test.vmem to run the hello_test +binary. + +Pass `-t` to get an FST trace of execution that be viewed with [GTKWave](http://gtkwave.sourceforge.net/) +If using the hello_test binary the simulator will halt itself, outputting some +simulation statistics: + +``` +Simulation statistics +===================== +Executed cycles: 633 +Wallclock time: 0.013 s +Simulation speed: 48692.3 cycles/s (48.6923 kHz) + +Performance Counters +==================== +Cycles: 483 +NONE: 0 +Instructions Retired: 266 +LSU Busy: 59 +Fetch Wait: 16 +Loads: 21 +Stores: 38 +Jumps: 46 +Conditional Branches: 53 +Taken Conditional Branches: 48 +Compressed Instructions: 182 +``` + +The simulator produces several output files + +* ibex_simple_system.log - The ASCII output written via the output peripheral +* ibex_simple_system_pcount.csv - A csv of the performance counters +* trace_core_00000000.log - An instruction trace of execution + +## System Memory Map + ++---------------------|-----------------------------------------------------------------------------+ +| Address | Description | ++=====================|=============================================================================+ +| 0x20000 | ASCII Out, write ASCII characters here that will get output to the log file | ++---------------------|-----------------------------------------------------------------------------+ +| 0x20004 | Simulator Halt, write 1 here to halt the simulation | ++---------------------|-----------------------------------------------------------------------------+ +| 0x100000 - 0x1FFFFF | 1 MB memory for instruction and data. Execution starts at 0x100080, | +| | exception handler base is 0x100000 | ++---------------------|-----------------------------------------------------------------------------+ + diff --git a/examples/simple_system/ibex_simple_system.cc b/examples/simple_system/ibex_simple_system.cc new file mode 100644 index 00000000..c214af4c --- /dev/null +++ b/examples/simple_system/ibex_simple_system.cc @@ -0,0 +1,50 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include + +#include +#include +#include + +#include "ibex_pcounts.h" +#include "verilated_toplevel.h" +#include "verilator_sim_ctrl.h" + +std::shared_ptr simctrl(nullptr); + +int main(int argc, char **argv) { + int retcode; + + auto top = std::make_shared(); + + simctrl = std::make_shared( + top.get(), top->IO_CLK, top->IO_RST_N, + VerilatorSimCtrlFlags::ResetPolarityNegative); + + retcode = simctrl->SetupSimulation(argc, argv); + + if (retcode != 0) + return retcode; + + // Initialize RAM + simctrl->InitRam("TOP.ibex_simple_system.u_ram"); + + std::cout << "Simulation of Ibex" << std::endl + << "==================" << std::endl + << std::endl; + + simctrl->RunSimulation(); + + std::cout << "\nPerformance Counters" << std::endl + << "====================" << std::endl; + std::cout << ibex_pcount_string( + top->ibex_simple_system__DOT__mhpmcounter_vals, false); + + std::ofstream pcount_csv("ibex_simple_system_pcount.csv"); + pcount_csv << ibex_pcount_string( + top->ibex_simple_system__DOT__mhpmcounter_vals, true); + + return 0; +} diff --git a/examples/simple_system/ibex_simple_system.core b/examples/simple_system/ibex_simple_system.core new file mode 100644 index 00000000..6e67ab17 --- /dev/null +++ b/examples/simple_system/ibex_simple_system.core @@ -0,0 +1,63 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:ibex:ibex_simple_system" +description: "Generic simple system for running binaries on ibex using verilator" +filesets: + files_sim_verilator: + depend: + - lowrisc:dv_verilator:simutil_verilator + - lowrisc:ibex:ibex_core_tracing + - lowrisc:ibex:sim_shared + - lowrisc:dv_verilator:ibex_pcounts + files: + - rtl/ibex_simple_system.sv + - ibex_simple_system.cc: { file_type: cppSource } + file_type: systemVerilogSource + +parameters: + RV32M: + datatype: int + paramtype: vlogparam + default: 1 + description: Enable the M ISA extension (hardware multiply/divide) [0/1] + RV32E: + datatype: int + paramtype: vlogparam + default: 0 + description: Enable the E ISA extension (reduced register set) [0/1] + +targets: + sim: + default_tool: verilator + filesets: + - files_sim_verilator + parameters: + - RV32M + - RV32E + toplevel: ibex_simple_system + tools: + verilator: + mode: cc + verilator_options: +# Disabling tracing reduces compile times by multiple times, but doesn't have a +# huge influence on runtime performance. (Based on early observations.) + - '--trace' + - '--trace-fst' # this requires -DVM_TRACE_FMT_FST in CFLAGS below! + - '--trace-structs' + - '--trace-params' + - '--trace-max-array 1024' +# compiler flags +# +# -O +# Optimization levels have a large impact on the runtime performance of the +# simulation model. -O2 and -O3 are pretty similar, -Os is slower than -O2/-O3 + - '-CFLAGS "-std=c++11 -Wall -DVM_TRACE_FMT_FST -DTOPLEVEL_NAME=ibex_simple_system -g -O0"' + - '-LDFLAGS "-pthread -lutil"' + - "-Wall" + - "-Wno-PINCONNECTEMPTY" + # XXX: Cleanup all warnings and remove this option + # (or make it more fine-grained at least) + - "-Wno-fatal" + diff --git a/examples/simple_system/rtl/ibex_simple_system.sv b/examples/simple_system/rtl/ibex_simple_system.sv new file mode 100644 index 00000000..80dafc5c --- /dev/null +++ b/examples/simple_system/rtl/ibex_simple_system.sv @@ -0,0 +1,191 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +/** + * Ibex simple system + * + * This is a basic system consisting of an ibex, a 1 MB sram for instruction/data + * and a small memory mapped control module for outputting ASCII text and + * controlling/halting the simulation from the software running on the ibex. + * + * It is designed to be used with verilator but should work with other + * simulators, a small amount of work may be required to support the + * simulator_ctrl module. + */ +module ibex_simple_system ( + input IO_CLK, + input IO_RST_N +); + + parameter bit RV32E = 0; + parameter bit RV32M = 1; + + logic clk_sys, rst_sys_n; + + assign clk_sys = IO_CLK; + assign rst_sys_n = IO_RST_N; + + typedef enum { + CoreD, + CoreI + } bus_host_e; + + typedef enum { + Ram, + SimCtrl + } bus_device_e; + + localparam NrDevices = 2; + localparam NrHosts = 2; + + // host and device signals + logic host_req [NrHosts]; + logic host_gnt [NrHosts]; + logic [31:0] host_addr [NrHosts]; + logic host_we [NrHosts]; + logic [ 3:0] host_be [NrHosts]; + logic [31:0] host_wdata [NrHosts]; + logic host_rvalid [NrHosts]; + logic [31:0] host_rdata [NrHosts]; + logic host_err [NrHosts]; + + // devices (slaves) + logic device_req [NrDevices]; + logic [31:0] device_addr [NrDevices]; + logic device_we [NrDevices]; + logic [ 3:0] device_be [NrDevices]; + logic [31:0] device_wdata [NrDevices]; + logic device_rvalid [NrDevices]; + logic [31:0] device_rdata [NrDevices]; + logic device_err [NrDevices]; + + // Device address mapping + logic [31:0] cfg_device_addr_base [NrDevices]; + logic [31:0] cfg_device_addr_mask [NrDevices]; + assign cfg_device_addr_base[Ram] = 32'h100000; + assign cfg_device_addr_mask[Ram] = ~32'hFFFFF; // 1 MB + assign cfg_device_addr_base[SimCtrl] = 32'h20000; + assign cfg_device_addr_mask[SimCtrl] = ~32'h3FF; // 1 kB + + + bus #( + .NrDevices (NrDevices), + .NrHosts (NrHosts ), + .DataWidth (32 ), + .AddressWidth(32 ) + ) u_bus ( + .clk_i (clk_sys), + .rst_ni (rst_sys_n), + + .host_req_i (host_req ), + .host_gnt_o (host_gnt ), + .host_addr_i (host_addr ), + .host_we_i (host_we ), + .host_be_i (host_be ), + .host_wdata_i (host_wdata ), + .host_rvalid_o (host_rvalid ), + .host_rdata_o (host_rdata ), + .host_err_o (host_err ), + + .device_req_o (device_req ), + .device_addr_o (device_addr ), + .device_we_o (device_we ), + .device_be_o (device_be ), + .device_wdata_o (device_wdata ), + .device_rvalid_i (device_rvalid), + .device_rdata_i (device_rdata ), + .device_err_i (device_err ), + + .cfg_device_addr_base, + .cfg_device_addr_mask + ); + + assign host_we[CoreI] = 1'b0; + assign host_be[CoreI] = 4'b1111; + assign host_wdata[CoreI] = 32'b0; + + ibex_core_tracing #( + .MHPMCounterNum(29), + .DmHaltAddr(32'h00100000), + .DmExceptionAddr(32'h00100000), + .RV32E(RV32E), + .RV32M(RV32M) + ) u_core ( + .clk_i (clk_sys), + .rst_ni (rst_sys_n), + + .test_en_i ('b0), + + .hart_id_i (32'b0), + // First instruction executed is at 0x0 + 0x80 + .boot_addr_i (32'h00100000), + + .instr_req_o (host_req[CoreI]), + .instr_gnt_i (host_gnt[CoreI]), + .instr_rvalid_i (host_rvalid[CoreI]), + .instr_addr_o (host_addr[CoreI]), + .instr_rdata_i (host_rdata[CoreI]), + .instr_err_i (host_err[CoreI]), + + .data_req_o (host_req[CoreD]), + .data_gnt_i (host_gnt[CoreD]), + .data_rvalid_i (host_rvalid[CoreD]), + .data_we_o (host_we[CoreD]), + .data_be_o (host_be[CoreD]), + .data_addr_o (host_addr[CoreD]), + .data_wdata_o (host_wdata[CoreD]), + .data_rdata_i (host_rdata[CoreD]), + .data_err_i (host_err[CoreD]), + + .irq_software_i (1'b0), + .irq_timer_i (1'b0), + .irq_external_i (1'b0), + .irq_fast_i (15'b0), + .irq_nm_i (1'b0), + + .debug_req_i ('b0), + + .fetch_enable_i ('b1), + .core_sleep_o () + ); + + // SRAM block for instruction and data storage + ram_1p #( + .Depth(1024*1024/4) + ) u_ram ( + .clk_i (clk_sys), + .rst_ni (rst_sys_n), + .req_i (device_req[Ram]), + .we_i (device_we[Ram]), + .be_i (device_be[Ram]), + .addr_i (device_addr[Ram]), + .wdata_i (device_wdata[Ram]), + .rvalid_o (device_rvalid[Ram]), + .rdata_o (device_rdata[Ram]) + ); + + simulator_ctrl #( + .LogName("ibex_simple_system.log") + ) u_simulator_ctrl ( + .clk_i (clk_sys), + .rst_ni (rst_sys_n), + + .req_i (device_req[SimCtrl]), + .we_i (device_we[SimCtrl]), + .be_i (device_be[SimCtrl]), + .addr_i (device_addr[SimCtrl]), + .wdata_i (device_wdata[SimCtrl]), + .rvalid_o (device_rvalid[SimCtrl]), + .rdata_o (device_rdata[SimCtrl]) + ); + + // Expose the performance counter array so it's easy to access in + // a verilator siumulation + logic [63:0] mhpmcounter_vals [32] /*verilator public_flat*/; + + for(genvar i = 0;i < 32; i = i + 1) begin + assign mhpmcounter_vals[i] = u_core.u_ibex_core.cs_registers_i.mhpmcounter_q[i]; + end +endmodule + diff --git a/examples/sw/simple_system/common/common.mk b/examples/sw/simple_system/common/common.mk new file mode 100644 index 00000000..5cd2737a --- /dev/null +++ b/examples/sw/simple_system/common/common.mk @@ -0,0 +1,69 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +COMMON_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) + +COMMON_SRCS = $(wildcard $(COMMON_DIR)/*.c) +INCS := -I$(COMMON_DIR) + +# ARCH = rv32im # to disable compressed instructions +ARCH ?= rv32imc + +ifdef PROGRAM +PROGRAM_C := $(PROGRAM).c +endif + +SRCS = $(COMMON_SRCS) $(PROGRAM_C) $(EXTRA_SRCS) + +C_SRCS = $(filter %.c, $(SRCS)) +ASM_SRCS = $(filter %.S, $(SRCS)) + +CC = riscv32-unknown-elf-gcc + +OBJCOPY ?= $(subst gcc,objcopy,$(wordlist 1,1,$(CC))) +OBJDUMP ?= $(subst gcc,objdump,$(wordlist 1,1,$(CC))) + +LINKER_SCRIPT ?= $(COMMON_DIR)/link.ld +CRT ?= $(COMMON_DIR)/crt0.S +CFLAGS ?= -march=$(ARCH) -mabi=ilp32 -static -mcmodel=medany -Wall -g -Os\ + -fvisibility=hidden -nostdlib -nostartfiles -ffreestanding $(PROGRAM_CFLAGS) + +OBJS := ${C_SRCS:.c=.o} ${ASM_SRCS:.S=.o} ${CRT:.S=.o} +DEPS = $(OBJS:%.o=%.d) + +ifdef PROGRAM +OUTFILES := $(PROGRAM).elf $(PROGRAM).vmem $(PROGRAM).bin $(PROGRAM).dis +else +OUTFILES := $(OBJS) +endif + +all: $(OUTFILES) + +$(PROGRAM).elf: $(OBJS) $(LINKER_SCRIPT) + $(CC) $(CFLAGS) -T $(LINKER_SCRIPT) $(OBJS) -o $@ $(LIBS) + +%.dis: %.elf + $(OBJDUMP) -fhSD $^ > $@ + +# Note: this target requires the srecord package to be installed. +# XXX: This could be replaced by objcopy once +# https://sourceware.org/bugzilla/show_bug.cgi?id=19921 +# is widely available. +%.vmem: %.bin + srec_cat $^ -binary -offset 0x0000 -byte-swap 4 -o $@ -vmem + +%.bin: %.elf + $(OBJCOPY) -O binary $^ $@ + +%.o: %.c + $(CC) $(CFLAGS) -MMD -c $(INCS) -o $@ $< + +%.o: %.S + $(CC) $(CFLAGS) -MMD -c $(INCS) -o $@ $< + +clean: + $(RM) -f $(OBJS) $(DEPS) + +distclean: clean + $(RM) -f $(OUTFILES) diff --git a/examples/sw/simple_system/common/crt0.S b/examples/sw/simple_system/common/crt0.S new file mode 100644 index 00000000..1e00057d --- /dev/null +++ b/examples/sw/simple_system/common/crt0.S @@ -0,0 +1,97 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +#include "simple_system_regs.h" + +.section .text + +default_exc_handler: + jal x0, simple_exc_handler + +reset_handler: + /* set all registers to zero */ + mv x1, x0 + mv x2, x1 + mv x3, x1 + mv x4, x1 + mv x5, x1 + mv x6, x1 + mv x7, x1 + mv x8, x1 + mv x9, x1 + mv x10, x1 + mv x11, x1 + mv x12, x1 + mv x13, x1 + mv x14, x1 + mv x15, x1 + mv x16, x1 + mv x17, x1 + mv x18, x1 + mv x19, x1 + mv x20, x1 + mv x21, x1 + mv x22, x1 + mv x23, x1 + mv x24, x1 + mv x25, x1 + mv x26, x1 + mv x27, x1 + mv x28, x1 + mv x29, x1 + mv x30, x1 + mv x31, x1 + + /* stack initilization */ + la x2, _stack_start + +_start: + .global _start + + /* clear BSS */ + la x26, _bss_start + la x27, _bss_end + + bge x26, x27, zero_loop_end + +zero_loop: + sw x0, 0(x26) + addi x26, x26, 4 + ble x26, x27, zero_loop +zero_loop_end: + + +main_entry: + /* jump to main program entry point (argc = argv = 0) */ + addi x10, x0, 0 + addi x11, x0, 0 + jal x1, main + + /* Halt simulation */ + la x5, SIM_CTRL_BASE + SIM_CTRL_CTRL + li x6, 1 + sw x6, 0(x5) + + /* If execution ends up here just put the core to sleep */ +sleep_loop: + wfi + j sleep_loop + +/* =================================================== [ exceptions ] === */ +/* This section has to be down here, since we have to disable rvc for it */ + + .section .vectors, "ax" + .option norvc; + + // All traps go to the same default_exc_handler. Create a landing pad of nops + // as IRQs can come into different addresses. + .org 0x00 + .rept 31 + nop + .endr + jal x0, default_exc_handler + + // reset vector + .org 0x80 + jal x0, reset_handler diff --git a/examples/sw/simple_system/common/link.ld b/examples/sw/simple_system/common/link.ld new file mode 100644 index 00000000..485cbaff --- /dev/null +++ b/examples/sw/simple_system/common/link.ld @@ -0,0 +1,63 @@ +/* Copyright lowRISC contributors. + Licensed under the Apache License, Version 2.0, see LICENSE for details. + SPDX-License-Identifier: Apache-2.0 */ + +OUTPUT_ARCH(riscv) + +MEMORY +{ + /* 992 kB should be enough for anybody... */ + ram : ORIGIN = 0x00100000, LENGTH = 0xF8000 /* 992 kB */ + stack : ORIGIN = 0x001F8000, LENGTH = 0x8000 /* 32 kB */ +} + +/* Stack information variables */ +_min_stack = 0x2000; /* 8K - minimum stack space to reserve */ +_stack_len = LENGTH(stack); +_stack_start = ORIGIN(stack) + LENGTH(stack); + +SECTIONS +{ + .vectors : + { + . = ALIGN(4); + KEEP(*(.vectors)) + } > ram + + .text : { + . = ALIGN(4); + *(.text) + *(.text.*) + } > ram + + .rodata : { + . = ALIGN(4); + *(.rodata); + *(.rodata.*) + } > ram + + .data : { + . = ALIGN(4); + *(.data); + *(.data.*) + } > ram + + .bss : + { + . = ALIGN(4); + _bss_start = .; + *(.bss) + *(.bss.*) + *(COMMON) + _bss_end = .; + } > ram + + /* ensure there is enough room for stack */ + .stack (NOLOAD): { + . = ALIGN(4); + . = . + _min_stack ; + . = ALIGN(4); + stack = . ; + _stack = . ; + } > stack +} diff --git a/examples/sw/simple_system/common/simple_system_common.c b/examples/sw/simple_system/common/simple_system_common.c new file mode 100644 index 00000000..a5729833 --- /dev/null +++ b/examples/sw/simple_system/common/simple_system_common.c @@ -0,0 +1,141 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "simple_system_common.h" + +int putchar(int c) { + DEV_WRITE(SIM_CTRL_BASE + SIM_CTRL_OUT, (unsigned char)c); + + return c; +} + +int puts(const char *str) { + while (*str) { + putchar(*str++); + } + + return 0; +} + +void puthex(uint32_t h) { + int cur_digit; + // Iterate through h taking top 4 bits each time and outputting ASCII of hex + // digit for those 4 bits + for (int i = 0; i < 8; i++) { + cur_digit = h >> 28; + + if (cur_digit < 10) + putchar('0' + cur_digit); + else + putchar('A' - 10 + cur_digit); + + h <<= 4; + } +} + +void sim_halt() { DEV_WRITE(SIM_CTRL_BASE + SIM_CTRL_CTRL, 1); } + +void pcount_reset() { + asm volatile( + "csrw minstret, x0\n" + "csrw mcycle, x0\n" + "csrw mhpmcounter3, x0\n" + "csrw mhpmcounter4, x0\n" + "csrw mhpmcounter5, x0\n" + "csrw mhpmcounter6, x0\n" + "csrw mhpmcounter7, x0\n" + "csrw mhpmcounter8, x0\n" + "csrw mhpmcounter9, x0\n" + "csrw mhpmcounter10, x0\n" + "csrw mhpmcounter11, x0\n" + "csrw mhpmcounter12, x0\n" + "csrw mhpmcounter13, x0\n" + "csrw mhpmcounter14, x0\n" + "csrw mhpmcounter15, x0\n" + "csrw mhpmcounter16, x0\n" + "csrw mhpmcounter17, x0\n" + "csrw mhpmcounter18, x0\n" + "csrw mhpmcounter19, x0\n" + "csrw mhpmcounter20, x0\n" + "csrw mhpmcounter21, x0\n" + "csrw mhpmcounter22, x0\n" + "csrw mhpmcounter23, x0\n" + "csrw mhpmcounter24, x0\n" + "csrw mhpmcounter25, x0\n" + "csrw mhpmcounter26, x0\n" + "csrw mhpmcounter27, x0\n" + "csrw mhpmcounter28, x0\n" + "csrw mhpmcounter29, x0\n" + "csrw mhpmcounter30, x0\n" + "csrw mhpmcounter31, x0\n" + "csrw minstreth, x0\n" + "csrw mcycleh, x0\n" + "csrw mhpmcounter3h, x0\n" + "csrw mhpmcounter4h, x0\n" + "csrw mhpmcounter5h, x0\n" + "csrw mhpmcounter6h, x0\n" + "csrw mhpmcounter7h, x0\n" + "csrw mhpmcounter8h, x0\n" + "csrw mhpmcounter9h, x0\n" + "csrw mhpmcounter10h, x0\n" + "csrw mhpmcounter11h, x0\n" + "csrw mhpmcounter12h, x0\n" + "csrw mhpmcounter13h, x0\n" + "csrw mhpmcounter14h, x0\n" + "csrw mhpmcounter15h, x0\n" + "csrw mhpmcounter16h, x0\n" + "csrw mhpmcounter17h, x0\n" + "csrw mhpmcounter18h, x0\n" + "csrw mhpmcounter19h, x0\n" + "csrw mhpmcounter20h, x0\n" + "csrw mhpmcounter21h, x0\n" + "csrw mhpmcounter22h, x0\n" + "csrw mhpmcounter23h, x0\n" + "csrw mhpmcounter24h, x0\n" + "csrw mhpmcounter25h, x0\n" + "csrw mhpmcounter26h, x0\n" + "csrw mhpmcounter27h, x0\n" + "csrw mhpmcounter28h, x0\n" + "csrw mhpmcounter29h, x0\n" + "csrw mhpmcounter30h, x0\n" + "csrw mhpmcounter31h, x0\n"); +} + +void pcount_enable(int enable) { + // Note cycle is disabled with everything else + unsigned int inhibit_val = enable ? 0x0 : 0xFFFFFFFF; + // mucounteren == mcountinhibit but binutils doesn't seem to known the + // mcountinhibit name + asm volatile("csrw mucounteren, %0\n" : : "r"(inhibit_val)); +} + +unsigned int get_mepc() { + uint32_t result; + __asm__ volatile("csrr %0, mepc;" : "=r"(result)); + return result; +} + +unsigned int get_mcause() { + uint32_t result; + __asm__ volatile("csrr %0, mcause;" : "=r"(result)); + return result; +} + +unsigned int get_mtval() { + uint32_t result; + __asm__ volatile("csrr %0, mtval;" : "=r"(result)); + return result; +} + +void simple_exc_handler(void) { + puts("EXCEPTION!!!\n"); + puts("============\n"); + puts("MEPC: 0x%0X");puthex(get_mepc()); + puts("\nMCAUSE: 0x%0X");puthex(get_mcause()); + puts("\nMTVAL: 0x%0X");puthex(get_mtval()); + putchar('\n'); + sim_halt(); + + while(1); +} diff --git a/examples/sw/simple_system/common/simple_system_common.h b/examples/sw/simple_system/common/simple_system_common.h new file mode 100644 index 00000000..1ab93ef6 --- /dev/null +++ b/examples/sw/simple_system/common/simple_system_common.h @@ -0,0 +1,58 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef SIMPLE_SYSTEM_COMMON_H__ + +#include + +#include "simple_system_regs.h" + +#define DEV_WRITE(addr, val) (*((volatile uint32_t *)(addr)) = val) +#define DEV_READ(addr, val) (*((volatile uint32_t *)(addr))) + +/** + * Writes character to simulator out log. Signature matches c stdlib function + * of the same name. + * + * @param c Character to output + * @returns Character output (never fails so no EOF ever returned) + */ +int putchar(int c); + +/** + * Writes string to simulator out log. Signature matches c stdlib function of + * the same name. + * + * @param str String to output + * @returns 0 always (never fails so no error) + */ +int puts(const char *str); + +/** + * Writes ASCII hex representation of number to simulator out log. + * + * @param h Number to output in hex + */ +void puthex(uint32_t h); + +/** + * Immediately halts the simulation + */ +void sim_halt(); + +/** + * Enables/disables performance counters. This effects mcycle and minstret as + * well as the mhpmcounterN counters. + * + * @param enable if non-zero enables, otherwise disables + */ +void pcount_enable(int enable); + +/** + * Resets all performance counters. This effects mcycle and minstret as well + * as the mhpmcounterN counters. + */ +void pcount_reset(); + +#endif diff --git a/examples/sw/simple_system/common/simple_system_regs.h b/examples/sw/simple_system/common/simple_system_regs.h new file mode 100644 index 00000000..8f5a8072 --- /dev/null +++ b/examples/sw/simple_system/common/simple_system_regs.h @@ -0,0 +1,12 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef SIMPLE_SYSTEM_REGS_H__ +#define SIMPLE_SYSTEM_REGS_H__ + +#define SIM_CTRL_BASE 0x20000 +#define SIM_CTRL_OUT 0x0 +#define SIM_CTRL_CTRL 0x4 + +#endif // SIMPLE_SYSTEM_REGS_H__ diff --git a/examples/sw/simple_system/hello_test/Makefile b/examples/sw/simple_system/hello_test/Makefile new file mode 100644 index 00000000..495a53b5 --- /dev/null +++ b/examples/sw/simple_system/hello_test/Makefile @@ -0,0 +1,14 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Generate a baremetal application + +# Name of the program $(PROGRAM).c will be added as a source file +PROGRAM = hello_test +PROGRAM_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) +# Any extra source files to include in the build. Use the upper case .S +# extension for assembly files +EXTRA_SRCS := + +include ${PROGRAM_DIR}/../common/common.mk diff --git a/examples/sw/simple_system/hello_test/hello_test.c b/examples/sw/simple_system/hello_test/hello_test.c new file mode 100644 index 00000000..2d630dd8 --- /dev/null +++ b/examples/sw/simple_system/hello_test/hello_test.c @@ -0,0 +1,21 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "simple_system_common.h" + +int main(int argc, char **argv) { + pcount_enable(0); + pcount_reset(); + pcount_enable(1); + + puts("Hello simple system\n"); + puthex(0xDEADBEEF); + putchar('\n'); + puthex(0xBAADF00D); + putchar('\n'); + + pcount_enable(0); + + return 0; +} diff --git a/shared/rtl/sim/simulator_ctrl.sv b/shared/rtl/sim/simulator_ctrl.sv new file mode 100644 index 00000000..9fa8de66 --- /dev/null +++ b/shared/rtl/sim/simulator_ctrl.sv @@ -0,0 +1,83 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +/** + * Module for communicating with the simulator that interfaces via the memory + * system. + * + * Contains two registers + * + * * 0x0 - CHAR_OUT_ADDR - [7:0] of write data output via output_char DPI call + * and SimOutputManager (see dv/common/cpp/sim_output_manager.cc) + * * 0x4 - SIM_CTRL_ADDR - Write 1 to bit 0 to halt sim + */ + +module simulator_ctrl #( + // passed to simulator via log_name of output_char DPI call + parameter string LogName = "ibex_out.log", + // If set flush on every char (useful for monitoring output whilst + // simulation is running). + parameter bit FlushOnChar = 1 +) ( + input clk_i, + input rst_ni, + + input req_i, + input we_i, + input [ 3:0] be_i, + input [31:0] addr_i, + input [31:0] wdata_i, + output logic rvalid_o, + output logic [31:0] rdata_o +); + + localparam CHAR_OUT_ADDR = 0; + localparam SIM_CTRL_ADDR = 1; + + logic [7:0] ctrl_addr; + + integer log_fd; + + initial begin + log_fd = $fopen(LogName, "w"); + end + + final begin + $fclose(log_fd); + end + + assign ctrl_addr = addr_i[9:2]; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (~rst_ni) begin + rvalid_o <= 0; + end else begin + // Immeditely respond to any request + rvalid_o <= req_i; + + if (req_i & we_i) begin + case (ctrl_addr) + CHAR_OUT_ADDR: begin + if (be_i[0]) begin + $fwrite(log_fd, "%c", wdata_i[7:0]); + + if(FlushOnChar) begin + $fflush(log_fd); + end + end + end + SIM_CTRL_ADDR: begin + if (be_i[0] & wdata_i[0]) begin + $display("Terminating simulation by software request."); + $finish; + end + end + endcase + end + end + end + + assign rdata_o = '0; +endmodule + diff --git a/shared/sim_shared.core b/shared/sim_shared.core index cf4aa080..e7a224fc 100644 --- a/shared/sim_shared.core +++ b/shared/sim_shared.core @@ -10,6 +10,7 @@ filesets: - ./rtl/prim_clock_gating.sv - ./rtl/ram_1p.sv - ./rtl/bus.sv + - ./rtl/sim/simulator_ctrl.sv file_type: systemVerilogSource targets: