Giter Club home page Giter Club logo

etiss's People

Contributors

aguynameddhia avatar andrewstevens-infineon avatar anoushkau avatar fpedd avatar heatdh avatar jogei avatar lukasauer avatar maltevonehren avatar philippvk avatar rafzi avatar togulcan avatar uzleosharif avatar wysiwyng avatar yasaminmoradi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

etiss's Issues

Cleanup example INI config files

I realized, that multiple configuration options found in examples/bare_etiss_processor/base.ini do not have an effect right now.

I.e. arch.cpu_cycle_time_ps=10000 is only used by OR1KArch while RISCVArch has the value 31250 hardcoded.

For this propertie and a probably a few other we should decide to either:

  • Remove the unsupported option from the example configuration file to reduce teh confusion for new users
  • or properly implement the options for all supported architectures.

general RISCV SW compilation

currently we are emulating a Pulp* machine while running RISCV code. This means we can only run SW that is compiled via Pulp* SDK (using their linker-script, runtimes and libs etc.).
In my eyes, it would be nice to break away from this flow and be able to support any RISCV SW development flow. Forexample, official RISCV tools (spike + pk) is able to run binaries generated via default riscv*-gcc settings. Obviously we dont expect such binary to work right away on our simulator but with simple custom linker-script and crt0.s (samples available online) we should be able to provide SW dev environment that serves more use-cases

CI still uses LLVM 7.0.0

See title, as ETISS requires LLVM 11 or greater per the cmake file, this should also be reflected in the CI.

Issues with Existing Fault Injection Code

This issue summarizes the functionality of the existing Fault Injection Code in ETISS and lists existing problems with it:

1.1 Functionality

The core concept is that a VirtualStruct, aka an Injector, checks whether one of its assigned Triggers is satisfied and then applies the corresponding Actions through the static Stressor that manages all Fault s registered through ETISS' configuration.
A Fault has a set of Triggers and a set of Actions.

Existing Trigger types are:

  • META_COUNTER: The Trigger has a sub trigger which has to fire a certain number (count) of times until the Trigger fires
  • VARIABLEVALUE: The trigger condition is satisfied if the associated variable Field is equal to a constant value
  • TIME: The trigger condition is satisfied, if ETISS simulation time has reached the given constant time value of the trigger
  • TIMERELATIVE: On the first check of the Triggercondition the given time value is added to the current simulation time to make a TIME type trigger
  • NOP: No trigger operation - invalid

Existing Action types are:

  • BITFLIP: Flips the target bit of the target Field equal to exclusive or of Field word with newval = newval ^ (1<<bit);
  • Command: Calls the Injectors applyCustomAction with the given string as an argument.
  • INJECTION: Injects a new Fault into the simulation, e.g., see TIMERELATIVE Trigger
  • NOP: No Action operation - invalid

1.2 Existing Problems / Todos

  • To allow Action being applied by the Stressor all VirtualStructs, e.g., the CPUCore, have to be mounted to the static VirtualStruct::root(). This is needed to allow the Stressor to resolve all Injectors when a faults schedule, e.g., faults.xml, is configured.
  • Field has constant access flags denying fault injection to itself. A Field must be constructed as injectable otherwise it is not.
  • NOP type Triggers and Actions lead to simulation errors instead of "don't care"s.
  • Stressor::firedTrigger calling Stressor::addFault in INJECTION type Actions result in deadlock because both take same mutex.
  • Limited Field fault capability with only supporting BITFLIPS
  • No "memory faults"
  • No "instruction faults". Requires re-translation of affected translation block if transiently faulted instruction data.
  • No "permanent" faults, because once a (non-sub) trigger fires, it is removed from the trigger list of an Injector
  • No example/how-to use fault injection
    • general example and how-to
    • example for architectural faults and scheduling
    • example for memory faults (requires etiss processor system)
  • better enums to allow nicer string->enum|enum->string conversion for xml

check if forced misalignment is performance issue

since we use struct packing for the ETISS_CPU struct, its members should be carefully placed to avoid misaligned memory accesses.

for example:

https://github.com/tum-ei-eda/etiss/blob/master/include_c/etiss/jit/CPU.h#L101

-> consider making ETISS_MAX_RESOURCES a multiple of 8.

https://github.com/tum-ei-eda/etiss/blob/master/ArchImpl/RISCV/RISCV.h#L77

-> should consider this in m2isar code generator. simple solution: sort member definitions by size descending

RISC-V Performance Improvements

ETISS translates blocks with a configurable block length and only stops when illegal instructions are found.

ETISS code blocks are not "basic blocks" that represent an indivisible section of code. They can be reentered at an offset different from zero. Their translated source code consists of a function with a large switch statement in the following form:

uint32 block1234(...) {
uint64 blockStart = 0x1234;
uint64 jumpAddr = cpu->PC - blockStart;
switch (jumpAddr) {
case 0x0:
// First translated instruction.
case 0x4:
// Second translated instruction.
// ...
break;
default:
return ERROR;
}
return SUCCESS;
}

Issue: For RISC-V, every translated instruction code ends with "return exception". This will exit the block function and go back to the ETISS main loop which causes a lot of overhead. ETISS will call the same block function again, but now the switch lookup becomes more expensive with every call as well.

Proposed solution:
Remove "return exception" from all instructions, except the ones that may jump to anything other than the next instruction. Could be automated by detecting an assignment to PC and only then insert the return at the end.

Possible improvements:

  • Resolve statically known jumps to targets within the block via goto.
  • Use control flow analysis to limit the number of possible entries into a block.

GDBServer: Watchpoints don't work

Our gdb server implementation does not seem to be able to handle watchpoints.

The gdb client reports an error about being unable to insert a hardware breakpoint.

Replicate with:

watch *0x0
c

Support TCC JIT engine on systems with SELinux enabled

By default, TCC does not support running on systems with selinux set to enforcing. Running ETISS leads to the following run-time error in this case.

tcc: error: mprotect failed: did you mean to configure --with-selinux?

Fortunately, this already gives us the solution to the problem, TCC just has to be configured differently in JITImpl/TCC/CMakeLists.txt. Now the question is, how this should be handled within the ETISS build system. I already briefly discussed this with @JoGei and we came up with three possibilities.

  1. Automatically detect selinux within cmake. This could be done by checking if the binary getenforce exists and returns Enforcing.
  2. Add a cmake variable (for example ETISS_SELINUX), which the user has to set accordingly.
  3. Always enable selinux support in TCC. This works, but may lead to a performance overhead.

I am not sure what the best approach would be here, option 1 would definitely be the most user-friendly one.

non-internal ETISS config options in "Allowed options"

ETISS initialize exposes configuration options that are not used by the neither core nor architecture. This leads to false feedback to users implying such options exists "out of the box". Some examples:

  • etiss.enable_dmi the "direct memory interface" seems to be something from for systemc wrapper of the CPUCore - no usage in standalone ETISS
  • etiss.log_pc is only checked in the example bare etiss processor to activate an additional plugin
  • vp.sw_binary_ram no usage, deprecated since existing SystemWrappers now rely on ELF files
  • vp.sw_binary_rom ""

The ETISS-Core should only expose options that it can also handle. While options like etiss.log_pc are used in the example, the example should expose its "extending" features, but not the Core.

Related code sections, where options are defined:

etiss/src/ETISS.cpp

Lines 721 to 753 in 36902d3

po::options_description desc("Allowed options");
desc.add_options()
("help", "Produce a help message that lists all supported options.")
("arch.cpu", po::value<std::string>(), "The CPU Architecture to simulate.")
("arch.or1k.ignore_sr_iee", po::value<bool>(), "Ignore exception on OpenRISC.")
("arch.or1k.if_stall_cycles", po::value<int>(), "Add instruction stall cycles on OpenRISC.")
("arch.cpu_cycle_time_ps", po::value<int>(), "Sets CPU cycles time on OpenRISC and ARM.")
("etiss.enable_dmi", po::value<bool>(), "Enables the Direct Memory Interface feature of SystemC to speed up memory accesses. This needs to be disabled for memory tracing.")
("etiss.log_pc", po::value<bool>(), "Enables logging of the program counter.")
("etiss.max_block_size", po::value<int>(), "Sets maximum amount of instructions in a block.")
("etiss.output_path_prefix", po::value<std::string>(), "Path prefix to use when writing output files.")
("etiss.loglevel", po::value<int>(), "Verbosity of logging output.")
("jit.gcc.cleanup", po::value<bool>(), "Cleans up temporary files in GCCJIT. ")
("jit.verify", po::value<bool>(), "Run some basic checks to verify the functionality of the JIT engine.")
("jit.debug", po::value<bool>(), "Causes the JIT Engines to compile in debug mode.")
("jit.type", po::value<std::string>(), "The JIT compiler to use.")
("jit.external_headers", po::value<std::string>(), "List of semicolon-separated paths to headers for the JIT to include.")
("jit.external_libs", po::value<std::string>(), "List of semicolon-separated library names for the JIT to link.")
("jit.external_header_paths", po::value<std::string>(), "List of semicolon-separated headers paths for the JIT.")
("jit.external_lib_paths", po::value<std::string>(), "List of semicolon-separated library paths for the JIT.")
("vp.sw_binary_ram", po::value<std::string>(), "Path to binary file to be loaded into RAM.")
("vp.sw_binary_rom", po::value<std::string>(), "Path to binary file to be loaded into ROM.")
("vp.elf_file", po::value<std::string>(), "Load ELF file.")
("vp.stats_file_path", po::value<std::string>(), "Path where the output json file gets stored after bare processor is run.")
("simple_mem_system.print_dbus_access", po::value<bool>(), "Traces accesses to the data bus.")
("simple_mem_system.print_ibus_access", po::value<bool>(), "Traces accesses to the instruction bus.")
("simple_mem_system.print_dbgbus_access", po::value<bool>(), "Traces accesses to the debug bus.")
("simple_mem_system.print_to_file", po::value<bool>(), "Write all tracing to a file instead of the terminal. The file will be located at etiss.output_path_prefix.")
("plugin.logger.logaddr", po::value<std::string>(), "Provides the compare address that is used to check for memory accesses that are redirected to the logger.")
("plugin.logger.logmask", po::value<std::string>(), "Provides the mask that is used to check for memory accesses that are redirected to the logger.")
("plugin.gdbserver.port", po::value<std::string>(), "Option for gdbserver")
("pluginToLoad,p", po::value<std::vector<std::string>>()->multitoken(), "List of plugins to be loaded.")
;

RISCVArch xIE CSRs (implementation specific fields) not setable

When trying to enable implementation specific lines in the Interrupt enable registers, bits above 12 are ignored by CSR Write instructions.
https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMFDQC-and-Priv-v1.11/riscv-privileged-20190608.pdf

specifies at p. 31 to enable bits 16 on-wards as custom interrupt lines which seem to be ignored by ETISS.

Test code:

int main()
{
    unsigned int tmie, t_smie = 0xFFFFFFFF;

    asm volatile("csrr %[rd], 0x304" : [rd] "=r" (tmie) );

    printf("MIE after reset: %x\n", tmie);

    asm volatile ("csrw 0x304, %0" : /* no output */ : "r" (t_smie));

    asm volatile("csrr %[rd], 0x304" : [rd] "=r" (tmie) );

    printf("MIE after attempted set: %x\n", tmie);
}

reports:

=== Setting up configurations ===
Load ini file.
Load Configs from .ini files:
ETISS: Info: Created new config container: global
ETISS: Info: [BoolConfigurations]
ETISS: Info: cleanup=true,
ETISS: Info: copy-headers=true,
ETISS: Info: ETISS::enable_dmi=true,
ETISS: Info: ETISS::log_pc=false,
ETISS: Info: hostendianness=false,
ETISS: Info: ignore_sr_iee=false,
ETISS: Info: integrated-library=true,
ETISS: Info: jit-debug=true,
ETISS: Info: library-loading=true,
ETISS: Info: norangeexception=false,
ETISS: Info: pyconsole=false,
ETISS: Info: returnjump=false,
ETISS: Info: sigint-console=false,
ETISS: Info: verifyJIT=false,
ETISS: Info: [IntConfigurations]
ETISS: Info: Arch::cpuCycleTime_ps=10000,
ETISS: Info: ETISS::CPU_quantum_ps=100000,
ETISS: Info: ETISS::sim_mode=0,
ETISS: Info: ETISS::write_pc_trace_from_time_us=0,
ETISS: Info: ETISS::write_pc_trace_until_time_us=3000000,
ETISS: Info: ifStallCycles=0,
ETISS: Info: logLevel=4,
ETISS: Info: Translation::MaxBlockSize=100,
ETISS: Info: vp::simulation_time_us=20000000,
ETISS: Info: [StringConfigurations]
ETISS: Info: CPUArch=RISCV,
ETISS: Info: ETISS::outputPathPrefix=,
ETISS: Info: sw_binary_ram=/data/home.local/repos/dumpy/etiss.du/build/installed/examples/SW/riscv/build/riscv_example.ram,
ETISS: Info: sw_binary_rom=/data/home.local/repos/dumpy/etiss.du/build/installed/examples/SW/riscv/build/riscv_example.rom,
ETISS: Info: vp::dram_file=/data/home.local/repos/dumpy/etiss.du/build/installed/examples/SW/riscv/build/riscv_example.ram,
ETISS: Info: vp::iram_file=/data/home.local/repos/dumpy/etiss.du/build/installed/examples/SW/riscv/build/riscv_example.rom,
=== Finished setting up configurations ===

=== Setting up test system ===
Setting up Memory
rom binary loaded!
ram binary loaded!
Setting up CPUCore
=== Finished Setting up test system ===

=== Setting up plug-ins ===
ETISS: Info: Adding Plugin Logger
ETISS: Info: options[logaddr] = 0x80000000
ETISS: Info: options[logmask] = 0x80000000
ETISS: Info: Plugin "Logger" loaded via library interface "ETISSINCLUDED"
ETISS: Info: Adding JIT "TCCJIT"
=== Setting up plug-ins ===

=== Simulation start ===
ETISS: Info: Init Plugin Logger @2147483648{SYSTEMWRAPPER}
ETISS: Warning: Removed empty etiss::instr::InstructionSet during compilation.
{
{ISA64_RISCV}
}
ETISS: Warning: Removed empty etiss::instr::InstructionSet during compilation.
{
{ISA64_RISCV}
}
MIE after reset: 0
MIE after attempted set: bbb
CPU Time: 0.000138031s Simulation Time: 0.2609s
CPU Cycles (estimated): 4417
MIPS (estimated): 0.0169299
=== Simulation end ===

CPU0 exited with exception: 0x80000000: Finished cpu execution. This is the proper way to exit from etiss::CPUCore::execute._

Second declaration of temporary variables in same Translation Block Def.

ArchImpl for RISCV64 fails for Atomic Instruction Set fails at JIT compile (possibly more ISAs):

Reason is variables are declarated multiple times in the same compound, e.g.:
1),

"etiss_uint32 MEM_offs;\n"

2)
"etiss_uint32 MEM_offs;\n"

Problem might be traced back to Code Generator for ArchImpl.

Example:

JIT-compilation:

image

Translated Host-C-code

image

Documentation build clutters `git pull`

Currently the Doxygen documentation is built and updated on every push to this repo, and the resulting html files committed to the gh-pages branch in this repo. While this practice guarantees up-to-date documentation, it also implies that this gh-pages branch is always updated on your local working folder if you run a git pull, resulting in a download of several 100 Mbytes.

Some ideas are:

  • Trigger documentation build manually, or only if tags are pushed
  • Host the documentation elsewhere (VP-Vibes? Wiki Repository?)

Overlapping InstructionDefinitions do not behave as expected

Consider the following InstructionDefinitions, with IT_T1 being the generic InstructionDefinition and the rest being specialized cases (instruction behavior removed, not needed for this discussion):

// IT_T1; encoding: b1011 | b1111 | firstcond[3:0] | mask[3:0]
static InstructionDefinition it_t1_mask_firstcond (
    ISA16_ARMv7M,
    "it_t1",
    (uint16_t) 0xbf00,
    (uint16_t) 0xff00,
    [] (BitArray & ba,etiss::CodeSet & cs,InstructionContext & ic) { return true; },
    0,
    nullptr
);

// NOP_T1; encoding: b1011 | b1111 | b0000 | b0000
static InstructionDefinition nop_t1_ (
    ISA16_ARMv7M,
    "nop_t1",
    (uint16_t) 0xbf00,
    (uint16_t) 0xffff,
    [] (BitArray & ba,etiss::CodeSet & cs,InstructionContext & ic) { return true; },
    0,
    nullptr
);

// YIELD_T1; encoding: b1011 | b1111 | b0001 | b0000
static InstructionDefinition yield_t1_ (
    ISA16_ARMv7M,
    "yield_t1",
    (uint16_t) 0xbf10,
    (uint16_t) 0xffff,
    [] (BitArray & ba,etiss::CodeSet & cs,InstructionContext & ic) { return true; },
    0,
    nullptr
);

// WFE_T1; encoding: b1011 | b1111 | b0010 | b0000
static InstructionDefinition wfe_t1_ (
    ISA16_ARMv7M,
    "wfe_t1",
    (uint16_t) 0xbf20,
    (uint16_t) 0xffff,
    [] (BitArray & ba,etiss::CodeSet & cs,InstructionContext & ic) { return true; },
    0,
    nullptr
);

// WFI_T1; encoding: b1011 | b1111 | b0011 | b0000
static InstructionDefinition wfi_t1_ (
    ISA16_ARMv7M,
    "wfi_t1",
    (uint16_t) 0xbf30,
    (uint16_t) 0xffff,
    [] (BitArray & ba,etiss::CodeSet & cs,InstructionContext & ic) { return true; },
    0,
    nullptr
);

// SEV_T1; encoding: b1011 | b1111 | b0100 | b0000
static InstructionDefinition sev_t1_ (
    ISA16_ARMv7M,
    "sev_t1",
    (uint16_t) 0xbf40,
    (uint16_t) 0xffff,
    [] (BitArray & ba,etiss::CodeSet & cs,InstructionContext & ic) { return true; },
    0,
    nullptr
);

These instructions compile fine, but during initialization ETISS terminates with the following fatal error: "OverlappedNode delegate must not be a plain Node", in file Instruction.cpp. Using all specialized instructions without IT_T1 works fine, as well as up to two specialized instructions together with IT_T1. Three or more specialized instructions cause the above error.

Background why this is needed: ARMv7M has certain instructions which are "specialized" cases of "generic" instructions, where e.g. if a specific register is used certain behavior will be different. Additionally, the reference manual calls these instructions differently. Some of these special cases can be encoded with conditionals inside one InstructionDefinition, others like the example above get very cumbersome if encoded that way.

RISC-V JIT Compile Error

This is probably related to the resource and CoreDSL changes. Is caused by the "simple_tflm" application, but probably just related to the use of AMOADD.W.

:1020: error: redeclaration of 'MEM_offs'

    case 108:
        {
cpu->cpuTime_ps += (1 * cpu->cpuCycleTime_ps);
//amoadd.w
etiss_uint32 exception = 0;
etiss_uint32 temp = 0;
etiss_uint8 * tmpbuf = (etiss_uint8 *)&temp;
etiss_uint32 offs = 0;
etiss_int32 res1 = 0;
etiss_uint32 res2 = 0;
offs = *((RISCV*)cpu)->X[13];
etiss_uint32 MEM_offs;
tmpbuf = (etiss_uint8 *)&MEM_offs;
exception = (*(system->dread))(system->handle,cpu,offs,tmpbuf,4);
etiss_int32 cast_0 = MEM_offs;
if((etiss_int32)((etiss_uint32)cast_0 - 0x80000000) > 0x0)
{
cast_0 =0x0 + (etiss_uint32)cast_0 ;
}
res1 = (etiss_int32)cast_0;
if(15 != 0)
{
*((RISCV*)cpu)->X[15] = res1;
}
res2 = res1 + *((RISCV*)cpu)->X[14];
etiss_uint32 MEM_offs;
tmpbuf = (etiss_uint8 *)&MEM_offs;
MEM_offs = res2;
exception = (*(system->dwrite))(system->handle,cpu,offs,tmpbuf,4);
if((offs + 4 > ((RISCV*)cpu)->RES) && (offs < 4 + ((RISCV*)cpu)->RES))
{
((RISCV*)cpu)->RES = 0;
}
cpu->instructionPointer = 39894ULL;
return exception;

        }

GDB server port cannot be set via command line

As mentioned in the title, the GDB server port cannot be set with a command line parameter. Specifically, I tried it with ./main -ietiss.ini -p gdbserver --plugin.gdbserver.port 1234. The output from ETISS looks good, however GDB times out when trying to connect to the non-standard port. Connecting to the standard port (2222) works, meaning that the command line parameter got ignored.

ETISS: Info:   Adding Plugin gdbserver

ETISS: Info: Plugin "gdbserver" loaded via library interface "ETISSINCLUDED"

ETISS: Info: plugin.gdbserver.port written from command line
               options[plugin.gdbserver.port] = 1234

CPU bootup

Currently in both the 32/64 bit versions of RISCVArch implementations, we are forced to boot from 0x80 which might not be true for general RISCV SoCs, though compatible with Pulpino. We have to provide flexibility and remove this hardcoded impl.

Moreover it also seems that RISCArch::resetCPU(... cpu, ... startpointer) doesn't really respect the custom passed startpointer b/c the HW reset at the start of the simulation basically override this setting

Broken Floating Point Registers in GDB

Broken Floating Point Registers

Currently, the display of floating point registers is broken. This leads to double-precision values being incorrectly displayed.

Take these to variables:

register double a asm ("f0") = 3.1415;
register float b asm ("f1") = 2.7182;

which are displayed as:

ft0            {float = -4.09600019, double = 6.9528787831812155e-310}	(raw 0x00007ffdc083126f)
ft1            {float = 2.71819997, double = 6.9527724078223043e-310}	(raw 0x00007ffd402df6fd)

in GDB when issuing info all-register. While the single-precision variable is correctly displayed, the double-precision variable is not.

The problem lies in the fact, that the current RISC-V Arch is a RV32IMAFDC. This means, that it supports double-precision instructions and has 64bit floating point registers (FLEN=64). The ETISS GDB server, however, only responds with 4 bytes (instead of 8). This is caused by the FloatRegField_RISCV class in RISCVArchSpecificImp.h beeing setup for single-precision/32bit:

class FloatRegField_RISCV : public BaseField_RISCV<uint32_t>
{
public:
    FloatRegField_RISCV(etiss::VirtualStruct &parent, int id)
        : BaseField_RISCV<uint32_t>(parent, "F" + std::to_string(id), 4, &((RISCV *)parent.structure_)->F[id])
    {
    }
};

Simply adjusting it to double-precision/64bit:

class FloatRegField_RISCV : public BaseField_RISCV<uint64_t>
{
public:
    FloatRegField_RISCV(etiss::VirtualStruct &parent, int id)
        : BaseField_RISCV<uint64_t>(parent, "F" + std::to_string(id), 8, &((RISCV *)parent.structure_)->F[id])
    {
    }
};

fixed the issue:

ft0            {float = -4.09600019, double = 3.1415000000000002}	(raw 0x400921cac083126f)
ft1            {float = 2.71819997, double = -nan(0xfffff402df6fd)}	(raw 0xffffffff402df6fd)

This way the implementation is also conformant to the RISC-V spec (section 9.2), in that it adheres to the "NaN Boxing of Narrower Values" in which "the upper bits of a valid NaN-boxed value must be all 1s".

mappedRegisterCount()

Additionally, I noticed that the mappedRegisterCount() in RISCVGDBCore.h returns 32. This would imply that the implementation would "only" have 32 mapped registers, which is obviously not the case, see RISCV.h.

Actually, this doesn't seem to be that big of an issue, as GDB simply one-by-one requests registers not set to it when it sends a "Read general registers" g request (which only sents 32) using multiple p requests afterwards. This is why I can still see floating-point registers in GDB.

At least including the PC, as is done in the RISCV64GDBCore.h, is probably a good idea nonetheless, i.e. changing it to 33. While one could go all the way up to 64, including the floating-point registers is probably not really necessary and just causes unnecessary overhead. However, I don't know how many registers are actually expected by GDB when it sends a "Read general registers" g request. The onlinedocs don't give any information on that either.

The only reason I am bringing this up in the first place is that the G "Write general registers." will probably always fail the way it is implemented right now, see GDBServer.cpp.

case 'G': // write registers
{
size_t treglen = 0;
for (unsigned i = 0; i < arch_->getGDBCore().mappedRegisterCount(); i++)
{
auto f = plugin_core_->getStruct()->findName(arch_->getGDBCore().mapRegister(i));
if (!f)
{
answer = "EFF";
etiss::log(etiss::ERROR, "Faulty implementation of the GDBCore: Register not found",
arch_->getGDBCore().mapRegister(i), *plugin_core_);
break;
}
treglen += f->width_;
}
if (command.length() == (treglen * 2) + 1)
{
answer = "OK";
size_t off = 1;

The for-loop, which is dependent on mappedRegisterCount(), will create a total size variable treglen and compare it against the incoming command.length(). If they don't match, the request will fail. Thus, it is crucial that mappedRegisterCount() returns the exact number of registers expected by GDBs G request.

I haven't gotten GDB to emit a G request and don't really know how to do so or when it is used. So I am not sure this is actually that relevant, but I just wanted to mention it here.

On another note

@rafzi you were right about the RISC-V vector support in GDB. While the latest GDB 11 release from June this year does have basic support for vector registers, see here and here, my rvv0.8 toolchain (with GDB 8.3.0) does not appear to have any RISC-V vector support. So I will postpone any work on GDB vector support for ETISS.

config value precision loss

We use "GetDoubleValue" from the SimpleINI library to get integer config values that can be larger than 32 bit.

This is an issue because very large values will be skewed to the nearest representable double, changing the intended value silently.

I'd suggest to patch our own "GetLongLongValue" into the library, since we keep a copy of it in this repository anyways.

cmake: copy without depdendency

In the main cmake, there is a block of code that copies includes into the build folder for an in-tree build of etiss.

https://github.com/tum-ei-eda/etiss/blob/master/CMakeLists.txt#L296

This is missing some dependency to the original includes. If they are changed, the change will not be reflected in the build folder, unless cmake is run manually.

To fix this we'd probably want to add custom commands: https://stackoverflow.com/questions/8434055/cmake-copy-if-original-file-changed

@uzleosharif

MMU broken. No Virtual Memory support.

  • Architectural code is missing integration of existing MMU plugin.
  • Simulation loop utilizing translation buffer needs to respect virtual address mapping

This required major revisions to various ETISS components. As of now, virtual memory is not supported.

LLVM versions > 11 break compilation

Commit 6470d4d relaxed LLVM version checks to allow version 11 and up. This breaks at least on my system (Arch Linux) with LLVM version 12.0.1. A reason why the CI didn't catch this fault is that in Windows builds LLVM is not even used, and on Linux / Mac builds LLVM version 11.0.0 is manually installed.

A better fix for the CI failure the aforementioned commit tried to fix would be to force installation of LLVM 11 on windows: choco install llvm --version=11.0.0 --allow-downgrade

RISCV: Code followed by data

Note sure if this is the correct fix:

76b3e78

Possible issue: Why does it try to translate more than the basic block? Should it not end after "ret"?

Example, when translating register_fini:

(gdb) x/20i register_fini
0x1b54a <register_fini>: lui a5,0x0
0x1b54e <register_fini+4>: mv a5,a5
0x1b552 <register_fini+8>: beqz a5,0x1b55e <register_fini+20>
0x1b554 <register_fini+10>: lui a0,0x12
0x1b556 <register_fini+12>: addi a0,a0,1894
0x1b55a <register_fini+16>: j 0x168f4
0x1b55e <register_fini+20>: ret
0x1b560: flw fs8,80(sp)
0x1b562: lui s0,0xffff8
0x1b564: flw fa0,48(sp)
0x1b566: flw fa2,88(sp)
0x1b568: lui tp,0xffff9
0x1b56a: csrs 0x2e3,sp
0x1b56e: jal 0x1b17a <_ZN12_GLOBAL__N_14pool8allocateEj.constprop.0+42>
0x1b570: fld ft0,232(sp)
0x1b572: unimp
0x1b574 <_ZN12_GLOBAL__N_1L12g_model_dataE>: 0x1c
0x1b576 <_ZN12_GLOBAL__N_1L12g_model_dataE+2>: unimp
0x1b578 <_ZN12_GLOBAL__N_1L12g_model_dataE+4>: lw a3,12(a2)
0x1b57a <_ZN12_GLOBAL__N_1L12g_model_dataE+6>: fld fa1,160(a4)
(gdb) x/60b register_fini
0x1b54a <register_fini>: 0xb7 0x07 0x00 0x00 0x93 0x87 0x07 0x00
0x1b552 <register_fini+8>: 0x91 0xc7 0x49 0x65 0x13 0x05 0x65 0x76
0x1b55a <register_fini+16>: 0x6f 0xb0 0xaf 0xb9 0x82 0x80 0x46 0x6c
0x1b562: 0x61 0x74 0x42 0x75 0x66 0x66 0x65 0x72
0x1b56a: 0x73 0x20 0x31 0x2e 0x31 0x31 0x2e 0x30
0x1b572: 0x00 0x00 0x1c 0x00 0x00 0x00 0x54 0x46
0x1b57a <_ZN12_GLOBAL__N_1L12g_model_dataE+6>: 0x4c 0x33 0x00 0x00 0x12 0x00 0x1c 0x00
0x1b582 <_ZN12_GLOBAL__N_1L12g_model_dataE+14>: 0x04 0x00 0x08 0x00

Remove ETISS_HOME

It is not technically required and has odd requirements (trailing path separator)

bare_etiss_processor/get_metrics.py: Invalid stats for Stack/Heap usage since memory map refactoring

The script get_metrics.py is useful to get information in the usage of memory in ETISS.

I recently discovered that the reported stack usage is always zero and the heap non-zero instead. Here is an example:

Model,Cycles,ROM,RAM,ROM read-only,ROM code,RAM data,RAM zero-init data,RAM stack,RAM heap
resnet,652858000,160542,70749,100564,59830,2201,66168,0,2380

Using the following memsegs.ini and MIN_STACK_SIZE=0x4000:

[IntConfigurations]
simple_mem_system.memseg_origin_00=0x0
simple_mem_system.memseg_length_00=0x100000
simple_mem_system.memseg_origin_01=0x100000
simple_mem_system.memseg_length_01=0x5000000

After having a look at the generated binary using readelf I figured out what is going on:

The Memory size of the RAM memory segment is not equal to the specified RAM_SIZE anymore which leads to the fact that it’s value can not be used to figure out the end of the ram and therefore the start/end of the stack section.

See before…

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001000 0x00000000 0x00000000 0x03f0c 0x03f0c R E 0x1000
  LOAD           0x005000 0x00100000 0x00100000 0x0088c 0x5000000 RW  0x1000

… and after #61:

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001000 0x00000000 0x00000000 0x2aaa8 0x2aaa8 R E 0x1000
  LOAD           0x02c000 0x00100000 0x00100000 0x00954 0x18bd4 RW  0x1000

Therefore the following code in the aforementioned script is invalid:

ramSize = e.get_segment(1)['p_memsz']

A rather “hacky” workaround would be parsing the value of the symbol VALUE_ram_size similar to the way, the stackSize and heapStart is determined.

LLVM 11 needs C++14 enabled

Currently when compiling ETISS with LLVM enabled a rather unwieldy template error related to various smart pointer features is thrown during compilation of LLVMJitLib.cpp. Setting the C++ standard to 14 in CMakeLists.txt fixes this.

No pull request to put this up for discussion, as there were some issues with C++14 in the past.

command line options

We can currently pass in config options using ini scripts or as command-line arguments. Currently we allow a certain options to be overwritten. For example we can pass 2 ini files:

// foo.ini
[Int Configurations]
a=0

// bar.ini
[IntConfigurations]
a=4
b=3

when we run etiss passing in these 2 files

> <etiss program> -i foo.ini -i bar.ini

then in this case etiss::cfg would take a as 0 and ignore overwrites

How should we deal such overwriting scenarios. I guess the easiest solution would be to disable this feature altogether and the user should make sure that he is not passing in conflicting values for a setting.

Implement `rdcycle`, `rdtime`, and `rdinstret`

Would be nice if ETISS supported these (OVPsim and Spike offer them). Currently reading them returns 0.

See RISC-V User-Level ISA V2.2, 2.8 Control and Status Register Instructions, Timers and Counters for more info. They can then in turn be used to, for example, run performance tests on TensorFlow Lite Micro.

run_helper: permission issue with multiple users

run_helper.sh creates a temporary config file in /tmp.

if another user tries to run the script afterwards, he will not have access to that file and etiss cannot start with that script.

solution: pick a unique file name for the tmp file. also clean it up after execution

RV64G examples on bare_etiss_processor

do we want to support RV64G ISA in examples? Currently i see that:

  • the SW in examples forces march=rv32gc and mabi for gcc. Though you can set it up in the CMake script but the README doesn't mention this option
  • the rv64 in run_helper.sh doesn't seem to work as ETISS crashes with unrecognized option

Make ETISS return nonzero exit value through application software

I am trying to make ETISS return a nonzero exit value through the application software. This way I can use ctest to automagically detect if unit tests failed.

Spike and OVPsim, for example, return a non-zero exit value when the application software runs __asm__ volatile("unimp");. ETISS however simply prints

ETISS: Warning: Illegal instruction at address: 0x43e
Illegal instruction at 0000043E with address 0000043E

and then hangs, but does not return.

I have also tried writing/reading and jumping do random places in the code without any luck, for example:

__asm__ volatile("sw zero, (zero)");

or

__asm__ volatile("li t0, -1\n"
                 "sw zero, (t0)");

I can use ctests TIMEOUT property to make the test fail after waiting x seconds. But this means that I either have to set the timeout very tight or wait quite some time for the tests run through...

Uninitialized Nodes in Instruction Set Tree

When uncommenting

// std::cout << iset.print() << std::endl;

the tree structure of the instruction set/instruction decoder gets printed.

However, some nodes in the compressed instruction set tree are printed as "uninitialized" (arrows <----- inserted by me):

...
MODE 1: 	ISA16_RISCV[default: 16]:
		ISA16_RISCV[16]:
			@0x0 Node[1:0]
				@0x0 Node[15:13]
					@0x0 Uninitialized Node <-----
					@0x1 Instruction: c.fld
					@0x2 Instruction: c.lw
					@0x3 Instruction: c.flw
					@0x5 Instruction: c.fsd
					@0x6 Instruction: c.sw
					@0x7 Instruction: c.fsw
				@0x1 Node[15:13]
					@0x0 Uninitialized Node <-----
					@0x1 Instruction: c.jal
					@0x2 Instruction: c.li
					@0x3 Uninitialized Node <-----
					@0x4 Node[11:10]
						@0x0 Node[12:12]
							@0x0 Instruction: c.srli
						@0x1 Node[12:12]
							@0x0 Instruction: c.srai
						@0x2 Instruction: c.andi
						@0x3 Node[6:5]
							@0x0 Node[12:12]
								@0x0 Instruction: c.sub
							@0x1 Node[12:12]
								@0x0 Instruction: c.xor
							@0x2 Node[12:12]
								@0x0 Instruction: c.or
							@0x3 Node[12:12]
								@0x0 Instruction: c.and
					@0x5 Instruction: c.j
					@0x6 Instruction: c.beqz
					@0x7 Instruction: c.bnez
				@0x2 Node[15:13]
					@0x0 Node[12:12]
						@0x0 Instruction: c.slli
					@0x1 Instruction: c.fldsp
					@0x2 Instruction: c.lwsp
					@0x3 Instruction: c.flwsp
					@0x4 Node[12:12]
						@0x0 Uninitialized Node <-----
						@0x1 Uninitialized Node <-----
					@0x5 Instruction: c.fsdsp
					@0x6 Instruction: c.swsp
					@0x7 Instruction: c.fswsp
...

A node gets printed as uninitialized when this condition evaluates to false:

if (reader_ != nullptr && subs_ != nullptr)

The second uninitialized node

@0x1 Node[15:13]
	@0x0 Uninitialized Node <-----

corresponds to the c.addi instruction. Checking the binary I am compiling (using an rv32gc compiler) this instruction gets used multiple times. I would thus expect the binary to throw some sort of error. However, the binary using these "uninitialized instructions" runs without any issues.

What is happening here? Why are those nodes printed as uninitialized? Why does the binary run anyways? Any help is appreciated! :)

PS: I am mainly asking because I am working on something else, where some instructions/nodes of a RISC-V instruction set extension are also printed as "uninitialized". However, those uninitialized instructions cause some trouble and I am trying to understand why and where the underlying issue is.

Better integration of third party libraries

Third party integration in ETISS is a bit intransparent. A lot of libraries are copy-pasted into ETISS source code which is mostly fine, but makes is harder to maintain and differ what foreign code is used (e.g., versioning, missing copyrights/licenses). A few examples, I am aware of:

  • pugixml - used in fault injection
  • legacy softfloat - kind of anyway a duplicate for the src/jitlib/softfloat
  • simpleini - extensive use in ETISS runtime configuration
  • tcc - fetched via CMake execute_process

A possible solution to this could be to add a third_party/ directory to ETISS' root to integrate such things - either through git submodules or CMake's FetchContent. Please feel free to extend the list above, if you are aware of more.

SimpleMemSystem ignores empty ELF segments

See title. Empty segments might result from minimal programs where the RAM segment is left empty by the compiler (i.e. no data in .data and .bss sections) but should still get allocated for heap and stack use.

Benchmarking: Pull request comments cannot be added

See e.g. https://github.com/tum-ei-eda/etiss/runs/3995739155?check_suite_focus=true#step:5:28 . The documentation of the GitHub action used to create comments says we need to add a private access token of an account with access to the repository for this to work (https://github.com/peter-evans/create-or-update-comment#accessing-issues-and-comments-in-other-repositories) This means either a developer has to supply their PAT to this repo, or we need a service account which is only used for activities such as these.

Windows: TCCJIT only works with path to external libraries in environment path

  • ETISS on Windows can not resolve external JIT library paths (softlfoat, resources, ...).
  • works if those paths are added to global (?) Windows path, e.g.,
    set PATH=%PATH%;<path/to/etiss/install>\include\jit\etiss\jit

Possibly ETISS on Windows can not resolve the default paths for external JIT libraries set within the architecture specific sources or none at all, since manually specifying them with absolute paths in config does not work either.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.