Added simple system

Simple system is a basic verilator top-level testbench for running
 executables.  It has functionality for outputting text to a log file
 and for the software to terminate the simulation
This commit is contained in:
Greg Chadwick 2019-10-30 16:47:18 +00:00 committed by Philipp Wagner
parent 31d423ae47
commit 2041f10c69
14 changed files with 970 additions and 0 deletions

View file

@ -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
<https://github.com/lowRISC/lowrisc-toolchains/releases>
## 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=<sw_vmem_file>
```
`<sw_vmem_file>` 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 |
+---------------------|-----------------------------------------------------------------------------+

View file

@ -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 <signal.h>
#include <iostream>
#include <memory>
#include <fstream>
#include "ibex_pcounts.h"
#include "verilated_toplevel.h"
#include "verilator_sim_ctrl.h"
std::shared_ptr<VerilatorSimCtrl> simctrl(nullptr);
int main(int argc, char **argv) {
int retcode;
auto top = std::make_shared<ibex_simple_system>();
simctrl = std::make_shared<VerilatorSimCtrl>(
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;
}

View file

@ -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"

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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
}

View file

@ -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);
}

View file

@ -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 <stdint.h>
#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

View file

@ -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__

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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: